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