Class TransparentListBox

Post your working scripts, libraries and tools for AHK v1.1 and older
just me
Posts: 9424
Joined: 02 Oct 2013, 08:51
Location: Germany

Class TransparentListBox

03 Oct 2013, 00:33

Update on 2015-01-17:
  • Added ability for scrolling by keys without having a vertical scroll bar.
  • Moved scripts to GitHub.
Update on 2013-10-05:
  • Added options to choose a background color for the selected item(s) and the transparency of this color.
  • Added scripts to the posting since we have spoilers now (THX).

Well, my first and exclusive contribution to the new forums.

I started to write this script by reason of this request. Another request can be found here. Both are pointing to the same example on CodeProject using an owner drawn ListBox.

When trying to port the code to AHK, I didn't find any advantage using the LBS_OWNERDRAWFIXED style. The whole painting has to be done by subclassing the control with AHK, so 'owner drawing' has to be done in either case.

This is what I've got so far. Sometimes you may notice some flickering. I didn't find a way to suppress all of it. Just a few other restrictions are documented in the class header.

:arrow: View sources on GitHub
:arrow: Download sources from GitHub
Last edited by just me on 17 Jan 2015, 04:20, edited 4 times in total.
tmplinshi
Posts: 1604
Joined: 01 Oct 2013, 14:57

Re: Class TransparentListBox

03 Oct 2013, 05:38

Thanks. Will use it someday. :)
Verdlin
Posts: 63
Joined: 04 Oct 2013, 08:55
Contact:

Re: Class TransparentListBox

04 Oct 2013, 09:28

Not much to say besides this looks great! The current limitations, such as no smooth scrolling, is not a big deal to me. I'm going to start changing my current scripts to use this, such as CFlyout (which hasn't been ported to the new forum as of yet).

One comment/question. Depending on the background picture, it can be difficult to easily spot which item is selected. Is is feasible to give an option to set the selected text background color? I messed with this idea a little bit, and it was easy enough to set the background color for the selected text. The two problems I couldn't fix were:

1. Partial transparency for background color. I don't even know of something like that is possible, and maybe it isn't a big deal. I just wanted to see how it would look.
2. Background color needs to be drawn over the entire width of the ListBox, not the selected text.
just me
Posts: 9424
Joined: 02 Oct 2013, 08:51
Location: Germany

Re: Class TransparentListBox

05 Oct 2013, 03:38

Verdlin wrote: 1. Partial transparency for background color. I don't even know of something like that is possible, and maybe it isn't a big deal. I just wanted to see how it would look.
2. Background color needs to be drawn over the entire width of the ListBox, not the selected text.
Well, I tried my best. I've updated the first post, give it a try. ;)
tmplinshi
Posts: 1604
Joined: 01 Oct 2013, 14:57

Re: Class TransparentListBox

05 Oct 2013, 08:03

Thanks, just me! I like the background color.

Image
Guest10
Posts: 578
Joined: 01 Oct 2013, 02:50

Re: Class TransparentListBox

06 Oct 2013, 05:18

when i run, it complains about this line in Class_TransparentListBox.ahk: :lol:
This.Items := StrSplit(Content, "`n")
Guest10
Posts: 578
Joined: 01 Oct 2013, 02:50

Re: Class TransparentListBox

06 Oct 2013, 05:40

added this and seems it took care of the prob. :lol:

Code: Select all

StrSplit(ByRef InputVar, Delimiters="", OmitChars="")

{

   o := []

   Loop, Parse, InputVar, % Delimiters, % OmitChars

      o.Insert(A_LoopField)

   return o

}
Guest10
Posts: 578
Joined: 01 Oct 2013, 02:50

Re: Class TransparentListBox

06 Oct 2013, 05:53

where should i add code and how so that when i select a number (Five, for example) for content from the list, then i can run some action?: :lol:
if content = Five
then
run, some action
Guest10
Posts: 578
Joined: 01 Oct 2013, 02:50

Re: Class TransparentListBox

06 Oct 2013, 06:32

is this how i should do this: :lol:
Selection:
GuiControlGet, LB
ToolTip, Selected: %LB%`nA_GuiEvent: %A_GuiEvent%`nA_EventInfo: %A_EventInfo%
SetTimer, KillTT, -750


If (LB == "Five")
MsgBox, Run Something...
just me
Posts: 9424
Joined: 02 Oct 2013, 08:51
Location: Germany

Re: Class TransparentListBox

06 Oct 2013, 07:11

Yes, the g-Label is working as for common ListBox controls.
Verdlin
Posts: 63
Joined: 04 Oct 2013, 08:55
Contact:

Re: Class TransparentListBox

07 Oct 2013, 15:23

just me wrote:
Verdlin wrote: 1. Partial transparency for background color. I don't even know of something like that is possible, and maybe it isn't a big deal. I just wanted to see how it would look.
2. Background color needs to be drawn over the entire width of the ListBox, not the selected text.
Well, I tried my best. I've updated the first post, give it a try. ;)
Oh-ho, yes! This is awesome.
Verdlin
Posts: 63
Joined: 04 Oct 2013, 08:55
Contact:

Re: Class TransparentListBox

15 Oct 2013, 21:11

I've been wondering about the possibility of wrapping items in the ListBox. Since the class handles drawing, isn't this pretty doable?
just me
Posts: 9424
Joined: 02 Oct 2013, 08:51
Location: Germany

Re: Class TransparentListBox

16 Oct 2013, 06:59

It should be feasible, but not with this class. You have to set the the LBS_OWNERDRAWVARIABLE style and to processs the WM_MEASUREITEM and WM_DRAWITEM messages.
just me
Posts: 9424
Joined: 02 Oct 2013, 08:51
Location: Germany

Re: Class TransparentListBox

17 Jan 2015, 04:15

Update on 2015-01-17 because of this request.
Verdlin
Posts: 63
Joined: 04 Oct 2013, 08:55
Contact:

Re: Class TransparentListBox

11 May 2016, 05:05

So happy to see the scrolling update! I had been spending a lot of time trying to make that work and didn't think to check for an update until now :)

Sometime the border around the ListBox doesn't get redrawn (until MouseOver) happens. I fixed this bug by adding the code below right before "Return 0" in bloc that processes WM.Paint

; Must redraw rectangle around list box.
SendMessage, WM_NCPAINT:=133, 0, 0,, ahk_id %hWnd%
Verdlin
Posts: 63
Joined: 04 Oct 2013, 08:55
Contact:

Re: Class TransparentListBox

13 May 2016, 06:15

I would also recommend putting this at the beginning of WM.Paint right before the call to BitBlt

Code: Select all

	; Update this.width and this.height in case a scrollbar was added or removed.
	VarSetCapacity(RECT, 16, 0)
	DllCall("User32.dll\GetClientRect", "Ptr", This.HLB, "Ptr", &RECT)
	This.Width := W := NumGet(RECT, 8, "Int")
	This.Height := H := NumGet(RECT, 12, "Int")
just me
Posts: 9424
Joined: 02 Oct 2013, 08:51
Location: Germany

Re: Class TransparentListBox

13 May 2016, 09:37

Hello Verdlin,

thanks for your suggestions. I'm working on it. The original design of the class was rather 'static'. So there might be more issues.
carno
Posts: 265
Joined: 20 Jun 2014, 16:48

Re: Class TransparentListBox

13 May 2016, 12:45

Wow! Beautiful.
just me
Posts: 9424
Joined: 02 Oct 2013, 08:51
Location: Germany

Re: Class TransparentListBox

16 May 2016, 04:18

Hello Verdlin,

I revised the class code trying to make it faster and maybe fixed a bug in SetRedraw(). Would you please test whether the non-client drawing issues still happen?

Code: Select all

; ==================================================================================================================================
; Namespace:      TransparentListBox
; Function:       Helper object for transparent ListBoxes
; Tested with:    AHK 1.1.19.01 (A32/U32/U64)
; Tested on:      Win 8.1 (x64)
; Version:        0.1.00.00/2013-10-03/just me - Initial release.
;                 0.1.01.00/2015-01-17/just me - Added scrolling by keys without a vertical scroll bar.
; ==================================================================================================================================
; CLASS TransparentListBox
;
; The class provides transparent background for ListBox controls. The whole stuff is done by subclassing the control.
;
; On creation via 'TLB := New TranparentListBox' you have to pass the HWNDs of the ListBox and the underlying control
; or window. Additionally you may pass a text color and a seperate color to draw selected items with. Colors have to
; be passed as RGB integer values.
;
; After you've changed the content or size of the ListBox, or if you want to change the text or selection color, you
; have to call 'TLB.Update()' once, passing the new color values if desired. Thw whole action should be enclosed by
; two calls of 'TLB.SetRedraw(False/True)' to avoid flickering as far as possible.
;
; Due to the complex way ListBoxes do their scrolling not all options of a common ListBox are supported.
; You have to keep in mind the following restrictions:
; - The new object instance has to be created before the Gui is shown.
; - The ListBox must not have a horizontal scroll bar (because I haven't a clue how to do the scrolling).
; - The Multi(select) option is not supported as yet (but it may be feasible).
; - Scrolling is not 'smooth'.
; ==================================================================================================================================
; Lib compatible function
; ==================================================================================================================================
TransparentListBox_Create(HLB, HBG, TxtColor := "", SelColor := "", SelBkGnd := "", SelBkTrans := 255) {
   Return New TransparentListBox(HLB, HBG, TxtColor, SelColor, SelBkGnd, SelBkTrans)
}
; ==================================================================================================================================
; Class
; ==================================================================================================================================
Class TransparentListBox {
   ; ===============================================================================================================================
   ; Constructor
   ; ===============================================================================================================================
   __New(HLB, HBG, TxtColor := "", SelColor := "", SelBkGnd := "", SelBkTrans := 255) {
      ; ----------------------------------------------------------------------------------------------------------------
      ; HLB        : HWND of the ListBox.
      ; HBG        : HWND of the control or Gui containing the background.
      ; TxtColor   : Optional - Text color (RGB integer value, e.g. 0xRRGGBB).
      ; SelColor   : Optional - Selected text color (RGB integer value, e.g. 0xRRGGBB).
      ; SelBkGnd   : Optional - Color of the selection rectangel (RGB integer value, e.g. 0xRRGGBB).
      ; SelBkTrans : Optional - Transparency of the selection rectangle (0 - 255).
      ; ----------------------------------------------------------------------------------------------------------------
      This.HLB := HLB
      This.HBG := HBG
      This.Parent := DllCall("GetParent", "Ptr", HLB, "UPtr")
      This.CtrlID := DllCall("GetDlgCtrlID", "Ptr", HLB, "UPtr")
      HDC := DllCall("GetDC", "Ptr", HLB, "UPtr")
      If (TxtColor <> "")
         This.TxtColor := ((TxtColor >> 16) & 0xFF) | (TxtColor & 0x00FF00) | ((TxtColor & 0xFF) << 16)
      Else
         This.TxtColor := DllCall("GetTextColor", "Ptr", HDC, "UInt")
      If (SelColor <> "")
         This.SelColor := ((SelColor >> 16) & 0xFF) | (SelColor & 0x00FF00) | ((SelColor & 0xFF) << 16)
      If (SelBkGnd <> "") {
         This.SelBkGnd := ((SelBkGnd >> 16) & 0xFF) | (SelBkGnd & 0x00FF00) | ((SelBkGnd & 0xFF) << 16)
         This.SelBkTrans := (SelBkTrans & 0xFF)
      }
      DllCall("ReleaseDC", "Ptr", HLB, "Ptr", HDC)
      VarSetCapacity(RECT, 16, 0)
      DllCall("SendMessage", "Ptr", HLB, "UInt", 0x0198, "Ptr", 0, "Ptr", &RECT) ; LB_GETITEMRECT
      This.ItemWidth := NumGet(RECT, 8, "Int") - NumGet(RECT, 0, "Int")
      This.ItemHeight := NumGet(RECT, 12, "Int") - NumGet(RECT, 4, "Int")
      This.ItemCount := DllCall("SendMessage", "Ptr", HLB, "UInt", 0x018B, "Ptr", 0, "Ptr", 0, "Int") ; LB_GETCOUNT
      This.Font := DllCall("SendMessage", "Ptr", HLB, "UInt", 0x0031, "Ptr", 0, "Ptr", 0, "UPtr") ; WM_GETFONT
      ControlGet, Content, List, , , ahk_id %HLB%
      This.Items := StrSplit(Content, "`n")
      This.HasBackground := False
      This.TopIndex := This.CurSel := -1
      This.Drawing := True
      ControlGet, Styles, Style, , , ahk_id %HLB%
      If (Styles & 0x00200000) { ; WS_VSCROLL -> the lisbox has a vertical scroll bar
         VarSetCapacity(SI, 28, 0) ; SCROLLINFO
         NumPut(28, SI, 0, "UInt") ; cbSize
         NumPut(3, SI, 4, "UInt")  ; fMask = SIF_RANGE | SIF_PAGE
         DllCall("GetScrollInfo", "Ptr", HLB, "Int", 1, "Ptr", &SI)
         This.SIMin := NumGet(SI, 8, "Int")    ; nMin
         This.SIMax := NumGet(SI, 12, "Int")   ; nMax
         This.SIPage := NumGet(SI, 16, "UInt") ; nPage
      }
      Else {
         DllCall("GetClientRect", "Ptr", HLB, "Ptr", &RECT)
         This.SIMin := 0
         This.SIPage := NumGet(RECT, 12, "Int") // This.ItemHeight
         This.SIMax := This.ItemCount - 1
      }
      SCCB := RegisterCallback("TransparentListBox.SubClassCallback")
      DllCall("SetWindowSubclass", "Ptr", HLB, "Ptr", SCCB, "Ptr", HLB, "Ptr", &This)
      This.SCCB := SCCB
   }
   ; ===============================================================================================================================
   ; Destructor
   ; ===============================================================================================================================
   __Delete() {
      If (This.BMPDC) {
         BGDC := DllCall("GetDC", "Ptr", This.HBG, "UPtr")
         DllCall("BitBlt", "Ptr", BGDC, "Int", This.Left, "Int", This.Top, "Int", This.Width, "Int", This.Height, "Ptr", This.BMPDC, "Int", 0, "Int", 0, "UInt", 0x00CC0020)
         DllCall("ReleaseDC", "Ptr", This.HBG, "Ptr", BGDC)
         DllCall("DeleteDC", "Ptr", This.BMPDC)
         DllCall("DeleteObject", "Ptr", This.HBMP)
         This.BMPDC := This.HBMP := 0
      }
      If (This.SELDC) {
         DllCall("DeleteDC", "Ptr", This.SELDC)
         DllCall("DeleteObject", "Ptr", This.HSEL)
      }
      If (This.HLB) {
         DllCall("RemoveWindowSubclass", "Ptr", This.HLB, "Ptr", This.SCCB, "Ptr", This.HLB)
      }
   }
   ; ===============================================================================================================================
   ; Update the instance variables
   ; ===============================================================================================================================
   UpDate(TxtColor := "", SelColor := "", SelBkGnd := "", SelBkTrans := "") {
      ; ----------------------------------------------------------------------------------------------------------------
      ; Optional TxtColor : New text color (RGB integer value, e.g. 0xRRGGBB).
      ; Optional SelColor : New selected text color (RGB integer value, e.g. 0xRRGGBB).
      ; Changes of the content or the size of the ListBox will be processed automatically.
      ; ----------------------------------------------------------------------------------------------------------------
      Drawing := This.Drawing
      If (Drawing)
         This.SetRedraw(False)
      This.__Delete()
      If (TxtColor = "")
         If (This.TxtColor)
            TxtColor := ((This.TxtColor >> 16) & 0xFF) | (This.TxtColor & 0x00FF00) | ((This.TxtColor & 0xFF) << 16)
      If (SelColor = "")
         If (This.SelColor)
            SelColor := ((This.SelColor >> 16) & 0xFF) | (This.SelColor & 0x00FF00) | ((This.SelColor & 0xFF) << 16)
      If (SelBkGnd = "")
         If (This.SelBkGnd)
            SelBkGnd := ((This.SelBkGnd >> 16) & 0xFF) | (This.SelBkGnd & 0x00FF00) | ((This.SelBkGnd & 0xFF) << 16)
      If (SelBkTrans = "")
         If (This.SelBkTrans)
            SelBkTrans := This.SelBkTrans
      This.__New(This.HLB, This.HBG, TxtColor, SelColor, SelBkGnd, SelBkTrans)
      If (Drawing)
         This.SetRedraw(True)
      Return True
   }
   ; ===============================================================================================================================
   ; Set Redrawing True/False
   ; ===============================================================================================================================
   SetRedraw(Mode) {
      ; It's highly recommended to call this function instead of using GuiControl, -/+Redraw,
      ; because the drawing state will be stored internally for use by other methods.
      Mode := !!Mode
      This.Drawing := Mode
      DllCall("SendMessage", "Ptr", This.HLB, "UInt", 0x000B, "Ptr", Mode, "Ptr", 0) ; WM_SETREDRAW
      If (Mode)
         WinSet, Redraw, , % "ahk_id " . This.HLB
      Return True
   }
   ; ===============================================================================================================================
   ; Methods for internal use
   ; ===============================================================================================================================
   ; Subclass callback function - for internal use only ----------------------------------------------------------------------------
   SubClassCallback(uMsg, wParam, lParam, IdSubclass, RefData) {
      Critical 100
      hWnd := This ; first parameter 'hWnd' is passed as 'This'
      Return Object(RefData).SubClassProc(hWnd, uMsg, wParam, lParam)
   }
   ; Subclassproc - for internal use only ------------------------------------------------------------------------------------------
   SubClassProc(hWnd, uMsg, wParam, lParam) {
      Static LB := {GETCOUNT: 0x018B, GETCURSEL: 0x0188, GETITEMRECT: 0x0198, GETTEXT: 0x0189,GETTEXTLEN: 0x018A
                  , GETTOPINDEX: 0x018E, ITEMFROMPOINT: 0x01A9, SETCURSEL: 0x0186}
      Static LBN := {SELCHANGE: 1, DBLCLK: 2}
      Static WM := {DESTROY: 0x0002, DRAWITEM: 0x002B, LBUTTONDBLCLK: 0x0203, ERASEBKGND: 0x0014, HSCROLL: 0x0114
                  , KEYDOWN: 0x0100, KILLFOCUS: 0x0008, LBUTTONDOWN: 0x0201, LBUTTONUP: 0x0202, MOUSEWHEEL: 0x020A
                  , PAINT: 0x000F, SETFOCUS: 0x0007, SETREDRAW: 0x000B, VSCROLL: 0x0115}
      Static VK := {DOWN: 0x28, END: 0x23, HOME: 0x24, NEXT: 0x22, PRIOR: 0x21, UP: 0x26
                  , 0x21: 1, 0x22: 1, 0x23: 1, 0x24: 1, 0x26: 1, 0x28: 1}
      Static DrawingMsg := ""
      ; ----------------------------------------------------------------------------------------------------------------------------
      ; Painting
      ; ----------------------------------------------------------------------------------------------------------------------------
      ; WM_PAINT message -----------------------------------------------------------------------------------------------------------
      If (uMsg = 0x000F) {
         VarSetCapacity(PAINTSTRUCT, A_PtrSize + (4 * 7) + 32 + (A_PtrSize - 4), 0)
         , LBDC := DllCall("BeginPaint", "Ptr", This.HLB, "Ptr", &PAINTSTRUCT, "UPtr")
         , This.Cursel := CurSel := DllCall("SendMessage", "Ptr", hWnd, "UInt", 0x0188, "Ptr", 0, "Ptr", 0, "Int") ; LB_GETCURSEL
         , This.TopIndex := TopIndex := DllCall("SendMessage", "Ptr", hWnd, "UInt", 0x018E, "Ptr", 0, "Ptr", 0, "Int") ; LB_GETTOPINDEX
         , DllCall("BitBlt", "Ptr", LBDC, "Int", 0, "Int", 0, "Int", This.Width, "Int", This.Height, "Ptr", This.BMPDC, "Int", 0, "Int", 0, "UInt", 0x00CC0020)
         , HFONT := DllCall("SelectObject", "Ptr", LBDC, "Ptr", This.Font, "UPtr")
         , DllCall("SetBkMode", "Ptr", LBDC, "Int", 1) ; TRANSPARENT
         , VarSetCapacity(RECT, 16, 0)
         , DllCall("GetClientRect", "Ptr", This.HLB, "Ptr", &RECT)
         , This.Width := NumGet(RECT, 8, "Int")
         , This.Height := NumGet(RECT, 12, "Int")
         , DllCall("SendMessage", "Ptr", hWnd, "UInt", 0x0198, "Ptr", TopIndex, "Ptr", &RECT) ; LB_GETITEMRECT
         , SELDC := This.SELDC
         , ItemCount := This.ItemCount
         , Height := This.Height
         While (TopIndex < ItemCount) && (NumGet(RECT, 12, "Int") <= Height) {
            If (SELDC) && (TopIndex = CurSel) {
               L := NumGet(RECT, 0, "Int"), T := NumGet(RECT, 4, "Int")
               , W := NumGet(RECT, 8, "Int") - L, H := NumGet(RECT, 12, "Int") - T
               If ((BkTrans := This.SelBkTrans) = 255)
                  DllCall("BitBlt", "Ptr", LBDC, "Int", L, "Int", T, "Int", W, "Int", H, "Ptr", SELDC, "Int", 0, "Int", 0, "UInt", 0x00CC0020)
               Else
                  DllCall("GdiAlphaBlend", "Ptr", LBDC, "Int", L, "Int", T, "Int", W, "Int", H, "Ptr", SELDC, "Int", 0, "Int", 0, "Int", W, "Int", H, "UInt", BkTrans << 16)
            }
            Txt := This.Items[TopIndex + 1], Len := StrLen(Txt)
            , TextColor := (TopIndex = CurSel ? This.SelColor : This.TxtColor)
            , DllCall("SetTextColor", "Ptr", LBDC, "UInt", TextColor)
            , NumPut(NumGet(RECT, 0, "Int") + 3, RECT, 0, "Int")
            , DllCall("DrawText", "Ptr", LBDC, "Ptr", &Txt, "Int", Len, "Ptr", &RECT, "UInt", 0x0840)
            , NumPut(NumGet(RECT, 0, "Int") - 3, RECT, 0, "Int")
            , DllCall("OffsetRect", "Ptr", &RECT, "Int", 0, "Int", This.ItemHeight)
            , TopIndex++
         }
         DllCall("SelectObject", "Ptr", LBDC, "Ptr", HFONT, "UPtr")
         , DllCall("EndPaint", "Ptr", &PAINTSTRUCT)
         Return 0
      }
      ; WM_ERASEBKGND message ------------------------------------------------------------------------------------------------------
      If (uMsg = 0x0014) {
         If (!This.HasBackground) { ; processed once after creation/update
            VarSetCapacity(RECT, 16, 0)
            , DllCall("GetClientRect", "Ptr", This.HLB, "Ptr", &RECT)
            , This.Width := W := NumGet(RECT, 8, "Int")
            , This.Height := H := NumGet(RECT, 12, "Int")
            , DllCall("ClientToScreen", "Ptr", This.HLB, "Ptr", &RECT)
            , DllCall("ScreenToClient", "Ptr", This.HBG, "Ptr", &RECT)
            , This.Left := L := NumGet(RECT, 0, "Int")
            , This.Top := T := NumGet(RECT, 4, "Int")
            , BGDC := DllCall("GetDC", "Ptr", This.HBG, "UPtr")
            , BMPDC := DllCall("CreateCompatibleDC", "Ptr", BGDC, "UPtr")
            , HBMP := DllCall("CreateCompatibleBitmap", "Ptr", BGDC, "Int", W, "Int", H, "UPtr")
            , DllCall("SelectObject", "Ptr", BMPDC, "Ptr", HBMP)
            , DllCall("BitBlt", "Ptr", BMPDC, "Int", 0, "Int", 0, "Int", W, "Int", H, "Ptr", BGDC, "Int", L, "Int", T, "UInt", 0x00CC0020)
            If (This.SelBkGnd <> "") {
               SELDC := DllCall("CreateCompatibleDC", "Ptr", BGDC, "UPtr")
               , HSEL := DllCall("CreateCompatibleBitmap", "Ptr", BGDC, "Int", This.ItemWidth, "Int", This.ItemHeight, "UPtr")
               , DllCall("SelectObject", "Ptr", SELDC, "Ptr", HSEL)
               , Brush := DllCall("CreateSolidBrush", "UInt", This.SelBkGnd, "UPtr")
               , VarSetCapacity(RECT, 16, 0)
               , NumPut(This.ItemWidth, RECT, 8, "Int")
               , NumPut(This.ItemHeight, RECT, 12, "Int")
               , DllCall("FillRect", "Ptr", SELDC, "Ptr", &RECT, "Ptr", Brush)
               , DllCall("DeleteObject", "Ptr", Brush)
               , This.SELDC := SELDC
               , This.HSEL := HSEL
            }
            DllCall("ReleaseDC", "Ptr", This.HBG, "Ptr", BGDC)
            , This.BMPDC := BMPDC
            , This.HBMP := HBMP
            , LBDC := DllCall("GetDC", "Ptr", hWnd, "UPtr")
            , DllCall("BitBlt", "Ptr", LBDC, "Int", 0, "Int", 0, "Int", W, "Int", H, "Ptr", BMPDC, "Int", 0, "Int", 0, "UInt", 0x00CC0020)
            , DllCall("ReleaseDC", "Ptr", hWnd, "Ptr", LBDC)
            , This.HasBackground := True
         }
         Return True
      }
      ; ----------------------------------------------------------------------------------------------------------------------------
      ; Selection & Focus
      ; ----------------------------------------------------------------------------------------------------------------------------
      ; WM_KILLFOCUS and WM_SETFOCUS messages --------------------------------------------------------------------------------------
      If (uMsg = 0x0008) || (uMsg = 0x0007) ; not processed
         Return 0
      ; LB_SETCURSEL message -------------------------------------------------------------------------------------------------------
      If (uMsg = 0x0186) {
         If (This.Drawing) {
            DrawingMsg := uMsg
            This.SetRedraw(False)
         }
         DllCall("DefSubclassProc", "Ptr", hWnd, "UInt", uMsg, "Ptr", wParam, "Ptr", lParam)
         If (DrawingMsg = 0x0186) {
            This.SetRedraw(True)
            DrawingMsg := ""
         }
         TopIndex := DllCall("SendMessage", "Ptr", hWnd, "UInt", 0x018E, "Ptr", 0, "Ptr", 0, "Int") ; LB_GETTOPINDEX
         DllCall("SetScrollPos", "Ptr", hWnd, "Int", 1, "Int", TopIndex, "UInt", True)
         Return 0
      }
      ; ----------------------------------------------------------------------------------------------------------------------------
      ; Keyboard
      ; ----------------------------------------------------------------------------------------------------------------------------
      ; WM_KEYDOWN message ---------------------------------------------------------------------------------------------------------
      If (uMsg = 0x0100) {
         If VK.HasKey(wParam) {
            CurSel := This.CurSel
            CurSel := (wParam = VK.DOWN)  ? (CurSel + 1)
                   :  (wParam = VK.UP)    ? (CurSel - 1)
                   :  (wParam = VK.Next)  ? (CurSel + This.SIPage - 1)
                   :  (wParam = VK.PRIOR) ? (CurSel - This.SIPage + 1)
                   :  (wParam = VK.HOME)  ? This.SIMin
                   :  (wParam = VK.END)   ? This.SIMax
                   :  CurSel
            CurSel := (CurSel < This.SIMin) ? This.SIMin : (CurSel > This.SIMax) ? This.SIMax : CurSel
            If (Cursel <> This.Cursel) {
               If (This.Drawing) {
                  DrawingMsg := uMsg
                  This.SetRedraw(False)
               }
               DllCall("SendMessage", "Ptr", hWnd, "UInt", 0x0186, "Ptr", CurSel, "Ptr", 0) ; LB_SETCURSEL
               If (DrawingMsg = 0x0100) {
                  This.SetRedraw(True)
                  DrawingMsg := ""
               }
               DllCall("PostMessage", "Ptr", This.Parent, "UInt", 0x0111, "Ptr", This.CtrlID | (1 << 16), "Ptr", hwnd) ; LBN_SELCHANGE
               This.Cursel := CurSel
            }
         }
         Return 0
      }
      ; ----------------------------------------------------------------------------------------------------------------------------
      ; Mouse
      ; ----------------------------------------------------------------------------------------------------------------------------
      ; WM_LBUTTONDOWN message -----------------------------------------------------------------------------------------------------
      If (uMsg = 0x0201) {
         ControlFocus, , ahk_id %hWnd%
         Return 0
      }
      ; WM_LBUTTONUP message -------------------------------------------------------------------------------------------------------
      If (uMsg = 0x0202) {
         Item := DllCall("SendMessage", "Ptr", hWnd, "UInt", 0x01A9, "Ptr", 0, "Ptr", lParam, "UInt") ; LB_SETCURSEL
         If !(Item & 0xFFFF0000) && (Item <> This.CurSel) {
            If (This.Drawing) {
               DrawingMsg := uMsg
               This.SetRedraw(False)
            }
            DllCall("SendMessage", "Ptr", hWnd, "UInt", 0x0186, "Ptr", Item, "Ptr", 0) ; LB_SETCURSEL
            If (DrawingMsg = 0x0202) {
               This.SetRedraw(True)
               DrawingMsg := ""
            }
            DllCall("PostMessage", "Ptr", This.Parent, "UInt", 0x0111, "Ptr", This.CtrlID | (1 << 16), "Ptr", hwnd) ; LBN_SELCHANGE
            This.Cursel := Item
         }
         Return 0
      }
      ; WM_LBUTTONDBLCLK message ---------------------------------------------------------------------------------------------------
      If (uMsg = 0x0203) {
         DllCall("PostMessage", "Ptr", This.Parent, "UInt", 0x0111, "Ptr", This.CtrlID | (2 << 16), "Ptr", hwnd) ; LBN_DBLCLICK
         Return 0
      }
      ; WM_MOUSEWHEEL message ------------------------------------------------------------------------------------------------------
      If (uMsg = 0x020A) {
         Delta := (wParam >> 16) & 0xFFFF
         If ((Delta <= 0x7FFF) && (This.TopIndex > This.SIMin))
         || ((Delta >  0x7FFF) && ((This.TopIndex + This.SIPage) <= This.SIMax))
            DllCall("PostMessage", "Ptr", hWnd, "UInt", 0x0115, "Ptr", Delta > 0x7FFF ? 1 : 0, "Ptr", 0) ; WM_VSCROLL
         Return 0
      }
      ; ----------------------------------------------------------------------------------------------------------------------------
      ; Scrolling
      ; ----------------------------------------------------------------------------------------------------------------------------
      ; WM_HCROLL message ----------------------------------------------------------------------------------------------------------
      If (uMsg = 0x0114)
         Return 0
      ; WM_VSCROLL message ---------------------------------------------------------------------------------------------------------
      If (uMsg = 0x0115) {
         If (((wParam = 1) || (wParam = 3) || (wParam = 7)) && ((This.TopIndex + This.SIPage) > This.SIMax))
         || (((wParam = 0) || (wParam = 2) || (wParam = 6)) && (This.TopIndex <= This.SIMin))
         || (wParam = 8) || (wParam = 4)
            Return 0
         If (This.Drawing) {
            DrawingMsg := uMsg
            This.SetRedraw(False)
         }
         DllCall("DefSubclassProc", "Ptr", hWnd, "UInt", uMsg, "Ptr", wParam, "Ptr", lParam)
         If (DrawingMsg = 0x0115) {
            This.SetRedraw(True)
            DrawingMsg := ""
         }
         This.TopIndex := DllCall("SendMessage", "Ptr", hWnd, "UInt", 0x018E, "Ptr", 0, "Ptr", 0, "Int") ; LB_GETTOPINDEX
         ScrollPos := DllCall("GetScrollPos", "Ptr", hWnd, "Int", 1, "Int") ; SB_VERT = 1
         DllCall("SetScrollPos", "Ptr", hWnd, "Int", 1, "Int", ScrollPos, "UInt", True)
         Return 0
      }
      ; ----------------------------------------------------------------------------------------------------------------------------
      ; Destroy
      ; ----------------------------------------------------------------------------------------------------------------------------
      ; WM_DESTROY message ---------------------------------------------------------------------------------------------------------
      If (uMsg = 0x0002)
         This.__Delete()
      ; ----------------------------------------------------------------------------------------------------------------------------
      ; Call DefSubclassProc for all which reached this point
      ; ----------------------------------------------------------------------------------------------------------------------------
      Return DllCall("DefSubclassProc", "Ptr", hWnd, "UInt", uMsg, "Ptr", wParam, "Ptr", lParam)
   }
}
Regards, just me

Return to “Scripts and Functions (v1)”

Who is online

Users browsing this forum: comvox, gwarble, IfThenElse and 128 guests