Coloring Framework
Posted: Tue Dec 13, 2005 2:51 am
Code updated For 5.20+
I needed some coloring for my main project in the listicons and I couldn't use gonzal's stuff (don't ask) and figured it can't be hard to do the simple kind of coloring I need without needing a high powered library like purecolor.
So... here you are. I smashed this together today with some code I stole from srod and Sparkie and some of my own stuff. It's in it's infancy but I'm posting it to see if there's interest. I'll probably be adding some other features into it and could possibly add things in that other people want but it's currently just another side project for me until I get my main project done. So work will be a little slow on it. Right now only string, text and combobox gadgets are in. Oh, also listicons. Not many functions to them and not much error checking currently. Sorry
That's the main form I used for testing so save it as whatever you want. The next bit of code is the actual coloring stuff. I have it set as xColor.pb in the main form so you'll have to rename it there if you save it differently.
And there you have it. Let me know if you spot errors. This is my first stab at doing control coloring. Use it or not
And have fun 
Oh, for controls with only one possible color (string, text, etc...) use xcSetGadgetColor(). For the listicon, use xcSetGadgetItemColor(). Likewise, there's two different removing procedures: xcRemoveColor() and xcRemoveItemColor(). There's also a simple xcGetGadgetColor() that I may add an index version for the item controls.
I needed some coloring for my main project in the listicons and I couldn't use gonzal's stuff (don't ask) and figured it can't be hard to do the simple kind of coloring I need without needing a high powered library like purecolor.
So... here you are. I smashed this together today with some code I stole from srod and Sparkie and some of my own stuff. It's in it's infancy but I'm posting it to see if there's interest. I'll probably be adding some other features into it and could possibly add things in that other people want but it's currently just another side project for me until I get my main project done. So work will be a little slow on it. Right now only string, text and combobox gadgets are in. Oh, also listicons. Not many functions to them and not much error checking currently. Sorry

Code: Select all
; By Xombie - 12/12/2005
;
Enumeration ; Window List
#WindowMain
EndEnumeration
Enumeration ; Menu List
#MenuMain
EndEnumeration
Enumeration ; Control List
#ButtonTest
#StringTest
#TextTest
#ComboTest
#ListTest
EndEnumeration
;- Includes
XIncludeFile "xColor.pb"
;
;- Callback
Procedure.l WindowCallback(HandleWindow, Message, wParam, lParam)
; Main form callback procedure.
lResult.l = #PB_ProcessPureBasicEvents
;
lResult = xc_HandleEvents(HandleWindow, Message, wParam, lParam, lResult)
;
ProcedureReturn lResult
;
EndProcedure
;-
;
DoQuit.b
;
If OpenWindow(#WindowMain, 100, 300, 300, 200, "Test", #PB_Window_SystemMenu | #PB_Window_MinimizeGadget | #PB_Window_MaximizeGadget)
;
; AdvancedGadgetEvents(#True)
StringGadget(#StringTest, 0, 0, 100, 20, "")
TextGadget(#TextTest, GadgetX(#StringTest) + GadgetWidth(#StringTest) + 1, GadgetY(#StringTest), 100, 20, "Test Text")
ComboBoxGadget(#ComboTest, GadgetX(#StringTest), GadgetY(#StringTest) + GadgetHeight(#StringTest) + 1, 100, 200)
ButtonGadget(#ButtonTest, GadgetX(#ComboTest), GadgetY(#ComboTest) + GadgetHeight(#ComboTest) + 1, 100, 20, "Test")
ListIconGadget(#ListTest, GadgetX(#TextTest), GadgetY(#TextTest) + GadgetHeight(#TextTest) + 1, 150, 100, "One", 50)
; EndIf
;
AddGadgetItem(#ComboTest, -1, "Test01")
AddGadgetItem(#ComboTest, -1, "Test02")
AddGadgetItem(#ComboTest, -1, "Test03")
AddGadgetItem(#ComboTest, -1, "Test04")
;
AddGadgetColumn(#ListTest, 1, "Two", 50)
AddGadgetItem(#ListTest, -1, "Blah" + Chr(10) + "Blah2")
AddGadgetItem(#ListTest, -1, "Test" + Chr(10) + "Test2")
AddGadgetItem(#ListTest, -1, "Test3" + Chr(10) + "Test4")
AddGadgetItem(#ListTest, -1, "Test5" + Chr(10) + "Test6")
AddGadgetItem(#ListTest, -1, "Test7" + Chr(10) + "Test8")
AddGadgetItem(#ListTest, -1, "Test9" + Chr(10) + "Test10")
;
SetWindowCallback(@WindowCallback())
;
xcSetGadgetColor(#StringTest, RGB(0, 0, 0), RGB(255, 0, 0))
xcSetGadgetColor(#TextTest, RGB(0, 64, 128), RGB(128, 64, 0))
xcSetGadgetItemColor(#ListTest, 1, RGB(0, 0, 255), RGB(128, 128, 0))
xcSetGadgetItemColor(#ListTest, 4, -1, RGB(128, 128, 0))
;
Repeat
;
EventID.l = WaitWindowEvent()
;
If EventID = #PB_Event_CloseWindow ; If the user has pressed on the close button
;
DoQuit = #True
;
ElseIf EventID = #PB_Event_Gadget
;
If EventGadget() = #ButtonTest
;
If EventType() = #PB_EventType_LeftClick
xcRemoveColor(#StringTest)
xcSetGadgetColor(#TextTest, RGB(0, 0, 0), RGB(64, 64, 0))
xcSetGadgetColor(#ComboTest, RGB(0, 64, 0), 0)
xcRemoveItemColor(#ListTest, 1)
xcSetGadgetItemColor(#ListTest, 2, 0, RGB(255, 255, 255))
EndIf
;
EndIf
;
EndIf
;
Until DoQuit = #True
EndIf
xcDestroy()
; Free the memory used by all of the controls.
End
Code: Select all
; By Xombie - 12/12/2005
;- Constants
#CDDS_ITEM = $10000
#CDDS_SUBITEM = $20000
#CDDS_PREPAINT = $1
#CDDS_ITEMPREPAINT = #CDDS_ITEM | #CDDS_PREPAINT
#CDDS_SUBITEMPREPAINT = #CDDS_SUBITEM | #CDDS_ITEMPREPAINT
#CDRF_DODEFAULT = $0
#CDRF_NOTIFYITEMDRAW = $20
#CDRF_NOTIFYSUBITEMDRAW = $20
#CDRF_NEWFONT = $2
;- Enumeration
Enumeration ; Control Type Enumeration
#xColor_Text
#xColor_String
#xColor_Combo
#xColor_ListIcon
EndEnumeration
;- Structures
Structure s_xColor_Colors
;
Index.l
; The zero index of the item to color.
ColorBack.l
; The background color for the item.
ColorFore.l
; The foreground color (text) of the item.
HandleBrush.l
; Handle of brush used to paint the background of a control.
EndStructure
Structure s_xColor_Controls
;
Identifier.l
; The PB identifier for the control.
Handle.l
; The handle for the control.
CallBack.l
; The old callback for the control.
Type.b
; The type of control.
Colors.l
; Pointer to an array of colors. For controls like buttons, there will only ever be one item in the array. Only items
; like listicons will have more than one item to allow for colors per item.
Size.l
; The size of the color array.
Count.l
; The count of items in the color array.
EndStructure
Structure s_xColor_Main
;
Controls.l
; Pointer to an array of controls.
Size.l
; Size of the control array.
Count.l
; Count of controls in the array.
EndStructure
;- Global Variables
Global _xColor.s_xColor_Main
; Pointer to an array of s_xColor structures.
;- Private Procedures
Procedure.b xc_GetGadgetType(Handle.l)
; Return the gadget type based on the classname used in CreateWindowExW_()
HoldString.s
; This will store the length of the wide character string, in characters.
lCount.l
; Used to store the number of character copied.
HoldString = Space(255)
; Allocate size for our string.
GetClassName_(Handle, @HoldString, 255)
; Call our function to retrieve the classname.
If HoldString = "Edit"
ProcedureReturn #xColor_String
ElseIf HoldString = "Static"
ProcedureReturn #xColor_Text
ElseIf HoldString = "ComboBox"
ProcedureReturn #xColor_Combo
ElseIf HoldString = "SysListView32"
ProcedureReturn #xColor_ListIcon
EndIf
;
EndProcedure
;- Private Procedures
Procedure.l xc_ColorFromHandle(Handle.l, Index.l)
; This will return the back color brush handle for a control and, alternately, for an item in the control.
;
*HoldColor.s_xColor_Colors
;
*HoldControl.s_xColor_Controls
;
If _xColor\Controls
; Ensure some controls exist within the array.
*Position = _xColor\Controls
While *Position - _xColor\Controls < _xColor\Size
; Loop through the controls.
*HoldControl = PeekL(*Position)
; Fill the control structure with the current control.
If Handle = *HoldControl\Handle
; lParam should be the handle to the control receiving the event. Check against the current control in the array.
ProcedureReturn PeekL(*HoldControl\Colors)
; Return the pointer to the color structure.
EndIf
;
*Position + 4
;
Wend
;
EndIf
;
EndProcedure
Procedure.l xc_ControlFromHandle(Handle.l)
; This will return the back color brush handle for a control and, alternately, for an item in the control.
;
*HoldControl.s_xColor_Controls
;
If _xColor\Controls
; Ensure some controls exist within the array.
*Position = _xColor\Controls
While *Position - _xColor\Controls < _xColor\Size
; Loop through the controls.
*HoldControl = PeekL(*Position)
; Fill the control structure with the current control.
If Handle = *HoldControl\Handle : ProcedureReturn *HoldControl : EndIf
;
*Position + 4
;
Wend
;
EndIf
;
EndProcedure
Procedure xc_DeleteColor(IndexControl.l, IndexItem.l)
; Used to remove a color from a specific line in a multi-line control.
;
EndProcedure
Procedure.b xc_GetRowColors(*HoldControl.s_xColor_Controls, Index.l, *ColorBack, *ColorFore)
;
;
*HoldColor.s_xColor_Colors
;
*Position = *HoldControl\Colors
While *Position - *HoldControl\Colors < *HoldControl\Size
;
*HoldColor = PeekL(*Position)
;
If *HoldColor\Index = Index
;
PokeL(*ColorBack, *HoldColor\ColorBack)
PokeL(*ColorFore, *HoldColor\ColorFore)
;
ProcedureReturn #True
;
EndIf
;
*Position + 4
;
Wend
;
ProcedureReturn #False
;
EndProcedure
;- Callbacks
Procedure.l xc_HandleComboEvents(HandleWindow.l, Message.l, wParam.l, lParam.l)
; Custom callback for combobox controls.
lResult.l
;
*HoldColor.s_xColor_Colors
;
*HoldControl.s_xColor_Controls
;
*HoldControl = xc_ControlFromHandle(HandleWindow)
;
If Message = #WM_CTLCOLORLISTBOX
;
*HoldColor = xc_ColorFromHandle(HandleWindow, -1)
; Return the pointer to the color array for the control.
If *HoldColor
; Ensure the control exists in the color array.
SetBkMode_(wParam, #TRANSPARENT)
;
SetTextColor_(wParam, *HoldColor\ColorFore)
; Set the foreground color for the button.
SetBkColor_(wParam, *HoldColor\ColorBack)
; The above line is borrowed a little from Sparkie. ( http://forums.purebasic.com/english/viewtopic.php?t=17426 )
lResult = *HoldColor\HandleBrush
; Return the handle to the color brush to show that the message was processed.
EndIf
;
Else
;
lResult = CallWindowProc_(*HoldControl\CallBack, HandleWindow, Message, wParam, lParam)
;
EndIf
;
ProcedureReturn lResult
;
EndProcedure
Procedure.l xc_HandleEvents(HandleWindow.l, Message.l, wParam.l, lParam.l, lResult.l)
;
HoldHandle.l
;
HoldFore.l : HoldBack.l
;
*HoldColor.s_xColor_Colors
;
*HoldControl.s_xColor_Controls
;
Protected Column, Row
;
Protected *pnmh.NMHDR, *LVCDHeader.NMLVCUSTOMDRAW
;
If Message = #WM_NOTIFY
;
*pnmh = lParam
;
If *pnmh\code = #NM_CUSTOMDRAW
; ListIcon custom draw code borrowed and modified from srod's code ( http://forums.purebasic.com/english/viewtopic.php?t=17662 )
*HoldControl = xc_ControlFromHandle(*pnmh\hwndFrom)
;
If *HoldControl
;
*LVCDHeader = lParam
;
If *LVCDHeader\nmcd\dwDrawStage = #CDDS_PREPAINT
;
lResult = #CDRF_NOTIFYITEMDRAW
;
ElseIf *LVCDHeader\nmcd\dwDrawStage = #CDDS_ITEMPREPAINT
;
lResult = #CDRF_NOTIFYSUBITEMDRAW
;
ElseIf *LVCDHeader\nmcd\dwDrawStage = #CDDS_SUBITEMPREPAINT
;
Row = *LVCDHeader\nmcd\dwItemSpec
;
Column = *LVCDHeader\iSubItem
;/
If xc_GetRowColors(*HoldControl, Row, @HoldBack, @HoldFore)
;
*LVCDHeader\clrTextBk = HoldBack
*LVCDHeader\clrText = HoldFore
;
lResult = #CDRF_NEWFONT
;
EndIf
;/
; If Column = 0
; *LVCDHeader\clrTextBk = #green
; *LVCDHeader\clrText = #blue ;Text colour
; Else
; *LVCDHeader\clrTextBk = #yellow
; *LVCDHeader\clrText = #red
; EndIf
;/
;
EndIf
;
EndIf
;
EndIf
;
ElseIf Message = #WM_CTLCOLOREDIT Or Message = #WM_CTLCOLORSTATIC
; Test for a string or text color event.
HoldHandle = lParam
;
*HoldControl = xc_ControlFromHandle(HoldHandle)
;
If *HoldControl
;
*HoldColor = xc_ColorFromHandle(HoldHandle, -1)
; Return the pointer to the color array for the control.
If *HoldColor
; Ensure the control exists in the color array.
SetBkMode_(wParam, #TRANSPARENT)
;
SetTextColor_(wParam, *HoldColor\ColorFore)
; Set the foreground color for the button.
If *HoldControl\Type = #xColor_Combo : SetBkColor_(wParam, *HoldColor\ColorBack) : EndIf
; The above line is borrowed a little from Sparkie. ( http://forums.purebasic.com/english/viewtopic.php?t=17426 ).
; Modified to work with these custom comboboxes. This will force a display of the color even if the combobox is
; not currently editable.
ProcedureReturn *HoldColor\HandleBrush
; Return the handle to the color brush to show that the message was processed.
EndIf
;
EndIf
;
EndIf
;
ProcedureReturn lResult
;
EndProcedure
;- Public Procedures
Procedure xcSetGadgetColor(Gadget.l, ColorBack.l, ColorFore.l)
;
; Position pointer within the array.
NewArray.l
; Array used to store new information.
; Pointer to the new array.
ExistsControl.b
; True if the control already exists in the array.
Handle.l
; The handle to the control.
Type.b
; Temporarily store the type of the control.
*HoldControl.s_xColor_Controls
; Pointer to new control structure.
*HoldColor.s_xColor_Colors
; Pointer to new color structure.
HoldStyle.l
; Used to store the previous style for the control.
Handle = GadgetID(Gadget)
; Store the handle to the control.
Type = xc_GetGadgetType(Handle)
; Retrieve the type of the control.
If Type <> #xColor_Combo And Type <> #xColor_String And Type <> #xColor_Text : MessageRequester("Error!", "Please use xcSetGadgetItemText() to set the color for a listicon.", #PB_MessageRequester_Ok) : ProcedureReturn : EndIf
;
If _xColor\Controls
; Controls exist within the array.
*Position = _xColor\Controls
While *Position - _xColor\Controls < _xColor\Size
; Begin looping through the existing controls.
*HoldControl = PeekL(*Position)
; Fill the control structure with the current control.
If *HoldControl\Identifier = Gadget : ExistsControl = #True : Break : EndIf
; Check if the control already exists in the array.
*Position + 4
;
Wend
;
If ExistsControl
; The control already exists in the array. Update with new color information.
*HoldColor = PeekL(*HoldControl\Colors)
; For non-item controls, there is only 1 color in the array. The first element. Fill the color structure with this information.
If ColorBack <> *HoldColor\ColorBack
; New back color. Update.
*HoldColor\ColorBack = ColorBack
; Store the new background color.
If *HoldColor\HandleBrush : DeleteObject_(*HoldColor\HandleBrush) : EndIf
; Delete the previous brush if it exists.
*HoldColor\HandleBrush = CreateSolidBrush_(ColorBack)
; Create the brush used to color the background.
EndIf
;
If ColorFore <> -1 : *HoldColor\ColorFore = ColorFore : EndIf
; Update the foreground (text) color information.
Else
; The control does not exist in the array.
NewArray = AllocateMemory(_xColor\Size + 4)
; Allocate room for the new control.
CopyMemory(_xColor\Controls, NewArray, _xColor\Size)
; Copy the existing control information into the new array.
*HoldControl = AllocateMemory(SizeOf(s_xColor_Controls))
; Allocate memory for the new control structure.
*HoldControl\Identifier = Gadget
*HoldControl\Handle = Handle
*HoldControl\Type = Type
;
If *HoldControl\Type = #xColor_Combo : *HoldControl\CallBack = SetWindowLong_(Handle, #GWL_WNDPROC, @xc_HandleComboEvents()) : EndIf
; Combobox requires a custom callback handler.
*HoldColor = AllocateMemory(SizeOf(s_xColor_Colors))
;
*HoldColor\Index = -1
; Non-item controls store no index.
*HoldColor\ColorBack = ColorBack
; Store the back color for the control.
*HoldColor\ColorFore = ColorFore
; Store the foreground (text) color for the control.
*HoldColor\HandleBrush = CreateSolidBrush_(ColorBack)
; Create the brush used to color the background.
*HoldControl\Colors = AllocateMemory(4)
; Allocate 4 bytes to store the color information for the control.
PokeL(*HoldControl\Colors, *HoldColor)
; Insert the color structure pointer in the control structure.
*HoldControl\Size = 4 : *HoldControl\Count = 1
; There is now 1 color for the control and it consumes 4 bytes of memory.
PokeL(NewArray + _xColor\Size, *HoldControl)
; Insert the control information into the new array.
FreeMemory(_xColor\Controls) : _xColor\Controls = NewArray
; Free the previous control array and set to the new array.
_xColor\Size + 4 : _xColor\Count + 1
; Increment the control size and count values for the new control.
EndIf
;
Else
; No controls exist in the array.
_xColor\Controls = AllocateMemory(4)
;
*HoldControl = AllocateMemory(SizeOf(s_xColor_Controls))
;
*HoldControl\Identifier = Gadget
*HoldControl\Handle = Handle
*HoldControl\Type = Type
;
If *HoldControl\Type = #xColor_Combo : *HoldControl\CallBack = SetWindowLong_(Handle, #GWL_WNDPROC, @xc_HandleComboEvents()) : EndIf
; Combobox requires a custom callback handler.
*HoldColor = AllocateMemory(SizeOf(s_xColor_Colors))
;
*HoldColor\Index = -1
; Non-item controls store no index.
*HoldColor\ColorBack = ColorBack
; Store the back color for the control.
*HoldColor\ColorFore = ColorFore
; Store the foreground (text) color for the control.
*HoldColor\HandleBrush = CreateSolidBrush_(ColorBack)
; Create the brush used to color the background.
*HoldControl\Colors = AllocateMemory(4)
; Allocate 4 bytes to store the color information for the control.
PokeL(*HoldControl\Colors, *HoldColor)
; Insert the color structure pointer in the control structure.
*HoldControl\Size = 4 : *HoldControl\Count = 1
; There is now 1 color for the control and it consumes 4 bytes of memory.
PokeL(_xColor\Controls, *HoldControl)
; Insert the pointer to the control into the array.
_xColor\Size = 4 : _xColor\Count = 1
; The initial control is added. One item now exists and it takes up 4 bytes of memory.
EndIf
;
InvalidateRect_(Handle, 0, #True)
; Invalidate the control. This will force a redraw of the control.
EndProcedure
Procedure xcSetGadgetItemColor(Gadget.l, Index.l, ColorBack.l, ColorFore.l)
; Set the color for a specific row in control. Currently only for listicons.
; Position pointer within the array.
NewArray.l
; Array used to store new information.
; Pointer to the new array.
ExistsControl.b
; True if the control already exists in the array.
Handle.l
; The handle to the control.
Type.b
; Temporarily store the type of the control.
*HoldControl.s_xColor_Controls
; Pointer to new control structure.
*HoldColor.s_xColor_Colors
; Pointer to new color structure.
HoldStyle.l
; Used to store the previous style for the control.
Handle = GadgetID(Gadget)
; Store the handle to the control.
Type = xc_GetGadgetType(Handle)
; Retrieve the type of the control.
If Type <> #xColor_ListIcon : MessageRequester("Error!", "Please use xcSetGadgetColor() for gadgets other than ListIcon()") : EndIf
;
If _xColor\Controls
; Controls exist within the array.
*Position = _xColor\Controls
While *Position - _xColor\Controls < _xColor\Size
; Begin looping through the existing controls.
*HoldControl = PeekL(*Position)
; Fill the control structure with the current control.
If *HoldControl\Identifier = Gadget : ExistsControl = #True : Break : EndIf
; Check if the control already exists in the array.
*Position + 4
;
Wend
;
If ExistsControl
; The control already exists in the array. Update with new color information.
*Position = *HoldControl\Colors
While *Position - *HoldControl\Colors < *HoldControl\Size
;
*HoldColor = PeekL(*Position)
;
If *HoldColor\Index = Index
; Located the passed index within the control.
*HoldColor\ColorBack = ColorBack
; A -1 means the back color should not be changed.
*HoldColor\ColorFore = ColorFore
; Update the foreground (text) color information.
ProcedureReturn
; Exit the procedure.
EndIf
;
*Position + 4
;
Wend
; After this point, the index did not exist in the control. Add the new index and it's color.
NewArray = AllocateMemory(*HoldControl\Size + 4)
;
CopyMemory(*HoldControl\Colors, NewArray, *HoldControl\Size)
;
*HoldColor = AllocateMemory(SizeOf(s_xColor_Colors))
;
*HoldColor\Index = Index
;
*HoldColor\ColorBack = ColorBack
; Store the back color for the control.
*HoldColor\ColorFore = ColorFore
; Store the foreground (text) color for the control.
*HoldColor\HandleBrush = 0
;
PokeL(NewArray + *HoldControl\Size, *HoldColor)
; Insert the color structure pointer in the control structure.
FreeMemory(*HoldControl\Colors) : *HoldControl\Colors = NewArray
;
*HoldControl\Size + 4 : *HoldControl\Count + 1
; There is now 1 color for the control and it consumes 4 bytes of memory.
Else
; The control does not exist in the array.
NewArray = AllocateMemory(_xColor\Size + 4)
; Allocate room for the new control.
CopyMemory(_xColor\Controls, NewArray, _xColor\Size)
; Copy the existing control information into the new array.
*HoldControl = AllocateMemory(SizeOf(s_xColor_Controls))
; Allocate memory for the new control structure.
*HoldControl\Identifier = Gadget
*HoldControl\Handle = Handle
*HoldControl\Type = Type
;
If *HoldControl\Type = #xColor_Combo : *HoldControl\CallBack = SetWindowLong_(Handle, #GWL_WNDPROC, @xc_HandleComboEvents()) : EndIf
; Combobox requires a custom callback handler.
*HoldColor = AllocateMemory(SizeOf(s_xColor_Colors))
;
*HoldColor\Index = Index
;
*HoldColor\ColorBack = ColorBack
; Store the back color for the control.
*HoldColor\ColorFore = ColorFore
; Store the foreground (text) color for the control.
*HoldColor\HandleBrush = 0
; Create the brush used to color the background.
*HoldControl\Colors = AllocateMemory(4)
; Allocate 4 bytes to store the color information for the control.
PokeL(*HoldControl\Colors, *HoldColor)
; Insert the color structure pointer in the control structure.
*HoldControl\Size = 4 : *HoldControl\Count = 1
; There is now 1 color for the control and it consumes 4 bytes of memory.
PokeL(NewArray + _xColor\Size, *HoldControl)
; Insert the control information into the new array.
FreeMemory(_xColor\Controls) : _xColor\Controls = NewArray
; Free the previous control array and set to the new array.
_xColor\Size + 4 : _xColor\Count + 1
; Increment the control size and count values for the new control.
EndIf
;
Else
; No controls exist in the array.
_xColor\Controls = AllocateMemory(4)
;
*HoldControl = AllocateMemory(SizeOf(s_xColor_Controls))
;
*HoldControl\Identifier = Gadget
*HoldControl\Handle = Handle
*HoldControl\Type = Type
;
If *HoldControl\Type = #xColor_Combo : *HoldControl\CallBack = SetWindowLong_(Handle, #GWL_WNDPROC, @xc_HandleComboEvents()) : EndIf
; Combobox requires a custom callback handler.
*HoldColor = AllocateMemory(SizeOf(s_xColor_Colors))
;
*HoldColor\Index = Index
;
*HoldColor\ColorBack = ColorBack
; Store the back color for the control.
*HoldColor\ColorFore = ColorFore
; Store the foreground (text) color for the control.
*HoldColor\HandleBrush = 0
; Create the brush used to color the background.
*HoldControl\Colors = AllocateMemory(4)
; Allocate 4 bytes to store the color information for the control.
PokeL(*HoldControl\Colors, *HoldColor)
; Insert the color structure pointer in the control structure.
*HoldControl\Size = 4 : *HoldControl\Count = 1
; There is now 1 color for the control and it consumes 4 bytes of memory.
PokeL(_xColor\Controls, *HoldControl)
; Insert the pointer to the control into the array.
_xColor\Size = 4 : _xColor\Count = 1
; The initial control is added. One item now exists and it takes up 4 bytes of memory.
EndIf
;
InvalidateRect_(Handle, 0, #True)
; Invalidate the control. This will force a redraw of the control.
EndProcedure
Procedure xcRemoveItemColor(Gadget.l, Index.l)
;
;
Handle.l
;
ExistsIndex.b
;
;
*HoldColor.s_xColor_Colors
;
*HoldControl.s_xColor_Controls
;
*HoldControl = xc_ControlFromHandle(GadgetID(Gadget))
; Fill the control structure with information about the control.
If *HoldControl = 0 : ProcedureReturn : EndIf
; Ensure the control exists in the array.
If *HoldControl\Count = 0 : ProcedureReturn : EndIf
; There must be colored items to remove.
If *HoldControl\Type <> #xColor_ListIcon : ProcedureReturn : EndIf
; Can only currently remove color from items in a listicon.
*Position = *HoldControl\Colors
While *Position - *HoldControl\Colors < *HoldControl\Size
;
*HoldColor = PeekL(*Position)
;
If *HoldColor\Index = Index : ExistsIndex = #True : Break : EndIf
;
*Position + 4
;
Wend
;
If ExistsIndex
;
If *HoldControl\Count = 1
; Only one item in the control.
FreeMemory(*HoldColor)
;
FreeMemory(*HoldControl\Colors) : *HoldControl\Colors = 0
;
*HoldControl\Size = 0 : *HoldControl\Count = 0
;
Else
;
NewArray = AllocateMemory(*HoldControl\Size - 4)
;
*NewPosition = NewArray
;
*Position = *HoldControl\Colors
While *Position - *HoldControl\Colors < *HoldControl\Size
;
*HoldColor = PeekL(*Position)
;
If *HoldColor\Index <> Index
;
PokeL(*NewPosition, *HoldColor)
;
*NewPosition + 4
;
Else
;
FreeMemory(*HoldColor)
;
EndIf
;
*Position + 4
;
Wend
;
FreeMemory(*HoldControl\Colors) : *HoldControl\Colors = NewArray
;
*HoldControl\Size - 4 : *HoldControl\Count - 1
;
EndIf
;
EndIf
;
InvalidateRect_(*HoldControl\Handle, 0, #True)
; Invalidate the control. This will force a redraw of the control.
EndProcedure
Procedure.l xcGetGadgetColor(Gadget.l, RetrieveBackColor.b)
; This will return the back color (if RetrieveBackColor is True) or the fore color (if RetrieveBackColor is False) for a control.
*HoldColor.s_xColor_Colors
;
*HoldControl.s_xColor_Controls
;
*HoldControl = xc_ControlFromHandle(GadgetID(Gadget))
;
If *HoldControl
;
If *HoldControl\Type = #xColor_Text Or *HoldControl\Type = #xColor_String Or *HoldControl\Type = #xColor_Combo
; Single Item Control.
*HoldColor = PeekL(*HoldControl\Colors)
;
If RetrieveBackColor : ProcedureReturn *HoldColor\ColorBack : Else : ProcedureReturn *HoldColor\ColorFore : EndIf
;
Else
; Multiple Item Control.
;
EndIf
;
EndIf
;
EndProcedure
Procedure xcRemoveColor(Gadget.l)
; This will remove any user defined color from a control.
;
Handle.l
;
;
*HoldColor.s_xColor_Colors
;
*HoldControl.s_xColor_Controls
;
If _xColor\Controls = 0 : ProcedureReturn : EndIf
; Ensure custom colors exist.
*HoldControl = xc_ControlFromHandle(GadgetID(Gadget))
; Fill the control structure with information about the control.
If *HoldControl = 0 : ProcedureReturn : EndIf
; Ensure the control exists in the array.
Handle = *HoldControl\Handle
; Store the handle to the control so it can be redrawn later.
If *HoldControl\Type = #xColor_Text Or *HoldControl\Type = #xColor_String Or *HoldControl\Type = #xColor_Combo
; Single Item Control.
*HoldColor = PeekL(*HoldControl\Colors)
;
If *HoldColor\HandleBrush : DeleteObject_(*HoldColor\HandleBrush) : EndIf
;
FreeMemory(*HoldColor)
;
FreeMemory(*HoldControl\Colors)
;
If *HoldControl\CallBack : SetWindowLong_(*HoldControl\Handle, #GWL_WNDPROC, *HoldControl\CallBack) : EndIf
;
FreeMemory(*HoldControl)
;
If _xColor\Count = 1
; This was the only control in the array.
FreeMemory(_xColor\Controls) : _xColor\Controls = 0
; Free the memory used to store the control array.
_xColor\Count = 0 : _xColor\Size = 0
; Reset the count and size to zero.
Else
;
NewArray = AllocateMemory(_xColor\Size - 4)
;
*NewPosition = NewArray
;
*Position = _xColor\Controls
;
While *Position - _xColor\Controls < _xColor\Size
;
If PeekL(*Position) <> *HoldControl
;
PokeL(*NewPosition, PeekL(*Position))
;
*NewPosition + 4
;
EndIf
;
*Position + 4
;
Wend
;
FreeMemory(_xColor\Controls) : _xColor\Controls = NewArray
;
EndIf
;
Else
; Multiple Item Control.
;
EndIf
;
InvalidateRect_(Handle, 0, #True)
; Invalidate the control. This will force a redraw of the control.
EndProcedure
Procedure xcDestroy()
; Used to free the memory used by all the colored controls.
;
*HoldColor.s_xColor_Colors
;
*HoldControl.s_xColor_Controls
;
If _xColor\Controls
;
*Position = _xColor\Controls
While *Position - _xColor\Controls < _xColor\Size
;
*HoldControl = PeekL(*Position)
;
If *HoldControl\Colors
;
*PositionSub = *HoldControl\Colors
While *PositionSub - *HoldControl\Colors < *HoldControl\Size
;
*HoldColor = PeekL(*PositionSub)
;
If *HoldControl\CallBack : SetWindowLong_(*HoldControl\Handle, #GWL_WNDPROC, *HoldControl\CallBack) : EndIf
; Remove any custom callback procedures from the control.
If *HoldColor\HandleBrush : DeleteObject_(*HoldColor\HandleBrush) : EndIf
;
FreeMemory(*HoldColor)
;
*PositionSub + 4
;
Wend
;
EndIf
;
FreeMemory(*HoldControl\Colors)
;
FreeMemory(*HoldControl)
;
*Position + 4
;
Wend
;
EndIf
;
FreeMemory(_xColor\Controls)
;
EndProcedure


Oh, for controls with only one possible color (string, text, etc...) use xcSetGadgetColor(). For the listicon, use xcSetGadgetItemColor(). Likewise, there's two different removing procedures: xcRemoveColor() and xcRemoveItemColor(). There's also a simple xcGetGadgetColor() that I may add an index version for the item controls.