Mouseover detection

Started by stevengraff, December 14, 2013, 06:26:43 AM

Previous topic - Next topic

stevengraff

Is there any way, while my dialog is up, to detect that the user has moved the mouse over a control? I'd like to change the button text from black to green when the mouse is over a button. Or raise a hint, explaining what the control does, or how a given setting works.

....IFICantBYTE

Yes, there is... you will need to do a couple of DllCalls and use a timer.
There are a few examples in the Tech Database... try searching for Mouseover or hover or even balloontips for a different way and look in the dialog sections.
Regards,
....IFICantBYTE

Nothing sucks more than that moment during an argument when you realize you're wrong. :)

Deana

Give this code a t try:

Code (winbatch) Select
#DefineSubRoutine TMOD(TMODhnd,TMODevent,ctrlnum,rsvd1,rsvd2)
   Select    TMODevent
    Case 0
      DialogProcOptions(TMODhnd, 1,500) ;Initialize Timer at .5 of a second intervals.
      Return -1
    Case 1 ;Timer event fired
      If udfMouseOver(TMODhnd,3)==3 ;If the udf returns the same control number we passed it, then mouse is over it
         DialogControlSet(TMODhnd,"VaryText_1",4,"The mouse is currently over the FIRST Static control.")
         DialogControlState(TMODhnd,"VaryText_1",4,1)
      ElseIf udfMouseOver(TMODhnd,4)==4
         DialogControlSet(TMODhnd,"VaryText_1",4,"The mouse is now over the SECOND Static control.")
         DialogControlState(TMODhnd,"VaryText_1",4,1)
      ElseIf udfMouseOver(TMODhnd,1)==1
         DialogControlSet(TMODhnd,"VaryText_1",4,"The mouse is now over the OK Button control.")
         DialogControlState(TMODhnd,"VaryText_1",4,1)
      ElseIf udfMouseOver(TMODhnd,2)==2
         DialogControlSet(TMODhnd,"VaryText_1",4,"The mouse is now over the CANCEL Button control.")
         DialogControlState(TMODhnd,"VaryText_1",4,1)
      Else
         DialogControlState(TMODhnd,"VaryText_1",3,1)   
      EndIf

      Return -1
   EndSelect
#EndSubRoutine

#DefineFunction udfMouseOver(hdlg, ctrlcnt)
  user32 = StrCat(DirWindows(1), 'User32.dll')
  hctrl = DllCall(user32, long:"GetDlgItem", long:hdlg, long:ctrlcnt+99)
  rect = BinaryAlloc(16)
  ; Fill buffer with control coordinates
  DllCall(StrCat(DirWindows(1), "User32.DLL"), long:"GetWindowRect", long:hctrl, lpbinary:rect)
  xx = BinaryPeek4(rect, 0)
  yy = BinaryPeek4(rect, 4)
  ; Is the mouse over the control?
  coords = MouseInfo(3) ; Mouse screen coordinates in pixels.
  mx  = ItemExtract(1, coords, ' ')
  my  = ItemExtract(2, coords, ' ')
  Result = DllCall(user32, long:"PtInRect", lpbinary:rect, long:mx, long:my)
  BinaryFree(rect)
  If Result == 0
     rtn = @FALSE
  Else
     rtn = StrCat(mx-xx, @TAB, my-yy); Convert mouse coords to client coords.
  EndIf
  If rtn<>0
     Return ctrlcnt
  Else
     Return 0
  EndIf
#EndFunction

MouseOverFormat=`WWWDLGED,6.2`

MouseOverCaption=`Test MouseOver Dialog`
MouseOverX=002
MouseOverY=033
MouseOverWidth=168
MouseOverHeight=085
MouseOverNumControls=006
MouseOverProcedure=`TMOD`
MouseOverFont=`DEFAULT`
MouseOverTextColor=`DEFAULT`
MouseOverBackground=`DEFAULT,DEFAULT`
MouseOverConfig=0

MouseOver001=`007,051,036,012,PUSHBUTTON,"PushButton_OK",DEFAULT,"OK",1,1,32,DEFAULT,DEFAULT,DEFAULT`
MouseOver002=`119,051,036,012,PUSHBUTTON,"PushButton_Cancel",DEFAULT,"Cancel",0,2,DEFAULT,DEFAULT,DEFAULT,DEFAULT`
MouseOver003=`009,011,048,012,STATICTEXT,"StaticText_1",DEFAULT,"1st Static control",DEFAULT,3,DEFAULT,DEFAULT,DEFAULT,DEFAULT`
MouseOver004=`009,027,048,012,STATICTEXT,"StaticText_2",DEFAULT,"2nd Static control",DEFAULT,4,DEFAULT,DEFAULT,DEFAULT,DEFAULT`
MouseOver005=`065,015,092,018,VARYTEXT,"VaryText_1",MyVariable2,"Vary 2",DEFAULT,5,1,"Microsoft Sans Serif|5632|70|34","255|255|255","128|128|192"`
MouseOver006=`003,067,160,012,STATICTEXT,"StaticText_3",DEFAULT,"Move the mouse over a static control to show a hidden text box.",DEFAULT,6,DEFAULT,DEFAULT,DEFAULT,DEFAULT`

ButtonPushed=Dialog("MouseOver")



Reference: http://techsupt.winbatch.com/webcgi/webbatch.exe?techsupt/tsleft.web+WinBatch/Dialog~Editor/Dialog~Editor~version~6.2/Samples+Mouseover~Static~Control.txt
Deana F.
Technical Support
Wilson WindowWare Inc.

stevengraff

Thanks, but... I seem to be running an older version of WinBatch, dialog format 6.1.

Deana

The same basic concept applies to 6.1 formatted dialogs. Keep in mind that named controls didn't exist with that version of dialog so you would need to change the dialog callback procedure to reference the control number rather than name....
Code (winbatch) Select

#DefineSubRoutine TMOD(TMODhnd,TMODevent,ctrlnum,rsvd1,rsvd2)
   Select    TMODevent
    Case 0
      DialogProcOptions(TMODhnd, 1,500) ;Initialize Timer at .5 of a second intervals.
      Return -1
    Case 1 ;Timer event fired
      If udfMouseOver(TMODhnd,3)==3 ;If the udf returns the same control number we passed it, then mouse is over it
         DialogControlSet(TMODhnd,005,4,"The mouse is currently over the FIRST Static control.")
         DialogControlState(TMODhnd,005,4,1)
      ElseIf udfMouseOver(TMODhnd,4)==4
         DialogControlSet(TMODhnd,005,4,"The mouse is now over the SECOND Static control.")
         DialogControlState(TMODhnd,005,4,1)
      ElseIf udfMouseOver(TMODhnd,1)==1
         DialogControlSet(TMODhnd,005,4,"The mouse is now over the OK Button control.")
         DialogControlState(TMODhnd,005,4,1)
      ElseIf udfMouseOver(TMODhnd,2)==2
         DialogControlSet(TMODhnd,005,4,"The mouse is now over the CANCEL Button control.")
         DialogControlState(TMODhnd,005,4,1)
      Else
         DialogControlState(TMODhnd,005,3,1)   
      EndIf

      Return -1
   EndSelect
#EndSubRoutine

#DefineFunction udfMouseOver(hdlg, ctrlcnt)
  user32 = StrCat(DirWindows(1), 'User32.dll')
  hctrl = DllCall(user32, long:"GetDlgItem", long:hdlg, long:ctrlcnt+99)
  rect = BinaryAlloc(16)
  ; Fill buffer with control coordinates
  DllCall(StrCat(DirWindows(1), "User32.DLL"), long:"GetWindowRect", long:hctrl, lpbinary:rect)
  xx = BinaryPeek4(rect, 0)
  yy = BinaryPeek4(rect, 4)
  ; Is the mouse over the control?
  coords = MouseInfo(3) ; Mouse screen coordinates in pixels.
  mx  = ItemExtract(1, coords, ' ')
  my  = ItemExtract(2, coords, ' ')
  Result = DllCall(user32, long:"PtInRect", lpbinary:rect, long:mx, long:my)
  BinaryFree(rect)
  If Result == 0
     rtn = @FALSE
  Else
     rtn = StrCat(mx-xx, @TAB, my-yy); Convert mouse coords to client coords.
  EndIf
  If rtn<>0
     Return ctrlcnt
  Else
     Return 0
  EndIf
#EndFunction

MouseOverFormat=`WWWDLGED,6.1`

MouseOverCaption=`Test MouseOver Dialog`
MouseOverX=002
MouseOverY=033
MouseOverWidth=168
MouseOverHeight=085
MouseOverNumControls=006
MouseOverProcedure=`TMOD`
MouseOverFont=`DEFAULT`
MouseOverTextColor=`DEFAULT`
MouseOverBackground=`DEFAULT,DEFAULT`
MouseOverConfig=0

MouseOver001=`007,051,036,012,PUSHBUTTON,DEFAULT,"OK",1,1,32,DEFAULT,DEFAULT,DEFAULT`
MouseOver002=`119,051,036,012,PUSHBUTTON,DEFAULT,"Cancel",0,2,DEFAULT,DEFAULT,DEFAULT,DEFAULT`
MouseOver003=`009,011,048,012,STATICTEXT,DEFAULT,"1st Static control",DEFAULT,3,DEFAULT,DEFAULT,DEFAULT,DEFAULT`
MouseOver004=`009,027,048,012,STATICTEXT,DEFAULT,"2nd Static control",DEFAULT,4,DEFAULT,DEFAULT,DEFAULT,DEFAULT`
MouseOver005=`065,015,092,018,VARYTEXT,MyVariable2,"Vary 2",DEFAULT,5,1,"Microsoft Sans Serif|5632|70|34","255|255|255","128|128|192"`
MouseOver006=`003,067,160,012,STATICTEXT,DEFAULT,"Move the mouse over a static control to show a hidden text box.",DEFAULT,6,DEFAULT,DEFAULT,DEFAULT,DEFAULT`

ButtonPushed=Dialog("MouseOver")

Deana F.
Technical Support
Wilson WindowWare Inc.

stevengraff

Yikes! That works!  :)

Note: I did have to adapt it for my version, as I can't use ElseIf

#DefineSubRoutine TMOD(TMODhnd,TMODevent,ctrlnum,rsvd1,rsvd2)
   Select    TMODevent
    Case 0
      DialogProcOptions(TMODhnd, 1,500) ;Initialize Timer at .5 of a second intervals.
      Return -1
    Case 1 ;Timer event fired
         DialogControlState(TMODhnd,005,3,1)
      If udfMouseOver(TMODhnd,3)==3 ;If the udf returns the same control number we passed it, then mouse is over it
         DialogControlSet(TMODhnd,005,4,"The mouse is currently over the FIRST Static control.")
         DialogControlState(TMODhnd,005,4,1)
Endif
      If udfMouseOver(TMODhnd,4)==4
         DialogControlSet(TMODhnd,005,4,"The mouse is now over the SECOND Static control.")
         DialogControlState(TMODhnd,005,4,1)
      EndIf
      If udfMouseOver(TMODhnd,1)==1
         DialogControlSet(TMODhnd,005,4,"The mouse is now over the OK Button control.")
         DialogControlState(TMODhnd,005,4,1)
      EndIf
      If udfMouseOver(TMODhnd,2)==2
         DialogControlSet(TMODhnd,005,4,"The mouse is now over the CANCEL Button control.")
         DialogControlState(TMODhnd,005,4,1)
Endif
      Return -1
   EndSelect
#EndSubRoutine

stevengraff

Something might need tweaking... I'm getting weird results. I'm trying this with a much larger dialog. Maybe the buffer in the second function should be bigger?

I thought I could just keep adding sections like:

      If udfMouseOver(TMODhnd,7)==7
         DialogControlSet(TMODhnd,005,4,"The mouse is now over control # 7.")
         DialogControlState(TMODhnd,005,4,1)
     Endif

But the new ones, i.e. > control #4, don't seem to line up. The mouseover action happens when mousing over a different, i.e. wrong, control.

Actually, in your little demo script I can add controls and the process still works right... but when I try to adapt it to my own script I get the weirdness. My dialog is much larger, having about 40 controls. And it starts closer to the center of the screen. Not sure what else about it could be that much different.

Deana

The udfMouseOver UDF is using a DllCall to call the GetDlgItem API. That API expects a control id.  The control id is set by the tab order of the controls in the dialog. But it is a little more complicated than that because of group boxes. So in order for GetDlgItem to work by adding 99, the control number and the tab order must follow the same sequence!

Starting in WinBatch 2010A January 27, 2010. we added DialogControlGet request-code 19  returns a window handle. You could modify the udfMouseOver UDF to accept  the control handle passed by your callback procedure.
Deana F.
Technical Support
Wilson WindowWare Inc.

stevengraff

Quote from: Deana on December 26, 2013, 09:04:45 AM
The udfMouseOver UDF is using a DllCall to call the GetDlgItem API. That API expects a control id.  The control id is set by the tab order of the controls in the dialog. But it is a little more complicated than that because of group boxes. So in order for GetDlgItem to work by adding 99, the control number and the tab order must follow the same sequence!

Starting in WinBatch 2010A January 27, 2010. we added DialogControlGet request-code 19  returns a window handle. You could modify the udfMouseOver UDF to accept  the control handle passed by your callback procedure.

I'm sure I will upgrade... eventually :)

In the meantime, it sounds like it will be worthwhile to re-do my tab orders to match my control numbers.

BTW, is there an auto-update mechanism in WB recent versions that will convert/update my old scripts?

stevengraff

Quote from: Deana on December 26, 2013, 09:04:45 AM
The udfMouseOver UDF is using a DllCall to call the GetDlgItem API. That API expects a control id.  The control id is set by the tab order of the controls in the dialog. But it is a little more complicated than that because of group boxes. So in order for GetDlgItem to work by adding 99, the control number and the tab order must follow the same sequence!
So, I noticed the mouseover alignment failing on another of my dialogs, this one having a single group box, even though the tab order lines up 1-to-1 with the control numbers. Is there a workaround for this?

Deana

Quote from: stevengraff on December 26, 2013, 02:53:04 PM
Quote from: Deana on December 26, 2013, 09:04:45 AM
The udfMouseOver UDF is using a DllCall to call the GetDlgItem API. That API expects a control id.  The control id is set by the tab order of the controls in the dialog. But it is a little more complicated than that because of group boxes. So in order for GetDlgItem to work by adding 99, the control number and the tab order must follow the same sequence!

Starting in WinBatch 2010A January 27, 2010. we added DialogControlGet request-code 19  returns a window handle. You could modify the udfMouseOver UDF to accept  the control handle passed by your callback procedure.

I'm sure I will upgrade... eventually :)

In the meantime, it sounds like it will be worthwhile to re-do my tab orders to match my control numbers.

BTW, is there an auto-update mechanism in WB recent versions that will convert/update my old scripts?

The WIL Dialog Editor has a menu option to Convert the dialog to the newer 6.2 format. however you will need to manually modify any of the function in your Dialog Callback procedure to reference the named control. However keep in mind that the newer version of WinBatch can still run the older 6.1 formatted dialogs, so there will really be no need to convert that code unless you need the newer 6.2 functionality.
Deana F.
Technical Support
Wilson WindowWare Inc.

Deana

Quote from: stevengraff on December 27, 2013, 05:05:13 AM
So, I noticed the mouseover alignment failing on another of my dialogs, this one having a single group box, even though the tab order lines up 1-to-1 with the control numbers. Is there a workaround for this?

Difficult to say without seeing the code. do you have a simple code sample that shows the problem? If so maybe post it an we can take a look.
Deana F.
Technical Support
Wilson WindowWare Inc.