Hey all,

I have a question that has been hanging me up for a few hours now. Im working on a 'fun' project which is basically a skined window object class. As such, i got all the skinning working from a resource bitmap and related skin coordinate info which is also packed in the resource file (to make the class easy to use).

My problem is giving the skinned window some functionality. Im trying at the moment to get it able to resize. The paint algo's work for resizing, however i cant seem to get the window "size box" to appear, or even how to trigger this event. I scoured the API for some hint, but havent found what im looking for.

The window itself is a WS_POPUP window, which alows me to get the full window area as the client area. Combined with regions and my skinning algo in the WM_PAINT handler it works well. However, the closest i get to resizing is when i set WS_SIZEBOX in the window styles. But this has a major drawback: It draws a frame around the region area, and the client DC returned from the WM_PAINT message doesnt include the border area where the frame appears. I then tried removing the WS_BORDER style but this did nothing.

I currently have regions set up to trap the cursor and determin which direction a resize should take place when the LButton is pressed in my client area, because i thought i would have to write my own handlers for resizing and avoid the WS_SIZEBOX style and all windows built in support. But as i said earlier I cant find an API that would give me the standard windows resize border that you often see when you resize any window.

Can anyone give me some help/direction suggestions on which direction i should proceed in?

Thanks alot!
Posted on 2004-03-21 15:19:58 by NaN
Use DefWindowProc(window,WM_SYSCOMMAND,n,0);
Where n is one of the following:
0xf000 - Sizing with keyboard
0xf001 - Left edge
0xf002 - Right edge
0xf003 - Upper edge
0xf004 - Upper left corner
0xf005 - Upper right corner
0xf006 - Lower edge
0xf007 - Lower left corner
0xf008 - Lower right corner

Btw, by processing WM_NCCALCSIZE and WM_NCPAINT, you can define your own frame.
Posted on 2004-03-21 16:30:26 by Sephiroth3
Ok... This helps alot and got things working. But im at another problem that I puzzling me.

What im doing is:

(1) the window is created as WS_POPUPAPPLICATION only. The WS_SIZEBOX is not included.
(2) processing WM_MOUSEMOVE / WM_LBUTTONDOWN messages with respect to regions determined for the resize boxes
(3) sending out SYS_COMMAND messages as Sephiroth3 helped me out on, which then does the appropriate resize action
(4) after a resize, in the WM_EXITSIZEMOVE I recalculate the window region and reset size box regions for the new window shape
(5) the window is repainted on the WM_PAINT message that follows the resize

Now the problem is when i shrink the window size, often the old image lingers as its screen space was not told to be redrawn properly. This one is even more puzzling than the previous. The only thing left out is im not processing (fully) the WM_NCCALCSIZE message, because to be honest, im having a hard time understanding how to use it properly... Im passing it on to the DefWindowProc, however, im debugging its return.. which is consistantly 0! (I cant find this WVR_* message value?? ) I tried forcing it to WVR_VALIDRECTS but its not improving anything.

Any thoughts?
Posted on 2004-03-21 20:48:08 by NaN
This one is truely wierd. What im finding is that the 'lingering' image is due to the fact that the NC area is one pixel wide around the window, and that while the rects' from WM_NCCALCSIZE is correct in their befor after sizes, windows is not 'cleaning up' the old rect fully. The lingering images are then only corrected when the window in the background (down the Z order) is made to redraw itself.

In essence the lingering image is dumped into another processes to deal with, but this process is unaware of it, so it lingers untill the other process wakes up on some event and redraws itself. :confused:

Posted on 2004-03-21 21:08:42 by NaN
Here is a picture of the mess im in ;)

The recalculated region for the skinned window is working correctly, as the fact the cursor is switched to RadASM (background window) within the rectangle of my skinned window, however, the old image from the previous resize is left in a 'validated' state. Even though its not valid and should be redrawn from the next window in the Z-order of things.

I've tried forcing invalid rect and region at various points of the resize, but nothing seems to work.

Here is the pic:
Posted on 2004-03-21 21:22:06 by NaN
id just grab the gdi handle to the whole window and repaint it every so often, like 30 times a sec or sometin.
Posted on 2004-03-21 21:27:27 by Qages
Murphy's Law Is always hanging over me :rolleyes:

I figured out my problem. I was so intent on this being a big convoluted problem when the answer was under my nose.

When i recalculated the resized region, and set it. I had "FALSE" set for the redraw flag (dont ask me why!).

Apparently this is the ONLY key moment you can fully redraw the old region, as i was sticking in invalidates at every step along the resizing process with no luck.

Now all I have to do is clean up the flicker... Which I think will not be too hard to do.
Posted on 2004-03-21 21:45:26 by NaN
Here is a working example ;)

I will release the full source when im done with the design... Besides its done with ObjAsm32 and I suspect not too may people are familiar with it as of yet...

Anywho, open it and see if it crashes on you maching.. There always seems to be a bug with this stuff that is usually OS dependant. Lemme know if it works. Thanks alot!

Posted on 2004-03-21 23:07:34 by NaN
The design is pretty robust. I have *all* key info in the RC file, such that the object class can be used on different windows with different skins. The resource sample is:


1211 SKINDATA // Format Px, Py, Width, Height
0L, 0L, 23L, 54L, // Upper Left Corner Skin
0L, 57L, 23L, 23L, // Lower Left Corner Skin
26L, 0L, 79L, 54L, // Upper Right Corner Skin
26L, 57L, 79L, 23L, // Lower Right Corner Skin
0L, 55L, 105L, 1L, // Horizontal Fill Bar
24L, 0L, 1L, 80L, // Vertical Fill Bar
40L, 40L, 150L, 200L, // Rgn Radius x1, x2, Min width, Min Height
34L, // Caption Bar Height
1201L, // Bitmap Resource ID
501L, // Icon Resource ID
0x00E4F9E1L, // Blt Back Color in client area
7L, // 1 = Vertical only / 2 = Horizontal only / 4 = XY
601L, // iCurX
602L, // iCurY
603L, // iCurXY
604L // Default Cursor

While the BMP skin is:
Posted on 2004-03-21 23:09:59 by NaN
Works pretty weird on my machine, win2k+sp4.

When I resize to smaller dimensions, it works fine. But when I resize to larger dimensions, the window doesn't actually resize until I let go of the mousebutton. If sizing up and down without letting go of the button, the "upsizing" works fine within the old max. window size.

Also, there's a lot of flickering while resizing, and the affected corners on resize go square instead of round.

It's nice work nevertheless, will be pretty decent once it's done. :alright:
Posted on 2004-03-22 03:11:05 by f0dder
Thanks f0dder.

The points you indicate are bizzard to me. Im not even sure where to look!

(1) The resize box will always be square. No way around it.
(2) When resizing, with the Lbutton down, the old image should not change, and only a square outline should follow the cursor (no flickering), just a square dotted line outlining a proposed size and shape. Even when you size inward, it should show its outline box being redrawn over the old image.
(3) When you release the LButton the window is redrawn in a resized shape. On my Win98 it have a very fast single instance flicker when the window gets very big, but not when small?
(4) Win98 has no issues on the limits of the resize. However, NT seems to like memory aligned if I remember things correctly. The LOCAL's on the stack may not be aligned on 8 byte boundries (definitely 4 byte tho). I only modify the lower limits. The upper limits are unmodified from the OS presets.

The bizzare part is alot of what you are indicating is stuff done by the OS, from appropriate DefWindowProc calls :confused:

Anyone else seing similar stuff on their OS's?

Posted on 2004-03-22 17:14:32 by NaN
The more i think about what your saying, I would say your OS has its resize API rewritten a bit. As i indicated above, there is only a WM_PAINT message issued when the resizing is finished. Both ways (up or down). Sounds like your OS issues a WM_PAINT when resizing small, but not when resizing BIG. This would explain the flickering your seeing, as its repainting alot more that designed ;)

Maybe i can interlock this somehow with the WM_PAINT message...

Posted on 2004-03-22 17:28:48 by NaN
Hmm, perhaps you haven't tested with "show window contents while dragging" enabled? Sounds like it, since you're talking about resize box and such :). When dragging with this setting enabled, the window is constantly being repainted on resize - which is why WM_ERASEBACKGROUND+WM_PAINT should be kept as simple and fast as possible, possibly using double-buffer technique.

The "squareness" I was talking about was thus not the "resize box" (since that doesn't appear with shows-content enabled), but rather that the corners affected by the resize aren't rounded, but have a black background filled to make them square.

4byte align should be just fine, as long as you're not dealing with SSE data types and such :) - and since you will be mainly limited by the speed of GDI calls, there's no reason to 32-byte align stuff either.

Have a look at the attached screenshots to see what I mean...

PS: are you issuing a GdiFlush() call after your painting is done? This might be an idea, I guess.
Posted on 2004-03-22 17:29:59 by f0dder
...that was sizing to larger dimensions. Here comes sizing to smaller dimensions. PS: is it possible to attach multiple files in one post?
Posted on 2004-03-22 17:30:44 by f0dder
Thanx f0dder, you nailed it.

I never heard or seen this setting in action. But after some snooping around the OS i found it in the destop settings.

When i turn it on, i get exactly the behavior your talking about!. So now have something to work with ;)

There is definitely alot more flickering as well, which im not surprised to see. As well to support this 'feature' i will need to adjust the region on the fly, which im not so sure can be done... It would be better if i can somehow force the window to behave without this 'feature'.. but only for the skinned window. Since it wouldnt be appropriate to mess with system settings ;)

Anywho.. time to do some MSDN reading ;)
Posted on 2004-03-22 18:51:19 by NaN

There is definitely alot more flickering as well, which im not surprised to see.

Can be eliminated though - double buffering. Means more memory usage, but not too bad.

As well to support this 'feature' i will need to adjust the region on the fly, which im not so sure can be done...

Should be doable, I've seen other skinned windows that resize "correctly". Like MSN, for instance. MSN is rather bloated etc., so it flickers a bit - but it can be done, and it can probably be implemented efficiently with no flicker.

Btw, If you need to update the dimensions of some internally used render-to-bitmaps (like if you do double buffering), I would suggest to resize in "chunks", say in 64px increments. Less overhead that way.

It would be better if i can somehow force the window to behave without this 'feature'.. but only for the skinned window.

Naaah. You're doing eyecandy, so you ought to go all the way and do it "the right way" :p. The resizing rectangle looks plain ugly when you're used to the full-resize, this has especially nagged me with toolbars in some IDEs. I think XP comes with this setting pre-enabled, perhaps 2k too. But it's been a long time since my last OS reinstall, so I could be wrong. Point being, anyway, that a lot of people will be used to "full dragging" resize, and would wrinkle their noses at sizing rectangles.

Since it wouldnt be appropriate to mess with system settings ;)

Indeed it wouldn't, and doing it would piss off a lot of users.

Anyway, keep up the good work - it looks nice-ish so far.

PS: Sorry for not telling you where to find the "full dragging" option... once you get too used to a feature, you forget that other people might not know it, or where to find it.
Posted on 2004-03-22 19:02:02 by f0dder
Well thanks to f0dder for a 'push' into directions I really didnt want to be in ;) , I can say its much more robust now.

To be honest, this is the best its going to get! There is still some redaw flickering, but im 100% sure its due to the OS and not the program. When you resize very fast, the OS has a lag time processing frames, as such you get the standard lagging refresh you typically see on apps like this.

But this is only in the 'feature' mode that f0dder pointed out. It resizes very fast and smooth without the show resize feature on.

Here is another sample to check out.

Thanks again f0dder :alright:
Posted on 2004-03-22 20:34:32 by NaN
Great, NaN, that's how it should be done :) - and there isn't really any flickering, not noticable anyway. Did you do double buffering?

Oh, I suppose it's on purpose only the right and bottom edges and the right,bottom corner allow resizing?
Posted on 2004-03-23 03:15:19 by f0dder
Ya, I didnt see the need for the other 5 edges. If you need the upper corner sized, you can move the window first ;)

I tried it on my XP machine at work, and was surprised that the normal resize box (outline only) on XP still does some back ground stuff. It is definitely not the same code as what my 98 machine has for the api. It runs beautifully in you 'show resize' mode, however.

Oh and yes, i did back buffer. I did it the wrong way as well but I didnt care. I will clean it up when i know its working correctly (as it now seems to be). What im mean by wrong way is im creating a DC et. al. in the WM_PAINT message before I do all the skinning, and then destroy all resources after finished. It was a very fast way to integrate a back buffer into the existing source. ;) I dont like stuff like this tho so i will proabaly clean it all up to have only one back buffer created on startup and stored into the object instance for use by the WM_PAINT method. Speed wise this is definitely the better solution. ;)

Anyone else have any grievences with the example?? (Seems only f0dder is willing to add comment)

Posted on 2004-03-23 21:02:49 by NaN

Ya, I didnt see the need for the other 5 edges. If you need the upper corner sized, you can move the window first ;)

Lazybones ;)

I dont like stuff like this tho so i will proabaly clean it all up to have only one back buffer created on startup and stored into the object instance for use by the WM_PAINT method.

Sounds good, as long as you still handle resize (and do it in "chunks"). Btw, CW_OWNDC class style might help a bit?
Posted on 2004-03-24 09:34:56 by f0dder