Alert text in dialogue box?

Discussions related to graphics (2D and 3D), animation and games programming
User avatar
5against4
Posts: 21
Joined: Tue 03 Apr 2018, 11:57
Location: The Cotswolds

Alert text in dialogue box?

Post by 5against4 »

i have a dialogue box with three drop-down menus; all three share the same options, but the choices made by the user mustn't include any duplications.

Is there any way to flag up an alert in the dialogue box if there's a duplication in order for the user to amend their selection? i've read carefully through the help doc for dialogue boxes and don't know if this would be possible within PROC_dlgitem? (TBH, i'm not really sure how to implement PROC_dlgitem in any case - it's ambiguous to me what it is and how it works.)

Ideally, the alert text would disappear after a couple of seconds, rather than staying there permanently.

And beyond this, can the text in dialogue boxes be formatted in any way other than its basic size (which is the same for everything in the box!)?
DDRM

Re: Alert text in dialogue box?

Post by DDRM »

Hi 5:4,

I'm assuming that this is for BB4W: I'm not familiar enough with the BBC_SDL equivalents to make useful comments, though these might give some hints if the library routines are sufficiently similar. Maybe someone else can offer comments on that?

You'll need to read the contents of the drop down boxes and do something based on the outcome. One solution would be to have a "static" item on your dialog box which you could set to either a "options need to be different" warning, or "all systems go!", as required. That could be either a bit of text or an image. Alternatively you could pop up a warning message box. In either case, you might want to disable the option to select "OK", either by greying it out, or by simply overriding it if clicked.

As far as I'm aware it's not possible to change the background colour of the standard controls - I know it's been discussed for edit controls in the past, and you CAN do it with a "rich edit" control, but not a standard one. That's where PROC_dlgitem comes in: it provides a generic way of calling CreateWindow. You'd need to have a look at the MSDN for this topic to find a suitable system class to call.

You will need to monitor the changes in the list boxes: you could either do this by polling them intermittently (and/or when something else in the dialogue gets activated), or you can look at the high 16 bits of wparam% for what has happened.

I'm assuming from the level of the questions that you are pretty comfortable with the manual and dialogue boxes and how they work, but if you need more specific guidance ask again, and I'll try to put together some demonstration code.

Best wishes,

D
User avatar
5against4
Posts: 21
Joined: Tue 03 Apr 2018, 11:57
Location: The Cotswolds

Re: Alert text in dialogue box?

Post by 5against4 »

DDRM wrote: Thu 21 Jun 2018, 08:57 I'm assuming that this is for BB4W…

You'll need to read the contents of the drop down boxes and do something based on the outcome. One solution would be to have a "static" item on your dialog box which you could set to either a "options need to be different" warning, or "all systems go!", as required. That could be either a bit of text or an image. Alternatively you could pop up a warning message box. In either case, you might want to disable the option to select "OK", either by greying it out, or by simply overriding it if clicked.
[…]
You will need to monitor the changes in the list boxes: you could either do this by polling them intermittently (and/or when something else in the dialogue gets activated), or you can look at the high 16 bits of wparam% for what has happened.

I'm assuming from the level of the questions that you are pretty comfortable with the manual and dialogue boxes and how they work, but if you need more specific guidance ask again, and I'll try to put together some demonstration code.
Yes, this is for BB4W - sorry, i was forgetting about the other incarnations.

When you say about reading the contents of the drop down boxes - is it possible to do that before the user has clicked on OK (i didn't think it was, but maybe i'm wrong)? If so, i can potentially disable the OK button until the conditions are met. If not, i'll likely have to stick with the override i'm currently using, which basically makes a rude noise and refuses to continue until they select correct options.

But let me know if you think there's a better way!

(Incidentally, i wouldn't say i'm that comfortable with dialogue boxes - in fact, until yesterday i'd never actually implemented them in my work, so consider me a bona fide noob! For example, "the high 16 bits of wparam%" is entirely lost on me…!)
DDRM

Re: Alert text in dialogue box?

Post by DDRM »

[takes a deep breath and tries to decide on a sensible level of reply, given my own ignorance, and wishing Richard were talking to us....]

Reading the content of controls: yes, you can get the contents at any time: have a look at the section towards the end of the "Dialog boxes" section of the manual, called "reading the contents of a dialog box". For example, it says you can use

Code: Select all

LB_GETCURSEL = 392
SYS "SendDlgItemMessage", !dlg%, id%, LB_GETCURSEL, 0, 0 TO sel%
... which will return the index of the currently selected line of a list box in sel%. If your 3 list boxes all have the same options (in the same order), the problem becomes as simple as ensuring that the values returned from the 3 list boxes are different. If you need the actual string, there's code there for that, too.

There are equivalent requests to get the current state of buttons, combo boxes, etc. Reading a text box is a little more complicated, but there's code in the same place to do that.

The significance of the wparam (and lparam) values depends a bit on how you handle the interrupts from the dialogue box. I tend to use the "old fashioned" approach of having an ON SYS statement, which detects when an interrupt occurs, and sends the relevant info to a handling routine. When Windows generates the interrupt, it passes you two parameters (wparam and lparam) which BB4W puts into it's own variables @wparam% and @lparam%. It's worth noting that these can be very transient: as soon as another interrupt occurs they will get overwritten, so it's good practice to copy them somewhere safe ASAP - usually by passing them as parameters to the handling routine, which will then have it's own local copy. Typically, the bottom 16 bits of @wparam% contain the ID of the item from which the message has originated - you can use this to decide what action needs taking (for example, if it's the "OK" button, you might want to read the values of all the other controls, and then close the dialogue box). In this case, if it's the list box, you might want to check the contents of the others, and grey out "OK" if there are common selections (or ungrey it once they are NOT the same!). You can get this info by using LowBits%=@wparam% AND &FFFF. Depending on the control, it may also return additional info in the top 16 bits of @wparam%: you can get this as HighBits%=@wparam%>>16.

Sorry, need to go and do some work. Get back to me if that doesn't make some sort of sense...
User avatar
5against4
Posts: 21
Joined: Tue 03 Apr 2018, 11:57
Location: The Cotswolds

Re: Alert text in dialogue box?

Post by 5against4 »

DDRM wrote: Fri 22 Jun 2018, 08:19 Reading the content of controls: yes, you can get the contents at any time: have a look at the section towards the end of the "Dialog boxes" section of the manual, called "reading the contents of a dialog box". For example, it says you can use

Code: Select all

LB_GETCURSEL = 392
SYS "SendDlgItemMessage", !dlg%, id%, LB_GETCURSEL, 0, 0 TO sel%
... which will return the index of the currently selected line of a list box in sel%. If your 3 list boxes all have the same options (in the same order), the problem becomes as simple as ensuring that the values returned from the 3 list boxes are different. If you need the actual string, there's code there for that, too.
Thanks for this - which i clearly hadn't taken in. Implementing it was easy, though i simply cannot get disabling/enabling the OK button to work in accordance with the logic check i'm doing. i've made a stripped-down version of the code below; when you get a chance if you could perhaps take a quick look over it and see what's tripping up this part, i'd be very grateful. The output simply displays the value of each combobox plus the OK status - but as you'll see, switching the OK button on and off doesn't work. i wonder if it's something to do with having multiple comboboxes, as it seemed to work okay with just one.

Code: Select all

      VDU 23,22,1920;1080;8,18,16,0:REM New mode: 1920x1080
      REMSYS "MoveWindow",@hwnd%,0,-1000,1920,1080,1:REM Shifts to second monitor
      SYS "ShowWindow", @hwnd%, 3 : REM Maximises window
      VDU 28,0,58,235,0
      PROCsetupinstruments:DIMorchestra$(1,1):orchestra$(0,0)="1":*FONT Consolas,14
      REM -------------------------------------------------------
      instrument1$="":instrument2$="":instrument3$=""

      REM. Program to demonstrate a Dialogue Box
      INSTALL @lib$+"WINLIB2"
      BS_DEFPUSHBUTTON = &1:CB_ADDSTRING = &143:CB_SETCURSEL = &14E:CBS_DROPDOWNLIST = &3:ES_AUTOHSCROLL = &80:ES_NUMBER = &2000:LB_ADDSTRING = &180
      LB_GETCURSEL = &188:UDM_SETRANGE = &465:UDS_ALIGNRIGHT = &4:UDS_AUTOBUDDY = &10:UDS_SETBUDDYINT = &2:WS_CHILD = &40000000:WS_GROUP = &20000:WS_VISIBLE = &10000000

      groupboxmargin=4:groupboxwidth=100:groupboxgap=10
      FOR defineplayer=1 TO VAL(orchestra$(0,0))
        defineplayer$="Define Player "+STR$(defineplayer)
        dlg%=FN_newdialog(defineplayer$, 300, 100, (groupboxwidth+groupboxgap)*3, 80, 10, 560)
        REM Setup groupbox regions
        FOR groupboxdisp=1 TO 3
          groupbox$="Specify instrument "+STR$(groupboxdisp)
          groupboxx=groupboxmargin+((groupboxdisp-1)*groupboxwidth)+((groupboxdisp-1)*groupboxgap)
          PROC_groupbox(dlg%, groupbox$, groupboxdisp, groupboxx, 4, groupboxwidth, 40, WS_GROUP)
          PROC_combobox(dlg%, "", 100+groupboxdisp, groupboxx+9, 18, 80, 100, CBS_DROPDOWNLIST)
        NEXT
        REM Set up OK/Cancel buttons
        pushbuttonwidth=56:OKbuttonx=groupboxmargin+groupboxwidth+(groupboxgap/2)-(pushbuttonwidth/2)
        Cancelbuttonx=groupboxmargin+(2*groupboxwidth)+(groupboxgap*1.5)-(pushbuttonwidth/2)
        PROC_pushbutton(dlg%, "OK",     1, OKbuttonx, 55, 56, 14, WS_GROUP OR BS_DEFPUSHBUTTON)
        PROC_pushbutton(dlg%, "Cancel", 2, Cancelbuttonx, 55, 56, 14, 0)
        PROC_showdialog(dlg%)
        REM Disable OK button
        SYS "GetDlgItem", !dlg%, 1 TO h%
        SYS "EnableWindow", h%, 0
  
        ON CLOSE PROC_closedialog(dlg%):QUIT
        ON ERROR PROC_closedialog(dlg%):PRINT'REPORT$:END
        REM Content for comboboxes
        FOR comboboxloop=0 TO instruments
          IF instruments$(comboboxloop,0)<>"x" THEN
            SYS "SendDlgItemMessage", !dlg%, 101, CB_ADDSTRING, 0, instruments$(comboboxloop,0)
            SYS "SendDlgItemMessage", !dlg%, 102, CB_ADDSTRING, 0, instruments$(comboboxloop,0)
            SYS "SendDlgItemMessage", !dlg%, 103, CB_ADDSTRING, 0, instruments$(comboboxloop,0)
          ENDIF
        NEXT
  
        Click%=0
        ON SYS Click% = @wparam% : RETURN
        instrumentokay=FALSE
        REPEAT
          WAIT 10:CB_GETCURSEL = 327
          SYS "SendDlgItemMessage", !dlg%, 101, CB_GETCURSEL, 0, 0 TO sel%:i1=sel%
          SYS "SendDlgItemMessage", !dlg%, 102, CB_GETCURSEL, 0, 0 TO sel%:i2=sel%
          SYS "SendDlgItemMessage", !dlg%, 103, CB_GETCURSEL, 0, 0 TO sel%:i3=sel%
          VDU4:PRINTi1,i2,i3;SPC(10);"OK = ";instrumentokay
          IF i1>0 AND i1<>i2 AND i1<>i3 THEN instrumentokay=TRUE ELSE instrumentokay=FALSE
          IF instrumentokay=TRUE AND i2=i3 AND i2>0 THEN instrumentokay=FALSE
          IF instrumentokay=TRUE THEN
            REM Enable OK button
            SYS "GetDlgItem", !dlg%, 1 TO h%
            SYS "EnableWindow", h%, 1
          ELSE
            REM Enable OK button
            SYS "GetDlgItem", !dlg%, 1 TO h%
            SYS "EnableWindow", h%, 0
          ENDIF
          click%=0
          SWAP Click%, click%
        UNTIL click%=1 OR click%=2 OR !dlg%=0
        IF click%=1 THEN
          DIM text% 255:SYS "GetDlgItemText", !dlg%, 101, text%, 255:instrument1$=$$text%
          DIM text% 255:SYS "GetDlgItemText", !dlg%, 102, text%, 255:instrument2$=$$text%
          DIM text% 255:SYS "GetDlgItemText", !dlg%, 103, text%, 255:instrument3$=$$text%
        ELSE
          PRINT "Cancel pressed"
        ENDIF
        PROC_closedialog(dlg%)
        PRINT"instrument1 = ";instrument1$
        PRINT"instrument2 = ";instrument2$
        PRINT"instrument3 = ";instrument3$
      NEXT
      END
      REM --------------------------------------------------------------------------
      DEFPROCsetupinstruments
      REM Setup instruments
      instruments=80:DIM instruments$(instruments,2)
      RESTORE +2
      REM 1. Woodwind
      DATA piccolo,62,96,flute,48,86,alto flute,43,86,bass flute,36,72,oboe,48,81,cor anglais,40,72,bass oboe,33,67,x,x,x
      DATA Eb clarinet,43,84,Bb clarinet,38,82,bass clarinet,25,70,contrabass clarinet,13,48,bassoon,22,67,contrabassoon,9,48,x,x,x,x,x,x
      REM 2. Brass
      DATA horn,22,65,x,x,x,x,x,x,x,x,x,piccolo trumpet,52,79,trumpet,40,72,flügelhorn,40,70,x,x,x
      DATA trombone,16,62,bass trombone,16,62,x,x,x,x,x,x,tenor tuba,19,62,bass tuba,14,53,x,x,x,x,x,x
      REM 3. Strings
      DATA violin,43,93,viola,36,88,cello,24,72,double bass,12,55,harp,11,90,x,x,x,x,x,x,x,x,x
      DATA x,x,x,x,x,x,x,x,x,x,x,x
      DATA x,x,x,x,x,x,x,x,x,x,x,x
      REM 4a. Pitched Percussion
      DATA piano,9,96,glockenspiel,60,96,celesta,48,96,crotales,72,84,tubular bells,48,65,xylophone,53,96,marimba,36,84,vibraphone,41,77
      DATA handbells,48,59,x,x,x,x,x,x,gongs,-1,5,x,x,x,x,x,x,x,x,x,x,x,x
      REM 4b. Unpitched Percussion
      DATA bass drum,-1,1,snare drum,-1,1,tenor drum,-1,1,tambourine,-1,1,triangle,-1,3,wood block,-1,1,suspended cymbal,-1,1,tam-tams,-1,8
      DATA rototoms,-1,6,chinese cymbals,-1,3,wine glasses,-1,12,kalimba,-1,6,lion's roar,-1,1,x,x,x,x,x,x,x,x,x
      FOR loop=1 TO instruments:READ instruments$(loop,0),instruments$(loop,1),instruments$(loop,2):NEXT
      REMPROCnewline(1):OSCLIdiagfont$:GCOL0,7:PRINT"Instruments setup completed."
      ENDPROC
DDRM

Re: Alert text in dialogue box?

Post by DDRM »

OK, that was a bit of a weird one. I played with various things, but then I remembered vaguely that "OK" and "Cancel" have a special status - they are, if you like "default" options, and don't behave like "your own" buttons.

If you change the ID of the "OK" button (I arbitrarily chose 51 below), it works as expected! Arguably that is naughty, because you are subverting the wishes of Microsoft, but frankly, my dear, I.....

I've made a few other changes you might want to consider: you shouldn't put DIMs inside a loop, or you will gradually (quite fast?) fill up your entire memory with new versions of the saved space. All you are doing is creating a temporary buffer for the SYS call to dump the answer in, so there's no reason not to re-use it. I've moved a few other things that don't need repeating out, too. I've also tidied up the logic around collecting the instruments and checking they don't match. See what you think.

Best wishes,

D

Code: Select all

      MODE 21
      REM VDU 23,22,1920;1080;8,18,16,0:REM New mode: 1920x1080
      REMSYS "MoveWindow",@hwnd%,0,-1000,1920,1080,1:REM Shifts to second monitor
      REM SYS "ShowWindow", @hwnd%, 3 : REM Maximises window
      VDU 28,0,58,235,0
      PROCsetupinstruments:DIMorchestra$(1,1):orchestra$(0,0)="1":*FONT Consolas,14
      REM -------------------------------------------------------
      instrument1$="":instrument2$="":instrument3$=""

      REM. Program to demonstrate a Dialogue Box
      INSTALL @lib$+"WINLIB2"
      BS_DEFPUSHBUTTON = &1:CB_ADDSTRING = &143:CB_SETCURSEL = &14E:CBS_DROPDOWNLIST = &3:ES_AUTOHSCROLL = &80:ES_NUMBER = &2000:LB_ADDSTRING = &180
      LB_GETCURSEL = &188:UDM_SETRANGE = &465:UDS_ALIGNRIGHT = &4:UDS_AUTOBUDDY = &10:UDS_SETBUDDYINT = &2:WS_CHILD = &40000000:WS_GROUP = &20000:WS_VISIBLE = &10000000

      groupboxmargin=4:groupboxwidth=100:groupboxgap=10
      FOR defineplayer=1 TO VAL(orchestra$(0,0))
        defineplayer$="Define Player "+STR$(defineplayer)
        dlg%=FN_newdialog(defineplayer$, 300, 100, (groupboxwidth+groupboxgap)*3, 80, 10, 560)
        REM Setup groupbox regions
        FOR groupboxdisp=1 TO 3
          groupbox$="Specify instrument "+STR$(groupboxdisp)
          groupboxx=groupboxmargin+((groupboxdisp-1)*groupboxwidth)+((groupboxdisp-1)*groupboxgap)
          PROC_groupbox(dlg%, groupbox$, groupboxdisp, groupboxx, 4, groupboxwidth, 40, WS_GROUP)
          PROC_combobox(dlg%, "", 100+groupboxdisp, groupboxx+9, 18, 80, 100, CBS_DROPDOWNLIST)
        NEXT
        REM Set up OK/Cancel buttons
        pushbuttonwidth=56:OKbuttonx=groupboxmargin+groupboxwidth+(groupboxgap/2)-(pushbuttonwidth/2)
        Cancelbuttonx=groupboxmargin+(2*groupboxwidth)+(groupboxgap*1.5)-(pushbuttonwidth/2)
        PROC_pushbutton(dlg%, "OK",     51, OKbuttonx, 55, 56, 14, WS_GROUP OR BS_DEFPUSHBUTTON)
        PROC_pushbutton(dlg%, "Cancel", 2, Cancelbuttonx, 55, 56, 14, 0)
        PROC_showdialog(dlg%)
        REM Disable OK button
        SYS "GetDlgItem", !dlg%, 1 TO h%
        SYS "EnableWindow", h%, 0
  
        ON CLOSE PROC_closedialog(dlg%):QUIT
        ON ERROR PROC_closedialog(dlg%):PRINT'REPORT$:END
        REM Content for comboboxes
        FOR comboboxloop=0 TO instruments
          IF instruments$(comboboxloop,0)<>"x" THEN
            SYS "SendDlgItemMessage", !dlg%, 101, CB_ADDSTRING, 0, instruments$(comboboxloop,0)
            SYS "SendDlgItemMessage", !dlg%, 102, CB_ADDSTRING, 0, instruments$(comboboxloop,0)
            SYS "SendDlgItemMessage", !dlg%, 103, CB_ADDSTRING, 0, instruments$(comboboxloop,0)
          ENDIF
        NEXT
  
        Click%=0
        ON SYS Click% = @wparam% : RETURN
        instrumentokay=FALSE
        REM Moved a few things out of the loop that don't need repeating
        DIM text% 255
        VDU4
        CB_GETCURSEL = 327
        SYS "GetDlgItem", !dlg%, 51 TO h%
        PRINT h%;"Button handle"
  
        REPEAT
          WAIT 10
          REM Tidied the logic up a bit here, so I can see what's happening...
          SYS "SendDlgItemMessage", !dlg%, 101, CB_GETCURSEL, 0, 0 TO i1%
          SYS "SendDlgItemMessage", !dlg%, 102, CB_GETCURSEL, 0, 0 TO i2%
          SYS "SendDlgItemMessage", !dlg%, 103, CB_GETCURSEL, 0, 0 TO i3%
          instrumentokay=FALSE
          IF i1%>0 AND i2%>0 AND i3%>0 AND i1%<>i2% AND i1%<>i3% AND i2%<>i3% THEN instrumentokay=TRUE
          IF instrumentokay THEN
            REM Enable OK button
            SYS "EnableWindow", h%, 1
          ELSE
            REM Disable OK button
            SYS "EnableWindow", h%, 0
          ENDIF
          PRINTi1%,i2%,i3%;SPC(10);"OK = ";instrumentokay
          click%=0
          SWAP Click%, click%
        UNTIL click%=51 OR click%=2 OR !dlg%=0
        IF click%=51 THEN
          SYS "GetDlgItemText", !dlg%, 101, text%, 255:instrument1$=$$text%
          SYS "GetDlgItemText", !dlg%, 102, text%, 255:instrument2$=$$text%
          SYS "GetDlgItemText", !dlg%, 103, text%, 255:instrument3$=$$text%
        ELSE
          PRINT "Cancel pressed"
        ENDIF
        PROC_closedialog(dlg%)
        PRINT"instrument1 = ";instrument1$
        PRINT"instrument2 = ";instrument2$
        PRINT"instrument3 = ";instrument3$
      NEXT
      END
      REM --------------------------------------------------------------------------
      DEFPROCsetupinstruments
      REM Setup instruments
      instruments=80:DIM instruments$(instruments,2)
      RESTORE +2
      REM 1. Woodwind
      DATA piccolo,62,96,flute,48,86,alto flute,43,86,bass flute,36,72,oboe,48,81,cor anglais,40,72,bass oboe,33,67,x,x,x
      DATA Eb clarinet,43,84,Bb clarinet,38,82,bass clarinet,25,70,contrabass clarinet,13,48,bassoon,22,67,contrabassoon,9,48,x,x,x,x,x,x
      REM 2. Brass
      DATA horn,22,65,x,x,x,x,x,x,x,x,x,piccolo trumpet,52,79,trumpet,40,72,flügelhorn,40,70,x,x,x
      DATA trombone,16,62,bass trombone,16,62,x,x,x,x,x,x,tenor tuba,19,62,bass tuba,14,53,x,x,x,x,x,x
      REM 3. Strings
      DATA violin,43,93,viola,36,88,cello,24,72,double bass,12,55,harp,11,90,x,x,x,x,x,x,x,x,x
      DATA x,x,x,x,x,x,x,x,x,x,x,x
      DATA x,x,x,x,x,x,x,x,x,x,x,x
      REM 4a. Pitched Percussion
      DATA piano,9,96,glockenspiel,60,96,celesta,48,96,crotales,72,84,tubular bells,48,65,xylophone,53,96,marimba,36,84,vibraphone,41,77
      DATA handbells,48,59,x,x,x,x,x,x,gongs,-1,5,x,x,x,x,x,x,x,x,x,x,x,x
      REM 4b. Unpitched Percussion
      DATA bass drum,-1,1,snare drum,-1,1,tenor drum,-1,1,tambourine,-1,1,triangle,-1,3,wood block,-1,1,suspended cymbal,-1,1,tam-tams,-1,8
      DATA rototoms,-1,6,chinese cymbals,-1,3,wine glasses,-1,12,kalimba,-1,6,lion's roar,-1,1,x,x,x,x,x,x,x,x,x
      FOR loop=1 TO instruments:READ instruments$(loop,0),instruments$(loop,1),instruments$(loop,2):NEXT
      REMPROCnewline(1):OSCLIdiagfont$:GCOL0,7:PRINT"Instruments setup completed."
      ENDPROC
User avatar
5against4
Posts: 21
Joined: Tue 03 Apr 2018, 11:57
Location: The Cotswolds

Re: Alert text in dialogue box?

Post by 5against4 »

Thanks a lot for this, i really appreciate you taking a look at it.

As it happens, you broke the logic but that's by the by as the other things you noted have sorted things out nicely. Silly of me not to have realised i'd put those DIMs within the loop (would never usually do that). The OK button ID issue is a bit weird, isn't it? But hey, as long as it works using an ID other than 1 is absolutely fine by me!

So thank you very much! i haven't bothered using dialogue boxes before but i'm glad to have (more or less) got my head around them - with your very kind help :) *tips hat*