001package jmri.jmrit.pragotronclock; 002 003import java.awt.Color; 004import java.awt.Image; 005import java.awt.event.ActionEvent; 006import java.awt.event.ActionListener; 007import java.awt.event.ComponentAdapter; 008import java.awt.event.ComponentEvent; 009import java.beans.PropertyChangeEvent; 010import java.beans.PropertyChangeListener; 011import java.util.Date; 012 013import javax.swing.BoxLayout; 014import javax.swing.JButton; 015import javax.swing.JLabel; 016 017import jmri.InstanceManager; 018import jmri.Timebase; 019import jmri.jmrit.catalog.NamedIcon; 020import jmri.util.JmriJFrame; 021 022/** 023 * Frame providing a simple clock showing Pragotron clock. 024 * <p> 025 * A Run/Stop button is built into this, but because I don't like the way it 026 * looks, it's not currently displayed in the GUI. 027 * 028 * @author Petr Sidlo Copyright (C) 2019 029 * 030 * Based on Nixie clock by Bob Jacobsen. 031 */ 032public class PragotronClockFrame extends JmriJFrame implements java.beans.PropertyChangeListener { 033 034 // GUI member declarations 035 JLabel h24; // hours 036 JLabel m1; // msb of minutes 037 JLabel m2; 038 JLabel colon; 039 040 double aspect; 041 double iconAspect10; 042 double iconAspectDot; 043 double iconAspect24; 044 int runPauseButtonWidth; 045 046 Timebase clock; 047 private final PropertyChangeListener minuteListener = (PropertyChangeEvent evt) -> update(); 048 049 JButton runPauseButton; 050 051 NamedIcon[] foldingSheets10 = new NamedIcon[10]; 052 NamedIcon[] baseFoldingSheets10 = new NamedIcon[10]; 053 NamedIcon[] foldingSheets24 = new NamedIcon[24]; 054 NamedIcon[] baseFoldingSheets24 = new NamedIcon[24]; 055 NamedIcon colonIcon; 056 NamedIcon baseColon; 057 //"base" variables used to hold original gifs, other variables used with scaled images 058 059 public PragotronClockFrame() { 060 super(Bundle.getMessage("MenuItemPragotronClock")); 061 062 this.getContentPane().setBackground(new Color(0x3D3D3D)); // set background to black 063 064 clock = InstanceManager.getDefault(jmri.Timebase.class); 065 066 //Load the images (these are now the larger version of the original gifs 067 for (int i = 0; i < 10; i++) { 068 baseFoldingSheets10[i] = new NamedIcon("resources/icons/misc/Pragotron/M" + i + ".png", "resources/icons/misc/Pragotron/M" + i + ".png"); 069 foldingSheets10[i] = new NamedIcon("resources/icons/misc/Pragotron/M" + i + ".png", "resources/icons/misc/Pragotron/M" + i + ".png"); 070 } 071 for (int i = 0; i < 24; i++) { 072 baseFoldingSheets24[i] = new NamedIcon("resources/icons/misc/Pragotron/H" + i + ".png", "resources/icons/misc/Pragotron/H" + i + ".png"); 073 foldingSheets24[i] = new NamedIcon("resources/icons/misc/Pragotron/H" + i + ".png", "resources/icons/misc/Pragotron/H" + i + ".png"); 074 } 075 colonIcon = new NamedIcon("resources/icons/misc/Pragotron/dot.png", "resources/icons/misc/Pragotron/dot.png"); 076 baseColon = new NamedIcon("resources/icons/misc/Pragotron/dot.png", "resources/icons/misc/Pragotron/dot.png"); 077 // set initial size the same as the original gifs 078 for (int i = 0; i < 10; i++) { 079 Image scaledImage = baseFoldingSheets10[i].getImage().getScaledInstance(32, 48, Image.SCALE_SMOOTH); // 152 / 192 080 foldingSheets10[i].setImage(scaledImage); 081 } 082 for (int i = 0; i < 24; i++) { 083 Image scaledImage = baseFoldingSheets24[i].getImage().getScaledInstance(80, 48, Image.SCALE_SMOOTH); // 320 / 192 084 foldingSheets24[i].setImage(scaledImage); 085 } 086 Image scaledImage = baseColon.getImage().getScaledInstance(10, 48, Image.SCALE_SMOOTH); // 40 / 192 087 colonIcon.setImage(scaledImage); 088 089 // create the run/pause button and get it's size 090 runPauseButton = new JButton(Bundle.getMessage("ButtonPauseClock")); 091 runPauseButton.setText( Bundle.getMessage( "ButtonPauseClock") ); 092 runPauseButtonWidth = runPauseButton.getPreferredSize().width; 093 094 // determine aspect ratio of a single digit graphic 095 iconAspect10 = 152.0 / 192.0; // 152 : 192 096 iconAspect24 = 320.0 / 192.0; // 320 : 192 097 iconAspectDot = 40.0 / 192.0; // 40 : 192 098 099 // determine the aspect ratio of the 1 hour digit, dot and 2 minutes digit 100 if (!clock.getShowStopButton()) { 101 aspect = (320.0 + 40.0 + 2 * 152.0) / 192.0; // pick up clock prefs choice: no button 102 } else { 103 aspect = (320.0 + 40.0 + 2 * 152.0 + runPauseButtonWidth) / 192.0; // pick up clock prefs choice: add width of a stop/start button 104 } 105 106 107 // init GUI 108 m1 = new JLabel(foldingSheets10[0]); 109 m2 = new JLabel(foldingSheets10[0]); 110 h24 = new JLabel(foldingSheets24[0]); 111 colon = new JLabel(colonIcon); 112 113 getContentPane().setLayout(new BoxLayout(getContentPane(), BoxLayout.X_AXIS)); 114 getContentPane().add(h24); 115 getContentPane().add(colon); 116 getContentPane().add(m1); 117 getContentPane().add(m2); 118 119 getContentPane().add(runPauseButton); 120 runPauseButton.addActionListener(new ButtonListener()); 121 // since Run/Stop button looks crummy, user may turn it on in clock prefs 122 runPauseButton.setVisible(clock.getShowStopButton()); // pick up clock prefs choice 123 updateButtonText(); 124 update(); 125 pack(); 126 127 // listen for changes to the Timebase parameters 128 clock.addPropertyChangeListener(this); 129 130 // request callback to update time 131 clock.addMinuteChangeListener(minuteListener); 132 133 // Add component listener to handle frame resizing event 134 this.addComponentListener( 135 new ComponentAdapter() { 136 @Override 137 public void componentResized(ComponentEvent e) { 138 scaleImage(); 139 } 140 }); 141 142 } 143 144 // Added method to scale the clock digit images to fit the 145 // size of the display window 146 public void scaleImage() { 147 int iconHeight10; 148 int iconWidth10; 149 int iconHeight24; 150 int iconWidth24; 151 int iconHeightDot; 152 int iconWidthDot; 153 int frameHeight = this.getContentPane().getSize().height; 154 int frameWidth = this.getContentPane().getSize().width; 155 if ((double) frameWidth / (double) frameHeight > aspect) { 156 iconHeight10 = frameHeight; 157 iconWidth10 = (int) (iconAspect10 * iconHeight10); 158 iconHeight24 = frameHeight; 159 iconWidth24 = (int) (iconAspect24 * iconHeight24); 160 iconHeightDot = frameHeight; 161 iconWidthDot = (int) (iconAspectDot * iconHeightDot); 162 } else { 163 // allow space in width for run stop button 164 int workingWidth = frameWidth; 165 if (clock.getShowStopButton()) workingWidth = frameWidth - runPauseButtonWidth; 166 iconWidth10 = (int) (workingWidth / 664.0 * 152.0); 167 iconHeight10 = (int) (iconWidth10 / iconAspect10); 168 iconWidth24 = (int) (workingWidth / 664.0 * 320.0); 169 iconHeight24 = (int) (iconWidth24 / iconAspect24); 170 iconWidthDot = (int) (workingWidth / 664.0 * 40.0); 171 iconHeightDot = (int) (iconWidthDot / iconAspectDot); 172 } 173 for (int i = 0; i < 10; i++) { 174 Image scaledImage = baseFoldingSheets10[i].getImage().getScaledInstance(Math.max(1,iconWidth10), Math.max(1,iconHeight10), Image.SCALE_SMOOTH); 175 foldingSheets10[i].setImage(scaledImage); 176 } 177 for (int i = 0; i < 24; i++) { 178 Image scaledImage = baseFoldingSheets24[i].getImage().getScaledInstance(Math.max(1,iconWidth24), Math.max(1,iconHeight24), Image.SCALE_SMOOTH); 179 foldingSheets24[i].setImage(scaledImage); 180 } 181 Image scaledImage = baseColon.getImage().getScaledInstance(Math.max(1,iconWidthDot) , Math.max(1,iconHeightDot), Image.SCALE_SMOOTH); 182 colonIcon.setImage(scaledImage); 183 184 // update the images on screen 185 this.getContentPane().revalidate(); 186 } 187 188 @SuppressWarnings("deprecation") // Date.getHours, getMinutes, getSeconds 189 void update() { 190 Date now = clock.getTime(); 191 int hours = now.getHours(); 192 int minutes = now.getMinutes(); 193 194 h24.setIcon(foldingSheets24[hours]); 195 m1.setIcon(foldingSheets10[minutes / 10]); 196 m2.setIcon(foldingSheets10[minutes - (minutes / 10) * 10]); 197 } 198 199 /** 200 * Handle a change to clock properties. 201 * @param e unused. 202 */ 203 @Override 204 public void propertyChange(PropertyChangeEvent e) { 205 updateButtonText(); 206 } 207 208 /** 209 * Update clock button text. 210 */ 211 private void updateButtonText(){ 212 runPauseButton.setText( Bundle.getMessage( clock.getRun() ? "ButtonPauseClock" : "ButtonRunClock") ); 213 } 214 215 private class ButtonListener implements ActionListener { 216 @Override 217 public void actionPerformed(ActionEvent a) { 218 clock.setRun(!clock.getRun()); 219 updateButtonText(); 220 } 221 } 222 223 @Override 224 public void dispose() { 225 clock.removeMinuteChangeListener(minuteListener); 226 clock.removePropertyChangeListener(this); 227 super.dispose(); 228 } 229 230}