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