Author Topic: [SDK] 03 - Take control of your window(s) [REGION]  (Read 7947 times)

Patrice Terrier

  • Administrator
  • *****
  • Posts: 1992
    • zapsolution
[SDK] 03 - Take control of your window(s) [REGION]
« on: February 09, 2020, 05:13:54 pm »
WORK IN PROGRESS
This is the third post of a serie, where I shall try to explain how to take complete control over SDI window.

1 -CREATE CUSTOM BORDER USING 9-IMAGE MODE
To skin the form we use a "9-image mode" with the magenta color, RGB(255,0,255), to delimit the transparent part, that will be used to create the region on the fly.


Currently the "9-image" are being stored in the current folder, however in final version they should be stored either in a dedicated SKIN folder or as embedded binary resources, because we are not using BMP but PNG files.

2 - TILING or STRETCHING %FORM_CENTER
You can edit the code to select between STRETCHING or TILING of the %FORM_CENTER

We draw our custom background there:
Code: [Select]
SUB zDrawBackground()
    LOCAL hMain AS LONG, hIC AS LONG, hDC AS LONG, rc AS RECT
    LOCAL graphics, Img, ImgW, ImgH, Wider, ImgAttr, TilingMode AS LONG

    hMain = zMainWindow(0)
    IF IsIconic(hMain) THEN EXIT SUB

    CALL GetClientRect(hMain, rc)
    hIC = zDisplayDC()
    hDC = zPaintToScreen(hMain, hIC, rc.nRight, rc.nBottom, 1)

    IF GdipCreateFromHDC(hDC, graphics) = 0 THEN
'      // Wider is being used to compensate the stretching mode
       Wider = 20
       TilingMode = %TRUE

'      // paint first the center
       Img = zGetMainProperty(hMain, %FORM_Center): CALL zGetImageSize(Img, ImgW, ImgH)
       IF TilingMode THEN '// Paint in tiling mode
          LOCAL Rows, Cols, x, y, dx, dy, xOffset, yOffset, WasImgW AS LONG
          xOffset = 0: yOffset = 0
'         // Calc number of rows and columns to paint.
          IF ImgW THEN Rows = rc.nRight \ ImgW: IF Rows * ImgW < rc.nRight THEN Rows = Rows + 1
          IF ImgH THEN Cols = rc.nBottom \ ImgH: IF Cols * ImgH < rc.nBottom THEN Cols = Cols + 1
'         // Spray out across destination.
          WasImgW = ImgW
          FOR y = 1 TO Cols
              IF dy + ImgH > rc.nBottom THEN ImgH = rc.nBottom - dy
              dx = 0: ImgW = WasImgW
              FOR x = 1 TO Rows
                  IF dx + ImgW > rc.nRight THEN ImgW = rc.nRight - dx
                  CALL GdipDrawImageRectRectI(graphics, Img, xOffset + dx, yOffset + dy, ImgW, ImgH, _
                                              0, 0, ImgW, ImgH, %UnitPixel, ImgAttr)
                  dx = dx + ImgW
              NEXT
              dy = dy + ImgH
          NEXT
       ELSE '              // Paint in stretch mode
          CALL GdipDrawImageRectRectI(graphics, Img, 0, 0, rc.nRight + Wider, rc.nBottom + Wider, _
                                      0, 0, ImgW, ImgH, %UnitPixel, ImgAttr)
       END IF

'      // paint top side
       Img = zGetMainProperty(hMain, %FORM_TopSide): CALL zGetImageSize(Img, ImgW, ImgH)
       CALL GdipDrawImageRectRectI(graphics, Img, 0, 0, rc.nRight + Wider, ImgH, _
                                   0, 0, ImgW, ImgH, %UnitPixel, ImgAttr)
'      // paint bottom side
       Img = zGetMainProperty(hMain, %FORM_BottomSide): CALL zGetImageSize(Img, ImgW, ImgH)
       CALL GdipDrawImageRectRectI(graphics, Img, 0, rc.nBottom - ImgH, rc.nRight + Wider, ImgH, _
                                   0, 0, ImgW, ImgH, %UnitPixel, ImgAttr)
'      // paint left side
       Img = zGetMainProperty(hMain, %FORM_SideLeft): CALL zGetImageSize(Img, ImgW, ImgH)
       CALL GdipDrawImageRectRectI(graphics, Img, 0, 0, ImgW, rc.nBottom + Wider, _
                                   0, 0, ImgW, ImgH, %UnitPixel, ImgAttr)
'      // paint right side
       Img = zGetMainProperty(hMain, %FORM_SideRight): CALL zGetImageSize(Img, ImgW, ImgH)
       CALL GdipDrawImageRectRectI(graphics, Img, rc.nRight - ImgW, 0, ImgW, rc.nBottom + Wider, _
                                   0, 0, ImgW, ImgH, %UnitPixel, ImgAttr)
'      // paint top left
       Img = zGetMainProperty(hMain, %FORM_TopLeft): CALL zGetImageSize(Img, ImgW, ImgH)
       CALL GdipDrawImageRectRectI(graphics, Img, 0, 0, ImgW, ImgH, _
                                   0, 0, ImgW, ImgH, %UnitPixel, ImgAttr)
'      // paint top right
       Img = zGetMainProperty(hMain, %FORM_TopRight): CALL zGetImageSize(Img, ImgW, ImgH)
       CALL GdipDrawImageRectRectI(graphics, Img, rc.nRight - ImgW, 0, ImgW, ImgH, _
                                   0, 0, ImgW, ImgH, %UnitPixel, ImgAttr)
'      // paint bottom left
       Img = zGetMainProperty(hMain, %FORM_BottomLeft): CALL zGetImageSize(Img, ImgW, ImgH)
       CALL GdipDrawImageRectRectI(graphics, Img, 0, rc.nBottom - ImgH, ImgW, ImgH, _
                                   0, 0, ImgW, ImgH, %UnitPixel, ImgAttr)
'      // paint bottom right
       Img = zGetMainProperty(hMain, %FORM_BottomRight): CALL zGetImageSize(Img, ImgW, ImgH)
       CALL GdipDrawImageRectRectI(graphics, Img, rc.nRight - ImgW, rc.nBottom - ImgH, ImgW, ImgH, _
                                   0, 0, ImgW, ImgH, %UnitPixel, ImgAttr)

       CALL GdipDeleteGraphics(graphics)
    END IF

'   // WP_PRINT and WM_PRINCLIENT is very valuable for double buffering technic
    'lParam& = %PRF_CLIENT OR %PRF_CHILDREN OR %PRF_NONCLIENT OR %PRF_ERASEBKGND OR %PRF_CHECKVISIBLE OR %PRF_OWNED
    lParam& = %PRF_CLIENT OR %PRF_CHILDREN OR %PRF_NONCLIENT OR %PRF_CHECKVISIBLE 'OR %PRF_OWNED
    CALL SendMessage(hMain, %WM_PRINT, hDC, lParam&)

    CALL DeleteDC(hIC)

'   // We use Magenta color, -1 means use the top left pixel color at coordinate 0,0.
    CALL zCreateFormRegion(&hFF00FF) ' &HFF00FF = Magenta color

END SUB

3 - CREATE REGION ON THE FLY
We use dynamic region that is updated while the user drags the borders.

If instead of the magenta color, you use -1 for transparent color, then the pixel color located at 0,0 ( top left corner) will be used to create the region.
Code: [Select]
'// Create new Main form region on the fly
SUB zCreateFormRegion(BYVAL TransColor AS LONG)

    LOCAL bm AS BITMAP
    LOCAL rdh AS RGNDATAHEADER PTR
    LOCAL lpRect AS RECT PTR
    LOCAl hRgn1 AS LONG, hRgn2 AS LONG, TT AS LONG, MaxRegions AS LONG, sRegionData AS STRING
    LOCAL hDIB, I, J, K, M, IsSame AS LONG

    hDIB = zGetPaintBitmap(zMainWindow(0)): IF hDIB = 0 THEN EXIT SUB

    MaxRegions = 4000

    CALL GetObject(hDIB, SIZEOF(bm), bm)
    REDIM Ar(0) AS LONG AT bm.bmBits

  ' Set up the transparent color
    IF TransColor = -1 THEN ' Common Trancolor is magenta &HFF00FF
       TransColor = (Ar((bm.bmHeight - 1) * bm.bmWidth) AND &HFFFFFF)'<--- (0, 0)
    END IF

    sRegionData = STRING$(LEN(RGNDATAHEADER) + LEN(RECT) * MaxRegions, 0)
    rdh = STRPTR(sRegionData)
    @rdh.nCount = MaxRegions + 1
    @rdh.dwSize = LEN(RGNDATAHEADER)
    @rdh.iType = %RDH_RECTANGLES
    @rdh.rcBound.nLeft = 0
    @rdh.rcBound.nTop = 0
    @rdh.rcBound.nRight = bm.bmWidth
    @rdh.rcBound.nBottom = bm.bmHeight
    FOR J = 0 TO bm.bmHeight - 1
        TT = bm.bmWidth * (bm.bmHeight - 1 - J): M = -1
        FOR I = 0 TO bm.bmWidth
            IF I = bm.bmWidth THEN K = TransColor ELSE K = (Ar(TT) AND &HFFFFFF): INCR TT

            IF K = TransColor THEN IsSame = -1 ELSE IsSame = 0

            IF IsSame = 0 THEN
               IF M = -1 THEN M = I
            ELSEIF M >= 0 THEN
               IF @rdh.nCount >= MaxRegions THEN
                  hRgn2 = ExtCreateRegion(BYVAL 0, LEN(RGNDATAHEADER) + (LEN(RECT) * @rdh.nCount), BYVAL rdh)
                  IF hRgn1 = 0 THEN
                     hRgn1 = hRgn2
                  ELSE
                     CALL CombineRgn(hRgn1, hRgn1, hRgn2, %RGN_OR)
                     CALL zDeleteObject(hRgn2)
                  END IF
                  lpRect = LEN(RGNDATAHEADER) + rdh
                  @rdh.nCount = 0
               END IF
               INCR @rdh.nCount
               @lpRect.nLeft = M
               @lpRect.nRight = I
               @lpRect.nTop = J
               @lpRect.nBottom = J + 1
               lpRect = lpRect + LEN(RECT)
               M = -1
            END IF
        NEXT
    NEXT
    hRgn2 = ExtCreateRegion(BYVAL 0, LEN(RGNDATAHEADER) + (LEN(RECT) * @rdh.nCount), BYVAL rdh)
    IF hRgn1 = 0 THEN
       hRgn1 = hRgn2
    ELSE
       CALL CombineRgn(hRgn1, hRgn1, hRgn2, %RGN_OR)
       CALL DeleteObject(hRgn2)
    END IF

    IF hRgn1 THEN CALL SetWindowRgn(zMainWindow(0), hRgn1, %TRUE)

END SUB

Next step:
I shall add the caption bar, and a new SUPERCLASS for PUSBUTTON with text.

To be continued...
« Last Edit: February 09, 2020, 05:21:17 pm by Patrice Terrier »
Patrice
(Always working with the latest Windows version available...)

Patrice Terrier

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