@@ -28,6 +28,10 @@ class TextButton extends Label {
2828 }
2929
3030 onhover ( ) { /*collapseit*/
31+ if ( ! this . isFocused ( ) ) {
32+ return ;
33+ }
34+
3135 // Map global mouse coords into the current canvas transform's local space so
3236 // hit-testing matches where the control is actually drawn (considering translate). (Copilot code)
3337 let localMouseX = mouseX ;
@@ -77,6 +81,10 @@ class TextButton extends Label {
7781 } ;
7882
7983 onClickEvent ( ) { /*collapseit*/
84+ if ( ! this . isFocused ( ) ) {
85+ return ;
86+ }
87+
8088 if ( this . internal_hovered ) {
8189 if ( mouseIsDown ) { //Se isto for verdade, ou seja está-se clicando em cima do botão, só falta largar para a...
8290 this . internal_waitingForRelease = true ; //...condição seguinte ser executada.
@@ -98,6 +106,26 @@ class TextButton extends Label {
98106 this . onClickEvent ( ) ;
99107 this . updateLanguage ( ) ;
100108 } ;
109+
110+ isFocused ( ) : boolean {
111+ // To prevent clicks and hover effects when it's not on the top window or
112+ // on a GameState when there's no window open
113+ if ( this . parent instanceof JSWindow ) {
114+ return this . parent . isTopWindow ( ) ;
115+ } else if ( this . parent instanceof GameState ) {
116+ // Check if an window is open
117+ const jsWindows = JSWindow . getAllInstances ( ) as Array < JSWindow > ;
118+ for ( let i = 0 ; i < jsWindows . length ; i ++ ) {
119+ if ( jsWindows [ i ] . visible ) {
120+ // If it's on a GameState and there's a window open, it's not focused
121+ return false ;
122+ }
123+ }
124+ return true ;
125+ } else {
126+ return true ;
127+ }
128+ }
101129}
102130
103131class PlayerInfo extends Label { /*collapseit*/
@@ -574,19 +602,27 @@ class JSWindow extends Rectangle { /*collapseit*/
574602 showing : boolean ;
575603 hiding : boolean ;
576604 container : { [ key : string ] : any } ;
577- parent : JSWindow | GameState | null ;
605+ parent ? : JSWindow | GameState ;
578606 constructor ( width : number , height : number ) {
579607 // By default the JSWindow is centered in the canvas. If a parent is
580608 // supplied we'll initialize relative to the parent's coordinates.
581609 super ( canvas . width / 2 - width / 2 , - height , width , height ) ;
582610 this . color = "#1062e8" ;
583611 this . outlinePosition = "inner" ;
584- this . showIndex = 100 ;
585612 this . maxYMoveSpeed = 40 ;
586613 this . showing = false ;
587614 this . hiding = false ;
588- this . container = new Object ( ) ;
589- this . parent = null ;
615+ this . container = new Proxy ( { } , {
616+ // Add parent to any object added to the container
617+ set : ( target : any , prop : string | symbol , value : any ) => {
618+ target [ prop as any ] = value ;
619+ if ( value && typeof value === "object" && "parent" in value ) {
620+ try { value . parent = this ; } catch ( e ) { /* ignore readonly */ }
621+ }
622+ return true ;
623+ }
624+ } ) ;
625+ this . parent = undefined ;
590626 }
591627 draw ( ) { /*collapseit*/
592628 super . draw ( ) ;
@@ -654,6 +690,7 @@ class JSWindow extends Rectangle { /*collapseit*/
654690 distance ( 0 , targetShowY , 0 , targetHideY ) /*Total*/ ;
655691
656692 if ( this . showing ) {
693+ this . visible = true ;
657694 this . y += this . maxYMoveSpeed * showProgress ;
658695 if ( Math . round ( this . y ) === Math . round ( targetShowY ) ) {
659696 this . showing = false ;
@@ -663,25 +700,41 @@ class JSWindow extends Rectangle { /*collapseit*/
663700 this . y += this . maxYMoveSpeed * ( 1 - hideProgress ) + 1 ;
664701 if ( this . y > targetHideY ) {
665702 this . hiding = false ;
703+ this . visible = false ;
666704 }
667705 }
668706 } ;
669707
670708 show ( ) { /*collapseit*/
671- this . visible = true ;
709+ // Starting position
672710 this . x = this . parent ? ( - this . parent . x + canvas . width / 2 - this . width / 2 ) : ( canvas . width / 2 - this . width / 2 ) ;
673711 this . y = this . parent ? ( - this . parent . y - this . height ) : - this . height ;
674712 this . showing = true ;
675713 this . hiding = false ;
676714 } ;
677715
678716 hide ( ) { /*collapseit*/
679- this . visible = true ;
717+ // Starting position
680718 this . x = this . parent ? ( - this . parent . x + canvas . width / 2 - this . width / 2 ) : ( canvas . width / 2 - this . width / 2 ) ;
681719 this . y = this . parent ? ( - this . parent . y + canvas . height / 2 - this . height / 2 ) : ( canvas . height / 2 - this . height / 2 ) ;
682720 this . showing = false ;
683721 this . hiding = true ;
684722 } ;
723+ /**
724+ * @returns Returns true if this window is the topmost visible window.
725+ */
726+ isTopWindow ( ) : boolean {
727+ const jsWindows = JSWindow . getAllInstances ( ) as Array < JSWindow > ;
728+ let topWindow : JSWindow | null = null ;
729+ let topShowIndex = - Infinity ;
730+ for ( let i = 0 ; i < jsWindows . length ; i ++ ) {
731+ if ( jsWindows [ i ] . visible && jsWindows [ i ] . showIndex > topShowIndex ) {
732+ topShowIndex = jsWindows [ i ] . showIndex ;
733+ topWindow = jsWindows [ i ] ;
734+ }
735+ }
736+ return topWindow === this ;
737+ }
685738}
686739
687740export { TextButton , PlayerInfo , Ball , GameState , JSWindow } ;
0 commit comments