Here is yet another colourable button that can have text and an optional image...
Not very original, based on ideas from this forum, nor is it very elegant; but did what I needed for a demo.
Feel free to hack / use / improve / ignore.
Code: Select all
;; My need was to use a button that could have text written to it and read it back.
; I also needed to change the text colour and background colour, and also
; display a smiley or similar image to emphasise the text written to the
; button. The PB button colour cannot be easily changed althogh PureColor was
; an option, however this did not get the image onto the button.
;
; So I wrote these procedures instead...
;
Procedure.l ButtonImageText(GadNum.l,Caption$,ForeColour.l,BackColour.l,Font.l) ;- Draw text on a ButtonImageGadget
; ===========================================================================================
; A method of drawing multi-line text into a ButtonImageGadget() with
; user specified Foreground and Background colours and Font. Includes a
; method of reading back the text from a gadget.
; Plus...
; The caption may be split into elements using the '|' character.
; Each element then occupies its own line on the button.
;
; If the first text element starts with '~' the rest of the element is parsed
; as a number that identifies an image to be drawn on the left of the button.
; The image is left aligned in the button with a small margin and text is put to the right.
; Uses the GadgetData() value to point to data which is stored in private memory.
; ===========================================================================================
; To do...
; More rigorous Result
; Use ReAllocateMemory() to expand table if required
Static *ButtonTable
Result = #True
; Specify the number of gadgets that can be handled.
TableSize.w = 128 * 80 ;128 buttons max at 80 bytes per button
; Recover the width and height of the gadget
Bw.w = GadgetWidth(GadNum.l)
Bh.w = GadgetHeight(GadNum.l)
; When first called create an area of memory to use as a table
If *ButtonTable = 0
*ButtonTable = AllocateMemory(TableSize)
EndIf
; Record structure, each gadget record is 80 bytes long
; LONG +00 Gadget Number
; LONG +04 ID of image
; LONG +08 Text colour
; LONG +12 Background colour
; LONG +16 Font ID
; BYTE*59 +20 Gadget Text 59 chars max
; BYTE +79 NULL string terminator
; Limit the caption string length
If Len(Caption$)>59
Caption$ = Left(Caption$,59)
EndIf
; If a font is not specified then use the PB standard one
If Font.l = 0
Font.l = GetGadgetFont(#PB_Default)
EndIf
; For each call to this routine we look up the button's ImageID()or create a new one
WrtDat.w = #False ; Flag...
*U = *ButtonTable ; Start at the base of the table
Repeat
If PeekL(*U) = GadNum ; Found existing gadget...
hI.l = PeekL(*U+4) ; Get the image ID
WrtDat.w = #True ; Set flag to have the data saved
Break
EndIf
If PeekL(*U) = 0 ; Got to a blank entry... new gadget!
hI.l = CreateImage(-1, Bw.w, Bh.w) ; Make a new image
PokeL(*U ,GadNum.l) ; Save the gadget number in the table
PokeL(*U+4 ,hI.l) ; Save the ImageID() in the table
WrtDat.w = #True ; Set flag to have data saved
Break
EndIf
*U + 80 ; Next record...
Until *U > *ButtonTable + TableSize
; Save the data sent by caller
If WrtDat.w
PokeL(*U+8 ,ForeColour.l) ; Keep the text colour
PokeL(*U+12 ,BackColour.l) ; Keep the background colour
PokeL(*U+16 ,Font.l) ; Keep the font
PokeS(*U+20 ,Caption$) ; Keep the string
SetGadgetData(GadNum,*U) ; Put the address of the data into GadgetData()
EndIf
; Do the drawing etc...
If StartDrawing(ImageOutput(hI.l))
; Fill whole area with background colour
DrawingMode(#PB_2DDrawing_Transparent)
Box(0,0,Bw,Bh,BackColour)
;Prepare to draw...
DrawingFont(Font) ; Set the font to be used
Fh.w = TextHeight(Caption$) ; The height of the caption = row spacing
Ne.w = CountString(Caption$,"|")+1 ; Number of elements in the caption = number of lines.
Fe.w = 1 ; First text element to draw
x.w = 0 ; Default horizontal offset for text
If Left(Caption$,1)="~" ; If an image is specified
Fe.w = 2 ; The first text element is the second field in the caption
k$ = StringField(Caption$,1,"|") ; Extract the image ID field...
P_ID.l = Val(PeekS(@k$+1)) ; and get the image ID from it
x.w = ImageWidth(P_ID)+7 ; Adjust the offset for the text
DrawImage(ImageID(P_ID),7,(Bh-ImageHeight(P_ID))/2) ; Draw the image
EndIf
Vs.w = Bh /(Ne.w+2-Fe.w) ; Vertical spacing of lines, half a line top and bottom
y.w = (Bh-(Ne.w+1-Fe.w)* Fh.w)/2 ; Vertical position of first line
FrontColor(ForeColour) ; Set the colour for the text
If Ne.w => Fe.w
For n.w = Fe.w To Ne.w ; For each line of the caption...
k$=StringField(Caption$,n.w,"|") ; Extract the text element
DrawText(x.w+(Bw.w-TextWidth(k$)-x.w)/2, y.w, k$,ForeColour); Put it on the image, centralised in the text area
y.w + Vs.w ; Move the vertical position down by one line
Next
EndIf
StopDrawing()
; Refresh the gadget from the image
SetGadgetState(GadNum,ImageID(hI.l))
Else
Result = #False
EndIf
ProcedureReturn Result
EndProcedure
Procedure.l ButtonImageReText(GadNum.l,Caption$) ;- Draw new text using existing colours and font
; =========================================================
; Draw new text in my ButtonImageGadget using the existing
; colours and font.
; =========================================================
; Record structure, each gadget record being 80 bytes long
; LONG +00 Gadget Number
; LONG +04 ID of image
; LONG +08 Text colour
; LONG +12 Background colour
; LONG +16 Font ID
; BYTE*59 +20 Gadget Text 59 chars max
; BYTE +79 NULL string terminator
Result = #True
; Recover the width and height of the gadget
Bw.w = GadgetWidth(GadNum.l)
Bh.w = GadgetHeight(GadNum.l)
; Limit the caption string length
If Len(Caption$)>59
Caption$ = Left(Caption$,59)
EndIf
*U =GetGadgetData(GadNum)
hI.l = PeekL(*U+4) ; Get the image ID
ForeColour.l = PeekL(*U+08) ; Get the text colour
BackColour.l = PeekL(*U+12) ; Get the background colour
Font.l = PeekL(*U+16) ; Get the font
PokeS(*U+20 ,Caption$) ; Keep the New string
; Do the drawing etc...
If StartDrawing(ImageOutput(hI.l))
; Fill whole area with background colour
DrawingMode(#PB_2DDrawing_Transparent)
Box(0,0,Bw,Bh,BackColour)
;Prepare to draw...
DrawingFont(Font) ; Set the font to be used
Fh.w = TextHeight(Caption$) ; The height of the caption = row spacing
Ne.w = CountString(Caption$,"|")+1 ; Number of elements in the caption = number of lines.
Fe.w = 1 ; First text element to draw
x.w = 0 ; Default horizontal offset for text
If Left(Caption$,1)="~" ; If an image is specified
Fe.w=2 ; The first text element is the second field in the caption
k$=StringField(Caption$,1,"|") ; Extract the image ID field...
P_ID.l = Val(PeekS(@k$+1)) ; and get the image ID from it
x.w = ImageWidth(P_ID)+7 ; Adjust the offset for the text
DrawImage(ImageID(P_ID),7,(Bh-ImageHeight(P_ID))/2); Draw the image
EndIf
Vs.w = Bh /(Ne.w+2-Fe.w) ; Vertical spacing of lines, half a line top and bottom
y.w = (Bh-(Ne.w+1-Fe.w)* Fh.w)/2 ; Vertical position of first line
FrontColor(ForeColour) ; Set the colour for the text
If Ne.w=>Fe.w
For n.w = Fe.w To Ne.w ; For each line of the caption...
k$=StringField(Caption$,n.w,"|") ; Extract the text element
DrawText(x.w+(Bw-TextWidth(k$)-x.w)/2, y.w, k$,ForeColour); Put it on the image, centralised in the text area
y.w + Vs.w ; Move the vertical position down by one line
Next
EndIf
StopDrawing()
; Refresh the gadget from the image
SetGadgetState(GadNum, ImageID(hI.l))
Else
Result = #False
EndIf
ProcedureReturn Result
EndProcedure
Procedure.s ButtonImageGetText(GadNum) ;- Read text from my ButtonImageGadget
; =======================================================
; Extract and return the string from my ButtonImageGadget
; =======================================================
Caption$ = PeekS(GetGadgetData(GadNum)+20) ; Get the whole text
If Left(Caption$,1)= "~" ; If it includes an image definition...
n.w = FindString(Caption$,"|",1) ; find the sparator at the end of the first field.
If n.w ; If separator found...
Caption$ = PeekS(@Caption$+n.w) ; Clip off the first field.
EndIf
EndIf
ProcedureReturn Caption$
EndProcedure
; =================================== Grotty test and exercise code =================================
; Test my text + colour button.
OpenWindow(0, 0, 0, 300, 600, "ButtonImage Test", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)
f.l = LoadFont(#PB_Any,"Courier New Bold",12)
y = 10
For n.w = 1 To 6
ImageGadget(n.w, 10, y, 200, 80, #Null ) ; Create the button
ButtonImageText(n.w,"Press here",Random($0000FF),Random($FF0000),f.l ) ; Draw the initial content
y+90
Next
; To display the text string recovered from the button
TextGadget(10,10,570,280,20,"",#PB_Text_Border)
; Create a test image to display to the left of the text
TestImage.w = 2
CreateImage(TestImage.w,50,50)
StartDrawing(ImageOutput(2))
Box(0,0,50,50,$FFFFFF)
Circle(25,25,15,$00FF00)
StopDrawing()
; Skeleton program...
Repeat
EventID = WaitWindowEvent()
Select EventID
Case #PB_Event_CloseWindow
End
Case #PB_Event_Gadget
GadID = EventGadget()
Select GadID
Case 1
ButtonImageText(GadID,"~"+Str(TestImage.w)+"|"+Str(ElapsedMilliseconds()),Random($FFFFFF),Random($FFFFFF),f.l)
Case 2
ButtonImageText(GadID,"~"+Str(TestImage.w)+"|Press button|to test|"+Str(ElapsedMilliseconds()),Random($FFFFFF),Random($FFFFFF),f.l)
Case 3
ButtonImageText(GadID,"~"+Str(TestImage.w)+"|Press| this button",Random($FFFFFF),Random($FFFFFF),f.l)
Case 4
ButtonImageText(GadID,"Press this|button|please",Random($FFFFFF),Random($FFFFFF),f.l)
Case 5
ButtonImageText(GadID,"~"+Str(TestImage.w)+"",Random($FFFFFF),Random($FFFFFF),f.l)
Case 6
ButtonImageText(GadID,"",Random($FFFFFF),Random($FFFFFF),f.l)
Break
EndSelect
; Read out the text from the gadget... wait, then re-write the gadget with same colours
SetGadgetText(10,"Text :"+ButtonImageGetText(GadID))
Delay(2000)
ButtonImageReText(GadID ,"~"+Str(TestImage)+"|NEW|TEXT|"+Str(n.w))
EndSelect
ForEver