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