So let's say a guy wants to create an application with a window containing several panes, something like OllyDbg, where the panes are linked together and mutually resize and all.
How would he do that? Is this something that requires Visual Studio? MFC? Can ResEd create something like this? Is it possible to "roll your own" (even though I'm sure that would be more work)? Perplexed here.
The magic secret is the API MoveWindow().
Quote from: hutch-- on February 05, 2022, 04:58:28 PM
The magic secret is the API MoveWindow().
You mean the function MoveWindow() in the Win32 API. :dazzled:
But what about those nice seamless shared borders: how do you get those? Plus those dividers that you can grab and drag; those aren't normal window borders.
> You mean the function MoveWindow() in the Win32 API
No, I meant what I said, the API MoveWindow().
OK, but how do you get those shared borders and dividers? Those don't just happen when you put windows next to each other.
GetClientRect() and/or GetWindowRect() for coordinates, then use MoveWindow() to position each child window to where you want it.
If you need to use GetWindowRect() which produces screen rather than client coordinates, you use either ScreenToClient() or the reverse ClientToScreen() to get the coordinates you need.
There is no easy way to do what you want.
Olly seems to be a MDI application.
Inside window don't have to be real dividers, an illusion is enough, as frame window can act as divider for child windows.
Only GetClientRect() and MoveWindow() are needed with some global X and Y variables.
Client windows can have their own borders / shadows.
Hutch is right, there is no magic API that does the job for you - it's all MoveWindow. Probably, that is: Olly does not use standard controls. You should absolutely try WinID (https://dennisbabkin.com/winid/), it gives you a wealth of information about the controls used.
I use WinSpy, which I think does about the same thing, give you info about whatever window (control) you click over.
This silly program written in C have two panes.
http://masm32.com/board/index.php?topic=7483.msg81793#msg81793
With it, someone see a one way to do panes.
There are several "mechanisms" that can be used to make those interfaces.
- MultiWin Interface: Timo example and Olly use this mechanism, with one or more Splitters. You can resize or hide child windows, but relative position is fixed.
- Multiple Document Interface (MDI): Is used more for repetition of similar windows, but you can make that with different windows.
- Docking Windows: Windows can be moved to different niches or even out of application window dragging them with mouse. Very common in IDE like Visual Studio, RadAsm, EasyCode, etc
Most IDE programs use docking windows, but inside that windows they sometimes use the others mechanisms :rolleyes:
Later I remembered that Zale don't like docking windows, then PB IDE is multiwin, with a MDI inside.
Quote from: NoCforMe on February 05, 2022, 01:43:15 PM
So let's say a guy wants to create an application with a window containing several panes, something like OllyDbg, where the panes are linked together and mutually resize and all.
How would he do that? Is this something that requires Visual Studio? MFC? Can ResEd create something like this? Is it possible to "roll your own" (even though I'm sure that would be more work)? Perplexed here.
In WM_SIZE use MoveWindow or better DeferWindowPos to arrange the child windows.
https://riptutorial.com/winapi/example/8080/wm-size
QuoteOK, but how do you get those shared borders and dividers? Those don't just happen when you put windows next to each other.
There is no common control for that. In a plain Win32 application, typically the main window is responsible to do this. Or you create your own "divider control".
http://www.catch22.net/tuts/win32/splitter-windows
In a single plane, think of 3 CreateWindowEx() windows side by side. The left one is a normal interface windows, the middle one is the splitter window and the right side one is another normal interface windows. The splitter window is where the control of resizing the left and right windows is performed. By using the mouse location, you can drag the splitter left or right. Within the control of the mouse moving the splitter window, you use MoveWindow() to control all 3 windows.
The left side window has its right side border changed. The splitter window maintains its width and the right side window is moved left to right with its right side border restricted to the right side of the parent window.
My Skeleton - Alive and Kicking example http://wjradburn.com/software/Skeleton.zip (http://wjradburn.com/software/Skeleton.zip) has two child windows using the main window to process messages for the "splitter bar" which is just the space between the two panes. A similar approach could be used for more panes, but would be a bit extra work for horizontal and vertical splits as in OllyDbg.
Splitter bar--that's the key thing I was looking for. Looking at "Alive and Kicking" now. Thanks!
Also there is an Splitter example in Masm32 SDK, inside exampl03 directory.
So the "splitter" is really just that little slice of the underlying parent window that shows through between the child windows, because the only time the parent window will get mouse messages is when the mouse is over that little sliver; all other messages will go to the children. Neat. And I was wondering how the application I was looking at got a special cursor to move the splitter, but that's just a matter of loading that cursor for the underlying window.
Exactly. And while user passes the mouse from left to right, from one control to the neighbouring one, the main WndProc receives a bunch of messages:
msg 1285 WM_SETCURSOR
msg 1286 WM_SETCURSOR
msg 1287 WM_SETCURSOR
msg 1288 WM_SETCURSOR
msg 1289 WM_GETICON
msg 1290 WM_GETICON
msg 1291 WM_SETCURSOR
msg 1292 WM_NCHITTEST
msg 1293 WM_SETCURSOR
msg 1294 WM_MOUSEFIRST
msg 1295 WM_NCHITTEST
msg 1296 WM_SETCURSOR
msg 1297 WM_MOUSEFIRST
msg 1298 WM_NCHITTEST
msg 1299 WM_SETCURSOR
msg 1300 WM_MOUSEFIRST
msg 1301 WM_SETCURSOR
msg 1302 WM_SETCURSOR
WM_SETCURSOR looks promising ;-)
A splitter without own window / control have some flickery in slow PC, but not an problem anymore, but i was somewhere at 2003.
wjr examples might work in that principle, a parent window work as splitter.
EDIT:
//these are for splitter, begin
case WM_SIZE:
MoveWindow(hWndTV, 0, 0, uDrag-1, HIWORD(lParam), TRUE);
MoveWindow(hWndLV, uDrag+1, 0, LOWORD(lParam)-101, HIWORD(lParam), TRUE);
return 0;
case WM_LBUTTONDOWN:
SetCapture(hWnd);
bDrag = TRUE;
return 0;
case WM_LBUTTONUP:
ReleaseCapture();
bDrag = FALSE;
return 0;
case WM_MOUSEMOVE:
if (bDrag) {
GetClientRect(hWnd, &rect);
if ((LOWORD(lParam)>50) && (LOWORD(lParam)<(rect.right)-50)) {
MoveWindow(hWndTV, 0, 0, LOWORD(lParam)-1, rect.bottom, TRUE);
MoveWindow(hWndLV, LOWORD(lParam)+1, 0,
rect.right-LOWORD(lParam)+1, rect.bottom, TRUE);
uDrag = LOWORD(lParam);
}
}
return 0;
//these was for splitter, end
Interesting:
What's the point of DeferWindowPos? (https://devblogs.microsoft.com/oldnewthing/20050706-26/?p=35023)
One of the toys in MASM32 is "qetb.exe" and that uses a 3 window design, the middle one being the splitter and as a separate window, you can change the splitter colour on mouse click. All done via MoveWindow().
Next question: let's say you have an app with 3 control windows, say one on the left and two stacked up vertically on the right. How to differentiate between landing on the vertical and horizontal splitters? (Because you want different cursors for them to guide the user.)
Maybe it's simple: if the cursor position is to the right of the vertical split, then load the vertical (north-south) cursor, else load the horizontal (east-west) one. Because if it's to the right of the vertical split, it must be somewhere over the horizontal split.
You can probably solve it with code inside Wm_SetCursor message
https://docs.microsoft.com/en-us/windows/win32/learnwin32/setting-the-cursor-image
TLODBC_sHell had this kind of code with 3 panes:
dx and dy are just delta of mouse positions against drag X Y positions.
void OnLButtonDown(HWND hWnd, BOOL fDoubleClick, int x, int y, UINT keyFlags)
{
int dx, dy;
SetCapture(hWnd);
dx = x - uDragX;
if (dx > - 10 && dx < 10)
bDragX = TRUE;
dy = y - uDragY;
if (dy > - 10 && dy < 10)
bDragY = TRUE;
}
void OnLButtonUp(HWND hwnd, int x, int y, UINT keyFlags)
{
ReleaseCapture();
bDragX = FALSE;
bDragY = FALSE;
}
void OnMouseMove(HWND hWnd, int x, int y, UINT keyFlags)
{
RECT rc;
BOOL bMove;
int dx = x - uDragX;
int dy = y - uDragY;
if (dx > -5 && dx < 5)
SetCursor(LoadCursor(NULL, IDC_SIZEWE));
else if (dy > -5 && dy < 5)
SetCursor(LoadCursor(NULL, IDC_SIZENS));
else
SetCursor(LoadCursor(NULL, IDC_ARROW));
bMove = FALSE;
GetClientRect(hWnd, &rc);
if (bDragX && !bDragY) // X
{
if (x > 50 && x < (rc.right - 50))
{
uDragX = x;
bMove = TRUE;
}
}
if (bDragY && !bDragX) // Y
{
if ((y > 50) && y < (rc.bottom - 50))
{
uDragY = y;
bMove = TRUE;
}
}
if (bMove)
{
ReSizeWindows(hWnd);
}
}
Yes, I think that confirms what I speculated about above.
Back to the laboratory!
My first attempt, but I'm not satisfied - it's slow and flickery.
Extract files to a folder and launch the exe.
Hi
Maybe you can get inspiration from one of the ObjAsm examples. :cool:
Regards, Biterider
Quote from: Biterider on February 08, 2022, 07:41:56 AM
Maybe you can get inspiration from one of the ObjAsm examples. :cool:
Thanks, it works fine, and no flicker, but in contrast to mine you don't update the controls
while you are dragging.
I'll have to study \Masm32\examples\exampl03\splitter\splitter.asm, it updates while dragging but more smoothly than mine :cool:
JJ, the problem I have with your example is not so much flicker as the annoyance that I have to drag the splitter really S-L-O-W-L-Y or else it escapes my grip. Reminds me of a program I wrote that moves things (control windows) around in a parent window and lets you resize them: really flaky behavior; sometimes things jump erratically, etc. Apparently this is more of an art than a science.
The notation is PowerBASIC but you do the same thing in assembler.
MoveWindow hSplitter,splitr-2,rbh,5,Rct.nBottom-(rbh+sbh),%TRUE
MoveWindow hEdit,splitr+1,rbh,Rct.nRight-splitr-1,Rct.nBottom-(rbh+sbh),%TRUE
MoveWindow hList,0,rbh,splitr-1,Rct.nBottom - (rbh + sbh), %TRUE
Flickering.
wcex.hbrBackground = %NULL ' set the background brush to 0 or NULL
Quote from: NoCforMe on February 08, 2022, 04:35:40 PM
JJ, the problem I have with your example is not so much flicker as the annoyance that I have to drag the splitter really S-L-O-W-L-Y or else it escapes my grip.
I know. I've tried with WM_MOUSEMOVE instead of WM_SETCURSOR, no change. I need to rethink the logic a little bit (if I find the time).
Attached a C source from an obscure web location. It's 140 lines short, but my three C compilers bark at them, for various reasons. C/C++ is a waste of time.
No compiling problems with Pelles C 11
EDIT: without CRT too.
Quote from: jj2007 on February 08, 2022, 08:26:24 PM
Attached a C source from an obscure web location. It's 140 lines short, but my three C compilers bark at them, for various reasons. C/C++ is a waste of time.
Here, I translated it to MASM (vanilla) for you. Works, Whoop-te-do.
Thanks, that's a nice action by somebody whose name is no C for me :tongue:
:rofl:
Quote from: TimoVJL on February 09, 2022, 06:11:24 AM
No compiling problems with Pelles C 11
Thanks, Timo. I guess I must check my version :rolleyes: