Dynamic Gadgets with automatic Font size adaption

Share your advanced PureBasic knowledge/code with the community.
User avatar
Andre
PureBasic Team
PureBasic Team
Posts: 2056
Joined: Fri Apr 25, 2003 6:14 pm
Location: Germany (Saxony, Deutscheinsiedel)
Contact:

Dynamic Gadgets with automatic Font size adaption

Post by Andre »

Another new and standalone code, by Werner Albus, which is also part of actually updated GFX_Wizzard_BF package.

This code provides a resizable GUI, where gadgets (button, editor) are automatically adapted according to the changed window size, including automatic adaption of the used font size.
Have fun with testing! :D

ButtonGadget_PB_Resizable_Font_and_Window_EX.pb (updated on 6th Dec. 2018)

Code: Select all

; Demo : Automatic resizing PB gadgets and fonts

; === Module DrawText_EX ===  
DeclareModule DrawText_EX
  
  Declare DrawText_EX(txt_x, txt_y, txt$, f_col=#White, b_col=#Black, flag=0, mode=0, stretch_x=0, stretch_y=0)
  ; All OS - Author(C) : Werner Albus - www.nachtoptik.de - www.quick-aes-256.de - Free for using and enhancing
  ; Flags : Text center=1 - Text right=2 - Text vertical=3
  ; Modes : Revers text mode=1 - RTL text mode=2 - Give only back the needed width mode=3 , height mode=4
  ; Mono line output give back the xx output coordinate - Multi line output give back the yy output coordinate
  ; For stretched text on a textured background often DrawingMode (#PB_2DDrawing_Transparent) is needed
  
  ; Create a image from the output, for post processing or using as image, give back a image (ID) - Padding -1 is automatic padding
  Declare DrawTextCreateImage_EX(txt$, f_col=#White, b_col=#Black, flag=0, mode=0, font_ID=0, stretch_x=0, stretch_y=0, padding=0)
  
  Declare PresetLineWidth_EX(max_1_) ; Preset the min output length for easy centric or right align outputs - Deactivate = 0
                                     ; Important for permanent changed outputs
  
  Declare DrawText_EX_AutoBox(padding_=-1, ; Automatic padding = -1 - Deactivate = -2
                              box_color_=0,
                              offset_x_=0,
                              offset_y_=0,
                              offset_xx_=0,
                              offset_yy_=0)
  
  Declare DrawText_EX_Box(activate_=1, box_color_1_=0, offset_x_1=0, offset_y_1_=0, width_=0, height_=0) ; Activate = 1 - Deactivate = 0
  
EndDeclareModule

Module DrawText_EX
  
  EnableExplicit
  
  Global max_1, padding=-2, box_color, offset_x, offset_y, offset_xx, offset_yy
  Global activate, box_color_1, offset_x_1, offset_y_1, width, height, from_image, image_color
  
  Procedure DrawText_EX(txt_x, txt_y, txt$, f_col=#White, b_col=#Black, flag=0, mode=0, stretch_x=0, stretch_y=0)
    If txt$="" : ProcedureReturn -1 : EndIf
    Protected i1=TextHeight(Space(1))+stretch_y, i2, i3, i4, i5, i6, i7, padding_1
    Protected result, max, max_len, max_2, max_3, txt_x_0=txt_x, txt_y_0=txt_y, amount_lines
    Protected txt1$, chr$, ln$, ln1$
    Protected Dim f1$(0), Dim f2$(0)
    
    txt1$=ReplaceString(ReplaceString(ReplaceString(txt$, #CRLF$, #LF$), #CR$, #LF$), #LFCR$, #LF$)
    i7=Len(txt1$)
    
    If flag<>3 And FindString(txt1$, #LF$)
      amount_lines=CountString(txt1$, #LF$)+1
      txt_y-i1
      For result=1 To i7
        ln$=StringField(txt1$, result, #LF$)
        i4=Len(ln$)
        If i4
          max_2=TextWidth(ln$)+stretch_x*i4
          If max_2>max_3
            max_3=max_2
            ln1$=ln$
            i2+i1
            max=TextWidth(ln$)+i4
            max_len=i4
          EndIf
        EndIf
      Next
      
      If max_1>0
        max=max_1
      EndIf
      
      If flag=1 ; Centered
        txt_x+max_len*(stretch_x>>1)-max_len>>1
      ElseIf flag=2 ; Right
        txt_x+max_len*(stretch_x)-max_len
      EndIf
    EndIf
    
    If mode=3 And flag<>3
      If i2
        If Not stretch_x
          ProcedureReturn TextWidth(ln1$)+2
        Else
          i6=Len(ln1$)
          For i4=1 To i6
            i5+TextWidth(Mid(ln1$, i4, 1))
          Next
          ProcedureReturn i5+stretch_x*i6+stretch_x/12
        EndIf
      Else
        If Not stretch_x
          ProcedureReturn TextWidth(txt1$)+2
        Else
          For i4=1 To i7
            i5+TextWidth(Mid(txt1$, i4, 1))
          Next
          ProcedureReturn i5+stretch_x*Len(txt1$)+stretch_x/12
        EndIf
      EndIf
    EndIf
    
    If mode=4 And flag<>3
      If i2
        ProcedureReturn amount_lines*(i1+1)-stretch_y
      Else
        ProcedureReturn i1+1-stretch_y
      EndIf
    EndIf
    
    Macro first_char_width
      i5=0
      For i4=1 To i7
        i6=TextWidth(Mid(txt1$, i4, 1))
        If i6>i5
          i5=i6
        EndIf
      Next
    EndMacro
    
    If padding=-1
      padding_1=TextWidth(Space(3))
    Else
      padding_1=padding
    EndIf
    
    If mode=3 And flag=3
      first_char_width
      ProcedureReturn i5
    EndIf
    
    If mode=4 And flag=3
      ProcedureReturn i1*i7-stretch_y
    EndIf
    
    If activate=1
      Box(txt_x_0+offset_x_1,
          txt_y_0+offset_y_1,
          width,
          height,
          box_color_1)
    EndIf
    
    If Not from_image
      If padding<>-2
        If i2
          Box(txt_x_0-padding_1+offset_x,
              txt_y_0-padding_1+offset_y,
              max+max_len*(stretch_x)-stretch_x-max_len+padding_1<<1+offset_xx,
              amount_lines*i1-stretch_y+padding_1<<1+offset_yy,
              box_color)
        Else
          If flag<>3
            Box(txt_x_0-padding_1+offset_x,
                txt_y_0-padding_1+offset_y,
                TextWidth(txt1$)+stretch_x*(i7-1)+padding_1<<1+offset_xx,
                i1+padding_1<<1+offset_yy,
                box_color)
          Else ; Vertical box
            first_char_width
            Box(txt_x_0-padding_1+offset_x>>1,
                txt_y_0-padding_1+offset_y,
                i5+padding_1<<1+offset_xx,
                i1*i7+padding_1<<1+offset_yy,
                box_color)
          EndIf
        EndIf
      EndIf
    Else
      DrawingMode(#PB_2DDrawing_Transparent)
    EndIf
    
    Macro spread_x(txt_x, txt_y, ln)
      i6=0
      i4=Len(ln)
      For i5=1 To Len(ln)
        ln1$=Mid(ln, i5, 1)
        If flag=1 And i2
          DrawText(txt_x+i6-i4*stretch_x>>1, txt_y, ln1$, f_col, b_col)
        ElseIf flag=2 And i2
          DrawText(txt_x+i6-i4*stretch_x, txt_y, ln1$, f_col, b_col)
        Else
          DrawText(txt_x+i6, txt_y, ln1$, f_col, b_col)
        EndIf
        i6+TextWidth(ln1$)+stretch_x
      Next   
    EndMacro
    
    Macro rtl(txt)
      i5=0
      i3=Len(txt)
      For i4=1 To i3
        If Mid(txt, i4, 1)=" "
          i6+1
        EndIf
        ln1$=StringField(txt, i4, " ")
        If ln1$<>""
          ReDim f1$(i5)
          ReDim f2$(i5)
          f1$(i5)=ln1$
          f2$(i5)=ReverseString(ln1$)
          i5+1
        EndIf
      Next
      txt=ReverseString(txt)
      For i4=0 To i5-1
        txt=ReplaceString(txt, f2$(i4), f1$(i4))
      Next
      i3=0 : i5=0 : i6=0
    EndMacro 
    
    Macro txt_out
      If mode=1
        ln$=ReverseString(ln$)
      ElseIf mode=2
        rtl(ln$)
      EndIf
      If flag=2 ; Right
        If stretch_x
          spread_x(txt_x+max-TextWidth(ln$), txt_y+i2, ln$)
        Else
          DrawText(txt_x+max-TextWidth(ln$), txt_y+i2, ln$, f_col, b_col)
        EndIf
      ElseIf flag=1 ; Centered
        If stretch_x
          spread_x(txt_x+max>>1-TextWidth(ln$)>>1, txt_y+i2, ln$)
        Else
        DrawText(txt_x+max>>1-TextWidth(ln$)>>1, txt_y+i2, ln$, f_col, b_col) : EndIf
      Else ; Left
        If stretch_x
          spread_x(txt_x, txt_y+i2, ln$)
        Else
          DrawText(txt_x, txt_y+i2, ln$, f_col, b_col)
        EndIf
      EndIf
    EndMacro
    
    If flag=3 And mode=1
      rtl(txt1$)
    EndIf
    If flag=3 ; Vertical
      txt1$=ReplaceString(txt1$, #LF$, " ")
      If mode
        txt1$=ReverseString(txt1$)
      EndIf
      For result=1 To i7
        chr$=Mid(txt1$, result, 1)
        first_char_width
        DrawText(i5>>1+txt_x-TextWidth(chr$)>>1, txt_y+i3, chr$, f_col, b_col)
        i3+i1
      Next
      ProcedureReturn txt_y+i3
    Else ; Horizontal
      If i2
        i2=0 : ln$=""
        For result=1 To i7
          chr$=Mid(txt1$, result, 1)
          If chr$=#LF$
            i2+i1
            txt_out
            ln$=""
          Else
            ln$+chr$
          EndIf
        Next
        i2+i1
        txt_out
        ProcedureReturn txt_y+i2+i1
      Else ; One line
        If mode=1
          txt$=ReverseString(txt$)
        ElseIf mode=2
          rtl(txt$)
        EndIf
        If stretch_x
          spread_x(txt_x, txt_y, txt$)
        Else
          DrawText(txt_x, txt_y, txt$, f_col, b_col)
        EndIf
      EndIf
    EndIf
    
    If i6
      ProcedureReturn txt_x+i6
    Else
      ProcedureReturn txt_x+TextWidth(txt$)
    EndIf
  EndProcedure
  
  Procedure DrawTextCreateImage_EX(txt$, f_col=#White, b_col=#Black, flag=0, mode=0, font_ID=0, stretch_x=0, stretch_y=0, padding=0)
    If txt$="" : ProcedureReturn -2 : EndIf
    Protected image_ID=CreateImage(#PB_Any, 1, 1)
    If Not image_ID : ProcedureReturn -3 : EndIf
    
    If Not StartDrawing(ImageOutput(image_ID)) ; Get the needed width and length for the output
      FreeImage(image_ID)
      ProcedureReturn -4
    EndIf
    
    If IsFont(font_ID) : DrawingFont(FontID(font_ID)) : EndIf
    
    If padding=-1
      padding=TextWidth(Space(3))
    EndIf
    
    If max_1>0
      Protected output_width=max_1 ; Get the needed width
    Else
      output_width=DrawText_EX(0, 0, txt$, 0, 0, flag, 3, stretch_x, stretch_y)-stretch_x ; Get the needed width
    EndIf
    Protected output_height=DrawText_EX(0, 0, txt$, 0, 0, flag, 4, stretch_x, stretch_y)-stretch_y ; Get the needed height
    StopDrawing()
    
    If mode=3
      FreeImage(image_ID)
      ProcedureReturn output_width+padding
    EndIf
    
    If mode=4
      FreeImage(image_ID)
      ProcedureReturn output_height+padding
    EndIf
    
    If Not ResizeImage(image_ID, output_width+padding<<1, output_height+padding<<1)
      FreeImage(image_ID)
      ProcedureReturn -5
    EndIf
    
    If Not StartDrawing(ImageOutput(image_ID)) ; Draw the text in the image
      FreeImage(image_ID)
      ProcedureReturn -6
    EndIf
    
    Box(0, 0, output_width+padding<<1, output_height+padding<<1, b_col)
    If IsFont(font_ID) : DrawingFont(FontID(font_ID)) : EndIf 
    
    Protected old_activate=activate
    activate=0
    from_image=1
    image_color=b_col
    DrawText_EX(padding, padding, txt$, f_col, 0, flag, mode, stretch_x, stretch_y)
    activate=old_activate
    from_image=0
    StopDrawing()
    
    ProcedureReturn image_ID
  EndProcedure
  
  Procedure PresetLineWidth_EX(max_1_)
    max_1=max_1_
  EndProcedure
  
  Procedure DrawText_EX_AutoBox(padding_=-1,
                                box_color_=0, 
                                offset_x_=0,
                                offset_y_=0,
                                offset_xx_=0,
                                offset_yy_=0)
    padding=padding_
    box_color=box_color_
    offset_x=offset_x_
    offset_y=offset_y_
    offset_xx=offset_xx_
    offset_yy=offset_yy_
  EndProcedure
  
  Procedure DrawText_EX_Box(activate_=1, box_color_1_=0, offset_x_1_=0, offset_y_1_=0, width_=0, height_=0)
    activate=activate_
    box_color_1=box_color_1_
    offset_x_1=offset_x_1_
    offset_y_1=offset_y_1_
    width=width_
    height=height_
  EndProcedure
  
EndModule
UseModule DrawText_EX

Procedure Offset_x_BF(old_window_x_size.f, window_ID, position_x.f)
  ProcedureReturn position_x/(old_window_x_size/WindowWidth(window_ID))
EndProcedure

Procedure Offset_y_BF(old_window_y_size.f, window_ID, position_y.f)
  ProcedureReturn position_y/(old_window_y_size/WindowHeight(window_ID))
EndProcedure

EnableExplicit

Global window_ID
Global origin_window_width, origin_window_height
Global gadget_1_ID, text_1$, x_pos_gadget_1, y_pos_gadget_1, button_width_gadget_1, button_height_gadget_1
Global gadget_2_ID, text_2$, x_pos_gadget_2, y_pos_gadget_2, button_width_gadget_2, button_height_gadget_2
Global gadget_3_ID, text_3$, x_pos_gadget_3, y_pos_gadget_3, button_width_gadget_3, button_height_gadget_3
Global gadget_4_ID, text_4$, x_pos_gadget_4, y_pos_gadget_4, button_width_gadget_4, button_height_gadget_4
Global max_font_size=99 ; This is the maximum font size to be output - between 40 and 60 should usually be enough
Global padding_x=25
CompilerIf #PB_Compiler_OS=#PB_OS_Linux
  Global padding_y=11
CompilerElse
  Global padding_y=5
CompilerEndIf
Global Dim font(max_font_size)
Global resulted_needed_font_size
Define needed_font_size

Procedure Needed_Button_Font_Size(window_ID,
                                  text$,
                                  origin_window_width,
                                  origin_window_height,
                                  x_pos_gadget,
                                  y_pos_gadget,
                                  button_width,
                                  button_height,
                                  padding_x,
                                  padding_y)
  
  Protected needed_font_size=max_font_size
  If text$="" : ProcedureReturn 0 : EndIf
  While needed_font_size>1
    If DrawTextCreateImage_EX(text$, 0, 0, 0, 3, font(needed_font_size), 0, 0, padding_x)=<Offset_x_BF(origin_window_width, window_ID, button_width) And
       DrawTextCreateImage_EX(text$, 0, 0, 0, 4, font(needed_font_size), 0, 0, padding_y)=<Offset_y_BF(origin_window_height, window_ID, button_height)
      Break
    EndIf
    needed_font_size-1
  Wend
  ProcedureReturn needed_font_size
EndProcedure

Procedure SetGadgetStates(window_ID,
                          gadget_ID,
                          text$,
                          origin_window_width,
                          origin_window_height,
                          x_pos_gadget,
                          y_pos_gadget,
                          origin_button_width,
                          origin_button_height,
                          padding_x,
                          padding_y)
  
  Protected resulted_needed_font_size=Needed_Button_Font_Size(window_ID,
                                                              text$,
                                                              origin_window_width,
                                                              origin_window_height,
                                                              x_pos_gadget,
                                                              y_pos_gadget,
                                                              origin_button_width,
                                                              origin_button_height,
                                                              padding_x,
                                                              padding_y)
  
  SetGadgetFont(gadget_ID, FontID(font(resulted_needed_font_size)))
  
  ResizeGadget(gadget_ID,
               Offset_x_BF(origin_window_width, window_ID, x_pos_gadget),
               Offset_y_BF(origin_window_height, window_ID, y_pos_gadget),
               Offset_x_BF(origin_window_width, window_ID, origin_button_width),
               Offset_y_BF(origin_window_height, window_ID, origin_button_height))
  ProcedureReturn resulted_needed_font_size
EndProcedure

Procedure WindowResizing_BindEvent()
  
  Protected resulted_needed_font_size=SetGadgetStates(window_ID,
                                                      gadget_1_ID,
                                                      text_1$,
                                                      origin_window_width,
                                                      origin_window_height,
                                                      x_pos_gadget_1,
                                                      y_pos_gadget_1,
                                                      button_width_gadget_1,
                                                      button_height_gadget_1,
                                                      padding_x,
                                                      padding_y) 
  
  ; The font size can also be easily inherited - Samples for simple add any gadgets with inheritance
  Protected editor_font_size=resulted_needed_font_size/1.8 : If editor_font_size<1 : editor_font_size=1 : EndIf
  SetGadgetFont(gadget_2_ID, FontID(font(Int(editor_font_size)))) ; You can get simple a dynamic font size from any gadget for the text output
  ResizeGadget(gadget_2_ID,
               Offset_x_BF(origin_window_width, window_ID, x_pos_gadget_2),
               Offset_y_BF(origin_window_height, window_ID, y_pos_gadget_2),
               Offset_x_BF(origin_window_width, window_ID, button_width_gadget_2),
               Offset_y_BF(origin_window_height, window_ID, button_height_gadget_2))
  
  editor_font_size=resulted_needed_font_size/1.8 : If editor_font_size<1 : editor_font_size=1 : EndIf
  SetGadgetFont(gadget_3_ID, FontID(font(Int(editor_font_size)))) ; You can get simple a dynamic font size from any gadget for the text output
  ResizeGadget(gadget_3_ID,
               Offset_x_BF(origin_window_width, window_ID, x_pos_gadget_3),
               Offset_y_BF(origin_window_height, window_ID, y_pos_gadget_3),
               Offset_x_BF(origin_window_width, window_ID, button_width_gadget_3),
               Offset_y_BF(origin_window_height, window_ID, button_height_gadget_3))
  
  editor_font_size=resulted_needed_font_size/4 : If editor_font_size<1 : editor_font_size=1 : EndIf
  SetGadgetFont(gadget_4_ID, FontID(font(Int(editor_font_size)))) ; You can get simple a dynamic font size from any gadget for the text output
  ResizeGadget(gadget_4_ID,
               Offset_x_BF(origin_window_width, window_ID, x_pos_gadget_4),
               Offset_y_BF(origin_window_height, window_ID, y_pos_gadget_4),
               Offset_x_BF(origin_window_width, window_ID, button_width_gadget_4),
               Offset_y_BF(origin_window_height, window_ID, button_height_gadget_4))
  
EndProcedure

window_ID=OpenWindow(#PB_Any, #PB_Ignore, #PB_Ignore , 1000, 580, "GFX_Wizzard_BF",
                     #PB_Window_SystemMenu | #PB_Window_ScreenCentered | #PB_Window_Invisible | #PB_Window_SizeGadget)

SetWindowColor(window_ID, $FF0000)
WindowBounds(window_ID, 170, 120, 1800, 1000)

For needed_font_size=1 To max_font_size ; Get the fonts
  font(needed_font_size)=LoadFont(#PB_Any, "", needed_font_size, #PB_Font_Bold)
Next needed_font_size

origin_window_width=WindowWidth(window_ID)
origin_window_height=WindowHeight(window_ID)

; ==================== Button 1 =====================
text_1$="It's magic"+#LF$+
        "This is a large PB Button"+#LF$+
        "Resize the Window"

button_width_gadget_1=600
button_height_gadget_1=200
x_pos_gadget_1=30
y_pos_gadget_1=WindowHeight(window_ID)/2-button_height_gadget_1/2

gadget_1_ID=ButtonGadget(#PB_Any,
                         x_pos_gadget_1,
                         y_pos_gadget_1,
                         button_width_gadget_1,
                         button_height_gadget_1,
                         text_1$,
                         #PB_Button_MultiLine)

; ==================== Button 2 =====================
text_2$="Bye"
button_width_gadget_2=160
button_height_gadget_2=60
x_pos_gadget_2=WindowWidth(window_ID)/2-button_width_gadget_2/2
y_pos_gadget_2=WindowHeight(window_ID)-button_height_gadget_2-30

gadget_2_ID=ButtonGadget(#PB_Any,
                         x_pos_gadget_2,
                         y_pos_gadget_2,
                         button_width_gadget_2,
                         button_height_gadget_2,
                         text_2$,
                         #PB_Button_MultiLine)

; ==================== Button 3 =====================
text_3$="GFX_Wizzard_BF"+#LF$+
        "Simple a little more"
button_width_gadget_3=350
button_height_gadget_3=90
x_pos_gadget_3=WindowWidth(window_ID)/2-button_width_gadget_3/2
y_pos_gadget_3=30

gadget_3_ID=ButtonGadget(#PB_Any,
                         x_pos_gadget_3,
                         y_pos_gadget_3,
                         button_width_gadget_3,
                         button_height_gadget_3,
                         text_3$,
                         #PB_Button_MultiLine)

; ==================== Editor 1 =====================
; Sample for simple add any gadgets
text_4$="This is a Editor Gadget"+#LF$+
        "The function is also included in GFX_Wizzard_BF,"+#LF$+
        "with more special functions and BF enhanced gadgets"+#LF$+
        "It is possible with all available gadgets,"+#LF$+
        "to create with this base code quickly a dynamic GUI"+#LF$+
        "There are as sample, ColorButton_BF, TextGadget_BF, ImageGadget_BF, ButtonImage"+#LF$+
        "Images and texts are fitted dynamically and precisely, without any distortion"+#LF$+
        "MessageRequester_BF automatically supports all of the above functions"+#LF$+
        "Amazing demo codes are available in the GFX_Wizzard_BF"+#LF$+
        "Download package included"
button_width_gadget_4=320
button_height_gadget_4=200
x_pos_gadget_4=WindowWidth(window_ID)-button_width_gadget_4-30
y_pos_gadget_4=WindowHeight(window_ID)/2-button_height_gadget_4/2

gadget_4_ID=EditorGadget(#PB_Any,
                         x_pos_gadget_4,
                         y_pos_gadget_4,
                         button_width_gadget_4,
                         button_height_gadget_4)

Define editor_font_size=resulted_needed_font_size/2.5 : If editor_font_size<1 : editor_font_size=1 : EndIf
SetGadgetFont(gadget_4_ID, FontID(font(Int(editor_font_size))))
SetGadgetText(gadget_4_ID, text_4$)

; =============== Get the result ===================

HideWindow(window_ID, 0)

WindowResizing_BindEvent() ; Init
BindEvent(#PB_Event_SizeWindow, @WindowResizing_BindEvent())

; TODO - After developing you can so preset simple the first or needed output size you want
; Change the user the window size, you can restart the GUI with this user defined size
; ResizeWindow(window_ID, #PB_Ignore, #PB_Ignore, 900, 600)

Repeat
  Define win_event=WaitWindowEvent()
  
  If win_event=#PB_Event_CloseWindow
    Break
  ElseIf win_event And EventGadget()=gadget_2_ID
    Break
  EndIf
ForEver
Bye,
...André
(PureBasicTeam::Docs & Support - PureArea.net | Order:: PureBasic | PureVisionXP)