001package jmri.jmrix.dccpp.swing.virtuallcd; 002 003import java.awt.*; 004import java.io.*; 005import java.util.ArrayList; 006 007import javax.swing.*; 008 009import jmri.jmrix.dccpp.*; 010import jmri.util.JmriJFrame; 011 012/** 013 * Frame to image the DCC-EX command station's OLED display 014 * Also sends request to DCC-EX to send copies of all LCD messages to this instance of JMRI 015 * 016 * @author BobJacobsen Copyright (C) 2023 017 * @author MSteveTodd Copyright (C) 2023 018 */ 019public class VirtualLCDFrame extends JmriJFrame implements DCCppListener { 020 021 private DCCppTrafficController _tc = null; 022 private DCCppSystemConnectionMemo _memo; 023 024 final static int TOTALLINES = 64; 025 private ArrayList<JLabel> lines; 026 027 public VirtualLCDFrame(DCCppSystemConnectionMemo memo) { 028 super(); 029 _tc = memo.getDCCppTrafficController(); 030 _memo = memo; 031 _tc.sendDCCppMessage(DCCppMessage.makeLCDRequestMsg(), null); 032 lines = new ArrayList<>(TOTALLINES + 1); 033 } 034 035 /** 036 * {@inheritDoc} 037 */ 038 @Override 039 public void message(DCCppMessage msg) { 040 } 041 042 /** 043 * {@inheritDoc} 044 */ 045 @Override 046 public void message(DCCppReply msg) { 047 if (msg.isLCDTextReply()) { // <@ display# line# "message text"> 048 int displayNumber = msg.getLCDDisplayNumInt(); 049 if (displayNumber == 0) { //TODO: add support for multiple LCD displays 050 int lineNumber = msg.getLCDLineNumInt(); 051 if (lineNumber < TOTALLINES) { 052 lines.get(lineNumber).setText(msg.getLCDTextString()+" "); // padding for appearance 053 pack(); 054 } else { 055 log.warn("Received LCD message for line {}, but configured for TOTALLINES limit of {}", 056 lineNumber, TOTALLINES-1); 057 } 058 log.debug("Received LCD message for display# {}, only display 0 supported at this time.", displayNumber); 059 } 060 } 061 } 062 063 /** 064 * {@inheritDoc} 065 */ 066 @Override 067 public void notifyTimeout(DCCppMessage msg) { 068 } 069 070 /** 071 * {@inheritDoc} 072 */ 073 @Override 074 public void initComponents() { 075 super.initComponents(); 076 getContentPane().setLayout(new BoxLayout(getContentPane(), BoxLayout.Y_AXIS)); 077 078 Font font = null; 079 // load the custom 5x8 found 080 try { 081 InputStream stream = new FileInputStream(new File("resources/fonts/5x8_lcd_hd44780u_a02.ttf")); 082 font = Font.createFont(Font.TRUETYPE_FONT, stream).deriveFont(16f).deriveFont(Font.BOLD); 083 } catch (IOException e1) { log.error("failed to find or open font file"); 084 } catch (FontFormatException e2) { log.error("font file not valid"); 085 } 086 087 var pane = new JPanel(); 088 pane.setLayout(new BoxLayout(pane, BoxLayout.Y_AXIS)); 089 // initialize the list of display lines 090 for (int i = 0; i<TOTALLINES; i++) { 091 var label = new JLabel(); 092 if (font != null) label.setFont(font); 093 label.setOpaque(true); 094 label.setBackground(Color.BLACK); 095 label.setForeground(Color.WHITE); 096 lines.add(label); 097 pane.add(lines.get(i)); 098 } 099 pane.setOpaque(true); 100 pane.setBackground(Color.BLACK); 101 this.add(pane); 102 103 // set the title, include prefix in event of multiple connections 104 setTitle(Bundle.getMessage("VirtualLCDFrameTitle") + " (" + _memo.getSystemPrefix() + ")"); 105 106 // pack to layout display 107 pack(); 108 } 109 110 private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(VirtualLCDFrame.class); 111 112}