Scrollbars Made Easy - New version 22 Nov 14

145 posts in this topic

Posted (edited)

[New Version] - 22 Nov 14

Added: Ability to use scrollbars with resizeable GUIs. A new function _GUIScrollbars_Resizer will initiate the GUI for resizing - the scrollbars can be set to vanish above a certain GUI size and the GUI can be automatically created at a size such that they do not appear. The function returns an array which can be used to ensure that the GUI cannot be resized above those dimensions.

New UDFs, examples and zip file below. :)

Previous changes: Changelog.txt


Are you bemused by scrollbars? :(>

Do you find them too difficult to use? :(>

Then you need the GUIScrollbars_Ex UDF! :)

Just download the zip at the end of the post and run this short script with the UDF in the same folder. No tricky calculations, no complicated functions to master - just easy to use, accurate scrollbars with one command!

[size=5]#include <guiconstantsex.au3>
#include "GUIScrollbars_Ex.au3"

; Create GUI with red background
$hGUI = GUICreate("Test", 500, 500)
GUISetBkColor(0xFF0000, $hGUI)

; Create a 1000x1000 green label
GUICtrlCreateLabel("", 0, 0, 1000, 1000)
GUICtrlSetBkColor(-1, 0x00FF00)

GUISetState()

; Generate scrollbars - Yes, this is all you need to do!!!!!!!!!!!!!!!!!!!!
_GUIScrollbars_Generate($hGUI, 1000, 1000)

While 1
	Switch GUIGetMsg()
		Case $GUI_EVENT_CLOSE
			Exit
	EndSwitch
WEnd[/size]
Try it today and see how easy it is!

I have been trying for some time to understand how scrollbars work and how to get them closely to match the area I want to display. After much research and headscratching I have come up with 2 UDFs which I hope will be of use to others. Apologies for the length of this post, but scrollbars are complex beasts and as I did this mainly for the less experienced user I want to make sure that they understand what is going on.

The 2 UDFs are:

GUIScrollbars_Ex.au3 - This gives you scrollbars sized to your GUI in one simple command - with no other includes or commands needed. The UDF is designed for those who would not normally use scrollbars because the whole process looks too complicated. It also includes a command to enable you to scroll page by page, thus making it easy to scroll to anywhere on the GUI with only simple calulations based on the values you used to create the GUIs. [New] Ability to have recalculated scrollbars on resizeable GUIs.

GUIScrollbars_Size.au3 - This calculates the Page and Max numbers for the user to feed into the _GUIScrollbar_SetScrollInfoPage/Max commands. The UDF is aimed at the more experienced user and is particularly useful when you have a GUI with a dynamic scroll size (i.e. adding or subtracting controls to the scrollable area as the script runs).

First, a short tutorial for those who are interested in how the scrollbars affect your GUI and what it is that the UDFs calculate:

A GUI with scrollbars can be thought of as a window onto a larger underlying GUI which can be brought into view by moving the scrollbars. The difficulty has always been to get the correct values for the Page size and Max scroll values. The Max value determines the visible borders of the larger GUI when the scrollbars are moved to the ends of their travel, while the Page value determines how far a click on the scrollbar will scroll the GUI and the size of the scrollbar thumb in relation to the scrollbar length (normally you want the thumb to indicate the relative sizes of the visible area and the whole GUI). The Page and Max values are closely interrelated and are often diffcult to set so that the scrollbars show enough of the larger GUI to be useful but not so much that you end up looking at a blank area because you have scrolled well past the place where you wanted to stop.

Firstly, we have to understand that the scrollbars work effectively in character units - the number of lines vertically and the number of characters horizontally - and not the pixels we normally use in AutoIt. So to correctly set the Page and Max values for a vertical scrollbar, we need to calculate how many lines of text would fit into the visible window (Page) and into the area we wish to scroll (Max). Similar calculations are need for a horizontal scrollbar - except we use the number of characters that fit across the 2 areas rather then the number of lines.

It is this use of lines and character widths that makes getting the scrollbars to scroll exactly one page at a time, or to exactly the border of a GUI, so difficult. The Page and Max values must be set in integers - and so if there is not an exact number of lines or character widths in the GUI then scrolling a page or to the maximum value of the GUI is more or less accurate depending on how close the value is to an integer.

Here is a diagram showing the edge position of 8000 scrollable GUIs when the scrollbars were set to the maximum value. The green lines indicate distance of the horizontal edge from the gui border and the blue lines the vertical. As you would expect, the average value is around the 0 mark, but the distance can be off by up to half the unit value - on my machine the line height is 17 and the character width is 8, which explains the slightly wider spread of the vertical error. The UDFs actually return Max values which result in the red (horizontal) and purple (vertical) positions - I felt it was more important to have all of the GUI visible, but there is an option to choose the tighter fit if required.

post-38576-12725542666823_thumb.png

Now we need to understand what happens when scrollbars are added to a GUI. Everything is driven by the fact that the client area of the GUI (the area inside the borders and title bar) is reduced in size when the scrollbars are added. The size of the bars is determined by the system, so this reduction varies from machine to machine. The fact that the client area is reduced in size has different effects depending on whether the GUI contained controls before the scrollbars were displayed.

- If the GUI was empty of controls, then the only requirement is to take account of the slightly smaller client area when adding controls - the available space for displaying controls in the visible window is slightly reduced.

Original GUI without controls      New GUI with reduced Client area
#-----------------#                #-----------------#
#       }         #                #      }x         #
#       }         #                #      }x         #       
#       }         #                #      }x         #
#       }         #                #~~~~~~}x         #
#~~~~~~~}         #                #xxxxxxxx         #
#                 #                #                 #
#                 #                #                 #
#                 #                #                 #
#-----------------#                #-----------------#
- If the GUI already held controls then the problems are much greater. Windows automatically resizes the GUI so that you will see all of the old client area within the new smaller one. As a result all of the controls in the GUI will shrink and move slightly - even if they are not visible in the client area. This means that the whole GUI has effectively shrunk in size, which will affect the calculation of the Max value. It also means that any controls added to the GUI must take into account the changed positions of the existing controls or they will not align correctly.

Original GUI with controls         New GUI with reduced Client area and effectively reduced Max size
#-----------------#                #---------------#
# @     }         #                # @    }x       #
#       }         #                #      }x       #
#       }         #                #      }x       #
#       }         #                #~~~~~~}x       #
#~~~~~~~}         #                #xxxxxxxx       #
#                 #                #               #
#                 #                #               #
#                 #                #             @ #
#               @ #                #---------------#
#-----------------#
The UDFs take into account these changes and calculate the necessary values to display the GUI as the user intended.

There is a small script below which shows the above effects on real GUIs.

I hope this short tutorial has explained why scrollbars are a complicated thing to get to work correctly. Now please read on and see why the 2 UDFs may well allow you to use them in the future.

All the files mentioned here are in a downloadable zip file at the end of the post.

GUIScroll_Size.au3

As mentioned previously, the GUIScroll_Size.au3 UDF is aimed at the more experienced user who wants to use the full range of _GUIScrollbar comands, but would like a quick way of getting the required Page and Max values. It uses no other include files so you will need to include GUIScrollbars.au3 yourself, as well as the necessary GUIRegisterMsg and procedures for WM_VSCROLL and WM_HSCROLL. The syntax is simple - the size of the scrollable GUI and either the handle of the GUI you have created to hold the scrollbars or the size of the one you are going to create. It returns a 6-element array including the Page and Max values for the scrollbars and factors to compensate for the "shrinkage" of the GUI if you had already drawn some controls and wished to add others. Of interest, the returned Max value is biased not to clip the edges of the GUI - reducing it by 1 makes a tighter fit but can lead to some clipping. (If that does not make sense, please see the tutorial above for more details)

The Size_Example_1 script to show the UDF in action - the "Pass Size" button shows the effect of creating the scrollbars BEFORE the controls, the "Pass Handle" button shows what happens if the scrollbars are created AFTER the controls. If you do not understand why there is a difference - go and read the tutorial above ;) ! You will need to have the GUIScroll_Size.au3 UDF in the same folder.

Where this UDF really helps is if you have a scrollable GUI of variable size - if the number of controls varies with user selections for example. All you need to do is to rerun the UDF with the new size of the scrollable GUI and it produces a new Max value for you to use. The Size_Example_2 script shows how the function enables you to dynamically size your scrollbars depending on the number of controls required. As before it requires the GUIScroll_Size.au3 UDF in the same folder.

--------

Now the "simple" GUIScrollbars_Ex.au3 (which is actually the more complex internally as you would expect).

This UDF is intended to be the single point of call for creating scrollbars on a GUI - it will automatically add the GUIScrollbars UDF and the WM_VSCROLL and WM_HSCROLL GUIRegisterMsg commands and procedures to your script - so you need no commands other than those within the UDF itself. These commands are _GUIScrollbars_Generate and _GUIScrollbars_Scroll_Page.

As you might expect, _GUIScrollbars_Generate generates scrollbars for your GUI. It is usually called AFTER you have added all the controls and all you need to use it is the GUI handle and the size of the underlying GUI you want to scroll. If you so wish, you can also decide to generate the scrollbars BEFORE the controls on the scrollable GUI, and you can choose if you want to risk not quite reaching the edge of the GUI when the scrollbars are at the maximum position. So a basic call could be as simple as:

_GUIScrollbars_Generate ($hGUI, 1000, 1000)

which would put scrollbars on the $hGUI window allowing a 1000x1000 underlying GUI to be displayed.

_GUIScrollbars_Scroll_Page lets you scroll a page at a time. If your GUI was 200 pixels wide, you would have 1000/200 = 5 pages to scroll before reaching the edge - no need to know what the actual Page and Max values are, just use this simple division based on the number you use to draw the GUIs. So:

_GUIScrollbars_Scroll_Page ($hGUI, 3)

would scroll to the third page - it would display the area between 400 and 600 pixels of the full 1000 pixel width. If you ask for a page over the maximum available, you just scroll to the maximum position - asking for page 1 resets you to the origin.

_GUIScrollbars_Minimize and _GUIScrollbars_Restore allow you to reset the scrollbars to the correct position after a minimize/restore cycle.

Ex_Example_1 shows the UDF working. You can decide whether to have both or just one scrollbar, whether to create the scrollbars before or after the controls, and whether you want the maximum scroll to be tight to the edge or leave a border. Just select the options you want - the script selects a random width and height for both the scrollbar GUI and the underlying GUI - and press the "Scroll" button to show a single page scroll down and/or right followed by a scroll to the bottom right corner of the GUI. There are labels to let you see the size of the GUI and the accuracy of the page scrolls (please read the tutorial above to understand why these are almost certainly inaccurate). The script requires the GUIScrollbars_Ex.au3 UDF in the same folder.

Ex_Example_2 is a really simple example to show how easy generating scrollbars can now become! As you can see - no other includes, no GUIRegisterMsg commands, no WM_H/VSCROLL procedure functions. Just accurate scrolling and proportional thumb sizes.

Ex_Example_3 shows the automatic calculation of control positions.

Ex_Example_4 shows how to initiate the cursor keys to scroll the GUI as well.

[New] Ex_Example_5 shows how to use the new _GUIScrollbarsEx_Resizer function.

I hope these 2 UDFs are useful to AutoIt users - I certainly find them so.

Here is a zip file with the UDFs and examples: Scrollbars.zip

My grateful thanks to the authors of the GUIScrollbars and WinAPI UDFs for their code, some of which I have plundered. And as always I welcome constructive criticism and/or effusive congratulations. :)

M23

Edited by Melba23
TheDcoder, Xandy and 232showtime like this

Share this post


Link to post
Share on other sites



Posted

I was looking at something like this a couple of days back and found this (a post by you) and now you release this, awesome! Thanks.

Share this post


Link to post
Share on other sites

Posted

Very good, but if i am a “less experienced user”, then i will have a difficulties to save all these scripts to correct files and make it work. Why you guys don't post an attached zip-file with all needed UDFs/Examples, so lazy users as my self could just download the archive, unpack it and check the great stuff you have there :idea:

Share this post


Link to post
Share on other sites

Posted

MrCreatoR,

post an attached zip-file

Done - see first post. :idea:

M23

Share this post


Link to post
Share on other sites

Posted

Done - see first post

Thank you!

Share this post


Link to post
Share on other sites

Posted

Melba23,

Posted Image AWESOME! A very nice implementation and a job well done!

I needed something like this for one of my projects so this will be of much use.

James

Share this post


Link to post
Share on other sites

Posted

Hi,

I realised that there was not a really simple example to show how easy GUIScrollbars_Ex is to use - so here it is:

#include <GUIConstantsEx.au3>
#include <GUIScrollbars_Ex.au3>

; Create GUI with red background
$hGUI = GUICreate("Test", 500, 500)
GUISetBkColor(0xFF0000, $hGUI)

; Create a 1000x1000 green label
GUICtrlCreateLabel("", 0, 0, 1000, 1000)
GUICtrlSetBkColor(-1, 0x00FF00)

GUISetState()

; Generate scrollbars - yes this is all you have to do!!!!!!!!!!!!!!
_GUIScrollbars_Generate($hGUI, 1000, 1000)

While 1

	Switch GUIGetMsg()
		Case $GUI_EVENT_CLOSE
			Exit
	EndSwitch

WEnd

I have added it to the zip above and amended the first post. :idea:

M23

Share this post


Link to post
Share on other sites

Posted

I realised that there was not a really simple example to show how easy GUIScrollbars_Ex is to use - so here it is:

Nice, but i think that you can make more usefull example. Many users need the scrollable GUI for the settings window, so this window could include more options in one place (reachable by the scroll).

Here is the example:

#include <GUIConstantsEx.au3>
#include <GUIScrollbars_Ex.au3>

; Create GUI
$hGUI = GUICreate("_GUIScrollbars_Generate Demo", 500, 500)

$iTop = 20

For $i = 1 To 100
	GUICtrlCreateCheckbox("Option " & $i & "-a", 20, $iTop)
	GUICtrlCreateCheckbox("Option " & $i & "-b", 500, $iTop)
	
	$iTop += 20
Next

; Generate scrollbars
_GUIScrollbars_Generate($hGUI, 600, $iTop)

GUISetState()

While 1
	Switch GUIGetMsg()
		Case $GUI_EVENT_CLOSE
			Exit
	EndSwitch
WEnd

P.S

I have one small(?) feature request: Add an ability to scroll the window by mouse wheel.

Share this post


Link to post
Share on other sites

Posted

MrCreatoR,

Add an ability to scroll the window by mouse wheel

I have never been able to get my mouse to scroll an AutoIt scrollbar. And yes I have tried your MouseOnEvent UDF. :idea: Everything works except the scroll wheel.

So if you would like to work at it, be my guest. :)

M23

Share this post


Link to post
Share on other sites

Posted

Hi Melba,

I'm drawing custom window, at least the title bar is custom. However I'm unable to make the scrollbars ignore the top region and only scroll an area beneath it.

#NoTrayIcon
#include <GUIConstantsEx.au3>
#include <WindowsConstants.au3>
#include <SendMessage.au3>
#include <Constants.au3>
#include <WinApi.au3>
#include <GUIScrollBars.au3>
#include <ScrollBarConstants.au3>

#include "../GUIScrollbars_Size.au3"


Global Const $SC_DRAGMOVE = 0xF012
Opt("MouseCoordMode", 2)

Local $tMsg
Opt("TrayMenuMode", 1)

$frmMain = GUICreate("frmMain", 333, 441, -1, -1, $WS_POPUP, 0)
GUISetState(@SW_SHOW)
GUISetBkColor(0xe9eff5, $frmMain)

; Scrollbars
$aRet = _GUIScrollbars_Size(0, 500, 1, 441)
GUIRegisterMsg($WM_VSCROLL, "_Scrollbars_WM_VSCROLL")

_GUIScrollBars_Init($frmMain)
_GUIScrollBars_ShowScrollBar($frmMain, $SB_VERT, True)
_GUIScrollBars_ShowScrollBar($frmMain, $SB_HORZ, False)
_GUIScrollBars_SetScrollInfoPage($frmMain, $SB_VERT, $aRet[2])
_GUIScrollBars_SetScrollInfoMax($frmMain, $SB_VERT, $aRet[3])

$rgn = _WinAPI_CreateRoundRectRgn(0, 0, 333, 441, 3, 3)
_WinAPI_SetWindowRgn($frmMain, $rgn)
DrawBar()

While 1
	$tMsg = TrayGetMsg()
	Switch $tMsg
		Case $TRAY_EVENT_PRIMARYDOWN
			GUISetState(@SW_SHOW)
			DrawBar()
			WinSetState("frmMain", "", @SW_RESTORE)
			Opt("TrayIconHide", 1)
	EndSwitch

	$nMsg = GUIGetMsg()
	Switch $nMsg
		Case $GUI_EVENT_CLOSE
			Exit
		Case $GUI_EVENT_PRIMARYDOWN
			$mPos = MouseGetPos()
			If $mPos[1] <= 20 Then
				If $mPos[0] >= 295 And $mPos[0] <= 316 Then
					GUISetState(@SW_HIDE)
					Opt("TrayIconHide", 0)
				ElseIf $mPos[0] >= 313 And $mPos[0] <= 322 Then
					Exit
				Else
					_SendMessage($frmMain, $WM_SYSCOMMAND, $SC_DRAGMOVE, 0)
				EndIf
			EndIf
	EndSwitch
WEnd

Func DrawBar()
	Local $aDim = WinGetClientSize($frmMain)
	Local $hDC = _WinAPI_GetDC($frmMain)
	; Bar
	Local $hBrush = _WinAPI_CreateSolidBrush(0xf5d997) ; 0x97d9f5
	Local $hRect = DllStructCreate($tagRECT)
	DllStructSetData($hRect, "Left", 0)
	DllStructSetData($hRect, "Top", 0)
	DllStructSetData($hRect, "Right", $aDim[0])
	DllStructSetData($hRect, "Bottom", 20)
	_WinAPI_FillRect($hDC, DllStructGetPtr($hRect), $hBrush)
	_WinAPI_DeleteObject($hBrush)
	; Bar text
	Local $sTitle = WinGetTitle($frmMain)
	Local $hBrush = _WinAPI_CreateSolidBrush(0x000000) ; 0xe9eff5
	DllStructSetData($hRect, "Left", 4)
	DllStructSetData($hRect, "Top", 2)
	DllStructSetData($hRect, "Right", $aDim[0] - 40)
	DllStructSetData($hRect, "Bottom", 20)
	_WinAPI_SetBkMode($hDC, $TRANSPARENT)
	_WinAPI_SetTextColor($hDC, 0xFFFFFF)
	_WinAPI_DrawText($hDC, $sTitle, $hRect, $DT_LEFT)
	_WinAPI_DeleteObject($hBrush)
	; Minimize
	$hBrush = _WinAPI_CreateSolidBrush(0x000000)
	DllStructSetData($hRect, "Left", $aDim[0] - 37)
	DllStructSetData($hRect, "Top", 12)
	DllStructSetData($hRect, "Right", $aDim[0] - 28)
	DllStructSetData($hRect, "Bottom", 14)
	_WinAPI_FillRect($hDC, DllStructGetPtr($hRect), $hBrush)
	_WinAPI_DeleteObject($hBrush)
	; Close
	Local $hPen = _WinAPI_CreatePen($PS_SOLID, 2, 0x000000)
	Local $hSelected = _WinAPI_SelectObject($hDC, $hPen)
	_WinAPI_DrawLine($hDC, $aDim[0] - 20, 5, $aDim[0] - 11, 14)
	_WinAPI_DrawLine($hDC, $aDim[0] - 20, 14, $aDim[0] - 11, 5)
	_WinAPI_SelectObject($hDC, $hSelected)
	_WinAPI_DeleteObject($hPen)
	$hBrush = _WinAPI_CreateSolidBrush(0xd8ded3)
	; Frame Edge
	;$hBrush = _WinAPI_CreateSolidBrush(0x000000)
	DllStructSetData($hRect, "Left", 0)
	DllStructSetData($hRect, "Top", 20)
	DllStructSetData($hRect, "Right", 1)
	DllStructSetData($hRect, "Bottom", 1)
	_WinAPI_FillRect($hDC, DllStructGetPtr($hRect), $hBrush)
	DllStructSetData($hRect, "Left", $aDim[0] - 2)
	DllStructSetData($hRect, "Top", 20)
	DllStructSetData($hRect, "Right", $aDim[0])
	DllStructSetData($hRect, "Bottom", $aDim[1])
	_WinAPI_FillRect($hDC, DllStructGetPtr($hRect), $hBrush)
	DllStructSetData($hRect, "Left", 0)
	DllStructSetData($hRect, "Top", 20)
	DllStructSetData($hRect, "Right", 1)
	DllStructSetData($hRect, "Bottom", $aDim[1])
	_WinAPI_FillRect($hDC, DllStructGetPtr($hRect), $hBrush)
	DllStructSetData($hRect, "Left", 0)
	DllStructSetData($hRect, "Top", $aDim[1] - 2)
	DllStructSetData($hRect, "Right", $aDim[0])
	DllStructSetData($hRect, "Bottom", $aDim[1])
	_WinAPI_FillRect($hDC, DllStructGetPtr($hRect), $hBrush)
	_WinAPI_DeleteObject($hBrush)
	_WinAPI_ReleaseDC($frmMain, $hDC)
	AdlibRegister("DrawBar")
EndFunc   ;==>DrawBar

Func _Scrollbars_WM_VSCROLL($hWnd, $Msg, $wParam, $lParam)

	#forceref $Msg, $wParam, $lParam
	Local $nScrollCode = BitAND($wParam, 0x0000FFFF)
	Local $iIndex = -1, $yChar, $yPos
	Local $Min, $Max, $Page, $Pos, $TrackPos

	For $x = 0 To UBound($aSB_WindowInfo) - 1
		If $aSB_WindowInfo[$x][0] = $hWnd Then
			$iIndex = $x
			$yChar = $aSB_WindowInfo[$iIndex][3]
			ExitLoop
		EndIf
	Next
	If $iIndex = -1 Then Return 0

	Local $tSCROLLINFO = _GUIScrollBars_GetScrollInfoEx($hWnd, $SB_VERT)
	$Min = DllStructGetData($tSCROLLINFO, "nMin")
	$Max = DllStructGetData($tSCROLLINFO, "nMax")
	$Page = DllStructGetData($tSCROLLINFO, "nPage")
	$yPos = DllStructGetData($tSCROLLINFO, "nPos")
	$Pos = $yPos
	$TrackPos = DllStructGetData($tSCROLLINFO, "nTrackPos")

	Switch $nScrollCode
		Case $SB_TOP
			DllStructSetData($tSCROLLINFO, "nPos", $Min)
		Case $SB_BOTTOM
			DllStructSetData($tSCROLLINFO, "nPos", $Max)
		Case $SB_LINEUP
			DllStructSetData($tSCROLLINFO, "nPos", $Pos - 1)
		Case $SB_LINEDOWN
			DllStructSetData($tSCROLLINFO, "nPos", $Pos + 1)
		Case $SB_PAGEUP
			DllStructSetData($tSCROLLINFO, "nPos", $Pos - $Page)
		Case $SB_PAGEDOWN
			DllStructSetData($tSCROLLINFO, "nPos", $Pos + $Page)
		Case $SB_THUMBTRACK
			DllStructSetData($tSCROLLINFO, "nPos", $TrackPos)
	EndSwitch

	DllStructSetData($tSCROLLINFO, "fMask", $SIF_POS)
	_GUIScrollBars_SetScrollInfo($hWnd, $SB_VERT, $tSCROLLINFO)
	_GUIScrollBars_GetScrollInfo($hWnd, $SB_VERT, $tSCROLLINFO)

	$Pos = DllStructGetData($tSCROLLINFO, "nPos")
	If ($Pos <> $yPos) Then
		_GUIScrollBars_ScrollWindow($hWnd, 0, $yChar * ($yPos - $Pos))
		$yPos = $Pos
	EndIf

	Return $GUI_RUNDEFMSG

EndFunc   ;==>_Scrollbars_WM_VSCROLL

James

Share this post


Link to post
Share on other sites

Posted

james,

As far as I know Windows draws the scrollbars to fill the client area - which is what is happening here. :)

However, nothing is impossible: :(

#NoTrayIcon
#include <GUIConstantsEx.au3>
#include <WindowsConstants.au3>
#include <SendMessage.au3>
#include <Constants.au3>
#include <WinApi.au3>
#include <GUIScrollBars.au3>
#include <ScrollBarConstants.au3>

#include <GUIScrollbars_Size.au3>


Global Const $SC_DRAGMOVE = 0xF012
Opt("MouseCoordMode", 2)

Local $tMsg
Opt("TrayMenuMode", 1)

$frmMain = GUICreate("frmMain", 333, 421, -1, -1, $WS_POPUP, 0)
GUISetState(@SW_SHOW)
GUISetBkColor(0xe9eff5, $frmMain)

$frmBar = GUICreate("frmBar", 333, 20, -1, -1, $WS_POPUP, 0)
GUISetState(@SW_SHOW)

$aPos = WinGetPos($frmMain)
WinMove($frmBar, "", $aPos[0], $aPos[1] - 20)

GUIRegisterMsg($WM_MOVE, "StickTogether")

; Scrollbars
$aRet = _GUIScrollbars_Size(0, 500, 1, 441)
GUIRegisterMsg($WM_VSCROLL, "_Scrollbars_WM_VSCROLL")

_GUIScrollBars_Init($frmMain)
_GUIScrollBars_ShowScrollBar($frmMain, $SB_VERT, True)
_GUIScrollBars_ShowScrollBar($frmMain, $SB_HORZ, False)
_GUIScrollBars_SetScrollInfoPage($frmMain, $SB_VERT, $aRet[2])
_GUIScrollBars_SetScrollInfoMax($frmMain, $SB_VERT, $aRet[3])

$rgn = _WinAPI_CreateRoundRectRgn(0, 0, 333, 441, 3, 3)
_WinAPI_SetWindowRgn($frmMain, $rgn)
DrawBar()

While 1
    $tMsg = TrayGetMsg()
    Switch $tMsg
        Case $TRAY_EVENT_PRIMARYDOWN
            GUISetState(@SW_SHOW)
            DrawBar()
            WinSetState("frmMain", "", @SW_RESTORE)
            Opt("TrayIconHide", 1)
    EndSwitch

    $nMsg = GUIGetMsg()
    Switch $nMsg
        Case $GUI_EVENT_CLOSE
            Exit
        Case $GUI_EVENT_PRIMARYDOWN
            $mPos = MouseGetPos()
            If $mPos[1] <= 20 Then
                If $mPos[0] >= 295 And $mPos[0] <= 316 Then
                    GUISetState(@SW_HIDE)
                    Opt("TrayIconHide", 0)
                ElseIf $mPos[0] >= 313 And $mPos[0] <= 322 Then
                    Exit
                Else
                    _SendMessage($frmBar, $WM_SYSCOMMAND, $SC_DRAGMOVE, 0)
                EndIf
            EndIf
    EndSwitch
WEnd

Func StickTogether($hWnd, $iMsg, $wParam, $lParam)

	#forceref $iMsg, $wParam, $lParam

    Switch $hWnd
		Case $frmBar
			Local $aPos = WinGetPos($frmBar)
			WinMove($frmMain, "", $aPos[0], $aPos[1] + 20)
	EndSwitch

EndFunc

Func DrawBar()
    Local $aDim = WinGetClientSize($frmBar)
    Local $hDC = _WinAPI_GetDC($frmBar)
    ; Bar
    Local $hBrush = _WinAPI_CreateSolidBrush(0xf5d997) ; 0x97d9f5
    Local $hRect = DllStructCreate($tagRECT)
    DllStructSetData($hRect, "Left", 0)
    DllStructSetData($hRect, "Top", 0)
    DllStructSetData($hRect, "Right", $aDim[0])
    DllStructSetData($hRect, "Bottom", 20)
    _WinAPI_FillRect($hDC, DllStructGetPtr($hRect), $hBrush)
    _WinAPI_DeleteObject($hBrush)
    ; Bar text
    Local $sTitle = WinGetTitle($frmBar)
    Local $hBrush = _WinAPI_CreateSolidBrush(0x000000) ; 0xe9eff5
    DllStructSetData($hRect, "Left", 4)
    DllStructSetData($hRect, "Top", 2)
    DllStructSetData($hRect, "Right", $aDim[0] - 40)
    DllStructSetData($hRect, "Bottom", 20)
    _WinAPI_SetBkMode($hDC, $TRANSPARENT)
    _WinAPI_SetTextColor($hDC, 0xFFFFFF)
    _WinAPI_DrawText($hDC, $sTitle, $hRect, $DT_LEFT)
    _WinAPI_DeleteObject($hBrush)
    ; Minimize
    $hBrush = _WinAPI_CreateSolidBrush(0x000000)
    DllStructSetData($hRect, "Left", $aDim[0] - 37)
    DllStructSetData($hRect, "Top", 12)
    DllStructSetData($hRect, "Right", $aDim[0] - 28)
    DllStructSetData($hRect, "Bottom", 14)
    _WinAPI_FillRect($hDC, DllStructGetPtr($hRect), $hBrush)
    _WinAPI_DeleteObject($hBrush)
    ; Close
    Local $hPen = _WinAPI_CreatePen($PS_SOLID, 2, 0x000000)
    Local $hSelected = _WinAPI_SelectObject($hDC, $hPen)
    _WinAPI_DrawLine($hDC, $aDim[0] - 20, 5, $aDim[0] - 11, 14)
    _WinAPI_DrawLine($hDC, $aDim[0] - 20, 14, $aDim[0] - 11, 5)
    _WinAPI_SelectObject($hDC, $hSelected)
    _WinAPI_DeleteObject($hPen)
    $hBrush = _WinAPI_CreateSolidBrush(0xd8ded3)
    ; Frame Edge
    ;$hBrush = _WinAPI_CreateSolidBrush(0x000000)
    DllStructSetData($hRect, "Left", 0)
    DllStructSetData($hRect, "Top", 20)
    DllStructSetData($hRect, "Right", 1)
    DllStructSetData($hRect, "Bottom", 1)
    _WinAPI_FillRect($hDC, DllStructGetPtr($hRect), $hBrush)
    DllStructSetData($hRect, "Left", $aDim[0] - 2)
    DllStructSetData($hRect, "Top", 20)
    DllStructSetData($hRect, "Right", $aDim[0])
    DllStructSetData($hRect, "Bottom", $aDim[1])
    _WinAPI_FillRect($hDC, DllStructGetPtr($hRect), $hBrush)
    DllStructSetData($hRect, "Left", 0)
    DllStructSetData($hRect, "Top", 20)
    DllStructSetData($hRect, "Right", 1)
    DllStructSetData($hRect, "Bottom", $aDim[1])
    _WinAPI_FillRect($hDC, DllStructGetPtr($hRect), $hBrush)
    DllStructSetData($hRect, "Left", 0)
    DllStructSetData($hRect, "Top", $aDim[1] - 2)
    DllStructSetData($hRect, "Right", $aDim[0])
    DllStructSetData($hRect, "Bottom", $aDim[1])
    _WinAPI_FillRect($hDC, DllStructGetPtr($hRect), $hBrush)
    _WinAPI_DeleteObject($hBrush)
    _WinAPI_ReleaseDC($frmBar, $hDC)
    AdlibRegister("DrawBar")
EndFunc   ;==>DrawBar

Func _Scrollbars_WM_VSCROLL($hWnd, $Msg, $wParam, $lParam)

    #forceref $Msg, $wParam, $lParam
    Local $nScrollCode = BitAND($wParam, 0x0000FFFF)
    Local $iIndex = -1, $yChar, $yPos
    Local $Min, $Max, $Page, $Pos, $TrackPos

    For $x = 0 To UBound($aSB_WindowInfo) - 1
        If $aSB_WindowInfo[$x][0] = $hWnd Then
            $iIndex = $x
            $yChar = $aSB_WindowInfo[$iIndex][3]
            ExitLoop
        EndIf
    Next
    If $iIndex = -1 Then Return 0

    Local $tSCROLLINFO = _GUIScrollBars_GetScrollInfoEx($hWnd, $SB_VERT)
    $Min = DllStructGetData($tSCROLLINFO, "nMin")
    $Max = DllStructGetData($tSCROLLINFO, "nMax")
    $Page = DllStructGetData($tSCROLLINFO, "nPage")
    $yPos = DllStructGetData($tSCROLLINFO, "nPos")
    $Pos = $yPos
    $TrackPos = DllStructGetData($tSCROLLINFO, "nTrackPos")

    Switch $nScrollCode
        Case $SB_TOP
            DllStructSetData($tSCROLLINFO, "nPos", $Min)
        Case $SB_BOTTOM
            DllStructSetData($tSCROLLINFO, "nPos", $Max)
        Case $SB_LINEUP
            DllStructSetData($tSCROLLINFO, "nPos", $Pos - 1)
        Case $SB_LINEDOWN
            DllStructSetData($tSCROLLINFO, "nPos", $Pos + 1)
        Case $SB_PAGEUP
            DllStructSetData($tSCROLLINFO, "nPos", $Pos - $Page)
        Case $SB_PAGEDOWN
            DllStructSetData($tSCROLLINFO, "nPos", $Pos + $Page)
        Case $SB_THUMBTRACK
            DllStructSetData($tSCROLLINFO, "nPos", $TrackPos)
    EndSwitch

    DllStructSetData($tSCROLLINFO, "fMask", $SIF_POS)
    _GUIScrollBars_SetScrollInfo($hWnd, $SB_VERT, $tSCROLLINFO)
    _GUIScrollBars_GetScrollInfo($hWnd, $SB_VERT, $tSCROLLINFO)

    $Pos = DllStructGetData($tSCROLLINFO, "nPos")
    If ($Pos <> $yPos) Then
        _GUIScrollBars_ScrollWindow($hWnd, 0, $yChar * ($yPos - $Pos))
        $yPos = $Pos
    EndIf

    Return $GUI_RUNDEFMSG

EndFunc   ;==>_Scrollbars_WM_VSCROLL

You work out how I did it! :idea:

M23

P.S. There is some work to do still, I have only done the bare minimum. After all it is nothing to do with my UDF! :)

Share this post


Link to post
Share on other sites

Posted

Melba,

Hmm I see. It's a little bit of a dirty method, but I'll work on it.

James

Share this post


Link to post
Share on other sites

Posted

James,

"dirty"? :idea:

"Inspired lateral thinking" would be my preferred comment! :)

M23

Share this post


Link to post
Share on other sites

Posted

"Inspired lateral thinking" would be my preferred comment! :idea:

M23

Posted Image

Two windows, one for title bar and one for client area? What were you inspired by, crack? :)

James

Share this post


Link to post
Share on other sites

Posted

"Inspired lateral thinking" would be my preferred comment! :idea:

M23

Posted Image

Two windows, one for title bar and one for client area? What were you inspired by, crack? :)

James

Share this post


Link to post
Share on other sites

Posted

Any reason not to make the content window an MDI child (WS_EX_MDICHILD)? Then moving the window takes care of itself. Here's an example. You might have to play with the window placement slightly, but it looks pretty good.

#NoTrayIcon
#include <GUIConstantsEx.au3>
#include <WindowsConstants.au3>
#include <SendMessage.au3>
#include <Constants.au3>
#include <WinApi.au3>
#include <GUIScrollBars.au3>
#include <ScrollBarConstants.au3>

#include <GUIScrollbars_Size.au3>


Global Const $SC_DRAGMOVE = 0xF012
Opt("MouseCoordMode", 2)

Local $tMsg
Opt("TrayMenuMode", 1)

$frmBar = GUICreate("frmBar", 333, 441, -1, -1, $WS_POPUP, 0)
GUISetState(@SW_SHOW)

$frmMain = GUICreate("frmMain", 333, 421, 4, 24, $WS_POPUP, $WS_EX_MDICHILD, $frmBar)
GUISetState(@SW_SHOW)

; Scrollbars
$aRet = _GUIScrollbars_Size(0, 500, 1, 441)
GUIRegisterMsg($WM_VSCROLL, "_Scrollbars_WM_VSCROLL")

_GUIScrollBars_Init($frmMain)
_GUIScrollBars_ShowScrollBar($frmMain, $SB_VERT, True)
_GUIScrollBars_ShowScrollBar($frmMain, $SB_HORZ, False)
_GUIScrollBars_SetScrollInfoPage($frmMain, $SB_VERT, $aRet[2])
_GUIScrollBars_SetScrollInfoMax($frmMain, $SB_VERT, $aRet[3])

$rgn = _WinAPI_CreateRoundRectRgn(0, 0, 333, 441, 3, 3)
_WinAPI_SetWindowRgn($frmMain, $rgn)
DrawBar()

While 1
    $tMsg = TrayGetMsg()
    Switch $tMsg
        Case $TRAY_EVENT_PRIMARYDOWN
            GUISetState(@SW_SHOW, $frmBar)
            GUISetState(@SW_SHOW, $frmMain)
			WinActivate($frmBar)
            DrawBar()
            Opt("TrayIconHide", 1)
    EndSwitch

    $nMsg = GUIGetMsg(1)
    Switch $nMsg[1] ; window
		Case $frmBar
			Switch $nMsg[0] ; event ID
				Case $GUI_EVENT_CLOSE
					Exit
				Case $GUI_EVENT_PRIMARYDOWN
					If $nMsg[4] <= 20 Then
						If $nMsg[3] >= 295 And $nMsg[3] <= 316 Then
							GUISetState(@SW_HIDE, $frmMain)
							GUISetState(@SW_HIDE, $frmBar)
							Opt("TrayIconHide", 0)
						ElseIf $nMsg[3] >= 313 And $nMsg[3] <= 322 Then
							Exit
						Else
							_SendMessage($frmBar, $WM_SYSCOMMAND, $SC_DRAGMOVE, 0)
						EndIf
					EndIf
			EndSwitch
    EndSwitch
WEnd

Func DrawBar()
    Local $aDim = WinGetClientSize($frmBar)
    Local $hDC = _WinAPI_GetDC($frmBar)
    ; Bar
    Local $hBrush = _WinAPI_CreateSolidBrush(0xf5d997) ; 0x97d9f5
    Local $hRect = DllStructCreate($tagRECT)
    DllStructSetData($hRect, "Left", 0)
    DllStructSetData($hRect, "Top", 0)
    DllStructSetData($hRect, "Right", $aDim[0])
    DllStructSetData($hRect, "Bottom", 20)
    _WinAPI_FillRect($hDC, DllStructGetPtr($hRect), $hBrush)
    _WinAPI_DeleteObject($hBrush)
    ; Bar text
    Local $sTitle = WinGetTitle($frmBar)
    Local $hBrush = _WinAPI_CreateSolidBrush(0x000000) ; 0xe9eff5
    DllStructSetData($hRect, "Left", 4)
    DllStructSetData($hRect, "Top", 2)
    DllStructSetData($hRect, "Right", $aDim[0] - 40)
    DllStructSetData($hRect, "Bottom", 20)
    _WinAPI_SetBkMode($hDC, $TRANSPARENT)
    _WinAPI_SetTextColor($hDC, 0xFFFFFF)
    _WinAPI_DrawText($hDC, $sTitle, $hRect, $DT_LEFT)
    _WinAPI_DeleteObject($hBrush)
    ; Minimize
    $hBrush = _WinAPI_CreateSolidBrush(0x000000)
    DllStructSetData($hRect, "Left", $aDim[0] - 37)
    DllStructSetData($hRect, "Top", 12)
    DllStructSetData($hRect, "Right", $aDim[0] - 28)
    DllStructSetData($hRect, "Bottom", 14)
    _WinAPI_FillRect($hDC, DllStructGetPtr($hRect), $hBrush)
    _WinAPI_DeleteObject($hBrush)
    ; Close
    Local $hPen = _WinAPI_CreatePen($PS_SOLID, 2, 0x000000)
    Local $hSelected = _WinAPI_SelectObject($hDC, $hPen)
    _WinAPI_DrawLine($hDC, $aDim[0] - 20, 5, $aDim[0] - 11, 14)
    _WinAPI_DrawLine($hDC, $aDim[0] - 20, 14, $aDim[0] - 11, 5)
    _WinAPI_SelectObject($hDC, $hSelected)
    _WinAPI_DeleteObject($hPen)
    $hBrush = _WinAPI_CreateSolidBrush(0xd8ded3)
    ; Frame Edge
    ;$hBrush = _WinAPI_CreateSolidBrush(0x000000)
    DllStructSetData($hRect, "Left", 0)
    DllStructSetData($hRect, "Top", 20)
    DllStructSetData($hRect, "Right", 1)
    DllStructSetData($hRect, "Bottom", 1)
    _WinAPI_FillRect($hDC, DllStructGetPtr($hRect), $hBrush)
    DllStructSetData($hRect, "Left", $aDim[0] - 2)
    DllStructSetData($hRect, "Top", 20)
    DllStructSetData($hRect, "Right", $aDim[0])
    DllStructSetData($hRect, "Bottom", $aDim[1])
    _WinAPI_FillRect($hDC, DllStructGetPtr($hRect), $hBrush)
    DllStructSetData($hRect, "Left", 0)
    DllStructSetData($hRect, "Top", 20)
    DllStructSetData($hRect, "Right", 1)
    DllStructSetData($hRect, "Bottom", $aDim[1])
    _WinAPI_FillRect($hDC, DllStructGetPtr($hRect), $hBrush)
    DllStructSetData($hRect, "Left", 0)
    DllStructSetData($hRect, "Top", $aDim[1] - 2)
    DllStructSetData($hRect, "Right", $aDim[0])
    DllStructSetData($hRect, "Bottom", $aDim[1])
    _WinAPI_FillRect($hDC, DllStructGetPtr($hRect), $hBrush)
    _WinAPI_DeleteObject($hBrush)
    _WinAPI_ReleaseDC($frmBar, $hDC)
    AdlibRegister("DrawBar")
EndFunc   ;==>DrawBar

Func _Scrollbars_WM_VSCROLL($hWnd, $Msg, $wParam, $lParam)

    #forceref $Msg, $wParam, $lParam
    Local $nScrollCode = BitAND($wParam, 0x0000FFFF)
    Local $iIndex = -1, $yChar, $yPos
    Local $Min, $Max, $Page, $Pos, $TrackPos

    For $x = 0 To UBound($aSB_WindowInfo) - 1
        If $aSB_WindowInfo[$x][0] = $hWnd Then
            $iIndex = $x
            $yChar = $aSB_WindowInfo[$iIndex][3]
            ExitLoop
        EndIf
    Next
    If $iIndex = -1 Then Return 0

    Local $tSCROLLINFO = _GUIScrollBars_GetScrollInfoEx($hWnd, $SB_VERT)
    $Min = DllStructGetData($tSCROLLINFO, "nMin")
    $Max = DllStructGetData($tSCROLLINFO, "nMax")
    $Page = DllStructGetData($tSCROLLINFO, "nPage")
    $yPos = DllStructGetData($tSCROLLINFO, "nPos")
    $Pos = $yPos
    $TrackPos = DllStructGetData($tSCROLLINFO, "nTrackPos")

    Switch $nScrollCode
        Case $SB_TOP
            DllStructSetData($tSCROLLINFO, "nPos", $Min)
        Case $SB_BOTTOM
            DllStructSetData($tSCROLLINFO, "nPos", $Max)
        Case $SB_LINEUP
            DllStructSetData($tSCROLLINFO, "nPos", $Pos - 1)
        Case $SB_LINEDOWN
            DllStructSetData($tSCROLLINFO, "nPos", $Pos + 1)
        Case $SB_PAGEUP
            DllStructSetData($tSCROLLINFO, "nPos", $Pos - $Page)
        Case $SB_PAGEDOWN
            DllStructSetData($tSCROLLINFO, "nPos", $Pos + $Page)
        Case $SB_THUMBTRACK
            DllStructSetData($tSCROLLINFO, "nPos", $TrackPos)
    EndSwitch

    DllStructSetData($tSCROLLINFO, "fMask", $SIF_POS)
    _GUIScrollBars_SetScrollInfo($hWnd, $SB_VERT, $tSCROLLINFO)
    _GUIScrollBars_GetScrollInfo($hWnd, $SB_VERT, $tSCROLLINFO)

    $Pos = DllStructGetData($tSCROLLINFO, "nPos")
    If ($Pos <> $yPos) Then
        _GUIScrollBars_ScrollWindow($hWnd, 0, $yChar * ($yPos - $Pos))
        $yPos = $Pos
    EndIf

    Return $GUI_RUNDEFMSG

EndFunc   ;==>_Scrollbars_WM_VSCROLL

Share this post


Link to post
Share on other sites

Posted

wraithdu,

I like a multi-brain solution to a problem! :idea:

M23

Share this post


Link to post
Share on other sites

Posted

Posted Image

Two windows, one for title bar and one for client area? What were you inspired by, crack? :idea:

James

One of my favorite tricks for solving many GUI problems is to use multiple windows. It can save me having to create multiple controls for example and in some cases I even change the text for a button when a window is shown and then change it back when that Window is hidden and the original Child restored.

Share this post


Link to post
Share on other sites

Posted

MrCreatoR,

I have never been able to get my mouse to scroll an AutoIt scrollbar. And yes I have tried your MouseOnEvent UDF. :idea: Everything works except the scroll wheel.

So if you would like to work at it, be my guest. :)

M23

It's easy, you just add this to the UDF:

#include <SendMessage.au3>

....

GUIRegisterMsg($WM_MOUSEWHEEL, "WM_MOUSEWHEEL")

....

Func WM_MOUSEWHEEL($hWnd, $nMsg, $wParam, $lParam)
    Local $nKeys = BitAnd($wParam, 0x0000FFFF)
    Local $nDistance = BitShift($wParam, 16)
	
	If $nDistance > 0 Then
		_SendMessage($hWnd, $WM_VSCROLL, $SB_LINEUP, 0)
    Else
		_SendMessage($hWnd, $WM_VSCROLL, $SB_LINEDOWN, 0)
    EndIf
EndFunc

At least for the vertical scroll this is usefull.

Share this post


Link to post
Share on other sites

Posted

And this one will enable the horizontal scroll by holding Shift or Ctrl key:

Func _Scrollbars_WM_MOUSEWHEEL($hWnd, $nMsg, $wParam, $lParam)
    Local $nKeys = BitAND($wParam, 0x0000FFFF)
    Local $nDistance = BitShift($wParam, 16)
	
	If $nKeys = 0 Then
		If $nDistance > 0 Then
			_SendMessage($hWnd, $WM_VSCROLL, $SB_LINEUP, 0)
		Else
			_SendMessage($hWnd, $WM_VSCROLL, $SB_LINEDOWN, 0)
		EndIf
	Else
		If $nDistance > 0 Then
			_SendMessage($hWnd, $WM_HSCROLL, $SB_LINELEFT, 0)
		Else
			_SendMessage($hWnd, $WM_HSCROLL, $SB_LINERIGHT, 0)
		EndIf
	EndIf
EndFunc

Share this post


Link to post
Share on other sites

Posted

....

I have never been able to get my mouse to scroll an AutoIt scrollbar. ....

M23

Melba23,

You obviously have not try the script here.

Share this post


Link to post
Share on other sites

Posted (edited)

Malkey and MrCreatoR,

It actually works! :(

How did I miss that when I was searching? :)

Thanks a lot to both of you - I will work on a modified version later today! :)

M23

Edit: Just seen MrCreatorR's earlier posts and did not want him to feel left out. :idea:

Edited by Melba23

Share this post


Link to post
Share on other sites

Posted

Hi,

Here is a stand-alone script using a new version of the _GUIScrollbars_Generate function which incorporates mouse scroll wheel support - horizontal scrolling is either by the horizontal wheel or by pressing Ctrl or Shft and using the vertical wheel:

#include <GUIConstantsEx.au3>
#include <WindowsConstants.au3>
#include <GuiScrollBars.au3>
#include <ScrollBarConstants.au3>
#include <SendMessage.au3>

Global $aSB_WindowInfo[1][8]

$hGUI = GUICreate("Test", 400, 300)

For $i = 1 To 20
	For $j = 1 To 20
		GUICtrlCreateLabel(($i - 1) * 20 + $j, 10 + 85 * ($i - 1), 10 + 30 * ($j - 1), 75, 25)
	Next
Next

; Generate scrollbars
_GUIScrollbars_Generate($hGUI, 85 * 19 + 75, 30 * 19 + 25)

GUISetState()

While 1

	Switch GUIGetMsg()
		Case $GUI_EVENT_CLOSE
			Exit
	EndSwitch
WEnd

Func _GUIScrollbars_Generate($hWnd, $iH_Scroll = 0, $iV_Scroll = 0, $iH_Tight = 0, $iV_Tight = 0, $fBefore = False)

	; Check if valid window handle
	If Not IsHWnd($hWnd) Then Return SetError(1, 0, 0)
	If $aSB_WindowInfo[0][0] <> "" Then ReDim $aSB_WindowInfo[UBound($aSB_WindowInfo) + 1][8]

	; If no scroll sizes set, return error
	If $iH_Scroll = 0 And $iV_Scroll = 0 Then Return SetError(2, 0, 0)

	; Confirm Tight values
	If $iH_Tight <> 0 Then $iH_Tight = 1
	If $iV_Tight <> 0 Then $iV_Tight = 1

	; Create structs
	Local $tTEXTMETRIC = DllStructCreate($tagTEXTMETRIC)
	Local $tSCROLLINFO = DllStructCreate($tagSCROLLINFO)
	DllStructSetData($tSCROLLINFO, "cbSize", DllStructGetSize($tSCROLLINFO))
	Local $tRect = DllStructCreate($tagRECT)

	; Declare local variables
	Local $iIndex = UBound($aSB_WindowInfo) - 1
	Local $iError, $iExtended

	; Save window handle
	$aSB_WindowInfo[$iIndex][0] = $hWnd

	; Determine text size
	Local $hDC = DllCall("user32.dll", "handle", "GetDC", "hwnd", $hWnd)
	If Not @error Then
		$hDC = $hDC[0]
		DllCall("gdi32.dll", "bool", "GetTextMetricsW", "handle", $hDC, "ptr", DllStructGetPtr($tTEXTMETRIC))
		If @error Then
			$iError = @error
			$iExtended = @extended
			DllCall("user32.dll", "int", "ReleaseDC", "hwnd", $hWnd, "handle", $hDC)
			Return SetError($iError, $iExtended, -2)
		EndIf
		DllCall("user32.dll", "int", "ReleaseDC", "hwnd", $hWnd, "handle", $hDC)
	Else
		Return SetError(@error, @extended, -1)
	EndIf
	$aSB_WindowInfo[$iIndex][2] = DllStructGetData($tTEXTMETRIC, "tmAveCharWidth")
	$aSB_WindowInfo[$iIndex][3] = DllStructGetData($tTEXTMETRIC, "tmHeight") + DllStructGetData($tTEXTMETRIC, "tmExternalLeading")

	; Size aperture window without bars
	DllCall("user32.dll", "bool", "GetClientRect", "hwnd", $hWnd, "ptr", DllStructGetPtr($tRect))
	If @error Then Return SetError(@error, @extended, -3)
	Local $iX_Client_Full = DllStructGetData($tRect, "Right") - DllStructGetData($tRect, "Left")
	Local $iY_Client_Full = DllStructGetData($tRect, "Bottom") - DllStructGetData($tRect, "Top")
	$aSB_WindowInfo[$iIndex][4] = $iX_Client_Full
	$aSB_WindowInfo[$iIndex][5] = $iY_Client_Full

	; Register scrollbar and mousewheel messages
	GUIRegisterMsg($WM_VSCROLL, "_Scrollbars_WM_VSCROLL")
	GUIRegisterMsg($WM_HSCROLL, "_Scrollbars_WM_HSCROLL")
	GUIRegisterMsg($WM_MOUSEWHEEL, "_Scrollbars_WM_MOUSEWHEEL")
	GUIRegisterMsg($WM_MOUSEHWHEEL, '_Scrollbars_WM_MOUSEHWHEEL')

	; Show scrollbars
	_GUIScrollBars_ShowScrollBar($hWnd, $SB_BOTH, False)
	If $iH_Scroll Then _GUIScrollBars_ShowScrollBar($hWnd, $SB_HORZ)
	If $iV_Scroll Then _GUIScrollBars_ShowScrollBar($hWnd, $SB_VERT)

	; Size aperture window with bars
	DllCall("user32.dll", "bool", "GetClientRect", "hwnd", $hWnd, "ptr", DllStructGetPtr($tRect))
	If @error Then Return SetError(@error, @extended, -3)
	Local $iX_Client_Bar = DllStructGetData($tRect, "Right") - DllStructGetData($tRect, "Left")
	Local $iY_Client_Bar = DllStructGetData($tRect, "Bottom") - DllStructGetData($tRect, "Top")

	; If horizontal scrollbar is required
	Local $iH_FullPage
	If $iH_Scroll Then
		If $fBefore Then
			; Use actual aperture width
			$aSB_WindowInfo[$iIndex][4] = $iX_Client_Bar
			; Determine page size (aperture width / text width)
			$iH_FullPage = Floor($aSB_WindowInfo[$iIndex][4] / $aSB_WindowInfo[$iIndex][2])
			; Determine max size (scroll width / text width - tight)
			$aSB_WindowInfo[$iIndex][6] = Floor($iH_Scroll / $aSB_WindowInfo[$iIndex][2]) - $iH_Tight
		Else
			; Use reduced aperture width only if other scrollbar exists
			If $iV_Scroll Then $aSB_WindowInfo[$iIndex][4] = $iX_Client_Bar
			; Determine page size (aperture width / text width)
			$iH_FullPage = Floor($aSB_WindowInfo[$iIndex][4] / $aSB_WindowInfo[$iIndex][2])
			; Determine max size (scroll width / text width * correction factor for V scrollbar if required - tight)
			$aSB_WindowInfo[$iIndex][6] = Floor($iH_Scroll / $aSB_WindowInfo[$iIndex][2] * $aSB_WindowInfo[$iIndex][4] / $iX_Client_Full) - $iH_Tight
		EndIf
	Else
		$aSB_WindowInfo[$iIndex][6] = 0
	EndIf

	; If vertical scrollbar required
	Local $iV_FullPage
	If $iV_Scroll Then
		If $fBefore Then
			; Use actual aperture height
			$aSB_WindowInfo[$iIndex][5] = $iY_Client_Bar
			; Determine page size (aperture width / text width)
			$iV_FullPage = Floor($aSB_WindowInfo[$iIndex][5] / $aSB_WindowInfo[$iIndex][3])
			; Determine max size (scroll width / text width - tight)
			$aSB_WindowInfo[$iIndex][7] = Floor($iV_Scroll / $aSB_WindowInfo[$iIndex][3]) - $iV_Tight
		Else
			; Use reduced aperture width only if other scrollbar exists
			If $iH_Scroll Then $aSB_WindowInfo[$iIndex][5] = $iY_Client_Bar
			; Determine page size (aperture width / text width)
			$iV_FullPage = Floor($aSB_WindowInfo[$iIndex][5] / $aSB_WindowInfo[$iIndex][3])
			; Determine max size (scroll width / text width * correction factor for H scrollbar if required - tight)
			$aSB_WindowInfo[$iIndex][7] = Floor($iV_Scroll / $aSB_WindowInfo[$iIndex][3] * $aSB_WindowInfo[$iIndex][5] / $iY_Client_Full) - $iV_Tight
		EndIf
	Else
		$aSB_WindowInfo[$iIndex][7] = 0
	EndIf

	Local $aRet[4]
	If $iV_Scroll Then
		$aRet[0] = $iX_Client_Bar
	Else
		$aRet[0] = $iX_Client_Full
	EndIf
	If $iH_Scroll Then
		$aRet[1] = $iY_Client_Bar
	Else
		$aRet[1] = $iY_Client_Full
	EndIf
	$aRet[2] = $iX_Client_Bar / $iX_Client_Full
	$aRet[3] = $iY_Client_Bar / $iY_Client_Full

	Local $fSuccess = True
	If _GUIScrollBars_ShowScrollBar($hWnd, $SB_BOTH, False) = False Then $fSuccess = False
	If $iH_Scroll Then
		If _GUIScrollBars_SetScrollInfoMax($hWnd, $SB_HORZ, $aSB_WindowInfo[$iIndex][6]) = False Then $fSuccess = False
		_GUIScrollBars_SetScrollInfoPage($hWnd, $SB_HORZ, $iH_FullPage)
		If @error Then $fSuccess = False
		If _GUIScrollBars_ShowScrollBar($hWnd, $SB_HORZ, True) = False Then $fSuccess = False
	Else
		If _GUIScrollBars_ShowScrollBar($hWnd, $SB_HORZ, False) = False Then $fSuccess = False
	EndIf
	If $iV_Scroll Then
		If _GUIScrollBars_SetScrollInfoMax($hWnd, $SB_VERT, $aSB_WindowInfo[$iIndex][7]) = False Then $fSuccess = False
		_GUIScrollBars_SetScrollInfoPage($hWnd, $SB_VERT, $iV_FullPage)
		If @error Then $fSuccess = False
		If _GUIScrollBars_ShowScrollBar($hWnd, $SB_VERT, True) = False Then $fSuccess = False
	Else
		If _GUIScrollBars_ShowScrollBar($hWnd, $SB_VERT, False) = False Then $fSuccess = False
	EndIf

	If $fSuccess Then Return $aRet
	Return SetError(3, 0, 0)

EndFunc   ;==>_GUIScrollbars_Generate

Func _Scrollbars_WM_VSCROLL($hWnd, $Msg, $wParam, $lParam)

	#forceref $Msg, $wParam, $lParam
	Local $nScrollCode = BitAND($wParam, 0x0000FFFF)
	Local $iIndex = -1, $yChar, $yPos
	Local $Min, $Max, $Page, $Pos, $TrackPos

	For $x = 0 To UBound($aSB_WindowInfo) - 1
		If $aSB_WindowInfo[$x][0] = $hWnd Then
			$iIndex = $x
			$yChar = $aSB_WindowInfo[$iIndex][3]
			ExitLoop
		EndIf
	Next
	If $iIndex = -1 Then Return 0

	Local $tSCROLLINFO = _GUIScrollBars_GetScrollInfoEx($hWnd, $SB_VERT)
	$Min = DllStructGetData($tSCROLLINFO, "nMin")
	$Max = DllStructGetData($tSCROLLINFO, "nMax")
	$Page = DllStructGetData($tSCROLLINFO, "nPage")
	$yPos = DllStructGetData($tSCROLLINFO, "nPos")
	$Pos = $yPos
	$TrackPos = DllStructGetData($tSCROLLINFO, "nTrackPos")

	Switch $nScrollCode
		Case $SB_TOP
			DllStructSetData($tSCROLLINFO, "nPos", $Min)
		Case $SB_BOTTOM
			DllStructSetData($tSCROLLINFO, "nPos", $Max)
		Case $SB_LINEUP
			DllStructSetData($tSCROLLINFO, "nPos", $Pos - 1)
		Case $SB_LINEDOWN
			DllStructSetData($tSCROLLINFO, "nPos", $Pos + 1)
		Case $SB_PAGEUP
			DllStructSetData($tSCROLLINFO, "nPos", $Pos - $Page)
		Case $SB_PAGEDOWN
			DllStructSetData($tSCROLLINFO, "nPos", $Pos + $Page)
		Case $SB_THUMBTRACK
			DllStructSetData($tSCROLLINFO, "nPos", $TrackPos)
	EndSwitch

	DllStructSetData($tSCROLLINFO, "fMask", $SIF_POS)
	_GUIScrollBars_SetScrollInfo($hWnd, $SB_VERT, $tSCROLLINFO)
	_GUIScrollBars_GetScrollInfo($hWnd, $SB_VERT, $tSCROLLINFO)

	$Pos = DllStructGetData($tSCROLLINFO, "nPos")
	If ($Pos <> $yPos) Then
		_GUIScrollBars_ScrollWindow($hWnd, 0, $yChar * ($yPos - $Pos))
		$yPos = $Pos
	EndIf

	Return $GUI_RUNDEFMSG

EndFunc   ;==>_Scrollbars_WM_VSCROLL

Func _Scrollbars_WM_HSCROLL($hWnd, $Msg, $wParam, $lParam)

	#forceref $Msg, $lParam
	Local $nScrollCode = BitAND($wParam, 0x0000FFFF)
	Local $iIndex = -1, $xChar, $xPos
	Local $Page, $Pos, $TrackPos

	For $x = 0 To UBound($aSB_WindowInfo) - 1
		If $aSB_WindowInfo[$x][0] = $hWnd Then
			$iIndex = $x
			$xChar = $aSB_WindowInfo[$iIndex][2]
			ExitLoop
		EndIf
	Next
	If $iIndex = -1 Then Return 0

	Local $tSCROLLINFO = _GUIScrollBars_GetScrollInfoEx($hWnd, $SB_HORZ)
	$Page = DllStructGetData($tSCROLLINFO, "nPage")
	$xPos = DllStructGetData($tSCROLLINFO, "nPos")
	$Pos = $xPos
	$TrackPos = DllStructGetData($tSCROLLINFO, "nTrackPos")
	Switch $nScrollCode
		Case $SB_LINELEFT
			DllStructSetData($tSCROLLINFO, "nPos", $Pos - 1)
		Case $SB_LINERIGHT
			DllStructSetData($tSCROLLINFO, "nPos", $Pos + 1)
		Case $SB_PAGELEFT
			DllStructSetData($tSCROLLINFO, "nPos", $Pos - $Page)
		Case $SB_PAGERIGHT
			DllStructSetData($tSCROLLINFO, "nPos", $Pos + $Page)
		Case $SB_THUMBTRACK
			DllStructSetData($tSCROLLINFO, "nPos", $TrackPos)
	EndSwitch

	DllStructSetData($tSCROLLINFO, "fMask", $SIF_POS)
	_GUIScrollBars_SetScrollInfo($hWnd, $SB_HORZ, $tSCROLLINFO)
	_GUIScrollBars_GetScrollInfo($hWnd, $SB_HORZ, $tSCROLLINFO)

	$Pos = DllStructGetData($tSCROLLINFO, "nPos")
	If ($Pos <> $xPos) Then _GUIScrollBars_ScrollWindow($hWnd, $xChar * ($xPos - $Pos), 0)

	Return $GUI_RUNDEFMSG

EndFunc   ;==>_Scrollbars_WM_HSCROLL

Func _Scrollbars_WM_MOUSEWHEEL($hWnd, $iMsg, $wParam, $lParam)

	Local $iDirn, $iDelta = BitShift($wParam, 16)

	If BitAND($wParam, 0x0000FFFF) Then ; If Ctrl or Shft pressed move Horz scrollbar
		$iDirn = $SB_LINERIGHT
		If $iDelta > 0 Then $iDirn = $SB_LINELEFT
		For $i = 1 To 10
			_SendMessage($hWnd, $WM_HSCROLL, $iDirn)
		Next
	Else ; Move Vert scrollbar
		$iDirn = $SB_LINEDOWN
		If $iDelta > 0 Then $iDirn = $SB_LINEUP
		_SendMessage($hWnd, $WM_VSCROLL, $iDirn)
	EndIf

	Return $GUI_RUNDEFMSG

EndFunc   ;==>_Scrollbars_WM_MOUSEWHEEL

Func _Scrollbars_WM_MOUSEHWHEEL($hWnd, $iMsg, $wParam, $lParam)

	Local $iDirn, $iDelta = BitShift($wParam, 16)

	Local $iDirn = $SB_LINERIGHT
	If $iDelta > 0 Then $iDirn = $SB_LINELEFT
	For $i = 1 To 10
		_SendMessage($hWnd, $WM_HSCROLL, $iDirn)
	Next

	Return $GUI_RUNDEFMSG

EndFunc   ;==>_Scrollbars_WM_MOUSEHWHEEL

It works well on my machine using the vertical wheel, but I do not have a horizontal wheel on my mouse to test. So before I release the new version of the UDF to the wider community, could some kind soul please test this stand-alone version and confirm that it does work with a horizontal wheel (and in the correct sense! :) )

Thanks in advance, :idea:

M23

Share this post


Link to post
Share on other sites

Posted

Fantastic Job!Awesome!Gold! :idea:

BTW i like GUIScrollbars_Ex.au3 :)

Thank you very-very much Melba23.

Share this post


Link to post
Share on other sites

Posted

Mouse wheel scrolling now incorporated. Mythanks to MrCreatoR and Malkey for the pointers. :idea:

See first post for new script and zip.

M23

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!


Register a new account

Sign in

Already have an account? Sign in here.


Sign In Now