ResizeGadgets: Auto-resize or auto-move your gadgets.

Share your advanced PureBasic knowledge/code with the community.
User avatar
NoahPhense
Addict
Addict
Posts: 1999
Joined: Thu Oct 16, 2003 8:30 pm
Location: North Florida

Post by NoahPhense »

gnozal wrote:
NoahPhense wrote:@gnozal

I just had to add this.. ;) My blackice picks up your GIF.. and reports it
as such everytime I enter a thread that you are in.

http://www.iss.net/security_center/refe ... 16027.html

people.freenet.de :D

- np
:shock: Don't remember from where I got this GIF, but I am using it since quite a while ...
I am behind a corporate firewall, and it don't complain.
Didn't mean it was bad.. just thought it was funny that it got picked up
for floading the browser.. ;)

- np
rsts
Addict
Addict
Posts: 2736
Joined: Wed Aug 24, 2005 8:39 am
Location: Southwest OH - USA

Re: PB 4.0 version added

Post by rsts »

USCode wrote:New version for PB 4.0 added to original posting.
Just what I needed. Works fine. Many thanks.

:)

cheers
akj
Enthusiast
Enthusiast
Posts: 668
Joined: Mon Jun 09, 2003 10:08 pm
Location: Nottingham

Post by akj »

I hope I am not going to annoy anyone, but I needed to modify the Resize Gadgets code as I wished to include an extra possibility of scaled (proportional) resizing, so I thought I might as well post my revised code.

My new code can, for example, simultaneously increase/reduce the size of all gadgets (and the gaps between gadgets) pro-rata according to the dimensions of the resized windows, which is something the original code cannot do.

The original routine was declared thus:
Procedure RS_Register(RS_window.l, RS_gadget.l, RS_left.b, RS_top.b, RS_right.b, RS_bottom.b)

But my new version is declared:
Procedure RS_Register(RS_window.l, RS_gadget.l, RS_resize_codes$="")

Thus four Boolean parameters have been replaced by one string parameter which could, for example, have a value of "0011".
This change is partly prompted by the need to incorporate an additional code of "2" to enable scaled resizing to be specified.
Note that the procedure permits the "0"s "1"s and "2"s to be replaced by alternative, more memorable, codes.

N. B. Additionally, I have made one non-essential change to the procedure parameters. The four Booleans used to be in the order:
Left, Top, Right, Bottom
But in my version the order is: Left, Right, Top, Bottom.
This new order fits in more logically with my style of writing the program.

The only changes to the two test programs (which don't used the new proportional resizing feature) are:

Test Program 1

Code: Select all

RS_Register(#Window_0,#Button_0,"1010") 
RS_Register(#Window_0,#Button_1,"0110") 
RS_Register(#Window_0,#Button_2,"1001") 
RS_Register(#Window_0,#Button_3,"0101") 
RS_Register(#Window_0,#Listview_0,"1111")
To see a crude example of proportional resizing, simply omit the final string parameter from each of the above 5 statements.

Test Program 2 (WebBrowser)

Code: Select all

RS_Register(0,4,"1110")
RS_Register(0,5,"0110")
RS_Register(0,6,"1110")
RS_Register(0,10,"1111")
My new version of the Resize Gadgets code is:

Code: Select all

; Automatically Resize PureBasic Gadgets
; Author: USCode, modified by AKJ to enable scaled (proportionate) resizing
; February 19, 2006 - Updated for PureBasic 4.0
; April 15, 2004 - Original release
;
; To use:
; - Include this source file
; - Call RS_Register ONCE for EACH Gadget to be resized, specifiying lock types
; - Call RS_Resize in the event loop, specifying Event and EventWindow

; DECLARATIONS

Structure RS_gadget_struct
  Window.l ; Window number
  Gadget.l ; Gadget number
  winw.l ; Original window size
  winh.l
  x.l ; Original gadget position
  y.l
  w.l ; Original gadget size
  h.l
  Lock_left.b ; Resizing codes
  Lock_right.b
  Lock_top.b
  Lock_bottom.b
EndStructure

Global NewList RS_Gadgets.RS_gadget_struct()

; PROCEDURES

Procedure RS_Register(RS_window.l, RS_gadget.l, RS_resize_codes$="") 
; Register gadget to be resized and how to resize
; Parameters:  WindowID (long), GadgetID (long), RS_resize_codes$ (string) for left, right, top, bottom
; (original order was: left, top, right, bottom)
;
; Resize/lock codes (case insensitive) for each of the four sides:
;   Unlocked: "0" or "u" or "f" (free, floating), with size unchanged
;   Locked  : "1" or "l" or "a" (anchored)
;   Scaled  : "2" or "s" or "p" (proportionate) [The default]
; There is a special case:
;   If the left/right (or top/bottom) codes are "ff" (or "00" or "uu") then the
;   gadget's centre is moved proportionally, but the gadget's size is unchanged
; If a gadget is assigned no resize/lock codes, they will default to "ssss"
;
; These combinations resize the gadgets width/height: "aa" "as" "sa" "ss"
; These combinations do not resize the gadget: Any combination including an "f"
; The combinations do not seem to be particularly useful:  "fs" "sf"


RS_resize_codes$=LCase(RS_resize_codes$)
With RS_Gadgets()
  AddElement(RS_Gadgets())
  \Gadget = RS_gadget
  \Window = RS_window
  \winw = WindowWidth(RS_window)
  \winh = WindowHeight(RS_window)
  \x = GadgetX(RS_gadget)
  \y = GadgetY(RS_gadget)
  \w = GadgetWidth(RS_gadget)
  \h = GadgetHeight(RS_gadget)
  ; Convert codes from string to numeric
  \Lock_left  = (FindString("ulsfap012", Mid(RS_resize_codes$,1,1), 1)+2)%3
  \Lock_right = (FindString("ulsfap012", Mid(RS_resize_codes$,2,1), 1)+2)%3
  \Lock_top   = (FindString("ulsfap012", Mid(RS_resize_codes$,3,1), 1)+2)%3
  \Lock_bottom= (FindString("ulsfap012", Mid(RS_resize_codes$,4,1), 1)+2)%3
EndWith
EndProcedure


Procedure RS_Unregister(RS_window.l, RS_gadget.l)
; Contributed by "FloHimself" 
ResetList(RS_Gadgets())
While NextElement(RS_Gadgets())
  If (RS_Gadgets()\Window = RS_window) And (RS_Gadgets()\Gadget = RS_gadget)
    DeleteElement(RS_Gadgets())
  EndIf
Wend
EndProcedure


Procedure RS_Resize(RS_Event.l, RS_window.l)
; Resize all registered gadgets For the resizing window
; Parameters: Event (long), Event Window (long)
Protected RS_gadget.l, RS_x.l, RS_y.l, RS_w.l, RS_h.l
Protected winw, winh ; Original dimensions of window
If RS_Event = #PB_Event_SizeWindow
  ResetList(RS_Gadgets())
  While NextElement(RS_Gadgets())
    If RS_Gadgets()\Window = RS_window
      winw = WindowWidth(RS_window) ; Current dimensions of window
      winh = WindowHeight(RS_window)
      With RS_Gadgets()
        RS_gadget = \Gadget
        Select \Lock_Left
        Case 0: RS_w = #PB_Ignore ; Unlocked, free, floating
          Select \Lock_Right
          Case 0: RS_x = ((\x*2+\w)*winw/\winw-\w)/2
          Case 1: RS_x = \x+winw-\winw
          Case 2: RS_x = \x+\w*winw/\winw-\w
          EndSelect
        Case 1: RS_x = #PB_Ignore ; Locked, anchored
          Select \Lock_Right
          Case 0: RS_w = #PB_Ignore
          Case 1: RS_w = \w+winw-\winw
          Case 2: RS_w = \w*(winw-\x)/(\winw-\x)
          EndSelect
        Case 2: ; Scaled, proportionate
          Select \Lock_Right
          Case 0: RS_w = #PB_Ignore
                  RS_x = \x*winw/\w
          Case 1: RS_w = \w+(winw-\winw)*\w/(\w+\x)
                  RS_x = \x+winw-\winw+\w-RS_w
          Case 2: RS_w = \w*winw/\winw
                  RS_x = \x*winw/\winw
          EndSelect
        EndSelect ; \Lock_Left
        ;
        Select \Lock_Top
        Case 0: RS_h = #PB_Ignore ; Free
          Select \Lock_Bottom
          Case 0: RS_y = ((\y*2+\h)*winh/\winh-\h)/2
          Case 1: RS_y = \y+winh-\winh
          Case 2: RS_y = \y+\h*winh/\winh-\h
          EndSelect
        Case 1: RS_y = #PB_Ignore ; Anchored
          Select \Lock_Bottom
          Case 0: RS_h = #PB_Ignore
          Case 1: RS_h = \h+winh-\winh
          Case 2: RS_h = \h*(winh-\y)/(\winh-\y)
          EndSelect
        Case 2: ; Scaled
          Select \Lock_Bottom
          Case 0: RS_h = #PB_Ignore
                  RS_y = \y*winh/\h
          Case 1: RS_h = \h+(winh-\winh)*\h/(\h+\y)
                  RS_y = \y+winh-\winh+\h-RS_h     
          Case 2: RS_h = \h*winh/\winh
                  RS_y = \y*winh/\winh
          EndSelect
        EndSelect ; \Lock_Top
      EndWith ; RS_Gadgets()
      ResizeGadget(RS_gadget, RS_x, RS_y, RS_w, RS_h)
    EndIf ; Window
  Wend ; NextElement()
EndIf ; RS_Event
EndProcedure
Anthony Jordan
User avatar
einander
Enthusiast
Enthusiast
Posts: 744
Joined: Thu Jun 26, 2003 2:09 am
Location: Spain (Galicia)

Post by einander »

@USCode
Thanks for your code!

I'm using it (PB4) with this CallBack to avoid flicker when resizing
Adapted from codes by Roger Beausoleil and Codemonger

Code: Select all

    Procedure NoFlick(hWnd, Msg, wParam, lParam)   ; OJO CallBack
        Select Msg
            Case #WM_ENTERSIZEMOVE
                SetWindowLong_(hWnd, -20, GetWindowLong_(hWnd, -20) | #WS_EX_COMPOSITED)
            Case #WM_EXITSIZEMOVE
                SendMessage_(hWnd, #WM_SETREDRAW, 0, 0)
                SetWindowLong_(hWnd, -20, GetWindowLong_(hWnd, -20) & ~#WS_EX_COMPOSITED)
                SendMessage_(hWnd, #WM_SETREDRAW, 1, 0)
        EndSelect
        ProcedureReturn #PB_ProcessPureBasicEvents 
    EndProcedure 
To call it:

Code: Select all

SetWindowCallback(@NoFlick())
before the MainLoop.

Cheers
USCode
Addict
Addict
Posts: 923
Joined: Wed Mar 24, 2004 11:04 pm
Location: Seattle

cross-platform

Post by USCode »

Thanks einander. Yeah, callbacks have been discussed but unfortunately, they're not cross-platform ... Windows only.

But, if you're doing Windows only then that's great!
gnozal
PureBasic Expert
PureBasic Expert
Posts: 4229
Joined: Sat Apr 26, 2003 8:27 am
Location: Strasbourg / France
Contact:

Re: cross-platform

Post by gnozal »

USCode wrote:Thanks einander. Yeah, callbacks have been discussed but unfortunately, they're not cross-platform ... Windows only.
But, if you're doing Windows only then that's great!
Windows XP only I think
For free libraries and tools, visit my web site (also home of jaPBe V3 and PureFORM).
User avatar
Rescator
Addict
Addict
Posts: 1769
Joined: Sat Feb 19, 2005 5:05 pm
Location: Norway

Post by Rescator »

I decided to improve AKJ's modifications by changing from the slightly unusual string parameter,
into a more standard flags based parameter for those that prefer that instead.

This is just a verbatim modification, it compiles ok, even with EnableExplicit,
but I have not done any testing,
so if there are any glearing bugs, shout out.

----- Here we go! ------

The only changes to the two test programs (which don't used the new proportional resizing feature) are:

Test Program 1

Code: Select all

RS_Register(#Window_0,#Button_0,#RS_Left_Lock|#RS_Right_Free|#RS_Top_Lock|#RS_Bottom_Free)
RS_Register(#Window_0,#Button_1,#RS_Left_Free|#RS_Right_Lock|#RS_Top_Lock|#RS_Bottom_Free)
RS_Register(#Window_0,#Button_2,#RS_Left_Lock|#RS_Right_Free|#RS_Top_Free|#RS_Bottom_Lock)
RS_Register(#Window_0,#Button_3,#RS_Left_Free|#RS_Right_Lock|#RS_Top_Free|#RS_Bottom_Lock)
RS_Register(#Window_0,#Listview_0,#RS_Left_Lock|#RS_Right_Lock|#RS_Top_Lock|#RS_Bottom_Lock)
To see a crude example of proportional resizing, simply omit the final parameter from each of the above 5 statements.

Test Program 2 (WebBrowser)

Code: Select all

RS_Register(0,4,#RS_Left_Lock|#RS_Right_Lock|#RS_Top_Lock|#RS_Bottom_Free)
RS_Register(0,5,#RS_Left_Free|#RS_Right_Lock|#RS_Top_Lock|#RS_Bottom_Free)
RS_Register(0,6,#RS_Left_Lock|#RS_Right_Lock|#RS_Top_Lock|#RS_Bottom_Free)
RS_Register(0,10,#RS_Left_Lock|#RS_Right_Lock|#RS_Top_Lock|#RS_Bottom_Lock)

Code: Select all

; Automatically Resize PureBasic Gadgets
; Author: USCode
; Mars 9, 2006 - modified by Rescator, changed string parameter into flags based instead.
; February 27, 2006 - modified by AKJ, scaled (proportionate) resizing
; February 19, 2006 - Updated for PureBasic 4.0
; April 15, 2004 - Original release
;
; To use:
; - Include this source file
; - Call RS_Register ONCE for EACH Gadget to be resized, specifiying lock types
; - Call RS_Resize in the event loop, specifying Event and EventWindow

; DECLARATIONS

Structure RS_gadget_struct
  Window.l ; Window number
  Gadget.l ; Gadget number
  winw.l ; Original window size
  winh.l
  x.l ; Original gadget position
  y.l
  w.l ; Original gadget size
  h.l
  flags.l ;Resize flags
EndStructure

Global NewList RS_Gadgets.RS_gadget_struct()

; Resize/lock flags for each of the four sides:
; #RS_xxxx_Free: free, floating, with size unchanged
; #RS_xxxx_Lock: anchored

; If the left/right (or top/bottom) codes are #RS_xxxx_Free then the
; gadget's centre is moved proportionally, but the gadget's size is unchanged

; Default (if a side flag is not specified) is proportionate resize/scaling for that side.

#RS_Left_Free   = $0001
#RS_Left_Lock   = $0002
#RS_Right_Free  = $0010
#RS_Right_Lock  = $0020
#RS_Top_Free    = $0100
#RS_Top_Lock    = $0200
#RS_Bottom_Free = $1000
#RS_Bottom_Lock = $2000

; PROCEDURES
Procedure RS_Register(RS_window.l, RS_gadget.l, RS_flags.l=0)
; Register gadget to be resized and how to resize
; Parameters:  WindowID (long), GadgetID (long), RS_flags (long).

With RS_Gadgets()
  AddElement(RS_Gadgets())
  \gadget = RS_gadget
  \window = RS_window
  \winw = WindowWidth(RS_window)
  \winh = WindowHeight(RS_window)
  \x = GadgetX(RS_gadget)
  \y = GadgetY(RS_gadget)
  \w = GadgetWidth(RS_gadget)
  \h = GadgetHeight(RS_gadget)
  \flags = RS_flags
EndWith
EndProcedure


Procedure RS_Unregister(RS_window.l, RS_gadget.l)
; Contributed by "FloHimself"
ResetList(RS_Gadgets())
While NextElement(RS_Gadgets())
  If (RS_Gadgets()\Window = RS_window) And (RS_Gadgets()\Gadget = RS_gadget)
    DeleteElement(RS_Gadgets())
  EndIf
Wend
EndProcedure


Procedure RS_Resize(RS_Event.l, RS_window.l)
; Resize all registered gadgets For the resizing window
; Parameters: Event (long), Event Window (long)
Protected RS_gadget.l, RS_x.l, RS_y.l, RS_w.l, RS_h.l
Protected winw, winh ; Original dimensions of window
If RS_Event = #PB_Event_SizeWindow
  ResetList(RS_Gadgets())
  While NextElement(RS_Gadgets())
    If RS_Gadgets()\Window = RS_window
      winw = WindowWidth(RS_window) ; Current dimensions of window
      winh = WindowHeight(RS_window)
      With RS_Gadgets()
        RS_gadget = \Gadget
        If \flags=#RS_Left_Free ; Unlocked, free, floating
         RS_w = #PB_Ignore
         If \flags=#RS_Right_Free
          RS_x = ((\x*2+\w)*winw/\winw-\w)/2
         ElseIf \flags=#RS_Right_Lock
          RS_x = \x+winw-\winw
         Else
          RS_x = \x+\w*winw/\winw-\w
         EndIf
        ElseIf \flags=#RS_Left_Lock ; Locked, anchored
         RS_x = #PB_Ignore
         If \flags=#RS_Right_Free
          RS_w = #PB_Ignore
         ElseIf \flags=#RS_Right_Lock
          RS_w = \w+winw-\winw
         Else
          RS_w = \w*(winw-\x)/(\winw-\x)
         EndIf
        Else ; Scaled, proportionate
         If \flags=#RS_Right_Free
          RS_w = #PB_Ignore
          RS_x = \x*winw/\w
         ElseIf \flags=#RS_Right_Lock
          RS_w = \w+(winw-\winw)*\w/(\w+\x)
          RS_x = \x+winw-\winw+\w-RS_w
         Else
          RS_w = \w*winw/\winw
          RS_x = \x*winw/\winw
         EndIf
        EndIf
        ;
        If \flags=#RS_Top_Free ; Unlocked, free, floating
         RS_h = #PB_Ignore
         If \flags=#RS_Bottom_Free
          RS_y = ((\y*2+\h)*winh/\winh-\h)/2
         ElseIf \flags=#RS_Bottom_Lock
          RS_y = \y+winh-\winh
         Else
          RS_y = \y+\h*winh/\winh-\h
         EndIf
        ElseIf \flags=#RS_Left_Lock ; Locked, anchored
         RS_y = #PB_Ignore
         If \flags=#RS_Bottom_Free
          RS_h = #PB_Ignore
         ElseIf \flags=#RS_Bottom_Lock
          RS_h = \h+winh-\winh
         Else
          RS_h = \h*(winh-\y)/(\winh-\y)
         EndIf
        Else ; Scaled, proportionate
         If \flags=#RS_Bottom_Free
          RS_h = #PB_Ignore
          RS_y = \y*winh/\h
         ElseIf \flags=#RS_Bottom_Lock
          RS_h = \h+(winh-\winh)*\h/(\h+\y)
          RS_y = \y+winh-\winh+\h-RS_h     
         Else
          RS_h = \h*winh/\winh
          RS_y = \y*winh/\winh
         EndIf
        EndIf
      EndWith ; RS_Gadgets()
      ResizeGadget(RS_gadget, RS_x, RS_y, RS_w, RS_h)
    EndIf ; Window
  Wend ; NextElement()
EndIf ; RS_Event
EndProcedure
akj
Enthusiast
Enthusiast
Posts: 668
Joined: Mon Jun 09, 2003 10:08 pm
Location: Nottingham

Post by akj »

Just for the record, I have a later unpublished version of the resizing code that is much more accurate as it takes into account the fact that gadgets rarely touch the extreme edge of the window. Thus there is an unused border just inside the client area of the window.

My new version automatically calculates the widths of these borders and uses them to fine-tune the positions of the resized gadgets. For example, a row of (say 7) equally-spaced buttons will remain perfectly equally-spaced after any amount of resizing. There is also an option to specify whether the borders vary in width [the default] as the window resizes or whether the widths remain static.

The new version also handles any statusbar automatically and uses better formulae for the proportional (scaled) resizing. However it does not fit in with the style adopted by Rescator, which is why I have not posted it here, to avoid confusion.
Anthony Jordan
chen
Enthusiast
Enthusiast
Posts: 338
Joined: Fri Dec 23, 2005 2:20 pm
Location: Quebec, Canada
Contact:

Post by chen »

akj wrote:
The new version also handles any statusbar automatically and uses better formulae for the proportional (scaled) resizing. However it does not fit in with the style adopted by Rescator, which is why I have not posted it here, to avoid confusion
I dont think these kind of usuful posts cause confusion.... we learn from
this knowledge, and the code that is helpful is included as part
of our projects...

Hope you reconsider and post your new code... :wink:
akj
Enthusiast
Enthusiast
Posts: 668
Joined: Mon Jun 09, 2003 10:08 pm
Location: Nottingham

Post by akj »

In accordance with Chen's request, I am now posting my more powerful version of the gadget resizing procedures together with a test routine.

The status bar resizing (righmost field only) has only been tested under Windows Me.

*** Updated ***

Code: Select all

; RS_ResizeGadgets.pbi  AKJ  25-Mar-06
; Automatically Resize PureBasic Gadgets
; Author: USCode, modified by AKJ to enable scaled (proportionate) resizing
; February 19, 2006 - Updated for PureBasic 4.0
; April 15, 2004 - Original release
; http://forums.purebasic.com/english/viewtopic.php?t=10218&postdays=0&postorder=asc&start=0
;
; To use:
;   Include this source file
;   Create windows and gadgets
;   Call RS_Register() ONCE for EACH Gadget to be resized, specifiying resize codes
;   Call RS_Margins() once for each window if margin widths are to be fixed
;     (A margin is the clear space usually present just inside a window's edge)
;   Call RS_Resize() in the event loop wherever #PB_Event_SizeWindow is checked
;   Optionally call RS_Unregister() to remove a gadget from the auto-resizing list
;   Optionally call RS_GetWinSize() to estimate the window size that
;     will result in a specified gadget having a specified target size

;- Declarations

Structure RS_gadget_struct
  Window.l ; Window number
  Gadget.l ; Gadget number
  x.l ; Original gadget position
  y.l
  w.l ; Original gadget size
  h.l
  left.l ; Resizing codes (text characters, converted to numeric)
  right.l
  top.l
  bottom.l
EndStructure
; Special case that defines a window (gadget number <0)
; All window definition elements precede gadget elements
  ; Window.l ; Window number
  ; Gadget.l ; -n if this window has/had n registered gadgets, else #PB_Ignore if 0
  ; x.l ; Flag: #True iff left/right window margins should remain fixed width
  ; y.l ; Flag: #True iff top/bottom window margins should remain fixed width
  ; w.l ; Original window size
  ; h.l
  ; left.l ; Dynamically calculated window margin widths
  ; right.l
  ; top.l
  ; bottom.l

Global NewList RS_Gadgets.RS_gadget_struct()
;}

Procedure RS_Margins(RS_window.l, fixed_lr.l=#True, fixed_tb.l=#True)
; Set whether a window's margins (borders) should remain fixed width 
; By default (this procedure unused), they change proportionally with the window size
; The first parameter identifies the window whose margins are to be configured
; The second parameter specifies whether the left/right margins should be fixed
; The third parameter specifies whether the top/bottom margins should be fixed
; (This procedure is also called internally by other procedures to define a window)
; The margin width values are calculated automatically by RS_Register()
Protected found.l = #False
With RS_Gadgets()
  ; First see if the window is already defined
  ResetList(RS_Gadgets())
  While NextElement(RS_Gadgets())
      If \Window=RS_window And \Gadget<0
        found=#True: Break
      EndIf
  Wend
  If Not found
    ; Define the window, using it's current size
    ResetList(RS_Gadgets())
    AddElement(RS_Gadgets()) ; !!! Bug: current element is set to -1 with InsertElement(RS_Gadgets())
    \Window = RS_window
    \Gadget = #PB_Ignore ; Flag: No gadgets yet registered for this window
    \w = WindowWidth(RS_window) ; Original window size
    \h = WindowHeight(RS_window)
  EndIf
  ; Configure the margins
  If fixed_lr<>#PB_Ignore: \x=fixed_lr: EndIf
  If fixed_tb<>#PB_Ignore: \y=fixed_tb: EndIf
EndWith
EndProcedure

Procedure RS_Register(RS_window.l, RS_gadget.l, RS_resize_codes$="") 
; Register gadget to be resized and how to resize
; Parameters:  WindowID (long), GadgetID (long), RS_resize_codes$ (string) for left, right, top, bottom
; (original order was: left, top, right, bottom)
;
; Resize/lock codes (case insensitive) for each of the four sides:
;   Unlocked: "0" or "u" or "f" (free, floating), with gadget size unchanged
;   Locked  : "1" or "l" or "a" (anchored)
;   Scaled  : "2" or "s" or "p" (proportionate) [The default]
; There is a special case:
;   If the left/right (or top/bottom) codes are "ff" (or "00" or "uu") then the
;   gadget's centre is moved proportionally, but the gadget's size is unchanged
; If a gadget is assigned no resize/lock codes, they will default to "ssss"
;
; These combinations resize the gadgets width/height: "aa" "as" "sa" "ss"
; These combinations do not resize the gadget: Any combination including an "f"
; These combinations do not seem to be particularly useful:  "fs" "sf"

Protected index.l ; Used in calculating margin sizes
Protected marl.l, marr.l, mart.l, marb.l ; Margin widths
RS_resize_codes$=LCase(RS_resize_codes$)
With RS_Gadgets()
  ; First ensure an element for the window exists in the linked list
  RS_Margins(RS_window, #PB_Ignore, #PB_Ignore)
  index = ListIndex(RS_Gadgets()) ; Remember the window element's position
  ; Create an element for the gadget at the end of the linked list
  LastElement(RS_Gadgets())
  AddElement(RS_Gadgets())
  \Window = RS_window
  \Gadget = RS_gadget
  \x = GadgetX(RS_gadget)
  \y = GadgetY(RS_gadget)
  \w = GadgetWidth(RS_gadget)
  \h = GadgetHeight(RS_gadget)
  ; Convert codes from string to numeric
  \left  = (FindString("ulsfap012", Mid(RS_resize_codes$,1,1), 1)+2)%3
  \right = (FindString("ulsfap012", Mid(RS_resize_codes$,2,1), 1)+2)%3
  \top   = (FindString("ulsfap012", Mid(RS_resize_codes$,3,1), 1)+2)%3
  \bottom= (FindString("ulsfap012", Mid(RS_resize_codes$,4,1), 1)+2)%3
  ; Calculate relative margin widths based on the current gadget
  marl=\x: marr=-\x-\w
  mart=\y: marb=-\y-\h
  ; Calculate actual margin widths based on all gadgets found so far for the window
  SelectElement(RS_Gadgets(), index) ; Revisit the window definition
  marr+\w: marb+\h ; Add the window sizes
  If marl<0: marl=0: EndIf ; Sanity tests
  If marr<0: marr=0: EndIf
  If mart<0: mart=0: EndIf
  If marb<0: marb=0: EndIf
  If \Gadget=#PB_Ignore ; If this is the first gadget for the window
    \Gadget=-1
    \left=marl: \right=marr: \top=mart: \bottom=marb
  Else ; Remember any margin narrower than so far found
    \Gadget-1
    If \left>marl: \left=marl: EndIf
    If \right>marr: \right=marr: EndIf
    If \top>mart: \top=mart: EndIf
    If \bottom>marb: \bottom=marb: EndIf
  EndIf
EndWith
EndProcedure

Procedure RS_Unregister(RS_window.l, RS_gadget.l)
; Contributed by "FloHimself"
; Unregistering a gadget is equivalent to giving it resizing codes of "afaf"
Protected found=#False
If RS_gadget>=0 ; Not allowed to delete elements that define windows
  ResetList(RS_Gadgets())
  With RS_Gadgets()
    While NextElement(RS_Gadgets())
        If \Window=RS_window And \Gadget=RS_gadget
          DeleteElement(RS_Gadgets())
          found=#True: Break
        EndIf
    Wend
    If found
      ; Update count in window definition element
      RS_Margins(RS_window, #PB_Ignore, #PB_Ignore) ; Find the window element
      \Gadget+1 ; E.g. -4 becomes -3
      If \Gadget<-9999 Or \Gadget>=0: \Gadget=#PB_Ignore: EndIf
    EndIf ; found
  EndWith
EndIf
EndProcedure

Procedure RS_Resize(RS_window.l, RS_gadget.l=#PB_Ignore, *RS_Width.l=0, *RS_Height.l=0)
; Resize all registered gadgets (and any statusbar) for the resizing window RS_window
; This should normally be called from the event loop whenever #PB_Event_SizeWindow occurs
;
; Typically, only argument 1 is defined, with the other three arguments unused.
; If the second argument is a gadget number, the gadgets are not resized,
;   instead the new width and height for that gadget are returned in arguments 3 and 4
;   based upon window dimensions given on entry also in arguments 3 and 4
; This feature is used by RS_GetWinSize()
;
Protected RS_x.l, RS_y.l, RS_w.l, RS_h.l ; Original gadget size
Protected oldw.l, oldh.l ; Original window size
Protected winw.l, winh.l ; Current window size
Protected oldl.l, oldr.l, oldt.l, oldb.l ; Window's original margin widths
Protected marl.l, marr.l, mart.l, marb.l ; Window's new margin sizes
Protected x,y ; Relative to left/top margins
Protected sbh, cn$, parts, part ; Status bar handle, classname, parts, part#
; Get the window's current or target size
If RS_gadget=#PB_Ignore
  winw = WindowWidth(RS_window): winh = WindowHeight(RS_window)
Else
  winw = PeekL(*RS_Width): winh = PeekL(*RS_Height)
EndIf
With RS_Gadgets()
  ; Find the linked list element defining the window
  RS_Margins(RS_window, #PB_Ignore, #PB_Ignore)
  ; Retrieve the window's original size
  oldw=\w: oldh=\h
  ; Retrieve the old margin sizes and calculate the new sizes
  ; N.B. Do not precalculate 'winw/oldw' as this causes a loss of accuracy
  oldl=\left:  marl=oldl: If \x=0: marl*winw/oldw: EndIf
  oldr=\right: marr=oldr: If \x=0: marr*winw/oldw: EndIf
  oldt=\top:   mart=oldt: If \y=0: mart*winh/oldh: EndIf
  oldb=\bottom:marb=oldb: If \y=0: marb*winh/oldh: EndIf
  ; Calculate the old and new window sizes INSIDE the margins
  oldw-oldl-oldr: winw-marl-marr
  oldh-oldt-oldb: winh-mart-marb

  ; Resize the gadgets
  While NextElement(RS_Gadgets()) ; Gadget elements always follow window elements
    If \Window = RS_window
      x=\x-oldl ; x is now relative to the original left margin
      Select \left
      Case 0: RS_w = #PB_Ignore ; Unlocked, free, floating
        Select \right
        Case 0: RS_x = ((x*2+\w)*winw/oldw-\w)/2
        Case 1: RS_x = x+winw-oldw
        Case 2: RS_x = (x+\w)*winw/oldw-\w
        EndSelect
      Case 1: RS_x = x ; Locked, anchored
        Select \right
        Case 0: RS_w = #PB_Ignore
        Case 1: RS_w = \w+winw-oldw
        Case 2: RS_w = (\w+x)*winw/oldw-x
        EndSelect
      Case 2: RS_x = x*winw/oldw ; Scaled, proportionate
        Select \right
        Case 0: RS_w = #PB_Ignore
        Case 1: RS_w = \w+x-RS_x+winw-oldw
        Case 2: RS_w = \w*winw/oldw
        EndSelect
      EndSelect ; \left
      ;
      y=\y-oldt ; y is now relative to the original top margin
      Select \top
      Case 0: RS_h = #PB_Ignore ; Free
        Select \bottom
        Case 0: RS_y = ((y*2+\h)*winh/oldh-\h)/2
        Case 1: RS_y = y+winh-oldh
        Case 2: RS_y = (y+\h)*winh/oldh-\h
        EndSelect
      Case 1: RS_y = y ; Anchored
        Select \bottom
        Case 0: RS_h = #PB_Ignore
        Case 1: RS_h = \h+winh-oldh
        Case 2: RS_h = (\h+y)*winh/oldh-y
        EndSelect
      Case 2: RS_y = y*winh/oldh ; Scaled
        Select \bottom
        Case 0: RS_h = #PB_Ignore
        Case 1: RS_h = \h+y-RS_y+winh-oldh
        Case 2: RS_h = \h*winh/oldh
        EndSelect
      EndSelect ; \top
      If RS_gadget=#PB_Ignore ; If resizing
        ResizeGadget(\Gadget, RS_x+marl, RS_y+mart, RS_w, RS_h)
      ElseIf RS_gadget=\Gadget ; If gadget size is wanted
        PokeL(*RS_Width, RS_w): PokeL(*RS_Height, RS_h) ; Return the result
        ProcedureReturn
      EndIf
    EndIf ; Window
  Wend ; NextElement()
EndWith ; RS_Gadgets()

; Resize the last part (only) of any statusbar
sbh=GetWindow_(WindowID(RS_window), #GW_CHILD)
Repeat
  cn$=Space(20) : GetClassName_(sbh,cn$,20)
  If cn$="msctls_statusbar32": Break: EndIf
  sbh=GetWindow_(sbh, #GW_HWNDNEXT)
Until sbh=0
If sbh ; If a status bar
  parts=SendMessage_(sbh, #SB_GETPARTS, 0, 0) ; Parts in statusbar
  If parts
    Protected Dim rightedge(parts-1)
    SendMessage_(sbh, #SB_GETPARTS, parts, @rightedge())
    rightedge(parts-1)=-1 ; Resize the last part to reach the window edge
    SendMessage_(sbh, #SB_SETPARTS, parts, @rightedge()) ; Redraw statusbar
  EndIf ; parts
EndIf ; sbh
EndProcedure

Procedure RS_GetWinSize(RS_window.l, RS_gadget.l, *RS_width, *RS_height)
; Calculate the window size that will result in a gadget having a given target size
; On entry, arguments 3 and 4 contain the gadget size, on return they hold the window size
; If the gadget cannot be resized (an error), return the original window size
Protected targetw, targeth, oldw1, oldh1, oldw, oldh, gadw1, gadh1, gadw, gadh
; Get the target gadget size
targetw = PeekL(*RS_width): targeth = PeekL(*RS_height)
; Find the linked list element defining the window
RS_Margins(RS_window, #PB_Ignore, #PB_Ignore)
; Get the window's original width and height
oldw=RS_Gadgets()\w: oldh=RS_Gadgets()\h
oldw1=oldw: oldh1=oldh
gadw1=oldw: gadh1=oldh ; First start point for iteration
gadw=oldw*2: gadh=oldh*2 ; Second start point
; Get the gadget size for the original window size
RS_Resize(RS_window, RS_gadget, @gadw1, @gadh1)
With RS_Gadgets()
If \left*\right*\top*\bottom ; If the gadget can be resized
  EndWith
  ; Get the gadget size for double that window size
  RS_Resize(RS_window, RS_Gadget, @gadw, @gadh) 
  ; Use 'Regula Falsi' method to iterate the window size for the target gadget size
  ; x3 = x1 - (x2-x1) * f(x1) / (f(x2)-f(x1))   where f() = gadgetsize - targetsize
  ; First iteration (result may differ from target by a few pixels)
  oldw = oldw1-oldw*(gadw1-targetw)/(gadw-gadw1)
  oldh = oldh1-oldh*(gadh1-targeth)/(gadh-gadh1)
  ; See what the gadget sizes are now
  gadw=oldw: gadh=oldh
  RS_Resize(RS_window, RS_gadget, @gadw, @gadh)
  ; Second iteration (result will probably be exactly equal to target)
  If gadw<>gadw1: oldw = oldw1-(oldw-oldw1)*(gadw1-targetw)/(gadw-gadw1): EndIf
  If gadh<>gadh1: oldh = oldh1-(oldh-oldh1)*(gadh1-targeth)/(gadh-gadh1): EndIf
EndIf
PokeL(*RS_width, oldw): PokeL(*RS_height, oldh) ; Return the desired window size
EndProcedure

;- Scaling logic
; Scaling logic in going from old window size to new window size:
; If either code is 0 (free), the gadget size remains unchanged

; 0,0 Free, Free (special case)
;     Distance between the gadget centre and window centre is scaled
; 0,1 Free, Anchored
; 0,2 Free, Scaled
;     The distance to the right/bottom of the gadget is scaled inside window margins
; 1,0 Anchored, Free
; 1,1 Anchored, Anchored
; 1,2 Anchored, Scaled
;     The distance to the right/bottom of the gadget is scaled inside window margins
; 2,0 Scaled, Free
;     The distance to the left/top of the gadget is scaled inside window margins
; 2,1 Scaled, Anchored
;     The distance to the left/top of the gadget is scaled inside window margins
; 2,2 Scaled, Scaled [Default]
;     All distances (left/top, gadget size, right/bottom) are scaled inside window margins
;     With variable margins, this is simply a magnification/reduction of the entire window image
;}

Code: Select all

; RS_ResizeGadgets Test 3   AKJ  25-Mar-06
; PureBasic 4 Beta 7
; Experiment: Drag an edge or corner of the window to resize it
; Experiment: Clicking button 9 will reduce it to a square shape

; N.B. I have declared ;- as a Folding Start Keyword in File -> Preferences -> Folding

;- Declarations
EnableExplicit
IncludePath #PB_Compiler_Home+"AKJ Procedures\"
XIncludeFile "FN RESIZE GADGETS.pbi"
;}

;- GUI constants
Enumeration
  #winMain
  #staBar ; Status bar
  #but0 ; Other button IDs follow this one
EndEnumeration
;}

;- GUI metrics
Define gap, stah, butw, buth, winw, winh
gap=30 ; Standard unit size of gap between gadgets
stah=24 ; Status bar height
butw=70: buth=40 ; Buttons
winw=butw*6+gap*9: winh=buth*3+gap*6+stah ; Window with 6 buttons across and 3 down
;}

;- GUI creation
Define flags, x, y, butx, buty, butnum
flags=#PB_Window_SizeGadget | #PB_Window_SystemMenu | #PB_Window_TitleBar | #PB_Window_ScreenCentered
If OpenWindow(#winMain, 0,0, winw,winh, "Resize Test", flags)
  CreateStatusBar(#staBar, WindowID(#winMain))
  AddStatusBarField(100): StatusBarText(#staBar, 0, "Part 0")
  AddStatusBarField(100): StatusBarText(#staBar, 1, "Part 1")
  AddStatusBarField(winw-200)
  CreateGadgetList(WindowID(#winMain))
  ; Create 18 buttons
  y=gap*2
  For buty=0 To 2
    x=gap*2
    For butx=0 To 5
      butnum=buty*6+butx
      ButtonGadget(#but0+butnum, x, y, butw, buth, "Button "+Str(butnum)) 
      x+butw+gap
    Next butx
    y+buth+gap
  Next buty
  SetGadgetText(#but0+9, "CLICK ME")
Else
  MessageRequester("Error", "Failed to create main window"): End
EndIf
;}

;- Register gadgets for resizing
; Resize/lock codes (case insensitive) for each of the four sides l, r, t, b:
;   Unlocked: "0" or "u" or "f" (free, floating), with gadget size unchanged
;   Locked  : "1" or "l" or "a" (anchored)
;   Scaled  : "2" or "s" or "p" (proportionate) [The default]
;   Special case: "ff" moves a gadget moved proportionally, but with size unchanged
Define button
For button=#but0+0 To #but0+17
  Select button
  Case #but0+0 To #but0+5
    RS_Register(#winMain, button, "afpf") ; Left anchored
  Case #but0+6 To #but0+8
    RS_Register(#winMain, button, "ffff") ; Move 
  Case #but0+9 To #but0+13
    RS_Register(#winMain, button, "pppp") ; Proportionate [the default]
  Case #but0+14
    RS_Register(#winMain, button, "ffff") ; Move   
  Case #but0+15 To #but0+17
    RS_Register(#winMain, button, "fafp") ; Right anchored
  EndSelect
Next button
RS_Margins(#winMain) ; Omit this line and notice the top & left margins !!!
;}

;- Event loop that detects window resizing (and bug report)
Define event, but9w, but9h
; SmartWindowRefresh(#winMain, #True) ; Try un-commenting this line !!!
Repeat
  event = WaitWindowEvent()
  Select event
  Case #PB_Event_Gadget
    If EventGadget()=#but0+9 ; If button 9
      ; Resize the entire window so that button 9 becomes square
      but9w=GadgetWidth(EventGadget()): but9h=GadgetHeight(EventGadget())
      If but9w>but9h: but9w=but9h: Else: but9h=but9w: EndIf ; Gadget will get smaller
      RS_GetWinSize(EventWindow(), EventGadget(), @but9w, @but9h)
      ResizeWindow(EventWindow(), #PB_Ignore, #PB_Ignore, but9w, but9h)
    EndIf
  Case #PB_Event_SizeWindow
    RS_Resize(#winMain)
    Debug EventWindow() ; Bug: This gives -1 the first time (if no status bar is present) and #winMain thereafter
  EndSelect
Until Event=#PB_Event_CloseWindow
;}

End
Last edited by akj on Sat Mar 25, 2006 6:59 pm, edited 2 times in total.
Anthony Jordan
chen
Enthusiast
Enthusiast
Posts: 338
Joined: Fri Dec 23, 2005 2:20 pm
Location: Quebec, Canada
Contact:

Post by chen »

Code: Select all

akj wrote
In accordance with Chen's request, I am now posting my more powerful version of the gadget resizing procedures together with a test routine.
Thanks a lot..... Im testing it.....:wink:
rsts
Addict
Addict
Posts: 2736
Joined: Wed Aug 24, 2005 8:39 am
Location: Southwest OH - USA

Post by rsts »

akj wrote:In accordance with Chen's request, I am now posting my more powerful version of the gadget resizing procedures together with a test routine.

The status bar resizing (righmost field only) has only been tested under Windows Me.
Thanks for sharing.

The resizing looks a little weird on my winxp installation - not too proportional, but rather varied or "jumbled", but I'll have to check more.

Thanks again.

cheers
chen
Enthusiast
Enthusiast
Posts: 338
Joined: Fri Dec 23, 2005 2:20 pm
Location: Quebec, Canada
Contact:

Post by chen »

Is there a way to put a minimum size.... with no flickering...?

Cause in the cross platform implementations when you fix a minimum
size and you try to resize below these limits the window and gadgets
start flickering....


Maybe you that are sharing your code know how to solve this problem....

I know that using API there is no problem... but it will nice a
cross platform solution.

:?:
akj
Enthusiast
Enthusiast
Posts: 668
Joined: Mon Jun 09, 2003 10:08 pm
Location: Nottingham

Post by akj »

rsts:
When you said "The resizing looks wierd" were you referring to the output of my test program?
If you were, please be aware the test program was only intended to show some of the available gadget resizing possibilities, and it was not meant to be a cosmetic display.
On the other hand, if it was a program you wrote yourself that was giving the wierd resizing, please post a copy of the program and if possible a screen shot (but I do not know how one does this in a forum) and I will investigate.

chen:
I do not know of a cross-platform solution.
In Windows, one way to implement a window size limitation, but avoiding flicker is to invoke a callback function just before the event loop with a statement like this:

Code: Select all

SetWindowCallback(@MinSize())
The callback routine itself could be:

Code: Select all

Procedure MinSize(hWnd, Msg, wParam, lParam)
Define *r.rect ; Will map to lParam
Select Msg
Case #WM_SIZING
  *r=lParam
  With *r
    If \right-\left<=200: \right=\left+200: EndIf
    If \bottom-\top<=200: \bottom=\top+200: EndIf
  EndWith
  ProcedureReturn 0
EndSelect 
ProcedureReturn #PB_ProcessPureBasicEvents 
EndProcedure
Of course, this callback routine could be merged with the NoFlick() routine posted by einander earlier in this topic.

P.S. I have just noticed that in the above code I have written "Define *r.rect" whereas I meant to write "Protected *r.rect". Could someone please explain to me the difference between Define and Protected when they occur in a procedure? I do not really understand the scope of a variable declared with Define.
Last edited by akj on Sun Mar 26, 2006 12:13 pm, edited 1 time in total.
Anthony Jordan
rsts
Addict
Addict
Posts: 2736
Joined: Wed Aug 24, 2005 8:39 am
Location: Southwest OH - USA

Post by rsts »

akj wrote:rsts:
When you said "The resizing looks wierd" were you referring to the output of my test program?
If you were, please be aware the test program was only intended to show some of the available gadget resizing possibilities, and it was not meant to be a cosmetic display.
On the other hand, if it was a program you wrote yourself that was giving the wierd resizing, please post a copy of the program and if possible a screen shot (but I do not know how one does this in a forum) and I will investigate.
It was with the example provided. Resized it leaves me with somewhat unpredictable results - but if that's what is expected, I'm ok with it.

cheers,
Post Reply