Monday, August 11, 2014

Proportional scaling of controls


With the anchor points of controls, there’s already a lot of possibilities to layout the user interface. The set of lock properties (LockTop, LockLeft, etc) of a RectControl give control over the scaling behavior of control elements when a Window changes size. In nearly all cases this is enough, but sometimes a proportional scaling of elements is best as the Window or other container control changes size.


Proportional scaling can always be done manually in the Resize events of the Window for every RectControl. To make this a bit easier to maintain, two extra methods and a property can be added to a Window or a Panel to do proportional scaling. A method to record all design time controls locations is called from the Open event of the Window or Panel. Then the method to play back the relative locations is called from the resizing events.


The RecordAllpagepanelControls method iterates through all RectControls on the Window and stores the relative location in a String.

  Dim i As Integer
  Dim ctrl As RectControl
  Dim l,t,w,h As Double
 
  Redim ControlsLocations(-1) //should be empty, in case it wasn't.

  For i = 0 To Self.ControlCount-1
   
    If Self.Control(i) IsA RectControl Then
      ctrl = RectControl( Self.Control(i) )
      l=ctrl.Left   / Self.Width
      t=ctrl.Top    / Self.Height
      w=ctrl.Width  / Self.Width
      h=ctrl.Height / Self.Height
     
      ControlsLocations.Append( Str(l) + ";" +Str(t) + ";" +Str(w) + ";" +Str(h) +";" + ctrl.Name)
    End if
   
  Next

The PlaybackPagepanelControls method reads the locations from the String and updates the positions of all stored controls to the new position relative to the current size of the Window.

  Dim i As Integer
  Dim ii As Integer
  Dim s As String
  Dim ctrl As RectControl
  Dim l,t,w,h As Double
 
  ii = 0
 
  For i = 0 To Self.ControlCount-1
   
    If Self.Control(i) IsA RectControl Then
     
      ctrl = RectControl( Self.Control(i) )
     
      s = ControlsLocations(ii)
     
      l=Val(NthField(s, ";", 1))
      t=Val(NthField(s, ";", 2))
      w=Val(NthField(s, ";", 3))
      h=Val(NthField(s, ";", 4))
     
      ctrl.Left = Round(Self.Width * l)
      ctrl.Top = Round(Self.Height * t)
      ctrl.Width = Round(Self.Width * w)
      ctrl.Height = Round(Self.Height * h)
     
      ii = ii+1 //next in ControlsLocations array
    End if
   
  Next

It would probably be even easier to create a component that performs this scaling or a component that adds this scaling to the container control it’s added to. For more detailed behavior, extra tests on the type of control can be added in the play back function of course.

Adding the methods to a simple example Window with a couple of shapes on it, these now scale proportionally.