Posts: 41
Threads: 12
Joined: 27.01.2025
20.09.2025, 07:43 PM
(This post was last modified: 20.09.2025, 09:46 PM by Gary Beene.)
I decided to break the gbScroller app into two parts. The first is posted in the forum as gbClientCapture.
It captures the area under the transparent dialog client, merging each new capture into a horizontal image for subsequent scrolling. I've not yet written the scrolling app.
The area between the Toolbar and Statusbar is captured and merged into a horizontal image.
Some new features come to mind:
1. allow using the arrow keys to more accurately position the dialog
2. with transparency, the resize with a mouse ability is limited to the caption and toolbar. Not sure why but I know I don't like it.
Not a feature, but I notice there is a tiny gap between the caption and toolbar. I'm not sure why. I thought the toolbar by default would be positioned immediately next to the caption.
And, another thing, I tweaked the various dimensions to make sure the client area is captured, without overlapping the toolbar, statusbar and dialog borders. But it seems to me that I should have been able to do a more exact dimensioning of the capture positioning/size.
Here's how I envision this working.
1. Call up the electronic copy of the music (PDF in this example).
2. Place gbClientCapture over the first row of music (resize as needed)
3. Click "Copy"
4. Scroll the PDF upwards until the next row of music is under gbClientCapture (that should be easier than moving the dialog itself.
5. Click "Copy"
6. Repeat until all rows of music are captured and placed in the "merge.bmp" file.
In this example, the Adele music sheet PDF is displayed vertically in my browser. The gbClientCapture is positioned over the first row, ready for "Copy". Then, instead of moving the dialog to a new position, I scroll the PDF upwards until the next row of music is visible under the dialog client area. Repeat Copying untill all rows of music are captured. With each capture the "merge.bmp" file is updated to contain the most recent capture.
Posts: 31
Threads: 5
Joined: 27.05.2024
20.09.2025, 10:18 PM
(This post was last modified: 20.09.2025, 10:27 PM by Jules Marchildon.)
Hey! Hey!
It's the 2-pixel divider part of the toolbar's rendering but you didn't fill it using your custom draw handler it only painted the provided rect leaving it's background color white and becomes transparent. Just remove it.
Code: '-add styles to remove the 3D borders and the 2-pixel top highlight/divider.
CONTROL ADD TOOLBAR, hDlg, %IDC_Toolbar, "", 0,0,0,0, %TBSTYLE_FLAT OR %CCS_NODIVIDER
Posts: 31
Threads: 5
Joined: 27.05.2024
I was looking at the resizing cursor issue. For sure the transparency is messing with the WM_NCHITTEST 'ing for the borders and the status bar grip sizer. For giggles I reverted back to the classic frame, but this introduced flicker issues with your toolbar.
Added %WM_CLIPCHILDREN to your dialog and under WM_INITDIALOG...
Code: '-disable DWM non-client rendering for classic borders
LOCAL policy AS LONG
policy = %DWMNCRP_DISABLED
LOCAL lReturn AS LONG
CALL DwmSetWindowAttribute(hDlg, %DWMWA_NCRENDERING_POLICY, BYVAL VARPTR(policy), 4)
'-force frame redraw to apply changes
SetWindowPos hDlg, 0, 0, 0, 0, 0, %SWP_FRAMECHANGED OR %SWP_NOMOVE OR %SWP_NOSIZE OR %SWP_NOZORDER
RedrawWindow hDlg, BYVAL 0, BYVAL 0, %RDW_FRAME OR %RDW_INVALIDATE
I tried adding a double buffer to your toolbar drawing but no luck so far reducing the flicker while resizing.
Posts: 31
Threads: 5
Joined: 27.05.2024
21.09.2025, 03:55 AM
(This post was last modified: 21.09.2025, 04:03 AM by Jules Marchildon.)
I was thinking it would be easier to create a region hole instead to avoid going down a deep rabbit hole to resolve your sizing issue. OK, so here is a snippet I lifted from an old post. It has one side effect...
Code: '
'-snippet taken from Greg Turgeon post 5 Aug 2007 PowerBASIC forum
' https://forum.powerbasic.com/forum/user-to-user-discussions/powerbasic-for-windows/14801-how-to-make-a-hole?p=205890#post205890
#COMPILE EXE
#DIM ALL
#INCLUDE "WIN32API.INC"
#RESOURCE MANIFEST, 1, "icons\xptheme_dpiaware.xml"
'--------------------------------------------------------------------------------------------------
'
'--------------------------------------------------------------------------------------------------
FUNCTION PBMAIN&()
LOCAL hDlg, x, y, lwide, lhigh AS LONG
DIALOG NEW PIXELS, 0,"", , , 496, 160, %WS_SYSMENU OR %WS_MINIMIZEBOX OR %WS_CAPTION OR %WS_THICKFRAME,, TO hDlg
DIALOG GET CLIENT hDlg TO x, y
DIALOG SHOW MODAL hDlg, CALL DlgMain&()
END FUNCTION
'--------------------------------------------------------------------------------------------------
'
'--------------------------------------------------------------------------------------------------
CALLBACK FUNCTION DlgMain&()
STATIC captionHigh AS LONG
LOCAL hRgn, lwide, lhigh, clientWide, clientHigh AS LONG
LOCAL rc AS RECT, p() AS POINTL
SELECT CASE AS LONG CBMSG
CASE %WM_INITDIALOG
captionHigh = GetSystemMetrics(%SM_CYCAPTION)
SetWindowPos CBHNDL, %HWND_TOPMOST, 0, 0, 0, 0, %SWP_NOSIZE OR %SWP_NOMOVE
DIALOG GET SIZE CBHNDL TO lwide, lhigh
DIALOG GET CLIENT CBHNDL TO clientWide, clientHigh
SetRect rc, 10, (lhigh-clientHigh)+captionHigh*2, lwide-10, lhigh-captionHigh
hRgn = CreateRectRgn(rc.nLeft, rc.nTop, rc.nRight, rc.nBottom)
CreateHole CBHNDL, hRgn, %TRUE
CASE %WM_SIZE
DIALOG GET SIZE CBHNDL TO lwide, lhigh
DIALOG GET CLIENT CBHNDL TO clientWide, clientHigh
SetRect rc, 10, (lhigh-clientHigh)+captionHigh*2, lwide-10, lhigh-captionHigh
hRgn = CreateRectRgn(rc.nLeft, rc.nTop, rc.nRight, rc.nBottom)
CreateHole CBHNDL, hRgn, %TRUE
END SELECT
END FUNCTION
'--------------------------------------------------------------------------------------------------
'
'--------------------------------------------------------------------------------------------------
FUNCTION CreateHole&(BYVAL hWnd AS LONG, BYVAL hRGN AS LONG, BYVAL Action AS LONG)
LOCAL windowRect AS RECT, hWindowRgn, hHoleRgn, hThisRgn AS LONG
GetWindowRect hWnd, windowRect
hWindowRgn = CreateRectRgn(0,0,WindowRect.nRight, WindowRect.nBottom)
hHoleRgn = CreateRectRgn(0,0,0,0)
IF Action THEN
hThisRgn = CreateRectRgn (0,0,0,0)
CombineRgn hThisRgn, hRGN, 0&, %RGN_COPY
ELSE
CombineRgn hThisRgn, hRGN, 0&, %RGN_OR
END IF
CombineRgn hHoleRgn, hThisRgn, hWindowRgn, %RGN_XOR
SetWindowRgn hWnd, hHoleRgn, %TRUE
END FUNCTION
Posts: 41
Threads: 12
Joined: 27.01.2025
21.09.2025, 04:45 AM
(This post was last modified: 21.09.2025, 04:46 AM by Gary Beene.)
Howdy, Jules!
Thanks! I'd never noticed CCS_NoDivider before. Searching gbThreads, I do not see CCS_NoDivider mentioned in any thread! But, it does what I wanted!
As for the region approach, it does restore resizing.
What is the drawback that you refer to?
Posts: 31
Threads: 5
Joined: 27.05.2024
Hey Gary,
The DWM detects the custom region and disables theming for that window to avoid conflicts with shaped windows and falls back to the classic look for the frame/title bar. This is a known Win32 limitation when using SetWindowRgn.
Here, try this other version, this time using GDI+ , as long as you keep enough margin the sizing cursors will activate.
Code: #COMPILE EXE
#DIM ALL
#INCLUDE "WIN32API.INC"
#INCLUDE "gdipDash0713.inc" '<-replace with Jose or you own GDI+ include file.
CALLBACK FUNCTION DlgMain()
STATIC captionHigh AS LONG
STATIC keyColor AS LONG
LOCAL hBrushBg, hBrushKey AS DWORD
LOCAL lwide, lhigh, clientWide, clientHigh AS LONG
LOCAL rcWindow AS RECT
LOCAL rcHoleClient AS RECT
LOCAL rcClient AS RECT
LOCAL ps AS PAINTSTRUCT
LOCAL hDC AS DWORD
LOCAL frameX, frameY AS LONG
SELECT CASE AS LONG CB.MSG
CASE %WM_INITDIALOG
captionHigh = GetSystemMetrics(%SM_CYCAPTION)
frameX = GetSystemMetrics(%SM_CXFRAME)
frameY = GetSystemMetrics(%SM_CYFRAME)
keyColor = RGB(255, 0, 255) ' <-use Magenta as key color
SetWindowPos CB.HNDL, %HWND_TOPMOST, 0, 0, 0, 0, %SWP_NOSIZE OR %SWP_NOMOVE
SetLayeredWindowAttributes CB.HNDL, keyColor, 0, %LWA_COLORKEY
'-force repaint
InvalidateRect CB.HNDL, BYVAL %NULL, %TRUE
CASE %WM_SIZE
InvalidateRect CB.HNDL, BYVAL %NULL, %TRUE
CASE %WM_ERASEBKGND
FUNCTION = 1 :EXIT FUNCTION
CASE %WM_PAINT
hDC = BeginPaint(CB.HNDL, ps)
DIALOG GET SIZE CB.HNDL TO lwide, lhigh
DIALOG GET CLIENT CB.HNDL TO clientWide, clientHigh
GetClientRect CB.HNDL, rcClient
'-calc hole in window coordinates
' note: tweak your margins, left +10, right -25, bottom -25 to allow cursor hit testing
SetRect rcWindow, 10, (lhigh - clientHigh) + captionHigh * 2, lwide - 25, lhigh - captionHigh - 25
'-convert our hole to client coordinates
SetRect rcHoleClient, rcWindow.nLeft - frameX, rcWindow.nTop - (captionHigh + frameY), rcWindow.nRight - frameX, rcWindow.nBottom - (captionHigh + frameY)
'-fill entire client with system dialog background color
hBrushBg = CreateSolidBrush(GetSysColor(%COLOR_3DFACE))
FillRect hDC, rcClient, hBrushBg
DeleteObject hBrushBg
'-now fill hole with key color for transparency
hBrushKey = CreateSolidBrush(keyColor)
FillRect hDC, rcHoleClient, hBrushKey
DeleteObject hBrushKey
EndPaint CB.HNDL, ps
FUNCTION = 0 :EXIT FUNCTION
END SELECT
END FUNCTION
'--------------------------------------------------------------------------------------------------
'
'--------------------------------------------------------------------------------------------------
FUNCTION PBMAIN() AS LONG
LOCAL hDlg AS LONG
LOCAL token AS DWORD
'-start GDI+
IF StartGDIplus(BYREF token) THEN
MSGBOX "Failed to start GDI+", , "Error"
EXIT FUNCTION
END IF
DIALOG NEW PIXELS, 0, "Square Hole Demo", , , 496, 160, %WS_SYSMENU OR %WS_MINIMIZEBOX OR %WS_CAPTION OR %WS_THICKFRAME, %WS_EX_LAYERED TO hDlg
DIALOG SHOW MODAL hDlg, CALL DlgMain
'-stop GDI+
StopGDIplus token
END FUNCTION
Posts: 41
Threads: 12
Joined: 27.01.2025
Howdy, Jules!
Thanks for the additional code - GDI+ version. I'm working on integrating what you showed into my code - but it's about 1am here and I'm toast for the night. Will return in the morning!
Posts: 31
Threads: 5
Joined: 27.05.2024
And Gary, just a note about the %WS_MAZIMIZEBOX style, seems there is an issue on the win32 level recovering from a restore using any of techniques we both used except for the Greg Turgeon snippet version that uses the classic theme.
Posts: 41
Threads: 12
Joined: 27.01.2025
21.09.2025, 09:14 PM
(This post was last modified: 21.09.2025, 09:14 PM by Gary Beene.)
Howdy, Jules!
I haven't forgotten you! Just having to do a few household tasks for the wife! It may be a couple of hours before I'm back online.
I have integrated your last code and it's working mostly fine. I've added the arrow-key positioning, simplified some of your WM_Paint code. I don't have the capture working quite right - a few pixels off. Including a manifest causes the toolbar to go black. I'll post something when I get back later.
Thanks again for your posts. I'm definitely happier with getting back the resizing capability. People would have whined about it!
Posts: 41
Threads: 12
Joined: 27.01.2025
22.09.2025, 02:19 AM
(This post was last modified: 22.09.2025, 02:37 AM by Gary Beene.)
gbClientCapture v2.0 posted in the source code forums (looks the same, just some code updates).
Changes:
1. Suggestion by Jules, where a hole in the client area is made transparent instead of the entire client area, thus letting the dialog respond normally to resizing. Thanks Jules!
2. Captured image size shows on Statusbar
3. Up/Down/Left/Right arrows will move the dialog for precision positioning
4. Raised the icon sizes to 48px and changed the font so it is NOT bold.
5. Shortcuts C-Copy N-New V-View ESC-exit
|