Simple non-modal custom dialog box closing automatically

Share your advanced PureBasic knowledge/code with the community.
User avatar
Blue
Addict
Addict
Posts: 967
Joined: Fri Oct 06, 2006 4:41 am
Location: Canada

Simple non-modal custom dialog box closing automatically

Post by Blue »

:: coded in PB 5.10, updated for PB 5.31 ::
:: 99% cross-platform (1% : see line 109) ::

It is quite easy to create a
custom non-modal dialog box that closes automatically
when the user clicks outside of it

The secret is to simply watch for #WM_LBUTTONUP and #WM_RBUTTONUP events occuring in the parent window.

Below is a full example. Wordy, so things are clearly demontrated 8), but still short :D
Lines 109-118 of the source code is where the concept is applied.

This may be of interest to newcomers to PureBasic or to Windows programming.

Code: Select all

;- ***** ***** ***** ***** ***** ***** *****
;- Blue - September 2013
;- --- --- --- --- --- --- --- --- --- ---
;- Child Window that closes 
;- ... when click detected outside of it
;- ***** ***** ***** ***** ***** ***** *****
; the child (technically correct : secondary) window has its own event loop

EnableExplicit

;{ constants
;- constants
;- .... for convenience
#enAttente = " Just waiting..."

#text = #PB_Gadget_FrontColor
#back = #PB_Gadget_BackColor

#colourF = $F4F7F9  ; child window background
#colourB = $FFFFFF  ; text box background 
#colourT = $FF0000  ; text
#colourL = $0779F8  ; labels

Enumeration   ; fenêtres
  #main_WINDOW
  #child_WINDOW
EndEnumeration

;- .... for gadgets
Enumeration
  #cmdOK
  #cmdANNULER
  #infoLABEL
  #infoBOX
  
  #F2_cmdOK
  #F2_cmd2
  #F2_cmd3

  #F2_cadre1
  #F2_cadre2
  #F2_cadreLABEL
EndEnumeration
;}

;- --- --- --- --- --- --- --- --- --- --- --- ---
Procedure Child_Window()
  Define winH = 120
  Define winW = WindowWidth(#main_WINDOW) * 0.66


  If 0 = OpenWindow(#child_WINDOW, 0, 0, winW, winH, "Busy Body", 
                    #PB_Window_BorderLess | #PB_Window_WindowCentered, 
                    windowID(#main_WINDOW))
    
    SetGadgetText(#infoBox, " Child window could not be created")
    ProcedureReturn 
  EndIf
  SetWindowColor(#child_WINDOW,#colourF)
  SetGadgetText(#infoBox, " Click anywhere outside the child window to close it. ")

  ;{ gadgets hiding here
  ;- .... gadgets
  Define gadget, gX,gY, gW,gH
  
  gX = 1
  gY = 1
  gW = winW - (gX * 2)
  gH = winH - (gY * 2)
  FrameGadget(#F2_cadre1, gX, gY, gW,gH, "", #PB_Frame_Flat)
  
  gX + 8
  gY + 8
  gW = winW - (gX * 2)
  gH = winH - (gY * 2)
  FrameGadget(#F2_cadre2, gX,gY, gW,gH, "")

  gadget = #F2_cadreLABEL
    gX + 8
    gW = 80
    gH = 18
    TextGadget(gadget, gX,gY, gW,gH, "Child window",#PB_Text_Center)
    SetGadgetColor(gadget, #back,#colourF)
    SetGadgetColor(gadget, #text, #colourL)

  #dX = 12
  gW = 100
  gX + #dX
  gY + 24
  gH = 25
  ButtonGadget(#F2_cmd2, gX,gY, gW,gH, "Something")

  gX + gW + #dX
  ButtonGadget(#F2_cmd3, gX,gY, gW,gH, "Something else")

  gW = 70
  gH = 32
  gX = GadgetWidth(#F2_cadre2) - gW
  gY = GadgetHeight(#F2_cadre2) - gH
  ButtonGadget(#F2_cmdOK, gX,gY, gW,gH, "OK", #PB_Button_Default)
  ;}

  ;- .... event loop
  Define event, gadget, window
  Repeat
    event = WaitWindowEvent()
    window = EventWindow()

    If window <> #child_WINDOW           ;- ...  [109] >> catching outside events
    ; events occuring OUTSIDE our dialog box are intercepted here, 
    ; therefore preempting actions tied to gadgets in the main window
      SetActiveWindow(#child_WINDOW)
      Select event
       ;Case #PB_Event_CloseWindow  : Break                      ; uncomment to have the main close button close the child window
        Case #WM_LBUTTONUP, #WM_RBUTTONUP : Break                ; mouse clicked : the loop's work is done. (Windows OS only)
       ;Case #PB_Event_LeftClick, #PB_Event_RightClick : Break   ; cross-platform : comment above line (won't catch clicks on buttons)
      EndSelect
     ;Debug "event = "+ Str(event) + "  gadget = "+ Str(gadget) 
      Continue     ; disregard everything
    EndIf

    Select event
      Case #PB_Event_Gadget
        gadget = EventGadget()
        Select gadget
          Case #F2_cmd2 : SetGadgetText(#infoBox,"The child window is busy doing something...")
          Case #F2_cmd3 : SetGadgetText(#infoBox,"The child window is doing something else...")
          Case #F2_cmdOK : Break
          Default        : SetGadgetText(#infoBox,"gadget #" + Str(gadget))
        EndSelect
    EndSelect
  ForEver

  CloseWindow(#child_WINDOW)
  SetGadgetText(#infoBox, #enAttente)
EndProcedure  ; _Child_Window_

Procedure Main_Window()
  Define winH = 280
  Define winW = 400
  If 0 = OpenWindow(#main_WINDOW, 0, 0, winW, winH, "Main Window", 
                    #PB_Window_SystemMenu | #PB_Window_ScreenCentered)
    End
  EndIf

  ;- .... gadgets
  Define gadget, gX,gY, gW,gH
  #marge = 10

  gX = #marge
  gY = #marge
  gW = 130
  gH = 25
  ButtonGadget(#cmdOK, gX,gY, gW,gH, "Open child window", #PB_Button_Default)

  gH = 36
  gW = 90
  gX = winW - gW - #marge
  gY = winH - gH - #marge
  ButtonGadget(#cmdANNULER, gX,gY, gW,gH, "Quit") 

  gadget = #infoLABEL
    gX = #marge
    gW = 90
    gH = 22
    gY - gH 
    TextGadget(gadget, gX,gY, gW,gH, "INFORMATION :")
    SetGadgetColor(gadget, #text,#colourL)

  gadget = #infoBOX
    gX + gW
    gW = winW - gX - #marge
    gH = 24
    gY - 5
    TextGadget(gadget, gX,gY, gW,gH, "",#PB_Text_Border)
    SetGadgetColor(gadget, #back, #colourB)
    SetGadgetColor(gadget, #text, #colourT)
EndProcedure  ; _Main_Window_

;- --- --- --- --- --- --- --- --- --- --- --- ---

;- main event loop
Define event, evType, gadget
Define fenetre

Main_Window()
SetGadgetText(#infoBox,#enAttente)

Repeat
  event = WaitWindowEvent()
  
  Select event
    Case #PB_Event_CloseWindow : Break
    Case #PB_Event_Gadget :
      gadget = EventGadget()
      Select gadget
        Case #cmdANNULER : Break
        Case #cmdOK      : Child_Window()
      EndSelect
  EndSelect
  
ForEver

End
I hope someone will find it useful.

[UpDate]
Changes made (colour constants and 2 events) to render code cross-platform
Last edited by Blue on Mon Sep 21, 2015 10:40 pm, edited 3 times in total.
PB Forums : Proof positive that 2 heads (or more...) are better than one :idea:
User avatar
ts-soft
Always Here
Always Here
Posts: 5756
Joined: Thu Jun 24, 2004 2:44 pm
Location: Berlin - Germany

Re: Simple way to create custom non-modal dialog box

Post by ts-soft »

Nice example, but
Blue wrote::: cross-platform (I think!) ::
No, no :wink:
Some WinAPI examples:
#WM_LBUTTONUP, #WM_RBUTTONUP, #Red and so on!
PureBasic 5.73 | SpiderBasic 2.30 | Windows 10 Pro (x64) | Linux Mint 20.1 (x64)
Old bugs good, new bugs bad! Updates are evil: might fix old bugs and introduce no new ones.
Image
User avatar
Blue
Addict
Addict
Posts: 967
Joined: Fri Oct 06, 2006 4:41 am
Location: Canada

Re: Simple way to create custom non-modal dialog box

Post by Blue »

ts-soft wrote:Nice example, but
Blue wrote::: cross-platform (I think!) ::
No, no :wink:
Some WinAPI examples:
#WM_LBUTTONUP, #WM_RBUTTONUP, #Red and so on!
Thank you very much, ts-soft, for catching this so quickly.

Gosh, darn it, I always thought of those as PB constants !
How foolish !

I think replacing #Red by its Hex value will make that one cross-platform (right ? :? ), but i have no idea what should replace the #WM_LBUTTONUP, #WM_RBUTTONUP constants. Have you ?

I know #PB_Event_LeftClick and #PB_Event_RightClick won't work, since those events won't fire on all gadgets (buttons, for instance).

Anyway, i'll try a few things and correct the presentation of my topic if I can't find a cross-platform solution.
PB Forums : Proof positive that 2 heads (or more...) are better than one :idea:
RASHAD
PureBasic Expert
PureBasic Expert
Posts: 4954
Joined: Sun Apr 12, 2009 6:27 am

Re: Simple non-modal custom dialog box closing automatically

Post by RASHAD »

Hi Blue
Replace :

Code: Select all

Case #WM_LBUTTONUP, #WM_RBUTTONUP
 
With :

Code: Select all

Case #PB_Event_LeftClick,#PB_Event_RightClick
Replace #Red,#Yellow,#Blue with HEX eq. etc $0000FF
And please use Light Gray or Light Yellow instead :P
Egypt my love
User avatar
Blue
Addict
Addict
Posts: 967
Joined: Fri Oct 06, 2006 4:41 am
Location: Canada

Re: Simple non-modal custom dialog box closing automatically

Post by Blue »

RASHAD wrote:Hi Blue
Replace :

Code: Select all

Case #WM_LBUTTONUP, #WM_RBUTTONUP
 
With :

Code: Select all

Case #PB_Event_LeftClick,#PB_Event_RightClick
Replace #Red,#Yellow,#Blue with HEX eq. etc $0000FF
And please use Light Gray or Light Yellow instead :P
Well... hello Mr Windows Magic.
Exactly what i was planning to do.

And please be specific: which colour do you wish me to replace with Light Gray :( exactly ?
Not my beloved Ultra Bright Yellow, i hope. It matches the colour of my teeth so well.
Besides, people curious enough to try this code are free to choose whichever colour they please.
It's only a matter of changing a single constant.

As for #WM_LBUTTONUP and #WM_RBUTTONUP, i was using them because they reported a click on anything in the other window. #PB_Event_LeftClick and #PB_Event_RightClick don't report clicks on the the button gadgets from the main window.

Try the code with #PB_Event_LeftClick and #PB_Event_RightClick, Rashad, and you'll see.
Let me know if you think of an alternative.

Thanks for the useful input, as always.
PB Forums : Proof positive that 2 heads (or more...) are better than one :idea:
User avatar
Blue
Addict
Addict
Posts: 967
Joined: Fri Oct 06, 2006 4:41 am
Location: Canada

Re: Simple non-modal custom dialog box closing automatically

Post by Blue »

I changed the code to make it *** MOSTLY *** cross-platform compatible.

colour constants : Hex values to replace Microsoft's constants
events : replaced #WM_LBUTTONUP by #PB_Event_LeftClick, and #WM_RBUTTONUP by #PB_Event_RightClick

in Windows, using the PB constants reduces the functionality of the code, since clicks on ButtonGadgets are not detected. So, in Windows, it's better to keep using the #WM_xxx symbolic constants.

PS >> ... plus i changed the yellow background to a yucky beige to accomodate Rashad's poor eyesight. :cry:
Last edited by Blue on Mon Sep 28, 2015 8:12 pm, edited 1 time in total.
PB Forums : Proof positive that 2 heads (or more...) are better than one :idea:
RASHAD
PureBasic Expert
PureBasic Expert
Posts: 4954
Joined: Sun Apr 12, 2009 6:27 am

Re: Simple non-modal custom dialog box closing automatically

Post by RASHAD »

Hi Blue
I am not sure about all your aims but I just tried my best to get as much as I can :)
I hope I am around not far

Remember PureBasic rule #1
Only one event loop

Code: Select all

Procedure move()
 ResizeWindow(1,WindowX(0)+150,WindowY(0)+125,300,150)
EndProcedure

LoadFont(0,"Georgia",14)

OpenWindow(0,0,0,600,400,"Win #1",#PB_Window_SystemMenu|#PB_Window_ScreenCentered)
ButtonGadget(0,10,10,100,20,"Open Window")
ButtonGadget(1,530,350,60,30,"QUIT")
TextGadget(2,10,360,200,30,"This is a test....",#PB_Text_Border)
SetGadgetFont(2,FontID(0))
OpenWindow(1,0,0,300,150,"Win #2",#PB_Window_BorderLess|#PB_Window_WindowCentered| #PB_Window_Invisible,WindowID(0))
SetWindowColor(1,$0000FF)
UseGadgetList(WindowID(1))
ContainerGadget(10,0,0,300,150,#PB_Container_Raised)
  SetGadgetColor(10,#PB_Gadget_BackColor,$DFFEFC)
  FrameGadget(11,15,15,260,110,"Child Window");,#PB_Frame_Single)
  ButtonGadget(12,210,90,60,30,"OK")
CloseGadgetList()

BindEvent(#PB_Event_MoveWindow,@Move())

Repeat
Select WaitWindowEvent()
;    Case #PB_Event_CloseWindow
;       Quit = 1
   Case #PB_Event_LeftClick,#PB_Event_RightClick
       If GetActiveWindow() = 0
          HideWindow(1,1)
          Flag = 0
       EndIf
          
   Case #PB_Event_Gadget
      Select EventGadget()
         Case 0
            If Flag = 0
              HideWindow(1,0)
              Flag = 1
            Else
              HideWindow(1,1)
              Flag = 0
            EndIf
            
         Case 1
            If Flag = 1
              HideWindow(1,1)
              Flag = 0
            Else
              Break
            EndIf
            
         Case 12
            HideWindow(1,1)
            Flag = 0
      EndSelect
EndSelect
Until Quit = 1
Egypt my love
User avatar
Blue
Addict
Addict
Posts: 967
Joined: Fri Oct 06, 2006 4:41 am
Location: Canada

Re: Simple non-modal custom dialog box closing automatically

Post by Blue »

RASHAD wrote:Hi Blue
I am not sure about all your aims but I just tried my best to get as much as I can :)
My aim is exactly as spelled out in the Topic title , Rashad : showing off a method to make a secondary dialog box (it can be a Help Sticky displayed temporarily, an input dialog, an 'About..." box, whatever...) that quietly goes away when the user clicks outside its real estate.

I believe my code does just that, although not, as i originally claimed, in a 100% cross-platform way. So that had to be set straight right away.
And I put this demo in this section of the forum, because it's called Tricks 'n' Tips.
That's all.

I didn't realize 'Only one event loop' was a golden rule. But, by breaking it to enclose my secondary window and all its attending code into a procedure, i have considerably lightened the main loop in my current 5 600 lines project. In particular, it has made debugging, and navigating the logic of the program, a lot easier. So i'm inclined to move in that direction for a lot of my self-vanishing secondary service windows.

Your method -- very clever BTW, and showing some good ideas definitely worth stealing :shock: -- obviously works too, but presents a very different concept, requiring that 2 windows be kept alive, which may or may not be viable in all circumstances. Plus, of course, there's the need to check which window is alive for EVERY single gadget in window #1. :!: This is leading into a very interesting discussion. However, i believe this particular section of the forum is not the proper venue for it. Perhaps the "Coding Questions' section ? :wink:

Anyway, I thought the golden rule was 'one loop if it's modal, separate loops if not', or is it the other way around ? :oops:
I'll have to ask Danilo or ts-soft or maybe Rashad again... :?

Cheers.
Last edited by Blue on Tue Sep 22, 2015 2:35 am, edited 2 times in total.
PB Forums : Proof positive that 2 heads (or more...) are better than one :idea:
RASHAD
PureBasic Expert
PureBasic Expert
Posts: 4954
Joined: Sun Apr 12, 2009 6:27 am

Re: Simple non-modal custom dialog box closing automatically

Post by RASHAD »

I knew that you will get angry :D
But I could not help it because I scratched my head for a trick to come over the mouse event but no way (in case of cross platform)
Just forget about cross platform and you are safe :wink:
Egypt my love
User avatar
Blue
Addict
Addict
Posts: 967
Joined: Fri Oct 06, 2006 4:41 am
Location: Canada

Re: Simple non-modal custom dialog box closing automatically

Post by Blue »

RASHAD wrote:I knew that you will get angry :D
But I could not help it because I scratched my head for a trick to come over the mouse event but no way (in case of cross platform)
Just forget about cross platform and you are safe :wink:
Glad you shoved a smiley at the end of that first sentence, Rashad. 8)
'Cause angry i am NOT.
I always welcome your 2 pennies of Tips'N'Tricks and enjoy exchanging with you.
I like it when you start scratching your head : it's a sure sign of good things to come.

So keep scratching, Rashad, and if you need a scalp doctor, i know a good one in Luxor :lol:
PB Forums : Proof positive that 2 heads (or more...) are better than one :idea:
RASHAD
PureBasic Expert
PureBasic Expert
Posts: 4954
Joined: Sun Apr 12, 2009 6:27 am

Re: Simple non-modal custom dialog box closing automatically

Post by RASHAD »

That doctor you mentioned I know him :P
I wish you meet him one day to get rid of you :mrgreen:
Egypt my love
User avatar
TI-994A
Addict
Addict
Posts: 2741
Joined: Sat Feb 19, 2011 3:47 am
Location: Singapore
Contact:

Re: Simple non-modal custom dialog box closing automatically

Post by TI-994A »

Blue wrote:I didn't realize 'Only one event loop' was a golden rule.
For what it's worth, it's not; if structured correctly. :wink:
Texas Instruments TI-99/4A Home Computer: the first home computer with a 16bit processor, crammed into an 8bit architecture. Great hardware - Poor design - Wonderful BASIC engine. And it could talk too! Please visit my YouTube Channel :D
infratec
Always Here
Always Here
Posts: 7620
Joined: Sun Sep 07, 2008 12:45 pm
Location: Germany

Re: Simple non-modal custom dialog box closing automatically

Post by infratec »

Hi,

Crossplatform (I hope)

Code: Select all

Procedure CloseAboutWindow()
  CloseWindow(EventWindow())
EndProcedure

Procedure About(Timeout.i=0)
  Win = OpenWindow(#PB_Any, 0, 0, 200, 100, "About", #PB_Window_Tool|#PB_Window_ScreenCentered)
  TextGadget(#PB_Any, 10, 10, 100, 20, "About")
  BindEvent(#PB_Event_DeactivateWindow, @CloseAboutWindow(), Win)
  If Timeout
    AddWindowTimer(Win, 1, Timeout)
    BindEvent(#PB_Event_Timer, @CloseAboutWindow(), Win)
  EndIf
EndProcedure


OpenWindow(0, 0, 0, 400, 300, "Test", #PB_Window_SystemMenu|#PB_Window_ScreenCentered)

ButtonGadget(0, 10, 10, 50, 20, "About")

Repeat
 
  Event = WaitWindowEvent()
 
  If Event = #PB_Event_Gadget
    About(3000)
  EndIf
 
Until Event = #PB_Event_CloseWindow
Look at page 3 for a version which works with #PB_Window_WindowCentered.

Bernd
Last edited by infratec on Wed Sep 30, 2015 1:53 pm, edited 2 times in total.
User avatar
Vera
Addict
Addict
Posts: 858
Joined: Tue Aug 11, 2009 1:56 pm
Location: Essen (Germany)

Re: Simple non-modal custom dialog box closing automatically

Post by Vera »

Hello Blue,
Maybe let time decide ? ~ Image

Code: Select all

Global about, TimeRuns

Procedure About() 
  TimeRuns = OpenWindow(#PB_Any, 0, 0, 200, 100, "About", #PB_Window_BorderLess | #PB_Window_ScreenCentered)
  SetWindowColor(TimeRuns, $8A1517)
  tex=TextGadget(#PB_Any, 10, 20, 150, 22, " Time is on your side", #PB_Text_Border|#PB_Text_Center)
  SetGadgetColor(tex, #PB_Gadget_FrontColor, $00CCFF) : SetGadgetColor(tex, #PB_Gadget_BackColor, $682651)
  SetActiveWindow(TimeRuns)
  AddWindowTimer(TimeRuns, 123, 1000) 
  about = 1 
EndProcedure

OpenWindow(0, 0, 0, 400, 300, "Test", #PB_Window_SystemMenu|#PB_Window_ScreenCentered)
ButtonGadget(0, 10, 20, 150, 22, "About Time")

Repeat
  Event = WaitWindowEvent()
  
  If Event = #PB_Event_Timer And about And GetActiveWindow() > -1 And GetActiveWindow() <> TimeRuns
     RemoveWindowTimer(TimeRuns, 123) : CloseWindow(TimeRuns) : about = 0
  EndIf
  
  If Event = #PB_Event_Gadget
    About()
  EndIf
 
Until Event = #PB_Event_CloseWindow
RASHAD
PureBasic Expert
PureBasic Expert
Posts: 4954
Joined: Sun Apr 12, 2009 6:27 am

Re: Simple non-modal custom dialog box closing automatically

Post by RASHAD »

@Bernd
@Vera
You are dead meat :mrgreen:
Just wait for Blue
Egypt my love
Post Reply