GUI text and string input alignment

Windows specific forum
PBJim
Enthusiast
Enthusiast
Posts: 296
Joined: Fri Jan 19, 2024 11:56 pm

GUI text and string input alignment

Post by PBJim »

I've been struggling with the alignment of text and their corresponding string gadgets. Is a better result possible, compared with the below? It's a new area for me, as all my past work with PureBasic has been with background process system software. I can move the string gadgets down a notch but it doesn't look right. What is the best way to align these input fields?

This is the result I see when dragging the gadgets into position (no special fonts, sizes or other adjustments).

Image

Is it possible to achieve the below alignment (not the fonts, but just the alignment), which is a comparable Windows application?

Image
User avatar
mk-soft
Always Here
Always Here
Posts: 6242
Joined: Fri May 12, 2006 6:51 pm
Location: Germany

Re: GUI text and string input alignment

Post by mk-soft »

Please put the code in, otherwise we will not see what you have created.
My Projects ThreadToGUI / OOP-BaseClass / EventDesigner V3
PB v3.30 / v5.75 - OS Mac Mini OSX 10.xx - VM Window Pro / Linux Ubuntu
Downloads on my Webspace / OneDrive
User avatar
Demivec
Addict
Addict
Posts: 4267
Joined: Mon Jul 25, 2005 3:51 pm
Location: Utah, USA

Re: GUI text and string input alignment

Post by Demivec »

PBJim wrote: Sun May 12, 2024 8:56 pmIs it possible to achieve the below alignment (not the fonts, but just the alignment), which is a comparable Windows application?
You mentioned dragging of gadgets into position. It sounds like you are using a form designer. Which one are you using?

If you are not using a form designer the aspects that you need to consider when aligning the text involves two things. One is the border size of the control and the other is the font size.

Using the font's size you can determine the sizing of the controls so that text appears centered vertically by reducing the height to do so. You can do this by sizing the string control to the value returned by GadgetHeight(#gadgetNum, #PB_Gadget_RequiredSize) .

To align the text in TextBoxes and StringGadget requires accounting for whether each one has a border around it. One defaults to a border and the other defaults to borderless. The borders are 2 pixels in thickness (by appearance). So for a borderless TextBox and a StringGadget with a border you have to add 2 pixels to the vertical positioning of the TextBox.


Here's some sample code to demonstrate things. Set the constant #test =0 for the default font size and =1 for a larger Courier New 24 pt font.

Code: Select all

;Only tested on Windows
EnableExplicit
#test = 0 ;=0 for default font size, =1 for CourierNew 24pt size

Enumeration windows 1
  #w_Record_set_up
EndEnumeration

Enumeration gadgets 1
  #g_name_txt
  #g_name_str
  #g_officePhoneNo_txt
  #g_officePhoneNo_str
  #g_mobilePhoneNo_txt
  #g_mobilePhoneNo_str
  #g_Save_btn
  #g_Cancel_btn
EndEnumeration

Enumeration images 1
  #im_temp
EndEnumeration

Enumeration fonts 1
  #f_Courier  
EndEnumeration


Enumeration faultTypes
  #ft_gadget_creation
  #ft_window_creation
  #ft_image_creation
  #ft_image_drawing
  #ft_map_element_creation
  #ft_font_loading
  #ft_generic
  #ft_custom
EndEnumeration

;Handle Fault Types; prints text messsage if value <> 0 and ends program
Procedure HFT(value, type, text.s = "")
  If Not value
    Select type
      Case #ft_gadget_creation
        text = "Unable to create gadget."
      Case #ft_window_creation
        text = "Unable to create window."
      Case #ft_image_creation
        text = "Unable to create image."
      Case #ft_image_drawing
        text = "Unable to draw to image."
      Case #ft_map_element_creation
        text = "Unable to create map element."
      Case #ft_font_loading
        text = "Unable to load font."
      Case #ft_custom
        ;use text as is.
      Default
        text = "Fatal error, unable to continue."
    EndSelect
    
    MessageRequester("Error", text.s)
    End
  EndIf
EndProcedure

Procedure window_Record_set_up()
  CompilerIf #test = 0
    Protected wx = 50, wy = 50, ww = 400, wh = 200
  CompilerElse
    Protected wx = 50, wy = 50, ww = 400 * 3, wh = 250 * 1.5
  CompilerEndIf
  
  Protected x, y, w, h, m = 50, sm = 30 ;m = margin and sm = spacing margin
  Protected fid, borderAdj = 2 + 1
  
  HFT(OpenWindow(#w_Record_set_up, wx, wy, ww, wh, "Record set-up", #PB_Window_SystemMenu), #ft_window_creation)
  
  ;For gadget font info only, this gadget will be setup properly later
  HFT(StringGadget(#g_name_str, 0, 0, 0, 0, "XgpM"), #ft_gadget_creation)
  CompilerIf #test = 0
    fid = GetGadgetFont(#g_name_str) ;does not work with a default font on MAC OS
  CompilerElse
    HFT(LoadFont(#f_Courier, "Courier New", 24), #ft_font_loading)
    fid = FontID(#f_Courier)
  CompilerEndIf
  SetGadgetFont(#g_name_str, fid)
  ;use height value for all gadgets with same font
  h = GadgetHeight(#g_name_str, #PB_Gadget_RequiredSize)
  
  w = (ww - (m * 2) - sm * 3) / 2: x = m: y = (m * 2 / 3) + borderAdj
  HFT(TextGadget(#g_name_txt, x, y, w, h, "Name"), #ft_gadget_creation): y + (h * 1.75)
  HFT(TextGadget(#g_officePhoneNo_txt, x, y, w, h, "Office Phone no."), #ft_gadget_creation): y + (h * 1.75)
  HFT(TextGadget(#g_mobilePhoneNo_txt, x, y, w, h, "Mobile Phone no."), #ft_gadget_creation)
  
  ;size string gadgets to give matching space above and below text (results change in accordance with font sizes)
  w = (ww - (m * 2) + sm) / 2: x = ww - m - w: y = (m * 2 / 3)
  HFT(StringGadget(#g_name_str, x, y, w, h, "PBJim"), #ft_gadget_creation): y + (h * 1.75)
  HFT(StringGadget(#g_officePhoneNo_str, x, y, w, h, "0234 1234 5678"), #ft_gadget_creation): y + (h * 1.75)
  HFT(StringGadget(#g_mobilePhoneNo_str, x, y, w, h, "0780 9760 1023"), #ft_gadget_creation)
  
  w = (ww - (m * 2) - (sm / 2) ) / 2: x = m: y + (h * 2.25)
  HFT(ButtonGadget(#g_Save_btn, x, y, w, h, "Save"), #ft_gadget_creation)
  x = ww - m - w
  HFT(ButtonGadget(#g_Cancel_btn, x, y, w, h, "Cancel"), #ft_gadget_creation)
  
  ;uncomment the following two lines to see the actual text areas
  ;SetGadgetColor(#g_name_txt, #PB_Gadget_BackColor, RGB(0, 255, 0))
  ;SetGadgetColor(#g_name_str, #PB_Gadget_BackColor, RGB(255, 255, 0))
  
  SetGadgetFont(#g_name_txt, fid)
  SetGadgetFont(#g_name_str, fid)
  SetGadgetFont(#g_officePhoneNo_str, fid)
  SetGadgetFont(#g_officePhoneNo_txt, fid)
  SetGadgetFont(#g_mobilePhoneNo_str, fid)
  SetGadgetFont(#g_mobilePhoneNo_txt, fid)
  SetGadgetFont(#g_Save_btn, fid)
  SetGadgetFont(#g_Cancel_btn, fid)
EndProcedure

window_Record_set_up()

Define event, quit = #False


Repeat
  event = WaitWindowEvent()
  
  Select event
    Case #PB_Event_CloseWindow
      quit = #True
    Case #PB_Event_Gadget
      Select EventGadget()
        Case #g_name_str  
        Case #g_officePhoneNo_str
        Case #g_mobilePhoneNo_str
        Case #g_Save_btn
          ;save values as record
          quit = #True
        Case #g_Cancel_btn
          quit = #True
      EndSelect
  EndSelect
Until quit = #True
breeze4me
Enthusiast
Enthusiast
Posts: 633
Joined: Thu Mar 09, 2006 9:24 am
Location: S. Kor

Re: GUI text and string input alignment

Post by breeze4me »

To place a string in the vertical center of a text gadget, you can use the #SS_CENTERIMAGE flag.

Code: Select all

OpenWindow(0, 0, 0, 500, 400, "", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)
TextGadget(0, 10, 10, 40, 24, "Name:", #SS_CENTERIMAGE)
StringGadget(1, 50, 10, 200, 24, "String")

Repeat : Until WaitWindowEvent() = #PB_Event_CloseWindow
PBJim
Enthusiast
Enthusiast
Posts: 296
Joined: Fri Jan 19, 2024 11:56 pm

Re: GUI text and string input alignment

Post by PBJim »

Thanks to all for the replies. I should have better explained when I sent this but it was late at night and brain fog had set in — the question was primarily about the IDE and the built-in form design, rather than about coding. I probably should have posted the question in that section.

Incidentally though, your solution looks perfect Demivec, thanks for that, the result is so much better than the default.

Image

The question related to the fact that by using only the built-in designer in PureBasic, the string gadget and the text gadget, when both positioned at the same vertical line on the grid, do not appear to be aligned when the application executes. We can adjust the 'y' coordinate in the resulting source code by 5 points and it will be perfect, but I wondered why it doesn't align them when we've dragged the gadgets into the same position — either it's slightly above, or slightly below and neither is right unless we adjust the coordinate manually in the source code.

This has come about because I intend to give the task to someone to produce the GUI forms to replace those within our existing legacy application. The person who will do this (a designer rather than a coder), will be instructed to use PureBasic's form designer and prepare the screens so that I can later add the business logic from our older application. The default we see is below. I think we will probably need to adjust the 'y' coordinate in the source code. As I mentioned in the post, we are not making adjustments to the font, size, or other characteristics, as the default font appearance and size is otherwise perfect for the type of application. I do not wish to use borders, just use only the defaults of the form designer. Thanks again.

Image
User avatar
ChrisR
Addict
Addict
Posts: 1466
Joined: Sun Jan 08, 2017 10:27 pm
Location: France

Re: GUI text and string input alignment

Post by ChrisR »

Maybe you can try IceDesign demo version and see if this extra tool brings you any benefits.
um, it's self-promotion :? but I've still got quite a few guys who've invested and trusted me, even some guys who don't use it at all
breeze4me
Enthusiast
Enthusiast
Posts: 633
Joined: Thu Mar 09, 2006 9:24 am
Location: S. Kor

Re: GUI text and string input alignment

Post by breeze4me »

The text gadget displays the string in the top left corner, so it won't be centered without the above mentioned flag. (a Windows feature)
PB's form designer only supports features that are common to multiple platforms, so you can't specify a Windows-only flag like the one above, so the only way to avoid coding is to use a form designer program other than the default form designer.

Alternatively, you can add a macro like the one below to the top of your form creation code.

Code: Select all

Macro PBTextGadget
  TextGadget
EndMacro

Macro TextGadget(Gadget, x, y, Width, Height, Text, Flags = 0)
  PBTextGadget(Gadget, x, y, Width, Height, Text, Flags | #SS_CENTERIMAGE)
EndMacro

OpenWindow(0, 0, 0, 500, 400, "", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)
TextGadget(0, 10, 10, 40, 24, "Name:")
StringGadget(1, 50, 10, 200, 24, "String")

Repeat : Until WaitWindowEvent() = #PB_Event_CloseWindow
PBJim
Enthusiast
Enthusiast
Posts: 296
Joined: Fri Jan 19, 2024 11:56 pm

Re: GUI text and string input alignment

Post by PBJim »

breeze4me wrote: Mon May 13, 2024 3:39 pm The text gadget displays the string in the top left corner, so it won't be centered without the above mentioned flag. (a Windows feature)
Apologies breeze4me , I'd intended to drop you a line to comment on your post, but I'm working on such an unreliable internet connection today that everything is taking me ages to do. :(

Yes, I see the effect from this flag. It didn't appear to be mentioned in PB's documentation for the text gadget. I'll play around with this and see what works best for us.
User avatar
Demivec
Addict
Addict
Posts: 4267
Joined: Mon Jul 25, 2005 3:51 pm
Location: Utah, USA

Re: GUI text and string input alignment

Post by Demivec »

PBJim wrote: Mon May 13, 2024 2:38 pmThe question related to the fact that by using only the built-in designer in PureBasic, the string gadget and the text gadget, when both positioned at the same vertical line on the grid, do not appear to be aligned when the application executes. We can adjust the 'y' coordinate in the resulting source code by 5 points and it will be perfect, but I wondered why it doesn't align them when we've dragged the gadgets into the same position — either it's slightly above, or slightly below and neither is right unless we adjust the coordinate manually in the source code.

This has come about because I intend to give the task to someone to produce the GUI forms to replace those within our existing legacy application. The person who will do this (a designer rather than a coder), will be instructed to use PureBasic's form designer and prepare the screens so that I can later add the business logic from our older application. The default we see is below. I think we will probably need to adjust the 'y' coordinate in the source code. As I mentioned in the post, we are not making adjustments to the font, size, or other characteristics, as the default font appearance and size is otherwise perfect for the type of application. I do not wish to use borders, just use only the defaults of the form designer. Thanks again.
I left a few lines in the sample code to show the effects of borders. They change the color of the string and text gadget used for the entry of 'Name'. If you uncomment those two lines you can see how well the gadget text spaces line up with and without borders. Remember that the text gadget defaults to borderless and the string gadget defaults to having a border. If you make the string gadget borderless its text will line up perfectly with the text gadget's text if both gadgets are at the same y position.

For the code sample you would have to modify the positioning of the text gadgets to remove the addition of the borderAdj to the text gadgets y position (since there is no border to adjust for).
I believe you should get things lined up also by adding a flag for a border around the text gadget so that both the string and text gadgets have a border (it looks hideous though if you do :wink:).

breeze4me's solution should work well too and addresses the problem more directly though I haven't had a moment to test it yet.
PBJim
Enthusiast
Enthusiast
Posts: 296
Joined: Fri Jan 19, 2024 11:56 pm

Re: GUI text and string input alignment

Post by PBJim »

Demivec wrote: Mon May 13, 2024 6:51 pm I left a few lines in the sample code to show the effects of borders. They change the color of the string and text gadget used for the entry of 'Name'. If you uncomment those two lines you can see how well the gadget text spaces line up with and without borders.
I saw the commented-out lines Demivec, yes and I noted that the addition of the border around the text gadget affected the vertical placement of the text when I uncommented. It wasn't lost on me :)

I hadn't got the point you make about the string gadget having the border, while the text gadget does not, but I see what you mean now. As I see it, unless we have a border with a text gadget, it's just a bit of a quirk that we have to adjust for that. I suppose in the early days of Windows, it was normal to use those sunken borders for everything.

Yes, I'm leaning towards breeze4me's method, as it's easy to add that — it aligns the text box perfectly.
User avatar
mk-soft
Always Here
Always Here
Posts: 6242
Joined: Fri May 12, 2006 6:51 pm
Location: Germany

Re: GUI text and string input alignment

Post by mk-soft »

Small code ... FitToSize(Gadget)

Update

Code: Select all

;-TOP by mk-soft

Procedure FitToSize(Gadget)
  Select GadgetType(Gadget)
    Case #PB_GadgetType_Text
      ResizeGadget(Gadget, #PB_Ignore, GadgetY(Gadget) + 3, #PB_Ignore, GadgetHeight(Gadget, #PB_Gadget_RequiredSize) + 2)
    Case #PB_GadgetType_String
      ResizeGadget(Gadget, #PB_Ignore, GadgetY(Gadget) + 0, #PB_Ignore, GadgetHeight(Gadget, #PB_Gadget_RequiredSize) + 2)
  EndSelect
EndProcedure

Procedure UpdateWindow()
  Protected dx, dy
  dx = WindowWidth(0)
  dy = WindowHeight(0) - StatusBarHeight(0) - MenuHeight()
  ; Resize Gadgets
EndProcedure

Procedure Main()
  Protected dx, dy
  
  #WinStyle = #PB_Window_SystemMenu | #PB_Window_SizeGadget | #PB_Window_MaximizeGadget | #PB_Window_MinimizeGadget
  
  If OpenWindow(0, #PB_Ignore, #PB_Ignore, 600, 400, "Test Window", #WinStyle)
    ; MenuBar
    CreateMenu(0, WindowID(0))
    MenuTitle("File")
    
    ; StatusBar
    CreateStatusBar(0, WindowID(0))
    AddStatusBarField(#PB_Ignore)
    
    ; Font
    LoadFont(0, "", 16)
    
    ; Gadgets
    dx = WindowWidth(0)
    dy = WindowHeight(0) - StatusBarHeight(0) - MenuHeight()
    TextGadget(0, 5, 5, 160, 0, "TextGadget", #PB_Text_Right)
    StringGadget(1, 170, 5, 160, 0, "StringGadget")
    FitToSize(0)
    FitToSize(1)
    
    SetGadgetFont(#PB_All, FontID(0))
    TextGadget(2, 5, 35, 160, 0, "TextGadget", #PB_Text_Right)
    StringGadget(3, 170, 35, 160, 0, "StringGadget")
    FitToSize(2)
    FitToSize(3)
    
    ; Bind Events
    BindEvent(#PB_Event_SizeWindow, @UpdateWindow(), 0)
    
    ; Main Loop
    Repeat
      Select WaitWindowEvent()
        Case #PB_Event_CloseWindow
          Select EventWindow()
            Case 0
              Break
          EndSelect
          
        Case #PB_Event_Menu
          Select EventMenu()
            
          EndSelect
          
        Case #PB_Event_Gadget
          Select EventGadget()
              
          EndSelect
          
      EndSelect
    ForEver
    
  EndIf
  
EndProcedure : Main()
My Projects ThreadToGUI / OOP-BaseClass / EventDesigner V3
PB v3.30 / v5.75 - OS Mac Mini OSX 10.xx - VM Window Pro / Linux Ubuntu
Downloads on my Webspace / OneDrive
User avatar
ChrisR
Addict
Addict
Posts: 1466
Joined: Sun Jan 08, 2017 10:27 pm
Location: France

Re: GUI text and string input alignment

Post by ChrisR »

AlignText2String according to the flags used. Tested on Windows only

Code: Select all

Procedure AlignText2String(GadgetText, GadgetString)
  Static Text2StringOffSet   ; or 2 hardcoded
  If Not Text2StringOffSet
    Protected Dummy = TextGadget(#PB_Any, -20, -20, 10, 0, "Abc", #PB_Text_Border)
    Text2StringOffSet = GadgetHeight(Dummy, #PB_Gadget_RequiredSize)
    FreeGadget(Dummy)
    Dummy = TextGadget(#PB_Any, -20, -20, 10, 0, "Abc")
    Text2StringOffSet - GadgetHeight(Dummy, #PB_Gadget_RequiredSize)
    FreeGadget(Dummy)
    ;Debug "Text2StringOffSet = " + Text2StringOffSet
  EndIf
  ResizeGadget(GadgetString, #PB_Ignore, #PB_Ignore, #PB_Ignore, GadgetHeight(GadgetString, #PB_Gadget_RequiredSize))
  If GetWindowLongPtr_(GadgetID(GadgetText), #GWL_EXSTYLE) & #WS_EX_CLIENTEDGE
    If GetWindowLongPtr_(GadgetID(GadgetString), #GWL_EXSTYLE) & #WS_EX_CLIENTEDGE
      ; #PB_Text_Border - Not #PB_String_BorderLess
      ResizeGadget(GadgetText, #PB_Ignore, GadgetY(GadgetString), #PB_Ignore, GadgetHeight(GadgetText, #PB_Gadget_RequiredSize))
    Else
      ; #PB_Text_Border - #PB_String_BorderLess
      ResizeGadget(GadgetText, #PB_Ignore, GadgetY(GadgetString) - Text2StringOffSet, #PB_Ignore, GadgetHeight(GadgetText, #PB_Gadget_RequiredSize))
    EndIf
  Else
    If GetWindowLongPtr_(GadgetID(GadgetString), #GWL_EXSTYLE) & #WS_EX_CLIENTEDGE
      ; Not #PB_Text_Border - Not #PB_String_BorderLess
      ResizeGadget(GadgetText, #PB_Ignore, GadgetY(GadgetString) + Text2StringOffSet, #PB_Ignore, GadgetHeight(GadgetText, #PB_Gadget_RequiredSize))
    Else
      ; Not #PB_Text_Border - #PB_String_BorderLess
      ResizeGadget(GadgetText, #PB_Ignore, GadgetY(GadgetString), #PB_Ignore, GadgetHeight(GadgetText, #PB_Gadget_RequiredSize))
    EndIf
  EndIf
EndProcedure

If OpenWindow(0, 0, 0, 220, 150, "AlignText2String", #PB_Window_SystemMenu | #PB_Window_ScreenCentered)
  TextGadget(1, 20, 20, 60, 0, "___Text1_____")
  StringGadget(2, 80, 20, 120, 0, "___String1_____")
  AlignText2String(1, 2)
  TextGadget(3, 20, 50, 60, 0, "___Text2_____", #PB_Text_Border)
  StringGadget(4, 80, 50, 120, 0, "___String2_____")
  AlignText2String(3, 4)
  TextGadget(5, 20, 80, 60, 0, "___Text3_____")
  StringGadget(6, 80, 80, 120, 0, "___String3_____", #PB_String_BorderLess)
  AlignText2String(5, 6)
  TextGadget(7, 20, 110, 60, 0, "___Text4_____", #PB_Text_Border)
  StringGadget(8, 80, 110, 120, 0, "___String4_____", #PB_String_BorderLess)
  AlignText2String(7, 8)
  
  Repeat : Until WaitWindowEvent() = #PB_Event_CloseWindow
EndIf
Post Reply