October 09, 2024, 04:38:31 PM

News:

Own IWBasic 2.x ? -----> Get your free upgrade to 3.x now.........


Mouse over a control (MouseOverControls.inc)

Started by Andy, July 18, 2017, 09:53:53 PM

Previous topic - Next topic

0 Members and 1 Guest are viewing this topic.

Andy

July 18, 2017, 09:53:53 PM Last Edit: July 18, 2017, 11:38:57 PM by Andy
This include file detects when the mouse is over any type of control or window and I think has many uses.

The zip file includes an example program and a help file.

Andy.
Day after day, day after day, we struck nor breath nor motion, as idle as a painted ship upon a painted ocean.

Andy

I've added in some more commands to the mouse over controls include file which are proving to be very handy.

The commands are as follows (not documented yet in the help file):

ControlClick
ControlClickUp
ControlRClick
ControlRclickUp

int = ControlClick(MyWindow,MyControl)
Returns True (1) if the mouse is over the control and the left mouse button was clicked.

int = ControlClickUp(MyWindow,MyControl)
Returns True (1) if the mouse is over the control and the left mouse button was released.

The other two commands do exactly the same as above but when the right mouse button is clicked / released.

Copy the include file to your includes folder and over write any older version if you have one.

Compile and run the button test program - BUT read the following first please!

In my reg viewer program I added in a context menu for a control, but when the context menu was showing it partly covered another control.  As you moved the mouse down the context menu at some point the mouse was also over the other control.

Because the mouse was over the other control, and I had told it to do something if it was - the control was doing this "action" even though you were moving the mouse up and down the first controls context menu.

So these new commands, together with a variable enabled me to stop this.

Have a look at this code from the button test program:-

          if mousedown(1) then CMenu = 0 '<---- Check is mouse left button clicked FIRST

'Check for Right click on control with this command
IF ControlRClick(win,static_1)
CMenu = 1 '<---------- Context menu exists!
POINT cursor3
GetCursorPos(cursor3)
ScreenToClient(win.hwnd, cursor3)
CONTEXTMENU win,cursor3.x, cursor3.y
  MENUITEM "Export key",0,2002
  separator
  MENUITEM "Copy key name",0,110
  separator
  MENUITEM "Copy key details",0,111
ENDMENU
endif

          '===================================================================
          '
          ' The control "radio_1" can have "static_1's" context menu over it
          ' so we need to check if the context menu exists or not.
          '
          ' Variable CMenu = 0 - no context menu.
          '          CMenu = 1 - context menu exists.
          '
          ' So, only do something with radio_1 IF context menu does not exists
          '
          '===================================================================

            if MouseOver(win,radio_1) = 1 and CMenu = 0 '<--------- Check here......
             SETFONT win,"Tahoma", 22, 400, 0, radio_1
          else
             if MouseMovedOff(win,radio_1) 'Do this one time only.
                SETFONT win,"Arial", 10, 400, 0, radio_1
             endif
          endif



Static_1 has the text ""Move the mouse over here, ..........."

When you right click say on the word "mouse" a context menu appears.

This context menu appears over part of the radio_1 controls text.

Radio_1's text will only enlarge if static_1's context menu does not exists.

Try it.

Finally, comment out AND CMenu = 0 from this line (like this):

if MouseOver(win,radio_1) = 1 'and CMenu = 0  '<--- comment out the AND part.

You will see the the problem, and how to fix it.

Still confused as to what I'm trying to say??????? then give it a go.

Andy.
:)



Day after day, day after day, we struck nor breath nor motion, as idle as a painted ship upon a painted ocean.

billhsln

I have been looking closely at your program/inc file and noticed that it takes a lot of storage.  See:

'====================================================================
' Somewhere to store the window and control co-ordinates, sizes etc.'
'                                                                   '
' 1,000 windows and 10,000 controls.                                '
'                                                                   '
'====================================================================
int MOControlDown[10000],MOControlAcross[10000],MOControlWidth[10000],MOControlHeight[10000]
' storage bytes: 40,000*4 = 160,000'
int MOControlNumber[10000],MOControlTrack[10000],MOControlOverNumber[10000]
' storage bytes: 30,000*4 = 120,000'
int MOWindowDown[1000],MOWindowAcross[1000],MOWindowWidth[1000],MOWindowHeight[1000],MOWindowOverNumber[1000]
' storage bytes: 5,000*4 = 20,000'
int MOWindowLeft[1000],MOWindowRight[1000],MOWindowTop[1000],MOWindowBottom[1000]
' storage bytes: 4,000*4 = 16,000'
UINT MOControlsWindow[10000],MOWindowPointer[1000]
' storage bytes: 11,000*4 = 44,000'
string MOWindowName[1000],MOWindowDesc[1000],MOControlType[10000]
' storage bytes: 3,000*255 = 765,000'

' Total storage bytes: 1,125,000'


I am guessing that 1000 windows and 10,000 controls is the max that can be created in IWB.  However, in reality, I would be surprised if any one would create more than maybe 50 windows with 1000 controls, which would free up alot of storage.  Plus looking at the code many of the 3 string fields, probably store much less than 255 chars.  So, I am wondering if they could be redefined as ISTRINGs.  Say the max length of the variable that will be stored in a STRING variable is 14 characters then:

' Reference dimensioned ISTRINGs (1000 rows of 14 chars each, add 1 for /0 as last char (needed)
def sn[15,1000]:istring
sn[0,c] = Name


Just some thing to think about to save the program from needing more than 1 Meg of memory just for this utility.

Bill
When all else fails, get a bigger hammer.

Andy

Bill,

Yes, you do make a good point.

My ultimate plan is to make them istrings and use pointers, so we could set an initial number of windows and controls, and increase when needed.

Just a bit busy coding something else at the moment, but thanks for taking the interest!

Andy.
:)
Day after day, day after day, we struck nor breath nor motion, as idle as a painted ship upon a painted ocean.

Andy

Hi,

Well I thought I would post this now, I need to document the new functions.

However, here they are:

MoveControlUp
MoveControlDown
MoveControlLeft
MoveControlRight


These are the same as I posted the other day, but they have an optional parameter
which limits a control's position to within "X" of the top / bottom / left or right of the current window specified.

Example:

MoveControlLeft(w1,SelectedControl,Movement,20) 'limits the control from being moved to within 20 of the left of the window specified.

There is also a correction for ControlUp that Brian reported to me.

ControlDrag

This now has four optional paramters (top / bottom / left /right), with these you cannot drag a control beyond these values. The sub wants a gold old tidy up but it works.

Example:

ControlDrag(MyWindow,MyControl,0,610,130,1090)

(0 from the top, 610 from the bottom, 130 from the left & 1090 from the right).
These values refer to your specified window not the screen position, and can stop a user dragging a control out of the window and subsequently out of sight.

In effect, you are creating a border inside your specified window in which a user is allowed to drag a control.

MOGetSize

It's like our GETSIZE command but it gives you the actual position of a control in the specified window not the position on screen, and I can tell you that's really handy!

You use it like this

MOGetSize(MyWindow,MyControl)

and it returns these values:

MOControlSize.x (across)   
MOControlSize.y (down)
MOControlSize.w (width)
MOControlSize.h (height)

You can then simply adjust your control's position using our SETSIZE command without doing any calculations.

I will post some examples here tomorrow.

See attached for version 6.0.

Andy.

P.S.
"I've just finished reading a book about a swimming pool, it started off really shallow but it had a deep ending" - sorry!

:)
Day after day, day after day, we struck nor breath nor motion, as idle as a painted ship upon a painted ocean.

jalih

May 17, 2021, 09:03:57 AM #5 Last Edit: May 17, 2021, 09:19:56 AM by jalih
Hi Andy,

Your ControlDrag procedure looks really complex. Consider capturing mouse when starting drag operation and releasing mouse capture on mouse button release.

Here is some old code:
$INCLUDE "windowssdk.inc"

window w1
openwindow w1,10,20,800,800,@sysmenu,0,"Drag the controls...",&w1_handler
CONTROL w1,@BUTTON,"Drag me1",50,40,200,50,0x50000000,1
CONTROL w1,@BUTTON,"Drag me2",50,150,100,50,0x50000000,2
CONTROL w1,@BUTTON,"Drag me3",50,250,100,50,0x50000000,3
CONTROL w1,@STATIC,"Hey",200,320,102,340,SS_NOTIFY, 4

SubClassControl(w1, 1)
SubClassControl(w1, 2)
SubClassControl(w1, 3)
SubClassControl(w1, 4)

waituntil iswindowclosed(w1)
end

sub w1_handler(),int
  SELECT @MESSAGE
    CASE @IDCREATE
      centerwindow w1
    CASE @IDCLOSEWINDOW
      UnSubClassControl(w1, 1)
      UnSubClassControl(w1, 2)
      UnSubClassControl(w1, 3)
      UnSubClassControl(w1, 4)
      CLOSEWINDOW w1
  endselect
  RETURN 0
ENDSUB


sub DragHandler(HWND hWnd,UINT uMsg,WPARAM wParam,LPARAM lParam),LRESULT
  static int drag = FALSE
  static POINT anchor
  int rcWin[4]
  SELECT uMsg
    case WM_LBUTTONDOWN
      drag = TRUE
      GetWindowRect(hWnd,&rcWin)
      w = rcWin[2] - rcWin[0]
      h = rcWin[3] - rcWin[1]
      GetCursorPos(&anchor)
      anchor.x = anchor.x - rcWin[0]
      anchor.y = anchor.y - rcWin[1]
      BringWIndowToTop(hWnd)
      SetCapture(hWnd)
      return 0
    case WM_LBUTTONUP
      ReleaseCapture()
      drag = FALSE
      anchor.x = 0
      anchor.y = 0
    case WM_MOUSEMOVE
      if drag
        GetWindowRect(hWnd,&rcWin)
        w = rcWin[2] - rcWin[0]
        h = rcWin[3] - rcWin[1]
        POINT pt
        GetCursorPos(&pt)
        pt.x = pt.x - anchor.x
        pt.y = pt.y - anchor.y
        MapWindowPoints(NULL, w1.hwnd, &pt, 1)
        MoveWindow(hWnd, pt.x, pt.y, w, h, TRUE)
        InvalidateRect(hWnd, NULL, TRUE)
      endif
    case WM_CAPTURECHANGED
      drag = FALSE
      InvalidateRect(hWnd, NULL, TRUE)
  ENDSELECT
  RETURN CallWindowProcA(GetWindowLong(hWnd, GWL_USERDATA),hWnd,uMsg,wParam,lParam)
ENDSUB


SUB SubClassControl(WINDOW parent, INT id)
  HWND hButton = GETCONTROLHANDLE(parent,id)
  WNDPROC lpFn = GetWindowLong(hButton, GWL_WNDPROC)

  if lpFn <> &DragHandler
    WNDPROC OldWndProc = SetWindowLongA(hButton,GWL_WNDPROC,&DragHandler)
    SetWindowLong(hButton, GWL_USERDATA, OldWndProc)
  endif
endsub


SUB UnSubClassControl(WINDOW parent, INT id)
  HWND hButton = GETCONTROLHANDLE(parent,id)

  WNDPROC OldWndProc = GetWindowLong(hButton, GWL_USERDATA)
  SetWindowLongA(hButton, GWL_WNDPROC, OldWndProc)
endsub

Andy

Hi Jalih,

Been to long since we have seen you!

Yes, I have to agree, in the case of dragging a control yours in much simpler.

Maybe there is a way to change my ControlDrag function to yours, I will have to see.

The idea behind this include file is to provide a "one stop shop" for us all where we can use / copy useful sections of code into our programs rather than having to spend hours searching for something.

Thanks so much for the code.
Andy.
:)
Day after day, day after day, we struck nor breath nor motion, as idle as a painted ship upon a painted ocean.