Associate named properties with gadgets (requires PB 4.50)
Posted: Thu May 06, 2010 3:50 pm
PB provides Set/GetGadgetData() to associate a single custom value with any PB gadget. This code shows a simple way to extend this to store any number of named properties in a gadget using the 4.50 maps in structure feature. This mimics the Windows API Set/GetProp_() functions, but it works on all platforms. It is also easy to modify to store other things like strings in these properties.
When you free a gadget with properties on it, call RemoveAllProps() first to clean up the associated memory as well. You can also just call ClearList(AllPropMaps()) to clean up everything, but then the pointers stored in SetGadgetData() will be wrong, so only do it when you destroy all gadgets as well.
When you free a gadget with properties on it, call RemoveAllProps() first to clean up the associated memory as well. You can also just call ClearList(AllPropMaps()) to clean up everything, but then the pointers stored in SetGadgetData() will be wrong, so only do it when you destroy all gadgets as well.
Code: Select all
; Structure to store the property map. You can easily modify this to store other stuff than just an integer value
; A pointer to this structure is stored with Set/GetGadgetData() for every gadget that you set properties on
;
Structure PropMap
Map Props.i()
EndStructure
; Store all the Map structures in a global list. This way a simple ClearList() cleans everything up, and
; there is no need to worry about things like Initialize/ClearStructure() which we would have to do for
; allocated memory blocks
;
Global NewList AllPropMaps.PropMap()
; Helper function:
; Returns the PropMap structure for #Gadget, Create specifies wether or not to create
; one if none exists.
;
Procedure GetPropMap(Gadget, Create)
*PropMap.PropMap = GetGadgetData(Gadget)
If *PropMap = 0 And Create
AddElement(AllPropMaps())
*PropMap = @AllPropMaps()
SetGadgetData(Gadget, *PropMap)
EndIf
ProcedureReturn *PropMap
EndProcedure
; Set a property on the given #Gadget
;
Procedure SetProp(Gadget, Name$, Value)
*PropMap.PropMap = GetPropMap(Gadget, #True)
*PropMap\Props(Name$) = Value
EndProcedure
; Get a property from the given #Gadget. Returns 0 if the property does not exist
;
Procedure GetProp(Gadget, Name$)
*PropMap.PropMap = GetPropMap(Gadget, #False)
If *PropMap
ProcedureReturn *PropMap\Props(Name$)
Else
ProcedureReturn 0
EndIf
EndProcedure
; Remove a peoperty from the given #Gadget (if it exists)
;
Procedure RemoveProp(Gadget, Name$)
*PropMap.PropMap = GetPropMap(Gadget, #False)
If *PropMap
DeleteMapElement(*PropMap\Props(), Name$)
EndIf
EndProcedure
; Remove all properties (and the map) from a given #Gadget.
; This should be called before FreeGadget() to make sure there are no leaks
;
Procedure RemoveAllProps(Gadget)
*PropMap.PropMap = GetPropMap(Gadget, #False)
If *PropMap
ChangeCurrentElement(AllPropMaps(), *PropMap)
DeleteElement(AllPropMaps())
SetGadgetData(Gadget, 0)
EndIf
EndProcedure
; Example
;
Enumeration
#Spin1
#Spin2
#Text1
#Text2
EndEnumeration
If OpenWindow(0, 0, 0, 210, 100, "SpinGadget", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)
SpinGadget(#Spin1, 20, 20, 80, 25, 0, 100, #PB_Spin_Numeric)
SpinGadget(#Spin2, 20, 55, 80, 25, 0, 100, #PB_Spin_Numeric)
TextGadget(#Text1, 110, 20, 80, 25, "", #PB_Text_Border)
TextGadget(#Text2, 110, 55, 80, 25, "", #PB_Text_Border)
SetProp(#Spin1, "TextGadget", #Text1)
SetProp(#Spin1, "Multiplier", 5)
SetGadgetState(#Spin1, 0)
SetProp(#Spin2, "TextGadget", #Text2)
SetProp(#Spin2, "Multiplier", 10)
SetGadgetState(#Spin2, 0)
Repeat
Event = WaitWindowEvent()
If Event = #PB_Event_Gadget
Gadget = EventGadget()
SetGadgetText(GetProp(Gadget, "TextGadget"), Str(GetGadgetState(Gadget) * GetProp(Gadget, "Multiplier")))
EndIf
Until Event = #PB_Event_CloseWindow
EndIf