
Function Extensions:
- SetGadgetItemColor() can now be used with ListViewGadget and ComboBoxGadget
- SetGadgetItemImage() can now be used with ListViewGadget.
- SetGadgetItemFont() and GetGadgetItemFont()
- GetGadgetItemImage()
- CheckGadgetItem()
- GetGadgetCheckedState()
Code: Select all
;
;**********************************************************************************
;
; SetGadgetItemEx.pbi library
; Windows only
; Zapman - March 2025 - 2
;
; This file should be saved under the name "SetGadgetItemEx.pbi".
;
; This library extends some PureBasic native functions or add functions for
; customizing the items appearance of ListViewGadget and ComboBoxGadget.
;
; Extensions :
; SetGadgetItemColor() can now be used with ListViewGadget and ComboBoxGadget.
; SetGadgetItemImage() can now be used with ListViewGadget.
;
; Additions (only for ListViewGadget and ComboBoxGadget):
; SetGadgetItemFont()
; GetGadgetItemFont()
; GetGadgetItemImage()
; CheckGadgetItem()
; GetGadgetCheckedState()
;
; This library is compatible with all other Zapman libraries, including
; SetGadgetColorEx.pbi and ApplyColorThemes.pbi
;
;***********************************************************************************
;
CompilerIf #PB_Compiler_IsMainFile
EnableExplicit
CompilerEndIf
;
;**********************************************************************************
;
;- 1- STRUCTURES GLOBALS AND CONSTANTES DECLARATIONS
;
#Zapman_Ignore = -1
;
Global SGI_GadgetsLineHeight = 18 ; <-- Must be at least equal to 16 to show entire icons.
#SGI_MenuBulletSize = 4
;
EnumerationBinary SGI_ShowSelectionMethod
#SGI_Bullet = 1
#SGI_Borders
#SGI_SystemColor
#SGI_ShadeBackground
EndEnumeration
;
Global SGI_ShowSelectionMethod
If SGI_ShowSelectionMethod = 0
; By changing the value of SGI_ShowSelectionMethod,
; you change the manner of showing that an item is selected.
; Usualy, a simple background shading is enough to do that,
; but it can be inefficient in a dark mode environment or
; when each item has its own particular color (or both).
; So, you can choose between four different methods
; (see the SGI_ShowSelectionMethod enumeration).
; Try each of them to decide.
;
; Note that your can eventually combine different methods.
; SGI_ShowSelectionMethod = #SGI_SystemColor | #SGI_Bullet
;
SGI_ShowSelectionMethod = #SGI_SystemColor | #SGI_Borders
EndIf
;
Structure GadgetItemStruct
GadgetNum.i
ODTType.i
ItemPos.i
Font.i
BackColor.i
TextColor.i
ImageNum.i
ImageHandle.i
ItemChecked.i
EndStructure
;
Global NewList ItemSpecs.GadgetItemStruct()
;
;
;
;*******************************************************************************
;
;- 2- GENERAL FUNCTIONS
; (possibly reusable by other programs)
;
;*******************************************************************************
;
Procedure LoadGadgetsDefaultFont()
#SPI_GETNONCLIENTMETRICS = $0029
Protected ncm.NONCLIENTMETRICS
ncm\cbSize = SizeOf(NONCLIENTMETRICS)
;
If SystemParametersInfo_(#SPI_GETNONCLIENTMETRICS, ncm\cbSize, @ncm, 0)
Protected FontName$ = PeekS(@ncm\lfCaptionFont\lfFaceName)
Protected FontSize = ncm\lfCaptionFont\lfHeight / DesktopResolutionY()
ProcedureReturn LoadFont(#PB_Any, FontName$, FontSize)
EndIf
EndProcedure
;
Global DefaultGadgetsFont = LoadGadgetsDefaultFont()
;
CompilerIf Not(Defined(GetImageFromShell32, #PB_Procedure))
Procedure GetImageFromShell32(IconNum, ImgWidth, ImgHeight)
;
Protected TransparentImage = CreateImage(#PB_Any, ImgWidth, ImgHeight, 32, #PB_Image_Transparent)
Protected hIcon = ExtractIcon_(0, "shell32.dll", IconNum)
;
If IsImage(TransparentImage) And hIcon
Protected Dest_hDC = StartDrawing(ImageOutput(TransparentImage))
If Dest_hDC
DrawingMode(#PB_2DDrawing_AlphaBlend)
Box(0, 0, ImgWidth, ImgHeight, RGBA(0, 0, 0, 0))
DrawIconEx_(Dest_hDC, 0, 0, hIcon, ImgWidth, ImgHeight, 0, #Null, #DI_NORMAL)
StopDrawing()
DeleteDC_(Dest_hDC)
EndIf
EndIf
DestroyIcon_(hIcon)
;
ProcedureReturn TransparentImage
EndProcedure
CompilerEndIf
;
CompilerIf Not(Defined(ResizeImageToIconSize, #PB_Procedure))
Procedure ResizeImageToIconSize(SourceImage)
;
If SourceImage
If IsImage(SourceImage)
SourceImage = ImageID(SourceImage)
EndIf
;
Protected ResizedImage = CreateImage(#PB_Any, GetSystemMetrics_(#SM_CXSMICON), GetSystemMetrics_(#SM_CYSMICON), 32, #PB_Image_Transparent)
If ResizedImage
If StartDrawing(ImageOutput(ResizedImage))
DrawingMode(#PB_2DDrawing_AlphaBlend)
DrawImage(SourceImage, 0, 0, GetSystemMetrics_(#SM_CXSMICON), GetSystemMetrics_(#SM_CYSMICON))
StopDrawing()
ProcedureReturn ResizedImage
EndIf
EndIf
EndIf
ProcedureReturn #Null
EndProcedure
CompilerEndIf
;
CompilerIf Not(Defined(CreateIconFromImage, #PB_Procedure))
Procedure CreateIconFromImage(hBitmap)
;
Protected iconInfo.ICONINFO, bitmap.BITMAP
;
If IsImage(hBitmap)
hBitmap = ImageID(hBitmap)
EndIf
;
If GetObject_(hBitmap, SizeOf(BITMAP), @bitmap)
;
; Fill the ICONINFO Structure
iconInfo\fIcon = #True
iconInfo\xHotspot = 0
iconInfo\yHotspot = 0
iconInfo\hbmMask = CreateBitmap_(bitmap\bmWidth, bitmap\bmHeight, 1, 1, #Null)
iconInfo\hbmColor = hBitmap
Protected hIcon = CreateIconIndirect_(@iconInfo)
;
; Free the mask
DeleteObject_(iconInfo\hbmMask)
;
ProcedureReturn hIcon
EndIf
EndProcedure
CompilerEndIf
;
CompilerIf Not(Defined(DrawTransparentRectangle, #PB_Procedure))
Procedure DrawTransparentRectangle(Dest_hDC, *rect.RECT, CoverColor, Opacity)
;
Protected TempRect.Rect, hBrush
Protected Srce_hDC = CreateCompatibleDC_(Dest_hDC)
;
If CoverColor = 0 : CoverColor = 1 : EndIf ; There is a bug when color = 0
;
If Srce_hDC
Protected ImgWidth = *rect\right - *rect\left
Protected ImgHeight = *rect\bottom - *rect\top
Protected hbmTemp = CreateCompatibleBitmap_(Dest_hDC, ImgWidth, ImgHeight)
If hbmTemp
Protected oldBitmap = SelectObject_(Srce_hDC, hbmTemp)
If oldBitmap
Protected blend, *blend.BLENDFUNCTION = @blend
;
If OpenLibrary(0, "Msimg32.dll")
;
; Fill hbmTemp with CoverColor
TempRect\left = 0 : TempRect\top = 0
TempRect\right = ImgWidth : TempRect\bottom = ImgHeight
hBrush = CreateSolidBrush_(CoverColor)
FillRect_(Srce_hDC, TempRect, hBrush)
DeleteObject_(hBrush)
;
; Copy hbmTemp from Srce_hDC to Dest_hDC, respecting AlphaBlend:
*blend\BlendOp = #AC_SRC_OVER
*blend\BlendFlags = 0
*blend\AlphaFormat = 0
*blend\SourceConstantAlpha = Opacity
CallFunction(0, "AlphaBlend", Dest_hDC, *rect\left, *rect\top, ImgWidth, ImgHeight, Srce_hDC, 0, 0, ImgWidth, ImgHeight, blend)
;
CloseLibrary(0)
EndIf
;
SelectObject_(Srce_hDC, oldBitmap)
EndIf
DeleteObject_(hbmTemp)
EndIf
DeleteDC_(Srce_hDC)
EndIf
EndProcedure
CompilerEndIf
;
CompilerIf Not(Defined(DrawRightPointingTriangle, #PB_Procedure))
Procedure DrawRightPointingTriangle(hDC, *rc.Rect, tSize, FrontColor, BackColor)
;
Protected *points = AllocateMemory(3 * SizeOf(POINT))
Protected vCenter = *rc\top + (*rc\bottom - *rc\top) / 2 - 1
;
; Calculate the coordinates of the triangle
PokeL(*points + 0, *rc\left + tSize) ; Point for the tip of the triangle
PokeL(*points + 4, vCenter) ; Centered vertically within the triangle
;
PokeL(*points + 8, *rc\left)
PokeL(*points + 12, vCenter + tSize) ; Bottom of the triangle
;
PokeL(*points + 16, *rc\left);
PokeL(*points + 20, vCenter - tSize) ; Top of the triangle
;
Protected hPen = CreatePen_(#PS_SOLID, 1, FrontColor) ; Pen with 1-pixel thickness
Protected hBrush = CreateSolidBrush_(BackColor)
SelectObject_(hDC, hPen)
SelectObject_(hDC, hBrush)
;
Polygon_(hDC, *points, 3) ; Draw the triangle
;
; CleanUp
DeleteObject_(hPen)
DeleteObject_(hBrush)
FreeMemory(*points)
EndProcedure
CompilerEndIf
;
CompilerIf Not(Defined(DrawCheckmark, #PB_Procedure))
Procedure DrawCheckmark(hDC, *rc.Rect, Size, Color)
Protected pt.POINT, hPen
; Calcul de la position du rectangle 10x10 à l'intérieur de rc
pt\x = *rc\left ; Aligné à gauche
pt\y = *rc\top + (*rc\bottom - *rc\top - Size) / 2; Centrage vertical
; Création d'un stylo pour dessiner la checkmark
hPen = CreatePen_(#PS_SOLID, 2, Color)
SelectObject_(hDC, hPen)
; Dessiner la checkmark (?) avec MoveToEx_ et LineTo_
MoveToEx_(hDC, pt\x + Size/5, pt\y + Size * 2 / 5, 0)
LineTo_(hDC, pt\x + Size * 3 / 5, pt\y + Size * 4 / 5)
LineTo_(hDC, pt\x + Size * 7 / 5, pt\y)
; Nettoyage
DeleteObject_(hPen)
EndProcedure
CompilerEndIf
;
CompilerIf Not(Defined(RefreshGadget, #PB_Procedure))
Procedure RefreshGadget(GadgetNum)
If IsWindowVisible_(GadgetID(GadgetNum))
HideGadget(GadgetNum, #True)
HideGadget(GadgetNum, #False)
EndIf
EndProcedure
CompilerEndIf
;
; *****************************************************************************
;
;- 3. SPECIALIZED PROCEDURES OF THE LIBRARY
;
; The following procedure are subroutines of the library functions.
;
; *****************************************************************************
;
Procedure SGI_GetODTTypeFromPBGadgetType(PBGadgetType)
Protected ODTType
Select PBGadgetType
Case #PB_GadgetType_ComboBox
ODTType = #ODT_COMBOBOX
Case #PB_GadgetType_ListView
ODTType = #ODT_LISTBOX
EndSelect
ProcedureReturn ODTType
EndProcedure
;
Procedure SGI_RetreiveItemSpecs(GadgetNum, ItemNum)
ForEach ItemSpecs()
If ItemSpecs()\GadgetNum = GadgetNum And ItemSpecs()\ItemPos = ItemNum
SetGadgetItemData(GadgetNum, ItemNum, ItemNum)
ProcedureReturn #True
Break
EndIf
Next
EndProcedure
;
Procedure SGI_OwnerDrawnCallback(hWnd, uMsg, wParam, lParam)
;
; Callback procedure for the main window hosting the gadgets
; whose items must be colored or set with a particular font.
;
Protected *drawItem.DRAWITEMSTRUCT
Protected *measureItem.MEASUREITEMSTRUCT
Protected hDC, rc.RECT, rc2.RECT, Text$, ImgAddress
Protected BackColor, TextColor, ItemChecked, hBrush, ImgVerticalMargin
Protected GadgetNum, GadgetOrMenuHandle, ItemNum, ODTType
Protected ItemFont, BackLuminosity, TextLuminosity
Protected Selected, Disabled, Opacity, CoverColor
;
Select uMsg
;
Case #WM_DESTROY
; Clean the memory when the main window is destroyed:
;
ForEach ItemSpecs()
If IsImage(ItemSpecs()\ImageNum)
FreeImage(ItemSpecs()\ImageNum)
DeleteElement(ItemSpecs())
EndIf
Next
;
Case #WM_MEASUREITEM
*measureItem = lParam
;
ODTType = *measureItem\CtlType
If ODTType = #ODT_COMBOBOX
*measureItem\itemHeight = SGI_GadgetsLineHeight
ProcedureReturn #True
EndIf
;
Case #WM_DRAWITEM
;- Callback: #WM_DRAWITEM
If lParam
*drawItem = lParam
ItemNum = *drawItem\itemID
ODTType = *drawItem\CtlType
hDC = *drawItem\hdc
rc = *drawItem\rcItem
GadgetNum = GetProp_(*drawItem\hwndItem, "PB_ID")
If IsGadget(GadgetNum)
If SGI_RetreiveItemSpecs(GadgetNum, ItemNum)
ItemFont = ItemSpecs()\Font
BackColor = ItemSpecs()\BackColor
TextColor = ItemSpecs()\TextColor
ItemChecked = ItemSpecs()\ItemChecked
ImgAddress = ItemSpecs()\ImageHandle
Else
ItemFont = #PB_Default
BackColor = #PB_Default
TextColor = #PB_Default
ItemChecked = 0
ImgAddress = 0
EndIf
;
If IsFont(ItemFont) = 0
ItemFont = DefaultGadgetsFont
EndIf
;
SelectObject_(hDC, FontID(ItemFont))
GadgetOrMenuHandle = GadgetID(GadgetNum)
Text$ = GetGadgetItemText(GadgetNum, ItemNum)
;
; _________________________________________
;
; Layout settings
;
ImgVerticalMargin = (SGI_GadgetsLineHeight - GetSystemMetrics_(#SM_CYSMICON)) / 2
If *drawItem\ItemState & #ODS_SELECTED
Selected = 1
EndIf
If *drawItem\ItemState & #ODS_GRAYED
Disabled = 1
Selected = 0
EndIf
;
; _________________________________________
;
; Define colors for text and background:
;
If BackColor = #PB_Default
CompilerIf Defined(SetGadgetsColorsFromTheme, #PB_Procedure)
; Manage compatibility with the ApplyColorThemes.pbi library
If ListSize(InterfaceColorPresets()) > 0
BackColor = GetRealColorFromType("BackgroundColor", InterfaceColorPresets()\BackgroundColor)
EndIf
CompilerElseIf Defined(ObjectTheme, #PB_Module)
; Manage compatibility with the ObjectTheme.pbi library:
BackColor = ObjectTheme::GetObjectThemeAttribute(0, #PB_Gadget_BackColor)
CompilerEndIf
If BackColor = #PB_Default
BackColor = GetSysColor_(#COLOR_WINDOW)
EndIf
EndIf
;
If TextColor = #PB_Default
CompilerIf Defined(SetGadgetsColorsFromTheme, #PB_Procedure)
; Manage compatibility with the ApplyColorThemes.pbi library:
If ListSize(InterfaceColorPresets()) > 0
TextColor = GetRealColorFromType("TextColor", InterfaceColorPresets()\TextColor)
EndIf
CompilerElseIf Defined(ObjectTheme, #PB_Module)
; Manage compatibility with the ObjectTheme.pbi library:
TextColor = ObjectTheme::GetObjectThemeAttribute(#PB_GadgetType_Button, #PB_Gadget_FrontColor)
CompilerEndIf
If TextColor = #PB_Default
TextColor = GetSysColor_(#COLOR_WINDOWTEXT)
EndIf
EndIf
;
; Based on Human perception of color
TextLuminosity = Red(TextColor)*0.299 + Green(TextColor)*0.587 + Blue(TextColor)*0.114
BackLuminosity = Red(BackColor)*0.299 + Green(BackColor)*0.587 + Blue(BackColor)*0.114
;
; _________________________________________
;
; Paint the background:
;
hBrush = CreateSolidBrush_(BackColor)
FillRect_(hDC, @rc, hBrush)
DeleteObject_(hBrush)
;
; _________________________________________
;
; Shade the background (eventually):
;
If Selected And (SGI_ShowSelectionMethod & #SGI_ShadeBackground)
;
If BackLuminosity > 128
CoverColor = #Black
Opacity = 40
Else
CoverColor = #White
Opacity = 60
EndIf
;
DrawTransparentRectangle(hDC, rc, CoverColor, Opacity)
;
If BackLuminosity < 128
TextColor = #White
Else
TextColor = #Black
EndIf
EndIf
;
; _________________________________________
;
; Draw borders (eventually):
;
If Selected And (SGI_ShowSelectionMethod & #SGI_Borders)
hBrush = CreateSolidBrush_(GetSysColor_(#COLOR_HIGHLIGHT))
FrameRect_(hDC, @rc, hBrush)
DeleteObject_(hBrush)
EndIf
;
; _________________________________________
;
; Apply 'HotState' when SGI_ShowSelectionMethod & #SGI_SystemColor
;
If Selected And (SGI_ShowSelectionMethod & #SGI_SystemColor)
Opacity = 100
CoverColor = GetSysColor_(#COLOR_HIGHLIGHT)
If BackLuminosity < 128
Opacity = 150
EndIf
;
DrawTransparentRectangle(hDC, rc, CoverColor, Opacity)
EndIf
;
; _________________________________________
;
; Draw a checkmark (eventually):
;
If ItemChecked
CopyMemory(@rc, @rc2, SizeOf(RECT))
rc2\right = rc2\left + DesktopScaledX(16)
; DrawThemeBackground_(hTheme, hDC, #MENU_POPUPCHECK, #MC_CHECKMARKNORMAL, @rc2, 0)
;DrawFrameControl_(hDC, @rc2, #DFC_MENU, #DFCS_MENUCHECK)
DrawCheckmark(hDC, @rc2, DesktopScaledX(10), TextColor)
rc\left + DesktopScaledX(18)
EndIf
;
;
; _________________________________________
;
; Draw a bullet (eventually):
;
If SGI_ShowSelectionMethod & #SGI_Bullet
If Selected
rc\left + DesktopScaledX(3)
DrawRightPointingTriangle(hDC, rc, DesktopScaledX( #SGI_MenuBulletSize), TextColor, BackColor)
rc\left + DesktopScaledX(#SGI_MenuBulletSize + 2)
EndIf
EndIf
;
; _________________________________________
;
; Draw an icon (eventually):
;
If ImgAddress ; Image illustrating the menu line
;
Protected icone = CreateIconFromImage(ImgAddress)
If icone <> 0
DrawIconEx_(hDC, rc\left, rc\top + ImgVerticalMargin, icone, 0, 0, 0, #Null, #DI_NORMAL)
rc\left + GetSystemMetrics_(#SM_CXSMICON) + DesktopScaledX(3)
EndIf
;
EndIf
;
; _________________________________________
;
; Draw the item text:
;
rc\Left + DesktopScaledX(2)
;
SetTextColor_(hDC, TextColor)
SetBkMode_(hDC, #TRANSPARENT)
DrawText_(hDC, Text$, Len(Text$), @rc, #DT_LEFT | #DT_VCENTER | #DT_SINGLELINE)
;
; _________________________________________
;
; Gray the item if it is Disabled:
;
If Disabled
; Item is grayed. Recover the drawing with a semi-transparent rectangle:
If BackLuminosity > 128
CoverColor = #White
Else
CoverColor = #Black
EndIf
rc = *drawItem\rcItem
DrawTransparentRectangle(hDC, rc, CoverColor, 128)
EndIf
;
ProcedureReturn #True
;
EndIf
EndIf
EndSelect
;
; Normal callback for all other messages:
Protected SGI_OldCallBack = GetProp_(hWnd, "SGI_OldCallBack")
ProcedureReturn CallWindowProc_(SGI_OldCallBack, hWnd, uMsg, wParam, lParam)
EndProcedure
;
Macro SGI_CreateGadget(OldNoGadget)
If ODTType = #ODT_LISTBOX
If OldNoGadget = -1
NewNoGadget = ListViewGadget(#PB_Any, PosX, PosY, GWidth, GHeight, CheckType)
Else
ListViewGadget(OldNoGadget, PosX, PosY, GWidth, GHeight, CheckType)
NewNoGadget = OldNoGadget
EndIf
ElseIf ODTType = #ODT_COMBOBOX
If OldNoGadget = -1
NewNoGadget = ComboBoxGadget(#PB_Any, PosX, PosY, GWidth, GHeight, CheckType)
Else
ComboBoxGadget(OldNoGadget, PosX, PosY, GWidth, GHeight, CheckType)
NewNoGadget = OldNoGadget
EndIf
EndIf
EndMacro
;
Procedure SGI_Recreategadget(NoGadget)
;
; Check is the gadget has been created with OWNERDRAW option.
; If not, the gadget is destroyed and recreated with the good option.
; Data and items of the old gadget are transfered in the new one.
; The PureBasic gadget identifiant should not change during
; the operation, but the gadget handle (GadgetID(NoGadget))
; will be different.
;
Protected ct, PosX, PosY, GWidth, GHeight, CheckType, NewNoGadget
;
If IsGadget(NoGadget)
Protected ODTType = SGI_GetODTTypeFromPBGadgetType(GadgetType(NoGadget))
Protected currentStyle = GetWindowLongPtr_(GadgetID(NoGadget), #GWL_STYLE)
;
If ODTType = #ODT_LISTBOX
CheckType = #LBS_OWNERDRAWFIXED
ElseIf ODTType = #ODT_COMBOBOX
CheckType = #CBS_OWNERDRAWFIXED
EndIf
;
If CheckType And Not (currentStyle & CheckType)
If ODTType = #ODT_COMBOBOX
CheckType | #CBS_HASSTRINGS
EndIf
; The gadget has been created without OWNERDRAWFIXED option.
; It is not possible to attribute this style after the creation,
; so, we must delete the gadget and recreate it with the right style.
;
; First store all what is possible to store about the gadget:
NewList mGadgetItemText$()
NewList mGadgetItemData()
Protected mGadgetState = GetGadgetState(NoGadget)
For ct = 0 To CountGadgetItems(NoGadget) - 1
AddElement(mGadgetItemText$())
AddElement(mGadgetItemData())
mGadgetItemText$() = GetGadgetItemText(NoGadget, ct)
mGadgetItemData() = GetGadgetItemData(NoGadget, ct)
Next
PosX = GadgetX(NoGadget) : PosY = GadgetY(NoGadget)
GWidth = GadgetWidth(NoGadget) : GHeight = GadgetHeight(NoGadget)
If ODTType = #ODT_COMBOBOX
GHeight = SGI_GadgetsLineHeight + 6 ; Height parameter is fixed to (SGI_GadgetsLineHeight + 6) for ownerdrawn ComboBox, whatever the value used to create it.
EndIf
FreeGadget(NoGadget)
;
; Recreate the gadget:
If NoGadget > 10000
; Gadget has been created using #PB_Any.
;
; Theorically, because the old gadget has just been deleted,
; the same number will be reattributed to the new one.
SGI_CreateGadget(-1)
If NewNoGadget <> NoGadget
; Gasp! It didn't work. Try to reuse the precedent number.
FreeGadget(NewNoGadget)
SGI_CreateGadget(NoGadget)
EndIf
Else
; Gadget has been created using a custom number. Keep it.
SGI_CreateGadget(NoGadget)
EndIf
;
If ODTType = #ODT_LISTBOX
SendMessage_(GadgetID(NoGadget), #LB_SETITEMHEIGHT, -1, SGI_GadgetsLineHeight)
EndIf
;
; Reattribute the content, the data and the style of the deleted gadget:
Protected NewStyle = GetWindowLongPtr_(GadgetID(NoGadget), #GWL_STYLE)
SetWindowLongPtr_(GadgetID(NoGadget), #GWL_STYLE, NewStyle | currentStyle)
;
ForEach mGadgetItemText$()
AddGadgetItem(NoGadget, -1, mGadgetItemText$())
SelectElement(mGadgetItemData(), ListIndex(mGadgetItemText$()))
SetGadgetItemData(NoGadget, ListIndex(mGadgetItemText$()), mGadgetItemData())
Next
SetGadgetState(NoGadget, mGadgetState)
;
;Clean memory:
FreeList(mGadgetItemText$())
FreeList(mGadgetItemData())
EndIf
EndIf
EndProcedure
;
Procedure SGI_SetGadgetItemEx(GadgetNum, ItemNum)
;
; This is the main used procedure of this library.
; For each gadget item designed by 'GadgetNum' and 'ItemNum',
; it creates or find a record in the ItemSpecs() list.
;
; This record will be later used by the SGI_OwnerDrawnCallback procedure
; to draw the item with the requested font, icone and color.
;
; In addition to creating a registration in ItemSpecs(), this procedure
; also installs 'SGI_OwnerDrawnCallback()' as a callback procedure for
; the application's main window.
;
; For ComboBox and ListView gadgets, this procedure checks that they were created
; with the 'OwnerDrawn' option. When this is not the case, these gadgets are
; destroyed and recreated with the correct option.
;
Protected Found = 0, MainWindowNum, SubMenu = 0, GadgetHandle, ItemPos, ResultType
Protected mItemNum = ItemNum, ct
;
;
If IsGadget(GadgetNum)
Protected ODTType = SGI_GetODTTypeFromPBGadgetType(GadgetType(GadgetNum))
GadgetHandle = GadgetID(GadgetNum)
;
; Retreive the main window PureBasic ID number:
Protected MwID = GetAncestor_(GadgetHandle, #GA_ROOT)
MainWindowNum = GetProp_(MwID, "PB_WINDOWID") - 1
;
EndIf
;
If ODTType
If SGI_RetreiveItemSpecs(GadgetNum, ItemNum) = 0
AddElement(ItemSpecs())
ItemSpecs()\GadgetNum = GadgetNum
ItemSpecs()\ItemPos = ItemNum
ItemSpecs()\ODTType = ODTType
ItemSpecs()\BackColor = -1
ItemSpecs()\TextColor = -1
ItemSpecs()\Font = -1
ItemSpecs()\ImageNum = -1
ItemSpecs()\ItemChecked = 0
;
Protected SGI_OldCallBack = GetProp_(MwID, "SGI_OldCallBack")
If SGI_OldCallBack = 0
SGI_OldCallBack = SetWindowLongPtr_(MwID, #GWL_WNDPROC, @SGI_OwnerDrawnCallback())
SetProp_(MwID, "SGI_OldCallBack" , SGI_OldCallBack)
SetProp_(MwID, "SGI_ActualCallBack", @SGI_OwnerDrawnCallback())
EndIf
;
SGI_Recreategadget(GadgetNum)
EndIf
;
ProcedureReturn #True
Else
;
ProcedureReturn #False
EndIf
EndProcedure
;
;
;
; *****************************************************************************
;
;- 4. LIBRARY FUNCTIONS
;
; Functions added to the native set of PureBasic functions
;
; *****************************************************************************
;
;
Procedure SetGadgetItemFont(GadgetNum, ItemNum, Font)
;
; Allows to set a particular font to an item of ComboBox or
; ListView Gadget.
;
If SGI_SetGadgetItemEx(GadgetNum, ItemNum)
ItemSpecs()\Font = Font
ProcedureReturn #True
EndIf
EndProcedure
;
Procedure GetGadgetItemFont(GadgetNum, ItemNum)
If SGI_RetreiveItemSpecs(GadgetNum, ItemNum)
ProcedureReturn ItemSpecs()\Font
EndIf
EndProcedure
;
Procedure CheckGadgetItem(GadgetNum, ItemNum, CheckUncheck)
;
; Allows to check or uncheck an item
; of a ComboBox or ListView Gadget.
;
If SGI_SetGadgetItemEx(GadgetNum, ItemNum)
ItemSpecs()\ItemChecked = CheckUncheck
ProcedureReturn #True
EndIf
EndProcedure
;
Procedure GetGadgetCheckedState(GadgetNum, ItemNum)
If SGI_RetreiveItemSpecs(GadgetNum, ItemNum)
ProcedureReturn ItemSpecs()\ItemChecked
EndIf
EndProcedure
;
Procedure SetGadgetItemColorEx(GadgetNum, ItemNum, Colortype, Color, Colonne = 0)
;
; Allows to set a particular color to an item of ComboBox or
; ListView Gadget.
;
; This function complete the PureBasic native fonction 'SetGadgetItemColor()'
; which does not apply to ComboBox and ListView (until PB 6.20).
;
If SGI_SetGadgetItemEx(GadgetNum, ItemNum)
If Colortype = #PB_Gadget_BackColor
ItemSpecs()\BackColor = Color
ProcedureReturn #True
ElseIf Colortype = #PB_Gadget_FrontColor
ItemSpecs()\TextColor = Color
ProcedureReturn #True
EndIf
Else
ProcedureReturn SetGadgetItemColor(GadgetNum, ItemNum, Colortype, Colonne)
EndIf
EndProcedure
;
Procedure GetGadgetItemColorEx(GadgetNum, ItemNum, Colortype, Colonne = 0)
;
If SGI_RetreiveItemSpecs(GadgetNum, ItemNum)
If Colortype = #PB_Gadget_BackColor
ProcedureReturn ItemSpecs()\BackColor
ElseIf Colortype = #PB_Gadget_FrontColor
ProcedureReturn ItemSpecs()\TextColor
EndIf
Else
ProcedureReturn GetGadgetItemColor(GadgetNum, ItemNum, Colortype, Colonne)
EndIf
EndProcedure
;
Procedure SetGadgetItemImageEx(GadgetNum, ItemNum, *ItemImagePtr)
;
; Allows to attribute an image to an item of ComboBox or
; ListView Gadget.
;
; This function complete the PureBasic native fonction 'SetGadgetItemColor()'
; which does not apply to ListView (until PB 6.20).
;
If IsImage(*ItemImagePtr)
*ItemImagePtr = ImageID(*ItemImagePtr)
EndIf
;
If SGI_SetGadgetItemEx(GadgetNum, ItemNum)
;
If IsImage(ItemSpecs()\ImageNum)
FreeImage(ItemSpecs()\ImageNum)
EndIf
ItemSpecs()\ImageHandle = 0
;
If *ItemImagePtr
ItemSpecs()\ImageNum = ResizeImageToIconSize(*ItemImagePtr)
If ItemSpecs()\ImageNum
ItemSpecs()\ImageHandle = ImageID(ItemSpecs()\ImageNum)
ProcedureReturn #True
EndIf
EndIf
;
Else
SetGadgetItemImage(GadgetNum, ItemNum, *ItemImagePtr)
EndIf
EndProcedure
;
Procedure GetGadgetItemImage(GadgetNum, ItemNum)
If SGI_RetreiveItemSpecs(GadgetNum, ItemNum)
ProcedureReturn ItemSpecs()\ImageHandle
EndIf
EndProcedure
;
;
;
; *****************************************************************************
;
;- 5. OVERRIDING OF PUREBASIC NATIVE FUNCTIONS
;
; *****************************************************************************
;
Macro SetGadgetItemColor(GadgetNum, ItemNum, Colortype, Color, Colonne = 0)
SetGadgetItemColorEx(GadgetNum, ItemNum, Colortype, Color, Colonne)
EndMacro
;
Macro GetGadgetItemColor(GadgetNum, ItemNum, Colortype, Colonne = 0)
GetGadgetItemColorEx(GadgetNum, ItemNum, Colortype, Colonne)
EndMacro
;
Macro SetGadgetItemImage(GadgetNum, ItemNum, ItemImagePtr)
SetGadgetItemImageEx(GadgetNum, ItemNum, ItemImagePtr)
EndMacro
;
; ********************************************************************************
;
;- 6- DEMONSTRATION PROGRAM
; (just to see how it works and what it can do)
;
;*******************************************************************************
;
CompilerIf #PB_Compiler_IsMainFile
; The following won't run when this file is used as 'Included'.
;
Define DemoWindow = OpenWindow(#PB_Any, 100, 100, 500, 365, "OwnerDraw ListView and ComboBox Gadgets", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)
If DemoWindow
;
Define CourierFont = LoadFont(#PB_Any, "Courier New", 9)
Define SegoeFont = LoadFont(#PB_Any, "Segoe UI", 9)
Define ComicFont = LoadFont(#PB_Any, "Comic Sans MS", 9)
Define ImpactFont = LoadFont(#PB_Any, "Impact", 9)
;
Define LightRedColor = RGB(255, 200, 200)
Define DarkRedColor = RGB(200, 0, 0)
Define GreenColor = RGB(200, 255, 200)
Define BlueColor = RGB(200, 200, 255)
Define YellowColor = RGB(255, 255, 0)
;
Define img1 = GetImageFromShell32(13, 32, 32)
Define img2 = GetImageFromShell32(43, 32, 32)
Define img3 = GetImageFromShell32(22, 32, 32)
;
; ListView
;
Define LVColor = ListViewGadget(#PB_Any, 10, 10, WindowWidth(DemoWindow) - 20, 80)
;
AddGadgetItem(LVColor, 0, "LV Impact")
SetGadgetItemImage(LVColor, 0, ImageID(img1))
SetGadgetItemFont(LVColor, 0, ImpactFont)
SetGadgetItemColor(LVColor, 0, #PB_Gadget_BackColor, LightRedColor)
;
AddGadgetItem(LVColor, 1, "LV Courier New")
SetGadgetItemImage(LVColor, 1, ImageID(img3))
SetGadgetItemFont(LVColor, 1, CourierFont)
SetGadgetItemColor(LVColor, 1, #PB_Gadget_BackColor, GreenColor)
;
AddGadgetItem(LVColor, 2, "LV Comic Sans MS")
CheckGadgetItem(LVColor, 2, #True)
SetGadgetItemFont(LVColor, 2, ComicFont)
SetGadgetItemColor(LVColor, 2, #PB_Gadget_BackColor, BlueColor)
;
AddGadgetItem(LVColor, 3, "Standard")
;
SetGadgetState(LVColor, 0)
;
; ComboBox
;
Define VPos = 100
Define CBColor = ComboBoxGadget(#PB_Any, 10, VPos, WindowWidth(DemoWindow) - 20, 0) ; <-- Height parameter is fixed to (SGI_GadgetsLineHeight + 6) for ownerdrawn ComboBox, whatever the value used to create it.
;
AddGadgetItem(CBColor, 0, "CB Impact")
SetGadgetItemFont(CBColor, 0, ImpactFont)
SetGadgetItemColor(CBColor, 0, #PB_Gadget_BackColor, DarkRedColor)
SetGadgetItemColor(CBColor, 0, #PB_Gadget_FrontColor, YellowColor)
SetGadgetItemImage(CBColor, 0, ImageID(img2))
;
AddGadgetItem(CBColor, 1, "Cb Courier New")
SetGadgetItemFont(CBColor, 1, CourierFont)
SetGadgetItemColor(CBColor, 1, #PB_Gadget_BackColor, GreenColor)
SetGadgetItemImage(CBColor, 1, ImageID(img3))
;
AddGadgetItem(CBColor, 2, "CB Comic Sans MS")
SetGadgetItemFont(CBColor, 2, ComicFont)
SetGadgetItemColor(CBColor, 2, #PB_Gadget_BackColor, BlueColor)
CheckGadgetItem(CBColor, 2, #True)
;
AddGadgetItem(CBColor, 3, "Standard")
;
SetGadgetState(CBColor, 0)
;
;
;* ----------------------------- Buttons -----------------------------
;
Define Msg$ = "By changing the value of SGI_ShowSelectionMethod, you change the manner"
Msg$ + " of showing to the user that an item is selected. Usualy, a "
Msg$ + "simple background shading is enough to do that, but it can be inefficient in a "
Msg$ + "dark mode environment or when each item has its own particular color (or both). "
Msg$ + "So, you can choose four different methods (see the SGI_ShowSelectionMethod enumeration)."
Msg$ + " Try each of them to decide." + #CR$ + "Note that your can eventually combine different methods:"
;
VPos + 40
TextGadget(#PB_Any, 10, VPos, WindowWidth(DemoWindow) - 20, 100, Msg$, #PB_Text_Center)
VPos + 95
Define HPos = 40
Define BulletButton = CheckBoxGadget(#PB_Any, HPos, VPos, 60, 25, "Bullet")
HPos + 85
Define BordersButton = CheckBoxGadget(#PB_Any, HPos, VPos, 60, 25, "Framing")
HPos + 100
Define SystemColorButton = CheckBoxGadget(#PB_Any, HPos, VPos, 90, 25, "SystemColor")
HPos + 120
Define ShadeButton = CheckBoxGadget(#PB_Any, HPos, VPos, 120, 25, "Shade background")
;
SetGadgetState(SystemColorButton, #True)
SetGadgetState(BulletButton, #True)
SetGadgetState(BordersButton, #True)
SGI_ShowSelectionMethod = #SGI_SystemColor | #SGI_Bullet | #SGI_Borders
;
Msg$ = "This library requires no special skills to use. No initialization is needed. "
Msg$ + "You don't need to install a callback procedure (this will be done automatically "
Msg$ + "if necessary)." + #CR$
Msg$ + "The only thing you need to do is include the library file in your program's code"
Msg$ + " by using 'XIncludeFile (path)/SetGadgetItemEx.pbi'." + #CR$ +"From then on, you can call"
Msg$ + " functions like 'SetGadgetItemColor()', 'SetGadgetItemFont()', 'SetGadgetItemImage()', etc."
;
VPos + 30
TextGadget(#PB_Any, 10, VPos, WindowWidth(DemoWindow) - 20, 100, Msg$, #PB_Text_Center)
;
; Main loop
Repeat
Select WaitWindowEvent()
Case #PB_Event_Gadget
Select EventGadget()
Case BulletButton, BordersButton, SystemColorButton, ShadeButton
SGI_ShowSelectionMethod = (GetGadgetState(BulletButton) * #SGI_Bullet)
SGI_ShowSelectionMethod | (GetGadgetState(BordersButton) * #SGI_Borders)
SGI_ShowSelectionMethod | (GetGadgetState(SystemColorButton) * #SGI_SystemColor)
SGI_ShowSelectionMethod | (GetGadgetState(ShadeButton) * #SGI_ShadeBackground)
RefreshGadget(LVColor)
RefreshGadget(CBColor)
EndSelect
Case #PB_Event_CloseWindow
Break
EndSelect
ForEver
CloseWindow(DemoWindow)
EndIf
CompilerEndIf