Liberty BASIC Community Forum
« Locate Refresh »

Welcome Guest. Please Login or Register.
Aug 16th, 2017, 4:50pm


Rules|Home|Help|Search|Recent Posts|Notification


« Previous Topic | Next Topic »
Pages: 1  Notify Send Topic Print
 thread  Author  Topic: Locate Refresh  (Read 171 times)
Rod
Global Moderator
ImageImageImageImageImage


member is offline

Avatar

Graphics = goosebumps!


PM

Gender: Male
Posts: 5471
xx Locate Refresh
« Thread started on: Aug 9th, 2017, 10:14am »

Lining stuff up in a window is one of the things that suffers between different Windows versions. Things that look ok in Win10 don't in Vista etc. So an easy way to get system metrics is desirable. Yes there are API calls but why am I not able to get this resize handler to work programatically, ie forcing a resize and redraw. It works perfectly if I manually resize the window frame.

Code:
    nomainwin
    graphicbox #1.graph, 5, 37, 300, 200
    WindowWidth = 312
    WindowHeight = 282

    open "Resize" for window as #1
    #1 "trapclose quit"
    #1 "resizehandler resized"
    call resized h$
    wait

sub resized handle$

    #1.graph "locate 4 36 "; WindowWidth - 8; " "; WindowHeight - 8 - 32
    #1 "refresh"
end sub

sub quit handle$
    close #1
    end
end sub
 
User IP Logged

Chris Iverson
Administrator
ImageImageImageImageImage


member is offline

Avatar

20% Cooler


Homepage PM

Gender: Male
Posts: 2276
xx Re: Locate Refresh
« Reply #1 on: Aug 9th, 2017, 4:25pm »

Interesting. I don't know if this is an optimization in LB or Windows, but every way I can think of for "refreshing" the window(even via the API) doesn't work if the window stays the same size. (I'm fairly certain this is in LB, as I don't think I've had C/C++/C# applications with similar issues)

InvalidateRect(), MoveWindow() with the same size/position, etc.

It only updates/refreshes if the actual window size changes.

...Hmm, let me try it with a WM_SIZE message.

EDIT: Sending the _WM_SIZE message directly DOES cause it to update.

Code:
    uMsg = _WM_SIZE
    wParam = _SIZE_RESTORED
    lParam = (WindowHeight * 65536) + WindowWidth
    a = SendMessage(hwnd(#1), uMsg, wParam, lParam) 



SendMessage function:
Code:
Function SendMessage(hWnd, uMsg, wParam, lParam)
    CallDLL #user32, "SendMessageA",_
    hWnd as ulong,_
    uMsg as ulong,_
    wParam as long,_
    lParam as long,_
    SendMessage as long
End Function 



Either way, I don't know why LB is not explicitly redrawing itself when issued a refresh command.
« Last Edit: Aug 9th, 2017, 4:30pm by Chris Iverson » User IP Logged

"Do you believe in destiny?" - Pyrrha Nikos, RWBY
"With what wish will your Soul Gem shine?" - Kyubey, Puella Magi Madoka Magica
Rod
Global Moderator
ImageImageImageImageImage


member is offline

Avatar

Graphics = goosebumps!


PM

Gender: Male
Posts: 5471
xx Re: Locate Refresh
« Reply #2 on: Aug 10th, 2017, 06:25am »

Ok, Richard has explained that once the event fires Liberty actually returns the client area in WindowWidth, WindowHeight. Potentially very useful.

The problem remains that I can't get the event to fire programmatically. I want to do this without the api call, it returns the client area in WindowWidth, WindowHeight which would be extremely useful in positioning controls.

But the refresh on its own changes nothing, I need to move the frame or issue Chris's api call to force the refresh to actually work.

Edit to add, the refresh changes the location of the graphicbox when I call the resizer sub but it uses the wrong WindowWidth and WindowHeight values. It uses the original values which are too big. If the resize handler fires on a frame move or from Chris's API call to redraw it then it uses the correct WindowWidth and WindowHeight values which are transformed to the smaller client area values.

So either have a call to refresh changes those values or give us new ClientWidth ClientHeight variables. :)

Code:
'   nomainwin
    graphicbox #1.graph, 5, 37, 300, 200
    WindowWidth = 312
    WindowHeight = 282

    open "Resize" for window as #1
    #1 "trapclose quit"
    #1 "resizehandler resized"
    call resized h$

'wait

     uMsg = _WM_SIZE
    wParam = _SIZE_RESTORED
    lParam = (WindowHeight * 65536) + WindowWidth
    a = SendMessage(hwnd(#1), uMsg, wParam, lParam)
    wait

Function SendMessage(hWnd, uMsg, wParam, lParam)
    CallDLL #user32, "SendMessageA",_
    hWnd as ulong,_
    uMsg as ulong,_
    wParam as long,_
    lParam as long,_
    SendMessage as long
End Function

sub resized handle$
    print WindowWidth,WindowHeight
    #1.graph "locate 1 1 "; WindowWidth-2; " "; WindowHeight-2
    #1 "refresh"
    print WindowWidth,WindowHeight
end sub

sub quit handle$
    close #1
    end
end sub
 



Richard offered this explanation in an email to me but it remains the fact that calling locate / refresh programmatically changes nothing. Rem out Chris's api call and you will see that nothing changes.

Quote:
Actually it *is* working!  The true reason why it *appears* not to be
working is quite different from what you (and Chris Iverson) think: the
values of WindowWidth and WindowHeight are different!  Try commenting
out the NOMAINWIN and adding a 'print WindowWidth, WindowHeight' to the
resize handler and all will be revealed.

The strange behaviour stems from a feature of LB (which I had to copy in
LBB for compatibility) which is that when a window is resized the values
of WindowWidth and WindowHeight are (unexpectedly) changed 'behind the
scenes' so that instead of corresponding to the entire window - which
they do initially - they correspond only to the window's Client Area
(i.e. excluding title bar and borders).

So when you 'force call' your resize handler those variables have their
initial values, but when it is later called automatically by the resize
action they have different values.  Chris's trick of sending a WM_SIZE
message (which also works in LBB) is actually updating the values of
WindowWidth and WindowHeight!

« Last Edit: Aug 11th, 2017, 03:45am by Rod » User IP Logged

Chris Iverson
Administrator
ImageImageImageImageImage


member is offline

Avatar

20% Cooler


Homepage PM

Gender: Male
Posts: 2276
xx Re: Locate Refresh
« Reply #3 on: Aug 11th, 2017, 01:05am »

Ohhhh, Richard's explanation makes sense. That's what I get for not paying close attention to the WM_SIZE documentation.

He's correct that the values specified for WindowWidth and WindowHeight in the beginning specify the maximum size of the window, but it changes to the client area size after a resize is issued by Windows.

The reason for this is, when Windows needs to tell a window that it's size has changed(so it can redraw itself to match the new window), it sends a WM_SIZE message.

However, the documentation for WM_SIZE explicitly states that the values passed in for the width and height to the WM_SIZE command are the client area, not the full window area.

That's why LB changes to using client area after a resize - the information that Windows provides the program is the client area, not the full window size.

This actually makes sense; all controls within the window are positioned according to the parent window's client area, not the full window size. That way, you don't need to do the math of accounting for the borders, titlebar, etc, yourself when positioning controls. Therefore, the new client area coordinates are the best to use in this case.

(Otherwise, putting a control at 0,0 or 10,10 on your window would overlay it on the title bar instead of the upper-left corner of the actual "window"(client area))
« Last Edit: Aug 11th, 2017, 01:06am by Chris Iverson » User IP Logged

"Do you believe in destiny?" - Pyrrha Nikos, RWBY
"With what wish will your Soul Gem shine?" - Kyubey, Puella Magi Madoka Magica
Rod
Global Moderator
ImageImageImageImageImage


member is offline

Avatar

Graphics = goosebumps!


PM

Gender: Male
Posts: 5471
xx Re: Locate Refresh
« Reply #4 on: Aug 11th, 2017, 02:42am »

Yes, so refresh provides useful info on client area that would allow controls to look right on any windows version. But it needs to work simply by issuing the refresh command not by api call or frame movement. It won't break anything making the change because refresh only works in conjunction with locate and these have always been feed the client are values in the past.
User IP Logged

Chris Iverson
Administrator
ImageImageImageImageImage


member is offline

Avatar

20% Cooler


Homepage PM

Gender: Male
Posts: 2276
xx Re: Locate Refresh
« Reply #5 on: Aug 11th, 2017, 10:13pm »

That's exactly the point - it DOES work. It's the difference between the client area and window area that's throwing the math off before any auto-resize.

Take out the resize handler AND the manual call to resize, and resize the window to show the full graphicbox.

You'll see the graphicbox is opened to 300 x 200 - exactly as initially specified.

Now, leave out the resize handler, but readd the manual call to resize. Resize the window to see the full graphicbox.

You'll see that, after the manual resize, the graphicbox is opened to 304 x 242 - which matches the math when compared against the INITIAL values of WindowWidth and WindowHeight(312 - 8 = 304, 282 - 8 - 32 = 242)

The window IS updating - it's just that it's still past the borders of the window, so you can't see it! After the first auto-resize, WindowWidth and WindowHeight hold the client area of the window, and then all the math checks out correctly.

The manual invocation of the resize handler, and all of the calculations within it, are working properly. It's the different meaning of WindowWidth and WindowHeight as execution proceeds that's throwing it off.
« Last Edit: Aug 11th, 2017, 10:15pm by Chris Iverson » User IP Logged

"Do you believe in destiny?" - Pyrrha Nikos, RWBY
"With what wish will your Soul Gem shine?" - Kyubey, Puella Magi Madoka Magica
Rod
Global Moderator
ImageImageImageImageImage


member is offline

Avatar

Graphics = goosebumps!


PM

Gender: Male
Posts: 5471
xx Re: Locate Refresh
« Reply #6 on: Aug 12th, 2017, 04:36am »

To be really clear it is NOT working correctly,it is inconsistent, moving the frame gets the correct metrics. calling the resize handler manually gets nothing, the metrics remain the same.

I was hoping for a simple way to be sure drawn controls lined up nicely no matter what version of windows used. Simply setting up the resize handler and calling it once at the start of a program should realign the controls, even though the window size has not actually changed.
User IP Logged

Chris Iverson
Administrator
ImageImageImageImageImage


member is offline

Avatar

20% Cooler


Homepage PM

Gender: Male
Posts: 2276
xx Re: Locate Refresh
« Reply #7 on: Aug 13th, 2017, 10:29pm »

Sorry, I should've clarified on my end.

You're absolutely right.

The little details I was talking about DO all work properly - but they add up to something that doesn't. Something that is inconsistent and confusing.

Unfortunately, the main fix for this would have to be something changing within LB itself.

For now, I can suggest a workaround of first opening the window to a size one pixel less than what you want, and then call the MoveWindow() API to cause it to expand one pixel, forcing it to run the resizehandler. You can even open the window as hidden, and show it after the resize, so the user doesn't see the resize. It's a bit more work, but it's better than calculating positions for everything twice.

Alternatively, you can ignore WindowWidth and WindowHeight in the resizehandler, and use GetClientRect() to get the client area manually in the resize handler, to make sure you're always working with consistent values.
« Last Edit: Aug 13th, 2017, 10:31pm by Chris Iverson » User IP Logged

"Do you believe in destiny?" - Pyrrha Nikos, RWBY
"With what wish will your Soul Gem shine?" - Kyubey, Puella Magi Madoka Magica
Pages: 1  Notify Send Topic Print
« Previous Topic | Next Topic »

Rules|Home|Help|Search|Recent Posts|Notification

Donate $6.99 for 50,000 Ad-Free Pageviews!

| |

This forum powered for FREE by Conforums ©
Sign up for your own Free Message Board today!
Terms of Service | Privacy Policy | Conforums Support | Parental Controls