Author Topic: [SDK] 01 - Take control of your window(s)  (Read 3227 times)

Patrice Terrier

  • Administrator
  • *****
  • Posts: 1980
    • zapsolution
[SDK] 01 - Take control of your window(s)
« on: February 09, 2020, 05:14:55 pm »
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
Code: [Select]
'// 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.
Code: [Select]
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.

Code: [Select]
'// 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...

« Last Edit: February 09, 2020, 05:28:16 pm by Patrice Terrier »
Patrice
(Always working with the latest Windows version available...)

Patrice Terrier

  • Administrator
  • *****
  • Posts: 1980
    • zapsolution
Re: [SDK] 01 - Take control of your window(s)
« Reply #1 on: February 09, 2020, 06:23:02 pm »
.
Patrice
(Always working with the latest Windows version available...)