Suggestion for resizing


#1

Currently when resizing a dialog window, the window and all of its components are forced to redraw on every mouse event. This gives the effect that the window updates while resizing, which can be useful at times.

However, with a very complicated number of paint overrides, or just a complicated UI with lots of painting (open gl + other stuff), this is not only unecessary, but taxing. It causes the size repaints to be slow and stuttering.

Can I suggest that JUCE enables the option to paint only the top level window border, like MS Windows does by default? This can be an option on the dialog window itself. Furthermore, it can have a property “respectOSResizeRepaintRules”, which allows you to both turn on repaint for resize, but only if the OS user hasn’t opted for it to be off for all of their windows (something windows lets you do).

Hope this is a good suggestion :slight_smile:


#2

ugh! I’ve always hated the border-resizing thing in Windows… so last century!

If your repaint is so slow, then your interface is going to be pretty stuttery anyway - maybe you could think about caching the slow-to-draw bits?


#3

[quote=“jules”]ugh! I’ve always hated the border-resizing thing in Windows… so last century!

If your repaint is so slow, then your interface is going to be pretty stuttery anyway - maybe you could think about caching the slow-to-draw bits?[/quote]

Caching would not help because the size of the windows are changing, caching is good for repaints due to other apps clipping your app and then being removed. Since nothing within your app has changed, certain areas can be cached and just blitted.

I disagree also that if resizing is slow that it means the whole app is slow. An app can have complex areas that are not designed for multiple subsecond repaints. JUCE is not running on a direct HW accellerated graphics API afterall (OGL or DX).

But I do agree that the way Windows does it is ugly. Maybe there’s a cooler style. But I do think it should be an option. I suppose if you’re really against it then its easy enough to implement within one’s own project.

Food for thought I hope.


#4

imagine the case of drawing a relatively complex 3d model – something that takes maybe 1 second to redraw. i’m getting ready to make the leap from my own gui to juce and this was something i had to deal with. what i ended up doing was flagging windows that didn’t refresh quickly. on resize, those windows simply scaled their contents with a couple opengl calls (my app used opengl for the gui). it was very hacky in that the scaled contents didn’t really line up with the newly resized window on a clean redraw, but it was certainly fast enough.

not that i’d suggest that as a solution, but perhaps there’s some means of inserting a refresh method that would normally call the paint method, but could also be overridden to do whatever tricks the programmer wants to simulate the resize or even just ignore the painting all-together…

(hope my jargon is correct here… i’m a c++ newbie)


#5

The message thread isn’t intended to be used for anything that takes more than a fraction of a second.

Don’t you think that any components that are really complex and slow to generate should get lazily redrawn by a background thread and cached? So you could stretch things around and interact with the app without it feeling sticky, and the graphics would catch up with you a moment later.


#6

That’s why its not making sense to currently have the window repainting as its being resized.

This sounds like a bad idea. Taking Win32 for example, its a single threaded API and the only thread that should be drawing or modifying any paint-effecting calls should be the main UI thread. If other threads need to paint, their calls need to be marshalled to the UI thread first (somewhat expensive).

I don’t believe using threading to do drawing is a good idea, that’s what the main thread should be doing. The other threads should be doing work to change state, which gets reflected by paint routines in the UI/main thread.

I had a similar thought as fathom. A cheap and easy way to show the window while resizing would be to blit once, and scale on each repaint while resizing.

But the problem with the way it is now is that if you have many nested components, you are causing not only all of the repaints, but the overhead of all of those function calls, which can be in the hundreds in some cases. Threading won’t help you here anyway, IMO.


#7

No, no, no. Threading is the only sane way to do something like this. The background thread would draw onto a cached image, which the paint() routine blits to the screen when it changes. Safe, neat, and the app always stays responsive.

The message thread is absolutely never the place to do complex rendering, or any operation that takes a significant time. Imagine if a web-browser blocked the message thread while it went off for a few seconds to download an image!

The functions calls are negligible compared to the time it takes to actually paint things. You’d need many thousands of components before this became noticable.


#8

[quote=“jules”]No, no, no. Threading is the only sane way to do something like this. The background thread would draw onto a cached image, which the paint() routine blits to the screen when it changes. Safe, neat, and the app always stays responsive.

The message thread is absolutely never the place to do complex rendering, or any operation that takes a significant time. Imagine if a web-browser blocked the message thread while it went off for a few seconds to download an image!
[/quote]

The technique you describe make sense for dealing with a static image (a web browser fetching an image), but how does that work when the window keeps resizing? For instance, by the time you are done repainting a complicated nest of windows, and ready to blit (across threads), the user has generated a new size already (remember they are resizing the window) and the image you’ve generated is useless.

I think you are looking at this from the perspective of thread timeslicing and its moot because either way you are going to have to repaint many times a second, whether its in the user thread or the worker thread, it makes no difference. The real problem is that painting complicated windows using GDI (on windows) or any non-HW-direct API is slow and should be avoided, and that is what happens when we have a window that repaints on resize().

The proof of this is real-time 3D applications/games. All drawing calls are done on the main UI thread, not a worker thread. The HW drawing is so fast that you can render and blit hundred of incredibly complicated frames per second, and still have time to poll the input hardware (mouse/keyboard/joystick) all within the same thread! We never use worker threads for rendering/drawing in realtime 3D apps. Worker threads in these apps are used for audio, networking and occassionaly input hardware (but not always).

Again, the above shows that its not a threading issue, its an issue of rendering with a highly abstracted drawing API (like GDI) vs. OpenGL. Since JUCE uses the native rendering API of each OS, it has to assume a worst case scenario.

[quote=“jules”]

The functions calls are negligible compared to the time it takes to actually paint things. You’d need many thousands of components before this became noticable.[/quote]

They may be the smallest portion of the performance hit, but if you have 300 calls for each resize, and the user is generating many resize events per second (windows mouse resolution is 40/sec) then that is a lot of function calls. Not to mention that there is a cost of syncronizing between a main thread and your drawer/worker thread. Its not exactly negligable, especially if the App is actually doing something itself while all this is going on.


#9

Another thing to note is that forcing repaint on resize() does not play well with components like the OpenGL component, or a DirectX component (should there ever be one), because they are doing painting on their own timing, in the way I described above.


#10