ButtonImageGadget Text and colours

Share your advanced PureBasic knowledge/code with the community.
RichardL
Enthusiast
Enthusiast
Posts: 532
Joined: Sat Sep 11, 2004 11:54 am
Location: UK

ButtonImageGadget Text and colours

Post by RichardL »

Code updated for 5.20+

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
Last edited by RichardL on Mon Mar 02, 2009 9:01 am, edited 2 times in total.
rsts
Addict
Addict
Posts: 2736
Joined: Wed Aug 24, 2005 8:39 am
Location: Southwest OH - USA

Post by rsts »

Very impressive.

This makes me want to change a program of mine ('cept it might upset my 'button artist'). I may just change it anyway. :)

Seriously, this is nice.

cheers
Post Reply