News:

MASM32 SDK Description, downloads and other helpful links
MASM32.com New Forum Link
masmforum WebSite

WM_NOTIFY for ownerdrawn buttons

Started by Fab, January 12, 2006, 10:40:49 AM

Previous topic - Next topic

Fab

Im having trouble finding out how to recieve the WM_NOTIFY message for my ownerdrawn buttons, I need it to find out when the mouse is over the button. I've set the button as NOTIFY also.

WM_NOTIFY doesn't get sent to my window when I use normal buttons either until I add the manifest file to the resource, which is odd. but I want WM_NOTIFY for my ownerdrawn buttons

maybe WM_NOTIFY isn't being sent to my main window when the button is ownerdrawn, and its being sent to the button itself. which means I'd have to set a custom wndproc for all my buttons (i'd prefer not doing it that way)

If someone can tell me a way to know if the mouse is over a button and when its left the button other than WM_NOTIFY then I'd use it instead.

Thanks in advance,
Fab

Tedd

Posting your code might be helpful (it beats guessing.)

Instead of setting a custom wndproc for all your buttons, you could subclass the button class and create your buttons as this class - which would have them all ownerdrawn by the same proc. But this doesn't really solve your original problem - just sidesteps it :wink

An alternative to wm_notify, could be wm_mousemove, but this would require checking the cursor position against each of your buttons every time the mouse moves - probably not the best idea.

Code.. post code :toothy
No snowflake in an avalanche feels responsible.

zooba

Creating the button with BS_NOTIFY sends notification messages through WM_COMMAND, not WM_NOTIFY. However, it still goes to the parent window.

You can check if the mouse is over your button using something like this:
invoke  GetCursorPos, ADDR mouse_pos
invoke  GetWindowRect, hButton, ADDR button_rect
invoke  PtInRect, ADDR button_rect, ADDR mouse_pos
.if(eax != 0)
    ; mouse is over button
.else
    ; mouse is not over button
.endif


Also, there is an itemState parameter in the DRAWITEMSTRUCT structure passed in a WM_DRAWITEM message. This parameter may contain the ODS_HOTLIGHT constant:
Quote from: MSDNODS_HOTLIGHT
Windows 98/Me, Windows 2000/XP: The item is being hot-tracked, that is, the item will be highlighted when the mouse is on the item.

This obviously isn't a complete description, so it'll need some experimentation, but it may be a start :U

Cheers,

Zooba

Fab

#3
Thank you both for the helpful info  :U

The reason I wanted to use WM_NOTIFY was for the BCN_HOTIMEMCHANGE notification.
on msdn
Quote
The BCN_HOTITEMCHANGE message notifies the button control owner that the mouse is entering or leaving the client area of the button control. The button control sends this notification in the form of a WM_NOTIFY message.

that is exactly what I needed to use

but later down the page

Quote
Note  To use this API, you must provide a manifest specifying Comclt32.dll version 6.0. For more information on manifests, see Using Windows XP Visual Styles.
and I need my program to work in win98 (and Comclt32.dll 6.0 isn't distributable)
Even when I added the manifest ownerdrawn buttons didn't recieve the BCN_HOTITEMCHANGE WM_NOTIFY message, only normal ones did.

so like your suggestions I used WM_MOUSEMOVE instead
but I still needed to find out when the mouse left the button window without having to use the surrounding/underlying window/s recieving a WM_MOUSEMOVE message to know when the mouse is off the button (because someone could move the mouse fast enough to leave the entire window without making WM_MOUSEMOVE trigger in the surrounding areas of the button)

so I cominbed TrackMouseEvent with the TME_LEAVE and the WM_MOUSEMOVE, and made some really bad code on how to track the mouse for each ownerdrawn button

also ODS_HOTLIGHT did not work for my ownerdrawn buttons, with or without a manifest file

this isn't a copy of my working code, I just wrote it out of memory to give you an idea of what Im trying to do, so it might have LOTS of mistakes


.data?
hWnd DWORD ?

Extra struct
  hOldproc DWORD ?
  IsMouseOver DWORD ?
Extra ends

.code

DialogProc proc uses esi,edi,ebx hWin:DWORD,uMsg:DWORD,wParam:DWORD,lParam:DWORD

.if uMsg == WM_INITDIALOG
  m2m hWnd,hWin
  mov edi,1001 ;first ownerdrawn button ID

  .while edi<=1100 

    invoke GetDlgItem,hWin,edi ;get hWnd for it
    mov esi,eax
    invoke GlobalAlloc,GMEM_FIXED or GMEM_ZEROINIT,SIZEOF Extra
    mov ebx,eax
    invoke GetWindowLong,esi,GWL_WNDPROC ;get it now before I change it
    mov [ebx].Extra.hOldproc,eax
    invoke SetWindowLong,esi,GWL_USERDATA,ebx ;set userdata to Alloced memory
    invoke SetWindowLong,esi,GWL_WNDPROC,addr proc_MYBUTTON ;subclass button
    inc edi
  .endw ;loop and do all 100 buttons

.elseif uMsg == WM_DRAWITEM
  mov esi,lParam
  assume esi:PTR DRAWITEMSTRUCT

  ; I do my button drawing here
  ; '.if [esi].itemstate & ODS_HOTLIGHT' doesn't work for me :(
  ; and it doesn't send out a WM_DRAWITEM every time I do a mouse over either
  ; so I use the following

  invoke GetWindowLong,[esi].hwndItem,GWL_USERDATA

  .if ([eax].Extra.IsMouseOver) && (eax)
  ;draw it like mouse is over button
  .else
  ;draw it normally
  .endif

  mov eax,TRUE
  assume esi:NOTHING
.elseif uMsg == WM_CLOSE
  invoke EndDialog,hWnd
  .else
  xor eax,eax
.endif

ret
DialogProc endp

proc_MYBUTTON proc hCtl:DWORD,uMsg:DWORD,wParam:DWORD,lParam:DWORD
LOCAL TME:TRACKMOUSEEVENT

.if uMsg == WM_MOUSEMOVE

  invoke GetWindowLong,hCtl,GWL_USERDATA
  .if [eax].Extra.IsMouseOver == FALSE ;dont want to redraw the button every time the mouse moves
    mov [eax].Extra.IsMouseOver,TRUE

    m2m TME.cbSize,SIZEOF TME
    m2m TME.dwFlags,TME_LEAVE
    m2m TME.hwndTrack,hCtl
    m2m TME.dwHoverTime,0
    invoke TrackMouseEvent,addr TME

    invoke RedrawWindow,hCtl,NULL,NULL,TRUE ;have to manually set off the WM_DRAWITEM notification
  .endif
.elseif uMsg == WM_MOUSELEAVE

  .if [eax].Extra.IsMouseOver == TRUE
    mov [eax].Extra.IsMouseOver,FALSE
    invoke RedrawWindow,hCtl,NULL,NULL,TRUE ;fires a WM_DRAWITEM
  .endif
.endif

invoke GetWindowLong,hCtl,GWL_USERDATA
invoke CallWindowProc,[eax].Extra.hOldproc,hCtl,uMsg,wParam,lParam

ret
proc_MYBUTTON endp



Is there a better way to make my buttons know if the mouse if over them or not than what I've attempted?

Thanks again,
Fab  :eek