I've been wondering how you can get a user to move controls - say buttons around a window. Anne does this most days when she is playing card games on her laptop.
So I've written a new routine in the Mouse over controls file to take care of dragging controls.
Attached is the program and new (beta version of the include file).
There are three buttons, you can drag them around the window as you please, just use a bit of common sense with how fast you do it.
I think this could be used for games, visual design etc, as it should work for any type of control.
You may have to play around with the timer speed.
Could any one test it for me and give feedback please...
Thanks,
Andy.
:)
Don't know what you've done, Andy, but it hasn't gone wrong for me yet!
Brian
Thanks Brian!
It's all in the sequence, just a few simple lines in the right order and it works.
Imagine the buttons loaded with images, say the ace of hearts, five of diamonds, and the three of clubs - you could see a card game coming.
Or, you could design a screen for designing something.
Thanks again for testing!
Andy.
:)
Andy,
I don't do cards, but I'm OK at Snap or spotting Mr Bun the Baker!
Brian
Great idea Andy!
For a long time I have been thinking about trying to make a simple WYSIWG Editor for making web pages, using the built in browser control to view the work in progress.
Maybe your Drag Control routines can be used to place text and/or pictures in the browser window, and move them around until the design is ok.
And then scan or parse that browser control in order to produce the proper html code. Have to think about this for a while, but example certainly is a leap forward for making such an Editor possible.
Thanks for sharing!
Egil
Thanks so much Egil,
I will have a think on that and see what I can come up with.
Thanks for the support!! - it has so many possibilities / uses.
Andy.
:)
Maybe someone will take the idea of moving controls around and come up with an idea for a Visual Designer that generates code of some kind ::) ;)
The possibility did cross my mind Larry, but didn't want to step on anybodies toes. ;)
I am going to look at Egils suggestion and see what I can come up with (that is the text and picture side of things).
:)
You could cheat too:
$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
SubClassButton(w1, 1)
SubClassButton(w1, 2)
SubClassButton(w1, 3)
waituntil iswindowclosed(w1)
end
sub w1_handler(),int
SELECT @MESSAGE
CASE @IDCREATE
centerwindow w1
CASE @IDCLOSEWINDOW
UnSubClassButton(w1, 1)
UnSubClassButton(w1, 2)
UnSubClassButton(w1, 3)
CLOSEWINDOW w1
endselect
RETURN 0
ENDSUB
sub ButtonHandler(HWND hWnd,UINT uMsg,WPARAM wParam,LPARAM lParam),LRESULT
SELECT uMsg
case WM_NCHITTEST
LRESULT hit = DefWindowProc(hWnd, uMsg, wParam, lParam)
if hit = HTCLIENT then hit = HTCAPTION
return hit
ENDSELECT
RETURN CallWindowProcA(GetWindowLong(hWnd, GWL_USERDATA),hWnd,uMsg,wParam,lParam)
ENDSUB
SUB SubClassButton(WINDOW parent, INT id)
HWND hButton = GETCONTROLHANDLE(parent,id)
WNDPROC lpFn = GetWindowLong(hButton, GWL_WNDPROC)
if lpFn <> &ButtonHandler
WNDPROC OldWndProc = SetWindowLongA(hButton,GWL_WNDPROC,&ButtonHandler)
SetWindowLong(hButton, GWL_USERDATA, OldWndProc)
endif
endsub
SUB UnSubClassButton(WINDOW parent, INT id)
HWND hButton = GETCONTROLHANDLE(parent,id)
WNDPROC OldWndProc = GetWindowLong(hButton, GWL_USERDATA)
SetWindowLongA(hButton, GWL_WNDPROC, OldWndProc)
endsub
Best way to handle dragging of controls would probably be using SetCapture(), ReleaseCapture() , handle mouse messages and WM_CAPTURECHANGED. Using timer is not necessary.
Jalih,
Nice bit of code, don't see how that's cheating!
One thing, with your code I can only drag buttons, I added a static and a checkbox - but they would not drag.
Andy.
Jalih,
Nice way of moving stuff about, but it does get mixed up sometimes - I ended up with the same wording on two buttons! Seems to be losing track of which button you are working on
Brian
Quote from: LarryMc on November 23, 2017, 06:52:15 PM
Maybe someone will take the idea of moving controls around and come up with an idea for a Visual Designer that generates code of some kind ::) ;)
Would it be a good idea to have a kind of framework to move tings around and place them on screen, and then add "modules" that generates the code needed for IWB, PHP, HTML etc... ?
I can see many uses for such a framework. And as a "bonus" many of our coders can be involved in writing the extra modules.
Quote from: Brian Pugh on November 24, 2017, 03:32:48 AM
Nice way of moving stuff about, but it does get mixed up sometimes - I ended up with the same wording on two buttons! Seems to be losing track of which button you are working on
It's not losing track of buttons. You should handle refreshing and z-order of buttons, so they get redrawn correctly. All it does, it lets window think you are moving window from it's caption bar.
First of all you don't need
"windowssdk.inc"
you must know how windows API functions work
when you learn that then you know everything!
Quote from: aurelCB on November 24, 2017, 11:44:59 AM
First of all you don't need
"windowssdk.inc"
you must know how windows API functions work
when you learn that then you know everything!
Any real reason not to use it? I prefer to spend my time doing productive work instead of reading and searching through header files for type definitions.
Why reinvent the wheel?
Windows API is huge, try doing gdi+, direct2d, directwrite or some other COM-stuff without header files.
Aurel,
Don't know where you are coming from, unless you are the 1 in 1 billion people
who know the API off by heart, and can write the headers, types and declares
off the bat, and convert them to IWB format as you type
Brian
Aurel,
Not sure what you are saying, without header files I'd be posting 20 questions a day.
Now, continuing with the dragging code, I've now got a button (region button) loaded with Brian's on / off images. I converted them to bitmaps.
When you place the mouse over the "off" button, it hot tracks and changes to"on" - the important thing is that this is now a picture and you can still drag it.
"Drag me 1" now has a right click context menu - the options don't do anything but you can see options for things like "properties" or "edit" etc.
Just wished I could get a flat button without a border. I did it once by making a static act like a button, but unsure if you can add a picture to a static?
Attached are the files.
Andy.
Here is my final demo...
Should also work with static controls, just remember to set SS_NOTIFY style. No timer is necessary.
$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",13,300,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
Quote from: jalih on November 25, 2017, 10:49:21 AM
Here is my final demo...
Great code!
And after setting a background color for the window, the beauty of it suddenly become clearer...
Thanks!
Egil
jalih's code looks like one of the very most basic parts of IWB+ without all the layers and layers of stuff stacked on (including the linked list trees, Andy) to accomplish everything else that is required. A few controls you have to draw to look like the real controls also, in order to get them to do in IWB+. Some you just allocate space.
Hi to all
Just to answer to Brian
You probably don't know that I am author of almost complete API headers for
Oxygen basic ( called awinh.inc )which use CDCL shape of windows api functions.
IWB(EB) can use same form
Also i have tested dll produced with IWB( in my case EB) and work with o2 compiler.
and dll produced with o2 work with IWB(EB).
also i have modifyed version of DLIB(pl) api headers too.
I hope that i explain from where i know about API functions :D
Aurel,
You certainly know a lot more than me, and I can see where you are coming from with all that development.
For the rest of us "mere mortals" we rely on those header files - but obviously you don't need to!
Jalih,
Nice code, I see you are sub classing the buttons to use a different handler, good stuff.
I think if you look through my mouse over include file at the functions available you will see a lot of coding and for "mere mortals" like myself who prefer a simple command to do all the work you want it to, then my include file is the way to go.
The whole point of me writing this file was so that any of us could add in say just 5 or 6 lines to their iwb program in a simple way to give some powerful functions.
Example:
To check if the mouse is over a control you only need 3 commands, all written for you (and yes that timer)....
1. MouseOverControl(w1,1) <--- Tell the include file the control you want to keep track of.
2. Trackwindow(w1) <--- Track the window in case it is moved / re-sized.
3. IF MouseOver(w1,1) <--- Mouse is over the control ----- do something.....
Where w1 is the window, and 1 is the control.
But as said before, nice code.
Andy.
:)
Quote from: aurelCB on November 26, 2017, 01:45:11 AM
Hi to all
Just to answer to Brian
You probably don't know that I am author of almost complete API headers for
Oxygen basic ( called awinh.inc )which use CDCL shape of windows api functions.
I thought Oxygen basic can read most C headers directly? Why not just use headers bundled with C compiler?
Aurel and Jalih,
It's a nice little debate, I appreciate all that you both do, but can we leave the header question off this post please, I think it's off track with my original question / point.
No offence meant! :)
Andy.
jalih
QuoteI thought Oxygen basic can read most C headers directly? Why not just use headers bundled with C compiler?
no...o2 is assembler with basic-like syntax and can read some C shape of includes but not
directly....so that is about headers.
andy
your questions is hmm strange to me ..
you probably understand that any GUI object is Window
but with different parameters...so if you can move window you can move any control
in similar way.
Another thing is if you wish to build Form builder or something like that .
In most GUI designer when you activate any control creation you can see this control
only when your mouse pointer is on new window area.
oh i see now
you want to move created controls around window?
that is relatively easy
under windows message WM_MOUSEMOVE
you must add code to detect position of your control
for example if your button is
x=100,y=100
under submesagge WM_LMOUSEBUTTONDOWN
which mean when your left mouse button is down
then you use
api call - MoveWindow where you add x,y variable to track you mouse pointer
is that clear for you?
Quote from: Andy on November 26, 2017, 03:23:37 AM
The whole point of me writing this file was so that any of us could add in say just 5 or 6 lines to their iwb program in a simple way to give some powerful functions.
Example:
To check if the mouse is over a control you only need 3 commands, all written for you (and yes that timer)....
1. MouseOverControl(w1,1) <--- Tell the include file the control you want to keep track of.
2. Trackwindow(w1) <--- Track the window in case it is moved / re-sized.
3. IF MouseOver(w1,1) <--- Mouse is over the control ----- do something.....
Where w1 is the window, and 1 is the control.
You could subclass control and store controls parent HWND. Define your own custom window message. Inside your subclassed control handler, you handle WM_NCHITTEST message and test if result is HTCLIENT. If it is, then get mouse cursor position and send your custom window message to parent window along with controls HWND and mouse cursor position information. You can store that information inside wparam and lparam of window message.
Now parent window gets window message along with control handle and mouse cursor position, when mouse cursor moves inside controls client area.
This functionality could be encapsulated inside two functions (add and remove tracking). Program using these functions would only need to handle your custom window message.
Both good ideas / suggestions, thanks - I will look into them.
So to round up the original question if my drag control command worked on other machines - yes it did.
Thanks every one for the posts / testing / suggestions, always useful and constructive.
Andy.
:)
Aurel,
This topic is in danger of becoming a Big Willy contest! I wish I knew more about the API without having to look them up frequently, and you must be clever to do what you have done, with your DLLS
But you started somewhere, and had some source code to get where you are now. What we are doing with the windowssdk.inc is a shortcut, admittedly. But the clever part is knowing which constant, type or declare, etc, to use given your current needs
Enough already!
Brian
Andy,
Here are my mouse tracking support routines for controls. You simply get window messages for mouse enter, mouse move and mouse leave.
Have fun!
$INCLUDE "windowssdk.inc"
' User defined window messages
$define MSG_TRACK_ENTER 0x4001
$define MSG_TRACK_MOVE 0x4002
$define MSG_TRACK_LEAVE 0x4003
window w1
openwindow w1,10,20,800,800,@sysmenu,0,"Mouse tracking for controls...",&w1_handler
CONTROL w1,@BUTTON,"1",50,40,200,50,0x50000000,1
CONTROL w1,@BUTTON,"2",50,150,100,50,0x50000000,2
CONTROL w1,@BUTTON,"3",50,250,100,50,0x50000000,3
CONTROL w1,@STATIC,"4",50,400,102,340,SS_NOTIFY, 4
TrackControl(w1, 1)
TrackControl(w1, 2)
TrackControl(w1, 3)
TrackControl(w1, 4)
openconsole
waituntil iswindowclosed(w1)
end
sub w1_handler(),int
SELECT @MESSAGE
CASE @IDCREATE
centerwindow w1
CASE @IDCLOSEWINDOW
UnTrackControl(w1, 1)
UnTrackControl(w1, 2)
UnTrackControl(w1, 3)
UnTrackControl(w1, 4)
CLOSEWINDOW w1
CASE MSG_TRACK_ENTER
print "Mouse Enter: ", "window handle:", @WPARAM, "x:", @LPARAM & 0xFF, "y:", @LPARAM >> 16
CASE MSG_TRACK_MOVE
print "Mouse Move : ", "window handle:", @WPARAM, "x:", @LPARAM & 0xFF, "y:", @LPARAM >> 16
CASE MSG_TRACK_LEAVE
print "Mouse Leave: ", "window handle:", @WPARAM
print ""
endselect
RETURN 0
ENDSUB
/****************************************************************************/
sub TrackHandler(HWND hWnd,UINT uMsg,WPARAM wParam,LPARAM lParam),LRESULT
static int enter = FALSE
TRACKMOUSEEVENT tme
tme.cbSize = sizeof(tme)
tme.dwFlags = TME_LEAVE
tme.hwndTrack = hWnd
tme.dwHoverTime = HOVER_DEFAULT
pointer dat = GetWindowLong(hWnd, GWL_USERDATA)
SELECT uMsg
CASE WM_MOUSEMOVE
if !enter
enter = TRUE
TrackMouseEvent(&tme)
sendmessage(#<int>dat[0], MSG_TRACK_ENTER, hWnd, lParam)
ELSE
sendmessage(#<int>dat[0], MSG_TRACK_MOVE, hWnd, lParam)
EndIF
return 0
CASE WM_MOUSELEAVE
enter = FALSE
sendmessage(#<int>dat[0], MSG_TRACK_LEAVE, hWnd, 0)
return 0
ENDSELECT
RETURN CallWindowProcA(#<int>dat[1],hWnd,uMsg,wParam,lParam)
ENDSUB
SUB TrackControl(WINDOW parent, INT id)
HWND hControl = GETCONTROLHANDLE(parent,id)
WNDPROC lpFn = GetWindowLong(hControl, GWL_WNDPROC)
pointer dat
IF lpFn <> &TrackHandler
WNDPROC OldWndProc = SetWindowLongA(hControl,GWL_WNDPROC,&TrackHandler)
dat = new(int, 2)
#<int>dat[0] = parent.hwnd
#<int>dat[1] = OldWndProc
SetWindowLong(hControl, GWL_USERDATA, dat)
endif
endsub
SUB UnTrackControl(WINDOW parent, INT id)
HWND hControl = GETCONTROLHANDLE(parent,id)
WNDPROC lpFn = GetWindowLong(hControl, GWL_WNDPROC)
if lpFn = &TrackHandler
pointer dat = GetWindowLong(hControl, GWL_USERDATA)
SetWindowLongA(hControl, GWL_WNDPROC, #<int>dat[1])
delete dat
endif
endsub
Thanks Jalih,
I will.
Think / consider this post closed now as far as I am concerned - thanks everyone.
Andy.