' Helper routines for resizing and moving / stretching controls
' in a window and setting the minimum size of a window
'factors for placement, used as string:
' "TL" or "0.0, 0.0" = Top left
' "TM" or "0.5, 0.0" = Top middle
' "TR" or "1.0, 0.0" = Top right
' "ML" or "0.0, 0.5" = Middle left
' "MM" or "0.5, 0.5" = Middle middle (Centre)
' "MR" or "1.0, 0.5" = Middle right
' "BL" or "0.0, 1.0" = Bottom left
' "BM" or "0.5, 1.0" = Bottom middle
' "BR" or "1.0, 1.0" = Bottom right
'
'Examples:
'
'Pin control on the bottom-right-hand side of the window
'pinCtl(hCtl, hWin, "BR")
'pinCtl(hCtl, hWin, "1.0, 1.0")
'Move / Stretch control if window is resized, from offset 1 to offset 2
'pinCtl(hCtl, hWin, "TL", "BR" )
'pinCtl(hCtl, hWin, "0.0, 0.0", "1.0, 1.0")
'Stop resizing and moving control if the window falls below a certain size (pixels)
'unpinCtl(hCtl, hWin, 450, 350)
'Move / Resize the controls when WM_SIZE message of parent window is handled:
'resizeControls(hWin)
'Limit the minimum permitted size of a window to width and height (pixels),
'can be used with the WM_GETMINMAXINFO message:
'setMinSize(450, 350)
===================================================================================
uses corewin
% HWND_DESKTOP=0
% WM_SIZING=532
% WM_GETMINMAXINFO=36
% SWP_NOZORDER=4
% SWP_DEFERERASE=0x2000
type Sizel
int cx 'width
int cy 'height
end type
type PFactor
double fx
double fy
end type
type sizing_data
int index
sys hParent
sys hCtl
PFactor pf1 'placement factors
PFactor pf2 'placement factors
RECT ofs 'offset Left, Top, Right, Bottom
int unpinned '0=pinned, 1=unpinned
int w, h 'width and height of parent
end type
'bounds for record data
type MaxPinnedCtls
int count
end type
MaxPinnedCtls MaxPinned = {10}
redim sizing_data PinCtl_Rec[MaxPinned.count]
'Attach position of the Control relative to the Parent window
sub pinCtl(sys hCtl, sys hParent, string placement1, optional string placement2="NONE_")
PFactor pf1, pf2
string place1=lcase(ltrim rtrim(placement1))
string place2=lcase(ltrim rtrim(placement2))
'Method 1: Static attachment
while 1
if place1="tl" then pf1.fx=0.0 : pf1.fy=0.0 : exit while
if place1="tm" then pf1.fx=0.5 : pf1.fy=0.0 : exit while
if place1="tr" then pf1.fx=1.0 : pf1.fy=0.0 : exit while
if place1="ml" then pf1.fx=0.0 : pf1.fy=0.5 : exit while
if place1="mm" then pf1.fx=0.5 : pf1.fy=0.5 : exit while
if place1="mr" then pf1.fx=1.0 : pf1.fy=0.5 : exit while
if place1="bl" then pf1.fx=0.0 : pf1.fy=1.0 : exit while
if place1="bm" then pf1.fx=0.5 : pf1.fy=1.0 : exit while
if place1="br" then pf1.fx=1.0 : pf1.fy=1.0 : exit while
'factors as values?
int pos=instr(place1,",")
if pos then pf1.fx=val(left(place1,pos-1)) : pf1.fy=val(mid(place1,pos+1)) : exit while
mbox "Error: wrong placement 1 in pinCtl function" : exit while
wend
if place2="none_" then pf2.fx=pf1.fx : pf2.fy=pf1.fy
'Method 2: Stretchy attachment?
while 1
if place2="none_" then exit while
if place2="tl" then pf2.fx=0.0 : pf2.fy=0.0 : exit while
if place2="tm" then pf2.fx=0.5 : pf2.fy=0.0 : exit while
if place2="tr" then pf2.fx=1.0 : pf2.fy=0.0 : exit while
if place2="ml" then pf2.fx=0.0 : pf2.fy=0.5 : exit while
if place2="mm" then pf2.fx=0.5 : pf2.fy=0.5 : exit while
if place2="mr" then pf2.fx=1.0 : pf2.fy=0.5 : exit while
if place2="bl" then pf2.fx=0.0 : pf2.fy=1.0 : exit while
if place2="bm" then pf2.fx=0.5 : pf2.fy=1.0 : exit while
if place2="br" then pf2.fx=1.0 : pf2.fy=1.0 : exit while
'factors as values?
pos=instr(place2,",")
if pos then pf2.fx=val(left(place2,pos-1)) : pf2.fy=val(mid(place2,pos+1)) : exit while
mbox "Error: wrong placement 2 in pinCtl function" : exit while
wend
Sizel ctlSize
RECT pRect, cRect
RECT ofs
'Get the size of the hParent window to be able to calculate offsets
GetClientRect(hParent, &pRect)
ctlSize.cx = pRect.right : ctlSize.cy = pRect.bottom
GetWindowRect(hCtl, &cRect)
'Calculate the offsets of the left, top, bottom, and right of the control.
MapWindowPoints(HWND_DESKTOP, GetParent(hCtl), &cRect, 2)
ofs.left= cRect.left - ctlSize.cx*pf1.fx
ofs.top= cRect.top - ctlSize.cy*pf1.fy
ofs.right= cRect.right - ctlSize.cx*pf2.fx
ofs.bottom=cRect.bottom - ctlSize.cy*pf2.fy
'Add entry to the data records
static int idx
'does hCtl already exist?
int i
for i=1 to idx
if PinCtl_Rec[i].hCtl=hCtl then
idx=i-1
exit for
end if
next i
idx+=1
if idx>MaxPinned.count then
MaxPinned.count+=10
redim sizing_data PinCtl_Rec[MaxPinned.count]
end if
PinCtl_Rec[idx].index=idx
PinCtl_Rec[idx].hParent=hParent
PinCtl_Rec[idx].hCtl=hCtl
PinCtl_Rec[idx].pf1.fx=pf1.fx
PinCtl_Rec[idx].pf1.fy=pf1.fy
PinCtl_Rec[idx].pf2.fx=pf2.fx
PinCtl_Rec[idx].pf2.fy=pf2.fy
PinCtl_Rec[idx].ofs.left=ofs.left
PinCtl_Rec[idx].ofs.top=ofs.top
PinCtl_Rec[idx].ofs.right=ofs.right
PinCtl_Rec[idx].ofs.bottom=ofs.bottom
end sub
'Mark control to stop resizing / moving at certain size of window (pixels)
sub unpinCtl(sys hCtl, sys hParent, int width, height)
int ix
bool found=false
for ix=1 to MaxPinned.count
if PinCtl_Rec[ix].hCtl=hCtl then
PinCtl_Rec[ix].unpinned=1
PinCtl_Rec[ix].w=width
PinCtl_Rec[ix].h=height
found=true : exit for
end if
next ix
if found=false then mbox "Error: Cannot find hCtl: " hCtl "in PinCtl_Rec"
end sub
'Procedure for resizing attached controls when WM_SIZE message is handled
sub resizeControls(sys hWin)
PFactor pf1, pf2
RECT ofs
Sizel ctlSize
RECT pRect, cRect 'parent, control
'Get the new size of the window
GetClientRect(hWin, &pRect)
ctlSize.cx = pRect.right : ctlSize.cy = pRect.bottom
int ix
'Go through each element in the data entries to see if it needs to be moved.
for ix = 1 to MaxPinned.count
if PinCtl_Rec[ix].index=0 then exit for
'If the element was inside the window that was resized, it needs to move.
if hWin = PinCtl_Rec[ix].hParent then
'Get the data out of the data entries for that record
pf1.fx=PinCtl_Rec[ix].pf1.fx : pf1.fy=PinCtl_Rec[ix].pf1.fy : pf2.fx=PinCtl_Rec[ix].pf2.fx : pf2.fy=PinCtl_Rec[ix].pf2.fy
ofs.left=PinCtl_Rec[ix].ofs.left : ofs.top=PinCtl_Rec[ix].ofs.top : ofs.right=PinCtl_Rec[ix].ofs.right : ofs.bottom=PinCtl_Rec[ix].ofs.bottom
'Stop resizing / moving if hParent falls below a certain size (pixels)?
if PinCtl_Rec[ix].unpinned=1 then
if ctlSize.cx < PinCtl_Rec[ix].w then ctlSize.cx=PinCtl_Rec[ix].w
if ctlSize.cy < PinCtl_Rec[ix].h then ctlSize.cy=PinCtl_Rec[ix].h
end if
'Calculate the new position and size of the control
ofs.left+=ctlSize.cx*pf1.fx : ofs.top+=ctlSize.cy*pf1.fy : ofs.right+=ctlSize.cx*pf2.fx : ofs.bottom+=ctlSize.cy*pf2.fy
SetWindowPos(PinCtl_Rec[ix].hCtl, 0, ofs.left, ofs.top, (ofs.right-ofs.left), (ofs.bottom-ofs.top), SWP_NOZORDER|SWP_DEFERERASE)
end if
next ix
end sub
'Can be combined with WM_GETMINMAXINFO message
macro setMinSize(xMin, yMin)
MINMAXINFO *mm
@mm = lParam
mm.ptMinTrackSize.x = xMin
mm.ptMinTrackSize.y = yMin
end macro
=============================================================================
'Adapt offsets of an existing control, using the given factors
'Optional add delta to position
sub modpinCtl(sys hCtl, optional int dx=0,dy=0,dcx=0,dcy=0)
Sizel ctlSize
RECT pRect, cRect 'parent, control
RECT ofs
int i
for i=1 to MaxPinned.count
if PinCtl_Rec[i].hCtl=hCtl then
exit for
end if
next i
if PinCtl_Rec[i].hCtl != hCtl then exit sub
'Get the size of the hParent window to be able to calculate offsets
GetClientRect(PinCtl_Rec[i].hParent, &pRect)
ctlSize.cx = pRect.right : ctlSize.cy = pRect.bottom
GetWindowRect(hCtl, &cRect)
'Calculate the offsets of the left, top, bottom, and right of the control.
MapWindowPoints(HWND_DESKTOP, GetParent(hCtl), &cRect, 2)
ofs.left= cRect.left + dx - ctlSize.cx*PinCtl_Rec[i].pf1.fx
ofs.top= cRect.top + dy - ctlSize.cy*PinCtl_Rec[i].pf1.fy
ofs.right= cRect.right + dcx - ctlSize.cx*PinCtl_Rec[i].pf2.fx
ofs.bottom=cRect.bottom + dcy - ctlSize.cy*PinCtl_Rec[i].pf2.fy
PinCtl_Rec[i].ofs.left=ofs.left
PinCtl_Rec[i].ofs.top=ofs.top
PinCtl_Rec[i].ofs.right=ofs.right
PinCtl_Rec[i].ofs.bottom=ofs.bottom
end sub