001package jmri.jmrit.lcdclock; 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 Lcd tubes. 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 Ken Cameron Copyright (C) 2007 029 * 030 * This was a very direct steal from the Nixie clock code, ver 1.12. Thank you 031 * Bob Jacobson. 032 * 033 */ 034public class LcdClockFrame extends JmriJFrame implements PropertyChangeListener { 035 036 // GUI member declarations 037 JLabel h1; // msb of hours 038 JLabel h2; 039 JLabel m1; // msb of minutes 040 JLabel m2; 041 JLabel colon; 042 043 double aspect; 044 double iconAspect; 045 int runPauseButtonWidth; 046 047 JButton runPauseButton; 048 049 Timebase clock; 050 private final PropertyChangeListener minuteListener = (PropertyChangeEvent evt) -> update(); 051 052 NamedIcon tubes[] = new NamedIcon[10]; 053 NamedIcon baseTubes[] = new NamedIcon[10]; 054 NamedIcon colonIcon; 055 NamedIcon baseColon; 056 //"base" variables used to hold original gifs, other variables used with scaled images 057 058 public LcdClockFrame() { 059 super(Bundle.getMessage("MenuItemLcdClock")); 060 061 clock = InstanceManager.getDefault(jmri.Timebase.class); 062 063 //Load the images (these are now the larger version of the original gifs 064 for (int i = 0; i < 10; i++) { 065 baseTubes[i] = new NamedIcon("resources/icons/misc/LCD/Lcd_" + i + "b.GIF", "resources/icons/misc/LCD/Lcd_" + i + "b.GIF"); 066 tubes[i] = new NamedIcon("resources/icons/misc/LCD/Lcd_" + i + "b.GIF", "resources/icons/misc/LCD/Lcd_" + i + "b.GIF"); 067 } 068 colonIcon = new NamedIcon("resources/icons/misc/LCD/Lcd_Colonb.GIF", "resources/icons/misc/LCD/Lcd_Colonb.GIF"); 069 baseColon = new NamedIcon("resources/icons/misc/LCD/Lcd_Colonb.GIF", "resources/icons/misc/LCD/Lcd_Colonb.GIF"); 070 // set initial size the same as the original gifs 071 for (int i = 0; i < 10; i++) { 072 Image scaledImage = baseTubes[i].getImage().getScaledInstance(23, 32, Image.SCALE_SMOOTH); 073 tubes[i].setImage(scaledImage); 074 } 075 Image scaledImage = baseColon.getImage().getScaledInstance(12, 32, Image.SCALE_SMOOTH); 076 colonIcon.setImage(scaledImage); 077 078 // create the run/pause button and get it's size 079 runPauseButton = new JButton(Bundle.getMessage("ButtonPauseClock")); 080 runPauseButton.setText( Bundle.getMessage( "ButtonPauseClock") ); 081 runPauseButtonWidth = runPauseButton.getPreferredSize().width; 082 083 // determine aspect ratio of a single digit graphic 084 iconAspect = 24. / 32.; 085 086 // determine the aspect ratio of the 4 digit base graphic plus a half digit for the colon 087 if (!clock.getShowStopButton()) { 088 aspect = (4.5 * 24.) / 32.; // pick up clock prefs choice: no button 089 } else { 090 aspect = (4.5 * 24. + runPauseButtonWidth) / 32.; // pick up clock prefs choice: add size of a stop/start button 091 } 092 093 // listen for changes to the Timebase parameters 094 clock.addPropertyChangeListener(this); 095 096 // init GUI 097 m1 = new JLabel(tubes[0]); 098 m2 = new JLabel(tubes[0]); 099 h1 = new JLabel(tubes[0]); 100 h2 = new JLabel(tubes[0]); 101 colon = new JLabel(colonIcon); 102 103 getContentPane().setLayout(new BoxLayout(getContentPane(), BoxLayout.X_AXIS)); 104 getContentPane().add(h1); 105 getContentPane().add(h2); 106 getContentPane().add(colon); 107 getContentPane().add(m1); 108 getContentPane().add(m2); 109 this.getContentPane().setBackground(new Color(0xFFFFFF)); // set background to white to match lcd 110 getContentPane().add(runPauseButton); 111 runPauseButton.addActionListener(new ButtonListener()); 112 // since Run/Stop button looks crummy, user may turn it on in clock prefs 113 runPauseButton.setVisible(clock.getShowStopButton()); // pick up clock prefs choice 114 updateButtonText(); 115 update(); 116 pack(); 117 118 // request callback to update time 119 clock.addMinuteChangeListener(minuteListener); 120 121 // Add component listener to handle frame resizing event 122 this.addComponentListener( 123 new ComponentAdapter() { 124 @Override 125 public void componentResized(ComponentEvent e) { 126 scaleImage(); 127 } 128 }); 129 130 } 131 132 // Added method to scale the clock digit images to fit the 133 // size of the display window 134 public void scaleImage() { 135 int iconHeight; 136 int iconWidth; 137 int frameHeight = this.getContentPane().getSize().height; 138 int frameWidth = this.getContentPane().getSize().width; 139 if ((double) frameWidth / (double) frameHeight > aspect) { 140 iconHeight = frameHeight; 141 iconWidth = (int) (iconAspect * iconHeight); 142 } else { 143 // allow space in width for run stop button 144 int workingWidth = frameWidth; 145 if (clock.getShowStopButton()) workingWidth = frameWidth - runPauseButtonWidth; 146 iconWidth = (int) (workingWidth / 4.5); 147 iconHeight = (int) (iconWidth / iconAspect); 148 } 149 for (int i = 0; i < 10; i++) { 150 Image scaledImage = baseTubes[i].getImage().getScaledInstance(Math.max(1,iconWidth), Math.max(1,iconHeight), Image.SCALE_SMOOTH); 151 tubes[i].setImage(scaledImage); 152 } 153 Image scaledImage = baseColon.getImage().getScaledInstance(Math.max(1,iconWidth / 2), Math.max(1,iconHeight), Image.SCALE_SMOOTH); 154 colonIcon.setImage(scaledImage); 155 // update the images on screen 156 this.getContentPane().revalidate(); 157 } 158 159 @SuppressWarnings("deprecation") // Date.getHours, getMinutes, getSeconds 160 void update() { 161 Date now = clock.getTime(); 162 int hours = now.getHours(); 163 int minutes = now.getMinutes(); 164 165 h1.setIcon(tubes[hours / 10]); 166 h2.setIcon(tubes[hours - (hours / 10) * 10]); 167 m1.setIcon(tubes[minutes / 10]); 168 m2.setIcon(tubes[minutes - (minutes / 10) * 10]); 169 } 170 171 /** 172 * Handle a change to clock properties. 173 * @param e unused. 174 */ 175 @Override 176 public void propertyChange( PropertyChangeEvent e) { 177 updateButtonText(); 178 } 179 180 /** 181 * Update clock button text. 182 */ 183 private void updateButtonText(){ 184 runPauseButton.setText( Bundle.getMessage( clock.getRun() ? "ButtonPauseClock" : "ButtonRunClock") ); 185 } 186 187 private class ButtonListener implements ActionListener { 188 @Override 189 public void actionPerformed(ActionEvent a) { 190 clock.setRun(!clock.getRun()); 191 updateButtonText(); 192 } 193 } 194 195 @Override 196 public void dispose() { 197 clock.removeMinuteChangeListener(minuteListener); 198 clock.removePropertyChangeListener(this); 199 super.dispose(); 200 } 201 202}