WORK IN PROGRESS
This is the first post of a serie, where I shall try to explain how to take complete control over SDI window.
1 - Use "CreateWindowEx" to create the popup.
2 - Use this dwstyle to create the window
%WS_POPUP OR %WS_VISIBLE OR %WS_CLIPSIBLINGS OR %WS_CLIPCHILDREN
3 - Handle yourself HITTEST detection to resize the window
'// Monitor Windows DEF PROC to take over HITTEST detection
FUNCTION zDefWindowProc(BYVAL hWnd AS LONG, BYVAL Msg AS LONG, BYVAL wParam AS LONG, BYVAL lParam AS LONG) AS LONG
LOCAL nRet, HITTEST AS LONG
LOCAL rc AS RECT
nRet = DefWindowProc(hWnd, Msg, wParam, lParam)
IF Msg = %WM_NCHITTEST THEN
IF IsZoomed(hWnd) = 0 THEN
IF nRet = %HTCLIENT THEN
LOCAL p AS POINTAPI
HITTEST = %HTCAPTION
IF zWinResizable(hWnd) THEN ' We fool Window
p.X = LOWRD(lParam): p.Y = HIWRD(lParam)
CALL ScreenToClient(hWnd, p)
CALL GetClientRect (hWnd, rc)
LOCAL xF, yF, xSide, Border AS LONG
xF = rc.nRight: yF = rc.nBottom
xSide = 0
Border = GetSystemMetrics(32) ' %SM_CXFRAME
IF ((p.X >= xF - Border) AND ((p.Y >= yF - Border))) THEN
HITTEST = %HTBOTTOMRIGHT
ELSE
'// Left side
IF (p.X <= 8) THEN
IF (p.X <= Border) THEN HITTEST = %HTLEFT
xSide = 1
END IF
'// Right side
IF (p.X >= xF - 8) THEN
IF (p.X >= xF - Border) THEN HITTEST = %HTRIGHT
xSide = 2
END IF
'// Top side
IF (p.Y <= Border) THEN
HITTEST = %HTTOP
IF (xSide = 1) THEN
HITTEST = %HTTOPLEFT
ELSEIF (xSide = 2) THEN
HITTEST = %HTTOPRIGHT
END IF
END IF
'// Bottom side
IF (p.Y >= yF - Border) THEN
IF (xSide = 1) THEN
HITTEST = %HTBOTTOMLEFT
ELSE
HITTEST = %HTBOTTOM
END IF
END IF
END IF
END IF
nRet = HITTEST
END IF
END IF
END IF
FUNCTION = nRet
END FUNCTION
4 - Use your own system buttons
This way you will be able to customize them as you want, making them, for example, ownerdrawn buttons.
SUB zCreateSysButton(BYVAL hMain AS LONG)
LOCAL rc AS RECT
LOCAL bw, bh AS LONG
IF IsWindow(hMain) THEN
CALL GetClientRect(hMain, rc)
bw = 80: bh = 22
' Create button "CLOSE"
CALL CreateWindowEx(0, "BUTTON", "CLOSE", %WS_CHILD OR %WS_VISIBLE OR %WS_TABSTOP, _
rc.nRight - bw, 0, bw, bh, hMain, %ID_CLOSE, zInstance, BYVAL %NULL)
CALL zSetCTLFont(GetDlgItem(hMain, %ID_CLOSE), zDefaultFont)
CALL zSetAnchorMode(GetDlgItem(hMain, %ID_CLOSE), %ANCHOR_RIGHT)
CALL CreateWindowEx(0, "BUTTON", "RESTORE", %WS_CHILD OR %WS_TABSTOP, _
rc.nRight - (bw * 2), 0, bw, bh, hMain, %ID_RESTORE, zInstance, BYVAL %NULL)
CALL zSetCTLFont(GetDlgItem(hMain, %ID_RESTORE), zDefaultFont)
CALL zSetAnchorMode(GetDlgItem(hMain, %ID_RESTORE), %ANCHOR_RIGHT)
CALL CreateWindowEx(0, "BUTTON", "MAXIMIZE", %WS_CHILD OR %WS_VISIBLE OR %WS_TABSTOP, _
rc.nRight - (bw * 2), 0, bw, bh, hMain, %ID_MAXIMIZE, zInstance, BYVAL %NULL)
CALL zSetCTLFont(GetDlgItem(hMain, %ID_MAXIMIZE), zDefaultFont)
CALL zSetAnchorMode(GetDlgItem(hMain, %ID_MAXIMIZE), %ANCHOR_RIGHT)
CALL CreateWindowEx(0, "BUTTON", "MINIMIZE", %WS_CHILD OR %WS_VISIBLE OR %WS_TABSTOP, _
rc.nRight - (bw * 3), 0, bw, bh, hMain, %ID_MINIMIZE, zInstance, BYVAL %NULL)
CALL zSetCTLFont(GetDlgItem(hMain, %ID_MINIMIZE), zDefaultFont)
CALL zSetAnchorMode(GetDlgItem(hMain, %ID_MINIMIZE), %ANCHOR_RIGHT)
END IF
END SUB
5 - Use anchor properties to move correctly child controls while resizing the main form.
'// Anchor item detection
FUNCTION zAnchorItem(BYVAL hWnd AS LONG) AS LONG
LOCAL Item AS LONG
IF UBOUND(gProp) > 0 THEN
ARRAY SCAN gProp(), FROM 1 TO 4, = MKL$(hWnd), TO Item
END IF
FUNCTION = Item
END FUNCTION
'// Anchor properties setup
FUNCTION zSetAnchorMode (BYVAL hWnd AS LONG, BYVAL AnchorMode AS LONG) AS LONG
LOCAL pZP AS LONG
IF IsWindow(hWnd) THEN
LOCAL rc AS RECT, pr AS RECT, p AS POINTAPI
pZP = zAnchorItem(hWnd)
IF pZP = 0 THEN ' If the object already exist then we ReUse it
pZP = MAX&(UBOUND(gProp) + 1, 1)
REDIM PRESERVE gProp(1 TO pZP) AS ANCHORPROPERTY
END IF
gProp(pZP).hWnd = hWnd
CALL GetWindowRect(hWnd, rc)
p.X = rc.nLeft: p.Y = rc.nTop
CALL ScreenToClient(Getparent(hWnd), p)
CALL GetClientRect(Getparent(hWnd), pr)
gProp(pZP).anchor = MIN&(MAX&(AnchorMode, %ANCHOR_NONE), %ANCHOR_CENTER)
gProp(pZP).rc.nLeft = p.X
gProp(pZP).rc.nTop = p.Y
gProp(pZP).rc.nRight = pr.nRight - (rc.nRight - rc.nLeft + p.X)
gProp(pZP).rc.nBottom = pr.nBottom - (rc.nBottom - rc.nTop + p.Y)
FUNCTION = -1
END IF
END FUNCTION
'// Anchor enum callback function
FUNCTION AnchorEnum(BYVAL hWnd AS LONG, BYVAL lParam AS LONG) AS LONG
'LOCAL zChildClass AS ASCIIZ * 32
LOCAL pr AS RECT, rc AS RECT, pZP AS LONG
LOCAL x, y, xW, yH AS LONG
'IF GetClassName(hWnd, zChildClass, SIZEOF(zChildClass)) THEN
pZP = zAnchorItem(hWnd)
IF pZP THEN
IF gProp(pZP).anchor > %ANCHOR_NONE THEN
CALL GetClientRect(hWnd, rc)
CALL GetClientRect(GetParent(hWnd), pr)
x = 0: y = 0: xW = 0: yH = 0
SELECT CASE LONG gProp(pZP).anchor
'CASE %ANCHOR_NONE '= 0
CASE %ANCHOR_WIDTH '= 1
x& = gProp(pZP).rc.nLeft
y& = gProp(pZP).rc.nTop
xW& = MAX&(pr.nRight - gProp(pZP).rc.nLeft - gProp(pZP).rc.nRight, 0)
yH& = rc.nBottom
CASE %ANCHOR_RIGHT '= 2
x& = pr.nRight - rc.nRight - gProp(pZP).rc.nRight
y& = gProp(pZP).rc.nTop
xW& = rc.nRight
yH& = rc.nBottom
CASE %ANCHOR_CENTER_HORZ '= 3
x& = (pr.nRight - rc.nRight) \ 2
y& = gProp(pZP).rc.nTop
xW& = rc.nRight
yH& = rc.nBottom
CASE %ANCHOR_HEIGHT '= 4
x& = gProp(pZP).rc.nLeft
y& = gProp(pZP).rc.nTop
xW& = rc.nRight
yH& = MAX&(pr.nBottom - gProp(pZP).rc.nTop - gProp(pZP).rc.nBottom, 0)
CASE %ANCHOR_HEIGHT_WIDTH '= 5
x& = gProp(pZP).rc.nLeft
y& = gProp(pZP).rc.nTop
xW& = MAX&(pr.nRight - gProp(pZP).rc.nLeft - gProp(pZP).rc.nRight, 0)
yH& = MAX&(pr.nBottom - gProp(pZP).rc.nTop - gProp(pZP).rc.nBottom, 0)
CASE %ANCHOR_HEIGHT_RIGHT '= 6
x& = pr.nRight - rc.nRight - gProp(pZP).rc.nRight
y& = gProp(pZP).rc.nTop
xW& = rc.nRight
yH& = MAX&(pr.nBottom - gProp(pZP).rc.nTop - gProp(pZP).rc.nBottom, 0)
CASE %ANCHOR_BOTTOM '= 7
x& = gProp(pZP).rc.nLeft
y& = pr.nBottom - gProp(pZP).rc.nBottom - rc.nBottom
xW& = rc.nRight
yH& = rc.nBottom
CASE %ANCHOR_BOTTOM_WIDTH '= 8
x& = gProp(pZP).rc.nLeft
y& = pr.nBottom - gProp(pZP).rc.nBottom - rc.nBottom
xW& = MAX&(pr.nRight - gProp(pZP).rc.nLeft - gProp(pZP).rc.nRight, 0)
yH& = rc.nBottom
CASE %ANCHOR_BOTTOM_RIGHT '= 9
x& = pr.nRight - rc.nRight - gProp(pZP).rc.nRight
y& = pr.nBottom - gProp(pZP).rc.nBottom - rc.nBottom
xW& = rc.nRight
yH& = rc.nBottom
CASE %ANCHOR_CENTER_HORZ_BOTTOM '= 10
x& = (pr.nRight - rc.nRight) \ 2
y& = pr.nBottom - gProp(pZP).rc.nBottom - rc.nBottom
xW& = rc.nRight
yH& = rc.nBottom
CASE %ANCHOR_CENTER_VERT '= 11
x& = gProp(pZP).rc.nLeft
y& = (pr.nBottom - rc.nBottom) \ 2
xW& = rc.nRight
yH& = rc.nBottom
CASE %ANCHOR_CENTER_VERT_RIGHT '= 12
x& = pr.nRight - rc.nRight - gProp(pZP).rc.nRight
y& = (pr.nBottom - rc.nBottom) \ 2
xW& = rc.nRight
yH& = rc.nBottom
CASE %ANCHOR_CENTER '= 13
x& = (pr.nRight - rc.nRight) \ 2
y& = (pr.nBottom - rc.nBottom) \ 2
xW& = rc.nRight
yH& = rc.nBottom
END SELECT
CALL MoveWindow(hWnd, x&, y&, xW&, yH&, 1)
END IF
END IF
'END IF
FUNCTION = %TRUE ' Continue enumeration of children..
END FUNCTION
Next step I will show you how to create the system ownerdrawn buttons
to make them look (and act) like VISTA buttons...