• Welcome to Powerbasic Museum 2020-B.
 

News:

Forum in repository mode. No new members allowed.

Main Menu

[SDK] 01 - Take control of your window(s)

Started by Patrice Terrier, August 05, 2007, 03:02:21 PM

Previous topic - Next topic

0 Members and 1 Guest are viewing this topic.

Patrice Terrier

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...


Patrice Terrier
www.zapsolution.com
Patrice Terrier
GDImage (advanced graphic addon)
http://www.zapsolution.com

Petr Schreiber

Patrice,

thanks for your example - result looks cool.
Just one thing - what is stored in zSkin01.rc ? I presume programs icon + something ?


Thanks a lot,
Petr
AMD Sempron 3400+ | 1GB RAM @ 533MHz | GeForce 6200 / GeForce 9500GT | 32bit Windows XP SP3

psch.thinbasic.com

Theo Gottwald

I also think that Posts "in series" are an interesting chance for many readers to easily get new experts knowledge.

Good idea, Patrice!

Patrice Terrier

Here is the RC file

PROGRAM ICON ZAP.ICO

// Manifest info for WinXP theme support
#define CREATEPROCESS_MANIFEST_RESOURCE_ID   1
#define RT_MANIFEST                         24
#define CONTROL_PANEL_RESOURCE_ID          123

CREATEPROCESS_MANIFEST_RESOURCE_ID RT_MANIFEST "control.man"


and here is the "control.man" XML manifest file


<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
   <assemblyIdentity
       version="1.0.0.0"
       processorArchitecture="X86"
       name="www.zapsolution.com"
       type="win32" />
   <description>WinXP Manifest For ZAP</description>
   <dependency>
       <dependentAssembly>
           <assemblyIdentity
               type="win32"
               name="Microsoft.Windows.Common-Controls"
               version="6.0.0.0"
               processorArchitecture="X86"
               publicKeyToken="6595b64144ccf1df"
               language="*" />
       </dependentAssembly>
   </dependency>
</assembly>    
Patrice Terrier
GDImage (advanced graphic addon)
http://www.zapsolution.com

Petr Schreiber

Thank you very much,

this info is really interesting to check "behind the scenes" stuff


Petr
AMD Sempron 3400+ | 1GB RAM @ 533MHz | GeForce 6200 / GeForce 9500GT | 32bit Windows XP SP3

psch.thinbasic.com

Patrice Terrier

The corrupted ZIP file attached to the first post of this thread has been removed (because of the "Server Collapse").

...
Patrice Terrier
GDImage (advanced graphic addon)
http://www.zapsolution.com