CreateWidget

Syntax

Widget = CreateWidget(x, y, Width, Height, *UserData=#Null, Flags=#Null)

Description

Creates a new standard ProGUI widget (the core “building block” for all UI elements). A standard widget is a rectangular canvas rendered and managed entirely by ProGUI. You control its appearance by attaching a #PG_Event_Draw handler and applying skin properties via a class, and its behaviour through additional event handlers.

Widgets can also act as containers by attaching a layout to them (via the #PG_Widget_LayoutFlex, #PG_Widget_LayoutGrid, or #PG_Widget_LayoutBasic flags), allowing you to nest child widgets inside to build complex UI hierarchies. Unlike CreateOsWidget(), standard widgets render identically across all supported platforms.

The new widget is automatically inserted into the current layout (see LayoutSetCurrent()).

Parameters

x
The initial horizontal position of the widget relative to its parent layout container (in DIPs). Primarily used by Basic layouts; Flex and Grid layouts override this based on their rules.

y
The initial vertical position of the widget relative to its parent layout container (in DIPs). Primarily used by Basic layouts; Flex and Grid layouts override this based on their rules.

Width
The initial ideal width of the widget (in DIPs). Layout engines may adjust this based on available space and other item properties. Use #PG_Widget_FitContent to automatically size based on content (e.g., a child layout's overflow).

Height
The initial ideal height of the widget (in DIPs). Layout engines may adjust this based on available space and other item properties. Use #PG_Widget_FitContent to automatically size based on content.

*UserData (optional)
A custom pointer or integer value to associate with the widget. Can be retrieved later using WidgetGetUserData(). Default is #Null.

Flags (optional)
A combination of flags to modify the widget’s behavior and appearance. Default is #Null.

#PG_Widget_Hide                : Creates the widget in a hidden state.
#PG_Widget_NoDraw              : Prevents the widget from being rendered.
#PG_Widget_NoMouse             : Configures the widget to ignore mouse events (mouse events pass through).
#PG_Widget_NoSkinBackground    : Disables the drawing of the skin's background for this widget.
#PG_Widget_NoSkinOutsetShadow  : Disables the drawing of the skin's outset drop shadow.
#PG_Widget_NoSkinInsetShadow   : Disables the drawing of the skin's inset shadow.
#PG_Widget_NoSkinBorder        : Disables the drawing of the skin's border.
#PG_Widget_NoBorder            : Completely disables any border rendering (skin or generated).
#PG_Widget_NoSkinRender        : Combination flag that disables all skin rendering (Background, Shadows, and Border).
#PG_Widget_NoCache             : Disables internal image caching for the widget's rendering.
#PG_Widget_DragWindow          : Allows the parent window to be dragged by clicking and dragging this widget.
#PG_Widget_LayoutBasic         : Automatically creates and attaches a Basic Layout to the widget, turning it into a container.
#PG_Widget_LayoutFlex          : Automatically creates and attaches a Flex Layout to the widget.
#PG_Widget_LayoutGrid          : Automatically creates and attaches a Grid Layout to the widget.

Note: Custom user flags can be defined starting from #PG_Widget_FirstUserFlag.

Return Value

Returns a handle to the newly created widget object if successful, or #Null if creation failed. This handle is used in subsequent widget-related commands.

Remarks

When called, the widget is automatically inserted into the current layout at the #PG_Last position. The current layout is managed via LayoutPush(), LayoutPop() or LayoutSetCurrent(). If you specify one of the #PG_Widget_Layout* flags, the widget will have a layout container created and attached to it automatically, allowing you to nest further widgets inside it (with the layout becoming the new current layout).

Note: If a new widget lacks a Draw EventHandler (via AddEventHandler()) or assigned skin properties, it will render with an “Under-construction” appearance. This includes a black-and-yellow striped “hazard tape” border, a semi-transparent yellow background, and the placeholder text “Widget” - perfect for rapid prototyping and identifying missing configurations.

Examples

IncludeFile "ProGUI_PB.pbi"

StartProGUI()

Global UserDataString$

; Custom draw procedure for our widget
Procedure DrawMyWidget(Widget, EventType, *EventData.PG_EventDraw, *UserData)
  
  DrawEllipse(*EventData\width / 2, *EventData\height / 2, *EventData\width / 2, *EventData\height / 2, 0, 0.1)
  DrawBoxStroke(0, 0, *EventData\width, *EventData\height, RGB(50, 50, 50), 0.8)

  ; Retrieve and display widget user data if it exists
  *widgetUserData = WidgetGetUserData(Widget)
  If *widgetUserData
    MyText$ = PeekS(*widgetUserData)
    Static MyTextObj ; Static text object for efficiency
    If Not MyTextObj
        MyTextObj = CreateText("", "Arial", 12)
        TextSetAlign(MyTextObj, #PG_Text_Align_Center)
        TextSetJustify(MyTextObj, #PG_Text_Justify_Center)
    EndIf
    TextSetContent(MyTextObj, MyText$)
    TextSetWidth(MyTextObj, *EventData\width - 10) ; Add padding
    TextSetHeight(MyTextObj, *EventData\height - 10)
    DrawTxt(MyTextObj, 5, 5, RGB(0,0,0), 1)
  EndIf

EndProcedure

MyWindow = CreateWindow(0, 0, 400, 300, "CreateWidget Example", #PG_Window_Default | #PG_Window_LayoutFlex) ; Use Flex layout

If MyWindow
    
  ; Add padding to the current window layout
  LayoutSetPadding(#Null, 10)
  
  ; Create a widget with UserData
  UserDataString$ = "Widget 1"
  Widget1 = CreateWidget(0, 0, 150, 50, @UserDataString$)
  WidgetSetClass(Widget1, "mywidget") ; Assign a class for skinning
  WidgetSetMargin(Widget1, 5)
  AddEventHandler(Widget1, #PG_Event_Draw, @DrawMyWidget())
  
  ; Set the background-color skin property for "mywidget"
  SkinSetValue("mywidget", "", "", "background-color", "red")
  
  LayoutPush() ; Push the current window layout onto the stack so we can easily restore it later

  ; Create another widget, automatically giving it a child Flex layout
  Widget2 = CreateWidget(0, 0, 100, 80, #Null, #PG_Widget_LayoutFlex)
  WidgetSetMargin(Widget2, 5)
  AddEventHandler(Widget2, #PG_Event_Draw, @DrawMyWidget())

  ; Add a sub-widget inside Widget2's layout (now the current layout)
  SubWidget = CreateWidget(0, 0, 50, 20)
  WidgetSetClass(SubWidget, "button") ; Different class
  WidgetSetMargin(SubWidget, 10)
  ; (Add drawing handler for SubWidget if needed)
  
  LayoutPop() ; Restore the window layout so it is now the current layout, newly created widgets will be added to the window
  
  ; Create a "place-holder" / "under-construction" widget with no skin class or draw event handler
  Widget3 = CreateWidget(0, 0, 100, 80)
  WidgetSetMargin(Widget3, 5)
  
  WindowShow(MyWindow, #True, #PG_WindowShow_ScreenCentered)

  Repeat
    Event = WaitWindowEvent()
  Until Event = #PB_Event_CloseWindow

EndIf

StopProGUI()
; This example shows how to wrap CreateWidget into a reusable custom component

IncludeFile "ProGUI_PB.pbi"

StartProGUI()

Structure MyWidget
    text.s
EndStructure

; Draw event handler for our widget
Procedure DrawMyWidget(Widget, EventType, *EventData.PG_EventDraw, *UserData)
  
  Protected *myWidget.MyWidget = WidgetGetUserData(Widget)
  
  DrawSkinText(Widget, "", 0, 0, *EventData\width, *EventData\height, *myWidget\text)
  
EndProcedure

; Destroy event handler for our widget
Procedure DestroyMyWidget(Widget, EventType, *EventData, *myWidget.MyWidget)
  ; Using the *UserData paramater of the event handler this time passed by AddEventHandler()
  ; instead of WidgetGetUserData(), this is entirely upto you offering flexibility.
  FreeStructure(*myWidget)
  Debug "custom widget freed!"
EndProcedure

; Mouse event handler for our widget
Procedure HoverMyWidget(Widget, EventType, *EventData.PG_EventMouse, *UserData)
  
  Select EventType
      
    Case #PG_Event_MouseEnter
      
      WidgetSetSkinState(Widget, "hover")
      
    Case #PG_Event_MouseLeave
      
      WidgetSetSkinState(Widget, "")
      
  EndSelect
  
EndProcedure

; Creates our custom "MyWidget"
Procedure CreateMyWidget(x.d, y.d, Width.d, Height.d, Text$)
  
  Protected *myWidget.MyWidget, widget
  
  *myWidget = AllocateStructure(MyWidget)
  *myWidget\text = Text$
  
  widget = CreateWidget(x, y, Width, Height, *myWidget)
  WidgetSetClass(widget, "mywidget")
  AddEventHandler(widget, #PG_Event_Draw, @DrawMyWidget())
  AddEventHandler(widget, #PG_Event_Destroy, @DestroyMyWidget(), *myWidget)
  AddEventHandler(widget, #PG_Event_MouseEnter, @HoverMyWidget())
  AddEventHandler(widget, #PG_Event_MouseLeave, @HoverMyWidget())
  
  ProcedureReturn widget
  
EndProcedure

; Create some CSS skin properties for our new "mywidget" class
SkinSetValue("mywidget", "", "", "color", "black")
SkinSetValue("mywidget", "", "", "font-family", "Arial")
SkinSetValue("mywidget", "", "", "font-size", "16px")
SkinSetValue("mywidget", "", "", "font-weight", "bold")
SkinSetValue("mywidget", "", "", "text-align", "center")
SkinSetValue("mywidget", "", "", "vertical-align", "center")
SkinSetValue("mywidget", "", "", "background", "linear-gradient(yellow, orange)")
SkinSetValue("mywidget", "", "", "border", "2px blue")
SkinSetValue("mywidget", "", "", "border-radius", "5px")

; Define a "hover" state for the same class
SkinSetValue("mywidget", "hover", "", "color", "crimson")
SkinSetValue("mywidget", "hover", "", "font-size", "24px")

; Define some animation transitions for the class
SkinSetValue("mywidget", "", "", "transition", "color 0.5s ease, font-size 0.5s ease-out-bounce")

MyWindow = CreateWindow(0, 0, 500, 300, "CreateWidget - Custom Self-contained Widget Example", #PG_Window_Default | #PG_Window_LayoutFlex) ; Use Flex layout

If MyWindow
    
  ; Add padding to the current window layout
  LayoutSetPadding(#Null, 10)
  
  ; Create and add our custom self-contained widget to the window's flex layout
  widget = CreateMyWidget(0, 0, 100, 40, "Widget 1")
  WidgetSetMargin(widget, 5)
  
  ; Create another one!
  widget2 = CreateMyWidget(0, 0, 120, 60, "Widget 2")
  WidgetSetMargin(widget2, 5)
  
  ; Create another one!
  widget3 = CreateMyWidget(0, 0, 100, 40, "Widget 3")
  WidgetSetMargin(widget3, 5)
  
  ; Create another one! this time we are going to name our widget and override some CSS class properties
  widget4 = CreateMyWidget(0, 0, 100, 40, "Widget 4")
  WidgetSetName(widget4, "widget4")
  WidgetSetMargin(widget4, 5)
  SkinSetValue("#widget4", "", "", "color", "white")
  SkinSetValue("#widget4", "hover", "", "border-radius", "10px")
  SkinSetValue("#widget4", "", "", "transition", "color 0.5s ease, font-size 0.5s ease-out-bounce, border-radius 0.5s ease")
  
  WindowShow(MyWindow, #True, #PG_WindowShow_ScreenCentered)

  Repeat
    Event = WaitWindowEvent()
  Until Event = #PB_Event_CloseWindow
  
  ; Free our custom widgets, this is just for demonstration purposes with the #PG_Event_Destroy event handler
  FreeWidget(widget)
  FreeWidget(widget2)
  FreeWidget(widget3)
  FreeWidget(widget4)
  
  Delay(1000)
  
EndIf

StopProGUI()

See Also

CreateOsWidget, LayoutInsertWidget, LayoutSetCurrent, WidgetSetClass, AddEventHandler, WidgetSetUserData, WidgetGetUserData, FreeWidget

Supported OS

Windows, Linux