WORK IN PROGRESSThis 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 MODETo 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_CENTERYou can edit the code to select between STRETCHING or TILING of the %FORM_CENTER
We draw our custom background there: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 FLYWe 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.
'// 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...