Hi,
I'm a totally blind PureBasic programmer. PB's IDE, tooling, and gadgets are all at least mostly accessible to a screen reader, and I love it. However, there's one thing that's always gotten me, positioning/resizing gadgets. I don't know what sizes look good. Currently, I just let each gadget fill up an equal part of the screen. Like, if I had 3 buttons, each one would take up WindowHeight(0) and WindowWIdth(0)/3. I imagine this doesn't look pretty, though. Plus, it can get kind of messy and confusing. Is there a way to have PureBasic handle all this kind of stuff for me? As well as handle resizing gadgets when the user resizes the window?
Thanks a ton!
Auto-positioning of gadgets
Auto-positioning of gadgets
PB v5.40/6.10, Windows 10 64-bit.
16-core AMD Ryzen 9 5950X, 128 GB DDR5.
16-core AMD Ryzen 9 5950X, 128 GB DDR5.
Re: Auto-positioning of gadgets
Using the Dialog library gives you an automatic layout system.
Simple example:
Simple example:
Code: Select all
;
; http://www.purebasic.fr/english/viewtopic.php?f=13&t=56528
;
CompilerIf #PB_Compiler_Unicode
#XmlEncoding = #PB_UTF8
CompilerElse
#XmlEncoding = #PB_Ascii
CompilerEndIf
#Dialog = 0
#Xml = 0
;#NSRoundedBezelStyle = 1
XML$ = "<?xml version='1.0'?>"+
"<dialogs>"+
" <window id='0' name='Window_Main' text='app' width='455' height='200' flags='#PB_Window_SystemMenu|#PB_Window_MinimizeGadget|#PB_Window_MaximizeGadget|#PB_Window_SizeGadget'>"+
" <gridbox columns='6'>" +
" <button text='Button 1' />" +
" <button text='Button 2' />" +
" <button text='Button 3' colspan='3' />" +
" <button text='Button 4' />" +
" <button text='Button 5' rowspan='2' />" +
" <button text='Button 6' />" +
" <button text='Button 7' />" +
" <button text='Button 8' />" +
" <button text='Button 9' />" +
" <button text='Button 10' />" +
" <button text='Button 11' />" +
" <button text='Button 12' />" +
" </gridbox>" +
" </window>"+
"</dialogs>"
If CatchXML(#Xml, @XML$, StringByteLength(XML$), 0, #XmlEncoding) And XMLStatus(#Xml) = #PB_XML_Success
If CreateDialog(#Dialog) And OpenXMLDialog(#Dialog, #Xml, "Window_Main")
Repeat
Event = WaitWindowEvent()
Until Event = #PB_Event_CloseWindow
Else
Debug "Dialog error: " + DialogError(#Dialog)
EndIf
Else
Debug "XML error: " + XMLError(#Xml) + " (Line: " + XMLErrorLine(#Xml) + ")"
EndIf
Re: Auto-positioning of gadgets
More advanced example:
Code: Select all
CompilerIf #PB_Compiler_Unicode
#XmlEncoding = #PB_UTF8
CompilerElse
#XmlEncoding = #PB_Ascii
CompilerEndIf
#Dialog = 0
#Xml = 0
XML$ = "<window id='#PB_Any' name='test' text='test' minwidth='600' minheight='auto' flags='#PB_Window_ScreenCentered | #PB_Window_SystemMenu | #PB_Window_SizeGadget'>" +
"<vbox expand='item:1'>" +
"" + ; gridbox 1
" <gridbox columns='5' colexpand='item:2' rowexpand='item:1'>" +
"" + ; column 1
"" + ; left side spin gadgets
" <singlebox expand='no'>" +
" <vbox expand='no'>" +
" <spin min='1' max='100' value='1' flags='#PB_Spin_Numeric|#PB_Spin_ReadOnly' width='60'/>" +
" <spin min='1' max='100' value='1' flags='#PB_Spin_Numeric|#PB_Spin_ReadOnly'/>" +
" <spin min='1' max='100' value='1' flags='#PB_Spin_Numeric|#PB_Spin_ReadOnly'/>" +
" <spin min='1' max='100' value='1' flags='#PB_Spin_Numeric|#PB_Spin_ReadOnly'/>" +
" </vbox>" +
" </singlebox>" +
"" + ; column 2-4
" <editor text='content' height='150' colspan='3' rowspan='2'/>" +
"" + ; column 5
"" + ; right side spin gadgets
" <singlebox expand='no'>" +
" <vbox expand='no'>" +
" <spin min='1' max='100' value='1' flags='#PB_Spin_Numeric|#PB_Spin_ReadOnly' width='60'/>" +
" <spin min='1' max='100' value='1' flags='#PB_Spin_Numeric|#PB_Spin_ReadOnly'/>" +
" <spin min='1' max='100' value='1' flags='#PB_Spin_Numeric|#PB_Spin_ReadOnly'/>" +
" <spin min='1' max='100' value='1' flags='#PB_Spin_Numeric|#PB_Spin_ReadOnly'/>" +
" </vbox>" +
" </singlebox>" +
" <singlebox/>" +
" <singlebox/>" +
" </gridbox>" +
"" + ; gridbox 2
" <gridbox columns='3' colexpand='item:2' rowexpand='item:1' align='bottom'>" +
"" + ; left side spin gadgets
" <singlebox expand='no'>" +
" <vbox expand='no'>" +
" <spin min='1' max='100' value='1' flags='#PB_Spin_Numeric|#PB_Spin_ReadOnly' width='60'/>" +
" <spin min='1' max='100' value='1' flags='#PB_Spin_Numeric|#PB_Spin_ReadOnly'/>" +
" <spin min='1' max='100' value='1' flags='#PB_Spin_Numeric|#PB_Spin_ReadOnly'/>" +
" <spin min='1' max='100' value='1' flags='#PB_Spin_Numeric|#PB_Spin_ReadOnly'/>" +
" </vbox>" +
" </singlebox>" +
"" + ; inner/middle gridbox for buttons
" <gridbox columns='5'>" +
" <button text='Btn 1'/>" +
" <button text='Btn 2'/>" +
" <button text='Btn 3'/>" +
" <button text='Btn 4'/>" +
" <button text='Btn 5'/>" +
" <vbox>" +
" <button text='Btn 6'/>" +
" <singlebox/>" +
" <button text='Btn 7'/>" +
" <singlebox/>" +
" </vbox>" +
" <singlebox expand='no' colspan='3' align='center'>" +
" <vbox expand='yes'>" +
" <spin min='1' max='100' value='1' flags='#PB_Spin_Numeric|#PB_Spin_ReadOnly' width='60'/>" +
" <spin min='1' max='100' value='1' flags='#PB_Spin_Numeric|#PB_Spin_ReadOnly'/>" +
" <checkbox text='Checkbox 1'/>" +
" <checkbox text='Checkbox 2'/>" +
" </vbox>" +
" </singlebox>" +
" <vbox>" +
" <button text='Btn 8'/>" +
" <singlebox/>" +
" <button text='Btn 9'/>" +
" <singlebox/>" +
" </vbox>" +
" </gridbox>" +
"" + ; right side spin gadgets
" <singlebox expand='no'>" +
" <vbox expand='no'>" +
" <spin min='1' max='100' value='1' flags='#PB_Spin_Numeric|#PB_Spin_ReadOnly' width='60'/>" +
" <spin min='1' max='100' value='1' flags='#PB_Spin_Numeric|#PB_Spin_ReadOnly'/>" +
" <spin min='1' max='100' value='1' flags='#PB_Spin_Numeric|#PB_Spin_ReadOnly'/>" +
" <spin min='1' max='100' value='1' flags='#PB_Spin_Numeric|#PB_Spin_ReadOnly'/>" +
" </vbox>" +
" </singlebox>" +
" </gridbox>" +
"</vbox>" +
"</window>"
If CatchXML(#Xml, @XML$, StringByteLength(XML$), 0, #XmlEncoding) And XMLStatus(#Xml) = #PB_XML_Success
If CreateDialog(#Dialog) And OpenXMLDialog(#Dialog, #Xml, "test", 0,0,800,600)
Repeat : Until WaitWindowEvent() = #PB_Event_CloseWindow
Else
Debug "Dialog error: " + DialogError(#Dialog)
EndIf
Else
Debug "XML error: " + XMLError(#Xml) + " (Line: " + XMLErrorLine(#Xml) + ")"
EndIf
Re: Auto-positioning of gadgets
Wow, this looks like exactly what I need! Thank you!
Last I heard though, the Dialog library can only do basic controls. You can't do, for example, multi-column listviews. Is this still the case? If so, how do you work around it?
Last I heard though, the Dialog library can only do basic controls. You can't do, for example, multi-column listviews. Is this still the case? If so, how do you work around it?
PB v5.40/6.10, Windows 10 64-bit.
16-core AMD Ryzen 9 5950X, 128 GB DDR5.
16-core AMD Ryzen 9 5950X, 128 GB DDR5.
Re: Auto-positioning of gadgets
You probably need to add a ContainerGadget inside the dialog and put custom controls inside the container by code, right after dialog creation.
Re: Auto-positioning of gadgets
Small example shows how to add a custom gadget/control to an empty Dialog container:
Code: Select all
;
; Use Custom Gadget with Dialog Container
;
; by Danilo, 2022/05/18
;
CompilerIf #PB_Compiler_Unicode
#XmlEncoding = #PB_UTF8
CompilerElse
#XmlEncoding = #PB_Ascii
CompilerEndIf
#Dialog = 0
#Xml = 0
XML$ = "<?xml version='1.0'?>"+
"<dialogs>"+
" <window id='#PB_Any' name='mainWindow' text='Custom Gadgets in Dialogs' width='455' height='200' flags='#PB_Window_SystemMenu|#PB_Window_MinimizeGadget|#PB_Window_MaximizeGadget|#PB_Window_SizeGadget'>"+
" <gridbox columns='6'>" +
" <button text='Button 1' />" +
" <button text='Button 2' />" +
" <container name='CustomGadget1' colspan='3' height='80'/>" +
" <button text='Button 4' />" +
" <button text='Button 5' rowspan='2' />" +
" <container name='CustomGadget2' rowspan='2' />" +
" <button text='Button 6' />" +
" <button text='Button 7' />" +
" <button text='Button 8' />" +
" <button text='Button 9' />" +
" <button text='Button 10' />" +
" <button text='Button 11' />" +
" <button text='Button 12' />" +
" </gridbox>" +
" </window>"+
"</dialogs>"
;
; Procedures for adding Custom Gadget to Dialog Container
; and control child resizing
;
Procedure __ResizeCustomGadget()
Protected gadget = EventGadget()
Protected child = GetGadgetData(gadget)
ResizeGadget(child,0,0,GadgetWidth(gadget),GadgetHeight(gadget))
EndProcedure
Procedure.i OpenDialogContainer(Dialog.i, ContainerName.s)
Protected Container = DialogGadget(Dialog, ContainerName)
If Container
OpenGadgetList(Container)
EndIf
ProcedureReturn Container
EndProcedure
Procedure CloseDialogContainer(Container, Gadget)
If Container
SetGadgetData(Container, Gadget)
CloseGadgetList()
BindGadgetEvent(Container,@__ResizeCustomGadget(),#PB_EventType_Resize)
ResizeGadget(Gadget,0,0,GadgetWidth(Container),GadgetHeight(Container))
EndIf
EndProcedure
;--------------------------------------------------------------
;
; Minimal Custom Gadget (just as an example)
;
Procedure Draw()
If StartDrawing(CanvasOutput(EventGadget()))
Protected width = OutputWidth(), height = OutputHeight()
Box(0,0,width,height,RGB(7, 136, 184))
FrontColor(RGB($FF,$FF,$FF))
LineXY(0,0, width-1, height-1)
LineXY(0,height-1, width-1, 0)
DrawingMode(#PB_2DDrawing_Outlined)
Box(0,0,width,height)
StopDrawing()
EndIf
EndProcedure
Procedure.i MyCustomGadget()
Protected gadget = CanvasGadget(#PB_Any, 0,0,0,0)
BindGadgetEvent(gadget,@Draw(),#PB_EventType_Resize)
ProcedureReturn gadget
EndProcedure
;
;--------------------------------------------------------------
If CatchXML(#Xml, @XML$, StringByteLength(XML$), 0, #XmlEncoding) And XMLStatus(#Xml) = #PB_XML_Success
If CreateDialog(#Dialog) And OpenXMLDialog(#Dialog, #Xml, "mainWindow")
; add a custom gadget to an empty dialog container
container = OpenDialogContainer(#Dialog,"CustomGadget1")
If container
customGadget = MyCustomGadget()
CloseDialogContainer(container, customGadget)
EndIf
container = OpenDialogContainer(#Dialog,"CustomGadget2")
If container
customGadget = MyCustomGadget()
CloseDialogContainer(container, customGadget)
EndIf
Repeat:Until WaitWindowEvent() = #PB_Event_CloseWindow
Else
Debug "Dialog error: " + DialogError(#Dialog)
EndIf
Else
Debug "XML error: " + XMLError(#Xml) + " (Line: " + XMLErrorLine(#Xml) + ")"
EndIf
Re: Auto-positioning of gadgets
It's not hard to write calculation rules using flags like in AutoIt3, but you still have to take the time to set the expected behavior.
You can define all GUI elements as a percentage and calculate using a scaling factor.
Code: Select all
w = WindowWidth(#Window)
h = WindowHeight(#Window)
btnW = (w - 10)/3 -10
btnP1 = 10
btnP1 = btnW + 20
btnP2 = (btnW + 10) *2 + 10
-
- Enthusiast
- Posts: 136
- Joined: Thu Nov 15, 2012 11:38 pm
- Location: Los Angeles
Re: Auto-positioning of gadgets
I use a pad with factor of 8 pixels between gadgets for breathability. Desktop resolution is a factor of 8, so this works out well when maximized.
Code: Select all
; 1. Add button to enumeration
; 2. In window_main() - Define button gadget(s)
; 3. In resize() - Adjust buttonCount to total enumerated buttons
; 4. In resize() - Insert resize line(s) for each button
;ENUMERATIONS
Enumeration windows
#window_main
EndEnumeration
Enumeration gadgets
#button_1
#button_2
#button_3
EndEnumeration
;GLOBALS
Global shutdown.b
Procedure resize()
winW = WindowWidth(#window_main)
winH = WindowHeight(#window_main)
pad = 8
buttonCount = 3
; For example: Three buttons will have a total of four pads - one in the beginning, one between 1 and 2, one between 2 and 3, and one after 3. So four pads (or buttonCount + 1).
buttonW = (winW - (pad * (buttonCount + 1))) / buttonCount
ResizeGadget(#button_1 , pad , pad , buttonW , winH - (pad * 2))
ResizeGadget(#button_2 , GadgetX(#button_1) + GadgetWidth(#button_1) + pad , GadgetY(#button_1) , buttonW , GadgetHeight(#button_1))
ResizeGadget(#button_3 , GadgetX(#button_2) + GadgetWidth(#button_2) + pad , GadgetY(#button_1) , buttonW , GadgetHeight(#button_1))
EndProcedure
Procedure window_main()
winX = 0
winY = 0
winW = 640
winH = 80
title$ = "Test"
flags = #PB_Window_MaximizeGadget |
#PB_Window_MinimizeGadget |
#PB_Window_ScreenCentered |
#PB_Window_SizeGadget |
#PB_Window_SystemMenu
OpenWindow(#window_main , winX , winY , winW , winH , title$ , flags)
ButtonGadget(#button_1 , 0 , 0 , 0 , 0 , "One")
ButtonGadget(#button_2 , 0 , 0 , 0 , 0 , "Two")
ButtonGadget(#button_3 , 0 , 0 , 0 , 0 , "Three")
BindEvent(#PB_Event_SizeWindow , @resize() , #window_main)
EndProcedure
window_main()
resize()
Repeat
event = WaitWindowEvent()
Select event
Case #PB_Event_CloseWindow
Select EventWindow()
Case #window_main
shutdown = #True
Default
CloseWindow(EventWindow())
EndSelect
Case #PB_Event_Gadget
EndSelect
Until shutdown = #True
End