which isn't possible for 100% as on Windows the behavior of gadgets is a little different. and there (on Windows) it has some glitches... I hope someone with more Win-API knowledge
can help to solve the problems.... But also everybody is invited to help to improve this gadget for the benefit of the PB-Community

Maybe someone with a Mac (Michel51?) could test this ....
A small explanation is included at the top
The point where the code needs to be changed (Windows) is located at line 265. The small api I'd implemented helps a bit to minimize the glitches on Windows...
but if your mouse is over the checkboxgadget created outside of the Expander... it will pop up into the foreground...:roll:
On Linux It's working like a charm....

The code
Code: Select all
;- ExpanderGadget
; 2008 by walker
;
;--------------------------------------------
;-free for everyone and any purposes
;-enhancements made by others
;-must be published and posted in the same PB-Forum ;-)
;-cross plattform ability must be achieved
;---Instructions---------------------------
; first set up a variable with 'expander' as type and fill in some parameter (those marked with an * are a must;
; those marked with # are set automatically - DO NOT SET OR CHANGE THESE VALUES) or use ExpanderSetDafaults(@myexpander)
; parameters:
;# gadget_id = gadgetnumber from #pb_any after creation of the gadget
;* normal_image = image shown at first start (loadimage/catchimage/createimage can be used)
;* expanded_image = image shown if clicked and gadget will be "expanded" (loadimage/catchimage/createimage can be used)
;* nr = number of the gadget; to be used with its_gadget() function call
; backgroundcolor.l = color of the gadget's background - if you don't want to set an own color, you MUST set it to #pb_any
; fontnr.l = font to be used with this gadget (loadfont())
;* expandergroup.l = to identify goups of Expandergadgets... see example
;* gx = x-coordinate of the top left edge
;* gy = y-coordinate of the top left edge
;* gw = width of the gadget
;* gh =height of the gadget
;# container.l = container for the expander
; containerw.l = calculated... but can be changed
; containerh.l = calculated... but can be changed
;
; The next step is to create an ExpanderGadget with 'ExpanderGadget(@myExpanderGadget)'
; after this, add some gadgets to the previous created Expander with AddExpanderGadget(@myExpanderGadget.expander,Gadget_number,Type,x,y,width,height,text.s="",color=0
; where Type is one of 'optiongadget', 'checkboxgadget', 'textgadget' or 'hyperlinkgadget'
; and at least close this gadget with 'CloseExpanderGadget(@myExpanderGadget)'
;
;---Structures----------------------------
;{
Structure expander_gadget ; structure for each gadget within an ExpanderGadget
expander_gadget.l ; the parent expander gadget
gadget_id.l ; the gadgetid
nr.l ;the number of the gadget
gadgettype.s ;type of the gadget
gadgettext.s ; text for the gadget (optional)
color.l ;optional
gx.l ;x-coordinate of the gadget
gy.l ;y-coordinate of the gadget
gw.l ;width of the gadget
gh.l ;heigth of the gadget
EndStructure
Structure all_exp
gadget_id.l
group.l
EndStructure
Global NewList expander_gadgets.expander_gadget()
Structure expander ;structure for the ExpanderGadget
Gadget_id.l ;Gadgetnumber
normal_image.l ;imagenumber
expanded_image.l ;imagenumber
backgroundcolor.l ;color - if you don't want to set an own color, you MUST set it to #pb_any
textcolor.l ;color
gadgettext.s ;text
fontnr.l ;font-number
expandergroup.l ;
gx.l ;x-coordinate of the gadget
gy.l ;y-coordinate of the gadget
gw.l ;width of the gadget
gh.l ;heigth of the gadget
container.l ;container for the expander
containerw.l
containerh.l
EndStructure
Global NewList all_expander_gadgets.all_exp()
;}
;---internal procedures-----------------
Procedure _create_expander_image(*Gadget_.expander,state); to create the appropriate image
Select state
Case 1
img_to_use=*Gadget_\normal_image
Case 2
img_to_use=*Gadget_\expanded_image
EndSelect
If ImageWidth(img_to_use)>ImageHeight(img_to_use)
f=ImageWidth(img_to_use)/ImageHeight(img_to_use)
Else
f=ImageHeight(img_to_use)/ImageWidth(img_to_use)
EndIf
ResizeImage(img_to_use,*Gadget_\gh*f,*Gadget_\gh)
img_tmp=CreateImage(#PB_Any,*Gadget_\gw,*Gadget_\gh)
;determine backgroundcolor of the image
If *Gadget_\backgroundcolor=#PB_Any
StartDrawing(ImageOutput(img_to_use))
*Gadget_\backgroundcolor=Point(0,0)
StopDrawing()
EndIf
StartDrawing(ImageOutput(img_tmp))
DrawingFont(FontID(*Gadget_\fontnr))
FillArea(0,0,-1,*Gadget_\backgroundcolor)
DrawImage(ImageID(img_to_use),0,0)
DrawingMode(1)
DrawText(ImageWidth(img_to_use)+4,*Gadget_\gh/2-TextHeight(*Gadget_\gadgettext)/2,*Gadget_\gadgettext,*Gadget_\textcolor)
StopDrawing()
ProcedureReturn img_tmp
EndProcedure
Procedure _show_gadgets(*gadget_.expander,show.l); shows or hides all gadgets
ForEach expander_gadgets()
If *gadget_\Gadget_id=expander_gadgets()\expander_gadget
If *gadget_\container=#PB_Any ;if not created yet...
just_new=#True
;the following is workin on Linux... perfectely... but not on windows (gadgets below the container are raised if the mouse is over them....)
*gadget_\container=ContainerGadget(#PB_Any,*Gadget_\gx-2,*Gadget_\gy+*Gadget_\gh,*gadget_\containerw,*gadget_\containerh,#PB_Container_Double)
EndIf
Select LCase(expander_gadgets()\gadgettype)
Case "optiongadget"
If expander_gadgets()\gadget_id=#PB_Any
expander_gadgets()\gadget_id=OptionGadget(#PB_Any,expander_gadgets()\gx,expander_gadgets()\gy,expander_gadgets()\gw,expander_gadgets()\gh,expander_gadgets()\gadgettext)
EndIf
Case "checkboxgadget"
If expander_gadgets()\gadget_id=#PB_Any
expander_gadgets()\gadget_id=CheckBoxGadget(#PB_Any,expander_gadgets()\gx,expander_gadgets()\gy,expander_gadgets()\gw,expander_gadgets()\gh,expander_gadgets()\gadgettext)
EndIf
Case "stringgadget"
If expander_gadgets()\gadget_id=#PB_Any
expander_gadgets()\gadget_id=StringGadget(#PB_Any,expander_gadgets()\gx,expander_gadgets()\gy,expander_gadgets()\gw,expander_gadgets()\gh,expander_gadgets()\gadgettext)
EndIf
Case "textgadget"
If expander_gadgets()\gadget_id=#PB_Any
expander_gadgets()\gadget_id=TextGadget(#PB_Any,expander_gadgets()\gx,expander_gadgets()\gy,expander_gadgets()\gw,expander_gadgets()\gh,expander_gadgets()\gadgettext)
EndIf
Case "hyperlinkgadget"
If expander_gadgets()\gadget_id=#PB_Any
expander_gadgets()\gadget_id=HyperLinkGadget(#PB_Any,expander_gadgets()\gx,expander_gadgets()\gy,expander_gadgets()\gw,expander_gadgets()\gh,expander_gadgets()\gadgettext,expander_gadgets()\color)
EndIf
; could be extended with more gadgets... if needed
EndSelect
EndIf
Next
If just_new=#True
CloseGadgetList()
EndIf
If show=#True
HideGadget(*gadget_\container,#False)
SetGadgetData(*Gadget_\Gadget_id,*gadget_\expanded_image)
tmp_img=_create_expander_image(*gadget_,2)
SetGadgetState(*Gadget_\gadget_id,ImageID(tmp_img))
FreeImage(tmp_img)
Else
HideGadget(*gadget_\container,#True)
SetGadgetData(*Gadget_\Gadget_id,*gadget_\normal_image)
tmp_img=_create_expander_image(*gadget_,1)
SetGadgetState(*Gadget_\gadget_id,ImageID(tmp_img))
FreeImage(tmp_img)
EndIf
While WindowEvent():Wend
ProcedureReturn 1
EndProcedure
;---public procedures-------------------
Procedure ExpanderSetDefaults(*Gadget_.expander)
CompilerIf #PB_Compiler_OS = #PB_OS_Windows
*background = GetSysColor_(#COLOR_WINDOW)
*Gadget_\fontnr=LoadFont(#PB_Any,"Arial",10)
CompilerEndIf
;-TODO: determine the background color of a gtk window OR setting background to transparent
CompilerIf #PB_Compiler_OS = #PB_OS_Linux
*background=$F6F6F6
*Gadget_\fontnr=LoadFont(#PB_Any,"Sans",10)
CompilerEndIf
CompilerIf #PB_Compiler_OS = #PB_OS_MacOS
*background = $CFF6FD; just a guess --- how to get the background on a MAC?
*Gadget_\fontnr=LoadFont(#PB_Any,"Arial",10)
CompilerEndIf
*gadget_\backgroundcolor=*background
For img = 0 To 1
tmp_img=CreateImage(#PB_Any,16,16)
StartDrawing(ImageOutput(tmp_img))
FrontColor(*background)
Box(0,0,16,16)
If img = 0
Start=4
For a = 7 To 11
LineXY(Start,a-4,start,15-start,0)
Start+1
Next a
StopDrawing()
*Gadget_\normal_image=tmp_img
ElseIf img=1
Start=2
For a = 6 To 10
Line(Start,a,13-Start*2,0,0)
Start+1
Next a
StopDrawing()
*Gadget_\expanded_image=tmp_img
EndIf
Next
ProcedureReturn 1
EndProcedure
Procedure its_Gadget(gadgetid) ; check and return which gadget is processed
ForEach expander_gadgets()
If expander_gadgets()\nr=Gadgetid
ProcedureReturn expander_gadgets()\gadget_id
EndIf
Next
ProcedureReturn 0
EndProcedure
Procedure CloseExpanderGadget(*gadget_.expander); NECESSARY after adding all gadgets to an ExpanderGadget
;if not called, the gadgets weren't created !!!!!
maxw=0
maxh=0
maxy=0
maxx=0
ForEach expander_gadgets()
If *gadget_\Gadget_id=expander_gadgets()\expander_gadget
If maxw<expander_gadgets()\gw
maxw=expander_gadgets()\gw
EndIf
If maxy<expander_gadgets()\gy
maxy=expander_gadgets()\gy
EndIf
If maxh<expander_gadgets()\gh
maxh=expander_gadgets()\gh
EndIf
If maxx<expander_gadgets()\gx
maxx=expander_gadgets()\gx
EndIf
EndIf
Next
*gadget_\containerw=maxw+30
*gadget_\containerh=maxy+maxh*2
_show_gadgets(*gadget_,#False)
ProcedureReturn 1
EndProcedure
Procedure ExpanderGadget_clicked(*gadget_.expander); if one is clicked..
;process the actual clicked one
Select GetGadgetData(*gadget_\gadget_id)
Case *gadget_\normal_image
;normal state -> switch to expanded state
_show_gadgets(*gadget_,#True)
Case *gadget_\expanded_image
;expanded state > switch to normal state
_show_gadgets(*gadget_,#False)
EndSelect
;close all other expander
ForEach all_expander_gadgets()
If all_expander_gadgets()\gadget_id<>*gadget_ And all_expander_gadgets()\group=*gadget_\expandergroup
_show_gadgets(all_expander_gadgets()\gadget_id,#False)
EndIf
Next
;-TODO necessary on windows... on Linux the redraw is done by gtk+ correct
;not the best solution ... I guess.. but fairly working
;
CompilerIf #PB_Compiler_OS = #PB_OS_Windows
r.RECT
GetClientRect_(WindowID(0),r)
InvalidateRect_(WindowID(0),r,0)
CompilerEndIf
While WindowEvent():Wend
ProcedureReturn 1
EndProcedure
Procedure ExpanderGadget(*Gadget_.expander); creates an ExpanderGadget
tmp_img=_create_expander_image(*Gadget_,1)
*Gadget_\Gadget_id=ImageGadget(#PB_Any,*Gadget_\gx,*Gadget_\gy,*Gadget_\gw,*Gadget_\gh,ImageID(tmp_img))
SetGadgetData(*Gadget_\Gadget_id,*gadget_\normal_image)
*Gadget_\container=#PB_Any
FreeImage(tmp_img)
AddElement(all_expander_gadgets())
all_expander_gadgets()\gadget_id=*Gadget_
all_expander_gadgets()\group=*Gadget_\expandergroup
ProcedureReturn *Gadget_\Gadget_id; the Gadgetid for the Expander
EndProcedure
Procedure AddExpanderGadget(*Gadget_.expander,Gadget_number.l,Type.s,x.l,y.l,width.l,height.l,text.s="",color=0); adds a gadget to the Expandergadget
AddElement(expander_gadgets())
expander_gadgets()\Expander_Gadget=*gadget_\gadget_id
expander_gadgets()\Gadget_id=#PB_Any
expander_gadgets()\gx=x
expander_gadgets()\gy=y
expander_gadgets()\gw=width
expander_gadgets()\gh=height
expander_gadgets()\gadgettext=text
expander_gadgets()\gadgettype=type
expander_gadgets()\nr=Gadget_number
expander_gadgets()\color=color
ProcedureReturn 1
EndProcedure
;--------DEMO------<
UseJPEGImageDecoder()
Define.expander myex_1, myex_2, myex_3,myex_4,myex_5,myex_6,myex_7
OpenWindow(0,0,0,500,330,"ExpanderGadget - Test")
CreateGadgetList(WindowID(0))
mb=ButtonGadget(#PB_Any,400,290,80,30,"exit")
DisableGadget(CheckBoxGadget(#PB_Any,10,180,150,25,"just another gadget"),#False)
myex_1\normal_image=LoadImage(#PB_Any,"blau.jpg")
myex_1\expanded_image=LoadImage(#PB_Any,"blau1.jpg")
myex_1\gx=10
myex_1\gy=10
myex_1\gw=150
myex_1\gh=20
myex_1\fontnr=LoadFont(#PB_Any,"sans",6)
myex_1\gadgettext="options"
myex_1\backgroundcolor=#PB_Any;if you don't want to set an own color, you MUST set it to #pb_any
myex_1\expandergroup=0
myex_2\normal_image=LoadImage(#PB_Any,"blau.jpg")
myex_2\expanded_image=LoadImage(#PB_Any,"blau1.jpg")
myex_2\gx=10
myex_2\gy=70
myex_2\gw=160
myex_2\gh=20
myex_2\fontnr=LoadFont(#PB_Any,"sans",10,#PB_Font_Bold)
myex_2\gadgettext="exit options"
myex_2\backgroundcolor=$8F9EFF;if you don't want to set an own color, you MUST set it to #pb_any
myex_2\expandergroup=0
myex_3\normal_image=LoadImage(#PB_Any,"blau.jpg")
myex_3\expanded_image=LoadImage(#PB_Any,"blau1.jpg")
myex_3\gx=10
myex_3\gy=130
myex_3\gw=160
myex_3\gh=20
myex_3\fontnr=LoadFont(#PB_Any,"courier",9)
myex_3\gadgettext="even more options"
myex_3\backgroundcolor=#PB_Any;if you don't want to set an own color, you MUST set it to #pb_any
myex_3\expandergroup=0
myex_4\normal_image=LoadImage(#PB_Any,"blau.jpg")
myex_4\expanded_image=LoadImage(#PB_Any,"blau1.jpg")
myex_4\gx=230
myex_4\gy=10
myex_4\gw=160
myex_4\gh=20
myex_4\fontnr=LoadFont(#PB_Any,"sans",10)
myex_4\gadgettext="second group 1"
myex_4\backgroundcolor=#PB_Any;if you don't want to set an own color, you MUST set it to #pb_any
myex_4\expandergroup=1
;you can reference to another already loaded image too;
myex_5\normal_image=myex_4\normal_image
myex_5\expanded_image=myex_4\expanded_image
myex_5\gx=230
myex_5\gy=50
myex_5\gw=160
myex_5\gh=20
myex_5\fontnr=LoadFont(#PB_Any,"arial",8)
myex_5\gadgettext="second group 2"
myex_5\backgroundcolor=#PB_Any;if you don't want to set an own color, you MUST set it to #pb_any
myex_5\expandergroup=1
ExpanderSetDefaults(@myex_6)
myex_6\gx=230
myex_6\gy=90
myex_6\gw=160
myex_6\gh=20
myex_6\gadgettext="with built-in images"
myex_6\expandergroup=1
my1=ExpanderGadget(@myex_1)
AddExpanderGadget(@myex_1,1,"optiongadget",10,10,100,20,"testext 1")
AddExpanderGadget(@myex_1,2,"optiongadget",10,30,100,20,"testext 2")
AddExpanderGadget(@myex_1,3,"optiongadget",10,50,100,20,"testext 3")
CloseExpanderGadget(@myex_1)
my2=ExpanderGadget(@myex_2)
AddExpanderGadget(@myex_2,4,"checkboxgadget",10,10,160,20,"enable exit button")
AddExpanderGadget(@myex_2,5,"checkboxgadget",10,30,160,20,"I have no function")
CloseExpanderGadget(@myex_2)
my3=ExpanderGadget(@myex_3)
AddExpanderGadget(@myex_3,6,"textgadget",10,10,170,25,"Please enter your Name")
AddExpanderGadget(@myex_3,7,"stringgadget",10,40,160,25,"")
AddExpanderGadget(@myex_3,8,"hyperlinkgadget",10,80,170,30,"klick me to exit the App",$0309FC)
CloseExpanderGadget(@myex_3)
my4=ExpanderGadget(@myex_4)
wy=10
For m=9 To 12
AddExpanderGadget(@myex_4,m,"HyperLinkGadget",10,wy,160,30,"entry number "+Str(m-8),RGB(255-wy, 0, 91+wy))
wy+30
Next
CloseExpanderGadget(@myex_4)
my5=ExpanderGadget(@myex_5)
wy=10
For m=13 To 17
AddExpanderGadget(@myex_5,m,"HyperLinkGadget",10,wy,160,30,"entry number "+Str(m-12),RGB(255-wy, 0+wy, 255))
wy+30
Next
CloseExpanderGadget(@myex_5)
my6=ExpanderGadget(@myex_6)
wy=10
For m=18 To 23
AddExpanderGadget(@myex_6,m,"HyperLinkGadget",10,wy,160,30,"entry number "+Str(m-12),RGB(255-wy, 0+wy, 25))
wy+30
Next
CloseExpanderGadget(@myex_6)
SetGadgetState(its_Gadget(2),#True)
SetGadgetState(its_Gadget(5),#True)
DisableGadget(mb,#True)
Repeat
event=WaitWindowEvent(0)
Select Event
Case #PB_Event_Gadget
Select EventGadget()
Case my1
expandergadget_clicked(@myex_1)
Case my2
expandergadget_clicked(@myex_2)
Case my3
expandergadget_clicked(@myex_3)
Case my4
expandergadget_clicked(@myex_4)
Case my5
expandergadget_clicked(@myex_5)
Case my6
expandergadget_clicked(@myex_6)
Case its_gadget(4)
Select GetGadgetState(its_gadget(4))
Case 1
DisableGadget(mb,#False)
Case 0
DisableGadget(mb,#True)
EndSelect
Case its_gadget(8)
quit=1
Case mb
quit=1
EndSelect
Case #PB_Event_CloseWindow
quit=1
EndSelect
Until quit=1
End

