From 1de426f2bcfb538f996d49e4eb72fd58f9fe9896 Mon Sep 17 00:00:00 2001 From: Frans Jacobs Date: Sat, 18 Jan 2025 16:11:27 +0100 Subject: [PATCH 01/24] Refactor Tiles, WIP --- nbproject/private/profiler/settings.xml | 9 + .../profiler/snapshot-1736349327025.nps | Bin 0 -> 14196 bytes .../commandStation/autopilot/AutoPilot.java | 6 +- .../autopilot/state/Dispatcher.java | 8 +- .../virtual/VirtualCommandStationImpl.java | 101 +- .../jcs/persistence/H2PersistenceService.java | 13 +- src/main/java/jcs/ui/layout/LayoutCanvas.java | 690 +++++----- src/main/java/jcs/ui/layout/LayoutPanel.java | 12 +- .../java/jcs/ui/layout/LayoutPanelTester.java | 3 +- .../jcs/ui/layout/LayoutPanelTesterRO.java | 3 +- src/main/java/jcs/ui/layout/RoutesDialog.java | 5 +- src/main/java/jcs/ui/layout/TileCache.java | 414 ++++++ .../ui/layout/dialogs/BlockControlDialog.java | 8 +- .../jcs/ui/layout/dialogs/BlockDialog.java | 9 +- .../jcs/ui/layout/dialogs/SensorDialog.java | 4 +- .../jcs/ui/layout/dialogs/SignalDialog.java | 4 +- .../jcs/ui/layout/dialogs/SwitchDialog.java | 4 +- .../jcs/ui/layout/tiles/AbstractTile.java | 893 ------------ src/main/java/jcs/ui/layout/tiles/Block.java | 268 ++-- src/main/java/jcs/ui/layout/tiles/Cross.java | 55 +- .../java/jcs/ui/layout/tiles/Crossing.java | 22 +- src/main/java/jcs/ui/layout/tiles/Curved.java | 45 +- .../jcs/ui/layout/tiles/DefaultTileModel.java | 289 ++++ src/main/java/jcs/ui/layout/tiles/End.java | 51 +- src/main/java/jcs/ui/layout/tiles/Sensor.java | 45 +- src/main/java/jcs/ui/layout/tiles/Signal.java | 51 +- .../java/jcs/ui/layout/tiles/Straight.java | 44 +- .../ui/layout/tiles/StraightDirection.java | 22 +- src/main/java/jcs/ui/layout/tiles/Switch.java | 86 +- src/main/java/jcs/ui/layout/tiles/Tile.java | 1216 +++++++++++++++-- src/main/java/jcs/ui/layout/tiles/Tile1.java | 221 +++ .../java/jcs/ui/layout/tiles/TileFactory.java | 395 +----- .../java/jcs/ui/layout/tiles/TileModel.java | 85 ++ .../tiles/sandbox/AlphaButtonPolicy.java | 91 ++ .../tiles/sandbox/BasicJogShuttleUI.java | 156 +++ .../ui/layout/tiles/sandbox/FocusExample.java | 86 ++ .../tiles/sandbox/FocusTraversalExample.java | 38 + .../layout/tiles/sandbox/InvokeExample.java | 115 ++ .../ui/layout/tiles/sandbox/JogShuttle.java | 154 +++ .../ui/layout/tiles/sandbox/JogShuttleUI.java | 11 + .../ui/layout/tiles/sandbox/SimpleModel.java | 84 ++ .../tiles/sandbox/SimpleModelInterface.java | 24 + .../jcs/ui/layout/tiles/sandbox/Sketch.java | 85 ++ .../jcs/ui/layout/tiles/BlockTileTester.form | 220 +++ .../jcs/ui/layout/tiles/BlockTileTester.java | 403 ++++-- .../jcs/ui/layout/tiles/CrossTileTester.java | 40 +- .../ui/layout/tiles/CrossingTileTester.form | 197 +++ .../ui/layout/tiles/CrossingTileTester.java | 253 +++- .../jcs/ui/layout/tiles/CurvedTileTester.form | 197 +++ .../jcs/ui/layout/tiles/CurvedTileTester.java | 239 +++- .../jcs/ui/layout/tiles/DotGridCanvas.java | 70 + .../jcs/ui/layout/tiles/EndTileTester.form | 197 +++ .../jcs/ui/layout/tiles/EndTileTester.java | 239 +++- .../jcs/ui/layout/tiles/SensorTileTester.form | 208 +++ .../jcs/ui/layout/tiles/SensorTileTester.java | 254 +++- .../jcs/ui/layout/tiles/SignalTileTester.form | 208 +++ .../jcs/ui/layout/tiles/SignalTileTester.java | 436 ++++-- .../tiles/StraightDirectionTileTester.form | 197 +++ .../tiles/StraightDirectionTileTester.java | 235 +++- .../ui/layout/tiles/StraightTileTester.form | 197 +++ .../ui/layout/tiles/StraightTileTester.java | 236 +++- .../jcs/ui/layout/tiles/SwitchTileTester.form | 208 +++ .../jcs/ui/layout/tiles/SwitchTileTester.java | 354 +++-- .../java/jcs/ui/layout/tiles/TileTester.form | 175 +++ .../java/jcs/ui/layout/tiles/TileTester.java | 170 +++ .../ui/layout/tiles/UnscaledBlockCanvas.java | 72 +- .../layout/tiles/UnscaledBlockTileFrame.java | 42 +- .../ui/layout/tiles/UnscaledTileFrame.form | 5 +- .../ui/layout/tiles/UnscaledTileFrame.java | 118 +- src/test/resources/images/DHG 6505.png | Bin 0 -> 25034 bytes 70 files changed, 8279 insertions(+), 2816 deletions(-) create mode 100644 nbproject/private/profiler/settings.xml create mode 100644 nbproject/private/profiler/snapshot-1736349327025.nps create mode 100644 src/main/java/jcs/ui/layout/TileCache.java delete mode 100755 src/main/java/jcs/ui/layout/tiles/AbstractTile.java create mode 100644 src/main/java/jcs/ui/layout/tiles/DefaultTileModel.java mode change 100644 => 100755 src/main/java/jcs/ui/layout/tiles/Tile.java create mode 100644 src/main/java/jcs/ui/layout/tiles/Tile1.java create mode 100644 src/main/java/jcs/ui/layout/tiles/TileModel.java create mode 100755 src/main/java/jcs/ui/layout/tiles/sandbox/AlphaButtonPolicy.java create mode 100755 src/main/java/jcs/ui/layout/tiles/sandbox/BasicJogShuttleUI.java create mode 100755 src/main/java/jcs/ui/layout/tiles/sandbox/FocusExample.java create mode 100755 src/main/java/jcs/ui/layout/tiles/sandbox/FocusTraversalExample.java create mode 100755 src/main/java/jcs/ui/layout/tiles/sandbox/InvokeExample.java create mode 100755 src/main/java/jcs/ui/layout/tiles/sandbox/JogShuttle.java create mode 100755 src/main/java/jcs/ui/layout/tiles/sandbox/JogShuttleUI.java create mode 100755 src/main/java/jcs/ui/layout/tiles/sandbox/SimpleModel.java create mode 100755 src/main/java/jcs/ui/layout/tiles/sandbox/SimpleModelInterface.java create mode 100755 src/main/java/jcs/ui/layout/tiles/sandbox/Sketch.java create mode 100644 src/test/java/jcs/ui/layout/tiles/BlockTileTester.form create mode 100644 src/test/java/jcs/ui/layout/tiles/CrossingTileTester.form create mode 100644 src/test/java/jcs/ui/layout/tiles/CurvedTileTester.form create mode 100644 src/test/java/jcs/ui/layout/tiles/DotGridCanvas.java create mode 100644 src/test/java/jcs/ui/layout/tiles/EndTileTester.form create mode 100644 src/test/java/jcs/ui/layout/tiles/SensorTileTester.form create mode 100644 src/test/java/jcs/ui/layout/tiles/SignalTileTester.form create mode 100644 src/test/java/jcs/ui/layout/tiles/StraightDirectionTileTester.form create mode 100644 src/test/java/jcs/ui/layout/tiles/StraightTileTester.form create mode 100644 src/test/java/jcs/ui/layout/tiles/SwitchTileTester.form create mode 100644 src/test/java/jcs/ui/layout/tiles/TileTester.form create mode 100644 src/test/java/jcs/ui/layout/tiles/TileTester.java create mode 100644 src/test/resources/images/DHG 6505.png diff --git a/nbproject/private/profiler/settings.xml b/nbproject/private/profiler/settings.xml new file mode 100644 index 00000000..31c9a1f4 --- /dev/null +++ b/nbproject/private/profiler/settings.xml @@ -0,0 +1,9 @@ + + + +10 +#org.netbeans.modules.profiler.v2.features.LocksFeature@#org.netbeans.modules.profiler.v2.features.MethodsFeature@#org.netbeans.modules.profiler.v2.features.MonitorFeature@ +true +ProjectClassesMode +false + diff --git a/nbproject/private/profiler/snapshot-1736349327025.nps b/nbproject/private/profiler/snapshot-1736349327025.nps new file mode 100644 index 0000000000000000000000000000000000000000..194a49f32e0d7900b9edfda03217f697cf01e92b GIT binary patch literal 14196 zcma*Nby(X=_b&=L<*Psm) zx#`~Td4K1gXYYH@KP&T{S!-sNeP+!(aeM>Tbdt4I25F)`LP0@6MM2?yhk~*$=$Uck zg9)XSOZ;W0UklPta=2~>8P>>2STUG7m#@7|D)%J3{=~2p_A$QR%0SaF|9J2sk{wO@ z1tsmbCr>@*UJDUFrD2Exr@J;g5$io#H;F!!YtoN??SEMIr7|rm>q}Z}x#h3lKBAJ} zw5K1u<-VWp&kCcMt#u^3sorlqx%=R_e76a6HFsZ?@8gMoEfLGR-9)C6ItJzg;>vs| zr)2{QW0q<30Mb=?Kp-<+rk&1m`Dq2c%A5eAy~y-xv6H4P1_x_B6cfxA6>AmIr9G>j z=h;$Uk3bldymp@ri^(Eh1+$Ad^eZn28m7uVJ70ZOb=3DJEml|fF+owsQKB$BNGSSfNZOIrWj>* zp4aPJvM4pKE4%Q$7u9DAA|s`$YkSLgEaXVHv)!84iUVhVoE|jKDk}O&CH8eR7s%kT znzu_d5KvUEyIEWGnkr82h;r`(&9S+bd zq(eEGA5D03%{Om|-Wlym{!d^wf=OS9C1>Q7f};cP>g{k);OhM6jxn`w&xIDZ7RQ{wt4JNC?4@+; zp1pYX98;_ZRs5y?_NoIj}cA5OEcm`(+W0)QJgs}Oh`mL@K;+)^Y=JA#7R$4GY8*$I;`x`f(m7UceWEb6_~BYHl9BuF#zb!3uvmpp zUxd)JqYI5OSe2CYjb0Q^tD64~-JYUj!BjHYE~9j1m+k5Gv=R7O&`dH_E1)N85BhBI zT>s{2(pjJK+k9BAnxT1SI$5-pgEh|<04Ou4H>pLYJxj*%@=}x4j#szq&H0?QcRuxu zt8+aSK4&3O-qg#%0fjmtK6Azi94m4)b3@kZcZNd+ADas#K{MY7aWz=0++GH5n{CGl z_O|CJ%&Gl00j6kuJ&L?JqIQi=)B?>>Hkc`((sXDA6f#W9xy!b(4}#etW$BIJC?$=p zLUuOe!*v9hD!7|t%)(Tacy%)3${_XhjYm?MRDg{s-4SzYW>;Lpt+rArSO3rrj(3>b zaF;!AZ1t4B-pDGxRuAdim%P%N$z)p~M2Swu^1ZoK*H-VNu!sUegKX8*1zJH~;%te} zIk!YI;aZv-EHTFmHOn>@4Bj*D=Q#uH{0_!3#Ef&?SQzg;Z@F!lg$z?`lq={D+J+eL+?h5TT#j84NXOaj`P#^+Xp;vgMW> zAVx-qnr_9^c-=U@!KqPT-@G76N|}Gd8mGGu8 z&umc0myt{K@(xfo<|I;CWk;yue(^Xv&mrQ7wa%{MjCO>&+X^NIE*ECnDqtqESv*>n zo2R=hV>C)1-dLPZ=BE0LC?qRkdem}6`xQ$2iX3}Pm{*uen75abYdilqIgG`3hBICy zYW*qiI-7O{A#o;S6z}n-AzPW;@Ebxo)!GZ!x>SV=zrK{O%Q~tpxUeyImK_FpqR&+0 zdJ3ZER?hQ_g}e9*5tn+T{p_PtD-M9OBjV_CMQ@_JaL&~#4d=;Ed$F|hO^Nn2FngZmGgz%H`DLQ;yTa)Xwo&F%FEAURVj*P69zH@vT!Kk2s`F_-sGqCoDPhiUv~u zV9{=|J*4&+-1RAoxDpEZBCI=qd^=z;rpli4H z*yTk+-$))-P;VO^O zrD%5F0uQa2A`%WFA@r#62fa@Nl)oXABiaBM81I{5iagV4)r!2D?YHW+Z``9YSzYI! z8xVaUu9heOq>ugtQj~Kj=jxofeCnV4%`#{qVIJ#YV=dRhvOEO-$v($RFTX z#_TkAx5Z~S7C;`~o0l6mr1X3nbeJ&r01jqu8>->sPSXyU8a=d_Pae@2g9f+i4Vl;Y z*RW7pUr0+2sQyY(ouZ<@uifE}FiwWx0Wln-HdxSxAM47s#4-ug@@`M}K$lj&9G&a_ zM3nc_QPG^PEXuizm4w=S!T3P0`QF*sFRY#xYihX1x@)iSZ{&!m=%2PpJ-J2)4%gf7x7u^+75uHyh0&^PXjng;cx%y>w&mR*%*O?=& zT$~y4WDJIu#FOw?FtDZx+G9?0Wa5-sXxYuBvJN5y<5y_U z9j00|M}A4Qb3`0QeS|g?)k2Hc3T#B(v52XJy`q>ixEIB2PZ+ZVEo9d|g^cX;P$^w? zUt$W1FYMIrV7N+4LmUlODloFqF%8boby%1_c~-~4ovdZ>3F-h!ih~4fOWMUj);pB# zt>2S;x|XcD`eClSGS2DQOMU*UnQ7@fEx# zWm!#eaqSDotUJAqZYJ`EJ9&X~3Z@ctcDcQ0HKTLb(H1JTKepRn$7IzyXSnGWeF_&~ znH#j=jtdtPcd5K29H2n+3gx%l)?6s77?dKpyHFL3J)b}GDr&XgP2R6%04{%Q*G)Q$ z5cR$1Ll@HfX}>`2JXBh<++$uEZt4@WYR;A@dnq7y^Luz*Zh2uwzpMIpf|=J3Iwtl3 zT||8__RQU#@s_;pfD#$+^Gd;I4wA=J9@kE$4j&49q6|?Vieqx>`tx)GBCCHGp)c16 zw>tzWrD{n{_v_v0Ip6eMscxeqaLFQC8WK#RqL#Pk&88v+)cESg+qbuk70SH6OUwZl zZawyXm8oe+MBVaJcpQhMSl~oUT%}}wYM7M7m?WxJ4n00y&|}}$?o$SO2~rQu**O*B+yOkvByV#L*L{R{jUA z@;@G868+6^Exo7rzfL&UT}@c}+e1?n=|hK8=1_qe}nDH6y`=)H)2H&wl9>u&94IX6H>!7$ra(MFX4=5()V z|11&P;iP#Sj0nqFRIxtdzW6vPkl62*S?xAc`}XHpQ#zM|WA%;ts0x>>sz=Nw^t85L z5$Fr@v0Fx#m)oik%E`Dxh|tii8s6_6EkA0f*=u;q+Uy4rKa$(C zsEXd;Z#aHS_K~M5&rGF>ZS{b?0A~XT)SVKj(|u2{{nj&HH-^1MN+o|d_2mt2i=Lx$ zk4>IlmUG#a@KJi@8&P2k=2l(PAH>EWuQ#Ay$($d!%bqy`4%jHZ<^A?mufj|urIEf# z_58g>fLqd=iuvk-zieDwfNztLM~Ga;wPNkfHT$bI=@ygT0GEd`O%~vOLX{Fk5Vh&yze@;OpV+`19;#yoUO0%J* zHvO#UR$TJz8H#RF5Z+{Z#eRbNY8q&}Vpv+BsAHnquE!_!1GX;^qVH5R!55Y28R}{D zi@3MD)OJ@l{yVO>Vi_+emF>}VQkyWdX(w0m3<{H{8pDqQg>TrdRx(@z?t9O&JJ?r3 z72%E^S{COivU6$hivtB-5OYnaaI`6w%PIQyL~VV|qqcDN@AcaHWV(gYt%nb9#TPj= z@!ASn*q6)Re&vrl*(NO5>cBHR)+=|gdD^xlG4@&ifzCm7zg|BjH~#EmxZ&eqe6E`G z>+FPsqPCKp)6o5hp2ysJo~{8V2{_A=P8ViFV~xaLGRSzI>xQQC&yHjFA7y1WU`@pt zg>!$dD^F&~Mm?@q@Q%BpoP$|<`3#Vg1(}rdU%}-Y#fT4-D76B-q&Gi>cW`yixhTc5 z17e=2jzM~_?-w-P9g=%0M*>jKT6jZiG*C z<;x{K*?M%XLAhBo?MSVlg9st$TH%UTLJGQbtsm@C?BD<{xQ}BNHt>JXejO(33)SB`$)m- z#EMlPG58{X#1eiwN7vu1FpF2``y!i2qK{d|P95d5AY0S+YGF)M;;RiJOIN795JN!n zNQkEJPmd!k_lq_=J;!N8dz^5^P%LZMg6SKa8}(@t?Q{}CCz9X%3D2Vp5B zb28K1(#|HSBC*g_U&HG{G#bRF*6WeUPARo=gxG-n25x9^hkYj`g03_*sE!*rVk?|9 zWUdpo_&(PS4?E`XpR%M)hoH8GjYU;o;}cP6CUVQXFU{T zylp%9vR5Z5$k#UmNl`l6Z)zoDGW!V?uDH{wV!!g@1gtk&>1lBTG&L}YzdFb@+O|m8S~*< z>V6blsO)d=pvU^A4kuPVH-UPiGt5VHe`Xfap8LWX)0OF|fK6n;TMm#+QC!iORpCsf z`hKt&6Le;HC_|dgk>%$377Y^Q4#>!`wU-+IAz0GR?NaYckaqvQg3Pi%m+z3xl(OtAHlI7LM@| zO2T67h#~3x+-;R}ODap3K!A}U#v2Qb+1s&h&v;_1MhW$mpa4Uj`2*^-0RpPH2^!WD zMoW>nQq$86S3&}}^vdnrJI1Mvv6u)z&B*kH237Jkrpvw>oGi9UG;lN_JzBL8MCUii z>++s5lWsWwfOHdczmYqmDxlm#AuxV!Q-L1yk>PUjfW0qj-HXeOPYl;Cr&uY)o4G0H zRJEA}YRxi^%Mr~)rYQKuemo{W%>`w~WM}fxsCrKeQ)yj?AO|m2--~V4-PfjmwTVTi z(j6ja+DQvd6?))7F{L@o(Qlz>vDW@v(d#|IPm~I1V3*-cEmIsRArANe)USyJ!mZ|3 zLv;>ff1k5o*^}30-m*8DC^i5y3$sKQ)Mog=>aHXMU6y?+*13|^lONlABq+_uM>}A!7Jpb0Vg`LXXx*@UCLu+PMM&;yS!87?-i-6|4yyn9|&@{?^6`Qj0?GZ0sR-}qb?OTlk zO`Cm_LOk)KmpaCtDzv>$znwJ13PuTMsK4^)y@S@#mDcN6iDafRe5+}gh3DZ>mlHZZ zohCWjXi6uS(@YWXadhx~Uz(`=%3x0Qp-YBVq=bg>YEo`bvVtr>8)?{;D z%<;0SYj;*RT%Rv*B|G=u3g@_Rz_WkGhw&Q5 zvC_F%NDmh*T2DbWjIb(6(sJ1%wt2D~N>f3GnUD{uwWoVmXK3F~r?)omrl+G;n7(~d zLCXS*u_=k2QdV*9ucqpa$X7dNHi%;bEkDOX#virO)eO)P^QS1$p_L(I9E!3Vl5agV zYJF6=u%mbP$hnWe;DkBh2{Nve^mZ8{y&f4!ugYZzw~6K}DK@<{9!TLk{k)e{JY0#N z9UlK2rnXBt^bp_N?DMX$&wohnSdVmJ74uP>s()kL9(v$jgJBY`hEXw6Lt8HEj`e%f zm+hx%H&ymoqD27hF~pJH4jaem_wd7YxXk@{47X}16ByF*VW=Z{vT7!^_=5ae2hTx) zS4HfHBIH^ty!K5ga58-~43q6SRgK(eB$Z13{H{59v1Ep81E_E`;em}FmM%q9@NxG= zbA>~$N?QF-(@iPg0)I{uFTvQwQCjb22Ue>Hv9sZq3w0^Dn`a+tEo(H#q7HG4wkZ60 z2VrmPv4g}oe%32!0L0V`75u(U?$`?N<{3@`0jzI$W+>j?Eo$Xve|X947Im=c=l9Z6 zv{kJqJ~_MkrIgTgnd@xW_S9R5u6{OHSjCgwLHNQKv`?~?K6Vxps{)X{Gu&t2TsnNy4KDuR>$?U`<}rkn`HC`aH*LsB?(V z`;Pi|3Y7Qhk5`M{sm(fi>?=u%S zwUv{LZb}WN6(3f(7E=bF+b`H3Rf3xcZr7#Vq_JEMUd0>Qm3~cJ6}4je1^>`*law@8 zuXEo3l<^9cF%E7PT+ZnD^oDJKa3A$LRWmL9p^ic)mZQz#eA?E}rXbCiD3n-<8MrO? z3Ig!KACIFU9Pr441cux{(NE5TW+hWl*46d%Sf;kM+55@gNN3(%$USvu^%GGrX?8bR zq%1c|b7Sq$yypDT^xU-B^nT1hV%HxLM1H7oS9Y!w`Lvj|V`4(xRiCrRP$5<#>f1oy zc1&>YWfT8x!u?a7`#^JJsd&kIwpaHPkRZyPE6AkDvKqA$VQ?| zxtuh%o8x?%ObBR_mrrOcM@TvnJ1+A!t1f?*JmEINd=`&d9_`)!prkn>HRY^NxJDo; zyAmD2arql!ZgqFP`b8nKr;8-x>wAzfua5pSL1RLqK_3-c)59$$emm`pj0gDZ0q3kt ztEzTY);6{k9qKZ)NSzf-&R#7C@Ih)K-PaOg05xjT6pg+q!yGR8t*I8XWY4`tIGMWe z^#U3n`6t@;tS9dgDB3LR`Y4$GhA3n4EcaCz%HqTTl=~qesS9SAfST_9#{SL+IH^RN z*;_Zbw5&3QSZokty|HNgZ)4Gez-!z^8d5QW?Ha9qG$rP;Eyb&OQ;R=C!mCV6N%qjuC zPv0kST|aTvxn6JnqVy&ZtAxH|ct=F^)-;6Kp)|CN?j2ZsWEzH%ql=LpaxH?OoY`AD zuYQeT>K`nEpw%k~q6zlKwPz3Q74hU`*XY{h)!LFh)mL9~|Kf!4HRkPp&@F$#zImx_ z#Fl@%o~qW*GFESLj!-U`5oH6_r2H8*6gX?H$^|e?ab}8fiK9m z>rsBh^4RIw)nY(P<}{L&lcA2F3~_q)OsBe&)5up_VwYk-f_H)^>0r&Z`VB_*cMm=i zvqGfhbobWe%p1^UKQzi>oCG(BAfA*@!xoqa$>VBaVn*`i=Jy_a?tJ;1Njr!kZHZrv z6nC4rj{)zV4g0hKBv5cg5PbF%upP5}fCOGT1de8--L+flOA?8(M)2aY?W`r625$$G z$1`#chbYqBssYd*N&K0hJ!uYy5&DPRVj1v4n^;DL@So!@nT%$3ylx~l4XzVG2y*2H zun~6_5M-edean5%SRdIr`ud#Io4iR?EJVzE-Bv^>Xsa^dq~K4iYAx98lQmy;p|kmkD7EaI&iZpf+X?ACt;HG z%f$qhSnoyD_>*{aDo9(BjqNl6d%$s;fn~oAefRi5Udh;@Gd&RQN&+SY>g?=Y9f4UyJ?NHjD3G3V)az$vrzSPhY!duxWo`)ZT!xc-YL(>2y6`?JX zFmc3_4+CGsf80Ie-n@93@*B;QO&zb~{fem<7PWN6D#n8xhU8PHX_%k?SG%=lr8N_( zR_x9to-H9M{5&i&QaS?BF1dvZO5stSOB!W1B)8dLby@Kjtm;z`fVUOV& zR8U@k6+he<&MAVpg9u1r`o%}bB*JO-o~CxM^Z7mA_Rn-&Q}Z10UnHh{Vz>4a-UM*B zrBCiAQvbj_;+JLaZ#pS4rUfVE@hsNJ4eGEMnSyojyyS=9Udtu|Rvbs>VDBi9h(eYx z@{|O9qryFNyFe_Yz=>yje@%^?Uj)(LCx&bE&U|Kn4Yv1@_0lSb=2# zYQaWipinF!aS-w4vqSdiU$I5hUKHeqYl_#EyT)v^pZ?;4+iYF;{Z=A4!@!GC>`g^0 zK|8MRm!Q>h>w8x5^Xv(Zw`iPcGT-nSTc1(S!5rW;A_!SThX{fgkqYpAC6*T?i6i+P zwpvIPL*N_f{`zH;FVT^I0vu!^Vu)qRR#aCA*XPbuSyxZCIHD@fg- zTyk%LiDvxpl6uVcqTJ&`f1lE2Yxl%lut23TK2M^NGTuHy z6ajoGph_5i)YMZj$si}YwZd6A6;&%*ds&d^`UjEuz>|ZuolZOmoMJsxN{A3YKl0V2 zkZ!jE{V%Mk6RmHhA0K3oim*%?Ll#vSe<<3e5*!y-ekI5%KoVafx3)z1?~;Rxk2D2I zYM2iJ1`F4w{c^H`Z2t$~lKhy+-_r-oZWxBK=5TeY12X^+(j3?N$M! zgPM94MiV4?utw8qiX8V8yzih4onC6ZNr;eShIS^F*+|ldT6Yh1S07v12;ortHk;O+ zzi?ihJw#1;XnufeMd+cGi# z`bg>FkePsc^OSLMhh^P#LP8GkuJenC-lf&zQ4Aqd_B{#rW8I^iek^!c+YqNE0-$gv>Z)GvQ!kpaTQE*WzDE4hJ zGNf)zF#J-E;m^P(A?pb-VQcw34T? z3@{~Me|XP$tFx$u-NeN;@Sceu%!$k}tIkCO?tQipHZuppxpok zS}WW__@%{Mj06r^kDJulK1?6~=Ea`zjGIQ+NpWQa!9A0kaRQvCv``avkgWM#2J@r{ z*?U}wBxCBx&s7Cu62@EA{T7z>sz2Wk;Vm35o6IHtNV)H~fQ2$bltHm%z1!bik)Swb zj`&DW=^wIW-tFPfH?@F(x(61oaa)4%po$oN=n@q{G$G?QYq&aaeX1W%v!`K4a4#ep zP_WO#H4u-u(l08D&kr}aE#Z`iJb*7flobgc{hg+-9&9zt4$(SJ!*Hd=LhK(bjJ^a2 zR`Ol#t@-qU{sg}uvD|Lm{S6kf3W%A>x6;Mz__(OY2$gK8acO!a;7cV?D_kjZ>wTpr zgUS!n8;;ufaikTIf||Zxg1HT5$#G<74f*Q0LDmJ7Cogs^C!o$nlJ=;U8b!qDOcW8A zWlj2QKuw7CGwohS1Z^{p;}dR%7$Ynid}$X}r~%GkAzb)R=gyx_Q)K527a^3) z-_i8`*hKYatRnCNZ>Ax+yKXH`2R!%~e?iTT+pV&4BMgbqN*wtOdYGncVrZ;TT~91c z1d&Br64GD4)cH}f?&<%^I~|b`^{$TGZXBXkFH|ZsmUWgtgdXBg8_H%@hi$m>g7Ug( z^^{O71jmGh(u);Z1>P)#lLXUq2K#YPdXcpj$_kxnHYp$pqWaI!U*!BFy&6qO;BWs_ z#EK~ro~5V!a)CUIx6=E2EbIMyDavSabCcYu{?e$Xc=IOM$P>zhx#+ME{xPLCxvPp$ z>q-;RW-(-fqL*V;%{DaxoCGG2AQq*e;rB7 z_1zj>G`UpK1ozbZnTm+28OWD4sxn)UX4mi1J?*aV8qMx8Mca=N^&Pn6im7DA} z5yoAh_%74u9O;Dj72pL+FeDeePyqgGs07)9r+^oByVYOlCi(tVI-Lwwu@A0|Z@x>i zgm+&jGGbDe4gKlqyB&(daUB2Cg#Bsy>iUBAe)Xbe3pN1Hw3bDO1?p2$>1 zHx(4vU0Wri;0F)W0pkIV0_4bp7vJQ!8}iDs+E0f^jFDSMJzh<>BX#!7TKrc0dSf?e zKHt=p)7Clk?RAZ@ypsTz)~6i23p$yiQ^&=;BEzAzZkF zMzeG0&i7MS9AAo@&q>L3PiSRlN9l)-``qymubA;ypC#`-;Z+~U?c?xftNo3n8}mVO zN!z2*#L%0!G(q9JYpxRoLF3)JR8Ul8h43Jb-Wx478a&r6N->~ugYF^-?Phg(Be@3< z>{0d9?Tf&T{l-3?g6T04k*P58AQ~5R5x!vKf}dF4()az_;`IyDy|OgII=AcRF)n%; z{t4a1=HCeVoG&ZmQbMcNPc+R z$@+{~2>cSPjhTzOpVN4GQ8?XxB(l+Z_{j|E;`Jgw1M@_Y7a z^wCe}5U?>E%b;;S^%^JD4`b^7LqC8RgI=QX+)iv5 z33p#WW(RBHV5X;`k2>s3?*mtTLLf)0-m|})o(vY3*zL&jI7uCR`b0h-F3?_e=PAv3 zSFs%;FA%#z6VYJQ$h%nUVOqa6G<6UmeUyJJ1Wfov9>`=2z>en# zRg+f6$PTiif>IkGZ(;MLK{SEJA_$H7ih!E$tNB5{x=g5`k2prVeeo|20#|ZKss`zk8$X{iV~0{$!qR(ZBpdByzt<@7AI zf%*zLVSl|Bxu#b18}};2+S1scy4lFp<@?fmzlYj8bovY@D8IVB{mRg;<@{*^1U` zFPwGy37U_7HQe~pLTJ+WY`wa~7{O7%@_TP-gct0yOG$iHWAUd?270j_7hZD1_s;}( z^z)Mvi{43&@c3kwQP6A;kN2f1A<{Q1vMGt@)Bxw)pC4@lsmY8K9M8B`@Q8kOl?y}Q zTETk);(ewMErM7A+5W>2_-C^Y0@;2?04Wn`6}qOFYmWEyP8IGBpKjvlg%t%O^b^41 z&(#=MV|gRzvrW~i7+-Pu}fQ%<|hV$16S$bHiAC%JL?iXEJ4JG z$6XE!7vNeiqRAq-zxw`IK*SAP<(vo@BMo(fXUd8pi;Q$AyE_f@7B|Bkox_A8VrLC) zy{l7bpza0-*?EB}NMQ$o)8>mKIVWB;p7l6=bccN=?YVJyU5_=%wB|x*A;B)z>Wa~^ z6u&Y;k1jBR7`{A@P}?tb#Wwdf6!B@ubimg-?n}P@z~1z`(037S%zzkn??peDCCcT? z0vDs<9hl!hzV*m@#sb>WOv-~yu|3e&)Xm@#-wa&Vzccn)l~2Gvle6(x*Zj~cM7~m$ zAz!H`X_VH>YjiO>X7q}KXz+DHx@2tSdHu{?u5@;bFT{W1u9`e#ap9d|3c70CUjId`Dg;3h&PL28ICMRNsm%}UN@;AKxsX^ImjjR>;_4aawJn8}AZ!*|AG@lHgcC~uoz znweB$r6iX<+TMB@w8#GV%BkGOding|Ap9Ip;*g}`(S4<9Jr;ty!)A-iAV`1;n)>I{ zpu>ihQWXf{!ku3Vd8B(-b#+WCP5B+QH|g48IMMGzUzZ!xk3qxaXa`?#rYW1NkUZ+u4i0h5Sd zyK8N-RRonUg2juwcY&-geTUyszl}7iw$4!R8d&2fDG^kyB?K>J-xAV=;H)@hOu<(9 zDraGSe3jT;!2#=>#@h3%>t9Yuqcsd8KLR8i8QiMv^h6NBeKCOc@1%1uQ$E=QIJ-;3 zN;$9krD$4JV#@KM>)l&AS&sSq>n|UHe5Q$TjkGFC0EQ)Ipt2_vg273EM2Dp)UJ(Q} zP#eRqPkwJLG>RM7NFO95(liNn1AmL1g9XjJQ|}s|8urbMorKZwi&5SB(3b^0SZxNv zqb*-py`Cip{s=uG{Cado+Evkqtmd7Rch?jQ@Dkx=HsZ+3ZvLe@rlkBqu0QtUAk){) zY+VXof0X`F9+VzcytfAI6Q(*ORr?O}ARR}(DhWDH!c4ickSNWaRT!`{!taQD@%g#% z=YT`ZCixuvb-=yRLsr^l)tj1#%dR-3_0O0}sx%>w{8*|F>I}i`(;odxjrReD6@hA# z>i!;9*T+%pQn}c5IfA}AtGQY9xb(dpOD}#K-Bz#eeuwQuqEbOuJih?i%`)a-cx2xX z*5sln__$i|1^3t5LP~?wY)%a2>U3|~-8`=+1`I%0XA96?f>)|VE)UoW`GkEaC}z2FuQ;pP|N<#{13qy2)1i-#Wz?BZl)YY%eaa0Njiw$_fW9Ja1t z7ZCDG+{)bE74&~FI9j`M0G%vB94;VhTPH^jAlMDrbmg#cv*K{I^#+M^b8&I~lMIp% zP1lE`VhIdtbJW)*KKoFi4!|U*>c*cL3Y};j(f8IlF-z zfnLZR`~$D8qbmfdBhUtfT$cOa7~C8{jt~xz0~q4P;Q)fzI9a;>s}=s5@o#~@SvhPS z-JR_IRjL1t-xX}`;Rv$ifY`Wz%>S>JFo*mxHqucLq^Gp?)n&y0Rms1$^#9`5l~UG` z5&!?x`EPy)a~C`0{QuGXZ-4&ZtmES31o^*^LVDnDds!nx?LQIsKg<2Aq3xZ3c0eab z2+}owjNstpXbW+2`Qvktqq&7W$nxL9$nifx^gov7u(x%vg@|+W2>pXKoGjjRnA;;) z<8XzT1MN8e8(NkiFvR8`4gRkpw#e z`cKaLFO!Fpi`^e?nAJAnR({p$|?kL(lR`v-gdmj~>G zRM++Y&l@gojvUrN4x|T>?*D@sZuUqaTckrl4o)s!|C8|lx~cy< getDevices() { List devices = new ArrayList<>(); @@ -130,12 +130,12 @@ public List getDevices() { } return devices; } - + @Override public String getIp() { return NetworkUtil.getIPv4HostAddress().getHostAddress(); } - + @Override public boolean power(boolean on) { Logger.trace("Switching Power " + (on ? "On" : "Off")); @@ -143,7 +143,7 @@ public boolean power(boolean on) { this.power = on; Logger.trace("Power is " + (power ? "On" : "Off")); PowerEvent pe = new PowerEvent(this.power); - + executor.execute(() -> fireAllPowerEventListeners(pe)); synchronized (this) { notifyAll(); @@ -152,22 +152,22 @@ public boolean power(boolean on) { } else { return false; } - + } - + private void fireAllPowerEventListeners(final PowerEvent powerEvent) { for (PowerEventListener listener : powerEventListeners) { listener.onPowerChange(powerEvent); } } - + @Override public void changeDirection(int locUid, LocomotiveBean.Direction direction) { if (this.power && this.connected) { Logger.debug("locUid " + locUid + " direction " + direction); - + LocomotiveDirectionEvent lde = new LocomotiveDirectionEvent(locUid, direction, commandStationBean.getId()); - + notifyLocomotiveDirectionEventListeners(lde); } else { if (!this.power) { @@ -175,11 +175,11 @@ public void changeDirection(int locUid, LocomotiveBean.Direction direction) { } } } - + private void notifyLocomotiveDirectionEventListeners(final LocomotiveDirectionEvent directionEvent) { executor.execute(() -> fireAllDirectionEventListeners(directionEvent)); } - + private void fireAllDirectionEventListeners(final LocomotiveDirectionEvent directionEvent) { if (directionEvent.isValid()) { for (LocomotiveDirectionEventListener listener : this.locomotiveDirectionEventListeners) { @@ -187,12 +187,12 @@ private void fireAllDirectionEventListeners(final LocomotiveDirectionEvent direc } } } - + @Override public void changeVelocity(int locUid, int speed, LocomotiveBean.Direction direction) { if (this.power && connected) { Logger.debug("locUid " + locUid + " speed " + speed); - + LocomotiveSpeedEvent lse = new LocomotiveSpeedEvent(locUid, speed, commandStationBean.getId()); executor.execute(() -> { fireAllLocomotiveSpeedEventListeners(lse); @@ -210,7 +210,7 @@ public void changeVelocity(int locUid, int speed, LocomotiveBean.Direction direc } } } - + private void fireAllLocomotiveSpeedEventListeners(final LocomotiveSpeedEvent speedEvent) { if (speedEvent.isValid()) { for (LocomotiveSpeedEventListener listener : this.locomotiveSpeedEventListeners) { @@ -218,7 +218,7 @@ private void fireAllLocomotiveSpeedEventListeners(final LocomotiveSpeedEvent spe } } } - + @Override public void changeFunctionValue(int locUid, int functionNumber, boolean flag) { if (this.power && connected) { @@ -231,7 +231,7 @@ public void changeFunctionValue(int locUid, int functionNumber, boolean flag) { } } } - + private void fireAllFunctionEventListeners(final LocomotiveFunctionEvent functionEvent) { if (functionEvent.isValid()) { for (LocomotiveFunctionEventListener listener : this.locomotiveFunctionEventListeners) { @@ -239,42 +239,42 @@ private void fireAllFunctionEventListeners(final LocomotiveFunctionEvent functio } } } - + @Override public List getLocomotives() { throw new UnsupportedOperationException("Not supported yet."); } - + @Override public Image getLocomotiveImage(String icon) { throw new UnsupportedOperationException("Not supported yet."); } - + @Override public Image getLocomotiveFunctionImage(String icon) { throw new UnsupportedOperationException("Not supported yet."); } - + @Override public boolean isSupportTrackMeasurements() { return false; } - + @Override public Map getTrackMeasurements() { throw new UnsupportedOperationException("Not supported yet."); } - + @Override public void switchAccessory(Integer address, AccessoryBean.AccessoryValue value) { switchAccessory(address, value, 200); } - + @Override public void switchAccessory(String id, AccessoryBean.AccessoryValue value) { throw new UnsupportedOperationException("Not supported yet."); } - + @Override public void switchAccessory(Integer address, AccessoryBean.AccessoryValue value, Integer switchTime) { if (this.power && connected) { @@ -289,37 +289,40 @@ public void switchAccessory(Integer address, AccessoryBean.AccessoryValue value, } ab.setId(id); ab.setCommandStationId(commandStationBean.getId()); - + AccessoryEvent ae = new AccessoryEvent(ab); - executor.execute(() -> fireAllAccessoryEventListeners(ae)); + //executor.execute(() -> fireAllAccessoryEventListeners(ae)); + Logger.trace("Switched accessory " + id + " to " + value.getValue()); + fireAllAccessoryEventListeners(ae); } else { if (!this.power) { Logger.warn("Can't switch accessory " + address + " to: " + value + " Power is OFF!"); } } } - + private void fireAllAccessoryEventListeners(final AccessoryEvent accessoryEvent) { for (AccessoryEventListener listener : this.accessoryEventListeners) { listener.onAccessoryChange(accessoryEvent); + Logger.trace("Fired accessory listener " + accessoryEvent.getId()); } } - + @Override public List getAccessories() { throw new UnsupportedOperationException("Not supported yet."); } - + @Override public DeviceBean getFeedbackDevice() { throw new UnsupportedOperationException("Not supported yet."); } - + @Override public List getFeedbackModules() { throw new UnsupportedOperationException("Not supported yet."); } - + @Override public synchronized void fireSensorEventListeners(final SensorEvent sensorEvent) { for (SensorEventListener listener : sensorEventListeners) { @@ -328,14 +331,14 @@ public synchronized void fireSensorEventListeners(final SensorEvent sensorEvent) } } } - + @Override public void simulateSensor(SensorEvent sensorEvent) { List acl = JCS.getJcsCommandStation().getFeedbackControllers(); - + for (FeedbackController fbc : acl) { fbc.fireSensorEventListeners(sensorEvent); } } - + } diff --git a/src/main/java/jcs/persistence/H2PersistenceService.java b/src/main/java/jcs/persistence/H2PersistenceService.java index 6b4e8534..0409ec81 100755 --- a/src/main/java/jcs/persistence/H2PersistenceService.java +++ b/src/main/java/jcs/persistence/H2PersistenceService.java @@ -611,12 +611,13 @@ public synchronized TileBean persist(TileBean tileBean) { if (tileBean == null) { return null; } - TileBean tb; - if (tileBean instanceof Tile tile) { - tb = tile.getTileBean(); - } else { - tb = tileBean; - } +// //TODO + TileBean tb = null; +// if (tileBean instanceof Tile tile) { +// tb = tile.getTileBean(); +// } else { +// tb = tileBean; +// } if (tb != null && tb.getId() != null) { if (database.where("id=?", tb.getId()).first(TileBean.class) != null) { diff --git a/src/main/java/jcs/ui/layout/LayoutCanvas.java b/src/main/java/jcs/ui/layout/LayoutCanvas.java index 40a5407e..fa7d4a8c 100755 --- a/src/main/java/jcs/ui/layout/LayoutCanvas.java +++ b/src/main/java/jcs/ui/layout/LayoutCanvas.java @@ -30,15 +30,11 @@ import java.awt.image.BufferedImage; import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; -import java.util.HashMap; import java.util.HashSet; -import java.util.LinkedList; import java.util.List; -import java.util.Map; import java.util.Set; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; -import java.util.stream.Collectors; import javax.swing.JFrame; import javax.swing.JMenuItem; import javax.swing.JPanel; @@ -52,14 +48,10 @@ import jcs.entities.BlockBean; import jcs.entities.BlockBean.BlockState; import jcs.entities.LocomotiveBean; -import jcs.entities.RouteElementBean; import jcs.entities.SensorBean; import jcs.entities.TileBean; import jcs.entities.TileBean.Direction; import jcs.entities.TileBean.Orientation; -import static jcs.entities.TileBean.Orientation.EAST; -import static jcs.entities.TileBean.Orientation.SOUTH; -import static jcs.entities.TileBean.Orientation.WEST; import static jcs.entities.TileBean.TileType.BLOCK; import static jcs.entities.TileBean.TileType.CROSS; import static jcs.entities.TileBean.TileType.CURVED; @@ -114,14 +106,14 @@ public enum Mode { private final ExecutorService executor; - private final Map tiles; - private final Map altTiles; +// private final Map tiles; +// private final Map altTiles; private final Set selectedTiles; private Tile selectedTile; private RoutesDialog routesDialog; - private final Map selectedRouteElements; + //private final Map selectedRouteElements; private Point movingTileCenterPoint; private BufferedImage movingTileImage; @@ -132,11 +124,11 @@ public LayoutCanvas() { public LayoutCanvas(boolean readonly) { this.readonly = readonly; - this.tiles = new HashMap<>(); - this.altTiles = new HashMap<>(); +// this.tiles = new HashMap<>(); +// this.altTiles = new HashMap<>(); this.selectedTiles = new HashSet<>(); - this.selectedRouteElements = new HashMap<>(); +// this.selectedRouteElements = new HashMap<>(); this.executor = Executors.newSingleThreadExecutor(); //this.executor = Executors.newCachedThreadPool(); @@ -156,8 +148,11 @@ private void postInit() { @Override protected void paintComponent(Graphics g) { + long started = System.currentTimeMillis(); + super.paintComponent(g); + Graphics2D g2 = (Graphics2D) g.create(); - Set snapshot = new HashSet<>(tiles.values()); + Set snapshot = new HashSet<>(TileCache.tiles.values()); if (this.drawGrid) { if (lineGrid) { @@ -170,7 +165,8 @@ protected void paintComponent(Graphics g) { } for (Tile tile : snapshot) { - tile.setDrawOutline(drawGrid); + //for (Tile tile : TileCache.tiles.values()) { + //tile.setDrawOutline(drawGrid); if (Mode.CONTROL != mode) { if (selectedTiles.contains(tile.getCenter())) { @@ -181,11 +177,11 @@ protected void paintComponent(Graphics g) { } } - tile.drawTile(g2, drawGrid); + tile.drawTile(g2); //debug - if (!this.readonly) { - tile.drawCenterPoint(g2, Color.magenta, 3); - } +// if (!this.readonly) { +// tile.drawCenterPoint(g2, Color.magenta, 3); +// } } if (this.movingTileCenterPoint != null && this.movingTileImage != null) { @@ -197,13 +193,18 @@ protected void paintComponent(Graphics g) { } g2.dispose(); + + long now = System.currentTimeMillis(); + Logger.trace("Duration: " + (now - started) + " ms."); } @Override public void propertyChange(PropertyChangeEvent evt) { if ("repaintTile".equals(evt.getPropertyName())) { Tile tile = (Tile) evt.getNewValue(); - this.repaint(tile.getBounds()); + + Logger.trace("Repainting Tile: " + tile.getId()); + repaint(tile.getBounds()); } } @@ -331,79 +332,101 @@ void setDirection(Direction direction) { void loadLayoutInBackground() { this.executor.execute(() -> loadTiles()); + +// new Thread(new Runnable() { +// public void run() { +// final String text = readHugeFile(); +// SwingUtilities.invokeLater(new Runnable() { +// public void run() { +// canvas.setTiles(); +// } +// }); +// } +// }).start(); } - public void loadTiles() { + private void loadTiles() { boolean showValues = Mode.CONTROL.equals(mode); + TileCache.loadTiles(this); + TileCache.setShowValues(showValues); + //TileCache.setDrawOutline(drawGrid); + TileCache.setDrawCenterPoint(!this.readonly); - List tileBeans = PersistenceFactory.getService().getTileBeans(); - +// List tileBeans = PersistenceFactory.getService().getTileBeans(); selectedTiles.clear(); - altTiles.clear(); - tiles.clear(); - selectedRouteElements.clear(); - - for (TileBean tb : tileBeans) { - Tile tile = TileFactory.createTile(tb, drawGrid, showValues); - tile.setPropertyChangeListener(this); - tiles.put(tile.getCenter(), tile); - - //Alternative point(s) to be able to find all points - if (!tile.getAltPoints().isEmpty()) { - Set alt = tile.getAltPoints(); - for (Point ap : alt) { - altTiles.put(ap, tile); - } - } +// altTiles.clear(); +// tiles.clear(); +// selectedRouteElements.clear(); + +// for (TileBean tb : tileBeans) { +// Tile tile = TileFactory.createTile(tb, drawGrid, showValues); +// tile.setPropertyChangeListener(this); +// tiles.put(tile.getCenter(), tile); +// +// //Alternative point(s) to be able to find all points +// if (!tile.getAltPoints().isEmpty()) { +// Set alt = tile.getAltPoints(); +// for (Point ap : alt) { +// altTiles.put(ap, tile); +// } +// } +// } +// Logger.debug("Loaded " + tiles.size() + " Tiles..."); + for (Tile tile : TileCache.tiles.values()) { + this.add(tile); } - Logger.debug("Loaded " + tiles.size() + " Tiles..."); + repaint(); } - public void saveLayout() { + void saveLayout() { //Create a snapshot as persisting is done in worker thread - Set snapshot = new HashSet<>(tiles.values()); +// Set snapshot = new HashSet<>(tiles.values()); this.selectedTiles.clear(); - this.executor.execute(() -> saveTiles(snapshot)); - } - - private synchronized void saveTiles(Set snapshot) { - Logger.debug("Saving " + snapshot.size() + " tiles..."); - List beans = new LinkedList<>(); +// this.executor.execute(() -> saveTiles(snapshot)); - for (Tile tile : snapshot) { - if (tile != null) { - TileBean tb = tile.getTileBean(); - Logger.trace("Saving " + tile + " -> " + tb); - beans.add(tb); - } else { - Logger.warn("Tile is null?"); - } - } - PersistenceFactory.getService().persist(beans); + this.executor.execute(() -> TileCache.saveTiles()); } +// private synchronized void saveTiles(Set snapshot) { +// TileCache.saveTiles(); +// +// Logger.debug("Saving " + snapshot.size() + " tiles..."); +// List beans = new LinkedList<>(); +// +// for (Tile tile : snapshot) { +// if (tile != null) { +// TileBean tb = tile.getTileBean(); +// Logger.trace("Saving " + tile + " -> " + tb); +// beans.add(tb); +// } else { +// Logger.warn("Tile is null?"); +// } +// } +// PersistenceFactory.getService().persist(beans); +// } private void saveTile(final Tile tile) { - if (tile != null) { - TileBean tb = tile.getTileBean(); - this.executor.execute(() -> PersistenceFactory.getService().persist(tb)); - } else { - Logger.warn("Tile is null?"); - } - } - - private void deleteTile(final Tile tile) { - if (tile != null) { - TileBean tb = tile.getTileBean(); - this.executor.execute(() -> PersistenceFactory.getService().remove(tb)); - } else { - Logger.warn("Tile is null?"); - } +// if (tile != null) { +// TileBean tb = tile.getTileBean(); +// this.executor.execute(() -> PersistenceFactory.getService().persist(tb)); + this.executor.execute(() -> TileCache.saveTile(tile)); +// } else { +// Logger.warn("Tile is null?"); +// } } +// private void deleteTile(final Tile tile) { +// if (tile != null) { +// TileBean tb = tile.getTileBean(); + //this.executor.execute(() -> PersistenceFactory.getService().remove(tb)); +// this.executor.execute(() -> TileCache.deleteTile(tile)); +// } else { +// Logger.warn("Tile is null?"); +// } +// } private void mouseMoveAction(MouseEvent evt) { Point sp = LayoutUtil.snapToGrid(evt.getPoint()); - Tile tile = findTile(sp); + Tile tile = TileCache.findTile(sp); if (tile != null) { setCursor(Cursor.getPredefinedCursor(Cursor.CROSSHAIR_CURSOR)); } else { @@ -415,7 +438,8 @@ private Tile getSelectedTile() { Tile t = null; if (!selectedTiles.isEmpty()) { for (Point p : this.selectedTiles) { - t = tiles.get(p); + //t = tiles.get(p); + t = TileCache.tiles.get(p); if (t != null) { return t; } @@ -426,7 +450,7 @@ private Tile getSelectedTile() { private void mousePressedAction(MouseEvent evt) { Point snapPoint = LayoutUtil.snapToGrid(evt.getPoint()); - Tile tile = findTile(snapPoint); + Tile tile = TileCache.findTile(snapPoint); //Clear any previous selection selectedTiles.clear(); @@ -471,9 +495,13 @@ private void mousePressedAction(MouseEvent evt) { if (MouseEvent.BUTTON3 == evt.getButton() && tile != null) { showOperationsPopupMenu(tile, snapPoint); } + repaint(); } case DELETE -> { - removeTiles(selectedTiles); + //removeTiles(selectedTiles); + TileCache.removeTiles(selectedTiles); + this.selectedTiles.clear(); + repaint(); } default -> { Logger.trace((tile != null ? "Selected tile: " + tile.getId() + ", " + tile.xyToString() : "No tile selected")); @@ -486,7 +514,6 @@ private void mousePressedAction(MouseEvent evt) { } } } - repaint(); } private void mouseDragAction(MouseEvent evt) { @@ -502,23 +529,23 @@ private void mouseDragAction(MouseEvent evt) { repaint(); } - private boolean checkTileOccupation(Tile tile) { - Set tilePoints = tile.getAllPoints(); - for (Point p : tilePoints) { - if (tiles.containsKey(p) || altTiles.containsKey(p)) { - //The is a match, check if it is an other tile - Tile mt = this.findTile(p); - if (tile.getId().equals(mt.getId())) { - //same tile continue - } else { - //Other tile so really occupied - return true; - } - } - } - return false; - } - +// private boolean checkTileOccupation(Tile tile) { +// Set tilePoints = tile.getAllPoints(); +// for (Point p : tilePoints) { +// if (tiles.containsKey(p) || altTiles.containsKey(p)) { +// //The is a match, check if it is an other tile +// Tile mt = this.findTile(p); +// if (tile.getId().equals(mt.getId())) { +// //same tile continue +// } else { +// //Other tile so really occupied +// return true; +// } +// } +// } +// return false; +// return TileCache.checkTileOccupation(tile); +// } private void mouseReleasedAction(MouseEvent evt) { Tile selTile = getSelectedTile(); if (selTile != null) { @@ -533,8 +560,9 @@ private void mouseReleasedAction(MouseEvent evt) { Logger.tag("Moving Tile from " + tp + " to " + snapPoint + " Tile to move: " + selTile); //Check if new position is free boolean canMove = true; - if (tiles.containsKey(snapPoint) || altTiles.containsKey(snapPoint)) { - Tile tile = findTile(snapPoint); + //if (tiles.containsKey(snapPoint) || altTiles.containsKey(snapPoint)) { + if (TileCache.containsPoint(snapPoint)) { + Tile tile = TileCache.findTile(snapPoint); if (selTile.getId().equals(tile.getId())) { //same tile so we can move canMove = true; @@ -546,48 +574,50 @@ private void mouseReleasedAction(MouseEvent evt) { if (canMove) { //Remove the original tile center from the tiles - Tile movingTile = tiles.remove(tp); + Tile movingTile = TileCache.tiles.remove(tp); if (movingTile != null) { //Also remove from the alt points Point oldCenter = movingTile.getCenter(); Set oldAltPoints = movingTile.getAltPoints(); //Logger.trace("Removing " + oldAltPoints.size() + " alt tile points"); for (Point ep : oldAltPoints) { - altTiles.remove(ep); - tiles.remove(ep); + TileCache.altTiles.remove(ep); + TileCache.tiles.remove(ep); } //Set the new center position movingTile.setCenter(snapPoint); //Check again, needed for tiles which are longer then 1 square, like a block - if (!checkTileOccupation(movingTile)) { + if (!TileCache.checkTileOccupation(movingTile)) { Logger.trace("Moved Tile " + movingTile.getId() + " from " + tp + " to " + snapPoint + "..."); - tiles.put(snapPoint, movingTile); + TileCache.tiles.put(snapPoint, movingTile); for (Point ep : movingTile.getAltPoints()) { - altTiles.put(ep, movingTile); + TileCache.altTiles.put(ep, movingTile); } selectedTiles.clear(); selectedTiles.addAll(movingTile.getAllPoints()); } else { //Do not move Tile, put back where it was movingTile.setCenter(oldCenter); - tiles.put(oldCenter, movingTile); + TileCache.tiles.put(oldCenter, movingTile); for (Point ep : movingTile.getAltPoints()) { - altTiles.put(ep, movingTile); + TileCache.altTiles.put(ep, movingTile); } } - if ("false".equals(System.getProperty("batch.tile.persist", "true"))) { - this.saveTile(movingTile); - } + //if ("false".equals(System.getProperty("batch.tile.persist", "true"))) { + //this.saveTile(movingTile); + TileCache.saveTile(movingTile); + //} } + repaint(); } } } movingTileImage = null; movingTileCenterPoint = null; - repaint(); + //repaint(); } private void executeControlActionForTile(Tile tile, Point p) { @@ -607,7 +637,7 @@ private void executeControlActionForTile(Tile tile, Point p) { BlockControlDialog bcd = new BlockControlDialog(getParentFrame(), block); bcd.setVisible(true); - this.repaint(block.getX(), block.getY(), block.getWidth(), block.getHeight()); + //this.repaint(block.getX(), block.getY(), block.getWidth(), block.getHeight()); } case SIGNAL -> this.executor.execute(() -> toggleSignal((Signal) tile)); @@ -625,10 +655,10 @@ private void toggleSwitch(Switch turnout) { if (turnout.getAccessoryBean() != null) { AccessoryBean ab = turnout.getAccessoryBean(); ab.toggle(); - turnout.setValue(ab.getAccessoryValue()); + turnout.setAccessoryValue(ab.getAccessoryValue()); JCS.getJcsCommandStation().switchAccessory(ab, ab.getAccessoryValue()); - repaint(turnout.getX(), turnout.getY(), turnout.getWidth(), turnout.getHeight()); + //repaint(turnout.getX(), turnout.getY(), turnout.getWidth(), turnout.getHeight()); } else { Logger.trace("No AccessoryBean configured for Turnout: " + turnout.getId()); } @@ -641,7 +671,7 @@ private void toggleSignal(Signal signal) { Logger.trace("A: " + ab.getAddress() + " S: " + ab.getStates() + " P: " + ab.getState()); JCS.getJcsCommandStation().switchAccessory(ab, ab.getAccessoryValue()); - repaint(signal.getX(), signal.getY(), signal.getWidth(), signal.getHeight()); + //repaint(signal.getX(), signal.getY(), signal.getWidth(), signal.getHeight()); } else { Logger.trace("No AccessoryBean configured for Signal: " + signal.getId()); } @@ -653,11 +683,8 @@ private void toggleSensor(Sensor sensor) { sb.toggle(); sensor.setActive((sb.getStatus() == 1)); Logger.trace("id: " + sb.getId() + " state " + sb.getStatus()); - - sensor.repaintTile(); - + //sensor.repaintTile(); SensorEvent sensorEvent = new SensorEvent(sb); - //this.executor.execute(() -> fireFeedbackEvent(sensorEvent)); fireFeedbackEvent(sensorEvent); } } @@ -679,7 +706,7 @@ private void editSelectedTileProperties() { if (!this.selectedTiles.isEmpty()) { Point tcp = this.selectedTiles.iterator().next(); - Tile tile = findTile(tcp); + Tile tile = TileCache.findTile(tcp); TileBean.TileType tt = tile.getTileType(); Logger.trace("Seleted tile " + tile.getId() + " TileType " + tt); @@ -725,9 +752,8 @@ private void editSelectedTileProperties() { default -> { } } + repaint(); } - //this.executor.execute(() -> repaint()); - repaint(); } private void showBlockPopupMenu(Tile tile, Point p) { @@ -765,8 +791,10 @@ private void showOperationsPopupMenu(Tile tile, Point p) { //which items should be shown boolean showProperties = false; boolean showFlip = false; + @SuppressWarnings("UnusedAssignment") boolean showRotate = false; boolean showMove = false; + @SuppressWarnings("UnusedAssignment") boolean showDelete = false; TileBean.TileType tt = tile.getTileType(); @@ -823,52 +851,50 @@ private void showOperationsPopupMenu(Tile tile, Point p) { this.operationsPM.show(this, p.x, p.y); } - public Tile findTile(Point cp) { - Tile result = this.tiles.get(cp); - if (result == null) { - //Logger.trace("Using alternative points..."); - result = this.altTiles.get(cp); - if (result != null) { - //Logger.trace("Found " + result + " in alt tiles"); - } - } - return result; - } - - private Point getCheckAvailable(Point newPoint) { - if (this.tiles.containsKey(newPoint)) { - Tile et = this.tiles.get(newPoint); - Logger.debug("@ " + newPoint + " is allready occcupied by: " + et + "..."); - //Search for the nearest avalaible free point - //first get the Center point of the tile which is occuping this slot - // show warning! - Point ecp = et.getCenter(); - - int w = et.getWidth(); - int h = et.getHeight(); - - Point np; - np = switch (this.orientation) { - case EAST -> - new Point(ecp.x + w, ecp.y); - case WEST -> - new Point(newPoint.x - w, ecp.y); - case SOUTH -> - new Point(ecp.x, newPoint.y + h); - default -> - new Point(ecp.x, newPoint.y - h); - }; - - Logger.trace("Alternative CP: " + np); - // recursive check - return getCheckAvailable(np); - } else { - Logger.debug("@ " + newPoint + " is not yet used..."); - - return newPoint; - } - } - +// public Tile findTile(Point cp) { +// Tile result = this.tiles.get(cp); +// if (result == null) { +// //Logger.trace("Using alternative points..."); +// result = this.altTiles.get(cp); +// if (result != null) { +// //Logger.trace("Found " + result + " in alt tiles"); +// } +// } +// return result; +// } +// private Point getCheckAvailable(Point newPoint) { +// if (this.tiles.containsKey(newPoint)) { +// Tile et = this.tiles.get(newPoint); +// Logger.debug("@ " + newPoint + " is allready occcupied by: " + et + "..."); +// //Search for the nearest avalaible free point +// //first get the Center point of the tile which is occuping this slot +// // show warning! +// Point ecp = et.getCenter(); +// +// int w = et.getWidth(); +// int h = et.getHeight(); +// +// Point np; +// np = switch (this.orientation) { +// case EAST -> +// new Point(ecp.x + w, ecp.y); +// case WEST -> +// new Point(newPoint.x - w, ecp.y); +// case SOUTH -> +// new Point(ecp.x, newPoint.y + h); +// default -> +// new Point(ecp.x, newPoint.y - h); +// }; +// +// Logger.trace("Alternative CP: " + np); +// // recursive check +// return getCheckAvailable(np); +// } else { +// Logger.debug("@ " + newPoint + " is not yet used..."); +// +// return newPoint; +// } +// } private Tile addTile(Point p) { if (this.orientation == null) { this.orientation = Orientation.EAST; @@ -879,41 +905,41 @@ private Tile addTile(Point p) { } Logger.trace("Adding: " + tileType + " @ " + p); - Point chkp = getCheckAvailable(p); + Point chkp = TileCache.checkAvailable(p, this.orientation); boolean fullRepaint = !chkp.equals(p); Tile tile = TileFactory.createTile(tileType, orientation, direction, chkp, drawGrid); //Can the tile be placed, keeping in mind the extra points - boolean canBeAdded = true; - if (!tile.getAltPoints().isEmpty()) { - //Check if the extra point positions are not occupied - Set tilePoints = tile.getAllPoints(); - - for (Point tp : tilePoints) { - if (tiles.containsKey(tp) || altTiles.containsKey(tp)) { - Logger.trace("Point " + p + " occupied by " + findTile(p).getId() + " Can't add new Tile: " + tile); - canBeAdded = false; - } - } - } - + boolean canBeAdded = TileCache.checkTileOccupation(tile); + +// if (!tile.getAltPoints().isEmpty()) { +// //Check if the extra point positions are not occupied +// Set tilePoints = tile.getAllPoints(); +// +// for (Point tp : tilePoints) { +// if (TileCache.containsPoint(tp)) { +// Logger.trace("Point " + p + " occupied by " + TileCache.findTile(p).getId() + " Can't add new Tile: " + tile); +// canBeAdded = false; +// } +// } +// } if (canBeAdded) { - tiles.put(chkp, tile); - //Alternative point(s) to be able to find all points - if (!tile.getAltPoints().isEmpty()) { - Set alt = tile.getAltPoints(); - for (Point ap : alt) { - this.altTiles.put(ap, tile); - } - } - - if ("false".equals(System.getProperty("batch.tile.persist", "true"))) { - this.saveTile(tile); - } - + TileCache.addTile(tile); + +// TileCache.tiles.put(chkp, tile); +// //Alternative point(s) to be able to find all points +// if (!tile.getAltPoints().isEmpty()) { +// Set alt = tile.getAltPoints(); +// for (Point ap : alt) { +// TileCache.altTiles.put(ap, tile); +// } +// } +// +// if ("false".equals(System.getProperty("batch.tile.persist", "true"))) { +// this.saveTile(tile); +// } Logger.trace("Added Tile " + tile.getClass().getSimpleName() + " " + tile.getOrientation() + " @ " + tile.getCenter() + " Full repaint: " + fullRepaint); - Logger.trace("Added " + tile + " There are now " + this.tiles.size() + " tiles..."); } if (fullRepaint) { @@ -928,30 +954,32 @@ private Tile addTile(Point p) { } void removeTiles() { - removeTiles(selectedTiles); - } - - private void removeTiles(Set pointsToRemove) { - for (Point p : pointsToRemove) { - Tile removed = this.tiles.remove(p); - - if ("false".equals(System.getProperty("batch.tile.persist", "true"))) { - this.deleteTile(removed); - } - - if (removed != null && removed.getAllPoints() != null) { - Set rps = removed.getAltPoints(); - //Also remove alt points - for (Point ap : rps) { - tiles.remove(ap); - } - - Logger.trace("Removed: " + removed); - } - } - selectedTiles.clear(); + TileCache.removeTiles(selectedTiles); + //removeTiles(selectedTiles); repaint(); } +// private void removeTiles(Set pointsToRemove) { +// TileCache.removeTiles(pointsToRemove); +// for (Point p : pointsToRemove) { +// Tile removed = TileCache.tiles.remove(p); +// +// if ("false".equals(System.getProperty("batch.tile.persist", "true"))) { +// this.deleteTile(removed); +// } +// +// if (removed != null && removed.getAllPoints() != null) { +// Set rps = removed.getAltPoints(); +// //Also remove alt points +// for (Point ap : rps) { +// tiles.remove(ap); +// } +// +// Logger.trace("Removed: " + removed); +// } +// } +// selectedTiles.clear(); +// repaint(); +// } private JFrame getParentFrame() { JFrame frame = (JFrame) SwingUtilities.getRoot(this); @@ -960,104 +988,111 @@ private JFrame getParentFrame() { public void rotateSelectedTile() { Logger.trace("Selected Tiles " + selectedTiles.size()); - - //make copy as the map could be cleared - Set snapshot = new HashSet<>(selectedTiles); - for (Point p : snapshot) { - Logger.trace("Selected Tile @ " + p); - if (this.tiles.containsKey(p)) { - Tile t = this.tiles.get(p); - //Remove the alternative or extra points... - for (Point ep : t.getAltPoints()) { - this.altTiles.remove(ep); - } - - t.rotate(); - Logger.trace("Rotated " + t); - this.orientation = t.getOrientation(); - this.direction = t.getDirection(); - - //override - this.tiles.put(p, t); - for (Point ep : t.getAltPoints()) { - this.altTiles.put(ep, t); - } - - this.selectedTiles.clear(); - this.selectedTiles.addAll(t.getAllPoints()); - - if ("false".equals(System.getProperty("batch.tile.persist", "true"))) { - this.saveTile(t); - } - } - } + TileCache.rotateTile(selectedTiles); + +// //make copy as the map could be cleared +// Set snapshot = new HashSet<>(selectedTiles); +// +// for (Point p : snapshot) { +// Logger.trace("Selected Tile @ " + p); +// if (this.tiles.containsKey(p)) { +// Tile t = this.tiles.get(p); +// //Remove the alternative or extra points... +// for (Point ep : t.getAltPoints()) { +// this.altTiles.remove(ep); +// } +// +// t.rotate(); +// Logger.trace("Rotated " + t); +// this.orientation = t.getOrientation(); +// this.direction = t.getDirection(); +// +// //override +// this.tiles.put(p, t); +// for (Point ep : t.getAltPoints()) { +// this.altTiles.put(ep, t); +// } +// +// this.selectedTiles.clear(); +// this.selectedTiles.addAll(t.getAllPoints()); +// +// if ("false".equals(System.getProperty("batch.tile.persist", "true"))) { +// this.saveTile(t); +// } +// } +// } repaint(); } public void flipSelectedTileHorizontal() { - Set snapshot = new HashSet<>(selectedTiles); - for (Point p : snapshot) { - Logger.trace("Selected Tile @ " + p); - if (this.tiles.containsKey(p)) { - Tile t = this.tiles.get(p); - //Remove the alternative or extra points... - for (Point ep : t.getAltPoints()) { - this.altTiles.remove(ep); - } - - t.flipHorizontal(); - Logger.trace("Flipped " + t); - this.orientation = t.getOrientation(); - this.direction = t.getDirection(); - - //override - this.tiles.put(p, t); - for (Point ep : t.getAltPoints()) { - this.altTiles.put(ep, t); - } - - if ("false".equals(System.getProperty("batch.tile.persist", "true"))) { - this.saveTile(t); - } - - this.selectedTiles.clear(); - this.selectedTiles.addAll(t.getAllPoints()); - } - } - this.executor.execute(() -> repaint()); + TileCache.flipHorizontal(selectedTiles); +// Set snapshot = new HashSet<>(selectedTiles); +// for (Point p : snapshot) { +// Logger.trace("Selected Tile @ " + p); +// if (this.tiles.containsKey(p)) { +// Tile t = this.tiles.get(p); +// //Remove the alternative or extra points... +// for (Point ep : t.getAltPoints()) { +// this.altTiles.remove(ep); +// } +// +// t.flipHorizontal(); +// Logger.trace("Flipped " + t); +// this.orientation = t.getOrientation(); +// this.direction = t.getDirection(); +// +// //override +// this.tiles.put(p, t); +// for (Point ep : t.getAltPoints()) { +// this.altTiles.put(ep, t); +// } +// +// if ("false".equals(System.getProperty("batch.tile.persist", "true"))) { +// this.saveTile(t); +// } +// +// this.selectedTiles.clear(); +// this.selectedTiles.addAll(t.getAllPoints()); +// } +// } +// this.executor.execute(() -> repaint()); + repaint(); } public void flipSelectedTileVertical() { - Set snapshot = new HashSet<>(selectedTiles); - for (Point p : snapshot) { - Logger.trace("Selected Tile @ " + p); - if (this.tiles.containsKey(p)) { - Tile t = this.tiles.get(p); - //Remove the alternative or extra points... - for (Point ep : t.getAltPoints()) { - this.altTiles.remove(ep); - } - - t.flipVertical(); - Logger.trace("Flipped " + t); - this.orientation = t.getOrientation(); - this.direction = t.getDirection(); - - //override - this.tiles.put(p, t); - for (Point ep : t.getAltPoints()) { - this.altTiles.put(ep, t); - } - - if ("false".equals(System.getProperty("batch.tile.persist", "true"))) { - this.saveTile(t); - } - - this.selectedTiles.clear(); - this.selectedTiles.addAll(t.getAllPoints()); - } - } - this.executor.execute(() -> repaint()); + TileCache.flipVertical(selectedTiles); + +// Set snapshot = new HashSet<>(selectedTiles); +// for (Point p : snapshot) { +// Logger.trace("Selected Tile @ " + p); +// if (this.tiles.containsKey(p)) { +// Tile t = this.tiles.get(p); +// //Remove the alternative or extra points... +// for (Point ep : t.getAltPoints()) { +// this.altTiles.remove(ep); +// } +// +// t.flipVertical(); +// Logger.trace("Flipped " + t); +// this.orientation = t.getOrientation(); +// this.direction = t.getDirection(); +// +// //override +// this.tiles.put(p, t); +// for (Point ep : t.getAltPoints()) { +// this.altTiles.put(ep, t); +// } +// +// if ("false".equals(System.getProperty("batch.tile.persist", "true"))) { +// this.saveTile(t); +// } +// +// this.selectedTiles.clear(); +// this.selectedTiles.addAll(t.getAllPoints()); +// } +// } +// this.executor.execute(() -> repaint()); + repaint(); } void routeLayout() { @@ -1066,11 +1101,12 @@ void routeLayout() { private void routeLayoutWithAStar() { //Make sure the layout is saved - Set snapshot = new HashSet<>(tiles.values()); - this.saveTiles(snapshot); + TileCache.saveTiles(); +// Set snapshot = new HashSet<>(tiles.values()); +// this.saveTiles(snapshot); AStar astar = new AStar(); - astar.buildGraph(this.tiles.values().stream().collect(Collectors.toList())); + astar.buildGraph(TileCache.getTiles()); astar.routeAll(); astar.persistRoutes(); if (this.routesDialog.isVisible()) { @@ -1360,7 +1396,9 @@ private void moveMIActionPerformed(ActionEvent evt) {//GEN-FIRST:event_moveMIAct }//GEN-LAST:event_moveMIActionPerformed private void deleteMIActionPerformed(ActionEvent evt) {//GEN-FIRST:event_deleteMIActionPerformed - this.removeTiles(selectedTiles); + //this.removeTiles(selectedTiles); + TileCache.removeTiles(selectedTiles); + this.selectedTiles.clear(); }//GEN-LAST:event_deleteMIActionPerformed private void propertiesMIActionPerformed(ActionEvent evt) {//GEN-FIRST:event_propertiesMIActionPerformed @@ -1396,8 +1434,10 @@ private void resetDispatcherMIActionPerformed(ActionEvent evt) {//GEN-FIRST:even Block block = (Block) selectedTile; LocomotiveBean locomotive = block.getBlockBean().getLocomotive(); - this.executor.execute(() -> AutoPilot.resetDispatcher(locomotive)); - repaint(); + this.executor.execute(() -> { + AutoPilot.resetDispatcher(locomotive); + repaint(); + }); } }//GEN-LAST:event_resetDispatcherMIActionPerformed @@ -1414,8 +1454,8 @@ private void removeLocMIActionPerformed(ActionEvent evt) {//GEN-FIRST:event_remo this.executor.execute(() -> { PersistenceFactory.getService().persist(block.getBlockBean()); PersistenceFactory.getService().persist(locomotive); + repaint(); }); - this.repaint(); } }//GEN-LAST:event_removeLocMIActionPerformed @@ -1441,8 +1481,10 @@ private void reverseArrivalSideMIActionPerformed(ActionEvent evt) {//GEN-FIRST:e block.getBlockBean().setArrivalSuffix("+"); } block.getBlockBean().setReverseArrival(!block.getBlockBean().isReverseArrival()); - this.executor.execute(() -> PersistenceFactory.getService().persist(block.getBlockBean())); - this.repaint(); + this.executor.execute(() -> { + PersistenceFactory.getService().persist(block.getBlockBean()); + block.repaintTile(); + }); } }//GEN-LAST:event_reverseArrivalSideMIActionPerformed @@ -1461,7 +1503,7 @@ private void toggleLocomotiveDirectionMIActionPerformed(ActionEvent evt) {//GEN- Logger.trace(block.getId() + " Logical changed from " + curDir + " to " + newDir + " for " + locomotive.getName()); this.executor.execute(() -> { - PersistenceFactory.getService().persist(block); + PersistenceFactory.getService().persist(block.getTileBean()); block.repaintTile(); }); } @@ -1478,8 +1520,10 @@ private void toggleOutOfOrderMIActionPerformed(ActionEvent evt) {//GEN-FIRST:eve } if (currentState != block.getRouteBlockState()) { - this.executor.execute(() -> PersistenceFactory.getService().persist(block.getBlockBean())); - this.repaint(); + this.executor.execute(() -> { + PersistenceFactory.getService().persist(block.getBlockBean()); + block.repaintTile(); + }); } } }//GEN-LAST:event_toggleOutOfOrderMIActionPerformed @@ -1494,8 +1538,10 @@ private void resetGhostMIActionPerformed(ActionEvent evt) {//GEN-FIRST:event_res } else { block.setBlockState(BlockBean.BlockState.FREE); } - this.executor.execute(() -> PersistenceFactory.getService().persist(block.getBlockBean())); - this.repaint(); + this.executor.execute(() -> { + PersistenceFactory.getService().persist(block.getBlockBean()); + block.repaintTile(); + }); } } }//GEN-LAST:event_resetGhostMIActionPerformed diff --git a/src/main/java/jcs/ui/layout/LayoutPanel.java b/src/main/java/jcs/ui/layout/LayoutPanel.java index 52efe209..dc8936c2 100755 --- a/src/main/java/jcs/ui/layout/LayoutPanel.java +++ b/src/main/java/jcs/ui/layout/LayoutPanel.java @@ -191,18 +191,14 @@ private void postInit() { } - public void saveLayout() { - this.canvas.saveLayout(); - } +// void saveLayout() { +// this.canvas.saveLayout(); +// } public void loadLayout() { this.canvas.loadLayoutInBackground(); } - public void loadTiles() { - this.canvas.loadTiles(); - } - /** * This method is called from within the constructor to initialize the form. WARNING: Do NOT modify this code. The content of this method is always regenerated by the Form Editor. */ @@ -885,7 +881,7 @@ private void propertiesMIActionPerformed(ActionEvent evt) {//GEN-FIRST:event_pro }//GEN-LAST:event_propertiesMIActionPerformed private void saveBtnActionPerformed(ActionEvent evt) {//GEN-FIRST:event_saveBtnActionPerformed - this.saveLayout(); + this.canvas.saveLayout(); }//GEN-LAST:event_saveBtnActionPerformed private void loadBtnActionPerformed(ActionEvent evt) {//GEN-FIRST:event_loadBtnActionPerformed diff --git a/src/main/java/jcs/ui/layout/LayoutPanelTester.java b/src/main/java/jcs/ui/layout/LayoutPanelTester.java index bf0c9cac..21c26fb0 100644 --- a/src/main/java/jcs/ui/layout/LayoutPanelTester.java +++ b/src/main/java/jcs/ui/layout/LayoutPanelTester.java @@ -35,7 +35,6 @@ public static void main(String args[]) { //System.setProperty("trackServiceAlwaysUseDemo", "true"); try { UIManager.setLookAndFeel("com.formdev.flatlaf.FlatLightLaf"); - //UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) { Logger.error(ex); } @@ -51,7 +50,7 @@ public static void main(String args[]) { } f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); - layoutPanel.loadTiles(); + layoutPanel.loadLayout(); f.pack(); Dimension dim = Toolkit.getDefaultToolkit().getScreenSize(); diff --git a/src/main/java/jcs/ui/layout/LayoutPanelTesterRO.java b/src/main/java/jcs/ui/layout/LayoutPanelTesterRO.java index da56baff..7eb4f2d7 100644 --- a/src/main/java/jcs/ui/layout/LayoutPanelTesterRO.java +++ b/src/main/java/jcs/ui/layout/LayoutPanelTesterRO.java @@ -35,7 +35,6 @@ public static void main(String args[]) { //System.setProperty("trackServiceAlwaysUseDemo", "true"); try { UIManager.setLookAndFeel("com.formdev.flatlaf.FlatLightLaf"); - //UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) { Logger.error(ex); } @@ -51,7 +50,7 @@ public static void main(String args[]) { } f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); - layoutPanel.loadLayout(); + //layoutPanel.loadLayout(); f.pack(); Dimension dim = Toolkit.getDefaultToolkit().getScreenSize(); diff --git a/src/main/java/jcs/ui/layout/RoutesDialog.java b/src/main/java/jcs/ui/layout/RoutesDialog.java index b23106e4..742a03e0 100644 --- a/src/main/java/jcs/ui/layout/RoutesDialog.java +++ b/src/main/java/jcs/ui/layout/RoutesDialog.java @@ -33,7 +33,6 @@ import jcs.entities.TileBean.Orientation; import jcs.persistence.PersistenceFactory; import jcs.ui.layout.events.TileEvent; -import jcs.ui.layout.tiles.TileFactory; import org.tinylog.Logger; /** @@ -120,7 +119,7 @@ private void resetRoute(List routeElements) { for (RouteElementBean re : routeElements) { String tileId = re.getTileId(); TileEvent tileEvent = new TileEvent(tileId, false); - TileFactory.fireTileEventListener(tileEvent); + TileCache.fireTileEventListener(tileEvent); } } @@ -145,7 +144,7 @@ private void showRoute(RouteBean routeBean) { } else { tileEvent = new TileEvent(tileId, true, incomingSide); } - TileFactory.fireTileEventListener(tileEvent); + TileCache.fireTileEventListener(tileEvent); } } diff --git a/src/main/java/jcs/ui/layout/TileCache.java b/src/main/java/jcs/ui/layout/TileCache.java new file mode 100644 index 00000000..28b78f8f --- /dev/null +++ b/src/main/java/jcs/ui/layout/TileCache.java @@ -0,0 +1,414 @@ +/* + * Copyright 2025 Frans Jacobs. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package jcs.ui.layout; + +import jcs.ui.layout.tiles.*; +import java.awt.Point; +import java.beans.PropertyChangeListener; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.stream.Collectors; +import jcs.entities.AccessoryBean.AccessoryValue; +import jcs.entities.AccessoryBean.SignalValue; +import jcs.entities.TileBean; +import jcs.entities.TileBean.Orientation; +import static jcs.entities.TileBean.Orientation.EAST; +import static jcs.entities.TileBean.Orientation.SOUTH; +import static jcs.entities.TileBean.Orientation.WEST; +import static jcs.entities.TileBean.TileType.CROSS; +import jcs.persistence.PersistenceFactory; +import jcs.ui.layout.events.TileEvent; +import jcs.ui.layout.events.TileEventListener; +import org.tinylog.Logger; + +/** + * Factory object to create Tiles and cache tiles + * + * @author frans + */ +public class TileCache { + + private static final Map tileEventListeners = new HashMap<>(); + + private static boolean drawOutline; + private static boolean drawCenterPoint; + private static boolean showValues; + + static final Map tiles = new HashMap<>(); + static final Map altTiles = new HashMap<>(); + + private TileCache() { + } + +// static void setDrawOutline(boolean drawOutline) { +// TileCache.drawOutline = drawOutline; +// +// for (Tile tile : tiles.values()) { +// tile.setDrawOutline(drawOutline); +// } +// } + static void setDrawCenterPoint(boolean drawCenterPoint) { + TileCache.drawCenterPoint = drawCenterPoint; + + for (Tile tile : tiles.values()) { + //if (tile instanceof AbstractTile abstractTile) { + tile.setDrawCenterPoint(drawCenterPoint); + //} + } + } + + public static void setShowValues(boolean showValues) { + TileCache.showValues = showValues; + + for (Tile tile : tiles.values()) { + TileBean.TileType tileType = tile.getTileType(); + //AbstractTile tile = null; + switch (tileType) { + case SWITCH -> { + if (showValues && ((Switch) tile).getTileBean().getAccessoryBean() != null) { + tile.setAccessoryValue(tile.getTileBean().getAccessoryBean().getAccessoryValue()); + } else { + tile.setAccessoryValue(AccessoryValue.OFF); + } + } + case CROSS -> { + if (showValues && ((Cross) tile).getTileBean().getAccessoryBean() != null) { + tile.setAccessoryValue(tile.getTileBean().getAccessoryBean().getAccessoryValue()); + } else { + tile.setAccessoryValue(AccessoryValue.OFF); + } + } + case SIGNAL -> { + if (showValues && ((Signal) tile).getTileBean().getAccessoryBean() != null) { + tile.setSignalValue(tile.getTileBean().getAccessoryBean().getSignalValue()); + } else { + tile.setSignalValue(SignalValue.OFF); + } + } + case SENSOR -> { + if (showValues && ((Sensor) tile).getTileBean().getSensorBean() != null) { + tile.setActive(tile.getTileBean().getSensorBean().isActive()); + } else { + tile.setActive(false); + } + } + case BLOCK -> { + } + } + } + } + + static void loadTiles(PropertyChangeListener listener) { + List tileBeans = PersistenceFactory.getService().getTileBeans(); + + tileEventListeners.clear(); + altTiles.clear(); + tiles.clear(); + + for (TileBean tb : tileBeans) { + Tile tile = TileFactory.createTile(tb, showValues); + //tile.setPropertyChangeListener(listener); + tiles.put(tile.getCenter(), tile); + addTileEventListener((TileEventListener) tile); + + //Alternative point(s) to be able to find all points + if (!tile.getAltPoints().isEmpty()) { + Set alt = tile.getAltPoints(); + for (Point ap : alt) { + altTiles.put(ap, tile); + } + } + } + + Logger.trace("Loaded " + tiles.size() + " Tiles..."); + } + + static List getTiles() { + return tiles.values().stream().collect(Collectors.toList()); + } + + static void addTile(Tile tile) { + tiles.put(tile.getCenter(), tile); + + addTileEventListener((TileEventListener) tile); + + //Alternative point(s) to be able to find all points + if (!tile.getAltPoints().isEmpty()) { + Set alt = tile.getAltPoints(); + for (Point ap : alt) { + altTiles.put(ap, tile); + } + } + + saveTile(tile); + Logger.trace("Added " + tile + " There are now " + TileCache.tiles.size() + " tiles..."); + } + + static void removeTiles(Set pointsToRemove) { + for (Point p : pointsToRemove) { + Tile removed = tiles.remove(p); + removeTileEventListener(removed); + + deleteTile(removed); + + if (removed != null && removed.getAllPoints() != null) { + Set rps = removed.getAltPoints(); + //Also remove alt points + for (Point ap : rps) { + altTiles.remove(ap); + } + + } + } + } + + static void deleteTile(final Tile tile) { + if (tile != null) { + TileBean tb = tile.getTileBean(); + PersistenceFactory.getService().remove(tb); + } else { + Logger.warn("Tile is null?"); + } + } + + static void saveTile(final Tile tile) { + if (tile != null) { + TileBean tb = tile.getTileBean(); + PersistenceFactory.getService().persist(tb); + } else { + Logger.warn("Tile is null?"); + } + } + + static void saveTiles() { + for (Tile tile : tiles.values()) { + saveTile(tile); + } + } + + public static Tile findTile(Point cp) { + Tile result = tiles.get(cp); + if (result == null) { + result = altTiles.get(cp); + if (result != null) { + } + } + return result; + } + + static boolean checkTileOccupation(Tile tile) { + Set tilePoints = tile.getAllPoints(); + for (Point p : tilePoints) { + if (tiles.containsKey(p) || altTiles.containsKey(p)) { + //The is a match, check if it is an other tile + Tile mt = findTile(p); + if (tile.getId().equals(mt.getId())) { + //same tile continue + } else { + //Other tile so really occupied + return true; + } + } + } + return false; + } + + static boolean containsPoint(Point point) { + return tiles.containsKey(point) || altTiles.containsKey(point); + } + + static Point checkAvailable(Point newPoint, Orientation orientation) { + if (tiles.containsKey(newPoint)) { + Tile et = tiles.get(newPoint); + Logger.trace("@ " + newPoint + " is allready occcupied by: " + et + "..."); + //Search for the nearest avalaible free point + //first get the Center point of the tile which is occuping this slot + // show warning! + Point ecp = et.getCenter(); + + int w = et.getWidth(); + int h = et.getHeight(); + + Point np; + np = switch (orientation) { + case EAST -> + new Point(ecp.x + w, ecp.y); + case WEST -> + new Point(newPoint.x - w, ecp.y); + case SOUTH -> + new Point(ecp.x, newPoint.y + h); + default -> + new Point(ecp.x, newPoint.y - h); + }; + + Logger.trace("Alternative CP: " + np); + // recursive check + return checkAvailable(np, orientation); + } else { + Logger.trace("@ " + newPoint + " is not yet used..."); + + return newPoint; + } + } + + static void rotateTile(Set centerPoints) { + for (Point p : centerPoints) { + if (tiles.containsKey(p)) { + Tile t = tiles.get(p); + //Remove the alternative or extra points... + for (Point ep : t.getAltPoints()) { + altTiles.remove(ep); + } + + t.rotate(); + + //update + tiles.put(p, t); + for (Point ep : t.getAltPoints()) { + altTiles.put(ep, t); + } + + saveTile(t); + } + } + } + + public static void flipHorizontal(Set points) { + flipTile(points, true); + } + + public static void flipVertical(Set points) { + flipTile(points, false); + } + + private static void flipTile(Set points, boolean horizontal) { + for (Point p : points) { + if (tiles.containsKey(p)) { + Tile t = tiles.get(p); + //Remove the alternative or extra points... + for (Point ep : t.getAltPoints()) { + altTiles.remove(ep); + } + + if (horizontal) { + t.flipHorizontal(); + } else { + t.flipVertical(); + } + //Update + tiles.put(p, t); + for (Point ep : t.getAltPoints()) { + altTiles.put(ep, t); + } + + if ("false".equals(System.getProperty("batch.tile.persist", "true"))) { + saveTile(t); + } + } + } + } + + static void moveTile(Point snapPoint, Tile tile) { + Point tp = tile.getCenter(); + if (!tp.equals(snapPoint)) { + //Check if new position is free + boolean canMove = true; + if (tiles.containsKey(snapPoint) || altTiles.containsKey(snapPoint)) { + Tile t = findTile(snapPoint); + if (tile.getId().equals(t.getId())) { + //same tile so we can move + canMove = true; + } else { + Logger.trace("Position " + snapPoint + " is occupied with tile: " + t + ", can't move tile " + tile.getId()); + canMove = false; + } + + if (canMove) { + //Remove the original tile center from the tiles + Tile movingTile = tiles.remove(tp); + if (movingTile != null) { + //Also remove from the alt points + Point oldCenter = movingTile.getCenter(); + Set oldAltPoints = movingTile.getAltPoints(); + //Logger.trace("Removing " + oldAltPoints.size() + " alt tile points"); + for (Point ep : oldAltPoints) { + altTiles.remove(ep); + tiles.remove(ep); + } + + //Set the new center position + movingTile.setCenter(snapPoint); + //Check again, needed for tiles which are longer then 1 square, like a block + if (!checkTileOccupation(movingTile)) { + Logger.trace("Moved Tile " + movingTile.getId() + " from " + tp + " to " + snapPoint + "..."); + tiles.put(snapPoint, movingTile); + for (Point ep : movingTile.getAltPoints()) { + altTiles.put(ep, movingTile); + } + } else { + //Do not move Tile, put back where it was + movingTile.setCenter(oldCenter); + tiles.put(oldCenter, movingTile); + for (Point ep : movingTile.getAltPoints()) { + altTiles.put(ep, movingTile); + } + } + + if ("false".equals(System.getProperty("batch.tile.persist", "true"))) { + saveTile(movingTile); + } + } + } + } + } + } + + static void addTileEventListener(TileEventListener listener) { + String key = listener.getId(); + tileEventListeners.put(key, listener); + } + + static void removeTileEventListener(Tile tile) { + if (tile instanceof TileEventListener tileEventListener) { + removeTileEventListener(tileEventListener); + } + } + + static void removeTileEventListener(TileEventListener listener) { + String key = listener.getId(); + tileEventListeners.remove(key, listener); + } + + public static void fireTileEventListener(TileEvent tileEvent) { + String key = tileEvent.getTileId(); + TileEventListener listener = tileEventListeners.get(key); + if (listener != null) { + listener.onTileChange(tileEvent); + Logger.trace("Fire listener on tile " + key); + } else { + //Logger.trace("Tile " + key + " not available"); + } + } + + static void fireAllTileEventListeners(TileEvent tileEvent) { + for (TileEventListener listener : tileEventListeners.values()) { + listener.onTileChange(tileEvent); + } + } + +} diff --git a/src/main/java/jcs/ui/layout/dialogs/BlockControlDialog.java b/src/main/java/jcs/ui/layout/dialogs/BlockControlDialog.java index 30d4b4fb..88057929 100644 --- a/src/main/java/jcs/ui/layout/dialogs/BlockControlDialog.java +++ b/src/main/java/jcs/ui/layout/dialogs/BlockControlDialog.java @@ -24,9 +24,9 @@ import jcs.entities.BlockBean; import jcs.entities.LocomotiveBean; import jcs.persistence.PersistenceFactory; +import jcs.ui.layout.TileCache; import jcs.ui.layout.events.TileEvent; import jcs.ui.layout.tiles.Block; -import jcs.ui.layout.tiles.TileFactory; import org.tinylog.Logger; /** @@ -74,7 +74,7 @@ private void postInit() { Logger.warn("Block has no BlockBean. Creating one..."); bb = new BlockBean(); bb.setId(block.getId()); - bb.setTile(block); + bb.setTile(block.getTileBean()); bb.setTileId(block.getId()); bb.setBlockState(BlockBean.BlockState.FREE); bb.setMaxWaitTime(0); @@ -421,7 +421,9 @@ private void saveExitBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-F PersistenceFactory.getService().persist(loc); } TileEvent tileEvent = new TileEvent(bb); - TileFactory.fireTileEventListener(tileEvent); + //TileFactory.fireTileEventListener(tileEvent); + TileCache.fireTileEventListener(tileEvent); + } this.setVisible(false); diff --git a/src/main/java/jcs/ui/layout/dialogs/BlockDialog.java b/src/main/java/jcs/ui/layout/dialogs/BlockDialog.java index 69e9826b..aa1974ba 100644 --- a/src/main/java/jcs/ui/layout/dialogs/BlockDialog.java +++ b/src/main/java/jcs/ui/layout/dialogs/BlockDialog.java @@ -27,6 +27,7 @@ import jcs.entities.SensorBean; import jcs.persistence.PersistenceFactory; import jcs.ui.layout.LayoutCanvas; +import jcs.ui.layout.TileCache; import jcs.ui.layout.tiles.Block; import jcs.ui.layout.tiles.Sensor; import jcs.ui.layout.tiles.Tile; @@ -100,7 +101,7 @@ private void postInit() { if (bb == null) { Logger.tags("bb is null for " + this.block.getId()); bb = new BlockBean(); - bb.setTile(block); + bb.setTile(block.getTileBean()); bb.setTileId(this.block.getId()); bb.setBlockState(BlockBean.BlockState.FREE); this.block.setBlockBean(bb); @@ -161,8 +162,10 @@ private void autoLink() { Logger.trace("Neighbor point +: " + pnp + " -: " + mnp); - Tile neighborPlus = this.layoutCanvas.findTile(pnp); - Tile neighborMin = this.layoutCanvas.findTile(mnp); + //Tile neighborPlus = this.layoutCanvas.findTile(pnp); + Tile neighborPlus = TileCache.findTile(pnp); + //Tile neighborMin = this.layoutCanvas.findTile(mnp); + Tile neighborMin = TileCache.findTile(mnp); if (neighborPlus != null && neighborPlus instanceof Sensor) { Sensor ps = (Sensor) neighborPlus; diff --git a/src/main/java/jcs/ui/layout/dialogs/SensorDialog.java b/src/main/java/jcs/ui/layout/dialogs/SensorDialog.java index 88b823c5..baf222ca 100644 --- a/src/main/java/jcs/ui/layout/dialogs/SensorDialog.java +++ b/src/main/java/jcs/ui/layout/dialogs/SensorDialog.java @@ -263,7 +263,7 @@ private void saveExitBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-F if (PersistenceFactory.getService() != null) { PersistenceFactory.getService().persist(sensorBean); - PersistenceFactory.getService().persist((sensor)); + PersistenceFactory.getService().persist((sensor.getTileBean())); JCS.getJcsCommandStation().addSensorEventListener(sensor); } } else if (this.sensor != null && this.sensor.getSensorBean() == null) { @@ -274,7 +274,7 @@ private void saveExitBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-F sensor.setSensorBean(sensorBean); Logger.trace("Created " + sensorBean); - PersistenceFactory.getService().persist((sensor)); + PersistenceFactory.getService().persist((sensor.getTileBean())); JCS.getJcsCommandStation().addSensorEventListener(sensor); } } diff --git a/src/main/java/jcs/ui/layout/dialogs/SignalDialog.java b/src/main/java/jcs/ui/layout/dialogs/SignalDialog.java index 064ae907..2e457e98 100644 --- a/src/main/java/jcs/ui/layout/dialogs/SignalDialog.java +++ b/src/main/java/jcs/ui/layout/dialogs/SignalDialog.java @@ -183,11 +183,11 @@ public void actionPerformed(java.awt.event.ActionEvent evt) { private void saveExitBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_saveExitBtnActionPerformed if (this.signal != null && this.signal.getAccessoryBean() != null) { if (this.signal.getAccessoryBean().getName() != null) { - PersistenceFactory.getService().persist((signal)); + PersistenceFactory.getService().persist((signal.getTileBean())); JCS.getJcsCommandStation().addAccessoryEventListener(signal); } else { this.signal.setAccessoryBean(null); - PersistenceFactory.getService().persist((signal)); + PersistenceFactory.getService().persist((signal.getTileBean())); } } this.setVisible(false); diff --git a/src/main/java/jcs/ui/layout/dialogs/SwitchDialog.java b/src/main/java/jcs/ui/layout/dialogs/SwitchDialog.java index 5916bbb3..0334d85b 100644 --- a/src/main/java/jcs/ui/layout/dialogs/SwitchDialog.java +++ b/src/main/java/jcs/ui/layout/dialogs/SwitchDialog.java @@ -189,12 +189,12 @@ public void actionPerformed(java.awt.event.ActionEvent evt) { private void saveExitBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_saveExitBtnActionPerformed if (this.turnout != null && this.turnout.getAccessoryBean() != null) { if (this.turnout.getAccessoryBean().getName() != null) { - PersistenceFactory.getService().persist((turnout)); + PersistenceFactory.getService().persist((turnout.getTileBean())); JCS.getJcsCommandStation().addAccessoryEventListener(turnout); } else { this.turnout.setAccessoryBean(null); - PersistenceFactory.getService().persist((turnout)); + PersistenceFactory.getService().persist((turnout.getTileBean())); } } this.setVisible(false); diff --git a/src/main/java/jcs/ui/layout/tiles/AbstractTile.java b/src/main/java/jcs/ui/layout/tiles/AbstractTile.java deleted file mode 100755 index 87013362..00000000 --- a/src/main/java/jcs/ui/layout/tiles/AbstractTile.java +++ /dev/null @@ -1,893 +0,0 @@ -/* - * Copyright 2024 Frans Jacobs. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package jcs.ui.layout.tiles; - -import java.awt.Color; -import java.awt.Graphics2D; -import java.awt.Point; -import java.awt.Rectangle; -import java.awt.geom.AffineTransform; -import java.awt.geom.Ellipse2D; -import java.awt.geom.PathIterator; -import java.awt.geom.Point2D; -import java.awt.geom.Rectangle2D; -import java.awt.image.AffineTransformOp; -import java.awt.image.BufferedImage; -import java.beans.PropertyChangeEvent; -import java.beans.PropertyChangeListener; -import java.util.Collection; -import java.util.Collections; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; -import jcs.entities.AccessoryBean.AccessoryValue; -import jcs.entities.TileBean; -import jcs.ui.layout.LayoutUtil; -import jcs.ui.layout.events.TileEvent; -import jcs.ui.layout.events.TileEventListener; -import static jcs.ui.layout.tiles.Tile.DEFAULT_TRACK_COLOR; -import org.imgscalr.Scalr; -import org.imgscalr.Scalr.Method; -import org.imgscalr.Scalr.Mode; - -/** - * Basic graphic element to display a track, turnout, etc on the screen.
- * By default the drawing of a Tile is Horizontal from L to R or West to East.
- * The default orientation is East. - * - *

- * The default size of a Tile is 40 x 40 pixels.
- * The center point of a Tile is stored and always snapped to the nearest grid point.
- * The basic grid is 20x 20 pixels.
- * - *

- * A Tile can be rotated (always clockwise).
- * Rotation will change the orientation from East -> South -> West -> North -> East.
- * - *

- * A Tile is rendered to a Buffered Image to speed up the display - */ -abstract class AbstractTile extends TileBean implements Tile, TileEventListener { - - protected int width; - protected int height; - protected int renderWidth; - protected int renderHeight; - - protected int offsetX = 0; - protected int offsetY = 0; - - protected int renderOffsetX = 0; - protected int renderOffsetY = 0; - - protected Color trackColor; - protected Color trackRouteColor; - protected Orientation incomingSide; - protected boolean drawRoute = false; - - protected Color backgroundColor; - protected boolean drawName = true; - - protected boolean drawOutline = false; - - protected boolean scaleImage = true; - - protected BufferedImage tileImage; - - protected PropertyChangeListener propertyChangeListener; - - protected AbstractTile(Point center) { - this(Orientation.EAST, Direction.CENTER, center.x, center.y); - } - - protected AbstractTile(Orientation orientation, Point center) { - this(orientation, Direction.CENTER, center.x, center.y); - } - - protected AbstractTile(Orientation orientation, int x, int y) { - this(orientation, Direction.CENTER, x, y); - } - - protected AbstractTile(Orientation orientation, Direction direction, int x, int y) { - this(orientation, direction, x, y, null); - } - - protected AbstractTile(Orientation orientation, Direction direction, int x, int y, Color backgroundColor) { - this.tileOrientation = orientation.getOrientation(); - this.tileDirection = direction.getDirection(); - - this.x = x; - this.y = y; - this.width = DEFAULT_WIDTH; - this.height = DEFAULT_HEIGHT; - this.renderWidth = RENDER_WIDTH; - this.renderHeight = RENDER_HEIGHT; - - this.trackColor = DEFAULT_TRACK_COLOR; - this.backgroundColor = backgroundColor; - if (this.backgroundColor == null) { - this.backgroundColor = DEFAULT_BACKGROUND_COLOR; - } - } - - protected AbstractTile(TileBean tileBean) { - copyInto(tileBean); - this.trackColor = DEFAULT_TRACK_COLOR; - this.backgroundColor = DEFAULT_BACKGROUND_COLOR; - this.renderWidth = RENDER_WIDTH; - this.renderHeight = RENDER_HEIGHT; - } - - private void copyInto(TileBean other) { - this.id = other.getId(); - this.type = other.getType(); - this.tileOrientation = other.getTileOrientation(); - this.tileDirection = other.getTileDirection(); - this.x = other.getX(); - this.y = other.getY(); - - if (other instanceof AbstractTile abstractTile) { - this.renderWidth = abstractTile.renderWidth; - this.renderHeight = abstractTile.renderHeight; - } - - this.setSignalType(other.getSignalType()); - this.accessoryId = other.getAccessoryId(); - this.signalAccessoryType = other.getSignalAccessoryType(); - this.sensorId = other.getSensorId(); - this.accessoryBean = other.getAccessoryBean(); - this.sensorBean = other.getSensorBean(); - this.blockBean = other.getBlockBean(); - } - - @Override - public TileBean getTileBean() { - TileBean tb = new TileBean(); - - tb.setId(this.id); - tb.setX(this.x); - tb.setY(this.y); - tb.setType(this.type); - tb.setTileOrientation(this.tileOrientation); - tb.setTileDirection(this.tileDirection); - tb.setSignalAccessoryType(this.signalAccessoryType); - tb.setAccessoryId(this.accessoryId); - tb.setSensorId(this.sensorId); - tb.setAccessoryBean(this.accessoryBean); - tb.setSensorBean(this.sensorBean); - tb.setBlockBean(this.blockBean); - - return tb; - } - - @Override - public Color getTrackColor() { - return trackColor; - } - - @Override - public final void setTrackColor(Color trackColor) { - this.trackColor = trackColor; - } - - @Override - public Color getTrackRouteColor() { - return trackRouteColor; - } - - @Override - public void setTrackRouteColor(Color trackRouteColor) { - this.trackRouteColor = trackRouteColor; - } - - @Override - public Orientation getIncomingSide() { - return incomingSide; - } - - @Override - public void setIncomingSide(Orientation incomingSide) { - this.incomingSide = incomingSide; - } - - @Override - public Color getBackgroundColor() { - return backgroundColor; - } - - @Override - public void setBackgroundColor(Color backgroundColor) { - this.backgroundColor = backgroundColor; - } - - @Override - public boolean isDrawRoute() { - return drawRoute; - } - - @Override - public void setDrawRoute(boolean drawRoute) { - this.drawRoute = drawRoute; - } - - public int getRenderWidth() { - return renderWidth; - } - - public int getRenderHeight() { - return renderHeight; - } - - /** - * Draw the AbstractTile - * - * @param g2d The graphics handle - * @param drawOutline - */ - @Override - public void drawTile(Graphics2D g2d, boolean drawOutline) { - // by default and image is rendered in the EAST orientation - Orientation o = getOrientation(); - if (o == null) { - o = Orientation.EAST; - } - - tileImage = createImage(); - Graphics2D g2di = tileImage.createGraphics(); - - //Avoid errors - if (drawRoute && incomingSide == null) { - incomingSide = getOrientation(); - } - - g2di.setBackground(backgroundColor); - g2di.clearRect(0, 0, this.renderWidth, this.renderHeight); - int ox = 0, oy = 0; - - AffineTransform trans = new AffineTransform(); - switch (o) { - case SOUTH -> { - trans.rotate(Math.PI / 2, this.renderWidth / 2, this.renderHeight / 2); - ox = (this.renderHeight - this.renderWidth) / 2; - oy = (this.renderWidth - this.renderHeight) / 2; - trans.translate(-ox, -oy); - } - case WEST -> { - trans.rotate(Math.PI, this.renderWidth / 2, this.renderHeight / 2); - trans.translate(ox, oy); - } - case NORTH -> { - trans.rotate(-Math.PI / 2, this.renderWidth / 2, this.renderHeight / 2); - ox = (this.renderHeight - this.renderWidth) / 2; - oy = (this.renderWidth - this.renderHeight) / 2; - trans.translate(-ox, -oy); - } - default -> { - trans.rotate(0.0, this.renderWidth / 2, this.renderHeight / 2); - trans.translate(ox, oy); - } - } - - g2di.setTransform(trans); - renderTile(g2di); - - if (drawRoute) { - renderTileRoute(g2di); - } - - //When the line grid is one the scale tile must be a little smaller - int sw, sh; - if (drawOutline) { - sw = this.getWidth() - 2; - sh = this.getHeight() - 2; - } else { - sw = this.getWidth(); - sh = this.getHeight(); - } - // Scale the image back... - if (scaleImage) { - tileImage = Scalr.resize(tileImage, Method.QUALITY, Mode.FIT_EXACT, sw, sh, Scalr.OP_ANTIALIAS); - } - - g2di.dispose(); - int oxx, oyy; - if (scaleImage) { - oxx = offsetX; - oyy = offsetY; - } else { - oxx = renderOffsetX; - oyy = renderOffsetY; - } - - g2d.drawImage(tileImage, (x - tileImage.getWidth() / 2) + oxx, (y - tileImage.getHeight() / 2) + oyy, null); - } - - @Override - public BufferedImage getTileImage() { - return tileImage; - } - - /** - * Render a tile image Always starts at (0,0) used the default width and height - * - * @param g2 the Graphic context - */ - @Override - public void drawName(Graphics2D g2) { - } - - @Override - public void drawCenterPoint(Graphics2D g2d) { - drawCenterPoint(g2d, Color.GRAY); - } - - @Override - public void drawCenterPoint(Graphics2D g2, Color color) { - drawCenterPoint(g2, color, 4); - } - - @Override - public void drawCenterPoint(Graphics2D g2d, Color color, double size) { - double dX = (this.x - size / 2); - double dY = (this.y - size / 2); - - g2d.setColor(color); - g2d.fill(new Ellipse2D.Double(dX, dY, size, size)); - - if (!getAltPoints().isEmpty()) { - // Also draw the alt points - Set alt = new HashSet<>(getAltPoints()); - - for (Point ap : alt) { - g2d.fill(new Ellipse2D.Double(ap.x, ap.y, size - 1, size - 1)); - } - } - } - - @Override - public void drawBounds(Graphics2D g2d) { - g2d.setColor(Color.yellow); - g2d.draw(getBounds()); - } - - /** - * Rotate the tile clockwise 90 deg - */ - @Override - public void rotate() { - switch (getOrientation()) { - case EAST -> - setOrientation(Orientation.SOUTH); - case SOUTH -> - setOrientation(Orientation.WEST); - case WEST -> - setOrientation(Orientation.NORTH); - default -> - setOrientation(Orientation.EAST); - } - } - - @Override - public void flipHorizontal() { - if (Orientation.NORTH.equals(getOrientation()) || Orientation.SOUTH.equals(getOrientation())) { - rotate(); - rotate(); - } - } - - @Override - public void flipVertical() { - if (Orientation.EAST.equals(getOrientation()) || Orientation.WEST.equals(getOrientation())) { - rotate(); - rotate(); - } - } - - @Override - public void move(int newX, int newY) { - Point cs = LayoutUtil.snapToGrid(newX, newY); - this.setCenter(cs); - } - - protected static void drawRotate(Graphics2D g2d, double x, double y, int angle, String text) { - g2d.translate((float) x, (float) y); - g2d.rotate(Math.toRadians(angle)); - g2d.drawString(text, 0, 0); - g2d.rotate(-Math.toRadians(angle)); - g2d.translate(-x, -y); - } - - public static BufferedImage flipHorizontally(BufferedImage source) { - BufferedImage output = new BufferedImage(source.getHeight(), source.getWidth(), source.getType()); - - AffineTransform flip = AffineTransform.getScaleInstance(1, -1); - flip.translate(0, -source.getHeight()); - AffineTransformOp op = new AffineTransformOp(flip, AffineTransformOp.TYPE_NEAREST_NEIGHBOR); - - op.filter(source, output); - - return output; - } - - public static BufferedImage flipVertically(BufferedImage source) { - BufferedImage output = new BufferedImage(source.getHeight(), source.getWidth(), source.getType()); - - AffineTransform flip = AffineTransform.getScaleInstance(-1, 1); - flip.translate(-source.getWidth(), 0); - AffineTransformOp op = new AffineTransformOp(flip, AffineTransformOp.TYPE_NEAREST_NEIGHBOR); - - op.filter(source, output); - - return output; - } - - @Override - public void setOrientation(Orientation orientation) { - this.tileOrientation = orientation.getOrientation(); - } - - @Override - public void setDirection(Direction direction) { - this.tileDirection = direction.getDirection(); - } - - @Override - public void setCenter(Point center) { - this.x = center.x; - this.y = center.y; - } - - @Override - public Set getAltPoints() { - return Collections.EMPTY_SET; - } - - @Override - public final int getOffsetX() { - return offsetX; - } - - @Override - public void setOffsetX(int offsetX) { - this.offsetX = offsetX; - } - - @Override - public final int getOffsetY() { - return offsetY; - } - - @Override - public void setOffsetY(int offsetY) { - this.offsetY = offsetY; - } - - protected BufferedImage createImage() { - return new BufferedImage(this.renderWidth, this.renderHeight, BufferedImage.TYPE_INT_RGB); - } - - @Override - public int getCenterX() { - if (this.x > 0) { - return this.x; - } else { - return GRID; - } - } - - @Override - public int getCenterY() { - if (this.y > 0) { - return this.y; - } else { - return GRID; - } - } - - public boolean isDrawName() { - return drawName; - } - - public void setDrawName(boolean drawName) { - this.drawName = drawName; - } - - @Override - public boolean isDrawOutline() { - return drawOutline; - } - - public boolean isScaleImage() { - return scaleImage; - } - - public void setScaleImage(boolean scaleImage) { - this.scaleImage = scaleImage; - } - - @Override - public void setDrawOutline(boolean drawOutline) { - if (this.drawOutline != drawOutline) { - this.drawOutline = drawOutline; - } - } - - @Override - public String toString() { - return this.getClass().getSimpleName() - + " {id: " - + id - + ", orientation: " - + getOrientation() - + ", direction: " - + getDirection() - + ", center: " - + xyToString() - + "}"; - } - - @Override - public Rectangle getBounds() { - int w, h, cx, cy; - if (this.width > 0 & this.height > 0) { - w = this.width; - h = this.height; - } else { - w = DEFAULT_WIDTH; - h = DEFAULT_HEIGHT; - } - - if (this.x > 0 && this.y > 0) { - cx = this.x + this.offsetX; - cy = this.y + this.offsetY; - } else { - cx = w / 2; - cy = h / 2; - } - - int ltx = cx - w / 2; - int lty = cy - h / 2; - return new Rectangle(ltx, lty, w, h); - } - - @Override - public Rectangle2D getBounds2D() { - return getBounds().getBounds2D(); - } - - @Override - public boolean contains(double x, double y) { - int w, h, cx, cy, tlx, tly; - if (this.width > 0 & this.height > 0) { - w = this.width; - h = this.height; - } else { - w = DEFAULT_WIDTH; - h = DEFAULT_HEIGHT; - } - - if (this.width > 0 & this.height > 0) { - cx = this.x; - cy = this.y; - } else { - cx = w / 2; - cy = h / 2; - } - - // top left dX and dY - tlx = cx - w / 2; - tly = cy - h / 2; - - // Check if X and Y range is ok - return !(x < tlx || x > (tlx + w) || y < tly || y > (tly + h)); - } - - @Override - public String xyToString() { - return "(" + this.x + "," + this.y + ")"; - } - - @Override - public boolean contains(Point2D p) { - return this.contains(p.getX(), p.getY()); - } - - @Override - public boolean intersects(double x, double y, double w, double h) { - return getBounds().intersects(x, y, w, h); - } - - @Override - public boolean intersects(Rectangle2D r2d) { - return getBounds().intersects(r2d); - } - - @Override - public boolean contains(double x, double y, double w, double h) { - return getBounds().contains(x, y, w, h); - } - - @Override - public boolean contains(Rectangle2D r2d) { - return getBounds().contains(r2d); - } - - @Override - public PathIterator getPathIterator(AffineTransform at) { - return getBounds().getPathIterator(at); - } - - @Override - public PathIterator getPathIterator(AffineTransform at, double flatness) { - return getBounds().getPathIterator(at, flatness); - } - - public PropertyChangeListener getPropertyChangeListener() { - return this.propertyChangeListener; - } - - @Override - public void setPropertyChangeListener(PropertyChangeListener propertyChangeListener) { - this.propertyChangeListener = propertyChangeListener; - } - - public void repaintTile() { - if (this.propertyChangeListener != null) { - this.propertyChangeListener.propertyChange(new PropertyChangeEvent(this, "repaintTile", this, this)); - } - } - - @Override - public void onTileChange(TileEvent tileEvent) { - if (tileEvent.isEventFor(this)) { - drawRoute = tileEvent.isShowRoute(); - setIncomingSide(tileEvent.getIncomingSide()); - - if (isJunction()) { - ((Switch) this).setRouteValue(tileEvent.getRouteState()); - } - - if (tileEvent.getBlockBean() != null) { - setBlockBean(tileEvent.getBlockBean()); - } - - if (tileEvent.getTileBean() != null) { - TileBean other = tileEvent.getTileBean(); - this.copyInto(other); - } - - if (isBlock()) { - ((Block) this).setRouteBlockState(tileEvent.getBlockState()); - if (!drawRoute) { - ((Block) this).setRouteBlockState(null); - } - } - - setBackgroundColor(tileEvent.getBackgroundColor()); - setTrackColor(tileEvent.getTrackColor()); - setTrackRouteColor(tileEvent.getTrackRouteColor()); - -// if (tileEvent.getBlockBean() != null) { -// setBlockBean(tileEvent.getBlockBean()); -// } - repaintTile(); - } - } - - @Override - public int getWidth() { - return this.width; - } - - @Override - public int getHeight() { - return this.height; - } - - @Override - public int getGridX() { - return (getCenterX() - Tile.GRID) / (Tile.GRID * 2); - } - - @Override - public int getGridY() { - return (getCenterY() - Tile.GRID) / (Tile.GRID * 2); - } - - /** - * The main route of the tile is horizontal - * - * @return true when main route goes from East to West or vv - */ - @Override - public boolean isHorizontal() { - return (Orientation.EAST == getOrientation() || Orientation.WEST == getOrientation()) && TileType.CURVED != getTileType(); - } - - /** - * The main route of the tile is vertical - * - * @return true when main route goes from North to South or vv - */ - @Override - public boolean isVertical() { - return (Orientation.NORTH == getOrientation() || Orientation.SOUTH == getOrientation()) && TileType.CURVED != getTileType(); - } - - @Override - public boolean isJunction() { - return false; - } - - @Override - public boolean isBlock() { - return false; - } - - @Override - public boolean isDirectional() { - return false; - } - - /** - * The main route of the tile is diagonal - * - * @return true when main route goes from North to East or West to South and vv - */ - @Override - public boolean isDiagonal() { - return TileType.CURVED == getTileType(); - } - - @Override - public boolean isCrossing() { - return TileType.CROSSING == getTileType(); - } - - public List getNeighbours() { - return neighbours; - } - - public void setNeighbours(List neighbours) { - this.neighbours = neighbours; - } - - @Override - public String getIdSuffix(Tile other) { - return ""; - } - - @Override - public Map getNeighborOrientations() { - Map edgeOrientations = new HashMap<>(); - - Map neighborPoints = getNeighborPoints(); - - for (Orientation o : Orientation.values()) { - edgeOrientations.put(neighborPoints.get(o), o); - } - return edgeOrientations; - } - - @Override - public Map getEdgeOrientations() { - Map edgeOrientations = new HashMap<>(); - - Map edgeConnections = getEdgePoints(); - - for (Orientation o : Orientation.values()) { - edgeOrientations.put(edgeConnections.get(o), o); - } - return edgeOrientations; - } - - @Override - public boolean isAdjacent(Tile other) { - boolean adjacent = false; - - if (other != null) { - Collection thisEdgePoints = getEdgePoints().values(); - Collection otherEdgePoints = other.getEdgePoints().values(); - - for (Point p : thisEdgePoints) { - adjacent = otherEdgePoints.contains(p); - if (adjacent) { - break; - } - } - } - - return adjacent; - } - - /** - * When the tile has a specific direction a train may travel then this method will indicate whether the other tile is in on the side where the arrow is pointing to - * - * @param other A Tile - * @return true where other is on the side of this tile where the arrow points to - */ - @Override - public boolean isArrowDirection(Tile other) { - return true; - } - - @Override - public AccessoryValue accessoryValueForRoute(Orientation from, Orientation to) { - return AccessoryValue.OFF; - } - - protected StringBuilder getImageKeyBuilder() { - StringBuilder sb = new StringBuilder(); - //sb.append(id); - sb.append(type); - sb.append("~"); - sb.append(getOrientation().getOrientation()); - sb.append("~"); - sb.append(getDirection().getDirection()); - sb.append("~"); - sb.append(isDrawOutline() ? "y" : "n"); - sb.append("~"); - int r = backgroundColor.getRed(); - int g = backgroundColor.getGreen(); - int b = backgroundColor.getBlue(); - sb.append("#"); - sb.append(r); - sb.append("#"); - sb.append(g); - sb.append("#"); - sb.append(b); - sb.append("~"); - r = trackColor.getRed(); - g = trackColor.getGreen(); - b = trackColor.getBlue(); - sb.append("#"); - sb.append(r); - sb.append("#"); - sb.append(g); - sb.append("#"); - sb.append(b); - sb.append("~"); - sb.append(isDrawRoute() ? "y" : "n"); - if (isDrawRoute()) { - if (incomingSide != null) { - sb.append("~"); - sb.append(incomingSide.getOrientation()); - } - sb.append("~"); - r = trackRouteColor.getRed(); - g = trackRouteColor.getGreen(); - b = trackRouteColor.getBlue(); - sb.append("#"); - sb.append(r); - sb.append("#"); - sb.append(g); - sb.append("#"); - sb.append(b); - } - - //sb.append("~"); - //Tile specific properties - //AccessoryValue - //SignalType - //SignalValue - //active; - //Logger.trace(sb); - return sb; - } - -} diff --git a/src/main/java/jcs/ui/layout/tiles/Block.java b/src/main/java/jcs/ui/layout/tiles/Block.java index 4635a845..780c3907 100755 --- a/src/main/java/jcs/ui/layout/tiles/Block.java +++ b/src/main/java/jcs/ui/layout/tiles/Block.java @@ -17,10 +17,13 @@ import java.awt.BasicStroke; import java.awt.Color; +import java.awt.Dimension; import java.awt.Font; +import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.Image; import java.awt.Point; +import java.awt.geom.Ellipse2D; import java.util.HashMap; import java.util.HashSet; import java.util.Map; @@ -29,7 +32,6 @@ import jcs.entities.BlockBean.BlockState; import jcs.entities.LocomotiveBean; import jcs.entities.TileBean; -import jcs.entities.TileBean.Direction; import jcs.entities.TileBean.Orientation; import static jcs.entities.TileBean.Orientation.EAST; import static jcs.entities.TileBean.Orientation.NORTH; @@ -42,56 +44,106 @@ import static jcs.ui.layout.tiles.Tile.RENDER_HEIGHT; import static jcs.ui.layout.tiles.Tile.RENDER_WIDTH; import jcs.ui.util.ImageUtil; +import org.tinylog.Logger; -public class Block extends AbstractTile implements Tile { +public class Block extends Tile { public static final int BLOCK_WIDTH = DEFAULT_WIDTH * 3; public static final int BLOCK_HEIGHT = DEFAULT_HEIGHT * 3; protected BlockState routeBlockState; - Block(TileBean tileBean) { - super(tileBean); - if (Orientation.EAST.equals(getOrientation()) || Orientation.WEST.equals(getOrientation())) { - this.width = BLOCK_WIDTH; + private static int blockWidth(Orientation orientation) { + if (Orientation.EAST == orientation || Orientation.WEST == orientation) { + return BLOCK_WIDTH; + } else { + return DEFAULT_WIDTH; + } + } + + private static int blockHeight(Orientation orientation) { + if (Orientation.EAST == orientation || Orientation.WEST == orientation) { + return DEFAULT_HEIGHT; + } else { + return BLOCK_HEIGHT; + } + } + + public Block(TileBean tileBean) { + super(tileBean, blockWidth(tileBean.getOrientation()), blockHeight(tileBean.getOrientation())); + setModel(new DefaultTileModel()); + + if (Orientation.EAST == tileBean.getOrientation() || Orientation.WEST == tileBean.getOrientation()) { this.renderWidth = RENDER_WIDTH * 3; - this.height = DEFAULT_HEIGHT; this.renderHeight = RENDER_HEIGHT; } else { - this.width = DEFAULT_WIDTH; this.renderWidth = RENDER_WIDTH; - this.height = BLOCK_HEIGHT; this.renderHeight = RENDER_HEIGHT * 3; } - this.blockBean = tileBean.getBlockBean(); - this.type = tileBean.getType(); } - Block(Orientation orientation, Point center) { + public Block(Orientation orientation, Point center) { this(orientation, center.x, center.y); } - Block(Orientation orientation, int x, int y) { - super(orientation, Direction.CENTER, x, y); + public Block(Orientation orientation, int x, int y) { + this(orientation, x, y, blockWidth(orientation), blockHeight(orientation)); + } + + public Block(Orientation orientation, int x, int y, int width, int height) { + super(TileType.BLOCK, orientation, x, y, width, height); + setModel(new DefaultTileModel()); - if (Orientation.EAST == getOrientation() || Orientation.WEST == getOrientation()) { - this.width = BLOCK_WIDTH; + if (Orientation.EAST == orientation || Orientation.WEST == orientation) { this.renderWidth = RENDER_WIDTH * 3; - this.height = DEFAULT_HEIGHT; this.renderHeight = RENDER_HEIGHT; } else { - this.width = DEFAULT_WIDTH; this.renderWidth = RENDER_WIDTH; - this.height = BLOCK_HEIGHT; this.renderHeight = RENDER_HEIGHT * 3; } - this.type = TileType.BLOCK.getTileType(); } +// Block(TileBean tileBean) { +// super(tileBean); +// if (Orientation.EAST.equals(getOrientation()) || Orientation.WEST.equals(getOrientation())) { +// this.width = BLOCK_WIDTH; +// this.renderWidth = RENDER_WIDTH * 3; +// this.height = DEFAULT_HEIGHT; +// this.renderHeight = RENDER_HEIGHT; +// } else { +// this.width = DEFAULT_WIDTH; +// this.renderWidth = RENDER_WIDTH; +// this.height = BLOCK_HEIGHT; +// this.renderHeight = RENDER_HEIGHT * 3; +// } +// this.blockBean = tileBean.getBlockBean(); +// this.tileType = tileBean.getTileType(); +// this.setLayout(null); +// } +// Block(Orientation orientation, Point center) { +// this(orientation, center.x, center.y); +// } +// Block(Orientation orientation, int x, int y) { +// super(orientation, Direction.CENTER, x, y); +// +// if (Orientation.EAST == getOrientation() || Orientation.WEST == getOrientation()) { +// this.width = BLOCK_WIDTH; +// this.renderWidth = RENDER_WIDTH * 3; +// this.height = DEFAULT_HEIGHT; +// this.renderHeight = RENDER_HEIGHT; +// } else { +// this.width = DEFAULT_WIDTH; +// this.renderWidth = RENDER_WIDTH; +// this.height = BLOCK_HEIGHT; +// this.renderHeight = RENDER_HEIGHT * 3; +// } +// this.tileType = TileType.BLOCK; +// this.setLayout(null); +// } @Override public Set getAltPoints() { - int xx = this.x; - int yy = this.y; + int xx = this.tileX; + int yy = this.tileY; Set alternatives = new HashSet<>(); if (Orientation.EAST.equals(getOrientation()) || Orientation.WEST.equals(getOrientation())) { @@ -291,43 +343,24 @@ public String getIdSuffix(Tile other) { @Override public void rotate() { super.rotate(); + Dimension d; if (Orientation.EAST.equals(getOrientation()) || Orientation.WEST.equals(getOrientation())) { - this.width = DEFAULT_WIDTH * 3; - this.height = DEFAULT_HEIGHT; + d = new Dimension(DEFAULT_WIDTH * 3, DEFAULT_HEIGHT); + //this.width = DEFAULT_WIDTH * 3; + //this.height = DEFAULT_HEIGHT; this.renderWidth = RENDER_WIDTH * 3; this.renderHeight = RENDER_HEIGHT; } else { - this.width = DEFAULT_WIDTH; - this.height = DEFAULT_HEIGHT * 3; + d = new Dimension(DEFAULT_WIDTH, DEFAULT_HEIGHT * 3); + //this.width = DEFAULT_WIDTH; + //this.height = DEFAULT_HEIGHT * 3; this.renderWidth = RENDER_WIDTH; this.renderHeight = RENDER_HEIGHT * 3; } - } - - public void setWidth(int width) { - this.width = width; - } - - public void setHeight(int height) { - this.height = height; - } - - public void setRenderWidth(int renderWidth) { - this.renderWidth = renderWidth; - } - - public void setRenderHeight(int renderHeight) { - this.renderHeight = renderHeight; - } - - public void setRenderOffsetX(int renderOffsetX) { - this.renderOffsetX = renderOffsetX; - } - - public void setRenderOffsetY(int renderOffsetY) { - this.renderOffsetY = renderOffsetY; + setSize(d); + setPreferredSize(d); } /** @@ -340,16 +373,11 @@ public void setRenderOffsetY(int renderOffsetY) { * * @return the Color which belong with the current Block State */ - public Color getBlockStateColor() { - if (blockBean != null) { - BlockState blockState = blockBean.getBlockState(); - return getBlockStateColor(blockState); - } else { - return Color.white; - } + Color getBlockStateColor() { + return getBlockStateColor(this.model.getBlockState()); } - public Color getBlockStateColor(BlockState blockState) { + protected Color getBlockStateColor(BlockState blockState) { return switch (blockState) { case GHOST -> new Color(250, 0, 0); @@ -376,21 +404,6 @@ public BlockState getRouteBlockState() { return routeBlockState; } - public BlockState getBlockState() { - if (blockBean != null) { - return blockBean.getBlockState(); - } else { - return BlockState.FREE; - } - } - - public void setBlockState(BlockState blockState) { - if (blockBean == null) { - this.blockBean = new BlockBean((TileBean) this); - } - blockBean.setBlockState(blockState); - } - public static String getDepartureSuffix(Orientation tileOrientation, boolean reverseArrival, LocomotiveBean.Direction direction) { if (LocomotiveBean.Direction.FORWARDS == direction) { if (Orientation.EAST == tileOrientation || Orientation.SOUTH == tileOrientation) { @@ -545,7 +558,6 @@ private void renderDirectionArrow(Graphics2D g2) { } } } - } private void renderLeftArrow(Graphics2D g2) { @@ -594,18 +606,18 @@ protected void overlayLocImage(Graphics2D g2d) { int h = locImage.getHeight(null); if (null == departureSuffix) { - xx = x - width / 2 + w; + xx = tileX - getWidth() / 2 + w; } else { switch (departureSuffix) { case "+" -> { - xx = x - width / 2 + w - 25; + xx = tileX - getWidth() / 2 + w - 25; } default -> { - xx = x - width / 2 + w + 10; + xx = tileX - getWidth() / 2 + w + 10; } } } - int yy = y - h / 2; + int yy = tileY - h / 2; if (reverseImage) { locImage = ImageUtil.flipVertically(locImage); @@ -619,17 +631,17 @@ protected void overlayLocImage(Graphics2D g2d) { int w = locImage.getWidth(null); int h = locImage.getHeight(null); - int xx = x - w / 2; + int xx = tileX - w / 2; int yy; if (null == departureSuffix) { - yy = y - height / 2 + h; + yy = tileY - getHeight() / 2 + h; } else { switch (departureSuffix) { case "-" -> { - yy = y - height / 2 + h - 25; + yy = tileY - getHeight() / 2 + h - 25; } default -> { - yy = y - height / 2 + h + 10; + yy = tileY - getHeight() / 2 + h + 10; } } } @@ -645,18 +657,18 @@ protected void overlayLocImage(Graphics2D g2d) { int w = locImage.getWidth(null); int h = locImage.getHeight(null); - int xx = x - w / 2; + int xx = tileX - w / 2; int yy; if (null == departureSuffix) { - int minY = y - height / 2 + h; + int minY = tileY - getHeight() / 2 + h; yy = minY; } else { switch (departureSuffix) { case "+" -> { - yy = y - height / 2 + h - 25; + yy = tileY - getHeight() / 2 + h - 25; } default -> { - yy = y - height / 2 + h + 10; + yy = tileY - getHeight() / 2 + h + 10; } } } @@ -672,18 +684,18 @@ protected void overlayLocImage(Graphics2D g2d) { int h = locImage.getHeight(null); if (null == departureSuffix) { - xx = x - width / 2 + w; + xx = tileX - getWidth() / 2 + w; } else { switch (departureSuffix) { case "-" -> { - xx = x - width / 2 + w - 25; + xx = tileX - getWidth() / 2 + w - 25; } default -> { - xx = x - width / 2 + w + 10; + xx = tileX - getWidth() / 2 + w + 10; } } } - int yy = y - h / 2; + int yy = tileY - h / 2; if (reverseImage) { locImage = ImageUtil.flipVertically(locImage); @@ -698,11 +710,10 @@ protected void overlayLocImage(Graphics2D g2d) { * Overridden to overlay a locomotive Icon * * @param g2d The graphics handle - * @param drawOutline */ @Override - public void drawTile(Graphics2D g2d, boolean drawOutline) { - super.drawTile(g2d, drawOutline); + public void drawTile(Graphics2D g2d) { + super.drawTile(g2d); if (getLocImage() != null) { overlayLocImage(g2d); } @@ -714,7 +725,7 @@ public void onTileChange(TileEvent tileEvent) { Color pb = this.backgroundColor; super.onTileChange(tileEvent); if (!pb.equals(backgroundColor)) { - repaintTile(); + repaint(); } } @@ -735,7 +746,7 @@ private Image getLocImage() { public String getBlockText() { String blockText; - if (!drawOutline && getBlockBean() != null && getBlockBean().getDescription() != null) { + if (getBlockBean() != null && getBlockBean().getDescription() != null) { if (blockBean.getLocomotive() != null && blockBean.getLocomotive().getName() != null && BlockState.GHOST != blockBean.getBlockState()) { blockText = getBlockBean().getLocomotive().getName(); } else { @@ -800,4 +811,71 @@ public void drawName(Graphics2D g2d) { g2d.setFont(newFont); } } + + @Override + protected void paintComponent(Graphics g) { + long started = System.currentTimeMillis(); + super.paintComponent(g); + + if (tileOrientation == Orientation.EAST || tileOrientation == Orientation.WEST) { + setBounds(this.tileX - GRID - GRID * 2, this.tileY - GRID, this.getWidth(), this.getHeight()); + } else { + setBounds(this.tileX - GRID, this.tileY - GRID - GRID * 2, this.getWidth(), this.getHeight()); + } + + Graphics2D g2 = (Graphics2D) g.create(); + drawTile(g2); + g2.dispose(); + + g.drawImage(tileImage, 0, 0, null); + + Logger.trace(id + ": W: " + getWidth() + " H: " + getHeight() + " oX: " + renderOffsetX + " oY: " + renderOffsetY); + + long now = System.currentTimeMillis(); + Logger.trace(id + " Duration: " + (now - started) + " ms."); + } + + @Override + protected void drawCenterPoint(Graphics2D g2d, Color color, double size) { + //super.drawCenterPoint(g2d, color, size); + + //A block has 2 alternate points + //1st square + //2nd square holds the centerpoint + //3rd square + double dX1, dX2, dX3, dY1, dY2, dY3; + if (Orientation.EAST == this.tileOrientation || Orientation.WEST == tileOrientation) { + dX1 = (renderWidth / 3 / 2 - size / 2 / 2); + dX2 = (renderWidth / 2 - size / 2); + dX3 = (renderWidth / 3 / 2 + renderWidth / 3 * 2 - size / 2); + dY1 = (renderHeight / 2 - size / 2 / 2); + dY2 = (renderHeight / 2 - size / 2 / 2); + dY3 = (renderHeight / 2 - size / 2 / 2); + } else { + dY1 = (renderWidth / 2 - size / 2 / 2); + + dY2 = (renderWidth / 2 - size / 2 / 2); + + dY3 = (renderWidth / 2 - size / 2 / 2); + + dX1 = (renderHeight / 3 / 2 - size / 2 / 2); + + dX2 = (renderHeight / 2 - size / 2); + + dX3 = (renderHeight / 3 / 2 + renderHeight / 3 * 2 - size / 2); + + } + + g2d.setColor(color); + + g2d.fill(new Ellipse2D.Double(dX1, dY1, size / 2, size / 2)); + g2d.fill(new Ellipse2D.Double(dX2, dY2, size, size)); + g2d.fill(new Ellipse2D.Double(dX3, dY3, size / 2, size / 2)); + + Logger.trace(id + " dX2: " + dX2 + " dY2: " + dY2 + " O: " + tileOrientation + " rW: " + renderWidth + " rH:" + renderHeight); + Logger.trace(id + " dX1: " + dX1 + " dY1: " + dY1); + Logger.trace(id + " dX3: " + dX3 + " dY3: " + dY3); + + } + } diff --git a/src/main/java/jcs/ui/layout/tiles/Cross.java b/src/main/java/jcs/ui/layout/tiles/Cross.java index 691758e8..d5153674 100644 --- a/src/main/java/jcs/ui/layout/tiles/Cross.java +++ b/src/main/java/jcs/ui/layout/tiles/Cross.java @@ -27,14 +27,17 @@ import static jcs.entities.AccessoryBean.AccessoryValue.GREEN; import static jcs.entities.AccessoryBean.AccessoryValue.RED; import jcs.entities.TileBean; +import jcs.entities.TileBean.Direction; +import jcs.entities.TileBean.Orientation; import static jcs.entities.TileBean.Orientation.NORTH; import static jcs.entities.TileBean.Orientation.SOUTH; import static jcs.entities.TileBean.Orientation.WEST; +import jcs.entities.TileBean.TileType; import static jcs.ui.layout.tiles.Tile.DEFAULT_HEIGHT; import static jcs.ui.layout.tiles.Tile.DEFAULT_WIDTH; import static jcs.ui.layout.tiles.Tile.GRID; -public class Cross extends Switch implements Tile { +public class Cross extends Switch { public static final int CROSS_WIDTH = DEFAULT_WIDTH * 2; public static final int CROSS_HEIGHT = DEFAULT_HEIGHT * 2; @@ -47,18 +50,38 @@ public class Cross extends Switch implements Tile { public static final Color LIGHT_GREEN = new Color(0, 255, 51); public static final Color DARK_GREEN = new Color(0, 153, 0); - Cross(TileBean tileBean) { - super(tileBean); - setWidthHeightAndOffsets(); + private static int crossWidth(Orientation orientation) { + if (Orientation.EAST == orientation || Orientation.WEST == orientation) { + return DEFAULT_WIDTH * 2; + } else { + return DEFAULT_WIDTH; + } + } + + private static int crossHeight(Orientation orientation) { + if (Orientation.EAST == orientation || Orientation.WEST == orientation) { + return DEFAULT_HEIGHT; + } else { + return DEFAULT_HEIGHT * 2; + } } - Cross(Orientation orientation, Direction direction, int x, int y) { - this(orientation, direction, new Point(x, y)); + public Cross(TileBean tileBean) { + super(tileBean, crossWidth(tileBean.getOrientation()), crossHeight(tileBean.getOrientation())); + setWidthHeightAndOffsets(); } public Cross(Orientation orientation, Direction direction, Point center) { - super(orientation, direction, center); - this.type = TileType.CROSS.getTileType(); + this(orientation, direction, center.x, center.y); + } + + public Cross(Orientation orientation, Direction direction, int x, int y) { + this(orientation, direction, x, y, crossWidth(orientation), crossHeight(orientation)); + } + + public Cross(Orientation orientation, Direction direction, int x, int y, int width, int height) { + super(orientation, direction, x, y, width, height); + this.tileType = TileType.CROSS; setWidthHeightAndOffsets(); } @@ -69,8 +92,8 @@ public Cross(Orientation orientation, Direction direction, Point center) { */ @Override public Set getAltPoints() { - int xx = this.x; - int yy = this.y; + int xx = this.tileX; + int yy = this.tileY; Set alternatives = new HashSet<>(); switch (getOrientation()) { @@ -88,7 +111,7 @@ public Set getAltPoints() { } default -> { //East so default - Point ep = new Point((x + DEFAULT_WIDTH), yy); + Point ep = new Point((tileX + DEFAULT_WIDTH), yy); alternatives.add(ep); } } @@ -225,7 +248,7 @@ public void rotate() { setWidthHeightAndOffsets(); } - void setWidthHeightAndOffsets() { + final void setWidthHeightAndOffsets() { //Reset offsets this.offsetY = 0; this.renderOffsetY = 0; @@ -233,16 +256,16 @@ void setWidthHeightAndOffsets() { this.renderOffsetX = 0; if (isHorizontal()) { - this.width = DEFAULT_WIDTH * 2; - this.height = DEFAULT_HEIGHT; + //this.width = DEFAULT_WIDTH * 2; + //this.height = DEFAULT_HEIGHT; this.renderWidth = RENDER_GRID * 4; this.renderHeight = RENDER_GRID * 2; this.offsetY = 0; this.renderOffsetY = 0; } else { - this.width = DEFAULT_WIDTH; - this.height = DEFAULT_HEIGHT * 2; + //this.width = DEFAULT_WIDTH; + //this.height = DEFAULT_HEIGHT * 2; this.renderWidth = RENDER_GRID * 2; this.renderHeight = RENDER_GRID * 4; diff --git a/src/main/java/jcs/ui/layout/tiles/Crossing.java b/src/main/java/jcs/ui/layout/tiles/Crossing.java index 0c1751ad..cacf54e1 100644 --- a/src/main/java/jcs/ui/layout/tiles/Crossing.java +++ b/src/main/java/jcs/ui/layout/tiles/Crossing.java @@ -22,24 +22,26 @@ import java.util.HashMap; import java.util.Map; import jcs.entities.TileBean; +import jcs.entities.TileBean.Orientation; +import jcs.entities.TileBean.TileType; -public class Crossing extends Straight implements Tile { +public class Crossing extends Straight { - Crossing(TileBean tileBean) { + public Crossing(TileBean tileBean) { super(tileBean); - this.width = DEFAULT_WIDTH; - this.height = DEFAULT_HEIGHT; } - Crossing(Orientation orientation, Point center) { + public Crossing(Orientation orientation, Point center) { this(orientation, center.x, center.y); } - Crossing(Orientation orientation, int x, int y) { - super(orientation, x, y); - this.type = TileType.CROSSING.getTileType(); - this.width = DEFAULT_WIDTH; - this.height = DEFAULT_HEIGHT; + public Crossing(Orientation orientation, int x, int y) { + this(orientation, x, y, DEFAULT_WIDTH, DEFAULT_HEIGHT); + } + + public Crossing(Orientation orientation, int x, int y, int width, int height) { + super(orientation, x, y, width, height); + this.tileType = TileType.CROSSING; } @Override diff --git a/src/main/java/jcs/ui/layout/tiles/Curved.java b/src/main/java/jcs/ui/layout/tiles/Curved.java index b82d882b..450c8c06 100755 --- a/src/main/java/jcs/ui/layout/tiles/Curved.java +++ b/src/main/java/jcs/ui/layout/tiles/Curved.java @@ -16,6 +16,7 @@ package jcs.ui.layout.tiles; import java.awt.BasicStroke; +import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.Point; import java.util.HashMap; @@ -23,24 +24,31 @@ import java.util.Map; import java.util.Set; import jcs.entities.TileBean; +import jcs.entities.TileBean.Orientation; +import static jcs.entities.TileBean.Orientation.NORTH; +import static jcs.entities.TileBean.Orientation.SOUTH; +import static jcs.entities.TileBean.Orientation.WEST; +import jcs.entities.TileBean.TileType; +import org.tinylog.Logger; -public class Curved extends AbstractTile implements Tile { +public class Curved extends Tile { Curved(TileBean tileBean) { - super(tileBean); - this.width = DEFAULT_WIDTH; - this.height = DEFAULT_HEIGHT; + super(tileBean, DEFAULT_WIDTH, DEFAULT_HEIGHT); + setModel(new DefaultTileModel()); + } + + Curved(Orientation orientation, Point center) { + this(orientation, center.x, center.y); } Curved(Orientation orientation, int x, int y) { - this(orientation, new Point(x, y)); + this(orientation, x, y, DEFAULT_WIDTH, DEFAULT_HEIGHT); } - Curved(Orientation orientation, Point center) { - super(orientation, center); - this.width = DEFAULT_WIDTH; - this.height = DEFAULT_HEIGHT; - this.type = TileType.CURVED.getTileType(); + Curved(Orientation orientation, int x, int y, int width, int height) { + super(TileType.CURVED, orientation, x, y, width, height); + setModel(new DefaultTileModel()); } @Override @@ -136,4 +144,21 @@ public void renderTileRoute(Graphics2D g2) { g2.fillPolygon(xPoints, yPoints, xPoints.length); } + @Override + protected void paintComponent(Graphics g) { + long started = System.currentTimeMillis(); + super.paintComponent(g); + + setBounds(this.tileX - GRID, this.tileY - GRID, this.getWidth(), this.getHeight()); + + Graphics2D g2 = (Graphics2D) g.create(); + drawTile(g2); + g2.dispose(); + + g.drawImage(this.tileImage, 0, 0, null); + + long now = System.currentTimeMillis(); + Logger.trace(this.id + " Duration: " + (now - started) + " ms."); + } + } diff --git a/src/main/java/jcs/ui/layout/tiles/DefaultTileModel.java b/src/main/java/jcs/ui/layout/tiles/DefaultTileModel.java new file mode 100644 index 00000000..3a60e1a4 --- /dev/null +++ b/src/main/java/jcs/ui/layout/tiles/DefaultTileModel.java @@ -0,0 +1,289 @@ +/* + * Copyright 2025 Frans Jacobs. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package jcs.ui.layout.tiles; + +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.ItemListener; +import javax.swing.event.ChangeEvent; +import javax.swing.event.ChangeListener; +import javax.swing.event.EventListenerList; +import jcs.entities.BlockBean.BlockState; + +/** + * + * @author fransjacobs + */ +@SuppressWarnings("serial") // Same-version serialization only +public class DefaultTileModel implements TileModel { + + protected transient ChangeEvent changeEvent = null; + + /** + * Stores the listeners on this model. + */ + protected EventListenerList listenerList = new EventListenerList(); + + protected boolean selected = false; + protected boolean scaleImage = true; + protected boolean showCenter = false; + protected boolean showRoute = false; + protected boolean showBlockState = false; + protected boolean showLocomotiveImage = false; + protected boolean showAccessoryValue = false; + protected boolean showSignalValue = false; + protected boolean sensorActive = false; + protected boolean showOutline = false; + + protected BlockState blockState; + + public DefaultTileModel() { + + } + + @Override + public boolean isSelected() { + return selected; + } + + @Override + public void setSelected(boolean selected) { + this.selected = selected; + fireStateChanged(); + } + + @Override + public boolean isScaleImage() { + return scaleImage; + } + + @Override + public void setScaleImage(boolean scaleImage) { + this.scaleImage = scaleImage; + fireStateChanged(); + } + + @Override + public boolean isShowCenter() { + return showCenter; + } + + @Override + public void setShowCenter(boolean showCenter) { + this.showCenter = showCenter; + fireStateChanged(); + } + + @Override + public boolean isShowRoute() { + return showRoute; + } + + @Override + public void setShowRoute(boolean showRoute) { + this.showRoute = showRoute; + fireStateChanged(); + } + + @Override + public boolean isShowBlockState() { + return showBlockState; + } + + @Override + public void setShowBlockState(boolean showBlockState) { + this.showBlockState = showBlockState; + fireStateChanged(); + } + + @Override + public boolean isShowLocomotiveImage() { + return showLocomotiveImage; + } + + @Override + public void setShowLocomotiveImage(boolean showLocomotiveImage) { + this.showLocomotiveImage = showLocomotiveImage; + fireStateChanged(); + } + + @Override + public boolean isShowAccessoryValue() { + return showAccessoryValue; + } + + @Override + public void setShowAccessoryValue(boolean showAccessoryValue) { + this.showAccessoryValue = showAccessoryValue; + fireStateChanged(); + } + + @Override + public boolean isShowSignalValue() { + return showSignalValue; + } + + @Override + public void setShowSignalValue(boolean showSignalValue) { + this.showSignalValue = showSignalValue; + fireStateChanged(); + } + + @Override + public boolean isSensorActive() { + return sensorActive; + } + + @Override + public void setSensorActive(boolean sensorActive) { + this.sensorActive = sensorActive; + fireStateChanged(); + } + + @Override + public BlockState getBlockState() { + if (blockState == null) { + blockState = BlockState.FREE; + } + return blockState; + } + + @Override + public void setBlockState(BlockState blockState) { + this.blockState = blockState; + fireStateChanged(); + } + + @Override + public void addChangeListener(ChangeListener l) { + listenerList.add(ChangeListener.class, l); + } + + /** + * {@inheritDoc} + */ + @Override + public void removeChangeListener(ChangeListener l) { + listenerList.remove(ChangeListener.class, l); + } + + /** + * Returns an array of all the change listeners registered on this DefaultButtonModel. + * + * @return all of this model's ChangeListeners or an empty array if no change listeners are currently registered + * + * @see #addChangeListener + * @see #removeChangeListener + * + * @since 1.4 + */ + public ChangeListener[] getChangeListeners() { + return listenerList.getListeners(ChangeListener.class); + } + + /** + * Notifies all listeners that have registered interest for notification on this event type. The event instance is created lazily. + * + * @see EventListenerList + */ + protected void fireStateChanged() { + // Guaranteed to return a non-null array + Object[] listeners = listenerList.getListenerList(); + // Process the listeners last to first, notifying + // those that are interested in this event + for (int i = listeners.length - 2; i >= 0; i -= 2) { + if (listeners[i] == ChangeListener.class) { + // Lazily create the event: + if (changeEvent == null) { + changeEvent = new ChangeEvent(this); + } + ((ChangeListener) listeners[i + 1]).stateChanged(changeEvent); + } + } + } + + /** + * {@inheritDoc} + */ +// @Override +// public void addItemListener(ItemListener l) { +// listenerList.add(ItemListener.class, l); +// } + /** + * {@inheritDoc} + */ +// @Override +// public void removeItemListener(ItemListener l) { +// listenerList.remove(ItemListener.class, l); +// } + /** + * Returns an array of all the item listeners registered on this DefaultButtonModel. + * + * @return all of this model's ItemListeners or an empty array if no item listeners are currently registered + * + * @see #addItemListener + * @see #removeItemListener + * + * @since 1.4 + */ + public ItemListener[] getItemListeners() { + return listenerList.getListeners(ItemListener.class); + } + + @Override + public void addActionListener(ActionListener l) { + listenerList.add(ActionListener.class, l); + } + + @Override + public void removeActionListener(ActionListener l) { + listenerList.remove(ActionListener.class, l); + } + + @Override + public ActionListener[] getActionListeners() { + return listenerList.getListeners(ActionListener.class); + } + + /** + * Notifies all listeners that have registered interest for notification on this event type. + * + * @param e the ActionEvent to deliver to listeners + * @see EventListenerList + */ + protected void fireActionPerformed(ActionEvent e) { + // Guaranteed to return a non-null array + Object[] listeners = listenerList.getListenerList(); + // Process the listeners last to first, notifying + // those that are interested in this event + for (int i = listeners.length - 2; i >= 0; i -= 2) { + if (listeners[i] == ActionListener.class) { + // Lazily create the event: + // if (changeEvent == null) + // changeEvent = new ChangeEvent(this); + ((ActionListener) listeners[i + 1]).actionPerformed(e); + } + } + } + + /** + * Overridden to return null. + */ +// @Override +// public Object[] getSelectedObjects() { +// return null; +// } +} diff --git a/src/main/java/jcs/ui/layout/tiles/End.java b/src/main/java/jcs/ui/layout/tiles/End.java index 8e535bbc..91026af3 100644 --- a/src/main/java/jcs/ui/layout/tiles/End.java +++ b/src/main/java/jcs/ui/layout/tiles/End.java @@ -17,6 +17,7 @@ import java.awt.BasicStroke; import java.awt.Color; +import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.Point; import java.util.HashMap; @@ -24,25 +25,32 @@ import java.util.Map; import java.util.Set; import jcs.entities.TileBean; - -public class End extends AbstractTile implements Tile { - - End(TileBean tileBean) { - super(tileBean); - this.width = DEFAULT_WIDTH; - this.height = DEFAULT_HEIGHT; +import jcs.entities.TileBean.Orientation; +import static jcs.entities.TileBean.Orientation.NORTH; +import static jcs.entities.TileBean.Orientation.SOUTH; +import static jcs.entities.TileBean.Orientation.WEST; +import jcs.entities.TileBean.TileType; +import org.tinylog.Logger; + +public class End extends Tile { + + public End(TileBean tileBean) { + super(tileBean, DEFAULT_WIDTH, DEFAULT_HEIGHT); + setModel(new DefaultTileModel()); } - End(Orientation orientation, Point center) { + public End(Orientation orientation, Point center) { this(orientation, center.x, center.y); + } + public End(Orientation orientation, int x, int y) { + this(orientation, x, y, DEFAULT_WIDTH, DEFAULT_HEIGHT); } - End(Orientation orientation, int x, int y) { - super(orientation, x, y); - this.type = TileType.END.getTileType(); - this.width = DEFAULT_WIDTH; - this.height = DEFAULT_HEIGHT; + public End(Orientation orientation, int x, int y, int width, int height) { + super(TileType.END, orientation, x, y, width, height); + + setModel(new DefaultTileModel()); } @Override @@ -123,4 +131,21 @@ public void renderTile(Graphics2D g2) { public void renderTileRoute(Graphics2D g2d) { } + @Override + protected void paintComponent(Graphics g) { + long started = System.currentTimeMillis(); + super.paintComponent(g); + + setBounds(this.tileX - GRID, this.tileY - GRID, this.getWidth(), this.getHeight()); + + Graphics2D g2 = (Graphics2D) g.create(); + drawTile(g2); + g2.dispose(); + + g.drawImage(this.tileImage, 0, 0, null); + + long now = System.currentTimeMillis(); + Logger.trace(this.id + " Duration: " + (now - started) + " ms."); + } + } diff --git a/src/main/java/jcs/ui/layout/tiles/Sensor.java b/src/main/java/jcs/ui/layout/tiles/Sensor.java index dacc13a4..cb5e9cd0 100644 --- a/src/main/java/jcs/ui/layout/tiles/Sensor.java +++ b/src/main/java/jcs/ui/layout/tiles/Sensor.java @@ -25,30 +25,26 @@ import jcs.commandStation.events.SensorEventListener; import jcs.entities.SensorBean; import jcs.entities.TileBean; +import jcs.entities.TileBean.Orientation; +import jcs.entities.TileBean.TileType; public class Sensor extends Straight implements SensorEventListener { - private boolean active; - - Sensor(TileBean tileBean) { + public Sensor(TileBean tileBean) { super(tileBean); } - Sensor(Orientation orientation, int x, int y) { - this(orientation, new Point(x, y)); - } - - Sensor(Orientation orientation, Point center) { - super(orientation, center); - this.type = TileType.SENSOR.getTileType(); + public Sensor(Orientation orientation, Point center) { + this(orientation, center.x, center.y); } - public boolean isActive() { - return this.active; + public Sensor(Orientation orientation, int x, int y) { + this(orientation, x, y, DEFAULT_WIDTH, DEFAULT_HEIGHT); } - public void setActive(boolean active) { - this.active = active; + public Sensor(Orientation orientation, int x, int y, int width, int height) { + super(orientation, x, y, width, height); + this.tileType = TileType.SENSOR; } private void renderSensor(Graphics2D g2) { @@ -60,7 +56,7 @@ private void renderSensor(Graphics2D g2) { float radius = 300; float[] dist = {0.0f, 0.6f}; - if (this.active) { + if (model.isSensorActive()) { Color[] colors = {Color.red.brighter(), Color.red.darker()}; RadialGradientPaint foreground = new RadialGradientPaint(c, radius, dist, colors, CycleMethod.REFLECT); g2.setPaint(foreground); @@ -74,31 +70,24 @@ private void renderSensor(Graphics2D g2) { } @Override - public void renderTile(Graphics2D g2) { - Graphics2D g2d = (Graphics2D) g2.create(); - + public void renderTile(Graphics2D g2d) { renderStraight(g2d); - - if (drawRoute) { - renderTileRoute(g2); - } - renderSensor(g2d); - - g2d.dispose(); } @Override public void onSensorChange(SensorEvent event) { SensorBean sensor = event.getSensorBean(); if (sensor.equalsDeviceIdAndContactId(getSensorBean())) { - this.setActive(sensor.isActive()); - repaintTile(); + setActive(sensor.isActive()); + repaint(); } } + //Sensor must also listen to the mouse now it is a component.... + //in UI Delegate TODO! @Override public String toString() { - return this.getClass().getSimpleName() + " {id: " + id + ", orientation: " + getOrientation() + ", direction: " + getDirection() + ", active: " + active + ", center: (" + x + "," + y + ")}"; + return getClass().getSimpleName() + " {id: " + id + ", orientation: " + getOrientation() + ", direction: " + getDirection() + ", active: " + model.isSensorActive() + ", center: (" + tileX + "," + tileY + ")}"; } } diff --git a/src/main/java/jcs/ui/layout/tiles/Signal.java b/src/main/java/jcs/ui/layout/tiles/Signal.java index e9c0412f..1b7a5b49 100644 --- a/src/main/java/jcs/ui/layout/tiles/Signal.java +++ b/src/main/java/jcs/ui/layout/tiles/Signal.java @@ -22,7 +22,6 @@ import java.awt.Polygon; import jcs.commandStation.events.AccessoryEvent; import jcs.commandStation.events.AccessoryEventListener; -import jcs.entities.AccessoryBean; import jcs.entities.AccessoryBean.SignalType; import static jcs.entities.AccessoryBean.SignalType.HP012; import static jcs.entities.AccessoryBean.SignalType.HP012SH1; @@ -33,19 +32,14 @@ import static jcs.entities.AccessoryBean.SignalValue.Hp1; import static jcs.entities.AccessoryBean.SignalValue.Hp2; import jcs.entities.TileBean; +import jcs.entities.TileBean.Orientation; +import jcs.entities.TileBean.TileType; import static jcs.ui.layout.tiles.Tile.RENDER_GRID; -public class Signal extends Straight implements Tile, AccessoryEventListener { - - private SignalValue signalValue; - private SignalType signalType; +public class Signal extends Straight implements AccessoryEventListener { Signal(TileBean tileBean) { super(tileBean); - if (tileBean.getAccessoryBean() != null) { - AccessoryBean ab = tileBean.getAccessoryBean(); - this.signalType = SignalType.getSignalType(ab.getType()); - } } Signal(Orientation orientation, int x, int y, SignalType signalType) { @@ -58,36 +52,9 @@ public class Signal extends Straight implements Tile, AccessoryEventListener { Signal(Orientation orientation, Point center, SignalType signalType) { super(orientation, center); + this.tileType = TileType.SIGNAL; this.signalType = signalType; this.signalValue = SignalValue.OFF; - this.type = TileType.SIGNAL.getTileType(); - } - - public SignalValue getSignalValue() { - return signalValue; - } - - @Override - public SignalType getSignalType() { - return signalType; - } - - public void setSignalValue(SignalValue signalValue) { - this.signalValue = signalValue; - } - - @Override - public void setAccessoryBean(AccessoryBean accessoryBean) { - this.accessoryBean = accessoryBean; - if (accessoryBean != null) { - this.accessoryId = accessoryBean.getId(); - this.signalValue = accessoryBean.getSignalValue(); - this.signalType = SignalType.getSignalType(accessoryBean.getType()); - } else { - this.accessoryId = null; - this.signalType = SignalType.NONE; - this.signalValue = SignalValue.OFF; - } } /** @@ -364,18 +331,14 @@ public void renderTile(Graphics2D g2) { renderSignal2(g2d); } - if (drawRoute) { - renderTileRoute(g2); - } - g2d.dispose(); } + //TODO move to UI delegate @Override public void onAccessoryChange(AccessoryEvent event) { - if (this.getAccessoryBean() != null && event.isEventFor(accessoryBean)) { - this.setSignalValue(event.getAccessoryBean().getSignalValue()); - repaintTile(); + if (getAccessoryBean() != null && event.isEventFor(accessoryBean)) { + setSignalValue(event.getAccessoryBean().getSignalValue()); } } } diff --git a/src/main/java/jcs/ui/layout/tiles/Straight.java b/src/main/java/jcs/ui/layout/tiles/Straight.java index db1646a0..6f8b3de6 100755 --- a/src/main/java/jcs/ui/layout/tiles/Straight.java +++ b/src/main/java/jcs/ui/layout/tiles/Straight.java @@ -16,6 +16,7 @@ package jcs.ui.layout.tiles; import java.awt.BasicStroke; +import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.Point; import java.util.HashMap; @@ -23,24 +24,28 @@ import java.util.Map; import java.util.Set; import jcs.entities.TileBean; +import jcs.entities.TileBean.Orientation; +import jcs.entities.TileBean.TileType; +import org.tinylog.Logger; -public class Straight extends AbstractTile implements Tile { +public class Straight extends Tile { - Straight(TileBean tileBean) { - super(tileBean); - this.width = DEFAULT_WIDTH; - this.height = DEFAULT_HEIGHT; + public Straight(TileBean tileBean) { + super(tileBean, DEFAULT_WIDTH, DEFAULT_HEIGHT); + setModel(new DefaultTileModel()); } - Straight(Orientation orientation, Point center) { + public Straight(Orientation orientation, Point center) { this(orientation, center.x, center.y); } - Straight(Orientation orientation, int x, int y) { - super(orientation, x, y); - this.type = TileType.STRAIGHT.getTileType(); - this.width = DEFAULT_WIDTH; - this.height = DEFAULT_HEIGHT; + public Straight(Orientation orientation, int x, int y) { + this(orientation, x, y, DEFAULT_WIDTH, DEFAULT_HEIGHT); + } + + public Straight(Orientation orientation, int x, int y, int width, int height) { + super(TileType.STRAIGHT, orientation, x, y, width, height); + setModel(new DefaultTileModel()); } @Override @@ -124,4 +129,21 @@ public void renderTile(Graphics2D g2) { renderStraight(g2); } + @Override + protected void paintComponent(Graphics g) { + long started = System.currentTimeMillis(); + super.paintComponent(g); + + setBounds(this.tileX - GRID, this.tileY - GRID, this.getWidth(), this.getHeight()); + + Graphics2D g2 = (Graphics2D) g.create(); + drawTile(g2); + g2.dispose(); + + g.drawImage(this.tileImage, 0, 0, null); + + long now = System.currentTimeMillis(); + Logger.trace(this.id + " Duration: " + (now - started) + " ms."); + } + } diff --git a/src/main/java/jcs/ui/layout/tiles/StraightDirection.java b/src/main/java/jcs/ui/layout/tiles/StraightDirection.java index fc5cb964..df3fbd01 100644 --- a/src/main/java/jcs/ui/layout/tiles/StraightDirection.java +++ b/src/main/java/jcs/ui/layout/tiles/StraightDirection.java @@ -21,20 +21,23 @@ import java.awt.Point; import java.util.Collection; import jcs.entities.TileBean; +import jcs.entities.TileBean.Orientation; +import jcs.entities.TileBean.TileType; public class StraightDirection extends Straight { - StraightDirection(TileBean tileBean) { + public StraightDirection(TileBean tileBean) { super(tileBean); + this.tileType = TileType.STRAIGHT_DIR; } - StraightDirection(Orientation orientation, int x, int y) { + public StraightDirection(Orientation orientation, int x, int y) { this(orientation, new Point(x, y)); } - StraightDirection(Orientation orientation, Point center) { + public StraightDirection(Orientation orientation, Point center) { super(orientation, center); - this.type = TileType.STRAIGHT_DIR.getTileType(); + this.tileType = TileType.STRAIGHT_DIR; } @Override @@ -71,18 +74,9 @@ private void renderDirectionArrow(Graphics2D g2) { } @Override - public void renderTile(Graphics2D g2) { - Graphics2D g2d = (Graphics2D) g2.create(); - + public void renderTile(Graphics2D g2d) { renderStraight(g2d); - renderDirectionArrow(g2d); - - if (drawRoute) { - renderTileRoute(g2); - } - - g2d.dispose(); } } diff --git a/src/main/java/jcs/ui/layout/tiles/Switch.java b/src/main/java/jcs/ui/layout/tiles/Switch.java index 3385847f..2a099a59 100644 --- a/src/main/java/jcs/ui/layout/tiles/Switch.java +++ b/src/main/java/jcs/ui/layout/tiles/Switch.java @@ -17,6 +17,7 @@ import java.awt.BasicStroke; import java.awt.Color; +import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.Point; import java.util.HashMap; @@ -29,30 +30,39 @@ import static jcs.entities.AccessoryBean.AccessoryValue.GREEN; import static jcs.entities.AccessoryBean.AccessoryValue.RED; import jcs.entities.TileBean; +import jcs.entities.TileBean.Direction; import static jcs.entities.TileBean.Direction.LEFT; import static jcs.entities.TileBean.Direction.RIGHT; +import jcs.entities.TileBean.Orientation; +import static jcs.entities.TileBean.Orientation.NORTH; +import static jcs.entities.TileBean.Orientation.SOUTH; +import static jcs.entities.TileBean.Orientation.WEST; +import jcs.entities.TileBean.TileType; +import org.tinylog.Logger; -public class Switch extends AbstractTile implements Tile, AccessoryEventListener { +public class Switch extends Tile implements AccessoryEventListener { - protected AccessoryValue accessoryValue; - protected AccessoryValue routeValue; - protected Color routeColor; + public Switch(TileBean tileBean) { + this(tileBean, DEFAULT_WIDTH, DEFAULT_HEIGHT); + } + + protected Switch(TileBean tileBean, int width, int height) { + super(tileBean, width, height); + setModel(new DefaultTileModel()); + } - Switch(TileBean tileBean) { - super(tileBean); - this.width = DEFAULT_WIDTH; - this.height = DEFAULT_HEIGHT; + public Switch(Orientation orientation, Direction direction, Point center) { + this(orientation, direction, center.x, center.y); } - Switch(Orientation orientation, Direction direction, int x, int y) { - this(orientation, direction, new Point(x, y)); + public Switch(Orientation orientation, Direction direction, int x, int y) { + this(orientation, direction, x, y, DEFAULT_WIDTH, DEFAULT_HEIGHT); } - Switch(Orientation orientation, Direction direction, Point center) { - super(orientation, direction, center.x, center.y); - this.width = DEFAULT_WIDTH; - this.height = DEFAULT_HEIGHT; - this.type = TileType.SWITCH.getTileType(); + public Switch(Orientation orientation, Direction direction, int x, int y, int width, int height) { + super(TileType.SWITCH, orientation, direction, x, y, width, height); + + setModel(new DefaultTileModel()); } @Override @@ -162,30 +172,6 @@ public Set getAllPoints() { return aps; } - public AccessoryValue getAccessoryValue() { - if (this.accessoryValue == null) { - return AccessoryValue.OFF; - } else { - return accessoryValue; - } - } - - public void setValue(AccessoryValue value) { - this.accessoryValue = value; - } - - public AccessoryValue getRouteValue() { - if (routeValue == null) { - return AccessoryValue.OFF; - } else { - return routeValue; - } - } - - public void setRouteValue(AccessoryValue value) { - this.routeValue = value; - } - protected void renderStraight(Graphics2D g2, Color color) { int xx, yy, w, h; xx = 0; @@ -284,9 +270,8 @@ public void renderTileRoute(Graphics2D g2) { @Override public void onAccessoryChange(AccessoryEvent event) { - if (this.getAccessoryBean() != null && event.isEventFor(accessoryBean)) { - setValue(event.getAccessoryBean().getAccessoryValue()); - repaintTile(); + if (getAccessoryBean() != null && event.isEventFor(accessoryBean)) { + setAccessoryValue(event.getAccessoryBean().getAccessoryValue()); } } @@ -355,4 +340,21 @@ public AccessoryValue accessoryValueForRoute(Orientation from, Orientation to) { return AccessoryValue.OFF; } } + + @Override + protected void paintComponent(Graphics g) { + long started = System.currentTimeMillis(); + super.paintComponent(g); + + setBounds(this.tileX - GRID, this.tileY - GRID, this.getWidth(), this.getHeight()); + + Graphics2D g2 = (Graphics2D) g.create(); + drawTile(g2); + g2.dispose(); + + g.drawImage(this.tileImage, 0, 0, null); + + long now = System.currentTimeMillis(); + Logger.trace(this.id + " Duration: " + (now - started) + " ms."); + } } diff --git a/src/main/java/jcs/ui/layout/tiles/Tile.java b/src/main/java/jcs/ui/layout/tiles/Tile.java old mode 100644 new mode 100755 index 3de8030e..5274714b --- a/src/main/java/jcs/ui/layout/tiles/Tile.java +++ b/src/main/java/jcs/ui/layout/tiles/Tile.java @@ -1,5 +1,5 @@ /* - * Copyright 2023 Frans Jacobs. + * Copyright 2024 Frans Jacobs. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -16,23 +16,66 @@ package jcs.ui.layout.tiles; import java.awt.Color; +import java.awt.Dimension; import java.awt.Graphics2D; import java.awt.Point; -import java.awt.Shape; +import java.awt.Rectangle; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.geom.AffineTransform; +import java.awt.geom.Ellipse2D; +import java.awt.geom.PathIterator; +import java.awt.geom.Point2D; +import java.awt.geom.Rectangle2D; +import java.awt.image.AffineTransformOp; import java.awt.image.BufferedImage; import java.beans.PropertyChangeListener; +import java.io.Serializable; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; import java.util.Map; import java.util.Set; +import javax.swing.JComponent; +import javax.swing.event.ChangeEvent; +import javax.swing.event.ChangeListener; +import jcs.entities.AccessoryBean; import jcs.entities.AccessoryBean.AccessoryValue; +import jcs.entities.AccessoryBean.SignalType; +import jcs.entities.BlockBean; +import jcs.entities.BlockBean.BlockState; +import jcs.entities.SensorBean; import jcs.entities.TileBean; import jcs.entities.TileBean.Direction; import jcs.entities.TileBean.Orientation; import jcs.entities.TileBean.TileType; +import jcs.ui.layout.LayoutUtil; +import jcs.ui.layout.events.TileEvent; +import jcs.ui.layout.events.TileEventListener; +import org.imgscalr.Scalr; +import org.imgscalr.Scalr.Method; +import org.imgscalr.Scalr.Mode; +import org.tinylog.Logger; /** - * @author frans + * Basic graphic element to display a track, turnout, etc on the screen.
+ * By default the drawing of a Tile is Horizontal from L to R or West to East.
+ * The default orientation is East. + * + *

+ * The default size of a Tile is 40 tileX 40 pixels.
+ * The center point of a Tile is stored and always snapped to the nearest grid point.
+ * The basic grid is 20x 20 pixels.
+ * + *

+ * A Tile can be rotated (always clockwise).
+ * Rotation will change the orientation from East -> South -> West -> North -> East.
+ * + *

+ * A Tile is rendered to a Buffered Image to speed up the display */ -public interface Tile extends Shape { +public abstract class Tile extends JComponent implements TileEventListener { //, ItemSelectable { public static final int GRID = 20; public static final int DEFAULT_WIDTH = GRID * 2; @@ -45,177 +88,1158 @@ public interface Tile extends Shape { public static final Color DEFAULT_BACKGROUND_COLOR = Color.white; public static final Color DEFAULT_TRACK_COLOR = Color.lightGray; public static final Color DEFAULT_ROUTE_TRACK_COLOR = Color.blue; + public static final Color DEFAULT_SELECTED_COLOR = Color.yellow; - boolean isDrawRoute(); - - void setDrawRoute(boolean drawRoute); + public static final String MODEL_CHANGED_PROPERTY = "model"; + public static final String CONTENT_AREA_FILLED_CHANGED_PROPERTY = "contentAreaFilled"; - Color getTrackColor(); - - void setTrackColor(Color trackColor); + /** + * The data model that determines the button's state. + */ + protected TileModel model = null; - Color getTrackRouteColor(); + protected String id; + protected Integer tileX; + protected Integer tileY; - void setTrackRouteColor(Color trackRouteColor); + protected int renderWidth; + protected int renderHeight; - Orientation getIncomingSide(); + protected Orientation tileOrientation; + protected Direction tileDirection; - void setIncomingSide(Orientation incomingSide); + protected TileType tileType; + protected String accessoryId; + protected String sensorId; - Color getBackgroundColor(); + protected AccessoryValue accessoryValue; + protected AccessoryValue routeValue; - void setBackgroundColor(Color backgroundColor); + protected SignalType signalType; + protected AccessoryBean.SignalValue signalValue; - String getId(); + protected AccessoryBean accessoryBean; + protected SensorBean sensorBean; + protected BlockBean blockBean; - void setId(String id); + protected List neighbours; - //String getImageKey(); - - BufferedImage getTileImage(); + protected int offsetX = 0; + protected int offsetY = 0; - void drawTile(Graphics2D g2d, boolean drawOutline); + protected int renderOffsetX = 0; + protected int renderOffsetY = 0; - void renderTile(Graphics2D g2d); + protected Color selectedColor; + protected Color trackColor; + protected Color trackRouteColor; + protected Orientation incomingSide; - void renderTileRoute(Graphics2D g2d); + protected Color backgroundColor; + protected boolean drawName = true; - void drawName(Graphics2D g2); + protected BufferedImage tileImage; - void drawCenterPoint(Graphics2D g2d); + protected PropertyChangeListener propertyChangeListener; - void drawCenterPoint(Graphics2D g2, Color color); + protected ChangeListener changeListener = null; + protected ActionListener actionListener = null; + //protected ItemListener itemListener = null; - void drawCenterPoint(Graphics2D g2d, Color color, double size); + protected transient ChangeEvent changeEvent; - void drawBounds(Graphics2D g2d); + private Handler handler; - void rotate(); + protected Tile(TileType tileType, Point center) { + this(tileType, Orientation.EAST, Direction.CENTER, center.x, center.y, DEFAULT_WIDTH, DEFAULT_HEIGHT); + } + + protected Tile(TileType tileType, Orientation orientation, Point center, int width, int height) { + this(tileType, orientation, Direction.CENTER, center.x, center.y, width, height); + } + + protected Tile(TileType tileType, Orientation orientation, int x, int y, int width, int height) { + this(tileType, orientation, Direction.CENTER, x, y, width, height); + } + + protected Tile(TileType tileType, Orientation orientation, Direction direction, int x, int y, int width, int height) { + this(tileType, orientation, direction, x, y, width, height, null, null); + } + + protected Tile(TileType tileType, Orientation orientation, Direction direction, int x, int y, int width, int height, Color backgroundColor, Color selectedColor) { + this.setLayout(null); + this.tileType = tileType; + + this.tileOrientation = orientation; + this.tileDirection = direction; + + this.tileX = x; + this.tileY = y; + + Dimension d = new Dimension(width, height); + this.setSize(d); + this.setPreferredSize(d); + + this.renderWidth = RENDER_WIDTH; + this.renderHeight = RENDER_HEIGHT; + + this.trackColor = DEFAULT_TRACK_COLOR; + this.backgroundColor = backgroundColor; + this.selectedColor = selectedColor; + + if (this.backgroundColor == null) { + this.backgroundColor = DEFAULT_BACKGROUND_COLOR; + } + if (this.selectedColor == null) { + this.selectedColor = DEFAULT_SELECTED_COLOR; + } + } + + protected Tile(Object tileBean) { + this(tileBean, DEFAULT_WIDTH, DEFAULT_HEIGHT); + } + + protected Tile(Object tileBean, int width, int height) { + copyInto(tileBean); + setLayout(null); + Dimension d = new Dimension(width, height); + this.setSize(d); + this.setPreferredSize(d); + + this.trackColor = DEFAULT_TRACK_COLOR; + this.backgroundColor = DEFAULT_BACKGROUND_COLOR; + this.selectedColor = DEFAULT_SELECTED_COLOR; + this.renderWidth = RENDER_WIDTH; + this.renderHeight = RENDER_HEIGHT; + } + + private void copyInto(Object object) { + if (object instanceof TileBean other) { + this.id = other.getId(); + this.tileType = other.getTileType(); + this.tileOrientation = other.getOrientation(); + this.tileOrientation = other.getOrientation(); + this.tileDirection = other.getDirection(); + this.tileDirection = other.getDirection(); + this.tileX = other.getX(); + this.tileY = other.getY(); + + this.signalType = other.getSignalType(); + this.accessoryId = other.getAccessoryId(); + this.sensorId = other.getSensorId(); + this.accessoryBean = other.getAccessoryBean(); + this.sensorBean = other.getSensorBean(); + this.blockBean = other.getBlockBean(); + + if (other.getAccessoryBean() != null) { + AccessoryBean ab = other.getAccessoryBean(); + this.signalType = SignalType.getSignalType(ab.getType()); + } + + } + + if (object instanceof Tile tile) { + this.renderWidth = tile.renderWidth; + this.renderHeight = tile.renderHeight; + } + + } + + public TileBean getTileBean() { + TileBean tb = new TileBean(); + tb.setId(this.id); + tb.setX(this.tileX); + tb.setY(this.tileY); + tb.setTileType(this.tileType); + tb.setTileOrientation(this.tileOrientation.getOrientation()); + tb.setTileDirection(this.tileDirection.getDirection()); + tb.setSignalType(this.signalType); + tb.setAccessoryId(this.accessoryId); + tb.setSensorId(this.sensorId); + tb.setAccessoryBean(this.accessoryBean); + tb.setSensorBean(this.sensorBean); + tb.setBlockBean(this.blockBean); + + return tb; + } + + public boolean isSelected() { + return model.isSelected(); + } + + public void setSelected(boolean b) { + //boolean oldValue = isSelected(); + model.setSelected(b); + } + + @Override + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public SignalType getSignalType() { + return this.signalType; + } + + public void setSignalType(SignalType signalType) { + this.signalType = signalType; + } + + public Integer getTileX() { + return tileX; + } + + public void setTileX(Integer x) { + this.tileX = x; + } + + public Integer getTileY() { + return tileY; + } + + public void setTileY(Integer y) { + this.tileY = y; + } + + public Point getCenter() { + return new Point(this.tileX, this.tileY); + } + + public void setCenter(Point center) { + this.tileX = center.x; + this.tileY = center.y; + } + + public Orientation getOrientation() { + return tileOrientation; + } + + public void setOrientation(Orientation orientation) { + this.tileOrientation = orientation; + } + + public Direction getDirection() { + return tileDirection; + } + + public void setDirection(Direction direction) { + this.tileDirection = direction; + } + + public String getAccessoryId() { + return accessoryId; + } + + public void setAccessoryId(String accessoryId) { + this.accessoryId = accessoryId; + } + + public String getSensorId() { + return sensorId; + } + + public void setSensorId(String sensorId) { + this.sensorId = sensorId; + } + + public boolean isActive() { + return model.isSensorActive(); + } + + public void setActive(boolean active) { + this.model.setSensorActive(active); + } + + public BlockState getBlockState() { + return this.model.getBlockState(); + } + + public void setBlockState(BlockState blockState) { + this.model.setBlockState(blockState); + } + + public AccessoryBean getAccessoryBean() { + return accessoryBean; + } + + public void setAccessoryBean(AccessoryBean accessoryBean) { + this.accessoryBean = accessoryBean; + + if (accessoryBean != null) { + this.accessoryId = accessoryBean.getId(); + this.signalValue = accessoryBean.getSignalValue(); + this.signalType = SignalType.getSignalType(accessoryBean.getType()); + } else { + this.accessoryId = null; + this.signalType = SignalType.NONE; + this.signalValue = AccessoryBean.SignalValue.OFF; + } + } + + public AccessoryValue getAccessoryValue() { + if (this.accessoryValue == null) { + return AccessoryValue.OFF; + } else { + return accessoryValue; + } + } + + public void setAccessoryValue(AccessoryValue value) { + this.accessoryValue = value; + repaint(); + } + + public AccessoryValue getRouteValue() { + if (routeValue == null) { + return AccessoryValue.OFF; + } else { + return routeValue; + } + } + + public void setRouteValue(AccessoryValue value) { + this.routeValue = value; + repaint(); + } + + public AccessoryBean.SignalValue getSignalValue() { + return signalValue; + } + + public void setSignalValue(AccessoryBean.SignalValue signalValue) { + this.signalValue = signalValue; + this.repaint(); + } + + public SensorBean getSensorBean() { + return sensorBean; + } + + public void setSensorBean(SensorBean sensorBean) { + this.sensorBean = sensorBean; + } + + public BlockBean getBlockBean() { + return blockBean; + } + + public void setBlockBean(BlockBean blockBean) { + this.blockBean = blockBean; + } + + public void setRenderWidth(int renderWidth) { + this.renderWidth = renderWidth; + } + + public void setRenderHeight(int renderHeight) { + this.renderHeight = renderHeight; + } + + public int getRenderOffsetX() { + return renderOffsetX; + } + + public void setRenderOffsetX(int renderOffsetX) { + this.renderOffsetX = renderOffsetX; + } + + public int getRenderOffsetY() { + return renderOffsetY; + } + + public void setRenderOffsetY(int renderOffsetY) { + this.renderOffsetY = renderOffsetY; + } + + public TileBean.TileType getTileType() { + return this.tileType; + } + + public final void setTileType(TileType tileType) { + this.tileType = tileType; + } + + public Color getTrackColor() { + return trackColor; + } + + public final void setTrackColor(Color trackColor) { + this.trackColor = trackColor; + } + + public Color getTrackRouteColor() { + return trackRouteColor; + } + + public void setTrackRouteColor(Color trackRouteColor) { + this.trackRouteColor = trackRouteColor; + } + + public Color getSelectedColor() { + return selectedColor; + } + + public void setSelectedColor(Color selectedColor) { + this.selectedColor = selectedColor; + } - void flipHorizontal(); + public Orientation getIncomingSide() { + return incomingSide; + } - void flipVertical(); + public void setIncomingSide(Orientation incomingSide) { + this.incomingSide = incomingSide; + } - void move(int newX, int newY); + public Color getBackgroundColor() { + return backgroundColor; + } - TileBean.Orientation getOrientation(); + public void setBackgroundColor(Color backgroundColor) { + this.backgroundColor = backgroundColor; + } - void setOrientation(TileBean.Orientation orientation); + public boolean isDrawRoute() { + return this.model.isShowRoute(); + } - Direction getDirection(); + public void setDrawRoute(boolean drawRoute) { + this.model.setShowRoute(drawRoute); + } - void setDirection(Direction direction); + public int getRenderWidth() { + return renderWidth; + } - Point getCenter(); + public int getRenderHeight() { + return renderHeight; + } - void setCenter(Point center); + abstract void renderTile(Graphics2D g2d); - /** - * @return a Set of alternative points in case the tile is not a square - */ - Set getAltPoints(); + abstract void renderTileRoute(Graphics2D g2d); /** - * @return All points relevant for the Object on the Canvas - */ - Set getAllPoints(); - - int getOffsetX(); - - void setOffsetX(int offsetX); - - int getOffsetY(); - - void setOffsetY(int offsetY); - - int getHeight(); - - int getWidth(); - - /** - * @return the X (pixel) coordinate of the center of the tile + * Draw the Tile + * + * @param g2d The graphics handle */ - int getCenterX(); + //@Override + public void drawTile(Graphics2D g2d) { + // by default and image is rendered in the EAST orientation + Orientation o = getOrientation(); + if (o == null) { + o = Orientation.EAST; + } + + tileImage = createImage(); + Graphics2D g2di = tileImage.createGraphics(); + + //Avoid errors + if (model.isShowRoute() && incomingSide == null) { + incomingSide = getOrientation(); + } + + if (model.isSelected()) { + g2di.setBackground(selectedColor); + } else { + g2di.setBackground(backgroundColor); + } + + g2di.clearRect(0, 0, renderWidth, renderHeight); + int ox = 0, oy = 0; + + AffineTransform trans = new AffineTransform(); + switch (o) { + case SOUTH -> { + trans.rotate(Math.PI / 2, renderWidth / 2, renderHeight / 2); + ox = (renderHeight - renderWidth) / 2; + oy = (renderWidth - renderHeight) / 2; + trans.translate(-ox, -oy); + } + case WEST -> { + trans.rotate(Math.PI, renderWidth / 2, renderHeight / 2); + trans.translate(ox, oy); + } + case NORTH -> { + trans.rotate(-Math.PI / 2, renderWidth / 2, renderHeight / 2); + ox = (renderHeight - renderWidth) / 2; + oy = (renderWidth - renderHeight) / 2; + trans.translate(-ox, -oy); + } + default -> { + //trans.rotate(0.0, this.renderWidth / 2, this.renderHeight / 2); + //trans.translate(ox, oy); + } + } + + g2di.setTransform(trans); + + renderTile(g2di); + + if (model.isShowRoute()) { + renderTileRoute(g2di); + } + + if (model.isShowCenter()) { + drawCenterPoint(g2di); + } + + // Scale the image back... + if (this.model.isScaleImage()) { + tileImage = Scalr.resize(tileImage, Method.AUTOMATIC, Mode.FIT_EXACT, getWidth(), getHeight(), Scalr.OP_ANTIALIAS); + } + + g2di.dispose(); + +// int oxx, oyy; +// if (scaleImage) { +// oxx = offsetX; +// oyy = offsetY; +// } else { +// oxx = renderOffsetX; +// oyy = renderOffsetY; +// } + //g2d.drawImage(tileImage, (tileX - tileImage.getWidth() / 2) + oxx, (tileY - tileImage.getHeight() / 2) + oyy, null); + } + + public BufferedImage getTileImage() { + return tileImage; + } /** - * @return then Y (pixel) coordinate of the center of the tile + * Render a tile image Always starts at (0,0) used the default width and height + * + * @param g2 the Graphic context */ - int getCenterY(); + public void drawName(Graphics2D g2) { + } - TileBean getTileBean(); + protected void drawCenterPoint(Graphics2D g2d) { + drawCenterPoint(g2d, Color.magenta); + } - boolean isDrawOutline(); + protected void drawCenterPoint(Graphics2D g2, Color color) { + drawCenterPoint(g2, color, 60); + } - void setDrawOutline(boolean drawOutline); + protected void drawCenterPoint(Graphics2D g2d, Color color, double size) { + double dX = (renderWidth / 2 - size / 2); + double dY = (renderHeight / 2 - size / 2); - TileType getTileType(); - - void setPropertyChangeListener(PropertyChangeListener listener); - - String xyToString(); + g2d.setColor(color); + g2d.fill(new Ellipse2D.Double(dX, dY, size, size)); + } /** - * @return the X number of the grid square (grid is 40 x 40 pix) + * Rotate the tile clockwise 90 deg */ - int getGridX(); + public void rotate() { + rotate(true); + } /** - * @return the Y number of the grid square (grid is 40 x 40 pix) + * Rotate the tile clockwise 90 deg */ - int getGridY(); + void rotate(boolean repaint) { + + switch (getOrientation()) { + case EAST -> + setOrientation(Orientation.SOUTH); + case SOUTH -> + setOrientation(Orientation.WEST); + case WEST -> + setOrientation(Orientation.NORTH); + default -> + setOrientation(Orientation.EAST); + } + if (repaint) { + repaint(); + } + } + + public void flipHorizontal() { + if (Orientation.NORTH.equals(getOrientation()) || Orientation.SOUTH.equals(getOrientation())) { + rotate(false); + rotate(true); + } + } + + public void flipVertical() { + if (Orientation.EAST.equals(getOrientation()) || Orientation.WEST.equals(getOrientation())) { + rotate(false); + rotate(true); + } + } + + @Override + public void move(int newX, int newY) { + Point cs = LayoutUtil.snapToGrid(newX, newY); + setCenter(cs); + } + + protected static void drawRotate(Graphics2D g2d, double x, double y, int angle, String text) { + g2d.translate((float) x, (float) y); + g2d.rotate(Math.toRadians(angle)); + g2d.drawString(text, 0, 0); + g2d.rotate(-Math.toRadians(angle)); + g2d.translate(-x, -y); + } + + public static BufferedImage flipHorizontally(BufferedImage source) { + BufferedImage output = new BufferedImage(source.getHeight(), source.getWidth(), source.getType()); + + AffineTransform flip = AffineTransform.getScaleInstance(1, -1); + flip.translate(0, -source.getHeight()); + AffineTransformOp op = new AffineTransformOp(flip, AffineTransformOp.TYPE_NEAREST_NEIGHBOR); + + op.filter(source, output); + + return output; + } + + public static BufferedImage flipVertically(BufferedImage source) { + BufferedImage output = new BufferedImage(source.getHeight(), source.getWidth(), source.getType()); + + AffineTransform flip = AffineTransform.getScaleInstance(-1, 1); + flip.translate(-source.getWidth(), 0); + AffineTransformOp op = new AffineTransformOp(flip, AffineTransformOp.TYPE_NEAREST_NEIGHBOR); + + op.filter(source, output); + + return output; + } + + public Set getAltPoints() { + return Collections.EMPTY_SET; + } + + public final int getOffsetX() { + return offsetX; + } + + public void setOffsetX(int offsetX) { + this.offsetX = offsetX; + } + + public final int getOffsetY() { + return offsetY; + } + + public void setOffsetY(int offsetY) { + this.offsetY = offsetY; + } + + protected BufferedImage createImage() { + return new BufferedImage(renderWidth, renderHeight, BufferedImage.TYPE_INT_RGB); + } + + public int getCenterX() { + if (this.tileX > 0) { + return this.tileX; + } else { + return GRID; + } + } + + public int getCenterY() { + if (this.tileY > 0) { + return this.tileY; + } else { + return GRID; + } + } + + public boolean isDrawName() { + return drawName; + } + + public void setDrawName(boolean drawName) { + this.drawName = drawName; + } + + public boolean isScaleImage() { + return model.isScaleImage(); + } + + public void setScaleImage(boolean scaleImage) { + Dimension d; + if (scaleImage) { + d = new Dimension(DEFAULT_WIDTH, DEFAULT_HEIGHT); + } else { + d = new Dimension(renderWidth, renderHeight); + } + + setSize(d); + setPreferredSize(d); + + model.setScaleImage(scaleImage); + } + + public boolean isDrawCenterPoint() { + return model.isShowCenter(); + } + + public void setDrawCenterPoint(boolean drawCenterPoint) { + model.setShowCenter(drawCenterPoint); + } + + @Override + public String toString() { + return this.getClass().getSimpleName() + + " {id: " + + this.id + + ", orientation: " + + getOrientation() + + ", direction: " + + getDirection() + + ", center: " + + xyToString() + + "}"; + } + + @Override + public Rectangle getBounds() { + int w, h, cx, cy; + //TODO: Check this may by the componet does this already + if (this.getWidth() > 0 & this.getHeight() > 0) { + //if (this.width > 0 & this.height > 0) { + //w = this.width; + w = this.getPreferredSize().width; + //h = this.height; + h = this.getPreferredSize().height; + } else { + w = DEFAULT_WIDTH; + h = DEFAULT_HEIGHT; + } + + if (this.tileX > 0 && this.tileY > 0) { + cx = this.tileX + this.offsetX; + cy = this.tileY + this.offsetY; + } else { + cx = w / 2; + cy = h / 2; + } + + int ltx = cx - w / 2; + int lty = cy - h / 2; + return new Rectangle(ltx, lty, w, h); + } + + public Rectangle2D getBounds2D() { + return getBounds().getBounds2D(); + } + + public boolean contains(double x, double y) { + int w, h, cx, cy, tlx, tly; + if (this.getWidth() > 0 & this.getHeight() > 0) { + //if (this.width > 0 & this.height > 0) { +// w = this.width; +// h = this.height; + w = this.getPreferredSize().width; + h = this.getPreferredSize().height; + + } else { + w = DEFAULT_WIDTH; + h = DEFAULT_HEIGHT; + } + + if (this.getWidth() > 0 & this.getHeight() > 0) { + //if (this.width > 0 & this.height > 0) { + cx = this.tileX; + cy = this.tileY; + } else { + cx = w / 2; + cy = h / 2; + } + + // top left dX and dY + tlx = cx - w / 2; + tly = cy - h / 2; + + // Check if X and Y range is ok + return !(x < tlx || x > (tlx + w) || y < tly || y > (tly + h)); + } + + public String xyToString() { + return "(" + this.tileX + "," + this.tileY + ")"; + } + + public boolean contains(Point2D p) { + return this.contains(p.getX(), p.getY()); + } + + public boolean intersects(double x, double y, double w, double h) { + return getBounds().intersects(x, y, w, h); + } + + public boolean intersects(Rectangle2D r2d) { + return getBounds().intersects(r2d); + } + + public boolean contains(double x, double y, double w, double h) { + return getBounds().contains(x, y, w, h); + } + + public boolean contains(Rectangle2D r2d) { + return getBounds().contains(r2d); + } + + public PathIterator getPathIterator(AffineTransform at) { + return getBounds().getPathIterator(at); + } + + public PathIterator getPathIterator(AffineTransform at, double flatness) { + return getBounds().getPathIterator(at, flatness); + } + + @Deprecated + public PropertyChangeListener getPropertyChangeListener() { + return this.propertyChangeListener; + } + + @Deprecated + public void setPropertyChangeListener(PropertyChangeListener propertyChangeListener) { + this.propertyChangeListener = propertyChangeListener; + } + + @Deprecated + public void repaintTile() { +// if (this.propertyChangeListener != null) { +// this.propertyChangeListener.propertyChange(new PropertyChangeEvent(this, "repaintTile", this, this)); +// } + } + + @Override + @Deprecated + public void onTileChange(TileEvent tileEvent) { + Logger.warn("Deprecated! " + tileEvent.getTileId()); + if (tileEvent.isEventFor(this)) { + boolean drawRoute = tileEvent.isShowRoute(); + setIncomingSide(tileEvent.getIncomingSide()); + + if (isJunction()) { + // setRouteValue(tileEvent.getRouteState()); + } + + if (tileEvent.getBlockBean() != null) { + this.setBlockBean(tileEvent.getBlockBean()); + } + + if (tileEvent.getTileBean() != null) { + TileBean other = tileEvent.getTileBean(); + this.copyInto(other); + } + + if (isBlock()) { + // ((Block) this).setRouteBlockState(tileEvent.getBlockState()); + if (!drawRoute) { + // ((Block) this).setRouteBlockState(null); + } + } + + setBackgroundColor(tileEvent.getBackgroundColor()); + setTrackColor(tileEvent.getTrackColor()); + setTrackRouteColor(tileEvent.getTrackRouteColor()); + +// if (tileEvent.getBlockBean() != null) { +// setBlockBean(tileEvent.getBlockBean()); +// } +// repaintTile(); + } + } + + public int getGridX() { + return (getCenterX() - Tile.GRID) / (Tile.GRID * 2); + } + + public int getGridY() { + return (getCenterY() - Tile.GRID) / (Tile.GRID * 2); + } /** * The main route of the tile is horizontal * * @return true when main route goes from East to West or vv */ - boolean isHorizontal(); + public boolean isHorizontal() { + return (Orientation.EAST == getOrientation() || Orientation.WEST == getOrientation()) && TileType.CURVED != getTileType(); + } /** * The main route of the tile is vertical * * @return true when main route goes from North to South or vv */ - boolean isVertical(); + public boolean isVertical() { + return (Orientation.NORTH == getOrientation() || Orientation.SOUTH == getOrientation()) && TileType.CURVED != getTileType(); + } + + public boolean isJunction() { + return false; + } + + public boolean isBlock() { + return false; + } + + public boolean isDirectional() { + return false; + } /** * The main route of the tile is diagonal * * @return true when main route goes from North to East or West to South and vv */ - boolean isDiagonal(); + public boolean isDiagonal() { + return TileType.CURVED == getTileType(); + } - boolean isJunction(); + public boolean isCrossing() { + return TileType.CROSSING == getTileType(); + } - boolean isBlock(); + public List getNeighbours() { + return this.neighbours; + } - boolean isDirectional(); + public void setNeighbours(List neighbours) { + this.neighbours = neighbours; + } - boolean isCrossing(); + public String getIdSuffix(Tile other) { + return ""; + } - Map getNeighborPoints(); + public Map getNeighborOrientations() { + Map edgeOrientations = new HashMap<>(); - Map getNeighborOrientations(); + Map neighborPoints = getNeighborPoints(); - Map getEdgePoints(); + for (Orientation o : Orientation.values()) { + edgeOrientations.put(neighborPoints.get(o), o); + } + return edgeOrientations; + } - Map getEdgeOrientations(); + public Map getEdgeOrientations() { + Map edgeOrientations = new HashMap<>(); - AccessoryValue accessoryValueForRoute(Orientation from, Orientation to); + Map edgeConnections = getEdgePoints(); - /** - * @param other a tile to check with this tile - * @return true when the other tile is adjacent to this and the "tracks" connect - */ - boolean isAdjacent(Tile other); + for (Orientation o : Orientation.values()) { + edgeOrientations.put(edgeConnections.get(o), o); + } + return edgeOrientations; + } + + public boolean isAdjacent(Tile other) { + boolean adjacent = false; - String getIdSuffix(Tile other); + if (other != null) { + Collection thisEdgePoints = getEdgePoints().values(); + Collection otherEdgePoints = other.getEdgePoints().values(); + + for (Point p : thisEdgePoints) { + adjacent = otherEdgePoints.contains(p); + if (adjacent) { + break; + } + } + } + + return adjacent; + } /** - * When the tile has a specific direction a train may travel then this method will indicate whether the other tile is in on the side where the arrow is pointing to + * When the tile has a specific direction a train may travel,
+ * then this method will indicate whether the other tile is in on the side where the arrow is pointing to. * * @param other A Tile * @return true where other is on the side of this tile where the arrow points to */ - boolean isArrowDirection(Tile other); + public boolean isArrowDirection(Tile other) { + return true; + } + + public AccessoryValue accessoryValueForRoute(Orientation from, Orientation to) { + return AccessoryValue.OFF; + } + + @Deprecated + protected StringBuilder getImageKeyBuilder() { + StringBuilder sb = new StringBuilder(); + //sb.append(id); + sb.append(this.tileType); + sb.append("~"); + sb.append(getOrientation().getOrientation()); + sb.append("~"); + sb.append(getDirection().getDirection()); + //sb.append("~"); + //sb.append(isDrawOutline() ? "y" : "n"); + sb.append("~"); + int r = backgroundColor.getRed(); + int g = backgroundColor.getGreen(); + int b = backgroundColor.getBlue(); + sb.append("#"); + sb.append(r); + sb.append("#"); + sb.append(g); + sb.append("#"); + sb.append(b); + sb.append("~"); + r = trackColor.getRed(); + g = trackColor.getGreen(); + b = trackColor.getBlue(); + sb.append("#"); + sb.append(r); + sb.append("#"); + sb.append(g); + sb.append("#"); + sb.append(b); + sb.append("~"); + sb.append(isDrawRoute() ? "y" : "n"); + if (isDrawRoute()) { + if (incomingSide != null) { + sb.append("~"); + sb.append(incomingSide.getOrientation()); + } + sb.append("~"); + r = trackRouteColor.getRed(); + g = trackRouteColor.getGreen(); + b = trackRouteColor.getBlue(); + sb.append("#"); + sb.append(r); + sb.append("#"); + sb.append(g); + sb.append("#"); + sb.append(b); + } + + //sb.append("~"); + //Tile specific properties + //AccessoryValue + //SignalType + //SignalValue + //active; + //Logger.trace(sb); + return sb; + } + + public abstract Map getNeighborPoints(); + + public abstract Map getEdgePoints(); + + public abstract Set getAllPoints(); + + public TileModel getModel() { + return model; + } + + public void setModel(TileModel newModel) { + TileModel oldModel = getModel(); + + if (oldModel != null) { + oldModel.removeChangeListener(changeListener); + oldModel.removeActionListener(actionListener); + changeListener = null; + actionListener = null; + } + + model = newModel; + + if (newModel != null) { + changeListener = createChangeListener(); + actionListener = createActionListener(); + + newModel.addChangeListener(changeListener); + newModel.addActionListener(actionListener); + } + + firePropertyChange(MODEL_CHANGED_PROPERTY, oldModel, newModel); + if (newModel != oldModel) { + revalidate(); + repaint(); + } + } + +// public TileUI getUI() { +// return (TileUI) ui; +// } +// public void setUI(TileUI ui) { +// super.setUI(ui); +// } + @Override + public void updateUI() { + } + + protected ChangeListener createChangeListener() { + return getHandler(); + } + + protected ActionListener createActionListener() { + return getHandler(); + } + + private Handler getHandler() { + if (handler == null) { + handler = new Handler(); + } + return handler; + } + + class Handler implements ActionListener, ChangeListener, Serializable { + + @Override + public void stateChanged(ChangeEvent e) { + Object source = e.getSource(); + + fireStateChanged(); + repaint(); + } + + @Override + public void actionPerformed(ActionEvent event) { + fireActionPerformed(event); + } + } + + protected void fireStateChanged() { + Object[] listeners = listenerList.getListenerList(); + //reverse order + for (int i = listeners.length - 2; i >= 0; i -= 2) { + if (listeners[i] == ChangeListener.class) { + // Lazily create the event: + if (changeEvent == null) { + changeEvent = new ChangeEvent(this); + } + ((ChangeListener) listeners[i + 1]).stateChanged(changeEvent); + } + } + } + + protected void fireActionPerformed(ActionEvent event) { + Object[] listeners = listenerList.getListenerList(); + ActionEvent e = null; + // reverse + for (int i = listeners.length - 2; i >= 0; i -= 2) { + if (listeners[i] == ActionListener.class) { + // Lazily create the event: + if (e == null) { + String actionCommand = event.getActionCommand(); + //if(actionCommand == null) { + // actionCommand = getActionCommand(); + //} + e = new ActionEvent(Tile.this, ActionEvent.ACTION_PERFORMED, actionCommand, event.getWhen(), event.getModifiers()); + } + ((ActionListener) listeners[i + 1]).actionPerformed(e); + } + } + } + } diff --git a/src/main/java/jcs/ui/layout/tiles/Tile1.java b/src/main/java/jcs/ui/layout/tiles/Tile1.java new file mode 100644 index 00000000..b01cb9be --- /dev/null +++ b/src/main/java/jcs/ui/layout/tiles/Tile1.java @@ -0,0 +1,221 @@ +/* + * Copyright 2023 Frans Jacobs. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package jcs.ui.layout.tiles; + +import java.awt.Color; +import java.awt.Graphics2D; +import java.awt.Point; +import java.awt.Shape; +import java.awt.image.BufferedImage; +import java.beans.PropertyChangeListener; +import java.util.Map; +import java.util.Set; +import jcs.entities.AccessoryBean.AccessoryValue; +import jcs.entities.TileBean; +import jcs.entities.TileBean.Direction; +import jcs.entities.TileBean.Orientation; +import jcs.entities.TileBean.TileType; + +/** + * @author frans + */ +public interface Tile1 extends Shape { + + public static final int GRID = 20; + public static final int DEFAULT_WIDTH = GRID * 2; + public static final int DEFAULT_HEIGHT = GRID * 2; + + static final int RENDER_GRID = GRID * 10; + static final int RENDER_WIDTH = RENDER_GRID * 2; + static final int RENDER_HEIGHT = RENDER_GRID * 2; + + public static final Color DEFAULT_BACKGROUND_COLOR = Color.white; + public static final Color DEFAULT_TRACK_COLOR = Color.lightGray; + public static final Color DEFAULT_ROUTE_TRACK_COLOR = Color.blue; + + boolean isDrawRoute(); + + void setDrawRoute(boolean drawRoute); + + Color getTrackColor(); + + void setTrackColor(Color trackColor); + + Color getTrackRouteColor(); + + void setTrackRouteColor(Color trackRouteColor); + + Orientation getIncomingSide(); + + void setIncomingSide(Orientation incomingSide); + + Color getBackgroundColor(); + + void setBackgroundColor(Color backgroundColor); + + String getId(); + + void setId(String id); + + //String getImageKey(); + + BufferedImage getTileImage(); + + void drawTile(Graphics2D g2d, boolean drawOutline); + + void renderTile(Graphics2D g2d); + + void renderTileRoute(Graphics2D g2d); + + void drawName(Graphics2D g2); + + void drawCenterPoint(Graphics2D g2d); + + void drawCenterPoint(Graphics2D g2, Color color); + + void drawCenterPoint(Graphics2D g2d, Color color, double size); + + void drawBounds(Graphics2D g2d); + + void rotate(); + + void flipHorizontal(); + + void flipVertical(); + + void move(int newX, int newY); + + TileBean.Orientation getOrientation(); + + void setOrientation(TileBean.Orientation orientation); + + Direction getDirection(); + + void setDirection(Direction direction); + + Point getCenter(); + + void setCenter(Point center); + + /** + * @return a Set of alternative points in case the tile is not a square + */ + Set getAltPoints(); + + /** + * @return All points relevant for the Object on the Canvas + */ + Set getAllPoints(); + + int getOffsetX(); + + void setOffsetX(int offsetX); + + int getOffsetY(); + + void setOffsetY(int offsetY); + + int getHeight(); + + int getWidth(); + + /** + * @return the X (pixel) coordinate of the center of the tile + */ + int getCenterX(); + + /** + * @return then Y (pixel) coordinate of the center of the tile + */ + int getCenterY(); + + TileBean getTileBean(); + + boolean isDrawOutline(); + + void setDrawOutline(boolean drawOutline); + + TileType getTileType(); + + void setPropertyChangeListener(PropertyChangeListener listener); + + String xyToString(); + + /** + * @return the X number of the grid square (grid is 40 x 40 pix) + */ + int getGridX(); + + /** + * @return the Y number of the grid square (grid is 40 x 40 pix) + */ + int getGridY(); + + /** + * The main route of the tile is horizontal + * + * @return true when main route goes from East to West or vv + */ + boolean isHorizontal(); + + /** + * The main route of the tile is vertical + * + * @return true when main route goes from North to South or vv + */ + boolean isVertical(); + + /** + * The main route of the tile is diagonal + * + * @return true when main route goes from North to East or West to South and vv + */ + boolean isDiagonal(); + + boolean isJunction(); + + boolean isBlock(); + + boolean isDirectional(); + + boolean isCrossing(); + + Map getNeighborPoints(); + + Map getNeighborOrientations(); + + Map getEdgePoints(); + + Map getEdgeOrientations(); + + AccessoryValue accessoryValueForRoute(Orientation from, Orientation to); + + /** + * @param other a tile to check with this tile + * @return true when the other tile is adjacent to this and the "tracks" connect + */ + boolean isAdjacent(Tile1 other); + + String getIdSuffix(Tile1 other); + + /** + * When the tile has a specific direction a train may travel then this method will indicate whether the other tile is in on the side where the arrow is pointing to + * + * @param other A Tile + * @return true where other is on the side of this tile where the arrow points to + */ + boolean isArrowDirection(Tile1 other); +} diff --git a/src/main/java/jcs/ui/layout/tiles/TileFactory.java b/src/main/java/jcs/ui/layout/tiles/TileFactory.java index 6baece4f..203796ba 100755 --- a/src/main/java/jcs/ui/layout/tiles/TileFactory.java +++ b/src/main/java/jcs/ui/layout/tiles/TileFactory.java @@ -16,27 +16,16 @@ package jcs.ui.layout.tiles; import java.awt.Point; -import java.awt.event.MouseEvent; -import java.beans.PropertyChangeListener; -import java.util.HashMap; -import java.util.HashSet; import java.util.LinkedList; import java.util.List; -import java.util.Map; -import java.util.Set; import jcs.JCS; import jcs.commandStation.events.AccessoryEventListener; import jcs.commandStation.events.SensorEventListener; import jcs.entities.AccessoryBean; -import jcs.entities.AccessoryBean.AccessoryValue; -import jcs.entities.AccessoryBean.SignalValue; import jcs.entities.SensorBean; import jcs.entities.TileBean; import jcs.entities.TileBean.Direction; import jcs.entities.TileBean.Orientation; -import static jcs.entities.TileBean.Orientation.EAST; -import static jcs.entities.TileBean.Orientation.SOUTH; -import static jcs.entities.TileBean.Orientation.WEST; import static jcs.entities.TileBean.TileType.BLOCK; import static jcs.entities.TileBean.TileType.CROSS; import static jcs.entities.TileBean.TileType.CROSSING; @@ -47,11 +36,6 @@ import static jcs.entities.TileBean.TileType.STRAIGHT; import static jcs.entities.TileBean.TileType.STRAIGHT_DIR; import static jcs.entities.TileBean.TileType.SWITCH; -import jcs.persistence.PersistenceFactory; -import jcs.ui.layout.LayoutCanvas; -import jcs.ui.layout.LayoutUtil; -import jcs.ui.layout.events.TileEvent; -import jcs.ui.layout.events.TileEventListener; import org.tinylog.Logger; /** @@ -73,14 +57,11 @@ public class TileFactory { private static int straightDirectionIdSeq; private static int endIdSeq; - private static final Map tileEventListeners = new HashMap<>(); - - private static boolean drawOutline; - private static boolean showValues; - - public static final Map tiles = new HashMap<>(); - public static final Map altTiles = new HashMap<>(); - + //private static final Map tileEventListeners = new HashMap<>(); +// private static boolean drawOutline; +// private static boolean showValues; +// public static final Map tiles = new HashMap<>(); +// public static final Map altTiles = new HashMap<>(); private TileFactory() { } @@ -153,16 +134,16 @@ public static Tile createTile(String tileId) { } public static Tile createTile(TileBean tileBean) { - return createTile(tileBean, false, false); + return createTile(tileBean, false); } - public static Tile createTile(TileBean tileBean, boolean drawOutline, boolean showValues) { + public static Tile createTile(TileBean tileBean, boolean showValues) { if (tileBean == null) { return null; } TileBean.TileType tileType = tileBean.getTileType(); - AbstractTile tile = null; + Tile tile = null; switch (tileType) { case STRAIGHT -> { tile = new Straight(tileBean); @@ -182,7 +163,7 @@ public static Tile createTile(TileBean tileBean, boolean drawOutline, boolean sh switchIdSeq = maxIdSeq(switchIdSeq, nextIdSeq(tileBean.getId())); if (showValues && tileBean.getAccessoryBean() != null) { - ((Switch) tile).setValue((tileBean.getAccessoryBean()).getAccessoryValue()); + tile.setAccessoryValue((tileBean.getAccessoryBean()).getAccessoryValue()); } JCS.getJcsCommandStation().addAccessoryEventListener((AccessoryEventListener) tile); } @@ -192,7 +173,7 @@ public static Tile createTile(TileBean tileBean, boolean drawOutline, boolean sh crossIdSeq = maxIdSeq(crossIdSeq, nextIdSeq(tileBean.getId())); if (showValues && tileBean.getAccessoryBean() != null) { - ((Switch) tile).setValue((tileBean.getAccessoryBean()).getAccessoryValue()); + tile.setAccessoryValue((tileBean.getAccessoryBean()).getAccessoryValue()); } JCS.getJcsCommandStation().addAccessoryEventListener((AccessoryEventListener) tile); } @@ -232,12 +213,10 @@ public static Tile createTile(TileBean tileBean, boolean drawOutline, boolean sh Logger.warn("Unknown Tile Type " + tileType); } - if (tile != null) { - tile.setDrawOutline(drawOutline); - } - - addTileEventListener((TileEventListener) tile); - +// if (tile != null) { +// tile.setDrawOutline(drawOutline); +// } +// addTileEventListener((TileEventListener) tile); return (Tile) tile; } @@ -296,11 +275,11 @@ public static Tile createTile(TileBean.TileType tileType, Orientation orientatio } if (tile != null) { - tile.setDrawOutline(drawOutline); + //tile.setDrawOutline(drawOutline); tile.setId(nextTileId(tileType)); } - addTileEventListener((TileEventListener) tile); +// addTileEventListener((TileEventListener) tile); return (Tile) tile; } @@ -308,350 +287,10 @@ public static List toTiles(List tileBeans, boolean drawOutline, List tileList = new LinkedList<>(); for (TileBean tileBean : tileBeans) { - Tile tile = createTile(tileBean, drawOutline, showValues); + Tile tile = createTile(tileBean, showValues); tileList.add(tile); } return tileList; } - private static void addTileEventListener(TileEventListener listener) { - String key = listener.getId(); - tileEventListeners.put(key, listener); - } - - public static void removeTileEventListener(Tile tile) { - if (tile instanceof TileEventListener tileEventListener) { - removeTileEventListener(tileEventListener); - } - } - - public static void removeTileEventListener(TileEventListener listener) { - String key = listener.getId(); - tileEventListeners.remove(key, listener); - } - - public static void fireTileEventListener(TileEvent tileEvent) { - String key = tileEvent.getTileId(); - TileEventListener listener = tileEventListeners.get(key); - if (listener != null) { - listener.onTileChange(tileEvent); - } else { - //Logger.trace("Tile " + key + " not available"); - } - } - - public static void fireAllTileEventListeners(TileEvent tileEvent) { - for (TileEventListener listener : tileEventListeners.values()) { - listener.onTileChange(tileEvent); - } - } - - public static void setPropertyListener(PropertyChangeListener propertyChangeListener) { - for (Tile tile : tiles.values()) { - tile.setPropertyChangeListener(propertyChangeListener); - } - } - - public static void setDrawOutline(boolean drawOutline) { - TileFactory.drawOutline = drawOutline; - - for (Tile tile : tiles.values()) { - tile.setDrawOutline(drawOutline); - } - } - - public static void setShowValues(boolean showValues) { - TileFactory.showValues = showValues; - - for (Tile tile : tiles.values()) { - TileBean.TileType tileType = tile.getTileType(); - //AbstractTile tile = null; - switch (tileType) { - case SWITCH -> { - if (showValues && ((AbstractTile) tile).getAccessoryBean() != null) { - ((Switch) tile).setValue((((AbstractTile) tile).getAccessoryBean()).getAccessoryValue()); - } else { - ((Switch) tile).setValue(AccessoryValue.OFF); - } - } - case CROSS -> { - if (showValues && ((AbstractTile) tile).getAccessoryBean() != null) { - ((Switch) tile).setValue((((AbstractTile) tile).getAccessoryBean()).getAccessoryValue()); - } else { - ((Switch) tile).setValue(AccessoryValue.OFF); - } - } - case SIGNAL -> { - if (showValues && ((AbstractTile) tile).getAccessoryBean() != null) { - ((Signal) tile).setSignalValue(((AccessoryBean) ((AbstractTile) tile).getAccessoryBean()).getSignalValue()); - } else { - ((Signal) tile).setSignalValue(SignalValue.OFF); - } - } - case SENSOR -> { - if (showValues && ((AbstractTile) tile).getSensorBean() != null) { - ((Sensor) tile).setActive(((SensorBean) ((AbstractTile) tile).getSensorBean()).isActive()); - } else { - ((Sensor) tile).setActive(false); - } - } - case BLOCK -> { - } - } - } - } - - public static void loadTiles() { - List tileBeans = PersistenceFactory.getService().getTileBeans(); - - altTiles.clear(); - tiles.clear(); - - for (TileBean tb : tileBeans) { - Tile tile = createTile(tb, drawOutline, showValues); - //tile.setPropertyChangeListener(this); - tiles.put(tile.getCenter(), tile); - - //Alternative point(s) to be able to find all points - if (!tile.getAltPoints().isEmpty()) { - Set alt = tile.getAltPoints(); - for (Point ap : alt) { - altTiles.put(ap, tile); - } - } - } - Logger.trace("Loaded " + tiles.size() + " Tiles..."); - - } - - public static void addTile(Tile tile) { - tiles.put(tile.getCenter(), tile); - //Alternative point(s) to be able to find all points - if (!tile.getAltPoints().isEmpty()) { - Set alt = tile.getAltPoints(); - for (Point ap : alt) { - altTiles.put(ap, tile); - } - } - - if ("false".equals(System.getProperty("batch.tile.persist", "true"))) { - saveTile(tile); - } - } - - public void removeTiles(Set pointsToRemove) { - for (Point p : pointsToRemove) { - Tile removed = tiles.remove(p); - - if ("false".equals(System.getProperty("batch.tile.persist", "true"))) { - deleteTile(removed); - } - - if (removed != null && removed.getAllPoints() != null) { - Set rps = removed.getAltPoints(); - //Also remove alt points - for (Point ap : rps) { - altTiles.remove(ap); - } - - } - } - } - - private void deleteTile(final Tile tile) { - if (tile != null) { - TileBean tb = tile.getTileBean(); - PersistenceFactory.getService().remove(tb); - } - } - - private static void saveTile(final Tile tile) { - if (tile != null) { - TileBean tb = tile.getTileBean(); - PersistenceFactory.getService().persist(tb); - } - } - - public static void saveTiles() { - List beans = new LinkedList<>(); - - for (Tile tile : tiles.values()) { - saveTile(tile); - } - } - - public static Tile findTile(Point cp) { - Tile result = tiles.get(cp); - if (result == null) { - result = altTiles.get(cp); - if (result != null) { - } - } - return result; - } - - public static boolean checkTileOccupation(Tile tile) { - Set tilePoints = tile.getAllPoints(); - for (Point p : tilePoints) { - if (tiles.containsKey(p) || altTiles.containsKey(p)) { - //The is a match, check if it is an other tile - Tile mt = findTile(p); - if (tile.getId().equals(mt.getId())) { - //same tile continue - } else { - //Other tile so really occupied - return true; - } - } - } - return false; - } - - public static Point checkAvailable(Point newPoint, Orientation orientation) { - if (tiles.containsKey(newPoint)) { - Tile et = tiles.get(newPoint); - Logger.trace("@ " + newPoint + " is allready occcupied by: " + et + "..."); - //Search for the nearest avalaible free point - //first get the Center point of the tile which is occuping this slot - // show warning! - Point ecp = et.getCenter(); - - int w = et.getWidth(); - int h = et.getHeight(); - - Point np; - np = switch (orientation) { - case EAST -> - new Point(ecp.x + w, ecp.y); - case WEST -> - new Point(newPoint.x - w, ecp.y); - case SOUTH -> - new Point(ecp.x, newPoint.y + h); - default -> - new Point(ecp.x, newPoint.y - h); - }; - - Logger.trace("Alternative CP: " + np); - // recursive check - return checkAvailable(np, orientation); - } else { - Logger.trace("@ " + newPoint + " is not yet used..."); - - return newPoint; - } - } - - public static void rotateTile(Set centerPoints) { - for (Point p : centerPoints) { - if (tiles.containsKey(p)) { - Tile t = tiles.get(p); - //Remove the alternative or extra points... - for (Point ep : t.getAltPoints()) { - altTiles.remove(ep); - } - - t.rotate(); - - //update - tiles.put(p, t); - for (Point ep : t.getAltPoints()) { - altTiles.put(ep, t); - } - - if ("false".equals(System.getProperty("batch.tile.persist", "true"))) { - saveTile(t); - } - } - } - } - - public static void flipHorizontal(Set points) { - flipTile(points, true); - } - - public static void flipVertical(Set points) { - flipTile(points, false); - } - - private static void flipTile(Set points, boolean horizontal) { - for (Point p : points) { - if (tiles.containsKey(p)) { - Tile t = tiles.get(p); - //Remove the alternative or extra points... - for (Point ep : t.getAltPoints()) { - altTiles.remove(ep); - } - - if (horizontal) { - t.flipHorizontal(); - } else { - t.flipVertical(); - } - //Update - tiles.put(p, t); - for (Point ep : t.getAltPoints()) { - altTiles.put(ep, t); - } - - if ("false".equals(System.getProperty("batch.tile.persist", "true"))) { - saveTile(t); - } - } - } - } - - public static void moveTile(Point snapPoint, Tile tile) { - Point tp = tile.getCenter(); - if (!tp.equals(snapPoint)) { - //Check if new position is free - boolean canMove = true; - if (tiles.containsKey(snapPoint) || altTiles.containsKey(snapPoint)) { - Tile t = findTile(snapPoint); - if (tile.getId().equals(t.getId())) { - //same tile so we can move - canMove = true; - } else { - Logger.trace("Position " + snapPoint + " is occupied with tile: " + t + ", can't move tile " + tile.getId()); - canMove = false; - } - - if (canMove) { - //Remove the original tile center from the tiles - Tile movingTile = tiles.remove(tp); - if (movingTile != null) { - //Also remove from the alt points - Point oldCenter = movingTile.getCenter(); - Set oldAltPoints = movingTile.getAltPoints(); - //Logger.trace("Removing " + oldAltPoints.size() + " alt tile points"); - for (Point ep : oldAltPoints) { - altTiles.remove(ep); - tiles.remove(ep); - } - - //Set the new center position - movingTile.setCenter(snapPoint); - //Check again, needed for tiles which are longer then 1 square, like a block - if (!checkTileOccupation(movingTile)) { - Logger.trace("Moved Tile " + movingTile.getId() + " from " + tp + " to " + snapPoint + "..."); - tiles.put(snapPoint, movingTile); - for (Point ep : movingTile.getAltPoints()) { - altTiles.put(ep, movingTile); - } - } else { - //Do not move Tile, put back where it was - movingTile.setCenter(oldCenter); - tiles.put(oldCenter, movingTile); - for (Point ep : movingTile.getAltPoints()) { - altTiles.put(ep, movingTile); - } - } - - if ("false".equals(System.getProperty("batch.tile.persist", "true"))) { - saveTile(movingTile); - } - } - } - } - } - } } diff --git a/src/main/java/jcs/ui/layout/tiles/TileModel.java b/src/main/java/jcs/ui/layout/tiles/TileModel.java new file mode 100644 index 00000000..b9f59c2a --- /dev/null +++ b/src/main/java/jcs/ui/layout/tiles/TileModel.java @@ -0,0 +1,85 @@ +/* + * Copyright 2025 fransjacobs. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package jcs.ui.layout.tiles; + +import java.awt.event.ActionListener; +import java.io.Serializable; +import javax.swing.event.ChangeListener; +import jcs.entities.BlockBean; + +/** + * + * @author fransjacobs + */ +public interface TileModel extends Serializable { + + boolean isSelected(); + + public void setSelected(boolean selected); + + boolean isScaleImage(); + + public void setScaleImage(boolean scaleImage); + + boolean isShowCenter(); + + public void setShowCenter(boolean showCenter); + + boolean isShowRoute(); + + public void setShowRoute(boolean showRoute); + + boolean isShowBlockState(); + + public void setShowBlockState(boolean showBlockState); + + boolean isShowLocomotiveImage(); + + public void setShowLocomotiveImage(boolean showLocomotiveImage); + + boolean isShowAccessoryValue(); + + public void setShowAccessoryValue(boolean showAccessoryValue); + + boolean isShowSignalValue(); + + public void setShowSignalValue(boolean showSignalValue); + + boolean isSensorActive(); + + public void setSensorActive(boolean active); + + BlockBean.BlockState getBlockState(); + + public void setBlockState(BlockBean.BlockState blockState); + + //boolean isShowOutline(); + //public void setShowOutline(boolean showOutline); + //@Override + //void addItemListener(ItemListener l); + //@Override + //void removeItemListener(ItemListener l); + void addChangeListener(ChangeListener l); + + void removeChangeListener(ChangeListener l); + + void addActionListener(ActionListener l); + + void removeActionListener(ActionListener l); + + ActionListener[] getActionListeners(); + +} diff --git a/src/main/java/jcs/ui/layout/tiles/sandbox/AlphaButtonPolicy.java b/src/main/java/jcs/ui/layout/tiles/sandbox/AlphaButtonPolicy.java new file mode 100755 index 00000000..16e7832a --- /dev/null +++ b/src/main/java/jcs/ui/layout/tiles/sandbox/AlphaButtonPolicy.java @@ -0,0 +1,91 @@ +// AlphaButtonPolicy.java +// A custom focus traversal policy that uses alphabetical ordering of button +// labels to determine "next" and "previous" buttons for keyboard traversal. +// +package jcs.ui.layout.tiles.sandbox; + +import java.awt.*; +import java.util.*; +import javax.swing.*; + +public class AlphaButtonPolicy extends FocusTraversalPolicy { + + private SortedMap getSortedButtons(Container focusCycleRoot) { + if (focusCycleRoot == null) { + throw new IllegalArgumentException("focusCycleRoot can't be null"); + } + SortedMap result = new TreeMap(); // Will sort all buttons by text. + sortRecursive(result, focusCycleRoot); + return result; + } + + private void sortRecursive(Map buttons, Container container) { + for (int i = 0; i < container.getComponentCount(); i++) { + Component c = container.getComponent(i); + if (c instanceof JButton) { // Found another button to sort. + buttons.put(((JButton) c).getText(), c); + } + if (c instanceof Container) { // Found a container to search. + sortRecursive(buttons, (Container) c); + } + } + } + + // The rest of the code implements the FocusTraversalPolicy interface. + public Component getFirstComponent(Container focusCycleRoot) { + SortedMap buttons = getSortedButtons(focusCycleRoot); + if (buttons.isEmpty()) { + return null; + } + return (Component) buttons.get(buttons.firstKey()); + } + + public Component getLastComponent(Container focusCycleRoot) { + SortedMap buttons = getSortedButtons(focusCycleRoot); + if (buttons.isEmpty()) { + return null; + } + return (Component) buttons.get(buttons.lastKey()); + } + + public Component getDefaultComponent(Container focusCycleRoot) { + return getFirstComponent(focusCycleRoot); + } + + public Component getComponentAfter(Container focusCycleRoot, + Component aComponent) { + if (!(aComponent instanceof JButton)) { + return null; + } + SortedMap buttons = getSortedButtons(focusCycleRoot); + // Find all buttons after the current one. + String nextName = ((JButton) aComponent).getText() + "\0"; + SortedMap nextButtons = buttons.tailMap(nextName); + if (nextButtons.isEmpty()) { // Wrapped back to beginning + if (!buttons.isEmpty()) { + return (Component) buttons.get(buttons.firstKey()); + } + return null; // Degenerate case of no buttons. + } + return (Component) nextButtons.get(nextButtons.firstKey()); + } + + public Component getComponentBefore(Container focusCycleRoot, + Component aComponent) { + if (!(aComponent instanceof JButton)) { + return null; + } + + SortedMap buttons = getSortedButtons(focusCycleRoot); + SortedMap prevButtons + = // Find all buttons before this one. + buttons.headMap(((JButton) aComponent).getText()); + if (prevButtons.isEmpty()) { // Wrapped back to end. + if (!buttons.isEmpty()) { + return (Component) buttons.get(buttons.lastKey()); + } + return null; // Degenerate case of no buttons. + } + return (Component) prevButtons.get(prevButtons.lastKey()); + } +} diff --git a/src/main/java/jcs/ui/layout/tiles/sandbox/BasicJogShuttleUI.java b/src/main/java/jcs/ui/layout/tiles/sandbox/BasicJogShuttleUI.java new file mode 100755 index 00000000..77154263 --- /dev/null +++ b/src/main/java/jcs/ui/layout/tiles/sandbox/BasicJogShuttleUI.java @@ -0,0 +1,156 @@ +// BasicJogShuttleUI.java +// A UI class for our custom JogShuttle component. +// +package jcs.ui.layout.tiles.sandbox; + +import java.awt.*; +import java.awt.event.*; + +import javax.swing.*; +import javax.swing.plaf.*; + +public class BasicJogShuttleUI extends JogShuttleUI + implements MouseListener, MouseMotionListener { + + private static final int KNOB_DISPLACEMENT = 3; + private static final int FINGER_SLOT_DISPLACEMENT = 15; + + private double lastAngle; // Used to track mouse drags. + + public static ComponentUI createUI(JComponent c) { + return new BasicJogShuttleUI(); + } + + public void installUI(JComponent c) { + JogShuttle shuttle = (JogShuttle) c; + shuttle.addMouseListener(this); + shuttle.addMouseMotionListener(this); + } + + public void uninstallUI(JComponent c) { + JogShuttle shuttle = (JogShuttle) c; + shuttle.removeMouseListener(this); + shuttle.removeMouseMotionListener(this); + } + + public void paint(Graphics g, JComponent c) { + // We don't want to paint inside the insets or borders. + Insets insets = c.getInsets(); + g.translate(insets.left, insets.top); + int width = c.getWidth() - insets.left - insets.right; + int height = c.getHeight() - insets.top - insets.bottom; + + // Draw the outside circle. + g.setColor(c.getForeground()); + g.fillOval(0, 0, width, height); + + Insets d = ((JogShuttle) c).getDialInsets(); + int value = ((JogShuttle) c).getValue(); + int valuePerRevolution = ((JogShuttle) c).getValuePerRevolution(); + + // Draw the edge of the dial. + g.setColor(Color.darkGray); + g.fillOval(d.left, d.top, width - (d.right * 2), height - (d.bottom * 2)); + + // Draw the inside of the dial. + g.setColor(Color.gray); + g.fillOval(d.left + KNOB_DISPLACEMENT, + d.top + KNOB_DISPLACEMENT, + width - (d.right + d.left) - KNOB_DISPLACEMENT * 2, + height - (d.bottom + d.top) - KNOB_DISPLACEMENT * 2); + + // Draw the finger slot. + drawFingerSlot(g, c, value, width, height, valuePerRevolution, + FINGER_SLOT_DISPLACEMENT - 1, + (double) (width / 2) - d.right - FINGER_SLOT_DISPLACEMENT, + (double) (height / 2) - d.bottom - FINGER_SLOT_DISPLACEMENT); + + g.translate(-insets.left, -insets.top); + } + + private void drawFingerSlot(Graphics g, JComponent c, int value, + int width, int height, int valuePerRevolution, int size, + double xradius, double yradius) { + + int currentPosition = value % valuePerRevolution; + + // Obtain the current angle in radians. + double angle = ((double) currentPosition / valuePerRevolution) + * java.lang.Math.PI * 2; + + // Obtain the X and Y coordinates of the finger slot, with the + // minimum value at twelve o'clock. + angle -= (java.lang.Math.PI / 2); + int xPosition = (int) (xradius * java.lang.Math.sin(angle)); + int yPosition = (int) (yradius * java.lang.Math.cos(angle)); + xPosition = (width / 2) - xPosition; + yPosition = (height / 2) + yPosition; + + // Draw the finger slot with a crescent shadow on the top left. + g.setColor(Color.darkGray); + g.fillOval(xPosition - (size / 2), yPosition - (size / 2), size, size); + g.setColor(Color.lightGray); + g.fillOval(xPosition - (size / 2) + 1, yPosition - (size / 2) + 1, + size - 1, size - 1); + + } + + // Figure out angle at which a mouse event occurred with respect to the + // center of the component for intuitive dial dragging. + protected double calculateAngle(MouseEvent e) { + int x = e.getX() - ((JComponent) e.getSource()).getWidth() / 2; + int y = -e.getY() + ((JComponent) e.getSource()).getHeight() / 2; + if (x == 0) { // Handle case where math would blow up. + if (y == 0) { + return lastAngle; // Can't tell... + } + if (y > 0) { + return Math.PI / 2; + } + return -Math.PI / 2; + } + return Math.atan((double) y / (double) x); + } + + public void mousePressed(MouseEvent e) { + lastAngle = calculateAngle(e); + } + + public void mouseReleased(MouseEvent e) { + } + + public void mouseClicked(MouseEvent e) { + } + + public void mouseEntered(MouseEvent e) { + } + + public void mouseExited(MouseEvent e) { + } + + // Figure out the change in angle over which the user has dragged, + // expressed as a fraction of a revolution. + public double angleDragged(MouseEvent e) { + double newAngle = calculateAngle(e); + double change = (lastAngle - newAngle) / Math.PI; + if (Math.abs(change) > 0.5) { // Handle crossing origin. + if (change < 0.0) { + change += 1.0; + } else { + change -= 1.0; + } + } + + lastAngle = newAngle; + return change; + } + + public void mouseDragged(MouseEvent e) { + JogShuttle theShuttle = (JogShuttle) e.getComponent(); + theShuttle.setValue(theShuttle.getValue() + + (int) (angleDragged(e) * theShuttle.getValuePerRevolution())); + } + + public void mouseMoved(MouseEvent e) { + } +} diff --git a/src/main/java/jcs/ui/layout/tiles/sandbox/FocusExample.java b/src/main/java/jcs/ui/layout/tiles/sandbox/FocusExample.java new file mode 100755 index 00000000..e27171f1 --- /dev/null +++ b/src/main/java/jcs/ui/layout/tiles/sandbox/FocusExample.java @@ -0,0 +1,86 @@ +// FocusExample.java +// An example of focus traversal using the keyboard to navigate through a +// small set of buttons. +// +package jcs.ui.layout.tiles.sandbox; + +import java.awt.*; +import java.awt.event.*; + +import javax.swing.*; + +public class FocusExample extends JFrame { + + public FocusExample() { + + super("Focus Example"); + setDefaultCloseOperation(EXIT_ON_CLOSE); + MyPanel mypanel = new MyPanel(); + + JButton button1 = new JButton("One"); + JButton button2 = new JButton("Two"); + JButton button3 = new JButton("Three"); + JButton button4 = new JButton("Four"); + JButton button5 = new MyButton("Five*"); + JButton button6 = new MyButton("Six*"); + JButton button7 = new JButton("Seven"); + + mypanel.add(button2); + mypanel.add(button3); + + JInternalFrame frame1 = new JInternalFrame("Internal Frame 1", + true, true, true, true); + + frame1.setBackground(Color.lightGray); + frame1.getContentPane().setLayout(new GridLayout(2, 3)); + frame1.setSize(300, 200); + + frame1.getContentPane().add(button1); + frame1.getContentPane().add(mypanel); + frame1.getContentPane().add(button4); + frame1.getContentPane().add(button5); + frame1.getContentPane().add(button6); + frame1.getContentPane().add(button7); + + JDesktopPane desktop = new JDesktopPane(); + desktop.add(frame1, new Integer(1)); + desktop.setOpaque(true); + + // Now set up the user interface window. + Container contentPane = getContentPane(); + contentPane.add(desktop, BorderLayout.CENTER); + setSize(new Dimension(400, 300)); + frame1.setVisible(true); + setVisible(true); + } + + public static void main(String[] args) { + new FocusExample(); + } + + class MyButton extends JButton { + + public MyButton(String s) { + super(s); + } + + public boolean isFocusable() { + return false; + } + } + + class MyPanel extends JPanel { + + public MyPanel() { + super(true); + java.util.Set upKeys = new java.util.HashSet(1); + upKeys.add(AWTKeyStroke.getAWTKeyStroke(KeyEvent.VK_UP, 0)); + setFocusTraversalKeys(KeyboardFocusManager.UP_CYCLE_TRAVERSAL_KEYS, + upKeys); + } + + public boolean isFocusCycleRoot() { + return true; + } + } +} diff --git a/src/main/java/jcs/ui/layout/tiles/sandbox/FocusTraversalExample.java b/src/main/java/jcs/ui/layout/tiles/sandbox/FocusTraversalExample.java new file mode 100755 index 00000000..39fdbec1 --- /dev/null +++ b/src/main/java/jcs/ui/layout/tiles/sandbox/FocusTraversalExample.java @@ -0,0 +1,38 @@ +//FocusTraversalExample.java +// Similar to the FocusExample, this class uses the custom AlphaButtonPolicy +// focus traversal policy to navigate another small set of buttons. +// +package jcs.ui.layout.tiles.sandbox; + +import java.awt.*; +import javax.swing.*; + +public class FocusTraversalExample extends JPanel { + + public FocusTraversalExample() { + setLayout(new GridLayout(6, 1)); + JButton button1 = new JButton("Texas"); + JButton button2 = new JButton("Vermont"); + JButton button3 = new JButton("Florida"); + JButton button4 = new JButton("Alabama"); + JButton button5 = new JButton("Minnesota"); + JButton button6 = new JButton("California"); + + setBackground(Color.lightGray); + add(button1); + add(button2); + add(button3); + add(button4); + add(button5); + add(button6); + } + + public static void main(String[] args) { + JFrame frame = new JFrame("Alphabetized Button Focus Traversal"); + frame.setFocusTraversalPolicy(new AlphaButtonPolicy()); + frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + frame.setContentPane(new FocusTraversalExample()); + frame.setSize(400, 300); + frame.setVisible(true); + } +} diff --git a/src/main/java/jcs/ui/layout/tiles/sandbox/InvokeExample.java b/src/main/java/jcs/ui/layout/tiles/sandbox/InvokeExample.java new file mode 100755 index 00000000..2f4815c2 --- /dev/null +++ b/src/main/java/jcs/ui/layout/tiles/sandbox/InvokeExample.java @@ -0,0 +1,115 @@ +// InvokeExample.java +// This class demonstrates several examples of how to handle long-running +// tasks (such as querying a remote resource). Some of the examples are +// good, some are not! +// + +package jcs.ui.layout.tiles.sandbox; + +import javax.swing.*; +import java.awt.*; +import java.awt.event.*; + +public class InvokeExample { + private static JButton good = new JButton("Good"); + private static JButton bad = new JButton("Bad"); + private static JButton bad2 = new JButton("Bad2"); + private static JLabel resultLabel = new JLabel("Ready", JLabel.CENTER); + + public static void main(String[] args) { + JFrame f = new JFrame(); + f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + + // Layout . . . + JPanel p = new JPanel(); + p.setOpaque(true); + p.setLayout(new FlowLayout()); + p.add(good); + p.add(bad); + p.add(bad2); + + Container c = f.getContentPane(); + c.setLayout(new BorderLayout()); + c.add(p, BorderLayout.CENTER); + c.add(resultLabel, BorderLayout.SOUTH); + + // Listeners + good.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent ev) { + resultLabel.setText("Working . . ."); + setEnabled(false); + + // We're going to do something that takes a long time, so we + // spin off a thread and update the display when we're done. + Thread worker = new Thread() { + public void run() { + // Something that takes a long time . . . in real life, this + // might be a DB query, remote method invocation, etc. + try { + Thread.sleep(5000); + } + catch (InterruptedException ex) {} + + // Report the result using invokeLater(). + SwingUtilities.invokeLater(new Runnable() { + public void run() { + resultLabel.setText("Ready"); + setEnabled(true); + } + }); + } + }; + + worker.start(); // So we don't hold up the dispatch thread. + } + }); + + bad.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent ev) { + resultLabel.setText("Working . . ."); + setEnabled(false); + + // We're going to do the same thing, but not in a separate thread. + try { + Thread.sleep(5000); // Dispatch thread is starving! + } + catch (InterruptedException ex) {} + + // Report the result. + resultLabel.setText("Ready"); + setEnabled(true); + } + }); + + bad2.addActionListener(new ActionListener() { + public void actionPerformed(ActionEvent ev) { + resultLabel.setText("Working . . . "); + setEnabled(false); + + // The wrong way to use invokeLater(). The runnable() shouldn't + // starve the dispatch thread. + SwingUtilities.invokeLater(new Runnable() { + public void run() { + try { + Thread.sleep(5000); // Dispatch thread is starving! + } + catch (InterruptedException ex) {} + + resultLabel.setText("Ready"); + setEnabled(true); + } + }); + } + }); + + f.setSize(300, 100); + f.setVisible(true); + } + + // Allows us to turn the buttons on or off while we work. + static void setEnabled(boolean b) { + good.setEnabled(b); + bad.setEnabled(b); + bad2.setEnabled(b); + } +} diff --git a/src/main/java/jcs/ui/layout/tiles/sandbox/JogShuttle.java b/src/main/java/jcs/ui/layout/tiles/sandbox/JogShuttle.java new file mode 100755 index 00000000..d39366fb --- /dev/null +++ b/src/main/java/jcs/ui/layout/tiles/sandbox/JogShuttle.java @@ -0,0 +1,154 @@ +// JogShuttle.java +// A custom jog shuttle component. (Some VCRs have such a thing for doing +// variable speed fast-forward and fast-reverse.) An example of using the +// JogShuttle can be found in Sketch.java. +// +package jcs.ui.layout.tiles.sandbox; + +import java.awt.*; + +import javax.swing.*; +import javax.swing.event.*; + +public class JogShuttle extends JComponent implements ChangeListener { + + private BoundedRangeModel model; + + // The dialInsets property tells how far the dial is inset + // from the sunken border. + private Insets dialInsets = new Insets(3, 3, 3, 3); + + // The valuePerRevolution property tells how many units the dial + // takes to make a complete revolution. + private int valuePerRevolution; + + // Constructors + public JogShuttle() { + init(new DefaultBoundedRangeModel()); + } + + public JogShuttle(BoundedRangeModel m) { + init(m); + } + + public JogShuttle(int min, int max, int value) { + init(new DefaultBoundedRangeModel(value, 1, min, max)); + } + + protected void init(BoundedRangeModel m) { + setModel(m); + valuePerRevolution = m.getMaximum() - m.getMinimum(); + setMinimumSize(new Dimension(80, 80)); + setPreferredSize(new Dimension(80, 80)); + updateUI(); + } + + public void setUI(JogShuttleUI ui) { + super.setUI(ui); + } + + public void updateUI() { + setUI((JogShuttleUI) UIManager.getUI(this)); + invalidate(); + } + + public String getUIClassID() { + return JogShuttleUI.UI_CLASS_ID; + } + + public void setModel(BoundedRangeModel m) { + BoundedRangeModel old = model; + if (old != null) { + old.removeChangeListener(this); + } + + if (m == null) { + model = new DefaultBoundedRangeModel(); + } else { + model = m; + } + model.addChangeListener(this); + + firePropertyChange("model", old, model); + } + + public BoundedRangeModel getModel() { + return model; + } + + // Methods + public void resetToMinimum() { + model.setValue(model.getMinimum()); + } + + public void resetToMaximum() { + model.setValue(model.getMaximum()); + } + + public void stateChanged(ChangeEvent e) { + repaint(); + } + + // Accessors and mutators + public int getMinimum() { + return model.getMinimum(); + } + + public void setMinimum(int m) { + int old = getMinimum(); + if (m != old) { + model.setMinimum(m); + firePropertyChange("minimum", old, m); + } + } + + public int getMaximum() { + return model.getMaximum(); + } + + public void setMaximum(int m) { + int old = getMaximum(); + if (m != old) { + model.setMaximum(m); + firePropertyChange("maximum", old, m); + } + } + + public int getValue() { + return model.getValue(); + } + + public void setValue(int v) { + int old = getValue(); + if (v != old) { + model.setValue(v); + firePropertyChange("value", old, v); + } + } + + // Display-specific properties + public int getValuePerRevolution() { + return valuePerRevolution; + } + + public void setValuePerRevolution(int v) { + int old = getValuePerRevolution(); + if (v != old) { + valuePerRevolution = v; + firePropertyChange("valuePerRevolution", old, v); + } + repaint(); + } + + public void setDialInsets(Insets i) { + dialInsets = i; + } + + public void setDialInsets(int top, int left, int bottom, int right) { + dialInsets = new Insets(top, left, bottom, right); + } + + public Insets getDialInsets() { + return dialInsets; + } +} diff --git a/src/main/java/jcs/ui/layout/tiles/sandbox/JogShuttleUI.java b/src/main/java/jcs/ui/layout/tiles/sandbox/JogShuttleUI.java new file mode 100755 index 00000000..790e0ae7 --- /dev/null +++ b/src/main/java/jcs/ui/layout/tiles/sandbox/JogShuttleUI.java @@ -0,0 +1,11 @@ +// JogShuttleUI.java +// Fill out the proper UIClassID information for our JogShuttle. +// + +package jcs.ui.layout.tiles.sandbox; + +import javax.swing.plaf.*; + +public abstract class JogShuttleUI extends ComponentUI { + public static final String UI_CLASS_ID = "JogShuttleUI"; +} diff --git a/src/main/java/jcs/ui/layout/tiles/sandbox/SimpleModel.java b/src/main/java/jcs/ui/layout/tiles/sandbox/SimpleModel.java new file mode 100755 index 00000000..bcbbbea9 --- /dev/null +++ b/src/main/java/jcs/ui/layout/tiles/sandbox/SimpleModel.java @@ -0,0 +1,84 @@ +// SimpleModel.java +// An example of a custom data model that could be used in any MVC +// scenario. +// +package jcs.ui.layout.tiles.sandbox; + +import javax.swing.event.*; + +public class SimpleModel implements SimpleModelInterface { + + protected transient ChangeEvent changeEvent = null; + protected EventListenerList listenerList = new EventListenerList(); + + private int value = 0; + private boolean activated = false; + + public SimpleModel() { + } + + public SimpleModel(int v) { + value = v; + } + + public SimpleModel(boolean b) { + activated = b; + } + + public SimpleModel(int v, boolean b) { + value = v; + activated = b; + } + + public int getValue() { + return value; + } + + public synchronized void setValue(int v) { + if (v != value) { + value = v; + fireChange(); + } + } + + public boolean isActivated() { + return activated; + } + + public synchronized void setActivated(boolean b) { + if (b != activated) { + activated = b; + fireChange(); + } + } + + public void addChangeListener(ChangeListener l) { + listenerList.add(ChangeListener.class, l); + } + + public void removeChangeListener(ChangeListener l) { + listenerList.remove(ChangeListener.class, l); + } + + public ChangeListener[] getChangeListeners() { + return (ChangeListener[]) listenerList.getListeners(ChangeListener.class); + } + + protected void fireChange() { + Object[] listeners = listenerList.getListenerList(); + for (int i = listeners.length - 2; i >= 0; i -= 2) { + if (listeners[i] == ChangeListener.class) { + if (changeEvent == null) { + changeEvent = new ChangeEvent(this); + } + ((ChangeListener) listeners[i + 1]).stateChanged(changeEvent); + } + } + } + + public String toString() { + String modelString = "value=" + getValue() + ", " + + "activated=" + isActivated(); + return getClass().getName() + "[" + modelString + "]"; + } +} diff --git a/src/main/java/jcs/ui/layout/tiles/sandbox/SimpleModelInterface.java b/src/main/java/jcs/ui/layout/tiles/sandbox/SimpleModelInterface.java new file mode 100755 index 00000000..1d24c7f0 --- /dev/null +++ b/src/main/java/jcs/ui/layout/tiles/sandbox/SimpleModelInterface.java @@ -0,0 +1,24 @@ +// SimpleModelInteface.java +// An example of a data model interface that could be used in any MVC +// scenario. This interface is implemented in the SimpleModel class. +// +package jcs.ui.layout.tiles.sandbox; + +import javax.swing.event.*; + +public interface SimpleModelInterface { + + public int getValue(); + + public void setValue(int v); + + public boolean isActivated(); + + public void setActivated(boolean b); + + public void addChangeListener(ChangeListener l); + + public void removeChangeListener(ChangeListener l); + + public ChangeListener[] getChangeListeners(); +} diff --git a/src/main/java/jcs/ui/layout/tiles/sandbox/Sketch.java b/src/main/java/jcs/ui/layout/tiles/sandbox/Sketch.java new file mode 100755 index 00000000..a8d4e2f7 --- /dev/null +++ b/src/main/java/jcs/ui/layout/tiles/sandbox/Sketch.java @@ -0,0 +1,85 @@ +// Sketch.java +// A sketching application with two dials: one for horizontal movement, one +// for vertical movement. The dials are instances of the JogShuttle class. +// +package jcs.ui.layout.tiles.sandbox; + +import java.awt.*; +import java.awt.event.*; +import java.beans.*; + +import javax.swing.*; +import javax.swing.border.*; + +public class Sketch extends JPanel + implements PropertyChangeListener, ActionListener { + + JogShuttle shuttle1; + JogShuttle shuttle2; + JPanel board; + JButton clear; + + int lastX, lastY; // Keep track of the last point we drew. + + public Sketch() { + super(true); + + setLayout(new BorderLayout()); + board = new JPanel(true); + board.setPreferredSize(new Dimension(300, 300)); + board.setBorder(new LineBorder(Color.black, 5)); + + clear = new JButton("Clear Drawing Area"); + clear.addActionListener(this); + + shuttle1 = new JogShuttle(0, 300, 150); + lastX = shuttle1.getValue(); + shuttle2 = new JogShuttle(0, 300, 150); + lastY = shuttle2.getValue(); + + shuttle1.setValuePerRevolution(100); + shuttle2.setValuePerRevolution(100); + + shuttle1.addPropertyChangeListener(this); + shuttle2.addPropertyChangeListener(this); + + shuttle1.setBorder(new BevelBorder(BevelBorder.RAISED)); + shuttle2.setBorder(new BevelBorder(BevelBorder.RAISED)); + + add(board, BorderLayout.NORTH); + add(shuttle1, BorderLayout.WEST); + add(clear, BorderLayout.CENTER); + add(shuttle2, BorderLayout.EAST); + } + + public void propertyChange(PropertyChangeEvent e) { + if (e.getPropertyName() == "value") { + Graphics g = board.getGraphics(); + g.setColor(getForeground()); + g.drawLine(lastX, lastY, + shuttle1.getValue(), shuttle2.getValue()); + lastX = shuttle1.getValue(); + lastY = shuttle2.getValue(); + } + } + + public void actionPerformed(ActionEvent e) { + // The button must have been pressed. + Insets insets = board.getInsets(); + Graphics g = board.getGraphics(); + g.setColor(board.getBackground()); + g.fillRect(insets.left, insets.top, + board.getWidth() - insets.left - insets.right, + board.getHeight() - insets.top - insets.bottom); + } + + public static void main(String[] args) { + UIManager.put(JogShuttleUI.UI_CLASS_ID, "BasicJogShuttleUI"); + Sketch s = new Sketch(); + JFrame frame = new JFrame("Sample Sketch Application"); + frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + frame.setContentPane(s); + frame.pack(); + frame.setVisible(true); + } +} diff --git a/src/test/java/jcs/ui/layout/tiles/BlockTileTester.form b/src/test/java/jcs/ui/layout/tiles/BlockTileTester.form new file mode 100644 index 00000000..cf9a0f6c --- /dev/null +++ b/src/test/java/jcs/ui/layout/tiles/BlockTileTester.form @@ -0,0 +1,220 @@ + + +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/test/java/jcs/ui/layout/tiles/BlockTileTester.java b/src/test/java/jcs/ui/layout/tiles/BlockTileTester.java index 9b4323d3..7b7d4a8f 100644 --- a/src/test/java/jcs/ui/layout/tiles/BlockTileTester.java +++ b/src/test/java/jcs/ui/layout/tiles/BlockTileTester.java @@ -1,5 +1,5 @@ /* - * Copyright 2023 Frans Jacobs. + * Copyright 2025 Frans Jacobs. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -17,155 +17,302 @@ import java.awt.Color; import java.awt.Dimension; -import java.awt.Graphics; -import java.awt.Graphics2D; import java.awt.Image; import java.awt.Toolkit; import java.io.File; -import java.io.IOException; -import javax.imageio.ImageIO; +import java.util.Arrays; +import java.util.List; import javax.swing.JFrame; import javax.swing.UIManager; import javax.swing.UnsupportedLookAndFeelException; import jcs.entities.BlockBean; +import jcs.entities.BlockBean.BlockState; import jcs.entities.LocomotiveBean; -import jcs.entities.TileBean.Orientation; +import jcs.entities.TileBean; +import jcs.ui.util.ImageUtil; import org.tinylog.Logger; -/** - * @author Frans Jacobs - */ -public class BlockTileTester extends JFrame { +public class BlockTileTester extends javax.swing.JFrame { + + private Tile blockEast; + private Tile blockSouth; + private Tile blockWest; + private Tile blockNorth; - private final Tile tileEast; - private final Tile tileSouth; - private final Tile tileWest; - private final Tile tileNorth; + private final List blockStates = Arrays.stream(BlockState.values()).toList(); + private int blockStateIndex = 0; - @SuppressWarnings("OverridableMethodCallInConstructor") + /** + * Creates new form TileTester + * + * @param title + */ public BlockTileTester(String title) { super(title); + initComponents(); + eastStateBtn.setText(this.blockStates.get(1).getState()); + createTiles(); + this.setVisible(true); + } - //LocomotiveBean lok1 = new LocomotiveBean(2L, "BR 81 002", 2L, 2, "DB BR 81 008", "mm_prg", 120, 1, 0, 0, false, true); - LocomotiveBean lok2 = new LocomotiveBean(12L, "BR 141 015-08", 12L, 12, "DB BR 141 136-2", "mm_prg", 120, 0, 0, 2, false, true); - - LocomotiveBean lok1 = new LocomotiveBean(8L, "NS DHG 6505", 8L, 8, "", "dcc", 100, 0, 0, 1, true, true); + private void createTiles() { - String imgPath = System.getProperty("user.home") + File.separator + "jcs" + File.separator + "cache" + File.separator + "dcc-ex" + File.separator + "ns dhg 6505.png"; - lok1.setIcon(imgPath); + blockEast = new Block(TileBean.Orientation.EAST, 200, 40); + blockEast.setId("east"); + blockEast.setBlockState(blockStates.get(blockStateIndex)); + //blockEast.setBlockBean(createBlockBean(blockEast)); + blockEast.setTrackRouteColor(Color.MAGENTA); - Image locImage = readImage(imgPath); - lok1.setLocIcon(locImage); + blockSouth = new Block(TileBean.Orientation.SOUTH, 360, 80); + blockSouth.setId("south"); + blockSouth.setBlockState(blockStates.get(blockStateIndex+1)); - tileEast = new Block(Orientation.EAST, 70, 190); - tileEast.setId("bk-1"); + blockSouth.setTrackRouteColor(Color.YELLOW); - BlockBean bbe = new BlockBean(); - bbe.setId(tileEast.getId()); - bbe.setTileId(tileEast.getId()); - //lok1.setDirection(LocomotiveBean.Direction.FORWARDS); - bbe.setLocomotive(lok1); - bbe.setDescription(tileEast.getId()); - //bbe.setReverseArrival(true); - ((Block) tileEast).setBlockBean(bbe); + blockWest = new Block(TileBean.Orientation.WEST, 200, 120); + blockWest.setId("west"); + blockSouth.setBlockState(blockStates.get(blockStateIndex+1)); + blockWest.setTrackRouteColor(Color.CYAN); - // - tileSouth = new Block(Orientation.SOUTH, 160, 190); - tileSouth.setId("bk-2"); - - BlockBean bbs = new BlockBean(); - bbs.setId(tileSouth.getId()); - bbs.setTileId(tileSouth.getId()); - bbs.setDescription(tileSouth.getId()); - //lok1.setDirection(LocomotiveBean.Direction.BACKWARDS); - bbs.setLocomotive(lok1); - //bbs.setReverseArrival(true); - ((Block) tileSouth).setBlockBean(bbs); - - tileWest = new Block(Orientation.WEST, 250, 190); - tileWest.setId("bk-3"); - BlockBean bbw = new BlockBean(); - bbw.setId(tileWest.getId()); - bbw.setTileId(tileWest.getId()); - //lok1.setDirection(LocomotiveBean.Direction.FORWARDS); - bbw.setLocomotive(lok1); - bbw.setDescription(tileWest.getId()); - //bbw.setReverseArrival(true); - ((Block) tileWest).setBlockBean(bbw); - - tileNorth = new Block(Orientation.NORTH, 340, 190); - tileNorth.setId("bk-4"); - BlockBean bbn = new BlockBean(); - bbn.setId(tileNorth.getId()); - bbn.setTileId(tileNorth.getId()); - lok1.setDirection(LocomotiveBean.Direction.BACKWARDS); - bbn.setLocomotive(lok1); - //bbn.setReverseArrival(true); - ((Block) tileNorth).setBlockBean(bbn); + blockNorth = new Block(TileBean.Orientation.NORTH, 40, 80); + blockNorth.setId("north"); + blockSouth.setBlockState(blockStates.get(blockStateIndex+1)); + blockNorth.setTrackRouteColor(Color.blue); + + dotGridCanvas.add(blockEast); + + dotGridCanvas.add(blockSouth); + dotGridCanvas.add(blockWest); + dotGridCanvas.add(blockNorth); + } + + private BlockBean createBlockBean(Tile tile) { + BlockBean blockBean = new BlockBean(); + blockBean.setId(tile.getId()); + blockBean.setTileId(tile.getId()); + blockBean.setDescription("Block-" + tile.getOrientation().getOrientation().toLowerCase()); + blockBean.setDepartureSuffix(null); + + blockBean.setBlockState(blockStates.get(blockStateIndex)); + +// if (this.showLocCB.isSelected()) { +// bbe.setLocomotive(createLocomotiveBean()); +// } else { +// bbe.setLocomotive(null); +// } + return blockBean; + } + + private LocomotiveBean createLocomotiveBean() { -// Logger.trace("East: "+ ((Block)tileEast).getLocomotiveBlockSuffix()); -// Logger.trace("West: "+ ((Block)tileWest).getLocomotiveBlockSuffix()); -// Logger.trace("North: "+ ((Block)tileNorth).getLocomotiveBlockSuffix()); -// Logger.trace("South: "+ ((Block)tileSouth).getLocomotiveBlockSuffix()); + // LocomotiveBean lok2 = new LocomotiveBean(12L, "BR 141 015-08", 12L, 12, "DB BR 141 136-2", "mm_prg", 120, 0, 0, 2, false, true); + // LocomotiveBean lok1 = new LocomotiveBean(8L, "NS DHG 6505", 8L, 8, "", "dcc", 100, 0, 0, 1, true, true); + + //String imgPath = System.getProperty("user.home") + File.separator + "jcs" + File.separator + "cache" + File.separator + "dcc-ex" + File.separator + "ns dhg 6505.png"; + //lok1.setIcon(imgPath); + + //Image locImage = readImage(imgPath); + //lok1.setLocIcon(locImage); + + //activateEastSensorBtn.setIcon(new javax.swing.ImageIcon(getClass().getResource("/images/DHG 6505.png"))); // NOI18N + LocomotiveBean lb = new LocomotiveBean(8L, "NS DHG 6505", 8L, 8, "", "dcc", 100, 0, 0, 1, true, true); + String imgPath = System.getProperty("user.home") + File.separator + "jcs" + File.separator + "images" + File.separator + "DHG 6505.png"; + lb.setIcon(imgPath); + Image locImage = ImageUtil.readImage(imgPath); + //Image is sized by default so + locImage = ImageUtil.scaleImage(locImage, 100); + lb.setLocIcon(locImage); + +// if (this.backwardsRB.isSelected()) { +// lb.setDirection(LocomotiveBean.Direction.BACKWARDS); +// } else { +// lb.setDirection(LocomotiveBean.Direction.FORWARDS); +// } + return lb; } - @Override - public void paint(Graphics g) { - Graphics2D g2d = (Graphics2D) g; + /** + * This method is called from within the constructor to initialize the form. WARNING: Do NOT modify this code. The content of this method is always regenerated by the Form Editor. + */ + @SuppressWarnings("unchecked") + // //GEN-BEGIN:initComponents + private void initComponents() { - tileEast.drawTile(g2d, true); - tileEast.drawBounds(g2d); - tileEast.drawCenterPoint(g2d, Color.red); + toolbarPanel = new javax.swing.JPanel(); + toolBar = new javax.swing.JToolBar(); + eastStateBtn = new javax.swing.JButton(); + eastTileBtn = new javax.swing.JToggleButton(); + southTileBtn = new javax.swing.JToggleButton(); + westTileBtn = new javax.swing.JToggleButton(); + northTileBtn = new javax.swing.JToggleButton(); + selectSouthTileBtn = new javax.swing.JToggleButton(); + drawCenterBtn = new javax.swing.JToggleButton(); + activateEastSensorBtn = new javax.swing.JToggleButton(); + dotGridCanvas = new jcs.ui.layout.tiles.DotGridCanvas(); - tileSouth.drawTile(g2d, false); - tileSouth.drawBounds(g2d); - tileSouth.drawCenterPoint(g2d, Color.blue); + setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE); - tileWest.drawTile(g2d, false); - tileWest.drawBounds(g2d); - tileWest.drawCenterPoint(g2d, Color.red); + java.awt.FlowLayout flowLayout1 = new java.awt.FlowLayout(java.awt.FlowLayout.LEFT); + flowLayout1.setAlignOnBaseline(true); + toolbarPanel.setLayout(flowLayout1); - tileNorth.drawTile(g2d, true); - tileNorth.drawBounds(g2d); - tileNorth.drawCenterPoint(g2d, Color.cyan); - } - - public static Image readImage(String path) { - Image image = null; - //path = System.getProperty("user.home") + File.separator + "jcs" + File.separator + "cache" + File.separator + shortName + File.separator; - - File imgFile; - if (path.contains(".")) { - imgFile = new File(path); - } else { - imgFile = new File(path); - } + toolBar.setRollover(true); + + eastStateBtn.setText("State"); + eastStateBtn.setFocusable(false); + eastStateBtn.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER); + eastStateBtn.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); + eastStateBtn.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + eastStateBtnActionPerformed(evt); + } + }); + toolBar.add(eastStateBtn); + + eastTileBtn.setText("East"); + eastTileBtn.setToolTipText(""); + eastTileBtn.setFocusable(false); + eastTileBtn.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER); + eastTileBtn.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); + eastTileBtn.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + eastTileBtnActionPerformed(evt); + } + }); + toolBar.add(eastTileBtn); + + southTileBtn.setText("South"); + southTileBtn.setFocusable(false); + southTileBtn.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER); + southTileBtn.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); + southTileBtn.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + southTileBtnActionPerformed(evt); + } + }); + toolBar.add(southTileBtn); + + westTileBtn.setText("West"); + westTileBtn.setFocusable(false); + westTileBtn.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER); + westTileBtn.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); + westTileBtn.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + westTileBtnActionPerformed(evt); + } + }); + toolBar.add(westTileBtn); - if (imgFile.exists()) { - try { - image = ImageIO.read(imgFile); + northTileBtn.setText("North"); + northTileBtn.setFocusable(false); + northTileBtn.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER); + northTileBtn.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); + northTileBtn.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + northTileBtnActionPerformed(evt); + } + }); + toolBar.add(northTileBtn); - //Image is sized by default so - if (image != null) { - int size = 100; - float aspect = (float) image.getHeight(null) / (float) image.getWidth(null); - image = image.getScaledInstance(size, (int) (size * aspect), Image.SCALE_SMOOTH); - } + selectSouthTileBtn.setText("Select Tile"); + selectSouthTileBtn.setFocusable(false); + selectSouthTileBtn.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER); + selectSouthTileBtn.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); + selectSouthTileBtn.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + selectSouthTileBtnActionPerformed(evt); + } + }); + toolBar.add(selectSouthTileBtn); - } catch (IOException e) { - Logger.trace("Image file " + path + " does not exists"); + drawCenterBtn.setText("show Center"); + drawCenterBtn.setFocusable(false); + drawCenterBtn.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER); + drawCenterBtn.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); + drawCenterBtn.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + drawCenterBtnActionPerformed(evt); } + }); + toolBar.add(drawCenterBtn); + + activateEastSensorBtn.setText("Icon"); + activateEastSensorBtn.setFocusable(false); + activateEastSensorBtn.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER); + activateEastSensorBtn.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); + activateEastSensorBtn.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + activateEastSensorBtnActionPerformed(evt); + } + }); + toolBar.add(activateEastSensorBtn); + + toolbarPanel.add(toolBar); + + getContentPane().add(toolbarPanel, java.awt.BorderLayout.NORTH); + + dotGridCanvas.setPreferredSize(new java.awt.Dimension(360, 280)); + getContentPane().add(dotGridCanvas, java.awt.BorderLayout.CENTER); + + pack(); + }// //GEN-END:initComponents + + private void northTileBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_northTileBtnActionPerformed + Logger.trace(blockNorth.id + "..."); + blockNorth.setDrawRoute(this.northTileBtn.isSelected()); + }//GEN-LAST:event_northTileBtnActionPerformed + + private void eastTileBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_eastTileBtnActionPerformed + blockEast.setDrawRoute(this.eastTileBtn.isSelected()); + }//GEN-LAST:event_eastTileBtnActionPerformed + + private void westTileBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_westTileBtnActionPerformed + blockWest.setDrawRoute(this.westTileBtn.isSelected()); + }//GEN-LAST:event_westTileBtnActionPerformed + + private void southTileBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_southTileBtnActionPerformed + blockSouth.setDrawRoute(this.southTileBtn.isSelected()); + }//GEN-LAST:event_southTileBtnActionPerformed + + private void selectSouthTileBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_selectSouthTileBtnActionPerformed + blockSouth.setSelected(this.selectSouthTileBtn.isSelected()); + }//GEN-LAST:event_selectSouthTileBtnActionPerformed + + private void drawCenterBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_drawCenterBtnActionPerformed + blockEast.setDrawCenterPoint(this.drawCenterBtn.isSelected()); + blockSouth.setDrawCenterPoint(this.drawCenterBtn.isSelected()); + }//GEN-LAST:event_drawCenterBtnActionPerformed + + private void activateEastSensorBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_activateEastSensorBtnActionPerformed + blockEast.setActive(this.activateEastSensorBtn.isSelected()); + }//GEN-LAST:event_activateEastSensorBtnActionPerformed + + private void eastStateBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_eastStateBtnActionPerformed + if (blockStateIndex + 1 < blockStates.size()) { + blockStateIndex++; + } else { + blockStateIndex = 0; } - return image; - } - - + //Logger.trace("BlockStates: " + this.blockStates.size() + " index: " + this.blockStateIndex); + this.blockEast.setBlockState(this.blockStates.get(blockStateIndex)); + if (blockStateIndex + 1 < blockStates.size()) { + this.eastStateBtn.setText(this.blockStates.get(blockStateIndex + 1).getState()); + } else { + this.eastStateBtn.setText(this.blockStates.get(0).getState()); + } + }//GEN-LAST:event_eastStateBtnActionPerformed + + /** + * @param args the command line arguments + */ public static void main(String args[]) { try { UIManager.setLookAndFeel("com.formdev.flatlaf.FlatLightLaf"); + BlockTileTester.setDefaultLookAndFeelDecorated(true); + } catch (ClassNotFoundException | InstantiationException | IllegalAccessException @@ -173,15 +320,27 @@ public static void main(String args[]) { Logger.error(ex); } - BlockTileTester app = new BlockTileTester("Block Tile Tester"); - - Dimension dim = Toolkit.getDefaultToolkit().getScreenSize(); - app.setSize(370, 300); - app.setLocation( - dim.width / 2 - app.getSize().width / 2, dim.height / 2 - app.getSize().height / 2); - - app.setVisible(true); - - app.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + /* Create and display the form */ + java.awt.EventQueue.invokeLater(() -> { + BlockTileTester app = new BlockTileTester("Sensor Tile Tester"); + app.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + Dimension dim = Toolkit.getDefaultToolkit().getScreenSize(); + app.setLocation(dim.width / 2 - app.getSize().width / 2, dim.height / 2 - app.getSize().height / 2); + app.pack(); + }); } + + // Variables declaration - do not modify//GEN-BEGIN:variables + private javax.swing.JToggleButton activateEastSensorBtn; + private jcs.ui.layout.tiles.DotGridCanvas dotGridCanvas; + private javax.swing.JToggleButton drawCenterBtn; + private javax.swing.JButton eastStateBtn; + private javax.swing.JToggleButton eastTileBtn; + private javax.swing.JToggleButton northTileBtn; + private javax.swing.JToggleButton selectSouthTileBtn; + private javax.swing.JToggleButton southTileBtn; + private javax.swing.JToolBar toolBar; + private javax.swing.JPanel toolbarPanel; + private javax.swing.JToggleButton westTileBtn; + // End of variables declaration//GEN-END:variables } diff --git a/src/test/java/jcs/ui/layout/tiles/CrossTileTester.java b/src/test/java/jcs/ui/layout/tiles/CrossTileTester.java index fc62c582..3173bd54 100644 --- a/src/test/java/jcs/ui/layout/tiles/CrossTileTester.java +++ b/src/test/java/jcs/ui/layout/tiles/CrossTileTester.java @@ -61,41 +61,41 @@ public CrossTileTester(String title) { public void paint(Graphics g) { Graphics2D g2d = (Graphics2D) g; - switchEastR.drawTile(g2d, true); - switchEastR.drawBounds(g2d); +// switchEastR.drawTile(g2d, true); +// switchEastR.drawBounds(g2d); switchEastR.drawCenterPoint(g2d, Color.red); - ((Switch) switchEastR).setValue(AccessoryValue.RED); + ((Switch) switchEastR).setAccessoryValue(AccessoryValue.RED); - switchSouthR.drawTile(g2d, false); - switchSouthR.drawBounds(g2d); +// switchSouthR.drawTile(g2d, false); +// switchSouthR.drawBounds(g2d); switchSouthR.drawCenterPoint(g2d, Color.blue); - switchWestR.drawTile(g2d, true); - switchWestR.drawBounds(g2d); +// switchWestR.drawTile(g2d, true); +// switchWestR.drawBounds(g2d); switchWestR.drawCenterPoint(g2d, Color.red); - ((Switch) switchWestR).setValue(AccessoryValue.GREEN); + ((Switch) switchWestR).setAccessoryValue(AccessoryValue.GREEN); - switchNorthR.drawTile(g2d, false); - switchNorthR.drawBounds(g2d); +// switchNorthR.drawTile(g2d, false); +// switchNorthR.drawBounds(g2d); switchNorthR.drawCenterPoint(g2d, Color.cyan); // - switchEastL.drawTile(g2d, false); - switchEastL.drawBounds(g2d); +// switchEastL.drawTile(g2d, false); +// switchEastL.drawBounds(g2d); switchEastL.drawCenterPoint(g2d, Color.red); - switchSouthL.drawTile(g2d, true); - switchSouthL.drawBounds(g2d); +// switchSouthL.drawTile(g2d, true); +// switchSouthL.drawBounds(g2d); switchSouthL.drawCenterPoint(g2d, Color.blue); - ((Switch) switchSouthL).setValue(AccessoryValue.GREEN); + ((Switch) switchSouthL).setAccessoryValue(AccessoryValue.GREEN); - switchWestL.drawTile(g2d, false); - switchWestL.drawBounds(g2d); +// switchWestL.drawTile(g2d, false); +// switchWestL.drawBounds(g2d); switchWestL.drawCenterPoint(g2d, Color.red); - switchNorthL.drawTile(g2d, true); - switchNorthL.drawBounds(g2d); +// switchNorthL.drawTile(g2d, true); +// switchNorthL.drawBounds(g2d); switchNorthL.drawCenterPoint(g2d, Color.cyan); - ((Switch) switchNorthL).setValue(AccessoryValue.RED); + ((Switch) switchNorthL).setAccessoryValue(AccessoryValue.RED); } diff --git a/src/test/java/jcs/ui/layout/tiles/CrossingTileTester.form b/src/test/java/jcs/ui/layout/tiles/CrossingTileTester.form new file mode 100644 index 00000000..eade3117 --- /dev/null +++ b/src/test/java/jcs/ui/layout/tiles/CrossingTileTester.form @@ -0,0 +1,197 @@ + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/test/java/jcs/ui/layout/tiles/CrossingTileTester.java b/src/test/java/jcs/ui/layout/tiles/CrossingTileTester.java index 108c2c65..04773a8d 100644 --- a/src/test/java/jcs/ui/layout/tiles/CrossingTileTester.java +++ b/src/test/java/jcs/ui/layout/tiles/CrossingTileTester.java @@ -1,5 +1,5 @@ /* - * Copyright 2023 Frans Jacobs. + * Copyright 2025 fransjacobs. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -17,76 +17,225 @@ import java.awt.Color; import java.awt.Dimension; -import java.awt.Graphics; -import java.awt.Graphics2D; import java.awt.Toolkit; import javax.swing.JFrame; import javax.swing.UIManager; import javax.swing.UnsupportedLookAndFeelException; -import jcs.entities.TileBean.Orientation; +import jcs.entities.TileBean; import org.tinylog.Logger; /** - * @author Frans Jacobs + * + * @author fransjacobs */ -public class CrossingTileTester extends JFrame { - - private final Tile trackEast; - private final Tile trackSouth; - private final Tile trackWest; - private final Tile trackNorth; - +public class CrossingTileTester extends javax.swing.JFrame { + + private Tile trackEast; + private Tile trackSouth; + private Tile trackWest; + private Tile trackNorth; + + /** + * Creates new form TileTester + * + * @param title + */ public CrossingTileTester(String title) { super(title); - - trackEast = new Crossing(Orientation.EAST, 70, 60); - trackSouth = new Crossing(Orientation.SOUTH, 160, 60); - trackWest = new Crossing(Orientation.WEST, 250, 60); - trackNorth = new Crossing(Orientation.NORTH, 340, 60); + initComponents(); + + createTiles(); + + this.setVisible(true); } - - @Override - public void paint(Graphics g) { - Graphics2D g2d = (Graphics2D) g; - - trackEast.drawTile(g2d, true); - trackEast.drawBounds(g2d); - //trackEast.drawCenterPoint(g2d, Color.red); - - trackSouth.drawTile(g2d, false); - trackSouth.drawBounds(g2d); - trackSouth.drawCenterPoint(g2d, Color.blue); - - trackWest.drawTile(g2d, true); - trackWest.drawBounds(g2d); - trackWest.drawCenterPoint(g2d, Color.red); - - trackNorth.drawTile(g2d, false); - trackNorth.drawBounds(g2d); - trackNorth.drawCenterPoint(g2d, Color.cyan); + + private void createTiles() { + + trackEast = new Crossing(TileBean.Orientation.EAST, 40, 40); + trackEast.setId("east"); + trackEast.setTrackRouteColor(Color.MAGENTA); + + trackSouth = new Crossing(TileBean.Orientation.SOUTH, 120, 40); + trackSouth.setId("south"); + trackSouth.setTrackRouteColor(Color.YELLOW); + trackSouth.setIncomingSide(TileBean.Orientation.EAST); + + trackWest = new Crossing(TileBean.Orientation.WEST, 200, 40); + trackWest.setId("west"); + trackWest.setTrackRouteColor(Color.CYAN); + trackWest.setIncomingSide(TileBean.Orientation.NORTH); + + trackNorth = new Crossing(TileBean.Orientation.NORTH, 280, 40); + trackNorth.setId("north"); + trackNorth.setTrackRouteColor(Color.blue); + + dotGridCanvas.add(trackEast); + + dotGridCanvas.add(trackSouth); + dotGridCanvas.add(trackWest); + dotGridCanvas.add(trackNorth); } + /** + * This method is called from within the constructor to initialize the form. WARNING: Do NOT modify this code. The content of this method is always regenerated by the Form Editor. + */ + @SuppressWarnings("unchecked") + // //GEN-BEGIN:initComponents + private void initComponents() { + + toolbarPanel = new javax.swing.JPanel(); + toolBar = new javax.swing.JToolBar(); + eastTileBtn = new javax.swing.JToggleButton(); + southTileBtn = new javax.swing.JToggleButton(); + westTileBtn = new javax.swing.JToggleButton(); + northTileBtn = new javax.swing.JToggleButton(); + selectSouthTileBtn = new javax.swing.JToggleButton(); + drawCenterBtn = new javax.swing.JToggleButton(); + dotGridCanvas = new jcs.ui.layout.tiles.DotGridCanvas(); + + setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE); + + java.awt.FlowLayout flowLayout1 = new java.awt.FlowLayout(java.awt.FlowLayout.LEFT); + flowLayout1.setAlignOnBaseline(true); + toolbarPanel.setLayout(flowLayout1); + + toolBar.setRollover(true); + + eastTileBtn.setText("East"); + eastTileBtn.setFocusable(false); + eastTileBtn.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER); + eastTileBtn.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); + eastTileBtn.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + eastTileBtnActionPerformed(evt); + } + }); + toolBar.add(eastTileBtn); + + southTileBtn.setText("South"); + southTileBtn.setFocusable(false); + southTileBtn.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER); + southTileBtn.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); + southTileBtn.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + southTileBtnActionPerformed(evt); + } + }); + toolBar.add(southTileBtn); + + westTileBtn.setText("West"); + westTileBtn.setFocusable(false); + westTileBtn.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER); + westTileBtn.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); + westTileBtn.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + westTileBtnActionPerformed(evt); + } + }); + toolBar.add(westTileBtn); + + northTileBtn.setText("North"); + northTileBtn.setFocusable(false); + northTileBtn.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER); + northTileBtn.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); + northTileBtn.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + northTileBtnActionPerformed(evt); + } + }); + toolBar.add(northTileBtn); + + selectSouthTileBtn.setText("Select Tile"); + selectSouthTileBtn.setFocusable(false); + selectSouthTileBtn.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER); + selectSouthTileBtn.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); + selectSouthTileBtn.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + selectSouthTileBtnActionPerformed(evt); + } + }); + toolBar.add(selectSouthTileBtn); + + drawCenterBtn.setText("show Center"); + drawCenterBtn.setFocusable(false); + drawCenterBtn.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER); + drawCenterBtn.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); + drawCenterBtn.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + drawCenterBtnActionPerformed(evt); + } + }); + toolBar.add(drawCenterBtn); + + toolbarPanel.add(toolBar); + + getContentPane().add(toolbarPanel, java.awt.BorderLayout.NORTH); + + dotGridCanvas.setPreferredSize(new java.awt.Dimension(360, 120)); + getContentPane().add(dotGridCanvas, java.awt.BorderLayout.CENTER); + + pack(); + }// //GEN-END:initComponents + + private void northTileBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_northTileBtnActionPerformed + Logger.trace(trackNorth.id + "..."); + this.trackNorth.setDrawRoute(this.northTileBtn.isSelected()); + }//GEN-LAST:event_northTileBtnActionPerformed + + private void eastTileBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_eastTileBtnActionPerformed + this.trackEast.setDrawRoute(this.eastTileBtn.isSelected()); + }//GEN-LAST:event_eastTileBtnActionPerformed + + private void westTileBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_westTileBtnActionPerformed + this.trackWest.setDrawRoute(this.westTileBtn.isSelected()); + }//GEN-LAST:event_westTileBtnActionPerformed + + private void southTileBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_southTileBtnActionPerformed + this.trackSouth.setDrawRoute(this.southTileBtn.isSelected()); + }//GEN-LAST:event_southTileBtnActionPerformed + + private void selectSouthTileBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_selectSouthTileBtnActionPerformed + this.trackSouth.setSelected(this.selectSouthTileBtn.isSelected()); + }//GEN-LAST:event_selectSouthTileBtnActionPerformed + + private void drawCenterBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_drawCenterBtnActionPerformed + this.trackNorth.setDrawCenterPoint(this.drawCenterBtn.isSelected()); + }//GEN-LAST:event_drawCenterBtnActionPerformed + + /** + * @param args the command line arguments + */ public static void main(String args[]) { - try { UIManager.setLookAndFeel("com.formdev.flatlaf.FlatLightLaf"); + CrossingTileTester.setDefaultLookAndFeelDecorated(true); + } catch (ClassNotFoundException - | InstantiationException - | IllegalAccessException - | UnsupportedLookAndFeelException ex) { + | InstantiationException + | IllegalAccessException + | UnsupportedLookAndFeelException ex) { Logger.error(ex); } - CrossingTileTester app = new CrossingTileTester("Crossing Tile Tester"); - - Dimension dim = Toolkit.getDefaultToolkit().getScreenSize(); - app.setSize(400, 100); - - app.setLocation( - dim.width / 2 - app.getSize().width / 2, dim.height / 2 - app.getSize().height / 2); - - app.setVisible(true); - - app.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + /* Create and display the form */ + java.awt.EventQueue.invokeLater(() -> { + CrossingTileTester app = new CrossingTileTester("CrossingTile Tester"); + app.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + Dimension dim = Toolkit.getDefaultToolkit().getScreenSize(); + app.setLocation(dim.width / 2 - app.getSize().width / 2, dim.height / 2 - app.getSize().height / 2); + app.pack(); + }); } + + // Variables declaration - do not modify//GEN-BEGIN:variables + private jcs.ui.layout.tiles.DotGridCanvas dotGridCanvas; + private javax.swing.JToggleButton drawCenterBtn; + private javax.swing.JToggleButton eastTileBtn; + private javax.swing.JToggleButton northTileBtn; + private javax.swing.JToggleButton selectSouthTileBtn; + private javax.swing.JToggleButton southTileBtn; + private javax.swing.JToolBar toolBar; + private javax.swing.JPanel toolbarPanel; + private javax.swing.JToggleButton westTileBtn; + // End of variables declaration//GEN-END:variables } diff --git a/src/test/java/jcs/ui/layout/tiles/CurvedTileTester.form b/src/test/java/jcs/ui/layout/tiles/CurvedTileTester.form new file mode 100644 index 00000000..eade3117 --- /dev/null +++ b/src/test/java/jcs/ui/layout/tiles/CurvedTileTester.form @@ -0,0 +1,197 @@ + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/test/java/jcs/ui/layout/tiles/CurvedTileTester.java b/src/test/java/jcs/ui/layout/tiles/CurvedTileTester.java index ee73601a..a2dfcc60 100644 --- a/src/test/java/jcs/ui/layout/tiles/CurvedTileTester.java +++ b/src/test/java/jcs/ui/layout/tiles/CurvedTileTester.java @@ -1,5 +1,5 @@ /* - * Copyright 2023 Frans Jacobs. + * Copyright 2025 fransjacobs. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -17,76 +17,223 @@ import java.awt.Color; import java.awt.Dimension; -import java.awt.Graphics; -import java.awt.Graphics2D; import java.awt.Toolkit; import javax.swing.JFrame; import javax.swing.UIManager; import javax.swing.UnsupportedLookAndFeelException; -import jcs.entities.TileBean.Orientation; +import jcs.entities.TileBean; import org.tinylog.Logger; /** - * @author Frans Jacobs + * + * @author fransjacobs */ -public class CurvedTileTester extends JFrame { - - private final Tile trackEast; - private final Tile trackSouth; - private final Tile trackWest; - private final Tile trackNorth; - +public class CurvedTileTester extends javax.swing.JFrame { + + private Tile trackEast; + private Tile trackSouth; + private Tile trackWest; + private Tile trackNorth; + + /** + * Creates new form TileTester + * + * @param title + */ public CurvedTileTester(String title) { super(title); + initComponents(); - trackEast = new Curved(Orientation.EAST, 70, 60); - trackSouth = new Curved(Orientation.SOUTH, 160, 60); - trackWest = new Curved(Orientation.WEST, 250, 60); - trackNorth = new Curved(Orientation.NORTH, 340, 60); + createTiles(); + + this.setVisible(true); } - @Override - public void paint(Graphics g) { - Graphics2D g2d = (Graphics2D) g; + private void createTiles() { + + trackEast = new Curved(TileBean.Orientation.EAST, 40, 40); + trackEast.setId("east"); + trackEast.setTrackRouteColor(Color.MAGENTA); - trackEast.drawTile(g2d, false); - trackEast.drawBounds(g2d); - trackEast.drawCenterPoint(g2d, Color.red); + trackSouth = new Curved(TileBean.Orientation.SOUTH, 120, 40); + trackSouth.setId("south"); + trackSouth.setTrackRouteColor(Color.YELLOW); - trackSouth.drawTile(g2d, false); - trackSouth.drawBounds(g2d); - trackSouth.drawCenterPoint(g2d, Color.blue); + trackWest = new Curved(TileBean.Orientation.WEST, 200, 40); + trackWest.setId("west"); + trackWest.setTrackRouteColor(Color.CYAN); - trackWest.drawTile(g2d, false); - trackWest.drawBounds(g2d); - trackWest.drawCenterPoint(g2d, Color.red); + trackNorth = new Curved(TileBean.Orientation.NORTH, 280, 40); + trackNorth.setId("north"); + trackNorth.setTrackRouteColor(Color.blue); - trackNorth.drawTile(g2d, false); - trackNorth.drawBounds(g2d); - trackNorth.drawCenterPoint(g2d, Color.cyan); + dotGridCanvas.add(trackEast); + + dotGridCanvas.add(trackSouth); + dotGridCanvas.add(trackWest); + dotGridCanvas.add(trackNorth); } + /** + * This method is called from within the constructor to initialize the form. WARNING: Do NOT modify this code. The content of this method is always regenerated by the Form Editor. + */ + @SuppressWarnings("unchecked") + // //GEN-BEGIN:initComponents + private void initComponents() { + + toolbarPanel = new javax.swing.JPanel(); + toolBar = new javax.swing.JToolBar(); + eastTileBtn = new javax.swing.JToggleButton(); + southTileBtn = new javax.swing.JToggleButton(); + westTileBtn = new javax.swing.JToggleButton(); + northTileBtn = new javax.swing.JToggleButton(); + selectSouthTileBtn = new javax.swing.JToggleButton(); + drawCenterBtn = new javax.swing.JToggleButton(); + dotGridCanvas = new jcs.ui.layout.tiles.DotGridCanvas(); + + setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE); + + java.awt.FlowLayout flowLayout1 = new java.awt.FlowLayout(java.awt.FlowLayout.LEFT); + flowLayout1.setAlignOnBaseline(true); + toolbarPanel.setLayout(flowLayout1); + + toolBar.setRollover(true); + + eastTileBtn.setText("East"); + eastTileBtn.setFocusable(false); + eastTileBtn.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER); + eastTileBtn.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); + eastTileBtn.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + eastTileBtnActionPerformed(evt); + } + }); + toolBar.add(eastTileBtn); + + southTileBtn.setText("South"); + southTileBtn.setFocusable(false); + southTileBtn.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER); + southTileBtn.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); + southTileBtn.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + southTileBtnActionPerformed(evt); + } + }); + toolBar.add(southTileBtn); + + westTileBtn.setText("West"); + westTileBtn.setFocusable(false); + westTileBtn.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER); + westTileBtn.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); + westTileBtn.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + westTileBtnActionPerformed(evt); + } + }); + toolBar.add(westTileBtn); + + northTileBtn.setText("North"); + northTileBtn.setFocusable(false); + northTileBtn.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER); + northTileBtn.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); + northTileBtn.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + northTileBtnActionPerformed(evt); + } + }); + toolBar.add(northTileBtn); + + selectSouthTileBtn.setText("Select Tile"); + selectSouthTileBtn.setFocusable(false); + selectSouthTileBtn.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER); + selectSouthTileBtn.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); + selectSouthTileBtn.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + selectSouthTileBtnActionPerformed(evt); + } + }); + toolBar.add(selectSouthTileBtn); + + drawCenterBtn.setText("show Center"); + drawCenterBtn.setFocusable(false); + drawCenterBtn.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER); + drawCenterBtn.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); + drawCenterBtn.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + drawCenterBtnActionPerformed(evt); + } + }); + toolBar.add(drawCenterBtn); + + toolbarPanel.add(toolBar); + + getContentPane().add(toolbarPanel, java.awt.BorderLayout.NORTH); + + dotGridCanvas.setPreferredSize(new java.awt.Dimension(360, 120)); + getContentPane().add(dotGridCanvas, java.awt.BorderLayout.CENTER); + + pack(); + }// //GEN-END:initComponents + + private void northTileBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_northTileBtnActionPerformed + Logger.trace(trackNorth.id + "..."); + this.trackNorth.setDrawRoute(this.northTileBtn.isSelected()); + }//GEN-LAST:event_northTileBtnActionPerformed + + private void eastTileBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_eastTileBtnActionPerformed + this.trackEast.setDrawRoute(this.eastTileBtn.isSelected()); + }//GEN-LAST:event_eastTileBtnActionPerformed + + private void westTileBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_westTileBtnActionPerformed + this.trackWest.setDrawRoute(this.westTileBtn.isSelected()); + }//GEN-LAST:event_westTileBtnActionPerformed + + private void southTileBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_southTileBtnActionPerformed + this.trackSouth.setDrawRoute(this.southTileBtn.isSelected()); + }//GEN-LAST:event_southTileBtnActionPerformed + + private void selectSouthTileBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_selectSouthTileBtnActionPerformed + this.trackSouth.setSelected(this.selectSouthTileBtn.isSelected()); + }//GEN-LAST:event_selectSouthTileBtnActionPerformed + + private void drawCenterBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_drawCenterBtnActionPerformed + this.trackNorth.setDrawCenterPoint(this.drawCenterBtn.isSelected()); + }//GEN-LAST:event_drawCenterBtnActionPerformed + + /** + * @param args the command line arguments + */ public static void main(String args[]) { - try { UIManager.setLookAndFeel("com.formdev.flatlaf.FlatLightLaf"); + CurvedTileTester.setDefaultLookAndFeelDecorated(true); + } catch (ClassNotFoundException - | InstantiationException - | IllegalAccessException - | UnsupportedLookAndFeelException ex) { + | InstantiationException + | IllegalAccessException + | UnsupportedLookAndFeelException ex) { Logger.error(ex); } - CurvedTileTester app = new CurvedTileTester("Curved Tile Tester"); - - Dimension dim = Toolkit.getDefaultToolkit().getScreenSize(); - app.setSize(400, 100); - - app.setLocation( - dim.width / 2 - app.getSize().width / 2, dim.height / 2 - app.getSize().height / 2); - - app.setVisible(true); - - app.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + /* Create and display the form */ + java.awt.EventQueue.invokeLater(() -> { + CurvedTileTester app = new CurvedTileTester("CurvedTile Tester"); + app.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + Dimension dim = Toolkit.getDefaultToolkit().getScreenSize(); + app.setLocation(dim.width / 2 - app.getSize().width / 2, dim.height / 2 - app.getSize().height / 2); + app.pack(); + }); } + + // Variables declaration - do not modify//GEN-BEGIN:variables + private jcs.ui.layout.tiles.DotGridCanvas dotGridCanvas; + private javax.swing.JToggleButton drawCenterBtn; + private javax.swing.JToggleButton eastTileBtn; + private javax.swing.JToggleButton northTileBtn; + private javax.swing.JToggleButton selectSouthTileBtn; + private javax.swing.JToggleButton southTileBtn; + private javax.swing.JToolBar toolBar; + private javax.swing.JPanel toolbarPanel; + private javax.swing.JToggleButton westTileBtn; + // End of variables declaration//GEN-END:variables } diff --git a/src/test/java/jcs/ui/layout/tiles/DotGridCanvas.java b/src/test/java/jcs/ui/layout/tiles/DotGridCanvas.java new file mode 100644 index 00000000..3fcbfd65 --- /dev/null +++ b/src/test/java/jcs/ui/layout/tiles/DotGridCanvas.java @@ -0,0 +1,70 @@ +/* + * Copyright 2025 Frans Jacobs. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package jcs.ui.layout.tiles; + +import java.awt.Color; +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.Paint; +import javax.swing.JPanel; +import org.tinylog.Logger; + +/** + * + * @author fransjacobs + */ +public class DotGridCanvas extends JPanel { + + public DotGridCanvas() { + setLayout(null); + setOpaque(true); + setDoubleBuffered(false); + } + + @Override + public void paint(Graphics g) { + long started = System.currentTimeMillis(); + + //Rectangle r = g.getClipBounds(); + //Logger.trace("Rx: " + r.x + " Ry: " + r.y + " Rw: " + r.width + " Rh: " + r.height); + super.paint(g); + + paintDotGrid(g); + long now = System.currentTimeMillis(); + Logger.trace("Duration: " + (now - started) + " ms."); + } + + private void paintDotGrid(Graphics g) { + int width = this.getWidth(); + int height = this.getHeight(); + + int xOffset = 0; + int yOffset = 0; + + //Logger.trace("W: " + width + " H: " + height + " X: " + this.getX() + " Y: " + this.getY()); + Graphics2D gc = (Graphics2D) g; + Paint p = gc.getPaint(); + gc.setPaint(Color.black); + + for (int r = 0; r < width; r++) { + for (int c = 0; c < height; c++) { + gc.drawOval((r * 20 * 2) + xOffset - 2, (c * 20 * 2) + yOffset - 2, 4, 4); + } + } + gc.setPaint(p); + } + +} diff --git a/src/test/java/jcs/ui/layout/tiles/EndTileTester.form b/src/test/java/jcs/ui/layout/tiles/EndTileTester.form new file mode 100644 index 00000000..eade3117 --- /dev/null +++ b/src/test/java/jcs/ui/layout/tiles/EndTileTester.form @@ -0,0 +1,197 @@ + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/test/java/jcs/ui/layout/tiles/EndTileTester.java b/src/test/java/jcs/ui/layout/tiles/EndTileTester.java index 4a95cd73..1a9400ed 100644 --- a/src/test/java/jcs/ui/layout/tiles/EndTileTester.java +++ b/src/test/java/jcs/ui/layout/tiles/EndTileTester.java @@ -1,5 +1,5 @@ /* - * Copyright 2023 Frans Jacobs. + * Copyright 2025 fransjacobs. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -17,76 +17,223 @@ import java.awt.Color; import java.awt.Dimension; -import java.awt.Graphics; -import java.awt.Graphics2D; import java.awt.Toolkit; import javax.swing.JFrame; import javax.swing.UIManager; import javax.swing.UnsupportedLookAndFeelException; -import jcs.entities.TileBean.Orientation; +import jcs.entities.TileBean; import org.tinylog.Logger; /** - * @author Frans Jacobs + * + * @author fransjacobs */ -public class EndTileTester extends JFrame { - - private final Tile trackEast; - private final Tile trackSouth; - private final Tile trackWest; - private final Tile trackNorth; - +public class EndTileTester extends javax.swing.JFrame { + + private Tile trackEast; + private Tile trackSouth; + private Tile trackWest; + private Tile trackNorth; + + /** + * Creates new form TileTester + * + * @param title + */ public EndTileTester(String title) { super(title); + initComponents(); + + createTiles(); - trackEast = new End(Orientation.EAST, 70, 60); - trackSouth = new End(Orientation.SOUTH, 160, 60); - trackWest = new End(Orientation.WEST, 250, 60); - trackNorth = new End(Orientation.NORTH, 340, 60); + this.setVisible(true); } - @Override - public void paint(Graphics g) { - Graphics2D g2d = (Graphics2D) g; + private void createTiles() { - trackEast.drawTile(g2d, false); - trackEast.drawBounds(g2d); - trackEast.drawCenterPoint(g2d, Color.red); + trackEast = new End(TileBean.Orientation.EAST, 40, 40); + trackEast.setId("east"); + trackEast.setTrackRouteColor(Color.MAGENTA); - trackSouth.drawTile(g2d, false); - trackSouth.drawBounds(g2d); - trackSouth.drawCenterPoint(g2d, Color.blue); + trackSouth = new End(TileBean.Orientation.SOUTH, 120, 40); + trackSouth.setId("south"); + trackSouth.setTrackRouteColor(Color.YELLOW); - trackWest.drawTile(g2d, false); - trackWest.drawBounds(g2d); - trackWest.drawCenterPoint(g2d, Color.red); + trackWest = new End(TileBean.Orientation.WEST, 200, 40); + trackWest.setId("west"); + trackWest.setTrackRouteColor(Color.CYAN); - trackNorth.drawTile(g2d, false); - trackNorth.drawBounds(g2d); - trackNorth.drawCenterPoint(g2d, Color.cyan); + trackNorth = new End(TileBean.Orientation.NORTH, 280, 40); + trackNorth.setId("north"); + trackNorth.setTrackRouteColor(Color.blue); + + dotGridCanvas.add(trackEast); + + dotGridCanvas.add(trackSouth); + dotGridCanvas.add(trackWest); + dotGridCanvas.add(trackNorth); } + /** + * This method is called from within the constructor to initialize the form. WARNING: Do NOT modify this code. The content of this method is always regenerated by the Form Editor. + */ + @SuppressWarnings("unchecked") + // //GEN-BEGIN:initComponents + private void initComponents() { + + toolbarPanel = new javax.swing.JPanel(); + toolBar = new javax.swing.JToolBar(); + eastTileBtn = new javax.swing.JToggleButton(); + southTileBtn = new javax.swing.JToggleButton(); + westTileBtn = new javax.swing.JToggleButton(); + northTileBtn = new javax.swing.JToggleButton(); + selectSouthTileBtn = new javax.swing.JToggleButton(); + drawCenterBtn = new javax.swing.JToggleButton(); + dotGridCanvas = new jcs.ui.layout.tiles.DotGridCanvas(); + + setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE); + + java.awt.FlowLayout flowLayout1 = new java.awt.FlowLayout(java.awt.FlowLayout.LEFT); + flowLayout1.setAlignOnBaseline(true); + toolbarPanel.setLayout(flowLayout1); + + toolBar.setRollover(true); + + eastTileBtn.setText("East"); + eastTileBtn.setFocusable(false); + eastTileBtn.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER); + eastTileBtn.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); + eastTileBtn.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + eastTileBtnActionPerformed(evt); + } + }); + toolBar.add(eastTileBtn); + + southTileBtn.setText("South"); + southTileBtn.setFocusable(false); + southTileBtn.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER); + southTileBtn.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); + southTileBtn.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + southTileBtnActionPerformed(evt); + } + }); + toolBar.add(southTileBtn); + + westTileBtn.setText("West"); + westTileBtn.setFocusable(false); + westTileBtn.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER); + westTileBtn.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); + westTileBtn.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + westTileBtnActionPerformed(evt); + } + }); + toolBar.add(westTileBtn); + + northTileBtn.setText("North"); + northTileBtn.setFocusable(false); + northTileBtn.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER); + northTileBtn.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); + northTileBtn.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + northTileBtnActionPerformed(evt); + } + }); + toolBar.add(northTileBtn); + + selectSouthTileBtn.setText("Select Tile"); + selectSouthTileBtn.setFocusable(false); + selectSouthTileBtn.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER); + selectSouthTileBtn.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); + selectSouthTileBtn.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + selectSouthTileBtnActionPerformed(evt); + } + }); + toolBar.add(selectSouthTileBtn); + + drawCenterBtn.setText("show Center"); + drawCenterBtn.setFocusable(false); + drawCenterBtn.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER); + drawCenterBtn.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); + drawCenterBtn.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + drawCenterBtnActionPerformed(evt); + } + }); + toolBar.add(drawCenterBtn); + + toolbarPanel.add(toolBar); + + getContentPane().add(toolbarPanel, java.awt.BorderLayout.NORTH); + + dotGridCanvas.setPreferredSize(new java.awt.Dimension(360, 120)); + getContentPane().add(dotGridCanvas, java.awt.BorderLayout.CENTER); + + pack(); + }// //GEN-END:initComponents + + private void northTileBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_northTileBtnActionPerformed + Logger.trace(trackNorth.id + "..."); + this.trackNorth.setDrawRoute(this.northTileBtn.isSelected()); + }//GEN-LAST:event_northTileBtnActionPerformed + + private void eastTileBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_eastTileBtnActionPerformed + this.trackEast.setDrawRoute(this.eastTileBtn.isSelected()); + }//GEN-LAST:event_eastTileBtnActionPerformed + + private void westTileBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_westTileBtnActionPerformed + this.trackWest.setDrawRoute(this.westTileBtn.isSelected()); + }//GEN-LAST:event_westTileBtnActionPerformed + + private void southTileBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_southTileBtnActionPerformed + this.trackSouth.setDrawRoute(this.southTileBtn.isSelected()); + }//GEN-LAST:event_southTileBtnActionPerformed + + private void selectSouthTileBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_selectSouthTileBtnActionPerformed + this.trackSouth.setSelected(this.selectSouthTileBtn.isSelected()); + }//GEN-LAST:event_selectSouthTileBtnActionPerformed + + private void drawCenterBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_drawCenterBtnActionPerformed + this.trackNorth.setDrawCenterPoint(this.drawCenterBtn.isSelected()); + }//GEN-LAST:event_drawCenterBtnActionPerformed + + /** + * @param args the command line arguments + */ public static void main(String args[]) { - try { UIManager.setLookAndFeel("com.formdev.flatlaf.FlatLightLaf"); + EndTileTester.setDefaultLookAndFeelDecorated(true); + } catch (ClassNotFoundException - | InstantiationException - | IllegalAccessException - | UnsupportedLookAndFeelException ex) { + | InstantiationException + | IllegalAccessException + | UnsupportedLookAndFeelException ex) { Logger.error(ex); } - EndTileTester app = new EndTileTester("End Tile Tester"); - - Dimension dim = Toolkit.getDefaultToolkit().getScreenSize(); - app.setSize(400, 100); - - app.setLocation( - dim.width / 2 - app.getSize().width / 2, dim.height / 2 - app.getSize().height / 2); - - app.setVisible(true); - - app.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + /* Create and display the form */ + java.awt.EventQueue.invokeLater(() -> { + EndTileTester app = new EndTileTester("EndTile Tester"); + app.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + Dimension dim = Toolkit.getDefaultToolkit().getScreenSize(); + app.setLocation(dim.width / 2 - app.getSize().width / 2, dim.height / 2 - app.getSize().height / 2); + app.pack(); + }); } + + // Variables declaration - do not modify//GEN-BEGIN:variables + private jcs.ui.layout.tiles.DotGridCanvas dotGridCanvas; + private javax.swing.JToggleButton drawCenterBtn; + private javax.swing.JToggleButton eastTileBtn; + private javax.swing.JToggleButton northTileBtn; + private javax.swing.JToggleButton selectSouthTileBtn; + private javax.swing.JToggleButton southTileBtn; + private javax.swing.JToolBar toolBar; + private javax.swing.JPanel toolbarPanel; + private javax.swing.JToggleButton westTileBtn; + // End of variables declaration//GEN-END:variables } diff --git a/src/test/java/jcs/ui/layout/tiles/SensorTileTester.form b/src/test/java/jcs/ui/layout/tiles/SensorTileTester.form new file mode 100644 index 00000000..335bf54f --- /dev/null +++ b/src/test/java/jcs/ui/layout/tiles/SensorTileTester.form @@ -0,0 +1,208 @@ + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/test/java/jcs/ui/layout/tiles/SensorTileTester.java b/src/test/java/jcs/ui/layout/tiles/SensorTileTester.java index 817d2d27..4e016041 100644 --- a/src/test/java/jcs/ui/layout/tiles/SensorTileTester.java +++ b/src/test/java/jcs/ui/layout/tiles/SensorTileTester.java @@ -1,5 +1,5 @@ /* - * Copyright 2023 Frans Jacobs. + * Copyright 2025 Frans Jacobs. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -17,78 +17,236 @@ import java.awt.Color; import java.awt.Dimension; -import java.awt.Graphics; -import java.awt.Graphics2D; import java.awt.Toolkit; import javax.swing.JFrame; import javax.swing.UIManager; import javax.swing.UnsupportedLookAndFeelException; -import jcs.entities.TileBean.Orientation; +import jcs.entities.TileBean; import org.tinylog.Logger; -/** - * @author Frans Jacobs - */ -public class SensorTileTester extends JFrame { +public class SensorTileTester extends javax.swing.JFrame { - private final Tile trackEast; - private final Tile trackSouth; - private final Tile trackWest; - private final Tile trackNorth; + private Tile sensorEast; + private Tile sensorSouth; + private Tile sensorWest; + private Tile sensorNorth; + /** + * Creates new form TileTester + * + * @param title + */ public SensorTileTester(String title) { super(title); + initComponents(); + + createTiles(); - trackEast = new Sensor(Orientation.EAST, 70, 60); - trackSouth = new Sensor(Orientation.SOUTH, 160, 60); - trackWest = new Sensor(Orientation.WEST, 250, 60); - trackNorth = new Sensor(Orientation.NORTH, 340, 60); + this.setVisible(true); } - @Override - public void paint(Graphics g) { - Graphics2D g2d = (Graphics2D) g; + private void createTiles() { + + sensorEast = new Sensor(TileBean.Orientation.EAST, 40, 40); + sensorEast.setId("east"); + sensorEast.setTrackRouteColor(Color.MAGENTA); - trackEast.drawTile(g2d, false); - trackEast.drawBounds(g2d); - trackEast.drawCenterPoint(g2d, Color.red); + sensorSouth = new Sensor(TileBean.Orientation.SOUTH, 120, 40); + sensorSouth.setId("south"); + sensorSouth.setTrackRouteColor(Color.YELLOW); - trackSouth.drawTile(g2d, false); - trackSouth.drawBounds(g2d); - trackSouth.drawCenterPoint(g2d, Color.blue); - ((Sensor) trackSouth).setActive(true); + sensorWest = new Sensor(TileBean.Orientation.WEST, 200, 40); + sensorWest.setId("west"); + sensorWest.setTrackRouteColor(Color.CYAN); - trackWest.drawTile(g2d, false); - trackWest.drawBounds(g2d); - trackWest.drawCenterPoint(g2d, Color.red); - ((Sensor) trackWest).setActive(true); + sensorNorth = new Sensor(TileBean.Orientation.NORTH, 280, 40); + sensorNorth.setId("north"); + sensorNorth.setTrackRouteColor(Color.blue); - trackNorth.drawTile(g2d, false); - trackNorth.drawBounds(g2d); - trackNorth.drawCenterPoint(g2d, Color.cyan); + dotGridCanvas.add(sensorEast); + + dotGridCanvas.add(sensorSouth); + dotGridCanvas.add(sensorWest); + dotGridCanvas.add(sensorNorth); } + /** + * This method is called from within the constructor to initialize the form. WARNING: Do NOT modify this code. The content of this method is always regenerated by the Form Editor. + */ + @SuppressWarnings("unchecked") + // //GEN-BEGIN:initComponents + private void initComponents() { + + toolbarPanel = new javax.swing.JPanel(); + toolBar = new javax.swing.JToolBar(); + eastTileBtn = new javax.swing.JToggleButton(); + southTileBtn = new javax.swing.JToggleButton(); + westTileBtn = new javax.swing.JToggleButton(); + northTileBtn = new javax.swing.JToggleButton(); + selectSouthTileBtn = new javax.swing.JToggleButton(); + drawCenterBtn = new javax.swing.JToggleButton(); + activateEastSensorBtn = new javax.swing.JToggleButton(); + dotGridCanvas = new jcs.ui.layout.tiles.DotGridCanvas(); + + setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE); + + java.awt.FlowLayout flowLayout1 = new java.awt.FlowLayout(java.awt.FlowLayout.LEFT); + flowLayout1.setAlignOnBaseline(true); + toolbarPanel.setLayout(flowLayout1); + + toolBar.setRollover(true); + + eastTileBtn.setText("East"); + eastTileBtn.setFocusable(false); + eastTileBtn.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER); + eastTileBtn.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); + eastTileBtn.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + eastTileBtnActionPerformed(evt); + } + }); + toolBar.add(eastTileBtn); + + southTileBtn.setText("South"); + southTileBtn.setFocusable(false); + southTileBtn.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER); + southTileBtn.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); + southTileBtn.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + southTileBtnActionPerformed(evt); + } + }); + toolBar.add(southTileBtn); + + westTileBtn.setText("West"); + westTileBtn.setFocusable(false); + westTileBtn.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER); + westTileBtn.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); + westTileBtn.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + westTileBtnActionPerformed(evt); + } + }); + toolBar.add(westTileBtn); + + northTileBtn.setText("North"); + northTileBtn.setFocusable(false); + northTileBtn.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER); + northTileBtn.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); + northTileBtn.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + northTileBtnActionPerformed(evt); + } + }); + toolBar.add(northTileBtn); + + selectSouthTileBtn.setText("Select Tile"); + selectSouthTileBtn.setFocusable(false); + selectSouthTileBtn.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER); + selectSouthTileBtn.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); + selectSouthTileBtn.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + selectSouthTileBtnActionPerformed(evt); + } + }); + toolBar.add(selectSouthTileBtn); + + drawCenterBtn.setText("show Center"); + drawCenterBtn.setFocusable(false); + drawCenterBtn.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER); + drawCenterBtn.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); + drawCenterBtn.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + drawCenterBtnActionPerformed(evt); + } + }); + toolBar.add(drawCenterBtn); + + activateEastSensorBtn.setText("Active"); + activateEastSensorBtn.setFocusable(false); + activateEastSensorBtn.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER); + activateEastSensorBtn.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); + activateEastSensorBtn.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + activateEastSensorBtnActionPerformed(evt); + } + }); + toolBar.add(activateEastSensorBtn); + + toolbarPanel.add(toolBar); + + getContentPane().add(toolbarPanel, java.awt.BorderLayout.NORTH); + + dotGridCanvas.setPreferredSize(new java.awt.Dimension(360, 120)); + getContentPane().add(dotGridCanvas, java.awt.BorderLayout.CENTER); + + pack(); + }// //GEN-END:initComponents + + private void northTileBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_northTileBtnActionPerformed + Logger.trace(sensorNorth.id + "..."); + sensorNorth.setDrawRoute(this.northTileBtn.isSelected()); + }//GEN-LAST:event_northTileBtnActionPerformed + + private void eastTileBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_eastTileBtnActionPerformed + sensorEast.setDrawRoute(this.eastTileBtn.isSelected()); + }//GEN-LAST:event_eastTileBtnActionPerformed + + private void westTileBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_westTileBtnActionPerformed + sensorWest.setDrawRoute(this.westTileBtn.isSelected()); + }//GEN-LAST:event_westTileBtnActionPerformed + + private void southTileBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_southTileBtnActionPerformed + sensorSouth.setDrawRoute(this.southTileBtn.isSelected()); + }//GEN-LAST:event_southTileBtnActionPerformed + + private void selectSouthTileBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_selectSouthTileBtnActionPerformed + sensorSouth.setSelected(this.selectSouthTileBtn.isSelected()); + }//GEN-LAST:event_selectSouthTileBtnActionPerformed + + private void drawCenterBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_drawCenterBtnActionPerformed + sensorNorth.setDrawCenterPoint(this.drawCenterBtn.isSelected()); + }//GEN-LAST:event_drawCenterBtnActionPerformed + + private void activateEastSensorBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_activateEastSensorBtnActionPerformed + sensorEast.setActive(this.activateEastSensorBtn.isSelected()); + }//GEN-LAST:event_activateEastSensorBtnActionPerformed + + /** + * @param args the command line arguments + */ public static void main(String args[]) { - try { UIManager.setLookAndFeel("com.formdev.flatlaf.FlatLightLaf"); + SensorTileTester.setDefaultLookAndFeelDecorated(true); + } catch (ClassNotFoundException - | InstantiationException - | IllegalAccessException - | UnsupportedLookAndFeelException ex) { + | InstantiationException + | IllegalAccessException + | UnsupportedLookAndFeelException ex) { Logger.error(ex); } - SensorTileTester app = new SensorTileTester("Sensor Tile Tester"); - - Dimension dim = Toolkit.getDefaultToolkit().getScreenSize(); - app.setSize(400, 100); - - app.setLocation( - dim.width / 2 - app.getSize().width / 2, dim.height / 2 - app.getSize().height / 2); - - app.setVisible(true); - - app.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + /* Create and display the form */ + java.awt.EventQueue.invokeLater(() -> { + SensorTileTester app = new SensorTileTester("Sensor Tile Tester"); + app.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + Dimension dim = Toolkit.getDefaultToolkit().getScreenSize(); + app.setLocation(dim.width / 2 - app.getSize().width / 2, dim.height / 2 - app.getSize().height / 2); + app.pack(); + }); } + + // Variables declaration - do not modify//GEN-BEGIN:variables + private javax.swing.JToggleButton activateEastSensorBtn; + private jcs.ui.layout.tiles.DotGridCanvas dotGridCanvas; + private javax.swing.JToggleButton drawCenterBtn; + private javax.swing.JToggleButton eastTileBtn; + private javax.swing.JToggleButton northTileBtn; + private javax.swing.JToggleButton selectSouthTileBtn; + private javax.swing.JToggleButton southTileBtn; + private javax.swing.JToolBar toolBar; + private javax.swing.JPanel toolbarPanel; + private javax.swing.JToggleButton westTileBtn; + // End of variables declaration//GEN-END:variables } diff --git a/src/test/java/jcs/ui/layout/tiles/SignalTileTester.form b/src/test/java/jcs/ui/layout/tiles/SignalTileTester.form new file mode 100644 index 00000000..c2b5aac8 --- /dev/null +++ b/src/test/java/jcs/ui/layout/tiles/SignalTileTester.form @@ -0,0 +1,208 @@ + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/test/java/jcs/ui/layout/tiles/SignalTileTester.java b/src/test/java/jcs/ui/layout/tiles/SignalTileTester.java index 62893ca8..c06af5b8 100644 --- a/src/test/java/jcs/ui/layout/tiles/SignalTileTester.java +++ b/src/test/java/jcs/ui/layout/tiles/SignalTileTester.java @@ -1,5 +1,5 @@ /* - * Copyright 2023 Frans Jacobs. + * Copyright 2025 Frans Jacobs. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -17,176 +17,304 @@ import java.awt.Color; import java.awt.Dimension; -import java.awt.Graphics; -import java.awt.Graphics2D; import java.awt.Toolkit; import javax.swing.JFrame; import javax.swing.UIManager; import javax.swing.UnsupportedLookAndFeelException; -import jcs.entities.AccessoryBean.SignalType; -import jcs.entities.AccessoryBean.SignalValue; -import jcs.entities.TileBean.Orientation; +import jcs.entities.AccessoryBean; +import jcs.entities.TileBean; import org.tinylog.Logger; -/** - * @author Frans Jacobs - */ -public class SignalTileTester extends JFrame { - - private final Tile signal2East; - private final Tile signal2South; - private final Tile signal2West; - private final Tile signal2North; - - private final Tile signal2MEast; - private final Tile signal2MSouth; - private final Tile signal2MWest; - private final Tile signal2MNorth; - - private final Tile signal3East; - private final Tile signal3South; - private final Tile signal3West; - private final Tile signal3North; - - private final Tile signal4East; - private final Tile signal4South; - private final Tile signal4West; - private final Tile signal4North; - - @SuppressWarnings("OverridableMethodCallInConstructor") +public class SignalTileTester extends javax.swing.JFrame { + + private Tile signal2East; + private Tile signal2South; + private Tile signal2West; + private Tile signal2North; + + private Tile signal2MEast; + private Tile signal2MSouth; + private Tile signal2MWest; + private Tile signal2MNorth; + + private Tile signal3East; + private Tile signal3South; + private Tile signal3West; + private Tile signal3North; + + private Tile signal4East; + private Tile signal4South; + private Tile signal4West; + private Tile signal4North; + + /** + * Creates new form TileTester + * + * @param title + */ public SignalTileTester(String title) { super(title); + initComponents(); - signal2East = new Signal(Orientation.EAST, 70, 60, SignalType.HP01); - ((Signal) signal2East).setSignalValue(SignalValue.Hp0); - - signal2South = new Signal(Orientation.SOUTH, 160, 60, SignalType.HP01); - ((Signal) signal2South).setSignalValue(SignalValue.Hp1); - - signal2West = new Signal(Orientation.WEST, 250, 60, SignalType.HP01); - ((Signal) signal2West).setSignalValue(SignalValue.Hp0); - - signal2North = new Signal(Orientation.NORTH, 340, 60, SignalType.HP01); - ((Signal) signal2North).setSignalValue(SignalValue.Hp1); - - // - signal2MEast = new Signal(Orientation.EAST, 70, 110, SignalType.HP0SH1); - ((Signal) signal2MEast).setSignalValue(SignalValue.Hp0); - - signal2MSouth = new Signal(Orientation.SOUTH, 160, 110, SignalType.HP0SH1); - ((Signal) signal2MSouth).setSignalValue(SignalValue.Hp1); - - signal2MWest = new Signal(Orientation.WEST, 250, 110, SignalType.HP0SH1); - ((Signal) signal2MWest).setSignalValue(SignalValue.Hp0); - - signal2MNorth = new Signal(Orientation.NORTH, 340, 110, SignalType.HP0SH1); - ((Signal) signal2MNorth).setSignalValue(SignalValue.Hp1); - - // - signal3East = new Signal(Orientation.EAST, 70, 160, SignalType.HP012); - ((Signal) signal3East).setSignalValue(SignalValue.Hp0); - - signal3South = new Signal(Orientation.SOUTH, 160, 160, SignalType.HP012); - ((Signal) signal3South).setSignalValue(SignalValue.Hp1); - - signal3West = new Signal(Orientation.WEST, 250, 160, SignalType.HP012); - ((Signal) signal3West).setSignalValue(SignalValue.Hp2); - - signal3North = new Signal(Orientation.NORTH, 340, 160, SignalType.HP012); - ((Signal) signal3North).setSignalValue(SignalValue.Hp0); - - // - signal4East = new Signal(Orientation.EAST, 70, 210, SignalType.HP012SH1); - ((Signal) signal4East).setSignalValue(SignalValue.Hp0); - - signal4South = new Signal(Orientation.SOUTH, 160, 210, SignalType.HP012SH1); - ((Signal) signal4South).setSignalValue(SignalValue.Hp1); - - signal4West = new Signal(Orientation.WEST, 250, 210, SignalType.HP012SH1); - ((Signal) signal4West).setSignalValue(SignalValue.Hp2); - - signal4North = new Signal(Orientation.NORTH, 340, 210, SignalType.HP012SH1); - ((Signal) signal4North).setSignalValue(SignalValue.Hp0Sh1); + createTiles(); + this.setVisible(true); } - @Override - public void paint(Graphics g) { - Graphics2D g2d = (Graphics2D) g; - // - signal2East.drawTile(g2d, false); - signal2East.drawBounds(g2d); - signal2East.drawCenterPoint(g2d, Color.red); + private void createTiles() { + signal2East = new Signal(TileBean.Orientation.EAST, 40, 40, AccessoryBean.SignalType.HP01); + signal2East.setId("east2"); + signal2East.setTrackRouteColor(Color.MAGENTA); + signal2East.setSignalValue(AccessoryBean.SignalValue.Hp0); - signal2South.drawTile(g2d, false); - signal2South.drawBounds(g2d); - signal2South.drawCenterPoint(g2d, Color.blue); + signal2South = new Signal(TileBean.Orientation.SOUTH, 120, 40, AccessoryBean.SignalType.HP01); + signal2South.setId("south2"); + signal2South.setTrackRouteColor(Color.YELLOW); + signal2South.setSignalValue(AccessoryBean.SignalValue.Hp1); - signal2West.drawTile(g2d, false); - signal2West.drawBounds(g2d); - signal2West.drawCenterPoint(g2d, Color.red); + signal2West = new Signal(TileBean.Orientation.WEST, 200, 40, AccessoryBean.SignalType.HP01); + signal2West.setId("west2"); + signal2West.setTrackRouteColor(Color.CYAN); + signal2West.setSignalValue(AccessoryBean.SignalValue.Hp0); - signal2North.drawTile(g2d, false); - signal2North.drawBounds(g2d); - signal2North.drawCenterPoint(g2d, Color.cyan); + signal2North = new Signal(TileBean.Orientation.NORTH, 280, 40, AccessoryBean.SignalType.HP01); + signal2North.setId("north2"); + signal2North.setTrackRouteColor(Color.blue); + signal2North.setSignalValue(AccessoryBean.SignalValue.Hp1); // - signal2MEast.drawTile(g2d, true); - signal2MEast.drawBounds(g2d); - signal2MEast.drawCenterPoint(g2d, Color.red); + signal2MEast = new Signal(TileBean.Orientation.EAST, 40, 120, AccessoryBean.SignalType.HP0SH1); + signal2MEast.setId("east2m"); + signal2MEast.setTrackRouteColor(Color.MAGENTA); + signal2MEast.setSignalValue(AccessoryBean.SignalValue.Hp0); - signal2MSouth.drawTile(g2d, true); - signal2MSouth.drawBounds(g2d); - signal2MSouth.drawCenterPoint(g2d, Color.blue); + signal2MSouth = new Signal(TileBean.Orientation.SOUTH, 120, 120, AccessoryBean.SignalType.HP0SH1); + signal2MSouth.setId("south2m"); + signal2MSouth.setSignalValue(AccessoryBean.SignalValue.Hp1); - signal2MWest.drawTile(g2d, true); - signal2MWest.drawBounds(g2d); - signal2MWest.drawCenterPoint(g2d, Color.red); + signal2MWest = new Signal(TileBean.Orientation.WEST, 200, 120, AccessoryBean.SignalType.HP0SH1); + signal2MWest.setId("west2m"); + signal2MWest.setSignalValue(AccessoryBean.SignalValue.Hp0); - signal2MNorth.drawTile(g2d, true); - signal2MNorth.drawBounds(g2d); - signal2MNorth.drawCenterPoint(g2d, Color.cyan); + signal2MNorth = new Signal(TileBean.Orientation.NORTH, 280, 120, AccessoryBean.SignalType.HP0SH1); + signal2MWest.setId("north2m"); + signal2MNorth.setSignalValue(AccessoryBean.SignalValue.Hp1); // - signal3East.drawTile(g2d, false); - signal3East.drawBounds(g2d); - signal3East.drawCenterPoint(g2d, Color.red); + signal3East = new Signal(TileBean.Orientation.EAST, 40, 200, AccessoryBean.SignalType.HP012); + signal3East.setId("east3"); + signal3East.setSignalValue(AccessoryBean.SignalValue.Hp0); - signal3South.drawTile(g2d, false); - signal3South.drawBounds(g2d); - signal3South.drawCenterPoint(g2d, Color.blue); + signal3South = new Signal(TileBean.Orientation.SOUTH, 120, 200, AccessoryBean.SignalType.HP012); + signal3South.setId("south3"); + signal3South.setSignalValue(AccessoryBean.SignalValue.Hp1); - signal3West.drawTile(g2d, false); - signal3West.drawBounds(g2d); - signal3West.drawCenterPoint(g2d, Color.red); + signal3West = new Signal(TileBean.Orientation.WEST, 200, 200, AccessoryBean.SignalType.HP012); + signal3West.setId("west3"); + signal3West.setSignalValue(AccessoryBean.SignalValue.Hp2); - signal3North.drawTile(g2d, false); - signal3North.drawBounds(g2d); - signal3North.drawCenterPoint(g2d, Color.cyan); + signal3North = new Signal(TileBean.Orientation.NORTH, 280, 200, AccessoryBean.SignalType.HP012); + signal3North.setId("north3"); + signal3North.setSignalValue(AccessoryBean.SignalValue.Hp0); // - signal4East.drawTile(g2d, true); - signal4East.drawBounds(g2d); - signal4East.drawCenterPoint(g2d, Color.red); - - signal4South.drawTile(g2d, true); - signal4South.drawBounds(g2d); - signal4South.drawCenterPoint(g2d, Color.blue); - - signal4West.drawTile(g2d, true); - signal4West.drawBounds(g2d); - signal4West.drawCenterPoint(g2d, Color.red); - - signal4North.drawTile(g2d, true); - signal4North.drawBounds(g2d); - signal4North.drawCenterPoint(g2d, Color.cyan); + signal4East = new Signal(TileBean.Orientation.EAST, 40, 280, AccessoryBean.SignalType.HP012SH1); + signal4East.setId("east4"); + signal4East.setSignalValue(AccessoryBean.SignalValue.Hp0); + + signal4South = new Signal(TileBean.Orientation.SOUTH, 120, 280, AccessoryBean.SignalType.HP012SH1); + signal4South.setId("south4"); + signal4South.setSignalValue(AccessoryBean.SignalValue.Hp1); + + signal4West = new Signal(TileBean.Orientation.WEST, 200, 280, AccessoryBean.SignalType.HP012SH1); + signal4West.setId("west4"); + signal4West.setSignalValue(AccessoryBean.SignalValue.Hp2); + + signal4North = new Signal(TileBean.Orientation.NORTH, 280, 280, AccessoryBean.SignalType.HP012SH1); + signal4North.setId("north4"); + signal4North.setSignalValue(AccessoryBean.SignalValue.Hp0Sh1); + + dotGridCanvas.add(signal2East); + dotGridCanvas.add(signal2South); + dotGridCanvas.add(signal2West); + dotGridCanvas.add(signal2North); + + dotGridCanvas.add(signal2MEast); + dotGridCanvas.add(signal2MSouth); + dotGridCanvas.add(signal2MWest); + dotGridCanvas.add(signal2MNorth); + + dotGridCanvas.add(signal3East); + dotGridCanvas.add(signal3South); + dotGridCanvas.add(signal3West); + dotGridCanvas.add(signal3North); + + dotGridCanvas.add(signal4East); + dotGridCanvas.add(signal4South); + dotGridCanvas.add(signal4West); + dotGridCanvas.add(signal4North); } - public static void main(String args[]) { + /** + * This method is called from within the constructor to initialize the form. WARNING: Do NOT modify this code. The content of this method is always regenerated by the Form Editor. + */ + @SuppressWarnings("unchecked") + // //GEN-BEGIN:initComponents + private void initComponents() { + + toolbarPanel = new javax.swing.JPanel(); + toolBar = new javax.swing.JToolBar(); + eastTileBtn = new javax.swing.JToggleButton(); + southTileBtn = new javax.swing.JToggleButton(); + westTileBtn = new javax.swing.JToggleButton(); + northTileBtn = new javax.swing.JToggleButton(); + selectSouthTileBtn = new javax.swing.JToggleButton(); + drawCenterBtn = new javax.swing.JToggleButton(); + greenRedBtn = new javax.swing.JToggleButton(); + dotGridCanvas = new jcs.ui.layout.tiles.DotGridCanvas(); + + setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE); + + java.awt.FlowLayout flowLayout1 = new java.awt.FlowLayout(java.awt.FlowLayout.LEFT); + flowLayout1.setAlignOnBaseline(true); + toolbarPanel.setLayout(flowLayout1); + + toolBar.setRollover(true); + + eastTileBtn.setText("East"); + eastTileBtn.setFocusable(false); + eastTileBtn.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER); + eastTileBtn.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); + eastTileBtn.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + eastTileBtnActionPerformed(evt); + } + }); + toolBar.add(eastTileBtn); + + southTileBtn.setText("South"); + southTileBtn.setFocusable(false); + southTileBtn.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER); + southTileBtn.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); + southTileBtn.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + southTileBtnActionPerformed(evt); + } + }); + toolBar.add(southTileBtn); + + westTileBtn.setText("West"); + westTileBtn.setFocusable(false); + westTileBtn.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER); + westTileBtn.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); + westTileBtn.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + westTileBtnActionPerformed(evt); + } + }); + toolBar.add(westTileBtn); + + northTileBtn.setText("North"); + northTileBtn.setFocusable(false); + northTileBtn.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER); + northTileBtn.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); + northTileBtn.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + northTileBtnActionPerformed(evt); + } + }); + toolBar.add(northTileBtn); + + selectSouthTileBtn.setText("Select Tile"); + selectSouthTileBtn.setFocusable(false); + selectSouthTileBtn.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER); + selectSouthTileBtn.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); + selectSouthTileBtn.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + selectSouthTileBtnActionPerformed(evt); + } + }); + toolBar.add(selectSouthTileBtn); + + drawCenterBtn.setText("show Center"); + drawCenterBtn.setFocusable(false); + drawCenterBtn.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER); + drawCenterBtn.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); + drawCenterBtn.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + drawCenterBtnActionPerformed(evt); + } + }); + toolBar.add(drawCenterBtn); + + greenRedBtn.setText("Red"); + greenRedBtn.setFocusable(false); + greenRedBtn.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER); + greenRedBtn.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); + greenRedBtn.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + greenRedBtnActionPerformed(evt); + } + }); + toolBar.add(greenRedBtn); + + toolbarPanel.add(toolBar); + + getContentPane().add(toolbarPanel, java.awt.BorderLayout.NORTH); + + dotGridCanvas.setPreferredSize(new java.awt.Dimension(360, 360)); + getContentPane().add(dotGridCanvas, java.awt.BorderLayout.CENTER); + + pack(); + }// //GEN-END:initComponents + + private void northTileBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_northTileBtnActionPerformed + Logger.trace(signal2North.id + "..."); + this.signal2North.setDrawRoute(this.northTileBtn.isSelected()); + }//GEN-LAST:event_northTileBtnActionPerformed + + private void eastTileBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_eastTileBtnActionPerformed + this.signal2East.setDrawRoute(this.eastTileBtn.isSelected()); + }//GEN-LAST:event_eastTileBtnActionPerformed + + private void westTileBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_westTileBtnActionPerformed + this.signal2West.setDrawRoute(this.westTileBtn.isSelected()); + }//GEN-LAST:event_westTileBtnActionPerformed + + private void southTileBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_southTileBtnActionPerformed + this.signal2South.setDrawRoute(this.southTileBtn.isSelected()); + }//GEN-LAST:event_southTileBtnActionPerformed + + private void selectSouthTileBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_selectSouthTileBtnActionPerformed + this.signal2South.setSelected(this.selectSouthTileBtn.isSelected()); + }//GEN-LAST:event_selectSouthTileBtnActionPerformed + + private void drawCenterBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_drawCenterBtnActionPerformed + this.signal2North.setDrawCenterPoint(this.drawCenterBtn.isSelected()); + }//GEN-LAST:event_drawCenterBtnActionPerformed + + private void greenRedBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_greenRedBtnActionPerformed + boolean red = this.greenRedBtn.isSelected(); + if (red) { + this.greenRedBtn.setText("Green"); + this.signal2East.setSignalValue(AccessoryBean.SignalValue.Hp0); + this.signal2MEast.setSignalValue(AccessoryBean.SignalValue.Hp0); + } else { + this.greenRedBtn.setText("Red"); + this.signal2East.setSignalValue(AccessoryBean.SignalValue.Hp1); + this.signal2MEast.setSignalValue(AccessoryBean.SignalValue.Hp1); + } + }//GEN-LAST:event_greenRedBtnActionPerformed + /** + * @param args the command line arguments + */ + public static void main(String args[]) { try { UIManager.setLookAndFeel("com.formdev.flatlaf.FlatLightLaf"); + SignalTileTester.setDefaultLookAndFeelDecorated(true); + } catch (ClassNotFoundException | InstantiationException | IllegalAccessException @@ -194,16 +322,26 @@ public static void main(String args[]) { Logger.error(ex); } - SignalTileTester app = new SignalTileTester("Signal Tile Tester"); - - Dimension dim = Toolkit.getDefaultToolkit().getScreenSize(); - app.setSize(400, 250); - - app.setLocation( - dim.width / 2 - app.getSize().width / 2, dim.height / 2 - app.getSize().height / 2); - - app.setVisible(true); - - app.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + /* Create and display the form */ + java.awt.EventQueue.invokeLater(() -> { + SignalTileTester app = new SignalTileTester("Signal Tile Tester"); + app.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + Dimension dim = Toolkit.getDefaultToolkit().getScreenSize(); + app.setLocation(dim.width / 2 - app.getSize().width / 2, dim.height / 2 - app.getSize().height / 2); + app.pack(); + }); } + + // Variables declaration - do not modify//GEN-BEGIN:variables + private jcs.ui.layout.tiles.DotGridCanvas dotGridCanvas; + private javax.swing.JToggleButton drawCenterBtn; + private javax.swing.JToggleButton eastTileBtn; + private javax.swing.JToggleButton greenRedBtn; + private javax.swing.JToggleButton northTileBtn; + private javax.swing.JToggleButton selectSouthTileBtn; + private javax.swing.JToggleButton southTileBtn; + private javax.swing.JToolBar toolBar; + private javax.swing.JPanel toolbarPanel; + private javax.swing.JToggleButton westTileBtn; + // End of variables declaration//GEN-END:variables } diff --git a/src/test/java/jcs/ui/layout/tiles/StraightDirectionTileTester.form b/src/test/java/jcs/ui/layout/tiles/StraightDirectionTileTester.form new file mode 100644 index 00000000..eade3117 --- /dev/null +++ b/src/test/java/jcs/ui/layout/tiles/StraightDirectionTileTester.form @@ -0,0 +1,197 @@ + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/test/java/jcs/ui/layout/tiles/StraightDirectionTileTester.java b/src/test/java/jcs/ui/layout/tiles/StraightDirectionTileTester.java index a72eaaf2..138f32c2 100644 --- a/src/test/java/jcs/ui/layout/tiles/StraightDirectionTileTester.java +++ b/src/test/java/jcs/ui/layout/tiles/StraightDirectionTileTester.java @@ -1,5 +1,5 @@ /* - * Copyright 2023 Frans Jacobs. + * Copyright 2025 Frans Jacobs. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -17,76 +17,219 @@ import java.awt.Color; import java.awt.Dimension; -import java.awt.Graphics; -import java.awt.Graphics2D; import java.awt.Toolkit; import javax.swing.JFrame; import javax.swing.UIManager; import javax.swing.UnsupportedLookAndFeelException; -import jcs.entities.TileBean.Orientation; +import jcs.entities.TileBean; import org.tinylog.Logger; -/** - * @author Frans Jacobs - */ -public class StraightDirectionTileTester extends JFrame { +public class StraightDirectionTileTester extends javax.swing.JFrame { - private final Tile trackEast; - private final Tile trackSouth; - private final Tile trackWest; - private final Tile trackNorth; + private Tile trackEast; + private Tile trackSouth; + private Tile trackWest; + private Tile trackNorth; + /** + * Creates new form TileTester + * + * @param title + */ public StraightDirectionTileTester(String title) { super(title); + initComponents(); + + createTiles(); - trackEast = new StraightDirection(Orientation.EAST, 70, 60); - trackSouth = new StraightDirection(Orientation.SOUTH, 160, 60); - trackWest = new StraightDirection(Orientation.WEST, 250, 60); - trackNorth = new StraightDirection(Orientation.NORTH, 340, 60); + this.setVisible(true); } - @Override - public void paint(Graphics g) { - Graphics2D g2d = (Graphics2D) g; + private void createTiles() { + + trackEast = new StraightDirection(TileBean.Orientation.EAST, 40, 40); + trackEast.setId("east"); + trackEast.setTrackRouteColor(Color.MAGENTA); - trackEast.drawTile(g2d, false); - trackEast.drawBounds(g2d); - trackEast.drawCenterPoint(g2d, Color.red); + trackSouth = new StraightDirection(TileBean.Orientation.SOUTH, 120, 40); + trackSouth.setId("south"); + trackSouth.setTrackRouteColor(Color.YELLOW); - trackSouth.drawTile(g2d, false); - trackSouth.drawBounds(g2d); - trackSouth.drawCenterPoint(g2d, Color.blue); + trackWest = new StraightDirection(TileBean.Orientation.WEST, 200, 40); + trackWest.setId("west"); + trackWest.setTrackRouteColor(Color.CYAN); - trackWest.drawTile(g2d, false); - trackWest.drawBounds(g2d); - trackWest.drawCenterPoint(g2d, Color.red); + trackNorth = new StraightDirection(TileBean.Orientation.NORTH, 280, 40); + trackNorth.setId("north"); + trackNorth.setTrackRouteColor(Color.blue); - trackNorth.drawTile(g2d, false); - trackNorth.drawBounds(g2d); - trackNorth.drawCenterPoint(g2d, Color.cyan); + dotGridCanvas.add(trackEast); + + dotGridCanvas.add(trackSouth); + dotGridCanvas.add(trackWest); + dotGridCanvas.add(trackNorth); } + /** + * This method is called from within the constructor to initialize the form. WARNING: Do NOT modify this code. The content of this method is always regenerated by the Form Editor. + */ + @SuppressWarnings("unchecked") + // //GEN-BEGIN:initComponents + private void initComponents() { + + toolbarPanel = new javax.swing.JPanel(); + toolBar = new javax.swing.JToolBar(); + eastTileBtn = new javax.swing.JToggleButton(); + southTileBtn = new javax.swing.JToggleButton(); + westTileBtn = new javax.swing.JToggleButton(); + northTileBtn = new javax.swing.JToggleButton(); + selectSouthTileBtn = new javax.swing.JToggleButton(); + drawCenterBtn = new javax.swing.JToggleButton(); + dotGridCanvas = new jcs.ui.layout.tiles.DotGridCanvas(); + + setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE); + + java.awt.FlowLayout flowLayout1 = new java.awt.FlowLayout(java.awt.FlowLayout.LEFT); + flowLayout1.setAlignOnBaseline(true); + toolbarPanel.setLayout(flowLayout1); + + toolBar.setRollover(true); + + eastTileBtn.setText("East"); + eastTileBtn.setFocusable(false); + eastTileBtn.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER); + eastTileBtn.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); + eastTileBtn.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + eastTileBtnActionPerformed(evt); + } + }); + toolBar.add(eastTileBtn); + + southTileBtn.setText("South"); + southTileBtn.setFocusable(false); + southTileBtn.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER); + southTileBtn.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); + southTileBtn.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + southTileBtnActionPerformed(evt); + } + }); + toolBar.add(southTileBtn); + + westTileBtn.setText("West"); + westTileBtn.setFocusable(false); + westTileBtn.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER); + westTileBtn.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); + westTileBtn.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + westTileBtnActionPerformed(evt); + } + }); + toolBar.add(westTileBtn); + + northTileBtn.setText("North"); + northTileBtn.setFocusable(false); + northTileBtn.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER); + northTileBtn.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); + northTileBtn.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + northTileBtnActionPerformed(evt); + } + }); + toolBar.add(northTileBtn); + + selectSouthTileBtn.setText("Select Tile"); + selectSouthTileBtn.setFocusable(false); + selectSouthTileBtn.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER); + selectSouthTileBtn.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); + selectSouthTileBtn.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + selectSouthTileBtnActionPerformed(evt); + } + }); + toolBar.add(selectSouthTileBtn); + + drawCenterBtn.setText("show Center"); + drawCenterBtn.setFocusable(false); + drawCenterBtn.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER); + drawCenterBtn.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); + drawCenterBtn.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + drawCenterBtnActionPerformed(evt); + } + }); + toolBar.add(drawCenterBtn); + + toolbarPanel.add(toolBar); + + getContentPane().add(toolbarPanel, java.awt.BorderLayout.NORTH); + + dotGridCanvas.setPreferredSize(new java.awt.Dimension(360, 120)); + getContentPane().add(dotGridCanvas, java.awt.BorderLayout.CENTER); + + pack(); + }// //GEN-END:initComponents + + private void northTileBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_northTileBtnActionPerformed + Logger.trace(trackNorth.id + "..."); + this.trackNorth.setDrawRoute(this.northTileBtn.isSelected()); + }//GEN-LAST:event_northTileBtnActionPerformed + + private void eastTileBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_eastTileBtnActionPerformed + this.trackEast.setDrawRoute(this.eastTileBtn.isSelected()); + }//GEN-LAST:event_eastTileBtnActionPerformed + + private void westTileBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_westTileBtnActionPerformed + this.trackWest.setDrawRoute(this.westTileBtn.isSelected()); + }//GEN-LAST:event_westTileBtnActionPerformed + + private void southTileBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_southTileBtnActionPerformed + this.trackSouth.setDrawRoute(this.southTileBtn.isSelected()); + }//GEN-LAST:event_southTileBtnActionPerformed + + private void selectSouthTileBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_selectSouthTileBtnActionPerformed + this.trackSouth.setSelected(this.selectSouthTileBtn.isSelected()); + }//GEN-LAST:event_selectSouthTileBtnActionPerformed + + private void drawCenterBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_drawCenterBtnActionPerformed + this.trackNorth.setDrawCenterPoint(this.drawCenterBtn.isSelected()); + }//GEN-LAST:event_drawCenterBtnActionPerformed + + /** + * @param args the command line arguments + */ public static void main(String args[]) { - try { UIManager.setLookAndFeel("com.formdev.flatlaf.FlatLightLaf"); + StraightDirectionTileTester.setDefaultLookAndFeelDecorated(true); + } catch (ClassNotFoundException - | InstantiationException - | IllegalAccessException - | UnsupportedLookAndFeelException ex) { + | InstantiationException + | IllegalAccessException + | UnsupportedLookAndFeelException ex) { Logger.error(ex); } - StraightDirectionTileTester app = new StraightDirectionTileTester("Straight Tile Tester"); - - Dimension dim = Toolkit.getDefaultToolkit().getScreenSize(); - app.setSize(400, 100); - - app.setLocation( - dim.width / 2 - app.getSize().width / 2, dim.height / 2 - app.getSize().height / 2); - - app.setVisible(true); - - app.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + /* Create and display the form */ + java.awt.EventQueue.invokeLater(() -> { + StraightDirectionTileTester app = new StraightDirectionTileTester("StraightDirTile Tester"); + app.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + Dimension dim = Toolkit.getDefaultToolkit().getScreenSize(); + app.setLocation(dim.width / 2 - app.getSize().width / 2, dim.height / 2 - app.getSize().height / 2); + app.pack(); + }); } + + // Variables declaration - do not modify//GEN-BEGIN:variables + private jcs.ui.layout.tiles.DotGridCanvas dotGridCanvas; + private javax.swing.JToggleButton drawCenterBtn; + private javax.swing.JToggleButton eastTileBtn; + private javax.swing.JToggleButton northTileBtn; + private javax.swing.JToggleButton selectSouthTileBtn; + private javax.swing.JToggleButton southTileBtn; + private javax.swing.JToolBar toolBar; + private javax.swing.JPanel toolbarPanel; + private javax.swing.JToggleButton westTileBtn; + // End of variables declaration//GEN-END:variables } diff --git a/src/test/java/jcs/ui/layout/tiles/StraightTileTester.form b/src/test/java/jcs/ui/layout/tiles/StraightTileTester.form new file mode 100644 index 00000000..eade3117 --- /dev/null +++ b/src/test/java/jcs/ui/layout/tiles/StraightTileTester.form @@ -0,0 +1,197 @@ + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/test/java/jcs/ui/layout/tiles/StraightTileTester.java b/src/test/java/jcs/ui/layout/tiles/StraightTileTester.java index 39e88cf9..0a383d3b 100644 --- a/src/test/java/jcs/ui/layout/tiles/StraightTileTester.java +++ b/src/test/java/jcs/ui/layout/tiles/StraightTileTester.java @@ -1,5 +1,5 @@ /* - * Copyright 2023 Frans Jacobs. + * Copyright 2025 Frans Jacobs. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -17,76 +17,220 @@ import java.awt.Color; import java.awt.Dimension; -import java.awt.Graphics; -import java.awt.Graphics2D; import java.awt.Toolkit; import javax.swing.JFrame; import javax.swing.UIManager; import javax.swing.UnsupportedLookAndFeelException; -import jcs.entities.TileBean.Orientation; +import jcs.entities.TileBean; import org.tinylog.Logger; -/** - * @author Frans Jacobs - */ -public class StraightTileTester extends JFrame { +public class StraightTileTester extends javax.swing.JFrame { - private final Tile trackEast; - private final Tile trackSouth; - private final Tile trackWest; - private final Tile trackNorth; + private Tile trackEast; + private Tile trackSouth; + private Tile trackWest; + private Tile trackNorth; + /** + * Creates new form TileTester + * + * @param title + */ public StraightTileTester(String title) { super(title); + initComponents(); + + createTiles(); - trackEast = new Straight(Orientation.EAST, 70, 60); - trackSouth = new Straight(Orientation.SOUTH, 160, 60); - trackWest = new Straight(Orientation.WEST, 250, 60); - trackNorth = new Straight(Orientation.NORTH, 340, 60); + this.setVisible(true); } - @Override - public void paint(Graphics g) { - Graphics2D g2d = (Graphics2D) g; + private void createTiles() { + + trackEast = new Straight(TileBean.Orientation.EAST, 40, 40); + trackEast.setId("east"); + trackEast.setTrackRouteColor(Color.MAGENTA); - trackEast.drawTile(g2d, false); - trackEast.drawBounds(g2d); - trackEast.drawCenterPoint(g2d, Color.red); + trackSouth = new Straight(TileBean.Orientation.SOUTH, 120, 40); + trackSouth.setId("south"); + trackSouth.setTrackRouteColor(Color.YELLOW); - trackSouth.drawTile(g2d, false); - trackSouth.drawBounds(g2d); - trackSouth.drawCenterPoint(g2d, Color.blue); + trackWest = new Straight(TileBean.Orientation.WEST, 200, 40); + trackWest.setId("west"); + trackWest.setTrackRouteColor(Color.CYAN); - trackWest.drawTile(g2d, false); - trackWest.drawBounds(g2d); - trackWest.drawCenterPoint(g2d, Color.red); + trackNorth = new Straight(TileBean.Orientation.NORTH, 280, 40); + trackNorth.setId("north"); + trackNorth.setTrackRouteColor(Color.blue); - trackNorth.drawTile(g2d, false); - trackNorth.drawBounds(g2d); - trackNorth.drawCenterPoint(g2d, Color.cyan); + dotGridCanvas.add(trackEast); + + dotGridCanvas.add(trackSouth); + dotGridCanvas.add(trackWest); + dotGridCanvas.add(trackNorth); } + /** + * This method is called from within the constructor to initialize the form. WARNING: Do NOT modify this code. The content of this method is always regenerated by the Form Editor. + */ + @SuppressWarnings("unchecked") + // //GEN-BEGIN:initComponents + private void initComponents() { + + toolbarPanel = new javax.swing.JPanel(); + toolBar = new javax.swing.JToolBar(); + eastTileBtn = new javax.swing.JToggleButton(); + southTileBtn = new javax.swing.JToggleButton(); + westTileBtn = new javax.swing.JToggleButton(); + northTileBtn = new javax.swing.JToggleButton(); + selectSouthTileBtn = new javax.swing.JToggleButton(); + drawCenterBtn = new javax.swing.JToggleButton(); + dotGridCanvas = new jcs.ui.layout.tiles.DotGridCanvas(); + + setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE); + + java.awt.FlowLayout flowLayout1 = new java.awt.FlowLayout(java.awt.FlowLayout.LEFT); + flowLayout1.setAlignOnBaseline(true); + toolbarPanel.setLayout(flowLayout1); + + toolBar.setRollover(true); + + eastTileBtn.setText("East"); + eastTileBtn.setFocusable(false); + eastTileBtn.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER); + eastTileBtn.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); + eastTileBtn.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + eastTileBtnActionPerformed(evt); + } + }); + toolBar.add(eastTileBtn); + + southTileBtn.setText("South"); + southTileBtn.setFocusable(false); + southTileBtn.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER); + southTileBtn.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); + southTileBtn.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + southTileBtnActionPerformed(evt); + } + }); + toolBar.add(southTileBtn); + + westTileBtn.setText("West"); + westTileBtn.setFocusable(false); + westTileBtn.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER); + westTileBtn.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); + westTileBtn.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + westTileBtnActionPerformed(evt); + } + }); + toolBar.add(westTileBtn); + + northTileBtn.setText("North"); + northTileBtn.setFocusable(false); + northTileBtn.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER); + northTileBtn.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); + northTileBtn.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + northTileBtnActionPerformed(evt); + } + }); + toolBar.add(northTileBtn); + + selectSouthTileBtn.setText("Select Tile"); + selectSouthTileBtn.setFocusable(false); + selectSouthTileBtn.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER); + selectSouthTileBtn.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); + selectSouthTileBtn.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + selectSouthTileBtnActionPerformed(evt); + } + }); + toolBar.add(selectSouthTileBtn); + + drawCenterBtn.setText("show Center"); + drawCenterBtn.setFocusable(false); + drawCenterBtn.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER); + drawCenterBtn.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); + drawCenterBtn.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + drawCenterBtnActionPerformed(evt); + } + }); + toolBar.add(drawCenterBtn); + + toolbarPanel.add(toolBar); + + getContentPane().add(toolbarPanel, java.awt.BorderLayout.NORTH); + + dotGridCanvas.setPreferredSize(new java.awt.Dimension(360, 120)); + getContentPane().add(dotGridCanvas, java.awt.BorderLayout.CENTER); + + pack(); + }// //GEN-END:initComponents + + private void northTileBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_northTileBtnActionPerformed + Logger.trace(trackNorth.id + "..."); + this.trackNorth.setDrawRoute(this.northTileBtn.isSelected()); + }//GEN-LAST:event_northTileBtnActionPerformed + + private void eastTileBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_eastTileBtnActionPerformed + this.trackEast.setDrawRoute(this.eastTileBtn.isSelected()); + }//GEN-LAST:event_eastTileBtnActionPerformed + + private void westTileBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_westTileBtnActionPerformed + this.trackWest.setDrawRoute(this.westTileBtn.isSelected()); + }//GEN-LAST:event_westTileBtnActionPerformed + + private void southTileBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_southTileBtnActionPerformed + this.trackSouth.setDrawRoute(this.southTileBtn.isSelected()); + }//GEN-LAST:event_southTileBtnActionPerformed + + private void selectSouthTileBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_selectSouthTileBtnActionPerformed + this.trackSouth.setSelected(this.selectSouthTileBtn.isSelected()); + }//GEN-LAST:event_selectSouthTileBtnActionPerformed + + private void drawCenterBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_drawCenterBtnActionPerformed + this.trackNorth.setDrawCenterPoint(this.drawCenterBtn.isSelected()); + this.trackEast.setDrawCenterPoint(this.drawCenterBtn.isSelected()); + }//GEN-LAST:event_drawCenterBtnActionPerformed + + /** + * @param args the command line arguments + */ public static void main(String args[]) { - try { UIManager.setLookAndFeel("com.formdev.flatlaf.FlatLightLaf"); + StraightTileTester.setDefaultLookAndFeelDecorated(true); + } catch (ClassNotFoundException - | InstantiationException - | IllegalAccessException - | UnsupportedLookAndFeelException ex) { + | InstantiationException + | IllegalAccessException + | UnsupportedLookAndFeelException ex) { Logger.error(ex); } - StraightTileTester app = new StraightTileTester("Straight Tile Tester"); - - Dimension dim = Toolkit.getDefaultToolkit().getScreenSize(); - app.setSize(400, 100); - - app.setLocation( - dim.width / 2 - app.getSize().width / 2, dim.height / 2 - app.getSize().height / 2); - - app.setVisible(true); - - app.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + /* Create and display the form */ + java.awt.EventQueue.invokeLater(() -> { + StraightTileTester app = new StraightTileTester("StraightTile Tester"); + app.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + Dimension dim = Toolkit.getDefaultToolkit().getScreenSize(); + app.setLocation(dim.width / 2 - app.getSize().width / 2, dim.height / 2 - app.getSize().height / 2); + app.pack(); + }); } + + // Variables declaration - do not modify//GEN-BEGIN:variables + private jcs.ui.layout.tiles.DotGridCanvas dotGridCanvas; + private javax.swing.JToggleButton drawCenterBtn; + private javax.swing.JToggleButton eastTileBtn; + private javax.swing.JToggleButton northTileBtn; + private javax.swing.JToggleButton selectSouthTileBtn; + private javax.swing.JToggleButton southTileBtn; + private javax.swing.JToolBar toolBar; + private javax.swing.JPanel toolbarPanel; + private javax.swing.JToggleButton westTileBtn; + // End of variables declaration//GEN-END:variables } diff --git a/src/test/java/jcs/ui/layout/tiles/SwitchTileTester.form b/src/test/java/jcs/ui/layout/tiles/SwitchTileTester.form new file mode 100644 index 00000000..4ea0ebf0 --- /dev/null +++ b/src/test/java/jcs/ui/layout/tiles/SwitchTileTester.form @@ -0,0 +1,208 @@ + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/test/java/jcs/ui/layout/tiles/SwitchTileTester.java b/src/test/java/jcs/ui/layout/tiles/SwitchTileTester.java index 1305ba3c..4b615a58 100644 --- a/src/test/java/jcs/ui/layout/tiles/SwitchTileTester.java +++ b/src/test/java/jcs/ui/layout/tiles/SwitchTileTester.java @@ -1,5 +1,5 @@ /* - * Copyright 2023 Frans Jacobs. + * Copyright 2025 Frans Jacobs. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -17,92 +17,284 @@ import java.awt.Color; import java.awt.Dimension; -import java.awt.Graphics; -import java.awt.Graphics2D; import java.awt.Toolkit; import javax.swing.JFrame; import javax.swing.UIManager; import javax.swing.UnsupportedLookAndFeelException; import jcs.entities.AccessoryBean.AccessoryValue; -import jcs.entities.TileBean.Direction; -import jcs.entities.TileBean.Orientation; +import jcs.entities.TileBean; import org.tinylog.Logger; -/** - * @author Frans Jacobs - */ -public class SwitchTileTester extends JFrame { +public class SwitchTileTester extends javax.swing.JFrame { - private final Tile switchEastR; - private final Tile switchSouthR; - private final Tile switchWestR; - private final Tile switchNorthR; + private Tile switchEastR; + private Tile switchSouthR; + private Tile switchWestR; + private Tile switchNorthR; - private final Tile switchEastL; - private final Tile switchSouthL; - private final Tile switchWestL; - private final Tile switchNorthL; + private Tile switchEastL; + private Tile switchSouthL; + private Tile switchWestL; + private Tile switchNorthL; + /** + * Creates new form TileTester + * + * @param title + */ public SwitchTileTester(String title) { super(title); + initComponents(); - switchEastR = new Switch(Orientation.EAST, Direction.RIGHT, 70, 60); - switchSouthR = new Switch(Orientation.SOUTH, Direction.RIGHT, 160, 60); - switchWestR = new Switch(Orientation.WEST, Direction.RIGHT, 250, 60); - switchNorthR = new Switch(Orientation.NORTH, Direction.RIGHT, 340, 60); + createTiles(); - switchEastL = new Switch(Orientation.EAST, Direction.LEFT, 70, 110); - switchSouthL = new Switch(Orientation.SOUTH, Direction.LEFT, 160, 110); - switchWestL = new Switch(Orientation.WEST, Direction.LEFT, 250, 110); - switchNorthL = new Switch(Orientation.NORTH, Direction.LEFT, 340, 110); + this.setVisible(true); } - @Override - public void paint(Graphics g) { - Graphics2D g2d = (Graphics2D) g; - - switchEastR.drawTile(g2d, true); - switchEastR.drawBounds(g2d); - switchEastR.drawCenterPoint(g2d, Color.red); - ((Switch) switchEastR).setValue(AccessoryValue.RED); - - switchSouthR.drawTile(g2d, false); - switchSouthR.drawBounds(g2d); - switchSouthR.drawCenterPoint(g2d, Color.blue); - - switchWestR.drawTile(g2d, true); - switchWestR.drawBounds(g2d); - switchWestR.drawCenterPoint(g2d, Color.red); - ((Switch) switchWestR).setValue(AccessoryValue.GREEN); - - switchNorthR.drawTile(g2d, false); - switchNorthR.drawBounds(g2d); - switchNorthR.drawCenterPoint(g2d, Color.cyan); - // - switchEastL.drawTile(g2d, false); - switchEastL.drawBounds(g2d); - switchEastL.drawCenterPoint(g2d, Color.red); - - switchSouthL.drawTile(g2d, true); - switchSouthL.drawBounds(g2d); - switchSouthL.drawCenterPoint(g2d, Color.blue); - ((Switch) switchSouthL).setValue(AccessoryValue.GREEN); - - switchWestL.drawTile(g2d, false); - switchWestL.drawBounds(g2d); - switchWestL.drawCenterPoint(g2d, Color.red); - - switchNorthL.drawTile(g2d, true); - switchNorthL.drawBounds(g2d); - switchNorthL.drawCenterPoint(g2d, Color.cyan); - ((Switch) switchNorthL).setValue(AccessoryValue.RED); + private void createTiles() { + + switchEastR = new Switch(TileBean.Orientation.EAST, TileBean.Direction.RIGHT, 40, 40); + switchEastR.setId("eastR"); + switchEastR.setTrackRouteColor(Color.MAGENTA); + switchEastR.setRouteValue(AccessoryValue.GREEN); + + switchSouthR = new Switch(TileBean.Orientation.SOUTH, TileBean.Direction.RIGHT, 120, 40); + switchSouthR.setId("southR"); + switchSouthR.setTrackRouteColor(Color.YELLOW); + switchSouthR.setRouteValue(AccessoryValue.RED); + + switchWestR = new Switch(TileBean.Orientation.WEST, TileBean.Direction.RIGHT, 200, 40); + switchWestR.setId("westR"); + switchWestR.setTrackRouteColor(Color.CYAN); + + switchNorthR = new Switch(TileBean.Orientation.NORTH, TileBean.Direction.RIGHT, 280, 40); + switchNorthR.setId("northR"); + switchNorthR.setTrackRouteColor(Color.blue); + switchNorthR.setRouteValue(AccessoryValue.GREEN); + +// switchEastR = new Switch(TileBean.Orientation.EAST, TileBean.Direction.RIGHT, 70, 60); +// switchSouthR = new Switch(TileBean.Orientation.SOUTH, TileBean.Direction.RIGHT, 160, 60); +// switchWestR = new Switch(TileBean.Orientation.WEST, TileBean.Direction.RIGHT, 250, 60); +// switchNorthR = new Switch(TileBean.Orientation.NORTH, TileBean.Direction.RIGHT, 340, 60); +// switchEastL = new Switch(TileBean.Orientation.EAST, TileBean.Direction.LEFT, 70, 110); +// switchSouthL = new Switch(TileBean.Orientation.SOUTH, TileBean.Direction.LEFT, 160, 110); +// switchWestL = new Switch(TileBean.Orientation.WEST, TileBean.Direction.LEFT, 250, 110); +// switchNorthL = new Switch(TileBean.Orientation.NORTH, TileBean.Direction.LEFT, 340, 110); + switchEastL = new Switch(TileBean.Orientation.EAST, TileBean.Direction.LEFT, 40, 120); + switchEastL.setId("eastR"); + switchEastL.setTrackRouteColor(Color.MAGENTA); + switchEastL.setRouteValue(AccessoryValue.GREEN); + + switchSouthL = new Switch(TileBean.Orientation.SOUTH, TileBean.Direction.LEFT, 120, 120); + switchSouthL.setId("southR"); + switchSouthL.setTrackRouteColor(Color.YELLOW); + switchSouthL.setRouteValue(AccessoryValue.RED); + + switchWestL = new Switch(TileBean.Orientation.WEST, TileBean.Direction.LEFT, 200, 120); + switchWestL.setId("westR"); + switchWestL.setTrackRouteColor(Color.CYAN); + + switchNorthL = new Switch(TileBean.Orientation.NORTH, TileBean.Direction.LEFT, 280, 120); + switchNorthL.setId("northR"); + switchNorthL.setTrackRouteColor(Color.blue); + switchNorthL.setRouteValue(AccessoryValue.GREEN); + + dotGridCanvas.add(switchEastR); + dotGridCanvas.add(switchSouthR); + dotGridCanvas.add(switchWestR); + dotGridCanvas.add(switchNorthR); + + dotGridCanvas.add(switchEastL); + dotGridCanvas.add(switchSouthL); + dotGridCanvas.add(switchWestL); + dotGridCanvas.add(switchNorthL); } - public static void main(String args[]) { + /** + * This method is called from within the constructor to initialize the form. WARNING: Do NOT modify this code. The content of this method is always regenerated by the Form Editor. + */ + @SuppressWarnings("unchecked") + // //GEN-BEGIN:initComponents + private void initComponents() { + + toolbarPanel = new javax.swing.JPanel(); + toolBar = new javax.swing.JToolBar(); + eastTileBtn = new javax.swing.JToggleButton(); + southTileBtn = new javax.swing.JToggleButton(); + westTileBtn = new javax.swing.JToggleButton(); + northTileBtn = new javax.swing.JToggleButton(); + selectSouthTileBtn = new javax.swing.JToggleButton(); + drawCenterBtn = new javax.swing.JToggleButton(); + greenRedBtn = new javax.swing.JToggleButton(); + dotGridCanvas = new jcs.ui.layout.tiles.DotGridCanvas(); + + setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE); + + java.awt.FlowLayout flowLayout1 = new java.awt.FlowLayout(java.awt.FlowLayout.LEFT); + flowLayout1.setAlignOnBaseline(true); + toolbarPanel.setLayout(flowLayout1); + + toolBar.setRollover(true); + + eastTileBtn.setText("East"); + eastTileBtn.setFocusable(false); + eastTileBtn.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER); + eastTileBtn.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); + eastTileBtn.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + eastTileBtnActionPerformed(evt); + } + }); + toolBar.add(eastTileBtn); + + southTileBtn.setText("South"); + southTileBtn.setFocusable(false); + southTileBtn.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER); + southTileBtn.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); + southTileBtn.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + southTileBtnActionPerformed(evt); + } + }); + toolBar.add(southTileBtn); + + westTileBtn.setText("West"); + westTileBtn.setFocusable(false); + westTileBtn.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER); + westTileBtn.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); + westTileBtn.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + westTileBtnActionPerformed(evt); + } + }); + toolBar.add(westTileBtn); + + northTileBtn.setText("North"); + northTileBtn.setFocusable(false); + northTileBtn.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER); + northTileBtn.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); + northTileBtn.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + northTileBtnActionPerformed(evt); + } + }); + toolBar.add(northTileBtn); + + selectSouthTileBtn.setText("Select Tile"); + selectSouthTileBtn.setFocusable(false); + selectSouthTileBtn.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER); + selectSouthTileBtn.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); + selectSouthTileBtn.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + selectSouthTileBtnActionPerformed(evt); + } + }); + toolBar.add(selectSouthTileBtn); + + drawCenterBtn.setText("show Center"); + drawCenterBtn.setFocusable(false); + drawCenterBtn.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER); + drawCenterBtn.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); + drawCenterBtn.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + drawCenterBtnActionPerformed(evt); + } + }); + toolBar.add(drawCenterBtn); + + greenRedBtn.setText("Red"); + greenRedBtn.setFocusable(false); + greenRedBtn.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER); + greenRedBtn.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); + greenRedBtn.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + greenRedBtnActionPerformed(evt); + } + }); + toolBar.add(greenRedBtn); + + toolbarPanel.add(toolBar); + getContentPane().add(toolbarPanel, java.awt.BorderLayout.NORTH); + + dotGridCanvas.setPreferredSize(new java.awt.Dimension(360, 200)); + getContentPane().add(dotGridCanvas, java.awt.BorderLayout.CENTER); + + pack(); + }// //GEN-END:initComponents + + private void northTileBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_northTileBtnActionPerformed + Logger.trace(switchNorthR.id + "..."); + this.switchNorthR.setDrawRoute(this.northTileBtn.isSelected()); + this.switchNorthL.setDrawRoute(this.northTileBtn.isSelected()); + }//GEN-LAST:event_northTileBtnActionPerformed + + private void eastTileBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_eastTileBtnActionPerformed + this.switchEastR.setDrawRoute(this.eastTileBtn.isSelected()); + this.switchEastL.setDrawRoute(this.eastTileBtn.isSelected()); + }//GEN-LAST:event_eastTileBtnActionPerformed + + private void westTileBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_westTileBtnActionPerformed + this.switchWestR.setDrawRoute(this.westTileBtn.isSelected()); + this.switchWestL.setDrawRoute(this.westTileBtn.isSelected()); + }//GEN-LAST:event_westTileBtnActionPerformed + + private void southTileBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_southTileBtnActionPerformed + this.switchSouthR.setDrawRoute(this.southTileBtn.isSelected()); + this.switchSouthL.setDrawRoute(this.southTileBtn.isSelected()); + }//GEN-LAST:event_southTileBtnActionPerformed + + private void selectSouthTileBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_selectSouthTileBtnActionPerformed + this.switchSouthR.setSelected(this.selectSouthTileBtn.isSelected()); + this.switchSouthL.setSelected(this.selectSouthTileBtn.isSelected()); + }//GEN-LAST:event_selectSouthTileBtnActionPerformed + + private void drawCenterBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_drawCenterBtnActionPerformed + this.switchNorthR.setDrawCenterPoint(this.drawCenterBtn.isSelected()); + this.switchEastL.setDrawCenterPoint(this.drawCenterBtn.isSelected()); + }//GEN-LAST:event_drawCenterBtnActionPerformed + + private void greenRedBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_greenRedBtnActionPerformed + boolean red = this.greenRedBtn.isSelected(); + if (red) { + this.greenRedBtn.setText("Green"); + if (this.westTileBtn.isSelected()) { + this.switchWestR.setAccessoryValue(AccessoryValue.OFF); + this.switchWestR.setRouteValue(AccessoryValue.GREEN); + + this.switchWestL.setAccessoryValue(AccessoryValue.OFF); + this.switchWestL.setRouteValue(AccessoryValue.GREEN); + + } else { + this.switchWestR.setAccessoryValue(AccessoryValue.GREEN); + + this.switchWestL.setAccessoryValue(AccessoryValue.GREEN); + } + } else { + this.greenRedBtn.setText("Red"); + if (this.westTileBtn.isSelected()) { + this.switchWestR.setAccessoryValue(AccessoryValue.OFF); + this.switchWestR.setRouteValue(AccessoryValue.RED); + + this.switchWestL.setAccessoryValue(AccessoryValue.OFF); + this.switchWestL.setRouteValue(AccessoryValue.RED); + } else { + this.switchWestR.setAccessoryValue(AccessoryValue.RED); + + this.switchWestL.setAccessoryValue(AccessoryValue.RED); + } + } + }//GEN-LAST:event_greenRedBtnActionPerformed + + /** + * @param args the command line arguments + */ + public static void main(String args[]) { try { UIManager.setLookAndFeel("com.formdev.flatlaf.FlatLightLaf"); + SwitchTileTester.setDefaultLookAndFeelDecorated(true); + } catch (ClassNotFoundException | InstantiationException | IllegalAccessException @@ -110,16 +302,26 @@ public static void main(String args[]) { Logger.error(ex); } - SwitchTileTester app = new SwitchTileTester("Turnout Tile Tester"); - - Dimension dim = Toolkit.getDefaultToolkit().getScreenSize(); - app.setSize(400, 150); - - app.setLocation( - dim.width / 2 - app.getSize().width / 2, dim.height / 2 - app.getSize().height / 2); - - app.setVisible(true); - - app.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + /* Create and display the form */ + java.awt.EventQueue.invokeLater(() -> { + SwitchTileTester app = new SwitchTileTester("Switch Tile Tester"); + app.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + Dimension dim = Toolkit.getDefaultToolkit().getScreenSize(); + app.setLocation(dim.width / 2 - app.getSize().width / 2, dim.height / 2 - app.getSize().height / 2); + app.pack(); + }); } + + // Variables declaration - do not modify//GEN-BEGIN:variables + private jcs.ui.layout.tiles.DotGridCanvas dotGridCanvas; + private javax.swing.JToggleButton drawCenterBtn; + private javax.swing.JToggleButton eastTileBtn; + private javax.swing.JToggleButton greenRedBtn; + private javax.swing.JToggleButton northTileBtn; + private javax.swing.JToggleButton selectSouthTileBtn; + private javax.swing.JToggleButton southTileBtn; + private javax.swing.JToolBar toolBar; + private javax.swing.JPanel toolbarPanel; + private javax.swing.JToggleButton westTileBtn; + // End of variables declaration//GEN-END:variables } diff --git a/src/test/java/jcs/ui/layout/tiles/TileTester.form b/src/test/java/jcs/ui/layout/tiles/TileTester.form new file mode 100644 index 00000000..2d98e3fa --- /dev/null +++ b/src/test/java/jcs/ui/layout/tiles/TileTester.form @@ -0,0 +1,175 @@ + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/test/java/jcs/ui/layout/tiles/TileTester.java b/src/test/java/jcs/ui/layout/tiles/TileTester.java new file mode 100644 index 00000000..6485baf5 --- /dev/null +++ b/src/test/java/jcs/ui/layout/tiles/TileTester.java @@ -0,0 +1,170 @@ +/* + * Copyright 2025 fransjacobs. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package jcs.ui.layout.tiles; + +import java.awt.Dimension; +import java.awt.Toolkit; +import javax.swing.JFrame; +import javax.swing.UIManager; +import javax.swing.UnsupportedLookAndFeelException; +import org.tinylog.Logger; + +/** + * + * @author fransjacobs + */ +public class TileTester extends javax.swing.JFrame { + + /** + * Creates new form TileTester + * @param title + */ + public TileTester(String title) { + super(title); + initComponents(); + + this.setVisible(true); + } + + /** + * This method is called from within the constructor to initialize the form. WARNING: Do NOT modify this code. The content of this method is always regenerated by the Form Editor. + */ + @SuppressWarnings("unchecked") + // //GEN-BEGIN:initComponents + private void initComponents() { + + toolbarPanel = new javax.swing.JPanel(); + toolBar = new javax.swing.JToolBar(); + northTileBtn = new javax.swing.JToggleButton(); + eastTileBtn = new javax.swing.JToggleButton(); + westTileBtn = new javax.swing.JToggleButton(); + southTileBtn = new javax.swing.JToggleButton(); + dotGridCanvas = new jcs.ui.layout.tiles.DotGridCanvas(); + + setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE); + + java.awt.FlowLayout flowLayout1 = new java.awt.FlowLayout(java.awt.FlowLayout.LEFT); + flowLayout1.setAlignOnBaseline(true); + toolbarPanel.setLayout(flowLayout1); + + toolBar.setRollover(true); + + northTileBtn.setText("North"); + northTileBtn.setFocusable(false); + northTileBtn.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER); + northTileBtn.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); + northTileBtn.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + northTileBtnActionPerformed(evt); + } + }); + toolBar.add(northTileBtn); + + eastTileBtn.setText("East"); + eastTileBtn.setFocusable(false); + eastTileBtn.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER); + eastTileBtn.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); + eastTileBtn.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + eastTileBtnActionPerformed(evt); + } + }); + toolBar.add(eastTileBtn); + + westTileBtn.setText("West"); + westTileBtn.setFocusable(false); + westTileBtn.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER); + westTileBtn.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); + westTileBtn.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + westTileBtnActionPerformed(evt); + } + }); + toolBar.add(westTileBtn); + + southTileBtn.setText("South"); + southTileBtn.setFocusable(false); + southTileBtn.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER); + southTileBtn.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); + southTileBtn.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + southTileBtnActionPerformed(evt); + } + }); + toolBar.add(southTileBtn); + + toolbarPanel.add(toolBar); + + getContentPane().add(toolbarPanel, java.awt.BorderLayout.NORTH); + + dotGridCanvas.setPreferredSize(new java.awt.Dimension(360, 120)); + getContentPane().add(dotGridCanvas, java.awt.BorderLayout.CENTER); + + pack(); + }// //GEN-END:initComponents + + private void northTileBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_northTileBtnActionPerformed + // TODO add your handling code here: + }//GEN-LAST:event_northTileBtnActionPerformed + + private void eastTileBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_eastTileBtnActionPerformed + // TODO add your handling code here: + }//GEN-LAST:event_eastTileBtnActionPerformed + + private void westTileBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_westTileBtnActionPerformed + // TODO add your handling code here: + }//GEN-LAST:event_westTileBtnActionPerformed + + private void southTileBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_southTileBtnActionPerformed + // TODO add your handling code here: + }//GEN-LAST:event_southTileBtnActionPerformed + + /** + * @param args the command line arguments + */ + public static void main(String args[]) { + try { + UIManager.setLookAndFeel("com.formdev.flatlaf.FlatLightLaf"); + TileTester.setDefaultLookAndFeelDecorated(true); + + } catch (ClassNotFoundException + | InstantiationException + | IllegalAccessException + | UnsupportedLookAndFeelException ex) { + Logger.error(ex); + } + + /* Create and display the form */ + java.awt.EventQueue.invokeLater(() -> { + TileTester app = new TileTester("Tile Tester"); + app.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + Dimension dim = Toolkit.getDefaultToolkit().getScreenSize(); + //app.setPreferredSize(new Dimension(360, 150)); + app.setLocation(dim.width / 2 - app.getSize().width / 2, dim.height / 2 - app.getSize().height / 2); + app.pack(); + }); + } + + // Variables declaration - do not modify//GEN-BEGIN:variables + private jcs.ui.layout.tiles.DotGridCanvas dotGridCanvas; + private javax.swing.JToggleButton eastTileBtn; + private javax.swing.JToggleButton northTileBtn; + private javax.swing.JToggleButton southTileBtn; + private javax.swing.JToolBar toolBar; + private javax.swing.JPanel toolbarPanel; + private javax.swing.JToggleButton westTileBtn; + // End of variables declaration//GEN-END:variables +} diff --git a/src/test/java/jcs/ui/layout/tiles/UnscaledBlockCanvas.java b/src/test/java/jcs/ui/layout/tiles/UnscaledBlockCanvas.java index 92b2c3cc..dc8f3998 100644 --- a/src/test/java/jcs/ui/layout/tiles/UnscaledBlockCanvas.java +++ b/src/test/java/jcs/ui/layout/tiles/UnscaledBlockCanvas.java @@ -17,7 +17,6 @@ import java.awt.Color; import java.awt.Dimension; -import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.Point; import java.awt.image.BufferedImage; @@ -39,6 +38,7 @@ public UnscaledBlockCanvas() { public void addTile(Tile block) { this.tiles.add(block); + this.add(block); } public boolean isShowCenter() { @@ -57,7 +57,7 @@ private Dimension getMinCanvasSize() { for (Tile tile : this.tiles) { Point tc = tile.getCenter(); - boolean expand = !((AbstractTile) tile).isScaleImage(); + boolean expand = !tile.isScaleImage(); int tw = tile.getWidth() * (expand ? 10 : 1); int th = tile.getHeight() * (expand ? 10 : 1); @@ -131,9 +131,9 @@ private BufferedImage paintTiles() { g2d.clearRect(0, 0, canvasSize.width, canvasSize.height); for (Tile tile : tiles) { - tile.setDrawOutline(showCenter); +// tile.setDrawOutline(showCenter); - tile.drawTile(g2d, true); + //tile.drawTile(g2d, true); if (showCenter) { tile.drawCenterPoint(g2d, Color.red); @@ -144,38 +144,38 @@ private BufferedImage paintTiles() { return canvasImage; } - @Override - protected void paintComponent(Graphics g) { - Graphics2D g2d = (Graphics2D) g; - BufferedImage canvasImage = paintTiles(); - - //paint the image in the middle so - int w = this.getSize().width; - int h = this.getSize().height; - - int cx = w / 2; - int cy = h / 2; - - int bw = canvasImage.getWidth(); - int bh = canvasImage.getHeight(); - - int pw = w; - int ph = h; - - if(bw > w) { - pw = w; - } - if(bh > h) { - ph = h; - } - - setPreferredSize(new Dimension(bw, bh)); - //setPreferredSize(new Dimension(pw, ph)); - - int x = cx - (bw / 2); - int y = cy - (bh / 2); - g2d.drawImage(canvasImage, null, x, y); - } +// @Override +// protected void paintComponent(Graphics g) { +// Graphics2D g2d = (Graphics2D) g; +// BufferedImage canvasImage = paintTiles(); +// +// //paint the image in the middle so +// int w = this.getSize().width; +// int h = this.getSize().height; +// +// int cx = w / 2; +// int cy = h / 2; +// +// int bw = canvasImage.getWidth(); +// int bh = canvasImage.getHeight(); +// +// int pw = w; +// int ph = h; +// +// if(bw > w) { +// pw = w; +// } +// if(bh > h) { +// ph = h; +// } +// +// setPreferredSize(new Dimension(bw, bh)); +// //setPreferredSize(new Dimension(pw, ph)); +// +// int x = cx - (bw / 2); +// int y = cy - (bh / 2); +// g2d.drawImage(canvasImage, null, x, y); +// } @Override public void propertyChange(PropertyChangeEvent evt) { diff --git a/src/test/java/jcs/ui/layout/tiles/UnscaledBlockTileFrame.java b/src/test/java/jcs/ui/layout/tiles/UnscaledBlockTileFrame.java index 54529517..6e37aad9 100644 --- a/src/test/java/jcs/ui/layout/tiles/UnscaledBlockTileFrame.java +++ b/src/test/java/jcs/ui/layout/tiles/UnscaledBlockTileFrame.java @@ -52,6 +52,8 @@ public UnscaledBlockTileFrame() { this.stateCB.setModel(createStateComboBoxModel()); initTile(); + + setVisible(true); } private ComboBoxModel createOrientationComboBoxModel() { @@ -119,9 +121,9 @@ private void initTile() { ((Block) blockTile).setBlockBean(bbe); if (this.scaleCB.isSelected()) { - ((AbstractTile) blockTile).setScaleImage(false); + blockTile.setScaleImage(false); } else { - ((AbstractTile) blockTile).setScaleImage(true); + blockTile.setScaleImage(true); } blockTileCanvas.addTile(blockTile); @@ -131,21 +133,21 @@ private void initTile() { private void changeOrientation() { Orientation orientation = (Orientation) this.orientationCB.getSelectedItem(); blockTile.setOrientation(orientation); - if (Orientation.EAST.equals(blockTile.getOrientation()) || Orientation.WEST.equals(blockTile.getOrientation())) { - ((Block) blockTile).setWidth(Tile.DEFAULT_WIDTH * 3); - ((Block) blockTile).setHeight(Tile.DEFAULT_HEIGHT); - - ((Block) blockTile).setRenderWidth(Tile.RENDER_WIDTH * 3); - ((Block) blockTile).setRenderHeight(Tile.RENDER_HEIGHT); - } else { - ((Block) blockTile).setWidth(Tile.DEFAULT_WIDTH); - ((Block) blockTile).setHeight(Tile.DEFAULT_HEIGHT * 3); - - ((Block) blockTile).setRenderWidth(Tile.RENDER_WIDTH); - ((Block) blockTile).setRenderHeight(Tile.RENDER_HEIGHT * 3); - } - - blockTile.drawTile((Graphics2D) getGraphics(), this.showCenterCB.isSelected()); +// if (Orientation.EAST.equals(blockTile.getOrientation()) || Orientation.WEST.equals(blockTile.getOrientation())) { +// ((Block) blockTile).setWidth(Tile.DEFAULT_WIDTH * 3); +// ((Block) blockTile).setHeight(Tile.DEFAULT_HEIGHT); +// +// ((Block) blockTile).setRenderWidth(Tile.RENDER_WIDTH * 3); +// ((Block) blockTile).setRenderHeight(Tile.RENDER_HEIGHT); +// } else { +// ((Block) blockTile).setWidth(Tile.DEFAULT_WIDTH); +// ((Block) blockTile).setHeight(Tile.DEFAULT_HEIGHT * 3); +// +// ((Block) blockTile).setRenderWidth(Tile.RENDER_WIDTH); +// ((Block) blockTile).setRenderHeight(Tile.RENDER_HEIGHT * 3); +// } +// +// blockTile.drawTile((Graphics2D) getGraphics(), this.showCenterCB.isSelected()); Dimension vps = this.blockTileCanvas.getPreferredSize(); Point cc = new Point(Math.abs(vps.width / 2), Math.abs(vps.height / 2)); @@ -396,9 +398,9 @@ private void forwardsRBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FI private void scaleCBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_scaleCBActionPerformed if (this.scaleCB.isSelected()) { - ((AbstractTile) blockTile).setScaleImage(false); + blockTile.setScaleImage(false); } else { - ((AbstractTile) blockTile).setScaleImage(true); + blockTile.setScaleImage(true); } repaint(); }//GEN-LAST:event_scaleCBActionPerformed @@ -454,7 +456,7 @@ public static void main(String args[]) { app.setTitle("Unscaled Tile Tester"); app.pack(); app.setLocationRelativeTo(null); - app.setVisible(true); + //app.setVisible(true); }); } diff --git a/src/test/java/jcs/ui/layout/tiles/UnscaledTileFrame.form b/src/test/java/jcs/ui/layout/tiles/UnscaledTileFrame.form index b59a2535..a7bb9ab5 100644 --- a/src/test/java/jcs/ui/layout/tiles/UnscaledTileFrame.form +++ b/src/test/java/jcs/ui/layout/tiles/UnscaledTileFrame.form @@ -405,9 +405,12 @@ - + + + + diff --git a/src/test/java/jcs/ui/layout/tiles/UnscaledTileFrame.java b/src/test/java/jcs/ui/layout/tiles/UnscaledTileFrame.java index cf3a9f5b..8efa793e 100644 --- a/src/test/java/jcs/ui/layout/tiles/UnscaledTileFrame.java +++ b/src/test/java/jcs/ui/layout/tiles/UnscaledTileFrame.java @@ -1,5 +1,5 @@ /* - * Copyright 2024 FJA. + * Copyright 2024 Frans Jacobs. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -17,12 +17,10 @@ import java.awt.Color; import java.awt.Graphics; -import java.awt.Graphics2D; import java.awt.Point; -import java.beans.PropertyChangeEvent; -import java.beans.PropertyChangeListener; import javax.swing.ComboBoxModel; import javax.swing.DefaultComboBoxModel; +import javax.swing.JComponent; import javax.swing.UIManager; import javax.swing.UnsupportedLookAndFeelException; import jcs.entities.AccessoryBean; @@ -41,7 +39,7 @@ * * @author FJA */ -public class UnscaledTileFrame extends javax.swing.JFrame implements PropertyChangeListener { +public class UnscaledTileFrame extends javax.swing.JFrame { private Tile tile; @@ -54,7 +52,9 @@ public UnscaledTileFrame() { this.orientationCB.setModel(createOrientationComboBoxModel()); this.incomingSideCB.setModel(createOrientationComboBoxModel()); this.directionCB.setModel(createDirectionComboBoxModel(true)); - drawTile(); + //drawTile(); + + addTile(); } private ComboBoxModel createTileTypeComboBoxModel() { @@ -97,7 +97,13 @@ private ComboBoxModel createDirectionComboBoxModel(boolean dontCare) return directionModel; } - private void drawTile() { + private void addTile() { + if (this.tile != null) { + Logger.trace("Removing tile " + this.tile.getId()); + this.cPanel.remove((JComponent) this.tile); + this.tile = null; + } + TileType tileType = (TileType) this.tileCB.getSelectedItem(); Orientation orientation = (Orientation) this.orientationCB.getSelectedItem(); @@ -135,8 +141,8 @@ private void drawTile() { } } } else { - x = w / 2; - y = h / 2 + 50; + x = w / 2 - 200; + y = h / 2 - 200; } Point center; @@ -146,18 +152,21 @@ private void drawTile() { center = new Point(x, y); } - tile = TileFactory.createTile(tileType, orientation, direction, center, showOutline); - tile.setPropertyChangeListener(this); + Tile newTile = TileFactory.createTile(tileType, orientation, direction, center, showOutline); + newTile.setScaleImage(false); + //tile.setPropertyChangeListener(this); Orientation incomingSide = (Orientation) this.incomingSideCB.getSelectedItem(); - tile.setIncomingSide(incomingSide); + newTile.setIncomingSide(incomingSide); - tile.setDrawRoute(this.displayRouteCB.isSelected()); - tile.setTrackRouteColor(Color.blue); + newTile.setDrawRoute(this.displayRouteCB.isSelected()); + newTile.setTrackRouteColor(Color.blue); - ((AbstractTile) tile).setScaleImage(false); + Logger.trace("Adding tile " + newTile.getId() + " " + newTile.xyToString()); - this.repaint(); + //this.cPanel.add((JComponent) newTile); + this.cPanel.add(newTile); + this.tile = newTile; } private AccessoryValue getAccessoryState() { @@ -178,7 +187,7 @@ private void changeAccesoryState() { if (this.displayRouteCB.isSelected()) { aSwitch.setRouteValue(getAccessoryState()); } else { - aSwitch.setValue(getAccessoryState()); + aSwitch.setAccessoryValue(getAccessoryState()); } } @@ -192,32 +201,39 @@ private void changeAccesoryState() { } } - repaint(); - } - - @Override - public void propertyChange(PropertyChangeEvent evt) { - if ("repaintTile".equals(evt.getPropertyName())) { - Tile t = (Tile) evt.getNewValue(); - Logger.trace("Tile: " + t); - this.repaint(); - } + this.tile.repaint(); } +// @Override +// public void propertyChange(PropertyChangeEvent evt) { +// if ("repaintTile".equals(evt.getPropertyName())) { +// Tile t = (Tile) evt.getNewValue(); +// Logger.trace("Tile: " + t); +// //this.repaint(); +// } +// } +// @Override +// public void paint(Graphics g) { +// super.paint(g); +// Graphics2D g2d = (Graphics2D) g; +// boolean outline = this.drawOutlineCB.isSelected(); +// boolean showRoute = this.displayRouteCB.isSelected(); +// tile.setDrawRoute(showRoute); +// +// tile.drawTile(g2d, outline); +// +// if (outline) { +// tile.drawBounds(g2d); +// tile.drawCenterPoint(g2d, Color.red); +// } +// } @Override public void paint(Graphics g) { + long started = System.currentTimeMillis(); super.paint(g); - Graphics2D g2d = (Graphics2D) g; - boolean outline = this.drawOutlineCB.isSelected(); - boolean showRoute = this.displayRouteCB.isSelected(); - tile.setDrawRoute(showRoute); - - tile.drawTile(g2d, outline); - if (outline) { - tile.drawBounds(g2d); - tile.drawCenterPoint(g2d, Color.red); - } + long now = System.currentTimeMillis(); + Logger.trace("Duration: " + (now - started) + " ms."); } private void changeDirection() { @@ -227,7 +243,7 @@ private void changeDirection() { if (TileType.CROSS == tile.getTileType()) { ((Cross) tile).setWidthHeightAndOffsets(); } - this.repaint(); + //this.repaint(); } private void rotateTile() { @@ -263,7 +279,7 @@ private void rotateTile() { this.orientationCB.setSelectedItem(tile.getOrientation()); - this.repaint(); + //this.repaint(); } private void changeOrientation() { @@ -300,10 +316,13 @@ private void changeOrientation() { tile.setCenter(new Point(x, y)); } - this.repaint(); + //this.repaint(); } private void showRoute() { + + Logger.trace("Show route on tile " + tile.getId()); + String tileId = tile.getId(); Orientation incomingSide = (Orientation) this.incomingSideCB.getSelectedItem(); @@ -314,20 +333,21 @@ private void showRoute() { } else { tileEvent = new TileEvent(tileId, true, incomingSide); } - TileFactory.fireTileEventListener(tileEvent); + //TileCache.fireTileEventListener(tileEvent); - //tile.setDrawRoute(displayRouteCB.isSelected()); + // ((JComponent) this.tile).repaint(); + tile.setDrawRoute(displayRouteCB.isSelected()); //repaint(); } private void showOutline() { - repaint(); + //repaint(); } private void changeIncomingSide() { Orientation incomingSide = (Orientation) this.incomingSideCB.getSelectedItem(); tile.setIncomingSide(incomingSide); - this.repaint(); + //this.repaint(); } /** @@ -450,9 +470,10 @@ public void actionPerformed(java.awt.event.ActionEvent evt) { getContentPane().add(nPanel, java.awt.BorderLayout.NORTH); - cPanel.setPreferredSize(new java.awt.Dimension(1000, 1000)); + cPanel.setPreferredSize(new java.awt.Dimension(800, 800)); cPanel.setLayout(null); getContentPane().add(cPanel, java.awt.BorderLayout.CENTER); + cPanel.getAccessibleContext().setAccessibleDescription(""); pack(); }// //GEN-END:initComponents @@ -462,7 +483,10 @@ private void rotateButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN- }//GEN-LAST:event_rotateButtonActionPerformed private void tileCBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_tileCBActionPerformed - drawTile(); + addTile(); + //this.tile.repaint(); + + this.repaint(); }//GEN-LAST:event_tileCBActionPerformed private void orientationCBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_orientationCBActionPerformed @@ -511,7 +535,7 @@ public static void main(String args[]) { java.awt.EventQueue.invokeLater(() -> { UnscaledTileFrame app = new UnscaledTileFrame(); app.setTitle("Unscaled Tile Tester"); - app.pack(); + //app.pack(); app.setLocationRelativeTo(null); app.setVisible(true); }); diff --git a/src/test/resources/images/DHG 6505.png b/src/test/resources/images/DHG 6505.png new file mode 100644 index 0000000000000000000000000000000000000000..1d57774457d44bd5a3ed690770d9a2729ffbb30e GIT binary patch literal 25034 zcmV(*K;FNJP)ZRA0;qoZf!zKP#Ya7 z=GJ%`A1g;uTjkYp&Axw%2cgw0}b8uwa#dM{Lc)y)+M{rC?V3kW=WJp_LO<-qrl9fzfX5z?FOI%_=Q(Hz@ zU*pPEc9WM-V`@xaWkOY3K2cb5kdsGRU`bqNCUVndnO;21dK1U=XDrIJCI6p*ocX}-^ zH!?m?ji#txVPc@5o=#6ul#`Oxu}N`qa!*`jM@m;JDKIK7Lz|nKUuA40DLFYiOWM0t z93nY?m6bq7S1>d|4-p*?8Za(4OOB0;=G9|rY;ajrOhQ6K6DBvp!MlW?qGD@wS6p1` z&s%P9V|;#eLq9oP}PIfcR+Hkz~?}*mUy{N3`l|h-~%X#1G7w$RF==JUPT>j*~q;U9D zkBQXV03MlYNB{s{JV``BRCr$8y$O62*Of1Ps=B&*t=_xUQfomH2w||X0kPN+g0bW{JOi$>hzvXw8PllkWHJ^S|^b=P|P)~$2T@;~R^Dsk}6)Aa&y0+i&zx1M;H z693i%|L3Xi_{-JT@NT9vmR zf49=RfM=Y~Vu^mx5;eZ{1c1@V@w~_K*2C{Gy>mRX^wu|G_zfNH1EFzXhAgJ$HlN$a zz4iDzO#k1v$I>y_%X&t%q~>@=be6``d?a-sV56fKf>PmybZ-FOhG5 z`&<=VX&06+Xy-Urx=&F46@BSM`4f3_RW`7nm1Zh<2kEN$O{2?0+}XjUTz6z=Zf+MX zHo?6BpV>KGC{<^QBg^s1=*KW3E`hN}Ji$m?F(nzE9J4jbeH_=$X zkoACbswF=F^DE!{LU;24y7@YzX2q$#W@m=yGKz?H)&d-0OZ?#0=C+{&(>_@7h7VqE z&d(|Pj*)I!uL5}u!TeZjzP2w?d@=&{Qzwl@4P4(eSJndFSYA;WLW?R%A^hRNV(l zFmPd>`b`p(Sw(~yEu14)!*gW}cbRaZkR3Px2i6{7a`sSWCz#>P3V7qPqVFVKE!|XR zD%!Ap8?6NYH0b=fO!=-%j7^{`CNd4zn=50+SNJ6WZ|oMe4flNe^78KtT`f6dbUkP< ziLhY`{J3NM+kailSfI0PEi+I5K_ctVif;~%?JYOKnKQ70M`XL=E#=-Bx>|CEQ1pdh zeY*vbRMM67Sbbfv^2o{~uoB?N$^$Ez9N`jo=%W*D*Ee-uk#>@hA(Iar__J69?2)Dz zJp9lX;X8QJ@-9HNR|{*ne!eeZ9dueyZZ{&=+9iVgYLHUPv+%Li_@DS=Je6##6;MvuZv%Hu1(>a1n6IGaE`9o{Z zQGm)&)o^XAp=wc~Y5_Pk)HY7nJh*0G7e-uyWD~aK}q`sDxlrAPyZ|gG}peZI9LjO#ndy?k2~+ z>d`e&S#$7_M5qSbe3)OmOxC5GWT-lZ4+?AGU>{UJhjLbcW6J@x^Wlf)7JTREYWV;O z-~yPCW$+SIk!2!4hbhtr2LY~iWp+60^qe}ezSKuu^+>k%l+)?>?spweKb70DBWJ3U z+9H+Ixas~1iJ4%IUIXx({aCFP9)^ei|K$VRXc;3WjLmHrnBRf1cm!awc67~}wAq$3 zJy1oC!b{7J-(koX7LB83LRNKr9LxV#DBP`deFnY_A5Wo-VMXalt2@k1-nk0}^I-EL zsN?P;phbHlUwO-Q-wC=}JVOdZXjwp}Ig`Ko^CsL=h&iCdn}*|1oq(XSm>d4hherg| z%&%ngvEu`ez+XJPqjhZM*S`GP{%|lwncAuG)*=L-{II7Y^c}3%jDpK!aQ-l?7iTZ` z&e7G<%^5%i7g=Gj8*uHR(ju+6hFSZ7#%%z;OdNcrD!x>`JA!SlWKolTTBLoJfGA3ca%@+sZ>yNBAO zQCMsM5s_S_4;?C4cO6>z-nD=0>N&P>!&dYe7)mDba3P;$<`AIoXdg>s?5`fHW{aqt zDwMAlHu~S8tHm=y{_re*2^Z|zgbTp~&;x4_PsLGGl*CRv)(_%3Do7T=H+G+?N9z3f ze7M#;{)?#EA4yH2)k<}!jCDvTXPq#{HVq_w$jNubaLU!n3UF^ttvsbFi31g@`P9+}A%a0B{@zoXEm2f^iI5=3AvC_tH$I#M*Wsj#V8+^qlXK z*y(EV4DW}z03QD~Jxy{3&|It=q>2nL{o+@x{rQe6g#&PuSt@I+tu6l=23!?_!_d-X zhwqSteGVW<^4bTL#~_Uds_2FVpB44>JJ-7O8sAa6N`BL5c0pvUL4V#L@ot+-7xDR1uXhaYV-6-^z`(k2OWA zR9;uv*yPSNfVkPk3-cJfokMN{k6 zb<8U&u=Yb{GtWL|NPQY;{BC zOyFRshn<`ZO_IZ_fz?fNwoOM76K&82$DCZPAAFH@VXj6ggO;gUXgEnO<>(OAO7;vL zC>(79Qc?!l-5$gL~%>pIPo#q9I1j1@NkJ#+~ zF~2r^JuFP-QJjXBVMB-IVGIJABF6zfB%}ofJTwh08iJA; z;PkZyxDWal&+qRwt60s@wxf5V5149c8AUxEiiMZe(yr=GxU;1dWM~<-wgCQWI}F_b z%f_?}3`8h=T0V#|`aZW-hF~1!Ev}DsT1y5BOri37@8t5#5vRFaIa}zw!Q%S1>G4i| z+5><~`G1#S`n^}G6Yn%?7BE=5im{KqL_*ww#yOTnm$vn1AO@lUch&aZ2fw}QwLUJH6q-c=`gjk`3`m!n z>zk1#n8xjC-W{)jdEPl^#);+7WFt$8@JE@@=x2nUWwpDfs+Y!`Ijwjryl|Jn(Dp2` z;?82ee<{`TwYJo1Z1*`>xEo+K4Btlwt8I4m*`sISZx$UrPUA2+2@cUU@q5dwQAZZc zMQa9pF<#I>)A%pK8!O(}vk~BR`f-mhPFh`0F_8s~v#p^8IVneJ0G5Txu_gQr;E!lQ z)B&R%Y@-NazETI)zlYvl&Mf7X!9ob$3^f=Q0ThNvlY(qQZqaP92=K+6urpJ%20^rSz_AzC`TBW` zSVNHDVd!IzQGp;v7JT6tZCW)RUaz&6=4lwS2Y`3;8=uIU=fMtuQRo>5EyQDq(m48Q zEUl3fUpR2FNwO7C5C7)xM|uz)_n^@nX&&iphT-O6)D-9*FMTrHNXz4$7OgO8mVSDL zLBY4@S&2W@Y=z+-MKIygm$1(%gPEoX8 zr~GZ>Qo)9OOOX}WbqF%%)=%~f!A<9}*Jb$9?jl4;isy{FcIPBQXE(vo5l}@!ZcSW~ zIt`)$fahIVC`N-o32+Q~X*HQ%+z%vQP0;UymrYISxVje4eJSrBcUxf`gmM44FpfRi z)RY2uD&ZDtO>dI&Bbo4%V%dNz(A)D2YW$Et=&r?zU=G=ay9+jb+JGStZJnS?w9?*Q zR@C;{M`aMRLi#2$yQ^c}&}=h+E3QXL0Jq^calxG;E>%0nw{P2iCp*sQ^j$Ez^rK&g zHLznv2kgGg`+JTsz z{#S5~v*0d>1!ga*7!#o(wNWqQ-*qthYvb2p!ntpKVYK7caY}7`f2)-uC)CVkqpU6O ztr{@8e~<+PM0+>T0+u`WppV$F*YDr3cUz(vMc-Cvwy`9hp33VT{GfQCrSYo<^$yP2 zK6cwHHd25G9{=Ry4?GSJpv@V)l3%&f+ymYhTpU-ky{GwbE|Rq5EqTQ!!ubH?$2{od zVvc-LP@HDFVy!`%tGLS*t}s-vM>5BH1)~~ncZeC|xyp65)k>zzy*TRRhUnlJ9VM4ZSAg-=KYek3E+UgH}mFxl*oF zo;rDY;ZqBLb*|&7)7jHV*=*))Hd@GzzW2~=KPmpYn7!>_JRK|E{8~0K6^TUJIm_{w z|CghIs-?6^F5uTTFmk?MFuhTxnRCCN zuHZMh>uxPt&HeK7Y(<|_VV)p+K@yxtamzFpRkSXmN=5)T<`rd*`6`1C`V5d;7qX4+ z-r2KE;~t#I?_#!S(=NE%{l6iXazi#@AFlqNc3n*sj zH{lgneJIitdH+%7Hq)+XAljG}p8-=v)65F^a*ESf&Y(Gs`60&D{OBrOX{;MM>?tr7 znqUGb5#Wpan);o%<;>t_d@Y*ZC8?BO0%kQB;Z|xg1V8^z`Ar}TV75_?p+O5u$S}!3 zY|~ukj2|3Bpb4;QkE0kQ1H(WjCAHZwicTey{N(-0rzz2Gs(c)T!bQtt0z!cgZa1L~ z2SoyD3$j{)Ex6Kyn+&wso;->H4r|=4L(}g=C=qBvqYkh03lj-Lr(X5Y^|g~WP!{Ps zokLcK16t4LZ$OxlbwJqaK#O~+JdH8k$c-a6?!iI{E|xNYFNN%n2{HI>a|X@`2^ba7 zMiBH^0)zyuOHw+nc^kSS&ya?j8M-4s1#%jDs0r#nw?@S~v~{M&5D0B9LFLtoklU%GIS{6mFeKm2r3Mz+o+JZRo{ z6#Z$1(reZu25bLmLqC-k3XY@YvXT6vDmtwbaWiM}4i&&ISL|ZK@d!s~ z*MVW(f(ykxEE>LXkELWn&tM|eKu{Z$&?opENe?&>-k`6^K}Qa9a+e!4^V??wuEaCy z^M!;A$ zB2*VCQgph;DwG+>3luM)$YXB;IbNQc$uqBAY2^wAjo*!Y+>LHhkwTL>Qii0}B_jx% zGRvVr1fj(fjY(39SyaIPVAg(4xMYOCmf6Dq6Vuzmsq05YR2 zSoDWM%J!TPFczSm)L{y;4n>zGxo9DTW4;77r@{lW4NL?mnn(n4r0n1dD^pzz6izo^ zL-WXKw#2M?`+amJo}p$gMlHWyDKNtyF=6SVm7q3gRo0!@%$Pr}!%Ik6P%>x0z?{Tf zh0P~Gt}S~S5&Qj`c~b}MPoG;gTcSaSSK%MfViool)70Z_upiB%0LRG0h`^^&t_jLn<`Z7vZhh;1;q--R=U-&Y23c7|=pf zAj~qz7rW3mT!F64GX$}L$q{cJa!nACtZ~pXxeDt~SIm~t{M6UPv;erHpjv=K+h2wF zq4!e4z^aS+x!=}v4tNufIv{&0eXcY83SSC7n%SbKm@Fj=l-OqHDE`3@H%B|8FBIy4 zcsH!u|K9z}u@VG@S4a-*#I&ZH&9fH zQI#%=aRZM6(6H0k6Tu`Zkgh^?b-7|Fa0Q;t|2#%CK{?KFC|blES`cr%LSyDJAy={l zt0nNq>=>39A*FJf2wY958W3t+D>w86Y2j~i(Q}sI?UQ&LipdNm?S)OR7AnHd3T)ZA zc}HW=GULpk7eFgUW^Z%C@D`r*{FO+rXo}-g0KSv>_P!el$Oabbw@=ehf#q_g{bSKyhDf$6viril!s(~u4=mKGZpcg#og75CQ_fdX|uWHb&$N6A&G zp{F%On%=bCLpfuWAP%uXVDnYZ0+|$Wnj53(kt8YSv`CW8HVND4CUxY2 zU<1~X#2l`;NKxISHpDVfu=B)3T$p*ZQ;Z=z$YGv1La~EJOf0xjJ$Tjvs)gDd19wHE zYfeX|i)q&1t`J^N0EtGP|9}U$BF~VT3-lZa*~v8Y_gf)(rf|lV&KU8+Xe<2w5^Dii zjVa)4O?cHR_Gu*Y8`*}9^SJ76yTV`s+YtDMe}HNr>xNwjxZsuWZh)WY5TiH>+lhyQWp_Vj-S6w(^rucm#DN zdxCNeB@~z#^IhO}f!as2sH!CIlq4L632ms(AhIpQIFy_xKO&<&Gu34eGE@&}n|Ibh z6?tM_a~94rb!I1bTi5M3G}}M}d9K7)j2TwCVNym5#7kAcKQ)Lkov!ji)3ejd-Fp(iidq$TueZN9n z;Y+y}$R5)t$7`D@coIlND3{9QY?jnrkY*D%P|#u}bbWge&!bT-+QF+?&Ey(^)KnmC zWZhz6Ie%6i#+wv^Qsf!;`_Q`aDD32b(k@7?`22%^_TZY@pa0q2x+Ay(T~W>upasKF z^4gQ+k;}vJq2~eSm7cuixE1zTnUrbZgSfMrQb0uX&(K+8JTt{V0xPg=*q2DE5ok^y%ghJ+{d^f7AewCmFRrBkg6yYWKF5JU4=JviF zT~W?tueS^?lrw}Ii$jLCkM_vXqMFMcUsmwq=@>S%o}P0zfvr!E(J!Y){S|#=XogdG z8brlRIz0DlVgsP)FIc% ziE0FVf@l=64qjKsFq>mksgR)gW97IHjA9LHaq#)6aTRj#xiF+fU)N86`&&n>SS)>E^xSGa0^a^OP zncaOwH*1Y6;yo~(-T4*XBk)2&gJ}nUW4jO<*WCdL0Am`BCs>aigJZfAfQD|$c}lKR z(xr!hC^{u5S&@0D7-rH>p7gW+6Ot+Xi~BRRm=LEx)kh6yjC3I~cTF$m_d%!U{CRC^ zd=MSy6;qB^<{4QYlx!&Hu`xOEH2g&nJ2)Z3gcE@g#A9=N#MZ}J7=g&48Qq)-LIvg~ zSYQO76sYxA~BWYm zH<3p6j1-fA1|48gj+x0=hPipIGT91~4j2#d;CIuQ6DtO~tiiHdi51H++!Pu)t&GSy zAzv!RkoSBhdZSOrd)^{rS`dn?UO^+=Pnz5lXVv-r{y3sZCq^-T@KL|eQ3*1pbUrAz z?UE$B-JQ<#;>`~07kV42^UTxUzP!EN;qVLk^>s22Q@@sikefy>U>JKofO1AXija~? z0|GP-9Hf&q=rfSxjIacn#Kt&)h9wV=7@h3p@k~=4s=?I8= ztXNZrblaFh2OE#aj3%hWxw0?CAp;?v^E;J-m`3@WM572`8pK=e&g;MD5ps%Fw2zmi zv+EkK`Mxy<&^`uV3+svlG(U=#-G}^>EOg3EfBm!Hr6(rxtU-B~G~pw(LF01(eJ`>V zInK?8P&sLoy+OKs(MDZ28C6)4Z_BP|M7C%gr#-8fpWke#qGtwY2!?uwgbKBM*e2-dV|yOaWR?<-Qe&U0hCcXa!<0JXXb#*8qgx4m9*fjj+G z!lSVL&ucSTT{emkMMFC=-JC-KD^FOkvX|(nBHE1>2K?eq#O7A?nVX=hr&kU^M}aC2 z$%AH+vz>HJMx>z3$eDp9WPb`##A_=d=$Qk&cT&j_LIWrtK z4y_k2iv>T%J2s~duu;w^vqeAkT>6*Kf6i0Ub?^JzpYSr5*U-)K)HSteB9X}c$+yLZ zi7T^>0wurfISN;<0Wk-88aQbMeL%k)FZ_o2auII#5UOmx@EEBfx z6(bi02PaRSJbwJ#mb;zg52-eN1&Kd#Fm7f`o9r_tO{V7vIerwYqG6-SR;!e^+p%2} z*k)hJ95eb@*1Q5okCNp#fPp+fPRp!-IfK4+S^gcOYa_BC>1auI>3m9(;K_+9A0}4;^4cj)vdo z^I@c1#%LgeJzlQ)<31@YB&oP5;S6`!^E`PD9|~K5L6{t zE08nNN}5Jk2(0=e1VO7eZ?{qeiYUzo8#B=3r^{B5Ph`&0WX3X1pAm!4vL4fxLMlQ;sf$D@PT9Az>Pelwl^AvSjAd!#p#XJdHo-HNC! z=tcRmVi1-06BrAi0Nz-~9x>t*kw4DVgDf&bxV$Jw|CEeb4m2afX6DsfD1$`{(gw1c#AJSo? z0Zk}qdKQP#xtT4Zdf=?T;6=kFPYED?=gx`9{t@&E#IzY%M32Dey_9sUV6f?WWj%0d zVws;MJBj2V^(WV#546Dq2|o^Kv7m2Q@3!d+cOANk^=gv=V~jg`9p=|;i* z0ISGxy6R)~kjb!QCo)IDU-<2Wdr3L$%qQ84%u}JNqDi*vGx=C?dh&w_TPEXVQbvd; z2L&`QH0_Oe-89Oe^Yf7+wB9!x4~W8tXC@=e8oA(xM@a_kh7LqO9@5hWSz!;FepMCr z7IpcVF4;gvbS5HY&=)~~hOD8^HNY5sHhs3LA+rQBnQ_zL0Z#XLy!!-3+?Ow3=3`OG||N>D21i`IOJRCFWZ1hj65aY?q2Q5Nw= zG;T~R$$k;s02A5?A43}Tv}X>hZG*ZFQ-q$@z^EE#Q;#h-)k6cA%dL(Dg4hup-{rFe(Swz?~qEiKr zGmowQV|GDvfoiiNqn%IIF)Yxm)Z1ok{M`9x-uHc7R!NrARZy({xYN+=ft0BtX}m=> z7{qExlC4df`jLgnWX$42WNA>1kTMIELjJm;JK$oC@y*^UEs<-5>%>}IPS{-)#amr6 zUaDTdZS?)6FScxJ`JYW@;RUrStEwp{(oj{6`H7sWDntT}Mc#i>C{@cVoKkL zf$0{So|~@PwX$j$2DJ(v1^M2Zk}4@v(OL$Zi00K=DRX(*C>ry23Rl#kt*BXRH6!P= z6_KB11*|d7q}YmPqgg^ghdy7dDS}+7irKEV-FB}D(yhG{X@B%WvF7^a>=PG(|Nig4 zPd6d@Drcka%c4xfWZ9N~Ke-Uwq7o>1wEYNqY=z>;GaNQ<1DMFP8*3=QxHhu@Z5J3w zHJczO$l8jAoTb6Nx@M@kYqcHjntR9K4)4E!#eCQO7U_P8RCv?oI((-QDCzz!lI8xb z053RgP}y1~c!s(OlygK&NYlpUGL1W-bxL5M?i=;91|VlpF~N%WWei%ONb}=>Y-bE1 zFIAq1k*lSmeo*{zpczhaGprBI-(X@-XfchAIy({Dg zUtSOAm>AK5ZT#TDPd$%zedJR=xb9PI|J!=m9{_yn2P1GDBEp;WBO~bQk1u0h6P5Fo z+X(-I#vEsfbUKFkt7It~&~_DzJbF%4s*U@Zx-zFp$qlgQrJe~{pL5`J8X@M=XgHvp z@zuy}n(!V>RHf8ScuPX7e?BydwY#cM-rlg%;C$ji!n}2w!?RMLY&5r?hoXa^oSNKB zQ&+m_-8I-}Dt?oNc@(P?p;-#oL@91Xz0OWkU0fgdHd0Q~3^w9^mk<3EDbBHX<7w=Ao%+@}w- zmhEJA=uwzFpYY1E%HOz~FA~?t!RPmgVYbG7tDX+>+jLkM^ZVE|NTWiNE75n+9BC&= zIn|_^FnAjLHHy7`{sq)AyhqQ3(`av?3sHJ`76@D(KbOU%1ABxea-d{=m1ea=RZsI$ z%(U1t&C_%o753VI4^BgwvYwPIAm6`@h7a}OO-ZgB0`s|`=_@7pw{dz0&Pw*)8{Y#T zITsYal4Hp<{Rx0AJ80GhZhRi@e-b|bvBy5P9Yd$b1eSB8@y#OLHI1QQ-=L|=`!lFk zd6cXSFR13%d25~lH0zo@V5tVZg;}Wf~O$G+Kr?b@4EN4Z_miwW%i6HTAe`&HLjG4!Z6xFmTgw4^V76eMe~9J zC}ESDiN`Z2@L0d;*}${A=JJ1r=mLMz*4DPAO()!4XqWE-$>Id(V~9bV(yPv0m0j%h z8#D_>cuaTtDH_wWp`SDOY-5wrTX;rDwN9nP zJwb{DY(bUU!|+)P5K>dg{yXVO6mr)Y86ypPDusdfrpC0cI@z(c|5l+1LagCOJB00Vuo&HwnT<4gTR8X8xw8@8 z!n3)g{X4uTioSTPL=J`VES+aF40RG2Oq@Zf`n%xH#eBnfo8jpC!H`sxJr?*g z{byh{$i>;4gv;&O>?B1-{JQh#yB40U%8IVAi&;hp7kcQbGGiv25oSggUZPR{04R)O z^AtGB#*Oa1H)fzoX|H`Cuh{h01H z50iZ<+blFU*aB#m@RRqK5lXE)NKR5K3K~tQ%}FU)BXF#fY>i3!^n)1osjiPi=mPxZ zxD&#`97iKUk*0Z1+Sn5>k1xM;p%1QO;-=FR?}vZ+!0hhjJiDB%#qdSE$Fl~Z2BDoj zl&c@=DGY@4(2~_hn>%|3dKxUl*kU;xTaLjh&7>_+J|aeggg_~6*&p|y71Q#9HBWQ( z=yv!DxMOuE6f;{aG}ll-i9^gw;$?Emaed^qH6sVngqf~CY!cNVcx|~H1o#JPFTxpE zV6*(=eR>^Y#h`7NG4t>{JexavAnPA3S)kycr*m>7R(Y$ni#_HvaUNPWJ|TW|q7^3e z$DWR45VECI)4eRqQ{;~=XV25YgY2=fh@Q5=+vFp_uLo|^Z3M?w!OWLdM4$RWeS=Xa zeuEP?!-2I1yQ5$*X`low5H`1EXb1+mV@9yy&GR&Moimvf3jVECgGIE--UN*os2JlJ z{IV?4EhkW(>^Z1eVjbZsMwLu)a^0t{hoxp2P9>W1&5(m!{1qwQQcnyYx$q7kUa!G=wdcmUOhUq1Gkc(1HxKbNk0$$eH z*yYfD{u8@NQMIK-Z7E8_;sVxeyXMSG3g5sXNalarGP`pb&*sFQI?1jYUookMuq{tr zsV*2^mLTnDg@P$!a$uu1Wek#45+e)05F511f{5F843>LYI;(W}!F{fE|FlqMFU>=g z@rrp3{N%yg_bz*K2=u$4k<1=kJjRCSdLC;W#6{)k-Eh47w#?Dhhe+XB6HI9nC@4|r zwbQsm5GqZxti1`b2vV)6s$wne#b9lSa4oW;0YXL$%?S3EZ@lz^0XKTa)#?M(}0JXtY!2LAyj&S>@EyP^CQX06-nOGO1i;dlA3NB$oh&1I#R+LK4LKu*sktHLqG|Ohym@y@ZPp^q(+Edx z==&0=eu}H*WRx^*s@d{6wFddT2_+|KOoAewVhF>IG5abuG8Z(9&~i#y zI<4^1)D(I!I^7_G8TZUJT5|{0=T*n~V69Z~mSi@Fv{gE2w5tqlNp5~M2bjI=0sI=Q#4s%^O8YA<}sLRBhJ#M1Sn(} z`{mKT@%)FMzS@55v+yr5hBr8NOEtY12BR{7K0oj?H1( zT%Ot81+S)-K2oeKKhg^@SZm3(qA2tm%kGjR>w@EVO@!4B!ZTz$0Pg#tljf&`b0qrJ zubPy`bOSrAMyaveKFZIVt-C>U)#GGHtLGy4AE+wiS>?YSdkyK5Uzy2Sah?PMIB0Ms@}jpeIGqr9nwHJIcnaPtDR3 z2^LdY<6UVm*gWZ6)gZxWwnGpvak+_fAk0y2i}~DA=iSfU z{oE;!>ek@{3Z1)T=r%fzLG@3+LD8&r_0r1tY zHckWl>u2f6OLx$+PET*0*g<>=3_JG>eN0)FPLT@q(>h9AxU>e$2}S9Mcr8F zK0)tYI`heAaCzS|_dNrIA)cuNiCG$Jr^TUx_ndb)FJ3f}f*_h6dJ|NBtm1t;o-O|S z12^XP7ZP91kKUk!VDi5$iOr&1+>F@we`qp-J7MFUY9fSQ469!PqUxWEl0 z1LUj2GWx@M9N zk`rxId_{5+PwPc-i?MNg?=jg{e+f97!4k-Lzwf9uzaSF}H>xbL) z=jnO}dFUDB3D+`LIfpLJJO{!~4bcO3>>)cMeS;ottREoKCr4gRSU{*WN?&%keof}D zXO3Tt1};M2y7A@5YMMmZ2uB(Hm9O;QqfU-lM0K&RpF43dqv~HbXUjje4oQ_{RZP>6It&8&hU26}lwHk8$ zmax~zVc7XbGwR+$caLv<=8n^>ik2z*{4TK`qI&-jwX(Pf%@d*g2C*HP3T$8i+m=bPvLBayYGV-iolCEvp&^$R;H%StZjQSgZjP6%TKPlF1QZKxr z*cHh|uSW_^LP#u`v_xt74a%b1SzV-2vz>+D?v?$OPBRxi0vP>Wllz zjtE8xM`7^`cVuCROwp>pKtC|x{-+to(pzHC-RhQ)+?HOg2R=zH(Jdpi!#6%$JJ5T~d*nvTz92mT z3$g`V(}r8VEYE$?+TioBjJeYwTdJIBwY-nNI4LKr=jV+sJ8Q6*Cn2Y0YxY>ii2kS7i56W<8s?i)`{qJ=n)421}#oAJ})D6m+<(Q|gf8y*)eIFP?z; z7s2Emy(W?1dY>HG0a#fYXmZ~Zz z#JQ5ISmFdt@K!X*R>0#fjL=Ia!QS;D3cjb2%$wY%r9r?1VvF9GUWk?YWLX&ewrS#@~C*E_hNS@qY4AN_KC$o2dO&IB4cTkaQI%L2^HEs7gm zKiRQdg^7WGDW<^onJ>X4Y8FhdWAVuhk68EC| zgi+jQYo-n+YIh2fUtLkQA<8YVkuQHdv%ra{A06&9t5;=LWq)j61P&t@iPOX+{9T5S zYk*vHUA2gDbroamCQqGF6km7{Tua ziE@4y=#e@J4#T5Tua?_-0@y#A>b>Dd?IwBX&&3ZPv7~amfKgP3*%BAv`S&-ig_jfa z)hApoKFuQ{`oTgtZ|fZiO&@bOjv`*hkRv}7nwPK#Mh8E9lK9o&8g7tn!7thvJa~}| z4=`DCMit_!`)mNpVieu)%5jVjJ^?@EFJ|oQHV>b4qs_YG@BqL+!N4Q>&lrEm4p9`2 z7M1O@Gj*2H0VA<3z&OL6P)1Hfi9Ki|gMUn}9=Q}H=9A@Oyd+TJjMgz5Arc+CpmSs? zbEHG}HD^)I0FF&tUsYj}Jn?iQ(Ld-A6Lc$P{>cX1i0>+=k~zuFg|!s z(h<6F8~*%jH~;v;e?3>mYv+Q%=k&=JlOZwYw-lZt;}>XTVQCXF8gh%ijB|FnzdYk3 zA-EKl6sHZ?fHzhk+<0X?=JH?E<#5#>OWThug0KDqJTkBnZaKtkI^zu9E>=ezBg0OV zM?UFhf(n%>PA8^9MrT=u$s01|@FK_IMT-b{1n?A7S!{}lkR)-rGsy&yz#T(#p7!ir zb(HeR>ZMufF#MI-FZ-iOJXm!>I_D6<(X{R2wQwDL`tdzHc)AjMKPZ5pZq38S7nP@P z^_V&7@6t|-cxl7EFlf+Hem(b1QJcn3hAdfcV8AlNu8P2t6%7WG>=EDc_J%)WN)$EO z+ol-`JHqDvVJySc7saJ80PX=ebp3q;i&(cX_Rx=wiV|gBnf7%DNx#uWjyA~Dv3(PX z6Fa4_7o@+k3Rcy=UB(M%6p}HfoY5KNIzk*n79tWKaWb|!q8Pk6aO2^z2nk0yQFE0c zz+RqHD0#EPl)LSE(J>FcpV)|zKLWbE!Ib)F%3!!P{e|x>a^=0+HA|*=E<6Tqo=+5Q zU9M=z=}d5~`BsNdH8>`nP^f3=*#iqPy_2E=G+0r*5GAVUaa2{8k3#jf*8@ItaFR}x_lwW4e#k5vX)} z1408GR*`$vYN2Y%LbYJyjF%=l9y)TyHC;tnPz0vu)q+V;D#%r5CM%#BG~3Kjp|LW0 zmU4Mbk(k2*dk9P>j2=yV(F|2fpcp~Qz=9~YCcsAPhEA;- zTRa$I=C>Z#V_5VJk;fp?o)2`cUNt?|{tWhhu@T=h{H0f*13)IT^>6*KUUKHpT)Jft zFo@?N!rUp@MPTki7e*bJ&44osyFS_62y}>~Bk&8=EV$?$o=kfyK7O=NaQo;*^+b3{ z5$+bsi7L8AUiEFpUpp{H?8Pu*fiZMe{q2$i4hIi81HGJ%M^_q3x?^F@+@8`aKrr3- zFNVCQqWf?Iq7QdL0;RXRkdcDwYzYC%}5w-Ja{L>Af)aTF$5RkdF*OScx5?z;s%Ev-^Ad{Ujsi4Z=>zZ24ptW z%{KMu)Hsu1W^ZPpY!D^X{AM`@yd%rPOg+~0(u-L&ddip;C0wJ&L-Z>w8}p;tO4A%h z+|sC8Ix#y%(39g$xlS0o?i4JVB%iH{As9)n!MIyA8lPc28UdSqyZS-SQZ|w+?25@$ zkFjY>zjdCo?Kmuu;k3uno1~K_6hO!h=AcLAMi|xuuxZf-DypLZJIfq#PLP&6o@ZrH z9Y4_h)KMEt{!`xV)U-2gzpp+jU9;+8potG-{X+HqzrE>2iVh9c_n%z-Bbt+K7pgS^ zMWjpwi^&lbd4$F-V%T$uQr8<{&&EBtfQ=`i?CROq47r}6DqYx+>_}@h%E<@A=4#Iw z&gd$ZgX?xf)ME$=2Pvm1RQ~$mvaxI;8NdJMw~DXWdLtM8iFvqtiKeU@Alf?Ro%}ew z^wWU`Z=0XY-pg@rrn~}gAnq95drA?D_rJ@_weecA+%msX9}Px>d8X`I8@)Jw9qpmH zU$B?l7nysI!u0+VGebeL(e>W5(M?Aw?W*1n=I*DmuGx4VRdl#_#I5ht=U@=TCWtc{ zSqbzK7vRJX>`s-C&+&=OH5b;rju+nu^%q>~DT;#RGK^XDoJ9Rymo;SU8`iEfJwrV; zL~WVVeP$?5uD`U`*nFY_!r@iJ;%N5Ru+`_& zvltksGv1YCW&B2<%mtK$Jsgc;hRyW0KV9N{F@M}-eBe+ntk5e2@w$ES^*^f5oKMl? zGhpOz-Hrlk7TG}5s#n-4z(%Y1i$8f-|DUDqh0k*vX^_4j)`+-b*&rHfY0!{03zl*Z zu_98-R+WF$P14&cL!YMTjmgg;c?K;Su?;&pc_V5*# ztT~%JZgtew8=JJI>-vhV&dKgJZaCa}f z9mxZq8pu?+fZgG6ORwlOn@orxiq;4Ap@Wnwf^1LN z%r$x@O%}{xwl6uEbXID-qTW1yV>*!SDo#7FbDT1F(pWawa#}Igl(7YJaYK8?Xfc{h z1((Sv2!;+z-cpIUC#M@M16%WV?-A(5QuW+6>^?NoRR28WpuQ|k{4wk&?so7rFN3w2zt;j>gl|=D5 zA+U26{l9AgsqE_nDuOhYtxVS;q$gOIj8J3YRx zBL!Ix?Ahm(GD3<87`=>2L$hR)-9ZITraQpP9k-Cm(`)R2oFjO7LrP zG!~E$+tO?j1+Yno`UcV1!V<4PI#_>8Z=KA>T>W1P(nF1GlPx5RX&j8U+I}eUcPq-I zQ7jB}fONie6TOSj4QKdy2w6(d67hlFK}0184ZEXfJ6qQ!?ty=|ZlGiP`$xIYJn;Af zJ7CM>gyC(yu)wZ7ac^Q-#hvqf=Uls5Y}H%TO_G7@#98z3rc)4+pzmU75u(ws&MivN zQR5fx((IuTvk|?VzpO1lq}>W9nG<1QDSD{V0+~j=7g;7maPq_82}}x(Ks474_#N(F zOv7!LlD86%a5F&D#0dPeoE?4G19cz{cPBLpd9t%ZRt_wb^wjMch?6u@4J2%UODMNebaLH^&1bnxC;vJu zmJ;WUWy<|HZ3(gcj0hWF#!!(0s6L>fIdHtBdvL7E1gmp4VXu9oKGN41>+>Pc;`-R% z%g$*lzq<#F0Y*7cr;Yv6%?W!<+fcw~ps8N;AbfmkaHpc3}N zk>v}H4VQ*isW;Go3ys052EE@Iw-Cl5@JNrYMl+LGGrwP-u*KK0&x7Q(3G!0ST=bZ%19Wtt$#NGHujJYU$b&jQLV zV+&4BP+BNM;U9MD>ho=c_MN^J{~$Km;HLf8ANL(!Od5!4h(Sbg0XE)-%8jst36JJs zMk|OoRZbA1&pOH_4S_nZx%B5pXM+Vw7-z{b_^ULj9Jdg&;%Q@+-pbqwIRsvn79pO+ z#x59VTA4Nylme6B5_|)YaWEuCny`eXm97-CQx|$$Lm%I*_evA&xJ%@uAhDSOIf74B z{>$@^tR1}J_|2YV+wFno`T4rLI=Kc8hFX2YQ~MfO-peTXAR^qQ=8*}jt7ob$;T`eO z6zMd7Zqxd+2j|4}0C)VNhCH)<=neWO3P{&|t2uX{?JRBfu~z~f2kF>6C#Az(pZyxm zGK;sPjJ^UMDX}VTU|Dix&BU5Zn$bmx70p#HvFM17WBBBk28wAgRDkn!B=uJ%AZJXr z__`aEZ={8a>E;^7;=O|lCfT%x!o1<`^iUUENNw;B1E&$DWm$H7wOw;y=QOLv~+9|k_vqFX%IC%LjbGBT30y$ji_O6B4CE>A9;_0 z6}2w@{tZ+7!KMs_Ix)Y?Z064%o5!x8r{X|6Al5R#_Uo=``$s>LpL*n&*qqQ-Q&yVRH33 z<~v7t2)W;8{w?R5Y-K_96J!3?{!&}gNSwvMyQZF9mh7_pief_xJvIpAeKA+rxTF$- zNn%-uNm!jo%%;?KOUp%inwLH3hJq$l`Eg6uy{Is#^$wC7uz~1%b6xgqr!j3b7D`}< zP1FBHWse^K1vCWf`yldQa`(Et^PgD8W z1D}Q5gzAdl1UI3yqJTiNIM(e==FqGJ>-n3asa1U=B3%CNT4BLtS6{x_{!lFh`-WT7 zg{lJu%{}3!mQLg+)~tAKZt(`WGrDDgn-XHl(V4Y!z5;Vd3bZC6q#{kI~1san_`;cjet^3wbLVuvDGoWoaZ8e1D?v{%&di9A-XXLp3 z!SjKe_qfth(vwz)?jQX565x-(5yO$@a={uFQV3c4n=gWnq%rKO6{xcZ>B*f_TOw+rG-Me+UP{lnXaEJ^C&d_E=Xiq->wAS6wj_1j{|S( z%N}giWlzBlil%S>xA~o&gW(&ep|I`QwrVfln$|YnrU^!LA!UPQ-Q*D#rC#jsg?V68 zOa+G56m5u-24llE^K|2#VIaS5{pd>Dznq(AE41RC028fHNYUiPoVxnC#vr=EzSR$Z zX_$#Vbuxcil8rq!o-d>_zkYLQFxNBB<9zXKvO;f6L{jTc^m20igZ~V-BnqSc@fG8O zX<8glbS6C2f>%z-#ZuR(^_Iwm=NAsjH(Hy=961QlCl{&*w7C%Cp#gb8 z^WlV5IxQ%@aacKSI6d7Lo)md&F>f-Jq$~!QgXt63p0E0BHjisr@Mq$+7i&!~RIl?6 z`Mim~aWGXTY_ih;9b=%@R=$aWed)q{j`tLAc+(zN9cj-*N;B4ywScMfY(lF)MF6FI z^x4C|xTHkB*7l1`Mv1Fje`(sDn}`+{W(>R7%bJk1d?6lx@vZYgl^5G`HF zo2LtzV*kMduf{Zm-XO;4E#-9*|0;ALP$plHKHxN8!G7R9Bqoj0mLx&C@A!jJv%7b9fKcq7RGZ+;~ib&ZSiX+4RXz5 zNr7a}%MJ|6Z#%DC+f=js<~^?VR8w0bq>NhID?a{sIqyrfIHyfw+0d>`*d~Qw)^maL z!g)(>Wb_8Ue9is|4t3O$)p*Xx8>R*64T>P^q}Aj^BsOk&PguJy&$}iy?HaSOEjZaR zo_Hxe17;do%*#kf#XYFXIm0lwCT--QT+C$DKlsn0DdjSX^@%L`YN-~3*DZ4IHrhxB zvL0!CTuZb?5zxVS8y3xsCrKrkDmoG0F@#6<3?b2yX2-sG>F4>$1?AUGyWdcU)05tU z!|R`@+Kp$xt-|=&*Rn(LI4HM)8MSCK7Zz7oVzxkRp=aIjiotQPI12n!1X2cmKVNRv z9BIEZXt7SHt?=O&UA%!Z5A>E8wdnZOTVPYERDw$nc3rdnea&NB=AmNHB_|h5nkVQD zBXjAka%S+$mo9iq&NID#?Td^i-%|SR$bGM4zGRC*<&+S&dLa|wv}$K(^H|6`HPVyH zbbIXK)2j?w&fF0$R5+z~X;LX`Z3>MAITfcq@ay!)P&Wg^+0wP`(-lX>m$>wi_F=x< zGSyW!guPW+u9;=I;3>%pqLHI5V(%|nmgmk+Y3}i6Q!YxgfpVr|wvuf!%Cf;=tVz=z zjQXdFMN?%#wokpd@}9}l!wbbU=P*vHTBzyO!8usCLABzhQ9b zo^b|K4W1Jxf7xq^n;aDz@^v_i_u)_trcyi-Pg{7gs!8RMd8ws3S2T-5ef{1KO``fe zm2r-hY|U%dy!vDIcKzR>P7#A4_+PC(YjhN4mba?9s;l4cM>^^5bVx!HNWefq2?-DZ zUnr|Gj*1V?AnW6-qQhZ^(F143jIOK8jQ-g@v%9mdI&)@MXV)|Pm^~r1du>N z5|VV1?xefZ??+X4bye;6RVRSL?$Oz~$>~aN-|uzne)qfI_ucP)hQj3Z)PZDraIo!A z`5HGW1-{BNyyo5nYeX`kOMOj_VJF!TgkJdpGBw8Rf4CXPdPI|`VFIYzmoI8I;JBlr zBOerifx{(rHMco**xTF;m~B|0%<(IouKpYrx0%1NfmGC3(Qwd{0$ulTu~r&4sH?%I zNr6ozK`P~C11UAL`WEAvU#0u1%~Sah*d=Uwj}`@i$qqoGTuUcxxe4Kej6_?lDH1fl z9^W=2fKV2X80yq9`Si~wV_#)O1q2vufYBO7h3OlXHh*5KEHPXIU-H?*pwgH@vOfWX zNQWK7k?g(>ShQ?uQd{-T%MJ7;ZHNAZ8z?dBh0C>g0Vam@HyBzO9NlmMp3#R)_fk{v z?7@L%7*G~fFr-a+UA`PTMLYUeIL>ETa~`Tibx7;a7*nJ6X;Km!;LN7qx${^Ldk5L) zO7-wgM}H_q~=)y$du=nK!SaypCrW2s56(7B(IJx;z7dKrK=IE_48-@YeSo z>wdYCFC;BF3OkiT){>+gSwpIJ5ZOC)%5)(?gc&JrKD6!#3_$Y$=9+I4e-L`)ci#3z z9T!MaSXD~sBIu>p%mU>J;{d7>%jj?nGt{i#W=s(^QsB;a;6TVo8}0wHWT?s*ZyFL7 z83#Ga!%a7h)?IL-DKxewm!F1ZKMV2mO`&Vk-dN^_vt|rh8#RuXw>ZSJhYm6j6t5%w z>KIS~zEmh=q)T$?hF$(fAQM_S@L}_0Ec1k~?@@mp6B1$z<2IIOg=!IaS+B-QCADd^ z(f_yU@Jy0J{q8;ePj_rR{P07++5F7EcfXx^`|mT>2Z`T1zSy#AK)s;*!gM-XB`iwQ zC9A2dmWnc!%WF8}gOlE+znRj6OUPKH?qa+j=@MN9Ro9&@7Z;wN4QS6TNo&;wt?qQ` z=1Vl8=E+A3+B=x#eK;5Eb^9&{*sLiKUA(;SpFa*a`+^U zlup^+4GTN|#=PU*$-^36Es*I0JrC5|mJ*gu&c&^5^?ae7iB#nYBS+=r8re3}IQt-1 zC;ccW=S6HQ<`36q{N40IpEFEOe#>9KdM2nQ#Z=y%LB_H~P1P3`tP#V3T6yZlZ5#gl zZTpXnNtRb{H*kauX&q<#^6?ic!m z6sW!(_drQPmXl-W%#|TtqlQ$&3@_@qGIm%;KzR0|&&5&NE1c#s?P1ofE6#pgn@B)p z8y$pG_C{adyVF;u$YfwQepmxDz>GP^b-#zrD=yC-3fn=Ky2q{#zyH#S*`Dd|;Kj<} zALKh8zfLv%QSc|?+0Cf#&u23-?fB`6seWtKMTvC8QauSBGVQr3_%ot^aX#x~Cf)pl z^U><&fJQ?(aWxPFS*0*7Z~d)%5k#q}DksXpdJr~FYPj3qhjws3c$H=7o4v}yx|O`p zE<~+kbr+iv>lYU@Vti3Q=dGXYbGL|F@!R0N`w4mb4cD>0G5jxm^P56`Rq^$)f((rA zHmG3@q_N68*}|4D^R4W3M{|zgnr6=@wS(^BR_;sdD08!st9?bzo$JQ)@6iq-sIy#1 z+H-t>3^~>`xXC5s){dc@F8$)#47iWZtig{ueYwB3%2zAr7=cN~N3x9nB!~c%}RmYT>+{#Cc4QBfZ>33*U0 zKQXcr+2&|kC$(REj=o~0U#Y^JXVEndLRW#r=MeFVKfdJ#Uve|I!A7tZb9mSOU2pB& zKS!+GkZ}Dhpp5-0cFhx2K%si|#htK!7rcd@ZvpIvk_(@2OX54KU6ogWO<9!x>-b(J zC4=6*y(yF#{u8By{k^d7wLR#cm-oTTdwcipQm_iV^(wr$yJUvFfN3zM>nQAb4KTG# zybQ1prNW!9dvIFVi`wzltC62zWQ86R!fQBwLg!qT6$b{na=jkFafHW(%a!I_Q55sv z8$keQdIKI|c*$W;~B%>bh zW#X+vWp@}OL7}<|71H{+8kFmlGvFSVZJ-{NTwDDJ%^|^O`5Tm3Cq13Hf%UTcHeV=+`Z}0mcGfr1W(J;ot+&NWf!`-sNT*hq;4cS z;NAHl`APSyHzQ7xxAtx+OGO)R7TS1*TImw_@kTTna75ITJ#EQ|_*f6mqq1q>=vkgM zNAHPCtMzSC-jvVhU*EvD#RBFjxN~n0f9ETA@?h7DO*>L$rzr(`L4JTAmi`r%Pa zSU;ShMUmQbaQzQAKGQllK0aAJVLqPj?G|YS`X?3Cq`fRk{j+p$ckjkblBAz$9(>*# zv2em?NM=6XtV5~UA8wqTnaQx~ixFkE+vN+gPkzw+^y1<174cJ-zq<+ctiL_3`}p9o zqsQN`3VR^@#$T=7UZ+4y%R|(g+m}7w5`_{ibG{uxl&gHK`-rqM-#y)4MN2U3a!;dX zXkI+ANz)6PQe#y`UdnvG^{^}-lkecoJ%`#(*6hB&Tyma%=?=DcBP;eEyW@*ga;VCl zD>+9rdVz0OJdvgy<#L}-iiKP$k?lQp@Y7?P_uRp-O$4q65ONDZU;E(S0rsaar$W2(JnZ;hx%Yp zYPuhxRIg&mR|GoQI8Yb!pe~PhIOoULOtL1c#{CUnZHqCe^W8>{g>Q)|sskZAkK-;p z8>)#L=OkYNlu6NXJljEY_#%b56UYFa!eGO2>v5Eg1qaknGU?2W)dUww7^8G(rRe+w z)YTlA@3BhnajiIRHt~rFK7Uy0bI@7LhH7*r^(j0GA*B#OV+bUdlY>INv9d3y_z&Pb zY9zLF-h#R-FiJnh+lk~wky= zRdq9nAxQbyCK`e;2rU<>u9-4u&}e|hli>OwTsFp`j>O}L;_Rcbp?5dhLZ7q;(nyij zOd(uNTmbjXWdWLKe2*P&2{Jese-Y!LzJM2}aj^)?xF>?AqlQZf}#)SRc$;Cr#Q?%SpNmC}4uo1@hO3p|$7Y_f!qhncM_zo$f zwM#h%750ur%T*FxXDe{*njIUqJ8*>9^oW1RE^qwhV**W=AzsW$w9_=4)mcPsV2iA= z3*};Xifo|9nFzN)LyMOPV{CxlEdAtSL@Tq|>p~(ui4P zt$Len8)?xALo+ZjkrEi4noktQ1_UxtTsT!U*|^K{s*=H{F5j|-_$MrHtXX@?2&x43 zId>cX?Y`3R!Z5(rpDQL;MzXsUZ)N~@%2}Gh2l+faxbOOJYf-=}zs?Om$AKJK;9U_V zmKTdO2x$uU9Kent4JKY!Jr4Xu5AQ3f&LZ(|7$$`|XC8lnOesj=&&L38sfjmwU zJ;+fO6+AObg5bh7W&$4*AO(79DV3{uv&7ATU<0a}hp!t@ms3m6;t04IFrqIrR>Ybx z4`owOgk`f%q@RxXvj*njG$d{^MkQ9`wDq^?os`vJb;sy%m4#HRGY>q% z7*oTH$7-Qy(ai@T0XBM}-{wZZmh1^ZvUEU_7Tgr!%ND`TMx3@uxh9qx?-_4(vu3ZG zt+i6lq}w!{NJuj#%hv6NkW^H=X`gMhR5Ib81$sAaFrdjP&pJgmXjzH$zl8JzC5dv; zqo&kJ-pG+mtgHczmN6Q=b)Xw%ODSXpv6~Yh)dPZy{3usn7}VP1_MJr%dyJ^0(2C7YO%ozXLDks?-ETa$_)RI)7Hx>+)jL_-vO zPt%a491KE|W%+CxN3z#6(q&mI5-LV7P-%(drhxL=fHr0sf?(_t5$0sJEjTQ>b*zOE zkv>%m4sl5KnL`DKxVx%G+Lk-Yr+zh2NTWO7o(h$M~ l&DcH#N2*#{_n0bX`yYE Date: Sun, 19 Jan 2025 19:04:23 +0100 Subject: [PATCH 02/24] Fix persistance, WIP Commit for the weekend --- .../jcs/persistence/H2PersistenceService.java | 18 +- src/main/java/jcs/ui/VNCPanel.java | 46 ++- .../ui/layout/tiles/UnscaledBlockCanvas.java | 286 ++++++++++-------- .../layout/tiles/UnscaledBlockTileFrame.form | 54 ++-- .../layout/tiles/UnscaledBlockTileFrame.java | 141 +++++---- 5 files changed, 296 insertions(+), 249 deletions(-) diff --git a/src/main/java/jcs/persistence/H2PersistenceService.java b/src/main/java/jcs/persistence/H2PersistenceService.java index 0409ec81..cb696eac 100755 --- a/src/main/java/jcs/persistence/H2PersistenceService.java +++ b/src/main/java/jcs/persistence/H2PersistenceService.java @@ -40,7 +40,6 @@ import jcs.entities.SensorBean; import jcs.entities.TileBean; import jcs.persistence.sqlmakers.H2SqlMaker; -import jcs.ui.layout.tiles.Tile; import org.tinylog.Logger; public class H2PersistenceService implements PersistenceService { @@ -611,20 +610,13 @@ public synchronized TileBean persist(TileBean tileBean) { if (tileBean == null) { return null; } -// //TODO - TileBean tb = null; -// if (tileBean instanceof Tile tile) { -// tb = tile.getTileBean(); -// } else { -// tb = tileBean; -// } - - if (tb != null && tb.getId() != null) { - if (database.where("id=?", tb.getId()).first(TileBean.class) != null) { - database.update(tb).getRowsAffected(); + + if (tileBean.getId() != null) { + if (database.where("id=?", tileBean.getId()).first(TileBean.class) != null) { + database.update(tileBean).getRowsAffected(); //Logger.trace("Updated " + tileBean); } else { - database.insert(tb); + database.insert(tileBean); } } diff --git a/src/main/java/jcs/ui/VNCPanel.java b/src/main/java/jcs/ui/VNCPanel.java index deced133..bf69b6c6 100644 --- a/src/main/java/jcs/ui/VNCPanel.java +++ b/src/main/java/jcs/ui/VNCPanel.java @@ -49,8 +49,7 @@ * * Inspired on the work of /~https://github.com/shinyhut/vernacular-vnc
* My ESU Ecos 50000 has a defect in the screen.
- * This Java viewer is helping the development. - * In hind site I thin is a welcome addition to add to the main frame in due time + * This Java viewer is helping the development. In hind site I thin is a welcome addition to add to the main frame in due time * * @author frans */ @@ -71,8 +70,23 @@ public VNCPanel() { private void initVnc() { addDrawingSurface(); - initialiseVernacularClient(); //clipboardMonitor.start(); + initialiseVernacularClient(); + + + String host; + InetAddress ia = EcosConnectionFactory.discoverEcos(); + //InetAddress ia = CSConnectionFactory.discoverCs(); + + if (ia != null) { + host = ia.getHostAddress(); + } else { + Logger.warn("Use a default host ip....."); + host = "192.168.1.110"; + } + + int port = DEFAULT_VNC_PORT; + this.connect(host, port); } @@ -388,19 +402,19 @@ public void windowClosing(java.awt.event.WindowEvent e) { vncPanel.menuPanel.setVisible(false); //String host = "192.168.1.110"; - String host; - InetAddress ia = EcosConnectionFactory.discoverEcos(); - //InetAddress ia = CSConnectionFactory.discoverCs(); - - if (ia != null) { - host = ia.getHostAddress(); - } else { - Logger.warn("Use a default host ip....."); - host = "192.168.1.110"; - } - - int port = DEFAULT_VNC_PORT; - vncPanel.connect(host, port); +// String host; +// InetAddress ia = EcosConnectionFactory.discoverEcos(); +// //InetAddress ia = CSConnectionFactory.discoverCs(); +// +// if (ia != null) { +// host = ia.getHostAddress(); +// } else { +// Logger.warn("Use a default host ip....."); +// host = "192.168.1.110"; +// } +// +// int port = DEFAULT_VNC_PORT; +// vncPanel.connect(host, port); testFrame.pack(); testFrame.setLocationRelativeTo(null); diff --git a/src/test/java/jcs/ui/layout/tiles/UnscaledBlockCanvas.java b/src/test/java/jcs/ui/layout/tiles/UnscaledBlockCanvas.java index dc8f3998..39eb21b4 100644 --- a/src/test/java/jcs/ui/layout/tiles/UnscaledBlockCanvas.java +++ b/src/test/java/jcs/ui/layout/tiles/UnscaledBlockCanvas.java @@ -16,134 +16,171 @@ package jcs.ui.layout.tiles; import java.awt.Color; -import java.awt.Dimension; +import java.awt.Graphics; import java.awt.Graphics2D; -import java.awt.Point; -import java.awt.image.BufferedImage; -import java.beans.PropertyChangeEvent; -import java.beans.PropertyChangeListener; -import java.util.ArrayList; -import java.util.List; -import javax.swing.JComponent; +import java.awt.Paint; +import javax.swing.JPanel; +import org.tinylog.Logger; -public class UnscaledBlockCanvas extends JComponent implements PropertyChangeListener { +public class UnscaledBlockCanvas extends JPanel { //implements PropertyChangeListener { - private boolean showCenter; - - private final List tiles; + private boolean expanded; public UnscaledBlockCanvas() { - tiles = new ArrayList<>(); - } - - public void addTile(Tile block) { - this.tiles.add(block); - this.add(block); - } - - public boolean isShowCenter() { - return showCenter; + setLayout(null); + setOpaque(true); + setDoubleBuffered(false); } - public void setShowCenter(boolean showCenter) { - this.showCenter = showCenter; - } - - private Dimension getMinCanvasSize() { - int minX = this.getSize().width; - int maxX = 0; - int minY = this.getSize().height; - int maxY = 0; - - for (Tile tile : this.tiles) { - Point tc = tile.getCenter(); - boolean expand = !tile.isScaleImage(); - int tw = tile.getWidth() * (expand ? 10 : 1); - int th = tile.getHeight() * (expand ? 10 : 1); - - if (minX > tc.x - (tw / 2)) { - minX = tc.x - (tw / 2); - } - if (maxX < tc.x + (tw / 2)) { - maxX = tc.x + (tw / 2); - } - if (minY > tc.y - (th / 2)) { - minY = tc.y - (th / 2); - } - if (maxY < tc.y + (th / 2)) { - maxY = tc.y + (th / 2); - } - } - - int totalWidth = maxX - minX; - if (totalWidth <= 120) { - totalWidth = totalWidth + 20; - } + @Override + public void paint(Graphics g) { + long started = System.currentTimeMillis(); - int totalHeight = maxY - minY; - if (totalHeight <= 40) { - totalHeight = totalHeight + 20; - } + //Rectangle r = g.getClipBounds(); + //Logger.trace("Rx: " + r.x + " Ry: " + r.y + " Rw: " + r.width + " Rh: " + r.height); + super.paint(g); - //Logger.trace("MinX: " + minX + " maxX: " + maxX + " minY: " + minY + " maxY: " + maxY + " Width: " + totalWidth + " Height: " + totalHeight); - return new Dimension(Math.abs(totalWidth), Math.abs(totalHeight)); + paintGrid(g); + long now = System.currentTimeMillis(); + Logger.trace("Duration: " + (now - started) + " ms."); } - private Dimension getMinRenderCanvasSize() { - int minX = this.getSize().width; - int maxX = 0; - int minY = this.getSize().height; - int maxY = 0; + private void paintGrid(Graphics g) { + int width = this.getWidth(); + int height = this.getHeight(); - for (Tile tile : this.tiles) { - Point tc = tile.getCenter(); + int xOffset = 0; + int yOffset = 0; - int tw = ((Block) tile).getRenderWidth(); - int th = ((Block) tile).getRenderHeight(); + //Logger.trace("W: " + width + " H: " + height + " X: " + this.getX() + " Y: " + this.getY()); + Graphics2D gc = (Graphics2D) g; + Paint p = gc.getPaint(); + gc.setPaint(Color.black); - if (minX > tc.x - (tw / 2)) { - minX = tc.x - (tw / 2); - } - if (maxX < tc.x + (tw / 2)) { - maxX = tc.x + (tw / 2); - } - if (minY > tc.y - (th / 2)) { - minY = tc.y - (th / 2); - } - if (maxY < tc.y + (th / 2)) { - maxY = tc.y + (th / 2); - } + int grid; + if (expanded) { + grid = 200; + } else { + grid = 20; } - int totalWidth = maxX - minX; - int totalHeight = maxY - minY; - - //Logger.trace("MinX: " + minX + " maxX: " + maxX + " minY: " + minY + " maxY: " + maxY + " Width: " + totalWidth + " Height: " + totalHeight); - return new Dimension(Math.abs(totalWidth), Math.abs(totalHeight)); - } - - private BufferedImage paintTiles() { - Dimension canvasSize = getMinCanvasSize(); - BufferedImage canvasImage = new BufferedImage(Math.abs(canvasSize.width), Math.abs(canvasSize.height), BufferedImage.TYPE_INT_RGB); - Graphics2D g2d = canvasImage.createGraphics(); - - g2d.setBackground(Color.white); - g2d.clearRect(0, 0, canvasSize.width, canvasSize.height); - - for (Tile tile : tiles) { -// tile.setDrawOutline(showCenter); - - //tile.drawTile(g2d, true); - - if (showCenter) { - tile.drawCenterPoint(g2d, Color.red); + for (int r = 0; r < width; r++) { + for (int c = 0; c < height; c++) { + gc.drawOval((r * grid * 2) + xOffset - 2, (c * grid * 2) + yOffset - 2, 4, 4); } } - g2d.dispose(); - - return canvasImage; + gc.setPaint(p); } + + + //private boolean showCenter; + //private final List tiles; +// public UnscaledBlockCanvas() { +// tiles = new ArrayList<>(); +// } +// public void addTile(Tile block) { +// this.tiles.add(block); +// this.add(block); +// } +// public boolean isShowCenter() { +// return showCenter; +// } +// public void setShowCenter(boolean showCenter) { +// this.showCenter = showCenter; +// } +// private Dimension getMinCanvasSize() { +// int minX = this.getSize().width; +// int maxX = 0; +// int minY = this.getSize().height; +// int maxY = 0; +// +// for (Tile tile : this.tiles) { +// Point tc = tile.getCenter(); +// boolean expand = !tile.isScaleImage(); +// int tw = tile.getWidth() * (expand ? 10 : 1); +// int th = tile.getHeight() * (expand ? 10 : 1); +// +// if (minX > tc.x - (tw / 2)) { +// minX = tc.x - (tw / 2); +// } +// if (maxX < tc.x + (tw / 2)) { +// maxX = tc.x + (tw / 2); +// } +// if (minY > tc.y - (th / 2)) { +// minY = tc.y - (th / 2); +// } +// if (maxY < tc.y + (th / 2)) { +// maxY = tc.y + (th / 2); +// } +// } +// +// int totalWidth = maxX - minX; +// if (totalWidth <= 120) { +// totalWidth = totalWidth + 20; +// } +// +// int totalHeight = maxY - minY; +// if (totalHeight <= 40) { +// totalHeight = totalHeight + 20; +// } +// +// //Logger.trace("MinX: " + minX + " maxX: " + maxX + " minY: " + minY + " maxY: " + maxY + " Width: " + totalWidth + " Height: " + totalHeight); +// return new Dimension(Math.abs(totalWidth), Math.abs(totalHeight)); +// } +// private Dimension getMinRenderCanvasSize() { +// int minX = this.getSize().width; +// int maxX = 0; +// int minY = this.getSize().height; +// int maxY = 0; +// +// for (Tile tile : this.tiles) { +// Point tc = tile.getCenter(); +// +// int tw = ((Block) tile).getRenderWidth(); +// int th = ((Block) tile).getRenderHeight(); +// +// if (minX > tc.x - (tw / 2)) { +// minX = tc.x - (tw / 2); +// } +// if (maxX < tc.x + (tw / 2)) { +// maxX = tc.x + (tw / 2); +// } +// if (minY > tc.y - (th / 2)) { +// minY = tc.y - (th / 2); +// } +// if (maxY < tc.y + (th / 2)) { +// maxY = tc.y + (th / 2); +// } +// } +// +// int totalWidth = maxX - minX; +// int totalHeight = maxY - minY; +// +// //Logger.trace("MinX: " + minX + " maxX: " + maxX + " minY: " + minY + " maxY: " + maxY + " Width: " + totalWidth + " Height: " + totalHeight); +// return new Dimension(Math.abs(totalWidth), Math.abs(totalHeight)); +// } +// private BufferedImage paintTiles() { +// Dimension canvasSize = getMinCanvasSize(); +// BufferedImage canvasImage = new BufferedImage(Math.abs(canvasSize.width), Math.abs(canvasSize.height), BufferedImage.TYPE_INT_RGB); +// Graphics2D g2d = canvasImage.createGraphics(); +// +// g2d.setBackground(Color.white); +// g2d.clearRect(0, 0, canvasSize.width, canvasSize.height); +// +// for (Tile tile : tiles) { +//// tile.setDrawOutline(showCenter); +// +// //tile.drawTile(g2d, true); +// +// if (showCenter) { +// tile.drawCenterPoint(g2d, Color.red); +// } +// } +// g2d.dispose(); +// +// return canvasImage; +// } // @Override // protected void paintComponent(Graphics g) { // Graphics2D g2d = (Graphics2D) g; @@ -175,23 +212,28 @@ private BufferedImage paintTiles() { // int x = cx - (bw / 2); // int y = cy - (bh / 2); // g2d.drawImage(canvasImage, null, x, y); +// } +// @Override +// public void propertyChange(PropertyChangeEvent evt) { +// if ("repaintTile".equals(evt.getPropertyName())) { +// Tile tile = (Tile) evt.getNewValue(); +// this.repaint(tile.getBounds()); +// } +// } +// @Override +// public Dimension getPreferredSize() { +// if (!tiles.isEmpty()) { +// return getMinCanvasSize(); +// } else { +// return this.getSize(); +// } // } - @Override - public void propertyChange(PropertyChangeEvent evt) { - if ("repaintTile".equals(evt.getPropertyName())) { - Tile tile = (Tile) evt.getNewValue(); - this.repaint(tile.getBounds()); - } + public boolean isExpanded() { + return expanded; } - @Override - public Dimension getPreferredSize() { - if (!tiles.isEmpty()) { - return getMinCanvasSize(); - } else { - return this.getSize(); - } + public void setExpanded(boolean expanded) { + this.expanded = expanded; } - } diff --git a/src/test/java/jcs/ui/layout/tiles/UnscaledBlockTileFrame.form b/src/test/java/jcs/ui/layout/tiles/UnscaledBlockTileFrame.form index 2f7f61a7..144e15cd 100644 --- a/src/test/java/jcs/ui/layout/tiles/UnscaledBlockTileFrame.form +++ b/src/test/java/jcs/ui/layout/tiles/UnscaledBlockTileFrame.form @@ -52,6 +52,14 @@ + + + + + + + + @@ -73,6 +81,22 @@ + + + + + + + + + + + + + + + + @@ -98,22 +122,6 @@ - - - - - - - - - - - - - - - - @@ -122,14 +130,6 @@ - - - - - - - - @@ -182,7 +182,7 @@ - + @@ -196,7 +196,7 @@ - + @@ -204,7 +204,7 @@ - + diff --git a/src/test/java/jcs/ui/layout/tiles/UnscaledBlockTileFrame.java b/src/test/java/jcs/ui/layout/tiles/UnscaledBlockTileFrame.java index 6e37aad9..5ea0df8e 100644 --- a/src/test/java/jcs/ui/layout/tiles/UnscaledBlockTileFrame.java +++ b/src/test/java/jcs/ui/layout/tiles/UnscaledBlockTileFrame.java @@ -16,14 +16,14 @@ package jcs.ui.layout.tiles; import java.awt.Dimension; -import java.awt.Graphics2D; import java.awt.Image; import java.awt.Point; -import java.beans.PropertyChangeEvent; -import java.beans.PropertyChangeListener; +import java.awt.image.BufferedImage; import java.io.File; import javax.swing.ComboBoxModel; import javax.swing.DefaultComboBoxModel; +import javax.swing.ImageIcon; +import javax.swing.JFrame; import javax.swing.UIManager; import javax.swing.UnsupportedLookAndFeelException; import jcs.entities.BlockBean; @@ -38,7 +38,7 @@ * * @author FJA */ -public class UnscaledBlockTileFrame extends javax.swing.JFrame implements PropertyChangeListener { +public class UnscaledBlockTileFrame extends JFrame { //implements PropertyChangeListener { private Tile blockTile; @@ -51,8 +51,8 @@ public UnscaledBlockTileFrame() { this.departureSideCB.setSelectedItem(""); this.stateCB.setModel(createStateComboBoxModel()); - initTile(); - + initBlock(); + setVisible(true); } @@ -82,8 +82,8 @@ private LocomotiveBean createLocomotiveBean() { LocomotiveBean lb = new LocomotiveBean(8L, "NS DHG 6505", 8L, 8, "", "dcc", 100, 0, 0, 1, true, true); String imgPath = System.getProperty("user.home") + File.separator + "jcs" + File.separator + "images" + File.separator + "DHG 6505.png"; lb.setIcon(imgPath); - Image locImage = ImageUtil.readImage(imgPath); - //Image is sized by default so + ImageIcon locIcon = new ImageIcon(getClass().getResource("/images/DHG 6505.png")); + Image locImage = new BufferedImage(locIcon.getIconWidth(), locIcon.getIconHeight(), BufferedImage.TYPE_INT_RGB); locImage = ImageUtil.scaleImage(locImage, 100); lb.setLocIcon(locImage); @@ -96,37 +96,36 @@ private LocomotiveBean createLocomotiveBean() { return lb; } - private void initTile() { - Dimension vps = this.blockTileCanvas.getPreferredSize(); + private void initBlock() { + Dimension vps = this.canvas.getPreferredSize(); + Logger.trace("Canvas size w: " + canvas.getWidth() + " h: " + canvas.getHeight()); blockTile = new Block(TileBean.Orientation.EAST, vps.width / 2, vps.height / 2); + blockTile.setId("bk-1"); - BlockBean bbe = new BlockBean(); - bbe.setId(blockTile.getId()); - bbe.setTileId(blockTile.getId()); - bbe.setDescription("Blok"); + BlockBean blockBean = new BlockBean(); + blockBean.setId(blockTile.getId()); + blockBean.setTileId(blockTile.getId()); + blockBean.setDescription("Blok 1"); //bbe.setArrivalSuffix((String) this.incomingSideCB.getSelectedItem()); - bbe.setDepartureSuffix(null); + blockBean.setDepartureSuffix(null); - bbe.setBlockState((BlockState) this.stateCB.getSelectedItem()); - bbe.setReverseArrival(this.reverseArrivalCB.isSelected()); + blockBean.setBlockState((BlockState) this.stateCB.getSelectedItem()); + blockBean.setReverseArrival(this.reverseArrivalCB.isSelected()); if (this.showLocCB.isSelected()) { - bbe.setLocomotive(createLocomotiveBean()); + blockBean.setLocomotive(createLocomotiveBean()); } else { - bbe.setLocomotive(null); + blockBean.setLocomotive(null); } - ((Block) blockTile).setBlockBean(bbe); + blockTile.setBlockBean(blockBean); - if (this.scaleCB.isSelected()) { - blockTile.setScaleImage(false); - } else { - blockTile.setScaleImage(true); - } + blockTile.setScaleImage(!scaleCB.isSelected()); + canvas.setExpanded(scaleCB.isSelected()); - blockTileCanvas.addTile(blockTile); + canvas.add(blockTile); centerSP.getViewport().validate(); } @@ -148,7 +147,7 @@ private void changeOrientation() { // } // // blockTile.drawTile((Graphics2D) getGraphics(), this.showCenterCB.isSelected()); - Dimension vps = this.blockTileCanvas.getPreferredSize(); + Dimension vps = this.canvas.getPreferredSize(); Point cc = new Point(Math.abs(vps.width / 2), Math.abs(vps.height / 2)); blockTile.setCenter(cc); @@ -167,19 +166,19 @@ private void initComponents() { locDirectionBG = new javax.swing.ButtonGroup(); nPanel = new javax.swing.JPanel(); scaleCB = new javax.swing.JCheckBox(); + rotateButton = new javax.swing.JButton(); orientationLabel = new javax.swing.JLabel(); orientationCB = new javax.swing.JComboBox<>(); + stateCB = new javax.swing.JComboBox<>(); incomingSuffix = new javax.swing.JLabel(); departureSideCB = new javax.swing.JComboBox<>(); - stateCB = new javax.swing.JComboBox<>(); reverseArrivalCB = new javax.swing.JCheckBox(); - rotateButton = new javax.swing.JButton(); showLocCB = new javax.swing.JCheckBox(); backwardsRB = new javax.swing.JRadioButton(); forwardsRB = new javax.swing.JRadioButton(); showCenterCB = new javax.swing.JCheckBox(); centerSP = new javax.swing.JScrollPane(); - blockTileCanvas = new jcs.ui.layout.tiles.UnscaledBlockCanvas(); + canvas = new jcs.ui.layout.tiles.UnscaledBlockCanvas(); setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE); setPreferredSize(new java.awt.Dimension(1250, 500)); @@ -194,6 +193,14 @@ public void actionPerformed(java.awt.event.ActionEvent evt) { }); nPanel.add(scaleCB); + rotateButton.setText("Rotate"); + rotateButton.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + rotateButtonActionPerformed(evt); + } + }); + nPanel.add(rotateButton); + orientationLabel.setText("Orientation"); nPanel.add(orientationLabel); @@ -205,6 +212,14 @@ public void actionPerformed(java.awt.event.ActionEvent evt) { }); nPanel.add(orientationCB); + stateCB.setPreferredSize(new java.awt.Dimension(150, 22)); + stateCB.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + stateCBActionPerformed(evt); + } + }); + nPanel.add(stateCB); + incomingSuffix.setText("Departure Suffix"); nPanel.add(incomingSuffix); @@ -217,14 +232,6 @@ public void actionPerformed(java.awt.event.ActionEvent evt) { }); nPanel.add(departureSideCB); - stateCB.setPreferredSize(new java.awt.Dimension(150, 22)); - stateCB.addActionListener(new java.awt.event.ActionListener() { - public void actionPerformed(java.awt.event.ActionEvent evt) { - stateCBActionPerformed(evt); - } - }); - nPanel.add(stateCB); - reverseArrivalCB.setText("Reverse Arrival Side"); reverseArrivalCB.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { @@ -233,14 +240,6 @@ public void actionPerformed(java.awt.event.ActionEvent evt) { }); nPanel.add(reverseArrivalCB); - rotateButton.setText("Rotate"); - rotateButton.addActionListener(new java.awt.event.ActionListener() { - public void actionPerformed(java.awt.event.ActionEvent evt) { - rotateButtonActionPerformed(evt); - } - }); - nPanel.add(rotateButton); - showLocCB.setLabel("Show Locomotive"); showLocCB.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { @@ -282,33 +281,33 @@ public void actionPerformed(java.awt.event.ActionEvent evt) { centerSP.setDoubleBuffered(true); centerSP.setMinimumSize(new java.awt.Dimension(1250, 440)); centerSP.setPreferredSize(new java.awt.Dimension(1250, 440)); - centerSP.setViewportView(blockTileCanvas); + centerSP.setViewportView(canvas); centerSP.addComponentListener(new java.awt.event.ComponentAdapter() { public void componentResized(java.awt.event.ComponentEvent evt) { centerSPComponentResized(evt); } }); - blockTileCanvas.setAutoscrolls(true); - blockTileCanvas.setPreferredSize(null); - blockTileCanvas.addComponentListener(new java.awt.event.ComponentAdapter() { + canvas.setAutoscrolls(true); + canvas.setPreferredSize(null); + canvas.addComponentListener(new java.awt.event.ComponentAdapter() { public void componentResized(java.awt.event.ComponentEvent evt) { - blockTileCanvasComponentResized(evt); + canvasComponentResized(evt); } }); - javax.swing.GroupLayout blockTileCanvasLayout = new javax.swing.GroupLayout(blockTileCanvas); - blockTileCanvas.setLayout(blockTileCanvasLayout); - blockTileCanvasLayout.setHorizontalGroup( - blockTileCanvasLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + javax.swing.GroupLayout canvasLayout = new javax.swing.GroupLayout(canvas); + canvas.setLayout(canvasLayout); + canvasLayout.setHorizontalGroup( + canvasLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGap(0, 1248, Short.MAX_VALUE) ); - blockTileCanvasLayout.setVerticalGroup( - blockTileCanvasLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + canvasLayout.setVerticalGroup( + canvasLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGap(0, 498, Short.MAX_VALUE) ); - centerSP.setViewportView(blockTileCanvas); + centerSP.setViewportView(canvas); getContentPane().add(centerSP, java.awt.BorderLayout.CENTER); @@ -411,7 +410,7 @@ private void centerSPComponentResized(java.awt.event.ComponentEvent evt) {//GEN- //wordt bij init aangeroepen }//GEN-LAST:event_centerSPComponentResized - private void blockTileCanvasComponentResized(java.awt.event.ComponentEvent evt) {//GEN-FIRST:event_blockTileCanvasComponentResized + private void canvasComponentResized(java.awt.event.ComponentEvent evt) {//GEN-FIRST:event_canvasComponentResized //Logger.trace(evt); //this.centerSP.setLocation(0, 0); //this.centerSP.getViewport().revalidate(); @@ -437,8 +436,9 @@ private void blockTileCanvasComponentResized(java.awt.event.ComponentEvent evt) //JViewport vp = scrollpane.getViewport(); //vp.setViewSize(newsize); // revalidate(); +//jcs.ui.layout.tiles.UnscaledBlockTileFrame.GridCanvas - }//GEN-LAST:event_blockTileCanvasComponentResized + }//GEN-LAST:event_canvasComponentResized /** * @param args the command line arguments @@ -456,23 +456,22 @@ public static void main(String args[]) { app.setTitle("Unscaled Tile Tester"); app.pack(); app.setLocationRelativeTo(null); - //app.setVisible(true); - }); - } - @Override - public void propertyChange(PropertyChangeEvent evt) { - if ("repaintTile".equals(evt.getPropertyName())) { - Tile t = (Tile) evt.getNewValue(); - Logger.trace("Tile: " + t); - this.repaint(); - } + }); } +// @Override +// public void propertyChange(PropertyChangeEvent evt) { +// if ("repaintTile".equals(evt.getPropertyName())) { +// Tile t = (Tile) evt.getNewValue(); +// Logger.trace("Tile: " + t); +// this.repaint(); +// } +// } // Variables declaration - do not modify//GEN-BEGIN:variables private javax.swing.JRadioButton backwardsRB; - private jcs.ui.layout.tiles.UnscaledBlockCanvas blockTileCanvas; + private jcs.ui.layout.tiles.UnscaledBlockCanvas canvas; private javax.swing.JScrollPane centerSP; private javax.swing.JComboBox departureSideCB; private javax.swing.JRadioButton forwardsRB; From fe9aa690ef917c97c6a212db26b8afc115a93b1b Mon Sep 17 00:00:00 2001 From: Frans Jacobs <41232225+fransjacobs@users.noreply.github.com> Date: Mon, 20 Jan 2025 20:13:41 +0100 Subject: [PATCH 03/24] Fix rotating of Block --- src/main/java/jcs/ui/layout/tiles/Block.java | 111 ++++++++++-------- src/main/java/jcs/ui/layout/tiles/Tile.java | 35 +++--- .../ui/layout/tiles/UnscaledBlockCanvas.java | 4 +- ...ileFrame.form => UnscaledBlockTester.form} | 3 - ...ileFrame.java => UnscaledBlockTester.java} | 81 +++++-------- 5 files changed, 117 insertions(+), 117 deletions(-) rename src/test/java/jcs/ui/layout/tiles/{UnscaledBlockTileFrame.form => UnscaledBlockTester.form} (98%) rename src/test/java/jcs/ui/layout/tiles/{UnscaledBlockTileFrame.java => UnscaledBlockTester.java} (88%) diff --git a/src/main/java/jcs/ui/layout/tiles/Block.java b/src/main/java/jcs/ui/layout/tiles/Block.java index 780c3907..ea23a0c8 100755 --- a/src/main/java/jcs/ui/layout/tiles/Block.java +++ b/src/main/java/jcs/ui/layout/tiles/Block.java @@ -72,14 +72,7 @@ private static int blockHeight(Orientation orientation) { public Block(TileBean tileBean) { super(tileBean, blockWidth(tileBean.getOrientation()), blockHeight(tileBean.getOrientation())); setModel(new DefaultTileModel()); - - if (Orientation.EAST == tileBean.getOrientation() || Orientation.WEST == tileBean.getOrientation()) { - this.renderWidth = RENDER_WIDTH * 3; - this.renderHeight = RENDER_HEIGHT; - } else { - this.renderWidth = RENDER_WIDTH; - this.renderHeight = RENDER_HEIGHT * 3; - } + changeRenderSize(); } public Block(Orientation orientation, Point center) { @@ -93,8 +86,11 @@ public Block(Orientation orientation, int x, int y) { public Block(Orientation orientation, int x, int y, int width, int height) { super(TileType.BLOCK, orientation, x, y, width, height); setModel(new DefaultTileModel()); + changeRenderSize(); + } - if (Orientation.EAST == orientation || Orientation.WEST == orientation) { + private void changeRenderSize() { + if (Orientation.EAST == tileOrientation || Orientation.WEST == tileOrientation) { this.renderWidth = RENDER_WIDTH * 3; this.renderHeight = RENDER_HEIGHT; } else { @@ -312,28 +308,28 @@ public String getIdSuffix(Tile other) { } if (match != null) { - if (Orientation.EAST == getOrientation() && Orientation.EAST == match) { + if (Orientation.EAST == tileOrientation && Orientation.EAST == match) { suffix = "+"; } - if (Orientation.WEST == getOrientation() && Orientation.WEST == match) { + if (Orientation.WEST == tileOrientation && Orientation.WEST == match) { suffix = "+"; } - if (Orientation.EAST == getOrientation() && Orientation.WEST == match) { + if (Orientation.EAST == tileOrientation && Orientation.WEST == match) { suffix = "-"; } - if (Orientation.WEST == getOrientation() && Orientation.EAST == match) { + if (Orientation.WEST == tileOrientation && Orientation.EAST == match) { suffix = "-"; } - if (Orientation.NORTH == getOrientation() && Orientation.NORTH == match) { + if (Orientation.NORTH == tileOrientation && Orientation.NORTH == match) { suffix = "+"; } - if (Orientation.NORTH == getOrientation() && Orientation.SOUTH == match) { + if (Orientation.NORTH == tileOrientation && Orientation.SOUTH == match) { suffix = "-"; } - if (Orientation.SOUTH == getOrientation() && Orientation.SOUTH == match) { + if (Orientation.SOUTH == tileOrientation && Orientation.SOUTH == match) { suffix = "+"; } - if (Orientation.SOUTH == getOrientation() && Orientation.NORTH == match) { + if (Orientation.SOUTH == tileOrientation && Orientation.NORTH == match) { suffix = "-"; } } @@ -341,26 +337,24 @@ public String getIdSuffix(Tile other) { } @Override - public void rotate() { - super.rotate(); - Dimension d; - if (Orientation.EAST.equals(getOrientation()) || Orientation.WEST.equals(getOrientation())) { - d = new Dimension(DEFAULT_WIDTH * 3, DEFAULT_HEIGHT); - //this.width = DEFAULT_WIDTH * 3; - //this.height = DEFAULT_HEIGHT; + public Orientation rotate() { + rotate(false); + int w = blockWidth(tileOrientation); + int h = blockHeight(tileOrientation); - this.renderWidth = RENDER_WIDTH * 3; - this.renderHeight = RENDER_HEIGHT; - } else { - d = new Dimension(DEFAULT_WIDTH, DEFAULT_HEIGHT * 3); - //this.width = DEFAULT_WIDTH; - //this.height = DEFAULT_HEIGHT * 3; + Dimension d = new Dimension(w, h); - this.renderWidth = RENDER_WIDTH; - this.renderHeight = RENDER_HEIGHT * 3; - } - setSize(d); +// if (Orientation.EAST == tileOrientation || Orientation.WEST == tileOrientation) { +// d = new Dimension(w, h); +// } else { +// d = new Dimension(DEFAULT_WIDTH, DEFAULT_HEIGHT * 3); +// } setPreferredSize(d); + setSize(d); + changeRenderSize(); + + repaint(); + return tileOrientation; } /** @@ -455,7 +449,7 @@ public void renderTile(Graphics2D g2) { g2.setStroke(new BasicStroke(20, BasicStroke.CAP_SQUARE, BasicStroke.JOIN_ROUND)); g2.setPaint(Color.darkGray); - g2.drawLine(rw + 20, yy - 0, rw + 20, yy + 300); + g2.drawLine(rw + GRID, yy - 0, rw + GRID, yy + 300); //When there is a locomotive in the block mark the direction of travel. //The default, forwards is in the direction of the block orientation, i.e. the + @@ -571,8 +565,7 @@ private void renderRightArrow(Graphics2D g2) { } @Override - public void renderTileRoute(Graphics2D g2d - ) { + public void renderTileRoute(Graphics2D g2d) { if (routeBlockState != null) { backgroundColor = getBlockStateColor(routeBlockState); } @@ -599,7 +592,7 @@ protected void overlayLocImage(Graphics2D g2d) { //Logger.trace("LocImage w: " + w + " h: " + h); //Depending on the block orientation the image needs to be rotated and flipped //Incase the departure suffix is NOT set center the locomotive image - switch (getOrientation()) { + switch (tileOrientation) { case WEST -> { int xx; int w = locImage.getWidth(null); @@ -817,20 +810,46 @@ protected void paintComponent(Graphics g) { long started = System.currentTimeMillis(); super.paintComponent(g); + int w = getWidth(); + int h = getHeight(); + //upon firts initializatien the width and height could still be wrong for reasons unknow to me... + //reset widh or height + boolean reset = false; + if (w != blockWidth(tileOrientation)) { + w = blockWidth(tileOrientation); + reset = true; + } + if (h != blockHeight(tileOrientation)) { + h = blockHeight(tileOrientation); + reset = true; + } + + if (reset) { + Logger.trace(id + " Resetting size... "); + Dimension d = new Dimension(w, h); + setPreferredSize(d); + setSize(d); + } + + int xx, yy; if (tileOrientation == Orientation.EAST || tileOrientation == Orientation.WEST) { - setBounds(this.tileX - GRID - GRID * 2, this.tileY - GRID, this.getWidth(), this.getHeight()); + xx = tileX - GRID - GRID * 2; + yy = tileY - GRID; + setBounds(xx, yy, w, h); } else { - setBounds(this.tileX - GRID, this.tileY - GRID - GRID * 2, this.getWidth(), this.getHeight()); + xx = tileX - GRID; + yy = tileY - GRID - GRID * 2; + setBounds(xx, yy, w, h); } + Logger.trace(id + ": " + tileOrientation + " W: " + getWidth() + " H: " + getHeight() + " tX: " + tileX + ", tY: " + tileY + " xx: " + xx + " yy: " + yy); + Graphics2D g2 = (Graphics2D) g.create(); drawTile(g2); g2.dispose(); g.drawImage(tileImage, 0, 0, null); - Logger.trace(id + ": W: " + getWidth() + " H: " + getHeight() + " oX: " + renderOffsetX + " oY: " + renderOffsetY); - long now = System.currentTimeMillis(); Logger.trace(id + " Duration: " + (now - started) + " ms."); } @@ -853,15 +872,15 @@ protected void drawCenterPoint(Graphics2D g2d, Color color, double size) { dY3 = (renderHeight / 2 - size / 2 / 2); } else { dY1 = (renderWidth / 2 - size / 2 / 2); - + dY2 = (renderWidth / 2 - size / 2 / 2); - + dY3 = (renderWidth / 2 - size / 2 / 2); dX1 = (renderHeight / 3 / 2 - size / 2 / 2); - + dX2 = (renderHeight / 2 - size / 2); - + dX3 = (renderHeight / 3 / 2 + renderHeight / 3 * 2 - size / 2); } diff --git a/src/main/java/jcs/ui/layout/tiles/Tile.java b/src/main/java/jcs/ui/layout/tiles/Tile.java index 5274714b..b1794914 100755 --- a/src/main/java/jcs/ui/layout/tiles/Tile.java +++ b/src/main/java/jcs/ui/layout/tiles/Tile.java @@ -167,18 +167,18 @@ protected Tile(TileType tileType, Orientation orientation, Direction direction, } protected Tile(TileType tileType, Orientation orientation, Direction direction, int x, int y, int width, int height, Color backgroundColor, Color selectedColor) { - this.setLayout(null); this.tileType = tileType; - this.tileOrientation = orientation; this.tileDirection = direction; - this.tileX = x; this.tileY = y; Dimension d = new Dimension(width, height); - this.setSize(d); - this.setPreferredSize(d); + super.setPreferredSize(d); + super.setSize(d); + + int w = getWidth(); + int h = getHeight(); this.renderWidth = RENDER_WIDTH; this.renderHeight = RENDER_HEIGHT; @@ -193,6 +193,7 @@ protected Tile(TileType tileType, Orientation orientation, Direction direction, if (this.selectedColor == null) { this.selectedColor = DEFAULT_SELECTED_COLOR; } + this.setLayout(null); } protected Tile(Object tileBean) { @@ -531,9 +532,8 @@ public int getRenderHeight() { //@Override public void drawTile(Graphics2D g2d) { // by default and image is rendered in the EAST orientation - Orientation o = getOrientation(); - if (o == null) { - o = Orientation.EAST; + if (tileOrientation == null) { + tileOrientation = Orientation.EAST; } tileImage = createImage(); @@ -554,7 +554,7 @@ public void drawTile(Graphics2D g2d) { int ox = 0, oy = 0; AffineTransform trans = new AffineTransform(); - switch (o) { + switch (tileOrientation) { case SOUTH -> { trans.rotate(Math.PI / 2, renderWidth / 2, renderHeight / 2); ox = (renderHeight - renderWidth) / 2; @@ -590,7 +590,7 @@ public void drawTile(Graphics2D g2d) { } // Scale the image back... - if (this.model.isScaleImage()) { + if (model.isScaleImage()) { tileImage = Scalr.resize(tileImage, Method.AUTOMATIC, Mode.FIT_EXACT, getWidth(), getHeight(), Scalr.OP_ANTIALIAS); } @@ -637,17 +637,21 @@ protected void drawCenterPoint(Graphics2D g2d, Color color, double size) { /** * Rotate the tile clockwise 90 deg + * + * @return */ - public void rotate() { - rotate(true); + public Orientation rotate() { + return rotate(true); } /** * Rotate the tile clockwise 90 deg + * + * @param repaint + * @return */ - void rotate(boolean repaint) { - - switch (getOrientation()) { + protected Orientation rotate(boolean repaint) { + switch (tileOrientation) { case EAST -> setOrientation(Orientation.SOUTH); case SOUTH -> @@ -660,6 +664,7 @@ void rotate(boolean repaint) { if (repaint) { repaint(); } + return tileOrientation; } public void flipHorizontal() { diff --git a/src/test/java/jcs/ui/layout/tiles/UnscaledBlockCanvas.java b/src/test/java/jcs/ui/layout/tiles/UnscaledBlockCanvas.java index 39eb21b4..4dce3bf3 100644 --- a/src/test/java/jcs/ui/layout/tiles/UnscaledBlockCanvas.java +++ b/src/test/java/jcs/ui/layout/tiles/UnscaledBlockCanvas.java @@ -28,8 +28,8 @@ public class UnscaledBlockCanvas extends JPanel { //implements PropertyChangeLis public UnscaledBlockCanvas() { setLayout(null); - setOpaque(true); - setDoubleBuffered(false); + setOpaque(false); + setDoubleBuffered(true); } @Override diff --git a/src/test/java/jcs/ui/layout/tiles/UnscaledBlockTileFrame.form b/src/test/java/jcs/ui/layout/tiles/UnscaledBlockTester.form similarity index 98% rename from src/test/java/jcs/ui/layout/tiles/UnscaledBlockTileFrame.form rename to src/test/java/jcs/ui/layout/tiles/UnscaledBlockTester.form index 144e15cd..098f9189 100644 --- a/src/test/java/jcs/ui/layout/tiles/UnscaledBlockTileFrame.form +++ b/src/test/java/jcs/ui/layout/tiles/UnscaledBlockTester.form @@ -199,9 +199,6 @@ - - - diff --git a/src/test/java/jcs/ui/layout/tiles/UnscaledBlockTileFrame.java b/src/test/java/jcs/ui/layout/tiles/UnscaledBlockTester.java similarity index 88% rename from src/test/java/jcs/ui/layout/tiles/UnscaledBlockTileFrame.java rename to src/test/java/jcs/ui/layout/tiles/UnscaledBlockTester.java index 5ea0df8e..10444f86 100644 --- a/src/test/java/jcs/ui/layout/tiles/UnscaledBlockTileFrame.java +++ b/src/test/java/jcs/ui/layout/tiles/UnscaledBlockTester.java @@ -29,8 +29,8 @@ import jcs.entities.BlockBean; import jcs.entities.BlockBean.BlockState; import jcs.entities.LocomotiveBean; -import jcs.entities.TileBean; import jcs.entities.TileBean.Orientation; +import jcs.ui.layout.LayoutUtil; import jcs.ui.util.ImageUtil; import org.tinylog.Logger; @@ -38,20 +38,24 @@ * * @author FJA */ -public class UnscaledBlockTileFrame extends JFrame { //implements PropertyChangeListener { +public class UnscaledBlockTester extends JFrame { //implements PropertyChangeListener { private Tile blockTile; /** * Creates new form UnscaledBlockTileFrame */ - public UnscaledBlockTileFrame() { + public UnscaledBlockTester() { initComponents(); + this.orientationCB.setModel(createOrientationComboBoxModel()); this.departureSideCB.setSelectedItem(""); this.stateCB.setModel(createStateComboBoxModel()); - initBlock(); + this.blockTile = initBlock(); + + canvas.add(blockTile); + centerSP.getViewport().validate(); setVisible(true); } @@ -96,64 +100,43 @@ private LocomotiveBean createLocomotiveBean() { return lb; } - private void initBlock() { - Dimension vps = this.canvas.getPreferredSize(); - Logger.trace("Canvas size w: " + canvas.getWidth() + " h: " + canvas.getHeight()); - blockTile = new Block(TileBean.Orientation.EAST, vps.width / 2, vps.height / 2); + private Block initBlock() { + Point center = LayoutUtil.snapToGrid(canvas.getWidth() / 2, canvas.getHeight() / 2); + int cX = center.x; + int cY = center.y; + + Logger.trace("Center X: " + cX + " Y: " + cY); - blockTile.setId("bk-1"); + Block block = new Block(Orientation.EAST, cX, cY); + block.setId("bk-1"); + block.setScaleImage(!scaleCB.isSelected()); + canvas.setExpanded(scaleCB.isSelected()); BlockBean blockBean = new BlockBean(); - blockBean.setId(blockTile.getId()); - blockBean.setTileId(blockTile.getId()); + blockBean.setId(block.getId()); + blockBean.setTileId(block.getId()); blockBean.setDescription("Blok 1"); //bbe.setArrivalSuffix((String) this.incomingSideCB.getSelectedItem()); blockBean.setDepartureSuffix(null); - blockBean.setBlockState((BlockState) this.stateCB.getSelectedItem()); - blockBean.setReverseArrival(this.reverseArrivalCB.isSelected()); + blockBean.setBlockState((BlockState) stateCB.getSelectedItem()); + blockBean.setReverseArrival(reverseArrivalCB.isSelected()); - if (this.showLocCB.isSelected()) { + if (showLocCB.isSelected()) { blockBean.setLocomotive(createLocomotiveBean()); } else { blockBean.setLocomotive(null); } - blockTile.setBlockBean(blockBean); - - blockTile.setScaleImage(!scaleCB.isSelected()); - canvas.setExpanded(scaleCB.isSelected()); + block.setBlockBean(blockBean); - canvas.add(blockTile); - centerSP.getViewport().validate(); + return block; } private void changeOrientation() { Orientation orientation = (Orientation) this.orientationCB.getSelectedItem(); blockTile.setOrientation(orientation); -// if (Orientation.EAST.equals(blockTile.getOrientation()) || Orientation.WEST.equals(blockTile.getOrientation())) { -// ((Block) blockTile).setWidth(Tile.DEFAULT_WIDTH * 3); -// ((Block) blockTile).setHeight(Tile.DEFAULT_HEIGHT); -// -// ((Block) blockTile).setRenderWidth(Tile.RENDER_WIDTH * 3); -// ((Block) blockTile).setRenderHeight(Tile.RENDER_HEIGHT); -// } else { -// ((Block) blockTile).setWidth(Tile.DEFAULT_WIDTH); -// ((Block) blockTile).setHeight(Tile.DEFAULT_HEIGHT * 3); -// -// ((Block) blockTile).setRenderWidth(Tile.RENDER_WIDTH); -// ((Block) blockTile).setRenderHeight(Tile.RENDER_HEIGHT * 3); -// } -// -// blockTile.drawTile((Graphics2D) getGraphics(), this.showCenterCB.isSelected()); - Dimension vps = this.canvas.getPreferredSize(); - - Point cc = new Point(Math.abs(vps.width / 2), Math.abs(vps.height / 2)); - blockTile.setCenter(cc); - - this.centerSP.getViewport().revalidate(); - repaint(); } /** @@ -289,7 +272,6 @@ public void componentResized(java.awt.event.ComponentEvent evt) { }); canvas.setAutoscrolls(true); - canvas.setPreferredSize(null); canvas.addComponentListener(new java.awt.event.ComponentAdapter() { public void componentResized(java.awt.event.ComponentEvent evt) { canvasComponentResized(evt); @@ -315,12 +297,9 @@ public void componentResized(java.awt.event.ComponentEvent evt) { }// //GEN-END:initComponents private void rotateButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_rotateButtonActionPerformed - this.blockTile.rotate(); - - Orientation orientation = blockTile.getOrientation(); + Orientation orientation = blockTile.rotate(); this.orientationCB.setSelectedItem(orientation); - Logger.trace("Blok is rotated to " + blockTile.getOrientation()); - repaint(); + Logger.trace("Blok is rotated to " + orientation); }//GEN-LAST:event_rotateButtonActionPerformed private void showLocCBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_showLocCBActionPerformed @@ -436,7 +415,7 @@ private void canvasComponentResized(java.awt.event.ComponentEvent evt) {//GEN-FI //JViewport vp = scrollpane.getViewport(); //vp.setViewSize(newsize); // revalidate(); -//jcs.ui.layout.tiles.UnscaledBlockTileFrame.GridCanvas +//jcs.ui.layout.tiles.UnscaledBlockTester.GridCanvas }//GEN-LAST:event_canvasComponentResized @@ -452,10 +431,10 @@ public static void main(String args[]) { /* Create and display the form */ java.awt.EventQueue.invokeLater(() -> { - UnscaledBlockTileFrame app = new UnscaledBlockTileFrame(); + UnscaledBlockTester app = new UnscaledBlockTester(); app.setTitle("Unscaled Tile Tester"); - app.pack(); app.setLocationRelativeTo(null); + app.pack(); }); } From 8db4c879cf198cbeae45f6f9fdb8955943def7fb Mon Sep 17 00:00:00 2001 From: Frans Jacobs <41232225+fransjacobs@users.noreply.github.com> Date: Wed, 22 Jan 2025 20:10:03 +0100 Subject: [PATCH 04/24] More refactoring for Block --- src/main/java/jcs/ui/layout/LayoutUtil.java | 492 +--------------- src/main/java/jcs/ui/layout/tiles/Block.java | 153 ++--- src/main/java/jcs/ui/layout/tiles/Cross.java | 10 +- .../jcs/ui/layout/tiles/DefaultTileModel.java | 80 +++ src/main/java/jcs/ui/layout/tiles/Tile.java | 534 ++++++++++-------- .../java/jcs/ui/layout/tiles/TileModel.java | 28 +- src/test/java/jcs/ui/layout/TileTest.java | 32 +- .../jcs/ui/layout/tiles/DotGridCanvas.java | 4 - .../ui/layout/tiles/UnscaledBlockCanvas.java | 14 +- .../ui/layout/tiles/UnscaledBlockTester.form | 5 +- .../ui/layout/tiles/UnscaledBlockTester.java | 118 ++-- 11 files changed, 522 insertions(+), 948 deletions(-) diff --git a/src/main/java/jcs/ui/layout/LayoutUtil.java b/src/main/java/jcs/ui/layout/LayoutUtil.java index d8525e07..a1e723a2 100644 --- a/src/main/java/jcs/ui/layout/LayoutUtil.java +++ b/src/main/java/jcs/ui/layout/LayoutUtil.java @@ -17,17 +17,14 @@ import jcs.ui.layout.tiles.Tile; import java.awt.Point; +import jcs.entities.TileBean.Orientation; +import static jcs.ui.layout.tiles.Block.BLOCK_HEIGHT; +import static jcs.ui.layout.tiles.Block.BLOCK_WIDTH; +import static jcs.ui.layout.tiles.Tile.DEFAULT_HEIGHT; +import static jcs.ui.layout.tiles.Tile.DEFAULT_WIDTH; -/** - * - * @author frans - */ public class LayoutUtil { -// private final static Map tiles = new HashMap<>(); -// private final static Map altTilesLookup = new HashMap<>(); -// private final static Map tileLookup = new HashMap<>(); - private LayoutUtil() { } @@ -66,159 +63,6 @@ public static int getGridY(int y) { return (sy - Tile.GRID) / (Tile.GRID * 2); } -// private static void addRelatedBeans(TileBean tileBean) { -// TileType tileType = tileBean.getTileType(); -// switch (tileType) { -// case STRAIGHT -> { -// } -// case STRAIGHT_DIR -> { -// } -// case END -> { -// } -// case CURVED -> { -// } -// case SWITCH -> { -// if (tileBean.getAccessoryBean() != null) { -// tileBean.setAccessoryBean(PersistenceFactory.getService().getAccessoryById(tileBean.getAccessoryId())); -// } -// } -// case CROSS -> { -// if (tileBean.getAccessoryBean() != null) { -// tileBean.setAccessoryBean(PersistenceFactory.getService().getAccessoryById(tileBean.getAccessoryId())); -// } -// } -// case SIGNAL -> { -// if (tileBean.getAccessoryBean() != null) { -// tileBean.setAccessoryBean(PersistenceFactory.getService().getAccessoryById(tileBean.getAccessoryId())); -// } -// } -// case SENSOR -> { -// if (tileBean.getSensorId() != null) { -// tileBean.setSensorBean(PersistenceFactory.getService().getSensor(tileBean.getSensorId())); -// } -// } -// case BLOCK -> { -// } -// default -> -// Logger.warn("Unknown Tile Type " + tileType); -// } -// } - -// public static final Map loadLayout(boolean drawGridLines, boolean showValues) { -// return loadLayout(drawGridLines, null, showValues); -// } - - /** - * Load Tiles from the persistent store - * - * @param drawGridLines - * @param listener - * @param showValues - * @return A Map of tiles, key is the center point of the tile - */ -// public static final Map loadLayout(boolean drawGridLines, PropertyChangeListener listener, boolean showValues) { -// //synchronized (LayoutUtil.tiles) { -// LayoutUtil.tiles.clear(); -// LayoutUtil.altTilesLookup.clear(); -// LayoutUtil.tileLookup.clear(); -// -// if (PersistenceFactory.getService() != null) { -// List tbl = PersistenceFactory.getService().getTiles(); -// -// Set beans = new HashSet<>(tbl); -// -// for (TileBean tb : beans) { -// addRelatedBeans(tb); -// Tile tile = TileFactory.createTile(tb, drawGridLines, showValues); -// -// if (listener != null) { -// tile.setPropertyChangeListener(listener); -// } -// -// registerAsEventListener(tile); -// -// LayoutUtil.tiles.put(tile.getCenter(), tile); -// for (Point ap : tile.getAltPoints()) { -// LayoutUtil.altTilesLookup.put(ap, tile); -// } -// -// LayoutUtil.tileLookup.put(tile.getId(), tile); -// } -// -// Logger.debug("Loaded " + tiles.size() + " Tiles..."); -// } else { -// Logger.error("Can't load tiles, no PersistenceService available"); -// } -// //} -// return LayoutUtil.tiles; -// } - -// private static void registerAsEventListener(Tile tile) { -// -//// switch (tile.getTileType()) { -//// case SENSOR: -//// TrackServiceFactory.getTrackService().addSensorListener((SensorListener) tile); -//// break; -//// case SWITCH: -//// TrackServiceFactory.getTrackService().addAccessoryListener((AccessoryListener) tile); -//// break; -//// case SIGNAL: -//// TrackServiceFactory.getTrackService().addAccessoryListener((AccessoryListener) tile); -//// break; -//// -//// default: -//// //Do nothing -//// break; -//// } -// } - -// private static boolean isNotLoaded() { -// return LayoutUtil.tiles == null || LayoutUtil.tiles.isEmpty(); -// } - -// public static Tile findTile(Point cp) { -// if (LayoutUtil.tiles == null || LayoutUtil.tiles.isEmpty()) { -// LayoutUtil.loadLayout(true, false); -// } -// Tile result = LayoutUtil.tiles.get(cp); -// -// if (result == null) { -// result = LayoutUtil.altTilesLookup.get(cp); -// if (result != null) { -// } -// } -// return result; -// } - -// public static boolean isTile(Point cp) { -// return findTile(cp) != null; -// } - -// public static boolean isBlock(Point cp) { -// Tile t = findTile(cp); -// if (t == null) { -// return false; -// } -// return TileType.BLOCK.equals(t.getTileType()); -// } - -// public static boolean isTrack(Point cp) { -// Tile t = findTile(cp); -// if (t == null) { -// return false; -// } -// TileType tt = t.getTileType(); -// return TileType.CURVED.equals(tt) || TileType.CURVED.equals(tt) || TileType.SENSOR.equals(tt) || TileType.SIGNAL.equals(tt) || TileType.STRAIGHT.equals(tt); -// } - -// public static final Map getTiles() { -// if (LayoutUtil.tiles == null || LayoutUtil.tiles.isEmpty()) { -// LayoutUtil.loadLayout(true, false); -// } -// -// return LayoutUtil.tiles; -// } - /** * Returns the euclidean distance of 2 Points * @@ -233,314 +77,20 @@ public static double euclideanDistance(Point p1, Point p2) { return d; } -// public static Set adjacentPointsFor(Tile tile) { -// return adjacentPointsFor(tile, AccessoryValue.OFF); -// } -// public static Set adjacentPointsFor(Tile tile, AccessoryValue accessoryValue) { -// Set adjacent = new HashSet<>(); -// int x = tile.getCenterX(); -// int y = tile.getCenterY(); -// int w = tile.getWidth(); -// int h = tile.getHeight(); -// Orientation orientation = tile.getOrientation(); -// Direction direction = tile.getDirection(); -// -// int oX = w / 2 + Tile.GRID; -// int oY = h / 2 + Tile.GRID; -// -// switch (tile.getTileType()) { -// case CURVED -> { -// switch (orientation) { -// case SOUTH -> { -// adjacent.add(new Point(x - oX, y)); -// adjacent.add(new Point(x, y + oY)); -// } -// case WEST -> { -// adjacent.add(new Point(x - oX, y)); -// adjacent.add(new Point(x, y - oY)); -// } -// case NORTH -> { -// adjacent.add(new Point(x + oX, y)); -// adjacent.add(new Point(x, y - oY)); -// } -// default -> { -// //EAST -// adjacent.add(new Point(x + oX, y)); -// adjacent.add(new Point(x, y + oY)); -// } -// } -// } -// case CROSS -> { -// if (Orientation.EAST.equals(orientation) || Orientation.WEST.equals(orientation)) { -// adjacent.add(new Point(x + oX, y)); -// adjacent.add(new Point(x - oX, y)); -// } else { -// adjacent.add(new Point(x, y + oY)); -// adjacent.add(new Point(x, y - oY)); -// } -// } -// case SWITCH -> { -// switch (orientation) { -// case SOUTH: -// switch (accessoryValue) { -// case GREEN: -// adjacent.add(new Point(x, y - oY)); -// break; -// case RED: -// if (Direction.LEFT.equals(direction)) { -// adjacent.add(new Point(x - oX, y)); -// } else { -// adjacent.add(new Point(x + oX, y)); -// } -// break; -// default: -// adjacent.add(new Point(x, y + oY)); -// } -// break; -// case WEST: -// switch (accessoryValue) { -// case GREEN: -// adjacent.add(new Point(x + oX, y)); -// break; -// case RED: -// if (Direction.LEFT.equals(direction)) { -// adjacent.add(new Point(x, y - oY)); -// } else { -// adjacent.add(new Point(x, y + oY)); -// } -// break; -// default: -// adjacent.add(new Point(x - oX, y)); -// break; -// } -// break; -// case NORTH: -// switch (accessoryValue) { -// case GREEN: -// adjacent.add(new Point(x, y + oY)); -// break; -// case RED: -// if (Direction.LEFT.equals(direction)) { -// adjacent.add(new Point(x + oX, y)); -// } else { -// adjacent.add(new Point(x - oX, y)); -// } -// break; -// default: -// adjacent.add(new Point(x, y - oY)); -// break; -// } -// break; -// default: -// //EAST -// switch (accessoryValue) { -// case GREEN: -// adjacent.add(new Point(x - oX, y)); -// break; -// case RED: -// if (Direction.LEFT.equals(direction)) { -// adjacent.add(new Point(x, y + oY)); -// } else { -// adjacent.add(new Point(x, y - oY)); -// } -// break; -// default: -// adjacent.add(new Point(x + oX, y)); -// break; -// } -// break; -// } -// } -// default -> { -// if (Orientation.EAST.equals(orientation) || Orientation.WEST.equals(orientation)) { -// adjacent.add(new Point(x + oX, y)); -// adjacent.add(new Point(x - oX, y)); -// } else { -// adjacent.add(new Point(x, y + oY)); -// adjacent.add(new Point(x, y - oY)); -// } -// } -// } -// return adjacent; -// } -// private static Point getAdjacentPoint(Tile block, String plusMinus) { -// int x = block.getCenterX(); -// int y = block.getCenterY(); -// int w = block.getWidth(); -// int h = block.getHeight(); -// Orientation o = block.getOrientation(); -// -// Point neighborPlus, neighborMin; -// switch (o) { -// case SOUTH: -// neighborPlus = new Point(x, y + h / 3 + Tile.GRID * 2); -// neighborMin = new Point(x, y - h / 3 - Tile.GRID * 2); -// break; -// case WEST: -// neighborPlus = new Point(x - w / 3 - Tile.GRID * 2, y); -// neighborMin = new Point(x + w / 3 + Tile.GRID * 2, y); -// break; -// case NORTH: -// neighborPlus = new Point(x, y - h / 3 - Tile.GRID * 2); -// neighborMin = new Point(x, y + h / 3 + Tile.GRID * 2); -// break; -// default: -// //East -// neighborPlus = new Point(x + w / 3 + Tile.GRID * 2, y); -// neighborMin = new Point(x - w / 3 - Tile.GRID * 2, y); -// break; -// } -// if ("+".equals(plusMinus)) { -// return neighborPlus; -// } else { -// return neighborMin; -// } -// } -// public static boolean isPlusAdjacent(Tile block, Point point) { -// Point p = getAdjacentPoint(block, "+"); -// return p.equals(point); -// } -// public static Point getPlusAdjacent(Tile block) { -// Point p = getAdjacentPoint(block, "+"); -// return p; -// } -// public static Point getMinusAdjacent(Tile block) { -// Point p = getAdjacentPoint(block, "-"); -// return p; -// } -// public static boolean isMinusAdjacent(Tile block, Point point) { -// Point p = getAdjacentPoint(block, "-"); -// return p.equals(point); -// } -// private static Point getPlusMinus(Tile block, String plusMinus) { -// int x = block.getCenterX(); -// int y = block.getCenterY(); -// int w = block.getWidth(); -// int h = block.getHeight(); -// Orientation o = block.getOrientation(); -// -// Point cpPlus, cpMin; -// switch (o) { -// case SOUTH -> { -// cpPlus = new Point(x, y + h / 3); -// cpMin = new Point(x, y - h / 3); -// } -// case WEST -> { -// cpPlus = new Point(x - w / 3, y); -// cpMin = new Point(x + w / 3, y); -// } -// case NORTH -> { -// cpPlus = new Point(x, y - h / 3); -// cpMin = new Point(x, y + h / 3); -// } -// default -> { -// //East -// cpPlus = new Point(x + w / 3, y); -// cpMin = new Point(x - w / 3, y); -// } -// } -// if ("+".equals(plusMinus)) { -// return cpPlus; -// } else { -// return cpMin; -// } -// } - /** - * Obtain the "center" of the plus (+) of a Block Tile - * - * @param block the block - * @return a Point - */ -// public static Point getPlusCenter(Tile block) { -// return getPlusMinus(block, "+"); -// } - /** - * Obtain the "center" of the minus (-) of a Block Tile - * - * @param block the block - * @return a Point - */ -// public static Point getMinusCenter(Tile block) { -// return getPlusMinus(block, "-"); -// } - /** - * The Adjacent Ids depend on the direction of the switch. The common point has 2 Ids one for R and one for G The opposite side has one id for G, the fork side the R - * - * @param tile the "from" - * @param switchTile the "target" - * @return a List with the nodeIds which are adjacent nodes - */ -// public static List getNodeIdsForAdjacentSwitch(Tile tile, Tile switchTile) { -// List nodeIds = new ArrayList<>(); -// Orientation o = switchTile.getOrientation(); -// int tileX = tile.getCenterX(); -// int tileY = tile.getCenterY(); -// int adjX = switchTile.getCenterX(); -// int adjY = switchTile.getCenterY(); -// switch (o) { -// case SOUTH -> { -// if (adjX == tileX && adjY != tileY) { -// //North or South -// if (adjX < tileX) { -// //Common -// nodeIds.add(switchTile.getId()); -// } else { -// //Green -// nodeIds.add(switchTile.getId() + "-G"); -// } -// } else { -// //Red -// nodeIds.add(switchTile.getId() + "-R"); -// } -// } -// case WEST -> { -// //East -// if (adjX != tileX && adjY == tileY) { -// //The common of a East L or R Switch -// if (adjX > tileX) { -// //Common -// nodeIds.add(switchTile.getId()); -// } else { -// //Green -// nodeIds.add(switchTile.getId() + "-G"); -// } -// } else { -// //Red -// nodeIds.add(switchTile.getId() + "-R"); -// } -// } -// case NORTH -> { -// if (adjX == tileX && adjY != tileY) { -// //North or South -// if (adjX > tileX) { -// //Common -// nodeIds.add(switchTile.getId()); -// } else { -// //Green -// nodeIds.add(switchTile.getId() + "-G"); -// } -// } else { -// //Red -// nodeIds.add(switchTile.getId() + "-R"); -// } -// } -// default -> { -// //East -// if (adjX != tileX && adjY == tileY) { -// //The common of a East L or R Switch -// if (adjX < tileX) { -// //Common -// nodeIds.add(switchTile.getId()); -// } else { -// //Green -// nodeIds.add(switchTile.getId() + "-G"); -// } -// } else { -// //Red -// nodeIds.add(switchTile.getId() + "-R"); -// } -// } -// } -// return nodeIds; -// } + public static int blockWidth(Orientation orientation) { + if (Orientation.EAST == orientation || Orientation.WEST == orientation) { + return BLOCK_WIDTH; + } else { + return DEFAULT_WIDTH; + } + } + + public static int blockHeight(Orientation orientation) { + if (Orientation.EAST == orientation || Orientation.WEST == orientation) { + return DEFAULT_HEIGHT; + } else { + return BLOCK_HEIGHT; + } + } + } diff --git a/src/main/java/jcs/ui/layout/tiles/Block.java b/src/main/java/jcs/ui/layout/tiles/Block.java index ea23a0c8..0e315910 100755 --- a/src/main/java/jcs/ui/layout/tiles/Block.java +++ b/src/main/java/jcs/ui/layout/tiles/Block.java @@ -38,6 +38,9 @@ import static jcs.entities.TileBean.Orientation.SOUTH; import static jcs.entities.TileBean.Orientation.WEST; import jcs.entities.TileBean.TileType; +import jcs.ui.layout.LayoutUtil; +import static jcs.ui.layout.LayoutUtil.blockHeight; +import static jcs.ui.layout.LayoutUtil.blockWidth; import jcs.ui.layout.events.TileEvent; import static jcs.ui.layout.tiles.Tile.DEFAULT_HEIGHT; import static jcs.ui.layout.tiles.Tile.DEFAULT_WIDTH; @@ -53,24 +56,8 @@ public class Block extends Tile { protected BlockState routeBlockState; - private static int blockWidth(Orientation orientation) { - if (Orientation.EAST == orientation || Orientation.WEST == orientation) { - return BLOCK_WIDTH; - } else { - return DEFAULT_WIDTH; - } - } - - private static int blockHeight(Orientation orientation) { - if (Orientation.EAST == orientation || Orientation.WEST == orientation) { - return DEFAULT_HEIGHT; - } else { - return BLOCK_HEIGHT; - } - } - public Block(TileBean tileBean) { - super(tileBean, blockWidth(tileBean.getOrientation()), blockHeight(tileBean.getOrientation())); + super(tileBean, LayoutUtil.blockWidth(tileBean.getOrientation()), LayoutUtil.blockHeight(tileBean.getOrientation())); setModel(new DefaultTileModel()); changeRenderSize(); } @@ -80,7 +67,7 @@ public Block(Orientation orientation, Point center) { } public Block(Orientation orientation, int x, int y) { - this(orientation, x, y, blockWidth(orientation), blockHeight(orientation)); + this(orientation, x, y, LayoutUtil.blockWidth(orientation), LayoutUtil.blockHeight(orientation)); } public Block(Orientation orientation, int x, int y, int width, int height) { @@ -99,43 +86,6 @@ private void changeRenderSize() { } } -// Block(TileBean tileBean) { -// super(tileBean); -// if (Orientation.EAST.equals(getOrientation()) || Orientation.WEST.equals(getOrientation())) { -// this.width = BLOCK_WIDTH; -// this.renderWidth = RENDER_WIDTH * 3; -// this.height = DEFAULT_HEIGHT; -// this.renderHeight = RENDER_HEIGHT; -// } else { -// this.width = DEFAULT_WIDTH; -// this.renderWidth = RENDER_WIDTH; -// this.height = BLOCK_HEIGHT; -// this.renderHeight = RENDER_HEIGHT * 3; -// } -// this.blockBean = tileBean.getBlockBean(); -// this.tileType = tileBean.getTileType(); -// this.setLayout(null); -// } -// Block(Orientation orientation, Point center) { -// this(orientation, center.x, center.y); -// } -// Block(Orientation orientation, int x, int y) { -// super(orientation, Direction.CENTER, x, y); -// -// if (Orientation.EAST == getOrientation() || Orientation.WEST == getOrientation()) { -// this.width = BLOCK_WIDTH; -// this.renderWidth = RENDER_WIDTH * 3; -// this.height = DEFAULT_HEIGHT; -// this.renderHeight = RENDER_HEIGHT; -// } else { -// this.width = DEFAULT_WIDTH; -// this.renderWidth = RENDER_WIDTH; -// this.height = BLOCK_HEIGHT; -// this.renderHeight = RENDER_HEIGHT * 3; -// } -// this.tileType = TileType.BLOCK; -// this.setLayout(null); -// } @Override public Set getAltPoints() { int xx = this.tileX; @@ -339,16 +289,10 @@ public String getIdSuffix(Tile other) { @Override public Orientation rotate() { rotate(false); - int w = blockWidth(tileOrientation); - int h = blockHeight(tileOrientation); + int w = LayoutUtil.blockWidth(tileOrientation); + int h = LayoutUtil.blockHeight(tileOrientation); Dimension d = new Dimension(w, h); - -// if (Orientation.EAST == tileOrientation || Orientation.WEST == tileOrientation) { -// d = new Dimension(w, h); -// } else { -// d = new Dimension(DEFAULT_WIDTH, DEFAULT_HEIGHT * 3); -// } setPreferredSize(d); setSize(d); changeRenderSize(); @@ -810,41 +754,26 @@ protected void paintComponent(Graphics g) { long started = System.currentTimeMillis(); super.paintComponent(g); - int w = getWidth(); - int h = getHeight(); - //upon firts initializatien the width and height could still be wrong for reasons unknow to me... - //reset widh or height - boolean reset = false; - if (w != blockWidth(tileOrientation)) { - w = blockWidth(tileOrientation); - reset = true; - } - if (h != blockHeight(tileOrientation)) { - h = blockHeight(tileOrientation); - reset = true; - } - - if (reset) { - Logger.trace(id + " Resetting size... "); - Dimension d = new Dimension(w, h); - setPreferredSize(d); - setSize(d); - } - + int multiplier = (model.isScaleImage() ? 1 : 10); int xx, yy; if (tileOrientation == Orientation.EAST || tileOrientation == Orientation.WEST) { - xx = tileX - GRID - GRID * 2; - yy = tileY - GRID; - setBounds(xx, yy, w, h); + xx = tileX - GRID * multiplier - GRID * multiplier * 2; + yy = tileY - GRID * multiplier; + } else { + xx = tileX - GRID * multiplier; + yy = tileY - GRID * multiplier - GRID * multiplier * 2; + } + + if (model.isScaleImage()) { + setBounds(xx, yy, LayoutUtil.blockWidth(tileOrientation), LayoutUtil.blockHeight(tileOrientation)); } else { - xx = tileX - GRID; - yy = tileY - GRID - GRID * 2; - setBounds(xx, yy, w, h); + setBounds(xx, yy, renderWidth, renderHeight); } - Logger.trace(id + ": " + tileOrientation + " W: " + getWidth() + " H: " + getHeight() + " tX: " + tileX + ", tY: " + tileY + " xx: " + xx + " yy: " + yy); + Logger.trace(id + ": " + tileOrientation + " W: " + getWidth() + " H: " + getHeight() + " tX: " + tileX + ", tY: " + tileY + " xx: " + xx + " yy: " + yy + " Scale factor: " + multiplier); Graphics2D g2 = (Graphics2D) g.create(); + //Graphics2D g2 = (Graphics2D) g; drawTile(g2); g2.dispose(); @@ -856,45 +785,39 @@ protected void paintComponent(Graphics g) { @Override protected void drawCenterPoint(Graphics2D g2d, Color color, double size) { - //super.drawCenterPoint(g2d, color, size); - //A block has 2 alternate points //1st square //2nd square holds the centerpoint //3rd square double dX1, dX2, dX3, dY1, dY2, dY3; - if (Orientation.EAST == this.tileOrientation || Orientation.WEST == tileOrientation) { - dX1 = (renderWidth / 3 / 2 - size / 2 / 2); - dX2 = (renderWidth / 2 - size / 2); - dX3 = (renderWidth / 3 / 2 + renderWidth / 3 * 2 - size / 2); - dY1 = (renderHeight / 2 - size / 2 / 2); - dY2 = (renderHeight / 2 - size / 2 / 2); - dY3 = (renderHeight / 2 - size / 2 / 2); + if (Orientation.EAST == tileOrientation || Orientation.WEST == tileOrientation) { + dX1 = renderWidth / 3 / 2 - size / 2 / 2; + dY1 = renderHeight / 2 - size / 2 / 2; + dX2 = renderWidth / 2 - size / 2; + dY2 = renderHeight / 2 - size / 2; + dX3 = renderWidth - renderWidth / 3 / 2 - size / 2 / 2; + dY3 = renderHeight / 2 - size / 2 / 2; } else { - dY1 = (renderWidth / 2 - size / 2 / 2); - - dY2 = (renderWidth / 2 - size / 2 / 2); - - dY3 = (renderWidth / 2 - size / 2 / 2); - - dX1 = (renderHeight / 3 / 2 - size / 2 / 2); - - dX2 = (renderHeight / 2 - size / 2); - - dX3 = (renderHeight / 3 / 2 + renderHeight / 3 * 2 - size / 2); - + dX1 = renderWidth / 2 - size / 2 / 2; + dY1 = renderHeight / 3 / 2 - size / 2 / 2; + dX2 = renderHeight / 2 - size / 2; + dY2 = renderWidth / 2 - size / 2; + dY3 = renderWidth / 2 - size / 2 / 2; + dX3 = renderHeight - renderHeight / 3 / 2 - size / 2 / 2; } g2d.setColor(color); - g2d.fill(new Ellipse2D.Double(dX1, dY1, size / 2, size / 2)); g2d.fill(new Ellipse2D.Double(dX2, dY2, size, size)); g2d.fill(new Ellipse2D.Double(dX3, dY3, size / 2, size / 2)); - Logger.trace(id + " dX2: " + dX2 + " dY2: " + dY2 + " O: " + tileOrientation + " rW: " + renderWidth + " rH:" + renderHeight); +// g2d.setPaint(Color.black); +// g2d.setStroke(new BasicStroke(2, BasicStroke.CAP_SQUARE, BasicStroke.JOIN_ROUND)); +// g2d.drawOval(renderWidth / 2 - 5, renderHeight / 2 - 5, 10, 10); + + Logger.trace(id + " dX2: " + dX2 + " dY2: " + dY2 + " O: " + tileOrientation + " rW: " + renderWidth + " rH:" + renderHeight + " Size: " + size); Logger.trace(id + " dX1: " + dX1 + " dY1: " + dY1); Logger.trace(id + " dX3: " + dX3 + " dY3: " + dY3); - } } diff --git a/src/main/java/jcs/ui/layout/tiles/Cross.java b/src/main/java/jcs/ui/layout/tiles/Cross.java index d5153674..170114d6 100644 --- a/src/main/java/jcs/ui/layout/tiles/Cross.java +++ b/src/main/java/jcs/ui/layout/tiles/Cross.java @@ -242,11 +242,11 @@ public Map getEdgePoints() { return edgeConnections; } - @Override - public void rotate() { - super.rotate(); - setWidthHeightAndOffsets(); - } +// @Override +// public void rotate() { +// super.rotate(); +// setWidthHeightAndOffsets(); +// } final void setWidthHeightAndOffsets() { //Reset offsets diff --git a/src/main/java/jcs/ui/layout/tiles/DefaultTileModel.java b/src/main/java/jcs/ui/layout/tiles/DefaultTileModel.java index 3a60e1a4..c766c6d2 100644 --- a/src/main/java/jcs/ui/layout/tiles/DefaultTileModel.java +++ b/src/main/java/jcs/ui/layout/tiles/DefaultTileModel.java @@ -22,6 +22,7 @@ import javax.swing.event.ChangeListener; import javax.swing.event.EventListenerList; import jcs.entities.BlockBean.BlockState; +import jcs.entities.LocomotiveBean; /** * @@ -49,6 +50,10 @@ public class DefaultTileModel implements TileModel { protected boolean showOutline = false; protected BlockState blockState; + protected boolean reverseArrival; + protected String arrivalSuffix; + protected LocomotiveBean.Direction logicalDirection; + protected LocomotiveBean locomotive; public DefaultTileModel() { @@ -167,6 +172,81 @@ public void setBlockState(BlockState blockState) { fireStateChanged(); } + @Override + public String getArrivalSuffix() { + return arrivalSuffix; + } + + @Override + public void setArrivalSuffix(String arrivalSuffix) { + this.arrivalSuffix = arrivalSuffix; + fireStateChanged(); + } + + @Override + public void setDepartureSuffix(String suffix) { + if (null == suffix) { + setArrivalSuffix(null); + } else { + switch (suffix) { + case "-" -> + setArrivalSuffix("+"); + default -> + setArrivalSuffix("-"); + } + } + } + + @Override + public String getDepartureSuffix() { + String departureSuffix = null; + if (arrivalSuffix != null) { + if ("-".equals(arrivalSuffix)) { + departureSuffix = "+"; + } else { + departureSuffix = "-"; + } + } + + return departureSuffix; + } + + @Override + public boolean isReverseArrival() { + return reverseArrival; + } + + @Override + public void setReverseArrival(boolean reverseArrival) { + this.reverseArrival = reverseArrival; + fireStateChanged(); + } + + @Override + public LocomotiveBean.Direction getLogicalDirection() { + return logicalDirection; + } + + @Override + public void setLogicalDirection(LocomotiveBean.Direction logicalDirection) { + this.logicalDirection = logicalDirection; + fireStateChanged(); + } + + @Override + public LocomotiveBean getLocomotive() { + return locomotive; + } + + @Override + public void setLocomotive(LocomotiveBean locomotive) { + this.locomotive = locomotive; + fireStateChanged(); + } + + + + @Override public void addChangeListener(ChangeListener l) { listenerList.add(ChangeListener.class, l); diff --git a/src/main/java/jcs/ui/layout/tiles/Tile.java b/src/main/java/jcs/ui/layout/tiles/Tile.java index b1794914..dd068616 100755 --- a/src/main/java/jcs/ui/layout/tiles/Tile.java +++ b/src/main/java/jcs/ui/layout/tiles/Tile.java @@ -45,6 +45,7 @@ import jcs.entities.AccessoryBean.SignalType; import jcs.entities.BlockBean; import jcs.entities.BlockBean.BlockState; +import jcs.entities.LocomotiveBean; import jcs.entities.SensorBean; import jcs.entities.TileBean; import jcs.entities.TileBean.Direction; @@ -80,16 +81,16 @@ public abstract class Tile extends JComponent implements TileEventListener { //, public static final int GRID = 20; public static final int DEFAULT_WIDTH = GRID * 2; public static final int DEFAULT_HEIGHT = GRID * 2; - + static final int RENDER_GRID = GRID * 10; static final int RENDER_WIDTH = RENDER_GRID * 2; static final int RENDER_HEIGHT = RENDER_GRID * 2; - + public static final Color DEFAULT_BACKGROUND_COLOR = Color.white; public static final Color DEFAULT_TRACK_COLOR = Color.lightGray; public static final Color DEFAULT_ROUTE_TRACK_COLOR = Color.blue; public static final Color DEFAULT_SELECTED_COLOR = Color.yellow; - + public static final String MODEL_CHANGED_PROPERTY = "model"; public static final String CONTENT_AREA_FILLED_CHANGED_PROPERTY = "contentAreaFilled"; @@ -97,123 +98,123 @@ public abstract class Tile extends JComponent implements TileEventListener { //, * The data model that determines the button's state. */ protected TileModel model = null; - + protected String id; protected Integer tileX; protected Integer tileY; - + protected int renderWidth; protected int renderHeight; - + protected Orientation tileOrientation; protected Direction tileDirection; - + protected TileType tileType; protected String accessoryId; protected String sensorId; - + protected AccessoryValue accessoryValue; protected AccessoryValue routeValue; - + protected SignalType signalType; protected AccessoryBean.SignalValue signalValue; - + protected AccessoryBean accessoryBean; protected SensorBean sensorBean; protected BlockBean blockBean; - + protected List neighbours; - + protected int offsetX = 0; protected int offsetY = 0; - + protected int renderOffsetX = 0; protected int renderOffsetY = 0; - + protected Color selectedColor; protected Color trackColor; protected Color trackRouteColor; protected Orientation incomingSide; - + protected Color backgroundColor; protected boolean drawName = true; - + protected BufferedImage tileImage; - + protected PropertyChangeListener propertyChangeListener; - + protected ChangeListener changeListener = null; protected ActionListener actionListener = null; //protected ItemListener itemListener = null; protected transient ChangeEvent changeEvent; - + private Handler handler; - protected Tile(TileType tileType, Point center) { - this(tileType, Orientation.EAST, Direction.CENTER, center.x, center.y, DEFAULT_WIDTH, DEFAULT_HEIGHT); - } - + //protected Tile(TileType tileType, Point center) { + // this(tileType, Orientation.EAST, Direction.CENTER, center.x, center.y, DEFAULT_WIDTH, DEFAULT_HEIGHT); + //} protected Tile(TileType tileType, Orientation orientation, Point center, int width, int height) { this(tileType, orientation, Direction.CENTER, center.x, center.y, width, height); } - + protected Tile(TileType tileType, Orientation orientation, int x, int y, int width, int height) { this(tileType, orientation, Direction.CENTER, x, y, width, height); } - + protected Tile(TileType tileType, Orientation orientation, Direction direction, int x, int y, int width, int height) { this(tileType, orientation, direction, x, y, width, height, null, null); } - + protected Tile(TileType tileType, Orientation orientation, Direction direction, int x, int y, int width, int height, Color backgroundColor, Color selectedColor) { this.tileType = tileType; this.tileOrientation = orientation; this.tileDirection = direction; this.tileX = x; this.tileY = y; - + + setLayout(null); Dimension d = new Dimension(width, height); - super.setPreferredSize(d); - super.setSize(d); - + setSize(d); + setPreferredSize(d); + int w = getWidth(); int h = getHeight(); - + this.renderWidth = RENDER_WIDTH; this.renderHeight = RENDER_HEIGHT; - + this.trackColor = DEFAULT_TRACK_COLOR; this.backgroundColor = backgroundColor; this.selectedColor = selectedColor; - + if (this.backgroundColor == null) { this.backgroundColor = DEFAULT_BACKGROUND_COLOR; } if (this.selectedColor == null) { this.selectedColor = DEFAULT_SELECTED_COLOR; } - this.setLayout(null); + } - + protected Tile(Object tileBean) { this(tileBean, DEFAULT_WIDTH, DEFAULT_HEIGHT); } - + protected Tile(Object tileBean, int width, int height) { copyInto(tileBean); setLayout(null); Dimension d = new Dimension(width, height); - this.setSize(d); - this.setPreferredSize(d); - + setSize(d); + setPreferredSize(d); + this.trackColor = DEFAULT_TRACK_COLOR; this.backgroundColor = DEFAULT_BACKGROUND_COLOR; this.selectedColor = DEFAULT_SELECTED_COLOR; this.renderWidth = RENDER_WIDTH; this.renderHeight = RENDER_HEIGHT; } - + private void copyInto(Object object) { if (object instanceof TileBean other) { this.id = other.getId(); @@ -224,28 +225,28 @@ private void copyInto(Object object) { this.tileDirection = other.getDirection(); this.tileX = other.getX(); this.tileY = other.getY(); - + this.signalType = other.getSignalType(); this.accessoryId = other.getAccessoryId(); this.sensorId = other.getSensorId(); this.accessoryBean = other.getAccessoryBean(); this.sensorBean = other.getSensorBean(); this.blockBean = other.getBlockBean(); - + if (other.getAccessoryBean() != null) { AccessoryBean ab = other.getAccessoryBean(); this.signalType = SignalType.getSignalType(ab.getType()); } - + } - + if (object instanceof Tile tile) { this.renderWidth = tile.renderWidth; this.renderHeight = tile.renderHeight; } - + } - + public TileBean getTileBean() { TileBean tb = new TileBean(); tb.setId(this.id); @@ -260,116 +261,162 @@ public TileBean getTileBean() { tb.setAccessoryBean(this.accessoryBean); tb.setSensorBean(this.sensorBean); tb.setBlockBean(this.blockBean); - + return tb; } - + public boolean isSelected() { return model.isSelected(); } - + public void setSelected(boolean b) { //boolean oldValue = isSelected(); model.setSelected(b); } - + @Override public String getId() { return id; } - + public void setId(String id) { this.id = id; } - + public SignalType getSignalType() { - return this.signalType; + return signalType; } - + public void setSignalType(SignalType signalType) { this.signalType = signalType; } - + public Integer getTileX() { return tileX; } - public void setTileX(Integer x) { - this.tileX = x; - } - +// public void setTileX(Integer x) { +// this.tileX = x; +// } public Integer getTileY() { return tileY; } - public void setTileY(Integer y) { - this.tileY = y; - } - +// public void setTileY(Integer y) { +// this.tileY = y; +// } public Point getCenter() { return new Point(this.tileX, this.tileY); } - + public void setCenter(Point center) { - this.tileX = center.x; - this.tileY = center.y; + tileX = center.x; + tileY = center.y; } - + public Orientation getOrientation() { return tileOrientation; } - + public void setOrientation(Orientation orientation) { this.tileOrientation = orientation; } - + public Direction getDirection() { return tileDirection; } - + public void setDirection(Direction direction) { this.tileDirection = direction; } - + public String getAccessoryId() { return accessoryId; } - + public void setAccessoryId(String accessoryId) { this.accessoryId = accessoryId; } - + public String getSensorId() { return sensorId; } - + public void setSensorId(String sensorId) { this.sensorId = sensorId; } - + public boolean isActive() { return model.isSensorActive(); } - + public void setActive(boolean active) { - this.model.setSensorActive(active); + model.setSensorActive(active); } - + public BlockState getBlockState() { - return this.model.getBlockState(); + return model.getBlockState(); } - + public void setBlockState(BlockState blockState) { - this.model.setBlockState(blockState); + if (blockBean != null) { + blockBean.setBlockState(blockState); + } + model.setBlockState(blockState); } - + + public String getDepartureSuffix() { + return model.getDepartureSuffix(); + } + + public void setDepartureSuffix(String suffix) { + if (blockBean != null) { + blockBean.setDepartureSuffix(suffix); + } + model.setDepartureSuffix(suffix); + } + + public boolean isReverseArrival() { + return model.isReverseArrival(); + } + + public void setReverseArrival(boolean reverseArrival) { + if (blockBean != null) { + blockBean.setReverseArrival(reverseArrival); + } + model.setReverseArrival(reverseArrival); + } + + public LocomotiveBean.Direction getLogicalDirection() { + return model.getLogicalDirection(); + } + + public void setLogicalDirection(LocomotiveBean.Direction logicalDirection) { + if (blockBean != null) { + blockBean.setLogicalDirection(logicalDirection.getDirection()); + } + model.setLogicalDirection(logicalDirection); + } + + public LocomotiveBean getLocomotive() { + return model.getLocomotive(); + } + + public void setLocomotive(LocomotiveBean locomotive) { + if (blockBean != null) { + blockBean.setLocomotive(locomotive); + } + + this.model.setLocomotive(locomotive); + } + public AccessoryBean getAccessoryBean() { return accessoryBean; } - + public void setAccessoryBean(AccessoryBean accessoryBean) { this.accessoryBean = accessoryBean; - + if (accessoryBean != null) { this.accessoryId = accessoryBean.getId(); this.signalValue = accessoryBean.getSignalValue(); @@ -380,7 +427,7 @@ public void setAccessoryBean(AccessoryBean accessoryBean) { this.signalValue = AccessoryBean.SignalValue.OFF; } } - + public AccessoryValue getAccessoryValue() { if (this.accessoryValue == null) { return AccessoryValue.OFF; @@ -388,12 +435,12 @@ public AccessoryValue getAccessoryValue() { return accessoryValue; } } - + public void setAccessoryValue(AccessoryValue value) { this.accessoryValue = value; repaint(); } - + public AccessoryValue getRouteValue() { if (routeValue == null) { return AccessoryValue.OFF; @@ -401,127 +448,127 @@ public AccessoryValue getRouteValue() { return routeValue; } } - + public void setRouteValue(AccessoryValue value) { this.routeValue = value; repaint(); } - + public AccessoryBean.SignalValue getSignalValue() { return signalValue; } - + public void setSignalValue(AccessoryBean.SignalValue signalValue) { this.signalValue = signalValue; this.repaint(); } - + public SensorBean getSensorBean() { return sensorBean; } - + public void setSensorBean(SensorBean sensorBean) { this.sensorBean = sensorBean; } - + public BlockBean getBlockBean() { return blockBean; } - + public void setBlockBean(BlockBean blockBean) { this.blockBean = blockBean; } - + public void setRenderWidth(int renderWidth) { this.renderWidth = renderWidth; } - + public void setRenderHeight(int renderHeight) { this.renderHeight = renderHeight; } - + public int getRenderOffsetX() { return renderOffsetX; } - + public void setRenderOffsetX(int renderOffsetX) { this.renderOffsetX = renderOffsetX; } - + public int getRenderOffsetY() { return renderOffsetY; } - + public void setRenderOffsetY(int renderOffsetY) { this.renderOffsetY = renderOffsetY; } - + public TileBean.TileType getTileType() { return this.tileType; } - + public final void setTileType(TileType tileType) { this.tileType = tileType; } - + public Color getTrackColor() { return trackColor; } - + public final void setTrackColor(Color trackColor) { this.trackColor = trackColor; } - + public Color getTrackRouteColor() { return trackRouteColor; } - + public void setTrackRouteColor(Color trackRouteColor) { this.trackRouteColor = trackRouteColor; } - + public Color getSelectedColor() { return selectedColor; } - + public void setSelectedColor(Color selectedColor) { this.selectedColor = selectedColor; } - + public Orientation getIncomingSide() { return incomingSide; } - + public void setIncomingSide(Orientation incomingSide) { this.incomingSide = incomingSide; } - + public Color getBackgroundColor() { return backgroundColor; } - + public void setBackgroundColor(Color backgroundColor) { this.backgroundColor = backgroundColor; } - + public boolean isDrawRoute() { - return this.model.isShowRoute(); + return model.isShowRoute(); } - + public void setDrawRoute(boolean drawRoute) { this.model.setShowRoute(drawRoute); } - + public int getRenderWidth() { return renderWidth; } - + public int getRenderHeight() { return renderHeight; } - + abstract void renderTile(Graphics2D g2d); - + abstract void renderTileRoute(Graphics2D g2d); /** @@ -535,7 +582,7 @@ public void drawTile(Graphics2D g2d) { if (tileOrientation == null) { tileOrientation = Orientation.EAST; } - + tileImage = createImage(); Graphics2D g2di = tileImage.createGraphics(); @@ -543,16 +590,16 @@ public void drawTile(Graphics2D g2d) { if (model.isShowRoute() && incomingSide == null) { incomingSide = getOrientation(); } - + if (model.isSelected()) { g2di.setBackground(selectedColor); } else { g2di.setBackground(backgroundColor); } - + g2di.clearRect(0, 0, renderWidth, renderHeight); int ox = 0, oy = 0; - + AffineTransform trans = new AffineTransform(); switch (tileOrientation) { case SOUTH -> { @@ -572,19 +619,22 @@ public void drawTile(Graphics2D g2d) { trans.translate(-ox, -oy); } default -> { - //trans.rotate(0.0, this.renderWidth / 2, this.renderHeight / 2); - //trans.translate(ox, oy); + trans.rotate(0.0, this.renderWidth / 2, this.renderHeight / 2); + trans.translate(ox, oy); } } - + + Logger.trace(tileOrientation.getOrientation() + " renderWidth: " + renderWidth + " renderHeight: " + renderHeight + " CP: (" + renderWidth / 2 + "," + renderHeight / 2 + ")"); + Logger.trace(tileOrientation.getOrientation() + " ox: " + ox + " oy: " + oy); + g2di.setTransform(trans); - + renderTile(g2di); - + if (model.isShowRoute()) { renderTileRoute(g2di); } - + if (model.isShowCenter()) { drawCenterPoint(g2di); } @@ -593,7 +643,7 @@ public void drawTile(Graphics2D g2d) { if (model.isScaleImage()) { tileImage = Scalr.resize(tileImage, Method.AUTOMATIC, Mode.FIT_EXACT, getWidth(), getHeight(), Scalr.OP_ANTIALIAS); } - + g2di.dispose(); // int oxx, oyy; @@ -606,7 +656,7 @@ public void drawTile(Graphics2D g2d) { // } //g2d.drawImage(tileImage, (tileX - tileImage.getWidth() / 2) + oxx, (tileY - tileImage.getHeight() / 2) + oyy, null); } - + public BufferedImage getTileImage() { return tileImage; } @@ -618,19 +668,19 @@ public BufferedImage getTileImage() { */ public void drawName(Graphics2D g2) { } - + protected void drawCenterPoint(Graphics2D g2d) { drawCenterPoint(g2d, Color.magenta); } - + protected void drawCenterPoint(Graphics2D g2, Color color) { drawCenterPoint(g2, color, 60); } - + protected void drawCenterPoint(Graphics2D g2d, Color color, double size) { double dX = (renderWidth / 2 - size / 2); double dY = (renderHeight / 2 - size / 2); - + g2d.setColor(color); g2d.fill(new Ellipse2D.Double(dX, dY, size, size)); } @@ -648,7 +698,7 @@ public Orientation rotate() { * Rotate the tile clockwise 90 deg * * @param repaint - * @return + * @return */ protected Orientation rotate(boolean repaint) { switch (tileOrientation) { @@ -666,27 +716,27 @@ protected Orientation rotate(boolean repaint) { } return tileOrientation; } - + public void flipHorizontal() { if (Orientation.NORTH.equals(getOrientation()) || Orientation.SOUTH.equals(getOrientation())) { rotate(false); rotate(true); } } - + public void flipVertical() { if (Orientation.EAST.equals(getOrientation()) || Orientation.WEST.equals(getOrientation())) { rotate(false); rotate(true); } } - + @Override public void move(int newX, int newY) { Point cs = LayoutUtil.snapToGrid(newX, newY); setCenter(cs); } - + protected static void drawRotate(Graphics2D g2d, double x, double y, int angle, String text) { g2d.translate((float) x, (float) y); g2d.rotate(Math.toRadians(angle)); @@ -694,83 +744,83 @@ protected static void drawRotate(Graphics2D g2d, double x, double y, int angle, g2d.rotate(-Math.toRadians(angle)); g2d.translate(-x, -y); } - + public static BufferedImage flipHorizontally(BufferedImage source) { BufferedImage output = new BufferedImage(source.getHeight(), source.getWidth(), source.getType()); - + AffineTransform flip = AffineTransform.getScaleInstance(1, -1); flip.translate(0, -source.getHeight()); AffineTransformOp op = new AffineTransformOp(flip, AffineTransformOp.TYPE_NEAREST_NEIGHBOR); - + op.filter(source, output); - + return output; } - + public static BufferedImage flipVertically(BufferedImage source) { BufferedImage output = new BufferedImage(source.getHeight(), source.getWidth(), source.getType()); - + AffineTransform flip = AffineTransform.getScaleInstance(-1, 1); flip.translate(-source.getWidth(), 0); AffineTransformOp op = new AffineTransformOp(flip, AffineTransformOp.TYPE_NEAREST_NEIGHBOR); - + op.filter(source, output); - + return output; } - + public Set getAltPoints() { return Collections.EMPTY_SET; } - + public final int getOffsetX() { return offsetX; } - + public void setOffsetX(int offsetX) { this.offsetX = offsetX; } - + public final int getOffsetY() { return offsetY; } - + public void setOffsetY(int offsetY) { this.offsetY = offsetY; } - + protected BufferedImage createImage() { return new BufferedImage(renderWidth, renderHeight, BufferedImage.TYPE_INT_RGB); } - + public int getCenterX() { - if (this.tileX > 0) { + if (tileX > 0) { return this.tileX; } else { return GRID; } } - + public int getCenterY() { - if (this.tileY > 0) { + if (tileY > 0) { return this.tileY; } else { return GRID; } } - + public boolean isDrawName() { return drawName; } - + public void setDrawName(boolean drawName) { this.drawName = drawName; } - + public boolean isScaleImage() { return model.isScaleImage(); } - + public void setScaleImage(boolean scaleImage) { Dimension d; if (scaleImage) { @@ -778,21 +828,21 @@ public void setScaleImage(boolean scaleImage) { } else { d = new Dimension(renderWidth, renderHeight); } - + setSize(d); setPreferredSize(d); - + model.setScaleImage(scaleImage); } - + public boolean isDrawCenterPoint() { return model.isShowCenter(); } - + public void setDrawCenterPoint(boolean drawCenterPoint) { model.setShowCenter(drawCenterPoint); } - + @Override public String toString() { return this.getClass().getSimpleName() @@ -806,7 +856,7 @@ public String toString() { + xyToString() + "}"; } - + @Override public Rectangle getBounds() { int w, h, cx, cy; @@ -821,7 +871,7 @@ public Rectangle getBounds() { w = DEFAULT_WIDTH; h = DEFAULT_HEIGHT; } - + if (this.tileX > 0 && this.tileY > 0) { cx = this.tileX + this.offsetX; cy = this.tileY + this.offsetY; @@ -829,16 +879,16 @@ public Rectangle getBounds() { cx = w / 2; cy = h / 2; } - + int ltx = cx - w / 2; int lty = cy - h / 2; return new Rectangle(ltx, lty, w, h); } - + public Rectangle2D getBounds2D() { return getBounds().getBounds2D(); } - + public boolean contains(double x, double y) { int w, h, cx, cy, tlx, tly; if (this.getWidth() > 0 & this.getHeight() > 0) { @@ -847,12 +897,12 @@ public boolean contains(double x, double y) { // h = this.height; w = this.getPreferredSize().width; h = this.getPreferredSize().height; - + } else { w = DEFAULT_WIDTH; h = DEFAULT_HEIGHT; } - + if (this.getWidth() > 0 & this.getHeight() > 0) { //if (this.width > 0 & this.height > 0) { cx = this.tileX; @@ -869,56 +919,56 @@ public boolean contains(double x, double y) { // Check if X and Y range is ok return !(x < tlx || x > (tlx + w) || y < tly || y > (tly + h)); } - + public String xyToString() { return "(" + this.tileX + "," + this.tileY + ")"; } - + public boolean contains(Point2D p) { return this.contains(p.getX(), p.getY()); } - + public boolean intersects(double x, double y, double w, double h) { return getBounds().intersects(x, y, w, h); } - + public boolean intersects(Rectangle2D r2d) { return getBounds().intersects(r2d); } - + public boolean contains(double x, double y, double w, double h) { return getBounds().contains(x, y, w, h); } - + public boolean contains(Rectangle2D r2d) { return getBounds().contains(r2d); } - + public PathIterator getPathIterator(AffineTransform at) { return getBounds().getPathIterator(at); } - + public PathIterator getPathIterator(AffineTransform at, double flatness) { return getBounds().getPathIterator(at, flatness); } - + @Deprecated public PropertyChangeListener getPropertyChangeListener() { return this.propertyChangeListener; } - + @Deprecated public void setPropertyChangeListener(PropertyChangeListener propertyChangeListener) { this.propertyChangeListener = propertyChangeListener; } - + @Deprecated public void repaintTile() { // if (this.propertyChangeListener != null) { // this.propertyChangeListener.propertyChange(new PropertyChangeEvent(this, "repaintTile", this, this)); // } } - + @Override @Deprecated public void onTileChange(TileEvent tileEvent) { @@ -926,27 +976,27 @@ public void onTileChange(TileEvent tileEvent) { if (tileEvent.isEventFor(this)) { boolean drawRoute = tileEvent.isShowRoute(); setIncomingSide(tileEvent.getIncomingSide()); - + if (isJunction()) { // setRouteValue(tileEvent.getRouteState()); } - + if (tileEvent.getBlockBean() != null) { this.setBlockBean(tileEvent.getBlockBean()); } - + if (tileEvent.getTileBean() != null) { TileBean other = tileEvent.getTileBean(); this.copyInto(other); } - + if (isBlock()) { // ((Block) this).setRouteBlockState(tileEvent.getBlockState()); if (!drawRoute) { // ((Block) this).setRouteBlockState(null); } } - + setBackgroundColor(tileEvent.getBackgroundColor()); setTrackColor(tileEvent.getTrackColor()); setTrackRouteColor(tileEvent.getTrackRouteColor()); @@ -958,21 +1008,13 @@ public void onTileChange(TileEvent tileEvent) { } } - public int getGridX() { - return (getCenterX() - Tile.GRID) / (Tile.GRID * 2); - } - - public int getGridY() { - return (getCenterY() - Tile.GRID) / (Tile.GRID * 2); - } - /** * The main route of the tile is horizontal * * @return true when main route goes from East to West or vv */ public boolean isHorizontal() { - return (Orientation.EAST == getOrientation() || Orientation.WEST == getOrientation()) && TileType.CURVED != getTileType(); + return (Orientation.EAST == tileOrientation || Orientation.WEST == tileOrientation) && TileType.CURVED != tileType; } /** @@ -981,19 +1023,19 @@ public boolean isHorizontal() { * @return true when main route goes from North to South or vv */ public boolean isVertical() { - return (Orientation.NORTH == getOrientation() || Orientation.SOUTH == getOrientation()) && TileType.CURVED != getTileType(); + return (Orientation.NORTH == tileOrientation || Orientation.SOUTH == tileOrientation) && TileType.CURVED != tileType; } - + public boolean isJunction() { - return false; + return TileType.SWITCH == tileType || TileType.CROSS == tileType; } - + public boolean isBlock() { - return false; + return TileType.BLOCK == tileType; } - + public boolean isDirectional() { - return false; + return TileType.STRAIGHT_DIR == tileType; } /** @@ -1002,54 +1044,54 @@ public boolean isDirectional() { * @return true when main route goes from North to East or West to South and vv */ public boolean isDiagonal() { - return TileType.CURVED == getTileType(); + return TileType.CURVED == tileType; } - + public boolean isCrossing() { - return TileType.CROSSING == getTileType(); + return TileType.CROSSING == tileType; } - + public List getNeighbours() { - return this.neighbours; + return neighbours; } - + public void setNeighbours(List neighbours) { this.neighbours = neighbours; } - + public String getIdSuffix(Tile other) { return ""; } - + public Map getNeighborOrientations() { Map edgeOrientations = new HashMap<>(); - + Map neighborPoints = getNeighborPoints(); - + for (Orientation o : Orientation.values()) { edgeOrientations.put(neighborPoints.get(o), o); } return edgeOrientations; } - + public Map getEdgeOrientations() { Map edgeOrientations = new HashMap<>(); - + Map edgeConnections = getEdgePoints(); - + for (Orientation o : Orientation.values()) { edgeOrientations.put(edgeConnections.get(o), o); } return edgeOrientations; } - + public boolean isAdjacent(Tile other) { boolean adjacent = false; - + if (other != null) { Collection thisEdgePoints = getEdgePoints().values(); Collection otherEdgePoints = other.getEdgePoints().values(); - + for (Point p : thisEdgePoints) { adjacent = otherEdgePoints.contains(p); if (adjacent) { @@ -1057,7 +1099,7 @@ public boolean isAdjacent(Tile other) { } } } - + return adjacent; } @@ -1071,11 +1113,11 @@ public boolean isAdjacent(Tile other) { public boolean isArrowDirection(Tile other) { return true; } - + public AccessoryValue accessoryValueForRoute(Orientation from, Orientation to) { return AccessoryValue.OFF; } - + @Deprecated protected StringBuilder getImageKeyBuilder() { StringBuilder sb = new StringBuilder(); @@ -1135,37 +1177,37 @@ protected StringBuilder getImageKeyBuilder() { //Logger.trace(sb); return sb; } - + public abstract Map getNeighborPoints(); - + public abstract Map getEdgePoints(); - + public abstract Set getAllPoints(); - + public TileModel getModel() { return model; } - + public void setModel(TileModel newModel) { TileModel oldModel = getModel(); - + if (oldModel != null) { oldModel.removeChangeListener(changeListener); oldModel.removeActionListener(actionListener); changeListener = null; actionListener = null; } - + model = newModel; - + if (newModel != null) { changeListener = createChangeListener(); actionListener = createActionListener(); - + newModel.addChangeListener(changeListener); newModel.addActionListener(actionListener); } - + firePropertyChange(MODEL_CHANGED_PROPERTY, oldModel, newModel); if (newModel != oldModel) { revalidate(); @@ -1182,38 +1224,38 @@ public void setModel(TileModel newModel) { @Override public void updateUI() { } - + protected ChangeListener createChangeListener() { return getHandler(); } - + protected ActionListener createActionListener() { return getHandler(); } - + private Handler getHandler() { if (handler == null) { handler = new Handler(); } return handler; } - + class Handler implements ActionListener, ChangeListener, Serializable { - + @Override public void stateChanged(ChangeEvent e) { Object source = e.getSource(); - + fireStateChanged(); repaint(); } - + @Override public void actionPerformed(ActionEvent event) { fireActionPerformed(event); } } - + protected void fireStateChanged() { Object[] listeners = listenerList.getListenerList(); //reverse order @@ -1227,7 +1269,7 @@ protected void fireStateChanged() { } } } - + protected void fireActionPerformed(ActionEvent event) { Object[] listeners = listenerList.getListenerList(); ActionEvent e = null; @@ -1246,5 +1288,5 @@ protected void fireActionPerformed(ActionEvent event) { } } } - + } diff --git a/src/main/java/jcs/ui/layout/tiles/TileModel.java b/src/main/java/jcs/ui/layout/tiles/TileModel.java index b9f59c2a..3d472126 100644 --- a/src/main/java/jcs/ui/layout/tiles/TileModel.java +++ b/src/main/java/jcs/ui/layout/tiles/TileModel.java @@ -19,6 +19,7 @@ import java.io.Serializable; import javax.swing.event.ChangeListener; import jcs.entities.BlockBean; +import jcs.entities.LocomotiveBean; /** * @@ -66,12 +67,27 @@ public interface TileModel extends Serializable { public void setBlockState(BlockBean.BlockState blockState); - //boolean isShowOutline(); - //public void setShowOutline(boolean showOutline); - //@Override - //void addItemListener(ItemListener l); - //@Override - //void removeItemListener(ItemListener l); + String getArrivalSuffix(); + + public void setArrivalSuffix(String arrivalSuffix); + + String getDepartureSuffix(); + + public void setDepartureSuffix(String suffix); + + boolean isReverseArrival(); + + public void setReverseArrival(boolean reverseArrival); + + LocomotiveBean.Direction getLogicalDirection(); + + public void setLogicalDirection(LocomotiveBean.Direction logicalDirection); + + LocomotiveBean getLocomotive(); + + public void setLocomotive(LocomotiveBean locomotive); + + // void addChangeListener(ChangeListener l); void removeChangeListener(ChangeListener l); diff --git a/src/test/java/jcs/ui/layout/TileTest.java b/src/test/java/jcs/ui/layout/TileTest.java index 6b634b1c..244a7d39 100644 --- a/src/test/java/jcs/ui/layout/TileTest.java +++ b/src/test/java/jcs/ui/layout/TileTest.java @@ -56,31 +56,33 @@ public void testgetCenterXZero() { assertEquals(expResult, result); } +// public int getGridX() { +// return (getCenterX() - Tile.GRID) / (Tile.GRID * 2); +// } +// public int getGridY() { +// return (getCenterY() - Tile.GRID) / (Tile.GRID * 2); +// } @Test public void testGetGridX() { System.out.println("getGridX"); Tile instance - = TileFactory.createTile( - TileBean.TileType.STRAIGHT, Orientation.EAST, Direction.CENTER, 100, 100, false); + = TileFactory.createTile(TileBean.TileType.STRAIGHT, Orientation.EAST, Direction.CENTER, 100, 100, false); int expResult = 2; - int result = instance.getGridX(); + int result = (instance.getTileX() - Tile.GRID) / (Tile.GRID * 2); + assertEquals(expResult, result); - instance - = TileFactory.createTile( - TileBean.TileType.STRAIGHT, Orientation.EAST, Direction.CENTER, 220, 220, false); + instance = TileFactory.createTile(TileBean.TileType.STRAIGHT, Orientation.EAST, Direction.CENTER, 220, 220, false); expResult = 5; - result = instance.getGridX(); + result = (instance.getTileX() - Tile.GRID) / (Tile.GRID * 2); assertEquals(expResult, result); } @Test public void testgetCenterY() { System.out.println("getCenterY"); - Tile instance - = TileFactory.createTile( - TileBean.TileType.STRAIGHT, Orientation.EAST, Direction.CENTER, 180, 100, false); + Tile instance = TileFactory.createTile(TileBean.TileType.STRAIGHT, Orientation.EAST, Direction.CENTER, 180, 100, false); int expResult = 100; int result = instance.getCenterY(); assertEquals(expResult, result); @@ -89,9 +91,7 @@ public void testgetCenterY() { @Test public void testgetCenterYZero() { System.out.println("getCenterY"); - Tile instance - = TileFactory.createTile( - TileBean.TileType.STRAIGHT, Orientation.EAST, Direction.CENTER, 0, 0, false); + Tile instance = TileFactory.createTile(TileBean.TileType.STRAIGHT, Orientation.EAST, Direction.CENTER, 0, 0, false); int expResult = 20; int result = instance.getCenterY(); assertEquals(expResult, result); @@ -100,11 +100,9 @@ public void testgetCenterYZero() { @Test public void testGetGridY() { System.out.println("getGridY"); - Tile instance - = TileFactory.createTile( - TileBean.TileType.STRAIGHT, Orientation.WEST, Direction.CENTER, 100, 140, false); + Tile instance = TileFactory.createTile(TileBean.TileType.STRAIGHT, Orientation.WEST, Direction.CENTER, 100, 140, false); int expResult = 3; - int result = instance.getGridY(); + int result = (instance.getTileY() - Tile.GRID) / (Tile.GRID * 2); assertEquals(expResult, result); } diff --git a/src/test/java/jcs/ui/layout/tiles/DotGridCanvas.java b/src/test/java/jcs/ui/layout/tiles/DotGridCanvas.java index 3fcbfd65..afb7d614 100644 --- a/src/test/java/jcs/ui/layout/tiles/DotGridCanvas.java +++ b/src/test/java/jcs/ui/layout/tiles/DotGridCanvas.java @@ -22,10 +22,6 @@ import javax.swing.JPanel; import org.tinylog.Logger; -/** - * - * @author fransjacobs - */ public class DotGridCanvas extends JPanel { public DotGridCanvas() { diff --git a/src/test/java/jcs/ui/layout/tiles/UnscaledBlockCanvas.java b/src/test/java/jcs/ui/layout/tiles/UnscaledBlockCanvas.java index 4dce3bf3..308362f5 100644 --- a/src/test/java/jcs/ui/layout/tiles/UnscaledBlockCanvas.java +++ b/src/test/java/jcs/ui/layout/tiles/UnscaledBlockCanvas.java @@ -25,20 +25,24 @@ public class UnscaledBlockCanvas extends JPanel { //implements PropertyChangeListener { private boolean expanded; + private int paintCount = 0; public UnscaledBlockCanvas() { setLayout(null); - setOpaque(false); + setOpaque(true); setDoubleBuffered(true); } @Override public void paint(Graphics g) { long started = System.currentTimeMillis(); + paintCount++; //Rectangle r = g.getClipBounds(); //Logger.trace("Rx: " + r.x + " Ry: " + r.y + " Rw: " + r.width + " Rh: " + r.height); - super.paint(g); + if (paintCount > 2) { + super.paint(g); + } paintGrid(g); long now = System.currentTimeMillis(); @@ -59,7 +63,7 @@ private void paintGrid(Graphics g) { int grid; if (expanded) { - grid = 200; + grid = 20; } else { grid = 20; } @@ -72,8 +76,6 @@ private void paintGrid(Graphics g) { gc.setPaint(p); } - - //private boolean showCenter; //private final List tiles; // public UnscaledBlockCanvas() { @@ -228,12 +230,12 @@ private void paintGrid(Graphics g) { // return this.getSize(); // } // } - public boolean isExpanded() { return expanded; } public void setExpanded(boolean expanded) { this.expanded = expanded; + this.repaint(); } } diff --git a/src/test/java/jcs/ui/layout/tiles/UnscaledBlockTester.form b/src/test/java/jcs/ui/layout/tiles/UnscaledBlockTester.form index 098f9189..9c565600 100644 --- a/src/test/java/jcs/ui/layout/tiles/UnscaledBlockTester.form +++ b/src/test/java/jcs/ui/layout/tiles/UnscaledBlockTester.form @@ -199,6 +199,9 @@ + + + @@ -212,7 +215,7 @@ - + diff --git a/src/test/java/jcs/ui/layout/tiles/UnscaledBlockTester.java b/src/test/java/jcs/ui/layout/tiles/UnscaledBlockTester.java index 10444f86..46d8ce54 100644 --- a/src/test/java/jcs/ui/layout/tiles/UnscaledBlockTester.java +++ b/src/test/java/jcs/ui/layout/tiles/UnscaledBlockTester.java @@ -1,5 +1,5 @@ /* - * Copyright 2024 FJA. + * Copyright 2024 Frans Jacobs. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -15,9 +15,7 @@ */ package jcs.ui.layout.tiles; -import java.awt.Dimension; import java.awt.Image; -import java.awt.Point; import java.awt.image.BufferedImage; import java.io.File; import javax.swing.ComboBoxModel; @@ -30,17 +28,12 @@ import jcs.entities.BlockBean.BlockState; import jcs.entities.LocomotiveBean; import jcs.entities.TileBean.Orientation; -import jcs.ui.layout.LayoutUtil; import jcs.ui.util.ImageUtil; import org.tinylog.Logger; -/** - * - * @author FJA - */ public class UnscaledBlockTester extends JFrame { //implements PropertyChangeListener { - private Tile blockTile; + private final Tile blockTile; /** * Creates new form UnscaledBlockTileFrame @@ -52,11 +45,12 @@ public UnscaledBlockTester() { this.departureSideCB.setSelectedItem(""); this.stateCB.setModel(createStateComboBoxModel()); - this.blockTile = initBlock(); + blockTile = createBlock(); canvas.add(blockTile); - centerSP.getViewport().validate(); + centerSP.getViewport().validate(); + pack(); setVisible(true); } @@ -79,6 +73,7 @@ private ComboBoxModel createStateComboBoxModel() { blockStateModel.addElement(BlockState.LOCKED); blockStateModel.addElement(BlockState.OUT_OF_ORDER); + blockStateModel.setSelectedItem(BlockState.FREE); return blockStateModel; } @@ -100,28 +95,20 @@ private LocomotiveBean createLocomotiveBean() { return lb; } - private Block initBlock() { - Point center = LayoutUtil.snapToGrid(canvas.getWidth() / 2, canvas.getHeight() / 2); - int cX = center.x; - int cY = center.y; - - Logger.trace("Center X: " + cX + " Y: " + cY); + private Block createBlock() { + Block block = new Block(Orientation.EAST, 640, 280); - Block block = new Block(Orientation.EAST, cX, cY); block.setId("bk-1"); + block.setBlockState((BlockState) stateCB.getSelectedItem()); block.setScaleImage(!scaleCB.isSelected()); - canvas.setExpanded(scaleCB.isSelected()); + //canvas.setExpanded(scaleCB.isSelected()); BlockBean blockBean = new BlockBean(); blockBean.setId(block.getId()); blockBean.setTileId(block.getId()); blockBean.setDescription("Blok 1"); - - //bbe.setArrivalSuffix((String) this.incomingSideCB.getSelectedItem()); blockBean.setDepartureSuffix(null); - - blockBean.setBlockState((BlockState) stateCB.getSelectedItem()); - blockBean.setReverseArrival(reverseArrivalCB.isSelected()); + blockBean.setDepartureSuffix((String) this.departureSideCB.getSelectedItem()); if (showLocCB.isSelected()) { blockBean.setLocomotive(createLocomotiveBean()); @@ -130,7 +117,6 @@ private Block initBlock() { } block.setBlockBean(blockBean); - return block; } @@ -272,6 +258,7 @@ public void componentResized(java.awt.event.ComponentEvent evt) { }); canvas.setAutoscrolls(true); + canvas.setPreferredSize(new java.awt.Dimension(1220, 410)); canvas.addComponentListener(new java.awt.event.ComponentAdapter() { public void componentResized(java.awt.event.ComponentEvent evt) { canvasComponentResized(evt); @@ -286,7 +273,7 @@ public void componentResized(java.awt.event.ComponentEvent evt) { ); canvasLayout.setVerticalGroup( canvasLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGap(0, 498, Short.MAX_VALUE) + .addGap(0, 445, Short.MAX_VALUE) ); centerSP.setViewportView(canvas); @@ -297,18 +284,17 @@ public void componentResized(java.awt.event.ComponentEvent evt) { }// //GEN-END:initComponents private void rotateButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_rotateButtonActionPerformed - Orientation orientation = blockTile.rotate(); + Orientation orientation = blockTile.rotate(); this.orientationCB.setSelectedItem(orientation); - Logger.trace("Blok is rotated to " + orientation); + Logger.trace("\nBlok is rotated to " + orientation); }//GEN-LAST:event_rotateButtonActionPerformed private void showLocCBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_showLocCBActionPerformed if (this.showLocCB.isSelected()) { - ((Block) blockTile).getBlockBean().setLocomotive(this.createLocomotiveBean()); + blockTile.setLocomotive(createLocomotiveBean()); } else { - ((Block) blockTile).getBlockBean().setLocomotive(null); + blockTile.setLocomotive(null); } - repaint(); }//GEN-LAST:event_showLocCBActionPerformed private void orientationCBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_orientationCBActionPerformed @@ -316,71 +302,49 @@ private void orientationCBActionPerformed(java.awt.event.ActionEvent evt) {//GEN }//GEN-LAST:event_orientationCBActionPerformed private void departureSideCBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_departureSideCBActionPerformed - if (blockTile != null && ((Block) blockTile).getBlockBean() != null) { - if ("".equals(this.departureSideCB.getSelectedItem())) { - ((Block) blockTile).getBlockBean().setDepartureSuffix(null); - } else { - ((Block) blockTile).getBlockBean().setDepartureSuffix((String) this.departureSideCB.getSelectedItem()); - } - repaint(); + if ("".equals(departureSideCB.getSelectedItem())) { + blockTile.setDepartureSuffix(null); + } else { + blockTile.setDepartureSuffix(departureSideCB.getSelectedItem().toString()); } }//GEN-LAST:event_departureSideCBActionPerformed private void stateCBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_stateCBActionPerformed - ((Block) blockTile).getBlockBean().setBlockState((BlockState) this.stateCB.getSelectedItem()); - repaint(); + blockTile.setBlockState((BlockState) stateCB.getSelectedItem()); }//GEN-LAST:event_stateCBActionPerformed private void showCenterCBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_showCenterCBActionPerformed - //Reset the logical direction - ((Block) blockTile).getBlockBean().setLogicalDirection(null); - repaint(); + blockTile.setDrawCenterPoint(this.showCenterCB.isSelected()); }//GEN-LAST:event_showCenterCBActionPerformed - private String getDepartureSuffix() { - if (((Block) blockTile).getBlockBean() != null && ((Block) blockTile).getBlockBean().getDepartureSuffix() != null && !"".equals(((Block) blockTile).getBlockBean().getDepartureSuffix())) { - return ((Block) blockTile).getBlockBean().getDepartureSuffix(); - } else { - return "+"; - } - } +// private String getDepartureSuffix() { +// return this.blockTile.getDepartureSuffix(); +// } private void reverseArrivalCBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_reverseArrivalCBActionPerformed - ((Block) blockTile).getBlockBean().setReverseArrival(this.reverseArrivalCB.isSelected()); - - //The Suffix is orientation dependent! -// if ("+".equals(((Block) blockTile).getBlockBean().getArrivalSuffix())) { -// ((Block) blockTile).getBlockBean().setArrivalSuffix("-"); -// } else { -// ((Block) blockTile).getBlockBean().setArrivalSuffix("+"); -// } -// this.departureSideCB.setSelectedItem(((Block) blockTile).getBlockBean().getArrivalSuffix()); - repaint(); + blockTile.setReverseArrival(reverseArrivalCB.isSelected()); }//GEN-LAST:event_reverseArrivalCBActionPerformed private void backwardsRBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_backwardsRBActionPerformed - if (((Block) blockTile).getBlockBean().getLocomotive() != null) { - //((Block) blockTile).getBlockBean().getLocomotive().setDispatcherDirection(LocomotiveBean.Direction.BACKWARDS); - ((Block) blockTile).getBlockBean().setLogicalDirection(LocomotiveBean.Direction.BACKWARDS.getDirection()); - repaint(); - } + blockTile.setLogicalDirection(LocomotiveBean.Direction.BACKWARDS); }//GEN-LAST:event_backwardsRBActionPerformed private void forwardsRBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_forwardsRBActionPerformed - if (((Block) blockTile).getBlockBean().getLocomotive() != null) { - //((Block) blockTile).getBlockBean().getLocomotive().setDispatcherDirection(LocomotiveBean.Direction.FORWARDS); - ((Block) blockTile).getBlockBean().setLogicalDirection(LocomotiveBean.Direction.FORWARDS.getDirection()); - repaint(); - } + blockTile.setLogicalDirection(LocomotiveBean.Direction.FORWARDS); }//GEN-LAST:event_forwardsRBActionPerformed private void scaleCBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_scaleCBActionPerformed - if (this.scaleCB.isSelected()) { - blockTile.setScaleImage(false); - } else { - blockTile.setScaleImage(true); - } - repaint(); + Logger.trace("\nBlok is expanded " + this.scaleCB.isSelected()); + blockTile.setScaleImage(!scaleCB.isSelected()); + canvas.setExpanded(scaleCB.isSelected()); + + //Shift the tile a bit to fit on the canvas +// if(!scaleCB.isSelected()) { +// blockTile.setCenter(new Point(620, 180)); +// } else { +// blockTile.setCenter(new Point(620, 140)); +// } + }//GEN-LAST:event_scaleCBActionPerformed private void centerSPComponentResized(java.awt.event.ComponentEvent evt) {//GEN-FIRST:event_centerSPComponentResized @@ -434,8 +398,8 @@ public static void main(String args[]) { UnscaledBlockTester app = new UnscaledBlockTester(); app.setTitle("Unscaled Tile Tester"); app.setLocationRelativeTo(null); - app.pack(); + //app.pack(); }); } From 14df7ec66e764eaf865c50215a5e05aea32a0f59 Mon Sep 17 00:00:00 2001 From: Frans Jacobs Date: Fri, 24 Jan 2025 23:41:15 +0100 Subject: [PATCH 05/24] More refactoring, Still issue with Block, it is continuously painting --- .../java/jcs/entities/LocomotiveBean.java | 6 +- src/main/java/jcs/ui/layout/LayoutCanvas.form | 4 +- src/main/java/jcs/ui/layout/LayoutCanvas.java | 268 +++--- src/main/java/jcs/ui/layout/LayoutPanel.form | 10 +- src/main/java/jcs/ui/layout/LayoutPanel.java | 3 +- src/main/java/jcs/ui/layout/LayoutUtil.java | 21 - src/main/java/jcs/ui/layout/TileCache.java | 6 +- src/main/java/jcs/ui/layout/tiles/Block.java | 222 ++--- .../java/jcs/ui/layout/tiles/Crossing.java | 32 +- src/main/java/jcs/ui/layout/tiles/Curved.java | 32 +- .../jcs/ui/layout/tiles/DefaultTileModel.java | 14 +- src/main/java/jcs/ui/layout/tiles/End.java | 32 +- .../java/jcs/ui/layout/tiles/Straight.java | 32 +- src/main/java/jcs/ui/layout/tiles/Switch.java | 32 +- src/main/java/jcs/ui/layout/tiles/Tile.java | 905 +++++++++--------- .../java/jcs/ui/layout/tiles/TileModel.java | 4 + .../jcs/ui/layout/tiles/BlockTileTester.java | 10 +- .../jcs/ui/layout/tiles/DotGridCanvas.java | 1 + .../ui/layout/tiles/UnscaledBlockCanvas.java | 6 +- .../ui/layout/tiles/UnscaledBlockTester.java | 46 +- 20 files changed, 831 insertions(+), 855 deletions(-) diff --git a/src/main/java/jcs/entities/LocomotiveBean.java b/src/main/java/jcs/entities/LocomotiveBean.java index a11b8c59..74f66cb8 100644 --- a/src/main/java/jcs/entities/LocomotiveBean.java +++ b/src/main/java/jcs/entities/LocomotiveBean.java @@ -525,7 +525,11 @@ public String getDirection() { } public static Direction get(String direction) { - return ENUM_MAP.get(direction); + if (direction != null) { + return ENUM_MAP.get(direction); + } else { + return null; + } } private static int translate2MarklinValue(String value) { diff --git a/src/main/java/jcs/ui/layout/LayoutCanvas.form b/src/main/java/jcs/ui/layout/LayoutCanvas.form index 4a20d061..884eba14 100755 --- a/src/main/java/jcs/ui/layout/LayoutCanvas.form +++ b/src/main/java/jcs/ui/layout/LayoutCanvas.form @@ -194,13 +194,11 @@ - + - - diff --git a/src/main/java/jcs/ui/layout/LayoutCanvas.java b/src/main/java/jcs/ui/layout/LayoutCanvas.java index fa7d4a8c..67f95120 100755 --- a/src/main/java/jcs/ui/layout/LayoutCanvas.java +++ b/src/main/java/jcs/ui/layout/LayoutCanvas.java @@ -21,6 +21,7 @@ import java.awt.Dimension; import java.awt.Graphics; import java.awt.Graphics2D; +import java.awt.Paint; import java.awt.Point; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; @@ -35,6 +36,7 @@ import java.util.Set; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; +import javax.swing.DebugGraphics; import javax.swing.JFrame; import javax.swing.JMenuItem; import javax.swing.JPanel; @@ -80,7 +82,7 @@ * This canvas / Panel is used to draw the layout * */ -public class LayoutCanvas extends JPanel implements PropertyChangeListener { +public class LayoutCanvas extends JPanel { //implements PropertyChangeListener { public enum Mode { SELECT, @@ -123,6 +125,10 @@ public LayoutCanvas() { } public LayoutCanvas(boolean readonly) { + setLayout(null); + setOpaque(true); + setDoubleBuffered(true); + this.readonly = readonly; // this.tiles = new HashMap<>(); // this.altTiles = new HashMap<>(); @@ -147,64 +153,85 @@ private void postInit() { } @Override - protected void paintComponent(Graphics g) { + public void paint(Graphics g) { long started = System.currentTimeMillis(); - super.paintComponent(g); - Graphics2D g2 = (Graphics2D) g.create(); - Set snapshot = new HashSet<>(TileCache.tiles.values()); + //for (Tile tile : TileCache.tiles.values()) { + // tile.setSelected(selectedTiles.contains(tile.getCenter())); + //} - if (this.drawGrid) { - if (lineGrid) { - paintLineGrid(g); - } else { - paintDotGrid(g); - } - } else { - paintNullGrid(g); - } - - for (Tile tile : snapshot) { - //for (Tile tile : TileCache.tiles.values()) { - //tile.setDrawOutline(drawGrid); - - if (Mode.CONTROL != mode) { - if (selectedTiles.contains(tile.getCenter())) { - //tile.setBackgroundColor(Color.yellow); - tile.setBackgroundColor(Color.orange); - } else { - tile.setBackgroundColor(Color.white); - } - } + //paintNullGrid(g); + super.paint(g); - tile.drawTile(g2); - //debug -// if (!this.readonly) { -// tile.drawCenterPoint(g2, Color.magenta, 3); -// } + if (drawGrid) { + //if (lineGrid) { + // paintLineGrid(g); + //} else { + paintDotGrid(g); + //} } - if (this.movingTileCenterPoint != null && this.movingTileImage != null) { - int x = movingTileCenterPoint.x; - int y = movingTileCenterPoint.y; - int w = movingTileImage.getWidth(); - int h = movingTileImage.getHeight(); - g2.drawImage(movingTileImage, (x - w / 2), (y - h / 2), null); - } + long now = System.currentTimeMillis(); + Logger.trace("Duration: " + (now - started) + " ms."); + } - g2.dispose(); + @Override + protected void paintComponent(Graphics g) { + long started = System.currentTimeMillis(); + super.paintComponent(g); +// Graphics2D g2 = (Graphics2D) g.create(); +// Set snapshot = new HashSet<>(TileCache.tiles.values()); +// +// if (this.drawGrid) { +// if (lineGrid) { +// paintLineGrid(g); +// } else { +// paintDotGrid(g); +// } +// } else { +// paintNullGrid(g); +// } +// +// for (Tile tile : snapshot) { +// //for (Tile tile : TileCache.tiles.values()) { +// //tile.setDrawOutline(drawGrid); +// +// if (Mode.CONTROL != mode) { +// if (selectedTiles.contains(tile.getCenter())) { +// //tile.setBackgroundColor(Color.yellow); +// tile.setBackgroundColor(Color.orange); +// } else { +// tile.setBackgroundColor(Color.white); +// } +// } +// +// //tile.drawTile(g2); +// //debug +//// if (!this.readonly) { +//// tile.drawCenterPoint(g2, Color.magenta, 3); +//// } +// } +// if (this.movingTileCenterPoint != null && this.movingTileImage != null) { +// int x = movingTileCenterPoint.x; +// int y = movingTileCenterPoint.y; +// int w = movingTileImage.getWidth(); +// int h = movingTileImage.getHeight(); +// g2.drawImage(movingTileImage, (x - w / 2), (y - h / 2), null); +// } +// +// g2.dispose(); long now = System.currentTimeMillis(); Logger.trace("Duration: " + (now - started) + " ms."); } - @Override + //@Override public void propertyChange(PropertyChangeEvent evt) { if ("repaintTile".equals(evt.getPropertyName())) { Tile tile = (Tile) evt.getNewValue(); Logger.trace("Repainting Tile: " + tile.getId()); - repaint(tile.getBounds()); +// repaint(tile.getBounds()); } } @@ -239,40 +266,58 @@ private void paintNullGrid(Graphics g) { } private void paintDotGrid(Graphics g) { - if (this.grid != null) { - int pw = this.getWidth(); - int ph = this.getHeight(); - - int gw = grid.getWidth(); - int gh = grid.getHeight(); - - if (pw != gw || ph != gh) { - //Logger.trace("Changed Canvas: " + pw + " x " + ph + " Grid: " + gw + " x " + gh); - this.grid = null; - } else { - } - } - - if (this.grid == null) { - int width = getSize().width; - int height = getSize().height; - grid = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB); - Graphics2D gc = grid.createGraphics(); + int width = this.getWidth(); + int height = this.getHeight(); - gc.setBackground(Color.white); - gc.clearRect(0, 0, width, height); + int xOffset = 0; + int yOffset = 0; - gc.setPaint(Color.black); + //Logger.trace("W: " + width + " H: " + height + " X: " + this.getX() + " Y: " + this.getY()); + Graphics2D gc = (Graphics2D) g; + Paint p = gc.getPaint(); + gc.setPaint(Color.black); - for (int r = 0; r < width; r++) { - for (int c = 0; c < height; c++) { - gc.drawOval(r * Tile.GRID * 2, c * Tile.GRID * 2, 1, 1); - } + for (int r = 0; r < width; r++) { + for (int c = 0; c < height; c++) { + gc.drawOval((r * 20 * 2) + xOffset - 2, (c * 20 * 2) + yOffset - 2, 4, 4); } - gc.dispose(); } - Graphics2D g2 = (Graphics2D) g; - g2.drawImage(grid, null, 0, 0); + gc.setPaint(p); + +// if (this.grid != null) { +// int pw = this.getWidth(); +// int ph = this.getHeight(); +// +// int gw = grid.getWidth(); +// int gh = grid.getHeight(); +// +// if (pw != gw || ph != gh) { +// //Logger.trace("Changed Canvas: " + pw + " x " + ph + " Grid: " + gw + " x " + gh); +// this.grid = null; +// } else { +// } +// } +// +// if (this.grid == null) { +// int width = getSize().width; +// int height = getSize().height; +// grid = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB); +// Graphics2D gc = grid.createGraphics(); +// +// gc.setBackground(Color.white); +// gc.clearRect(0, 0, width, height); +// +// gc.setPaint(Color.black); +// +// for (int r = 0; r < width; r++) { +// for (int c = 0; c < height; c++) { +// gc.drawOval(r * Tile.GRID * 2, c * Tile.GRID * 2, 1, 1); +// } +// } +// gc.dispose(); +// } +// Graphics2D g2 = (Graphics2D) g; +// g2.drawImage(grid, null, 0, 0); } private void paintLineGrid(Graphics g) { @@ -347,7 +392,7 @@ void loadLayoutInBackground() { private void loadTiles() { boolean showValues = Mode.CONTROL.equals(mode); - TileCache.loadTiles(this); + TileCache.loadTiles(); TileCache.setShowValues(showValues); //TileCache.setDrawOutline(drawGrid); TileCache.setDrawCenterPoint(!this.readonly); @@ -450,12 +495,21 @@ private Tile getSelectedTile() { private void mousePressedAction(MouseEvent evt) { Point snapPoint = LayoutUtil.snapToGrid(evt.getPoint()); - Tile tile = TileCache.findTile(snapPoint); //Clear any previous selection + for(Point p : selectedTiles) { + if(TileCache.containsPoint(p)) { + Tile st = TileCache.findTile(p); + st.setSelected(false); + } + } + selectedTiles.clear(); + Tile tile = TileCache.findTile(snapPoint); + if (tile != null) { selectedTiles.addAll(tile.getAllPoints()); + tile.setSelected(true); } switch (mode) { @@ -481,9 +535,11 @@ private void mousePressedAction(MouseEvent evt) { if (addedTile != null) { selectedTiles.addAll(addedTile.getAllPoints()); - if ("false".equals(System.getProperty("batch.tile.persist", "true"))) { - this.saveTile(tile); - } + //if ("false".equals(System.getProperty("batch.tile.persist", "true"))) { + //this.saveTile(tile); + this.add(addedTile); + repaint(); + //} } } else { if (tile != null) { @@ -495,11 +551,17 @@ private void mousePressedAction(MouseEvent evt) { if (MouseEvent.BUTTON3 == evt.getButton() && tile != null) { showOperationsPopupMenu(tile, snapPoint); } - repaint(); + } case DELETE -> { //removeTiles(selectedTiles); - TileCache.removeTiles(selectedTiles); + //TileCache.removeTiles(selectedTiles); + Tile t = (Tile) this.getComponentAt(snapPoint); + if (t != null) { + this.remove(t); + TileCache.deleteTile(t); + } + this.selectedTiles.clear(); repaint(); } @@ -911,34 +973,11 @@ private Tile addTile(Point p) { Tile tile = TileFactory.createTile(tileType, orientation, direction, chkp, drawGrid); //Can the tile be placed, keeping in mind the extra points - boolean canBeAdded = TileCache.checkTileOccupation(tile); + boolean canBeAdded = !TileCache.checkTileOccupation(tile); -// if (!tile.getAltPoints().isEmpty()) { -// //Check if the extra point positions are not occupied -// Set tilePoints = tile.getAllPoints(); -// -// for (Point tp : tilePoints) { -// if (TileCache.containsPoint(tp)) { -// Logger.trace("Point " + p + " occupied by " + TileCache.findTile(p).getId() + " Can't add new Tile: " + tile); -// canBeAdded = false; -// } -// } -// } if (canBeAdded) { TileCache.addTile(tile); -// TileCache.tiles.put(chkp, tile); -// //Alternative point(s) to be able to find all points -// if (!tile.getAltPoints().isEmpty()) { -// Set alt = tile.getAltPoints(); -// for (Point ap : alt) { -// TileCache.altTiles.put(ap, tile); -// } -// } -// -// if ("false".equals(System.getProperty("batch.tile.persist", "true"))) { -// this.saveTile(tile); -// } Logger.trace("Added Tile " + tile.getClass().getSimpleName() + " " + tile.getOrientation() + " @ " + tile.getCenter() + " Full repaint: " + fullRepaint); } @@ -1306,10 +1345,8 @@ public void actionPerformed(ActionEvent evt) { }); blockPopupMenu.add(blockPropertiesMI); - setBackground(new Color(250, 250, 250)); - setAutoscrolls(true); + setBackground(new Color(255, 255, 255)); setMinimumSize(new Dimension(1398, 848)); - setOpaque(false); setPreferredSize(new Dimension(1398, 848)); addMouseMotionListener(new MouseMotionAdapter() { public void mouseDragged(MouseEvent evt) { @@ -1483,7 +1520,7 @@ private void reverseArrivalSideMIActionPerformed(ActionEvent evt) {//GEN-FIRST:e block.getBlockBean().setReverseArrival(!block.getBlockBean().isReverseArrival()); this.executor.execute(() -> { PersistenceFactory.getService().persist(block.getBlockBean()); - block.repaintTile(); + //block.repaintTile(); }); } }//GEN-LAST:event_reverseArrivalSideMIActionPerformed @@ -1504,7 +1541,7 @@ private void toggleLocomotiveDirectionMIActionPerformed(ActionEvent evt) {//GEN- this.executor.execute(() -> { PersistenceFactory.getService().persist(block.getTileBean()); - block.repaintTile(); + //block.repaintTile(); }); } }//GEN-LAST:event_toggleLocomotiveDirectionMIActionPerformed @@ -1512,17 +1549,18 @@ private void toggleLocomotiveDirectionMIActionPerformed(ActionEvent evt) {//GEN- private void toggleOutOfOrderMIActionPerformed(ActionEvent evt) {//GEN-FIRST:event_toggleOutOfOrderMIActionPerformed if (this.selectedTile != null) { Block block = (Block) selectedTile; - BlockBean.BlockState currentState = block.getBlockState(); - if (BlockBean.BlockState.FREE == currentState) { - block.setBlockState(BlockBean.BlockState.OUT_OF_ORDER); - } else if (BlockBean.BlockState.OUT_OF_ORDER == currentState) { - block.setBlockState(BlockBean.BlockState.FREE); + BlockState currentState = block.getBlockState(); + if (BlockState.FREE == currentState) { + block.setBlockState(BlockState.OUT_OF_ORDER); + } else if (BlockState.OUT_OF_ORDER == currentState) { + block.setBlockState(BlockState.FREE); } - if (currentState != block.getRouteBlockState()) { + if (currentState != block.getBlockState()) { //getRouteBlockState()) { this.executor.execute(() -> { PersistenceFactory.getService().persist(block.getBlockBean()); - block.repaintTile(); + //block.repaintTile(); + }); } } @@ -1540,7 +1578,7 @@ private void resetGhostMIActionPerformed(ActionEvent evt) {//GEN-FIRST:event_res } this.executor.execute(() -> { PersistenceFactory.getService().persist(block.getBlockBean()); - block.repaintTile(); + //block.repaintTile(); }); } } diff --git a/src/main/java/jcs/ui/layout/LayoutPanel.form b/src/main/java/jcs/ui/layout/LayoutPanel.form index 7fc284b9..1386e2e4 100755 --- a/src/main/java/jcs/ui/layout/LayoutPanel.form +++ b/src/main/java/jcs/ui/layout/LayoutPanel.form @@ -1034,13 +1034,21 @@ + + + + + + - + + + diff --git a/src/main/java/jcs/ui/layout/LayoutPanel.java b/src/main/java/jcs/ui/layout/LayoutPanel.java index dc8936c2..8a942a81 100755 --- a/src/main/java/jcs/ui/layout/LayoutPanel.java +++ b/src/main/java/jcs/ui/layout/LayoutPanel.java @@ -811,8 +811,9 @@ public void actionPerformed(ActionEvent evt) { canvasScrollPane.setPreferredSize(new Dimension(1024, 850)); canvasScrollPane.setViewportView(canvas); + canvas.setMinimumSize(new Dimension(800, 700)); canvas.setName(""); // NOI18N - canvas.setLayout(new BorderLayout()); + canvas.setPreferredSize(new Dimension(800, 700)); canvasScrollPane.setViewportView(canvas); add(canvasScrollPane, BorderLayout.CENTER); diff --git a/src/main/java/jcs/ui/layout/LayoutUtil.java b/src/main/java/jcs/ui/layout/LayoutUtil.java index a1e723a2..14a1361b 100644 --- a/src/main/java/jcs/ui/layout/LayoutUtil.java +++ b/src/main/java/jcs/ui/layout/LayoutUtil.java @@ -17,11 +17,6 @@ import jcs.ui.layout.tiles.Tile; import java.awt.Point; -import jcs.entities.TileBean.Orientation; -import static jcs.ui.layout.tiles.Block.BLOCK_HEIGHT; -import static jcs.ui.layout.tiles.Block.BLOCK_WIDTH; -import static jcs.ui.layout.tiles.Tile.DEFAULT_HEIGHT; -import static jcs.ui.layout.tiles.Tile.DEFAULT_WIDTH; public class LayoutUtil { @@ -77,20 +72,4 @@ public static double euclideanDistance(Point p1, Point p2) { return d; } - public static int blockWidth(Orientation orientation) { - if (Orientation.EAST == orientation || Orientation.WEST == orientation) { - return BLOCK_WIDTH; - } else { - return DEFAULT_WIDTH; - } - } - - public static int blockHeight(Orientation orientation) { - if (Orientation.EAST == orientation || Orientation.WEST == orientation) { - return DEFAULT_HEIGHT; - } else { - return BLOCK_HEIGHT; - } - } - } diff --git a/src/main/java/jcs/ui/layout/TileCache.java b/src/main/java/jcs/ui/layout/TileCache.java index 28b78f8f..566d9605 100644 --- a/src/main/java/jcs/ui/layout/TileCache.java +++ b/src/main/java/jcs/ui/layout/TileCache.java @@ -113,7 +113,7 @@ public static void setShowValues(boolean showValues) { } } - static void loadTiles(PropertyChangeListener listener) { + static void loadTiles() { List tileBeans = PersistenceFactory.getService().getTileBeans(); tileEventListeners.clear(); @@ -124,7 +124,7 @@ static void loadTiles(PropertyChangeListener listener) { Tile tile = TileFactory.createTile(tb, showValues); //tile.setPropertyChangeListener(listener); tiles.put(tile.getCenter(), tile); - addTileEventListener((TileEventListener) tile); + //addTileEventListener((TileEventListener) tile); //Alternative point(s) to be able to find all points if (!tile.getAltPoints().isEmpty()) { @@ -145,7 +145,7 @@ static List getTiles() { static void addTile(Tile tile) { tiles.put(tile.getCenter(), tile); - addTileEventListener((TileEventListener) tile); + //addTileEventListener((TileEventListener) tile); //Alternative point(s) to be able to find all points if (!tile.getAltPoints().isEmpty()) { diff --git a/src/main/java/jcs/ui/layout/tiles/Block.java b/src/main/java/jcs/ui/layout/tiles/Block.java index 0e315910..d150243c 100755 --- a/src/main/java/jcs/ui/layout/tiles/Block.java +++ b/src/main/java/jcs/ui/layout/tiles/Block.java @@ -24,6 +24,7 @@ import java.awt.Image; import java.awt.Point; import java.awt.geom.Ellipse2D; +import java.awt.image.BufferedImage; import java.util.HashMap; import java.util.HashSet; import java.util.Map; @@ -38,10 +39,6 @@ import static jcs.entities.TileBean.Orientation.SOUTH; import static jcs.entities.TileBean.Orientation.WEST; import jcs.entities.TileBean.TileType; -import jcs.ui.layout.LayoutUtil; -import static jcs.ui.layout.LayoutUtil.blockHeight; -import static jcs.ui.layout.LayoutUtil.blockWidth; -import jcs.ui.layout.events.TileEvent; import static jcs.ui.layout.tiles.Tile.DEFAULT_HEIGHT; import static jcs.ui.layout.tiles.Tile.DEFAULT_WIDTH; import static jcs.ui.layout.tiles.Tile.RENDER_HEIGHT; @@ -54,12 +51,13 @@ public class Block extends Tile { public static final int BLOCK_WIDTH = DEFAULT_WIDTH * 3; public static final int BLOCK_HEIGHT = DEFAULT_HEIGHT * 3; - protected BlockState routeBlockState; - public Block(TileBean tileBean) { - super(tileBean, LayoutUtil.blockWidth(tileBean.getOrientation()), LayoutUtil.blockHeight(tileBean.getOrientation())); + super(tileBean); setModel(new DefaultTileModel()); + changeRenderSize(); + + populateModel(); } public Block(Orientation orientation, Point center) { @@ -67,7 +65,7 @@ public Block(Orientation orientation, Point center) { } public Block(Orientation orientation, int x, int y) { - this(orientation, x, y, LayoutUtil.blockWidth(orientation), LayoutUtil.blockHeight(orientation)); + this(orientation, x, y, tileWidth(orientation, TileType.BLOCK), tileHeight(orientation, TileType.BLOCK)); } public Block(Orientation orientation, int x, int y, int width, int height) { @@ -289,8 +287,8 @@ public String getIdSuffix(Tile other) { @Override public Orientation rotate() { rotate(false); - int w = LayoutUtil.blockWidth(tileOrientation); - int h = LayoutUtil.blockHeight(tileOrientation); + int w = tileWidth(tileOrientation, TileType.BLOCK); + int h = tileHeight(tileOrientation, TileType.BLOCK); Dimension d = new Dimension(w, h); setPreferredSize(d); @@ -334,14 +332,6 @@ protected Color getBlockStateColor(BlockState blockState) { }; } - public void setRouteBlockState(BlockState routeBlockState) { - this.routeBlockState = routeBlockState; - } - - public BlockState getRouteBlockState() { - return routeBlockState; - } - public static String getDepartureSuffix(Orientation tileOrientation, boolean reverseArrival, LocomotiveBean.Direction direction) { if (LocomotiveBean.Direction.FORWARDS == direction) { if (Orientation.EAST == tileOrientation || Orientation.SOUTH == tileOrientation) { @@ -397,7 +387,7 @@ public void renderTile(Graphics2D g2) { //When there is a locomotive in the block mark the direction of travel. //The default, forwards is in the direction of the block orientation, i.e. the + - if (getBlockBean() != null && getBlockBean().getLocomotive() != null && getBlockBean().getLocomotive().getName() != null) { + if (model.getLocomotive() != null && model.getLocomotive().getName() != null) { renderDirectionArrow(g2); } @@ -406,25 +396,24 @@ public void renderTile(Graphics2D g2) { private void renderDirectionArrow(Graphics2D g2) { //The default, forwards is in the direction of the block orientation, i.e. the + - Orientation orientation = this.getOrientation(); BlockBean bb = this.getBlockBean(); - boolean reverseArrival = bb.isReverseArrival(); + boolean reverseArrival = model.isReverseArrival(); LocomotiveBean.Direction logicalDirection; if (bb.getLogicalDirection() != null) { - logicalDirection = LocomotiveBean.Direction.get(bb.getLogicalDirection()); + logicalDirection = model.getLogicalDirection(); } else { - logicalDirection = bb.getLocomotive().getDirection(); + logicalDirection = model.getLocomotive().getDirection(); } - String departureSuffix = bb.getDepartureSuffix(); + String departureSuffix = model.getDepartureSuffix(); if (departureSuffix == null) { - departureSuffix = Block.getDepartureSuffix(orientation, reverseArrival, logicalDirection); + departureSuffix = Block.getDepartureSuffix(tileOrientation, reverseArrival, logicalDirection); } //Logger.trace(this.getId()+" LogicalDirection is " + (bb.getLogicalDirection() != null ? "Set" : "Not Set") + " Dir: " + logicalDirection.getDirection() + " Orientation: " + orientation.getOrientation() + " departureSuffix: " + departureSuffix); if ("+".equals(departureSuffix)) { - if (Orientation.EAST == orientation || Orientation.SOUTH == orientation) { + if (Orientation.EAST == tileOrientation || Orientation.SOUTH == tileOrientation) { switch (logicalDirection) { case LocomotiveBean.Direction.FORWARDS -> { if (reverseArrival) { @@ -460,7 +449,7 @@ private void renderDirectionArrow(Graphics2D g2) { } } } else { - if (Orientation.EAST == orientation || Orientation.SOUTH == orientation) { + if (Orientation.EAST == tileOrientation || Orientation.SOUTH == tileOrientation) { switch (logicalDirection) { case LocomotiveBean.Direction.FORWARDS -> { if (reverseArrival) { @@ -510,172 +499,140 @@ private void renderRightArrow(Graphics2D g2) { @Override public void renderTileRoute(Graphics2D g2d) { - if (routeBlockState != null) { - backgroundColor = getBlockStateColor(routeBlockState); + if (model.isShowBlockState()) { + backgroundColor = getBlockStateColor(model.getBlockState()); } } - protected void overlayLocImage(Graphics2D g2d) { - Image locImage = getLocImage(); - String departureSuffix = null; - boolean reverseImage = true; - if (getBlockBean() != null) { - reverseImage = getBlockBean().isReverseArrival(); - } + protected void overlayLocImage() { + int ww = tileImage.getWidth(); + int hh = tileImage.getHeight(); - if (getBlockBean() != null) { - departureSuffix = getBlockBean().getDepartureSuffix(); - } + BufferedImage overlay = new BufferedImage(ww, hh, BufferedImage.TYPE_INT_ARGB); + Graphics2D g2i = overlay.createGraphics(); + + Image locImage = getLocImage(); if (locImage != null) { + String departureSuffix = model.getDepartureSuffix(); + boolean reverseImage = model.isReverseArrival(); + + Logger.trace("LocImage w: " + locImage.getWidth(null) + " h: " + locImage.getHeight(null)); // scale it to max h of 45 int size = 45; float aspect = (float) locImage.getHeight(null) / (float) locImage.getWidth(null); //TODO: Use Scalr? locImage = locImage.getScaledInstance(size, (int) (size * aspect), Image.SCALE_SMOOTH); - //Logger.trace("LocImage w: " + w + " h: " + h); //Depending on the block orientation the image needs to be rotated and flipped //Incase the departure suffix is NOT set center the locomotive image + int w, h, xx, yy; switch (tileOrientation) { case WEST -> { - int xx; - int w = locImage.getWidth(null); - int h = locImage.getHeight(null); + w = locImage.getWidth(null); + h = locImage.getHeight(null); if (null == departureSuffix) { - xx = tileX - getWidth() / 2 + w; + xx = BLOCK_WIDTH / 2 - getWidth() / 2 + w; } else { switch (departureSuffix) { case "+" -> { - xx = tileX - getWidth() / 2 + w - 25; + xx = BLOCK_WIDTH / 2 - getWidth() / 2 + w - 25; } default -> { - xx = tileX - getWidth() / 2 + w + 10; + xx = BLOCK_WIDTH / 2 - getWidth() / 2 + w + 10; } } } - int yy = tileY - h / 2; + yy = DEFAULT_HEIGHT / 2 - h / 2; if (reverseImage) { locImage = ImageUtil.flipVertically(locImage); } - g2d.drawImage(locImage, xx, yy, null); } case SOUTH -> { locImage = ImageUtil.flipHorizontally(locImage); locImage = ImageUtil.rotate(locImage, 90); - int w = locImage.getWidth(null); - int h = locImage.getHeight(null); + w = locImage.getWidth(null); + h = locImage.getHeight(null); + xx = DEFAULT_WIDTH / 2 - w / 2; - int xx = tileX - w / 2; - int yy; if (null == departureSuffix) { - yy = tileY - getHeight() / 2 + h; + yy = BLOCK_HEIGHT / 2 - getHeight() / 2 + h; } else { switch (departureSuffix) { case "-" -> { - yy = tileY - getHeight() / 2 + h - 25; + yy = BLOCK_HEIGHT / 2 - getHeight() / 2 + h - 25; } default -> { - yy = tileY - getHeight() / 2 + h + 10; + yy = BLOCK_HEIGHT / 2 - getHeight() / 2 + h + 10; } } } if (reverseImage) { locImage = ImageUtil.flipHorizontally(locImage); } - g2d.drawImage(locImage, xx, yy, null); + //g2d.drawImage(locImage, xx, yy, null); } case NORTH -> { locImage = ImageUtil.flipHorizontally(locImage); locImage = ImageUtil.rotate(locImage, 90); - int w = locImage.getWidth(null); - int h = locImage.getHeight(null); + w = locImage.getWidth(null); + h = locImage.getHeight(null); + xx = DEFAULT_WIDTH / 2 - w / 2; - int xx = tileX - w / 2; - int yy; if (null == departureSuffix) { - int minY = tileY - getHeight() / 2 + h; + int minY = BLOCK_HEIGHT / 2 - getHeight() / 2 + h; yy = minY; } else { switch (departureSuffix) { case "+" -> { - yy = tileY - getHeight() / 2 + h - 25; + yy = BLOCK_HEIGHT / 2 - getHeight() / 2 + h - 25; } default -> { - yy = tileY - getHeight() / 2 + h + 10; + yy = BLOCK_HEIGHT / 2 - getHeight() / 2 + h + 10; } } } if (reverseImage) { locImage = ImageUtil.flipHorizontally(locImage); } - g2d.drawImage(locImage, xx, yy, null); } default -> { - //EAST - int xx; - int w = locImage.getWidth(null); - int h = locImage.getHeight(null); - + w = locImage.getWidth(null); + h = locImage.getHeight(null); if (null == departureSuffix) { - xx = tileX - getWidth() / 2 + w; + xx = BLOCK_WIDTH / 2 - getWidth() / 2 + w; } else { switch (departureSuffix) { case "-" -> { - xx = tileX - getWidth() / 2 + w - 25; + xx = BLOCK_WIDTH / 2 - getWidth() / 2 + w - 25; } default -> { - xx = tileX - getWidth() / 2 + w + 10; + xx = BLOCK_WIDTH / 2 - getWidth() / 2 + w + 10; } } } - int yy = tileY - h / 2; + yy = DEFAULT_HEIGHT / 2 - h / 2; if (reverseImage) { locImage = ImageUtil.flipVertically(locImage); } - g2d.drawImage(locImage, xx, yy, null); } } - } - } - /** - * Overridden to overlay a locomotive Icon - * - * @param g2d The graphics handle - */ - @Override - public void drawTile(Graphics2D g2d) { - super.drawTile(g2d); - if (getLocImage() != null) { - overlayLocImage(g2d); + g2i.drawImage(tileImage, 0, 0, null); + g2i.drawImage(locImage, xx, yy, null); + g2i.dispose(); + tileImage = overlay; } - } - @Override - public void onTileChange(TileEvent tileEvent) { - //TODO: Does not yet work for route block status change - Color pb = this.backgroundColor; - super.onTileChange(tileEvent); - if (!pb.equals(backgroundColor)) { - repaint(); - } } private Image getLocImage() { - if (blockBean != null && blockBean.getLocomotive() != null && blockBean.getLocomotive().getLocIcon() != null) { - //Do not show the image in block state FREE, OUT_OF_ORDER and LOCKED - BlockState blockState = blockBean.getBlockState(); - boolean showImage = !(BlockState.FREE == blockState || BlockState.LOCKED == blockState || BlockState.OUT_OF_ORDER == blockState || BlockState.GHOST == blockState); - if (showImage) { - return blockBean.getLocomotive().getLocIcon(); - } else { - return null; - } + if (model.getLocomotive() != null && model.getLocomotive().getLocIcon() != null) { + return model.getLocomotive().getLocIcon(); } else { return null; } @@ -683,20 +640,20 @@ private Image getLocImage() { public String getBlockText() { String blockText; - if (getBlockBean() != null && getBlockBean().getDescription() != null) { + if (blockBean != null && blockBean.getDescription() != null) { if (blockBean.getLocomotive() != null && blockBean.getLocomotive().getName() != null && BlockState.GHOST != blockBean.getBlockState()) { - blockText = getBlockBean().getLocomotive().getName(); + blockText = blockBean.getLocomotive().getName(); } else { - if (getBlockBean().getDescription().length() > 0) { - blockText = getBlockBean().getDescription(); + if (blockBean.getDescription().length() > 0) { + blockText = blockBean.getDescription(); } else { blockText = getId(); } } } else { // Design mode show description when available - if (getBlockBean() != null && getBlockBean().getDescription() != null && getBlockBean().getDescription().length() > 0) { - blockText = getBlockBean().getDescription(); + if (blockBean != null && blockBean.getDescription() != null && blockBean.getDescription().length() > 0) { + blockText = blockBean.getDescription(); } else { blockText = getId(); } @@ -706,9 +663,7 @@ public String getBlockText() { @Override public void drawName(Graphics2D g2d) { - Image locImage = getLocImage(); - - if (locImage == null) { + if (!model.isOverlayImage()) { g2d.setPaint(Color.black); Font currentFont = g2d.getFont(); @@ -729,7 +684,7 @@ public void drawName(Graphics2D g2d) { int textHeight = g2d.getFontMetrics().getHeight(); - switch (getOrientation()) { + switch (tileOrientation) { case EAST -> { drawRotate(g2d, ((RENDER_WIDTH * 3) / 2) - textWidth / 2, RENDER_GRID + textHeight / 3, 0, blockText); } @@ -754,7 +709,7 @@ protected void paintComponent(Graphics g) { long started = System.currentTimeMillis(); super.paintComponent(g); - int multiplier = (model.isScaleImage() ? 1 : 10); + int multiplier = 1; //(model.isScaleImage() ? 1 : 10); int xx, yy; if (tileOrientation == Orientation.EAST || tileOrientation == Orientation.WEST) { xx = tileX - GRID * multiplier - GRID * multiplier * 2; @@ -764,21 +719,34 @@ protected void paintComponent(Graphics g) { yy = tileY - GRID * multiplier - GRID * multiplier * 2; } - if (model.isScaleImage()) { - setBounds(xx, yy, LayoutUtil.blockWidth(tileOrientation), LayoutUtil.blockHeight(tileOrientation)); - } else { - setBounds(xx, yy, renderWidth, renderHeight); - } + //if (model.isScaleImage()) { + setBounds(xx, yy, tileWidth(tileOrientation, TileType.BLOCK), tileHeight(tileOrientation, TileType.BLOCK)); + //setBounds(tileX - 60, tileY - 20, tileWidth(tileOrientation, TileType.BLOCK), tileHeight(tileOrientation, TileType.BLOCK)); + //} else { + //setBounds(xx, yy, renderWidth, renderHeight); + //} + + + //setBounds(tileX - GRID, tileY - GRID, DEFAULT_WIDTH, DEFAULT_HEIGHT); - Logger.trace(id + ": " + tileOrientation + " W: " + getWidth() + " H: " + getHeight() + " tX: " + tileX + ", tY: " + tileY + " xx: " + xx + " yy: " + yy + " Scale factor: " + multiplier); + //Graphics2D g2 = (Graphics2D) g.create(); + //Graphics2D g2 = (Graphics2D) g.create(tileX - GRID, tileY - GRID, DEFAULT_WIDTH, DEFAULT_HEIGHT); + + + //Logger.trace(id + ": " + tileOrientation + " W: " + getWidth() + " H: " + getHeight() + " tX: " + tileX + ", tY: " + tileY + " xx: " + xx + " yy: " + yy + " Scale factor: " + multiplier); Graphics2D g2 = (Graphics2D) g.create(); - //Graphics2D g2 = (Graphics2D) g; drawTile(g2); g2.dispose(); + if (model.isOverlayImage()) { + overlayLocImage(); + } + g.drawImage(tileImage, 0, 0, null); + //new Exception().printStackTrace() ; + long now = System.currentTimeMillis(); Logger.trace(id + " Duration: " + (now - started) + " ms."); } @@ -811,13 +779,9 @@ protected void drawCenterPoint(Graphics2D g2d, Color color, double size) { g2d.fill(new Ellipse2D.Double(dX2, dY2, size, size)); g2d.fill(new Ellipse2D.Double(dX3, dY3, size / 2, size / 2)); -// g2d.setPaint(Color.black); -// g2d.setStroke(new BasicStroke(2, BasicStroke.CAP_SQUARE, BasicStroke.JOIN_ROUND)); -// g2d.drawOval(renderWidth / 2 - 5, renderHeight / 2 - 5, 10, 10); - - Logger.trace(id + " dX2: " + dX2 + " dY2: " + dY2 + " O: " + tileOrientation + " rW: " + renderWidth + " rH:" + renderHeight + " Size: " + size); - Logger.trace(id + " dX1: " + dX1 + " dY1: " + dY1); - Logger.trace(id + " dX3: " + dX3 + " dY3: " + dY3); + //Logger.trace(id + " dX2: " + dX2 + " dY2: " + dY2 + " O: " + tileOrientation + " rW: " + renderWidth + " rH:" + renderHeight + " Size: " + size); + //Logger.trace(id + " dX1: " + dX1 + " dY1: " + dY1); + //Logger.trace(id + " dX3: " + dX3 + " dY3: " + dY3); } } diff --git a/src/main/java/jcs/ui/layout/tiles/Crossing.java b/src/main/java/jcs/ui/layout/tiles/Crossing.java index cacf54e1..c9813112 100644 --- a/src/main/java/jcs/ui/layout/tiles/Crossing.java +++ b/src/main/java/jcs/ui/layout/tiles/Crossing.java @@ -129,21 +129,21 @@ protected void renderRouteVertical(Graphics2D g2) { g2.fillRect(xxs, yys, w, h); } - @Override - public void renderTileRoute(Graphics2D g2) { - if (isHorizontal()) { - if (Orientation.EAST == incomingSide || Orientation.WEST == incomingSide) { - renderRouteStraight(g2); - } else { - renderRouteVertical(g2); - } - } else { - if (Orientation.NORTH == incomingSide || Orientation.SOUTH == incomingSide) { - renderRouteStraight(g2); - } else { - renderRouteVertical(g2); - } - } - } +// @Override +// public void renderTileRoute(Graphics2D g2) { +// if (isHorizontal()) { +// if (Orientation.EAST == incomingSide || Orientation.WEST == incomingSide) { +// renderRouteStraight(g2); +// } else { +// renderRouteVertical(g2); +// } +// } else { +// if (Orientation.NORTH == incomingSide || Orientation.SOUTH == incomingSide) { +// renderRouteStraight(g2); +// } else { +// renderRouteVertical(g2); +// } +// } +// } } diff --git a/src/main/java/jcs/ui/layout/tiles/Curved.java b/src/main/java/jcs/ui/layout/tiles/Curved.java index 450c8c06..1aad3e4b 100755 --- a/src/main/java/jcs/ui/layout/tiles/Curved.java +++ b/src/main/java/jcs/ui/layout/tiles/Curved.java @@ -144,21 +144,21 @@ public void renderTileRoute(Graphics2D g2) { g2.fillPolygon(xPoints, yPoints, xPoints.length); } - @Override - protected void paintComponent(Graphics g) { - long started = System.currentTimeMillis(); - super.paintComponent(g); - - setBounds(this.tileX - GRID, this.tileY - GRID, this.getWidth(), this.getHeight()); - - Graphics2D g2 = (Graphics2D) g.create(); - drawTile(g2); - g2.dispose(); - - g.drawImage(this.tileImage, 0, 0, null); - - long now = System.currentTimeMillis(); - Logger.trace(this.id + " Duration: " + (now - started) + " ms."); - } +// @Override +// protected void paintComponent(Graphics g) { +// long started = System.currentTimeMillis(); +// super.paintComponent(g); +// +// setBounds(this.tileX - GRID, this.tileY - GRID, this.getWidth(), this.getHeight()); +// +// Graphics2D g2 = (Graphics2D) g.create(); +// drawTile(g2); +// g2.dispose(); +// +// g.drawImage(this.tileImage, 0, 0, null); +// +// long now = System.currentTimeMillis(); +// Logger.trace(this.id + " Duration: " + (now - started) + " ms."); +// } } diff --git a/src/main/java/jcs/ui/layout/tiles/DefaultTileModel.java b/src/main/java/jcs/ui/layout/tiles/DefaultTileModel.java index c766c6d2..f584c651 100644 --- a/src/main/java/jcs/ui/layout/tiles/DefaultTileModel.java +++ b/src/main/java/jcs/ui/layout/tiles/DefaultTileModel.java @@ -52,6 +52,7 @@ public class DefaultTileModel implements TileModel { protected BlockState blockState; protected boolean reverseArrival; protected String arrivalSuffix; + protected boolean overlayImage = false; protected LocomotiveBean.Direction logicalDirection; protected LocomotiveBean locomotive; @@ -244,9 +245,16 @@ public void setLocomotive(LocomotiveBean locomotive) { fireStateChanged(); } - - - + @Override + public boolean isOverlayImage() { + return overlayImage; + } + + @Override + public void setOverlayImage(boolean overlayImage) { + this.overlayImage = overlayImage; + } + @Override public void addChangeListener(ChangeListener l) { listenerList.add(ChangeListener.class, l); diff --git a/src/main/java/jcs/ui/layout/tiles/End.java b/src/main/java/jcs/ui/layout/tiles/End.java index 91026af3..fd474844 100644 --- a/src/main/java/jcs/ui/layout/tiles/End.java +++ b/src/main/java/jcs/ui/layout/tiles/End.java @@ -131,21 +131,21 @@ public void renderTile(Graphics2D g2) { public void renderTileRoute(Graphics2D g2d) { } - @Override - protected void paintComponent(Graphics g) { - long started = System.currentTimeMillis(); - super.paintComponent(g); - - setBounds(this.tileX - GRID, this.tileY - GRID, this.getWidth(), this.getHeight()); - - Graphics2D g2 = (Graphics2D) g.create(); - drawTile(g2); - g2.dispose(); - - g.drawImage(this.tileImage, 0, 0, null); - - long now = System.currentTimeMillis(); - Logger.trace(this.id + " Duration: " + (now - started) + " ms."); - } +// @Override +// protected void paintComponent(Graphics g) { +// long started = System.currentTimeMillis(); +// super.paintComponent(g); +// +// setBounds(this.tileX - GRID, this.tileY - GRID, this.getWidth(), this.getHeight()); +// +// Graphics2D g2 = (Graphics2D) g.create(); +// drawTile(g2); +// g2.dispose(); +// +// g.drawImage(this.tileImage, 0, 0, null); +// +// long now = System.currentTimeMillis(); +// Logger.trace(this.id + " Duration: " + (now - started) + " ms."); +// } } diff --git a/src/main/java/jcs/ui/layout/tiles/Straight.java b/src/main/java/jcs/ui/layout/tiles/Straight.java index 6f8b3de6..8a45ba69 100755 --- a/src/main/java/jcs/ui/layout/tiles/Straight.java +++ b/src/main/java/jcs/ui/layout/tiles/Straight.java @@ -129,21 +129,21 @@ public void renderTile(Graphics2D g2) { renderStraight(g2); } - @Override - protected void paintComponent(Graphics g) { - long started = System.currentTimeMillis(); - super.paintComponent(g); - - setBounds(this.tileX - GRID, this.tileY - GRID, this.getWidth(), this.getHeight()); - - Graphics2D g2 = (Graphics2D) g.create(); - drawTile(g2); - g2.dispose(); - - g.drawImage(this.tileImage, 0, 0, null); - - long now = System.currentTimeMillis(); - Logger.trace(this.id + " Duration: " + (now - started) + " ms."); - } +// @Override +// protected void paintComponent(Graphics g) { +// long started = System.currentTimeMillis(); +// super.paintComponent(g); +// +// setBounds(this.tileX - GRID, this.tileY - GRID, this.getWidth(), this.getHeight()); +// +// Graphics2D g2 = (Graphics2D) g.create(); +// drawTile(g2); +// g2.dispose(); +// +// g.drawImage(this.tileImage, 0, 0, null); +// +// long now = System.currentTimeMillis(); +// Logger.trace(this.id + " Duration: " + (now - started) + " ms."); +// } } diff --git a/src/main/java/jcs/ui/layout/tiles/Switch.java b/src/main/java/jcs/ui/layout/tiles/Switch.java index 2a099a59..c75a4d45 100644 --- a/src/main/java/jcs/ui/layout/tiles/Switch.java +++ b/src/main/java/jcs/ui/layout/tiles/Switch.java @@ -341,20 +341,20 @@ public AccessoryValue accessoryValueForRoute(Orientation from, Orientation to) { } } - @Override - protected void paintComponent(Graphics g) { - long started = System.currentTimeMillis(); - super.paintComponent(g); - - setBounds(this.tileX - GRID, this.tileY - GRID, this.getWidth(), this.getHeight()); - - Graphics2D g2 = (Graphics2D) g.create(); - drawTile(g2); - g2.dispose(); - - g.drawImage(this.tileImage, 0, 0, null); - - long now = System.currentTimeMillis(); - Logger.trace(this.id + " Duration: " + (now - started) + " ms."); - } +// @Override +// protected void paintComponent(Graphics g) { +// long started = System.currentTimeMillis(); +// super.paintComponent(g); +// +// setBounds(this.tileX - GRID, this.tileY - GRID, this.getWidth(), this.getHeight()); +// +// Graphics2D g2 = (Graphics2D) g.create(); +// drawTile(g2); +// g2.dispose(); +// +// g.drawImage(this.tileImage, 0, 0, null); +// +// long now = System.currentTimeMillis(); +// Logger.trace(this.id + " Duration: " + (now - started) + " ms."); +// } } diff --git a/src/main/java/jcs/ui/layout/tiles/Tile.java b/src/main/java/jcs/ui/layout/tiles/Tile.java index dd068616..ae8f39f1 100755 --- a/src/main/java/jcs/ui/layout/tiles/Tile.java +++ b/src/main/java/jcs/ui/layout/tiles/Tile.java @@ -17,15 +17,14 @@ import java.awt.Color; import java.awt.Dimension; +import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.Point; -import java.awt.Rectangle; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.geom.AffineTransform; import java.awt.geom.Ellipse2D; import java.awt.geom.PathIterator; -import java.awt.geom.Point2D; import java.awt.geom.Rectangle2D; import java.awt.image.AffineTransformOp; import java.awt.image.BufferedImage; @@ -52,8 +51,8 @@ import jcs.entities.TileBean.Orientation; import jcs.entities.TileBean.TileType; import jcs.ui.layout.LayoutUtil; -import jcs.ui.layout.events.TileEvent; -import jcs.ui.layout.events.TileEventListener; +import static jcs.ui.layout.tiles.Block.BLOCK_HEIGHT; +import static jcs.ui.layout.tiles.Block.BLOCK_WIDTH; import org.imgscalr.Scalr; import org.imgscalr.Scalr.Method; import org.imgscalr.Scalr.Mode; @@ -76,21 +75,21 @@ *

* A Tile is rendered to a Buffered Image to speed up the display */ -public abstract class Tile extends JComponent implements TileEventListener { //, ItemSelectable { +public abstract class Tile extends JComponent { //implements TileEventListener { //, ItemSelectable { public static final int GRID = 20; public static final int DEFAULT_WIDTH = GRID * 2; public static final int DEFAULT_HEIGHT = GRID * 2; - + static final int RENDER_GRID = GRID * 10; static final int RENDER_WIDTH = RENDER_GRID * 2; static final int RENDER_HEIGHT = RENDER_GRID * 2; - + public static final Color DEFAULT_BACKGROUND_COLOR = Color.white; public static final Color DEFAULT_TRACK_COLOR = Color.lightGray; public static final Color DEFAULT_ROUTE_TRACK_COLOR = Color.blue; public static final Color DEFAULT_SELECTED_COLOR = Color.yellow; - + public static final String MODEL_CHANGED_PROPERTY = "model"; public static final String CONTENT_AREA_FILLED_CHANGED_PROPERTY = "contentAreaFilled"; @@ -98,325 +97,362 @@ public abstract class Tile extends JComponent implements TileEventListener { //, * The data model that determines the button's state. */ protected TileModel model = null; - + protected String id; protected Integer tileX; protected Integer tileY; - + protected int renderWidth; protected int renderHeight; - + protected Orientation tileOrientation; protected Direction tileDirection; - + protected TileType tileType; protected String accessoryId; protected String sensorId; - + protected AccessoryValue accessoryValue; protected AccessoryValue routeValue; - + protected SignalType signalType; protected AccessoryBean.SignalValue signalValue; - + + protected TileBean tileBean; protected AccessoryBean accessoryBean; protected SensorBean sensorBean; protected BlockBean blockBean; - + protected List neighbours; - + protected int offsetX = 0; protected int offsetY = 0; - + protected int renderOffsetX = 0; protected int renderOffsetY = 0; - + protected Color selectedColor; protected Color trackColor; protected Color trackRouteColor; protected Orientation incomingSide; - + protected Color backgroundColor; protected boolean drawName = true; - + protected BufferedImage tileImage; - + protected PropertyChangeListener propertyChangeListener; - + protected ChangeListener changeListener = null; protected ActionListener actionListener = null; - //protected ItemListener itemListener = null; protected transient ChangeEvent changeEvent; - + private Handler handler; - //protected Tile(TileType tileType, Point center) { - // this(tileType, Orientation.EAST, Direction.CENTER, center.x, center.y, DEFAULT_WIDTH, DEFAULT_HEIGHT); - //} protected Tile(TileType tileType, Orientation orientation, Point center, int width, int height) { this(tileType, orientation, Direction.CENTER, center.x, center.y, width, height); } - + protected Tile(TileType tileType, Orientation orientation, int x, int y, int width, int height) { this(tileType, orientation, Direction.CENTER, x, y, width, height); } - + protected Tile(TileType tileType, Orientation orientation, Direction direction, int x, int y, int width, int height) { this(tileType, orientation, direction, x, y, width, height, null, null); } - + protected Tile(TileType tileType, Orientation orientation, Direction direction, int x, int y, int width, int height, Color backgroundColor, Color selectedColor) { this.tileType = tileType; this.tileOrientation = orientation; this.tileDirection = direction; this.tileX = x; this.tileY = y; - + setLayout(null); Dimension d = new Dimension(width, height); setSize(d); setPreferredSize(d); - - int w = getWidth(); - int h = getHeight(); - + + //int w = getWidth(); + //int h = getHeight(); this.renderWidth = RENDER_WIDTH; this.renderHeight = RENDER_HEIGHT; - + this.trackColor = DEFAULT_TRACK_COLOR; this.backgroundColor = backgroundColor; this.selectedColor = selectedColor; - + if (this.backgroundColor == null) { this.backgroundColor = DEFAULT_BACKGROUND_COLOR; } if (this.selectedColor == null) { this.selectedColor = DEFAULT_SELECTED_COLOR; } - } - - protected Tile(Object tileBean) { - this(tileBean, DEFAULT_WIDTH, DEFAULT_HEIGHT); + + protected Tile(TileBean tileBean) { + //this(tileBean, DEFAULT_WIDTH, DEFAULT_HEIGHT); + this(tileBean, tileWidth(tileBean.getOrientation(), tileBean.getTileType()), tileHeight(tileBean.getOrientation(), tileBean.getTileType())); } - - protected Tile(Object tileBean, int width, int height) { - copyInto(tileBean); + + protected Tile(TileBean tileBean, int width, int height) { + this.tileBean = tileBean; + //Quick properties + this.id = tileBean.getId(); + this.tileType = tileBean.getTileType(); + this.tileOrientation = tileBean.getOrientation(); + this.tileDirection = tileBean.getDirection(); + this.tileX = tileBean.getX(); + this.tileY = tileBean.getY(); + + this.accessoryId = tileBean.getAccessoryId(); + this.accessoryBean = tileBean.getAccessoryBean(); + this.signalType = tileBean.getSignalType(); + + this.sensorId = tileBean.getSensorId(); + this.sensorBean = tileBean.getSensorBean(); + this.blockBean = tileBean.getBlockBean(); + setLayout(null); Dimension d = new Dimension(width, height); setSize(d); setPreferredSize(d); - + this.trackColor = DEFAULT_TRACK_COLOR; this.backgroundColor = DEFAULT_BACKGROUND_COLOR; this.selectedColor = DEFAULT_SELECTED_COLOR; this.renderWidth = RENDER_WIDTH; this.renderHeight = RENDER_HEIGHT; } - - private void copyInto(Object object) { - if (object instanceof TileBean other) { - this.id = other.getId(); - this.tileType = other.getTileType(); - this.tileOrientation = other.getOrientation(); - this.tileOrientation = other.getOrientation(); - this.tileDirection = other.getDirection(); - this.tileDirection = other.getDirection(); - this.tileX = other.getX(); - this.tileY = other.getY(); - - this.signalType = other.getSignalType(); - this.accessoryId = other.getAccessoryId(); - this.sensorId = other.getSensorId(); - this.accessoryBean = other.getAccessoryBean(); - this.sensorBean = other.getSensorBean(); - this.blockBean = other.getBlockBean(); - - if (other.getAccessoryBean() != null) { - AccessoryBean ab = other.getAccessoryBean(); - this.signalType = SignalType.getSignalType(ab.getType()); + + protected static int tileWidth(Orientation orientation, TileType tileType) { + if (Orientation.EAST == orientation || Orientation.WEST == orientation) { + if (null == tileType) { + return DEFAULT_WIDTH; + } else { + return switch (tileType) { + case BLOCK -> + BLOCK_WIDTH; + case CROSS -> + DEFAULT_WIDTH * 2; + default -> + DEFAULT_WIDTH; + }; } - + } else { + return DEFAULT_WIDTH; } - - if (object instanceof Tile tile) { - this.renderWidth = tile.renderWidth; - this.renderHeight = tile.renderHeight; + } + + protected static int tileHeight(Orientation orientation, TileType tileType) { + if (Orientation.EAST == orientation || Orientation.WEST == orientation) { + return DEFAULT_HEIGHT; + } else { + if (null == tileType) { + return DEFAULT_HEIGHT; + } else { + return switch (tileType) { + case BLOCK -> + BLOCK_HEIGHT; + case CROSS -> + DEFAULT_HEIGHT * 2; + default -> + DEFAULT_HEIGHT; + }; + } } - } - + + protected void populateModel() { + if (this.blockBean != null) { + this.model.setBlockState(this.blockBean.getBlockState()); + this.model.setLocomotive(this.blockBean.getLocomotive()); + this.model.setArrivalSuffix(this.blockBean.getArrivalSuffix()); + this.model.setLogicalDirection(LocomotiveBean.Direction.get(this.blockBean.getLogicalDirection())); + } + } + public TileBean getTileBean() { - TileBean tb = new TileBean(); - tb.setId(this.id); - tb.setX(this.tileX); - tb.setY(this.tileY); - tb.setTileType(this.tileType); - tb.setTileOrientation(this.tileOrientation.getOrientation()); - tb.setTileDirection(this.tileDirection.getDirection()); - tb.setSignalType(this.signalType); - tb.setAccessoryId(this.accessoryId); - tb.setSensorId(this.sensorId); - tb.setAccessoryBean(this.accessoryBean); - tb.setSensorBean(this.sensorBean); - tb.setBlockBean(this.blockBean); - - return tb; - } - + if (tileBean == null) { + tileBean = new TileBean(); + tileBean.setId(this.id); + tileBean.setX(this.tileX); + tileBean.setY(this.tileY); + tileBean.setTileType(this.tileType); + tileBean.setTileOrientation(this.tileOrientation.getOrientation()); + tileBean.setTileDirection(this.tileDirection.getDirection()); + tileBean.setSignalType(this.signalType); + tileBean.setAccessoryId(this.accessoryId); + tileBean.setSensorId(this.sensorId); + tileBean.setAccessoryBean(this.accessoryBean); + tileBean.setSensorBean(this.sensorBean); + tileBean.setBlockBean(this.blockBean); + } + return tileBean; + } + public boolean isSelected() { return model.isSelected(); } - + public void setSelected(boolean b) { //boolean oldValue = isSelected(); model.setSelected(b); } - - @Override + + //@Override public String getId() { return id; } - + public void setId(String id) { this.id = id; } - + public SignalType getSignalType() { return signalType; } - + public void setSignalType(SignalType signalType) { this.signalType = signalType; } - + public Integer getTileX() { return tileX; } -// public void setTileX(Integer x) { -// this.tileX = x; -// } public Integer getTileY() { return tileY; } -// public void setTileY(Integer y) { -// this.tileY = y; -// } public Point getCenter() { return new Point(this.tileX, this.tileY); } - + public void setCenter(Point center) { tileX = center.x; tileY = center.y; + if (this.tileBean != null) { + this.tileBean.setCenter(center); + } } - + public Orientation getOrientation() { return tileOrientation; } - + public void setOrientation(Orientation orientation) { this.tileOrientation = orientation; + if (this.tileBean != null) { + this.tileBean.setOrientation(orientation); + } } - + public Direction getDirection() { return tileDirection; } - + public void setDirection(Direction direction) { this.tileDirection = direction; + if (this.tileBean != null) { + this.tileBean.setDirection(direction); + } } - + public String getAccessoryId() { return accessoryId; } - + public void setAccessoryId(String accessoryId) { this.accessoryId = accessoryId; + if (this.tileBean != null) { + this.tileBean.setAccessoryId(accessoryId); + } } - + public String getSensorId() { return sensorId; } - + public void setSensorId(String sensorId) { this.sensorId = sensorId; } - + public boolean isActive() { return model.isSensorActive(); } - + public void setActive(boolean active) { model.setSensorActive(active); } - + public BlockState getBlockState() { return model.getBlockState(); } - + public void setBlockState(BlockState blockState) { if (blockBean != null) { blockBean.setBlockState(blockState); + LocomotiveBean locomotive = model.getLocomotive(); + model.setOverlayImage(locomotive != null && locomotive.getLocIcon() != null && (blockState == BlockState.OCCUPIED || blockState == BlockState.INBOUND || blockState == BlockState.OUTBOUND)); } model.setBlockState(blockState); } - + public String getDepartureSuffix() { return model.getDepartureSuffix(); } - + public void setDepartureSuffix(String suffix) { if (blockBean != null) { blockBean.setDepartureSuffix(suffix); } model.setDepartureSuffix(suffix); } - + public boolean isReverseArrival() { return model.isReverseArrival(); } - + public void setReverseArrival(boolean reverseArrival) { if (blockBean != null) { blockBean.setReverseArrival(reverseArrival); } model.setReverseArrival(reverseArrival); } - + public LocomotiveBean.Direction getLogicalDirection() { return model.getLogicalDirection(); } - + public void setLogicalDirection(LocomotiveBean.Direction logicalDirection) { if (blockBean != null) { blockBean.setLogicalDirection(logicalDirection.getDirection()); } model.setLogicalDirection(logicalDirection); } - + public LocomotiveBean getLocomotive() { return model.getLocomotive(); } - + public void setLocomotive(LocomotiveBean locomotive) { if (blockBean != null) { blockBean.setLocomotive(locomotive); + model.setOverlayImage(locomotive != null && locomotive.getLocIcon() != null && (model.getBlockState() == BlockState.OCCUPIED || model.getBlockState() == BlockState.INBOUND || model.getBlockState() == BlockState.OUTBOUND)); } - - this.model.setLocomotive(locomotive); + + model.setLocomotive(locomotive); } - + public AccessoryBean getAccessoryBean() { return accessoryBean; } - + public void setAccessoryBean(AccessoryBean accessoryBean) { this.accessoryBean = accessoryBean; - + if (accessoryBean != null) { this.accessoryId = accessoryBean.getId(); this.signalValue = accessoryBean.getSignalValue(); @@ -427,7 +463,7 @@ public void setAccessoryBean(AccessoryBean accessoryBean) { this.signalValue = AccessoryBean.SignalValue.OFF; } } - + public AccessoryValue getAccessoryValue() { if (this.accessoryValue == null) { return AccessoryValue.OFF; @@ -435,12 +471,12 @@ public AccessoryValue getAccessoryValue() { return accessoryValue; } } - + public void setAccessoryValue(AccessoryValue value) { this.accessoryValue = value; repaint(); } - + public AccessoryValue getRouteValue() { if (routeValue == null) { return AccessoryValue.OFF; @@ -448,127 +484,127 @@ public AccessoryValue getRouteValue() { return routeValue; } } - + public void setRouteValue(AccessoryValue value) { this.routeValue = value; repaint(); } - + public AccessoryBean.SignalValue getSignalValue() { return signalValue; } - + public void setSignalValue(AccessoryBean.SignalValue signalValue) { this.signalValue = signalValue; this.repaint(); } - + public SensorBean getSensorBean() { return sensorBean; } - + public void setSensorBean(SensorBean sensorBean) { this.sensorBean = sensorBean; } - + public BlockBean getBlockBean() { return blockBean; } - + public void setBlockBean(BlockBean blockBean) { this.blockBean = blockBean; } - + public void setRenderWidth(int renderWidth) { this.renderWidth = renderWidth; } - + public void setRenderHeight(int renderHeight) { this.renderHeight = renderHeight; } - + public int getRenderOffsetX() { return renderOffsetX; } - + public void setRenderOffsetX(int renderOffsetX) { this.renderOffsetX = renderOffsetX; } - + public int getRenderOffsetY() { return renderOffsetY; } - + public void setRenderOffsetY(int renderOffsetY) { this.renderOffsetY = renderOffsetY; } - + public TileBean.TileType getTileType() { return this.tileType; } - + public final void setTileType(TileType tileType) { this.tileType = tileType; } - + public Color getTrackColor() { return trackColor; } - + public final void setTrackColor(Color trackColor) { this.trackColor = trackColor; } - + public Color getTrackRouteColor() { return trackRouteColor; } - + public void setTrackRouteColor(Color trackRouteColor) { this.trackRouteColor = trackRouteColor; } - + public Color getSelectedColor() { return selectedColor; } - + public void setSelectedColor(Color selectedColor) { this.selectedColor = selectedColor; } - + public Orientation getIncomingSide() { return incomingSide; } - + public void setIncomingSide(Orientation incomingSide) { this.incomingSide = incomingSide; } - + public Color getBackgroundColor() { return backgroundColor; } - + public void setBackgroundColor(Color backgroundColor) { this.backgroundColor = backgroundColor; } - + public boolean isDrawRoute() { return model.isShowRoute(); } - + public void setDrawRoute(boolean drawRoute) { this.model.setShowRoute(drawRoute); } - + public int getRenderWidth() { return renderWidth; } - + public int getRenderHeight() { return renderHeight; } - + abstract void renderTile(Graphics2D g2d); - + abstract void renderTileRoute(Graphics2D g2d); /** @@ -576,30 +612,29 @@ public int getRenderHeight() { * * @param g2d The graphics handle */ - //@Override public void drawTile(Graphics2D g2d) { // by default and image is rendered in the EAST orientation if (tileOrientation == null) { tileOrientation = Orientation.EAST; } - - tileImage = createImage(); - Graphics2D g2di = tileImage.createGraphics(); + + BufferedImage bf = createImage(); + Graphics2D g2di = bf.createGraphics(); //Avoid errors if (model.isShowRoute() && incomingSide == null) { incomingSide = getOrientation(); } - + if (model.isSelected()) { g2di.setBackground(selectedColor); } else { g2di.setBackground(backgroundColor); } - + g2di.clearRect(0, 0, renderWidth, renderHeight); int ox = 0, oy = 0; - + AffineTransform trans = new AffineTransform(); switch (tileOrientation) { case SOUTH -> { @@ -623,40 +658,31 @@ public void drawTile(Graphics2D g2d) { trans.translate(ox, oy); } } - - Logger.trace(tileOrientation.getOrientation() + " renderWidth: " + renderWidth + " renderHeight: " + renderHeight + " CP: (" + renderWidth / 2 + "," + renderHeight / 2 + ")"); - Logger.trace(tileOrientation.getOrientation() + " ox: " + ox + " oy: " + oy); - + + //Logger.trace(tileOrientation.getOrientation() + " renderWidth: " + renderWidth + " renderHeight: " + renderHeight + " CP: (" + renderWidth / 2 + "," + renderHeight / 2 + ")"); + //Logger.trace(tileOrientation.getOrientation() + " ox: " + ox + " oy: " + oy); g2di.setTransform(trans); - + renderTile(g2di); - + if (model.isShowRoute()) { renderTileRoute(g2di); } - + if (model.isShowCenter()) { drawCenterPoint(g2di); } // Scale the image back... if (model.isScaleImage()) { - tileImage = Scalr.resize(tileImage, Method.AUTOMATIC, Mode.FIT_EXACT, getWidth(), getHeight(), Scalr.OP_ANTIALIAS); + tileImage = Scalr.resize(bf, Method.AUTOMATIC, Mode.FIT_EXACT, getWidth(), getHeight(), Scalr.OP_ANTIALIAS); + } else { + tileImage = bf; } - - g2di.dispose(); -// int oxx, oyy; -// if (scaleImage) { -// oxx = offsetX; -// oyy = offsetY; -// } else { -// oxx = renderOffsetX; -// oyy = renderOffsetY; -// } - //g2d.drawImage(tileImage, (tileX - tileImage.getWidth() / 2) + oxx, (tileY - tileImage.getHeight() / 2) + oyy, null); + g2di.dispose(); } - + public BufferedImage getTileImage() { return tileImage; } @@ -668,19 +694,19 @@ public BufferedImage getTileImage() { */ public void drawName(Graphics2D g2) { } - + protected void drawCenterPoint(Graphics2D g2d) { drawCenterPoint(g2d, Color.magenta); } - + protected void drawCenterPoint(Graphics2D g2, Color color) { drawCenterPoint(g2, color, 60); } - + protected void drawCenterPoint(Graphics2D g2d, Color color, double size) { double dX = (renderWidth / 2 - size / 2); double dY = (renderHeight / 2 - size / 2); - + g2d.setColor(color); g2d.fill(new Ellipse2D.Double(dX, dY, size, size)); } @@ -716,27 +742,27 @@ protected Orientation rotate(boolean repaint) { } return tileOrientation; } - + public void flipHorizontal() { if (Orientation.NORTH.equals(getOrientation()) || Orientation.SOUTH.equals(getOrientation())) { rotate(false); rotate(true); } } - + public void flipVertical() { if (Orientation.EAST.equals(getOrientation()) || Orientation.WEST.equals(getOrientation())) { rotate(false); rotate(true); } } - + @Override public void move(int newX, int newY) { Point cs = LayoutUtil.snapToGrid(newX, newY); setCenter(cs); } - + protected static void drawRotate(Graphics2D g2d, double x, double y, int angle, String text) { g2d.translate((float) x, (float) y); g2d.rotate(Math.toRadians(angle)); @@ -744,55 +770,55 @@ protected static void drawRotate(Graphics2D g2d, double x, double y, int angle, g2d.rotate(-Math.toRadians(angle)); g2d.translate(-x, -y); } - + public static BufferedImage flipHorizontally(BufferedImage source) { BufferedImage output = new BufferedImage(source.getHeight(), source.getWidth(), source.getType()); - + AffineTransform flip = AffineTransform.getScaleInstance(1, -1); flip.translate(0, -source.getHeight()); AffineTransformOp op = new AffineTransformOp(flip, AffineTransformOp.TYPE_NEAREST_NEIGHBOR); - + op.filter(source, output); - + return output; } - + public static BufferedImage flipVertically(BufferedImage source) { BufferedImage output = new BufferedImage(source.getHeight(), source.getWidth(), source.getType()); - + AffineTransform flip = AffineTransform.getScaleInstance(-1, 1); flip.translate(-source.getWidth(), 0); AffineTransformOp op = new AffineTransformOp(flip, AffineTransformOp.TYPE_NEAREST_NEIGHBOR); - + op.filter(source, output); - + return output; } - + public Set getAltPoints() { return Collections.EMPTY_SET; } - + public final int getOffsetX() { return offsetX; } - + public void setOffsetX(int offsetX) { this.offsetX = offsetX; } - + public final int getOffsetY() { return offsetY; } - + public void setOffsetY(int offsetY) { this.offsetY = offsetY; } - + protected BufferedImage createImage() { return new BufferedImage(renderWidth, renderHeight, BufferedImage.TYPE_INT_RGB); } - + public int getCenterX() { if (tileX > 0) { return this.tileX; @@ -800,7 +826,7 @@ public int getCenterX() { return GRID; } } - + public int getCenterY() { if (tileY > 0) { return this.tileY; @@ -808,19 +834,19 @@ public int getCenterY() { return GRID; } } - + public boolean isDrawName() { return drawName; } - + public void setDrawName(boolean drawName) { this.drawName = drawName; } - + public boolean isScaleImage() { return model.isScaleImage(); } - + public void setScaleImage(boolean scaleImage) { Dimension d; if (scaleImage) { @@ -828,21 +854,21 @@ public void setScaleImage(boolean scaleImage) { } else { d = new Dimension(renderWidth, renderHeight); } - + setSize(d); setPreferredSize(d); - + model.setScaleImage(scaleImage); } - + public boolean isDrawCenterPoint() { return model.isShowCenter(); } - + public void setDrawCenterPoint(boolean drawCenterPoint) { model.setShowCenter(drawCenterPoint); } - + @Override public String toString() { return this.getClass().getSimpleName() @@ -856,158 +882,147 @@ public String toString() { + xyToString() + "}"; } - - @Override - public Rectangle getBounds() { - int w, h, cx, cy; - //TODO: Check this may by the componet does this already - if (this.getWidth() > 0 & this.getHeight() > 0) { - //if (this.width > 0 & this.height > 0) { - //w = this.width; - w = this.getPreferredSize().width; - //h = this.height; - h = this.getPreferredSize().height; - } else { - w = DEFAULT_WIDTH; - h = DEFAULT_HEIGHT; - } - - if (this.tileX > 0 && this.tileY > 0) { - cx = this.tileX + this.offsetX; - cy = this.tileY + this.offsetY; - } else { - cx = w / 2; - cy = h / 2; - } - - int ltx = cx - w / 2; - int lty = cy - h / 2; - return new Rectangle(ltx, lty, w, h); - } - - public Rectangle2D getBounds2D() { - return getBounds().getBounds2D(); - } - - public boolean contains(double x, double y) { - int w, h, cx, cy, tlx, tly; - if (this.getWidth() > 0 & this.getHeight() > 0) { - //if (this.width > 0 & this.height > 0) { -// w = this.width; -// h = this.height; - w = this.getPreferredSize().width; - h = this.getPreferredSize().height; - - } else { - w = DEFAULT_WIDTH; - h = DEFAULT_HEIGHT; - } - - if (this.getWidth() > 0 & this.getHeight() > 0) { - //if (this.width > 0 & this.height > 0) { - cx = this.tileX; - cy = this.tileY; - } else { - cx = w / 2; - cy = h / 2; - } - // top left dX and dY - tlx = cx - w / 2; - tly = cy - h / 2; +// @Override +// public Rectangle getBounds() { +// int w, h, cx, cy; +// //TODO: Check this may by the componet does this already +// if (this.getWidth() > 0 & this.getHeight() > 0) { +// //if (this.width > 0 & this.height > 0) { +// //w = this.width; +// w = this.getPreferredSize().width; +// //h = this.height; +// h = this.getPreferredSize().height; +// } else { +// w = DEFAULT_WIDTH; +// h = DEFAULT_HEIGHT; +// } +// +// if (this.tileX > 0 && this.tileY > 0) { +// cx = this.tileX + this.offsetX; +// cy = this.tileY + this.offsetY; +// } else { +// cx = w / 2; +// cy = h / 2; +// } +// +// int ltx = cx - w / 2; +// int lty = cy - h / 2; +// return new Rectangle(ltx, lty, w, h); +// } + +// public Rectangle2D getBounds2D() { +// return getBounds().getBounds2D(); +// } + +// public boolean contains(double x, double y) { +// int w, h, cx, cy, tlx, tly; +// if (this.getWidth() > 0 & this.getHeight() > 0) { +// //if (this.width > 0 & this.height > 0) { +//// w = this.width; +//// h = this.height; +// w = this.getPreferredSize().width; +// h = this.getPreferredSize().height; +// +// } else { +// w = DEFAULT_WIDTH; +// h = DEFAULT_HEIGHT; +// } +// +// if (this.getWidth() > 0 & this.getHeight() > 0) { +// //if (this.width > 0 & this.height > 0) { +// cx = this.tileX; +// cy = this.tileY; +// } else { +// cx = w / 2; +// cy = h / 2; +// } +// +// // top left dX and dY +// tlx = cx - w / 2; +// tly = cy - h / 2; +// +// // Check if X and Y range is ok +// return !(x < tlx || x > (tlx + w) || y < tly || y > (tly + h)); +// } - // Check if X and Y range is ok - return !(x < tlx || x > (tlx + w) || y < tly || y > (tly + h)); - } - public String xyToString() { return "(" + this.tileX + "," + this.tileY + ")"; } - - public boolean contains(Point2D p) { - return this.contains(p.getX(), p.getY()); - } - - public boolean intersects(double x, double y, double w, double h) { - return getBounds().intersects(x, y, w, h); - } - - public boolean intersects(Rectangle2D r2d) { - return getBounds().intersects(r2d); - } - - public boolean contains(double x, double y, double w, double h) { - return getBounds().contains(x, y, w, h); - } - - public boolean contains(Rectangle2D r2d) { - return getBounds().contains(r2d); - } - - public PathIterator getPathIterator(AffineTransform at) { - return getBounds().getPathIterator(at); - } - - public PathIterator getPathIterator(AffineTransform at, double flatness) { - return getBounds().getPathIterator(at, flatness); - } - - @Deprecated - public PropertyChangeListener getPropertyChangeListener() { - return this.propertyChangeListener; - } - - @Deprecated - public void setPropertyChangeListener(PropertyChangeListener propertyChangeListener) { - this.propertyChangeListener = propertyChangeListener; - } - - @Deprecated - public void repaintTile() { -// if (this.propertyChangeListener != null) { -// this.propertyChangeListener.propertyChange(new PropertyChangeEvent(this, "repaintTile", this, this)); -// } - } - - @Override - @Deprecated - public void onTileChange(TileEvent tileEvent) { - Logger.warn("Deprecated! " + tileEvent.getTileId()); - if (tileEvent.isEventFor(this)) { - boolean drawRoute = tileEvent.isShowRoute(); - setIncomingSide(tileEvent.getIncomingSide()); - - if (isJunction()) { - // setRouteValue(tileEvent.getRouteState()); - } - - if (tileEvent.getBlockBean() != null) { - this.setBlockBean(tileEvent.getBlockBean()); - } - - if (tileEvent.getTileBean() != null) { - TileBean other = tileEvent.getTileBean(); - this.copyInto(other); - } - - if (isBlock()) { - // ((Block) this).setRouteBlockState(tileEvent.getBlockState()); - if (!drawRoute) { - // ((Block) this).setRouteBlockState(null); - } - } - - setBackgroundColor(tileEvent.getBackgroundColor()); - setTrackColor(tileEvent.getTrackColor()); - setTrackRouteColor(tileEvent.getTrackRouteColor()); +// public boolean contains(Point2D p) { +// return this.contains(p.getX(), p.getY()); +// } + +// public boolean intersects(double x, double y, double w, double h) { +// return getBounds().intersects(x, y, w, h); +// } + +// public boolean intersects(Rectangle2D r2d) { +// return getBounds().intersects(r2d); +// } + +// public boolean contains(double x, double y, double w, double h) { +// return getBounds().contains(x, y, w, h); +// } + +// public boolean contains(Rectangle2D r2d) { +// return getBounds().contains(r2d); +// } + +// public PathIterator getPathIterator(AffineTransform at) { +// return getBounds().getPathIterator(at); +// } + +// public PathIterator getPathIterator(AffineTransform at, double flatness) { +// return getBounds().getPathIterator(at, flatness); +// } + +// @Deprecated +// public PropertyChangeListener getPropertyChangeListener() { +// return this.propertyChangeListener; +// } +// @Deprecated +// public void setPropertyChangeListener(PropertyChangeListener propertyChangeListener) { +// this.propertyChangeListener = propertyChangeListener; +// } + //@Override +// @Deprecated +// public void onTileChange(TileEvent tileEvent) { +// Logger.warn("Deprecated! " + tileEvent.getTileId()); +// if (tileEvent.isEventFor(this)) { +// boolean drawRoute = tileEvent.isShowRoute(); +// setIncomingSide(tileEvent.getIncomingSide()); +// +// if (isJunction()) { +// // setRouteValue(tileEvent.getRouteState()); +// } +// // if (tileEvent.getBlockBean() != null) { -// setBlockBean(tileEvent.getBlockBean()); +// this.setBlockBean(tileEvent.getBlockBean()); // } -// repaintTile(); - } - } - +// +// //if (tileEvent.getTileBean() != null) { +// // TileBean other = tileEvent.getTileBean(); +// // this.copyInto(other); +// //} +// if (isBlock()) { +// // ((Block) this).setRouteBlockState(tileEvent.getBlockState()); +// if (!drawRoute) { +// // ((Block) this).setRouteBlockState(null); +// } +// } +// +// setBackgroundColor(tileEvent.getBackgroundColor()); +// setTrackColor(tileEvent.getTrackColor()); +// setTrackRouteColor(tileEvent.getTrackRouteColor()); +// +//// if (tileEvent.getBlockBean() != null) { +//// setBlockBean(tileEvent.getBlockBean()); +//// } +//// repaintTile(); +// } +// } /** * The main route of the tile is horizontal * @@ -1025,15 +1040,15 @@ public boolean isHorizontal() { public boolean isVertical() { return (Orientation.NORTH == tileOrientation || Orientation.SOUTH == tileOrientation) && TileType.CURVED != tileType; } - + public boolean isJunction() { return TileType.SWITCH == tileType || TileType.CROSS == tileType; } - + public boolean isBlock() { return TileType.BLOCK == tileType; } - + public boolean isDirectional() { return TileType.STRAIGHT_DIR == tileType; } @@ -1046,52 +1061,52 @@ public boolean isDirectional() { public boolean isDiagonal() { return TileType.CURVED == tileType; } - + public boolean isCrossing() { return TileType.CROSSING == tileType; } - + public List getNeighbours() { return neighbours; } - + public void setNeighbours(List neighbours) { this.neighbours = neighbours; } - + public String getIdSuffix(Tile other) { return ""; } - + public Map getNeighborOrientations() { Map edgeOrientations = new HashMap<>(); - + Map neighborPoints = getNeighborPoints(); - + for (Orientation o : Orientation.values()) { edgeOrientations.put(neighborPoints.get(o), o); } return edgeOrientations; } - + public Map getEdgeOrientations() { Map edgeOrientations = new HashMap<>(); - + Map edgeConnections = getEdgePoints(); - + for (Orientation o : Orientation.values()) { edgeOrientations.put(edgeConnections.get(o), o); } return edgeOrientations; } - + public boolean isAdjacent(Tile other) { boolean adjacent = false; - + if (other != null) { Collection thisEdgePoints = getEdgePoints().values(); Collection otherEdgePoints = other.getEdgePoints().values(); - + for (Point p : thisEdgePoints) { adjacent = otherEdgePoints.contains(p); if (adjacent) { @@ -1099,7 +1114,7 @@ public boolean isAdjacent(Tile other) { } } } - + return adjacent; } @@ -1113,101 +1128,41 @@ public boolean isAdjacent(Tile other) { public boolean isArrowDirection(Tile other) { return true; } - + public AccessoryValue accessoryValueForRoute(Orientation from, Orientation to) { return AccessoryValue.OFF; } - - @Deprecated - protected StringBuilder getImageKeyBuilder() { - StringBuilder sb = new StringBuilder(); - //sb.append(id); - sb.append(this.tileType); - sb.append("~"); - sb.append(getOrientation().getOrientation()); - sb.append("~"); - sb.append(getDirection().getDirection()); - //sb.append("~"); - //sb.append(isDrawOutline() ? "y" : "n"); - sb.append("~"); - int r = backgroundColor.getRed(); - int g = backgroundColor.getGreen(); - int b = backgroundColor.getBlue(); - sb.append("#"); - sb.append(r); - sb.append("#"); - sb.append(g); - sb.append("#"); - sb.append(b); - sb.append("~"); - r = trackColor.getRed(); - g = trackColor.getGreen(); - b = trackColor.getBlue(); - sb.append("#"); - sb.append(r); - sb.append("#"); - sb.append(g); - sb.append("#"); - sb.append(b); - sb.append("~"); - sb.append(isDrawRoute() ? "y" : "n"); - if (isDrawRoute()) { - if (incomingSide != null) { - sb.append("~"); - sb.append(incomingSide.getOrientation()); - } - sb.append("~"); - r = trackRouteColor.getRed(); - g = trackRouteColor.getGreen(); - b = trackRouteColor.getBlue(); - sb.append("#"); - sb.append(r); - sb.append("#"); - sb.append(g); - sb.append("#"); - sb.append(b); - } - //sb.append("~"); - //Tile specific properties - //AccessoryValue - //SignalType - //SignalValue - //active; - //Logger.trace(sb); - return sb; - } - public abstract Map getNeighborPoints(); - + public abstract Map getEdgePoints(); - + public abstract Set getAllPoints(); - + public TileModel getModel() { return model; } - + public void setModel(TileModel newModel) { TileModel oldModel = getModel(); - + if (oldModel != null) { oldModel.removeChangeListener(changeListener); oldModel.removeActionListener(actionListener); changeListener = null; actionListener = null; } - + model = newModel; - + if (newModel != null) { changeListener = createChangeListener(); actionListener = createActionListener(); - + newModel.addChangeListener(changeListener); newModel.addActionListener(actionListener); } - + firePropertyChange(MODEL_CHANGED_PROPERTY, oldModel, newModel); if (newModel != oldModel) { revalidate(); @@ -1224,38 +1179,38 @@ public void setModel(TileModel newModel) { @Override public void updateUI() { } - + protected ChangeListener createChangeListener() { return getHandler(); } - + protected ActionListener createActionListener() { return getHandler(); } - + private Handler getHandler() { if (handler == null) { handler = new Handler(); } return handler; } - + class Handler implements ActionListener, ChangeListener, Serializable { - + @Override public void stateChanged(ChangeEvent e) { Object source = e.getSource(); - + fireStateChanged(); repaint(); } - + @Override public void actionPerformed(ActionEvent event) { fireActionPerformed(event); } } - + protected void fireStateChanged() { Object[] listeners = listenerList.getListenerList(); //reverse order @@ -1269,7 +1224,7 @@ protected void fireStateChanged() { } } } - + protected void fireActionPerformed(ActionEvent event) { Object[] listeners = listenerList.getListenerList(); ActionEvent e = null; @@ -1288,5 +1243,23 @@ protected void fireActionPerformed(ActionEvent event) { } } } - + + @Override + protected void paintComponent(Graphics g) { + long started = System.currentTimeMillis(); + super.paintComponent(g); + + setBounds(tileX - GRID, tileY - GRID, DEFAULT_WIDTH, DEFAULT_HEIGHT); + + Graphics2D g2 = (Graphics2D) g.create(); + //Graphics2D g2 = (Graphics2D) g.create(tileX - GRID, tileY - GRID, DEFAULT_WIDTH, DEFAULT_HEIGHT); + drawTile(g2); + g2.dispose(); + + g.drawImage(tileImage, 0, 0, null); + + long now = System.currentTimeMillis(); + Logger.trace(id + " Duration: " + (now - started) + " ms. Tile (" + tileX + "," + tileY + ")"); + } + } diff --git a/src/main/java/jcs/ui/layout/tiles/TileModel.java b/src/main/java/jcs/ui/layout/tiles/TileModel.java index 3d472126..46f144f3 100644 --- a/src/main/java/jcs/ui/layout/tiles/TileModel.java +++ b/src/main/java/jcs/ui/layout/tiles/TileModel.java @@ -87,6 +87,10 @@ public interface TileModel extends Serializable { public void setLocomotive(LocomotiveBean locomotive); + boolean isOverlayImage(); + + public void setOverlayImage(boolean overlayImage); + // void addChangeListener(ChangeListener l); diff --git a/src/test/java/jcs/ui/layout/tiles/BlockTileTester.java b/src/test/java/jcs/ui/layout/tiles/BlockTileTester.java index 7b7d4a8f..b06cde9a 100644 --- a/src/test/java/jcs/ui/layout/tiles/BlockTileTester.java +++ b/src/test/java/jcs/ui/layout/tiles/BlockTileTester.java @@ -57,9 +57,9 @@ public BlockTileTester(String title) { private void createTiles() { - blockEast = new Block(TileBean.Orientation.EAST, 200, 40); + blockEast = new Block(TileBean.Orientation.EAST, 220, 60); blockEast.setId("east"); - blockEast.setBlockState(blockStates.get(blockStateIndex)); + //blockEast.setBlockState(blockStates.get(blockStateIndex)); //blockEast.setBlockBean(createBlockBean(blockEast)); blockEast.setTrackRouteColor(Color.MAGENTA); @@ -81,9 +81,9 @@ private void createTiles() { dotGridCanvas.add(blockEast); - dotGridCanvas.add(blockSouth); - dotGridCanvas.add(blockWest); - dotGridCanvas.add(blockNorth); + //dotGridCanvas.add(blockSouth); + //dotGridCanvas.add(blockWest); + //dotGridCanvas.add(blockNorth); } private BlockBean createBlockBean(Tile tile) { diff --git a/src/test/java/jcs/ui/layout/tiles/DotGridCanvas.java b/src/test/java/jcs/ui/layout/tiles/DotGridCanvas.java index afb7d614..24b3f47b 100644 --- a/src/test/java/jcs/ui/layout/tiles/DotGridCanvas.java +++ b/src/test/java/jcs/ui/layout/tiles/DotGridCanvas.java @@ -28,6 +28,7 @@ public DotGridCanvas() { setLayout(null); setOpaque(true); setDoubleBuffered(false); + setBackground(Color.white); } @Override diff --git a/src/test/java/jcs/ui/layout/tiles/UnscaledBlockCanvas.java b/src/test/java/jcs/ui/layout/tiles/UnscaledBlockCanvas.java index 308362f5..b4efac2a 100644 --- a/src/test/java/jcs/ui/layout/tiles/UnscaledBlockCanvas.java +++ b/src/test/java/jcs/ui/layout/tiles/UnscaledBlockCanvas.java @@ -25,7 +25,6 @@ public class UnscaledBlockCanvas extends JPanel { //implements PropertyChangeListener { private boolean expanded; - private int paintCount = 0; public UnscaledBlockCanvas() { setLayout(null); @@ -36,13 +35,10 @@ public UnscaledBlockCanvas() { @Override public void paint(Graphics g) { long started = System.currentTimeMillis(); - paintCount++; //Rectangle r = g.getClipBounds(); //Logger.trace("Rx: " + r.x + " Ry: " + r.y + " Rw: " + r.width + " Rh: " + r.height); - if (paintCount > 2) { - super.paint(g); - } + super.paint(g); paintGrid(g); long now = System.currentTimeMillis(); diff --git a/src/test/java/jcs/ui/layout/tiles/UnscaledBlockTester.java b/src/test/java/jcs/ui/layout/tiles/UnscaledBlockTester.java index 46d8ce54..6c0ecff4 100644 --- a/src/test/java/jcs/ui/layout/tiles/UnscaledBlockTester.java +++ b/src/test/java/jcs/ui/layout/tiles/UnscaledBlockTester.java @@ -22,6 +22,7 @@ import javax.swing.DefaultComboBoxModel; import javax.swing.ImageIcon; import javax.swing.JFrame; +import javax.swing.JLabel; import javax.swing.UIManager; import javax.swing.UnsupportedLookAndFeelException; import jcs.entities.BlockBean; @@ -48,6 +49,17 @@ public UnscaledBlockTester() { blockTile = createBlock(); canvas.add(blockTile); + //String imgPath = System.getProperty("user.home") + File.separator + "jcs" + File.separator + "images" + File.separator + "DHG 6505.png"; + //ImageIcon locIcon = new ImageIcon(getClass().getResource("/images/DHG 6505.png")); + //Image locImage = new BufferedImage(locIcon.getIconWidth(), locIcon.getIconHeight(), BufferedImage.TYPE_INT_RGB); + + //String imgPath = System.getProperty("user.home") + File.separator + "jcs" + File.separator + "images" + File.separator + "DHG 6505.png"; + //Image locImage = ImageUtil.readImage(imgPath); + + //locImage = ImageUtil.scaleImage(locImage, 100); + //JLabel c = new JLabel(new ImageIcon(locImage)); + + //canvas.add(c); centerSP.getViewport().validate(); pack(); @@ -79,17 +91,18 @@ private ComboBoxModel createStateComboBoxModel() { private LocomotiveBean createLocomotiveBean() { LocomotiveBean lb = new LocomotiveBean(8L, "NS DHG 6505", 8L, 8, "", "dcc", 100, 0, 0, 1, true, true); - String imgPath = System.getProperty("user.home") + File.separator + "jcs" + File.separator + "images" + File.separator + "DHG 6505.png"; + String imgPath = getClass().getResource("/images/DHG 6505.png").getFile().replaceAll("%20"," "); lb.setIcon(imgPath); - ImageIcon locIcon = new ImageIcon(getClass().getResource("/images/DHG 6505.png")); - Image locImage = new BufferedImage(locIcon.getIconWidth(), locIcon.getIconHeight(), BufferedImage.TYPE_INT_RGB); + Image locImage = ImageUtil.readImage(imgPath); locImage = ImageUtil.scaleImage(locImage, 100); lb.setLocIcon(locImage); - if (this.backwardsRB.isSelected()) { + if (backwardsRB.isSelected()) { lb.setDirection(LocomotiveBean.Direction.BACKWARDS); + this.blockTile.setLogicalDirection(LocomotiveBean.Direction.BACKWARDS); } else { lb.setDirection(LocomotiveBean.Direction.FORWARDS); + this.blockTile.setLogicalDirection(LocomotiveBean.Direction.FORWARDS); } return lb; @@ -290,7 +303,7 @@ private void rotateButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN- }//GEN-LAST:event_rotateButtonActionPerformed private void showLocCBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_showLocCBActionPerformed - if (this.showLocCB.isSelected()) { + if (showLocCB.isSelected()) { blockTile.setLocomotive(createLocomotiveBean()); } else { blockTile.setLocomotive(null); @@ -302,10 +315,12 @@ private void orientationCBActionPerformed(java.awt.event.ActionEvent evt) {//GEN }//GEN-LAST:event_orientationCBActionPerformed private void departureSideCBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_departureSideCBActionPerformed - if ("".equals(departureSideCB.getSelectedItem())) { - blockTile.setDepartureSuffix(null); - } else { - blockTile.setDepartureSuffix(departureSideCB.getSelectedItem().toString()); + if (blockTile != null) { + if ("".equals(departureSideCB.getSelectedItem())) { + blockTile.setDepartureSuffix(null); + } else { + blockTile.setDepartureSuffix(departureSideCB.getSelectedItem().toString()); + } } }//GEN-LAST:event_departureSideCBActionPerformed @@ -317,10 +332,6 @@ private void showCenterCBActionPerformed(java.awt.event.ActionEvent evt) {//GEN- blockTile.setDrawCenterPoint(this.showCenterCB.isSelected()); }//GEN-LAST:event_showCenterCBActionPerformed -// private String getDepartureSuffix() { -// return this.blockTile.getDepartureSuffix(); -// } - private void reverseArrivalCBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_reverseArrivalCBActionPerformed blockTile.setReverseArrival(reverseArrivalCB.isSelected()); }//GEN-LAST:event_reverseArrivalCBActionPerformed @@ -403,15 +414,6 @@ public static void main(String args[]) { }); } -// @Override -// public void propertyChange(PropertyChangeEvent evt) { -// if ("repaintTile".equals(evt.getPropertyName())) { -// Tile t = (Tile) evt.getNewValue(); -// Logger.trace("Tile: " + t); -// this.repaint(); -// } -// } - // Variables declaration - do not modify//GEN-BEGIN:variables private javax.swing.JRadioButton backwardsRB; private jcs.ui.layout.tiles.UnscaledBlockCanvas canvas; From 4bab1471c66aac8e4d04f43182bb7255172ee360 Mon Sep 17 00:00:00 2001 From: Frans Jacobs Date: Sat, 25 Jan 2025 22:31:08 +0100 Subject: [PATCH 06/24] Slowly restoring the Edit functionality, but now a lot faster --- src/main/java/jcs/ui/layout/LayoutCanvas.java | 563 ++++-------------- src/main/java/jcs/ui/layout/LayoutPanel.java | 6 +- src/main/java/jcs/ui/layout/TileCache.java | 117 ++-- src/main/java/jcs/ui/layout/tiles/Block.java | 42 +- src/main/java/jcs/ui/layout/tiles/Tile.java | 49 +- .../jcs/ui/layout/tiles/BlockTileTester.java | 14 +- 6 files changed, 211 insertions(+), 580 deletions(-) diff --git a/src/main/java/jcs/ui/layout/LayoutCanvas.java b/src/main/java/jcs/ui/layout/LayoutCanvas.java index 67f95120..d822940a 100755 --- a/src/main/java/jcs/ui/layout/LayoutCanvas.java +++ b/src/main/java/jcs/ui/layout/LayoutCanvas.java @@ -29,14 +29,11 @@ import java.awt.event.MouseEvent; import java.awt.event.MouseMotionAdapter; import java.awt.image.BufferedImage; -import java.beans.PropertyChangeEvent; -import java.beans.PropertyChangeListener; import java.util.HashSet; import java.util.List; import java.util.Set; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; -import javax.swing.DebugGraphics; import javax.swing.JFrame; import javax.swing.JMenuItem; import javax.swing.JPanel; @@ -54,6 +51,7 @@ import jcs.entities.TileBean; import jcs.entities.TileBean.Direction; import jcs.entities.TileBean.Orientation; +import jcs.entities.TileBean.TileType; import static jcs.entities.TileBean.TileType.BLOCK; import static jcs.entities.TileBean.TileType.CROSS; import static jcs.entities.TileBean.TileType.CURVED; @@ -100,16 +98,13 @@ public enum Mode { private Orientation orientation; private Direction direction; - private TileBean.TileType tileType; + private TileType tileType; private Point mouseLocation = new Point(); - private BufferedImage grid; - + //private BufferedImage grid; private final ExecutorService executor; -// private final Map tiles; -// private final Map altTiles; private final Set selectedTiles; private Tile selectedTile; @@ -125,6 +120,7 @@ public LayoutCanvas() { } public LayoutCanvas(boolean readonly) { + super(); setLayout(null); setOpaque(true); setDoubleBuffered(true); @@ -155,20 +151,14 @@ private void postInit() { @Override public void paint(Graphics g) { long started = System.currentTimeMillis(); - - //for (Tile tile : TileCache.tiles.values()) { - // tile.setSelected(selectedTiles.contains(tile.getCenter())); - //} - - //paintNullGrid(g); super.paint(g); if (drawGrid) { - //if (lineGrid) { - // paintLineGrid(g); - //} else { - paintDotGrid(g); - //} + if (lineGrid) { + paintLineGrid(g); + } else { + paintDotGrid(g); + } } long now = System.currentTimeMillis(); @@ -226,75 +216,23 @@ protected void paintComponent(Graphics g) { } //@Override - public void propertyChange(PropertyChangeEvent evt) { - if ("repaintTile".equals(evt.getPropertyName())) { - Tile tile = (Tile) evt.getNewValue(); - - Logger.trace("Repainting Tile: " + tile.getId()); -// repaint(tile.getBounds()); - } - } - - private void paintNullGrid(Graphics g) { - if (this.grid != null) { - int pw = this.getWidth(); - int ph = this.getHeight(); - int gw = grid.getWidth(); - int gh = grid.getHeight(); - - if (pw != gw || ph != gh) { - this.grid = null; - } - } - - if (this.grid == null) { - int width = getSize().width; - int height = getSize().height; - grid = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB); - Graphics2D gc = grid.createGraphics(); - - gc.setBackground(Color.white); - gc.clearRect(0, 0, width, height); - - gc.setPaint(Color.black); - - gc.dispose(); - } - Graphics2D g2 = (Graphics2D) g; - //Draw grid from pre computed image - g2.drawImage(grid, null, 0, 0); - } - - private void paintDotGrid(Graphics g) { - int width = this.getWidth(); - int height = this.getHeight(); - - int xOffset = 0; - int yOffset = 0; - - //Logger.trace("W: " + width + " H: " + height + " X: " + this.getX() + " Y: " + this.getY()); - Graphics2D gc = (Graphics2D) g; - Paint p = gc.getPaint(); - gc.setPaint(Color.black); - - for (int r = 0; r < width; r++) { - for (int c = 0; c < height; c++) { - gc.drawOval((r * 20 * 2) + xOffset - 2, (c * 20 * 2) + yOffset - 2, 4, 4); - } - } - gc.setPaint(p); - +// public void propertyChange(PropertyChangeEvent evt) { +// if ("repaintTile".equals(evt.getPropertyName())) { +// Tile tile = (Tile) evt.getNewValue(); +// +// Logger.trace("Repainting Tile: " + tile.getId()); +//// repaint(tile.getBounds()); +// } +// } +// private void paintNullGrid(Graphics g) { // if (this.grid != null) { // int pw = this.getWidth(); // int ph = this.getHeight(); -// // int gw = grid.getWidth(); // int gh = grid.getHeight(); // // if (pw != gw || ph != gh) { -// //Logger.trace("Changed Canvas: " + pw + " x " + ph + " Grid: " + gw + " x " + gh); // this.grid = null; -// } else { // } // } // @@ -309,51 +247,45 @@ private void paintDotGrid(Graphics g) { // // gc.setPaint(Color.black); // -// for (int r = 0; r < width; r++) { -// for (int c = 0; c < height; c++) { -// gc.drawOval(r * Tile.GRID * 2, c * Tile.GRID * 2, 1, 1); -// } -// } // gc.dispose(); // } // Graphics2D g2 = (Graphics2D) g; +// //Draw grid from pre computed image // g2.drawImage(grid, null, 0, 0); - } - - private void paintLineGrid(Graphics g) { - if (this.grid != null) { - int pw = this.getWidth(); - int ph = this.getHeight(); - - int gw = grid.getWidth(); - int gh = grid.getHeight(); +// } + private void paintDotGrid(Graphics g) { + int width = getWidth(); + int height = getHeight(); + Graphics2D gc = (Graphics2D) g; + Paint p = gc.getPaint(); + gc.setPaint(Color.black); - if (pw != gw || ph != gh) { - this.grid = null; + int xOffset = 0; + int yOffset = 0; + for (int r = 0; r < width; r++) { + for (int c = 0; c < height; c++) { + gc.drawOval((r * 20 * 2) + xOffset - 2, (c * 20 * 2) + yOffset - 2, 4, 4); } } + gc.setPaint(p); + } - if (this.grid == null) { - int width = getSize().width; - int height = getSize().height; - grid = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB); - Graphics2D gc = grid.createGraphics(); - - gc.setBackground(Color.white); - gc.clearRect(0, 0, width, height); - gc.setPaint(Color.lightGray); + private void paintLineGrid(Graphics g) { + int width = getWidth(); + int height = getHeight(); + Graphics2D gc = (Graphics2D) g; + Paint p = gc.getPaint(); + gc.setPaint(Color.black); + gc.setPaint(Color.lightGray); - gc.setStroke(new BasicStroke(1, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND)); - for (int x = 0; x < width; x += 40) { - gc.drawLine(x, 0, x, height); - } - for (int y = 0; y < height; y += 40) { - gc.drawLine(0, y, width, y); - } - gc.dispose(); + gc.setStroke(new BasicStroke(1, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND)); + for (int x = 0; x < width; x += 40) { + gc.drawLine(x, 0, x, height); + } + for (int y = 0; y < height; y += 40) { + gc.drawLine(0, y, width, y); } - Graphics2D g2 = (Graphics2D) g; - g2.drawImage(grid, null, 0, 0); + gc.setPaint(p); } void setMode(LayoutCanvas.Mode mode) { @@ -391,84 +323,19 @@ void loadLayoutInBackground() { } private void loadTiles() { - boolean showValues = Mode.CONTROL.equals(mode); + //boolean showValues = Mode.CONTROL.equals(mode); TileCache.loadTiles(); - TileCache.setShowValues(showValues); - //TileCache.setDrawOutline(drawGrid); - TileCache.setDrawCenterPoint(!this.readonly); -// List tileBeans = PersistenceFactory.getService().getTileBeans(); selectedTiles.clear(); -// altTiles.clear(); -// tiles.clear(); -// selectedRouteElements.clear(); - -// for (TileBean tb : tileBeans) { -// Tile tile = TileFactory.createTile(tb, drawGrid, showValues); -// tile.setPropertyChangeListener(this); -// tiles.put(tile.getCenter(), tile); -// -// //Alternative point(s) to be able to find all points -// if (!tile.getAltPoints().isEmpty()) { -// Set alt = tile.getAltPoints(); -// for (Point ap : alt) { -// altTiles.put(ap, tile); -// } -// } -// } -// Logger.debug("Loaded " + tiles.size() + " Tiles..."); for (Tile tile : TileCache.tiles.values()) { this.add(tile); + tile.setDrawCenterPoint(!readonly); + tile.setBounds(tile.getTileBounds()); } repaint(); } - void saveLayout() { - //Create a snapshot as persisting is done in worker thread -// Set snapshot = new HashSet<>(tiles.values()); - this.selectedTiles.clear(); -// this.executor.execute(() -> saveTiles(snapshot)); - - this.executor.execute(() -> TileCache.saveTiles()); - } - -// private synchronized void saveTiles(Set snapshot) { -// TileCache.saveTiles(); -// -// Logger.debug("Saving " + snapshot.size() + " tiles..."); -// List beans = new LinkedList<>(); -// -// for (Tile tile : snapshot) { -// if (tile != null) { -// TileBean tb = tile.getTileBean(); -// Logger.trace("Saving " + tile + " -> " + tb); -// beans.add(tb); -// } else { -// Logger.warn("Tile is null?"); -// } -// } -// PersistenceFactory.getService().persist(beans); -// } - private void saveTile(final Tile tile) { -// if (tile != null) { -// TileBean tb = tile.getTileBean(); -// this.executor.execute(() -> PersistenceFactory.getService().persist(tb)); - this.executor.execute(() -> TileCache.saveTile(tile)); -// } else { -// Logger.warn("Tile is null?"); -// } - } - -// private void deleteTile(final Tile tile) { -// if (tile != null) { -// TileBean tb = tile.getTileBean(); - //this.executor.execute(() -> PersistenceFactory.getService().remove(tb)); -// this.executor.execute(() -> TileCache.deleteTile(tile)); -// } else { -// Logger.warn("Tile is null?"); -// } -// } private void mouseMoveAction(MouseEvent evt) { Point sp = LayoutUtil.snapToGrid(evt.getPoint()); Tile tile = TileCache.findTile(sp); @@ -497,19 +364,20 @@ private void mousePressedAction(MouseEvent evt) { Point snapPoint = LayoutUtil.snapToGrid(evt.getPoint()); //Clear any previous selection - for(Point p : selectedTiles) { - if(TileCache.containsPoint(p)) { + for (Point p : selectedTiles) { + if (TileCache.containsPoint(p)) { Tile st = TileCache.findTile(p); st.setSelected(false); - } + } } - + selectedTiles.clear(); Tile tile = TileCache.findTile(snapPoint); - + if (tile != null) { selectedTiles.addAll(tile.getAllPoints()); tile.setSelected(true); + selectedTile = tile; } switch (mode) { @@ -518,8 +386,6 @@ private void mousePressedAction(MouseEvent evt) { if (evt.getButton() == MouseEvent.BUTTON1) { executeControlActionForTile(tile, snapPoint); } else { - Logger.trace("Show menuitems for tile " + tile); - this.selectedTile = tile; if (tile.isBlock()) { showBlockPopupMenu(tile, snapPoint); } @@ -530,16 +396,10 @@ private void mousePressedAction(MouseEvent evt) { if (MouseEvent.BUTTON1 == evt.getButton() && tile == null) { //Only add a new tile when there is no tile on the selected snapPoint Logger.trace("Adding a new tile: " + tileType + " @ (" + snapPoint.x + ", " + snapPoint.y + ")"); - - Tile addedTile = addTile(snapPoint); + Tile addedTile = addTile(snapPoint, tileType, orientation, direction, true, !readonly); if (addedTile != null) { selectedTiles.addAll(addedTile.getAllPoints()); - - //if ("false".equals(System.getProperty("batch.tile.persist", "true"))) { - //this.saveTile(tile); - this.add(addedTile); - repaint(); - //} + repaint(addedTile.getTileBounds()); } } else { if (tile != null) { @@ -551,31 +411,59 @@ private void mousePressedAction(MouseEvent evt) { if (MouseEvent.BUTTON3 == evt.getButton() && tile != null) { showOperationsPopupMenu(tile, snapPoint); } - } case DELETE -> { - //removeTiles(selectedTiles); - //TileCache.removeTiles(selectedTiles); - Tile t = (Tile) this.getComponentAt(snapPoint); - if (t != null) { - this.remove(t); - TileCache.deleteTile(t); + Tile toBeDeleted = (Tile) getComponentAt(snapPoint); + if (toBeDeleted != null) { + removeTile(toBeDeleted); + selectedTiles.clear(); + repaint(toBeDeleted.getTileBounds()); + selectedTile = null; } - - this.selectedTiles.clear(); - repaint(); } default -> { Logger.trace((tile != null ? "Selected tile: " + tile.getId() + ", " + tile.xyToString() : "No tile selected")); - if (tile == null) { - this.selectedTiles.clear(); - } + //if (tile == null) { + // this.selectedTiles.clear(); + //} if (MouseEvent.BUTTON3 == evt.getButton()) { showOperationsPopupMenu(tile, snapPoint); } } } + + } + + private Tile addTile(Point p, TileType tileType, Orientation orientation, Direction direction, boolean selected, boolean showCenter) { + Logger.trace("Adding: " + tileType + " @ " + p + " O: " + orientation + " D: " + direction); + Point chkp = TileCache.checkAvailable(p, orientation); + + Tile tile = TileFactory.createTile(tileType, orientation, direction, chkp, drawGrid); + tile.setSelected(selected); + tile.setDrawCenterPoint(showCenter); + + //Can the tile be placed, keeping in mind the extra points + boolean canBeAdded = !TileCache.checkTileOccupation(tile); + + if (canBeAdded) { + add(tile); + tile.setBounds(tile.getTileBounds()); + + TileCache.addTile(tile); + return tile; + } else { + return null; + } + } + + void removeTile(Tile tile) { + Tile toBeDeleted = (Tile) getComponentAt(tile.getCenter()); + if (toBeDeleted != null) { + Logger.trace("Deleting Tile " + tile.getId()); + remove(toBeDeleted); + TileCache.deleteTile(tile); + } } private void mouseDragAction(MouseEvent evt) { @@ -591,23 +479,6 @@ private void mouseDragAction(MouseEvent evt) { repaint(); } -// private boolean checkTileOccupation(Tile tile) { -// Set tilePoints = tile.getAllPoints(); -// for (Point p : tilePoints) { -// if (tiles.containsKey(p) || altTiles.containsKey(p)) { -// //The is a match, check if it is an other tile -// Tile mt = this.findTile(p); -// if (tile.getId().equals(mt.getId())) { -// //same tile continue -// } else { -// //Other tile so really occupied -// return true; -// } -// } -// } -// return false; -// return TileCache.checkTileOccupation(tile); -// } private void mouseReleasedAction(MouseEvent evt) { Tile selTile = getSelectedTile(); if (selTile != null) { @@ -859,7 +730,7 @@ private void showOperationsPopupMenu(Tile tile, Point p) { @SuppressWarnings("UnusedAssignment") boolean showDelete = false; - TileBean.TileType tt = tile.getTileType(); + TileType tt = tile.getTileType(); switch (tt) { case SENSOR -> { showProperties = true; @@ -913,225 +784,28 @@ private void showOperationsPopupMenu(Tile tile, Point p) { this.operationsPM.show(this, p.x, p.y); } -// public Tile findTile(Point cp) { -// Tile result = this.tiles.get(cp); -// if (result == null) { -// //Logger.trace("Using alternative points..."); -// result = this.altTiles.get(cp); -// if (result != null) { -// //Logger.trace("Found " + result + " in alt tiles"); -// } -// } -// return result; -// } -// private Point getCheckAvailable(Point newPoint) { -// if (this.tiles.containsKey(newPoint)) { -// Tile et = this.tiles.get(newPoint); -// Logger.debug("@ " + newPoint + " is allready occcupied by: " + et + "..."); -// //Search for the nearest avalaible free point -// //first get the Center point of the tile which is occuping this slot -// // show warning! -// Point ecp = et.getCenter(); -// -// int w = et.getWidth(); -// int h = et.getHeight(); -// -// Point np; -// np = switch (this.orientation) { -// case EAST -> -// new Point(ecp.x + w, ecp.y); -// case WEST -> -// new Point(newPoint.x - w, ecp.y); -// case SOUTH -> -// new Point(ecp.x, newPoint.y + h); -// default -> -// new Point(ecp.x, newPoint.y - h); -// }; -// -// Logger.trace("Alternative CP: " + np); -// // recursive check -// return getCheckAvailable(np); -// } else { -// Logger.debug("@ " + newPoint + " is not yet used..."); -// -// return newPoint; -// } -// } - private Tile addTile(Point p) { - if (this.orientation == null) { - this.orientation = Orientation.EAST; - } - - if (this.direction == null) { - this.direction = Direction.RIGHT; - } - - Logger.trace("Adding: " + tileType + " @ " + p); - Point chkp = TileCache.checkAvailable(p, this.orientation); - boolean fullRepaint = !chkp.equals(p); - - Tile tile = TileFactory.createTile(tileType, orientation, direction, chkp, drawGrid); - - //Can the tile be placed, keeping in mind the extra points - boolean canBeAdded = !TileCache.checkTileOccupation(tile); - - if (canBeAdded) { - TileCache.addTile(tile); - - Logger.trace("Added Tile " + tile.getClass().getSimpleName() + " " + tile.getOrientation() + " @ " + tile.getCenter() + " Full repaint: " + fullRepaint); - } - - if (fullRepaint) { - this.repaint(); - } - - if (canBeAdded) { - return tile; - } else { - return null; - } - } - - void removeTiles() { - TileCache.removeTiles(selectedTiles); - //removeTiles(selectedTiles); - repaint(); - } -// private void removeTiles(Set pointsToRemove) { -// TileCache.removeTiles(pointsToRemove); -// for (Point p : pointsToRemove) { -// Tile removed = TileCache.tiles.remove(p); -// -// if ("false".equals(System.getProperty("batch.tile.persist", "true"))) { -// this.deleteTile(removed); -// } -// -// if (removed != null && removed.getAllPoints() != null) { -// Set rps = removed.getAltPoints(); -// //Also remove alt points -// for (Point ap : rps) { -// tiles.remove(ap); -// } -// -// Logger.trace("Removed: " + removed); -// } -// } -// selectedTiles.clear(); -// repaint(); -// } - private JFrame getParentFrame() { JFrame frame = (JFrame) SwingUtilities.getRoot(this); return frame; } public void rotateSelectedTile() { - Logger.trace("Selected Tiles " + selectedTiles.size()); - TileCache.rotateTile(selectedTiles); - -// //make copy as the map could be cleared -// Set snapshot = new HashSet<>(selectedTiles); -// -// for (Point p : snapshot) { -// Logger.trace("Selected Tile @ " + p); -// if (this.tiles.containsKey(p)) { -// Tile t = this.tiles.get(p); -// //Remove the alternative or extra points... -// for (Point ep : t.getAltPoints()) { -// this.altTiles.remove(ep); -// } -// -// t.rotate(); -// Logger.trace("Rotated " + t); -// this.orientation = t.getOrientation(); -// this.direction = t.getDirection(); -// -// //override -// this.tiles.put(p, t); -// for (Point ep : t.getAltPoints()) { -// this.altTiles.put(ep, t); -// } -// -// this.selectedTiles.clear(); -// this.selectedTiles.addAll(t.getAllPoints()); -// -// if ("false".equals(System.getProperty("batch.tile.persist", "true"))) { -// this.saveTile(t); -// } -// } -// } - repaint(); + Logger.trace("Selected Tile " + selectedTile.getId()); + selectedTile = TileCache.rotateTile(selectedTile); + selectedTile.setBounds(selectedTile.getTileBounds()); + selectedTile.repaint(); } public void flipSelectedTileHorizontal() { - TileCache.flipHorizontal(selectedTiles); -// Set snapshot = new HashSet<>(selectedTiles); -// for (Point p : snapshot) { -// Logger.trace("Selected Tile @ " + p); -// if (this.tiles.containsKey(p)) { -// Tile t = this.tiles.get(p); -// //Remove the alternative or extra points... -// for (Point ep : t.getAltPoints()) { -// this.altTiles.remove(ep); -// } -// -// t.flipHorizontal(); -// Logger.trace("Flipped " + t); -// this.orientation = t.getOrientation(); -// this.direction = t.getDirection(); -// -// //override -// this.tiles.put(p, t); -// for (Point ep : t.getAltPoints()) { -// this.altTiles.put(ep, t); -// } -// -// if ("false".equals(System.getProperty("batch.tile.persist", "true"))) { -// this.saveTile(t); -// } -// -// this.selectedTiles.clear(); -// this.selectedTiles.addAll(t.getAllPoints()); -// } -// } -// this.executor.execute(() -> repaint()); - repaint(); + selectedTile = TileCache.flipHorizontal(selectedTile); + selectedTile.setBounds(selectedTile.getTileBounds()); + selectedTile.repaint(); } public void flipSelectedTileVertical() { - TileCache.flipVertical(selectedTiles); - -// Set snapshot = new HashSet<>(selectedTiles); -// for (Point p : snapshot) { -// Logger.trace("Selected Tile @ " + p); -// if (this.tiles.containsKey(p)) { -// Tile t = this.tiles.get(p); -// //Remove the alternative or extra points... -// for (Point ep : t.getAltPoints()) { -// this.altTiles.remove(ep); -// } -// -// t.flipVertical(); -// Logger.trace("Flipped " + t); -// this.orientation = t.getOrientation(); -// this.direction = t.getDirection(); -// -// //override -// this.tiles.put(p, t); -// for (Point ep : t.getAltPoints()) { -// this.altTiles.put(ep, t); -// } -// -// if ("false".equals(System.getProperty("batch.tile.persist", "true"))) { -// this.saveTile(t); -// } -// -// this.selectedTiles.clear(); -// this.selectedTiles.addAll(t.getAllPoints()); -// } -// } -// this.executor.execute(() -> repaint()); - repaint(); + selectedTile = TileCache.flipVertical(selectedTile); + selectedTile.setBounds(selectedTile.getTileBounds()); + selectedTile.repaint(); } void routeLayout() { @@ -1380,7 +1054,7 @@ private void horizontalMIActionPerformed(ActionEvent evt) {//GEN-FIRST:event_hor Logger.trace(this.orientation + ", " + evt.getModifiers() + ", " + evt.paramString()); if (this.mouseLocation != null && evt.getModifiers() == ActionEvent.MOUSE_EVENT_MASK) { - addTile(this.mouseLocation); + //addTile(this.mouseLocation); this.mouseLocation = null; } }//GEN-LAST:event_horizontalMIActionPerformed @@ -1389,7 +1063,7 @@ private void verticalMIActionPerformed(ActionEvent evt) {//GEN-FIRST:event_verti Logger.trace(this.orientation + ", " + evt.getModifiers() + ", " + evt.paramString()); if (this.mouseLocation != null && evt.getModifiers() == ActionEvent.MOUSE_EVENT_MASK) { - addTile(this.mouseLocation); + //addTile(this.mouseLocation); this.mouseLocation = null; } }//GEN-LAST:event_verticalMIActionPerformed @@ -1398,7 +1072,7 @@ private void rightMIActionPerformed(ActionEvent evt) {//GEN-FIRST:event_rightMIA Logger.trace(this.orientation + ", " + evt.getModifiers() + ", " + evt.paramString()); if (this.mouseLocation != null && evt.getModifiers() == ActionEvent.MOUSE_EVENT_MASK) { - addTile(this.mouseLocation); + //addTile(this.mouseLocation); this.mouseLocation = null; } }//GEN-LAST:event_rightMIActionPerformed @@ -1407,7 +1081,7 @@ private void leftMIActionPerformed(ActionEvent evt) {//GEN-FIRST:event_leftMIAct Logger.trace(this.orientation + ", " + evt.getModifiers() + ", " + evt.paramString()); if (this.mouseLocation != null && evt.getModifiers() == ActionEvent.MOUSE_EVENT_MASK) { - addTile(this.mouseLocation); + //addTile(this.mouseLocation); this.mouseLocation = null; } }//GEN-LAST:event_leftMIActionPerformed @@ -1433,9 +1107,12 @@ private void moveMIActionPerformed(ActionEvent evt) {//GEN-FIRST:event_moveMIAct }//GEN-LAST:event_moveMIActionPerformed private void deleteMIActionPerformed(ActionEvent evt) {//GEN-FIRST:event_deleteMIActionPerformed - //this.removeTiles(selectedTiles); - TileCache.removeTiles(selectedTiles); - this.selectedTiles.clear(); + if (selectedTile != null) { + removeTile(selectedTile); + selectedTiles.clear(); + repaint(selectedTile.getTileBounds()); + selectedTile = null; + } }//GEN-LAST:event_deleteMIActionPerformed private void propertiesMIActionPerformed(ActionEvent evt) {//GEN-FIRST:event_propertiesMIActionPerformed diff --git a/src/main/java/jcs/ui/layout/LayoutPanel.java b/src/main/java/jcs/ui/layout/LayoutPanel.java index 8a942a81..909a4fd1 100755 --- a/src/main/java/jcs/ui/layout/LayoutPanel.java +++ b/src/main/java/jcs/ui/layout/LayoutPanel.java @@ -874,7 +874,7 @@ private void moveMIActionPerformed(ActionEvent evt) {//GEN-FIRST:event_moveMIAct }//GEN-LAST:event_moveMIActionPerformed private void deleteMIActionPerformed(ActionEvent evt) {//GEN-FIRST:event_deleteMIActionPerformed - this.canvas.removeTiles(); + //this.canvas.removeTiles(); }//GEN-LAST:event_deleteMIActionPerformed private void propertiesMIActionPerformed(ActionEvent evt) {//GEN-FIRST:event_propertiesMIActionPerformed @@ -882,7 +882,7 @@ private void propertiesMIActionPerformed(ActionEvent evt) {//GEN-FIRST:event_pro }//GEN-LAST:event_propertiesMIActionPerformed private void saveBtnActionPerformed(ActionEvent evt) {//GEN-FIRST:event_saveBtnActionPerformed - this.canvas.saveLayout(); + //this.canvas.saveLayout(); }//GEN-LAST:event_saveBtnActionPerformed private void loadBtnActionPerformed(ActionEvent evt) {//GEN-FIRST:event_loadBtnActionPerformed @@ -899,7 +899,7 @@ private void addBtnActionPerformed(ActionEvent evt) {//GEN-FIRST:event_addBtnAct private void deleteBtnActionPerformed(ActionEvent evt) {//GEN-FIRST:event_deleteBtnActionPerformed setMode(LayoutCanvas.Mode.DELETE); - this.canvas.removeTiles(); + //this.canvas.removeTiles(); }//GEN-LAST:event_deleteBtnActionPerformed private void repaintBtnActionPerformed(ActionEvent evt) {//GEN-FIRST:event_repaintBtnActionPerformed diff --git a/src/main/java/jcs/ui/layout/TileCache.java b/src/main/java/jcs/ui/layout/TileCache.java index 566d9605..7299e2c4 100644 --- a/src/main/java/jcs/ui/layout/TileCache.java +++ b/src/main/java/jcs/ui/layout/TileCache.java @@ -45,7 +45,6 @@ public class TileCache { private static final Map tileEventListeners = new HashMap<>(); - private static boolean drawOutline; private static boolean drawCenterPoint; private static boolean showValues; @@ -55,13 +54,6 @@ public class TileCache { private TileCache() { } -// static void setDrawOutline(boolean drawOutline) { -// TileCache.drawOutline = drawOutline; -// -// for (Tile tile : tiles.values()) { -// tile.setDrawOutline(drawOutline); -// } -// } static void setDrawCenterPoint(boolean drawCenterPoint) { TileCache.drawCenterPoint = drawCenterPoint; @@ -146,7 +138,6 @@ static void addTile(Tile tile) { tiles.put(tile.getCenter(), tile); //addTileEventListener((TileEventListener) tile); - //Alternative point(s) to be able to find all points if (!tile.getAltPoints().isEmpty()) { Set alt = tile.getAltPoints(); @@ -159,28 +150,22 @@ static void addTile(Tile tile) { Logger.trace("Added " + tile + " There are now " + TileCache.tiles.size() + " tiles..."); } - static void removeTiles(Set pointsToRemove) { - for (Point p : pointsToRemove) { - Tile removed = tiles.remove(p); - removeTileEventListener(removed); - - deleteTile(removed); - - if (removed != null && removed.getAllPoints() != null) { - Set rps = removed.getAltPoints(); + static void deleteTile(final Tile tile) { + if (tile != null) { + if (tiles.containsKey(tile.getCenter())) { + tiles.remove(tile.getCenter()); + Set rps = tile.getAltPoints(); //Also remove alt points for (Point ap : rps) { altTiles.remove(ap); } + TileBean tb = tile.getTileBean(); + PersistenceFactory.getService().remove(tb); + Logger.trace("Deleted " + tile.getId()); + } else { + Logger.warn("Tile " + tile.getId() + " not found in cache"); } - } - } - - static void deleteTile(final Tile tile) { - if (tile != null) { - TileBean tb = tile.getTileBean(); - PersistenceFactory.getService().remove(tb); } else { Logger.warn("Tile is null?"); } @@ -266,61 +251,59 @@ static Point checkAvailable(Point newPoint, Orientation orientation) { } } - static void rotateTile(Set centerPoints) { - for (Point p : centerPoints) { - if (tiles.containsKey(p)) { - Tile t = tiles.get(p); - //Remove the alternative or extra points... - for (Point ep : t.getAltPoints()) { - altTiles.remove(ep); - } + static Tile rotateTile(Tile tile) { + if (!tiles.containsKey(tile.getCenter())) { + Logger.warn("Tile " + tile.getId() + " NOT in cache!"); + } - t.rotate(); + //Remove the alternative or extra points... + for (Point ep : tile.getAltPoints()) { + altTiles.remove(ep); + } - //update - tiles.put(p, t); - for (Point ep : t.getAltPoints()) { - altTiles.put(ep, t); - } + tile.rotate(); - saveTile(t); - } + //update + tiles.put(tile.getCenter(), tile); + for (Point ep : tile.getAltPoints()) { + altTiles.put(ep, tile); } + + saveTile(tile); + return tile; } - public static void flipHorizontal(Set points) { - flipTile(points, true); + static Tile flipHorizontal(Tile tile) { + return flipTile(tile, true); } - public static void flipVertical(Set points) { - flipTile(points, false); + public static Tile flipVertical(Tile tile) { + return flipTile(tile, false); } - private static void flipTile(Set points, boolean horizontal) { - for (Point p : points) { - if (tiles.containsKey(p)) { - Tile t = tiles.get(p); - //Remove the alternative or extra points... - for (Point ep : t.getAltPoints()) { - altTiles.remove(ep); - } + private static Tile flipTile(Tile tile, boolean horizontal) { + if (!tiles.containsKey(tile.getCenter())) { + Logger.warn("Tile " + tile.getId() + " NOT in cache!"); + } - if (horizontal) { - t.flipHorizontal(); - } else { - t.flipVertical(); - } - //Update - tiles.put(p, t); - for (Point ep : t.getAltPoints()) { - altTiles.put(ep, t); - } + //Remove the alternative or extra points... + for (Point ep : tile.getAltPoints()) { + altTiles.remove(ep); + } - if ("false".equals(System.getProperty("batch.tile.persist", "true"))) { - saveTile(t); - } - } + if (horizontal) { + tile.flipHorizontal(); + } else { + tile.flipVertical(); } + //update + tiles.put(tile.getCenter(), tile); + for (Point ep : tile.getAltPoints()) { + altTiles.put(ep, tile); + } + + saveTile(tile); + return tile; } static void moveTile(Point snapPoint, Tile tile) { diff --git a/src/main/java/jcs/ui/layout/tiles/Block.java b/src/main/java/jcs/ui/layout/tiles/Block.java index d150243c..abf288dc 100755 --- a/src/main/java/jcs/ui/layout/tiles/Block.java +++ b/src/main/java/jcs/ui/layout/tiles/Block.java @@ -23,6 +23,7 @@ import java.awt.Graphics2D; import java.awt.Image; import java.awt.Point; +import java.awt.Rectangle; import java.awt.geom.Ellipse2D; import java.awt.image.BufferedImage; import java.util.HashMap; @@ -41,6 +42,7 @@ import jcs.entities.TileBean.TileType; import static jcs.ui.layout.tiles.Tile.DEFAULT_HEIGHT; import static jcs.ui.layout.tiles.Tile.DEFAULT_WIDTH; +import static jcs.ui.layout.tiles.Tile.GRID; import static jcs.ui.layout.tiles.Tile.RENDER_HEIGHT; import static jcs.ui.layout.tiles.Tile.RENDER_WIDTH; import jcs.ui.util.ImageUtil; @@ -286,7 +288,8 @@ public String getIdSuffix(Tile other) { @Override public Orientation rotate() { - rotate(false); + super.rotate(); + int w = tileWidth(tileOrientation, TileType.BLOCK); int h = tileHeight(tileOrientation, TileType.BLOCK); @@ -295,7 +298,9 @@ public Orientation rotate() { setSize(d); changeRenderSize(); - repaint(); + setBounds(getTileBounds()); + + repaint(getTileBounds()); return tileOrientation; } @@ -705,11 +710,8 @@ public void drawName(Graphics2D g2d) { } @Override - protected void paintComponent(Graphics g) { - long started = System.currentTimeMillis(); - super.paintComponent(g); - - int multiplier = 1; //(model.isScaleImage() ? 1 : 10); + public Rectangle getTileBounds() { + int multiplier = (model.isScaleImage() ? 1 : 10); int xx, yy; if (tileOrientation == Orientation.EAST || tileOrientation == Orientation.WEST) { xx = tileX - GRID * multiplier - GRID * multiplier * 2; @@ -719,21 +721,16 @@ protected void paintComponent(Graphics g) { yy = tileY - GRID * multiplier - GRID * multiplier * 2; } - //if (model.isScaleImage()) { - setBounds(xx, yy, tileWidth(tileOrientation, TileType.BLOCK), tileHeight(tileOrientation, TileType.BLOCK)); - //setBounds(tileX - 60, tileY - 20, tileWidth(tileOrientation, TileType.BLOCK), tileHeight(tileOrientation, TileType.BLOCK)); - //} else { - //setBounds(xx, yy, renderWidth, renderHeight); - //} - - - //setBounds(tileX - GRID, tileY - GRID, DEFAULT_WIDTH, DEFAULT_HEIGHT); - - //Graphics2D g2 = (Graphics2D) g.create(); - //Graphics2D g2 = (Graphics2D) g.create(tileX - GRID, tileY - GRID, DEFAULT_WIDTH, DEFAULT_HEIGHT); - + if (model.isScaleImage()) { + return new Rectangle(xx, yy, tileWidth(tileOrientation, TileType.BLOCK), tileHeight(tileOrientation, TileType.BLOCK)); + } else { + return new Rectangle(xx, yy, renderWidth, renderHeight); + } + } - //Logger.trace(id + ": " + tileOrientation + " W: " + getWidth() + " H: " + getHeight() + " tX: " + tileX + ", tY: " + tileY + " xx: " + xx + " yy: " + yy + " Scale factor: " + multiplier); + @Override + protected void paintComponent(Graphics g) { + long started = System.currentTimeMillis(); Graphics2D g2 = (Graphics2D) g.create(); drawTile(g2); @@ -744,9 +741,6 @@ protected void paintComponent(Graphics g) { } g.drawImage(tileImage, 0, 0, null); - - //new Exception().printStackTrace() ; - long now = System.currentTimeMillis(); Logger.trace(id + " Duration: " + (now - started) + " ms."); } diff --git a/src/main/java/jcs/ui/layout/tiles/Tile.java b/src/main/java/jcs/ui/layout/tiles/Tile.java index ae8f39f1..dfaf4512 100755 --- a/src/main/java/jcs/ui/layout/tiles/Tile.java +++ b/src/main/java/jcs/ui/layout/tiles/Tile.java @@ -20,12 +20,11 @@ import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.Point; +import java.awt.Rectangle; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.geom.AffineTransform; import java.awt.geom.Ellipse2D; -import java.awt.geom.PathIterator; -import java.awt.geom.Rectangle2D; import java.awt.image.AffineTransformOp; import java.awt.image.BufferedImage; import java.beans.PropertyChangeListener; @@ -344,8 +343,8 @@ public Orientation getOrientation() { public void setOrientation(Orientation orientation) { this.tileOrientation = orientation; - if (this.tileBean != null) { - this.tileBean.setOrientation(orientation); + if (tileBean != null) { + tileBean.setOrientation(orientation); } } @@ -714,19 +713,9 @@ protected void drawCenterPoint(Graphics2D g2d, Color color, double size) { /** * Rotate the tile clockwise 90 deg * - * @return + * @return the new Orientation */ public Orientation rotate() { - return rotate(true); - } - - /** - * Rotate the tile clockwise 90 deg - * - * @param repaint - * @return - */ - protected Orientation rotate(boolean repaint) { switch (tileOrientation) { case EAST -> setOrientation(Orientation.SOUTH); @@ -737,23 +726,20 @@ protected Orientation rotate(boolean repaint) { default -> setOrientation(Orientation.EAST); } - if (repaint) { - repaint(); - } return tileOrientation; } public void flipHorizontal() { - if (Orientation.NORTH.equals(getOrientation()) || Orientation.SOUTH.equals(getOrientation())) { - rotate(false); - rotate(true); + if (Orientation.NORTH == tileOrientation || Orientation.SOUTH == tileOrientation) { + rotate(); + rotate(); } } public void flipVertical() { if (Orientation.EAST.equals(getOrientation()) || Orientation.WEST.equals(getOrientation())) { - rotate(false); - rotate(true); + rotate(); + rotate(); } } @@ -910,11 +896,9 @@ public String toString() { // int lty = cy - h / 2; // return new Rectangle(ltx, lty, w, h); // } - // public Rectangle2D getBounds2D() { // return getBounds().getBounds2D(); // } - // public boolean contains(double x, double y) { // int w, h, cx, cy, tlx, tly; // if (this.getWidth() > 0 & this.getHeight() > 0) { @@ -945,7 +929,6 @@ public String toString() { // // Check if X and Y range is ok // return !(x < tlx || x > (tlx + w) || y < tly || y > (tly + h)); // } - public String xyToString() { return "(" + this.tileX + "," + this.tileY + ")"; } @@ -953,31 +936,24 @@ public String xyToString() { // public boolean contains(Point2D p) { // return this.contains(p.getX(), p.getY()); // } - // public boolean intersects(double x, double y, double w, double h) { // return getBounds().intersects(x, y, w, h); // } - // public boolean intersects(Rectangle2D r2d) { // return getBounds().intersects(r2d); // } - // public boolean contains(double x, double y, double w, double h) { // return getBounds().contains(x, y, w, h); // } - // public boolean contains(Rectangle2D r2d) { // return getBounds().contains(r2d); // } - // public PathIterator getPathIterator(AffineTransform at) { // return getBounds().getPathIterator(at); // } - // public PathIterator getPathIterator(AffineTransform at, double flatness) { // return getBounds().getPathIterator(at, flatness); // } - // @Deprecated // public PropertyChangeListener getPropertyChangeListener() { // return this.propertyChangeListener; @@ -1244,12 +1220,13 @@ protected void fireActionPerformed(ActionEvent event) { } } + public Rectangle getTileBounds() { + return new Rectangle(tileX - GRID, tileY - GRID, DEFAULT_WIDTH, DEFAULT_HEIGHT); + } + @Override protected void paintComponent(Graphics g) { long started = System.currentTimeMillis(); - super.paintComponent(g); - - setBounds(tileX - GRID, tileY - GRID, DEFAULT_WIDTH, DEFAULT_HEIGHT); Graphics2D g2 = (Graphics2D) g.create(); //Graphics2D g2 = (Graphics2D) g.create(tileX - GRID, tileY - GRID, DEFAULT_WIDTH, DEFAULT_HEIGHT); diff --git a/src/test/java/jcs/ui/layout/tiles/BlockTileTester.java b/src/test/java/jcs/ui/layout/tiles/BlockTileTester.java index b06cde9a..d50b4f9f 100644 --- a/src/test/java/jcs/ui/layout/tiles/BlockTileTester.java +++ b/src/test/java/jcs/ui/layout/tiles/BlockTileTester.java @@ -59,8 +59,8 @@ private void createTiles() { blockEast = new Block(TileBean.Orientation.EAST, 220, 60); blockEast.setId("east"); - //blockEast.setBlockState(blockStates.get(blockStateIndex)); - //blockEast.setBlockBean(createBlockBean(blockEast)); + blockEast.setBlockState(blockStates.get(blockStateIndex)); + blockEast.setBlockBean(createBlockBean(blockEast)); blockEast.setTrackRouteColor(Color.MAGENTA); blockSouth = new Block(TileBean.Orientation.SOUTH, 360, 80); @@ -69,21 +69,21 @@ private void createTiles() { blockSouth.setTrackRouteColor(Color.YELLOW); - blockWest = new Block(TileBean.Orientation.WEST, 200, 120); + blockWest = new Block(TileBean.Orientation.WEST, 180, 140); blockWest.setId("west"); blockSouth.setBlockState(blockStates.get(blockStateIndex+1)); blockWest.setTrackRouteColor(Color.CYAN); - blockNorth = new Block(TileBean.Orientation.NORTH, 40, 80); + blockNorth = new Block(TileBean.Orientation.NORTH, 60, 100); blockNorth.setId("north"); blockSouth.setBlockState(blockStates.get(blockStateIndex+1)); blockNorth.setTrackRouteColor(Color.blue); dotGridCanvas.add(blockEast); - //dotGridCanvas.add(blockSouth); - //dotGridCanvas.add(blockWest); - //dotGridCanvas.add(blockNorth); + dotGridCanvas.add(blockSouth); + dotGridCanvas.add(blockWest); + dotGridCanvas.add(blockNorth); } private BlockBean createBlockBean(Tile tile) { From cbcf078fe4de26a193cbf1e4672cb430df09d6f7 Mon Sep 17 00:00:00 2001 From: Frans Jacobs Date: Sun, 26 Jan 2025 15:36:06 +0100 Subject: [PATCH 07/24] Cross Tile working again --- src/main/java/jcs/ui/layout/LayoutCanvas.java | 117 ++---- src/main/java/jcs/ui/layout/TileCache.java | 18 +- src/main/java/jcs/ui/layout/tiles/Cross.java | 231 +++++++----- .../java/jcs/ui/layout/tiles/Straight.java | 2 - src/main/java/jcs/ui/layout/tiles/Switch.java | 25 +- src/main/java/jcs/ui/layout/tiles/Tile.java | 170 ++------- .../jcs/ui/layout/tiles/CrossTileTester.form | 208 +++++++++++ .../jcs/ui/layout/tiles/CrossTileTester.java | 333 ++++++++++++++---- .../jcs/ui/layout/tiles/DotGridCanvas.java | 40 ++- .../ui/layout/tiles/StraightTileTester.java | 1 - .../ui/layout/tiles/UnscaledBlockCanvas.java | 173 +-------- .../ui/layout/tiles/UnscaledTileFrame.java | 8 +- 12 files changed, 742 insertions(+), 584 deletions(-) create mode 100644 src/test/java/jcs/ui/layout/tiles/CrossTileTester.form diff --git a/src/main/java/jcs/ui/layout/LayoutCanvas.java b/src/main/java/jcs/ui/layout/LayoutCanvas.java index d822940a..6ac0884d 100755 --- a/src/main/java/jcs/ui/layout/LayoutCanvas.java +++ b/src/main/java/jcs/ui/layout/LayoutCanvas.java @@ -17,6 +17,7 @@ import java.awt.BasicStroke; import java.awt.Color; +import java.awt.Component; import java.awt.Cursor; import java.awt.Dimension; import java.awt.Graphics; @@ -165,94 +166,34 @@ public void paint(Graphics g) { Logger.trace("Duration: " + (now - started) + " ms."); } +// @Override +// protected void paintComponent(Graphics g) { +// long started = System.currentTimeMillis(); +// super.paintComponent(g); +// long now = System.currentTimeMillis(); +// Logger.trace("Duration: " + (now - started) + " ms."); +// } + @Override - protected void paintComponent(Graphics g) { - long started = System.currentTimeMillis(); - super.paintComponent(g); - -// Graphics2D g2 = (Graphics2D) g.create(); -// Set snapshot = new HashSet<>(TileCache.tiles.values()); -// -// if (this.drawGrid) { -// if (lineGrid) { -// paintLineGrid(g); -// } else { -// paintDotGrid(g); -// } -// } else { -// paintNullGrid(g); -// } -// -// for (Tile tile : snapshot) { -// //for (Tile tile : TileCache.tiles.values()) { -// //tile.setDrawOutline(drawGrid); -// -// if (Mode.CONTROL != mode) { -// if (selectedTiles.contains(tile.getCenter())) { -// //tile.setBackgroundColor(Color.yellow); -// tile.setBackgroundColor(Color.orange); -// } else { -// tile.setBackgroundColor(Color.white); -// } -// } -// -// //tile.drawTile(g2); -// //debug -//// if (!this.readonly) { -//// tile.drawCenterPoint(g2, Color.magenta, 3); -//// } -// } -// if (this.movingTileCenterPoint != null && this.movingTileImage != null) { -// int x = movingTileCenterPoint.x; -// int y = movingTileCenterPoint.y; -// int w = movingTileImage.getWidth(); -// int h = movingTileImage.getHeight(); -// g2.drawImage(movingTileImage, (x - w / 2), (y - h / 2), null); -// } -// -// g2.dispose(); - long now = System.currentTimeMillis(); - Logger.trace("Duration: " + (now - started) + " ms."); + public Component add(Component component) { + super.add(component); + if (component instanceof Tile tile) { + tile.setBounds(tile.getTileBounds()); + } + return component; + } + + @Override + public Component add(String name, Component component) { + if (component instanceof Tile tile) { + super.add(tile.getId(), tile); + tile.setBounds(tile.getTileBounds()); + } else { + super.add(component); + } + return component; } - //@Override -// public void propertyChange(PropertyChangeEvent evt) { -// if ("repaintTile".equals(evt.getPropertyName())) { -// Tile tile = (Tile) evt.getNewValue(); -// -// Logger.trace("Repainting Tile: " + tile.getId()); -//// repaint(tile.getBounds()); -// } -// } -// private void paintNullGrid(Graphics g) { -// if (this.grid != null) { -// int pw = this.getWidth(); -// int ph = this.getHeight(); -// int gw = grid.getWidth(); -// int gh = grid.getHeight(); -// -// if (pw != gw || ph != gh) { -// this.grid = null; -// } -// } -// -// if (this.grid == null) { -// int width = getSize().width; -// int height = getSize().height; -// grid = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB); -// Graphics2D gc = grid.createGraphics(); -// -// gc.setBackground(Color.white); -// gc.clearRect(0, 0, width, height); -// -// gc.setPaint(Color.black); -// -// gc.dispose(); -// } -// Graphics2D g2 = (Graphics2D) g; -// //Draw grid from pre computed image -// g2.drawImage(grid, null, 0, 0); -// } private void paintDotGrid(Graphics g) { int width = getWidth(); int height = getHeight(); @@ -330,7 +271,7 @@ private void loadTiles() { for (Tile tile : TileCache.tiles.values()) { this.add(tile); tile.setDrawCenterPoint(!readonly); - tile.setBounds(tile.getTileBounds()); + //tile.setBounds(tile.getTileBounds()); } repaint(); @@ -448,9 +389,9 @@ private Tile addTile(Point p, TileType tileType, Orientation orientation, Direct if (canBeAdded) { add(tile); - tile.setBounds(tile.getTileBounds()); + //tile.setBounds(tile.getTileBounds()); - TileCache.addTile(tile); + TileCache.addAndSaveTile(tile); return tile; } else { return null; diff --git a/src/main/java/jcs/ui/layout/TileCache.java b/src/main/java/jcs/ui/layout/TileCache.java index 7299e2c4..361bb354 100644 --- a/src/main/java/jcs/ui/layout/TileCache.java +++ b/src/main/java/jcs/ui/layout/TileCache.java @@ -17,7 +17,6 @@ import jcs.ui.layout.tiles.*; import java.awt.Point; -import java.beans.PropertyChangeListener; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -49,6 +48,7 @@ public class TileCache { private static boolean showValues; static final Map tiles = new HashMap<>(); + static final Map points = new HashMap<>(); static final Map altTiles = new HashMap<>(); private TileCache() { @@ -116,8 +116,9 @@ static void loadTiles() { Tile tile = TileFactory.createTile(tb, showValues); //tile.setPropertyChangeListener(listener); tiles.put(tile.getCenter(), tile); - //addTileEventListener((TileEventListener) tile); + points.put(tile.getId(), tile.getCenter()); + //addTileEventListener((TileEventListener) tile); //Alternative point(s) to be able to find all points if (!tile.getAltPoints().isEmpty()) { Set alt = tile.getAltPoints(); @@ -134,8 +135,9 @@ static List getTiles() { return tiles.values().stream().collect(Collectors.toList()); } - static void addTile(Tile tile) { + static void addAndSaveTile(Tile tile) { tiles.put(tile.getCenter(), tile); + points.put(tile.getId(), tile.getCenter()); //addTileEventListener((TileEventListener) tile); //Alternative point(s) to be able to find all points @@ -154,6 +156,7 @@ static void deleteTile(final Tile tile) { if (tile != null) { if (tiles.containsKey(tile.getCenter())) { tiles.remove(tile.getCenter()); + points.remove(tile.getId()); Set rps = tile.getAltPoints(); //Also remove alt points for (Point ap : rps) { @@ -196,6 +199,15 @@ public static Tile findTile(Point cp) { return result; } + public static Tile findTile(String id) { + Point p = points.get(id); + if (p != null) { + return findTile(p); + } else { + return null; + } + } + static boolean checkTileOccupation(Tile tile) { Set tilePoints = tile.getAllPoints(); for (Point p : tilePoints) { diff --git a/src/main/java/jcs/ui/layout/tiles/Cross.java b/src/main/java/jcs/ui/layout/tiles/Cross.java index 170114d6..3df8e88b 100644 --- a/src/main/java/jcs/ui/layout/tiles/Cross.java +++ b/src/main/java/jcs/ui/layout/tiles/Cross.java @@ -19,6 +19,8 @@ import java.awt.Color; import java.awt.Graphics2D; import java.awt.Point; +import java.awt.Rectangle; +import java.awt.geom.Ellipse2D; import java.util.HashMap; import java.util.HashSet; import java.util.Map; @@ -36,6 +38,9 @@ import static jcs.ui.layout.tiles.Tile.DEFAULT_HEIGHT; import static jcs.ui.layout.tiles.Tile.DEFAULT_WIDTH; import static jcs.ui.layout.tiles.Tile.GRID; +import static jcs.ui.layout.tiles.Tile.tileHeight; +import static jcs.ui.layout.tiles.Tile.tileWidth; +import org.tinylog.Logger; public class Cross extends Switch { @@ -50,68 +55,106 @@ public class Cross extends Switch { public static final Color LIGHT_GREEN = new Color(0, 255, 51); public static final Color DARK_GREEN = new Color(0, 153, 0); - private static int crossWidth(Orientation orientation) { - if (Orientation.EAST == orientation || Orientation.WEST == orientation) { - return DEFAULT_WIDTH * 2; - } else { - return DEFAULT_WIDTH; - } + public Cross(Orientation orientation, Direction direction, Point center) { + this(orientation, direction, center.x, center.y); } - private static int crossHeight(Orientation orientation) { - if (Orientation.EAST == orientation || Orientation.WEST == orientation) { - return DEFAULT_HEIGHT; - } else { - return DEFAULT_HEIGHT * 2; - } + public Cross(Orientation orientation, Direction direction, int x, int y) { + this(orientation, direction, x, y, tileWidth(orientation, TileType.CROSS), tileHeight(orientation, TileType.CROSS)); } - public Cross(TileBean tileBean) { - super(tileBean, crossWidth(tileBean.getOrientation()), crossHeight(tileBean.getOrientation())); - setWidthHeightAndOffsets(); + public Cross(Orientation orientation, Direction direction, int x, int y, int width, int height) { + super(TileType.CROSS, orientation, direction, x, y, width, height); + changeRenderSizeAndOffsets(); } - public Cross(Orientation orientation, Direction direction, Point center) { - this(orientation, direction, center.x, center.y); + public Cross(TileBean tileBean) { + super(tileBean, tileWidth(tileBean.getOrientation(), TileType.CROSS), tileHeight(tileBean.getOrientation(), TileType.CROSS)); + changeRenderSizeAndOffsets(); } - public Cross(Orientation orientation, Direction direction, int x, int y) { - this(orientation, direction, x, y, crossWidth(orientation), crossHeight(orientation)); - } + private void changeRenderSizeAndOffsets() { + //Reset offsets + this.offsetY = 0; + this.renderOffsetY = 0; + this.offsetX = 0; + this.renderOffsetX = 0; - public Cross(Orientation orientation, Direction direction, int x, int y, int width, int height) { - super(orientation, direction, x, y, width, height); - this.tileType = TileType.CROSS; - setWidthHeightAndOffsets(); + if (isHorizontal()) { + //this.width = DEFAULT_WIDTH * 2; + //this.height = DEFAULT_HEIGHT; + this.renderWidth = RENDER_GRID * 4; + this.renderHeight = RENDER_GRID * 2; + + this.offsetY = 0; + this.renderOffsetY = 0; + } else { + //this.width = DEFAULT_WIDTH; + //this.height = DEFAULT_HEIGHT * 2; + this.renderWidth = RENDER_GRID * 2; + this.renderHeight = RENDER_GRID * 4; + + this.offsetX = 0; + this.renderOffsetX = 0; + } + + //Due to the asymetical shape (center is on the left) + //the offset has to be changed with the rotation + switch (getOrientation()) { + case SOUTH -> { + this.offsetY = +GRID; + this.renderOffsetY = RENDER_GRID; + } + case WEST -> { + this.offsetX = -GRID; + this.renderOffsetX = -RENDER_GRID; + } + case NORTH -> { + this.offsetY = -GRID; + this.renderOffsetY = -RENDER_GRID; + } + default -> { + //East so default + this.offsetX = +GRID; + this.renderOffsetX = +RENDER_GRID; + } + } } +// private void changeRenderSize() { +// if (Orientation.EAST == tileOrientation || Orientation.WEST == tileOrientation) { +// this.renderWidth = RENDER_WIDTH * 2; +// this.renderHeight = RENDER_HEIGHT; +// } else { +// this.renderWidth = RENDER_WIDTH; +// this.renderHeight = RENDER_HEIGHT * 2; +// } +// } /** - * A Cross has a width in horizontal position of 2 tiles and a height of 1 tile in Vertical position a width of 1 tile and a height of 2 tiles. + * A Cross has a width in horizontal position of 2 tiles and a height of 1 tile in Vertical position.
* * @return the set of center point which mark the position of the Cross */ @Override public Set getAltPoints() { - int xx = this.tileX; - int yy = this.tileY; Set alternatives = new HashSet<>(); switch (getOrientation()) { case SOUTH -> { - Point sp = new Point(xx, (yy + DEFAULT_HEIGHT)); + Point sp = new Point(tileX, (tileY + DEFAULT_HEIGHT)); alternatives.add(sp); } case WEST -> { - Point wp = new Point((xx - DEFAULT_WIDTH), yy); + Point wp = new Point((tileX - DEFAULT_WIDTH), tileY); alternatives.add(wp); } case NORTH -> { - Point np = new Point(xx, (yy - DEFAULT_HEIGHT)); + Point np = new Point(tileX, (tileY - DEFAULT_HEIGHT)); alternatives.add(np); } default -> { //East so default - Point ep = new Point((tileX + DEFAULT_WIDTH), yy); + Point ep = new Point((tileX + DEFAULT_WIDTH), tileY); alternatives.add(ep); } } @@ -242,60 +285,6 @@ public Map getEdgePoints() { return edgeConnections; } -// @Override -// public void rotate() { -// super.rotate(); -// setWidthHeightAndOffsets(); -// } - - final void setWidthHeightAndOffsets() { - //Reset offsets - this.offsetY = 0; - this.renderOffsetY = 0; - this.offsetX = 0; - this.renderOffsetX = 0; - - if (isHorizontal()) { - //this.width = DEFAULT_WIDTH * 2; - //this.height = DEFAULT_HEIGHT; - this.renderWidth = RENDER_GRID * 4; - this.renderHeight = RENDER_GRID * 2; - - this.offsetY = 0; - this.renderOffsetY = 0; - } else { - //this.width = DEFAULT_WIDTH; - //this.height = DEFAULT_HEIGHT * 2; - this.renderWidth = RENDER_GRID * 2; - this.renderHeight = RENDER_GRID * 4; - - this.offsetX = 0; - this.renderOffsetX = 0; - } - - //Due to the asymetical shape (center is on the left) - //the offset has to be changed with the rotation - switch (getOrientation()) { - case SOUTH -> { - this.offsetY = +GRID; - this.renderOffsetY = RENDER_GRID; - } - case WEST -> { - this.offsetX = -GRID; - this.renderOffsetX = -RENDER_GRID; - } - case NORTH -> { - this.offsetY = -GRID; - this.renderOffsetY = -RENDER_GRID; - } - default -> { - //East so default - this.offsetX = +GRID; - this.renderOffsetX = +RENDER_GRID; - } - } - } - @Override protected void renderStraight(Graphics2D g2, Color color) { int xx, yy, w, h; @@ -589,4 +578,76 @@ public AccessoryValue accessoryValueForRoute(Orientation from, Orientation to) { return AccessoryValue.OFF; } } + + @Override + protected void drawCenterPoint(Graphics2D g2d, Color color, double size) { + //A Cross has 1 alternate point + //1st square holds the centerpoint + //2nd square + double dX1, dX2, dY1, dY2; + switch (tileOrientation) { + case SOUTH -> { + dX1 = renderWidth / 2 - size / 2; + dY1 = renderHeight / 2 - renderHeight / 4 - size / 2; + dX2 = renderWidth / 2 + renderWidth - size / 4; + dY2 = renderHeight / 2 - renderHeight / 4 - size / 4; + } + case WEST -> { + dX1 = renderWidth / 2 - renderWidth / 4 - size / 2; + dY1 = renderHeight / 2 - size / 2; + dX2 = renderWidth / 2 + renderWidth / 4 - size / 4; + dY2 = renderHeight / 2 - size / 4; + } + case NORTH -> { + dX1 = renderWidth / 2 - size / 2; + dY1 = renderHeight / 2 - renderHeight / 4 - size / 2; + dX2 = renderWidth / 2 + renderWidth - size / 4; + dY2 = renderHeight / 2 - renderHeight / 4 - size / 4; + } + default -> { + //East + dX1 = renderWidth / 2 - renderWidth / 4 - size / 2; + dY1 = renderHeight / 2 - size / 2; + dX2 = renderWidth / 2 + renderWidth / 4 - size / 4; + dY2 = renderHeight / 2 - size / 4; + } + } + + g2d.setColor(color); + g2d.fill(new Ellipse2D.Double(dX1, dY1, size, size)); + g2d.fill(new Ellipse2D.Double(dX2, dY2, size / 2, size / 2)); + } + + @Override + public Rectangle getTileBounds() { + int multiplier = (model.isScaleImage() ? 1 : 10); + int xx, yy; + //Centerpoint is inbalanced + switch (tileOrientation) { + case SOUTH -> { + xx = tileX - GRID * multiplier; + yy = tileY - GRID * multiplier; + } + case WEST -> { + xx = tileX - GRID * multiplier - GRID * 2 * multiplier; + yy = tileY - GRID * multiplier; + } + case NORTH -> { + xx = tileX - GRID * multiplier; + yy = tileY - GRID * multiplier - GRID * 2 * multiplier; + } + default -> { + //East + xx = tileX - GRID * multiplier; + yy = tileY - GRID * multiplier; + } + } + + if (model.isScaleImage()) { + return new Rectangle(xx, yy, tileWidth(tileOrientation, TileType.CROSS), tileHeight(tileOrientation, TileType.CROSS)); + } else { + return new Rectangle(xx, yy, renderWidth, renderHeight); + } + } + } diff --git a/src/main/java/jcs/ui/layout/tiles/Straight.java b/src/main/java/jcs/ui/layout/tiles/Straight.java index 8a45ba69..96685548 100755 --- a/src/main/java/jcs/ui/layout/tiles/Straight.java +++ b/src/main/java/jcs/ui/layout/tiles/Straight.java @@ -16,7 +16,6 @@ package jcs.ui.layout.tiles; import java.awt.BasicStroke; -import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.Point; import java.util.HashMap; @@ -26,7 +25,6 @@ import jcs.entities.TileBean; import jcs.entities.TileBean.Orientation; import jcs.entities.TileBean.TileType; -import org.tinylog.Logger; public class Straight extends Tile { diff --git a/src/main/java/jcs/ui/layout/tiles/Switch.java b/src/main/java/jcs/ui/layout/tiles/Switch.java index c75a4d45..de49b9ae 100644 --- a/src/main/java/jcs/ui/layout/tiles/Switch.java +++ b/src/main/java/jcs/ui/layout/tiles/Switch.java @@ -17,7 +17,6 @@ import java.awt.BasicStroke; import java.awt.Color; -import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.Point; import java.util.HashMap; @@ -38,19 +37,9 @@ import static jcs.entities.TileBean.Orientation.SOUTH; import static jcs.entities.TileBean.Orientation.WEST; import jcs.entities.TileBean.TileType; -import org.tinylog.Logger; public class Switch extends Tile implements AccessoryEventListener { - public Switch(TileBean tileBean) { - this(tileBean, DEFAULT_WIDTH, DEFAULT_HEIGHT); - } - - protected Switch(TileBean tileBean, int width, int height) { - super(tileBean, width, height); - setModel(new DefaultTileModel()); - } - public Switch(Orientation orientation, Direction direction, Point center) { this(orientation, direction, center.x, center.y); } @@ -60,8 +49,20 @@ public Switch(Orientation orientation, Direction direction, int x, int y) { } public Switch(Orientation orientation, Direction direction, int x, int y, int width, int height) { - super(TileType.SWITCH, orientation, direction, x, y, width, height); + this(TileType.SWITCH, orientation, direction, x, y, width, height); + } + protected Switch(TileType tileType, Orientation orientation, Direction direction, int x, int y, int width, int height) { + super(tileType, orientation, direction, x, y, width, height); + setModel(new DefaultTileModel()); + } + + public Switch(TileBean tileBean) { + this(tileBean, DEFAULT_WIDTH, DEFAULT_HEIGHT); + } + + protected Switch(TileBean tileBean, int width, int height) { + super(tileBean, width, height); setModel(new DefaultTileModel()); } diff --git a/src/main/java/jcs/ui/layout/tiles/Tile.java b/src/main/java/jcs/ui/layout/tiles/Tile.java index dfaf4512..da73f3fd 100755 --- a/src/main/java/jcs/ui/layout/tiles/Tile.java +++ b/src/main/java/jcs/ui/layout/tiles/Tile.java @@ -173,8 +173,6 @@ protected Tile(TileType tileType, Orientation orientation, Direction direction, setSize(d); setPreferredSize(d); - //int w = getWidth(); - //int h = getHeight(); this.renderWidth = RENDER_WIDTH; this.renderHeight = RENDER_HEIGHT; @@ -191,7 +189,6 @@ protected Tile(TileType tileType, Orientation orientation, Direction direction, } protected Tile(TileBean tileBean) { - //this(tileBean, DEFAULT_WIDTH, DEFAULT_HEIGHT); this(tileBean, tileWidth(tileBean.getOrientation(), tileBean.getTileType()), tileHeight(tileBean.getOrientation(), tileBean.getTileType())); } @@ -300,7 +297,6 @@ public void setSelected(boolean b) { model.setSelected(b); } - //@Override public String getId() { return id; } @@ -332,8 +328,8 @@ public Point getCenter() { public void setCenter(Point center) { tileX = center.x; tileY = center.y; - if (this.tileBean != null) { - this.tileBean.setCenter(center); + if (tileBean != null) { + tileBean.setCenter(center); } } @@ -354,8 +350,8 @@ public Direction getDirection() { public void setDirection(Direction direction) { this.tileDirection = direction; - if (this.tileBean != null) { - this.tileBean.setDirection(direction); + if (tileBean != null) { + tileBean.setDirection(direction); } } @@ -365,8 +361,8 @@ public String getAccessoryId() { public void setAccessoryId(String accessoryId) { this.accessoryId = accessoryId; - if (this.tileBean != null) { - this.tileBean.setAccessoryId(accessoryId); + if (tileBean != null) { + tileBean.setAccessoryId(accessoryId); } } @@ -453,13 +449,13 @@ public void setAccessoryBean(AccessoryBean accessoryBean) { this.accessoryBean = accessoryBean; if (accessoryBean != null) { - this.accessoryId = accessoryBean.getId(); - this.signalValue = accessoryBean.getSignalValue(); - this.signalType = SignalType.getSignalType(accessoryBean.getType()); + accessoryId = accessoryBean.getId(); + signalValue = accessoryBean.getSignalValue(); + signalType = SignalType.getSignalType(accessoryBean.getType()); } else { - this.accessoryId = null; - this.signalType = SignalType.NONE; - this.signalValue = AccessoryBean.SignalValue.OFF; + accessoryId = null; + signalType = SignalType.NONE; + signalValue = AccessoryBean.SignalValue.OFF; } } @@ -495,7 +491,7 @@ public AccessoryBean.SignalValue getSignalValue() { public void setSignalValue(AccessoryBean.SignalValue signalValue) { this.signalValue = signalValue; - this.repaint(); + repaint(); } public SensorBean getSensorBean() { @@ -606,6 +602,12 @@ public int getRenderHeight() { abstract void renderTileRoute(Graphics2D g2d); + public abstract Map getNeighborPoints(); + + public abstract Map getEdgePoints(); + + public abstract Set getAllPoints(); + /** * Draw the Tile * @@ -869,136 +871,10 @@ public String toString() { + "}"; } -// @Override -// public Rectangle getBounds() { -// int w, h, cx, cy; -// //TODO: Check this may by the componet does this already -// if (this.getWidth() > 0 & this.getHeight() > 0) { -// //if (this.width > 0 & this.height > 0) { -// //w = this.width; -// w = this.getPreferredSize().width; -// //h = this.height; -// h = this.getPreferredSize().height; -// } else { -// w = DEFAULT_WIDTH; -// h = DEFAULT_HEIGHT; -// } -// -// if (this.tileX > 0 && this.tileY > 0) { -// cx = this.tileX + this.offsetX; -// cy = this.tileY + this.offsetY; -// } else { -// cx = w / 2; -// cy = h / 2; -// } -// -// int ltx = cx - w / 2; -// int lty = cy - h / 2; -// return new Rectangle(ltx, lty, w, h); -// } -// public Rectangle2D getBounds2D() { -// return getBounds().getBounds2D(); -// } -// public boolean contains(double x, double y) { -// int w, h, cx, cy, tlx, tly; -// if (this.getWidth() > 0 & this.getHeight() > 0) { -// //if (this.width > 0 & this.height > 0) { -//// w = this.width; -//// h = this.height; -// w = this.getPreferredSize().width; -// h = this.getPreferredSize().height; -// -// } else { -// w = DEFAULT_WIDTH; -// h = DEFAULT_HEIGHT; -// } -// -// if (this.getWidth() > 0 & this.getHeight() > 0) { -// //if (this.width > 0 & this.height > 0) { -// cx = this.tileX; -// cy = this.tileY; -// } else { -// cx = w / 2; -// cy = h / 2; -// } -// -// // top left dX and dY -// tlx = cx - w / 2; -// tly = cy - h / 2; -// -// // Check if X and Y range is ok -// return !(x < tlx || x > (tlx + w) || y < tly || y > (tly + h)); -// } public String xyToString() { return "(" + this.tileX + "," + this.tileY + ")"; } -// public boolean contains(Point2D p) { -// return this.contains(p.getX(), p.getY()); -// } -// public boolean intersects(double x, double y, double w, double h) { -// return getBounds().intersects(x, y, w, h); -// } -// public boolean intersects(Rectangle2D r2d) { -// return getBounds().intersects(r2d); -// } -// public boolean contains(double x, double y, double w, double h) { -// return getBounds().contains(x, y, w, h); -// } -// public boolean contains(Rectangle2D r2d) { -// return getBounds().contains(r2d); -// } -// public PathIterator getPathIterator(AffineTransform at) { -// return getBounds().getPathIterator(at); -// } -// public PathIterator getPathIterator(AffineTransform at, double flatness) { -// return getBounds().getPathIterator(at, flatness); -// } -// @Deprecated -// public PropertyChangeListener getPropertyChangeListener() { -// return this.propertyChangeListener; -// } -// @Deprecated -// public void setPropertyChangeListener(PropertyChangeListener propertyChangeListener) { -// this.propertyChangeListener = propertyChangeListener; -// } - //@Override -// @Deprecated -// public void onTileChange(TileEvent tileEvent) { -// Logger.warn("Deprecated! " + tileEvent.getTileId()); -// if (tileEvent.isEventFor(this)) { -// boolean drawRoute = tileEvent.isShowRoute(); -// setIncomingSide(tileEvent.getIncomingSide()); -// -// if (isJunction()) { -// // setRouteValue(tileEvent.getRouteState()); -// } -// -// if (tileEvent.getBlockBean() != null) { -// this.setBlockBean(tileEvent.getBlockBean()); -// } -// -// //if (tileEvent.getTileBean() != null) { -// // TileBean other = tileEvent.getTileBean(); -// // this.copyInto(other); -// //} -// if (isBlock()) { -// // ((Block) this).setRouteBlockState(tileEvent.getBlockState()); -// if (!drawRoute) { -// // ((Block) this).setRouteBlockState(null); -// } -// } -// -// setBackgroundColor(tileEvent.getBackgroundColor()); -// setTrackColor(tileEvent.getTrackColor()); -// setTrackRouteColor(tileEvent.getTrackRouteColor()); -// -//// if (tileEvent.getBlockBean() != null) { -//// setBlockBean(tileEvent.getBlockBean()); -//// } -//// repaintTile(); -// } -// } /** * The main route of the tile is horizontal * @@ -1109,12 +985,6 @@ public AccessoryValue accessoryValueForRoute(Orientation from, Orientation to) { return AccessoryValue.OFF; } - public abstract Map getNeighborPoints(); - - public abstract Map getEdgePoints(); - - public abstract Set getAllPoints(); - public TileModel getModel() { return model; } @@ -1175,7 +1045,7 @@ class Handler implements ActionListener, ChangeListener, Serializable { @Override public void stateChanged(ChangeEvent e) { - Object source = e.getSource(); + //Object source = e.getSource(); fireStateChanged(); repaint(); diff --git a/src/test/java/jcs/ui/layout/tiles/CrossTileTester.form b/src/test/java/jcs/ui/layout/tiles/CrossTileTester.form new file mode 100644 index 00000000..59c4dba4 --- /dev/null +++ b/src/test/java/jcs/ui/layout/tiles/CrossTileTester.form @@ -0,0 +1,208 @@ + + +

+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/test/java/jcs/ui/layout/tiles/CrossTileTester.java b/src/test/java/jcs/ui/layout/tiles/CrossTileTester.java index 3173bd54..308066e9 100644 --- a/src/test/java/jcs/ui/layout/tiles/CrossTileTester.java +++ b/src/test/java/jcs/ui/layout/tiles/CrossTileTester.java @@ -1,5 +1,5 @@ /* - * Copyright 2023 Frans Jacobs. + * Copyright 2025 Frans Jacobs. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -17,92 +17,279 @@ import java.awt.Color; import java.awt.Dimension; -import java.awt.Graphics; -import java.awt.Graphics2D; import java.awt.Toolkit; import javax.swing.JFrame; import javax.swing.UIManager; import javax.swing.UnsupportedLookAndFeelException; import jcs.entities.AccessoryBean.AccessoryValue; -import jcs.entities.TileBean.Direction; -import jcs.entities.TileBean.Orientation; +import jcs.entities.TileBean; import org.tinylog.Logger; -/** - * @author Frans Jacobs - */ -public class CrossTileTester extends JFrame { +public class CrossTileTester extends javax.swing.JFrame { - private final Tile switchEastR; - private final Tile switchSouthR; - private final Tile switchWestR; - private final Tile switchNorthR; + private Tile crossEastR; + private Tile crossSouthR; + private Tile crossWestR; + private Tile crossNorthR; - private final Tile switchEastL; - private final Tile switchSouthL; - private final Tile switchWestL; - private final Tile switchNorthL; + private Tile crossEastL; + private Tile crossSouthL; + private Tile crossWestL; + private Tile crossNorthL; + /** + * Creates new form TileTester + * + * @param title + */ public CrossTileTester(String title) { super(title); + initComponents(); - switchEastR = new Cross(Orientation.EAST, Direction.RIGHT, 70, 100); - switchSouthR = new Cross(Orientation.SOUTH, Direction.RIGHT, 160, 100); - switchWestR = new Cross(Orientation.WEST, Direction.RIGHT, 250, 100); - switchNorthR = new Cross(Orientation.NORTH, Direction.RIGHT, 300, 100); + createTiles(); - switchEastL = new Cross(Orientation.EAST, Direction.LEFT, 70, 200); - switchSouthL = new Cross(Orientation.SOUTH, Direction.LEFT, 160, 200); - switchWestL = new Cross(Orientation.WEST, Direction.LEFT, 250, 200); - switchNorthL = new Cross(Orientation.NORTH, Direction.LEFT, 300, 200); + this.setVisible(true); } - @Override - public void paint(Graphics g) { - Graphics2D g2d = (Graphics2D) g; + private void createTiles() { + + crossEastR = new Cross(TileBean.Orientation.EAST, TileBean.Direction.RIGHT, 60, 60); + crossEastR.setId("eastR"); + crossEastR.setTrackRouteColor(Color.MAGENTA); + crossEastR.setRouteValue(AccessoryValue.GREEN); -// switchEastR.drawTile(g2d, true); -// switchEastR.drawBounds(g2d); - switchEastR.drawCenterPoint(g2d, Color.red); - ((Switch) switchEastR).setAccessoryValue(AccessoryValue.RED); + crossSouthR = new Cross(TileBean.Orientation.SOUTH, TileBean.Direction.RIGHT, 180, 60); + crossSouthR.setId("southR"); + crossSouthR.setTrackRouteColor(Color.YELLOW); + crossSouthR.setRouteValue(AccessoryValue.RED); -// switchSouthR.drawTile(g2d, false); -// switchSouthR.drawBounds(g2d); - switchSouthR.drawCenterPoint(g2d, Color.blue); + crossWestR = new Cross(TileBean.Orientation.WEST, TileBean.Direction.RIGHT, 380, 60); + crossWestR.setId("westR"); + crossWestR.setTrackRouteColor(Color.CYAN); -// switchWestR.drawTile(g2d, true); -// switchWestR.drawBounds(g2d); - switchWestR.drawCenterPoint(g2d, Color.red); - ((Switch) switchWestR).setAccessoryValue(AccessoryValue.GREEN); + crossNorthR = new Cross(TileBean.Orientation.NORTH, TileBean.Direction.RIGHT, 180, 220); + crossNorthR.setId("northR"); + crossNorthR.setTrackRouteColor(Color.blue); + crossNorthR.setRouteValue(AccessoryValue.GREEN); -// switchNorthR.drawTile(g2d, false); -// switchNorthR.drawBounds(g2d); - switchNorthR.drawCenterPoint(g2d, Color.cyan); // -// switchEastL.drawTile(g2d, false); -// switchEastL.drawBounds(g2d); - switchEastL.drawCenterPoint(g2d, Color.red); + crossEastL = new Cross(TileBean.Orientation.EAST, TileBean.Direction.LEFT, 60, 140); + crossEastL.setId("eastR"); + crossEastL.setTrackRouteColor(Color.MAGENTA); + crossEastL.setRouteValue(AccessoryValue.GREEN); + + crossSouthL = new Cross(TileBean.Orientation.SOUTH, TileBean.Direction.LEFT, 260, 60); + crossSouthL.setId("southR"); + crossSouthL.setTrackRouteColor(Color.YELLOW); + crossSouthL.setRouteValue(AccessoryValue.RED); -// switchSouthL.drawTile(g2d, true); -// switchSouthL.drawBounds(g2d); - switchSouthL.drawCenterPoint(g2d, Color.blue); - ((Switch) switchSouthL).setAccessoryValue(AccessoryValue.GREEN); + crossWestL = new Cross(TileBean.Orientation.WEST, TileBean.Direction.LEFT, 380, 140); + crossWestL.setId("westR"); + crossWestL.setTrackRouteColor(Color.CYAN); -// switchWestL.drawTile(g2d, false); -// switchWestL.drawBounds(g2d); - switchWestL.drawCenterPoint(g2d, Color.red); + crossNorthL = new Cross(TileBean.Orientation.NORTH, TileBean.Direction.LEFT, 260, 220); + crossNorthL.setId("northR"); + crossNorthL.setTrackRouteColor(Color.blue); + crossNorthL.setRouteValue(AccessoryValue.GREEN); -// switchNorthL.drawTile(g2d, true); -// switchNorthL.drawBounds(g2d); - switchNorthL.drawCenterPoint(g2d, Color.cyan); - ((Switch) switchNorthL).setAccessoryValue(AccessoryValue.RED); + dotGridCanvas.add(crossEastR); + dotGridCanvas.add(crossSouthR); + dotGridCanvas.add(crossWestR); + dotGridCanvas.add(crossNorthR); + dotGridCanvas.add(crossEastL); + dotGridCanvas.add(crossSouthL); + dotGridCanvas.add(crossWestL); + dotGridCanvas.add(crossNorthL); } - public static void main(String args[]) { + /** + * This method is called from within the constructor to initialize the form. WARNING: Do NOT modify this code. The content of this method is always regenerated by the Form Editor. + */ + @SuppressWarnings("unchecked") + // //GEN-BEGIN:initComponents + private void initComponents() { + + toolbarPanel = new javax.swing.JPanel(); + toolBar = new javax.swing.JToolBar(); + eastTileBtn = new javax.swing.JToggleButton(); + southTileBtn = new javax.swing.JToggleButton(); + westTileBtn = new javax.swing.JToggleButton(); + northTileBtn = new javax.swing.JToggleButton(); + selectSouthTileBtn = new javax.swing.JToggleButton(); + drawCenterBtn = new javax.swing.JToggleButton(); + greenRedBtn = new javax.swing.JToggleButton(); + dotGridCanvas = new jcs.ui.layout.tiles.DotGridCanvas(); + + setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE); + + java.awt.FlowLayout flowLayout1 = new java.awt.FlowLayout(java.awt.FlowLayout.LEFT); + flowLayout1.setAlignOnBaseline(true); + toolbarPanel.setLayout(flowLayout1); + + toolBar.setRollover(true); + + eastTileBtn.setText("East"); + eastTileBtn.setFocusable(false); + eastTileBtn.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER); + eastTileBtn.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); + eastTileBtn.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + eastTileBtnActionPerformed(evt); + } + }); + toolBar.add(eastTileBtn); + + southTileBtn.setText("South"); + southTileBtn.setFocusable(false); + southTileBtn.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER); + southTileBtn.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); + southTileBtn.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + southTileBtnActionPerformed(evt); + } + }); + toolBar.add(southTileBtn); + + westTileBtn.setText("West"); + westTileBtn.setFocusable(false); + westTileBtn.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER); + westTileBtn.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); + westTileBtn.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + westTileBtnActionPerformed(evt); + } + }); + toolBar.add(westTileBtn); + + northTileBtn.setText("North"); + northTileBtn.setFocusable(false); + northTileBtn.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER); + northTileBtn.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); + northTileBtn.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + northTileBtnActionPerformed(evt); + } + }); + toolBar.add(northTileBtn); + + selectSouthTileBtn.setText("Select Tile"); + selectSouthTileBtn.setFocusable(false); + selectSouthTileBtn.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER); + selectSouthTileBtn.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); + selectSouthTileBtn.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + selectSouthTileBtnActionPerformed(evt); + } + }); + toolBar.add(selectSouthTileBtn); + + drawCenterBtn.setText("show Center"); + drawCenterBtn.setFocusable(false); + drawCenterBtn.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER); + drawCenterBtn.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); + drawCenterBtn.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + drawCenterBtnActionPerformed(evt); + } + }); + toolBar.add(drawCenterBtn); + + greenRedBtn.setText("Red"); + greenRedBtn.setFocusable(false); + greenRedBtn.setHorizontalTextPosition(javax.swing.SwingConstants.CENTER); + greenRedBtn.setVerticalTextPosition(javax.swing.SwingConstants.BOTTOM); + greenRedBtn.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + greenRedBtnActionPerformed(evt); + } + }); + toolBar.add(greenRedBtn); + + toolbarPanel.add(toolBar); + + getContentPane().add(toolbarPanel, java.awt.BorderLayout.NORTH); + + dotGridCanvas.setPreferredSize(new java.awt.Dimension(480, 320)); + getContentPane().add(dotGridCanvas, java.awt.BorderLayout.CENTER); + pack(); + }// //GEN-END:initComponents + + private void northTileBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_northTileBtnActionPerformed + Logger.trace(crossNorthR.id + "..."); + this.crossNorthR.setDrawRoute(this.northTileBtn.isSelected()); + this.crossNorthL.setDrawRoute(this.northTileBtn.isSelected()); + }//GEN-LAST:event_northTileBtnActionPerformed + + private void eastTileBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_eastTileBtnActionPerformed + this.crossEastR.setDrawRoute(this.eastTileBtn.isSelected()); + this.crossEastL.setDrawRoute(this.eastTileBtn.isSelected()); + }//GEN-LAST:event_eastTileBtnActionPerformed + + private void westTileBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_westTileBtnActionPerformed + this.crossWestR.setDrawRoute(this.westTileBtn.isSelected()); + this.crossWestL.setDrawRoute(this.westTileBtn.isSelected()); + }//GEN-LAST:event_westTileBtnActionPerformed + + private void southTileBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_southTileBtnActionPerformed + this.crossSouthR.setDrawRoute(this.southTileBtn.isSelected()); + this.crossSouthL.setDrawRoute(this.southTileBtn.isSelected()); + }//GEN-LAST:event_southTileBtnActionPerformed + + private void selectSouthTileBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_selectSouthTileBtnActionPerformed + this.crossSouthR.setSelected(this.selectSouthTileBtn.isSelected()); + this.crossSouthL.setSelected(this.selectSouthTileBtn.isSelected()); + }//GEN-LAST:event_selectSouthTileBtnActionPerformed + + private void drawCenterBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_drawCenterBtnActionPerformed + this.crossEastR.setDrawCenterPoint(this.drawCenterBtn.isSelected()); + this.crossEastL.setDrawCenterPoint(this.drawCenterBtn.isSelected()); + this.crossSouthR.setDrawCenterPoint(this.drawCenterBtn.isSelected()); + this.crossSouthL.setDrawCenterPoint(this.drawCenterBtn.isSelected()); + this.crossWestR.setDrawCenterPoint(this.drawCenterBtn.isSelected()); + this.crossWestL.setDrawCenterPoint(this.drawCenterBtn.isSelected()); + this.crossNorthR.setDrawCenterPoint(this.drawCenterBtn.isSelected()); + this.crossNorthL.setDrawCenterPoint(this.drawCenterBtn.isSelected()); + }//GEN-LAST:event_drawCenterBtnActionPerformed + + private void greenRedBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_greenRedBtnActionPerformed + boolean red = this.greenRedBtn.isSelected(); + if (red) { + this.greenRedBtn.setText("Green"); + if (this.westTileBtn.isSelected()) { + this.crossWestR.setAccessoryValue(AccessoryValue.OFF); + this.crossWestR.setRouteValue(AccessoryValue.GREEN); + + this.crossWestL.setAccessoryValue(AccessoryValue.OFF); + this.crossWestL.setRouteValue(AccessoryValue.GREEN); + } else { + this.crossWestR.setAccessoryValue(AccessoryValue.GREEN); + this.crossWestL.setAccessoryValue(AccessoryValue.GREEN); + } + } else { + this.greenRedBtn.setText("Red"); + if (this.westTileBtn.isSelected()) { + this.crossWestR.setAccessoryValue(AccessoryValue.OFF); + this.crossWestR.setRouteValue(AccessoryValue.RED); + + this.crossWestL.setAccessoryValue(AccessoryValue.OFF); + this.crossWestL.setRouteValue(AccessoryValue.RED); + } else { + this.crossWestR.setAccessoryValue(AccessoryValue.RED); + this.crossWestL.setAccessoryValue(AccessoryValue.RED); + } + } + }//GEN-LAST:event_greenRedBtnActionPerformed + + /** + * @param args the command line arguments + */ + public static void main(String args[]) { try { UIManager.setLookAndFeel("com.formdev.flatlaf.FlatLightLaf"); + CrossTileTester.setDefaultLookAndFeelDecorated(true); + } catch (ClassNotFoundException | InstantiationException | IllegalAccessException @@ -110,16 +297,26 @@ public static void main(String args[]) { Logger.error(ex); } - CrossTileTester app = new CrossTileTester("Cross Tile Tester"); - - Dimension dim = Toolkit.getDefaultToolkit().getScreenSize(); - app.setSize(400, 300); - - app.setLocation( - dim.width / 2 - app.getSize().width / 2, dim.height / 2 - app.getSize().height / 2); - - app.setVisible(true); - - app.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + /* Create and display the form */ + java.awt.EventQueue.invokeLater(() -> { + CrossTileTester app = new CrossTileTester("Switch Tile Tester"); + app.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + Dimension dim = Toolkit.getDefaultToolkit().getScreenSize(); + app.setLocation(dim.width / 2 - app.getSize().width / 2, dim.height / 2 - app.getSize().height / 2); + app.pack(); + }); } + + // Variables declaration - do not modify//GEN-BEGIN:variables + private jcs.ui.layout.tiles.DotGridCanvas dotGridCanvas; + private javax.swing.JToggleButton drawCenterBtn; + private javax.swing.JToggleButton eastTileBtn; + private javax.swing.JToggleButton greenRedBtn; + private javax.swing.JToggleButton northTileBtn; + private javax.swing.JToggleButton selectSouthTileBtn; + private javax.swing.JToggleButton southTileBtn; + private javax.swing.JToolBar toolBar; + private javax.swing.JPanel toolbarPanel; + private javax.swing.JToggleButton westTileBtn; + // End of variables declaration//GEN-END:variables } diff --git a/src/test/java/jcs/ui/layout/tiles/DotGridCanvas.java b/src/test/java/jcs/ui/layout/tiles/DotGridCanvas.java index 24b3f47b..a789e06b 100644 --- a/src/test/java/jcs/ui/layout/tiles/DotGridCanvas.java +++ b/src/test/java/jcs/ui/layout/tiles/DotGridCanvas.java @@ -16,6 +16,7 @@ package jcs.ui.layout.tiles; import java.awt.Color; +import java.awt.Component; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.Paint; @@ -23,31 +24,48 @@ import org.tinylog.Logger; public class DotGridCanvas extends JPanel { - + public DotGridCanvas() { - setLayout(null); + super(null, false); setOpaque(true); - setDoubleBuffered(false); setBackground(Color.white); } - + +// @Override +// protected void paintComponent(Graphics g) { +// long started = System.currentTimeMillis(); +// super.paintComponent(g); +// +// paintDotGrid(g); +// long now = System.currentTimeMillis(); +// Logger.trace("Duration: " + (now - started) + " ms."); +// } + @Override public void paint(Graphics g) { long started = System.currentTimeMillis(); - - //Rectangle r = g.getClipBounds(); - //Logger.trace("Rx: " + r.x + " Ry: " + r.y + " Rw: " + r.width + " Rh: " + r.height); super.paint(g); - + paintDotGrid(g); long now = System.currentTimeMillis(); Logger.trace("Duration: " + (now - started) + " ms."); } + + + @Override + public Component add(Component component) { + super.add(component); + if (component instanceof Tile tile) { + tile.setBounds(tile.getTileBounds()); + } + return component; + } + private void paintDotGrid(Graphics g) { int width = this.getWidth(); int height = this.getHeight(); - + int xOffset = 0; int yOffset = 0; @@ -55,7 +73,7 @@ private void paintDotGrid(Graphics g) { Graphics2D gc = (Graphics2D) g; Paint p = gc.getPaint(); gc.setPaint(Color.black); - + for (int r = 0; r < width; r++) { for (int c = 0; c < height; c++) { gc.drawOval((r * 20 * 2) + xOffset - 2, (c * 20 * 2) + yOffset - 2, 4, 4); @@ -63,5 +81,5 @@ private void paintDotGrid(Graphics g) { } gc.setPaint(p); } - + } diff --git a/src/test/java/jcs/ui/layout/tiles/StraightTileTester.java b/src/test/java/jcs/ui/layout/tiles/StraightTileTester.java index 0a383d3b..df3bcbdd 100644 --- a/src/test/java/jcs/ui/layout/tiles/StraightTileTester.java +++ b/src/test/java/jcs/ui/layout/tiles/StraightTileTester.java @@ -64,7 +64,6 @@ private void createTiles() { trackNorth.setTrackRouteColor(Color.blue); dotGridCanvas.add(trackEast); - dotGridCanvas.add(trackSouth); dotGridCanvas.add(trackWest); dotGridCanvas.add(trackNorth); diff --git a/src/test/java/jcs/ui/layout/tiles/UnscaledBlockCanvas.java b/src/test/java/jcs/ui/layout/tiles/UnscaledBlockCanvas.java index b4efac2a..486d1b0d 100644 --- a/src/test/java/jcs/ui/layout/tiles/UnscaledBlockCanvas.java +++ b/src/test/java/jcs/ui/layout/tiles/UnscaledBlockCanvas.java @@ -16,13 +16,14 @@ package jcs.ui.layout.tiles; import java.awt.Color; +import java.awt.Component; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.Paint; import javax.swing.JPanel; import org.tinylog.Logger; -public class UnscaledBlockCanvas extends JPanel { //implements PropertyChangeListener { +public class UnscaledBlockCanvas extends JPanel { private boolean expanded; @@ -33,12 +34,18 @@ public UnscaledBlockCanvas() { } @Override - public void paint(Graphics g) { - long started = System.currentTimeMillis(); + public Component add(Component component) { + super.add(component); + if (component instanceof Tile tile) { + tile.setBounds(tile.getTileBounds()); + } + return component; + } - //Rectangle r = g.getClipBounds(); - //Logger.trace("Rx: " + r.x + " Ry: " + r.y + " Rw: " + r.width + " Rh: " + r.height); - super.paint(g); + @Override + protected void paintComponent(Graphics g) { + long started = System.currentTimeMillis(); + super.paintComponent(g); paintGrid(g); long now = System.currentTimeMillis(); @@ -72,160 +79,6 @@ private void paintGrid(Graphics g) { gc.setPaint(p); } - //private boolean showCenter; - //private final List tiles; -// public UnscaledBlockCanvas() { -// tiles = new ArrayList<>(); -// } -// public void addTile(Tile block) { -// this.tiles.add(block); -// this.add(block); -// } -// public boolean isShowCenter() { -// return showCenter; -// } -// public void setShowCenter(boolean showCenter) { -// this.showCenter = showCenter; -// } -// private Dimension getMinCanvasSize() { -// int minX = this.getSize().width; -// int maxX = 0; -// int minY = this.getSize().height; -// int maxY = 0; -// -// for (Tile tile : this.tiles) { -// Point tc = tile.getCenter(); -// boolean expand = !tile.isScaleImage(); -// int tw = tile.getWidth() * (expand ? 10 : 1); -// int th = tile.getHeight() * (expand ? 10 : 1); -// -// if (minX > tc.x - (tw / 2)) { -// minX = tc.x - (tw / 2); -// } -// if (maxX < tc.x + (tw / 2)) { -// maxX = tc.x + (tw / 2); -// } -// if (minY > tc.y - (th / 2)) { -// minY = tc.y - (th / 2); -// } -// if (maxY < tc.y + (th / 2)) { -// maxY = tc.y + (th / 2); -// } -// } -// -// int totalWidth = maxX - minX; -// if (totalWidth <= 120) { -// totalWidth = totalWidth + 20; -// } -// -// int totalHeight = maxY - minY; -// if (totalHeight <= 40) { -// totalHeight = totalHeight + 20; -// } -// -// //Logger.trace("MinX: " + minX + " maxX: " + maxX + " minY: " + minY + " maxY: " + maxY + " Width: " + totalWidth + " Height: " + totalHeight); -// return new Dimension(Math.abs(totalWidth), Math.abs(totalHeight)); -// } -// private Dimension getMinRenderCanvasSize() { -// int minX = this.getSize().width; -// int maxX = 0; -// int minY = this.getSize().height; -// int maxY = 0; -// -// for (Tile tile : this.tiles) { -// Point tc = tile.getCenter(); -// -// int tw = ((Block) tile).getRenderWidth(); -// int th = ((Block) tile).getRenderHeight(); -// -// if (minX > tc.x - (tw / 2)) { -// minX = tc.x - (tw / 2); -// } -// if (maxX < tc.x + (tw / 2)) { -// maxX = tc.x + (tw / 2); -// } -// if (minY > tc.y - (th / 2)) { -// minY = tc.y - (th / 2); -// } -// if (maxY < tc.y + (th / 2)) { -// maxY = tc.y + (th / 2); -// } -// } -// -// int totalWidth = maxX - minX; -// int totalHeight = maxY - minY; -// -// //Logger.trace("MinX: " + minX + " maxX: " + maxX + " minY: " + minY + " maxY: " + maxY + " Width: " + totalWidth + " Height: " + totalHeight); -// return new Dimension(Math.abs(totalWidth), Math.abs(totalHeight)); -// } -// private BufferedImage paintTiles() { -// Dimension canvasSize = getMinCanvasSize(); -// BufferedImage canvasImage = new BufferedImage(Math.abs(canvasSize.width), Math.abs(canvasSize.height), BufferedImage.TYPE_INT_RGB); -// Graphics2D g2d = canvasImage.createGraphics(); -// -// g2d.setBackground(Color.white); -// g2d.clearRect(0, 0, canvasSize.width, canvasSize.height); -// -// for (Tile tile : tiles) { -//// tile.setDrawOutline(showCenter); -// -// //tile.drawTile(g2d, true); -// -// if (showCenter) { -// tile.drawCenterPoint(g2d, Color.red); -// } -// } -// g2d.dispose(); -// -// return canvasImage; -// } -// @Override -// protected void paintComponent(Graphics g) { -// Graphics2D g2d = (Graphics2D) g; -// BufferedImage canvasImage = paintTiles(); -// -// //paint the image in the middle so -// int w = this.getSize().width; -// int h = this.getSize().height; -// -// int cx = w / 2; -// int cy = h / 2; -// -// int bw = canvasImage.getWidth(); -// int bh = canvasImage.getHeight(); -// -// int pw = w; -// int ph = h; -// -// if(bw > w) { -// pw = w; -// } -// if(bh > h) { -// ph = h; -// } -// -// setPreferredSize(new Dimension(bw, bh)); -// //setPreferredSize(new Dimension(pw, ph)); -// -// int x = cx - (bw / 2); -// int y = cy - (bh / 2); -// g2d.drawImage(canvasImage, null, x, y); -// } -// @Override -// public void propertyChange(PropertyChangeEvent evt) { -// if ("repaintTile".equals(evt.getPropertyName())) { -// Tile tile = (Tile) evt.getNewValue(); -// this.repaint(tile.getBounds()); -// } -// } -// @Override -// public Dimension getPreferredSize() { -// if (!tiles.isEmpty()) { -// return getMinCanvasSize(); -// } else { -// return this.getSize(); -// } -// } public boolean isExpanded() { return expanded; } diff --git a/src/test/java/jcs/ui/layout/tiles/UnscaledTileFrame.java b/src/test/java/jcs/ui/layout/tiles/UnscaledTileFrame.java index 8efa793e..43e5bf53 100644 --- a/src/test/java/jcs/ui/layout/tiles/UnscaledTileFrame.java +++ b/src/test/java/jcs/ui/layout/tiles/UnscaledTileFrame.java @@ -240,9 +240,9 @@ private void changeDirection() { Direction direction = (Direction) this.directionCB.getSelectedItem(); this.tile.setDirection(direction); - if (TileType.CROSS == tile.getTileType()) { - ((Cross) tile).setWidthHeightAndOffsets(); - } + //if (TileType.CROSS == tile.getTileType()) { + // ((Cross) tile).setWidthHeightAndOffsets(); + //} //this.repaint(); } @@ -287,7 +287,7 @@ private void changeOrientation() { tile.setOrientation(orientation); if (TileType.CROSS == tile.getTileType()) { - ((Cross) tile).setWidthHeightAndOffsets(); + //((Cross) tile).setWidthHeightAndOffsets(); int x = tile.getCenterX(); int y = tile.getCenterY(); From c95c95fdff0ff1a5ea9d74b94c05256ca547de94 Mon Sep 17 00:00:00 2001 From: Frans Jacobs <41232225+fransjacobs@users.noreply.github.com> Date: Sun, 26 Jan 2025 22:07:19 +0100 Subject: [PATCH 08/24] More refactoring issue with rotation of Cross --- src/main/java/jcs/ui/layout/LayoutCanvas.java | 6 +- src/main/java/jcs/ui/layout/tiles/Block.java | 22 +- src/main/java/jcs/ui/layout/tiles/Cross.java | 2 + src/main/java/jcs/ui/layout/tiles/Curved.java | 15 +- .../jcs/ui/layout/tiles/DefaultTileModel.java | 17 ++ src/main/java/jcs/ui/layout/tiles/End.java | 8 +- .../java/jcs/ui/layout/tiles/Straight.java | 4 +- src/main/java/jcs/ui/layout/tiles/Switch.java | 4 +- src/main/java/jcs/ui/layout/tiles/Tile.java | 43 ++- .../java/jcs/ui/layout/tiles/TileFactory.java | 13 +- .../java/jcs/ui/layout/tiles/TileModel.java | 5 + src/test/java/jcs/ui/layout/TileTest.java | 288 +++++++++--------- .../jcs/ui/layout/tiles/DotGridCanvas.java | 42 +-- ...ledTileFrame.form => TileTesterFrame.form} | 53 +++- ...ledTileFrame.java => TileTesterFrame.java} | 282 ++++++++--------- 15 files changed, 438 insertions(+), 366 deletions(-) rename src/test/java/jcs/ui/layout/tiles/{UnscaledTileFrame.form => TileTesterFrame.form} (91%) rename src/test/java/jcs/ui/layout/tiles/{UnscaledTileFrame.java => TileTesterFrame.java} (74%) diff --git a/src/main/java/jcs/ui/layout/LayoutCanvas.java b/src/main/java/jcs/ui/layout/LayoutCanvas.java index 6ac0884d..5ba67e08 100755 --- a/src/main/java/jcs/ui/layout/LayoutCanvas.java +++ b/src/main/java/jcs/ui/layout/LayoutCanvas.java @@ -380,7 +380,7 @@ private Tile addTile(Point p, TileType tileType, Orientation orientation, Direct Logger.trace("Adding: " + tileType + " @ " + p + " O: " + orientation + " D: " + direction); Point chkp = TileCache.checkAvailable(p, orientation); - Tile tile = TileFactory.createTile(tileType, orientation, direction, chkp, drawGrid); + Tile tile = TileFactory.createTile(tileType, orientation, direction, chkp); tile.setSelected(selected); tile.setDrawCenterPoint(showCenter); @@ -734,7 +734,9 @@ public void rotateSelectedTile() { Logger.trace("Selected Tile " + selectedTile.getId()); selectedTile = TileCache.rotateTile(selectedTile); selectedTile.setBounds(selectedTile.getTileBounds()); - selectedTile.repaint(); + //selectedTile.repaint(); + + repaint(selectedTile.getTileBounds()); } public void flipSelectedTileHorizontal() { diff --git a/src/main/java/jcs/ui/layout/tiles/Block.java b/src/main/java/jcs/ui/layout/tiles/Block.java index abf288dc..105cfcdb 100755 --- a/src/main/java/jcs/ui/layout/tiles/Block.java +++ b/src/main/java/jcs/ui/layout/tiles/Block.java @@ -55,10 +55,8 @@ public class Block extends Tile { public Block(TileBean tileBean) { super(tileBean); - setModel(new DefaultTileModel()); - + setModel(new DefaultTileModel(tileBean.getOrientation())); changeRenderSize(); - populateModel(); } @@ -72,11 +70,12 @@ public Block(Orientation orientation, int x, int y) { public Block(Orientation orientation, int x, int y, int width, int height) { super(TileType.BLOCK, orientation, x, y, width, height); - setModel(new DefaultTileModel()); + setModel(new DefaultTileModel(orientation)); changeRenderSize(); } private void changeRenderSize() { + Orientation tileOrientation = model.getTileOrienation(); if (Orientation.EAST == tileOrientation || Orientation.WEST == tileOrientation) { this.renderWidth = RENDER_WIDTH * 3; this.renderHeight = RENDER_HEIGHT; @@ -257,6 +256,7 @@ public String getIdSuffix(Tile other) { } } + Orientation tileOrientation = model.getTileOrienation(); if (match != null) { if (Orientation.EAST == tileOrientation && Orientation.EAST == match) { suffix = "+"; @@ -288,6 +288,7 @@ public String getIdSuffix(Tile other) { @Override public Orientation rotate() { + Orientation tileOrientation = model.getTileOrienation(); super.rotate(); int w = tileWidth(tileOrientation, TileType.BLOCK); @@ -300,7 +301,7 @@ public Orientation rotate() { setBounds(getTileBounds()); - repaint(getTileBounds()); + //repaint(getTileBounds()); return tileOrientation; } @@ -401,6 +402,7 @@ public void renderTile(Graphics2D g2) { private void renderDirectionArrow(Graphics2D g2) { //The default, forwards is in the direction of the block orientation, i.e. the + + Orientation tileOrientation = model.getTileOrienation(); BlockBean bb = this.getBlockBean(); boolean reverseArrival = model.isReverseArrival(); @@ -512,6 +514,7 @@ public void renderTileRoute(Graphics2D g2d) { protected void overlayLocImage() { int ww = tileImage.getWidth(); int hh = tileImage.getHeight(); + Orientation tileOrientation = model.getTileOrienation(); BufferedImage overlay = new BufferedImage(ww, hh, BufferedImage.TYPE_INT_ARGB); Graphics2D g2i = overlay.createGraphics(); @@ -632,7 +635,6 @@ protected void overlayLocImage() { g2i.dispose(); tileImage = overlay; } - } private Image getLocImage() { @@ -688,6 +690,7 @@ public void drawName(Graphics2D g2d) { } int textHeight = g2d.getFontMetrics().getHeight(); + Orientation tileOrientation = model.getTileOrienation(); switch (tileOrientation) { case EAST -> { @@ -712,6 +715,8 @@ public void drawName(Graphics2D g2d) { @Override public Rectangle getTileBounds() { int multiplier = (model.isScaleImage() ? 1 : 10); + Orientation tileOrientation = model.getTileOrienation(); + int xx, yy; if (tileOrientation == Orientation.EAST || tileOrientation == Orientation.WEST) { xx = tileX - GRID * multiplier - GRID * multiplier * 2; @@ -751,6 +756,7 @@ protected void drawCenterPoint(Graphics2D g2d, Color color, double size) { //1st square //2nd square holds the centerpoint //3rd square + Orientation tileOrientation = model.getTileOrienation(); double dX1, dX2, dX3, dY1, dY2, dY3; if (Orientation.EAST == tileOrientation || Orientation.WEST == tileOrientation) { dX1 = renderWidth / 3 / 2 - size / 2 / 2; @@ -772,10 +778,6 @@ protected void drawCenterPoint(Graphics2D g2d, Color color, double size) { g2d.fill(new Ellipse2D.Double(dX1, dY1, size / 2, size / 2)); g2d.fill(new Ellipse2D.Double(dX2, dY2, size, size)); g2d.fill(new Ellipse2D.Double(dX3, dY3, size / 2, size / 2)); - - //Logger.trace(id + " dX2: " + dX2 + " dY2: " + dY2 + " O: " + tileOrientation + " rW: " + renderWidth + " rH:" + renderHeight + " Size: " + size); - //Logger.trace(id + " dX1: " + dX1 + " dY1: " + dY1); - //Logger.trace(id + " dX3: " + dX3 + " dY3: " + dY3); } } diff --git a/src/main/java/jcs/ui/layout/tiles/Cross.java b/src/main/java/jcs/ui/layout/tiles/Cross.java index 3df8e88b..72e03d11 100644 --- a/src/main/java/jcs/ui/layout/tiles/Cross.java +++ b/src/main/java/jcs/ui/layout/tiles/Cross.java @@ -585,6 +585,7 @@ protected void drawCenterPoint(Graphics2D g2d, Color color, double size) { //1st square holds the centerpoint //2nd square double dX1, dX2, dY1, dY2; + Orientation tileOrientation = model.getTileOrienation(); switch (tileOrientation) { case SOUTH -> { dX1 = renderWidth / 2 - size / 2; @@ -623,6 +624,7 @@ public Rectangle getTileBounds() { int multiplier = (model.isScaleImage() ? 1 : 10); int xx, yy; //Centerpoint is inbalanced + Orientation tileOrientation = model.getTileOrienation(); switch (tileOrientation) { case SOUTH -> { xx = tileX - GRID * multiplier; diff --git a/src/main/java/jcs/ui/layout/tiles/Curved.java b/src/main/java/jcs/ui/layout/tiles/Curved.java index 1aad3e4b..0de19ed3 100755 --- a/src/main/java/jcs/ui/layout/tiles/Curved.java +++ b/src/main/java/jcs/ui/layout/tiles/Curved.java @@ -16,7 +16,6 @@ package jcs.ui.layout.tiles; import java.awt.BasicStroke; -import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.Point; import java.util.HashMap; @@ -29,26 +28,25 @@ import static jcs.entities.TileBean.Orientation.SOUTH; import static jcs.entities.TileBean.Orientation.WEST; import jcs.entities.TileBean.TileType; -import org.tinylog.Logger; public class Curved extends Tile { - Curved(TileBean tileBean) { + public Curved(TileBean tileBean) { super(tileBean, DEFAULT_WIDTH, DEFAULT_HEIGHT); - setModel(new DefaultTileModel()); + setModel(new DefaultTileModel(tileBean.getOrientation())); } - Curved(Orientation orientation, Point center) { + public Curved(Orientation orientation, Point center) { this(orientation, center.x, center.y); } - Curved(Orientation orientation, int x, int y) { + public Curved(Orientation orientation, int x, int y) { this(orientation, x, y, DEFAULT_WIDTH, DEFAULT_HEIGHT); } - Curved(Orientation orientation, int x, int y, int width, int height) { + public Curved(Orientation orientation, int x, int y, int width, int height) { super(TileType.CURVED, orientation, x, y, width, height); - setModel(new DefaultTileModel()); + setModel(new DefaultTileModel(orientation)); } @Override @@ -160,5 +158,4 @@ public void renderTileRoute(Graphics2D g2) { // long now = System.currentTimeMillis(); // Logger.trace(this.id + " Duration: " + (now - started) + " ms."); // } - } diff --git a/src/main/java/jcs/ui/layout/tiles/DefaultTileModel.java b/src/main/java/jcs/ui/layout/tiles/DefaultTileModel.java index f584c651..6663ee90 100644 --- a/src/main/java/jcs/ui/layout/tiles/DefaultTileModel.java +++ b/src/main/java/jcs/ui/layout/tiles/DefaultTileModel.java @@ -23,6 +23,7 @@ import javax.swing.event.EventListenerList; import jcs.entities.BlockBean.BlockState; import jcs.entities.LocomotiveBean; +import jcs.entities.TileBean.Orientation; /** * @@ -41,6 +42,7 @@ public class DefaultTileModel implements TileModel { protected boolean selected = false; protected boolean scaleImage = true; protected boolean showCenter = false; + protected Orientation tileOrienation; protected boolean showRoute = false; protected boolean showBlockState = false; protected boolean showLocomotiveImage = false; @@ -57,7 +59,11 @@ public class DefaultTileModel implements TileModel { protected LocomotiveBean locomotive; public DefaultTileModel() { + this(Orientation.EAST); + } + public DefaultTileModel(Orientation orientation) { + this.tileOrienation = orientation; } @Override @@ -93,6 +99,17 @@ public void setShowCenter(boolean showCenter) { fireStateChanged(); } + @Override + public Orientation getTileOrienation() { + return tileOrienation; + } + + @Override + public void setTileOrienation(Orientation tileOrienation) { + this.tileOrienation = tileOrienation; + fireStateChanged(); + } + @Override public boolean isShowRoute() { return showRoute; diff --git a/src/main/java/jcs/ui/layout/tiles/End.java b/src/main/java/jcs/ui/layout/tiles/End.java index fd474844..e71da407 100644 --- a/src/main/java/jcs/ui/layout/tiles/End.java +++ b/src/main/java/jcs/ui/layout/tiles/End.java @@ -17,7 +17,6 @@ import java.awt.BasicStroke; import java.awt.Color; -import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.Point; import java.util.HashMap; @@ -30,13 +29,12 @@ import static jcs.entities.TileBean.Orientation.SOUTH; import static jcs.entities.TileBean.Orientation.WEST; import jcs.entities.TileBean.TileType; -import org.tinylog.Logger; public class End extends Tile { public End(TileBean tileBean) { super(tileBean, DEFAULT_WIDTH, DEFAULT_HEIGHT); - setModel(new DefaultTileModel()); + setModel(new DefaultTileModel(tileBean.getOrientation())); } public End(Orientation orientation, Point center) { @@ -49,8 +47,7 @@ public End(Orientation orientation, int x, int y) { public End(Orientation orientation, int x, int y, int width, int height) { super(TileType.END, orientation, x, y, width, height); - - setModel(new DefaultTileModel()); + setModel(new DefaultTileModel(orientation)); } @Override @@ -147,5 +144,4 @@ public void renderTileRoute(Graphics2D g2d) { // long now = System.currentTimeMillis(); // Logger.trace(this.id + " Duration: " + (now - started) + " ms."); // } - } diff --git a/src/main/java/jcs/ui/layout/tiles/Straight.java b/src/main/java/jcs/ui/layout/tiles/Straight.java index 96685548..9cc63d74 100755 --- a/src/main/java/jcs/ui/layout/tiles/Straight.java +++ b/src/main/java/jcs/ui/layout/tiles/Straight.java @@ -30,7 +30,7 @@ public class Straight extends Tile { public Straight(TileBean tileBean) { super(tileBean, DEFAULT_WIDTH, DEFAULT_HEIGHT); - setModel(new DefaultTileModel()); + setModel(new DefaultTileModel(tileBean.getOrientation())); } public Straight(Orientation orientation, Point center) { @@ -43,7 +43,7 @@ public Straight(Orientation orientation, int x, int y) { public Straight(Orientation orientation, int x, int y, int width, int height) { super(TileType.STRAIGHT, orientation, x, y, width, height); - setModel(new DefaultTileModel()); + setModel(new DefaultTileModel(orientation)); } @Override diff --git a/src/main/java/jcs/ui/layout/tiles/Switch.java b/src/main/java/jcs/ui/layout/tiles/Switch.java index de49b9ae..abfd920f 100644 --- a/src/main/java/jcs/ui/layout/tiles/Switch.java +++ b/src/main/java/jcs/ui/layout/tiles/Switch.java @@ -54,7 +54,7 @@ public Switch(Orientation orientation, Direction direction, int x, int y, int wi protected Switch(TileType tileType, Orientation orientation, Direction direction, int x, int y, int width, int height) { super(tileType, orientation, direction, x, y, width, height); - setModel(new DefaultTileModel()); + setModel(new DefaultTileModel(orientation)); } public Switch(TileBean tileBean) { @@ -63,7 +63,7 @@ public Switch(TileBean tileBean) { protected Switch(TileBean tileBean, int width, int height) { super(tileBean, width, height); - setModel(new DefaultTileModel()); + setModel(new DefaultTileModel(tileBean.getOrientation())); } @Override diff --git a/src/main/java/jcs/ui/layout/tiles/Tile.java b/src/main/java/jcs/ui/layout/tiles/Tile.java index da73f3fd..fdf6acf3 100755 --- a/src/main/java/jcs/ui/layout/tiles/Tile.java +++ b/src/main/java/jcs/ui/layout/tiles/Tile.java @@ -104,7 +104,7 @@ public abstract class Tile extends JComponent { //implements TileEventListener { protected int renderWidth; protected int renderHeight; - protected Orientation tileOrientation; + //protected Orientation tileOrientation; protected Direction tileDirection; protected TileType tileType; @@ -163,7 +163,8 @@ protected Tile(TileType tileType, Orientation orientation, Direction direction, protected Tile(TileType tileType, Orientation orientation, Direction direction, int x, int y, int width, int height, Color backgroundColor, Color selectedColor) { this.tileType = tileType; - this.tileOrientation = orientation; + //this.tileOrientation = orientation; + //model.setTileOrienation(orientation); this.tileDirection = direction; this.tileX = x; this.tileY = y; @@ -197,7 +198,8 @@ protected Tile(TileBean tileBean, int width, int height) { //Quick properties this.id = tileBean.getId(); this.tileType = tileBean.getTileType(); - this.tileOrientation = tileBean.getOrientation(); + //this.tileOrientation = tileBean.getOrientation(); + //this.model.setTileOrienation(tileBean.getOrientation()); this.tileDirection = tileBean.getDirection(); this.tileX = tileBean.getX(); this.tileY = tileBean.getY(); @@ -276,7 +278,9 @@ public TileBean getTileBean() { tileBean.setX(this.tileX); tileBean.setY(this.tileY); tileBean.setTileType(this.tileType); - tileBean.setTileOrientation(this.tileOrientation.getOrientation()); + //tileBean.setTileOrientation(this.tileOrientation.getOrientation()); + tileBean.setTileOrientation(this.model.getTileOrienation().getOrientation()); + tileBean.setTileDirection(this.tileDirection.getDirection()); tileBean.setSignalType(this.signalType); tileBean.setAccessoryId(this.accessoryId); @@ -334,11 +338,13 @@ public void setCenter(Point center) { } public Orientation getOrientation() { - return tileOrientation; + //return tileOrientation; + return model.getTileOrienation(); } public void setOrientation(Orientation orientation) { - this.tileOrientation = orientation; + //this.tileOrientation = orientation; + model.setTileOrienation(orientation); if (tileBean != null) { tileBean.setOrientation(orientation); } @@ -615,9 +621,10 @@ public int getRenderHeight() { */ public void drawTile(Graphics2D g2d) { // by default and image is rendered in the EAST orientation - if (tileOrientation == null) { - tileOrientation = Orientation.EAST; - } + Orientation tileOrientation = model.getTileOrienation(); +// if (tileOrientation == null) { +// tileOrientation = Orientation.EAST; +// } BufferedImage bf = createImage(); Graphics2D g2di = bf.createGraphics(); @@ -718,6 +725,7 @@ protected void drawCenterPoint(Graphics2D g2d, Color color, double size) { * @return the new Orientation */ public Orientation rotate() { + Orientation tileOrientation = model.getTileOrienation(); switch (tileOrientation) { case EAST -> setOrientation(Orientation.SOUTH); @@ -728,10 +736,11 @@ public Orientation rotate() { default -> setOrientation(Orientation.EAST); } - return tileOrientation; + return model.getTileOrienation(); } public void flipHorizontal() { + Orientation tileOrientation = model.getTileOrienation(); if (Orientation.NORTH == tileOrientation || Orientation.SOUTH == tileOrientation) { rotate(); rotate(); @@ -739,7 +748,8 @@ public void flipHorizontal() { } public void flipVertical() { - if (Orientation.EAST.equals(getOrientation()) || Orientation.WEST.equals(getOrientation())) { + Orientation tileOrientation = model.getTileOrienation(); + if (Orientation.EAST == tileOrientation || Orientation.WEST == tileOrientation) { rotate(); rotate(); } @@ -881,6 +891,7 @@ public String xyToString() { * @return true when main route goes from East to West or vv */ public boolean isHorizontal() { + Orientation tileOrientation = model.getTileOrienation(); return (Orientation.EAST == tileOrientation || Orientation.WEST == tileOrientation) && TileType.CURVED != tileType; } @@ -890,6 +901,7 @@ public boolean isHorizontal() { * @return true when main route goes from North to South or vv */ public boolean isVertical() { + Orientation tileOrientation = model.getTileOrienation(); return (Orientation.NORTH == tileOrientation || Orientation.SOUTH == tileOrientation) && TileType.CURVED != tileType; } @@ -1091,7 +1103,14 @@ protected void fireActionPerformed(ActionEvent event) { } public Rectangle getTileBounds() { - return new Rectangle(tileX - GRID, tileY - GRID, DEFAULT_WIDTH, DEFAULT_HEIGHT); + //return new Rectangle(tileX - GRID, tileY - GRID, DEFAULT_WIDTH, DEFAULT_HEIGHT); + + if (model.isScaleImage()) { + return new Rectangle(tileX - GRID, tileY - GRID, DEFAULT_WIDTH, DEFAULT_HEIGHT); + } else { + return new Rectangle(tileX - renderWidth / 2, tileY - renderHeight / 2, renderWidth, renderHeight); + } + } @Override diff --git a/src/main/java/jcs/ui/layout/tiles/TileFactory.java b/src/main/java/jcs/ui/layout/tiles/TileFactory.java index 203796ba..f1522721 100755 --- a/src/main/java/jcs/ui/layout/tiles/TileFactory.java +++ b/src/main/java/jcs/ui/layout/tiles/TileFactory.java @@ -228,8 +228,8 @@ public static Tile createTile(TileBean tileBean, boolean showValues) { * @param drawOutline whether the outline of the tile must be rendered * @return a Tile object */ - public static Tile createTile(TileBean.TileType tileType, Orientation orientation, int x, int y, boolean drawOutline) { - return createTile(tileType, orientation, Direction.CENTER, x, y, drawOutline); + public static Tile createTile(TileBean.TileType tileType, Orientation orientation, int x, int y) { + return createTile(tileType, orientation, Direction.CENTER, x, y); } /** @@ -238,14 +238,13 @@ public static Tile createTile(TileBean.TileType tileType, Orientation orientatio * @param direction direction plays a role with Turnout tiles whether it goes to the Left or Right * @param x the tile center X * @param y the tile center Y - * @param drawOutline whether the outline of the tile must be rendered * @return a Tile object */ - public static Tile createTile(TileBean.TileType tileType, Orientation orientation, Direction direction, int x, int y, boolean drawOutline) { - return createTile(tileType, orientation, direction, new Point(x, y), drawOutline); + public static Tile createTile(TileBean.TileType tileType, Orientation orientation, Direction direction, int x, int y) { + return createTile(tileType, orientation, direction, new Point(x, y)); } - public static Tile createTile(TileBean.TileType tileType, Orientation orientation, Direction direction, Point center, boolean drawOutline) { + public static Tile createTile(TileBean.TileType tileType, Orientation orientation, Direction direction, Point center) { Tile tile = null; switch (tileType) { case STRAIGHT -> { @@ -275,11 +274,9 @@ public static Tile createTile(TileBean.TileType tileType, Orientation orientatio } if (tile != null) { - //tile.setDrawOutline(drawOutline); tile.setId(nextTileId(tileType)); } -// addTileEventListener((TileEventListener) tile); return (Tile) tile; } diff --git a/src/main/java/jcs/ui/layout/tiles/TileModel.java b/src/main/java/jcs/ui/layout/tiles/TileModel.java index 46f144f3..84b78bf0 100644 --- a/src/main/java/jcs/ui/layout/tiles/TileModel.java +++ b/src/main/java/jcs/ui/layout/tiles/TileModel.java @@ -20,6 +20,7 @@ import javax.swing.event.ChangeListener; import jcs.entities.BlockBean; import jcs.entities.LocomotiveBean; +import jcs.entities.TileBean; /** * @@ -39,6 +40,10 @@ public interface TileModel extends Serializable { public void setShowCenter(boolean showCenter); + public TileBean.Orientation getTileOrienation(); + + void setTileOrienation(TileBean.Orientation tileOrienation); + boolean isShowRoute(); public void setShowRoute(boolean showRoute); diff --git a/src/test/java/jcs/ui/layout/TileTest.java b/src/test/java/jcs/ui/layout/TileTest.java index 244a7d39..cd18f276 100644 --- a/src/test/java/jcs/ui/layout/TileTest.java +++ b/src/test/java/jcs/ui/layout/TileTest.java @@ -39,7 +39,7 @@ public TileTest() { @Test public void testgetCenterX() { System.out.println("getCenterX"); - Tile instance = TileFactory.createTile(TileBean.TileType.STRAIGHT, Orientation.EAST, Direction.CENTER, 180, 100, false); + Tile instance = TileFactory.createTile(TileBean.TileType.STRAIGHT, Orientation.EAST, Direction.CENTER, 180, 100); int expResult = 180; int result = instance.getCenterX(); assertEquals(expResult, result); @@ -49,30 +49,22 @@ public void testgetCenterX() { public void testgetCenterXZero() { System.out.println("getCenterX"); Tile instance - = TileFactory.createTile( - TileBean.TileType.STRAIGHT, Orientation.EAST, Direction.CENTER, 0, 0, false); + = TileFactory.createTile(TileBean.TileType.STRAIGHT, Orientation.EAST, Direction.CENTER, 0, 0); int expResult = 20; int result = instance.getCenterX(); assertEquals(expResult, result); } -// public int getGridX() { -// return (getCenterX() - Tile.GRID) / (Tile.GRID * 2); -// } -// public int getGridY() { -// return (getCenterY() - Tile.GRID) / (Tile.GRID * 2); -// } @Test public void testGetGridX() { System.out.println("getGridX"); - Tile instance - = TileFactory.createTile(TileBean.TileType.STRAIGHT, Orientation.EAST, Direction.CENTER, 100, 100, false); + Tile instance = TileFactory.createTile(TileBean.TileType.STRAIGHT, Orientation.EAST, Direction.CENTER, 100, 100); int expResult = 2; int result = (instance.getTileX() - Tile.GRID) / (Tile.GRID * 2); assertEquals(expResult, result); - instance = TileFactory.createTile(TileBean.TileType.STRAIGHT, Orientation.EAST, Direction.CENTER, 220, 220, false); + instance = TileFactory.createTile(TileBean.TileType.STRAIGHT, Orientation.EAST, Direction.CENTER, 220, 220); expResult = 5; result = (instance.getTileX() - Tile.GRID) / (Tile.GRID * 2); @@ -82,7 +74,7 @@ public void testGetGridX() { @Test public void testgetCenterY() { System.out.println("getCenterY"); - Tile instance = TileFactory.createTile(TileBean.TileType.STRAIGHT, Orientation.EAST, Direction.CENTER, 180, 100, false); + Tile instance = TileFactory.createTile(TileBean.TileType.STRAIGHT, Orientation.EAST, Direction.CENTER, 180, 100); int expResult = 100; int result = instance.getCenterY(); assertEquals(expResult, result); @@ -91,7 +83,7 @@ public void testgetCenterY() { @Test public void testgetCenterYZero() { System.out.println("getCenterY"); - Tile instance = TileFactory.createTile(TileBean.TileType.STRAIGHT, Orientation.EAST, Direction.CENTER, 0, 0, false); + Tile instance = TileFactory.createTile(TileBean.TileType.STRAIGHT, Orientation.EAST, Direction.CENTER, 0, 0); int expResult = 20; int result = instance.getCenterY(); assertEquals(expResult, result); @@ -100,7 +92,7 @@ public void testgetCenterYZero() { @Test public void testGetGridY() { System.out.println("getGridY"); - Tile instance = TileFactory.createTile(TileBean.TileType.STRAIGHT, Orientation.WEST, Direction.CENTER, 100, 140, false); + Tile instance = TileFactory.createTile(TileBean.TileType.STRAIGHT, Orientation.WEST, Direction.CENTER, 100, 140); int expResult = 3; int result = (instance.getTileY() - Tile.GRID) / (Tile.GRID * 2); assertEquals(expResult, result); @@ -110,8 +102,7 @@ public void testGetGridY() { public void testGetAllPoints() { System.out.println("getAllPoints"); Tile instance - = TileFactory.createTile( - TileBean.TileType.BLOCK, Orientation.WEST, Direction.CENTER, 220, 220, false); + = TileFactory.createTile(TileBean.TileType.BLOCK, Orientation.WEST, Direction.CENTER, 220, 220); Set expResult = new HashSet<>(); expResult.add(new Point(220, 220)); expResult.add(new Point(180, 220)); @@ -126,8 +117,7 @@ public void testGetAllPoints() { public void testGetAltPointsBlock() { System.out.println("getAltPointsBlock"); Tile instance - = TileFactory.createTile( - TileBean.TileType.BLOCK, Orientation.WEST, Direction.CENTER, 220, 220, false); + = TileFactory.createTile(TileBean.TileType.BLOCK, Orientation.WEST, Direction.CENTER, 220, 220); Set expResult = new HashSet<>(); expResult.add(new Point(180, 220)); expResult.add(new Point(260, 220)); @@ -140,16 +130,16 @@ public void testGetAltPointsCross() { System.out.println("getAltPointsCross"); Tile instanceE = TileFactory.createTile( - TileBean.TileType.CROSS, Orientation.EAST, Direction.CENTER, 220, 220, false); + TileBean.TileType.CROSS, Orientation.EAST, Direction.CENTER, 220, 220); Tile instanceS = TileFactory.createTile( - TileBean.TileType.CROSS, Orientation.SOUTH, Direction.CENTER, 220, 220, false); + TileBean.TileType.CROSS, Orientation.SOUTH, Direction.CENTER, 220, 220); Tile instanceW = TileFactory.createTile( - TileBean.TileType.CROSS, Orientation.WEST, Direction.CENTER, 220, 220, false); + TileBean.TileType.CROSS, Orientation.WEST, Direction.CENTER, 220, 220); Tile instanceN = TileFactory.createTile( - TileBean.TileType.CROSS, Orientation.NORTH, Direction.CENTER, 220, 220, false); + TileBean.TileType.CROSS, Orientation.NORTH, Direction.CENTER, 220, 220); Set expResultE = new HashSet<>(); expResultE.add(new Point(260, 220)); @@ -186,31 +176,31 @@ public void testGetNeighborPointsCross() { System.out.println("getNeighborPointsCross"); Tile instanceEL = TileFactory.createTile( - TileBean.TileType.CROSS, Orientation.EAST, Direction.LEFT, 220, 220, false); + TileBean.TileType.CROSS, Orientation.EAST, Direction.LEFT, 220, 220); Tile instanceER = TileFactory.createTile( - TileBean.TileType.CROSS, Orientation.EAST, Direction.RIGHT, 220, 220, false); + TileBean.TileType.CROSS, Orientation.EAST, Direction.RIGHT, 220, 220); Tile instanceWL = TileFactory.createTile( - TileBean.TileType.CROSS, Orientation.WEST, Direction.LEFT, 220, 220, false); + TileBean.TileType.CROSS, Orientation.WEST, Direction.LEFT, 220, 220); Tile instanceWR = TileFactory.createTile( - TileBean.TileType.CROSS, Orientation.WEST, Direction.RIGHT, 220, 220, false); + TileBean.TileType.CROSS, Orientation.WEST, Direction.RIGHT, 220, 220); Tile instanceSL = TileFactory.createTile( - TileBean.TileType.CROSS, Orientation.SOUTH, Direction.LEFT, 220, 220, false); + TileBean.TileType.CROSS, Orientation.SOUTH, Direction.LEFT, 220, 220); Tile instanceSR = TileFactory.createTile( - TileBean.TileType.CROSS, Orientation.SOUTH, Direction.RIGHT, 220, 220, false); + TileBean.TileType.CROSS, Orientation.SOUTH, Direction.RIGHT, 220, 220); Tile instanceNL = TileFactory.createTile( - TileBean.TileType.CROSS, Orientation.NORTH, Direction.LEFT, 220, 220, false); + TileBean.TileType.CROSS, Orientation.NORTH, Direction.LEFT, 220, 220); Tile instanceNR = TileFactory.createTile( - TileBean.TileType.CROSS, Orientation.NORTH, Direction.RIGHT, 220, 220, false); + TileBean.TileType.CROSS, Orientation.NORTH, Direction.RIGHT, 220, 220); Map expResultEL = new HashMap<>(); expResultEL.put(Orientation.EAST, new Point(300, 220)); @@ -298,23 +288,23 @@ public void testIsAdjacentStraight() { System.out.println("isAdjacentStraight"); Tile instanceE = TileFactory.createTile( - TileBean.TileType.STRAIGHT, Orientation.EAST, Direction.CENTER, 100, 100, false); + TileBean.TileType.STRAIGHT, Orientation.EAST, Direction.CENTER, 100, 100); Tile instanceN = TileFactory.createTile( - TileBean.TileType.STRAIGHT, Orientation.NORTH, Direction.CENTER, 100, 100, false); + TileBean.TileType.STRAIGHT, Orientation.NORTH, Direction.CENTER, 100, 100); Tile west = TileFactory.createTile( - TileBean.TileType.STRAIGHT, Orientation.WEST, Direction.CENTER, 60, 100, false); + TileBean.TileType.STRAIGHT, Orientation.WEST, Direction.CENTER, 60, 100); Tile east = TileFactory.createTile( - TileBean.TileType.STRAIGHT, Orientation.EAST, Direction.CENTER, 140, 100, false); + TileBean.TileType.STRAIGHT, Orientation.EAST, Direction.CENTER, 140, 100); Tile north = TileFactory.createTile( - TileBean.TileType.STRAIGHT, Orientation.NORTH, Direction.CENTER, 100, 60, false); + TileBean.TileType.STRAIGHT, Orientation.NORTH, Direction.CENTER, 100, 60); Tile south = TileFactory.createTile( - TileBean.TileType.STRAIGHT, Orientation.SOUTH, Direction.CENTER, 100, 140, false); + TileBean.TileType.STRAIGHT, Orientation.SOUTH, Direction.CENTER, 100, 140); assertTrue(instanceE.isAdjacent(west)); assertTrue(instanceE.isAdjacent(east)); @@ -333,31 +323,31 @@ public void testIsAdjacentBlock() { Tile instanceE = TileFactory.createTile( - TileBean.TileType.BLOCK, Orientation.EAST, Direction.CENTER, 220, 220, false); + TileBean.TileType.BLOCK, Orientation.EAST, Direction.CENTER, 220, 220); Tile instanceW = TileFactory.createTile( - TileBean.TileType.BLOCK, Orientation.WEST, Direction.CENTER, 220, 220, false); + TileBean.TileType.BLOCK, Orientation.WEST, Direction.CENTER, 220, 220); Tile instanceS = TileFactory.createTile( - TileBean.TileType.BLOCK, Orientation.SOUTH, Direction.CENTER, 220, 220, false); + TileBean.TileType.BLOCK, Orientation.SOUTH, Direction.CENTER, 220, 220); Tile instanceN = TileFactory.createTile( - TileBean.TileType.BLOCK, Orientation.NORTH, Direction.CENTER, 220, 220, false); + TileBean.TileType.BLOCK, Orientation.NORTH, Direction.CENTER, 220, 220); Tile west = TileFactory.createTile( - TileBean.TileType.STRAIGHT, Orientation.WEST, Direction.CENTER, 140, 220, false); + TileBean.TileType.STRAIGHT, Orientation.WEST, Direction.CENTER, 140, 220); Tile east = TileFactory.createTile( - TileBean.TileType.STRAIGHT, Orientation.EAST, Direction.CENTER, 300, 220, false); + TileBean.TileType.STRAIGHT, Orientation.EAST, Direction.CENTER, 300, 220); Tile north = TileFactory.createTile( - TileBean.TileType.STRAIGHT, Orientation.NORTH, Direction.CENTER, 220, 140, false); + TileBean.TileType.STRAIGHT, Orientation.NORTH, Direction.CENTER, 220, 140); Tile south = TileFactory.createTile( - TileBean.TileType.STRAIGHT, Orientation.SOUTH, Direction.CENTER, 220, 300, false); + TileBean.TileType.STRAIGHT, Orientation.SOUTH, Direction.CENTER, 220, 300); assertTrue(instanceE.isAdjacent(west)); assertTrue(instanceE.isAdjacent(east)); @@ -380,29 +370,29 @@ public void testIsAdjacentCurved() { System.out.println("isAdjacentCurved"); Tile instanceE = TileFactory.createTile( - TileBean.TileType.CURVED, Orientation.EAST, Direction.CENTER, 860, 140, false); + TileBean.TileType.CURVED, Orientation.EAST, Direction.CENTER, 860, 140); Tile instanceN = TileFactory.createTile( - TileBean.TileType.CURVED, Orientation.NORTH, Direction.CENTER, 860, 140, false); + TileBean.TileType.CURVED, Orientation.NORTH, Direction.CENTER, 860, 140); Tile instanceW = TileFactory.createTile( - TileBean.TileType.CURVED, Orientation.WEST, Direction.CENTER, 860, 140, false); + TileBean.TileType.CURVED, Orientation.WEST, Direction.CENTER, 860, 140); Tile instanceS = TileFactory.createTile( - TileBean.TileType.CURVED, Orientation.SOUTH, Direction.CENTER, 860, 140, false); + TileBean.TileType.CURVED, Orientation.SOUTH, Direction.CENTER, 860, 140); Tile straightE = TileFactory.createTile( - TileBean.TileType.STRAIGHT, Orientation.EAST, Direction.CENTER, 900, 140, false); + TileBean.TileType.STRAIGHT, Orientation.EAST, Direction.CENTER, 900, 140); Tile straightN = TileFactory.createTile( - TileBean.TileType.STRAIGHT, Orientation.NORTH, Direction.CENTER, 860, 100, false); + TileBean.TileType.STRAIGHT, Orientation.NORTH, Direction.CENTER, 860, 100); Tile straightW = TileFactory.createTile( - TileBean.TileType.STRAIGHT, Orientation.WEST, Direction.CENTER, 820, 140, false); + TileBean.TileType.STRAIGHT, Orientation.WEST, Direction.CENTER, 820, 140); Tile straightS = TileFactory.createTile( - TileBean.TileType.STRAIGHT, Orientation.SOUTH, Direction.CENTER, 860, 180, false); + TileBean.TileType.STRAIGHT, Orientation.SOUTH, Direction.CENTER, 860, 180); assertTrue(instanceE.isAdjacent(straightE)); assertFalse(instanceE.isAdjacent(straightN)); @@ -431,29 +421,29 @@ public void testIsAdjacentEnd() { Tile instanceE = TileFactory.createTile( - TileBean.TileType.END, Orientation.EAST, Direction.CENTER, 860, 140, false); + TileBean.TileType.END, Orientation.EAST, Direction.CENTER, 860, 140); Tile instanceS = TileFactory.createTile( - TileBean.TileType.END, Orientation.SOUTH, Direction.CENTER, 860, 140, false); + TileBean.TileType.END, Orientation.SOUTH, Direction.CENTER, 860, 140); Tile instanceW = TileFactory.createTile( - TileBean.TileType.END, Orientation.WEST, Direction.CENTER, 860, 140, false); + TileBean.TileType.END, Orientation.WEST, Direction.CENTER, 860, 140); Tile instanceN = TileFactory.createTile( - TileBean.TileType.END, Orientation.NORTH, Direction.CENTER, 860, 140, false); + TileBean.TileType.END, Orientation.NORTH, Direction.CENTER, 860, 140); Tile straightE = TileFactory.createTile( - TileBean.TileType.STRAIGHT, Orientation.EAST, Direction.CENTER, 900, 140, false); + TileBean.TileType.STRAIGHT, Orientation.EAST, Direction.CENTER, 900, 140); Tile straightN = TileFactory.createTile( - TileBean.TileType.STRAIGHT, Orientation.NORTH, Direction.CENTER, 860, 100, false); + TileBean.TileType.STRAIGHT, Orientation.NORTH, Direction.CENTER, 860, 100); Tile straightW = TileFactory.createTile( - TileBean.TileType.STRAIGHT, Orientation.WEST, Direction.CENTER, 820, 140, false); + TileBean.TileType.STRAIGHT, Orientation.WEST, Direction.CENTER, 820, 140); Tile straightS = TileFactory.createTile( - TileBean.TileType.STRAIGHT, Orientation.SOUTH, Direction.CENTER, 860, 180, false); + TileBean.TileType.STRAIGHT, Orientation.SOUTH, Direction.CENTER, 860, 180); assertFalse(instanceE.isAdjacent(straightE)); assertFalse(instanceE.isAdjacent(straightS)); @@ -481,30 +471,30 @@ public void testgetIdSuffix() { System.out.println("getGetIdSuffix"); Tile instanceE = TileFactory.createTile( - TileBean.TileType.BLOCK, Orientation.EAST, Direction.CENTER, 220, 220, false); + TileBean.TileType.BLOCK, Orientation.EAST, Direction.CENTER, 220, 220); Tile instanceW = TileFactory.createTile( - TileBean.TileType.BLOCK, Orientation.WEST, Direction.CENTER, 220, 220, false); + TileBean.TileType.BLOCK, Orientation.WEST, Direction.CENTER, 220, 220); Tile instanceN = TileFactory.createTile( - TileBean.TileType.BLOCK, Orientation.NORTH, Direction.CENTER, 220, 220, false); + TileBean.TileType.BLOCK, Orientation.NORTH, Direction.CENTER, 220, 220); Tile instanceS = TileFactory.createTile( - TileBean.TileType.BLOCK, Orientation.SOUTH, Direction.CENTER, 220, 220, false); + TileBean.TileType.BLOCK, Orientation.SOUTH, Direction.CENTER, 220, 220); Tile west = TileFactory.createTile( - TileBean.TileType.STRAIGHT, Orientation.WEST, Direction.CENTER, 140, 220, false); + TileBean.TileType.STRAIGHT, Orientation.WEST, Direction.CENTER, 140, 220); Tile east = TileFactory.createTile( - TileBean.TileType.STRAIGHT, Orientation.EAST, Direction.CENTER, 300, 220, false); + TileBean.TileType.STRAIGHT, Orientation.EAST, Direction.CENTER, 300, 220); Tile north = TileFactory.createTile( - TileBean.TileType.STRAIGHT, Orientation.NORTH, Direction.CENTER, 220, 140, false); + TileBean.TileType.STRAIGHT, Orientation.NORTH, Direction.CENTER, 220, 140); Tile south = TileFactory.createTile( - TileBean.TileType.STRAIGHT, Orientation.NORTH, Direction.CENTER, 220, 300, false); + TileBean.TileType.STRAIGHT, Orientation.NORTH, Direction.CENTER, 220, 300); String expResult = "-"; String result = instanceE.getIdSuffix(west); @@ -535,55 +525,55 @@ public void testIsAdjacentSwitchL() { System.out.println("isAdjacentSwitchL"); Tile instanceE = TileFactory.createTile( - TileBean.TileType.SWITCH, Orientation.EAST, Direction.LEFT, 1060, 140, false); + TileBean.TileType.SWITCH, Orientation.EAST, Direction.LEFT, 1060, 140); Tile instanceS = TileFactory.createTile( - TileBean.TileType.SWITCH, Orientation.SOUTH, Direction.LEFT, 1060, 140, false); + TileBean.TileType.SWITCH, Orientation.SOUTH, Direction.LEFT, 1060, 140); Tile instanceW = TileFactory.createTile( - TileBean.TileType.SWITCH, Orientation.WEST, Direction.LEFT, 1060, 140, false); + TileBean.TileType.SWITCH, Orientation.WEST, Direction.LEFT, 1060, 140); Tile instanceN = TileFactory.createTile( - TileBean.TileType.SWITCH, Orientation.NORTH, Direction.LEFT, 1060, 140, false); + TileBean.TileType.SWITCH, Orientation.NORTH, Direction.LEFT, 1060, 140); Tile north = TileFactory.createTile( - TileBean.TileType.STRAIGHT, Orientation.NORTH, Direction.CENTER, 1060, 100, false); + TileBean.TileType.STRAIGHT, Orientation.NORTH, Direction.CENTER, 1060, 100); Tile west = TileFactory.createTile( - TileBean.TileType.STRAIGHT, Orientation.WEST, Direction.CENTER, 1020, 140, false); + TileBean.TileType.STRAIGHT, Orientation.WEST, Direction.CENTER, 1020, 140); Tile east = TileFactory.createTile( - TileBean.TileType.STRAIGHT, Orientation.EAST, Direction.CENTER, 1100, 140, false); + TileBean.TileType.STRAIGHT, Orientation.EAST, Direction.CENTER, 1100, 140); Tile south = TileFactory.createTile( - TileBean.TileType.STRAIGHT, Orientation.SOUTH, Direction.CENTER, 1060, 180, false); + TileBean.TileType.STRAIGHT, Orientation.SOUTH, Direction.CENTER, 1060, 180); Tile westCS = TileFactory.createTile( - TileBean.TileType.CURVED, Orientation.SOUTH, Direction.CENTER, 1020, 140, false); + TileBean.TileType.CURVED, Orientation.SOUTH, Direction.CENTER, 1020, 140); Tile westCE = TileFactory.createTile( - TileBean.TileType.CURVED, Orientation.EAST, Direction.CENTER, 1020, 140, false); + TileBean.TileType.CURVED, Orientation.EAST, Direction.CENTER, 1020, 140); Tile westCW = TileFactory.createTile( - TileBean.TileType.CURVED, Orientation.WEST, Direction.CENTER, 1020, 140, false); + TileBean.TileType.CURVED, Orientation.WEST, Direction.CENTER, 1020, 140); Tile westCN = TileFactory.createTile( - TileBean.TileType.CURVED, Orientation.NORTH, Direction.CENTER, 1020, 140, false); + TileBean.TileType.CURVED, Orientation.NORTH, Direction.CENTER, 1020, 140); Tile southCS = TileFactory.createTile( - TileBean.TileType.CURVED, Orientation.SOUTH, Direction.CENTER, 1060, 180, false); + TileBean.TileType.CURVED, Orientation.SOUTH, Direction.CENTER, 1060, 180); Tile southCE = TileFactory.createTile( - TileBean.TileType.CURVED, Orientation.EAST, Direction.CENTER, 1060, 180, false); + TileBean.TileType.CURVED, Orientation.EAST, Direction.CENTER, 1060, 180); Tile southCW = TileFactory.createTile( - TileBean.TileType.CURVED, Orientation.WEST, Direction.CENTER, 1060, 180, false); + TileBean.TileType.CURVED, Orientation.WEST, Direction.CENTER, 1060, 180); Tile southCN = TileFactory.createTile( - TileBean.TileType.CURVED, Orientation.NORTH, Direction.CENTER, 1060, 180, false); + TileBean.TileType.CURVED, Orientation.NORTH, Direction.CENTER, 1060, 180); assertTrue(instanceE.isAdjacent(west)); assertTrue(instanceE.isAdjacent(east)); @@ -621,55 +611,55 @@ public void testIsAdjacentSwitchR() { System.out.println("isAdjacentSwitchR"); Tile instanceE = TileFactory.createTile( - TileBean.TileType.SWITCH, Orientation.EAST, Direction.RIGHT, 1060, 140, false); + TileBean.TileType.SWITCH, Orientation.EAST, Direction.RIGHT, 1060, 140); Tile instanceS = TileFactory.createTile( - TileBean.TileType.SWITCH, Orientation.SOUTH, Direction.RIGHT, 1060, 140, false); + TileBean.TileType.SWITCH, Orientation.SOUTH, Direction.RIGHT, 1060, 140); Tile instanceW = TileFactory.createTile( - TileBean.TileType.SWITCH, Orientation.WEST, Direction.RIGHT, 1060, 140, false); + TileBean.TileType.SWITCH, Orientation.WEST, Direction.RIGHT, 1060, 140); Tile instanceN = TileFactory.createTile( - TileBean.TileType.SWITCH, Orientation.NORTH, Direction.RIGHT, 1060, 140, false); + TileBean.TileType.SWITCH, Orientation.NORTH, Direction.RIGHT, 1060, 140); Tile north = TileFactory.createTile( - TileBean.TileType.STRAIGHT, Orientation.NORTH, Direction.CENTER, 1060, 100, false); + TileBean.TileType.STRAIGHT, Orientation.NORTH, Direction.CENTER, 1060, 100); Tile west = TileFactory.createTile( - TileBean.TileType.STRAIGHT, Orientation.WEST, Direction.CENTER, 1020, 140, false); + TileBean.TileType.STRAIGHT, Orientation.WEST, Direction.CENTER, 1020, 140); Tile east = TileFactory.createTile( - TileBean.TileType.STRAIGHT, Orientation.EAST, Direction.CENTER, 1100, 140, false); + TileBean.TileType.STRAIGHT, Orientation.EAST, Direction.CENTER, 1100, 140); Tile south = TileFactory.createTile( - TileBean.TileType.STRAIGHT, Orientation.SOUTH, Direction.CENTER, 1060, 180, false); + TileBean.TileType.STRAIGHT, Orientation.SOUTH, Direction.CENTER, 1060, 180); Tile eastCS = TileFactory.createTile( - TileBean.TileType.CURVED, Orientation.SOUTH, Direction.CENTER, 1100, 140, false); + TileBean.TileType.CURVED, Orientation.SOUTH, Direction.CENTER, 1100, 140); Tile eastCE = TileFactory.createTile( - TileBean.TileType.CURVED, Orientation.EAST, Direction.CENTER, 1100, 140, false); + TileBean.TileType.CURVED, Orientation.EAST, Direction.CENTER, 1100, 140); Tile eastCW = TileFactory.createTile( - TileBean.TileType.CURVED, Orientation.WEST, Direction.CENTER, 1100, 140, false); + TileBean.TileType.CURVED, Orientation.WEST, Direction.CENTER, 1100, 140); Tile eastCN = TileFactory.createTile( - TileBean.TileType.CURVED, Orientation.NORTH, Direction.CENTER, 1100, 140, false); + TileBean.TileType.CURVED, Orientation.NORTH, Direction.CENTER, 1100, 140); Tile northCS = TileFactory.createTile( - TileBean.TileType.CURVED, Orientation.SOUTH, Direction.CENTER, 1060, 100, false); + TileBean.TileType.CURVED, Orientation.SOUTH, Direction.CENTER, 1060, 100); Tile northCE = TileFactory.createTile( - TileBean.TileType.CURVED, Orientation.EAST, Direction.CENTER, 1060, 100, false); + TileBean.TileType.CURVED, Orientation.EAST, Direction.CENTER, 1060, 100); Tile northCW = TileFactory.createTile( - TileBean.TileType.CURVED, Orientation.WEST, Direction.CENTER, 1060, 100, false); + TileBean.TileType.CURVED, Orientation.WEST, Direction.CENTER, 1060, 100); Tile northCN = TileFactory.createTile( - TileBean.TileType.CURVED, Orientation.NORTH, Direction.CENTER, 1060, 100, false); + TileBean.TileType.CURVED, Orientation.NORTH, Direction.CENTER, 1060, 100); assertTrue(instanceE.isAdjacent(west)); assertTrue(instanceE.isAdjacent(east)); @@ -707,29 +697,29 @@ public void testIsArrowSwitchSide() { System.out.println("isArrowSwitchSide"); Tile instanceE = TileFactory.createTile( - TileBean.TileType.STRAIGHT_DIR, Orientation.EAST, Direction.RIGHT, 860, 140, false); + TileBean.TileType.STRAIGHT_DIR, Orientation.EAST, Direction.RIGHT, 860, 140); Tile instanceS = TileFactory.createTile( - TileBean.TileType.STRAIGHT_DIR, Orientation.SOUTH, Direction.RIGHT, 860, 140, false); + TileBean.TileType.STRAIGHT_DIR, Orientation.SOUTH, Direction.RIGHT, 860, 140); Tile instanceW = TileFactory.createTile( - TileBean.TileType.STRAIGHT_DIR, Orientation.WEST, Direction.RIGHT, 860, 140, false); + TileBean.TileType.STRAIGHT_DIR, Orientation.WEST, Direction.RIGHT, 860, 140); Tile instanceN = TileFactory.createTile( - TileBean.TileType.STRAIGHT_DIR, Orientation.NORTH, Direction.RIGHT, 860, 140, false); + TileBean.TileType.STRAIGHT_DIR, Orientation.NORTH, Direction.RIGHT, 860, 140); Tile straighE = TileFactory.createTile( - TileBean.TileType.STRAIGHT, Orientation.EAST, Direction.CENTER, 900, 140, false); + TileBean.TileType.STRAIGHT, Orientation.EAST, Direction.CENTER, 900, 140); Tile straighS = TileFactory.createTile( - TileBean.TileType.STRAIGHT, Orientation.SOUTH, Direction.CENTER, 860, 180, false); + TileBean.TileType.STRAIGHT, Orientation.SOUTH, Direction.CENTER, 860, 180); Tile straighW = TileFactory.createTile( - TileBean.TileType.STRAIGHT, Orientation.WEST, Direction.CENTER, 820, 140, false); + TileBean.TileType.STRAIGHT, Orientation.WEST, Direction.CENTER, 820, 140); Tile straighN = TileFactory.createTile( - TileBean.TileType.STRAIGHT, Orientation.NORTH, Direction.CENTER, 860, 100, false); + TileBean.TileType.STRAIGHT, Orientation.NORTH, Direction.CENTER, 860, 100); assertTrue(instanceE.isArrowDirection(straighE)); assertFalse(instanceE.isArrowDirection(straighW)); @@ -749,53 +739,53 @@ public void testIsAdjacentCrossL() { System.out.println("iIsAdjacentCrossL"); Tile instanceE = TileFactory.createTile( - TileBean.TileType.CROSS, Orientation.EAST, Direction.LEFT, 860, 100, false); + TileBean.TileType.CROSS, Orientation.EAST, Direction.LEFT, 860, 100); Tile instanceS = TileFactory.createTile( - TileBean.TileType.CROSS, Orientation.SOUTH, Direction.LEFT, 860, 100, false); + TileBean.TileType.CROSS, Orientation.SOUTH, Direction.LEFT, 860, 100); Tile instanceW = TileFactory.createTile( - TileBean.TileType.CROSS, Orientation.WEST, Direction.LEFT, 860, 100, false); + TileBean.TileType.CROSS, Orientation.WEST, Direction.LEFT, 860, 100); Tile instanceN = TileFactory.createTile( - TileBean.TileType.CROSS, Orientation.NORTH, Direction.LEFT, 860, 100, false); + TileBean.TileType.CROSS, Orientation.NORTH, Direction.LEFT, 860, 100); Tile north = TileFactory.createTile( - TileBean.TileType.STRAIGHT, Orientation.NORTH, Direction.CENTER, 900, 60, false); + TileBean.TileType.STRAIGHT, Orientation.NORTH, Direction.CENTER, 900, 60); Tile north2 = TileFactory.createTile( - TileBean.TileType.STRAIGHT, Orientation.NORTH, Direction.CENTER, 860, 60, false); + TileBean.TileType.STRAIGHT, Orientation.NORTH, Direction.CENTER, 860, 60); Tile north3 = TileFactory.createTile( - TileBean.TileType.STRAIGHT, Orientation.NORTH, Direction.CENTER, 860, 20, false); + TileBean.TileType.STRAIGHT, Orientation.NORTH, Direction.CENTER, 860, 20); Tile west = TileFactory.createTile( - TileBean.TileType.STRAIGHT, Orientation.WEST, Direction.CENTER, 820, 100, false); + TileBean.TileType.STRAIGHT, Orientation.WEST, Direction.CENTER, 820, 100); Tile west2 = TileFactory.createTile( - TileBean.TileType.STRAIGHT, Orientation.WEST, Direction.CENTER, 780, 100, false); + TileBean.TileType.STRAIGHT, Orientation.WEST, Direction.CENTER, 780, 100); Tile west3 = TileFactory.createTile( - TileBean.TileType.STRAIGHT, Orientation.WEST, Direction.CENTER, 820, 60, false); + TileBean.TileType.STRAIGHT, Orientation.WEST, Direction.CENTER, 820, 60); Tile east = TileFactory.createTile( - TileBean.TileType.STRAIGHT, Orientation.EAST, Direction.CENTER, 940, 100, false); + TileBean.TileType.STRAIGHT, Orientation.EAST, Direction.CENTER, 940, 100); Tile east2 = TileFactory.createTile( - TileBean.TileType.STRAIGHT, Orientation.EAST, Direction.CENTER, 900, 100, false); + TileBean.TileType.STRAIGHT, Orientation.EAST, Direction.CENTER, 900, 100); Tile east3 = TileFactory.createTile( - TileBean.TileType.STRAIGHT, Orientation.EAST, Direction.CENTER, 900, 140, false); + TileBean.TileType.STRAIGHT, Orientation.EAST, Direction.CENTER, 900, 140); Tile south = TileFactory.createTile( - TileBean.TileType.STRAIGHT, Orientation.SOUTH, Direction.CENTER, 860, 140, false); + TileBean.TileType.STRAIGHT, Orientation.SOUTH, Direction.CENTER, 860, 140); Tile south2 = TileFactory.createTile( - TileBean.TileType.STRAIGHT, Orientation.SOUTH, Direction.CENTER, 820, 140, false); + TileBean.TileType.STRAIGHT, Orientation.SOUTH, Direction.CENTER, 820, 140); Tile south3 = TileFactory.createTile( - TileBean.TileType.STRAIGHT, Orientation.SOUTH, Direction.CENTER, 860, 180, false); + TileBean.TileType.STRAIGHT, Orientation.SOUTH, Direction.CENTER, 860, 180); assertTrue(instanceE.isAdjacent(west)); assertTrue(instanceE.isAdjacent(east)); @@ -823,60 +813,60 @@ public void testIsAdjacentCrossR() { System.out.println("iIsAdjacentCrossR"); Tile instanceE = TileFactory.createTile( - TileBean.TileType.CROSS, Orientation.EAST, Direction.RIGHT, 860, 100, false); + TileBean.TileType.CROSS, Orientation.EAST, Direction.RIGHT, 860, 100); Tile instanceS = TileFactory.createTile( - TileBean.TileType.CROSS, Orientation.SOUTH, Direction.RIGHT, 860, 100, false); + TileBean.TileType.CROSS, Orientation.SOUTH, Direction.RIGHT, 860, 100); Tile instanceW = TileFactory.createTile( - TileBean.TileType.CROSS, Orientation.WEST, Direction.RIGHT, 860, 100, false); + TileBean.TileType.CROSS, Orientation.WEST, Direction.RIGHT, 860, 100); Tile instanceN = TileFactory.createTile( - TileBean.TileType.CROSS, Orientation.NORTH, Direction.RIGHT, 860, 100, false); + TileBean.TileType.CROSS, Orientation.NORTH, Direction.RIGHT, 860, 100); Tile north = TileFactory.createTile( - TileBean.TileType.STRAIGHT, Orientation.NORTH, Direction.CENTER, 860, 60, false); + TileBean.TileType.STRAIGHT, Orientation.NORTH, Direction.CENTER, 860, 60); Tile north2 = TileFactory.createTile( - TileBean.TileType.STRAIGHT, Orientation.NORTH, Direction.CENTER, 860, 60, false); + TileBean.TileType.STRAIGHT, Orientation.NORTH, Direction.CENTER, 860, 60); Tile north3 = TileFactory.createTile( - TileBean.TileType.STRAIGHT, Orientation.NORTH, Direction.CENTER, 860, 20, false); + TileBean.TileType.STRAIGHT, Orientation.NORTH, Direction.CENTER, 860, 20); Tile north4 = TileFactory.createTile( - TileBean.TileType.STRAIGHT, Orientation.NORTH, Direction.CENTER, 820, 60, false); + TileBean.TileType.STRAIGHT, Orientation.NORTH, Direction.CENTER, 820, 60); Tile west = TileFactory.createTile( - TileBean.TileType.STRAIGHT, Orientation.WEST, Direction.CENTER, 820, 140, false); + TileBean.TileType.STRAIGHT, Orientation.WEST, Direction.CENTER, 820, 140); Tile west2 = TileFactory.createTile( - TileBean.TileType.STRAIGHT, Orientation.WEST, Direction.CENTER, 820, 100, false); + TileBean.TileType.STRAIGHT, Orientation.WEST, Direction.CENTER, 820, 100); Tile west3 = TileFactory.createTile( - TileBean.TileType.STRAIGHT, Orientation.WEST, Direction.CENTER, 860, 100, false); + TileBean.TileType.STRAIGHT, Orientation.WEST, Direction.CENTER, 860, 100); Tile west4 = TileFactory.createTile( - TileBean.TileType.STRAIGHT, Orientation.WEST, Direction.CENTER, 780, 100, false); + TileBean.TileType.STRAIGHT, Orientation.WEST, Direction.CENTER, 780, 100); Tile east = TileFactory.createTile( - TileBean.TileType.STRAIGHT, Orientation.EAST, Direction.CENTER, 940, 100, false); + TileBean.TileType.STRAIGHT, Orientation.EAST, Direction.CENTER, 940, 100); Tile east2 = TileFactory.createTile( - TileBean.TileType.STRAIGHT, Orientation.EAST, Direction.CENTER, 900, 60, false); + TileBean.TileType.STRAIGHT, Orientation.EAST, Direction.CENTER, 900, 60); Tile east3 = TileFactory.createTile( - TileBean.TileType.STRAIGHT, Orientation.EAST, Direction.CENTER, 900, 100, false); + TileBean.TileType.STRAIGHT, Orientation.EAST, Direction.CENTER, 900, 100); Tile south = TileFactory.createTile( - TileBean.TileType.STRAIGHT, Orientation.SOUTH, Direction.CENTER, 860, 140, false); + TileBean.TileType.STRAIGHT, Orientation.SOUTH, Direction.CENTER, 860, 140); Tile south2 = TileFactory.createTile( - TileBean.TileType.STRAIGHT, Orientation.SOUTH, Direction.CENTER, 900, 140, false); + TileBean.TileType.STRAIGHT, Orientation.SOUTH, Direction.CENTER, 900, 140); Tile south3 = TileFactory.createTile( - TileBean.TileType.STRAIGHT, Orientation.SOUTH, Direction.CENTER, 860, 180, false); + TileBean.TileType.STRAIGHT, Orientation.SOUTH, Direction.CENTER, 860, 180); assertTrue(instanceE.isAdjacent(west2)); assertTrue(instanceE.isAdjacent(east)); @@ -902,14 +892,14 @@ public void testIsAdjacentCrossR() { @Test public void testIsAdjacentCrossing() { System.out.println("isAdjacentCrossing"); - Tile instanceE = TileFactory.createTile(TileBean.TileType.CROSSING, Orientation.EAST, Direction.CENTER, 100, 100, false); + Tile instanceE = TileFactory.createTile(TileBean.TileType.CROSSING, Orientation.EAST, Direction.CENTER, 100, 100); - Tile instanceN = TileFactory.createTile(TileBean.TileType.CROSSING, Orientation.NORTH, Direction.CENTER, 100, 100, false); + Tile instanceN = TileFactory.createTile(TileBean.TileType.CROSSING, Orientation.NORTH, Direction.CENTER, 100, 100); - Tile west = TileFactory.createTile(TileBean.TileType.STRAIGHT, Orientation.WEST, Direction.CENTER, 60, 100, false); - Tile east = TileFactory.createTile(TileBean.TileType.STRAIGHT, Orientation.EAST, Direction.CENTER, 140, 100, false); - Tile north = TileFactory.createTile(TileBean.TileType.STRAIGHT, Orientation.NORTH, Direction.CENTER, 100, 60, false); - Tile south = TileFactory.createTile(TileBean.TileType.STRAIGHT, Orientation.SOUTH, Direction.CENTER, 100, 140, false); + Tile west = TileFactory.createTile(TileBean.TileType.STRAIGHT, Orientation.WEST, Direction.CENTER, 60, 100); + Tile east = TileFactory.createTile(TileBean.TileType.STRAIGHT, Orientation.EAST, Direction.CENTER, 140, 100); + Tile north = TileFactory.createTile(TileBean.TileType.STRAIGHT, Orientation.NORTH, Direction.CENTER, 100, 60); + Tile south = TileFactory.createTile(TileBean.TileType.STRAIGHT, Orientation.SOUTH, Direction.CENTER, 100, 140); assertTrue(instanceE.isAdjacent(west)); assertTrue(instanceE.isAdjacent(east)); diff --git a/src/test/java/jcs/ui/layout/tiles/DotGridCanvas.java b/src/test/java/jcs/ui/layout/tiles/DotGridCanvas.java index a789e06b..d9b5d190 100644 --- a/src/test/java/jcs/ui/layout/tiles/DotGridCanvas.java +++ b/src/test/java/jcs/ui/layout/tiles/DotGridCanvas.java @@ -23,24 +23,19 @@ import javax.swing.JPanel; import org.tinylog.Logger; + +// jcs.ui.layout.tiles.DotGridCanvas + public class DotGridCanvas extends JPanel { + private boolean expanded; + public DotGridCanvas() { super(null, false); setOpaque(true); - setBackground(Color.white); + //setBackground(Color.white); } -// @Override -// protected void paintComponent(Graphics g) { -// long started = System.currentTimeMillis(); -// super.paintComponent(g); -// -// paintDotGrid(g); -// long now = System.currentTimeMillis(); -// Logger.trace("Duration: " + (now - started) + " ms."); -// } - @Override public void paint(Graphics g) { long started = System.currentTimeMillis(); @@ -50,9 +45,7 @@ public void paint(Graphics g) { long now = System.currentTimeMillis(); Logger.trace("Duration: " + (now - started) + " ms."); } - - - + @Override public Component add(Component component) { super.add(component); @@ -66,20 +59,33 @@ private void paintDotGrid(Graphics g) { int width = this.getWidth(); int height = this.getHeight(); - int xOffset = 0; - int yOffset = 0; + int grid; + if (expanded) { + grid = 20; + } else { + grid = 20; + } - //Logger.trace("W: " + width + " H: " + height + " X: " + this.getX() + " Y: " + this.getY()); Graphics2D gc = (Graphics2D) g; Paint p = gc.getPaint(); gc.setPaint(Color.black); for (int r = 0; r < width; r++) { for (int c = 0; c < height; c++) { - gc.drawOval((r * 20 * 2) + xOffset - 2, (c * 20 * 2) + yOffset - 2, 4, 4); + gc.drawOval((r * grid * 2) - 2, (c * grid * 2) - 2, 4, 4); } } gc.setPaint(p); + + } + + public boolean isExpanded() { + return expanded; + } + + public void setExpanded(boolean expanded) { + this.expanded = expanded; + this.repaint(); } } diff --git a/src/test/java/jcs/ui/layout/tiles/UnscaledTileFrame.form b/src/test/java/jcs/ui/layout/tiles/TileTesterFrame.form similarity index 91% rename from src/test/java/jcs/ui/layout/tiles/UnscaledTileFrame.form rename to src/test/java/jcs/ui/layout/tiles/TileTesterFrame.form index a7bb9ab5..9b77fbc1 100644 --- a/src/test/java/jcs/ui/layout/tiles/UnscaledTileFrame.form +++ b/src/test/java/jcs/ui/layout/tiles/TileTesterFrame.form @@ -22,12 +22,20 @@ - + + + + + + + + + @@ -162,12 +170,20 @@
- + + + + + + + + + - + - + @@ -390,11 +406,27 @@ - - + + + + + + + + + + + + + + + + + + - + @@ -402,15 +434,12 @@
- + - + - - - diff --git a/src/test/java/jcs/ui/layout/tiles/UnscaledTileFrame.java b/src/test/java/jcs/ui/layout/tiles/TileTesterFrame.java similarity index 74% rename from src/test/java/jcs/ui/layout/tiles/UnscaledTileFrame.java rename to src/test/java/jcs/ui/layout/tiles/TileTesterFrame.java index 43e5bf53..c5e311b7 100644 --- a/src/test/java/jcs/ui/layout/tiles/UnscaledTileFrame.java +++ b/src/test/java/jcs/ui/layout/tiles/TileTesterFrame.java @@ -16,11 +16,9 @@ package jcs.ui.layout.tiles; import java.awt.Color; -import java.awt.Graphics; import java.awt.Point; import javax.swing.ComboBoxModel; import javax.swing.DefaultComboBoxModel; -import javax.swing.JComponent; import javax.swing.UIManager; import javax.swing.UnsupportedLookAndFeelException; import jcs.entities.AccessoryBean; @@ -32,29 +30,26 @@ import static jcs.entities.TileBean.Orientation.SOUTH; import static jcs.entities.TileBean.Orientation.WEST; import jcs.entities.TileBean.TileType; +import jcs.ui.layout.LayoutUtil; import jcs.ui.layout.events.TileEvent; import org.tinylog.Logger; -/** - * - * @author FJA - */ -public class UnscaledTileFrame extends javax.swing.JFrame { +public class TileTesterFrame extends javax.swing.JFrame { private Tile tile; - /** - * Creates new form UnscaledBlockTileFrame - */ - public UnscaledTileFrame() { + public TileTesterFrame() { initComponents(); this.tileCB.setModel(createTileTypeComboBoxModel()); this.orientationCB.setModel(createOrientationComboBoxModel()); this.incomingSideCB.setModel(createOrientationComboBoxModel()); this.directionCB.setModel(createDirectionComboBoxModel(true)); - //drawTile(); - addTile(); + createTile(); + + pack(); + + setVisible(true); } private ComboBoxModel createTileTypeComboBoxModel() { @@ -97,75 +92,78 @@ private ComboBoxModel createDirectionComboBoxModel(boolean dontCare) return directionModel; } - private void addTile() { - if (this.tile != null) { - Logger.trace("Removing tile " + this.tile.getId()); - this.cPanel.remove((JComponent) this.tile); - this.tile = null; + private void createTile() { + if (tile != null) { + Logger.trace("Removing tile " + tile.getId()); + canvas.remove(tile); + tile = null; } - TileType tileType = (TileType) this.tileCB.getSelectedItem(); - Orientation orientation = (Orientation) this.orientationCB.getSelectedItem(); + TileType tileType = (TileType) tileCB.getSelectedItem(); + Orientation orientation = (Orientation) orientationCB.getSelectedItem(); if (TileType.SWITCH == tileType || TileType.CROSS == tileType) { - this.directionCB.setModel(createDirectionComboBoxModel(false)); + directionCB.setModel(createDirectionComboBoxModel(false)); } else { - this.directionCB.setModel(createDirectionComboBoxModel(true)); + directionCB.setModel(createDirectionComboBoxModel(true)); } Direction direction = (Direction) this.directionCB.getSelectedItem(); - boolean showOutline = this.drawOutlineCB.isSelected(); - - int w = this.cPanel.getWidth(); - int h = this.cPanel.getHeight(); - - int x; - int y; - if (TileType.CROSS == tileType) { - switch (orientation) { - case SOUTH -> { - x = w / 2 + 200; - y = h / 2 - 150; - } - case WEST -> { - x = w / 2 + 400; - y = h / 2 + 50; - } - case NORTH -> { - x = w / 2 + 200; - y = h / 2 + 250; - } - default -> { - x = w / 2; - y = h / 2 + 50; - } - } - } else { - x = w / 2 - 200; - y = h / 2 - 200; - } - - Point center; - if (TileType.CROSS.equals(tileType)) { - center = new Point(x - 200, y); - } else { - center = new Point(x, y); - } - - Tile newTile = TileFactory.createTile(tileType, orientation, direction, center, showOutline); - newTile.setScaleImage(false); + boolean scale = !scaleCB.isSelected(); + boolean showCenter = showCenterCB.isSelected(); + + int w = canvas.getWidth(); + int h = canvas.getHeight(); + + int x = w / 2; + int y = h / 2; + Point tileCenter = new Point(x, y); + tileCenter = LayoutUtil.snapToGrid(tileCenter); + +// if (TileType.CROSS == tileType) { +// switch (orientation) { +// case SOUTH -> { +// x = w / 2 + 200; +// y = h / 2 - 150; +// } +// case WEST -> { +// x = w / 2 + 400; +// y = h / 2 + 50; +// } +// case NORTH -> { +// x = w / 2 + 200; +// y = h / 2 + 250; +// } +// default -> { +// x = w / 2; +// y = h / 2 + 50; +// } +// } +// } else { +// x = w / 2 - 200; +// y = h / 2 - 200; +// } +// Point center; +// if (TileType.CROSS.equals(tileType)) { +// center = new Point(x - 200, y); +// } else { +// center = new Point(x, y); +// } + Tile newTile = TileFactory.createTile(tileType, orientation, direction, tileCenter); + newTile.setScaleImage(scale); + newTile.setDrawCenterPoint(showCenter); //tile.setPropertyChangeListener(this); Orientation incomingSide = (Orientation) this.incomingSideCB.getSelectedItem(); newTile.setIncomingSide(incomingSide); - newTile.setDrawRoute(this.displayRouteCB.isSelected()); + newTile.setDrawRoute(displayRouteCB.isSelected()); newTile.setTrackRouteColor(Color.blue); Logger.trace("Adding tile " + newTile.getId() + " " + newTile.xyToString()); //this.cPanel.add((JComponent) newTile); - this.cPanel.add(newTile); + this.canvas.add(newTile); this.tile = newTile; } @@ -183,6 +181,10 @@ private AccessoryValue getAccessoryState() { } private void changeAccesoryState() { + if(tile instanceof Sensor) { + tile.setActive(this.redRB.isSelected()); + } + if (tile instanceof Switch aSwitch) { if (this.displayRouteCB.isSelected()) { aSwitch.setRouteValue(getAccessoryState()); @@ -201,7 +203,7 @@ private void changeAccesoryState() { } } - this.tile.repaint(); + //this.tile.repaint(); } // @Override @@ -227,15 +229,14 @@ private void changeAccesoryState() { // tile.drawCenterPoint(g2d, Color.red); // } // } - @Override - public void paint(Graphics g) { - long started = System.currentTimeMillis(); - super.paint(g); - - long now = System.currentTimeMillis(); - Logger.trace("Duration: " + (now - started) + " ms."); - } - +// @Override +// public void paint(Graphics g) { +// long started = System.currentTimeMillis(); +// super.paint(g); +// +// long now = System.currentTimeMillis(); +// Logger.trace("Duration: " + (now - started) + " ms."); +// } private void changeDirection() { Direction direction = (Direction) this.directionCB.getSelectedItem(); this.tile.setDirection(direction); @@ -247,39 +248,38 @@ private void changeDirection() { } private void rotateTile() { - this.tile.rotate(); - - if (TileType.CROSS == tile.getTileType()) { - int x = tile.getCenterX(); - int y = tile.getCenterY(); - int w = tile.getWidth() * 10; - int h = tile.getHeight() * 10; - - //calculate a new centerpoint for cross - switch (tile.getOrientation()) { - case SOUTH -> { - x = x + w / 2; - y = y - h / 4; - } - case WEST -> { - x = x + w / 4; - y = y + h / 2; - } - case NORTH -> { - x = x - w / 2; - y = y + h / 4; - } - default -> { - x = x - w / 4; - y = y - h / 2; - } - } - tile.setCenter(new Point(x, y)); - } - - this.orientationCB.setSelectedItem(tile.getOrientation()); - - //this.repaint(); + Orientation newOrientation = tile.rotate(); + orientationCB.setSelectedItem(newOrientation); + +// if (TileType.CROSS == tile.getTileType()) { +// int x = tile.getCenterX(); +// int y = tile.getCenterY(); +// int w = tile.getWidth() * 10; +// int h = tile.getHeight() * 10; +// +// //calculate a new centerpoint for cross +// switch (tile.getOrientation()) { +// case SOUTH -> { +// x = x + w / 2; +// y = y - h / 4; +// } +// case WEST -> { +// x = x + w / 4; +// y = y + h / 2; +// } +// case NORTH -> { +// x = x - w / 2; +// y = y + h / 4; +// } +// default -> { +// x = x - w / 4; +// y = y - h / 2; +// } +// } +// tile.setCenter(new Point(x, y)); +// } + //this.canvas.repaint(this.tile.getTileBounds()); + //tile.repaint(); } private void changeOrientation() { @@ -326,12 +326,12 @@ private void showRoute() { String tileId = tile.getId(); Orientation incomingSide = (Orientation) this.incomingSideCB.getSelectedItem(); - TileEvent tileEvent; + //TileEvent tileEvent; if (tile.isJunction()) { AccessoryValue routeState = getAccessoryState(); - tileEvent = new TileEvent(tileId, true, incomingSide, routeState); + //tileEvent = new TileEvent(tileId, true, incomingSide, routeState); } else { - tileEvent = new TileEvent(tileId, true, incomingSide); + //tileEvent = new TileEvent(tileId, true, incomingSide); } //TileCache.fireTileEventListener(tileEvent); @@ -340,9 +340,9 @@ private void showRoute() { //repaint(); } - private void showOutline() { - //repaint(); - } +// private void showOutline() { +// //repaint(); +// } private void changeIncomingSide() { Orientation incomingSide = (Orientation) this.incomingSideCB.getSelectedItem(); @@ -369,11 +369,14 @@ private void initComponents() { greenRB = new javax.swing.JRadioButton(); redRB = new javax.swing.JRadioButton(); displayRouteCB = new javax.swing.JCheckBox(); - drawOutlineCB = new javax.swing.JCheckBox(); - cPanel = new javax.swing.JPanel(); + scaleCB = new javax.swing.JCheckBox(); + showCenterCB = new javax.swing.JCheckBox(); + canvas = new jcs.ui.layout.tiles.DotGridCanvas(); setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE); + nPanel.setMinimumSize(new java.awt.Dimension(860, 36)); + nPanel.setPreferredSize(new java.awt.Dimension(1020, 36)); java.awt.FlowLayout flowLayout1 = new java.awt.FlowLayout(java.awt.FlowLayout.LEFT); flowLayout1.setAlignOnBaseline(true); nPanel.setLayout(flowLayout1); @@ -460,20 +463,26 @@ public void actionPerformed(java.awt.event.ActionEvent evt) { }); nPanel.add(displayRouteCB); - drawOutlineCB.setText("Outline"); - drawOutlineCB.addActionListener(new java.awt.event.ActionListener() { + scaleCB.setText("Scale"); + scaleCB.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + scaleCBActionPerformed(evt); + } + }); + nPanel.add(scaleCB); + + showCenterCB.setText("Center"); + showCenterCB.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { - drawOutlineCBActionPerformed(evt); + showCenterCBActionPerformed(evt); } }); - nPanel.add(drawOutlineCB); + nPanel.add(showCenterCB); getContentPane().add(nPanel, java.awt.BorderLayout.NORTH); - cPanel.setPreferredSize(new java.awt.Dimension(800, 800)); - cPanel.setLayout(null); - getContentPane().add(cPanel, java.awt.BorderLayout.CENTER); - cPanel.getAccessibleContext().setAccessibleDescription(""); + canvas.setPreferredSize(new java.awt.Dimension(600, 600)); + getContentPane().add(canvas, java.awt.BorderLayout.CENTER); pack(); }// //GEN-END:initComponents @@ -483,10 +492,7 @@ private void rotateButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN- }//GEN-LAST:event_rotateButtonActionPerformed private void tileCBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_tileCBActionPerformed - addTile(); - //this.tile.repaint(); - - this.repaint(); + createTile(); }//GEN-LAST:event_tileCBActionPerformed private void orientationCBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_orientationCBActionPerformed @@ -513,14 +519,19 @@ private void displayRouteCBActionPerformed(java.awt.event.ActionEvent evt) {//GE showRoute(); }//GEN-LAST:event_displayRouteCBActionPerformed - private void drawOutlineCBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_drawOutlineCBActionPerformed - showOutline(); - }//GEN-LAST:event_drawOutlineCBActionPerformed + private void scaleCBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_scaleCBActionPerformed + this.tile.setScaleImage(!this.scaleCB.isSelected()); + this.tile.setBounds(this.tile.getTileBounds()); + }//GEN-LAST:event_scaleCBActionPerformed private void incomingSideCBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_incomingSideCBActionPerformed changeIncomingSide(); }//GEN-LAST:event_incomingSideCBActionPerformed + private void showCenterCBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_showCenterCBActionPerformed + this.tile.setDrawCenterPoint(this.showCenterCB.isSelected()); + }//GEN-LAST:event_showCenterCBActionPerformed + /** * @param args the command line arguments */ @@ -533,20 +544,17 @@ public static void main(String args[]) { /* Create and display the form */ java.awt.EventQueue.invokeLater(() -> { - UnscaledTileFrame app = new UnscaledTileFrame(); - app.setTitle("Unscaled Tile Tester"); - //app.pack(); + TileTesterFrame app = new TileTesterFrame(); + app.setTitle("Tile Tester"); app.setLocationRelativeTo(null); - app.setVisible(true); }); } // Variables declaration - do not modify//GEN-BEGIN:variables private javax.swing.ButtonGroup accessoryBG; - private javax.swing.JPanel cPanel; + private jcs.ui.layout.tiles.DotGridCanvas canvas; private javax.swing.JComboBox directionCB; private javax.swing.JCheckBox displayRouteCB; - private javax.swing.JCheckBox drawOutlineCB; private javax.swing.JRadioButton greenRB; private javax.swing.JLabel inComingLbl; private javax.swing.JComboBox incomingSideCB; @@ -555,6 +563,8 @@ public static void main(String args[]) { private javax.swing.JComboBox orientationCB; private javax.swing.JRadioButton redRB; private javax.swing.JButton rotateButton; + private javax.swing.JCheckBox scaleCB; + private javax.swing.JCheckBox showCenterCB; private javax.swing.JComboBox tileCB; // End of variables declaration//GEN-END:variables } From 11edd00824785d47247c367613e170415c6d4df0 Mon Sep 17 00:00:00 2001 From: fja-itank Date: Mon, 27 Jan 2025 13:22:17 +0100 Subject: [PATCH 09/24] Fix Cross --- nb-configuration.xml | 40 +- src/main/java/jcs/ui/layout/tiles/Block.java | 784 +----------- src/main/java/jcs/ui/layout/tiles/Cross.java | 656 +--------- src/main/java/jcs/ui/layout/tiles/Tile.java | 1132 +---------------- .../jcs/ui/layout/tiles/TileTesterFrame.form | 455 +------ .../jcs/ui/layout/tiles/TileTesterFrame.java | 571 +-------- 6 files changed, 6 insertions(+), 3632 deletions(-) diff --git a/nb-configuration.xml b/nb-configuration.xml index e5ed60ac..5490e808 100644 --- a/nb-configuration.xml +++ b/nb-configuration.xml @@ -1,39 +1 @@ - - - - - - apache20 - true - 4 - 2 - 4 - 2 - 2 - none - 2 - 2 - true - 2 - 200 - true - none - 4 - 4 - 8 - 80 - true - project - all - - + apache20 true 4 2 4 2 2 none 2 2 true 2 200 true none 4 4 8 80 true project all true true LF false \ No newline at end of file diff --git a/src/main/java/jcs/ui/layout/tiles/Block.java b/src/main/java/jcs/ui/layout/tiles/Block.java index 105cfcdb..e98fa594 100755 --- a/src/main/java/jcs/ui/layout/tiles/Block.java +++ b/src/main/java/jcs/ui/layout/tiles/Block.java @@ -1,783 +1 @@ -/* - * Copyright 2024 Frans Jacobs. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package jcs.ui.layout.tiles; - -import java.awt.BasicStroke; -import java.awt.Color; -import java.awt.Dimension; -import java.awt.Font; -import java.awt.Graphics; -import java.awt.Graphics2D; -import java.awt.Image; -import java.awt.Point; -import java.awt.Rectangle; -import java.awt.geom.Ellipse2D; -import java.awt.image.BufferedImage; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Map; -import java.util.Set; -import jcs.entities.BlockBean; -import jcs.entities.BlockBean.BlockState; -import jcs.entities.LocomotiveBean; -import jcs.entities.TileBean; -import jcs.entities.TileBean.Orientation; -import static jcs.entities.TileBean.Orientation.EAST; -import static jcs.entities.TileBean.Orientation.NORTH; -import static jcs.entities.TileBean.Orientation.SOUTH; -import static jcs.entities.TileBean.Orientation.WEST; -import jcs.entities.TileBean.TileType; -import static jcs.ui.layout.tiles.Tile.DEFAULT_HEIGHT; -import static jcs.ui.layout.tiles.Tile.DEFAULT_WIDTH; -import static jcs.ui.layout.tiles.Tile.GRID; -import static jcs.ui.layout.tiles.Tile.RENDER_HEIGHT; -import static jcs.ui.layout.tiles.Tile.RENDER_WIDTH; -import jcs.ui.util.ImageUtil; -import org.tinylog.Logger; - -public class Block extends Tile { - - public static final int BLOCK_WIDTH = DEFAULT_WIDTH * 3; - public static final int BLOCK_HEIGHT = DEFAULT_HEIGHT * 3; - - public Block(TileBean tileBean) { - super(tileBean); - setModel(new DefaultTileModel(tileBean.getOrientation())); - changeRenderSize(); - populateModel(); - } - - public Block(Orientation orientation, Point center) { - this(orientation, center.x, center.y); - } - - public Block(Orientation orientation, int x, int y) { - this(orientation, x, y, tileWidth(orientation, TileType.BLOCK), tileHeight(orientation, TileType.BLOCK)); - } - - public Block(Orientation orientation, int x, int y, int width, int height) { - super(TileType.BLOCK, orientation, x, y, width, height); - setModel(new DefaultTileModel(orientation)); - changeRenderSize(); - } - - private void changeRenderSize() { - Orientation tileOrientation = model.getTileOrienation(); - if (Orientation.EAST == tileOrientation || Orientation.WEST == tileOrientation) { - this.renderWidth = RENDER_WIDTH * 3; - this.renderHeight = RENDER_HEIGHT; - } else { - this.renderWidth = RENDER_WIDTH; - this.renderHeight = RENDER_HEIGHT * 3; - } - } - - @Override - public Set getAltPoints() { - int xx = this.tileX; - int yy = this.tileY; - Set alternatives = new HashSet<>(); - - if (Orientation.EAST.equals(getOrientation()) || Orientation.WEST.equals(getOrientation())) { - // West - Point wp = new Point((xx - DEFAULT_WIDTH), yy); - Point ep = new Point((xx + DEFAULT_WIDTH), yy); - alternatives.add(wp); - alternatives.add(ep); - } else { - Point np = new Point(xx, (yy - DEFAULT_HEIGHT)); - Point sp = new Point(xx, (yy + DEFAULT_HEIGHT)); - alternatives.add(np); - alternatives.add(sp); - } - - return alternatives; - } - - @Override - public Set getAllPoints() { - Set aps = new HashSet<>(); - aps.add(getCenter()); - aps.addAll(getAltPoints()); - return aps; - } - - public Point getAltPoint(String suffix) { - int cx = this.getCenterX(); - int cy = this.getCenterY(); - if ("+".equals(suffix)) { - return switch (this.getOrientation()) { - case WEST -> - new Point(cx - Tile.GRID * 2, cy); - case NORTH -> - new Point(cx, cy - Tile.GRID * 2); - case SOUTH -> - new Point(cx, cy + Tile.GRID * 2); - default -> - new Point(cx + Tile.GRID * 2, cy); - }; - } else { - return switch (this.getOrientation()) { - case EAST -> - new Point(cx - Tile.GRID * 2, cy); - case SOUTH -> - new Point(cx, cy - Tile.GRID * 2); - case NORTH -> - new Point(cx, cy + Tile.GRID * 2); - default -> - new Point(cx + Tile.GRID * 2, cy); - }; - } - } - - @Override - public boolean isBlock() { - return true; - } - - @Override - public Map getNeighborPoints() { - Map neighbors = new HashMap<>(); - Orientation orientation = this.getOrientation(); - int cx = this.getCenterX(); - int cy = this.getCenterY(); - - // Horizontal - if (Orientation.EAST == orientation || Orientation.WEST == orientation) { - neighbors.put(Orientation.EAST, new Point(cx + Tile.GRID * 4, cy)); - neighbors.put(Orientation.WEST, new Point(cx - Tile.GRID * 4, cy)); - } else { - // Vertical - neighbors.put(Orientation.NORTH, new Point(cx, cy - Tile.GRID * 4)); - neighbors.put(Orientation.SOUTH, new Point(cx, cy + Tile.GRID * 4)); - } - return neighbors; - } - - @Override - public Map getEdgePoints() { - Map edgeConnections = new HashMap<>(); - Orientation orientation = this.getOrientation(); - int cx = this.getCenterX(); - int cy = this.getCenterY(); - - // Horizontal - if (Orientation.EAST == orientation || Orientation.WEST == orientation) { - edgeConnections.put(Orientation.EAST, new Point(cx + Tile.GRID * 3, cy)); - edgeConnections.put(Orientation.WEST, new Point(cx - Tile.GRID * 3, cy)); - } else { - // Vertical - edgeConnections.put(Orientation.NORTH, new Point(cx, cy - Tile.GRID * 3)); - edgeConnections.put(Orientation.SOUTH, new Point(cx, cy + Tile.GRID * 3)); - } - return edgeConnections; - } - - public Point getNeighborPoint(String suffix) { - int cx = getCenterX(); - int cy = getCenterY(); - if ("+".equals(suffix)) { - return switch (getOrientation()) { - case WEST -> - new Point(cx - Tile.GRID * 4, cy); - case NORTH -> - new Point(cx, cy - Tile.GRID * 4); - case SOUTH -> - new Point(cx, cy + Tile.GRID * 4); - default -> - new Point(cx + Tile.GRID * 4, cy); - }; - } else { - return switch (getOrientation()) { - case EAST -> - new Point(cx - Tile.GRID * 4, cy); - case SOUTH -> - new Point(cx, cy - Tile.GRID * 4); - case NORTH -> - new Point(cx, cy + Tile.GRID * 4); - default -> - new Point(cx + Tile.GRID * 4, cy); - }; - } - } - - public Orientation getTravelDirection(String suffix) { - if ("+".equals(suffix)) { - return getOrientation(); - } else { - return switch (getOrientation()) { - case EAST -> - Orientation.WEST; - case SOUTH -> - Orientation.NORTH; - case NORTH -> - Orientation.SOUTH; - default -> - Orientation.EAST; - }; - } - } - - @Override - public String getIdSuffix(Tile other) { - String suffix = null; - Orientation match = null; - if (isAdjacent(other)) { - Map blockSides = this.getEdgePoints(); - Map otherSides = other.getEdgePoints(); - - for (Orientation bo : Orientation.values()) { - Point bp = blockSides.get(bo); - - if (bp != null) { - for (Orientation oo : Orientation.values()) { - Point op = otherSides.get(oo); - if (op != null) { - if (op.equals(bp)) { - match = bo; - break; - } - } - } - } - } - } - - Orientation tileOrientation = model.getTileOrienation(); - if (match != null) { - if (Orientation.EAST == tileOrientation && Orientation.EAST == match) { - suffix = "+"; - } - if (Orientation.WEST == tileOrientation && Orientation.WEST == match) { - suffix = "+"; - } - if (Orientation.EAST == tileOrientation && Orientation.WEST == match) { - suffix = "-"; - } - if (Orientation.WEST == tileOrientation && Orientation.EAST == match) { - suffix = "-"; - } - if (Orientation.NORTH == tileOrientation && Orientation.NORTH == match) { - suffix = "+"; - } - if (Orientation.NORTH == tileOrientation && Orientation.SOUTH == match) { - suffix = "-"; - } - if (Orientation.SOUTH == tileOrientation && Orientation.SOUTH == match) { - suffix = "+"; - } - if (Orientation.SOUTH == tileOrientation && Orientation.NORTH == match) { - suffix = "-"; - } - } - return suffix; - } - - @Override - public Orientation rotate() { - Orientation tileOrientation = model.getTileOrienation(); - super.rotate(); - - int w = tileWidth(tileOrientation, TileType.BLOCK); - int h = tileHeight(tileOrientation, TileType.BLOCK); - - Dimension d = new Dimension(w, h); - setPreferredSize(d); - setSize(d); - changeRenderSize(); - - setBounds(getTileBounds()); - - //repaint(getTileBounds()); - return tileOrientation; - } - - /** - * Depending on the block status change the background color
- * - Red: Occupied
- * - Green: Departure
- * - Magenta: Arrival / entering
- * - Yellow: reserved
- * - White: all clear / default
- * - * @return the Color which belong with the current Block State - */ - Color getBlockStateColor() { - return getBlockStateColor(this.model.getBlockState()); - } - - protected Color getBlockStateColor(BlockState blockState) { - return switch (blockState) { - case GHOST -> - new Color(250, 0, 0); - case LOCKED -> - new Color(250, 250, 210); - case OCCUPIED -> - new Color(250, 210, 210); - case OUT_OF_ORDER -> - new Color(190, 190, 190); - case OUTBOUND -> - new Color(210, 250, 210); - case INBOUND -> - new Color(250, 210, 250); - default -> - new Color(255, 255, 255); - }; - } - - public static String getDepartureSuffix(Orientation tileOrientation, boolean reverseArrival, LocomotiveBean.Direction direction) { - if (LocomotiveBean.Direction.FORWARDS == direction) { - if (Orientation.EAST == tileOrientation || Orientation.SOUTH == tileOrientation) { - if (reverseArrival) { - return "-"; - } else { - return "+"; - } - } else { - if (reverseArrival) { - return "+"; - } else { - return "-"; - } - } - } else { - if (Orientation.EAST == tileOrientation || Orientation.SOUTH == tileOrientation) { - if (reverseArrival) { - return "+"; - } else { - return "-"; - } - } else { - if (reverseArrival) { - return "-"; - } else { - return "+"; - } - } - } - } - - @Override - public void renderTile(Graphics2D g2) { - int xx = 20; - int yy = 50; - int rw = RENDER_WIDTH * 3 - 40; - int rh = 300; - - g2.setStroke(new BasicStroke(3, BasicStroke.CAP_SQUARE, BasicStroke.JOIN_ROUND)); - - g2.setPaint(Color.darkGray); - g2.drawRoundRect(xx, yy, rw, rh, 15, 15); - - Color blockStateColor = getBlockStateColor(); - //Logger.trace("Block " + this.id + " State: " + this.getBlockBean().getBlockState().getState() + " Color: " + blockStateColor.toString()); - g2.setPaint(blockStateColor); - g2.fillRoundRect(xx, yy, rw, rh, 15, 15); - - g2.setStroke(new BasicStroke(20, BasicStroke.CAP_SQUARE, BasicStroke.JOIN_ROUND)); - g2.setPaint(Color.darkGray); - g2.drawLine(rw + GRID, yy - 0, rw + GRID, yy + 300); - - //When there is a locomotive in the block mark the direction of travel. - //The default, forwards is in the direction of the block orientation, i.e. the + - if (model.getLocomotive() != null && model.getLocomotive().getName() != null) { - renderDirectionArrow(g2); - } - - drawName(g2); - } - - private void renderDirectionArrow(Graphics2D g2) { - //The default, forwards is in the direction of the block orientation, i.e. the + - Orientation tileOrientation = model.getTileOrienation(); - BlockBean bb = this.getBlockBean(); - boolean reverseArrival = model.isReverseArrival(); - - LocomotiveBean.Direction logicalDirection; - if (bb.getLogicalDirection() != null) { - logicalDirection = model.getLogicalDirection(); - } else { - logicalDirection = model.getLocomotive().getDirection(); - } - - String departureSuffix = model.getDepartureSuffix(); - if (departureSuffix == null) { - departureSuffix = Block.getDepartureSuffix(tileOrientation, reverseArrival, logicalDirection); - } - - //Logger.trace(this.getId()+" LogicalDirection is " + (bb.getLogicalDirection() != null ? "Set" : "Not Set") + " Dir: " + logicalDirection.getDirection() + " Orientation: " + orientation.getOrientation() + " departureSuffix: " + departureSuffix); - if ("+".equals(departureSuffix)) { - if (Orientation.EAST == tileOrientation || Orientation.SOUTH == tileOrientation) { - switch (logicalDirection) { - case LocomotiveBean.Direction.FORWARDS -> { - if (reverseArrival) { - renderLeftArrow(g2); - } else { - renderRightArrow(g2); - } - } - case LocomotiveBean.Direction.BACKWARDS -> { - if (reverseArrival) { - renderRightArrow(g2); - } else { - renderLeftArrow(g2); - } - } - } - } else { - switch (logicalDirection) { - case LocomotiveBean.Direction.BACKWARDS -> { - if (reverseArrival) { - renderLeftArrow(g2); - } else { - renderRightArrow(g2); - } - } - case LocomotiveBean.Direction.FORWARDS -> { - if (reverseArrival) { - renderRightArrow(g2); - } else { - renderLeftArrow(g2); - } - } - } - } - } else { - if (Orientation.EAST == tileOrientation || Orientation.SOUTH == tileOrientation) { - switch (logicalDirection) { - case LocomotiveBean.Direction.FORWARDS -> { - if (reverseArrival) { - renderLeftArrow(g2); - } else { - renderRightArrow(g2); - } - } - case LocomotiveBean.Direction.BACKWARDS -> { - if (reverseArrival) { - renderRightArrow(g2); - } else { - renderLeftArrow(g2); - } - } - } - } else { - switch (logicalDirection) { - case LocomotiveBean.Direction.BACKWARDS -> { - if (reverseArrival) { - renderLeftArrow(g2); - } else { - renderRightArrow(g2); - } - } - case LocomotiveBean.Direction.FORWARDS -> { - if (reverseArrival) { - renderRightArrow(g2); - } else { - renderLeftArrow(g2); - } - } - } - } - } - } - - private void renderLeftArrow(Graphics2D g2) { - //Logger.trace(this.getId()+" LogicalDirection is " + this.getBlockBean().getLogicalDirection() + " Orientation: " + this.getOrientation() + " departureSuffix: " + this.getBlockBean().getDepartureSuffix()); - g2.fillPolygon(new int[]{0, 50, 50,}, new int[]{200, 150, 250}, 3); - } - - private void renderRightArrow(Graphics2D g2) { - //Logger.trace(this.getId()+" LogicalDirection is " + this.getBlockBean().getLogicalDirection() + " Orientation: " + this.getOrientation() + " departureSuffix: " + this.getBlockBean().getDepartureSuffix()); - g2.fillPolygon(new int[]{1180, 1130, 1130,}, new int[]{200, 150, 250}, 3); - } - - @Override - public void renderTileRoute(Graphics2D g2d) { - if (model.isShowBlockState()) { - backgroundColor = getBlockStateColor(model.getBlockState()); - } - } - - protected void overlayLocImage() { - int ww = tileImage.getWidth(); - int hh = tileImage.getHeight(); - Orientation tileOrientation = model.getTileOrienation(); - - BufferedImage overlay = new BufferedImage(ww, hh, BufferedImage.TYPE_INT_ARGB); - Graphics2D g2i = overlay.createGraphics(); - - Image locImage = getLocImage(); - if (locImage != null) { - String departureSuffix = model.getDepartureSuffix(); - boolean reverseImage = model.isReverseArrival(); - - Logger.trace("LocImage w: " + locImage.getWidth(null) + " h: " + locImage.getHeight(null)); - // scale it to max h of 45 - int size = 45; - float aspect = (float) locImage.getHeight(null) / (float) locImage.getWidth(null); - //TODO: Use Scalr? - locImage = locImage.getScaledInstance(size, (int) (size * aspect), Image.SCALE_SMOOTH); - - //Depending on the block orientation the image needs to be rotated and flipped - //Incase the departure suffix is NOT set center the locomotive image - int w, h, xx, yy; - switch (tileOrientation) { - case WEST -> { - w = locImage.getWidth(null); - h = locImage.getHeight(null); - - if (null == departureSuffix) { - xx = BLOCK_WIDTH / 2 - getWidth() / 2 + w; - } else { - switch (departureSuffix) { - case "+" -> { - xx = BLOCK_WIDTH / 2 - getWidth() / 2 + w - 25; - } - default -> { - xx = BLOCK_WIDTH / 2 - getWidth() / 2 + w + 10; - } - } - } - yy = DEFAULT_HEIGHT / 2 - h / 2; - - if (reverseImage) { - locImage = ImageUtil.flipVertically(locImage); - } - } - case SOUTH -> { - locImage = ImageUtil.flipHorizontally(locImage); - locImage = ImageUtil.rotate(locImage, 90); - - w = locImage.getWidth(null); - h = locImage.getHeight(null); - xx = DEFAULT_WIDTH / 2 - w / 2; - - if (null == departureSuffix) { - yy = BLOCK_HEIGHT / 2 - getHeight() / 2 + h; - } else { - switch (departureSuffix) { - case "-" -> { - yy = BLOCK_HEIGHT / 2 - getHeight() / 2 + h - 25; - } - default -> { - yy = BLOCK_HEIGHT / 2 - getHeight() / 2 + h + 10; - } - } - } - if (reverseImage) { - locImage = ImageUtil.flipHorizontally(locImage); - } - //g2d.drawImage(locImage, xx, yy, null); - } - case NORTH -> { - locImage = ImageUtil.flipHorizontally(locImage); - locImage = ImageUtil.rotate(locImage, 90); - - w = locImage.getWidth(null); - h = locImage.getHeight(null); - xx = DEFAULT_WIDTH / 2 - w / 2; - - if (null == departureSuffix) { - int minY = BLOCK_HEIGHT / 2 - getHeight() / 2 + h; - yy = minY; - } else { - switch (departureSuffix) { - case "+" -> { - yy = BLOCK_HEIGHT / 2 - getHeight() / 2 + h - 25; - } - default -> { - yy = BLOCK_HEIGHT / 2 - getHeight() / 2 + h + 10; - } - } - } - if (reverseImage) { - locImage = ImageUtil.flipHorizontally(locImage); - } - } - default -> { - w = locImage.getWidth(null); - h = locImage.getHeight(null); - if (null == departureSuffix) { - xx = BLOCK_WIDTH / 2 - getWidth() / 2 + w; - } else { - switch (departureSuffix) { - case "-" -> { - xx = BLOCK_WIDTH / 2 - getWidth() / 2 + w - 25; - } - default -> { - xx = BLOCK_WIDTH / 2 - getWidth() / 2 + w + 10; - } - } - } - yy = DEFAULT_HEIGHT / 2 - h / 2; - - if (reverseImage) { - locImage = ImageUtil.flipVertically(locImage); - } - } - } - - g2i.drawImage(tileImage, 0, 0, null); - g2i.drawImage(locImage, xx, yy, null); - g2i.dispose(); - tileImage = overlay; - } - } - - private Image getLocImage() { - if (model.getLocomotive() != null && model.getLocomotive().getLocIcon() != null) { - return model.getLocomotive().getLocIcon(); - } else { - return null; - } - } - - public String getBlockText() { - String blockText; - if (blockBean != null && blockBean.getDescription() != null) { - if (blockBean.getLocomotive() != null && blockBean.getLocomotive().getName() != null && BlockState.GHOST != blockBean.getBlockState()) { - blockText = blockBean.getLocomotive().getName(); - } else { - if (blockBean.getDescription().length() > 0) { - blockText = blockBean.getDescription(); - } else { - blockText = getId(); - } - } - } else { - // Design mode show description when available - if (blockBean != null && blockBean.getDescription() != null && blockBean.getDescription().length() > 0) { - blockText = blockBean.getDescription(); - } else { - blockText = getId(); - } - } - return blockText; - } - - @Override - public void drawName(Graphics2D g2d) { - if (!model.isOverlayImage()) { - g2d.setPaint(Color.black); - - Font currentFont = g2d.getFont(); - Font newFont = currentFont.deriveFont(currentFont.getSize() * 10.0F); - g2d.setFont(newFont); - - String blockText = getBlockText(); - - // Scale the text if necessary - int textWidth = g2d.getFontMetrics().stringWidth(blockText); - double fontscale = 10.0; - if (textWidth > 845) { - fontscale = fontscale * 847.0 / textWidth; - newFont = currentFont.deriveFont(currentFont.getSize() * (float) fontscale); - g2d.setFont(newFont); - textWidth = g2d.getFontMetrics().stringWidth(blockText); - } - - int textHeight = g2d.getFontMetrics().getHeight(); - Orientation tileOrientation = model.getTileOrienation(); - - switch (tileOrientation) { - case EAST -> { - drawRotate(g2d, ((RENDER_WIDTH * 3) / 2) - textWidth / 2, RENDER_GRID + textHeight / 3, 0, blockText); - } - case WEST -> { - drawRotate(g2d, ((RENDER_WIDTH * 3) / 2) + textWidth / 2, RENDER_GRID - textHeight / 3, 180, blockText); - } - case NORTH -> { - drawRotate(g2d, ((RENDER_WIDTH * 3) / 2) - textWidth / 2, RENDER_GRID + textHeight / 3, 0, blockText); - } - case SOUTH -> { - drawRotate(g2d, ((RENDER_WIDTH * 3) / 2) + textWidth / 2, RENDER_GRID - textHeight / 3, 180, blockText); - } - } - // reset to the original font - newFont = currentFont.deriveFont(currentFont.getSize() * 1.0F); - g2d.setFont(newFont); - } - } - - @Override - public Rectangle getTileBounds() { - int multiplier = (model.isScaleImage() ? 1 : 10); - Orientation tileOrientation = model.getTileOrienation(); - - int xx, yy; - if (tileOrientation == Orientation.EAST || tileOrientation == Orientation.WEST) { - xx = tileX - GRID * multiplier - GRID * multiplier * 2; - yy = tileY - GRID * multiplier; - } else { - xx = tileX - GRID * multiplier; - yy = tileY - GRID * multiplier - GRID * multiplier * 2; - } - - if (model.isScaleImage()) { - return new Rectangle(xx, yy, tileWidth(tileOrientation, TileType.BLOCK), tileHeight(tileOrientation, TileType.BLOCK)); - } else { - return new Rectangle(xx, yy, renderWidth, renderHeight); - } - } - - @Override - protected void paintComponent(Graphics g) { - long started = System.currentTimeMillis(); - - Graphics2D g2 = (Graphics2D) g.create(); - drawTile(g2); - g2.dispose(); - - if (model.isOverlayImage()) { - overlayLocImage(); - } - - g.drawImage(tileImage, 0, 0, null); - long now = System.currentTimeMillis(); - Logger.trace(id + " Duration: " + (now - started) + " ms."); - } - - @Override - protected void drawCenterPoint(Graphics2D g2d, Color color, double size) { - //A block has 2 alternate points - //1st square - //2nd square holds the centerpoint - //3rd square - Orientation tileOrientation = model.getTileOrienation(); - double dX1, dX2, dX3, dY1, dY2, dY3; - if (Orientation.EAST == tileOrientation || Orientation.WEST == tileOrientation) { - dX1 = renderWidth / 3 / 2 - size / 2 / 2; - dY1 = renderHeight / 2 - size / 2 / 2; - dX2 = renderWidth / 2 - size / 2; - dY2 = renderHeight / 2 - size / 2; - dX3 = renderWidth - renderWidth / 3 / 2 - size / 2 / 2; - dY3 = renderHeight / 2 - size / 2 / 2; - } else { - dX1 = renderWidth / 2 - size / 2 / 2; - dY1 = renderHeight / 3 / 2 - size / 2 / 2; - dX2 = renderHeight / 2 - size / 2; - dY2 = renderWidth / 2 - size / 2; - dY3 = renderWidth / 2 - size / 2 / 2; - dX3 = renderHeight - renderHeight / 3 / 2 - size / 2 / 2; - } - - g2d.setColor(color); - g2d.fill(new Ellipse2D.Double(dX1, dY1, size / 2, size / 2)); - g2d.fill(new Ellipse2D.Double(dX2, dY2, size, size)); - g2d.fill(new Ellipse2D.Double(dX3, dY3, size / 2, size / 2)); - } - -} +/* * Copyright 2024 Frans Jacobs. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package jcs.ui.layout.tiles; import java.awt.BasicStroke; import java.awt.Color; import java.awt.Dimension; import java.awt.Font; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.Image; import java.awt.Point; import java.awt.Rectangle; import java.awt.geom.Ellipse2D; import java.awt.image.BufferedImage; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set; import jcs.entities.BlockBean; import jcs.entities.BlockBean.BlockState; import jcs.entities.LocomotiveBean; import jcs.entities.TileBean; import jcs.entities.TileBean.Orientation; import static jcs.entities.TileBean.Orientation.EAST; import static jcs.entities.TileBean.Orientation.NORTH; import static jcs.entities.TileBean.Orientation.SOUTH; import static jcs.entities.TileBean.Orientation.WEST; import jcs.entities.TileBean.TileType; import static jcs.ui.layout.tiles.Tile.DEFAULT_HEIGHT; import static jcs.ui.layout.tiles.Tile.DEFAULT_WIDTH; import static jcs.ui.layout.tiles.Tile.GRID; import static jcs.ui.layout.tiles.Tile.RENDER_HEIGHT; import static jcs.ui.layout.tiles.Tile.RENDER_WIDTH; import jcs.ui.util.ImageUtil; import org.tinylog.Logger; public class Block extends Tile { public static final int BLOCK_WIDTH = DEFAULT_WIDTH * 3; public static final int BLOCK_HEIGHT = DEFAULT_HEIGHT * 3; public Block(TileBean tileBean) { super(tileBean); setModel(new DefaultTileModel(tileBean.getOrientation())); changeRenderSize(); populateModel(); } public Block(Orientation orientation, Point center) { this(orientation, center.x, center.y); } public Block(Orientation orientation, int x, int y) { this(orientation, x, y, tileWidth(orientation, TileType.BLOCK), tileHeight(orientation, TileType.BLOCK)); } public Block(Orientation orientation, int x, int y, int width, int height) { super(TileType.BLOCK, orientation, x, y, width, height); setModel(new DefaultTileModel(orientation)); changeRenderSize(); } private void changeRenderSize() { Orientation tileOrientation = model.getTileOrienation(); if (Orientation.EAST == tileOrientation || Orientation.WEST == tileOrientation) { this.renderWidth = RENDER_WIDTH * 3; this.renderHeight = RENDER_HEIGHT; } else { this.renderWidth = RENDER_WIDTH; this.renderHeight = RENDER_HEIGHT * 3; } } @Override public Set getAltPoints() { int xx = this.tileX; int yy = this.tileY; Set alternatives = new HashSet<>(); if (Orientation.EAST.equals(getOrientation()) || Orientation.WEST.equals(getOrientation())) { // West Point wp = new Point((xx - DEFAULT_WIDTH), yy); Point ep = new Point((xx + DEFAULT_WIDTH), yy); alternatives.add(wp); alternatives.add(ep); } else { Point np = new Point(xx, (yy - DEFAULT_HEIGHT)); Point sp = new Point(xx, (yy + DEFAULT_HEIGHT)); alternatives.add(np); alternatives.add(sp); } return alternatives; } @Override public Set getAllPoints() { Set aps = new HashSet<>(); aps.add(getCenter()); aps.addAll(getAltPoints()); return aps; } public Point getAltPoint(String suffix) { int cx = this.getCenterX(); int cy = this.getCenterY(); if ("+".equals(suffix)) { return switch (this.getOrientation()) { case WEST -> new Point(cx - Tile.GRID * 2, cy); case NORTH -> new Point(cx, cy - Tile.GRID * 2); case SOUTH -> new Point(cx, cy + Tile.GRID * 2); default -> new Point(cx + Tile.GRID * 2, cy); }; } else { return switch (this.getOrientation()) { case EAST -> new Point(cx - Tile.GRID * 2, cy); case SOUTH -> new Point(cx, cy - Tile.GRID * 2); case NORTH -> new Point(cx, cy + Tile.GRID * 2); default -> new Point(cx + Tile.GRID * 2, cy); }; } } @Override public boolean isBlock() { return true; } @Override public Map getNeighborPoints() { Map neighbors = new HashMap<>(); Orientation orientation = this.getOrientation(); int cx = this.getCenterX(); int cy = this.getCenterY(); // Horizontal if (Orientation.EAST == orientation || Orientation.WEST == orientation) { neighbors.put(Orientation.EAST, new Point(cx + Tile.GRID * 4, cy)); neighbors.put(Orientation.WEST, new Point(cx - Tile.GRID * 4, cy)); } else { // Vertical neighbors.put(Orientation.NORTH, new Point(cx, cy - Tile.GRID * 4)); neighbors.put(Orientation.SOUTH, new Point(cx, cy + Tile.GRID * 4)); } return neighbors; } @Override public Map getEdgePoints() { Map edgeConnections = new HashMap<>(); Orientation orientation = this.getOrientation(); int cx = this.getCenterX(); int cy = this.getCenterY(); // Horizontal if (Orientation.EAST == orientation || Orientation.WEST == orientation) { edgeConnections.put(Orientation.EAST, new Point(cx + Tile.GRID * 3, cy)); edgeConnections.put(Orientation.WEST, new Point(cx - Tile.GRID * 3, cy)); } else { // Vertical edgeConnections.put(Orientation.NORTH, new Point(cx, cy - Tile.GRID * 3)); edgeConnections.put(Orientation.SOUTH, new Point(cx, cy + Tile.GRID * 3)); } return edgeConnections; } public Point getNeighborPoint(String suffix) { int cx = getCenterX(); int cy = getCenterY(); if ("+".equals(suffix)) { return switch (getOrientation()) { case WEST -> new Point(cx - Tile.GRID * 4, cy); case NORTH -> new Point(cx, cy - Tile.GRID * 4); case SOUTH -> new Point(cx, cy + Tile.GRID * 4); default -> new Point(cx + Tile.GRID * 4, cy); }; } else { return switch (getOrientation()) { case EAST -> new Point(cx - Tile.GRID * 4, cy); case SOUTH -> new Point(cx, cy - Tile.GRID * 4); case NORTH -> new Point(cx, cy + Tile.GRID * 4); default -> new Point(cx + Tile.GRID * 4, cy); }; } } public Orientation getTravelDirection(String suffix) { if ("+".equals(suffix)) { return getOrientation(); } else { return switch (getOrientation()) { case EAST -> Orientation.WEST; case SOUTH -> Orientation.NORTH; case NORTH -> Orientation.SOUTH; default -> Orientation.EAST; }; } } @Override public String getIdSuffix(Tile other) { String suffix = null; Orientation match = null; if (isAdjacent(other)) { Map blockSides = this.getEdgePoints(); Map otherSides = other.getEdgePoints(); for (Orientation bo : Orientation.values()) { Point bp = blockSides.get(bo); if (bp != null) { for (Orientation oo : Orientation.values()) { Point op = otherSides.get(oo); if (op != null) { if (op.equals(bp)) { match = bo; break; } } } } } } Orientation tileOrientation = model.getTileOrienation(); if (match != null) { if (Orientation.EAST == tileOrientation && Orientation.EAST == match) { suffix = "+"; } if (Orientation.WEST == tileOrientation && Orientation.WEST == match) { suffix = "+"; } if (Orientation.EAST == tileOrientation && Orientation.WEST == match) { suffix = "-"; } if (Orientation.WEST == tileOrientation && Orientation.EAST == match) { suffix = "-"; } if (Orientation.NORTH == tileOrientation && Orientation.NORTH == match) { suffix = "+"; } if (Orientation.NORTH == tileOrientation && Orientation.SOUTH == match) { suffix = "-"; } if (Orientation.SOUTH == tileOrientation && Orientation.SOUTH == match) { suffix = "+"; } if (Orientation.SOUTH == tileOrientation && Orientation.NORTH == match) { suffix = "-"; } } return suffix; } @Override public Orientation rotate() { super.rotate(); Orientation tileOrientation = model.getTileOrienation(); int w = tileWidth(tileOrientation, TileType.BLOCK); int h = tileHeight(tileOrientation, TileType.BLOCK); Dimension d = new Dimension(w, h); setPreferredSize(d); setSize(d); changeRenderSize(); setBounds(getTileBounds()); return model.getTileOrienation(); } /** * Depending on the block status change the background color
* - Red: Occupied
* - Green: Departure
* - Magenta: Arrival / entering
* - Yellow: reserved
* - White: all clear / default
* * @return the Color which belong with the current Block State */ Color getBlockStateColor() { return getBlockStateColor(this.model.getBlockState()); } protected Color getBlockStateColor(BlockState blockState) { return switch (blockState) { case GHOST -> new Color(250, 0, 0); case LOCKED -> new Color(250, 250, 210); case OCCUPIED -> new Color(250, 210, 210); case OUT_OF_ORDER -> new Color(190, 190, 190); case OUTBOUND -> new Color(210, 250, 210); case INBOUND -> new Color(250, 210, 250); default -> new Color(255, 255, 255); }; } public static String getDepartureSuffix(Orientation tileOrientation, boolean reverseArrival, LocomotiveBean.Direction direction) { if (LocomotiveBean.Direction.FORWARDS == direction) { if (Orientation.EAST == tileOrientation || Orientation.SOUTH == tileOrientation) { if (reverseArrival) { return "-"; } else { return "+"; } } else { if (reverseArrival) { return "+"; } else { return "-"; } } } else { if (Orientation.EAST == tileOrientation || Orientation.SOUTH == tileOrientation) { if (reverseArrival) { return "+"; } else { return "-"; } } else { if (reverseArrival) { return "-"; } else { return "+"; } } } } @Override public void renderTile(Graphics2D g2) { int xx = 20; int yy = 50; int rw = RENDER_WIDTH * 3 - 40; int rh = 300; g2.setStroke(new BasicStroke(3, BasicStroke.CAP_SQUARE, BasicStroke.JOIN_ROUND)); g2.setPaint(Color.darkGray); g2.drawRoundRect(xx, yy, rw, rh, 15, 15); Color blockStateColor = getBlockStateColor(); //Logger.trace("Block " + this.id + " State: " + this.getBlockBean().getBlockState().getState() + " Color: " + blockStateColor.toString()); g2.setPaint(blockStateColor); g2.fillRoundRect(xx, yy, rw, rh, 15, 15); g2.setStroke(new BasicStroke(20, BasicStroke.CAP_SQUARE, BasicStroke.JOIN_ROUND)); g2.setPaint(Color.darkGray); g2.drawLine(rw + GRID, yy - 0, rw + GRID, yy + 300); //When there is a locomotive in the block mark the direction of travel. //The default, forwards is in the direction of the block orientation, i.e. the + if (model.getLocomotive() != null && model.getLocomotive().getName() != null) { renderDirectionArrow(g2); } drawName(g2); } private void renderDirectionArrow(Graphics2D g2) { //The default, forwards is in the direction of the block orientation, i.e. the + Orientation tileOrientation = model.getTileOrienation(); BlockBean bb = this.getBlockBean(); boolean reverseArrival = model.isReverseArrival(); LocomotiveBean.Direction logicalDirection; if (bb.getLogicalDirection() != null) { logicalDirection = model.getLogicalDirection(); } else { logicalDirection = model.getLocomotive().getDirection(); } String departureSuffix = model.getDepartureSuffix(); if (departureSuffix == null) { departureSuffix = Block.getDepartureSuffix(tileOrientation, reverseArrival, logicalDirection); } //Logger.trace(this.getId()+" LogicalDirection is " + (bb.getLogicalDirection() != null ? "Set" : "Not Set") + " Dir: " + logicalDirection.getDirection() + " Orientation: " + orientation.getOrientation() + " departureSuffix: " + departureSuffix); if ("+".equals(departureSuffix)) { if (Orientation.EAST == tileOrientation || Orientation.SOUTH == tileOrientation) { switch (logicalDirection) { case LocomotiveBean.Direction.FORWARDS -> { if (reverseArrival) { renderLeftArrow(g2); } else { renderRightArrow(g2); } } case LocomotiveBean.Direction.BACKWARDS -> { if (reverseArrival) { renderRightArrow(g2); } else { renderLeftArrow(g2); } } } } else { switch (logicalDirection) { case LocomotiveBean.Direction.BACKWARDS -> { if (reverseArrival) { renderLeftArrow(g2); } else { renderRightArrow(g2); } } case LocomotiveBean.Direction.FORWARDS -> { if (reverseArrival) { renderRightArrow(g2); } else { renderLeftArrow(g2); } } } } } else { if (Orientation.EAST == tileOrientation || Orientation.SOUTH == tileOrientation) { switch (logicalDirection) { case LocomotiveBean.Direction.FORWARDS -> { if (reverseArrival) { renderLeftArrow(g2); } else { renderRightArrow(g2); } } case LocomotiveBean.Direction.BACKWARDS -> { if (reverseArrival) { renderRightArrow(g2); } else { renderLeftArrow(g2); } } } } else { switch (logicalDirection) { case LocomotiveBean.Direction.BACKWARDS -> { if (reverseArrival) { renderLeftArrow(g2); } else { renderRightArrow(g2); } } case LocomotiveBean.Direction.FORWARDS -> { if (reverseArrival) { renderRightArrow(g2); } else { renderLeftArrow(g2); } } } } } } private void renderLeftArrow(Graphics2D g2) { //Logger.trace(this.getId()+" LogicalDirection is " + this.getBlockBean().getLogicalDirection() + " Orientation: " + this.getOrientation() + " departureSuffix: " + this.getBlockBean().getDepartureSuffix()); g2.fillPolygon(new int[]{0, 50, 50,}, new int[]{200, 150, 250}, 3); } private void renderRightArrow(Graphics2D g2) { //Logger.trace(this.getId()+" LogicalDirection is " + this.getBlockBean().getLogicalDirection() + " Orientation: " + this.getOrientation() + " departureSuffix: " + this.getBlockBean().getDepartureSuffix()); g2.fillPolygon(new int[]{1180, 1130, 1130,}, new int[]{200, 150, 250}, 3); } @Override public void renderTileRoute(Graphics2D g2d) { if (model.isShowBlockState()) { backgroundColor = getBlockStateColor(model.getBlockState()); } } protected void overlayLocImage() { int ww = tileImage.getWidth(); int hh = tileImage.getHeight(); Orientation tileOrientation = model.getTileOrienation(); BufferedImage overlay = new BufferedImage(ww, hh, BufferedImage.TYPE_INT_ARGB); Graphics2D g2i = overlay.createGraphics(); Image locImage = getLocImage(); if (locImage != null) { String departureSuffix = model.getDepartureSuffix(); boolean reverseImage = model.isReverseArrival(); Logger.trace("LocImage w: " + locImage.getWidth(null) + " h: " + locImage.getHeight(null)); // scale it to max h of 45 int size = 45; float aspect = (float) locImage.getHeight(null) / (float) locImage.getWidth(null); //TODO: Use Scalr? locImage = locImage.getScaledInstance(size, (int) (size * aspect), Image.SCALE_SMOOTH); //Depending on the block orientation the image needs to be rotated and flipped //Incase the departure suffix is NOT set center the locomotive image int w, h, xx, yy; switch (tileOrientation) { case WEST -> { w = locImage.getWidth(null); h = locImage.getHeight(null); if (null == departureSuffix) { xx = BLOCK_WIDTH / 2 - getWidth() / 2 + w; } else { switch (departureSuffix) { case "+" -> { xx = BLOCK_WIDTH / 2 - getWidth() / 2 + w - 25; } default -> { xx = BLOCK_WIDTH / 2 - getWidth() / 2 + w + 10; } } } yy = DEFAULT_HEIGHT / 2 - h / 2; if (reverseImage) { locImage = ImageUtil.flipVertically(locImage); } } case SOUTH -> { locImage = ImageUtil.flipHorizontally(locImage); locImage = ImageUtil.rotate(locImage, 90); w = locImage.getWidth(null); h = locImage.getHeight(null); xx = DEFAULT_WIDTH / 2 - w / 2; if (null == departureSuffix) { yy = BLOCK_HEIGHT / 2 - getHeight() / 2 + h; } else { switch (departureSuffix) { case "-" -> { yy = BLOCK_HEIGHT / 2 - getHeight() / 2 + h - 25; } default -> { yy = BLOCK_HEIGHT / 2 - getHeight() / 2 + h + 10; } } } if (reverseImage) { locImage = ImageUtil.flipHorizontally(locImage); } } case NORTH -> { locImage = ImageUtil.flipHorizontally(locImage); locImage = ImageUtil.rotate(locImage, 90); w = locImage.getWidth(null); h = locImage.getHeight(null); xx = DEFAULT_WIDTH / 2 - w / 2; if (null == departureSuffix) { int minY = BLOCK_HEIGHT / 2 - getHeight() / 2 + h; yy = minY; } else { switch (departureSuffix) { case "+" -> { yy = BLOCK_HEIGHT / 2 - getHeight() / 2 + h - 25; } default -> { yy = BLOCK_HEIGHT / 2 - getHeight() / 2 + h + 10; } } } if (reverseImage) { locImage = ImageUtil.flipHorizontally(locImage); } } default -> { w = locImage.getWidth(null); h = locImage.getHeight(null); if (null == departureSuffix) { xx = BLOCK_WIDTH / 2 - getWidth() / 2 + w; } else { switch (departureSuffix) { case "-" -> { xx = BLOCK_WIDTH / 2 - getWidth() / 2 + w - 25; } default -> { xx = BLOCK_WIDTH / 2 - getWidth() / 2 + w + 10; } } } yy = DEFAULT_HEIGHT / 2 - h / 2; if (reverseImage) { locImage = ImageUtil.flipVertically(locImage); } } } g2i.drawImage(tileImage, 0, 0, null); g2i.drawImage(locImage, xx, yy, null); g2i.dispose(); tileImage = overlay; } } private Image getLocImage() { if (model.getLocomotive() != null && model.getLocomotive().getLocIcon() != null) { return model.getLocomotive().getLocIcon(); } else { return null; } } public String getBlockText() { String blockText; if (blockBean != null && blockBean.getDescription() != null) { if (blockBean.getLocomotive() != null && blockBean.getLocomotive().getName() != null && BlockState.GHOST != blockBean.getBlockState()) { blockText = blockBean.getLocomotive().getName(); } else { if (blockBean.getDescription().length() > 0) { blockText = blockBean.getDescription(); } else { blockText = getId(); } } } else { // Design mode show description when available if (blockBean != null && blockBean.getDescription() != null && blockBean.getDescription().length() > 0) { blockText = blockBean.getDescription(); } else { blockText = getId(); } } return blockText; } @Override public void drawName(Graphics2D g2d) { if (!model.isOverlayImage()) { g2d.setPaint(Color.black); Font currentFont = g2d.getFont(); Font newFont = currentFont.deriveFont(currentFont.getSize() * 10.0F); g2d.setFont(newFont); String blockText = getBlockText(); // Scale the text if necessary int textWidth = g2d.getFontMetrics().stringWidth(blockText); double fontscale = 10.0; if (textWidth > 845) { fontscale = fontscale * 847.0 / textWidth; newFont = currentFont.deriveFont(currentFont.getSize() * (float) fontscale); g2d.setFont(newFont); textWidth = g2d.getFontMetrics().stringWidth(blockText); } int textHeight = g2d.getFontMetrics().getHeight(); Orientation tileOrientation = model.getTileOrienation(); switch (tileOrientation) { case EAST -> { drawRotate(g2d, ((RENDER_WIDTH * 3) / 2) - textWidth / 2, RENDER_GRID + textHeight / 3, 0, blockText); } case WEST -> { drawRotate(g2d, ((RENDER_WIDTH * 3) / 2) + textWidth / 2, RENDER_GRID - textHeight / 3, 180, blockText); } case NORTH -> { drawRotate(g2d, ((RENDER_WIDTH * 3) / 2) - textWidth / 2, RENDER_GRID + textHeight / 3, 0, blockText); } case SOUTH -> { drawRotate(g2d, ((RENDER_WIDTH * 3) / 2) + textWidth / 2, RENDER_GRID - textHeight / 3, 180, blockText); } } // reset to the original font newFont = currentFont.deriveFont(currentFont.getSize() * 1.0F); g2d.setFont(newFont); } } @Override public Rectangle getTileBounds() { int multiplier = (model.isScaleImage() ? 1 : 10); Orientation tileOrientation = model.getTileOrienation(); int xx, yy; if (tileOrientation == Orientation.EAST || tileOrientation == Orientation.WEST) { xx = tileX - GRID * multiplier - GRID * multiplier * 2; yy = tileY - GRID * multiplier; } else { xx = tileX - GRID * multiplier; yy = tileY - GRID * multiplier - GRID * multiplier * 2; } if (model.isScaleImage()) { return new Rectangle(xx, yy, tileWidth(tileOrientation, TileType.BLOCK), tileHeight(tileOrientation, TileType.BLOCK)); } else { return new Rectangle(xx, yy, renderWidth, renderHeight); } } @Override protected void paintComponent(Graphics g) { long started = System.currentTimeMillis(); Graphics2D g2 = (Graphics2D) g.create(); drawTile(g2); g2.dispose(); if (model.isOverlayImage()) { overlayLocImage(); } g.drawImage(tileImage, 0, 0, null); long now = System.currentTimeMillis(); Logger.trace(id + " Duration: " + (now - started) + " ms."); } @Override protected void drawCenterPoint(Graphics2D g2d, Color color, double size) { //A block has 2 alternate points //1st square //2nd square holds the centerpoint //3rd square Orientation tileOrientation = model.getTileOrienation(); double dX1, dX2, dX3, dY1, dY2, dY3; if (Orientation.EAST == tileOrientation || Orientation.WEST == tileOrientation) { dX1 = renderWidth / 3 / 2 - size / 2 / 2; dY1 = renderHeight / 2 - size / 2 / 2; dX2 = renderWidth / 2 - size / 2; dY2 = renderHeight / 2 - size / 2; dX3 = renderWidth - renderWidth / 3 / 2 - size / 2 / 2; dY3 = renderHeight / 2 - size / 2 / 2; } else { dX1 = renderWidth / 2 - size / 2 / 2; dY1 = renderHeight / 3 / 2 - size / 2 / 2; dX2 = renderHeight / 2 - size / 2; dY2 = renderWidth / 2 - size / 2; dY3 = renderWidth / 2 - size / 2 / 2; dX3 = renderHeight - renderHeight / 3 / 2 - size / 2 / 2; } g2d.setColor(color); g2d.fill(new Ellipse2D.Double(dX1, dY1, size / 2, size / 2)); g2d.fill(new Ellipse2D.Double(dX2, dY2, size, size)); g2d.fill(new Ellipse2D.Double(dX3, dY3, size / 2, size / 2)); } } \ No newline at end of file diff --git a/src/main/java/jcs/ui/layout/tiles/Cross.java b/src/main/java/jcs/ui/layout/tiles/Cross.java index 72e03d11..7b35150e 100644 --- a/src/main/java/jcs/ui/layout/tiles/Cross.java +++ b/src/main/java/jcs/ui/layout/tiles/Cross.java @@ -1,655 +1 @@ -/* - * Copyright 2023 Frans Jacobs. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package jcs.ui.layout.tiles; - -import java.awt.BasicStroke; -import java.awt.Color; -import java.awt.Graphics2D; -import java.awt.Point; -import java.awt.Rectangle; -import java.awt.geom.Ellipse2D; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Map; -import java.util.Set; -import jcs.entities.AccessoryBean.AccessoryValue; -import static jcs.entities.AccessoryBean.AccessoryValue.GREEN; -import static jcs.entities.AccessoryBean.AccessoryValue.RED; -import jcs.entities.TileBean; -import jcs.entities.TileBean.Direction; -import jcs.entities.TileBean.Orientation; -import static jcs.entities.TileBean.Orientation.NORTH; -import static jcs.entities.TileBean.Orientation.SOUTH; -import static jcs.entities.TileBean.Orientation.WEST; -import jcs.entities.TileBean.TileType; -import static jcs.ui.layout.tiles.Tile.DEFAULT_HEIGHT; -import static jcs.ui.layout.tiles.Tile.DEFAULT_WIDTH; -import static jcs.ui.layout.tiles.Tile.GRID; -import static jcs.ui.layout.tiles.Tile.tileHeight; -import static jcs.ui.layout.tiles.Tile.tileWidth; -import org.tinylog.Logger; - -public class Cross extends Switch { - - public static final int CROSS_WIDTH = DEFAULT_WIDTH * 2; - public static final int CROSS_HEIGHT = DEFAULT_HEIGHT * 2; - - public static final Color VERY_LIGHT_RED = new Color(255, 102, 102); - public static final Color LIGHT_RED = new Color(255, 51, 51); - public static final Color DARK_RED = new Color(204, 0, 0); - - public static final Color VERY_LIGHT_GREEN = new Color(102, 255, 102); - public static final Color LIGHT_GREEN = new Color(0, 255, 51); - public static final Color DARK_GREEN = new Color(0, 153, 0); - - public Cross(Orientation orientation, Direction direction, Point center) { - this(orientation, direction, center.x, center.y); - } - - public Cross(Orientation orientation, Direction direction, int x, int y) { - this(orientation, direction, x, y, tileWidth(orientation, TileType.CROSS), tileHeight(orientation, TileType.CROSS)); - } - - public Cross(Orientation orientation, Direction direction, int x, int y, int width, int height) { - super(TileType.CROSS, orientation, direction, x, y, width, height); - changeRenderSizeAndOffsets(); - } - - public Cross(TileBean tileBean) { - super(tileBean, tileWidth(tileBean.getOrientation(), TileType.CROSS), tileHeight(tileBean.getOrientation(), TileType.CROSS)); - changeRenderSizeAndOffsets(); - } - - private void changeRenderSizeAndOffsets() { - //Reset offsets - this.offsetY = 0; - this.renderOffsetY = 0; - this.offsetX = 0; - this.renderOffsetX = 0; - - if (isHorizontal()) { - //this.width = DEFAULT_WIDTH * 2; - //this.height = DEFAULT_HEIGHT; - this.renderWidth = RENDER_GRID * 4; - this.renderHeight = RENDER_GRID * 2; - - this.offsetY = 0; - this.renderOffsetY = 0; - } else { - //this.width = DEFAULT_WIDTH; - //this.height = DEFAULT_HEIGHT * 2; - this.renderWidth = RENDER_GRID * 2; - this.renderHeight = RENDER_GRID * 4; - - this.offsetX = 0; - this.renderOffsetX = 0; - } - - //Due to the asymetical shape (center is on the left) - //the offset has to be changed with the rotation - switch (getOrientation()) { - case SOUTH -> { - this.offsetY = +GRID; - this.renderOffsetY = RENDER_GRID; - } - case WEST -> { - this.offsetX = -GRID; - this.renderOffsetX = -RENDER_GRID; - } - case NORTH -> { - this.offsetY = -GRID; - this.renderOffsetY = -RENDER_GRID; - } - default -> { - //East so default - this.offsetX = +GRID; - this.renderOffsetX = +RENDER_GRID; - } - } - } - -// private void changeRenderSize() { -// if (Orientation.EAST == tileOrientation || Orientation.WEST == tileOrientation) { -// this.renderWidth = RENDER_WIDTH * 2; -// this.renderHeight = RENDER_HEIGHT; -// } else { -// this.renderWidth = RENDER_WIDTH; -// this.renderHeight = RENDER_HEIGHT * 2; -// } -// } - /** - * A Cross has a width in horizontal position of 2 tiles and a height of 1 tile in Vertical position.
- * - * @return the set of center point which mark the position of the Cross - */ - @Override - public Set getAltPoints() { - Set alternatives = new HashSet<>(); - - switch (getOrientation()) { - case SOUTH -> { - Point sp = new Point(tileX, (tileY + DEFAULT_HEIGHT)); - alternatives.add(sp); - } - case WEST -> { - Point wp = new Point((tileX - DEFAULT_WIDTH), tileY); - alternatives.add(wp); - } - case NORTH -> { - Point np = new Point(tileX, (tileY - DEFAULT_HEIGHT)); - alternatives.add(np); - } - default -> { - //East so default - Point ep = new Point((tileX + DEFAULT_WIDTH), tileY); - alternatives.add(ep); - } - } - return alternatives; - } - - @Override - public Map getNeighborPoints() { - Map neighbors = new HashMap<>(); - Orientation orientation = this.getOrientation(); - Direction direction = this.getDirection(); - int cx = this.getCenterX(); - int cy = this.getCenterY(); - - switch (orientation) { - case SOUTH -> { - neighbors.put(Orientation.NORTH, new Point(cx, cy - Tile.GRID * 2)); - neighbors.put(Orientation.SOUTH, new Point(cx, cy + Tile.GRID * 4)); - - if (Direction.LEFT == direction) { - neighbors.put(Orientation.EAST, new Point(cx + Tile.GRID * 2, cy + Tile.GRID * 2)); - neighbors.put(Orientation.WEST, new Point(cx - Tile.GRID * 2, cy)); - } else { - neighbors.put(Orientation.EAST, new Point(cx + Tile.GRID * 2, cy)); - neighbors.put(Orientation.WEST, new Point(cx - Tile.GRID * 2, cy + Tile.GRID * 2)); - } - } - case WEST -> { - neighbors.put(Orientation.EAST, new Point(cx + Tile.GRID * 2, cy)); - neighbors.put(Orientation.WEST, new Point(cx - Tile.GRID * 4, cy)); - - if (Direction.LEFT == direction) { - neighbors.put(Orientation.NORTH, new Point(cx, cy - Tile.GRID * 2)); - neighbors.put(Orientation.SOUTH, new Point(cx - Tile.GRID * 2, cy + Tile.GRID * 2)); - } else { - neighbors.put(Orientation.NORTH, new Point(cx - Tile.GRID * 2, cy - Tile.GRID * 2)); - neighbors.put(Orientation.SOUTH, new Point(cx, cy + Tile.GRID * 2)); - } - } - case NORTH -> { - neighbors.put(Orientation.NORTH, new Point(cx, cy - Tile.GRID * 4)); - neighbors.put(Orientation.SOUTH, new Point(cx, cy + Tile.GRID * 2)); - - if (Direction.LEFT == direction) { - neighbors.put(Orientation.EAST, new Point(cx + Tile.GRID * 2, cy)); - neighbors.put(Orientation.WEST, new Point(cx - Tile.GRID * 2, cy - Tile.GRID * 2)); - } else { - neighbors.put(Orientation.EAST, new Point(cx + Tile.GRID * 2, cy - Tile.GRID * 2)); - neighbors.put(Orientation.WEST, new Point(cx - Tile.GRID * 2, cy)); - } - } - default -> { - //EAST - neighbors.put(Orientation.EAST, new Point(cx + Tile.GRID * 4, cy)); - neighbors.put(Orientation.WEST, new Point(cx - Tile.GRID * 2, cy)); - - if (Direction.LEFT == direction) { - neighbors.put(Orientation.NORTH, new Point(cx + Tile.GRID * 2, cy - Tile.GRID * 2)); - neighbors.put(Orientation.SOUTH, new Point(cx, cy + Tile.GRID * 2)); - } else { - neighbors.put(Orientation.NORTH, new Point(cx, cy - Tile.GRID * 2)); - neighbors.put(Orientation.SOUTH, new Point(cx + Tile.GRID * 2, cy + Tile.GRID * 2)); - } - } - } - return neighbors; - } - - @Override - public Map getEdgePoints() { - Map edgeConnections = new HashMap<>(); - Orientation orientation = this.getOrientation(); - Direction direction = this.getDirection(); - int cx = this.getCenterX(); - int cy = this.getCenterY(); - - switch (orientation) { - case SOUTH -> { - edgeConnections.put(Orientation.NORTH, new Point(cx, cy - Tile.GRID)); - edgeConnections.put(Orientation.SOUTH, new Point(cx, cy + Tile.GRID * 3)); - - if (Direction.LEFT == direction) { - edgeConnections.put(Orientation.EAST, new Point(cx + Tile.GRID, cy + Tile.GRID * 2)); - edgeConnections.put(Orientation.WEST, new Point(cx - Tile.GRID, cy)); - } else { - edgeConnections.put(Orientation.EAST, new Point(cx + Tile.GRID, cy)); - edgeConnections.put(Orientation.WEST, new Point(cx - Tile.GRID, cy + Tile.GRID * 2)); - } - } - case WEST -> { - edgeConnections.put(Orientation.EAST, new Point(cx + Tile.GRID, cy)); - edgeConnections.put(Orientation.WEST, new Point(cx - Tile.GRID * 3, cy)); - - if (Direction.LEFT == direction) { - edgeConnections.put(Orientation.NORTH, new Point(cx, cy - Tile.GRID)); - edgeConnections.put(Orientation.SOUTH, new Point(cx - Tile.GRID * 2, cy + Tile.GRID)); - } else { - edgeConnections.put(Orientation.NORTH, new Point(cx - Tile.GRID * 2, cy - Tile.GRID)); - edgeConnections.put(Orientation.SOUTH, new Point(cx, cy + Tile.GRID)); - } - } - case NORTH -> { - edgeConnections.put(Orientation.NORTH, new Point(cx, cy - Tile.GRID * 3)); - edgeConnections.put(Orientation.SOUTH, new Point(cx, cy + Tile.GRID)); - - if (Direction.LEFT == direction) { - edgeConnections.put(Orientation.EAST, new Point(cx + Tile.GRID, cy)); - edgeConnections.put(Orientation.WEST, new Point(cx - Tile.GRID, cy - Tile.GRID * 2)); - } else { - edgeConnections.put(Orientation.EAST, new Point(cx + Tile.GRID, cy - Tile.GRID * 2)); - edgeConnections.put(Orientation.WEST, new Point(cx - Tile.GRID, cy)); - } - } - default -> { - //EAST - edgeConnections.put(Orientation.EAST, new Point(cx + Tile.GRID * 3, cy)); - edgeConnections.put(Orientation.WEST, new Point(cx - Tile.GRID, cy)); - - if (Direction.LEFT == direction) { - edgeConnections.put(Orientation.NORTH, new Point(cx + Tile.GRID * 2, cy - Tile.GRID)); - edgeConnections.put(Orientation.SOUTH, new Point(cx, cy + Tile.GRID)); - } else { - edgeConnections.put(Orientation.NORTH, new Point(cx, cy - Tile.GRID)); - edgeConnections.put(Orientation.SOUTH, new Point(cx + Tile.GRID * 2, cy + Tile.GRID)); - } - } - } - return edgeConnections; - } - - @Override - protected void renderStraight(Graphics2D g2, Color color) { - int xx, yy, w, h; - xx = 0; - yy = 170; - w = RENDER_WIDTH; - h = 60; - - g2.setStroke(new BasicStroke(4, BasicStroke.JOIN_MITER, BasicStroke.JOIN_ROUND)); - g2.setPaint(color); - g2.fillRect(xx, yy, w, h); - } - - @Override - protected void renderRouteStraight(Graphics2D g2, Color color) { - int xx, yy, w, h; - xx = 0; - yy = 190; - w = RENDER_WIDTH; - h = 20; - - g2.setStroke(new BasicStroke(4, BasicStroke.JOIN_MITER, BasicStroke.JOIN_ROUND)); - g2.setPaint(color); - g2.fillRect(xx, yy, w, h); - } - - protected void renderStraight2(Graphics2D g2, Color color) { - int xx, yy, w, h; - xx = RENDER_WIDTH; - yy = 170; - w = RENDER_WIDTH; - h = 60; - - g2.setStroke(new BasicStroke(4, BasicStroke.JOIN_MITER, BasicStroke.JOIN_ROUND)); - g2.setPaint(color); - g2.fillRect(xx, yy, w, h); - } - - protected void renderRouteStraight2(Graphics2D g2, Color color) { - int xx, yy, w, h; - xx = RENDER_WIDTH; - yy = 190; - w = RENDER_WIDTH; - h = 20; - - g2.setStroke(new BasicStroke(4, BasicStroke.JOIN_MITER, BasicStroke.JOIN_ROUND)); - g2.setPaint(color); - g2.fillRect(xx, yy, w, h); - } - - @Override - protected void renderDiagonal(Graphics2D g2, Color color) { - int[] xPoints, yPoints; - if (Direction.RIGHT.equals(getDirection())) { - xPoints = new int[]{400, 400, 167, 230}; - yPoints = new int[]{170, 230, 0, 0}; - } else { - xPoints = new int[]{400, 400, 170, 230}; - yPoints = new int[]{230, 170, 400, 400}; - } - - g2.setStroke(new BasicStroke(4, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND)); - g2.setPaint(color); - g2.fillPolygon(xPoints, yPoints, xPoints.length); - } - - @Override - protected void renderRouteDiagonal(Graphics2D g2, Color color) { - int[] xPoints, yPoints; - if (Direction.RIGHT.equals(getDirection())) { - xPoints = new int[]{420, 400, 190, 210}; - yPoints = new int[]{210, 210, 0, 0}; - } else { - xPoints = new int[]{400, 400, 190, 210}; - yPoints = new int[]{210, 190, 400, 400}; - } - - g2.setStroke(new BasicStroke(4, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND)); - g2.setPaint(color); - g2.fillPolygon(xPoints, yPoints, xPoints.length); - } - - protected void renderDiagonal2(Graphics2D g2, Color color) { - int[] xPoints, yPoints; - if (Direction.RIGHT.equals(getDirection())) { - xPoints = new int[]{400, 400, 570, 630}; - yPoints = new int[]{170, 230, 400, 400}; - } else { - xPoints = new int[]{400, 400, 570, 630}; - yPoints = new int[]{230, 170, 0, 0}; - } - - g2.setStroke(new BasicStroke(4, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND)); - g2.setPaint(color); - g2.fillPolygon(xPoints, yPoints, xPoints.length); - } - - protected void renderRouteDiagonal2(Graphics2D g2, Color color) { - int[] xPoints, yPoints; - if (Direction.RIGHT.equals(getDirection())) { - xPoints = new int[]{400, 380, 590, 610}; - yPoints = new int[]{190, 190, 400, 400}; - } else { - xPoints = new int[]{400, 380, 590, 610}; - yPoints = new int[]{210, 210, 0, 0}; - } - - g2.setStroke(new BasicStroke(4, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND)); - g2.setPaint(color); - g2.setPaint(Color.cyan); - g2.fillPolygon(xPoints, yPoints, xPoints.length); - } - - @Override - public void renderTile(Graphics2D g2) { - if (accessoryValue == null) { - this.accessoryValue = AccessoryValue.OFF; - } - - switch (accessoryValue) { - case RED -> { - renderStraight2(g2, Cross.LIGHT_RED); - renderDiagonal(g2, Cross.LIGHT_RED); - renderStraight(g2, Cross.DARK_RED); - renderDiagonal2(g2, Cross.DARK_RED); - } - case GREEN -> { - renderDiagonal(g2, Cross.VERY_LIGHT_GREEN); - renderDiagonal2(g2, Cross.VERY_LIGHT_GREEN); - renderStraight(g2, Cross.DARK_GREEN); - renderStraight2(g2, Cross.DARK_GREEN); - } - default -> { - renderStraight(g2, trackColor); - renderStraight2(g2, trackColor); - renderDiagonal(g2, trackColor); - renderDiagonal2(g2, trackColor); - } - } - } - - @Override - public void renderTileRoute(Graphics2D g2) { - if (routeValue == null) { - routeValue = AccessoryValue.OFF; - } - if (incomingSide == null) { - incomingSide = getOrientation(); - } - - if (isHorizontal()) { - if (AccessoryValue.GREEN == routeValue && (Orientation.NORTH == incomingSide || Orientation.SOUTH == incomingSide)) { - renderRouteDiagonal(g2, trackRouteColor); - renderRouteDiagonal2(g2, trackRouteColor); - } else if (AccessoryValue.GREEN == routeValue && (Orientation.EAST == incomingSide || Orientation.WEST == incomingSide)) { - renderRouteStraight(g2, trackRouteColor); - renderRouteStraight2(g2, trackRouteColor); - } else if (AccessoryValue.RED == routeValue && Orientation.EAST == getOrientation()) { - if (Direction.RIGHT == getDirection() && (Orientation.EAST == incomingSide || Orientation.NORTH == incomingSide)) { - renderRouteStraight2(g2, trackRouteColor); - renderRouteDiagonal(g2, trackRouteColor); - } else if (Direction.RIGHT == getDirection() && (Orientation.WEST == incomingSide || Orientation.SOUTH == incomingSide)) { - renderRouteDiagonal2(g2, trackRouteColor); - renderRouteStraight(g2, trackRouteColor); - } else if (Direction.LEFT == getDirection() && (Orientation.EAST == incomingSide || Orientation.SOUTH == incomingSide)) { - renderRouteStraight2(g2, trackRouteColor); - renderRouteDiagonal(g2, trackRouteColor); - } else if (Direction.LEFT == getDirection() && (Orientation.WEST == incomingSide || Orientation.NORTH == incomingSide)) { - renderRouteStraight(g2, trackColor); - renderRouteDiagonal2(g2, trackColor); - } - } else if (AccessoryValue.RED == routeValue && Orientation.WEST == getOrientation()) { - if (Direction.RIGHT == getDirection() && (Orientation.EAST == incomingSide || Orientation.NORTH == incomingSide)) { - renderRouteStraight(g2, trackRouteColor); - renderRouteDiagonal2(g2, trackRouteColor); - } else if (Direction.RIGHT == getDirection() && (Orientation.WEST == incomingSide || Orientation.SOUTH == incomingSide)) { - renderRouteDiagonal(g2, trackRouteColor); - renderRouteStraight2(g2, trackRouteColor); - } else if (Direction.LEFT == getDirection() && (Orientation.EAST == incomingSide || Orientation.SOUTH == incomingSide)) { - renderRouteStraight(g2, trackRouteColor); - renderRouteDiagonal2(g2, trackRouteColor); - } else if (Direction.LEFT == getDirection() && (Orientation.WEST == incomingSide || Orientation.NORTH == incomingSide)) { - renderRouteStraight2(g2, trackColor); - renderRouteDiagonal(g2, trackColor); - } - } - } else { - if (AccessoryValue.GREEN == routeValue && (Orientation.NORTH == incomingSide || Orientation.SOUTH == incomingSide)) { - renderRouteStraight(g2, trackRouteColor); - renderRouteStraight2(g2, trackRouteColor); - } else if (AccessoryValue.GREEN == routeValue && (Orientation.EAST == incomingSide || Orientation.WEST == incomingSide)) { - renderRouteDiagonal(g2, trackRouteColor); - renderRouteDiagonal2(g2, trackRouteColor); - } else if (AccessoryValue.RED == routeValue && Orientation.SOUTH == getOrientation()) { - if (Direction.RIGHT == getDirection() && (Orientation.EAST == incomingSide || Orientation.SOUTH == incomingSide)) { - renderRouteStraight2(g2, trackRouteColor); - renderRouteDiagonal(g2, trackRouteColor); - } else if (Direction.RIGHT == getDirection() && (Orientation.WEST == incomingSide || Orientation.NORTH == incomingSide)) { - renderRouteDiagonal2(g2, trackRouteColor); - renderRouteStraight(g2, trackRouteColor); - } else if (Direction.LEFT == getDirection() && (Orientation.EAST == incomingSide || Orientation.NORTH == incomingSide)) { - renderRouteStraight(g2, trackRouteColor); - renderRouteDiagonal2(g2, trackRouteColor); - } else if (Direction.LEFT == getDirection() && (Orientation.WEST == incomingSide || Orientation.SOUTH == incomingSide)) { - renderRouteStraight2(g2, trackColor); - renderRouteDiagonal(g2, trackColor); - } - } else if (AccessoryValue.RED == routeValue && Orientation.NORTH == getOrientation()) { - if (Direction.RIGHT == getDirection() && (Orientation.EAST == incomingSide || Orientation.SOUTH == incomingSide)) { - renderRouteStraight(g2, trackRouteColor); - renderRouteDiagonal2(g2, trackRouteColor); - } else if (Direction.RIGHT == getDirection() && (Orientation.WEST == incomingSide || Orientation.NORTH == incomingSide)) { - renderRouteDiagonal(g2, trackRouteColor); - renderRouteStraight2(g2, trackRouteColor); - } else if (Direction.LEFT == getDirection() && (Orientation.EAST == incomingSide || Orientation.NORTH == incomingSide)) { - renderRouteStraight2(g2, trackRouteColor); - renderRouteDiagonal(g2, trackRouteColor); - } else if (Direction.LEFT == getDirection() && (Orientation.WEST == incomingSide || Orientation.SOUTH == incomingSide)) { - renderRouteStraight(g2, trackColor); - renderRouteDiagonal2(g2, trackColor); - } - } - } - } - - @Override - public AccessoryValue accessoryValueForRoute(Orientation from, Orientation to) { - if (from != null && to != null && this.getDirection() != null) { - switch (this.getDirection()) { - case LEFT -> { - if (this.isHorizontal()) { - if ((from == Orientation.WEST && to == Orientation.EAST) || (from == Orientation.EAST && to == Orientation.WEST)) { - return AccessoryValue.GREEN; - } else if ((from == Orientation.NORTH && to == Orientation.SOUTH) || (from == Orientation.SOUTH && to == Orientation.NORTH)) { - return AccessoryValue.GREEN; - } else if ((from == Orientation.NORTH && to == Orientation.WEST) || (from == Orientation.WEST && to == Orientation.NORTH)) { - return AccessoryValue.RED; - } else if ((from == Orientation.EAST && to == Orientation.SOUTH) || (from == Orientation.SOUTH && to == Orientation.EAST)) { - return AccessoryValue.RED; - } else { - return AccessoryValue.OFF; - } - } else { - //Vertical - if ((from == Orientation.WEST && to == Orientation.EAST) || (from == Orientation.EAST && to == Orientation.WEST)) { - return AccessoryValue.GREEN; - } else if ((from == Orientation.NORTH && to == Orientation.SOUTH) || (from == Orientation.SOUTH && to == Orientation.NORTH)) { - return AccessoryValue.GREEN; - } else if ((from == Orientation.SOUTH && to == Orientation.WEST) || (from == Orientation.WEST && to == Orientation.SOUTH)) { - return AccessoryValue.RED; - } else if ((from == Orientation.EAST && to == Orientation.NORTH) || (from == Orientation.NORTH && to == Orientation.EAST)) { - return AccessoryValue.RED; - } else { - return AccessoryValue.OFF; - } - } - } - case RIGHT -> { - if (this.isHorizontal()) { - if ((from == Orientation.WEST && to == Orientation.EAST) || (from == Orientation.EAST && to == Orientation.WEST)) { - return AccessoryValue.GREEN; - } else if ((from == Orientation.NORTH && to == Orientation.SOUTH) || (from == Orientation.SOUTH && to == Orientation.NORTH)) { - return AccessoryValue.GREEN; - } else if ((from == Orientation.NORTH && to == Orientation.EAST) || (from == Orientation.EAST && to == Orientation.NORTH)) { - return AccessoryValue.RED; - } else if ((from == Orientation.WEST && to == Orientation.SOUTH) || (from == Orientation.SOUTH && to == Orientation.WEST)) { - return AccessoryValue.RED; - } else { - return AccessoryValue.OFF; - } - } else { - //Vertical - if ((from == Orientation.WEST && to == Orientation.EAST) || (from == Orientation.EAST && to == Orientation.WEST)) { - return AccessoryValue.GREEN; - } else if ((from == Orientation.NORTH && to == Orientation.SOUTH) || (from == Orientation.SOUTH && to == Orientation.NORTH)) { - return AccessoryValue.GREEN; - } else if ((from == Orientation.SOUTH && to == Orientation.EAST) || (from == Orientation.EAST && to == Orientation.SOUTH)) { - return AccessoryValue.RED; - } else if ((from == Orientation.WEST && to == Orientation.NORTH) || (from == Orientation.NORTH && to == Orientation.WEST)) { - return AccessoryValue.RED; - } else { - return AccessoryValue.OFF; - } - } - } - default -> { - return AccessoryValue.OFF; - } - } - } else { - return AccessoryValue.OFF; - } - } - - @Override - protected void drawCenterPoint(Graphics2D g2d, Color color, double size) { - //A Cross has 1 alternate point - //1st square holds the centerpoint - //2nd square - double dX1, dX2, dY1, dY2; - Orientation tileOrientation = model.getTileOrienation(); - switch (tileOrientation) { - case SOUTH -> { - dX1 = renderWidth / 2 - size / 2; - dY1 = renderHeight / 2 - renderHeight / 4 - size / 2; - dX2 = renderWidth / 2 + renderWidth - size / 4; - dY2 = renderHeight / 2 - renderHeight / 4 - size / 4; - } - case WEST -> { - dX1 = renderWidth / 2 - renderWidth / 4 - size / 2; - dY1 = renderHeight / 2 - size / 2; - dX2 = renderWidth / 2 + renderWidth / 4 - size / 4; - dY2 = renderHeight / 2 - size / 4; - } - case NORTH -> { - dX1 = renderWidth / 2 - size / 2; - dY1 = renderHeight / 2 - renderHeight / 4 - size / 2; - dX2 = renderWidth / 2 + renderWidth - size / 4; - dY2 = renderHeight / 2 - renderHeight / 4 - size / 4; - } - default -> { - //East - dX1 = renderWidth / 2 - renderWidth / 4 - size / 2; - dY1 = renderHeight / 2 - size / 2; - dX2 = renderWidth / 2 + renderWidth / 4 - size / 4; - dY2 = renderHeight / 2 - size / 4; - } - } - - g2d.setColor(color); - g2d.fill(new Ellipse2D.Double(dX1, dY1, size, size)); - g2d.fill(new Ellipse2D.Double(dX2, dY2, size / 2, size / 2)); - } - - @Override - public Rectangle getTileBounds() { - int multiplier = (model.isScaleImage() ? 1 : 10); - int xx, yy; - //Centerpoint is inbalanced - Orientation tileOrientation = model.getTileOrienation(); - switch (tileOrientation) { - case SOUTH -> { - xx = tileX - GRID * multiplier; - yy = tileY - GRID * multiplier; - } - case WEST -> { - xx = tileX - GRID * multiplier - GRID * 2 * multiplier; - yy = tileY - GRID * multiplier; - } - case NORTH -> { - xx = tileX - GRID * multiplier; - yy = tileY - GRID * multiplier - GRID * 2 * multiplier; - } - default -> { - //East - xx = tileX - GRID * multiplier; - yy = tileY - GRID * multiplier; - } - } - - if (model.isScaleImage()) { - return new Rectangle(xx, yy, tileWidth(tileOrientation, TileType.CROSS), tileHeight(tileOrientation, TileType.CROSS)); - } else { - return new Rectangle(xx, yy, renderWidth, renderHeight); - } - } - -} +/* * Copyright 2023 Frans Jacobs. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package jcs.ui.layout.tiles; import java.awt.BasicStroke; import java.awt.Color; import java.awt.Dimension; import java.awt.Graphics2D; import java.awt.Point; import java.awt.Rectangle; import java.awt.geom.Ellipse2D; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set; import jcs.entities.AccessoryBean.AccessoryValue; import static jcs.entities.AccessoryBean.AccessoryValue.GREEN; import static jcs.entities.AccessoryBean.AccessoryValue.RED; import jcs.entities.TileBean; import jcs.entities.TileBean.Direction; import jcs.entities.TileBean.Orientation; import static jcs.entities.TileBean.Orientation.NORTH; import static jcs.entities.TileBean.Orientation.SOUTH; import static jcs.entities.TileBean.Orientation.WEST; import jcs.entities.TileBean.TileType; import static jcs.ui.layout.tiles.Tile.DEFAULT_HEIGHT; import static jcs.ui.layout.tiles.Tile.DEFAULT_WIDTH; import static jcs.ui.layout.tiles.Tile.GRID; import static jcs.ui.layout.tiles.Tile.tileHeight; import static jcs.ui.layout.tiles.Tile.tileWidth; import org.tinylog.Logger; public class Cross extends Switch { public static final int CROSS_WIDTH = DEFAULT_WIDTH * 2; public static final int CROSS_HEIGHT = DEFAULT_HEIGHT * 2; public static final Color VERY_LIGHT_RED = new Color(255, 102, 102); public static final Color LIGHT_RED = new Color(255, 51, 51); public static final Color DARK_RED = new Color(204, 0, 0); public static final Color VERY_LIGHT_GREEN = new Color(102, 255, 102); public static final Color LIGHT_GREEN = new Color(0, 255, 51); public static final Color DARK_GREEN = new Color(0, 153, 0); public Cross(Orientation orientation, Direction direction, Point center) { this(orientation, direction, center.x, center.y); } public Cross(Orientation orientation, Direction direction, int x, int y) { this(orientation, direction, x, y, tileWidth(orientation, TileType.CROSS), tileHeight(orientation, TileType.CROSS)); } public Cross(Orientation orientation, Direction direction, int x, int y, int width, int height) { super(TileType.CROSS, orientation, direction, x, y, width, height); changeRenderSizeAndOffsets(); } public Cross(TileBean tileBean) { super(tileBean, tileWidth(tileBean.getOrientation(), TileType.CROSS), tileHeight(tileBean.getOrientation(), TileType.CROSS)); changeRenderSizeAndOffsets(); } /** * A Cross has a width in horizontal position of 2 tiles and a height of 1 tile in Vertical position.
* * @return the set of center point which mark the position of the Cross */ @Override public Set getAltPoints() { Set alternatives = new HashSet<>(); switch (getOrientation()) { case SOUTH -> { Point sp = new Point(tileX, (tileY + DEFAULT_HEIGHT)); alternatives.add(sp); } case WEST -> { Point wp = new Point((tileX - DEFAULT_WIDTH), tileY); alternatives.add(wp); } case NORTH -> { Point np = new Point(tileX, (tileY - DEFAULT_HEIGHT)); alternatives.add(np); } default -> { //East so default Point ep = new Point((tileX + DEFAULT_WIDTH), tileY); alternatives.add(ep); } } return alternatives; } @Override public Map getNeighborPoints() { Map neighbors = new HashMap<>(); Orientation orientation = this.getOrientation(); Direction direction = this.getDirection(); int cx = this.getCenterX(); int cy = this.getCenterY(); switch (orientation) { case SOUTH -> { neighbors.put(Orientation.NORTH, new Point(cx, cy - Tile.GRID * 2)); neighbors.put(Orientation.SOUTH, new Point(cx, cy + Tile.GRID * 4)); if (Direction.LEFT == direction) { neighbors.put(Orientation.EAST, new Point(cx + Tile.GRID * 2, cy + Tile.GRID * 2)); neighbors.put(Orientation.WEST, new Point(cx - Tile.GRID * 2, cy)); } else { neighbors.put(Orientation.EAST, new Point(cx + Tile.GRID * 2, cy)); neighbors.put(Orientation.WEST, new Point(cx - Tile.GRID * 2, cy + Tile.GRID * 2)); } } case WEST -> { neighbors.put(Orientation.EAST, new Point(cx + Tile.GRID * 2, cy)); neighbors.put(Orientation.WEST, new Point(cx - Tile.GRID * 4, cy)); if (Direction.LEFT == direction) { neighbors.put(Orientation.NORTH, new Point(cx, cy - Tile.GRID * 2)); neighbors.put(Orientation.SOUTH, new Point(cx - Tile.GRID * 2, cy + Tile.GRID * 2)); } else { neighbors.put(Orientation.NORTH, new Point(cx - Tile.GRID * 2, cy - Tile.GRID * 2)); neighbors.put(Orientation.SOUTH, new Point(cx, cy + Tile.GRID * 2)); } } case NORTH -> { neighbors.put(Orientation.NORTH, new Point(cx, cy - Tile.GRID * 4)); neighbors.put(Orientation.SOUTH, new Point(cx, cy + Tile.GRID * 2)); if (Direction.LEFT == direction) { neighbors.put(Orientation.EAST, new Point(cx + Tile.GRID * 2, cy)); neighbors.put(Orientation.WEST, new Point(cx - Tile.GRID * 2, cy - Tile.GRID * 2)); } else { neighbors.put(Orientation.EAST, new Point(cx + Tile.GRID * 2, cy - Tile.GRID * 2)); neighbors.put(Orientation.WEST, new Point(cx - Tile.GRID * 2, cy)); } } default -> { //EAST neighbors.put(Orientation.EAST, new Point(cx + Tile.GRID * 4, cy)); neighbors.put(Orientation.WEST, new Point(cx - Tile.GRID * 2, cy)); if (Direction.LEFT == direction) { neighbors.put(Orientation.NORTH, new Point(cx + Tile.GRID * 2, cy - Tile.GRID * 2)); neighbors.put(Orientation.SOUTH, new Point(cx, cy + Tile.GRID * 2)); } else { neighbors.put(Orientation.NORTH, new Point(cx, cy - Tile.GRID * 2)); neighbors.put(Orientation.SOUTH, new Point(cx + Tile.GRID * 2, cy + Tile.GRID * 2)); } } } return neighbors; } @Override public Map getEdgePoints() { Map edgeConnections = new HashMap<>(); Orientation orientation = this.getOrientation(); Direction direction = this.getDirection(); int cx = this.getCenterX(); int cy = this.getCenterY(); switch (orientation) { case SOUTH -> { edgeConnections.put(Orientation.NORTH, new Point(cx, cy - Tile.GRID)); edgeConnections.put(Orientation.SOUTH, new Point(cx, cy + Tile.GRID * 3)); if (Direction.LEFT == direction) { edgeConnections.put(Orientation.EAST, new Point(cx + Tile.GRID, cy + Tile.GRID * 2)); edgeConnections.put(Orientation.WEST, new Point(cx - Tile.GRID, cy)); } else { edgeConnections.put(Orientation.EAST, new Point(cx + Tile.GRID, cy)); edgeConnections.put(Orientation.WEST, new Point(cx - Tile.GRID, cy + Tile.GRID * 2)); } } case WEST -> { edgeConnections.put(Orientation.EAST, new Point(cx + Tile.GRID, cy)); edgeConnections.put(Orientation.WEST, new Point(cx - Tile.GRID * 3, cy)); if (Direction.LEFT == direction) { edgeConnections.put(Orientation.NORTH, new Point(cx, cy - Tile.GRID)); edgeConnections.put(Orientation.SOUTH, new Point(cx - Tile.GRID * 2, cy + Tile.GRID)); } else { edgeConnections.put(Orientation.NORTH, new Point(cx - Tile.GRID * 2, cy - Tile.GRID)); edgeConnections.put(Orientation.SOUTH, new Point(cx, cy + Tile.GRID)); } } case NORTH -> { edgeConnections.put(Orientation.NORTH, new Point(cx, cy - Tile.GRID * 3)); edgeConnections.put(Orientation.SOUTH, new Point(cx, cy + Tile.GRID)); if (Direction.LEFT == direction) { edgeConnections.put(Orientation.EAST, new Point(cx + Tile.GRID, cy)); edgeConnections.put(Orientation.WEST, new Point(cx - Tile.GRID, cy - Tile.GRID * 2)); } else { edgeConnections.put(Orientation.EAST, new Point(cx + Tile.GRID, cy - Tile.GRID * 2)); edgeConnections.put(Orientation.WEST, new Point(cx - Tile.GRID, cy)); } } default -> { //EAST edgeConnections.put(Orientation.EAST, new Point(cx + Tile.GRID * 3, cy)); edgeConnections.put(Orientation.WEST, new Point(cx - Tile.GRID, cy)); if (Direction.LEFT == direction) { edgeConnections.put(Orientation.NORTH, new Point(cx + Tile.GRID * 2, cy - Tile.GRID)); edgeConnections.put(Orientation.SOUTH, new Point(cx, cy + Tile.GRID)); } else { edgeConnections.put(Orientation.NORTH, new Point(cx, cy - Tile.GRID)); edgeConnections.put(Orientation.SOUTH, new Point(cx + Tile.GRID * 2, cy + Tile.GRID)); } } } return edgeConnections; } @Override protected void renderStraight(Graphics2D g2, Color color) { int xx, yy, w, h; xx = 0; yy = 170; w = RENDER_WIDTH; h = 60; g2.setStroke(new BasicStroke(4, BasicStroke.JOIN_MITER, BasicStroke.JOIN_ROUND)); g2.setPaint(color); g2.fillRect(xx, yy, w, h); } @Override protected void renderRouteStraight(Graphics2D g2, Color color) { int xx, yy, w, h; xx = 0; yy = 190; w = RENDER_WIDTH; h = 20; g2.setStroke(new BasicStroke(4, BasicStroke.JOIN_MITER, BasicStroke.JOIN_ROUND)); g2.setPaint(color); g2.fillRect(xx, yy, w, h); } protected void renderStraight2(Graphics2D g2, Color color) { int xx, yy, w, h; xx = RENDER_WIDTH; yy = 170; w = RENDER_WIDTH; h = 60; g2.setStroke(new BasicStroke(4, BasicStroke.JOIN_MITER, BasicStroke.JOIN_ROUND)); g2.setPaint(color); g2.fillRect(xx, yy, w, h); } protected void renderRouteStraight2(Graphics2D g2, Color color) { int xx, yy, w, h; xx = RENDER_WIDTH; yy = 190; w = RENDER_WIDTH; h = 20; g2.setStroke(new BasicStroke(4, BasicStroke.JOIN_MITER, BasicStroke.JOIN_ROUND)); g2.setPaint(color); g2.fillRect(xx, yy, w, h); } @Override protected void renderDiagonal(Graphics2D g2, Color color) { int[] xPoints, yPoints; if (Direction.RIGHT.equals(getDirection())) { xPoints = new int[]{400, 400, 167, 230}; yPoints = new int[]{170, 230, 0, 0}; } else { xPoints = new int[]{400, 400, 170, 230}; yPoints = new int[]{230, 170, 400, 400}; } g2.setStroke(new BasicStroke(4, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND)); g2.setPaint(color); g2.fillPolygon(xPoints, yPoints, xPoints.length); } @Override protected void renderRouteDiagonal(Graphics2D g2, Color color) { int[] xPoints, yPoints; if (Direction.RIGHT.equals(getDirection())) { xPoints = new int[]{420, 400, 190, 210}; yPoints = new int[]{210, 210, 0, 0}; } else { xPoints = new int[]{400, 400, 190, 210}; yPoints = new int[]{210, 190, 400, 400}; } g2.setStroke(new BasicStroke(4, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND)); g2.setPaint(color); g2.fillPolygon(xPoints, yPoints, xPoints.length); } protected void renderDiagonal2(Graphics2D g2, Color color) { int[] xPoints, yPoints; if (Direction.RIGHT.equals(getDirection())) { xPoints = new int[]{400, 400, 570, 630}; yPoints = new int[]{170, 230, 400, 400}; } else { xPoints = new int[]{400, 400, 570, 630}; yPoints = new int[]{230, 170, 0, 0}; } g2.setStroke(new BasicStroke(4, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND)); g2.setPaint(color); g2.fillPolygon(xPoints, yPoints, xPoints.length); } protected void renderRouteDiagonal2(Graphics2D g2, Color color) { int[] xPoints, yPoints; if (Direction.RIGHT.equals(getDirection())) { xPoints = new int[]{400, 380, 590, 610}; yPoints = new int[]{190, 190, 400, 400}; } else { xPoints = new int[]{400, 380, 590, 610}; yPoints = new int[]{210, 210, 0, 0}; } g2.setStroke(new BasicStroke(4, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND)); g2.setPaint(color); g2.setPaint(Color.cyan); g2.fillPolygon(xPoints, yPoints, xPoints.length); } @Override public void renderTile(Graphics2D g2) { if (accessoryValue == null) { this.accessoryValue = AccessoryValue.OFF; } switch (accessoryValue) { case RED -> { renderStraight2(g2, Cross.LIGHT_RED); renderDiagonal(g2, Cross.LIGHT_RED); renderStraight(g2, Cross.DARK_RED); renderDiagonal2(g2, Cross.DARK_RED); } case GREEN -> { renderDiagonal(g2, Cross.VERY_LIGHT_GREEN); renderDiagonal2(g2, Cross.VERY_LIGHT_GREEN); renderStraight(g2, Cross.DARK_GREEN); renderStraight2(g2, Cross.DARK_GREEN); } default -> { renderStraight(g2, trackColor); renderStraight2(g2, trackColor); renderDiagonal(g2, trackColor); renderDiagonal2(g2, trackColor); } } } @Override public void renderTileRoute(Graphics2D g2) { if (routeValue == null) { routeValue = AccessoryValue.OFF; } if (incomingSide == null) { incomingSide = getOrientation(); } if (isHorizontal()) { if (AccessoryValue.GREEN == routeValue && (Orientation.NORTH == incomingSide || Orientation.SOUTH == incomingSide)) { renderRouteDiagonal(g2, trackRouteColor); renderRouteDiagonal2(g2, trackRouteColor); } else if (AccessoryValue.GREEN == routeValue && (Orientation.EAST == incomingSide || Orientation.WEST == incomingSide)) { renderRouteStraight(g2, trackRouteColor); renderRouteStraight2(g2, trackRouteColor); } else if (AccessoryValue.RED == routeValue && Orientation.EAST == getOrientation()) { if (Direction.RIGHT == getDirection() && (Orientation.EAST == incomingSide || Orientation.NORTH == incomingSide)) { renderRouteStraight2(g2, trackRouteColor); renderRouteDiagonal(g2, trackRouteColor); } else if (Direction.RIGHT == getDirection() && (Orientation.WEST == incomingSide || Orientation.SOUTH == incomingSide)) { renderRouteDiagonal2(g2, trackRouteColor); renderRouteStraight(g2, trackRouteColor); } else if (Direction.LEFT == getDirection() && (Orientation.EAST == incomingSide || Orientation.SOUTH == incomingSide)) { renderRouteStraight2(g2, trackRouteColor); renderRouteDiagonal(g2, trackRouteColor); } else if (Direction.LEFT == getDirection() && (Orientation.WEST == incomingSide || Orientation.NORTH == incomingSide)) { renderRouteStraight(g2, trackColor); renderRouteDiagonal2(g2, trackColor); } } else if (AccessoryValue.RED == routeValue && Orientation.WEST == getOrientation()) { if (Direction.RIGHT == getDirection() && (Orientation.EAST == incomingSide || Orientation.NORTH == incomingSide)) { renderRouteStraight(g2, trackRouteColor); renderRouteDiagonal2(g2, trackRouteColor); } else if (Direction.RIGHT == getDirection() && (Orientation.WEST == incomingSide || Orientation.SOUTH == incomingSide)) { renderRouteDiagonal(g2, trackRouteColor); renderRouteStraight2(g2, trackRouteColor); } else if (Direction.LEFT == getDirection() && (Orientation.EAST == incomingSide || Orientation.SOUTH == incomingSide)) { renderRouteStraight(g2, trackRouteColor); renderRouteDiagonal2(g2, trackRouteColor); } else if (Direction.LEFT == getDirection() && (Orientation.WEST == incomingSide || Orientation.NORTH == incomingSide)) { renderRouteStraight2(g2, trackColor); renderRouteDiagonal(g2, trackColor); } } } else { if (AccessoryValue.GREEN == routeValue && (Orientation.NORTH == incomingSide || Orientation.SOUTH == incomingSide)) { renderRouteStraight(g2, trackRouteColor); renderRouteStraight2(g2, trackRouteColor); } else if (AccessoryValue.GREEN == routeValue && (Orientation.EAST == incomingSide || Orientation.WEST == incomingSide)) { renderRouteDiagonal(g2, trackRouteColor); renderRouteDiagonal2(g2, trackRouteColor); } else if (AccessoryValue.RED == routeValue && Orientation.SOUTH == getOrientation()) { if (Direction.RIGHT == getDirection() && (Orientation.EAST == incomingSide || Orientation.SOUTH == incomingSide)) { renderRouteStraight2(g2, trackRouteColor); renderRouteDiagonal(g2, trackRouteColor); } else if (Direction.RIGHT == getDirection() && (Orientation.WEST == incomingSide || Orientation.NORTH == incomingSide)) { renderRouteDiagonal2(g2, trackRouteColor); renderRouteStraight(g2, trackRouteColor); } else if (Direction.LEFT == getDirection() && (Orientation.EAST == incomingSide || Orientation.NORTH == incomingSide)) { renderRouteStraight(g2, trackRouteColor); renderRouteDiagonal2(g2, trackRouteColor); } else if (Direction.LEFT == getDirection() && (Orientation.WEST == incomingSide || Orientation.SOUTH == incomingSide)) { renderRouteStraight2(g2, trackColor); renderRouteDiagonal(g2, trackColor); } } else if (AccessoryValue.RED == routeValue && Orientation.NORTH == getOrientation()) { if (Direction.RIGHT == getDirection() && (Orientation.EAST == incomingSide || Orientation.SOUTH == incomingSide)) { renderRouteStraight(g2, trackRouteColor); renderRouteDiagonal2(g2, trackRouteColor); } else if (Direction.RIGHT == getDirection() && (Orientation.WEST == incomingSide || Orientation.NORTH == incomingSide)) { renderRouteDiagonal(g2, trackRouteColor); renderRouteStraight2(g2, trackRouteColor); } else if (Direction.LEFT == getDirection() && (Orientation.EAST == incomingSide || Orientation.NORTH == incomingSide)) { renderRouteStraight2(g2, trackRouteColor); renderRouteDiagonal(g2, trackRouteColor); } else if (Direction.LEFT == getDirection() && (Orientation.WEST == incomingSide || Orientation.SOUTH == incomingSide)) { renderRouteStraight(g2, trackColor); renderRouteDiagonal2(g2, trackColor); } } } } @Override public AccessoryValue accessoryValueForRoute(Orientation from, Orientation to) { if (from != null && to != null && this.getDirection() != null) { switch (this.getDirection()) { case LEFT -> { if (this.isHorizontal()) { if ((from == Orientation.WEST && to == Orientation.EAST) || (from == Orientation.EAST && to == Orientation.WEST)) { return AccessoryValue.GREEN; } else if ((from == Orientation.NORTH && to == Orientation.SOUTH) || (from == Orientation.SOUTH && to == Orientation.NORTH)) { return AccessoryValue.GREEN; } else if ((from == Orientation.NORTH && to == Orientation.WEST) || (from == Orientation.WEST && to == Orientation.NORTH)) { return AccessoryValue.RED; } else if ((from == Orientation.EAST && to == Orientation.SOUTH) || (from == Orientation.SOUTH && to == Orientation.EAST)) { return AccessoryValue.RED; } else { return AccessoryValue.OFF; } } else { //Vertical if ((from == Orientation.WEST && to == Orientation.EAST) || (from == Orientation.EAST && to == Orientation.WEST)) { return AccessoryValue.GREEN; } else if ((from == Orientation.NORTH && to == Orientation.SOUTH) || (from == Orientation.SOUTH && to == Orientation.NORTH)) { return AccessoryValue.GREEN; } else if ((from == Orientation.SOUTH && to == Orientation.WEST) || (from == Orientation.WEST && to == Orientation.SOUTH)) { return AccessoryValue.RED; } else if ((from == Orientation.EAST && to == Orientation.NORTH) || (from == Orientation.NORTH && to == Orientation.EAST)) { return AccessoryValue.RED; } else { return AccessoryValue.OFF; } } } case RIGHT -> { if (this.isHorizontal()) { if ((from == Orientation.WEST && to == Orientation.EAST) || (from == Orientation.EAST && to == Orientation.WEST)) { return AccessoryValue.GREEN; } else if ((from == Orientation.NORTH && to == Orientation.SOUTH) || (from == Orientation.SOUTH && to == Orientation.NORTH)) { return AccessoryValue.GREEN; } else if ((from == Orientation.NORTH && to == Orientation.EAST) || (from == Orientation.EAST && to == Orientation.NORTH)) { return AccessoryValue.RED; } else if ((from == Orientation.WEST && to == Orientation.SOUTH) || (from == Orientation.SOUTH && to == Orientation.WEST)) { return AccessoryValue.RED; } else { return AccessoryValue.OFF; } } else { //Vertical if ((from == Orientation.WEST && to == Orientation.EAST) || (from == Orientation.EAST && to == Orientation.WEST)) { return AccessoryValue.GREEN; } else if ((from == Orientation.NORTH && to == Orientation.SOUTH) || (from == Orientation.SOUTH && to == Orientation.NORTH)) { return AccessoryValue.GREEN; } else if ((from == Orientation.SOUTH && to == Orientation.EAST) || (from == Orientation.EAST && to == Orientation.SOUTH)) { return AccessoryValue.RED; } else if ((from == Orientation.WEST && to == Orientation.NORTH) || (from == Orientation.NORTH && to == Orientation.WEST)) { return AccessoryValue.RED; } else { return AccessoryValue.OFF; } } } default -> { return AccessoryValue.OFF; } } } else { return AccessoryValue.OFF; } } @Override protected void drawCenterPoint(Graphics2D g2d, Color color, double size) { //A Cross has 1 alternate point //1st square holds the centerpoint //2nd square double dX1, dX2, dY1, dY2; Orientation tileOrientation = model.getTileOrienation(); switch (tileOrientation) { case SOUTH -> { dX1 = renderWidth / 2 - size / 2; dY1 = renderHeight / 2 - renderHeight / 4 - size / 2; dX2 = renderWidth / 2 + renderWidth - size / 4; dY2 = renderHeight / 2 - renderHeight / 4 - size / 4; } case WEST -> { dX1 = renderWidth / 2 - renderWidth / 4 - size / 2; dY1 = renderHeight / 2 - size / 2; dX2 = renderWidth / 2 + renderWidth / 4 - size / 4; dY2 = renderHeight / 2 - size / 4; } case NORTH -> { dX1 = renderWidth / 2 - size / 2; dY1 = renderHeight / 2 - renderHeight / 4 - size / 2; dX2 = renderWidth / 2 + renderWidth - size / 4; dY2 = renderHeight / 2 - renderHeight / 4 - size / 4; } default -> { //East dX1 = renderWidth / 2 - renderWidth / 4 - size / 2; dY1 = renderHeight / 2 - size / 2; dX2 = renderWidth / 2 + renderWidth / 4 - size / 4; dY2 = renderHeight / 2 - size / 4; } } g2d.setColor(color); g2d.fill(new Ellipse2D.Double(dX1, dY1, size, size)); g2d.fill(new Ellipse2D.Double(dX2, dY2, size / 2, size / 2)); } @Override public Rectangle getTileBounds() { Orientation tileOrientation = model.getTileOrienation(); int xx, yy, w, h, multiplier; if (model.isScaleImage()) { w = tileWidth(tileOrientation, TileType.CROSS); h = tileHeight(tileOrientation, TileType.CROSS); multiplier = 1; } else { w = renderWidth; h = renderHeight; multiplier = 10; } switch (tileOrientation) { case SOUTH -> { xx = tileX - GRID * multiplier; yy = tileY - GRID * multiplier; } case WEST -> { xx = tileX - GRID * multiplier - GRID * 2 * multiplier; yy = tileY - GRID * multiplier; } case NORTH -> { xx = tileX - GRID * multiplier; yy = tileY - GRID * multiplier - GRID * 2 * multiplier; } default -> { //East xx = tileX - GRID * multiplier; yy = tileY - GRID * multiplier; } } Logger.trace(id + " O: " + tileOrientation + " Cur Cp: " + xyToString() + " New DsP: (" + xx + ", " + yy + ") W: " + w + " H: " + h + " M: " + multiplier + " Ox: " + offsetX + " Oy: " + offsetY); if (model.isScaleImage()) { return new Rectangle(xx, yy, tileWidth(tileOrientation, TileType.CROSS), tileHeight(tileOrientation, TileType.CROSS)); } else { return new Rectangle(xx, yy, renderWidth, renderHeight); } } private void changeRenderSizeAndOffsets() { //Reset offsets this.offsetY = 0; this.renderOffsetY = 0; this.offsetX = 0; this.renderOffsetX = 0; if (isHorizontal()) { //this.width = DEFAULT_WIDTH * 2; //this.height = DEFAULT_HEIGHT; this.renderWidth = RENDER_GRID * 4; this.renderHeight = RENDER_GRID * 2; this.offsetY = 0; this.renderOffsetY = 0; } else { //this.width = DEFAULT_WIDTH; //this.height = DEFAULT_HEIGHT * 2; this.renderWidth = RENDER_GRID * 2; this.renderHeight = RENDER_GRID * 4; this.offsetX = 0; this.renderOffsetX = 0; } //Due to the asymetical shape (center is on the left) //the offset has to be changed with the rotation Orientation tileOrientation = model.getTileOrienation(); switch (tileOrientation) { case SOUTH -> { this.offsetY = +GRID; this.renderOffsetY = RENDER_GRID; } case WEST -> { this.offsetX = -GRID; this.renderOffsetX = -RENDER_GRID; } case NORTH -> { this.offsetY = -GRID; this.renderOffsetY = -RENDER_GRID; } default -> { //East so default this.offsetX = +GRID; this.renderOffsetX = +RENDER_GRID; } } } @Override public Orientation rotate() { super.rotate(); Orientation tileOrientation = model.getTileOrienation(); int w = tileWidth(tileOrientation, TileType.CROSS); int h = tileHeight(tileOrientation, TileType.CROSS); //the centerpoin can shift as a cross is inbalanced int multiplier = (model.isScaleImage() ? 1 : 10); int x, y; switch (tileOrientation) { case SOUTH -> { //the centerpoint remains the same x = tileX; y = tileY; } case WEST -> { // centerpoint shifts to the 2nd square x = tileX; // - GRID * multiplier - GRID * 2 * multiplier; y = tileY; // - GRID * multiplier; } case NORTH -> { x = tileX; // - GRID * multiplier; y = tileY; // - GRID * multiplier - GRID * 2 * multiplier; } default -> { //East x = tileX; y = tileY; } } Dimension d = new Dimension(w, h); setPreferredSize(d); setSize(d); changeRenderSizeAndOffsets(); //set the new center this.tileX = x; this.tileY = y; Logger.trace(id + " O: " + tileOrientation + " Cur Cp: " + xyToString() + " New CP: (" + x + ", " + y + ") W: " + w + " H: " + h + " M: " + multiplier + " Ox: " + offsetX + " Oy: " + offsetY); setBounds(getTileBounds()); return tileOrientation; } } \ No newline at end of file diff --git a/src/main/java/jcs/ui/layout/tiles/Tile.java b/src/main/java/jcs/ui/layout/tiles/Tile.java index fdf6acf3..dfd1939e 100755 --- a/src/main/java/jcs/ui/layout/tiles/Tile.java +++ b/src/main/java/jcs/ui/layout/tiles/Tile.java @@ -1,1131 +1 @@ -/* - * Copyright 2024 Frans Jacobs. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package jcs.ui.layout.tiles; - -import java.awt.Color; -import java.awt.Dimension; -import java.awt.Graphics; -import java.awt.Graphics2D; -import java.awt.Point; -import java.awt.Rectangle; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; -import java.awt.geom.AffineTransform; -import java.awt.geom.Ellipse2D; -import java.awt.image.AffineTransformOp; -import java.awt.image.BufferedImage; -import java.beans.PropertyChangeListener; -import java.io.Serializable; -import java.util.Collection; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Set; -import javax.swing.JComponent; -import javax.swing.event.ChangeEvent; -import javax.swing.event.ChangeListener; -import jcs.entities.AccessoryBean; -import jcs.entities.AccessoryBean.AccessoryValue; -import jcs.entities.AccessoryBean.SignalType; -import jcs.entities.BlockBean; -import jcs.entities.BlockBean.BlockState; -import jcs.entities.LocomotiveBean; -import jcs.entities.SensorBean; -import jcs.entities.TileBean; -import jcs.entities.TileBean.Direction; -import jcs.entities.TileBean.Orientation; -import jcs.entities.TileBean.TileType; -import jcs.ui.layout.LayoutUtil; -import static jcs.ui.layout.tiles.Block.BLOCK_HEIGHT; -import static jcs.ui.layout.tiles.Block.BLOCK_WIDTH; -import org.imgscalr.Scalr; -import org.imgscalr.Scalr.Method; -import org.imgscalr.Scalr.Mode; -import org.tinylog.Logger; - -/** - * Basic graphic element to display a track, turnout, etc on the screen.
- * By default the drawing of a Tile is Horizontal from L to R or West to East.
- * The default orientation is East. - * - *

- * The default size of a Tile is 40 tileX 40 pixels.
- * The center point of a Tile is stored and always snapped to the nearest grid point.
- * The basic grid is 20x 20 pixels.
- * - *

- * A Tile can be rotated (always clockwise).
- * Rotation will change the orientation from East -> South -> West -> North -> East.
- * - *

- * A Tile is rendered to a Buffered Image to speed up the display - */ -public abstract class Tile extends JComponent { //implements TileEventListener { //, ItemSelectable { - - public static final int GRID = 20; - public static final int DEFAULT_WIDTH = GRID * 2; - public static final int DEFAULT_HEIGHT = GRID * 2; - - static final int RENDER_GRID = GRID * 10; - static final int RENDER_WIDTH = RENDER_GRID * 2; - static final int RENDER_HEIGHT = RENDER_GRID * 2; - - public static final Color DEFAULT_BACKGROUND_COLOR = Color.white; - public static final Color DEFAULT_TRACK_COLOR = Color.lightGray; - public static final Color DEFAULT_ROUTE_TRACK_COLOR = Color.blue; - public static final Color DEFAULT_SELECTED_COLOR = Color.yellow; - - public static final String MODEL_CHANGED_PROPERTY = "model"; - public static final String CONTENT_AREA_FILLED_CHANGED_PROPERTY = "contentAreaFilled"; - - /** - * The data model that determines the button's state. - */ - protected TileModel model = null; - - protected String id; - protected Integer tileX; - protected Integer tileY; - - protected int renderWidth; - protected int renderHeight; - - //protected Orientation tileOrientation; - protected Direction tileDirection; - - protected TileType tileType; - protected String accessoryId; - protected String sensorId; - - protected AccessoryValue accessoryValue; - protected AccessoryValue routeValue; - - protected SignalType signalType; - protected AccessoryBean.SignalValue signalValue; - - protected TileBean tileBean; - protected AccessoryBean accessoryBean; - protected SensorBean sensorBean; - protected BlockBean blockBean; - - protected List neighbours; - - protected int offsetX = 0; - protected int offsetY = 0; - - protected int renderOffsetX = 0; - protected int renderOffsetY = 0; - - protected Color selectedColor; - protected Color trackColor; - protected Color trackRouteColor; - protected Orientation incomingSide; - - protected Color backgroundColor; - protected boolean drawName = true; - - protected BufferedImage tileImage; - - protected PropertyChangeListener propertyChangeListener; - - protected ChangeListener changeListener = null; - protected ActionListener actionListener = null; - - protected transient ChangeEvent changeEvent; - - private Handler handler; - - protected Tile(TileType tileType, Orientation orientation, Point center, int width, int height) { - this(tileType, orientation, Direction.CENTER, center.x, center.y, width, height); - } - - protected Tile(TileType tileType, Orientation orientation, int x, int y, int width, int height) { - this(tileType, orientation, Direction.CENTER, x, y, width, height); - } - - protected Tile(TileType tileType, Orientation orientation, Direction direction, int x, int y, int width, int height) { - this(tileType, orientation, direction, x, y, width, height, null, null); - } - - protected Tile(TileType tileType, Orientation orientation, Direction direction, int x, int y, int width, int height, Color backgroundColor, Color selectedColor) { - this.tileType = tileType; - //this.tileOrientation = orientation; - //model.setTileOrienation(orientation); - this.tileDirection = direction; - this.tileX = x; - this.tileY = y; - - setLayout(null); - Dimension d = new Dimension(width, height); - setSize(d); - setPreferredSize(d); - - this.renderWidth = RENDER_WIDTH; - this.renderHeight = RENDER_HEIGHT; - - this.trackColor = DEFAULT_TRACK_COLOR; - this.backgroundColor = backgroundColor; - this.selectedColor = selectedColor; - - if (this.backgroundColor == null) { - this.backgroundColor = DEFAULT_BACKGROUND_COLOR; - } - if (this.selectedColor == null) { - this.selectedColor = DEFAULT_SELECTED_COLOR; - } - } - - protected Tile(TileBean tileBean) { - this(tileBean, tileWidth(tileBean.getOrientation(), tileBean.getTileType()), tileHeight(tileBean.getOrientation(), tileBean.getTileType())); - } - - protected Tile(TileBean tileBean, int width, int height) { - this.tileBean = tileBean; - //Quick properties - this.id = tileBean.getId(); - this.tileType = tileBean.getTileType(); - //this.tileOrientation = tileBean.getOrientation(); - //this.model.setTileOrienation(tileBean.getOrientation()); - this.tileDirection = tileBean.getDirection(); - this.tileX = tileBean.getX(); - this.tileY = tileBean.getY(); - - this.accessoryId = tileBean.getAccessoryId(); - this.accessoryBean = tileBean.getAccessoryBean(); - this.signalType = tileBean.getSignalType(); - - this.sensorId = tileBean.getSensorId(); - this.sensorBean = tileBean.getSensorBean(); - this.blockBean = tileBean.getBlockBean(); - - setLayout(null); - Dimension d = new Dimension(width, height); - setSize(d); - setPreferredSize(d); - - this.trackColor = DEFAULT_TRACK_COLOR; - this.backgroundColor = DEFAULT_BACKGROUND_COLOR; - this.selectedColor = DEFAULT_SELECTED_COLOR; - this.renderWidth = RENDER_WIDTH; - this.renderHeight = RENDER_HEIGHT; - } - - protected static int tileWidth(Orientation orientation, TileType tileType) { - if (Orientation.EAST == orientation || Orientation.WEST == orientation) { - if (null == tileType) { - return DEFAULT_WIDTH; - } else { - return switch (tileType) { - case BLOCK -> - BLOCK_WIDTH; - case CROSS -> - DEFAULT_WIDTH * 2; - default -> - DEFAULT_WIDTH; - }; - } - } else { - return DEFAULT_WIDTH; - } - } - - protected static int tileHeight(Orientation orientation, TileType tileType) { - if (Orientation.EAST == orientation || Orientation.WEST == orientation) { - return DEFAULT_HEIGHT; - } else { - if (null == tileType) { - return DEFAULT_HEIGHT; - } else { - return switch (tileType) { - case BLOCK -> - BLOCK_HEIGHT; - case CROSS -> - DEFAULT_HEIGHT * 2; - default -> - DEFAULT_HEIGHT; - }; - } - } - } - - protected void populateModel() { - if (this.blockBean != null) { - this.model.setBlockState(this.blockBean.getBlockState()); - this.model.setLocomotive(this.blockBean.getLocomotive()); - this.model.setArrivalSuffix(this.blockBean.getArrivalSuffix()); - this.model.setLogicalDirection(LocomotiveBean.Direction.get(this.blockBean.getLogicalDirection())); - } - } - - public TileBean getTileBean() { - if (tileBean == null) { - tileBean = new TileBean(); - tileBean.setId(this.id); - tileBean.setX(this.tileX); - tileBean.setY(this.tileY); - tileBean.setTileType(this.tileType); - //tileBean.setTileOrientation(this.tileOrientation.getOrientation()); - tileBean.setTileOrientation(this.model.getTileOrienation().getOrientation()); - - tileBean.setTileDirection(this.tileDirection.getDirection()); - tileBean.setSignalType(this.signalType); - tileBean.setAccessoryId(this.accessoryId); - tileBean.setSensorId(this.sensorId); - tileBean.setAccessoryBean(this.accessoryBean); - tileBean.setSensorBean(this.sensorBean); - tileBean.setBlockBean(this.blockBean); - } - return tileBean; - } - - public boolean isSelected() { - return model.isSelected(); - } - - public void setSelected(boolean b) { - //boolean oldValue = isSelected(); - model.setSelected(b); - } - - public String getId() { - return id; - } - - public void setId(String id) { - this.id = id; - } - - public SignalType getSignalType() { - return signalType; - } - - public void setSignalType(SignalType signalType) { - this.signalType = signalType; - } - - public Integer getTileX() { - return tileX; - } - - public Integer getTileY() { - return tileY; - } - - public Point getCenter() { - return new Point(this.tileX, this.tileY); - } - - public void setCenter(Point center) { - tileX = center.x; - tileY = center.y; - if (tileBean != null) { - tileBean.setCenter(center); - } - } - - public Orientation getOrientation() { - //return tileOrientation; - return model.getTileOrienation(); - } - - public void setOrientation(Orientation orientation) { - //this.tileOrientation = orientation; - model.setTileOrienation(orientation); - if (tileBean != null) { - tileBean.setOrientation(orientation); - } - } - - public Direction getDirection() { - return tileDirection; - } - - public void setDirection(Direction direction) { - this.tileDirection = direction; - if (tileBean != null) { - tileBean.setDirection(direction); - } - } - - public String getAccessoryId() { - return accessoryId; - } - - public void setAccessoryId(String accessoryId) { - this.accessoryId = accessoryId; - if (tileBean != null) { - tileBean.setAccessoryId(accessoryId); - } - } - - public String getSensorId() { - return sensorId; - } - - public void setSensorId(String sensorId) { - this.sensorId = sensorId; - } - - public boolean isActive() { - return model.isSensorActive(); - } - - public void setActive(boolean active) { - model.setSensorActive(active); - } - - public BlockState getBlockState() { - return model.getBlockState(); - } - - public void setBlockState(BlockState blockState) { - if (blockBean != null) { - blockBean.setBlockState(blockState); - LocomotiveBean locomotive = model.getLocomotive(); - model.setOverlayImage(locomotive != null && locomotive.getLocIcon() != null && (blockState == BlockState.OCCUPIED || blockState == BlockState.INBOUND || blockState == BlockState.OUTBOUND)); - } - model.setBlockState(blockState); - } - - public String getDepartureSuffix() { - return model.getDepartureSuffix(); - } - - public void setDepartureSuffix(String suffix) { - if (blockBean != null) { - blockBean.setDepartureSuffix(suffix); - } - model.setDepartureSuffix(suffix); - } - - public boolean isReverseArrival() { - return model.isReverseArrival(); - } - - public void setReverseArrival(boolean reverseArrival) { - if (blockBean != null) { - blockBean.setReverseArrival(reverseArrival); - } - model.setReverseArrival(reverseArrival); - } - - public LocomotiveBean.Direction getLogicalDirection() { - return model.getLogicalDirection(); - } - - public void setLogicalDirection(LocomotiveBean.Direction logicalDirection) { - if (blockBean != null) { - blockBean.setLogicalDirection(logicalDirection.getDirection()); - } - model.setLogicalDirection(logicalDirection); - } - - public LocomotiveBean getLocomotive() { - return model.getLocomotive(); - } - - public void setLocomotive(LocomotiveBean locomotive) { - if (blockBean != null) { - blockBean.setLocomotive(locomotive); - model.setOverlayImage(locomotive != null && locomotive.getLocIcon() != null && (model.getBlockState() == BlockState.OCCUPIED || model.getBlockState() == BlockState.INBOUND || model.getBlockState() == BlockState.OUTBOUND)); - } - - model.setLocomotive(locomotive); - } - - public AccessoryBean getAccessoryBean() { - return accessoryBean; - } - - public void setAccessoryBean(AccessoryBean accessoryBean) { - this.accessoryBean = accessoryBean; - - if (accessoryBean != null) { - accessoryId = accessoryBean.getId(); - signalValue = accessoryBean.getSignalValue(); - signalType = SignalType.getSignalType(accessoryBean.getType()); - } else { - accessoryId = null; - signalType = SignalType.NONE; - signalValue = AccessoryBean.SignalValue.OFF; - } - } - - public AccessoryValue getAccessoryValue() { - if (this.accessoryValue == null) { - return AccessoryValue.OFF; - } else { - return accessoryValue; - } - } - - public void setAccessoryValue(AccessoryValue value) { - this.accessoryValue = value; - repaint(); - } - - public AccessoryValue getRouteValue() { - if (routeValue == null) { - return AccessoryValue.OFF; - } else { - return routeValue; - } - } - - public void setRouteValue(AccessoryValue value) { - this.routeValue = value; - repaint(); - } - - public AccessoryBean.SignalValue getSignalValue() { - return signalValue; - } - - public void setSignalValue(AccessoryBean.SignalValue signalValue) { - this.signalValue = signalValue; - repaint(); - } - - public SensorBean getSensorBean() { - return sensorBean; - } - - public void setSensorBean(SensorBean sensorBean) { - this.sensorBean = sensorBean; - } - - public BlockBean getBlockBean() { - return blockBean; - } - - public void setBlockBean(BlockBean blockBean) { - this.blockBean = blockBean; - } - - public void setRenderWidth(int renderWidth) { - this.renderWidth = renderWidth; - } - - public void setRenderHeight(int renderHeight) { - this.renderHeight = renderHeight; - } - - public int getRenderOffsetX() { - return renderOffsetX; - } - - public void setRenderOffsetX(int renderOffsetX) { - this.renderOffsetX = renderOffsetX; - } - - public int getRenderOffsetY() { - return renderOffsetY; - } - - public void setRenderOffsetY(int renderOffsetY) { - this.renderOffsetY = renderOffsetY; - } - - public TileBean.TileType getTileType() { - return this.tileType; - } - - public final void setTileType(TileType tileType) { - this.tileType = tileType; - } - - public Color getTrackColor() { - return trackColor; - } - - public final void setTrackColor(Color trackColor) { - this.trackColor = trackColor; - } - - public Color getTrackRouteColor() { - return trackRouteColor; - } - - public void setTrackRouteColor(Color trackRouteColor) { - this.trackRouteColor = trackRouteColor; - } - - public Color getSelectedColor() { - return selectedColor; - } - - public void setSelectedColor(Color selectedColor) { - this.selectedColor = selectedColor; - } - - public Orientation getIncomingSide() { - return incomingSide; - } - - public void setIncomingSide(Orientation incomingSide) { - this.incomingSide = incomingSide; - } - - public Color getBackgroundColor() { - return backgroundColor; - } - - public void setBackgroundColor(Color backgroundColor) { - this.backgroundColor = backgroundColor; - } - - public boolean isDrawRoute() { - return model.isShowRoute(); - } - - public void setDrawRoute(boolean drawRoute) { - this.model.setShowRoute(drawRoute); - } - - public int getRenderWidth() { - return renderWidth; - } - - public int getRenderHeight() { - return renderHeight; - } - - abstract void renderTile(Graphics2D g2d); - - abstract void renderTileRoute(Graphics2D g2d); - - public abstract Map getNeighborPoints(); - - public abstract Map getEdgePoints(); - - public abstract Set getAllPoints(); - - /** - * Draw the Tile - * - * @param g2d The graphics handle - */ - public void drawTile(Graphics2D g2d) { - // by default and image is rendered in the EAST orientation - Orientation tileOrientation = model.getTileOrienation(); -// if (tileOrientation == null) { -// tileOrientation = Orientation.EAST; -// } - - BufferedImage bf = createImage(); - Graphics2D g2di = bf.createGraphics(); - - //Avoid errors - if (model.isShowRoute() && incomingSide == null) { - incomingSide = getOrientation(); - } - - if (model.isSelected()) { - g2di.setBackground(selectedColor); - } else { - g2di.setBackground(backgroundColor); - } - - g2di.clearRect(0, 0, renderWidth, renderHeight); - int ox = 0, oy = 0; - - AffineTransform trans = new AffineTransform(); - switch (tileOrientation) { - case SOUTH -> { - trans.rotate(Math.PI / 2, renderWidth / 2, renderHeight / 2); - ox = (renderHeight - renderWidth) / 2; - oy = (renderWidth - renderHeight) / 2; - trans.translate(-ox, -oy); - } - case WEST -> { - trans.rotate(Math.PI, renderWidth / 2, renderHeight / 2); - trans.translate(ox, oy); - } - case NORTH -> { - trans.rotate(-Math.PI / 2, renderWidth / 2, renderHeight / 2); - ox = (renderHeight - renderWidth) / 2; - oy = (renderWidth - renderHeight) / 2; - trans.translate(-ox, -oy); - } - default -> { - trans.rotate(0.0, this.renderWidth / 2, this.renderHeight / 2); - trans.translate(ox, oy); - } - } - - //Logger.trace(tileOrientation.getOrientation() + " renderWidth: " + renderWidth + " renderHeight: " + renderHeight + " CP: (" + renderWidth / 2 + "," + renderHeight / 2 + ")"); - //Logger.trace(tileOrientation.getOrientation() + " ox: " + ox + " oy: " + oy); - g2di.setTransform(trans); - - renderTile(g2di); - - if (model.isShowRoute()) { - renderTileRoute(g2di); - } - - if (model.isShowCenter()) { - drawCenterPoint(g2di); - } - - // Scale the image back... - if (model.isScaleImage()) { - tileImage = Scalr.resize(bf, Method.AUTOMATIC, Mode.FIT_EXACT, getWidth(), getHeight(), Scalr.OP_ANTIALIAS); - } else { - tileImage = bf; - } - - g2di.dispose(); - } - - public BufferedImage getTileImage() { - return tileImage; - } - - /** - * Render a tile image Always starts at (0,0) used the default width and height - * - * @param g2 the Graphic context - */ - public void drawName(Graphics2D g2) { - } - - protected void drawCenterPoint(Graphics2D g2d) { - drawCenterPoint(g2d, Color.magenta); - } - - protected void drawCenterPoint(Graphics2D g2, Color color) { - drawCenterPoint(g2, color, 60); - } - - protected void drawCenterPoint(Graphics2D g2d, Color color, double size) { - double dX = (renderWidth / 2 - size / 2); - double dY = (renderHeight / 2 - size / 2); - - g2d.setColor(color); - g2d.fill(new Ellipse2D.Double(dX, dY, size, size)); - } - - /** - * Rotate the tile clockwise 90 deg - * - * @return the new Orientation - */ - public Orientation rotate() { - Orientation tileOrientation = model.getTileOrienation(); - switch (tileOrientation) { - case EAST -> - setOrientation(Orientation.SOUTH); - case SOUTH -> - setOrientation(Orientation.WEST); - case WEST -> - setOrientation(Orientation.NORTH); - default -> - setOrientation(Orientation.EAST); - } - return model.getTileOrienation(); - } - - public void flipHorizontal() { - Orientation tileOrientation = model.getTileOrienation(); - if (Orientation.NORTH == tileOrientation || Orientation.SOUTH == tileOrientation) { - rotate(); - rotate(); - } - } - - public void flipVertical() { - Orientation tileOrientation = model.getTileOrienation(); - if (Orientation.EAST == tileOrientation || Orientation.WEST == tileOrientation) { - rotate(); - rotate(); - } - } - - @Override - public void move(int newX, int newY) { - Point cs = LayoutUtil.snapToGrid(newX, newY); - setCenter(cs); - } - - protected static void drawRotate(Graphics2D g2d, double x, double y, int angle, String text) { - g2d.translate((float) x, (float) y); - g2d.rotate(Math.toRadians(angle)); - g2d.drawString(text, 0, 0); - g2d.rotate(-Math.toRadians(angle)); - g2d.translate(-x, -y); - } - - public static BufferedImage flipHorizontally(BufferedImage source) { - BufferedImage output = new BufferedImage(source.getHeight(), source.getWidth(), source.getType()); - - AffineTransform flip = AffineTransform.getScaleInstance(1, -1); - flip.translate(0, -source.getHeight()); - AffineTransformOp op = new AffineTransformOp(flip, AffineTransformOp.TYPE_NEAREST_NEIGHBOR); - - op.filter(source, output); - - return output; - } - - public static BufferedImage flipVertically(BufferedImage source) { - BufferedImage output = new BufferedImage(source.getHeight(), source.getWidth(), source.getType()); - - AffineTransform flip = AffineTransform.getScaleInstance(-1, 1); - flip.translate(-source.getWidth(), 0); - AffineTransformOp op = new AffineTransformOp(flip, AffineTransformOp.TYPE_NEAREST_NEIGHBOR); - - op.filter(source, output); - - return output; - } - - public Set getAltPoints() { - return Collections.EMPTY_SET; - } - - public final int getOffsetX() { - return offsetX; - } - - public void setOffsetX(int offsetX) { - this.offsetX = offsetX; - } - - public final int getOffsetY() { - return offsetY; - } - - public void setOffsetY(int offsetY) { - this.offsetY = offsetY; - } - - protected BufferedImage createImage() { - return new BufferedImage(renderWidth, renderHeight, BufferedImage.TYPE_INT_RGB); - } - - public int getCenterX() { - if (tileX > 0) { - return this.tileX; - } else { - return GRID; - } - } - - public int getCenterY() { - if (tileY > 0) { - return this.tileY; - } else { - return GRID; - } - } - - public boolean isDrawName() { - return drawName; - } - - public void setDrawName(boolean drawName) { - this.drawName = drawName; - } - - public boolean isScaleImage() { - return model.isScaleImage(); - } - - public void setScaleImage(boolean scaleImage) { - Dimension d; - if (scaleImage) { - d = new Dimension(DEFAULT_WIDTH, DEFAULT_HEIGHT); - } else { - d = new Dimension(renderWidth, renderHeight); - } - - setSize(d); - setPreferredSize(d); - - model.setScaleImage(scaleImage); - } - - public boolean isDrawCenterPoint() { - return model.isShowCenter(); - } - - public void setDrawCenterPoint(boolean drawCenterPoint) { - model.setShowCenter(drawCenterPoint); - } - - @Override - public String toString() { - return this.getClass().getSimpleName() - + " {id: " - + this.id - + ", orientation: " - + getOrientation() - + ", direction: " - + getDirection() - + ", center: " - + xyToString() - + "}"; - } - - public String xyToString() { - return "(" + this.tileX + "," + this.tileY + ")"; - } - - /** - * The main route of the tile is horizontal - * - * @return true when main route goes from East to West or vv - */ - public boolean isHorizontal() { - Orientation tileOrientation = model.getTileOrienation(); - return (Orientation.EAST == tileOrientation || Orientation.WEST == tileOrientation) && TileType.CURVED != tileType; - } - - /** - * The main route of the tile is vertical - * - * @return true when main route goes from North to South or vv - */ - public boolean isVertical() { - Orientation tileOrientation = model.getTileOrienation(); - return (Orientation.NORTH == tileOrientation || Orientation.SOUTH == tileOrientation) && TileType.CURVED != tileType; - } - - public boolean isJunction() { - return TileType.SWITCH == tileType || TileType.CROSS == tileType; - } - - public boolean isBlock() { - return TileType.BLOCK == tileType; - } - - public boolean isDirectional() { - return TileType.STRAIGHT_DIR == tileType; - } - - /** - * The main route of the tile is diagonal - * - * @return true when main route goes from North to East or West to South and vv - */ - public boolean isDiagonal() { - return TileType.CURVED == tileType; - } - - public boolean isCrossing() { - return TileType.CROSSING == tileType; - } - - public List getNeighbours() { - return neighbours; - } - - public void setNeighbours(List neighbours) { - this.neighbours = neighbours; - } - - public String getIdSuffix(Tile other) { - return ""; - } - - public Map getNeighborOrientations() { - Map edgeOrientations = new HashMap<>(); - - Map neighborPoints = getNeighborPoints(); - - for (Orientation o : Orientation.values()) { - edgeOrientations.put(neighborPoints.get(o), o); - } - return edgeOrientations; - } - - public Map getEdgeOrientations() { - Map edgeOrientations = new HashMap<>(); - - Map edgeConnections = getEdgePoints(); - - for (Orientation o : Orientation.values()) { - edgeOrientations.put(edgeConnections.get(o), o); - } - return edgeOrientations; - } - - public boolean isAdjacent(Tile other) { - boolean adjacent = false; - - if (other != null) { - Collection thisEdgePoints = getEdgePoints().values(); - Collection otherEdgePoints = other.getEdgePoints().values(); - - for (Point p : thisEdgePoints) { - adjacent = otherEdgePoints.contains(p); - if (adjacent) { - break; - } - } - } - - return adjacent; - } - - /** - * When the tile has a specific direction a train may travel,
- * then this method will indicate whether the other tile is in on the side where the arrow is pointing to. - * - * @param other A Tile - * @return true where other is on the side of this tile where the arrow points to - */ - public boolean isArrowDirection(Tile other) { - return true; - } - - public AccessoryValue accessoryValueForRoute(Orientation from, Orientation to) { - return AccessoryValue.OFF; - } - - public TileModel getModel() { - return model; - } - - public void setModel(TileModel newModel) { - TileModel oldModel = getModel(); - - if (oldModel != null) { - oldModel.removeChangeListener(changeListener); - oldModel.removeActionListener(actionListener); - changeListener = null; - actionListener = null; - } - - model = newModel; - - if (newModel != null) { - changeListener = createChangeListener(); - actionListener = createActionListener(); - - newModel.addChangeListener(changeListener); - newModel.addActionListener(actionListener); - } - - firePropertyChange(MODEL_CHANGED_PROPERTY, oldModel, newModel); - if (newModel != oldModel) { - revalidate(); - repaint(); - } - } - -// public TileUI getUI() { -// return (TileUI) ui; -// } -// public void setUI(TileUI ui) { -// super.setUI(ui); -// } - @Override - public void updateUI() { - } - - protected ChangeListener createChangeListener() { - return getHandler(); - } - - protected ActionListener createActionListener() { - return getHandler(); - } - - private Handler getHandler() { - if (handler == null) { - handler = new Handler(); - } - return handler; - } - - class Handler implements ActionListener, ChangeListener, Serializable { - - @Override - public void stateChanged(ChangeEvent e) { - //Object source = e.getSource(); - - fireStateChanged(); - repaint(); - } - - @Override - public void actionPerformed(ActionEvent event) { - fireActionPerformed(event); - } - } - - protected void fireStateChanged() { - Object[] listeners = listenerList.getListenerList(); - //reverse order - for (int i = listeners.length - 2; i >= 0; i -= 2) { - if (listeners[i] == ChangeListener.class) { - // Lazily create the event: - if (changeEvent == null) { - changeEvent = new ChangeEvent(this); - } - ((ChangeListener) listeners[i + 1]).stateChanged(changeEvent); - } - } - } - - protected void fireActionPerformed(ActionEvent event) { - Object[] listeners = listenerList.getListenerList(); - ActionEvent e = null; - // reverse - for (int i = listeners.length - 2; i >= 0; i -= 2) { - if (listeners[i] == ActionListener.class) { - // Lazily create the event: - if (e == null) { - String actionCommand = event.getActionCommand(); - //if(actionCommand == null) { - // actionCommand = getActionCommand(); - //} - e = new ActionEvent(Tile.this, ActionEvent.ACTION_PERFORMED, actionCommand, event.getWhen(), event.getModifiers()); - } - ((ActionListener) listeners[i + 1]).actionPerformed(e); - } - } - } - - public Rectangle getTileBounds() { - //return new Rectangle(tileX - GRID, tileY - GRID, DEFAULT_WIDTH, DEFAULT_HEIGHT); - - if (model.isScaleImage()) { - return new Rectangle(tileX - GRID, tileY - GRID, DEFAULT_WIDTH, DEFAULT_HEIGHT); - } else { - return new Rectangle(tileX - renderWidth / 2, tileY - renderHeight / 2, renderWidth, renderHeight); - } - - } - - @Override - protected void paintComponent(Graphics g) { - long started = System.currentTimeMillis(); - - Graphics2D g2 = (Graphics2D) g.create(); - //Graphics2D g2 = (Graphics2D) g.create(tileX - GRID, tileY - GRID, DEFAULT_WIDTH, DEFAULT_HEIGHT); - drawTile(g2); - g2.dispose(); - - g.drawImage(tileImage, 0, 0, null); - - long now = System.currentTimeMillis(); - Logger.trace(id + " Duration: " + (now - started) + " ms. Tile (" + tileX + "," + tileY + ")"); - } - -} +/* * Copyright 2024 Frans Jacobs. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package jcs.ui.layout.tiles; import java.awt.Color; import java.awt.Dimension; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.Point; import java.awt.Rectangle; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.geom.AffineTransform; import java.awt.geom.Ellipse2D; import java.awt.image.AffineTransformOp; import java.awt.image.BufferedImage; import java.beans.PropertyChangeListener; import java.io.Serializable; import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Set; import javax.swing.JComponent; import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; import jcs.entities.AccessoryBean; import jcs.entities.AccessoryBean.AccessoryValue; import jcs.entities.AccessoryBean.SignalType; import jcs.entities.BlockBean; import jcs.entities.BlockBean.BlockState; import jcs.entities.LocomotiveBean; import jcs.entities.SensorBean; import jcs.entities.TileBean; import jcs.entities.TileBean.Direction; import jcs.entities.TileBean.Orientation; import jcs.entities.TileBean.TileType; import jcs.ui.layout.LayoutUtil; import static jcs.ui.layout.tiles.Block.BLOCK_HEIGHT; import static jcs.ui.layout.tiles.Block.BLOCK_WIDTH; import org.imgscalr.Scalr; import org.imgscalr.Scalr.Method; import org.imgscalr.Scalr.Mode; import org.tinylog.Logger; /** * Basic graphic element to display a track, turnout, etc on the screen.
* By default the drawing of a Tile is Horizontal from L to R or West to East.
* The default orientation is East. * *

* The default size of a Tile is 40 tileX 40 pixels.
* The center point of a Tile is stored and always snapped to the nearest grid point.
* The basic grid is 20x 20 pixels.
* *

* A Tile can be rotated (always clockwise).
* Rotation will change the orientation from East -> South -> West -> North -> East.
* *

* A Tile is rendered to a Buffered Image to speed up the display */ public abstract class Tile extends JComponent { //implements TileEventListener { //, ItemSelectable { public static final int GRID = 20; public static final int DEFAULT_WIDTH = GRID * 2; public static final int DEFAULT_HEIGHT = GRID * 2; static final int RENDER_GRID = GRID * 10; static final int RENDER_WIDTH = RENDER_GRID * 2; static final int RENDER_HEIGHT = RENDER_GRID * 2; public static final Color DEFAULT_BACKGROUND_COLOR = Color.white; public static final Color DEFAULT_TRACK_COLOR = Color.lightGray; public static final Color DEFAULT_ROUTE_TRACK_COLOR = Color.blue; public static final Color DEFAULT_SELECTED_COLOR = Color.yellow; public static final String MODEL_CHANGED_PROPERTY = "model"; public static final String CONTENT_AREA_FILLED_CHANGED_PROPERTY = "contentAreaFilled"; /** * The data model that determines the button's state. */ protected TileModel model = null; protected String id; protected Integer tileX; protected Integer tileY; protected int renderWidth; protected int renderHeight; //protected Orientation tileOrientation; protected Direction tileDirection; protected TileType tileType; protected String accessoryId; protected String sensorId; protected AccessoryValue accessoryValue; protected AccessoryValue routeValue; protected SignalType signalType; protected AccessoryBean.SignalValue signalValue; protected TileBean tileBean; protected AccessoryBean accessoryBean; protected SensorBean sensorBean; protected BlockBean blockBean; protected List neighbours; protected int offsetX = 0; protected int offsetY = 0; protected int renderOffsetX = 0; protected int renderOffsetY = 0; protected Color selectedColor; protected Color trackColor; protected Color trackRouteColor; protected Orientation incomingSide; protected Color backgroundColor; protected boolean drawName = true; protected BufferedImage tileImage; protected PropertyChangeListener propertyChangeListener; protected ChangeListener changeListener = null; protected ActionListener actionListener = null; protected transient ChangeEvent changeEvent; private Handler handler; protected Tile(TileType tileType, Orientation orientation, Point center, int width, int height) { this(tileType, orientation, Direction.CENTER, center.x, center.y, width, height); } protected Tile(TileType tileType, Orientation orientation, int x, int y, int width, int height) { this(tileType, orientation, Direction.CENTER, x, y, width, height); } protected Tile(TileType tileType, Orientation orientation, Direction direction, int x, int y, int width, int height) { this(tileType, orientation, direction, x, y, width, height, null, null); } protected Tile(TileType tileType, Orientation orientation, Direction direction, int x, int y, int width, int height, Color backgroundColor, Color selectedColor) { this.tileType = tileType; //this.tileOrientation = orientation; //model.setTileOrienation(orientation); this.tileDirection = direction; this.tileX = x; this.tileY = y; setLayout(null); Dimension d = new Dimension(width, height); setSize(d); setPreferredSize(d); this.renderWidth = RENDER_WIDTH; this.renderHeight = RENDER_HEIGHT; this.trackColor = DEFAULT_TRACK_COLOR; this.backgroundColor = backgroundColor; this.selectedColor = selectedColor; if (this.backgroundColor == null) { this.backgroundColor = DEFAULT_BACKGROUND_COLOR; } if (this.selectedColor == null) { this.selectedColor = DEFAULT_SELECTED_COLOR; } } protected Tile(TileBean tileBean) { this(tileBean, tileWidth(tileBean.getOrientation(), tileBean.getTileType()), tileHeight(tileBean.getOrientation(), tileBean.getTileType())); } protected Tile(TileBean tileBean, int width, int height) { this.tileBean = tileBean; //Quick properties this.id = tileBean.getId(); this.tileType = tileBean.getTileType(); //this.tileOrientation = tileBean.getOrientation(); //this.model.setTileOrienation(tileBean.getOrientation()); this.tileDirection = tileBean.getDirection(); this.tileX = tileBean.getX(); this.tileY = tileBean.getY(); this.accessoryId = tileBean.getAccessoryId(); this.accessoryBean = tileBean.getAccessoryBean(); this.signalType = tileBean.getSignalType(); this.sensorId = tileBean.getSensorId(); this.sensorBean = tileBean.getSensorBean(); this.blockBean = tileBean.getBlockBean(); setLayout(null); Dimension d = new Dimension(width, height); setSize(d); setPreferredSize(d); this.trackColor = DEFAULT_TRACK_COLOR; this.backgroundColor = DEFAULT_BACKGROUND_COLOR; this.selectedColor = DEFAULT_SELECTED_COLOR; this.renderWidth = RENDER_WIDTH; this.renderHeight = RENDER_HEIGHT; } protected static int tileWidth(Orientation orientation, TileType tileType) { if (Orientation.EAST == orientation || Orientation.WEST == orientation) { if (null == tileType) { return DEFAULT_WIDTH; } else { return switch (tileType) { case BLOCK -> BLOCK_WIDTH; case CROSS -> DEFAULT_WIDTH * 2; default -> DEFAULT_WIDTH; }; } } else { return DEFAULT_WIDTH; } } protected static int tileHeight(Orientation orientation, TileType tileType) { if (Orientation.EAST == orientation || Orientation.WEST == orientation) { return DEFAULT_HEIGHT; } else { if (null == tileType) { return DEFAULT_HEIGHT; } else { return switch (tileType) { case BLOCK -> BLOCK_HEIGHT; case CROSS -> DEFAULT_HEIGHT * 2; default -> DEFAULT_HEIGHT; }; } } } protected void populateModel() { if (this.blockBean != null) { this.model.setBlockState(this.blockBean.getBlockState()); this.model.setLocomotive(this.blockBean.getLocomotive()); this.model.setArrivalSuffix(this.blockBean.getArrivalSuffix()); this.model.setLogicalDirection(LocomotiveBean.Direction.get(this.blockBean.getLogicalDirection())); } } public TileBean getTileBean() { if (tileBean == null) { tileBean = new TileBean(); tileBean.setId(this.id); tileBean.setX(this.tileX); tileBean.setY(this.tileY); tileBean.setTileType(this.tileType); //tileBean.setTileOrientation(this.tileOrientation.getOrientation()); tileBean.setTileOrientation(this.model.getTileOrienation().getOrientation()); tileBean.setTileDirection(this.tileDirection.getDirection()); tileBean.setSignalType(this.signalType); tileBean.setAccessoryId(this.accessoryId); tileBean.setSensorId(this.sensorId); tileBean.setAccessoryBean(this.accessoryBean); tileBean.setSensorBean(this.sensorBean); tileBean.setBlockBean(this.blockBean); } return tileBean; } public boolean isSelected() { return model.isSelected(); } public void setSelected(boolean b) { //boolean oldValue = isSelected(); model.setSelected(b); } public String getId() { return id; } public void setId(String id) { this.id = id; } public SignalType getSignalType() { return signalType; } public void setSignalType(SignalType signalType) { this.signalType = signalType; } public Integer getTileX() { return tileX; } public Integer getTileY() { return tileY; } public Point getCenter() { return new Point(this.tileX, this.tileY); } public void setCenter(Point center) { tileX = center.x; tileY = center.y; if (tileBean != null) { tileBean.setCenter(center); } Logger.trace(id + " Cp: " + xyToString()); } public Orientation getOrientation() { //return tileOrientation; return model.getTileOrienation(); } public void setOrientation(Orientation orientation) { //this.tileOrientation = orientation; model.setTileOrienation(orientation); if (tileBean != null) { tileBean.setOrientation(orientation); } } public Direction getDirection() { return tileDirection; } public void setDirection(Direction direction) { this.tileDirection = direction; if (tileBean != null) { tileBean.setDirection(direction); } } public String getAccessoryId() { return accessoryId; } public void setAccessoryId(String accessoryId) { this.accessoryId = accessoryId; if (tileBean != null) { tileBean.setAccessoryId(accessoryId); } } public String getSensorId() { return sensorId; } public void setSensorId(String sensorId) { this.sensorId = sensorId; } public boolean isActive() { return model.isSensorActive(); } public void setActive(boolean active) { model.setSensorActive(active); } public BlockState getBlockState() { return model.getBlockState(); } public void setBlockState(BlockState blockState) { if (blockBean != null) { blockBean.setBlockState(blockState); LocomotiveBean locomotive = model.getLocomotive(); model.setOverlayImage(locomotive != null && locomotive.getLocIcon() != null && (blockState == BlockState.OCCUPIED || blockState == BlockState.INBOUND || blockState == BlockState.OUTBOUND)); } model.setBlockState(blockState); } public String getDepartureSuffix() { return model.getDepartureSuffix(); } public void setDepartureSuffix(String suffix) { if (blockBean != null) { blockBean.setDepartureSuffix(suffix); } model.setDepartureSuffix(suffix); } public boolean isReverseArrival() { return model.isReverseArrival(); } public void setReverseArrival(boolean reverseArrival) { if (blockBean != null) { blockBean.setReverseArrival(reverseArrival); } model.setReverseArrival(reverseArrival); } public LocomotiveBean.Direction getLogicalDirection() { return model.getLogicalDirection(); } public void setLogicalDirection(LocomotiveBean.Direction logicalDirection) { if (blockBean != null) { blockBean.setLogicalDirection(logicalDirection.getDirection()); } model.setLogicalDirection(logicalDirection); } public LocomotiveBean getLocomotive() { return model.getLocomotive(); } public void setLocomotive(LocomotiveBean locomotive) { if (blockBean != null) { blockBean.setLocomotive(locomotive); model.setOverlayImage(locomotive != null && locomotive.getLocIcon() != null && (model.getBlockState() == BlockState.OCCUPIED || model.getBlockState() == BlockState.INBOUND || model.getBlockState() == BlockState.OUTBOUND)); } model.setLocomotive(locomotive); } public AccessoryBean getAccessoryBean() { return accessoryBean; } public void setAccessoryBean(AccessoryBean accessoryBean) { this.accessoryBean = accessoryBean; if (accessoryBean != null) { accessoryId = accessoryBean.getId(); signalValue = accessoryBean.getSignalValue(); signalType = SignalType.getSignalType(accessoryBean.getType()); } else { accessoryId = null; signalType = SignalType.NONE; signalValue = AccessoryBean.SignalValue.OFF; } } public AccessoryValue getAccessoryValue() { if (this.accessoryValue == null) { return AccessoryValue.OFF; } else { return accessoryValue; } } public void setAccessoryValue(AccessoryValue value) { this.accessoryValue = value; repaint(); } public AccessoryValue getRouteValue() { if (routeValue == null) { return AccessoryValue.OFF; } else { return routeValue; } } public void setRouteValue(AccessoryValue value) { this.routeValue = value; repaint(); } public AccessoryBean.SignalValue getSignalValue() { return signalValue; } public void setSignalValue(AccessoryBean.SignalValue signalValue) { this.signalValue = signalValue; repaint(); } public SensorBean getSensorBean() { return sensorBean; } public void setSensorBean(SensorBean sensorBean) { this.sensorBean = sensorBean; } public BlockBean getBlockBean() { return blockBean; } public void setBlockBean(BlockBean blockBean) { this.blockBean = blockBean; } public void setRenderWidth(int renderWidth) { this.renderWidth = renderWidth; } public void setRenderHeight(int renderHeight) { this.renderHeight = renderHeight; } public int getRenderOffsetX() { return renderOffsetX; } public void setRenderOffsetX(int renderOffsetX) { this.renderOffsetX = renderOffsetX; } public int getRenderOffsetY() { return renderOffsetY; } public void setRenderOffsetY(int renderOffsetY) { this.renderOffsetY = renderOffsetY; } public TileBean.TileType getTileType() { return this.tileType; } public final void setTileType(TileType tileType) { this.tileType = tileType; } public Color getTrackColor() { return trackColor; } public final void setTrackColor(Color trackColor) { this.trackColor = trackColor; } public Color getTrackRouteColor() { return trackRouteColor; } public void setTrackRouteColor(Color trackRouteColor) { this.trackRouteColor = trackRouteColor; } public Color getSelectedColor() { return selectedColor; } public void setSelectedColor(Color selectedColor) { this.selectedColor = selectedColor; } public Orientation getIncomingSide() { return incomingSide; } public void setIncomingSide(Orientation incomingSide) { this.incomingSide = incomingSide; } public Color getBackgroundColor() { return backgroundColor; } public void setBackgroundColor(Color backgroundColor) { this.backgroundColor = backgroundColor; } public boolean isDrawRoute() { return model.isShowRoute(); } public void setDrawRoute(boolean drawRoute) { this.model.setShowRoute(drawRoute); } public int getRenderWidth() { return renderWidth; } public int getRenderHeight() { return renderHeight; } abstract void renderTile(Graphics2D g2d); abstract void renderTileRoute(Graphics2D g2d); public abstract Map getNeighborPoints(); public abstract Map getEdgePoints(); public abstract Set getAllPoints(); /** * Draw the Tile * * @param g2d The graphics handle */ public void drawTile(Graphics2D g2d) { // by default and image is rendered in the EAST orientation Orientation tileOrientation = model.getTileOrienation(); // if (tileOrientation == null) { // tileOrientation = Orientation.EAST; // } BufferedImage bf = createImage(); Graphics2D g2di = bf.createGraphics(); //Avoid errors if (model.isShowRoute() && incomingSide == null) { incomingSide = getOrientation(); } if (model.isSelected()) { g2di.setBackground(selectedColor); } else { g2di.setBackground(backgroundColor); } g2di.clearRect(0, 0, renderWidth, renderHeight); int ox = 0, oy = 0; AffineTransform trans = new AffineTransform(); switch (tileOrientation) { case SOUTH -> { trans.rotate(Math.PI / 2, renderWidth / 2, renderHeight / 2); ox = (renderHeight - renderWidth) / 2; oy = (renderWidth - renderHeight) / 2; trans.translate(-ox, -oy); } case WEST -> { trans.rotate(Math.PI, renderWidth / 2, renderHeight / 2); trans.translate(ox, oy); } case NORTH -> { trans.rotate(-Math.PI / 2, renderWidth / 2, renderHeight / 2); ox = (renderHeight - renderWidth) / 2; oy = (renderWidth - renderHeight) / 2; trans.translate(-ox, -oy); } default -> { trans.rotate(0.0, this.renderWidth / 2, this.renderHeight / 2); trans.translate(ox, oy); } } //Logger.trace(tileOrientation.getOrientation() + " renderWidth: " + renderWidth + " renderHeight: " + renderHeight + " CP: (" + renderWidth / 2 + "," + renderHeight / 2 + ")"); //Logger.trace(tileOrientation.getOrientation() + " ox: " + ox + " oy: " + oy); g2di.setTransform(trans); renderTile(g2di); if (model.isShowRoute()) { renderTileRoute(g2di); } if (model.isShowCenter()) { drawCenterPoint(g2di); } // Scale the image back... if (model.isScaleImage()) { tileImage = Scalr.resize(bf, Method.AUTOMATIC, Mode.FIT_EXACT, getWidth(), getHeight(), Scalr.OP_ANTIALIAS); } else { tileImage = bf; } g2di.dispose(); Logger.trace(id + " Cp: " + xyToString()); } public BufferedImage getTileImage() { return tileImage; } /** * Render a tile image Always starts at (0,0) used the default width and height * * @param g2 the Graphic context */ public void drawName(Graphics2D g2) { } protected void drawCenterPoint(Graphics2D g2d) { drawCenterPoint(g2d, Color.magenta); } protected void drawCenterPoint(Graphics2D g2, Color color) { drawCenterPoint(g2, color, 60); } protected void drawCenterPoint(Graphics2D g2d, Color color, double size) { double dX = (renderWidth / 2 - size / 2); double dY = (renderHeight / 2 - size / 2); g2d.setColor(color); g2d.fill(new Ellipse2D.Double(dX, dY, size, size)); } /** * Rotate the tile clockwise 90 deg * * @return the new Orientation */ public Orientation rotate() { Orientation tileOrientation = model.getTileOrienation(); switch (tileOrientation) { case EAST -> setOrientation(Orientation.SOUTH); case SOUTH -> setOrientation(Orientation.WEST); case WEST -> setOrientation(Orientation.NORTH); default -> setOrientation(Orientation.EAST); } return model.getTileOrienation(); } public void flipHorizontal() { Orientation tileOrientation = model.getTileOrienation(); if (Orientation.NORTH == tileOrientation || Orientation.SOUTH == tileOrientation) { rotate(); rotate(); } } public void flipVertical() { Orientation tileOrientation = model.getTileOrienation(); if (Orientation.EAST == tileOrientation || Orientation.WEST == tileOrientation) { rotate(); rotate(); } } @Override public void move(int newX, int newY) { Point cs = LayoutUtil.snapToGrid(newX, newY); setCenter(cs); } protected static void drawRotate(Graphics2D g2d, double x, double y, int angle, String text) { g2d.translate((float) x, (float) y); g2d.rotate(Math.toRadians(angle)); g2d.drawString(text, 0, 0); g2d.rotate(-Math.toRadians(angle)); g2d.translate(-x, -y); } public static BufferedImage flipHorizontally(BufferedImage source) { BufferedImage output = new BufferedImage(source.getHeight(), source.getWidth(), source.getType()); AffineTransform flip = AffineTransform.getScaleInstance(1, -1); flip.translate(0, -source.getHeight()); AffineTransformOp op = new AffineTransformOp(flip, AffineTransformOp.TYPE_NEAREST_NEIGHBOR); op.filter(source, output); return output; } public static BufferedImage flipVertically(BufferedImage source) { BufferedImage output = new BufferedImage(source.getHeight(), source.getWidth(), source.getType()); AffineTransform flip = AffineTransform.getScaleInstance(-1, 1); flip.translate(-source.getWidth(), 0); AffineTransformOp op = new AffineTransformOp(flip, AffineTransformOp.TYPE_NEAREST_NEIGHBOR); op.filter(source, output); return output; } public Set getAltPoints() { return Collections.EMPTY_SET; } public final int getOffsetX() { return offsetX; } public void setOffsetX(int offsetX) { this.offsetX = offsetX; } public final int getOffsetY() { return offsetY; } public void setOffsetY(int offsetY) { this.offsetY = offsetY; } protected BufferedImage createImage() { return new BufferedImage(renderWidth, renderHeight, BufferedImage.TYPE_INT_RGB); } public int getCenterX() { if (tileX > 0) { return this.tileX; } else { return GRID; } } public int getCenterY() { if (tileY > 0) { return this.tileY; } else { return GRID; } } public boolean isDrawName() { return drawName; } public void setDrawName(boolean drawName) { this.drawName = drawName; } public boolean isScaleImage() { return model.isScaleImage(); } public void setScaleImage(boolean scaleImage) { Dimension d; if (scaleImage) { d = new Dimension(DEFAULT_WIDTH, DEFAULT_HEIGHT); } else { d = new Dimension(renderWidth, renderHeight); } setSize(d); setPreferredSize(d); model.setScaleImage(scaleImage); } public boolean isDrawCenterPoint() { return model.isShowCenter(); } public void setDrawCenterPoint(boolean drawCenterPoint) { model.setShowCenter(drawCenterPoint); } @Override public String toString() { return this.getClass().getSimpleName() + " {id: " + this.id + ", orientation: " + getOrientation() + ", direction: " + getDirection() + ", center: " + xyToString() + "}"; } public String xyToString() { return "(" + this.tileX + "," + this.tileY + ")"; } /** * The main route of the tile is horizontal * * @return true when main route goes from East to West or vv */ public boolean isHorizontal() { Orientation tileOrientation = model.getTileOrienation(); return (Orientation.EAST == tileOrientation || Orientation.WEST == tileOrientation) && TileType.CURVED != tileType; } /** * The main route of the tile is vertical * * @return true when main route goes from North to South or vv */ public boolean isVertical() { Orientation tileOrientation = model.getTileOrienation(); return (Orientation.NORTH == tileOrientation || Orientation.SOUTH == tileOrientation) && TileType.CURVED != tileType; } public boolean isJunction() { return TileType.SWITCH == tileType || TileType.CROSS == tileType; } public boolean isBlock() { return TileType.BLOCK == tileType; } public boolean isDirectional() { return TileType.STRAIGHT_DIR == tileType; } /** * The main route of the tile is diagonal * * @return true when main route goes from North to East or West to South and vv */ public boolean isDiagonal() { return TileType.CURVED == tileType; } public boolean isCrossing() { return TileType.CROSSING == tileType; } public List getNeighbours() { return neighbours; } public void setNeighbours(List neighbours) { this.neighbours = neighbours; } public String getIdSuffix(Tile other) { return ""; } public Map getNeighborOrientations() { Map edgeOrientations = new HashMap<>(); Map neighborPoints = getNeighborPoints(); for (Orientation o : Orientation.values()) { edgeOrientations.put(neighborPoints.get(o), o); } return edgeOrientations; } public Map getEdgeOrientations() { Map edgeOrientations = new HashMap<>(); Map edgeConnections = getEdgePoints(); for (Orientation o : Orientation.values()) { edgeOrientations.put(edgeConnections.get(o), o); } return edgeOrientations; } public boolean isAdjacent(Tile other) { boolean adjacent = false; if (other != null) { Collection thisEdgePoints = getEdgePoints().values(); Collection otherEdgePoints = other.getEdgePoints().values(); for (Point p : thisEdgePoints) { adjacent = otherEdgePoints.contains(p); if (adjacent) { break; } } } return adjacent; } /** * When the tile has a specific direction a train may travel,
* then this method will indicate whether the other tile is in on the side where the arrow is pointing to. * * @param other A Tile * @return true where other is on the side of this tile where the arrow points to */ public boolean isArrowDirection(Tile other) { return true; } public AccessoryValue accessoryValueForRoute(Orientation from, Orientation to) { return AccessoryValue.OFF; } public TileModel getModel() { return model; } public void setModel(TileModel newModel) { TileModel oldModel = getModel(); if (oldModel != null) { oldModel.removeChangeListener(changeListener); oldModel.removeActionListener(actionListener); changeListener = null; actionListener = null; } model = newModel; if (newModel != null) { changeListener = createChangeListener(); actionListener = createActionListener(); newModel.addChangeListener(changeListener); newModel.addActionListener(actionListener); } firePropertyChange(MODEL_CHANGED_PROPERTY, oldModel, newModel); if (newModel != oldModel) { revalidate(); repaint(); } } // public TileUI getUI() { // return (TileUI) ui; // } // public void setUI(TileUI ui) { // super.setUI(ui); // } @Override public void updateUI() { } protected ChangeListener createChangeListener() { return getHandler(); } protected ActionListener createActionListener() { return getHandler(); } private Handler getHandler() { if (handler == null) { handler = new Handler(); } return handler; } class Handler implements ActionListener, ChangeListener, Serializable { @Override public void stateChanged(ChangeEvent e) { //Object source = e.getSource(); fireStateChanged(); repaint(); } @Override public void actionPerformed(ActionEvent event) { fireActionPerformed(event); } } protected void fireStateChanged() { Object[] listeners = listenerList.getListenerList(); //reverse order for (int i = listeners.length - 2; i >= 0; i -= 2) { if (listeners[i] == ChangeListener.class) { // Lazily create the event: if (changeEvent == null) { changeEvent = new ChangeEvent(this); } ((ChangeListener) listeners[i + 1]).stateChanged(changeEvent); } } } protected void fireActionPerformed(ActionEvent event) { Object[] listeners = listenerList.getListenerList(); ActionEvent e = null; // reverse for (int i = listeners.length - 2; i >= 0; i -= 2) { if (listeners[i] == ActionListener.class) { // Lazily create the event: if (e == null) { String actionCommand = event.getActionCommand(); //if(actionCommand == null) { // actionCommand = getActionCommand(); //} e = new ActionEvent(Tile.this, ActionEvent.ACTION_PERFORMED, actionCommand, event.getWhen(), event.getModifiers()); } ((ActionListener) listeners[i + 1]).actionPerformed(e); } } } public Rectangle getTileBounds() { if (model.isScaleImage()) { return new Rectangle(tileX - GRID, tileY - GRID, DEFAULT_WIDTH, DEFAULT_HEIGHT); } else { return new Rectangle(tileX - renderWidth / 2, tileY - renderHeight / 2, renderWidth, renderHeight); } } @Override protected void paintComponent(Graphics g) { long started = System.currentTimeMillis(); Graphics2D g2 = (Graphics2D) g.create(); //Graphics2D g2 = (Graphics2D) g.create(tileX - GRID, tileY - GRID, DEFAULT_WIDTH, DEFAULT_HEIGHT); drawTile(g2); g2.dispose(); g.drawImage(tileImage, 0, 0, null); long now = System.currentTimeMillis(); Logger.trace(id + " Duration: " + (now - started) + " ms. Cp: " + xyToString() + " O: " + model.getTileOrienation()); } } \ No newline at end of file diff --git a/src/test/java/jcs/ui/layout/tiles/TileTesterFrame.form b/src/test/java/jcs/ui/layout/tiles/TileTesterFrame.form index 9b77fbc1..345a66d6 100644 --- a/src/test/java/jcs/ui/layout/tiles/TileTesterFrame.form +++ b/src/test/java/jcs/ui/layout/tiles/TileTesterFrame.form @@ -1,454 +1 @@ - - -

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - +
\ No newline at end of file diff --git a/src/test/java/jcs/ui/layout/tiles/TileTesterFrame.java b/src/test/java/jcs/ui/layout/tiles/TileTesterFrame.java index c5e311b7..f8881283 100644 --- a/src/test/java/jcs/ui/layout/tiles/TileTesterFrame.java +++ b/src/test/java/jcs/ui/layout/tiles/TileTesterFrame.java @@ -1,570 +1 @@ -/* - * Copyright 2024 Frans Jacobs. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package jcs.ui.layout.tiles; - -import java.awt.Color; -import java.awt.Point; -import javax.swing.ComboBoxModel; -import javax.swing.DefaultComboBoxModel; -import javax.swing.UIManager; -import javax.swing.UnsupportedLookAndFeelException; -import jcs.entities.AccessoryBean; -import jcs.entities.AccessoryBean.AccessoryValue; -import jcs.entities.TileBean; -import jcs.entities.TileBean.Direction; -import jcs.entities.TileBean.Orientation; -import static jcs.entities.TileBean.Orientation.NORTH; -import static jcs.entities.TileBean.Orientation.SOUTH; -import static jcs.entities.TileBean.Orientation.WEST; -import jcs.entities.TileBean.TileType; -import jcs.ui.layout.LayoutUtil; -import jcs.ui.layout.events.TileEvent; -import org.tinylog.Logger; - -public class TileTesterFrame extends javax.swing.JFrame { - - private Tile tile; - - public TileTesterFrame() { - initComponents(); - this.tileCB.setModel(createTileTypeComboBoxModel()); - this.orientationCB.setModel(createOrientationComboBoxModel()); - this.incomingSideCB.setModel(createOrientationComboBoxModel()); - this.directionCB.setModel(createDirectionComboBoxModel(true)); - - createTile(); - - pack(); - - setVisible(true); - } - - private ComboBoxModel createTileTypeComboBoxModel() { - DefaultComboBoxModel tileTypeModel = new DefaultComboBoxModel(); - - tileTypeModel.addElement(TileBean.TileType.STRAIGHT); - tileTypeModel.addElement(TileBean.TileType.STRAIGHT_DIR); - tileTypeModel.addElement(TileBean.TileType.SENSOR); - tileTypeModel.addElement(TileBean.TileType.SIGNAL); - tileTypeModel.addElement(TileBean.TileType.END); - tileTypeModel.addElement(TileBean.TileType.CROSSING); - tileTypeModel.addElement(TileBean.TileType.CURVED); - tileTypeModel.addElement(TileBean.TileType.SWITCH); - tileTypeModel.addElement(TileBean.TileType.CROSS); - - return tileTypeModel; - } - - private ComboBoxModel createOrientationComboBoxModel() { - DefaultComboBoxModel orientationModel = new DefaultComboBoxModel(); - - orientationModel.addElement(Orientation.EAST); - orientationModel.addElement(Orientation.SOUTH); - orientationModel.addElement(Orientation.WEST); - orientationModel.addElement(Orientation.NORTH); - - return orientationModel; - } - - private ComboBoxModel createDirectionComboBoxModel(boolean dontCare) { - DefaultComboBoxModel directionModel = new DefaultComboBoxModel(); - - if (dontCare) { - directionModel.addElement(Direction.CENTER); - } else { - directionModel.addElement(Direction.LEFT); - directionModel.addElement(Direction.RIGHT); - } - - return directionModel; - } - - private void createTile() { - if (tile != null) { - Logger.trace("Removing tile " + tile.getId()); - canvas.remove(tile); - tile = null; - } - - TileType tileType = (TileType) tileCB.getSelectedItem(); - Orientation orientation = (Orientation) orientationCB.getSelectedItem(); - - if (TileType.SWITCH == tileType || TileType.CROSS == tileType) { - directionCB.setModel(createDirectionComboBoxModel(false)); - } else { - directionCB.setModel(createDirectionComboBoxModel(true)); - } - - Direction direction = (Direction) this.directionCB.getSelectedItem(); - boolean scale = !scaleCB.isSelected(); - boolean showCenter = showCenterCB.isSelected(); - - int w = canvas.getWidth(); - int h = canvas.getHeight(); - - int x = w / 2; - int y = h / 2; - Point tileCenter = new Point(x, y); - tileCenter = LayoutUtil.snapToGrid(tileCenter); - -// if (TileType.CROSS == tileType) { -// switch (orientation) { -// case SOUTH -> { -// x = w / 2 + 200; -// y = h / 2 - 150; -// } -// case WEST -> { -// x = w / 2 + 400; -// y = h / 2 + 50; -// } -// case NORTH -> { -// x = w / 2 + 200; -// y = h / 2 + 250; -// } -// default -> { -// x = w / 2; -// y = h / 2 + 50; -// } -// } -// } else { -// x = w / 2 - 200; -// y = h / 2 - 200; -// } -// Point center; -// if (TileType.CROSS.equals(tileType)) { -// center = new Point(x - 200, y); -// } else { -// center = new Point(x, y); -// } - Tile newTile = TileFactory.createTile(tileType, orientation, direction, tileCenter); - newTile.setScaleImage(scale); - newTile.setDrawCenterPoint(showCenter); - - //tile.setPropertyChangeListener(this); - Orientation incomingSide = (Orientation) this.incomingSideCB.getSelectedItem(); - newTile.setIncomingSide(incomingSide); - - newTile.setDrawRoute(displayRouteCB.isSelected()); - newTile.setTrackRouteColor(Color.blue); - - Logger.trace("Adding tile " + newTile.getId() + " " + newTile.xyToString()); - - //this.cPanel.add((JComponent) newTile); - this.canvas.add(newTile); - this.tile = newTile; - } - - private AccessoryValue getAccessoryState() { - AccessoryValue value; - if (greenRB.isSelected()) { - value = AccessoryValue.GREEN; - } else if (redRB.isSelected()) { - value = AccessoryValue.RED; - - } else { - value = AccessoryValue.OFF; - } - return value; - } - - private void changeAccesoryState() { - if(tile instanceof Sensor) { - tile.setActive(this.redRB.isSelected()); - } - - if (tile instanceof Switch aSwitch) { - if (this.displayRouteCB.isSelected()) { - aSwitch.setRouteValue(getAccessoryState()); - } else { - aSwitch.setAccessoryValue(getAccessoryState()); - } - } - - if (tile instanceof Signal aSignal) { - if (this.greenRB.isSelected()) { - aSignal.setSignalValue(AccessoryBean.SignalValue.Hp1); - } else if (this.redRB.isSelected()) { - aSignal.setSignalValue(AccessoryBean.SignalValue.Hp0); - } else { - aSignal.setSignalValue(AccessoryBean.SignalValue.OFF); - } - } - - //this.tile.repaint(); - } - -// @Override -// public void propertyChange(PropertyChangeEvent evt) { -// if ("repaintTile".equals(evt.getPropertyName())) { -// Tile t = (Tile) evt.getNewValue(); -// Logger.trace("Tile: " + t); -// //this.repaint(); -// } -// } -// @Override -// public void paint(Graphics g) { -// super.paint(g); -// Graphics2D g2d = (Graphics2D) g; -// boolean outline = this.drawOutlineCB.isSelected(); -// boolean showRoute = this.displayRouteCB.isSelected(); -// tile.setDrawRoute(showRoute); -// -// tile.drawTile(g2d, outline); -// -// if (outline) { -// tile.drawBounds(g2d); -// tile.drawCenterPoint(g2d, Color.red); -// } -// } -// @Override -// public void paint(Graphics g) { -// long started = System.currentTimeMillis(); -// super.paint(g); -// -// long now = System.currentTimeMillis(); -// Logger.trace("Duration: " + (now - started) + " ms."); -// } - private void changeDirection() { - Direction direction = (Direction) this.directionCB.getSelectedItem(); - this.tile.setDirection(direction); - - //if (TileType.CROSS == tile.getTileType()) { - // ((Cross) tile).setWidthHeightAndOffsets(); - //} - //this.repaint(); - } - - private void rotateTile() { - Orientation newOrientation = tile.rotate(); - orientationCB.setSelectedItem(newOrientation); - -// if (TileType.CROSS == tile.getTileType()) { -// int x = tile.getCenterX(); -// int y = tile.getCenterY(); -// int w = tile.getWidth() * 10; -// int h = tile.getHeight() * 10; -// -// //calculate a new centerpoint for cross -// switch (tile.getOrientation()) { -// case SOUTH -> { -// x = x + w / 2; -// y = y - h / 4; -// } -// case WEST -> { -// x = x + w / 4; -// y = y + h / 2; -// } -// case NORTH -> { -// x = x - w / 2; -// y = y + h / 4; -// } -// default -> { -// x = x - w / 4; -// y = y - h / 2; -// } -// } -// tile.setCenter(new Point(x, y)); -// } - //this.canvas.repaint(this.tile.getTileBounds()); - //tile.repaint(); - } - - private void changeOrientation() { - Orientation orientation = (Orientation) this.orientationCB.getSelectedItem(); - tile.setOrientation(orientation); - - if (TileType.CROSS == tile.getTileType()) { - //((Cross) tile).setWidthHeightAndOffsets(); - - int x = tile.getCenterX(); - int y = tile.getCenterY(); - int w = tile.getWidth() * 10; - int h = tile.getHeight() * 10; - - //calculate a new centerpoint for cross - switch (tile.getOrientation()) { - case SOUTH -> { - x = x + w / 2; - y = y - h / 4; - } - case WEST -> { - x = x + w / 4; - y = y + h / 2; - } - case NORTH -> { - x = x - w / 2; - y = y + h / 4; - } - default -> { - x = x - w / 4; - y = y - h / 2; - } - } - tile.setCenter(new Point(x, y)); - } - - //this.repaint(); - } - - private void showRoute() { - - Logger.trace("Show route on tile " + tile.getId()); - - String tileId = tile.getId(); - Orientation incomingSide = (Orientation) this.incomingSideCB.getSelectedItem(); - - //TileEvent tileEvent; - if (tile.isJunction()) { - AccessoryValue routeState = getAccessoryState(); - //tileEvent = new TileEvent(tileId, true, incomingSide, routeState); - } else { - //tileEvent = new TileEvent(tileId, true, incomingSide); - } - //TileCache.fireTileEventListener(tileEvent); - - // ((JComponent) this.tile).repaint(); - tile.setDrawRoute(displayRouteCB.isSelected()); - //repaint(); - } - -// private void showOutline() { -// //repaint(); -// } - - private void changeIncomingSide() { - Orientation incomingSide = (Orientation) this.incomingSideCB.getSelectedItem(); - tile.setIncomingSide(incomingSide); - //this.repaint(); - } - - /** - * This method is called from within the constructor to initialize the form. WARNING: Do NOT modify this code. The content of this method is always regenerated by the Form Editor. - */ - @SuppressWarnings("unchecked") - // //GEN-BEGIN:initComponents - private void initComponents() { - - accessoryBG = new javax.swing.ButtonGroup(); - nPanel = new javax.swing.JPanel(); - tileCB = new javax.swing.JComboBox<>(); - orientationCB = new javax.swing.JComboBox<>(); - inComingLbl = new javax.swing.JLabel(); - incomingSideCB = new javax.swing.JComboBox<>(); - directionCB = new javax.swing.JComboBox<>(); - rotateButton = new javax.swing.JButton(); - offRB = new javax.swing.JRadioButton(); - greenRB = new javax.swing.JRadioButton(); - redRB = new javax.swing.JRadioButton(); - displayRouteCB = new javax.swing.JCheckBox(); - scaleCB = new javax.swing.JCheckBox(); - showCenterCB = new javax.swing.JCheckBox(); - canvas = new jcs.ui.layout.tiles.DotGridCanvas(); - - setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE); - - nPanel.setMinimumSize(new java.awt.Dimension(860, 36)); - nPanel.setPreferredSize(new java.awt.Dimension(1020, 36)); - java.awt.FlowLayout flowLayout1 = new java.awt.FlowLayout(java.awt.FlowLayout.LEFT); - flowLayout1.setAlignOnBaseline(true); - nPanel.setLayout(flowLayout1); - - tileCB.setPreferredSize(new java.awt.Dimension(150, 23)); - tileCB.addActionListener(new java.awt.event.ActionListener() { - public void actionPerformed(java.awt.event.ActionEvent evt) { - tileCBActionPerformed(evt); - } - }); - nPanel.add(tileCB); - - orientationCB.setPreferredSize(new java.awt.Dimension(100, 23)); - orientationCB.addActionListener(new java.awt.event.ActionListener() { - public void actionPerformed(java.awt.event.ActionEvent evt) { - orientationCBActionPerformed(evt); - } - }); - nPanel.add(orientationCB); - - inComingLbl.setText("Incoming Orientation"); - nPanel.add(inComingLbl); - - incomingSideCB.setPreferredSize(new java.awt.Dimension(100, 23)); - incomingSideCB.addActionListener(new java.awt.event.ActionListener() { - public void actionPerformed(java.awt.event.ActionEvent evt) { - incomingSideCBActionPerformed(evt); - } - }); - nPanel.add(incomingSideCB); - - directionCB.setPreferredSize(new java.awt.Dimension(100, 23)); - directionCB.addActionListener(new java.awt.event.ActionListener() { - public void actionPerformed(java.awt.event.ActionEvent evt) { - directionCBActionPerformed(evt); - } - }); - nPanel.add(directionCB); - - rotateButton.setText("Rotate"); - rotateButton.addActionListener(new java.awt.event.ActionListener() { - public void actionPerformed(java.awt.event.ActionEvent evt) { - rotateButtonActionPerformed(evt); - } - }); - nPanel.add(rotateButton); - - accessoryBG.add(offRB); - offRB.setForeground(new java.awt.Color(153, 153, 153)); - offRB.setSelected(true); - offRB.setText("Off"); - offRB.addActionListener(new java.awt.event.ActionListener() { - public void actionPerformed(java.awt.event.ActionEvent evt) { - offRBActionPerformed(evt); - } - }); - nPanel.add(offRB); - - accessoryBG.add(greenRB); - greenRB.setForeground(new java.awt.Color(102, 255, 0)); - greenRB.setText("Green"); - greenRB.addActionListener(new java.awt.event.ActionListener() { - public void actionPerformed(java.awt.event.ActionEvent evt) { - greenRBActionPerformed(evt); - } - }); - nPanel.add(greenRB); - - accessoryBG.add(redRB); - redRB.setForeground(new java.awt.Color(255, 0, 51)); - redRB.setText("Red"); - redRB.addActionListener(new java.awt.event.ActionListener() { - public void actionPerformed(java.awt.event.ActionEvent evt) { - redRBActionPerformed(evt); - } - }); - nPanel.add(redRB); - - displayRouteCB.setText("Route"); - displayRouteCB.addActionListener(new java.awt.event.ActionListener() { - public void actionPerformed(java.awt.event.ActionEvent evt) { - displayRouteCBActionPerformed(evt); - } - }); - nPanel.add(displayRouteCB); - - scaleCB.setText("Scale"); - scaleCB.addActionListener(new java.awt.event.ActionListener() { - public void actionPerformed(java.awt.event.ActionEvent evt) { - scaleCBActionPerformed(evt); - } - }); - nPanel.add(scaleCB); - - showCenterCB.setText("Center"); - showCenterCB.addActionListener(new java.awt.event.ActionListener() { - public void actionPerformed(java.awt.event.ActionEvent evt) { - showCenterCBActionPerformed(evt); - } - }); - nPanel.add(showCenterCB); - - getContentPane().add(nPanel, java.awt.BorderLayout.NORTH); - - canvas.setPreferredSize(new java.awt.Dimension(600, 600)); - getContentPane().add(canvas, java.awt.BorderLayout.CENTER); - - pack(); - }// //GEN-END:initComponents - - private void rotateButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_rotateButtonActionPerformed - rotateTile(); - }//GEN-LAST:event_rotateButtonActionPerformed - - private void tileCBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_tileCBActionPerformed - createTile(); - }//GEN-LAST:event_tileCBActionPerformed - - private void orientationCBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_orientationCBActionPerformed - changeOrientation(); - }//GEN-LAST:event_orientationCBActionPerformed - - private void directionCBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_directionCBActionPerformed - changeDirection(); - }//GEN-LAST:event_directionCBActionPerformed - - private void offRBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_offRBActionPerformed - changeAccesoryState(); - }//GEN-LAST:event_offRBActionPerformed - - private void greenRBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_greenRBActionPerformed - changeAccesoryState(); - }//GEN-LAST:event_greenRBActionPerformed - - private void redRBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_redRBActionPerformed - changeAccesoryState(); - }//GEN-LAST:event_redRBActionPerformed - - private void displayRouteCBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_displayRouteCBActionPerformed - showRoute(); - }//GEN-LAST:event_displayRouteCBActionPerformed - - private void scaleCBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_scaleCBActionPerformed - this.tile.setScaleImage(!this.scaleCB.isSelected()); - this.tile.setBounds(this.tile.getTileBounds()); - }//GEN-LAST:event_scaleCBActionPerformed - - private void incomingSideCBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_incomingSideCBActionPerformed - changeIncomingSide(); - }//GEN-LAST:event_incomingSideCBActionPerformed - - private void showCenterCBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_showCenterCBActionPerformed - this.tile.setDrawCenterPoint(this.showCenterCB.isSelected()); - }//GEN-LAST:event_showCenterCBActionPerformed - - /** - * @param args the command line arguments - */ - public static void main(String args[]) { - try { - UIManager.setLookAndFeel("com.formdev.flatlaf.FlatLightLaf"); - } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) { - Logger.error(ex); - } - - /* Create and display the form */ - java.awt.EventQueue.invokeLater(() -> { - TileTesterFrame app = new TileTesterFrame(); - app.setTitle("Tile Tester"); - app.setLocationRelativeTo(null); - }); - } - - // Variables declaration - do not modify//GEN-BEGIN:variables - private javax.swing.ButtonGroup accessoryBG; - private jcs.ui.layout.tiles.DotGridCanvas canvas; - private javax.swing.JComboBox directionCB; - private javax.swing.JCheckBox displayRouteCB; - private javax.swing.JRadioButton greenRB; - private javax.swing.JLabel inComingLbl; - private javax.swing.JComboBox incomingSideCB; - private javax.swing.JPanel nPanel; - private javax.swing.JRadioButton offRB; - private javax.swing.JComboBox orientationCB; - private javax.swing.JRadioButton redRB; - private javax.swing.JButton rotateButton; - private javax.swing.JCheckBox scaleCB; - private javax.swing.JCheckBox showCenterCB; - private javax.swing.JComboBox tileCB; - // End of variables declaration//GEN-END:variables -} +/* * Copyright 2024 Frans Jacobs. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package jcs.ui.layout.tiles; import java.awt.Color; import java.awt.Point; import javax.swing.ComboBoxModel; import javax.swing.DefaultComboBoxModel; import javax.swing.UIManager; import javax.swing.UnsupportedLookAndFeelException; import jcs.entities.AccessoryBean; import jcs.entities.AccessoryBean.AccessoryValue; import jcs.entities.TileBean; import jcs.entities.TileBean.Direction; import jcs.entities.TileBean.Orientation; import static jcs.entities.TileBean.Orientation.NORTH; import static jcs.entities.TileBean.Orientation.SOUTH; import static jcs.entities.TileBean.Orientation.WEST; import jcs.entities.TileBean.TileType; import jcs.ui.layout.LayoutUtil; import jcs.ui.layout.events.TileEvent; import org.tinylog.Logger; public class TileTesterFrame extends javax.swing.JFrame { private Tile tile; public TileTesterFrame() { initComponents(); this.tileCB.setModel(createTileTypeComboBoxModel()); this.orientationCB.setModel(createOrientationComboBoxModel()); this.incomingSideCB.setModel(createOrientationComboBoxModel()); this.directionCB.setModel(createDirectionComboBoxModel(true)); createTile(); pack(); setVisible(true); } private ComboBoxModel createTileTypeComboBoxModel() { DefaultComboBoxModel tileTypeModel = new DefaultComboBoxModel(); tileTypeModel.addElement(TileBean.TileType.STRAIGHT); tileTypeModel.addElement(TileBean.TileType.STRAIGHT_DIR); tileTypeModel.addElement(TileBean.TileType.SENSOR); tileTypeModel.addElement(TileBean.TileType.SIGNAL); tileTypeModel.addElement(TileBean.TileType.END); tileTypeModel.addElement(TileBean.TileType.CROSSING); tileTypeModel.addElement(TileBean.TileType.CURVED); tileTypeModel.addElement(TileBean.TileType.SWITCH); tileTypeModel.addElement(TileBean.TileType.CROSS); return tileTypeModel; } private ComboBoxModel createOrientationComboBoxModel() { DefaultComboBoxModel orientationModel = new DefaultComboBoxModel(); orientationModel.addElement(Orientation.EAST); orientationModel.addElement(Orientation.SOUTH); orientationModel.addElement(Orientation.WEST); orientationModel.addElement(Orientation.NORTH); return orientationModel; } private ComboBoxModel createDirectionComboBoxModel(boolean dontCare) { DefaultComboBoxModel directionModel = new DefaultComboBoxModel(); if (dontCare) { directionModel.addElement(Direction.CENTER); } else { directionModel.addElement(Direction.LEFT); directionModel.addElement(Direction.RIGHT); } return directionModel; } private void createTile() { if (tile != null) { Logger.trace("Removing tile " + tile.getId()); canvas.remove(tile); tile = null; } TileType tileType = (TileType) tileCB.getSelectedItem(); Orientation orientation = (Orientation) orientationCB.getSelectedItem(); if (TileType.SWITCH == tileType || TileType.CROSS == tileType) { directionCB.setModel(createDirectionComboBoxModel(false)); } else { directionCB.setModel(createDirectionComboBoxModel(true)); } Direction direction = (Direction) this.directionCB.getSelectedItem(); boolean scale = !scaleCB.isSelected(); boolean showCenter = showCenterCB.isSelected(); int w = canvas.getWidth(); int h = canvas.getHeight(); int x = w / 2; int y = h / 2; Point tileCenter = new Point(x, y); tileCenter = LayoutUtil.snapToGrid(tileCenter); // if (TileType.CROSS == tileType) { // switch (orientation) { // case SOUTH -> { // x = w / 2 + 200; // y = h / 2 - 150; // } // case WEST -> { // x = w / 2 + 400; // y = h / 2 + 50; // } // case NORTH -> { // x = w / 2 + 200; // y = h / 2 + 250; // } // default -> { // x = w / 2; // y = h / 2 + 50; // } // } // } else { // x = w / 2 - 200; // y = h / 2 - 200; // } // Point center; // if (TileType.CROSS.equals(tileType)) { // center = new Point(x - 200, y); // } else { // center = new Point(x, y); // } Tile newTile = TileFactory.createTile(tileType, orientation, direction, tileCenter); newTile.setScaleImage(scale); newTile.setDrawCenterPoint(showCenter); //tile.setPropertyChangeListener(this); Orientation incomingSide = (Orientation) this.incomingSideCB.getSelectedItem(); newTile.setIncomingSide(incomingSide); newTile.setDrawRoute(displayRouteCB.isSelected()); newTile.setTrackRouteColor(Color.blue); Logger.trace("Adding tile " + newTile.getId() + " " + newTile.xyToString()); //this.cPanel.add((JComponent) newTile); this.canvas.add(newTile); this.tile = newTile; } private AccessoryValue getAccessoryState() { AccessoryValue value; if (greenRB.isSelected()) { value = AccessoryValue.GREEN; } else if (redRB.isSelected()) { value = AccessoryValue.RED; } else { value = AccessoryValue.OFF; } return value; } private void changeAccesoryState() { if(tile instanceof Sensor) { tile.setActive(this.redRB.isSelected()); } if (tile instanceof Switch aSwitch) { if (this.displayRouteCB.isSelected()) { aSwitch.setRouteValue(getAccessoryState()); } else { aSwitch.setAccessoryValue(getAccessoryState()); } } if (tile instanceof Signal aSignal) { if (this.greenRB.isSelected()) { aSignal.setSignalValue(AccessoryBean.SignalValue.Hp1); } else if (this.redRB.isSelected()) { aSignal.setSignalValue(AccessoryBean.SignalValue.Hp0); } else { aSignal.setSignalValue(AccessoryBean.SignalValue.OFF); } } //this.tile.repaint(); } // @Override // public void propertyChange(PropertyChangeEvent evt) { // if ("repaintTile".equals(evt.getPropertyName())) { // Tile t = (Tile) evt.getNewValue(); // Logger.trace("Tile: " + t); // //this.repaint(); // } // } // @Override // public void paint(Graphics g) { // super.paint(g); // Graphics2D g2d = (Graphics2D) g; // boolean outline = this.drawOutlineCB.isSelected(); // boolean showRoute = this.displayRouteCB.isSelected(); // tile.setDrawRoute(showRoute); // // tile.drawTile(g2d, outline); // // if (outline) { // tile.drawBounds(g2d); // tile.drawCenterPoint(g2d, Color.red); // } // } // @Override // public void paint(Graphics g) { // long started = System.currentTimeMillis(); // super.paint(g); // // long now = System.currentTimeMillis(); // Logger.trace("Duration: " + (now - started) + " ms."); // } private void changeDirection() { Direction direction = (Direction) this.directionCB.getSelectedItem(); this.tile.setDirection(direction); //if (TileType.CROSS == tile.getTileType()) { // ((Cross) tile).setWidthHeightAndOffsets(); //} //this.repaint(); } private void rotateTile() { Orientation newOrientation = tile.rotate(); orientationCB.setSelectedItem(newOrientation); // if (TileType.CROSS == tile.getTileType()) { // int x = tile.getCenterX(); // int y = tile.getCenterY(); // int w = tile.getWidth() * 10; // int h = tile.getHeight() * 10; // // //calculate a new centerpoint for cross // switch (tile.getOrientation()) { // case SOUTH -> { // x = x + w / 2; // y = y - h / 4; // } // case WEST -> { // x = x + w / 4; // y = y + h / 2; // } // case NORTH -> { // x = x - w / 2; // y = y + h / 4; // } // default -> { // x = x - w / 4; // y = y - h / 2; // } // } // tile.setCenter(new Point(x, y)); // } //this.canvas.repaint(this.tile.getTileBounds()); //tile.repaint(); } private void changeOrientation() { Orientation orientation = (Orientation) this.orientationCB.getSelectedItem(); tile.setOrientation(orientation); // if (TileType.CROSS == tile.getTileType()) { // //((Cross) tile).setWidthHeightAndOffsets(); // // int x = tile.getCenterX(); // int y = tile.getCenterY(); // int w = tile.getWidth() * 10; // int h = tile.getHeight() * 10; // // //calculate a new centerpoint for cross // switch (tile.getOrientation()) { // case SOUTH -> { // x = x + w / 2; // y = y - h / 4; // } // case WEST -> { // x = x + w / 4; // y = y + h / 2; // } // case NORTH -> { // x = x - w / 2; // y = y + h / 4; // } // default -> { // x = x - w / 4; // y = y - h / 2; // } // } // tile.setCenter(new Point(x, y)); // } //this.repaint(); } private void showRoute() { Logger.trace("Show route on tile " + tile.getId()); String tileId = tile.getId(); Orientation incomingSide = (Orientation) this.incomingSideCB.getSelectedItem(); //TileEvent tileEvent; if (tile.isJunction()) { AccessoryValue routeState = getAccessoryState(); //tileEvent = new TileEvent(tileId, true, incomingSide, routeState); } else { //tileEvent = new TileEvent(tileId, true, incomingSide); } //TileCache.fireTileEventListener(tileEvent); // ((JComponent) this.tile).repaint(); tile.setDrawRoute(displayRouteCB.isSelected()); //repaint(); } // private void showOutline() { // //repaint(); // } private void changeIncomingSide() { Orientation incomingSide = (Orientation) this.incomingSideCB.getSelectedItem(); tile.setIncomingSide(incomingSide); //this.repaint(); } /** * This method is called from within the constructor to initialize the form. WARNING: Do NOT modify this code. The content of this method is always regenerated by the Form Editor. */ @SuppressWarnings("unchecked") // //GEN-BEGIN:initComponents private void initComponents() { accessoryBG = new javax.swing.ButtonGroup(); nPanel = new javax.swing.JPanel(); tileCB = new javax.swing.JComboBox<>(); orientationCB = new javax.swing.JComboBox<>(); inComingLbl = new javax.swing.JLabel(); incomingSideCB = new javax.swing.JComboBox<>(); directionCB = new javax.swing.JComboBox<>(); rotateButton = new javax.swing.JButton(); offRB = new javax.swing.JRadioButton(); greenRB = new javax.swing.JRadioButton(); redRB = new javax.swing.JRadioButton(); displayRouteCB = new javax.swing.JCheckBox(); scaleCB = new javax.swing.JCheckBox(); showCenterCB = new javax.swing.JCheckBox(); canvas = new jcs.ui.layout.tiles.DotGridCanvas(); setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE); nPanel.setMinimumSize(new java.awt.Dimension(860, 36)); nPanel.setPreferredSize(new java.awt.Dimension(1020, 36)); java.awt.FlowLayout flowLayout1 = new java.awt.FlowLayout(java.awt.FlowLayout.LEFT); flowLayout1.setAlignOnBaseline(true); nPanel.setLayout(flowLayout1); tileCB.setPreferredSize(new java.awt.Dimension(150, 23)); tileCB.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { tileCBActionPerformed(evt); } }); nPanel.add(tileCB); orientationCB.setPreferredSize(new java.awt.Dimension(100, 23)); orientationCB.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { orientationCBActionPerformed(evt); } }); nPanel.add(orientationCB); inComingLbl.setText("Incoming Orientation"); nPanel.add(inComingLbl); incomingSideCB.setPreferredSize(new java.awt.Dimension(100, 23)); incomingSideCB.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { incomingSideCBActionPerformed(evt); } }); nPanel.add(incomingSideCB); directionCB.setPreferredSize(new java.awt.Dimension(100, 23)); directionCB.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { directionCBActionPerformed(evt); } }); nPanel.add(directionCB); rotateButton.setText("Rotate"); rotateButton.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { rotateButtonActionPerformed(evt); } }); nPanel.add(rotateButton); accessoryBG.add(offRB); offRB.setForeground(new java.awt.Color(153, 153, 153)); offRB.setSelected(true); offRB.setText("Off"); offRB.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { offRBActionPerformed(evt); } }); nPanel.add(offRB); accessoryBG.add(greenRB); greenRB.setForeground(new java.awt.Color(102, 255, 0)); greenRB.setText("Green"); greenRB.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { greenRBActionPerformed(evt); } }); nPanel.add(greenRB); accessoryBG.add(redRB); redRB.setForeground(new java.awt.Color(255, 0, 51)); redRB.setText("Red"); redRB.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { redRBActionPerformed(evt); } }); nPanel.add(redRB); displayRouteCB.setText("Route"); displayRouteCB.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { displayRouteCBActionPerformed(evt); } }); nPanel.add(displayRouteCB); scaleCB.setText("Scale"); scaleCB.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { scaleCBActionPerformed(evt); } }); nPanel.add(scaleCB); showCenterCB.setText("Center"); showCenterCB.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { showCenterCBActionPerformed(evt); } }); nPanel.add(showCenterCB); getContentPane().add(nPanel, java.awt.BorderLayout.NORTH); canvas.setPreferredSize(new java.awt.Dimension(600, 600)); getContentPane().add(canvas, java.awt.BorderLayout.CENTER); pack(); }// //GEN-END:initComponents private void rotateButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_rotateButtonActionPerformed rotateTile(); }//GEN-LAST:event_rotateButtonActionPerformed private void tileCBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_tileCBActionPerformed createTile(); }//GEN-LAST:event_tileCBActionPerformed private void orientationCBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_orientationCBActionPerformed changeOrientation(); }//GEN-LAST:event_orientationCBActionPerformed private void directionCBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_directionCBActionPerformed changeDirection(); }//GEN-LAST:event_directionCBActionPerformed private void offRBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_offRBActionPerformed changeAccesoryState(); }//GEN-LAST:event_offRBActionPerformed private void greenRBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_greenRBActionPerformed changeAccesoryState(); }//GEN-LAST:event_greenRBActionPerformed private void redRBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_redRBActionPerformed changeAccesoryState(); }//GEN-LAST:event_redRBActionPerformed private void displayRouteCBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_displayRouteCBActionPerformed showRoute(); }//GEN-LAST:event_displayRouteCBActionPerformed private void scaleCBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_scaleCBActionPerformed this.tile.setScaleImage(!this.scaleCB.isSelected()); this.tile.setBounds(this.tile.getTileBounds()); }//GEN-LAST:event_scaleCBActionPerformed private void incomingSideCBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_incomingSideCBActionPerformed changeIncomingSide(); }//GEN-LAST:event_incomingSideCBActionPerformed private void showCenterCBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_showCenterCBActionPerformed this.tile.setDrawCenterPoint(this.showCenterCB.isSelected()); }//GEN-LAST:event_showCenterCBActionPerformed /** * @param args the command line arguments */ public static void main(String args[]) { try { UIManager.setLookAndFeel("com.formdev.flatlaf.FlatLightLaf"); } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) { Logger.error(ex); } /* Create and display the form */ java.awt.EventQueue.invokeLater(() -> { TileTesterFrame app = new TileTesterFrame(); app.setTitle("Tile Tester"); app.setLocationRelativeTo(null); }); } // Variables declaration - do not modify//GEN-BEGIN:variables private javax.swing.ButtonGroup accessoryBG; private jcs.ui.layout.tiles.DotGridCanvas canvas; private javax.swing.JComboBox directionCB; private javax.swing.JCheckBox displayRouteCB; private javax.swing.JRadioButton greenRB; private javax.swing.JLabel inComingLbl; private javax.swing.JComboBox incomingSideCB; private javax.swing.JPanel nPanel; private javax.swing.JRadioButton offRB; private javax.swing.JComboBox orientationCB; private javax.swing.JRadioButton redRB; private javax.swing.JButton rotateButton; private javax.swing.JCheckBox scaleCB; private javax.swing.JCheckBox showCenterCB; private javax.swing.JComboBox tileCB; // End of variables declaration//GEN-END:variables } \ No newline at end of file From 7b2ca1db8f1028b01a13723a3ac1562941e84211 Mon Sep 17 00:00:00 2001 From: Frans Jacobs <41232225+fransjacobs@users.noreply.github.com> Date: Tue, 28 Jan 2025 18:14:26 +0100 Subject: [PATCH 10/24] Tiles can be moved, extra check is needed for Block and Cross WIP --- src/main/java/jcs/ui/layout/LayoutCanvas.java | 308 ++--- src/main/java/jcs/ui/layout/TileCache.java | 101 +- src/main/java/jcs/ui/layout/tiles/Cross.java | 669 +++++++++- .../jcs/ui/layout/tiles/DefaultTileModel.java | 22 + src/main/java/jcs/ui/layout/tiles/Tile.java | 1134 ++++++++++++++++- .../java/jcs/ui/layout/tiles/TileFactory.java | 1 - .../java/jcs/ui/layout/tiles/TileModel.java | 5 + 7 files changed, 2007 insertions(+), 233 deletions(-) diff --git a/src/main/java/jcs/ui/layout/LayoutCanvas.java b/src/main/java/jcs/ui/layout/LayoutCanvas.java index 5ba67e08..fb3813da 100755 --- a/src/main/java/jcs/ui/layout/LayoutCanvas.java +++ b/src/main/java/jcs/ui/layout/LayoutCanvas.java @@ -29,8 +29,6 @@ import java.awt.event.MouseAdapter; import java.awt.event.MouseEvent; import java.awt.event.MouseMotionAdapter; -import java.awt.image.BufferedImage; -import java.util.HashSet; import java.util.List; import java.util.Set; import java.util.concurrent.ExecutorService; @@ -103,19 +101,14 @@ public enum Mode { private Point mouseLocation = new Point(); - //private BufferedImage grid; private final ExecutorService executor; - private final Set selectedTiles; - private Tile selectedTile; private RoutesDialog routesDialog; //private final Map selectedRouteElements; - private Point movingTileCenterPoint; - private BufferedImage movingTileImage; - + //private Point mousePressedPoint; public LayoutCanvas() { this(false); } @@ -127,12 +120,7 @@ public LayoutCanvas(boolean readonly) { setDoubleBuffered(true); this.readonly = readonly; -// this.tiles = new HashMap<>(); -// this.altTiles = new HashMap<>(); - - this.selectedTiles = new HashSet<>(); // this.selectedRouteElements = new HashMap<>(); - this.executor = Executors.newSingleThreadExecutor(); //this.executor = Executors.newCachedThreadPool(); @@ -166,14 +154,6 @@ public void paint(Graphics g) { Logger.trace("Duration: " + (now - started) + " ms."); } -// @Override -// protected void paintComponent(Graphics g) { -// long started = System.currentTimeMillis(); -// super.paintComponent(g); -// long now = System.currentTimeMillis(); -// Logger.trace("Duration: " + (now - started) + " ms."); -// } - @Override public Component add(Component component) { super.add(component); @@ -264,14 +244,14 @@ void loadLayoutInBackground() { } private void loadTiles() { - //boolean showValues = Mode.CONTROL.equals(mode); TileCache.loadTiles(); + removeAll(); + + selectedTile = null; - selectedTiles.clear(); for (Tile tile : TileCache.tiles.values()) { - this.add(tile); + add(tile); tile.setDrawCenterPoint(!readonly); - //tile.setBounds(tile.getTileBounds()); } repaint(); @@ -279,101 +259,77 @@ private void loadTiles() { private void mouseMoveAction(MouseEvent evt) { Point sp = LayoutUtil.snapToGrid(evt.getPoint()); - Tile tile = TileCache.findTile(sp); - if (tile != null) { + if (selectedTile != null) { setCursor(Cursor.getPredefinedCursor(Cursor.CROSSHAIR_CURSOR)); } else { setCursor(Cursor.getDefaultCursor()); } } - private Tile getSelectedTile() { - Tile t = null; - if (!selectedTiles.isEmpty()) { - for (Point p : this.selectedTiles) { - //t = tiles.get(p); - t = TileCache.tiles.get(p); - if (t != null) { - return t; - } - } - } - return t; - } - private void mousePressedAction(MouseEvent evt) { Point snapPoint = LayoutUtil.snapToGrid(evt.getPoint()); - //Clear any previous selection - for (Point p : selectedTiles) { - if (TileCache.containsPoint(p)) { - Tile st = TileCache.findTile(p); - st.setSelected(false); - } + Tile previousSelected = this.selectedTile; + selectedTile = TileCache.findTile(snapPoint); + if (selectedTile != null) { + selectedTile.setSelected(true); } - selectedTiles.clear(); - Tile tile = TileCache.findTile(snapPoint); - - if (tile != null) { - selectedTiles.addAll(tile.getAllPoints()); - tile.setSelected(true); - selectedTile = tile; + if (previousSelected != null && selectedTile != null && previousSelected.getId().equals(selectedTile.getId())) { + Logger.trace("Same tile " + selectedTile.getId() + " selected"); + } else if (previousSelected != null) { + previousSelected.setSelected(false); } switch (mode) { case CONTROL -> { - if (tile != null) { + if (selectedTile != null) { if (evt.getButton() == MouseEvent.BUTTON1) { - executeControlActionForTile(tile, snapPoint); + executeControlActionForTile(selectedTile, snapPoint); } else { - if (tile.isBlock()) { - showBlockPopupMenu(tile, snapPoint); + if (selectedTile.isBlock()) { + showBlockPopupMenu(selectedTile, snapPoint); } } } } case ADD -> { - if (MouseEvent.BUTTON1 == evt.getButton() && tile == null) { + if (MouseEvent.BUTTON1 == evt.getButton() && selectedTile == null) { //Only add a new tile when there is no tile on the selected snapPoint Logger.trace("Adding a new tile: " + tileType + " @ (" + snapPoint.x + ", " + snapPoint.y + ")"); - Tile addedTile = addTile(snapPoint, tileType, orientation, direction, true, !readonly); - if (addedTile != null) { - selectedTiles.addAll(addedTile.getAllPoints()); - repaint(addedTile.getTileBounds()); + selectedTile = addTile(snapPoint, tileType, orientation, direction, true, !readonly); + if (selectedTile != null) { + //selectedTiles.addAll(selectedTile.getAllPoints()); + selectedTile.setSelected(true); + repaint(selectedTile.getTileBounds()); } } else { - if (tile != null) { - Logger.debug("A tile exists at the selected position: " + tile.getTileType() + " @ (" + snapPoint.x + ", " + snapPoint.y + ") id: " + tile.getId()); + if (selectedTile != null) { + Logger.debug("A tile exists at the selected position: " + selectedTile.getTileType() + " @ (" + snapPoint.x + ", " + snapPoint.y + ") id: " + selectedTile.getId()); } else { Logger.warn("Found something (" + snapPoint.x + ", " + snapPoint.y + ")"); } } - if (MouseEvent.BUTTON3 == evt.getButton() && tile != null) { - showOperationsPopupMenu(tile, snapPoint); + if (MouseEvent.BUTTON3 == evt.getButton() && selectedTile != null) { + showOperationsPopupMenu(selectedTile, snapPoint); } } case DELETE -> { Tile toBeDeleted = (Tile) getComponentAt(snapPoint); if (toBeDeleted != null) { removeTile(toBeDeleted); - selectedTiles.clear(); + //selectedTiles.clear(); repaint(toBeDeleted.getTileBounds()); selectedTile = null; } } default -> { - Logger.trace((tile != null ? "Selected tile: " + tile.getId() + ", " + tile.xyToString() : "No tile selected")); - //if (tile == null) { - // this.selectedTiles.clear(); - //} - + Logger.trace((selectedTile != null ? "Selected tile: " + selectedTile.getId() + ", " + selectedTile.xyToString() : "No tile selected")); if (MouseEvent.BUTTON3 == evt.getButton()) { - showOperationsPopupMenu(tile, snapPoint); + showOperationsPopupMenu(selectedTile, snapPoint); } } } - } private Tile addTile(Point p, TileType tileType, Orientation orientation, Direction direction, boolean selected, boolean showCenter) { @@ -389,8 +345,6 @@ private Tile addTile(Point p, TileType tileType, Orientation orientation, Direct if (canBeAdded) { add(tile); - //tile.setBounds(tile.getTileBounds()); - TileCache.addAndSaveTile(tile); return tile; } else { @@ -409,89 +363,107 @@ void removeTile(Tile tile) { private void mouseDragAction(MouseEvent evt) { Point snapPoint = LayoutUtil.snapToGrid(evt.getPoint()); - Tile selTile = getSelectedTile(); - if (selTile != null) { - movingTileImage = selTile.getTileImage(); - movingTileCenterPoint = snapPoint; - } else { - movingTileImage = null; - movingTileCenterPoint = null; + + if (selectedTile != null) { + int z = getComponentZOrder(selectedTile); + Logger.trace("Moving Tile: " + selectedTile.getId() + " Z: " + z + " @ " + selectedTile.xyToString()); + + //Put on Top + setComponentZOrder(selectedTile, 0); + int curX = snapPoint.x - Tile.GRID; + int curY = snapPoint.y - Tile.GRID; + + //check overlap in the cache + //This wil only chek the snappint, whic incas of a moving Block or Cross in not enough! + //TODO ! Needed are the alt point of the moved block or Cross. + //How to do this? + if (TileCache.containsPoint(snapPoint)) { + selectedTile.setSelectedColor(Tile.DEFAULT_WARN_COLOR); + } else { + selectedTile.setSelectedColor(Tile.DEFAULT_SELECTED_COLOR); + } + + selectedTile.setBounds(curX, curY, selectedTile.getWidth(), selectedTile.getHeight()); } - repaint(); } private void mouseReleasedAction(MouseEvent evt) { - Tile selTile = getSelectedTile(); - if (selTile != null) { - Logger.trace("Selected tile: " + selTile.getId() + ", " + selTile.xyToString()); - } - Point snapPoint = LayoutUtil.snapToGrid(evt.getPoint()); - if (!LayoutCanvas.Mode.CONTROL.equals(mode) && MouseEvent.BUTTON1 == evt.getButton() && selTile != null) { - Point tp = selTile.getCenter(); - if (!tp.equals(snapPoint)) { - Logger.tag("Moving Tile from " + tp + " to " + snapPoint + " Tile to move: " + selTile); - //Check if new position is free - boolean canMove = true; - //if (tiles.containsKey(snapPoint) || altTiles.containsKey(snapPoint)) { - if (TileCache.containsPoint(snapPoint)) { - Tile tile = TileCache.findTile(snapPoint); - if (selTile.getId().equals(tile.getId())) { - //same tile so we can move - canMove = true; - } else { - Logger.debug("Position " + snapPoint + " is occupied with tile: " + tile + ", can't move tile " + selTile.getId()); - canMove = false; - } - } + boolean snapPointOccupied = TileCache.containsPoint(snapPoint); + if (!Mode.CONTROL.equals(mode) && MouseEvent.BUTTON1 == evt.getButton() && selectedTile != null) { + + boolean destinationOccupied = TileCache.containsPoints(selectedTile.getAllPoints()); - if (canMove) { - //Remove the original tile center from the tiles - Tile movingTile = TileCache.tiles.remove(tp); - if (movingTile != null) { - //Also remove from the alt points - Point oldCenter = movingTile.getCenter(); - Set oldAltPoints = movingTile.getAltPoints(); - //Logger.trace("Removing " + oldAltPoints.size() + " alt tile points"); - for (Point ep : oldAltPoints) { - TileCache.altTiles.remove(ep); - TileCache.tiles.remove(ep); - } + + Logger.trace("Selected tile: " + selectedTile.getId() + ", " + selectedTile.xyToString()+" Dest Occ "+destinationOccupied); - //Set the new center position - movingTile.setCenter(snapPoint); - //Check again, needed for tiles which are longer then 1 square, like a block - if (!TileCache.checkTileOccupation(movingTile)) { - Logger.trace("Moved Tile " + movingTile.getId() + " from " + tp + " to " + snapPoint + "..."); - TileCache.tiles.put(snapPoint, movingTile); - for (Point ep : movingTile.getAltPoints()) { - TileCache.altTiles.put(ep, movingTile); - } - selectedTiles.clear(); - selectedTiles.addAll(movingTile.getAllPoints()); - } else { - //Do not move Tile, put back where it was - movingTile.setCenter(oldCenter); - TileCache.tiles.put(oldCenter, movingTile); - for (Point ep : movingTile.getAltPoints()) { - TileCache.altTiles.put(ep, movingTile); - } - } + if (destinationOccupied || snapPointOccupied) { + Logger.debug("Can't move tile " + selectedTile.getId() + " from " + selectedTile.xyToString() + " to (" + snapPoint.x + "," + snapPoint.y + ")!"); - //if ("false".equals(System.getProperty("batch.tile.persist", "true"))) { - //this.saveTile(movingTile); - TileCache.saveTile(movingTile); - //} - } - repaint(); - } + //selectedTile.setBounds(selectedTile.getTileX(), selectedTile.getTileY(), selectedTile.getWidth(), selectedTile.getHeight()); + selectedTile.setBounds(selectedTile.getTileBounds()); + selectedTile.setSelectedColor(Tile.DEFAULT_SELECTED_COLOR); + + } else { + TileCache.moveTile(snapPoint, selectedTile); } - } - movingTileImage = null; - movingTileCenterPoint = null; - //repaint(); +// Point tp = selectedTile.getCenter(); +// if (!tp.equals(snapPoint)) { +// +// Logger.tag("Moving Tile from " + tp + " to " + snapPoint + " Tile to move: " + selectedTile); +// //Check if new position is free +// boolean canMove = true; +// if (TileCache.containsPoint(snapPoint)) { +// Tile tile = TileCache.findTile(snapPoint); +// if (selectedTile.getId().equals(tile.getId())) { +// //same tile so we can move +// canMove = true; +// } else { +// Logger.debug("Position " + snapPoint + " is occupied with tile: " + tile + ", can't move tile " + selectedTile.getId()); +// canMove = false; +// } +// } +// +// if (canMove) { +// //Remove the original tile center from the tiles +// Tile movingTile = TileCache.tiles.remove(tp); +// if (movingTile != null) { +// //Also remove from the alt points +// Point oldCenter = movingTile.getCenter(); +// Set oldAltPoints = movingTile.getAltPoints(); +// //Logger.trace("Removing " + oldAltPoints.size() + " alt tile points"); +// for (Point ep : oldAltPoints) { +// TileCache.altTiles.remove(ep); +// TileCache.tiles.remove(ep); +// } +// +// //Set the new center position +// movingTile.setCenter(snapPoint); +// //Check again, needed for tiles which are longer then 1 square, like a block +// if (!TileCache.checkTileOccupation(movingTile)) { +// Logger.trace("Moved Tile " + movingTile.getId() + " from " + tp + " to " + snapPoint + "..."); +// TileCache.tiles.put(snapPoint, movingTile); +// for (Point ep : movingTile.getAltPoints()) { +// TileCache.altTiles.put(ep, movingTile); +// } +// } else { +// //Do not move Tile, put back where it was +// movingTile.setCenter(oldCenter); +// TileCache.tiles.put(oldCenter, movingTile); +// for (Point ep : movingTile.getAltPoints()) { +// TileCache.altTiles.put(ep, movingTile); +// } +// } +// +// TileCache.saveTile(movingTile); +// } +// //TODO is this needed? + // repaint(); + // } + // } + } } private void executeControlActionForTile(Tile tile, Point p) { @@ -510,8 +482,6 @@ private void executeControlActionForTile(Tile tile, Point p) { Block block = (Block) tile; BlockControlDialog bcd = new BlockControlDialog(getParentFrame(), block); bcd.setVisible(true); - - //this.repaint(block.getX(), block.getY(), block.getWidth(), block.getHeight()); } case SIGNAL -> this.executor.execute(() -> toggleSignal((Signal) tile)); @@ -532,7 +502,6 @@ private void toggleSwitch(Switch turnout) { turnout.setAccessoryValue(ab.getAccessoryValue()); JCS.getJcsCommandStation().switchAccessory(ab, ab.getAccessoryValue()); - //repaint(turnout.getX(), turnout.getY(), turnout.getWidth(), turnout.getHeight()); } else { Logger.trace("No AccessoryBean configured for Turnout: " + turnout.getId()); } @@ -545,7 +514,6 @@ private void toggleSignal(Signal signal) { Logger.trace("A: " + ab.getAddress() + " S: " + ab.getStates() + " P: " + ab.getState()); JCS.getJcsCommandStation().switchAccessory(ab, ab.getAccessoryValue()); - //repaint(signal.getX(), signal.getY(), signal.getWidth(), signal.getHeight()); } else { Logger.trace("No AccessoryBean configured for Signal: " + signal.getId()); } @@ -557,7 +525,6 @@ private void toggleSensor(Sensor sensor) { sb.toggle(); sensor.setActive((sb.getStatus() == 1)); Logger.trace("id: " + sb.getId() + " state " + sb.getStatus()); - //sensor.repaintTile(); SensorEvent sensorEvent = new SensorEvent(sb); fireFeedbackEvent(sensorEvent); } @@ -578,12 +545,9 @@ private void editSelectedTileProperties() { boolean showMove = false; boolean showDelete = false; - if (!this.selectedTiles.isEmpty()) { - Point tcp = this.selectedTiles.iterator().next(); - Tile tile = TileCache.findTile(tcp); - TileBean.TileType tt = tile.getTileType(); - - Logger.trace("Seleted tile " + tile.getId() + " TileType " + tt); + if (selectedTile != null) { + TileBean.TileType tt = selectedTile.getTileType(); + Logger.trace("Selected tile " + selectedTile.getId() + " TileType " + tt); switch (tt) { case END -> { @@ -603,24 +567,24 @@ private void editSelectedTileProperties() { showDelete = true; } case SENSOR -> { - SensorDialog fbd = new SensorDialog(getParentFrame(), (Sensor) tile); + SensorDialog fbd = new SensorDialog(getParentFrame(), (Sensor) selectedTile); fbd.setVisible(true); } case SIGNAL -> { - SignalDialog sd = new SignalDialog(getParentFrame(), (Signal) tile); + SignalDialog sd = new SignalDialog(getParentFrame(), (Signal) selectedTile); sd.setVisible(true); } case SWITCH -> { - SwitchDialog td = new SwitchDialog(getParentFrame(), (Switch) tile); + SwitchDialog td = new SwitchDialog(getParentFrame(), (Switch) selectedTile); td.setVisible(true); } case CROSS -> { - SwitchDialog td = new SwitchDialog(getParentFrame(), (Switch) tile); + SwitchDialog td = new SwitchDialog(getParentFrame(), (Switch) selectedTile); td.setVisible(true); } case BLOCK -> { - Logger.trace("Show BlockDialog for " + tile.getId()); - BlockDialog bd = new BlockDialog(getParentFrame(), (Block) tile, this); + Logger.trace("Show BlockDialog for " + selectedTile.getId()); + BlockDialog bd = new BlockDialog(getParentFrame(), (Block) selectedTile, this); bd.setVisible(true); } default -> { @@ -734,21 +698,16 @@ public void rotateSelectedTile() { Logger.trace("Selected Tile " + selectedTile.getId()); selectedTile = TileCache.rotateTile(selectedTile); selectedTile.setBounds(selectedTile.getTileBounds()); - //selectedTile.repaint(); - - repaint(selectedTile.getTileBounds()); } public void flipSelectedTileHorizontal() { selectedTile = TileCache.flipHorizontal(selectedTile); selectedTile.setBounds(selectedTile.getTileBounds()); - selectedTile.repaint(); } public void flipSelectedTileVertical() { selectedTile = TileCache.flipVertical(selectedTile); selectedTile.setBounds(selectedTile.getTileBounds()); - selectedTile.repaint(); } void routeLayout() { @@ -758,8 +717,6 @@ void routeLayout() { private void routeLayoutWithAStar() { //Make sure the layout is saved TileCache.saveTiles(); -// Set snapshot = new HashSet<>(tiles.values()); -// this.saveTiles(snapshot); AStar astar = new AStar(); astar.buildGraph(TileCache.getTiles()); @@ -1052,7 +1009,6 @@ private void moveMIActionPerformed(ActionEvent evt) {//GEN-FIRST:event_moveMIAct private void deleteMIActionPerformed(ActionEvent evt) {//GEN-FIRST:event_deleteMIActionPerformed if (selectedTile != null) { removeTile(selectedTile); - selectedTiles.clear(); repaint(selectedTile.getTileBounds()); selectedTile = null; } @@ -1140,7 +1096,6 @@ private void reverseArrivalSideMIActionPerformed(ActionEvent evt) {//GEN-FIRST:e block.getBlockBean().setReverseArrival(!block.getBlockBean().isReverseArrival()); this.executor.execute(() -> { PersistenceFactory.getService().persist(block.getBlockBean()); - //block.repaintTile(); }); } }//GEN-LAST:event_reverseArrivalSideMIActionPerformed @@ -1161,7 +1116,6 @@ private void toggleLocomotiveDirectionMIActionPerformed(ActionEvent evt) {//GEN- this.executor.execute(() -> { PersistenceFactory.getService().persist(block.getTileBean()); - //block.repaintTile(); }); } }//GEN-LAST:event_toggleLocomotiveDirectionMIActionPerformed @@ -1179,7 +1133,6 @@ private void toggleOutOfOrderMIActionPerformed(ActionEvent evt) {//GEN-FIRST:eve if (currentState != block.getBlockState()) { //getRouteBlockState()) { this.executor.execute(() -> { PersistenceFactory.getService().persist(block.getBlockBean()); - //block.repaintTile(); }); } @@ -1198,7 +1151,6 @@ private void resetGhostMIActionPerformed(ActionEvent evt) {//GEN-FIRST:event_res } this.executor.execute(() -> { PersistenceFactory.getService().persist(block.getBlockBean()); - //block.repaintTile(); }); } } diff --git a/src/main/java/jcs/ui/layout/TileCache.java b/src/main/java/jcs/ui/layout/TileCache.java index 361bb354..c44f5909 100644 --- a/src/main/java/jcs/ui/layout/TileCache.java +++ b/src/main/java/jcs/ui/layout/TileCache.java @@ -54,16 +54,15 @@ public class TileCache { private TileCache() { } - static void setDrawCenterPoint(boolean drawCenterPoint) { - TileCache.drawCenterPoint = drawCenterPoint; - - for (Tile tile : tiles.values()) { - //if (tile instanceof AbstractTile abstractTile) { - tile.setDrawCenterPoint(drawCenterPoint); - //} - } - } - +// static void setDrawCenterPoint(boolean drawCenterPoint) { +// TileCache.drawCenterPoint = drawCenterPoint; +// +// for (Tile tile : tiles.values()) { +// //if (tile instanceof AbstractTile abstractTile) { +// tile.setDrawCenterPoint(drawCenterPoint); +// //} +// } +// } public static void setShowValues(boolean showValues) { TileCache.showValues = showValues; @@ -225,6 +224,14 @@ static boolean checkTileOccupation(Tile tile) { return false; } + static boolean containsPoints(Set points) { + for (Point p : points) { + return tiles.containsKey(p) || altTiles.containsKey(p); + } + return false; + + } + static boolean containsPoint(Point point) { return tiles.containsKey(point) || altTiles.containsKey(point); } @@ -322,54 +329,44 @@ static void moveTile(Point snapPoint, Tile tile) { Point tp = tile.getCenter(); if (!tp.equals(snapPoint)) { //Check if new position is free - boolean canMove = true; - if (tiles.containsKey(snapPoint) || altTiles.containsKey(snapPoint)) { - Tile t = findTile(snapPoint); - if (tile.getId().equals(t.getId())) { - //same tile so we can move - canMove = true; - } else { - Logger.trace("Position " + snapPoint + " is occupied with tile: " + t + ", can't move tile " + tile.getId()); - canMove = false; - } - - if (canMove) { - //Remove the original tile center from the tiles - Tile movingTile = tiles.remove(tp); - if (movingTile != null) { - //Also remove from the alt points - Point oldCenter = movingTile.getCenter(); - Set oldAltPoints = movingTile.getAltPoints(); - //Logger.trace("Removing " + oldAltPoints.size() + " alt tile points"); - for (Point ep : oldAltPoints) { - altTiles.remove(ep); - tiles.remove(ep); - } + boolean canMove = !TileCache.containsPoint(snapPoint); + + if (canMove) { + Logger.trace("Moving from tile " + tile.getId() + " from " + tile.xyToString() + " to (" + snapPoint.x + "," + snapPoint.y + ")"); + //Remove the original tile center from the tiles + Tile movingTile = tiles.remove(tp); + if (movingTile != null) { + //Also remove from the alt points + Point oldCenter = movingTile.getCenter(); + Set oldAltPoints = movingTile.getAltPoints(); + //Logger.trace("Removing " + oldAltPoints.size() + " alt tile points"); + for (Point ep : oldAltPoints) { + altTiles.remove(ep); + tiles.remove(ep); + } - //Set the new center position - movingTile.setCenter(snapPoint); - //Check again, needed for tiles which are longer then 1 square, like a block - if (!checkTileOccupation(movingTile)) { - Logger.trace("Moved Tile " + movingTile.getId() + " from " + tp + " to " + snapPoint + "..."); - tiles.put(snapPoint, movingTile); - for (Point ep : movingTile.getAltPoints()) { - altTiles.put(ep, movingTile); - } - } else { - //Do not move Tile, put back where it was - movingTile.setCenter(oldCenter); - tiles.put(oldCenter, movingTile); - for (Point ep : movingTile.getAltPoints()) { - altTiles.put(ep, movingTile); - } + //Set the new center position + movingTile.setCenter(snapPoint); + //Check again, needed for tiles which are longer then 1 square, like a block + if (!checkTileOccupation(movingTile)) { + Logger.trace("Moved Tile " + movingTile.getId() + " from " + tp + " to " + snapPoint + "..."); + tiles.put(snapPoint, movingTile); + for (Point ep : movingTile.getAltPoints()) { + altTiles.put(ep, movingTile); } - - if ("false".equals(System.getProperty("batch.tile.persist", "true"))) { - saveTile(movingTile); + } else { + //Do not move Tile, put back where it was + movingTile.setCenter(oldCenter); + tiles.put(oldCenter, movingTile); + for (Point ep : movingTile.getAltPoints()) { + altTiles.put(ep, movingTile); } } + + saveTile(movingTile); } } + //} } } diff --git a/src/main/java/jcs/ui/layout/tiles/Cross.java b/src/main/java/jcs/ui/layout/tiles/Cross.java index 7b35150e..4777b114 100644 --- a/src/main/java/jcs/ui/layout/tiles/Cross.java +++ b/src/main/java/jcs/ui/layout/tiles/Cross.java @@ -1 +1,668 @@ -/* * Copyright 2023 Frans Jacobs. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package jcs.ui.layout.tiles; import java.awt.BasicStroke; import java.awt.Color; import java.awt.Dimension; import java.awt.Graphics2D; import java.awt.Point; import java.awt.Rectangle; import java.awt.geom.Ellipse2D; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set; import jcs.entities.AccessoryBean.AccessoryValue; import static jcs.entities.AccessoryBean.AccessoryValue.GREEN; import static jcs.entities.AccessoryBean.AccessoryValue.RED; import jcs.entities.TileBean; import jcs.entities.TileBean.Direction; import jcs.entities.TileBean.Orientation; import static jcs.entities.TileBean.Orientation.NORTH; import static jcs.entities.TileBean.Orientation.SOUTH; import static jcs.entities.TileBean.Orientation.WEST; import jcs.entities.TileBean.TileType; import static jcs.ui.layout.tiles.Tile.DEFAULT_HEIGHT; import static jcs.ui.layout.tiles.Tile.DEFAULT_WIDTH; import static jcs.ui.layout.tiles.Tile.GRID; import static jcs.ui.layout.tiles.Tile.tileHeight; import static jcs.ui.layout.tiles.Tile.tileWidth; import org.tinylog.Logger; public class Cross extends Switch { public static final int CROSS_WIDTH = DEFAULT_WIDTH * 2; public static final int CROSS_HEIGHT = DEFAULT_HEIGHT * 2; public static final Color VERY_LIGHT_RED = new Color(255, 102, 102); public static final Color LIGHT_RED = new Color(255, 51, 51); public static final Color DARK_RED = new Color(204, 0, 0); public static final Color VERY_LIGHT_GREEN = new Color(102, 255, 102); public static final Color LIGHT_GREEN = new Color(0, 255, 51); public static final Color DARK_GREEN = new Color(0, 153, 0); public Cross(Orientation orientation, Direction direction, Point center) { this(orientation, direction, center.x, center.y); } public Cross(Orientation orientation, Direction direction, int x, int y) { this(orientation, direction, x, y, tileWidth(orientation, TileType.CROSS), tileHeight(orientation, TileType.CROSS)); } public Cross(Orientation orientation, Direction direction, int x, int y, int width, int height) { super(TileType.CROSS, orientation, direction, x, y, width, height); changeRenderSizeAndOffsets(); } public Cross(TileBean tileBean) { super(tileBean, tileWidth(tileBean.getOrientation(), TileType.CROSS), tileHeight(tileBean.getOrientation(), TileType.CROSS)); changeRenderSizeAndOffsets(); } /** * A Cross has a width in horizontal position of 2 tiles and a height of 1 tile in Vertical position.
* * @return the set of center point which mark the position of the Cross */ @Override public Set getAltPoints() { Set alternatives = new HashSet<>(); switch (getOrientation()) { case SOUTH -> { Point sp = new Point(tileX, (tileY + DEFAULT_HEIGHT)); alternatives.add(sp); } case WEST -> { Point wp = new Point((tileX - DEFAULT_WIDTH), tileY); alternatives.add(wp); } case NORTH -> { Point np = new Point(tileX, (tileY - DEFAULT_HEIGHT)); alternatives.add(np); } default -> { //East so default Point ep = new Point((tileX + DEFAULT_WIDTH), tileY); alternatives.add(ep); } } return alternatives; } @Override public Map getNeighborPoints() { Map neighbors = new HashMap<>(); Orientation orientation = this.getOrientation(); Direction direction = this.getDirection(); int cx = this.getCenterX(); int cy = this.getCenterY(); switch (orientation) { case SOUTH -> { neighbors.put(Orientation.NORTH, new Point(cx, cy - Tile.GRID * 2)); neighbors.put(Orientation.SOUTH, new Point(cx, cy + Tile.GRID * 4)); if (Direction.LEFT == direction) { neighbors.put(Orientation.EAST, new Point(cx + Tile.GRID * 2, cy + Tile.GRID * 2)); neighbors.put(Orientation.WEST, new Point(cx - Tile.GRID * 2, cy)); } else { neighbors.put(Orientation.EAST, new Point(cx + Tile.GRID * 2, cy)); neighbors.put(Orientation.WEST, new Point(cx - Tile.GRID * 2, cy + Tile.GRID * 2)); } } case WEST -> { neighbors.put(Orientation.EAST, new Point(cx + Tile.GRID * 2, cy)); neighbors.put(Orientation.WEST, new Point(cx - Tile.GRID * 4, cy)); if (Direction.LEFT == direction) { neighbors.put(Orientation.NORTH, new Point(cx, cy - Tile.GRID * 2)); neighbors.put(Orientation.SOUTH, new Point(cx - Tile.GRID * 2, cy + Tile.GRID * 2)); } else { neighbors.put(Orientation.NORTH, new Point(cx - Tile.GRID * 2, cy - Tile.GRID * 2)); neighbors.put(Orientation.SOUTH, new Point(cx, cy + Tile.GRID * 2)); } } case NORTH -> { neighbors.put(Orientation.NORTH, new Point(cx, cy - Tile.GRID * 4)); neighbors.put(Orientation.SOUTH, new Point(cx, cy + Tile.GRID * 2)); if (Direction.LEFT == direction) { neighbors.put(Orientation.EAST, new Point(cx + Tile.GRID * 2, cy)); neighbors.put(Orientation.WEST, new Point(cx - Tile.GRID * 2, cy - Tile.GRID * 2)); } else { neighbors.put(Orientation.EAST, new Point(cx + Tile.GRID * 2, cy - Tile.GRID * 2)); neighbors.put(Orientation.WEST, new Point(cx - Tile.GRID * 2, cy)); } } default -> { //EAST neighbors.put(Orientation.EAST, new Point(cx + Tile.GRID * 4, cy)); neighbors.put(Orientation.WEST, new Point(cx - Tile.GRID * 2, cy)); if (Direction.LEFT == direction) { neighbors.put(Orientation.NORTH, new Point(cx + Tile.GRID * 2, cy - Tile.GRID * 2)); neighbors.put(Orientation.SOUTH, new Point(cx, cy + Tile.GRID * 2)); } else { neighbors.put(Orientation.NORTH, new Point(cx, cy - Tile.GRID * 2)); neighbors.put(Orientation.SOUTH, new Point(cx + Tile.GRID * 2, cy + Tile.GRID * 2)); } } } return neighbors; } @Override public Map getEdgePoints() { Map edgeConnections = new HashMap<>(); Orientation orientation = this.getOrientation(); Direction direction = this.getDirection(); int cx = this.getCenterX(); int cy = this.getCenterY(); switch (orientation) { case SOUTH -> { edgeConnections.put(Orientation.NORTH, new Point(cx, cy - Tile.GRID)); edgeConnections.put(Orientation.SOUTH, new Point(cx, cy + Tile.GRID * 3)); if (Direction.LEFT == direction) { edgeConnections.put(Orientation.EAST, new Point(cx + Tile.GRID, cy + Tile.GRID * 2)); edgeConnections.put(Orientation.WEST, new Point(cx - Tile.GRID, cy)); } else { edgeConnections.put(Orientation.EAST, new Point(cx + Tile.GRID, cy)); edgeConnections.put(Orientation.WEST, new Point(cx - Tile.GRID, cy + Tile.GRID * 2)); } } case WEST -> { edgeConnections.put(Orientation.EAST, new Point(cx + Tile.GRID, cy)); edgeConnections.put(Orientation.WEST, new Point(cx - Tile.GRID * 3, cy)); if (Direction.LEFT == direction) { edgeConnections.put(Orientation.NORTH, new Point(cx, cy - Tile.GRID)); edgeConnections.put(Orientation.SOUTH, new Point(cx - Tile.GRID * 2, cy + Tile.GRID)); } else { edgeConnections.put(Orientation.NORTH, new Point(cx - Tile.GRID * 2, cy - Tile.GRID)); edgeConnections.put(Orientation.SOUTH, new Point(cx, cy + Tile.GRID)); } } case NORTH -> { edgeConnections.put(Orientation.NORTH, new Point(cx, cy - Tile.GRID * 3)); edgeConnections.put(Orientation.SOUTH, new Point(cx, cy + Tile.GRID)); if (Direction.LEFT == direction) { edgeConnections.put(Orientation.EAST, new Point(cx + Tile.GRID, cy)); edgeConnections.put(Orientation.WEST, new Point(cx - Tile.GRID, cy - Tile.GRID * 2)); } else { edgeConnections.put(Orientation.EAST, new Point(cx + Tile.GRID, cy - Tile.GRID * 2)); edgeConnections.put(Orientation.WEST, new Point(cx - Tile.GRID, cy)); } } default -> { //EAST edgeConnections.put(Orientation.EAST, new Point(cx + Tile.GRID * 3, cy)); edgeConnections.put(Orientation.WEST, new Point(cx - Tile.GRID, cy)); if (Direction.LEFT == direction) { edgeConnections.put(Orientation.NORTH, new Point(cx + Tile.GRID * 2, cy - Tile.GRID)); edgeConnections.put(Orientation.SOUTH, new Point(cx, cy + Tile.GRID)); } else { edgeConnections.put(Orientation.NORTH, new Point(cx, cy - Tile.GRID)); edgeConnections.put(Orientation.SOUTH, new Point(cx + Tile.GRID * 2, cy + Tile.GRID)); } } } return edgeConnections; } @Override protected void renderStraight(Graphics2D g2, Color color) { int xx, yy, w, h; xx = 0; yy = 170; w = RENDER_WIDTH; h = 60; g2.setStroke(new BasicStroke(4, BasicStroke.JOIN_MITER, BasicStroke.JOIN_ROUND)); g2.setPaint(color); g2.fillRect(xx, yy, w, h); } @Override protected void renderRouteStraight(Graphics2D g2, Color color) { int xx, yy, w, h; xx = 0; yy = 190; w = RENDER_WIDTH; h = 20; g2.setStroke(new BasicStroke(4, BasicStroke.JOIN_MITER, BasicStroke.JOIN_ROUND)); g2.setPaint(color); g2.fillRect(xx, yy, w, h); } protected void renderStraight2(Graphics2D g2, Color color) { int xx, yy, w, h; xx = RENDER_WIDTH; yy = 170; w = RENDER_WIDTH; h = 60; g2.setStroke(new BasicStroke(4, BasicStroke.JOIN_MITER, BasicStroke.JOIN_ROUND)); g2.setPaint(color); g2.fillRect(xx, yy, w, h); } protected void renderRouteStraight2(Graphics2D g2, Color color) { int xx, yy, w, h; xx = RENDER_WIDTH; yy = 190; w = RENDER_WIDTH; h = 20; g2.setStroke(new BasicStroke(4, BasicStroke.JOIN_MITER, BasicStroke.JOIN_ROUND)); g2.setPaint(color); g2.fillRect(xx, yy, w, h); } @Override protected void renderDiagonal(Graphics2D g2, Color color) { int[] xPoints, yPoints; if (Direction.RIGHT.equals(getDirection())) { xPoints = new int[]{400, 400, 167, 230}; yPoints = new int[]{170, 230, 0, 0}; } else { xPoints = new int[]{400, 400, 170, 230}; yPoints = new int[]{230, 170, 400, 400}; } g2.setStroke(new BasicStroke(4, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND)); g2.setPaint(color); g2.fillPolygon(xPoints, yPoints, xPoints.length); } @Override protected void renderRouteDiagonal(Graphics2D g2, Color color) { int[] xPoints, yPoints; if (Direction.RIGHT.equals(getDirection())) { xPoints = new int[]{420, 400, 190, 210}; yPoints = new int[]{210, 210, 0, 0}; } else { xPoints = new int[]{400, 400, 190, 210}; yPoints = new int[]{210, 190, 400, 400}; } g2.setStroke(new BasicStroke(4, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND)); g2.setPaint(color); g2.fillPolygon(xPoints, yPoints, xPoints.length); } protected void renderDiagonal2(Graphics2D g2, Color color) { int[] xPoints, yPoints; if (Direction.RIGHT.equals(getDirection())) { xPoints = new int[]{400, 400, 570, 630}; yPoints = new int[]{170, 230, 400, 400}; } else { xPoints = new int[]{400, 400, 570, 630}; yPoints = new int[]{230, 170, 0, 0}; } g2.setStroke(new BasicStroke(4, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND)); g2.setPaint(color); g2.fillPolygon(xPoints, yPoints, xPoints.length); } protected void renderRouteDiagonal2(Graphics2D g2, Color color) { int[] xPoints, yPoints; if (Direction.RIGHT.equals(getDirection())) { xPoints = new int[]{400, 380, 590, 610}; yPoints = new int[]{190, 190, 400, 400}; } else { xPoints = new int[]{400, 380, 590, 610}; yPoints = new int[]{210, 210, 0, 0}; } g2.setStroke(new BasicStroke(4, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND)); g2.setPaint(color); g2.setPaint(Color.cyan); g2.fillPolygon(xPoints, yPoints, xPoints.length); } @Override public void renderTile(Graphics2D g2) { if (accessoryValue == null) { this.accessoryValue = AccessoryValue.OFF; } switch (accessoryValue) { case RED -> { renderStraight2(g2, Cross.LIGHT_RED); renderDiagonal(g2, Cross.LIGHT_RED); renderStraight(g2, Cross.DARK_RED); renderDiagonal2(g2, Cross.DARK_RED); } case GREEN -> { renderDiagonal(g2, Cross.VERY_LIGHT_GREEN); renderDiagonal2(g2, Cross.VERY_LIGHT_GREEN); renderStraight(g2, Cross.DARK_GREEN); renderStraight2(g2, Cross.DARK_GREEN); } default -> { renderStraight(g2, trackColor); renderStraight2(g2, trackColor); renderDiagonal(g2, trackColor); renderDiagonal2(g2, trackColor); } } } @Override public void renderTileRoute(Graphics2D g2) { if (routeValue == null) { routeValue = AccessoryValue.OFF; } if (incomingSide == null) { incomingSide = getOrientation(); } if (isHorizontal()) { if (AccessoryValue.GREEN == routeValue && (Orientation.NORTH == incomingSide || Orientation.SOUTH == incomingSide)) { renderRouteDiagonal(g2, trackRouteColor); renderRouteDiagonal2(g2, trackRouteColor); } else if (AccessoryValue.GREEN == routeValue && (Orientation.EAST == incomingSide || Orientation.WEST == incomingSide)) { renderRouteStraight(g2, trackRouteColor); renderRouteStraight2(g2, trackRouteColor); } else if (AccessoryValue.RED == routeValue && Orientation.EAST == getOrientation()) { if (Direction.RIGHT == getDirection() && (Orientation.EAST == incomingSide || Orientation.NORTH == incomingSide)) { renderRouteStraight2(g2, trackRouteColor); renderRouteDiagonal(g2, trackRouteColor); } else if (Direction.RIGHT == getDirection() && (Orientation.WEST == incomingSide || Orientation.SOUTH == incomingSide)) { renderRouteDiagonal2(g2, trackRouteColor); renderRouteStraight(g2, trackRouteColor); } else if (Direction.LEFT == getDirection() && (Orientation.EAST == incomingSide || Orientation.SOUTH == incomingSide)) { renderRouteStraight2(g2, trackRouteColor); renderRouteDiagonal(g2, trackRouteColor); } else if (Direction.LEFT == getDirection() && (Orientation.WEST == incomingSide || Orientation.NORTH == incomingSide)) { renderRouteStraight(g2, trackColor); renderRouteDiagonal2(g2, trackColor); } } else if (AccessoryValue.RED == routeValue && Orientation.WEST == getOrientation()) { if (Direction.RIGHT == getDirection() && (Orientation.EAST == incomingSide || Orientation.NORTH == incomingSide)) { renderRouteStraight(g2, trackRouteColor); renderRouteDiagonal2(g2, trackRouteColor); } else if (Direction.RIGHT == getDirection() && (Orientation.WEST == incomingSide || Orientation.SOUTH == incomingSide)) { renderRouteDiagonal(g2, trackRouteColor); renderRouteStraight2(g2, trackRouteColor); } else if (Direction.LEFT == getDirection() && (Orientation.EAST == incomingSide || Orientation.SOUTH == incomingSide)) { renderRouteStraight(g2, trackRouteColor); renderRouteDiagonal2(g2, trackRouteColor); } else if (Direction.LEFT == getDirection() && (Orientation.WEST == incomingSide || Orientation.NORTH == incomingSide)) { renderRouteStraight2(g2, trackColor); renderRouteDiagonal(g2, trackColor); } } } else { if (AccessoryValue.GREEN == routeValue && (Orientation.NORTH == incomingSide || Orientation.SOUTH == incomingSide)) { renderRouteStraight(g2, trackRouteColor); renderRouteStraight2(g2, trackRouteColor); } else if (AccessoryValue.GREEN == routeValue && (Orientation.EAST == incomingSide || Orientation.WEST == incomingSide)) { renderRouteDiagonal(g2, trackRouteColor); renderRouteDiagonal2(g2, trackRouteColor); } else if (AccessoryValue.RED == routeValue && Orientation.SOUTH == getOrientation()) { if (Direction.RIGHT == getDirection() && (Orientation.EAST == incomingSide || Orientation.SOUTH == incomingSide)) { renderRouteStraight2(g2, trackRouteColor); renderRouteDiagonal(g2, trackRouteColor); } else if (Direction.RIGHT == getDirection() && (Orientation.WEST == incomingSide || Orientation.NORTH == incomingSide)) { renderRouteDiagonal2(g2, trackRouteColor); renderRouteStraight(g2, trackRouteColor); } else if (Direction.LEFT == getDirection() && (Orientation.EAST == incomingSide || Orientation.NORTH == incomingSide)) { renderRouteStraight(g2, trackRouteColor); renderRouteDiagonal2(g2, trackRouteColor); } else if (Direction.LEFT == getDirection() && (Orientation.WEST == incomingSide || Orientation.SOUTH == incomingSide)) { renderRouteStraight2(g2, trackColor); renderRouteDiagonal(g2, trackColor); } } else if (AccessoryValue.RED == routeValue && Orientation.NORTH == getOrientation()) { if (Direction.RIGHT == getDirection() && (Orientation.EAST == incomingSide || Orientation.SOUTH == incomingSide)) { renderRouteStraight(g2, trackRouteColor); renderRouteDiagonal2(g2, trackRouteColor); } else if (Direction.RIGHT == getDirection() && (Orientation.WEST == incomingSide || Orientation.NORTH == incomingSide)) { renderRouteDiagonal(g2, trackRouteColor); renderRouteStraight2(g2, trackRouteColor); } else if (Direction.LEFT == getDirection() && (Orientation.EAST == incomingSide || Orientation.NORTH == incomingSide)) { renderRouteStraight2(g2, trackRouteColor); renderRouteDiagonal(g2, trackRouteColor); } else if (Direction.LEFT == getDirection() && (Orientation.WEST == incomingSide || Orientation.SOUTH == incomingSide)) { renderRouteStraight(g2, trackColor); renderRouteDiagonal2(g2, trackColor); } } } } @Override public AccessoryValue accessoryValueForRoute(Orientation from, Orientation to) { if (from != null && to != null && this.getDirection() != null) { switch (this.getDirection()) { case LEFT -> { if (this.isHorizontal()) { if ((from == Orientation.WEST && to == Orientation.EAST) || (from == Orientation.EAST && to == Orientation.WEST)) { return AccessoryValue.GREEN; } else if ((from == Orientation.NORTH && to == Orientation.SOUTH) || (from == Orientation.SOUTH && to == Orientation.NORTH)) { return AccessoryValue.GREEN; } else if ((from == Orientation.NORTH && to == Orientation.WEST) || (from == Orientation.WEST && to == Orientation.NORTH)) { return AccessoryValue.RED; } else if ((from == Orientation.EAST && to == Orientation.SOUTH) || (from == Orientation.SOUTH && to == Orientation.EAST)) { return AccessoryValue.RED; } else { return AccessoryValue.OFF; } } else { //Vertical if ((from == Orientation.WEST && to == Orientation.EAST) || (from == Orientation.EAST && to == Orientation.WEST)) { return AccessoryValue.GREEN; } else if ((from == Orientation.NORTH && to == Orientation.SOUTH) || (from == Orientation.SOUTH && to == Orientation.NORTH)) { return AccessoryValue.GREEN; } else if ((from == Orientation.SOUTH && to == Orientation.WEST) || (from == Orientation.WEST && to == Orientation.SOUTH)) { return AccessoryValue.RED; } else if ((from == Orientation.EAST && to == Orientation.NORTH) || (from == Orientation.NORTH && to == Orientation.EAST)) { return AccessoryValue.RED; } else { return AccessoryValue.OFF; } } } case RIGHT -> { if (this.isHorizontal()) { if ((from == Orientation.WEST && to == Orientation.EAST) || (from == Orientation.EAST && to == Orientation.WEST)) { return AccessoryValue.GREEN; } else if ((from == Orientation.NORTH && to == Orientation.SOUTH) || (from == Orientation.SOUTH && to == Orientation.NORTH)) { return AccessoryValue.GREEN; } else if ((from == Orientation.NORTH && to == Orientation.EAST) || (from == Orientation.EAST && to == Orientation.NORTH)) { return AccessoryValue.RED; } else if ((from == Orientation.WEST && to == Orientation.SOUTH) || (from == Orientation.SOUTH && to == Orientation.WEST)) { return AccessoryValue.RED; } else { return AccessoryValue.OFF; } } else { //Vertical if ((from == Orientation.WEST && to == Orientation.EAST) || (from == Orientation.EAST && to == Orientation.WEST)) { return AccessoryValue.GREEN; } else if ((from == Orientation.NORTH && to == Orientation.SOUTH) || (from == Orientation.SOUTH && to == Orientation.NORTH)) { return AccessoryValue.GREEN; } else if ((from == Orientation.SOUTH && to == Orientation.EAST) || (from == Orientation.EAST && to == Orientation.SOUTH)) { return AccessoryValue.RED; } else if ((from == Orientation.WEST && to == Orientation.NORTH) || (from == Orientation.NORTH && to == Orientation.WEST)) { return AccessoryValue.RED; } else { return AccessoryValue.OFF; } } } default -> { return AccessoryValue.OFF; } } } else { return AccessoryValue.OFF; } } @Override protected void drawCenterPoint(Graphics2D g2d, Color color, double size) { //A Cross has 1 alternate point //1st square holds the centerpoint //2nd square double dX1, dX2, dY1, dY2; Orientation tileOrientation = model.getTileOrienation(); switch (tileOrientation) { case SOUTH -> { dX1 = renderWidth / 2 - size / 2; dY1 = renderHeight / 2 - renderHeight / 4 - size / 2; dX2 = renderWidth / 2 + renderWidth - size / 4; dY2 = renderHeight / 2 - renderHeight / 4 - size / 4; } case WEST -> { dX1 = renderWidth / 2 - renderWidth / 4 - size / 2; dY1 = renderHeight / 2 - size / 2; dX2 = renderWidth / 2 + renderWidth / 4 - size / 4; dY2 = renderHeight / 2 - size / 4; } case NORTH -> { dX1 = renderWidth / 2 - size / 2; dY1 = renderHeight / 2 - renderHeight / 4 - size / 2; dX2 = renderWidth / 2 + renderWidth - size / 4; dY2 = renderHeight / 2 - renderHeight / 4 - size / 4; } default -> { //East dX1 = renderWidth / 2 - renderWidth / 4 - size / 2; dY1 = renderHeight / 2 - size / 2; dX2 = renderWidth / 2 + renderWidth / 4 - size / 4; dY2 = renderHeight / 2 - size / 4; } } g2d.setColor(color); g2d.fill(new Ellipse2D.Double(dX1, dY1, size, size)); g2d.fill(new Ellipse2D.Double(dX2, dY2, size / 2, size / 2)); } @Override public Rectangle getTileBounds() { Orientation tileOrientation = model.getTileOrienation(); int xx, yy, w, h, multiplier; if (model.isScaleImage()) { w = tileWidth(tileOrientation, TileType.CROSS); h = tileHeight(tileOrientation, TileType.CROSS); multiplier = 1; } else { w = renderWidth; h = renderHeight; multiplier = 10; } switch (tileOrientation) { case SOUTH -> { xx = tileX - GRID * multiplier; yy = tileY - GRID * multiplier; } case WEST -> { xx = tileX - GRID * multiplier - GRID * 2 * multiplier; yy = tileY - GRID * multiplier; } case NORTH -> { xx = tileX - GRID * multiplier; yy = tileY - GRID * multiplier - GRID * 2 * multiplier; } default -> { //East xx = tileX - GRID * multiplier; yy = tileY - GRID * multiplier; } } Logger.trace(id + " O: " + tileOrientation + " Cur Cp: " + xyToString() + " New DsP: (" + xx + ", " + yy + ") W: " + w + " H: " + h + " M: " + multiplier + " Ox: " + offsetX + " Oy: " + offsetY); if (model.isScaleImage()) { return new Rectangle(xx, yy, tileWidth(tileOrientation, TileType.CROSS), tileHeight(tileOrientation, TileType.CROSS)); } else { return new Rectangle(xx, yy, renderWidth, renderHeight); } } private void changeRenderSizeAndOffsets() { //Reset offsets this.offsetY = 0; this.renderOffsetY = 0; this.offsetX = 0; this.renderOffsetX = 0; if (isHorizontal()) { //this.width = DEFAULT_WIDTH * 2; //this.height = DEFAULT_HEIGHT; this.renderWidth = RENDER_GRID * 4; this.renderHeight = RENDER_GRID * 2; this.offsetY = 0; this.renderOffsetY = 0; } else { //this.width = DEFAULT_WIDTH; //this.height = DEFAULT_HEIGHT * 2; this.renderWidth = RENDER_GRID * 2; this.renderHeight = RENDER_GRID * 4; this.offsetX = 0; this.renderOffsetX = 0; } //Due to the asymetical shape (center is on the left) //the offset has to be changed with the rotation Orientation tileOrientation = model.getTileOrienation(); switch (tileOrientation) { case SOUTH -> { this.offsetY = +GRID; this.renderOffsetY = RENDER_GRID; } case WEST -> { this.offsetX = -GRID; this.renderOffsetX = -RENDER_GRID; } case NORTH -> { this.offsetY = -GRID; this.renderOffsetY = -RENDER_GRID; } default -> { //East so default this.offsetX = +GRID; this.renderOffsetX = +RENDER_GRID; } } } @Override public Orientation rotate() { super.rotate(); Orientation tileOrientation = model.getTileOrienation(); int w = tileWidth(tileOrientation, TileType.CROSS); int h = tileHeight(tileOrientation, TileType.CROSS); //the centerpoin can shift as a cross is inbalanced int multiplier = (model.isScaleImage() ? 1 : 10); int x, y; switch (tileOrientation) { case SOUTH -> { //the centerpoint remains the same x = tileX; y = tileY; } case WEST -> { // centerpoint shifts to the 2nd square x = tileX; // - GRID * multiplier - GRID * 2 * multiplier; y = tileY; // - GRID * multiplier; } case NORTH -> { x = tileX; // - GRID * multiplier; y = tileY; // - GRID * multiplier - GRID * 2 * multiplier; } default -> { //East x = tileX; y = tileY; } } Dimension d = new Dimension(w, h); setPreferredSize(d); setSize(d); changeRenderSizeAndOffsets(); //set the new center this.tileX = x; this.tileY = y; Logger.trace(id + " O: " + tileOrientation + " Cur Cp: " + xyToString() + " New CP: (" + x + ", " + y + ") W: " + w + " H: " + h + " M: " + multiplier + " Ox: " + offsetX + " Oy: " + offsetY); setBounds(getTileBounds()); return tileOrientation; } } \ No newline at end of file +/* + * Copyright 2023 Frans Jacobs. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package jcs.ui.layout.tiles; + +import java.awt.BasicStroke; +import java.awt.Color; +import java.awt.Dimension; +import java.awt.Graphics2D; +import java.awt.Point; +import java.awt.Rectangle; +import java.awt.geom.Ellipse2D; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; +import jcs.entities.AccessoryBean.AccessoryValue; +import static jcs.entities.AccessoryBean.AccessoryValue.GREEN; +import static jcs.entities.AccessoryBean.AccessoryValue.RED; +import jcs.entities.TileBean; +import jcs.entities.TileBean.Direction; +import jcs.entities.TileBean.Orientation; +import static jcs.entities.TileBean.Orientation.NORTH; +import static jcs.entities.TileBean.Orientation.SOUTH; +import static jcs.entities.TileBean.Orientation.WEST; +import jcs.entities.TileBean.TileType; +import static jcs.ui.layout.tiles.Tile.DEFAULT_HEIGHT; +import static jcs.ui.layout.tiles.Tile.DEFAULT_WIDTH; +import static jcs.ui.layout.tiles.Tile.GRID; +import static jcs.ui.layout.tiles.Tile.tileHeight; +import static jcs.ui.layout.tiles.Tile.tileWidth; + +public class Cross extends Switch { + + public static final int CROSS_WIDTH = DEFAULT_WIDTH * 2; + public static final int CROSS_HEIGHT = DEFAULT_HEIGHT * 2; + + public static final Color VERY_LIGHT_RED = new Color(255, 102, 102); + public static final Color LIGHT_RED = new Color(255, 51, 51); + public static final Color DARK_RED = new Color(204, 0, 0); + + public static final Color VERY_LIGHT_GREEN = new Color(102, 255, 102); + public static final Color LIGHT_GREEN = new Color(0, 255, 51); + public static final Color DARK_GREEN = new Color(0, 153, 0); + + public Cross(Orientation orientation, Direction direction, Point center) { + this(orientation, direction, center.x, center.y); + } + + public Cross(Orientation orientation, Direction direction, int x, int y) { + this(orientation, direction, x, y, tileWidth(orientation, TileType.CROSS), tileHeight(orientation, TileType.CROSS)); + } + + public Cross(Orientation orientation, Direction direction, int x, int y, int width, int height) { + super(TileType.CROSS, orientation, direction, x, y, width, height); + changeRenderSizeAndOffsets(); + } + + public Cross(TileBean tileBean) { + super(tileBean, tileWidth(tileBean.getOrientation(), TileType.CROSS), tileHeight(tileBean.getOrientation(), TileType.CROSS)); + changeRenderSizeAndOffsets(); + } + + /** + * A Cross has a width in horizontal position of 2 tiles and a height of 1 tile in Vertical position.
+ * + * @return the set of center point which mark the position of the Cross + */ + @Override + public Set getAltPoints() { + Set alternatives = new HashSet<>(); + + switch (getOrientation()) { + case SOUTH -> { + Point sp = new Point(tileX, (tileY + DEFAULT_HEIGHT)); + alternatives.add(sp); + } + case WEST -> { + Point wp = new Point((tileX - DEFAULT_WIDTH), tileY); + alternatives.add(wp); + } + case NORTH -> { + Point np = new Point(tileX, (tileY - DEFAULT_HEIGHT)); + alternatives.add(np); + } + default -> { + //East so default + Point ep = new Point((tileX + DEFAULT_WIDTH), tileY); + alternatives.add(ep); + } + } + return alternatives; + } + + @Override + public Map getNeighborPoints() { + Map neighbors = new HashMap<>(); + Orientation orientation = this.getOrientation(); + Direction direction = this.getDirection(); + int cx = this.getCenterX(); + int cy = this.getCenterY(); + + switch (orientation) { + case SOUTH -> { + neighbors.put(Orientation.NORTH, new Point(cx, cy - Tile.GRID * 2)); + neighbors.put(Orientation.SOUTH, new Point(cx, cy + Tile.GRID * 4)); + + if (Direction.LEFT == direction) { + neighbors.put(Orientation.EAST, new Point(cx + Tile.GRID * 2, cy + Tile.GRID * 2)); + neighbors.put(Orientation.WEST, new Point(cx - Tile.GRID * 2, cy)); + } else { + neighbors.put(Orientation.EAST, new Point(cx + Tile.GRID * 2, cy)); + neighbors.put(Orientation.WEST, new Point(cx - Tile.GRID * 2, cy + Tile.GRID * 2)); + } + } + case WEST -> { + neighbors.put(Orientation.EAST, new Point(cx + Tile.GRID * 2, cy)); + neighbors.put(Orientation.WEST, new Point(cx - Tile.GRID * 4, cy)); + + if (Direction.LEFT == direction) { + neighbors.put(Orientation.NORTH, new Point(cx, cy - Tile.GRID * 2)); + neighbors.put(Orientation.SOUTH, new Point(cx - Tile.GRID * 2, cy + Tile.GRID * 2)); + } else { + neighbors.put(Orientation.NORTH, new Point(cx - Tile.GRID * 2, cy - Tile.GRID * 2)); + neighbors.put(Orientation.SOUTH, new Point(cx, cy + Tile.GRID * 2)); + } + } + case NORTH -> { + neighbors.put(Orientation.NORTH, new Point(cx, cy - Tile.GRID * 4)); + neighbors.put(Orientation.SOUTH, new Point(cx, cy + Tile.GRID * 2)); + + if (Direction.LEFT == direction) { + neighbors.put(Orientation.EAST, new Point(cx + Tile.GRID * 2, cy)); + neighbors.put(Orientation.WEST, new Point(cx - Tile.GRID * 2, cy - Tile.GRID * 2)); + } else { + neighbors.put(Orientation.EAST, new Point(cx + Tile.GRID * 2, cy - Tile.GRID * 2)); + neighbors.put(Orientation.WEST, new Point(cx - Tile.GRID * 2, cy)); + } + } + default -> { + //EAST + neighbors.put(Orientation.EAST, new Point(cx + Tile.GRID * 4, cy)); + neighbors.put(Orientation.WEST, new Point(cx - Tile.GRID * 2, cy)); + + if (Direction.LEFT == direction) { + neighbors.put(Orientation.NORTH, new Point(cx + Tile.GRID * 2, cy - Tile.GRID * 2)); + neighbors.put(Orientation.SOUTH, new Point(cx, cy + Tile.GRID * 2)); + } else { + neighbors.put(Orientation.NORTH, new Point(cx, cy - Tile.GRID * 2)); + neighbors.put(Orientation.SOUTH, new Point(cx + Tile.GRID * 2, cy + Tile.GRID * 2)); + } + } + } + return neighbors; + } + + @Override + public Map getEdgePoints() { + Map edgeConnections = new HashMap<>(); + Orientation orientation = this.getOrientation(); + Direction direction = this.getDirection(); + int cx = this.getCenterX(); + int cy = this.getCenterY(); + + switch (orientation) { + case SOUTH -> { + edgeConnections.put(Orientation.NORTH, new Point(cx, cy - Tile.GRID)); + edgeConnections.put(Orientation.SOUTH, new Point(cx, cy + Tile.GRID * 3)); + + if (Direction.LEFT == direction) { + edgeConnections.put(Orientation.EAST, new Point(cx + Tile.GRID, cy + Tile.GRID * 2)); + edgeConnections.put(Orientation.WEST, new Point(cx - Tile.GRID, cy)); + } else { + edgeConnections.put(Orientation.EAST, new Point(cx + Tile.GRID, cy)); + edgeConnections.put(Orientation.WEST, new Point(cx - Tile.GRID, cy + Tile.GRID * 2)); + } + } + case WEST -> { + edgeConnections.put(Orientation.EAST, new Point(cx + Tile.GRID, cy)); + edgeConnections.put(Orientation.WEST, new Point(cx - Tile.GRID * 3, cy)); + + if (Direction.LEFT == direction) { + edgeConnections.put(Orientation.NORTH, new Point(cx, cy - Tile.GRID)); + edgeConnections.put(Orientation.SOUTH, new Point(cx - Tile.GRID * 2, cy + Tile.GRID)); + } else { + edgeConnections.put(Orientation.NORTH, new Point(cx - Tile.GRID * 2, cy - Tile.GRID)); + edgeConnections.put(Orientation.SOUTH, new Point(cx, cy + Tile.GRID)); + } + } + case NORTH -> { + edgeConnections.put(Orientation.NORTH, new Point(cx, cy - Tile.GRID * 3)); + edgeConnections.put(Orientation.SOUTH, new Point(cx, cy + Tile.GRID)); + + if (Direction.LEFT == direction) { + edgeConnections.put(Orientation.EAST, new Point(cx + Tile.GRID, cy)); + edgeConnections.put(Orientation.WEST, new Point(cx - Tile.GRID, cy - Tile.GRID * 2)); + } else { + edgeConnections.put(Orientation.EAST, new Point(cx + Tile.GRID, cy - Tile.GRID * 2)); + edgeConnections.put(Orientation.WEST, new Point(cx - Tile.GRID, cy)); + } + } + default -> { + //EAST + edgeConnections.put(Orientation.EAST, new Point(cx + Tile.GRID * 3, cy)); + edgeConnections.put(Orientation.WEST, new Point(cx - Tile.GRID, cy)); + + if (Direction.LEFT == direction) { + edgeConnections.put(Orientation.NORTH, new Point(cx + Tile.GRID * 2, cy - Tile.GRID)); + edgeConnections.put(Orientation.SOUTH, new Point(cx, cy + Tile.GRID)); + } else { + edgeConnections.put(Orientation.NORTH, new Point(cx, cy - Tile.GRID)); + edgeConnections.put(Orientation.SOUTH, new Point(cx + Tile.GRID * 2, cy + Tile.GRID)); + } + } + } + return edgeConnections; + } + + @Override + protected void renderStraight(Graphics2D g2, Color color) { + int xx, yy, w, h; + xx = 0; + yy = 170; + w = RENDER_WIDTH; + h = 60; + + g2.setStroke(new BasicStroke(4, BasicStroke.JOIN_MITER, BasicStroke.JOIN_ROUND)); + g2.setPaint(color); + g2.fillRect(xx, yy, w, h); + } + + @Override + protected void renderRouteStraight(Graphics2D g2, Color color) { + int xx, yy, w, h; + xx = 0; + yy = 190; + w = RENDER_WIDTH; + h = 20; + + g2.setStroke(new BasicStroke(4, BasicStroke.JOIN_MITER, BasicStroke.JOIN_ROUND)); + g2.setPaint(color); + g2.fillRect(xx, yy, w, h); + } + + protected void renderStraight2(Graphics2D g2, Color color) { + int xx, yy, w, h; + xx = RENDER_WIDTH; + yy = 170; + w = RENDER_WIDTH; + h = 60; + + g2.setStroke(new BasicStroke(4, BasicStroke.JOIN_MITER, BasicStroke.JOIN_ROUND)); + g2.setPaint(color); + g2.fillRect(xx, yy, w, h); + } + + protected void renderRouteStraight2(Graphics2D g2, Color color) { + int xx, yy, w, h; + xx = RENDER_WIDTH; + yy = 190; + w = RENDER_WIDTH; + h = 20; + + g2.setStroke(new BasicStroke(4, BasicStroke.JOIN_MITER, BasicStroke.JOIN_ROUND)); + g2.setPaint(color); + g2.fillRect(xx, yy, w, h); + } + + @Override + protected void renderDiagonal(Graphics2D g2, Color color) { + int[] xPoints, yPoints; + if (Direction.RIGHT.equals(getDirection())) { + xPoints = new int[]{400, 400, 167, 230}; + yPoints = new int[]{170, 230, 0, 0}; + } else { + xPoints = new int[]{400, 400, 170, 230}; + yPoints = new int[]{230, 170, 400, 400}; + } + + g2.setStroke(new BasicStroke(4, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND)); + g2.setPaint(color); + g2.fillPolygon(xPoints, yPoints, xPoints.length); + } + + @Override + protected void renderRouteDiagonal(Graphics2D g2, Color color) { + int[] xPoints, yPoints; + if (Direction.RIGHT.equals(getDirection())) { + xPoints = new int[]{420, 400, 190, 210}; + yPoints = new int[]{210, 210, 0, 0}; + } else { + xPoints = new int[]{400, 400, 190, 210}; + yPoints = new int[]{210, 190, 400, 400}; + } + + g2.setStroke(new BasicStroke(4, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND)); + g2.setPaint(color); + g2.fillPolygon(xPoints, yPoints, xPoints.length); + } + + protected void renderDiagonal2(Graphics2D g2, Color color) { + int[] xPoints, yPoints; + if (Direction.RIGHT.equals(getDirection())) { + xPoints = new int[]{400, 400, 570, 630}; + yPoints = new int[]{170, 230, 400, 400}; + } else { + xPoints = new int[]{400, 400, 570, 630}; + yPoints = new int[]{230, 170, 0, 0}; + } + + g2.setStroke(new BasicStroke(4, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND)); + g2.setPaint(color); + g2.fillPolygon(xPoints, yPoints, xPoints.length); + } + + protected void renderRouteDiagonal2(Graphics2D g2, Color color) { + int[] xPoints, yPoints; + if (Direction.RIGHT.equals(getDirection())) { + xPoints = new int[]{400, 380, 590, 610}; + yPoints = new int[]{190, 190, 400, 400}; + } else { + xPoints = new int[]{400, 380, 590, 610}; + yPoints = new int[]{210, 210, 0, 0}; + } + + g2.setStroke(new BasicStroke(4, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND)); + g2.setPaint(color); + g2.setPaint(Color.cyan); + g2.fillPolygon(xPoints, yPoints, xPoints.length); + } + + @Override + public void renderTile(Graphics2D g2) { + if (accessoryValue == null) { + this.accessoryValue = AccessoryValue.OFF; + } + + switch (accessoryValue) { + case RED -> { + renderStraight2(g2, Cross.LIGHT_RED); + renderDiagonal(g2, Cross.LIGHT_RED); + renderStraight(g2, Cross.DARK_RED); + renderDiagonal2(g2, Cross.DARK_RED); + } + case GREEN -> { + renderDiagonal(g2, Cross.VERY_LIGHT_GREEN); + renderDiagonal2(g2, Cross.VERY_LIGHT_GREEN); + renderStraight(g2, Cross.DARK_GREEN); + renderStraight2(g2, Cross.DARK_GREEN); + } + default -> { + renderStraight(g2, trackColor); + renderStraight2(g2, trackColor); + renderDiagonal(g2, trackColor); + renderDiagonal2(g2, trackColor); + } + } + } + + @Override + public void renderTileRoute(Graphics2D g2) { + if (routeValue == null) { + routeValue = AccessoryValue.OFF; + } + if (incomingSide == null) { + incomingSide = getOrientation(); + } + + if (isHorizontal()) { + if (AccessoryValue.GREEN == routeValue && (Orientation.NORTH == incomingSide || Orientation.SOUTH == incomingSide)) { + renderRouteDiagonal(g2, trackRouteColor); + renderRouteDiagonal2(g2, trackRouteColor); + } else if (AccessoryValue.GREEN == routeValue && (Orientation.EAST == incomingSide || Orientation.WEST == incomingSide)) { + renderRouteStraight(g2, trackRouteColor); + renderRouteStraight2(g2, trackRouteColor); + } else if (AccessoryValue.RED == routeValue && Orientation.EAST == getOrientation()) { + if (Direction.RIGHT == getDirection() && (Orientation.EAST == incomingSide || Orientation.NORTH == incomingSide)) { + renderRouteStraight2(g2, trackRouteColor); + renderRouteDiagonal(g2, trackRouteColor); + } else if (Direction.RIGHT == getDirection() && (Orientation.WEST == incomingSide || Orientation.SOUTH == incomingSide)) { + renderRouteDiagonal2(g2, trackRouteColor); + renderRouteStraight(g2, trackRouteColor); + } else if (Direction.LEFT == getDirection() && (Orientation.EAST == incomingSide || Orientation.SOUTH == incomingSide)) { + renderRouteStraight2(g2, trackRouteColor); + renderRouteDiagonal(g2, trackRouteColor); + } else if (Direction.LEFT == getDirection() && (Orientation.WEST == incomingSide || Orientation.NORTH == incomingSide)) { + renderRouteStraight(g2, trackColor); + renderRouteDiagonal2(g2, trackColor); + } + } else if (AccessoryValue.RED == routeValue && Orientation.WEST == getOrientation()) { + if (Direction.RIGHT == getDirection() && (Orientation.EAST == incomingSide || Orientation.NORTH == incomingSide)) { + renderRouteStraight(g2, trackRouteColor); + renderRouteDiagonal2(g2, trackRouteColor); + } else if (Direction.RIGHT == getDirection() && (Orientation.WEST == incomingSide || Orientation.SOUTH == incomingSide)) { + renderRouteDiagonal(g2, trackRouteColor); + renderRouteStraight2(g2, trackRouteColor); + } else if (Direction.LEFT == getDirection() && (Orientation.EAST == incomingSide || Orientation.SOUTH == incomingSide)) { + renderRouteStraight(g2, trackRouteColor); + renderRouteDiagonal2(g2, trackRouteColor); + } else if (Direction.LEFT == getDirection() && (Orientation.WEST == incomingSide || Orientation.NORTH == incomingSide)) { + renderRouteStraight2(g2, trackColor); + renderRouteDiagonal(g2, trackColor); + } + } + } else { + if (AccessoryValue.GREEN == routeValue && (Orientation.NORTH == incomingSide || Orientation.SOUTH == incomingSide)) { + renderRouteStraight(g2, trackRouteColor); + renderRouteStraight2(g2, trackRouteColor); + } else if (AccessoryValue.GREEN == routeValue && (Orientation.EAST == incomingSide || Orientation.WEST == incomingSide)) { + renderRouteDiagonal(g2, trackRouteColor); + renderRouteDiagonal2(g2, trackRouteColor); + } else if (AccessoryValue.RED == routeValue && Orientation.SOUTH == getOrientation()) { + if (Direction.RIGHT == getDirection() && (Orientation.EAST == incomingSide || Orientation.SOUTH == incomingSide)) { + renderRouteStraight2(g2, trackRouteColor); + renderRouteDiagonal(g2, trackRouteColor); + } else if (Direction.RIGHT == getDirection() && (Orientation.WEST == incomingSide || Orientation.NORTH == incomingSide)) { + renderRouteDiagonal2(g2, trackRouteColor); + renderRouteStraight(g2, trackRouteColor); + } else if (Direction.LEFT == getDirection() && (Orientation.EAST == incomingSide || Orientation.NORTH == incomingSide)) { + renderRouteStraight(g2, trackRouteColor); + renderRouteDiagonal2(g2, trackRouteColor); + } else if (Direction.LEFT == getDirection() && (Orientation.WEST == incomingSide || Orientation.SOUTH == incomingSide)) { + renderRouteStraight2(g2, trackColor); + renderRouteDiagonal(g2, trackColor); + } + } else if (AccessoryValue.RED == routeValue && Orientation.NORTH == getOrientation()) { + if (Direction.RIGHT == getDirection() && (Orientation.EAST == incomingSide || Orientation.SOUTH == incomingSide)) { + renderRouteStraight(g2, trackRouteColor); + renderRouteDiagonal2(g2, trackRouteColor); + } else if (Direction.RIGHT == getDirection() && (Orientation.WEST == incomingSide || Orientation.NORTH == incomingSide)) { + renderRouteDiagonal(g2, trackRouteColor); + renderRouteStraight2(g2, trackRouteColor); + } else if (Direction.LEFT == getDirection() && (Orientation.EAST == incomingSide || Orientation.NORTH == incomingSide)) { + renderRouteStraight2(g2, trackRouteColor); + renderRouteDiagonal(g2, trackRouteColor); + } else if (Direction.LEFT == getDirection() && (Orientation.WEST == incomingSide || Orientation.SOUTH == incomingSide)) { + renderRouteStraight(g2, trackColor); + renderRouteDiagonal2(g2, trackColor); + } + } + } + } + + @Override + public AccessoryValue accessoryValueForRoute(Orientation from, Orientation to) { + if (from != null && to != null && this.getDirection() != null) { + switch (this.getDirection()) { + case LEFT -> { + if (this.isHorizontal()) { + if ((from == Orientation.WEST && to == Orientation.EAST) || (from == Orientation.EAST && to == Orientation.WEST)) { + return AccessoryValue.GREEN; + } else if ((from == Orientation.NORTH && to == Orientation.SOUTH) || (from == Orientation.SOUTH && to == Orientation.NORTH)) { + return AccessoryValue.GREEN; + } else if ((from == Orientation.NORTH && to == Orientation.WEST) || (from == Orientation.WEST && to == Orientation.NORTH)) { + return AccessoryValue.RED; + } else if ((from == Orientation.EAST && to == Orientation.SOUTH) || (from == Orientation.SOUTH && to == Orientation.EAST)) { + return AccessoryValue.RED; + } else { + return AccessoryValue.OFF; + } + } else { + //Vertical + if ((from == Orientation.WEST && to == Orientation.EAST) || (from == Orientation.EAST && to == Orientation.WEST)) { + return AccessoryValue.GREEN; + } else if ((from == Orientation.NORTH && to == Orientation.SOUTH) || (from == Orientation.SOUTH && to == Orientation.NORTH)) { + return AccessoryValue.GREEN; + } else if ((from == Orientation.SOUTH && to == Orientation.WEST) || (from == Orientation.WEST && to == Orientation.SOUTH)) { + return AccessoryValue.RED; + } else if ((from == Orientation.EAST && to == Orientation.NORTH) || (from == Orientation.NORTH && to == Orientation.EAST)) { + return AccessoryValue.RED; + } else { + return AccessoryValue.OFF; + } + } + } + case RIGHT -> { + if (this.isHorizontal()) { + if ((from == Orientation.WEST && to == Orientation.EAST) || (from == Orientation.EAST && to == Orientation.WEST)) { + return AccessoryValue.GREEN; + } else if ((from == Orientation.NORTH && to == Orientation.SOUTH) || (from == Orientation.SOUTH && to == Orientation.NORTH)) { + return AccessoryValue.GREEN; + } else if ((from == Orientation.NORTH && to == Orientation.EAST) || (from == Orientation.EAST && to == Orientation.NORTH)) { + return AccessoryValue.RED; + } else if ((from == Orientation.WEST && to == Orientation.SOUTH) || (from == Orientation.SOUTH && to == Orientation.WEST)) { + return AccessoryValue.RED; + } else { + return AccessoryValue.OFF; + } + } else { + //Vertical + if ((from == Orientation.WEST && to == Orientation.EAST) || (from == Orientation.EAST && to == Orientation.WEST)) { + return AccessoryValue.GREEN; + } else if ((from == Orientation.NORTH && to == Orientation.SOUTH) || (from == Orientation.SOUTH && to == Orientation.NORTH)) { + return AccessoryValue.GREEN; + } else if ((from == Orientation.SOUTH && to == Orientation.EAST) || (from == Orientation.EAST && to == Orientation.SOUTH)) { + return AccessoryValue.RED; + } else if ((from == Orientation.WEST && to == Orientation.NORTH) || (from == Orientation.NORTH && to == Orientation.WEST)) { + return AccessoryValue.RED; + } else { + return AccessoryValue.OFF; + } + } + } + default -> { + return AccessoryValue.OFF; + } + } + } else { + return AccessoryValue.OFF; + } + } + + @Override + protected void drawCenterPoint(Graphics2D g2d, Color color, double size) { + //A Cross has 1 alternate point + //1st square holds the centerpoint + //2nd square + double dX1, dX2, dY1, dY2; + Orientation tileOrientation = model.getTileOrienation(); + switch (tileOrientation) { + case SOUTH -> { + dX1 = renderWidth / 2 - size / 2; + dY1 = renderHeight / 2 - renderHeight / 4 - size / 2; + dX2 = renderWidth / 2 + renderWidth - size / 4; + dY2 = renderHeight / 2 - renderHeight / 4 - size / 4; + } + case WEST -> { + dX1 = renderWidth / 2 - renderWidth / 4 - size / 2; + dY1 = renderHeight / 2 - size / 2; + dX2 = renderWidth / 2 + renderWidth / 4 - size / 4; + dY2 = renderHeight / 2 - size / 4; + } + case NORTH -> { + dX1 = renderWidth / 2 - size / 2; + dY1 = renderHeight / 2 - renderHeight / 4 - size / 2; + dX2 = renderWidth / 2 + renderWidth - size / 4; + dY2 = renderHeight / 2 - renderHeight / 4 - size / 4; + } + default -> { + //East + dX1 = renderWidth / 2 - renderWidth / 4 - size / 2; + dY1 = renderHeight / 2 - size / 2; + dX2 = renderWidth / 2 + renderWidth / 4 - size / 4; + dY2 = renderHeight / 2 - size / 4; + } + } + + g2d.setColor(color); + g2d.fill(new Ellipse2D.Double(dX1, dY1, size, size)); + g2d.fill(new Ellipse2D.Double(dX2, dY2, size / 2, size / 2)); + } + + @Override + public Rectangle getTileBounds() { + Orientation tileOrientation = model.getTileOrienation(); + int xx, yy, w, h, multiplier; + if (model.isScaleImage()) { + w = tileWidth(tileOrientation, TileType.CROSS); + h = tileHeight(tileOrientation, TileType.CROSS); + multiplier = 1; + } else { + w = renderWidth; + h = renderHeight; + multiplier = 10; + } + + switch (tileOrientation) { + case SOUTH -> { + xx = tileX - GRID * multiplier; + yy = tileY - GRID * multiplier; + } + case WEST -> { + xx = tileX - GRID * multiplier - GRID * 2 * multiplier; + yy = tileY - GRID * multiplier; + } + case NORTH -> { + xx = tileX - GRID * multiplier; + yy = tileY - GRID * multiplier - GRID * 2 * multiplier; + } + default -> { + //East + xx = tileX - GRID * multiplier; + yy = tileY - GRID * multiplier; + } + } + + if (model.isScaleImage()) { + return new Rectangle(xx, yy, tileWidth(tileOrientation, TileType.CROSS), tileHeight(tileOrientation, TileType.CROSS)); + } else { + return new Rectangle(xx, yy, renderWidth, renderHeight); + } + } + + private void changeRenderSizeAndOffsets() { + //Reset offsets + this.offsetY = 0; + this.renderOffsetY = 0; + this.offsetX = 0; + this.renderOffsetX = 0; + + if (isHorizontal()) { + this.renderWidth = RENDER_GRID * 4; + this.renderHeight = RENDER_GRID * 2; + + this.offsetY = 0; + this.renderOffsetY = 0; + } else { + this.renderWidth = RENDER_GRID * 2; + this.renderHeight = RENDER_GRID * 4; + + this.offsetX = 0; + this.renderOffsetX = 0; + } + + //Due to the asymetical shape (center is on the left) + //the offset has to be changed with the rotation + Orientation tileOrientation = model.getTileOrienation(); + switch (tileOrientation) { + case SOUTH -> { + this.offsetY = +GRID; + this.renderOffsetY = RENDER_GRID; + } + case WEST -> { + this.offsetX = -GRID; + this.renderOffsetX = -RENDER_GRID; + } + case NORTH -> { + this.offsetY = -GRID; + this.renderOffsetY = -RENDER_GRID; + } + default -> { + //East so default + this.offsetX = +GRID; + this.renderOffsetX = +RENDER_GRID; + } + } + } + + @Override + public Orientation rotate() { + super.rotate(); + + Orientation tileOrientation = model.getTileOrienation(); + int w = tileWidth(tileOrientation, TileType.CROSS); + int h = tileHeight(tileOrientation, TileType.CROSS); + + Dimension d = new Dimension(w, h); + setPreferredSize(d); + setSize(d); + changeRenderSizeAndOffsets(); + + setBounds(getTileBounds()); + return tileOrientation; + } + +} diff --git a/src/main/java/jcs/ui/layout/tiles/DefaultTileModel.java b/src/main/java/jcs/ui/layout/tiles/DefaultTileModel.java index 6663ee90..d9e99fd9 100644 --- a/src/main/java/jcs/ui/layout/tiles/DefaultTileModel.java +++ b/src/main/java/jcs/ui/layout/tiles/DefaultTileModel.java @@ -15,6 +15,7 @@ */ package jcs.ui.layout.tiles; +import java.awt.Color; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.ItemListener; @@ -40,6 +41,7 @@ public class DefaultTileModel implements TileModel { protected EventListenerList listenerList = new EventListenerList(); protected boolean selected = false; + protected Color selectedColor; protected boolean scaleImage = true; protected boolean showCenter = false; protected Orientation tileOrienation; @@ -64,6 +66,7 @@ public DefaultTileModel() { public DefaultTileModel(Orientation orientation) { this.tileOrienation = orientation; + this.selectedColor = Tile.DEFAULT_SELECTED_COLOR; } @Override @@ -77,6 +80,25 @@ public void setSelected(boolean selected) { fireStateChanged(); } + @Override + public Color getSelectedColor() { + return selectedColor; + } + + @Override + public void setSelectedColor(Color selectedColor) { + Color prevColor = selectedColor; + if (selectedColor != null) { + this.selectedColor = selectedColor; + } else { + this.selectedColor = Tile.DEFAULT_SELECTED_COLOR; + } + + if (!this.selectedColor.equals(prevColor)) { + fireStateChanged(); + } + } + @Override public boolean isScaleImage() { return scaleImage; diff --git a/src/main/java/jcs/ui/layout/tiles/Tile.java b/src/main/java/jcs/ui/layout/tiles/Tile.java index dfd1939e..f22ea4f7 100755 --- a/src/main/java/jcs/ui/layout/tiles/Tile.java +++ b/src/main/java/jcs/ui/layout/tiles/Tile.java @@ -1 +1,1133 @@ -/* * Copyright 2024 Frans Jacobs. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package jcs.ui.layout.tiles; import java.awt.Color; import java.awt.Dimension; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.Point; import java.awt.Rectangle; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.geom.AffineTransform; import java.awt.geom.Ellipse2D; import java.awt.image.AffineTransformOp; import java.awt.image.BufferedImage; import java.beans.PropertyChangeListener; import java.io.Serializable; import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Set; import javax.swing.JComponent; import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; import jcs.entities.AccessoryBean; import jcs.entities.AccessoryBean.AccessoryValue; import jcs.entities.AccessoryBean.SignalType; import jcs.entities.BlockBean; import jcs.entities.BlockBean.BlockState; import jcs.entities.LocomotiveBean; import jcs.entities.SensorBean; import jcs.entities.TileBean; import jcs.entities.TileBean.Direction; import jcs.entities.TileBean.Orientation; import jcs.entities.TileBean.TileType; import jcs.ui.layout.LayoutUtil; import static jcs.ui.layout.tiles.Block.BLOCK_HEIGHT; import static jcs.ui.layout.tiles.Block.BLOCK_WIDTH; import org.imgscalr.Scalr; import org.imgscalr.Scalr.Method; import org.imgscalr.Scalr.Mode; import org.tinylog.Logger; /** * Basic graphic element to display a track, turnout, etc on the screen.
* By default the drawing of a Tile is Horizontal from L to R or West to East.
* The default orientation is East. * *

* The default size of a Tile is 40 tileX 40 pixels.
* The center point of a Tile is stored and always snapped to the nearest grid point.
* The basic grid is 20x 20 pixels.
* *

* A Tile can be rotated (always clockwise).
* Rotation will change the orientation from East -> South -> West -> North -> East.
* *

* A Tile is rendered to a Buffered Image to speed up the display */ public abstract class Tile extends JComponent { //implements TileEventListener { //, ItemSelectable { public static final int GRID = 20; public static final int DEFAULT_WIDTH = GRID * 2; public static final int DEFAULT_HEIGHT = GRID * 2; static final int RENDER_GRID = GRID * 10; static final int RENDER_WIDTH = RENDER_GRID * 2; static final int RENDER_HEIGHT = RENDER_GRID * 2; public static final Color DEFAULT_BACKGROUND_COLOR = Color.white; public static final Color DEFAULT_TRACK_COLOR = Color.lightGray; public static final Color DEFAULT_ROUTE_TRACK_COLOR = Color.blue; public static final Color DEFAULT_SELECTED_COLOR = Color.yellow; public static final String MODEL_CHANGED_PROPERTY = "model"; public static final String CONTENT_AREA_FILLED_CHANGED_PROPERTY = "contentAreaFilled"; /** * The data model that determines the button's state. */ protected TileModel model = null; protected String id; protected Integer tileX; protected Integer tileY; protected int renderWidth; protected int renderHeight; //protected Orientation tileOrientation; protected Direction tileDirection; protected TileType tileType; protected String accessoryId; protected String sensorId; protected AccessoryValue accessoryValue; protected AccessoryValue routeValue; protected SignalType signalType; protected AccessoryBean.SignalValue signalValue; protected TileBean tileBean; protected AccessoryBean accessoryBean; protected SensorBean sensorBean; protected BlockBean blockBean; protected List neighbours; protected int offsetX = 0; protected int offsetY = 0; protected int renderOffsetX = 0; protected int renderOffsetY = 0; protected Color selectedColor; protected Color trackColor; protected Color trackRouteColor; protected Orientation incomingSide; protected Color backgroundColor; protected boolean drawName = true; protected BufferedImage tileImage; protected PropertyChangeListener propertyChangeListener; protected ChangeListener changeListener = null; protected ActionListener actionListener = null; protected transient ChangeEvent changeEvent; private Handler handler; protected Tile(TileType tileType, Orientation orientation, Point center, int width, int height) { this(tileType, orientation, Direction.CENTER, center.x, center.y, width, height); } protected Tile(TileType tileType, Orientation orientation, int x, int y, int width, int height) { this(tileType, orientation, Direction.CENTER, x, y, width, height); } protected Tile(TileType tileType, Orientation orientation, Direction direction, int x, int y, int width, int height) { this(tileType, orientation, direction, x, y, width, height, null, null); } protected Tile(TileType tileType, Orientation orientation, Direction direction, int x, int y, int width, int height, Color backgroundColor, Color selectedColor) { this.tileType = tileType; //this.tileOrientation = orientation; //model.setTileOrienation(orientation); this.tileDirection = direction; this.tileX = x; this.tileY = y; setLayout(null); Dimension d = new Dimension(width, height); setSize(d); setPreferredSize(d); this.renderWidth = RENDER_WIDTH; this.renderHeight = RENDER_HEIGHT; this.trackColor = DEFAULT_TRACK_COLOR; this.backgroundColor = backgroundColor; this.selectedColor = selectedColor; if (this.backgroundColor == null) { this.backgroundColor = DEFAULT_BACKGROUND_COLOR; } if (this.selectedColor == null) { this.selectedColor = DEFAULT_SELECTED_COLOR; } } protected Tile(TileBean tileBean) { this(tileBean, tileWidth(tileBean.getOrientation(), tileBean.getTileType()), tileHeight(tileBean.getOrientation(), tileBean.getTileType())); } protected Tile(TileBean tileBean, int width, int height) { this.tileBean = tileBean; //Quick properties this.id = tileBean.getId(); this.tileType = tileBean.getTileType(); //this.tileOrientation = tileBean.getOrientation(); //this.model.setTileOrienation(tileBean.getOrientation()); this.tileDirection = tileBean.getDirection(); this.tileX = tileBean.getX(); this.tileY = tileBean.getY(); this.accessoryId = tileBean.getAccessoryId(); this.accessoryBean = tileBean.getAccessoryBean(); this.signalType = tileBean.getSignalType(); this.sensorId = tileBean.getSensorId(); this.sensorBean = tileBean.getSensorBean(); this.blockBean = tileBean.getBlockBean(); setLayout(null); Dimension d = new Dimension(width, height); setSize(d); setPreferredSize(d); this.trackColor = DEFAULT_TRACK_COLOR; this.backgroundColor = DEFAULT_BACKGROUND_COLOR; this.selectedColor = DEFAULT_SELECTED_COLOR; this.renderWidth = RENDER_WIDTH; this.renderHeight = RENDER_HEIGHT; } protected static int tileWidth(Orientation orientation, TileType tileType) { if (Orientation.EAST == orientation || Orientation.WEST == orientation) { if (null == tileType) { return DEFAULT_WIDTH; } else { return switch (tileType) { case BLOCK -> BLOCK_WIDTH; case CROSS -> DEFAULT_WIDTH * 2; default -> DEFAULT_WIDTH; }; } } else { return DEFAULT_WIDTH; } } protected static int tileHeight(Orientation orientation, TileType tileType) { if (Orientation.EAST == orientation || Orientation.WEST == orientation) { return DEFAULT_HEIGHT; } else { if (null == tileType) { return DEFAULT_HEIGHT; } else { return switch (tileType) { case BLOCK -> BLOCK_HEIGHT; case CROSS -> DEFAULT_HEIGHT * 2; default -> DEFAULT_HEIGHT; }; } } } protected void populateModel() { if (this.blockBean != null) { this.model.setBlockState(this.blockBean.getBlockState()); this.model.setLocomotive(this.blockBean.getLocomotive()); this.model.setArrivalSuffix(this.blockBean.getArrivalSuffix()); this.model.setLogicalDirection(LocomotiveBean.Direction.get(this.blockBean.getLogicalDirection())); } } public TileBean getTileBean() { if (tileBean == null) { tileBean = new TileBean(); tileBean.setId(this.id); tileBean.setX(this.tileX); tileBean.setY(this.tileY); tileBean.setTileType(this.tileType); //tileBean.setTileOrientation(this.tileOrientation.getOrientation()); tileBean.setTileOrientation(this.model.getTileOrienation().getOrientation()); tileBean.setTileDirection(this.tileDirection.getDirection()); tileBean.setSignalType(this.signalType); tileBean.setAccessoryId(this.accessoryId); tileBean.setSensorId(this.sensorId); tileBean.setAccessoryBean(this.accessoryBean); tileBean.setSensorBean(this.sensorBean); tileBean.setBlockBean(this.blockBean); } return tileBean; } public boolean isSelected() { return model.isSelected(); } public void setSelected(boolean b) { //boolean oldValue = isSelected(); model.setSelected(b); } public String getId() { return id; } public void setId(String id) { this.id = id; } public SignalType getSignalType() { return signalType; } public void setSignalType(SignalType signalType) { this.signalType = signalType; } public Integer getTileX() { return tileX; } public Integer getTileY() { return tileY; } public Point getCenter() { return new Point(this.tileX, this.tileY); } public void setCenter(Point center) { tileX = center.x; tileY = center.y; if (tileBean != null) { tileBean.setCenter(center); } Logger.trace(id + " Cp: " + xyToString()); } public Orientation getOrientation() { //return tileOrientation; return model.getTileOrienation(); } public void setOrientation(Orientation orientation) { //this.tileOrientation = orientation; model.setTileOrienation(orientation); if (tileBean != null) { tileBean.setOrientation(orientation); } } public Direction getDirection() { return tileDirection; } public void setDirection(Direction direction) { this.tileDirection = direction; if (tileBean != null) { tileBean.setDirection(direction); } } public String getAccessoryId() { return accessoryId; } public void setAccessoryId(String accessoryId) { this.accessoryId = accessoryId; if (tileBean != null) { tileBean.setAccessoryId(accessoryId); } } public String getSensorId() { return sensorId; } public void setSensorId(String sensorId) { this.sensorId = sensorId; } public boolean isActive() { return model.isSensorActive(); } public void setActive(boolean active) { model.setSensorActive(active); } public BlockState getBlockState() { return model.getBlockState(); } public void setBlockState(BlockState blockState) { if (blockBean != null) { blockBean.setBlockState(blockState); LocomotiveBean locomotive = model.getLocomotive(); model.setOverlayImage(locomotive != null && locomotive.getLocIcon() != null && (blockState == BlockState.OCCUPIED || blockState == BlockState.INBOUND || blockState == BlockState.OUTBOUND)); } model.setBlockState(blockState); } public String getDepartureSuffix() { return model.getDepartureSuffix(); } public void setDepartureSuffix(String suffix) { if (blockBean != null) { blockBean.setDepartureSuffix(suffix); } model.setDepartureSuffix(suffix); } public boolean isReverseArrival() { return model.isReverseArrival(); } public void setReverseArrival(boolean reverseArrival) { if (blockBean != null) { blockBean.setReverseArrival(reverseArrival); } model.setReverseArrival(reverseArrival); } public LocomotiveBean.Direction getLogicalDirection() { return model.getLogicalDirection(); } public void setLogicalDirection(LocomotiveBean.Direction logicalDirection) { if (blockBean != null) { blockBean.setLogicalDirection(logicalDirection.getDirection()); } model.setLogicalDirection(logicalDirection); } public LocomotiveBean getLocomotive() { return model.getLocomotive(); } public void setLocomotive(LocomotiveBean locomotive) { if (blockBean != null) { blockBean.setLocomotive(locomotive); model.setOverlayImage(locomotive != null && locomotive.getLocIcon() != null && (model.getBlockState() == BlockState.OCCUPIED || model.getBlockState() == BlockState.INBOUND || model.getBlockState() == BlockState.OUTBOUND)); } model.setLocomotive(locomotive); } public AccessoryBean getAccessoryBean() { return accessoryBean; } public void setAccessoryBean(AccessoryBean accessoryBean) { this.accessoryBean = accessoryBean; if (accessoryBean != null) { accessoryId = accessoryBean.getId(); signalValue = accessoryBean.getSignalValue(); signalType = SignalType.getSignalType(accessoryBean.getType()); } else { accessoryId = null; signalType = SignalType.NONE; signalValue = AccessoryBean.SignalValue.OFF; } } public AccessoryValue getAccessoryValue() { if (this.accessoryValue == null) { return AccessoryValue.OFF; } else { return accessoryValue; } } public void setAccessoryValue(AccessoryValue value) { this.accessoryValue = value; repaint(); } public AccessoryValue getRouteValue() { if (routeValue == null) { return AccessoryValue.OFF; } else { return routeValue; } } public void setRouteValue(AccessoryValue value) { this.routeValue = value; repaint(); } public AccessoryBean.SignalValue getSignalValue() { return signalValue; } public void setSignalValue(AccessoryBean.SignalValue signalValue) { this.signalValue = signalValue; repaint(); } public SensorBean getSensorBean() { return sensorBean; } public void setSensorBean(SensorBean sensorBean) { this.sensorBean = sensorBean; } public BlockBean getBlockBean() { return blockBean; } public void setBlockBean(BlockBean blockBean) { this.blockBean = blockBean; } public void setRenderWidth(int renderWidth) { this.renderWidth = renderWidth; } public void setRenderHeight(int renderHeight) { this.renderHeight = renderHeight; } public int getRenderOffsetX() { return renderOffsetX; } public void setRenderOffsetX(int renderOffsetX) { this.renderOffsetX = renderOffsetX; } public int getRenderOffsetY() { return renderOffsetY; } public void setRenderOffsetY(int renderOffsetY) { this.renderOffsetY = renderOffsetY; } public TileBean.TileType getTileType() { return this.tileType; } public final void setTileType(TileType tileType) { this.tileType = tileType; } public Color getTrackColor() { return trackColor; } public final void setTrackColor(Color trackColor) { this.trackColor = trackColor; } public Color getTrackRouteColor() { return trackRouteColor; } public void setTrackRouteColor(Color trackRouteColor) { this.trackRouteColor = trackRouteColor; } public Color getSelectedColor() { return selectedColor; } public void setSelectedColor(Color selectedColor) { this.selectedColor = selectedColor; } public Orientation getIncomingSide() { return incomingSide; } public void setIncomingSide(Orientation incomingSide) { this.incomingSide = incomingSide; } public Color getBackgroundColor() { return backgroundColor; } public void setBackgroundColor(Color backgroundColor) { this.backgroundColor = backgroundColor; } public boolean isDrawRoute() { return model.isShowRoute(); } public void setDrawRoute(boolean drawRoute) { this.model.setShowRoute(drawRoute); } public int getRenderWidth() { return renderWidth; } public int getRenderHeight() { return renderHeight; } abstract void renderTile(Graphics2D g2d); abstract void renderTileRoute(Graphics2D g2d); public abstract Map getNeighborPoints(); public abstract Map getEdgePoints(); public abstract Set getAllPoints(); /** * Draw the Tile * * @param g2d The graphics handle */ public void drawTile(Graphics2D g2d) { // by default and image is rendered in the EAST orientation Orientation tileOrientation = model.getTileOrienation(); // if (tileOrientation == null) { // tileOrientation = Orientation.EAST; // } BufferedImage bf = createImage(); Graphics2D g2di = bf.createGraphics(); //Avoid errors if (model.isShowRoute() && incomingSide == null) { incomingSide = getOrientation(); } if (model.isSelected()) { g2di.setBackground(selectedColor); } else { g2di.setBackground(backgroundColor); } g2di.clearRect(0, 0, renderWidth, renderHeight); int ox = 0, oy = 0; AffineTransform trans = new AffineTransform(); switch (tileOrientation) { case SOUTH -> { trans.rotate(Math.PI / 2, renderWidth / 2, renderHeight / 2); ox = (renderHeight - renderWidth) / 2; oy = (renderWidth - renderHeight) / 2; trans.translate(-ox, -oy); } case WEST -> { trans.rotate(Math.PI, renderWidth / 2, renderHeight / 2); trans.translate(ox, oy); } case NORTH -> { trans.rotate(-Math.PI / 2, renderWidth / 2, renderHeight / 2); ox = (renderHeight - renderWidth) / 2; oy = (renderWidth - renderHeight) / 2; trans.translate(-ox, -oy); } default -> { trans.rotate(0.0, this.renderWidth / 2, this.renderHeight / 2); trans.translate(ox, oy); } } //Logger.trace(tileOrientation.getOrientation() + " renderWidth: " + renderWidth + " renderHeight: " + renderHeight + " CP: (" + renderWidth / 2 + "," + renderHeight / 2 + ")"); //Logger.trace(tileOrientation.getOrientation() + " ox: " + ox + " oy: " + oy); g2di.setTransform(trans); renderTile(g2di); if (model.isShowRoute()) { renderTileRoute(g2di); } if (model.isShowCenter()) { drawCenterPoint(g2di); } // Scale the image back... if (model.isScaleImage()) { tileImage = Scalr.resize(bf, Method.AUTOMATIC, Mode.FIT_EXACT, getWidth(), getHeight(), Scalr.OP_ANTIALIAS); } else { tileImage = bf; } g2di.dispose(); Logger.trace(id + " Cp: " + xyToString()); } public BufferedImage getTileImage() { return tileImage; } /** * Render a tile image Always starts at (0,0) used the default width and height * * @param g2 the Graphic context */ public void drawName(Graphics2D g2) { } protected void drawCenterPoint(Graphics2D g2d) { drawCenterPoint(g2d, Color.magenta); } protected void drawCenterPoint(Graphics2D g2, Color color) { drawCenterPoint(g2, color, 60); } protected void drawCenterPoint(Graphics2D g2d, Color color, double size) { double dX = (renderWidth / 2 - size / 2); double dY = (renderHeight / 2 - size / 2); g2d.setColor(color); g2d.fill(new Ellipse2D.Double(dX, dY, size, size)); } /** * Rotate the tile clockwise 90 deg * * @return the new Orientation */ public Orientation rotate() { Orientation tileOrientation = model.getTileOrienation(); switch (tileOrientation) { case EAST -> setOrientation(Orientation.SOUTH); case SOUTH -> setOrientation(Orientation.WEST); case WEST -> setOrientation(Orientation.NORTH); default -> setOrientation(Orientation.EAST); } return model.getTileOrienation(); } public void flipHorizontal() { Orientation tileOrientation = model.getTileOrienation(); if (Orientation.NORTH == tileOrientation || Orientation.SOUTH == tileOrientation) { rotate(); rotate(); } } public void flipVertical() { Orientation tileOrientation = model.getTileOrienation(); if (Orientation.EAST == tileOrientation || Orientation.WEST == tileOrientation) { rotate(); rotate(); } } @Override public void move(int newX, int newY) { Point cs = LayoutUtil.snapToGrid(newX, newY); setCenter(cs); } protected static void drawRotate(Graphics2D g2d, double x, double y, int angle, String text) { g2d.translate((float) x, (float) y); g2d.rotate(Math.toRadians(angle)); g2d.drawString(text, 0, 0); g2d.rotate(-Math.toRadians(angle)); g2d.translate(-x, -y); } public static BufferedImage flipHorizontally(BufferedImage source) { BufferedImage output = new BufferedImage(source.getHeight(), source.getWidth(), source.getType()); AffineTransform flip = AffineTransform.getScaleInstance(1, -1); flip.translate(0, -source.getHeight()); AffineTransformOp op = new AffineTransformOp(flip, AffineTransformOp.TYPE_NEAREST_NEIGHBOR); op.filter(source, output); return output; } public static BufferedImage flipVertically(BufferedImage source) { BufferedImage output = new BufferedImage(source.getHeight(), source.getWidth(), source.getType()); AffineTransform flip = AffineTransform.getScaleInstance(-1, 1); flip.translate(-source.getWidth(), 0); AffineTransformOp op = new AffineTransformOp(flip, AffineTransformOp.TYPE_NEAREST_NEIGHBOR); op.filter(source, output); return output; } public Set getAltPoints() { return Collections.EMPTY_SET; } public final int getOffsetX() { return offsetX; } public void setOffsetX(int offsetX) { this.offsetX = offsetX; } public final int getOffsetY() { return offsetY; } public void setOffsetY(int offsetY) { this.offsetY = offsetY; } protected BufferedImage createImage() { return new BufferedImage(renderWidth, renderHeight, BufferedImage.TYPE_INT_RGB); } public int getCenterX() { if (tileX > 0) { return this.tileX; } else { return GRID; } } public int getCenterY() { if (tileY > 0) { return this.tileY; } else { return GRID; } } public boolean isDrawName() { return drawName; } public void setDrawName(boolean drawName) { this.drawName = drawName; } public boolean isScaleImage() { return model.isScaleImage(); } public void setScaleImage(boolean scaleImage) { Dimension d; if (scaleImage) { d = new Dimension(DEFAULT_WIDTH, DEFAULT_HEIGHT); } else { d = new Dimension(renderWidth, renderHeight); } setSize(d); setPreferredSize(d); model.setScaleImage(scaleImage); } public boolean isDrawCenterPoint() { return model.isShowCenter(); } public void setDrawCenterPoint(boolean drawCenterPoint) { model.setShowCenter(drawCenterPoint); } @Override public String toString() { return this.getClass().getSimpleName() + " {id: " + this.id + ", orientation: " + getOrientation() + ", direction: " + getDirection() + ", center: " + xyToString() + "}"; } public String xyToString() { return "(" + this.tileX + "," + this.tileY + ")"; } /** * The main route of the tile is horizontal * * @return true when main route goes from East to West or vv */ public boolean isHorizontal() { Orientation tileOrientation = model.getTileOrienation(); return (Orientation.EAST == tileOrientation || Orientation.WEST == tileOrientation) && TileType.CURVED != tileType; } /** * The main route of the tile is vertical * * @return true when main route goes from North to South or vv */ public boolean isVertical() { Orientation tileOrientation = model.getTileOrienation(); return (Orientation.NORTH == tileOrientation || Orientation.SOUTH == tileOrientation) && TileType.CURVED != tileType; } public boolean isJunction() { return TileType.SWITCH == tileType || TileType.CROSS == tileType; } public boolean isBlock() { return TileType.BLOCK == tileType; } public boolean isDirectional() { return TileType.STRAIGHT_DIR == tileType; } /** * The main route of the tile is diagonal * * @return true when main route goes from North to East or West to South and vv */ public boolean isDiagonal() { return TileType.CURVED == tileType; } public boolean isCrossing() { return TileType.CROSSING == tileType; } public List getNeighbours() { return neighbours; } public void setNeighbours(List neighbours) { this.neighbours = neighbours; } public String getIdSuffix(Tile other) { return ""; } public Map getNeighborOrientations() { Map edgeOrientations = new HashMap<>(); Map neighborPoints = getNeighborPoints(); for (Orientation o : Orientation.values()) { edgeOrientations.put(neighborPoints.get(o), o); } return edgeOrientations; } public Map getEdgeOrientations() { Map edgeOrientations = new HashMap<>(); Map edgeConnections = getEdgePoints(); for (Orientation o : Orientation.values()) { edgeOrientations.put(edgeConnections.get(o), o); } return edgeOrientations; } public boolean isAdjacent(Tile other) { boolean adjacent = false; if (other != null) { Collection thisEdgePoints = getEdgePoints().values(); Collection otherEdgePoints = other.getEdgePoints().values(); for (Point p : thisEdgePoints) { adjacent = otherEdgePoints.contains(p); if (adjacent) { break; } } } return adjacent; } /** * When the tile has a specific direction a train may travel,
* then this method will indicate whether the other tile is in on the side where the arrow is pointing to. * * @param other A Tile * @return true where other is on the side of this tile where the arrow points to */ public boolean isArrowDirection(Tile other) { return true; } public AccessoryValue accessoryValueForRoute(Orientation from, Orientation to) { return AccessoryValue.OFF; } public TileModel getModel() { return model; } public void setModel(TileModel newModel) { TileModel oldModel = getModel(); if (oldModel != null) { oldModel.removeChangeListener(changeListener); oldModel.removeActionListener(actionListener); changeListener = null; actionListener = null; } model = newModel; if (newModel != null) { changeListener = createChangeListener(); actionListener = createActionListener(); newModel.addChangeListener(changeListener); newModel.addActionListener(actionListener); } firePropertyChange(MODEL_CHANGED_PROPERTY, oldModel, newModel); if (newModel != oldModel) { revalidate(); repaint(); } } // public TileUI getUI() { // return (TileUI) ui; // } // public void setUI(TileUI ui) { // super.setUI(ui); // } @Override public void updateUI() { } protected ChangeListener createChangeListener() { return getHandler(); } protected ActionListener createActionListener() { return getHandler(); } private Handler getHandler() { if (handler == null) { handler = new Handler(); } return handler; } class Handler implements ActionListener, ChangeListener, Serializable { @Override public void stateChanged(ChangeEvent e) { //Object source = e.getSource(); fireStateChanged(); repaint(); } @Override public void actionPerformed(ActionEvent event) { fireActionPerformed(event); } } protected void fireStateChanged() { Object[] listeners = listenerList.getListenerList(); //reverse order for (int i = listeners.length - 2; i >= 0; i -= 2) { if (listeners[i] == ChangeListener.class) { // Lazily create the event: if (changeEvent == null) { changeEvent = new ChangeEvent(this); } ((ChangeListener) listeners[i + 1]).stateChanged(changeEvent); } } } protected void fireActionPerformed(ActionEvent event) { Object[] listeners = listenerList.getListenerList(); ActionEvent e = null; // reverse for (int i = listeners.length - 2; i >= 0; i -= 2) { if (listeners[i] == ActionListener.class) { // Lazily create the event: if (e == null) { String actionCommand = event.getActionCommand(); //if(actionCommand == null) { // actionCommand = getActionCommand(); //} e = new ActionEvent(Tile.this, ActionEvent.ACTION_PERFORMED, actionCommand, event.getWhen(), event.getModifiers()); } ((ActionListener) listeners[i + 1]).actionPerformed(e); } } } public Rectangle getTileBounds() { if (model.isScaleImage()) { return new Rectangle(tileX - GRID, tileY - GRID, DEFAULT_WIDTH, DEFAULT_HEIGHT); } else { return new Rectangle(tileX - renderWidth / 2, tileY - renderHeight / 2, renderWidth, renderHeight); } } @Override protected void paintComponent(Graphics g) { long started = System.currentTimeMillis(); Graphics2D g2 = (Graphics2D) g.create(); //Graphics2D g2 = (Graphics2D) g.create(tileX - GRID, tileY - GRID, DEFAULT_WIDTH, DEFAULT_HEIGHT); drawTile(g2); g2.dispose(); g.drawImage(tileImage, 0, 0, null); long now = System.currentTimeMillis(); Logger.trace(id + " Duration: " + (now - started) + " ms. Cp: " + xyToString() + " O: " + model.getTileOrienation()); } } \ No newline at end of file +/* + * Copyright 2024 Frans Jacobs. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package jcs.ui.layout.tiles; + +import java.awt.Color; +import java.awt.Dimension; +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.Point; +import java.awt.Rectangle; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.geom.AffineTransform; +import java.awt.geom.Ellipse2D; +import java.awt.image.AffineTransformOp; +import java.awt.image.BufferedImage; +import java.beans.PropertyChangeListener; +import java.io.Serializable; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; +import javax.swing.JComponent; +import javax.swing.event.ChangeEvent; +import javax.swing.event.ChangeListener; +import jcs.entities.AccessoryBean; +import jcs.entities.AccessoryBean.AccessoryValue; +import jcs.entities.AccessoryBean.SignalType; +import jcs.entities.BlockBean; +import jcs.entities.BlockBean.BlockState; +import jcs.entities.LocomotiveBean; +import jcs.entities.SensorBean; +import jcs.entities.TileBean; +import jcs.entities.TileBean.Direction; +import jcs.entities.TileBean.Orientation; +import jcs.entities.TileBean.TileType; +import jcs.ui.layout.LayoutUtil; +import static jcs.ui.layout.tiles.Block.BLOCK_HEIGHT; +import static jcs.ui.layout.tiles.Block.BLOCK_WIDTH; +import org.imgscalr.Scalr; +import org.imgscalr.Scalr.Method; +import org.imgscalr.Scalr.Mode; +import org.tinylog.Logger; + +/** + * Basic graphic element to display a track, turnout, etc on the screen.
+ * By default the drawing of a Tile is Horizontal from L to R or West to East.
+ * The default orientation is East. + * + *

+ * The default size of a Tile is 40 tileX 40 pixels.
+ * The center point of a Tile is stored and always snapped to the nearest grid point.
+ * The basic grid is 20x 20 pixels.
+ * + *

+ * A Tile can be rotated (always clockwise).
+ * Rotation will change the orientation from East -> South -> West -> North -> East.
+ * + *

+ * A Tile is rendered to a Buffered Image to speed up the display + */ +public abstract class Tile extends JComponent { //implements TileEventListener { //, ItemSelectable { + + public static final int GRID = 20; + public static final int DEFAULT_WIDTH = GRID * 2; + public static final int DEFAULT_HEIGHT = GRID * 2; + + static final int RENDER_GRID = GRID * 10; + static final int RENDER_WIDTH = RENDER_GRID * 2; + static final int RENDER_HEIGHT = RENDER_GRID * 2; + + public static final Color DEFAULT_BACKGROUND_COLOR = Color.white; + public static final Color DEFAULT_TRACK_COLOR = Color.lightGray; + public static final Color DEFAULT_ROUTE_TRACK_COLOR = Color.blue; + public static final Color DEFAULT_SELECTED_COLOR = Color.orange; + public static final Color DEFAULT_WARN_COLOR = Color.red; + + public static final String MODEL_CHANGED_PROPERTY = "model"; + public static final String CONTENT_AREA_FILLED_CHANGED_PROPERTY = "contentAreaFilled"; + + /** + * The data model that determines the button's state. + */ + protected TileModel model = null; + + protected String id; + protected Integer tileX; + protected Integer tileY; + + protected int renderWidth; + protected int renderHeight; + + //protected Orientation tileOrientation; + protected Direction tileDirection; + + protected TileType tileType; + protected String accessoryId; + protected String sensorId; + + protected AccessoryValue accessoryValue; + protected AccessoryValue routeValue; + + protected SignalType signalType; + protected AccessoryBean.SignalValue signalValue; + + protected TileBean tileBean; + protected AccessoryBean accessoryBean; + protected SensorBean sensorBean; + protected BlockBean blockBean; + + protected List neighbours; + + protected int offsetX = 0; + protected int offsetY = 0; + + protected int renderOffsetX = 0; + protected int renderOffsetY = 0; + + //protected Color selectedColor; + protected Color trackColor; + protected Color trackRouteColor; + protected Orientation incomingSide; + + protected Color backgroundColor; + protected boolean drawName = true; + + protected BufferedImage tileImage; + + protected PropertyChangeListener propertyChangeListener; + + protected ChangeListener changeListener = null; + protected ActionListener actionListener = null; + + protected transient ChangeEvent changeEvent; + + private Handler handler; + + protected Tile(TileType tileType, Orientation orientation, Point center, int width, int height) { + this(tileType, orientation, Direction.CENTER, center.x, center.y, width, height); + } + + protected Tile(TileType tileType, Orientation orientation, int x, int y, int width, int height) { + this(tileType, orientation, Direction.CENTER, x, y, width, height); + } + + protected Tile(TileType tileType, Orientation orientation, Direction direction, int x, int y, int width, int height) { + this(tileType, orientation, direction, x, y, width, height, null, null); + } + + protected Tile(TileType tileType, Orientation orientation, Direction direction, int x, int y, int width, int height, Color backgroundColor, Color selectedColor) { + this.tileType = tileType; + //this.tileOrientation = orientation; + //model.setTileOrienation(orientation); + this.tileDirection = direction; + this.tileX = x; + this.tileY = y; + + setLayout(null); + Dimension d = new Dimension(width, height); + setSize(d); + setPreferredSize(d); + + this.renderWidth = RENDER_WIDTH; + this.renderHeight = RENDER_HEIGHT; + + this.trackColor = DEFAULT_TRACK_COLOR; + this.backgroundColor = backgroundColor; + //this.selectedColor = selectedColor; + + if (this.backgroundColor == null) { + this.backgroundColor = DEFAULT_BACKGROUND_COLOR; + } +// if (this.selectedColor == null) { +// this.selectedColor = DEFAULT_SELECTED_COLOR; +// } + } + + protected Tile(TileBean tileBean) { + this(tileBean, tileWidth(tileBean.getOrientation(), tileBean.getTileType()), tileHeight(tileBean.getOrientation(), tileBean.getTileType())); + } + + protected Tile(TileBean tileBean, int width, int height) { + this.tileBean = tileBean; + //Quick properties + this.id = tileBean.getId(); + this.tileType = tileBean.getTileType(); + //this.tileOrientation = tileBean.getOrientation(); + //this.model.setTileOrienation(tileBean.getOrientation()); + this.tileDirection = tileBean.getDirection(); + this.tileX = tileBean.getX(); + this.tileY = tileBean.getY(); + + this.accessoryId = tileBean.getAccessoryId(); + this.accessoryBean = tileBean.getAccessoryBean(); + this.signalType = tileBean.getSignalType(); + + this.sensorId = tileBean.getSensorId(); + this.sensorBean = tileBean.getSensorBean(); + this.blockBean = tileBean.getBlockBean(); + + setLayout(null); + Dimension d = new Dimension(width, height); + setSize(d); + setPreferredSize(d); + + this.trackColor = DEFAULT_TRACK_COLOR; + this.backgroundColor = DEFAULT_BACKGROUND_COLOR; +// this.selectedColor = DEFAULT_SELECTED_COLOR; + this.renderWidth = RENDER_WIDTH; + this.renderHeight = RENDER_HEIGHT; + } + + protected static int tileWidth(Orientation orientation, TileType tileType) { + if (Orientation.EAST == orientation || Orientation.WEST == orientation) { + if (null == tileType) { + return DEFAULT_WIDTH; + } else { + return switch (tileType) { + case BLOCK -> + BLOCK_WIDTH; + case CROSS -> + DEFAULT_WIDTH * 2; + default -> + DEFAULT_WIDTH; + }; + } + } else { + return DEFAULT_WIDTH; + } + } + + protected static int tileHeight(Orientation orientation, TileType tileType) { + if (Orientation.EAST == orientation || Orientation.WEST == orientation) { + return DEFAULT_HEIGHT; + } else { + if (null == tileType) { + return DEFAULT_HEIGHT; + } else { + return switch (tileType) { + case BLOCK -> + BLOCK_HEIGHT; + case CROSS -> + DEFAULT_HEIGHT * 2; + default -> + DEFAULT_HEIGHT; + }; + } + } + } + + protected void populateModel() { + if (this.blockBean != null) { + this.model.setBlockState(this.blockBean.getBlockState()); + this.model.setLocomotive(this.blockBean.getLocomotive()); + this.model.setArrivalSuffix(this.blockBean.getArrivalSuffix()); + this.model.setLogicalDirection(LocomotiveBean.Direction.get(this.blockBean.getLogicalDirection())); + } + } + + public TileBean getTileBean() { + if (tileBean == null) { + tileBean = new TileBean(); + tileBean.setId(this.id); + tileBean.setX(this.tileX); + tileBean.setY(this.tileY); + tileBean.setTileType(this.tileType); + //tileBean.setTileOrientation(this.tileOrientation.getOrientation()); + tileBean.setTileOrientation(this.model.getTileOrienation().getOrientation()); + + tileBean.setTileDirection(this.tileDirection.getDirection()); + tileBean.setSignalType(this.signalType); + tileBean.setAccessoryId(this.accessoryId); + tileBean.setSensorId(this.sensorId); + tileBean.setAccessoryBean(this.accessoryBean); + tileBean.setSensorBean(this.sensorBean); + tileBean.setBlockBean(this.blockBean); + } + return tileBean; + } + + public boolean isSelected() { + return model.isSelected(); + } + + public void setSelected(boolean b) { + //boolean oldValue = isSelected(); + model.setSelected(b); + } + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public SignalType getSignalType() { + return signalType; + } + + public void setSignalType(SignalType signalType) { + this.signalType = signalType; + } + + public Integer getTileX() { + return tileX; + } + + public Integer getTileY() { + return tileY; + } + + public Point getCenter() { + return new Point(this.tileX, this.tileY); + } + + public void setCenter(Point center) { + tileX = center.x; + tileY = center.y; + if (tileBean != null) { + tileBean.setCenter(center); + } + Logger.trace(id + " Cp: " + xyToString()); + } + + public Orientation getOrientation() { + //return tileOrientation; + return model.getTileOrienation(); + } + + public void setOrientation(Orientation orientation) { + //this.tileOrientation = orientation; + model.setTileOrienation(orientation); + if (tileBean != null) { + tileBean.setOrientation(orientation); + } + } + + public Direction getDirection() { + return tileDirection; + } + + public void setDirection(Direction direction) { + this.tileDirection = direction; + if (tileBean != null) { + tileBean.setDirection(direction); + } + } + + public String getAccessoryId() { + return accessoryId; + } + + public void setAccessoryId(String accessoryId) { + this.accessoryId = accessoryId; + if (tileBean != null) { + tileBean.setAccessoryId(accessoryId); + } + } + + public String getSensorId() { + return sensorId; + } + + public void setSensorId(String sensorId) { + this.sensorId = sensorId; + } + + public boolean isActive() { + return model.isSensorActive(); + } + + public void setActive(boolean active) { + model.setSensorActive(active); + } + + public BlockState getBlockState() { + return model.getBlockState(); + } + + public void setBlockState(BlockState blockState) { + if (blockBean != null) { + blockBean.setBlockState(blockState); + LocomotiveBean locomotive = model.getLocomotive(); + model.setOverlayImage(locomotive != null && locomotive.getLocIcon() != null && (blockState == BlockState.OCCUPIED || blockState == BlockState.INBOUND || blockState == BlockState.OUTBOUND)); + } + model.setBlockState(blockState); + } + + public String getDepartureSuffix() { + return model.getDepartureSuffix(); + } + + public void setDepartureSuffix(String suffix) { + if (blockBean != null) { + blockBean.setDepartureSuffix(suffix); + } + model.setDepartureSuffix(suffix); + } + + public boolean isReverseArrival() { + return model.isReverseArrival(); + } + + public void setReverseArrival(boolean reverseArrival) { + if (blockBean != null) { + blockBean.setReverseArrival(reverseArrival); + } + model.setReverseArrival(reverseArrival); + } + + public LocomotiveBean.Direction getLogicalDirection() { + return model.getLogicalDirection(); + } + + public void setLogicalDirection(LocomotiveBean.Direction logicalDirection) { + if (blockBean != null) { + blockBean.setLogicalDirection(logicalDirection.getDirection()); + } + model.setLogicalDirection(logicalDirection); + } + + public LocomotiveBean getLocomotive() { + return model.getLocomotive(); + } + + public void setLocomotive(LocomotiveBean locomotive) { + if (blockBean != null) { + blockBean.setLocomotive(locomotive); + model.setOverlayImage(locomotive != null && locomotive.getLocIcon() != null && (model.getBlockState() == BlockState.OCCUPIED || model.getBlockState() == BlockState.INBOUND || model.getBlockState() == BlockState.OUTBOUND)); + } + + model.setLocomotive(locomotive); + } + + public AccessoryBean getAccessoryBean() { + return accessoryBean; + } + + public void setAccessoryBean(AccessoryBean accessoryBean) { + this.accessoryBean = accessoryBean; + + if (accessoryBean != null) { + accessoryId = accessoryBean.getId(); + signalValue = accessoryBean.getSignalValue(); + signalType = SignalType.getSignalType(accessoryBean.getType()); + } else { + accessoryId = null; + signalType = SignalType.NONE; + signalValue = AccessoryBean.SignalValue.OFF; + } + } + + public AccessoryValue getAccessoryValue() { + if (this.accessoryValue == null) { + return AccessoryValue.OFF; + } else { + return accessoryValue; + } + } + + public void setAccessoryValue(AccessoryValue value) { + this.accessoryValue = value; + repaint(); + } + + public AccessoryValue getRouteValue() { + if (routeValue == null) { + return AccessoryValue.OFF; + } else { + return routeValue; + } + } + + public void setRouteValue(AccessoryValue value) { + this.routeValue = value; + repaint(); + } + + public AccessoryBean.SignalValue getSignalValue() { + return signalValue; + } + + public void setSignalValue(AccessoryBean.SignalValue signalValue) { + this.signalValue = signalValue; + repaint(); + } + + public SensorBean getSensorBean() { + return sensorBean; + } + + public void setSensorBean(SensorBean sensorBean) { + this.sensorBean = sensorBean; + } + + public BlockBean getBlockBean() { + return blockBean; + } + + public void setBlockBean(BlockBean blockBean) { + this.blockBean = blockBean; + } + + public void setRenderWidth(int renderWidth) { + this.renderWidth = renderWidth; + } + + public void setRenderHeight(int renderHeight) { + this.renderHeight = renderHeight; + } + + public int getRenderOffsetX() { + return renderOffsetX; + } + + public void setRenderOffsetX(int renderOffsetX) { + this.renderOffsetX = renderOffsetX; + } + + public int getRenderOffsetY() { + return renderOffsetY; + } + + public void setRenderOffsetY(int renderOffsetY) { + this.renderOffsetY = renderOffsetY; + } + + public TileBean.TileType getTileType() { + return this.tileType; + } + + public final void setTileType(TileType tileType) { + this.tileType = tileType; + } + + public Color getTrackColor() { + return trackColor; + } + + public final void setTrackColor(Color trackColor) { + this.trackColor = trackColor; + } + + public Color getTrackRouteColor() { + return trackRouteColor; + } + + public void setTrackRouteColor(Color trackRouteColor) { + this.trackRouteColor = trackRouteColor; + } + + public Color getSelectedColor() { + return model.getSelectedColor(); + } + + public void setSelectedColor(Color selectedColor) { + this.model.setSelectedColor(selectedColor); + } + + public Orientation getIncomingSide() { + return incomingSide; + } + + public void setIncomingSide(Orientation incomingSide) { + this.incomingSide = incomingSide; + } + + public Color getBackgroundColor() { + return backgroundColor; + } + + public void setBackgroundColor(Color backgroundColor) { + this.backgroundColor = backgroundColor; + } + + public boolean isDrawRoute() { + return model.isShowRoute(); + } + + public void setDrawRoute(boolean drawRoute) { + this.model.setShowRoute(drawRoute); + } + + public int getRenderWidth() { + return renderWidth; + } + + public int getRenderHeight() { + return renderHeight; + } + + abstract void renderTile(Graphics2D g2d); + + abstract void renderTileRoute(Graphics2D g2d); + + public abstract Map getNeighborPoints(); + + public abstract Map getEdgePoints(); + + public abstract Set getAllPoints(); + + /** + * Draw the Tile + * + * @param g2d The graphics handle + */ + public void drawTile(Graphics2D g2d) { + // by default and image is rendered in the EAST orientation + Orientation tileOrientation = model.getTileOrienation(); +// if (tileOrientation == null) { +// tileOrientation = Orientation.EAST; +// } + + BufferedImage bf = createImage(); + Graphics2D g2di = bf.createGraphics(); + + //Avoid errors + if (model.isShowRoute() && incomingSide == null) { + incomingSide = getOrientation(); + } + + if (model.isSelected()) { + g2di.setBackground(model.getSelectedColor()); + } else { + g2di.setBackground(backgroundColor); + } + + g2di.clearRect(0, 0, renderWidth, renderHeight); + int ox = 0, oy = 0; + + AffineTransform trans = new AffineTransform(); + switch (tileOrientation) { + case SOUTH -> { + trans.rotate(Math.PI / 2, renderWidth / 2, renderHeight / 2); + ox = (renderHeight - renderWidth) / 2; + oy = (renderWidth - renderHeight) / 2; + trans.translate(-ox, -oy); + } + case WEST -> { + trans.rotate(Math.PI, renderWidth / 2, renderHeight / 2); + trans.translate(ox, oy); + } + case NORTH -> { + trans.rotate(-Math.PI / 2, renderWidth / 2, renderHeight / 2); + ox = (renderHeight - renderWidth) / 2; + oy = (renderWidth - renderHeight) / 2; + trans.translate(-ox, -oy); + } + default -> { + trans.rotate(0.0, this.renderWidth / 2, this.renderHeight / 2); + trans.translate(ox, oy); + } + } + + //Logger.trace(tileOrientation.getOrientation() + " renderWidth: " + renderWidth + " renderHeight: " + renderHeight + " CP: (" + renderWidth / 2 + "," + renderHeight / 2 + ")"); + //Logger.trace(tileOrientation.getOrientation() + " ox: " + ox + " oy: " + oy); + g2di.setTransform(trans); + + renderTile(g2di); + + if (model.isShowRoute()) { + renderTileRoute(g2di); + } + + if (model.isShowCenter()) { + drawCenterPoint(g2di); + } + + // Scale the image back... + if (model.isScaleImage()) { + tileImage = Scalr.resize(bf, Method.AUTOMATIC, Mode.FIT_EXACT, getWidth(), getHeight(), Scalr.OP_ANTIALIAS); + } else { + tileImage = bf; + } + + g2di.dispose(); + + Logger.trace(id + " Cp: " + xyToString()); + + } + + public BufferedImage getTileImage() { + return tileImage; + } + + /** + * Render a tile image Always starts at (0,0) used the default width and height + * + * @param g2 the Graphic context + */ + public void drawName(Graphics2D g2) { + } + + protected void drawCenterPoint(Graphics2D g2d) { + drawCenterPoint(g2d, Color.magenta); + } + + protected void drawCenterPoint(Graphics2D g2, Color color) { + drawCenterPoint(g2, color, 60); + } + + protected void drawCenterPoint(Graphics2D g2d, Color color, double size) { + double dX = (renderWidth / 2 - size / 2); + double dY = (renderHeight / 2 - size / 2); + + g2d.setColor(color); + g2d.fill(new Ellipse2D.Double(dX, dY, size, size)); + } + + /** + * Rotate the tile clockwise 90 deg + * + * @return the new Orientation + */ + public Orientation rotate() { + Orientation tileOrientation = model.getTileOrienation(); + switch (tileOrientation) { + case EAST -> + setOrientation(Orientation.SOUTH); + case SOUTH -> + setOrientation(Orientation.WEST); + case WEST -> + setOrientation(Orientation.NORTH); + default -> + setOrientation(Orientation.EAST); + } + return model.getTileOrienation(); + } + + public void flipHorizontal() { + Orientation tileOrientation = model.getTileOrienation(); + if (Orientation.NORTH == tileOrientation || Orientation.SOUTH == tileOrientation) { + rotate(); + rotate(); + } + } + + public void flipVertical() { + Orientation tileOrientation = model.getTileOrienation(); + if (Orientation.EAST == tileOrientation || Orientation.WEST == tileOrientation) { + rotate(); + rotate(); + } + } + + @Override + public void move(int newX, int newY) { + Point cs = LayoutUtil.snapToGrid(newX, newY); + setCenter(cs); + } + + protected static void drawRotate(Graphics2D g2d, double x, double y, int angle, String text) { + g2d.translate((float) x, (float) y); + g2d.rotate(Math.toRadians(angle)); + g2d.drawString(text, 0, 0); + g2d.rotate(-Math.toRadians(angle)); + g2d.translate(-x, -y); + } + + public static BufferedImage flipHorizontally(BufferedImage source) { + BufferedImage output = new BufferedImage(source.getHeight(), source.getWidth(), source.getType()); + + AffineTransform flip = AffineTransform.getScaleInstance(1, -1); + flip.translate(0, -source.getHeight()); + AffineTransformOp op = new AffineTransformOp(flip, AffineTransformOp.TYPE_NEAREST_NEIGHBOR); + + op.filter(source, output); + + return output; + } + + public static BufferedImage flipVertically(BufferedImage source) { + BufferedImage output = new BufferedImage(source.getHeight(), source.getWidth(), source.getType()); + + AffineTransform flip = AffineTransform.getScaleInstance(-1, 1); + flip.translate(-source.getWidth(), 0); + AffineTransformOp op = new AffineTransformOp(flip, AffineTransformOp.TYPE_NEAREST_NEIGHBOR); + + op.filter(source, output); + + return output; + } + + public Set getAltPoints() { + return Collections.EMPTY_SET; + } + + public final int getOffsetX() { + return offsetX; + } + + public void setOffsetX(int offsetX) { + this.offsetX = offsetX; + } + + public final int getOffsetY() { + return offsetY; + } + + public void setOffsetY(int offsetY) { + this.offsetY = offsetY; + } + + protected BufferedImage createImage() { + return new BufferedImage(renderWidth, renderHeight, BufferedImage.TYPE_INT_RGB); + } + + public int getCenterX() { + if (tileX > 0) { + return this.tileX; + } else { + return GRID; + } + } + + public int getCenterY() { + if (tileY > 0) { + return this.tileY; + } else { + return GRID; + } + } + + public boolean isDrawName() { + return drawName; + } + + public void setDrawName(boolean drawName) { + this.drawName = drawName; + } + + public boolean isScaleImage() { + return model.isScaleImage(); + } + + public void setScaleImage(boolean scaleImage) { + Dimension d; + if (scaleImage) { + d = new Dimension(DEFAULT_WIDTH, DEFAULT_HEIGHT); + } else { + d = new Dimension(renderWidth, renderHeight); + } + + setSize(d); + setPreferredSize(d); + + model.setScaleImage(scaleImage); + } + + public boolean isDrawCenterPoint() { + return model.isShowCenter(); + } + + public void setDrawCenterPoint(boolean drawCenterPoint) { + model.setShowCenter(drawCenterPoint); + } + + @Override + public String toString() { + return this.getClass().getSimpleName() + + " {id: " + + this.id + + ", orientation: " + + getOrientation() + + ", direction: " + + getDirection() + + ", center: " + + xyToString() + + "}"; + } + + public String xyToString() { + return "(" + this.tileX + "," + this.tileY + ")"; + } + + /** + * The main route of the tile is horizontal + * + * @return true when main route goes from East to West or vv + */ + public boolean isHorizontal() { + Orientation tileOrientation = model.getTileOrienation(); + return (Orientation.EAST == tileOrientation || Orientation.WEST == tileOrientation) && TileType.CURVED != tileType; + } + + /** + * The main route of the tile is vertical + * + * @return true when main route goes from North to South or vv + */ + public boolean isVertical() { + Orientation tileOrientation = model.getTileOrienation(); + return (Orientation.NORTH == tileOrientation || Orientation.SOUTH == tileOrientation) && TileType.CURVED != tileType; + } + + public boolean isJunction() { + return TileType.SWITCH == tileType || TileType.CROSS == tileType; + } + + public boolean isBlock() { + return TileType.BLOCK == tileType; + } + + public boolean isDirectional() { + return TileType.STRAIGHT_DIR == tileType; + } + + /** + * The main route of the tile is diagonal + * + * @return true when main route goes from North to East or West to South and vv + */ + public boolean isDiagonal() { + return TileType.CURVED == tileType; + } + + public boolean isCrossing() { + return TileType.CROSSING == tileType; + } + + public List getNeighbours() { + return neighbours; + } + + public void setNeighbours(List neighbours) { + this.neighbours = neighbours; + } + + public String getIdSuffix(Tile other) { + return ""; + } + + public Map getNeighborOrientations() { + Map edgeOrientations = new HashMap<>(); + + Map neighborPoints = getNeighborPoints(); + + for (Orientation o : Orientation.values()) { + edgeOrientations.put(neighborPoints.get(o), o); + } + return edgeOrientations; + } + + public Map getEdgeOrientations() { + Map edgeOrientations = new HashMap<>(); + + Map edgeConnections = getEdgePoints(); + + for (Orientation o : Orientation.values()) { + edgeOrientations.put(edgeConnections.get(o), o); + } + return edgeOrientations; + } + + public boolean isAdjacent(Tile other) { + boolean adjacent = false; + + if (other != null) { + Collection thisEdgePoints = getEdgePoints().values(); + Collection otherEdgePoints = other.getEdgePoints().values(); + + for (Point p : thisEdgePoints) { + adjacent = otherEdgePoints.contains(p); + if (adjacent) { + break; + } + } + } + + return adjacent; + } + + /** + * When the tile has a specific direction a train may travel,
+ * then this method will indicate whether the other tile is in on the side where the arrow is pointing to. + * + * @param other A Tile + * @return true where other is on the side of this tile where the arrow points to + */ + public boolean isArrowDirection(Tile other) { + return true; + } + + public AccessoryValue accessoryValueForRoute(Orientation from, Orientation to) { + return AccessoryValue.OFF; + } + + public TileModel getModel() { + return model; + } + + public void setModel(TileModel newModel) { + TileModel oldModel = getModel(); + + if (oldModel != null) { + oldModel.removeChangeListener(changeListener); + oldModel.removeActionListener(actionListener); + changeListener = null; + actionListener = null; + } + + model = newModel; + + if (newModel != null) { + changeListener = createChangeListener(); + actionListener = createActionListener(); + + newModel.addChangeListener(changeListener); + newModel.addActionListener(actionListener); + } + + firePropertyChange(MODEL_CHANGED_PROPERTY, oldModel, newModel); + if (newModel != oldModel) { + revalidate(); + repaint(); + } + } + +// public TileUI getUI() { +// return (TileUI) ui; +// } +// public void setUI(TileUI ui) { +// super.setUI(ui); +// } + @Override + public void updateUI() { + } + + protected ChangeListener createChangeListener() { + return getHandler(); + } + + protected ActionListener createActionListener() { + return getHandler(); + } + + private Handler getHandler() { + if (handler == null) { + handler = new Handler(); + } + return handler; + } + + class Handler implements ActionListener, ChangeListener, Serializable { + + @Override + public void stateChanged(ChangeEvent e) { + //Object source = e.getSource(); + + fireStateChanged(); + repaint(); + } + + @Override + public void actionPerformed(ActionEvent event) { + fireActionPerformed(event); + } + } + + protected void fireStateChanged() { + Object[] listeners = listenerList.getListenerList(); + //reverse order + for (int i = listeners.length - 2; i >= 0; i -= 2) { + if (listeners[i] == ChangeListener.class) { + // Lazily create the event: + if (changeEvent == null) { + changeEvent = new ChangeEvent(this); + } + ((ChangeListener) listeners[i + 1]).stateChanged(changeEvent); + } + } + } + + protected void fireActionPerformed(ActionEvent event) { + Object[] listeners = listenerList.getListenerList(); + ActionEvent e = null; + // reverse + for (int i = listeners.length - 2; i >= 0; i -= 2) { + if (listeners[i] == ActionListener.class) { + // Lazily create the event: + if (e == null) { + String actionCommand = event.getActionCommand(); + //if(actionCommand == null) { + // actionCommand = getActionCommand(); + //} + e = new ActionEvent(Tile.this, ActionEvent.ACTION_PERFORMED, actionCommand, event.getWhen(), event.getModifiers()); + } + ((ActionListener) listeners[i + 1]).actionPerformed(e); + } + } + } + + public Rectangle getTileBounds() { + if (model.isScaleImage()) { + return new Rectangle(tileX - GRID, tileY - GRID, DEFAULT_WIDTH, DEFAULT_HEIGHT); + } else { + return new Rectangle(tileX - renderWidth / 2, tileY - renderHeight / 2, renderWidth, renderHeight); + } + } + + @Override + protected void paintComponent(Graphics g) { + long started = System.currentTimeMillis(); + + Graphics2D g2 = (Graphics2D) g.create(); + //Graphics2D g2 = (Graphics2D) g.create(tileX - GRID, tileY - GRID, DEFAULT_WIDTH, DEFAULT_HEIGHT); + drawTile(g2); + g2.dispose(); + + g.drawImage(tileImage, 0, 0, null); + + long now = System.currentTimeMillis(); + Logger.trace(id + " Duration: " + (now - started) + " ms. Cp: " + xyToString() + " O: " + model.getTileOrienation()); + } + +} diff --git a/src/main/java/jcs/ui/layout/tiles/TileFactory.java b/src/main/java/jcs/ui/layout/tiles/TileFactory.java index f1522721..40d6db61 100755 --- a/src/main/java/jcs/ui/layout/tiles/TileFactory.java +++ b/src/main/java/jcs/ui/layout/tiles/TileFactory.java @@ -225,7 +225,6 @@ public static Tile createTile(TileBean tileBean, boolean showValues) { * @param orientation whether the orientation of the Tile is EAST, WEST, NORTH or SOUTH * @param x the tile center X * @param y the tile center Y - * @param drawOutline whether the outline of the tile must be rendered * @return a Tile object */ public static Tile createTile(TileBean.TileType tileType, Orientation orientation, int x, int y) { diff --git a/src/main/java/jcs/ui/layout/tiles/TileModel.java b/src/main/java/jcs/ui/layout/tiles/TileModel.java index 84b78bf0..4280d06e 100644 --- a/src/main/java/jcs/ui/layout/tiles/TileModel.java +++ b/src/main/java/jcs/ui/layout/tiles/TileModel.java @@ -15,6 +15,7 @@ */ package jcs.ui.layout.tiles; +import java.awt.Color; import java.awt.event.ActionListener; import java.io.Serializable; import javax.swing.event.ChangeListener; @@ -32,6 +33,10 @@ public interface TileModel extends Serializable { public void setSelected(boolean selected); + Color getSelectedColor(); + + public void setSelectedColor(Color selectedColor); + boolean isScaleImage(); public void setScaleImage(boolean scaleImage); From 1cbd14c92ec7b0bdafe5373c537a9b301dc4b325 Mon Sep 17 00:00:00 2001 From: fja-itank Date: Wed, 29 Jan 2025 20:14:50 +0100 Subject: [PATCH 11/24] Adding tests for checking Tile occupancy in the edit screen --- .../commandStation/autopilot/AutoPilot.java | 2 +- .../autopilot/state/Dispatcher.java | 2 +- src/main/java/jcs/ui/layout/LayoutCanvas.form | 234 +--- src/main/java/jcs/ui/layout/LayoutCanvas.java | 114 +- src/main/java/jcs/ui/layout/RoutesDialog.java | 1 + src/main/java/jcs/ui/layout/TileCache.java | 406 ------ .../ui/layout/dialogs/BlockControlDialog.java | 2 +- .../jcs/ui/layout/dialogs/BlockDialog.java | 2 +- src/main/java/jcs/ui/layout/tiles/Block.java | 2 +- src/main/java/jcs/ui/layout/tiles/Cross.java | 669 +--------- .../java/jcs/ui/layout/tiles/Crossing.java | 150 +-- src/main/java/jcs/ui/layout/tiles/Curved.java | 162 +-- src/main/java/jcs/ui/layout/tiles/End.java | 148 +-- .../java/jcs/ui/layout/tiles/Straight.java | 148 +-- src/main/java/jcs/ui/layout/tiles/Switch.java | 362 +----- src/main/java/jcs/ui/layout/tiles/Tile.java | 1134 +---------------- .../java/jcs/ui/layout/tiles/TileCache.java | 1 + .../java/jcs/ui/layout/tiles/TileFactory.java | 293 +---- 18 files changed, 40 insertions(+), 3792 deletions(-) delete mode 100644 src/main/java/jcs/ui/layout/TileCache.java create mode 100644 src/main/java/jcs/ui/layout/tiles/TileCache.java diff --git a/src/main/java/jcs/commandStation/autopilot/AutoPilot.java b/src/main/java/jcs/commandStation/autopilot/AutoPilot.java index f3bfb91c..23ce3b8b 100644 --- a/src/main/java/jcs/commandStation/autopilot/AutoPilot.java +++ b/src/main/java/jcs/commandStation/autopilot/AutoPilot.java @@ -37,7 +37,7 @@ import jcs.entities.RouteBean; import jcs.entities.SensorBean; import jcs.persistence.PersistenceFactory; -import jcs.ui.layout.TileCache; +import jcs.ui.layout.tiles.TileCache; import jcs.ui.layout.events.TileEvent; import org.tinylog.Logger; diff --git a/src/main/java/jcs/commandStation/autopilot/state/Dispatcher.java b/src/main/java/jcs/commandStation/autopilot/state/Dispatcher.java index d474b4da..70801fc9 100644 --- a/src/main/java/jcs/commandStation/autopilot/state/Dispatcher.java +++ b/src/main/java/jcs/commandStation/autopilot/state/Dispatcher.java @@ -32,7 +32,7 @@ import jcs.entities.RouteElementBean; import jcs.entities.TileBean; import jcs.persistence.PersistenceFactory; -import jcs.ui.layout.TileCache; +import jcs.ui.layout.tiles.TileCache; import jcs.ui.layout.events.TileEvent; import org.tinylog.Logger; diff --git a/src/main/java/jcs/ui/layout/LayoutCanvas.form b/src/main/java/jcs/ui/layout/LayoutCanvas.form index 884eba14..3a7b262c 100755 --- a/src/main/java/jcs/ui/layout/LayoutCanvas.form +++ b/src/main/java/jcs/ui/layout/LayoutCanvas.form @@ -1,233 +1 @@ - - -

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
+
\ No newline at end of file diff --git a/src/main/java/jcs/ui/layout/LayoutCanvas.java b/src/main/java/jcs/ui/layout/LayoutCanvas.java index fb3813da..edc748ef 100755 --- a/src/main/java/jcs/ui/layout/LayoutCanvas.java +++ b/src/main/java/jcs/ui/layout/LayoutCanvas.java @@ -73,6 +73,8 @@ import jcs.ui.layout.tiles.Switch; import jcs.ui.layout.tiles.Tile; import jcs.ui.layout.tiles.TileFactory; +import jcs.ui.layout.tiles.TileCache; +import static jcs.ui.layout.tiles.TileCache.findTile; import org.tinylog.Logger; /** @@ -244,12 +246,12 @@ void loadLayoutInBackground() { } private void loadTiles() { - TileCache.loadTiles(); - removeAll(); + List tiles = TileCache.loadTiles(); + removeAll(); selectedTile = null; - for (Tile tile : TileCache.tiles.values()) { + for (Tile tile : tiles) { add(tile); tile.setDrawCenterPoint(!readonly); } @@ -324,7 +326,7 @@ private void mousePressedAction(MouseEvent evt) { } } default -> { - Logger.trace((selectedTile != null ? "Selected tile: " + selectedTile.getId() + ", " + selectedTile.xyToString() : "No tile selected")); + Logger.trace((selectedTile != null ? "Selected tile: " + selectedTile.getId() + ", " + selectedTile.xyToString() : "No tile @ (" + snapPoint.x + "," + snapPoint.y + ")")); if (MouseEvent.BUTTON3 == evt.getButton()) { showOperationsPopupMenu(selectedTile, snapPoint); } @@ -334,20 +336,18 @@ private void mousePressedAction(MouseEvent evt) { private Tile addTile(Point p, TileType tileType, Orientation orientation, Direction direction, boolean selected, boolean showCenter) { Logger.trace("Adding: " + tileType + " @ " + p + " O: " + orientation + " D: " + direction); - Point chkp = TileCache.checkAvailable(p, orientation); - - Tile tile = TileFactory.createTile(tileType, orientation, direction, chkp); - tile.setSelected(selected); - tile.setDrawCenterPoint(showCenter); + Tile tile = TileFactory.createTile(tileType, orientation, direction, p); - //Can the tile be placed, keeping in mind the extra points - boolean canBeAdded = !TileCache.checkTileOccupation(tile); - - if (canBeAdded) { + if (TileCache.canMoveTo(tile, p)) { + tile.setSelected(selected); + tile.setDrawCenterPoint(showCenter); add(tile); TileCache.addAndSaveTile(tile); return tile; } else { + Tile occ = TileCache.findTile(p); + Logger.trace("Can't add tile " + tile.getId() + " on " + tile.xyToString() + " Is occupied by " + occ.getId()); + TileFactory.rollback(tile); return null; } } @@ -372,15 +372,11 @@ private void mouseDragAction(MouseEvent evt) { setComponentZOrder(selectedTile, 0); int curX = snapPoint.x - Tile.GRID; int curY = snapPoint.y - Tile.GRID; - - //check overlap in the cache - //This wil only chek the snappint, whic incas of a moving Block or Cross in not enough! - //TODO ! Needed are the alt point of the moved block or Cross. - //How to do this? - if (TileCache.containsPoint(snapPoint)) { - selectedTile.setSelectedColor(Tile.DEFAULT_WARN_COLOR); - } else { + + if (TileCache.canMoveTo(selectedTile, snapPoint)) { selectedTile.setSelectedColor(Tile.DEFAULT_SELECTED_COLOR); + } else { + selectedTile.setSelectedColor(Tile.DEFAULT_WARN_COLOR); } selectedTile.setBounds(curX, curY, selectedTile.getWidth(), selectedTile.getHeight()); @@ -390,79 +386,17 @@ private void mouseDragAction(MouseEvent evt) { private void mouseReleasedAction(MouseEvent evt) { Point snapPoint = LayoutUtil.snapToGrid(evt.getPoint()); - boolean snapPointOccupied = TileCache.containsPoint(snapPoint); - if (!Mode.CONTROL.equals(mode) && MouseEvent.BUTTON1 == evt.getButton() && selectedTile != null) { - - boolean destinationOccupied = TileCache.containsPoints(selectedTile.getAllPoints()); + if (!Mode.CONTROL.equals(mode) && MouseEvent.BUTTON1 == evt.getButton() && selectedTile != null && !selectedTile.getCenter().equals(snapPoint)) { - - Logger.trace("Selected tile: " + selectedTile.getId() + ", " + selectedTile.xyToString()+" Dest Occ "+destinationOccupied); - - if (destinationOccupied || snapPointOccupied) { - Logger.debug("Can't move tile " + selectedTile.getId() + " from " + selectedTile.xyToString() + " to (" + snapPoint.x + "," + snapPoint.y + ")!"); + if (TileCache.canMoveTo(selectedTile, snapPoint)) { + TileCache.moveTo(selectedTile, snapPoint); + } else { + Tile occ = TileCache.findTile(snapPoint); + Logger.trace("Can't Move tile " + selectedTile.getId() + " from " + selectedTile.xyToString() + " to (" + snapPoint.x + "," + snapPoint.y + ") Is occupied by " + occ.getId()); - //selectedTile.setBounds(selectedTile.getTileX(), selectedTile.getTileY(), selectedTile.getWidth(), selectedTile.getHeight()); - selectedTile.setBounds(selectedTile.getTileBounds()); selectedTile.setSelectedColor(Tile.DEFAULT_SELECTED_COLOR); - - } else { - TileCache.moveTile(snapPoint, selectedTile); + selectedTile.setBounds(selectedTile.getTileBounds()); } - -// Point tp = selectedTile.getCenter(); -// if (!tp.equals(snapPoint)) { -// -// Logger.tag("Moving Tile from " + tp + " to " + snapPoint + " Tile to move: " + selectedTile); -// //Check if new position is free -// boolean canMove = true; -// if (TileCache.containsPoint(snapPoint)) { -// Tile tile = TileCache.findTile(snapPoint); -// if (selectedTile.getId().equals(tile.getId())) { -// //same tile so we can move -// canMove = true; -// } else { -// Logger.debug("Position " + snapPoint + " is occupied with tile: " + tile + ", can't move tile " + selectedTile.getId()); -// canMove = false; -// } -// } -// -// if (canMove) { -// //Remove the original tile center from the tiles -// Tile movingTile = TileCache.tiles.remove(tp); -// if (movingTile != null) { -// //Also remove from the alt points -// Point oldCenter = movingTile.getCenter(); -// Set oldAltPoints = movingTile.getAltPoints(); -// //Logger.trace("Removing " + oldAltPoints.size() + " alt tile points"); -// for (Point ep : oldAltPoints) { -// TileCache.altTiles.remove(ep); -// TileCache.tiles.remove(ep); -// } -// -// //Set the new center position -// movingTile.setCenter(snapPoint); -// //Check again, needed for tiles which are longer then 1 square, like a block -// if (!TileCache.checkTileOccupation(movingTile)) { -// Logger.trace("Moved Tile " + movingTile.getId() + " from " + tp + " to " + snapPoint + "..."); -// TileCache.tiles.put(snapPoint, movingTile); -// for (Point ep : movingTile.getAltPoints()) { -// TileCache.altTiles.put(ep, movingTile); -// } -// } else { -// //Do not move Tile, put back where it was -// movingTile.setCenter(oldCenter); -// TileCache.tiles.put(oldCenter, movingTile); -// for (Point ep : movingTile.getAltPoints()) { -// TileCache.altTiles.put(ep, movingTile); -// } -// } -// -// TileCache.saveTile(movingTile); -// } -// //TODO is this needed? - // repaint(); - // } - // } } } diff --git a/src/main/java/jcs/ui/layout/RoutesDialog.java b/src/main/java/jcs/ui/layout/RoutesDialog.java index 742a03e0..6f564d26 100644 --- a/src/main/java/jcs/ui/layout/RoutesDialog.java +++ b/src/main/java/jcs/ui/layout/RoutesDialog.java @@ -15,6 +15,7 @@ */ package jcs.ui.layout; +import jcs.ui.layout.tiles.TileCache; import java.awt.Color; import java.awt.Component; import java.awt.Point; diff --git a/src/main/java/jcs/ui/layout/TileCache.java b/src/main/java/jcs/ui/layout/TileCache.java deleted file mode 100644 index c44f5909..00000000 --- a/src/main/java/jcs/ui/layout/TileCache.java +++ /dev/null @@ -1,406 +0,0 @@ -/* - * Copyright 2025 Frans Jacobs. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package jcs.ui.layout; - -import jcs.ui.layout.tiles.*; -import java.awt.Point; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.stream.Collectors; -import jcs.entities.AccessoryBean.AccessoryValue; -import jcs.entities.AccessoryBean.SignalValue; -import jcs.entities.TileBean; -import jcs.entities.TileBean.Orientation; -import static jcs.entities.TileBean.Orientation.EAST; -import static jcs.entities.TileBean.Orientation.SOUTH; -import static jcs.entities.TileBean.Orientation.WEST; -import static jcs.entities.TileBean.TileType.CROSS; -import jcs.persistence.PersistenceFactory; -import jcs.ui.layout.events.TileEvent; -import jcs.ui.layout.events.TileEventListener; -import org.tinylog.Logger; - -/** - * Factory object to create Tiles and cache tiles - * - * @author frans - */ -public class TileCache { - - private static final Map tileEventListeners = new HashMap<>(); - - private static boolean drawCenterPoint; - private static boolean showValues; - - static final Map tiles = new HashMap<>(); - static final Map points = new HashMap<>(); - static final Map altTiles = new HashMap<>(); - - private TileCache() { - } - -// static void setDrawCenterPoint(boolean drawCenterPoint) { -// TileCache.drawCenterPoint = drawCenterPoint; -// -// for (Tile tile : tiles.values()) { -// //if (tile instanceof AbstractTile abstractTile) { -// tile.setDrawCenterPoint(drawCenterPoint); -// //} -// } -// } - public static void setShowValues(boolean showValues) { - TileCache.showValues = showValues; - - for (Tile tile : tiles.values()) { - TileBean.TileType tileType = tile.getTileType(); - //AbstractTile tile = null; - switch (tileType) { - case SWITCH -> { - if (showValues && ((Switch) tile).getTileBean().getAccessoryBean() != null) { - tile.setAccessoryValue(tile.getTileBean().getAccessoryBean().getAccessoryValue()); - } else { - tile.setAccessoryValue(AccessoryValue.OFF); - } - } - case CROSS -> { - if (showValues && ((Cross) tile).getTileBean().getAccessoryBean() != null) { - tile.setAccessoryValue(tile.getTileBean().getAccessoryBean().getAccessoryValue()); - } else { - tile.setAccessoryValue(AccessoryValue.OFF); - } - } - case SIGNAL -> { - if (showValues && ((Signal) tile).getTileBean().getAccessoryBean() != null) { - tile.setSignalValue(tile.getTileBean().getAccessoryBean().getSignalValue()); - } else { - tile.setSignalValue(SignalValue.OFF); - } - } - case SENSOR -> { - if (showValues && ((Sensor) tile).getTileBean().getSensorBean() != null) { - tile.setActive(tile.getTileBean().getSensorBean().isActive()); - } else { - tile.setActive(false); - } - } - case BLOCK -> { - } - } - } - } - - static void loadTiles() { - List tileBeans = PersistenceFactory.getService().getTileBeans(); - - tileEventListeners.clear(); - altTiles.clear(); - tiles.clear(); - - for (TileBean tb : tileBeans) { - Tile tile = TileFactory.createTile(tb, showValues); - //tile.setPropertyChangeListener(listener); - tiles.put(tile.getCenter(), tile); - points.put(tile.getId(), tile.getCenter()); - - //addTileEventListener((TileEventListener) tile); - //Alternative point(s) to be able to find all points - if (!tile.getAltPoints().isEmpty()) { - Set alt = tile.getAltPoints(); - for (Point ap : alt) { - altTiles.put(ap, tile); - } - } - } - - Logger.trace("Loaded " + tiles.size() + " Tiles..."); - } - - static List getTiles() { - return tiles.values().stream().collect(Collectors.toList()); - } - - static void addAndSaveTile(Tile tile) { - tiles.put(tile.getCenter(), tile); - points.put(tile.getId(), tile.getCenter()); - - //addTileEventListener((TileEventListener) tile); - //Alternative point(s) to be able to find all points - if (!tile.getAltPoints().isEmpty()) { - Set alt = tile.getAltPoints(); - for (Point ap : alt) { - altTiles.put(ap, tile); - } - } - - saveTile(tile); - Logger.trace("Added " + tile + " There are now " + TileCache.tiles.size() + " tiles..."); - } - - static void deleteTile(final Tile tile) { - if (tile != null) { - if (tiles.containsKey(tile.getCenter())) { - tiles.remove(tile.getCenter()); - points.remove(tile.getId()); - Set rps = tile.getAltPoints(); - //Also remove alt points - for (Point ap : rps) { - altTiles.remove(ap); - } - - TileBean tb = tile.getTileBean(); - PersistenceFactory.getService().remove(tb); - Logger.trace("Deleted " + tile.getId()); - } else { - Logger.warn("Tile " + tile.getId() + " not found in cache"); - } - } else { - Logger.warn("Tile is null?"); - } - } - - static void saveTile(final Tile tile) { - if (tile != null) { - TileBean tb = tile.getTileBean(); - PersistenceFactory.getService().persist(tb); - } else { - Logger.warn("Tile is null?"); - } - } - - static void saveTiles() { - for (Tile tile : tiles.values()) { - saveTile(tile); - } - } - - public static Tile findTile(Point cp) { - Tile result = tiles.get(cp); - if (result == null) { - result = altTiles.get(cp); - if (result != null) { - } - } - return result; - } - - public static Tile findTile(String id) { - Point p = points.get(id); - if (p != null) { - return findTile(p); - } else { - return null; - } - } - - static boolean checkTileOccupation(Tile tile) { - Set tilePoints = tile.getAllPoints(); - for (Point p : tilePoints) { - if (tiles.containsKey(p) || altTiles.containsKey(p)) { - //The is a match, check if it is an other tile - Tile mt = findTile(p); - if (tile.getId().equals(mt.getId())) { - //same tile continue - } else { - //Other tile so really occupied - return true; - } - } - } - return false; - } - - static boolean containsPoints(Set points) { - for (Point p : points) { - return tiles.containsKey(p) || altTiles.containsKey(p); - } - return false; - - } - - static boolean containsPoint(Point point) { - return tiles.containsKey(point) || altTiles.containsKey(point); - } - - static Point checkAvailable(Point newPoint, Orientation orientation) { - if (tiles.containsKey(newPoint)) { - Tile et = tiles.get(newPoint); - Logger.trace("@ " + newPoint + " is allready occcupied by: " + et + "..."); - //Search for the nearest avalaible free point - //first get the Center point of the tile which is occuping this slot - // show warning! - Point ecp = et.getCenter(); - - int w = et.getWidth(); - int h = et.getHeight(); - - Point np; - np = switch (orientation) { - case EAST -> - new Point(ecp.x + w, ecp.y); - case WEST -> - new Point(newPoint.x - w, ecp.y); - case SOUTH -> - new Point(ecp.x, newPoint.y + h); - default -> - new Point(ecp.x, newPoint.y - h); - }; - - Logger.trace("Alternative CP: " + np); - // recursive check - return checkAvailable(np, orientation); - } else { - Logger.trace("@ " + newPoint + " is not yet used..."); - - return newPoint; - } - } - - static Tile rotateTile(Tile tile) { - if (!tiles.containsKey(tile.getCenter())) { - Logger.warn("Tile " + tile.getId() + " NOT in cache!"); - } - - //Remove the alternative or extra points... - for (Point ep : tile.getAltPoints()) { - altTiles.remove(ep); - } - - tile.rotate(); - - //update - tiles.put(tile.getCenter(), tile); - for (Point ep : tile.getAltPoints()) { - altTiles.put(ep, tile); - } - - saveTile(tile); - return tile; - } - - static Tile flipHorizontal(Tile tile) { - return flipTile(tile, true); - } - - public static Tile flipVertical(Tile tile) { - return flipTile(tile, false); - } - - private static Tile flipTile(Tile tile, boolean horizontal) { - if (!tiles.containsKey(tile.getCenter())) { - Logger.warn("Tile " + tile.getId() + " NOT in cache!"); - } - - //Remove the alternative or extra points... - for (Point ep : tile.getAltPoints()) { - altTiles.remove(ep); - } - - if (horizontal) { - tile.flipHorizontal(); - } else { - tile.flipVertical(); - } - //update - tiles.put(tile.getCenter(), tile); - for (Point ep : tile.getAltPoints()) { - altTiles.put(ep, tile); - } - - saveTile(tile); - return tile; - } - - static void moveTile(Point snapPoint, Tile tile) { - Point tp = tile.getCenter(); - if (!tp.equals(snapPoint)) { - //Check if new position is free - boolean canMove = !TileCache.containsPoint(snapPoint); - - if (canMove) { - Logger.trace("Moving from tile " + tile.getId() + " from " + tile.xyToString() + " to (" + snapPoint.x + "," + snapPoint.y + ")"); - //Remove the original tile center from the tiles - Tile movingTile = tiles.remove(tp); - if (movingTile != null) { - //Also remove from the alt points - Point oldCenter = movingTile.getCenter(); - Set oldAltPoints = movingTile.getAltPoints(); - //Logger.trace("Removing " + oldAltPoints.size() + " alt tile points"); - for (Point ep : oldAltPoints) { - altTiles.remove(ep); - tiles.remove(ep); - } - - //Set the new center position - movingTile.setCenter(snapPoint); - //Check again, needed for tiles which are longer then 1 square, like a block - if (!checkTileOccupation(movingTile)) { - Logger.trace("Moved Tile " + movingTile.getId() + " from " + tp + " to " + snapPoint + "..."); - tiles.put(snapPoint, movingTile); - for (Point ep : movingTile.getAltPoints()) { - altTiles.put(ep, movingTile); - } - } else { - //Do not move Tile, put back where it was - movingTile.setCenter(oldCenter); - tiles.put(oldCenter, movingTile); - for (Point ep : movingTile.getAltPoints()) { - altTiles.put(ep, movingTile); - } - } - - saveTile(movingTile); - } - } - //} - } - } - - static void addTileEventListener(TileEventListener listener) { - String key = listener.getId(); - tileEventListeners.put(key, listener); - } - - static void removeTileEventListener(Tile tile) { - if (tile instanceof TileEventListener tileEventListener) { - removeTileEventListener(tileEventListener); - } - } - - static void removeTileEventListener(TileEventListener listener) { - String key = listener.getId(); - tileEventListeners.remove(key, listener); - } - - public static void fireTileEventListener(TileEvent tileEvent) { - String key = tileEvent.getTileId(); - TileEventListener listener = tileEventListeners.get(key); - if (listener != null) { - listener.onTileChange(tileEvent); - Logger.trace("Fire listener on tile " + key); - } else { - //Logger.trace("Tile " + key + " not available"); - } - } - - static void fireAllTileEventListeners(TileEvent tileEvent) { - for (TileEventListener listener : tileEventListeners.values()) { - listener.onTileChange(tileEvent); - } - } - -} diff --git a/src/main/java/jcs/ui/layout/dialogs/BlockControlDialog.java b/src/main/java/jcs/ui/layout/dialogs/BlockControlDialog.java index 88057929..b5881650 100644 --- a/src/main/java/jcs/ui/layout/dialogs/BlockControlDialog.java +++ b/src/main/java/jcs/ui/layout/dialogs/BlockControlDialog.java @@ -24,7 +24,7 @@ import jcs.entities.BlockBean; import jcs.entities.LocomotiveBean; import jcs.persistence.PersistenceFactory; -import jcs.ui.layout.TileCache; +import jcs.ui.layout.tiles.TileCache; import jcs.ui.layout.events.TileEvent; import jcs.ui.layout.tiles.Block; import org.tinylog.Logger; diff --git a/src/main/java/jcs/ui/layout/dialogs/BlockDialog.java b/src/main/java/jcs/ui/layout/dialogs/BlockDialog.java index aa1974ba..9b06c95f 100644 --- a/src/main/java/jcs/ui/layout/dialogs/BlockDialog.java +++ b/src/main/java/jcs/ui/layout/dialogs/BlockDialog.java @@ -27,7 +27,7 @@ import jcs.entities.SensorBean; import jcs.persistence.PersistenceFactory; import jcs.ui.layout.LayoutCanvas; -import jcs.ui.layout.TileCache; +import jcs.ui.layout.tiles.TileCache; import jcs.ui.layout.tiles.Block; import jcs.ui.layout.tiles.Sensor; import jcs.ui.layout.tiles.Tile; diff --git a/src/main/java/jcs/ui/layout/tiles/Block.java b/src/main/java/jcs/ui/layout/tiles/Block.java index e98fa594..c9f36962 100755 --- a/src/main/java/jcs/ui/layout/tiles/Block.java +++ b/src/main/java/jcs/ui/layout/tiles/Block.java @@ -1 +1 @@ -/* * Copyright 2024 Frans Jacobs. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package jcs.ui.layout.tiles; import java.awt.BasicStroke; import java.awt.Color; import java.awt.Dimension; import java.awt.Font; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.Image; import java.awt.Point; import java.awt.Rectangle; import java.awt.geom.Ellipse2D; import java.awt.image.BufferedImage; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set; import jcs.entities.BlockBean; import jcs.entities.BlockBean.BlockState; import jcs.entities.LocomotiveBean; import jcs.entities.TileBean; import jcs.entities.TileBean.Orientation; import static jcs.entities.TileBean.Orientation.EAST; import static jcs.entities.TileBean.Orientation.NORTH; import static jcs.entities.TileBean.Orientation.SOUTH; import static jcs.entities.TileBean.Orientation.WEST; import jcs.entities.TileBean.TileType; import static jcs.ui.layout.tiles.Tile.DEFAULT_HEIGHT; import static jcs.ui.layout.tiles.Tile.DEFAULT_WIDTH; import static jcs.ui.layout.tiles.Tile.GRID; import static jcs.ui.layout.tiles.Tile.RENDER_HEIGHT; import static jcs.ui.layout.tiles.Tile.RENDER_WIDTH; import jcs.ui.util.ImageUtil; import org.tinylog.Logger; public class Block extends Tile { public static final int BLOCK_WIDTH = DEFAULT_WIDTH * 3; public static final int BLOCK_HEIGHT = DEFAULT_HEIGHT * 3; public Block(TileBean tileBean) { super(tileBean); setModel(new DefaultTileModel(tileBean.getOrientation())); changeRenderSize(); populateModel(); } public Block(Orientation orientation, Point center) { this(orientation, center.x, center.y); } public Block(Orientation orientation, int x, int y) { this(orientation, x, y, tileWidth(orientation, TileType.BLOCK), tileHeight(orientation, TileType.BLOCK)); } public Block(Orientation orientation, int x, int y, int width, int height) { super(TileType.BLOCK, orientation, x, y, width, height); setModel(new DefaultTileModel(orientation)); changeRenderSize(); } private void changeRenderSize() { Orientation tileOrientation = model.getTileOrienation(); if (Orientation.EAST == tileOrientation || Orientation.WEST == tileOrientation) { this.renderWidth = RENDER_WIDTH * 3; this.renderHeight = RENDER_HEIGHT; } else { this.renderWidth = RENDER_WIDTH; this.renderHeight = RENDER_HEIGHT * 3; } } @Override public Set getAltPoints() { int xx = this.tileX; int yy = this.tileY; Set alternatives = new HashSet<>(); if (Orientation.EAST.equals(getOrientation()) || Orientation.WEST.equals(getOrientation())) { // West Point wp = new Point((xx - DEFAULT_WIDTH), yy); Point ep = new Point((xx + DEFAULT_WIDTH), yy); alternatives.add(wp); alternatives.add(ep); } else { Point np = new Point(xx, (yy - DEFAULT_HEIGHT)); Point sp = new Point(xx, (yy + DEFAULT_HEIGHT)); alternatives.add(np); alternatives.add(sp); } return alternatives; } @Override public Set getAllPoints() { Set aps = new HashSet<>(); aps.add(getCenter()); aps.addAll(getAltPoints()); return aps; } public Point getAltPoint(String suffix) { int cx = this.getCenterX(); int cy = this.getCenterY(); if ("+".equals(suffix)) { return switch (this.getOrientation()) { case WEST -> new Point(cx - Tile.GRID * 2, cy); case NORTH -> new Point(cx, cy - Tile.GRID * 2); case SOUTH -> new Point(cx, cy + Tile.GRID * 2); default -> new Point(cx + Tile.GRID * 2, cy); }; } else { return switch (this.getOrientation()) { case EAST -> new Point(cx - Tile.GRID * 2, cy); case SOUTH -> new Point(cx, cy - Tile.GRID * 2); case NORTH -> new Point(cx, cy + Tile.GRID * 2); default -> new Point(cx + Tile.GRID * 2, cy); }; } } @Override public boolean isBlock() { return true; } @Override public Map getNeighborPoints() { Map neighbors = new HashMap<>(); Orientation orientation = this.getOrientation(); int cx = this.getCenterX(); int cy = this.getCenterY(); // Horizontal if (Orientation.EAST == orientation || Orientation.WEST == orientation) { neighbors.put(Orientation.EAST, new Point(cx + Tile.GRID * 4, cy)); neighbors.put(Orientation.WEST, new Point(cx - Tile.GRID * 4, cy)); } else { // Vertical neighbors.put(Orientation.NORTH, new Point(cx, cy - Tile.GRID * 4)); neighbors.put(Orientation.SOUTH, new Point(cx, cy + Tile.GRID * 4)); } return neighbors; } @Override public Map getEdgePoints() { Map edgeConnections = new HashMap<>(); Orientation orientation = this.getOrientation(); int cx = this.getCenterX(); int cy = this.getCenterY(); // Horizontal if (Orientation.EAST == orientation || Orientation.WEST == orientation) { edgeConnections.put(Orientation.EAST, new Point(cx + Tile.GRID * 3, cy)); edgeConnections.put(Orientation.WEST, new Point(cx - Tile.GRID * 3, cy)); } else { // Vertical edgeConnections.put(Orientation.NORTH, new Point(cx, cy - Tile.GRID * 3)); edgeConnections.put(Orientation.SOUTH, new Point(cx, cy + Tile.GRID * 3)); } return edgeConnections; } public Point getNeighborPoint(String suffix) { int cx = getCenterX(); int cy = getCenterY(); if ("+".equals(suffix)) { return switch (getOrientation()) { case WEST -> new Point(cx - Tile.GRID * 4, cy); case NORTH -> new Point(cx, cy - Tile.GRID * 4); case SOUTH -> new Point(cx, cy + Tile.GRID * 4); default -> new Point(cx + Tile.GRID * 4, cy); }; } else { return switch (getOrientation()) { case EAST -> new Point(cx - Tile.GRID * 4, cy); case SOUTH -> new Point(cx, cy - Tile.GRID * 4); case NORTH -> new Point(cx, cy + Tile.GRID * 4); default -> new Point(cx + Tile.GRID * 4, cy); }; } } public Orientation getTravelDirection(String suffix) { if ("+".equals(suffix)) { return getOrientation(); } else { return switch (getOrientation()) { case EAST -> Orientation.WEST; case SOUTH -> Orientation.NORTH; case NORTH -> Orientation.SOUTH; default -> Orientation.EAST; }; } } @Override public String getIdSuffix(Tile other) { String suffix = null; Orientation match = null; if (isAdjacent(other)) { Map blockSides = this.getEdgePoints(); Map otherSides = other.getEdgePoints(); for (Orientation bo : Orientation.values()) { Point bp = blockSides.get(bo); if (bp != null) { for (Orientation oo : Orientation.values()) { Point op = otherSides.get(oo); if (op != null) { if (op.equals(bp)) { match = bo; break; } } } } } } Orientation tileOrientation = model.getTileOrienation(); if (match != null) { if (Orientation.EAST == tileOrientation && Orientation.EAST == match) { suffix = "+"; } if (Orientation.WEST == tileOrientation && Orientation.WEST == match) { suffix = "+"; } if (Orientation.EAST == tileOrientation && Orientation.WEST == match) { suffix = "-"; } if (Orientation.WEST == tileOrientation && Orientation.EAST == match) { suffix = "-"; } if (Orientation.NORTH == tileOrientation && Orientation.NORTH == match) { suffix = "+"; } if (Orientation.NORTH == tileOrientation && Orientation.SOUTH == match) { suffix = "-"; } if (Orientation.SOUTH == tileOrientation && Orientation.SOUTH == match) { suffix = "+"; } if (Orientation.SOUTH == tileOrientation && Orientation.NORTH == match) { suffix = "-"; } } return suffix; } @Override public Orientation rotate() { super.rotate(); Orientation tileOrientation = model.getTileOrienation(); int w = tileWidth(tileOrientation, TileType.BLOCK); int h = tileHeight(tileOrientation, TileType.BLOCK); Dimension d = new Dimension(w, h); setPreferredSize(d); setSize(d); changeRenderSize(); setBounds(getTileBounds()); return model.getTileOrienation(); } /** * Depending on the block status change the background color
* - Red: Occupied
* - Green: Departure
* - Magenta: Arrival / entering
* - Yellow: reserved
* - White: all clear / default
* * @return the Color which belong with the current Block State */ Color getBlockStateColor() { return getBlockStateColor(this.model.getBlockState()); } protected Color getBlockStateColor(BlockState blockState) { return switch (blockState) { case GHOST -> new Color(250, 0, 0); case LOCKED -> new Color(250, 250, 210); case OCCUPIED -> new Color(250, 210, 210); case OUT_OF_ORDER -> new Color(190, 190, 190); case OUTBOUND -> new Color(210, 250, 210); case INBOUND -> new Color(250, 210, 250); default -> new Color(255, 255, 255); }; } public static String getDepartureSuffix(Orientation tileOrientation, boolean reverseArrival, LocomotiveBean.Direction direction) { if (LocomotiveBean.Direction.FORWARDS == direction) { if (Orientation.EAST == tileOrientation || Orientation.SOUTH == tileOrientation) { if (reverseArrival) { return "-"; } else { return "+"; } } else { if (reverseArrival) { return "+"; } else { return "-"; } } } else { if (Orientation.EAST == tileOrientation || Orientation.SOUTH == tileOrientation) { if (reverseArrival) { return "+"; } else { return "-"; } } else { if (reverseArrival) { return "-"; } else { return "+"; } } } } @Override public void renderTile(Graphics2D g2) { int xx = 20; int yy = 50; int rw = RENDER_WIDTH * 3 - 40; int rh = 300; g2.setStroke(new BasicStroke(3, BasicStroke.CAP_SQUARE, BasicStroke.JOIN_ROUND)); g2.setPaint(Color.darkGray); g2.drawRoundRect(xx, yy, rw, rh, 15, 15); Color blockStateColor = getBlockStateColor(); //Logger.trace("Block " + this.id + " State: " + this.getBlockBean().getBlockState().getState() + " Color: " + blockStateColor.toString()); g2.setPaint(blockStateColor); g2.fillRoundRect(xx, yy, rw, rh, 15, 15); g2.setStroke(new BasicStroke(20, BasicStroke.CAP_SQUARE, BasicStroke.JOIN_ROUND)); g2.setPaint(Color.darkGray); g2.drawLine(rw + GRID, yy - 0, rw + GRID, yy + 300); //When there is a locomotive in the block mark the direction of travel. //The default, forwards is in the direction of the block orientation, i.e. the + if (model.getLocomotive() != null && model.getLocomotive().getName() != null) { renderDirectionArrow(g2); } drawName(g2); } private void renderDirectionArrow(Graphics2D g2) { //The default, forwards is in the direction of the block orientation, i.e. the + Orientation tileOrientation = model.getTileOrienation(); BlockBean bb = this.getBlockBean(); boolean reverseArrival = model.isReverseArrival(); LocomotiveBean.Direction logicalDirection; if (bb.getLogicalDirection() != null) { logicalDirection = model.getLogicalDirection(); } else { logicalDirection = model.getLocomotive().getDirection(); } String departureSuffix = model.getDepartureSuffix(); if (departureSuffix == null) { departureSuffix = Block.getDepartureSuffix(tileOrientation, reverseArrival, logicalDirection); } //Logger.trace(this.getId()+" LogicalDirection is " + (bb.getLogicalDirection() != null ? "Set" : "Not Set") + " Dir: " + logicalDirection.getDirection() + " Orientation: " + orientation.getOrientation() + " departureSuffix: " + departureSuffix); if ("+".equals(departureSuffix)) { if (Orientation.EAST == tileOrientation || Orientation.SOUTH == tileOrientation) { switch (logicalDirection) { case LocomotiveBean.Direction.FORWARDS -> { if (reverseArrival) { renderLeftArrow(g2); } else { renderRightArrow(g2); } } case LocomotiveBean.Direction.BACKWARDS -> { if (reverseArrival) { renderRightArrow(g2); } else { renderLeftArrow(g2); } } } } else { switch (logicalDirection) { case LocomotiveBean.Direction.BACKWARDS -> { if (reverseArrival) { renderLeftArrow(g2); } else { renderRightArrow(g2); } } case LocomotiveBean.Direction.FORWARDS -> { if (reverseArrival) { renderRightArrow(g2); } else { renderLeftArrow(g2); } } } } } else { if (Orientation.EAST == tileOrientation || Orientation.SOUTH == tileOrientation) { switch (logicalDirection) { case LocomotiveBean.Direction.FORWARDS -> { if (reverseArrival) { renderLeftArrow(g2); } else { renderRightArrow(g2); } } case LocomotiveBean.Direction.BACKWARDS -> { if (reverseArrival) { renderRightArrow(g2); } else { renderLeftArrow(g2); } } } } else { switch (logicalDirection) { case LocomotiveBean.Direction.BACKWARDS -> { if (reverseArrival) { renderLeftArrow(g2); } else { renderRightArrow(g2); } } case LocomotiveBean.Direction.FORWARDS -> { if (reverseArrival) { renderRightArrow(g2); } else { renderLeftArrow(g2); } } } } } } private void renderLeftArrow(Graphics2D g2) { //Logger.trace(this.getId()+" LogicalDirection is " + this.getBlockBean().getLogicalDirection() + " Orientation: " + this.getOrientation() + " departureSuffix: " + this.getBlockBean().getDepartureSuffix()); g2.fillPolygon(new int[]{0, 50, 50,}, new int[]{200, 150, 250}, 3); } private void renderRightArrow(Graphics2D g2) { //Logger.trace(this.getId()+" LogicalDirection is " + this.getBlockBean().getLogicalDirection() + " Orientation: " + this.getOrientation() + " departureSuffix: " + this.getBlockBean().getDepartureSuffix()); g2.fillPolygon(new int[]{1180, 1130, 1130,}, new int[]{200, 150, 250}, 3); } @Override public void renderTileRoute(Graphics2D g2d) { if (model.isShowBlockState()) { backgroundColor = getBlockStateColor(model.getBlockState()); } } protected void overlayLocImage() { int ww = tileImage.getWidth(); int hh = tileImage.getHeight(); Orientation tileOrientation = model.getTileOrienation(); BufferedImage overlay = new BufferedImage(ww, hh, BufferedImage.TYPE_INT_ARGB); Graphics2D g2i = overlay.createGraphics(); Image locImage = getLocImage(); if (locImage != null) { String departureSuffix = model.getDepartureSuffix(); boolean reverseImage = model.isReverseArrival(); Logger.trace("LocImage w: " + locImage.getWidth(null) + " h: " + locImage.getHeight(null)); // scale it to max h of 45 int size = 45; float aspect = (float) locImage.getHeight(null) / (float) locImage.getWidth(null); //TODO: Use Scalr? locImage = locImage.getScaledInstance(size, (int) (size * aspect), Image.SCALE_SMOOTH); //Depending on the block orientation the image needs to be rotated and flipped //Incase the departure suffix is NOT set center the locomotive image int w, h, xx, yy; switch (tileOrientation) { case WEST -> { w = locImage.getWidth(null); h = locImage.getHeight(null); if (null == departureSuffix) { xx = BLOCK_WIDTH / 2 - getWidth() / 2 + w; } else { switch (departureSuffix) { case "+" -> { xx = BLOCK_WIDTH / 2 - getWidth() / 2 + w - 25; } default -> { xx = BLOCK_WIDTH / 2 - getWidth() / 2 + w + 10; } } } yy = DEFAULT_HEIGHT / 2 - h / 2; if (reverseImage) { locImage = ImageUtil.flipVertically(locImage); } } case SOUTH -> { locImage = ImageUtil.flipHorizontally(locImage); locImage = ImageUtil.rotate(locImage, 90); w = locImage.getWidth(null); h = locImage.getHeight(null); xx = DEFAULT_WIDTH / 2 - w / 2; if (null == departureSuffix) { yy = BLOCK_HEIGHT / 2 - getHeight() / 2 + h; } else { switch (departureSuffix) { case "-" -> { yy = BLOCK_HEIGHT / 2 - getHeight() / 2 + h - 25; } default -> { yy = BLOCK_HEIGHT / 2 - getHeight() / 2 + h + 10; } } } if (reverseImage) { locImage = ImageUtil.flipHorizontally(locImage); } } case NORTH -> { locImage = ImageUtil.flipHorizontally(locImage); locImage = ImageUtil.rotate(locImage, 90); w = locImage.getWidth(null); h = locImage.getHeight(null); xx = DEFAULT_WIDTH / 2 - w / 2; if (null == departureSuffix) { int minY = BLOCK_HEIGHT / 2 - getHeight() / 2 + h; yy = minY; } else { switch (departureSuffix) { case "+" -> { yy = BLOCK_HEIGHT / 2 - getHeight() / 2 + h - 25; } default -> { yy = BLOCK_HEIGHT / 2 - getHeight() / 2 + h + 10; } } } if (reverseImage) { locImage = ImageUtil.flipHorizontally(locImage); } } default -> { w = locImage.getWidth(null); h = locImage.getHeight(null); if (null == departureSuffix) { xx = BLOCK_WIDTH / 2 - getWidth() / 2 + w; } else { switch (departureSuffix) { case "-" -> { xx = BLOCK_WIDTH / 2 - getWidth() / 2 + w - 25; } default -> { xx = BLOCK_WIDTH / 2 - getWidth() / 2 + w + 10; } } } yy = DEFAULT_HEIGHT / 2 - h / 2; if (reverseImage) { locImage = ImageUtil.flipVertically(locImage); } } } g2i.drawImage(tileImage, 0, 0, null); g2i.drawImage(locImage, xx, yy, null); g2i.dispose(); tileImage = overlay; } } private Image getLocImage() { if (model.getLocomotive() != null && model.getLocomotive().getLocIcon() != null) { return model.getLocomotive().getLocIcon(); } else { return null; } } public String getBlockText() { String blockText; if (blockBean != null && blockBean.getDescription() != null) { if (blockBean.getLocomotive() != null && blockBean.getLocomotive().getName() != null && BlockState.GHOST != blockBean.getBlockState()) { blockText = blockBean.getLocomotive().getName(); } else { if (blockBean.getDescription().length() > 0) { blockText = blockBean.getDescription(); } else { blockText = getId(); } } } else { // Design mode show description when available if (blockBean != null && blockBean.getDescription() != null && blockBean.getDescription().length() > 0) { blockText = blockBean.getDescription(); } else { blockText = getId(); } } return blockText; } @Override public void drawName(Graphics2D g2d) { if (!model.isOverlayImage()) { g2d.setPaint(Color.black); Font currentFont = g2d.getFont(); Font newFont = currentFont.deriveFont(currentFont.getSize() * 10.0F); g2d.setFont(newFont); String blockText = getBlockText(); // Scale the text if necessary int textWidth = g2d.getFontMetrics().stringWidth(blockText); double fontscale = 10.0; if (textWidth > 845) { fontscale = fontscale * 847.0 / textWidth; newFont = currentFont.deriveFont(currentFont.getSize() * (float) fontscale); g2d.setFont(newFont); textWidth = g2d.getFontMetrics().stringWidth(blockText); } int textHeight = g2d.getFontMetrics().getHeight(); Orientation tileOrientation = model.getTileOrienation(); switch (tileOrientation) { case EAST -> { drawRotate(g2d, ((RENDER_WIDTH * 3) / 2) - textWidth / 2, RENDER_GRID + textHeight / 3, 0, blockText); } case WEST -> { drawRotate(g2d, ((RENDER_WIDTH * 3) / 2) + textWidth / 2, RENDER_GRID - textHeight / 3, 180, blockText); } case NORTH -> { drawRotate(g2d, ((RENDER_WIDTH * 3) / 2) - textWidth / 2, RENDER_GRID + textHeight / 3, 0, blockText); } case SOUTH -> { drawRotate(g2d, ((RENDER_WIDTH * 3) / 2) + textWidth / 2, RENDER_GRID - textHeight / 3, 180, blockText); } } // reset to the original font newFont = currentFont.deriveFont(currentFont.getSize() * 1.0F); g2d.setFont(newFont); } } @Override public Rectangle getTileBounds() { int multiplier = (model.isScaleImage() ? 1 : 10); Orientation tileOrientation = model.getTileOrienation(); int xx, yy; if (tileOrientation == Orientation.EAST || tileOrientation == Orientation.WEST) { xx = tileX - GRID * multiplier - GRID * multiplier * 2; yy = tileY - GRID * multiplier; } else { xx = tileX - GRID * multiplier; yy = tileY - GRID * multiplier - GRID * multiplier * 2; } if (model.isScaleImage()) { return new Rectangle(xx, yy, tileWidth(tileOrientation, TileType.BLOCK), tileHeight(tileOrientation, TileType.BLOCK)); } else { return new Rectangle(xx, yy, renderWidth, renderHeight); } } @Override protected void paintComponent(Graphics g) { long started = System.currentTimeMillis(); Graphics2D g2 = (Graphics2D) g.create(); drawTile(g2); g2.dispose(); if (model.isOverlayImage()) { overlayLocImage(); } g.drawImage(tileImage, 0, 0, null); long now = System.currentTimeMillis(); Logger.trace(id + " Duration: " + (now - started) + " ms."); } @Override protected void drawCenterPoint(Graphics2D g2d, Color color, double size) { //A block has 2 alternate points //1st square //2nd square holds the centerpoint //3rd square Orientation tileOrientation = model.getTileOrienation(); double dX1, dX2, dX3, dY1, dY2, dY3; if (Orientation.EAST == tileOrientation || Orientation.WEST == tileOrientation) { dX1 = renderWidth / 3 / 2 - size / 2 / 2; dY1 = renderHeight / 2 - size / 2 / 2; dX2 = renderWidth / 2 - size / 2; dY2 = renderHeight / 2 - size / 2; dX3 = renderWidth - renderWidth / 3 / 2 - size / 2 / 2; dY3 = renderHeight / 2 - size / 2 / 2; } else { dX1 = renderWidth / 2 - size / 2 / 2; dY1 = renderHeight / 3 / 2 - size / 2 / 2; dX2 = renderHeight / 2 - size / 2; dY2 = renderWidth / 2 - size / 2; dY3 = renderWidth / 2 - size / 2 / 2; dX3 = renderHeight - renderHeight / 3 / 2 - size / 2 / 2; } g2d.setColor(color); g2d.fill(new Ellipse2D.Double(dX1, dY1, size / 2, size / 2)); g2d.fill(new Ellipse2D.Double(dX2, dY2, size, size)); g2d.fill(new Ellipse2D.Double(dX3, dY3, size / 2, size / 2)); } } \ No newline at end of file +/* * Copyright 2024 Frans Jacobs. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package jcs.ui.layout.tiles; import java.awt.BasicStroke; import java.awt.Color; import java.awt.Dimension; import java.awt.Font; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.Image; import java.awt.Point; import java.awt.Rectangle; import java.awt.geom.Ellipse2D; import java.awt.image.BufferedImage; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set; import jcs.entities.BlockBean; import jcs.entities.BlockBean.BlockState; import jcs.entities.LocomotiveBean; import jcs.entities.TileBean; import jcs.entities.TileBean.Orientation; import static jcs.entities.TileBean.Orientation.EAST; import static jcs.entities.TileBean.Orientation.NORTH; import static jcs.entities.TileBean.Orientation.SOUTH; import static jcs.entities.TileBean.Orientation.WEST; import jcs.entities.TileBean.TileType; import static jcs.ui.layout.tiles.Tile.DEFAULT_HEIGHT; import static jcs.ui.layout.tiles.Tile.DEFAULT_WIDTH; import static jcs.ui.layout.tiles.Tile.GRID; import static jcs.ui.layout.tiles.Tile.RENDER_HEIGHT; import static jcs.ui.layout.tiles.Tile.RENDER_WIDTH; import jcs.ui.util.ImageUtil; import org.tinylog.Logger; public class Block extends Tile { public static final int BLOCK_WIDTH = DEFAULT_WIDTH * 3; public static final int BLOCK_HEIGHT = DEFAULT_HEIGHT * 3; public Block(TileBean tileBean) { super(tileBean); setModel(new DefaultTileModel(tileBean.getOrientation())); changeRenderSize(); populateModel(); } public Block(Orientation orientation, Point center) { this(orientation, center.x, center.y); } public Block(Orientation orientation, int x, int y) { this(orientation, x, y, tileWidth(orientation, TileType.BLOCK), tileHeight(orientation, TileType.BLOCK)); } public Block(Orientation orientation, int x, int y, int width, int height) { super(TileType.BLOCK, orientation, x, y, width, height); setModel(new DefaultTileModel(orientation)); changeRenderSize(); } private void changeRenderSize() { Orientation tileOrientation = model.getTileOrienation(); if (Orientation.EAST == tileOrientation || Orientation.WEST == tileOrientation) { this.renderWidth = RENDER_WIDTH * 3; this.renderHeight = RENDER_HEIGHT; } else { this.renderWidth = RENDER_WIDTH; this.renderHeight = RENDER_HEIGHT * 3; } } @Override public Set getAltPoints() { int xx = this.tileX; int yy = this.tileY; Set alternatives = new HashSet<>(); if (Orientation.EAST.equals(getOrientation()) || Orientation.WEST.equals(getOrientation())) { // West Point wp = new Point((xx - DEFAULT_WIDTH), yy); Point ep = new Point((xx + DEFAULT_WIDTH), yy); alternatives.add(wp); alternatives.add(ep); } else { Point np = new Point(xx, (yy - DEFAULT_HEIGHT)); Point sp = new Point(xx, (yy + DEFAULT_HEIGHT)); alternatives.add(np); alternatives.add(sp); } return alternatives; } @Override public Set getAllPoints() { Set aps = new HashSet<>(); aps.add(getCenter()); aps.addAll(getAltPoints()); return aps; } @Override Set getAllPoints(Point center) { Set points = getAltPoints(center); points.add(center); return points; } @Override Set getAltPoints(Point center) { Set alts = new HashSet<>(); if (Orientation.EAST == model.getTileOrienation() || Orientation.WEST == model.getTileOrienation()) { // West Point wp = new Point((center.x - DEFAULT_WIDTH), center.y); Point ep = new Point((center.x + DEFAULT_WIDTH), center.y); alts.add(wp); alts.add(ep); } else { Point np = new Point(center.x, (center.y - DEFAULT_HEIGHT)); Point sp = new Point(center.x, (center.y + DEFAULT_HEIGHT)); alts.add(np); alts.add(sp); } return alts; } public Point getAltPoint(String suffix) { int cx = this.getCenterX(); int cy = this.getCenterY(); if ("+".equals(suffix)) { return switch (this.getOrientation()) { case WEST -> new Point(cx - Tile.GRID * 2, cy); case NORTH -> new Point(cx, cy - Tile.GRID * 2); case SOUTH -> new Point(cx, cy + Tile.GRID * 2); default -> new Point(cx + Tile.GRID * 2, cy); }; } else { return switch (this.getOrientation()) { case EAST -> new Point(cx - Tile.GRID * 2, cy); case SOUTH -> new Point(cx, cy - Tile.GRID * 2); case NORTH -> new Point(cx, cy + Tile.GRID * 2); default -> new Point(cx + Tile.GRID * 2, cy); }; } } @Override public boolean isBlock() { return true; } @Override public Map getNeighborPoints() { Map neighbors = new HashMap<>(); Orientation orientation = this.getOrientation(); int cx = this.getCenterX(); int cy = this.getCenterY(); // Horizontal if (Orientation.EAST == orientation || Orientation.WEST == orientation) { neighbors.put(Orientation.EAST, new Point(cx + Tile.GRID * 4, cy)); neighbors.put(Orientation.WEST, new Point(cx - Tile.GRID * 4, cy)); } else { // Vertical neighbors.put(Orientation.NORTH, new Point(cx, cy - Tile.GRID * 4)); neighbors.put(Orientation.SOUTH, new Point(cx, cy + Tile.GRID * 4)); } return neighbors; } @Override public Map getEdgePoints() { Map edgeConnections = new HashMap<>(); Orientation orientation = this.getOrientation(); int cx = this.getCenterX(); int cy = this.getCenterY(); // Horizontal if (Orientation.EAST == orientation || Orientation.WEST == orientation) { edgeConnections.put(Orientation.EAST, new Point(cx + Tile.GRID * 3, cy)); edgeConnections.put(Orientation.WEST, new Point(cx - Tile.GRID * 3, cy)); } else { // Vertical edgeConnections.put(Orientation.NORTH, new Point(cx, cy - Tile.GRID * 3)); edgeConnections.put(Orientation.SOUTH, new Point(cx, cy + Tile.GRID * 3)); } return edgeConnections; } public Point getNeighborPoint(String suffix) { int cx = getCenterX(); int cy = getCenterY(); if ("+".equals(suffix)) { return switch (getOrientation()) { case WEST -> new Point(cx - Tile.GRID * 4, cy); case NORTH -> new Point(cx, cy - Tile.GRID * 4); case SOUTH -> new Point(cx, cy + Tile.GRID * 4); default -> new Point(cx + Tile.GRID * 4, cy); }; } else { return switch (getOrientation()) { case EAST -> new Point(cx - Tile.GRID * 4, cy); case SOUTH -> new Point(cx, cy - Tile.GRID * 4); case NORTH -> new Point(cx, cy + Tile.GRID * 4); default -> new Point(cx + Tile.GRID * 4, cy); }; } } public Orientation getTravelDirection(String suffix) { if ("+".equals(suffix)) { return getOrientation(); } else { return switch (getOrientation()) { case EAST -> Orientation.WEST; case SOUTH -> Orientation.NORTH; case NORTH -> Orientation.SOUTH; default -> Orientation.EAST; }; } } @Override public String getIdSuffix(Tile other) { String suffix = null; Orientation match = null; if (isAdjacent(other)) { Map blockSides = this.getEdgePoints(); Map otherSides = other.getEdgePoints(); for (Orientation bo : Orientation.values()) { Point bp = blockSides.get(bo); if (bp != null) { for (Orientation oo : Orientation.values()) { Point op = otherSides.get(oo); if (op != null) { if (op.equals(bp)) { match = bo; break; } } } } } } Orientation tileOrientation = model.getTileOrienation(); if (match != null) { if (Orientation.EAST == tileOrientation && Orientation.EAST == match) { suffix = "+"; } if (Orientation.WEST == tileOrientation && Orientation.WEST == match) { suffix = "+"; } if (Orientation.EAST == tileOrientation && Orientation.WEST == match) { suffix = "-"; } if (Orientation.WEST == tileOrientation && Orientation.EAST == match) { suffix = "-"; } if (Orientation.NORTH == tileOrientation && Orientation.NORTH == match) { suffix = "+"; } if (Orientation.NORTH == tileOrientation && Orientation.SOUTH == match) { suffix = "-"; } if (Orientation.SOUTH == tileOrientation && Orientation.SOUTH == match) { suffix = "+"; } if (Orientation.SOUTH == tileOrientation && Orientation.NORTH == match) { suffix = "-"; } } return suffix; } @Override public Orientation rotate() { super.rotate(); Orientation tileOrientation = model.getTileOrienation(); int w = tileWidth(tileOrientation, TileType.BLOCK); int h = tileHeight(tileOrientation, TileType.BLOCK); Dimension d = new Dimension(w, h); setPreferredSize(d); setSize(d); changeRenderSize(); setBounds(getTileBounds()); return model.getTileOrienation(); } /** * Depending on the block status change the background color
* - Red: Occupied
* - Green: Departure
* - Magenta: Arrival / entering
* - Yellow: reserved
* - White: all clear / default
* * @return the Color which belong with the current Block State */ Color getBlockStateColor() { return getBlockStateColor(this.model.getBlockState()); } protected Color getBlockStateColor(BlockState blockState) { return switch (blockState) { case GHOST -> new Color(250, 0, 0); case LOCKED -> new Color(250, 250, 210); case OCCUPIED -> new Color(250, 210, 210); case OUT_OF_ORDER -> new Color(190, 190, 190); case OUTBOUND -> new Color(210, 250, 210); case INBOUND -> new Color(250, 210, 250); default -> new Color(255, 255, 255); }; } public static String getDepartureSuffix(Orientation tileOrientation, boolean reverseArrival, LocomotiveBean.Direction direction) { if (LocomotiveBean.Direction.FORWARDS == direction) { if (Orientation.EAST == tileOrientation || Orientation.SOUTH == tileOrientation) { if (reverseArrival) { return "-"; } else { return "+"; } } else { if (reverseArrival) { return "+"; } else { return "-"; } } } else { if (Orientation.EAST == tileOrientation || Orientation.SOUTH == tileOrientation) { if (reverseArrival) { return "+"; } else { return "-"; } } else { if (reverseArrival) { return "-"; } else { return "+"; } } } } @Override public void renderTile(Graphics2D g2) { int xx = 20; int yy = 50; int rw = RENDER_WIDTH * 3 - 40; int rh = 300; g2.setStroke(new BasicStroke(3, BasicStroke.CAP_SQUARE, BasicStroke.JOIN_ROUND)); g2.setPaint(Color.darkGray); g2.drawRoundRect(xx, yy, rw, rh, 15, 15); Color blockStateColor = getBlockStateColor(); //Logger.trace("Block " + this.id + " State: " + this.getBlockBean().getBlockState().getState() + " Color: " + blockStateColor.toString()); g2.setPaint(blockStateColor); g2.fillRoundRect(xx, yy, rw, rh, 15, 15); g2.setStroke(new BasicStroke(20, BasicStroke.CAP_SQUARE, BasicStroke.JOIN_ROUND)); g2.setPaint(Color.darkGray); g2.drawLine(rw + GRID, yy - 0, rw + GRID, yy + 300); //When there is a locomotive in the block mark the direction of travel. //The default, forwards is in the direction of the block orientation, i.e. the + if (model.getLocomotive() != null && model.getLocomotive().getName() != null) { renderDirectionArrow(g2); } drawName(g2); } private void renderDirectionArrow(Graphics2D g2) { //The default, forwards is in the direction of the block orientation, i.e. the + Orientation tileOrientation = model.getTileOrienation(); BlockBean bb = this.getBlockBean(); boolean reverseArrival = model.isReverseArrival(); LocomotiveBean.Direction logicalDirection; if (bb.getLogicalDirection() != null) { logicalDirection = model.getLogicalDirection(); } else { logicalDirection = model.getLocomotive().getDirection(); } String departureSuffix = model.getDepartureSuffix(); if (departureSuffix == null) { departureSuffix = Block.getDepartureSuffix(tileOrientation, reverseArrival, logicalDirection); } //Logger.trace(this.getId()+" LogicalDirection is " + (bb.getLogicalDirection() != null ? "Set" : "Not Set") + " Dir: " + logicalDirection.getDirection() + " Orientation: " + orientation.getOrientation() + " departureSuffix: " + departureSuffix); if ("+".equals(departureSuffix)) { if (Orientation.EAST == tileOrientation || Orientation.SOUTH == tileOrientation) { switch (logicalDirection) { case LocomotiveBean.Direction.FORWARDS -> { if (reverseArrival) { renderLeftArrow(g2); } else { renderRightArrow(g2); } } case LocomotiveBean.Direction.BACKWARDS -> { if (reverseArrival) { renderRightArrow(g2); } else { renderLeftArrow(g2); } } } } else { switch (logicalDirection) { case LocomotiveBean.Direction.BACKWARDS -> { if (reverseArrival) { renderLeftArrow(g2); } else { renderRightArrow(g2); } } case LocomotiveBean.Direction.FORWARDS -> { if (reverseArrival) { renderRightArrow(g2); } else { renderLeftArrow(g2); } } } } } else { if (Orientation.EAST == tileOrientation || Orientation.SOUTH == tileOrientation) { switch (logicalDirection) { case LocomotiveBean.Direction.FORWARDS -> { if (reverseArrival) { renderLeftArrow(g2); } else { renderRightArrow(g2); } } case LocomotiveBean.Direction.BACKWARDS -> { if (reverseArrival) { renderRightArrow(g2); } else { renderLeftArrow(g2); } } } } else { switch (logicalDirection) { case LocomotiveBean.Direction.BACKWARDS -> { if (reverseArrival) { renderLeftArrow(g2); } else { renderRightArrow(g2); } } case LocomotiveBean.Direction.FORWARDS -> { if (reverseArrival) { renderRightArrow(g2); } else { renderLeftArrow(g2); } } } } } } private void renderLeftArrow(Graphics2D g2) { //Logger.trace(this.getId()+" LogicalDirection is " + this.getBlockBean().getLogicalDirection() + " Orientation: " + this.getOrientation() + " departureSuffix: " + this.getBlockBean().getDepartureSuffix()); g2.fillPolygon(new int[]{0, 50, 50,}, new int[]{200, 150, 250}, 3); } private void renderRightArrow(Graphics2D g2) { //Logger.trace(this.getId()+" LogicalDirection is " + this.getBlockBean().getLogicalDirection() + " Orientation: " + this.getOrientation() + " departureSuffix: " + this.getBlockBean().getDepartureSuffix()); g2.fillPolygon(new int[]{1180, 1130, 1130,}, new int[]{200, 150, 250}, 3); } @Override public void renderTileRoute(Graphics2D g2d) { if (model.isShowBlockState()) { backgroundColor = getBlockStateColor(model.getBlockState()); } } protected void overlayLocImage() { int ww = tileImage.getWidth(); int hh = tileImage.getHeight(); Orientation tileOrientation = model.getTileOrienation(); BufferedImage overlay = new BufferedImage(ww, hh, BufferedImage.TYPE_INT_ARGB); Graphics2D g2i = overlay.createGraphics(); Image locImage = getLocImage(); if (locImage != null) { String departureSuffix = model.getDepartureSuffix(); boolean reverseImage = model.isReverseArrival(); Logger.trace("LocImage w: " + locImage.getWidth(null) + " h: " + locImage.getHeight(null)); // scale it to max h of 45 int size = 45; float aspect = (float) locImage.getHeight(null) / (float) locImage.getWidth(null); //TODO: Use Scalr? locImage = locImage.getScaledInstance(size, (int) (size * aspect), Image.SCALE_SMOOTH); //Depending on the block orientation the image needs to be rotated and flipped //Incase the departure suffix is NOT set center the locomotive image int w, h, xx, yy; switch (tileOrientation) { case WEST -> { w = locImage.getWidth(null); h = locImage.getHeight(null); if (null == departureSuffix) { xx = BLOCK_WIDTH / 2 - getWidth() / 2 + w; } else { switch (departureSuffix) { case "+" -> { xx = BLOCK_WIDTH / 2 - getWidth() / 2 + w - 25; } default -> { xx = BLOCK_WIDTH / 2 - getWidth() / 2 + w + 10; } } } yy = DEFAULT_HEIGHT / 2 - h / 2; if (reverseImage) { locImage = ImageUtil.flipVertically(locImage); } } case SOUTH -> { locImage = ImageUtil.flipHorizontally(locImage); locImage = ImageUtil.rotate(locImage, 90); w = locImage.getWidth(null); h = locImage.getHeight(null); xx = DEFAULT_WIDTH / 2 - w / 2; if (null == departureSuffix) { yy = BLOCK_HEIGHT / 2 - getHeight() / 2 + h; } else { switch (departureSuffix) { case "-" -> { yy = BLOCK_HEIGHT / 2 - getHeight() / 2 + h - 25; } default -> { yy = BLOCK_HEIGHT / 2 - getHeight() / 2 + h + 10; } } } if (reverseImage) { locImage = ImageUtil.flipHorizontally(locImage); } } case NORTH -> { locImage = ImageUtil.flipHorizontally(locImage); locImage = ImageUtil.rotate(locImage, 90); w = locImage.getWidth(null); h = locImage.getHeight(null); xx = DEFAULT_WIDTH / 2 - w / 2; if (null == departureSuffix) { int minY = BLOCK_HEIGHT / 2 - getHeight() / 2 + h; yy = minY; } else { switch (departureSuffix) { case "+" -> { yy = BLOCK_HEIGHT / 2 - getHeight() / 2 + h - 25; } default -> { yy = BLOCK_HEIGHT / 2 - getHeight() / 2 + h + 10; } } } if (reverseImage) { locImage = ImageUtil.flipHorizontally(locImage); } } default -> { w = locImage.getWidth(null); h = locImage.getHeight(null); if (null == departureSuffix) { xx = BLOCK_WIDTH / 2 - getWidth() / 2 + w; } else { switch (departureSuffix) { case "-" -> { xx = BLOCK_WIDTH / 2 - getWidth() / 2 + w - 25; } default -> { xx = BLOCK_WIDTH / 2 - getWidth() / 2 + w + 10; } } } yy = DEFAULT_HEIGHT / 2 - h / 2; if (reverseImage) { locImage = ImageUtil.flipVertically(locImage); } } } g2i.drawImage(tileImage, 0, 0, null); g2i.drawImage(locImage, xx, yy, null); g2i.dispose(); tileImage = overlay; } } private Image getLocImage() { if (model.getLocomotive() != null && model.getLocomotive().getLocIcon() != null) { return model.getLocomotive().getLocIcon(); } else { return null; } } public String getBlockText() { String blockText; if (blockBean != null && blockBean.getDescription() != null) { if (blockBean.getLocomotive() != null && blockBean.getLocomotive().getName() != null && BlockState.GHOST != blockBean.getBlockState()) { blockText = blockBean.getLocomotive().getName(); } else { if (blockBean.getDescription().length() > 0) { blockText = blockBean.getDescription(); } else { blockText = getId(); } } } else { // Design mode show description when available if (blockBean != null && blockBean.getDescription() != null && blockBean.getDescription().length() > 0) { blockText = blockBean.getDescription(); } else { blockText = getId(); } } return blockText; } @Override public void drawName(Graphics2D g2d) { if (!model.isOverlayImage()) { g2d.setPaint(Color.black); Font currentFont = g2d.getFont(); Font newFont = currentFont.deriveFont(currentFont.getSize() * 10.0F); g2d.setFont(newFont); String blockText = getBlockText(); // Scale the text if necessary int textWidth = g2d.getFontMetrics().stringWidth(blockText); double fontscale = 10.0; if (textWidth > 845) { fontscale = fontscale * 847.0 / textWidth; newFont = currentFont.deriveFont(currentFont.getSize() * (float) fontscale); g2d.setFont(newFont); textWidth = g2d.getFontMetrics().stringWidth(blockText); } int textHeight = g2d.getFontMetrics().getHeight(); Orientation tileOrientation = model.getTileOrienation(); switch (tileOrientation) { case EAST -> { drawRotate(g2d, ((RENDER_WIDTH * 3) / 2) - textWidth / 2, RENDER_GRID + textHeight / 3, 0, blockText); } case WEST -> { drawRotate(g2d, ((RENDER_WIDTH * 3) / 2) + textWidth / 2, RENDER_GRID - textHeight / 3, 180, blockText); } case NORTH -> { drawRotate(g2d, ((RENDER_WIDTH * 3) / 2) - textWidth / 2, RENDER_GRID + textHeight / 3, 0, blockText); } case SOUTH -> { drawRotate(g2d, ((RENDER_WIDTH * 3) / 2) + textWidth / 2, RENDER_GRID - textHeight / 3, 180, blockText); } } // reset to the original font newFont = currentFont.deriveFont(currentFont.getSize() * 1.0F); g2d.setFont(newFont); } } @Override public Rectangle getTileBounds() { int multiplier = (model.isScaleImage() ? 1 : 10); Orientation tileOrientation = model.getTileOrienation(); int xx, yy; if (tileOrientation == Orientation.EAST || tileOrientation == Orientation.WEST) { xx = tileX - GRID * multiplier - GRID * multiplier * 2; yy = tileY - GRID * multiplier; } else { xx = tileX - GRID * multiplier; yy = tileY - GRID * multiplier - GRID * multiplier * 2; } if (model.isScaleImage()) { return new Rectangle(xx, yy, tileWidth(tileOrientation, TileType.BLOCK), tileHeight(tileOrientation, TileType.BLOCK)); } else { return new Rectangle(xx, yy, renderWidth, renderHeight); } } @Override protected void paintComponent(Graphics g) { long started = System.currentTimeMillis(); Graphics2D g2 = (Graphics2D) g.create(); drawTile(g2); g2.dispose(); if (model.isOverlayImage()) { overlayLocImage(); } g.drawImage(tileImage, 0, 0, null); long now = System.currentTimeMillis(); Logger.trace(id + " Duration: " + (now - started) + " ms."); } @Override protected void drawCenterPoint(Graphics2D g2d, Color color, double size) { //A block has 2 alternate points //1st square //2nd square holds the centerpoint //3rd square Orientation tileOrientation = model.getTileOrienation(); double dX1, dX2, dX3, dY1, dY2, dY3; if (Orientation.EAST == tileOrientation || Orientation.WEST == tileOrientation) { dX1 = renderWidth / 3 / 2 - size / 2 / 2; dY1 = renderHeight / 2 - size / 2 / 2; dX2 = renderWidth / 2 - size / 2; dY2 = renderHeight / 2 - size / 2; dX3 = renderWidth - renderWidth / 3 / 2 - size / 2 / 2; dY3 = renderHeight / 2 - size / 2 / 2; } else { dX1 = renderWidth / 2 - size / 2 / 2; dY1 = renderHeight / 3 / 2 - size / 2 / 2; dX2 = renderHeight / 2 - size / 2; dY2 = renderWidth / 2 - size / 2; dY3 = renderWidth / 2 - size / 2 / 2; dX3 = renderHeight - renderHeight / 3 / 2 - size / 2 / 2; } g2d.setColor(color); g2d.fill(new Ellipse2D.Double(dX1, dY1, size / 2, size / 2)); g2d.fill(new Ellipse2D.Double(dX2, dY2, size, size)); g2d.fill(new Ellipse2D.Double(dX3, dY3, size / 2, size / 2)); } } \ No newline at end of file diff --git a/src/main/java/jcs/ui/layout/tiles/Cross.java b/src/main/java/jcs/ui/layout/tiles/Cross.java index 4777b114..419a693f 100644 --- a/src/main/java/jcs/ui/layout/tiles/Cross.java +++ b/src/main/java/jcs/ui/layout/tiles/Cross.java @@ -1,668 +1 @@ -/* - * Copyright 2023 Frans Jacobs. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package jcs.ui.layout.tiles; - -import java.awt.BasicStroke; -import java.awt.Color; -import java.awt.Dimension; -import java.awt.Graphics2D; -import java.awt.Point; -import java.awt.Rectangle; -import java.awt.geom.Ellipse2D; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Map; -import java.util.Set; -import jcs.entities.AccessoryBean.AccessoryValue; -import static jcs.entities.AccessoryBean.AccessoryValue.GREEN; -import static jcs.entities.AccessoryBean.AccessoryValue.RED; -import jcs.entities.TileBean; -import jcs.entities.TileBean.Direction; -import jcs.entities.TileBean.Orientation; -import static jcs.entities.TileBean.Orientation.NORTH; -import static jcs.entities.TileBean.Orientation.SOUTH; -import static jcs.entities.TileBean.Orientation.WEST; -import jcs.entities.TileBean.TileType; -import static jcs.ui.layout.tiles.Tile.DEFAULT_HEIGHT; -import static jcs.ui.layout.tiles.Tile.DEFAULT_WIDTH; -import static jcs.ui.layout.tiles.Tile.GRID; -import static jcs.ui.layout.tiles.Tile.tileHeight; -import static jcs.ui.layout.tiles.Tile.tileWidth; - -public class Cross extends Switch { - - public static final int CROSS_WIDTH = DEFAULT_WIDTH * 2; - public static final int CROSS_HEIGHT = DEFAULT_HEIGHT * 2; - - public static final Color VERY_LIGHT_RED = new Color(255, 102, 102); - public static final Color LIGHT_RED = new Color(255, 51, 51); - public static final Color DARK_RED = new Color(204, 0, 0); - - public static final Color VERY_LIGHT_GREEN = new Color(102, 255, 102); - public static final Color LIGHT_GREEN = new Color(0, 255, 51); - public static final Color DARK_GREEN = new Color(0, 153, 0); - - public Cross(Orientation orientation, Direction direction, Point center) { - this(orientation, direction, center.x, center.y); - } - - public Cross(Orientation orientation, Direction direction, int x, int y) { - this(orientation, direction, x, y, tileWidth(orientation, TileType.CROSS), tileHeight(orientation, TileType.CROSS)); - } - - public Cross(Orientation orientation, Direction direction, int x, int y, int width, int height) { - super(TileType.CROSS, orientation, direction, x, y, width, height); - changeRenderSizeAndOffsets(); - } - - public Cross(TileBean tileBean) { - super(tileBean, tileWidth(tileBean.getOrientation(), TileType.CROSS), tileHeight(tileBean.getOrientation(), TileType.CROSS)); - changeRenderSizeAndOffsets(); - } - - /** - * A Cross has a width in horizontal position of 2 tiles and a height of 1 tile in Vertical position.
- * - * @return the set of center point which mark the position of the Cross - */ - @Override - public Set getAltPoints() { - Set alternatives = new HashSet<>(); - - switch (getOrientation()) { - case SOUTH -> { - Point sp = new Point(tileX, (tileY + DEFAULT_HEIGHT)); - alternatives.add(sp); - } - case WEST -> { - Point wp = new Point((tileX - DEFAULT_WIDTH), tileY); - alternatives.add(wp); - } - case NORTH -> { - Point np = new Point(tileX, (tileY - DEFAULT_HEIGHT)); - alternatives.add(np); - } - default -> { - //East so default - Point ep = new Point((tileX + DEFAULT_WIDTH), tileY); - alternatives.add(ep); - } - } - return alternatives; - } - - @Override - public Map getNeighborPoints() { - Map neighbors = new HashMap<>(); - Orientation orientation = this.getOrientation(); - Direction direction = this.getDirection(); - int cx = this.getCenterX(); - int cy = this.getCenterY(); - - switch (orientation) { - case SOUTH -> { - neighbors.put(Orientation.NORTH, new Point(cx, cy - Tile.GRID * 2)); - neighbors.put(Orientation.SOUTH, new Point(cx, cy + Tile.GRID * 4)); - - if (Direction.LEFT == direction) { - neighbors.put(Orientation.EAST, new Point(cx + Tile.GRID * 2, cy + Tile.GRID * 2)); - neighbors.put(Orientation.WEST, new Point(cx - Tile.GRID * 2, cy)); - } else { - neighbors.put(Orientation.EAST, new Point(cx + Tile.GRID * 2, cy)); - neighbors.put(Orientation.WEST, new Point(cx - Tile.GRID * 2, cy + Tile.GRID * 2)); - } - } - case WEST -> { - neighbors.put(Orientation.EAST, new Point(cx + Tile.GRID * 2, cy)); - neighbors.put(Orientation.WEST, new Point(cx - Tile.GRID * 4, cy)); - - if (Direction.LEFT == direction) { - neighbors.put(Orientation.NORTH, new Point(cx, cy - Tile.GRID * 2)); - neighbors.put(Orientation.SOUTH, new Point(cx - Tile.GRID * 2, cy + Tile.GRID * 2)); - } else { - neighbors.put(Orientation.NORTH, new Point(cx - Tile.GRID * 2, cy - Tile.GRID * 2)); - neighbors.put(Orientation.SOUTH, new Point(cx, cy + Tile.GRID * 2)); - } - } - case NORTH -> { - neighbors.put(Orientation.NORTH, new Point(cx, cy - Tile.GRID * 4)); - neighbors.put(Orientation.SOUTH, new Point(cx, cy + Tile.GRID * 2)); - - if (Direction.LEFT == direction) { - neighbors.put(Orientation.EAST, new Point(cx + Tile.GRID * 2, cy)); - neighbors.put(Orientation.WEST, new Point(cx - Tile.GRID * 2, cy - Tile.GRID * 2)); - } else { - neighbors.put(Orientation.EAST, new Point(cx + Tile.GRID * 2, cy - Tile.GRID * 2)); - neighbors.put(Orientation.WEST, new Point(cx - Tile.GRID * 2, cy)); - } - } - default -> { - //EAST - neighbors.put(Orientation.EAST, new Point(cx + Tile.GRID * 4, cy)); - neighbors.put(Orientation.WEST, new Point(cx - Tile.GRID * 2, cy)); - - if (Direction.LEFT == direction) { - neighbors.put(Orientation.NORTH, new Point(cx + Tile.GRID * 2, cy - Tile.GRID * 2)); - neighbors.put(Orientation.SOUTH, new Point(cx, cy + Tile.GRID * 2)); - } else { - neighbors.put(Orientation.NORTH, new Point(cx, cy - Tile.GRID * 2)); - neighbors.put(Orientation.SOUTH, new Point(cx + Tile.GRID * 2, cy + Tile.GRID * 2)); - } - } - } - return neighbors; - } - - @Override - public Map getEdgePoints() { - Map edgeConnections = new HashMap<>(); - Orientation orientation = this.getOrientation(); - Direction direction = this.getDirection(); - int cx = this.getCenterX(); - int cy = this.getCenterY(); - - switch (orientation) { - case SOUTH -> { - edgeConnections.put(Orientation.NORTH, new Point(cx, cy - Tile.GRID)); - edgeConnections.put(Orientation.SOUTH, new Point(cx, cy + Tile.GRID * 3)); - - if (Direction.LEFT == direction) { - edgeConnections.put(Orientation.EAST, new Point(cx + Tile.GRID, cy + Tile.GRID * 2)); - edgeConnections.put(Orientation.WEST, new Point(cx - Tile.GRID, cy)); - } else { - edgeConnections.put(Orientation.EAST, new Point(cx + Tile.GRID, cy)); - edgeConnections.put(Orientation.WEST, new Point(cx - Tile.GRID, cy + Tile.GRID * 2)); - } - } - case WEST -> { - edgeConnections.put(Orientation.EAST, new Point(cx + Tile.GRID, cy)); - edgeConnections.put(Orientation.WEST, new Point(cx - Tile.GRID * 3, cy)); - - if (Direction.LEFT == direction) { - edgeConnections.put(Orientation.NORTH, new Point(cx, cy - Tile.GRID)); - edgeConnections.put(Orientation.SOUTH, new Point(cx - Tile.GRID * 2, cy + Tile.GRID)); - } else { - edgeConnections.put(Orientation.NORTH, new Point(cx - Tile.GRID * 2, cy - Tile.GRID)); - edgeConnections.put(Orientation.SOUTH, new Point(cx, cy + Tile.GRID)); - } - } - case NORTH -> { - edgeConnections.put(Orientation.NORTH, new Point(cx, cy - Tile.GRID * 3)); - edgeConnections.put(Orientation.SOUTH, new Point(cx, cy + Tile.GRID)); - - if (Direction.LEFT == direction) { - edgeConnections.put(Orientation.EAST, new Point(cx + Tile.GRID, cy)); - edgeConnections.put(Orientation.WEST, new Point(cx - Tile.GRID, cy - Tile.GRID * 2)); - } else { - edgeConnections.put(Orientation.EAST, new Point(cx + Tile.GRID, cy - Tile.GRID * 2)); - edgeConnections.put(Orientation.WEST, new Point(cx - Tile.GRID, cy)); - } - } - default -> { - //EAST - edgeConnections.put(Orientation.EAST, new Point(cx + Tile.GRID * 3, cy)); - edgeConnections.put(Orientation.WEST, new Point(cx - Tile.GRID, cy)); - - if (Direction.LEFT == direction) { - edgeConnections.put(Orientation.NORTH, new Point(cx + Tile.GRID * 2, cy - Tile.GRID)); - edgeConnections.put(Orientation.SOUTH, new Point(cx, cy + Tile.GRID)); - } else { - edgeConnections.put(Orientation.NORTH, new Point(cx, cy - Tile.GRID)); - edgeConnections.put(Orientation.SOUTH, new Point(cx + Tile.GRID * 2, cy + Tile.GRID)); - } - } - } - return edgeConnections; - } - - @Override - protected void renderStraight(Graphics2D g2, Color color) { - int xx, yy, w, h; - xx = 0; - yy = 170; - w = RENDER_WIDTH; - h = 60; - - g2.setStroke(new BasicStroke(4, BasicStroke.JOIN_MITER, BasicStroke.JOIN_ROUND)); - g2.setPaint(color); - g2.fillRect(xx, yy, w, h); - } - - @Override - protected void renderRouteStraight(Graphics2D g2, Color color) { - int xx, yy, w, h; - xx = 0; - yy = 190; - w = RENDER_WIDTH; - h = 20; - - g2.setStroke(new BasicStroke(4, BasicStroke.JOIN_MITER, BasicStroke.JOIN_ROUND)); - g2.setPaint(color); - g2.fillRect(xx, yy, w, h); - } - - protected void renderStraight2(Graphics2D g2, Color color) { - int xx, yy, w, h; - xx = RENDER_WIDTH; - yy = 170; - w = RENDER_WIDTH; - h = 60; - - g2.setStroke(new BasicStroke(4, BasicStroke.JOIN_MITER, BasicStroke.JOIN_ROUND)); - g2.setPaint(color); - g2.fillRect(xx, yy, w, h); - } - - protected void renderRouteStraight2(Graphics2D g2, Color color) { - int xx, yy, w, h; - xx = RENDER_WIDTH; - yy = 190; - w = RENDER_WIDTH; - h = 20; - - g2.setStroke(new BasicStroke(4, BasicStroke.JOIN_MITER, BasicStroke.JOIN_ROUND)); - g2.setPaint(color); - g2.fillRect(xx, yy, w, h); - } - - @Override - protected void renderDiagonal(Graphics2D g2, Color color) { - int[] xPoints, yPoints; - if (Direction.RIGHT.equals(getDirection())) { - xPoints = new int[]{400, 400, 167, 230}; - yPoints = new int[]{170, 230, 0, 0}; - } else { - xPoints = new int[]{400, 400, 170, 230}; - yPoints = new int[]{230, 170, 400, 400}; - } - - g2.setStroke(new BasicStroke(4, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND)); - g2.setPaint(color); - g2.fillPolygon(xPoints, yPoints, xPoints.length); - } - - @Override - protected void renderRouteDiagonal(Graphics2D g2, Color color) { - int[] xPoints, yPoints; - if (Direction.RIGHT.equals(getDirection())) { - xPoints = new int[]{420, 400, 190, 210}; - yPoints = new int[]{210, 210, 0, 0}; - } else { - xPoints = new int[]{400, 400, 190, 210}; - yPoints = new int[]{210, 190, 400, 400}; - } - - g2.setStroke(new BasicStroke(4, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND)); - g2.setPaint(color); - g2.fillPolygon(xPoints, yPoints, xPoints.length); - } - - protected void renderDiagonal2(Graphics2D g2, Color color) { - int[] xPoints, yPoints; - if (Direction.RIGHT.equals(getDirection())) { - xPoints = new int[]{400, 400, 570, 630}; - yPoints = new int[]{170, 230, 400, 400}; - } else { - xPoints = new int[]{400, 400, 570, 630}; - yPoints = new int[]{230, 170, 0, 0}; - } - - g2.setStroke(new BasicStroke(4, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND)); - g2.setPaint(color); - g2.fillPolygon(xPoints, yPoints, xPoints.length); - } - - protected void renderRouteDiagonal2(Graphics2D g2, Color color) { - int[] xPoints, yPoints; - if (Direction.RIGHT.equals(getDirection())) { - xPoints = new int[]{400, 380, 590, 610}; - yPoints = new int[]{190, 190, 400, 400}; - } else { - xPoints = new int[]{400, 380, 590, 610}; - yPoints = new int[]{210, 210, 0, 0}; - } - - g2.setStroke(new BasicStroke(4, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND)); - g2.setPaint(color); - g2.setPaint(Color.cyan); - g2.fillPolygon(xPoints, yPoints, xPoints.length); - } - - @Override - public void renderTile(Graphics2D g2) { - if (accessoryValue == null) { - this.accessoryValue = AccessoryValue.OFF; - } - - switch (accessoryValue) { - case RED -> { - renderStraight2(g2, Cross.LIGHT_RED); - renderDiagonal(g2, Cross.LIGHT_RED); - renderStraight(g2, Cross.DARK_RED); - renderDiagonal2(g2, Cross.DARK_RED); - } - case GREEN -> { - renderDiagonal(g2, Cross.VERY_LIGHT_GREEN); - renderDiagonal2(g2, Cross.VERY_LIGHT_GREEN); - renderStraight(g2, Cross.DARK_GREEN); - renderStraight2(g2, Cross.DARK_GREEN); - } - default -> { - renderStraight(g2, trackColor); - renderStraight2(g2, trackColor); - renderDiagonal(g2, trackColor); - renderDiagonal2(g2, trackColor); - } - } - } - - @Override - public void renderTileRoute(Graphics2D g2) { - if (routeValue == null) { - routeValue = AccessoryValue.OFF; - } - if (incomingSide == null) { - incomingSide = getOrientation(); - } - - if (isHorizontal()) { - if (AccessoryValue.GREEN == routeValue && (Orientation.NORTH == incomingSide || Orientation.SOUTH == incomingSide)) { - renderRouteDiagonal(g2, trackRouteColor); - renderRouteDiagonal2(g2, trackRouteColor); - } else if (AccessoryValue.GREEN == routeValue && (Orientation.EAST == incomingSide || Orientation.WEST == incomingSide)) { - renderRouteStraight(g2, trackRouteColor); - renderRouteStraight2(g2, trackRouteColor); - } else if (AccessoryValue.RED == routeValue && Orientation.EAST == getOrientation()) { - if (Direction.RIGHT == getDirection() && (Orientation.EAST == incomingSide || Orientation.NORTH == incomingSide)) { - renderRouteStraight2(g2, trackRouteColor); - renderRouteDiagonal(g2, trackRouteColor); - } else if (Direction.RIGHT == getDirection() && (Orientation.WEST == incomingSide || Orientation.SOUTH == incomingSide)) { - renderRouteDiagonal2(g2, trackRouteColor); - renderRouteStraight(g2, trackRouteColor); - } else if (Direction.LEFT == getDirection() && (Orientation.EAST == incomingSide || Orientation.SOUTH == incomingSide)) { - renderRouteStraight2(g2, trackRouteColor); - renderRouteDiagonal(g2, trackRouteColor); - } else if (Direction.LEFT == getDirection() && (Orientation.WEST == incomingSide || Orientation.NORTH == incomingSide)) { - renderRouteStraight(g2, trackColor); - renderRouteDiagonal2(g2, trackColor); - } - } else if (AccessoryValue.RED == routeValue && Orientation.WEST == getOrientation()) { - if (Direction.RIGHT == getDirection() && (Orientation.EAST == incomingSide || Orientation.NORTH == incomingSide)) { - renderRouteStraight(g2, trackRouteColor); - renderRouteDiagonal2(g2, trackRouteColor); - } else if (Direction.RIGHT == getDirection() && (Orientation.WEST == incomingSide || Orientation.SOUTH == incomingSide)) { - renderRouteDiagonal(g2, trackRouteColor); - renderRouteStraight2(g2, trackRouteColor); - } else if (Direction.LEFT == getDirection() && (Orientation.EAST == incomingSide || Orientation.SOUTH == incomingSide)) { - renderRouteStraight(g2, trackRouteColor); - renderRouteDiagonal2(g2, trackRouteColor); - } else if (Direction.LEFT == getDirection() && (Orientation.WEST == incomingSide || Orientation.NORTH == incomingSide)) { - renderRouteStraight2(g2, trackColor); - renderRouteDiagonal(g2, trackColor); - } - } - } else { - if (AccessoryValue.GREEN == routeValue && (Orientation.NORTH == incomingSide || Orientation.SOUTH == incomingSide)) { - renderRouteStraight(g2, trackRouteColor); - renderRouteStraight2(g2, trackRouteColor); - } else if (AccessoryValue.GREEN == routeValue && (Orientation.EAST == incomingSide || Orientation.WEST == incomingSide)) { - renderRouteDiagonal(g2, trackRouteColor); - renderRouteDiagonal2(g2, trackRouteColor); - } else if (AccessoryValue.RED == routeValue && Orientation.SOUTH == getOrientation()) { - if (Direction.RIGHT == getDirection() && (Orientation.EAST == incomingSide || Orientation.SOUTH == incomingSide)) { - renderRouteStraight2(g2, trackRouteColor); - renderRouteDiagonal(g2, trackRouteColor); - } else if (Direction.RIGHT == getDirection() && (Orientation.WEST == incomingSide || Orientation.NORTH == incomingSide)) { - renderRouteDiagonal2(g2, trackRouteColor); - renderRouteStraight(g2, trackRouteColor); - } else if (Direction.LEFT == getDirection() && (Orientation.EAST == incomingSide || Orientation.NORTH == incomingSide)) { - renderRouteStraight(g2, trackRouteColor); - renderRouteDiagonal2(g2, trackRouteColor); - } else if (Direction.LEFT == getDirection() && (Orientation.WEST == incomingSide || Orientation.SOUTH == incomingSide)) { - renderRouteStraight2(g2, trackColor); - renderRouteDiagonal(g2, trackColor); - } - } else if (AccessoryValue.RED == routeValue && Orientation.NORTH == getOrientation()) { - if (Direction.RIGHT == getDirection() && (Orientation.EAST == incomingSide || Orientation.SOUTH == incomingSide)) { - renderRouteStraight(g2, trackRouteColor); - renderRouteDiagonal2(g2, trackRouteColor); - } else if (Direction.RIGHT == getDirection() && (Orientation.WEST == incomingSide || Orientation.NORTH == incomingSide)) { - renderRouteDiagonal(g2, trackRouteColor); - renderRouteStraight2(g2, trackRouteColor); - } else if (Direction.LEFT == getDirection() && (Orientation.EAST == incomingSide || Orientation.NORTH == incomingSide)) { - renderRouteStraight2(g2, trackRouteColor); - renderRouteDiagonal(g2, trackRouteColor); - } else if (Direction.LEFT == getDirection() && (Orientation.WEST == incomingSide || Orientation.SOUTH == incomingSide)) { - renderRouteStraight(g2, trackColor); - renderRouteDiagonal2(g2, trackColor); - } - } - } - } - - @Override - public AccessoryValue accessoryValueForRoute(Orientation from, Orientation to) { - if (from != null && to != null && this.getDirection() != null) { - switch (this.getDirection()) { - case LEFT -> { - if (this.isHorizontal()) { - if ((from == Orientation.WEST && to == Orientation.EAST) || (from == Orientation.EAST && to == Orientation.WEST)) { - return AccessoryValue.GREEN; - } else if ((from == Orientation.NORTH && to == Orientation.SOUTH) || (from == Orientation.SOUTH && to == Orientation.NORTH)) { - return AccessoryValue.GREEN; - } else if ((from == Orientation.NORTH && to == Orientation.WEST) || (from == Orientation.WEST && to == Orientation.NORTH)) { - return AccessoryValue.RED; - } else if ((from == Orientation.EAST && to == Orientation.SOUTH) || (from == Orientation.SOUTH && to == Orientation.EAST)) { - return AccessoryValue.RED; - } else { - return AccessoryValue.OFF; - } - } else { - //Vertical - if ((from == Orientation.WEST && to == Orientation.EAST) || (from == Orientation.EAST && to == Orientation.WEST)) { - return AccessoryValue.GREEN; - } else if ((from == Orientation.NORTH && to == Orientation.SOUTH) || (from == Orientation.SOUTH && to == Orientation.NORTH)) { - return AccessoryValue.GREEN; - } else if ((from == Orientation.SOUTH && to == Orientation.WEST) || (from == Orientation.WEST && to == Orientation.SOUTH)) { - return AccessoryValue.RED; - } else if ((from == Orientation.EAST && to == Orientation.NORTH) || (from == Orientation.NORTH && to == Orientation.EAST)) { - return AccessoryValue.RED; - } else { - return AccessoryValue.OFF; - } - } - } - case RIGHT -> { - if (this.isHorizontal()) { - if ((from == Orientation.WEST && to == Orientation.EAST) || (from == Orientation.EAST && to == Orientation.WEST)) { - return AccessoryValue.GREEN; - } else if ((from == Orientation.NORTH && to == Orientation.SOUTH) || (from == Orientation.SOUTH && to == Orientation.NORTH)) { - return AccessoryValue.GREEN; - } else if ((from == Orientation.NORTH && to == Orientation.EAST) || (from == Orientation.EAST && to == Orientation.NORTH)) { - return AccessoryValue.RED; - } else if ((from == Orientation.WEST && to == Orientation.SOUTH) || (from == Orientation.SOUTH && to == Orientation.WEST)) { - return AccessoryValue.RED; - } else { - return AccessoryValue.OFF; - } - } else { - //Vertical - if ((from == Orientation.WEST && to == Orientation.EAST) || (from == Orientation.EAST && to == Orientation.WEST)) { - return AccessoryValue.GREEN; - } else if ((from == Orientation.NORTH && to == Orientation.SOUTH) || (from == Orientation.SOUTH && to == Orientation.NORTH)) { - return AccessoryValue.GREEN; - } else if ((from == Orientation.SOUTH && to == Orientation.EAST) || (from == Orientation.EAST && to == Orientation.SOUTH)) { - return AccessoryValue.RED; - } else if ((from == Orientation.WEST && to == Orientation.NORTH) || (from == Orientation.NORTH && to == Orientation.WEST)) { - return AccessoryValue.RED; - } else { - return AccessoryValue.OFF; - } - } - } - default -> { - return AccessoryValue.OFF; - } - } - } else { - return AccessoryValue.OFF; - } - } - - @Override - protected void drawCenterPoint(Graphics2D g2d, Color color, double size) { - //A Cross has 1 alternate point - //1st square holds the centerpoint - //2nd square - double dX1, dX2, dY1, dY2; - Orientation tileOrientation = model.getTileOrienation(); - switch (tileOrientation) { - case SOUTH -> { - dX1 = renderWidth / 2 - size / 2; - dY1 = renderHeight / 2 - renderHeight / 4 - size / 2; - dX2 = renderWidth / 2 + renderWidth - size / 4; - dY2 = renderHeight / 2 - renderHeight / 4 - size / 4; - } - case WEST -> { - dX1 = renderWidth / 2 - renderWidth / 4 - size / 2; - dY1 = renderHeight / 2 - size / 2; - dX2 = renderWidth / 2 + renderWidth / 4 - size / 4; - dY2 = renderHeight / 2 - size / 4; - } - case NORTH -> { - dX1 = renderWidth / 2 - size / 2; - dY1 = renderHeight / 2 - renderHeight / 4 - size / 2; - dX2 = renderWidth / 2 + renderWidth - size / 4; - dY2 = renderHeight / 2 - renderHeight / 4 - size / 4; - } - default -> { - //East - dX1 = renderWidth / 2 - renderWidth / 4 - size / 2; - dY1 = renderHeight / 2 - size / 2; - dX2 = renderWidth / 2 + renderWidth / 4 - size / 4; - dY2 = renderHeight / 2 - size / 4; - } - } - - g2d.setColor(color); - g2d.fill(new Ellipse2D.Double(dX1, dY1, size, size)); - g2d.fill(new Ellipse2D.Double(dX2, dY2, size / 2, size / 2)); - } - - @Override - public Rectangle getTileBounds() { - Orientation tileOrientation = model.getTileOrienation(); - int xx, yy, w, h, multiplier; - if (model.isScaleImage()) { - w = tileWidth(tileOrientation, TileType.CROSS); - h = tileHeight(tileOrientation, TileType.CROSS); - multiplier = 1; - } else { - w = renderWidth; - h = renderHeight; - multiplier = 10; - } - - switch (tileOrientation) { - case SOUTH -> { - xx = tileX - GRID * multiplier; - yy = tileY - GRID * multiplier; - } - case WEST -> { - xx = tileX - GRID * multiplier - GRID * 2 * multiplier; - yy = tileY - GRID * multiplier; - } - case NORTH -> { - xx = tileX - GRID * multiplier; - yy = tileY - GRID * multiplier - GRID * 2 * multiplier; - } - default -> { - //East - xx = tileX - GRID * multiplier; - yy = tileY - GRID * multiplier; - } - } - - if (model.isScaleImage()) { - return new Rectangle(xx, yy, tileWidth(tileOrientation, TileType.CROSS), tileHeight(tileOrientation, TileType.CROSS)); - } else { - return new Rectangle(xx, yy, renderWidth, renderHeight); - } - } - - private void changeRenderSizeAndOffsets() { - //Reset offsets - this.offsetY = 0; - this.renderOffsetY = 0; - this.offsetX = 0; - this.renderOffsetX = 0; - - if (isHorizontal()) { - this.renderWidth = RENDER_GRID * 4; - this.renderHeight = RENDER_GRID * 2; - - this.offsetY = 0; - this.renderOffsetY = 0; - } else { - this.renderWidth = RENDER_GRID * 2; - this.renderHeight = RENDER_GRID * 4; - - this.offsetX = 0; - this.renderOffsetX = 0; - } - - //Due to the asymetical shape (center is on the left) - //the offset has to be changed with the rotation - Orientation tileOrientation = model.getTileOrienation(); - switch (tileOrientation) { - case SOUTH -> { - this.offsetY = +GRID; - this.renderOffsetY = RENDER_GRID; - } - case WEST -> { - this.offsetX = -GRID; - this.renderOffsetX = -RENDER_GRID; - } - case NORTH -> { - this.offsetY = -GRID; - this.renderOffsetY = -RENDER_GRID; - } - default -> { - //East so default - this.offsetX = +GRID; - this.renderOffsetX = +RENDER_GRID; - } - } - } - - @Override - public Orientation rotate() { - super.rotate(); - - Orientation tileOrientation = model.getTileOrienation(); - int w = tileWidth(tileOrientation, TileType.CROSS); - int h = tileHeight(tileOrientation, TileType.CROSS); - - Dimension d = new Dimension(w, h); - setPreferredSize(d); - setSize(d); - changeRenderSizeAndOffsets(); - - setBounds(getTileBounds()); - return tileOrientation; - } - -} +/* * Copyright 2023 Frans Jacobs. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package jcs.ui.layout.tiles; import java.awt.BasicStroke; import java.awt.Color; import java.awt.Dimension; import java.awt.Graphics2D; import java.awt.Point; import java.awt.Rectangle; import java.awt.geom.Ellipse2D; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set; import jcs.entities.AccessoryBean.AccessoryValue; import static jcs.entities.AccessoryBean.AccessoryValue.GREEN; import static jcs.entities.AccessoryBean.AccessoryValue.RED; import jcs.entities.TileBean; import jcs.entities.TileBean.Direction; import jcs.entities.TileBean.Orientation; import static jcs.entities.TileBean.Orientation.NORTH; import static jcs.entities.TileBean.Orientation.SOUTH; import static jcs.entities.TileBean.Orientation.WEST; import jcs.entities.TileBean.TileType; import static jcs.ui.layout.tiles.Tile.DEFAULT_HEIGHT; import static jcs.ui.layout.tiles.Tile.DEFAULT_WIDTH; import static jcs.ui.layout.tiles.Tile.GRID; import static jcs.ui.layout.tiles.Tile.tileHeight; import static jcs.ui.layout.tiles.Tile.tileWidth; public class Cross extends Switch { public static final int CROSS_WIDTH = DEFAULT_WIDTH * 2; public static final int CROSS_HEIGHT = DEFAULT_HEIGHT * 2; public static final Color VERY_LIGHT_RED = new Color(255, 102, 102); public static final Color LIGHT_RED = new Color(255, 51, 51); public static final Color DARK_RED = new Color(204, 0, 0); public static final Color VERY_LIGHT_GREEN = new Color(102, 255, 102); public static final Color LIGHT_GREEN = new Color(0, 255, 51); public static final Color DARK_GREEN = new Color(0, 153, 0); public Cross(Orientation orientation, Direction direction, Point center) { this(orientation, direction, center.x, center.y); } public Cross(Orientation orientation, Direction direction, int x, int y) { this(orientation, direction, x, y, tileWidth(orientation, TileType.CROSS), tileHeight(orientation, TileType.CROSS)); } public Cross(Orientation orientation, Direction direction, int x, int y, int width, int height) { super(TileType.CROSS, orientation, direction, x, y, width, height); changeRenderSizeAndOffsets(); } public Cross(TileBean tileBean) { super(tileBean, tileWidth(tileBean.getOrientation(), TileType.CROSS), tileHeight(tileBean.getOrientation(), TileType.CROSS)); changeRenderSizeAndOffsets(); } /** * A Cross has a width in horizontal position of 2 tiles and a height of 1 tile in Vertical position.
* * @return the Set of points which mark the position of the Cross */ @Override public Set getAltPoints() { return getAltPoints(getCenter()); } @Override public Set getAllPoints() { return getAllPoints(getCenter()); } @Override public Set getAllPoints(Point center) { Set aps = getAltPoints(center); aps.add(center); return aps; } @Override Set getAltPoints(Point center) { Set alts = new HashSet<>(); switch (getOrientation()) { case SOUTH -> { Point sp = new Point(center.x, (center.y + DEFAULT_HEIGHT)); alts.add(sp); } case WEST -> { Point wp = new Point((center.x - DEFAULT_WIDTH), center.y); alts.add(wp); } case NORTH -> { Point np = new Point(center.x, (center.y - DEFAULT_HEIGHT)); alts.add(np); } default -> { //East so default Point ep = new Point((center.x + DEFAULT_WIDTH), center.y); alts.add(ep); } } return alts; } @Override public Map getNeighborPoints() { Map neighbors = new HashMap<>(); Orientation orientation = this.getOrientation(); Direction direction = this.getDirection(); int cx = this.getCenterX(); int cy = this.getCenterY(); switch (orientation) { case SOUTH -> { neighbors.put(Orientation.NORTH, new Point(cx, cy - Tile.GRID * 2)); neighbors.put(Orientation.SOUTH, new Point(cx, cy + Tile.GRID * 4)); if (Direction.LEFT == direction) { neighbors.put(Orientation.EAST, new Point(cx + Tile.GRID * 2, cy + Tile.GRID * 2)); neighbors.put(Orientation.WEST, new Point(cx - Tile.GRID * 2, cy)); } else { neighbors.put(Orientation.EAST, new Point(cx + Tile.GRID * 2, cy)); neighbors.put(Orientation.WEST, new Point(cx - Tile.GRID * 2, cy + Tile.GRID * 2)); } } case WEST -> { neighbors.put(Orientation.EAST, new Point(cx + Tile.GRID * 2, cy)); neighbors.put(Orientation.WEST, new Point(cx - Tile.GRID * 4, cy)); if (Direction.LEFT == direction) { neighbors.put(Orientation.NORTH, new Point(cx, cy - Tile.GRID * 2)); neighbors.put(Orientation.SOUTH, new Point(cx - Tile.GRID * 2, cy + Tile.GRID * 2)); } else { neighbors.put(Orientation.NORTH, new Point(cx - Tile.GRID * 2, cy - Tile.GRID * 2)); neighbors.put(Orientation.SOUTH, new Point(cx, cy + Tile.GRID * 2)); } } case NORTH -> { neighbors.put(Orientation.NORTH, new Point(cx, cy - Tile.GRID * 4)); neighbors.put(Orientation.SOUTH, new Point(cx, cy + Tile.GRID * 2)); if (Direction.LEFT == direction) { neighbors.put(Orientation.EAST, new Point(cx + Tile.GRID * 2, cy)); neighbors.put(Orientation.WEST, new Point(cx - Tile.GRID * 2, cy - Tile.GRID * 2)); } else { neighbors.put(Orientation.EAST, new Point(cx + Tile.GRID * 2, cy - Tile.GRID * 2)); neighbors.put(Orientation.WEST, new Point(cx - Tile.GRID * 2, cy)); } } default -> { //EAST neighbors.put(Orientation.EAST, new Point(cx + Tile.GRID * 4, cy)); neighbors.put(Orientation.WEST, new Point(cx - Tile.GRID * 2, cy)); if (Direction.LEFT == direction) { neighbors.put(Orientation.NORTH, new Point(cx + Tile.GRID * 2, cy - Tile.GRID * 2)); neighbors.put(Orientation.SOUTH, new Point(cx, cy + Tile.GRID * 2)); } else { neighbors.put(Orientation.NORTH, new Point(cx, cy - Tile.GRID * 2)); neighbors.put(Orientation.SOUTH, new Point(cx + Tile.GRID * 2, cy + Tile.GRID * 2)); } } } return neighbors; } @Override public Map getEdgePoints() { Map edgeConnections = new HashMap<>(); Orientation orientation = this.getOrientation(); Direction direction = this.getDirection(); int cx = this.getCenterX(); int cy = this.getCenterY(); switch (orientation) { case SOUTH -> { edgeConnections.put(Orientation.NORTH, new Point(cx, cy - Tile.GRID)); edgeConnections.put(Orientation.SOUTH, new Point(cx, cy + Tile.GRID * 3)); if (Direction.LEFT == direction) { edgeConnections.put(Orientation.EAST, new Point(cx + Tile.GRID, cy + Tile.GRID * 2)); edgeConnections.put(Orientation.WEST, new Point(cx - Tile.GRID, cy)); } else { edgeConnections.put(Orientation.EAST, new Point(cx + Tile.GRID, cy)); edgeConnections.put(Orientation.WEST, new Point(cx - Tile.GRID, cy + Tile.GRID * 2)); } } case WEST -> { edgeConnections.put(Orientation.EAST, new Point(cx + Tile.GRID, cy)); edgeConnections.put(Orientation.WEST, new Point(cx - Tile.GRID * 3, cy)); if (Direction.LEFT == direction) { edgeConnections.put(Orientation.NORTH, new Point(cx, cy - Tile.GRID)); edgeConnections.put(Orientation.SOUTH, new Point(cx - Tile.GRID * 2, cy + Tile.GRID)); } else { edgeConnections.put(Orientation.NORTH, new Point(cx - Tile.GRID * 2, cy - Tile.GRID)); edgeConnections.put(Orientation.SOUTH, new Point(cx, cy + Tile.GRID)); } } case NORTH -> { edgeConnections.put(Orientation.NORTH, new Point(cx, cy - Tile.GRID * 3)); edgeConnections.put(Orientation.SOUTH, new Point(cx, cy + Tile.GRID)); if (Direction.LEFT == direction) { edgeConnections.put(Orientation.EAST, new Point(cx + Tile.GRID, cy)); edgeConnections.put(Orientation.WEST, new Point(cx - Tile.GRID, cy - Tile.GRID * 2)); } else { edgeConnections.put(Orientation.EAST, new Point(cx + Tile.GRID, cy - Tile.GRID * 2)); edgeConnections.put(Orientation.WEST, new Point(cx - Tile.GRID, cy)); } } default -> { //EAST edgeConnections.put(Orientation.EAST, new Point(cx + Tile.GRID * 3, cy)); edgeConnections.put(Orientation.WEST, new Point(cx - Tile.GRID, cy)); if (Direction.LEFT == direction) { edgeConnections.put(Orientation.NORTH, new Point(cx + Tile.GRID * 2, cy - Tile.GRID)); edgeConnections.put(Orientation.SOUTH, new Point(cx, cy + Tile.GRID)); } else { edgeConnections.put(Orientation.NORTH, new Point(cx, cy - Tile.GRID)); edgeConnections.put(Orientation.SOUTH, new Point(cx + Tile.GRID * 2, cy + Tile.GRID)); } } } return edgeConnections; } @Override protected void renderStraight(Graphics2D g2, Color color) { int xx, yy, w, h; xx = 0; yy = 170; w = RENDER_WIDTH; h = 60; g2.setStroke(new BasicStroke(4, BasicStroke.JOIN_MITER, BasicStroke.JOIN_ROUND)); g2.setPaint(color); g2.fillRect(xx, yy, w, h); } @Override protected void renderRouteStraight(Graphics2D g2, Color color) { int xx, yy, w, h; xx = 0; yy = 190; w = RENDER_WIDTH; h = 20; g2.setStroke(new BasicStroke(4, BasicStroke.JOIN_MITER, BasicStroke.JOIN_ROUND)); g2.setPaint(color); g2.fillRect(xx, yy, w, h); } protected void renderStraight2(Graphics2D g2, Color color) { int xx, yy, w, h; xx = RENDER_WIDTH; yy = 170; w = RENDER_WIDTH; h = 60; g2.setStroke(new BasicStroke(4, BasicStroke.JOIN_MITER, BasicStroke.JOIN_ROUND)); g2.setPaint(color); g2.fillRect(xx, yy, w, h); } protected void renderRouteStraight2(Graphics2D g2, Color color) { int xx, yy, w, h; xx = RENDER_WIDTH; yy = 190; w = RENDER_WIDTH; h = 20; g2.setStroke(new BasicStroke(4, BasicStroke.JOIN_MITER, BasicStroke.JOIN_ROUND)); g2.setPaint(color); g2.fillRect(xx, yy, w, h); } @Override protected void renderDiagonal(Graphics2D g2, Color color) { int[] xPoints, yPoints; if (Direction.RIGHT.equals(getDirection())) { xPoints = new int[]{400, 400, 167, 230}; yPoints = new int[]{170, 230, 0, 0}; } else { xPoints = new int[]{400, 400, 170, 230}; yPoints = new int[]{230, 170, 400, 400}; } g2.setStroke(new BasicStroke(4, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND)); g2.setPaint(color); g2.fillPolygon(xPoints, yPoints, xPoints.length); } @Override protected void renderRouteDiagonal(Graphics2D g2, Color color) { int[] xPoints, yPoints; if (Direction.RIGHT.equals(getDirection())) { xPoints = new int[]{420, 400, 190, 210}; yPoints = new int[]{210, 210, 0, 0}; } else { xPoints = new int[]{400, 400, 190, 210}; yPoints = new int[]{210, 190, 400, 400}; } g2.setStroke(new BasicStroke(4, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND)); g2.setPaint(color); g2.fillPolygon(xPoints, yPoints, xPoints.length); } protected void renderDiagonal2(Graphics2D g2, Color color) { int[] xPoints, yPoints; if (Direction.RIGHT.equals(getDirection())) { xPoints = new int[]{400, 400, 570, 630}; yPoints = new int[]{170, 230, 400, 400}; } else { xPoints = new int[]{400, 400, 570, 630}; yPoints = new int[]{230, 170, 0, 0}; } g2.setStroke(new BasicStroke(4, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND)); g2.setPaint(color); g2.fillPolygon(xPoints, yPoints, xPoints.length); } protected void renderRouteDiagonal2(Graphics2D g2, Color color) { int[] xPoints, yPoints; if (Direction.RIGHT.equals(getDirection())) { xPoints = new int[]{400, 380, 590, 610}; yPoints = new int[]{190, 190, 400, 400}; } else { xPoints = new int[]{400, 380, 590, 610}; yPoints = new int[]{210, 210, 0, 0}; } g2.setStroke(new BasicStroke(4, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND)); g2.setPaint(color); g2.setPaint(Color.cyan); g2.fillPolygon(xPoints, yPoints, xPoints.length); } @Override public void renderTile(Graphics2D g2) { if (accessoryValue == null) { this.accessoryValue = AccessoryValue.OFF; } switch (accessoryValue) { case RED -> { renderStraight2(g2, Cross.LIGHT_RED); renderDiagonal(g2, Cross.LIGHT_RED); renderStraight(g2, Cross.DARK_RED); renderDiagonal2(g2, Cross.DARK_RED); } case GREEN -> { renderDiagonal(g2, Cross.VERY_LIGHT_GREEN); renderDiagonal2(g2, Cross.VERY_LIGHT_GREEN); renderStraight(g2, Cross.DARK_GREEN); renderStraight2(g2, Cross.DARK_GREEN); } default -> { renderStraight(g2, trackColor); renderStraight2(g2, trackColor); renderDiagonal(g2, trackColor); renderDiagonal2(g2, trackColor); } } } @Override public void renderTileRoute(Graphics2D g2) { if (routeValue == null) { routeValue = AccessoryValue.OFF; } if (incomingSide == null) { incomingSide = getOrientation(); } if (isHorizontal()) { if (AccessoryValue.GREEN == routeValue && (Orientation.NORTH == incomingSide || Orientation.SOUTH == incomingSide)) { renderRouteDiagonal(g2, trackRouteColor); renderRouteDiagonal2(g2, trackRouteColor); } else if (AccessoryValue.GREEN == routeValue && (Orientation.EAST == incomingSide || Orientation.WEST == incomingSide)) { renderRouteStraight(g2, trackRouteColor); renderRouteStraight2(g2, trackRouteColor); } else if (AccessoryValue.RED == routeValue && Orientation.EAST == getOrientation()) { if (Direction.RIGHT == getDirection() && (Orientation.EAST == incomingSide || Orientation.NORTH == incomingSide)) { renderRouteStraight2(g2, trackRouteColor); renderRouteDiagonal(g2, trackRouteColor); } else if (Direction.RIGHT == getDirection() && (Orientation.WEST == incomingSide || Orientation.SOUTH == incomingSide)) { renderRouteDiagonal2(g2, trackRouteColor); renderRouteStraight(g2, trackRouteColor); } else if (Direction.LEFT == getDirection() && (Orientation.EAST == incomingSide || Orientation.SOUTH == incomingSide)) { renderRouteStraight2(g2, trackRouteColor); renderRouteDiagonal(g2, trackRouteColor); } else if (Direction.LEFT == getDirection() && (Orientation.WEST == incomingSide || Orientation.NORTH == incomingSide)) { renderRouteStraight(g2, trackColor); renderRouteDiagonal2(g2, trackColor); } } else if (AccessoryValue.RED == routeValue && Orientation.WEST == getOrientation()) { if (Direction.RIGHT == getDirection() && (Orientation.EAST == incomingSide || Orientation.NORTH == incomingSide)) { renderRouteStraight(g2, trackRouteColor); renderRouteDiagonal2(g2, trackRouteColor); } else if (Direction.RIGHT == getDirection() && (Orientation.WEST == incomingSide || Orientation.SOUTH == incomingSide)) { renderRouteDiagonal(g2, trackRouteColor); renderRouteStraight2(g2, trackRouteColor); } else if (Direction.LEFT == getDirection() && (Orientation.EAST == incomingSide || Orientation.SOUTH == incomingSide)) { renderRouteStraight(g2, trackRouteColor); renderRouteDiagonal2(g2, trackRouteColor); } else if (Direction.LEFT == getDirection() && (Orientation.WEST == incomingSide || Orientation.NORTH == incomingSide)) { renderRouteStraight2(g2, trackColor); renderRouteDiagonal(g2, trackColor); } } } else { if (AccessoryValue.GREEN == routeValue && (Orientation.NORTH == incomingSide || Orientation.SOUTH == incomingSide)) { renderRouteStraight(g2, trackRouteColor); renderRouteStraight2(g2, trackRouteColor); } else if (AccessoryValue.GREEN == routeValue && (Orientation.EAST == incomingSide || Orientation.WEST == incomingSide)) { renderRouteDiagonal(g2, trackRouteColor); renderRouteDiagonal2(g2, trackRouteColor); } else if (AccessoryValue.RED == routeValue && Orientation.SOUTH == getOrientation()) { if (Direction.RIGHT == getDirection() && (Orientation.EAST == incomingSide || Orientation.SOUTH == incomingSide)) { renderRouteStraight2(g2, trackRouteColor); renderRouteDiagonal(g2, trackRouteColor); } else if (Direction.RIGHT == getDirection() && (Orientation.WEST == incomingSide || Orientation.NORTH == incomingSide)) { renderRouteDiagonal2(g2, trackRouteColor); renderRouteStraight(g2, trackRouteColor); } else if (Direction.LEFT == getDirection() && (Orientation.EAST == incomingSide || Orientation.NORTH == incomingSide)) { renderRouteStraight(g2, trackRouteColor); renderRouteDiagonal2(g2, trackRouteColor); } else if (Direction.LEFT == getDirection() && (Orientation.WEST == incomingSide || Orientation.SOUTH == incomingSide)) { renderRouteStraight2(g2, trackColor); renderRouteDiagonal(g2, trackColor); } } else if (AccessoryValue.RED == routeValue && Orientation.NORTH == getOrientation()) { if (Direction.RIGHT == getDirection() && (Orientation.EAST == incomingSide || Orientation.SOUTH == incomingSide)) { renderRouteStraight(g2, trackRouteColor); renderRouteDiagonal2(g2, trackRouteColor); } else if (Direction.RIGHT == getDirection() && (Orientation.WEST == incomingSide || Orientation.NORTH == incomingSide)) { renderRouteDiagonal(g2, trackRouteColor); renderRouteStraight2(g2, trackRouteColor); } else if (Direction.LEFT == getDirection() && (Orientation.EAST == incomingSide || Orientation.NORTH == incomingSide)) { renderRouteStraight2(g2, trackRouteColor); renderRouteDiagonal(g2, trackRouteColor); } else if (Direction.LEFT == getDirection() && (Orientation.WEST == incomingSide || Orientation.SOUTH == incomingSide)) { renderRouteStraight(g2, trackColor); renderRouteDiagonal2(g2, trackColor); } } } } @Override public AccessoryValue accessoryValueForRoute(Orientation from, Orientation to) { if (from != null && to != null && this.getDirection() != null) { switch (this.getDirection()) { case LEFT -> { if (this.isHorizontal()) { if ((from == Orientation.WEST && to == Orientation.EAST) || (from == Orientation.EAST && to == Orientation.WEST)) { return AccessoryValue.GREEN; } else if ((from == Orientation.NORTH && to == Orientation.SOUTH) || (from == Orientation.SOUTH && to == Orientation.NORTH)) { return AccessoryValue.GREEN; } else if ((from == Orientation.NORTH && to == Orientation.WEST) || (from == Orientation.WEST && to == Orientation.NORTH)) { return AccessoryValue.RED; } else if ((from == Orientation.EAST && to == Orientation.SOUTH) || (from == Orientation.SOUTH && to == Orientation.EAST)) { return AccessoryValue.RED; } else { return AccessoryValue.OFF; } } else { //Vertical if ((from == Orientation.WEST && to == Orientation.EAST) || (from == Orientation.EAST && to == Orientation.WEST)) { return AccessoryValue.GREEN; } else if ((from == Orientation.NORTH && to == Orientation.SOUTH) || (from == Orientation.SOUTH && to == Orientation.NORTH)) { return AccessoryValue.GREEN; } else if ((from == Orientation.SOUTH && to == Orientation.WEST) || (from == Orientation.WEST && to == Orientation.SOUTH)) { return AccessoryValue.RED; } else if ((from == Orientation.EAST && to == Orientation.NORTH) || (from == Orientation.NORTH && to == Orientation.EAST)) { return AccessoryValue.RED; } else { return AccessoryValue.OFF; } } } case RIGHT -> { if (this.isHorizontal()) { if ((from == Orientation.WEST && to == Orientation.EAST) || (from == Orientation.EAST && to == Orientation.WEST)) { return AccessoryValue.GREEN; } else if ((from == Orientation.NORTH && to == Orientation.SOUTH) || (from == Orientation.SOUTH && to == Orientation.NORTH)) { return AccessoryValue.GREEN; } else if ((from == Orientation.NORTH && to == Orientation.EAST) || (from == Orientation.EAST && to == Orientation.NORTH)) { return AccessoryValue.RED; } else if ((from == Orientation.WEST && to == Orientation.SOUTH) || (from == Orientation.SOUTH && to == Orientation.WEST)) { return AccessoryValue.RED; } else { return AccessoryValue.OFF; } } else { //Vertical if ((from == Orientation.WEST && to == Orientation.EAST) || (from == Orientation.EAST && to == Orientation.WEST)) { return AccessoryValue.GREEN; } else if ((from == Orientation.NORTH && to == Orientation.SOUTH) || (from == Orientation.SOUTH && to == Orientation.NORTH)) { return AccessoryValue.GREEN; } else if ((from == Orientation.SOUTH && to == Orientation.EAST) || (from == Orientation.EAST && to == Orientation.SOUTH)) { return AccessoryValue.RED; } else if ((from == Orientation.WEST && to == Orientation.NORTH) || (from == Orientation.NORTH && to == Orientation.WEST)) { return AccessoryValue.RED; } else { return AccessoryValue.OFF; } } } default -> { return AccessoryValue.OFF; } } } else { return AccessoryValue.OFF; } } @Override protected void drawCenterPoint(Graphics2D g2d, Color color, double size) { //A Cross has 1 alternate point //1st square holds the centerpoint //2nd square double dX1, dX2, dY1, dY2; Orientation tileOrientation = model.getTileOrienation(); switch (tileOrientation) { case SOUTH -> { dX1 = renderWidth / 2 - size / 2; dY1 = renderHeight / 2 - renderHeight / 4 - size / 2; dX2 = renderWidth / 2 + renderWidth - size / 4; dY2 = renderHeight / 2 - renderHeight / 4 - size / 4; } case WEST -> { dX1 = renderWidth / 2 - renderWidth / 4 - size / 2; dY1 = renderHeight / 2 - size / 2; dX2 = renderWidth / 2 + renderWidth / 4 - size / 4; dY2 = renderHeight / 2 - size / 4; } case NORTH -> { dX1 = renderWidth / 2 - size / 2; dY1 = renderHeight / 2 - renderHeight / 4 - size / 2; dX2 = renderWidth / 2 + renderWidth - size / 4; dY2 = renderHeight / 2 - renderHeight / 4 - size / 4; } default -> { //East dX1 = renderWidth / 2 - renderWidth / 4 - size / 2; dY1 = renderHeight / 2 - size / 2; dX2 = renderWidth / 2 + renderWidth / 4 - size / 4; dY2 = renderHeight / 2 - size / 4; } } g2d.setColor(color); g2d.fill(new Ellipse2D.Double(dX1, dY1, size, size)); g2d.fill(new Ellipse2D.Double(dX2, dY2, size / 2, size / 2)); } @Override public Rectangle getTileBounds() { Orientation tileOrientation = model.getTileOrienation(); int xx, yy, w, h, multiplier; if (model.isScaleImage()) { w = tileWidth(tileOrientation, TileType.CROSS); h = tileHeight(tileOrientation, TileType.CROSS); multiplier = 1; } else { w = renderWidth; h = renderHeight; multiplier = 10; } switch (tileOrientation) { case SOUTH -> { xx = tileX - GRID * multiplier; yy = tileY - GRID * multiplier; } case WEST -> { xx = tileX - GRID * multiplier - GRID * 2 * multiplier; yy = tileY - GRID * multiplier; } case NORTH -> { xx = tileX - GRID * multiplier; yy = tileY - GRID * multiplier - GRID * 2 * multiplier; } default -> { //East xx = tileX - GRID * multiplier; yy = tileY - GRID * multiplier; } } if (model.isScaleImage()) { return new Rectangle(xx, yy, w, h); } else { return new Rectangle(xx, yy, renderWidth, renderHeight); } } private void changeRenderSizeAndOffsets() { //Reset offsets this.offsetY = 0; this.renderOffsetY = 0; this.offsetX = 0; this.renderOffsetX = 0; if (isHorizontal()) { this.renderWidth = RENDER_GRID * 4; this.renderHeight = RENDER_GRID * 2; this.offsetY = 0; this.renderOffsetY = 0; } else { this.renderWidth = RENDER_GRID * 2; this.renderHeight = RENDER_GRID * 4; this.offsetX = 0; this.renderOffsetX = 0; } //Due to the asymetical shape (center is on the left) //the offset has to be changed with the rotation Orientation tileOrientation = model.getTileOrienation(); switch (tileOrientation) { case SOUTH -> { this.offsetY = +GRID; this.renderOffsetY = RENDER_GRID; } case WEST -> { this.offsetX = -GRID; this.renderOffsetX = -RENDER_GRID; } case NORTH -> { this.offsetY = -GRID; this.renderOffsetY = -RENDER_GRID; } default -> { //East so default this.offsetX = +GRID; this.renderOffsetX = +RENDER_GRID; } } } @Override public Orientation rotate() { super.rotate(); Orientation tileOrientation = model.getTileOrienation(); int w = tileWidth(tileOrientation, TileType.CROSS); int h = tileHeight(tileOrientation, TileType.CROSS); Dimension d = new Dimension(w, h); setPreferredSize(d); setSize(d); changeRenderSizeAndOffsets(); setBounds(getTileBounds()); return tileOrientation; } } \ No newline at end of file diff --git a/src/main/java/jcs/ui/layout/tiles/Crossing.java b/src/main/java/jcs/ui/layout/tiles/Crossing.java index c9813112..59e62085 100644 --- a/src/main/java/jcs/ui/layout/tiles/Crossing.java +++ b/src/main/java/jcs/ui/layout/tiles/Crossing.java @@ -1,149 +1 @@ -/* - * Copyright 2023 Frans Jacobs. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package jcs.ui.layout.tiles; - -import java.awt.BasicStroke; -import java.awt.Color; -import java.awt.Graphics2D; -import java.awt.Point; -import java.util.HashMap; -import java.util.Map; -import jcs.entities.TileBean; -import jcs.entities.TileBean.Orientation; -import jcs.entities.TileBean.TileType; - -public class Crossing extends Straight { - - public Crossing(TileBean tileBean) { - super(tileBean); - } - - public Crossing(Orientation orientation, Point center) { - this(orientation, center.x, center.y); - } - - public Crossing(Orientation orientation, int x, int y) { - this(orientation, x, y, DEFAULT_WIDTH, DEFAULT_HEIGHT); - } - - public Crossing(Orientation orientation, int x, int y, int width, int height) { - super(orientation, x, y, width, height); - this.tileType = TileType.CROSSING; - } - - @Override - public Map getNeighborPoints() { - Map neighbors = new HashMap<>(); - int cx = this.getCenterX(); - int cy = this.getCenterY(); - - // Horizontal - neighbors.put(Orientation.EAST, new Point(cx + Tile.GRID * 2, cy)); - neighbors.put(Orientation.WEST, new Point(cx - Tile.GRID * 2, cy)); - // Vertical - neighbors.put(Orientation.NORTH, new Point(cx, cy - Tile.GRID * 2)); - neighbors.put(Orientation.SOUTH, new Point(cx, cy + Tile.GRID * 2)); - return neighbors; - } - - @Override - public Map getEdgePoints() { - Map edgeConnections = new HashMap<>(); - int cx = this.getCenterX(); - int cy = this.getCenterY(); - - // Horizontal - edgeConnections.put(Orientation.EAST, new Point(cx + Tile.GRID, cy)); - edgeConnections.put(Orientation.WEST, new Point(cx - Tile.GRID, cy)); - // Vertical - edgeConnections.put(Orientation.NORTH, new Point(cx, cy - Tile.GRID)); - edgeConnections.put(Orientation.SOUTH, new Point(cx, cy + Tile.GRID)); - return edgeConnections; - } - - protected void renderVerticalAndDividers(Graphics2D g2) { - int xxn, yyn, xxs, yys, w, h; - xxn = 175; - yyn = 0; - xxs = 175; - yys = 325; - w = 50; - h = 75; - - g2.setStroke(new BasicStroke(4, BasicStroke.JOIN_MITER, BasicStroke.JOIN_ROUND)); - g2.setPaint(trackColor); - - //North - g2.fillRect(xxn, yyn, w, h); - //South - g2.fillRect(xxs, yys, w, h); - - //Dividers - int[] xNorthPoly = new int[]{85, 115, 285, 315}; - int[] yNorthPoly = new int[]{85, 125, 125, 85}; - - int[] xSouthPoly = new int[]{85, 115, 285, 315}; - int[] ySouthPoly = new int[]{315, 275, 275, 315}; - - g2.setPaint(Color.darkGray); - g2.setStroke(new BasicStroke(8, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND)); - - g2.drawPolyline(xNorthPoly, yNorthPoly, xNorthPoly.length); - g2.drawPolyline(xSouthPoly, ySouthPoly, xSouthPoly.length); - } - - @Override - public void renderTile(Graphics2D g2) { - renderStraight(g2); - renderVerticalAndDividers(g2); - } - - protected void renderRouteVertical(Graphics2D g2) { - int xxn, yyn, xxs, yys, w, h; - xxn = 190; - yyn = 0; - xxs = 190; - yys = 325; - w = 20; - h = 75; - - g2.setStroke(new BasicStroke(4, BasicStroke.JOIN_MITER, BasicStroke.JOIN_ROUND)); - g2.setPaint(this.trackRouteColor); - - //North - g2.fillRect(xxn, yyn, w, h); - //South - g2.fillRect(xxs, yys, w, h); - } - -// @Override -// public void renderTileRoute(Graphics2D g2) { -// if (isHorizontal()) { -// if (Orientation.EAST == incomingSide || Orientation.WEST == incomingSide) { -// renderRouteStraight(g2); -// } else { -// renderRouteVertical(g2); -// } -// } else { -// if (Orientation.NORTH == incomingSide || Orientation.SOUTH == incomingSide) { -// renderRouteStraight(g2); -// } else { -// renderRouteVertical(g2); -// } -// } -// } - -} +/* * Copyright 2023 Frans Jacobs. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package jcs.ui.layout.tiles; import java.awt.BasicStroke; import java.awt.Color; import java.awt.Graphics2D; import java.awt.Point; import java.util.HashMap; import java.util.Map; import jcs.entities.TileBean; import jcs.entities.TileBean.Orientation; import jcs.entities.TileBean.TileType; public class Crossing extends Straight { public Crossing(TileBean tileBean) { super(tileBean); } public Crossing(Orientation orientation, Point center) { this(orientation, center.x, center.y); } public Crossing(Orientation orientation, int x, int y) { this(orientation, x, y, DEFAULT_WIDTH, DEFAULT_HEIGHT); } public Crossing(Orientation orientation, int x, int y, int width, int height) { super(orientation, x, y, width, height); this.tileType = TileType.CROSSING; } @Override public Map getNeighborPoints() { Map neighbors = new HashMap<>(); int cx = this.getCenterX(); int cy = this.getCenterY(); // Horizontal neighbors.put(Orientation.EAST, new Point(cx + Tile.GRID * 2, cy)); neighbors.put(Orientation.WEST, new Point(cx - Tile.GRID * 2, cy)); // Vertical neighbors.put(Orientation.NORTH, new Point(cx, cy - Tile.GRID * 2)); neighbors.put(Orientation.SOUTH, new Point(cx, cy + Tile.GRID * 2)); return neighbors; } @Override public Map getEdgePoints() { Map edgeConnections = new HashMap<>(); int cx = this.getCenterX(); int cy = this.getCenterY(); // Horizontal edgeConnections.put(Orientation.EAST, new Point(cx + Tile.GRID, cy)); edgeConnections.put(Orientation.WEST, new Point(cx - Tile.GRID, cy)); // Vertical edgeConnections.put(Orientation.NORTH, new Point(cx, cy - Tile.GRID)); edgeConnections.put(Orientation.SOUTH, new Point(cx, cy + Tile.GRID)); return edgeConnections; } protected void renderVerticalAndDividers(Graphics2D g2) { int xxn, yyn, xxs, yys, w, h; xxn = 175; yyn = 0; xxs = 175; yys = 325; w = 50; h = 75; g2.setStroke(new BasicStroke(4, BasicStroke.JOIN_MITER, BasicStroke.JOIN_ROUND)); g2.setPaint(trackColor); //North g2.fillRect(xxn, yyn, w, h); //South g2.fillRect(xxs, yys, w, h); //Dividers int[] xNorthPoly = new int[]{85, 115, 285, 315}; int[] yNorthPoly = new int[]{85, 125, 125, 85}; int[] xSouthPoly = new int[]{85, 115, 285, 315}; int[] ySouthPoly = new int[]{315, 275, 275, 315}; g2.setPaint(Color.darkGray); g2.setStroke(new BasicStroke(8, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND)); g2.drawPolyline(xNorthPoly, yNorthPoly, xNorthPoly.length); g2.drawPolyline(xSouthPoly, ySouthPoly, xSouthPoly.length); } @Override public void renderTile(Graphics2D g2) { renderStraight(g2); renderVerticalAndDividers(g2); } protected void renderRouteVertical(Graphics2D g2) { int xxn, yyn, xxs, yys, w, h; xxn = 190; yyn = 0; xxs = 190; yys = 325; w = 20; h = 75; g2.setStroke(new BasicStroke(4, BasicStroke.JOIN_MITER, BasicStroke.JOIN_ROUND)); g2.setPaint(this.trackRouteColor); //North g2.fillRect(xxn, yyn, w, h); //South g2.fillRect(xxs, yys, w, h); } } \ No newline at end of file diff --git a/src/main/java/jcs/ui/layout/tiles/Curved.java b/src/main/java/jcs/ui/layout/tiles/Curved.java index 0de19ed3..c16fa01b 100755 --- a/src/main/java/jcs/ui/layout/tiles/Curved.java +++ b/src/main/java/jcs/ui/layout/tiles/Curved.java @@ -1,161 +1 @@ -/* - * Copyright 2023 Frans Jacobs. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package jcs.ui.layout.tiles; - -import java.awt.BasicStroke; -import java.awt.Graphics2D; -import java.awt.Point; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Map; -import java.util.Set; -import jcs.entities.TileBean; -import jcs.entities.TileBean.Orientation; -import static jcs.entities.TileBean.Orientation.NORTH; -import static jcs.entities.TileBean.Orientation.SOUTH; -import static jcs.entities.TileBean.Orientation.WEST; -import jcs.entities.TileBean.TileType; - -public class Curved extends Tile { - - public Curved(TileBean tileBean) { - super(tileBean, DEFAULT_WIDTH, DEFAULT_HEIGHT); - setModel(new DefaultTileModel(tileBean.getOrientation())); - } - - public Curved(Orientation orientation, Point center) { - this(orientation, center.x, center.y); - } - - public Curved(Orientation orientation, int x, int y) { - this(orientation, x, y, DEFAULT_WIDTH, DEFAULT_HEIGHT); - } - - public Curved(Orientation orientation, int x, int y, int width, int height) { - super(TileType.CURVED, orientation, x, y, width, height); - setModel(new DefaultTileModel(orientation)); - } - - @Override - public Map getNeighborPoints() { - Map neighbors = new HashMap<>(); - Orientation orientation = this.getOrientation(); - int cx = this.getCenterX(); - int cy = this.getCenterY(); - - switch (orientation) { - case SOUTH -> { - neighbors.put(Orientation.WEST, new Point(cx - Tile.GRID * 2, cy)); - neighbors.put(Orientation.SOUTH, new Point(cx, cy + Tile.GRID * 2)); - } - case WEST -> { - neighbors.put(Orientation.WEST, new Point(cx - Tile.GRID * 2, cy)); - neighbors.put(Orientation.NORTH, new Point(cx, cy - Tile.GRID * 2)); - } - case NORTH -> { - neighbors.put(Orientation.NORTH, new Point(cx, cy - Tile.GRID * 2)); - neighbors.put(Orientation.EAST, new Point(cx + Tile.GRID * 2, cy)); - } - default -> { - //EAST - neighbors.put(Orientation.EAST, new Point(cx + Tile.GRID * 2, cy)); - neighbors.put(Orientation.SOUTH, new Point(cx, cy + Tile.GRID * 2)); - } - } - return neighbors; - } - - @Override - public Map getEdgePoints() { - Map edgeConnections = new HashMap<>(); - - Orientation orientation = this.getOrientation(); - int cx = this.getCenterX(); - int cy = this.getCenterY(); - - switch (orientation) { - case SOUTH -> { - // | | - // b \ |\ | - edgeConnections.put(Orientation.WEST, new Point(cx - Tile.GRID, cy)); - edgeConnections.put(Orientation.SOUTH, new Point(cx, cy + Tile.GRID)); - } - case WEST -> { - // |/ | - // t / | | - edgeConnections.put(Orientation.WEST, new Point(cx - Tile.GRID, cy)); - edgeConnections.put(Orientation.NORTH, new Point(cx, cy - Tile.GRID)); - } - case NORTH -> { - // t \ - edgeConnections.put(Orientation.NORTH, new Point(cx, cy - Tile.GRID)); - edgeConnections.put(Orientation.EAST, new Point(cx + Tile.GRID, cy)); - } - default -> { - //EAST b / - edgeConnections.put(Orientation.EAST, new Point(cx + Tile.GRID, cy)); - edgeConnections.put(Orientation.SOUTH, new Point(cx, cy + Tile.GRID)); - } - } - return edgeConnections; - } - - @Override - public Set getAllPoints() { - Set aps = new HashSet<>(); - aps.add(getCenter()); - return aps; - } - - @Override - public void renderTile(Graphics2D g2) { - int[] xPoints = new int[]{400, 400, 170, 230}; - int[] yPoints = new int[]{230, 170, 400, 400}; - - g2.setStroke(new BasicStroke(1, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND)); - g2.setPaint(trackColor); - - g2.fillPolygon(xPoints, yPoints, xPoints.length); - } - - @Override - public void renderTileRoute(Graphics2D g2) { - int[] xPoints = new int[]{400, 400, 190, 210}; - int[] yPoints = new int[]{210, 190, 400, 400}; - - g2.setStroke(new BasicStroke(1, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND)); - g2.setPaint(trackRouteColor); - - g2.fillPolygon(xPoints, yPoints, xPoints.length); - } - -// @Override -// protected void paintComponent(Graphics g) { -// long started = System.currentTimeMillis(); -// super.paintComponent(g); -// -// setBounds(this.tileX - GRID, this.tileY - GRID, this.getWidth(), this.getHeight()); -// -// Graphics2D g2 = (Graphics2D) g.create(); -// drawTile(g2); -// g2.dispose(); -// -// g.drawImage(this.tileImage, 0, 0, null); -// -// long now = System.currentTimeMillis(); -// Logger.trace(this.id + " Duration: " + (now - started) + " ms."); -// } -} +/* * Copyright 2023 Frans Jacobs. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package jcs.ui.layout.tiles; import java.awt.BasicStroke; import java.awt.Graphics2D; import java.awt.Point; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set; import jcs.entities.TileBean; import jcs.entities.TileBean.Orientation; import static jcs.entities.TileBean.Orientation.NORTH; import static jcs.entities.TileBean.Orientation.SOUTH; import static jcs.entities.TileBean.Orientation.WEST; import jcs.entities.TileBean.TileType; public class Curved extends Tile { public Curved(TileBean tileBean) { super(tileBean, DEFAULT_WIDTH, DEFAULT_HEIGHT); setModel(new DefaultTileModel(tileBean.getOrientation())); } public Curved(Orientation orientation, Point center) { this(orientation, center.x, center.y); } public Curved(Orientation orientation, int x, int y) { this(orientation, x, y, DEFAULT_WIDTH, DEFAULT_HEIGHT); } public Curved(Orientation orientation, int x, int y, int width, int height) { super(TileType.CURVED, orientation, x, y, width, height); setModel(new DefaultTileModel(orientation)); } @Override public Map getNeighborPoints() { Map neighbors = new HashMap<>(); Orientation orientation = this.getOrientation(); int cx = this.getCenterX(); int cy = this.getCenterY(); switch (orientation) { case SOUTH -> { neighbors.put(Orientation.WEST, new Point(cx - Tile.GRID * 2, cy)); neighbors.put(Orientation.SOUTH, new Point(cx, cy + Tile.GRID * 2)); } case WEST -> { neighbors.put(Orientation.WEST, new Point(cx - Tile.GRID * 2, cy)); neighbors.put(Orientation.NORTH, new Point(cx, cy - Tile.GRID * 2)); } case NORTH -> { neighbors.put(Orientation.NORTH, new Point(cx, cy - Tile.GRID * 2)); neighbors.put(Orientation.EAST, new Point(cx + Tile.GRID * 2, cy)); } default -> { //EAST neighbors.put(Orientation.EAST, new Point(cx + Tile.GRID * 2, cy)); neighbors.put(Orientation.SOUTH, new Point(cx, cy + Tile.GRID * 2)); } } return neighbors; } @Override public Map getEdgePoints() { Map edgeConnections = new HashMap<>(); Orientation orientation = this.getOrientation(); int cx = this.getCenterX(); int cy = this.getCenterY(); switch (orientation) { case SOUTH -> { // | | // b \ |\ | edgeConnections.put(Orientation.WEST, new Point(cx - Tile.GRID, cy)); edgeConnections.put(Orientation.SOUTH, new Point(cx, cy + Tile.GRID)); } case WEST -> { // |/ | // t / | | edgeConnections.put(Orientation.WEST, new Point(cx - Tile.GRID, cy)); edgeConnections.put(Orientation.NORTH, new Point(cx, cy - Tile.GRID)); } case NORTH -> { // t \ edgeConnections.put(Orientation.NORTH, new Point(cx, cy - Tile.GRID)); edgeConnections.put(Orientation.EAST, new Point(cx + Tile.GRID, cy)); } default -> { //EAST b / edgeConnections.put(Orientation.EAST, new Point(cx + Tile.GRID, cy)); edgeConnections.put(Orientation.SOUTH, new Point(cx, cy + Tile.GRID)); } } return edgeConnections; } @Override public void renderTile(Graphics2D g2) { int[] xPoints = new int[]{400, 400, 170, 230}; int[] yPoints = new int[]{230, 170, 400, 400}; g2.setStroke(new BasicStroke(1, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND)); g2.setPaint(trackColor); g2.fillPolygon(xPoints, yPoints, xPoints.length); } @Override public void renderTileRoute(Graphics2D g2) { int[] xPoints = new int[]{400, 400, 190, 210}; int[] yPoints = new int[]{210, 190, 400, 400}; g2.setStroke(new BasicStroke(1, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND)); g2.setPaint(trackRouteColor); g2.fillPolygon(xPoints, yPoints, xPoints.length); } // @Override // protected void paintComponent(Graphics g) { // long started = System.currentTimeMillis(); // super.paintComponent(g); // // setBounds(this.tileX - GRID, this.tileY - GRID, this.getWidth(), this.getHeight()); // // Graphics2D g2 = (Graphics2D) g.create(); // drawTile(g2); // g2.dispose(); // // g.drawImage(this.tileImage, 0, 0, null); // // long now = System.currentTimeMillis(); // Logger.trace(this.id + " Duration: " + (now - started) + " ms."); // } } \ No newline at end of file diff --git a/src/main/java/jcs/ui/layout/tiles/End.java b/src/main/java/jcs/ui/layout/tiles/End.java index e71da407..79b10135 100644 --- a/src/main/java/jcs/ui/layout/tiles/End.java +++ b/src/main/java/jcs/ui/layout/tiles/End.java @@ -1,147 +1 @@ -/* - * Copyright 2023 Frans Jacobs. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package jcs.ui.layout.tiles; - -import java.awt.BasicStroke; -import java.awt.Color; -import java.awt.Graphics2D; -import java.awt.Point; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Map; -import java.util.Set; -import jcs.entities.TileBean; -import jcs.entities.TileBean.Orientation; -import static jcs.entities.TileBean.Orientation.NORTH; -import static jcs.entities.TileBean.Orientation.SOUTH; -import static jcs.entities.TileBean.Orientation.WEST; -import jcs.entities.TileBean.TileType; - -public class End extends Tile { - - public End(TileBean tileBean) { - super(tileBean, DEFAULT_WIDTH, DEFAULT_HEIGHT); - setModel(new DefaultTileModel(tileBean.getOrientation())); - } - - public End(Orientation orientation, Point center) { - this(orientation, center.x, center.y); - } - - public End(Orientation orientation, int x, int y) { - this(orientation, x, y, DEFAULT_WIDTH, DEFAULT_HEIGHT); - } - - public End(Orientation orientation, int x, int y, int width, int height) { - super(TileType.END, orientation, x, y, width, height); - setModel(new DefaultTileModel(orientation)); - } - - @Override - public Map getNeighborPoints() { - Map neighbors = new HashMap<>(); - Orientation orientation = this.getOrientation(); - int cx = this.getCenterX(); - int cy = this.getCenterY(); - - switch (orientation) { - case SOUTH -> - neighbors.put(Orientation.SOUTH, new Point(cx, cy - Tile.GRID * 2)); - case WEST -> - neighbors.put(Orientation.WEST, new Point(cx + Tile.GRID * 2, cy)); - case NORTH -> - neighbors.put(Orientation.NORTH, new Point(cx, cy + Tile.GRID * 2)); - default -> //EAST - neighbors.put(Orientation.EAST, new Point(cx - Tile.GRID * 2, cy)); - } - return neighbors; - } - - @Override - public Set getAllPoints() { - Set aps = new HashSet<>(); - aps.add(getCenter()); - return aps; - } - - @Override - public Map getEdgePoints() { - Map edgeConnections = new HashMap<>(); - Orientation orientation = this.getOrientation(); - int cx = this.getCenterX(); - int cy = this.getCenterY(); - - switch (orientation) { - case SOUTH -> - edgeConnections.put(Orientation.SOUTH, new Point(cx, cy - Tile.GRID)); - case WEST -> - edgeConnections.put(Orientation.WEST, new Point(cx + Tile.GRID, cy)); - case NORTH -> - edgeConnections.put(Orientation.NORTH, new Point(cx, cy + Tile.GRID)); - default -> //EAST - edgeConnections.put(Orientation.EAST, new Point(cx - Tile.GRID, cy)); - } - return edgeConnections; - } - - protected void renderEnd(Graphics2D g2) { - int xx, yy, w, h; - xx = 0; - yy = 175; - - w = RENDER_GRID; - h = 50; - - g2.setStroke(new BasicStroke(40, BasicStroke.JOIN_MITER, BasicStroke.JOIN_ROUND)); - g2.setPaint(trackColor); - g2.fillRect(xx, yy, w, h); - - xx = RENDER_GRID; - yy = 100; - - w = 30; - h = 200; - - g2.setPaint(Color.DARK_GRAY); - g2.fillRect(xx, yy, w, h); - } - - @Override - public void renderTile(Graphics2D g2) { - renderEnd(g2); - } - - @Override - public void renderTileRoute(Graphics2D g2d) { - } - -// @Override -// protected void paintComponent(Graphics g) { -// long started = System.currentTimeMillis(); -// super.paintComponent(g); -// -// setBounds(this.tileX - GRID, this.tileY - GRID, this.getWidth(), this.getHeight()); -// -// Graphics2D g2 = (Graphics2D) g.create(); -// drawTile(g2); -// g2.dispose(); -// -// g.drawImage(this.tileImage, 0, 0, null); -// -// long now = System.currentTimeMillis(); -// Logger.trace(this.id + " Duration: " + (now - started) + " ms."); -// } -} +/* * Copyright 2023 Frans Jacobs. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package jcs.ui.layout.tiles; import java.awt.BasicStroke; import java.awt.Color; import java.awt.Graphics2D; import java.awt.Point; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set; import jcs.entities.TileBean; import jcs.entities.TileBean.Orientation; import static jcs.entities.TileBean.Orientation.NORTH; import static jcs.entities.TileBean.Orientation.SOUTH; import static jcs.entities.TileBean.Orientation.WEST; import jcs.entities.TileBean.TileType; public class End extends Tile { public End(TileBean tileBean) { super(tileBean, DEFAULT_WIDTH, DEFAULT_HEIGHT); setModel(new DefaultTileModel(tileBean.getOrientation())); } public End(Orientation orientation, Point center) { this(orientation, center.x, center.y); } public End(Orientation orientation, int x, int y) { this(orientation, x, y, DEFAULT_WIDTH, DEFAULT_HEIGHT); } public End(Orientation orientation, int x, int y, int width, int height) { super(TileType.END, orientation, x, y, width, height); setModel(new DefaultTileModel(orientation)); } @Override public Map getNeighborPoints() { Map neighbors = new HashMap<>(); Orientation orientation = this.getOrientation(); int cx = this.getCenterX(); int cy = this.getCenterY(); switch (orientation) { case SOUTH -> neighbors.put(Orientation.SOUTH, new Point(cx, cy - Tile.GRID * 2)); case WEST -> neighbors.put(Orientation.WEST, new Point(cx + Tile.GRID * 2, cy)); case NORTH -> neighbors.put(Orientation.NORTH, new Point(cx, cy + Tile.GRID * 2)); default -> //EAST neighbors.put(Orientation.EAST, new Point(cx - Tile.GRID * 2, cy)); } return neighbors; } @Override public Map getEdgePoints() { Map edgeConnections = new HashMap<>(); Orientation orientation = this.getOrientation(); int cx = this.getCenterX(); int cy = this.getCenterY(); switch (orientation) { case SOUTH -> edgeConnections.put(Orientation.SOUTH, new Point(cx, cy - Tile.GRID)); case WEST -> edgeConnections.put(Orientation.WEST, new Point(cx + Tile.GRID, cy)); case NORTH -> edgeConnections.put(Orientation.NORTH, new Point(cx, cy + Tile.GRID)); default -> //EAST edgeConnections.put(Orientation.EAST, new Point(cx - Tile.GRID, cy)); } return edgeConnections; } protected void renderEnd(Graphics2D g2) { int xx, yy, w, h; xx = 0; yy = 175; w = RENDER_GRID; h = 50; g2.setStroke(new BasicStroke(40, BasicStroke.JOIN_MITER, BasicStroke.JOIN_ROUND)); g2.setPaint(trackColor); g2.fillRect(xx, yy, w, h); xx = RENDER_GRID; yy = 100; w = 30; h = 200; g2.setPaint(Color.DARK_GRAY); g2.fillRect(xx, yy, w, h); } @Override public void renderTile(Graphics2D g2) { renderEnd(g2); } @Override public void renderTileRoute(Graphics2D g2d) { } // @Override // protected void paintComponent(Graphics g) { // long started = System.currentTimeMillis(); // super.paintComponent(g); // // setBounds(this.tileX - GRID, this.tileY - GRID, this.getWidth(), this.getHeight()); // // Graphics2D g2 = (Graphics2D) g.create(); // drawTile(g2); // g2.dispose(); // // g.drawImage(this.tileImage, 0, 0, null); // // long now = System.currentTimeMillis(); // Logger.trace(this.id + " Duration: " + (now - started) + " ms."); // } } \ No newline at end of file diff --git a/src/main/java/jcs/ui/layout/tiles/Straight.java b/src/main/java/jcs/ui/layout/tiles/Straight.java index 9cc63d74..e34552ca 100755 --- a/src/main/java/jcs/ui/layout/tiles/Straight.java +++ b/src/main/java/jcs/ui/layout/tiles/Straight.java @@ -1,147 +1 @@ -/* - * Copyright 2023 Frans Jacobs. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package jcs.ui.layout.tiles; - -import java.awt.BasicStroke; -import java.awt.Graphics2D; -import java.awt.Point; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Map; -import java.util.Set; -import jcs.entities.TileBean; -import jcs.entities.TileBean.Orientation; -import jcs.entities.TileBean.TileType; - -public class Straight extends Tile { - - public Straight(TileBean tileBean) { - super(tileBean, DEFAULT_WIDTH, DEFAULT_HEIGHT); - setModel(new DefaultTileModel(tileBean.getOrientation())); - } - - public Straight(Orientation orientation, Point center) { - this(orientation, center.x, center.y); - } - - public Straight(Orientation orientation, int x, int y) { - this(orientation, x, y, DEFAULT_WIDTH, DEFAULT_HEIGHT); - } - - public Straight(Orientation orientation, int x, int y, int width, int height) { - super(TileType.STRAIGHT, orientation, x, y, width, height); - setModel(new DefaultTileModel(orientation)); - } - - @Override - public Map getNeighborPoints() { - Map neighbors = new HashMap<>(); - Orientation orientation = this.getOrientation(); - int cx = this.getCenterX(); - int cy = this.getCenterY(); - - if (Orientation.EAST == orientation || Orientation.WEST == orientation) { - // Horizontal - neighbors.put(Orientation.EAST, new Point(cx + Tile.GRID * 2, cy)); - neighbors.put(Orientation.WEST, new Point(cx - Tile.GRID * 2, cy)); - } else { - // Vertical - neighbors.put(Orientation.NORTH, new Point(cx, cy - Tile.GRID * 2)); - neighbors.put(Orientation.SOUTH, new Point(cx, cy + Tile.GRID * 2)); - } - return neighbors; - } - - @Override - public Map getEdgePoints() { - Map edgeConnections = new HashMap<>(); - Orientation orientation = this.getOrientation(); - int cx = this.getCenterX(); - int cy = this.getCenterY(); - - if (Orientation.EAST == orientation || Orientation.WEST == orientation) { - // Horizontal - edgeConnections.put(Orientation.EAST, new Point(cx + Tile.GRID, cy)); - edgeConnections.put(Orientation.WEST, new Point(cx - Tile.GRID, cy)); - } else { - // Vertical - edgeConnections.put(Orientation.NORTH, new Point(cx, cy - Tile.GRID)); - edgeConnections.put(Orientation.SOUTH, new Point(cx, cy + Tile.GRID)); - } - return edgeConnections; - } - - @Override - public Set getAllPoints() { - Set aps = new HashSet<>(); - aps.add(getCenter()); - return aps; - } - - protected void renderStraight(Graphics2D g2) { - int xx, yy, w, h; - xx = 0; - yy = 170; - w = RENDER_WIDTH; - h = 60; - - g2.setStroke(new BasicStroke(4, BasicStroke.JOIN_MITER, BasicStroke.JOIN_ROUND)); - g2.setPaint(trackColor); - - g2.fillRect(xx, yy, w, h); - } - - protected void renderRouteStraight(Graphics2D g2) { - int xx, yy, w, h; - xx = 0; - yy = 190; - w = RENDER_WIDTH; - h = 20; - - g2.setStroke(new BasicStroke(4, BasicStroke.JOIN_MITER, BasicStroke.JOIN_ROUND)); - g2.setPaint(trackRouteColor); - - g2.fillRect(xx, yy, w, h); - } - - @Override - public void renderTileRoute(Graphics2D g2) { - renderRouteStraight(g2); - } - - @Override - public void renderTile(Graphics2D g2) { - renderStraight(g2); - } - -// @Override -// protected void paintComponent(Graphics g) { -// long started = System.currentTimeMillis(); -// super.paintComponent(g); -// -// setBounds(this.tileX - GRID, this.tileY - GRID, this.getWidth(), this.getHeight()); -// -// Graphics2D g2 = (Graphics2D) g.create(); -// drawTile(g2); -// g2.dispose(); -// -// g.drawImage(this.tileImage, 0, 0, null); -// -// long now = System.currentTimeMillis(); -// Logger.trace(this.id + " Duration: " + (now - started) + " ms."); -// } - -} +/* * Copyright 2023 Frans Jacobs. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package jcs.ui.layout.tiles; import java.awt.BasicStroke; import java.awt.Graphics2D; import java.awt.Point; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set; import jcs.entities.TileBean; import jcs.entities.TileBean.Orientation; import jcs.entities.TileBean.TileType; public class Straight extends Tile { public Straight(TileBean tileBean) { super(tileBean, DEFAULT_WIDTH, DEFAULT_HEIGHT); setModel(new DefaultTileModel(tileBean.getOrientation())); } public Straight(Orientation orientation, Point center) { this(orientation, center.x, center.y); } public Straight(Orientation orientation, int x, int y) { this(orientation, x, y, DEFAULT_WIDTH, DEFAULT_HEIGHT); } public Straight(Orientation orientation, int x, int y, int width, int height) { super(TileType.STRAIGHT, orientation, x, y, width, height); setModel(new DefaultTileModel(orientation)); } @Override public Map getNeighborPoints() { Map neighbors = new HashMap<>(); Orientation orientation = this.getOrientation(); int cx = this.getCenterX(); int cy = this.getCenterY(); if (Orientation.EAST == orientation || Orientation.WEST == orientation) { // Horizontal neighbors.put(Orientation.EAST, new Point(cx + Tile.GRID * 2, cy)); neighbors.put(Orientation.WEST, new Point(cx - Tile.GRID * 2, cy)); } else { // Vertical neighbors.put(Orientation.NORTH, new Point(cx, cy - Tile.GRID * 2)); neighbors.put(Orientation.SOUTH, new Point(cx, cy + Tile.GRID * 2)); } return neighbors; } @Override public Map getEdgePoints() { Map edgeConnections = new HashMap<>(); Orientation orientation = this.getOrientation(); int cx = this.getCenterX(); int cy = this.getCenterY(); if (Orientation.EAST == orientation || Orientation.WEST == orientation) { // Horizontal edgeConnections.put(Orientation.EAST, new Point(cx + Tile.GRID, cy)); edgeConnections.put(Orientation.WEST, new Point(cx - Tile.GRID, cy)); } else { // Vertical edgeConnections.put(Orientation.NORTH, new Point(cx, cy - Tile.GRID)); edgeConnections.put(Orientation.SOUTH, new Point(cx, cy + Tile.GRID)); } return edgeConnections; } protected void renderStraight(Graphics2D g2) { int xx, yy, w, h; xx = 0; yy = 170; w = RENDER_WIDTH; h = 60; g2.setStroke(new BasicStroke(4, BasicStroke.JOIN_MITER, BasicStroke.JOIN_ROUND)); g2.setPaint(trackColor); g2.fillRect(xx, yy, w, h); } protected void renderRouteStraight(Graphics2D g2) { int xx, yy, w, h; xx = 0; yy = 190; w = RENDER_WIDTH; h = 20; g2.setStroke(new BasicStroke(4, BasicStroke.JOIN_MITER, BasicStroke.JOIN_ROUND)); g2.setPaint(trackRouteColor); g2.fillRect(xx, yy, w, h); } @Override public void renderTileRoute(Graphics2D g2) { renderRouteStraight(g2); } @Override public void renderTile(Graphics2D g2) { renderStraight(g2); } } \ No newline at end of file diff --git a/src/main/java/jcs/ui/layout/tiles/Switch.java b/src/main/java/jcs/ui/layout/tiles/Switch.java index abfd920f..9dd3a651 100644 --- a/src/main/java/jcs/ui/layout/tiles/Switch.java +++ b/src/main/java/jcs/ui/layout/tiles/Switch.java @@ -1,361 +1 @@ -/* - * Copyright 2023 Frans Jacobs. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package jcs.ui.layout.tiles; - -import java.awt.BasicStroke; -import java.awt.Color; -import java.awt.Graphics2D; -import java.awt.Point; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Map; -import java.util.Set; -import jcs.commandStation.events.AccessoryEvent; -import jcs.commandStation.events.AccessoryEventListener; -import jcs.entities.AccessoryBean.AccessoryValue; -import static jcs.entities.AccessoryBean.AccessoryValue.GREEN; -import static jcs.entities.AccessoryBean.AccessoryValue.RED; -import jcs.entities.TileBean; -import jcs.entities.TileBean.Direction; -import static jcs.entities.TileBean.Direction.LEFT; -import static jcs.entities.TileBean.Direction.RIGHT; -import jcs.entities.TileBean.Orientation; -import static jcs.entities.TileBean.Orientation.NORTH; -import static jcs.entities.TileBean.Orientation.SOUTH; -import static jcs.entities.TileBean.Orientation.WEST; -import jcs.entities.TileBean.TileType; - -public class Switch extends Tile implements AccessoryEventListener { - - public Switch(Orientation orientation, Direction direction, Point center) { - this(orientation, direction, center.x, center.y); - } - - public Switch(Orientation orientation, Direction direction, int x, int y) { - this(orientation, direction, x, y, DEFAULT_WIDTH, DEFAULT_HEIGHT); - } - - public Switch(Orientation orientation, Direction direction, int x, int y, int width, int height) { - this(TileType.SWITCH, orientation, direction, x, y, width, height); - } - - protected Switch(TileType tileType, Orientation orientation, Direction direction, int x, int y, int width, int height) { - super(tileType, orientation, direction, x, y, width, height); - setModel(new DefaultTileModel(orientation)); - } - - public Switch(TileBean tileBean) { - this(tileBean, DEFAULT_WIDTH, DEFAULT_HEIGHT); - } - - protected Switch(TileBean tileBean, int width, int height) { - super(tileBean, width, height); - setModel(new DefaultTileModel(tileBean.getOrientation())); - } - - @Override - public Map getNeighborPoints() { - Map neighbors = new HashMap<>(); - Orientation orientation = this.getOrientation(); - Direction direction = this.getDirection(); - int cx = this.getCenterX(); - int cy = this.getCenterY(); - - switch (orientation) { - case SOUTH -> { - neighbors.put(Orientation.NORTH, new Point(cx, cy - Tile.GRID * 2)); - neighbors.put(Orientation.SOUTH, new Point(cx, cy + Tile.GRID * 2)); - if (Direction.LEFT == direction) { - neighbors.put(Orientation.WEST, new Point(cx - Tile.GRID * 2, cy)); - } else { - neighbors.put(Orientation.EAST, new Point(cx + Tile.GRID * 2, cy)); - } - } - case WEST -> { - neighbors.put(Orientation.EAST, new Point(cx + Tile.GRID * 2, cy)); - neighbors.put(Orientation.WEST, new Point(cx - Tile.GRID * 2, cy)); - if (Direction.LEFT == direction) { - neighbors.put(Orientation.NORTH, new Point(cx, cy - Tile.GRID * 2)); - } else { - neighbors.put(Orientation.SOUTH, new Point(cx, cy + Tile.GRID * 2)); - } - } - case NORTH -> { - neighbors.put(Orientation.NORTH, new Point(cx, cy - Tile.GRID * 2)); - neighbors.put(Orientation.SOUTH, new Point(cx, cy + Tile.GRID * 2)); - if (Direction.LEFT == direction) { - neighbors.put(Orientation.EAST, new Point(cx + Tile.GRID * 2, cy)); - } else { - neighbors.put(Orientation.WEST, new Point(cx - Tile.GRID * 2, cy)); - } - } - default -> { - //EAST - neighbors.put(Orientation.EAST, new Point(cx + Tile.GRID * 2, cy)); - neighbors.put(Orientation.WEST, new Point(cx - Tile.GRID * 2, cy)); - if (Direction.LEFT == direction) { - neighbors.put(Orientation.SOUTH, new Point(cx, cy + Tile.GRID * 2)); - } else { - neighbors.put(Orientation.NORTH, new Point(cx, cy - Tile.GRID * 2)); - } - } - } - return neighbors; - } - - @Override - public Map getEdgePoints() { - Map edgeConnections = new HashMap<>(); - Orientation orientation = this.getOrientation(); - Direction direction = this.getDirection(); - int cx = this.getCenterX(); - int cy = this.getCenterY(); - - switch (orientation) { - case SOUTH -> { - edgeConnections.put(Orientation.NORTH, new Point(cx, cy - Tile.GRID)); - edgeConnections.put(Orientation.SOUTH, new Point(cx, cy + Tile.GRID)); - if (Direction.LEFT == direction) { - edgeConnections.put(Orientation.WEST, new Point(cx - Tile.GRID, cy)); - } else { - edgeConnections.put(Orientation.EAST, new Point(cx + Tile.GRID, cy)); - } - } - case WEST -> { - edgeConnections.put(Orientation.EAST, new Point(cx + Tile.GRID, cy)); - edgeConnections.put(Orientation.WEST, new Point(cx - Tile.GRID, cy)); - if (Direction.LEFT == direction) { - edgeConnections.put(Orientation.NORTH, new Point(cx, cy - Tile.GRID)); - } else { - edgeConnections.put(Orientation.SOUTH, new Point(cx, cy + Tile.GRID)); - } - } - case NORTH -> { - edgeConnections.put(Orientation.NORTH, new Point(cx, cy - Tile.GRID)); - edgeConnections.put(Orientation.SOUTH, new Point(cx, cy + Tile.GRID)); - if (Direction.LEFT == direction) { - edgeConnections.put(Orientation.EAST, new Point(cx + Tile.GRID, cy)); - } else { - edgeConnections.put(Orientation.WEST, new Point(cx - Tile.GRID, cy)); - } - } - default -> { - //EAST - edgeConnections.put(Orientation.EAST, new Point(cx + Tile.GRID, cy)); - edgeConnections.put(Orientation.WEST, new Point(cx - Tile.GRID, cy)); - if (Direction.LEFT == direction) { - edgeConnections.put(Orientation.SOUTH, new Point(cx, cy + Tile.GRID)); - } else { - edgeConnections.put(Orientation.NORTH, new Point(cx, cy - Tile.GRID)); - } - } - } - return edgeConnections; - } - - @Override - public Set getAllPoints() { - Set aps = new HashSet<>(); - aps.add(getCenter()); - return aps; - } - - protected void renderStraight(Graphics2D g2, Color color) { - int xx, yy, w, h; - xx = 0; - yy = 170; - w = RENDER_WIDTH; - h = 60; - - g2.setStroke(new BasicStroke(4, BasicStroke.JOIN_MITER, BasicStroke.JOIN_ROUND)); - g2.setPaint(color); - - g2.fillRect(xx, yy, w, h); - } - - protected void renderDiagonal(Graphics2D g2, Color color) { - int[] xPoints, yPoints; - if (Direction.RIGHT.equals(getDirection())) { - xPoints = new int[]{400, 400, 170, 230}; - yPoints = new int[]{170, 230, 0, 0}; - } else { - xPoints = new int[]{400, 400, 170, 230}; - yPoints = new int[]{230, 170, 400, 400}; - } - - g2.setStroke(new BasicStroke(1, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND)); - g2.setPaint(color); - g2.fillPolygon(xPoints, yPoints, xPoints.length); - } - - protected void renderRouteStraight(Graphics2D g2, Color color) { - int xx, yy, w, h; - xx = 0; - yy = 190; - w = RENDER_WIDTH; - h = 20; - - g2.setStroke(new BasicStroke(4, BasicStroke.JOIN_MITER, BasicStroke.JOIN_ROUND)); - g2.setPaint(color); - - g2.fillRect(xx, yy, w, h); - } - - protected void renderRouteDiagonal(Graphics2D g2, Color color) { - int[] xPoints, yPoints; - if (Direction.RIGHT.equals(getDirection())) { - xPoints = new int[]{400, 400, 190, 210}; - yPoints = new int[]{190, 210, 0, 0}; - } else { - xPoints = new int[]{400, 400, 190, 210}; - yPoints = new int[]{210, 190, 400, 400}; - } - - g2.setStroke(new BasicStroke(1, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND)); - g2.setPaint(color); - - g2.fillPolygon(xPoints, yPoints, xPoints.length); - } - - @Override - public void renderTile(Graphics2D g2) { - if (accessoryValue == null) { - this.accessoryValue = AccessoryValue.OFF; - } - - switch (accessoryValue) { - case RED -> { - renderStraight(g2, trackColor); - renderDiagonal(g2, Color.red); - } - case GREEN -> { - renderDiagonal(g2, trackColor); - renderStraight(g2, Color.green); - } - default -> { - renderStraight(g2, trackColor); - renderDiagonal(g2, trackColor); - } - } - } - - @Override - public void renderTileRoute(Graphics2D g2) { - if (routeValue == null) { - routeValue = AccessoryValue.OFF; - } - switch (routeValue) { - case RED -> { - renderRouteDiagonal(g2, trackRouteColor); - } - case GREEN -> { - renderRouteStraight(g2, trackRouteColor); - } - default -> { - } - } - } - - @Override - public void onAccessoryChange(AccessoryEvent event) { - if (getAccessoryBean() != null && event.isEventFor(accessoryBean)) { - setAccessoryValue(event.getAccessoryBean().getAccessoryValue()); - } - } - - @Override - public boolean isJunction() { - return true; - } - - @Override - public AccessoryValue accessoryValueForRoute(Orientation from, Orientation to) { - if (from != null && to != null && this.getDirection() != null) { - switch (this.getDirection()) { - case LEFT -> { - if (this.isHorizontal()) { - if ((from == Orientation.WEST && to == Orientation.EAST) || (from == Orientation.EAST && to == Orientation.WEST)) { - return AccessoryValue.GREEN; - } else if (((from == Orientation.EAST && to == Orientation.SOUTH) || (from == Orientation.SOUTH && to == Orientation.EAST)) && Orientation.EAST == this.getOrientation()) { - return AccessoryValue.RED; - } else if (((from == Orientation.WEST && to == Orientation.NORTH) || (from == Orientation.NORTH && to == Orientation.WEST)) && Orientation.WEST == this.getOrientation()) { - return AccessoryValue.RED; - } else { - return AccessoryValue.OFF; - } - } else { - //Vertical - if ((from == Orientation.NORTH && to == Orientation.SOUTH) || (from == Orientation.SOUTH && to == Orientation.NORTH)) { - return AccessoryValue.GREEN; - } else if (((from == Orientation.SOUTH && to == Orientation.WEST) || (from == Orientation.WEST && to == Orientation.SOUTH)) && Orientation.SOUTH == this.getOrientation()) { - return AccessoryValue.RED; - } else if (((from == Orientation.NORTH && to == Orientation.EAST) || (from == Orientation.EAST && to == Orientation.NORTH)) && Orientation.NORTH == this.getOrientation()) { - return AccessoryValue.RED; - } else { - return AccessoryValue.OFF; - } - } - } - case RIGHT -> { - if (this.isHorizontal()) { - if ((from == Orientation.WEST && to == Orientation.EAST) || (from == Orientation.EAST && to == Orientation.WEST)) { - return AccessoryValue.GREEN; - } else if (((from == Orientation.EAST && to == Orientation.NORTH) || (from == Orientation.NORTH && to == Orientation.EAST)) && Orientation.EAST == this.getOrientation()) { - return AccessoryValue.RED; - } else if (((from == Orientation.WEST && to == Orientation.SOUTH) || (from == Orientation.SOUTH && to == Orientation.WEST)) && Orientation.WEST == this.getOrientation()) { - return AccessoryValue.RED; - } else { - return AccessoryValue.OFF; - } - } else { - //Vertical - if ((from == Orientation.NORTH && to == Orientation.SOUTH) || (from == Orientation.SOUTH && to == Orientation.NORTH)) { - return AccessoryValue.GREEN; - } else if (((from == Orientation.EAST && to == Orientation.SOUTH) || (from == Orientation.SOUTH && to == Orientation.EAST)) && Orientation.SOUTH == this.getOrientation()) { - return AccessoryValue.RED; - } else if (((from == Orientation.WEST && to == Orientation.NORTH) || (from == Orientation.NORTH && to == Orientation.WEST)) && Orientation.NORTH == this.getOrientation()) { - return AccessoryValue.RED; - } else { - return AccessoryValue.OFF; - } - } - } - default -> { - return AccessoryValue.OFF; - } - } - } else { - return AccessoryValue.OFF; - } - } - -// @Override -// protected void paintComponent(Graphics g) { -// long started = System.currentTimeMillis(); -// super.paintComponent(g); -// -// setBounds(this.tileX - GRID, this.tileY - GRID, this.getWidth(), this.getHeight()); -// -// Graphics2D g2 = (Graphics2D) g.create(); -// drawTile(g2); -// g2.dispose(); -// -// g.drawImage(this.tileImage, 0, 0, null); -// -// long now = System.currentTimeMillis(); -// Logger.trace(this.id + " Duration: " + (now - started) + " ms."); -// } -} +/* * Copyright 2023 Frans Jacobs. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package jcs.ui.layout.tiles; import java.awt.BasicStroke; import java.awt.Color; import java.awt.Graphics2D; import java.awt.Point; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set; import jcs.commandStation.events.AccessoryEvent; import jcs.commandStation.events.AccessoryEventListener; import jcs.entities.AccessoryBean.AccessoryValue; import static jcs.entities.AccessoryBean.AccessoryValue.GREEN; import static jcs.entities.AccessoryBean.AccessoryValue.RED; import jcs.entities.TileBean; import jcs.entities.TileBean.Direction; import static jcs.entities.TileBean.Direction.LEFT; import static jcs.entities.TileBean.Direction.RIGHT; import jcs.entities.TileBean.Orientation; import static jcs.entities.TileBean.Orientation.NORTH; import static jcs.entities.TileBean.Orientation.SOUTH; import static jcs.entities.TileBean.Orientation.WEST; import jcs.entities.TileBean.TileType; public class Switch extends Tile implements AccessoryEventListener { public Switch(Orientation orientation, Direction direction, Point center) { this(orientation, direction, center.x, center.y); } public Switch(Orientation orientation, Direction direction, int x, int y) { this(orientation, direction, x, y, DEFAULT_WIDTH, DEFAULT_HEIGHT); } public Switch(Orientation orientation, Direction direction, int x, int y, int width, int height) { this(TileType.SWITCH, orientation, direction, x, y, width, height); } protected Switch(TileType tileType, Orientation orientation, Direction direction, int x, int y, int width, int height) { super(tileType, orientation, direction, x, y, width, height); setModel(new DefaultTileModel(orientation)); } public Switch(TileBean tileBean) { this(tileBean, DEFAULT_WIDTH, DEFAULT_HEIGHT); } protected Switch(TileBean tileBean, int width, int height) { super(tileBean, width, height); setModel(new DefaultTileModel(tileBean.getOrientation())); } @Override public Map getNeighborPoints() { Map neighbors = new HashMap<>(); Orientation orientation = this.getOrientation(); Direction direction = this.getDirection(); int cx = this.getCenterX(); int cy = this.getCenterY(); switch (orientation) { case SOUTH -> { neighbors.put(Orientation.NORTH, new Point(cx, cy - Tile.GRID * 2)); neighbors.put(Orientation.SOUTH, new Point(cx, cy + Tile.GRID * 2)); if (Direction.LEFT == direction) { neighbors.put(Orientation.WEST, new Point(cx - Tile.GRID * 2, cy)); } else { neighbors.put(Orientation.EAST, new Point(cx + Tile.GRID * 2, cy)); } } case WEST -> { neighbors.put(Orientation.EAST, new Point(cx + Tile.GRID * 2, cy)); neighbors.put(Orientation.WEST, new Point(cx - Tile.GRID * 2, cy)); if (Direction.LEFT == direction) { neighbors.put(Orientation.NORTH, new Point(cx, cy - Tile.GRID * 2)); } else { neighbors.put(Orientation.SOUTH, new Point(cx, cy + Tile.GRID * 2)); } } case NORTH -> { neighbors.put(Orientation.NORTH, new Point(cx, cy - Tile.GRID * 2)); neighbors.put(Orientation.SOUTH, new Point(cx, cy + Tile.GRID * 2)); if (Direction.LEFT == direction) { neighbors.put(Orientation.EAST, new Point(cx + Tile.GRID * 2, cy)); } else { neighbors.put(Orientation.WEST, new Point(cx - Tile.GRID * 2, cy)); } } default -> { //EAST neighbors.put(Orientation.EAST, new Point(cx + Tile.GRID * 2, cy)); neighbors.put(Orientation.WEST, new Point(cx - Tile.GRID * 2, cy)); if (Direction.LEFT == direction) { neighbors.put(Orientation.SOUTH, new Point(cx, cy + Tile.GRID * 2)); } else { neighbors.put(Orientation.NORTH, new Point(cx, cy - Tile.GRID * 2)); } } } return neighbors; } @Override public Map getEdgePoints() { Map edgeConnections = new HashMap<>(); Orientation orientation = this.getOrientation(); Direction direction = this.getDirection(); int cx = this.getCenterX(); int cy = this.getCenterY(); switch (orientation) { case SOUTH -> { edgeConnections.put(Orientation.NORTH, new Point(cx, cy - Tile.GRID)); edgeConnections.put(Orientation.SOUTH, new Point(cx, cy + Tile.GRID)); if (Direction.LEFT == direction) { edgeConnections.put(Orientation.WEST, new Point(cx - Tile.GRID, cy)); } else { edgeConnections.put(Orientation.EAST, new Point(cx + Tile.GRID, cy)); } } case WEST -> { edgeConnections.put(Orientation.EAST, new Point(cx + Tile.GRID, cy)); edgeConnections.put(Orientation.WEST, new Point(cx - Tile.GRID, cy)); if (Direction.LEFT == direction) { edgeConnections.put(Orientation.NORTH, new Point(cx, cy - Tile.GRID)); } else { edgeConnections.put(Orientation.SOUTH, new Point(cx, cy + Tile.GRID)); } } case NORTH -> { edgeConnections.put(Orientation.NORTH, new Point(cx, cy - Tile.GRID)); edgeConnections.put(Orientation.SOUTH, new Point(cx, cy + Tile.GRID)); if (Direction.LEFT == direction) { edgeConnections.put(Orientation.EAST, new Point(cx + Tile.GRID, cy)); } else { edgeConnections.put(Orientation.WEST, new Point(cx - Tile.GRID, cy)); } } default -> { //EAST edgeConnections.put(Orientation.EAST, new Point(cx + Tile.GRID, cy)); edgeConnections.put(Orientation.WEST, new Point(cx - Tile.GRID, cy)); if (Direction.LEFT == direction) { edgeConnections.put(Orientation.SOUTH, new Point(cx, cy + Tile.GRID)); } else { edgeConnections.put(Orientation.NORTH, new Point(cx, cy - Tile.GRID)); } } } return edgeConnections; } protected void renderStraight(Graphics2D g2, Color color) { int xx, yy, w, h; xx = 0; yy = 170; w = RENDER_WIDTH; h = 60; g2.setStroke(new BasicStroke(4, BasicStroke.JOIN_MITER, BasicStroke.JOIN_ROUND)); g2.setPaint(color); g2.fillRect(xx, yy, w, h); } protected void renderDiagonal(Graphics2D g2, Color color) { int[] xPoints, yPoints; if (Direction.RIGHT.equals(getDirection())) { xPoints = new int[]{400, 400, 170, 230}; yPoints = new int[]{170, 230, 0, 0}; } else { xPoints = new int[]{400, 400, 170, 230}; yPoints = new int[]{230, 170, 400, 400}; } g2.setStroke(new BasicStroke(1, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND)); g2.setPaint(color); g2.fillPolygon(xPoints, yPoints, xPoints.length); } protected void renderRouteStraight(Graphics2D g2, Color color) { int xx, yy, w, h; xx = 0; yy = 190; w = RENDER_WIDTH; h = 20; g2.setStroke(new BasicStroke(4, BasicStroke.JOIN_MITER, BasicStroke.JOIN_ROUND)); g2.setPaint(color); g2.fillRect(xx, yy, w, h); } protected void renderRouteDiagonal(Graphics2D g2, Color color) { int[] xPoints, yPoints; if (Direction.RIGHT.equals(getDirection())) { xPoints = new int[]{400, 400, 190, 210}; yPoints = new int[]{190, 210, 0, 0}; } else { xPoints = new int[]{400, 400, 190, 210}; yPoints = new int[]{210, 190, 400, 400}; } g2.setStroke(new BasicStroke(1, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND)); g2.setPaint(color); g2.fillPolygon(xPoints, yPoints, xPoints.length); } @Override public void renderTile(Graphics2D g2) { if (accessoryValue == null) { this.accessoryValue = AccessoryValue.OFF; } switch (accessoryValue) { case RED -> { renderStraight(g2, trackColor); renderDiagonal(g2, Color.red); } case GREEN -> { renderDiagonal(g2, trackColor); renderStraight(g2, Color.green); } default -> { renderStraight(g2, trackColor); renderDiagonal(g2, trackColor); } } } @Override public void renderTileRoute(Graphics2D g2) { if (routeValue == null) { routeValue = AccessoryValue.OFF; } switch (routeValue) { case RED -> { renderRouteDiagonal(g2, trackRouteColor); } case GREEN -> { renderRouteStraight(g2, trackRouteColor); } default -> { } } } @Override public void onAccessoryChange(AccessoryEvent event) { if (getAccessoryBean() != null && event.isEventFor(accessoryBean)) { setAccessoryValue(event.getAccessoryBean().getAccessoryValue()); } } @Override public boolean isJunction() { return true; } @Override public AccessoryValue accessoryValueForRoute(Orientation from, Orientation to) { if (from != null && to != null && this.getDirection() != null) { switch (this.getDirection()) { case LEFT -> { if (this.isHorizontal()) { if ((from == Orientation.WEST && to == Orientation.EAST) || (from == Orientation.EAST && to == Orientation.WEST)) { return AccessoryValue.GREEN; } else if (((from == Orientation.EAST && to == Orientation.SOUTH) || (from == Orientation.SOUTH && to == Orientation.EAST)) && Orientation.EAST == this.getOrientation()) { return AccessoryValue.RED; } else if (((from == Orientation.WEST && to == Orientation.NORTH) || (from == Orientation.NORTH && to == Orientation.WEST)) && Orientation.WEST == this.getOrientation()) { return AccessoryValue.RED; } else { return AccessoryValue.OFF; } } else { //Vertical if ((from == Orientation.NORTH && to == Orientation.SOUTH) || (from == Orientation.SOUTH && to == Orientation.NORTH)) { return AccessoryValue.GREEN; } else if (((from == Orientation.SOUTH && to == Orientation.WEST) || (from == Orientation.WEST && to == Orientation.SOUTH)) && Orientation.SOUTH == this.getOrientation()) { return AccessoryValue.RED; } else if (((from == Orientation.NORTH && to == Orientation.EAST) || (from == Orientation.EAST && to == Orientation.NORTH)) && Orientation.NORTH == this.getOrientation()) { return AccessoryValue.RED; } else { return AccessoryValue.OFF; } } } case RIGHT -> { if (this.isHorizontal()) { if ((from == Orientation.WEST && to == Orientation.EAST) || (from == Orientation.EAST && to == Orientation.WEST)) { return AccessoryValue.GREEN; } else if (((from == Orientation.EAST && to == Orientation.NORTH) || (from == Orientation.NORTH && to == Orientation.EAST)) && Orientation.EAST == this.getOrientation()) { return AccessoryValue.RED; } else if (((from == Orientation.WEST && to == Orientation.SOUTH) || (from == Orientation.SOUTH && to == Orientation.WEST)) && Orientation.WEST == this.getOrientation()) { return AccessoryValue.RED; } else { return AccessoryValue.OFF; } } else { //Vertical if ((from == Orientation.NORTH && to == Orientation.SOUTH) || (from == Orientation.SOUTH && to == Orientation.NORTH)) { return AccessoryValue.GREEN; } else if (((from == Orientation.EAST && to == Orientation.SOUTH) || (from == Orientation.SOUTH && to == Orientation.EAST)) && Orientation.SOUTH == this.getOrientation()) { return AccessoryValue.RED; } else if (((from == Orientation.WEST && to == Orientation.NORTH) || (from == Orientation.NORTH && to == Orientation.WEST)) && Orientation.NORTH == this.getOrientation()) { return AccessoryValue.RED; } else { return AccessoryValue.OFF; } } } default -> { return AccessoryValue.OFF; } } } else { return AccessoryValue.OFF; } } // @Override // protected void paintComponent(Graphics g) { // long started = System.currentTimeMillis(); // super.paintComponent(g); // // setBounds(this.tileX - GRID, this.tileY - GRID, this.getWidth(), this.getHeight()); // // Graphics2D g2 = (Graphics2D) g.create(); // drawTile(g2); // g2.dispose(); // // g.drawImage(this.tileImage, 0, 0, null); // // long now = System.currentTimeMillis(); // Logger.trace(this.id + " Duration: " + (now - started) + " ms."); // } } \ No newline at end of file diff --git a/src/main/java/jcs/ui/layout/tiles/Tile.java b/src/main/java/jcs/ui/layout/tiles/Tile.java index f22ea4f7..48c1598a 100755 --- a/src/main/java/jcs/ui/layout/tiles/Tile.java +++ b/src/main/java/jcs/ui/layout/tiles/Tile.java @@ -1,1133 +1 @@ -/* - * Copyright 2024 Frans Jacobs. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package jcs.ui.layout.tiles; - -import java.awt.Color; -import java.awt.Dimension; -import java.awt.Graphics; -import java.awt.Graphics2D; -import java.awt.Point; -import java.awt.Rectangle; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; -import java.awt.geom.AffineTransform; -import java.awt.geom.Ellipse2D; -import java.awt.image.AffineTransformOp; -import java.awt.image.BufferedImage; -import java.beans.PropertyChangeListener; -import java.io.Serializable; -import java.util.Collection; -import java.util.Collections; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Set; -import javax.swing.JComponent; -import javax.swing.event.ChangeEvent; -import javax.swing.event.ChangeListener; -import jcs.entities.AccessoryBean; -import jcs.entities.AccessoryBean.AccessoryValue; -import jcs.entities.AccessoryBean.SignalType; -import jcs.entities.BlockBean; -import jcs.entities.BlockBean.BlockState; -import jcs.entities.LocomotiveBean; -import jcs.entities.SensorBean; -import jcs.entities.TileBean; -import jcs.entities.TileBean.Direction; -import jcs.entities.TileBean.Orientation; -import jcs.entities.TileBean.TileType; -import jcs.ui.layout.LayoutUtil; -import static jcs.ui.layout.tiles.Block.BLOCK_HEIGHT; -import static jcs.ui.layout.tiles.Block.BLOCK_WIDTH; -import org.imgscalr.Scalr; -import org.imgscalr.Scalr.Method; -import org.imgscalr.Scalr.Mode; -import org.tinylog.Logger; - -/** - * Basic graphic element to display a track, turnout, etc on the screen.
- * By default the drawing of a Tile is Horizontal from L to R or West to East.
- * The default orientation is East. - * - *

- * The default size of a Tile is 40 tileX 40 pixels.
- * The center point of a Tile is stored and always snapped to the nearest grid point.
- * The basic grid is 20x 20 pixels.
- * - *

- * A Tile can be rotated (always clockwise).
- * Rotation will change the orientation from East -> South -> West -> North -> East.
- * - *

- * A Tile is rendered to a Buffered Image to speed up the display - */ -public abstract class Tile extends JComponent { //implements TileEventListener { //, ItemSelectable { - - public static final int GRID = 20; - public static final int DEFAULT_WIDTH = GRID * 2; - public static final int DEFAULT_HEIGHT = GRID * 2; - - static final int RENDER_GRID = GRID * 10; - static final int RENDER_WIDTH = RENDER_GRID * 2; - static final int RENDER_HEIGHT = RENDER_GRID * 2; - - public static final Color DEFAULT_BACKGROUND_COLOR = Color.white; - public static final Color DEFAULT_TRACK_COLOR = Color.lightGray; - public static final Color DEFAULT_ROUTE_TRACK_COLOR = Color.blue; - public static final Color DEFAULT_SELECTED_COLOR = Color.orange; - public static final Color DEFAULT_WARN_COLOR = Color.red; - - public static final String MODEL_CHANGED_PROPERTY = "model"; - public static final String CONTENT_AREA_FILLED_CHANGED_PROPERTY = "contentAreaFilled"; - - /** - * The data model that determines the button's state. - */ - protected TileModel model = null; - - protected String id; - protected Integer tileX; - protected Integer tileY; - - protected int renderWidth; - protected int renderHeight; - - //protected Orientation tileOrientation; - protected Direction tileDirection; - - protected TileType tileType; - protected String accessoryId; - protected String sensorId; - - protected AccessoryValue accessoryValue; - protected AccessoryValue routeValue; - - protected SignalType signalType; - protected AccessoryBean.SignalValue signalValue; - - protected TileBean tileBean; - protected AccessoryBean accessoryBean; - protected SensorBean sensorBean; - protected BlockBean blockBean; - - protected List neighbours; - - protected int offsetX = 0; - protected int offsetY = 0; - - protected int renderOffsetX = 0; - protected int renderOffsetY = 0; - - //protected Color selectedColor; - protected Color trackColor; - protected Color trackRouteColor; - protected Orientation incomingSide; - - protected Color backgroundColor; - protected boolean drawName = true; - - protected BufferedImage tileImage; - - protected PropertyChangeListener propertyChangeListener; - - protected ChangeListener changeListener = null; - protected ActionListener actionListener = null; - - protected transient ChangeEvent changeEvent; - - private Handler handler; - - protected Tile(TileType tileType, Orientation orientation, Point center, int width, int height) { - this(tileType, orientation, Direction.CENTER, center.x, center.y, width, height); - } - - protected Tile(TileType tileType, Orientation orientation, int x, int y, int width, int height) { - this(tileType, orientation, Direction.CENTER, x, y, width, height); - } - - protected Tile(TileType tileType, Orientation orientation, Direction direction, int x, int y, int width, int height) { - this(tileType, orientation, direction, x, y, width, height, null, null); - } - - protected Tile(TileType tileType, Orientation orientation, Direction direction, int x, int y, int width, int height, Color backgroundColor, Color selectedColor) { - this.tileType = tileType; - //this.tileOrientation = orientation; - //model.setTileOrienation(orientation); - this.tileDirection = direction; - this.tileX = x; - this.tileY = y; - - setLayout(null); - Dimension d = new Dimension(width, height); - setSize(d); - setPreferredSize(d); - - this.renderWidth = RENDER_WIDTH; - this.renderHeight = RENDER_HEIGHT; - - this.trackColor = DEFAULT_TRACK_COLOR; - this.backgroundColor = backgroundColor; - //this.selectedColor = selectedColor; - - if (this.backgroundColor == null) { - this.backgroundColor = DEFAULT_BACKGROUND_COLOR; - } -// if (this.selectedColor == null) { -// this.selectedColor = DEFAULT_SELECTED_COLOR; -// } - } - - protected Tile(TileBean tileBean) { - this(tileBean, tileWidth(tileBean.getOrientation(), tileBean.getTileType()), tileHeight(tileBean.getOrientation(), tileBean.getTileType())); - } - - protected Tile(TileBean tileBean, int width, int height) { - this.tileBean = tileBean; - //Quick properties - this.id = tileBean.getId(); - this.tileType = tileBean.getTileType(); - //this.tileOrientation = tileBean.getOrientation(); - //this.model.setTileOrienation(tileBean.getOrientation()); - this.tileDirection = tileBean.getDirection(); - this.tileX = tileBean.getX(); - this.tileY = tileBean.getY(); - - this.accessoryId = tileBean.getAccessoryId(); - this.accessoryBean = tileBean.getAccessoryBean(); - this.signalType = tileBean.getSignalType(); - - this.sensorId = tileBean.getSensorId(); - this.sensorBean = tileBean.getSensorBean(); - this.blockBean = tileBean.getBlockBean(); - - setLayout(null); - Dimension d = new Dimension(width, height); - setSize(d); - setPreferredSize(d); - - this.trackColor = DEFAULT_TRACK_COLOR; - this.backgroundColor = DEFAULT_BACKGROUND_COLOR; -// this.selectedColor = DEFAULT_SELECTED_COLOR; - this.renderWidth = RENDER_WIDTH; - this.renderHeight = RENDER_HEIGHT; - } - - protected static int tileWidth(Orientation orientation, TileType tileType) { - if (Orientation.EAST == orientation || Orientation.WEST == orientation) { - if (null == tileType) { - return DEFAULT_WIDTH; - } else { - return switch (tileType) { - case BLOCK -> - BLOCK_WIDTH; - case CROSS -> - DEFAULT_WIDTH * 2; - default -> - DEFAULT_WIDTH; - }; - } - } else { - return DEFAULT_WIDTH; - } - } - - protected static int tileHeight(Orientation orientation, TileType tileType) { - if (Orientation.EAST == orientation || Orientation.WEST == orientation) { - return DEFAULT_HEIGHT; - } else { - if (null == tileType) { - return DEFAULT_HEIGHT; - } else { - return switch (tileType) { - case BLOCK -> - BLOCK_HEIGHT; - case CROSS -> - DEFAULT_HEIGHT * 2; - default -> - DEFAULT_HEIGHT; - }; - } - } - } - - protected void populateModel() { - if (this.blockBean != null) { - this.model.setBlockState(this.blockBean.getBlockState()); - this.model.setLocomotive(this.blockBean.getLocomotive()); - this.model.setArrivalSuffix(this.blockBean.getArrivalSuffix()); - this.model.setLogicalDirection(LocomotiveBean.Direction.get(this.blockBean.getLogicalDirection())); - } - } - - public TileBean getTileBean() { - if (tileBean == null) { - tileBean = new TileBean(); - tileBean.setId(this.id); - tileBean.setX(this.tileX); - tileBean.setY(this.tileY); - tileBean.setTileType(this.tileType); - //tileBean.setTileOrientation(this.tileOrientation.getOrientation()); - tileBean.setTileOrientation(this.model.getTileOrienation().getOrientation()); - - tileBean.setTileDirection(this.tileDirection.getDirection()); - tileBean.setSignalType(this.signalType); - tileBean.setAccessoryId(this.accessoryId); - tileBean.setSensorId(this.sensorId); - tileBean.setAccessoryBean(this.accessoryBean); - tileBean.setSensorBean(this.sensorBean); - tileBean.setBlockBean(this.blockBean); - } - return tileBean; - } - - public boolean isSelected() { - return model.isSelected(); - } - - public void setSelected(boolean b) { - //boolean oldValue = isSelected(); - model.setSelected(b); - } - - public String getId() { - return id; - } - - public void setId(String id) { - this.id = id; - } - - public SignalType getSignalType() { - return signalType; - } - - public void setSignalType(SignalType signalType) { - this.signalType = signalType; - } - - public Integer getTileX() { - return tileX; - } - - public Integer getTileY() { - return tileY; - } - - public Point getCenter() { - return new Point(this.tileX, this.tileY); - } - - public void setCenter(Point center) { - tileX = center.x; - tileY = center.y; - if (tileBean != null) { - tileBean.setCenter(center); - } - Logger.trace(id + " Cp: " + xyToString()); - } - - public Orientation getOrientation() { - //return tileOrientation; - return model.getTileOrienation(); - } - - public void setOrientation(Orientation orientation) { - //this.tileOrientation = orientation; - model.setTileOrienation(orientation); - if (tileBean != null) { - tileBean.setOrientation(orientation); - } - } - - public Direction getDirection() { - return tileDirection; - } - - public void setDirection(Direction direction) { - this.tileDirection = direction; - if (tileBean != null) { - tileBean.setDirection(direction); - } - } - - public String getAccessoryId() { - return accessoryId; - } - - public void setAccessoryId(String accessoryId) { - this.accessoryId = accessoryId; - if (tileBean != null) { - tileBean.setAccessoryId(accessoryId); - } - } - - public String getSensorId() { - return sensorId; - } - - public void setSensorId(String sensorId) { - this.sensorId = sensorId; - } - - public boolean isActive() { - return model.isSensorActive(); - } - - public void setActive(boolean active) { - model.setSensorActive(active); - } - - public BlockState getBlockState() { - return model.getBlockState(); - } - - public void setBlockState(BlockState blockState) { - if (blockBean != null) { - blockBean.setBlockState(blockState); - LocomotiveBean locomotive = model.getLocomotive(); - model.setOverlayImage(locomotive != null && locomotive.getLocIcon() != null && (blockState == BlockState.OCCUPIED || blockState == BlockState.INBOUND || blockState == BlockState.OUTBOUND)); - } - model.setBlockState(blockState); - } - - public String getDepartureSuffix() { - return model.getDepartureSuffix(); - } - - public void setDepartureSuffix(String suffix) { - if (blockBean != null) { - blockBean.setDepartureSuffix(suffix); - } - model.setDepartureSuffix(suffix); - } - - public boolean isReverseArrival() { - return model.isReverseArrival(); - } - - public void setReverseArrival(boolean reverseArrival) { - if (blockBean != null) { - blockBean.setReverseArrival(reverseArrival); - } - model.setReverseArrival(reverseArrival); - } - - public LocomotiveBean.Direction getLogicalDirection() { - return model.getLogicalDirection(); - } - - public void setLogicalDirection(LocomotiveBean.Direction logicalDirection) { - if (blockBean != null) { - blockBean.setLogicalDirection(logicalDirection.getDirection()); - } - model.setLogicalDirection(logicalDirection); - } - - public LocomotiveBean getLocomotive() { - return model.getLocomotive(); - } - - public void setLocomotive(LocomotiveBean locomotive) { - if (blockBean != null) { - blockBean.setLocomotive(locomotive); - model.setOverlayImage(locomotive != null && locomotive.getLocIcon() != null && (model.getBlockState() == BlockState.OCCUPIED || model.getBlockState() == BlockState.INBOUND || model.getBlockState() == BlockState.OUTBOUND)); - } - - model.setLocomotive(locomotive); - } - - public AccessoryBean getAccessoryBean() { - return accessoryBean; - } - - public void setAccessoryBean(AccessoryBean accessoryBean) { - this.accessoryBean = accessoryBean; - - if (accessoryBean != null) { - accessoryId = accessoryBean.getId(); - signalValue = accessoryBean.getSignalValue(); - signalType = SignalType.getSignalType(accessoryBean.getType()); - } else { - accessoryId = null; - signalType = SignalType.NONE; - signalValue = AccessoryBean.SignalValue.OFF; - } - } - - public AccessoryValue getAccessoryValue() { - if (this.accessoryValue == null) { - return AccessoryValue.OFF; - } else { - return accessoryValue; - } - } - - public void setAccessoryValue(AccessoryValue value) { - this.accessoryValue = value; - repaint(); - } - - public AccessoryValue getRouteValue() { - if (routeValue == null) { - return AccessoryValue.OFF; - } else { - return routeValue; - } - } - - public void setRouteValue(AccessoryValue value) { - this.routeValue = value; - repaint(); - } - - public AccessoryBean.SignalValue getSignalValue() { - return signalValue; - } - - public void setSignalValue(AccessoryBean.SignalValue signalValue) { - this.signalValue = signalValue; - repaint(); - } - - public SensorBean getSensorBean() { - return sensorBean; - } - - public void setSensorBean(SensorBean sensorBean) { - this.sensorBean = sensorBean; - } - - public BlockBean getBlockBean() { - return blockBean; - } - - public void setBlockBean(BlockBean blockBean) { - this.blockBean = blockBean; - } - - public void setRenderWidth(int renderWidth) { - this.renderWidth = renderWidth; - } - - public void setRenderHeight(int renderHeight) { - this.renderHeight = renderHeight; - } - - public int getRenderOffsetX() { - return renderOffsetX; - } - - public void setRenderOffsetX(int renderOffsetX) { - this.renderOffsetX = renderOffsetX; - } - - public int getRenderOffsetY() { - return renderOffsetY; - } - - public void setRenderOffsetY(int renderOffsetY) { - this.renderOffsetY = renderOffsetY; - } - - public TileBean.TileType getTileType() { - return this.tileType; - } - - public final void setTileType(TileType tileType) { - this.tileType = tileType; - } - - public Color getTrackColor() { - return trackColor; - } - - public final void setTrackColor(Color trackColor) { - this.trackColor = trackColor; - } - - public Color getTrackRouteColor() { - return trackRouteColor; - } - - public void setTrackRouteColor(Color trackRouteColor) { - this.trackRouteColor = trackRouteColor; - } - - public Color getSelectedColor() { - return model.getSelectedColor(); - } - - public void setSelectedColor(Color selectedColor) { - this.model.setSelectedColor(selectedColor); - } - - public Orientation getIncomingSide() { - return incomingSide; - } - - public void setIncomingSide(Orientation incomingSide) { - this.incomingSide = incomingSide; - } - - public Color getBackgroundColor() { - return backgroundColor; - } - - public void setBackgroundColor(Color backgroundColor) { - this.backgroundColor = backgroundColor; - } - - public boolean isDrawRoute() { - return model.isShowRoute(); - } - - public void setDrawRoute(boolean drawRoute) { - this.model.setShowRoute(drawRoute); - } - - public int getRenderWidth() { - return renderWidth; - } - - public int getRenderHeight() { - return renderHeight; - } - - abstract void renderTile(Graphics2D g2d); - - abstract void renderTileRoute(Graphics2D g2d); - - public abstract Map getNeighborPoints(); - - public abstract Map getEdgePoints(); - - public abstract Set getAllPoints(); - - /** - * Draw the Tile - * - * @param g2d The graphics handle - */ - public void drawTile(Graphics2D g2d) { - // by default and image is rendered in the EAST orientation - Orientation tileOrientation = model.getTileOrienation(); -// if (tileOrientation == null) { -// tileOrientation = Orientation.EAST; -// } - - BufferedImage bf = createImage(); - Graphics2D g2di = bf.createGraphics(); - - //Avoid errors - if (model.isShowRoute() && incomingSide == null) { - incomingSide = getOrientation(); - } - - if (model.isSelected()) { - g2di.setBackground(model.getSelectedColor()); - } else { - g2di.setBackground(backgroundColor); - } - - g2di.clearRect(0, 0, renderWidth, renderHeight); - int ox = 0, oy = 0; - - AffineTransform trans = new AffineTransform(); - switch (tileOrientation) { - case SOUTH -> { - trans.rotate(Math.PI / 2, renderWidth / 2, renderHeight / 2); - ox = (renderHeight - renderWidth) / 2; - oy = (renderWidth - renderHeight) / 2; - trans.translate(-ox, -oy); - } - case WEST -> { - trans.rotate(Math.PI, renderWidth / 2, renderHeight / 2); - trans.translate(ox, oy); - } - case NORTH -> { - trans.rotate(-Math.PI / 2, renderWidth / 2, renderHeight / 2); - ox = (renderHeight - renderWidth) / 2; - oy = (renderWidth - renderHeight) / 2; - trans.translate(-ox, -oy); - } - default -> { - trans.rotate(0.0, this.renderWidth / 2, this.renderHeight / 2); - trans.translate(ox, oy); - } - } - - //Logger.trace(tileOrientation.getOrientation() + " renderWidth: " + renderWidth + " renderHeight: " + renderHeight + " CP: (" + renderWidth / 2 + "," + renderHeight / 2 + ")"); - //Logger.trace(tileOrientation.getOrientation() + " ox: " + ox + " oy: " + oy); - g2di.setTransform(trans); - - renderTile(g2di); - - if (model.isShowRoute()) { - renderTileRoute(g2di); - } - - if (model.isShowCenter()) { - drawCenterPoint(g2di); - } - - // Scale the image back... - if (model.isScaleImage()) { - tileImage = Scalr.resize(bf, Method.AUTOMATIC, Mode.FIT_EXACT, getWidth(), getHeight(), Scalr.OP_ANTIALIAS); - } else { - tileImage = bf; - } - - g2di.dispose(); - - Logger.trace(id + " Cp: " + xyToString()); - - } - - public BufferedImage getTileImage() { - return tileImage; - } - - /** - * Render a tile image Always starts at (0,0) used the default width and height - * - * @param g2 the Graphic context - */ - public void drawName(Graphics2D g2) { - } - - protected void drawCenterPoint(Graphics2D g2d) { - drawCenterPoint(g2d, Color.magenta); - } - - protected void drawCenterPoint(Graphics2D g2, Color color) { - drawCenterPoint(g2, color, 60); - } - - protected void drawCenterPoint(Graphics2D g2d, Color color, double size) { - double dX = (renderWidth / 2 - size / 2); - double dY = (renderHeight / 2 - size / 2); - - g2d.setColor(color); - g2d.fill(new Ellipse2D.Double(dX, dY, size, size)); - } - - /** - * Rotate the tile clockwise 90 deg - * - * @return the new Orientation - */ - public Orientation rotate() { - Orientation tileOrientation = model.getTileOrienation(); - switch (tileOrientation) { - case EAST -> - setOrientation(Orientation.SOUTH); - case SOUTH -> - setOrientation(Orientation.WEST); - case WEST -> - setOrientation(Orientation.NORTH); - default -> - setOrientation(Orientation.EAST); - } - return model.getTileOrienation(); - } - - public void flipHorizontal() { - Orientation tileOrientation = model.getTileOrienation(); - if (Orientation.NORTH == tileOrientation || Orientation.SOUTH == tileOrientation) { - rotate(); - rotate(); - } - } - - public void flipVertical() { - Orientation tileOrientation = model.getTileOrienation(); - if (Orientation.EAST == tileOrientation || Orientation.WEST == tileOrientation) { - rotate(); - rotate(); - } - } - - @Override - public void move(int newX, int newY) { - Point cs = LayoutUtil.snapToGrid(newX, newY); - setCenter(cs); - } - - protected static void drawRotate(Graphics2D g2d, double x, double y, int angle, String text) { - g2d.translate((float) x, (float) y); - g2d.rotate(Math.toRadians(angle)); - g2d.drawString(text, 0, 0); - g2d.rotate(-Math.toRadians(angle)); - g2d.translate(-x, -y); - } - - public static BufferedImage flipHorizontally(BufferedImage source) { - BufferedImage output = new BufferedImage(source.getHeight(), source.getWidth(), source.getType()); - - AffineTransform flip = AffineTransform.getScaleInstance(1, -1); - flip.translate(0, -source.getHeight()); - AffineTransformOp op = new AffineTransformOp(flip, AffineTransformOp.TYPE_NEAREST_NEIGHBOR); - - op.filter(source, output); - - return output; - } - - public static BufferedImage flipVertically(BufferedImage source) { - BufferedImage output = new BufferedImage(source.getHeight(), source.getWidth(), source.getType()); - - AffineTransform flip = AffineTransform.getScaleInstance(-1, 1); - flip.translate(-source.getWidth(), 0); - AffineTransformOp op = new AffineTransformOp(flip, AffineTransformOp.TYPE_NEAREST_NEIGHBOR); - - op.filter(source, output); - - return output; - } - - public Set getAltPoints() { - return Collections.EMPTY_SET; - } - - public final int getOffsetX() { - return offsetX; - } - - public void setOffsetX(int offsetX) { - this.offsetX = offsetX; - } - - public final int getOffsetY() { - return offsetY; - } - - public void setOffsetY(int offsetY) { - this.offsetY = offsetY; - } - - protected BufferedImage createImage() { - return new BufferedImage(renderWidth, renderHeight, BufferedImage.TYPE_INT_RGB); - } - - public int getCenterX() { - if (tileX > 0) { - return this.tileX; - } else { - return GRID; - } - } - - public int getCenterY() { - if (tileY > 0) { - return this.tileY; - } else { - return GRID; - } - } - - public boolean isDrawName() { - return drawName; - } - - public void setDrawName(boolean drawName) { - this.drawName = drawName; - } - - public boolean isScaleImage() { - return model.isScaleImage(); - } - - public void setScaleImage(boolean scaleImage) { - Dimension d; - if (scaleImage) { - d = new Dimension(DEFAULT_WIDTH, DEFAULT_HEIGHT); - } else { - d = new Dimension(renderWidth, renderHeight); - } - - setSize(d); - setPreferredSize(d); - - model.setScaleImage(scaleImage); - } - - public boolean isDrawCenterPoint() { - return model.isShowCenter(); - } - - public void setDrawCenterPoint(boolean drawCenterPoint) { - model.setShowCenter(drawCenterPoint); - } - - @Override - public String toString() { - return this.getClass().getSimpleName() - + " {id: " - + this.id - + ", orientation: " - + getOrientation() - + ", direction: " - + getDirection() - + ", center: " - + xyToString() - + "}"; - } - - public String xyToString() { - return "(" + this.tileX + "," + this.tileY + ")"; - } - - /** - * The main route of the tile is horizontal - * - * @return true when main route goes from East to West or vv - */ - public boolean isHorizontal() { - Orientation tileOrientation = model.getTileOrienation(); - return (Orientation.EAST == tileOrientation || Orientation.WEST == tileOrientation) && TileType.CURVED != tileType; - } - - /** - * The main route of the tile is vertical - * - * @return true when main route goes from North to South or vv - */ - public boolean isVertical() { - Orientation tileOrientation = model.getTileOrienation(); - return (Orientation.NORTH == tileOrientation || Orientation.SOUTH == tileOrientation) && TileType.CURVED != tileType; - } - - public boolean isJunction() { - return TileType.SWITCH == tileType || TileType.CROSS == tileType; - } - - public boolean isBlock() { - return TileType.BLOCK == tileType; - } - - public boolean isDirectional() { - return TileType.STRAIGHT_DIR == tileType; - } - - /** - * The main route of the tile is diagonal - * - * @return true when main route goes from North to East or West to South and vv - */ - public boolean isDiagonal() { - return TileType.CURVED == tileType; - } - - public boolean isCrossing() { - return TileType.CROSSING == tileType; - } - - public List getNeighbours() { - return neighbours; - } - - public void setNeighbours(List neighbours) { - this.neighbours = neighbours; - } - - public String getIdSuffix(Tile other) { - return ""; - } - - public Map getNeighborOrientations() { - Map edgeOrientations = new HashMap<>(); - - Map neighborPoints = getNeighborPoints(); - - for (Orientation o : Orientation.values()) { - edgeOrientations.put(neighborPoints.get(o), o); - } - return edgeOrientations; - } - - public Map getEdgeOrientations() { - Map edgeOrientations = new HashMap<>(); - - Map edgeConnections = getEdgePoints(); - - for (Orientation o : Orientation.values()) { - edgeOrientations.put(edgeConnections.get(o), o); - } - return edgeOrientations; - } - - public boolean isAdjacent(Tile other) { - boolean adjacent = false; - - if (other != null) { - Collection thisEdgePoints = getEdgePoints().values(); - Collection otherEdgePoints = other.getEdgePoints().values(); - - for (Point p : thisEdgePoints) { - adjacent = otherEdgePoints.contains(p); - if (adjacent) { - break; - } - } - } - - return adjacent; - } - - /** - * When the tile has a specific direction a train may travel,
- * then this method will indicate whether the other tile is in on the side where the arrow is pointing to. - * - * @param other A Tile - * @return true where other is on the side of this tile where the arrow points to - */ - public boolean isArrowDirection(Tile other) { - return true; - } - - public AccessoryValue accessoryValueForRoute(Orientation from, Orientation to) { - return AccessoryValue.OFF; - } - - public TileModel getModel() { - return model; - } - - public void setModel(TileModel newModel) { - TileModel oldModel = getModel(); - - if (oldModel != null) { - oldModel.removeChangeListener(changeListener); - oldModel.removeActionListener(actionListener); - changeListener = null; - actionListener = null; - } - - model = newModel; - - if (newModel != null) { - changeListener = createChangeListener(); - actionListener = createActionListener(); - - newModel.addChangeListener(changeListener); - newModel.addActionListener(actionListener); - } - - firePropertyChange(MODEL_CHANGED_PROPERTY, oldModel, newModel); - if (newModel != oldModel) { - revalidate(); - repaint(); - } - } - -// public TileUI getUI() { -// return (TileUI) ui; -// } -// public void setUI(TileUI ui) { -// super.setUI(ui); -// } - @Override - public void updateUI() { - } - - protected ChangeListener createChangeListener() { - return getHandler(); - } - - protected ActionListener createActionListener() { - return getHandler(); - } - - private Handler getHandler() { - if (handler == null) { - handler = new Handler(); - } - return handler; - } - - class Handler implements ActionListener, ChangeListener, Serializable { - - @Override - public void stateChanged(ChangeEvent e) { - //Object source = e.getSource(); - - fireStateChanged(); - repaint(); - } - - @Override - public void actionPerformed(ActionEvent event) { - fireActionPerformed(event); - } - } - - protected void fireStateChanged() { - Object[] listeners = listenerList.getListenerList(); - //reverse order - for (int i = listeners.length - 2; i >= 0; i -= 2) { - if (listeners[i] == ChangeListener.class) { - // Lazily create the event: - if (changeEvent == null) { - changeEvent = new ChangeEvent(this); - } - ((ChangeListener) listeners[i + 1]).stateChanged(changeEvent); - } - } - } - - protected void fireActionPerformed(ActionEvent event) { - Object[] listeners = listenerList.getListenerList(); - ActionEvent e = null; - // reverse - for (int i = listeners.length - 2; i >= 0; i -= 2) { - if (listeners[i] == ActionListener.class) { - // Lazily create the event: - if (e == null) { - String actionCommand = event.getActionCommand(); - //if(actionCommand == null) { - // actionCommand = getActionCommand(); - //} - e = new ActionEvent(Tile.this, ActionEvent.ACTION_PERFORMED, actionCommand, event.getWhen(), event.getModifiers()); - } - ((ActionListener) listeners[i + 1]).actionPerformed(e); - } - } - } - - public Rectangle getTileBounds() { - if (model.isScaleImage()) { - return new Rectangle(tileX - GRID, tileY - GRID, DEFAULT_WIDTH, DEFAULT_HEIGHT); - } else { - return new Rectangle(tileX - renderWidth / 2, tileY - renderHeight / 2, renderWidth, renderHeight); - } - } - - @Override - protected void paintComponent(Graphics g) { - long started = System.currentTimeMillis(); - - Graphics2D g2 = (Graphics2D) g.create(); - //Graphics2D g2 = (Graphics2D) g.create(tileX - GRID, tileY - GRID, DEFAULT_WIDTH, DEFAULT_HEIGHT); - drawTile(g2); - g2.dispose(); - - g.drawImage(tileImage, 0, 0, null); - - long now = System.currentTimeMillis(); - Logger.trace(id + " Duration: " + (now - started) + " ms. Cp: " + xyToString() + " O: " + model.getTileOrienation()); - } - -} +/* * Copyright 2024 Frans Jacobs. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package jcs.ui.layout.tiles; import java.awt.Color; import java.awt.Dimension; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.Point; import java.awt.Rectangle; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.geom.AffineTransform; import java.awt.geom.Ellipse2D; import java.awt.image.AffineTransformOp; import java.awt.image.BufferedImage; import java.beans.PropertyChangeListener; import java.io.Serializable; import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import javax.swing.JComponent; import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; import jcs.entities.AccessoryBean; import jcs.entities.AccessoryBean.AccessoryValue; import jcs.entities.AccessoryBean.SignalType; import jcs.entities.BlockBean; import jcs.entities.BlockBean.BlockState; import jcs.entities.LocomotiveBean; import jcs.entities.SensorBean; import jcs.entities.TileBean; import jcs.entities.TileBean.Direction; import jcs.entities.TileBean.Orientation; import jcs.entities.TileBean.TileType; import jcs.ui.layout.LayoutUtil; import static jcs.ui.layout.tiles.Block.BLOCK_HEIGHT; import static jcs.ui.layout.tiles.Block.BLOCK_WIDTH; import org.imgscalr.Scalr; import org.imgscalr.Scalr.Method; import org.imgscalr.Scalr.Mode; import org.tinylog.Logger; /** * Basic graphic element to display a track, turnout, etc on the screen.
* By default the drawing of a Tile is Horizontal from L to R or West to East.
* The default orientation is East. * *

* The default size of a Tile is 40 tileX 40 pixels.
* The center point of a Tile is stored and always snapped to the nearest grid point.
* The basic grid is 20x 20 pixels.
* *

* A Tile can be rotated (always clockwise).
* Rotation will change the orientation from East -> South -> West -> North -> East.
* *

* A Tile is rendered to a Buffered Image to speed up the display */ public abstract class Tile extends JComponent { //implements TileEventListener { //, ItemSelectable { public static final int GRID = 20; public static final int DEFAULT_WIDTH = GRID * 2; public static final int DEFAULT_HEIGHT = GRID * 2; static final int RENDER_GRID = GRID * 10; static final int RENDER_WIDTH = RENDER_GRID * 2; static final int RENDER_HEIGHT = RENDER_GRID * 2; public static final Color DEFAULT_BACKGROUND_COLOR = Color.white; public static final Color DEFAULT_TRACK_COLOR = Color.lightGray; public static final Color DEFAULT_ROUTE_TRACK_COLOR = Color.blue; public static final Color DEFAULT_SELECTED_COLOR = Color.orange; public static final Color DEFAULT_WARN_COLOR = Color.red; public static final String MODEL_CHANGED_PROPERTY = "model"; public static final String CONTENT_AREA_FILLED_CHANGED_PROPERTY = "contentAreaFilled"; /** * The data model that determines the button's state. */ protected TileModel model = null; protected String id; protected Integer tileX; protected Integer tileY; protected int renderWidth; protected int renderHeight; //protected Orientation tileOrientation; protected Direction tileDirection; protected TileType tileType; protected String accessoryId; protected String sensorId; protected AccessoryValue accessoryValue; protected AccessoryValue routeValue; protected SignalType signalType; protected AccessoryBean.SignalValue signalValue; protected TileBean tileBean; protected AccessoryBean accessoryBean; protected SensorBean sensorBean; protected BlockBean blockBean; protected List neighbours; protected int offsetX = 0; protected int offsetY = 0; protected int renderOffsetX = 0; protected int renderOffsetY = 0; //protected Color selectedColor; protected Color trackColor; protected Color trackRouteColor; protected Orientation incomingSide; protected Color backgroundColor; protected boolean drawName = true; protected BufferedImage tileImage; protected PropertyChangeListener propertyChangeListener; protected ChangeListener changeListener = null; protected ActionListener actionListener = null; protected transient ChangeEvent changeEvent; private Handler handler; protected Tile(TileType tileType, Orientation orientation, Point center, int width, int height) { this(tileType, orientation, Direction.CENTER, center.x, center.y, width, height); } protected Tile(TileType tileType, Orientation orientation, int x, int y, int width, int height) { this(tileType, orientation, Direction.CENTER, x, y, width, height); } protected Tile(TileType tileType, Orientation orientation, Direction direction, int x, int y, int width, int height) { this(tileType, orientation, direction, x, y, width, height, null, null); } protected Tile(TileType tileType, Orientation orientation, Direction direction, int x, int y, int width, int height, Color backgroundColor, Color selectedColor) { this.tileType = tileType; //this.tileOrientation = orientation; //model.setTileOrienation(orientation); this.tileDirection = direction; this.tileX = x; this.tileY = y; setLayout(null); Dimension d = new Dimension(width, height); setSize(d); setPreferredSize(d); this.renderWidth = RENDER_WIDTH; this.renderHeight = RENDER_HEIGHT; this.trackColor = DEFAULT_TRACK_COLOR; this.backgroundColor = backgroundColor; //this.selectedColor = selectedColor; if (this.backgroundColor == null) { this.backgroundColor = DEFAULT_BACKGROUND_COLOR; } // if (this.selectedColor == null) { // this.selectedColor = DEFAULT_SELECTED_COLOR; // } } protected Tile(TileBean tileBean) { this(tileBean, tileWidth(tileBean.getOrientation(), tileBean.getTileType()), tileHeight(tileBean.getOrientation(), tileBean.getTileType())); } protected Tile(TileBean tileBean, int width, int height) { this.tileBean = tileBean; //Quick properties this.id = tileBean.getId(); this.tileType = tileBean.getTileType(); //this.tileOrientation = tileBean.getOrientation(); //this.model.setTileOrienation(tileBean.getOrientation()); this.tileDirection = tileBean.getDirection(); this.tileX = tileBean.getX(); this.tileY = tileBean.getY(); this.accessoryId = tileBean.getAccessoryId(); this.accessoryBean = tileBean.getAccessoryBean(); this.signalType = tileBean.getSignalType(); this.sensorId = tileBean.getSensorId(); this.sensorBean = tileBean.getSensorBean(); this.blockBean = tileBean.getBlockBean(); setLayout(null); Dimension d = new Dimension(width, height); setSize(d); setPreferredSize(d); this.trackColor = DEFAULT_TRACK_COLOR; this.backgroundColor = DEFAULT_BACKGROUND_COLOR; // this.selectedColor = DEFAULT_SELECTED_COLOR; this.renderWidth = RENDER_WIDTH; this.renderHeight = RENDER_HEIGHT; } protected static int tileWidth(Orientation orientation, TileType tileType) { if (Orientation.EAST == orientation || Orientation.WEST == orientation) { if (null == tileType) { return DEFAULT_WIDTH; } else { return switch (tileType) { case BLOCK -> BLOCK_WIDTH; case CROSS -> DEFAULT_WIDTH * 2; default -> DEFAULT_WIDTH; }; } } else { return DEFAULT_WIDTH; } } protected static int tileHeight(Orientation orientation, TileType tileType) { if (Orientation.EAST == orientation || Orientation.WEST == orientation) { return DEFAULT_HEIGHT; } else { if (null == tileType) { return DEFAULT_HEIGHT; } else { return switch (tileType) { case BLOCK -> BLOCK_HEIGHT; case CROSS -> DEFAULT_HEIGHT * 2; default -> DEFAULT_HEIGHT; }; } } } protected void populateModel() { if (this.blockBean != null) { this.model.setBlockState(this.blockBean.getBlockState()); this.model.setLocomotive(this.blockBean.getLocomotive()); this.model.setArrivalSuffix(this.blockBean.getArrivalSuffix()); this.model.setLogicalDirection(LocomotiveBean.Direction.get(this.blockBean.getLogicalDirection())); } } public TileBean getTileBean() { if (tileBean == null) { tileBean = new TileBean(); tileBean.setId(this.id); tileBean.setX(this.tileX); tileBean.setY(this.tileY); tileBean.setTileType(this.tileType); //tileBean.setTileOrientation(this.tileOrientation.getOrientation()); tileBean.setTileOrientation(this.model.getTileOrienation().getOrientation()); tileBean.setTileDirection(this.tileDirection.getDirection()); tileBean.setSignalType(this.signalType); tileBean.setAccessoryId(this.accessoryId); tileBean.setSensorId(this.sensorId); tileBean.setAccessoryBean(this.accessoryBean); tileBean.setSensorBean(this.sensorBean); tileBean.setBlockBean(this.blockBean); } return tileBean; } public boolean isSelected() { return model.isSelected(); } public void setSelected(boolean b) { //boolean oldValue = isSelected(); model.setSelected(b); } public String getId() { return id; } public void setId(String id) { this.id = id; } public SignalType getSignalType() { return signalType; } public void setSignalType(SignalType signalType) { this.signalType = signalType; } public Integer getTileX() { return tileX; } public Integer getTileY() { return tileY; } public Point getCenter() { return new Point(this.tileX, this.tileY); } public void setCenter(Point center) { tileX = center.x; tileY = center.y; if (tileBean != null) { tileBean.setCenter(center); } Logger.trace(id + " Cp: " + xyToString()); } public Orientation getOrientation() { //return tileOrientation; return model.getTileOrienation(); } public void setOrientation(Orientation orientation) { //this.tileOrientation = orientation; model.setTileOrienation(orientation); if (tileBean != null) { tileBean.setOrientation(orientation); } } public Direction getDirection() { return tileDirection; } public void setDirection(Direction direction) { this.tileDirection = direction; if (tileBean != null) { tileBean.setDirection(direction); } } public String getAccessoryId() { return accessoryId; } public void setAccessoryId(String accessoryId) { this.accessoryId = accessoryId; if (tileBean != null) { tileBean.setAccessoryId(accessoryId); } } public String getSensorId() { return sensorId; } public void setSensorId(String sensorId) { this.sensorId = sensorId; } public boolean isActive() { return model.isSensorActive(); } public void setActive(boolean active) { model.setSensorActive(active); } public BlockState getBlockState() { return model.getBlockState(); } public void setBlockState(BlockState blockState) { if (blockBean != null) { blockBean.setBlockState(blockState); LocomotiveBean locomotive = model.getLocomotive(); model.setOverlayImage(locomotive != null && locomotive.getLocIcon() != null && (blockState == BlockState.OCCUPIED || blockState == BlockState.INBOUND || blockState == BlockState.OUTBOUND)); } model.setBlockState(blockState); } public String getDepartureSuffix() { return model.getDepartureSuffix(); } public void setDepartureSuffix(String suffix) { if (blockBean != null) { blockBean.setDepartureSuffix(suffix); } model.setDepartureSuffix(suffix); } public boolean isReverseArrival() { return model.isReverseArrival(); } public void setReverseArrival(boolean reverseArrival) { if (blockBean != null) { blockBean.setReverseArrival(reverseArrival); } model.setReverseArrival(reverseArrival); } public LocomotiveBean.Direction getLogicalDirection() { return model.getLogicalDirection(); } public void setLogicalDirection(LocomotiveBean.Direction logicalDirection) { if (blockBean != null) { blockBean.setLogicalDirection(logicalDirection.getDirection()); } model.setLogicalDirection(logicalDirection); } public LocomotiveBean getLocomotive() { return model.getLocomotive(); } public void setLocomotive(LocomotiveBean locomotive) { if (blockBean != null) { blockBean.setLocomotive(locomotive); model.setOverlayImage(locomotive != null && locomotive.getLocIcon() != null && (model.getBlockState() == BlockState.OCCUPIED || model.getBlockState() == BlockState.INBOUND || model.getBlockState() == BlockState.OUTBOUND)); } model.setLocomotive(locomotive); } public AccessoryBean getAccessoryBean() { return accessoryBean; } public void setAccessoryBean(AccessoryBean accessoryBean) { this.accessoryBean = accessoryBean; if (accessoryBean != null) { accessoryId = accessoryBean.getId(); signalValue = accessoryBean.getSignalValue(); signalType = SignalType.getSignalType(accessoryBean.getType()); } else { accessoryId = null; signalType = SignalType.NONE; signalValue = AccessoryBean.SignalValue.OFF; } } public AccessoryValue getAccessoryValue() { if (this.accessoryValue == null) { return AccessoryValue.OFF; } else { return accessoryValue; } } public void setAccessoryValue(AccessoryValue value) { this.accessoryValue = value; repaint(); } public AccessoryValue getRouteValue() { if (routeValue == null) { return AccessoryValue.OFF; } else { return routeValue; } } public void setRouteValue(AccessoryValue value) { this.routeValue = value; repaint(); } public AccessoryBean.SignalValue getSignalValue() { return signalValue; } public void setSignalValue(AccessoryBean.SignalValue signalValue) { this.signalValue = signalValue; repaint(); } public SensorBean getSensorBean() { return sensorBean; } public void setSensorBean(SensorBean sensorBean) { this.sensorBean = sensorBean; } public BlockBean getBlockBean() { return blockBean; } public void setBlockBean(BlockBean blockBean) { this.blockBean = blockBean; } public void setRenderWidth(int renderWidth) { this.renderWidth = renderWidth; } public void setRenderHeight(int renderHeight) { this.renderHeight = renderHeight; } public int getRenderOffsetX() { return renderOffsetX; } public void setRenderOffsetX(int renderOffsetX) { this.renderOffsetX = renderOffsetX; } public int getRenderOffsetY() { return renderOffsetY; } public void setRenderOffsetY(int renderOffsetY) { this.renderOffsetY = renderOffsetY; } public TileBean.TileType getTileType() { return this.tileType; } public final void setTileType(TileType tileType) { this.tileType = tileType; } public Color getTrackColor() { return trackColor; } public final void setTrackColor(Color trackColor) { this.trackColor = trackColor; } public Color getTrackRouteColor() { return trackRouteColor; } public void setTrackRouteColor(Color trackRouteColor) { this.trackRouteColor = trackRouteColor; } public Color getSelectedColor() { return model.getSelectedColor(); } public void setSelectedColor(Color selectedColor) { this.model.setSelectedColor(selectedColor); } public Orientation getIncomingSide() { return incomingSide; } public void setIncomingSide(Orientation incomingSide) { this.incomingSide = incomingSide; } public Color getBackgroundColor() { return backgroundColor; } public void setBackgroundColor(Color backgroundColor) { this.backgroundColor = backgroundColor; } public boolean isDrawRoute() { return model.isShowRoute(); } public void setDrawRoute(boolean drawRoute) { this.model.setShowRoute(drawRoute); } public int getRenderWidth() { return renderWidth; } public int getRenderHeight() { return renderHeight; } abstract void renderTile(Graphics2D g2d); abstract void renderTileRoute(Graphics2D g2d); public abstract Map getNeighborPoints(); public abstract Map getEdgePoints(); //public abstract Set getAllPoints(); //public abstract Set getAllPoints(Point center); //public abstract Set getAltPoints(Point center); Set getAltPoints(Point center) { return Collections.EMPTY_SET; } public Set getAllPoints() { return getAllPoints(getCenter()); } Set getAllPoints(Point center) { Set aps = new HashSet<>(); aps.add(center); return aps; } /** * Draw the Tile * * @param g2d The graphics handle */ public void drawTile(Graphics2D g2d) { // by default and image is rendered in the EAST orientation Orientation tileOrientation = model.getTileOrienation(); // if (tileOrientation == null) { // tileOrientation = Orientation.EAST; // } BufferedImage bf = createImage(); Graphics2D g2di = bf.createGraphics(); //Avoid errors if (model.isShowRoute() && incomingSide == null) { incomingSide = getOrientation(); } if (model.isSelected()) { g2di.setBackground(model.getSelectedColor()); } else { g2di.setBackground(backgroundColor); } g2di.clearRect(0, 0, renderWidth, renderHeight); int ox = 0, oy = 0; AffineTransform trans = new AffineTransform(); switch (tileOrientation) { case SOUTH -> { trans.rotate(Math.PI / 2, renderWidth / 2, renderHeight / 2); ox = (renderHeight - renderWidth) / 2; oy = (renderWidth - renderHeight) / 2; trans.translate(-ox, -oy); } case WEST -> { trans.rotate(Math.PI, renderWidth / 2, renderHeight / 2); trans.translate(ox, oy); } case NORTH -> { trans.rotate(-Math.PI / 2, renderWidth / 2, renderHeight / 2); ox = (renderHeight - renderWidth) / 2; oy = (renderWidth - renderHeight) / 2; trans.translate(-ox, -oy); } default -> { trans.rotate(0.0, this.renderWidth / 2, this.renderHeight / 2); trans.translate(ox, oy); } } //Logger.trace(tileOrientation.getOrientation() + " renderWidth: " + renderWidth + " renderHeight: " + renderHeight + " CP: (" + renderWidth / 2 + "," + renderHeight / 2 + ")"); //Logger.trace(tileOrientation.getOrientation() + " ox: " + ox + " oy: " + oy); g2di.setTransform(trans); renderTile(g2di); if (model.isShowRoute()) { renderTileRoute(g2di); } if (model.isShowCenter()) { drawCenterPoint(g2di); } // Scale the image back... if (model.isScaleImage()) { tileImage = Scalr.resize(bf, Method.AUTOMATIC, Mode.FIT_EXACT, getWidth(), getHeight(), Scalr.OP_ANTIALIAS); } else { tileImage = bf; } g2di.dispose(); Logger.trace(id + " Cp: " + xyToString()); } public BufferedImage getTileImage() { return tileImage; } /** * Render a tile image Always starts at (0,0) used the default width and height * * @param g2 the Graphic context */ public void drawName(Graphics2D g2) { } protected void drawCenterPoint(Graphics2D g2d) { drawCenterPoint(g2d, Color.magenta); } protected void drawCenterPoint(Graphics2D g2, Color color) { drawCenterPoint(g2, color, 60); } protected void drawCenterPoint(Graphics2D g2d, Color color, double size) { double dX = (renderWidth / 2 - size / 2); double dY = (renderHeight / 2 - size / 2); g2d.setColor(color); g2d.fill(new Ellipse2D.Double(dX, dY, size, size)); } /** * Rotate the tile clockwise 90 deg * * @return the new Orientation */ public Orientation rotate() { Orientation tileOrientation = model.getTileOrienation(); switch (tileOrientation) { case EAST -> setOrientation(Orientation.SOUTH); case SOUTH -> setOrientation(Orientation.WEST); case WEST -> setOrientation(Orientation.NORTH); default -> setOrientation(Orientation.EAST); } return model.getTileOrienation(); } public void flipHorizontal() { Orientation tileOrientation = model.getTileOrienation(); if (Orientation.NORTH == tileOrientation || Orientation.SOUTH == tileOrientation) { rotate(); rotate(); } } public void flipVertical() { Orientation tileOrientation = model.getTileOrienation(); if (Orientation.EAST == tileOrientation || Orientation.WEST == tileOrientation) { rotate(); rotate(); } } @Override public void move(int newX, int newY) { Point cs = LayoutUtil.snapToGrid(newX, newY); setCenter(cs); } protected static void drawRotate(Graphics2D g2d, double x, double y, int angle, String text) { g2d.translate((float) x, (float) y); g2d.rotate(Math.toRadians(angle)); g2d.drawString(text, 0, 0); g2d.rotate(-Math.toRadians(angle)); g2d.translate(-x, -y); } public static BufferedImage flipHorizontally(BufferedImage source) { BufferedImage output = new BufferedImage(source.getHeight(), source.getWidth(), source.getType()); AffineTransform flip = AffineTransform.getScaleInstance(1, -1); flip.translate(0, -source.getHeight()); AffineTransformOp op = new AffineTransformOp(flip, AffineTransformOp.TYPE_NEAREST_NEIGHBOR); op.filter(source, output); return output; } public static BufferedImage flipVertically(BufferedImage source) { BufferedImage output = new BufferedImage(source.getHeight(), source.getWidth(), source.getType()); AffineTransform flip = AffineTransform.getScaleInstance(-1, 1); flip.translate(-source.getWidth(), 0); AffineTransformOp op = new AffineTransformOp(flip, AffineTransformOp.TYPE_NEAREST_NEIGHBOR); op.filter(source, output); return output; } public Set getAltPoints() { return Collections.EMPTY_SET; } public final int getOffsetX() { return offsetX; } public void setOffsetX(int offsetX) { this.offsetX = offsetX; } public final int getOffsetY() { return offsetY; } public void setOffsetY(int offsetY) { this.offsetY = offsetY; } protected BufferedImage createImage() { return new BufferedImage(renderWidth, renderHeight, BufferedImage.TYPE_INT_RGB); } public int getCenterX() { if (tileX > 0) { return this.tileX; } else { return GRID; } } public int getCenterY() { if (tileY > 0) { return this.tileY; } else { return GRID; } } public boolean isDrawName() { return drawName; } public void setDrawName(boolean drawName) { this.drawName = drawName; } public boolean isScaleImage() { return model.isScaleImage(); } public void setScaleImage(boolean scaleImage) { Dimension d; if (scaleImage) { d = new Dimension(DEFAULT_WIDTH, DEFAULT_HEIGHT); } else { d = new Dimension(renderWidth, renderHeight); } setSize(d); setPreferredSize(d); model.setScaleImage(scaleImage); } public boolean isDrawCenterPoint() { return model.isShowCenter(); } public void setDrawCenterPoint(boolean drawCenterPoint) { model.setShowCenter(drawCenterPoint); } @Override public String toString() { return this.getClass().getSimpleName() + " {id: " + this.id + ", orientation: " + getOrientation() + ", direction: " + getDirection() + ", center: " + xyToString() + "}"; } public String xyToString() { return "(" + this.tileX + "," + this.tileY + ")"; } /** * The main route of the tile is horizontal * * @return true when main route goes from East to West or vv */ public boolean isHorizontal() { Orientation tileOrientation = model.getTileOrienation(); return (Orientation.EAST == tileOrientation || Orientation.WEST == tileOrientation) && TileType.CURVED != tileType; } /** * The main route of the tile is vertical * * @return true when main route goes from North to South or vv */ public boolean isVertical() { Orientation tileOrientation = model.getTileOrienation(); return (Orientation.NORTH == tileOrientation || Orientation.SOUTH == tileOrientation) && TileType.CURVED != tileType; } public boolean isJunction() { return TileType.SWITCH == tileType || TileType.CROSS == tileType; } public boolean isBlock() { return TileType.BLOCK == tileType; } public boolean isDirectional() { return TileType.STRAIGHT_DIR == tileType; } /** * The main route of the tile is diagonal * * @return true when main route goes from North to East or West to South and vv */ public boolean isDiagonal() { return TileType.CURVED == tileType; } public boolean isCrossing() { return TileType.CROSSING == tileType; } public List getNeighbours() { return neighbours; } public void setNeighbours(List neighbours) { this.neighbours = neighbours; } public String getIdSuffix(Tile other) { return ""; } public Map getNeighborOrientations() { Map edgeOrientations = new HashMap<>(); Map neighborPoints = getNeighborPoints(); for (Orientation o : Orientation.values()) { edgeOrientations.put(neighborPoints.get(o), o); } return edgeOrientations; } public Map getEdgeOrientations() { Map edgeOrientations = new HashMap<>(); Map edgeConnections = getEdgePoints(); for (Orientation o : Orientation.values()) { edgeOrientations.put(edgeConnections.get(o), o); } return edgeOrientations; } public boolean isAdjacent(Tile other) { boolean adjacent = false; if (other != null) { Collection thisEdgePoints = getEdgePoints().values(); Collection otherEdgePoints = other.getEdgePoints().values(); for (Point p : thisEdgePoints) { adjacent = otherEdgePoints.contains(p); if (adjacent) { break; } } } return adjacent; } /** * When the tile has a specific direction a train may travel,
* then this method will indicate whether the other tile is in on the side where the arrow is pointing to. * * @param other A Tile * @return true where other is on the side of this tile where the arrow points to */ public boolean isArrowDirection(Tile other) { return true; } public AccessoryValue accessoryValueForRoute(Orientation from, Orientation to) { return AccessoryValue.OFF; } public TileModel getModel() { return model; } public void setModel(TileModel newModel) { TileModel oldModel = getModel(); if (oldModel != null) { oldModel.removeChangeListener(changeListener); oldModel.removeActionListener(actionListener); changeListener = null; actionListener = null; } model = newModel; if (newModel != null) { changeListener = createChangeListener(); actionListener = createActionListener(); newModel.addChangeListener(changeListener); newModel.addActionListener(actionListener); } firePropertyChange(MODEL_CHANGED_PROPERTY, oldModel, newModel); if (newModel != oldModel) { revalidate(); repaint(); } } // public TileUI getUI() { // return (TileUI) ui; // } // public void setUI(TileUI ui) { // super.setUI(ui); // } @Override public void updateUI() { } protected ChangeListener createChangeListener() { return getHandler(); } protected ActionListener createActionListener() { return getHandler(); } private Handler getHandler() { if (handler == null) { handler = new Handler(); } return handler; } class Handler implements ActionListener, ChangeListener, Serializable { @Override public void stateChanged(ChangeEvent e) { //Object source = e.getSource(); fireStateChanged(); repaint(); } @Override public void actionPerformed(ActionEvent event) { fireActionPerformed(event); } } protected void fireStateChanged() { Object[] listeners = listenerList.getListenerList(); //reverse order for (int i = listeners.length - 2; i >= 0; i -= 2) { if (listeners[i] == ChangeListener.class) { // Lazily create the event: if (changeEvent == null) { changeEvent = new ChangeEvent(this); } ((ChangeListener) listeners[i + 1]).stateChanged(changeEvent); } } } protected void fireActionPerformed(ActionEvent event) { Object[] listeners = listenerList.getListenerList(); ActionEvent e = null; // reverse for (int i = listeners.length - 2; i >= 0; i -= 2) { if (listeners[i] == ActionListener.class) { // Lazily create the event: if (e == null) { String actionCommand = event.getActionCommand(); //if(actionCommand == null) { // actionCommand = getActionCommand(); //} e = new ActionEvent(Tile.this, ActionEvent.ACTION_PERFORMED, actionCommand, event.getWhen(), event.getModifiers()); } ((ActionListener) listeners[i + 1]).actionPerformed(e); } } } public Rectangle getTileBounds() { if (model.isScaleImage()) { return new Rectangle(tileX - GRID, tileY - GRID, DEFAULT_WIDTH, DEFAULT_HEIGHT); } else { return new Rectangle(tileX - renderWidth / 2, tileY - renderHeight / 2, renderWidth, renderHeight); } } @Override protected void paintComponent(Graphics g) { long started = System.currentTimeMillis(); Graphics2D g2 = (Graphics2D) g.create(); //Graphics2D g2 = (Graphics2D) g.create(tileX - GRID, tileY - GRID, DEFAULT_WIDTH, DEFAULT_HEIGHT); drawTile(g2); g2.dispose(); g.drawImage(tileImage, 0, 0, null); long now = System.currentTimeMillis(); Logger.trace(id + " Duration: " + (now - started) + " ms. Cp: " + xyToString() + " O: " + model.getTileOrienation()); } } \ No newline at end of file diff --git a/src/main/java/jcs/ui/layout/tiles/TileCache.java b/src/main/java/jcs/ui/layout/tiles/TileCache.java new file mode 100644 index 00000000..2716f298 --- /dev/null +++ b/src/main/java/jcs/ui/layout/tiles/TileCache.java @@ -0,0 +1 @@ +/* * Copyright 2025 Frans Jacobs. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package jcs.ui.layout.tiles; import java.awt.Point; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Set; import java.util.stream.Collectors; import jcs.entities.AccessoryBean.AccessoryValue; import jcs.entities.AccessoryBean.SignalValue; import jcs.entities.TileBean; import jcs.entities.TileBean.Orientation; import static jcs.entities.TileBean.Orientation.EAST; import static jcs.entities.TileBean.Orientation.SOUTH; import static jcs.entities.TileBean.Orientation.WEST; import jcs.entities.TileBean.TileType; import static jcs.entities.TileBean.TileType.BLOCK; import static jcs.entities.TileBean.TileType.CROSS; import static jcs.entities.TileBean.TileType.SENSOR; import static jcs.entities.TileBean.TileType.SIGNAL; import jcs.persistence.PersistenceFactory; import jcs.ui.layout.events.TileEvent; import jcs.ui.layout.events.TileEventListener; import org.tinylog.Logger; /** * Factory object to create Tiles and cache tiles * * @author frans */ public class TileCache { //private static final Map tileEventListeners = new HashMap<>(); private static boolean showValues; static final Map tiles = new HashMap<>(); static final Map tileAltPoints = new HashMap<>(); static final Map points = new HashMap<>(); //static final Map altTiles = new HashMap<>(); private TileCache() { } @Deprecated public static void setShowValues(boolean showValues) { TileCache.showValues = showValues; for (Tile tile : tiles.values()) { TileType tileType = tile.getTileType(); switch (tileType) { case SWITCH -> { if (showValues && ((Switch) tile).getTileBean().getAccessoryBean() != null) { tile.setAccessoryValue(tile.getTileBean().getAccessoryBean().getAccessoryValue()); } else { tile.setAccessoryValue(AccessoryValue.OFF); } } case CROSS -> { if (showValues && ((Cross) tile).getTileBean().getAccessoryBean() != null) { tile.setAccessoryValue(tile.getTileBean().getAccessoryBean().getAccessoryValue()); } else { tile.setAccessoryValue(AccessoryValue.OFF); } } case SIGNAL -> { if (showValues && ((Signal) tile).getTileBean().getAccessoryBean() != null) { tile.setSignalValue(tile.getTileBean().getAccessoryBean().getSignalValue()); } else { tile.setSignalValue(SignalValue.OFF); } } case SENSOR -> { if (showValues && ((Sensor) tile).getTileBean().getSensorBean() != null) { tile.setActive(tile.getTileBean().getSensorBean().isActive()); } else { tile.setActive(false); } } case BLOCK -> { } } } } public static List loadTiles() { tileAltPoints.clear(); points.clear(); tiles.clear(); List tileBeans = PersistenceFactory.getService().getTileBeans(); for (TileBean tb : tileBeans) { Tile tile = TileFactory.createTile(tb, showValues); tiles.put(tile.getCenter(), tile); points.put(tile.getId(), tile.getCenter()); //Alternative point(s) to be able to find all points if (!tile.getAltPoints().isEmpty()) { Set alt = tile.getAltPoints(); for (Point ap : alt) { tileAltPoints.put(ap, tile); } } } Logger.trace("Loaded " + tiles.size() + " Tiles..."); return tiles.values().stream().collect(Collectors.toList()); } public static List getTiles() { return tiles.values().stream().collect(Collectors.toList()); } public static void addAndSaveTile(Tile tile) { tiles.put(tile.getCenter(), tile); points.put(tile.getId(), tile.getCenter()); //Alternative point(s) to be able to find all points if (!tile.getAltPoints().isEmpty()) { Set alt = tile.getAltPoints(); for (Point ap : alt) { tileAltPoints.put(ap, tile); } } saveTile(tile); Logger.trace("Added " + tile + " There are now " + tiles.size() + " tiles..."); } public static void saveTile(final Tile tile) { if (tile != null) { TileBean tb = tile.getTileBean(); PersistenceFactory.getService().persist(tb); } else { Logger.warn("Tile is null?"); } } public static void saveTiles() { for (Tile tile : tiles.values()) { saveTile(tile); } } public static void deleteTile(final Tile tile) { if (tile != null) { if (tiles.containsKey(tile.getCenter())) { Set rps = tile.getAltPoints(); //Also remove alt points for (Point ap : rps) { tileAltPoints.remove(ap); } points.remove(tile.getId()); tiles.remove(tile.getCenter()); TileBean tb = tile.getTileBean(); PersistenceFactory.getService().remove(tb); Logger.trace("Deleted " + tile.getId()); } else { Logger.warn("Tile " + tile.getId() + " not found in cache"); } } else { Logger.warn("Tile is null?"); } } public static Tile findTile(Point cp) { Tile result = tiles.get(cp); if (result == null) { result = tileAltPoints.get(cp); } return result; } public static Tile findTile(String id) { Point p = points.get(id); if (p != null) { return findTile(p); } else { return null; } } public static boolean canMoveTo(Tile tile, Point p) { //check if a tile exist with point p Logger.trace("Checking " + tile.id + " New Point (" + p.x + "," + p.y + ")"); if (tiles.containsKey(p) && !tile.getCenter().equals(p) && !tile.getAltPoints().contains(p)) { return false; } if (tileAltPoints.containsKey(p) && !tile.getAltPoints().contains(p)) { return false; } //Check with the tile new alt points if these are also free... Set altPoints = tile.getAltPoints(p); Logger.trace("Checking " + tile.id + " on " + altPoints.size() + " alt points..."); for (Point ap : altPoints) { Logger.trace("Checking " + tile.id + " New Alt Point (" + ap.x + "," + ap.y + ")"); if (tiles.containsKey(ap) && !tile.getCenter().equals(ap) && !tile.getAltPoints().contains(ap)) { return false; } if (tileAltPoints.containsKey(ap) && !tile.getAltPoints().contains(ap)) { return false; } } Logger.trace("Checking " + tile.id + " can move to (" + p.x + "," + p.y + ")"); return true; } public static void moveTo(Tile tile, Point p) { if (canMoveTo(tile, p)) { Logger.trace("Moving tile " + tile.getId() + " from " + tile.xyToString() + " to (" + p.x + "," + p.y + ")"); Set rps = tile.getAltPoints(); //remove alt points for (Point ap : rps) { tileAltPoints.remove(ap); } points.remove(tile.getId()); tiles.remove(tile.getCenter()); tile.setCenter(p); addAndSaveTile(tile); } else { Tile occ = findTile(p); Logger.trace("Can't Move tile " + tile.id + " from " + tile.xyToString() + " to (" + p.x + "," + p.y + ") Is occupied by " + occ.id); } } @Deprecated public static boolean checkTileOccupation(Tile tile) { Set tilePoints = tile.getAllPoints(); for (Point p : tilePoints) { if (tiles.containsKey(p) || tileAltPoints.containsKey(p)) { //The is a match, check if it is an other tile Tile mt = findTile(p); if (tile.getId().equals(mt.getId())) { //same tile continue } else { //Other tile so really occupied return true; } } } return false; } @Deprecated public static boolean containsPoint(Set points) { for (Point p : points) { return tiles.containsKey(p) || tileAltPoints.containsKey(p); } return false; } public static boolean containsPoint(Point point) { return tiles.containsKey(point) || tileAltPoints.containsKey(point); } @Deprecated public static Point checkAvailable(Point newPoint, Orientation orientation) { if (tiles.containsKey(newPoint)) { Tile et = tiles.get(newPoint); Logger.trace("@ " + newPoint + " is allready occcupied by: " + et + "..."); //Search for the nearest avalaible free point //first get the Center point of the tile which is occuping this slot // show warning! Point ecp = et.getCenter(); int w = et.getWidth(); int h = et.getHeight(); Point np; np = switch (orientation) { case EAST -> new Point(ecp.x + w, ecp.y); case WEST -> new Point(newPoint.x - w, ecp.y); case SOUTH -> new Point(ecp.x, newPoint.y + h); default -> new Point(ecp.x, newPoint.y - h); }; Logger.trace("Alternative CP: " + np); // recursive check return checkAvailable(np, orientation); } else { Logger.trace("@ " + newPoint + " is not yet used..."); return newPoint; } } public static Tile rotateTile(Tile tile) { if (!tiles.containsKey(tile.getCenter())) { Logger.warn("Tile " + tile.getId() + " NOT in cache!"); } //Remove the alternative or extra points... for (Point ep : tile.getAltPoints()) { tileAltPoints.remove(ep); } tile.rotate(); //update tiles.put(tile.getCenter(), tile); for (Point ep : tile.getAltPoints()) { tileAltPoints.put(ep, tile); } saveTile(tile); return tile; } public static Tile flipHorizontal(Tile tile) { return flipTile(tile, true); } public static Tile flipVertical(Tile tile) { return flipTile(tile, false); } private static Tile flipTile(Tile tile, boolean horizontal) { if (!tiles.containsKey(tile.getCenter())) { Logger.warn("Tile " + tile.getId() + " NOT in cache!"); } //Remove the alternative or extra points... for (Point ep : tile.getAltPoints()) { tileAltPoints.remove(ep); } if (horizontal) { tile.flipHorizontal(); } else { tile.flipVertical(); } //update tiles.put(tile.getCenter(), tile); for (Point ep : tile.getAltPoints()) { tileAltPoints.put(ep, tile); } saveTile(tile); return tile; } @Deprecated public static void addTileEventListener(TileEventListener listener) { String key = listener.getId(); //tileEventListeners.put(key, listener); } @Deprecated public static void removeTileEventListener(Tile tile) { if (tile instanceof TileEventListener tileEventListener) { removeTileEventListener(tileEventListener); } } static void removeTileEventListener(TileEventListener listener) { String key = listener.getId(); //tileEventListeners.remove(key, listener); } @Deprecated public static void fireTileEventListener(TileEvent tileEvent) { // String key = tileEvent.getTileId(); // TileEventListener listener = tileEventListeners.get(key); // if (listener != null) { // listener.onTileChange(tileEvent); // Logger.trace("Fire listener on tile " + key); // } else { // //Logger.trace("Tile " + key + " not available"); // } } @Deprecated public static void fireAllTileEventListeners(TileEvent tileEvent) { // for (TileEventListener listener : tileEventListeners.values()) { // listener.onTileChange(tileEvent); // } } } \ No newline at end of file diff --git a/src/main/java/jcs/ui/layout/tiles/TileFactory.java b/src/main/java/jcs/ui/layout/tiles/TileFactory.java index 40d6db61..5b0439c2 100755 --- a/src/main/java/jcs/ui/layout/tiles/TileFactory.java +++ b/src/main/java/jcs/ui/layout/tiles/TileFactory.java @@ -1,292 +1 @@ -/* - * Copyright 2023 Frans Jacobs. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package jcs.ui.layout.tiles; - -import java.awt.Point; -import java.util.LinkedList; -import java.util.List; -import jcs.JCS; -import jcs.commandStation.events.AccessoryEventListener; -import jcs.commandStation.events.SensorEventListener; -import jcs.entities.AccessoryBean; -import jcs.entities.SensorBean; -import jcs.entities.TileBean; -import jcs.entities.TileBean.Direction; -import jcs.entities.TileBean.Orientation; -import static jcs.entities.TileBean.TileType.BLOCK; -import static jcs.entities.TileBean.TileType.CROSS; -import static jcs.entities.TileBean.TileType.CROSSING; -import static jcs.entities.TileBean.TileType.CURVED; -import static jcs.entities.TileBean.TileType.END; -import static jcs.entities.TileBean.TileType.SENSOR; -import static jcs.entities.TileBean.TileType.SIGNAL; -import static jcs.entities.TileBean.TileType.STRAIGHT; -import static jcs.entities.TileBean.TileType.STRAIGHT_DIR; -import static jcs.entities.TileBean.TileType.SWITCH; -import org.tinylog.Logger; - -/** - * Factory object to create Tiles and cache tiles - * - * @author frans - */ -public class TileFactory { - - // Keep the records of the used id sequence number - private static int straightIdSeq; - private static int crossingIdSeq; - private static int curvedIdSeq; - private static int switchIdSeq; - private static int crossIdSeq; - private static int signalIdSeq; - private static int sensorIdSeq; - private static int blockIdSeq; - private static int straightDirectionIdSeq; - private static int endIdSeq; - - //private static final Map tileEventListeners = new HashMap<>(); -// private static boolean drawOutline; -// private static boolean showValues; -// public static final Map tiles = new HashMap<>(); -// public static final Map altTiles = new HashMap<>(); - private TileFactory() { - } - - private static int nextIdSeq(String id) { - String idnr = id.substring(3); - int idSeq = Integer.parseInt(idnr); - return idSeq; - } - - private static String nextTileId(TileBean.TileType tileType) { - switch (tileType) { - case STRAIGHT -> { - straightIdSeq++; - return "st-" + straightIdSeq; - } - case CROSSING -> { - crossingIdSeq++; - return "cr-" + crossingIdSeq; - } - case CURVED -> { - curvedIdSeq++; - return "ct-" + curvedIdSeq; - } - case SWITCH -> { - switchIdSeq++; - return "sw-" + switchIdSeq; - } - case CROSS -> { - crossIdSeq++; - return "cs-" + crossIdSeq; - } - case SIGNAL -> { - signalIdSeq++; - return "si-" + signalIdSeq; - } - case SENSOR -> { - sensorIdSeq++; - return "se-" + sensorIdSeq; - } - case BLOCK -> { - blockIdSeq++; - return "bk-" + blockIdSeq; - } - case STRAIGHT_DIR -> { - straightDirectionIdSeq++; - return "sd-" + straightDirectionIdSeq; - } - case END -> { - endIdSeq++; - return "et-" + endIdSeq; - } - default -> { - Logger.warn("Unknown Tile Type " + tileType); - return null; - } - } - } - - private static int maxIdSeq(int currentId, int newId) { - if (currentId < newId) { - return newId; - } else { - return currentId; - } - } - - public static Tile createTile(String tileId) { - TileBean tileBean = JCS.getPersistenceService().getTileBean(tileId); - return createTile(tileBean); - } - - public static Tile createTile(TileBean tileBean) { - return createTile(tileBean, false); - } - - public static Tile createTile(TileBean tileBean, boolean showValues) { - if (tileBean == null) { - return null; - } - - TileBean.TileType tileType = tileBean.getTileType(); - Tile tile = null; - switch (tileType) { - case STRAIGHT -> { - tile = new Straight(tileBean); - straightIdSeq = maxIdSeq(straightIdSeq, nextIdSeq(tileBean.getId())); - } - case CROSSING -> { - tile = new Crossing(tileBean); - crossingIdSeq = maxIdSeq(crossingIdSeq, nextIdSeq(tileBean.getId())); - } - case CURVED -> { - tile = new Curved(tileBean); - curvedIdSeq = maxIdSeq(curvedIdSeq, nextIdSeq(tileBean.getId())); - } - case SWITCH -> { - tile = new Switch(tileBean); - tile.setAccessoryBean(tileBean.getAccessoryBean()); - - switchIdSeq = maxIdSeq(switchIdSeq, nextIdSeq(tileBean.getId())); - if (showValues && tileBean.getAccessoryBean() != null) { - tile.setAccessoryValue((tileBean.getAccessoryBean()).getAccessoryValue()); - } - JCS.getJcsCommandStation().addAccessoryEventListener((AccessoryEventListener) tile); - } - case CROSS -> { - tile = new Cross(tileBean); - tile.setAccessoryBean(tileBean.getAccessoryBean()); - - crossIdSeq = maxIdSeq(crossIdSeq, nextIdSeq(tileBean.getId())); - if (showValues && tileBean.getAccessoryBean() != null) { - tile.setAccessoryValue((tileBean.getAccessoryBean()).getAccessoryValue()); - } - JCS.getJcsCommandStation().addAccessoryEventListener((AccessoryEventListener) tile); - } - case SIGNAL -> { - tile = new Signal(tileBean); - tile.setAccessoryBean(tileBean.getAccessoryBean()); - - signalIdSeq = maxIdSeq(signalIdSeq, nextIdSeq(tileBean.getId())); - if (showValues && tileBean.getAccessoryBean() != null) { - ((Signal) tile).setSignalValue(((AccessoryBean) tileBean.getAccessoryBean()).getSignalValue()); - } - JCS.getJcsCommandStation().addAccessoryEventListener((AccessoryEventListener) tile); - } - case SENSOR -> { - tile = new Sensor(tileBean); - tile.setSensorBean(tileBean.getSensorBean()); - sensorIdSeq = maxIdSeq(sensorIdSeq, nextIdSeq(tileBean.getId())); - if (showValues && tileBean.getSensorBean() != null) { - ((Sensor) tile).setActive(((SensorBean) tileBean.getSensorBean()).isActive()); - } - JCS.getJcsCommandStation().addSensorEventListener((SensorEventListener) tile); - } - case BLOCK -> { - tile = new Block(tileBean); - tile.setBlockBean(tileBean.getBlockBean()); - blockIdSeq = maxIdSeq(blockIdSeq, nextIdSeq(tileBean.getId())); - } - case STRAIGHT_DIR -> { - tile = new StraightDirection(tileBean); - straightDirectionIdSeq = maxIdSeq(straightDirectionIdSeq, nextIdSeq(tileBean.getId())); - } - case END -> { - tile = new End(tileBean); - endIdSeq = maxIdSeq(endIdSeq, nextIdSeq(tileBean.getId())); - } - default -> - Logger.warn("Unknown Tile Type " + tileType); - } - -// if (tile != null) { -// tile.setDrawOutline(drawOutline); -// } -// addTileEventListener((TileEventListener) tile); - return (Tile) tile; - } - - /** - * @param tileType type of type to create - * @param orientation whether the orientation of the Tile is EAST, WEST, NORTH or SOUTH - * @param x the tile center X - * @param y the tile center Y - * @return a Tile object - */ - public static Tile createTile(TileBean.TileType tileType, Orientation orientation, int x, int y) { - return createTile(tileType, orientation, Direction.CENTER, x, y); - } - - /** - * @param tileType type of type to create - * @param orientation whether the orientation of the Tile is EAST, WEST, NORTH or SOUTH - * @param direction direction plays a role with Turnout tiles whether it goes to the Left or Right - * @param x the tile center X - * @param y the tile center Y - * @return a Tile object - */ - public static Tile createTile(TileBean.TileType tileType, Orientation orientation, Direction direction, int x, int y) { - return createTile(tileType, orientation, direction, new Point(x, y)); - } - - public static Tile createTile(TileBean.TileType tileType, Orientation orientation, Direction direction, Point center) { - Tile tile = null; - switch (tileType) { - case STRAIGHT -> { - tile = new Straight(orientation, center); - } - case CROSSING -> { - tile = new Crossing(orientation, center); - } - case CURVED -> - tile = new Curved(orientation, center); - case SWITCH -> - tile = new Switch(orientation, direction, center); - case CROSS -> - tile = new Cross(orientation, direction, center); - case SIGNAL -> - tile = new Signal(orientation, center); - case SENSOR -> - tile = new Sensor(orientation, center); - case BLOCK -> - tile = new Block(orientation, center); - case STRAIGHT_DIR -> - tile = new StraightDirection(orientation, center); - case END -> - tile = new End(orientation, center); - default -> - Logger.warn("Unknown Tile Type " + tileType); - } - - if (tile != null) { - tile.setId(nextTileId(tileType)); - } - - return (Tile) tile; - } - - public static List toTiles(List tileBeans, boolean drawOutline, boolean showValues) { - List tileList = new LinkedList<>(); - - for (TileBean tileBean : tileBeans) { - Tile tile = createTile(tileBean, showValues); - tileList.add(tile); - } - return tileList; - } - -} +/* * Copyright 2023 Frans Jacobs. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package jcs.ui.layout.tiles; import java.awt.Point; import java.util.LinkedList; import java.util.List; import jcs.JCS; import jcs.commandStation.events.AccessoryEventListener; import jcs.commandStation.events.SensorEventListener; import jcs.entities.AccessoryBean; import jcs.entities.SensorBean; import jcs.entities.TileBean; import jcs.entities.TileBean.Direction; import jcs.entities.TileBean.Orientation; import static jcs.entities.TileBean.TileType.BLOCK; import static jcs.entities.TileBean.TileType.CROSS; import static jcs.entities.TileBean.TileType.CROSSING; import static jcs.entities.TileBean.TileType.CURVED; import static jcs.entities.TileBean.TileType.END; import static jcs.entities.TileBean.TileType.SENSOR; import static jcs.entities.TileBean.TileType.SIGNAL; import static jcs.entities.TileBean.TileType.STRAIGHT; import static jcs.entities.TileBean.TileType.STRAIGHT_DIR; import static jcs.entities.TileBean.TileType.SWITCH; import org.tinylog.Logger; /** * Factory object to create Tiles and cache tiles * * @author frans */ public class TileFactory { // Keep the records of the used id sequence number private static int straightIdSeq; private static int crossingIdSeq; private static int curvedIdSeq; private static int switchIdSeq; private static int crossIdSeq; private static int signalIdSeq; private static int sensorIdSeq; private static int blockIdSeq; private static int straightDirectionIdSeq; private static int endIdSeq; private TileFactory() { } private static int nextIdSeq(String id) { String idnr = id.substring(3); int idSeq = Integer.parseInt(idnr); return idSeq; } private static String nextTileId(TileBean.TileType tileType) { switch (tileType) { case STRAIGHT -> { straightIdSeq++; return "st-" + straightIdSeq; } case CROSSING -> { crossingIdSeq++; return "cr-" + crossingIdSeq; } case CURVED -> { curvedIdSeq++; return "ct-" + curvedIdSeq; } case SWITCH -> { switchIdSeq++; return "sw-" + switchIdSeq; } case CROSS -> { crossIdSeq++; return "cs-" + crossIdSeq; } case SIGNAL -> { signalIdSeq++; return "si-" + signalIdSeq; } case SENSOR -> { sensorIdSeq++; return "se-" + sensorIdSeq; } case BLOCK -> { blockIdSeq++; return "bk-" + blockIdSeq; } case STRAIGHT_DIR -> { straightDirectionIdSeq++; return "sd-" + straightDirectionIdSeq; } case END -> { endIdSeq++; return "et-" + endIdSeq; } default -> { Logger.warn("Unknown Tile Type " + tileType); return null; } } } private static int maxIdSeq(int currentId, int newId) { if (currentId < newId) { return newId; } else { return currentId; } } public static Tile createTile(String tileId) { TileBean tileBean = JCS.getPersistenceService().getTileBean(tileId); return createTile(tileBean); } public static Tile createTile(TileBean tileBean) { return createTile(tileBean, false); } public static Tile createTile(TileBean tileBean, boolean showValues) { if (tileBean == null) { return null; } TileBean.TileType tileType = tileBean.getTileType(); Tile tile = null; switch (tileType) { case STRAIGHT -> { tile = new Straight(tileBean); straightIdSeq = maxIdSeq(straightIdSeq, nextIdSeq(tileBean.getId())); } case CROSSING -> { tile = new Crossing(tileBean); crossingIdSeq = maxIdSeq(crossingIdSeq, nextIdSeq(tileBean.getId())); } case CURVED -> { tile = new Curved(tileBean); curvedIdSeq = maxIdSeq(curvedIdSeq, nextIdSeq(tileBean.getId())); } case SWITCH -> { tile = new Switch(tileBean); tile.setAccessoryBean(tileBean.getAccessoryBean()); switchIdSeq = maxIdSeq(switchIdSeq, nextIdSeq(tileBean.getId())); if (showValues && tileBean.getAccessoryBean() != null) { tile.setAccessoryValue((tileBean.getAccessoryBean()).getAccessoryValue()); } JCS.getJcsCommandStation().addAccessoryEventListener((AccessoryEventListener) tile); } case CROSS -> { tile = new Cross(tileBean); tile.setAccessoryBean(tileBean.getAccessoryBean()); crossIdSeq = maxIdSeq(crossIdSeq, nextIdSeq(tileBean.getId())); if (showValues && tileBean.getAccessoryBean() != null) { tile.setAccessoryValue((tileBean.getAccessoryBean()).getAccessoryValue()); } JCS.getJcsCommandStation().addAccessoryEventListener((AccessoryEventListener) tile); } case SIGNAL -> { tile = new Signal(tileBean); tile.setAccessoryBean(tileBean.getAccessoryBean()); signalIdSeq = maxIdSeq(signalIdSeq, nextIdSeq(tileBean.getId())); if (showValues && tileBean.getAccessoryBean() != null) { ((Signal) tile).setSignalValue(((AccessoryBean) tileBean.getAccessoryBean()).getSignalValue()); } JCS.getJcsCommandStation().addAccessoryEventListener((AccessoryEventListener) tile); } case SENSOR -> { tile = new Sensor(tileBean); tile.setSensorBean(tileBean.getSensorBean()); sensorIdSeq = maxIdSeq(sensorIdSeq, nextIdSeq(tileBean.getId())); if (showValues && tileBean.getSensorBean() != null) { ((Sensor) tile).setActive(((SensorBean) tileBean.getSensorBean()).isActive()); } JCS.getJcsCommandStation().addSensorEventListener((SensorEventListener) tile); } case BLOCK -> { tile = new Block(tileBean); tile.setBlockBean(tileBean.getBlockBean()); blockIdSeq = maxIdSeq(blockIdSeq, nextIdSeq(tileBean.getId())); } case STRAIGHT_DIR -> { tile = new StraightDirection(tileBean); straightDirectionIdSeq = maxIdSeq(straightDirectionIdSeq, nextIdSeq(tileBean.getId())); } case END -> { tile = new End(tileBean); endIdSeq = maxIdSeq(endIdSeq, nextIdSeq(tileBean.getId())); } default -> Logger.warn("Unknown Tile Type " + tileType); } return (Tile) tile; } public static void rollback(Tile tile) { switch (tile.tileType) { case STRAIGHT -> { straightIdSeq--; } case CROSSING -> { crossingIdSeq--; } case CURVED -> { curvedIdSeq--; } case SWITCH -> { switchIdSeq--; } case CROSS -> { crossIdSeq--; } case SIGNAL -> { signalIdSeq--; } case SENSOR -> { sensorIdSeq--; } case BLOCK -> { blockIdSeq--; } case STRAIGHT_DIR -> { straightDirectionIdSeq--; } case END -> { endIdSeq--; } } } /** * @param tileType type of type to create * @param orientation whether the orientation of the Tile is EAST, WEST, NORTH or SOUTH * @param x the tile center X * @param y the tile center Y * @return a Tile object */ public static Tile createTile(TileBean.TileType tileType, Orientation orientation, int x, int y) { return createTile(tileType, orientation, Direction.CENTER, x, y); } /** * @param tileType type of type to create * @param orientation whether the orientation of the Tile is EAST, WEST, NORTH or SOUTH * @param direction direction plays a role with Turnout tiles whether it goes to the Left or Right * @param x the tile center X * @param y the tile center Y * @return a Tile object */ public static Tile createTile(TileBean.TileType tileType, Orientation orientation, Direction direction, int x, int y) { return createTile(tileType, orientation, direction, new Point(x, y)); } public static Tile createTile(TileBean.TileType tileType, Orientation orientation, Direction direction, Point center) { Tile tile = null; switch (tileType) { case STRAIGHT -> { tile = new Straight(orientation, center); } case CROSSING -> { tile = new Crossing(orientation, center); } case CURVED -> tile = new Curved(orientation, center); case SWITCH -> tile = new Switch(orientation, direction, center); case CROSS -> tile = new Cross(orientation, direction, center); case SIGNAL -> tile = new Signal(orientation, center); case SENSOR -> tile = new Sensor(orientation, center); case BLOCK -> tile = new Block(orientation, center); case STRAIGHT_DIR -> tile = new StraightDirection(orientation, center); case END -> tile = new End(orientation, center); default -> Logger.warn("Unknown Tile Type " + tileType); } if (tile != null) { tile.setId(nextTileId(tileType)); } return (Tile) tile; } public static List toTiles(List tileBeans, boolean drawOutline, boolean showValues) { List tileList = new LinkedList<>(); for (TileBean tileBean : tileBeans) { Tile tile = createTile(tileBean, showValues); tileList.add(tile); } return tileList; } } \ No newline at end of file From 0a9560e5ee0a4dd46632ebbbea99604e3929c34b Mon Sep 17 00:00:00 2001 From: Frans Jacobs <41232225+fransjacobs@users.noreply.github.com> Date: Thu, 30 Jan 2025 16:03:14 +0100 Subject: [PATCH 12/24] Fix moving of tile in edit screen --- src/main/java/jcs/ui/layout/LayoutCanvas.java | 68 +- src/main/java/jcs/ui/layout/tiles/Tile.java | 1142 ++++++++++++++++- .../java/jcs/ui/layout/tiles/TileCache.java | 404 +++++- 3 files changed, 1597 insertions(+), 17 deletions(-) diff --git a/src/main/java/jcs/ui/layout/LayoutCanvas.java b/src/main/java/jcs/ui/layout/LayoutCanvas.java index edc748ef..15011e12 100755 --- a/src/main/java/jcs/ui/layout/LayoutCanvas.java +++ b/src/main/java/jcs/ui/layout/LayoutCanvas.java @@ -30,7 +30,6 @@ import java.awt.event.MouseEvent; import java.awt.event.MouseMotionAdapter; import java.util.List; -import java.util.Set; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import javax.swing.JFrame; @@ -50,6 +49,7 @@ import jcs.entities.TileBean; import jcs.entities.TileBean.Direction; import jcs.entities.TileBean.Orientation; +import static jcs.entities.TileBean.Orientation.SOUTH; import jcs.entities.TileBean.TileType; import static jcs.entities.TileBean.TileType.BLOCK; import static jcs.entities.TileBean.TileType.CROSS; @@ -74,7 +74,6 @@ import jcs.ui.layout.tiles.Tile; import jcs.ui.layout.tiles.TileFactory; import jcs.ui.layout.tiles.TileCache; -import static jcs.ui.layout.tiles.TileCache.findTile; import org.tinylog.Logger; /** @@ -108,9 +107,7 @@ public enum Mode { private Tile selectedTile; private RoutesDialog routesDialog; - //private final Map selectedRouteElements; - //private Point mousePressedPoint; public LayoutCanvas() { this(false); } @@ -271,7 +268,7 @@ private void mouseMoveAction(MouseEvent evt) { private void mousePressedAction(MouseEvent evt) { Point snapPoint = LayoutUtil.snapToGrid(evt.getPoint()); //Clear any previous selection - Tile previousSelected = this.selectedTile; + Tile previousSelected = selectedTile; selectedTile = TileCache.findTile(snapPoint); if (selectedTile != null) { selectedTile.setSelected(true); @@ -363,15 +360,10 @@ void removeTile(Tile tile) { private void mouseDragAction(MouseEvent evt) { Point snapPoint = LayoutUtil.snapToGrid(evt.getPoint()); - if (selectedTile != null) { int z = getComponentZOrder(selectedTile); - Logger.trace("Moving Tile: " + selectedTile.getId() + " Z: " + z + " @ " + selectedTile.xyToString()); - - //Put on Top setComponentZOrder(selectedTile, 0); - int curX = snapPoint.x - Tile.GRID; - int curY = snapPoint.y - Tile.GRID; + //Logger.trace("Moving: " + selectedTile.getId() + " @ " + selectedTile.xyToString() + " P: " + snapPoint.x + "," + snapPoint.y + ")"); if (TileCache.canMoveTo(selectedTile, snapPoint)) { selectedTile.setSelectedColor(Tile.DEFAULT_SELECTED_COLOR); @@ -379,20 +371,66 @@ private void mouseDragAction(MouseEvent evt) { selectedTile.setSelectedColor(Tile.DEFAULT_WARN_COLOR); } + int curX, curY; + switch (selectedTile.getTileType()) { + case BLOCK -> { + if (selectedTile.isHorizontal()) { + curX = snapPoint.x - Tile.GRID - Tile.GRID * 2; + curY = snapPoint.y - Tile.GRID; + } else { + curX = snapPoint.x - Tile.GRID; + curY = snapPoint.y - Tile.GRID - Tile.GRID * 2; + } + } + case CROSS -> { + switch (selectedTile.getOrientation()) { + case SOUTH -> { + curX = snapPoint.x - Tile.GRID; + curY = snapPoint.y - Tile.GRID; + } + case WEST -> { + curX = snapPoint.x - Tile.GRID - Tile.GRID * 2; + curY = snapPoint.y - Tile.GRID; + } + case NORTH -> { + curX = snapPoint.x - Tile.GRID; + curY = snapPoint.y - Tile.GRID - Tile.GRID * 2; + } + default -> { + //East + curX = snapPoint.x - Tile.GRID; + curY = snapPoint.y - Tile.GRID; + } + } + } + default -> { + curX = snapPoint.x - Tile.GRID; + curY = snapPoint.y - Tile.GRID; + } + } selectedTile.setBounds(curX, curY, selectedTile.getWidth(), selectedTile.getHeight()); + //this.repaint(selectedTile.getTileBounds()); } } private void mouseReleasedAction(MouseEvent evt) { Point snapPoint = LayoutUtil.snapToGrid(evt.getPoint()); + //if (selectedTile != null) { + // Logger.trace(selectedTile.getId() + " sp: (" + snapPoint.x + "," + snapPoint.y + ")"); + //} else { + // Logger.trace("No Tile @ (" + snapPoint.x + "," + snapPoint.y + ")"); + //} - if (!Mode.CONTROL.equals(mode) && MouseEvent.BUTTON1 == evt.getButton() && selectedTile != null && !selectedTile.getCenter().equals(snapPoint)) { - + if (!Mode.CONTROL.equals(mode) && MouseEvent.BUTTON1 == evt.getButton() && selectedTile != null) { if (TileCache.canMoveTo(selectedTile, snapPoint)) { TileCache.moveTo(selectedTile, snapPoint); } else { - Tile occ = TileCache.findTile(snapPoint); - Logger.trace("Can't Move tile " + selectedTile.getId() + " from " + selectedTile.xyToString() + " to (" + snapPoint.x + "," + snapPoint.y + ") Is occupied by " + occ.getId()); + //Tile occ = TileCache.findTile(snapPoint); + //String occtile = ""; + //if (occ != null) { + // occtile = " Is occupied by " + occ.getId(); + //} + //Logger.trace("Can't Move tile " + selectedTile.getId() + " from " + selectedTile.xyToString() + " to (" + snapPoint.x + "," + snapPoint.y + ")" + occtile); selectedTile.setSelectedColor(Tile.DEFAULT_SELECTED_COLOR); selectedTile.setBounds(selectedTile.getTileBounds()); diff --git a/src/main/java/jcs/ui/layout/tiles/Tile.java b/src/main/java/jcs/ui/layout/tiles/Tile.java index 48c1598a..07127650 100755 --- a/src/main/java/jcs/ui/layout/tiles/Tile.java +++ b/src/main/java/jcs/ui/layout/tiles/Tile.java @@ -1 +1,1141 @@ -/* * Copyright 2024 Frans Jacobs. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package jcs.ui.layout.tiles; import java.awt.Color; import java.awt.Dimension; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.Point; import java.awt.Rectangle; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.geom.AffineTransform; import java.awt.geom.Ellipse2D; import java.awt.image.AffineTransformOp; import java.awt.image.BufferedImage; import java.beans.PropertyChangeListener; import java.io.Serializable; import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import javax.swing.JComponent; import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; import jcs.entities.AccessoryBean; import jcs.entities.AccessoryBean.AccessoryValue; import jcs.entities.AccessoryBean.SignalType; import jcs.entities.BlockBean; import jcs.entities.BlockBean.BlockState; import jcs.entities.LocomotiveBean; import jcs.entities.SensorBean; import jcs.entities.TileBean; import jcs.entities.TileBean.Direction; import jcs.entities.TileBean.Orientation; import jcs.entities.TileBean.TileType; import jcs.ui.layout.LayoutUtil; import static jcs.ui.layout.tiles.Block.BLOCK_HEIGHT; import static jcs.ui.layout.tiles.Block.BLOCK_WIDTH; import org.imgscalr.Scalr; import org.imgscalr.Scalr.Method; import org.imgscalr.Scalr.Mode; import org.tinylog.Logger; /** * Basic graphic element to display a track, turnout, etc on the screen.
* By default the drawing of a Tile is Horizontal from L to R or West to East.
* The default orientation is East. * *

* The default size of a Tile is 40 tileX 40 pixels.
* The center point of a Tile is stored and always snapped to the nearest grid point.
* The basic grid is 20x 20 pixels.
* *

* A Tile can be rotated (always clockwise).
* Rotation will change the orientation from East -> South -> West -> North -> East.
* *

* A Tile is rendered to a Buffered Image to speed up the display */ public abstract class Tile extends JComponent { //implements TileEventListener { //, ItemSelectable { public static final int GRID = 20; public static final int DEFAULT_WIDTH = GRID * 2; public static final int DEFAULT_HEIGHT = GRID * 2; static final int RENDER_GRID = GRID * 10; static final int RENDER_WIDTH = RENDER_GRID * 2; static final int RENDER_HEIGHT = RENDER_GRID * 2; public static final Color DEFAULT_BACKGROUND_COLOR = Color.white; public static final Color DEFAULT_TRACK_COLOR = Color.lightGray; public static final Color DEFAULT_ROUTE_TRACK_COLOR = Color.blue; public static final Color DEFAULT_SELECTED_COLOR = Color.orange; public static final Color DEFAULT_WARN_COLOR = Color.red; public static final String MODEL_CHANGED_PROPERTY = "model"; public static final String CONTENT_AREA_FILLED_CHANGED_PROPERTY = "contentAreaFilled"; /** * The data model that determines the button's state. */ protected TileModel model = null; protected String id; protected Integer tileX; protected Integer tileY; protected int renderWidth; protected int renderHeight; //protected Orientation tileOrientation; protected Direction tileDirection; protected TileType tileType; protected String accessoryId; protected String sensorId; protected AccessoryValue accessoryValue; protected AccessoryValue routeValue; protected SignalType signalType; protected AccessoryBean.SignalValue signalValue; protected TileBean tileBean; protected AccessoryBean accessoryBean; protected SensorBean sensorBean; protected BlockBean blockBean; protected List neighbours; protected int offsetX = 0; protected int offsetY = 0; protected int renderOffsetX = 0; protected int renderOffsetY = 0; //protected Color selectedColor; protected Color trackColor; protected Color trackRouteColor; protected Orientation incomingSide; protected Color backgroundColor; protected boolean drawName = true; protected BufferedImage tileImage; protected PropertyChangeListener propertyChangeListener; protected ChangeListener changeListener = null; protected ActionListener actionListener = null; protected transient ChangeEvent changeEvent; private Handler handler; protected Tile(TileType tileType, Orientation orientation, Point center, int width, int height) { this(tileType, orientation, Direction.CENTER, center.x, center.y, width, height); } protected Tile(TileType tileType, Orientation orientation, int x, int y, int width, int height) { this(tileType, orientation, Direction.CENTER, x, y, width, height); } protected Tile(TileType tileType, Orientation orientation, Direction direction, int x, int y, int width, int height) { this(tileType, orientation, direction, x, y, width, height, null, null); } protected Tile(TileType tileType, Orientation orientation, Direction direction, int x, int y, int width, int height, Color backgroundColor, Color selectedColor) { this.tileType = tileType; //this.tileOrientation = orientation; //model.setTileOrienation(orientation); this.tileDirection = direction; this.tileX = x; this.tileY = y; setLayout(null); Dimension d = new Dimension(width, height); setSize(d); setPreferredSize(d); this.renderWidth = RENDER_WIDTH; this.renderHeight = RENDER_HEIGHT; this.trackColor = DEFAULT_TRACK_COLOR; this.backgroundColor = backgroundColor; //this.selectedColor = selectedColor; if (this.backgroundColor == null) { this.backgroundColor = DEFAULT_BACKGROUND_COLOR; } // if (this.selectedColor == null) { // this.selectedColor = DEFAULT_SELECTED_COLOR; // } } protected Tile(TileBean tileBean) { this(tileBean, tileWidth(tileBean.getOrientation(), tileBean.getTileType()), tileHeight(tileBean.getOrientation(), tileBean.getTileType())); } protected Tile(TileBean tileBean, int width, int height) { this.tileBean = tileBean; //Quick properties this.id = tileBean.getId(); this.tileType = tileBean.getTileType(); //this.tileOrientation = tileBean.getOrientation(); //this.model.setTileOrienation(tileBean.getOrientation()); this.tileDirection = tileBean.getDirection(); this.tileX = tileBean.getX(); this.tileY = tileBean.getY(); this.accessoryId = tileBean.getAccessoryId(); this.accessoryBean = tileBean.getAccessoryBean(); this.signalType = tileBean.getSignalType(); this.sensorId = tileBean.getSensorId(); this.sensorBean = tileBean.getSensorBean(); this.blockBean = tileBean.getBlockBean(); setLayout(null); Dimension d = new Dimension(width, height); setSize(d); setPreferredSize(d); this.trackColor = DEFAULT_TRACK_COLOR; this.backgroundColor = DEFAULT_BACKGROUND_COLOR; // this.selectedColor = DEFAULT_SELECTED_COLOR; this.renderWidth = RENDER_WIDTH; this.renderHeight = RENDER_HEIGHT; } protected static int tileWidth(Orientation orientation, TileType tileType) { if (Orientation.EAST == orientation || Orientation.WEST == orientation) { if (null == tileType) { return DEFAULT_WIDTH; } else { return switch (tileType) { case BLOCK -> BLOCK_WIDTH; case CROSS -> DEFAULT_WIDTH * 2; default -> DEFAULT_WIDTH; }; } } else { return DEFAULT_WIDTH; } } protected static int tileHeight(Orientation orientation, TileType tileType) { if (Orientation.EAST == orientation || Orientation.WEST == orientation) { return DEFAULT_HEIGHT; } else { if (null == tileType) { return DEFAULT_HEIGHT; } else { return switch (tileType) { case BLOCK -> BLOCK_HEIGHT; case CROSS -> DEFAULT_HEIGHT * 2; default -> DEFAULT_HEIGHT; }; } } } protected void populateModel() { if (this.blockBean != null) { this.model.setBlockState(this.blockBean.getBlockState()); this.model.setLocomotive(this.blockBean.getLocomotive()); this.model.setArrivalSuffix(this.blockBean.getArrivalSuffix()); this.model.setLogicalDirection(LocomotiveBean.Direction.get(this.blockBean.getLogicalDirection())); } } public TileBean getTileBean() { if (tileBean == null) { tileBean = new TileBean(); tileBean.setId(this.id); tileBean.setX(this.tileX); tileBean.setY(this.tileY); tileBean.setTileType(this.tileType); //tileBean.setTileOrientation(this.tileOrientation.getOrientation()); tileBean.setTileOrientation(this.model.getTileOrienation().getOrientation()); tileBean.setTileDirection(this.tileDirection.getDirection()); tileBean.setSignalType(this.signalType); tileBean.setAccessoryId(this.accessoryId); tileBean.setSensorId(this.sensorId); tileBean.setAccessoryBean(this.accessoryBean); tileBean.setSensorBean(this.sensorBean); tileBean.setBlockBean(this.blockBean); } return tileBean; } public boolean isSelected() { return model.isSelected(); } public void setSelected(boolean b) { //boolean oldValue = isSelected(); model.setSelected(b); } public String getId() { return id; } public void setId(String id) { this.id = id; } public SignalType getSignalType() { return signalType; } public void setSignalType(SignalType signalType) { this.signalType = signalType; } public Integer getTileX() { return tileX; } public Integer getTileY() { return tileY; } public Point getCenter() { return new Point(this.tileX, this.tileY); } public void setCenter(Point center) { tileX = center.x; tileY = center.y; if (tileBean != null) { tileBean.setCenter(center); } Logger.trace(id + " Cp: " + xyToString()); } public Orientation getOrientation() { //return tileOrientation; return model.getTileOrienation(); } public void setOrientation(Orientation orientation) { //this.tileOrientation = orientation; model.setTileOrienation(orientation); if (tileBean != null) { tileBean.setOrientation(orientation); } } public Direction getDirection() { return tileDirection; } public void setDirection(Direction direction) { this.tileDirection = direction; if (tileBean != null) { tileBean.setDirection(direction); } } public String getAccessoryId() { return accessoryId; } public void setAccessoryId(String accessoryId) { this.accessoryId = accessoryId; if (tileBean != null) { tileBean.setAccessoryId(accessoryId); } } public String getSensorId() { return sensorId; } public void setSensorId(String sensorId) { this.sensorId = sensorId; } public boolean isActive() { return model.isSensorActive(); } public void setActive(boolean active) { model.setSensorActive(active); } public BlockState getBlockState() { return model.getBlockState(); } public void setBlockState(BlockState blockState) { if (blockBean != null) { blockBean.setBlockState(blockState); LocomotiveBean locomotive = model.getLocomotive(); model.setOverlayImage(locomotive != null && locomotive.getLocIcon() != null && (blockState == BlockState.OCCUPIED || blockState == BlockState.INBOUND || blockState == BlockState.OUTBOUND)); } model.setBlockState(blockState); } public String getDepartureSuffix() { return model.getDepartureSuffix(); } public void setDepartureSuffix(String suffix) { if (blockBean != null) { blockBean.setDepartureSuffix(suffix); } model.setDepartureSuffix(suffix); } public boolean isReverseArrival() { return model.isReverseArrival(); } public void setReverseArrival(boolean reverseArrival) { if (blockBean != null) { blockBean.setReverseArrival(reverseArrival); } model.setReverseArrival(reverseArrival); } public LocomotiveBean.Direction getLogicalDirection() { return model.getLogicalDirection(); } public void setLogicalDirection(LocomotiveBean.Direction logicalDirection) { if (blockBean != null) { blockBean.setLogicalDirection(logicalDirection.getDirection()); } model.setLogicalDirection(logicalDirection); } public LocomotiveBean getLocomotive() { return model.getLocomotive(); } public void setLocomotive(LocomotiveBean locomotive) { if (blockBean != null) { blockBean.setLocomotive(locomotive); model.setOverlayImage(locomotive != null && locomotive.getLocIcon() != null && (model.getBlockState() == BlockState.OCCUPIED || model.getBlockState() == BlockState.INBOUND || model.getBlockState() == BlockState.OUTBOUND)); } model.setLocomotive(locomotive); } public AccessoryBean getAccessoryBean() { return accessoryBean; } public void setAccessoryBean(AccessoryBean accessoryBean) { this.accessoryBean = accessoryBean; if (accessoryBean != null) { accessoryId = accessoryBean.getId(); signalValue = accessoryBean.getSignalValue(); signalType = SignalType.getSignalType(accessoryBean.getType()); } else { accessoryId = null; signalType = SignalType.NONE; signalValue = AccessoryBean.SignalValue.OFF; } } public AccessoryValue getAccessoryValue() { if (this.accessoryValue == null) { return AccessoryValue.OFF; } else { return accessoryValue; } } public void setAccessoryValue(AccessoryValue value) { this.accessoryValue = value; repaint(); } public AccessoryValue getRouteValue() { if (routeValue == null) { return AccessoryValue.OFF; } else { return routeValue; } } public void setRouteValue(AccessoryValue value) { this.routeValue = value; repaint(); } public AccessoryBean.SignalValue getSignalValue() { return signalValue; } public void setSignalValue(AccessoryBean.SignalValue signalValue) { this.signalValue = signalValue; repaint(); } public SensorBean getSensorBean() { return sensorBean; } public void setSensorBean(SensorBean sensorBean) { this.sensorBean = sensorBean; } public BlockBean getBlockBean() { return blockBean; } public void setBlockBean(BlockBean blockBean) { this.blockBean = blockBean; } public void setRenderWidth(int renderWidth) { this.renderWidth = renderWidth; } public void setRenderHeight(int renderHeight) { this.renderHeight = renderHeight; } public int getRenderOffsetX() { return renderOffsetX; } public void setRenderOffsetX(int renderOffsetX) { this.renderOffsetX = renderOffsetX; } public int getRenderOffsetY() { return renderOffsetY; } public void setRenderOffsetY(int renderOffsetY) { this.renderOffsetY = renderOffsetY; } public TileBean.TileType getTileType() { return this.tileType; } public final void setTileType(TileType tileType) { this.tileType = tileType; } public Color getTrackColor() { return trackColor; } public final void setTrackColor(Color trackColor) { this.trackColor = trackColor; } public Color getTrackRouteColor() { return trackRouteColor; } public void setTrackRouteColor(Color trackRouteColor) { this.trackRouteColor = trackRouteColor; } public Color getSelectedColor() { return model.getSelectedColor(); } public void setSelectedColor(Color selectedColor) { this.model.setSelectedColor(selectedColor); } public Orientation getIncomingSide() { return incomingSide; } public void setIncomingSide(Orientation incomingSide) { this.incomingSide = incomingSide; } public Color getBackgroundColor() { return backgroundColor; } public void setBackgroundColor(Color backgroundColor) { this.backgroundColor = backgroundColor; } public boolean isDrawRoute() { return model.isShowRoute(); } public void setDrawRoute(boolean drawRoute) { this.model.setShowRoute(drawRoute); } public int getRenderWidth() { return renderWidth; } public int getRenderHeight() { return renderHeight; } abstract void renderTile(Graphics2D g2d); abstract void renderTileRoute(Graphics2D g2d); public abstract Map getNeighborPoints(); public abstract Map getEdgePoints(); //public abstract Set getAllPoints(); //public abstract Set getAllPoints(Point center); //public abstract Set getAltPoints(Point center); Set getAltPoints(Point center) { return Collections.EMPTY_SET; } public Set getAllPoints() { return getAllPoints(getCenter()); } Set getAllPoints(Point center) { Set aps = new HashSet<>(); aps.add(center); return aps; } /** * Draw the Tile * * @param g2d The graphics handle */ public void drawTile(Graphics2D g2d) { // by default and image is rendered in the EAST orientation Orientation tileOrientation = model.getTileOrienation(); // if (tileOrientation == null) { // tileOrientation = Orientation.EAST; // } BufferedImage bf = createImage(); Graphics2D g2di = bf.createGraphics(); //Avoid errors if (model.isShowRoute() && incomingSide == null) { incomingSide = getOrientation(); } if (model.isSelected()) { g2di.setBackground(model.getSelectedColor()); } else { g2di.setBackground(backgroundColor); } g2di.clearRect(0, 0, renderWidth, renderHeight); int ox = 0, oy = 0; AffineTransform trans = new AffineTransform(); switch (tileOrientation) { case SOUTH -> { trans.rotate(Math.PI / 2, renderWidth / 2, renderHeight / 2); ox = (renderHeight - renderWidth) / 2; oy = (renderWidth - renderHeight) / 2; trans.translate(-ox, -oy); } case WEST -> { trans.rotate(Math.PI, renderWidth / 2, renderHeight / 2); trans.translate(ox, oy); } case NORTH -> { trans.rotate(-Math.PI / 2, renderWidth / 2, renderHeight / 2); ox = (renderHeight - renderWidth) / 2; oy = (renderWidth - renderHeight) / 2; trans.translate(-ox, -oy); } default -> { trans.rotate(0.0, this.renderWidth / 2, this.renderHeight / 2); trans.translate(ox, oy); } } //Logger.trace(tileOrientation.getOrientation() + " renderWidth: " + renderWidth + " renderHeight: " + renderHeight + " CP: (" + renderWidth / 2 + "," + renderHeight / 2 + ")"); //Logger.trace(tileOrientation.getOrientation() + " ox: " + ox + " oy: " + oy); g2di.setTransform(trans); renderTile(g2di); if (model.isShowRoute()) { renderTileRoute(g2di); } if (model.isShowCenter()) { drawCenterPoint(g2di); } // Scale the image back... if (model.isScaleImage()) { tileImage = Scalr.resize(bf, Method.AUTOMATIC, Mode.FIT_EXACT, getWidth(), getHeight(), Scalr.OP_ANTIALIAS); } else { tileImage = bf; } g2di.dispose(); Logger.trace(id + " Cp: " + xyToString()); } public BufferedImage getTileImage() { return tileImage; } /** * Render a tile image Always starts at (0,0) used the default width and height * * @param g2 the Graphic context */ public void drawName(Graphics2D g2) { } protected void drawCenterPoint(Graphics2D g2d) { drawCenterPoint(g2d, Color.magenta); } protected void drawCenterPoint(Graphics2D g2, Color color) { drawCenterPoint(g2, color, 60); } protected void drawCenterPoint(Graphics2D g2d, Color color, double size) { double dX = (renderWidth / 2 - size / 2); double dY = (renderHeight / 2 - size / 2); g2d.setColor(color); g2d.fill(new Ellipse2D.Double(dX, dY, size, size)); } /** * Rotate the tile clockwise 90 deg * * @return the new Orientation */ public Orientation rotate() { Orientation tileOrientation = model.getTileOrienation(); switch (tileOrientation) { case EAST -> setOrientation(Orientation.SOUTH); case SOUTH -> setOrientation(Orientation.WEST); case WEST -> setOrientation(Orientation.NORTH); default -> setOrientation(Orientation.EAST); } return model.getTileOrienation(); } public void flipHorizontal() { Orientation tileOrientation = model.getTileOrienation(); if (Orientation.NORTH == tileOrientation || Orientation.SOUTH == tileOrientation) { rotate(); rotate(); } } public void flipVertical() { Orientation tileOrientation = model.getTileOrienation(); if (Orientation.EAST == tileOrientation || Orientation.WEST == tileOrientation) { rotate(); rotate(); } } @Override public void move(int newX, int newY) { Point cs = LayoutUtil.snapToGrid(newX, newY); setCenter(cs); } protected static void drawRotate(Graphics2D g2d, double x, double y, int angle, String text) { g2d.translate((float) x, (float) y); g2d.rotate(Math.toRadians(angle)); g2d.drawString(text, 0, 0); g2d.rotate(-Math.toRadians(angle)); g2d.translate(-x, -y); } public static BufferedImage flipHorizontally(BufferedImage source) { BufferedImage output = new BufferedImage(source.getHeight(), source.getWidth(), source.getType()); AffineTransform flip = AffineTransform.getScaleInstance(1, -1); flip.translate(0, -source.getHeight()); AffineTransformOp op = new AffineTransformOp(flip, AffineTransformOp.TYPE_NEAREST_NEIGHBOR); op.filter(source, output); return output; } public static BufferedImage flipVertically(BufferedImage source) { BufferedImage output = new BufferedImage(source.getHeight(), source.getWidth(), source.getType()); AffineTransform flip = AffineTransform.getScaleInstance(-1, 1); flip.translate(-source.getWidth(), 0); AffineTransformOp op = new AffineTransformOp(flip, AffineTransformOp.TYPE_NEAREST_NEIGHBOR); op.filter(source, output); return output; } public Set getAltPoints() { return Collections.EMPTY_SET; } public final int getOffsetX() { return offsetX; } public void setOffsetX(int offsetX) { this.offsetX = offsetX; } public final int getOffsetY() { return offsetY; } public void setOffsetY(int offsetY) { this.offsetY = offsetY; } protected BufferedImage createImage() { return new BufferedImage(renderWidth, renderHeight, BufferedImage.TYPE_INT_RGB); } public int getCenterX() { if (tileX > 0) { return this.tileX; } else { return GRID; } } public int getCenterY() { if (tileY > 0) { return this.tileY; } else { return GRID; } } public boolean isDrawName() { return drawName; } public void setDrawName(boolean drawName) { this.drawName = drawName; } public boolean isScaleImage() { return model.isScaleImage(); } public void setScaleImage(boolean scaleImage) { Dimension d; if (scaleImage) { d = new Dimension(DEFAULT_WIDTH, DEFAULT_HEIGHT); } else { d = new Dimension(renderWidth, renderHeight); } setSize(d); setPreferredSize(d); model.setScaleImage(scaleImage); } public boolean isDrawCenterPoint() { return model.isShowCenter(); } public void setDrawCenterPoint(boolean drawCenterPoint) { model.setShowCenter(drawCenterPoint); } @Override public String toString() { return this.getClass().getSimpleName() + " {id: " + this.id + ", orientation: " + getOrientation() + ", direction: " + getDirection() + ", center: " + xyToString() + "}"; } public String xyToString() { return "(" + this.tileX + "," + this.tileY + ")"; } /** * The main route of the tile is horizontal * * @return true when main route goes from East to West or vv */ public boolean isHorizontal() { Orientation tileOrientation = model.getTileOrienation(); return (Orientation.EAST == tileOrientation || Orientation.WEST == tileOrientation) && TileType.CURVED != tileType; } /** * The main route of the tile is vertical * * @return true when main route goes from North to South or vv */ public boolean isVertical() { Orientation tileOrientation = model.getTileOrienation(); return (Orientation.NORTH == tileOrientation || Orientation.SOUTH == tileOrientation) && TileType.CURVED != tileType; } public boolean isJunction() { return TileType.SWITCH == tileType || TileType.CROSS == tileType; } public boolean isBlock() { return TileType.BLOCK == tileType; } public boolean isDirectional() { return TileType.STRAIGHT_DIR == tileType; } /** * The main route of the tile is diagonal * * @return true when main route goes from North to East or West to South and vv */ public boolean isDiagonal() { return TileType.CURVED == tileType; } public boolean isCrossing() { return TileType.CROSSING == tileType; } public List getNeighbours() { return neighbours; } public void setNeighbours(List neighbours) { this.neighbours = neighbours; } public String getIdSuffix(Tile other) { return ""; } public Map getNeighborOrientations() { Map edgeOrientations = new HashMap<>(); Map neighborPoints = getNeighborPoints(); for (Orientation o : Orientation.values()) { edgeOrientations.put(neighborPoints.get(o), o); } return edgeOrientations; } public Map getEdgeOrientations() { Map edgeOrientations = new HashMap<>(); Map edgeConnections = getEdgePoints(); for (Orientation o : Orientation.values()) { edgeOrientations.put(edgeConnections.get(o), o); } return edgeOrientations; } public boolean isAdjacent(Tile other) { boolean adjacent = false; if (other != null) { Collection thisEdgePoints = getEdgePoints().values(); Collection otherEdgePoints = other.getEdgePoints().values(); for (Point p : thisEdgePoints) { adjacent = otherEdgePoints.contains(p); if (adjacent) { break; } } } return adjacent; } /** * When the tile has a specific direction a train may travel,
* then this method will indicate whether the other tile is in on the side where the arrow is pointing to. * * @param other A Tile * @return true where other is on the side of this tile where the arrow points to */ public boolean isArrowDirection(Tile other) { return true; } public AccessoryValue accessoryValueForRoute(Orientation from, Orientation to) { return AccessoryValue.OFF; } public TileModel getModel() { return model; } public void setModel(TileModel newModel) { TileModel oldModel = getModel(); if (oldModel != null) { oldModel.removeChangeListener(changeListener); oldModel.removeActionListener(actionListener); changeListener = null; actionListener = null; } model = newModel; if (newModel != null) { changeListener = createChangeListener(); actionListener = createActionListener(); newModel.addChangeListener(changeListener); newModel.addActionListener(actionListener); } firePropertyChange(MODEL_CHANGED_PROPERTY, oldModel, newModel); if (newModel != oldModel) { revalidate(); repaint(); } } // public TileUI getUI() { // return (TileUI) ui; // } // public void setUI(TileUI ui) { // super.setUI(ui); // } @Override public void updateUI() { } protected ChangeListener createChangeListener() { return getHandler(); } protected ActionListener createActionListener() { return getHandler(); } private Handler getHandler() { if (handler == null) { handler = new Handler(); } return handler; } class Handler implements ActionListener, ChangeListener, Serializable { @Override public void stateChanged(ChangeEvent e) { //Object source = e.getSource(); fireStateChanged(); repaint(); } @Override public void actionPerformed(ActionEvent event) { fireActionPerformed(event); } } protected void fireStateChanged() { Object[] listeners = listenerList.getListenerList(); //reverse order for (int i = listeners.length - 2; i >= 0; i -= 2) { if (listeners[i] == ChangeListener.class) { // Lazily create the event: if (changeEvent == null) { changeEvent = new ChangeEvent(this); } ((ChangeListener) listeners[i + 1]).stateChanged(changeEvent); } } } protected void fireActionPerformed(ActionEvent event) { Object[] listeners = listenerList.getListenerList(); ActionEvent e = null; // reverse for (int i = listeners.length - 2; i >= 0; i -= 2) { if (listeners[i] == ActionListener.class) { // Lazily create the event: if (e == null) { String actionCommand = event.getActionCommand(); //if(actionCommand == null) { // actionCommand = getActionCommand(); //} e = new ActionEvent(Tile.this, ActionEvent.ACTION_PERFORMED, actionCommand, event.getWhen(), event.getModifiers()); } ((ActionListener) listeners[i + 1]).actionPerformed(e); } } } public Rectangle getTileBounds() { if (model.isScaleImage()) { return new Rectangle(tileX - GRID, tileY - GRID, DEFAULT_WIDTH, DEFAULT_HEIGHT); } else { return new Rectangle(tileX - renderWidth / 2, tileY - renderHeight / 2, renderWidth, renderHeight); } } @Override protected void paintComponent(Graphics g) { long started = System.currentTimeMillis(); Graphics2D g2 = (Graphics2D) g.create(); //Graphics2D g2 = (Graphics2D) g.create(tileX - GRID, tileY - GRID, DEFAULT_WIDTH, DEFAULT_HEIGHT); drawTile(g2); g2.dispose(); g.drawImage(tileImage, 0, 0, null); long now = System.currentTimeMillis(); Logger.trace(id + " Duration: " + (now - started) + " ms. Cp: " + xyToString() + " O: " + model.getTileOrienation()); } } \ No newline at end of file +/* + * Copyright 2024 Frans Jacobs. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package jcs.ui.layout.tiles; + +import java.awt.Color; +import java.awt.Dimension; +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.Point; +import java.awt.Rectangle; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.geom.AffineTransform; +import java.awt.geom.Ellipse2D; +import java.awt.image.AffineTransformOp; +import java.awt.image.BufferedImage; +import java.beans.PropertyChangeListener; +import java.io.Serializable; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import javax.swing.JComponent; +import javax.swing.event.ChangeEvent; +import javax.swing.event.ChangeListener; +import jcs.entities.AccessoryBean; +import jcs.entities.AccessoryBean.AccessoryValue; +import jcs.entities.AccessoryBean.SignalType; +import jcs.entities.BlockBean; +import jcs.entities.BlockBean.BlockState; +import jcs.entities.LocomotiveBean; +import jcs.entities.SensorBean; +import jcs.entities.TileBean; +import jcs.entities.TileBean.Direction; +import jcs.entities.TileBean.Orientation; +import jcs.entities.TileBean.TileType; +import jcs.ui.layout.LayoutUtil; +import static jcs.ui.layout.tiles.Block.BLOCK_HEIGHT; +import static jcs.ui.layout.tiles.Block.BLOCK_WIDTH; +import org.imgscalr.Scalr; +import org.imgscalr.Scalr.Method; +import org.imgscalr.Scalr.Mode; +import org.tinylog.Logger; + +/** + * Basic graphic element to display a track, turnout, etc on the screen.
+ * By default the drawing of a Tile is Horizontal from L to R or West to East.
+ * The default orientation is East. + * + *

+ * The default size of a Tile is 40 tileX 40 pixels.
+ * The center point of a Tile is stored and always snapped to the nearest grid point.
+ * The basic grid is 20x 20 pixels.
+ * + *

+ * A Tile can be rotated (always clockwise).
+ * Rotation will change the orientation from East -> South -> West -> North -> East.
+ * + *

+ * A Tile is rendered to a Buffered Image to speed up the display + */ +public abstract class Tile extends JComponent { //implements TileEventListener { //, ItemSelectable { + + public static final int GRID = 20; + public static final int DEFAULT_WIDTH = GRID * 2; + public static final int DEFAULT_HEIGHT = GRID * 2; + + static final int RENDER_GRID = GRID * 10; + static final int RENDER_WIDTH = RENDER_GRID * 2; + static final int RENDER_HEIGHT = RENDER_GRID * 2; + + public static final Color DEFAULT_BACKGROUND_COLOR = Color.white; + public static final Color DEFAULT_TRACK_COLOR = Color.lightGray; + public static final Color DEFAULT_ROUTE_TRACK_COLOR = Color.blue; + public static final Color DEFAULT_SELECTED_COLOR = Color.orange; + public static final Color DEFAULT_WARN_COLOR = Color.red; + + public static final String MODEL_CHANGED_PROPERTY = "model"; + public static final String CONTENT_AREA_FILLED_CHANGED_PROPERTY = "contentAreaFilled"; + + /** + * The data model that determines the button's state. + */ + protected TileModel model = null; + + protected String id; + protected Integer tileX; + protected Integer tileY; + + protected int renderWidth; + protected int renderHeight; + + //protected Orientation tileOrientation; + protected Direction tileDirection; + + protected TileType tileType; + protected String accessoryId; + protected String sensorId; + + protected AccessoryValue accessoryValue; + protected AccessoryValue routeValue; + + protected SignalType signalType; + protected AccessoryBean.SignalValue signalValue; + + protected TileBean tileBean; + protected AccessoryBean accessoryBean; + protected SensorBean sensorBean; + protected BlockBean blockBean; + + protected List neighbours; + + protected int offsetX = 0; + protected int offsetY = 0; + + protected int renderOffsetX = 0; + protected int renderOffsetY = 0; + + //protected Color selectedColor; + protected Color trackColor; + protected Color trackRouteColor; + protected Orientation incomingSide; + + protected Color backgroundColor; + protected boolean drawName = true; + + protected BufferedImage tileImage; + + protected PropertyChangeListener propertyChangeListener; + + protected ChangeListener changeListener = null; + protected ActionListener actionListener = null; + + protected transient ChangeEvent changeEvent; + + private Handler handler; + + protected Tile(TileType tileType, Orientation orientation, Point center, int width, int height) { + this(tileType, orientation, Direction.CENTER, center.x, center.y, width, height); + } + + protected Tile(TileType tileType, Orientation orientation, int x, int y, int width, int height) { + this(tileType, orientation, Direction.CENTER, x, y, width, height); + } + + protected Tile(TileType tileType, Orientation orientation, Direction direction, int x, int y, int width, int height) { + this(tileType, orientation, direction, x, y, width, height, null, null); + } + + protected Tile(TileType tileType, Orientation orientation, Direction direction, int x, int y, int width, int height, Color backgroundColor, Color selectedColor) { + this.tileType = tileType; + //this.tileOrientation = orientation; + //model.setTileOrienation(orientation); + this.tileDirection = direction; + this.tileX = x; + this.tileY = y; + + setLayout(null); + Dimension d = new Dimension(width, height); + setSize(d); + setPreferredSize(d); + + this.renderWidth = RENDER_WIDTH; + this.renderHeight = RENDER_HEIGHT; + + this.trackColor = DEFAULT_TRACK_COLOR; + this.backgroundColor = backgroundColor; + //this.selectedColor = selectedColor; + + if (this.backgroundColor == null) { + this.backgroundColor = DEFAULT_BACKGROUND_COLOR; + } +// if (this.selectedColor == null) { +// this.selectedColor = DEFAULT_SELECTED_COLOR; +// } + } + + protected Tile(TileBean tileBean) { + this(tileBean, tileWidth(tileBean.getOrientation(), tileBean.getTileType()), tileHeight(tileBean.getOrientation(), tileBean.getTileType())); + } + + protected Tile(TileBean tileBean, int width, int height) { + this.tileBean = tileBean; + //Quick properties + this.id = tileBean.getId(); + this.tileType = tileBean.getTileType(); + //this.tileOrientation = tileBean.getOrientation(); + //this.model.setTileOrienation(tileBean.getOrientation()); + this.tileDirection = tileBean.getDirection(); + this.tileX = tileBean.getX(); + this.tileY = tileBean.getY(); + + this.accessoryId = tileBean.getAccessoryId(); + this.accessoryBean = tileBean.getAccessoryBean(); + this.signalType = tileBean.getSignalType(); + + this.sensorId = tileBean.getSensorId(); + this.sensorBean = tileBean.getSensorBean(); + this.blockBean = tileBean.getBlockBean(); + + setLayout(null); + Dimension d = new Dimension(width, height); + setSize(d); + setPreferredSize(d); + + this.trackColor = DEFAULT_TRACK_COLOR; + this.backgroundColor = DEFAULT_BACKGROUND_COLOR; +// this.selectedColor = DEFAULT_SELECTED_COLOR; + this.renderWidth = RENDER_WIDTH; + this.renderHeight = RENDER_HEIGHT; + } + + protected static int tileWidth(Orientation orientation, TileType tileType) { + if (Orientation.EAST == orientation || Orientation.WEST == orientation) { + if (null == tileType) { + return DEFAULT_WIDTH; + } else { + return switch (tileType) { + case BLOCK -> + BLOCK_WIDTH; + case CROSS -> + DEFAULT_WIDTH * 2; + default -> + DEFAULT_WIDTH; + }; + } + } else { + return DEFAULT_WIDTH; + } + } + + protected static int tileHeight(Orientation orientation, TileType tileType) { + if (Orientation.EAST == orientation || Orientation.WEST == orientation) { + return DEFAULT_HEIGHT; + } else { + if (null == tileType) { + return DEFAULT_HEIGHT; + } else { + return switch (tileType) { + case BLOCK -> + BLOCK_HEIGHT; + case CROSS -> + DEFAULT_HEIGHT * 2; + default -> + DEFAULT_HEIGHT; + }; + } + } + } + + protected void populateModel() { + if (this.blockBean != null) { + this.model.setBlockState(this.blockBean.getBlockState()); + this.model.setLocomotive(this.blockBean.getLocomotive()); + this.model.setArrivalSuffix(this.blockBean.getArrivalSuffix()); + this.model.setLogicalDirection(LocomotiveBean.Direction.get(this.blockBean.getLogicalDirection())); + } + } + + public TileBean getTileBean() { + if (tileBean == null) { + tileBean = new TileBean(); + tileBean.setId(this.id); + tileBean.setX(this.tileX); + tileBean.setY(this.tileY); + tileBean.setTileType(this.tileType); + //tileBean.setTileOrientation(this.tileOrientation.getOrientation()); + tileBean.setTileOrientation(this.model.getTileOrienation().getOrientation()); + + tileBean.setTileDirection(this.tileDirection.getDirection()); + tileBean.setSignalType(this.signalType); + tileBean.setAccessoryId(this.accessoryId); + tileBean.setSensorId(this.sensorId); + tileBean.setAccessoryBean(this.accessoryBean); + tileBean.setSensorBean(this.sensorBean); + tileBean.setBlockBean(this.blockBean); + } + return tileBean; + } + + public boolean isSelected() { + return model.isSelected(); + } + + public void setSelected(boolean b) { + //boolean oldValue = isSelected(); + model.setSelected(b); + } + + public String getId() { + return id; + } + + public void setId(String id) { + this.id = id; + } + + public SignalType getSignalType() { + return signalType; + } + + public void setSignalType(SignalType signalType) { + this.signalType = signalType; + } + + public Integer getTileX() { + return tileX; + } + + public Integer getTileY() { + return tileY; + } + + public Point getCenter() { + return new Point(this.tileX, this.tileY); + } + + public void setCenter(Point center) { + tileX = center.x; + tileY = center.y; + if (tileBean != null) { + tileBean.setCenter(center); + } + } + + public Orientation getOrientation() { + //return tileOrientation; + return model.getTileOrienation(); + } + + public void setOrientation(Orientation orientation) { + //this.tileOrientation = orientation; + model.setTileOrienation(orientation); + if (tileBean != null) { + tileBean.setOrientation(orientation); + } + } + + public Direction getDirection() { + return tileDirection; + } + + public void setDirection(Direction direction) { + this.tileDirection = direction; + if (tileBean != null) { + tileBean.setDirection(direction); + } + } + + public String getAccessoryId() { + return accessoryId; + } + + public void setAccessoryId(String accessoryId) { + this.accessoryId = accessoryId; + if (tileBean != null) { + tileBean.setAccessoryId(accessoryId); + } + } + + public String getSensorId() { + return sensorId; + } + + public void setSensorId(String sensorId) { + this.sensorId = sensorId; + } + + public boolean isActive() { + return model.isSensorActive(); + } + + public void setActive(boolean active) { + model.setSensorActive(active); + } + + public BlockState getBlockState() { + return model.getBlockState(); + } + + public void setBlockState(BlockState blockState) { + if (blockBean != null) { + blockBean.setBlockState(blockState); + LocomotiveBean locomotive = model.getLocomotive(); + model.setOverlayImage(locomotive != null && locomotive.getLocIcon() != null && (blockState == BlockState.OCCUPIED || blockState == BlockState.INBOUND || blockState == BlockState.OUTBOUND)); + } + model.setBlockState(blockState); + } + + public String getDepartureSuffix() { + return model.getDepartureSuffix(); + } + + public void setDepartureSuffix(String suffix) { + if (blockBean != null) { + blockBean.setDepartureSuffix(suffix); + } + model.setDepartureSuffix(suffix); + } + + public boolean isReverseArrival() { + return model.isReverseArrival(); + } + + public void setReverseArrival(boolean reverseArrival) { + if (blockBean != null) { + blockBean.setReverseArrival(reverseArrival); + } + model.setReverseArrival(reverseArrival); + } + + public LocomotiveBean.Direction getLogicalDirection() { + return model.getLogicalDirection(); + } + + public void setLogicalDirection(LocomotiveBean.Direction logicalDirection) { + if (blockBean != null) { + blockBean.setLogicalDirection(logicalDirection.getDirection()); + } + model.setLogicalDirection(logicalDirection); + } + + public LocomotiveBean getLocomotive() { + return model.getLocomotive(); + } + + public void setLocomotive(LocomotiveBean locomotive) { + if (blockBean != null) { + blockBean.setLocomotive(locomotive); + model.setOverlayImage(locomotive != null && locomotive.getLocIcon() != null && (model.getBlockState() == BlockState.OCCUPIED || model.getBlockState() == BlockState.INBOUND || model.getBlockState() == BlockState.OUTBOUND)); + } + + model.setLocomotive(locomotive); + } + + public AccessoryBean getAccessoryBean() { + return accessoryBean; + } + + public void setAccessoryBean(AccessoryBean accessoryBean) { + this.accessoryBean = accessoryBean; + + if (accessoryBean != null) { + accessoryId = accessoryBean.getId(); + signalValue = accessoryBean.getSignalValue(); + signalType = SignalType.getSignalType(accessoryBean.getType()); + } else { + accessoryId = null; + signalType = SignalType.NONE; + signalValue = AccessoryBean.SignalValue.OFF; + } + } + + public AccessoryValue getAccessoryValue() { + if (this.accessoryValue == null) { + return AccessoryValue.OFF; + } else { + return accessoryValue; + } + } + + public void setAccessoryValue(AccessoryValue value) { + this.accessoryValue = value; + repaint(); + } + + public AccessoryValue getRouteValue() { + if (routeValue == null) { + return AccessoryValue.OFF; + } else { + return routeValue; + } + } + + public void setRouteValue(AccessoryValue value) { + this.routeValue = value; + repaint(); + } + + public AccessoryBean.SignalValue getSignalValue() { + return signalValue; + } + + public void setSignalValue(AccessoryBean.SignalValue signalValue) { + this.signalValue = signalValue; + repaint(); + } + + public SensorBean getSensorBean() { + return sensorBean; + } + + public void setSensorBean(SensorBean sensorBean) { + this.sensorBean = sensorBean; + } + + public BlockBean getBlockBean() { + return blockBean; + } + + public void setBlockBean(BlockBean blockBean) { + this.blockBean = blockBean; + } + + public void setRenderWidth(int renderWidth) { + this.renderWidth = renderWidth; + } + + public void setRenderHeight(int renderHeight) { + this.renderHeight = renderHeight; + } + + public int getRenderOffsetX() { + return renderOffsetX; + } + + public void setRenderOffsetX(int renderOffsetX) { + this.renderOffsetX = renderOffsetX; + } + + public int getRenderOffsetY() { + return renderOffsetY; + } + + public void setRenderOffsetY(int renderOffsetY) { + this.renderOffsetY = renderOffsetY; + } + + public TileBean.TileType getTileType() { + return this.tileType; + } + + public final void setTileType(TileType tileType) { + this.tileType = tileType; + } + + public Color getTrackColor() { + return trackColor; + } + + public final void setTrackColor(Color trackColor) { + this.trackColor = trackColor; + } + + public Color getTrackRouteColor() { + return trackRouteColor; + } + + public void setTrackRouteColor(Color trackRouteColor) { + this.trackRouteColor = trackRouteColor; + } + + public Color getSelectedColor() { + return model.getSelectedColor(); + } + + public void setSelectedColor(Color selectedColor) { + this.model.setSelectedColor(selectedColor); + } + + public Orientation getIncomingSide() { + return incomingSide; + } + + public void setIncomingSide(Orientation incomingSide) { + this.incomingSide = incomingSide; + } + + public Color getBackgroundColor() { + return backgroundColor; + } + + public void setBackgroundColor(Color backgroundColor) { + this.backgroundColor = backgroundColor; + } + + public boolean isDrawRoute() { + return model.isShowRoute(); + } + + public void setDrawRoute(boolean drawRoute) { + this.model.setShowRoute(drawRoute); + } + + public int getRenderWidth() { + return renderWidth; + } + + public int getRenderHeight() { + return renderHeight; + } + + abstract void renderTile(Graphics2D g2d); + + abstract void renderTileRoute(Graphics2D g2d); + + public abstract Map getNeighborPoints(); + + public abstract Map getEdgePoints(); + + //public abstract Set getAllPoints(); + //public abstract Set getAllPoints(Point center); + //public abstract Set getAltPoints(Point center); + Set getAltPoints(Point center) { + return Collections.EMPTY_SET; + } + + public Set getAllPoints() { + return getAllPoints(getCenter()); + } + + Set getAllPoints(Point center) { + Set aps = new HashSet<>(); + aps.add(center); + return aps; + } + + /** + * Draw the Tile + * + * @param g2d The graphics handle + */ + public void drawTile(Graphics2D g2d) { + // by default and image is rendered in the EAST orientation + Orientation tileOrientation = model.getTileOrienation(); + + BufferedImage bf = createImage(); + Graphics2D g2di = bf.createGraphics(); + + //Avoid errors + if (model.isShowRoute() && incomingSide == null) { + incomingSide = getOrientation(); + } + + if (model.isSelected()) { + g2di.setBackground(model.getSelectedColor()); + } else { + g2di.setBackground(backgroundColor); + } + + g2di.clearRect(0, 0, renderWidth, renderHeight); + int ox = 0, oy = 0; + + AffineTransform trans = new AffineTransform(); + switch (tileOrientation) { + case SOUTH -> { + trans.rotate(Math.PI / 2, renderWidth / 2, renderHeight / 2); + ox = (renderHeight - renderWidth) / 2; + oy = (renderWidth - renderHeight) / 2; + trans.translate(-ox, -oy); + } + case WEST -> { + trans.rotate(Math.PI, renderWidth / 2, renderHeight / 2); + trans.translate(ox, oy); + } + case NORTH -> { + trans.rotate(-Math.PI / 2, renderWidth / 2, renderHeight / 2); + ox = (renderHeight - renderWidth) / 2; + oy = (renderWidth - renderHeight) / 2; + trans.translate(-ox, -oy); + } + default -> { + trans.rotate(0.0, this.renderWidth / 2, this.renderHeight / 2); + trans.translate(ox, oy); + } + } + + //Logger.trace(tileOrientation.getOrientation() + " renderWidth: " + renderWidth + " renderHeight: " + renderHeight + " CP: (" + renderWidth / 2 + "," + renderHeight / 2 + ")"); + //Logger.trace(tileOrientation.getOrientation() + " ox: " + ox + " oy: " + oy); + g2di.setTransform(trans); + + renderTile(g2di); + + if (model.isShowRoute()) { + renderTileRoute(g2di); + } + + if (model.isShowCenter()) { + drawCenterPoint(g2di); + } + + // Scale the image back... + if (model.isScaleImage()) { + tileImage = Scalr.resize(bf, Method.AUTOMATIC, Mode.FIT_EXACT, getWidth(), getHeight(), Scalr.OP_ANTIALIAS); + } else { + tileImage = bf; + } + g2di.dispose(); + } + + public BufferedImage getTileImage() { + return tileImage; + } + + /** + * Render a tile image Always starts at (0,0) used the default width and height + * + * @param g2 the Graphic context + */ + public void drawName(Graphics2D g2) { + } + + protected void drawCenterPoint(Graphics2D g2d) { + drawCenterPoint(g2d, Color.magenta); + } + + protected void drawCenterPoint(Graphics2D g2, Color color) { + drawCenterPoint(g2, color, 60); + } + + protected void drawCenterPoint(Graphics2D g2d, Color color, double size) { + double dX = (renderWidth / 2 - size / 2); + double dY = (renderHeight / 2 - size / 2); + + g2d.setColor(color); + g2d.fill(new Ellipse2D.Double(dX, dY, size, size)); + } + + /** + * Rotate the tile clockwise 90 deg + * + * @return the new Orientation + */ + public Orientation rotate() { + Orientation tileOrientation = model.getTileOrienation(); + switch (tileOrientation) { + case EAST -> + setOrientation(Orientation.SOUTH); + case SOUTH -> + setOrientation(Orientation.WEST); + case WEST -> + setOrientation(Orientation.NORTH); + default -> + setOrientation(Orientation.EAST); + } + return model.getTileOrienation(); + } + + public void flipHorizontal() { + Orientation tileOrientation = model.getTileOrienation(); + if (Orientation.NORTH == tileOrientation || Orientation.SOUTH == tileOrientation) { + rotate(); + rotate(); + } + } + + public void flipVertical() { + Orientation tileOrientation = model.getTileOrienation(); + if (Orientation.EAST == tileOrientation || Orientation.WEST == tileOrientation) { + rotate(); + rotate(); + } + } + + @Override + public void move(int newX, int newY) { + Point cs = LayoutUtil.snapToGrid(newX, newY); + setCenter(cs); + } + + protected static void drawRotate(Graphics2D g2d, double x, double y, int angle, String text) { + g2d.translate((float) x, (float) y); + g2d.rotate(Math.toRadians(angle)); + g2d.drawString(text, 0, 0); + g2d.rotate(-Math.toRadians(angle)); + g2d.translate(-x, -y); + } + + public static BufferedImage flipHorizontally(BufferedImage source) { + BufferedImage output = new BufferedImage(source.getHeight(), source.getWidth(), source.getType()); + + AffineTransform flip = AffineTransform.getScaleInstance(1, -1); + flip.translate(0, -source.getHeight()); + AffineTransformOp op = new AffineTransformOp(flip, AffineTransformOp.TYPE_NEAREST_NEIGHBOR); + + op.filter(source, output); + + return output; + } + + public static BufferedImage flipVertically(BufferedImage source) { + BufferedImage output = new BufferedImage(source.getHeight(), source.getWidth(), source.getType()); + + AffineTransform flip = AffineTransform.getScaleInstance(-1, 1); + flip.translate(-source.getWidth(), 0); + AffineTransformOp op = new AffineTransformOp(flip, AffineTransformOp.TYPE_NEAREST_NEIGHBOR); + + op.filter(source, output); + + return output; + } + + public Set getAltPoints() { + return Collections.EMPTY_SET; + } + + public final int getOffsetX() { + return offsetX; + } + + public void setOffsetX(int offsetX) { + this.offsetX = offsetX; + } + + public final int getOffsetY() { + return offsetY; + } + + public void setOffsetY(int offsetY) { + this.offsetY = offsetY; + } + + protected BufferedImage createImage() { + return new BufferedImage(renderWidth, renderHeight, BufferedImage.TYPE_INT_RGB); + } + + public int getCenterX() { + if (tileX > 0) { + return this.tileX; + } else { + return GRID; + } + } + + public int getCenterY() { + if (tileY > 0) { + return this.tileY; + } else { + return GRID; + } + } + + public boolean isDrawName() { + return drawName; + } + + public void setDrawName(boolean drawName) { + this.drawName = drawName; + } + + public boolean isScaleImage() { + return model.isScaleImage(); + } + + public void setScaleImage(boolean scaleImage) { + Dimension d; + if (scaleImage) { + d = new Dimension(DEFAULT_WIDTH, DEFAULT_HEIGHT); + } else { + d = new Dimension(renderWidth, renderHeight); + } + + setSize(d); + setPreferredSize(d); + + model.setScaleImage(scaleImage); + } + + public boolean isDrawCenterPoint() { + return model.isShowCenter(); + } + + public void setDrawCenterPoint(boolean drawCenterPoint) { + model.setShowCenter(drawCenterPoint); + } + + @Override + public String toString() { + return this.getClass().getSimpleName() + + " {id: " + + this.id + + ", orientation: " + + getOrientation() + + ", direction: " + + getDirection() + + ", center: " + + xyToString() + + "}"; + } + + public String xyToString() { + return "(" + this.tileX + "," + this.tileY + ")"; + } + + /** + * The main route of the tile is horizontal + * + * @return true when main route goes from East to West or vv + */ + public boolean isHorizontal() { + Orientation tileOrientation = model.getTileOrienation(); + return (Orientation.EAST == tileOrientation || Orientation.WEST == tileOrientation) && TileType.CURVED != tileType; + } + + /** + * The main route of the tile is vertical + * + * @return true when main route goes from North to South or vv + */ + public boolean isVertical() { + Orientation tileOrientation = model.getTileOrienation(); + return (Orientation.NORTH == tileOrientation || Orientation.SOUTH == tileOrientation) && TileType.CURVED != tileType; + } + + public boolean isJunction() { + return TileType.SWITCH == tileType || TileType.CROSS == tileType; + } + + public boolean isBlock() { + return TileType.BLOCK == tileType; + } + + public boolean isDirectional() { + return TileType.STRAIGHT_DIR == tileType; + } + + /** + * The main route of the tile is diagonal + * + * @return true when main route goes from North to East or West to South and vv + */ + public boolean isDiagonal() { + return TileType.CURVED == tileType; + } + + public boolean isCrossing() { + return TileType.CROSSING == tileType; + } + + public List getNeighbours() { + return neighbours; + } + + public void setNeighbours(List neighbours) { + this.neighbours = neighbours; + } + + public String getIdSuffix(Tile other) { + return ""; + } + + public Map getNeighborOrientations() { + Map edgeOrientations = new HashMap<>(); + + Map neighborPoints = getNeighborPoints(); + + for (Orientation o : Orientation.values()) { + edgeOrientations.put(neighborPoints.get(o), o); + } + return edgeOrientations; + } + + public Map getEdgeOrientations() { + Map edgeOrientations = new HashMap<>(); + + Map edgeConnections = getEdgePoints(); + + for (Orientation o : Orientation.values()) { + edgeOrientations.put(edgeConnections.get(o), o); + } + return edgeOrientations; + } + + public boolean isAdjacent(Tile other) { + boolean adjacent = false; + + if (other != null) { + Collection thisEdgePoints = getEdgePoints().values(); + Collection otherEdgePoints = other.getEdgePoints().values(); + + for (Point p : thisEdgePoints) { + adjacent = otherEdgePoints.contains(p); + if (adjacent) { + break; + } + } + } + + return adjacent; + } + + /** + * When the tile has a specific direction a train may travel,
+ * then this method will indicate whether the other tile is in on the side where the arrow is pointing to. + * + * @param other A Tile + * @return true where other is on the side of this tile where the arrow points to + */ + public boolean isArrowDirection(Tile other) { + return true; + } + + public AccessoryValue accessoryValueForRoute(Orientation from, Orientation to) { + return AccessoryValue.OFF; + } + + public TileModel getModel() { + return model; + } + + public void setModel(TileModel newModel) { + TileModel oldModel = getModel(); + + if (oldModel != null) { + oldModel.removeChangeListener(changeListener); + oldModel.removeActionListener(actionListener); + changeListener = null; + actionListener = null; + } + + model = newModel; + + if (newModel != null) { + changeListener = createChangeListener(); + actionListener = createActionListener(); + + newModel.addChangeListener(changeListener); + newModel.addActionListener(actionListener); + } + + firePropertyChange(MODEL_CHANGED_PROPERTY, oldModel, newModel); + if (newModel != oldModel) { + revalidate(); + repaint(); + } + } + +// public TileUI getUI() { +// return (TileUI) ui; +// } +// public void setUI(TileUI ui) { +// super.setUI(ui); +// } + @Override + public void updateUI() { + } + + protected ChangeListener createChangeListener() { + return getHandler(); + } + + protected ActionListener createActionListener() { + return getHandler(); + } + + private Handler getHandler() { + if (handler == null) { + handler = new Handler(); + } + return handler; + } + + class Handler implements ActionListener, ChangeListener, Serializable { + + @Override + public void stateChanged(ChangeEvent e) { + //Object source = e.getSource(); + + fireStateChanged(); + repaint(); + } + + @Override + public void actionPerformed(ActionEvent event) { + fireActionPerformed(event); + } + } + + protected void fireStateChanged() { + Object[] listeners = listenerList.getListenerList(); + //reverse order + for (int i = listeners.length - 2; i >= 0; i -= 2) { + if (listeners[i] == ChangeListener.class) { + // Lazily create the event: + if (changeEvent == null) { + changeEvent = new ChangeEvent(this); + } + ((ChangeListener) listeners[i + 1]).stateChanged(changeEvent); + } + } + } + + protected void fireActionPerformed(ActionEvent event) { + Object[] listeners = listenerList.getListenerList(); + ActionEvent e = null; + // reverse + for (int i = listeners.length - 2; i >= 0; i -= 2) { + if (listeners[i] == ActionListener.class) { + // Lazily create the event: + if (e == null) { + String actionCommand = event.getActionCommand(); + //if(actionCommand == null) { + // actionCommand = getActionCommand(); + //} + e = new ActionEvent(Tile.this, ActionEvent.ACTION_PERFORMED, actionCommand, event.getWhen(), event.getModifiers()); + } + ((ActionListener) listeners[i + 1]).actionPerformed(e); + } + } + } + + public Rectangle getTileBounds() { + if (model.isScaleImage()) { + return new Rectangle(tileX - GRID, tileY - GRID, DEFAULT_WIDTH, DEFAULT_HEIGHT); + } else { + return new Rectangle(tileX - renderWidth / 2, tileY - renderHeight / 2, renderWidth, renderHeight); + } + } + + @Override + protected void paintComponent(Graphics g) { + long started = System.currentTimeMillis(); + + Graphics2D g2 = (Graphics2D) g.create(); + //Graphics2D g2 = (Graphics2D) g.create(tileX - GRID, tileY - GRID, DEFAULT_WIDTH, DEFAULT_HEIGHT); + drawTile(g2); + g2.dispose(); + + g.drawImage(tileImage, 0, 0, null); + + long now = System.currentTimeMillis(); + Logger.trace(id + " Duration: " + (now - started) + " ms. Cp: " + xyToString() + " O: " + model.getTileOrienation()); + } + +} diff --git a/src/main/java/jcs/ui/layout/tiles/TileCache.java b/src/main/java/jcs/ui/layout/tiles/TileCache.java index 2716f298..3d32de97 100644 --- a/src/main/java/jcs/ui/layout/tiles/TileCache.java +++ b/src/main/java/jcs/ui/layout/tiles/TileCache.java @@ -1 +1,403 @@ -/* * Copyright 2025 Frans Jacobs. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package jcs.ui.layout.tiles; import java.awt.Point; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Set; import java.util.stream.Collectors; import jcs.entities.AccessoryBean.AccessoryValue; import jcs.entities.AccessoryBean.SignalValue; import jcs.entities.TileBean; import jcs.entities.TileBean.Orientation; import static jcs.entities.TileBean.Orientation.EAST; import static jcs.entities.TileBean.Orientation.SOUTH; import static jcs.entities.TileBean.Orientation.WEST; import jcs.entities.TileBean.TileType; import static jcs.entities.TileBean.TileType.BLOCK; import static jcs.entities.TileBean.TileType.CROSS; import static jcs.entities.TileBean.TileType.SENSOR; import static jcs.entities.TileBean.TileType.SIGNAL; import jcs.persistence.PersistenceFactory; import jcs.ui.layout.events.TileEvent; import jcs.ui.layout.events.TileEventListener; import org.tinylog.Logger; /** * Factory object to create Tiles and cache tiles * * @author frans */ public class TileCache { //private static final Map tileEventListeners = new HashMap<>(); private static boolean showValues; static final Map tiles = new HashMap<>(); static final Map tileAltPoints = new HashMap<>(); static final Map points = new HashMap<>(); //static final Map altTiles = new HashMap<>(); private TileCache() { } @Deprecated public static void setShowValues(boolean showValues) { TileCache.showValues = showValues; for (Tile tile : tiles.values()) { TileType tileType = tile.getTileType(); switch (tileType) { case SWITCH -> { if (showValues && ((Switch) tile).getTileBean().getAccessoryBean() != null) { tile.setAccessoryValue(tile.getTileBean().getAccessoryBean().getAccessoryValue()); } else { tile.setAccessoryValue(AccessoryValue.OFF); } } case CROSS -> { if (showValues && ((Cross) tile).getTileBean().getAccessoryBean() != null) { tile.setAccessoryValue(tile.getTileBean().getAccessoryBean().getAccessoryValue()); } else { tile.setAccessoryValue(AccessoryValue.OFF); } } case SIGNAL -> { if (showValues && ((Signal) tile).getTileBean().getAccessoryBean() != null) { tile.setSignalValue(tile.getTileBean().getAccessoryBean().getSignalValue()); } else { tile.setSignalValue(SignalValue.OFF); } } case SENSOR -> { if (showValues && ((Sensor) tile).getTileBean().getSensorBean() != null) { tile.setActive(tile.getTileBean().getSensorBean().isActive()); } else { tile.setActive(false); } } case BLOCK -> { } } } } public static List loadTiles() { tileAltPoints.clear(); points.clear(); tiles.clear(); List tileBeans = PersistenceFactory.getService().getTileBeans(); for (TileBean tb : tileBeans) { Tile tile = TileFactory.createTile(tb, showValues); tiles.put(tile.getCenter(), tile); points.put(tile.getId(), tile.getCenter()); //Alternative point(s) to be able to find all points if (!tile.getAltPoints().isEmpty()) { Set alt = tile.getAltPoints(); for (Point ap : alt) { tileAltPoints.put(ap, tile); } } } Logger.trace("Loaded " + tiles.size() + " Tiles..."); return tiles.values().stream().collect(Collectors.toList()); } public static List getTiles() { return tiles.values().stream().collect(Collectors.toList()); } public static void addAndSaveTile(Tile tile) { tiles.put(tile.getCenter(), tile); points.put(tile.getId(), tile.getCenter()); //Alternative point(s) to be able to find all points if (!tile.getAltPoints().isEmpty()) { Set alt = tile.getAltPoints(); for (Point ap : alt) { tileAltPoints.put(ap, tile); } } saveTile(tile); Logger.trace("Added " + tile + " There are now " + tiles.size() + " tiles..."); } public static void saveTile(final Tile tile) { if (tile != null) { TileBean tb = tile.getTileBean(); PersistenceFactory.getService().persist(tb); } else { Logger.warn("Tile is null?"); } } public static void saveTiles() { for (Tile tile : tiles.values()) { saveTile(tile); } } public static void deleteTile(final Tile tile) { if (tile != null) { if (tiles.containsKey(tile.getCenter())) { Set rps = tile.getAltPoints(); //Also remove alt points for (Point ap : rps) { tileAltPoints.remove(ap); } points.remove(tile.getId()); tiles.remove(tile.getCenter()); TileBean tb = tile.getTileBean(); PersistenceFactory.getService().remove(tb); Logger.trace("Deleted " + tile.getId()); } else { Logger.warn("Tile " + tile.getId() + " not found in cache"); } } else { Logger.warn("Tile is null?"); } } public static Tile findTile(Point cp) { Tile result = tiles.get(cp); if (result == null) { result = tileAltPoints.get(cp); } return result; } public static Tile findTile(String id) { Point p = points.get(id); if (p != null) { return findTile(p); } else { return null; } } public static boolean canMoveTo(Tile tile, Point p) { //check if a tile exist with point p Logger.trace("Checking " + tile.id + " New Point (" + p.x + "," + p.y + ")"); if (tiles.containsKey(p) && !tile.getCenter().equals(p) && !tile.getAltPoints().contains(p)) { return false; } if (tileAltPoints.containsKey(p) && !tile.getAltPoints().contains(p)) { return false; } //Check with the tile new alt points if these are also free... Set altPoints = tile.getAltPoints(p); Logger.trace("Checking " + tile.id + " on " + altPoints.size() + " alt points..."); for (Point ap : altPoints) { Logger.trace("Checking " + tile.id + " New Alt Point (" + ap.x + "," + ap.y + ")"); if (tiles.containsKey(ap) && !tile.getCenter().equals(ap) && !tile.getAltPoints().contains(ap)) { return false; } if (tileAltPoints.containsKey(ap) && !tile.getAltPoints().contains(ap)) { return false; } } Logger.trace("Checking " + tile.id + " can move to (" + p.x + "," + p.y + ")"); return true; } public static void moveTo(Tile tile, Point p) { if (canMoveTo(tile, p)) { Logger.trace("Moving tile " + tile.getId() + " from " + tile.xyToString() + " to (" + p.x + "," + p.y + ")"); Set rps = tile.getAltPoints(); //remove alt points for (Point ap : rps) { tileAltPoints.remove(ap); } points.remove(tile.getId()); tiles.remove(tile.getCenter()); tile.setCenter(p); addAndSaveTile(tile); } else { Tile occ = findTile(p); Logger.trace("Can't Move tile " + tile.id + " from " + tile.xyToString() + " to (" + p.x + "," + p.y + ") Is occupied by " + occ.id); } } @Deprecated public static boolean checkTileOccupation(Tile tile) { Set tilePoints = tile.getAllPoints(); for (Point p : tilePoints) { if (tiles.containsKey(p) || tileAltPoints.containsKey(p)) { //The is a match, check if it is an other tile Tile mt = findTile(p); if (tile.getId().equals(mt.getId())) { //same tile continue } else { //Other tile so really occupied return true; } } } return false; } @Deprecated public static boolean containsPoint(Set points) { for (Point p : points) { return tiles.containsKey(p) || tileAltPoints.containsKey(p); } return false; } public static boolean containsPoint(Point point) { return tiles.containsKey(point) || tileAltPoints.containsKey(point); } @Deprecated public static Point checkAvailable(Point newPoint, Orientation orientation) { if (tiles.containsKey(newPoint)) { Tile et = tiles.get(newPoint); Logger.trace("@ " + newPoint + " is allready occcupied by: " + et + "..."); //Search for the nearest avalaible free point //first get the Center point of the tile which is occuping this slot // show warning! Point ecp = et.getCenter(); int w = et.getWidth(); int h = et.getHeight(); Point np; np = switch (orientation) { case EAST -> new Point(ecp.x + w, ecp.y); case WEST -> new Point(newPoint.x - w, ecp.y); case SOUTH -> new Point(ecp.x, newPoint.y + h); default -> new Point(ecp.x, newPoint.y - h); }; Logger.trace("Alternative CP: " + np); // recursive check return checkAvailable(np, orientation); } else { Logger.trace("@ " + newPoint + " is not yet used..."); return newPoint; } } public static Tile rotateTile(Tile tile) { if (!tiles.containsKey(tile.getCenter())) { Logger.warn("Tile " + tile.getId() + " NOT in cache!"); } //Remove the alternative or extra points... for (Point ep : tile.getAltPoints()) { tileAltPoints.remove(ep); } tile.rotate(); //update tiles.put(tile.getCenter(), tile); for (Point ep : tile.getAltPoints()) { tileAltPoints.put(ep, tile); } saveTile(tile); return tile; } public static Tile flipHorizontal(Tile tile) { return flipTile(tile, true); } public static Tile flipVertical(Tile tile) { return flipTile(tile, false); } private static Tile flipTile(Tile tile, boolean horizontal) { if (!tiles.containsKey(tile.getCenter())) { Logger.warn("Tile " + tile.getId() + " NOT in cache!"); } //Remove the alternative or extra points... for (Point ep : tile.getAltPoints()) { tileAltPoints.remove(ep); } if (horizontal) { tile.flipHorizontal(); } else { tile.flipVertical(); } //update tiles.put(tile.getCenter(), tile); for (Point ep : tile.getAltPoints()) { tileAltPoints.put(ep, tile); } saveTile(tile); return tile; } @Deprecated public static void addTileEventListener(TileEventListener listener) { String key = listener.getId(); //tileEventListeners.put(key, listener); } @Deprecated public static void removeTileEventListener(Tile tile) { if (tile instanceof TileEventListener tileEventListener) { removeTileEventListener(tileEventListener); } } static void removeTileEventListener(TileEventListener listener) { String key = listener.getId(); //tileEventListeners.remove(key, listener); } @Deprecated public static void fireTileEventListener(TileEvent tileEvent) { // String key = tileEvent.getTileId(); // TileEventListener listener = tileEventListeners.get(key); // if (listener != null) { // listener.onTileChange(tileEvent); // Logger.trace("Fire listener on tile " + key); // } else { // //Logger.trace("Tile " + key + " not available"); // } } @Deprecated public static void fireAllTileEventListeners(TileEvent tileEvent) { // for (TileEventListener listener : tileEventListeners.values()) { // listener.onTileChange(tileEvent); // } } } \ No newline at end of file +/* + * Copyright 2025 Frans Jacobs. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package jcs.ui.layout.tiles; + +import java.awt.Point; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.stream.Collector; +import java.util.stream.Collectors; +import jcs.entities.AccessoryBean.AccessoryValue; +import jcs.entities.AccessoryBean.SignalValue; +import jcs.entities.TileBean; +import jcs.entities.TileBean.Orientation; +import static jcs.entities.TileBean.Orientation.EAST; +import static jcs.entities.TileBean.Orientation.SOUTH; +import static jcs.entities.TileBean.Orientation.WEST; +import jcs.entities.TileBean.TileType; +import static jcs.entities.TileBean.TileType.BLOCK; +import static jcs.entities.TileBean.TileType.CROSS; +import static jcs.entities.TileBean.TileType.SENSOR; +import static jcs.entities.TileBean.TileType.SIGNAL; +import jcs.persistence.PersistenceFactory; +import jcs.ui.layout.events.TileEvent; +import jcs.ui.layout.events.TileEventListener; +import org.tinylog.Logger; + +/** + * Factory object to create Tiles and cache tiles + * + * @author frans + */ +public class TileCache { + + //private static final Map tileEventListeners = new HashMap<>(); + private static boolean showValues; + + static final Map tiles = new HashMap<>(); + static final Map tileAltPoints = new HashMap<>(); + static final Map points = new HashMap<>(); + //static final Map altTiles = new HashMap<>(); + + private TileCache() { + } + + @Deprecated + public static void setShowValues(boolean showValues) { + TileCache.showValues = showValues; + + for (Tile tile : tiles.values()) { + TileType tileType = tile.getTileType(); + switch (tileType) { + case SWITCH -> { + if (showValues && ((Switch) tile).getTileBean().getAccessoryBean() != null) { + tile.setAccessoryValue(tile.getTileBean().getAccessoryBean().getAccessoryValue()); + } else { + tile.setAccessoryValue(AccessoryValue.OFF); + } + } + case CROSS -> { + if (showValues && ((Cross) tile).getTileBean().getAccessoryBean() != null) { + tile.setAccessoryValue(tile.getTileBean().getAccessoryBean().getAccessoryValue()); + } else { + tile.setAccessoryValue(AccessoryValue.OFF); + } + } + case SIGNAL -> { + if (showValues && ((Signal) tile).getTileBean().getAccessoryBean() != null) { + tile.setSignalValue(tile.getTileBean().getAccessoryBean().getSignalValue()); + } else { + tile.setSignalValue(SignalValue.OFF); + } + } + case SENSOR -> { + if (showValues && ((Sensor) tile).getTileBean().getSensorBean() != null) { + tile.setActive(tile.getTileBean().getSensorBean().isActive()); + } else { + tile.setActive(false); + } + } + case BLOCK -> { + } + } + } + } + + public static List loadTiles() { + tileAltPoints.clear(); + points.clear(); + tiles.clear(); + + List tileBeans = PersistenceFactory.getService().getTileBeans(); + + for (TileBean tb : tileBeans) { + Tile tile = TileFactory.createTile(tb, showValues); + tiles.put(tile.getCenter(), tile); + points.put(tile.getId(), tile.getCenter()); + //Alternative point(s) to be able to find all points + if (!tile.getAltPoints().isEmpty()) { + Set alt = tile.getAltPoints(); + for (Point ap : alt) { + tileAltPoints.put(ap, tile); + } + } + } + + Logger.trace("Loaded " + tiles.size() + " Tiles..."); + return tiles.values().stream().collect(Collectors.toList()); + } + + public static List getTiles() { + return tiles.values().stream().collect(Collectors.toList()); + } + + public static Tile addAndSaveTile(Tile tile) { + tiles.put(tile.getCenter(), tile); + points.put(tile.getId(), tile.getCenter()); + + //Alternative point(s) to be able to find all points + if (!tile.getAltPoints().isEmpty()) { + Set alt = tile.getAltPoints(); + for (Point ap : alt) { + tileAltPoints.put(ap, tile); + } + } + + saveTile(tile); + //Logger.trace("Added " + tile + " There are now " + tiles.size() + " tiles..."); + return tile; + } + + public static void saveTile(final Tile tile) { + if (tile != null) { + TileBean tb = tile.getTileBean(); + PersistenceFactory.getService().persist(tb); + } else { + Logger.warn("Tile is null?"); + } + } + + public static void saveTiles() { + for (Tile tile : tiles.values()) { + saveTile(tile); + } + } + + public static void deleteTile(final Tile tile) { + if (tile != null) { + if (tiles.containsKey(tile.getCenter())) { + Set rps = tile.getAltPoints(); + //Also remove alt points + for (Point ap : rps) { + tileAltPoints.remove(ap); + } + points.remove(tile.getId()); + tiles.remove(tile.getCenter()); + + TileBean tb = tile.getTileBean(); + PersistenceFactory.getService().remove(tb); + Logger.trace("Deleted " + tile.getId()); + } else { + Logger.warn("Tile " + tile.getId() + " not found in cache"); + } + } else { + Logger.warn("Tile is null?"); + } + } + + public static Tile findTile(Point cp) { + Tile result = tiles.get(cp); + if (result == null) { + result = tileAltPoints.get(cp); + } + return result; + } + + public static Tile findTile(String id) { + Point p = points.get(id); + if (p != null) { + return findTile(p); + } else { + return null; + } + } + + public static boolean canMoveTo(Tile tile, Point p) { + //check if a tile exist with point p + //Check if the cache contains a Cp of a tile on p + //Logger.trace("Checking " + tile.id + " New Point (" + p.x + "," + p.y + ")"); + if (tiles.containsKey(p) && !tile.getCenter().equals(p) && !tile.getAltPoints().contains(p)) { + return false; + } + //Check if the cache contains a Cp on any of the Alt point is case of a Block or Cross + if (tileAltPoints.containsKey(p) && !tile.getAltPoints().contains(p)) { + return false; + } + + //Check with the tile on the new Cp with the new alt points if that is also free... + Set altPoints = tile.getAltPoints(p); + for (Point ap : altPoints) { + if (tiles.containsKey(ap) && !tile.getCenter().equals(ap) && !tile.getAltPoints().contains(ap)) { + return false; + } + if (tileAltPoints.containsKey(ap) && !tile.getAltPoints().contains(ap)) { + return false; + } + } + //Logger.trace("Checked " + tile.id + " can move to (" + p.x + "," + p.y + ")"); + return true; + } + + public static void moveTo(Tile tile, Point p) { + if (canMoveTo(tile, p)) { + //Logger.trace("Moving " + tile.getId() + " from " + tile.xyToString() + " to (" + p.x + "," + p.y + ")"); + Set rps = tile.getAltPoints(); + //remove alt points + for (Point ap : rps) { + tileAltPoints.remove(ap); + } + points.remove(tile.getId()); + tiles.remove(tile.getCenter()); + + tile.setCenter(p); + Tile t = addAndSaveTile(tile); + //Logger.trace("Moved " + t.id + " to " + t.xyToString()); + } else { + Tile occ = findTile(p); + Logger.trace("Can't Move tile " + tile.id + " from " + tile.xyToString() + " to (" + p.x + "," + p.y + ") Is occupied by " + occ.id); + } + } + + @Deprecated + public static boolean checkTileOccupation(Tile tile) { + Set tilePoints = tile.getAllPoints(); + for (Point p : tilePoints) { + if (tiles.containsKey(p) || tileAltPoints.containsKey(p)) { + //The is a match, check if it is an other tile + Tile mt = findTile(p); + if (tile.getId().equals(mt.getId())) { + //same tile continue + } else { + //Other tile so really occupied + return true; + } + } + } + return false; + } + + @Deprecated + public static boolean containsPoint(Set points) { + for (Point p : points) { + return tiles.containsKey(p) || tileAltPoints.containsKey(p); + } + return false; + } + + public static boolean containsPoint(Point point) { + return tiles.containsKey(point) || tileAltPoints.containsKey(point); + } + + @Deprecated + public static Point checkAvailable(Point newPoint, Orientation orientation) { + if (tiles.containsKey(newPoint)) { + Tile et = tiles.get(newPoint); + Logger.trace("@ " + newPoint + " is allready occcupied by: " + et + "..."); + //Search for the nearest avalaible free point + //first get the Center point of the tile which is occuping this slot + // show warning! + Point ecp = et.getCenter(); + + int w = et.getWidth(); + int h = et.getHeight(); + + Point np; + np = switch (orientation) { + case EAST -> + new Point(ecp.x + w, ecp.y); + case WEST -> + new Point(newPoint.x - w, ecp.y); + case SOUTH -> + new Point(ecp.x, newPoint.y + h); + default -> + new Point(ecp.x, newPoint.y - h); + }; + + Logger.trace("Alternative CP: " + np); + // recursive check + return checkAvailable(np, orientation); + } else { + Logger.trace("@ " + newPoint + " is not yet used..."); + + return newPoint; + } + } + + public static Tile rotateTile(Tile tile) { + if (!tiles.containsKey(tile.getCenter())) { + Logger.warn("Tile " + tile.getId() + " NOT in cache!"); + } + + //Remove the alternative or extra points... + for (Point ep : tile.getAltPoints()) { + tileAltPoints.remove(ep); + } + + tile.rotate(); + + //update + tiles.put(tile.getCenter(), tile); + for (Point ep : tile.getAltPoints()) { + tileAltPoints.put(ep, tile); + } + + saveTile(tile); + return tile; + } + + public static Tile flipHorizontal(Tile tile) { + return flipTile(tile, true); + } + + public static Tile flipVertical(Tile tile) { + return flipTile(tile, false); + } + + private static Tile flipTile(Tile tile, boolean horizontal) { + if (!tiles.containsKey(tile.getCenter())) { + Logger.warn("Tile " + tile.getId() + " NOT in cache!"); + } + + //Remove the alternative or extra points... + for (Point ep : tile.getAltPoints()) { + tileAltPoints.remove(ep); + } + + if (horizontal) { + tile.flipHorizontal(); + } else { + tile.flipVertical(); + } + //update + tiles.put(tile.getCenter(), tile); + for (Point ep : tile.getAltPoints()) { + tileAltPoints.put(ep, tile); + } + + saveTile(tile); + return tile; + } + + @Deprecated + public static void addTileEventListener(TileEventListener listener) { + String key = listener.getId(); + //tileEventListeners.put(key, listener); + } + + @Deprecated + public static void removeTileEventListener(Tile tile) { + if (tile instanceof TileEventListener tileEventListener) { + removeTileEventListener(tileEventListener); + } + } + + static void removeTileEventListener(TileEventListener listener) { + String key = listener.getId(); + //tileEventListeners.remove(key, listener); + } + + @Deprecated + public static void fireTileEventListener(TileEvent tileEvent) { +// String key = tileEvent.getTileId(); +// TileEventListener listener = tileEventListeners.get(key); +// if (listener != null) { +// listener.onTileChange(tileEvent); +// Logger.trace("Fire listener on tile " + key); +// } else { +// //Logger.trace("Tile " + key + " not available"); +// } + } + + @Deprecated + public static void fireAllTileEventListeners(TileEvent tileEvent) { +// for (TileEventListener listener : tileEventListeners.values()) { +// listener.onTileChange(tileEvent); +// } + } + +} From 0b4cff3e702cd61987227f0c1f91dda70d6a58fb Mon Sep 17 00:00:00 2001 From: Frans Jacobs <41232225+fransjacobs@users.noreply.github.com> Date: Thu, 30 Jan 2025 19:15:03 +0100 Subject: [PATCH 13/24] Multiple fixes --- .../commandStation/autopilot/AutoPilot.java | 4 +- .../autopilot/state/Dispatcher.java | 6 +- .../esu/ecos/EsuEcosCommandStationImpl.java | 19 +- src/main/java/jcs/ui/VNCPanel.java | 38 +-- src/main/java/jcs/ui/layout/LayoutCanvas.java | 36 ++- src/main/java/jcs/ui/layout/LayoutPanel.form | 94 +----- src/main/java/jcs/ui/layout/LayoutPanel.java | 112 +------ src/main/java/jcs/ui/layout/RoutesDialog.java | 43 ++- .../ui/layout/dialogs/BlockControlDialog.java | 3 +- src/main/java/jcs/ui/layout/tiles/Tile.java | 8 +- .../java/jcs/ui/layout/tiles/TileCache.java | 295 ++++++++---------- .../jcs/ui/layout/tiles/BlockTileTester.java | 8 +- .../jcs/ui/layout/tiles/CrossTileTester.java | 16 +- .../ui/layout/tiles/CrossingTileTester.java | 8 +- .../jcs/ui/layout/tiles/CurvedTileTester.java | 8 +- .../jcs/ui/layout/tiles/EndTileTester.java | 8 +- .../jcs/ui/layout/tiles/SensorTileTester.java | 8 +- .../jcs/ui/layout/tiles/SignalTileTester.java | 8 +- .../tiles/StraightDirectionTileTester.java | 8 +- .../ui/layout/tiles/StraightTileTester.java | 8 +- .../jcs/ui/layout/tiles/SwitchTileTester.java | 16 +- .../jcs/ui/layout/tiles/TileTesterFrame.java | 2 +- 22 files changed, 278 insertions(+), 478 deletions(-) diff --git a/src/main/java/jcs/commandStation/autopilot/AutoPilot.java b/src/main/java/jcs/commandStation/autopilot/AutoPilot.java index 23ce3b8b..d31d1637 100644 --- a/src/main/java/jcs/commandStation/autopilot/AutoPilot.java +++ b/src/main/java/jcs/commandStation/autopilot/AutoPilot.java @@ -322,7 +322,7 @@ public static void resetStates() { } PersistenceFactory.getService().persist(block); TileEvent tileEvent = new TileEvent(block); - TileCache.fireTileEventListener(tileEvent); + //TileCache.fireTileEventListener(tileEvent); } JCS.getJcsCommandStation().switchPower(true); @@ -403,7 +403,7 @@ private static void handleGhost(SensorEvent event) { JCS.getJcsCommandStation().switchPower(false); TileEvent tileEvent = new TileEvent(block); - TileCache.fireTileEventListener(tileEvent); + //TileCache.fireTileEventListener(tileEvent); } else { if (block.getLocomotiveId() != null) { //keep state as is diff --git a/src/main/java/jcs/commandStation/autopilot/state/Dispatcher.java b/src/main/java/jcs/commandStation/autopilot/state/Dispatcher.java index 70801fc9..715e54dc 100644 --- a/src/main/java/jcs/commandStation/autopilot/state/Dispatcher.java +++ b/src/main/java/jcs/commandStation/autopilot/state/Dispatcher.java @@ -327,14 +327,14 @@ public static void resetRoute(RouteBean route) { for (RouteElementBean re : routeElements) { String tileId = re.getTileId(); TileEvent tileEvent = new TileEvent(tileId, false); - TileCache.fireTileEventListener(tileEvent); + //TileCache.fireTileEventListener(tileEvent); } } void showBlockState(BlockBean blockBean) { Logger.trace("Show block " + blockBean); TileEvent tileEvent = new TileEvent(blockBean); - TileCache.fireTileEventListener(tileEvent); + //TileCache.fireTileEventListener(tileEvent); } void showRoute(RouteBean routeBean, Color routeColor) { @@ -351,7 +351,7 @@ void showRoute(RouteBean routeBean, Color routeColor) { } else { tileEvent = new TileEvent(tileId, true, incomingSide, routeColor); } - TileCache.fireTileEventListener(tileEvent); + //TileCache.fireTileEventListener(tileEvent); } } diff --git a/src/main/java/jcs/commandStation/esu/ecos/EsuEcosCommandStationImpl.java b/src/main/java/jcs/commandStation/esu/ecos/EsuEcosCommandStationImpl.java index 2e2b5766..53ec814a 100644 --- a/src/main/java/jcs/commandStation/esu/ecos/EsuEcosCommandStationImpl.java +++ b/src/main/java/jcs/commandStation/esu/ecos/EsuEcosCommandStationImpl.java @@ -56,6 +56,7 @@ import static jcs.entities.AccessoryBean.AccessoryValue.GREEN; import static jcs.entities.AccessoryBean.AccessoryValue.RED; import jcs.entities.LocomotiveBean; +import jcs.util.NetworkUtil; import org.tinylog.Logger; public class EsuEcosCommandStationImpl extends AbstractController implements DecoderController, AccessoryController, FeedbackController { @@ -98,8 +99,6 @@ public void setVirtual(boolean flag) { connect(); } - - @Override public boolean connect() { if (!connected) { @@ -122,10 +121,17 @@ public boolean connect() { if (commandStationBean.getIpAddress() != null) { EcosConnectionFactory.writeLastUsedIpAddressProperty(commandStationBean.getIpAddress()); } else { - //try to discover the ECoS - InetAddress ecosAddr = EcosConnectionFactory.discoverEcos(); - String ip = ecosAddr.getHostAddress(); + + String ip; + if (!virtual) { + //try to discover the ECoS + InetAddress ecosAddr = EcosConnectionFactory.discoverEcos(); + ip = ecosAddr.getHostAddress(); + } else { + ip = NetworkUtil.getIPv4HostAddress().getHostAddress(); + } commandStationBean.setIpAddress(ip); + EcosConnectionFactory.writeLastUsedIpAddressProperty(commandStationBean.getIpAddress()); canConnect = ip != null; if (!canConnect) { @@ -231,10 +237,9 @@ private void initFeedbackManager() { for (int i = 0; i < feedbackManager.getSize(); i++) { int moduleId = i + FeedbackManager.S88_OFFSET; reply = connection.sendMessage(EcosMessageFactory.getFeedbackModuleInfo(moduleId)); - + //TODO: Start of day... //feedbackManager.update(reply); - connection.sendMessage(EcosMessageFactory.subscribeFeedbackModule(moduleId)); //Logger.trace("r: "+reply.getResponse()); } diff --git a/src/main/java/jcs/ui/VNCPanel.java b/src/main/java/jcs/ui/VNCPanel.java index bf69b6c6..c3ba8bc1 100644 --- a/src/main/java/jcs/ui/VNCPanel.java +++ b/src/main/java/jcs/ui/VNCPanel.java @@ -42,6 +42,7 @@ import javax.swing.JPanel; import javax.swing.UIManager; import javax.swing.UnsupportedLookAndFeelException; +import jcs.JCS; import jcs.commandStation.esu.ecos.net.EcosConnectionFactory; import org.tinylog.Logger; @@ -69,25 +70,25 @@ public VNCPanel() { } private void initVnc() { - addDrawingSurface(); - //clipboardMonitor.start(); - initialiseVernacularClient(); - - - String host; - InetAddress ia = EcosConnectionFactory.discoverEcos(); - //InetAddress ia = CSConnectionFactory.discoverCs(); - - if (ia != null) { - host = ia.getHostAddress(); - } else { - Logger.warn("Use a default host ip....."); - host = "192.168.1.110"; + if (JCS.getJcsCommandStation() != null) { + if (!JCS.getJcsCommandStation().getCommandStationBean().isVirtual()) { + addDrawingSurface(); + //clipboardMonitor.start(); + initialiseVernacularClient(); + String host = JCS.getJcsCommandStation().getCommandStationInfo().getHostname(); + + //InetAddress ia = EcosConnectionFactory.discoverEcos(); + //InetAddress ia = CSConnectionFactory.discoverCs(); + //if (ia != null) { + // host = ia.getHostAddress(); + //} else { + // Logger.warn("Use a default host ip....."); + // host = "192.168.1.110"; + //} + int port = DEFAULT_VNC_PORT; + this.connect(host, port); } - - int port = DEFAULT_VNC_PORT; - this.connect(host, port); - + } } private void addDrawingSurface() { @@ -415,7 +416,6 @@ public void windowClosing(java.awt.event.WindowEvent e) { // // int port = DEFAULT_VNC_PORT; // vncPanel.connect(host, port); - testFrame.pack(); testFrame.setLocationRelativeTo(null); testFrame.setVisible(true); diff --git a/src/main/java/jcs/ui/layout/LayoutCanvas.java b/src/main/java/jcs/ui/layout/LayoutCanvas.java index 15011e12..bc89dd21 100755 --- a/src/main/java/jcs/ui/layout/LayoutCanvas.java +++ b/src/main/java/jcs/ui/layout/LayoutCanvas.java @@ -91,10 +91,14 @@ public enum Mode { CONTROL } + static final int LINE_GRID = 0; + static final int DOT_GRID = 1; + + private int gridType = LINE_GRID; + private boolean readonly; private Mode mode; private boolean drawGrid = true; - private boolean lineGrid = true; private Orientation orientation; private Direction direction; @@ -133,24 +137,23 @@ public LayoutCanvas(boolean readonly) { private void postInit() { routesDialog = new RoutesDialog(getParentFrame(), false, this, this.readonly); - lineGrid = "true".equals(System.getProperty("draw.linegrid", "true")); } @Override public void paint(Graphics g) { - long started = System.currentTimeMillis(); + //long started = System.currentTimeMillis(); super.paint(g); if (drawGrid) { - if (lineGrid) { + if (this.gridType == LINE_GRID) { paintLineGrid(g); } else { paintDotGrid(g); } } - long now = System.currentTimeMillis(); - Logger.trace("Duration: " + (now - started) + " ms."); + //long now = System.currentTimeMillis(); + //Logger.trace("Duration: " + (now - started) + " ms."); } @Override @@ -214,8 +217,18 @@ void setMode(LayoutCanvas.Mode mode) { } void setDrawGrid(boolean flag) { - this.drawGrid = flag; - this.repaint(); + if (flag) { + switch (gridType) { + case LINE_GRID -> + gridType = DOT_GRID; + case DOT_GRID -> + gridType = LINE_GRID; + default -> + gridType = LINE_GRID; + } + } + drawGrid = flag; + repaint(); } void setTileType(TileBean.TileType tileType) { @@ -250,10 +263,11 @@ private void loadTiles() { for (Tile tile : tiles) { add(tile); - tile.setDrawCenterPoint(!readonly); + boolean showCenter = "true".equalsIgnoreCase(System.getProperty("tile.show.center", "false")); + if (showCenter) { + tile.setDrawCenterPoint(showCenter); + } } - - repaint(); } private void mouseMoveAction(MouseEvent evt) { diff --git a/src/main/java/jcs/ui/layout/LayoutPanel.form b/src/main/java/jcs/ui/layout/LayoutPanel.form index 1386e2e4..158b41a2 100755 --- a/src/main/java/jcs/ui/layout/LayoutPanel.form +++ b/src/main/java/jcs/ui/layout/LayoutPanel.form @@ -181,29 +181,6 @@ - - - - - - - - - - - - - - - - - - - - - - - @@ -227,29 +204,6 @@ - - - - - - - - - - - - - - - - - - - - - - - @@ -458,7 +412,7 @@ - + @@ -845,29 +799,6 @@ - - - - - - - - - - - - - - - - - - - - - - - @@ -914,29 +845,6 @@ - - - - - - - - - - - - - - - - - - - - - - - diff --git a/src/main/java/jcs/ui/layout/LayoutPanel.java b/src/main/java/jcs/ui/layout/LayoutPanel.java index 909a4fd1..df6383c0 100755 --- a/src/main/java/jcs/ui/layout/LayoutPanel.java +++ b/src/main/java/jcs/ui/layout/LayoutPanel.java @@ -73,17 +73,10 @@ private void postInit() { if (readonly) { this.canvas.setDrawGrid(!readonly); - this.saveBtn.setEnabled(!readonly); - this.saveBtn.setVisible(!readonly); - this.toolBar.remove(this.saveBtn); - this.loadBtn.setEnabled(!readonly); this.loadBtn.setVisible(!readonly); this.toolBar.remove(this.loadBtn); - this.repaintBtn.setEnabled(readonly); - this.repaintBtn.setVisible(readonly); - this.routeBtn.setEnabled(readonly); this.routeBtn.setVisible(readonly); @@ -136,18 +129,12 @@ private void postInit() { this.crossingBtn.setEnabled(!readonly); this.crossingBtn.setVisible(!readonly); - this.moveBtn.setEnabled(!readonly); - this.moveBtn.setVisible(!readonly); - this.flipVerticalBtn.setEnabled(!readonly); this.flipVerticalBtn.setVisible(!readonly); this.flipHorizontalBtn.setEnabled(!readonly); this.flipHorizontalBtn.setVisible(!readonly); - this.rotateBtn.setEnabled(!readonly); - this.rotateBtn.setVisible(!readonly); - //Todo Remove the Autopilot related things from this panel //this.autoPilotBtn.setEnabled(readonly && JCS.getJcsCommandStation().isPowerOn()); // this.autoPilotBtn.setEnabled(readonly); @@ -157,15 +144,6 @@ private void postInit() { // this.startAllLocomotivesBtn.setEnabled(readonly && this.autoPilotBtn.isSelected()); // this.startAllLocomotivesBtn.setVisible(readonly); } else { - if ("true".equals(System.getProperty("batch.tile.persist", "true"))) { - this.saveBtn.setEnabled(true); - this.saveBtn.setVisible(true); - } else { - this.saveBtn.setEnabled(false); - this.saveBtn.setVisible(false); - this.toolBar.remove(this.saveBtn); - } - // this.toolBar.remove(this.autoPilotBtn); // this.autoPilotBtn.setEnabled(readonly); // this.autoPilotBtn.setVisible(readonly); @@ -194,7 +172,6 @@ private void postInit() { // void saveLayout() { // this.canvas.saveLayout(); // } - public void loadLayout() { this.canvas.loadLayoutInBackground(); } @@ -223,9 +200,7 @@ private void initComponents() { tileBtnGroup = new ButtonGroup(); topPanel = new JPanel(); toolBar = new JToolBar(); - saveBtn = new JButton(); loadBtn = new JButton(); - repaintBtn = new JButton(); routeBtn = new JButton(); autoPilotBtn = new JToggleButton(); startAllLocomotivesBtn = new JToggleButton(); @@ -250,10 +225,8 @@ private void initComponents() { endTrackBtn = new JToggleButton(); crossingBtn = new JToggleButton(); filler4 = new Box.Filler(new Dimension(20, 0), new Dimension(20, 0), new Dimension(20, 32767)); - moveBtn = new JButton(); flipVerticalBtn = new JButton(); flipHorizontalBtn = new JButton(); - rotateBtn = new JButton(); canvasScrollPane = new JScrollPane(); canvas = new LayoutCanvas(this.readonly); @@ -370,21 +343,6 @@ public void componentShown(ComponentEvent evt) { toolBar.setName(""); // NOI18N toolBar.setPreferredSize(new Dimension(1100, 42)); - saveBtn.setIcon(new ImageIcon(getClass().getResource("/media/save-24.png"))); // NOI18N - saveBtn.setToolTipText("Save"); - saveBtn.setFocusable(false); - saveBtn.setHorizontalTextPosition(SwingConstants.CENTER); - saveBtn.setMaximumSize(new Dimension(40, 40)); - saveBtn.setMinimumSize(new Dimension(40, 40)); - saveBtn.setPreferredSize(new Dimension(40, 40)); - saveBtn.setVerticalTextPosition(SwingConstants.BOTTOM); - saveBtn.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent evt) { - saveBtnActionPerformed(evt); - } - }); - toolBar.add(saveBtn); - loadBtn.setIcon(new ImageIcon(getClass().getResource("/media/load-24.png"))); // NOI18N loadBtn.setToolTipText("Load"); loadBtn.setFocusable(false); @@ -400,21 +358,6 @@ public void actionPerformed(ActionEvent evt) { }); toolBar.add(loadBtn); - repaintBtn.setIcon(new ImageIcon(getClass().getResource("/media/CS2-3-Sync.png"))); // NOI18N - repaintBtn.setToolTipText("Repaint"); - repaintBtn.setFocusable(false); - repaintBtn.setHorizontalTextPosition(SwingConstants.CENTER); - repaintBtn.setMaximumSize(new Dimension(40, 40)); - repaintBtn.setMinimumSize(new Dimension(38, 38)); - repaintBtn.setPreferredSize(new Dimension(38, 38)); - repaintBtn.setVerticalTextPosition(SwingConstants.BOTTOM); - repaintBtn.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent evt) { - repaintBtnActionPerformed(evt); - } - }); - toolBar.add(repaintBtn); - routeBtn.setIcon(new ImageIcon(getClass().getResource("/media/river-black.png"))); // NOI18N routeBtn.setToolTipText("Route"); routeBtn.setFocusable(false); @@ -529,7 +472,7 @@ public void actionPerformed(ActionEvent evt) { gridBtn.setIcon(new ImageIcon(getClass().getResource("/media/grid-2-24.png"))); // NOI18N gridBtn.setSelected(true); - gridBtn.setToolTipText("Grid"); + gridBtn.setToolTipText("Show Grid"); gridBtn.setHorizontalTextPosition(SwingConstants.CENTER); gridBtn.setSelectedIcon(new ImageIcon(getClass().getResource("/media/grid-dot-24.png"))); // NOI18N gridBtn.setVerticalTextPosition(SwingConstants.BOTTOM); @@ -742,21 +685,6 @@ public void actionPerformed(ActionEvent evt) { toolBar.add(crossingBtn); toolBar.add(filler4); - moveBtn.setIcon(new ImageIcon(getClass().getResource("/media/drag-24.png"))); // NOI18N - moveBtn.setToolTipText("Move"); - moveBtn.setFocusable(false); - moveBtn.setHorizontalTextPosition(SwingConstants.CENTER); - moveBtn.setMaximumSize(new Dimension(40, 40)); - moveBtn.setMinimumSize(new Dimension(38, 38)); - moveBtn.setPreferredSize(new Dimension(38, 38)); - moveBtn.setVerticalTextPosition(SwingConstants.BOTTOM); - moveBtn.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent evt) { - moveBtnActionPerformed(evt); - } - }); - toolBar.add(moveBtn); - flipVerticalBtn.setIcon(new ImageIcon(getClass().getResource("/media/flip-vertical-24.png"))); // NOI18N flipVerticalBtn.setToolTipText("Flip Vertical"); flipVerticalBtn.setFocusable(false); @@ -787,21 +715,6 @@ public void actionPerformed(ActionEvent evt) { }); toolBar.add(flipHorizontalBtn); - rotateBtn.setIcon(new ImageIcon(getClass().getResource("/media/rotate2-24.png"))); // NOI18N - rotateBtn.setToolTipText("Rotate"); - rotateBtn.setFocusable(false); - rotateBtn.setHorizontalTextPosition(SwingConstants.CENTER); - rotateBtn.setMaximumSize(new Dimension(40, 40)); - rotateBtn.setMinimumSize(new Dimension(38, 38)); - rotateBtn.setPreferredSize(new Dimension(38, 38)); - rotateBtn.setVerticalTextPosition(SwingConstants.BOTTOM); - rotateBtn.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent evt) { - rotateBtnActionPerformed(evt); - } - }); - toolBar.add(rotateBtn); - topPanel.add(toolBar); add(topPanel, BorderLayout.NORTH); @@ -881,10 +794,6 @@ private void propertiesMIActionPerformed(ActionEvent evt) {//GEN-FIRST:event_pro // editSelectedTileProperties(); }//GEN-LAST:event_propertiesMIActionPerformed - private void saveBtnActionPerformed(ActionEvent evt) {//GEN-FIRST:event_saveBtnActionPerformed - //this.canvas.saveLayout(); - }//GEN-LAST:event_saveBtnActionPerformed - private void loadBtnActionPerformed(ActionEvent evt) {//GEN-FIRST:event_loadBtnActionPerformed this.loadLayout(); }//GEN-LAST:event_loadBtnActionPerformed @@ -902,10 +811,6 @@ private void deleteBtnActionPerformed(ActionEvent evt) {//GEN-FIRST:event_delete //this.canvas.removeTiles(); }//GEN-LAST:event_deleteBtnActionPerformed - private void repaintBtnActionPerformed(ActionEvent evt) {//GEN-FIRST:event_repaintBtnActionPerformed - this.canvas.repaint(); - }//GEN-LAST:event_repaintBtnActionPerformed - private void straightBtnActionPerformed(ActionEvent evt) {//GEN-FIRST:event_straightBtnActionPerformed setTileType(TileBean.TileType.STRAIGHT); }//GEN-LAST:event_straightBtnActionPerformed @@ -918,10 +823,6 @@ private void blockBtnActionPerformed(ActionEvent evt) {//GEN-FIRST:event_blockBt setTileType(TileBean.TileType.BLOCK); }//GEN-LAST:event_blockBtnActionPerformed - private void rotateBtnActionPerformed(ActionEvent evt) {//GEN-FIRST:event_rotateBtnActionPerformed - this.canvas.rotateSelectedTile(); - }//GEN-LAST:event_rotateBtnActionPerformed - private void flipHorizontalBtnActionPerformed(ActionEvent evt) {//GEN-FIRST:event_flipHorizontalBtnActionPerformed this.canvas.flipSelectedTileHorizontal(); }//GEN-LAST:event_flipHorizontalBtnActionPerformed @@ -930,10 +831,6 @@ private void flipVerticalBtnActionPerformed(ActionEvent evt) {//GEN-FIRST:event_ this.canvas.flipSelectedTileVertical(); }//GEN-LAST:event_flipVerticalBtnActionPerformed - private void moveBtnActionPerformed(ActionEvent evt) {//GEN-FIRST:event_moveBtnActionPerformed - setMode(LayoutCanvas.Mode.MOVE); - }//GEN-LAST:event_moveBtnActionPerformed - private void rightSwitchBtnActionPerformed(ActionEvent evt) {//GEN-FIRST:event_rightSwitchBtnActionPerformed this.setTileType(TileBean.TileType.SWITCH); this.setDirection(Direction.RIGHT); @@ -953,8 +850,7 @@ private void sensorBtnActionPerformed(ActionEvent evt) {//GEN-FIRST:event_sensor }//GEN-LAST:event_sensorBtnActionPerformed private void gridBtnActionPerformed(ActionEvent evt) {//GEN-FIRST:event_gridBtnActionPerformed - this.canvas.setDrawGrid(this.gridBtn.isSelected()); - this.canvas.repaint(); + this.canvas.setDrawGrid(this.gridBtn.isSelected()); }//GEN-LAST:event_gridBtnActionPerformed private void formComponentResized(ComponentEvent evt) {//GEN-FIRST:event_formComponentResized @@ -1117,18 +1013,14 @@ public void onPowerChange(PowerEvent event) { private JMenuItem leftMI; private JToggleButton leftSwitchBtn; private JButton loadBtn; - private JButton moveBtn; private JMenuItem moveMI; private JPopupMenu operationsPM; private JMenuItem propertiesMI; - private JButton repaintBtn; private JButton resetAutopilotBtn; private JMenuItem rightMI; private JToggleButton rightSwitchBtn; - private JButton rotateBtn; private JMenuItem rotateMI; private JButton routeBtn; - private JButton saveBtn; private JButton selectBtn; private JToggleButton sensorBtn; private JToggleButton signalBtn; diff --git a/src/main/java/jcs/ui/layout/RoutesDialog.java b/src/main/java/jcs/ui/layout/RoutesDialog.java index 6f564d26..12cf89a2 100644 --- a/src/main/java/jcs/ui/layout/RoutesDialog.java +++ b/src/main/java/jcs/ui/layout/RoutesDialog.java @@ -33,7 +33,7 @@ import jcs.entities.RouteElementBean; import jcs.entities.TileBean.Orientation; import jcs.persistence.PersistenceFactory; -import jcs.ui.layout.events.TileEvent; +import jcs.ui.layout.tiles.Tile; import org.tinylog.Logger; /** @@ -74,16 +74,16 @@ public RoutesDialog(java.awt.Frame parent, boolean modal, LayoutCanvas layoutCan this.setIconImage(new ImageIcon(iconUrl).getImage()); } - if (this.readonly) { - this.routeBtn.setEnabled(!readonly); - this.routeBtn.setVisible(!readonly); + if (readonly) { + routeBtn.setEnabled(!readonly); + routeBtn.setVisible(!readonly); - this.deleteRoutesBtn.setEnabled(!readonly); - this.deleteRoutesBtn.setVisible(!readonly); + deleteRoutesBtn.setEnabled(!readonly); + deleteRoutesBtn.setVisible(!readonly); } - if (this.defaultRouteColor == null) { - this.defaultRouteColor = Color.darkGray; + if (defaultRouteColor == null) { + defaultRouteColor = Tile.DEFAULT_ROUTE_TRACK_COLOR; } } @@ -119,8 +119,16 @@ private void setSelectedRoute(RouteBean route) { private void resetRoute(List routeElements) { for (RouteElementBean re : routeElements) { String tileId = re.getTileId(); - TileEvent tileEvent = new TileEvent(tileId, false); - TileCache.fireTileEventListener(tileEvent); + Tile tile = TileCache.findTile(tileId); + + if (tile.isBlock()) { + tile.setBlockState(BlockState.FREE); + } + if (tile.isJunction()) { + tile.setRouteValue(AccessoryBean.AccessoryValue.OFF); + } + + tile.setShowRoute(false); } } @@ -131,21 +139,22 @@ private void showRoute(RouteBean routeBean) { String tileId = re.getTileId(); Orientation incomingSide = re.getIncomingOrientation(); - TileEvent tileEvent; + Tile tile = TileCache.findTile(tileId); + tile.setIncomingSide(incomingSide); + tile.setTrackRouteColor(defaultRouteColor); + if (re.isTurnout()) { AccessoryBean.AccessoryValue routeState = re.getAccessoryValue(); - tileEvent = new TileEvent(tileId, true, incomingSide, routeState); + tile.setRouteValue(routeState); } else if (re.isBlock()) { if (re.getTileId().equals(routeBean.getFromTileId())) { //departure block - tileEvent = new TileEvent(tileId, true, BlockState.OUTBOUND); + tile.setBlockState(BlockState.OUTBOUND); } else { - tileEvent = new TileEvent(tileId, true, BlockState.INBOUND); + tile.setBlockState(BlockState.INBOUND); } - } else { - tileEvent = new TileEvent(tileId, true, incomingSide); } - TileCache.fireTileEventListener(tileEvent); + tile.setShowRoute(true); } } diff --git a/src/main/java/jcs/ui/layout/dialogs/BlockControlDialog.java b/src/main/java/jcs/ui/layout/dialogs/BlockControlDialog.java index b5881650..3ea13750 100644 --- a/src/main/java/jcs/ui/layout/dialogs/BlockControlDialog.java +++ b/src/main/java/jcs/ui/layout/dialogs/BlockControlDialog.java @@ -24,7 +24,6 @@ import jcs.entities.BlockBean; import jcs.entities.LocomotiveBean; import jcs.persistence.PersistenceFactory; -import jcs.ui.layout.tiles.TileCache; import jcs.ui.layout.events.TileEvent; import jcs.ui.layout.tiles.Block; import org.tinylog.Logger; @@ -422,7 +421,7 @@ private void saveExitBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-F } TileEvent tileEvent = new TileEvent(bb); //TileFactory.fireTileEventListener(tileEvent); - TileCache.fireTileEventListener(tileEvent); + //TileCache.fireTileEventListener(tileEvent); } diff --git a/src/main/java/jcs/ui/layout/tiles/Tile.java b/src/main/java/jcs/ui/layout/tiles/Tile.java index 07127650..44b3636a 100755 --- a/src/main/java/jcs/ui/layout/tiles/Tile.java +++ b/src/main/java/jcs/ui/layout/tiles/Tile.java @@ -87,8 +87,8 @@ public abstract class Tile extends JComponent { //implements TileEventListener { public static final Color DEFAULT_BACKGROUND_COLOR = Color.white; public static final Color DEFAULT_TRACK_COLOR = Color.lightGray; - public static final Color DEFAULT_ROUTE_TRACK_COLOR = Color.blue; - public static final Color DEFAULT_SELECTED_COLOR = Color.orange; + public static final Color DEFAULT_ROUTE_TRACK_COLOR = Color.darkGray; + public static final Color DEFAULT_SELECTED_COLOR = Color.yellow; public static final Color DEFAULT_WARN_COLOR = Color.red; public static final String MODEL_CHANGED_PROPERTY = "model"; @@ -590,11 +590,11 @@ public void setBackgroundColor(Color backgroundColor) { this.backgroundColor = backgroundColor; } - public boolean isDrawRoute() { + public boolean isShowRoute() { return model.isShowRoute(); } - public void setDrawRoute(boolean drawRoute) { + public void setShowRoute(boolean drawRoute) { this.model.setShowRoute(drawRoute); } diff --git a/src/main/java/jcs/ui/layout/tiles/TileCache.java b/src/main/java/jcs/ui/layout/tiles/TileCache.java index 3d32de97..a2f9d7c5 100644 --- a/src/main/java/jcs/ui/layout/tiles/TileCache.java +++ b/src/main/java/jcs/ui/layout/tiles/TileCache.java @@ -20,23 +20,9 @@ import java.util.List; import java.util.Map; import java.util.Set; -import java.util.stream.Collector; import java.util.stream.Collectors; -import jcs.entities.AccessoryBean.AccessoryValue; -import jcs.entities.AccessoryBean.SignalValue; import jcs.entities.TileBean; -import jcs.entities.TileBean.Orientation; -import static jcs.entities.TileBean.Orientation.EAST; -import static jcs.entities.TileBean.Orientation.SOUTH; -import static jcs.entities.TileBean.Orientation.WEST; -import jcs.entities.TileBean.TileType; -import static jcs.entities.TileBean.TileType.BLOCK; -import static jcs.entities.TileBean.TileType.CROSS; -import static jcs.entities.TileBean.TileType.SENSOR; -import static jcs.entities.TileBean.TileType.SIGNAL; import jcs.persistence.PersistenceFactory; -import jcs.ui.layout.events.TileEvent; -import jcs.ui.layout.events.TileEventListener; import org.tinylog.Logger; /** @@ -46,58 +32,54 @@ */ public class TileCache { - //private static final Map tileEventListeners = new HashMap<>(); - private static boolean showValues; - + //private static boolean showValues; static final Map tiles = new HashMap<>(); static final Map tileAltPoints = new HashMap<>(); static final Map points = new HashMap<>(); - //static final Map altTiles = new HashMap<>(); private TileCache() { } - @Deprecated - public static void setShowValues(boolean showValues) { - TileCache.showValues = showValues; - - for (Tile tile : tiles.values()) { - TileType tileType = tile.getTileType(); - switch (tileType) { - case SWITCH -> { - if (showValues && ((Switch) tile).getTileBean().getAccessoryBean() != null) { - tile.setAccessoryValue(tile.getTileBean().getAccessoryBean().getAccessoryValue()); - } else { - tile.setAccessoryValue(AccessoryValue.OFF); - } - } - case CROSS -> { - if (showValues && ((Cross) tile).getTileBean().getAccessoryBean() != null) { - tile.setAccessoryValue(tile.getTileBean().getAccessoryBean().getAccessoryValue()); - } else { - tile.setAccessoryValue(AccessoryValue.OFF); - } - } - case SIGNAL -> { - if (showValues && ((Signal) tile).getTileBean().getAccessoryBean() != null) { - tile.setSignalValue(tile.getTileBean().getAccessoryBean().getSignalValue()); - } else { - tile.setSignalValue(SignalValue.OFF); - } - } - case SENSOR -> { - if (showValues && ((Sensor) tile).getTileBean().getSensorBean() != null) { - tile.setActive(tile.getTileBean().getSensorBean().isActive()); - } else { - tile.setActive(false); - } - } - case BLOCK -> { - } - } - } - } - +// @Deprecated +// public static void setShowValues(boolean showValues) { +// TileCache.showValues = showValues; +// +// for (Tile tile : tiles.values()) { +// TileType tileType = tile.getTileType(); +// switch (tileType) { +// case SWITCH -> { +// if (showValues && ((Switch) tile).getTileBean().getAccessoryBean() != null) { +// tile.setAccessoryValue(tile.getTileBean().getAccessoryBean().getAccessoryValue()); +// } else { +// tile.setAccessoryValue(AccessoryValue.OFF); +// } +// } +// case CROSS -> { +// if (showValues && ((Cross) tile).getTileBean().getAccessoryBean() != null) { +// tile.setAccessoryValue(tile.getTileBean().getAccessoryBean().getAccessoryValue()); +// } else { +// tile.setAccessoryValue(AccessoryValue.OFF); +// } +// } +// case SIGNAL -> { +// if (showValues && ((Signal) tile).getTileBean().getAccessoryBean() != null) { +// tile.setSignalValue(tile.getTileBean().getAccessoryBean().getSignalValue()); +// } else { +// tile.setSignalValue(SignalValue.OFF); +// } +// } +// case SENSOR -> { +// if (showValues && ((Sensor) tile).getTileBean().getSensorBean() != null) { +// tile.setActive(tile.getTileBean().getSensorBean().isActive()); +// } else { +// tile.setActive(false); +// } +// } +// case BLOCK -> { +// } +// } +// } +// } public static List loadTiles() { tileAltPoints.clear(); points.clear(); @@ -106,7 +88,7 @@ public static List loadTiles() { List tileBeans = PersistenceFactory.getService().getTileBeans(); for (TileBean tb : tileBeans) { - Tile tile = TileFactory.createTile(tb, showValues); + Tile tile = TileFactory.createTile(tb, false); tiles.put(tile.getCenter(), tile); points.put(tile.getId(), tile.getCenter()); //Alternative point(s) to be able to find all points @@ -243,71 +225,67 @@ public static void moveTo(Tile tile, Point p) { } } - @Deprecated - public static boolean checkTileOccupation(Tile tile) { - Set tilePoints = tile.getAllPoints(); - for (Point p : tilePoints) { - if (tiles.containsKey(p) || tileAltPoints.containsKey(p)) { - //The is a match, check if it is an other tile - Tile mt = findTile(p); - if (tile.getId().equals(mt.getId())) { - //same tile continue - } else { - //Other tile so really occupied - return true; - } - } - } - return false; - } - - @Deprecated - public static boolean containsPoint(Set points) { - for (Point p : points) { - return tiles.containsKey(p) || tileAltPoints.containsKey(p); - } - return false; - } - - public static boolean containsPoint(Point point) { - return tiles.containsKey(point) || tileAltPoints.containsKey(point); - } - - @Deprecated - public static Point checkAvailable(Point newPoint, Orientation orientation) { - if (tiles.containsKey(newPoint)) { - Tile et = tiles.get(newPoint); - Logger.trace("@ " + newPoint + " is allready occcupied by: " + et + "..."); - //Search for the nearest avalaible free point - //first get the Center point of the tile which is occuping this slot - // show warning! - Point ecp = et.getCenter(); - - int w = et.getWidth(); - int h = et.getHeight(); - - Point np; - np = switch (orientation) { - case EAST -> - new Point(ecp.x + w, ecp.y); - case WEST -> - new Point(newPoint.x - w, ecp.y); - case SOUTH -> - new Point(ecp.x, newPoint.y + h); - default -> - new Point(ecp.x, newPoint.y - h); - }; - - Logger.trace("Alternative CP: " + np); - // recursive check - return checkAvailable(np, orientation); - } else { - Logger.trace("@ " + newPoint + " is not yet used..."); - - return newPoint; - } - } - +// @Deprecated +// public static boolean checkTileOccupation(Tile tile) { +// Set tilePoints = tile.getAllPoints(); +// for (Point p : tilePoints) { +// if (tiles.containsKey(p) || tileAltPoints.containsKey(p)) { +// //The is a match, check if it is an other tile +// Tile mt = findTile(p); +// if (tile.getId().equals(mt.getId())) { +// //same tile continue +// } else { +// //Other tile so really occupied +// return true; +// } +// } +// } +// return false; +// } +// @Deprecated +// public static boolean containsPoint(Set points) { +// for (Point p : points) { +// return tiles.containsKey(p) || tileAltPoints.containsKey(p); +// } +// return false; +// } +// public static boolean containsPoint(Point point) { +// return tiles.containsKey(point) || tileAltPoints.containsKey(point); +// } +// @Deprecated +// public static Point checkAvailable(Point newPoint, Orientation orientation) { +// if (tiles.containsKey(newPoint)) { +// Tile et = tiles.get(newPoint); +// Logger.trace("@ " + newPoint + " is allready occcupied by: " + et + "..."); +// //Search for the nearest avalaible free point +// //first get the Center point of the tile which is occuping this slot +// // show warning! +// Point ecp = et.getCenter(); +// +// int w = et.getWidth(); +// int h = et.getHeight(); +// +// Point np; +// np = switch (orientation) { +// case EAST -> +// new Point(ecp.x + w, ecp.y); +// case WEST -> +// new Point(newPoint.x - w, ecp.y); +// case SOUTH -> +// new Point(ecp.x, newPoint.y + h); +// default -> +// new Point(ecp.x, newPoint.y - h); +// }; +// +// Logger.trace("Alternative CP: " + np); +// // recursive check +// return checkAvailable(np, orientation); +// } else { +// Logger.trace("@ " + newPoint + " is not yet used..."); +// +// return newPoint; +// } +// } public static Tile rotateTile(Tile tile) { if (!tiles.containsKey(tile.getCenter())) { Logger.warn("Tile " + tile.getId() + " NOT in cache!"); @@ -363,41 +341,36 @@ private static Tile flipTile(Tile tile, boolean horizontal) { return tile; } - @Deprecated - public static void addTileEventListener(TileEventListener listener) { - String key = listener.getId(); - //tileEventListeners.put(key, listener); - } - - @Deprecated - public static void removeTileEventListener(Tile tile) { - if (tile instanceof TileEventListener tileEventListener) { - removeTileEventListener(tileEventListener); - } - } - - static void removeTileEventListener(TileEventListener listener) { - String key = listener.getId(); - //tileEventListeners.remove(key, listener); - } - - @Deprecated - public static void fireTileEventListener(TileEvent tileEvent) { -// String key = tileEvent.getTileId(); -// TileEventListener listener = tileEventListeners.get(key); -// if (listener != null) { -// listener.onTileChange(tileEvent); -// Logger.trace("Fire listener on tile " + key); -// } else { -// //Logger.trace("Tile " + key + " not available"); +// @Deprecated +// public static void addTileEventListener(TileEventListener listener) { +// String key = listener.getId(); +// //tileEventListeners.put(key, listener); +// } +// @Deprecated +// public static void removeTileEventListener(Tile tile) { +// if (tile instanceof TileEventListener tileEventListener) { +// removeTileEventListener(tileEventListener); // } - } - - @Deprecated - public static void fireAllTileEventListeners(TileEvent tileEvent) { -// for (TileEventListener listener : tileEventListeners.values()) { -// listener.onTileChange(tileEvent); -// } - } - +// } +// static void removeTileEventListener(TileEventListener listener) { +// String key = listener.getId(); +// //tileEventListeners.remove(key, listener); +// } +// @Deprecated +// public static void fireTileEventListener(TileEvent tileEvent) { +//// String key = tileEvent.getTileId(); +//// TileEventListener listener = tileEventListeners.get(key); +//// if (listener != null) { +//// listener.onTileChange(tileEvent); +//// Logger.trace("Fire listener on tile " + key); +//// } else { +//// //Logger.trace("Tile " + key + " not available"); +//// } +// } +// @Deprecated +// public static void fireAllTileEventListeners(TileEvent tileEvent) { +//// for (TileEventListener listener : tileEventListeners.values()) { +//// listener.onTileChange(tileEvent); +//// } +// } } diff --git a/src/test/java/jcs/ui/layout/tiles/BlockTileTester.java b/src/test/java/jcs/ui/layout/tiles/BlockTileTester.java index d50b4f9f..620fef4b 100644 --- a/src/test/java/jcs/ui/layout/tiles/BlockTileTester.java +++ b/src/test/java/jcs/ui/layout/tiles/BlockTileTester.java @@ -261,19 +261,19 @@ public void actionPerformed(java.awt.event.ActionEvent evt) { private void northTileBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_northTileBtnActionPerformed Logger.trace(blockNorth.id + "..."); - blockNorth.setDrawRoute(this.northTileBtn.isSelected()); + blockNorth.setShowRoute(this.northTileBtn.isSelected()); }//GEN-LAST:event_northTileBtnActionPerformed private void eastTileBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_eastTileBtnActionPerformed - blockEast.setDrawRoute(this.eastTileBtn.isSelected()); + blockEast.setShowRoute(this.eastTileBtn.isSelected()); }//GEN-LAST:event_eastTileBtnActionPerformed private void westTileBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_westTileBtnActionPerformed - blockWest.setDrawRoute(this.westTileBtn.isSelected()); + blockWest.setShowRoute(this.westTileBtn.isSelected()); }//GEN-LAST:event_westTileBtnActionPerformed private void southTileBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_southTileBtnActionPerformed - blockSouth.setDrawRoute(this.southTileBtn.isSelected()); + blockSouth.setShowRoute(this.southTileBtn.isSelected()); }//GEN-LAST:event_southTileBtnActionPerformed private void selectSouthTileBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_selectSouthTileBtnActionPerformed diff --git a/src/test/java/jcs/ui/layout/tiles/CrossTileTester.java b/src/test/java/jcs/ui/layout/tiles/CrossTileTester.java index 308066e9..7a15ae65 100644 --- a/src/test/java/jcs/ui/layout/tiles/CrossTileTester.java +++ b/src/test/java/jcs/ui/layout/tiles/CrossTileTester.java @@ -218,23 +218,23 @@ public void actionPerformed(java.awt.event.ActionEvent evt) { private void northTileBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_northTileBtnActionPerformed Logger.trace(crossNorthR.id + "..."); - this.crossNorthR.setDrawRoute(this.northTileBtn.isSelected()); - this.crossNorthL.setDrawRoute(this.northTileBtn.isSelected()); + this.crossNorthR.setShowRoute(this.northTileBtn.isSelected()); + this.crossNorthL.setShowRoute(this.northTileBtn.isSelected()); }//GEN-LAST:event_northTileBtnActionPerformed private void eastTileBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_eastTileBtnActionPerformed - this.crossEastR.setDrawRoute(this.eastTileBtn.isSelected()); - this.crossEastL.setDrawRoute(this.eastTileBtn.isSelected()); + this.crossEastR.setShowRoute(this.eastTileBtn.isSelected()); + this.crossEastL.setShowRoute(this.eastTileBtn.isSelected()); }//GEN-LAST:event_eastTileBtnActionPerformed private void westTileBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_westTileBtnActionPerformed - this.crossWestR.setDrawRoute(this.westTileBtn.isSelected()); - this.crossWestL.setDrawRoute(this.westTileBtn.isSelected()); + this.crossWestR.setShowRoute(this.westTileBtn.isSelected()); + this.crossWestL.setShowRoute(this.westTileBtn.isSelected()); }//GEN-LAST:event_westTileBtnActionPerformed private void southTileBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_southTileBtnActionPerformed - this.crossSouthR.setDrawRoute(this.southTileBtn.isSelected()); - this.crossSouthL.setDrawRoute(this.southTileBtn.isSelected()); + this.crossSouthR.setShowRoute(this.southTileBtn.isSelected()); + this.crossSouthL.setShowRoute(this.southTileBtn.isSelected()); }//GEN-LAST:event_southTileBtnActionPerformed private void selectSouthTileBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_selectSouthTileBtnActionPerformed diff --git a/src/test/java/jcs/ui/layout/tiles/CrossingTileTester.java b/src/test/java/jcs/ui/layout/tiles/CrossingTileTester.java index 04773a8d..11ee9511 100644 --- a/src/test/java/jcs/ui/layout/tiles/CrossingTileTester.java +++ b/src/test/java/jcs/ui/layout/tiles/CrossingTileTester.java @@ -179,19 +179,19 @@ public void actionPerformed(java.awt.event.ActionEvent evt) { private void northTileBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_northTileBtnActionPerformed Logger.trace(trackNorth.id + "..."); - this.trackNorth.setDrawRoute(this.northTileBtn.isSelected()); + this.trackNorth.setShowRoute(this.northTileBtn.isSelected()); }//GEN-LAST:event_northTileBtnActionPerformed private void eastTileBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_eastTileBtnActionPerformed - this.trackEast.setDrawRoute(this.eastTileBtn.isSelected()); + this.trackEast.setShowRoute(this.eastTileBtn.isSelected()); }//GEN-LAST:event_eastTileBtnActionPerformed private void westTileBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_westTileBtnActionPerformed - this.trackWest.setDrawRoute(this.westTileBtn.isSelected()); + this.trackWest.setShowRoute(this.westTileBtn.isSelected()); }//GEN-LAST:event_westTileBtnActionPerformed private void southTileBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_southTileBtnActionPerformed - this.trackSouth.setDrawRoute(this.southTileBtn.isSelected()); + this.trackSouth.setShowRoute(this.southTileBtn.isSelected()); }//GEN-LAST:event_southTileBtnActionPerformed private void selectSouthTileBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_selectSouthTileBtnActionPerformed diff --git a/src/test/java/jcs/ui/layout/tiles/CurvedTileTester.java b/src/test/java/jcs/ui/layout/tiles/CurvedTileTester.java index a2dfcc60..32b0b76f 100644 --- a/src/test/java/jcs/ui/layout/tiles/CurvedTileTester.java +++ b/src/test/java/jcs/ui/layout/tiles/CurvedTileTester.java @@ -177,19 +177,19 @@ public void actionPerformed(java.awt.event.ActionEvent evt) { private void northTileBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_northTileBtnActionPerformed Logger.trace(trackNorth.id + "..."); - this.trackNorth.setDrawRoute(this.northTileBtn.isSelected()); + this.trackNorth.setShowRoute(this.northTileBtn.isSelected()); }//GEN-LAST:event_northTileBtnActionPerformed private void eastTileBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_eastTileBtnActionPerformed - this.trackEast.setDrawRoute(this.eastTileBtn.isSelected()); + this.trackEast.setShowRoute(this.eastTileBtn.isSelected()); }//GEN-LAST:event_eastTileBtnActionPerformed private void westTileBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_westTileBtnActionPerformed - this.trackWest.setDrawRoute(this.westTileBtn.isSelected()); + this.trackWest.setShowRoute(this.westTileBtn.isSelected()); }//GEN-LAST:event_westTileBtnActionPerformed private void southTileBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_southTileBtnActionPerformed - this.trackSouth.setDrawRoute(this.southTileBtn.isSelected()); + this.trackSouth.setShowRoute(this.southTileBtn.isSelected()); }//GEN-LAST:event_southTileBtnActionPerformed private void selectSouthTileBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_selectSouthTileBtnActionPerformed diff --git a/src/test/java/jcs/ui/layout/tiles/EndTileTester.java b/src/test/java/jcs/ui/layout/tiles/EndTileTester.java index 1a9400ed..15b3ed3c 100644 --- a/src/test/java/jcs/ui/layout/tiles/EndTileTester.java +++ b/src/test/java/jcs/ui/layout/tiles/EndTileTester.java @@ -177,19 +177,19 @@ public void actionPerformed(java.awt.event.ActionEvent evt) { private void northTileBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_northTileBtnActionPerformed Logger.trace(trackNorth.id + "..."); - this.trackNorth.setDrawRoute(this.northTileBtn.isSelected()); + this.trackNorth.setShowRoute(this.northTileBtn.isSelected()); }//GEN-LAST:event_northTileBtnActionPerformed private void eastTileBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_eastTileBtnActionPerformed - this.trackEast.setDrawRoute(this.eastTileBtn.isSelected()); + this.trackEast.setShowRoute(this.eastTileBtn.isSelected()); }//GEN-LAST:event_eastTileBtnActionPerformed private void westTileBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_westTileBtnActionPerformed - this.trackWest.setDrawRoute(this.westTileBtn.isSelected()); + this.trackWest.setShowRoute(this.westTileBtn.isSelected()); }//GEN-LAST:event_westTileBtnActionPerformed private void southTileBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_southTileBtnActionPerformed - this.trackSouth.setDrawRoute(this.southTileBtn.isSelected()); + this.trackSouth.setShowRoute(this.southTileBtn.isSelected()); }//GEN-LAST:event_southTileBtnActionPerformed private void selectSouthTileBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_selectSouthTileBtnActionPerformed diff --git a/src/test/java/jcs/ui/layout/tiles/SensorTileTester.java b/src/test/java/jcs/ui/layout/tiles/SensorTileTester.java index 4e016041..d0987c8d 100644 --- a/src/test/java/jcs/ui/layout/tiles/SensorTileTester.java +++ b/src/test/java/jcs/ui/layout/tiles/SensorTileTester.java @@ -185,19 +185,19 @@ public void actionPerformed(java.awt.event.ActionEvent evt) { private void northTileBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_northTileBtnActionPerformed Logger.trace(sensorNorth.id + "..."); - sensorNorth.setDrawRoute(this.northTileBtn.isSelected()); + sensorNorth.setShowRoute(this.northTileBtn.isSelected()); }//GEN-LAST:event_northTileBtnActionPerformed private void eastTileBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_eastTileBtnActionPerformed - sensorEast.setDrawRoute(this.eastTileBtn.isSelected()); + sensorEast.setShowRoute(this.eastTileBtn.isSelected()); }//GEN-LAST:event_eastTileBtnActionPerformed private void westTileBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_westTileBtnActionPerformed - sensorWest.setDrawRoute(this.westTileBtn.isSelected()); + sensorWest.setShowRoute(this.westTileBtn.isSelected()); }//GEN-LAST:event_westTileBtnActionPerformed private void southTileBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_southTileBtnActionPerformed - sensorSouth.setDrawRoute(this.southTileBtn.isSelected()); + sensorSouth.setShowRoute(this.southTileBtn.isSelected()); }//GEN-LAST:event_southTileBtnActionPerformed private void selectSouthTileBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_selectSouthTileBtnActionPerformed diff --git a/src/test/java/jcs/ui/layout/tiles/SignalTileTester.java b/src/test/java/jcs/ui/layout/tiles/SignalTileTester.java index c06af5b8..a1e62419 100644 --- a/src/test/java/jcs/ui/layout/tiles/SignalTileTester.java +++ b/src/test/java/jcs/ui/layout/tiles/SignalTileTester.java @@ -271,19 +271,19 @@ public void actionPerformed(java.awt.event.ActionEvent evt) { private void northTileBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_northTileBtnActionPerformed Logger.trace(signal2North.id + "..."); - this.signal2North.setDrawRoute(this.northTileBtn.isSelected()); + this.signal2North.setShowRoute(this.northTileBtn.isSelected()); }//GEN-LAST:event_northTileBtnActionPerformed private void eastTileBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_eastTileBtnActionPerformed - this.signal2East.setDrawRoute(this.eastTileBtn.isSelected()); + this.signal2East.setShowRoute(this.eastTileBtn.isSelected()); }//GEN-LAST:event_eastTileBtnActionPerformed private void westTileBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_westTileBtnActionPerformed - this.signal2West.setDrawRoute(this.westTileBtn.isSelected()); + this.signal2West.setShowRoute(this.westTileBtn.isSelected()); }//GEN-LAST:event_westTileBtnActionPerformed private void southTileBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_southTileBtnActionPerformed - this.signal2South.setDrawRoute(this.southTileBtn.isSelected()); + this.signal2South.setShowRoute(this.southTileBtn.isSelected()); }//GEN-LAST:event_southTileBtnActionPerformed private void selectSouthTileBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_selectSouthTileBtnActionPerformed diff --git a/src/test/java/jcs/ui/layout/tiles/StraightDirectionTileTester.java b/src/test/java/jcs/ui/layout/tiles/StraightDirectionTileTester.java index 138f32c2..30ad25da 100644 --- a/src/test/java/jcs/ui/layout/tiles/StraightDirectionTileTester.java +++ b/src/test/java/jcs/ui/layout/tiles/StraightDirectionTileTester.java @@ -173,19 +173,19 @@ public void actionPerformed(java.awt.event.ActionEvent evt) { private void northTileBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_northTileBtnActionPerformed Logger.trace(trackNorth.id + "..."); - this.trackNorth.setDrawRoute(this.northTileBtn.isSelected()); + this.trackNorth.setShowRoute(this.northTileBtn.isSelected()); }//GEN-LAST:event_northTileBtnActionPerformed private void eastTileBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_eastTileBtnActionPerformed - this.trackEast.setDrawRoute(this.eastTileBtn.isSelected()); + this.trackEast.setShowRoute(this.eastTileBtn.isSelected()); }//GEN-LAST:event_eastTileBtnActionPerformed private void westTileBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_westTileBtnActionPerformed - this.trackWest.setDrawRoute(this.westTileBtn.isSelected()); + this.trackWest.setShowRoute(this.westTileBtn.isSelected()); }//GEN-LAST:event_westTileBtnActionPerformed private void southTileBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_southTileBtnActionPerformed - this.trackSouth.setDrawRoute(this.southTileBtn.isSelected()); + this.trackSouth.setShowRoute(this.southTileBtn.isSelected()); }//GEN-LAST:event_southTileBtnActionPerformed private void selectSouthTileBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_selectSouthTileBtnActionPerformed diff --git a/src/test/java/jcs/ui/layout/tiles/StraightTileTester.java b/src/test/java/jcs/ui/layout/tiles/StraightTileTester.java index df3bcbdd..ea006b17 100644 --- a/src/test/java/jcs/ui/layout/tiles/StraightTileTester.java +++ b/src/test/java/jcs/ui/layout/tiles/StraightTileTester.java @@ -172,19 +172,19 @@ public void actionPerformed(java.awt.event.ActionEvent evt) { private void northTileBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_northTileBtnActionPerformed Logger.trace(trackNorth.id + "..."); - this.trackNorth.setDrawRoute(this.northTileBtn.isSelected()); + this.trackNorth.setShowRoute(this.northTileBtn.isSelected()); }//GEN-LAST:event_northTileBtnActionPerformed private void eastTileBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_eastTileBtnActionPerformed - this.trackEast.setDrawRoute(this.eastTileBtn.isSelected()); + this.trackEast.setShowRoute(this.eastTileBtn.isSelected()); }//GEN-LAST:event_eastTileBtnActionPerformed private void westTileBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_westTileBtnActionPerformed - this.trackWest.setDrawRoute(this.westTileBtn.isSelected()); + this.trackWest.setShowRoute(this.westTileBtn.isSelected()); }//GEN-LAST:event_westTileBtnActionPerformed private void southTileBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_southTileBtnActionPerformed - this.trackSouth.setDrawRoute(this.southTileBtn.isSelected()); + this.trackSouth.setShowRoute(this.southTileBtn.isSelected()); }//GEN-LAST:event_southTileBtnActionPerformed private void selectSouthTileBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_selectSouthTileBtnActionPerformed diff --git a/src/test/java/jcs/ui/layout/tiles/SwitchTileTester.java b/src/test/java/jcs/ui/layout/tiles/SwitchTileTester.java index 4b615a58..584d6df0 100644 --- a/src/test/java/jcs/ui/layout/tiles/SwitchTileTester.java +++ b/src/test/java/jcs/ui/layout/tiles/SwitchTileTester.java @@ -226,23 +226,23 @@ public void actionPerformed(java.awt.event.ActionEvent evt) { private void northTileBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_northTileBtnActionPerformed Logger.trace(switchNorthR.id + "..."); - this.switchNorthR.setDrawRoute(this.northTileBtn.isSelected()); - this.switchNorthL.setDrawRoute(this.northTileBtn.isSelected()); + this.switchNorthR.setShowRoute(this.northTileBtn.isSelected()); + this.switchNorthL.setShowRoute(this.northTileBtn.isSelected()); }//GEN-LAST:event_northTileBtnActionPerformed private void eastTileBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_eastTileBtnActionPerformed - this.switchEastR.setDrawRoute(this.eastTileBtn.isSelected()); - this.switchEastL.setDrawRoute(this.eastTileBtn.isSelected()); + this.switchEastR.setShowRoute(this.eastTileBtn.isSelected()); + this.switchEastL.setShowRoute(this.eastTileBtn.isSelected()); }//GEN-LAST:event_eastTileBtnActionPerformed private void westTileBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_westTileBtnActionPerformed - this.switchWestR.setDrawRoute(this.westTileBtn.isSelected()); - this.switchWestL.setDrawRoute(this.westTileBtn.isSelected()); + this.switchWestR.setShowRoute(this.westTileBtn.isSelected()); + this.switchWestL.setShowRoute(this.westTileBtn.isSelected()); }//GEN-LAST:event_westTileBtnActionPerformed private void southTileBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_southTileBtnActionPerformed - this.switchSouthR.setDrawRoute(this.southTileBtn.isSelected()); - this.switchSouthL.setDrawRoute(this.southTileBtn.isSelected()); + this.switchSouthR.setShowRoute(this.southTileBtn.isSelected()); + this.switchSouthL.setShowRoute(this.southTileBtn.isSelected()); }//GEN-LAST:event_southTileBtnActionPerformed private void selectSouthTileBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_selectSouthTileBtnActionPerformed diff --git a/src/test/java/jcs/ui/layout/tiles/TileTesterFrame.java b/src/test/java/jcs/ui/layout/tiles/TileTesterFrame.java index f8881283..8d11d4ec 100644 --- a/src/test/java/jcs/ui/layout/tiles/TileTesterFrame.java +++ b/src/test/java/jcs/ui/layout/tiles/TileTesterFrame.java @@ -1 +1 @@ -/* * Copyright 2024 Frans Jacobs. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package jcs.ui.layout.tiles; import java.awt.Color; import java.awt.Point; import javax.swing.ComboBoxModel; import javax.swing.DefaultComboBoxModel; import javax.swing.UIManager; import javax.swing.UnsupportedLookAndFeelException; import jcs.entities.AccessoryBean; import jcs.entities.AccessoryBean.AccessoryValue; import jcs.entities.TileBean; import jcs.entities.TileBean.Direction; import jcs.entities.TileBean.Orientation; import static jcs.entities.TileBean.Orientation.NORTH; import static jcs.entities.TileBean.Orientation.SOUTH; import static jcs.entities.TileBean.Orientation.WEST; import jcs.entities.TileBean.TileType; import jcs.ui.layout.LayoutUtil; import jcs.ui.layout.events.TileEvent; import org.tinylog.Logger; public class TileTesterFrame extends javax.swing.JFrame { private Tile tile; public TileTesterFrame() { initComponents(); this.tileCB.setModel(createTileTypeComboBoxModel()); this.orientationCB.setModel(createOrientationComboBoxModel()); this.incomingSideCB.setModel(createOrientationComboBoxModel()); this.directionCB.setModel(createDirectionComboBoxModel(true)); createTile(); pack(); setVisible(true); } private ComboBoxModel createTileTypeComboBoxModel() { DefaultComboBoxModel tileTypeModel = new DefaultComboBoxModel(); tileTypeModel.addElement(TileBean.TileType.STRAIGHT); tileTypeModel.addElement(TileBean.TileType.STRAIGHT_DIR); tileTypeModel.addElement(TileBean.TileType.SENSOR); tileTypeModel.addElement(TileBean.TileType.SIGNAL); tileTypeModel.addElement(TileBean.TileType.END); tileTypeModel.addElement(TileBean.TileType.CROSSING); tileTypeModel.addElement(TileBean.TileType.CURVED); tileTypeModel.addElement(TileBean.TileType.SWITCH); tileTypeModel.addElement(TileBean.TileType.CROSS); return tileTypeModel; } private ComboBoxModel createOrientationComboBoxModel() { DefaultComboBoxModel orientationModel = new DefaultComboBoxModel(); orientationModel.addElement(Orientation.EAST); orientationModel.addElement(Orientation.SOUTH); orientationModel.addElement(Orientation.WEST); orientationModel.addElement(Orientation.NORTH); return orientationModel; } private ComboBoxModel createDirectionComboBoxModel(boolean dontCare) { DefaultComboBoxModel directionModel = new DefaultComboBoxModel(); if (dontCare) { directionModel.addElement(Direction.CENTER); } else { directionModel.addElement(Direction.LEFT); directionModel.addElement(Direction.RIGHT); } return directionModel; } private void createTile() { if (tile != null) { Logger.trace("Removing tile " + tile.getId()); canvas.remove(tile); tile = null; } TileType tileType = (TileType) tileCB.getSelectedItem(); Orientation orientation = (Orientation) orientationCB.getSelectedItem(); if (TileType.SWITCH == tileType || TileType.CROSS == tileType) { directionCB.setModel(createDirectionComboBoxModel(false)); } else { directionCB.setModel(createDirectionComboBoxModel(true)); } Direction direction = (Direction) this.directionCB.getSelectedItem(); boolean scale = !scaleCB.isSelected(); boolean showCenter = showCenterCB.isSelected(); int w = canvas.getWidth(); int h = canvas.getHeight(); int x = w / 2; int y = h / 2; Point tileCenter = new Point(x, y); tileCenter = LayoutUtil.snapToGrid(tileCenter); // if (TileType.CROSS == tileType) { // switch (orientation) { // case SOUTH -> { // x = w / 2 + 200; // y = h / 2 - 150; // } // case WEST -> { // x = w / 2 + 400; // y = h / 2 + 50; // } // case NORTH -> { // x = w / 2 + 200; // y = h / 2 + 250; // } // default -> { // x = w / 2; // y = h / 2 + 50; // } // } // } else { // x = w / 2 - 200; // y = h / 2 - 200; // } // Point center; // if (TileType.CROSS.equals(tileType)) { // center = new Point(x - 200, y); // } else { // center = new Point(x, y); // } Tile newTile = TileFactory.createTile(tileType, orientation, direction, tileCenter); newTile.setScaleImage(scale); newTile.setDrawCenterPoint(showCenter); //tile.setPropertyChangeListener(this); Orientation incomingSide = (Orientation) this.incomingSideCB.getSelectedItem(); newTile.setIncomingSide(incomingSide); newTile.setDrawRoute(displayRouteCB.isSelected()); newTile.setTrackRouteColor(Color.blue); Logger.trace("Adding tile " + newTile.getId() + " " + newTile.xyToString()); //this.cPanel.add((JComponent) newTile); this.canvas.add(newTile); this.tile = newTile; } private AccessoryValue getAccessoryState() { AccessoryValue value; if (greenRB.isSelected()) { value = AccessoryValue.GREEN; } else if (redRB.isSelected()) { value = AccessoryValue.RED; } else { value = AccessoryValue.OFF; } return value; } private void changeAccesoryState() { if(tile instanceof Sensor) { tile.setActive(this.redRB.isSelected()); } if (tile instanceof Switch aSwitch) { if (this.displayRouteCB.isSelected()) { aSwitch.setRouteValue(getAccessoryState()); } else { aSwitch.setAccessoryValue(getAccessoryState()); } } if (tile instanceof Signal aSignal) { if (this.greenRB.isSelected()) { aSignal.setSignalValue(AccessoryBean.SignalValue.Hp1); } else if (this.redRB.isSelected()) { aSignal.setSignalValue(AccessoryBean.SignalValue.Hp0); } else { aSignal.setSignalValue(AccessoryBean.SignalValue.OFF); } } //this.tile.repaint(); } // @Override // public void propertyChange(PropertyChangeEvent evt) { // if ("repaintTile".equals(evt.getPropertyName())) { // Tile t = (Tile) evt.getNewValue(); // Logger.trace("Tile: " + t); // //this.repaint(); // } // } // @Override // public void paint(Graphics g) { // super.paint(g); // Graphics2D g2d = (Graphics2D) g; // boolean outline = this.drawOutlineCB.isSelected(); // boolean showRoute = this.displayRouteCB.isSelected(); // tile.setDrawRoute(showRoute); // // tile.drawTile(g2d, outline); // // if (outline) { // tile.drawBounds(g2d); // tile.drawCenterPoint(g2d, Color.red); // } // } // @Override // public void paint(Graphics g) { // long started = System.currentTimeMillis(); // super.paint(g); // // long now = System.currentTimeMillis(); // Logger.trace("Duration: " + (now - started) + " ms."); // } private void changeDirection() { Direction direction = (Direction) this.directionCB.getSelectedItem(); this.tile.setDirection(direction); //if (TileType.CROSS == tile.getTileType()) { // ((Cross) tile).setWidthHeightAndOffsets(); //} //this.repaint(); } private void rotateTile() { Orientation newOrientation = tile.rotate(); orientationCB.setSelectedItem(newOrientation); // if (TileType.CROSS == tile.getTileType()) { // int x = tile.getCenterX(); // int y = tile.getCenterY(); // int w = tile.getWidth() * 10; // int h = tile.getHeight() * 10; // // //calculate a new centerpoint for cross // switch (tile.getOrientation()) { // case SOUTH -> { // x = x + w / 2; // y = y - h / 4; // } // case WEST -> { // x = x + w / 4; // y = y + h / 2; // } // case NORTH -> { // x = x - w / 2; // y = y + h / 4; // } // default -> { // x = x - w / 4; // y = y - h / 2; // } // } // tile.setCenter(new Point(x, y)); // } //this.canvas.repaint(this.tile.getTileBounds()); //tile.repaint(); } private void changeOrientation() { Orientation orientation = (Orientation) this.orientationCB.getSelectedItem(); tile.setOrientation(orientation); // if (TileType.CROSS == tile.getTileType()) { // //((Cross) tile).setWidthHeightAndOffsets(); // // int x = tile.getCenterX(); // int y = tile.getCenterY(); // int w = tile.getWidth() * 10; // int h = tile.getHeight() * 10; // // //calculate a new centerpoint for cross // switch (tile.getOrientation()) { // case SOUTH -> { // x = x + w / 2; // y = y - h / 4; // } // case WEST -> { // x = x + w / 4; // y = y + h / 2; // } // case NORTH -> { // x = x - w / 2; // y = y + h / 4; // } // default -> { // x = x - w / 4; // y = y - h / 2; // } // } // tile.setCenter(new Point(x, y)); // } //this.repaint(); } private void showRoute() { Logger.trace("Show route on tile " + tile.getId()); String tileId = tile.getId(); Orientation incomingSide = (Orientation) this.incomingSideCB.getSelectedItem(); //TileEvent tileEvent; if (tile.isJunction()) { AccessoryValue routeState = getAccessoryState(); //tileEvent = new TileEvent(tileId, true, incomingSide, routeState); } else { //tileEvent = new TileEvent(tileId, true, incomingSide); } //TileCache.fireTileEventListener(tileEvent); // ((JComponent) this.tile).repaint(); tile.setDrawRoute(displayRouteCB.isSelected()); //repaint(); } // private void showOutline() { // //repaint(); // } private void changeIncomingSide() { Orientation incomingSide = (Orientation) this.incomingSideCB.getSelectedItem(); tile.setIncomingSide(incomingSide); //this.repaint(); } /** * This method is called from within the constructor to initialize the form. WARNING: Do NOT modify this code. The content of this method is always regenerated by the Form Editor. */ @SuppressWarnings("unchecked") // //GEN-BEGIN:initComponents private void initComponents() { accessoryBG = new javax.swing.ButtonGroup(); nPanel = new javax.swing.JPanel(); tileCB = new javax.swing.JComboBox<>(); orientationCB = new javax.swing.JComboBox<>(); inComingLbl = new javax.swing.JLabel(); incomingSideCB = new javax.swing.JComboBox<>(); directionCB = new javax.swing.JComboBox<>(); rotateButton = new javax.swing.JButton(); offRB = new javax.swing.JRadioButton(); greenRB = new javax.swing.JRadioButton(); redRB = new javax.swing.JRadioButton(); displayRouteCB = new javax.swing.JCheckBox(); scaleCB = new javax.swing.JCheckBox(); showCenterCB = new javax.swing.JCheckBox(); canvas = new jcs.ui.layout.tiles.DotGridCanvas(); setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE); nPanel.setMinimumSize(new java.awt.Dimension(860, 36)); nPanel.setPreferredSize(new java.awt.Dimension(1020, 36)); java.awt.FlowLayout flowLayout1 = new java.awt.FlowLayout(java.awt.FlowLayout.LEFT); flowLayout1.setAlignOnBaseline(true); nPanel.setLayout(flowLayout1); tileCB.setPreferredSize(new java.awt.Dimension(150, 23)); tileCB.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { tileCBActionPerformed(evt); } }); nPanel.add(tileCB); orientationCB.setPreferredSize(new java.awt.Dimension(100, 23)); orientationCB.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { orientationCBActionPerformed(evt); } }); nPanel.add(orientationCB); inComingLbl.setText("Incoming Orientation"); nPanel.add(inComingLbl); incomingSideCB.setPreferredSize(new java.awt.Dimension(100, 23)); incomingSideCB.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { incomingSideCBActionPerformed(evt); } }); nPanel.add(incomingSideCB); directionCB.setPreferredSize(new java.awt.Dimension(100, 23)); directionCB.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { directionCBActionPerformed(evt); } }); nPanel.add(directionCB); rotateButton.setText("Rotate"); rotateButton.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { rotateButtonActionPerformed(evt); } }); nPanel.add(rotateButton); accessoryBG.add(offRB); offRB.setForeground(new java.awt.Color(153, 153, 153)); offRB.setSelected(true); offRB.setText("Off"); offRB.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { offRBActionPerformed(evt); } }); nPanel.add(offRB); accessoryBG.add(greenRB); greenRB.setForeground(new java.awt.Color(102, 255, 0)); greenRB.setText("Green"); greenRB.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { greenRBActionPerformed(evt); } }); nPanel.add(greenRB); accessoryBG.add(redRB); redRB.setForeground(new java.awt.Color(255, 0, 51)); redRB.setText("Red"); redRB.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { redRBActionPerformed(evt); } }); nPanel.add(redRB); displayRouteCB.setText("Route"); displayRouteCB.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { displayRouteCBActionPerformed(evt); } }); nPanel.add(displayRouteCB); scaleCB.setText("Scale"); scaleCB.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { scaleCBActionPerformed(evt); } }); nPanel.add(scaleCB); showCenterCB.setText("Center"); showCenterCB.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { showCenterCBActionPerformed(evt); } }); nPanel.add(showCenterCB); getContentPane().add(nPanel, java.awt.BorderLayout.NORTH); canvas.setPreferredSize(new java.awt.Dimension(600, 600)); getContentPane().add(canvas, java.awt.BorderLayout.CENTER); pack(); }// //GEN-END:initComponents private void rotateButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_rotateButtonActionPerformed rotateTile(); }//GEN-LAST:event_rotateButtonActionPerformed private void tileCBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_tileCBActionPerformed createTile(); }//GEN-LAST:event_tileCBActionPerformed private void orientationCBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_orientationCBActionPerformed changeOrientation(); }//GEN-LAST:event_orientationCBActionPerformed private void directionCBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_directionCBActionPerformed changeDirection(); }//GEN-LAST:event_directionCBActionPerformed private void offRBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_offRBActionPerformed changeAccesoryState(); }//GEN-LAST:event_offRBActionPerformed private void greenRBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_greenRBActionPerformed changeAccesoryState(); }//GEN-LAST:event_greenRBActionPerformed private void redRBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_redRBActionPerformed changeAccesoryState(); }//GEN-LAST:event_redRBActionPerformed private void displayRouteCBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_displayRouteCBActionPerformed showRoute(); }//GEN-LAST:event_displayRouteCBActionPerformed private void scaleCBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_scaleCBActionPerformed this.tile.setScaleImage(!this.scaleCB.isSelected()); this.tile.setBounds(this.tile.getTileBounds()); }//GEN-LAST:event_scaleCBActionPerformed private void incomingSideCBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_incomingSideCBActionPerformed changeIncomingSide(); }//GEN-LAST:event_incomingSideCBActionPerformed private void showCenterCBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_showCenterCBActionPerformed this.tile.setDrawCenterPoint(this.showCenterCB.isSelected()); }//GEN-LAST:event_showCenterCBActionPerformed /** * @param args the command line arguments */ public static void main(String args[]) { try { UIManager.setLookAndFeel("com.formdev.flatlaf.FlatLightLaf"); } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) { Logger.error(ex); } /* Create and display the form */ java.awt.EventQueue.invokeLater(() -> { TileTesterFrame app = new TileTesterFrame(); app.setTitle("Tile Tester"); app.setLocationRelativeTo(null); }); } // Variables declaration - do not modify//GEN-BEGIN:variables private javax.swing.ButtonGroup accessoryBG; private jcs.ui.layout.tiles.DotGridCanvas canvas; private javax.swing.JComboBox directionCB; private javax.swing.JCheckBox displayRouteCB; private javax.swing.JRadioButton greenRB; private javax.swing.JLabel inComingLbl; private javax.swing.JComboBox incomingSideCB; private javax.swing.JPanel nPanel; private javax.swing.JRadioButton offRB; private javax.swing.JComboBox orientationCB; private javax.swing.JRadioButton redRB; private javax.swing.JButton rotateButton; private javax.swing.JCheckBox scaleCB; private javax.swing.JCheckBox showCenterCB; private javax.swing.JComboBox tileCB; // End of variables declaration//GEN-END:variables } \ No newline at end of file +/* * Copyright 2024 Frans Jacobs. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package jcs.ui.layout.tiles; import java.awt.Color; import java.awt.Point; import javax.swing.ComboBoxModel; import javax.swing.DefaultComboBoxModel; import javax.swing.UIManager; import javax.swing.UnsupportedLookAndFeelException; import jcs.entities.AccessoryBean; import jcs.entities.AccessoryBean.AccessoryValue; import jcs.entities.TileBean; import jcs.entities.TileBean.Direction; import jcs.entities.TileBean.Orientation; import static jcs.entities.TileBean.Orientation.NORTH; import static jcs.entities.TileBean.Orientation.SOUTH; import static jcs.entities.TileBean.Orientation.WEST; import jcs.entities.TileBean.TileType; import jcs.ui.layout.LayoutUtil; import jcs.ui.layout.events.TileEvent; import org.tinylog.Logger; public class TileTesterFrame extends javax.swing.JFrame { private Tile tile; public TileTesterFrame() { initComponents(); this.tileCB.setModel(createTileTypeComboBoxModel()); this.orientationCB.setModel(createOrientationComboBoxModel()); this.incomingSideCB.setModel(createOrientationComboBoxModel()); this.directionCB.setModel(createDirectionComboBoxModel(true)); createTile(); pack(); setVisible(true); } private ComboBoxModel createTileTypeComboBoxModel() { DefaultComboBoxModel tileTypeModel = new DefaultComboBoxModel(); tileTypeModel.addElement(TileBean.TileType.STRAIGHT); tileTypeModel.addElement(TileBean.TileType.STRAIGHT_DIR); tileTypeModel.addElement(TileBean.TileType.SENSOR); tileTypeModel.addElement(TileBean.TileType.SIGNAL); tileTypeModel.addElement(TileBean.TileType.END); tileTypeModel.addElement(TileBean.TileType.CROSSING); tileTypeModel.addElement(TileBean.TileType.CURVED); tileTypeModel.addElement(TileBean.TileType.SWITCH); tileTypeModel.addElement(TileBean.TileType.CROSS); return tileTypeModel; } private ComboBoxModel createOrientationComboBoxModel() { DefaultComboBoxModel orientationModel = new DefaultComboBoxModel(); orientationModel.addElement(Orientation.EAST); orientationModel.addElement(Orientation.SOUTH); orientationModel.addElement(Orientation.WEST); orientationModel.addElement(Orientation.NORTH); return orientationModel; } private ComboBoxModel createDirectionComboBoxModel(boolean dontCare) { DefaultComboBoxModel directionModel = new DefaultComboBoxModel(); if (dontCare) { directionModel.addElement(Direction.CENTER); } else { directionModel.addElement(Direction.LEFT); directionModel.addElement(Direction.RIGHT); } return directionModel; } private void createTile() { if (tile != null) { Logger.trace("Removing tile " + tile.getId()); canvas.remove(tile); tile = null; } TileType tileType = (TileType) tileCB.getSelectedItem(); Orientation orientation = (Orientation) orientationCB.getSelectedItem(); if (TileType.SWITCH == tileType || TileType.CROSS == tileType) { directionCB.setModel(createDirectionComboBoxModel(false)); } else { directionCB.setModel(createDirectionComboBoxModel(true)); } Direction direction = (Direction) this.directionCB.getSelectedItem(); boolean scale = !scaleCB.isSelected(); boolean showCenter = showCenterCB.isSelected(); int w = canvas.getWidth(); int h = canvas.getHeight(); int x = w / 2; int y = h / 2; Point tileCenter = new Point(x, y); tileCenter = LayoutUtil.snapToGrid(tileCenter); // if (TileType.CROSS == tileType) { // switch (orientation) { // case SOUTH -> { // x = w / 2 + 200; // y = h / 2 - 150; // } // case WEST -> { // x = w / 2 + 400; // y = h / 2 + 50; // } // case NORTH -> { // x = w / 2 + 200; // y = h / 2 + 250; // } // default -> { // x = w / 2; // y = h / 2 + 50; // } // } // } else { // x = w / 2 - 200; // y = h / 2 - 200; // } // Point center; // if (TileType.CROSS.equals(tileType)) { // center = new Point(x - 200, y); // } else { // center = new Point(x, y); // } Tile newTile = TileFactory.createTile(tileType, orientation, direction, tileCenter); newTile.setScaleImage(scale); newTile.setDrawCenterPoint(showCenter); //tile.setPropertyChangeListener(this); Orientation incomingSide = (Orientation) this.incomingSideCB.getSelectedItem(); newTile.setIncomingSide(incomingSide); newTile.setShowRoute(displayRouteCB.isSelected()); newTile.setTrackRouteColor(Color.blue); Logger.trace("Adding tile " + newTile.getId() + " " + newTile.xyToString()); //this.cPanel.add((JComponent) newTile); this.canvas.add(newTile); this.tile = newTile; } private AccessoryValue getAccessoryState() { AccessoryValue value; if (greenRB.isSelected()) { value = AccessoryValue.GREEN; } else if (redRB.isSelected()) { value = AccessoryValue.RED; } else { value = AccessoryValue.OFF; } return value; } private void changeAccesoryState() { if(tile instanceof Sensor) { tile.setActive(this.redRB.isSelected()); } if (tile instanceof Switch aSwitch) { if (this.displayRouteCB.isSelected()) { aSwitch.setRouteValue(getAccessoryState()); } else { aSwitch.setAccessoryValue(getAccessoryState()); } } if (tile instanceof Signal aSignal) { if (this.greenRB.isSelected()) { aSignal.setSignalValue(AccessoryBean.SignalValue.Hp1); } else if (this.redRB.isSelected()) { aSignal.setSignalValue(AccessoryBean.SignalValue.Hp0); } else { aSignal.setSignalValue(AccessoryBean.SignalValue.OFF); } } //this.tile.repaint(); } // @Override // public void propertyChange(PropertyChangeEvent evt) { // if ("repaintTile".equals(evt.getPropertyName())) { // Tile t = (Tile) evt.getNewValue(); // Logger.trace("Tile: " + t); // //this.repaint(); // } // } // @Override // public void paint(Graphics g) { // super.paint(g); // Graphics2D g2d = (Graphics2D) g; // boolean outline = this.drawOutlineCB.isSelected(); // boolean showRoute = this.displayRouteCB.isSelected(); // tile.setShowRoute(showRoute); // // tile.drawTile(g2d, outline); // // if (outline) { // tile.drawBounds(g2d); // tile.drawCenterPoint(g2d, Color.red); // } // } // @Override // public void paint(Graphics g) { // long started = System.currentTimeMillis(); // super.paint(g); // // long now = System.currentTimeMillis(); // Logger.trace("Duration: " + (now - started) + " ms."); // } private void changeDirection() { Direction direction = (Direction) this.directionCB.getSelectedItem(); this.tile.setDirection(direction); //if (TileType.CROSS == tile.getTileType()) { // ((Cross) tile).setWidthHeightAndOffsets(); //} //this.repaint(); } private void rotateTile() { Orientation newOrientation = tile.rotate(); orientationCB.setSelectedItem(newOrientation); // if (TileType.CROSS == tile.getTileType()) { // int x = tile.getCenterX(); // int y = tile.getCenterY(); // int w = tile.getWidth() * 10; // int h = tile.getHeight() * 10; // // //calculate a new centerpoint for cross // switch (tile.getOrientation()) { // case SOUTH -> { // x = x + w / 2; // y = y - h / 4; // } // case WEST -> { // x = x + w / 4; // y = y + h / 2; // } // case NORTH -> { // x = x - w / 2; // y = y + h / 4; // } // default -> { // x = x - w / 4; // y = y - h / 2; // } // } // tile.setCenter(new Point(x, y)); // } //this.canvas.repaint(this.tile.getTileBounds()); //tile.repaint(); } private void changeOrientation() { Orientation orientation = (Orientation) this.orientationCB.getSelectedItem(); tile.setOrientation(orientation); // if (TileType.CROSS == tile.getTileType()) { // //((Cross) tile).setWidthHeightAndOffsets(); // // int x = tile.getCenterX(); // int y = tile.getCenterY(); // int w = tile.getWidth() * 10; // int h = tile.getHeight() * 10; // // //calculate a new centerpoint for cross // switch (tile.getOrientation()) { // case SOUTH -> { // x = x + w / 2; // y = y - h / 4; // } // case WEST -> { // x = x + w / 4; // y = y + h / 2; // } // case NORTH -> { // x = x - w / 2; // y = y + h / 4; // } // default -> { // x = x - w / 4; // y = y - h / 2; // } // } // tile.setCenter(new Point(x, y)); // } //this.repaint(); } private void showRoute() { Logger.trace("Show route on tile " + tile.getId()); String tileId = tile.getId(); Orientation incomingSide = (Orientation) this.incomingSideCB.getSelectedItem(); //TileEvent tileEvent; if (tile.isJunction()) { AccessoryValue routeState = getAccessoryState(); //tileEvent = new TileEvent(tileId, true, incomingSide, routeState); } else { //tileEvent = new TileEvent(tileId, true, incomingSide); } //TileCache.fireTileEventListener(tileEvent); // ((JComponent) this.tile).repaint(); tile.setShowRoute(displayRouteCB.isSelected()); //repaint(); } // private void showOutline() { // //repaint(); // } private void changeIncomingSide() { Orientation incomingSide = (Orientation) this.incomingSideCB.getSelectedItem(); tile.setIncomingSide(incomingSide); //this.repaint(); } /** * This method is called from within the constructor to initialize the form. WARNING: Do NOT modify this code. The content of this method is always regenerated by the Form Editor. */ @SuppressWarnings("unchecked") // //GEN-BEGIN:initComponents private void initComponents() { accessoryBG = new javax.swing.ButtonGroup(); nPanel = new javax.swing.JPanel(); tileCB = new javax.swing.JComboBox<>(); orientationCB = new javax.swing.JComboBox<>(); inComingLbl = new javax.swing.JLabel(); incomingSideCB = new javax.swing.JComboBox<>(); directionCB = new javax.swing.JComboBox<>(); rotateButton = new javax.swing.JButton(); offRB = new javax.swing.JRadioButton(); greenRB = new javax.swing.JRadioButton(); redRB = new javax.swing.JRadioButton(); displayRouteCB = new javax.swing.JCheckBox(); scaleCB = new javax.swing.JCheckBox(); showCenterCB = new javax.swing.JCheckBox(); canvas = new jcs.ui.layout.tiles.DotGridCanvas(); setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE); nPanel.setMinimumSize(new java.awt.Dimension(860, 36)); nPanel.setPreferredSize(new java.awt.Dimension(1020, 36)); java.awt.FlowLayout flowLayout1 = new java.awt.FlowLayout(java.awt.FlowLayout.LEFT); flowLayout1.setAlignOnBaseline(true); nPanel.setLayout(flowLayout1); tileCB.setPreferredSize(new java.awt.Dimension(150, 23)); tileCB.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { tileCBActionPerformed(evt); } }); nPanel.add(tileCB); orientationCB.setPreferredSize(new java.awt.Dimension(100, 23)); orientationCB.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { orientationCBActionPerformed(evt); } }); nPanel.add(orientationCB); inComingLbl.setText("Incoming Orientation"); nPanel.add(inComingLbl); incomingSideCB.setPreferredSize(new java.awt.Dimension(100, 23)); incomingSideCB.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { incomingSideCBActionPerformed(evt); } }); nPanel.add(incomingSideCB); directionCB.setPreferredSize(new java.awt.Dimension(100, 23)); directionCB.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { directionCBActionPerformed(evt); } }); nPanel.add(directionCB); rotateButton.setText("Rotate"); rotateButton.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { rotateButtonActionPerformed(evt); } }); nPanel.add(rotateButton); accessoryBG.add(offRB); offRB.setForeground(new java.awt.Color(153, 153, 153)); offRB.setSelected(true); offRB.setText("Off"); offRB.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { offRBActionPerformed(evt); } }); nPanel.add(offRB); accessoryBG.add(greenRB); greenRB.setForeground(new java.awt.Color(102, 255, 0)); greenRB.setText("Green"); greenRB.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { greenRBActionPerformed(evt); } }); nPanel.add(greenRB); accessoryBG.add(redRB); redRB.setForeground(new java.awt.Color(255, 0, 51)); redRB.setText("Red"); redRB.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { redRBActionPerformed(evt); } }); nPanel.add(redRB); displayRouteCB.setText("Route"); displayRouteCB.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { displayRouteCBActionPerformed(evt); } }); nPanel.add(displayRouteCB); scaleCB.setText("Scale"); scaleCB.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { scaleCBActionPerformed(evt); } }); nPanel.add(scaleCB); showCenterCB.setText("Center"); showCenterCB.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { showCenterCBActionPerformed(evt); } }); nPanel.add(showCenterCB); getContentPane().add(nPanel, java.awt.BorderLayout.NORTH); canvas.setPreferredSize(new java.awt.Dimension(600, 600)); getContentPane().add(canvas, java.awt.BorderLayout.CENTER); pack(); }// //GEN-END:initComponents private void rotateButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_rotateButtonActionPerformed rotateTile(); }//GEN-LAST:event_rotateButtonActionPerformed private void tileCBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_tileCBActionPerformed createTile(); }//GEN-LAST:event_tileCBActionPerformed private void orientationCBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_orientationCBActionPerformed changeOrientation(); }//GEN-LAST:event_orientationCBActionPerformed private void directionCBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_directionCBActionPerformed changeDirection(); }//GEN-LAST:event_directionCBActionPerformed private void offRBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_offRBActionPerformed changeAccesoryState(); }//GEN-LAST:event_offRBActionPerformed private void greenRBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_greenRBActionPerformed changeAccesoryState(); }//GEN-LAST:event_greenRBActionPerformed private void redRBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_redRBActionPerformed changeAccesoryState(); }//GEN-LAST:event_redRBActionPerformed private void displayRouteCBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_displayRouteCBActionPerformed showRoute(); }//GEN-LAST:event_displayRouteCBActionPerformed private void scaleCBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_scaleCBActionPerformed this.tile.setScaleImage(!this.scaleCB.isSelected()); this.tile.setBounds(this.tile.getTileBounds()); }//GEN-LAST:event_scaleCBActionPerformed private void incomingSideCBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_incomingSideCBActionPerformed changeIncomingSide(); }//GEN-LAST:event_incomingSideCBActionPerformed private void showCenterCBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_showCenterCBActionPerformed this.tile.setDrawCenterPoint(this.showCenterCB.isSelected()); }//GEN-LAST:event_showCenterCBActionPerformed /** * @param args the command line arguments */ public static void main(String args[]) { try { UIManager.setLookAndFeel("com.formdev.flatlaf.FlatLightLaf"); } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) { Logger.error(ex); } /* Create and display the form */ java.awt.EventQueue.invokeLater(() -> { TileTesterFrame app = new TileTesterFrame(); app.setTitle("Tile Tester"); app.setLocationRelativeTo(null); }); } // Variables declaration - do not modify//GEN-BEGIN:variables private javax.swing.ButtonGroup accessoryBG; private jcs.ui.layout.tiles.DotGridCanvas canvas; private javax.swing.JComboBox directionCB; private javax.swing.JCheckBox displayRouteCB; private javax.swing.JRadioButton greenRB; private javax.swing.JLabel inComingLbl; private javax.swing.JComboBox incomingSideCB; private javax.swing.JPanel nPanel; private javax.swing.JRadioButton offRB; private javax.swing.JComboBox orientationCB; private javax.swing.JRadioButton redRB; private javax.swing.JButton rotateButton; private javax.swing.JCheckBox scaleCB; private javax.swing.JCheckBox showCenterCB; private javax.swing.JComboBox tileCB; // End of variables declaration//GEN-END:variables } \ No newline at end of file From 93ecce40d2dc9ffcb6e310f7c138a1c2a16f3fad Mon Sep 17 00:00:00 2001 From: Frans Jacobs Date: Fri, 7 Feb 2025 17:08:03 +0100 Subject: [PATCH 14/24] Refactored the UI code to make each tile following the MVC pattern. The Tile which are extended from JComponent now follow the MVC patter, as echt tile has it own UI delegate. Next step is to add the mouse listeners in the Sensor and switched so that these components can be controlled --- src/main/java/jcs/ui/layout/tiles/Block.java | 805 +++++++++++++++++- src/main/java/jcs/ui/layout/tiles/Cross.java | 698 ++++++++++++++- .../java/jcs/ui/layout/tiles/Crossing.java | 148 +++- src/main/java/jcs/ui/layout/tiles/Curved.java | 134 ++- .../jcs/ui/layout/tiles/DefaultTileModel.java | 73 +- src/main/java/jcs/ui/layout/tiles/End.java | 109 ++- src/main/java/jcs/ui/layout/tiles/Sensor.java | 38 +- src/main/java/jcs/ui/layout/tiles/Signal.java | 566 ++++++------ .../java/jcs/ui/layout/tiles/Straight.java | 105 ++- .../ui/layout/tiles/StraightDirection.java | 48 +- src/main/java/jcs/ui/layout/tiles/Switch.java | 346 +++++++- src/main/java/jcs/ui/layout/tiles/Tile.java | 502 ++++++----- src/main/java/jcs/ui/layout/tiles/Tile1.java | 221 ----- .../java/jcs/ui/layout/tiles/TileModel.java | 6 +- .../jcs/ui/layout/tiles/enums/Rotation.java | 50 -- .../java/jcs/ui/layout/tiles/ui/BlockUI.java | 506 +++++++++++ .../java/jcs/ui/layout/tiles/ui/CrossUI.java | 362 ++++++++ .../jcs/ui/layout/tiles/ui/CrossingUI.java | 94 ++ .../java/jcs/ui/layout/tiles/ui/CurvedUI.java | 62 ++ .../java/jcs/ui/layout/tiles/ui/EndUI.java | 66 ++ .../java/jcs/ui/layout/tiles/ui/SensorUI.java | 69 ++ .../java/jcs/ui/layout/tiles/ui/SignalUI.java | 325 +++++++ .../layout/tiles/ui/StraightDirectionUI.java | 49 ++ .../jcs/ui/layout/tiles/ui/StraightUI.java | 75 ++ .../java/jcs/ui/layout/tiles/ui/SwitchUI.java | 146 ++++ .../java/jcs/ui/layout/tiles/ui/TileUI.java | 272 ++++++ .../jcs/ui/layout/tiles/TileTesterFrame.form | 455 +++++++++- .../jcs/ui/layout/tiles/TileTesterFrame.java | 2 +- 28 files changed, 5406 insertions(+), 926 deletions(-) delete mode 100644 src/main/java/jcs/ui/layout/tiles/Tile1.java delete mode 100755 src/main/java/jcs/ui/layout/tiles/enums/Rotation.java create mode 100644 src/main/java/jcs/ui/layout/tiles/ui/BlockUI.java create mode 100644 src/main/java/jcs/ui/layout/tiles/ui/CrossUI.java create mode 100644 src/main/java/jcs/ui/layout/tiles/ui/CrossingUI.java create mode 100644 src/main/java/jcs/ui/layout/tiles/ui/CurvedUI.java create mode 100644 src/main/java/jcs/ui/layout/tiles/ui/EndUI.java create mode 100644 src/main/java/jcs/ui/layout/tiles/ui/SensorUI.java create mode 100644 src/main/java/jcs/ui/layout/tiles/ui/SignalUI.java create mode 100644 src/main/java/jcs/ui/layout/tiles/ui/StraightDirectionUI.java create mode 100644 src/main/java/jcs/ui/layout/tiles/ui/StraightUI.java create mode 100644 src/main/java/jcs/ui/layout/tiles/ui/SwitchUI.java create mode 100644 src/main/java/jcs/ui/layout/tiles/ui/TileUI.java diff --git a/src/main/java/jcs/ui/layout/tiles/Block.java b/src/main/java/jcs/ui/layout/tiles/Block.java index c9f36962..faa77ea3 100755 --- a/src/main/java/jcs/ui/layout/tiles/Block.java +++ b/src/main/java/jcs/ui/layout/tiles/Block.java @@ -1 +1,804 @@ -/* * Copyright 2024 Frans Jacobs. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package jcs.ui.layout.tiles; import java.awt.BasicStroke; import java.awt.Color; import java.awt.Dimension; import java.awt.Font; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.Image; import java.awt.Point; import java.awt.Rectangle; import java.awt.geom.Ellipse2D; import java.awt.image.BufferedImage; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set; import jcs.entities.BlockBean; import jcs.entities.BlockBean.BlockState; import jcs.entities.LocomotiveBean; import jcs.entities.TileBean; import jcs.entities.TileBean.Orientation; import static jcs.entities.TileBean.Orientation.EAST; import static jcs.entities.TileBean.Orientation.NORTH; import static jcs.entities.TileBean.Orientation.SOUTH; import static jcs.entities.TileBean.Orientation.WEST; import jcs.entities.TileBean.TileType; import static jcs.ui.layout.tiles.Tile.DEFAULT_HEIGHT; import static jcs.ui.layout.tiles.Tile.DEFAULT_WIDTH; import static jcs.ui.layout.tiles.Tile.GRID; import static jcs.ui.layout.tiles.Tile.RENDER_HEIGHT; import static jcs.ui.layout.tiles.Tile.RENDER_WIDTH; import jcs.ui.util.ImageUtil; import org.tinylog.Logger; public class Block extends Tile { public static final int BLOCK_WIDTH = DEFAULT_WIDTH * 3; public static final int BLOCK_HEIGHT = DEFAULT_HEIGHT * 3; public Block(TileBean tileBean) { super(tileBean); setModel(new DefaultTileModel(tileBean.getOrientation())); changeRenderSize(); populateModel(); } public Block(Orientation orientation, Point center) { this(orientation, center.x, center.y); } public Block(Orientation orientation, int x, int y) { this(orientation, x, y, tileWidth(orientation, TileType.BLOCK), tileHeight(orientation, TileType.BLOCK)); } public Block(Orientation orientation, int x, int y, int width, int height) { super(TileType.BLOCK, orientation, x, y, width, height); setModel(new DefaultTileModel(orientation)); changeRenderSize(); } private void changeRenderSize() { Orientation tileOrientation = model.getTileOrienation(); if (Orientation.EAST == tileOrientation || Orientation.WEST == tileOrientation) { this.renderWidth = RENDER_WIDTH * 3; this.renderHeight = RENDER_HEIGHT; } else { this.renderWidth = RENDER_WIDTH; this.renderHeight = RENDER_HEIGHT * 3; } } @Override public Set getAltPoints() { int xx = this.tileX; int yy = this.tileY; Set alternatives = new HashSet<>(); if (Orientation.EAST.equals(getOrientation()) || Orientation.WEST.equals(getOrientation())) { // West Point wp = new Point((xx - DEFAULT_WIDTH), yy); Point ep = new Point((xx + DEFAULT_WIDTH), yy); alternatives.add(wp); alternatives.add(ep); } else { Point np = new Point(xx, (yy - DEFAULT_HEIGHT)); Point sp = new Point(xx, (yy + DEFAULT_HEIGHT)); alternatives.add(np); alternatives.add(sp); } return alternatives; } @Override public Set getAllPoints() { Set aps = new HashSet<>(); aps.add(getCenter()); aps.addAll(getAltPoints()); return aps; } @Override Set getAllPoints(Point center) { Set points = getAltPoints(center); points.add(center); return points; } @Override Set getAltPoints(Point center) { Set alts = new HashSet<>(); if (Orientation.EAST == model.getTileOrienation() || Orientation.WEST == model.getTileOrienation()) { // West Point wp = new Point((center.x - DEFAULT_WIDTH), center.y); Point ep = new Point((center.x + DEFAULT_WIDTH), center.y); alts.add(wp); alts.add(ep); } else { Point np = new Point(center.x, (center.y - DEFAULT_HEIGHT)); Point sp = new Point(center.x, (center.y + DEFAULT_HEIGHT)); alts.add(np); alts.add(sp); } return alts; } public Point getAltPoint(String suffix) { int cx = this.getCenterX(); int cy = this.getCenterY(); if ("+".equals(suffix)) { return switch (this.getOrientation()) { case WEST -> new Point(cx - Tile.GRID * 2, cy); case NORTH -> new Point(cx, cy - Tile.GRID * 2); case SOUTH -> new Point(cx, cy + Tile.GRID * 2); default -> new Point(cx + Tile.GRID * 2, cy); }; } else { return switch (this.getOrientation()) { case EAST -> new Point(cx - Tile.GRID * 2, cy); case SOUTH -> new Point(cx, cy - Tile.GRID * 2); case NORTH -> new Point(cx, cy + Tile.GRID * 2); default -> new Point(cx + Tile.GRID * 2, cy); }; } } @Override public boolean isBlock() { return true; } @Override public Map getNeighborPoints() { Map neighbors = new HashMap<>(); Orientation orientation = this.getOrientation(); int cx = this.getCenterX(); int cy = this.getCenterY(); // Horizontal if (Orientation.EAST == orientation || Orientation.WEST == orientation) { neighbors.put(Orientation.EAST, new Point(cx + Tile.GRID * 4, cy)); neighbors.put(Orientation.WEST, new Point(cx - Tile.GRID * 4, cy)); } else { // Vertical neighbors.put(Orientation.NORTH, new Point(cx, cy - Tile.GRID * 4)); neighbors.put(Orientation.SOUTH, new Point(cx, cy + Tile.GRID * 4)); } return neighbors; } @Override public Map getEdgePoints() { Map edgeConnections = new HashMap<>(); Orientation orientation = this.getOrientation(); int cx = this.getCenterX(); int cy = this.getCenterY(); // Horizontal if (Orientation.EAST == orientation || Orientation.WEST == orientation) { edgeConnections.put(Orientation.EAST, new Point(cx + Tile.GRID * 3, cy)); edgeConnections.put(Orientation.WEST, new Point(cx - Tile.GRID * 3, cy)); } else { // Vertical edgeConnections.put(Orientation.NORTH, new Point(cx, cy - Tile.GRID * 3)); edgeConnections.put(Orientation.SOUTH, new Point(cx, cy + Tile.GRID * 3)); } return edgeConnections; } public Point getNeighborPoint(String suffix) { int cx = getCenterX(); int cy = getCenterY(); if ("+".equals(suffix)) { return switch (getOrientation()) { case WEST -> new Point(cx - Tile.GRID * 4, cy); case NORTH -> new Point(cx, cy - Tile.GRID * 4); case SOUTH -> new Point(cx, cy + Tile.GRID * 4); default -> new Point(cx + Tile.GRID * 4, cy); }; } else { return switch (getOrientation()) { case EAST -> new Point(cx - Tile.GRID * 4, cy); case SOUTH -> new Point(cx, cy - Tile.GRID * 4); case NORTH -> new Point(cx, cy + Tile.GRID * 4); default -> new Point(cx + Tile.GRID * 4, cy); }; } } public Orientation getTravelDirection(String suffix) { if ("+".equals(suffix)) { return getOrientation(); } else { return switch (getOrientation()) { case EAST -> Orientation.WEST; case SOUTH -> Orientation.NORTH; case NORTH -> Orientation.SOUTH; default -> Orientation.EAST; }; } } @Override public String getIdSuffix(Tile other) { String suffix = null; Orientation match = null; if (isAdjacent(other)) { Map blockSides = this.getEdgePoints(); Map otherSides = other.getEdgePoints(); for (Orientation bo : Orientation.values()) { Point bp = blockSides.get(bo); if (bp != null) { for (Orientation oo : Orientation.values()) { Point op = otherSides.get(oo); if (op != null) { if (op.equals(bp)) { match = bo; break; } } } } } } Orientation tileOrientation = model.getTileOrienation(); if (match != null) { if (Orientation.EAST == tileOrientation && Orientation.EAST == match) { suffix = "+"; } if (Orientation.WEST == tileOrientation && Orientation.WEST == match) { suffix = "+"; } if (Orientation.EAST == tileOrientation && Orientation.WEST == match) { suffix = "-"; } if (Orientation.WEST == tileOrientation && Orientation.EAST == match) { suffix = "-"; } if (Orientation.NORTH == tileOrientation && Orientation.NORTH == match) { suffix = "+"; } if (Orientation.NORTH == tileOrientation && Orientation.SOUTH == match) { suffix = "-"; } if (Orientation.SOUTH == tileOrientation && Orientation.SOUTH == match) { suffix = "+"; } if (Orientation.SOUTH == tileOrientation && Orientation.NORTH == match) { suffix = "-"; } } return suffix; } @Override public Orientation rotate() { super.rotate(); Orientation tileOrientation = model.getTileOrienation(); int w = tileWidth(tileOrientation, TileType.BLOCK); int h = tileHeight(tileOrientation, TileType.BLOCK); Dimension d = new Dimension(w, h); setPreferredSize(d); setSize(d); changeRenderSize(); setBounds(getTileBounds()); return model.getTileOrienation(); } /** * Depending on the block status change the background color
* - Red: Occupied
* - Green: Departure
* - Magenta: Arrival / entering
* - Yellow: reserved
* - White: all clear / default
* * @return the Color which belong with the current Block State */ Color getBlockStateColor() { return getBlockStateColor(this.model.getBlockState()); } protected Color getBlockStateColor(BlockState blockState) { return switch (blockState) { case GHOST -> new Color(250, 0, 0); case LOCKED -> new Color(250, 250, 210); case OCCUPIED -> new Color(250, 210, 210); case OUT_OF_ORDER -> new Color(190, 190, 190); case OUTBOUND -> new Color(210, 250, 210); case INBOUND -> new Color(250, 210, 250); default -> new Color(255, 255, 255); }; } public static String getDepartureSuffix(Orientation tileOrientation, boolean reverseArrival, LocomotiveBean.Direction direction) { if (LocomotiveBean.Direction.FORWARDS == direction) { if (Orientation.EAST == tileOrientation || Orientation.SOUTH == tileOrientation) { if (reverseArrival) { return "-"; } else { return "+"; } } else { if (reverseArrival) { return "+"; } else { return "-"; } } } else { if (Orientation.EAST == tileOrientation || Orientation.SOUTH == tileOrientation) { if (reverseArrival) { return "+"; } else { return "-"; } } else { if (reverseArrival) { return "-"; } else { return "+"; } } } } @Override public void renderTile(Graphics2D g2) { int xx = 20; int yy = 50; int rw = RENDER_WIDTH * 3 - 40; int rh = 300; g2.setStroke(new BasicStroke(3, BasicStroke.CAP_SQUARE, BasicStroke.JOIN_ROUND)); g2.setPaint(Color.darkGray); g2.drawRoundRect(xx, yy, rw, rh, 15, 15); Color blockStateColor = getBlockStateColor(); //Logger.trace("Block " + this.id + " State: " + this.getBlockBean().getBlockState().getState() + " Color: " + blockStateColor.toString()); g2.setPaint(blockStateColor); g2.fillRoundRect(xx, yy, rw, rh, 15, 15); g2.setStroke(new BasicStroke(20, BasicStroke.CAP_SQUARE, BasicStroke.JOIN_ROUND)); g2.setPaint(Color.darkGray); g2.drawLine(rw + GRID, yy - 0, rw + GRID, yy + 300); //When there is a locomotive in the block mark the direction of travel. //The default, forwards is in the direction of the block orientation, i.e. the + if (model.getLocomotive() != null && model.getLocomotive().getName() != null) { renderDirectionArrow(g2); } drawName(g2); } private void renderDirectionArrow(Graphics2D g2) { //The default, forwards is in the direction of the block orientation, i.e. the + Orientation tileOrientation = model.getTileOrienation(); BlockBean bb = this.getBlockBean(); boolean reverseArrival = model.isReverseArrival(); LocomotiveBean.Direction logicalDirection; if (bb.getLogicalDirection() != null) { logicalDirection = model.getLogicalDirection(); } else { logicalDirection = model.getLocomotive().getDirection(); } String departureSuffix = model.getDepartureSuffix(); if (departureSuffix == null) { departureSuffix = Block.getDepartureSuffix(tileOrientation, reverseArrival, logicalDirection); } //Logger.trace(this.getId()+" LogicalDirection is " + (bb.getLogicalDirection() != null ? "Set" : "Not Set") + " Dir: " + logicalDirection.getDirection() + " Orientation: " + orientation.getOrientation() + " departureSuffix: " + departureSuffix); if ("+".equals(departureSuffix)) { if (Orientation.EAST == tileOrientation || Orientation.SOUTH == tileOrientation) { switch (logicalDirection) { case LocomotiveBean.Direction.FORWARDS -> { if (reverseArrival) { renderLeftArrow(g2); } else { renderRightArrow(g2); } } case LocomotiveBean.Direction.BACKWARDS -> { if (reverseArrival) { renderRightArrow(g2); } else { renderLeftArrow(g2); } } } } else { switch (logicalDirection) { case LocomotiveBean.Direction.BACKWARDS -> { if (reverseArrival) { renderLeftArrow(g2); } else { renderRightArrow(g2); } } case LocomotiveBean.Direction.FORWARDS -> { if (reverseArrival) { renderRightArrow(g2); } else { renderLeftArrow(g2); } } } } } else { if (Orientation.EAST == tileOrientation || Orientation.SOUTH == tileOrientation) { switch (logicalDirection) { case LocomotiveBean.Direction.FORWARDS -> { if (reverseArrival) { renderLeftArrow(g2); } else { renderRightArrow(g2); } } case LocomotiveBean.Direction.BACKWARDS -> { if (reverseArrival) { renderRightArrow(g2); } else { renderLeftArrow(g2); } } } } else { switch (logicalDirection) { case LocomotiveBean.Direction.BACKWARDS -> { if (reverseArrival) { renderLeftArrow(g2); } else { renderRightArrow(g2); } } case LocomotiveBean.Direction.FORWARDS -> { if (reverseArrival) { renderRightArrow(g2); } else { renderLeftArrow(g2); } } } } } } private void renderLeftArrow(Graphics2D g2) { //Logger.trace(this.getId()+" LogicalDirection is " + this.getBlockBean().getLogicalDirection() + " Orientation: " + this.getOrientation() + " departureSuffix: " + this.getBlockBean().getDepartureSuffix()); g2.fillPolygon(new int[]{0, 50, 50,}, new int[]{200, 150, 250}, 3); } private void renderRightArrow(Graphics2D g2) { //Logger.trace(this.getId()+" LogicalDirection is " + this.getBlockBean().getLogicalDirection() + " Orientation: " + this.getOrientation() + " departureSuffix: " + this.getBlockBean().getDepartureSuffix()); g2.fillPolygon(new int[]{1180, 1130, 1130,}, new int[]{200, 150, 250}, 3); } @Override public void renderTileRoute(Graphics2D g2d) { if (model.isShowBlockState()) { backgroundColor = getBlockStateColor(model.getBlockState()); } } protected void overlayLocImage() { int ww = tileImage.getWidth(); int hh = tileImage.getHeight(); Orientation tileOrientation = model.getTileOrienation(); BufferedImage overlay = new BufferedImage(ww, hh, BufferedImage.TYPE_INT_ARGB); Graphics2D g2i = overlay.createGraphics(); Image locImage = getLocImage(); if (locImage != null) { String departureSuffix = model.getDepartureSuffix(); boolean reverseImage = model.isReverseArrival(); Logger.trace("LocImage w: " + locImage.getWidth(null) + " h: " + locImage.getHeight(null)); // scale it to max h of 45 int size = 45; float aspect = (float) locImage.getHeight(null) / (float) locImage.getWidth(null); //TODO: Use Scalr? locImage = locImage.getScaledInstance(size, (int) (size * aspect), Image.SCALE_SMOOTH); //Depending on the block orientation the image needs to be rotated and flipped //Incase the departure suffix is NOT set center the locomotive image int w, h, xx, yy; switch (tileOrientation) { case WEST -> { w = locImage.getWidth(null); h = locImage.getHeight(null); if (null == departureSuffix) { xx = BLOCK_WIDTH / 2 - getWidth() / 2 + w; } else { switch (departureSuffix) { case "+" -> { xx = BLOCK_WIDTH / 2 - getWidth() / 2 + w - 25; } default -> { xx = BLOCK_WIDTH / 2 - getWidth() / 2 + w + 10; } } } yy = DEFAULT_HEIGHT / 2 - h / 2; if (reverseImage) { locImage = ImageUtil.flipVertically(locImage); } } case SOUTH -> { locImage = ImageUtil.flipHorizontally(locImage); locImage = ImageUtil.rotate(locImage, 90); w = locImage.getWidth(null); h = locImage.getHeight(null); xx = DEFAULT_WIDTH / 2 - w / 2; if (null == departureSuffix) { yy = BLOCK_HEIGHT / 2 - getHeight() / 2 + h; } else { switch (departureSuffix) { case "-" -> { yy = BLOCK_HEIGHT / 2 - getHeight() / 2 + h - 25; } default -> { yy = BLOCK_HEIGHT / 2 - getHeight() / 2 + h + 10; } } } if (reverseImage) { locImage = ImageUtil.flipHorizontally(locImage); } } case NORTH -> { locImage = ImageUtil.flipHorizontally(locImage); locImage = ImageUtil.rotate(locImage, 90); w = locImage.getWidth(null); h = locImage.getHeight(null); xx = DEFAULT_WIDTH / 2 - w / 2; if (null == departureSuffix) { int minY = BLOCK_HEIGHT / 2 - getHeight() / 2 + h; yy = minY; } else { switch (departureSuffix) { case "+" -> { yy = BLOCK_HEIGHT / 2 - getHeight() / 2 + h - 25; } default -> { yy = BLOCK_HEIGHT / 2 - getHeight() / 2 + h + 10; } } } if (reverseImage) { locImage = ImageUtil.flipHorizontally(locImage); } } default -> { w = locImage.getWidth(null); h = locImage.getHeight(null); if (null == departureSuffix) { xx = BLOCK_WIDTH / 2 - getWidth() / 2 + w; } else { switch (departureSuffix) { case "-" -> { xx = BLOCK_WIDTH / 2 - getWidth() / 2 + w - 25; } default -> { xx = BLOCK_WIDTH / 2 - getWidth() / 2 + w + 10; } } } yy = DEFAULT_HEIGHT / 2 - h / 2; if (reverseImage) { locImage = ImageUtil.flipVertically(locImage); } } } g2i.drawImage(tileImage, 0, 0, null); g2i.drawImage(locImage, xx, yy, null); g2i.dispose(); tileImage = overlay; } } private Image getLocImage() { if (model.getLocomotive() != null && model.getLocomotive().getLocIcon() != null) { return model.getLocomotive().getLocIcon(); } else { return null; } } public String getBlockText() { String blockText; if (blockBean != null && blockBean.getDescription() != null) { if (blockBean.getLocomotive() != null && blockBean.getLocomotive().getName() != null && BlockState.GHOST != blockBean.getBlockState()) { blockText = blockBean.getLocomotive().getName(); } else { if (blockBean.getDescription().length() > 0) { blockText = blockBean.getDescription(); } else { blockText = getId(); } } } else { // Design mode show description when available if (blockBean != null && blockBean.getDescription() != null && blockBean.getDescription().length() > 0) { blockText = blockBean.getDescription(); } else { blockText = getId(); } } return blockText; } @Override public void drawName(Graphics2D g2d) { if (!model.isOverlayImage()) { g2d.setPaint(Color.black); Font currentFont = g2d.getFont(); Font newFont = currentFont.deriveFont(currentFont.getSize() * 10.0F); g2d.setFont(newFont); String blockText = getBlockText(); // Scale the text if necessary int textWidth = g2d.getFontMetrics().stringWidth(blockText); double fontscale = 10.0; if (textWidth > 845) { fontscale = fontscale * 847.0 / textWidth; newFont = currentFont.deriveFont(currentFont.getSize() * (float) fontscale); g2d.setFont(newFont); textWidth = g2d.getFontMetrics().stringWidth(blockText); } int textHeight = g2d.getFontMetrics().getHeight(); Orientation tileOrientation = model.getTileOrienation(); switch (tileOrientation) { case EAST -> { drawRotate(g2d, ((RENDER_WIDTH * 3) / 2) - textWidth / 2, RENDER_GRID + textHeight / 3, 0, blockText); } case WEST -> { drawRotate(g2d, ((RENDER_WIDTH * 3) / 2) + textWidth / 2, RENDER_GRID - textHeight / 3, 180, blockText); } case NORTH -> { drawRotate(g2d, ((RENDER_WIDTH * 3) / 2) - textWidth / 2, RENDER_GRID + textHeight / 3, 0, blockText); } case SOUTH -> { drawRotate(g2d, ((RENDER_WIDTH * 3) / 2) + textWidth / 2, RENDER_GRID - textHeight / 3, 180, blockText); } } // reset to the original font newFont = currentFont.deriveFont(currentFont.getSize() * 1.0F); g2d.setFont(newFont); } } @Override public Rectangle getTileBounds() { int multiplier = (model.isScaleImage() ? 1 : 10); Orientation tileOrientation = model.getTileOrienation(); int xx, yy; if (tileOrientation == Orientation.EAST || tileOrientation == Orientation.WEST) { xx = tileX - GRID * multiplier - GRID * multiplier * 2; yy = tileY - GRID * multiplier; } else { xx = tileX - GRID * multiplier; yy = tileY - GRID * multiplier - GRID * multiplier * 2; } if (model.isScaleImage()) { return new Rectangle(xx, yy, tileWidth(tileOrientation, TileType.BLOCK), tileHeight(tileOrientation, TileType.BLOCK)); } else { return new Rectangle(xx, yy, renderWidth, renderHeight); } } @Override protected void paintComponent(Graphics g) { long started = System.currentTimeMillis(); Graphics2D g2 = (Graphics2D) g.create(); drawTile(g2); g2.dispose(); if (model.isOverlayImage()) { overlayLocImage(); } g.drawImage(tileImage, 0, 0, null); long now = System.currentTimeMillis(); Logger.trace(id + " Duration: " + (now - started) + " ms."); } @Override protected void drawCenterPoint(Graphics2D g2d, Color color, double size) { //A block has 2 alternate points //1st square //2nd square holds the centerpoint //3rd square Orientation tileOrientation = model.getTileOrienation(); double dX1, dX2, dX3, dY1, dY2, dY3; if (Orientation.EAST == tileOrientation || Orientation.WEST == tileOrientation) { dX1 = renderWidth / 3 / 2 - size / 2 / 2; dY1 = renderHeight / 2 - size / 2 / 2; dX2 = renderWidth / 2 - size / 2; dY2 = renderHeight / 2 - size / 2; dX3 = renderWidth - renderWidth / 3 / 2 - size / 2 / 2; dY3 = renderHeight / 2 - size / 2 / 2; } else { dX1 = renderWidth / 2 - size / 2 / 2; dY1 = renderHeight / 3 / 2 - size / 2 / 2; dX2 = renderHeight / 2 - size / 2; dY2 = renderWidth / 2 - size / 2; dY3 = renderWidth / 2 - size / 2 / 2; dX3 = renderHeight - renderHeight / 3 / 2 - size / 2 / 2; } g2d.setColor(color); g2d.fill(new Ellipse2D.Double(dX1, dY1, size / 2, size / 2)); g2d.fill(new Ellipse2D.Double(dX2, dY2, size, size)); g2d.fill(new Ellipse2D.Double(dX3, dY3, size / 2, size / 2)); } } \ No newline at end of file +/* + * Copyright 2024 Frans Jacobs. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package jcs.ui.layout.tiles; + +import java.awt.Dimension; +import java.awt.Point; +import java.awt.Rectangle; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; +import javax.swing.UIManager; +import jcs.entities.LocomotiveBean; +import jcs.entities.TileBean; +import jcs.entities.TileBean.Orientation; +import static jcs.entities.TileBean.Orientation.EAST; +import static jcs.entities.TileBean.Orientation.NORTH; +import static jcs.entities.TileBean.Orientation.SOUTH; +import static jcs.entities.TileBean.Orientation.WEST; +import jcs.entities.TileBean.TileType; +import static jcs.ui.layout.tiles.Tile.DEFAULT_HEIGHT; +import static jcs.ui.layout.tiles.Tile.DEFAULT_WIDTH; +import static jcs.ui.layout.tiles.Tile.GRID; +import jcs.ui.layout.tiles.ui.StraightUI; +import jcs.ui.layout.tiles.ui.TileUI; + +public class Block extends Tile { + + public static final int BLOCK_WIDTH = DEFAULT_WIDTH * 3; + public static final int BLOCK_HEIGHT = DEFAULT_HEIGHT * 3; + + public Block(TileBean tileBean) { + super(tileBean); + setModel(new DefaultTileModel(tileBean.getOrientation())); + //changeRenderSize(); + + populateModel(); + initUI(); + } + + public Block(Orientation orientation, Point center) { + this(orientation, center.x, center.y); + } + + public Block(Orientation orientation, int x, int y) { + this(orientation, x, y, tileWidth(orientation, TileType.BLOCK), tileHeight(orientation, TileType.BLOCK)); + } + + public Block(Orientation orientation, int x, int y, int width, int height) { + super(TileType.BLOCK, orientation, x, y, width, height); + setModel(new DefaultTileModel(orientation)); + //changeRenderSize(); + initUI(); + } + + private void initUI() { + updateUI(); + } + + @Override + public String getUIClassID() { + return StraightUI.UI_CLASS_ID; + } + + @Override + public void updateUI() { + UIManager.put(TileUI.UI_CLASS_ID, "jcs.ui.layout.tiles.ui.BlockUI"); + setUI((TileUI) UIManager.getUI(this)); + invalidate(); + } + +// private void changeRenderSize() { +// Orientation tileOrientation = model.getTileOrienation(); +// if (Orientation.EAST == tileOrientation || Orientation.WEST == tileOrientation) { +// this.renderWidth = RENDER_WIDTH * 3; +// this.renderHeight = RENDER_HEIGHT; +// } else { +// this.renderWidth = RENDER_WIDTH; +// this.renderHeight = RENDER_HEIGHT * 3; +// } +// } + @Override + public Set getAltPoints() { + int xx = this.tileX; + int yy = this.tileY; + Set alternatives = new HashSet<>(); + + if (Orientation.EAST.equals(getOrientation()) || Orientation.WEST.equals(getOrientation())) { + // West + Point wp = new Point((xx - DEFAULT_WIDTH), yy); + Point ep = new Point((xx + DEFAULT_WIDTH), yy); + alternatives.add(wp); + alternatives.add(ep); + } else { + Point np = new Point(xx, (yy - DEFAULT_HEIGHT)); + Point sp = new Point(xx, (yy + DEFAULT_HEIGHT)); + alternatives.add(np); + alternatives.add(sp); + } + + return alternatives; + } + + @Override + public Set getAllPoints() { + Set aps = new HashSet<>(); + aps.add(getCenter()); + aps.addAll(getAltPoints()); + return aps; + } + + @Override + Set getAllPoints(Point center) { + Set points = getAltPoints(center); + points.add(center); + return points; + } + + @Override + Set getAltPoints(Point center) { + Set alts = new HashSet<>(); + + if (Orientation.EAST == model.getTileOrienation() || Orientation.WEST == model.getTileOrienation()) { + // West + Point wp = new Point((center.x - DEFAULT_WIDTH), center.y); + Point ep = new Point((center.x + DEFAULT_WIDTH), center.y); + alts.add(wp); + alts.add(ep); + } else { + Point np = new Point(center.x, (center.y - DEFAULT_HEIGHT)); + Point sp = new Point(center.x, (center.y + DEFAULT_HEIGHT)); + alts.add(np); + alts.add(sp); + } + + return alts; + } + + public Point getAltPoint(String suffix) { + int cx = this.getCenterX(); + int cy = this.getCenterY(); + if ("+".equals(suffix)) { + return switch (this.getOrientation()) { + case WEST -> + new Point(cx - Tile.GRID * 2, cy); + case NORTH -> + new Point(cx, cy - Tile.GRID * 2); + case SOUTH -> + new Point(cx, cy + Tile.GRID * 2); + default -> + new Point(cx + Tile.GRID * 2, cy); + }; + } else { + return switch (this.getOrientation()) { + case EAST -> + new Point(cx - Tile.GRID * 2, cy); + case SOUTH -> + new Point(cx, cy - Tile.GRID * 2); + case NORTH -> + new Point(cx, cy + Tile.GRID * 2); + default -> + new Point(cx + Tile.GRID * 2, cy); + }; + } + } + + @Override + public boolean isBlock() { + return true; + } + + @Override + public Map getNeighborPoints() { + Map neighbors = new HashMap<>(); + Orientation orientation = this.getOrientation(); + int cx = this.getCenterX(); + int cy = this.getCenterY(); + + // Horizontal + if (Orientation.EAST == orientation || Orientation.WEST == orientation) { + neighbors.put(Orientation.EAST, new Point(cx + Tile.GRID * 4, cy)); + neighbors.put(Orientation.WEST, new Point(cx - Tile.GRID * 4, cy)); + } else { + // Vertical + neighbors.put(Orientation.NORTH, new Point(cx, cy - Tile.GRID * 4)); + neighbors.put(Orientation.SOUTH, new Point(cx, cy + Tile.GRID * 4)); + } + return neighbors; + } + + @Override + public Map getEdgePoints() { + Map edgeConnections = new HashMap<>(); + Orientation orientation = this.getOrientation(); + int cx = this.getCenterX(); + int cy = this.getCenterY(); + + // Horizontal + if (Orientation.EAST == orientation || Orientation.WEST == orientation) { + edgeConnections.put(Orientation.EAST, new Point(cx + Tile.GRID * 3, cy)); + edgeConnections.put(Orientation.WEST, new Point(cx - Tile.GRID * 3, cy)); + } else { + // Vertical + edgeConnections.put(Orientation.NORTH, new Point(cx, cy - Tile.GRID * 3)); + edgeConnections.put(Orientation.SOUTH, new Point(cx, cy + Tile.GRID * 3)); + } + return edgeConnections; + } + + public Point getNeighborPoint(String suffix) { + int cx = getCenterX(); + int cy = getCenterY(); + if ("+".equals(suffix)) { + return switch (getOrientation()) { + case WEST -> + new Point(cx - Tile.GRID * 4, cy); + case NORTH -> + new Point(cx, cy - Tile.GRID * 4); + case SOUTH -> + new Point(cx, cy + Tile.GRID * 4); + default -> + new Point(cx + Tile.GRID * 4, cy); + }; + } else { + return switch (getOrientation()) { + case EAST -> + new Point(cx - Tile.GRID * 4, cy); + case SOUTH -> + new Point(cx, cy - Tile.GRID * 4); + case NORTH -> + new Point(cx, cy + Tile.GRID * 4); + default -> + new Point(cx + Tile.GRID * 4, cy); + }; + } + } + + public Orientation getTravelDirection(String suffix) { + if ("+".equals(suffix)) { + return getOrientation(); + } else { + return switch (getOrientation()) { + case EAST -> + Orientation.WEST; + case SOUTH -> + Orientation.NORTH; + case NORTH -> + Orientation.SOUTH; + default -> + Orientation.EAST; + }; + } + } + + @Override + public String getIdSuffix(Tile other) { + String suffix = null; + Orientation match = null; + if (isAdjacent(other)) { + Map blockSides = this.getEdgePoints(); + Map otherSides = other.getEdgePoints(); + + for (Orientation bo : Orientation.values()) { + Point bp = blockSides.get(bo); + + if (bp != null) { + for (Orientation oo : Orientation.values()) { + Point op = otherSides.get(oo); + if (op != null) { + if (op.equals(bp)) { + match = bo; + break; + } + } + } + } + } + } + + Orientation tileOrientation = model.getTileOrienation(); + if (match != null) { + if (Orientation.EAST == tileOrientation && Orientation.EAST == match) { + suffix = "+"; + } + if (Orientation.WEST == tileOrientation && Orientation.WEST == match) { + suffix = "+"; + } + if (Orientation.EAST == tileOrientation && Orientation.WEST == match) { + suffix = "-"; + } + if (Orientation.WEST == tileOrientation && Orientation.EAST == match) { + suffix = "-"; + } + if (Orientation.NORTH == tileOrientation && Orientation.NORTH == match) { + suffix = "+"; + } + if (Orientation.NORTH == tileOrientation && Orientation.SOUTH == match) { + suffix = "-"; + } + if (Orientation.SOUTH == tileOrientation && Orientation.SOUTH == match) { + suffix = "+"; + } + if (Orientation.SOUTH == tileOrientation && Orientation.NORTH == match) { + suffix = "-"; + } + } + return suffix; + } + + @Override + public Orientation rotate() { + super.rotate(); + + Orientation tileOrientation = model.getTileOrienation(); + int w = tileWidth(tileOrientation, TileType.BLOCK); + int h = tileHeight(tileOrientation, TileType.BLOCK); + + Dimension d = new Dimension(w, h); + setPreferredSize(d); + setSize(d); + //changeRenderSize(); + + setBounds(getTileBounds()); + return model.getTileOrienation(); + } + + /** + * Depending on the block status change the background color
+ * - Red: Occupied
+ * - Green: Departure
+ * - Magenta: Arrival / entering
+ * - Yellow: reserved
+ * - White: all clear / default
+ * + * @return the Color which belong with the current Block State + */ +// Color getBlockStateColor() { +// return getBlockStateColor(this.model.getBlockState()); +// } +// protected Color getBlockStateColor(BlockState blockState) { +// return switch (blockState) { +// case GHOST -> +// new Color(250, 0, 0); +// case LOCKED -> +// new Color(250, 250, 210); +// case OCCUPIED -> +// new Color(250, 210, 210); +// case OUT_OF_ORDER -> +// new Color(190, 190, 190); +// case OUTBOUND -> +// new Color(210, 250, 210); +// case INBOUND -> +// new Color(250, 210, 250); +// default -> +// new Color(255, 255, 255); +// }; +// } + public static String getDepartureSuffix(Orientation tileOrientation, boolean reverseArrival, LocomotiveBean.Direction direction) { + if (LocomotiveBean.Direction.FORWARDS == direction) { + if (Orientation.EAST == tileOrientation || Orientation.SOUTH == tileOrientation) { + if (reverseArrival) { + return "-"; + } else { + return "+"; + } + } else { + if (reverseArrival) { + return "+"; + } else { + return "-"; + } + } + } else { + if (Orientation.EAST == tileOrientation || Orientation.SOUTH == tileOrientation) { + if (reverseArrival) { + return "+"; + } else { + return "-"; + } + } else { + if (reverseArrival) { + return "-"; + } else { + return "+"; + } + } + } + } + +// @Override +// public void renderTile(Graphics2D g2) { +// int xx = 20; +// int yy = 50; +// int rw = RENDER_WIDTH * 3 - 40; +// int rh = 300; +// +// g2.setStroke(new BasicStroke(3, BasicStroke.CAP_SQUARE, BasicStroke.JOIN_ROUND)); +// +// g2.setPaint(Color.darkGray); +// g2.drawRoundRect(xx, yy, rw, rh, 15, 15); +// +// Color blockStateColor = getBlockStateColor(); +// //Logger.trace("Block " + this.id + " State: " + this.getBlockBean().getBlockState().getState() + " Color: " + blockStateColor.toString()); +// g2.setPaint(blockStateColor); +// g2.fillRoundRect(xx, yy, rw, rh, 15, 15); +// +// g2.setStroke(new BasicStroke(20, BasicStroke.CAP_SQUARE, BasicStroke.JOIN_ROUND)); +// g2.setPaint(Color.darkGray); +// g2.drawLine(rw + GRID, yy - 0, rw + GRID, yy + 300); +// +// //When there is a locomotive in the block mark the direction of travel. +// //The default, forwards is in the direction of the block orientation, i.e. the + +// if (model.getLocomotive() != null && model.getLocomotive().getName() != null) { +// renderDirectionArrow(g2); +// } +// +// drawName(g2); +// } +// private void renderDirectionArrow(Graphics2D g2) { +// //The default, forwards is in the direction of the block orientation, i.e. the + +// Orientation tileOrientation = model.getTileOrienation(); +// BlockBean bb = this.getBlockBean(); +// boolean reverseArrival = model.isReverseArrival(); +// +// LocomotiveBean.Direction logicalDirection; +// if (bb.getLogicalDirection() != null) { +// logicalDirection = model.getLogicalDirection(); +// } else { +// logicalDirection = model.getLocomotive().getDirection(); +// } +// +// String departureSuffix = model.getDepartureSuffix(); +// if (departureSuffix == null) { +// departureSuffix = Block.getDepartureSuffix(tileOrientation, reverseArrival, logicalDirection); +// } +// +// //Logger.trace(this.getId()+" LogicalDirection is " + (bb.getLogicalDirection() != null ? "Set" : "Not Set") + " Dir: " + logicalDirection.getDirection() + " Orientation: " + orientation.getOrientation() + " departureSuffix: " + departureSuffix); +// if ("+".equals(departureSuffix)) { +// if (Orientation.EAST == tileOrientation || Orientation.SOUTH == tileOrientation) { +// switch (logicalDirection) { +// case LocomotiveBean.Direction.FORWARDS -> { +// if (reverseArrival) { +// renderLeftArrow(g2); +// } else { +// renderRightArrow(g2); +// } +// } +// case LocomotiveBean.Direction.BACKWARDS -> { +// if (reverseArrival) { +// renderRightArrow(g2); +// } else { +// renderLeftArrow(g2); +// } +// } +// } +// } else { +// switch (logicalDirection) { +// case LocomotiveBean.Direction.BACKWARDS -> { +// if (reverseArrival) { +// renderLeftArrow(g2); +// } else { +// renderRightArrow(g2); +// } +// } +// case LocomotiveBean.Direction.FORWARDS -> { +// if (reverseArrival) { +// renderRightArrow(g2); +// } else { +// renderLeftArrow(g2); +// } +// } +// } +// } +// } else { +// if (Orientation.EAST == tileOrientation || Orientation.SOUTH == tileOrientation) { +// switch (logicalDirection) { +// case LocomotiveBean.Direction.FORWARDS -> { +// if (reverseArrival) { +// renderLeftArrow(g2); +// } else { +// renderRightArrow(g2); +// } +// } +// case LocomotiveBean.Direction.BACKWARDS -> { +// if (reverseArrival) { +// renderRightArrow(g2); +// } else { +// renderLeftArrow(g2); +// } +// } +// } +// } else { +// switch (logicalDirection) { +// case LocomotiveBean.Direction.BACKWARDS -> { +// if (reverseArrival) { +// renderLeftArrow(g2); +// } else { +// renderRightArrow(g2); +// } +// } +// case LocomotiveBean.Direction.FORWARDS -> { +// if (reverseArrival) { +// renderRightArrow(g2); +// } else { +// renderLeftArrow(g2); +// } +// } +// } +// } +// } +// } +// private void renderLeftArrow(Graphics2D g2) { +// //Logger.trace(this.getId()+" LogicalDirection is " + this.getBlockBean().getLogicalDirection() + " Orientation: " + this.getOrientation() + " departureSuffix: " + this.getBlockBean().getDepartureSuffix()); +// g2.fillPolygon(new int[]{0, 50, 50,}, new int[]{200, 150, 250}, 3); +// } +// private void renderRightArrow(Graphics2D g2) { +// //Logger.trace(this.getId()+" LogicalDirection is " + this.getBlockBean().getLogicalDirection() + " Orientation: " + this.getOrientation() + " departureSuffix: " + this.getBlockBean().getDepartureSuffix()); +// g2.fillPolygon(new int[]{1180, 1130, 1130,}, new int[]{200, 150, 250}, 3); +// } +// @Override +// public void renderTileRoute(Graphics2D g2d) { +// if (model.isShowBlockState()) { +// backgroundColor = getBlockStateColor(model.getBlockState()); +// } +// } +// protected void overlayLocImage() { +// int ww = tileImage.getWidth(); +// int hh = tileImage.getHeight(); +// Orientation tileOrientation = model.getTileOrienation(); +// +// BufferedImage overlay = new BufferedImage(ww, hh, BufferedImage.TYPE_INT_ARGB); +// Graphics2D g2i = overlay.createGraphics(); +// +// Image locImage = getLocImage(); +// if (locImage != null) { +// String departureSuffix = model.getDepartureSuffix(); +// boolean reverseImage = model.isReverseArrival(); +// +// Logger.trace("LocImage w: " + locImage.getWidth(null) + " h: " + locImage.getHeight(null)); +// // scale it to max h of 45 +// int size = 45; +// float aspect = (float) locImage.getHeight(null) / (float) locImage.getWidth(null); +// //TODO: Use Scalr? +// locImage = locImage.getScaledInstance(size, (int) (size * aspect), Image.SCALE_SMOOTH); +// +// //Depending on the block orientation the image needs to be rotated and flipped +// //Incase the departure suffix is NOT set center the locomotive image +// int w, h, xx, yy; +// switch (tileOrientation) { +// case WEST -> { +// w = locImage.getWidth(null); +// h = locImage.getHeight(null); +// +// if (null == departureSuffix) { +// xx = BLOCK_WIDTH / 2 - getWidth() / 2 + w; +// } else { +// switch (departureSuffix) { +// case "+" -> { +// xx = BLOCK_WIDTH / 2 - getWidth() / 2 + w - 25; +// } +// default -> { +// xx = BLOCK_WIDTH / 2 - getWidth() / 2 + w + 10; +// } +// } +// } +// yy = DEFAULT_HEIGHT / 2 - h / 2; +// +// if (reverseImage) { +// locImage = ImageUtil.flipVertically(locImage); +// } +// } +// case SOUTH -> { +// locImage = ImageUtil.flipHorizontally(locImage); +// locImage = ImageUtil.rotate(locImage, 90); +// +// w = locImage.getWidth(null); +// h = locImage.getHeight(null); +// xx = DEFAULT_WIDTH / 2 - w / 2; +// +// if (null == departureSuffix) { +// yy = BLOCK_HEIGHT / 2 - getHeight() / 2 + h; +// } else { +// switch (departureSuffix) { +// case "-" -> { +// yy = BLOCK_HEIGHT / 2 - getHeight() / 2 + h - 25; +// } +// default -> { +// yy = BLOCK_HEIGHT / 2 - getHeight() / 2 + h + 10; +// } +// } +// } +// if (reverseImage) { +// locImage = ImageUtil.flipHorizontally(locImage); +// } +// } +// case NORTH -> { +// locImage = ImageUtil.flipHorizontally(locImage); +// locImage = ImageUtil.rotate(locImage, 90); +// +// w = locImage.getWidth(null); +// h = locImage.getHeight(null); +// xx = DEFAULT_WIDTH / 2 - w / 2; +// +// if (null == departureSuffix) { +// int minY = BLOCK_HEIGHT / 2 - getHeight() / 2 + h; +// yy = minY; +// } else { +// switch (departureSuffix) { +// case "+" -> { +// yy = BLOCK_HEIGHT / 2 - getHeight() / 2 + h - 25; +// } +// default -> { +// yy = BLOCK_HEIGHT / 2 - getHeight() / 2 + h + 10; +// } +// } +// } +// if (reverseImage) { +// locImage = ImageUtil.flipHorizontally(locImage); +// } +// } +// default -> { +// w = locImage.getWidth(null); +// h = locImage.getHeight(null); +// if (null == departureSuffix) { +// xx = BLOCK_WIDTH / 2 - getWidth() / 2 + w; +// } else { +// switch (departureSuffix) { +// case "-" -> { +// xx = BLOCK_WIDTH / 2 - getWidth() / 2 + w - 25; +// } +// default -> { +// xx = BLOCK_WIDTH / 2 - getWidth() / 2 + w + 10; +// } +// } +// } +// yy = DEFAULT_HEIGHT / 2 - h / 2; +// +// if (reverseImage) { +// locImage = ImageUtil.flipVertically(locImage); +// } +// } +// } +// +// g2i.drawImage(tileImage, 0, 0, null); +// g2i.drawImage(locImage, xx, yy, null); +// g2i.dispose(); +// tileImage = overlay; +// } +// } +// private Image getLocImage() { +// if (model.getLocomotive() != null && model.getLocomotive().getLocIcon() != null) { +// return model.getLocomotive().getLocIcon(); +// } else { +// return null; +// } +// } +// public String getBlockText() { +// String blockText; +// if (blockBean != null && blockBean.getDescription() != null) { +// if (blockBean.getLocomotive() != null && blockBean.getLocomotive().getName() != null && BlockState.GHOST != blockBean.getBlockState()) { +// blockText = blockBean.getLocomotive().getName(); +// } else { +// if (blockBean.getDescription().length() > 0) { +// blockText = blockBean.getDescription(); +// } else { +// blockText = getId(); +// } +// } +// } else { +// // Design mode show description when available +// if (blockBean != null && blockBean.getDescription() != null && blockBean.getDescription().length() > 0) { +// blockText = blockBean.getDescription(); +// } else { +// blockText = getId(); +// } +// } +// return blockText; +// } +// @Override +// public void drawName(Graphics2D g2d) { +// if (!model.isOverlayImage()) { +// g2d.setPaint(Color.black); +// +// Font currentFont = g2d.getFont(); +// Font newFont = currentFont.deriveFont(currentFont.getSize() * 10.0F); +// g2d.setFont(newFont); +// +// String blockText = getBlockText(); +// +// // Scale the text if necessary +// int textWidth = g2d.getFontMetrics().stringWidth(blockText); +// double fontscale = 10.0; +// if (textWidth > 845) { +// fontscale = fontscale * 847.0 / textWidth; +// newFont = currentFont.deriveFont(currentFont.getSize() * (float) fontscale); +// g2d.setFont(newFont); +// textWidth = g2d.getFontMetrics().stringWidth(blockText); +// } +// +// int textHeight = g2d.getFontMetrics().getHeight(); +// Orientation tileOrientation = model.getTileOrienation(); +// +// switch (tileOrientation) { +// case EAST -> { +// drawRotate(g2d, ((RENDER_WIDTH * 3) / 2) - textWidth / 2, RENDER_GRID + textHeight / 3, 0, blockText); +// } +// case WEST -> { +// drawRotate(g2d, ((RENDER_WIDTH * 3) / 2) + textWidth / 2, RENDER_GRID - textHeight / 3, 180, blockText); +// } +// case NORTH -> { +// drawRotate(g2d, ((RENDER_WIDTH * 3) / 2) - textWidth / 2, RENDER_GRID + textHeight / 3, 0, blockText); +// } +// case SOUTH -> { +// drawRotate(g2d, ((RENDER_WIDTH * 3) / 2) + textWidth / 2, RENDER_GRID - textHeight / 3, 180, blockText); +// } +// } +// // reset to the original font +// newFont = currentFont.deriveFont(currentFont.getSize() * 1.0F); +// g2d.setFont(newFont); +// } +// } + @Override + public Rectangle getTileBounds() { + int multiplier = (model.isScaleImage() ? 1 : 10); + Orientation tileOrientation = model.getTileOrienation(); + + int xx, yy; + if (tileOrientation == Orientation.EAST || tileOrientation == Orientation.WEST) { + xx = tileX - GRID * multiplier - GRID * multiplier * 2; + yy = tileY - GRID * multiplier; + } else { + xx = tileX - GRID * multiplier; + yy = tileY - GRID * multiplier - GRID * multiplier * 2; + } + + if (model.isScaleImage()) { + return new Rectangle(xx, yy, tileWidth(tileOrientation, TileType.BLOCK), tileHeight(tileOrientation, TileType.BLOCK)); + } else { + int renderWidth = getUI().getRenderWidth(); + int renderHeight = getUI().getRenderHeight(); + + return new Rectangle(xx, yy, renderWidth, renderHeight); + } + } + +// @Override +// protected void paintComponent(Graphics g) { +// long started = System.currentTimeMillis(); +// +// Graphics2D g2 = (Graphics2D) g.create(); +// drawTile(g2); +// g2.dispose(); +// +// if (model.isOverlayImage()) { +// overlayLocImage(); +// } +// +// g.drawImage(tileImage, 0, 0, null); +// long now = System.currentTimeMillis(); +// Logger.trace(id + " Duration: " + (now - started) + " ms."); +// } +// @Override +// protected void drawCenterPoint(Graphics2D g2d, Color color, double size) { +// //A block has 2 alternate points +// //1st square +// //2nd square holds the centerpoint +// //3rd square +// Orientation tileOrientation = model.getTileOrienation(); +// double dX1, dX2, dX3, dY1, dY2, dY3; +// if (Orientation.EAST == tileOrientation || Orientation.WEST == tileOrientation) { +// dX1 = renderWidth / 3 / 2 - size / 2 / 2; +// dY1 = renderHeight / 2 - size / 2 / 2; +// dX2 = renderWidth / 2 - size / 2; +// dY2 = renderHeight / 2 - size / 2; +// dX3 = renderWidth - renderWidth / 3 / 2 - size / 2 / 2; +// dY3 = renderHeight / 2 - size / 2 / 2; +// } else { +// dX1 = renderWidth / 2 - size / 2 / 2; +// dY1 = renderHeight / 3 / 2 - size / 2 / 2; +// dX2 = renderHeight / 2 - size / 2; +// dY2 = renderWidth / 2 - size / 2; +// dY3 = renderWidth / 2 - size / 2 / 2; +// dX3 = renderHeight - renderHeight / 3 / 2 - size / 2 / 2; +// } +// +// g2d.setColor(color); +// g2d.fill(new Ellipse2D.Double(dX1, dY1, size / 2, size / 2)); +// g2d.fill(new Ellipse2D.Double(dX2, dY2, size, size)); +// g2d.fill(new Ellipse2D.Double(dX3, dY3, size / 2, size / 2)); +// } +} diff --git a/src/main/java/jcs/ui/layout/tiles/Cross.java b/src/main/java/jcs/ui/layout/tiles/Cross.java index 419a693f..33b902f0 100644 --- a/src/main/java/jcs/ui/layout/tiles/Cross.java +++ b/src/main/java/jcs/ui/layout/tiles/Cross.java @@ -1 +1,697 @@ -/* * Copyright 2023 Frans Jacobs. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package jcs.ui.layout.tiles; import java.awt.BasicStroke; import java.awt.Color; import java.awt.Dimension; import java.awt.Graphics2D; import java.awt.Point; import java.awt.Rectangle; import java.awt.geom.Ellipse2D; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set; import jcs.entities.AccessoryBean.AccessoryValue; import static jcs.entities.AccessoryBean.AccessoryValue.GREEN; import static jcs.entities.AccessoryBean.AccessoryValue.RED; import jcs.entities.TileBean; import jcs.entities.TileBean.Direction; import jcs.entities.TileBean.Orientation; import static jcs.entities.TileBean.Orientation.NORTH; import static jcs.entities.TileBean.Orientation.SOUTH; import static jcs.entities.TileBean.Orientation.WEST; import jcs.entities.TileBean.TileType; import static jcs.ui.layout.tiles.Tile.DEFAULT_HEIGHT; import static jcs.ui.layout.tiles.Tile.DEFAULT_WIDTH; import static jcs.ui.layout.tiles.Tile.GRID; import static jcs.ui.layout.tiles.Tile.tileHeight; import static jcs.ui.layout.tiles.Tile.tileWidth; public class Cross extends Switch { public static final int CROSS_WIDTH = DEFAULT_WIDTH * 2; public static final int CROSS_HEIGHT = DEFAULT_HEIGHT * 2; public static final Color VERY_LIGHT_RED = new Color(255, 102, 102); public static final Color LIGHT_RED = new Color(255, 51, 51); public static final Color DARK_RED = new Color(204, 0, 0); public static final Color VERY_LIGHT_GREEN = new Color(102, 255, 102); public static final Color LIGHT_GREEN = new Color(0, 255, 51); public static final Color DARK_GREEN = new Color(0, 153, 0); public Cross(Orientation orientation, Direction direction, Point center) { this(orientation, direction, center.x, center.y); } public Cross(Orientation orientation, Direction direction, int x, int y) { this(orientation, direction, x, y, tileWidth(orientation, TileType.CROSS), tileHeight(orientation, TileType.CROSS)); } public Cross(Orientation orientation, Direction direction, int x, int y, int width, int height) { super(TileType.CROSS, orientation, direction, x, y, width, height); changeRenderSizeAndOffsets(); } public Cross(TileBean tileBean) { super(tileBean, tileWidth(tileBean.getOrientation(), TileType.CROSS), tileHeight(tileBean.getOrientation(), TileType.CROSS)); changeRenderSizeAndOffsets(); } /** * A Cross has a width in horizontal position of 2 tiles and a height of 1 tile in Vertical position.
* * @return the Set of points which mark the position of the Cross */ @Override public Set getAltPoints() { return getAltPoints(getCenter()); } @Override public Set getAllPoints() { return getAllPoints(getCenter()); } @Override public Set getAllPoints(Point center) { Set aps = getAltPoints(center); aps.add(center); return aps; } @Override Set getAltPoints(Point center) { Set alts = new HashSet<>(); switch (getOrientation()) { case SOUTH -> { Point sp = new Point(center.x, (center.y + DEFAULT_HEIGHT)); alts.add(sp); } case WEST -> { Point wp = new Point((center.x - DEFAULT_WIDTH), center.y); alts.add(wp); } case NORTH -> { Point np = new Point(center.x, (center.y - DEFAULT_HEIGHT)); alts.add(np); } default -> { //East so default Point ep = new Point((center.x + DEFAULT_WIDTH), center.y); alts.add(ep); } } return alts; } @Override public Map getNeighborPoints() { Map neighbors = new HashMap<>(); Orientation orientation = this.getOrientation(); Direction direction = this.getDirection(); int cx = this.getCenterX(); int cy = this.getCenterY(); switch (orientation) { case SOUTH -> { neighbors.put(Orientation.NORTH, new Point(cx, cy - Tile.GRID * 2)); neighbors.put(Orientation.SOUTH, new Point(cx, cy + Tile.GRID * 4)); if (Direction.LEFT == direction) { neighbors.put(Orientation.EAST, new Point(cx + Tile.GRID * 2, cy + Tile.GRID * 2)); neighbors.put(Orientation.WEST, new Point(cx - Tile.GRID * 2, cy)); } else { neighbors.put(Orientation.EAST, new Point(cx + Tile.GRID * 2, cy)); neighbors.put(Orientation.WEST, new Point(cx - Tile.GRID * 2, cy + Tile.GRID * 2)); } } case WEST -> { neighbors.put(Orientation.EAST, new Point(cx + Tile.GRID * 2, cy)); neighbors.put(Orientation.WEST, new Point(cx - Tile.GRID * 4, cy)); if (Direction.LEFT == direction) { neighbors.put(Orientation.NORTH, new Point(cx, cy - Tile.GRID * 2)); neighbors.put(Orientation.SOUTH, new Point(cx - Tile.GRID * 2, cy + Tile.GRID * 2)); } else { neighbors.put(Orientation.NORTH, new Point(cx - Tile.GRID * 2, cy - Tile.GRID * 2)); neighbors.put(Orientation.SOUTH, new Point(cx, cy + Tile.GRID * 2)); } } case NORTH -> { neighbors.put(Orientation.NORTH, new Point(cx, cy - Tile.GRID * 4)); neighbors.put(Orientation.SOUTH, new Point(cx, cy + Tile.GRID * 2)); if (Direction.LEFT == direction) { neighbors.put(Orientation.EAST, new Point(cx + Tile.GRID * 2, cy)); neighbors.put(Orientation.WEST, new Point(cx - Tile.GRID * 2, cy - Tile.GRID * 2)); } else { neighbors.put(Orientation.EAST, new Point(cx + Tile.GRID * 2, cy - Tile.GRID * 2)); neighbors.put(Orientation.WEST, new Point(cx - Tile.GRID * 2, cy)); } } default -> { //EAST neighbors.put(Orientation.EAST, new Point(cx + Tile.GRID * 4, cy)); neighbors.put(Orientation.WEST, new Point(cx - Tile.GRID * 2, cy)); if (Direction.LEFT == direction) { neighbors.put(Orientation.NORTH, new Point(cx + Tile.GRID * 2, cy - Tile.GRID * 2)); neighbors.put(Orientation.SOUTH, new Point(cx, cy + Tile.GRID * 2)); } else { neighbors.put(Orientation.NORTH, new Point(cx, cy - Tile.GRID * 2)); neighbors.put(Orientation.SOUTH, new Point(cx + Tile.GRID * 2, cy + Tile.GRID * 2)); } } } return neighbors; } @Override public Map getEdgePoints() { Map edgeConnections = new HashMap<>(); Orientation orientation = this.getOrientation(); Direction direction = this.getDirection(); int cx = this.getCenterX(); int cy = this.getCenterY(); switch (orientation) { case SOUTH -> { edgeConnections.put(Orientation.NORTH, new Point(cx, cy - Tile.GRID)); edgeConnections.put(Orientation.SOUTH, new Point(cx, cy + Tile.GRID * 3)); if (Direction.LEFT == direction) { edgeConnections.put(Orientation.EAST, new Point(cx + Tile.GRID, cy + Tile.GRID * 2)); edgeConnections.put(Orientation.WEST, new Point(cx - Tile.GRID, cy)); } else { edgeConnections.put(Orientation.EAST, new Point(cx + Tile.GRID, cy)); edgeConnections.put(Orientation.WEST, new Point(cx - Tile.GRID, cy + Tile.GRID * 2)); } } case WEST -> { edgeConnections.put(Orientation.EAST, new Point(cx + Tile.GRID, cy)); edgeConnections.put(Orientation.WEST, new Point(cx - Tile.GRID * 3, cy)); if (Direction.LEFT == direction) { edgeConnections.put(Orientation.NORTH, new Point(cx, cy - Tile.GRID)); edgeConnections.put(Orientation.SOUTH, new Point(cx - Tile.GRID * 2, cy + Tile.GRID)); } else { edgeConnections.put(Orientation.NORTH, new Point(cx - Tile.GRID * 2, cy - Tile.GRID)); edgeConnections.put(Orientation.SOUTH, new Point(cx, cy + Tile.GRID)); } } case NORTH -> { edgeConnections.put(Orientation.NORTH, new Point(cx, cy - Tile.GRID * 3)); edgeConnections.put(Orientation.SOUTH, new Point(cx, cy + Tile.GRID)); if (Direction.LEFT == direction) { edgeConnections.put(Orientation.EAST, new Point(cx + Tile.GRID, cy)); edgeConnections.put(Orientation.WEST, new Point(cx - Tile.GRID, cy - Tile.GRID * 2)); } else { edgeConnections.put(Orientation.EAST, new Point(cx + Tile.GRID, cy - Tile.GRID * 2)); edgeConnections.put(Orientation.WEST, new Point(cx - Tile.GRID, cy)); } } default -> { //EAST edgeConnections.put(Orientation.EAST, new Point(cx + Tile.GRID * 3, cy)); edgeConnections.put(Orientation.WEST, new Point(cx - Tile.GRID, cy)); if (Direction.LEFT == direction) { edgeConnections.put(Orientation.NORTH, new Point(cx + Tile.GRID * 2, cy - Tile.GRID)); edgeConnections.put(Orientation.SOUTH, new Point(cx, cy + Tile.GRID)); } else { edgeConnections.put(Orientation.NORTH, new Point(cx, cy - Tile.GRID)); edgeConnections.put(Orientation.SOUTH, new Point(cx + Tile.GRID * 2, cy + Tile.GRID)); } } } return edgeConnections; } @Override protected void renderStraight(Graphics2D g2, Color color) { int xx, yy, w, h; xx = 0; yy = 170; w = RENDER_WIDTH; h = 60; g2.setStroke(new BasicStroke(4, BasicStroke.JOIN_MITER, BasicStroke.JOIN_ROUND)); g2.setPaint(color); g2.fillRect(xx, yy, w, h); } @Override protected void renderRouteStraight(Graphics2D g2, Color color) { int xx, yy, w, h; xx = 0; yy = 190; w = RENDER_WIDTH; h = 20; g2.setStroke(new BasicStroke(4, BasicStroke.JOIN_MITER, BasicStroke.JOIN_ROUND)); g2.setPaint(color); g2.fillRect(xx, yy, w, h); } protected void renderStraight2(Graphics2D g2, Color color) { int xx, yy, w, h; xx = RENDER_WIDTH; yy = 170; w = RENDER_WIDTH; h = 60; g2.setStroke(new BasicStroke(4, BasicStroke.JOIN_MITER, BasicStroke.JOIN_ROUND)); g2.setPaint(color); g2.fillRect(xx, yy, w, h); } protected void renderRouteStraight2(Graphics2D g2, Color color) { int xx, yy, w, h; xx = RENDER_WIDTH; yy = 190; w = RENDER_WIDTH; h = 20; g2.setStroke(new BasicStroke(4, BasicStroke.JOIN_MITER, BasicStroke.JOIN_ROUND)); g2.setPaint(color); g2.fillRect(xx, yy, w, h); } @Override protected void renderDiagonal(Graphics2D g2, Color color) { int[] xPoints, yPoints; if (Direction.RIGHT.equals(getDirection())) { xPoints = new int[]{400, 400, 167, 230}; yPoints = new int[]{170, 230, 0, 0}; } else { xPoints = new int[]{400, 400, 170, 230}; yPoints = new int[]{230, 170, 400, 400}; } g2.setStroke(new BasicStroke(4, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND)); g2.setPaint(color); g2.fillPolygon(xPoints, yPoints, xPoints.length); } @Override protected void renderRouteDiagonal(Graphics2D g2, Color color) { int[] xPoints, yPoints; if (Direction.RIGHT.equals(getDirection())) { xPoints = new int[]{420, 400, 190, 210}; yPoints = new int[]{210, 210, 0, 0}; } else { xPoints = new int[]{400, 400, 190, 210}; yPoints = new int[]{210, 190, 400, 400}; } g2.setStroke(new BasicStroke(4, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND)); g2.setPaint(color); g2.fillPolygon(xPoints, yPoints, xPoints.length); } protected void renderDiagonal2(Graphics2D g2, Color color) { int[] xPoints, yPoints; if (Direction.RIGHT.equals(getDirection())) { xPoints = new int[]{400, 400, 570, 630}; yPoints = new int[]{170, 230, 400, 400}; } else { xPoints = new int[]{400, 400, 570, 630}; yPoints = new int[]{230, 170, 0, 0}; } g2.setStroke(new BasicStroke(4, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND)); g2.setPaint(color); g2.fillPolygon(xPoints, yPoints, xPoints.length); } protected void renderRouteDiagonal2(Graphics2D g2, Color color) { int[] xPoints, yPoints; if (Direction.RIGHT.equals(getDirection())) { xPoints = new int[]{400, 380, 590, 610}; yPoints = new int[]{190, 190, 400, 400}; } else { xPoints = new int[]{400, 380, 590, 610}; yPoints = new int[]{210, 210, 0, 0}; } g2.setStroke(new BasicStroke(4, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND)); g2.setPaint(color); g2.setPaint(Color.cyan); g2.fillPolygon(xPoints, yPoints, xPoints.length); } @Override public void renderTile(Graphics2D g2) { if (accessoryValue == null) { this.accessoryValue = AccessoryValue.OFF; } switch (accessoryValue) { case RED -> { renderStraight2(g2, Cross.LIGHT_RED); renderDiagonal(g2, Cross.LIGHT_RED); renderStraight(g2, Cross.DARK_RED); renderDiagonal2(g2, Cross.DARK_RED); } case GREEN -> { renderDiagonal(g2, Cross.VERY_LIGHT_GREEN); renderDiagonal2(g2, Cross.VERY_LIGHT_GREEN); renderStraight(g2, Cross.DARK_GREEN); renderStraight2(g2, Cross.DARK_GREEN); } default -> { renderStraight(g2, trackColor); renderStraight2(g2, trackColor); renderDiagonal(g2, trackColor); renderDiagonal2(g2, trackColor); } } } @Override public void renderTileRoute(Graphics2D g2) { if (routeValue == null) { routeValue = AccessoryValue.OFF; } if (incomingSide == null) { incomingSide = getOrientation(); } if (isHorizontal()) { if (AccessoryValue.GREEN == routeValue && (Orientation.NORTH == incomingSide || Orientation.SOUTH == incomingSide)) { renderRouteDiagonal(g2, trackRouteColor); renderRouteDiagonal2(g2, trackRouteColor); } else if (AccessoryValue.GREEN == routeValue && (Orientation.EAST == incomingSide || Orientation.WEST == incomingSide)) { renderRouteStraight(g2, trackRouteColor); renderRouteStraight2(g2, trackRouteColor); } else if (AccessoryValue.RED == routeValue && Orientation.EAST == getOrientation()) { if (Direction.RIGHT == getDirection() && (Orientation.EAST == incomingSide || Orientation.NORTH == incomingSide)) { renderRouteStraight2(g2, trackRouteColor); renderRouteDiagonal(g2, trackRouteColor); } else if (Direction.RIGHT == getDirection() && (Orientation.WEST == incomingSide || Orientation.SOUTH == incomingSide)) { renderRouteDiagonal2(g2, trackRouteColor); renderRouteStraight(g2, trackRouteColor); } else if (Direction.LEFT == getDirection() && (Orientation.EAST == incomingSide || Orientation.SOUTH == incomingSide)) { renderRouteStraight2(g2, trackRouteColor); renderRouteDiagonal(g2, trackRouteColor); } else if (Direction.LEFT == getDirection() && (Orientation.WEST == incomingSide || Orientation.NORTH == incomingSide)) { renderRouteStraight(g2, trackColor); renderRouteDiagonal2(g2, trackColor); } } else if (AccessoryValue.RED == routeValue && Orientation.WEST == getOrientation()) { if (Direction.RIGHT == getDirection() && (Orientation.EAST == incomingSide || Orientation.NORTH == incomingSide)) { renderRouteStraight(g2, trackRouteColor); renderRouteDiagonal2(g2, trackRouteColor); } else if (Direction.RIGHT == getDirection() && (Orientation.WEST == incomingSide || Orientation.SOUTH == incomingSide)) { renderRouteDiagonal(g2, trackRouteColor); renderRouteStraight2(g2, trackRouteColor); } else if (Direction.LEFT == getDirection() && (Orientation.EAST == incomingSide || Orientation.SOUTH == incomingSide)) { renderRouteStraight(g2, trackRouteColor); renderRouteDiagonal2(g2, trackRouteColor); } else if (Direction.LEFT == getDirection() && (Orientation.WEST == incomingSide || Orientation.NORTH == incomingSide)) { renderRouteStraight2(g2, trackColor); renderRouteDiagonal(g2, trackColor); } } } else { if (AccessoryValue.GREEN == routeValue && (Orientation.NORTH == incomingSide || Orientation.SOUTH == incomingSide)) { renderRouteStraight(g2, trackRouteColor); renderRouteStraight2(g2, trackRouteColor); } else if (AccessoryValue.GREEN == routeValue && (Orientation.EAST == incomingSide || Orientation.WEST == incomingSide)) { renderRouteDiagonal(g2, trackRouteColor); renderRouteDiagonal2(g2, trackRouteColor); } else if (AccessoryValue.RED == routeValue && Orientation.SOUTH == getOrientation()) { if (Direction.RIGHT == getDirection() && (Orientation.EAST == incomingSide || Orientation.SOUTH == incomingSide)) { renderRouteStraight2(g2, trackRouteColor); renderRouteDiagonal(g2, trackRouteColor); } else if (Direction.RIGHT == getDirection() && (Orientation.WEST == incomingSide || Orientation.NORTH == incomingSide)) { renderRouteDiagonal2(g2, trackRouteColor); renderRouteStraight(g2, trackRouteColor); } else if (Direction.LEFT == getDirection() && (Orientation.EAST == incomingSide || Orientation.NORTH == incomingSide)) { renderRouteStraight(g2, trackRouteColor); renderRouteDiagonal2(g2, trackRouteColor); } else if (Direction.LEFT == getDirection() && (Orientation.WEST == incomingSide || Orientation.SOUTH == incomingSide)) { renderRouteStraight2(g2, trackColor); renderRouteDiagonal(g2, trackColor); } } else if (AccessoryValue.RED == routeValue && Orientation.NORTH == getOrientation()) { if (Direction.RIGHT == getDirection() && (Orientation.EAST == incomingSide || Orientation.SOUTH == incomingSide)) { renderRouteStraight(g2, trackRouteColor); renderRouteDiagonal2(g2, trackRouteColor); } else if (Direction.RIGHT == getDirection() && (Orientation.WEST == incomingSide || Orientation.NORTH == incomingSide)) { renderRouteDiagonal(g2, trackRouteColor); renderRouteStraight2(g2, trackRouteColor); } else if (Direction.LEFT == getDirection() && (Orientation.EAST == incomingSide || Orientation.NORTH == incomingSide)) { renderRouteStraight2(g2, trackRouteColor); renderRouteDiagonal(g2, trackRouteColor); } else if (Direction.LEFT == getDirection() && (Orientation.WEST == incomingSide || Orientation.SOUTH == incomingSide)) { renderRouteStraight(g2, trackColor); renderRouteDiagonal2(g2, trackColor); } } } } @Override public AccessoryValue accessoryValueForRoute(Orientation from, Orientation to) { if (from != null && to != null && this.getDirection() != null) { switch (this.getDirection()) { case LEFT -> { if (this.isHorizontal()) { if ((from == Orientation.WEST && to == Orientation.EAST) || (from == Orientation.EAST && to == Orientation.WEST)) { return AccessoryValue.GREEN; } else if ((from == Orientation.NORTH && to == Orientation.SOUTH) || (from == Orientation.SOUTH && to == Orientation.NORTH)) { return AccessoryValue.GREEN; } else if ((from == Orientation.NORTH && to == Orientation.WEST) || (from == Orientation.WEST && to == Orientation.NORTH)) { return AccessoryValue.RED; } else if ((from == Orientation.EAST && to == Orientation.SOUTH) || (from == Orientation.SOUTH && to == Orientation.EAST)) { return AccessoryValue.RED; } else { return AccessoryValue.OFF; } } else { //Vertical if ((from == Orientation.WEST && to == Orientation.EAST) || (from == Orientation.EAST && to == Orientation.WEST)) { return AccessoryValue.GREEN; } else if ((from == Orientation.NORTH && to == Orientation.SOUTH) || (from == Orientation.SOUTH && to == Orientation.NORTH)) { return AccessoryValue.GREEN; } else if ((from == Orientation.SOUTH && to == Orientation.WEST) || (from == Orientation.WEST && to == Orientation.SOUTH)) { return AccessoryValue.RED; } else if ((from == Orientation.EAST && to == Orientation.NORTH) || (from == Orientation.NORTH && to == Orientation.EAST)) { return AccessoryValue.RED; } else { return AccessoryValue.OFF; } } } case RIGHT -> { if (this.isHorizontal()) { if ((from == Orientation.WEST && to == Orientation.EAST) || (from == Orientation.EAST && to == Orientation.WEST)) { return AccessoryValue.GREEN; } else if ((from == Orientation.NORTH && to == Orientation.SOUTH) || (from == Orientation.SOUTH && to == Orientation.NORTH)) { return AccessoryValue.GREEN; } else if ((from == Orientation.NORTH && to == Orientation.EAST) || (from == Orientation.EAST && to == Orientation.NORTH)) { return AccessoryValue.RED; } else if ((from == Orientation.WEST && to == Orientation.SOUTH) || (from == Orientation.SOUTH && to == Orientation.WEST)) { return AccessoryValue.RED; } else { return AccessoryValue.OFF; } } else { //Vertical if ((from == Orientation.WEST && to == Orientation.EAST) || (from == Orientation.EAST && to == Orientation.WEST)) { return AccessoryValue.GREEN; } else if ((from == Orientation.NORTH && to == Orientation.SOUTH) || (from == Orientation.SOUTH && to == Orientation.NORTH)) { return AccessoryValue.GREEN; } else if ((from == Orientation.SOUTH && to == Orientation.EAST) || (from == Orientation.EAST && to == Orientation.SOUTH)) { return AccessoryValue.RED; } else if ((from == Orientation.WEST && to == Orientation.NORTH) || (from == Orientation.NORTH && to == Orientation.WEST)) { return AccessoryValue.RED; } else { return AccessoryValue.OFF; } } } default -> { return AccessoryValue.OFF; } } } else { return AccessoryValue.OFF; } } @Override protected void drawCenterPoint(Graphics2D g2d, Color color, double size) { //A Cross has 1 alternate point //1st square holds the centerpoint //2nd square double dX1, dX2, dY1, dY2; Orientation tileOrientation = model.getTileOrienation(); switch (tileOrientation) { case SOUTH -> { dX1 = renderWidth / 2 - size / 2; dY1 = renderHeight / 2 - renderHeight / 4 - size / 2; dX2 = renderWidth / 2 + renderWidth - size / 4; dY2 = renderHeight / 2 - renderHeight / 4 - size / 4; } case WEST -> { dX1 = renderWidth / 2 - renderWidth / 4 - size / 2; dY1 = renderHeight / 2 - size / 2; dX2 = renderWidth / 2 + renderWidth / 4 - size / 4; dY2 = renderHeight / 2 - size / 4; } case NORTH -> { dX1 = renderWidth / 2 - size / 2; dY1 = renderHeight / 2 - renderHeight / 4 - size / 2; dX2 = renderWidth / 2 + renderWidth - size / 4; dY2 = renderHeight / 2 - renderHeight / 4 - size / 4; } default -> { //East dX1 = renderWidth / 2 - renderWidth / 4 - size / 2; dY1 = renderHeight / 2 - size / 2; dX2 = renderWidth / 2 + renderWidth / 4 - size / 4; dY2 = renderHeight / 2 - size / 4; } } g2d.setColor(color); g2d.fill(new Ellipse2D.Double(dX1, dY1, size, size)); g2d.fill(new Ellipse2D.Double(dX2, dY2, size / 2, size / 2)); } @Override public Rectangle getTileBounds() { Orientation tileOrientation = model.getTileOrienation(); int xx, yy, w, h, multiplier; if (model.isScaleImage()) { w = tileWidth(tileOrientation, TileType.CROSS); h = tileHeight(tileOrientation, TileType.CROSS); multiplier = 1; } else { w = renderWidth; h = renderHeight; multiplier = 10; } switch (tileOrientation) { case SOUTH -> { xx = tileX - GRID * multiplier; yy = tileY - GRID * multiplier; } case WEST -> { xx = tileX - GRID * multiplier - GRID * 2 * multiplier; yy = tileY - GRID * multiplier; } case NORTH -> { xx = tileX - GRID * multiplier; yy = tileY - GRID * multiplier - GRID * 2 * multiplier; } default -> { //East xx = tileX - GRID * multiplier; yy = tileY - GRID * multiplier; } } if (model.isScaleImage()) { return new Rectangle(xx, yy, w, h); } else { return new Rectangle(xx, yy, renderWidth, renderHeight); } } private void changeRenderSizeAndOffsets() { //Reset offsets this.offsetY = 0; this.renderOffsetY = 0; this.offsetX = 0; this.renderOffsetX = 0; if (isHorizontal()) { this.renderWidth = RENDER_GRID * 4; this.renderHeight = RENDER_GRID * 2; this.offsetY = 0; this.renderOffsetY = 0; } else { this.renderWidth = RENDER_GRID * 2; this.renderHeight = RENDER_GRID * 4; this.offsetX = 0; this.renderOffsetX = 0; } //Due to the asymetical shape (center is on the left) //the offset has to be changed with the rotation Orientation tileOrientation = model.getTileOrienation(); switch (tileOrientation) { case SOUTH -> { this.offsetY = +GRID; this.renderOffsetY = RENDER_GRID; } case WEST -> { this.offsetX = -GRID; this.renderOffsetX = -RENDER_GRID; } case NORTH -> { this.offsetY = -GRID; this.renderOffsetY = -RENDER_GRID; } default -> { //East so default this.offsetX = +GRID; this.renderOffsetX = +RENDER_GRID; } } } @Override public Orientation rotate() { super.rotate(); Orientation tileOrientation = model.getTileOrienation(); int w = tileWidth(tileOrientation, TileType.CROSS); int h = tileHeight(tileOrientation, TileType.CROSS); Dimension d = new Dimension(w, h); setPreferredSize(d); setSize(d); changeRenderSizeAndOffsets(); setBounds(getTileBounds()); return tileOrientation; } } \ No newline at end of file +/* + * Copyright 2023 Frans Jacobs. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package jcs.ui.layout.tiles; + +import java.awt.Color; +import java.awt.Dimension; +import java.awt.Point; +import java.awt.Rectangle; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; +import javax.swing.UIManager; +import jcs.entities.AccessoryBean.AccessoryValue; +import jcs.entities.TileBean; +import jcs.entities.TileBean.Direction; +import jcs.entities.TileBean.Orientation; +import static jcs.entities.TileBean.Orientation.NORTH; +import static jcs.entities.TileBean.Orientation.SOUTH; +import static jcs.entities.TileBean.Orientation.WEST; +import jcs.entities.TileBean.TileType; +import static jcs.ui.layout.tiles.Tile.DEFAULT_HEIGHT; +import static jcs.ui.layout.tiles.Tile.DEFAULT_WIDTH; +import static jcs.ui.layout.tiles.Tile.GRID; +import static jcs.ui.layout.tiles.Tile.tileHeight; +import static jcs.ui.layout.tiles.Tile.tileWidth; +import jcs.ui.layout.tiles.ui.CrossUI; +import jcs.ui.layout.tiles.ui.TileUI; + +public class Cross extends Switch { + + public static final int CROSS_WIDTH = DEFAULT_WIDTH * 2; + public static final int CROSS_HEIGHT = DEFAULT_HEIGHT * 2; + + public static final Color VERY_LIGHT_RED = new Color(255, 102, 102); + public static final Color LIGHT_RED = new Color(255, 51, 51); + public static final Color DARK_RED = new Color(204, 0, 0); + + public static final Color VERY_LIGHT_GREEN = new Color(102, 255, 102); + public static final Color LIGHT_GREEN = new Color(0, 255, 51); + public static final Color DARK_GREEN = new Color(0, 153, 0); + + public Cross(Orientation orientation, Direction direction, Point center) { + this(orientation, direction, center.x, center.y); + } + + public Cross(Orientation orientation, Direction direction, int x, int y) { + this(orientation, direction, x, y, tileWidth(orientation, TileType.CROSS), tileHeight(orientation, TileType.CROSS)); + } + + public Cross(Orientation orientation, Direction direction, int x, int y, int width, int height) { + super(TileType.CROSS, orientation, direction, x, y, width, height); + changeRenderSizeAndOffsets(); + } + + public Cross(TileBean tileBean) { + super(tileBean, tileWidth(tileBean.getOrientation(), TileType.CROSS), tileHeight(tileBean.getOrientation(), TileType.CROSS)); + changeRenderSizeAndOffsets(); + } + + @Override + public String getUIClassID() { + return CrossUI.UI_CLASS_ID; + } + + @Override + public void updateUI() { + UIManager.put(TileUI.UI_CLASS_ID, "jcs.ui.layout.tiles.ui.CrossUI"); + setUI((TileUI) UIManager.getUI(this)); + invalidate(); + } + + /** + * A Cross has a width in horizontal position of 2 tiles and a height of 1 tile in Vertical position.
+ * + * @return the Set of points which mark the position of the Cross + */ + @Override + public Set getAltPoints() { + return getAltPoints(getCenter()); + } + + @Override + public Set getAllPoints() { + return getAllPoints(getCenter()); + } + + @Override + public Set getAllPoints(Point center) { + Set aps = getAltPoints(center); + aps.add(center); + return aps; + } + + @Override + Set getAltPoints(Point center) { + Set alts = new HashSet<>(); + switch (getOrientation()) { + case SOUTH -> { + Point sp = new Point(center.x, (center.y + DEFAULT_HEIGHT)); + alts.add(sp); + } + case WEST -> { + Point wp = new Point((center.x - DEFAULT_WIDTH), center.y); + alts.add(wp); + } + case NORTH -> { + Point np = new Point(center.x, (center.y - DEFAULT_HEIGHT)); + alts.add(np); + } + default -> { + //East so default + Point ep = new Point((center.x + DEFAULT_WIDTH), center.y); + alts.add(ep); + } + } + return alts; + } + + @Override + public Map getNeighborPoints() { + Map neighbors = new HashMap<>(); + Orientation orientation = this.getOrientation(); + Direction direction = this.getDirection(); + int cx = this.getCenterX(); + int cy = this.getCenterY(); + + switch (orientation) { + case SOUTH -> { + neighbors.put(Orientation.NORTH, new Point(cx, cy - Tile.GRID * 2)); + neighbors.put(Orientation.SOUTH, new Point(cx, cy + Tile.GRID * 4)); + + if (Direction.LEFT == direction) { + neighbors.put(Orientation.EAST, new Point(cx + Tile.GRID * 2, cy + Tile.GRID * 2)); + neighbors.put(Orientation.WEST, new Point(cx - Tile.GRID * 2, cy)); + } else { + neighbors.put(Orientation.EAST, new Point(cx + Tile.GRID * 2, cy)); + neighbors.put(Orientation.WEST, new Point(cx - Tile.GRID * 2, cy + Tile.GRID * 2)); + } + } + case WEST -> { + neighbors.put(Orientation.EAST, new Point(cx + Tile.GRID * 2, cy)); + neighbors.put(Orientation.WEST, new Point(cx - Tile.GRID * 4, cy)); + + if (Direction.LEFT == direction) { + neighbors.put(Orientation.NORTH, new Point(cx, cy - Tile.GRID * 2)); + neighbors.put(Orientation.SOUTH, new Point(cx - Tile.GRID * 2, cy + Tile.GRID * 2)); + } else { + neighbors.put(Orientation.NORTH, new Point(cx - Tile.GRID * 2, cy - Tile.GRID * 2)); + neighbors.put(Orientation.SOUTH, new Point(cx, cy + Tile.GRID * 2)); + } + } + case NORTH -> { + neighbors.put(Orientation.NORTH, new Point(cx, cy - Tile.GRID * 4)); + neighbors.put(Orientation.SOUTH, new Point(cx, cy + Tile.GRID * 2)); + + if (Direction.LEFT == direction) { + neighbors.put(Orientation.EAST, new Point(cx + Tile.GRID * 2, cy)); + neighbors.put(Orientation.WEST, new Point(cx - Tile.GRID * 2, cy - Tile.GRID * 2)); + } else { + neighbors.put(Orientation.EAST, new Point(cx + Tile.GRID * 2, cy - Tile.GRID * 2)); + neighbors.put(Orientation.WEST, new Point(cx - Tile.GRID * 2, cy)); + } + } + default -> { + //EAST + neighbors.put(Orientation.EAST, new Point(cx + Tile.GRID * 4, cy)); + neighbors.put(Orientation.WEST, new Point(cx - Tile.GRID * 2, cy)); + + if (Direction.LEFT == direction) { + neighbors.put(Orientation.NORTH, new Point(cx + Tile.GRID * 2, cy - Tile.GRID * 2)); + neighbors.put(Orientation.SOUTH, new Point(cx, cy + Tile.GRID * 2)); + } else { + neighbors.put(Orientation.NORTH, new Point(cx, cy - Tile.GRID * 2)); + neighbors.put(Orientation.SOUTH, new Point(cx + Tile.GRID * 2, cy + Tile.GRID * 2)); + } + } + } + return neighbors; + } + + @Override + public Map getEdgePoints() { + Map edgeConnections = new HashMap<>(); + Orientation orientation = getOrientation(); + Direction direction = getDirection(); + int cx = this.getCenterX(); + int cy = this.getCenterY(); + + switch (orientation) { + case SOUTH -> { + edgeConnections.put(Orientation.NORTH, new Point(cx, cy - Tile.GRID)); + edgeConnections.put(Orientation.SOUTH, new Point(cx, cy + Tile.GRID * 3)); + + if (Direction.LEFT == direction) { + edgeConnections.put(Orientation.EAST, new Point(cx + Tile.GRID, cy + Tile.GRID * 2)); + edgeConnections.put(Orientation.WEST, new Point(cx - Tile.GRID, cy)); + } else { + edgeConnections.put(Orientation.EAST, new Point(cx + Tile.GRID, cy)); + edgeConnections.put(Orientation.WEST, new Point(cx - Tile.GRID, cy + Tile.GRID * 2)); + } + } + case WEST -> { + edgeConnections.put(Orientation.EAST, new Point(cx + Tile.GRID, cy)); + edgeConnections.put(Orientation.WEST, new Point(cx - Tile.GRID * 3, cy)); + + if (Direction.LEFT == direction) { + edgeConnections.put(Orientation.NORTH, new Point(cx, cy - Tile.GRID)); + edgeConnections.put(Orientation.SOUTH, new Point(cx - Tile.GRID * 2, cy + Tile.GRID)); + } else { + edgeConnections.put(Orientation.NORTH, new Point(cx - Tile.GRID * 2, cy - Tile.GRID)); + edgeConnections.put(Orientation.SOUTH, new Point(cx, cy + Tile.GRID)); + } + } + case NORTH -> { + edgeConnections.put(Orientation.NORTH, new Point(cx, cy - Tile.GRID * 3)); + edgeConnections.put(Orientation.SOUTH, new Point(cx, cy + Tile.GRID)); + + if (Direction.LEFT == direction) { + edgeConnections.put(Orientation.EAST, new Point(cx + Tile.GRID, cy)); + edgeConnections.put(Orientation.WEST, new Point(cx - Tile.GRID, cy - Tile.GRID * 2)); + } else { + edgeConnections.put(Orientation.EAST, new Point(cx + Tile.GRID, cy - Tile.GRID * 2)); + edgeConnections.put(Orientation.WEST, new Point(cx - Tile.GRID, cy)); + } + } + default -> { + //EAST + edgeConnections.put(Orientation.EAST, new Point(cx + Tile.GRID * 3, cy)); + edgeConnections.put(Orientation.WEST, new Point(cx - Tile.GRID, cy)); + + if (Direction.LEFT == direction) { + edgeConnections.put(Orientation.NORTH, new Point(cx + Tile.GRID * 2, cy - Tile.GRID)); + edgeConnections.put(Orientation.SOUTH, new Point(cx, cy + Tile.GRID)); + } else { + edgeConnections.put(Orientation.NORTH, new Point(cx, cy - Tile.GRID)); + edgeConnections.put(Orientation.SOUTH, new Point(cx + Tile.GRID * 2, cy + Tile.GRID)); + } + } + } + return edgeConnections; + } + +// @Override +// protected void renderStraight(Graphics2D g2, Color color) { +// int xx, yy, w, h; +// xx = 0; +// yy = 170; +// w = RENDER_WIDTH; +// h = 60; +// +// g2.setStroke(new BasicStroke(4, BasicStroke.JOIN_MITER, BasicStroke.JOIN_ROUND)); +// g2.setPaint(color); +// g2.fillRect(xx, yy, w, h); +// } +// @Override +// protected void renderRouteStraight(Graphics2D g2, Color color) { +// int xx, yy, w, h; +// xx = 0; +// yy = 190; +// w = RENDER_WIDTH; +// h = 20; +// +// g2.setStroke(new BasicStroke(4, BasicStroke.JOIN_MITER, BasicStroke.JOIN_ROUND)); +// g2.setPaint(color); +// g2.fillRect(xx, yy, w, h); +// } +// protected void renderStraight2(Graphics2D g2, Color color) { +// int xx, yy, w, h; +// xx = RENDER_WIDTH; +// yy = 170; +// w = RENDER_WIDTH; +// h = 60; +// +// g2.setStroke(new BasicStroke(4, BasicStroke.JOIN_MITER, BasicStroke.JOIN_ROUND)); +// g2.setPaint(color); +// g2.fillRect(xx, yy, w, h); +// } +// protected void renderRouteStraight2(Graphics2D g2, Color color) { +// int xx, yy, w, h; +// xx = RENDER_WIDTH; +// yy = 190; +// w = RENDER_WIDTH; +// h = 20; +// +// g2.setStroke(new BasicStroke(4, BasicStroke.JOIN_MITER, BasicStroke.JOIN_ROUND)); +// g2.setPaint(color); +// g2.fillRect(xx, yy, w, h); +// } +// @Override +// protected void renderDiagonal(Graphics2D g2, Color color) { +// int[] xPoints, yPoints; +// if (Direction.RIGHT.equals(getDirection())) { +// xPoints = new int[]{400, 400, 167, 230}; +// yPoints = new int[]{170, 230, 0, 0}; +// } else { +// xPoints = new int[]{400, 400, 170, 230}; +// yPoints = new int[]{230, 170, 400, 400}; +// } +// +// g2.setStroke(new BasicStroke(4, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND)); +// g2.setPaint(color); +// g2.fillPolygon(xPoints, yPoints, xPoints.length); +// } +// @Override +// protected void renderRouteDiagonal(Graphics2D g2, Color color) { +// int[] xPoints, yPoints; +// if (Direction.RIGHT.equals(getDirection())) { +// xPoints = new int[]{420, 400, 190, 210}; +// yPoints = new int[]{210, 210, 0, 0}; +// } else { +// xPoints = new int[]{400, 400, 190, 210}; +// yPoints = new int[]{210, 190, 400, 400}; +// } +// +// g2.setStroke(new BasicStroke(4, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND)); +// g2.setPaint(color); +// g2.fillPolygon(xPoints, yPoints, xPoints.length); +// } +// protected void renderDiagonal2(Graphics2D g2, Color color) { +// int[] xPoints, yPoints; +// if (Direction.RIGHT.equals(getDirection())) { +// xPoints = new int[]{400, 400, 570, 630}; +// yPoints = new int[]{170, 230, 400, 400}; +// } else { +// xPoints = new int[]{400, 400, 570, 630}; +// yPoints = new int[]{230, 170, 0, 0}; +// } +// +// g2.setStroke(new BasicStroke(4, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND)); +// g2.setPaint(color); +// g2.fillPolygon(xPoints, yPoints, xPoints.length); +// } +// protected void renderRouteDiagonal2(Graphics2D g2, Color color) { +// int[] xPoints, yPoints; +// if (Direction.RIGHT.equals(getDirection())) { +// xPoints = new int[]{400, 380, 590, 610}; +// yPoints = new int[]{190, 190, 400, 400}; +// } else { +// xPoints = new int[]{400, 380, 590, 610}; +// yPoints = new int[]{210, 210, 0, 0}; +// } +// +// g2.setStroke(new BasicStroke(4, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND)); +// g2.setPaint(color); +// g2.setPaint(Color.cyan); +// g2.fillPolygon(xPoints, yPoints, xPoints.length); +// } +// @Override +// public void renderTile(Graphics2D g2) { +// if (accessoryValue == null) { +// this.accessoryValue = AccessoryValue.OFF; +// } +// +// switch (accessoryValue) { +// case RED -> { +// renderStraight2(g2, Cross.LIGHT_RED); +// renderDiagonal(g2, Cross.LIGHT_RED); +// renderStraight(g2, Cross.DARK_RED); +// renderDiagonal2(g2, Cross.DARK_RED); +// } +// case GREEN -> { +// renderDiagonal(g2, Cross.VERY_LIGHT_GREEN); +// renderDiagonal2(g2, Cross.VERY_LIGHT_GREEN); +// renderStraight(g2, Cross.DARK_GREEN); +// renderStraight2(g2, Cross.DARK_GREEN); +// } +// default -> { +// renderStraight(g2, trackColor); +// renderStraight2(g2, trackColor); +// renderDiagonal(g2, trackColor); +// renderDiagonal2(g2, trackColor); +// } +// } +// } +// @Override +// public void renderTileRoute(Graphics2D g2) { +// if (routeValue == null) { +// routeValue = AccessoryValue.OFF; +// } +// if (model.getIncomingSide() == null) { +// model.setIncomingSide(model.getTileOrienation()); +// } +// +// Orientation incomingSide = model.getIncomingSide(); +// +// if (isHorizontal()) { +// if (AccessoryValue.GREEN == routeValue && (Orientation.NORTH == incomingSide || Orientation.SOUTH == incomingSide)) { +// renderRouteDiagonal(g2, trackRouteColor); +// renderRouteDiagonal2(g2, trackRouteColor); +// } else if (AccessoryValue.GREEN == routeValue && (Orientation.EAST == incomingSide || Orientation.WEST == incomingSide)) { +// renderRouteStraight(g2, trackRouteColor); +// renderRouteStraight2(g2, trackRouteColor); +// } else if (AccessoryValue.RED == routeValue && Orientation.EAST == getOrientation()) { +// if (Direction.RIGHT == getDirection() && (Orientation.EAST == incomingSide || Orientation.NORTH == incomingSide)) { +// renderRouteStraight2(g2, trackRouteColor); +// renderRouteDiagonal(g2, trackRouteColor); +// } else if (Direction.RIGHT == getDirection() && (Orientation.WEST == incomingSide || Orientation.SOUTH == incomingSide)) { +// renderRouteDiagonal2(g2, trackRouteColor); +// renderRouteStraight(g2, trackRouteColor); +// } else if (Direction.LEFT == getDirection() && (Orientation.EAST == incomingSide || Orientation.SOUTH == incomingSide)) { +// renderRouteStraight2(g2, trackRouteColor); +// renderRouteDiagonal(g2, trackRouteColor); +// } else if (Direction.LEFT == getDirection() && (Orientation.WEST == incomingSide || Orientation.NORTH == incomingSide)) { +// renderRouteStraight(g2, trackColor); +// renderRouteDiagonal2(g2, trackColor); +// } +// } else if (AccessoryValue.RED == routeValue && Orientation.WEST == getOrientation()) { +// if (Direction.RIGHT == getDirection() && (Orientation.EAST == incomingSide || Orientation.NORTH == incomingSide)) { +// renderRouteStraight(g2, trackRouteColor); +// renderRouteDiagonal2(g2, trackRouteColor); +// } else if (Direction.RIGHT == getDirection() && (Orientation.WEST == incomingSide || Orientation.SOUTH == incomingSide)) { +// renderRouteDiagonal(g2, trackRouteColor); +// renderRouteStraight2(g2, trackRouteColor); +// } else if (Direction.LEFT == getDirection() && (Orientation.EAST == incomingSide || Orientation.SOUTH == incomingSide)) { +// renderRouteStraight(g2, trackRouteColor); +// renderRouteDiagonal2(g2, trackRouteColor); +// } else if (Direction.LEFT == getDirection() && (Orientation.WEST == incomingSide || Orientation.NORTH == incomingSide)) { +// renderRouteStraight2(g2, trackColor); +// renderRouteDiagonal(g2, trackColor); +// } +// } +// } else { +// if (AccessoryValue.GREEN == routeValue && (Orientation.NORTH == incomingSide || Orientation.SOUTH == incomingSide)) { +// renderRouteStraight(g2, trackRouteColor); +// renderRouteStraight2(g2, trackRouteColor); +// } else if (AccessoryValue.GREEN == routeValue && (Orientation.EAST == incomingSide || Orientation.WEST == incomingSide)) { +// renderRouteDiagonal(g2, trackRouteColor); +// renderRouteDiagonal2(g2, trackRouteColor); +// } else if (AccessoryValue.RED == routeValue && Orientation.SOUTH == getOrientation()) { +// if (Direction.RIGHT == getDirection() && (Orientation.EAST == incomingSide || Orientation.SOUTH == incomingSide)) { +// renderRouteStraight2(g2, trackRouteColor); +// renderRouteDiagonal(g2, trackRouteColor); +// } else if (Direction.RIGHT == getDirection() && (Orientation.WEST == incomingSide || Orientation.NORTH == incomingSide)) { +// renderRouteDiagonal2(g2, trackRouteColor); +// renderRouteStraight(g2, trackRouteColor); +// } else if (Direction.LEFT == getDirection() && (Orientation.EAST == incomingSide || Orientation.NORTH == incomingSide)) { +// renderRouteStraight(g2, trackRouteColor); +// renderRouteDiagonal2(g2, trackRouteColor); +// } else if (Direction.LEFT == getDirection() && (Orientation.WEST == incomingSide || Orientation.SOUTH == incomingSide)) { +// renderRouteStraight2(g2, trackColor); +// renderRouteDiagonal(g2, trackColor); +// } +// } else if (AccessoryValue.RED == routeValue && Orientation.NORTH == getOrientation()) { +// if (Direction.RIGHT == getDirection() && (Orientation.EAST == incomingSide || Orientation.SOUTH == incomingSide)) { +// renderRouteStraight(g2, trackRouteColor); +// renderRouteDiagonal2(g2, trackRouteColor); +// } else if (Direction.RIGHT == getDirection() && (Orientation.WEST == incomingSide || Orientation.NORTH == incomingSide)) { +// renderRouteDiagonal(g2, trackRouteColor); +// renderRouteStraight2(g2, trackRouteColor); +// } else if (Direction.LEFT == getDirection() && (Orientation.EAST == incomingSide || Orientation.NORTH == incomingSide)) { +// renderRouteStraight2(g2, trackRouteColor); +// renderRouteDiagonal(g2, trackRouteColor); +// } else if (Direction.LEFT == getDirection() && (Orientation.WEST == incomingSide || Orientation.SOUTH == incomingSide)) { +// renderRouteStraight(g2, trackColor); +// renderRouteDiagonal2(g2, trackColor); +// } +// } +// } +// } + @Override + public AccessoryValue accessoryValueForRoute(Orientation from, Orientation to) { + if (from != null && to != null && this.getDirection() != null) { + switch (this.getDirection()) { + case LEFT -> { + if (this.isHorizontal()) { + if ((from == Orientation.WEST && to == Orientation.EAST) || (from == Orientation.EAST && to == Orientation.WEST)) { + return AccessoryValue.GREEN; + } else if ((from == Orientation.NORTH && to == Orientation.SOUTH) || (from == Orientation.SOUTH && to == Orientation.NORTH)) { + return AccessoryValue.GREEN; + } else if ((from == Orientation.NORTH && to == Orientation.WEST) || (from == Orientation.WEST && to == Orientation.NORTH)) { + return AccessoryValue.RED; + } else if ((from == Orientation.EAST && to == Orientation.SOUTH) || (from == Orientation.SOUTH && to == Orientation.EAST)) { + return AccessoryValue.RED; + } else { + return AccessoryValue.OFF; + } + } else { + //Vertical + if ((from == Orientation.WEST && to == Orientation.EAST) || (from == Orientation.EAST && to == Orientation.WEST)) { + return AccessoryValue.GREEN; + } else if ((from == Orientation.NORTH && to == Orientation.SOUTH) || (from == Orientation.SOUTH && to == Orientation.NORTH)) { + return AccessoryValue.GREEN; + } else if ((from == Orientation.SOUTH && to == Orientation.WEST) || (from == Orientation.WEST && to == Orientation.SOUTH)) { + return AccessoryValue.RED; + } else if ((from == Orientation.EAST && to == Orientation.NORTH) || (from == Orientation.NORTH && to == Orientation.EAST)) { + return AccessoryValue.RED; + } else { + return AccessoryValue.OFF; + } + } + } + case RIGHT -> { + if (this.isHorizontal()) { + if ((from == Orientation.WEST && to == Orientation.EAST) || (from == Orientation.EAST && to == Orientation.WEST)) { + return AccessoryValue.GREEN; + } else if ((from == Orientation.NORTH && to == Orientation.SOUTH) || (from == Orientation.SOUTH && to == Orientation.NORTH)) { + return AccessoryValue.GREEN; + } else if ((from == Orientation.NORTH && to == Orientation.EAST) || (from == Orientation.EAST && to == Orientation.NORTH)) { + return AccessoryValue.RED; + } else if ((from == Orientation.WEST && to == Orientation.SOUTH) || (from == Orientation.SOUTH && to == Orientation.WEST)) { + return AccessoryValue.RED; + } else { + return AccessoryValue.OFF; + } + } else { + //Vertical + if ((from == Orientation.WEST && to == Orientation.EAST) || (from == Orientation.EAST && to == Orientation.WEST)) { + return AccessoryValue.GREEN; + } else if ((from == Orientation.NORTH && to == Orientation.SOUTH) || (from == Orientation.SOUTH && to == Orientation.NORTH)) { + return AccessoryValue.GREEN; + } else if ((from == Orientation.SOUTH && to == Orientation.EAST) || (from == Orientation.EAST && to == Orientation.SOUTH)) { + return AccessoryValue.RED; + } else if ((from == Orientation.WEST && to == Orientation.NORTH) || (from == Orientation.NORTH && to == Orientation.WEST)) { + return AccessoryValue.RED; + } else { + return AccessoryValue.OFF; + } + } + } + default -> { + return AccessoryValue.OFF; + } + } + } else { + return AccessoryValue.OFF; + } + } + +// @Override +// protected void drawCenterPoint(Graphics2D g2d, Color color, double size) { +// //A Cross has 1 alternate point +// //1st square holds the centerpoint +// //2nd square +// double dX1, dX2, dY1, dY2; +// Orientation tileOrientation = model.getTileOrienation(); +// switch (tileOrientation) { +// case SOUTH -> { +// dX1 = renderWidth / 2 - size / 2; +// dY1 = renderHeight / 2 - renderHeight / 4 - size / 2; +// dX2 = renderWidth / 2 + renderWidth - size / 4; +// dY2 = renderHeight / 2 - renderHeight / 4 - size / 4; +// } +// case WEST -> { +// dX1 = renderWidth / 2 - renderWidth / 4 - size / 2; +// dY1 = renderHeight / 2 - size / 2; +// dX2 = renderWidth / 2 + renderWidth / 4 - size / 4; +// dY2 = renderHeight / 2 - size / 4; +// } +// case NORTH -> { +// dX1 = renderWidth / 2 - size / 2; +// dY1 = renderHeight / 2 - renderHeight / 4 - size / 2; +// dX2 = renderWidth / 2 + renderWidth - size / 4; +// dY2 = renderHeight / 2 - renderHeight / 4 - size / 4; +// } +// default -> { +// //East +// dX1 = renderWidth / 2 - renderWidth / 4 - size / 2; +// dY1 = renderHeight / 2 - size / 2; +// dX2 = renderWidth / 2 + renderWidth / 4 - size / 4; +// dY2 = renderHeight / 2 - size / 4; +// } +// } +// +// g2d.setColor(color); +// g2d.fill(new Ellipse2D.Double(dX1, dY1, size, size)); +// g2d.fill(new Ellipse2D.Double(dX2, dY2, size / 2, size / 2)); +// } + @Override + public Rectangle getTileBounds() { + Orientation tileOrientation = model.getTileOrienation(); + int xx, yy, w, h, multiplier; + if (model.isScaleImage()) { + w = tileWidth(tileOrientation, TileType.CROSS); + h = tileHeight(tileOrientation, TileType.CROSS); + multiplier = 1; + } else { + int renderWidth = getUI().getRenderWidth(); + int renderHeight = getUI().getRenderHeight(); + + w = renderWidth; + h = renderHeight; + multiplier = 10; + } + + switch (tileOrientation) { + case SOUTH -> { + xx = tileX - GRID * multiplier; + yy = tileY - GRID * multiplier; + } + case WEST -> { + xx = tileX - GRID * multiplier - GRID * 2 * multiplier; + yy = tileY - GRID * multiplier; + } + case NORTH -> { + xx = tileX - GRID * multiplier; + yy = tileY - GRID * multiplier - GRID * 2 * multiplier; + } + default -> { + //East + xx = tileX - GRID * multiplier; + yy = tileY - GRID * multiplier; + } + } + + if (model.isScaleImage()) { + return new Rectangle(xx, yy, w, h); + } else { + int renderWidth = getUI().getRenderWidth(); + int renderHeight = getUI().getRenderHeight(); + + return new Rectangle(xx, yy, renderWidth, renderHeight); + } + } + + private void changeRenderSizeAndOffsets() { + +// if (getUI() instanceof CrossUI cui) { +// +// cui.changeRenderSize(this); +// } else { +// Logger.warn("UI is a "+getUI().getClass().getSimpleName()); +// } + //Reset offsets +// this.offsetY = 0; + this.renderOffsetY = 0; +// this.offsetX = 0; + this.renderOffsetX = 0; + if (isHorizontal()) { + //this.renderWidth = RENDER_GRID * 4; + //this.renderHeight = RENDER_GRID * 2; + +// this.offsetY = 0; + this.renderOffsetY = 0; + } else { + //this.renderWidth = RENDER_GRID * 2; + //this.renderHeight = RENDER_GRID * 4; + + /// this.offsetX = 0; + this.renderOffsetX = 0; + } + + //Due to the asymetical shape (center is on the left) + //the offset has to be changed with the rotation +// Orientation tileOrientation = model.getTileOrienation(); +// switch (tileOrientation) { +// case SOUTH -> { +// this.offsetY = +GRID; +// this.renderOffsetY = RENDER_GRID; +// } +// case WEST -> { +// this.offsetX = -GRID; +// this.renderOffsetX = -RENDER_GRID; +// } +// case NORTH -> { +// this.offsetY = -GRID; +// this.renderOffsetY = -RENDER_GRID; +// } +// default -> { +// //East so default +// this.offsetX = +GRID; +// this.renderOffsetX = +RENDER_GRID; +// } +// } + } + + @Override + public Orientation rotate() { + super.rotate(); + + Orientation tileOrientation = model.getTileOrienation(); + int w = tileWidth(tileOrientation, TileType.CROSS); + int h = tileHeight(tileOrientation, TileType.CROSS); + + Dimension d = new Dimension(w, h); + setPreferredSize(d); + setSize(d); + changeRenderSizeAndOffsets(); + + setBounds(getTileBounds()); + return tileOrientation; + } + +} diff --git a/src/main/java/jcs/ui/layout/tiles/Crossing.java b/src/main/java/jcs/ui/layout/tiles/Crossing.java index 59e62085..f9f7cc97 100644 --- a/src/main/java/jcs/ui/layout/tiles/Crossing.java +++ b/src/main/java/jcs/ui/layout/tiles/Crossing.java @@ -1 +1,147 @@ -/* * Copyright 2023 Frans Jacobs. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package jcs.ui.layout.tiles; import java.awt.BasicStroke; import java.awt.Color; import java.awt.Graphics2D; import java.awt.Point; import java.util.HashMap; import java.util.Map; import jcs.entities.TileBean; import jcs.entities.TileBean.Orientation; import jcs.entities.TileBean.TileType; public class Crossing extends Straight { public Crossing(TileBean tileBean) { super(tileBean); } public Crossing(Orientation orientation, Point center) { this(orientation, center.x, center.y); } public Crossing(Orientation orientation, int x, int y) { this(orientation, x, y, DEFAULT_WIDTH, DEFAULT_HEIGHT); } public Crossing(Orientation orientation, int x, int y, int width, int height) { super(orientation, x, y, width, height); this.tileType = TileType.CROSSING; } @Override public Map getNeighborPoints() { Map neighbors = new HashMap<>(); int cx = this.getCenterX(); int cy = this.getCenterY(); // Horizontal neighbors.put(Orientation.EAST, new Point(cx + Tile.GRID * 2, cy)); neighbors.put(Orientation.WEST, new Point(cx - Tile.GRID * 2, cy)); // Vertical neighbors.put(Orientation.NORTH, new Point(cx, cy - Tile.GRID * 2)); neighbors.put(Orientation.SOUTH, new Point(cx, cy + Tile.GRID * 2)); return neighbors; } @Override public Map getEdgePoints() { Map edgeConnections = new HashMap<>(); int cx = this.getCenterX(); int cy = this.getCenterY(); // Horizontal edgeConnections.put(Orientation.EAST, new Point(cx + Tile.GRID, cy)); edgeConnections.put(Orientation.WEST, new Point(cx - Tile.GRID, cy)); // Vertical edgeConnections.put(Orientation.NORTH, new Point(cx, cy - Tile.GRID)); edgeConnections.put(Orientation.SOUTH, new Point(cx, cy + Tile.GRID)); return edgeConnections; } protected void renderVerticalAndDividers(Graphics2D g2) { int xxn, yyn, xxs, yys, w, h; xxn = 175; yyn = 0; xxs = 175; yys = 325; w = 50; h = 75; g2.setStroke(new BasicStroke(4, BasicStroke.JOIN_MITER, BasicStroke.JOIN_ROUND)); g2.setPaint(trackColor); //North g2.fillRect(xxn, yyn, w, h); //South g2.fillRect(xxs, yys, w, h); //Dividers int[] xNorthPoly = new int[]{85, 115, 285, 315}; int[] yNorthPoly = new int[]{85, 125, 125, 85}; int[] xSouthPoly = new int[]{85, 115, 285, 315}; int[] ySouthPoly = new int[]{315, 275, 275, 315}; g2.setPaint(Color.darkGray); g2.setStroke(new BasicStroke(8, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND)); g2.drawPolyline(xNorthPoly, yNorthPoly, xNorthPoly.length); g2.drawPolyline(xSouthPoly, ySouthPoly, xSouthPoly.length); } @Override public void renderTile(Graphics2D g2) { renderStraight(g2); renderVerticalAndDividers(g2); } protected void renderRouteVertical(Graphics2D g2) { int xxn, yyn, xxs, yys, w, h; xxn = 190; yyn = 0; xxs = 190; yys = 325; w = 20; h = 75; g2.setStroke(new BasicStroke(4, BasicStroke.JOIN_MITER, BasicStroke.JOIN_ROUND)); g2.setPaint(this.trackRouteColor); //North g2.fillRect(xxn, yyn, w, h); //South g2.fillRect(xxs, yys, w, h); } } \ No newline at end of file +/* + * Copyright 2023 Frans Jacobs. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package jcs.ui.layout.tiles; + +import java.awt.Point; +import java.util.HashMap; +import java.util.Map; +import javax.swing.UIManager; +import jcs.entities.TileBean; +import jcs.entities.TileBean.Orientation; +import jcs.entities.TileBean.TileType; +import jcs.ui.layout.tiles.ui.CrossingUI; +import jcs.ui.layout.tiles.ui.TileUI; + +public class Crossing extends Straight { + + public Crossing(TileBean tileBean) { + super(tileBean); + initUI(); + } + + public Crossing(Orientation orientation, Point center) { + this(orientation, center.x, center.y); + } + + public Crossing(Orientation orientation, int x, int y) { + this(orientation, x, y, DEFAULT_WIDTH, DEFAULT_HEIGHT); + } + + public Crossing(Orientation orientation, int x, int y, int width, int height) { + super(orientation, x, y, width, height); + this.tileType = TileType.CROSSING; + initUI(); + } + + private void initUI() { + updateUI(); + } + + @Override + public String getUIClassID() { + return CrossingUI.UI_CLASS_ID; + } + + @Override + public void updateUI() { + UIManager.put(TileUI.UI_CLASS_ID, "jcs.ui.layout.tiles.ui.CrossingUI"); + setUI((TileUI) UIManager.getUI(this)); + invalidate(); + } + + @Override + public Map getNeighborPoints() { + Map neighbors = new HashMap<>(); + int cx = this.getCenterX(); + int cy = this.getCenterY(); + + // Horizontal + neighbors.put(Orientation.EAST, new Point(cx + Tile.GRID * 2, cy)); + neighbors.put(Orientation.WEST, new Point(cx - Tile.GRID * 2, cy)); + // Vertical + neighbors.put(Orientation.NORTH, new Point(cx, cy - Tile.GRID * 2)); + neighbors.put(Orientation.SOUTH, new Point(cx, cy + Tile.GRID * 2)); + return neighbors; + } + + @Override + public Map getEdgePoints() { + Map edgeConnections = new HashMap<>(); + int cx = this.getCenterX(); + int cy = this.getCenterY(); + + // Horizontal + edgeConnections.put(Orientation.EAST, new Point(cx + Tile.GRID, cy)); + edgeConnections.put(Orientation.WEST, new Point(cx - Tile.GRID, cy)); + // Vertical + edgeConnections.put(Orientation.NORTH, new Point(cx, cy - Tile.GRID)); + edgeConnections.put(Orientation.SOUTH, new Point(cx, cy + Tile.GRID)); + return edgeConnections; + } + +// protected void renderVerticalAndDividers(Graphics2D g2) { +// int xxn, yyn, xxs, yys, w, h; +// xxn = 175; +// yyn = 0; +// xxs = 175; +// yys = 325; +// w = 50; +// h = 75; +// +// g2.setStroke(new BasicStroke(4, BasicStroke.JOIN_MITER, BasicStroke.JOIN_ROUND)); +// g2.setPaint(trackColor); +// +// //North +// g2.fillRect(xxn, yyn, w, h); +// //South +// g2.fillRect(xxs, yys, w, h); +// +// //Dividers +// int[] xNorthPoly = new int[]{85, 115, 285, 315}; +// int[] yNorthPoly = new int[]{85, 125, 125, 85}; +// +// int[] xSouthPoly = new int[]{85, 115, 285, 315}; +// int[] ySouthPoly = new int[]{315, 275, 275, 315}; +// +// g2.setPaint(Color.darkGray); +// g2.setStroke(new BasicStroke(8, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND)); +// +// g2.drawPolyline(xNorthPoly, yNorthPoly, xNorthPoly.length); +// g2.drawPolyline(xSouthPoly, ySouthPoly, xSouthPoly.length); +// } +// @Override +// public void renderTile(Graphics2D g2) { +// renderStraight(g2); +// renderVerticalAndDividers(g2); +// } +// protected void renderRouteVertical(Graphics2D g2) { +// int xxn, yyn, xxs, yys, w, h; +// xxn = 190; +// yyn = 0; +// xxs = 190; +// yys = 325; +// w = 20; +// h = 75; +// +// g2.setStroke(new BasicStroke(4, BasicStroke.JOIN_MITER, BasicStroke.JOIN_ROUND)); +// g2.setPaint(this.trackRouteColor); +// +// //North +// g2.fillRect(xxn, yyn, w, h); +// //South +// g2.fillRect(xxs, yys, w, h); +// } +} diff --git a/src/main/java/jcs/ui/layout/tiles/Curved.java b/src/main/java/jcs/ui/layout/tiles/Curved.java index c16fa01b..d52281e4 100755 --- a/src/main/java/jcs/ui/layout/tiles/Curved.java +++ b/src/main/java/jcs/ui/layout/tiles/Curved.java @@ -1 +1,133 @@ -/* * Copyright 2023 Frans Jacobs. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package jcs.ui.layout.tiles; import java.awt.BasicStroke; import java.awt.Graphics2D; import java.awt.Point; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set; import jcs.entities.TileBean; import jcs.entities.TileBean.Orientation; import static jcs.entities.TileBean.Orientation.NORTH; import static jcs.entities.TileBean.Orientation.SOUTH; import static jcs.entities.TileBean.Orientation.WEST; import jcs.entities.TileBean.TileType; public class Curved extends Tile { public Curved(TileBean tileBean) { super(tileBean, DEFAULT_WIDTH, DEFAULT_HEIGHT); setModel(new DefaultTileModel(tileBean.getOrientation())); } public Curved(Orientation orientation, Point center) { this(orientation, center.x, center.y); } public Curved(Orientation orientation, int x, int y) { this(orientation, x, y, DEFAULT_WIDTH, DEFAULT_HEIGHT); } public Curved(Orientation orientation, int x, int y, int width, int height) { super(TileType.CURVED, orientation, x, y, width, height); setModel(new DefaultTileModel(orientation)); } @Override public Map getNeighborPoints() { Map neighbors = new HashMap<>(); Orientation orientation = this.getOrientation(); int cx = this.getCenterX(); int cy = this.getCenterY(); switch (orientation) { case SOUTH -> { neighbors.put(Orientation.WEST, new Point(cx - Tile.GRID * 2, cy)); neighbors.put(Orientation.SOUTH, new Point(cx, cy + Tile.GRID * 2)); } case WEST -> { neighbors.put(Orientation.WEST, new Point(cx - Tile.GRID * 2, cy)); neighbors.put(Orientation.NORTH, new Point(cx, cy - Tile.GRID * 2)); } case NORTH -> { neighbors.put(Orientation.NORTH, new Point(cx, cy - Tile.GRID * 2)); neighbors.put(Orientation.EAST, new Point(cx + Tile.GRID * 2, cy)); } default -> { //EAST neighbors.put(Orientation.EAST, new Point(cx + Tile.GRID * 2, cy)); neighbors.put(Orientation.SOUTH, new Point(cx, cy + Tile.GRID * 2)); } } return neighbors; } @Override public Map getEdgePoints() { Map edgeConnections = new HashMap<>(); Orientation orientation = this.getOrientation(); int cx = this.getCenterX(); int cy = this.getCenterY(); switch (orientation) { case SOUTH -> { // | | // b \ |\ | edgeConnections.put(Orientation.WEST, new Point(cx - Tile.GRID, cy)); edgeConnections.put(Orientation.SOUTH, new Point(cx, cy + Tile.GRID)); } case WEST -> { // |/ | // t / | | edgeConnections.put(Orientation.WEST, new Point(cx - Tile.GRID, cy)); edgeConnections.put(Orientation.NORTH, new Point(cx, cy - Tile.GRID)); } case NORTH -> { // t \ edgeConnections.put(Orientation.NORTH, new Point(cx, cy - Tile.GRID)); edgeConnections.put(Orientation.EAST, new Point(cx + Tile.GRID, cy)); } default -> { //EAST b / edgeConnections.put(Orientation.EAST, new Point(cx + Tile.GRID, cy)); edgeConnections.put(Orientation.SOUTH, new Point(cx, cy + Tile.GRID)); } } return edgeConnections; } @Override public void renderTile(Graphics2D g2) { int[] xPoints = new int[]{400, 400, 170, 230}; int[] yPoints = new int[]{230, 170, 400, 400}; g2.setStroke(new BasicStroke(1, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND)); g2.setPaint(trackColor); g2.fillPolygon(xPoints, yPoints, xPoints.length); } @Override public void renderTileRoute(Graphics2D g2) { int[] xPoints = new int[]{400, 400, 190, 210}; int[] yPoints = new int[]{210, 190, 400, 400}; g2.setStroke(new BasicStroke(1, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND)); g2.setPaint(trackRouteColor); g2.fillPolygon(xPoints, yPoints, xPoints.length); } // @Override // protected void paintComponent(Graphics g) { // long started = System.currentTimeMillis(); // super.paintComponent(g); // // setBounds(this.tileX - GRID, this.tileY - GRID, this.getWidth(), this.getHeight()); // // Graphics2D g2 = (Graphics2D) g.create(); // drawTile(g2); // g2.dispose(); // // g.drawImage(this.tileImage, 0, 0, null); // // long now = System.currentTimeMillis(); // Logger.trace(this.id + " Duration: " + (now - started) + " ms."); // } } \ No newline at end of file +/* + * Copyright 2023 Frans Jacobs. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package jcs.ui.layout.tiles; + +import java.awt.Point; +import java.util.HashMap; +import java.util.Map; +import javax.swing.UIManager; +import jcs.entities.TileBean; +import jcs.entities.TileBean.Orientation; +import static jcs.entities.TileBean.Orientation.NORTH; +import static jcs.entities.TileBean.Orientation.SOUTH; +import static jcs.entities.TileBean.Orientation.WEST; +import jcs.entities.TileBean.TileType; +import jcs.ui.layout.tiles.ui.CurvedUI; +import jcs.ui.layout.tiles.ui.TileUI; + +public class Curved extends Tile { + + public Curved(TileBean tileBean) { + super(tileBean, DEFAULT_WIDTH, DEFAULT_HEIGHT); + setModel(new DefaultTileModel(tileBean.getOrientation())); + initUI(); + } + + public Curved(Orientation orientation, Point center) { + this(orientation, center.x, center.y); + } + + public Curved(Orientation orientation, int x, int y) { + this(orientation, x, y, DEFAULT_WIDTH, DEFAULT_HEIGHT); + } + + public Curved(Orientation orientation, int x, int y, int width, int height) { + super(TileType.CURVED, orientation, x, y, width, height); + setModel(new DefaultTileModel(orientation)); + initUI(); + } + + private void initUI() { + updateUI(); + } + + @Override + public String getUIClassID() { + return CurvedUI.UI_CLASS_ID; + } + + @Override + public void updateUI() { + UIManager.put(TileUI.UI_CLASS_ID, "jcs.ui.layout.tiles.ui.CurvedUI"); + setUI((TileUI) UIManager.getUI(this)); + invalidate(); + } + + @Override + public Map getNeighborPoints() { + Map neighbors = new HashMap<>(); + Orientation orientation = this.getOrientation(); + int cx = this.getCenterX(); + int cy = this.getCenterY(); + + switch (orientation) { + case SOUTH -> { + neighbors.put(Orientation.WEST, new Point(cx - Tile.GRID * 2, cy)); + neighbors.put(Orientation.SOUTH, new Point(cx, cy + Tile.GRID * 2)); + } + case WEST -> { + neighbors.put(Orientation.WEST, new Point(cx - Tile.GRID * 2, cy)); + neighbors.put(Orientation.NORTH, new Point(cx, cy - Tile.GRID * 2)); + } + case NORTH -> { + neighbors.put(Orientation.NORTH, new Point(cx, cy - Tile.GRID * 2)); + neighbors.put(Orientation.EAST, new Point(cx + Tile.GRID * 2, cy)); + } + default -> { + //EAST + neighbors.put(Orientation.EAST, new Point(cx + Tile.GRID * 2, cy)); + neighbors.put(Orientation.SOUTH, new Point(cx, cy + Tile.GRID * 2)); + } + } + return neighbors; + } + + @Override + public Map getEdgePoints() { + Map edgeConnections = new HashMap<>(); + + Orientation orientation = this.getOrientation(); + int cx = this.getCenterX(); + int cy = this.getCenterY(); + + switch (orientation) { + case SOUTH -> { + // | | + // b \ |\ | + edgeConnections.put(Orientation.WEST, new Point(cx - Tile.GRID, cy)); + edgeConnections.put(Orientation.SOUTH, new Point(cx, cy + Tile.GRID)); + } + case WEST -> { + // |/ | + // t / | | + edgeConnections.put(Orientation.WEST, new Point(cx - Tile.GRID, cy)); + edgeConnections.put(Orientation.NORTH, new Point(cx, cy - Tile.GRID)); + } + case NORTH -> { + // t \ + edgeConnections.put(Orientation.NORTH, new Point(cx, cy - Tile.GRID)); + edgeConnections.put(Orientation.EAST, new Point(cx + Tile.GRID, cy)); + } + default -> { + //EAST b / + edgeConnections.put(Orientation.EAST, new Point(cx + Tile.GRID, cy)); + edgeConnections.put(Orientation.SOUTH, new Point(cx, cy + Tile.GRID)); + } + } + return edgeConnections; + } + +} diff --git a/src/main/java/jcs/ui/layout/tiles/DefaultTileModel.java b/src/main/java/jcs/ui/layout/tiles/DefaultTileModel.java index d9e99fd9..2d97658b 100644 --- a/src/main/java/jcs/ui/layout/tiles/DefaultTileModel.java +++ b/src/main/java/jcs/ui/layout/tiles/DefaultTileModel.java @@ -18,7 +18,6 @@ import java.awt.Color; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; -import java.awt.event.ItemListener; import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; import javax.swing.event.EventListenerList; @@ -28,16 +27,11 @@ /** * - * @author fransjacobs */ -@SuppressWarnings("serial") // Same-version serialization only public class DefaultTileModel implements TileModel { protected transient ChangeEvent changeEvent = null; - /** - * Stores the listeners on this model. - */ protected EventListenerList listenerList = new EventListenerList(); protected boolean selected = false; @@ -45,6 +39,8 @@ public class DefaultTileModel implements TileModel { protected boolean scaleImage = true; protected boolean showCenter = false; protected Orientation tileOrienation; + protected Orientation incomingSide; + protected boolean showRoute = false; protected boolean showBlockState = false; protected boolean showLocomotiveImage = false; @@ -93,7 +89,7 @@ public void setSelectedColor(Color selectedColor) { } else { this.selectedColor = Tile.DEFAULT_SELECTED_COLOR; } - + if (!this.selectedColor.equals(prevColor)) { fireStateChanged(); } @@ -131,6 +127,16 @@ public void setTileOrienation(Orientation tileOrienation) { this.tileOrienation = tileOrienation; fireStateChanged(); } + + @Override + public Orientation getIncomingSide() { + return incomingSide; + } + + @Override + public void setIncomingSide(Orientation incomingSide) { + this.incomingSide = incomingSide; + } @Override public boolean isShowRoute() { @@ -310,30 +316,21 @@ public void removeChangeListener(ChangeListener l) { /** * Returns an array of all the change listeners registered on this DefaultButtonModel. * - * @return all of this model's ChangeListeners or an empty array if no change listeners are currently registered - * - * @see #addChangeListener - * @see #removeChangeListener - * - * @since 1.4 + * @return */ public ChangeListener[] getChangeListeners() { return listenerList.getListeners(ChangeListener.class); } /** - * Notifies all listeners that have registered interest for notification on this event type. The event instance is created lazily. - * - * @see EventListenerList + * Notifies all listeners that have registered interest for notification on this event type.br> The event instance is created lazily. */ protected void fireStateChanged() { - // Guaranteed to return a non-null array Object[] listeners = listenerList.getListenerList(); // Process the listeners last to first, notifying // those that are interested in this event for (int i = listeners.length - 2; i >= 0; i -= 2) { if (listeners[i] == ChangeListener.class) { - // Lazily create the event: if (changeEvent == null) { changeEvent = new ChangeEvent(this); } @@ -342,34 +339,9 @@ protected void fireStateChanged() { } } - /** - * {@inheritDoc} - */ -// @Override -// public void addItemListener(ItemListener l) { -// listenerList.add(ItemListener.class, l); +// public ItemListener[] getItemListeners() { +// return listenerList.getListeners(ItemListener.class); // } - /** - * {@inheritDoc} - */ -// @Override -// public void removeItemListener(ItemListener l) { -// listenerList.remove(ItemListener.class, l); -// } - /** - * Returns an array of all the item listeners registered on this DefaultButtonModel. - * - * @return all of this model's ItemListeners or an empty array if no item listeners are currently registered - * - * @see #addItemListener - * @see #removeItemListener - * - * @since 1.4 - */ - public ItemListener[] getItemListeners() { - return listenerList.getListeners(ItemListener.class); - } - @Override public void addActionListener(ActionListener l) { listenerList.add(ActionListener.class, l); @@ -389,16 +361,14 @@ public ActionListener[] getActionListeners() { * Notifies all listeners that have registered interest for notification on this event type. * * @param e the ActionEvent to deliver to listeners - * @see EventListenerList */ protected void fireActionPerformed(ActionEvent e) { - // Guaranteed to return a non-null array Object[] listeners = listenerList.getListenerList(); // Process the listeners last to first, notifying // those that are interested in this event for (int i = listeners.length - 2; i >= 0; i -= 2) { if (listeners[i] == ActionListener.class) { - // Lazily create the event: + // if (changeEvent == null) // changeEvent = new ChangeEvent(this); ((ActionListener) listeners[i + 1]).actionPerformed(e); @@ -406,11 +376,4 @@ protected void fireActionPerformed(ActionEvent e) { } } - /** - * Overridden to return null. - */ -// @Override -// public Object[] getSelectedObjects() { -// return null; -// } } diff --git a/src/main/java/jcs/ui/layout/tiles/End.java b/src/main/java/jcs/ui/layout/tiles/End.java index 79b10135..38b2383f 100644 --- a/src/main/java/jcs/ui/layout/tiles/End.java +++ b/src/main/java/jcs/ui/layout/tiles/End.java @@ -1 +1,108 @@ -/* * Copyright 2023 Frans Jacobs. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package jcs.ui.layout.tiles; import java.awt.BasicStroke; import java.awt.Color; import java.awt.Graphics2D; import java.awt.Point; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set; import jcs.entities.TileBean; import jcs.entities.TileBean.Orientation; import static jcs.entities.TileBean.Orientation.NORTH; import static jcs.entities.TileBean.Orientation.SOUTH; import static jcs.entities.TileBean.Orientation.WEST; import jcs.entities.TileBean.TileType; public class End extends Tile { public End(TileBean tileBean) { super(tileBean, DEFAULT_WIDTH, DEFAULT_HEIGHT); setModel(new DefaultTileModel(tileBean.getOrientation())); } public End(Orientation orientation, Point center) { this(orientation, center.x, center.y); } public End(Orientation orientation, int x, int y) { this(orientation, x, y, DEFAULT_WIDTH, DEFAULT_HEIGHT); } public End(Orientation orientation, int x, int y, int width, int height) { super(TileType.END, orientation, x, y, width, height); setModel(new DefaultTileModel(orientation)); } @Override public Map getNeighborPoints() { Map neighbors = new HashMap<>(); Orientation orientation = this.getOrientation(); int cx = this.getCenterX(); int cy = this.getCenterY(); switch (orientation) { case SOUTH -> neighbors.put(Orientation.SOUTH, new Point(cx, cy - Tile.GRID * 2)); case WEST -> neighbors.put(Orientation.WEST, new Point(cx + Tile.GRID * 2, cy)); case NORTH -> neighbors.put(Orientation.NORTH, new Point(cx, cy + Tile.GRID * 2)); default -> //EAST neighbors.put(Orientation.EAST, new Point(cx - Tile.GRID * 2, cy)); } return neighbors; } @Override public Map getEdgePoints() { Map edgeConnections = new HashMap<>(); Orientation orientation = this.getOrientation(); int cx = this.getCenterX(); int cy = this.getCenterY(); switch (orientation) { case SOUTH -> edgeConnections.put(Orientation.SOUTH, new Point(cx, cy - Tile.GRID)); case WEST -> edgeConnections.put(Orientation.WEST, new Point(cx + Tile.GRID, cy)); case NORTH -> edgeConnections.put(Orientation.NORTH, new Point(cx, cy + Tile.GRID)); default -> //EAST edgeConnections.put(Orientation.EAST, new Point(cx - Tile.GRID, cy)); } return edgeConnections; } protected void renderEnd(Graphics2D g2) { int xx, yy, w, h; xx = 0; yy = 175; w = RENDER_GRID; h = 50; g2.setStroke(new BasicStroke(40, BasicStroke.JOIN_MITER, BasicStroke.JOIN_ROUND)); g2.setPaint(trackColor); g2.fillRect(xx, yy, w, h); xx = RENDER_GRID; yy = 100; w = 30; h = 200; g2.setPaint(Color.DARK_GRAY); g2.fillRect(xx, yy, w, h); } @Override public void renderTile(Graphics2D g2) { renderEnd(g2); } @Override public void renderTileRoute(Graphics2D g2d) { } // @Override // protected void paintComponent(Graphics g) { // long started = System.currentTimeMillis(); // super.paintComponent(g); // // setBounds(this.tileX - GRID, this.tileY - GRID, this.getWidth(), this.getHeight()); // // Graphics2D g2 = (Graphics2D) g.create(); // drawTile(g2); // g2.dispose(); // // g.drawImage(this.tileImage, 0, 0, null); // // long now = System.currentTimeMillis(); // Logger.trace(this.id + " Duration: " + (now - started) + " ms."); // } } \ No newline at end of file +/* + * Copyright 2023 Frans Jacobs. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package jcs.ui.layout.tiles; + +import java.awt.Point; +import java.util.HashMap; +import java.util.Map; +import javax.swing.UIManager; +import jcs.entities.TileBean; +import jcs.entities.TileBean.Orientation; +import static jcs.entities.TileBean.Orientation.NORTH; +import static jcs.entities.TileBean.Orientation.SOUTH; +import static jcs.entities.TileBean.Orientation.WEST; +import jcs.entities.TileBean.TileType; +import jcs.ui.layout.tiles.ui.EndUI; +import jcs.ui.layout.tiles.ui.TileUI; + +public class End extends Tile { + + public End(TileBean tileBean) { + super(tileBean, DEFAULT_WIDTH, DEFAULT_HEIGHT); + setModel(new DefaultTileModel(tileBean.getOrientation())); + initUI(); + } + + public End(Orientation orientation, Point center) { + this(orientation, center.x, center.y); + } + + public End(Orientation orientation, int x, int y) { + this(orientation, x, y, DEFAULT_WIDTH, DEFAULT_HEIGHT); + } + + public End(Orientation orientation, int x, int y, int width, int height) { + super(TileType.END, orientation, x, y, width, height); + setModel(new DefaultTileModel(orientation)); + initUI(); + } + + private void initUI() { + updateUI(); + } + + @Override + public String getUIClassID() { + return EndUI.UI_CLASS_ID; + } + + @Override + public void updateUI() { + UIManager.put(TileUI.UI_CLASS_ID, "jcs.ui.layout.tiles.ui.EndUI"); + setUI((TileUI) UIManager.getUI(this)); + invalidate(); + } + + @Override + public Map getNeighborPoints() { + Map neighbors = new HashMap<>(); + Orientation orientation = this.getOrientation(); + int cx = this.getCenterX(); + int cy = this.getCenterY(); + + switch (orientation) { + case SOUTH -> + neighbors.put(Orientation.SOUTH, new Point(cx, cy - Tile.GRID * 2)); + case WEST -> + neighbors.put(Orientation.WEST, new Point(cx + Tile.GRID * 2, cy)); + case NORTH -> + neighbors.put(Orientation.NORTH, new Point(cx, cy + Tile.GRID * 2)); + default -> //EAST + neighbors.put(Orientation.EAST, new Point(cx - Tile.GRID * 2, cy)); + } + return neighbors; + } + + @Override + public Map getEdgePoints() { + Map edgeConnections = new HashMap<>(); + Orientation orientation = this.getOrientation(); + int cx = this.getCenterX(); + int cy = this.getCenterY(); + + switch (orientation) { + case SOUTH -> + edgeConnections.put(Orientation.SOUTH, new Point(cx, cy - Tile.GRID)); + case WEST -> + edgeConnections.put(Orientation.WEST, new Point(cx + Tile.GRID, cy)); + case NORTH -> + edgeConnections.put(Orientation.NORTH, new Point(cx, cy + Tile.GRID)); + default -> //EAST + edgeConnections.put(Orientation.EAST, new Point(cx - Tile.GRID, cy)); + } + return edgeConnections; + } +} diff --git a/src/main/java/jcs/ui/layout/tiles/Sensor.java b/src/main/java/jcs/ui/layout/tiles/Sensor.java index cb5e9cd0..3b0bcd7d 100644 --- a/src/main/java/jcs/ui/layout/tiles/Sensor.java +++ b/src/main/java/jcs/ui/layout/tiles/Sensor.java @@ -15,18 +15,16 @@ */ package jcs.ui.layout.tiles; -import java.awt.Color; -import java.awt.Graphics2D; -import java.awt.MultipleGradientPaint.CycleMethod; import java.awt.Point; -import java.awt.RadialGradientPaint; -import java.awt.geom.Ellipse2D; +import javax.swing.UIManager; import jcs.commandStation.events.SensorEvent; import jcs.commandStation.events.SensorEventListener; import jcs.entities.SensorBean; import jcs.entities.TileBean; import jcs.entities.TileBean.Orientation; import jcs.entities.TileBean.TileType; +import jcs.ui.layout.tiles.ui.SensorUI; +import jcs.ui.layout.tiles.ui.TileUI; public class Sensor extends Straight implements SensorEventListener { @@ -47,32 +45,16 @@ public Sensor(Orientation orientation, int x, int y, int width, int height) { this.tileType = TileType.SENSOR; } - private void renderSensor(Graphics2D g2) { - int xx, yy; - xx = RENDER_GRID - 75; - yy = RENDER_GRID - 75; - - Point c = new Point(xx, yy); - float radius = 300; - float[] dist = {0.0f, 0.6f}; - - if (model.isSensorActive()) { - Color[] colors = {Color.red.brighter(), Color.red.darker()}; - RadialGradientPaint foreground = new RadialGradientPaint(c, radius, dist, colors, CycleMethod.REFLECT); - g2.setPaint(foreground); - } else { - Color[] colors = {Color.green.darker(), Color.green.brighter()}; - RadialGradientPaint foreground = new RadialGradientPaint(c, radius, dist, colors, CycleMethod.REFLECT); - g2.setPaint(foreground); - } - - g2.fill(new Ellipse2D.Double(xx, yy, 0.5f * radius, 0.5f * radius)); + @Override + public String getUIClassID() { + return SensorUI.UI_CLASS_ID; } @Override - public void renderTile(Graphics2D g2d) { - renderStraight(g2d); - renderSensor(g2d); + public void updateUI() { + UIManager.put(TileUI.UI_CLASS_ID, "jcs.ui.layout.tiles.ui.SensorUI"); + setUI((TileUI) UIManager.getUI(this)); + invalidate(); } @Override diff --git a/src/main/java/jcs/ui/layout/tiles/Signal.java b/src/main/java/jcs/ui/layout/tiles/Signal.java index 1b7a5b49..982b666d 100644 --- a/src/main/java/jcs/ui/layout/tiles/Signal.java +++ b/src/main/java/jcs/ui/layout/tiles/Signal.java @@ -15,26 +15,17 @@ */ package jcs.ui.layout.tiles; -import java.awt.BasicStroke; -import java.awt.Color; -import java.awt.Graphics2D; import java.awt.Point; -import java.awt.Polygon; +import javax.swing.UIManager; import jcs.commandStation.events.AccessoryEvent; import jcs.commandStation.events.AccessoryEventListener; import jcs.entities.AccessoryBean.SignalType; -import static jcs.entities.AccessoryBean.SignalType.HP012; -import static jcs.entities.AccessoryBean.SignalType.HP012SH1; -import static jcs.entities.AccessoryBean.SignalType.HP0SH1; import jcs.entities.AccessoryBean.SignalValue; -import static jcs.entities.AccessoryBean.SignalValue.Hp0; -import static jcs.entities.AccessoryBean.SignalValue.Hp0Sh1; -import static jcs.entities.AccessoryBean.SignalValue.Hp1; -import static jcs.entities.AccessoryBean.SignalValue.Hp2; import jcs.entities.TileBean; import jcs.entities.TileBean.Orientation; import jcs.entities.TileBean.TileType; -import static jcs.ui.layout.tiles.Tile.RENDER_GRID; +import jcs.ui.layout.tiles.ui.SignalUI; +import jcs.ui.layout.tiles.ui.TileUI; public class Signal extends Straight implements AccessoryEventListener { @@ -57,283 +48,290 @@ public class Signal extends Straight implements AccessoryEventListener { this.signalValue = SignalValue.OFF; } - /** - * Render a Signal with 2 lights - * - * @param g2d the graphics context - */ - protected void renderSignal2(Graphics2D g2d) { - int rx = RENDER_GRID; - int ry = RENDER_GRID + 60; - int rw = 180; - int rh = 100; - int l1x = RENDER_GRID + 20; - int l1y = RENDER_GRID + 80; - int l2x = RENDER_GRID + 100; - int l2y = RENDER_GRID + 80; - - Color color1 = Color.gray; - Color color2 = Color.gray; - - if (this.signalValue == null) { - this.signalValue = SignalValue.OFF; - } - - switch (signalValue) { - case Hp0 -> { - color1 = Color.red; - color2 = Color.gray; - } - case Hp1 -> { - color1 = Color.gray; - color2 = Color.green; - } - default -> { - } - } - - g2d.setStroke(new BasicStroke(10f)); - g2d.setPaint(Color.darkGray); - g2d.fillRoundRect(rx, ry, rw, rh, 30, 30); - - g2d.setPaint(color1); - g2d.fillOval(l1x, l1y, 60, 60); - g2d.setPaint(color2); - g2d.fillOval(l2x, l2y, 60, 60); - } - - protected void renderSignal3(Graphics2D g2d) { - int rx = RENDER_GRID; - int ry = RENDER_GRID + 60; - int rw = 180; - int rh = 100; - - int c1x = RENDER_GRID + 130; - int c1y = RENDER_GRID + 115; - - int c2x = RENDER_GRID + 10; - int c2y = RENDER_GRID + 115; - - int c3x = RENDER_GRID + 10; - int c3y = RENDER_GRID + 65; - - // Initialize all "lights" - Color color1 = Color.gray; - Color color2 = Color.gray; - Color color3 = Color.gray; - - if (this.signalValue == null) { - this.signalValue = SignalValue.OFF; - } - - switch (this.signalValue) { - case Hp0 -> { - color3 = Color.red; - } - case Hp1 -> - color1 = Color.green; - case Hp2 -> { - color1 = Color.green; - color2 = Color.yellow; - } - default -> { - } - } - - g2d.setStroke(new BasicStroke(10f)); - g2d.setPaint(Color.darkGray); - g2d.fillRoundRect(rx, ry, rw, rh, 30, 30); - - g2d.setPaint(color1); - g2d.fillOval(c1x, c1y, 40, 40); - - g2d.setPaint(color2); - g2d.fillOval(c2x, c2y, 40, 40); - - g2d.setPaint(color3); - g2d.fillOval(c3x, c3y, 40, 40); - } - - /** - * Render a entry Signal which can show 4 light images - * - * @param g2d the Graphics context - */ - protected void renderSignal4(Graphics2D g2d) { - int rx = RENDER_GRID - 50; - int ry = RENDER_GRID + 50; - int rw = 240; - int rh = 120; - int c1x = RENDER_GRID + 140; - int c1y = RENDER_GRID + 60; - - int c2x = RENDER_GRID + 90; - int c2y = RENDER_GRID + 60; - - int c3x = RENDER_GRID + 90; - int c3y = RENDER_GRID + 120; - - int c4x = RENDER_GRID + 60; - int c4y = RENDER_GRID + 130; - - int c5x = RENDER_GRID + 10; - int c5y = RENDER_GRID + 70; - - int c6x = RENDER_GRID - 40; - int c6y = RENDER_GRID + 60; - - // Initialize all "lights" - Color color1 = Color.gray; - Color color2 = Color.gray; - Color color3 = Color.gray; - Color color4 = Color.gray; - Color color5 = Color.gray; - Color color6 = Color.gray; - - if (this.signalValue == null) { - this.signalValue = SignalValue.OFF; - } - - switch (this.signalValue) { - case Hp0 -> { - color2 = Color.red; - color3 = Color.red; - } - case Hp1 -> - color1 = Color.green; - case Hp2 -> { - color1 = Color.green; - color6 = Color.yellow; - } - case Hp0Sh1 -> { - color2 = Color.red; - color4 = Color.white; - color5 = Color.white; - } - default -> { - } - } - - g2d.setStroke(new BasicStroke(10f)); - g2d.setPaint(Color.darkGray); - g2d.fillRoundRect(rx, ry, rw, rh, 30, 30); - - g2d.setPaint(color1); - g2d.fillOval(c1x, c1y, 40, 40); - g2d.setPaint(color2); - g2d.fillOval(c2x, c2y, 40, 40); - g2d.setPaint(color3); - g2d.fillOval(c3x, c3y, 40, 40); - g2d.setPaint(color4); - g2d.fillOval(c4x, c4y, 20, 20); - g2d.setPaint(color5); - g2d.fillOval(c5x, c5y, 20, 20); - g2d.setPaint(color6); - g2d.fillOval(c6x, c6y, 40, 40); - } - - /** - * Render a midget Signal - * - * @param g2d the Graphics context - */ - protected void renderSignal2m(Graphics2D g2d) { - int[] xps - = new int[]{ - RENDER_GRID + 80, - +RENDER_GRID + 150, - +RENDER_GRID + 170, - RENDER_GRID + 170, - +RENDER_GRID + 150, - RENDER_GRID + 80 - }; - int[] yps - = new int[]{ - RENDER_GRID + 60, - RENDER_GRID + 60, - RENDER_GRID + 80, - +RENDER_GRID + 160, - +RENDER_GRID + 180, - RENDER_GRID + 180 - }; - - Polygon signalOutline = new Polygon(xps, yps, xps.length); - - int c1x = RENDER_GRID + 130; - int c1y = RENDER_GRID + 70; - - int c2x = RENDER_GRID + 130; - int c2y = RENDER_GRID + 140; - - int c3x = RENDER_GRID + 130; - int c3y = RENDER_GRID + 105; - - int c4x = RENDER_GRID + 85; - int c4y = RENDER_GRID + 70; - - Color color1 = Color.gray; - Color color2 = Color.gray; - Color color3 = Color.gray; - Color color4 = Color.gray; - - if (this.signalValue == null) { - this.signalValue = SignalValue.OFF; - } - - switch (this.signalValue) { - case Hp0 -> { - color1 = Color.red; - color2 = Color.red; - } - case Hp1 -> { - color3 = Color.white; - color4 = Color.white; - } - default -> { - } - } - - g2d.setStroke(new BasicStroke(10f)); - g2d.setPaint(Color.darkGray); - - g2d.fillPolygon(signalOutline); - - g2d.setPaint(color1); - g2d.fillOval(c1x, c1y, 30, 30); - - g2d.setPaint(color2); - g2d.fillOval(c2x, c2y, 30, 30); - - g2d.setPaint(color3); - g2d.fillOval(c3x, c3y, 30, 30); - - g2d.setPaint(color4); - g2d.fillOval(c4x, c4y, 30, 30); + @Override + public String getUIClassID() { + return SignalUI.UI_CLASS_ID; } @Override - public void renderTile(Graphics2D g2) { - Graphics2D g2d = (Graphics2D) g2.create(); - renderStraight(g2d); - - if (signalType == null) { - signalType = SignalType.NONE; - } - - switch (signalType) { - case HP012 -> - renderSignal3(g2d); - case HP012SH1 -> - renderSignal4(g2d); - case HP0SH1 -> - renderSignal2m(g2d); - default -> - renderSignal2(g2d); - } - - g2d.dispose(); + public void updateUI() { + UIManager.put(TileUI.UI_CLASS_ID, "jcs.ui.layout.tiles.ui.SignalUI"); + setUI((TileUI) UIManager.getUI(this)); + invalidate(); } +// /** +// * Render a Signal with 2 lights +// * +// * @param g2d the graphics context +// */ +// protected void renderSignal2(Graphics2D g2d) { +// int rx = RENDER_GRID; +// int ry = RENDER_GRID + 60; +// int rw = 180; +// int rh = 100; +// int l1x = RENDER_GRID + 20; +// int l1y = RENDER_GRID + 80; +// int l2x = RENDER_GRID + 100; +// int l2y = RENDER_GRID + 80; +// +// Color color1 = Color.gray; +// Color color2 = Color.gray; +// +// if (this.signalValue == null) { +// this.signalValue = SignalValue.OFF; +// } +// +// switch (signalValue) { +// case Hp0 -> { +// color1 = Color.red; +// color2 = Color.gray; +// } +// case Hp1 -> { +// color1 = Color.gray; +// color2 = Color.green; +// } +// default -> { +// } +// } +// +// g2d.setStroke(new BasicStroke(10f)); +// g2d.setPaint(Color.darkGray); +// g2d.fillRoundRect(rx, ry, rw, rh, 30, 30); +// +// g2d.setPaint(color1); +// g2d.fillOval(l1x, l1y, 60, 60); +// g2d.setPaint(color2); +// g2d.fillOval(l2x, l2y, 60, 60); +// } +// protected void renderSignal3(Graphics2D g2d) { +// int rx = RENDER_GRID; +// int ry = RENDER_GRID + 60; +// int rw = 180; +// int rh = 100; +// +// int c1x = RENDER_GRID + 130; +// int c1y = RENDER_GRID + 115; +// +// int c2x = RENDER_GRID + 10; +// int c2y = RENDER_GRID + 115; +// +// int c3x = RENDER_GRID + 10; +// int c3y = RENDER_GRID + 65; +// +// // Initialize all "lights" +// Color color1 = Color.gray; +// Color color2 = Color.gray; +// Color color3 = Color.gray; +// +// if (this.signalValue == null) { +// this.signalValue = SignalValue.OFF; +// } +// +// switch (this.signalValue) { +// case Hp0 -> { +// color3 = Color.red; +// } +// case Hp1 -> +// color1 = Color.green; +// case Hp2 -> { +// color1 = Color.green; +// color2 = Color.yellow; +// } +// default -> { +// } +// } +// +// g2d.setStroke(new BasicStroke(10f)); +// g2d.setPaint(Color.darkGray); +// g2d.fillRoundRect(rx, ry, rw, rh, 30, 30); +// +// g2d.setPaint(color1); +// g2d.fillOval(c1x, c1y, 40, 40); +// +// g2d.setPaint(color2); +// g2d.fillOval(c2x, c2y, 40, 40); +// +// g2d.setPaint(color3); +// g2d.fillOval(c3x, c3y, 40, 40); +// } +// /** +// * Render a entry Signal which can show 4 light images +// * +// * @param g2d the Graphics context +// */ +// protected void renderSignal4(Graphics2D g2d) { +// int rx = RENDER_GRID - 50; +// int ry = RENDER_GRID + 50; +// int rw = 240; +// int rh = 120; +// int c1x = RENDER_GRID + 140; +// int c1y = RENDER_GRID + 60; +// +// int c2x = RENDER_GRID + 90; +// int c2y = RENDER_GRID + 60; +// +// int c3x = RENDER_GRID + 90; +// int c3y = RENDER_GRID + 120; +// +// int c4x = RENDER_GRID + 60; +// int c4y = RENDER_GRID + 130; +// +// int c5x = RENDER_GRID + 10; +// int c5y = RENDER_GRID + 70; +// +// int c6x = RENDER_GRID - 40; +// int c6y = RENDER_GRID + 60; +// +// // Initialize all "lights" +// Color color1 = Color.gray; +// Color color2 = Color.gray; +// Color color3 = Color.gray; +// Color color4 = Color.gray; +// Color color5 = Color.gray; +// Color color6 = Color.gray; +// +// if (this.signalValue == null) { +// this.signalValue = SignalValue.OFF; +// } +// +// switch (this.signalValue) { +// case Hp0 -> { +// color2 = Color.red; +// color3 = Color.red; +// } +// case Hp1 -> +// color1 = Color.green; +// case Hp2 -> { +// color1 = Color.green; +// color6 = Color.yellow; +// } +// case Hp0Sh1 -> { +// color2 = Color.red; +// color4 = Color.white; +// color5 = Color.white; +// } +// default -> { +// } +// } +// +// g2d.setStroke(new BasicStroke(10f)); +// g2d.setPaint(Color.darkGray); +// g2d.fillRoundRect(rx, ry, rw, rh, 30, 30); +// +// g2d.setPaint(color1); +// g2d.fillOval(c1x, c1y, 40, 40); +// g2d.setPaint(color2); +// g2d.fillOval(c2x, c2y, 40, 40); +// g2d.setPaint(color3); +// g2d.fillOval(c3x, c3y, 40, 40); +// g2d.setPaint(color4); +// g2d.fillOval(c4x, c4y, 20, 20); +// g2d.setPaint(color5); +// g2d.fillOval(c5x, c5y, 20, 20); +// g2d.setPaint(color6); +// g2d.fillOval(c6x, c6y, 40, 40); +// } +// /** +// * Render a midget Signal +// * +// * @param g2d the Graphics context +// */ +// protected void renderSignal2m(Graphics2D g2d) { +// int[] xps +// = new int[]{ +// RENDER_GRID + 80, +// +RENDER_GRID + 150, +// +RENDER_GRID + 170, +// RENDER_GRID + 170, +// +RENDER_GRID + 150, +// RENDER_GRID + 80 +// }; +// int[] yps +// = new int[]{ +// RENDER_GRID + 60, +// RENDER_GRID + 60, +// RENDER_GRID + 80, +// +RENDER_GRID + 160, +// +RENDER_GRID + 180, +// RENDER_GRID + 180 +// }; +// +// Polygon signalOutline = new Polygon(xps, yps, xps.length); +// +// int c1x = RENDER_GRID + 130; +// int c1y = RENDER_GRID + 70; +// +// int c2x = RENDER_GRID + 130; +// int c2y = RENDER_GRID + 140; +// +// int c3x = RENDER_GRID + 130; +// int c3y = RENDER_GRID + 105; +// +// int c4x = RENDER_GRID + 85; +// int c4y = RENDER_GRID + 70; +// +// Color color1 = Color.gray; +// Color color2 = Color.gray; +// Color color3 = Color.gray; +// Color color4 = Color.gray; +// +// if (this.signalValue == null) { +// this.signalValue = SignalValue.OFF; +// } +// +// switch (this.signalValue) { +// case Hp0 -> { +// color1 = Color.red; +// color2 = Color.red; +// } +// case Hp1 -> { +// color3 = Color.white; +// color4 = Color.white; +// } +// default -> { +// } +// } +// +// g2d.setStroke(new BasicStroke(10f)); +// g2d.setPaint(Color.darkGray); +// +// g2d.fillPolygon(signalOutline); +// +// g2d.setPaint(color1); +// g2d.fillOval(c1x, c1y, 30, 30); +// +// g2d.setPaint(color2); +// g2d.fillOval(c2x, c2y, 30, 30); +// +// g2d.setPaint(color3); +// g2d.fillOval(c3x, c3y, 30, 30); +// +// g2d.setPaint(color4); +// g2d.fillOval(c4x, c4y, 30, 30); +// } +// @Override +// public void renderTile(Graphics2D g2) { +// Graphics2D g2d = (Graphics2D) g2.create(); +// renderStraight(g2d); +// +// if (signalType == null) { +// signalType = SignalType.NONE; +// } +// +// switch (signalType) { +// case HP012 -> +// renderSignal3(g2d); +// case HP012SH1 -> +// renderSignal4(g2d); +// case HP0SH1 -> +// renderSignal2m(g2d); +// default -> +// renderSignal2(g2d); +// } +// +// g2d.dispose(); +// } //TODO move to UI delegate @Override public void onAccessoryChange(AccessoryEvent event) { diff --git a/src/main/java/jcs/ui/layout/tiles/Straight.java b/src/main/java/jcs/ui/layout/tiles/Straight.java index e34552ca..2160a5f1 100755 --- a/src/main/java/jcs/ui/layout/tiles/Straight.java +++ b/src/main/java/jcs/ui/layout/tiles/Straight.java @@ -1 +1,104 @@ -/* * Copyright 2023 Frans Jacobs. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package jcs.ui.layout.tiles; import java.awt.BasicStroke; import java.awt.Graphics2D; import java.awt.Point; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set; import jcs.entities.TileBean; import jcs.entities.TileBean.Orientation; import jcs.entities.TileBean.TileType; public class Straight extends Tile { public Straight(TileBean tileBean) { super(tileBean, DEFAULT_WIDTH, DEFAULT_HEIGHT); setModel(new DefaultTileModel(tileBean.getOrientation())); } public Straight(Orientation orientation, Point center) { this(orientation, center.x, center.y); } public Straight(Orientation orientation, int x, int y) { this(orientation, x, y, DEFAULT_WIDTH, DEFAULT_HEIGHT); } public Straight(Orientation orientation, int x, int y, int width, int height) { super(TileType.STRAIGHT, orientation, x, y, width, height); setModel(new DefaultTileModel(orientation)); } @Override public Map getNeighborPoints() { Map neighbors = new HashMap<>(); Orientation orientation = this.getOrientation(); int cx = this.getCenterX(); int cy = this.getCenterY(); if (Orientation.EAST == orientation || Orientation.WEST == orientation) { // Horizontal neighbors.put(Orientation.EAST, new Point(cx + Tile.GRID * 2, cy)); neighbors.put(Orientation.WEST, new Point(cx - Tile.GRID * 2, cy)); } else { // Vertical neighbors.put(Orientation.NORTH, new Point(cx, cy - Tile.GRID * 2)); neighbors.put(Orientation.SOUTH, new Point(cx, cy + Tile.GRID * 2)); } return neighbors; } @Override public Map getEdgePoints() { Map edgeConnections = new HashMap<>(); Orientation orientation = this.getOrientation(); int cx = this.getCenterX(); int cy = this.getCenterY(); if (Orientation.EAST == orientation || Orientation.WEST == orientation) { // Horizontal edgeConnections.put(Orientation.EAST, new Point(cx + Tile.GRID, cy)); edgeConnections.put(Orientation.WEST, new Point(cx - Tile.GRID, cy)); } else { // Vertical edgeConnections.put(Orientation.NORTH, new Point(cx, cy - Tile.GRID)); edgeConnections.put(Orientation.SOUTH, new Point(cx, cy + Tile.GRID)); } return edgeConnections; } protected void renderStraight(Graphics2D g2) { int xx, yy, w, h; xx = 0; yy = 170; w = RENDER_WIDTH; h = 60; g2.setStroke(new BasicStroke(4, BasicStroke.JOIN_MITER, BasicStroke.JOIN_ROUND)); g2.setPaint(trackColor); g2.fillRect(xx, yy, w, h); } protected void renderRouteStraight(Graphics2D g2) { int xx, yy, w, h; xx = 0; yy = 190; w = RENDER_WIDTH; h = 20; g2.setStroke(new BasicStroke(4, BasicStroke.JOIN_MITER, BasicStroke.JOIN_ROUND)); g2.setPaint(trackRouteColor); g2.fillRect(xx, yy, w, h); } @Override public void renderTileRoute(Graphics2D g2) { renderRouteStraight(g2); } @Override public void renderTile(Graphics2D g2) { renderStraight(g2); } } \ No newline at end of file +/* + * Copyright 2023 Frans Jacobs. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package jcs.ui.layout.tiles; + +import jcs.ui.layout.tiles.ui.StraightUI; +import jcs.ui.layout.tiles.ui.TileUI; +import java.awt.Point; +import java.util.HashMap; +import java.util.Map; +import javax.swing.UIManager; +import jcs.entities.TileBean; +import jcs.entities.TileBean.Orientation; +import jcs.entities.TileBean.TileType; + +public class Straight extends Tile { + + public Straight(TileBean tileBean) { + super(tileBean, DEFAULT_WIDTH, DEFAULT_HEIGHT); + setModel(new DefaultTileModel(tileBean.getOrientation())); + initUI(); + } + + public Straight(Orientation orientation, Point center) { + this(orientation, center.x, center.y); + } + + public Straight(Orientation orientation, int x, int y) { + this(orientation, x, y, DEFAULT_WIDTH, DEFAULT_HEIGHT); + } + + public Straight(Orientation orientation, int x, int y, int width, int height) { + super(TileType.STRAIGHT, orientation, x, y, width, height); + setModel(new DefaultTileModel(orientation)); + initUI(); + } + + private void initUI() { + updateUI(); + } + + @Override + public String getUIClassID() { + return StraightUI.UI_CLASS_ID; + } + + @Override + public void updateUI() { + UIManager.put(TileUI.UI_CLASS_ID, "jcs.ui.layout.tiles.ui.StraightUI"); + setUI((TileUI) UIManager.getUI(this)); + invalidate(); + } + + @Override + public Map getNeighborPoints() { + Map neighbors = new HashMap<>(); + Orientation orientation = this.getOrientation(); + int cx = this.getCenterX(); + int cy = this.getCenterY(); + + if (Orientation.EAST == orientation || Orientation.WEST == orientation) { + // Horizontal + neighbors.put(Orientation.EAST, new Point(cx + Tile.GRID * 2, cy)); + neighbors.put(Orientation.WEST, new Point(cx - Tile.GRID * 2, cy)); + } else { + // Vertical + neighbors.put(Orientation.NORTH, new Point(cx, cy - Tile.GRID * 2)); + neighbors.put(Orientation.SOUTH, new Point(cx, cy + Tile.GRID * 2)); + } + return neighbors; + } + + @Override + public Map getEdgePoints() { + Map edgeConnections = new HashMap<>(); + Orientation orientation = this.getOrientation(); + int cx = this.getCenterX(); + int cy = this.getCenterY(); + + if (Orientation.EAST == orientation || Orientation.WEST == orientation) { + // Horizontal + edgeConnections.put(Orientation.EAST, new Point(cx + Tile.GRID, cy)); + edgeConnections.put(Orientation.WEST, new Point(cx - Tile.GRID, cy)); + } else { + // Vertical + edgeConnections.put(Orientation.NORTH, new Point(cx, cy - Tile.GRID)); + edgeConnections.put(Orientation.SOUTH, new Point(cx, cy + Tile.GRID)); + } + return edgeConnections; + } + +} diff --git a/src/main/java/jcs/ui/layout/tiles/StraightDirection.java b/src/main/java/jcs/ui/layout/tiles/StraightDirection.java index df3fbd01..df847634 100644 --- a/src/main/java/jcs/ui/layout/tiles/StraightDirection.java +++ b/src/main/java/jcs/ui/layout/tiles/StraightDirection.java @@ -15,14 +15,14 @@ */ package jcs.ui.layout.tiles; -import java.awt.BasicStroke; -import java.awt.Color; -import java.awt.Graphics2D; import java.awt.Point; import java.util.Collection; +import javax.swing.UIManager; import jcs.entities.TileBean; import jcs.entities.TileBean.Orientation; import jcs.entities.TileBean.TileType; +import jcs.ui.layout.tiles.ui.StraightDirectionUI; +import jcs.ui.layout.tiles.ui.TileUI; public class StraightDirection extends Straight { @@ -40,6 +40,18 @@ public StraightDirection(Orientation orientation, Point center) { this.tileType = TileType.STRAIGHT_DIR; } + @Override + public String getUIClassID() { + return StraightDirectionUI.UI_CLASS_ID; + } + + @Override + public void updateUI() { + UIManager.put(TileUI.UI_CLASS_ID, "jcs.ui.layout.tiles.ui.StraightDirectionUI"); + setUI((TileUI) UIManager.getUI(this)); + invalidate(); + } + @Override public boolean isDirectional() { return true; @@ -63,20 +75,18 @@ public boolean isArrowDirection(Tile other) { return arrowDirection && isAdjacent(other); } - private void renderDirectionArrow(Graphics2D g2) { - // |\ - // ==|+=== - // |/ - g2.setStroke(new BasicStroke(4, BasicStroke.JOIN_MITER, BasicStroke.JOIN_ROUND)); - g2.setPaint(Color.green.darker()); - - g2.fillPolygon(new int[]{150, 150, 270}, new int[]{130, 270, 200}, 3); - } - - @Override - public void renderTile(Graphics2D g2d) { - renderStraight(g2d); - renderDirectionArrow(g2d); - } - +// private void renderDirectionArrow(Graphics2D g2) { +// // |\ +// // ==|+=== +// // |/ +// g2.setStroke(new BasicStroke(4, BasicStroke.JOIN_MITER, BasicStroke.JOIN_ROUND)); +// g2.setPaint(Color.green.darker()); +// +// g2.fillPolygon(new int[]{150, 150, 270}, new int[]{130, 270, 200}, 3); +// } +// @Override +// public void renderTile(Graphics2D g2d) { +// renderStraight(g2d); +// renderDirectionArrow(g2d); +// } } diff --git a/src/main/java/jcs/ui/layout/tiles/Switch.java b/src/main/java/jcs/ui/layout/tiles/Switch.java index 9dd3a651..933583f8 100644 --- a/src/main/java/jcs/ui/layout/tiles/Switch.java +++ b/src/main/java/jcs/ui/layout/tiles/Switch.java @@ -1 +1,345 @@ -/* * Copyright 2023 Frans Jacobs. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package jcs.ui.layout.tiles; import java.awt.BasicStroke; import java.awt.Color; import java.awt.Graphics2D; import java.awt.Point; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set; import jcs.commandStation.events.AccessoryEvent; import jcs.commandStation.events.AccessoryEventListener; import jcs.entities.AccessoryBean.AccessoryValue; import static jcs.entities.AccessoryBean.AccessoryValue.GREEN; import static jcs.entities.AccessoryBean.AccessoryValue.RED; import jcs.entities.TileBean; import jcs.entities.TileBean.Direction; import static jcs.entities.TileBean.Direction.LEFT; import static jcs.entities.TileBean.Direction.RIGHT; import jcs.entities.TileBean.Orientation; import static jcs.entities.TileBean.Orientation.NORTH; import static jcs.entities.TileBean.Orientation.SOUTH; import static jcs.entities.TileBean.Orientation.WEST; import jcs.entities.TileBean.TileType; public class Switch extends Tile implements AccessoryEventListener { public Switch(Orientation orientation, Direction direction, Point center) { this(orientation, direction, center.x, center.y); } public Switch(Orientation orientation, Direction direction, int x, int y) { this(orientation, direction, x, y, DEFAULT_WIDTH, DEFAULT_HEIGHT); } public Switch(Orientation orientation, Direction direction, int x, int y, int width, int height) { this(TileType.SWITCH, orientation, direction, x, y, width, height); } protected Switch(TileType tileType, Orientation orientation, Direction direction, int x, int y, int width, int height) { super(tileType, orientation, direction, x, y, width, height); setModel(new DefaultTileModel(orientation)); } public Switch(TileBean tileBean) { this(tileBean, DEFAULT_WIDTH, DEFAULT_HEIGHT); } protected Switch(TileBean tileBean, int width, int height) { super(tileBean, width, height); setModel(new DefaultTileModel(tileBean.getOrientation())); } @Override public Map getNeighborPoints() { Map neighbors = new HashMap<>(); Orientation orientation = this.getOrientation(); Direction direction = this.getDirection(); int cx = this.getCenterX(); int cy = this.getCenterY(); switch (orientation) { case SOUTH -> { neighbors.put(Orientation.NORTH, new Point(cx, cy - Tile.GRID * 2)); neighbors.put(Orientation.SOUTH, new Point(cx, cy + Tile.GRID * 2)); if (Direction.LEFT == direction) { neighbors.put(Orientation.WEST, new Point(cx - Tile.GRID * 2, cy)); } else { neighbors.put(Orientation.EAST, new Point(cx + Tile.GRID * 2, cy)); } } case WEST -> { neighbors.put(Orientation.EAST, new Point(cx + Tile.GRID * 2, cy)); neighbors.put(Orientation.WEST, new Point(cx - Tile.GRID * 2, cy)); if (Direction.LEFT == direction) { neighbors.put(Orientation.NORTH, new Point(cx, cy - Tile.GRID * 2)); } else { neighbors.put(Orientation.SOUTH, new Point(cx, cy + Tile.GRID * 2)); } } case NORTH -> { neighbors.put(Orientation.NORTH, new Point(cx, cy - Tile.GRID * 2)); neighbors.put(Orientation.SOUTH, new Point(cx, cy + Tile.GRID * 2)); if (Direction.LEFT == direction) { neighbors.put(Orientation.EAST, new Point(cx + Tile.GRID * 2, cy)); } else { neighbors.put(Orientation.WEST, new Point(cx - Tile.GRID * 2, cy)); } } default -> { //EAST neighbors.put(Orientation.EAST, new Point(cx + Tile.GRID * 2, cy)); neighbors.put(Orientation.WEST, new Point(cx - Tile.GRID * 2, cy)); if (Direction.LEFT == direction) { neighbors.put(Orientation.SOUTH, new Point(cx, cy + Tile.GRID * 2)); } else { neighbors.put(Orientation.NORTH, new Point(cx, cy - Tile.GRID * 2)); } } } return neighbors; } @Override public Map getEdgePoints() { Map edgeConnections = new HashMap<>(); Orientation orientation = this.getOrientation(); Direction direction = this.getDirection(); int cx = this.getCenterX(); int cy = this.getCenterY(); switch (orientation) { case SOUTH -> { edgeConnections.put(Orientation.NORTH, new Point(cx, cy - Tile.GRID)); edgeConnections.put(Orientation.SOUTH, new Point(cx, cy + Tile.GRID)); if (Direction.LEFT == direction) { edgeConnections.put(Orientation.WEST, new Point(cx - Tile.GRID, cy)); } else { edgeConnections.put(Orientation.EAST, new Point(cx + Tile.GRID, cy)); } } case WEST -> { edgeConnections.put(Orientation.EAST, new Point(cx + Tile.GRID, cy)); edgeConnections.put(Orientation.WEST, new Point(cx - Tile.GRID, cy)); if (Direction.LEFT == direction) { edgeConnections.put(Orientation.NORTH, new Point(cx, cy - Tile.GRID)); } else { edgeConnections.put(Orientation.SOUTH, new Point(cx, cy + Tile.GRID)); } } case NORTH -> { edgeConnections.put(Orientation.NORTH, new Point(cx, cy - Tile.GRID)); edgeConnections.put(Orientation.SOUTH, new Point(cx, cy + Tile.GRID)); if (Direction.LEFT == direction) { edgeConnections.put(Orientation.EAST, new Point(cx + Tile.GRID, cy)); } else { edgeConnections.put(Orientation.WEST, new Point(cx - Tile.GRID, cy)); } } default -> { //EAST edgeConnections.put(Orientation.EAST, new Point(cx + Tile.GRID, cy)); edgeConnections.put(Orientation.WEST, new Point(cx - Tile.GRID, cy)); if (Direction.LEFT == direction) { edgeConnections.put(Orientation.SOUTH, new Point(cx, cy + Tile.GRID)); } else { edgeConnections.put(Orientation.NORTH, new Point(cx, cy - Tile.GRID)); } } } return edgeConnections; } protected void renderStraight(Graphics2D g2, Color color) { int xx, yy, w, h; xx = 0; yy = 170; w = RENDER_WIDTH; h = 60; g2.setStroke(new BasicStroke(4, BasicStroke.JOIN_MITER, BasicStroke.JOIN_ROUND)); g2.setPaint(color); g2.fillRect(xx, yy, w, h); } protected void renderDiagonal(Graphics2D g2, Color color) { int[] xPoints, yPoints; if (Direction.RIGHT.equals(getDirection())) { xPoints = new int[]{400, 400, 170, 230}; yPoints = new int[]{170, 230, 0, 0}; } else { xPoints = new int[]{400, 400, 170, 230}; yPoints = new int[]{230, 170, 400, 400}; } g2.setStroke(new BasicStroke(1, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND)); g2.setPaint(color); g2.fillPolygon(xPoints, yPoints, xPoints.length); } protected void renderRouteStraight(Graphics2D g2, Color color) { int xx, yy, w, h; xx = 0; yy = 190; w = RENDER_WIDTH; h = 20; g2.setStroke(new BasicStroke(4, BasicStroke.JOIN_MITER, BasicStroke.JOIN_ROUND)); g2.setPaint(color); g2.fillRect(xx, yy, w, h); } protected void renderRouteDiagonal(Graphics2D g2, Color color) { int[] xPoints, yPoints; if (Direction.RIGHT.equals(getDirection())) { xPoints = new int[]{400, 400, 190, 210}; yPoints = new int[]{190, 210, 0, 0}; } else { xPoints = new int[]{400, 400, 190, 210}; yPoints = new int[]{210, 190, 400, 400}; } g2.setStroke(new BasicStroke(1, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND)); g2.setPaint(color); g2.fillPolygon(xPoints, yPoints, xPoints.length); } @Override public void renderTile(Graphics2D g2) { if (accessoryValue == null) { this.accessoryValue = AccessoryValue.OFF; } switch (accessoryValue) { case RED -> { renderStraight(g2, trackColor); renderDiagonal(g2, Color.red); } case GREEN -> { renderDiagonal(g2, trackColor); renderStraight(g2, Color.green); } default -> { renderStraight(g2, trackColor); renderDiagonal(g2, trackColor); } } } @Override public void renderTileRoute(Graphics2D g2) { if (routeValue == null) { routeValue = AccessoryValue.OFF; } switch (routeValue) { case RED -> { renderRouteDiagonal(g2, trackRouteColor); } case GREEN -> { renderRouteStraight(g2, trackRouteColor); } default -> { } } } @Override public void onAccessoryChange(AccessoryEvent event) { if (getAccessoryBean() != null && event.isEventFor(accessoryBean)) { setAccessoryValue(event.getAccessoryBean().getAccessoryValue()); } } @Override public boolean isJunction() { return true; } @Override public AccessoryValue accessoryValueForRoute(Orientation from, Orientation to) { if (from != null && to != null && this.getDirection() != null) { switch (this.getDirection()) { case LEFT -> { if (this.isHorizontal()) { if ((from == Orientation.WEST && to == Orientation.EAST) || (from == Orientation.EAST && to == Orientation.WEST)) { return AccessoryValue.GREEN; } else if (((from == Orientation.EAST && to == Orientation.SOUTH) || (from == Orientation.SOUTH && to == Orientation.EAST)) && Orientation.EAST == this.getOrientation()) { return AccessoryValue.RED; } else if (((from == Orientation.WEST && to == Orientation.NORTH) || (from == Orientation.NORTH && to == Orientation.WEST)) && Orientation.WEST == this.getOrientation()) { return AccessoryValue.RED; } else { return AccessoryValue.OFF; } } else { //Vertical if ((from == Orientation.NORTH && to == Orientation.SOUTH) || (from == Orientation.SOUTH && to == Orientation.NORTH)) { return AccessoryValue.GREEN; } else if (((from == Orientation.SOUTH && to == Orientation.WEST) || (from == Orientation.WEST && to == Orientation.SOUTH)) && Orientation.SOUTH == this.getOrientation()) { return AccessoryValue.RED; } else if (((from == Orientation.NORTH && to == Orientation.EAST) || (from == Orientation.EAST && to == Orientation.NORTH)) && Orientation.NORTH == this.getOrientation()) { return AccessoryValue.RED; } else { return AccessoryValue.OFF; } } } case RIGHT -> { if (this.isHorizontal()) { if ((from == Orientation.WEST && to == Orientation.EAST) || (from == Orientation.EAST && to == Orientation.WEST)) { return AccessoryValue.GREEN; } else if (((from == Orientation.EAST && to == Orientation.NORTH) || (from == Orientation.NORTH && to == Orientation.EAST)) && Orientation.EAST == this.getOrientation()) { return AccessoryValue.RED; } else if (((from == Orientation.WEST && to == Orientation.SOUTH) || (from == Orientation.SOUTH && to == Orientation.WEST)) && Orientation.WEST == this.getOrientation()) { return AccessoryValue.RED; } else { return AccessoryValue.OFF; } } else { //Vertical if ((from == Orientation.NORTH && to == Orientation.SOUTH) || (from == Orientation.SOUTH && to == Orientation.NORTH)) { return AccessoryValue.GREEN; } else if (((from == Orientation.EAST && to == Orientation.SOUTH) || (from == Orientation.SOUTH && to == Orientation.EAST)) && Orientation.SOUTH == this.getOrientation()) { return AccessoryValue.RED; } else if (((from == Orientation.WEST && to == Orientation.NORTH) || (from == Orientation.NORTH && to == Orientation.WEST)) && Orientation.NORTH == this.getOrientation()) { return AccessoryValue.RED; } else { return AccessoryValue.OFF; } } } default -> { return AccessoryValue.OFF; } } } else { return AccessoryValue.OFF; } } // @Override // protected void paintComponent(Graphics g) { // long started = System.currentTimeMillis(); // super.paintComponent(g); // // setBounds(this.tileX - GRID, this.tileY - GRID, this.getWidth(), this.getHeight()); // // Graphics2D g2 = (Graphics2D) g.create(); // drawTile(g2); // g2.dispose(); // // g.drawImage(this.tileImage, 0, 0, null); // // long now = System.currentTimeMillis(); // Logger.trace(this.id + " Duration: " + (now - started) + " ms."); // } } \ No newline at end of file +/* + * Copyright 2023 Frans Jacobs. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package jcs.ui.layout.tiles; + +import java.awt.Point; +import java.util.HashMap; +import java.util.Map; +import javax.swing.UIManager; +import jcs.commandStation.events.AccessoryEvent; +import jcs.commandStation.events.AccessoryEventListener; +import jcs.entities.AccessoryBean.AccessoryValue; +import jcs.entities.TileBean; +import jcs.entities.TileBean.Direction; +import static jcs.entities.TileBean.Direction.LEFT; +import static jcs.entities.TileBean.Direction.RIGHT; +import jcs.entities.TileBean.Orientation; +import static jcs.entities.TileBean.Orientation.NORTH; +import static jcs.entities.TileBean.Orientation.SOUTH; +import static jcs.entities.TileBean.Orientation.WEST; +import jcs.entities.TileBean.TileType; +import jcs.ui.layout.tiles.ui.SwitchUI; +import jcs.ui.layout.tiles.ui.TileUI; + +public class Switch extends Tile implements AccessoryEventListener { + + public Switch(Orientation orientation, Direction direction, Point center) { + this(orientation, direction, center.x, center.y); + } + + public Switch(Orientation orientation, Direction direction, int x, int y) { + this(orientation, direction, x, y, DEFAULT_WIDTH, DEFAULT_HEIGHT); + } + + public Switch(Orientation orientation, Direction direction, int x, int y, int width, int height) { + this(TileType.SWITCH, orientation, direction, x, y, width, height); + } + + protected Switch(TileType tileType, Orientation orientation, Direction direction, int x, int y, int width, int height) { + super(tileType, orientation, direction, x, y, width, height); + setModel(new DefaultTileModel(orientation)); + initUI(); + } + + public Switch(TileBean tileBean) { + this(tileBean, DEFAULT_WIDTH, DEFAULT_HEIGHT); + } + + protected Switch(TileBean tileBean, int width, int height) { + super(tileBean, width, height); + setModel(new DefaultTileModel(tileBean.getOrientation())); + initUI(); + } + + private void initUI() { + updateUI(); + } + + @Override + public String getUIClassID() { + return SwitchUI.UI_CLASS_ID; + } + + @Override + public void updateUI() { + UIManager.put(TileUI.UI_CLASS_ID, "jcs.ui.layout.tiles.ui.SwitchUI"); + setUI((TileUI) UIManager.getUI(this)); + invalidate(); + } + + @Override + public Map getNeighborPoints() { + Map neighbors = new HashMap<>(); + Orientation orientation = this.getOrientation(); + Direction direction = this.getDirection(); + int cx = this.getCenterX(); + int cy = this.getCenterY(); + + switch (orientation) { + case SOUTH -> { + neighbors.put(Orientation.NORTH, new Point(cx, cy - Tile.GRID * 2)); + neighbors.put(Orientation.SOUTH, new Point(cx, cy + Tile.GRID * 2)); + if (Direction.LEFT == direction) { + neighbors.put(Orientation.WEST, new Point(cx - Tile.GRID * 2, cy)); + } else { + neighbors.put(Orientation.EAST, new Point(cx + Tile.GRID * 2, cy)); + } + } + case WEST -> { + neighbors.put(Orientation.EAST, new Point(cx + Tile.GRID * 2, cy)); + neighbors.put(Orientation.WEST, new Point(cx - Tile.GRID * 2, cy)); + if (Direction.LEFT == direction) { + neighbors.put(Orientation.NORTH, new Point(cx, cy - Tile.GRID * 2)); + } else { + neighbors.put(Orientation.SOUTH, new Point(cx, cy + Tile.GRID * 2)); + } + } + case NORTH -> { + neighbors.put(Orientation.NORTH, new Point(cx, cy - Tile.GRID * 2)); + neighbors.put(Orientation.SOUTH, new Point(cx, cy + Tile.GRID * 2)); + if (Direction.LEFT == direction) { + neighbors.put(Orientation.EAST, new Point(cx + Tile.GRID * 2, cy)); + } else { + neighbors.put(Orientation.WEST, new Point(cx - Tile.GRID * 2, cy)); + } + } + default -> { + //EAST + neighbors.put(Orientation.EAST, new Point(cx + Tile.GRID * 2, cy)); + neighbors.put(Orientation.WEST, new Point(cx - Tile.GRID * 2, cy)); + if (Direction.LEFT == direction) { + neighbors.put(Orientation.SOUTH, new Point(cx, cy + Tile.GRID * 2)); + } else { + neighbors.put(Orientation.NORTH, new Point(cx, cy - Tile.GRID * 2)); + } + } + } + return neighbors; + } + + @Override + public Map getEdgePoints() { + Map edgeConnections = new HashMap<>(); + Orientation orientation = this.getOrientation(); + Direction direction = this.getDirection(); + int cx = this.getCenterX(); + int cy = this.getCenterY(); + + switch (orientation) { + case SOUTH -> { + edgeConnections.put(Orientation.NORTH, new Point(cx, cy - Tile.GRID)); + edgeConnections.put(Orientation.SOUTH, new Point(cx, cy + Tile.GRID)); + if (Direction.LEFT == direction) { + edgeConnections.put(Orientation.WEST, new Point(cx - Tile.GRID, cy)); + } else { + edgeConnections.put(Orientation.EAST, new Point(cx + Tile.GRID, cy)); + } + } + case WEST -> { + edgeConnections.put(Orientation.EAST, new Point(cx + Tile.GRID, cy)); + edgeConnections.put(Orientation.WEST, new Point(cx - Tile.GRID, cy)); + if (Direction.LEFT == direction) { + edgeConnections.put(Orientation.NORTH, new Point(cx, cy - Tile.GRID)); + } else { + edgeConnections.put(Orientation.SOUTH, new Point(cx, cy + Tile.GRID)); + } + } + case NORTH -> { + edgeConnections.put(Orientation.NORTH, new Point(cx, cy - Tile.GRID)); + edgeConnections.put(Orientation.SOUTH, new Point(cx, cy + Tile.GRID)); + if (Direction.LEFT == direction) { + edgeConnections.put(Orientation.EAST, new Point(cx + Tile.GRID, cy)); + } else { + edgeConnections.put(Orientation.WEST, new Point(cx - Tile.GRID, cy)); + } + } + default -> { + //EAST + edgeConnections.put(Orientation.EAST, new Point(cx + Tile.GRID, cy)); + edgeConnections.put(Orientation.WEST, new Point(cx - Tile.GRID, cy)); + if (Direction.LEFT == direction) { + edgeConnections.put(Orientation.SOUTH, new Point(cx, cy + Tile.GRID)); + } else { + edgeConnections.put(Orientation.NORTH, new Point(cx, cy - Tile.GRID)); + } + } + } + return edgeConnections; + } + +// protected void renderStraight(Graphics2D g2, Color color) { +// int xx, yy, w, h; +// xx = 0; +// yy = 170; +// w = RENDER_WIDTH; +// h = 60; +// +// g2.setStroke(new BasicStroke(4, BasicStroke.JOIN_MITER, BasicStroke.JOIN_ROUND)); +// g2.setPaint(color); +// +// g2.fillRect(xx, yy, w, h); +// } +// protected void renderDiagonal(Graphics2D g2, Color color) { +// int[] xPoints, yPoints; +// if (Direction.RIGHT.equals(getDirection())) { +// xPoints = new int[]{400, 400, 170, 230}; +// yPoints = new int[]{170, 230, 0, 0}; +// } else { +// xPoints = new int[]{400, 400, 170, 230}; +// yPoints = new int[]{230, 170, 400, 400}; +// } +// +// g2.setStroke(new BasicStroke(1, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND)); +// g2.setPaint(color); +// g2.fillPolygon(xPoints, yPoints, xPoints.length); +// } +// protected void renderRouteStraight(Graphics2D g2, Color color) { +// int xx, yy, w, h; +// xx = 0; +// yy = 190; +// w = RENDER_WIDTH; +// h = 20; +// +// g2.setStroke(new BasicStroke(4, BasicStroke.JOIN_MITER, BasicStroke.JOIN_ROUND)); +// g2.setPaint(color); +// +// g2.fillRect(xx, yy, w, h); +// } +// protected void renderRouteDiagonal(Graphics2D g2, Color color) { +// int[] xPoints, yPoints; +// if (Direction.RIGHT.equals(getDirection())) { +// xPoints = new int[]{400, 400, 190, 210}; +// yPoints = new int[]{190, 210, 0, 0}; +// } else { +// xPoints = new int[]{400, 400, 190, 210}; +// yPoints = new int[]{210, 190, 400, 400}; +// } +// +// g2.setStroke(new BasicStroke(1, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND)); +// g2.setPaint(color); +// +// g2.fillPolygon(xPoints, yPoints, xPoints.length); +// } +// @Override +// public void renderTile(Graphics2D g2) { +// if (accessoryValue == null) { +// this.accessoryValue = AccessoryValue.OFF; +// } +// +// switch (accessoryValue) { +// case RED -> { +// renderStraight(g2, trackColor); +// renderDiagonal(g2, Color.red); +// } +// case GREEN -> { +// renderDiagonal(g2, trackColor); +// renderStraight(g2, Color.green); +// } +// default -> { +// renderStraight(g2, trackColor); +// renderDiagonal(g2, trackColor); +// } +// } +// } +// @Override +// public void renderTileRoute(Graphics2D g2) { +// if (routeValue == null) { +// routeValue = AccessoryValue.OFF; +// } +// switch (routeValue) { +// case RED -> { +// renderRouteDiagonal(g2, trackRouteColor); +// } +// case GREEN -> { +// renderRouteStraight(g2, trackRouteColor); +// } +// default -> { +// } +// } +// } + @Override + public void onAccessoryChange(AccessoryEvent event) { + if (getAccessoryBean() != null && event.isEventFor(accessoryBean)) { + setAccessoryValue(event.getAccessoryBean().getAccessoryValue()); + } + } + + @Override + public boolean isJunction() { + return true; + } + + @Override + public AccessoryValue accessoryValueForRoute(Orientation from, Orientation to) { + if (from != null && to != null && this.getDirection() != null) { + switch (this.getDirection()) { + case LEFT -> { + if (this.isHorizontal()) { + if ((from == Orientation.WEST && to == Orientation.EAST) || (from == Orientation.EAST && to == Orientation.WEST)) { + return AccessoryValue.GREEN; + } else if (((from == Orientation.EAST && to == Orientation.SOUTH) || (from == Orientation.SOUTH && to == Orientation.EAST)) && Orientation.EAST == this.getOrientation()) { + return AccessoryValue.RED; + } else if (((from == Orientation.WEST && to == Orientation.NORTH) || (from == Orientation.NORTH && to == Orientation.WEST)) && Orientation.WEST == this.getOrientation()) { + return AccessoryValue.RED; + } else { + return AccessoryValue.OFF; + } + } else { + //Vertical + if ((from == Orientation.NORTH && to == Orientation.SOUTH) || (from == Orientation.SOUTH && to == Orientation.NORTH)) { + return AccessoryValue.GREEN; + } else if (((from == Orientation.SOUTH && to == Orientation.WEST) || (from == Orientation.WEST && to == Orientation.SOUTH)) && Orientation.SOUTH == this.getOrientation()) { + return AccessoryValue.RED; + } else if (((from == Orientation.NORTH && to == Orientation.EAST) || (from == Orientation.EAST && to == Orientation.NORTH)) && Orientation.NORTH == this.getOrientation()) { + return AccessoryValue.RED; + } else { + return AccessoryValue.OFF; + } + } + } + case RIGHT -> { + if (this.isHorizontal()) { + if ((from == Orientation.WEST && to == Orientation.EAST) || (from == Orientation.EAST && to == Orientation.WEST)) { + return AccessoryValue.GREEN; + } else if (((from == Orientation.EAST && to == Orientation.NORTH) || (from == Orientation.NORTH && to == Orientation.EAST)) && Orientation.EAST == this.getOrientation()) { + return AccessoryValue.RED; + } else if (((from == Orientation.WEST && to == Orientation.SOUTH) || (from == Orientation.SOUTH && to == Orientation.WEST)) && Orientation.WEST == this.getOrientation()) { + return AccessoryValue.RED; + } else { + return AccessoryValue.OFF; + } + } else { + //Vertical + if ((from == Orientation.NORTH && to == Orientation.SOUTH) || (from == Orientation.SOUTH && to == Orientation.NORTH)) { + return AccessoryValue.GREEN; + } else if (((from == Orientation.EAST && to == Orientation.SOUTH) || (from == Orientation.SOUTH && to == Orientation.EAST)) && Orientation.SOUTH == this.getOrientation()) { + return AccessoryValue.RED; + } else if (((from == Orientation.WEST && to == Orientation.NORTH) || (from == Orientation.NORTH && to == Orientation.WEST)) && Orientation.NORTH == this.getOrientation()) { + return AccessoryValue.RED; + } else { + return AccessoryValue.OFF; + } + } + } + default -> { + return AccessoryValue.OFF; + } + } + } else { + return AccessoryValue.OFF; + } + } +} diff --git a/src/main/java/jcs/ui/layout/tiles/Tile.java b/src/main/java/jcs/ui/layout/tiles/Tile.java index 44b3636a..688c48f8 100755 --- a/src/main/java/jcs/ui/layout/tiles/Tile.java +++ b/src/main/java/jcs/ui/layout/tiles/Tile.java @@ -15,6 +15,7 @@ */ package jcs.ui.layout.tiles; +import jcs.ui.layout.tiles.ui.TileUI; import java.awt.Color; import java.awt.Dimension; import java.awt.Graphics; @@ -24,7 +25,6 @@ import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.geom.AffineTransform; -import java.awt.geom.Ellipse2D; import java.awt.image.AffineTransformOp; import java.awt.image.BufferedImage; import java.beans.PropertyChangeListener; @@ -53,9 +53,6 @@ import jcs.ui.layout.LayoutUtil; import static jcs.ui.layout.tiles.Block.BLOCK_HEIGHT; import static jcs.ui.layout.tiles.Block.BLOCK_WIDTH; -import org.imgscalr.Scalr; -import org.imgscalr.Scalr.Method; -import org.imgscalr.Scalr.Mode; import org.tinylog.Logger; /** @@ -75,16 +72,15 @@ *

* A Tile is rendered to a Buffered Image to speed up the display */ -public abstract class Tile extends JComponent { //implements TileEventListener { //, ItemSelectable { +public abstract class Tile extends JComponent { // implements ChangeListener public static final int GRID = 20; public static final int DEFAULT_WIDTH = GRID * 2; public static final int DEFAULT_HEIGHT = GRID * 2; - static final int RENDER_GRID = GRID * 10; - static final int RENDER_WIDTH = RENDER_GRID * 2; - static final int RENDER_HEIGHT = RENDER_GRID * 2; - + //static final int RENDER_GRID = GRID * 10; + //static final int RENDER_WIDTH = RENDER_GRID * 2; + //static final int RENDER_HEIGHT = RENDER_GRID * 2; public static final Color DEFAULT_BACKGROUND_COLOR = Color.white; public static final Color DEFAULT_TRACK_COLOR = Color.lightGray; public static final Color DEFAULT_ROUTE_TRACK_COLOR = Color.darkGray; @@ -92,7 +88,7 @@ public abstract class Tile extends JComponent { //implements TileEventListener { public static final Color DEFAULT_WARN_COLOR = Color.red; public static final String MODEL_CHANGED_PROPERTY = "model"; - public static final String CONTENT_AREA_FILLED_CHANGED_PROPERTY = "contentAreaFilled"; +// public static final String CONTENT_AREA_FILLED_CHANGED_PROPERTY = "contentAreaFilled"; /** * The data model that determines the button's state. @@ -103,10 +99,8 @@ public abstract class Tile extends JComponent { //implements TileEventListener { protected Integer tileX; protected Integer tileY; - protected int renderWidth; - protected int renderHeight; - - //protected Orientation tileOrientation; + //protected int renderWidth; + //protected int renderHeight; protected Direction tileDirection; protected TileType tileType; @@ -126,18 +120,16 @@ public abstract class Tile extends JComponent { //implements TileEventListener { protected List neighbours; - protected int offsetX = 0; - protected int offsetY = 0; +// protected int offsetX = 0; +// protected int offsetY = 0; protected int renderOffsetX = 0; protected int renderOffsetY = 0; - //protected Color selectedColor; - protected Color trackColor; - protected Color trackRouteColor; - protected Orientation incomingSide; - - protected Color backgroundColor; + //protected Color trackColor; + //protected Color trackRouteColor; + //protected Orientation incomingSide; + //protected Color backgroundColor; protected boolean drawName = true; protected BufferedImage tileImage; @@ -148,7 +140,6 @@ public abstract class Tile extends JComponent { //implements TileEventListener { protected ActionListener actionListener = null; protected transient ChangeEvent changeEvent; - private Handler handler; protected Tile(TileType tileType, Orientation orientation, Point center, int width, int height) { @@ -165,8 +156,6 @@ protected Tile(TileType tileType, Orientation orientation, Direction direction, protected Tile(TileType tileType, Orientation orientation, Direction direction, int x, int y, int width, int height, Color backgroundColor, Color selectedColor) { this.tileType = tileType; - //this.tileOrientation = orientation; - //model.setTileOrienation(orientation); this.tileDirection = direction; this.tileX = x; this.tileY = y; @@ -176,19 +165,13 @@ protected Tile(TileType tileType, Orientation orientation, Direction direction, setSize(d); setPreferredSize(d); - this.renderWidth = RENDER_WIDTH; - this.renderHeight = RENDER_HEIGHT; - - this.trackColor = DEFAULT_TRACK_COLOR; - this.backgroundColor = backgroundColor; - //this.selectedColor = selectedColor; - - if (this.backgroundColor == null) { - this.backgroundColor = DEFAULT_BACKGROUND_COLOR; - } -// if (this.selectedColor == null) { -// this.selectedColor = DEFAULT_SELECTED_COLOR; -// } + //this.renderWidth = RENDER_WIDTH; + //this.renderHeight = RENDER_HEIGHT; + //this.trackColor = DEFAULT_TRACK_COLOR; + //this.backgroundColor = backgroundColor; + //if (this.backgroundColor == null) { + // this.backgroundColor = DEFAULT_BACKGROUND_COLOR; + //} } protected Tile(TileBean tileBean) { @@ -200,8 +183,6 @@ protected Tile(TileBean tileBean, int width, int height) { //Quick properties this.id = tileBean.getId(); this.tileType = tileBean.getTileType(); - //this.tileOrientation = tileBean.getOrientation(); - //this.model.setTileOrienation(tileBean.getOrientation()); this.tileDirection = tileBean.getDirection(); this.tileX = tileBean.getX(); this.tileY = tileBean.getY(); @@ -219,13 +200,70 @@ protected Tile(TileBean tileBean, int width, int height) { setSize(d); setPreferredSize(d); - this.trackColor = DEFAULT_TRACK_COLOR; - this.backgroundColor = DEFAULT_BACKGROUND_COLOR; -// this.selectedColor = DEFAULT_SELECTED_COLOR; - this.renderWidth = RENDER_WIDTH; - this.renderHeight = RENDER_HEIGHT; + //this.trackColor = DEFAULT_TRACK_COLOR; + //this.backgroundColor = DEFAULT_BACKGROUND_COLOR; + //this.renderWidth = RENDER_WIDTH; + //this.renderHeight = RENDER_HEIGHT; + } + + @Override + public String getUIClassID() { + return TileUI.UI_CLASS_ID; } + @Override + public TileUI getUI() { + return (TileUI) ui; + } + + public void setUI(TileUI ui) { + super.setUI(ui); + } + + public TileModel getModel() { + return model; + } + + public void setModel(TileModel newModel) { + TileModel oldModel = getModel(); + + if (oldModel != null) { + oldModel.removeChangeListener(changeListener); + oldModel.removeActionListener(actionListener); + changeListener = null; + actionListener = null; + } + + model = newModel; + + if (newModel != null) { + changeListener = createChangeListener(); + actionListener = createActionListener(); + + newModel.addChangeListener(changeListener); + newModel.addActionListener(actionListener); + } + + firePropertyChange(MODEL_CHANGED_PROPERTY, oldModel, newModel); + if (newModel != oldModel) { + revalidate(); + repaint(); + } + } + +// @Override +// public String getUIClassID() { +// return TileUI.UI_CLASS_ID; +// } +// @Override +// public void updateUI() { +// if (UIManager.get(TileUI.UI_CLASS_ID) == null) { +// UIManager.put(TileUI.UI_CLASS_ID, getUIClassID()); +// } +// +// setUI((TileUI) UIManager.getUI(this)); +// invalidate(); +// } protected static int tileWidth(Orientation orientation, TileType tileType) { if (Orientation.EAST == orientation || Orientation.WEST == orientation) { if (null == tileType) { @@ -299,7 +337,6 @@ public boolean isSelected() { } public void setSelected(boolean b) { - //boolean oldValue = isSelected(); model.setSelected(b); } @@ -340,12 +377,10 @@ public void setCenter(Point center) { } public Orientation getOrientation() { - //return tileOrientation; return model.getTileOrienation(); } public void setOrientation(Orientation orientation) { - //this.tileOrientation = orientation; model.setTileOrienation(orientation); if (tileBean != null) { tileBean.setOrientation(orientation); @@ -518,14 +553,12 @@ public void setBlockBean(BlockBean blockBean) { this.blockBean = blockBean; } - public void setRenderWidth(int renderWidth) { - this.renderWidth = renderWidth; - } - - public void setRenderHeight(int renderHeight) { - this.renderHeight = renderHeight; - } - +// public void setRenderWidth(int renderWidth) { +// this.renderWidth = renderWidth; +// } +// public void setRenderHeight(int renderHeight) { +// this.renderHeight = renderHeight; +// } public int getRenderOffsetX() { return renderOffsetX; } @@ -550,20 +583,22 @@ public final void setTileType(TileType tileType) { this.tileType = tileType; } - public Color getTrackColor() { - return trackColor; - } - - public final void setTrackColor(Color trackColor) { - this.trackColor = trackColor; - } - - public Color getTrackRouteColor() { - return trackRouteColor; +// public Color getTrackColor() { +// return trackColor; +// } + public void setTrackColor(Color trackColor) { + if (getUI() != null) { + getUI().setTrackColor(trackColor); + } } +// public Color getTrackRouteColor() { +// return trackRouteColor; +// } public void setTrackRouteColor(Color trackRouteColor) { - this.trackRouteColor = trackRouteColor; + if (getUI() != null) { + getUI().setTrackRouteColor(trackRouteColor); + } } public Color getSelectedColor() { @@ -571,25 +606,23 @@ public Color getSelectedColor() { } public void setSelectedColor(Color selectedColor) { - this.model.setSelectedColor(selectedColor); + model.setSelectedColor(selectedColor); } public Orientation getIncomingSide() { - return incomingSide; + return model.getIncomingSide(); } public void setIncomingSide(Orientation incomingSide) { - this.incomingSide = incomingSide; - } - - public Color getBackgroundColor() { - return backgroundColor; - } - - public void setBackgroundColor(Color backgroundColor) { - this.backgroundColor = backgroundColor; + model.setIncomingSide(incomingSide); } +// public Color getBackgroundColor() { +// return backgroundColor; +// } +// public void setBackgroundColor(Color backgroundColor) { +// this.backgroundColor = backgroundColor; +// } public boolean isShowRoute() { return model.isShowRoute(); } @@ -598,25 +631,18 @@ public void setShowRoute(boolean drawRoute) { this.model.setShowRoute(drawRoute); } - public int getRenderWidth() { - return renderWidth; - } - - public int getRenderHeight() { - return renderHeight; - } - - abstract void renderTile(Graphics2D g2d); - - abstract void renderTileRoute(Graphics2D g2d); - +// public int getRenderWidth() { +// return renderWidth; +// } +// public int getRenderHeight() { +// return renderHeight; +// } +// abstract void renderTile(Graphics2D g2d); +// abstract void renderTileRoute(Graphics2D g2d); public abstract Map getNeighborPoints(); public abstract Map getEdgePoints(); - //public abstract Set getAllPoints(); - //public abstract Set getAllPoints(Point center); - //public abstract Set getAltPoints(Point center); Set getAltPoints(Point center) { return Collections.EMPTY_SET; } @@ -636,102 +662,96 @@ Set getAllPoints(Point center) { * * @param g2d The graphics handle */ - public void drawTile(Graphics2D g2d) { - // by default and image is rendered in the EAST orientation - Orientation tileOrientation = model.getTileOrienation(); - - BufferedImage bf = createImage(); - Graphics2D g2di = bf.createGraphics(); - - //Avoid errors - if (model.isShowRoute() && incomingSide == null) { - incomingSide = getOrientation(); - } - - if (model.isSelected()) { - g2di.setBackground(model.getSelectedColor()); - } else { - g2di.setBackground(backgroundColor); - } - - g2di.clearRect(0, 0, renderWidth, renderHeight); - int ox = 0, oy = 0; - - AffineTransform trans = new AffineTransform(); - switch (tileOrientation) { - case SOUTH -> { - trans.rotate(Math.PI / 2, renderWidth / 2, renderHeight / 2); - ox = (renderHeight - renderWidth) / 2; - oy = (renderWidth - renderHeight) / 2; - trans.translate(-ox, -oy); - } - case WEST -> { - trans.rotate(Math.PI, renderWidth / 2, renderHeight / 2); - trans.translate(ox, oy); - } - case NORTH -> { - trans.rotate(-Math.PI / 2, renderWidth / 2, renderHeight / 2); - ox = (renderHeight - renderWidth) / 2; - oy = (renderWidth - renderHeight) / 2; - trans.translate(-ox, -oy); - } - default -> { - trans.rotate(0.0, this.renderWidth / 2, this.renderHeight / 2); - trans.translate(ox, oy); - } - } - - //Logger.trace(tileOrientation.getOrientation() + " renderWidth: " + renderWidth + " renderHeight: " + renderHeight + " CP: (" + renderWidth / 2 + "," + renderHeight / 2 + ")"); - //Logger.trace(tileOrientation.getOrientation() + " ox: " + ox + " oy: " + oy); - g2di.setTransform(trans); - - renderTile(g2di); - - if (model.isShowRoute()) { - renderTileRoute(g2di); - } - - if (model.isShowCenter()) { - drawCenterPoint(g2di); - } - - // Scale the image back... - if (model.isScaleImage()) { - tileImage = Scalr.resize(bf, Method.AUTOMATIC, Mode.FIT_EXACT, getWidth(), getHeight(), Scalr.OP_ANTIALIAS); - } else { - tileImage = bf; - } - g2di.dispose(); - } - - public BufferedImage getTileImage() { - return tileImage; - } - +// public void drawTile(Graphics2D g2d) { +// // by default and image is rendered in the EAST orientation +// Orientation tileOrientation = model.getTileOrienation(); +// +// BufferedImage bf = createImage(); +// Graphics2D g2di = bf.createGraphics(); +// +// //Avoid errors +// if (model.isShowRoute() && model.getIncomingSide() == null) { +// model.setIncomingSide(tileOrientation); +// } +// +// if (model.isSelected()) { +// g2di.setBackground(model.getSelectedColor()); +// } else { +// g2di.setBackground(backgroundColor); +// } +// +// g2di.clearRect(0, 0, renderWidth, renderHeight); +// int ox = 0, oy = 0; +// +// AffineTransform trans = new AffineTransform(); +// switch (tileOrientation) { +// case SOUTH -> { +// trans.rotate(Math.PI / 2, renderWidth / 2, renderHeight / 2); +// ox = (renderHeight - renderWidth) / 2; +// oy = (renderWidth - renderHeight) / 2; +// trans.translate(-ox, -oy); +// } +// case WEST -> { +// trans.rotate(Math.PI, renderWidth / 2, renderHeight / 2); +// trans.translate(ox, oy); +// } +// case NORTH -> { +// trans.rotate(-Math.PI / 2, renderWidth / 2, renderHeight / 2); +// ox = (renderHeight - renderWidth) / 2; +// oy = (renderWidth - renderHeight) / 2; +// trans.translate(-ox, -oy); +// } +// default -> { +// trans.rotate(0.0, this.renderWidth / 2, this.renderHeight / 2); +// trans.translate(ox, oy); +// } +// } +// +// //Logger.trace(tileOrientation.getOrientation() + " renderWidth: " + renderWidth + " renderHeight: " + renderHeight + " CP: (" + renderWidth / 2 + "," + renderHeight / 2 + ")"); +// //Logger.trace(tileOrientation.getOrientation() + " ox: " + ox + " oy: " + oy); +// g2di.setTransform(trans); +// +// renderTile(g2di); +// +// if (model.isShowRoute()) { +// renderTileRoute(g2di); +// } +// +// if (model.isShowCenter()) { +// drawCenterPoint(g2di); +// } +// +// // Scale the image back... +// if (model.isScaleImage()) { +// tileImage = Scalr.resize(bf, Method.AUTOMATIC, Mode.FIT_EXACT, getWidth(), getHeight(), Scalr.OP_ANTIALIAS); +// } else { +// tileImage = bf; +// } +// g2di.dispose(); +// } +// public BufferedImage getTileImage() { +// return tileImage; +// } /** * Render a tile image Always starts at (0,0) used the default width and height * * @param g2 the Graphic context */ - public void drawName(Graphics2D g2) { - } - - protected void drawCenterPoint(Graphics2D g2d) { - drawCenterPoint(g2d, Color.magenta); - } - - protected void drawCenterPoint(Graphics2D g2, Color color) { - drawCenterPoint(g2, color, 60); - } - - protected void drawCenterPoint(Graphics2D g2d, Color color, double size) { - double dX = (renderWidth / 2 - size / 2); - double dY = (renderHeight / 2 - size / 2); - - g2d.setColor(color); - g2d.fill(new Ellipse2D.Double(dX, dY, size, size)); - } - +// public void drawName(Graphics2D g2) { +// } +// protected void drawCenterPoint(Graphics2D g2d) { +// drawCenterPoint(g2d, Color.magenta); +// } +// protected void drawCenterPoint(Graphics2D g2, Color color) { +// drawCenterPoint(g2, color, 60); +// } +// protected void drawCenterPoint(Graphics2D g2d, Color color, double size) { +// double dX = (renderWidth / 2 - size / 2); +// double dY = (renderHeight / 2 - size / 2); +// +// g2d.setColor(color); +// g2d.fill(new Ellipse2D.Double(dX, dY, size, size)); +// } /** * Rotate the tile clockwise 90 deg * @@ -774,13 +794,13 @@ public void move(int newX, int newY) { setCenter(cs); } - protected static void drawRotate(Graphics2D g2d, double x, double y, int angle, String text) { - g2d.translate((float) x, (float) y); - g2d.rotate(Math.toRadians(angle)); - g2d.drawString(text, 0, 0); - g2d.rotate(-Math.toRadians(angle)); - g2d.translate(-x, -y); - } +// protected static void drawRotate(Graphics2D g2d, double x, double y, int angle, String text) { +// g2d.translate((float) x, (float) y); +// g2d.rotate(Math.toRadians(angle)); +// g2d.drawString(text, 0, 0); +// g2d.rotate(-Math.toRadians(angle)); +// g2d.translate(-x, -y); +// } public static BufferedImage flipHorizontally(BufferedImage source) { BufferedImage output = new BufferedImage(source.getHeight(), source.getWidth(), source.getType()); @@ -810,26 +830,25 @@ public Set getAltPoints() { return Collections.EMPTY_SET; } - public final int getOffsetX() { - return offsetX; - } - - public void setOffsetX(int offsetX) { - this.offsetX = offsetX; - } - - public final int getOffsetY() { - return offsetY; - } - - public void setOffsetY(int offsetY) { - this.offsetY = offsetY; - } - - protected BufferedImage createImage() { - return new BufferedImage(renderWidth, renderHeight, BufferedImage.TYPE_INT_RGB); - } - +// public final int getOffsetX() { +// return offsetX; +// } +// +// public void setOffsetX(int offsetX) { +// this.offsetX = offsetX; +// } +// +// public final int getOffsetY() { +// return offsetY; +// } +// +// public void setOffsetY(int offsetY) { +// this.offsetY = offsetY; +// } + +// protected BufferedImage createImage() { +// return new BufferedImage(renderWidth, renderHeight, BufferedImage.TYPE_INT_RGB); +// } public int getCenterX() { if (tileX > 0) { return this.tileX; @@ -863,12 +882,14 @@ public void setScaleImage(boolean scaleImage) { if (scaleImage) { d = new Dimension(DEFAULT_WIDTH, DEFAULT_HEIGHT); } else { + int renderWidth = getUI().getRenderWidth(); + int renderHeight = getUI().getRenderHeight(); + d = new Dimension(renderWidth, renderHeight); } setSize(d); setPreferredSize(d); - model.setScaleImage(scaleImage); } @@ -1010,47 +1031,6 @@ public AccessoryValue accessoryValueForRoute(Orientation from, Orientation to) { return AccessoryValue.OFF; } - public TileModel getModel() { - return model; - } - - public void setModel(TileModel newModel) { - TileModel oldModel = getModel(); - - if (oldModel != null) { - oldModel.removeChangeListener(changeListener); - oldModel.removeActionListener(actionListener); - changeListener = null; - actionListener = null; - } - - model = newModel; - - if (newModel != null) { - changeListener = createChangeListener(); - actionListener = createActionListener(); - - newModel.addChangeListener(changeListener); - newModel.addActionListener(actionListener); - } - - firePropertyChange(MODEL_CHANGED_PROPERTY, oldModel, newModel); - if (newModel != oldModel) { - revalidate(); - repaint(); - } - } - -// public TileUI getUI() { -// return (TileUI) ui; -// } -// public void setUI(TileUI ui) { -// super.setUI(ui); -// } - @Override - public void updateUI() { - } - protected ChangeListener createChangeListener() { return getHandler(); } @@ -1119,6 +1099,9 @@ public Rectangle getTileBounds() { if (model.isScaleImage()) { return new Rectangle(tileX - GRID, tileY - GRID, DEFAULT_WIDTH, DEFAULT_HEIGHT); } else { + int renderWidth = getUI().getRenderWidth(); + int renderHeight = getUI().getRenderHeight(); + return new Rectangle(tileX - renderWidth / 2, tileY - renderHeight / 2, renderWidth, renderHeight); } } @@ -1127,13 +1110,14 @@ public Rectangle getTileBounds() { protected void paintComponent(Graphics g) { long started = System.currentTimeMillis(); - Graphics2D g2 = (Graphics2D) g.create(); - //Graphics2D g2 = (Graphics2D) g.create(tileX - GRID, tileY - GRID, DEFAULT_WIDTH, DEFAULT_HEIGHT); - drawTile(g2); - g2.dispose(); - - g.drawImage(tileImage, 0, 0, null); + super.paintComponent(g); + //Graphics2D g2 = (Graphics2D) g.create(); + //Graphics2D g2 = (Graphics2D) g.create(tileX - GRID, tileY - GRID, DEFAULT_WIDTH, DEFAULT_HEIGHT); + //drawTile(g2); + //getUI().drawTile(g2, this); + //g2.dispose(); + //g.drawImage(tileImage, 0, 0, null); long now = System.currentTimeMillis(); Logger.trace(id + " Duration: " + (now - started) + " ms. Cp: " + xyToString() + " O: " + model.getTileOrienation()); } diff --git a/src/main/java/jcs/ui/layout/tiles/Tile1.java b/src/main/java/jcs/ui/layout/tiles/Tile1.java deleted file mode 100644 index b01cb9be..00000000 --- a/src/main/java/jcs/ui/layout/tiles/Tile1.java +++ /dev/null @@ -1,221 +0,0 @@ -/* - * Copyright 2023 Frans Jacobs. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package jcs.ui.layout.tiles; - -import java.awt.Color; -import java.awt.Graphics2D; -import java.awt.Point; -import java.awt.Shape; -import java.awt.image.BufferedImage; -import java.beans.PropertyChangeListener; -import java.util.Map; -import java.util.Set; -import jcs.entities.AccessoryBean.AccessoryValue; -import jcs.entities.TileBean; -import jcs.entities.TileBean.Direction; -import jcs.entities.TileBean.Orientation; -import jcs.entities.TileBean.TileType; - -/** - * @author frans - */ -public interface Tile1 extends Shape { - - public static final int GRID = 20; - public static final int DEFAULT_WIDTH = GRID * 2; - public static final int DEFAULT_HEIGHT = GRID * 2; - - static final int RENDER_GRID = GRID * 10; - static final int RENDER_WIDTH = RENDER_GRID * 2; - static final int RENDER_HEIGHT = RENDER_GRID * 2; - - public static final Color DEFAULT_BACKGROUND_COLOR = Color.white; - public static final Color DEFAULT_TRACK_COLOR = Color.lightGray; - public static final Color DEFAULT_ROUTE_TRACK_COLOR = Color.blue; - - boolean isDrawRoute(); - - void setDrawRoute(boolean drawRoute); - - Color getTrackColor(); - - void setTrackColor(Color trackColor); - - Color getTrackRouteColor(); - - void setTrackRouteColor(Color trackRouteColor); - - Orientation getIncomingSide(); - - void setIncomingSide(Orientation incomingSide); - - Color getBackgroundColor(); - - void setBackgroundColor(Color backgroundColor); - - String getId(); - - void setId(String id); - - //String getImageKey(); - - BufferedImage getTileImage(); - - void drawTile(Graphics2D g2d, boolean drawOutline); - - void renderTile(Graphics2D g2d); - - void renderTileRoute(Graphics2D g2d); - - void drawName(Graphics2D g2); - - void drawCenterPoint(Graphics2D g2d); - - void drawCenterPoint(Graphics2D g2, Color color); - - void drawCenterPoint(Graphics2D g2d, Color color, double size); - - void drawBounds(Graphics2D g2d); - - void rotate(); - - void flipHorizontal(); - - void flipVertical(); - - void move(int newX, int newY); - - TileBean.Orientation getOrientation(); - - void setOrientation(TileBean.Orientation orientation); - - Direction getDirection(); - - void setDirection(Direction direction); - - Point getCenter(); - - void setCenter(Point center); - - /** - * @return a Set of alternative points in case the tile is not a square - */ - Set getAltPoints(); - - /** - * @return All points relevant for the Object on the Canvas - */ - Set getAllPoints(); - - int getOffsetX(); - - void setOffsetX(int offsetX); - - int getOffsetY(); - - void setOffsetY(int offsetY); - - int getHeight(); - - int getWidth(); - - /** - * @return the X (pixel) coordinate of the center of the tile - */ - int getCenterX(); - - /** - * @return then Y (pixel) coordinate of the center of the tile - */ - int getCenterY(); - - TileBean getTileBean(); - - boolean isDrawOutline(); - - void setDrawOutline(boolean drawOutline); - - TileType getTileType(); - - void setPropertyChangeListener(PropertyChangeListener listener); - - String xyToString(); - - /** - * @return the X number of the grid square (grid is 40 x 40 pix) - */ - int getGridX(); - - /** - * @return the Y number of the grid square (grid is 40 x 40 pix) - */ - int getGridY(); - - /** - * The main route of the tile is horizontal - * - * @return true when main route goes from East to West or vv - */ - boolean isHorizontal(); - - /** - * The main route of the tile is vertical - * - * @return true when main route goes from North to South or vv - */ - boolean isVertical(); - - /** - * The main route of the tile is diagonal - * - * @return true when main route goes from North to East or West to South and vv - */ - boolean isDiagonal(); - - boolean isJunction(); - - boolean isBlock(); - - boolean isDirectional(); - - boolean isCrossing(); - - Map getNeighborPoints(); - - Map getNeighborOrientations(); - - Map getEdgePoints(); - - Map getEdgeOrientations(); - - AccessoryValue accessoryValueForRoute(Orientation from, Orientation to); - - /** - * @param other a tile to check with this tile - * @return true when the other tile is adjacent to this and the "tracks" connect - */ - boolean isAdjacent(Tile1 other); - - String getIdSuffix(Tile1 other); - - /** - * When the tile has a specific direction a train may travel then this method will indicate whether the other tile is in on the side where the arrow is pointing to - * - * @param other A Tile - * @return true where other is on the side of this tile where the arrow points to - */ - boolean isArrowDirection(Tile1 other); -} diff --git a/src/main/java/jcs/ui/layout/tiles/TileModel.java b/src/main/java/jcs/ui/layout/tiles/TileModel.java index 4280d06e..31a4cb28 100644 --- a/src/main/java/jcs/ui/layout/tiles/TileModel.java +++ b/src/main/java/jcs/ui/layout/tiles/TileModel.java @@ -1,5 +1,5 @@ /* - * Copyright 2025 fransjacobs. + * Copyright 2025 Frans Jacobs. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -49,6 +49,10 @@ public interface TileModel extends Serializable { void setTileOrienation(TileBean.Orientation tileOrienation); + public TileBean.Orientation getIncomingSide(); + + void setIncomingSide(TileBean.Orientation incomingSide); + boolean isShowRoute(); public void setShowRoute(boolean showRoute); diff --git a/src/main/java/jcs/ui/layout/tiles/enums/Rotation.java b/src/main/java/jcs/ui/layout/tiles/enums/Rotation.java deleted file mode 100755 index a535050f..00000000 --- a/src/main/java/jcs/ui/layout/tiles/enums/Rotation.java +++ /dev/null @@ -1,50 +0,0 @@ -/* - * Copyright (C) 2019 Frans Jacobs. - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, - * MA 02110-1301 USA - */ -package jcs.ui.layout.tiles.enums; - -import java.util.Collections; -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; - -public enum Rotation { - R0("R0"), R90("R90"), R180("R180"), R270("R270"); - - private final String rotation; - private static final Map ENUM_MAP; - - Rotation(String rotation) { - this.rotation = rotation; - } - - static { - Map map = new ConcurrentHashMap<>(); - for (Rotation instance : Rotation.values()) { - map.put(instance.getRotation(), instance); - } - ENUM_MAP = Collections.unmodifiableMap(map); - } - - public String getRotation() { - return this.rotation; - } - - public static Rotation get(String rotation) { - return ENUM_MAP.get(rotation); - } -} diff --git a/src/main/java/jcs/ui/layout/tiles/ui/BlockUI.java b/src/main/java/jcs/ui/layout/tiles/ui/BlockUI.java new file mode 100644 index 00000000..41ac8b24 --- /dev/null +++ b/src/main/java/jcs/ui/layout/tiles/ui/BlockUI.java @@ -0,0 +1,506 @@ +/* + * Copyright 2025 Frans Jacobs. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package jcs.ui.layout.tiles.ui; + +import java.awt.BasicStroke; +import java.awt.Color; +import java.awt.Font; +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.Image; +import java.awt.Insets; +import java.awt.geom.Ellipse2D; +import java.awt.image.BufferedImage; +import javax.swing.JComponent; +import javax.swing.plaf.ComponentUI; +import jcs.entities.BlockBean; +import static jcs.entities.BlockBean.BlockState.GHOST; +import static jcs.entities.BlockBean.BlockState.INBOUND; +import static jcs.entities.BlockBean.BlockState.LOCKED; +import static jcs.entities.BlockBean.BlockState.OCCUPIED; +import static jcs.entities.BlockBean.BlockState.OUTBOUND; +import static jcs.entities.BlockBean.BlockState.OUT_OF_ORDER; +import jcs.entities.LocomotiveBean; +import jcs.entities.TileBean; +import static jcs.entities.TileBean.Orientation.EAST; +import static jcs.entities.TileBean.Orientation.NORTH; +import static jcs.entities.TileBean.Orientation.SOUTH; +import static jcs.entities.TileBean.Orientation.WEST; +import jcs.ui.layout.tiles.Block; +import static jcs.ui.layout.tiles.Block.BLOCK_HEIGHT; +import static jcs.ui.layout.tiles.Block.BLOCK_WIDTH; +import jcs.ui.layout.tiles.Tile; +import static jcs.ui.layout.tiles.Tile.DEFAULT_HEIGHT; +import static jcs.ui.layout.tiles.Tile.DEFAULT_WIDTH; +import static jcs.ui.layout.tiles.Tile.GRID; +import jcs.ui.layout.tiles.TileModel; +import jcs.ui.util.ImageUtil; +import org.tinylog.Logger; + +public class BlockUI extends TileUI { + + public BlockUI() { + } + + public static ComponentUI createUI(JComponent c) { + return new BlockUI(); + } + +// Color getBlockStateColor() { +// return getBlockStateColor(this.model.getBlockState()); +// } + protected Color getBlockStateColor(BlockBean.BlockState blockState) { + return switch (blockState) { + case GHOST -> + new Color(250, 0, 0); + case LOCKED -> + new Color(250, 250, 210); + case OCCUPIED -> + new Color(250, 210, 210); + case OUT_OF_ORDER -> + new Color(190, 190, 190); + case OUTBOUND -> + new Color(210, 250, 210); + case INBOUND -> + new Color(250, 210, 250); + default -> + new Color(255, 255, 255); + }; + } + + @Override + public void renderTile(Graphics2D g2, JComponent c) { + Tile tile = (Tile) c; + TileModel model = tile.getModel(); + + int xx = 20; + int yy = 50; + int rw = RENDER_WIDTH * 3 - 40; + int rh = 300; + + g2.setStroke(new BasicStroke(3, BasicStroke.CAP_SQUARE, BasicStroke.JOIN_ROUND)); + + g2.setPaint(Color.darkGray); + g2.drawRoundRect(xx, yy, rw, rh, 15, 15); + + Color blockStateColor = getBlockStateColor(model.getBlockState()); + //Logger.trace("Block " + this.id + " State: " + this.getBlockBean().getBlockState().getState() + " Color: " + blockStateColor.toString()); + g2.setPaint(blockStateColor); + g2.fillRoundRect(xx, yy, rw, rh, 15, 15); + + g2.setStroke(new BasicStroke(20, BasicStroke.CAP_SQUARE, BasicStroke.JOIN_ROUND)); + g2.setPaint(Color.darkGray); + g2.drawLine(rw + GRID, yy - 0, rw + GRID, yy + 300); + + //When there is a locomotive in the block mark the direction of travel. + //The default, forwards is in the direction of the block orientation, i.e. the + + if (model.getLocomotive() != null && model.getLocomotive().getName() != null) { + renderDirectionArrow(g2, c); + } + + drawName(g2, c); + } + + private void renderDirectionArrow(Graphics2D g2, JComponent c) { + Tile tile = (Tile) c; + TileModel model = tile.getModel(); + + //The default, forwards is in the direction of the block orientation, i.e. the + + TileBean.Orientation tileOrientation = model.getTileOrienation(); + BlockBean bb = tile.getBlockBean(); + boolean reverseArrival = model.isReverseArrival(); + + LocomotiveBean.Direction logicalDirection; + if (bb.getLogicalDirection() != null) { + logicalDirection = model.getLogicalDirection(); + } else { + logicalDirection = model.getLocomotive().getDirection(); + } + + String departureSuffix = model.getDepartureSuffix(); + if (departureSuffix == null) { + departureSuffix = Block.getDepartureSuffix(tileOrientation, reverseArrival, logicalDirection); + } + + //Logger.trace(this.getId()+" LogicalDirection is " + (bb.getLogicalDirection() != null ? "Set" : "Not Set") + " Dir: " + logicalDirection.getDirection() + " Orientation: " + orientation.getOrientation() + " departureSuffix: " + departureSuffix); + if ("+".equals(departureSuffix)) { + if (TileBean.Orientation.EAST == tileOrientation || TileBean.Orientation.SOUTH == tileOrientation) { + switch (logicalDirection) { + case LocomotiveBean.Direction.FORWARDS -> { + if (reverseArrival) { + renderLeftArrow(g2); + } else { + renderRightArrow(g2); + } + } + case LocomotiveBean.Direction.BACKWARDS -> { + if (reverseArrival) { + renderRightArrow(g2); + } else { + renderLeftArrow(g2); + } + } + } + } else { + switch (logicalDirection) { + case LocomotiveBean.Direction.BACKWARDS -> { + if (reverseArrival) { + renderLeftArrow(g2); + } else { + renderRightArrow(g2); + } + } + case LocomotiveBean.Direction.FORWARDS -> { + if (reverseArrival) { + renderRightArrow(g2); + } else { + renderLeftArrow(g2); + } + } + } + } + } else { + if (TileBean.Orientation.EAST == tileOrientation || TileBean.Orientation.SOUTH == tileOrientation) { + switch (logicalDirection) { + case LocomotiveBean.Direction.FORWARDS -> { + if (reverseArrival) { + renderLeftArrow(g2); + } else { + renderRightArrow(g2); + } + } + case LocomotiveBean.Direction.BACKWARDS -> { + if (reverseArrival) { + renderRightArrow(g2); + } else { + renderLeftArrow(g2); + } + } + } + } else { + switch (logicalDirection) { + case LocomotiveBean.Direction.BACKWARDS -> { + if (reverseArrival) { + renderLeftArrow(g2); + } else { + renderRightArrow(g2); + } + } + case LocomotiveBean.Direction.FORWARDS -> { + if (reverseArrival) { + renderRightArrow(g2); + } else { + renderLeftArrow(g2); + } + } + } + } + } + } + + private void renderLeftArrow(Graphics2D g2) { + //Logger.trace(this.getId()+" LogicalDirection is " + this.getBlockBean().getLogicalDirection() + " Orientation: " + this.getOrientation() + " departureSuffix: " + this.getBlockBean().getDepartureSuffix()); + g2.fillPolygon(new int[]{0, 50, 50,}, new int[]{200, 150, 250}, 3); + } + + private void renderRightArrow(Graphics2D g2) { + //Logger.trace(this.getId()+" LogicalDirection is " + this.getBlockBean().getLogicalDirection() + " Orientation: " + this.getOrientation() + " departureSuffix: " + this.getBlockBean().getDepartureSuffix()); + g2.fillPolygon(new int[]{1180, 1130, 1130,}, new int[]{200, 150, 250}, 3); + } + + @Override + public void renderTileRoute(Graphics2D g2d, JComponent c) { + Tile tile = (Tile) c; + TileModel model = tile.getModel(); + + if (model.isShowBlockState()) { + backgroundColor = getBlockStateColor(model.getBlockState()); + } + } + + protected void overlayLocImage(JComponent c) { + Tile tile = (Tile) c; + TileModel model = tile.getModel(); + + int ww = tileImage.getWidth(); + int hh = tileImage.getHeight(); + TileBean.Orientation tileOrientation = model.getTileOrienation(); + + BufferedImage overlay = new BufferedImage(ww, hh, BufferedImage.TYPE_INT_ARGB); + Graphics2D g2i = overlay.createGraphics(); + + Image locImage; + if (model.getLocomotive() != null && model.getLocomotive().getLocIcon() != null) { + locImage = model.getLocomotive().getLocIcon(); + } else { + locImage = null; + } + + if (locImage != null) { + String departureSuffix = model.getDepartureSuffix(); + boolean reverseImage = model.isReverseArrival(); + + Logger.trace("LocImage w: " + locImage.getWidth(null) + " h: " + locImage.getHeight(null)); + // scale it to max h of 45 + int size = 45; + float aspect = (float) locImage.getHeight(null) / (float) locImage.getWidth(null); + //TODO: Use Scalr? + locImage = locImage.getScaledInstance(size, (int) (size * aspect), Image.SCALE_SMOOTH); + + //Depending on the block orientation the image needs to be rotated and flipped + //Incase the departure suffix is NOT set center the locomotive image + int w, h, xx, yy; + switch (tileOrientation) { + case WEST -> { + w = locImage.getWidth(null); + h = locImage.getHeight(null); + + if (null == departureSuffix) { + xx = BLOCK_WIDTH / 2 - tile.getWidth() / 2 + w; + } else { + switch (departureSuffix) { + case "+" -> { + xx = BLOCK_WIDTH / 2 - tile.getWidth() / 2 + w - 25; + } + default -> { + xx = BLOCK_WIDTH / 2 - tile.getWidth() / 2 + w + 10; + } + } + } + yy = DEFAULT_HEIGHT / 2 - h / 2; + + if (reverseImage) { + locImage = ImageUtil.flipVertically(locImage); + } + } + case SOUTH -> { + locImage = ImageUtil.flipHorizontally(locImage); + locImage = ImageUtil.rotate(locImage, 90); + + w = locImage.getWidth(null); + h = locImage.getHeight(null); + xx = DEFAULT_WIDTH / 2 - w / 2; + + if (null == departureSuffix) { + yy = BLOCK_HEIGHT / 2 - tile.getHeight() / 2 + h; + } else { + switch (departureSuffix) { + case "-" -> { + yy = BLOCK_HEIGHT / 2 - tile.getHeight() / 2 + h - 25; + } + default -> { + yy = BLOCK_HEIGHT / 2 - tile.getHeight() / 2 + h + 10; + } + } + } + if (reverseImage) { + locImage = ImageUtil.flipHorizontally(locImage); + } + } + case NORTH -> { + locImage = ImageUtil.flipHorizontally(locImage); + locImage = ImageUtil.rotate(locImage, 90); + + w = locImage.getWidth(null); + h = locImage.getHeight(null); + xx = DEFAULT_WIDTH / 2 - w / 2; + + if (null == departureSuffix) { + int minY = BLOCK_HEIGHT / 2 - tile.getHeight() / 2 + h; + yy = minY; + } else { + switch (departureSuffix) { + case "+" -> { + yy = BLOCK_HEIGHT / 2 - tile.getHeight() / 2 + h - 25; + } + default -> { + yy = BLOCK_HEIGHT / 2 - tile.getHeight() / 2 + h + 10; + } + } + } + if (reverseImage) { + locImage = ImageUtil.flipHorizontally(locImage); + } + } + default -> { + w = locImage.getWidth(null); + h = locImage.getHeight(null); + if (null == departureSuffix) { + xx = BLOCK_WIDTH / 2 - tile.getWidth() / 2 + w; + } else { + switch (departureSuffix) { + case "-" -> { + xx = BLOCK_WIDTH / 2 - tile.getWidth() / 2 + w - 25; + } + default -> { + xx = BLOCK_WIDTH / 2 - tile.getWidth() / 2 + w + 10; + } + } + } + yy = DEFAULT_HEIGHT / 2 - h / 2; + + if (reverseImage) { + locImage = ImageUtil.flipVertically(locImage); + } + } + } + + g2i.drawImage(tileImage, 0, 0, null); + g2i.drawImage(locImage, xx, yy, null); + g2i.dispose(); + tileImage = overlay; + } + } + +// private Image getLocImage() { +// if (model.getLocomotive() != null && model.getLocomotive().getLocIcon() != null) { +// return model.getLocomotive().getLocIcon(); +// } else { +// return null; +// } +// } + public String getBlockText(Tile tile) { + BlockBean blockBean = tile.getBlockBean(); + String blockText; + if (blockBean != null && blockBean.getDescription() != null) { + if (blockBean.getLocomotive() != null && blockBean.getLocomotive().getName() != null && BlockBean.BlockState.GHOST != blockBean.getBlockState()) { + blockText = blockBean.getLocomotive().getName(); + } else { + if (blockBean.getDescription().length() > 0) { + blockText = blockBean.getDescription(); + } else { + blockText = tile.getId(); + } + } + } else { + // Design mode show description when available + if (blockBean != null && blockBean.getDescription() != null && blockBean.getDescription().length() > 0) { + blockText = blockBean.getDescription(); + } else { + blockText = tile.getId(); + } + } + return blockText; + } + + @Override + public void drawName(Graphics2D g2d, JComponent c) { + Tile tile = (Tile) c; + TileModel model = tile.getModel(); + + if (!model.isOverlayImage()) { + g2d.setPaint(Color.black); + + Font currentFont = g2d.getFont(); + Font newFont = currentFont.deriveFont(currentFont.getSize() * 10.0F); + g2d.setFont(newFont); + + String blockText = getBlockText(tile); + + // Scale the text if necessary + int textWidth = g2d.getFontMetrics().stringWidth(blockText); + double fontscale = 10.0; + if (textWidth > 845) { + fontscale = fontscale * 847.0 / textWidth; + newFont = currentFont.deriveFont(currentFont.getSize() * (float) fontscale); + g2d.setFont(newFont); + textWidth = g2d.getFontMetrics().stringWidth(blockText); + } + + int textHeight = g2d.getFontMetrics().getHeight(); + TileBean.Orientation tileOrientation = model.getTileOrienation(); + + switch (tileOrientation) { + case EAST -> { + drawRotate(g2d, ((RENDER_WIDTH * 3) / 2) - textWidth / 2, RENDER_GRID + textHeight / 3, 0, blockText); + } + case WEST -> { + drawRotate(g2d, ((RENDER_WIDTH * 3) / 2) + textWidth / 2, RENDER_GRID - textHeight / 3, 180, blockText); + } + case NORTH -> { + drawRotate(g2d, ((RENDER_WIDTH * 3) / 2) - textWidth / 2, RENDER_GRID + textHeight / 3, 0, blockText); + } + case SOUTH -> { + drawRotate(g2d, ((RENDER_WIDTH * 3) / 2) + textWidth / 2, RENDER_GRID - textHeight / 3, 180, blockText); + } + } + // reset to the original font + newFont = currentFont.deriveFont(currentFont.getSize() * 1.0F); + g2d.setFont(newFont); + } + } + + @Override + protected void drawCenterPoint(Graphics2D g2d, Color color, double size, JComponent c) { + Tile tile = (Tile) c; + TileModel model = tile.getModel(); + //A block has 2 alternate points + //1st square + //2nd square holds the centerpoint + //3rd square + TileBean.Orientation tileOrientation = model.getTileOrienation(); + double dX1, dX2, dX3, dY1, dY2, dY3; + if (TileBean.Orientation.EAST == tileOrientation || TileBean.Orientation.WEST == tileOrientation) { + dX1 = renderWidth / 3 / 2 - size / 2 / 2; + dY1 = renderHeight / 2 - size / 2 / 2; + dX2 = renderWidth / 2 - size / 2; + dY2 = renderHeight / 2 - size / 2; + dX3 = renderWidth - renderWidth / 3 / 2 - size / 2 / 2; + dY3 = renderHeight / 2 - size / 2 / 2; + } else { + dX1 = renderWidth / 2 - size / 2 / 2; + dY1 = renderHeight / 3 / 2 - size / 2 / 2; + dX2 = renderHeight / 2 - size / 2; + dY2 = renderWidth / 2 - size / 2; + dY3 = renderWidth / 2 - size / 2 / 2; + dX3 = renderHeight - renderHeight / 3 / 2 - size / 2 / 2; + } + + g2d.setColor(color); + g2d.fill(new Ellipse2D.Double(dX1, dY1, size / 2, size / 2)); + g2d.fill(new Ellipse2D.Double(dX2, dY2, size, size)); + g2d.fill(new Ellipse2D.Double(dX3, dY3, size / 2, size / 2)); + } + + @Override + public void paint(Graphics g, JComponent c) { + Tile tile = (Tile) c; + TileModel model = tile.getModel(); + + long started = System.currentTimeMillis(); + // We don't want to paint inside the insets or borders. + Insets insets = c.getInsets(); + g.translate(insets.left, insets.top); + + Graphics2D g2 = (Graphics2D) g.create(); + drawTile(g2, c); + if (model.isOverlayImage()) { + overlayLocImage(c); + } + + g2.dispose(); + + g.drawImage(tileImage, 0, 0, null); + + g.translate(-insets.left, -insets.top); + + if (Logger.isTraceEnabled()) { + long now = System.currentTimeMillis(); + Logger.trace(tile.getId() + " Duration: " + (now - started) + " ms. Cp: " + tile.xyToString() + " O: " + model.getTileOrienation()); + } + } + +} diff --git a/src/main/java/jcs/ui/layout/tiles/ui/CrossUI.java b/src/main/java/jcs/ui/layout/tiles/ui/CrossUI.java new file mode 100644 index 00000000..a592b60d --- /dev/null +++ b/src/main/java/jcs/ui/layout/tiles/ui/CrossUI.java @@ -0,0 +1,362 @@ +/* + * Copyright 2025 Frans Jacobs. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package jcs.ui.layout.tiles.ui; + +import java.awt.BasicStroke; +import java.awt.Color; +import java.awt.Graphics2D; +import java.awt.geom.Ellipse2D; +import javax.swing.JComponent; +import javax.swing.plaf.ComponentUI; +import jcs.entities.AccessoryBean; +import static jcs.entities.AccessoryBean.AccessoryValue.GREEN; +import static jcs.entities.AccessoryBean.AccessoryValue.RED; +import jcs.entities.TileBean; +import static jcs.entities.TileBean.Orientation.NORTH; +import static jcs.entities.TileBean.Orientation.SOUTH; +import static jcs.entities.TileBean.Orientation.WEST; +import jcs.ui.layout.tiles.Cross; +import jcs.ui.layout.tiles.Tile; +import jcs.ui.layout.tiles.TileModel; + +public class CrossUI extends TileUI { + + public CrossUI() { + super(); + //Default is east +// this.renderWidth = RENDER_GRID * 4; +// this.renderHeight = RENDER_GRID * 2; + } + + public static ComponentUI createUI(JComponent c) { + return new CrossUI(); + } + +// public void changeRenderSize(Tile tile) { +// //Reset offsets +// //this.offsetY = 0; +// //this.renderOffsetY = 0; +// //this.offsetX = 0; +// //this.renderOffsetX = 0; +// +// if (tile.isHorizontal()) { +// this.renderWidth = RENDER_GRID * 4; +// this.renderHeight = RENDER_GRID * 2; +// +// //this.offsetY = 0; +// //this.renderOffsetY = 0; +// } else { +// this.renderWidth = RENDER_GRID * 2; +// this.renderHeight = RENDER_GRID * 4; +// +// //this.offsetX = 0; +// //this.renderOffsetX = 0; +// } +// +// //Due to the asymetical shape (center is on the left) +// //the offset has to be changed with the rotation +//// } +// } + + protected void renderStraight(Graphics2D g2, Color color) { + int xx = 0; + int yy = 170; + int w = RENDER_WIDTH; + int h = 60; + + g2.setStroke(new BasicStroke(4, BasicStroke.JOIN_MITER, BasicStroke.JOIN_ROUND)); + g2.setPaint(color); + g2.fillRect(xx, yy, w, h); + } + + protected void renderRouteStraight(Graphics2D g2, Color color) { + int xx = 0; + int yy = 190; + int w = RENDER_WIDTH; + int h = 20; + + g2.setStroke(new BasicStroke(4, BasicStroke.JOIN_MITER, BasicStroke.JOIN_ROUND)); + g2.setPaint(color); + g2.fillRect(xx, yy, w, h); + } + + protected void renderStraight2(Graphics2D g2, Color color) { + int xx = RENDER_WIDTH; + int yy = 170; + int w = RENDER_WIDTH; + int h = 60; + + g2.setStroke(new BasicStroke(4, BasicStroke.JOIN_MITER, BasicStroke.JOIN_ROUND)); + g2.setPaint(color); + g2.fillRect(xx, yy, w, h); + } + + protected void renderRouteStraight2(Graphics2D g2, Color color) { + int xx = RENDER_WIDTH; + int yy = 190; + int w = RENDER_WIDTH; + int h = 20; + + g2.setStroke(new BasicStroke(4, BasicStroke.JOIN_MITER, BasicStroke.JOIN_ROUND)); + g2.setPaint(color); + g2.fillRect(xx, yy, w, h); + } + + protected void renderDiagonal(Graphics2D g2, Color color, JComponent c) { + Tile tile = (Tile) c; + TileBean.Direction direction = tile.getDirection(); + + int[] xPoints, yPoints; + if (TileBean.Direction.RIGHT.equals(direction)) { + xPoints = new int[]{400, 400, 167, 230}; + yPoints = new int[]{170, 230, 0, 0}; + } else { + xPoints = new int[]{400, 400, 170, 230}; + yPoints = new int[]{230, 170, 400, 400}; + } + + g2.setStroke(new BasicStroke(4, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND)); + g2.setPaint(color); + g2.fillPolygon(xPoints, yPoints, xPoints.length); + } + + protected void renderRouteDiagonal(Graphics2D g2, Color color, JComponent c) { + Tile tile = (Tile) c; + TileBean.Direction direction = tile.getDirection(); + + int[] xPoints, yPoints; + if (TileBean.Direction.RIGHT.equals(direction)) { + xPoints = new int[]{420, 400, 190, 210}; + yPoints = new int[]{210, 210, 0, 0}; + } else { + xPoints = new int[]{400, 400, 190, 210}; + yPoints = new int[]{210, 190, 400, 400}; + } + + g2.setStroke(new BasicStroke(4, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND)); + g2.setPaint(color); + g2.fillPolygon(xPoints, yPoints, xPoints.length); + } + + protected void renderDiagonal2(Graphics2D g2, Color color, JComponent c) { + Tile tile = (Tile) c; + TileBean.Direction direction = tile.getDirection(); + + int[] xPoints, yPoints; + if (TileBean.Direction.RIGHT.equals(direction)) { + xPoints = new int[]{400, 400, 570, 630}; + yPoints = new int[]{170, 230, 400, 400}; + } else { + xPoints = new int[]{400, 400, 570, 630}; + yPoints = new int[]{230, 170, 0, 0}; + } + + g2.setStroke(new BasicStroke(4, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND)); + g2.setPaint(color); + g2.fillPolygon(xPoints, yPoints, xPoints.length); + } + + protected void renderRouteDiagonal2(Graphics2D g2, Color color, JComponent c) { + Tile tile = (Tile) c; + TileBean.Direction direction = tile.getDirection(); + + int[] xPoints, yPoints; + if (TileBean.Direction.RIGHT.equals(direction)) { + xPoints = new int[]{400, 380, 590, 610}; + yPoints = new int[]{190, 190, 400, 400}; + } else { + xPoints = new int[]{400, 380, 590, 610}; + yPoints = new int[]{210, 210, 0, 0}; + } + + g2.setStroke(new BasicStroke(4, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND)); + g2.setPaint(color); + g2.setPaint(Color.cyan); + g2.fillPolygon(xPoints, yPoints, xPoints.length); + } + + @Override + public void renderTile(Graphics2D g2, JComponent c) { + Tile tile = (Tile) c; + AccessoryBean.AccessoryValue accessoryValue = tile.getAccessoryValue(); + //Color trackColor = tile.getTrackColor(); + + if (accessoryValue == null) { + accessoryValue = AccessoryBean.AccessoryValue.OFF; + } + + switch (accessoryValue) { + case RED -> { + renderStraight2(g2, Cross.LIGHT_RED); + renderDiagonal(g2, Cross.LIGHT_RED, c); + renderStraight(g2, Cross.DARK_RED); + renderDiagonal2(g2, Cross.DARK_RED, c); + } + case GREEN -> { + renderDiagonal(g2, Cross.VERY_LIGHT_GREEN, c); + renderDiagonal2(g2, Cross.VERY_LIGHT_GREEN, c); + renderStraight(g2, Cross.DARK_GREEN); + renderStraight2(g2, Cross.DARK_GREEN); + } + default -> { + renderStraight(g2, trackColor); + renderStraight2(g2, trackColor); + renderDiagonal(g2, trackColor, c); + renderDiagonal2(g2, trackColor, c); + } + } + } + + @Override + public void renderTileRoute(Graphics2D g2, JComponent c) { + Tile tile = (Tile) c; + TileModel model = tile.getModel(); + TileBean.Direction direction = tile.getDirection(); + TileBean.Orientation orientation = tile.getOrientation(); + + if (model.getIncomingSide() == null) { + model.setIncomingSide(model.getTileOrienation()); + } + TileBean.Orientation incomingSide = model.getIncomingSide(); + + AccessoryBean.AccessoryValue routeValue = tile.getRouteValue(); + if (routeValue == null) { + routeValue = AccessoryBean.AccessoryValue.OFF; + } + + //Color trackColor = tile.getTrackColor(); + //Color trackRouteColor = tile.getTrackRouteColor(); + if (tile.isHorizontal()) { + if (AccessoryBean.AccessoryValue.GREEN == routeValue && (TileBean.Orientation.NORTH == incomingSide || TileBean.Orientation.SOUTH == incomingSide)) { + renderRouteDiagonal(g2, trackRouteColor, c); + renderRouteDiagonal2(g2, trackRouteColor, c); + } else if (AccessoryBean.AccessoryValue.GREEN == routeValue && (TileBean.Orientation.EAST == incomingSide || TileBean.Orientation.WEST == incomingSide)) { + renderRouteStraight(g2, trackRouteColor); + renderRouteStraight2(g2, trackRouteColor); + } else if (AccessoryBean.AccessoryValue.RED == routeValue && TileBean.Orientation.EAST == orientation) { + if (TileBean.Direction.RIGHT == direction && (TileBean.Orientation.EAST == incomingSide || TileBean.Orientation.NORTH == incomingSide)) { + renderRouteStraight2(g2, trackRouteColor); + renderRouteDiagonal(g2, trackRouteColor, c); + } else if (TileBean.Direction.RIGHT == direction && (TileBean.Orientation.WEST == incomingSide || TileBean.Orientation.SOUTH == incomingSide)) { + renderRouteDiagonal2(g2, trackRouteColor, c); + renderRouteStraight(g2, trackRouteColor); + } else if (TileBean.Direction.LEFT == direction && (TileBean.Orientation.EAST == incomingSide || TileBean.Orientation.SOUTH == incomingSide)) { + renderRouteStraight2(g2, trackRouteColor); + renderRouteDiagonal(g2, trackRouteColor, c); + } else if (TileBean.Direction.LEFT == direction && (TileBean.Orientation.WEST == incomingSide || TileBean.Orientation.NORTH == incomingSide)) { + renderRouteStraight(g2, trackColor); + renderRouteDiagonal2(g2, trackColor, c); + } + } else if (AccessoryBean.AccessoryValue.RED == routeValue && TileBean.Orientation.WEST == orientation) { + if (TileBean.Direction.RIGHT == direction && (TileBean.Orientation.EAST == incomingSide || TileBean.Orientation.NORTH == incomingSide)) { + renderRouteStraight(g2, trackRouteColor); + renderRouteDiagonal2(g2, trackRouteColor, c); + } else if (TileBean.Direction.RIGHT == direction && (TileBean.Orientation.WEST == incomingSide || TileBean.Orientation.SOUTH == incomingSide)) { + renderRouteDiagonal(g2, trackRouteColor, c); + renderRouteStraight2(g2, trackRouteColor); + } else if (TileBean.Direction.LEFT == direction && (TileBean.Orientation.EAST == incomingSide || TileBean.Orientation.SOUTH == incomingSide)) { + renderRouteStraight(g2, trackRouteColor); + renderRouteDiagonal2(g2, trackRouteColor, c); + } else if (TileBean.Direction.LEFT == direction && (TileBean.Orientation.WEST == incomingSide || TileBean.Orientation.NORTH == incomingSide)) { + renderRouteStraight2(g2, trackColor); + renderRouteDiagonal(g2, trackColor, c); + } + } + } else { + if (AccessoryBean.AccessoryValue.GREEN == routeValue && (TileBean.Orientation.NORTH == incomingSide || TileBean.Orientation.SOUTH == incomingSide)) { + renderRouteStraight(g2, trackRouteColor); + renderRouteStraight2(g2, trackRouteColor); + } else if (AccessoryBean.AccessoryValue.GREEN == routeValue && (TileBean.Orientation.EAST == incomingSide || TileBean.Orientation.WEST == incomingSide)) { + renderRouteDiagonal(g2, trackRouteColor, c); + renderRouteDiagonal2(g2, trackRouteColor, c); + } else if (AccessoryBean.AccessoryValue.RED == routeValue && TileBean.Orientation.SOUTH == orientation) { + if (TileBean.Direction.RIGHT == direction && (TileBean.Orientation.EAST == incomingSide || TileBean.Orientation.SOUTH == incomingSide)) { + renderRouteStraight2(g2, trackRouteColor); + renderRouteDiagonal(g2, trackRouteColor, c); + } else if (TileBean.Direction.RIGHT == direction && (TileBean.Orientation.WEST == incomingSide || TileBean.Orientation.NORTH == incomingSide)) { + renderRouteDiagonal2(g2, trackRouteColor, c); + renderRouteStraight(g2, trackRouteColor); + } else if (TileBean.Direction.LEFT == direction && (TileBean.Orientation.EAST == incomingSide || TileBean.Orientation.NORTH == incomingSide)) { + renderRouteStraight(g2, trackRouteColor); + renderRouteDiagonal2(g2, trackRouteColor, c); + } else if (TileBean.Direction.LEFT == direction && (TileBean.Orientation.WEST == incomingSide || TileBean.Orientation.SOUTH == incomingSide)) { + renderRouteStraight2(g2, trackColor); + renderRouteDiagonal(g2, trackColor, c); + } + } else if (AccessoryBean.AccessoryValue.RED == routeValue && TileBean.Orientation.NORTH == orientation) { + if (TileBean.Direction.RIGHT == direction && (TileBean.Orientation.EAST == incomingSide || TileBean.Orientation.SOUTH == incomingSide)) { + renderRouteStraight(g2, trackRouteColor); + renderRouteDiagonal2(g2, trackRouteColor, c); + } else if (TileBean.Direction.RIGHT == direction && (TileBean.Orientation.WEST == incomingSide || TileBean.Orientation.NORTH == incomingSide)) { + renderRouteDiagonal(g2, trackRouteColor, c); + renderRouteStraight2(g2, trackRouteColor); + } else if (TileBean.Direction.LEFT == direction && (TileBean.Orientation.EAST == incomingSide || TileBean.Orientation.NORTH == incomingSide)) { + renderRouteStraight2(g2, trackRouteColor); + renderRouteDiagonal(g2, trackRouteColor, c); + } else if (TileBean.Direction.LEFT == direction && (TileBean.Orientation.WEST == incomingSide || TileBean.Orientation.SOUTH == incomingSide)) { + renderRouteStraight(g2, trackColor); + renderRouteDiagonal2(g2, trackColor, c); + } + } + } + } + + @Override + protected void drawCenterPoint(Graphics2D g2d, Color color, double size, JComponent c) { + Tile tile = (Tile) c; + TileModel model = tile.getModel(); + TileBean.Orientation tileOrientation = model.getTileOrienation(); + //int renderWidth = tile.getRenderWidth(); + //int renderHeight = tile.getRenderHeight(); + + //A Cross has 1 alternate point + //1st square holds the centerpoint + //2nd square + double dX1, dX2, dY1, dY2; + switch (tileOrientation) { + case SOUTH -> { + dX1 = renderWidth / 2 - size / 2; + dY1 = renderHeight / 2 - renderHeight / 4 - size / 2; + dX2 = renderWidth / 2 + renderWidth - size / 4; + dY2 = renderHeight / 2 - renderHeight / 4 - size / 4; + } + case WEST -> { + dX1 = renderWidth / 2 - renderWidth / 4 - size / 2; + dY1 = renderHeight / 2 - size / 2; + dX2 = renderWidth / 2 + renderWidth / 4 - size / 4; + dY2 = renderHeight / 2 - size / 4; + } + case NORTH -> { + dX1 = renderWidth / 2 - size / 2; + dY1 = renderHeight / 2 - renderHeight / 4 - size / 2; + dX2 = renderWidth / 2 + renderWidth - size / 4; + dY2 = renderHeight / 2 - renderHeight / 4 - size / 4; + } + default -> { + //East + dX1 = renderWidth / 2 - renderWidth / 4 - size / 2; + dY1 = renderHeight / 2 - size / 2; + dX2 = renderWidth / 2 + renderWidth / 4 - size / 4; + dY2 = renderHeight / 2 - size / 4; + } + } + + g2d.setColor(color); + g2d.fill(new Ellipse2D.Double(dX1, dY1, size, size)); + g2d.fill(new Ellipse2D.Double(dX2, dY2, size / 2, size / 2)); + } + +} diff --git a/src/main/java/jcs/ui/layout/tiles/ui/CrossingUI.java b/src/main/java/jcs/ui/layout/tiles/ui/CrossingUI.java new file mode 100644 index 00000000..b7fe6b5b --- /dev/null +++ b/src/main/java/jcs/ui/layout/tiles/ui/CrossingUI.java @@ -0,0 +1,94 @@ +/* + * Copyright 2025 Frans Jacobs. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package jcs.ui.layout.tiles.ui; + +import java.awt.BasicStroke; +import java.awt.Color; +import java.awt.Graphics2D; +import javax.swing.JComponent; +import javax.swing.plaf.ComponentUI; +import jcs.ui.layout.tiles.Tile; + +public class CrossingUI extends StraightUI { + + public CrossingUI() { + } + + public static ComponentUI createUI(JComponent c) { + return new CrossingUI(); + } + + protected void renderVerticalAndDividers(Graphics2D g2, JComponent c) { + Tile tile = (Tile) c; + //Color trackColor = tile.getTrackColor(); + + int xxn = 175; + int yyn = 0; + int xxs = 175; + int yys = 325; + int w = 50; + int h = 75; + + g2.setStroke(new BasicStroke(4, BasicStroke.JOIN_MITER, BasicStroke.JOIN_ROUND)); + g2.setPaint(trackColor); + + //North + g2.fillRect(xxn, yyn, w, h); + //South + g2.fillRect(xxs, yys, w, h); + + //Dividers + int[] xNorthPoly = new int[]{85, 115, 285, 315}; + int[] yNorthPoly = new int[]{85, 125, 125, 85}; + + int[] xSouthPoly = new int[]{85, 115, 285, 315}; + int[] ySouthPoly = new int[]{315, 275, 275, 315}; + + g2.setPaint(Color.darkGray); + g2.setStroke(new BasicStroke(8, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND)); + + g2.drawPolyline(xNorthPoly, yNorthPoly, xNorthPoly.length); + g2.drawPolyline(xSouthPoly, ySouthPoly, xSouthPoly.length); + } + + protected void renderRouteVertical(Graphics2D g2, JComponent c) { + Tile tile = (Tile) c; + //Color trackRouteColor = tile.getTrackRouteColor(); + + int xxn, yyn, xxs, yys, w, h; + xxn = 190; + yyn = 0; + xxs = 190; + yys = 325; + w = 20; + h = 75; + + g2.setStroke(new BasicStroke(4, BasicStroke.JOIN_MITER, BasicStroke.JOIN_ROUND)); + g2.setPaint(trackRouteColor); + + //North + g2.fillRect(xxn, yyn, w, h); + //South + g2.fillRect(xxs, yys, w, h); + } + + @Override + public void renderTile(Graphics2D g2, JComponent c) { + renderStraight(g2, c); + renderVerticalAndDividers(g2, c); + } + +} diff --git a/src/main/java/jcs/ui/layout/tiles/ui/CurvedUI.java b/src/main/java/jcs/ui/layout/tiles/ui/CurvedUI.java new file mode 100644 index 00000000..e9dad0c4 --- /dev/null +++ b/src/main/java/jcs/ui/layout/tiles/ui/CurvedUI.java @@ -0,0 +1,62 @@ +/* + * Copyright 2025 Frans Jacobs. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package jcs.ui.layout.tiles.ui; + +import java.awt.BasicStroke; +import java.awt.Color; +import java.awt.Graphics2D; +import javax.swing.JComponent; +import javax.swing.plaf.ComponentUI; +import jcs.ui.layout.tiles.Tile; + +public class CurvedUI extends TileUI { + + public CurvedUI() { + } + + public static ComponentUI createUI(JComponent c) { + return new CurvedUI(); + } + + @Override + public void renderTile(Graphics2D g2, JComponent c) { + Tile tile = (Tile) c; + //Color trackColor = tile.getTrackColor(); + + int[] xPoints = new int[]{400, 400, 170, 230}; + int[] yPoints = new int[]{230, 170, 400, 400}; + + g2.setStroke(new BasicStroke(1, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND)); + g2.setPaint(trackColor); + + g2.fillPolygon(xPoints, yPoints, xPoints.length); + } + + @Override + public void renderTileRoute(Graphics2D g2, JComponent c) { + Tile tile = (Tile) c; + //Color trackRouteColor = tile.getTrackRouteColor(); + + int[] xPoints = new int[]{400, 400, 190, 210}; + int[] yPoints = new int[]{210, 190, 400, 400}; + + g2.setStroke(new BasicStroke(1, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND)); + g2.setPaint(trackRouteColor); + + g2.fillPolygon(xPoints, yPoints, xPoints.length); + } + +} diff --git a/src/main/java/jcs/ui/layout/tiles/ui/EndUI.java b/src/main/java/jcs/ui/layout/tiles/ui/EndUI.java new file mode 100644 index 00000000..e49ec7ae --- /dev/null +++ b/src/main/java/jcs/ui/layout/tiles/ui/EndUI.java @@ -0,0 +1,66 @@ +/* + * Copyright 2025 Frans Jacobs. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package jcs.ui.layout.tiles.ui; + +import java.awt.BasicStroke; +import java.awt.Color; +import java.awt.Graphics2D; +import javax.swing.JComponent; +import javax.swing.plaf.ComponentUI; +import jcs.ui.layout.tiles.Tile; + +public class EndUI extends TileUI { + + public EndUI() { + } + + public static ComponentUI createUI(JComponent c) { + return new EndUI(); + } + + protected void renderEnd(Graphics2D g2, JComponent c) { + Tile tile = (Tile) c; + //Color trackColor = tile.getTrackColor(); + + int xx = 0; + int yy = 175; + int w = RENDER_GRID; + int h = 50; + + g2.setStroke(new BasicStroke(40, BasicStroke.JOIN_MITER, BasicStroke.JOIN_ROUND)); + g2.setPaint(trackColor); + g2.fillRect(xx, yy, w, h); + + xx = RENDER_GRID; + yy = 100; + + w = 30; + h = 200; + + g2.setPaint(Color.DARK_GRAY); + g2.fillRect(xx, yy, w, h); + } + + @Override + public void renderTile(Graphics2D g2, JComponent c) { + renderEnd(g2, c); + } + + @Override + public void renderTileRoute(Graphics2D g2d, JComponent c) { + } + +} diff --git a/src/main/java/jcs/ui/layout/tiles/ui/SensorUI.java b/src/main/java/jcs/ui/layout/tiles/ui/SensorUI.java new file mode 100644 index 00000000..0e2ce14e --- /dev/null +++ b/src/main/java/jcs/ui/layout/tiles/ui/SensorUI.java @@ -0,0 +1,69 @@ +/* + * Copyright 2025 Frans Jacobs. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package jcs.ui.layout.tiles.ui; + +import java.awt.Color; +import java.awt.Graphics2D; +import java.awt.MultipleGradientPaint; +import java.awt.Point; +import java.awt.RadialGradientPaint; +import java.awt.geom.Ellipse2D; +import javax.swing.JComponent; +import javax.swing.plaf.ComponentUI; +import jcs.ui.layout.tiles.Tile; +import jcs.ui.layout.tiles.TileModel; + +public class SensorUI extends StraightUI { + + public SensorUI() { + } + + public static ComponentUI createUI(JComponent c) { + return new SensorUI(); + } + + private void renderSensor(Graphics2D g2, JComponent c) { + Tile tile = (Tile) c; + TileModel model = tile.getModel(); + + int xx = RENDER_GRID - 75; + int yy = RENDER_GRID - 75; + + Point cp = new Point(xx, yy); + float radius = 300; + float[] dist = {0.0f, 0.6f}; + + if (model.isSensorActive()) { + Color[] colors = {Color.red.brighter(), Color.red.darker()}; + RadialGradientPaint foreground = new RadialGradientPaint(cp, radius, dist, colors, MultipleGradientPaint.CycleMethod.REFLECT); + g2.setPaint(foreground); + } else { + Color[] colors = {Color.green.darker(), Color.green.brighter()}; + RadialGradientPaint foreground = new RadialGradientPaint(cp, radius, dist, colors, MultipleGradientPaint.CycleMethod.REFLECT); + g2.setPaint(foreground); + } + + g2.fill(new Ellipse2D.Double(xx, yy, 0.5f * radius, 0.5f * radius)); + } + + + @Override + public void renderTile(Graphics2D g2, JComponent c) { + renderStraight(g2, c); + renderSensor(g2, c); + } + +} diff --git a/src/main/java/jcs/ui/layout/tiles/ui/SignalUI.java b/src/main/java/jcs/ui/layout/tiles/ui/SignalUI.java new file mode 100644 index 00000000..f53462b1 --- /dev/null +++ b/src/main/java/jcs/ui/layout/tiles/ui/SignalUI.java @@ -0,0 +1,325 @@ +/* + * Copyright 2025 Frans Jacobs. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package jcs.ui.layout.tiles.ui; + +import java.awt.BasicStroke; +import java.awt.Color; +import java.awt.Graphics2D; +import java.awt.Polygon; +import javax.swing.JComponent; +import javax.swing.plaf.ComponentUI; +import jcs.entities.AccessoryBean; +import jcs.entities.AccessoryBean.SignalType; +import static jcs.entities.AccessoryBean.SignalType.HP012; +import static jcs.entities.AccessoryBean.SignalType.HP012SH1; +import static jcs.entities.AccessoryBean.SignalType.HP0SH1; +import jcs.entities.AccessoryBean.SignalValue; +import static jcs.entities.AccessoryBean.SignalValue.Hp0; +import static jcs.entities.AccessoryBean.SignalValue.Hp0Sh1; +import static jcs.entities.AccessoryBean.SignalValue.Hp1; +import static jcs.entities.AccessoryBean.SignalValue.Hp2; +import jcs.ui.layout.tiles.Tile; + +public class SignalUI extends StraightUI { + + public SignalUI() { + } + + public static ComponentUI createUI(JComponent c) { + return new SignalUI(); + } + + /** + * Render a Signal with 2 lights + * + * @param g2d the graphics context + * @param c + */ + protected void renderSignal2(Graphics2D g2d, JComponent c) { + Tile tile = (Tile) c; + SignalValue signalValue = tile.getSignalValue(); + + int rx = RENDER_GRID; + int ry = RENDER_GRID + 60; + int rw = 180; + int rh = 100; + int l1x = RENDER_GRID + 20; + int l1y = RENDER_GRID + 80; + int l2x = RENDER_GRID + 100; + int l2y = RENDER_GRID + 80; + + Color color1 = Color.gray; + Color color2 = Color.gray; + + if (signalValue == null) { + signalValue = AccessoryBean.SignalValue.OFF; + } + + switch (signalValue) { + case Hp0 -> { + color1 = Color.red; + color2 = Color.gray; + } + case Hp1 -> { + color1 = Color.gray; + color2 = Color.green; + } + default -> { + } + } + + g2d.setStroke(new BasicStroke(10f)); + g2d.setPaint(Color.darkGray); + g2d.fillRoundRect(rx, ry, rw, rh, 30, 30); + + g2d.setPaint(color1); + g2d.fillOval(l1x, l1y, 60, 60); + g2d.setPaint(color2); + g2d.fillOval(l2x, l2y, 60, 60); + } + + protected void renderSignal3(Graphics2D g2d, JComponent c) { + Tile tile = (Tile) c; + SignalValue signalValue = tile.getSignalValue(); + + int rx = RENDER_GRID; + int ry = RENDER_GRID + 60; + int rw = 180; + int rh = 100; + + int c1x = RENDER_GRID + 130; + int c1y = RENDER_GRID + 115; + + int c2x = RENDER_GRID + 10; + int c2y = RENDER_GRID + 115; + + int c3x = RENDER_GRID + 10; + int c3y = RENDER_GRID + 65; + + // Initialize all "lights" + Color color1 = Color.gray; + Color color2 = Color.gray; + Color color3 = Color.gray; + + if (signalValue == null) { + signalValue = AccessoryBean.SignalValue.OFF; + } + + switch (signalValue) { + case Hp0 -> { + color3 = Color.red; + } + case Hp1 -> + color1 = Color.green; + case Hp2 -> { + color1 = Color.green; + color2 = Color.yellow; + } + default -> { + } + } + + g2d.setStroke(new BasicStroke(10f)); + g2d.setPaint(Color.darkGray); + g2d.fillRoundRect(rx, ry, rw, rh, 30, 30); + + g2d.setPaint(color1); + g2d.fillOval(c1x, c1y, 40, 40); + + g2d.setPaint(color2); + g2d.fillOval(c2x, c2y, 40, 40); + + g2d.setPaint(color3); + g2d.fillOval(c3x, c3y, 40, 40); + } + + /** + * Render a entry Signal which can show 4 light images + * + * @param g2d the Graphics context + * @param c + */ + protected void renderSignal4(Graphics2D g2d, JComponent c) { + Tile tile = (Tile) c; + SignalValue signalValue = tile.getSignalValue(); + + int rx = RENDER_GRID - 50; + int ry = RENDER_GRID + 50; + int rw = 240; + int rh = 120; + int c1x = RENDER_GRID + 140; + int c1y = RENDER_GRID + 60; + + int c2x = RENDER_GRID + 90; + int c2y = RENDER_GRID + 60; + + int c3x = RENDER_GRID + 90; + int c3y = RENDER_GRID + 120; + + int c4x = RENDER_GRID + 60; + int c4y = RENDER_GRID + 130; + + int c5x = RENDER_GRID + 10; + int c5y = RENDER_GRID + 70; + + int c6x = RENDER_GRID - 40; + int c6y = RENDER_GRID + 60; + + // Initialize all "lights" + Color color1 = Color.gray; + Color color2 = Color.gray; + Color color3 = Color.gray; + Color color4 = Color.gray; + Color color5 = Color.gray; + Color color6 = Color.gray; + + if (signalValue == null) { + signalValue = AccessoryBean.SignalValue.OFF; + } + + switch (signalValue) { + case Hp0 -> { + color2 = Color.red; + color3 = Color.red; + } + case Hp1 -> + color1 = Color.green; + case Hp2 -> { + color1 = Color.green; + color6 = Color.yellow; + } + case Hp0Sh1 -> { + color2 = Color.red; + color4 = Color.white; + color5 = Color.white; + } + default -> { + } + } + + g2d.setStroke(new BasicStroke(10f)); + g2d.setPaint(Color.darkGray); + g2d.fillRoundRect(rx, ry, rw, rh, 30, 30); + + g2d.setPaint(color1); + g2d.fillOval(c1x, c1y, 40, 40); + g2d.setPaint(color2); + g2d.fillOval(c2x, c2y, 40, 40); + g2d.setPaint(color3); + g2d.fillOval(c3x, c3y, 40, 40); + g2d.setPaint(color4); + g2d.fillOval(c4x, c4y, 20, 20); + g2d.setPaint(color5); + g2d.fillOval(c5x, c5y, 20, 20); + g2d.setPaint(color6); + g2d.fillOval(c6x, c6y, 40, 40); + } + + /** + * Render a midget Signal + * + * @param g2d the Graphics context + * @param c + */ + protected void renderSignal2m(Graphics2D g2d, JComponent c) { + Tile tile = (Tile) c; + SignalValue signalValue = tile.getSignalValue(); + + int[] xps = new int[]{RENDER_GRID + 80, +RENDER_GRID + 150, +RENDER_GRID + 170, RENDER_GRID + 170, +RENDER_GRID + 150, RENDER_GRID + 80}; + + int[] yps = new int[]{RENDER_GRID + 60, RENDER_GRID + 60, RENDER_GRID + 80, +RENDER_GRID + 160, +RENDER_GRID + 180, RENDER_GRID + 180}; + + Polygon signalOutline = new Polygon(xps, yps, xps.length); + + int c1x = RENDER_GRID + 130; + int c1y = RENDER_GRID + 70; + + int c2x = RENDER_GRID + 130; + int c2y = RENDER_GRID + 140; + + int c3x = RENDER_GRID + 130; + int c3y = RENDER_GRID + 105; + + int c4x = RENDER_GRID + 85; + int c4y = RENDER_GRID + 70; + + Color color1 = Color.gray; + Color color2 = Color.gray; + Color color3 = Color.gray; + Color color4 = Color.gray; + + if (signalValue == null) { + signalValue = AccessoryBean.SignalValue.OFF; + } + + switch (signalValue) { + case Hp0 -> { + color1 = Color.red; + color2 = Color.red; + } + case Hp1 -> { + color3 = Color.white; + color4 = Color.white; + } + default -> { + } + } + + g2d.setStroke(new BasicStroke(10f)); + g2d.setPaint(Color.darkGray); + + g2d.fillPolygon(signalOutline); + + g2d.setPaint(color1); + g2d.fillOval(c1x, c1y, 30, 30); + + g2d.setPaint(color2); + g2d.fillOval(c2x, c2y, 30, 30); + + g2d.setPaint(color3); + g2d.fillOval(c3x, c3y, 30, 30); + + g2d.setPaint(color4); + g2d.fillOval(c4x, c4y, 30, 30); + } + + @Override + public void renderTile(Graphics2D g2, JComponent c) { + Tile tile = (Tile) c; + SignalType signalType = tile.getSignalType(); + + Graphics2D g2d = (Graphics2D) g2.create(); + renderStraight(g2d, c); + + if (signalType == null) { + signalType = AccessoryBean.SignalType.NONE; + } + + switch (signalType) { + case HP012 -> + renderSignal3(g2d, c); + case HP012SH1 -> + renderSignal4(g2d, c); + case HP0SH1 -> + renderSignal2m(g2d, c); + default -> + renderSignal2(g2d, c); + } + + g2d.dispose(); + } + +} diff --git a/src/main/java/jcs/ui/layout/tiles/ui/StraightDirectionUI.java b/src/main/java/jcs/ui/layout/tiles/ui/StraightDirectionUI.java new file mode 100644 index 00000000..858b5cce --- /dev/null +++ b/src/main/java/jcs/ui/layout/tiles/ui/StraightDirectionUI.java @@ -0,0 +1,49 @@ +/* + * Copyright 2025 Frans Jacobs. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package jcs.ui.layout.tiles.ui; + +import java.awt.BasicStroke; +import java.awt.Color; +import java.awt.Graphics2D; +import javax.swing.JComponent; +import javax.swing.plaf.ComponentUI; + +public class StraightDirectionUI extends StraightUI { + + public StraightDirectionUI() { + } + + public static ComponentUI createUI(JComponent c) { + return new StraightDirectionUI(); + } + + private void renderDirectionArrow(Graphics2D g2, JComponent c) { + // |\ + // ==|+=== + // |/ + g2.setStroke(new BasicStroke(4, BasicStroke.JOIN_MITER, BasicStroke.JOIN_ROUND)); + g2.setPaint(Color.green.darker()); + + g2.fillPolygon(new int[]{150, 150, 270}, new int[]{130, 270, 200}, 3); + } + + @Override + public void renderTile(Graphics2D g2, JComponent c) { + renderStraight(g2, c); + renderDirectionArrow(g2, c); + } + +} diff --git a/src/main/java/jcs/ui/layout/tiles/ui/StraightUI.java b/src/main/java/jcs/ui/layout/tiles/ui/StraightUI.java new file mode 100644 index 00000000..31bb053f --- /dev/null +++ b/src/main/java/jcs/ui/layout/tiles/ui/StraightUI.java @@ -0,0 +1,75 @@ +/* + * Copyright 2025 Frans Jacobs. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package jcs.ui.layout.tiles.ui; + +import java.awt.BasicStroke; +import java.awt.Color; +import java.awt.Graphics2D; +import javax.swing.JComponent; +import javax.swing.plaf.ComponentUI; +import jcs.ui.layout.tiles.Tile; + +public class StraightUI extends TileUI { + + public StraightUI() { + } + + public static ComponentUI createUI(JComponent c) { + return new StraightUI(); + } + + protected void renderStraight(Graphics2D g2, JComponent c) { + Tile tile = (Tile) c; + //Color trackColor = tile.getTrackColor(); + + int xx = 0; + int yy = 170; + int w = RENDER_WIDTH; + int h = 60; + + g2.setStroke(new BasicStroke(4, BasicStroke.JOIN_MITER, BasicStroke.JOIN_ROUND)); + g2.setPaint(trackColor); + + g2.fillRect(xx, yy, w, h); + } + + protected void renderRouteStraight(Graphics2D g2, JComponent c) { + Tile tile = (Tile) c; + + int xx, yy, w, h; + xx = 0; + yy = 190; + w = RENDER_WIDTH; + h = 20; + + //Color trackRouteColor = tile.getTrackRouteColor(); + g2.setStroke(new BasicStroke(4, BasicStroke.JOIN_MITER, BasicStroke.JOIN_ROUND)); + g2.setPaint(trackRouteColor); + + g2.fillRect(xx, yy, w, h); + } + + @Override + public void renderTileRoute(Graphics2D g2, JComponent c) { + renderRouteStraight(g2, c); + } + + @Override + public void renderTile(Graphics2D g2, JComponent c) { + renderStraight(g2, c); + } + +} diff --git a/src/main/java/jcs/ui/layout/tiles/ui/SwitchUI.java b/src/main/java/jcs/ui/layout/tiles/ui/SwitchUI.java new file mode 100644 index 00000000..6b4ae851 --- /dev/null +++ b/src/main/java/jcs/ui/layout/tiles/ui/SwitchUI.java @@ -0,0 +1,146 @@ +/* + * Copyright 2025 Frans Jacobs. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package jcs.ui.layout.tiles.ui; + +import java.awt.BasicStroke; +import java.awt.Color; +import java.awt.Graphics2D; +import javax.swing.JComponent; +import javax.swing.plaf.ComponentUI; +import jcs.entities.AccessoryBean; +import jcs.entities.AccessoryBean.AccessoryValue; +import static jcs.entities.AccessoryBean.AccessoryValue.GREEN; +import static jcs.entities.AccessoryBean.AccessoryValue.RED; +import jcs.entities.TileBean; +import jcs.ui.layout.tiles.Tile; + +public class SwitchUI extends TileUI { + + public SwitchUI() { + } + + public static ComponentUI createUI(JComponent c) { + return new SwitchUI(); + } + + protected void renderStraight(Graphics2D g2, Color color, JComponent c) { + int xx = 0; + int yy = 170; + int w = RENDER_WIDTH; + int h = 60; + + g2.setStroke(new BasicStroke(4, BasicStroke.JOIN_MITER, BasicStroke.JOIN_ROUND)); + g2.setPaint(color); + + g2.fillRect(xx, yy, w, h); + } + + protected void renderDiagonal(Graphics2D g2, Color color, JComponent c) { + Tile tile = (Tile) c; + TileBean.Direction direction = tile.getDirection(); + + int[] xPoints, yPoints; + if (TileBean.Direction.RIGHT.equals(direction)) { + xPoints = new int[]{400, 400, 170, 230}; + yPoints = new int[]{170, 230, 0, 0}; + } else { + xPoints = new int[]{400, 400, 170, 230}; + yPoints = new int[]{230, 170, 400, 400}; + } + + g2.setStroke(new BasicStroke(1, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND)); + g2.setPaint(color); + g2.fillPolygon(xPoints, yPoints, xPoints.length); + } + + protected void renderRouteStraight(Graphics2D g2, Color color, JComponent c) { + int xx = 0; + int yy = 190; + int w = RENDER_WIDTH; + int h = 20; + + g2.setStroke(new BasicStroke(4, BasicStroke.JOIN_MITER, BasicStroke.JOIN_ROUND)); + g2.setPaint(color); + + g2.fillRect(xx, yy, w, h); + } + + protected void renderRouteDiagonal(Graphics2D g2, Color color, JComponent c) { + Tile tile = (Tile) c; + TileBean.Direction direction = tile.getDirection(); + + int[] xPoints, yPoints; + if (TileBean.Direction.RIGHT.equals(direction)) { + xPoints = new int[]{400, 400, 190, 210}; + yPoints = new int[]{190, 210, 0, 0}; + } else { + xPoints = new int[]{400, 400, 190, 210}; + yPoints = new int[]{210, 190, 400, 400}; + } + + g2.setStroke(new BasicStroke(1, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND)); + g2.setPaint(color); + + g2.fillPolygon(xPoints, yPoints, xPoints.length); + } + + @Override + public void renderTile(Graphics2D g2, JComponent c) { + Tile tile = (Tile) c; + AccessoryValue accessoryValue = tile.getAccessoryValue(); + //Color trackColor = tile.getTrackColor(); + + if (accessoryValue == null) { + accessoryValue = AccessoryBean.AccessoryValue.OFF; + } + + switch (accessoryValue) { + case RED -> { + renderStraight(g2, trackColor, c); + renderDiagonal(g2, Color.red, c); + } + case GREEN -> { + renderDiagonal(g2, trackColor, c); + renderStraight(g2, Color.green, c); + } + default -> { + renderStraight(g2, trackColor, c); + renderDiagonal(g2, trackColor, c); + } + } + } + + @Override + public void renderTileRoute(Graphics2D g2, JComponent c) { + Tile tile = (Tile) c; + AccessoryValue routeValue = tile.getRouteValue(); + //Color trackRouteColor = tile.getTrackRouteColor(); + + if (routeValue == null) { + routeValue = AccessoryBean.AccessoryValue.OFF; + } + switch (routeValue) { + case RED -> { + renderRouteDiagonal(g2, trackRouteColor, c); + } + case GREEN -> { + renderRouteStraight(g2, trackRouteColor, c); + } + default -> { + } + } + } +} diff --git a/src/main/java/jcs/ui/layout/tiles/ui/TileUI.java b/src/main/java/jcs/ui/layout/tiles/ui/TileUI.java new file mode 100644 index 00000000..3d2f7176 --- /dev/null +++ b/src/main/java/jcs/ui/layout/tiles/ui/TileUI.java @@ -0,0 +1,272 @@ +/* + * Copyright 2025 Frans Jacobs. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package jcs.ui.layout.tiles.ui; + +import java.awt.Color; +import java.awt.Graphics; +import java.awt.Graphics2D; +import java.awt.Insets; +import java.awt.geom.AffineTransform; +import java.awt.geom.Ellipse2D; +import java.awt.image.BufferedImage; +import javax.swing.JComponent; +import javax.swing.plaf.ComponentUI; +import jcs.entities.TileBean; +import static jcs.entities.TileBean.Orientation.NORTH; +import static jcs.entities.TileBean.Orientation.SOUTH; +import static jcs.entities.TileBean.Orientation.WEST; +import jcs.ui.layout.tiles.Tile; +import static jcs.ui.layout.tiles.Tile.DEFAULT_BACKGROUND_COLOR; +import static jcs.ui.layout.tiles.Tile.DEFAULT_TRACK_COLOR; +import static jcs.ui.layout.tiles.Tile.GRID; +import jcs.ui.layout.tiles.TileModel; +import org.imgscalr.Scalr; +import org.tinylog.Logger; + +/** + * + * @author fransjacobs + */ +public abstract class TileUI extends ComponentUI { + + protected static final int RENDER_GRID = GRID * 10; + protected static final int RENDER_WIDTH = RENDER_GRID * 2; + protected static final int RENDER_HEIGHT = RENDER_GRID * 2; + + public static final String UI_CLASS_ID = "jcs.ui.layout.tiles.ui.TileUI"; + + protected int renderWidth; + protected int renderHeight; + + protected Color backgroundColor; + protected Color trackColor; + protected Color trackRouteColor; + + protected BufferedImage tileImage; + + protected TileUI() { + this.backgroundColor = DEFAULT_BACKGROUND_COLOR; + this.trackColor = DEFAULT_TRACK_COLOR; + } + + private void setRenderSize(JComponent c) { + Tile tile = (Tile) c; + + switch (tile.getTileType()) { + case CROSS -> { + if (tile.isHorizontal()) { + this.renderWidth = RENDER_GRID * 4; + this.renderHeight = RENDER_GRID * 2; + } else { + this.renderWidth = RENDER_GRID * 2; + this.renderHeight = RENDER_GRID * 4; + } + } + case BLOCK -> { + if (tile.isHorizontal()) { + this.renderWidth = RENDER_WIDTH * 3; + this.renderHeight = RENDER_HEIGHT; + } else { + this.renderWidth = RENDER_WIDTH; + this.renderHeight = RENDER_HEIGHT * 3; + } + } + default -> { + this.renderWidth = RENDER_WIDTH; + this.renderHeight = RENDER_HEIGHT; + } + } + } + + abstract void renderTile(Graphics2D g2d, JComponent c); + + abstract void renderTileRoute(Graphics2D g2d, JComponent c); + + public int getRenderWidth() { + return renderWidth; + } + + public void setRenderWidth(int renderWidth) { + this.renderWidth = renderWidth; + } + + public int getRenderHeight() { + return renderHeight; + } + + public void setRenderHeight(int renderHeight) { + this.renderHeight = renderHeight; + } + + public Color getBackgroundColor() { + return backgroundColor; + } + + public void setBackgroundColor(Color backgroundColor) { + this.backgroundColor = backgroundColor; + } + + public Color getTrackColor() { + return trackColor; + } + + public void setTrackColor(Color trackColor) { + this.trackColor = trackColor; + } + + public Color getTrackRouteColor() { + return trackRouteColor; + } + + public void setTrackRouteColor(Color trackRouteColor) { + this.trackRouteColor = trackRouteColor; + } + + protected BufferedImage createImage() { + return new BufferedImage(renderWidth, renderHeight, BufferedImage.TYPE_INT_RGB); + } + + public BufferedImage getTileImage() { + return tileImage; + } + + public void drawTile(Graphics2D g2d, JComponent c) { + // by default and image is rendered in the EAST orientation + setRenderSize(c); + + Tile tile = (Tile) c; + TileModel model = ((Tile) c).getModel(); + TileBean.Orientation tileOrientation = model.getTileOrienation(); + + //BufferedImage bf = new BufferedImage(tile.getRenderWidth(), tile.getRenderHeight(), BufferedImage.TYPE_INT_RGB); + BufferedImage bf = createImage(); + Graphics2D g2di = bf.createGraphics(); + + //Avoid errors + if (model.isShowRoute() && model.getIncomingSide() == null) { + model.setIncomingSide(tileOrientation); + } + + if (model.isSelected()) { + g2di.setBackground(model.getSelectedColor()); + } else { + g2di.setBackground(backgroundColor); + } + + g2di.clearRect(0, 0, renderWidth, renderHeight); + int ox = 0, oy = 0; + + AffineTransform trans = new AffineTransform(); + switch (tileOrientation) { + case SOUTH -> { + trans.rotate(Math.PI / 2, renderWidth / 2, renderHeight / 2); + ox = (renderHeight - renderWidth) / 2; + oy = (renderWidth - renderHeight) / 2; + trans.translate(-ox, -oy); + } + case WEST -> { + trans.rotate(Math.PI, renderWidth / 2, renderHeight / 2); + trans.translate(ox, oy); + } + case NORTH -> { + trans.rotate(-Math.PI / 2, renderWidth / 2, renderHeight / 2); + ox = (renderHeight - renderWidth) / 2; + oy = (renderWidth - renderHeight) / 2; + trans.translate(-ox, -oy); + } + default -> { + trans.rotate(0.0, renderWidth / 2, renderHeight / 2); + trans.translate(ox, oy); + } + } + + g2di.setTransform(trans); + + renderTile(g2di, c); + + if (model.isShowRoute()) { + renderTileRoute(g2di, c); + } + + if (model.isShowCenter()) { + drawCenterPoint(g2di, c); + } + + // Scale the image back... + if (model.isScaleImage()) { + tileImage = Scalr.resize(bf, Scalr.Method.AUTOMATIC, Scalr.Mode.FIT_EXACT, tile.getWidth(), tile.getHeight(), Scalr.OP_ANTIALIAS); + } else { + tileImage = bf; + } + g2di.dispose(); + } + + /** + * Render a tile image Always starts at (0,0) used the default width and height + * + * @param g2 the Graphic context + * @param c + */ + protected void drawName(Graphics2D g2, JComponent c) { + } + + protected void drawCenterPoint(Graphics2D g2d, JComponent c) { + drawCenterPoint(g2d, Color.magenta, c); + } + + protected void drawCenterPoint(Graphics2D g2, Color color, JComponent c) { + drawCenterPoint(g2, color, 60, c); + } + + protected void drawCenterPoint(Graphics2D g2d, Color color, double size, JComponent c) { + double dX = (renderWidth / 2 - size / 2); + double dY = (renderHeight / 2 - size / 2); + + g2d.setColor(color); + g2d.fill(new Ellipse2D.Double(dX, dY, size, size)); + } + + protected static void drawRotate(Graphics2D g2d, double x, double y, int angle, String text) { + g2d.translate((float) x, (float) y); + g2d.rotate(Math.toRadians(angle)); + g2d.drawString(text, 0, 0); + g2d.rotate(-Math.toRadians(angle)); + g2d.translate(-x, -y); + } + + @Override + public void paint(Graphics g, JComponent c) { + long started = System.currentTimeMillis(); + // We don't want to paint inside the insets or borders. + Insets insets = c.getInsets(); + g.translate(insets.left, insets.top); + + Graphics2D g2 = (Graphics2D) g.create(); + + drawTile(g2, c); + g2.dispose(); + + g.drawImage(tileImage, 0, 0, null); + g.translate(-insets.left, -insets.top); + + if (Logger.isTraceEnabled()) { + Tile tile = (Tile) c; + TileModel model = tile.getModel(); + long now = System.currentTimeMillis(); + Logger.trace(tile.getId() + " Duration: " + (now - started) + " ms. Cp: " + tile.xyToString() + " O: " + model.getTileOrienation()); + } + } +} diff --git a/src/test/java/jcs/ui/layout/tiles/TileTesterFrame.form b/src/test/java/jcs/ui/layout/tiles/TileTesterFrame.form index 345a66d6..9b77fbc1 100644 --- a/src/test/java/jcs/ui/layout/tiles/TileTesterFrame.form +++ b/src/test/java/jcs/ui/layout/tiles/TileTesterFrame.form @@ -1 +1,454 @@ -

\ No newline at end of file + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/test/java/jcs/ui/layout/tiles/TileTesterFrame.java b/src/test/java/jcs/ui/layout/tiles/TileTesterFrame.java index 8d11d4ec..3aa327eb 100644 --- a/src/test/java/jcs/ui/layout/tiles/TileTesterFrame.java +++ b/src/test/java/jcs/ui/layout/tiles/TileTesterFrame.java @@ -1 +1 @@ -/* * Copyright 2024 Frans Jacobs. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package jcs.ui.layout.tiles; import java.awt.Color; import java.awt.Point; import javax.swing.ComboBoxModel; import javax.swing.DefaultComboBoxModel; import javax.swing.UIManager; import javax.swing.UnsupportedLookAndFeelException; import jcs.entities.AccessoryBean; import jcs.entities.AccessoryBean.AccessoryValue; import jcs.entities.TileBean; import jcs.entities.TileBean.Direction; import jcs.entities.TileBean.Orientation; import static jcs.entities.TileBean.Orientation.NORTH; import static jcs.entities.TileBean.Orientation.SOUTH; import static jcs.entities.TileBean.Orientation.WEST; import jcs.entities.TileBean.TileType; import jcs.ui.layout.LayoutUtil; import jcs.ui.layout.events.TileEvent; import org.tinylog.Logger; public class TileTesterFrame extends javax.swing.JFrame { private Tile tile; public TileTesterFrame() { initComponents(); this.tileCB.setModel(createTileTypeComboBoxModel()); this.orientationCB.setModel(createOrientationComboBoxModel()); this.incomingSideCB.setModel(createOrientationComboBoxModel()); this.directionCB.setModel(createDirectionComboBoxModel(true)); createTile(); pack(); setVisible(true); } private ComboBoxModel createTileTypeComboBoxModel() { DefaultComboBoxModel tileTypeModel = new DefaultComboBoxModel(); tileTypeModel.addElement(TileBean.TileType.STRAIGHT); tileTypeModel.addElement(TileBean.TileType.STRAIGHT_DIR); tileTypeModel.addElement(TileBean.TileType.SENSOR); tileTypeModel.addElement(TileBean.TileType.SIGNAL); tileTypeModel.addElement(TileBean.TileType.END); tileTypeModel.addElement(TileBean.TileType.CROSSING); tileTypeModel.addElement(TileBean.TileType.CURVED); tileTypeModel.addElement(TileBean.TileType.SWITCH); tileTypeModel.addElement(TileBean.TileType.CROSS); return tileTypeModel; } private ComboBoxModel createOrientationComboBoxModel() { DefaultComboBoxModel orientationModel = new DefaultComboBoxModel(); orientationModel.addElement(Orientation.EAST); orientationModel.addElement(Orientation.SOUTH); orientationModel.addElement(Orientation.WEST); orientationModel.addElement(Orientation.NORTH); return orientationModel; } private ComboBoxModel createDirectionComboBoxModel(boolean dontCare) { DefaultComboBoxModel directionModel = new DefaultComboBoxModel(); if (dontCare) { directionModel.addElement(Direction.CENTER); } else { directionModel.addElement(Direction.LEFT); directionModel.addElement(Direction.RIGHT); } return directionModel; } private void createTile() { if (tile != null) { Logger.trace("Removing tile " + tile.getId()); canvas.remove(tile); tile = null; } TileType tileType = (TileType) tileCB.getSelectedItem(); Orientation orientation = (Orientation) orientationCB.getSelectedItem(); if (TileType.SWITCH == tileType || TileType.CROSS == tileType) { directionCB.setModel(createDirectionComboBoxModel(false)); } else { directionCB.setModel(createDirectionComboBoxModel(true)); } Direction direction = (Direction) this.directionCB.getSelectedItem(); boolean scale = !scaleCB.isSelected(); boolean showCenter = showCenterCB.isSelected(); int w = canvas.getWidth(); int h = canvas.getHeight(); int x = w / 2; int y = h / 2; Point tileCenter = new Point(x, y); tileCenter = LayoutUtil.snapToGrid(tileCenter); // if (TileType.CROSS == tileType) { // switch (orientation) { // case SOUTH -> { // x = w / 2 + 200; // y = h / 2 - 150; // } // case WEST -> { // x = w / 2 + 400; // y = h / 2 + 50; // } // case NORTH -> { // x = w / 2 + 200; // y = h / 2 + 250; // } // default -> { // x = w / 2; // y = h / 2 + 50; // } // } // } else { // x = w / 2 - 200; // y = h / 2 - 200; // } // Point center; // if (TileType.CROSS.equals(tileType)) { // center = new Point(x - 200, y); // } else { // center = new Point(x, y); // } Tile newTile = TileFactory.createTile(tileType, orientation, direction, tileCenter); newTile.setScaleImage(scale); newTile.setDrawCenterPoint(showCenter); //tile.setPropertyChangeListener(this); Orientation incomingSide = (Orientation) this.incomingSideCB.getSelectedItem(); newTile.setIncomingSide(incomingSide); newTile.setShowRoute(displayRouteCB.isSelected()); newTile.setTrackRouteColor(Color.blue); Logger.trace("Adding tile " + newTile.getId() + " " + newTile.xyToString()); //this.cPanel.add((JComponent) newTile); this.canvas.add(newTile); this.tile = newTile; } private AccessoryValue getAccessoryState() { AccessoryValue value; if (greenRB.isSelected()) { value = AccessoryValue.GREEN; } else if (redRB.isSelected()) { value = AccessoryValue.RED; } else { value = AccessoryValue.OFF; } return value; } private void changeAccesoryState() { if(tile instanceof Sensor) { tile.setActive(this.redRB.isSelected()); } if (tile instanceof Switch aSwitch) { if (this.displayRouteCB.isSelected()) { aSwitch.setRouteValue(getAccessoryState()); } else { aSwitch.setAccessoryValue(getAccessoryState()); } } if (tile instanceof Signal aSignal) { if (this.greenRB.isSelected()) { aSignal.setSignalValue(AccessoryBean.SignalValue.Hp1); } else if (this.redRB.isSelected()) { aSignal.setSignalValue(AccessoryBean.SignalValue.Hp0); } else { aSignal.setSignalValue(AccessoryBean.SignalValue.OFF); } } //this.tile.repaint(); } // @Override // public void propertyChange(PropertyChangeEvent evt) { // if ("repaintTile".equals(evt.getPropertyName())) { // Tile t = (Tile) evt.getNewValue(); // Logger.trace("Tile: " + t); // //this.repaint(); // } // } // @Override // public void paint(Graphics g) { // super.paint(g); // Graphics2D g2d = (Graphics2D) g; // boolean outline = this.drawOutlineCB.isSelected(); // boolean showRoute = this.displayRouteCB.isSelected(); // tile.setShowRoute(showRoute); // // tile.drawTile(g2d, outline); // // if (outline) { // tile.drawBounds(g2d); // tile.drawCenterPoint(g2d, Color.red); // } // } // @Override // public void paint(Graphics g) { // long started = System.currentTimeMillis(); // super.paint(g); // // long now = System.currentTimeMillis(); // Logger.trace("Duration: " + (now - started) + " ms."); // } private void changeDirection() { Direction direction = (Direction) this.directionCB.getSelectedItem(); this.tile.setDirection(direction); //if (TileType.CROSS == tile.getTileType()) { // ((Cross) tile).setWidthHeightAndOffsets(); //} //this.repaint(); } private void rotateTile() { Orientation newOrientation = tile.rotate(); orientationCB.setSelectedItem(newOrientation); // if (TileType.CROSS == tile.getTileType()) { // int x = tile.getCenterX(); // int y = tile.getCenterY(); // int w = tile.getWidth() * 10; // int h = tile.getHeight() * 10; // // //calculate a new centerpoint for cross // switch (tile.getOrientation()) { // case SOUTH -> { // x = x + w / 2; // y = y - h / 4; // } // case WEST -> { // x = x + w / 4; // y = y + h / 2; // } // case NORTH -> { // x = x - w / 2; // y = y + h / 4; // } // default -> { // x = x - w / 4; // y = y - h / 2; // } // } // tile.setCenter(new Point(x, y)); // } //this.canvas.repaint(this.tile.getTileBounds()); //tile.repaint(); } private void changeOrientation() { Orientation orientation = (Orientation) this.orientationCB.getSelectedItem(); tile.setOrientation(orientation); // if (TileType.CROSS == tile.getTileType()) { // //((Cross) tile).setWidthHeightAndOffsets(); // // int x = tile.getCenterX(); // int y = tile.getCenterY(); // int w = tile.getWidth() * 10; // int h = tile.getHeight() * 10; // // //calculate a new centerpoint for cross // switch (tile.getOrientation()) { // case SOUTH -> { // x = x + w / 2; // y = y - h / 4; // } // case WEST -> { // x = x + w / 4; // y = y + h / 2; // } // case NORTH -> { // x = x - w / 2; // y = y + h / 4; // } // default -> { // x = x - w / 4; // y = y - h / 2; // } // } // tile.setCenter(new Point(x, y)); // } //this.repaint(); } private void showRoute() { Logger.trace("Show route on tile " + tile.getId()); String tileId = tile.getId(); Orientation incomingSide = (Orientation) this.incomingSideCB.getSelectedItem(); //TileEvent tileEvent; if (tile.isJunction()) { AccessoryValue routeState = getAccessoryState(); //tileEvent = new TileEvent(tileId, true, incomingSide, routeState); } else { //tileEvent = new TileEvent(tileId, true, incomingSide); } //TileCache.fireTileEventListener(tileEvent); // ((JComponent) this.tile).repaint(); tile.setShowRoute(displayRouteCB.isSelected()); //repaint(); } // private void showOutline() { // //repaint(); // } private void changeIncomingSide() { Orientation incomingSide = (Orientation) this.incomingSideCB.getSelectedItem(); tile.setIncomingSide(incomingSide); //this.repaint(); } /** * This method is called from within the constructor to initialize the form. WARNING: Do NOT modify this code. The content of this method is always regenerated by the Form Editor. */ @SuppressWarnings("unchecked") // //GEN-BEGIN:initComponents private void initComponents() { accessoryBG = new javax.swing.ButtonGroup(); nPanel = new javax.swing.JPanel(); tileCB = new javax.swing.JComboBox<>(); orientationCB = new javax.swing.JComboBox<>(); inComingLbl = new javax.swing.JLabel(); incomingSideCB = new javax.swing.JComboBox<>(); directionCB = new javax.swing.JComboBox<>(); rotateButton = new javax.swing.JButton(); offRB = new javax.swing.JRadioButton(); greenRB = new javax.swing.JRadioButton(); redRB = new javax.swing.JRadioButton(); displayRouteCB = new javax.swing.JCheckBox(); scaleCB = new javax.swing.JCheckBox(); showCenterCB = new javax.swing.JCheckBox(); canvas = new jcs.ui.layout.tiles.DotGridCanvas(); setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE); nPanel.setMinimumSize(new java.awt.Dimension(860, 36)); nPanel.setPreferredSize(new java.awt.Dimension(1020, 36)); java.awt.FlowLayout flowLayout1 = new java.awt.FlowLayout(java.awt.FlowLayout.LEFT); flowLayout1.setAlignOnBaseline(true); nPanel.setLayout(flowLayout1); tileCB.setPreferredSize(new java.awt.Dimension(150, 23)); tileCB.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { tileCBActionPerformed(evt); } }); nPanel.add(tileCB); orientationCB.setPreferredSize(new java.awt.Dimension(100, 23)); orientationCB.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { orientationCBActionPerformed(evt); } }); nPanel.add(orientationCB); inComingLbl.setText("Incoming Orientation"); nPanel.add(inComingLbl); incomingSideCB.setPreferredSize(new java.awt.Dimension(100, 23)); incomingSideCB.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { incomingSideCBActionPerformed(evt); } }); nPanel.add(incomingSideCB); directionCB.setPreferredSize(new java.awt.Dimension(100, 23)); directionCB.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { directionCBActionPerformed(evt); } }); nPanel.add(directionCB); rotateButton.setText("Rotate"); rotateButton.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { rotateButtonActionPerformed(evt); } }); nPanel.add(rotateButton); accessoryBG.add(offRB); offRB.setForeground(new java.awt.Color(153, 153, 153)); offRB.setSelected(true); offRB.setText("Off"); offRB.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { offRBActionPerformed(evt); } }); nPanel.add(offRB); accessoryBG.add(greenRB); greenRB.setForeground(new java.awt.Color(102, 255, 0)); greenRB.setText("Green"); greenRB.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { greenRBActionPerformed(evt); } }); nPanel.add(greenRB); accessoryBG.add(redRB); redRB.setForeground(new java.awt.Color(255, 0, 51)); redRB.setText("Red"); redRB.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { redRBActionPerformed(evt); } }); nPanel.add(redRB); displayRouteCB.setText("Route"); displayRouteCB.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { displayRouteCBActionPerformed(evt); } }); nPanel.add(displayRouteCB); scaleCB.setText("Scale"); scaleCB.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { scaleCBActionPerformed(evt); } }); nPanel.add(scaleCB); showCenterCB.setText("Center"); showCenterCB.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { showCenterCBActionPerformed(evt); } }); nPanel.add(showCenterCB); getContentPane().add(nPanel, java.awt.BorderLayout.NORTH); canvas.setPreferredSize(new java.awt.Dimension(600, 600)); getContentPane().add(canvas, java.awt.BorderLayout.CENTER); pack(); }// //GEN-END:initComponents private void rotateButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_rotateButtonActionPerformed rotateTile(); }//GEN-LAST:event_rotateButtonActionPerformed private void tileCBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_tileCBActionPerformed createTile(); }//GEN-LAST:event_tileCBActionPerformed private void orientationCBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_orientationCBActionPerformed changeOrientation(); }//GEN-LAST:event_orientationCBActionPerformed private void directionCBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_directionCBActionPerformed changeDirection(); }//GEN-LAST:event_directionCBActionPerformed private void offRBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_offRBActionPerformed changeAccesoryState(); }//GEN-LAST:event_offRBActionPerformed private void greenRBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_greenRBActionPerformed changeAccesoryState(); }//GEN-LAST:event_greenRBActionPerformed private void redRBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_redRBActionPerformed changeAccesoryState(); }//GEN-LAST:event_redRBActionPerformed private void displayRouteCBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_displayRouteCBActionPerformed showRoute(); }//GEN-LAST:event_displayRouteCBActionPerformed private void scaleCBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_scaleCBActionPerformed this.tile.setScaleImage(!this.scaleCB.isSelected()); this.tile.setBounds(this.tile.getTileBounds()); }//GEN-LAST:event_scaleCBActionPerformed private void incomingSideCBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_incomingSideCBActionPerformed changeIncomingSide(); }//GEN-LAST:event_incomingSideCBActionPerformed private void showCenterCBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_showCenterCBActionPerformed this.tile.setDrawCenterPoint(this.showCenterCB.isSelected()); }//GEN-LAST:event_showCenterCBActionPerformed /** * @param args the command line arguments */ public static void main(String args[]) { try { UIManager.setLookAndFeel("com.formdev.flatlaf.FlatLightLaf"); } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) { Logger.error(ex); } /* Create and display the form */ java.awt.EventQueue.invokeLater(() -> { TileTesterFrame app = new TileTesterFrame(); app.setTitle("Tile Tester"); app.setLocationRelativeTo(null); }); } // Variables declaration - do not modify//GEN-BEGIN:variables private javax.swing.ButtonGroup accessoryBG; private jcs.ui.layout.tiles.DotGridCanvas canvas; private javax.swing.JComboBox directionCB; private javax.swing.JCheckBox displayRouteCB; private javax.swing.JRadioButton greenRB; private javax.swing.JLabel inComingLbl; private javax.swing.JComboBox incomingSideCB; private javax.swing.JPanel nPanel; private javax.swing.JRadioButton offRB; private javax.swing.JComboBox orientationCB; private javax.swing.JRadioButton redRB; private javax.swing.JButton rotateButton; private javax.swing.JCheckBox scaleCB; private javax.swing.JCheckBox showCenterCB; private javax.swing.JComboBox tileCB; // End of variables declaration//GEN-END:variables } \ No newline at end of file +/* * Copyright 2024 Frans Jacobs. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package jcs.ui.layout.tiles; import java.awt.Color; import java.awt.Point; import javax.swing.ComboBoxModel; import javax.swing.DefaultComboBoxModel; import javax.swing.UIManager; import javax.swing.UnsupportedLookAndFeelException; import jcs.entities.AccessoryBean; import jcs.entities.AccessoryBean.AccessoryValue; import jcs.entities.TileBean; import jcs.entities.TileBean.Direction; import jcs.entities.TileBean.Orientation; import jcs.entities.TileBean.TileType; import jcs.ui.layout.LayoutUtil; import org.tinylog.Logger; public class TileTesterFrame extends javax.swing.JFrame { private Tile tile; public TileTesterFrame() { initComponents(); this.tileCB.setModel(createTileTypeComboBoxModel()); this.orientationCB.setModel(createOrientationComboBoxModel()); this.incomingSideCB.setModel(createOrientationComboBoxModel()); this.directionCB.setModel(createDirectionComboBoxModel(true)); createTile(); pack(); setVisible(true); } private ComboBoxModel createTileTypeComboBoxModel() { DefaultComboBoxModel tileTypeModel = new DefaultComboBoxModel(); tileTypeModel.addElement(TileBean.TileType.STRAIGHT); tileTypeModel.addElement(TileBean.TileType.STRAIGHT_DIR); tileTypeModel.addElement(TileBean.TileType.SENSOR); tileTypeModel.addElement(TileBean.TileType.SIGNAL); tileTypeModel.addElement(TileBean.TileType.END); tileTypeModel.addElement(TileBean.TileType.CROSSING); tileTypeModel.addElement(TileBean.TileType.CURVED); tileTypeModel.addElement(TileBean.TileType.SWITCH); tileTypeModel.addElement(TileBean.TileType.CROSS); return tileTypeModel; } private ComboBoxModel createOrientationComboBoxModel() { DefaultComboBoxModel orientationModel = new DefaultComboBoxModel(); orientationModel.addElement(Orientation.EAST); orientationModel.addElement(Orientation.SOUTH); orientationModel.addElement(Orientation.WEST); orientationModel.addElement(Orientation.NORTH); return orientationModel; } private ComboBoxModel createDirectionComboBoxModel(boolean dontCare) { DefaultComboBoxModel directionModel = new DefaultComboBoxModel(); if (dontCare) { directionModel.addElement(Direction.CENTER); } else { directionModel.addElement(Direction.LEFT); directionModel.addElement(Direction.RIGHT); } return directionModel; } private void createTile() { if (tile != null) { Logger.trace("Removing tile " + tile.getId()); canvas.remove(tile); tile = null; } TileType tileType = (TileType) tileCB.getSelectedItem(); Orientation orientation = (Orientation) orientationCB.getSelectedItem(); if (TileType.SWITCH == tileType || TileType.CROSS == tileType) { directionCB.setModel(createDirectionComboBoxModel(false)); } else { directionCB.setModel(createDirectionComboBoxModel(true)); } Direction direction = (Direction) this.directionCB.getSelectedItem(); boolean scale = !scaleCB.isSelected(); boolean showCenter = showCenterCB.isSelected(); int w = canvas.getWidth(); int h = canvas.getHeight(); int x = w / 2; int y = h / 2; Point tileCenter = new Point(x, y); tileCenter = LayoutUtil.snapToGrid(tileCenter); Tile newTile = TileFactory.createTile(tileType, orientation, direction, tileCenter); newTile.setScaleImage(scale); newTile.setDrawCenterPoint(showCenter); //tile.setPropertyChangeListener(this); Orientation incomingSide = (Orientation) this.incomingSideCB.getSelectedItem(); newTile.setIncomingSide(incomingSide); newTile.setShowRoute(displayRouteCB.isSelected()); newTile.setTrackRouteColor(Color.blue); Logger.trace("Adding tile " + newTile.getId() + " " + newTile.xyToString()); //this.cPanel.add((JComponent) newTile); this.canvas.add(newTile); this.tile = newTile; tile.updateUI(); } private AccessoryValue getAccessoryState() { AccessoryValue value; if (greenRB.isSelected()) { value = AccessoryValue.GREEN; } else if (redRB.isSelected()) { value = AccessoryValue.RED; } else { value = AccessoryValue.OFF; } return value; } private void changeAccesoryState() { if (tile instanceof Sensor) { tile.setActive(this.redRB.isSelected()); } if (tile instanceof Switch aSwitch) { if (this.displayRouteCB.isSelected()) { aSwitch.setRouteValue(getAccessoryState()); } else { aSwitch.setAccessoryValue(getAccessoryState()); } } if (tile instanceof Signal aSignal) { if (this.greenRB.isSelected()) { aSignal.setSignalValue(AccessoryBean.SignalValue.Hp1); } else if (this.redRB.isSelected()) { aSignal.setSignalValue(AccessoryBean.SignalValue.Hp0); } else { aSignal.setSignalValue(AccessoryBean.SignalValue.OFF); } } //this.tile.repaint(); } // @Override // public void propertyChange(PropertyChangeEvent evt) { // if ("repaintTile".equals(evt.getPropertyName())) { // Tile t = (Tile) evt.getNewValue(); // Logger.trace("Tile: " + t); // //this.repaint(); // } // } // @Override // public void paint(Graphics g) { // super.paint(g); // Graphics2D g2d = (Graphics2D) g; // boolean outline = this.drawOutlineCB.isSelected(); // boolean showRoute = this.displayRouteCB.isSelected(); // tile.setShowRoute(showRoute); // // tile.drawTile(g2d, outline); // // if (outline) { // tile.drawBounds(g2d); // tile.drawCenterPoint(g2d, Color.red); // } // } // @Override // public void paint(Graphics g) { // long started = System.currentTimeMillis(); // super.paint(g); // // long now = System.currentTimeMillis(); // Logger.trace("Duration: " + (now - started) + " ms."); // } private void changeDirection() { Direction direction = (Direction) this.directionCB.getSelectedItem(); this.tile.setDirection(direction); //if (TileType.CROSS == tile.getTileType()) { // ((Cross) tile).setWidthHeightAndOffsets(); //} //this.repaint(); } private void rotateTile() { Orientation newOrientation = tile.rotate(); orientationCB.setSelectedItem(newOrientation); // if (TileType.CROSS == tile.getTileType()) { // int x = tile.getCenterX(); // int y = tile.getCenterY(); // int w = tile.getWidth() * 10; // int h = tile.getHeight() * 10; // // //calculate a new centerpoint for cross // switch (tile.getOrientation()) { // case SOUTH -> { // x = x + w / 2; // y = y - h / 4; // } // case WEST -> { // x = x + w / 4; // y = y + h / 2; // } // case NORTH -> { // x = x - w / 2; // y = y + h / 4; // } // default -> { // x = x - w / 4; // y = y - h / 2; // } // } // tile.setCenter(new Point(x, y)); // } //this.canvas.repaint(this.tile.getTileBounds()); //tile.repaint(); } private void changeOrientation() { Orientation orientation = (Orientation) this.orientationCB.getSelectedItem(); tile.setOrientation(orientation); // if (TileType.CROSS == tile.getTileType()) { // //((Cross) tile).setWidthHeightAndOffsets(); // // int x = tile.getCenterX(); // int y = tile.getCenterY(); // int w = tile.getWidth() * 10; // int h = tile.getHeight() * 10; // // //calculate a new centerpoint for cross // switch (tile.getOrientation()) { // case SOUTH -> { // x = x + w / 2; // y = y - h / 4; // } // case WEST -> { // x = x + w / 4; // y = y + h / 2; // } // case NORTH -> { // x = x - w / 2; // y = y + h / 4; // } // default -> { // x = x - w / 4; // y = y - h / 2; // } // } // tile.setCenter(new Point(x, y)); // } //this.repaint(); } private void showRoute() { Logger.trace("Show route on tile " + tile.getId()); String tileId = tile.getId(); Orientation incomingSide = (Orientation) this.incomingSideCB.getSelectedItem(); //TileEvent tileEvent; if (tile.isJunction()) { AccessoryValue routeState = getAccessoryState(); //tileEvent = new TileEvent(tileId, true, incomingSide, routeState); } else { //tileEvent = new TileEvent(tileId, true, incomingSide); } //TileCache.fireTileEventListener(tileEvent); // ((JComponent) this.tile).repaint(); tile.setShowRoute(displayRouteCB.isSelected()); //repaint(); } // private void showOutline() { // //repaint(); // } private void changeIncomingSide() { Orientation incomingSide = (Orientation) this.incomingSideCB.getSelectedItem(); tile.setIncomingSide(incomingSide); //this.repaint(); } /** * This method is called from within the constructor to initialize the form. WARNING: Do NOT modify this code. The content of this method is always regenerated by the Form Editor. */ @SuppressWarnings("unchecked") // //GEN-BEGIN:initComponents private void initComponents() { accessoryBG = new javax.swing.ButtonGroup(); nPanel = new javax.swing.JPanel(); tileCB = new javax.swing.JComboBox<>(); orientationCB = new javax.swing.JComboBox<>(); inComingLbl = new javax.swing.JLabel(); incomingSideCB = new javax.swing.JComboBox<>(); directionCB = new javax.swing.JComboBox<>(); rotateButton = new javax.swing.JButton(); offRB = new javax.swing.JRadioButton(); greenRB = new javax.swing.JRadioButton(); redRB = new javax.swing.JRadioButton(); displayRouteCB = new javax.swing.JCheckBox(); scaleCB = new javax.swing.JCheckBox(); showCenterCB = new javax.swing.JCheckBox(); canvas = new jcs.ui.layout.tiles.DotGridCanvas(); setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE); nPanel.setMinimumSize(new java.awt.Dimension(860, 36)); nPanel.setPreferredSize(new java.awt.Dimension(1020, 36)); java.awt.FlowLayout flowLayout1 = new java.awt.FlowLayout(java.awt.FlowLayout.LEFT); flowLayout1.setAlignOnBaseline(true); nPanel.setLayout(flowLayout1); tileCB.setPreferredSize(new java.awt.Dimension(150, 23)); tileCB.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { tileCBActionPerformed(evt); } }); nPanel.add(tileCB); orientationCB.setPreferredSize(new java.awt.Dimension(100, 23)); orientationCB.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { orientationCBActionPerformed(evt); } }); nPanel.add(orientationCB); inComingLbl.setText("Incoming Orientation"); nPanel.add(inComingLbl); incomingSideCB.setPreferredSize(new java.awt.Dimension(100, 23)); incomingSideCB.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { incomingSideCBActionPerformed(evt); } }); nPanel.add(incomingSideCB); directionCB.setPreferredSize(new java.awt.Dimension(100, 23)); directionCB.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { directionCBActionPerformed(evt); } }); nPanel.add(directionCB); rotateButton.setText("Rotate"); rotateButton.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { rotateButtonActionPerformed(evt); } }); nPanel.add(rotateButton); accessoryBG.add(offRB); offRB.setForeground(new java.awt.Color(153, 153, 153)); offRB.setSelected(true); offRB.setText("Off"); offRB.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { offRBActionPerformed(evt); } }); nPanel.add(offRB); accessoryBG.add(greenRB); greenRB.setForeground(new java.awt.Color(102, 255, 0)); greenRB.setText("Green"); greenRB.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { greenRBActionPerformed(evt); } }); nPanel.add(greenRB); accessoryBG.add(redRB); redRB.setForeground(new java.awt.Color(255, 0, 51)); redRB.setText("Red"); redRB.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { redRBActionPerformed(evt); } }); nPanel.add(redRB); displayRouteCB.setText("Route"); displayRouteCB.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { displayRouteCBActionPerformed(evt); } }); nPanel.add(displayRouteCB); scaleCB.setText("Scale"); scaleCB.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { scaleCBActionPerformed(evt); } }); nPanel.add(scaleCB); showCenterCB.setText("Center"); showCenterCB.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { showCenterCBActionPerformed(evt); } }); nPanel.add(showCenterCB); getContentPane().add(nPanel, java.awt.BorderLayout.NORTH); canvas.setPreferredSize(new java.awt.Dimension(600, 600)); getContentPane().add(canvas, java.awt.BorderLayout.CENTER); pack(); }// //GEN-END:initComponents private void rotateButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_rotateButtonActionPerformed rotateTile(); }//GEN-LAST:event_rotateButtonActionPerformed private void tileCBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_tileCBActionPerformed createTile(); }//GEN-LAST:event_tileCBActionPerformed private void orientationCBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_orientationCBActionPerformed changeOrientation(); }//GEN-LAST:event_orientationCBActionPerformed private void directionCBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_directionCBActionPerformed changeDirection(); }//GEN-LAST:event_directionCBActionPerformed private void offRBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_offRBActionPerformed changeAccesoryState(); }//GEN-LAST:event_offRBActionPerformed private void greenRBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_greenRBActionPerformed changeAccesoryState(); }//GEN-LAST:event_greenRBActionPerformed private void redRBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_redRBActionPerformed changeAccesoryState(); }//GEN-LAST:event_redRBActionPerformed private void displayRouteCBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_displayRouteCBActionPerformed showRoute(); }//GEN-LAST:event_displayRouteCBActionPerformed private void scaleCBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_scaleCBActionPerformed this.tile.setScaleImage(!this.scaleCB.isSelected()); this.tile.setBounds(this.tile.getTileBounds()); }//GEN-LAST:event_scaleCBActionPerformed private void incomingSideCBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_incomingSideCBActionPerformed changeIncomingSide(); }//GEN-LAST:event_incomingSideCBActionPerformed private void showCenterCBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_showCenterCBActionPerformed this.tile.setDrawCenterPoint(this.showCenterCB.isSelected()); }//GEN-LAST:event_showCenterCBActionPerformed /** * @param args the command line arguments */ public static void main(String args[]) { try { UIManager.setLookAndFeel("com.formdev.flatlaf.FlatLightLaf"); } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) { Logger.error(ex); } /* Create and display the form */ java.awt.EventQueue.invokeLater(() -> { TileTesterFrame app = new TileTesterFrame(); app.setTitle("Tile Tester"); app.setLocationRelativeTo(null); }); } // Variables declaration - do not modify//GEN-BEGIN:variables private javax.swing.ButtonGroup accessoryBG; private jcs.ui.layout.tiles.DotGridCanvas canvas; private javax.swing.JComboBox directionCB; private javax.swing.JCheckBox displayRouteCB; private javax.swing.JRadioButton greenRB; private javax.swing.JLabel inComingLbl; private javax.swing.JComboBox incomingSideCB; private javax.swing.JPanel nPanel; private javax.swing.JRadioButton offRB; private javax.swing.JComboBox orientationCB; private javax.swing.JRadioButton redRB; private javax.swing.JButton rotateButton; private javax.swing.JCheckBox scaleCB; private javax.swing.JCheckBox showCenterCB; private javax.swing.JComboBox tileCB; // End of variables declaration//GEN-END:variables } \ No newline at end of file From 80e933d0fe01cf18968c4028bd14dc5738848270 Mon Sep 17 00:00:00 2001 From: Frans Jacobs Date: Sat, 8 Feb 2025 17:07:05 +0100 Subject: [PATCH 15/24] Cleanup code, minor fix in Crossing --- src/main/java/jcs/ui/layout/tiles/Block.java | 426 +----------------- src/main/java/jcs/ui/layout/tiles/Cross.java | 300 +----------- .../java/jcs/ui/layout/tiles/Crossing.java | 3 + src/main/java/jcs/ui/layout/tiles/Curved.java | 3 + src/main/java/jcs/ui/layout/tiles/End.java | 3 + src/main/java/jcs/ui/layout/tiles/Sensor.java | 3 + src/main/java/jcs/ui/layout/tiles/Signal.java | 275 +---------- .../java/jcs/ui/layout/tiles/Straight.java | 3 + .../ui/layout/tiles/StraightDirection.java | 18 +- src/main/java/jcs/ui/layout/tiles/Switch.java | 93 +--- src/main/java/jcs/ui/layout/tiles/Tile.java | 242 ++-------- .../java/jcs/ui/layout/tiles/ui/CrossUI.java | 31 -- .../jcs/ui/layout/tiles/ui/CrossingUI.java | 35 +- .../java/jcs/ui/layout/tiles/ui/CurvedUI.java | 7 - .../java/jcs/ui/layout/tiles/ui/EndUI.java | 3 - .../jcs/ui/layout/tiles/ui/StraightUI.java | 8 - .../java/jcs/ui/layout/tiles/ui/SwitchUI.java | 3 - .../java/jcs/ui/layout/tiles/ui/TileUI.java | 5 +- 18 files changed, 90 insertions(+), 1371 deletions(-) diff --git a/src/main/java/jcs/ui/layout/tiles/Block.java b/src/main/java/jcs/ui/layout/tiles/Block.java index faa77ea3..8a6eb0a7 100755 --- a/src/main/java/jcs/ui/layout/tiles/Block.java +++ b/src/main/java/jcs/ui/layout/tiles/Block.java @@ -37,6 +37,9 @@ import jcs.ui.layout.tiles.ui.StraightUI; import jcs.ui.layout.tiles.ui.TileUI; +/** + * Representation of a Block on the layout + */ public class Block extends Tile { public static final int BLOCK_WIDTH = DEFAULT_WIDTH * 3; @@ -45,8 +48,6 @@ public class Block extends Tile { public Block(TileBean tileBean) { super(tileBean); setModel(new DefaultTileModel(tileBean.getOrientation())); - //changeRenderSize(); - populateModel(); initUI(); } @@ -62,7 +63,6 @@ public Block(Orientation orientation, int x, int y) { public Block(Orientation orientation, int x, int y, int width, int height) { super(TileType.BLOCK, orientation, x, y, width, height); setModel(new DefaultTileModel(orientation)); - //changeRenderSize(); initUI(); } @@ -82,16 +82,6 @@ public void updateUI() { invalidate(); } -// private void changeRenderSize() { -// Orientation tileOrientation = model.getTileOrienation(); -// if (Orientation.EAST == tileOrientation || Orientation.WEST == tileOrientation) { -// this.renderWidth = RENDER_WIDTH * 3; -// this.renderHeight = RENDER_HEIGHT; -// } else { -// this.renderWidth = RENDER_WIDTH; -// this.renderHeight = RENDER_HEIGHT * 3; -// } -// } @Override public Set getAltPoints() { int xx = this.tileX; @@ -331,43 +321,10 @@ public Orientation rotate() { Dimension d = new Dimension(w, h); setPreferredSize(d); setSize(d); - //changeRenderSize(); - setBounds(getTileBounds()); return model.getTileOrienation(); } - /** - * Depending on the block status change the background color
- * - Red: Occupied
- * - Green: Departure
- * - Magenta: Arrival / entering
- * - Yellow: reserved
- * - White: all clear / default
- * - * @return the Color which belong with the current Block State - */ -// Color getBlockStateColor() { -// return getBlockStateColor(this.model.getBlockState()); -// } -// protected Color getBlockStateColor(BlockState blockState) { -// return switch (blockState) { -// case GHOST -> -// new Color(250, 0, 0); -// case LOCKED -> -// new Color(250, 250, 210); -// case OCCUPIED -> -// new Color(250, 210, 210); -// case OUT_OF_ORDER -> -// new Color(190, 190, 190); -// case OUTBOUND -> -// new Color(210, 250, 210); -// case INBOUND -> -// new Color(250, 210, 250); -// default -> -// new Color(255, 255, 255); -// }; -// } public static String getDepartureSuffix(Orientation tileOrientation, boolean reverseArrival, LocomotiveBean.Direction direction) { if (LocomotiveBean.Direction.FORWARDS == direction) { if (Orientation.EAST == tileOrientation || Orientation.SOUTH == tileOrientation) { @@ -400,338 +357,6 @@ public static String getDepartureSuffix(Orientation tileOrientation, boolean rev } } -// @Override -// public void renderTile(Graphics2D g2) { -// int xx = 20; -// int yy = 50; -// int rw = RENDER_WIDTH * 3 - 40; -// int rh = 300; -// -// g2.setStroke(new BasicStroke(3, BasicStroke.CAP_SQUARE, BasicStroke.JOIN_ROUND)); -// -// g2.setPaint(Color.darkGray); -// g2.drawRoundRect(xx, yy, rw, rh, 15, 15); -// -// Color blockStateColor = getBlockStateColor(); -// //Logger.trace("Block " + this.id + " State: " + this.getBlockBean().getBlockState().getState() + " Color: " + blockStateColor.toString()); -// g2.setPaint(blockStateColor); -// g2.fillRoundRect(xx, yy, rw, rh, 15, 15); -// -// g2.setStroke(new BasicStroke(20, BasicStroke.CAP_SQUARE, BasicStroke.JOIN_ROUND)); -// g2.setPaint(Color.darkGray); -// g2.drawLine(rw + GRID, yy - 0, rw + GRID, yy + 300); -// -// //When there is a locomotive in the block mark the direction of travel. -// //The default, forwards is in the direction of the block orientation, i.e. the + -// if (model.getLocomotive() != null && model.getLocomotive().getName() != null) { -// renderDirectionArrow(g2); -// } -// -// drawName(g2); -// } -// private void renderDirectionArrow(Graphics2D g2) { -// //The default, forwards is in the direction of the block orientation, i.e. the + -// Orientation tileOrientation = model.getTileOrienation(); -// BlockBean bb = this.getBlockBean(); -// boolean reverseArrival = model.isReverseArrival(); -// -// LocomotiveBean.Direction logicalDirection; -// if (bb.getLogicalDirection() != null) { -// logicalDirection = model.getLogicalDirection(); -// } else { -// logicalDirection = model.getLocomotive().getDirection(); -// } -// -// String departureSuffix = model.getDepartureSuffix(); -// if (departureSuffix == null) { -// departureSuffix = Block.getDepartureSuffix(tileOrientation, reverseArrival, logicalDirection); -// } -// -// //Logger.trace(this.getId()+" LogicalDirection is " + (bb.getLogicalDirection() != null ? "Set" : "Not Set") + " Dir: " + logicalDirection.getDirection() + " Orientation: " + orientation.getOrientation() + " departureSuffix: " + departureSuffix); -// if ("+".equals(departureSuffix)) { -// if (Orientation.EAST == tileOrientation || Orientation.SOUTH == tileOrientation) { -// switch (logicalDirection) { -// case LocomotiveBean.Direction.FORWARDS -> { -// if (reverseArrival) { -// renderLeftArrow(g2); -// } else { -// renderRightArrow(g2); -// } -// } -// case LocomotiveBean.Direction.BACKWARDS -> { -// if (reverseArrival) { -// renderRightArrow(g2); -// } else { -// renderLeftArrow(g2); -// } -// } -// } -// } else { -// switch (logicalDirection) { -// case LocomotiveBean.Direction.BACKWARDS -> { -// if (reverseArrival) { -// renderLeftArrow(g2); -// } else { -// renderRightArrow(g2); -// } -// } -// case LocomotiveBean.Direction.FORWARDS -> { -// if (reverseArrival) { -// renderRightArrow(g2); -// } else { -// renderLeftArrow(g2); -// } -// } -// } -// } -// } else { -// if (Orientation.EAST == tileOrientation || Orientation.SOUTH == tileOrientation) { -// switch (logicalDirection) { -// case LocomotiveBean.Direction.FORWARDS -> { -// if (reverseArrival) { -// renderLeftArrow(g2); -// } else { -// renderRightArrow(g2); -// } -// } -// case LocomotiveBean.Direction.BACKWARDS -> { -// if (reverseArrival) { -// renderRightArrow(g2); -// } else { -// renderLeftArrow(g2); -// } -// } -// } -// } else { -// switch (logicalDirection) { -// case LocomotiveBean.Direction.BACKWARDS -> { -// if (reverseArrival) { -// renderLeftArrow(g2); -// } else { -// renderRightArrow(g2); -// } -// } -// case LocomotiveBean.Direction.FORWARDS -> { -// if (reverseArrival) { -// renderRightArrow(g2); -// } else { -// renderLeftArrow(g2); -// } -// } -// } -// } -// } -// } -// private void renderLeftArrow(Graphics2D g2) { -// //Logger.trace(this.getId()+" LogicalDirection is " + this.getBlockBean().getLogicalDirection() + " Orientation: " + this.getOrientation() + " departureSuffix: " + this.getBlockBean().getDepartureSuffix()); -// g2.fillPolygon(new int[]{0, 50, 50,}, new int[]{200, 150, 250}, 3); -// } -// private void renderRightArrow(Graphics2D g2) { -// //Logger.trace(this.getId()+" LogicalDirection is " + this.getBlockBean().getLogicalDirection() + " Orientation: " + this.getOrientation() + " departureSuffix: " + this.getBlockBean().getDepartureSuffix()); -// g2.fillPolygon(new int[]{1180, 1130, 1130,}, new int[]{200, 150, 250}, 3); -// } -// @Override -// public void renderTileRoute(Graphics2D g2d) { -// if (model.isShowBlockState()) { -// backgroundColor = getBlockStateColor(model.getBlockState()); -// } -// } -// protected void overlayLocImage() { -// int ww = tileImage.getWidth(); -// int hh = tileImage.getHeight(); -// Orientation tileOrientation = model.getTileOrienation(); -// -// BufferedImage overlay = new BufferedImage(ww, hh, BufferedImage.TYPE_INT_ARGB); -// Graphics2D g2i = overlay.createGraphics(); -// -// Image locImage = getLocImage(); -// if (locImage != null) { -// String departureSuffix = model.getDepartureSuffix(); -// boolean reverseImage = model.isReverseArrival(); -// -// Logger.trace("LocImage w: " + locImage.getWidth(null) + " h: " + locImage.getHeight(null)); -// // scale it to max h of 45 -// int size = 45; -// float aspect = (float) locImage.getHeight(null) / (float) locImage.getWidth(null); -// //TODO: Use Scalr? -// locImage = locImage.getScaledInstance(size, (int) (size * aspect), Image.SCALE_SMOOTH); -// -// //Depending on the block orientation the image needs to be rotated and flipped -// //Incase the departure suffix is NOT set center the locomotive image -// int w, h, xx, yy; -// switch (tileOrientation) { -// case WEST -> { -// w = locImage.getWidth(null); -// h = locImage.getHeight(null); -// -// if (null == departureSuffix) { -// xx = BLOCK_WIDTH / 2 - getWidth() / 2 + w; -// } else { -// switch (departureSuffix) { -// case "+" -> { -// xx = BLOCK_WIDTH / 2 - getWidth() / 2 + w - 25; -// } -// default -> { -// xx = BLOCK_WIDTH / 2 - getWidth() / 2 + w + 10; -// } -// } -// } -// yy = DEFAULT_HEIGHT / 2 - h / 2; -// -// if (reverseImage) { -// locImage = ImageUtil.flipVertically(locImage); -// } -// } -// case SOUTH -> { -// locImage = ImageUtil.flipHorizontally(locImage); -// locImage = ImageUtil.rotate(locImage, 90); -// -// w = locImage.getWidth(null); -// h = locImage.getHeight(null); -// xx = DEFAULT_WIDTH / 2 - w / 2; -// -// if (null == departureSuffix) { -// yy = BLOCK_HEIGHT / 2 - getHeight() / 2 + h; -// } else { -// switch (departureSuffix) { -// case "-" -> { -// yy = BLOCK_HEIGHT / 2 - getHeight() / 2 + h - 25; -// } -// default -> { -// yy = BLOCK_HEIGHT / 2 - getHeight() / 2 + h + 10; -// } -// } -// } -// if (reverseImage) { -// locImage = ImageUtil.flipHorizontally(locImage); -// } -// } -// case NORTH -> { -// locImage = ImageUtil.flipHorizontally(locImage); -// locImage = ImageUtil.rotate(locImage, 90); -// -// w = locImage.getWidth(null); -// h = locImage.getHeight(null); -// xx = DEFAULT_WIDTH / 2 - w / 2; -// -// if (null == departureSuffix) { -// int minY = BLOCK_HEIGHT / 2 - getHeight() / 2 + h; -// yy = minY; -// } else { -// switch (departureSuffix) { -// case "+" -> { -// yy = BLOCK_HEIGHT / 2 - getHeight() / 2 + h - 25; -// } -// default -> { -// yy = BLOCK_HEIGHT / 2 - getHeight() / 2 + h + 10; -// } -// } -// } -// if (reverseImage) { -// locImage = ImageUtil.flipHorizontally(locImage); -// } -// } -// default -> { -// w = locImage.getWidth(null); -// h = locImage.getHeight(null); -// if (null == departureSuffix) { -// xx = BLOCK_WIDTH / 2 - getWidth() / 2 + w; -// } else { -// switch (departureSuffix) { -// case "-" -> { -// xx = BLOCK_WIDTH / 2 - getWidth() / 2 + w - 25; -// } -// default -> { -// xx = BLOCK_WIDTH / 2 - getWidth() / 2 + w + 10; -// } -// } -// } -// yy = DEFAULT_HEIGHT / 2 - h / 2; -// -// if (reverseImage) { -// locImage = ImageUtil.flipVertically(locImage); -// } -// } -// } -// -// g2i.drawImage(tileImage, 0, 0, null); -// g2i.drawImage(locImage, xx, yy, null); -// g2i.dispose(); -// tileImage = overlay; -// } -// } -// private Image getLocImage() { -// if (model.getLocomotive() != null && model.getLocomotive().getLocIcon() != null) { -// return model.getLocomotive().getLocIcon(); -// } else { -// return null; -// } -// } -// public String getBlockText() { -// String blockText; -// if (blockBean != null && blockBean.getDescription() != null) { -// if (blockBean.getLocomotive() != null && blockBean.getLocomotive().getName() != null && BlockState.GHOST != blockBean.getBlockState()) { -// blockText = blockBean.getLocomotive().getName(); -// } else { -// if (blockBean.getDescription().length() > 0) { -// blockText = blockBean.getDescription(); -// } else { -// blockText = getId(); -// } -// } -// } else { -// // Design mode show description when available -// if (blockBean != null && blockBean.getDescription() != null && blockBean.getDescription().length() > 0) { -// blockText = blockBean.getDescription(); -// } else { -// blockText = getId(); -// } -// } -// return blockText; -// } -// @Override -// public void drawName(Graphics2D g2d) { -// if (!model.isOverlayImage()) { -// g2d.setPaint(Color.black); -// -// Font currentFont = g2d.getFont(); -// Font newFont = currentFont.deriveFont(currentFont.getSize() * 10.0F); -// g2d.setFont(newFont); -// -// String blockText = getBlockText(); -// -// // Scale the text if necessary -// int textWidth = g2d.getFontMetrics().stringWidth(blockText); -// double fontscale = 10.0; -// if (textWidth > 845) { -// fontscale = fontscale * 847.0 / textWidth; -// newFont = currentFont.deriveFont(currentFont.getSize() * (float) fontscale); -// g2d.setFont(newFont); -// textWidth = g2d.getFontMetrics().stringWidth(blockText); -// } -// -// int textHeight = g2d.getFontMetrics().getHeight(); -// Orientation tileOrientation = model.getTileOrienation(); -// -// switch (tileOrientation) { -// case EAST -> { -// drawRotate(g2d, ((RENDER_WIDTH * 3) / 2) - textWidth / 2, RENDER_GRID + textHeight / 3, 0, blockText); -// } -// case WEST -> { -// drawRotate(g2d, ((RENDER_WIDTH * 3) / 2) + textWidth / 2, RENDER_GRID - textHeight / 3, 180, blockText); -// } -// case NORTH -> { -// drawRotate(g2d, ((RENDER_WIDTH * 3) / 2) - textWidth / 2, RENDER_GRID + textHeight / 3, 0, blockText); -// } -// case SOUTH -> { -// drawRotate(g2d, ((RENDER_WIDTH * 3) / 2) + textWidth / 2, RENDER_GRID - textHeight / 3, 180, blockText); -// } -// } -// // reset to the original font -// newFont = currentFont.deriveFont(currentFont.getSize() * 1.0F); -// g2d.setFont(newFont); -// } -// } @Override public Rectangle getTileBounds() { int multiplier = (model.isScaleImage() ? 1 : 10); @@ -756,49 +381,4 @@ public Rectangle getTileBounds() { } } -// @Override -// protected void paintComponent(Graphics g) { -// long started = System.currentTimeMillis(); -// -// Graphics2D g2 = (Graphics2D) g.create(); -// drawTile(g2); -// g2.dispose(); -// -// if (model.isOverlayImage()) { -// overlayLocImage(); -// } -// -// g.drawImage(tileImage, 0, 0, null); -// long now = System.currentTimeMillis(); -// Logger.trace(id + " Duration: " + (now - started) + " ms."); -// } -// @Override -// protected void drawCenterPoint(Graphics2D g2d, Color color, double size) { -// //A block has 2 alternate points -// //1st square -// //2nd square holds the centerpoint -// //3rd square -// Orientation tileOrientation = model.getTileOrienation(); -// double dX1, dX2, dX3, dY1, dY2, dY3; -// if (Orientation.EAST == tileOrientation || Orientation.WEST == tileOrientation) { -// dX1 = renderWidth / 3 / 2 - size / 2 / 2; -// dY1 = renderHeight / 2 - size / 2 / 2; -// dX2 = renderWidth / 2 - size / 2; -// dY2 = renderHeight / 2 - size / 2; -// dX3 = renderWidth - renderWidth / 3 / 2 - size / 2 / 2; -// dY3 = renderHeight / 2 - size / 2 / 2; -// } else { -// dX1 = renderWidth / 2 - size / 2 / 2; -// dY1 = renderHeight / 3 / 2 - size / 2 / 2; -// dX2 = renderHeight / 2 - size / 2; -// dY2 = renderWidth / 2 - size / 2; -// dY3 = renderWidth / 2 - size / 2 / 2; -// dX3 = renderHeight - renderHeight / 3 / 2 - size / 2 / 2; -// } -// -// g2d.setColor(color); -// g2d.fill(new Ellipse2D.Double(dX1, dY1, size / 2, size / 2)); -// g2d.fill(new Ellipse2D.Double(dX2, dY2, size, size)); -// g2d.fill(new Ellipse2D.Double(dX3, dY3, size / 2, size / 2)); -// } } diff --git a/src/main/java/jcs/ui/layout/tiles/Cross.java b/src/main/java/jcs/ui/layout/tiles/Cross.java index 33b902f0..4fa88889 100644 --- a/src/main/java/jcs/ui/layout/tiles/Cross.java +++ b/src/main/java/jcs/ui/layout/tiles/Cross.java @@ -40,6 +40,9 @@ import jcs.ui.layout.tiles.ui.CrossUI; import jcs.ui.layout.tiles.ui.TileUI; +/** + * Representation of a Cross switch on the layout + */ public class Cross extends Switch { public static final int CROSS_WIDTH = DEFAULT_WIDTH * 2; @@ -254,223 +257,6 @@ public Map getEdgePoints() { return edgeConnections; } -// @Override -// protected void renderStraight(Graphics2D g2, Color color) { -// int xx, yy, w, h; -// xx = 0; -// yy = 170; -// w = RENDER_WIDTH; -// h = 60; -// -// g2.setStroke(new BasicStroke(4, BasicStroke.JOIN_MITER, BasicStroke.JOIN_ROUND)); -// g2.setPaint(color); -// g2.fillRect(xx, yy, w, h); -// } -// @Override -// protected void renderRouteStraight(Graphics2D g2, Color color) { -// int xx, yy, w, h; -// xx = 0; -// yy = 190; -// w = RENDER_WIDTH; -// h = 20; -// -// g2.setStroke(new BasicStroke(4, BasicStroke.JOIN_MITER, BasicStroke.JOIN_ROUND)); -// g2.setPaint(color); -// g2.fillRect(xx, yy, w, h); -// } -// protected void renderStraight2(Graphics2D g2, Color color) { -// int xx, yy, w, h; -// xx = RENDER_WIDTH; -// yy = 170; -// w = RENDER_WIDTH; -// h = 60; -// -// g2.setStroke(new BasicStroke(4, BasicStroke.JOIN_MITER, BasicStroke.JOIN_ROUND)); -// g2.setPaint(color); -// g2.fillRect(xx, yy, w, h); -// } -// protected void renderRouteStraight2(Graphics2D g2, Color color) { -// int xx, yy, w, h; -// xx = RENDER_WIDTH; -// yy = 190; -// w = RENDER_WIDTH; -// h = 20; -// -// g2.setStroke(new BasicStroke(4, BasicStroke.JOIN_MITER, BasicStroke.JOIN_ROUND)); -// g2.setPaint(color); -// g2.fillRect(xx, yy, w, h); -// } -// @Override -// protected void renderDiagonal(Graphics2D g2, Color color) { -// int[] xPoints, yPoints; -// if (Direction.RIGHT.equals(getDirection())) { -// xPoints = new int[]{400, 400, 167, 230}; -// yPoints = new int[]{170, 230, 0, 0}; -// } else { -// xPoints = new int[]{400, 400, 170, 230}; -// yPoints = new int[]{230, 170, 400, 400}; -// } -// -// g2.setStroke(new BasicStroke(4, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND)); -// g2.setPaint(color); -// g2.fillPolygon(xPoints, yPoints, xPoints.length); -// } -// @Override -// protected void renderRouteDiagonal(Graphics2D g2, Color color) { -// int[] xPoints, yPoints; -// if (Direction.RIGHT.equals(getDirection())) { -// xPoints = new int[]{420, 400, 190, 210}; -// yPoints = new int[]{210, 210, 0, 0}; -// } else { -// xPoints = new int[]{400, 400, 190, 210}; -// yPoints = new int[]{210, 190, 400, 400}; -// } -// -// g2.setStroke(new BasicStroke(4, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND)); -// g2.setPaint(color); -// g2.fillPolygon(xPoints, yPoints, xPoints.length); -// } -// protected void renderDiagonal2(Graphics2D g2, Color color) { -// int[] xPoints, yPoints; -// if (Direction.RIGHT.equals(getDirection())) { -// xPoints = new int[]{400, 400, 570, 630}; -// yPoints = new int[]{170, 230, 400, 400}; -// } else { -// xPoints = new int[]{400, 400, 570, 630}; -// yPoints = new int[]{230, 170, 0, 0}; -// } -// -// g2.setStroke(new BasicStroke(4, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND)); -// g2.setPaint(color); -// g2.fillPolygon(xPoints, yPoints, xPoints.length); -// } -// protected void renderRouteDiagonal2(Graphics2D g2, Color color) { -// int[] xPoints, yPoints; -// if (Direction.RIGHT.equals(getDirection())) { -// xPoints = new int[]{400, 380, 590, 610}; -// yPoints = new int[]{190, 190, 400, 400}; -// } else { -// xPoints = new int[]{400, 380, 590, 610}; -// yPoints = new int[]{210, 210, 0, 0}; -// } -// -// g2.setStroke(new BasicStroke(4, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND)); -// g2.setPaint(color); -// g2.setPaint(Color.cyan); -// g2.fillPolygon(xPoints, yPoints, xPoints.length); -// } -// @Override -// public void renderTile(Graphics2D g2) { -// if (accessoryValue == null) { -// this.accessoryValue = AccessoryValue.OFF; -// } -// -// switch (accessoryValue) { -// case RED -> { -// renderStraight2(g2, Cross.LIGHT_RED); -// renderDiagonal(g2, Cross.LIGHT_RED); -// renderStraight(g2, Cross.DARK_RED); -// renderDiagonal2(g2, Cross.DARK_RED); -// } -// case GREEN -> { -// renderDiagonal(g2, Cross.VERY_LIGHT_GREEN); -// renderDiagonal2(g2, Cross.VERY_LIGHT_GREEN); -// renderStraight(g2, Cross.DARK_GREEN); -// renderStraight2(g2, Cross.DARK_GREEN); -// } -// default -> { -// renderStraight(g2, trackColor); -// renderStraight2(g2, trackColor); -// renderDiagonal(g2, trackColor); -// renderDiagonal2(g2, trackColor); -// } -// } -// } -// @Override -// public void renderTileRoute(Graphics2D g2) { -// if (routeValue == null) { -// routeValue = AccessoryValue.OFF; -// } -// if (model.getIncomingSide() == null) { -// model.setIncomingSide(model.getTileOrienation()); -// } -// -// Orientation incomingSide = model.getIncomingSide(); -// -// if (isHorizontal()) { -// if (AccessoryValue.GREEN == routeValue && (Orientation.NORTH == incomingSide || Orientation.SOUTH == incomingSide)) { -// renderRouteDiagonal(g2, trackRouteColor); -// renderRouteDiagonal2(g2, trackRouteColor); -// } else if (AccessoryValue.GREEN == routeValue && (Orientation.EAST == incomingSide || Orientation.WEST == incomingSide)) { -// renderRouteStraight(g2, trackRouteColor); -// renderRouteStraight2(g2, trackRouteColor); -// } else if (AccessoryValue.RED == routeValue && Orientation.EAST == getOrientation()) { -// if (Direction.RIGHT == getDirection() && (Orientation.EAST == incomingSide || Orientation.NORTH == incomingSide)) { -// renderRouteStraight2(g2, trackRouteColor); -// renderRouteDiagonal(g2, trackRouteColor); -// } else if (Direction.RIGHT == getDirection() && (Orientation.WEST == incomingSide || Orientation.SOUTH == incomingSide)) { -// renderRouteDiagonal2(g2, trackRouteColor); -// renderRouteStraight(g2, trackRouteColor); -// } else if (Direction.LEFT == getDirection() && (Orientation.EAST == incomingSide || Orientation.SOUTH == incomingSide)) { -// renderRouteStraight2(g2, trackRouteColor); -// renderRouteDiagonal(g2, trackRouteColor); -// } else if (Direction.LEFT == getDirection() && (Orientation.WEST == incomingSide || Orientation.NORTH == incomingSide)) { -// renderRouteStraight(g2, trackColor); -// renderRouteDiagonal2(g2, trackColor); -// } -// } else if (AccessoryValue.RED == routeValue && Orientation.WEST == getOrientation()) { -// if (Direction.RIGHT == getDirection() && (Orientation.EAST == incomingSide || Orientation.NORTH == incomingSide)) { -// renderRouteStraight(g2, trackRouteColor); -// renderRouteDiagonal2(g2, trackRouteColor); -// } else if (Direction.RIGHT == getDirection() && (Orientation.WEST == incomingSide || Orientation.SOUTH == incomingSide)) { -// renderRouteDiagonal(g2, trackRouteColor); -// renderRouteStraight2(g2, trackRouteColor); -// } else if (Direction.LEFT == getDirection() && (Orientation.EAST == incomingSide || Orientation.SOUTH == incomingSide)) { -// renderRouteStraight(g2, trackRouteColor); -// renderRouteDiagonal2(g2, trackRouteColor); -// } else if (Direction.LEFT == getDirection() && (Orientation.WEST == incomingSide || Orientation.NORTH == incomingSide)) { -// renderRouteStraight2(g2, trackColor); -// renderRouteDiagonal(g2, trackColor); -// } -// } -// } else { -// if (AccessoryValue.GREEN == routeValue && (Orientation.NORTH == incomingSide || Orientation.SOUTH == incomingSide)) { -// renderRouteStraight(g2, trackRouteColor); -// renderRouteStraight2(g2, trackRouteColor); -// } else if (AccessoryValue.GREEN == routeValue && (Orientation.EAST == incomingSide || Orientation.WEST == incomingSide)) { -// renderRouteDiagonal(g2, trackRouteColor); -// renderRouteDiagonal2(g2, trackRouteColor); -// } else if (AccessoryValue.RED == routeValue && Orientation.SOUTH == getOrientation()) { -// if (Direction.RIGHT == getDirection() && (Orientation.EAST == incomingSide || Orientation.SOUTH == incomingSide)) { -// renderRouteStraight2(g2, trackRouteColor); -// renderRouteDiagonal(g2, trackRouteColor); -// } else if (Direction.RIGHT == getDirection() && (Orientation.WEST == incomingSide || Orientation.NORTH == incomingSide)) { -// renderRouteDiagonal2(g2, trackRouteColor); -// renderRouteStraight(g2, trackRouteColor); -// } else if (Direction.LEFT == getDirection() && (Orientation.EAST == incomingSide || Orientation.NORTH == incomingSide)) { -// renderRouteStraight(g2, trackRouteColor); -// renderRouteDiagonal2(g2, trackRouteColor); -// } else if (Direction.LEFT == getDirection() && (Orientation.WEST == incomingSide || Orientation.SOUTH == incomingSide)) { -// renderRouteStraight2(g2, trackColor); -// renderRouteDiagonal(g2, trackColor); -// } -// } else if (AccessoryValue.RED == routeValue && Orientation.NORTH == getOrientation()) { -// if (Direction.RIGHT == getDirection() && (Orientation.EAST == incomingSide || Orientation.SOUTH == incomingSide)) { -// renderRouteStraight(g2, trackRouteColor); -// renderRouteDiagonal2(g2, trackRouteColor); -// } else if (Direction.RIGHT == getDirection() && (Orientation.WEST == incomingSide || Orientation.NORTH == incomingSide)) { -// renderRouteDiagonal(g2, trackRouteColor); -// renderRouteStraight2(g2, trackRouteColor); -// } else if (Direction.LEFT == getDirection() && (Orientation.EAST == incomingSide || Orientation.NORTH == incomingSide)) { -// renderRouteStraight2(g2, trackRouteColor); -// renderRouteDiagonal(g2, trackRouteColor); -// } else if (Direction.LEFT == getDirection() && (Orientation.WEST == incomingSide || Orientation.SOUTH == incomingSide)) { -// renderRouteStraight(g2, trackColor); -// renderRouteDiagonal2(g2, trackColor); -// } -// } -// } -// } @Override public AccessoryValue accessoryValueForRoute(Orientation from, Orientation to) { if (from != null && to != null && this.getDirection() != null) { @@ -540,45 +326,6 @@ public AccessoryValue accessoryValueForRoute(Orientation from, Orientation to) { } } -// @Override -// protected void drawCenterPoint(Graphics2D g2d, Color color, double size) { -// //A Cross has 1 alternate point -// //1st square holds the centerpoint -// //2nd square -// double dX1, dX2, dY1, dY2; -// Orientation tileOrientation = model.getTileOrienation(); -// switch (tileOrientation) { -// case SOUTH -> { -// dX1 = renderWidth / 2 - size / 2; -// dY1 = renderHeight / 2 - renderHeight / 4 - size / 2; -// dX2 = renderWidth / 2 + renderWidth - size / 4; -// dY2 = renderHeight / 2 - renderHeight / 4 - size / 4; -// } -// case WEST -> { -// dX1 = renderWidth / 2 - renderWidth / 4 - size / 2; -// dY1 = renderHeight / 2 - size / 2; -// dX2 = renderWidth / 2 + renderWidth / 4 - size / 4; -// dY2 = renderHeight / 2 - size / 4; -// } -// case NORTH -> { -// dX1 = renderWidth / 2 - size / 2; -// dY1 = renderHeight / 2 - renderHeight / 4 - size / 2; -// dX2 = renderWidth / 2 + renderWidth - size / 4; -// dY2 = renderHeight / 2 - renderHeight / 4 - size / 4; -// } -// default -> { -// //East -// dX1 = renderWidth / 2 - renderWidth / 4 - size / 2; -// dY1 = renderHeight / 2 - size / 2; -// dX2 = renderWidth / 2 + renderWidth / 4 - size / 4; -// dY2 = renderHeight / 2 - size / 4; -// } -// } -// -// g2d.setColor(color); -// g2d.fill(new Ellipse2D.Double(dX1, dY1, size, size)); -// g2d.fill(new Ellipse2D.Double(dX2, dY2, size / 2, size / 2)); -// } @Override public Rectangle getTileBounds() { Orientation tileOrientation = model.getTileOrienation(); @@ -627,54 +374,13 @@ public Rectangle getTileBounds() { } private void changeRenderSizeAndOffsets() { - -// if (getUI() instanceof CrossUI cui) { -// -// cui.changeRenderSize(this); -// } else { -// Logger.warn("UI is a "+getUI().getClass().getSimpleName()); -// } - //Reset offsets -// this.offsetY = 0; this.renderOffsetY = 0; -// this.offsetX = 0; this.renderOffsetX = 0; if (isHorizontal()) { - //this.renderWidth = RENDER_GRID * 4; - //this.renderHeight = RENDER_GRID * 2; - -// this.offsetY = 0; this.renderOffsetY = 0; } else { - //this.renderWidth = RENDER_GRID * 2; - //this.renderHeight = RENDER_GRID * 4; - - /// this.offsetX = 0; this.renderOffsetX = 0; } - - //Due to the asymetical shape (center is on the left) - //the offset has to be changed with the rotation -// Orientation tileOrientation = model.getTileOrienation(); -// switch (tileOrientation) { -// case SOUTH -> { -// this.offsetY = +GRID; -// this.renderOffsetY = RENDER_GRID; -// } -// case WEST -> { -// this.offsetX = -GRID; -// this.renderOffsetX = -RENDER_GRID; -// } -// case NORTH -> { -// this.offsetY = -GRID; -// this.renderOffsetY = -RENDER_GRID; -// } -// default -> { -// //East so default -// this.offsetX = +GRID; -// this.renderOffsetX = +RENDER_GRID; -// } -// } } @Override diff --git a/src/main/java/jcs/ui/layout/tiles/Crossing.java b/src/main/java/jcs/ui/layout/tiles/Crossing.java index f9f7cc97..1a00e86f 100644 --- a/src/main/java/jcs/ui/layout/tiles/Crossing.java +++ b/src/main/java/jcs/ui/layout/tiles/Crossing.java @@ -25,6 +25,9 @@ import jcs.ui.layout.tiles.ui.CrossingUI; import jcs.ui.layout.tiles.ui.TileUI; +/** + * Representation of a (passive) Crossing the layout + */ public class Crossing extends Straight { public Crossing(TileBean tileBean) { diff --git a/src/main/java/jcs/ui/layout/tiles/Curved.java b/src/main/java/jcs/ui/layout/tiles/Curved.java index d52281e4..124f4a44 100755 --- a/src/main/java/jcs/ui/layout/tiles/Curved.java +++ b/src/main/java/jcs/ui/layout/tiles/Curved.java @@ -28,6 +28,9 @@ import jcs.ui.layout.tiles.ui.CurvedUI; import jcs.ui.layout.tiles.ui.TileUI; +/** + * Representation of a Curved track on the layout + */ public class Curved extends Tile { public Curved(TileBean tileBean) { diff --git a/src/main/java/jcs/ui/layout/tiles/End.java b/src/main/java/jcs/ui/layout/tiles/End.java index 38b2383f..a1c5e6aa 100644 --- a/src/main/java/jcs/ui/layout/tiles/End.java +++ b/src/main/java/jcs/ui/layout/tiles/End.java @@ -28,6 +28,9 @@ import jcs.ui.layout.tiles.ui.EndUI; import jcs.ui.layout.tiles.ui.TileUI; +/** + * Representation of a End track on the layout + */ public class End extends Tile { public End(TileBean tileBean) { diff --git a/src/main/java/jcs/ui/layout/tiles/Sensor.java b/src/main/java/jcs/ui/layout/tiles/Sensor.java index 3b0bcd7d..25ecf42b 100644 --- a/src/main/java/jcs/ui/layout/tiles/Sensor.java +++ b/src/main/java/jcs/ui/layout/tiles/Sensor.java @@ -26,6 +26,9 @@ import jcs.ui.layout.tiles.ui.SensorUI; import jcs.ui.layout.tiles.ui.TileUI; +/** + * Representation of a Sensor in a track on the layout + */ public class Sensor extends Straight implements SensorEventListener { public Sensor(TileBean tileBean) { diff --git a/src/main/java/jcs/ui/layout/tiles/Signal.java b/src/main/java/jcs/ui/layout/tiles/Signal.java index 982b666d..25765a26 100644 --- a/src/main/java/jcs/ui/layout/tiles/Signal.java +++ b/src/main/java/jcs/ui/layout/tiles/Signal.java @@ -27,6 +27,9 @@ import jcs.ui.layout.tiles.ui.SignalUI; import jcs.ui.layout.tiles.ui.TileUI; +/** + * Representation of a Signal besides the track on the layout + */ public class Signal extends Straight implements AccessoryEventListener { Signal(TileBean tileBean) { @@ -60,278 +63,6 @@ public void updateUI() { invalidate(); } -// /** -// * Render a Signal with 2 lights -// * -// * @param g2d the graphics context -// */ -// protected void renderSignal2(Graphics2D g2d) { -// int rx = RENDER_GRID; -// int ry = RENDER_GRID + 60; -// int rw = 180; -// int rh = 100; -// int l1x = RENDER_GRID + 20; -// int l1y = RENDER_GRID + 80; -// int l2x = RENDER_GRID + 100; -// int l2y = RENDER_GRID + 80; -// -// Color color1 = Color.gray; -// Color color2 = Color.gray; -// -// if (this.signalValue == null) { -// this.signalValue = SignalValue.OFF; -// } -// -// switch (signalValue) { -// case Hp0 -> { -// color1 = Color.red; -// color2 = Color.gray; -// } -// case Hp1 -> { -// color1 = Color.gray; -// color2 = Color.green; -// } -// default -> { -// } -// } -// -// g2d.setStroke(new BasicStroke(10f)); -// g2d.setPaint(Color.darkGray); -// g2d.fillRoundRect(rx, ry, rw, rh, 30, 30); -// -// g2d.setPaint(color1); -// g2d.fillOval(l1x, l1y, 60, 60); -// g2d.setPaint(color2); -// g2d.fillOval(l2x, l2y, 60, 60); -// } -// protected void renderSignal3(Graphics2D g2d) { -// int rx = RENDER_GRID; -// int ry = RENDER_GRID + 60; -// int rw = 180; -// int rh = 100; -// -// int c1x = RENDER_GRID + 130; -// int c1y = RENDER_GRID + 115; -// -// int c2x = RENDER_GRID + 10; -// int c2y = RENDER_GRID + 115; -// -// int c3x = RENDER_GRID + 10; -// int c3y = RENDER_GRID + 65; -// -// // Initialize all "lights" -// Color color1 = Color.gray; -// Color color2 = Color.gray; -// Color color3 = Color.gray; -// -// if (this.signalValue == null) { -// this.signalValue = SignalValue.OFF; -// } -// -// switch (this.signalValue) { -// case Hp0 -> { -// color3 = Color.red; -// } -// case Hp1 -> -// color1 = Color.green; -// case Hp2 -> { -// color1 = Color.green; -// color2 = Color.yellow; -// } -// default -> { -// } -// } -// -// g2d.setStroke(new BasicStroke(10f)); -// g2d.setPaint(Color.darkGray); -// g2d.fillRoundRect(rx, ry, rw, rh, 30, 30); -// -// g2d.setPaint(color1); -// g2d.fillOval(c1x, c1y, 40, 40); -// -// g2d.setPaint(color2); -// g2d.fillOval(c2x, c2y, 40, 40); -// -// g2d.setPaint(color3); -// g2d.fillOval(c3x, c3y, 40, 40); -// } -// /** -// * Render a entry Signal which can show 4 light images -// * -// * @param g2d the Graphics context -// */ -// protected void renderSignal4(Graphics2D g2d) { -// int rx = RENDER_GRID - 50; -// int ry = RENDER_GRID + 50; -// int rw = 240; -// int rh = 120; -// int c1x = RENDER_GRID + 140; -// int c1y = RENDER_GRID + 60; -// -// int c2x = RENDER_GRID + 90; -// int c2y = RENDER_GRID + 60; -// -// int c3x = RENDER_GRID + 90; -// int c3y = RENDER_GRID + 120; -// -// int c4x = RENDER_GRID + 60; -// int c4y = RENDER_GRID + 130; -// -// int c5x = RENDER_GRID + 10; -// int c5y = RENDER_GRID + 70; -// -// int c6x = RENDER_GRID - 40; -// int c6y = RENDER_GRID + 60; -// -// // Initialize all "lights" -// Color color1 = Color.gray; -// Color color2 = Color.gray; -// Color color3 = Color.gray; -// Color color4 = Color.gray; -// Color color5 = Color.gray; -// Color color6 = Color.gray; -// -// if (this.signalValue == null) { -// this.signalValue = SignalValue.OFF; -// } -// -// switch (this.signalValue) { -// case Hp0 -> { -// color2 = Color.red; -// color3 = Color.red; -// } -// case Hp1 -> -// color1 = Color.green; -// case Hp2 -> { -// color1 = Color.green; -// color6 = Color.yellow; -// } -// case Hp0Sh1 -> { -// color2 = Color.red; -// color4 = Color.white; -// color5 = Color.white; -// } -// default -> { -// } -// } -// -// g2d.setStroke(new BasicStroke(10f)); -// g2d.setPaint(Color.darkGray); -// g2d.fillRoundRect(rx, ry, rw, rh, 30, 30); -// -// g2d.setPaint(color1); -// g2d.fillOval(c1x, c1y, 40, 40); -// g2d.setPaint(color2); -// g2d.fillOval(c2x, c2y, 40, 40); -// g2d.setPaint(color3); -// g2d.fillOval(c3x, c3y, 40, 40); -// g2d.setPaint(color4); -// g2d.fillOval(c4x, c4y, 20, 20); -// g2d.setPaint(color5); -// g2d.fillOval(c5x, c5y, 20, 20); -// g2d.setPaint(color6); -// g2d.fillOval(c6x, c6y, 40, 40); -// } -// /** -// * Render a midget Signal -// * -// * @param g2d the Graphics context -// */ -// protected void renderSignal2m(Graphics2D g2d) { -// int[] xps -// = new int[]{ -// RENDER_GRID + 80, -// +RENDER_GRID + 150, -// +RENDER_GRID + 170, -// RENDER_GRID + 170, -// +RENDER_GRID + 150, -// RENDER_GRID + 80 -// }; -// int[] yps -// = new int[]{ -// RENDER_GRID + 60, -// RENDER_GRID + 60, -// RENDER_GRID + 80, -// +RENDER_GRID + 160, -// +RENDER_GRID + 180, -// RENDER_GRID + 180 -// }; -// -// Polygon signalOutline = new Polygon(xps, yps, xps.length); -// -// int c1x = RENDER_GRID + 130; -// int c1y = RENDER_GRID + 70; -// -// int c2x = RENDER_GRID + 130; -// int c2y = RENDER_GRID + 140; -// -// int c3x = RENDER_GRID + 130; -// int c3y = RENDER_GRID + 105; -// -// int c4x = RENDER_GRID + 85; -// int c4y = RENDER_GRID + 70; -// -// Color color1 = Color.gray; -// Color color2 = Color.gray; -// Color color3 = Color.gray; -// Color color4 = Color.gray; -// -// if (this.signalValue == null) { -// this.signalValue = SignalValue.OFF; -// } -// -// switch (this.signalValue) { -// case Hp0 -> { -// color1 = Color.red; -// color2 = Color.red; -// } -// case Hp1 -> { -// color3 = Color.white; -// color4 = Color.white; -// } -// default -> { -// } -// } -// -// g2d.setStroke(new BasicStroke(10f)); -// g2d.setPaint(Color.darkGray); -// -// g2d.fillPolygon(signalOutline); -// -// g2d.setPaint(color1); -// g2d.fillOval(c1x, c1y, 30, 30); -// -// g2d.setPaint(color2); -// g2d.fillOval(c2x, c2y, 30, 30); -// -// g2d.setPaint(color3); -// g2d.fillOval(c3x, c3y, 30, 30); -// -// g2d.setPaint(color4); -// g2d.fillOval(c4x, c4y, 30, 30); -// } -// @Override -// public void renderTile(Graphics2D g2) { -// Graphics2D g2d = (Graphics2D) g2.create(); -// renderStraight(g2d); -// -// if (signalType == null) { -// signalType = SignalType.NONE; -// } -// -// switch (signalType) { -// case HP012 -> -// renderSignal3(g2d); -// case HP012SH1 -> -// renderSignal4(g2d); -// case HP0SH1 -> -// renderSignal2m(g2d); -// default -> -// renderSignal2(g2d); -// } -// -// g2d.dispose(); -// } //TODO move to UI delegate @Override public void onAccessoryChange(AccessoryEvent event) { diff --git a/src/main/java/jcs/ui/layout/tiles/Straight.java b/src/main/java/jcs/ui/layout/tiles/Straight.java index 2160a5f1..437c48ff 100755 --- a/src/main/java/jcs/ui/layout/tiles/Straight.java +++ b/src/main/java/jcs/ui/layout/tiles/Straight.java @@ -25,6 +25,9 @@ import jcs.entities.TileBean.Orientation; import jcs.entities.TileBean.TileType; +/** + * Representation of a Straight track on the layout + */ public class Straight extends Tile { public Straight(TileBean tileBean) { diff --git a/src/main/java/jcs/ui/layout/tiles/StraightDirection.java b/src/main/java/jcs/ui/layout/tiles/StraightDirection.java index df847634..a3ae761c 100644 --- a/src/main/java/jcs/ui/layout/tiles/StraightDirection.java +++ b/src/main/java/jcs/ui/layout/tiles/StraightDirection.java @@ -24,6 +24,9 @@ import jcs.ui.layout.tiles.ui.StraightDirectionUI; import jcs.ui.layout.tiles.ui.TileUI; +/** + * Representation of a Straight track where trans can only run in one direction on the layout + */ public class StraightDirection extends Straight { public StraightDirection(TileBean tileBean) { @@ -74,19 +77,4 @@ public boolean isArrowDirection(Tile other) { } return arrowDirection && isAdjacent(other); } - -// private void renderDirectionArrow(Graphics2D g2) { -// // |\ -// // ==|+=== -// // |/ -// g2.setStroke(new BasicStroke(4, BasicStroke.JOIN_MITER, BasicStroke.JOIN_ROUND)); -// g2.setPaint(Color.green.darker()); -// -// g2.fillPolygon(new int[]{150, 150, 270}, new int[]{130, 270, 200}, 3); -// } -// @Override -// public void renderTile(Graphics2D g2d) { -// renderStraight(g2d); -// renderDirectionArrow(g2d); -// } } diff --git a/src/main/java/jcs/ui/layout/tiles/Switch.java b/src/main/java/jcs/ui/layout/tiles/Switch.java index 933583f8..1ce2f43f 100644 --- a/src/main/java/jcs/ui/layout/tiles/Switch.java +++ b/src/main/java/jcs/ui/layout/tiles/Switch.java @@ -34,6 +34,9 @@ import jcs.ui.layout.tiles.ui.SwitchUI; import jcs.ui.layout.tiles.ui.TileUI; +/** + * Representation of a Switch or Turnout on the layout + */ public class Switch extends Tile implements AccessoryEventListener { public Switch(Orientation orientation, Direction direction, Point center) { @@ -180,96 +183,6 @@ public Map getEdgePoints() { return edgeConnections; } -// protected void renderStraight(Graphics2D g2, Color color) { -// int xx, yy, w, h; -// xx = 0; -// yy = 170; -// w = RENDER_WIDTH; -// h = 60; -// -// g2.setStroke(new BasicStroke(4, BasicStroke.JOIN_MITER, BasicStroke.JOIN_ROUND)); -// g2.setPaint(color); -// -// g2.fillRect(xx, yy, w, h); -// } -// protected void renderDiagonal(Graphics2D g2, Color color) { -// int[] xPoints, yPoints; -// if (Direction.RIGHT.equals(getDirection())) { -// xPoints = new int[]{400, 400, 170, 230}; -// yPoints = new int[]{170, 230, 0, 0}; -// } else { -// xPoints = new int[]{400, 400, 170, 230}; -// yPoints = new int[]{230, 170, 400, 400}; -// } -// -// g2.setStroke(new BasicStroke(1, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND)); -// g2.setPaint(color); -// g2.fillPolygon(xPoints, yPoints, xPoints.length); -// } -// protected void renderRouteStraight(Graphics2D g2, Color color) { -// int xx, yy, w, h; -// xx = 0; -// yy = 190; -// w = RENDER_WIDTH; -// h = 20; -// -// g2.setStroke(new BasicStroke(4, BasicStroke.JOIN_MITER, BasicStroke.JOIN_ROUND)); -// g2.setPaint(color); -// -// g2.fillRect(xx, yy, w, h); -// } -// protected void renderRouteDiagonal(Graphics2D g2, Color color) { -// int[] xPoints, yPoints; -// if (Direction.RIGHT.equals(getDirection())) { -// xPoints = new int[]{400, 400, 190, 210}; -// yPoints = new int[]{190, 210, 0, 0}; -// } else { -// xPoints = new int[]{400, 400, 190, 210}; -// yPoints = new int[]{210, 190, 400, 400}; -// } -// -// g2.setStroke(new BasicStroke(1, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND)); -// g2.setPaint(color); -// -// g2.fillPolygon(xPoints, yPoints, xPoints.length); -// } -// @Override -// public void renderTile(Graphics2D g2) { -// if (accessoryValue == null) { -// this.accessoryValue = AccessoryValue.OFF; -// } -// -// switch (accessoryValue) { -// case RED -> { -// renderStraight(g2, trackColor); -// renderDiagonal(g2, Color.red); -// } -// case GREEN -> { -// renderDiagonal(g2, trackColor); -// renderStraight(g2, Color.green); -// } -// default -> { -// renderStraight(g2, trackColor); -// renderDiagonal(g2, trackColor); -// } -// } -// } -// @Override -// public void renderTileRoute(Graphics2D g2) { -// if (routeValue == null) { -// routeValue = AccessoryValue.OFF; -// } -// switch (routeValue) { -// case RED -> { -// renderRouteDiagonal(g2, trackRouteColor); -// } -// case GREEN -> { -// renderRouteStraight(g2, trackRouteColor); -// } -// default -> { -// } -// } -// } @Override public void onAccessoryChange(AccessoryEvent event) { if (getAccessoryBean() != null && event.isEventFor(accessoryBean)) { diff --git a/src/main/java/jcs/ui/layout/tiles/Tile.java b/src/main/java/jcs/ui/layout/tiles/Tile.java index 688c48f8..e36a3df1 100755 --- a/src/main/java/jcs/ui/layout/tiles/Tile.java +++ b/src/main/java/jcs/ui/layout/tiles/Tile.java @@ -19,7 +19,6 @@ import java.awt.Color; import java.awt.Dimension; import java.awt.Graphics; -import java.awt.Graphics2D; import java.awt.Point; import java.awt.Rectangle; import java.awt.event.ActionEvent; @@ -70,7 +69,9 @@ * Rotation will change the orientation from East -> South -> West -> North -> East.
* *

- * A Tile is rendered to a Buffered Image to speed up the display + * Tile follows the MVC Patten, hence all properties which could change during operation
+ * which have an influence on the screen are in the TileModel.
+ * All Drawing code is in the TileUI. */ public abstract class Tile extends JComponent { // implements ChangeListener @@ -78,9 +79,6 @@ public abstract class Tile extends JComponent { // implements ChangeListener public static final int DEFAULT_WIDTH = GRID * 2; public static final int DEFAULT_HEIGHT = GRID * 2; - //static final int RENDER_GRID = GRID * 10; - //static final int RENDER_WIDTH = RENDER_GRID * 2; - //static final int RENDER_HEIGHT = RENDER_GRID * 2; public static final Color DEFAULT_BACKGROUND_COLOR = Color.white; public static final Color DEFAULT_TRACK_COLOR = Color.lightGray; public static final Color DEFAULT_ROUTE_TRACK_COLOR = Color.darkGray; @@ -91,7 +89,7 @@ public abstract class Tile extends JComponent { // implements ChangeListener // public static final String CONTENT_AREA_FILLED_CHANGED_PROPERTY = "contentAreaFilled"; /** - * The data model that determines the button's state. + * The data model that determines the Tile state. */ protected TileModel model = null; @@ -99,8 +97,6 @@ public abstract class Tile extends JComponent { // implements ChangeListener protected Integer tileX; protected Integer tileY; - //protected int renderWidth; - //protected int renderHeight; protected Direction tileDirection; protected TileType tileType; @@ -120,16 +116,9 @@ public abstract class Tile extends JComponent { // implements ChangeListener protected List neighbours; -// protected int offsetX = 0; -// protected int offsetY = 0; - protected int renderOffsetX = 0; protected int renderOffsetY = 0; - //protected Color trackColor; - //protected Color trackRouteColor; - //protected Orientation incomingSide; - //protected Color backgroundColor; protected boolean drawName = true; protected BufferedImage tileImage; @@ -164,14 +153,6 @@ protected Tile(TileType tileType, Orientation orientation, Direction direction, Dimension d = new Dimension(width, height); setSize(d); setPreferredSize(d); - - //this.renderWidth = RENDER_WIDTH; - //this.renderHeight = RENDER_HEIGHT; - //this.trackColor = DEFAULT_TRACK_COLOR; - //this.backgroundColor = backgroundColor; - //if (this.backgroundColor == null) { - // this.backgroundColor = DEFAULT_BACKGROUND_COLOR; - //} } protected Tile(TileBean tileBean) { @@ -180,7 +161,6 @@ protected Tile(TileBean tileBean) { protected Tile(TileBean tileBean, int width, int height) { this.tileBean = tileBean; - //Quick properties this.id = tileBean.getId(); this.tileType = tileBean.getTileType(); this.tileDirection = tileBean.getDirection(); @@ -199,11 +179,6 @@ protected Tile(TileBean tileBean, int width, int height) { Dimension d = new Dimension(width, height); setSize(d); setPreferredSize(d); - - //this.trackColor = DEFAULT_TRACK_COLOR; - //this.backgroundColor = DEFAULT_BACKGROUND_COLOR; - //this.renderWidth = RENDER_WIDTH; - //this.renderHeight = RENDER_HEIGHT; } @Override @@ -251,19 +226,6 @@ public void setModel(TileModel newModel) { } } -// @Override -// public String getUIClassID() { -// return TileUI.UI_CLASS_ID; -// } -// @Override -// public void updateUI() { -// if (UIManager.get(TileUI.UI_CLASS_ID) == null) { -// UIManager.put(TileUI.UI_CLASS_ID, getUIClassID()); -// } -// -// setUI((TileUI) UIManager.getUI(this)); -// invalidate(); -// } protected static int tileWidth(Orientation orientation, TileType tileType) { if (Orientation.EAST == orientation || Orientation.WEST == orientation) { if (null == tileType) { @@ -318,7 +280,6 @@ public TileBean getTileBean() { tileBean.setX(this.tileX); tileBean.setY(this.tileY); tileBean.setTileType(this.tileType); - //tileBean.setTileOrientation(this.tileOrientation.getOrientation()); tileBean.setTileOrientation(this.model.getTileOrienation().getOrientation()); tileBean.setTileDirection(this.tileDirection.getDirection()); @@ -332,6 +293,10 @@ public TileBean getTileBean() { return tileBean; } + /** + * + * @return true when the Tile is selected in the screen + */ public boolean isSelected() { return model.isSelected(); } @@ -356,14 +321,26 @@ public void setSignalType(SignalType signalType) { this.signalType = signalType; } + /** + * + * @return the Tile X coordinate on the screen. + */ public Integer getTileX() { return tileX; } + /** + * + * @return the Tile Y coordinate on the screen + */ public Integer getTileY() { return tileY; } + /** + * + * @return the Tile X and Y coordinates on the screen. + */ public Point getCenter() { return new Point(this.tileX, this.tileY); } @@ -376,6 +353,10 @@ public void setCenter(Point center) { } } + /** + * + * @return The Tile Orientation. The default orientation is East or from left to right + */ public Orientation getOrientation() { return model.getTileOrienation(); } @@ -553,12 +534,6 @@ public void setBlockBean(BlockBean blockBean) { this.blockBean = blockBean; } -// public void setRenderWidth(int renderWidth) { -// this.renderWidth = renderWidth; -// } -// public void setRenderHeight(int renderHeight) { -// this.renderHeight = renderHeight; -// } public int getRenderOffsetX() { return renderOffsetX; } @@ -583,17 +558,11 @@ public final void setTileType(TileType tileType) { this.tileType = tileType; } -// public Color getTrackColor() { -// return trackColor; -// } public void setTrackColor(Color trackColor) { if (getUI() != null) { getUI().setTrackColor(trackColor); } } -// public Color getTrackRouteColor() { -// return trackRouteColor; -// } public void setTrackRouteColor(Color trackRouteColor) { if (getUI() != null) { @@ -617,12 +586,6 @@ public void setIncomingSide(Orientation incomingSide) { model.setIncomingSide(incomingSide); } -// public Color getBackgroundColor() { -// return backgroundColor; -// } -// public void setBackgroundColor(Color backgroundColor) { -// this.backgroundColor = backgroundColor; -// } public boolean isShowRoute() { return model.isShowRoute(); } @@ -631,14 +594,13 @@ public void setShowRoute(boolean drawRoute) { this.model.setShowRoute(drawRoute); } -// public int getRenderWidth() { -// return renderWidth; -// } -// public int getRenderHeight() { -// return renderHeight; -// } -// abstract void renderTile(Graphics2D g2d); -// abstract void renderTileRoute(Graphics2D g2d); + /** + * + * @return a Map of points which are adjacent of the Tile
+ * The key is the location with respect to this tile, i.e. is the neighbor point o the East (right side)>
+ * on the west side (on the left) or on the top (north) or bottom (south). + * + */ public abstract Map getNeighborPoints(); public abstract Map getEdgePoints(); @@ -657,101 +619,6 @@ Set getAllPoints(Point center) { return aps; } - /** - * Draw the Tile - * - * @param g2d The graphics handle - */ -// public void drawTile(Graphics2D g2d) { -// // by default and image is rendered in the EAST orientation -// Orientation tileOrientation = model.getTileOrienation(); -// -// BufferedImage bf = createImage(); -// Graphics2D g2di = bf.createGraphics(); -// -// //Avoid errors -// if (model.isShowRoute() && model.getIncomingSide() == null) { -// model.setIncomingSide(tileOrientation); -// } -// -// if (model.isSelected()) { -// g2di.setBackground(model.getSelectedColor()); -// } else { -// g2di.setBackground(backgroundColor); -// } -// -// g2di.clearRect(0, 0, renderWidth, renderHeight); -// int ox = 0, oy = 0; -// -// AffineTransform trans = new AffineTransform(); -// switch (tileOrientation) { -// case SOUTH -> { -// trans.rotate(Math.PI / 2, renderWidth / 2, renderHeight / 2); -// ox = (renderHeight - renderWidth) / 2; -// oy = (renderWidth - renderHeight) / 2; -// trans.translate(-ox, -oy); -// } -// case WEST -> { -// trans.rotate(Math.PI, renderWidth / 2, renderHeight / 2); -// trans.translate(ox, oy); -// } -// case NORTH -> { -// trans.rotate(-Math.PI / 2, renderWidth / 2, renderHeight / 2); -// ox = (renderHeight - renderWidth) / 2; -// oy = (renderWidth - renderHeight) / 2; -// trans.translate(-ox, -oy); -// } -// default -> { -// trans.rotate(0.0, this.renderWidth / 2, this.renderHeight / 2); -// trans.translate(ox, oy); -// } -// } -// -// //Logger.trace(tileOrientation.getOrientation() + " renderWidth: " + renderWidth + " renderHeight: " + renderHeight + " CP: (" + renderWidth / 2 + "," + renderHeight / 2 + ")"); -// //Logger.trace(tileOrientation.getOrientation() + " ox: " + ox + " oy: " + oy); -// g2di.setTransform(trans); -// -// renderTile(g2di); -// -// if (model.isShowRoute()) { -// renderTileRoute(g2di); -// } -// -// if (model.isShowCenter()) { -// drawCenterPoint(g2di); -// } -// -// // Scale the image back... -// if (model.isScaleImage()) { -// tileImage = Scalr.resize(bf, Method.AUTOMATIC, Mode.FIT_EXACT, getWidth(), getHeight(), Scalr.OP_ANTIALIAS); -// } else { -// tileImage = bf; -// } -// g2di.dispose(); -// } -// public BufferedImage getTileImage() { -// return tileImage; -// } - /** - * Render a tile image Always starts at (0,0) used the default width and height - * - * @param g2 the Graphic context - */ -// public void drawName(Graphics2D g2) { -// } -// protected void drawCenterPoint(Graphics2D g2d) { -// drawCenterPoint(g2d, Color.magenta); -// } -// protected void drawCenterPoint(Graphics2D g2, Color color) { -// drawCenterPoint(g2, color, 60); -// } -// protected void drawCenterPoint(Graphics2D g2d, Color color, double size) { -// double dX = (renderWidth / 2 - size / 2); -// double dY = (renderHeight / 2 - size / 2); -// -// g2d.setColor(color); -// g2d.fill(new Ellipse2D.Double(dX, dY, size, size)); -// } /** * Rotate the tile clockwise 90 deg * @@ -794,14 +661,6 @@ public void move(int newX, int newY) { setCenter(cs); } -// protected static void drawRotate(Graphics2D g2d, double x, double y, int angle, String text) { -// g2d.translate((float) x, (float) y); -// g2d.rotate(Math.toRadians(angle)); -// g2d.drawString(text, 0, 0); -// g2d.rotate(-Math.toRadians(angle)); -// g2d.translate(-x, -y); -// } - public static BufferedImage flipHorizontally(BufferedImage source) { BufferedImage output = new BufferedImage(source.getHeight(), source.getWidth(), source.getType()); @@ -830,25 +689,6 @@ public Set getAltPoints() { return Collections.EMPTY_SET; } -// public final int getOffsetX() { -// return offsetX; -// } -// -// public void setOffsetX(int offsetX) { -// this.offsetX = offsetX; -// } -// -// public final int getOffsetY() { -// return offsetY; -// } -// -// public void setOffsetY(int offsetY) { -// this.offsetY = offsetY; -// } - -// protected BufferedImage createImage() { -// return new BufferedImage(renderWidth, renderHeight, BufferedImage.TYPE_INT_RGB); -// } public int getCenterX() { if (tileX > 0) { return this.tileX; @@ -1050,8 +890,6 @@ class Handler implements ActionListener, ChangeListener, Serializable { @Override public void stateChanged(ChangeEvent e) { - //Object source = e.getSource(); - fireStateChanged(); repaint(); } @@ -1108,18 +946,12 @@ public Rectangle getTileBounds() { @Override protected void paintComponent(Graphics g) { - long started = System.currentTimeMillis(); - - super.paintComponent(g); - - //Graphics2D g2 = (Graphics2D) g.create(); - //Graphics2D g2 = (Graphics2D) g.create(tileX - GRID, tileY - GRID, DEFAULT_WIDTH, DEFAULT_HEIGHT); - //drawTile(g2); - //getUI().drawTile(g2, this); - //g2.dispose(); - //g.drawImage(tileImage, 0, 0, null); - long now = System.currentTimeMillis(); - Logger.trace(id + " Duration: " + (now - started) + " ms. Cp: " + xyToString() + " O: " + model.getTileOrienation()); + if (Logger.isTraceEnabled()) { + long started = System.currentTimeMillis(); + super.paintComponent(g); + long now = System.currentTimeMillis(); + Logger.trace(id + " Duration: " + (now - started) + " ms. Cp: " + xyToString() + " O: " + model.getTileOrienation()); + } } } diff --git a/src/main/java/jcs/ui/layout/tiles/ui/CrossUI.java b/src/main/java/jcs/ui/layout/tiles/ui/CrossUI.java index a592b60d..94255d94 100644 --- a/src/main/java/jcs/ui/layout/tiles/ui/CrossUI.java +++ b/src/main/java/jcs/ui/layout/tiles/ui/CrossUI.java @@ -36,41 +36,12 @@ public class CrossUI extends TileUI { public CrossUI() { super(); - //Default is east -// this.renderWidth = RENDER_GRID * 4; -// this.renderHeight = RENDER_GRID * 2; } public static ComponentUI createUI(JComponent c) { return new CrossUI(); } -// public void changeRenderSize(Tile tile) { -// //Reset offsets -// //this.offsetY = 0; -// //this.renderOffsetY = 0; -// //this.offsetX = 0; -// //this.renderOffsetX = 0; -// -// if (tile.isHorizontal()) { -// this.renderWidth = RENDER_GRID * 4; -// this.renderHeight = RENDER_GRID * 2; -// -// //this.offsetY = 0; -// //this.renderOffsetY = 0; -// } else { -// this.renderWidth = RENDER_GRID * 2; -// this.renderHeight = RENDER_GRID * 4; -// -// //this.offsetX = 0; -// //this.renderOffsetX = 0; -// } -// -// //Due to the asymetical shape (center is on the left) -// //the offset has to be changed with the rotation -//// } -// } - protected void renderStraight(Graphics2D g2, Color color) { int xx = 0; int yy = 170; @@ -237,8 +208,6 @@ public void renderTileRoute(Graphics2D g2, JComponent c) { routeValue = AccessoryBean.AccessoryValue.OFF; } - //Color trackColor = tile.getTrackColor(); - //Color trackRouteColor = tile.getTrackRouteColor(); if (tile.isHorizontal()) { if (AccessoryBean.AccessoryValue.GREEN == routeValue && (TileBean.Orientation.NORTH == incomingSide || TileBean.Orientation.SOUTH == incomingSide)) { renderRouteDiagonal(g2, trackRouteColor, c); diff --git a/src/main/java/jcs/ui/layout/tiles/ui/CrossingUI.java b/src/main/java/jcs/ui/layout/tiles/ui/CrossingUI.java index b7fe6b5b..90eec11c 100644 --- a/src/main/java/jcs/ui/layout/tiles/ui/CrossingUI.java +++ b/src/main/java/jcs/ui/layout/tiles/ui/CrossingUI.java @@ -20,6 +20,7 @@ import java.awt.Graphics2D; import javax.swing.JComponent; import javax.swing.plaf.ComponentUI; +import jcs.entities.TileBean.Orientation; import jcs.ui.layout.tiles.Tile; public class CrossingUI extends StraightUI { @@ -32,9 +33,6 @@ public static ComponentUI createUI(JComponent c) { } protected void renderVerticalAndDividers(Graphics2D g2, JComponent c) { - Tile tile = (Tile) c; - //Color trackColor = tile.getTrackColor(); - int xxn = 175; int yyn = 0; int xxs = 175; @@ -65,16 +63,12 @@ protected void renderVerticalAndDividers(Graphics2D g2, JComponent c) { } protected void renderRouteVertical(Graphics2D g2, JComponent c) { - Tile tile = (Tile) c; - //Color trackRouteColor = tile.getTrackRouteColor(); - - int xxn, yyn, xxs, yys, w, h; - xxn = 190; - yyn = 0; - xxs = 190; - yys = 325; - w = 20; - h = 75; + int xxn = 190; + int yyn = 0; + int xxs = 190; + int yys = 325; + int w = 20; + int h = 75; g2.setStroke(new BasicStroke(4, BasicStroke.JOIN_MITER, BasicStroke.JOIN_ROUND)); g2.setPaint(trackRouteColor); @@ -91,4 +85,19 @@ public void renderTile(Graphics2D g2, JComponent c) { renderVerticalAndDividers(g2, c); } + @Override + public void renderTileRoute(Graphics2D g2, JComponent c) { + Tile tile = (Tile) c; + Orientation incomingSide = tile.getIncomingSide(); + if (tile.isHorizontal() && (Orientation.NORTH == incomingSide || Orientation.SOUTH == incomingSide)) { + renderRouteVertical(g2, c); + } else if (tile.isHorizontal() && (Orientation.EAST == incomingSide || Orientation.WEST == incomingSide)) { + renderRouteStraight(g2, c); + } else if (tile.isVertical() && (Orientation.WEST == incomingSide || Orientation.EAST == incomingSide)) { + renderRouteVertical(g2, c); + } else { + renderRouteStraight(g2, c); + } + } + } diff --git a/src/main/java/jcs/ui/layout/tiles/ui/CurvedUI.java b/src/main/java/jcs/ui/layout/tiles/ui/CurvedUI.java index e9dad0c4..6f176c44 100644 --- a/src/main/java/jcs/ui/layout/tiles/ui/CurvedUI.java +++ b/src/main/java/jcs/ui/layout/tiles/ui/CurvedUI.java @@ -16,7 +16,6 @@ package jcs.ui.layout.tiles.ui; import java.awt.BasicStroke; -import java.awt.Color; import java.awt.Graphics2D; import javax.swing.JComponent; import javax.swing.plaf.ComponentUI; @@ -33,9 +32,6 @@ public static ComponentUI createUI(JComponent c) { @Override public void renderTile(Graphics2D g2, JComponent c) { - Tile tile = (Tile) c; - //Color trackColor = tile.getTrackColor(); - int[] xPoints = new int[]{400, 400, 170, 230}; int[] yPoints = new int[]{230, 170, 400, 400}; @@ -47,9 +43,6 @@ public void renderTile(Graphics2D g2, JComponent c) { @Override public void renderTileRoute(Graphics2D g2, JComponent c) { - Tile tile = (Tile) c; - //Color trackRouteColor = tile.getTrackRouteColor(); - int[] xPoints = new int[]{400, 400, 190, 210}; int[] yPoints = new int[]{210, 190, 400, 400}; diff --git a/src/main/java/jcs/ui/layout/tiles/ui/EndUI.java b/src/main/java/jcs/ui/layout/tiles/ui/EndUI.java index e49ec7ae..c79b3463 100644 --- a/src/main/java/jcs/ui/layout/tiles/ui/EndUI.java +++ b/src/main/java/jcs/ui/layout/tiles/ui/EndUI.java @@ -32,9 +32,6 @@ public static ComponentUI createUI(JComponent c) { } protected void renderEnd(Graphics2D g2, JComponent c) { - Tile tile = (Tile) c; - //Color trackColor = tile.getTrackColor(); - int xx = 0; int yy = 175; int w = RENDER_GRID; diff --git a/src/main/java/jcs/ui/layout/tiles/ui/StraightUI.java b/src/main/java/jcs/ui/layout/tiles/ui/StraightUI.java index 31bb053f..712fc11f 100644 --- a/src/main/java/jcs/ui/layout/tiles/ui/StraightUI.java +++ b/src/main/java/jcs/ui/layout/tiles/ui/StraightUI.java @@ -16,11 +16,9 @@ package jcs.ui.layout.tiles.ui; import java.awt.BasicStroke; -import java.awt.Color; import java.awt.Graphics2D; import javax.swing.JComponent; import javax.swing.plaf.ComponentUI; -import jcs.ui.layout.tiles.Tile; public class StraightUI extends TileUI { @@ -32,9 +30,6 @@ public static ComponentUI createUI(JComponent c) { } protected void renderStraight(Graphics2D g2, JComponent c) { - Tile tile = (Tile) c; - //Color trackColor = tile.getTrackColor(); - int xx = 0; int yy = 170; int w = RENDER_WIDTH; @@ -47,15 +42,12 @@ protected void renderStraight(Graphics2D g2, JComponent c) { } protected void renderRouteStraight(Graphics2D g2, JComponent c) { - Tile tile = (Tile) c; - int xx, yy, w, h; xx = 0; yy = 190; w = RENDER_WIDTH; h = 20; - //Color trackRouteColor = tile.getTrackRouteColor(); g2.setStroke(new BasicStroke(4, BasicStroke.JOIN_MITER, BasicStroke.JOIN_ROUND)); g2.setPaint(trackRouteColor); diff --git a/src/main/java/jcs/ui/layout/tiles/ui/SwitchUI.java b/src/main/java/jcs/ui/layout/tiles/ui/SwitchUI.java index 6b4ae851..fd729988 100644 --- a/src/main/java/jcs/ui/layout/tiles/ui/SwitchUI.java +++ b/src/main/java/jcs/ui/layout/tiles/ui/SwitchUI.java @@ -101,8 +101,6 @@ protected void renderRouteDiagonal(Graphics2D g2, Color color, JComponent c) { public void renderTile(Graphics2D g2, JComponent c) { Tile tile = (Tile) c; AccessoryValue accessoryValue = tile.getAccessoryValue(); - //Color trackColor = tile.getTrackColor(); - if (accessoryValue == null) { accessoryValue = AccessoryBean.AccessoryValue.OFF; } @@ -127,7 +125,6 @@ public void renderTile(Graphics2D g2, JComponent c) { public void renderTileRoute(Graphics2D g2, JComponent c) { Tile tile = (Tile) c; AccessoryValue routeValue = tile.getRouteValue(); - //Color trackRouteColor = tile.getTrackRouteColor(); if (routeValue == null) { routeValue = AccessoryBean.AccessoryValue.OFF; diff --git a/src/main/java/jcs/ui/layout/tiles/ui/TileUI.java b/src/main/java/jcs/ui/layout/tiles/ui/TileUI.java index 3d2f7176..9f30b6f4 100644 --- a/src/main/java/jcs/ui/layout/tiles/ui/TileUI.java +++ b/src/main/java/jcs/ui/layout/tiles/ui/TileUI.java @@ -37,8 +37,7 @@ import org.tinylog.Logger; /** - * - * @author fransjacobs + * The drawing functionality of a Tile. */ public abstract class TileUI extends ComponentUI { @@ -150,8 +149,6 @@ public void drawTile(Graphics2D g2d, JComponent c) { Tile tile = (Tile) c; TileModel model = ((Tile) c).getModel(); TileBean.Orientation tileOrientation = model.getTileOrienation(); - - //BufferedImage bf = new BufferedImage(tile.getRenderWidth(), tile.getRenderHeight(), BufferedImage.TYPE_INT_RGB); BufferedImage bf = createImage(); Graphics2D g2di = bf.createGraphics(); From 0f837227317d3c2a41353573c94a6ae3eed8a8b8 Mon Sep 17 00:00:00 2001 From: Frans Jacobs Date: Sat, 8 Feb 2025 17:08:28 +0100 Subject: [PATCH 16/24] More cleanup --- .../tiles/sandbox/AlphaButtonPolicy.java | 91 ---------- .../tiles/sandbox/BasicJogShuttleUI.java | 156 ------------------ .../ui/layout/tiles/sandbox/FocusExample.java | 86 ---------- .../tiles/sandbox/FocusTraversalExample.java | 38 ----- .../layout/tiles/sandbox/InvokeExample.java | 115 ------------- .../ui/layout/tiles/sandbox/JogShuttle.java | 154 ----------------- .../ui/layout/tiles/sandbox/JogShuttleUI.java | 11 -- .../ui/layout/tiles/sandbox/SimpleModel.java | 84 ---------- .../tiles/sandbox/SimpleModelInterface.java | 24 --- .../jcs/ui/layout/tiles/sandbox/Sketch.java | 85 ---------- 10 files changed, 844 deletions(-) delete mode 100755 src/main/java/jcs/ui/layout/tiles/sandbox/AlphaButtonPolicy.java delete mode 100755 src/main/java/jcs/ui/layout/tiles/sandbox/BasicJogShuttleUI.java delete mode 100755 src/main/java/jcs/ui/layout/tiles/sandbox/FocusExample.java delete mode 100755 src/main/java/jcs/ui/layout/tiles/sandbox/FocusTraversalExample.java delete mode 100755 src/main/java/jcs/ui/layout/tiles/sandbox/InvokeExample.java delete mode 100755 src/main/java/jcs/ui/layout/tiles/sandbox/JogShuttle.java delete mode 100755 src/main/java/jcs/ui/layout/tiles/sandbox/JogShuttleUI.java delete mode 100755 src/main/java/jcs/ui/layout/tiles/sandbox/SimpleModel.java delete mode 100755 src/main/java/jcs/ui/layout/tiles/sandbox/SimpleModelInterface.java delete mode 100755 src/main/java/jcs/ui/layout/tiles/sandbox/Sketch.java diff --git a/src/main/java/jcs/ui/layout/tiles/sandbox/AlphaButtonPolicy.java b/src/main/java/jcs/ui/layout/tiles/sandbox/AlphaButtonPolicy.java deleted file mode 100755 index 16e7832a..00000000 --- a/src/main/java/jcs/ui/layout/tiles/sandbox/AlphaButtonPolicy.java +++ /dev/null @@ -1,91 +0,0 @@ -// AlphaButtonPolicy.java -// A custom focus traversal policy that uses alphabetical ordering of button -// labels to determine "next" and "previous" buttons for keyboard traversal. -// -package jcs.ui.layout.tiles.sandbox; - -import java.awt.*; -import java.util.*; -import javax.swing.*; - -public class AlphaButtonPolicy extends FocusTraversalPolicy { - - private SortedMap getSortedButtons(Container focusCycleRoot) { - if (focusCycleRoot == null) { - throw new IllegalArgumentException("focusCycleRoot can't be null"); - } - SortedMap result = new TreeMap(); // Will sort all buttons by text. - sortRecursive(result, focusCycleRoot); - return result; - } - - private void sortRecursive(Map buttons, Container container) { - for (int i = 0; i < container.getComponentCount(); i++) { - Component c = container.getComponent(i); - if (c instanceof JButton) { // Found another button to sort. - buttons.put(((JButton) c).getText(), c); - } - if (c instanceof Container) { // Found a container to search. - sortRecursive(buttons, (Container) c); - } - } - } - - // The rest of the code implements the FocusTraversalPolicy interface. - public Component getFirstComponent(Container focusCycleRoot) { - SortedMap buttons = getSortedButtons(focusCycleRoot); - if (buttons.isEmpty()) { - return null; - } - return (Component) buttons.get(buttons.firstKey()); - } - - public Component getLastComponent(Container focusCycleRoot) { - SortedMap buttons = getSortedButtons(focusCycleRoot); - if (buttons.isEmpty()) { - return null; - } - return (Component) buttons.get(buttons.lastKey()); - } - - public Component getDefaultComponent(Container focusCycleRoot) { - return getFirstComponent(focusCycleRoot); - } - - public Component getComponentAfter(Container focusCycleRoot, - Component aComponent) { - if (!(aComponent instanceof JButton)) { - return null; - } - SortedMap buttons = getSortedButtons(focusCycleRoot); - // Find all buttons after the current one. - String nextName = ((JButton) aComponent).getText() + "\0"; - SortedMap nextButtons = buttons.tailMap(nextName); - if (nextButtons.isEmpty()) { // Wrapped back to beginning - if (!buttons.isEmpty()) { - return (Component) buttons.get(buttons.firstKey()); - } - return null; // Degenerate case of no buttons. - } - return (Component) nextButtons.get(nextButtons.firstKey()); - } - - public Component getComponentBefore(Container focusCycleRoot, - Component aComponent) { - if (!(aComponent instanceof JButton)) { - return null; - } - - SortedMap buttons = getSortedButtons(focusCycleRoot); - SortedMap prevButtons - = // Find all buttons before this one. - buttons.headMap(((JButton) aComponent).getText()); - if (prevButtons.isEmpty()) { // Wrapped back to end. - if (!buttons.isEmpty()) { - return (Component) buttons.get(buttons.lastKey()); - } - return null; // Degenerate case of no buttons. - } - return (Component) prevButtons.get(prevButtons.lastKey()); - } -} diff --git a/src/main/java/jcs/ui/layout/tiles/sandbox/BasicJogShuttleUI.java b/src/main/java/jcs/ui/layout/tiles/sandbox/BasicJogShuttleUI.java deleted file mode 100755 index 77154263..00000000 --- a/src/main/java/jcs/ui/layout/tiles/sandbox/BasicJogShuttleUI.java +++ /dev/null @@ -1,156 +0,0 @@ -// BasicJogShuttleUI.java -// A UI class for our custom JogShuttle component. -// -package jcs.ui.layout.tiles.sandbox; - -import java.awt.*; -import java.awt.event.*; - -import javax.swing.*; -import javax.swing.plaf.*; - -public class BasicJogShuttleUI extends JogShuttleUI - implements MouseListener, MouseMotionListener { - - private static final int KNOB_DISPLACEMENT = 3; - private static final int FINGER_SLOT_DISPLACEMENT = 15; - - private double lastAngle; // Used to track mouse drags. - - public static ComponentUI createUI(JComponent c) { - return new BasicJogShuttleUI(); - } - - public void installUI(JComponent c) { - JogShuttle shuttle = (JogShuttle) c; - shuttle.addMouseListener(this); - shuttle.addMouseMotionListener(this); - } - - public void uninstallUI(JComponent c) { - JogShuttle shuttle = (JogShuttle) c; - shuttle.removeMouseListener(this); - shuttle.removeMouseMotionListener(this); - } - - public void paint(Graphics g, JComponent c) { - // We don't want to paint inside the insets or borders. - Insets insets = c.getInsets(); - g.translate(insets.left, insets.top); - int width = c.getWidth() - insets.left - insets.right; - int height = c.getHeight() - insets.top - insets.bottom; - - // Draw the outside circle. - g.setColor(c.getForeground()); - g.fillOval(0, 0, width, height); - - Insets d = ((JogShuttle) c).getDialInsets(); - int value = ((JogShuttle) c).getValue(); - int valuePerRevolution = ((JogShuttle) c).getValuePerRevolution(); - - // Draw the edge of the dial. - g.setColor(Color.darkGray); - g.fillOval(d.left, d.top, width - (d.right * 2), height - (d.bottom * 2)); - - // Draw the inside of the dial. - g.setColor(Color.gray); - g.fillOval(d.left + KNOB_DISPLACEMENT, - d.top + KNOB_DISPLACEMENT, - width - (d.right + d.left) - KNOB_DISPLACEMENT * 2, - height - (d.bottom + d.top) - KNOB_DISPLACEMENT * 2); - - // Draw the finger slot. - drawFingerSlot(g, c, value, width, height, valuePerRevolution, - FINGER_SLOT_DISPLACEMENT - 1, - (double) (width / 2) - d.right - FINGER_SLOT_DISPLACEMENT, - (double) (height / 2) - d.bottom - FINGER_SLOT_DISPLACEMENT); - - g.translate(-insets.left, -insets.top); - } - - private void drawFingerSlot(Graphics g, JComponent c, int value, - int width, int height, int valuePerRevolution, int size, - double xradius, double yradius) { - - int currentPosition = value % valuePerRevolution; - - // Obtain the current angle in radians. - double angle = ((double) currentPosition / valuePerRevolution) - * java.lang.Math.PI * 2; - - // Obtain the X and Y coordinates of the finger slot, with the - // minimum value at twelve o'clock. - angle -= (java.lang.Math.PI / 2); - int xPosition = (int) (xradius * java.lang.Math.sin(angle)); - int yPosition = (int) (yradius * java.lang.Math.cos(angle)); - xPosition = (width / 2) - xPosition; - yPosition = (height / 2) + yPosition; - - // Draw the finger slot with a crescent shadow on the top left. - g.setColor(Color.darkGray); - g.fillOval(xPosition - (size / 2), yPosition - (size / 2), size, size); - g.setColor(Color.lightGray); - g.fillOval(xPosition - (size / 2) + 1, yPosition - (size / 2) + 1, - size - 1, size - 1); - - } - - // Figure out angle at which a mouse event occurred with respect to the - // center of the component for intuitive dial dragging. - protected double calculateAngle(MouseEvent e) { - int x = e.getX() - ((JComponent) e.getSource()).getWidth() / 2; - int y = -e.getY() + ((JComponent) e.getSource()).getHeight() / 2; - if (x == 0) { // Handle case where math would blow up. - if (y == 0) { - return lastAngle; // Can't tell... - } - if (y > 0) { - return Math.PI / 2; - } - return -Math.PI / 2; - } - return Math.atan((double) y / (double) x); - } - - public void mousePressed(MouseEvent e) { - lastAngle = calculateAngle(e); - } - - public void mouseReleased(MouseEvent e) { - } - - public void mouseClicked(MouseEvent e) { - } - - public void mouseEntered(MouseEvent e) { - } - - public void mouseExited(MouseEvent e) { - } - - // Figure out the change in angle over which the user has dragged, - // expressed as a fraction of a revolution. - public double angleDragged(MouseEvent e) { - double newAngle = calculateAngle(e); - double change = (lastAngle - newAngle) / Math.PI; - if (Math.abs(change) > 0.5) { // Handle crossing origin. - if (change < 0.0) { - change += 1.0; - } else { - change -= 1.0; - } - } - - lastAngle = newAngle; - return change; - } - - public void mouseDragged(MouseEvent e) { - JogShuttle theShuttle = (JogShuttle) e.getComponent(); - theShuttle.setValue(theShuttle.getValue() - + (int) (angleDragged(e) * theShuttle.getValuePerRevolution())); - } - - public void mouseMoved(MouseEvent e) { - } -} diff --git a/src/main/java/jcs/ui/layout/tiles/sandbox/FocusExample.java b/src/main/java/jcs/ui/layout/tiles/sandbox/FocusExample.java deleted file mode 100755 index e27171f1..00000000 --- a/src/main/java/jcs/ui/layout/tiles/sandbox/FocusExample.java +++ /dev/null @@ -1,86 +0,0 @@ -// FocusExample.java -// An example of focus traversal using the keyboard to navigate through a -// small set of buttons. -// -package jcs.ui.layout.tiles.sandbox; - -import java.awt.*; -import java.awt.event.*; - -import javax.swing.*; - -public class FocusExample extends JFrame { - - public FocusExample() { - - super("Focus Example"); - setDefaultCloseOperation(EXIT_ON_CLOSE); - MyPanel mypanel = new MyPanel(); - - JButton button1 = new JButton("One"); - JButton button2 = new JButton("Two"); - JButton button3 = new JButton("Three"); - JButton button4 = new JButton("Four"); - JButton button5 = new MyButton("Five*"); - JButton button6 = new MyButton("Six*"); - JButton button7 = new JButton("Seven"); - - mypanel.add(button2); - mypanel.add(button3); - - JInternalFrame frame1 = new JInternalFrame("Internal Frame 1", - true, true, true, true); - - frame1.setBackground(Color.lightGray); - frame1.getContentPane().setLayout(new GridLayout(2, 3)); - frame1.setSize(300, 200); - - frame1.getContentPane().add(button1); - frame1.getContentPane().add(mypanel); - frame1.getContentPane().add(button4); - frame1.getContentPane().add(button5); - frame1.getContentPane().add(button6); - frame1.getContentPane().add(button7); - - JDesktopPane desktop = new JDesktopPane(); - desktop.add(frame1, new Integer(1)); - desktop.setOpaque(true); - - // Now set up the user interface window. - Container contentPane = getContentPane(); - contentPane.add(desktop, BorderLayout.CENTER); - setSize(new Dimension(400, 300)); - frame1.setVisible(true); - setVisible(true); - } - - public static void main(String[] args) { - new FocusExample(); - } - - class MyButton extends JButton { - - public MyButton(String s) { - super(s); - } - - public boolean isFocusable() { - return false; - } - } - - class MyPanel extends JPanel { - - public MyPanel() { - super(true); - java.util.Set upKeys = new java.util.HashSet(1); - upKeys.add(AWTKeyStroke.getAWTKeyStroke(KeyEvent.VK_UP, 0)); - setFocusTraversalKeys(KeyboardFocusManager.UP_CYCLE_TRAVERSAL_KEYS, - upKeys); - } - - public boolean isFocusCycleRoot() { - return true; - } - } -} diff --git a/src/main/java/jcs/ui/layout/tiles/sandbox/FocusTraversalExample.java b/src/main/java/jcs/ui/layout/tiles/sandbox/FocusTraversalExample.java deleted file mode 100755 index 39fdbec1..00000000 --- a/src/main/java/jcs/ui/layout/tiles/sandbox/FocusTraversalExample.java +++ /dev/null @@ -1,38 +0,0 @@ -//FocusTraversalExample.java -// Similar to the FocusExample, this class uses the custom AlphaButtonPolicy -// focus traversal policy to navigate another small set of buttons. -// -package jcs.ui.layout.tiles.sandbox; - -import java.awt.*; -import javax.swing.*; - -public class FocusTraversalExample extends JPanel { - - public FocusTraversalExample() { - setLayout(new GridLayout(6, 1)); - JButton button1 = new JButton("Texas"); - JButton button2 = new JButton("Vermont"); - JButton button3 = new JButton("Florida"); - JButton button4 = new JButton("Alabama"); - JButton button5 = new JButton("Minnesota"); - JButton button6 = new JButton("California"); - - setBackground(Color.lightGray); - add(button1); - add(button2); - add(button3); - add(button4); - add(button5); - add(button6); - } - - public static void main(String[] args) { - JFrame frame = new JFrame("Alphabetized Button Focus Traversal"); - frame.setFocusTraversalPolicy(new AlphaButtonPolicy()); - frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); - frame.setContentPane(new FocusTraversalExample()); - frame.setSize(400, 300); - frame.setVisible(true); - } -} diff --git a/src/main/java/jcs/ui/layout/tiles/sandbox/InvokeExample.java b/src/main/java/jcs/ui/layout/tiles/sandbox/InvokeExample.java deleted file mode 100755 index 2f4815c2..00000000 --- a/src/main/java/jcs/ui/layout/tiles/sandbox/InvokeExample.java +++ /dev/null @@ -1,115 +0,0 @@ -// InvokeExample.java -// This class demonstrates several examples of how to handle long-running -// tasks (such as querying a remote resource). Some of the examples are -// good, some are not! -// - -package jcs.ui.layout.tiles.sandbox; - -import javax.swing.*; -import java.awt.*; -import java.awt.event.*; - -public class InvokeExample { - private static JButton good = new JButton("Good"); - private static JButton bad = new JButton("Bad"); - private static JButton bad2 = new JButton("Bad2"); - private static JLabel resultLabel = new JLabel("Ready", JLabel.CENTER); - - public static void main(String[] args) { - JFrame f = new JFrame(); - f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); - - // Layout . . . - JPanel p = new JPanel(); - p.setOpaque(true); - p.setLayout(new FlowLayout()); - p.add(good); - p.add(bad); - p.add(bad2); - - Container c = f.getContentPane(); - c.setLayout(new BorderLayout()); - c.add(p, BorderLayout.CENTER); - c.add(resultLabel, BorderLayout.SOUTH); - - // Listeners - good.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent ev) { - resultLabel.setText("Working . . ."); - setEnabled(false); - - // We're going to do something that takes a long time, so we - // spin off a thread and update the display when we're done. - Thread worker = new Thread() { - public void run() { - // Something that takes a long time . . . in real life, this - // might be a DB query, remote method invocation, etc. - try { - Thread.sleep(5000); - } - catch (InterruptedException ex) {} - - // Report the result using invokeLater(). - SwingUtilities.invokeLater(new Runnable() { - public void run() { - resultLabel.setText("Ready"); - setEnabled(true); - } - }); - } - }; - - worker.start(); // So we don't hold up the dispatch thread. - } - }); - - bad.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent ev) { - resultLabel.setText("Working . . ."); - setEnabled(false); - - // We're going to do the same thing, but not in a separate thread. - try { - Thread.sleep(5000); // Dispatch thread is starving! - } - catch (InterruptedException ex) {} - - // Report the result. - resultLabel.setText("Ready"); - setEnabled(true); - } - }); - - bad2.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent ev) { - resultLabel.setText("Working . . . "); - setEnabled(false); - - // The wrong way to use invokeLater(). The runnable() shouldn't - // starve the dispatch thread. - SwingUtilities.invokeLater(new Runnable() { - public void run() { - try { - Thread.sleep(5000); // Dispatch thread is starving! - } - catch (InterruptedException ex) {} - - resultLabel.setText("Ready"); - setEnabled(true); - } - }); - } - }); - - f.setSize(300, 100); - f.setVisible(true); - } - - // Allows us to turn the buttons on or off while we work. - static void setEnabled(boolean b) { - good.setEnabled(b); - bad.setEnabled(b); - bad2.setEnabled(b); - } -} diff --git a/src/main/java/jcs/ui/layout/tiles/sandbox/JogShuttle.java b/src/main/java/jcs/ui/layout/tiles/sandbox/JogShuttle.java deleted file mode 100755 index d39366fb..00000000 --- a/src/main/java/jcs/ui/layout/tiles/sandbox/JogShuttle.java +++ /dev/null @@ -1,154 +0,0 @@ -// JogShuttle.java -// A custom jog shuttle component. (Some VCRs have such a thing for doing -// variable speed fast-forward and fast-reverse.) An example of using the -// JogShuttle can be found in Sketch.java. -// -package jcs.ui.layout.tiles.sandbox; - -import java.awt.*; - -import javax.swing.*; -import javax.swing.event.*; - -public class JogShuttle extends JComponent implements ChangeListener { - - private BoundedRangeModel model; - - // The dialInsets property tells how far the dial is inset - // from the sunken border. - private Insets dialInsets = new Insets(3, 3, 3, 3); - - // The valuePerRevolution property tells how many units the dial - // takes to make a complete revolution. - private int valuePerRevolution; - - // Constructors - public JogShuttle() { - init(new DefaultBoundedRangeModel()); - } - - public JogShuttle(BoundedRangeModel m) { - init(m); - } - - public JogShuttle(int min, int max, int value) { - init(new DefaultBoundedRangeModel(value, 1, min, max)); - } - - protected void init(BoundedRangeModel m) { - setModel(m); - valuePerRevolution = m.getMaximum() - m.getMinimum(); - setMinimumSize(new Dimension(80, 80)); - setPreferredSize(new Dimension(80, 80)); - updateUI(); - } - - public void setUI(JogShuttleUI ui) { - super.setUI(ui); - } - - public void updateUI() { - setUI((JogShuttleUI) UIManager.getUI(this)); - invalidate(); - } - - public String getUIClassID() { - return JogShuttleUI.UI_CLASS_ID; - } - - public void setModel(BoundedRangeModel m) { - BoundedRangeModel old = model; - if (old != null) { - old.removeChangeListener(this); - } - - if (m == null) { - model = new DefaultBoundedRangeModel(); - } else { - model = m; - } - model.addChangeListener(this); - - firePropertyChange("model", old, model); - } - - public BoundedRangeModel getModel() { - return model; - } - - // Methods - public void resetToMinimum() { - model.setValue(model.getMinimum()); - } - - public void resetToMaximum() { - model.setValue(model.getMaximum()); - } - - public void stateChanged(ChangeEvent e) { - repaint(); - } - - // Accessors and mutators - public int getMinimum() { - return model.getMinimum(); - } - - public void setMinimum(int m) { - int old = getMinimum(); - if (m != old) { - model.setMinimum(m); - firePropertyChange("minimum", old, m); - } - } - - public int getMaximum() { - return model.getMaximum(); - } - - public void setMaximum(int m) { - int old = getMaximum(); - if (m != old) { - model.setMaximum(m); - firePropertyChange("maximum", old, m); - } - } - - public int getValue() { - return model.getValue(); - } - - public void setValue(int v) { - int old = getValue(); - if (v != old) { - model.setValue(v); - firePropertyChange("value", old, v); - } - } - - // Display-specific properties - public int getValuePerRevolution() { - return valuePerRevolution; - } - - public void setValuePerRevolution(int v) { - int old = getValuePerRevolution(); - if (v != old) { - valuePerRevolution = v; - firePropertyChange("valuePerRevolution", old, v); - } - repaint(); - } - - public void setDialInsets(Insets i) { - dialInsets = i; - } - - public void setDialInsets(int top, int left, int bottom, int right) { - dialInsets = new Insets(top, left, bottom, right); - } - - public Insets getDialInsets() { - return dialInsets; - } -} diff --git a/src/main/java/jcs/ui/layout/tiles/sandbox/JogShuttleUI.java b/src/main/java/jcs/ui/layout/tiles/sandbox/JogShuttleUI.java deleted file mode 100755 index 790e0ae7..00000000 --- a/src/main/java/jcs/ui/layout/tiles/sandbox/JogShuttleUI.java +++ /dev/null @@ -1,11 +0,0 @@ -// JogShuttleUI.java -// Fill out the proper UIClassID information for our JogShuttle. -// - -package jcs.ui.layout.tiles.sandbox; - -import javax.swing.plaf.*; - -public abstract class JogShuttleUI extends ComponentUI { - public static final String UI_CLASS_ID = "JogShuttleUI"; -} diff --git a/src/main/java/jcs/ui/layout/tiles/sandbox/SimpleModel.java b/src/main/java/jcs/ui/layout/tiles/sandbox/SimpleModel.java deleted file mode 100755 index bcbbbea9..00000000 --- a/src/main/java/jcs/ui/layout/tiles/sandbox/SimpleModel.java +++ /dev/null @@ -1,84 +0,0 @@ -// SimpleModel.java -// An example of a custom data model that could be used in any MVC -// scenario. -// -package jcs.ui.layout.tiles.sandbox; - -import javax.swing.event.*; - -public class SimpleModel implements SimpleModelInterface { - - protected transient ChangeEvent changeEvent = null; - protected EventListenerList listenerList = new EventListenerList(); - - private int value = 0; - private boolean activated = false; - - public SimpleModel() { - } - - public SimpleModel(int v) { - value = v; - } - - public SimpleModel(boolean b) { - activated = b; - } - - public SimpleModel(int v, boolean b) { - value = v; - activated = b; - } - - public int getValue() { - return value; - } - - public synchronized void setValue(int v) { - if (v != value) { - value = v; - fireChange(); - } - } - - public boolean isActivated() { - return activated; - } - - public synchronized void setActivated(boolean b) { - if (b != activated) { - activated = b; - fireChange(); - } - } - - public void addChangeListener(ChangeListener l) { - listenerList.add(ChangeListener.class, l); - } - - public void removeChangeListener(ChangeListener l) { - listenerList.remove(ChangeListener.class, l); - } - - public ChangeListener[] getChangeListeners() { - return (ChangeListener[]) listenerList.getListeners(ChangeListener.class); - } - - protected void fireChange() { - Object[] listeners = listenerList.getListenerList(); - for (int i = listeners.length - 2; i >= 0; i -= 2) { - if (listeners[i] == ChangeListener.class) { - if (changeEvent == null) { - changeEvent = new ChangeEvent(this); - } - ((ChangeListener) listeners[i + 1]).stateChanged(changeEvent); - } - } - } - - public String toString() { - String modelString = "value=" + getValue() + ", " - + "activated=" + isActivated(); - return getClass().getName() + "[" + modelString + "]"; - } -} diff --git a/src/main/java/jcs/ui/layout/tiles/sandbox/SimpleModelInterface.java b/src/main/java/jcs/ui/layout/tiles/sandbox/SimpleModelInterface.java deleted file mode 100755 index 1d24c7f0..00000000 --- a/src/main/java/jcs/ui/layout/tiles/sandbox/SimpleModelInterface.java +++ /dev/null @@ -1,24 +0,0 @@ -// SimpleModelInteface.java -// An example of a data model interface that could be used in any MVC -// scenario. This interface is implemented in the SimpleModel class. -// -package jcs.ui.layout.tiles.sandbox; - -import javax.swing.event.*; - -public interface SimpleModelInterface { - - public int getValue(); - - public void setValue(int v); - - public boolean isActivated(); - - public void setActivated(boolean b); - - public void addChangeListener(ChangeListener l); - - public void removeChangeListener(ChangeListener l); - - public ChangeListener[] getChangeListeners(); -} diff --git a/src/main/java/jcs/ui/layout/tiles/sandbox/Sketch.java b/src/main/java/jcs/ui/layout/tiles/sandbox/Sketch.java deleted file mode 100755 index a8d4e2f7..00000000 --- a/src/main/java/jcs/ui/layout/tiles/sandbox/Sketch.java +++ /dev/null @@ -1,85 +0,0 @@ -// Sketch.java -// A sketching application with two dials: one for horizontal movement, one -// for vertical movement. The dials are instances of the JogShuttle class. -// -package jcs.ui.layout.tiles.sandbox; - -import java.awt.*; -import java.awt.event.*; -import java.beans.*; - -import javax.swing.*; -import javax.swing.border.*; - -public class Sketch extends JPanel - implements PropertyChangeListener, ActionListener { - - JogShuttle shuttle1; - JogShuttle shuttle2; - JPanel board; - JButton clear; - - int lastX, lastY; // Keep track of the last point we drew. - - public Sketch() { - super(true); - - setLayout(new BorderLayout()); - board = new JPanel(true); - board.setPreferredSize(new Dimension(300, 300)); - board.setBorder(new LineBorder(Color.black, 5)); - - clear = new JButton("Clear Drawing Area"); - clear.addActionListener(this); - - shuttle1 = new JogShuttle(0, 300, 150); - lastX = shuttle1.getValue(); - shuttle2 = new JogShuttle(0, 300, 150); - lastY = shuttle2.getValue(); - - shuttle1.setValuePerRevolution(100); - shuttle2.setValuePerRevolution(100); - - shuttle1.addPropertyChangeListener(this); - shuttle2.addPropertyChangeListener(this); - - shuttle1.setBorder(new BevelBorder(BevelBorder.RAISED)); - shuttle2.setBorder(new BevelBorder(BevelBorder.RAISED)); - - add(board, BorderLayout.NORTH); - add(shuttle1, BorderLayout.WEST); - add(clear, BorderLayout.CENTER); - add(shuttle2, BorderLayout.EAST); - } - - public void propertyChange(PropertyChangeEvent e) { - if (e.getPropertyName() == "value") { - Graphics g = board.getGraphics(); - g.setColor(getForeground()); - g.drawLine(lastX, lastY, - shuttle1.getValue(), shuttle2.getValue()); - lastX = shuttle1.getValue(); - lastY = shuttle2.getValue(); - } - } - - public void actionPerformed(ActionEvent e) { - // The button must have been pressed. - Insets insets = board.getInsets(); - Graphics g = board.getGraphics(); - g.setColor(board.getBackground()); - g.fillRect(insets.left, insets.top, - board.getWidth() - insets.left - insets.right, - board.getHeight() - insets.top - insets.bottom); - } - - public static void main(String[] args) { - UIManager.put(JogShuttleUI.UI_CLASS_ID, "BasicJogShuttleUI"); - Sketch s = new Sketch(); - JFrame frame = new JFrame("Sample Sketch Application"); - frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); - frame.setContentPane(s); - frame.pack(); - frame.setVisible(true); - } -} From 2f2ca21b8b767eaf60a5ee14170d80d2e9b60101 Mon Sep 17 00:00:00 2001 From: Frans Jacobs Date: Sun, 9 Feb 2025 14:56:32 +0100 Subject: [PATCH 17/24] The Sensor dispaly is now working again. Clicking on a Sensor will trigger the Sensor actions --- .../commandStation/JCSCommandStationImpl.java | 2 + .../esu/ecos/EsuEcosCommandStationImpl.java | 14 +- .../commandStation/events/AccessoryEvent.java | 4 +- .../commandStation/events/JCSActionEvent.java | 30 ++ .../commandStation/events/SensorEvent.java | 22 +- src/main/java/jcs/entities/SensorBean.java | 26 +- src/main/java/jcs/ui/layout/LayoutCanvas.form | 234 +++++++++++- src/main/java/jcs/ui/layout/LayoutCanvas.java | 54 ++- .../jcs/ui/layout/dialogs/SensorDialog.java | 2 +- src/main/java/jcs/ui/layout/tiles/Sensor.java | 1 - src/main/java/jcs/ui/layout/tiles/Tile.java | 335 +++++++++--------- .../layout/tiles/TileActionEventHandler.java | 96 +++++ .../java/jcs/ui/layout/tiles/TileCache.java | 162 ++------- .../java/jcs/ui/layout/tiles/TileFactory.java | 321 ++++++++++++++++- .../java/jcs/ui/layout/tiles/ui/SensorUI.java | 67 +++- .../java/jcs/ui/layout/tiles/ui/TileUI.java | 19 + 16 files changed, 1039 insertions(+), 350 deletions(-) create mode 100644 src/main/java/jcs/commandStation/events/JCSActionEvent.java create mode 100644 src/main/java/jcs/ui/layout/tiles/TileActionEventHandler.java diff --git a/src/main/java/jcs/commandStation/JCSCommandStationImpl.java b/src/main/java/jcs/commandStation/JCSCommandStationImpl.java index d0b0aa2e..73048cef 100755 --- a/src/main/java/jcs/commandStation/JCSCommandStationImpl.java +++ b/src/main/java/jcs/commandStation/JCSCommandStationImpl.java @@ -671,11 +671,13 @@ private class SensorChangeEventListener implements SensorEventListener { @Override public void onSensorChange(SensorEvent event) { SensorBean sb = event.getSensorBean(); + boolean newValue = event.isActive(); SensorBean dbsb = PersistenceFactory.getService().getSensor(sb.getDeviceId(), sb.getContactId()); if (dbsb != null) { sb.setId(dbsb.getId()); sb.setName(dbsb.getName()); + sb.setActive(newValue); PersistenceFactory.getService().persist(sb); } diff --git a/src/main/java/jcs/commandStation/esu/ecos/EsuEcosCommandStationImpl.java b/src/main/java/jcs/commandStation/esu/ecos/EsuEcosCommandStationImpl.java index 53ec814a..b1b98540 100644 --- a/src/main/java/jcs/commandStation/esu/ecos/EsuEcosCommandStationImpl.java +++ b/src/main/java/jcs/commandStation/esu/ecos/EsuEcosCommandStationImpl.java @@ -236,7 +236,8 @@ private void initFeedbackManager() { for (int i = 0; i < feedbackManager.getSize(); i++) { int moduleId = i + FeedbackManager.S88_OFFSET; - reply = connection.sendMessage(EcosMessageFactory.getFeedbackModuleInfo(moduleId)); + //reply = + connection.sendMessage(EcosMessageFactory.getFeedbackModuleInfo(moduleId)); //TODO: Start of day... //feedbackManager.update(reply); @@ -575,8 +576,12 @@ public List getFeedbackModules() { @Override public void fireSensorEventListeners(SensorEvent sensorEvent) { Logger.trace("SensorEvent: " + sensorEvent); - for (SensorEventListener listener : sensorEventListeners) { - listener.onSensorChange(sensorEvent); + if (sensorEventListeners != null && !sensorEventListeners.isEmpty()) { + for (SensorEventListener listener : sensorEventListeners) { + //if (listener != null) { + listener.onSensorChange(sensorEvent); + //} + } } } @@ -703,7 +708,8 @@ public void run() { } } -////////////////////////////////////////////////////////////////////////////////////// + ////////////////////////////////////////////////////////////////////////////////////// + /// @param a // For testing only public static void main(String[] a) { diff --git a/src/main/java/jcs/commandStation/events/AccessoryEvent.java b/src/main/java/jcs/commandStation/events/AccessoryEvent.java index 6da6b9b2..ab2c04d9 100755 --- a/src/main/java/jcs/commandStation/events/AccessoryEvent.java +++ b/src/main/java/jcs/commandStation/events/AccessoryEvent.java @@ -15,12 +15,11 @@ */ package jcs.commandStation.events; -import java.io.Serializable; import jcs.entities.AccessoryBean; import jcs.entities.AccessoryBean.AccessoryValue; import jcs.entities.AccessoryBean.SignalValue; -public class AccessoryEvent implements Serializable { +public class AccessoryEvent implements JCSActionEvent { private final AccessoryBean accessoryBean; @@ -51,6 +50,7 @@ public AccessoryValue getValue() { return this.accessoryBean.getAccessoryValue(); } + @Override public String getId() { return this.accessoryBean.getId(); } diff --git a/src/main/java/jcs/commandStation/events/JCSActionEvent.java b/src/main/java/jcs/commandStation/events/JCSActionEvent.java new file mode 100644 index 00000000..49a278bd --- /dev/null +++ b/src/main/java/jcs/commandStation/events/JCSActionEvent.java @@ -0,0 +1,30 @@ +/* + * Copyright 2025 Frans Jacobs. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package jcs.commandStation.events; + +/** + * + * An Action is required on the implemented delegate Event Object. + */ +public interface JCSActionEvent { + + /** + * + * @return the id of the Object which requires an action + */ + String getId(); + +} diff --git a/src/main/java/jcs/commandStation/events/SensorEvent.java b/src/main/java/jcs/commandStation/events/SensorEvent.java index 2021fcfb..b498b2f8 100755 --- a/src/main/java/jcs/commandStation/events/SensorEvent.java +++ b/src/main/java/jcs/commandStation/events/SensorEvent.java @@ -18,21 +18,27 @@ import jcs.entities.SensorBean; /** - * - * @author Frans Jacobs + * Value change happened on a Sensor. */ -public class SensorEvent { +public class SensorEvent implements JCSActionEvent { private final SensorBean sensorBean; + private final boolean newValue; public SensorEvent(SensorBean sensorBean) { + this(sensorBean, sensorBean.isActive()); + } + + public SensorEvent(SensorBean sensorBean, boolean newValue) { this.sensorBean = sensorBean; + this.newValue = newValue; } public SensorBean getSensorBean() { return sensorBean; } + @Override public String getId() { if (sensorBean.getId() != null) { return sensorBean.getId(); @@ -51,21 +57,21 @@ public String getId() { } public Integer getDeviceId() { - return this.sensorBean.getDeviceId(); + return sensorBean.getDeviceId(); } public Integer getContactId() { - return this.sensorBean.getContactId(); + return sensorBean.getContactId(); } public boolean isChanged() { - boolean active = sensorBean.isActive(); + //boolean active = sensorBean.isActive(); boolean prevActive = sensorBean.isPreviousActive(); - return active != prevActive; + return newValue != prevActive; } public boolean isActive() { - return sensorBean.isActive(); + return newValue; //sensorBean.isActive(); } @Override diff --git a/src/main/java/jcs/entities/SensorBean.java b/src/main/java/jcs/entities/SensorBean.java index 74a76cf2..4f341f8f 100755 --- a/src/main/java/jcs/entities/SensorBean.java +++ b/src/main/java/jcs/entities/SensorBean.java @@ -147,7 +147,7 @@ public void toggle() { status = 0; } previousStatus = status; - Date lastChanged = this.lastUpdated; + Date lastChanged = lastUpdated; if (lastChanged == null) { lastChanged = new Date(); } @@ -177,8 +177,14 @@ public Date getLastUpdated() { return lastUpdated; } - public void setLastUpdated(Date lastUpdated) { - this.lastUpdated = lastUpdated; + public void setLastUpdated(Date updatedOn) { + Date prevUpdated = lastUpdated; + lastUpdated = updatedOn; + + if (lastUpdated != null && prevUpdated != null) { + Long m = (updatedOn.getTime() - prevUpdated.getTime()) / 10; + this.millis = m.intValue(); + } } @Transient @@ -191,22 +197,28 @@ public boolean isActive() { } public void setActive(boolean active) { - this.status = active ? 1 : 0; + previousStatus = status; + status = active ? 1 : 0; } public void setPreviousActive(boolean active) { - this.previousStatus = active ? 1 : 0; + previousStatus = active ? 1 : 0; } @Transient public boolean isPreviousActive() { - if (this.previousStatus != null) { - return this.previousStatus > 0; + if (previousStatus != null) { + return previousStatus > 0; } else { return false; } } + @Transient + public boolean hasChanged() { + return !status.equals(previousStatus); + } + @Override public int hashCode() { int hash = 3; diff --git a/src/main/java/jcs/ui/layout/LayoutCanvas.form b/src/main/java/jcs/ui/layout/LayoutCanvas.form index 3a7b262c..884eba14 100755 --- a/src/main/java/jcs/ui/layout/LayoutCanvas.form +++ b/src/main/java/jcs/ui/layout/LayoutCanvas.form @@ -1 +1,233 @@ -

\ No newline at end of file + + +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
diff --git a/src/main/java/jcs/ui/layout/LayoutCanvas.java b/src/main/java/jcs/ui/layout/LayoutCanvas.java index bc89dd21..860c36fd 100755 --- a/src/main/java/jcs/ui/layout/LayoutCanvas.java +++ b/src/main/java/jcs/ui/layout/LayoutCanvas.java @@ -38,14 +38,11 @@ import javax.swing.JPopupMenu; import javax.swing.SwingUtilities; import jcs.JCS; -import jcs.commandStation.FeedbackController; import jcs.commandStation.autopilot.AutoPilot; -import jcs.commandStation.events.SensorEvent; import jcs.entities.AccessoryBean; import jcs.entities.BlockBean; import jcs.entities.BlockBean.BlockState; import jcs.entities.LocomotiveBean; -import jcs.entities.SensorBean; import jcs.entities.TileBean; import jcs.entities.TileBean.Direction; import jcs.entities.TileBean.Orientation; @@ -61,6 +58,7 @@ import static jcs.entities.TileBean.TileType.STRAIGHT_DIR; import static jcs.entities.TileBean.TileType.SWITCH; import jcs.persistence.PersistenceFactory; +import static jcs.ui.layout.LayoutCanvas.Mode.CONTROL; import jcs.ui.layout.dialogs.BlockControlDialog; import jcs.ui.layout.dialogs.BlockDialog; import jcs.ui.layout.dialogs.SensorDialog; @@ -139,6 +137,10 @@ private void postInit() { routesDialog = new RoutesDialog(getParentFrame(), false, this, this.readonly); } + public boolean isReadonly() { + return readonly; + } + @Override public void paint(Graphics g) { //long started = System.currentTimeMillis(); @@ -256,7 +258,7 @@ void loadLayoutInBackground() { } private void loadTiles() { - List tiles = TileCache.loadTiles(); + List tiles = TileCache.loadTiles(readonly); removeAll(); selectedTile = null; @@ -284,7 +286,8 @@ private void mousePressedAction(MouseEvent evt) { //Clear any previous selection Tile previousSelected = selectedTile; selectedTile = TileCache.findTile(snapPoint); - if (selectedTile != null) { + //Only show selected tile in edit mode + if (selectedTile != null && CONTROL != mode) { selectedTile.setSelected(true); } @@ -460,7 +463,7 @@ private void executeControlActionForTile(Tile tile, Point p) { case CURVED -> { } case SENSOR -> { - this.executor.execute(() -> toggleSensor((Sensor) tile)); + //this.executor.execute(() -> toggleSensor((Sensor) tile)); } case BLOCK -> { Logger.trace("Show BlockDialog for " + tile.getId()); @@ -505,24 +508,22 @@ private void toggleSignal(Signal signal) { } } - private void toggleSensor(Sensor sensor) { - SensorBean sb = sensor.getSensorBean(); - if (sb != null) { - sb.toggle(); - sensor.setActive((sb.getStatus() == 1)); - Logger.trace("id: " + sb.getId() + " state " + sb.getStatus()); - SensorEvent sensorEvent = new SensorEvent(sb); - fireFeedbackEvent(sensorEvent); - } - } - - private void fireFeedbackEvent(SensorEvent sensorEvent) { - List acl = JCS.getJcsCommandStation().getFeedbackControllers(); - for (FeedbackController fbc : acl) { - fbc.fireSensorEventListeners(sensorEvent); - } - } - +// private void toggleSensor(Sensor sensor) { +// SensorBean sb = sensor.getSensorBean(); +// if (sb != null) { +// sb.toggle(); +// sensor.setActive((sb.getStatus() == 1)); +// Logger.trace("id: " + sb.getId() + " state " + sb.getStatus()); +// SensorEvent sensorEvent = new SensorEvent(sb); +// fireFeedbackEvent(sensorEvent); +// } +// } +// private void fireFeedbackEvent(SensorEvent sensorEvent) { +// List acl = JCS.getJcsCommandStation().getFeedbackControllers(); +// for (FeedbackController fbc : acl) { +// fbc.fireSensorEventListeners(sensorEvent); +// } +// } private void editSelectedTileProperties() { //the first tile should be the selected one boolean showProperties = false; @@ -940,7 +941,6 @@ private void horizontalMIActionPerformed(ActionEvent evt) {//GEN-FIRST:event_hor Logger.trace(this.orientation + ", " + evt.getModifiers() + ", " + evt.paramString()); if (this.mouseLocation != null && evt.getModifiers() == ActionEvent.MOUSE_EVENT_MASK) { - //addTile(this.mouseLocation); this.mouseLocation = null; } }//GEN-LAST:event_horizontalMIActionPerformed @@ -949,7 +949,6 @@ private void verticalMIActionPerformed(ActionEvent evt) {//GEN-FIRST:event_verti Logger.trace(this.orientation + ", " + evt.getModifiers() + ", " + evt.paramString()); if (this.mouseLocation != null && evt.getModifiers() == ActionEvent.MOUSE_EVENT_MASK) { - //addTile(this.mouseLocation); this.mouseLocation = null; } }//GEN-LAST:event_verticalMIActionPerformed @@ -958,7 +957,6 @@ private void rightMIActionPerformed(ActionEvent evt) {//GEN-FIRST:event_rightMIA Logger.trace(this.orientation + ", " + evt.getModifiers() + ", " + evt.paramString()); if (this.mouseLocation != null && evt.getModifiers() == ActionEvent.MOUSE_EVENT_MASK) { - //addTile(this.mouseLocation); this.mouseLocation = null; } }//GEN-LAST:event_rightMIActionPerformed @@ -967,7 +965,6 @@ private void leftMIActionPerformed(ActionEvent evt) {//GEN-FIRST:event_leftMIAct Logger.trace(this.orientation + ", " + evt.getModifiers() + ", " + evt.paramString()); if (this.mouseLocation != null && evt.getModifiers() == ActionEvent.MOUSE_EVENT_MASK) { - //addTile(this.mouseLocation); this.mouseLocation = null; } }//GEN-LAST:event_leftMIActionPerformed @@ -1129,6 +1126,7 @@ private void resetGhostMIActionPerformed(ActionEvent evt) {//GEN-FIRST:event_res if (this.selectedTile != null) { Block block = (Block) selectedTile; BlockBean.BlockState currentState = block.getBlockState(); + if (BlockBean.BlockState.GHOST == currentState) { if (block.getBlockBean().getLocomotiveId() != null) { block.setBlockState(BlockBean.BlockState.OCCUPIED); diff --git a/src/main/java/jcs/ui/layout/dialogs/SensorDialog.java b/src/main/java/jcs/ui/layout/dialogs/SensorDialog.java index baf222ca..0d7f2c20 100644 --- a/src/main/java/jcs/ui/layout/dialogs/SensorDialog.java +++ b/src/main/java/jcs/ui/layout/dialogs/SensorDialog.java @@ -69,7 +69,7 @@ private void postInit() { usedSensorIds.add(tb.getSensorId()); } } - //Filter the unused turnouts + //Filter the unused sensors List filtered = new ArrayList<>(); for (SensorBean sb : sensors) { if (!usedSensorIds.contains(sb.getId())) { diff --git a/src/main/java/jcs/ui/layout/tiles/Sensor.java b/src/main/java/jcs/ui/layout/tiles/Sensor.java index 25ecf42b..baedc593 100644 --- a/src/main/java/jcs/ui/layout/tiles/Sensor.java +++ b/src/main/java/jcs/ui/layout/tiles/Sensor.java @@ -65,7 +65,6 @@ public void onSensorChange(SensorEvent event) { SensorBean sensor = event.getSensorBean(); if (sensor.equalsDeviceIdAndContactId(getSensorBean())) { setActive(sensor.isActive()); - repaint(); } } diff --git a/src/main/java/jcs/ui/layout/tiles/Tile.java b/src/main/java/jcs/ui/layout/tiles/Tile.java index e36a3df1..144fdb56 100755 --- a/src/main/java/jcs/ui/layout/tiles/Tile.java +++ b/src/main/java/jcs/ui/layout/tiles/Tile.java @@ -78,13 +78,13 @@ public abstract class Tile extends JComponent { // implements ChangeListener public static final int GRID = 20; public static final int DEFAULT_WIDTH = GRID * 2; public static final int DEFAULT_HEIGHT = GRID * 2; - + public static final Color DEFAULT_BACKGROUND_COLOR = Color.white; public static final Color DEFAULT_TRACK_COLOR = Color.lightGray; public static final Color DEFAULT_ROUTE_TRACK_COLOR = Color.darkGray; public static final Color DEFAULT_SELECTED_COLOR = Color.yellow; public static final Color DEFAULT_WARN_COLOR = Color.red; - + public static final String MODEL_CHANGED_PROPERTY = "model"; // public static final String CONTENT_AREA_FILLED_CHANGED_PROPERTY = "contentAreaFilled"; @@ -92,73 +92,73 @@ public abstract class Tile extends JComponent { // implements ChangeListener * The data model that determines the Tile state. */ protected TileModel model = null; - + protected String id; protected Integer tileX; protected Integer tileY; - + protected Direction tileDirection; - + protected TileType tileType; protected String accessoryId; protected String sensorId; - + protected AccessoryValue accessoryValue; protected AccessoryValue routeValue; - + protected SignalType signalType; protected AccessoryBean.SignalValue signalValue; - + protected TileBean tileBean; protected AccessoryBean accessoryBean; protected SensorBean sensorBean; protected BlockBean blockBean; - + protected List neighbours; - + protected int renderOffsetX = 0; protected int renderOffsetY = 0; - + protected boolean drawName = true; - + protected BufferedImage tileImage; - + protected PropertyChangeListener propertyChangeListener; - + protected ChangeListener changeListener = null; protected ActionListener actionListener = null; - + protected transient ChangeEvent changeEvent; private Handler handler; - + protected Tile(TileType tileType, Orientation orientation, Point center, int width, int height) { this(tileType, orientation, Direction.CENTER, center.x, center.y, width, height); } - + protected Tile(TileType tileType, Orientation orientation, int x, int y, int width, int height) { this(tileType, orientation, Direction.CENTER, x, y, width, height); } - + protected Tile(TileType tileType, Orientation orientation, Direction direction, int x, int y, int width, int height) { this(tileType, orientation, direction, x, y, width, height, null, null); } - + protected Tile(TileType tileType, Orientation orientation, Direction direction, int x, int y, int width, int height, Color backgroundColor, Color selectedColor) { this.tileType = tileType; this.tileDirection = direction; this.tileX = x; this.tileY = y; - + setLayout(null); Dimension d = new Dimension(width, height); setSize(d); setPreferredSize(d); } - + protected Tile(TileBean tileBean) { this(tileBean, tileWidth(tileBean.getOrientation(), tileBean.getTileType()), tileHeight(tileBean.getOrientation(), tileBean.getTileType())); } - + protected Tile(TileBean tileBean, int width, int height) { this.tileBean = tileBean; this.id = tileBean.getId(); @@ -166,66 +166,66 @@ protected Tile(TileBean tileBean, int width, int height) { this.tileDirection = tileBean.getDirection(); this.tileX = tileBean.getX(); this.tileY = tileBean.getY(); - + this.accessoryId = tileBean.getAccessoryId(); this.accessoryBean = tileBean.getAccessoryBean(); this.signalType = tileBean.getSignalType(); - + this.sensorId = tileBean.getSensorId(); this.sensorBean = tileBean.getSensorBean(); this.blockBean = tileBean.getBlockBean(); - + setLayout(null); Dimension d = new Dimension(width, height); setSize(d); setPreferredSize(d); } - + @Override public String getUIClassID() { return TileUI.UI_CLASS_ID; } - + @Override public TileUI getUI() { return (TileUI) ui; } - + public void setUI(TileUI ui) { super.setUI(ui); } - + public TileModel getModel() { return model; } - + public void setModel(TileModel newModel) { TileModel oldModel = getModel(); - + if (oldModel != null) { oldModel.removeChangeListener(changeListener); oldModel.removeActionListener(actionListener); changeListener = null; actionListener = null; } - + model = newModel; - + if (newModel != null) { changeListener = createChangeListener(); actionListener = createActionListener(); - + newModel.addChangeListener(changeListener); newModel.addActionListener(actionListener); } - + firePropertyChange(MODEL_CHANGED_PROPERTY, oldModel, newModel); if (newModel != oldModel) { revalidate(); repaint(); } } - + protected static int tileWidth(Orientation orientation, TileType tileType) { if (Orientation.EAST == orientation || Orientation.WEST == orientation) { if (null == tileType) { @@ -244,7 +244,7 @@ protected static int tileWidth(Orientation orientation, TileType tileType) { return DEFAULT_WIDTH; } } - + protected static int tileHeight(Orientation orientation, TileType tileType) { if (Orientation.EAST == orientation || Orientation.WEST == orientation) { return DEFAULT_HEIGHT; @@ -263,7 +263,7 @@ protected static int tileHeight(Orientation orientation, TileType tileType) { } } } - + protected void populateModel() { if (this.blockBean != null) { this.model.setBlockState(this.blockBean.getBlockState()); @@ -272,7 +272,7 @@ protected void populateModel() { this.model.setLogicalDirection(LocomotiveBean.Direction.get(this.blockBean.getLogicalDirection())); } } - + public TileBean getTileBean() { if (tileBean == null) { tileBean = new TileBean(); @@ -281,7 +281,19 @@ public TileBean getTileBean() { tileBean.setY(this.tileY); tileBean.setTileType(this.tileType); tileBean.setTileOrientation(this.model.getTileOrienation().getOrientation()); - + + tileBean.setTileDirection(this.tileDirection.getDirection()); + tileBean.setSignalType(this.signalType); + tileBean.setAccessoryId(this.accessoryId); + tileBean.setSensorId(this.sensorId); + tileBean.setAccessoryBean(this.accessoryBean); + tileBean.setSensorBean(this.sensorBean); + tileBean.setBlockBean(this.blockBean); + } else { + //update + tileBean.setX(this.tileX); + tileBean.setY(this.tileY); + tileBean.setTileOrientation(this.model.getTileOrienation().getOrientation()); tileBean.setTileDirection(this.tileDirection.getDirection()); tileBean.setSignalType(this.signalType); tileBean.setAccessoryId(this.accessoryId); @@ -300,23 +312,23 @@ public TileBean getTileBean() { public boolean isSelected() { return model.isSelected(); } - + public void setSelected(boolean b) { model.setSelected(b); } - + public String getId() { return id; } - + public void setId(String id) { this.id = id; } - + public SignalType getSignalType() { return signalType; } - + public void setSignalType(SignalType signalType) { this.signalType = signalType; } @@ -344,7 +356,7 @@ public Integer getTileY() { public Point getCenter() { return new Point(this.tileX, this.tileY); } - + public void setCenter(Point center) { tileX = center.x; tileY = center.y; @@ -360,56 +372,59 @@ public void setCenter(Point center) { public Orientation getOrientation() { return model.getTileOrienation(); } - + public void setOrientation(Orientation orientation) { model.setTileOrienation(orientation); if (tileBean != null) { tileBean.setOrientation(orientation); } } - + public Direction getDirection() { return tileDirection; } - + public void setDirection(Direction direction) { this.tileDirection = direction; if (tileBean != null) { tileBean.setDirection(direction); } } - + public String getAccessoryId() { return accessoryId; } - + public void setAccessoryId(String accessoryId) { this.accessoryId = accessoryId; if (tileBean != null) { tileBean.setAccessoryId(accessoryId); } } - + public String getSensorId() { return sensorId; } - + public void setSensorId(String sensorId) { this.sensorId = sensorId; } - + public boolean isActive() { return model.isSensorActive(); } - + public void setActive(boolean active) { model.setSensorActive(active); + if (this.sensorBean != null) { + this.sensorBean.setActive(active); + } } - + public BlockState getBlockState() { return model.getBlockState(); } - + public void setBlockState(BlockState blockState) { if (blockBean != null) { blockBean.setBlockState(blockState); @@ -418,60 +433,60 @@ public void setBlockState(BlockState blockState) { } model.setBlockState(blockState); } - + public String getDepartureSuffix() { return model.getDepartureSuffix(); } - + public void setDepartureSuffix(String suffix) { if (blockBean != null) { blockBean.setDepartureSuffix(suffix); } model.setDepartureSuffix(suffix); } - + public boolean isReverseArrival() { return model.isReverseArrival(); } - + public void setReverseArrival(boolean reverseArrival) { if (blockBean != null) { blockBean.setReverseArrival(reverseArrival); } model.setReverseArrival(reverseArrival); } - + public LocomotiveBean.Direction getLogicalDirection() { return model.getLogicalDirection(); } - + public void setLogicalDirection(LocomotiveBean.Direction logicalDirection) { if (blockBean != null) { blockBean.setLogicalDirection(logicalDirection.getDirection()); } model.setLogicalDirection(logicalDirection); } - + public LocomotiveBean getLocomotive() { return model.getLocomotive(); } - + public void setLocomotive(LocomotiveBean locomotive) { if (blockBean != null) { blockBean.setLocomotive(locomotive); model.setOverlayImage(locomotive != null && locomotive.getLocIcon() != null && (model.getBlockState() == BlockState.OCCUPIED || model.getBlockState() == BlockState.INBOUND || model.getBlockState() == BlockState.OUTBOUND)); } - + model.setLocomotive(locomotive); } - + public AccessoryBean getAccessoryBean() { return accessoryBean; } - + public void setAccessoryBean(AccessoryBean accessoryBean) { this.accessoryBean = accessoryBean; - + if (accessoryBean != null) { accessoryId = accessoryBean.getId(); signalValue = accessoryBean.getSignalValue(); @@ -482,7 +497,7 @@ public void setAccessoryBean(AccessoryBean accessoryBean) { signalValue = AccessoryBean.SignalValue.OFF; } } - + public AccessoryValue getAccessoryValue() { if (this.accessoryValue == null) { return AccessoryValue.OFF; @@ -490,12 +505,12 @@ public AccessoryValue getAccessoryValue() { return accessoryValue; } } - + public void setAccessoryValue(AccessoryValue value) { this.accessoryValue = value; repaint(); } - + public AccessoryValue getRouteValue() { if (routeValue == null) { return AccessoryValue.OFF; @@ -503,93 +518,93 @@ public AccessoryValue getRouteValue() { return routeValue; } } - + public void setRouteValue(AccessoryValue value) { this.routeValue = value; repaint(); } - + public AccessoryBean.SignalValue getSignalValue() { return signalValue; } - + public void setSignalValue(AccessoryBean.SignalValue signalValue) { this.signalValue = signalValue; repaint(); } - + public SensorBean getSensorBean() { return sensorBean; } - + public void setSensorBean(SensorBean sensorBean) { this.sensorBean = sensorBean; } - + public BlockBean getBlockBean() { return blockBean; } - + public void setBlockBean(BlockBean blockBean) { this.blockBean = blockBean; } - + public int getRenderOffsetX() { return renderOffsetX; } - + public void setRenderOffsetX(int renderOffsetX) { this.renderOffsetX = renderOffsetX; } - + public int getRenderOffsetY() { return renderOffsetY; } - + public void setRenderOffsetY(int renderOffsetY) { this.renderOffsetY = renderOffsetY; } - + public TileBean.TileType getTileType() { return this.tileType; } - + public final void setTileType(TileType tileType) { this.tileType = tileType; } - + public void setTrackColor(Color trackColor) { if (getUI() != null) { getUI().setTrackColor(trackColor); } } - + public void setTrackRouteColor(Color trackRouteColor) { if (getUI() != null) { getUI().setTrackRouteColor(trackRouteColor); } } - + public Color getSelectedColor() { return model.getSelectedColor(); } - + public void setSelectedColor(Color selectedColor) { model.setSelectedColor(selectedColor); } - + public Orientation getIncomingSide() { return model.getIncomingSide(); } - + public void setIncomingSide(Orientation incomingSide) { model.setIncomingSide(incomingSide); } - + public boolean isShowRoute() { return model.isShowRoute(); } - + public void setShowRoute(boolean drawRoute) { this.model.setShowRoute(drawRoute); } @@ -602,17 +617,17 @@ public void setShowRoute(boolean drawRoute) { * */ public abstract Map getNeighborPoints(); - + public abstract Map getEdgePoints(); - + Set getAltPoints(Point center) { return Collections.EMPTY_SET; } - + public Set getAllPoints() { return getAllPoints(getCenter()); } - + Set getAllPoints(Point center) { Set aps = new HashSet<>(); aps.add(center); @@ -638,7 +653,7 @@ public Orientation rotate() { } return model.getTileOrienation(); } - + public void flipHorizontal() { Orientation tileOrientation = model.getTileOrienation(); if (Orientation.NORTH == tileOrientation || Orientation.SOUTH == tileOrientation) { @@ -646,7 +661,7 @@ public void flipHorizontal() { rotate(); } } - + public void flipVertical() { Orientation tileOrientation = model.getTileOrienation(); if (Orientation.EAST == tileOrientation || Orientation.WEST == tileOrientation) { @@ -654,41 +669,41 @@ public void flipVertical() { rotate(); } } - + @Override public void move(int newX, int newY) { Point cs = LayoutUtil.snapToGrid(newX, newY); setCenter(cs); } - + public static BufferedImage flipHorizontally(BufferedImage source) { BufferedImage output = new BufferedImage(source.getHeight(), source.getWidth(), source.getType()); - + AffineTransform flip = AffineTransform.getScaleInstance(1, -1); flip.translate(0, -source.getHeight()); AffineTransformOp op = new AffineTransformOp(flip, AffineTransformOp.TYPE_NEAREST_NEIGHBOR); - + op.filter(source, output); - + return output; } - + public static BufferedImage flipVertically(BufferedImage source) { BufferedImage output = new BufferedImage(source.getHeight(), source.getWidth(), source.getType()); - + AffineTransform flip = AffineTransform.getScaleInstance(-1, 1); flip.translate(-source.getWidth(), 0); AffineTransformOp op = new AffineTransformOp(flip, AffineTransformOp.TYPE_NEAREST_NEIGHBOR); - + op.filter(source, output); - + return output; } - + public Set getAltPoints() { return Collections.EMPTY_SET; } - + public int getCenterX() { if (tileX > 0) { return this.tileX; @@ -696,7 +711,7 @@ public int getCenterX() { return GRID; } } - + public int getCenterY() { if (tileY > 0) { return this.tileY; @@ -704,19 +719,19 @@ public int getCenterY() { return GRID; } } - + public boolean isDrawName() { return drawName; } - + public void setDrawName(boolean drawName) { this.drawName = drawName; } - + public boolean isScaleImage() { return model.isScaleImage(); } - + public void setScaleImage(boolean scaleImage) { Dimension d; if (scaleImage) { @@ -724,23 +739,23 @@ public void setScaleImage(boolean scaleImage) { } else { int renderWidth = getUI().getRenderWidth(); int renderHeight = getUI().getRenderHeight(); - + d = new Dimension(renderWidth, renderHeight); } - + setSize(d); setPreferredSize(d); model.setScaleImage(scaleImage); } - + public boolean isDrawCenterPoint() { return model.isShowCenter(); } - + public void setDrawCenterPoint(boolean drawCenterPoint) { model.setShowCenter(drawCenterPoint); } - + @Override public String toString() { return this.getClass().getSimpleName() @@ -754,7 +769,7 @@ public String toString() { + xyToString() + "}"; } - + public String xyToString() { return "(" + this.tileX + "," + this.tileY + ")"; } @@ -778,15 +793,15 @@ public boolean isVertical() { Orientation tileOrientation = model.getTileOrienation(); return (Orientation.NORTH == tileOrientation || Orientation.SOUTH == tileOrientation) && TileType.CURVED != tileType; } - + public boolean isJunction() { return TileType.SWITCH == tileType || TileType.CROSS == tileType; } - + public boolean isBlock() { return TileType.BLOCK == tileType; } - + public boolean isDirectional() { return TileType.STRAIGHT_DIR == tileType; } @@ -799,52 +814,52 @@ public boolean isDirectional() { public boolean isDiagonal() { return TileType.CURVED == tileType; } - + public boolean isCrossing() { return TileType.CROSSING == tileType; } - + public List getNeighbours() { return neighbours; } - + public void setNeighbours(List neighbours) { this.neighbours = neighbours; } - + public String getIdSuffix(Tile other) { return ""; } - + public Map getNeighborOrientations() { Map edgeOrientations = new HashMap<>(); - + Map neighborPoints = getNeighborPoints(); - + for (Orientation o : Orientation.values()) { edgeOrientations.put(neighborPoints.get(o), o); } return edgeOrientations; } - + public Map getEdgeOrientations() { Map edgeOrientations = new HashMap<>(); - + Map edgeConnections = getEdgePoints(); - + for (Orientation o : Orientation.values()) { edgeOrientations.put(edgeConnections.get(o), o); } return edgeOrientations; } - + public boolean isAdjacent(Tile other) { boolean adjacent = false; - + if (other != null) { Collection thisEdgePoints = getEdgePoints().values(); Collection otherEdgePoints = other.getEdgePoints().values(); - + for (Point p : thisEdgePoints) { adjacent = otherEdgePoints.contains(p); if (adjacent) { @@ -852,7 +867,7 @@ public boolean isAdjacent(Tile other) { } } } - + return adjacent; } @@ -866,40 +881,40 @@ public boolean isAdjacent(Tile other) { public boolean isArrowDirection(Tile other) { return true; } - + public AccessoryValue accessoryValueForRoute(Orientation from, Orientation to) { return AccessoryValue.OFF; } - + protected ChangeListener createChangeListener() { return getHandler(); } - + protected ActionListener createActionListener() { return getHandler(); } - + private Handler getHandler() { if (handler == null) { handler = new Handler(); } return handler; } - + class Handler implements ActionListener, ChangeListener, Serializable { - + @Override public void stateChanged(ChangeEvent e) { fireStateChanged(); repaint(); } - + @Override public void actionPerformed(ActionEvent event) { fireActionPerformed(event); } } - + protected void fireStateChanged() { Object[] listeners = listenerList.getListenerList(); //reverse order @@ -913,7 +928,7 @@ protected void fireStateChanged() { } } } - + protected void fireActionPerformed(ActionEvent event) { Object[] listeners = listenerList.getListenerList(); ActionEvent e = null; @@ -932,26 +947,26 @@ protected void fireActionPerformed(ActionEvent event) { } } } - + public Rectangle getTileBounds() { if (model.isScaleImage()) { return new Rectangle(tileX - GRID, tileY - GRID, DEFAULT_WIDTH, DEFAULT_HEIGHT); } else { int renderWidth = getUI().getRenderWidth(); int renderHeight = getUI().getRenderHeight(); - + return new Rectangle(tileX - renderWidth / 2, tileY - renderHeight / 2, renderWidth, renderHeight); } } - - @Override - protected void paintComponent(Graphics g) { - if (Logger.isTraceEnabled()) { - long started = System.currentTimeMillis(); - super.paintComponent(g); - long now = System.currentTimeMillis(); - Logger.trace(id + " Duration: " + (now - started) + " ms. Cp: " + xyToString() + " O: " + model.getTileOrienation()); - } - } - + +// @Override +// protected void paintComponent(Graphics g) { +// if (Logger.isTraceEnabled()) { +// long started = System.currentTimeMillis(); +// super.paintComponent(g); +// long now = System.currentTimeMillis(); +// Logger.trace(id + " Duration: " + (now - started) + " ms. Cp: " + xyToString() + " O: " + model.getTileOrienation()); +// } +// } + } diff --git a/src/main/java/jcs/ui/layout/tiles/TileActionEventHandler.java b/src/main/java/jcs/ui/layout/tiles/TileActionEventHandler.java new file mode 100644 index 00000000..bc36f141 --- /dev/null +++ b/src/main/java/jcs/ui/layout/tiles/TileActionEventHandler.java @@ -0,0 +1,96 @@ +/* + * Copyright 2025 fransjacobs. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package jcs.ui.layout.tiles; + +import java.util.List; +import java.util.concurrent.ConcurrentLinkedQueue; +import jcs.JCS; +import jcs.commandStation.FeedbackController; +import jcs.commandStation.events.AccessoryEvent; +import jcs.commandStation.events.JCSActionEvent; +import jcs.commandStation.events.SensorEvent; +import org.tinylog.Logger; + +/** + * + * @author fransjacobs + */ +class TileActionEventHandler extends Thread { + + private boolean stop = false; + private boolean quit = true; + + private final ConcurrentLinkedQueue eventQueue; + + TileActionEventHandler(ConcurrentLinkedQueue eventQueue) { + this.eventQueue = eventQueue; + } + + void quit() { + this.quit = true; + } + + boolean isRunning() { + return !this.quit; + } + + boolean isFinished() { + return this.stop; + } + + @Override + public void run() { + this.quit = false; + this.setName("TILE-ACTION-EVENT-HANDLER"); + + Logger.trace("Tile ActionEventHandler Started..."); + + while (isRunning()) { + try { + JCSActionEvent event = eventQueue.poll(); + if (event != null) { + if (event instanceof SensorEvent sensorEvent) { + fireSensorEvent(sensorEvent); + } + if (event instanceof AccessoryEvent) { + + } + + } else { + //lets sleep for a while + synchronized (this) { + wait(10000); + } + } + + } catch (InterruptedException ex) { + Logger.error(ex); + } + } + + stop = true; + Logger.trace("Tile ActionEventHandler Stopped..."); + } + + private void fireSensorEvent(SensorEvent sensorEvent) { + //Logger.trace("Firing Sensor Action " + sensorEvent.getId() + " -> " + sensorEvent.isActive()); + List acl = JCS.getJcsCommandStation().getFeedbackControllers(); + for (FeedbackController fbc : acl) { + fbc.fireSensorEventListeners(sensorEvent); + } + } + +} diff --git a/src/main/java/jcs/ui/layout/tiles/TileCache.java b/src/main/java/jcs/ui/layout/tiles/TileCache.java index a2f9d7c5..528b637c 100644 --- a/src/main/java/jcs/ui/layout/tiles/TileCache.java +++ b/src/main/java/jcs/ui/layout/tiles/TileCache.java @@ -20,10 +20,15 @@ import java.util.List; import java.util.Map; import java.util.Set; +import java.util.concurrent.ConcurrentLinkedQueue; import java.util.stream.Collectors; +import jcs.JCS; +import jcs.commandStation.FeedbackController; import jcs.entities.TileBean; import jcs.persistence.PersistenceFactory; import org.tinylog.Logger; +import jcs.commandStation.events.JCSActionEvent; +import jcs.commandStation.events.SensorEvent; /** * Factory object to create Tiles and cache tiles @@ -32,55 +37,26 @@ */ public class TileCache { - //private static boolean showValues; static final Map tiles = new HashMap<>(); static final Map tileAltPoints = new HashMap<>(); static final Map points = new HashMap<>(); + private static final ConcurrentLinkedQueue eventsQueue = new ConcurrentLinkedQueue(); + + private static final TileActionEventHandler actionEventQueueHandler = new TileActionEventHandler(eventsQueue); + + static { + actionEventQueueHandler.start(); + } + private TileCache() { } -// @Deprecated -// public static void setShowValues(boolean showValues) { -// TileCache.showValues = showValues; -// -// for (Tile tile : tiles.values()) { -// TileType tileType = tile.getTileType(); -// switch (tileType) { -// case SWITCH -> { -// if (showValues && ((Switch) tile).getTileBean().getAccessoryBean() != null) { -// tile.setAccessoryValue(tile.getTileBean().getAccessoryBean().getAccessoryValue()); -// } else { -// tile.setAccessoryValue(AccessoryValue.OFF); -// } -// } -// case CROSS -> { -// if (showValues && ((Cross) tile).getTileBean().getAccessoryBean() != null) { -// tile.setAccessoryValue(tile.getTileBean().getAccessoryBean().getAccessoryValue()); -// } else { -// tile.setAccessoryValue(AccessoryValue.OFF); -// } -// } -// case SIGNAL -> { -// if (showValues && ((Signal) tile).getTileBean().getAccessoryBean() != null) { -// tile.setSignalValue(tile.getTileBean().getAccessoryBean().getSignalValue()); -// } else { -// tile.setSignalValue(SignalValue.OFF); -// } -// } -// case SENSOR -> { -// if (showValues && ((Sensor) tile).getTileBean().getSensorBean() != null) { -// tile.setActive(tile.getTileBean().getSensorBean().isActive()); -// } else { -// tile.setActive(false); -// } -// } -// case BLOCK -> { -// } -// } -// } -// } public static List loadTiles() { + return loadTiles(false); + } + + public static List loadTiles(boolean showvalues) { tileAltPoints.clear(); points.clear(); tiles.clear(); @@ -88,7 +64,7 @@ public static List loadTiles() { List tileBeans = PersistenceFactory.getService().getTileBeans(); for (TileBean tb : tileBeans) { - Tile tile = TileFactory.createTile(tb, false); + Tile tile = TileFactory.createTile(tb, showvalues); tiles.put(tile.getCenter(), tile); points.put(tile.getId(), tile.getCenter()); //Alternative point(s) to be able to find all points @@ -98,6 +74,8 @@ public static List loadTiles() { tileAltPoints.put(ap, tile); } } + //Extra actions for some tile of tiles + } Logger.trace("Loaded " + tiles.size() + " Tiles..."); @@ -225,67 +203,6 @@ public static void moveTo(Tile tile, Point p) { } } -// @Deprecated -// public static boolean checkTileOccupation(Tile tile) { -// Set tilePoints = tile.getAllPoints(); -// for (Point p : tilePoints) { -// if (tiles.containsKey(p) || tileAltPoints.containsKey(p)) { -// //The is a match, check if it is an other tile -// Tile mt = findTile(p); -// if (tile.getId().equals(mt.getId())) { -// //same tile continue -// } else { -// //Other tile so really occupied -// return true; -// } -// } -// } -// return false; -// } -// @Deprecated -// public static boolean containsPoint(Set points) { -// for (Point p : points) { -// return tiles.containsKey(p) || tileAltPoints.containsKey(p); -// } -// return false; -// } -// public static boolean containsPoint(Point point) { -// return tiles.containsKey(point) || tileAltPoints.containsKey(point); -// } -// @Deprecated -// public static Point checkAvailable(Point newPoint, Orientation orientation) { -// if (tiles.containsKey(newPoint)) { -// Tile et = tiles.get(newPoint); -// Logger.trace("@ " + newPoint + " is allready occcupied by: " + et + "..."); -// //Search for the nearest avalaible free point -// //first get the Center point of the tile which is occuping this slot -// // show warning! -// Point ecp = et.getCenter(); -// -// int w = et.getWidth(); -// int h = et.getHeight(); -// -// Point np; -// np = switch (orientation) { -// case EAST -> -// new Point(ecp.x + w, ecp.y); -// case WEST -> -// new Point(newPoint.x - w, ecp.y); -// case SOUTH -> -// new Point(ecp.x, newPoint.y + h); -// default -> -// new Point(ecp.x, newPoint.y - h); -// }; -// -// Logger.trace("Alternative CP: " + np); -// // recursive check -// return checkAvailable(np, orientation); -// } else { -// Logger.trace("@ " + newPoint + " is not yet used..."); -// -// return newPoint; -// } -// } public static Tile rotateTile(Tile tile) { if (!tiles.containsKey(tile.getCenter())) { Logger.warn("Tile " + tile.getId() + " NOT in cache!"); @@ -341,36 +258,11 @@ private static Tile flipTile(Tile tile, boolean horizontal) { return tile; } -// @Deprecated -// public static void addTileEventListener(TileEventListener listener) { -// String key = listener.getId(); -// //tileEventListeners.put(key, listener); -// } -// @Deprecated -// public static void removeTileEventListener(Tile tile) { -// if (tile instanceof TileEventListener tileEventListener) { -// removeTileEventListener(tileEventListener); -// } -// } -// static void removeTileEventListener(TileEventListener listener) { -// String key = listener.getId(); -// //tileEventListeners.remove(key, listener); -// } -// @Deprecated -// public static void fireTileEventListener(TileEvent tileEvent) { -//// String key = tileEvent.getTileId(); -//// TileEventListener listener = tileEventListeners.get(key); -//// if (listener != null) { -//// listener.onTileChange(tileEvent); -//// Logger.trace("Fire listener on tile " + key); -//// } else { -//// //Logger.trace("Tile " + key + " not available"); -//// } -// } -// @Deprecated -// public static void fireAllTileEventListeners(TileEvent tileEvent) { -//// for (TileEventListener listener : tileEventListeners.values()) { -//// listener.onTileChange(tileEvent); -//// } -// } + public static void enqueTileAction(JCSActionEvent jcsEvent) { + eventsQueue.offer(jcsEvent); + synchronized (TileCache.actionEventQueueHandler) { + actionEventQueueHandler.notifyAll(); + } + } + } diff --git a/src/main/java/jcs/ui/layout/tiles/TileFactory.java b/src/main/java/jcs/ui/layout/tiles/TileFactory.java index 5b0439c2..0e6c6b0d 100755 --- a/src/main/java/jcs/ui/layout/tiles/TileFactory.java +++ b/src/main/java/jcs/ui/layout/tiles/TileFactory.java @@ -1 +1,320 @@ -/* * Copyright 2023 Frans Jacobs. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package jcs.ui.layout.tiles; import java.awt.Point; import java.util.LinkedList; import java.util.List; import jcs.JCS; import jcs.commandStation.events.AccessoryEventListener; import jcs.commandStation.events.SensorEventListener; import jcs.entities.AccessoryBean; import jcs.entities.SensorBean; import jcs.entities.TileBean; import jcs.entities.TileBean.Direction; import jcs.entities.TileBean.Orientation; import static jcs.entities.TileBean.TileType.BLOCK; import static jcs.entities.TileBean.TileType.CROSS; import static jcs.entities.TileBean.TileType.CROSSING; import static jcs.entities.TileBean.TileType.CURVED; import static jcs.entities.TileBean.TileType.END; import static jcs.entities.TileBean.TileType.SENSOR; import static jcs.entities.TileBean.TileType.SIGNAL; import static jcs.entities.TileBean.TileType.STRAIGHT; import static jcs.entities.TileBean.TileType.STRAIGHT_DIR; import static jcs.entities.TileBean.TileType.SWITCH; import org.tinylog.Logger; /** * Factory object to create Tiles and cache tiles * * @author frans */ public class TileFactory { // Keep the records of the used id sequence number private static int straightIdSeq; private static int crossingIdSeq; private static int curvedIdSeq; private static int switchIdSeq; private static int crossIdSeq; private static int signalIdSeq; private static int sensorIdSeq; private static int blockIdSeq; private static int straightDirectionIdSeq; private static int endIdSeq; private TileFactory() { } private static int nextIdSeq(String id) { String idnr = id.substring(3); int idSeq = Integer.parseInt(idnr); return idSeq; } private static String nextTileId(TileBean.TileType tileType) { switch (tileType) { case STRAIGHT -> { straightIdSeq++; return "st-" + straightIdSeq; } case CROSSING -> { crossingIdSeq++; return "cr-" + crossingIdSeq; } case CURVED -> { curvedIdSeq++; return "ct-" + curvedIdSeq; } case SWITCH -> { switchIdSeq++; return "sw-" + switchIdSeq; } case CROSS -> { crossIdSeq++; return "cs-" + crossIdSeq; } case SIGNAL -> { signalIdSeq++; return "si-" + signalIdSeq; } case SENSOR -> { sensorIdSeq++; return "se-" + sensorIdSeq; } case BLOCK -> { blockIdSeq++; return "bk-" + blockIdSeq; } case STRAIGHT_DIR -> { straightDirectionIdSeq++; return "sd-" + straightDirectionIdSeq; } case END -> { endIdSeq++; return "et-" + endIdSeq; } default -> { Logger.warn("Unknown Tile Type " + tileType); return null; } } } private static int maxIdSeq(int currentId, int newId) { if (currentId < newId) { return newId; } else { return currentId; } } public static Tile createTile(String tileId) { TileBean tileBean = JCS.getPersistenceService().getTileBean(tileId); return createTile(tileBean); } public static Tile createTile(TileBean tileBean) { return createTile(tileBean, false); } public static Tile createTile(TileBean tileBean, boolean showValues) { if (tileBean == null) { return null; } TileBean.TileType tileType = tileBean.getTileType(); Tile tile = null; switch (tileType) { case STRAIGHT -> { tile = new Straight(tileBean); straightIdSeq = maxIdSeq(straightIdSeq, nextIdSeq(tileBean.getId())); } case CROSSING -> { tile = new Crossing(tileBean); crossingIdSeq = maxIdSeq(crossingIdSeq, nextIdSeq(tileBean.getId())); } case CURVED -> { tile = new Curved(tileBean); curvedIdSeq = maxIdSeq(curvedIdSeq, nextIdSeq(tileBean.getId())); } case SWITCH -> { tile = new Switch(tileBean); tile.setAccessoryBean(tileBean.getAccessoryBean()); switchIdSeq = maxIdSeq(switchIdSeq, nextIdSeq(tileBean.getId())); if (showValues && tileBean.getAccessoryBean() != null) { tile.setAccessoryValue((tileBean.getAccessoryBean()).getAccessoryValue()); } JCS.getJcsCommandStation().addAccessoryEventListener((AccessoryEventListener) tile); } case CROSS -> { tile = new Cross(tileBean); tile.setAccessoryBean(tileBean.getAccessoryBean()); crossIdSeq = maxIdSeq(crossIdSeq, nextIdSeq(tileBean.getId())); if (showValues && tileBean.getAccessoryBean() != null) { tile.setAccessoryValue((tileBean.getAccessoryBean()).getAccessoryValue()); } JCS.getJcsCommandStation().addAccessoryEventListener((AccessoryEventListener) tile); } case SIGNAL -> { tile = new Signal(tileBean); tile.setAccessoryBean(tileBean.getAccessoryBean()); signalIdSeq = maxIdSeq(signalIdSeq, nextIdSeq(tileBean.getId())); if (showValues && tileBean.getAccessoryBean() != null) { ((Signal) tile).setSignalValue(((AccessoryBean) tileBean.getAccessoryBean()).getSignalValue()); } JCS.getJcsCommandStation().addAccessoryEventListener((AccessoryEventListener) tile); } case SENSOR -> { tile = new Sensor(tileBean); tile.setSensorBean(tileBean.getSensorBean()); sensorIdSeq = maxIdSeq(sensorIdSeq, nextIdSeq(tileBean.getId())); if (showValues && tileBean.getSensorBean() != null) { ((Sensor) tile).setActive(((SensorBean) tileBean.getSensorBean()).isActive()); } JCS.getJcsCommandStation().addSensorEventListener((SensorEventListener) tile); } case BLOCK -> { tile = new Block(tileBean); tile.setBlockBean(tileBean.getBlockBean()); blockIdSeq = maxIdSeq(blockIdSeq, nextIdSeq(tileBean.getId())); } case STRAIGHT_DIR -> { tile = new StraightDirection(tileBean); straightDirectionIdSeq = maxIdSeq(straightDirectionIdSeq, nextIdSeq(tileBean.getId())); } case END -> { tile = new End(tileBean); endIdSeq = maxIdSeq(endIdSeq, nextIdSeq(tileBean.getId())); } default -> Logger.warn("Unknown Tile Type " + tileType); } return (Tile) tile; } public static void rollback(Tile tile) { switch (tile.tileType) { case STRAIGHT -> { straightIdSeq--; } case CROSSING -> { crossingIdSeq--; } case CURVED -> { curvedIdSeq--; } case SWITCH -> { switchIdSeq--; } case CROSS -> { crossIdSeq--; } case SIGNAL -> { signalIdSeq--; } case SENSOR -> { sensorIdSeq--; } case BLOCK -> { blockIdSeq--; } case STRAIGHT_DIR -> { straightDirectionIdSeq--; } case END -> { endIdSeq--; } } } /** * @param tileType type of type to create * @param orientation whether the orientation of the Tile is EAST, WEST, NORTH or SOUTH * @param x the tile center X * @param y the tile center Y * @return a Tile object */ public static Tile createTile(TileBean.TileType tileType, Orientation orientation, int x, int y) { return createTile(tileType, orientation, Direction.CENTER, x, y); } /** * @param tileType type of type to create * @param orientation whether the orientation of the Tile is EAST, WEST, NORTH or SOUTH * @param direction direction plays a role with Turnout tiles whether it goes to the Left or Right * @param x the tile center X * @param y the tile center Y * @return a Tile object */ public static Tile createTile(TileBean.TileType tileType, Orientation orientation, Direction direction, int x, int y) { return createTile(tileType, orientation, direction, new Point(x, y)); } public static Tile createTile(TileBean.TileType tileType, Orientation orientation, Direction direction, Point center) { Tile tile = null; switch (tileType) { case STRAIGHT -> { tile = new Straight(orientation, center); } case CROSSING -> { tile = new Crossing(orientation, center); } case CURVED -> tile = new Curved(orientation, center); case SWITCH -> tile = new Switch(orientation, direction, center); case CROSS -> tile = new Cross(orientation, direction, center); case SIGNAL -> tile = new Signal(orientation, center); case SENSOR -> tile = new Sensor(orientation, center); case BLOCK -> tile = new Block(orientation, center); case STRAIGHT_DIR -> tile = new StraightDirection(orientation, center); case END -> tile = new End(orientation, center); default -> Logger.warn("Unknown Tile Type " + tileType); } if (tile != null) { tile.setId(nextTileId(tileType)); } return (Tile) tile; } public static List toTiles(List tileBeans, boolean drawOutline, boolean showValues) { List tileList = new LinkedList<>(); for (TileBean tileBean : tileBeans) { Tile tile = createTile(tileBean, showValues); tileList.add(tile); } return tileList; } } \ No newline at end of file +/* + * Copyright 2023 Frans Jacobs. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package jcs.ui.layout.tiles; + +import java.awt.Point; +import java.util.LinkedList; +import java.util.List; +import jcs.JCS; +import jcs.commandStation.events.AccessoryEventListener; +import jcs.commandStation.events.SensorEventListener; +import jcs.entities.AccessoryBean; +import jcs.entities.SensorBean; +import jcs.entities.TileBean; +import jcs.entities.TileBean.Direction; +import jcs.entities.TileBean.Orientation; +import static jcs.entities.TileBean.TileType.BLOCK; +import static jcs.entities.TileBean.TileType.CROSS; +import static jcs.entities.TileBean.TileType.CROSSING; +import static jcs.entities.TileBean.TileType.CURVED; +import static jcs.entities.TileBean.TileType.END; +import static jcs.entities.TileBean.TileType.SENSOR; +import static jcs.entities.TileBean.TileType.SIGNAL; +import static jcs.entities.TileBean.TileType.STRAIGHT; +import static jcs.entities.TileBean.TileType.STRAIGHT_DIR; +import static jcs.entities.TileBean.TileType.SWITCH; +import org.tinylog.Logger; + +/** + * Factory object to create Tiles and cache tiles + * + * @author frans + */ +public class TileFactory { + + // Keep the records of the used id sequence number + private static int straightIdSeq; + private static int crossingIdSeq; + private static int curvedIdSeq; + private static int switchIdSeq; + private static int crossIdSeq; + private static int signalIdSeq; + private static int sensorIdSeq; + private static int blockIdSeq; + private static int straightDirectionIdSeq; + private static int endIdSeq; + + private TileFactory() { + } + + private static int nextIdSeq(String id) { + String idnr = id.substring(3); + int idSeq = Integer.parseInt(idnr); + return idSeq; + } + + private static String nextTileId(TileBean.TileType tileType) { + switch (tileType) { + case STRAIGHT -> { + straightIdSeq++; + return "st-" + straightIdSeq; + } + case CROSSING -> { + crossingIdSeq++; + return "cr-" + crossingIdSeq; + } + case CURVED -> { + curvedIdSeq++; + return "ct-" + curvedIdSeq; + } + case SWITCH -> { + switchIdSeq++; + return "sw-" + switchIdSeq; + } + case CROSS -> { + crossIdSeq++; + return "cs-" + crossIdSeq; + } + case SIGNAL -> { + signalIdSeq++; + return "si-" + signalIdSeq; + } + case SENSOR -> { + sensorIdSeq++; + return "se-" + sensorIdSeq; + } + case BLOCK -> { + blockIdSeq++; + return "bk-" + blockIdSeq; + } + case STRAIGHT_DIR -> { + straightDirectionIdSeq++; + return "sd-" + straightDirectionIdSeq; + } + case END -> { + endIdSeq++; + return "et-" + endIdSeq; + } + default -> { + Logger.warn("Unknown Tile Type " + tileType); + return null; + } + } + } + + private static int maxIdSeq(int currentId, int newId) { + if (currentId < newId) { + return newId; + } else { + return currentId; + } + } + + public static Tile createTile(String tileId) { + TileBean tileBean = JCS.getPersistenceService().getTileBean(tileId); + return createTile(tileBean); + } + + public static Tile createTile(TileBean tileBean) { + return createTile(tileBean, false); + } + + public static Tile createTile(TileBean tileBean, boolean showValues) { + if (tileBean == null) { + return null; + } + + TileBean.TileType tileType = tileBean.getTileType(); + Tile tile = null; + switch (tileType) { + case STRAIGHT -> { + tile = new Straight(tileBean); + straightIdSeq = maxIdSeq(straightIdSeq, nextIdSeq(tileBean.getId())); + } + case CROSSING -> { + tile = new Crossing(tileBean); + crossingIdSeq = maxIdSeq(crossingIdSeq, nextIdSeq(tileBean.getId())); + } + case CURVED -> { + tile = new Curved(tileBean); + curvedIdSeq = maxIdSeq(curvedIdSeq, nextIdSeq(tileBean.getId())); + } + case SWITCH -> { + tile = new Switch(tileBean); + tile.setAccessoryBean(tileBean.getAccessoryBean()); + + switchIdSeq = maxIdSeq(switchIdSeq, nextIdSeq(tileBean.getId())); + if (showValues && tileBean.getAccessoryBean() != null) { + tile.setAccessoryValue((tileBean.getAccessoryBean()).getAccessoryValue()); + } + JCS.getJcsCommandStation().addAccessoryEventListener((AccessoryEventListener) tile); + } + case CROSS -> { + tile = new Cross(tileBean); + tile.setAccessoryBean(tileBean.getAccessoryBean()); + + crossIdSeq = maxIdSeq(crossIdSeq, nextIdSeq(tileBean.getId())); + if (showValues && tileBean.getAccessoryBean() != null) { + tile.setAccessoryValue((tileBean.getAccessoryBean()).getAccessoryValue()); + } + JCS.getJcsCommandStation().addAccessoryEventListener((AccessoryEventListener) tile); + } + case SIGNAL -> { + tile = new Signal(tileBean); + tile.setAccessoryBean(tileBean.getAccessoryBean()); + + signalIdSeq = maxIdSeq(signalIdSeq, nextIdSeq(tileBean.getId())); + if (showValues && tileBean.getAccessoryBean() != null) { + ((Signal) tile).setSignalValue(((AccessoryBean) tileBean.getAccessoryBean()).getSignalValue()); + } + JCS.getJcsCommandStation().addAccessoryEventListener((AccessoryEventListener) tile); + } + case SENSOR -> { + tile = new Sensor(tileBean); + tile.setSensorBean(tileBean.getSensorBean()); + sensorIdSeq = maxIdSeq(sensorIdSeq, nextIdSeq(tileBean.getId())); + + if (showValues && tileBean.getSensorBean() != null) { + ((Sensor) tile).setActive(((SensorBean) tileBean.getSensorBean()).isActive()); + } + JCS.getJcsCommandStation().addSensorEventListener((SensorEventListener) tile); + } + case BLOCK -> { + tile = new Block(tileBean); + tile.setBlockBean(tileBean.getBlockBean()); + blockIdSeq = maxIdSeq(blockIdSeq, nextIdSeq(tileBean.getId())); + } + case STRAIGHT_DIR -> { + tile = new StraightDirection(tileBean); + straightDirectionIdSeq = maxIdSeq(straightDirectionIdSeq, nextIdSeq(tileBean.getId())); + } + case END -> { + tile = new End(tileBean); + endIdSeq = maxIdSeq(endIdSeq, nextIdSeq(tileBean.getId())); + } + default -> + Logger.warn("Unknown Tile Type " + tileType); + } + + return (Tile) tile; + } + + public static void rollback(Tile tile) { + switch (tile.tileType) { + case STRAIGHT -> { + straightIdSeq--; + } + case CROSSING -> { + crossingIdSeq--; + } + case CURVED -> { + curvedIdSeq--; + } + case SWITCH -> { + switchIdSeq--; + } + case CROSS -> { + crossIdSeq--; + } + case SIGNAL -> { + signalIdSeq--; + } + case SENSOR -> { + sensorIdSeq--; + } + case BLOCK -> { + blockIdSeq--; + } + case STRAIGHT_DIR -> { + straightDirectionIdSeq--; + } + case END -> { + endIdSeq--; + } + } + + } + + /** + * @param tileType type of type to create + * @param orientation whether the orientation of the Tile is EAST, WEST, NORTH or SOUTH + * @param x the tile center X + * @param y the tile center Y + * @return a Tile object + */ + public static Tile createTile(TileBean.TileType tileType, Orientation orientation, int x, int y) { + return createTile(tileType, orientation, Direction.CENTER, x, y); + } + + /** + * @param tileType type of type to create + * @param orientation whether the orientation of the Tile is EAST, WEST, NORTH or SOUTH + * @param direction direction plays a role with Turnout tiles whether it goes to the Left or Right + * @param x the tile center X + * @param y the tile center Y + * @return a Tile object + */ + public static Tile createTile(TileBean.TileType tileType, Orientation orientation, Direction direction, int x, int y) { + return createTile(tileType, orientation, direction, new Point(x, y)); + } + + public static Tile createTile(TileBean.TileType tileType, Orientation orientation, Direction direction, Point center) { + Tile tile = null; + switch (tileType) { + case STRAIGHT -> { + tile = new Straight(orientation, center); + } + case CROSSING -> { + tile = new Crossing(orientation, center); + } + case CURVED -> + tile = new Curved(orientation, center); + case SWITCH -> + tile = new Switch(orientation, direction, center); + case CROSS -> + tile = new Cross(orientation, direction, center); + case SIGNAL -> + tile = new Signal(orientation, center); + case SENSOR -> + tile = new Sensor(orientation, center); + case BLOCK -> + tile = new Block(orientation, center); + case STRAIGHT_DIR -> + tile = new StraightDirection(orientation, center); + case END -> + tile = new End(orientation, center); + default -> + Logger.warn("Unknown Tile Type " + tileType); + } + + if (tile != null) { + tile.setId(nextTileId(tileType)); + } + + return (Tile) tile; + } + + public static List toTiles(List tileBeans, boolean drawOutline, boolean showValues) { + List tileList = new LinkedList<>(); + + for (TileBean tileBean : tileBeans) { + Tile tile = createTile(tileBean, showValues); + tileList.add(tile); + } + return tileList; + } + +} diff --git a/src/main/java/jcs/ui/layout/tiles/ui/SensorUI.java b/src/main/java/jcs/ui/layout/tiles/ui/SensorUI.java index 0e2ce14e..c24a6a91 100644 --- a/src/main/java/jcs/ui/layout/tiles/ui/SensorUI.java +++ b/src/main/java/jcs/ui/layout/tiles/ui/SensorUI.java @@ -16,17 +16,25 @@ package jcs.ui.layout.tiles.ui; import java.awt.Color; +import java.awt.Component; import java.awt.Graphics2D; import java.awt.MultipleGradientPaint; import java.awt.Point; import java.awt.RadialGradientPaint; +import java.awt.event.MouseEvent; +import java.awt.event.MouseListener; import java.awt.geom.Ellipse2D; +import java.util.Date; import javax.swing.JComponent; import javax.swing.plaf.ComponentUI; +import jcs.commandStation.events.SensorEvent; +import jcs.entities.SensorBean; import jcs.ui.layout.tiles.Tile; +import jcs.ui.layout.tiles.TileCache; import jcs.ui.layout.tiles.TileModel; +import org.tinylog.Logger; -public class SensorUI extends StraightUI { +public class SensorUI extends StraightUI implements MouseListener { public SensorUI() { } @@ -35,6 +43,18 @@ public static ComponentUI createUI(JComponent c) { return new SensorUI(); } + @Override + public void installUI(JComponent c) { + Tile tile = (Tile) c; + tile.addMouseListener(this); + } + + @Override + public void uninstallUI(JComponent c) { + Tile tile = (Tile) c; + tile.removeMouseListener(this); + } + private void renderSensor(Graphics2D g2, JComponent c) { Tile tile = (Tile) c; TileModel model = tile.getModel(); @@ -59,11 +79,54 @@ private void renderSensor(Graphics2D g2, JComponent c) { g2.fill(new Ellipse2D.Double(xx, yy, 0.5f * radius, 0.5f * radius)); } - @Override public void renderTile(Graphics2D g2, JComponent c) { renderStraight(g2, c); renderSensor(g2, c); } + @Override + public void mousePressed(MouseEvent e) { + //Logger.trace("Mouse button " + e.getButton() + " @ (" + e.getXOnScreen() + ","); + redispatchToParent(e); + } + + @Override + public void mouseReleased(MouseEvent e) { + //Logger.trace("Mouse button " + e.getButton() + " @ (" + e.getXOnScreen() + ","); + redispatchToParent(e); + } + + @Override + public void mouseClicked(MouseEvent e) { + //Logger.trace("Mouse button " + e.getButton() + " @ (" + e.getXOnScreen() + ","); + //Only JCS is in CONTROL mode (readonly) activate sensor action events. + + if (isControlMode((Component) e.getSource()) && e.getButton() == MouseEvent.BUTTON1) { + Tile tile = (Tile) e.getSource(); + tile.setActive(!tile.isActive()); + if (tile.getSensorBean() != null) { + SensorBean sb = tile.getSensorBean(); + sb.setLastUpdated(new Date()); + SensorEvent sae = new SensorEvent(sb); + TileCache.enqueTileAction(sae); + //Logger.trace("Changing Tile "+tile.getId()+" Sensor "+sb.getId()+" to "+sb.isActive()+"..."); + } + } else { + redispatchToParent(e); + } + } + + @Override + public void mouseEntered(MouseEvent e) { + //Logger.trace("Mouse button " + e.getButton() + " @ (" + e.getXOnScreen() + ","); + redispatchToParent(e); + } + + @Override + public void mouseExited(MouseEvent e) { + //Logger.trace("Mouse button " + e.getButton() + " @ (" + e.getXOnScreen() + ","); + redispatchToParent(e); + } + } diff --git a/src/main/java/jcs/ui/layout/tiles/ui/TileUI.java b/src/main/java/jcs/ui/layout/tiles/ui/TileUI.java index 9f30b6f4..039988b6 100644 --- a/src/main/java/jcs/ui/layout/tiles/ui/TileUI.java +++ b/src/main/java/jcs/ui/layout/tiles/ui/TileUI.java @@ -16,18 +16,22 @@ package jcs.ui.layout.tiles.ui; import java.awt.Color; +import java.awt.Component; import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.Insets; +import java.awt.event.MouseEvent; import java.awt.geom.AffineTransform; import java.awt.geom.Ellipse2D; import java.awt.image.BufferedImage; import javax.swing.JComponent; +import javax.swing.SwingUtilities; import javax.swing.plaf.ComponentUI; import jcs.entities.TileBean; import static jcs.entities.TileBean.Orientation.NORTH; import static jcs.entities.TileBean.Orientation.SOUTH; import static jcs.entities.TileBean.Orientation.WEST; +import jcs.ui.layout.LayoutCanvas; import jcs.ui.layout.tiles.Tile; import static jcs.ui.layout.tiles.Tile.DEFAULT_BACKGROUND_COLOR; import static jcs.ui.layout.tiles.Tile.DEFAULT_TRACK_COLOR; @@ -266,4 +270,19 @@ public void paint(Graphics g, JComponent c) { Logger.trace(tile.getId() + " Duration: " + (now - started) + " ms. Cp: " + tile.xyToString() + " O: " + model.getTileOrienation()); } } + + protected void redispatchToParent(MouseEvent e) { + Component source = (Component) e.getSource(); + MouseEvent parentEvent = SwingUtilities.convertMouseEvent(source, e, source.getParent()); + source.getParent().dispatchEvent(parentEvent); + } + + protected boolean isControlMode(Component c) { + if (c.getParent() != null && c.getParent() instanceof LayoutCanvas) { + return ((LayoutCanvas) c.getParent()).isReadonly(); + } else { + return false; + } + } + } From 461ee5230cd1eb4b2e72d821b938f6aaf892bd95 Mon Sep 17 00:00:00 2001 From: Frans Jacobs Date: Sun, 9 Feb 2025 20:03:43 +0100 Subject: [PATCH 18/24] Restored the control of Switches using the Command screen --- .../esu/ecos/EsuEcosCommandStationImpl.java | 8 +- src/main/java/jcs/ui/layout/LayoutCanvas.java | 34 +- .../jcs/ui/layout/tiles/DefaultTileModel.java | 29 +- src/main/java/jcs/ui/layout/tiles/Signal.java | 2 +- src/main/java/jcs/ui/layout/tiles/Tile.java | 384 +++++++++--------- .../layout/tiles/TileActionEventHandler.java | 10 +- .../java/jcs/ui/layout/tiles/TileModel.java | 9 + .../java/jcs/ui/layout/tiles/ui/CrossUI.java | 4 +- .../java/jcs/ui/layout/tiles/ui/SensorUI.java | 10 +- .../java/jcs/ui/layout/tiles/ui/SignalUI.java | 13 +- .../java/jcs/ui/layout/tiles/ui/SwitchUI.java | 81 +++- 11 files changed, 369 insertions(+), 215 deletions(-) diff --git a/src/main/java/jcs/commandStation/esu/ecos/EsuEcosCommandStationImpl.java b/src/main/java/jcs/commandStation/esu/ecos/EsuEcosCommandStationImpl.java index b1b98540..86379a6a 100644 --- a/src/main/java/jcs/commandStation/esu/ecos/EsuEcosCommandStationImpl.java +++ b/src/main/java/jcs/commandStation/esu/ecos/EsuEcosCommandStationImpl.java @@ -579,7 +579,7 @@ public void fireSensorEventListeners(SensorEvent sensorEvent) { if (sensorEventListeners != null && !sensorEventListeners.isEmpty()) { for (SensorEventListener listener : sensorEventListeners) { //if (listener != null) { - listener.onSensorChange(sensorEvent); + listener.onSensorChange(sensorEvent); //} } } @@ -617,8 +617,10 @@ void fireFunctionEventListeners(final LocomotiveFunctionEvent functionEvent) { } void fireAccessoryEventListeners(final AccessoryEvent accessoryEvent) { - for (AccessoryEventListener listener : this.accessoryEventListeners) { - listener.onAccessoryChange(accessoryEvent); + if (accessoryEventListeners != null && !accessoryEventListeners.isEmpty()) { + for (AccessoryEventListener listener : accessoryEventListeners) { + listener.onAccessoryChange(accessoryEvent); + } } } diff --git a/src/main/java/jcs/ui/layout/LayoutCanvas.java b/src/main/java/jcs/ui/layout/LayoutCanvas.java index 860c36fd..f50704db 100755 --- a/src/main/java/jcs/ui/layout/LayoutCanvas.java +++ b/src/main/java/jcs/ui/layout/LayoutCanvas.java @@ -472,29 +472,31 @@ private void executeControlActionForTile(Tile tile, Point p) { BlockControlDialog bcd = new BlockControlDialog(getParentFrame(), block); bcd.setVisible(true); } - case SIGNAL -> - this.executor.execute(() -> toggleSignal((Signal) tile)); - case SWITCH -> - this.executor.execute(() -> toggleSwitch((Switch) tile)); + case SIGNAL -> { + //this.executor.execute(() -> toggleSignal((Signal) tile)); + } + case SWITCH -> { + //this.executor.execute(() -> toggleSwitch((Switch) tile)); + } case CROSS -> { - this.executor.execute(() -> toggleSwitch((Switch) tile)); + //this.executor.execute(() -> toggleSwitch((Switch) tile)); } default -> { } } } - private void toggleSwitch(Switch turnout) { - if (turnout.getAccessoryBean() != null) { - AccessoryBean ab = turnout.getAccessoryBean(); - ab.toggle(); - turnout.setAccessoryValue(ab.getAccessoryValue()); - - JCS.getJcsCommandStation().switchAccessory(ab, ab.getAccessoryValue()); - } else { - Logger.trace("No AccessoryBean configured for Turnout: " + turnout.getId()); - } - } +// private void toggleSwitch(Switch turnout) { +// if (turnout.getAccessoryBean() != null) { +// AccessoryBean ab = turnout.getAccessoryBean(); +// ab.toggle(); +// turnout.setAccessoryValue(ab.getAccessoryValue()); +// +// JCS.getJcsCommandStation().switchAccessory(ab, ab.getAccessoryValue()); +// } else { +// Logger.trace("No AccessoryBean configured for Turnout: " + turnout.getId()); +// } +// } private void toggleSignal(Signal signal) { if (signal.getAccessoryBean() != null) { diff --git a/src/main/java/jcs/ui/layout/tiles/DefaultTileModel.java b/src/main/java/jcs/ui/layout/tiles/DefaultTileModel.java index 2d97658b..7aabdfd7 100644 --- a/src/main/java/jcs/ui/layout/tiles/DefaultTileModel.java +++ b/src/main/java/jcs/ui/layout/tiles/DefaultTileModel.java @@ -21,6 +21,8 @@ import javax.swing.event.ChangeEvent; import javax.swing.event.ChangeListener; import javax.swing.event.EventListenerList; +import jcs.entities.AccessoryBean.AccessoryValue; +import jcs.entities.AccessoryBean.SignalValue; import jcs.entities.BlockBean.BlockState; import jcs.entities.LocomotiveBean; import jcs.entities.TileBean.Orientation; @@ -47,6 +49,9 @@ public class DefaultTileModel implements TileModel { protected boolean showAccessoryValue = false; protected boolean showSignalValue = false; protected boolean sensorActive = false; + protected AccessoryValue accessoryValue; + protected SignalValue signalValue; + protected boolean showOutline = false; protected BlockState blockState; @@ -127,7 +132,7 @@ public void setTileOrienation(Orientation tileOrienation) { this.tileOrienation = tileOrienation; fireStateChanged(); } - + @Override public Orientation getIncomingSide() { return incomingSide; @@ -204,6 +209,28 @@ public void setSensorActive(boolean sensorActive) { fireStateChanged(); } + @Override + public AccessoryValue getAccessoryValue() { + return accessoryValue; + } + + @Override + public void setAccessoryValue(AccessoryValue accessoryValue) { + this.accessoryValue = accessoryValue; + fireStateChanged(); + } + + @Override + public SignalValue getSignalValue() { + return signalValue; + } + + @Override + public void setSignalValue(SignalValue signalValue) { + this.signalValue = signalValue; + fireStateChanged(); + } + @Override public BlockState getBlockState() { if (blockState == null) { diff --git a/src/main/java/jcs/ui/layout/tiles/Signal.java b/src/main/java/jcs/ui/layout/tiles/Signal.java index 25765a26..f0c6eb69 100644 --- a/src/main/java/jcs/ui/layout/tiles/Signal.java +++ b/src/main/java/jcs/ui/layout/tiles/Signal.java @@ -48,7 +48,7 @@ public class Signal extends Straight implements AccessoryEventListener { super(orientation, center); this.tileType = TileType.SIGNAL; this.signalType = signalType; - this.signalValue = SignalValue.OFF; + model.setSignalValue(SignalValue.OFF); } @Override diff --git a/src/main/java/jcs/ui/layout/tiles/Tile.java b/src/main/java/jcs/ui/layout/tiles/Tile.java index 144fdb56..1c3648ee 100755 --- a/src/main/java/jcs/ui/layout/tiles/Tile.java +++ b/src/main/java/jcs/ui/layout/tiles/Tile.java @@ -18,7 +18,6 @@ import jcs.ui.layout.tiles.ui.TileUI; import java.awt.Color; import java.awt.Dimension; -import java.awt.Graphics; import java.awt.Point; import java.awt.Rectangle; import java.awt.event.ActionEvent; @@ -41,6 +40,7 @@ import jcs.entities.AccessoryBean; import jcs.entities.AccessoryBean.AccessoryValue; import jcs.entities.AccessoryBean.SignalType; +import jcs.entities.AccessoryBean.SignalValue; import jcs.entities.BlockBean; import jcs.entities.BlockBean.BlockState; import jcs.entities.LocomotiveBean; @@ -52,7 +52,6 @@ import jcs.ui.layout.LayoutUtil; import static jcs.ui.layout.tiles.Block.BLOCK_HEIGHT; import static jcs.ui.layout.tiles.Block.BLOCK_WIDTH; -import org.tinylog.Logger; /** * Basic graphic element to display a track, turnout, etc on the screen.
@@ -78,13 +77,13 @@ public abstract class Tile extends JComponent { // implements ChangeListener public static final int GRID = 20; public static final int DEFAULT_WIDTH = GRID * 2; public static final int DEFAULT_HEIGHT = GRID * 2; - + public static final Color DEFAULT_BACKGROUND_COLOR = Color.white; public static final Color DEFAULT_TRACK_COLOR = Color.lightGray; public static final Color DEFAULT_ROUTE_TRACK_COLOR = Color.darkGray; public static final Color DEFAULT_SELECTED_COLOR = Color.yellow; public static final Color DEFAULT_WARN_COLOR = Color.red; - + public static final String MODEL_CHANGED_PROPERTY = "model"; // public static final String CONTENT_AREA_FILLED_CHANGED_PROPERTY = "contentAreaFilled"; @@ -92,140 +91,139 @@ public abstract class Tile extends JComponent { // implements ChangeListener * The data model that determines the Tile state. */ protected TileModel model = null; - + protected String id; protected Integer tileX; protected Integer tileY; - + protected Direction tileDirection; - + protected TileType tileType; protected String accessoryId; protected String sensorId; - - protected AccessoryValue accessoryValue; + + //protected AccessoryValue accessoryValue; protected AccessoryValue routeValue; - + protected SignalType signalType; - protected AccessoryBean.SignalValue signalValue; - + //protected AccessoryBean.SignalValue signalValue; + protected TileBean tileBean; protected AccessoryBean accessoryBean; protected SensorBean sensorBean; protected BlockBean blockBean; - + protected List neighbours; - + protected int renderOffsetX = 0; protected int renderOffsetY = 0; - + protected boolean drawName = true; - + protected BufferedImage tileImage; - + protected PropertyChangeListener propertyChangeListener; - + protected ChangeListener changeListener = null; protected ActionListener actionListener = null; - + protected transient ChangeEvent changeEvent; private Handler handler; - + protected Tile(TileType tileType, Orientation orientation, Point center, int width, int height) { this(tileType, orientation, Direction.CENTER, center.x, center.y, width, height); } - + protected Tile(TileType tileType, Orientation orientation, int x, int y, int width, int height) { this(tileType, orientation, Direction.CENTER, x, y, width, height); } - + protected Tile(TileType tileType, Orientation orientation, Direction direction, int x, int y, int width, int height) { this(tileType, orientation, direction, x, y, width, height, null, null); } - + protected Tile(TileType tileType, Orientation orientation, Direction direction, int x, int y, int width, int height, Color backgroundColor, Color selectedColor) { this.tileType = tileType; this.tileDirection = direction; this.tileX = x; this.tileY = y; - + setLayout(null); Dimension d = new Dimension(width, height); setSize(d); setPreferredSize(d); } - + protected Tile(TileBean tileBean) { this(tileBean, tileWidth(tileBean.getOrientation(), tileBean.getTileType()), tileHeight(tileBean.getOrientation(), tileBean.getTileType())); } - + protected Tile(TileBean tileBean, int width, int height) { this.tileBean = tileBean; - this.id = tileBean.getId(); - this.tileType = tileBean.getTileType(); - this.tileDirection = tileBean.getDirection(); - this.tileX = tileBean.getX(); - this.tileY = tileBean.getY(); - - this.accessoryId = tileBean.getAccessoryId(); - this.accessoryBean = tileBean.getAccessoryBean(); - this.signalType = tileBean.getSignalType(); - - this.sensorId = tileBean.getSensorId(); - this.sensorBean = tileBean.getSensorBean(); - this.blockBean = tileBean.getBlockBean(); - + id = tileBean.getId(); + tileType = tileBean.getTileType(); + tileDirection = tileBean.getDirection(); + tileX = tileBean.getX(); + tileY = tileBean.getY(); + + accessoryId = tileBean.getAccessoryId(); + accessoryBean = tileBean.getAccessoryBean(); + + sensorId = tileBean.getSensorId(); + sensorBean = tileBean.getSensorBean(); + blockBean = tileBean.getBlockBean(); + setLayout(null); Dimension d = new Dimension(width, height); setSize(d); setPreferredSize(d); } - + @Override public String getUIClassID() { return TileUI.UI_CLASS_ID; } - + @Override public TileUI getUI() { return (TileUI) ui; } - + public void setUI(TileUI ui) { super.setUI(ui); } - + public TileModel getModel() { return model; } - + public void setModel(TileModel newModel) { TileModel oldModel = getModel(); - + if (oldModel != null) { oldModel.removeChangeListener(changeListener); oldModel.removeActionListener(actionListener); changeListener = null; actionListener = null; } - + model = newModel; - + if (newModel != null) { changeListener = createChangeListener(); actionListener = createActionListener(); - + newModel.addChangeListener(changeListener); newModel.addActionListener(actionListener); } - + firePropertyChange(MODEL_CHANGED_PROPERTY, oldModel, newModel); if (newModel != oldModel) { revalidate(); repaint(); } } - + protected static int tileWidth(Orientation orientation, TileType tileType) { if (Orientation.EAST == orientation || Orientation.WEST == orientation) { if (null == tileType) { @@ -244,7 +242,7 @@ protected static int tileWidth(Orientation orientation, TileType tileType) { return DEFAULT_WIDTH; } } - + protected static int tileHeight(Orientation orientation, TileType tileType) { if (Orientation.EAST == orientation || Orientation.WEST == orientation) { return DEFAULT_HEIGHT; @@ -263,7 +261,7 @@ protected static int tileHeight(Orientation orientation, TileType tileType) { } } } - + protected void populateModel() { if (this.blockBean != null) { this.model.setBlockState(this.blockBean.getBlockState()); @@ -271,8 +269,15 @@ protected void populateModel() { this.model.setArrivalSuffix(this.blockBean.getArrivalSuffix()); this.model.setLogicalDirection(LocomotiveBean.Direction.get(this.blockBean.getLogicalDirection())); } + if (accessoryBean != null) { + setAccessoryBean(accessoryBean); + } + if (sensorBean != null) { + setSensorBean(sensorBean); + } + } - + public TileBean getTileBean() { if (tileBean == null) { tileBean = new TileBean(); @@ -281,7 +286,7 @@ public TileBean getTileBean() { tileBean.setY(this.tileY); tileBean.setTileType(this.tileType); tileBean.setTileOrientation(this.model.getTileOrienation().getOrientation()); - + tileBean.setTileDirection(this.tileDirection.getDirection()); tileBean.setSignalType(this.signalType); tileBean.setAccessoryId(this.accessoryId); @@ -312,23 +317,23 @@ public TileBean getTileBean() { public boolean isSelected() { return model.isSelected(); } - + public void setSelected(boolean b) { model.setSelected(b); } - + public String getId() { return id; } - + public void setId(String id) { this.id = id; } - + public SignalType getSignalType() { return signalType; } - + public void setSignalType(SignalType signalType) { this.signalType = signalType; } @@ -356,7 +361,7 @@ public Integer getTileY() { public Point getCenter() { return new Point(this.tileX, this.tileY); } - + public void setCenter(Point center) { tileX = center.x; tileY = center.y; @@ -372,59 +377,59 @@ public void setCenter(Point center) { public Orientation getOrientation() { return model.getTileOrienation(); } - + public void setOrientation(Orientation orientation) { model.setTileOrienation(orientation); if (tileBean != null) { tileBean.setOrientation(orientation); } } - + public Direction getDirection() { return tileDirection; } - + public void setDirection(Direction direction) { this.tileDirection = direction; if (tileBean != null) { tileBean.setDirection(direction); } } - + public String getAccessoryId() { return accessoryId; } - + public void setAccessoryId(String accessoryId) { this.accessoryId = accessoryId; if (tileBean != null) { tileBean.setAccessoryId(accessoryId); } } - + public String getSensorId() { return sensorId; } - + public void setSensorId(String sensorId) { this.sensorId = sensorId; } - + public boolean isActive() { return model.isSensorActive(); } - + public void setActive(boolean active) { model.setSensorActive(active); if (this.sensorBean != null) { this.sensorBean.setActive(active); } } - + public BlockState getBlockState() { return model.getBlockState(); } - + public void setBlockState(BlockState blockState) { if (blockBean != null) { blockBean.setBlockState(blockState); @@ -433,84 +438,90 @@ public void setBlockState(BlockState blockState) { } model.setBlockState(blockState); } - + public String getDepartureSuffix() { return model.getDepartureSuffix(); } - + public void setDepartureSuffix(String suffix) { if (blockBean != null) { blockBean.setDepartureSuffix(suffix); } model.setDepartureSuffix(suffix); } - + public boolean isReverseArrival() { return model.isReverseArrival(); } - + public void setReverseArrival(boolean reverseArrival) { if (blockBean != null) { blockBean.setReverseArrival(reverseArrival); } model.setReverseArrival(reverseArrival); } - + public LocomotiveBean.Direction getLogicalDirection() { return model.getLogicalDirection(); } - + public void setLogicalDirection(LocomotiveBean.Direction logicalDirection) { if (blockBean != null) { blockBean.setLogicalDirection(logicalDirection.getDirection()); } model.setLogicalDirection(logicalDirection); } - + public LocomotiveBean getLocomotive() { return model.getLocomotive(); } - + public void setLocomotive(LocomotiveBean locomotive) { if (blockBean != null) { blockBean.setLocomotive(locomotive); model.setOverlayImage(locomotive != null && locomotive.getLocIcon() != null && (model.getBlockState() == BlockState.OCCUPIED || model.getBlockState() == BlockState.INBOUND || model.getBlockState() == BlockState.OUTBOUND)); } - + model.setLocomotive(locomotive); } - + public AccessoryBean getAccessoryBean() { return accessoryBean; } - + public void setAccessoryBean(AccessoryBean accessoryBean) { this.accessoryBean = accessoryBean; - if (accessoryBean != null) { accessoryId = accessoryBean.getId(); - signalValue = accessoryBean.getSignalValue(); - signalType = SignalType.getSignalType(accessoryBean.getType()); + if (accessoryBean.isSignal()) { + signalType = SignalType.getSignalType(accessoryBean.getType()); + model.setSignalValue(accessoryBean.getSignalValue()); + } else if (accessoryBean.isTurnout()) { + model.setAccessoryValue(accessoryBean.getAccessoryValue()); + } else { + model.setAccessoryValue(AccessoryValue.OFF); + } } else { accessoryId = null; signalType = SignalType.NONE; - signalValue = AccessoryBean.SignalValue.OFF; + model.setAccessoryValue(AccessoryValue.OFF); } } - - public AccessoryValue getAccessoryValue() { - if (this.accessoryValue == null) { - return AccessoryValue.OFF; - } else { - return accessoryValue; - } - } - + +// public AccessoryValue getAccessoryValue() { +// if (this.accessoryValue == null) { +// return AccessoryValue.OFF; +// } else { +// return accessoryValue; +// } +// } public void setAccessoryValue(AccessoryValue value) { - this.accessoryValue = value; - repaint(); + model.setAccessoryValue(value); + if (accessoryBean != null) { + accessoryBean.setAccessoryValue(value); + } } - + public AccessoryValue getRouteValue() { if (routeValue == null) { return AccessoryValue.OFF; @@ -518,93 +529,101 @@ public AccessoryValue getRouteValue() { return routeValue; } } - + public void setRouteValue(AccessoryValue value) { this.routeValue = value; repaint(); } - - public AccessoryBean.SignalValue getSignalValue() { - return signalValue; - } - + +// public AccessoryBean.SignalValue getSignalValue() { +// return signalValue; +// } public void setSignalValue(AccessoryBean.SignalValue signalValue) { - this.signalValue = signalValue; - repaint(); + model.setSignalValue(signalValue); + if (this.accessoryBean != null) { + this.accessoryBean.setSignalValue(signalValue); + } } - + public SensorBean getSensorBean() { return sensorBean; } - + public void setSensorBean(SensorBean sensorBean) { this.sensorBean = sensorBean; + if (sensorBean != null) { + sensorId = sensorBean.getId(); + model.setSensorActive(sensorBean.isActive()); + } else { + model.setSensorActive(false); + sensorId = null; + } } - + public BlockBean getBlockBean() { return blockBean; } - + public void setBlockBean(BlockBean blockBean) { this.blockBean = blockBean; } - + public int getRenderOffsetX() { return renderOffsetX; } - + public void setRenderOffsetX(int renderOffsetX) { this.renderOffsetX = renderOffsetX; } - + public int getRenderOffsetY() { return renderOffsetY; } - + public void setRenderOffsetY(int renderOffsetY) { this.renderOffsetY = renderOffsetY; } - + public TileBean.TileType getTileType() { return this.tileType; } - + public final void setTileType(TileType tileType) { this.tileType = tileType; } - + public void setTrackColor(Color trackColor) { if (getUI() != null) { getUI().setTrackColor(trackColor); } } - + public void setTrackRouteColor(Color trackRouteColor) { if (getUI() != null) { getUI().setTrackRouteColor(trackRouteColor); } } - + public Color getSelectedColor() { return model.getSelectedColor(); } - + public void setSelectedColor(Color selectedColor) { model.setSelectedColor(selectedColor); } - + public Orientation getIncomingSide() { return model.getIncomingSide(); } - + public void setIncomingSide(Orientation incomingSide) { model.setIncomingSide(incomingSide); } - + public boolean isShowRoute() { return model.isShowRoute(); } - + public void setShowRoute(boolean drawRoute) { this.model.setShowRoute(drawRoute); } @@ -617,17 +636,17 @@ public void setShowRoute(boolean drawRoute) { * */ public abstract Map getNeighborPoints(); - + public abstract Map getEdgePoints(); - + Set getAltPoints(Point center) { return Collections.EMPTY_SET; } - + public Set getAllPoints() { return getAllPoints(getCenter()); } - + Set getAllPoints(Point center) { Set aps = new HashSet<>(); aps.add(center); @@ -653,7 +672,7 @@ public Orientation rotate() { } return model.getTileOrienation(); } - + public void flipHorizontal() { Orientation tileOrientation = model.getTileOrienation(); if (Orientation.NORTH == tileOrientation || Orientation.SOUTH == tileOrientation) { @@ -661,7 +680,7 @@ public void flipHorizontal() { rotate(); } } - + public void flipVertical() { Orientation tileOrientation = model.getTileOrienation(); if (Orientation.EAST == tileOrientation || Orientation.WEST == tileOrientation) { @@ -669,41 +688,41 @@ public void flipVertical() { rotate(); } } - + @Override public void move(int newX, int newY) { Point cs = LayoutUtil.snapToGrid(newX, newY); setCenter(cs); } - + public static BufferedImage flipHorizontally(BufferedImage source) { BufferedImage output = new BufferedImage(source.getHeight(), source.getWidth(), source.getType()); - + AffineTransform flip = AffineTransform.getScaleInstance(1, -1); flip.translate(0, -source.getHeight()); AffineTransformOp op = new AffineTransformOp(flip, AffineTransformOp.TYPE_NEAREST_NEIGHBOR); - + op.filter(source, output); - + return output; } - + public static BufferedImage flipVertically(BufferedImage source) { BufferedImage output = new BufferedImage(source.getHeight(), source.getWidth(), source.getType()); - + AffineTransform flip = AffineTransform.getScaleInstance(-1, 1); flip.translate(-source.getWidth(), 0); AffineTransformOp op = new AffineTransformOp(flip, AffineTransformOp.TYPE_NEAREST_NEIGHBOR); - + op.filter(source, output); - + return output; } - + public Set getAltPoints() { return Collections.EMPTY_SET; } - + public int getCenterX() { if (tileX > 0) { return this.tileX; @@ -711,7 +730,7 @@ public int getCenterX() { return GRID; } } - + public int getCenterY() { if (tileY > 0) { return this.tileY; @@ -719,19 +738,19 @@ public int getCenterY() { return GRID; } } - + public boolean isDrawName() { return drawName; } - + public void setDrawName(boolean drawName) { this.drawName = drawName; } - + public boolean isScaleImage() { return model.isScaleImage(); } - + public void setScaleImage(boolean scaleImage) { Dimension d; if (scaleImage) { @@ -739,23 +758,23 @@ public void setScaleImage(boolean scaleImage) { } else { int renderWidth = getUI().getRenderWidth(); int renderHeight = getUI().getRenderHeight(); - + d = new Dimension(renderWidth, renderHeight); } - + setSize(d); setPreferredSize(d); model.setScaleImage(scaleImage); } - + public boolean isDrawCenterPoint() { return model.isShowCenter(); } - + public void setDrawCenterPoint(boolean drawCenterPoint) { model.setShowCenter(drawCenterPoint); } - + @Override public String toString() { return this.getClass().getSimpleName() @@ -769,7 +788,7 @@ public String toString() { + xyToString() + "}"; } - + public String xyToString() { return "(" + this.tileX + "," + this.tileY + ")"; } @@ -793,15 +812,15 @@ public boolean isVertical() { Orientation tileOrientation = model.getTileOrienation(); return (Orientation.NORTH == tileOrientation || Orientation.SOUTH == tileOrientation) && TileType.CURVED != tileType; } - + public boolean isJunction() { return TileType.SWITCH == tileType || TileType.CROSS == tileType; } - + public boolean isBlock() { return TileType.BLOCK == tileType; } - + public boolean isDirectional() { return TileType.STRAIGHT_DIR == tileType; } @@ -814,52 +833,52 @@ public boolean isDirectional() { public boolean isDiagonal() { return TileType.CURVED == tileType; } - + public boolean isCrossing() { return TileType.CROSSING == tileType; } - + public List getNeighbours() { return neighbours; } - + public void setNeighbours(List neighbours) { this.neighbours = neighbours; } - + public String getIdSuffix(Tile other) { return ""; } - + public Map getNeighborOrientations() { Map edgeOrientations = new HashMap<>(); - + Map neighborPoints = getNeighborPoints(); - + for (Orientation o : Orientation.values()) { edgeOrientations.put(neighborPoints.get(o), o); } return edgeOrientations; } - + public Map getEdgeOrientations() { Map edgeOrientations = new HashMap<>(); - + Map edgeConnections = getEdgePoints(); - + for (Orientation o : Orientation.values()) { edgeOrientations.put(edgeConnections.get(o), o); } return edgeOrientations; } - + public boolean isAdjacent(Tile other) { boolean adjacent = false; - + if (other != null) { Collection thisEdgePoints = getEdgePoints().values(); Collection otherEdgePoints = other.getEdgePoints().values(); - + for (Point p : thisEdgePoints) { adjacent = otherEdgePoints.contains(p); if (adjacent) { @@ -867,7 +886,7 @@ public boolean isAdjacent(Tile other) { } } } - + return adjacent; } @@ -881,40 +900,40 @@ public boolean isAdjacent(Tile other) { public boolean isArrowDirection(Tile other) { return true; } - + public AccessoryValue accessoryValueForRoute(Orientation from, Orientation to) { return AccessoryValue.OFF; } - + protected ChangeListener createChangeListener() { return getHandler(); } - + protected ActionListener createActionListener() { return getHandler(); } - + private Handler getHandler() { if (handler == null) { handler = new Handler(); } return handler; } - + class Handler implements ActionListener, ChangeListener, Serializable { - + @Override public void stateChanged(ChangeEvent e) { fireStateChanged(); repaint(); } - + @Override public void actionPerformed(ActionEvent event) { fireActionPerformed(event); } } - + protected void fireStateChanged() { Object[] listeners = listenerList.getListenerList(); //reverse order @@ -928,7 +947,7 @@ protected void fireStateChanged() { } } } - + protected void fireActionPerformed(ActionEvent event) { Object[] listeners = listenerList.getListenerList(); ActionEvent e = null; @@ -947,18 +966,18 @@ protected void fireActionPerformed(ActionEvent event) { } } } - + public Rectangle getTileBounds() { if (model.isScaleImage()) { return new Rectangle(tileX - GRID, tileY - GRID, DEFAULT_WIDTH, DEFAULT_HEIGHT); } else { int renderWidth = getUI().getRenderWidth(); int renderHeight = getUI().getRenderHeight(); - + return new Rectangle(tileX - renderWidth / 2, tileY - renderHeight / 2, renderWidth, renderHeight); } } - + // @Override // protected void paintComponent(Graphics g) { // if (Logger.isTraceEnabled()) { @@ -968,5 +987,4 @@ public Rectangle getTileBounds() { // Logger.trace(id + " Duration: " + (now - started) + " ms. Cp: " + xyToString() + " O: " + model.getTileOrienation()); // } // } - } diff --git a/src/main/java/jcs/ui/layout/tiles/TileActionEventHandler.java b/src/main/java/jcs/ui/layout/tiles/TileActionEventHandler.java index bc36f141..93a1cf34 100644 --- a/src/main/java/jcs/ui/layout/tiles/TileActionEventHandler.java +++ b/src/main/java/jcs/ui/layout/tiles/TileActionEventHandler.java @@ -22,6 +22,7 @@ import jcs.commandStation.events.AccessoryEvent; import jcs.commandStation.events.JCSActionEvent; import jcs.commandStation.events.SensorEvent; +import jcs.entities.AccessoryBean; import org.tinylog.Logger; /** @@ -65,8 +66,8 @@ public void run() { if (event instanceof SensorEvent sensorEvent) { fireSensorEvent(sensorEvent); } - if (event instanceof AccessoryEvent) { - + if (event instanceof AccessoryEvent accessoryEvent) { + switchChanged(accessoryEvent); } } else { @@ -93,4 +94,9 @@ private void fireSensorEvent(SensorEvent sensorEvent) { } } + private void switchChanged(AccessoryEvent accessoryEvent) { + AccessoryBean ab = accessoryEvent.getAccessoryBean(); + JCS.getJcsCommandStation().switchAccessory(ab, ab.getAccessoryValue()); + } + } diff --git a/src/main/java/jcs/ui/layout/tiles/TileModel.java b/src/main/java/jcs/ui/layout/tiles/TileModel.java index 31a4cb28..4266b0e7 100644 --- a/src/main/java/jcs/ui/layout/tiles/TileModel.java +++ b/src/main/java/jcs/ui/layout/tiles/TileModel.java @@ -19,6 +19,7 @@ import java.awt.event.ActionListener; import java.io.Serializable; import javax.swing.event.ChangeListener; +import jcs.entities.AccessoryBean; import jcs.entities.BlockBean; import jcs.entities.LocomotiveBean; import jcs.entities.TileBean; @@ -77,6 +78,14 @@ public interface TileModel extends Serializable { public void setSensorActive(boolean active); + AccessoryBean.AccessoryValue getAccessoryValue(); + + public void setAccessoryValue(AccessoryBean.AccessoryValue accessoryValue); + + AccessoryBean.SignalValue getSignalValue(); + + public void setSignalValue(AccessoryBean.SignalValue signalValue); + BlockBean.BlockState getBlockState(); public void setBlockState(BlockBean.BlockState blockState); diff --git a/src/main/java/jcs/ui/layout/tiles/ui/CrossUI.java b/src/main/java/jcs/ui/layout/tiles/ui/CrossUI.java index 94255d94..62848973 100644 --- a/src/main/java/jcs/ui/layout/tiles/ui/CrossUI.java +++ b/src/main/java/jcs/ui/layout/tiles/ui/CrossUI.java @@ -162,8 +162,8 @@ protected void renderRouteDiagonal2(Graphics2D g2, Color color, JComponent c) { @Override public void renderTile(Graphics2D g2, JComponent c) { Tile tile = (Tile) c; - AccessoryBean.AccessoryValue accessoryValue = tile.getAccessoryValue(); - //Color trackColor = tile.getTrackColor(); + TileModel model = tile.getModel(); + AccessoryBean.AccessoryValue accessoryValue = model.getAccessoryValue(); if (accessoryValue == null) { accessoryValue = AccessoryBean.AccessoryValue.OFF; diff --git a/src/main/java/jcs/ui/layout/tiles/ui/SensorUI.java b/src/main/java/jcs/ui/layout/tiles/ui/SensorUI.java index c24a6a91..ba953453 100644 --- a/src/main/java/jcs/ui/layout/tiles/ui/SensorUI.java +++ b/src/main/java/jcs/ui/layout/tiles/ui/SensorUI.java @@ -32,7 +32,6 @@ import jcs.ui.layout.tiles.Tile; import jcs.ui.layout.tiles.TileCache; import jcs.ui.layout.tiles.TileModel; -import org.tinylog.Logger; public class SensorUI extends StraightUI implements MouseListener { @@ -120,12 +119,21 @@ public void mouseClicked(MouseEvent e) { @Override public void mouseEntered(MouseEvent e) { //Logger.trace("Mouse button " + e.getButton() + " @ (" + e.getXOnScreen() + ","); + Tile tile = (Tile) e.getSource(); + String toolTipText = tile.getId(); + if (tile.getSensorBean() != null) { + toolTipText = toolTipText + "; Id: " + tile.getSensorBean().getId(); + } + tile.setToolTipText(toolTipText); + redispatchToParent(e); } @Override public void mouseExited(MouseEvent e) { //Logger.trace("Mouse button " + e.getButton() + " @ (" + e.getXOnScreen() + ","); + Tile tile = (Tile) e.getSource(); + tile.setToolTipText(null); redispatchToParent(e); } diff --git a/src/main/java/jcs/ui/layout/tiles/ui/SignalUI.java b/src/main/java/jcs/ui/layout/tiles/ui/SignalUI.java index f53462b1..a312bc55 100644 --- a/src/main/java/jcs/ui/layout/tiles/ui/SignalUI.java +++ b/src/main/java/jcs/ui/layout/tiles/ui/SignalUI.java @@ -32,6 +32,7 @@ import static jcs.entities.AccessoryBean.SignalValue.Hp1; import static jcs.entities.AccessoryBean.SignalValue.Hp2; import jcs.ui.layout.tiles.Tile; +import jcs.ui.layout.tiles.TileModel; public class SignalUI extends StraightUI { @@ -50,7 +51,8 @@ public static ComponentUI createUI(JComponent c) { */ protected void renderSignal2(Graphics2D g2d, JComponent c) { Tile tile = (Tile) c; - SignalValue signalValue = tile.getSignalValue(); + TileModel model = tile.getModel(); + SignalValue signalValue = model.getSignalValue(); int rx = RENDER_GRID; int ry = RENDER_GRID + 60; @@ -93,7 +95,8 @@ protected void renderSignal2(Graphics2D g2d, JComponent c) { protected void renderSignal3(Graphics2D g2d, JComponent c) { Tile tile = (Tile) c; - SignalValue signalValue = tile.getSignalValue(); + TileModel model = tile.getModel(); + SignalValue signalValue = model.getSignalValue(); int rx = RENDER_GRID; int ry = RENDER_GRID + 60; @@ -154,7 +157,8 @@ protected void renderSignal3(Graphics2D g2d, JComponent c) { */ protected void renderSignal4(Graphics2D g2d, JComponent c) { Tile tile = (Tile) c; - SignalValue signalValue = tile.getSignalValue(); + TileModel model = tile.getModel(); + SignalValue signalValue = model.getSignalValue(); int rx = RENDER_GRID - 50; int ry = RENDER_GRID + 50; @@ -236,7 +240,8 @@ protected void renderSignal4(Graphics2D g2d, JComponent c) { */ protected void renderSignal2m(Graphics2D g2d, JComponent c) { Tile tile = (Tile) c; - SignalValue signalValue = tile.getSignalValue(); + TileModel model = tile.getModel(); + SignalValue signalValue = model.getSignalValue(); int[] xps = new int[]{RENDER_GRID + 80, +RENDER_GRID + 150, +RENDER_GRID + 170, RENDER_GRID + 170, +RENDER_GRID + 150, RENDER_GRID + 80}; diff --git a/src/main/java/jcs/ui/layout/tiles/ui/SwitchUI.java b/src/main/java/jcs/ui/layout/tiles/ui/SwitchUI.java index fd729988..598719d9 100644 --- a/src/main/java/jcs/ui/layout/tiles/ui/SwitchUI.java +++ b/src/main/java/jcs/ui/layout/tiles/ui/SwitchUI.java @@ -17,17 +17,24 @@ import java.awt.BasicStroke; import java.awt.Color; +import java.awt.Component; import java.awt.Graphics2D; +import java.awt.event.MouseEvent; +import java.awt.event.MouseListener; import javax.swing.JComponent; import javax.swing.plaf.ComponentUI; +import jcs.commandStation.events.AccessoryEvent; import jcs.entities.AccessoryBean; import jcs.entities.AccessoryBean.AccessoryValue; import static jcs.entities.AccessoryBean.AccessoryValue.GREEN; import static jcs.entities.AccessoryBean.AccessoryValue.RED; import jcs.entities.TileBean; import jcs.ui.layout.tiles.Tile; +import jcs.ui.layout.tiles.TileCache; +import jcs.ui.layout.tiles.TileModel; +import org.tinylog.Logger; -public class SwitchUI extends TileUI { +public class SwitchUI extends TileUI implements MouseListener { public SwitchUI() { } @@ -36,6 +43,18 @@ public static ComponentUI createUI(JComponent c) { return new SwitchUI(); } + @Override + public void installUI(JComponent c) { + Tile tile = (Tile) c; + tile.addMouseListener(this); + } + + @Override + public void uninstallUI(JComponent c) { + Tile tile = (Tile) c; + tile.removeMouseListener(this); + } + protected void renderStraight(Graphics2D g2, Color color, JComponent c) { int xx = 0; int yy = 170; @@ -100,7 +119,9 @@ protected void renderRouteDiagonal(Graphics2D g2, Color color, JComponent c) { @Override public void renderTile(Graphics2D g2, JComponent c) { Tile tile = (Tile) c; - AccessoryValue accessoryValue = tile.getAccessoryValue(); + TileModel model = tile.getModel(); + AccessoryValue accessoryValue = model.getAccessoryValue(); + if (accessoryValue == null) { accessoryValue = AccessoryBean.AccessoryValue.OFF; } @@ -140,4 +161,60 @@ public void renderTileRoute(Graphics2D g2, JComponent c) { } } } + + @Override + public void mousePressed(MouseEvent e) { + //Logger.trace("Mouse button " + e.getButton() + " @ (" + e.getXOnScreen() + ","); + redispatchToParent(e); + } + + @Override + public void mouseReleased(MouseEvent e) { + //Logger.trace("Mouse button " + e.getButton() + " @ (" + e.getXOnScreen() + ","); + redispatchToParent(e); + } + + @Override + public void mouseClicked(MouseEvent e) { + //Logger.trace("Mouse button " + e.getButton() + " @ (" + e.getXOnScreen() + ","); + //Only JCS is in CONTROL mode (readonly) activate accessory action events. + if (isControlMode((Component) e.getSource()) && e.getButton() == MouseEvent.BUTTON1) { + Tile tile = (Tile) e.getSource(); + tile.setActive(!tile.isActive()); + + if (tile.getAccessoryBean() != null) { + AccessoryBean ab = tile.getAccessoryBean(); + ab.toggle(); + tile.setAccessoryValue(ab.getAccessoryValue()); + + AccessoryEvent aae = new AccessoryEvent(ab); + TileCache.enqueTileAction(aae); + Logger.trace("Changing Tile " + tile.getId() + " Accessory " + ab.getId() + " to " + ab.getAccessoryValue().getValue() + "..."); + } + } else { + redispatchToParent(e); + } + } + + @Override + public void mouseEntered(MouseEvent e) { + //Logger.trace("Mouse button " + e.getButton() + " @ (" + e.getXOnScreen() + ","); + Tile tile = (Tile) e.getSource(); + String toolTipText = tile.getId(); + if (tile.getAccessoryBean() != null) { + toolTipText = toolTipText + "; Id: " + tile.getAccessoryBean().getId(); + } + tile.setToolTipText(toolTipText); + + redispatchToParent(e); + } + + @Override + public void mouseExited(MouseEvent e) { + //Logger.trace("Mouse button " + e.getButton() + " @ (" + e.getXOnScreen() + ","); + Tile tile = (Tile) e.getSource(); + tile.setToolTipText(null); + redispatchToParent(e); + } + } From 138b01285efa6f9dcf2a83a1821b5c7d6216eb97 Mon Sep 17 00:00:00 2001 From: Frans Jacobs Date: Mon, 10 Feb 2025 21:16:55 +0100 Subject: [PATCH 19/24] Fixed draging, added Restored Signal Control --- .../jcs/persistence/H2PersistenceService.java | 25 ++++++ src/main/java/jcs/ui/layout/LayoutCanvas.java | 34 +------- .../java/jcs/ui/layout/LayoutPanelTester.java | 2 +- .../jcs/ui/layout/LayoutPanelTesterRO.java | 2 +- src/main/java/jcs/ui/layout/tiles/Tile.java | 10 --- .../java/jcs/ui/layout/tiles/ui/SensorUI.java | 45 ++++++---- .../java/jcs/ui/layout/tiles/ui/SignalUI.java | 82 ++++++++++++++++++- .../java/jcs/ui/layout/tiles/ui/SwitchUI.java | 42 ++++++---- .../java/jcs/ui/layout/tiles/ui/TileUI.java | 10 ++- 9 files changed, 174 insertions(+), 78 deletions(-) diff --git a/src/main/java/jcs/persistence/H2PersistenceService.java b/src/main/java/jcs/persistence/H2PersistenceService.java index cb696eac..001e1e64 100755 --- a/src/main/java/jcs/persistence/H2PersistenceService.java +++ b/src/main/java/jcs/persistence/H2PersistenceService.java @@ -629,6 +629,8 @@ public synchronized TileBean persist(TileBean tileBean) { @Override public synchronized void remove(TileBean tileBean) { + removeRouteByTileId(tileBean.getId()); + if (tileBean.getBlockBean() != null) { BlockBean bb = tileBean.getBlockBean(); this.remove(bb); @@ -774,6 +776,29 @@ public synchronized RouteBean persist(RouteBean route) { return route; } + private void removeRouteElementsByRouteId(String routeId) { + database.sql("delete from route_elements where route_id =?", routeId).execute(); + } + + private void removeRouteByTileId(String tileId) { + + List routIds = new ArrayList<>(); + List fromRoutes = database.where("from_tile_id = ?", tileId).results(RouteBean.class); + for (RouteBean rb : fromRoutes) { + removeRouteElementsByRouteId(rb.getId()); + routIds.add(rb.getId()); + } + List toRoutes = database.where("to_tile_id = ?", tileId).results(RouteBean.class); + for (RouteBean rb : toRoutes) { + removeRouteElementsByRouteId(rb.getId()); + routIds.add(rb.getId()); + } + + for (String rid : routIds) { + database.sql("delete from routes where id =?", rid).execute(); + } + } + @Override public synchronized void remove(RouteBean route) { if (route.getRouteElements() != null && !route.getRouteElements().isEmpty()) { diff --git a/src/main/java/jcs/ui/layout/LayoutCanvas.java b/src/main/java/jcs/ui/layout/LayoutCanvas.java index f50704db..a42424c7 100755 --- a/src/main/java/jcs/ui/layout/LayoutCanvas.java +++ b/src/main/java/jcs/ui/layout/LayoutCanvas.java @@ -282,6 +282,7 @@ private void mouseMoveAction(MouseEvent evt) { } private void mousePressedAction(MouseEvent evt) { + Logger.trace("@ (" + evt.getX() + "," + evt.getY() + ")"); Point snapPoint = LayoutUtil.snapToGrid(evt.getPoint()); //Clear any previous selection Tile previousSelected = selectedTile; @@ -376,11 +377,12 @@ void removeTile(Tile tile) { } private void mouseDragAction(MouseEvent evt) { + //Logger.trace("@ (" + evt.getX() + "," + evt.getY() + ")"); Point snapPoint = LayoutUtil.snapToGrid(evt.getPoint()); if (selectedTile != null) { int z = getComponentZOrder(selectedTile); setComponentZOrder(selectedTile, 0); - //Logger.trace("Moving: " + selectedTile.getId() + " @ " + selectedTile.xyToString() + " P: " + snapPoint.x + "," + snapPoint.y + ")"); + Logger.trace("Moving: " + selectedTile.getId() + " @ " + selectedTile.xyToString() + " P: " + snapPoint.x + "," + snapPoint.y + ")"); if (TileCache.canMoveTo(selectedTile, snapPoint)) { selectedTile.setSelectedColor(Tile.DEFAULT_SELECTED_COLOR); @@ -426,7 +428,6 @@ private void mouseDragAction(MouseEvent evt) { } } selectedTile.setBounds(curX, curY, selectedTile.getWidth(), selectedTile.getHeight()); - //this.repaint(selectedTile.getTileBounds()); } } @@ -486,18 +487,6 @@ private void executeControlActionForTile(Tile tile, Point p) { } } -// private void toggleSwitch(Switch turnout) { -// if (turnout.getAccessoryBean() != null) { -// AccessoryBean ab = turnout.getAccessoryBean(); -// ab.toggle(); -// turnout.setAccessoryValue(ab.getAccessoryValue()); -// -// JCS.getJcsCommandStation().switchAccessory(ab, ab.getAccessoryValue()); -// } else { -// Logger.trace("No AccessoryBean configured for Turnout: " + turnout.getId()); -// } -// } - private void toggleSignal(Signal signal) { if (signal.getAccessoryBean() != null) { AccessoryBean ab = signal.getAccessoryBean(); @@ -510,22 +499,6 @@ private void toggleSignal(Signal signal) { } } -// private void toggleSensor(Sensor sensor) { -// SensorBean sb = sensor.getSensorBean(); -// if (sb != null) { -// sb.toggle(); -// sensor.setActive((sb.getStatus() == 1)); -// Logger.trace("id: " + sb.getId() + " state " + sb.getStatus()); -// SensorEvent sensorEvent = new SensorEvent(sb); -// fireFeedbackEvent(sensorEvent); -// } -// } -// private void fireFeedbackEvent(SensorEvent sensorEvent) { -// List acl = JCS.getJcsCommandStation().getFeedbackControllers(); -// for (FeedbackController fbc : acl) { -// fbc.fireSensorEventListeners(sensorEvent); -// } -// } private void editSelectedTileProperties() { //the first tile should be the selected one boolean showProperties = false; @@ -1118,7 +1091,6 @@ private void toggleOutOfOrderMIActionPerformed(ActionEvent evt) {//GEN-FIRST:eve if (currentState != block.getBlockState()) { //getRouteBlockState()) { this.executor.execute(() -> { PersistenceFactory.getService().persist(block.getBlockBean()); - }); } } diff --git a/src/main/java/jcs/ui/layout/LayoutPanelTester.java b/src/main/java/jcs/ui/layout/LayoutPanelTester.java index 21c26fb0..3dbe297b 100644 --- a/src/main/java/jcs/ui/layout/LayoutPanelTester.java +++ b/src/main/java/jcs/ui/layout/LayoutPanelTester.java @@ -42,7 +42,7 @@ public static void main(String args[]) { java.awt.EventQueue.invokeLater(() -> { JFrame f = new JFrame("LayoutPanel Tester"); LayoutPanel layoutPanel = new LayoutPanel(); - f.add(layoutPanel); + f.getContentPane().add(layoutPanel); URL iconUrl = JCS.class.getResource("/media/jcs-train-64.png"); if (iconUrl != null) { diff --git a/src/main/java/jcs/ui/layout/LayoutPanelTesterRO.java b/src/main/java/jcs/ui/layout/LayoutPanelTesterRO.java index 7eb4f2d7..80807bf7 100644 --- a/src/main/java/jcs/ui/layout/LayoutPanelTesterRO.java +++ b/src/main/java/jcs/ui/layout/LayoutPanelTesterRO.java @@ -42,7 +42,7 @@ public static void main(String args[]) { java.awt.EventQueue.invokeLater(() -> { JFrame f = new JFrame("LayoutPanel Tester"); LayoutPanel layoutPanel = new LayoutPanel(true); - f.add(layoutPanel); + f.getContentPane().add(layoutPanel); URL iconUrl = JCS.class.getResource("/media/jcs-train-64.png"); if (iconUrl != null) { diff --git a/src/main/java/jcs/ui/layout/tiles/Tile.java b/src/main/java/jcs/ui/layout/tiles/Tile.java index 1c3648ee..9242f325 100755 --- a/src/main/java/jcs/ui/layout/tiles/Tile.java +++ b/src/main/java/jcs/ui/layout/tiles/Tile.java @@ -508,13 +508,6 @@ public void setAccessoryBean(AccessoryBean accessoryBean) { } } -// public AccessoryValue getAccessoryValue() { -// if (this.accessoryValue == null) { -// return AccessoryValue.OFF; -// } else { -// return accessoryValue; -// } -// } public void setAccessoryValue(AccessoryValue value) { model.setAccessoryValue(value); if (accessoryBean != null) { @@ -535,9 +528,6 @@ public void setRouteValue(AccessoryValue value) { repaint(); } -// public AccessoryBean.SignalValue getSignalValue() { -// return signalValue; -// } public void setSignalValue(AccessoryBean.SignalValue signalValue) { model.setSignalValue(signalValue); if (this.accessoryBean != null) { diff --git a/src/main/java/jcs/ui/layout/tiles/ui/SensorUI.java b/src/main/java/jcs/ui/layout/tiles/ui/SensorUI.java index ba953453..da0c54c4 100644 --- a/src/main/java/jcs/ui/layout/tiles/ui/SensorUI.java +++ b/src/main/java/jcs/ui/layout/tiles/ui/SensorUI.java @@ -23,6 +23,7 @@ import java.awt.RadialGradientPaint; import java.awt.event.MouseEvent; import java.awt.event.MouseListener; +import java.awt.event.MouseMotionListener; import java.awt.geom.Ellipse2D; import java.util.Date; import javax.swing.JComponent; @@ -32,8 +33,9 @@ import jcs.ui.layout.tiles.Tile; import jcs.ui.layout.tiles.TileCache; import jcs.ui.layout.tiles.TileModel; +import org.tinylog.Logger; -public class SensorUI extends StraightUI implements MouseListener { +public class SensorUI extends StraightUI implements MouseListener, MouseMotionListener { public SensorUI() { } @@ -46,12 +48,14 @@ public static ComponentUI createUI(JComponent c) { public void installUI(JComponent c) { Tile tile = (Tile) c; tile.addMouseListener(this); + tile.addMouseMotionListener(this); } @Override public void uninstallUI(JComponent c) { Tile tile = (Tile) c; tile.removeMouseListener(this); + tile.removeMouseMotionListener(this); } private void renderSensor(Graphics2D g2, JComponent c) { @@ -86,21 +90,8 @@ public void renderTile(Graphics2D g2, JComponent c) { @Override public void mousePressed(MouseEvent e) { - //Logger.trace("Mouse button " + e.getButton() + " @ (" + e.getXOnScreen() + ","); - redispatchToParent(e); - } - - @Override - public void mouseReleased(MouseEvent e) { - //Logger.trace("Mouse button " + e.getButton() + " @ (" + e.getXOnScreen() + ","); - redispatchToParent(e); - } - - @Override - public void mouseClicked(MouseEvent e) { - //Logger.trace("Mouse button " + e.getButton() + " @ (" + e.getXOnScreen() + ","); + //Logger.trace("Mouse button " + e.getButton() + " @ (" + e.getXOnScreen() + "," + e.getYOnScreen() + ")"); //Only JCS is in CONTROL mode (readonly) activate sensor action events. - if (isControlMode((Component) e.getSource()) && e.getButton() == MouseEvent.BUTTON1) { Tile tile = (Tile) e.getSource(); tile.setActive(!tile.isActive()); @@ -116,6 +107,18 @@ public void mouseClicked(MouseEvent e) { } } + @Override + public void mouseReleased(MouseEvent e) { + //Logger.trace("Mouse button " + e.getButton() + " @ (" + e.getXOnScreen() + "," + e.getYOnScreen() + ")"); + redispatchToParent(e); + } + + @Override + public void mouseClicked(MouseEvent e) { + //Logger.trace("Mouse button " + e.getButton() + " @ (" + e.getXOnScreen() + "," + e.getYOnScreen()); + redispatchToParent(e); + } + @Override public void mouseEntered(MouseEvent e) { //Logger.trace("Mouse button " + e.getButton() + " @ (" + e.getXOnScreen() + ","); @@ -137,4 +140,16 @@ public void mouseExited(MouseEvent e) { redispatchToParent(e); } + @Override + public void mouseDragged(MouseEvent e) { + //Logger.trace("Mouse button " + e.getButton() + " @ (" + e.getXOnScreen() + "," + e.getYOnScreen()); + redispatchToParent(e); + } + + @Override + public void mouseMoved(MouseEvent e) { + //Logger.trace("Mouse button " + e.getButton() + " @ (" + e.getXOnScreen() + "," + e.getYOnScreen()); + redispatchToParent(e); + } + } diff --git a/src/main/java/jcs/ui/layout/tiles/ui/SignalUI.java b/src/main/java/jcs/ui/layout/tiles/ui/SignalUI.java index a312bc55..d15db642 100644 --- a/src/main/java/jcs/ui/layout/tiles/ui/SignalUI.java +++ b/src/main/java/jcs/ui/layout/tiles/ui/SignalUI.java @@ -17,10 +17,15 @@ import java.awt.BasicStroke; import java.awt.Color; +import java.awt.Component; import java.awt.Graphics2D; import java.awt.Polygon; +import java.awt.event.MouseEvent; +import java.awt.event.MouseListener; +import java.awt.event.MouseMotionListener; import javax.swing.JComponent; import javax.swing.plaf.ComponentUI; +import jcs.commandStation.events.AccessoryEvent; import jcs.entities.AccessoryBean; import jcs.entities.AccessoryBean.SignalType; import static jcs.entities.AccessoryBean.SignalType.HP012; @@ -32,9 +37,11 @@ import static jcs.entities.AccessoryBean.SignalValue.Hp1; import static jcs.entities.AccessoryBean.SignalValue.Hp2; import jcs.ui.layout.tiles.Tile; +import jcs.ui.layout.tiles.TileCache; import jcs.ui.layout.tiles.TileModel; +import org.tinylog.Logger; -public class SignalUI extends StraightUI { +public class SignalUI extends StraightUI implements MouseListener, MouseMotionListener { public SignalUI() { } @@ -43,6 +50,20 @@ public static ComponentUI createUI(JComponent c) { return new SignalUI(); } + @Override + public void installUI(JComponent c) { + Tile tile = (Tile) c; + tile.addMouseListener(this); + tile.addMouseMotionListener(this); + } + + @Override + public void uninstallUI(JComponent c) { + Tile tile = (Tile) c; + tile.removeMouseListener(this); + tile.removeMouseMotionListener(this); + } + /** * Render a Signal with 2 lights * @@ -327,4 +348,63 @@ public void renderTile(Graphics2D g2, JComponent c) { g2d.dispose(); } + @Override + public void mousePressed(MouseEvent e) { + //Only JCS is in CONTROL mode (readonly) activate accessory action events. + if (isControlMode((Component) e.getSource()) && e.getButton() == MouseEvent.BUTTON1) { + Tile tile = (Tile) e.getSource(); + tile.setActive(!tile.isActive()); + + if (tile.getAccessoryBean() != null) { + AccessoryBean ab = tile.getAccessoryBean(); + ab.toggle(); + tile.setSignalValue(ab.getSignalValue()); + + AccessoryEvent aae = new AccessoryEvent(ab); + TileCache.enqueTileAction(aae); + Logger.trace("Changing Tile " + tile.getId() + " Accessory " + ab.getId() + " to " + ab.getSignalValue().getSignalValue() + "..."); + } + } else { + redispatchToParent(e); + } + } + + @Override + public void mouseReleased(MouseEvent e) { + redispatchToParent(e); + } + + @Override + public void mouseClicked(MouseEvent e) { + redispatchToParent(e); + } + + @Override + public void mouseEntered(MouseEvent e) { + Tile tile = (Tile) e.getSource(); + String toolTipText = tile.getId(); + if (tile.getAccessoryBean() != null) { + toolTipText = toolTipText + "; Id: " + tile.getAccessoryBean().getId(); + } + tile.setToolTipText(toolTipText); + redispatchToParent(e); + } + + @Override + public void mouseExited(MouseEvent e) { + Tile tile = (Tile) e.getSource(); + tile.setToolTipText(null); + redispatchToParent(e); + } + + @Override + public void mouseDragged(MouseEvent e) { + redispatchToParent(e); + } + + @Override + public void mouseMoved(MouseEvent e) { + redispatchToParent(e); + } + } diff --git a/src/main/java/jcs/ui/layout/tiles/ui/SwitchUI.java b/src/main/java/jcs/ui/layout/tiles/ui/SwitchUI.java index 598719d9..b12cb799 100644 --- a/src/main/java/jcs/ui/layout/tiles/ui/SwitchUI.java +++ b/src/main/java/jcs/ui/layout/tiles/ui/SwitchUI.java @@ -21,6 +21,7 @@ import java.awt.Graphics2D; import java.awt.event.MouseEvent; import java.awt.event.MouseListener; +import java.awt.event.MouseMotionListener; import javax.swing.JComponent; import javax.swing.plaf.ComponentUI; import jcs.commandStation.events.AccessoryEvent; @@ -34,7 +35,7 @@ import jcs.ui.layout.tiles.TileModel; import org.tinylog.Logger; -public class SwitchUI extends TileUI implements MouseListener { +public class SwitchUI extends TileUI implements MouseListener, MouseMotionListener { public SwitchUI() { } @@ -47,12 +48,14 @@ public static ComponentUI createUI(JComponent c) { public void installUI(JComponent c) { Tile tile = (Tile) c; tile.addMouseListener(this); + tile.addMouseMotionListener(this); } @Override public void uninstallUI(JComponent c) { Tile tile = (Tile) c; tile.removeMouseListener(this); + tile.removeMouseMotionListener(this); } protected void renderStraight(Graphics2D g2, Color color, JComponent c) { @@ -164,19 +167,6 @@ public void renderTileRoute(Graphics2D g2, JComponent c) { @Override public void mousePressed(MouseEvent e) { - //Logger.trace("Mouse button " + e.getButton() + " @ (" + e.getXOnScreen() + ","); - redispatchToParent(e); - } - - @Override - public void mouseReleased(MouseEvent e) { - //Logger.trace("Mouse button " + e.getButton() + " @ (" + e.getXOnScreen() + ","); - redispatchToParent(e); - } - - @Override - public void mouseClicked(MouseEvent e) { - //Logger.trace("Mouse button " + e.getButton() + " @ (" + e.getXOnScreen() + ","); //Only JCS is in CONTROL mode (readonly) activate accessory action events. if (isControlMode((Component) e.getSource()) && e.getButton() == MouseEvent.BUTTON1) { Tile tile = (Tile) e.getSource(); @@ -196,16 +186,24 @@ public void mouseClicked(MouseEvent e) { } } + @Override + public void mouseReleased(MouseEvent e) { + redispatchToParent(e); + } + + @Override + public void mouseClicked(MouseEvent e) { + redispatchToParent(e); + } + @Override public void mouseEntered(MouseEvent e) { - //Logger.trace("Mouse button " + e.getButton() + " @ (" + e.getXOnScreen() + ","); Tile tile = (Tile) e.getSource(); String toolTipText = tile.getId(); if (tile.getAccessoryBean() != null) { toolTipText = toolTipText + "; Id: " + tile.getAccessoryBean().getId(); } tile.setToolTipText(toolTipText); - redispatchToParent(e); } @@ -217,4 +215,16 @@ public void mouseExited(MouseEvent e) { redispatchToParent(e); } + @Override + public void mouseDragged(MouseEvent e) { + //Logger.trace("Mouse button " + e.getButton() + " @ (" + e.getXOnScreen() + "," + e.getYOnScreen()); + redispatchToParent(e); + } + + @Override + public void mouseMoved(MouseEvent e) { + //Logger.trace("Mouse button " + e.getButton() + " @ (" + e.getXOnScreen() + "," + e.getYOnScreen()); + redispatchToParent(e); + } + } diff --git a/src/main/java/jcs/ui/layout/tiles/ui/TileUI.java b/src/main/java/jcs/ui/layout/tiles/ui/TileUI.java index 039988b6..3ba5bec9 100644 --- a/src/main/java/jcs/ui/layout/tiles/ui/TileUI.java +++ b/src/main/java/jcs/ui/layout/tiles/ui/TileUI.java @@ -20,6 +20,7 @@ import java.awt.Graphics; import java.awt.Graphics2D; import java.awt.Insets; +import java.awt.Point; import java.awt.event.MouseEvent; import java.awt.geom.AffineTransform; import java.awt.geom.Ellipse2D; @@ -32,6 +33,7 @@ import static jcs.entities.TileBean.Orientation.SOUTH; import static jcs.entities.TileBean.Orientation.WEST; import jcs.ui.layout.LayoutCanvas; +import jcs.ui.layout.LayoutUtil; import jcs.ui.layout.tiles.Tile; import static jcs.ui.layout.tiles.Tile.DEFAULT_BACKGROUND_COLOR; import static jcs.ui.layout.tiles.Tile.DEFAULT_TRACK_COLOR; @@ -263,7 +265,7 @@ public void paint(Graphics g, JComponent c) { g.drawImage(tileImage, 0, 0, null); g.translate(-insets.left, -insets.top); - if (Logger.isTraceEnabled()) { + if (Logger.isTraceEnabled() && 1 == 2) { Tile tile = (Tile) c; TileModel model = tile.getModel(); long now = System.currentTimeMillis(); @@ -273,8 +275,10 @@ public void paint(Graphics g, JComponent c) { protected void redispatchToParent(MouseEvent e) { Component source = (Component) e.getSource(); - MouseEvent parentEvent = SwingUtilities.convertMouseEvent(source, e, source.getParent()); - source.getParent().dispatchEvent(parentEvent); + Point cp = SwingUtilities.convertPoint(source, e.getPoint(), source.getParent()); + MouseEvent me = new MouseEvent(source, e.getID(), e.getWhen(), e.getModifiersEx(), cp.x, cp.y, e.getClickCount(), e.isPopupTrigger(), e.getButton()); + //Logger.trace("ME @ (" + me.getXOnScreen() + "," + me.getYOnScreen() + ") PE @ (" + cp.x + "," + cp.y + ")"); + source.getParent().dispatchEvent(me); } protected boolean isControlMode(Component c) { From f49924043051e94a6db6884e6acba3e57c872c96 Mon Sep 17 00:00:00 2001 From: Frans Jacobs Date: Wed, 12 Feb 2025 20:54:04 +0100 Subject: [PATCH 20/24] Autopilot is working more or less with some issues --- .../commandStation/autopilot/AutoPilot.java | 50 +++-- .../autopilot/state/Dispatcher.java | 42 ++-- .../autopilot/state/EnterBlockState.java | 14 +- .../autopilot/state/PrepareRouteState.java | 2 +- src/main/java/jcs/ui/JCSFrame.form | 10 +- src/main/java/jcs/ui/JCSFrame.java | 11 +- src/main/java/jcs/ui/layout/LayoutCanvas.java | 92 +++------ src/main/java/jcs/ui/layout/LayoutPanel.form | 6 +- src/main/java/jcs/ui/layout/LayoutPanel.java | 4 +- .../ui/layout/dialogs/BlockControlDialog.java | 174 +++++++++-------- .../jcs/ui/layout/tiles/DefaultTileModel.java | 35 +++- src/main/java/jcs/ui/layout/tiles/Tile.java | 38 +++- .../java/jcs/ui/layout/tiles/TileCache.java | 179 ++++++++++-------- .../java/jcs/ui/layout/tiles/TileModel.java | 2 + .../java/jcs/ui/layout/tiles/ui/BlockUI.java | 3 - 15 files changed, 356 insertions(+), 306 deletions(-) diff --git a/src/main/java/jcs/commandStation/autopilot/AutoPilot.java b/src/main/java/jcs/commandStation/autopilot/AutoPilot.java index d31d1637..ec8f7415 100644 --- a/src/main/java/jcs/commandStation/autopilot/AutoPilot.java +++ b/src/main/java/jcs/commandStation/autopilot/AutoPilot.java @@ -37,13 +37,15 @@ import jcs.entities.RouteBean; import jcs.entities.SensorBean; import jcs.persistence.PersistenceFactory; +import jcs.ui.layout.tiles.Tile; import jcs.ui.layout.tiles.TileCache; -import jcs.ui.layout.events.TileEvent; import org.tinylog.Logger; /** - * - * @author frans + * The AutoPilot is the "automatic driving engine".
+ * Every Locomotive on the track will start it own Thread.
+ * The Dispatcher is run in this Thread.
+ * The AutoPilot has it own Monitor Thread: AutoPilotThread. * */ public final class AutoPilot { @@ -52,9 +54,7 @@ public final class AutoPilot { private static CommandStationBean commandStationBean; - //private final Map sensorHandlers = Collections.synchronizedMap(new HashMap<>()); private static final Map sensorHandlers = new HashMap<>(); - //private final Map dispatchers = Collections.synchronizedMap(new HashMap<>()); private static final Map dispatchers = new HashMap<>(); //Need a list to be able to unregister @@ -289,6 +289,7 @@ public static void resetStates() { int freeBlockCounter = 0; List blocks = PersistenceFactory.getService().getBlocks(); for (BlockBean block : blocks) { + Tile tile = TileCache.findTile(block.getTileId()); if (block.getLocomotiveId() != null) { if (null == block.getBlockState()) { if (BlockBean.BlockState.OCCUPIED == block.getBlockState()) { @@ -298,35 +299,33 @@ public static void resetStates() { switch (block.getBlockState()) { case LOCKED, INBOUND -> { //destinations block, reset! - block.setLocomotive(null); - block.setBlockState(BlockBean.BlockState.FREE); - block.setArrivalSuffix(null); + tile.setLocomotive(null); + //block.setLocomotive(null); + tile.setBlockState(BlockBean.BlockState.FREE); + tile.setArrivalSuffix(null); freeBlockCounter++; } case OUTBOUND -> { - block.setBlockState(BlockBean.BlockState.OCCUPIED); - block.setArrivalSuffix(null); + tile.setBlockState(BlockBean.BlockState.OCCUPIED); + tile.setArrivalSuffix(null); occupiedBlockCounter++; } default -> { if (BlockBean.BlockState.OCCUPIED == block.getBlockState()) { - block.setArrivalSuffix(null); + tile.setArrivalSuffix(null); occupiedBlockCounter++; } } } } } else { - block.setBlockState(BlockBean.BlockState.FREE); + tile.setBlockState(BlockBean.BlockState.FREE); freeBlockCounter++; } - PersistenceFactory.getService().persist(block); - TileEvent tileEvent = new TileEvent(block); - //TileCache.fireTileEventListener(tileEvent); + PersistenceFactory.getService().persist(tile.getBlockBean()); } JCS.getJcsCommandStation().switchPower(true); - Logger.debug("Occupied blocks: " + occupiedBlockCounter + " Free blocks " + freeBlockCounter + " of total " + blocks.size() + " blocks"); } @@ -368,12 +367,12 @@ public static List getOnTrackLocomotives() { } } - //if (Logger.isDebugEnabled()) { - // Logger.trace("There are " + activeLocomotives.size() + " Locomotives on the track: "); - for (LocomotiveBean loc : activeLocomotives) { - Logger.trace(loc); + if (Logger.isTraceEnabled()) { + // Logger.trace("There are " + activeLocomotives.size() + " Locomotives on the track: "); + for (LocomotiveBean loc : activeLocomotives) { + Logger.trace(loc); + } } - //} return new ArrayList<>(activeLocomotives); } @@ -392,29 +391,28 @@ private static void handleGhost(SensorEvent event) { List blocks = PersistenceFactory.getService().getBlocks(); String sensorId = event.getId(); for (BlockBean block : blocks) { + Tile tile = TileCache.findTile(block.getTileId()); + if ((block.getMinSensorId().equals(sensorId) || block.getPlusSensorId().equals(sensorId)) && block.getLocomotiveId() == null) { if (event.getSensorBean().isActive()) { block.setBlockState(BlockBean.BlockState.GHOST); + tile.setBlockState(BlockBean.BlockState.GHOST); //Also persist PersistenceFactory.getService().persist(block); - Logger.warn("Ghost Detected! @ Sensor " + sensorId + " in block " + block.getId()); //Switch power OFF! JCS.getJcsCommandStation().switchPower(false); - - TileEvent tileEvent = new TileEvent(block); - //TileCache.fireTileEventListener(tileEvent); } else { if (block.getLocomotiveId() != null) { //keep state as is } else { block.setBlockState(BlockBean.BlockState.FREE); + tile.setBlockState(BlockBean.BlockState.FREE); } } break; } } - } static void handleSensorEvent(SensorEvent event) { diff --git a/src/main/java/jcs/commandStation/autopilot/state/Dispatcher.java b/src/main/java/jcs/commandStation/autopilot/state/Dispatcher.java index 715e54dc..0c06c18e 100644 --- a/src/main/java/jcs/commandStation/autopilot/state/Dispatcher.java +++ b/src/main/java/jcs/commandStation/autopilot/state/Dispatcher.java @@ -34,6 +34,7 @@ import jcs.persistence.PersistenceFactory; import jcs.ui.layout.tiles.TileCache; import jcs.ui.layout.events.TileEvent; +import jcs.ui.layout.tiles.Tile; import org.tinylog.Logger; /** @@ -189,7 +190,7 @@ BlockBean getDepartureBlock() { return PersistenceFactory.getService().getBlockByTileId(departureBlockId); } else { BlockBean departureBlock = PersistenceFactory.getService().getBlockByLocomotiveId(locomotiveBean.getId()); - this.departureBlockId = departureBlock.getTileId(); + departureBlockId = departureBlock.getTileId(); return departureBlock; } } @@ -289,7 +290,6 @@ public void onIgnoreEvent(SensorEvent event) { this.exitSensorId = null; } } - } //Logger.trace("Event for a ignored listener: " + event.getId() + " Changed: " + event.isChanged() + ", active: " + event.getSensorBean().isActive()); } @@ -326,32 +326,52 @@ public static void resetRoute(RouteBean route) { List routeElements = route.getRouteElements(); for (RouteElementBean re : routeElements) { String tileId = re.getTileId(); - TileEvent tileEvent = new TileEvent(tileId, false); - //TileCache.fireTileEventListener(tileEvent); + Tile tile = TileCache.findTile(tileId); + + if (tile.isBlock()) { + if (tile.getLocomotive() != null) { + tile.setBlockState(BlockBean.BlockState.OCCUPIED); + } else { + tile.setBlockState(BlockBean.BlockState.FREE); + } + } + if (tile.isJunction()) { + tile.setRouteValue(AccessoryBean.AccessoryValue.OFF); + } + tile.setShowRoute(false); } } void showBlockState(BlockBean blockBean) { Logger.trace("Show block " + blockBean); - TileEvent tileEvent = new TileEvent(blockBean); - //TileCache.fireTileEventListener(tileEvent); + Tile tile = TileCache.findTile(blockBean.getTileId()); + tile.setBlockBean(blockBean); } void showRoute(RouteBean routeBean, Color routeColor) { Logger.trace("Show route " + routeBean.toLogString()); List routeElements = routeBean.getRouteElements(); + for (RouteElementBean re : routeElements) { String tileId = re.getTileId(); TileBean.Orientation incomingSide = re.getIncomingOrientation(); - TileEvent tileEvent; + Tile tile = TileCache.findTile(tileId); + tile.setIncomingSide(incomingSide); + tile.setTrackRouteColor(Tile.DEFAULT_ROUTE_TRACK_COLOR); + if (re.isTurnout()) { AccessoryBean.AccessoryValue routeState = re.getAccessoryValue(); - tileEvent = new TileEvent(tileId, true, incomingSide, routeState, routeColor); - } else { - tileEvent = new TileEvent(tileId, true, incomingSide, routeColor); + tile.setRouteValue(routeState); + } else if (re.isBlock()) { + if (re.getTileId().equals(routeBean.getFromTileId())) { + //departure block + tile.setBlockState(BlockBean.BlockState.OUTBOUND); + } else { + tile.setBlockState(BlockBean.BlockState.INBOUND); + } } - //TileCache.fireTileEventListener(tileEvent); + tile.setShowRoute(true); } } diff --git a/src/main/java/jcs/commandStation/autopilot/state/EnterBlockState.java b/src/main/java/jcs/commandStation/autopilot/state/EnterBlockState.java index 1d21e6aa..18583f41 100644 --- a/src/main/java/jcs/commandStation/autopilot/state/EnterBlockState.java +++ b/src/main/java/jcs/commandStation/autopilot/state/EnterBlockState.java @@ -32,7 +32,6 @@ class EnterBlockState extends DispatcherState implements SensorEventListener { private boolean locomotiveBraking = false; private boolean canAdvanceToNextState = false; private String inSensorId; - //private Dispatcher dispatcher; @Override DispatcherState execute(Dispatcher dispatcher) { @@ -53,7 +52,6 @@ DispatcherState execute(Dispatcher dispatcher) { dispatcher.setWaitForSensorid(inSensorId); //Register this state as a SensorEventListener - //this.dispatcher = dispatcher; JCS.getJcsCommandStation().addSensorEventListener(this); Logger.trace("Destination block " + destinationBlock.getId() + " In SensorId: " + inSensorId); @@ -67,19 +65,16 @@ DispatcherState execute(Dispatcher dispatcher) { destinationBlock.setBlockState(BlockBean.BlockState.INBOUND); PersistenceFactory.getService().persist(departureBlock); + PersistenceFactory.getService().persist(destinationBlock); + dispatcher.showBlockState(departureBlock); - dispatcher.showRoute(route, Color.magenta); - - PersistenceFactory.getService().persist(destinationBlock); dispatcher.showBlockState(destinationBlock); //Switch the departure block sensors on again - //dispatcher.clearDepartureIgnoreEventHandlers(); - - //dispatcher.setOccupationSensorId(null); + //dispatcher.clearDepartureIgnoreEventHandlers(); + //dispatcher.setOccupationSensorId(null); //dispatcher.setExitSensorId(null); - Logger.trace("Now Waiting for the IN event from SensorId: " + this.inSensorId + " Running loco: " + locomotive.getName() + " [" + locomotive.getDecoderType().getDecoderType() + " (" + locomotive.getAddress() + ")] Direction: " + locomotive.getDirection().getDirection() + " current velocity: " + locomotive.getVelocity()); } @@ -117,5 +112,4 @@ public void onSensorChange(SensorEvent sensorEvent) { } } } - } diff --git a/src/main/java/jcs/commandStation/autopilot/state/PrepareRouteState.java b/src/main/java/jcs/commandStation/autopilot/state/PrepareRouteState.java index c23b62e2..55ea53c3 100644 --- a/src/main/java/jcs/commandStation/autopilot/state/PrepareRouteState.java +++ b/src/main/java/jcs/commandStation/autopilot/state/PrepareRouteState.java @@ -103,7 +103,7 @@ boolean searchRoute(Dispatcher dispatcher) { Direction newDirection = LocomotiveBean.toggle(oldDirection); Logger.trace("Reversing Locomotive, from " + oldDirection + " to " + newDirection + "..."); - this.swapLocomotiveDirection = true; + swapLocomotiveDirection = true; //Do NOT persist the direction yet, just test.... //locomotive.setDispatcherDirection(newDirection); departureBlock.setLogicalDirection(newDirection.getDirection()); diff --git a/src/main/java/jcs/ui/JCSFrame.form b/src/main/java/jcs/ui/JCSFrame.form index 65291d38..4da3c4b3 100755 --- a/src/main/java/jcs/ui/JCSFrame.form +++ b/src/main/java/jcs/ui/JCSFrame.form @@ -172,6 +172,9 @@ + + + @@ -181,11 +184,6 @@ - - - - - @@ -195,7 +193,7 @@ - + diff --git a/src/main/java/jcs/ui/JCSFrame.java b/src/main/java/jcs/ui/JCSFrame.java index 8db050af..4988a9c7 100755 --- a/src/main/java/jcs/ui/JCSFrame.java +++ b/src/main/java/jcs/ui/JCSFrame.java @@ -162,13 +162,14 @@ public void actionPerformed(ActionEvent e) { public void showExtraToolbar(JToolBar toolbar) { this.jcsToolBar.add(toolbar); jcsToolBar.doLayout(); - this.repaint(); + this.toolbarPanel.repaint(); } public void hideExtraToolbar(JToolBar toolbar) { this.jcsToolBar.remove(toolbar); jcsToolBar.doLayout(); - this.repaint(); + this.toolbarPanel.repaint(); + //this.repaint(); } public void showOverviewPanel() { @@ -336,18 +337,16 @@ public void windowClosing(WindowEvent evt) { }); toolbarPanel.setName("toolbarPanel"); // NOI18N + toolbarPanel.setPreferredSize(new Dimension(1350, 52)); FlowLayout flowLayout8 = new FlowLayout(FlowLayout.LEFT); flowLayout8.setAlignOnBaseline(true); toolbarPanel.setLayout(flowLayout8); - jcsToolBar.setBorderPainted(false); - jcsToolBar.setDoubleBuffered(true); - jcsToolBar.setMargin(new Insets(1, 1, 1, 1)); jcsToolBar.setMaximumSize(new Dimension(1050, 42)); jcsToolBar.setMinimumSize(new Dimension(1000, 42)); jcsToolBar.setName("ToolBar"); // NOI18N jcsToolBar.setOpaque(false); - jcsToolBar.setPreferredSize(new Dimension(1300, 42)); + jcsToolBar.setPreferredSize(new Dimension(1380, 42)); connectButton.setIcon(new ImageIcon(getClass().getResource("/media/monitor-off-24.png"))); // NOI18N connectButton.setToolTipText("Connect/Disconnect with Central Station"); diff --git a/src/main/java/jcs/ui/layout/LayoutCanvas.java b/src/main/java/jcs/ui/layout/LayoutCanvas.java index a42424c7..daad3415 100755 --- a/src/main/java/jcs/ui/layout/LayoutCanvas.java +++ b/src/main/java/jcs/ui/layout/LayoutCanvas.java @@ -37,9 +37,7 @@ import javax.swing.JPanel; import javax.swing.JPopupMenu; import javax.swing.SwingUtilities; -import jcs.JCS; import jcs.commandStation.autopilot.AutoPilot; -import jcs.entities.AccessoryBean; import jcs.entities.BlockBean; import jcs.entities.BlockBean.BlockState; import jcs.entities.LocomotiveBean; @@ -121,7 +119,6 @@ public LayoutCanvas(boolean readonly) { setDoubleBuffered(true); this.readonly = readonly; -// this.selectedRouteElements = new HashMap<>(); this.executor = Executors.newSingleThreadExecutor(); //this.executor = Executors.newCachedThreadPool(); @@ -433,23 +430,10 @@ private void mouseDragAction(MouseEvent evt) { private void mouseReleasedAction(MouseEvent evt) { Point snapPoint = LayoutUtil.snapToGrid(evt.getPoint()); - //if (selectedTile != null) { - // Logger.trace(selectedTile.getId() + " sp: (" + snapPoint.x + "," + snapPoint.y + ")"); - //} else { - // Logger.trace("No Tile @ (" + snapPoint.x + "," + snapPoint.y + ")"); - //} - if (!Mode.CONTROL.equals(mode) && MouseEvent.BUTTON1 == evt.getButton() && selectedTile != null) { if (TileCache.canMoveTo(selectedTile, snapPoint)) { TileCache.moveTo(selectedTile, snapPoint); } else { - //Tile occ = TileCache.findTile(snapPoint); - //String occtile = ""; - //if (occ != null) { - // occtile = " Is occupied by " + occ.getId(); - //} - //Logger.trace("Can't Move tile " + selectedTile.getId() + " from " + selectedTile.xyToString() + " to (" + snapPoint.x + "," + snapPoint.y + ")" + occtile); - selectedTile.setSelectedColor(Tile.DEFAULT_SELECTED_COLOR); selectedTile.setBounds(selectedTile.getTileBounds()); } @@ -472,6 +456,9 @@ private void executeControlActionForTile(Tile tile, Point p) { Block block = (Block) tile; BlockControlDialog bcd = new BlockControlDialog(getParentFrame(), block); bcd.setVisible(true); + + Logger.trace("Block properties closed"); + this.repaint(block.getTileBounds()); } case SIGNAL -> { //this.executor.execute(() -> toggleSignal((Signal) tile)); @@ -487,18 +474,6 @@ private void executeControlActionForTile(Tile tile, Point p) { } } - private void toggleSignal(Signal signal) { - if (signal.getAccessoryBean() != null) { - AccessoryBean ab = signal.getAccessoryBean(); - ab.toggle(); - Logger.trace("A: " + ab.getAddress() + " S: " + ab.getStates() + " P: " + ab.getState()); - - JCS.getJcsCommandStation().switchAccessory(ab, ab.getAccessoryValue()); - } else { - Logger.trace("No AccessoryBean configured for Signal: " + signal.getId()); - } - } - private void editSelectedTileProperties() { //the first tile should be the selected one boolean showProperties = false; @@ -678,19 +653,19 @@ void routeLayout() { private void routeLayoutWithAStar() { //Make sure the layout is saved - TileCache.saveTiles(); + TileCache.persistAllTiles(); AStar astar = new AStar(); astar.buildGraph(TileCache.getTiles()); astar.routeAll(); astar.persistRoutes(); - if (this.routesDialog.isVisible()) { - this.routesDialog.loadRoutes(); + if (routesDialog.isVisible()) { + routesDialog.loadRoutes(); } } void showRoutesDialog() { - this.routesDialog.setVisible(true); + routesDialog.setVisible(true); } /** @@ -983,20 +958,16 @@ private void formMouseDragged(MouseEvent evt) {//GEN-FIRST:event_formMouseDragge private void startLocomotiveMIActionPerformed(ActionEvent evt) {//GEN-FIRST:event_startLocomotiveMIActionPerformed if (this.selectedTile != null) { Block block = (Block) selectedTile; - LocomotiveBean locomotive = block.getBlockBean().getLocomotive(); - - this.executor.execute(() -> AutoPilot.startStopLocomotive(locomotive, true)); - repaint(); + LocomotiveBean locomotive = block.getLocomotive(); + executor.execute(() -> AutoPilot.startStopLocomotive(locomotive, true)); } }//GEN-LAST:event_startLocomotiveMIActionPerformed private void stopLocomotiveMIActionPerformed(ActionEvent evt) {//GEN-FIRST:event_stopLocomotiveMIActionPerformed - if (this.selectedTile != null) { + if (selectedTile != null) { Block block = (Block) selectedTile; - LocomotiveBean locomotive = block.getBlockBean().getLocomotive(); - - this.executor.execute(() -> AutoPilot.startStopLocomotive(locomotive, false)); - repaint(); + LocomotiveBean locomotive = block.getLocomotive(); + executor.execute(() -> AutoPilot.startStopLocomotive(locomotive, false)); } }//GEN-LAST:event_stopLocomotiveMIActionPerformed @@ -1013,19 +984,16 @@ private void resetDispatcherMIActionPerformed(ActionEvent evt) {//GEN-FIRST:even }//GEN-LAST:event_resetDispatcherMIActionPerformed private void removeLocMIActionPerformed(ActionEvent evt) {//GEN-FIRST:event_removeLocMIActionPerformed - if (this.selectedTile != null) { + if (selectedTile != null) { Block block = (Block) selectedTile; - LocomotiveBean locomotive = block.getBlockBean().getLocomotive(); + LocomotiveBean locomotive = block.getLocomotive(); locomotive.setDispatcherDirection(null); - block.getBlockBean().setLocomotive(null); - block.setBlockState(BlockState.FREE); - block.getBlockBean().setArrivalSuffix(null); + block.setLocomotive(null); - this.executor.execute(() -> { + executor.execute(() -> { PersistenceFactory.getService().persist(block.getBlockBean()); PersistenceFactory.getService().persist(locomotive); - repaint(); }); } }//GEN-LAST:event_removeLocMIActionPerformed @@ -1036,8 +1004,7 @@ private void blockPropertiesMIActionPerformed(ActionEvent evt) {//GEN-FIRST:even Block block = (Block) selectedTile; BlockControlDialog bcd = new BlockControlDialog(getParentFrame(), block); bcd.setVisible(true); - - this.repaint(block.getX(), block.getY(), block.getWidth(), block.getHeight()); + repaint(block.getTileBounds()); } }//GEN-LAST:event_blockPropertiesMIActionPerformed @@ -1045,13 +1012,13 @@ private void reverseArrivalSideMIActionPerformed(ActionEvent evt) {//GEN-FIRST:e if (this.selectedTile != null) { Block block = (Block) selectedTile; - String suffix = block.getBlockBean().getArrivalSuffix(); + String suffix = block.getArrivalSuffix(); if ("+".equals(suffix)) { - block.getBlockBean().setArrivalSuffix("-"); + block.setArrivalSuffix("-"); } else { - block.getBlockBean().setArrivalSuffix("+"); + block.setArrivalSuffix("+"); } - block.getBlockBean().setReverseArrival(!block.getBlockBean().isReverseArrival()); + block.setReverseArrival(!block.isReverseArrival()); this.executor.execute(() -> { PersistenceFactory.getService().persist(block.getBlockBean()); }); @@ -1059,18 +1026,19 @@ private void reverseArrivalSideMIActionPerformed(ActionEvent evt) {//GEN-FIRST:e }//GEN-LAST:event_reverseArrivalSideMIActionPerformed private void toggleLocomotiveDirectionMIActionPerformed(ActionEvent evt) {//GEN-FIRST:event_toggleLocomotiveDirectionMIActionPerformed - if (this.selectedTile != null) { + if (selectedTile != null) { Block block = (Block) selectedTile; - LocomotiveBean locomotive = block.getBlockBean().getLocomotive(); + LocomotiveBean locomotive = block.getLocomotive(); + LocomotiveBean.Direction curDir; - if (block.getBlockBean().getLogicalDirection() != null) { - curDir = LocomotiveBean.Direction.get(block.getBlockBean().getLogicalDirection()); + if (block.getLogicalDirection() != null) { + curDir = block.getLogicalDirection(); } else { curDir = locomotive.getDirection(); } LocomotiveBean.Direction newDir = LocomotiveBean.toggle(curDir); - block.getBlockBean().setLogicalDirection(newDir.getDirection()); - Logger.trace(block.getId() + " Logical changed from " + curDir + " to " + newDir + " for " + locomotive.getName()); + block.setLogicalDirection(newDir); + Logger.trace(block.getId() + " LogicalDir changed from " + curDir + " to " + newDir + " for " + locomotive.getName()); this.executor.execute(() -> { PersistenceFactory.getService().persist(block.getTileBean()); @@ -1088,7 +1056,7 @@ private void toggleOutOfOrderMIActionPerformed(ActionEvent evt) {//GEN-FIRST:eve block.setBlockState(BlockState.FREE); } - if (currentState != block.getBlockState()) { //getRouteBlockState()) { + if (currentState != block.getBlockState()) { this.executor.execute(() -> { PersistenceFactory.getService().persist(block.getBlockBean()); }); @@ -1102,7 +1070,7 @@ private void resetGhostMIActionPerformed(ActionEvent evt) {//GEN-FIRST:event_res BlockBean.BlockState currentState = block.getBlockState(); if (BlockBean.BlockState.GHOST == currentState) { - if (block.getBlockBean().getLocomotiveId() != null) { + if (block.getLocomotive() != null) { block.setBlockState(BlockBean.BlockState.OCCUPIED); } else { block.setBlockState(BlockBean.BlockState.FREE); diff --git a/src/main/java/jcs/ui/layout/LayoutPanel.form b/src/main/java/jcs/ui/layout/LayoutPanel.form index 158b41a2..1942d961 100755 --- a/src/main/java/jcs/ui/layout/LayoutPanel.form +++ b/src/main/java/jcs/ui/layout/LayoutPanel.form @@ -163,10 +163,6 @@ - - - - @@ -175,7 +171,7 @@ - + diff --git a/src/main/java/jcs/ui/layout/LayoutPanel.java b/src/main/java/jcs/ui/layout/LayoutPanel.java index df6383c0..20ae29ef 100755 --- a/src/main/java/jcs/ui/layout/LayoutPanel.java +++ b/src/main/java/jcs/ui/layout/LayoutPanel.java @@ -336,12 +336,10 @@ public void componentShown(ComponentEvent evt) { flowLayout1.setAlignOnBaseline(true); topPanel.setLayout(flowLayout1); - toolBar.setDoubleBuffered(true); - toolBar.setMargin(new Insets(1, 1, 1, 1)); toolBar.setMaximumSize(new Dimension(1200, 42)); toolBar.setMinimumSize(new Dimension(1150, 42)); toolBar.setName(""); // NOI18N - toolBar.setPreferredSize(new Dimension(1100, 42)); + toolBar.setPreferredSize(new Dimension(1000, 42)); loadBtn.setIcon(new ImageIcon(getClass().getResource("/media/load-24.png"))); // NOI18N loadBtn.setToolTipText("Load"); diff --git a/src/main/java/jcs/ui/layout/dialogs/BlockControlDialog.java b/src/main/java/jcs/ui/layout/dialogs/BlockControlDialog.java index 3ea13750..22d0953c 100644 --- a/src/main/java/jcs/ui/layout/dialogs/BlockControlDialog.java +++ b/src/main/java/jcs/ui/layout/dialogs/BlockControlDialog.java @@ -24,18 +24,17 @@ import jcs.entities.BlockBean; import jcs.entities.LocomotiveBean; import jcs.persistence.PersistenceFactory; -import jcs.ui.layout.events.TileEvent; import jcs.ui.layout.tiles.Block; +import jcs.ui.layout.tiles.TileCache; import org.tinylog.Logger; /** * - * @author fransjacobs */ public class BlockControlDialog extends javax.swing.JDialog { - + private final Block block; - + private ComboBoxModel locomotiveComboBoxModel; /** @@ -48,25 +47,26 @@ public BlockControlDialog(java.awt.Frame parent, Block block) { super(parent, true); this.block = block; initComponents(); - + postInit(); } - + private void postInit() { setLocationRelativeTo(null); - String text = this.headingLbl.getText() + " " + this.block.getId(); - this.headingLbl.setText(text); - - if (this.block != null) { + if (block != null) { + String text = headingLbl.getText() + " " + block.getId(); + headingLbl.setText(text); + List locos = new LinkedList<>(); LocomotiveBean emptyBean = new LocomotiveBean(); locos.add(emptyBean); locos.addAll(PersistenceFactory.getService().getLocomotives(true)); + //Only Loc's which should be shown locomotiveComboBoxModel = new DefaultComboBoxModel(locos.toArray()); - this.locomotiveCB.setModel(locomotiveComboBoxModel); - - BlockBean bb = this.block.getBlockBean(); + locomotiveCB.setModel(locomotiveComboBoxModel); + + BlockBean bb = block.getBlockBean(); if (bb == null) { bb = PersistenceFactory.getService().getBlockByTileId(block.getId()); if (bb == null) { @@ -79,55 +79,55 @@ private void postInit() { bb.setMaxWaitTime(0); bb.setMinWaitTime(10); } - this.block.setBlockBean(bb); + block.setBlockBean(bb); } - - this.blockIdTF.setText(block.getId()); - this.blockNameTF.setText(bb.getDescription()); - + + blockIdTF.setText(block.getId()); + blockNameTF.setText(bb.getDescription()); + if (bb.getLocomotiveId() != null && bb.getLocomotive() == null) { bb.setLocomotive(PersistenceFactory.getService().getLocomotive(bb.getLocomotiveId())); - this.startLocButton.setEnabled(true); + startLocButton.setEnabled(true); } - + if (bb.getMinWaitTime() != null) { - this.minWaitSpinner.setValue(bb.getMinWaitTime()); + minWaitSpinner.setValue(bb.getMinWaitTime()); } - + if (bb.getMaxWaitTime() != null) { - this.maxWaitSpinner.setValue(bb.getMaxWaitTime()); + maxWaitSpinner.setValue(bb.getMaxWaitTime()); } - - this.alwaysStopCB.setSelected(bb.isAlwaysStop()); - this.randomWaitCB.setSelected(bb.isRandomWait()); - + + alwaysStopCB.setSelected(bb.isAlwaysStop()); + randomWaitCB.setSelected(bb.isRandomWait()); + if (bb.getLocomotive() != null) { - this.locomotiveCB.setSelectedItem(bb.getLocomotive()); + locomotiveCB.setSelectedItem(bb.getLocomotive()); if (bb.getBlockState() == null) { bb.setBlockState(BlockBean.BlockState.OCCUPIED); } - + if (bb.getLocomotive().getLocIcon() != null) { - this.locomotiveIconLbl.setIcon(new ImageIcon(bb.getLocomotive().getLocIcon())); - this.locomotiveIconLbl.setText(null); + locomotiveIconLbl.setIcon(new ImageIcon(bb.getLocomotive().getLocIcon())); + locomotiveIconLbl.setText(null); } else { - this.locomotiveIconLbl.setText(bb.getLocomotive().getName()); + locomotiveIconLbl.setText(bb.getLocomotive().getName()); } - + if (LocomotiveBean.Direction.BACKWARDS == bb.getLocomotive().getDirection()) { - this.backwardsRB.setSelected(true); + backwardsRB.setSelected(true); } else { - this.forwardsRB.setSelected(true); + forwardsRB.setSelected(true); } - - this.startLocButton.setEnabled(AutoPilot.isAutoModeActive()); - this.startLocButton.setSelected(AutoPilot.isRunning(bb.getLocomotive())); + + startLocButton.setEnabled(AutoPilot.isAutoModeActive()); + startLocButton.setSelected(AutoPilot.isRunning(bb.getLocomotive())); } else { - this.locomotiveCB.setSelectedItem(emptyBean); - this.startLocButton.setEnabled(false); - - if (bb.getBlockState() == null) { - bb.setBlockState(BlockBean.BlockState.FREE); + locomotiveCB.setSelectedItem(emptyBean); + startLocButton.setEnabled(false); + + if (block.getBlockState() == null) { + block.setBlockState(BlockBean.BlockState.FREE); } } } @@ -412,50 +412,64 @@ public void actionPerformed(java.awt.event.ActionEvent evt) { }// //GEN-END:initComponents private void saveExitBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_saveExitBtnActionPerformed - if (this.block != null && this.block.getBlockBean() != null) { - BlockBean bb = this.block.getBlockBean(); + if (block != null && block.getBlockBean() != null) { + BlockBean bb = block.getBlockBean(); + bb.setLocomotive(block.getLocomotive()); + if (bb.getLocomotive() == null) { + bb.setBlockState(BlockBean.BlockState.FREE); + } else { + bb.setBlockState(block.getBlockState()); + } + if (block.getLogicalDirection() != null) { + bb.setLogicalDirection(block.getLogicalDirection().getDirection()); + } else { + bb.setLogicalDirection(null); + } + bb.setReverseArrival(block.isReverseArrival()); + bb.setArrivalSuffix(block.getArrivalSuffix()); + PersistenceFactory.getService().persist(bb); + if (bb.getLocomotive() != null && bb.getLocomotive().getName() != null) { LocomotiveBean loc = bb.getLocomotive(); PersistenceFactory.getService().persist(loc); } - TileEvent tileEvent = new TileEvent(bb); - //TileFactory.fireTileEventListener(tileEvent); - //TileCache.fireTileEventListener(tileEvent); - + + TileCache.findTile(bb.getTileId()).setBlockBean(bb); } - - this.setVisible(false); - this.dispose(); + + setVisible(false); + dispose(); Logger.trace(evt.getActionCommand() + "Block " + block.getId() + " Locomotive: " + this.block.getBlockBean().getLocomotive()); }//GEN-LAST:event_saveExitBtnActionPerformed private void locomotiveCBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_locomotiveCBActionPerformed - Logger.trace(evt.getActionCommand() + " -> " + this.locomotiveComboBoxModel.getSelectedItem()); - - LocomotiveBean selected = (LocomotiveBean) this.locomotiveComboBoxModel.getSelectedItem(); - - block.getBlockBean().setLocomotive(selected); - if (block.getBlockBean().getLocomotiveId() != null) { - block.getBlockBean().setBlockState(BlockBean.BlockState.OCCUPIED); - } else { - block.getBlockBean().setBlockState(BlockBean.BlockState.FREE); - } - + Logger.trace(evt.getActionCommand() + " -> " + locomotiveComboBoxModel.getSelectedItem()); + + LocomotiveBean selected = (LocomotiveBean) locomotiveComboBoxModel.getSelectedItem(); + + block.setLocomotive(selected); + //block.getBlockBean().setLocomotive(selected); + //if (block.getBlockBean().getLocomotiveId() != null) { + // block.getBlockBean().setBlockState(BlockBean.BlockState.OCCUPIED); + //} else { + // block.getBlockBean().setBlockState(BlockBean.BlockState.FREE); + //} + if (selected.getLocIcon() != null) { locomotiveIconLbl.setIcon(new ImageIcon(selected.getLocIcon())); locomotiveIconLbl.setText(null); } else { locomotiveIconLbl.setText(selected.getName()); } - + if (LocomotiveBean.Direction.BACKWARDS == selected.getDirection()) { - this.backwardsRB.setSelected(true); + backwardsRB.setSelected(true); } else { - this.forwardsRB.setSelected(true); + forwardsRB.setSelected(true); } - - if (block.getBlockBean().getLocomotiveId() != null) { + + if (block.getLocomotive() != null) { startLocButton.setEnabled(true); } else { startLocButton.setEnabled(false); @@ -463,44 +477,44 @@ private void locomotiveCBActionPerformed(java.awt.event.ActionEvent evt) {//GEN- }//GEN-LAST:event_locomotiveCBActionPerformed private void startLocButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_startLocButtonActionPerformed - LocomotiveBean loc = this.block.getBlockBean().getLocomotive(); + LocomotiveBean loc = block.getLocomotive(); if (loc != null) { - AutoPilot.startStopLocomotive(loc, this.startLocButton.isSelected()); + AutoPilot.startStopLocomotive(loc, startLocButton.isSelected()); } }//GEN-LAST:event_startLocButtonActionPerformed private void reverseArrivalBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_reverseArrivalBtnActionPerformed - String suffix = block.getBlockBean().getArrivalSuffix(); + String suffix = block.getArrivalSuffix(); if ("+".equals(suffix)) { - block.getBlockBean().setArrivalSuffix("-"); + block.setArrivalSuffix("-"); } else { - block.getBlockBean().setArrivalSuffix("+"); + block.setArrivalSuffix("+"); } - block.getBlockBean().setReverseArrival(!block.getBlockBean().isReverseArrival()); + block.setReverseArrival(!block.isReverseArrival()); }//GEN-LAST:event_reverseArrivalBtnActionPerformed private void backwardsRBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_backwardsRBActionPerformed - block.getBlockBean().setLogicalDirection(LocomotiveBean.Direction.BACKWARDS.getDirection()); + block.setLogicalDirection(LocomotiveBean.Direction.BACKWARDS); }//GEN-LAST:event_backwardsRBActionPerformed private void forwardsRBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_forwardsRBActionPerformed - block.getBlockBean().setLogicalDirection(LocomotiveBean.Direction.FORWARDS.getDirection()); + block.setLogicalDirection(LocomotiveBean.Direction.FORWARDS); }//GEN-LAST:event_forwardsRBActionPerformed private void alwaysStopCBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_alwaysStopCBActionPerformed - this.block.getBlockBean().setAlwaysStop(this.alwaysStopCB.isSelected()); + block.getBlockBean().setAlwaysStop(alwaysStopCB.isSelected()); }//GEN-LAST:event_alwaysStopCBActionPerformed private void randomWaitCBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_randomWaitCBActionPerformed - this.block.getBlockBean().setRandomWait(this.randomWaitCB.isSelected()); + block.getBlockBean().setRandomWait(randomWaitCB.isSelected()); }//GEN-LAST:event_randomWaitCBActionPerformed private void minWaitSpinnerStateChanged(javax.swing.event.ChangeEvent evt) {//GEN-FIRST:event_minWaitSpinnerStateChanged - this.block.getBlockBean().setMinWaitTime((Integer) this.minWaitSpinner.getValue()); + block.getBlockBean().setMinWaitTime((Integer) minWaitSpinner.getValue()); }//GEN-LAST:event_minWaitSpinnerStateChanged private void maxWaitSpinnerStateChanged(javax.swing.event.ChangeEvent evt) {//GEN-FIRST:event_maxWaitSpinnerStateChanged - this.block.getBlockBean().setMaxWaitTime((Integer) this.maxWaitSpinner.getValue()); + block.getBlockBean().setMaxWaitTime((Integer) maxWaitSpinner.getValue()); }//GEN-LAST:event_maxWaitSpinnerStateChanged // Variables declaration - do not modify//GEN-BEGIN:variables diff --git a/src/main/java/jcs/ui/layout/tiles/DefaultTileModel.java b/src/main/java/jcs/ui/layout/tiles/DefaultTileModel.java index 7aabdfd7..66ad1089 100644 --- a/src/main/java/jcs/ui/layout/tiles/DefaultTileModel.java +++ b/src/main/java/jcs/ui/layout/tiles/DefaultTileModel.java @@ -23,6 +23,7 @@ import javax.swing.event.EventListenerList; import jcs.entities.AccessoryBean.AccessoryValue; import jcs.entities.AccessoryBean.SignalValue; +import jcs.entities.BlockBean; import jcs.entities.BlockBean.BlockState; import jcs.entities.LocomotiveBean; import jcs.entities.TileBean.Orientation; @@ -54,12 +55,12 @@ public class DefaultTileModel implements TileModel { protected boolean showOutline = false; - protected BlockState blockState; protected boolean reverseArrival; protected String arrivalSuffix; protected boolean overlayImage = false; - protected LocomotiveBean.Direction logicalDirection; + protected BlockState blockState; protected LocomotiveBean locomotive; + protected LocomotiveBean.Direction logicalDirection; public DefaultTileModel() { this(Orientation.EAST); @@ -68,6 +69,7 @@ public DefaultTileModel() { public DefaultTileModel(Orientation orientation) { this.tileOrienation = orientation; this.selectedColor = Tile.DEFAULT_SELECTED_COLOR; + this.blockState = BlockState.FREE; } @Override @@ -159,6 +161,16 @@ public boolean isShowBlockState() { return showBlockState; } + //Set all block properties is one go + @Override + public void setBlockBean(BlockBean blockBean) { + locomotive = blockBean.getLocomotive(); + logicalDirection = LocomotiveBean.Direction.get(blockBean.getLogicalDirection()); + arrivalSuffix = blockBean.getArrivalSuffix(); + reverseArrival = blockBean.isReverseArrival(); + setBlockState(blockBean.getBlockState()); + } + @Override public void setShowBlockState(boolean showBlockState) { this.showBlockState = showBlockState; @@ -242,6 +254,14 @@ public BlockState getBlockState() { @Override public void setBlockState(BlockState blockState) { this.blockState = blockState; + overlayImage = locomotive != null + && locomotive.getLocIcon() != null + && (BlockState.OCCUPIED == blockState || BlockState.INBOUND == blockState || BlockState.OUTBOUND == blockState); + + if (BlockState.FREE == blockState || BlockState.OCCUPIED == blockState) { + arrivalSuffix = null; + } + fireStateChanged(); } @@ -314,6 +334,17 @@ public LocomotiveBean getLocomotive() { @Override public void setLocomotive(LocomotiveBean locomotive) { this.locomotive = locomotive; + if (locomotive != null) { + blockState = BlockState.OCCUPIED; + } else { + blockState = BlockState.FREE; + arrivalSuffix = null; + } + + this.overlayImage = locomotive != null + && locomotive.getLocIcon() != null + && (BlockState.OCCUPIED == blockState || BlockState.INBOUND == blockState || BlockState.OUTBOUND == blockState); + fireStateChanged(); } diff --git a/src/main/java/jcs/ui/layout/tiles/Tile.java b/src/main/java/jcs/ui/layout/tiles/Tile.java index 9242f325..e5ed6a7d 100755 --- a/src/main/java/jcs/ui/layout/tiles/Tile.java +++ b/src/main/java/jcs/ui/layout/tiles/Tile.java @@ -40,7 +40,6 @@ import jcs.entities.AccessoryBean; import jcs.entities.AccessoryBean.AccessoryValue; import jcs.entities.AccessoryBean.SignalType; -import jcs.entities.AccessoryBean.SignalValue; import jcs.entities.BlockBean; import jcs.entities.BlockBean.BlockState; import jcs.entities.LocomotiveBean; @@ -52,6 +51,7 @@ import jcs.ui.layout.LayoutUtil; import static jcs.ui.layout.tiles.Block.BLOCK_HEIGHT; import static jcs.ui.layout.tiles.Block.BLOCK_WIDTH; +import org.tinylog.Logger; /** * Basic graphic element to display a track, turnout, etc on the screen.
@@ -431,12 +431,12 @@ public BlockState getBlockState() { } public void setBlockState(BlockState blockState) { + model.setBlockState(blockState); if (blockBean != null) { blockBean.setBlockState(blockState); - LocomotiveBean locomotive = model.getLocomotive(); - model.setOverlayImage(locomotive != null && locomotive.getLocIcon() != null && (blockState == BlockState.OCCUPIED || blockState == BlockState.INBOUND || blockState == BlockState.OUTBOUND)); + } else { + Logger.warn("Blockbean for " + id + " is NOT set!"); } - model.setBlockState(blockState); } public String getDepartureSuffix() { @@ -444,10 +444,12 @@ public String getDepartureSuffix() { } public void setDepartureSuffix(String suffix) { + model.setDepartureSuffix(suffix); if (blockBean != null) { blockBean.setDepartureSuffix(suffix); + } else { + Logger.warn("Blockbean for " + id + " is NOT set!"); } - model.setDepartureSuffix(suffix); } public boolean isReverseArrival() { @@ -455,10 +457,12 @@ public boolean isReverseArrival() { } public void setReverseArrival(boolean reverseArrival) { + model.setReverseArrival(reverseArrival); if (blockBean != null) { blockBean.setReverseArrival(reverseArrival); + } else { + Logger.warn("Blockbean for " + id + " is NOT set!"); } - model.setReverseArrival(reverseArrival); } public LocomotiveBean.Direction getLogicalDirection() { @@ -466,10 +470,12 @@ public LocomotiveBean.Direction getLogicalDirection() { } public void setLogicalDirection(LocomotiveBean.Direction logicalDirection) { + model.setLogicalDirection(logicalDirection); if (blockBean != null) { blockBean.setLogicalDirection(logicalDirection.getDirection()); + } else { + Logger.warn("Blockbean for " + id + " is NOT set!"); } - model.setLogicalDirection(logicalDirection); } public LocomotiveBean getLocomotive() { @@ -477,12 +483,25 @@ public LocomotiveBean getLocomotive() { } public void setLocomotive(LocomotiveBean locomotive) { + model.setLocomotive(locomotive); if (blockBean != null) { blockBean.setLocomotive(locomotive); - model.setOverlayImage(locomotive != null && locomotive.getLocIcon() != null && (model.getBlockState() == BlockState.OCCUPIED || model.getBlockState() == BlockState.INBOUND || model.getBlockState() == BlockState.OUTBOUND)); + } else { + Logger.warn("Blockbean for " + id + " is NOT set!"); } + } - model.setLocomotive(locomotive); + public String getArrivalSuffix() { + return model.getArrivalSuffix(); + } + + public void setArrivalSuffix(String arrivalSuffix) { + model.setArrivalSuffix(arrivalSuffix); + if (blockBean != null) { + blockBean.setArrivalSuffix(arrivalSuffix); + } else { + Logger.warn("Blockbean for " + id + " is NOT set!"); + } } public AccessoryBean getAccessoryBean() { @@ -556,6 +575,7 @@ public BlockBean getBlockBean() { public void setBlockBean(BlockBean blockBean) { this.blockBean = blockBean; + this.model.setBlockBean(blockBean); } public int getRenderOffsetX() { diff --git a/src/main/java/jcs/ui/layout/tiles/TileCache.java b/src/main/java/jcs/ui/layout/tiles/TileCache.java index 528b637c..02c347a6 100644 --- a/src/main/java/jcs/ui/layout/tiles/TileCache.java +++ b/src/main/java/jcs/ui/layout/tiles/TileCache.java @@ -16,30 +16,27 @@ package jcs.ui.layout.tiles; import java.awt.Point; -import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentLinkedQueue; import java.util.stream.Collectors; -import jcs.JCS; -import jcs.commandStation.FeedbackController; import jcs.entities.TileBean; import jcs.persistence.PersistenceFactory; import org.tinylog.Logger; import jcs.commandStation.events.JCSActionEvent; -import jcs.commandStation.events.SensorEvent; /** - * Factory object to create Tiles and cache tiles + * Factory object to create Tiles and cache pointMap * * @author frans */ public class TileCache { - static final Map tiles = new HashMap<>(); - static final Map tileAltPoints = new HashMap<>(); - static final Map points = new HashMap<>(); + static final Map idMap = new ConcurrentHashMap<>(); + static final Map pointMap = new ConcurrentHashMap<>(); + static final Map altPointMap = new ConcurrentHashMap<>(); private static final ConcurrentLinkedQueue eventsQueue = new ConcurrentLinkedQueue(); @@ -57,125 +54,120 @@ public static List loadTiles() { } public static List loadTiles(boolean showvalues) { - tileAltPoints.clear(); - points.clear(); - tiles.clear(); + altPointMap.clear(); + pointMap.clear(); + idMap.clear(); List tileBeans = PersistenceFactory.getService().getTileBeans(); for (TileBean tb : tileBeans) { Tile tile = TileFactory.createTile(tb, showvalues); - tiles.put(tile.getCenter(), tile); - points.put(tile.getId(), tile.getCenter()); - //Alternative point(s) to be able to find all points + idMap.put(tile.id, tile); + pointMap.put(tile.getCenter(), tile); + //Alternative point(s) to be able to find all pointIds if (!tile.getAltPoints().isEmpty()) { Set alt = tile.getAltPoints(); for (Point ap : alt) { - tileAltPoints.put(ap, tile); + altPointMap.put(ap, tile); } } - //Extra actions for some tile of tiles - } - Logger.trace("Loaded " + tiles.size() + " Tiles..."); - return tiles.values().stream().collect(Collectors.toList()); + Logger.trace("Loaded " + idMap.size() + " Tiles..."); + return idMap.values().stream().collect(Collectors.toList()); } public static List getTiles() { - return tiles.values().stream().collect(Collectors.toList()); + return idMap.values().stream().collect(Collectors.toList()); } public static Tile addAndSaveTile(Tile tile) { - tiles.put(tile.getCenter(), tile); - points.put(tile.getId(), tile.getCenter()); + if (tile == null) { + throw new IllegalArgumentException("Tile cannot be null"); + } + + pointMap.put(tile.getCenter(), tile); + idMap.put(tile.getId(), tile); - //Alternative point(s) to be able to find all points + //Alternative point(s) to be able to find all pointIds if (!tile.getAltPoints().isEmpty()) { Set alt = tile.getAltPoints(); for (Point ap : alt) { - tileAltPoints.put(ap, tile); + altPointMap.put(ap, tile); } } - saveTile(tile); - //Logger.trace("Added " + tile + " There are now " + tiles.size() + " tiles..."); + persistTile(tile); + //Logger.trace("Added " + tile + " There are now " + pointMap.size() + " pointMap..."); return tile; } - public static void saveTile(final Tile tile) { - if (tile != null) { - TileBean tb = tile.getTileBean(); - PersistenceFactory.getService().persist(tb); - } else { - Logger.warn("Tile is null?"); + public static void persistTile(final Tile tile) { + if (tile == null) { + throw new IllegalArgumentException("Tile cannot be null"); } + TileBean tb = tile.getTileBean(); + PersistenceFactory.getService().persist(tb); } - public static void saveTiles() { - for (Tile tile : tiles.values()) { - saveTile(tile); + public static void persistAllTiles() { + for (Tile tile : idMap.values()) { + persistTile(tile); } } public static void deleteTile(final Tile tile) { - if (tile != null) { - if (tiles.containsKey(tile.getCenter())) { - Set rps = tile.getAltPoints(); - //Also remove alt points - for (Point ap : rps) { - tileAltPoints.remove(ap); - } - points.remove(tile.getId()); - tiles.remove(tile.getCenter()); - - TileBean tb = tile.getTileBean(); - PersistenceFactory.getService().remove(tb); - Logger.trace("Deleted " + tile.getId()); - } else { - Logger.warn("Tile " + tile.getId() + " not found in cache"); + if (tile == null) { + throw new IllegalArgumentException("Tile cannot be null"); + } + if (idMap.containsKey(tile.id)) { + Set rps = tile.getAltPoints(); + //Also remove alt pointIds + for (Point ap : rps) { + altPointMap.remove(ap); } + pointMap.remove(tile.getCenter()); + idMap.remove(tile.id); + TileBean tb = tile.getTileBean(); + PersistenceFactory.getService().remove(tb); + Logger.trace("Deleted " + tile.getId()); } else { - Logger.warn("Tile is null?"); + Logger.warn("Tile " + tile.getId() + " not found in cache"); } } public static Tile findTile(Point cp) { - Tile result = tiles.get(cp); + Tile result = pointMap.get(cp); if (result == null) { - result = tileAltPoints.get(cp); + result = altPointMap.get(cp); } return result; } public static Tile findTile(String id) { - Point p = points.get(id); - if (p != null) { - return findTile(p); - } else { - return null; - } + Tile tile = idMap.get(id); + return tile; } public static boolean canMoveTo(Tile tile, Point p) { //check if a tile exist with point p //Check if the cache contains a Cp of a tile on p //Logger.trace("Checking " + tile.id + " New Point (" + p.x + "," + p.y + ")"); - if (tiles.containsKey(p) && !tile.getCenter().equals(p) && !tile.getAltPoints().contains(p)) { + if (pointMap.containsKey(p) && !tile.getCenter().equals(p) && !tile.getAltPoints().contains(p)) { return false; } //Check if the cache contains a Cp on any of the Alt point is case of a Block or Cross - if (tileAltPoints.containsKey(p) && !tile.getAltPoints().contains(p)) { + if (altPointMap.containsKey(p) && !tile.getAltPoints().contains(p)) { return false; } - //Check with the tile on the new Cp with the new alt points if that is also free... + //Check with the tile on the new Cp with the new alt pointIds if that is also free... Set altPoints = tile.getAltPoints(p); for (Point ap : altPoints) { - if (tiles.containsKey(ap) && !tile.getCenter().equals(ap) && !tile.getAltPoints().contains(ap)) { + if (pointMap.containsKey(ap) && !tile.getCenter().equals(ap) && !tile.getAltPoints().contains(ap)) { return false; } - if (tileAltPoints.containsKey(ap) && !tile.getAltPoints().contains(ap)) { + if (altPointMap.containsKey(ap) && !tile.getAltPoints().contains(ap)) { return false; } } @@ -184,19 +176,23 @@ public static boolean canMoveTo(Tile tile, Point p) { } public static void moveTo(Tile tile, Point p) { + if (tile == null || p == null) { + throw new IllegalArgumentException("Tile or new Center Point cannot be null"); + } + if (canMoveTo(tile, p)) { //Logger.trace("Moving " + tile.getId() + " from " + tile.xyToString() + " to (" + p.x + "," + p.y + ")"); Set rps = tile.getAltPoints(); - //remove alt points + //remove alt pointIds for (Point ap : rps) { - tileAltPoints.remove(ap); + altPointMap.remove(ap); } - points.remove(tile.getId()); - tiles.remove(tile.getCenter()); + //pointIds.remove(tile.getId()); + idMap.remove(tile.id); + pointMap.remove(tile.getCenter()); tile.setCenter(p); - Tile t = addAndSaveTile(tile); - //Logger.trace("Moved " + t.id + " to " + t.xyToString()); + addAndSaveTile(tile); } else { Tile occ = findTile(p); Logger.trace("Can't Move tile " + tile.id + " from " + tile.xyToString() + " to (" + p.x + "," + p.y + ") Is occupied by " + occ.id); @@ -204,24 +200,25 @@ public static void moveTo(Tile tile, Point p) { } public static Tile rotateTile(Tile tile) { - if (!tiles.containsKey(tile.getCenter())) { + if (!pointMap.containsKey(tile.getCenter())) { Logger.warn("Tile " + tile.getId() + " NOT in cache!"); } - //Remove the alternative or extra points... + //Remove the alternative or extra pointIds... for (Point ep : tile.getAltPoints()) { - tileAltPoints.remove(ep); + altPointMap.remove(ep); } tile.rotate(); //update - tiles.put(tile.getCenter(), tile); + pointMap.put(tile.getCenter(), tile); for (Point ep : tile.getAltPoints()) { - tileAltPoints.put(ep, tile); + altPointMap.put(ep, tile); } + idMap.put(tile.id, tile); - saveTile(tile); + persistTile(tile); return tile; } @@ -234,13 +231,13 @@ public static Tile flipVertical(Tile tile) { } private static Tile flipTile(Tile tile, boolean horizontal) { - if (!tiles.containsKey(tile.getCenter())) { + if (!pointMap.containsKey(tile.getCenter())) { Logger.warn("Tile " + tile.getId() + " NOT in cache!"); } - //Remove the alternative or extra points... + //Remove the alternative or extra pointIds... for (Point ep : tile.getAltPoints()) { - tileAltPoints.remove(ep); + altPointMap.remove(ep); } if (horizontal) { @@ -249,12 +246,13 @@ private static Tile flipTile(Tile tile, boolean horizontal) { tile.flipVertical(); } //update - tiles.put(tile.getCenter(), tile); + pointMap.put(tile.getCenter(), tile); for (Point ep : tile.getAltPoints()) { - tileAltPoints.put(ep, tile); + altPointMap.put(ep, tile); } + idMap.put(tile.id, tile); - saveTile(tile); + persistTile(tile); return tile; } @@ -265,4 +263,21 @@ public static void enqueTileAction(JCSActionEvent jcsEvent) { } } + public static void repaintTile(Tile tile) { + repaintTile(tile.id); + } + + public static void repaintTile(String tileId) { + if (tileId == null) { + throw new IllegalArgumentException("TileId cannot be null"); + } + + if (idMap.containsKey(tileId)) { + Tile tile = idMap.get(tileId); + tile.repaint(); + } else { + Logger.warn("Can't find a Tile with Id: " + tileId + " in the cache"); + } + } + } diff --git a/src/main/java/jcs/ui/layout/tiles/TileModel.java b/src/main/java/jcs/ui/layout/tiles/TileModel.java index 4266b0e7..84900940 100644 --- a/src/main/java/jcs/ui/layout/tiles/TileModel.java +++ b/src/main/java/jcs/ui/layout/tiles/TileModel.java @@ -60,6 +60,8 @@ public interface TileModel extends Serializable { boolean isShowBlockState(); + void setBlockBean(BlockBean blockBean); + public void setShowBlockState(boolean showBlockState); boolean isShowLocomotiveImage(); diff --git a/src/main/java/jcs/ui/layout/tiles/ui/BlockUI.java b/src/main/java/jcs/ui/layout/tiles/ui/BlockUI.java index 41ac8b24..44d9b3b5 100644 --- a/src/main/java/jcs/ui/layout/tiles/ui/BlockUI.java +++ b/src/main/java/jcs/ui/layout/tiles/ui/BlockUI.java @@ -59,9 +59,6 @@ public static ComponentUI createUI(JComponent c) { return new BlockUI(); } -// Color getBlockStateColor() { -// return getBlockStateColor(this.model.getBlockState()); -// } protected Color getBlockStateColor(BlockBean.BlockState blockState) { return switch (blockState) { case GHOST -> From f7ffd046d1364b3e5315eafc8b98f6105bb062f0 Mon Sep 17 00:00:00 2001 From: Frans Jacobs Date: Thu, 13 Feb 2025 20:38:32 +0100 Subject: [PATCH 21/24] More refactoring TileFactory and duplicate TileCache removed --- .../autopilot/state/Dispatcher.java | 169 ++++----- src/main/java/jcs/ui/layout/LayoutCanvas.java | 5 +- .../ui/layout/dialogs/BlockControlDialog.java | 12 +- .../ui/layout/pathfinding/astar/AStar.java | 28 +- .../layout/pathfinding/astar/TileCache.java | 90 ----- .../jcs/ui/layout/tiles/DefaultTileModel.java | 12 +- .../java/jcs/ui/layout/tiles/TileCache.java | 279 ++++++++++++++- .../java/jcs/ui/layout/tiles/TileFactory.java | 320 ------------------ .../java/jcs/ui/layout/tiles/ui/CurvedUI.java | 1 - .../java/jcs/ui/layout/tiles/ui/EndUI.java | 1 - .../java/jcs/ui/layout/tiles/ui/SensorUI.java | 1 - .../java/jcs/ui/layout/tiles/ui/TileUI.java | 1 - .../autopilot/AutoPilotTest.java | 7 +- src/test/java/jcs/ui/layout/TileTest.java | 285 ++++++++-------- .../pathfinding/astar/AStarCrossLeftEast.java | 23 +- .../astar/AStarCrossLeftSouth.java | 16 +- .../astar/AStarCrossRightEast.java | 16 +- .../astar/AStarCrossRightSouth.java | 16 +- .../pathfinding/astar/AStarCrossingTest.java | 19 +- .../astar/AStarSwitchLeftEast.java | 22 +- .../astar/AStarSwitchLeftNorth.java | 16 +- .../astar/AStarSwitchLeftSouth.java | 18 +- .../astar/AStarSwitchLeftWest.java | 17 +- .../layout/pathfinding/astar/AStarTest.java | 14 +- .../astar/AStarTestWithDirection.java | 16 +- .../jcs/ui/layout/tiles/TileTesterFrame.java | 2 +- 26 files changed, 631 insertions(+), 775 deletions(-) delete mode 100644 src/main/java/jcs/ui/layout/pathfinding/astar/TileCache.java delete mode 100755 src/main/java/jcs/ui/layout/tiles/TileFactory.java diff --git a/src/main/java/jcs/commandStation/autopilot/state/Dispatcher.java b/src/main/java/jcs/commandStation/autopilot/state/Dispatcher.java index 0c06c18e..b9f9f44a 100644 --- a/src/main/java/jcs/commandStation/autopilot/state/Dispatcher.java +++ b/src/main/java/jcs/commandStation/autopilot/state/Dispatcher.java @@ -43,14 +43,14 @@ * */ public class Dispatcher { - + private final LocomotiveBean locomotiveBean; - + private RouteBean routeBean; - + private String departureBlockId; private String destinationBlockId; - + private String waitingForSensorId; //Enter Sensor of the destination private String enterSensorId; @@ -61,13 +61,13 @@ public class Dispatcher { private String occupationSensorId; //The exit of the departure private String exitSensorId; - + private final List stateEventListeners; - + private final ThreadGroup parent; - + private StateMachineThread stateMachineThread; - + public Dispatcher(ThreadGroup parent, LocomotiveBean locomotiveBean) { this.parent = parent; this.locomotiveBean = locomotiveBean; @@ -76,27 +76,27 @@ public Dispatcher(ThreadGroup parent, LocomotiveBean locomotiveBean) { this.stateEventListeners = new LinkedList<>(); this.stateMachineThread = new StateMachineThread(parent, this); } - + StateMachineThread getStateMachineThread() { return stateMachineThread; } - + public Long getId() { return this.locomotiveBean.getId(); } - + public String getName() { return this.locomotiveBean.getName(); } - + public LocomotiveBean getLocomotiveBean() { return locomotiveBean; } - + RouteBean getRouteBean() { return routeBean; } - + void setRouteBean(RouteBean routeBean) { this.routeBean = routeBean; if (routeBean == null) { @@ -107,11 +107,11 @@ void setRouteBean(RouteBean routeBean) { this.destinationBlockId = routeBean.getToTileId(); } } - + public boolean isLocomotiveAutomodeOn() { return this.stateMachineThread.isEnableAutomode(); } - + public boolean startLocomotiveAutomode() { //Only when the Autopilot is ON! if (AutoPilot.isAutoModeActive()) { @@ -121,30 +121,30 @@ public boolean startLocomotiveAutomode() { } return this.stateMachineThread.isEnableAutomode(); } - + public void stopLocomotiveAutomode() { stateMachineThread.setEnableAutomode(false); } - + void startRunning() { if (this.stateMachineThread != null && this.stateMachineThread.isThreadRunning()) { return; } - + if (this.stateMachineThread == null || !this.stateMachineThread.isAlive()) { stateMachineThread = new StateMachineThread(this.parent, this); } - + this.stateMachineThread.setEnableAutomode(true); if (!this.stateMachineThread.isThreadRunning()) { this.stateMachineThread.start(); } } - + public void stopRunning() { if (stateMachineThread != null && stateMachineThread.isThreadRunning()) { stateMachineThread.stopRunningThread(); - + try { Logger.trace(this.getName() + " Thread Joining..."); stateMachineThread.join(); @@ -154,7 +154,7 @@ public void stopRunning() { Logger.trace(this.getName() + " Thread Joined!"); } } - + void resetDispatcher() { this.routeBean = null; this.departureBlockId = null; @@ -166,13 +166,13 @@ void resetDispatcher() { this.stateEventListeners.clear(); this.locomotiveBean.setDispatcherDirection(Direction.SWITCH); } - + public void reset() { Logger.trace("Resetting dispatcher " + getName() + " StateMachine..."); this.stateMachineThread.reset(); resetDispatcher(); } - + public boolean isRunning() { if (stateMachineThread != null) { return stateMachineThread.isThreadRunning(); @@ -194,7 +194,7 @@ BlockBean getDepartureBlock() { return departureBlock; } } - + BlockBean getDestinationBlock() { if (destinationBlockId != null) { return PersistenceFactory.getService().getBlockByTileId(destinationBlockId); @@ -205,7 +205,7 @@ BlockBean getDestinationBlock() { return null; } } - + public String getStateName() { if (stateMachineThread != null) { return stateMachineThread.getDispatcherStateName(); @@ -213,47 +213,47 @@ public String getStateName() { return "#Idle"; } } - + void setWaitForSensorid(String sensorId) { this.waitingForSensorId = sensorId; } - + public String getWaitingForSensorId() { return waitingForSensorId; } - + public String getEnterSensorId() { return enterSensorId; } - + void setEnterSensorId(String enterSensorId) { this.enterSensorId = enterSensorId; } - + public String getInSensorId() { return inSensorId; } - + void setInSensorId(String inSensorId) { this.inSensorId = inSensorId; } - + public String getOccupationSensorId() { return occupationSensorId; } - + void setOccupationSensorId(String occupationSensorId) { this.occupationSensorId = occupationSensorId; } - + public String getExitSensorId() { return exitSensorId; } - + void setExitSensorId(String exitSensorId) { this.exitSensorId = exitSensorId; } - + void clearDepartureIgnoreEventHandlers() { if (departureBlockId != null) { BlockBean departureBlock = getDepartureBlock(); @@ -263,7 +263,7 @@ void clearDepartureIgnoreEventHandlers() { AutoPilot.removeHandler(plusSensorId); } } - + public void onIgnoreEvent(SensorEvent event) { //Only in Simulator mode if (JCS.getJcsCommandStation().getCommandStationBean().isVirtual()) { @@ -272,19 +272,19 @@ public void onIgnoreEvent(SensorEvent event) { this.waitingForSensorId = null; } } - + if (this.enterSensorId != null && this.enterSensorId.equals(event.getId())) { if (!event.isActive()) { this.enterSensorId = null; } } - + if (this.inSensorId != null && this.inSensorId.equals(event.getId())) { if (!event.isActive()) { this.inSensorId = null; } } - + if (this.exitSensorId != null && this.exitSensorId.equals(event.getId())) { if (!event.isActive()) { this.exitSensorId = null; @@ -293,100 +293,107 @@ public void onIgnoreEvent(SensorEvent event) { } //Logger.trace("Event for a ignored listener: " + event.getId() + " Changed: " + event.isChanged() + ", active: " + event.getSensorBean().isActive()); } - + synchronized void switchAccessory(AccessoryBean accessory, AccessoryValue value) { JCS.getJcsCommandStation().switchAccessory(accessory, value); } - + synchronized void changeLocomotiveVelocity(LocomotiveBean locomotive, int velocity) { JCS.getJcsCommandStation().changeLocomotiveSpeed(velocity, locomotive); locomotiveBean.setVelocity(velocity); } - + synchronized void changeLocomotiveDirection(LocomotiveBean locomotive, Direction newDirection) { JCS.getJcsCommandStation().changeLocomotiveDirection(newDirection, locomotive); locomotiveBean.setDirection(newDirection); } - + void fireStateListeners(String s) { for (StateEventListener sel : stateEventListeners) { sel.onStateChange(this); } } - + public void addStateEventListener(StateEventListener listener) { stateEventListeners.add(listener); } - + public void removeStateEventListener(StateEventListener listener) { stateEventListeners.remove(listener); } - + public static void resetRoute(RouteBean route) { List routeElements = route.getRouteElements(); for (RouteElementBean re : routeElements) { String tileId = re.getTileId(); Tile tile = TileCache.findTile(tileId); - - if (tile.isBlock()) { - if (tile.getLocomotive() != null) { - tile.setBlockState(BlockBean.BlockState.OCCUPIED); - } else { - tile.setBlockState(BlockBean.BlockState.FREE); + if (tile != null) { + if (tile.isBlock()) { + if (tile.getLocomotive() != null) { + tile.setBlockState(BlockBean.BlockState.OCCUPIED); + } else { + tile.setBlockState(BlockBean.BlockState.FREE); + } } + if (tile.isJunction()) { + tile.setRouteValue(AccessoryBean.AccessoryValue.OFF); + } + tile.setShowRoute(false); + } else { + Logger.warn(("Tile with id " + tileId + " NOT in TileCache!")); } - if (tile.isJunction()) { - tile.setRouteValue(AccessoryBean.AccessoryValue.OFF); - } - tile.setShowRoute(false); } } - + void showBlockState(BlockBean blockBean) { Logger.trace("Show block " + blockBean); Tile tile = TileCache.findTile(blockBean.getTileId()); - tile.setBlockBean(blockBean); + tile.setBlockBean(blockBean); } - + void showRoute(RouteBean routeBean, Color routeColor) { Logger.trace("Show route " + routeBean.toLogString()); List routeElements = routeBean.getRouteElements(); - + for (RouteElementBean re : routeElements) { String tileId = re.getTileId(); - TileBean.Orientation incomingSide = re.getIncomingOrientation(); - Tile tile = TileCache.findTile(tileId); - tile.setIncomingSide(incomingSide); - tile.setTrackRouteColor(Tile.DEFAULT_ROUTE_TRACK_COLOR); - - if (re.isTurnout()) { - AccessoryBean.AccessoryValue routeState = re.getAccessoryValue(); - tile.setRouteValue(routeState); - } else if (re.isBlock()) { - if (re.getTileId().equals(routeBean.getFromTileId())) { - //departure block - tile.setBlockState(BlockBean.BlockState.OUTBOUND); - } else { - tile.setBlockState(BlockBean.BlockState.INBOUND); + if (tile != null) { + TileBean.Orientation incomingSide = re.getIncomingOrientation(); + + tile.setIncomingSide(incomingSide); + tile.setTrackRouteColor(Tile.DEFAULT_ROUTE_TRACK_COLOR); + + if (re.isTurnout()) { + AccessoryBean.AccessoryValue routeState = re.getAccessoryValue(); + tile.setRouteValue(routeState); + } else if (re.isBlock()) { + if (re.getTileId().equals(routeBean.getFromTileId())) { + //departure block + tile.setBlockState(BlockBean.BlockState.OUTBOUND); + } else { + tile.setBlockState(BlockBean.BlockState.INBOUND); + } } + tile.setShowRoute(true); + } else { + Logger.warn("Tile with id " + tileId + " NOT in TileCache!"); } - tile.setShowRoute(true); } } - + int getRandomNumber(int min, int max) { Random random = new Random(); return random.ints(min, max).findFirst().getAsInt(); } - + @Override public int hashCode() { int hash = 7; hash = 37 * hash + Objects.hashCode(locomotiveBean.getId()); return hash; } - + @Override public boolean equals(Object obj) { if (this == obj) { diff --git a/src/main/java/jcs/ui/layout/LayoutCanvas.java b/src/main/java/jcs/ui/layout/LayoutCanvas.java index daad3415..8e3672ef 100755 --- a/src/main/java/jcs/ui/layout/LayoutCanvas.java +++ b/src/main/java/jcs/ui/layout/LayoutCanvas.java @@ -68,7 +68,6 @@ import jcs.ui.layout.tiles.Signal; import jcs.ui.layout.tiles.Switch; import jcs.ui.layout.tiles.Tile; -import jcs.ui.layout.tiles.TileFactory; import jcs.ui.layout.tiles.TileCache; import org.tinylog.Logger; @@ -348,7 +347,7 @@ private void mousePressedAction(MouseEvent evt) { private Tile addTile(Point p, TileType tileType, Orientation orientation, Direction direction, boolean selected, boolean showCenter) { Logger.trace("Adding: " + tileType + " @ " + p + " O: " + orientation + " D: " + direction); - Tile tile = TileFactory.createTile(tileType, orientation, direction, p); + Tile tile = TileCache.createTile(tileType, orientation, direction, p); if (TileCache.canMoveTo(tile, p)) { tile.setSelected(selected); @@ -359,7 +358,7 @@ private Tile addTile(Point p, TileType tileType, Orientation orientation, Direct } else { Tile occ = TileCache.findTile(p); Logger.trace("Can't add tile " + tile.getId() + " on " + tile.xyToString() + " Is occupied by " + occ.getId()); - TileFactory.rollback(tile); + TileCache.rollback(tile); return null; } } diff --git a/src/main/java/jcs/ui/layout/dialogs/BlockControlDialog.java b/src/main/java/jcs/ui/layout/dialogs/BlockControlDialog.java index 22d0953c..88409cd5 100644 --- a/src/main/java/jcs/ui/layout/dialogs/BlockControlDialog.java +++ b/src/main/java/jcs/ui/layout/dialogs/BlockControlDialog.java @@ -448,13 +448,11 @@ private void locomotiveCBActionPerformed(java.awt.event.ActionEvent evt) {//GEN- LocomotiveBean selected = (LocomotiveBean) locomotiveComboBoxModel.getSelectedItem(); - block.setLocomotive(selected); - //block.getBlockBean().setLocomotive(selected); - //if (block.getBlockBean().getLocomotiveId() != null) { - // block.getBlockBean().setBlockState(BlockBean.BlockState.OCCUPIED); - //} else { - // block.getBlockBean().setBlockState(BlockBean.BlockState.FREE); - //} + if (selected.getId() != null) { + block.setLocomotive(selected); + } else { + block.setLocomotive(null); + } if (selected.getLocIcon() != null) { locomotiveIconLbl.setIcon(new ImageIcon(selected.getLocIcon())); diff --git a/src/main/java/jcs/ui/layout/pathfinding/astar/AStar.java b/src/main/java/jcs/ui/layout/pathfinding/astar/AStar.java index a3f84a64..66e5f71c 100644 --- a/src/main/java/jcs/ui/layout/pathfinding/astar/AStar.java +++ b/src/main/java/jcs/ui/layout/pathfinding/astar/AStar.java @@ -29,7 +29,7 @@ import jcs.entities.RouteElementBean; import jcs.persistence.PersistenceFactory; import jcs.ui.layout.tiles.Tile; -import jcs.ui.layout.tiles.TileFactory; +import jcs.ui.layout.tiles.TileCache; import org.tinylog.Logger; /** @@ -39,13 +39,13 @@ */ public class AStar { - private final TileCache tileCache; + //private final TileCache tileCache; private final Graph graph; private final Map routes; public AStar() { - this.tileCache = new TileCache(); + //this.tileCache = new TileCache(); this.routes = new HashMap<>(); this.graph = new Graph(); } @@ -53,8 +53,8 @@ public AStar() { public List> getAllBlockToBlockNodes() { List> fromToList = new ArrayList<>(); - List fromNodes = this.graph.getBlockNodes(); - List toNodes = this.graph.getBlockNodes(); + List fromNodes = graph.getBlockNodes(); + List toNodes = graph.getBlockNodes(); for (Node from : fromNodes) { boolean fromBlock = from.isBlock(); @@ -186,7 +186,7 @@ public List findPath(Node from, String fromSuffix, Node to, String toSuffi } public List routeAll() { - this.routes.clear(); + routes.clear(); List> blockToBlockList = getAllBlockToBlockNodes(); Logger.trace("Try to route " + blockToBlockList.size() * 2 * 2 + " Possible block to block routes"); Logger.trace("============================================================================="); @@ -216,7 +216,7 @@ public List routeAll() { Logger.debug("No Path from " + fid + " to " + tid); } else { RouteBean routeBean = createRouteBeanFromNodePath(path); - this.routes.put(routeBean.getId(), routeBean); + routes.put(routeBean.getId(), routeBean); } //} @@ -231,7 +231,7 @@ public List routeAll() { } public void buildGraph(List tiles) { - this.tileCache.reload(tiles); + //this.tileCache.reload(tiles); this.graph.clear(); //Every Tile becomes a node @@ -248,8 +248,10 @@ public void buildGraph(List tiles) { Logger.trace("Node: " + node.getId() + " has " + neighborPoints.size() + " neighbors " + (node.isBlock() ? "[Block]" : "") + (node.isJunction() ? "[Junction]" : "")); for (Point p : neighborPoints) { - if (tileCache.contains(p)) { - Node neighbor = graph.getNode(tileCache.getTileId(p)); + //if (tileCache.contains(p)) { + if (TileCache.contains(p)) { + //Node neighbor = graph.getNode(tileCache.getTileId(p)); + Node neighbor = graph.getNode(TileCache.findTile(p).getId()); if (node.getTile().isAdjacent(neighbor.getTile())) { double distance; @@ -267,7 +269,7 @@ public void buildGraph(List tiles) { } } //Logger.trace("Neighbor: " + neighbor.getId() + " Distance: " + distance); - this.graph.link(node, neighbor, distance); + graph.link(node, neighbor, distance); } } } @@ -275,11 +277,11 @@ public void buildGraph(List tiles) { } public List getNodes() { - return this.graph.getNodes(); + return graph.getNodes(); } public static void main(String[] a) { - List tiles = TileFactory.toTiles(PersistenceFactory.getService().getTileBeans(), false, false); + List tiles = TileCache.loadTiles(); AStar gb = new AStar(); gb.buildGraph(tiles); diff --git a/src/main/java/jcs/ui/layout/pathfinding/astar/TileCache.java b/src/main/java/jcs/ui/layout/pathfinding/astar/TileCache.java deleted file mode 100644 index 9ce7f707..00000000 --- a/src/main/java/jcs/ui/layout/pathfinding/astar/TileCache.java +++ /dev/null @@ -1,90 +0,0 @@ -/* - * Copyright 2023 frans. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package jcs.ui.layout.pathfinding.astar; - -import java.awt.Point; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import jcs.ui.layout.tiles.Tile; -import org.tinylog.Logger; - -/** - * - * @author frans - */ -public class TileCache { - - private final Map tilePointMap; - private final Map tileIdMap; - - public TileCache() { - this(null); - } - - public TileCache(List tiles) { - this.tilePointMap = new HashMap<>(); - this.tileIdMap = new HashMap<>(); - reload(tiles); - } - - public final synchronized void reload(List tiles) { - this.tilePointMap.clear(); - this.tileIdMap.clear(); - - if (tiles != null && !tiles.isEmpty()) { - for (Tile tile : tiles) { - if (tile.isBlock()) { - //A block is s rectangle which fils the space of 3 tiles hence there are 3 "center" points. - for (Point p : tile.getAltPoints()) { - this.tilePointMap.put(p, tile); - } - } else { - //A tile is a square, center is the point too look for - this.tilePointMap.put(tile.getCenter(), tile); - } - - this.tileIdMap.put(tile.getId(), tile); - } - Logger.trace("Loaded " + tiles.size() + " tiles"); - } - } - - public Tile getTile(String id) { - return this.tileIdMap.get(id); - } - - public boolean contains(String id) { - return this.tileIdMap.containsKey(id); - } - - public Tile getTile(Point p) { - return this.tilePointMap.get(p); - } - - public String getTileId(Point p) { - if (this.tilePointMap.containsKey(p)) { - return this.tilePointMap.get(p).getId(); - } else { - return null; - } - } - - public boolean contains(Point p) { - return this.tilePointMap.containsKey(p); - } - -} diff --git a/src/main/java/jcs/ui/layout/tiles/DefaultTileModel.java b/src/main/java/jcs/ui/layout/tiles/DefaultTileModel.java index 66ad1089..d904fcd5 100644 --- a/src/main/java/jcs/ui/layout/tiles/DefaultTileModel.java +++ b/src/main/java/jcs/ui/layout/tiles/DefaultTileModel.java @@ -164,11 +164,13 @@ public boolean isShowBlockState() { //Set all block properties is one go @Override public void setBlockBean(BlockBean blockBean) { - locomotive = blockBean.getLocomotive(); - logicalDirection = LocomotiveBean.Direction.get(blockBean.getLogicalDirection()); - arrivalSuffix = blockBean.getArrivalSuffix(); - reverseArrival = blockBean.isReverseArrival(); - setBlockState(blockBean.getBlockState()); + if (blockBean != null) { + locomotive = blockBean.getLocomotive(); + logicalDirection = LocomotiveBean.Direction.get(blockBean.getLogicalDirection()); + arrivalSuffix = blockBean.getArrivalSuffix(); + reverseArrival = blockBean.isReverseArrival(); + setBlockState(blockBean.getBlockState()); + } } @Override diff --git a/src/main/java/jcs/ui/layout/tiles/TileCache.java b/src/main/java/jcs/ui/layout/tiles/TileCache.java index 02c347a6..825c3987 100644 --- a/src/main/java/jcs/ui/layout/tiles/TileCache.java +++ b/src/main/java/jcs/ui/layout/tiles/TileCache.java @@ -16,16 +16,31 @@ package jcs.ui.layout.tiles; import java.awt.Point; +import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Set; -import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentLinkedQueue; import java.util.stream.Collectors; +import jcs.JCS; +import jcs.commandStation.events.AccessoryEventListener; import jcs.entities.TileBean; import jcs.persistence.PersistenceFactory; import org.tinylog.Logger; import jcs.commandStation.events.JCSActionEvent; +import jcs.commandStation.events.SensorEventListener; +import jcs.entities.AccessoryBean; +import jcs.entities.SensorBean; +import static jcs.entities.TileBean.TileType.BLOCK; +import static jcs.entities.TileBean.TileType.CROSS; +import static jcs.entities.TileBean.TileType.CROSSING; +import static jcs.entities.TileBean.TileType.CURVED; +import static jcs.entities.TileBean.TileType.END; +import static jcs.entities.TileBean.TileType.SENSOR; +import static jcs.entities.TileBean.TileType.SIGNAL; +import static jcs.entities.TileBean.TileType.STRAIGHT; +import static jcs.entities.TileBean.TileType.STRAIGHT_DIR; +import static jcs.entities.TileBean.TileType.SWITCH; /** * Factory object to create Tiles and cache pointMap @@ -34,12 +49,23 @@ */ public class TileCache { - static final Map idMap = new ConcurrentHashMap<>(); - static final Map pointMap = new ConcurrentHashMap<>(); - static final Map altPointMap = new ConcurrentHashMap<>(); + // Keep the records of the used id sequence number + private static int straightIdSeq; + private static int crossingIdSeq; + private static int curvedIdSeq; + private static int switchIdSeq; + private static int crossIdSeq; + private static int signalIdSeq; + private static int sensorIdSeq; + private static int blockIdSeq; + private static int straightDirectionIdSeq; + private static int endIdSeq; + + static final Map idMap = new HashMap<>(); + static final Map pointMap = new HashMap<>(); + static final Map altPointMap = new HashMap<>(); private static final ConcurrentLinkedQueue eventsQueue = new ConcurrentLinkedQueue(); - private static final TileActionEventHandler actionEventQueueHandler = new TileActionEventHandler(eventsQueue); static { @@ -49,6 +75,243 @@ public class TileCache { private TileCache() { } + private static int nextIdSeq(String id) { + String idnr = id.substring(3); + int idSeq = Integer.parseInt(idnr); + return idSeq; + } + + private static String nextTileId(TileBean.TileType tileType) { + switch (tileType) { + case STRAIGHT -> { + straightIdSeq++; + return "st-" + straightIdSeq; + } + case CROSSING -> { + crossingIdSeq++; + return "cr-" + crossingIdSeq; + } + case CURVED -> { + curvedIdSeq++; + return "ct-" + curvedIdSeq; + } + case SWITCH -> { + switchIdSeq++; + return "sw-" + switchIdSeq; + } + case CROSS -> { + crossIdSeq++; + return "cs-" + crossIdSeq; + } + case SIGNAL -> { + signalIdSeq++; + return "si-" + signalIdSeq; + } + case SENSOR -> { + sensorIdSeq++; + return "se-" + sensorIdSeq; + } + case BLOCK -> { + blockIdSeq++; + return "bk-" + blockIdSeq; + } + case STRAIGHT_DIR -> { + straightDirectionIdSeq++; + return "sd-" + straightDirectionIdSeq; + } + case END -> { + endIdSeq++; + return "et-" + endIdSeq; + } + default -> { + Logger.warn("Unknown Tile Type " + tileType); + return null; + } + } + } + + private static int maxIdSeq(int currentId, int newId) { + if (currentId < newId) { + return newId; + } else { + return currentId; + } + } + + public static Tile createTile(TileBean tileBean, boolean showValues) { + if (tileBean == null) { + return null; + } + + TileBean.TileType tileType = tileBean.getTileType(); + Tile tile = null; + switch (tileType) { + case STRAIGHT -> { + tile = new Straight(tileBean); + straightIdSeq = maxIdSeq(straightIdSeq, nextIdSeq(tileBean.getId())); + } + case CROSSING -> { + tile = new Crossing(tileBean); + crossingIdSeq = maxIdSeq(crossingIdSeq, nextIdSeq(tileBean.getId())); + } + case CURVED -> { + tile = new Curved(tileBean); + curvedIdSeq = maxIdSeq(curvedIdSeq, nextIdSeq(tileBean.getId())); + } + case SWITCH -> { + tile = new Switch(tileBean); + tile.setAccessoryBean(tileBean.getAccessoryBean()); + + switchIdSeq = maxIdSeq(switchIdSeq, nextIdSeq(tileBean.getId())); + if (showValues && tileBean.getAccessoryBean() != null) { + tile.setAccessoryValue((tileBean.getAccessoryBean()).getAccessoryValue()); + } + JCS.getJcsCommandStation().addAccessoryEventListener((AccessoryEventListener) tile); + } + case CROSS -> { + tile = new Cross(tileBean); + tile.setAccessoryBean(tileBean.getAccessoryBean()); + + crossIdSeq = maxIdSeq(crossIdSeq, nextIdSeq(tileBean.getId())); + if (showValues && tileBean.getAccessoryBean() != null) { + tile.setAccessoryValue((tileBean.getAccessoryBean()).getAccessoryValue()); + } + JCS.getJcsCommandStation().addAccessoryEventListener((AccessoryEventListener) tile); + } + case SIGNAL -> { + tile = new Signal(tileBean); + tile.setAccessoryBean(tileBean.getAccessoryBean()); + + signalIdSeq = maxIdSeq(signalIdSeq, nextIdSeq(tileBean.getId())); + if (showValues && tileBean.getAccessoryBean() != null) { + ((Signal) tile).setSignalValue(((AccessoryBean) tileBean.getAccessoryBean()).getSignalValue()); + } + JCS.getJcsCommandStation().addAccessoryEventListener((AccessoryEventListener) tile); + } + case SENSOR -> { + tile = new Sensor(tileBean); + tile.setSensorBean(tileBean.getSensorBean()); + sensorIdSeq = maxIdSeq(sensorIdSeq, nextIdSeq(tileBean.getId())); + + if (showValues && tileBean.getSensorBean() != null) { + ((Sensor) tile).setActive(((SensorBean) tileBean.getSensorBean()).isActive()); + } + JCS.getJcsCommandStation().addSensorEventListener((SensorEventListener) tile); + } + case BLOCK -> { + tile = new Block(tileBean); + tile.setBlockBean(tileBean.getBlockBean()); + blockIdSeq = maxIdSeq(blockIdSeq, nextIdSeq(tileBean.getId())); + } + case STRAIGHT_DIR -> { + tile = new StraightDirection(tileBean); + straightDirectionIdSeq = maxIdSeq(straightDirectionIdSeq, nextIdSeq(tileBean.getId())); + } + case END -> { + tile = new End(tileBean); + endIdSeq = maxIdSeq(endIdSeq, nextIdSeq(tileBean.getId())); + } + default -> + Logger.warn("Unknown Tile Type " + tileType); + } + + return (Tile) tile; + } + + /** + * @param tileType type of type to create + * @param orientation whether the orientation of the Tile is EAST, WEST, NORTH or SOUTH + * @param x the tile center X + * @param y the tile center Y + * @return a Tile object + */ + public static Tile createTile(TileBean.TileType tileType, TileBean.Orientation orientation, int x, int y) { + return createTile(tileType, orientation, TileBean.Direction.CENTER, x, y); + } + + /** + * @param tileType type of type to create + * @param orientation whether the orientation of the Tile is EAST, WEST, NORTH or SOUTH + * @param direction direction plays a role with Turnout tiles whether it goes to the Left or Right + * @param x the tile center X + * @param y the tile center Y + * @return a Tile object + */ + public static Tile createTile(TileBean.TileType tileType, TileBean.Orientation orientation, TileBean.Direction direction, int x, int y) { + return createTile(tileType, orientation, direction, new Point(x, y)); + } + + public static Tile createTile(TileBean.TileType tileType, TileBean.Orientation orientation, TileBean.Direction direction, Point center) { + Tile tile = null; + switch (tileType) { + case STRAIGHT -> { + tile = new Straight(orientation, center); + } + case CROSSING -> { + tile = new Crossing(orientation, center); + } + case CURVED -> + tile = new Curved(orientation, center); + case SWITCH -> + tile = new Switch(orientation, direction, center); + case CROSS -> + tile = new Cross(orientation, direction, center); + case SIGNAL -> + tile = new Signal(orientation, center); + case SENSOR -> + tile = new Sensor(orientation, center); + case BLOCK -> + tile = new Block(orientation, center); + case STRAIGHT_DIR -> + tile = new StraightDirection(orientation, center); + case END -> + tile = new End(orientation, center); + default -> + Logger.warn("Unknown Tile Type " + tileType); + } + + if (tile != null) { + tile.setId(nextTileId(tileType)); + } + + return (Tile) tile; + } + + public static void rollback(Tile tile) { + switch (tile.tileType) { + case STRAIGHT -> { + straightIdSeq--; + } + case CROSSING -> { + crossingIdSeq--; + } + case CURVED -> { + curvedIdSeq--; + } + case SWITCH -> { + switchIdSeq--; + } + case CROSS -> { + crossIdSeq--; + } + case SIGNAL -> { + signalIdSeq--; + } + case SENSOR -> { + sensorIdSeq--; + } + case BLOCK -> { + blockIdSeq--; + } + case STRAIGHT_DIR -> { + straightDirectionIdSeq--; + } + case END -> { + endIdSeq--; + } + } + } + public static List loadTiles() { return loadTiles(false); } @@ -61,7 +324,7 @@ public static List loadTiles(boolean showvalues) { List tileBeans = PersistenceFactory.getService().getTileBeans(); for (TileBean tb : tileBeans) { - Tile tile = TileFactory.createTile(tb, showvalues); + Tile tile = createTile(tb, showvalues); idMap.put(tile.id, tile); pointMap.put(tile.getCenter(), tile); //Alternative point(s) to be able to find all pointIds @@ -149,6 +412,10 @@ public static Tile findTile(String id) { return tile; } + public static boolean contains(Point p) { + return pointMap.containsKey(p); + } + public static boolean canMoveTo(Tile tile, Point p) { //check if a tile exist with point p //Check if the cache contains a Cp of a tile on p diff --git a/src/main/java/jcs/ui/layout/tiles/TileFactory.java b/src/main/java/jcs/ui/layout/tiles/TileFactory.java deleted file mode 100755 index 0e6c6b0d..00000000 --- a/src/main/java/jcs/ui/layout/tiles/TileFactory.java +++ /dev/null @@ -1,320 +0,0 @@ -/* - * Copyright 2023 Frans Jacobs. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package jcs.ui.layout.tiles; - -import java.awt.Point; -import java.util.LinkedList; -import java.util.List; -import jcs.JCS; -import jcs.commandStation.events.AccessoryEventListener; -import jcs.commandStation.events.SensorEventListener; -import jcs.entities.AccessoryBean; -import jcs.entities.SensorBean; -import jcs.entities.TileBean; -import jcs.entities.TileBean.Direction; -import jcs.entities.TileBean.Orientation; -import static jcs.entities.TileBean.TileType.BLOCK; -import static jcs.entities.TileBean.TileType.CROSS; -import static jcs.entities.TileBean.TileType.CROSSING; -import static jcs.entities.TileBean.TileType.CURVED; -import static jcs.entities.TileBean.TileType.END; -import static jcs.entities.TileBean.TileType.SENSOR; -import static jcs.entities.TileBean.TileType.SIGNAL; -import static jcs.entities.TileBean.TileType.STRAIGHT; -import static jcs.entities.TileBean.TileType.STRAIGHT_DIR; -import static jcs.entities.TileBean.TileType.SWITCH; -import org.tinylog.Logger; - -/** - * Factory object to create Tiles and cache tiles - * - * @author frans - */ -public class TileFactory { - - // Keep the records of the used id sequence number - private static int straightIdSeq; - private static int crossingIdSeq; - private static int curvedIdSeq; - private static int switchIdSeq; - private static int crossIdSeq; - private static int signalIdSeq; - private static int sensorIdSeq; - private static int blockIdSeq; - private static int straightDirectionIdSeq; - private static int endIdSeq; - - private TileFactory() { - } - - private static int nextIdSeq(String id) { - String idnr = id.substring(3); - int idSeq = Integer.parseInt(idnr); - return idSeq; - } - - private static String nextTileId(TileBean.TileType tileType) { - switch (tileType) { - case STRAIGHT -> { - straightIdSeq++; - return "st-" + straightIdSeq; - } - case CROSSING -> { - crossingIdSeq++; - return "cr-" + crossingIdSeq; - } - case CURVED -> { - curvedIdSeq++; - return "ct-" + curvedIdSeq; - } - case SWITCH -> { - switchIdSeq++; - return "sw-" + switchIdSeq; - } - case CROSS -> { - crossIdSeq++; - return "cs-" + crossIdSeq; - } - case SIGNAL -> { - signalIdSeq++; - return "si-" + signalIdSeq; - } - case SENSOR -> { - sensorIdSeq++; - return "se-" + sensorIdSeq; - } - case BLOCK -> { - blockIdSeq++; - return "bk-" + blockIdSeq; - } - case STRAIGHT_DIR -> { - straightDirectionIdSeq++; - return "sd-" + straightDirectionIdSeq; - } - case END -> { - endIdSeq++; - return "et-" + endIdSeq; - } - default -> { - Logger.warn("Unknown Tile Type " + tileType); - return null; - } - } - } - - private static int maxIdSeq(int currentId, int newId) { - if (currentId < newId) { - return newId; - } else { - return currentId; - } - } - - public static Tile createTile(String tileId) { - TileBean tileBean = JCS.getPersistenceService().getTileBean(tileId); - return createTile(tileBean); - } - - public static Tile createTile(TileBean tileBean) { - return createTile(tileBean, false); - } - - public static Tile createTile(TileBean tileBean, boolean showValues) { - if (tileBean == null) { - return null; - } - - TileBean.TileType tileType = tileBean.getTileType(); - Tile tile = null; - switch (tileType) { - case STRAIGHT -> { - tile = new Straight(tileBean); - straightIdSeq = maxIdSeq(straightIdSeq, nextIdSeq(tileBean.getId())); - } - case CROSSING -> { - tile = new Crossing(tileBean); - crossingIdSeq = maxIdSeq(crossingIdSeq, nextIdSeq(tileBean.getId())); - } - case CURVED -> { - tile = new Curved(tileBean); - curvedIdSeq = maxIdSeq(curvedIdSeq, nextIdSeq(tileBean.getId())); - } - case SWITCH -> { - tile = new Switch(tileBean); - tile.setAccessoryBean(tileBean.getAccessoryBean()); - - switchIdSeq = maxIdSeq(switchIdSeq, nextIdSeq(tileBean.getId())); - if (showValues && tileBean.getAccessoryBean() != null) { - tile.setAccessoryValue((tileBean.getAccessoryBean()).getAccessoryValue()); - } - JCS.getJcsCommandStation().addAccessoryEventListener((AccessoryEventListener) tile); - } - case CROSS -> { - tile = new Cross(tileBean); - tile.setAccessoryBean(tileBean.getAccessoryBean()); - - crossIdSeq = maxIdSeq(crossIdSeq, nextIdSeq(tileBean.getId())); - if (showValues && tileBean.getAccessoryBean() != null) { - tile.setAccessoryValue((tileBean.getAccessoryBean()).getAccessoryValue()); - } - JCS.getJcsCommandStation().addAccessoryEventListener((AccessoryEventListener) tile); - } - case SIGNAL -> { - tile = new Signal(tileBean); - tile.setAccessoryBean(tileBean.getAccessoryBean()); - - signalIdSeq = maxIdSeq(signalIdSeq, nextIdSeq(tileBean.getId())); - if (showValues && tileBean.getAccessoryBean() != null) { - ((Signal) tile).setSignalValue(((AccessoryBean) tileBean.getAccessoryBean()).getSignalValue()); - } - JCS.getJcsCommandStation().addAccessoryEventListener((AccessoryEventListener) tile); - } - case SENSOR -> { - tile = new Sensor(tileBean); - tile.setSensorBean(tileBean.getSensorBean()); - sensorIdSeq = maxIdSeq(sensorIdSeq, nextIdSeq(tileBean.getId())); - - if (showValues && tileBean.getSensorBean() != null) { - ((Sensor) tile).setActive(((SensorBean) tileBean.getSensorBean()).isActive()); - } - JCS.getJcsCommandStation().addSensorEventListener((SensorEventListener) tile); - } - case BLOCK -> { - tile = new Block(tileBean); - tile.setBlockBean(tileBean.getBlockBean()); - blockIdSeq = maxIdSeq(blockIdSeq, nextIdSeq(tileBean.getId())); - } - case STRAIGHT_DIR -> { - tile = new StraightDirection(tileBean); - straightDirectionIdSeq = maxIdSeq(straightDirectionIdSeq, nextIdSeq(tileBean.getId())); - } - case END -> { - tile = new End(tileBean); - endIdSeq = maxIdSeq(endIdSeq, nextIdSeq(tileBean.getId())); - } - default -> - Logger.warn("Unknown Tile Type " + tileType); - } - - return (Tile) tile; - } - - public static void rollback(Tile tile) { - switch (tile.tileType) { - case STRAIGHT -> { - straightIdSeq--; - } - case CROSSING -> { - crossingIdSeq--; - } - case CURVED -> { - curvedIdSeq--; - } - case SWITCH -> { - switchIdSeq--; - } - case CROSS -> { - crossIdSeq--; - } - case SIGNAL -> { - signalIdSeq--; - } - case SENSOR -> { - sensorIdSeq--; - } - case BLOCK -> { - blockIdSeq--; - } - case STRAIGHT_DIR -> { - straightDirectionIdSeq--; - } - case END -> { - endIdSeq--; - } - } - - } - - /** - * @param tileType type of type to create - * @param orientation whether the orientation of the Tile is EAST, WEST, NORTH or SOUTH - * @param x the tile center X - * @param y the tile center Y - * @return a Tile object - */ - public static Tile createTile(TileBean.TileType tileType, Orientation orientation, int x, int y) { - return createTile(tileType, orientation, Direction.CENTER, x, y); - } - - /** - * @param tileType type of type to create - * @param orientation whether the orientation of the Tile is EAST, WEST, NORTH or SOUTH - * @param direction direction plays a role with Turnout tiles whether it goes to the Left or Right - * @param x the tile center X - * @param y the tile center Y - * @return a Tile object - */ - public static Tile createTile(TileBean.TileType tileType, Orientation orientation, Direction direction, int x, int y) { - return createTile(tileType, orientation, direction, new Point(x, y)); - } - - public static Tile createTile(TileBean.TileType tileType, Orientation orientation, Direction direction, Point center) { - Tile tile = null; - switch (tileType) { - case STRAIGHT -> { - tile = new Straight(orientation, center); - } - case CROSSING -> { - tile = new Crossing(orientation, center); - } - case CURVED -> - tile = new Curved(orientation, center); - case SWITCH -> - tile = new Switch(orientation, direction, center); - case CROSS -> - tile = new Cross(orientation, direction, center); - case SIGNAL -> - tile = new Signal(orientation, center); - case SENSOR -> - tile = new Sensor(orientation, center); - case BLOCK -> - tile = new Block(orientation, center); - case STRAIGHT_DIR -> - tile = new StraightDirection(orientation, center); - case END -> - tile = new End(orientation, center); - default -> - Logger.warn("Unknown Tile Type " + tileType); - } - - if (tile != null) { - tile.setId(nextTileId(tileType)); - } - - return (Tile) tile; - } - - public static List toTiles(List tileBeans, boolean drawOutline, boolean showValues) { - List tileList = new LinkedList<>(); - - for (TileBean tileBean : tileBeans) { - Tile tile = createTile(tileBean, showValues); - tileList.add(tile); - } - return tileList; - } - -} diff --git a/src/main/java/jcs/ui/layout/tiles/ui/CurvedUI.java b/src/main/java/jcs/ui/layout/tiles/ui/CurvedUI.java index 6f176c44..8ceb75f5 100644 --- a/src/main/java/jcs/ui/layout/tiles/ui/CurvedUI.java +++ b/src/main/java/jcs/ui/layout/tiles/ui/CurvedUI.java @@ -19,7 +19,6 @@ import java.awt.Graphics2D; import javax.swing.JComponent; import javax.swing.plaf.ComponentUI; -import jcs.ui.layout.tiles.Tile; public class CurvedUI extends TileUI { diff --git a/src/main/java/jcs/ui/layout/tiles/ui/EndUI.java b/src/main/java/jcs/ui/layout/tiles/ui/EndUI.java index c79b3463..dd84ad21 100644 --- a/src/main/java/jcs/ui/layout/tiles/ui/EndUI.java +++ b/src/main/java/jcs/ui/layout/tiles/ui/EndUI.java @@ -20,7 +20,6 @@ import java.awt.Graphics2D; import javax.swing.JComponent; import javax.swing.plaf.ComponentUI; -import jcs.ui.layout.tiles.Tile; public class EndUI extends TileUI { diff --git a/src/main/java/jcs/ui/layout/tiles/ui/SensorUI.java b/src/main/java/jcs/ui/layout/tiles/ui/SensorUI.java index da0c54c4..14fda899 100644 --- a/src/main/java/jcs/ui/layout/tiles/ui/SensorUI.java +++ b/src/main/java/jcs/ui/layout/tiles/ui/SensorUI.java @@ -33,7 +33,6 @@ import jcs.ui.layout.tiles.Tile; import jcs.ui.layout.tiles.TileCache; import jcs.ui.layout.tiles.TileModel; -import org.tinylog.Logger; public class SensorUI extends StraightUI implements MouseListener, MouseMotionListener { diff --git a/src/main/java/jcs/ui/layout/tiles/ui/TileUI.java b/src/main/java/jcs/ui/layout/tiles/ui/TileUI.java index 3ba5bec9..aa438f1c 100644 --- a/src/main/java/jcs/ui/layout/tiles/ui/TileUI.java +++ b/src/main/java/jcs/ui/layout/tiles/ui/TileUI.java @@ -33,7 +33,6 @@ import static jcs.entities.TileBean.Orientation.SOUTH; import static jcs.entities.TileBean.Orientation.WEST; import jcs.ui.layout.LayoutCanvas; -import jcs.ui.layout.LayoutUtil; import jcs.ui.layout.tiles.Tile; import static jcs.ui.layout.tiles.Tile.DEFAULT_BACKGROUND_COLOR; import static jcs.ui.layout.tiles.Tile.DEFAULT_TRACK_COLOR; diff --git a/src/test/java/jcs/commandStation/autopilot/AutoPilotTest.java b/src/test/java/jcs/commandStation/autopilot/AutoPilotTest.java index 930856ec..26470c86 100644 --- a/src/test/java/jcs/commandStation/autopilot/AutoPilotTest.java +++ b/src/test/java/jcs/commandStation/autopilot/AutoPilotTest.java @@ -31,7 +31,7 @@ import jcs.persistence.PersistenceService; import jcs.persistence.util.PersistenceTestHelper; import jcs.ui.layout.tiles.Tile; -import jcs.ui.layout.tiles.TileFactory; +import jcs.ui.layout.tiles.TileCache; import jcs.util.RunUtil; import static org.junit.Assert.assertEquals; import org.junit.jupiter.api.AfterAll; @@ -71,7 +71,7 @@ public AutoPilotTest() { //When running in a batch the default command station could be different.. CommandStationBean virt = ps.getCommandStation("virtual"); ps.changeDefaultCommandStation(virt); - + if (RunUtil.isWindows()) { Logger.info("Skipping tests on Windows!"); skipTest = true; @@ -358,7 +358,8 @@ public void testGetOnTrackLocomotives() { } System.out.println("getOnTrackLocomotives"); //Check is the test script has run well - List tiles = TileFactory.toTiles(ps.getTileBeans(), false, false); + //List tiles = TileFactory.toTiles(ps.getTileBeans(), false, false); + List tiles = TileCache.loadTiles(false); assertEquals(29, tiles.size()); List blocks = ps.getBlocks(); assertEquals(4, blocks.size()); diff --git a/src/test/java/jcs/ui/layout/TileTest.java b/src/test/java/jcs/ui/layout/TileTest.java index cd18f276..75c2fd1a 100644 --- a/src/test/java/jcs/ui/layout/TileTest.java +++ b/src/test/java/jcs/ui/layout/TileTest.java @@ -24,7 +24,7 @@ import jcs.entities.TileBean.Direction; import jcs.entities.TileBean.Orientation; import jcs.ui.layout.tiles.Tile; -import jcs.ui.layout.tiles.TileFactory; +import jcs.ui.layout.tiles.TileCache; import static org.junit.Assert.*; import org.junit.Test; @@ -39,7 +39,7 @@ public TileTest() { @Test public void testgetCenterX() { System.out.println("getCenterX"); - Tile instance = TileFactory.createTile(TileBean.TileType.STRAIGHT, Orientation.EAST, Direction.CENTER, 180, 100); + Tile instance = TileCache.createTile(TileBean.TileType.STRAIGHT, Orientation.EAST, Direction.CENTER, 180, 100); int expResult = 180; int result = instance.getCenterX(); assertEquals(expResult, result); @@ -48,8 +48,7 @@ public void testgetCenterX() { @Test public void testgetCenterXZero() { System.out.println("getCenterX"); - Tile instance - = TileFactory.createTile(TileBean.TileType.STRAIGHT, Orientation.EAST, Direction.CENTER, 0, 0); + Tile instance = TileCache.createTile(TileBean.TileType.STRAIGHT, Orientation.EAST, Direction.CENTER, 0, 0); int expResult = 20; int result = instance.getCenterX(); assertEquals(expResult, result); @@ -58,13 +57,13 @@ public void testgetCenterXZero() { @Test public void testGetGridX() { System.out.println("getGridX"); - Tile instance = TileFactory.createTile(TileBean.TileType.STRAIGHT, Orientation.EAST, Direction.CENTER, 100, 100); + Tile instance = TileCache.createTile(TileBean.TileType.STRAIGHT, Orientation.EAST, Direction.CENTER, 100, 100); int expResult = 2; int result = (instance.getTileX() - Tile.GRID) / (Tile.GRID * 2); assertEquals(expResult, result); - instance = TileFactory.createTile(TileBean.TileType.STRAIGHT, Orientation.EAST, Direction.CENTER, 220, 220); + instance = TileCache.createTile(TileBean.TileType.STRAIGHT, Orientation.EAST, Direction.CENTER, 220, 220); expResult = 5; result = (instance.getTileX() - Tile.GRID) / (Tile.GRID * 2); @@ -74,7 +73,7 @@ public void testGetGridX() { @Test public void testgetCenterY() { System.out.println("getCenterY"); - Tile instance = TileFactory.createTile(TileBean.TileType.STRAIGHT, Orientation.EAST, Direction.CENTER, 180, 100); + Tile instance = TileCache.createTile(TileBean.TileType.STRAIGHT, Orientation.EAST, Direction.CENTER, 180, 100); int expResult = 100; int result = instance.getCenterY(); assertEquals(expResult, result); @@ -83,7 +82,7 @@ public void testgetCenterY() { @Test public void testgetCenterYZero() { System.out.println("getCenterY"); - Tile instance = TileFactory.createTile(TileBean.TileType.STRAIGHT, Orientation.EAST, Direction.CENTER, 0, 0); + Tile instance = TileCache.createTile(TileBean.TileType.STRAIGHT, Orientation.EAST, Direction.CENTER, 0, 0); int expResult = 20; int result = instance.getCenterY(); assertEquals(expResult, result); @@ -92,7 +91,7 @@ public void testgetCenterYZero() { @Test public void testGetGridY() { System.out.println("getGridY"); - Tile instance = TileFactory.createTile(TileBean.TileType.STRAIGHT, Orientation.WEST, Direction.CENTER, 100, 140); + Tile instance = TileCache.createTile(TileBean.TileType.STRAIGHT, Orientation.WEST, Direction.CENTER, 100, 140); int expResult = 3; int result = (instance.getTileY() - Tile.GRID) / (Tile.GRID * 2); assertEquals(expResult, result); @@ -101,8 +100,7 @@ public void testGetGridY() { @Test public void testGetAllPoints() { System.out.println("getAllPoints"); - Tile instance - = TileFactory.createTile(TileBean.TileType.BLOCK, Orientation.WEST, Direction.CENTER, 220, 220); + Tile instance = TileCache.createTile(TileBean.TileType.BLOCK, Orientation.WEST, Direction.CENTER, 220, 220); Set expResult = new HashSet<>(); expResult.add(new Point(220, 220)); expResult.add(new Point(180, 220)); @@ -116,8 +114,7 @@ public void testGetAllPoints() { @Test public void testGetAltPointsBlock() { System.out.println("getAltPointsBlock"); - Tile instance - = TileFactory.createTile(TileBean.TileType.BLOCK, Orientation.WEST, Direction.CENTER, 220, 220); + Tile instance = TileCache.createTile(TileBean.TileType.BLOCK, Orientation.WEST, Direction.CENTER, 220, 220); Set expResult = new HashSet<>(); expResult.add(new Point(180, 220)); expResult.add(new Point(260, 220)); @@ -128,17 +125,15 @@ public void testGetAltPointsBlock() { @Test public void testGetAltPointsCross() { System.out.println("getAltPointsCross"); - Tile instanceE - = TileFactory.createTile( - TileBean.TileType.CROSS, Orientation.EAST, Direction.CENTER, 220, 220); + Tile instanceE = TileCache.createTile(TileBean.TileType.CROSS, Orientation.EAST, Direction.CENTER, 220, 220); Tile instanceS - = TileFactory.createTile( + = TileCache.createTile( TileBean.TileType.CROSS, Orientation.SOUTH, Direction.CENTER, 220, 220); Tile instanceW - = TileFactory.createTile( + = TileCache.createTile( TileBean.TileType.CROSS, Orientation.WEST, Direction.CENTER, 220, 220); Tile instanceN - = TileFactory.createTile( + = TileCache.createTile( TileBean.TileType.CROSS, Orientation.NORTH, Direction.CENTER, 220, 220); Set expResultE = new HashSet<>(); @@ -175,31 +170,31 @@ public void testGetAltPointsCross() { public void testGetNeighborPointsCross() { System.out.println("getNeighborPointsCross"); Tile instanceEL - = TileFactory.createTile( + = TileCache.createTile( TileBean.TileType.CROSS, Orientation.EAST, Direction.LEFT, 220, 220); Tile instanceER - = TileFactory.createTile( + = TileCache.createTile( TileBean.TileType.CROSS, Orientation.EAST, Direction.RIGHT, 220, 220); Tile instanceWL - = TileFactory.createTile( + = TileCache.createTile( TileBean.TileType.CROSS, Orientation.WEST, Direction.LEFT, 220, 220); Tile instanceWR - = TileFactory.createTile( + = TileCache.createTile( TileBean.TileType.CROSS, Orientation.WEST, Direction.RIGHT, 220, 220); Tile instanceSL - = TileFactory.createTile( + = TileCache.createTile( TileBean.TileType.CROSS, Orientation.SOUTH, Direction.LEFT, 220, 220); Tile instanceSR - = TileFactory.createTile( + = TileCache.createTile( TileBean.TileType.CROSS, Orientation.SOUTH, Direction.RIGHT, 220, 220); Tile instanceNL - = TileFactory.createTile( + = TileCache.createTile( TileBean.TileType.CROSS, Orientation.NORTH, Direction.LEFT, 220, 220); Tile instanceNR - = TileFactory.createTile( + = TileCache.createTile( TileBean.TileType.CROSS, Orientation.NORTH, Direction.RIGHT, 220, 220); Map expResultEL = new HashMap<>(); @@ -287,23 +282,23 @@ public void testGetNeighborPointsCross() { public void testIsAdjacentStraight() { System.out.println("isAdjacentStraight"); Tile instanceE - = TileFactory.createTile( + = TileCache.createTile( TileBean.TileType.STRAIGHT, Orientation.EAST, Direction.CENTER, 100, 100); Tile instanceN - = TileFactory.createTile( + = TileCache.createTile( TileBean.TileType.STRAIGHT, Orientation.NORTH, Direction.CENTER, 100, 100); Tile west - = TileFactory.createTile( + = TileCache.createTile( TileBean.TileType.STRAIGHT, Orientation.WEST, Direction.CENTER, 60, 100); Tile east - = TileFactory.createTile( + = TileCache.createTile( TileBean.TileType.STRAIGHT, Orientation.EAST, Direction.CENTER, 140, 100); Tile north - = TileFactory.createTile( + = TileCache.createTile( TileBean.TileType.STRAIGHT, Orientation.NORTH, Direction.CENTER, 100, 60); Tile south - = TileFactory.createTile( + = TileCache.createTile( TileBean.TileType.STRAIGHT, Orientation.SOUTH, Direction.CENTER, 100, 140); assertTrue(instanceE.isAdjacent(west)); @@ -322,31 +317,31 @@ public void testIsAdjacentBlock() { System.out.println("isAdjacentBlock"); Tile instanceE - = TileFactory.createTile( + = TileCache.createTile( TileBean.TileType.BLOCK, Orientation.EAST, Direction.CENTER, 220, 220); Tile instanceW - = TileFactory.createTile( + = TileCache.createTile( TileBean.TileType.BLOCK, Orientation.WEST, Direction.CENTER, 220, 220); Tile instanceS - = TileFactory.createTile( + = TileCache.createTile( TileBean.TileType.BLOCK, Orientation.SOUTH, Direction.CENTER, 220, 220); Tile instanceN - = TileFactory.createTile( + = TileCache.createTile( TileBean.TileType.BLOCK, Orientation.NORTH, Direction.CENTER, 220, 220); Tile west - = TileFactory.createTile( + = TileCache.createTile( TileBean.TileType.STRAIGHT, Orientation.WEST, Direction.CENTER, 140, 220); Tile east - = TileFactory.createTile( + = TileCache.createTile( TileBean.TileType.STRAIGHT, Orientation.EAST, Direction.CENTER, 300, 220); Tile north - = TileFactory.createTile( + = TileCache.createTile( TileBean.TileType.STRAIGHT, Orientation.NORTH, Direction.CENTER, 220, 140); Tile south - = TileFactory.createTile( + = TileCache.createTile( TileBean.TileType.STRAIGHT, Orientation.SOUTH, Direction.CENTER, 220, 300); assertTrue(instanceE.isAdjacent(west)); @@ -369,29 +364,29 @@ public void testIsAdjacentBlock() { public void testIsAdjacentCurved() { System.out.println("isAdjacentCurved"); Tile instanceE - = TileFactory.createTile( + = TileCache.createTile( TileBean.TileType.CURVED, Orientation.EAST, Direction.CENTER, 860, 140); Tile instanceN - = TileFactory.createTile( + = TileCache.createTile( TileBean.TileType.CURVED, Orientation.NORTH, Direction.CENTER, 860, 140); Tile instanceW - = TileFactory.createTile( + = TileCache.createTile( TileBean.TileType.CURVED, Orientation.WEST, Direction.CENTER, 860, 140); Tile instanceS - = TileFactory.createTile( + = TileCache.createTile( TileBean.TileType.CURVED, Orientation.SOUTH, Direction.CENTER, 860, 140); Tile straightE - = TileFactory.createTile( + = TileCache.createTile( TileBean.TileType.STRAIGHT, Orientation.EAST, Direction.CENTER, 900, 140); Tile straightN - = TileFactory.createTile( + = TileCache.createTile( TileBean.TileType.STRAIGHT, Orientation.NORTH, Direction.CENTER, 860, 100); Tile straightW - = TileFactory.createTile( + = TileCache.createTile( TileBean.TileType.STRAIGHT, Orientation.WEST, Direction.CENTER, 820, 140); Tile straightS - = TileFactory.createTile( + = TileCache.createTile( TileBean.TileType.STRAIGHT, Orientation.SOUTH, Direction.CENTER, 860, 180); assertTrue(instanceE.isAdjacent(straightE)); @@ -420,29 +415,29 @@ public void testIsAdjacentEnd() { System.out.println("isAdjacentEnd"); Tile instanceE - = TileFactory.createTile( + = TileCache.createTile( TileBean.TileType.END, Orientation.EAST, Direction.CENTER, 860, 140); Tile instanceS - = TileFactory.createTile( + = TileCache.createTile( TileBean.TileType.END, Orientation.SOUTH, Direction.CENTER, 860, 140); Tile instanceW - = TileFactory.createTile( + = TileCache.createTile( TileBean.TileType.END, Orientation.WEST, Direction.CENTER, 860, 140); Tile instanceN - = TileFactory.createTile( + = TileCache.createTile( TileBean.TileType.END, Orientation.NORTH, Direction.CENTER, 860, 140); Tile straightE - = TileFactory.createTile( + = TileCache.createTile( TileBean.TileType.STRAIGHT, Orientation.EAST, Direction.CENTER, 900, 140); Tile straightN - = TileFactory.createTile( + = TileCache.createTile( TileBean.TileType.STRAIGHT, Orientation.NORTH, Direction.CENTER, 860, 100); Tile straightW - = TileFactory.createTile( + = TileCache.createTile( TileBean.TileType.STRAIGHT, Orientation.WEST, Direction.CENTER, 820, 140); Tile straightS - = TileFactory.createTile( + = TileCache.createTile( TileBean.TileType.STRAIGHT, Orientation.SOUTH, Direction.CENTER, 860, 180); assertFalse(instanceE.isAdjacent(straightE)); @@ -470,30 +465,30 @@ public void testIsAdjacentEnd() { public void testgetIdSuffix() { System.out.println("getGetIdSuffix"); Tile instanceE - = TileFactory.createTile( + = TileCache.createTile( TileBean.TileType.BLOCK, Orientation.EAST, Direction.CENTER, 220, 220); Tile instanceW - = TileFactory.createTile( + = TileCache.createTile( TileBean.TileType.BLOCK, Orientation.WEST, Direction.CENTER, 220, 220); Tile instanceN - = TileFactory.createTile( + = TileCache.createTile( TileBean.TileType.BLOCK, Orientation.NORTH, Direction.CENTER, 220, 220); Tile instanceS - = TileFactory.createTile( + = TileCache.createTile( TileBean.TileType.BLOCK, Orientation.SOUTH, Direction.CENTER, 220, 220); Tile west - = TileFactory.createTile( + = TileCache.createTile( TileBean.TileType.STRAIGHT, Orientation.WEST, Direction.CENTER, 140, 220); Tile east - = TileFactory.createTile( + = TileCache.createTile( TileBean.TileType.STRAIGHT, Orientation.EAST, Direction.CENTER, 300, 220); Tile north - = TileFactory.createTile( + = TileCache.createTile( TileBean.TileType.STRAIGHT, Orientation.NORTH, Direction.CENTER, 220, 140); Tile south - = TileFactory.createTile( + = TileCache.createTile( TileBean.TileType.STRAIGHT, Orientation.NORTH, Direction.CENTER, 220, 300); String expResult = "-"; @@ -524,55 +519,55 @@ public void testgetIdSuffix() { public void testIsAdjacentSwitchL() { System.out.println("isAdjacentSwitchL"); Tile instanceE - = TileFactory.createTile( + = TileCache.createTile( TileBean.TileType.SWITCH, Orientation.EAST, Direction.LEFT, 1060, 140); Tile instanceS - = TileFactory.createTile( + = TileCache.createTile( TileBean.TileType.SWITCH, Orientation.SOUTH, Direction.LEFT, 1060, 140); Tile instanceW - = TileFactory.createTile( + = TileCache.createTile( TileBean.TileType.SWITCH, Orientation.WEST, Direction.LEFT, 1060, 140); Tile instanceN - = TileFactory.createTile( + = TileCache.createTile( TileBean.TileType.SWITCH, Orientation.NORTH, Direction.LEFT, 1060, 140); Tile north - = TileFactory.createTile( + = TileCache.createTile( TileBean.TileType.STRAIGHT, Orientation.NORTH, Direction.CENTER, 1060, 100); Tile west - = TileFactory.createTile( + = TileCache.createTile( TileBean.TileType.STRAIGHT, Orientation.WEST, Direction.CENTER, 1020, 140); Tile east - = TileFactory.createTile( + = TileCache.createTile( TileBean.TileType.STRAIGHT, Orientation.EAST, Direction.CENTER, 1100, 140); Tile south - = TileFactory.createTile( + = TileCache.createTile( TileBean.TileType.STRAIGHT, Orientation.SOUTH, Direction.CENTER, 1060, 180); Tile westCS - = TileFactory.createTile( + = TileCache.createTile( TileBean.TileType.CURVED, Orientation.SOUTH, Direction.CENTER, 1020, 140); Tile westCE - = TileFactory.createTile( + = TileCache.createTile( TileBean.TileType.CURVED, Orientation.EAST, Direction.CENTER, 1020, 140); Tile westCW - = TileFactory.createTile( + = TileCache.createTile( TileBean.TileType.CURVED, Orientation.WEST, Direction.CENTER, 1020, 140); Tile westCN - = TileFactory.createTile( + = TileCache.createTile( TileBean.TileType.CURVED, Orientation.NORTH, Direction.CENTER, 1020, 140); Tile southCS - = TileFactory.createTile( + = TileCache.createTile( TileBean.TileType.CURVED, Orientation.SOUTH, Direction.CENTER, 1060, 180); Tile southCE - = TileFactory.createTile( + = TileCache.createTile( TileBean.TileType.CURVED, Orientation.EAST, Direction.CENTER, 1060, 180); Tile southCW - = TileFactory.createTile( + = TileCache.createTile( TileBean.TileType.CURVED, Orientation.WEST, Direction.CENTER, 1060, 180); Tile southCN - = TileFactory.createTile( + = TileCache.createTile( TileBean.TileType.CURVED, Orientation.NORTH, Direction.CENTER, 1060, 180); assertTrue(instanceE.isAdjacent(west)); @@ -610,55 +605,55 @@ public void testIsAdjacentSwitchL() { public void testIsAdjacentSwitchR() { System.out.println("isAdjacentSwitchR"); Tile instanceE - = TileFactory.createTile( + = TileCache.createTile( TileBean.TileType.SWITCH, Orientation.EAST, Direction.RIGHT, 1060, 140); Tile instanceS - = TileFactory.createTile( + = TileCache.createTile( TileBean.TileType.SWITCH, Orientation.SOUTH, Direction.RIGHT, 1060, 140); Tile instanceW - = TileFactory.createTile( + = TileCache.createTile( TileBean.TileType.SWITCH, Orientation.WEST, Direction.RIGHT, 1060, 140); Tile instanceN - = TileFactory.createTile( + = TileCache.createTile( TileBean.TileType.SWITCH, Orientation.NORTH, Direction.RIGHT, 1060, 140); Tile north - = TileFactory.createTile( + = TileCache.createTile( TileBean.TileType.STRAIGHT, Orientation.NORTH, Direction.CENTER, 1060, 100); Tile west - = TileFactory.createTile( + = TileCache.createTile( TileBean.TileType.STRAIGHT, Orientation.WEST, Direction.CENTER, 1020, 140); Tile east - = TileFactory.createTile( + = TileCache.createTile( TileBean.TileType.STRAIGHT, Orientation.EAST, Direction.CENTER, 1100, 140); Tile south - = TileFactory.createTile( + = TileCache.createTile( TileBean.TileType.STRAIGHT, Orientation.SOUTH, Direction.CENTER, 1060, 180); Tile eastCS - = TileFactory.createTile( + = TileCache.createTile( TileBean.TileType.CURVED, Orientation.SOUTH, Direction.CENTER, 1100, 140); Tile eastCE - = TileFactory.createTile( + = TileCache.createTile( TileBean.TileType.CURVED, Orientation.EAST, Direction.CENTER, 1100, 140); Tile eastCW - = TileFactory.createTile( + = TileCache.createTile( TileBean.TileType.CURVED, Orientation.WEST, Direction.CENTER, 1100, 140); Tile eastCN - = TileFactory.createTile( + = TileCache.createTile( TileBean.TileType.CURVED, Orientation.NORTH, Direction.CENTER, 1100, 140); Tile northCS - = TileFactory.createTile( + = TileCache.createTile( TileBean.TileType.CURVED, Orientation.SOUTH, Direction.CENTER, 1060, 100); Tile northCE - = TileFactory.createTile( + = TileCache.createTile( TileBean.TileType.CURVED, Orientation.EAST, Direction.CENTER, 1060, 100); Tile northCW - = TileFactory.createTile( + = TileCache.createTile( TileBean.TileType.CURVED, Orientation.WEST, Direction.CENTER, 1060, 100); Tile northCN - = TileFactory.createTile( + = TileCache.createTile( TileBean.TileType.CURVED, Orientation.NORTH, Direction.CENTER, 1060, 100); assertTrue(instanceE.isAdjacent(west)); @@ -696,29 +691,29 @@ public void testIsAdjacentSwitchR() { public void testIsArrowSwitchSide() { System.out.println("isArrowSwitchSide"); Tile instanceE - = TileFactory.createTile( + = TileCache.createTile( TileBean.TileType.STRAIGHT_DIR, Orientation.EAST, Direction.RIGHT, 860, 140); Tile instanceS - = TileFactory.createTile( + = TileCache.createTile( TileBean.TileType.STRAIGHT_DIR, Orientation.SOUTH, Direction.RIGHT, 860, 140); Tile instanceW - = TileFactory.createTile( + = TileCache.createTile( TileBean.TileType.STRAIGHT_DIR, Orientation.WEST, Direction.RIGHT, 860, 140); Tile instanceN - = TileFactory.createTile( + = TileCache.createTile( TileBean.TileType.STRAIGHT_DIR, Orientation.NORTH, Direction.RIGHT, 860, 140); Tile straighE - = TileFactory.createTile( + = TileCache.createTile( TileBean.TileType.STRAIGHT, Orientation.EAST, Direction.CENTER, 900, 140); Tile straighS - = TileFactory.createTile( + = TileCache.createTile( TileBean.TileType.STRAIGHT, Orientation.SOUTH, Direction.CENTER, 860, 180); Tile straighW - = TileFactory.createTile( + = TileCache.createTile( TileBean.TileType.STRAIGHT, Orientation.WEST, Direction.CENTER, 820, 140); Tile straighN - = TileFactory.createTile( + = TileCache.createTile( TileBean.TileType.STRAIGHT, Orientation.NORTH, Direction.CENTER, 860, 100); assertTrue(instanceE.isArrowDirection(straighE)); @@ -738,53 +733,53 @@ public void testIsArrowSwitchSide() { public void testIsAdjacentCrossL() { System.out.println("iIsAdjacentCrossL"); Tile instanceE - = TileFactory.createTile( + = TileCache.createTile( TileBean.TileType.CROSS, Orientation.EAST, Direction.LEFT, 860, 100); Tile instanceS - = TileFactory.createTile( + = TileCache.createTile( TileBean.TileType.CROSS, Orientation.SOUTH, Direction.LEFT, 860, 100); Tile instanceW - = TileFactory.createTile( + = TileCache.createTile( TileBean.TileType.CROSS, Orientation.WEST, Direction.LEFT, 860, 100); Tile instanceN - = TileFactory.createTile( + = TileCache.createTile( TileBean.TileType.CROSS, Orientation.NORTH, Direction.LEFT, 860, 100); Tile north - = TileFactory.createTile( + = TileCache.createTile( TileBean.TileType.STRAIGHT, Orientation.NORTH, Direction.CENTER, 900, 60); Tile north2 - = TileFactory.createTile( + = TileCache.createTile( TileBean.TileType.STRAIGHT, Orientation.NORTH, Direction.CENTER, 860, 60); Tile north3 - = TileFactory.createTile( + = TileCache.createTile( TileBean.TileType.STRAIGHT, Orientation.NORTH, Direction.CENTER, 860, 20); Tile west - = TileFactory.createTile( + = TileCache.createTile( TileBean.TileType.STRAIGHT, Orientation.WEST, Direction.CENTER, 820, 100); Tile west2 - = TileFactory.createTile( + = TileCache.createTile( TileBean.TileType.STRAIGHT, Orientation.WEST, Direction.CENTER, 780, 100); Tile west3 - = TileFactory.createTile( + = TileCache.createTile( TileBean.TileType.STRAIGHT, Orientation.WEST, Direction.CENTER, 820, 60); Tile east - = TileFactory.createTile( + = TileCache.createTile( TileBean.TileType.STRAIGHT, Orientation.EAST, Direction.CENTER, 940, 100); Tile east2 - = TileFactory.createTile( + = TileCache.createTile( TileBean.TileType.STRAIGHT, Orientation.EAST, Direction.CENTER, 900, 100); Tile east3 - = TileFactory.createTile( + = TileCache.createTile( TileBean.TileType.STRAIGHT, Orientation.EAST, Direction.CENTER, 900, 140); Tile south - = TileFactory.createTile( + = TileCache.createTile( TileBean.TileType.STRAIGHT, Orientation.SOUTH, Direction.CENTER, 860, 140); Tile south2 - = TileFactory.createTile( + = TileCache.createTile( TileBean.TileType.STRAIGHT, Orientation.SOUTH, Direction.CENTER, 820, 140); Tile south3 - = TileFactory.createTile( + = TileCache.createTile( TileBean.TileType.STRAIGHT, Orientation.SOUTH, Direction.CENTER, 860, 180); assertTrue(instanceE.isAdjacent(west)); @@ -812,60 +807,60 @@ public void testIsAdjacentCrossL() { public void testIsAdjacentCrossR() { System.out.println("iIsAdjacentCrossR"); Tile instanceE - = TileFactory.createTile( + = TileCache.createTile( TileBean.TileType.CROSS, Orientation.EAST, Direction.RIGHT, 860, 100); Tile instanceS - = TileFactory.createTile( + = TileCache.createTile( TileBean.TileType.CROSS, Orientation.SOUTH, Direction.RIGHT, 860, 100); Tile instanceW - = TileFactory.createTile( + = TileCache.createTile( TileBean.TileType.CROSS, Orientation.WEST, Direction.RIGHT, 860, 100); Tile instanceN - = TileFactory.createTile( + = TileCache.createTile( TileBean.TileType.CROSS, Orientation.NORTH, Direction.RIGHT, 860, 100); Tile north - = TileFactory.createTile( + = TileCache.createTile( TileBean.TileType.STRAIGHT, Orientation.NORTH, Direction.CENTER, 860, 60); Tile north2 - = TileFactory.createTile( + = TileCache.createTile( TileBean.TileType.STRAIGHT, Orientation.NORTH, Direction.CENTER, 860, 60); Tile north3 - = TileFactory.createTile( + = TileCache.createTile( TileBean.TileType.STRAIGHT, Orientation.NORTH, Direction.CENTER, 860, 20); Tile north4 - = TileFactory.createTile( + = TileCache.createTile( TileBean.TileType.STRAIGHT, Orientation.NORTH, Direction.CENTER, 820, 60); Tile west - = TileFactory.createTile( + = TileCache.createTile( TileBean.TileType.STRAIGHT, Orientation.WEST, Direction.CENTER, 820, 140); Tile west2 - = TileFactory.createTile( + = TileCache.createTile( TileBean.TileType.STRAIGHT, Orientation.WEST, Direction.CENTER, 820, 100); Tile west3 - = TileFactory.createTile( + = TileCache.createTile( TileBean.TileType.STRAIGHT, Orientation.WEST, Direction.CENTER, 860, 100); Tile west4 - = TileFactory.createTile( + = TileCache.createTile( TileBean.TileType.STRAIGHT, Orientation.WEST, Direction.CENTER, 780, 100); Tile east - = TileFactory.createTile( + = TileCache.createTile( TileBean.TileType.STRAIGHT, Orientation.EAST, Direction.CENTER, 940, 100); Tile east2 - = TileFactory.createTile( + = TileCache.createTile( TileBean.TileType.STRAIGHT, Orientation.EAST, Direction.CENTER, 900, 60); Tile east3 - = TileFactory.createTile( + = TileCache.createTile( TileBean.TileType.STRAIGHT, Orientation.EAST, Direction.CENTER, 900, 100); Tile south - = TileFactory.createTile( + = TileCache.createTile( TileBean.TileType.STRAIGHT, Orientation.SOUTH, Direction.CENTER, 860, 140); Tile south2 - = TileFactory.createTile( + = TileCache.createTile( TileBean.TileType.STRAIGHT, Orientation.SOUTH, Direction.CENTER, 900, 140); Tile south3 - = TileFactory.createTile( + = TileCache.createTile( TileBean.TileType.STRAIGHT, Orientation.SOUTH, Direction.CENTER, 860, 180); assertTrue(instanceE.isAdjacent(west2)); @@ -892,14 +887,14 @@ public void testIsAdjacentCrossR() { @Test public void testIsAdjacentCrossing() { System.out.println("isAdjacentCrossing"); - Tile instanceE = TileFactory.createTile(TileBean.TileType.CROSSING, Orientation.EAST, Direction.CENTER, 100, 100); + Tile instanceE = TileCache.createTile(TileBean.TileType.CROSSING, Orientation.EAST, Direction.CENTER, 100, 100); - Tile instanceN = TileFactory.createTile(TileBean.TileType.CROSSING, Orientation.NORTH, Direction.CENTER, 100, 100); + Tile instanceN = TileCache.createTile(TileBean.TileType.CROSSING, Orientation.NORTH, Direction.CENTER, 100, 100); - Tile west = TileFactory.createTile(TileBean.TileType.STRAIGHT, Orientation.WEST, Direction.CENTER, 60, 100); - Tile east = TileFactory.createTile(TileBean.TileType.STRAIGHT, Orientation.EAST, Direction.CENTER, 140, 100); - Tile north = TileFactory.createTile(TileBean.TileType.STRAIGHT, Orientation.NORTH, Direction.CENTER, 100, 60); - Tile south = TileFactory.createTile(TileBean.TileType.STRAIGHT, Orientation.SOUTH, Direction.CENTER, 100, 140); + Tile west = TileCache.createTile(TileBean.TileType.STRAIGHT, Orientation.WEST, Direction.CENTER, 60, 100); + Tile east = TileCache.createTile(TileBean.TileType.STRAIGHT, Orientation.EAST, Direction.CENTER, 140, 100); + Tile north = TileCache.createTile(TileBean.TileType.STRAIGHT, Orientation.NORTH, Direction.CENTER, 100, 60); + Tile south = TileCache.createTile(TileBean.TileType.STRAIGHT, Orientation.SOUTH, Direction.CENTER, 100, 140); assertTrue(instanceE.isAdjacent(west)); assertTrue(instanceE.isAdjacent(east)); diff --git a/src/test/java/jcs/ui/layout/pathfinding/astar/AStarCrossLeftEast.java b/src/test/java/jcs/ui/layout/pathfinding/astar/AStarCrossLeftEast.java index cda2231c..f388fdb0 100644 --- a/src/test/java/jcs/ui/layout/pathfinding/astar/AStarCrossLeftEast.java +++ b/src/test/java/jcs/ui/layout/pathfinding/astar/AStarCrossLeftEast.java @@ -18,10 +18,9 @@ import java.util.ArrayList; import java.util.List; import jcs.entities.RouteBean; -import jcs.persistence.PersistenceFactory; import jcs.persistence.util.PersistenceTestHelper; import jcs.ui.layout.tiles.Tile; -import jcs.ui.layout.tiles.TileFactory; +import jcs.ui.layout.tiles.TileCache; import org.junit.After; import static org.junit.Assert.assertEquals; import org.junit.Before; @@ -54,7 +53,8 @@ public void tearDown() { @Test public void testBuildGraph() { System.out.println("buildGraph"); - List tiles = TileFactory.toTiles(PersistenceFactory.getService().getTileBeans(), false, false); + List tiles = TileCache.loadTiles(false); + assertEquals(21, tiles.size()); AStar instance = new AStar(); instance.buildGraph(tiles); @@ -68,7 +68,8 @@ public void testBuildGraph() { @Test public void testGetAllBlockToBlockNodes() { System.out.println("getAllBlockToBlockNodes"); - List tiles = TileFactory.toTiles(PersistenceFactory.getService().getTileBeans(), false, false); + List tiles = TileCache.loadTiles(false); + AStar instance = new AStar(); instance.buildGraph(tiles); List> result = instance.getAllBlockToBlockNodes(); @@ -86,7 +87,8 @@ public void testFindPath_bk_1p_bk2m() { String toNodeId = "bk-2"; String toSuffix = "-"; AStar instance = new AStar(); - List tiles = TileFactory.toTiles(PersistenceFactory.getService().getTileBeans(), false, false); + List tiles = TileCache.loadTiles(false); + instance.buildGraph(tiles); String expPath = "[bk-1+]->[bk-2-]: bk-1+[bk-1] -> st-1 -> st-2 -> cs-3[GREEN] -> st-5 -> st-6 -> bk-2-[bk-2]"; @@ -107,7 +109,8 @@ public void testFindPath_bk_4m_bk3p() { String toNodeId = "bk-3"; String toSuffix = "+"; AStar instance = new AStar(); - List tiles = TileFactory.toTiles(PersistenceFactory.getService().getTileBeans(), false, false); + List tiles = TileCache.loadTiles(false); + instance.buildGraph(tiles); String expPath = "[bk-4-]->[bk-3+]: bk-4-[bk-4] -> st-29 -> st-30 -> cs-3[GREEN] -> st-25 -> st-26 -> bk-3+[bk-3]"; @@ -124,7 +127,8 @@ public void testFindPath_bk_2m_bk4m() { String toNodeId = "bk-4"; String toSuffix = "-"; AStar instance = new AStar(); - List tiles = TileFactory.toTiles(PersistenceFactory.getService().getTileBeans(), false, false); + List tiles = TileCache.loadTiles(false); + instance.buildGraph(tiles); String expPath = ""; @@ -141,7 +145,8 @@ public void testFindPath_bk_2m_bk3p() { String toNodeId = "bk-3"; String toSuffix = "+"; AStar instance = new AStar(); - List tiles = TileFactory.toTiles(PersistenceFactory.getService().getTileBeans(), false, false); + List tiles = TileCache.loadTiles(false); + instance.buildGraph(tiles); String expPath = "[bk-2-]->[bk-3+]: bk-2-[bk-2] -> st-6 -> st-5 -> cs-3[RED] -> st-25 -> st-26 -> bk-3+[bk-3]"; @@ -156,7 +161,7 @@ public void testFindPath_bk_2m_bk3p() { @Test public void testRouteAll() { System.out.println("routeAll"); - List tiles = TileFactory.toTiles(PersistenceFactory.getService().getTileBeans(), false, false); + List tiles = TileCache.loadTiles(false); List expRouteDesc = new ArrayList<>(); diff --git a/src/test/java/jcs/ui/layout/pathfinding/astar/AStarCrossLeftSouth.java b/src/test/java/jcs/ui/layout/pathfinding/astar/AStarCrossLeftSouth.java index 7ed22ab3..aa13a460 100644 --- a/src/test/java/jcs/ui/layout/pathfinding/astar/AStarCrossLeftSouth.java +++ b/src/test/java/jcs/ui/layout/pathfinding/astar/AStarCrossLeftSouth.java @@ -18,10 +18,8 @@ import java.util.ArrayList; import java.util.List; import jcs.entities.RouteBean; -import jcs.persistence.PersistenceFactory; import jcs.persistence.util.PersistenceTestHelper; import jcs.ui.layout.tiles.Tile; -import jcs.ui.layout.tiles.TileFactory; import org.junit.After; import static org.junit.Assert.assertEquals; import org.junit.Before; @@ -54,7 +52,7 @@ public void tearDown() { @Test public void testBuildGraph() { System.out.println("buildGraph"); - List tiles = TileFactory.toTiles(PersistenceFactory.getService().getTileBeans(), false, false); + List tiles = jcs.ui.layout.tiles.TileCache.loadTiles(false); assertEquals(21, tiles.size()); AStar instance = new AStar(); instance.buildGraph(tiles); @@ -68,7 +66,7 @@ public void testBuildGraph() { @Test public void testGetAllBlockToBlockNodes() { System.out.println("getAllBlockToBlockNodes"); - List tiles = TileFactory.toTiles(PersistenceFactory.getService().getTileBeans(), false, false); + List tiles = jcs.ui.layout.tiles.TileCache.loadTiles(false); AStar instance = new AStar(); instance.buildGraph(tiles); List> result = instance.getAllBlockToBlockNodes(); @@ -86,7 +84,7 @@ public void testFindPath_bk_1p_bk2m() { String toNodeId = "bk-2"; String toSuffix = "-"; AStar instance = new AStar(); - List tiles = TileFactory.toTiles(PersistenceFactory.getService().getTileBeans(), false, false); + List tiles = jcs.ui.layout.tiles.TileCache.loadTiles(false); instance.buildGraph(tiles); String expPath = "[bk-1+]->[bk-2-]: bk-1+[bk-1] -> st-1 -> st-2 -> cs-3[GREEN] -> st-5 -> st-6 -> bk-2-[bk-2]"; @@ -107,7 +105,7 @@ public void testFindPath_bk_4m_bk3p() { String toNodeId = "bk-3"; String toSuffix = "+"; AStar instance = new AStar(); - List tiles = TileFactory.toTiles(PersistenceFactory.getService().getTileBeans(), false, false); + List tiles = jcs.ui.layout.tiles.TileCache.loadTiles(false); instance.buildGraph(tiles); String expPath = "[bk-4-]->[bk-3+]: bk-4-[bk-4] -> st-29 -> st-30 -> cs-3[GREEN] -> st-25 -> st-26 -> bk-3+[bk-3]"; @@ -124,7 +122,7 @@ public void testFindPath_bk_2m_bk4m() { String toNodeId = "bk-4"; String toSuffix = "-"; AStar instance = new AStar(); - List tiles = TileFactory.toTiles(PersistenceFactory.getService().getTileBeans(), false, false); + List tiles = jcs.ui.layout.tiles.TileCache.loadTiles(false); instance.buildGraph(tiles); String expPath = "[bk-2-]->[bk-4-]: bk-2-[bk-2] -> st-6 -> st-5 -> cs-3[RED] -> st-30 -> st-29 -> bk-4-[bk-4]"; @@ -141,7 +139,7 @@ public void testFindPath_bk_2m_bk3p() { String toNodeId = "bk-3"; String toSuffix = "+"; AStar instance = new AStar(); - List tiles = TileFactory.toTiles(PersistenceFactory.getService().getTileBeans(), false, false); + List tiles = jcs.ui.layout.tiles.TileCache.loadTiles(false); instance.buildGraph(tiles); String expPath = ""; @@ -156,7 +154,7 @@ public void testFindPath_bk_2m_bk3p() { @Test public void testRouteAll() { System.out.println("routeAll"); - List tiles = TileFactory.toTiles(PersistenceFactory.getService().getTileBeans(), false, false); + List tiles = jcs.ui.layout.tiles.TileCache.loadTiles(false); List expRouteDesc = new ArrayList<>(); diff --git a/src/test/java/jcs/ui/layout/pathfinding/astar/AStarCrossRightEast.java b/src/test/java/jcs/ui/layout/pathfinding/astar/AStarCrossRightEast.java index 1de71214..53b2a7e8 100644 --- a/src/test/java/jcs/ui/layout/pathfinding/astar/AStarCrossRightEast.java +++ b/src/test/java/jcs/ui/layout/pathfinding/astar/AStarCrossRightEast.java @@ -18,10 +18,8 @@ import java.util.ArrayList; import java.util.List; import jcs.entities.RouteBean; -import jcs.persistence.PersistenceFactory; import jcs.persistence.util.PersistenceTestHelper; import jcs.ui.layout.tiles.Tile; -import jcs.ui.layout.tiles.TileFactory; import org.junit.After; import static org.junit.Assert.assertEquals; import org.junit.Before; @@ -54,7 +52,7 @@ public void tearDown() { @Test public void testBuildGraph() { System.out.println("buildGraph"); - List tiles = TileFactory.toTiles(PersistenceFactory.getService().getTileBeans(), false, false); + List tiles = jcs.ui.layout.tiles.TileCache.loadTiles(false); assertEquals(21, tiles.size()); AStar instance = new AStar(); instance.buildGraph(tiles); @@ -68,7 +66,7 @@ public void testBuildGraph() { @Test public void testGetAllBlockToBlockNodes() { System.out.println("getAllBlockToBlockNodes"); - List tiles = TileFactory.toTiles(PersistenceFactory.getService().getTileBeans(), false, false); + List tiles = jcs.ui.layout.tiles.TileCache.loadTiles(false); AStar instance = new AStar(); instance.buildGraph(tiles); List> result = instance.getAllBlockToBlockNodes(); @@ -86,7 +84,7 @@ public void testFindPath_bk_1p_bk2m() { String toNodeId = "bk-2"; String toSuffix = "-"; AStar instance = new AStar(); - List tiles = TileFactory.toTiles(PersistenceFactory.getService().getTileBeans(), false, false); + List tiles = jcs.ui.layout.tiles.TileCache.loadTiles(false); instance.buildGraph(tiles); String expPath = "[bk-1+]->[bk-2-]: bk-1+[bk-1] -> st-1 -> st-2 -> cs-2[GREEN] -> st-5 -> st-6 -> bk-2-[bk-2]"; @@ -107,7 +105,7 @@ public void testFindPath_bk_4m_bk3p() { String toNodeId = "bk-3"; String toSuffix = "+"; AStar instance = new AStar(); - List tiles = TileFactory.toTiles(PersistenceFactory.getService().getTileBeans(), false, false); + List tiles = jcs.ui.layout.tiles.TileCache.loadTiles(false); instance.buildGraph(tiles); String expPath = "[bk-4-]->[bk-3+]: bk-4-[bk-4] -> st-29 -> st-30 -> cs-2[GREEN] -> st-25 -> st-26 -> bk-3+[bk-3]"; @@ -124,7 +122,7 @@ public void testFindPath_bk_2m_bk4m() { String toNodeId = "bk-4"; String toSuffix = "-"; AStar instance = new AStar(); - List tiles = TileFactory.toTiles(PersistenceFactory.getService().getTileBeans(), false, false); + List tiles = jcs.ui.layout.tiles.TileCache.loadTiles(false); instance.buildGraph(tiles); String expPath = "[bk-2-]->[bk-4-]: bk-2-[bk-2] -> st-6 -> st-5 -> cs-2[RED] -> st-30 -> st-29 -> bk-4-[bk-4]"; @@ -141,7 +139,7 @@ public void testFindPath_bk_2m_bk3p() { String toNodeId = "bk-3"; String toSuffix = "+"; AStar instance = new AStar(); - List tiles = TileFactory.toTiles(PersistenceFactory.getService().getTileBeans(), false, false); + List tiles = jcs.ui.layout.tiles.TileCache.loadTiles(false); instance.buildGraph(tiles); String expPath = ""; @@ -156,7 +154,7 @@ public void testFindPath_bk_2m_bk3p() { @Test public void testRouteAll() { System.out.println("routeAll"); - List tiles = TileFactory.toTiles(PersistenceFactory.getService().getTileBeans(), false, false); + List tiles = jcs.ui.layout.tiles.TileCache.loadTiles(false); List expRouteDesc = new ArrayList<>(); diff --git a/src/test/java/jcs/ui/layout/pathfinding/astar/AStarCrossRightSouth.java b/src/test/java/jcs/ui/layout/pathfinding/astar/AStarCrossRightSouth.java index ecba391b..4ad7e132 100644 --- a/src/test/java/jcs/ui/layout/pathfinding/astar/AStarCrossRightSouth.java +++ b/src/test/java/jcs/ui/layout/pathfinding/astar/AStarCrossRightSouth.java @@ -18,10 +18,8 @@ import java.util.ArrayList; import java.util.List; import jcs.entities.RouteBean; -import jcs.persistence.PersistenceFactory; import jcs.persistence.util.PersistenceTestHelper; import jcs.ui.layout.tiles.Tile; -import jcs.ui.layout.tiles.TileFactory; import org.junit.After; import static org.junit.Assert.assertEquals; import org.junit.Before; @@ -54,7 +52,7 @@ public void tearDown() { @Test public void testBuildGraph() { System.out.println("buildGraph"); - List tiles = TileFactory.toTiles(PersistenceFactory.getService().getTileBeans(), false, false); + List tiles = jcs.ui.layout.tiles.TileCache.loadTiles(false); assertEquals(21, tiles.size()); AStar instance = new AStar(); instance.buildGraph(tiles); @@ -68,7 +66,7 @@ public void testBuildGraph() { @Test public void testGetAllBlockToBlockNodes() { System.out.println("getAllBlockToBlockNodes"); - List tiles = TileFactory.toTiles(PersistenceFactory.getService().getTileBeans(), false, false); + List tiles = jcs.ui.layout.tiles.TileCache.loadTiles(false); AStar instance = new AStar(); instance.buildGraph(tiles); List> result = instance.getAllBlockToBlockNodes(); @@ -86,7 +84,7 @@ public void testFindPath_bk_1p_bk2m() { String toNodeId = "bk-2"; String toSuffix = "-"; AStar instance = new AStar(); - List tiles = TileFactory.toTiles(PersistenceFactory.getService().getTileBeans(), false, false); + List tiles = jcs.ui.layout.tiles.TileCache.loadTiles(false); instance.buildGraph(tiles); String expPath = "[bk-1+]->[bk-2-]: bk-1+[bk-1] -> st-1 -> st-2 -> cs-2[GREEN] -> st-5 -> st-6 -> bk-2-[bk-2]"; @@ -107,7 +105,7 @@ public void testFindPath_bk_4m_bk3p() { String toNodeId = "bk-3"; String toSuffix = "+"; AStar instance = new AStar(); - List tiles = TileFactory.toTiles(PersistenceFactory.getService().getTileBeans(), false, false); + List tiles = jcs.ui.layout.tiles.TileCache.loadTiles(false); instance.buildGraph(tiles); String expPath = "[bk-4-]->[bk-3+]: bk-4-[bk-4] -> st-29 -> st-30 -> cs-2[GREEN] -> st-25 -> st-26 -> bk-3+[bk-3]"; @@ -124,7 +122,7 @@ public void testFindPath_bk_2m_bk4m() { String toNodeId = "bk-4"; String toSuffix = "-"; AStar instance = new AStar(); - List tiles = TileFactory.toTiles(PersistenceFactory.getService().getTileBeans(), false, false); + List tiles = jcs.ui.layout.tiles.TileCache.loadTiles(false); instance.buildGraph(tiles); String expPath = ""; @@ -141,7 +139,7 @@ public void testFindPath_bk_2m_bk3p() { String toNodeId = "bk-3"; String toSuffix = "+"; AStar instance = new AStar(); - List tiles = TileFactory.toTiles(PersistenceFactory.getService().getTileBeans(), false, false); + List tiles = jcs.ui.layout.tiles.TileCache.loadTiles(false); instance.buildGraph(tiles); String expPath = "[bk-2-]->[bk-3+]: bk-2-[bk-2] -> st-6 -> st-5 -> cs-2[RED] -> st-25 -> st-26 -> bk-3+[bk-3]"; @@ -156,7 +154,7 @@ public void testFindPath_bk_2m_bk3p() { @Test public void testRouteAll() { System.out.println("routeAll"); - List tiles = TileFactory.toTiles(PersistenceFactory.getService().getTileBeans(), false, false); + List tiles = jcs.ui.layout.tiles.TileCache.loadTiles(false); List expRouteDesc = new ArrayList<>(); diff --git a/src/test/java/jcs/ui/layout/pathfinding/astar/AStarCrossingTest.java b/src/test/java/jcs/ui/layout/pathfinding/astar/AStarCrossingTest.java index f558911e..ca7e2626 100644 --- a/src/test/java/jcs/ui/layout/pathfinding/astar/AStarCrossingTest.java +++ b/src/test/java/jcs/ui/layout/pathfinding/astar/AStarCrossingTest.java @@ -18,10 +18,8 @@ import java.util.ArrayList; import java.util.List; import jcs.entities.RouteBean; -import jcs.persistence.PersistenceFactory; import jcs.persistence.util.PersistenceTestHelper; import jcs.ui.layout.tiles.Tile; -import jcs.ui.layout.tiles.TileFactory; import org.junit.After; import static org.junit.Assert.assertEquals; import org.junit.Before; @@ -54,7 +52,8 @@ public void tearDown() { @Test public void testBuildGraph() { System.out.println("buildGraph"); - List tiles = TileFactory.toTiles(PersistenceFactory.getService().getTileBeans(), false, false); + List tiles = jcs.ui.layout.tiles.TileCache.loadTiles(false); + assertEquals(21, tiles.size()); AStar instance = new AStar(); instance.buildGraph(tiles); @@ -68,7 +67,8 @@ public void testBuildGraph() { @Test public void testGetAllBlockToBlockNodes() { System.out.println("getAllBlockToBlockNodes"); - List tiles = TileFactory.toTiles(PersistenceFactory.getService().getTileBeans(), false, false); + List tiles = jcs.ui.layout.tiles.TileCache.loadTiles(false); + AStar instance = new AStar(); instance.buildGraph(tiles); List> result = instance.getAllBlockToBlockNodes(); @@ -86,7 +86,8 @@ public void testFindPath_bk_1p_bk2m() { String toNodeId = "bk-2"; String toSuffix = "-"; AStar instance = new AStar(); - List tiles = TileFactory.toTiles(PersistenceFactory.getService().getTileBeans(), false, false); + List tiles = jcs.ui.layout.tiles.TileCache.loadTiles(false); + instance.buildGraph(tiles); String expPath = "[bk-1+]->[bk-2-]: bk-1+[bk-1] -> st-1 -> st-2 -> cr-1 -> st-5 -> st-6 -> bk-2-[bk-2]"; @@ -107,7 +108,8 @@ public void testFindPath_bk_4m_bk3p() { String toNodeId = "bk-3"; String toSuffix = "+"; AStar instance = new AStar(); - List tiles = TileFactory.toTiles(PersistenceFactory.getService().getTileBeans(), false, false); + List tiles = jcs.ui.layout.tiles.TileCache.loadTiles(false); + instance.buildGraph(tiles); String expPath = "[bk-4-]->[bk-3+]: bk-4-[bk-4] -> st-29 -> st-30 -> cr-1 -> st-25 -> st-26 -> bk-3+[bk-3]"; @@ -124,7 +126,8 @@ public void testFindPath_bk_2m_bk4m() { String toNodeId = "bk-4"; String toSuffix = "-"; AStar instance = new AStar(); - List tiles = TileFactory.toTiles(PersistenceFactory.getService().getTileBeans(), false, false); + List tiles = jcs.ui.layout.tiles.TileCache.loadTiles(false); + instance.buildGraph(tiles); String expPath = ""; @@ -139,7 +142,7 @@ public void testFindPath_bk_2m_bk4m() { @Test public void testRouteAll() { System.out.println("routeAll"); - List tiles = TileFactory.toTiles(PersistenceFactory.getService().getTileBeans(), false, false); + List tiles = jcs.ui.layout.tiles.TileCache.loadTiles(false); List expRouteDesc = new ArrayList<>(); diff --git a/src/test/java/jcs/ui/layout/pathfinding/astar/AStarSwitchLeftEast.java b/src/test/java/jcs/ui/layout/pathfinding/astar/AStarSwitchLeftEast.java index c907b6fb..83ab13a6 100644 --- a/src/test/java/jcs/ui/layout/pathfinding/astar/AStarSwitchLeftEast.java +++ b/src/test/java/jcs/ui/layout/pathfinding/astar/AStarSwitchLeftEast.java @@ -18,10 +18,8 @@ import java.util.ArrayList; import java.util.List; import jcs.entities.RouteBean; -import jcs.persistence.PersistenceFactory; import jcs.persistence.util.PersistenceTestHelper; import jcs.ui.layout.tiles.Tile; -import jcs.ui.layout.tiles.TileFactory; import org.junit.After; import static org.junit.Assert.assertEquals; import org.junit.Before; @@ -54,7 +52,8 @@ public void tearDown() { @Test public void testBuildGraph() { System.out.println("buildGraph"); - List tiles = TileFactory.toTiles(PersistenceFactory.getService().getTileBeans(), false, false); + List tiles = jcs.ui.layout.tiles.TileCache.loadTiles(false); + assertEquals(21, tiles.size()); AStar instance = new AStar(); instance.buildGraph(tiles); @@ -68,7 +67,8 @@ public void testBuildGraph() { @Test public void testGetAllBlockToBlockNodes() { System.out.println("getAllBlockToBlockNodes"); - List tiles = TileFactory.toTiles(PersistenceFactory.getService().getTileBeans(), false, false); + List tiles = jcs.ui.layout.tiles.TileCache.loadTiles(false); + AStar instance = new AStar(); instance.buildGraph(tiles); List> result = instance.getAllBlockToBlockNodes(); @@ -86,7 +86,8 @@ public void testFindPath_bk_1p_bk2m() { String toNodeId = "bk-2"; String toSuffix = "-"; AStar instance = new AStar(); - List tiles = TileFactory.toTiles(PersistenceFactory.getService().getTileBeans(), false, false); + List tiles = jcs.ui.layout.tiles.TileCache.loadTiles(false); + instance.buildGraph(tiles); String expPath = "[bk-1+]->[bk-2-]: bk-1+[bk-1] -> st-1 -> st-2 -> sw-1[GREEN] -> st-5 -> st-6 -> bk-2-[bk-2]"; @@ -107,7 +108,8 @@ public void testFindPath_bk_4m_bk3p() { String toNodeId = "bk-3"; String toSuffix = "+"; AStar instance = new AStar(); - List tiles = TileFactory.toTiles(PersistenceFactory.getService().getTileBeans(), false, false); + List tiles = jcs.ui.layout.tiles.TileCache.loadTiles(false); + instance.buildGraph(tiles); String expPath = ""; @@ -124,7 +126,8 @@ public void testFindPath_bk_2m_bk4m() { String toNodeId = "bk-4"; String toSuffix = "-"; AStar instance = new AStar(); - List tiles = TileFactory.toTiles(PersistenceFactory.getService().getTileBeans(), false, false); + List tiles = jcs.ui.layout.tiles.TileCache.loadTiles(false); + instance.buildGraph(tiles); String expPath = ""; @@ -141,7 +144,8 @@ public void testFindPath_bk_2m_bk3p() { String toNodeId = "bk-3"; String toSuffix = "+"; AStar instance = new AStar(); - List tiles = TileFactory.toTiles(PersistenceFactory.getService().getTileBeans(), false, false); + List tiles = jcs.ui.layout.tiles.TileCache.loadTiles(false); + instance.buildGraph(tiles); String expPath = "[bk-2-]->[bk-3+]: bk-2-[bk-2] -> st-6 -> st-5 -> sw-1[RED] -> st-25 -> st-26 -> bk-3+[bk-3]"; @@ -156,7 +160,7 @@ public void testFindPath_bk_2m_bk3p() { @Test public void testRouteAll() { System.out.println("routeAll"); - List tiles = TileFactory.toTiles(PersistenceFactory.getService().getTileBeans(), false, false); + List tiles = jcs.ui.layout.tiles.TileCache.loadTiles(false); List expRouteDesc = new ArrayList<>(); diff --git a/src/test/java/jcs/ui/layout/pathfinding/astar/AStarSwitchLeftNorth.java b/src/test/java/jcs/ui/layout/pathfinding/astar/AStarSwitchLeftNorth.java index 56e2caa5..cf091c8f 100644 --- a/src/test/java/jcs/ui/layout/pathfinding/astar/AStarSwitchLeftNorth.java +++ b/src/test/java/jcs/ui/layout/pathfinding/astar/AStarSwitchLeftNorth.java @@ -18,10 +18,8 @@ import java.util.ArrayList; import java.util.List; import jcs.entities.RouteBean; -import jcs.persistence.PersistenceFactory; import jcs.persistence.util.PersistenceTestHelper; import jcs.ui.layout.tiles.Tile; -import jcs.ui.layout.tiles.TileFactory; import org.junit.After; import static org.junit.Assert.assertEquals; import org.junit.Before; @@ -54,7 +52,7 @@ public void tearDown() { @Test public void testBuildGraph() { System.out.println("buildGraph"); - List tiles = TileFactory.toTiles(PersistenceFactory.getService().getTileBeans(), false, false); + List tiles = jcs.ui.layout.tiles.TileCache.loadTiles(false); assertEquals(21, tiles.size()); AStar instance = new AStar(); instance.buildGraph(tiles); @@ -68,7 +66,7 @@ public void testBuildGraph() { @Test public void testGetAllBlockToBlockNodes() { System.out.println("getAllBlockToBlockNodes"); - List tiles = TileFactory.toTiles(PersistenceFactory.getService().getTileBeans(), false, false); + List tiles = jcs.ui.layout.tiles.TileCache.loadTiles(false); AStar instance = new AStar(); instance.buildGraph(tiles); List> result = instance.getAllBlockToBlockNodes(); @@ -86,7 +84,7 @@ public void testFindPath_bk_1p_bk2m() { String toNodeId = "bk-2"; String toSuffix = "-"; AStar instance = new AStar(); - List tiles = TileFactory.toTiles(PersistenceFactory.getService().getTileBeans(), false, false); + List tiles = jcs.ui.layout.tiles.TileCache.loadTiles(false); instance.buildGraph(tiles); String expPath = ""; @@ -107,7 +105,7 @@ public void testFindPath_bk_4m_bk3p() { String toNodeId = "bk-3"; String toSuffix = "+"; AStar instance = new AStar(); - List tiles = TileFactory.toTiles(PersistenceFactory.getService().getTileBeans(), false, false); + List tiles = jcs.ui.layout.tiles.TileCache.loadTiles(false); instance.buildGraph(tiles); String expPath = "[bk-4-]->[bk-3+]: bk-4-[bk-4] -> st-29 -> st-30 -> sw-1[GREEN] -> st-25 -> st-26 -> bk-3+[bk-3]"; @@ -124,7 +122,7 @@ public void testFindPath_bk_2m_bk4m() { String toNodeId = "bk-4"; String toSuffix = "-"; AStar instance = new AStar(); - List tiles = TileFactory.toTiles(PersistenceFactory.getService().getTileBeans(), false, false); + List tiles = jcs.ui.layout.tiles.TileCache.loadTiles(false); instance.buildGraph(tiles); String expPath = "[bk-2-]->[bk-4-]: bk-2-[bk-2] -> st-6 -> st-5 -> sw-1[RED] -> st-30 -> st-29 -> bk-4-[bk-4]"; @@ -141,7 +139,7 @@ public void testFindPath_bk_2m_bk3p() { String toNodeId = "bk-3"; String toSuffix = "+"; AStar instance = new AStar(); - List tiles = TileFactory.toTiles(PersistenceFactory.getService().getTileBeans(), false, false); + List tiles = jcs.ui.layout.tiles.TileCache.loadTiles(false); instance.buildGraph(tiles); String expPath = ""; @@ -156,7 +154,7 @@ public void testFindPath_bk_2m_bk3p() { @Test public void testRouteAll() { System.out.println("routeAll"); - List tiles = TileFactory.toTiles(PersistenceFactory.getService().getTileBeans(), false, false); + List tiles = jcs.ui.layout.tiles.TileCache.loadTiles(false); List expRouteDesc = new ArrayList<>(); diff --git a/src/test/java/jcs/ui/layout/pathfinding/astar/AStarSwitchLeftSouth.java b/src/test/java/jcs/ui/layout/pathfinding/astar/AStarSwitchLeftSouth.java index a6d53691..772669e6 100644 --- a/src/test/java/jcs/ui/layout/pathfinding/astar/AStarSwitchLeftSouth.java +++ b/src/test/java/jcs/ui/layout/pathfinding/astar/AStarSwitchLeftSouth.java @@ -18,10 +18,8 @@ import java.util.ArrayList; import java.util.List; import jcs.entities.RouteBean; -import jcs.persistence.PersistenceFactory; import jcs.persistence.util.PersistenceTestHelper; import jcs.ui.layout.tiles.Tile; -import jcs.ui.layout.tiles.TileFactory; import org.junit.After; import static org.junit.Assert.assertEquals; import org.junit.Before; @@ -54,7 +52,7 @@ public void tearDown() { @Test public void testBuildGraph() { System.out.println("buildGraph"); - List tiles = TileFactory.toTiles(PersistenceFactory.getService().getTileBeans(), false, false); + List tiles = jcs.ui.layout.tiles.TileCache.loadTiles(false); assertEquals(21, tiles.size()); AStar instance = new AStar(); instance.buildGraph(tiles); @@ -68,7 +66,8 @@ public void testBuildGraph() { @Test public void testGetAllBlockToBlockNodes() { System.out.println("getAllBlockToBlockNodes"); - List tiles = TileFactory.toTiles(PersistenceFactory.getService().getTileBeans(), false, false); + List tiles = jcs.ui.layout.tiles.TileCache.loadTiles(false); + AStar instance = new AStar(); instance.buildGraph(tiles); List> result = instance.getAllBlockToBlockNodes(); @@ -86,7 +85,7 @@ public void testFindPath_bk_1p_bk2m() { String toNodeId = "bk-2"; String toSuffix = "-"; AStar instance = new AStar(); - List tiles = TileFactory.toTiles(PersistenceFactory.getService().getTileBeans(), false, false); + List tiles = jcs.ui.layout.tiles.TileCache.loadTiles(false); instance.buildGraph(tiles); String expPath = ""; @@ -107,7 +106,7 @@ public void testFindPath_bk_4m_bk3p() { String toNodeId = "bk-3"; String toSuffix = "+"; AStar instance = new AStar(); - List tiles = TileFactory.toTiles(PersistenceFactory.getService().getTileBeans(), false, false); + List tiles = jcs.ui.layout.tiles.TileCache.loadTiles(false); instance.buildGraph(tiles); String expPath = "[bk-4-]->[bk-3+]: bk-4-[bk-4] -> st-29 -> st-30 -> sw-1[GREEN] -> st-25 -> st-26 -> bk-3+[bk-3]"; @@ -124,7 +123,8 @@ public void testFindPath_bk_2m_bk4m() { String toNodeId = "bk-4"; String toSuffix = "-"; AStar instance = new AStar(); - List tiles = TileFactory.toTiles(PersistenceFactory.getService().getTileBeans(), false, false); + List tiles = jcs.ui.layout.tiles.TileCache.loadTiles(false); + instance.buildGraph(tiles); String expPath = ""; @@ -141,7 +141,7 @@ public void testFindPath_bk_2m_bk3p() { String toNodeId = "bk-3"; String toSuffix = "+"; AStar instance = new AStar(); - List tiles = TileFactory.toTiles(PersistenceFactory.getService().getTileBeans(), false, false); + List tiles = jcs.ui.layout.tiles.TileCache.loadTiles(false); instance.buildGraph(tiles); String expPath = ""; @@ -156,7 +156,7 @@ public void testFindPath_bk_2m_bk3p() { @Test public void testRouteAll() { System.out.println("routeAll"); - List tiles = TileFactory.toTiles(PersistenceFactory.getService().getTileBeans(), false, false); + List tiles = jcs.ui.layout.tiles.TileCache.loadTiles(false); List expRouteDesc = new ArrayList<>(); diff --git a/src/test/java/jcs/ui/layout/pathfinding/astar/AStarSwitchLeftWest.java b/src/test/java/jcs/ui/layout/pathfinding/astar/AStarSwitchLeftWest.java index 81797259..f980b320 100644 --- a/src/test/java/jcs/ui/layout/pathfinding/astar/AStarSwitchLeftWest.java +++ b/src/test/java/jcs/ui/layout/pathfinding/astar/AStarSwitchLeftWest.java @@ -18,10 +18,8 @@ import java.util.ArrayList; import java.util.List; import jcs.entities.RouteBean; -import jcs.persistence.PersistenceFactory; import jcs.persistence.util.PersistenceTestHelper; import jcs.ui.layout.tiles.Tile; -import jcs.ui.layout.tiles.TileFactory; import org.junit.After; import static org.junit.Assert.assertEquals; import org.junit.Before; @@ -54,7 +52,7 @@ public void tearDown() { @Test public void testBuildGraph() { System.out.println("buildGraph"); - List tiles = TileFactory.toTiles(PersistenceFactory.getService().getTileBeans(), false, false); + List tiles = jcs.ui.layout.tiles.TileCache.loadTiles(false); assertEquals(21, tiles.size()); AStar instance = new AStar(); instance.buildGraph(tiles); @@ -68,7 +66,7 @@ public void testBuildGraph() { @Test public void testGetAllBlockToBlockNodes() { System.out.println("getAllBlockToBlockNodes"); - List tiles = TileFactory.toTiles(PersistenceFactory.getService().getTileBeans(), false, false); + List tiles = jcs.ui.layout.tiles.TileCache.loadTiles(false); AStar instance = new AStar(); instance.buildGraph(tiles); List> result = instance.getAllBlockToBlockNodes(); @@ -86,7 +84,7 @@ public void testFindPath_bk_1p_bk2m() { String toNodeId = "bk-2"; String toSuffix = "-"; AStar instance = new AStar(); - List tiles = TileFactory.toTiles(PersistenceFactory.getService().getTileBeans(), false, false); + List tiles = jcs.ui.layout.tiles.TileCache.loadTiles(false); instance.buildGraph(tiles); String expPath = "[bk-1+]->[bk-2-]: bk-1+[bk-1] -> st-1 -> st-2 -> sw-1[GREEN] -> st-5 -> st-6 -> bk-2-[bk-2]"; @@ -107,7 +105,8 @@ public void testFindPath_bk_4m_bk3p() { String toNodeId = "bk-3"; String toSuffix = "+"; AStar instance = new AStar(); - List tiles = TileFactory.toTiles(PersistenceFactory.getService().getTileBeans(), false, false); + List tiles = jcs.ui.layout.tiles.TileCache.loadTiles(false); + instance.buildGraph(tiles); String expPath = ""; @@ -124,7 +123,7 @@ public void testFindPath_bk_2m_bk4m() { String toNodeId = "bk-4"; String toSuffix = "-"; AStar instance = new AStar(); - List tiles = TileFactory.toTiles(PersistenceFactory.getService().getTileBeans(), false, false); + List tiles = jcs.ui.layout.tiles.TileCache.loadTiles(false); instance.buildGraph(tiles); String expPath = ""; @@ -141,7 +140,7 @@ public void testFindPath_bk_2m_bk3p() { String toNodeId = "bk-3"; String toSuffix = "+"; AStar instance = new AStar(); - List tiles = TileFactory.toTiles(PersistenceFactory.getService().getTileBeans(), false, false); + List tiles = jcs.ui.layout.tiles.TileCache.loadTiles(false); instance.buildGraph(tiles); String expPath = ""; @@ -156,7 +155,7 @@ public void testFindPath_bk_2m_bk3p() { @Test public void testRouteAll() { System.out.println("routeAll"); - List tiles = TileFactory.toTiles(PersistenceFactory.getService().getTileBeans(), false, false); + List tiles = jcs.ui.layout.tiles.TileCache.loadTiles(false); List expRouteDesc = new ArrayList<>(); diff --git a/src/test/java/jcs/ui/layout/pathfinding/astar/AStarTest.java b/src/test/java/jcs/ui/layout/pathfinding/astar/AStarTest.java index 314b1ded..f7d905d2 100644 --- a/src/test/java/jcs/ui/layout/pathfinding/astar/AStarTest.java +++ b/src/test/java/jcs/ui/layout/pathfinding/astar/AStarTest.java @@ -18,10 +18,8 @@ import java.util.ArrayList; import java.util.List; import jcs.entities.RouteBean; -import jcs.persistence.PersistenceFactory; import jcs.persistence.util.PersistenceTestHelper; import jcs.ui.layout.tiles.Tile; -import jcs.ui.layout.tiles.TileFactory; import org.junit.After; import static org.junit.Assert.assertEquals; import org.junit.Before; @@ -55,7 +53,7 @@ public void tearDown() { @Test public void testBuildGraph() { System.out.println("buildGraph"); - List tiles = TileFactory.toTiles(PersistenceFactory.getService().getTileBeans(), false, false); + List tiles = jcs.ui.layout.tiles.TileCache.loadTiles(false); assertEquals(37, tiles.size()); AStar instance = new AStar(); instance.buildGraph(tiles); @@ -69,7 +67,7 @@ public void testBuildGraph() { @Test public void testGetAllBlockToBlockNodes() { System.out.println("getAllBlockToBlockNodes"); - List tiles = TileFactory.toTiles(PersistenceFactory.getService().getTileBeans(), false, false); + List tiles = jcs.ui.layout.tiles.TileCache.loadTiles(false); AStar instance = new AStar(); instance.buildGraph(tiles); List> result = instance.getAllBlockToBlockNodes(); @@ -87,7 +85,7 @@ public void testFindPathbk_2p_bkm3() { String toNodeId = "bk-3"; String toSuffix = "-"; AStar instance = new AStar(); - List tiles = TileFactory.toTiles(PersistenceFactory.getService().getTileBeans(), false, false); + List tiles = jcs.ui.layout.tiles.TileCache.loadTiles(false); instance.buildGraph(tiles); String expPath = "[bk-2+]->[bk-3-]: bk-2+[bk-2] -> se-3 -> st-4 -> ct-1 -> sw-2[RED] -> st-5 -> ct-4 -> st-11 -> st-12 -> st-13 -> st-14 -> ct-6 -> st-20 -> st-19 -> st-18 -> se-6 -> bk-3-[bk-3]"; @@ -108,7 +106,7 @@ public void testFindPathbk_2m_bkm3() { String toNodeId = "bk-3"; String toSuffix = "-"; AStar instance = new AStar(); - List tiles = TileFactory.toTiles(PersistenceFactory.getService().getTileBeans(), false, false); + List tiles = jcs.ui.layout.tiles.TileCache.loadTiles(false); instance.buildGraph(tiles); String expPath = ""; List path = instance.findPath(fromNodeId, fromSuffix, toNodeId, toSuffix); @@ -122,7 +120,7 @@ public void testFindPathbk_2m_bkm3() { //@Test public void testRouteAll() { System.out.println("routeAll"); - List tiles = TileFactory.toTiles(PersistenceFactory.getService().getTileBeans(), false, false); + List tiles = jcs.ui.layout.tiles.TileCache.loadTiles(false); List expRouteDesc = new ArrayList<>(); @@ -164,7 +162,7 @@ public void testRouteAll() { //@Test public void testGetRoute() { System.out.println("getRoute"); - List tiles = TileFactory.toTiles(PersistenceFactory.getService().getTileBeans(), false, false); + List tiles = jcs.ui.layout.tiles.TileCache.loadTiles(false); AStar instance = new AStar(); instance.buildGraph(tiles); List routeBeans = instance.routeAll(); diff --git a/src/test/java/jcs/ui/layout/pathfinding/astar/AStarTestWithDirection.java b/src/test/java/jcs/ui/layout/pathfinding/astar/AStarTestWithDirection.java index eaed4cb2..ccd8b00a 100644 --- a/src/test/java/jcs/ui/layout/pathfinding/astar/AStarTestWithDirection.java +++ b/src/test/java/jcs/ui/layout/pathfinding/astar/AStarTestWithDirection.java @@ -18,10 +18,8 @@ import java.util.ArrayList; import java.util.List; import jcs.entities.RouteBean; -import jcs.persistence.PersistenceFactory; import jcs.persistence.util.PersistenceTestHelper; import jcs.ui.layout.tiles.Tile; -import jcs.ui.layout.tiles.TileFactory; import org.junit.After; import static org.junit.Assert.assertEquals; import org.junit.Before; @@ -55,7 +53,7 @@ public void tearDown() { @Test public void testBuildGraph() { System.out.println("buildGraph"); - List tiles = TileFactory.toTiles(PersistenceFactory.getService().getTileBeans(), false, false); + List tiles = jcs.ui.layout.tiles.TileCache.loadTiles(false); assertEquals(37, tiles.size()); AStar instance = new AStar(); instance.buildGraph(tiles); @@ -69,7 +67,7 @@ public void testBuildGraph() { @Test public void testGetAllBlockToBlockNodes() { System.out.println("getAllBlockToBlockNodes"); - List tiles = TileFactory.toTiles(PersistenceFactory.getService().getTileBeans(), false, false); + List tiles = jcs.ui.layout.tiles.TileCache.loadTiles(false); AStar instance = new AStar(); instance.buildGraph(tiles); List> result = instance.getAllBlockToBlockNodes(); @@ -87,7 +85,7 @@ public void testFindPathbk_2p_bkm3() { String toNodeId = "bk-3"; String toSuffix = "-"; AStar instance = new AStar(); - List tiles = TileFactory.toTiles(PersistenceFactory.getService().getTileBeans(), false, false); + List tiles = jcs.ui.layout.tiles.TileCache.loadTiles(false); instance.buildGraph(tiles); String expPath = "[bk-2+]->[bk-3-]: bk-2+[bk-2] -> se-3 -> sd-3 -> ct-1 -> sw-2[RED] -> st-5 -> ct-4 -> st-11 -> st-12 -> st-13 -> st-14 -> ct-6 -> st-20 -> st-19 -> st-18 -> se-6 -> bk-3-[bk-3]"; @@ -108,7 +106,7 @@ public void testFindPathbk_2p_bk3m() { String toNodeId = "bk-3"; String toSuffix = "-"; AStar instance = new AStar(); - List tiles = TileFactory.toTiles(PersistenceFactory.getService().getTileBeans(), false, false); + List tiles = jcs.ui.layout.tiles.TileCache.loadTiles(false); instance.buildGraph(tiles); String expPath = "[bk-2+]->[bk-3-]: bk-2+[bk-2] -> se-3 -> sd-3 -> ct-1 -> sw-2[RED] -> st-5 -> ct-4 -> st-11 -> st-12 -> st-13 -> st-14 -> ct-6 -> st-20 -> st-19 -> st-18 -> se-6 -> bk-3-[bk-3]"; @@ -129,7 +127,7 @@ public void testFindPathbk_2m_bk3p() { String toNodeId = "bk-3"; String toSuffix = "+"; AStar instance = new AStar(); - List tiles = TileFactory.toTiles(PersistenceFactory.getService().getTileBeans(), false, false); + List tiles = jcs.ui.layout.tiles.TileCache.loadTiles(false); instance.buildGraph(tiles); String expPath = ""; List path = instance.findPath(fromNodeId, fromSuffix, toNodeId, toSuffix); @@ -143,7 +141,7 @@ public void testFindPathbk_2m_bk3p() { @Test public void testRouteAll() { System.out.println("routeAll"); - List tiles = TileFactory.toTiles(PersistenceFactory.getService().getTileBeans(), false, false); + List tiles = jcs.ui.layout.tiles.TileCache.loadTiles(false); List expRouteDesc = new ArrayList<>(); @@ -177,7 +175,7 @@ public void testRouteAll() { //@Test public void testGetRoute() { System.out.println("getRoute"); - List tiles = TileFactory.toTiles(PersistenceFactory.getService().getTileBeans(), false, false); + List tiles = jcs.ui.layout.tiles.TileCache.loadTiles(false); AStar instance = new AStar(); instance.buildGraph(tiles); List routeBeans = instance.routeAll(); diff --git a/src/test/java/jcs/ui/layout/tiles/TileTesterFrame.java b/src/test/java/jcs/ui/layout/tiles/TileTesterFrame.java index 3aa327eb..2f35c035 100644 --- a/src/test/java/jcs/ui/layout/tiles/TileTesterFrame.java +++ b/src/test/java/jcs/ui/layout/tiles/TileTesterFrame.java @@ -1 +1 @@ -/* * Copyright 2024 Frans Jacobs. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package jcs.ui.layout.tiles; import java.awt.Color; import java.awt.Point; import javax.swing.ComboBoxModel; import javax.swing.DefaultComboBoxModel; import javax.swing.UIManager; import javax.swing.UnsupportedLookAndFeelException; import jcs.entities.AccessoryBean; import jcs.entities.AccessoryBean.AccessoryValue; import jcs.entities.TileBean; import jcs.entities.TileBean.Direction; import jcs.entities.TileBean.Orientation; import jcs.entities.TileBean.TileType; import jcs.ui.layout.LayoutUtil; import org.tinylog.Logger; public class TileTesterFrame extends javax.swing.JFrame { private Tile tile; public TileTesterFrame() { initComponents(); this.tileCB.setModel(createTileTypeComboBoxModel()); this.orientationCB.setModel(createOrientationComboBoxModel()); this.incomingSideCB.setModel(createOrientationComboBoxModel()); this.directionCB.setModel(createDirectionComboBoxModel(true)); createTile(); pack(); setVisible(true); } private ComboBoxModel createTileTypeComboBoxModel() { DefaultComboBoxModel tileTypeModel = new DefaultComboBoxModel(); tileTypeModel.addElement(TileBean.TileType.STRAIGHT); tileTypeModel.addElement(TileBean.TileType.STRAIGHT_DIR); tileTypeModel.addElement(TileBean.TileType.SENSOR); tileTypeModel.addElement(TileBean.TileType.SIGNAL); tileTypeModel.addElement(TileBean.TileType.END); tileTypeModel.addElement(TileBean.TileType.CROSSING); tileTypeModel.addElement(TileBean.TileType.CURVED); tileTypeModel.addElement(TileBean.TileType.SWITCH); tileTypeModel.addElement(TileBean.TileType.CROSS); return tileTypeModel; } private ComboBoxModel createOrientationComboBoxModel() { DefaultComboBoxModel orientationModel = new DefaultComboBoxModel(); orientationModel.addElement(Orientation.EAST); orientationModel.addElement(Orientation.SOUTH); orientationModel.addElement(Orientation.WEST); orientationModel.addElement(Orientation.NORTH); return orientationModel; } private ComboBoxModel createDirectionComboBoxModel(boolean dontCare) { DefaultComboBoxModel directionModel = new DefaultComboBoxModel(); if (dontCare) { directionModel.addElement(Direction.CENTER); } else { directionModel.addElement(Direction.LEFT); directionModel.addElement(Direction.RIGHT); } return directionModel; } private void createTile() { if (tile != null) { Logger.trace("Removing tile " + tile.getId()); canvas.remove(tile); tile = null; } TileType tileType = (TileType) tileCB.getSelectedItem(); Orientation orientation = (Orientation) orientationCB.getSelectedItem(); if (TileType.SWITCH == tileType || TileType.CROSS == tileType) { directionCB.setModel(createDirectionComboBoxModel(false)); } else { directionCB.setModel(createDirectionComboBoxModel(true)); } Direction direction = (Direction) this.directionCB.getSelectedItem(); boolean scale = !scaleCB.isSelected(); boolean showCenter = showCenterCB.isSelected(); int w = canvas.getWidth(); int h = canvas.getHeight(); int x = w / 2; int y = h / 2; Point tileCenter = new Point(x, y); tileCenter = LayoutUtil.snapToGrid(tileCenter); Tile newTile = TileFactory.createTile(tileType, orientation, direction, tileCenter); newTile.setScaleImage(scale); newTile.setDrawCenterPoint(showCenter); //tile.setPropertyChangeListener(this); Orientation incomingSide = (Orientation) this.incomingSideCB.getSelectedItem(); newTile.setIncomingSide(incomingSide); newTile.setShowRoute(displayRouteCB.isSelected()); newTile.setTrackRouteColor(Color.blue); Logger.trace("Adding tile " + newTile.getId() + " " + newTile.xyToString()); //this.cPanel.add((JComponent) newTile); this.canvas.add(newTile); this.tile = newTile; tile.updateUI(); } private AccessoryValue getAccessoryState() { AccessoryValue value; if (greenRB.isSelected()) { value = AccessoryValue.GREEN; } else if (redRB.isSelected()) { value = AccessoryValue.RED; } else { value = AccessoryValue.OFF; } return value; } private void changeAccesoryState() { if (tile instanceof Sensor) { tile.setActive(this.redRB.isSelected()); } if (tile instanceof Switch aSwitch) { if (this.displayRouteCB.isSelected()) { aSwitch.setRouteValue(getAccessoryState()); } else { aSwitch.setAccessoryValue(getAccessoryState()); } } if (tile instanceof Signal aSignal) { if (this.greenRB.isSelected()) { aSignal.setSignalValue(AccessoryBean.SignalValue.Hp1); } else if (this.redRB.isSelected()) { aSignal.setSignalValue(AccessoryBean.SignalValue.Hp0); } else { aSignal.setSignalValue(AccessoryBean.SignalValue.OFF); } } //this.tile.repaint(); } // @Override // public void propertyChange(PropertyChangeEvent evt) { // if ("repaintTile".equals(evt.getPropertyName())) { // Tile t = (Tile) evt.getNewValue(); // Logger.trace("Tile: " + t); // //this.repaint(); // } // } // @Override // public void paint(Graphics g) { // super.paint(g); // Graphics2D g2d = (Graphics2D) g; // boolean outline = this.drawOutlineCB.isSelected(); // boolean showRoute = this.displayRouteCB.isSelected(); // tile.setShowRoute(showRoute); // // tile.drawTile(g2d, outline); // // if (outline) { // tile.drawBounds(g2d); // tile.drawCenterPoint(g2d, Color.red); // } // } // @Override // public void paint(Graphics g) { // long started = System.currentTimeMillis(); // super.paint(g); // // long now = System.currentTimeMillis(); // Logger.trace("Duration: " + (now - started) + " ms."); // } private void changeDirection() { Direction direction = (Direction) this.directionCB.getSelectedItem(); this.tile.setDirection(direction); //if (TileType.CROSS == tile.getTileType()) { // ((Cross) tile).setWidthHeightAndOffsets(); //} //this.repaint(); } private void rotateTile() { Orientation newOrientation = tile.rotate(); orientationCB.setSelectedItem(newOrientation); // if (TileType.CROSS == tile.getTileType()) { // int x = tile.getCenterX(); // int y = tile.getCenterY(); // int w = tile.getWidth() * 10; // int h = tile.getHeight() * 10; // // //calculate a new centerpoint for cross // switch (tile.getOrientation()) { // case SOUTH -> { // x = x + w / 2; // y = y - h / 4; // } // case WEST -> { // x = x + w / 4; // y = y + h / 2; // } // case NORTH -> { // x = x - w / 2; // y = y + h / 4; // } // default -> { // x = x - w / 4; // y = y - h / 2; // } // } // tile.setCenter(new Point(x, y)); // } //this.canvas.repaint(this.tile.getTileBounds()); //tile.repaint(); } private void changeOrientation() { Orientation orientation = (Orientation) this.orientationCB.getSelectedItem(); tile.setOrientation(orientation); // if (TileType.CROSS == tile.getTileType()) { // //((Cross) tile).setWidthHeightAndOffsets(); // // int x = tile.getCenterX(); // int y = tile.getCenterY(); // int w = tile.getWidth() * 10; // int h = tile.getHeight() * 10; // // //calculate a new centerpoint for cross // switch (tile.getOrientation()) { // case SOUTH -> { // x = x + w / 2; // y = y - h / 4; // } // case WEST -> { // x = x + w / 4; // y = y + h / 2; // } // case NORTH -> { // x = x - w / 2; // y = y + h / 4; // } // default -> { // x = x - w / 4; // y = y - h / 2; // } // } // tile.setCenter(new Point(x, y)); // } //this.repaint(); } private void showRoute() { Logger.trace("Show route on tile " + tile.getId()); String tileId = tile.getId(); Orientation incomingSide = (Orientation) this.incomingSideCB.getSelectedItem(); //TileEvent tileEvent; if (tile.isJunction()) { AccessoryValue routeState = getAccessoryState(); //tileEvent = new TileEvent(tileId, true, incomingSide, routeState); } else { //tileEvent = new TileEvent(tileId, true, incomingSide); } //TileCache.fireTileEventListener(tileEvent); // ((JComponent) this.tile).repaint(); tile.setShowRoute(displayRouteCB.isSelected()); //repaint(); } // private void showOutline() { // //repaint(); // } private void changeIncomingSide() { Orientation incomingSide = (Orientation) this.incomingSideCB.getSelectedItem(); tile.setIncomingSide(incomingSide); //this.repaint(); } /** * This method is called from within the constructor to initialize the form. WARNING: Do NOT modify this code. The content of this method is always regenerated by the Form Editor. */ @SuppressWarnings("unchecked") // //GEN-BEGIN:initComponents private void initComponents() { accessoryBG = new javax.swing.ButtonGroup(); nPanel = new javax.swing.JPanel(); tileCB = new javax.swing.JComboBox<>(); orientationCB = new javax.swing.JComboBox<>(); inComingLbl = new javax.swing.JLabel(); incomingSideCB = new javax.swing.JComboBox<>(); directionCB = new javax.swing.JComboBox<>(); rotateButton = new javax.swing.JButton(); offRB = new javax.swing.JRadioButton(); greenRB = new javax.swing.JRadioButton(); redRB = new javax.swing.JRadioButton(); displayRouteCB = new javax.swing.JCheckBox(); scaleCB = new javax.swing.JCheckBox(); showCenterCB = new javax.swing.JCheckBox(); canvas = new jcs.ui.layout.tiles.DotGridCanvas(); setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE); nPanel.setMinimumSize(new java.awt.Dimension(860, 36)); nPanel.setPreferredSize(new java.awt.Dimension(1020, 36)); java.awt.FlowLayout flowLayout1 = new java.awt.FlowLayout(java.awt.FlowLayout.LEFT); flowLayout1.setAlignOnBaseline(true); nPanel.setLayout(flowLayout1); tileCB.setPreferredSize(new java.awt.Dimension(150, 23)); tileCB.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { tileCBActionPerformed(evt); } }); nPanel.add(tileCB); orientationCB.setPreferredSize(new java.awt.Dimension(100, 23)); orientationCB.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { orientationCBActionPerformed(evt); } }); nPanel.add(orientationCB); inComingLbl.setText("Incoming Orientation"); nPanel.add(inComingLbl); incomingSideCB.setPreferredSize(new java.awt.Dimension(100, 23)); incomingSideCB.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { incomingSideCBActionPerformed(evt); } }); nPanel.add(incomingSideCB); directionCB.setPreferredSize(new java.awt.Dimension(100, 23)); directionCB.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { directionCBActionPerformed(evt); } }); nPanel.add(directionCB); rotateButton.setText("Rotate"); rotateButton.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { rotateButtonActionPerformed(evt); } }); nPanel.add(rotateButton); accessoryBG.add(offRB); offRB.setForeground(new java.awt.Color(153, 153, 153)); offRB.setSelected(true); offRB.setText("Off"); offRB.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { offRBActionPerformed(evt); } }); nPanel.add(offRB); accessoryBG.add(greenRB); greenRB.setForeground(new java.awt.Color(102, 255, 0)); greenRB.setText("Green"); greenRB.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { greenRBActionPerformed(evt); } }); nPanel.add(greenRB); accessoryBG.add(redRB); redRB.setForeground(new java.awt.Color(255, 0, 51)); redRB.setText("Red"); redRB.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { redRBActionPerformed(evt); } }); nPanel.add(redRB); displayRouteCB.setText("Route"); displayRouteCB.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { displayRouteCBActionPerformed(evt); } }); nPanel.add(displayRouteCB); scaleCB.setText("Scale"); scaleCB.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { scaleCBActionPerformed(evt); } }); nPanel.add(scaleCB); showCenterCB.setText("Center"); showCenterCB.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { showCenterCBActionPerformed(evt); } }); nPanel.add(showCenterCB); getContentPane().add(nPanel, java.awt.BorderLayout.NORTH); canvas.setPreferredSize(new java.awt.Dimension(600, 600)); getContentPane().add(canvas, java.awt.BorderLayout.CENTER); pack(); }// //GEN-END:initComponents private void rotateButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_rotateButtonActionPerformed rotateTile(); }//GEN-LAST:event_rotateButtonActionPerformed private void tileCBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_tileCBActionPerformed createTile(); }//GEN-LAST:event_tileCBActionPerformed private void orientationCBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_orientationCBActionPerformed changeOrientation(); }//GEN-LAST:event_orientationCBActionPerformed private void directionCBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_directionCBActionPerformed changeDirection(); }//GEN-LAST:event_directionCBActionPerformed private void offRBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_offRBActionPerformed changeAccesoryState(); }//GEN-LAST:event_offRBActionPerformed private void greenRBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_greenRBActionPerformed changeAccesoryState(); }//GEN-LAST:event_greenRBActionPerformed private void redRBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_redRBActionPerformed changeAccesoryState(); }//GEN-LAST:event_redRBActionPerformed private void displayRouteCBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_displayRouteCBActionPerformed showRoute(); }//GEN-LAST:event_displayRouteCBActionPerformed private void scaleCBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_scaleCBActionPerformed this.tile.setScaleImage(!this.scaleCB.isSelected()); this.tile.setBounds(this.tile.getTileBounds()); }//GEN-LAST:event_scaleCBActionPerformed private void incomingSideCBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_incomingSideCBActionPerformed changeIncomingSide(); }//GEN-LAST:event_incomingSideCBActionPerformed private void showCenterCBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_showCenterCBActionPerformed this.tile.setDrawCenterPoint(this.showCenterCB.isSelected()); }//GEN-LAST:event_showCenterCBActionPerformed /** * @param args the command line arguments */ public static void main(String args[]) { try { UIManager.setLookAndFeel("com.formdev.flatlaf.FlatLightLaf"); } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) { Logger.error(ex); } /* Create and display the form */ java.awt.EventQueue.invokeLater(() -> { TileTesterFrame app = new TileTesterFrame(); app.setTitle("Tile Tester"); app.setLocationRelativeTo(null); }); } // Variables declaration - do not modify//GEN-BEGIN:variables private javax.swing.ButtonGroup accessoryBG; private jcs.ui.layout.tiles.DotGridCanvas canvas; private javax.swing.JComboBox directionCB; private javax.swing.JCheckBox displayRouteCB; private javax.swing.JRadioButton greenRB; private javax.swing.JLabel inComingLbl; private javax.swing.JComboBox incomingSideCB; private javax.swing.JPanel nPanel; private javax.swing.JRadioButton offRB; private javax.swing.JComboBox orientationCB; private javax.swing.JRadioButton redRB; private javax.swing.JButton rotateButton; private javax.swing.JCheckBox scaleCB; private javax.swing.JCheckBox showCenterCB; private javax.swing.JComboBox tileCB; // End of variables declaration//GEN-END:variables } \ No newline at end of file +/* * Copyright 2024 Frans Jacobs. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package jcs.ui.layout.tiles; import java.awt.Color; import java.awt.Point; import javax.swing.ComboBoxModel; import javax.swing.DefaultComboBoxModel; import javax.swing.UIManager; import javax.swing.UnsupportedLookAndFeelException; import jcs.entities.AccessoryBean; import jcs.entities.AccessoryBean.AccessoryValue; import jcs.entities.TileBean; import jcs.entities.TileBean.Direction; import jcs.entities.TileBean.Orientation; import jcs.entities.TileBean.TileType; import jcs.ui.layout.LayoutUtil; import org.tinylog.Logger; public class TileTesterFrame extends javax.swing.JFrame { private Tile tile; public TileTesterFrame() { initComponents(); this.tileCB.setModel(createTileTypeComboBoxModel()); this.orientationCB.setModel(createOrientationComboBoxModel()); this.incomingSideCB.setModel(createOrientationComboBoxModel()); this.directionCB.setModel(createDirectionComboBoxModel(true)); createTile(); pack(); setVisible(true); } private ComboBoxModel createTileTypeComboBoxModel() { DefaultComboBoxModel tileTypeModel = new DefaultComboBoxModel(); tileTypeModel.addElement(TileBean.TileType.STRAIGHT); tileTypeModel.addElement(TileBean.TileType.STRAIGHT_DIR); tileTypeModel.addElement(TileBean.TileType.SENSOR); tileTypeModel.addElement(TileBean.TileType.SIGNAL); tileTypeModel.addElement(TileBean.TileType.END); tileTypeModel.addElement(TileBean.TileType.CROSSING); tileTypeModel.addElement(TileBean.TileType.CURVED); tileTypeModel.addElement(TileBean.TileType.SWITCH); tileTypeModel.addElement(TileBean.TileType.CROSS); return tileTypeModel; } private ComboBoxModel createOrientationComboBoxModel() { DefaultComboBoxModel orientationModel = new DefaultComboBoxModel(); orientationModel.addElement(Orientation.EAST); orientationModel.addElement(Orientation.SOUTH); orientationModel.addElement(Orientation.WEST); orientationModel.addElement(Orientation.NORTH); return orientationModel; } private ComboBoxModel createDirectionComboBoxModel(boolean dontCare) { DefaultComboBoxModel directionModel = new DefaultComboBoxModel(); if (dontCare) { directionModel.addElement(Direction.CENTER); } else { directionModel.addElement(Direction.LEFT); directionModel.addElement(Direction.RIGHT); } return directionModel; } private void createTile() { if (tile != null) { Logger.trace("Removing tile " + tile.getId()); canvas.remove(tile); tile = null; } TileType tileType = (TileType) tileCB.getSelectedItem(); Orientation orientation = (Orientation) orientationCB.getSelectedItem(); if (TileType.SWITCH == tileType || TileType.CROSS == tileType) { directionCB.setModel(createDirectionComboBoxModel(false)); } else { directionCB.setModel(createDirectionComboBoxModel(true)); } Direction direction = (Direction) this.directionCB.getSelectedItem(); boolean scale = !scaleCB.isSelected(); boolean showCenter = showCenterCB.isSelected(); int w = canvas.getWidth(); int h = canvas.getHeight(); int x = w / 2; int y = h / 2; Point tileCenter = new Point(x, y); tileCenter = LayoutUtil.snapToGrid(tileCenter); Tile newTile = TileCache.createTile(tileType, orientation, direction, tileCenter); newTile.setScaleImage(scale); newTile.setDrawCenterPoint(showCenter); //tile.setPropertyChangeListener(this); Orientation incomingSide = (Orientation) this.incomingSideCB.getSelectedItem(); newTile.setIncomingSide(incomingSide); newTile.setShowRoute(displayRouteCB.isSelected()); newTile.setTrackRouteColor(Color.blue); Logger.trace("Adding tile " + newTile.getId() + " " + newTile.xyToString()); //this.cPanel.add((JComponent) newTile); this.canvas.add(newTile); this.tile = newTile; tile.updateUI(); } private AccessoryValue getAccessoryState() { AccessoryValue value; if (greenRB.isSelected()) { value = AccessoryValue.GREEN; } else if (redRB.isSelected()) { value = AccessoryValue.RED; } else { value = AccessoryValue.OFF; } return value; } private void changeAccesoryState() { if (tile instanceof Sensor) { tile.setActive(this.redRB.isSelected()); } if (tile instanceof Switch aSwitch) { if (this.displayRouteCB.isSelected()) { aSwitch.setRouteValue(getAccessoryState()); } else { aSwitch.setAccessoryValue(getAccessoryState()); } } if (tile instanceof Signal aSignal) { if (this.greenRB.isSelected()) { aSignal.setSignalValue(AccessoryBean.SignalValue.Hp1); } else if (this.redRB.isSelected()) { aSignal.setSignalValue(AccessoryBean.SignalValue.Hp0); } else { aSignal.setSignalValue(AccessoryBean.SignalValue.OFF); } } //this.tile.repaint(); } // @Override // public void propertyChange(PropertyChangeEvent evt) { // if ("repaintTile".equals(evt.getPropertyName())) { // Tile t = (Tile) evt.getNewValue(); // Logger.trace("Tile: " + t); // //this.repaint(); // } // } // @Override // public void paint(Graphics g) { // super.paint(g); // Graphics2D g2d = (Graphics2D) g; // boolean outline = this.drawOutlineCB.isSelected(); // boolean showRoute = this.displayRouteCB.isSelected(); // tile.setShowRoute(showRoute); // // tile.drawTile(g2d, outline); // // if (outline) { // tile.drawBounds(g2d); // tile.drawCenterPoint(g2d, Color.red); // } // } // @Override // public void paint(Graphics g) { // long started = System.currentTimeMillis(); // super.paint(g); // // long now = System.currentTimeMillis(); // Logger.trace("Duration: " + (now - started) + " ms."); // } private void changeDirection() { Direction direction = (Direction) this.directionCB.getSelectedItem(); this.tile.setDirection(direction); //if (TileType.CROSS == tile.getTileType()) { // ((Cross) tile).setWidthHeightAndOffsets(); //} //this.repaint(); } private void rotateTile() { Orientation newOrientation = tile.rotate(); orientationCB.setSelectedItem(newOrientation); // if (TileType.CROSS == tile.getTileType()) { // int x = tile.getCenterX(); // int y = tile.getCenterY(); // int w = tile.getWidth() * 10; // int h = tile.getHeight() * 10; // // //calculate a new centerpoint for cross // switch (tile.getOrientation()) { // case SOUTH -> { // x = x + w / 2; // y = y - h / 4; // } // case WEST -> { // x = x + w / 4; // y = y + h / 2; // } // case NORTH -> { // x = x - w / 2; // y = y + h / 4; // } // default -> { // x = x - w / 4; // y = y - h / 2; // } // } // tile.setCenter(new Point(x, y)); // } //this.canvas.repaint(this.tile.getTileBounds()); //tile.repaint(); } private void changeOrientation() { Orientation orientation = (Orientation) this.orientationCB.getSelectedItem(); tile.setOrientation(orientation); // if (TileType.CROSS == tile.getTileType()) { // //((Cross) tile).setWidthHeightAndOffsets(); // // int x = tile.getCenterX(); // int y = tile.getCenterY(); // int w = tile.getWidth() * 10; // int h = tile.getHeight() * 10; // // //calculate a new centerpoint for cross // switch (tile.getOrientation()) { // case SOUTH -> { // x = x + w / 2; // y = y - h / 4; // } // case WEST -> { // x = x + w / 4; // y = y + h / 2; // } // case NORTH -> { // x = x - w / 2; // y = y + h / 4; // } // default -> { // x = x - w / 4; // y = y - h / 2; // } // } // tile.setCenter(new Point(x, y)); // } //this.repaint(); } private void showRoute() { Logger.trace("Show route on tile " + tile.getId()); String tileId = tile.getId(); Orientation incomingSide = (Orientation) this.incomingSideCB.getSelectedItem(); //TileEvent tileEvent; if (tile.isJunction()) { AccessoryValue routeState = getAccessoryState(); //tileEvent = new TileEvent(tileId, true, incomingSide, routeState); } else { //tileEvent = new TileEvent(tileId, true, incomingSide); } //TileCache.fireTileEventListener(tileEvent); // ((JComponent) this.tile).repaint(); tile.setShowRoute(displayRouteCB.isSelected()); //repaint(); } // private void showOutline() { // //repaint(); // } private void changeIncomingSide() { Orientation incomingSide = (Orientation) this.incomingSideCB.getSelectedItem(); tile.setIncomingSide(incomingSide); //this.repaint(); } /** * This method is called from within the constructor to initialize the form. WARNING: Do NOT modify this code. The content of this method is always regenerated by the Form Editor. */ @SuppressWarnings("unchecked") // //GEN-BEGIN:initComponents private void initComponents() { accessoryBG = new javax.swing.ButtonGroup(); nPanel = new javax.swing.JPanel(); tileCB = new javax.swing.JComboBox<>(); orientationCB = new javax.swing.JComboBox<>(); inComingLbl = new javax.swing.JLabel(); incomingSideCB = new javax.swing.JComboBox<>(); directionCB = new javax.swing.JComboBox<>(); rotateButton = new javax.swing.JButton(); offRB = new javax.swing.JRadioButton(); greenRB = new javax.swing.JRadioButton(); redRB = new javax.swing.JRadioButton(); displayRouteCB = new javax.swing.JCheckBox(); scaleCB = new javax.swing.JCheckBox(); showCenterCB = new javax.swing.JCheckBox(); canvas = new jcs.ui.layout.tiles.DotGridCanvas(); setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE); nPanel.setMinimumSize(new java.awt.Dimension(860, 36)); nPanel.setPreferredSize(new java.awt.Dimension(1020, 36)); java.awt.FlowLayout flowLayout1 = new java.awt.FlowLayout(java.awt.FlowLayout.LEFT); flowLayout1.setAlignOnBaseline(true); nPanel.setLayout(flowLayout1); tileCB.setPreferredSize(new java.awt.Dimension(150, 23)); tileCB.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { tileCBActionPerformed(evt); } }); nPanel.add(tileCB); orientationCB.setPreferredSize(new java.awt.Dimension(100, 23)); orientationCB.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { orientationCBActionPerformed(evt); } }); nPanel.add(orientationCB); inComingLbl.setText("Incoming Orientation"); nPanel.add(inComingLbl); incomingSideCB.setPreferredSize(new java.awt.Dimension(100, 23)); incomingSideCB.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { incomingSideCBActionPerformed(evt); } }); nPanel.add(incomingSideCB); directionCB.setPreferredSize(new java.awt.Dimension(100, 23)); directionCB.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { directionCBActionPerformed(evt); } }); nPanel.add(directionCB); rotateButton.setText("Rotate"); rotateButton.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { rotateButtonActionPerformed(evt); } }); nPanel.add(rotateButton); accessoryBG.add(offRB); offRB.setForeground(new java.awt.Color(153, 153, 153)); offRB.setSelected(true); offRB.setText("Off"); offRB.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { offRBActionPerformed(evt); } }); nPanel.add(offRB); accessoryBG.add(greenRB); greenRB.setForeground(new java.awt.Color(102, 255, 0)); greenRB.setText("Green"); greenRB.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { greenRBActionPerformed(evt); } }); nPanel.add(greenRB); accessoryBG.add(redRB); redRB.setForeground(new java.awt.Color(255, 0, 51)); redRB.setText("Red"); redRB.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { redRBActionPerformed(evt); } }); nPanel.add(redRB); displayRouteCB.setText("Route"); displayRouteCB.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { displayRouteCBActionPerformed(evt); } }); nPanel.add(displayRouteCB); scaleCB.setText("Scale"); scaleCB.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { scaleCBActionPerformed(evt); } }); nPanel.add(scaleCB); showCenterCB.setText("Center"); showCenterCB.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { showCenterCBActionPerformed(evt); } }); nPanel.add(showCenterCB); getContentPane().add(nPanel, java.awt.BorderLayout.NORTH); canvas.setPreferredSize(new java.awt.Dimension(600, 600)); getContentPane().add(canvas, java.awt.BorderLayout.CENTER); pack(); }// //GEN-END:initComponents private void rotateButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_rotateButtonActionPerformed rotateTile(); }//GEN-LAST:event_rotateButtonActionPerformed private void tileCBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_tileCBActionPerformed createTile(); }//GEN-LAST:event_tileCBActionPerformed private void orientationCBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_orientationCBActionPerformed changeOrientation(); }//GEN-LAST:event_orientationCBActionPerformed private void directionCBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_directionCBActionPerformed changeDirection(); }//GEN-LAST:event_directionCBActionPerformed private void offRBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_offRBActionPerformed changeAccesoryState(); }//GEN-LAST:event_offRBActionPerformed private void greenRBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_greenRBActionPerformed changeAccesoryState(); }//GEN-LAST:event_greenRBActionPerformed private void redRBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_redRBActionPerformed changeAccesoryState(); }//GEN-LAST:event_redRBActionPerformed private void displayRouteCBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_displayRouteCBActionPerformed showRoute(); }//GEN-LAST:event_displayRouteCBActionPerformed private void scaleCBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_scaleCBActionPerformed this.tile.setScaleImage(!this.scaleCB.isSelected()); this.tile.setBounds(this.tile.getTileBounds()); }//GEN-LAST:event_scaleCBActionPerformed private void incomingSideCBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_incomingSideCBActionPerformed changeIncomingSide(); }//GEN-LAST:event_incomingSideCBActionPerformed private void showCenterCBActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_showCenterCBActionPerformed this.tile.setDrawCenterPoint(this.showCenterCB.isSelected()); }//GEN-LAST:event_showCenterCBActionPerformed /** * @param args the command line arguments */ public static void main(String args[]) { try { UIManager.setLookAndFeel("com.formdev.flatlaf.FlatLightLaf"); } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) { Logger.error(ex); } /* Create and display the form */ java.awt.EventQueue.invokeLater(() -> { TileTesterFrame app = new TileTesterFrame(); app.setTitle("Tile Tester"); app.setLocationRelativeTo(null); }); } // Variables declaration - do not modify//GEN-BEGIN:variables private javax.swing.ButtonGroup accessoryBG; private jcs.ui.layout.tiles.DotGridCanvas canvas; private javax.swing.JComboBox directionCB; private javax.swing.JCheckBox displayRouteCB; private javax.swing.JRadioButton greenRB; private javax.swing.JLabel inComingLbl; private javax.swing.JComboBox incomingSideCB; private javax.swing.JPanel nPanel; private javax.swing.JRadioButton offRB; private javax.swing.JComboBox orientationCB; private javax.swing.JRadioButton redRB; private javax.swing.JButton rotateButton; private javax.swing.JCheckBox scaleCB; private javax.swing.JCheckBox showCenterCB; private javax.swing.JComboBox tileCB; // End of variables declaration//GEN-END:variables } \ No newline at end of file From f0de294ea13d6f6c46e863c065e1a03a7ac8f354 Mon Sep 17 00:00:00 2001 From: Frans Jacobs Date: Thu, 13 Feb 2025 21:07:50 +0100 Subject: [PATCH 22/24] Experiment for idle state --- .../jcs/commandStation/autopilot/state/IdleState.java | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/main/java/jcs/commandStation/autopilot/state/IdleState.java b/src/main/java/jcs/commandStation/autopilot/state/IdleState.java index df5b5dbb..01988258 100644 --- a/src/main/java/jcs/commandStation/autopilot/state/IdleState.java +++ b/src/main/java/jcs/commandStation/autopilot/state/IdleState.java @@ -59,6 +59,17 @@ DispatcherState execute(Dispatcher dispatcher) { } catch (InterruptedException ex) { Logger.trace("Interrupted: " + ex.getMessage()); } + } else { + //Automode is switched off for this Dispatcher so the Idle state must end... + Logger.trace(dispatcher.getName() + " Automode: " + AutoPilot.isAutoModeActive() + " Dispacher " + dispatcher.isLocomotiveAutomodeOn()); + try { + synchronized (this) { + wait(10000); + } + } catch (InterruptedException ex) { + Logger.trace("Interrupted: " + ex.getMessage()); + } + } } return this; From 82c018c88fc2775d8c54c0a6f2e1d90f1fba15eb Mon Sep 17 00:00:00 2001 From: Frans Jacobs Date: Wed, 19 Feb 2025 17:30:49 +0100 Subject: [PATCH 23/24] Most of the issues are now solved --- pom.xml | 5 + src/main/java/jcs/JCS.java | 107 +++++---- .../autopilot/ActionCommandHandler.java | 102 +++++++++ .../commandStation/autopilot/AutoPilot.java | 214 ++++++++++++------ .../autopilot/AutoPilotActionEvent.java | 46 ++++ .../autopilot/DriveSimulator.java | 3 - .../autopilot/state/Dispatcher.java | 172 +++++++------- .../autopilot/state/IdleState.java | 4 +- ...teMachineThread.java => StateMachine.java} | 79 ++++--- .../esu/ecos/FeedbackManager.java | 1 - .../java/jcs/ui/DispatcherStatusPanel.java | 14 +- src/main/java/jcs/ui/JCSFrame.form | 71 +++--- src/main/java/jcs/ui/JCSFrame.java | 121 +++++----- src/main/java/jcs/ui/layout/LayoutCanvas.java | 39 ++-- src/main/java/jcs/ui/layout/LayoutPanel.java | 24 +- .../ui/layout/dialogs/BlockControlDialog.java | 14 +- .../java/jcs/ui/layout/events/TileEvent.java | 157 ------------- .../ui/layout/events/TileEventListener.java | 24 -- .../java/jcs/ui/layout/tiles/TileCache.java | 2 +- .../jcs/ui/table/DispatcherTablePanel.java | 72 ++---- .../jcs/ui/table/LocomotiveTablePanel.java | 10 +- .../resources/media/arrowhead-right-gn.png | Bin 0 -> 456 bytes src/main/resources/media/pause-gr.png | Bin 0 -> 186 bytes src/main/resources/media/reset-happy.png | Bin 0 -> 738 bytes src/main/resources/tinylog-dev.properties | 7 +- src/main/resources/tinylog.properties | 6 +- .../autopilot/AutoPilotTest.java | 8 +- .../state/StateMachineStepByStepTest.java | 32 +-- .../state/StateMachineThreadTest.java | 15 +- 29 files changed, 692 insertions(+), 657 deletions(-) create mode 100644 src/main/java/jcs/commandStation/autopilot/ActionCommandHandler.java create mode 100644 src/main/java/jcs/commandStation/autopilot/AutoPilotActionEvent.java rename src/main/java/jcs/commandStation/autopilot/state/{StateMachineThread.java => StateMachine.java} (92%) delete mode 100644 src/main/java/jcs/ui/layout/events/TileEvent.java delete mode 100644 src/main/java/jcs/ui/layout/events/TileEventListener.java create mode 100755 src/main/resources/media/arrowhead-right-gn.png create mode 100755 src/main/resources/media/pause-gr.png create mode 100755 src/main/resources/media/reset-happy.png diff --git a/pom.xml b/pom.xml index 7222ff10..d7a8a16d 100644 --- a/pom.xml +++ b/pom.xml @@ -172,6 +172,11 @@ logback-classic 1.2.13 + org.netbeans.external AbsoluteLayout diff --git a/src/main/java/jcs/JCS.java b/src/main/java/jcs/JCS.java index 93ef061a..b14d1b48 100755 --- a/src/main/java/jcs/JCS.java +++ b/src/main/java/jcs/JCS.java @@ -16,10 +16,13 @@ package jcs; import java.awt.GraphicsEnvironment; +import java.io.File; +import java.io.IOException; import java.net.URL; import java.util.ArrayList; import java.util.List; import javax.swing.ImageIcon; +import javax.swing.JOptionPane; import javax.swing.UIManager; import javax.swing.UnsupportedLookAndFeelException; import jcs.commandStation.JCSCommandStation; @@ -46,22 +49,22 @@ * */ public class JCS extends Thread { - + private static JCS instance = null; private static JCSSplash splashScreen; private static PersistenceService persistentStore; private static JCSCommandStation jcsCommandStation; - + private static MacOsAdapter osAdapter; private static JCSFrame jcsFrame; private static String version; - + private final List refreshEventListeners; - + private JCS() { refreshEventListeners = new ArrayList<>(); } - + public static void logProgress(String message) { if (splashScreen != null) { splashScreen.logProgress(message); @@ -69,18 +72,18 @@ public static void logProgress(String message) { Logger.info(message); } } - + public static JCSFrame getParentFrame() { return jcsFrame; } - + public static PersistenceService getPersistenceService() { if (persistentStore == null) { persistentStore = PersistenceFactory.getService(); } return persistentStore; } - + public static JCSCommandStation getJcsCommandStation() { if (jcsCommandStation == null) { if (getPersistenceService() != null) { @@ -91,18 +94,18 @@ public static JCSCommandStation getJcsCommandStation() { } return jcsCommandStation; } - + private void startGui() { JCS.logProgress("Check OS..."); - + if (RunUtil.isMacOSX()) { MacOsAdapter.setMacOsProperties(); osAdapter = new MacOsAdapter(); } - + java.awt.EventQueue.invokeLater(() -> { jcsFrame = new JCSFrame(); - + if (RunUtil.isMacOSX()) { osAdapter.setUiCallback(jcsFrame); } @@ -112,9 +115,9 @@ private void startGui() { if (iconUrl != null) { jcsFrame.setIconImage(new ImageIcon(iconUrl).getImage()); } - + FrameMonitor.registerFrame(jcsFrame, JCS.class.getName()); - + jcsFrame.setVisible(true); jcsFrame.toFront(); jcsFrame.showOverviewPanel(); @@ -122,12 +125,12 @@ private void startGui() { jcsFrame.connect(true); } }); - + JCS.logProgress("JCS started..."); - + int mb = 1024 * 1024; Runtime runtime = Runtime.getRuntime(); - + StringBuilder sb = new StringBuilder(); sb.append("Used Memory: "); sb.append((runtime.totalMemory() - runtime.freeMemory()) / mb); @@ -138,7 +141,7 @@ private void startGui() { sb.append(" [MB]. Max Memory: "); sb.append(runtime.maxMemory() / mb); sb.append(" [MB]."); - + Logger.info(sb); splashScreen.hideSplash(200); splashScreen.close(); @@ -155,21 +158,21 @@ public void run() { ProcessFactory.getInstance().shutdown(); Logger.info("JCS " + VersionInfo.getVersion() + " session finished"); } - + public static void addRefreshListener(RefreshEventListener refreshListener) { instance.refreshEventListeners.add(refreshListener); } - + public static void removeRefreshListener(RefreshEventListener refreshListener) { instance.refreshEventListeners.remove(refreshListener); } - + public static void settingsChanged(RefreshEvent refreshEvent) { for (RefreshEventListener rel : instance.refreshEventListeners) { rel.onChange(refreshEvent); } } - + public static JCS getInstance() { if (instance == null) { instance = new JCS(); @@ -179,21 +182,38 @@ public static JCS getInstance() { } return instance; } - + + private static boolean lockAppInstance() { + try { + String lockFilePath = System.getProperty("user.home") + File.separator + "jcs" + File.separator + "jcs.lock"; + + final File file = new File(lockFilePath); + if (file.createNewFile()) { + file.deleteOnExit(); + return true; + } + return false; + } catch (IOException e) { + return false; + } + } + public static void main(String[] args) { System.setProperty("fazecast.jSerialComm.appid", "JCS"); version = VersionInfo.getVersion(); Logger.info("Starting JCS Version " + version + "..."); - + if (GraphicsEnvironment.isHeadless()) { Logger.error("This JDK environment is headless, can't start a GUI!"); //Quit.... System.exit(1); } + //Load properties RunUtil.loadProperties(); + RunUtil.loadExternalProperties(); - + try { String plaf = System.getProperty("jcs.plaf", "com.formdev.flatlaf.FlatLightLaf"); if (plaf != null) { @@ -204,11 +224,19 @@ public static void main(String[] args) { } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) { Logger.error(ex); } - + + if (!lockAppInstance()) { + Logger.warn("Can not obtain a lock. Check if an other instance of JCS is running"); + JOptionPane.showMessageDialog(null, "There is another instance of JCS running.", "JCS allready running", JOptionPane.INFORMATION_MESSAGE, null); + System.exit(0); + } + splashScreen = new JCSSplash(); + splashScreen.showSplash(); + splashScreen.setProgressMax(25); - + logProgress("JCS is Starting..."); //Check the persistent properties, prepare environment @@ -221,24 +249,27 @@ public static void main(String[] args) { //Database file exist check whether an update is needed String dbVersion = H2DatabaseUtil.getDataBaseVersion(); + if (!H2DatabaseUtil.DB_VERSION.equals(dbVersion)) { Logger.trace("Current DB Version " + dbVersion + " need to be updated to: " + H2DatabaseUtil.DB_VERSION + "..."); logProgress("Updating JCS Database to version " + H2DatabaseUtil.DB_VERSION + "..."); dbVersion = H2DatabaseUtil.updateDatabase(); } + logProgress("Connecting to existing Database version " + dbVersion + "..."); - + logProgress("Starting JCS Command Station..."); persistentStore = getPersistenceService(); jcsCommandStation = getJcsCommandStation(); - - if (persistentStore != null) { + + if (persistentStore + != null) { if ("true".equalsIgnoreCase(System.getProperty("commandStation.autoconnect", "true"))) { if (jcsCommandStation != null) { boolean connected = jcsCommandStation.connect(); if (connected) { logProgress("Connected with Command Station..."); - + boolean power = jcsCommandStation.isPowerOn(); logProgress("Track Power is " + (power ? "on" : "off")); Logger.info("Track Power is " + (power ? "on" : "off")); @@ -250,9 +281,9 @@ public static void main(String[] args) { logProgress("NO Default Command Station found..."); } } - + logProgress("Starting UI..."); - + JCS jcs = JCS.getInstance(); jcs.startGui(); } else { @@ -263,20 +294,20 @@ public static void main(String[] args) { System.exit(0); } } - + private static class Powerlistener implements PowerEventListener { - + Powerlistener() { } - + @Override public void onPowerChange(PowerEvent event) { Logger.info("Track Power is " + (event.isPower() ? "on" : "off")); - + if (JCS.jcsFrame != null) { JCS.jcsFrame.powerChanged(event); } } } - + } diff --git a/src/main/java/jcs/commandStation/autopilot/ActionCommandHandler.java b/src/main/java/jcs/commandStation/autopilot/ActionCommandHandler.java new file mode 100644 index 00000000..62195505 --- /dev/null +++ b/src/main/java/jcs/commandStation/autopilot/ActionCommandHandler.java @@ -0,0 +1,102 @@ +/* + * Copyright 2025 fransjacobs. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package jcs.commandStation.autopilot; + +import java.util.concurrent.ConcurrentLinkedQueue; +import org.tinylog.Logger; + +/** + * + * A Handler to Monitor the AutoPilot engine. + * + */ +public class ActionCommandHandler extends Thread { + + private boolean stop = false; + private boolean quit = true; + + private final ConcurrentLinkedQueue eventQueue; + + ActionCommandHandler(ConcurrentLinkedQueue eventQueue) { + this.eventQueue = eventQueue; + } + + void quit() { + this.quit = true; + } + + boolean isRunning() { + return !this.quit; + } + + boolean isFinished() { + return this.stop; + } + + @Override + public void run() { + quit = false; + setName("AUTOPILOT-COMMAND-HANDLER"); + + Logger.trace("AutoPilot ActionCommandHandler Started..."); + + while (isRunning()) { + try { + AutoPilotActionEvent event = eventQueue.poll(); + if (event != null) { + switch (event.getActionCommand()) { + case "start" -> { + AutoPilot.startAutoMode(); + } + case "stop" -> { + AutoPilot.stopAutoMode(); + } + case "startLocomotive" -> { + AutoPilot.startDispatcher(event.getLocomotiveBean()); + } + case "stopLocomotive" -> { + AutoPilot.stopDispatcher(event.getLocomotiveBean()); + } + case "startAllLocomotives" -> { + AutoPilot.startLocomotives(); + } + case "removeLocomotive" -> { + AutoPilot.removeDispatcher(event.getLocomotiveBean()); + } + case "addLocomotive" -> { + AutoPilot.addDispatcher(event.getLocomotiveBean()); + } + case "reset" -> { + AutoPilot.resetStates(); + } + } + } else { + //lets sleep for a while + synchronized (this) { + wait(10000); + } + } + + } catch (InterruptedException ex) { + Logger.error(ex); + } + } + + stop = true; + Logger.trace("Tile ActionEventHandler Stopped..."); + } + +} diff --git a/src/main/java/jcs/commandStation/autopilot/AutoPilot.java b/src/main/java/jcs/commandStation/autopilot/AutoPilot.java index ec8f7415..d733f806 100644 --- a/src/main/java/jcs/commandStation/autopilot/AutoPilot.java +++ b/src/main/java/jcs/commandStation/autopilot/AutoPilot.java @@ -23,8 +23,7 @@ import java.util.List; import java.util.Map; import java.util.Set; -import java.util.concurrent.ExecutorService; -import java.util.concurrent.Executors; +import java.util.concurrent.ConcurrentLinkedQueue; import java.util.concurrent.Semaphore; import java.util.stream.Collectors; import jcs.JCS; @@ -45,12 +44,12 @@ * The AutoPilot is the "automatic driving engine".
* Every Locomotive on the track will start it own Thread.
* The Dispatcher is run in this Thread.
- * The AutoPilot has it own Monitor Thread: AutoPilotThread. + * The AutoPilot has it own Monitor Thread: AutoPilotMonitorThread. * */ public final class AutoPilot { - private static AutoPilotThread autoPilotThread = null; + private static AutoPilotMonitorThread autoPilotThread = null; private static CommandStationBean commandStationBean; @@ -61,43 +60,83 @@ public final class AutoPilot { private static final List autoPilotStatusListeners = Collections.synchronizedList(new ArrayList<>()); private static final Semaphore semaphore = new Semaphore(1); - private static final ExecutorService executor = Executors.newCachedThreadPool(); private static final ThreadGroup autoPilotRunners = new ThreadGroup("AUTOPILOT"); + private static final ConcurrentLinkedQueue actionCommandQueue = new ConcurrentLinkedQueue(); + + private static final ActionCommandHandler actionCommandHandler = new ActionCommandHandler(actionCommandQueue); + + static { + actionCommandHandler.start(); + } + private AutoPilot() { } public static void runAutoPilot(boolean flag) { if (flag) { - executor.execute(() -> startAutoMode()); + enqueCommand(new AutoPilotActionEvent("start")); } else { - executor.execute(() -> stopAutoMode()); + enqueCommand(new AutoPilotActionEvent("stop")); } } - public synchronized static void startAutoMode() { + public static void startLocomotive(LocomotiveBean locomotiveBean) { + enqueCommand(new AutoPilotActionEvent("startLocomotive", locomotiveBean)); + } + + public static void stopLocomotive(LocomotiveBean locomotiveBean) { + enqueCommand(new AutoPilotActionEvent("stopLocomotive", locomotiveBean)); + } + + public static void removeLocomotive(LocomotiveBean locomotiveBean) { + enqueCommand(new AutoPilotActionEvent("removeLocomotive", locomotiveBean)); + } + + public static void addLocomotive(LocomotiveBean locomotiveBean) { + enqueCommand(new AutoPilotActionEvent("addLocomotive", locomotiveBean)); + } + + public static void startAllLocomotives() { + enqueCommand(new AutoPilotActionEvent("startAllLocomotives")); + } + + public static void reset() { + enqueCommand(new AutoPilotActionEvent("reset")); + } + + private static void enqueCommand(AutoPilotActionEvent command) { + actionCommandQueue.offer(command); + synchronized (AutoPilot.actionCommandHandler) { + actionCommandHandler.notifyAll(); + } + } + + static boolean startAutoMode() { if (JCS.getJcsCommandStation().isPowerOn()) { if (autoPilotThread != null && autoPilotThread.isRunning()) { Logger.trace("Allready running"); + return true; } else { commandStationBean = JCS.getJcsCommandStation().getCommandStationBean(); dispatchers.clear(); sensorHandlers.clear(); - autoPilotThread = new AutoPilotThread(autoPilotRunners); + autoPilotThread = new AutoPilotMonitorThread(autoPilotRunners); autoPilotThread.start(); + Logger.debug("AutoMode Started"); + return true; } } else { - Logger.warn("Can't start Automode is Power is Off!"); + Logger.warn("Can't start Automode, Command Station Power is Off!"); + return false; } } - public static void stopAutoMode() { + static void stopAutoMode() { if (autoPilotThread != null) { - autoPilotThread.stopAutoMode(); - - //Notify all dispachers so thath the ones which waiting and Idle will stop + //Notify all dispachers so that the ones which waiting and Idle will stop Set snapshot = new HashSet<>(dispatchers.values()); for (Dispatcher d : snapshot) { d.stopLocomotiveAutomode(); @@ -106,12 +145,16 @@ public static void stopAutoMode() { } } + autoPilotThread.stopAutoMode(); + try { autoPilotThread.join(); } catch (InterruptedException ex) { Logger.error("Interruppted during join " + ex); } } + Logger.debug("AutoMode Stopped"); + } public static boolean isAutoModeActive() { @@ -139,7 +182,7 @@ public static boolean isRunning(LocomotiveBean locomotive) { } } - public static boolean areDispatchersRunning() { + public static boolean isADispatcherRunning() { boolean isRunning = false; Set snapshot = new HashSet<>(dispatchers.values()); for (Dispatcher ld : snapshot) { @@ -162,7 +205,7 @@ public static int getRunningDispatcherCount() { return runningDispatchers; } - public static synchronized Dispatcher createDispatcher(LocomotiveBean locomotiveBean) { + static Dispatcher createDispatcher(LocomotiveBean locomotiveBean) { Dispatcher dispatcher = null; //check if the locomotive is on track if (isOnTrack(locomotiveBean)) { @@ -180,6 +223,32 @@ public static synchronized Dispatcher createDispatcher(LocomotiveBean locomotive return dispatcher; } + static void removeDispatcher(LocomotiveBean locomotiveBean) { + if (dispatchers.containsKey(locomotiveBean.getName())) { + Dispatcher dispatcher = dispatchers.remove(locomotiveBean.getName()); + Logger.trace("removing Dispatcher for locomotive " + locomotiveBean.getName()); + if (dispatcher.isRunning()) { + Logger.trace("Stopping Automode for " + locomotiveBean.getName() + "..."); + dispatcher.stopLocomotiveAutomode(); + dispatcher.stopRunning(); + } + + dispatcher.removeAllStateEventListeners(); + + for (AutoPilotStatusListener asl : autoPilotStatusListeners) { + asl.statusChanged(autoPilotThread.running); + } + } + } + + static void addDispatcher(LocomotiveBean locomotiveBean) { + createDispatcher(locomotiveBean); + + for (AutoPilotStatusListener asl : autoPilotStatusListeners) { + asl.statusChanged(autoPilotThread.running); + } + } + public static void prepareAllDispatchers() { Logger.trace("Preparing Dispatchers for all on track locomotives..."); List locs = getOnTrackLocomotives(); @@ -192,7 +261,7 @@ public static void prepareAllDispatchers() { if (snapshot.containsKey(loc.getName())) { dispatcher = snapshot.get(loc.getName()); dispatchers.put(loc.getName(), dispatcher); - Logger.trace("Reused dispatcher for " + loc.getName() + "..."); + Logger.trace("Re use dispatcher " + loc.getName() + "..."); } else { createDispatcher(loc); } @@ -200,7 +269,7 @@ public static void prepareAllDispatchers() { } public static synchronized void clearDispatchers() { - Logger.trace("Remove all Dispatchers..."); + Logger.trace("Removing all Dispatchers..."); for (Dispatcher dispatcher : dispatchers.values()) { dispatcher.stopLocomotiveAutomode(); @@ -209,32 +278,42 @@ public static synchronized void clearDispatchers() { dispatchers.clear(); } - public static void startStopLocomotive(LocomotiveBean locomotiveBean, boolean start) { - Logger.trace((start ? "Starting" : "Stopping") + " auto drive for " + locomotiveBean.getName()); + static void startDispatcher(LocomotiveBean locomotiveBean) { + Logger.trace("Starting locomotive for " + locomotiveBean.getName()); String key = locomotiveBean.getName(); - if (start) { - Dispatcher dispatcher; - if (dispatchers.containsKey(key)) { - dispatcher = dispatchers.get(key); - Logger.trace("Dispatcher " + key + " exists"); - } else { - dispatcher = createDispatcher(locomotiveBean); - Logger.trace("Dispatcher " + key + " created"); - } + Dispatcher dispatcher; + if (dispatchers.containsKey(key)) { + dispatcher = dispatchers.get(key); + //Logger.trace("Dispatcher " + key + " exists"); + } else { + dispatcher = createDispatcher(locomotiveBean); + Logger.trace("Dispatcher " + key + " created"); + } - if (!dispatcher.isRunning()) { - Logger.trace("Starting dispatcher thread" + key); - dispatcher.startLocomotiveAutomode(); - } + if (!dispatcher.isRunning()) { + Logger.trace("Starting dispatcher thread " + key); + dispatcher.startLocomotiveAutomode(); + } - Logger.trace("Started dispatcher" + key + " automode..."); - } else { - Dispatcher dispatcher = dispatchers.get(key); - if (dispatcher != null && dispatcher.isRunning()) { - dispatcher.stopLocomotiveAutomode(); - Logger.trace("Stopped dispatcher" + key + " automode..."); - } + Logger.trace("Started locomotive " + key + "..."); + } + + static void stopDispatcher(LocomotiveBean locomotiveBean) { + Logger.trace("Stopping locomotive " + locomotiveBean.getName()); + String key = locomotiveBean.getName(); + + Dispatcher dispatcher = dispatchers.get(key); + if (dispatcher != null && dispatcher.isRunning()) { + dispatcher.stopLocomotiveAutomode(); + Logger.trace("Stopped locomotive " + key + "..."); + } + } + + static void startLocomotives() { + List locos = getOnTrackLocomotives(); + for (LocomotiveBean loc : locos) { + startDispatcher(loc); } } @@ -254,24 +333,11 @@ public static synchronized void resetDispatcher(LocomotiveBean locomotiveBean) { dispatcher.reset(); } - private static void startStopAllLocomotivesInBackground(boolean start) { - List onTrackLocos = getOnTrackLocomotives(); - Logger.trace((start ? "Starting" : "Stopping") + " automode for " + onTrackLocos.size() + " ontrack locomotives..."); - - for (LocomotiveBean locomotiveBean : onTrackLocos) { - startStopLocomotive(locomotiveBean, start); - } - } - - public static void startAllLocomotives() { - executor.execute(() -> startStopAllLocomotivesInBackground(true)); - } + static void resetStates() { + Logger.trace("Resetting AutoPilot..."); - public static void stopAllLocomotives() { - executor.execute(() -> startStopAllLocomotivesInBackground(false)); - } + stopAutoMode(); - public static void resetStates() { List routes = PersistenceFactory.getService().getRoutes(); int lockedCounter = 0; for (RouteBean route : routes) { @@ -300,7 +366,6 @@ public static void resetStates() { case LOCKED, INBOUND -> { //destinations block, reset! tile.setLocomotive(null); - //block.setLocomotive(null); tile.setBlockState(BlockBean.BlockState.FREE); tile.setArrivalSuffix(null); freeBlockCounter++; @@ -359,21 +424,26 @@ public static List getOnTrackLocomotives() { List occupiedBlocks = blocks.stream().filter(t -> t.getLocomotive() != null && t.getLocomotive().getId() != null).collect(Collectors.toList()); //Logger.trace("There " + (occupiedBlocks.size() == 1 ? "is" : "are") + " " + occupiedBlocks.size() + " occupied block(s)"); - Set activeLocomotives = new HashSet<>(); + //Set activeLocomotives = new HashSet<>(); + ArrayList activeLocomotives = new ArrayList<>(); for (BlockBean occupiedBlock : occupiedBlocks) { LocomotiveBean dbl = PersistenceFactory.getService().getLocomotive(occupiedBlock.getLocomotiveId()); if (dbl != null) { - activeLocomotives.add(dbl); + if (activeLocomotives.contains(dbl)) { + Logger.warn("Loc " + dbl.getName() + " Is allready in the list! "); + } else { + activeLocomotives.add(dbl); + } } } - if (Logger.isTraceEnabled()) { - // Logger.trace("There are " + activeLocomotives.size() + " Locomotives on the track: "); - for (LocomotiveBean loc : activeLocomotives) { - Logger.trace(loc); - } - } - return new ArrayList<>(activeLocomotives); + //if (Logger.isTraceEnabled()) { + //Logger.trace("There are " + activeLocomotives.size() + " Locomotives on the track: "); + //for (LocomotiveBean loc : activeLocomotives) { + // Logger.trace(loc); + //} + //} + return activeLocomotives; //new ArrayList<>(activeLocomotives); } public static boolean isGostDetected() { @@ -468,15 +538,15 @@ public static int avialablePermits() { return semaphore.availablePermits(); } - private static class AutoPilotThread extends Thread { + private static class AutoPilotMonitorThread extends Thread { private final List sensorListeners = new ArrayList<>(); private boolean running = false; private boolean stopped = false; - AutoPilotThread(ThreadGroup parent) { - super(parent, "AUTO_MAIN"); + AutoPilotMonitorThread(ThreadGroup parent) { + super(parent, "AUTOPILOT-MONITOR"); } void stopAutoMode() { @@ -525,7 +595,7 @@ public void run() { registerAllSensors(); prepareAllDispatchers(); - Logger.trace("Autopilot Started. Notify " + autoPilotStatusListeners.size() + " Listeners..."); + Logger.trace("Autopilot Started. There are " + dispatchers.size() + " Dispatchers created..."); for (AutoPilotStatusListener asl : autoPilotStatusListeners) { asl.statusChanged(running); @@ -547,7 +617,7 @@ public void run() { long start = now; long timeout = now + 30000; //Check if all dispachers are stopped - boolean dispatchersRunning = areDispatchersRunning(); + boolean dispatchersRunning = isADispatcherRunning(); Logger.trace("Try to finish all dispatchers. There are " + getRunningDispatcherCount() + " Dispatchers running..."); @@ -562,7 +632,7 @@ public void run() { } while (dispatchersRunning && now < timeout) { - dispatchersRunning = areDispatchersRunning(); + dispatchersRunning = isADispatcherRunning(); try { synchronized (this) { wait(10); diff --git a/src/main/java/jcs/commandStation/autopilot/AutoPilotActionEvent.java b/src/main/java/jcs/commandStation/autopilot/AutoPilotActionEvent.java new file mode 100644 index 00000000..9360dd09 --- /dev/null +++ b/src/main/java/jcs/commandStation/autopilot/AutoPilotActionEvent.java @@ -0,0 +1,46 @@ +/* + * Copyright 2025 fransjacobs. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package jcs.commandStation.autopilot; + +import jcs.entities.LocomotiveBean; + +/** + * + * @author fransjacobs + */ +public class AutoPilotActionEvent { + + private final String actionCommand; + private final LocomotiveBean locomotiveBean; + + AutoPilotActionEvent(String actionCommand) { + this(actionCommand, null); + } + + AutoPilotActionEvent(String actionCommand, LocomotiveBean locomotiveBean) { + this.actionCommand = actionCommand; + this.locomotiveBean = locomotiveBean; + } + + String getActionCommand() { + return actionCommand; + } + + LocomotiveBean getLocomotiveBean() { + return locomotiveBean; + } + +} diff --git a/src/main/java/jcs/commandStation/autopilot/DriveSimulator.java b/src/main/java/jcs/commandStation/autopilot/DriveSimulator.java index c9e2a371..c55b839d 100644 --- a/src/main/java/jcs/commandStation/autopilot/DriveSimulator.java +++ b/src/main/java/jcs/commandStation/autopilot/DriveSimulator.java @@ -16,14 +16,11 @@ package jcs.commandStation.autopilot; import java.util.List; -import java.util.concurrent.Callable; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.ScheduledThreadPoolExecutor; import java.util.concurrent.TimeUnit; import jcs.JCS; -import jcs.commandStation.AccessoryController; import jcs.commandStation.FeedbackController; -import jcs.commandStation.GenericController; import jcs.commandStation.autopilot.state.Dispatcher; import jcs.commandStation.events.SensorEvent; import jcs.entities.LocomotiveBean; diff --git a/src/main/java/jcs/commandStation/autopilot/state/Dispatcher.java b/src/main/java/jcs/commandStation/autopilot/state/Dispatcher.java index b9f9f44a..647430fd 100644 --- a/src/main/java/jcs/commandStation/autopilot/state/Dispatcher.java +++ b/src/main/java/jcs/commandStation/autopilot/state/Dispatcher.java @@ -33,24 +33,23 @@ import jcs.entities.TileBean; import jcs.persistence.PersistenceFactory; import jcs.ui.layout.tiles.TileCache; -import jcs.ui.layout.events.TileEvent; import jcs.ui.layout.tiles.Tile; import org.tinylog.Logger; /** * The Dispatcher is the controlling class during auto mode of one Locomotive
- * When a Locomotive runs a separate stateMachineThread is started which handles all the states.
+ * When a Locomotive runs a separate stateMachine is started which handles all the states.
* */ public class Dispatcher { - + private final LocomotiveBean locomotiveBean; - + private RouteBean routeBean; - + private String departureBlockId; private String destinationBlockId; - + private String waitingForSensorId; //Enter Sensor of the destination private String enterSensorId; @@ -61,42 +60,42 @@ public class Dispatcher { private String occupationSensorId; //The exit of the departure private String exitSensorId; - + private final List stateEventListeners; - + private final ThreadGroup parent; - - private StateMachineThread stateMachineThread; - + + private StateMachine stateMachine; + public Dispatcher(ThreadGroup parent, LocomotiveBean locomotiveBean) { this.parent = parent; this.locomotiveBean = locomotiveBean; //Prefill with the current locomotive direction this.locomotiveBean.setDispatcherDirection(locomotiveBean.getDirection()); this.stateEventListeners = new LinkedList<>(); - this.stateMachineThread = new StateMachineThread(parent, this); + this.stateMachine = new StateMachine(parent, this); } - - StateMachineThread getStateMachineThread() { - return stateMachineThread; + + StateMachine getStateMachine() { + return stateMachine; } - + public Long getId() { return this.locomotiveBean.getId(); } - + public String getName() { return this.locomotiveBean.getName(); } - + public LocomotiveBean getLocomotiveBean() { return locomotiveBean; } - + RouteBean getRouteBean() { return routeBean; } - + void setRouteBean(RouteBean routeBean) { this.routeBean = routeBean; if (routeBean == null) { @@ -107,54 +106,54 @@ void setRouteBean(RouteBean routeBean) { this.destinationBlockId = routeBean.getToTileId(); } } - + public boolean isLocomotiveAutomodeOn() { - return this.stateMachineThread.isEnableAutomode(); + return stateMachine.isAutomodeEnabled(); } - + public boolean startLocomotiveAutomode() { //Only when the Autopilot is ON! if (AutoPilot.isAutoModeActive()) { - stateMachineThread.setEnableAutomode(true); + stateMachine.setEnableAutomode(true); //is the thread running? startRunning(); } - return this.stateMachineThread.isEnableAutomode(); + return this.stateMachine.isAutomodeEnabled(); } - + public void stopLocomotiveAutomode() { - stateMachineThread.setEnableAutomode(false); + stateMachine.setEnableAutomode(false); } - + void startRunning() { - if (this.stateMachineThread != null && this.stateMachineThread.isThreadRunning()) { + if (this.stateMachine != null && this.stateMachine.isThreadRunning()) { return; } - - if (this.stateMachineThread == null || !this.stateMachineThread.isAlive()) { - stateMachineThread = new StateMachineThread(this.parent, this); + + if (this.stateMachine == null || !this.stateMachine.isAlive()) { + stateMachine = new StateMachine(this.parent, this); } - - this.stateMachineThread.setEnableAutomode(true); - if (!this.stateMachineThread.isThreadRunning()) { - this.stateMachineThread.start(); + + this.stateMachine.setEnableAutomode(true); + if (!this.stateMachine.isThreadRunning()) { + this.stateMachine.start(); } } - + public void stopRunning() { - if (stateMachineThread != null && stateMachineThread.isThreadRunning()) { - stateMachineThread.stopRunningThread(); - + if (stateMachine != null && stateMachine.isThreadRunning()) { + stateMachine.stopRunningThread(); + try { Logger.trace(this.getName() + " Thread Joining..."); - stateMachineThread.join(); + stateMachine.join(); } catch (InterruptedException ex) { Logger.trace("Join error " + ex); } Logger.trace(this.getName() + " Thread Joined!"); } } - + void resetDispatcher() { this.routeBean = null; this.departureBlockId = null; @@ -166,16 +165,16 @@ void resetDispatcher() { this.stateEventListeners.clear(); this.locomotiveBean.setDispatcherDirection(Direction.SWITCH); } - + public void reset() { Logger.trace("Resetting dispatcher " + getName() + " StateMachine..."); - this.stateMachineThread.reset(); + this.stateMachine.reset(); resetDispatcher(); } - + public boolean isRunning() { - if (stateMachineThread != null) { - return stateMachineThread.isThreadRunning(); + if (stateMachine != null) { + return stateMachine.isThreadRunning(); } else { return false; } @@ -194,7 +193,7 @@ BlockBean getDepartureBlock() { return departureBlock; } } - + BlockBean getDestinationBlock() { if (destinationBlockId != null) { return PersistenceFactory.getService().getBlockByTileId(destinationBlockId); @@ -205,55 +204,55 @@ BlockBean getDestinationBlock() { return null; } } - + public String getStateName() { - if (stateMachineThread != null) { - return stateMachineThread.getDispatcherStateName(); + if (stateMachine != null) { + return stateMachine.getDispatcherStateName(); } else { return "#Idle"; } } - + void setWaitForSensorid(String sensorId) { this.waitingForSensorId = sensorId; } - + public String getWaitingForSensorId() { return waitingForSensorId; } - + public String getEnterSensorId() { return enterSensorId; } - + void setEnterSensorId(String enterSensorId) { this.enterSensorId = enterSensorId; } - + public String getInSensorId() { return inSensorId; } - + void setInSensorId(String inSensorId) { this.inSensorId = inSensorId; } - + public String getOccupationSensorId() { return occupationSensorId; } - + void setOccupationSensorId(String occupationSensorId) { this.occupationSensorId = occupationSensorId; } - + public String getExitSensorId() { return exitSensorId; } - + void setExitSensorId(String exitSensorId) { this.exitSensorId = exitSensorId; } - + void clearDepartureIgnoreEventHandlers() { if (departureBlockId != null) { BlockBean departureBlock = getDepartureBlock(); @@ -263,7 +262,7 @@ void clearDepartureIgnoreEventHandlers() { AutoPilot.removeHandler(plusSensorId); } } - + public void onIgnoreEvent(SensorEvent event) { //Only in Simulator mode if (JCS.getJcsCommandStation().getCommandStationBean().isVirtual()) { @@ -272,19 +271,19 @@ public void onIgnoreEvent(SensorEvent event) { this.waitingForSensorId = null; } } - + if (this.enterSensorId != null && this.enterSensorId.equals(event.getId())) { if (!event.isActive()) { this.enterSensorId = null; } } - + if (this.inSensorId != null && this.inSensorId.equals(event.getId())) { if (!event.isActive()) { this.inSensorId = null; } } - + if (this.exitSensorId != null && this.exitSensorId.equals(event.getId())) { if (!event.isActive()) { this.exitSensorId = null; @@ -293,35 +292,39 @@ public void onIgnoreEvent(SensorEvent event) { } //Logger.trace("Event for a ignored listener: " + event.getId() + " Changed: " + event.isChanged() + ", active: " + event.getSensorBean().isActive()); } - + synchronized void switchAccessory(AccessoryBean accessory, AccessoryValue value) { JCS.getJcsCommandStation().switchAccessory(accessory, value); } - + synchronized void changeLocomotiveVelocity(LocomotiveBean locomotive, int velocity) { JCS.getJcsCommandStation().changeLocomotiveSpeed(velocity, locomotive); locomotiveBean.setVelocity(velocity); } - + synchronized void changeLocomotiveDirection(LocomotiveBean locomotive, Direction newDirection) { JCS.getJcsCommandStation().changeLocomotiveDirection(newDirection, locomotive); locomotiveBean.setDirection(newDirection); } - - void fireStateListeners(String s) { + + public void fireStateListeners(String s) { for (StateEventListener sel : stateEventListeners) { sel.onStateChange(this); } } - + public void addStateEventListener(StateEventListener listener) { stateEventListeners.add(listener); } - + public void removeStateEventListener(StateEventListener listener) { stateEventListeners.remove(listener); } - + + public void removeAllStateEventListeners() { + stateEventListeners.clear(); + } + public static void resetRoute(RouteBean route) { List routeElements = route.getRouteElements(); for (RouteElementBean re : routeElements) { @@ -344,26 +347,27 @@ public static void resetRoute(RouteBean route) { } } } - + void showBlockState(BlockBean blockBean) { - Logger.trace("Show block " + blockBean); Tile tile = TileCache.findTile(blockBean.getTileId()); - tile.setBlockBean(blockBean); + if (tile != null) { + tile.setBlockBean(blockBean); + } } - + void showRoute(RouteBean routeBean, Color routeColor) { Logger.trace("Show route " + routeBean.toLogString()); List routeElements = routeBean.getRouteElements(); - + for (RouteElementBean re : routeElements) { String tileId = re.getTileId(); Tile tile = TileCache.findTile(tileId); if (tile != null) { TileBean.Orientation incomingSide = re.getIncomingOrientation(); - + tile.setIncomingSide(incomingSide); tile.setTrackRouteColor(Tile.DEFAULT_ROUTE_TRACK_COLOR); - + if (re.isTurnout()) { AccessoryBean.AccessoryValue routeState = re.getAccessoryValue(); tile.setRouteValue(routeState); @@ -381,19 +385,19 @@ void showRoute(RouteBean routeBean, Color routeColor) { } } } - + int getRandomNumber(int min, int max) { Random random = new Random(); return random.ints(min, max).findFirst().getAsInt(); } - + @Override public int hashCode() { int hash = 7; hash = 37 * hash + Objects.hashCode(locomotiveBean.getId()); return hash; } - + @Override public boolean equals(Object obj) { if (this == obj) { diff --git a/src/main/java/jcs/commandStation/autopilot/state/IdleState.java b/src/main/java/jcs/commandStation/autopilot/state/IdleState.java index 01988258..4ec46479 100644 --- a/src/main/java/jcs/commandStation/autopilot/state/IdleState.java +++ b/src/main/java/jcs/commandStation/autopilot/state/IdleState.java @@ -60,8 +60,10 @@ DispatcherState execute(Dispatcher dispatcher) { Logger.trace("Interrupted: " + ex.getMessage()); } } else { - //Automode is switched off for this Dispatcher so the Idle state must end... + //Locomotive is stopped... Logger.trace(dispatcher.getName() + " Automode: " + AutoPilot.isAutoModeActive() + " Dispacher " + dispatcher.isLocomotiveAutomodeOn()); + + //stop this thread... try { synchronized (this) { wait(10000); diff --git a/src/main/java/jcs/commandStation/autopilot/state/StateMachineThread.java b/src/main/java/jcs/commandStation/autopilot/state/StateMachine.java similarity index 92% rename from src/main/java/jcs/commandStation/autopilot/state/StateMachineThread.java rename to src/main/java/jcs/commandStation/autopilot/state/StateMachine.java index a15defc5..2c3aeb39 100644 --- a/src/main/java/jcs/commandStation/autopilot/state/StateMachineThread.java +++ b/src/main/java/jcs/commandStation/autopilot/state/StateMachine.java @@ -41,33 +41,33 @@ * * @author frans */ -class StateMachineThread extends Thread { - +class StateMachine extends Thread { + private final Dispatcher dispatcher; private DispatcherState dispatcherState; - + private boolean running = false; - + private boolean enableAutomode = false; private boolean resetRequested = false; - - StateMachineThread(ThreadGroup parent, Dispatcher dispatcher) { - super(parent, "STM->" + dispatcher.getLocomotiveBean().getName()); + + StateMachine(ThreadGroup parent, Dispatcher dispatcher) { + super(parent, "STM->" + dispatcher.getLocomotiveBean().getName().toUpperCase()); this.dispatcher = dispatcher; this.dispatcherState = new IdleState(); } - + boolean isThreadRunning() { return this.running; } - + synchronized void stopRunningThread() { this.running = false; this.enableAutomode = false; notifyAll(); } - - boolean isEnableAutomode() { + + boolean isAutomodeEnabled() { return this.enableAutomode; } @@ -82,46 +82,56 @@ synchronized void reset() { //Switch of running this.enableAutomode = false; this.resetRequested = true; - + Logger.trace("Reset requested..."); if (running) { notifyAll(); } } - + DispatcherState getDispatcherState() { return dispatcherState; } - + String getDispatcherStateName() { return dispatcherState.getName(); } - + void handleState() { //Obtain current dispatcherState DispatcherState previousState = dispatcherState; //Execute the action for the current dispatcherState dispatcherState = dispatcherState.execute(dispatcher); - + if ("true".equals(System.getProperty("state.machine.stepTest", "false"))) { Logger.debug("Current State: " + dispatcherState.getName() + " Previous State: " + previousState.getName()); } - + if (!AutoPilot.isAutoModeActive()) { //Automode has stopped, let the Thread finish when WaitState is reached or is Idle if (dispatcherState instanceof IdleState || dispatcherState instanceof WaitState) { Logger.trace(getName() + " Stopping thread as Autopilot automode is stopped"); this.running = false; //Just stop - synchronized(this) { + synchronized (this) { + this.notifyAll(); + } + } + } + + if (!dispatcher.isLocomotiveAutomodeOn()) { + if (dispatcherState instanceof IdleState) { + Logger.trace(getName() + " Stopping thread as Locomotive " + dispatcher.getName() + " has stopped..."); + this.running = false; + synchronized (this) { this.notifyAll(); } } } - + if (previousState != dispatcherState || dispatcherState instanceof WaitState) { //handle the dispatcherState changes - Logger.trace("Fire for "+dispatcherState.getName()); + Logger.trace("Fire for " + dispatcherState.getName()); dispatcher.fireStateListeners(dispatcherState.getName()); } @@ -145,7 +155,7 @@ void resetStateMachine() { Logger.trace("Removing " + sensorEventListener.toString() + " as Sensor Listener..."); JCS.getJcsCommandStation().removeSensorEventListener(sensorEventListener); } - + dispatcher.clearDepartureIgnoreEventHandlers(); //Restore the Departure block state @@ -158,7 +168,7 @@ void resetStateMachine() { destinationBlock.setLocomotive(null); destinationBlock.setArrivalSuffix(null); destinationBlock.setReverseArrival(false); - + PersistenceFactory.getService().persist(departureBlock); PersistenceFactory.getService().persist(destinationBlock); @@ -166,15 +176,15 @@ void resetStateMachine() { RouteBean route = dispatcher.getRouteBean(); route.setLocked(false); Dispatcher.resetRoute(route); - + PersistenceFactory.getService().persist(route); dispatcher.setRouteBean(null); - + dispatcher.showBlockState(departureBlock); dispatcher.showBlockState(destinationBlock); - + dispatcherState = new IdleState(); - + this.resetRequested = false; } @@ -200,7 +210,7 @@ public void run() { this.running = true; Logger.trace(getName() + " Started. State " + dispatcherState.getName() + "..."); } - + while (running) { if (resetRequested) { resetStateMachine(); @@ -208,7 +218,7 @@ public void run() { handleState(); } } - + Logger.trace(getName() + " in state " + dispatcherState.getClass().getSimpleName() + " is ending..."); //Make sure that also the linked locomotive is stopped @@ -223,19 +233,14 @@ public void run() { } else { Logger.trace("No sensor listeners are registered..."); } - + dispatcher.clearDepartureIgnoreEventHandlers(); Logger.trace("Ignore Handlers removed..."); - + dispatcher.fireStateListeners(getName() + " Finished"); Logger.trace(getName() + " State listeners fired..."); - + Logger.trace(getName() + " last state " + dispatcherState.getClass().getSimpleName() + " is Finished"); } - -// synchronized void sensorUpdated(final SensorEvent sensorEvent) { -// Logger.trace("Sensor " + sensorEvent.getId() + " Value " + (sensorEvent.isActive() ? "On" : "Off")); -// this.notifyAll(); -// } - + } diff --git a/src/main/java/jcs/commandStation/esu/ecos/FeedbackManager.java b/src/main/java/jcs/commandStation/esu/ecos/FeedbackManager.java index 87c97142..d55e6f72 100644 --- a/src/main/java/jcs/commandStation/esu/ecos/FeedbackManager.java +++ b/src/main/java/jcs/commandStation/esu/ecos/FeedbackManager.java @@ -42,7 +42,6 @@ class FeedbackManager { } private List parse(EcosMessage message) { - Logger.trace(message.getMessage()); Logger.trace(message.getResponse()); List changedSensors; diff --git a/src/main/java/jcs/ui/DispatcherStatusPanel.java b/src/main/java/jcs/ui/DispatcherStatusPanel.java index 8495ad73..d9f52bc7 100644 --- a/src/main/java/jcs/ui/DispatcherStatusPanel.java +++ b/src/main/java/jcs/ui/DispatcherStatusPanel.java @@ -30,7 +30,19 @@ public class DispatcherStatusPanel extends JPanel implements RefreshEventListene public DispatcherStatusPanel() { initComponents(); } - + + public void showDispatcherTab() { + this.tabsPane.setSelectedIndex(1); + } + + public void showLocomotiveTab() { + this.tabsPane.setSelectedIndex(0); + } + + public void refresh() { + this.locomotiveTablePanel.refresh(); + } + @Override public void onChange(RefreshEvent event) { this.locomotiveTablePanel.onChange(event); diff --git a/src/main/java/jcs/ui/JCSFrame.form b/src/main/java/jcs/ui/JCSFrame.form index 4da3c4b3..6ab04d2b 100755 --- a/src/main/java/jcs/ui/JCSFrame.form +++ b/src/main/java/jcs/ui/JCSFrame.form @@ -409,7 +409,7 @@ - + @@ -480,7 +480,7 @@ - + @@ -583,7 +583,7 @@ - + @@ -616,12 +616,12 @@ - + - + - + @@ -629,7 +629,9 @@ - + + + @@ -642,25 +644,39 @@ - + - - - - + + + + + + + + + + + + + + + + + + - + - + @@ -689,7 +705,7 @@ - + @@ -700,35 +716,12 @@ - + - - - - - - - - - - - - - - - - - - - - - - -
diff --git a/src/main/java/jcs/ui/JCSFrame.java b/src/main/java/jcs/ui/JCSFrame.java index 4988a9c7..bb8db46f 100755 --- a/src/main/java/jcs/ui/JCSFrame.java +++ b/src/main/java/jcs/ui/JCSFrame.java @@ -244,7 +244,7 @@ private void setControllerProperties() { } private void showSensorMonitor() { - if (this.feedbackMonitor == null) { + if (feedbackMonitor == null) { Logger.trace("Creating a Monitor UI"); feedbackMonitor = new FeedbackMonitor(); FrameMonitor.registerFrame(feedbackMonitor, FeedbackMonitor.class.getName()); @@ -277,10 +277,10 @@ private void initComponents() { showFeedbackMonitorBtn = new JButton(); filler8 = new Box.Filler(new Dimension(20, 0), new Dimension(20, 0), new Dimension(20, 32767)); autoPilotBtn = new JToggleButton(); - startAllLocomotivesBtn = new JToggleButton(); - resetAutoPilotBtn = new JButton(); + startAllLocsBtn = new JButton(); filler9 = new Box.Filler(new Dimension(20, 0), new Dimension(20, 0), new Dimension(20, 32767)); - showSettingsBtn = new JButton(); + resetAutoPilotBtn = new JButton(); + filler10 = new Box.Filler(new Dimension(20, 0), new Dimension(20, 0), new Dimension(20, 32767)); statusPanel = new StatusPanel(); mainPanel = new JPanel(); locoDisplaySP = new JSplitPane(); @@ -436,7 +436,7 @@ public void actionPerformed(ActionEvent evt) { jcsToolBar.add(filler4); showEditDesignBtn.setIcon(new ImageIcon(getClass().getResource("/media/paintbrush-24.png"))); // NOI18N - showEditDesignBtn.setToolTipText("Design Layout"); + showEditDesignBtn.setToolTipText("Edit Layout"); showEditDesignBtn.setBorder(BorderFactory.createLineBorder(new Color(204, 204, 204))); showEditDesignBtn.setFocusable(false); showEditDesignBtn.setHorizontalTextPosition(SwingConstants.CENTER); @@ -473,7 +473,7 @@ public void actionPerformed(ActionEvent evt) { jcsToolBar.add(showVNCBtn); showKeyboardBtn.setIcon(new ImageIcon(getClass().getResource("/media/controller-24.png"))); // NOI18N - showKeyboardBtn.setToolTipText("Diagnostics"); + showKeyboardBtn.setToolTipText("Show Accessory Keyboard"); showKeyboardBtn.setBorder(BorderFactory.createLineBorder(new Color(204, 204, 204))); showKeyboardBtn.setDoubleBuffered(true); showKeyboardBtn.setFocusable(false); @@ -516,7 +516,7 @@ public void actionPerformed(ActionEvent evt) { jcsToolBar.add(filler8); autoPilotBtn.setIcon(new ImageIcon(getClass().getResource("/media/pilot.png"))); // NOI18N - autoPilotBtn.setToolTipText("Connect/Disconnect with Central Station"); + autoPilotBtn.setToolTipText("En- or Disable automatic driving"); autoPilotBtn.setBorder(BorderFactory.createLineBorder(new Color(204, 204, 204))); autoPilotBtn.setDoubleBuffered(true); autoPilotBtn.setFocusable(false); @@ -535,29 +535,31 @@ public void actionPerformed(ActionEvent evt) { }); jcsToolBar.add(autoPilotBtn); - startAllLocomotivesBtn.setIcon(new ImageIcon(getClass().getResource("/media/cruise-control-on-black.png"))); // NOI18N - startAllLocomotivesBtn.setToolTipText("Connect/Disconnect with Central Station"); - startAllLocomotivesBtn.setBorder(BorderFactory.createLineBorder(new Color(204, 204, 204))); - startAllLocomotivesBtn.setDoubleBuffered(true); - startAllLocomotivesBtn.setEnabled(false); - startAllLocomotivesBtn.setFocusable(false); - startAllLocomotivesBtn.setHorizontalTextPosition(SwingConstants.CENTER); - startAllLocomotivesBtn.setMargin(new Insets(0, 0, 0, 0)); - startAllLocomotivesBtn.setMaximumSize(new Dimension(40, 40)); - startAllLocomotivesBtn.setMinimumSize(new Dimension(40, 40)); - startAllLocomotivesBtn.setName("startAllLocomotivesBtn"); // NOI18N - startAllLocomotivesBtn.setPreferredSize(new Dimension(40, 40)); - startAllLocomotivesBtn.setSelectedIcon(new ImageIcon(getClass().getResource("/media/cruise-control-on-green.png"))); // NOI18N - startAllLocomotivesBtn.setVerticalTextPosition(SwingConstants.BOTTOM); - startAllLocomotivesBtn.addActionListener(new ActionListener() { + startAllLocsBtn.setIcon(new ImageIcon(getClass().getResource("/media/arrowhead-right-gn.png"))); // NOI18N + startAllLocsBtn.setToolTipText("Start all Locomotives"); + startAllLocsBtn.setBorder(BorderFactory.createLineBorder(new Color(204, 204, 204))); + startAllLocsBtn.setDisabledIcon(new ImageIcon(getClass().getResource("/media/pause-gr.png"))); // NOI18N + startAllLocsBtn.setEnabled(false); + startAllLocsBtn.setFocusable(false); + startAllLocsBtn.setHorizontalTextPosition(SwingConstants.CENTER); + startAllLocsBtn.setMargin(new Insets(0, 0, 0, 0)); + startAllLocsBtn.setMaximumSize(new Dimension(40, 40)); + startAllLocsBtn.setMinimumSize(new Dimension(40, 40)); + startAllLocsBtn.setName("startAllLocsBtn"); // NOI18N + startAllLocsBtn.setPreferredSize(new Dimension(40, 40)); + startAllLocsBtn.setVerticalTextPosition(SwingConstants.BOTTOM); + startAllLocsBtn.addActionListener(new ActionListener() { public void actionPerformed(ActionEvent evt) { - startAllLocomotivesBtnActionPerformed(evt); + startAllLocsBtnActionPerformed(evt); } }); - jcsToolBar.add(startAllLocomotivesBtn); + jcsToolBar.add(startAllLocsBtn); + + filler9.setName("filler9"); // NOI18N + jcsToolBar.add(filler9); - resetAutoPilotBtn.setIcon(new ImageIcon(getClass().getResource("/media/director-red.png"))); // NOI18N - resetAutoPilotBtn.setToolTipText("Design Layout"); + resetAutoPilotBtn.setIcon(new ImageIcon(getClass().getResource("/media/reset-happy.png"))); // NOI18N + resetAutoPilotBtn.setToolTipText("Stop and Reset AutoPilot"); resetAutoPilotBtn.setBorder(BorderFactory.createLineBorder(new Color(204, 204, 204))); resetAutoPilotBtn.setFocusable(false); resetAutoPilotBtn.setHorizontalTextPosition(SwingConstants.CENTER); @@ -574,23 +576,8 @@ public void actionPerformed(ActionEvent evt) { }); jcsToolBar.add(resetAutoPilotBtn); - filler9.setName("filler9"); // NOI18N - jcsToolBar.add(filler9); - - showSettingsBtn.setIcon(new ImageIcon(getClass().getResource("/media/load-24.png"))); // NOI18N - showSettingsBtn.setFocusable(false); - showSettingsBtn.setHorizontalTextPosition(SwingConstants.CENTER); - showSettingsBtn.setMaximumSize(new Dimension(40, 40)); - showSettingsBtn.setMinimumSize(new Dimension(40, 40)); - showSettingsBtn.setName("showSettingsBtn"); // NOI18N - showSettingsBtn.setPreferredSize(new Dimension(40, 40)); - showSettingsBtn.setVerticalTextPosition(SwingConstants.BOTTOM); - showSettingsBtn.addActionListener(new ActionListener() { - public void actionPerformed(ActionEvent evt) { - showSettingsBtnActionPerformed(evt); - } - }); - jcsToolBar.add(showSettingsBtn); + filler10.setName("filler10"); // NOI18N + jcsToolBar.add(filler10); toolbarPanel.add(jcsToolBar); @@ -873,13 +860,13 @@ private void showKeyboardBtnActionPerformed(ActionEvent evt) {//GEN-FIRST:event_ }//GEN-LAST:event_showKeyboardBtnActionPerformed private void quitMIActionPerformed(ActionEvent evt) {//GEN-FIRST:event_quitMIActionPerformed - this.dispatchEvent(new WindowEvent(this, WindowEvent.WINDOW_CLOSING)); + dispatchEvent(new WindowEvent(this, WindowEvent.WINDOW_CLOSING)); }//GEN-LAST:event_quitMIActionPerformed private void formWindowClosing(WindowEvent evt) {//GEN-FIRST:event_formWindowClosing boolean closed = this.handleQuitRequest(); if (closed) { - this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); setVisible(false); dispose(); @@ -903,7 +890,7 @@ private void showEditDesignBtnActionPerformed(ActionEvent evt) {//GEN-FIRST:even private void showOverviewBtnActionPerformed(ActionEvent evt) {//GEN-FIRST:event_showOverviewBtnActionPerformed showOverviewPanel(); - this.overviewPanel.loadLayout(); + overviewPanel.loadLayout(); }//GEN-LAST:event_showOverviewBtnActionPerformed private void powerButtonActionPerformed(ActionEvent evt) {//GEN-FIRST:event_powerButtonActionPerformed @@ -994,10 +981,6 @@ private void commandStationsMIActionPerformed(ActionEvent evt) {//GEN-FIRST:even csd.setVisible(true); }//GEN-LAST:event_commandStationsMIActionPerformed - private void showSettingsBtnActionPerformed(ActionEvent evt) {//GEN-FIRST:event_showSettingsBtnActionPerformed - showSettings(); - }//GEN-LAST:event_showSettingsBtnActionPerformed - private void aboutMIActionPerformed(ActionEvent evt) {//GEN-FIRST:event_aboutMIActionPerformed Logger.trace(evt.getActionCommand()); AboutDialog dialog = new AboutDialog(this, true); @@ -1012,31 +995,22 @@ private void showVNCBtnActionPerformed(ActionEvent evt) {//GEN-FIRST:event_showV }//GEN-LAST:event_showVNCBtnActionPerformed private void autoPilotBtnActionPerformed(ActionEvent evt) {//GEN-FIRST:event_autoPilotBtnActionPerformed - Logger.trace(evt.getActionCommand() + (this.autoPilotBtn.isSelected() ? " Enable" : " Disable") + " Auto mode"); + //Logger.trace(evt.getActionCommand() + (autoPilotBtn.isSelected() ? " Enable" : " Disable") + " Auto mode"); - if (this.autoPilotBtn.isSelected()) { - this.startAllLocomotivesBtn.setEnabled(true); + if (autoPilotBtn.isSelected()) { + startAllLocsBtn.setEnabled(true); + dispatcherStatusPanel.showDispatcherTab(); + // startAllLocsBtn.setIcon(new ImageIcon(getClass().getResource("/media/arrowhead-right-gn.png"))); } else { - if (this.startAllLocomotivesBtn.isSelected()) { - startAllLocomotivesBtn.doClick(); - } - this.startAllLocomotivesBtn.setEnabled(false); + startAllLocsBtn.setEnabled(false); + dispatcherStatusPanel.showLocomotiveTab(); } - AutoPilot.runAutoPilot(this.autoPilotBtn.isSelected()); + AutoPilot.runAutoPilot(autoPilotBtn.isSelected()); }//GEN-LAST:event_autoPilotBtnActionPerformed - private void startAllLocomotivesBtnActionPerformed(ActionEvent evt) {//GEN-FIRST:event_startAllLocomotivesBtnActionPerformed - Logger.trace(evt.getActionCommand() + " Start All Locomotives " + this.startAllLocomotivesBtn.isSelected()); - if (this.startAllLocomotivesBtn.isSelected()) { - AutoPilot.startAllLocomotives(); - } else { - AutoPilot.stopAllLocomotives(); - } - }//GEN-LAST:event_startAllLocomotivesBtnActionPerformed - private void resetAutoPilotBtnActionPerformed(ActionEvent evt) {//GEN-FIRST:event_resetAutoPilotBtnActionPerformed - AutoPilot.resetStates(); + AutoPilot.reset(); }//GEN-LAST:event_resetAutoPilotBtnActionPerformed private void virtualCBActionPerformed(ActionEvent evt) {//GEN-FIRST:event_virtualCBActionPerformed @@ -1046,6 +1020,13 @@ private void virtualCBActionPerformed(ActionEvent evt) {//GEN-FIRST:event_virtua } }//GEN-LAST:event_virtualCBActionPerformed + private void startAllLocsBtnActionPerformed(ActionEvent evt) {//GEN-FIRST:event_startAllLocsBtnActionPerformed + int result = JOptionPane.showConfirmDialog(this, "Are you sure you want to start All Locomotives?", "Start ALL Locomotives", JOptionPane.YES_NO_OPTION); + if (result == JOptionPane.YES_OPTION) { + AutoPilot.startAllLocomotives(); + } + }//GEN-LAST:event_startAllLocsBtnActionPerformed + private String getTitleString() { String jcsVersion = VersionInfo.getVersion(); @@ -1128,6 +1109,7 @@ public void powerChanged(PowerEvent event) { private JMenuItem editLayout; private JMenu fileMenu; private Box.Filler filler1; + private Box.Filler filler10; private Box.Filler filler2; private Box.Filler filler3; private Box.Filler filler4; @@ -1162,9 +1144,8 @@ public void powerChanged(PowerEvent event) { private JMenuItem showLocosMI; private JButton showOverviewBtn; private JMenuItem showSensorMonitor; - private JButton showSettingsBtn; private JButton showVNCBtn; - private JToggleButton startAllLocomotivesBtn; + private JButton startAllLocsBtn; private StatusPanel statusPanel; private JPanel toolbarPanel; private JMenu toolsMenu; diff --git a/src/main/java/jcs/ui/layout/LayoutCanvas.java b/src/main/java/jcs/ui/layout/LayoutCanvas.java index 8e3672ef..34b3ad87 100755 --- a/src/main/java/jcs/ui/layout/LayoutCanvas.java +++ b/src/main/java/jcs/ui/layout/LayoutCanvas.java @@ -955,18 +955,18 @@ private void formMouseDragged(MouseEvent evt) {//GEN-FIRST:event_formMouseDragge }//GEN-LAST:event_formMouseDragged private void startLocomotiveMIActionPerformed(ActionEvent evt) {//GEN-FIRST:event_startLocomotiveMIActionPerformed - if (this.selectedTile != null) { - Block block = (Block) selectedTile; - LocomotiveBean locomotive = block.getLocomotive(); - executor.execute(() -> AutoPilot.startStopLocomotive(locomotive, true)); + if (selectedTile != null && selectedTile.isBlock() && selectedTile.getLocomotive() != null) { + LocomotiveBean locomotive = selectedTile.getLocomotive(); + //executor.execute(() -> AutoPilot.startStopLocomotive(locomotive, true)); + AutoPilot.startLocomotive(locomotive); } }//GEN-LAST:event_startLocomotiveMIActionPerformed private void stopLocomotiveMIActionPerformed(ActionEvent evt) {//GEN-FIRST:event_stopLocomotiveMIActionPerformed - if (selectedTile != null) { - Block block = (Block) selectedTile; - LocomotiveBean locomotive = block.getLocomotive(); - executor.execute(() -> AutoPilot.startStopLocomotive(locomotive, false)); + if (selectedTile != null && selectedTile.isBlock() && selectedTile.getLocomotive() != null) { + LocomotiveBean locomotive = selectedTile.getLocomotive(); + //executor.execute(() -> AutoPilot.startStopLocomotive(locomotive, false)); + AutoPilot.stopLocomotive(locomotive); } }//GEN-LAST:event_stopLocomotiveMIActionPerformed @@ -983,27 +983,28 @@ private void resetDispatcherMIActionPerformed(ActionEvent evt) {//GEN-FIRST:even }//GEN-LAST:event_resetDispatcherMIActionPerformed private void removeLocMIActionPerformed(ActionEvent evt) {//GEN-FIRST:event_removeLocMIActionPerformed - if (selectedTile != null) { - Block block = (Block) selectedTile; - LocomotiveBean locomotive = block.getLocomotive(); + if (selectedTile != null && selectedTile.isBlock()) { + LocomotiveBean locomotive = selectedTile.getLocomotive(); locomotive.setDispatcherDirection(null); - - block.setLocomotive(null); - + + selectedTile.setLocomotive(null); + executor.execute(() -> { - PersistenceFactory.getService().persist(block.getBlockBean()); + PersistenceFactory.getService().persist(selectedTile.getBlockBean()); PersistenceFactory.getService().persist(locomotive); + + AutoPilot.removeLocomotive(locomotive); }); } }//GEN-LAST:event_removeLocMIActionPerformed private void blockPropertiesMIActionPerformed(ActionEvent evt) {//GEN-FIRST:event_blockPropertiesMIActionPerformed - if (this.selectedTile != null) { + if (selectedTile != null && selectedTile.isBlock()) { //show the Block control dialog so tha a locomotive can be assigned to the block - Block block = (Block) selectedTile; - BlockControlDialog bcd = new BlockControlDialog(getParentFrame(), block); + BlockControlDialog bcd = new BlockControlDialog(getParentFrame(), (Block) selectedTile); bcd.setVisible(true); - repaint(block.getTileBounds()); + + repaint(selectedTile.getTileBounds()); } }//GEN-LAST:event_blockPropertiesMIActionPerformed diff --git a/src/main/java/jcs/ui/layout/LayoutPanel.java b/src/main/java/jcs/ui/layout/LayoutPanel.java index 20ae29ef..9917b52c 100755 --- a/src/main/java/jcs/ui/layout/LayoutPanel.java +++ b/src/main/java/jcs/ui/layout/LayoutPanel.java @@ -18,7 +18,6 @@ import java.awt.BorderLayout; import java.awt.Dimension; import java.awt.FlowLayout; -import java.awt.Insets; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.ComponentAdapter; @@ -848,7 +847,7 @@ private void sensorBtnActionPerformed(ActionEvent evt) {//GEN-FIRST:event_sensor }//GEN-LAST:event_sensorBtnActionPerformed private void gridBtnActionPerformed(ActionEvent evt) {//GEN-FIRST:event_gridBtnActionPerformed - this.canvas.setDrawGrid(this.gridBtn.isSelected()); + this.canvas.setDrawGrid(this.gridBtn.isSelected()); }//GEN-LAST:event_gridBtnActionPerformed private void formComponentResized(ComponentEvent evt) {//GEN-FIRST:event_formComponentResized @@ -897,27 +896,24 @@ private void endTrackBtnActionPerformed(ActionEvent evt) {//GEN-FIRST:event_endT }//GEN-LAST:event_endTrackBtnActionPerformed private void autoPilotBtnActionPerformed(ActionEvent evt) {//GEN-FIRST:event_autoPilotBtnActionPerformed - Logger.trace(evt.getActionCommand() + (this.autoPilotBtn.isSelected() ? " Enable" : " Disable") + " Auto mode"); + Logger.trace(evt.getActionCommand() + (autoPilotBtn.isSelected() ? " Enable" : " Disable") + " Auto mode"); - if (this.autoPilotBtn.isSelected()) { - this.startAllLocomotivesBtn.setEnabled(true); + if (autoPilotBtn.isSelected()) { + startAllLocomotivesBtn.setEnabled(true); } else { - if (this.startAllLocomotivesBtn.isSelected()) { - startAllLocomotivesBtn.doClick(); - } - this.startAllLocomotivesBtn.setEnabled(false); + ///if (startAllLocomotivesBtn.isSelected()) { + // startAllLocomotivesBtn.doClick(); + //} + startAllLocomotivesBtn.setEnabled(false); } - AutoPilot.runAutoPilot(this.autoPilotBtn.isSelected()); - + AutoPilot.runAutoPilot(autoPilotBtn.isSelected()); }//GEN-LAST:event_autoPilotBtnActionPerformed private void startAllLocomotivesBtnActionPerformed(ActionEvent evt) {//GEN-FIRST:event_startAllLocomotivesBtnActionPerformed Logger.trace(evt.getActionCommand() + " Start All Locomotives " + this.startAllLocomotivesBtn.isSelected()); if (this.startAllLocomotivesBtn.isSelected()) { AutoPilot.startAllLocomotives(); - } else { - AutoPilot.stopAllLocomotives(); } }//GEN-LAST:event_startAllLocomotivesBtnActionPerformed @@ -926,7 +922,7 @@ private void crossingBtnActionPerformed(ActionEvent evt) {//GEN-FIRST:event_cros }//GEN-LAST:event_crossingBtnActionPerformed private void resetAutopilotBtnActionPerformed(ActionEvent evt) {//GEN-FIRST:event_resetAutopilotBtnActionPerformed - AutoPilot.resetStates(); + AutoPilot.reset(); }//GEN-LAST:event_resetAutopilotBtnActionPerformed private void setTileType(TileBean.TileType tileType) { diff --git a/src/main/java/jcs/ui/layout/dialogs/BlockControlDialog.java b/src/main/java/jcs/ui/layout/dialogs/BlockControlDialog.java index 88409cd5..1fe853fa 100644 --- a/src/main/java/jcs/ui/layout/dialogs/BlockControlDialog.java +++ b/src/main/java/jcs/ui/layout/dialogs/BlockControlDialog.java @@ -433,6 +433,8 @@ private void saveExitBtnActionPerformed(java.awt.event.ActionEvent evt) {//GEN-F if (bb.getLocomotive() != null && bb.getLocomotive().getName() != null) { LocomotiveBean loc = bb.getLocomotive(); PersistenceFactory.getService().persist(loc); + + AutoPilot.addLocomotive(loc); } TileCache.findTile(bb.getTileId()).setBlockBean(bb); @@ -448,6 +450,7 @@ private void locomotiveCBActionPerformed(java.awt.event.ActionEvent evt) {//GEN- LocomotiveBean selected = (LocomotiveBean) locomotiveComboBoxModel.getSelectedItem(); + LocomotiveBean previous = block.getLocomotive(); if (selected.getId() != null) { block.setLocomotive(selected); } else { @@ -472,12 +475,21 @@ private void locomotiveCBActionPerformed(java.awt.event.ActionEvent evt) {//GEN- } else { startLocButton.setEnabled(false); } + + if (previous != null && previous.getId() != null && !previous.getId().equals(selected.getId())) { + AutoPilot.removeLocomotive(previous); + } + }//GEN-LAST:event_locomotiveCBActionPerformed private void startLocButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_startLocButtonActionPerformed LocomotiveBean loc = block.getLocomotive(); if (loc != null) { - AutoPilot.startStopLocomotive(loc, startLocButton.isSelected()); + if (startLocButton.isSelected()) { + AutoPilot.startLocomotive(loc); + } else { + AutoPilot.stopLocomotive(loc); + } } }//GEN-LAST:event_startLocButtonActionPerformed diff --git a/src/main/java/jcs/ui/layout/events/TileEvent.java b/src/main/java/jcs/ui/layout/events/TileEvent.java deleted file mode 100644 index de3b4f1b..00000000 --- a/src/main/java/jcs/ui/layout/events/TileEvent.java +++ /dev/null @@ -1,157 +0,0 @@ -/* - * Copyright 2023 Frans Jacobs. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package jcs.ui.layout.events; - -import java.awt.Color; -import jcs.entities.AccessoryBean; -import jcs.entities.AccessoryBean.AccessoryValue; -import jcs.entities.BlockBean; -import jcs.entities.BlockBean.BlockState; -import jcs.entities.TileBean; -import jcs.entities.TileBean.Orientation; -import jcs.ui.layout.tiles.Tile; - -/** - * - * @author Frans Jacobs - */ -public class TileEvent { - - private final String tileId; - - private final Color backgroundColor; - private final Color trackColor; - private final Color trackRouteColor; - - private final Orientation incomingSide; - private final boolean showRoute; - - private AccessoryBean.AccessoryValue routeState; - private BlockBean blockBean; - private TileBean tileBean; - - private BlockState blockState; - - public TileEvent(String tileId, boolean showRoute) { - this(tileId, showRoute, null, AccessoryValue.OFF); - } - - public TileEvent(String tileId, boolean showRoute, Orientation incomingSide) { - this(tileId, showRoute, incomingSide, AccessoryValue.OFF); - } - - public TileEvent(String tileId, boolean showRoute, Orientation incomingSide, Color trackRouteColor) { - this(tileId, showRoute, incomingSide, AccessoryValue.OFF, trackRouteColor); - } - - public TileEvent(String tileId, boolean showRoute, Orientation incomingSide, AccessoryValue routeState) { - this(tileId, showRoute, incomingSide, routeState, Tile.DEFAULT_ROUTE_TRACK_COLOR); - } - - public TileEvent(String tileId, boolean showRoute, Orientation incomingSide, AccessoryValue routeState, Color trackRouteColor) { - this(tileId, showRoute, incomingSide, routeState, Tile.DEFAULT_BACKGROUND_COLOR, Tile.DEFAULT_TRACK_COLOR, trackRouteColor, BlockState.FREE); - } - - public TileEvent(String tileId, boolean showRoute, BlockState blockState) { - this(tileId, showRoute, null, AccessoryValue.OFF, Tile.DEFAULT_BACKGROUND_COLOR, Tile.DEFAULT_TRACK_COLOR, Tile.DEFAULT_ROUTE_TRACK_COLOR, blockState); - } - - public TileEvent(String tileId, boolean showRoute, Orientation incomingSide, AccessoryValue routeState, Color backgroundColor, Color trackColor, Color trackRouteColor, BlockState blockState) { - this.tileId = tileId; - this.showRoute = showRoute; - this.incomingSide = incomingSide; - this.routeState = routeState; - - this.tileBean = null; - this.blockBean = null; - - this.backgroundColor = backgroundColor; - this.trackColor = trackColor; - this.trackRouteColor = trackRouteColor; - this.blockState = blockState; - } - - public TileEvent(BlockBean blockBean) { - this.tileId = blockBean.getTileId(); - - this.showRoute = false; - this.blockBean = blockBean; - - this.incomingSide = Orientation.EAST; - this.backgroundColor = Tile.DEFAULT_BACKGROUND_COLOR; - this.trackColor = Tile.DEFAULT_TRACK_COLOR; - this.trackRouteColor = Tile.DEFAULT_ROUTE_TRACK_COLOR; - } - - public TileEvent(TileBean tileBean) { - this.tileId = tileBean.getId(); - - this.showRoute = false; - - this.tileBean = tileBean; - this.blockBean = tileBean.getBlockBean(); - - this.incomingSide = tileBean.getOrientation(); - this.backgroundColor = Tile.DEFAULT_BACKGROUND_COLOR; - this.trackColor = Tile.DEFAULT_TRACK_COLOR; - this.trackRouteColor = Tile.DEFAULT_ROUTE_TRACK_COLOR; - } - - public boolean isEventFor(Tile tile) { - return this.tileId.equals(tile.getId()); - } - - public String getTileId() { - return tileId; - } - - public boolean isShowRoute() { - return showRoute; - } - - public Orientation getIncomingSide() { - return incomingSide; - } - - public AccessoryValue getRouteState() { - return routeState; - } - - public Color getBackgroundColor() { - return backgroundColor; - } - - public Color getTrackColor() { - return trackColor; - } - - public Color getTrackRouteColor() { - return trackRouteColor; - } - - public BlockBean getBlockBean() { - return blockBean; - } - - public TileBean getTileBean() { - return tileBean; - } - - public BlockState getBlockState() { - return blockState; - } - -} diff --git a/src/main/java/jcs/ui/layout/events/TileEventListener.java b/src/main/java/jcs/ui/layout/events/TileEventListener.java deleted file mode 100644 index 94480bb3..00000000 --- a/src/main/java/jcs/ui/layout/events/TileEventListener.java +++ /dev/null @@ -1,24 +0,0 @@ -/* - * Copyright 2023 Frans Jacobs. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package jcs.ui.layout.events; - -public interface TileEventListener { - - String getId(); - - void onTileChange(TileEvent tileEvent); - -} diff --git a/src/main/java/jcs/ui/layout/tiles/TileCache.java b/src/main/java/jcs/ui/layout/tiles/TileCache.java index 825c3987..ade3c9c2 100644 --- a/src/main/java/jcs/ui/layout/tiles/TileCache.java +++ b/src/main/java/jcs/ui/layout/tiles/TileCache.java @@ -27,7 +27,6 @@ import jcs.entities.TileBean; import jcs.persistence.PersistenceFactory; import org.tinylog.Logger; -import jcs.commandStation.events.JCSActionEvent; import jcs.commandStation.events.SensorEventListener; import jcs.entities.AccessoryBean; import jcs.entities.SensorBean; @@ -41,6 +40,7 @@ import static jcs.entities.TileBean.TileType.STRAIGHT; import static jcs.entities.TileBean.TileType.STRAIGHT_DIR; import static jcs.entities.TileBean.TileType.SWITCH; +import jcs.commandStation.events.JCSActionEvent; /** * Factory object to create Tiles and cache pointMap diff --git a/src/main/java/jcs/ui/table/DispatcherTablePanel.java b/src/main/java/jcs/ui/table/DispatcherTablePanel.java index 93857a8c..b9624cff 100644 --- a/src/main/java/jcs/ui/table/DispatcherTablePanel.java +++ b/src/main/java/jcs/ui/table/DispatcherTablePanel.java @@ -25,8 +25,6 @@ import javax.swing.JLabel; import javax.swing.JTable; import javax.swing.SwingUtilities; -import javax.swing.UIManager; -import javax.swing.UnsupportedLookAndFeelException; import javax.swing.event.RowSorterEvent; import javax.swing.table.DefaultTableCellRenderer; import javax.swing.table.TableRowSorter; @@ -47,14 +45,12 @@ public class DispatcherTablePanel extends javax.swing.JPanel implements AutoPilo * Creates new form LocomotiveTablePanel */ public DispatcherTablePanel() { - initComponents(); this.dispatcherTable.setDefaultRenderer(Image.class, new LocIconRenderer()); this.dispatcherTable.getRowSorter().addRowSorterListener((RowSorterEvent e) -> { //Logger.trace(e.getType() + "," + e.getSource().getSortKeys());// Sorting changed }); - initModel(); } @@ -67,7 +63,7 @@ private void initModel() { public void statusChanged(boolean running) { List dispatchers = AutoPilot.getLocomotiveDispatchers(); Logger.trace("Found " + dispatchers.size() + " Dispatchers. Automode: " + (running ? "on" : "off")); - this.locomotiveDispatcherTableModel.refresh(); + locomotiveDispatcherTableModel.refresh(); } private class LocIconRenderer extends DefaultTableCellRenderer { @@ -75,15 +71,16 @@ private class LocIconRenderer extends DefaultTableCellRenderer { @Override public Component getTableCellRendererComponent(JTable table, Object value, boolean isSelected, boolean hasFocus, int row, int column) { super.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column); - - Image img = (Image) value; - int size = 40; - float aspect = (float) img.getHeight(null) / (float) img.getWidth(null); - img = img.getScaledInstance(size, (int) (size * aspect), Image.SCALE_SMOOTH); - BufferedImage bi = ImageUtil.toBuffered(img); - setIcon(new ImageIcon(bi)); - setHorizontalAlignment(JLabel.CENTER); - setText(""); + if (value != null) { + Image img = (Image) value; + int size = 40; + float aspect = (float) img.getHeight(null) / (float) img.getWidth(null); + img = img.getScaledInstance(size, (int) (size * aspect), Image.SCALE_SMOOTH); + BufferedImage bi = ImageUtil.toBuffered(img); + setIcon(new ImageIcon(bi)); + setHorizontalAlignment(JLabel.CENTER); + setText(""); + } return this; } } @@ -135,10 +132,10 @@ private void dispatcherTableMouseReleased(java.awt.event.MouseEvent evt) {//GEN- public void setVisible(boolean aFlag) { super.setVisible(aFlag); if (aFlag) { - AutoPilot.addAutoPilotStatusListener(this); + //AutoPilot.addAutoPilotStatusListener(this); statusChanged(AutoPilot.isAutoModeActive()); } else { - AutoPilot.removeAutoPilotStatusListener(this); + //AutoPilot.removeAutoPilotStatusListener(this); } } @@ -165,47 +162,4 @@ private void showDriverCabDialog(LocomotiveBean locomotiveBean) { private jcs.ui.table.model.LocomotiveDispatcherTableModel locomotiveDispatcherTableModel; // End of variables declaration//GEN-END:variables - public static void main(String args[]) { - - long now = System.currentTimeMillis(); - long maxtime = now + 5000L; - AutoPilot.startAutoMode(); - int dispcnt = AutoPilot.getLocomotiveDispatchers().size(); - while (dispcnt == 0 && now < maxtime) { - now = System.currentTimeMillis(); - dispcnt = AutoPilot.getLocomotiveDispatchers().size(); - } - - try { - String plaf = System.getProperty("jcs.plaf", "com.formdev.flatlaf.FlatLightLaf"); - if (plaf != null) { - UIManager.setLookAndFeel(plaf); - } else { - UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName()); - } - } catch (ClassNotFoundException | InstantiationException | IllegalAccessException | UnsupportedLookAndFeelException ex) { - Logger.error(ex); - } - - java.awt.EventQueue.invokeLater(() -> { - - DispatcherTablePanel testPanel = new DispatcherTablePanel(); - JFrame testFrame = new JFrame("LocomotiveTablePanel Tester"); - - testFrame.add(testPanel); - - testFrame.addWindowListener(new java.awt.event.WindowAdapter() { - @Override - public void windowClosing(java.awt.event.WindowEvent e) { - System.exit(0); - } - }); - testFrame.pack(); - testFrame.setLocationRelativeTo(null); - - //testPanel.loadLocomotives(); - //testPanel.locomotiveDispatcherTableModel.refresh(); - testFrame.setVisible(true); - }); - } } diff --git a/src/main/java/jcs/ui/table/LocomotiveTablePanel.java b/src/main/java/jcs/ui/table/LocomotiveTablePanel.java index c9a3caf1..d4bf146d 100644 --- a/src/main/java/jcs/ui/table/LocomotiveTablePanel.java +++ b/src/main/java/jcs/ui/table/LocomotiveTablePanel.java @@ -52,9 +52,9 @@ public LocomotiveTablePanel() { initComponents(); - this.locomotiveTable.setDefaultRenderer(Image.class, new LocIconRenderer()); + locomotiveTable.setDefaultRenderer(Image.class, new LocIconRenderer()); - this.locomotiveTable.getRowSorter().addRowSorterListener((RowSorterEvent e) -> { + locomotiveTable.getRowSorter().addRowSorterListener((RowSorterEvent e) -> { //Logger.trace(e.getType() + "," + e.getSource().getSortKeys());// Sorting changed }); @@ -80,10 +80,14 @@ private void initModel() { @Override public void onChange(RefreshEvent event) { if ("locomotives".equals(event.getSource())) { - locomotiveBeanTableModel.refresh(); + refresh(); } } + public void refresh() { + locomotiveBeanTableModel.refresh(); + } + private class LocIconRenderer extends DefaultTableCellRenderer { @Override diff --git a/src/main/resources/media/arrowhead-right-gn.png b/src/main/resources/media/arrowhead-right-gn.png new file mode 100755 index 0000000000000000000000000000000000000000..b850cfba9f060322de851e4619018b8d7d28d53e GIT binary patch literal 456 zcmV;(0XP1MP)Px#1ZP1_K>z@;j|==^1poj532;bRa{vGi!vFvd!vV){sAK>D0bNN%K~zXf<&?im z!%!53&rK_|@*c6EvmIRuiX`b)-5p&V1P9$5b#rrd)7`~QH~)b`7fA<&E{+Z^;*h>Z zOrbxngDu!gLzCD^zwvx<5BI`*z@J1L?-E=q$UF;{3`QJl6Fn{l&bkz7i7Nnz)^bEm z9k?e_rGaFC?-TK4!u5U+`_Z!hI+@QVeuD{UE4M%`6}Y?7%pzd{K)@1NbgMe<^~zgK zNgqezf-%H&5EY`9Hf~kAX{0Uy00Nc4XlUb}gKK%|f0C&H06>%n=uDYz!w$T%)MK(2 zj37dFU~x+Y&Y^UeM*#p3qd*p|PCHk^cMuPQUkKO>ZT~?!{B{FozA1K#mAK)^x&Z@i z4EgAzSSw;H9(x0000gTe~ HDWM4fW+XUD literal 0 HcmV?d00001 diff --git a/src/main/resources/media/reset-happy.png b/src/main/resources/media/reset-happy.png new file mode 100755 index 0000000000000000000000000000000000000000..3ec82eea2cfe526b837478b500d2a92482036993 GIT binary patch literal 738 zcmV<80v-K{P)Px#1ZP1_K>z@;j|==^1poj532;bRa{vGi!vFvd!vV){sAK>D0(VJ7K~zXf-IXzD z6Hyq)f8VmC^`yO6gukQVCm4o#X+co zU`2<3(p-o`r8HC;+fp4$a(ACYbCH{JWc@BRPp-raWx|2h&E;xraB1!Kvi zKta)dUp7eDftmDh?L}-!gq{Igb}sFSPAe4Sb72%-if2lxk?K->4#30(fJP-#bi}Jf z%$03bEdw7Fb$nT16yttauV$|XwIR9!8kJ1ZGBPVj8bHzac-~klU+eP>7cG^sRDH0| zg>hhEXO$cjc<{B7y&kiR25i~6v@uNkV-1OMHD3P3Iak+w1aRUGX4o7av~-L zUY$EoNd(h>k|@?<)C7RRZu&ob1>UU9lGub*hH1v6!_@_cVQv&@S*7ky;j_XqL z&4~x3MygAS+ze}b!3b07vJ@h dispList = AutoPilot.getLocomotiveDispatchers(); assertEquals(1, dispList.size()); - assertFalse(AutoPilot.areDispatchersRunning()); + assertFalse(AutoPilot.isADispatcherRunning()); AutoPilot.stopAutoMode(); //let the autopilot finish... @@ -542,7 +542,7 @@ public void testStartAllLocomotives() { public void testStopAllLocomotives() { System.out.println("stopAllLocomotives"); AutoPilot instance = null; - AutoPilot.stopAllLocomotives(); + //AutoPilot.stopAllLocomotives(); fail("The test case is a prototype."); } diff --git a/src/test/java/jcs/commandStation/autopilot/state/StateMachineStepByStepTest.java b/src/test/java/jcs/commandStation/autopilot/state/StateMachineStepByStepTest.java index 1aa92a52..bde9a609 100644 --- a/src/test/java/jcs/commandStation/autopilot/state/StateMachineStepByStepTest.java +++ b/src/test/java/jcs/commandStation/autopilot/state/StateMachineStepByStepTest.java @@ -77,14 +77,14 @@ public void setUp() { ps.persist(route); } JCS.getJcsCommandStation().switchPower(true); - AutoPilot.startAutoMode(); + AutoPilot.runAutoPilot(true); Logger.info("=========================== setUp done.............."); } @AfterEach public void tearDown() { Logger.info("=========================== Teardown.............."); - AutoPilot.stopAutoMode(); + AutoPilot.runAutoPilot(false); long now = System.currentTimeMillis(); long start = now; long timeout = now + 10000; @@ -201,7 +201,7 @@ public void testBk1ToBk4() { BlockBean block4 = ps.getBlockByTileId("bk-4"); assertEquals(BlockBean.BlockState.FREE, block4.getBlockState()); - StateMachineThread stateMachine = dispatcher.getStateMachineThread(); + StateMachine stateMachine = dispatcher.getStateMachine(); //Start from bk-1 assertEquals(NS_DHG_6505, block1.getLocomotiveId()); @@ -211,7 +211,7 @@ public void testBk1ToBk4() { //Thread should NOT run! assertFalse(stateMachine.isThreadRunning()); - assertFalse(stateMachine.isEnableAutomode()); + assertFalse(stateMachine.isAutomodeEnabled()); assertEquals("IdleState", stateMachine.getDispatcherStateName()); //Execute IdleState @@ -222,7 +222,7 @@ public void testBk1ToBk4() { //Departure //Automode should be enabled stateMachine.setEnableAutomode(true); - assertTrue(stateMachine.isEnableAutomode()); + assertTrue(stateMachine.isAutomodeEnabled()); //Execute IdleState again stateMachine.handleState(); @@ -385,7 +385,7 @@ public void testFromBk1ToBk4andViceVersa() { block4.setMinWaitTime(3); ps.persist(block4); - StateMachineThread stateMachine = dispatcher.getStateMachineThread(); + StateMachine stateMachine = dispatcher.getStateMachine(); //Start from bk-1 assertEquals(NS_DHG_6505, block1.getLocomotiveId()); @@ -395,7 +395,7 @@ public void testFromBk1ToBk4andViceVersa() { //Thread should NOT run! assertFalse(stateMachine.isThreadRunning()); - assertFalse(stateMachine.isEnableAutomode()); + assertFalse(stateMachine.isAutomodeEnabled()); assertEquals("IdleState", stateMachine.getDispatcherStateName()); //Execute IdleState @@ -406,7 +406,7 @@ public void testFromBk1ToBk4andViceVersa() { //Departure //Automode should be enabled stateMachine.setEnableAutomode(true); - assertTrue(stateMachine.isEnableAutomode()); + assertTrue(stateMachine.isAutomodeEnabled()); //Execute IdleState again stateMachine.handleState(); @@ -695,7 +695,7 @@ public void testFromBk1ToBk4andViceVersa() { //Automode OFF! stateMachine.setEnableAutomode(false); - assertFalse(stateMachine.isEnableAutomode()); + assertFalse(stateMachine.isAutomodeEnabled()); //Execute the WaitState stateMachine.handleState(); @@ -722,7 +722,7 @@ public void testFromBk1ToBk4Gost() { BlockBean block4 = ps.getBlockByTileId("bk-4"); assertEquals(BlockBean.BlockState.FREE, block4.getBlockState()); - StateMachineThread stateMachine = dispatcher.getStateMachineThread(); + StateMachine stateMachine = dispatcher.getStateMachine(); //Start from bk-1 assertEquals(NS_DHG_6505, block1.getLocomotiveId()); @@ -732,7 +732,7 @@ public void testFromBk1ToBk4Gost() { //Thread should NOT run! assertFalse(stateMachine.isThreadRunning()); - assertFalse(stateMachine.isEnableAutomode()); + assertFalse(stateMachine.isAutomodeEnabled()); assertEquals("IdleState", stateMachine.getDispatcherStateName()); //Execute IdleState @@ -743,7 +743,7 @@ public void testFromBk1ToBk4Gost() { //Departure //Automode should be enabled stateMachine.setEnableAutomode(true); - assertTrue(stateMachine.isEnableAutomode()); + assertTrue(stateMachine.isAutomodeEnabled()); //Execute IdleState again stateMachine.handleState(); @@ -839,7 +839,7 @@ public void testReset() { BlockBean block4 = ps.getBlockByTileId("bk-4"); assertEquals(BlockBean.BlockState.OUT_OF_ORDER, block4.getBlockState()); - StateMachineThread instance = dispatcher.getStateMachineThread(); + StateMachine instance = dispatcher.getStateMachine(); //Start from bk-2 assertEquals(NS_1631, block2.getLocomotiveId()); @@ -849,7 +849,7 @@ public void testReset() { assertNull(dispatcher.getRouteBean()); assertFalse(instance.isThreadRunning()); - assertFalse(instance.isEnableAutomode()); + assertFalse(instance.isAutomodeEnabled()); assertEquals("IdleState", instance.getDispatcherStateName()); //Execute IdleState @@ -872,7 +872,7 @@ public void testReset() { //Automode ON! instance.setEnableAutomode(true); - assertTrue(instance.isEnableAutomode()); + assertTrue(instance.isAutomodeEnabled()); assertFalse(instance.isThreadRunning()); block1 = ps.getBlockByTileId("bk-1"); @@ -965,7 +965,7 @@ public void testReset() { assertNull(dispatcher.getRouteBean()); assertNull(dispatcher.getDestinationBlock()); - assertFalse(instance.isEnableAutomode()); + assertFalse(instance.isAutomodeEnabled()); block1 = ps.getBlockByTileId("bk-1"); assertEquals(BlockBean.BlockState.OUT_OF_ORDER, block1.getBlockState()); diff --git a/src/test/java/jcs/commandStation/autopilot/state/StateMachineThreadTest.java b/src/test/java/jcs/commandStation/autopilot/state/StateMachineThreadTest.java index 6892971f..84859fdb 100644 --- a/src/test/java/jcs/commandStation/autopilot/state/StateMachineThreadTest.java +++ b/src/test/java/jcs/commandStation/autopilot/state/StateMachineThreadTest.java @@ -36,7 +36,6 @@ import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeEach; -import org.junit.jupiter.api.Test; import static org.junit.jupiter.api.Assertions.*; import org.junit.jupiter.api.BeforeAll; import org.tinylog.Logger; @@ -109,7 +108,7 @@ public void setUp() { Logger.trace("Power on in " + (now - start) + "ms."); - AutoPilot.startAutoMode(); + AutoPilot.runAutoPilot(true); Logger.info("=========================== setUp done.............."); } @@ -117,7 +116,7 @@ public void setUp() { @AfterEach public void tearDown() { Logger.info("=========================== Teardown.............."); - AutoPilot.stopAutoMode(); + AutoPilot.runAutoPilot(false); long now = System.currentTimeMillis(); long start = now; long timeout = now + 10000; @@ -270,7 +269,7 @@ public void testBk1ToBk4() { assertTrue(AutoPilot.isOnTrack(dhg)); assertTrue(AutoPilot.isAutoModeActive()); - AutoPilot.startAutoMode(); + AutoPilot.runAutoPilot(true); long now = System.currentTimeMillis(); long timeout = now + 10000; @@ -578,7 +577,7 @@ public void testStartStopLocomotiveAutomode() { long now = System.currentTimeMillis(); long timeout = now + 10000; //Start Automode - AutoPilot.startAutoMode(); + AutoPilot.runAutoPilot(true); boolean autoPilotRunning = AutoPilot.isAutoModeActive(); while (!autoPilotRunning && timeout > now) { @@ -846,7 +845,7 @@ public void testStartStopThreadRunning() { BlockBean block3 = PersistenceFactory.getService().getBlockByTileId("bk-3"); assertEquals(BlockBean.BlockState.OUT_OF_ORDER, block3.getBlockState()); - StateMachineThread instance = dispatcher.getStateMachineThread(); + StateMachine instance = dispatcher.getStateMachine(); assertFalse(instance.isThreadRunning()); assertFalse(instance.isAlive()); @@ -865,7 +864,7 @@ public void testStartStopThreadRunning() { Logger.debug("Dispatcher Thread Started"); assertTrue(instance.isThreadRunning()); assertTrue(instance.isAlive()); - assertFalse(instance.isEnableAutomode()); + assertFalse(instance.isAutomodeEnabled()); instance.stopRunningThread(); Logger.debug("Dispatcher Thread Stopped"); @@ -906,7 +905,7 @@ public static void beforeAll() { @AfterAll public static void assertOutput() { - AutoPilot.stopAutoMode(); + AutoPilot.runAutoPilot(false); long now = System.currentTimeMillis(); long start = now; From dd93284b787d8d2de45e5684c4688c7d7f0e0acd Mon Sep 17 00:00:00 2001 From: Frans Jacobs Date: Wed, 19 Feb 2025 21:27:20 +0100 Subject: [PATCH 24/24] GUI minor changes --- src/main/java/jcs/ui/JCSFrame.form | 37 +++- src/main/java/jcs/ui/JCSFrame.java | 23 ++- src/main/java/jcs/ui/layout/LayoutCanvas.form | 6 +- src/main/java/jcs/ui/layout/LayoutCanvas.java | 174 ++++++++++-------- src/main/java/jcs/ui/layout/LayoutPanel.form | 24 +-- src/main/java/jcs/ui/layout/LayoutPanel.java | 20 +- .../java/jcs/ui/layout/tiles/TileCache.java | 25 ++- src/main/resources/tinylog-dev.properties | 2 +- 8 files changed, 193 insertions(+), 118 deletions(-) diff --git a/src/main/java/jcs/ui/JCSFrame.form b/src/main/java/jcs/ui/JCSFrame.form index 6ab04d2b..9c5ed621 100755 --- a/src/main/java/jcs/ui/JCSFrame.form +++ b/src/main/java/jcs/ui/JCSFrame.form @@ -798,7 +798,13 @@
+ + + + + + @@ -809,11 +815,11 @@ - + - + @@ -826,7 +832,7 @@ - + @@ -846,11 +852,11 @@ - + - + @@ -864,9 +870,12 @@ - + + + + @@ -895,7 +904,13 @@ + + + + + + @@ -998,7 +1013,13 @@ + + + + + + @@ -1011,11 +1032,11 @@ - + - + diff --git a/src/main/java/jcs/ui/JCSFrame.java b/src/main/java/jcs/ui/JCSFrame.java index bb8db46f..b75af53d 100755 --- a/src/main/java/jcs/ui/JCSFrame.java +++ b/src/main/java/jcs/ui/JCSFrame.java @@ -583,26 +583,29 @@ public void actionPerformed(ActionEvent evt) { getContentPane().add(toolbarPanel, BorderLayout.NORTH); + statusPanel.setMinimumSize(new Dimension(1227, 45)); statusPanel.setName("statusPanel"); // NOI18N + statusPanel.setPreferredSize(new Dimension(1227, 48)); getContentPane().add(statusPanel, BorderLayout.SOUTH); - mainPanel.setMinimumSize(new Dimension(1050, 900)); + mainPanel.setMinimumSize(new Dimension(1232, 770)); mainPanel.setName("mainPanel"); // NOI18N - mainPanel.setPreferredSize(new Dimension(1315, 850)); + mainPanel.setPreferredSize(new Dimension(1232, 770)); mainPanel.setLayout(new BorderLayout()); - locoDisplaySP.setDividerLocation(300); + locoDisplaySP.setDividerLocation(302); locoDisplaySP.setMinimumSize(new Dimension(1050, 900)); locoDisplaySP.setName("locoDisplaySP"); // NOI18N locoDisplaySP.setPreferredSize(new Dimension(1050, 850)); - centerPanel.setMinimumSize(new Dimension(1000, 900)); + centerPanel.setMinimumSize(new Dimension(1002, 772)); centerPanel.setName("centerPanel"); // NOI18N - centerPanel.setPreferredSize(new Dimension(1010, 900)); + centerPanel.setPreferredSize(new Dimension(1002, 772)); centerPanel.setLayout(new CardLayout()); - keyboardSensorMessagePanel.setMinimumSize(new Dimension(885, 840)); + keyboardSensorMessagePanel.setMinimumSize(new Dimension(1002, 772)); keyboardSensorMessagePanel.setName("keyboardSensorMessagePanel"); // NOI18N + keyboardSensorMessagePanel.setPreferredSize(new Dimension(1002, 772)); centerPanel.add(keyboardSensorMessagePanel, "diagnosticPanel"); layoutPanel.setMinimumSize(new Dimension(885, 160)); @@ -610,7 +613,9 @@ public void actionPerformed(ActionEvent evt) { centerPanel.add(layoutPanel, "designPanel"); layoutPanel.getAccessibleContext().setAccessibleName("designPanel"); + overviewPanel.setMinimumSize(new Dimension(1002, 772)); overviewPanel.setName("overviewPanel"); // NOI18N + overviewPanel.setPreferredSize(new Dimension(1002, 772)); centerPanel.add(overviewPanel, "overviewPanel"); overviewPanel.getAccessibleContext().setAccessibleName("overviewPanel"); @@ -624,14 +629,16 @@ public void actionPerformed(ActionEvent evt) { centerPanel.add(settingsPanel, "settingsPanel"); + vncPanel.setMinimumSize(new Dimension(1002, 772)); vncPanel.setName("vncPanel"); // NOI18N + vncPanel.setPreferredSize(new Dimension(1002, 772)); centerPanel.add(vncPanel, "vncPanel"); locoDisplaySP.setRightComponent(centerPanel); - leftPanel.setMinimumSize(new Dimension(220, 850)); + leftPanel.setMinimumSize(new Dimension(225, 772)); leftPanel.setName("leftPanel"); // NOI18N - leftPanel.setPreferredSize(new Dimension(225, 845)); + leftPanel.setPreferredSize(new Dimension(225, 772)); leftPanel.setLayout(new BorderLayout(1, 1)); bottomLeftPanel.setBorder(BorderFactory.createTitledBorder("Controller Properties")); diff --git a/src/main/java/jcs/ui/layout/LayoutCanvas.form b/src/main/java/jcs/ui/layout/LayoutCanvas.form index 884eba14..0253ad8b 100755 --- a/src/main/java/jcs/ui/layout/LayoutCanvas.form +++ b/src/main/java/jcs/ui/layout/LayoutCanvas.form @@ -197,10 +197,10 @@ - + - + @@ -224,7 +224,7 @@ - + diff --git a/src/main/java/jcs/ui/layout/LayoutCanvas.java b/src/main/java/jcs/ui/layout/LayoutCanvas.java index 34b3ad87..a1914b97 100755 --- a/src/main/java/jcs/ui/layout/LayoutCanvas.java +++ b/src/main/java/jcs/ui/layout/LayoutCanvas.java @@ -85,38 +85,38 @@ public enum Mode { DELETE, CONTROL } - + static final int LINE_GRID = 0; static final int DOT_GRID = 1; - + private int gridType = LINE_GRID; - + private boolean readonly; private Mode mode; private boolean drawGrid = true; - + private Orientation orientation; private Direction direction; private TileType tileType; - + private Point mouseLocation = new Point(); - + private final ExecutorService executor; - + private Tile selectedTile; - + private RoutesDialog routesDialog; - + public LayoutCanvas() { this(false); } - + public LayoutCanvas(boolean readonly) { super(); setLayout(null); setOpaque(true); setDoubleBuffered(true); - + this.readonly = readonly; this.executor = Executors.newSingleThreadExecutor(); //this.executor = Executors.newCachedThreadPool(); @@ -124,24 +124,24 @@ public LayoutCanvas(boolean readonly) { this.mode = Mode.SELECT; this.orientation = Orientation.EAST; this.direction = Direction.CENTER; - + initComponents(); postInit(); } - + private void postInit() { routesDialog = new RoutesDialog(getParentFrame(), false, this, this.readonly); } - + public boolean isReadonly() { return readonly; } - + @Override public void paint(Graphics g) { //long started = System.currentTimeMillis(); super.paint(g); - + if (drawGrid) { if (this.gridType == LINE_GRID) { paintLineGrid(g); @@ -153,7 +153,7 @@ public void paint(Graphics g) { //long now = System.currentTimeMillis(); //Logger.trace("Duration: " + (now - started) + " ms."); } - + @Override public Component add(Component component) { super.add(component); @@ -162,7 +162,7 @@ public Component add(Component component) { } return component; } - + @Override public Component add(String name, Component component) { if (component instanceof Tile tile) { @@ -173,14 +173,14 @@ public Component add(String name, Component component) { } return component; } - + private void paintDotGrid(Graphics g) { int width = getWidth(); int height = getHeight(); Graphics2D gc = (Graphics2D) g; Paint p = gc.getPaint(); gc.setPaint(Color.black); - + int xOffset = 0; int yOffset = 0; for (int r = 0; r < width; r++) { @@ -190,7 +190,7 @@ private void paintDotGrid(Graphics g) { } gc.setPaint(p); } - + private void paintLineGrid(Graphics g) { int width = getWidth(); int height = getHeight(); @@ -198,7 +198,7 @@ private void paintLineGrid(Graphics g) { Paint p = gc.getPaint(); gc.setPaint(Color.black); gc.setPaint(Color.lightGray); - + gc.setStroke(new BasicStroke(1, BasicStroke.CAP_ROUND, BasicStroke.JOIN_ROUND)); for (int x = 0; x < width; x += 40) { gc.drawLine(x, 0, x, height); @@ -208,12 +208,12 @@ private void paintLineGrid(Graphics g) { } gc.setPaint(p); } - + void setMode(LayoutCanvas.Mode mode) { this.mode = mode; Logger.trace("Mode: " + mode); } - + void setDrawGrid(boolean flag) { if (flag) { switch (gridType) { @@ -228,16 +228,16 @@ void setDrawGrid(boolean flag) { drawGrid = flag; repaint(); } - + void setTileType(TileBean.TileType tileType) { this.tileType = tileType; Logger.trace("TileType: " + tileType + " Current mode: " + mode); } - + void setDirection(Direction direction) { this.direction = direction; } - + void loadLayoutInBackground() { this.executor.execute(() -> loadTiles()); @@ -252,13 +252,35 @@ void loadLayoutInBackground() { // } // }).start(); } - + private void loadTiles() { List tiles = TileCache.loadTiles(readonly); - + removeAll(); selectedTile = null; - + + Dimension minSize = TileCache.getMinCanvasSize(); + setMinimumSize(minSize); + + //Check if we must enlarge the canvas + int w = getPreferredSize().width; + int h = getPreferredSize().height; + boolean changeSize = false; + if (w < minSize.width) { + w = minSize.width; + changeSize = true; + } + if (h < minSize.height) { + h = minSize.height; + changeSize = true; + } + + if (changeSize) { + setPreferredSize(new Dimension(w, h)); + setSize(new Dimension(w, h)); + Logger.trace("Changed size to w: " + w + " h: " + h); + } + for (Tile tile : tiles) { add(tile); boolean showCenter = "true".equalsIgnoreCase(System.getProperty("tile.show.center", "false")); @@ -267,7 +289,7 @@ private void loadTiles() { } } } - + private void mouseMoveAction(MouseEvent evt) { Point sp = LayoutUtil.snapToGrid(evt.getPoint()); if (selectedTile != null) { @@ -276,7 +298,7 @@ private void mouseMoveAction(MouseEvent evt) { setCursor(Cursor.getDefaultCursor()); } } - + private void mousePressedAction(MouseEvent evt) { Logger.trace("@ (" + evt.getX() + "," + evt.getY() + ")"); Point snapPoint = LayoutUtil.snapToGrid(evt.getPoint()); @@ -287,13 +309,13 @@ private void mousePressedAction(MouseEvent evt) { if (selectedTile != null && CONTROL != mode) { selectedTile.setSelected(true); } - + if (previousSelected != null && selectedTile != null && previousSelected.getId().equals(selectedTile.getId())) { Logger.trace("Same tile " + selectedTile.getId() + " selected"); } else if (previousSelected != null) { previousSelected.setSelected(false); } - + switch (mode) { case CONTROL -> { if (selectedTile != null) { @@ -344,11 +366,11 @@ private void mousePressedAction(MouseEvent evt) { } } } - + private Tile addTile(Point p, TileType tileType, Orientation orientation, Direction direction, boolean selected, boolean showCenter) { Logger.trace("Adding: " + tileType + " @ " + p + " O: " + orientation + " D: " + direction); Tile tile = TileCache.createTile(tileType, orientation, direction, p); - + if (TileCache.canMoveTo(tile, p)) { tile.setSelected(selected); tile.setDrawCenterPoint(showCenter); @@ -362,7 +384,7 @@ private Tile addTile(Point p, TileType tileType, Orientation orientation, Direct return null; } } - + void removeTile(Tile tile) { Tile toBeDeleted = (Tile) getComponentAt(tile.getCenter()); if (toBeDeleted != null) { @@ -371,7 +393,7 @@ void removeTile(Tile tile) { TileCache.deleteTile(tile); } } - + private void mouseDragAction(MouseEvent evt) { //Logger.trace("@ (" + evt.getX() + "," + evt.getY() + ")"); Point snapPoint = LayoutUtil.snapToGrid(evt.getPoint()); @@ -379,13 +401,13 @@ private void mouseDragAction(MouseEvent evt) { int z = getComponentZOrder(selectedTile); setComponentZOrder(selectedTile, 0); Logger.trace("Moving: " + selectedTile.getId() + " @ " + selectedTile.xyToString() + " P: " + snapPoint.x + "," + snapPoint.y + ")"); - + if (TileCache.canMoveTo(selectedTile, snapPoint)) { selectedTile.setSelectedColor(Tile.DEFAULT_SELECTED_COLOR); } else { selectedTile.setSelectedColor(Tile.DEFAULT_WARN_COLOR); } - + int curX, curY; switch (selectedTile.getTileType()) { case BLOCK -> { @@ -426,7 +448,7 @@ private void mouseDragAction(MouseEvent evt) { selectedTile.setBounds(curX, curY, selectedTile.getWidth(), selectedTile.getHeight()); } } - + private void mouseReleasedAction(MouseEvent evt) { Point snapPoint = LayoutUtil.snapToGrid(evt.getPoint()); if (!Mode.CONTROL.equals(mode) && MouseEvent.BUTTON1 == evt.getButton() && selectedTile != null) { @@ -438,7 +460,7 @@ private void mouseReleasedAction(MouseEvent evt) { } } } - + private void executeControlActionForTile(Tile tile, Point p) { TileBean.TileType tt = tile.getTileType(); switch (tt) { @@ -455,7 +477,7 @@ private void executeControlActionForTile(Tile tile, Point p) { Block block = (Block) tile; BlockControlDialog bcd = new BlockControlDialog(getParentFrame(), block); bcd.setVisible(true); - + Logger.trace("Block properties closed"); this.repaint(block.getTileBounds()); } @@ -472,7 +494,7 @@ private void executeControlActionForTile(Tile tile, Point p) { } } } - + private void editSelectedTileProperties() { //the first tile should be the selected one boolean showProperties = false; @@ -480,11 +502,11 @@ private void editSelectedTileProperties() { boolean showRotate = false; boolean showMove = false; boolean showDelete = false; - + if (selectedTile != null) { TileBean.TileType tt = selectedTile.getTileType(); Logger.trace("Selected tile " + selectedTile.getId() + " TileType " + tt); - + switch (tt) { case END -> { showRotate = true; @@ -529,7 +551,7 @@ private void editSelectedTileProperties() { repaint(); } } - + private void showBlockPopupMenu(Tile tile, Point p) { if (tile == null || p == null) { return; @@ -545,18 +567,18 @@ private void showBlockPopupMenu(Tile tile, Point p) { this.toggleLocomotiveDirectionMI.setEnabled(hasLoco); this.reverseArrivalSideMI.setEnabled(hasLoco); this.resetGhostMI.setEnabled(isGhost); - + this.toggleOutOfOrderMI.setEnabled(!hasLoco); - + if (BlockBean.BlockState.OUT_OF_ORDER == ((Block) tile).getBlockState()) { this.toggleOutOfOrderMI.setText("Enable Block"); } else { this.toggleOutOfOrderMI.setText("Set Out of Order"); } - + this.blockPopupMenu.show(this, p.x, p.y); } - + private void showOperationsPopupMenu(Tile tile, Point p) { if (tile == null || p == null) { return; @@ -570,7 +592,7 @@ private void showOperationsPopupMenu(Tile tile, Point p) { boolean showMove = false; @SuppressWarnings("UnusedAssignment") boolean showDelete = false; - + TileType tt = tile.getTileType(); switch (tt) { case SENSOR -> { @@ -606,16 +628,16 @@ private void showOperationsPopupMenu(Tile tile, Point p) { } } this.xyMI.setVisible(true); - + String extra = ""; if (tile instanceof Sensor s) { if (s.getSensorBean() != null) { extra = " " + s.getSensorBean().getName(); } } - + this.xyMI.setText(tile.getId() + extra + " (" + p.x + "," + p.y + ") O: " + tile.getOrientation().getOrientation() + " D: " + tile.getDirection()); - + this.propertiesMI.setVisible(showProperties); this.flipHorizontalMI.setVisible(showFlip); this.flipVerticalMI.setVisible(showFlip); @@ -624,36 +646,36 @@ private void showOperationsPopupMenu(Tile tile, Point p) { this.deleteMI.setVisible(showDelete); this.operationsPM.show(this, p.x, p.y); } - + private JFrame getParentFrame() { JFrame frame = (JFrame) SwingUtilities.getRoot(this); return frame; } - + public void rotateSelectedTile() { Logger.trace("Selected Tile " + selectedTile.getId()); selectedTile = TileCache.rotateTile(selectedTile); selectedTile.setBounds(selectedTile.getTileBounds()); } - + public void flipSelectedTileHorizontal() { selectedTile = TileCache.flipHorizontal(selectedTile); selectedTile.setBounds(selectedTile.getTileBounds()); } - + public void flipSelectedTileVertical() { selectedTile = TileCache.flipVertical(selectedTile); selectedTile.setBounds(selectedTile.getTileBounds()); } - + void routeLayout() { this.executor.execute(() -> routeLayoutWithAStar()); } - + private void routeLayoutWithAStar() { //Make sure the layout is saved TileCache.persistAllTiles(); - + AStar astar = new AStar(); astar.buildGraph(TileCache.getTiles()); astar.routeAll(); @@ -662,7 +684,7 @@ private void routeLayoutWithAStar() { routesDialog.loadRoutes(); } } - + void showRoutesDialog() { routesDialog.setVisible(true); } @@ -856,8 +878,8 @@ public void actionPerformed(ActionEvent evt) { blockPopupMenu.add(blockPropertiesMI); setBackground(new Color(255, 255, 255)); - setMinimumSize(new Dimension(1398, 848)); - setPreferredSize(new Dimension(1398, 848)); + setMinimumSize(new Dimension(1000, 760)); + setPreferredSize(new Dimension(1000, 760)); addMouseMotionListener(new MouseMotionAdapter() { public void mouseDragged(MouseEvent evt) { formMouseDragged(evt); @@ -888,7 +910,7 @@ private void formMouseReleased(MouseEvent evt) {//GEN-FIRST:event_formMouseRelea private void horizontalMIActionPerformed(ActionEvent evt) {//GEN-FIRST:event_horizontalMIActionPerformed Logger.trace(this.orientation + ", " + evt.getModifiers() + ", " + evt.paramString()); - + if (this.mouseLocation != null && evt.getModifiers() == ActionEvent.MOUSE_EVENT_MASK) { this.mouseLocation = null; } @@ -896,7 +918,7 @@ private void horizontalMIActionPerformed(ActionEvent evt) {//GEN-FIRST:event_hor private void verticalMIActionPerformed(ActionEvent evt) {//GEN-FIRST:event_verticalMIActionPerformed Logger.trace(this.orientation + ", " + evt.getModifiers() + ", " + evt.paramString()); - + if (this.mouseLocation != null && evt.getModifiers() == ActionEvent.MOUSE_EVENT_MASK) { this.mouseLocation = null; } @@ -904,7 +926,7 @@ private void verticalMIActionPerformed(ActionEvent evt) {//GEN-FIRST:event_verti private void rightMIActionPerformed(ActionEvent evt) {//GEN-FIRST:event_rightMIActionPerformed Logger.trace(this.orientation + ", " + evt.getModifiers() + ", " + evt.paramString()); - + if (this.mouseLocation != null && evt.getModifiers() == ActionEvent.MOUSE_EVENT_MASK) { this.mouseLocation = null; } @@ -912,7 +934,7 @@ private void rightMIActionPerformed(ActionEvent evt) {//GEN-FIRST:event_rightMIA private void leftMIActionPerformed(ActionEvent evt) {//GEN-FIRST:event_leftMIActionPerformed Logger.trace(this.orientation + ", " + evt.getModifiers() + ", " + evt.paramString()); - + if (this.mouseLocation != null && evt.getModifiers() == ActionEvent.MOUSE_EVENT_MASK) { this.mouseLocation = null; } @@ -974,7 +996,7 @@ private void resetDispatcherMIActionPerformed(ActionEvent evt) {//GEN-FIRST:even if (this.selectedTile != null) { Block block = (Block) selectedTile; LocomotiveBean locomotive = block.getBlockBean().getLocomotive(); - + this.executor.execute(() -> { AutoPilot.resetDispatcher(locomotive); repaint(); @@ -984,7 +1006,7 @@ private void resetDispatcherMIActionPerformed(ActionEvent evt) {//GEN-FIRST:even private void removeLocMIActionPerformed(ActionEvent evt) {//GEN-FIRST:event_removeLocMIActionPerformed if (selectedTile != null && selectedTile.isBlock()) { - LocomotiveBean locomotive = selectedTile.getLocomotive(); + LocomotiveBean locomotive = selectedTile.getLocomotive(); locomotive.setDispatcherDirection(null); selectedTile.setLocomotive(null); @@ -1011,7 +1033,7 @@ private void blockPropertiesMIActionPerformed(ActionEvent evt) {//GEN-FIRST:even private void reverseArrivalSideMIActionPerformed(ActionEvent evt) {//GEN-FIRST:event_reverseArrivalSideMIActionPerformed if (this.selectedTile != null) { Block block = (Block) selectedTile; - + String suffix = block.getArrivalSuffix(); if ("+".equals(suffix)) { block.setArrivalSuffix("-"); @@ -1029,7 +1051,7 @@ private void toggleLocomotiveDirectionMIActionPerformed(ActionEvent evt) {//GEN- if (selectedTile != null) { Block block = (Block) selectedTile; LocomotiveBean locomotive = block.getLocomotive(); - + LocomotiveBean.Direction curDir; if (block.getLogicalDirection() != null) { curDir = block.getLogicalDirection(); @@ -1039,7 +1061,7 @@ private void toggleLocomotiveDirectionMIActionPerformed(ActionEvent evt) {//GEN- LocomotiveBean.Direction newDir = LocomotiveBean.toggle(curDir); block.setLogicalDirection(newDir); Logger.trace(block.getId() + " LogicalDir changed from " + curDir + " to " + newDir + " for " + locomotive.getName()); - + this.executor.execute(() -> { PersistenceFactory.getService().persist(block.getTileBean()); }); @@ -1055,7 +1077,7 @@ private void toggleOutOfOrderMIActionPerformed(ActionEvent evt) {//GEN-FIRST:eve } else if (BlockState.OUT_OF_ORDER == currentState) { block.setBlockState(BlockState.FREE); } - + if (currentState != block.getBlockState()) { this.executor.execute(() -> { PersistenceFactory.getService().persist(block.getBlockBean()); @@ -1068,7 +1090,7 @@ private void resetGhostMIActionPerformed(ActionEvent evt) {//GEN-FIRST:event_res if (this.selectedTile != null) { Block block = (Block) selectedTile; BlockBean.BlockState currentState = block.getBlockState(); - + if (BlockBean.BlockState.GHOST == currentState) { if (block.getLocomotive() != null) { block.setBlockState(BlockBean.BlockState.OCCUPIED); diff --git a/src/main/java/jcs/ui/layout/LayoutPanel.form b/src/main/java/jcs/ui/layout/LayoutPanel.form index 1942d961..8f2962af 100755 --- a/src/main/java/jcs/ui/layout/LayoutPanel.form +++ b/src/main/java/jcs/ui/layout/LayoutPanel.form @@ -116,11 +116,11 @@ - + - + @@ -138,7 +138,7 @@ - + @@ -149,10 +149,10 @@ - + - + @@ -171,7 +171,7 @@ - + @@ -917,17 +917,19 @@ - - + - + + + + @@ -939,11 +941,11 @@ - + - + diff --git a/src/main/java/jcs/ui/layout/LayoutPanel.java b/src/main/java/jcs/ui/layout/LayoutPanel.java index 9917b52c..932cbcfd 100755 --- a/src/main/java/jcs/ui/layout/LayoutPanel.java +++ b/src/main/java/jcs/ui/layout/LayoutPanel.java @@ -312,9 +312,9 @@ public void actionPerformed(ActionEvent evt) { }); operationsPM.add(deleteMI); - setMinimumSize(new Dimension(1400, 900)); + setMinimumSize(new Dimension(1002, 772)); setOpaque(false); - setPreferredSize(new Dimension(1400, 900)); + setPreferredSize(new Dimension(1002, 772)); addComponentListener(new ComponentAdapter() { public void componentHidden(ComponentEvent evt) { formComponentHidden(evt); @@ -329,8 +329,8 @@ public void componentShown(ComponentEvent evt) { setLayout(new BorderLayout()); topPanel.setMaximumSize(new Dimension(32767, 50)); - topPanel.setMinimumSize(new Dimension(1400, 50)); - topPanel.setPreferredSize(new Dimension(1400, 50)); + topPanel.setMinimumSize(new Dimension(1000, 50)); + topPanel.setPreferredSize(new Dimension(1000, 50)); FlowLayout flowLayout1 = new FlowLayout(FlowLayout.LEFT); flowLayout1.setAlignOnBaseline(true); topPanel.setLayout(flowLayout1); @@ -338,7 +338,7 @@ public void componentShown(ComponentEvent evt) { toolBar.setMaximumSize(new Dimension(1200, 42)); toolBar.setMinimumSize(new Dimension(1150, 42)); toolBar.setName(""); // NOI18N - toolBar.setPreferredSize(new Dimension(1000, 42)); + toolBar.setPreferredSize(new Dimension(980, 42)); loadBtn.setIcon(new ImageIcon(getClass().getResource("/media/load-24.png"))); // NOI18N loadBtn.setToolTipText("Load"); @@ -716,17 +716,17 @@ public void actionPerformed(ActionEvent evt) { add(topPanel, BorderLayout.NORTH); - canvasScrollPane.setDoubleBuffered(true); - canvasScrollPane.setMinimumSize(new Dimension(1024, 850)); - canvasScrollPane.setPreferredSize(new Dimension(1024, 850)); + canvasScrollPane.setMinimumSize(new Dimension(1000, 740)); + canvasScrollPane.setPreferredSize(new Dimension(980, 700)); canvasScrollPane.setViewportView(canvas); - canvas.setMinimumSize(new Dimension(800, 700)); + canvas.setMinimumSize(new Dimension(1000, 720)); canvas.setName(""); // NOI18N - canvas.setPreferredSize(new Dimension(800, 700)); + canvas.setPreferredSize(new Dimension(1000, 720)); canvasScrollPane.setViewportView(canvas); add(canvasScrollPane, BorderLayout.CENTER); + canvasScrollPane.getAccessibleContext().setAccessibleDescription(""); }// //GEN-END:initComponents private void horizontalMIActionPerformed(ActionEvent evt) {//GEN-FIRST:event_horizontalMIActionPerformed diff --git a/src/main/java/jcs/ui/layout/tiles/TileCache.java b/src/main/java/jcs/ui/layout/tiles/TileCache.java index ade3c9c2..3b8dd766 100644 --- a/src/main/java/jcs/ui/layout/tiles/TileCache.java +++ b/src/main/java/jcs/ui/layout/tiles/TileCache.java @@ -15,6 +15,7 @@ */ package jcs.ui.layout.tiles; +import java.awt.Dimension; import java.awt.Point; import java.util.HashMap; import java.util.List; @@ -41,6 +42,7 @@ import static jcs.entities.TileBean.TileType.STRAIGHT_DIR; import static jcs.entities.TileBean.TileType.SWITCH; import jcs.commandStation.events.JCSActionEvent; +import static jcs.ui.layout.tiles.Tile.GRID; /** * Factory object to create Tiles and cache pointMap @@ -68,6 +70,9 @@ public class TileCache { private static final ConcurrentLinkedQueue eventsQueue = new ConcurrentLinkedQueue(); private static final TileActionEventHandler actionEventQueueHandler = new TileActionEventHandler(eventsQueue); + private static int maxX; + private static int maxY; + static { actionEventQueueHandler.start(); } @@ -320,11 +325,14 @@ public static List loadTiles(boolean showvalues) { altPointMap.clear(); pointMap.clear(); idMap.clear(); + maxX = 0; + maxY = 0; List tileBeans = PersistenceFactory.getService().getTileBeans(); for (TileBean tb : tileBeans) { Tile tile = createTile(tb, showvalues); + calculateMaxCoordinates(tile.tileX, tile.tileY); idMap.put(tile.id, tile); pointMap.put(tile.getCenter(), tile); //Alternative point(s) to be able to find all pointIds @@ -336,7 +344,7 @@ public static List loadTiles(boolean showvalues) { } } - Logger.trace("Loaded " + idMap.size() + " Tiles..."); + Logger.trace("Loaded " + idMap.size() + " Tiles. Max: (" + maxX + "," + maxY + ")"); return idMap.values().stream().collect(Collectors.toList()); } @@ -344,6 +352,21 @@ public static List getTiles() { return idMap.values().stream().collect(Collectors.toList()); } + static void calculateMaxCoordinates(int tileX, int tileY) { + if (maxX < tileX) { + maxX = tileX; + } + if (maxY < tileY) { + maxY = tileY; + } + } + + public static Dimension getMinCanvasSize() { + int w = maxX + GRID; + int h = maxY + GRID; + return new Dimension(w, h); + } + public static Tile addAndSaveTile(Tile tile) { if (tile == null) { throw new IllegalArgumentException("Tile cannot be null"); diff --git a/src/main/resources/tinylog-dev.properties b/src/main/resources/tinylog-dev.properties index eb46adc1..0766ee23 100755 --- a/src/main/resources/tinylog-dev.properties +++ b/src/main/resources/tinylog-dev.properties @@ -36,5 +36,5 @@ exception = strip: jdk.internal level@jcs.util = info #level@jcs.commandStation = debug -level@jcs.ui.layout = info +#level@jcs.ui.layout = info level@jcs.commandStation.esu.ecos.EcosMessage = info \ No newline at end of file