; WinApp.pbi
; Window Application Framework
; Created: 2019-04-08
; Provides basic window application functionality
; Conventions:
; Variable - lowerCamelCase
; Procedure, structure - UpperCamelCase
; Bugs and workarounds:
; 1. In Windows when restoring a maximised window (on startup) it doesn't register properly if there is a
; status bar. https://www.purebasic.fr/english/viewtopic.php?f=4&t=70094
; *** A workaround has been applied
; *** Fix has been applied to Purebasic and the workaround has been removed
;
; 2. In Linux (only some versions?) the #PB_Event_SizeWindow is triggered after the #PB_Event_MaximizeWindow.
; This causes problems when relying on #PB_Event_MaximizeWindow to update the window contents.
; It is possible to avoid this bug completely by not using the MaximiseAppWindow() procedure for anything.
; *** No workaround necessary, do not rely on MaximiseAppWindow() to update window contents
;
; 3. Linux always returns normal for the window type when using GetWindowState(0). This can cause problems for
; procedures that update the window size only when the window is normal. Separate code needs to be used for
; Linux and Windows.
; *** A workaround has been applied
; *** 20/05/2024 - problem is no longer there, removing workaround
;
EnableExplicit
;- 00 - Includes
;CompilerIf #PB_Compiler_OS = #PB_OS_Windows
; XIncludeFile "Includes/ObjectTheme/ObjectTheme.pbi"
; UseModule ObjectTheme
;CompilerEndIf
;XIncludeFile "Includes/MousePointer/MousePointer.pbi"
CompilerIf #PB_Compiler_OS = #PB_OS_Windows
Macro MOUSE_CURSOR_ARROW : #IDC_ARROW : EndMacro
Macro MOUSE_CURSOR_SIZEWE : #IDC_SIZEWE : EndMacro
Macro MOUSE_CURSOR_SIZENS : #IDC_SIZENS : EndMacro
Macro MOUSE_CURSOR_BUSY : #IDC_WAIT : EndMacro
CompilerElseIf #PB_Compiler_OS = #PB_OS_MacOS
Macro MOUSE_CURSOR_ARROW : 0 : EndMacro
Macro MOUSE_CURSOR_SIZEWE : 17 : EndMacro
Macro MOUSE_CURSOR_SIZENS : 32 : EndMacro
Macro MOUSE_CURSOR_BUSY : 7 : EndMacro
ImportC ""
SetThemeCursor(CursorType.L)
EndImport
CompilerElseIf #PB_Compiler_OS = #PB_OS_Linux
Global *Cursor.GdkCursor
Macro MOUSE_CURSOR_ARROW : #GDK_ARROW : EndMacro
Macro MOUSE_CURSOR_SIZEWE : #GDK_SB_H_DOUBLE_ARROW : EndMacro
Macro MOUSE_CURSOR_SIZENS : #GDK_SB_V_DOUBLE_ARROW : EndMacro
Macro MOUSE_CURSOR_BUSY : #GDK_WATCH : EndMacro
ImportC ""
gtk_widget_get_window(*widget.GtkWidget)
EndImport
CompilerEndIf
Procedure SetCursor(hWnd, CursorId)
CompilerIf #PB_Compiler_OS = #PB_OS_Windows
SetClassLongPtr_(hWnd, #GCL_HCURSOR, LoadCursor_(0, CursorId))
CompilerElseIf #PB_Compiler_OS = #PB_OS_MacOS
SetThemeCursor(CursorId)
CompilerElseIf #PB_Compiler_OS = #PB_OS_Linux
*Cursor= gdk_cursor_new_(CursorID)
If *Cursor
gdk_window_set_cursor_(gtk_widget_get_window(hWnd), *Cursor)
EndIf
CompilerEndIf
EndProcedure
CompilerIf #PB_Compiler_OS = #PB_OS_Linux
#GTK_STYLE_PROVIDER_PRIORITY_FALLBACK = 1
#GTK_STYLE_PROVIDER_PRIORITY_THEME = 200
#GTK_STYLE_PROVIDER_PRIORITY_SETTINGS = 400
#GTK_STYLE_PROVIDER_PRIORITY_APPLICATION = 600
#GTK_STYLE_PROVIDER_PRIORITY_USER = 800
ImportC ""
gtk_css_provider_load_from_data(*CSSProvider, CSSData.P-UTF8, Length, *Error.GError)
gtk_css_provider_new()
gtk_style_context_add_provider_for_screen(*Screen.GdkScreen, *StyleProvider, Priority)
EndImport
Procedure SetLinuxStyle()
Protected CSSProvider, CSSDefault.s, Screen
CSSDefault = "button, entry {min-height: 20px;} "
CSSDefault + "tab {min-height: 20px;} "
CSSDefault + "button, scale {padding-bottom: 2px; padding-left: 2px; padding-right: 2px; padding-top: 2px} "
CSSDefault + "entry {padding-bottom: 3px; padding-left: 6px; padding-right: 6px; padding-top: 3px} "
CSSDefault + "scrolledwindow undershoot.top, scrolledwindow undershoot.right, scrolledwindow undershoot.bottom, scrolledwindow undershoot.left { background-image: none; } "
CSSProvider= gtk_css_provider_new()
gtk_css_provider_load_from_data(CSSProvider, CSSDefault, -1, 0)
Screen = gdk_display_get_default_screen_(gdk_display_get_default_())
gtk_style_context_add_provider_for_screen(Screen, CSSProvider, #GTK_STYLE_PROVIDER_PRIORITY_APPLICATION)
g_object_unref_(CSSProvider)
EndProcedure
CompilerEndIf
;- 10 - Enumerations
Enumeration GadgetType
#GadgetTypeText
#GadgetTypeString
#GadgetTypeButton
#GadgetTypeButtonImage
#GadgetTypeCanvas
#GadgetTypeScrollArea
EndEnumeration
Enumeration DWMWINDOWATTRIBUTE ; used for darkmode
#DWMWA_USE_IMMERSIVE_DARK_MODE = 20
EndEnumeration
Enumeration AlignHorizontal
#AlignHorizontalLeft
#AlignHorizontalCentre
#AlignHorizontalRight
EndEnumeration
Enumeration AlignVertical
#AlignVerticalTop
#AlignVerticalCentre
#AlignVerticalBottom
EndEnumeration
Enumeration ColourPalette
#ColourPalette0
#ColourPalette1
#ColourPalette2
#ColourPalette3
#ColourPalette4
#ColourPalette5
#ColourPalette6
EndEnumeration
Enumeration GadgetEdge
#GadgetEdgeNone
#GadgetEdgeTop
#GadgetEdgeRight
#GadgetEdgeBottom
#GadgetEdgeLeft
EndEnumeration
Enumeration DimensionType
#DimensionNormal
#DimensionPercentage
#DimensionCalculated
EndEnumeration
;- 20 - Constants
#MAX_WINDOWS = 4
#MAX_GADGETS = 50
#MAX_MENU_TITLES = 20
#MAX_MENU_ITEMS = 50
#MAX_EVENTS = 64
#MAX_COLOUR_SCHEMES = 6
#MS_TO_SAVE_MOVED_WINDOW = 1500
#ENABLE_MENU = 0
#DISABLE_MENU = 1
#DARK_MODE_BACKGROUND = $383838
#DARK_MODE_COLOUR1 = $191919
#DARK_MODE_COLOUR2 = $202020
#DARK_MODE_FOREGROUND = $FFFFFF
#Bug_1_Workaround = #True
#Bug_3_Workaround = #True
#SCROLLBAR_WIDTH_WIN = 18
#SCROLLBAR_WIDTH_MAC = 18
#SCROLLBAR_WIDTH_LIN = 14
;- 30 - Structures
Structure DesktopStructure
; structure to store parametres for each available display
name.s
width.i
height.i
depth.i
frequency.i
resolutionX.d
resolutionY.d
EndStructure
Structure WindowStructure
allowResize.i ; to allow the window to be resized or maximised
backColour.i ; background colour of window
centerNew.i ; center the window if Position_Set is not set
centerParent.i ; always centers window to the parent window
disableParent.i ; when set causes the parent window to be disabled
height.i ; Height
invisible.i ; set to make the window invisible
maximised.i ; set when window is maximised
maximiseEnable.i ; enables the maximise button
menuEnable.i
menuInit.i ; set to 1 when the menu is initialised
menuHeight.i ; height of the menu in pixels, Windows = 20
minWidth.i ; minimum size of window
minHeight.i
minimiseEnable.i ; enables the minimise button
moved.i ; set when the window is moved, reset manually
num.i ; index of the window, starts at 0
parent.i ; -1 means no parent window, 0 is the first window etc
positionSet.i ; set to 1 once the user sets it's position
ratio.f ; ratio of W and H
ratioEnable.i ; set to enforce keeping the ratio when resizing the window
restoreFix.i ; used as a workaround for bug #1
saveState.i ; set to save the window state
startMaximise.i ; not used anymore, solution for Bug #2 is to not use MaximiseAppWindow for anything
systemMenu.i ; shows the system menu if set
title.s
titleHeight.i
toolbarOverlay.i ; holds the ID of the overlay used when chaning the toolbar colour
width.i ; width
x.i ; X position of window
y.i ; Y position of window
EndStructure
Structure MenuTitleStructure
text.s
window.i
EndStructure
Structure MenuItemStructure
bar.i ; set to 1 for a bar
checked.i
enabled.i
imageID.i
menuID.i
text.s
EndStructure
Structure GadgetStructure
active.i ; when set tp 1 this will be active when showing the window
backColour.i
disabled.i ; set this to 1 to disable
height.i
flags.i ; gadget ID used to calculate the height of the gadget
group.i ; groups allow multiple gadgets to be aligned in one direction
heightCalc.i
heightType.i ; 0 = pixels, 1 = percent of window
id.i ; gadget id used for debugging (make sure a gadget is initialised)
imageID.i
maxHeight.i
maxWidth.i
minHeight.i
minWidth.i
minWidthType.i ; 0 = pixels, 1 = percent of window
minHeightType.i ; 0 = pixels, 1 = percent of window
maxWidthType.i ; 0 = pixels, 1 = percent of window
maxHeightType.i; 0 = pixels, 1 = percent of window
parent.i ; gadgets can belong to a parent (container, panel or scroll area)
resizeBottom.i
resizeLeft.i ; the left side is resizable
resizeRight.i; the right side is resizable
resizeTop.i
resizeHandleSize.i ; the size in pixels of the handle to grab with the mouse to resize the gadget
saveConfigWidth.i ; save the width to config
saveConfigHeight.i ; save the height to config
scrollAreaHeight.i ; scroll area when used with a scroll area
scrollAreaWidth.i ; scroll area when used with a scroll area
scrollStep.i
text.s
toolTip.s
type.i
width.i
widthCalc.i ; gadget ID used to calculate the width of the gadget
widthType.i ; 0 = pixels, 1 = percent of window
window.i
windowHeight.i ; the height is equal to the window height and will automatically be resized
windowWidth.i ; the width is equal to the window width and will automatically be resized
x.i
xAlign.i ; 0=left, 1=right, 2=center
xAlt.i
xCalc.i ; calculated x from another gadget x+width
xType.i ; ; 0 = normal, 1 = calculated from a gadget x+width
y.i
yAlign.i ; 0=left, 1=right, 2=center
yAlt.i
yCalc.i ; calculated y from another gadget y+height
yType.i ; ; 0 = normal, 1 = calculated from a gadget y+height
EndStructure
Structure GadgetActionStructure
hoverID.i ; the ID of the gadget being hovered over (-1 means none)
hoverEdge.i ; the edge of the gadget being hovered over (see GadgetEdge enumeration)
dragID.i ; the ID of the gadget that is being dragged (-1 means none)
dragEdge.i ; the edge of the gadget that is being dragged
MX.i ; mouse position
MY.i
EndStructure
Structure WindowDataStructure
; Structure of pointers used for event binding
*desktops.DesktopStructure
*windows.WindowStructure ; this points to the first array record, and can move through the array as needed
*gadgets.GadgetStructure
*settings.SettingsStructure
*events.EventsStructure
*numWindows.Integer
*numGadgets.Integer
*numEvents.Integer
*quit.Integer
EndStructure
Structure ColoursStructure ; holds the colours used by the app
colour0.i
colour1.i
colour2.i
colour3.i
colour4.i
colour5.i
colour6.i
EndStructure
Structure SettingsStructure
colourScheme.i ; selected colour scheme 0=default
colours.ColoursStructure[#MAX_COLOUR_SCHEMES]
debugOutline.i ; turns on outline of gadgets for debugging
EndStructure
Structure EventStructure
event.i
eventGadget.i
eventType.i
EndStructure
;- 40 - Prototypes
PrototypeC.i DwmSetWindowAttribute(hwnd.i, dwAttribute.l, *pvAttribute, cbAttribute.l) ; used for dark mode
;- 50 - Globals
;- 60 - Variables
Define activeDesktop.i = 0 ; currently active desktop
Define activeWindow.i = 0 ; currently active window
Define addGadget.i = 0 ; next gadget to add
Define colours.ColoursStructure
Define darkMode.i ; turns on darkmode (Windows only)
Dim desktops.DesktopStructure(0) ; Array to hold monitor information
Dim events.EventStructure(#MAX_EVENTS) ; array to hold events
Define numEvents.i ; number of events currently stored
Dim gadgets.GadgetStructure(#MAX_GADGETS) ; array to hold gadgets, always store gadgets for one window sequentially in one block
Define gadgetActions.GadgetActionStructure ; structure to hold variables for acting on gadgets
Define lastWindowMove.q ; last time a window was moved, 0 if not moved
Dim menuItems.MenuItemStructure(#MAX_MENU_ITEMS) ; array to hold menu items, always store menus for one window sequentially in one block
Dim menuTitles.MenuTitleStructure(#MAX_MENU_TITLES) ; array to hold menu titles
Dim menuWindowIndex.i(#MAX_MENU_ITEMS) ; array to hold menu start id, useful for optimising
Define numMonitors.i = 0 ; number of monitors detected
Define quit.i = 0
Define saveSettings.i ; used to trigger a save of settings
Define settings.SettingsStructure
Define settingsFilename.s = "settings.cfg"
Define settingsLoaded.i = 0 ; set to 1 if settings have been loaded
Define toolbarColour.i
Define windowData.WindowDataStructure ; used to pass pointers to bound procedures
Dim windows.WindowStructure(#MAX_WINDOWS) ; array to hold windows
;- 70 - Procedure declarations
Declare ResizeGadget2(gadget.i, window.i, *gadgets.GadgetStructure, numGadgets.i, *desktop.DesktopStructure, *window.WindowStructure, *settings.SettingsStructure)
;- 80 - Procedures
Procedure.i x2(window.i, gadget.i, *gadgets.GadgetStructure, numGadgets.i, *desktop.DesktopStructure)
; *gadgets is a pointer to an array of gadgets
Protected wWidth.i
Protected x.i = 0
Protected group.i
Protected totalWidth.i ; width of the individual gadget or group of gadgets
Protected firstGroupGadget.i ; the first gadget using that group
Protected c.i
Protected *currentGadget.GadgetStructure
Protected *calcGadget.GadgetStructure
Protected *nextGadget.GadgetStructure
*currentGadget = *gadgets + (SizeOf(GadgetStructure) * gadget)
If *currentGadget\window <> window
; gadget is not on the window
ProcedureReturn -1
EndIf
wWidth = WindowWidth(window, #PB_Window_InnerCoordinate)
group = *currentGadget\group
For c = 0 To numGadgets-1
*nextGadget = *gadgets + (SizeOf(GadgetStructure) * c)
If *nextGadget\group = group
Break
EndIf
Next c
firstGroupGadget = c
If group >= 0 ; only calculate group if it is an actual group
For c = 0 To numGadgets-1
*nextGadget = *gadgets + (SizeOf(GadgetStructure) * c)
If *nextGadget\group = group
totalWidth = totalWidth + *nextGadget\width
EndIf
Next c
Else
totalWidth = *currentGadget\width
EndIf
; left aligned
x = *currentGadget\x
; check if it's calculated from another gadget
If *currentGadget\xType = 1
; calculated from another gadget
*calcGadget = *gadgets + (SizeOf(GadgetStructure) * *currentGadget\xCalc)
x = *calcGadget\x + *calcGadget\width
EndIf
; centre aligned
If *currentGadget\xAlign = #AlignHorizontalCentre
x = (wWidth/2) - (totalWidth/2) ; set x to the left most position for the group
If group <> -1 ; only process the group if the gadget is in one
c = firstGroupGadget
*nextGadget = *gadgets + (SizeOf(GadgetStructure) * c)
While *nextGadget\group = group And c < numGadgets
If c < gadget
x = x + *nextGadget\width
EndIf
c = c + 1
*nextGadget = *gadgets + (SizeOf(GadgetStructure) * c)
Wend
EndIf
EndIf
; right aligned
If *currentGadget\xAlign = #AlignHorizontalRight
x = wWidth - *currentGadget\width
If group <> -1 ; only process the group if the gadget is in one
c = firstGroupGadget
*nextGadget = *gadgets + (SizeOf(GadgetStructure) * c)
While *nextGadget\group <> group
x = x + *nextGadget\width
c = c + 1
*nextGadget = *gadgets + (SizeOf(GadgetStructure) * c)
Wend
EndIf
EndIf
ProcedureReturn x
EndProcedure
Procedure.i y2(window.i, gadget.i, *gadgets.GadgetStructure, numGadgets.i, *desktop.DesktopStructure)
; *gadgets is a pointer to an array of gadgets
Protected wHeight.i
Protected y.i = 0
Protected group.i
Protected totalHeight.i ; width of the individual gadget or group of gadgets
Protected firstGroupGadget.i ; the first gadget using that group
Protected c.i
Protected *currentGadget.GadgetStructure
Protected *calcGadget.GadgetStructure
Protected *nextGadget.GadgetStructure
*currentGadget = *gadgets + (SizeOf(GadgetStructure) * gadget)
If *currentGadget\window <> window
; gadget is not on the window
ProcedureReturn -1
EndIf
wHeight = WindowWidth(window, #PB_Window_InnerCoordinate)
group = *currentGadget\group
For c = 0 To numGadgets-1
*nextGadget = *gadgets + (SizeOf(GadgetStructure) * c)
If *nextGadget\group = group
Break
EndIf
Next c
firstGroupGadget = c
If group >= 0 ; only calculate group if it is an actual group
For c = 0 To numGadgets-1
*nextGadget = *gadgets + (SizeOf(GadgetStructure) * c)
If *nextGadget\group = group
totalHeight = totalHeight + *nextGadget\height
EndIf
Next c
Else
totalHeight = *currentGadget\height
EndIf
; top aligned
y = *currentGadget\y
; check if it's calculated from another gadget
If *currentGadget\yType = 1
; calculated from another gadget
*calcGadget = *gadgets + (SizeOf(GadgetStructure) * *currentGadget\yCalc)
y = *calcGadget\y + *calcGadget\height
EndIf
; centre aligned
If *currentGadget\yAlign = #AlignVerticalCentre
y = (wHeight/2) - (totalHeight/2) ; set x to the left most position for the group
If group <> -1 ; only process the group if the gadget is in one
c = firstGroupGadget
*nextGadget = *gadgets + (SizeOf(GadgetStructure) * c)
While *nextGadget\group = group And c < numGadgets
If c < gadget
y = y + *nextGadget\height
EndIf
c = c + 1
*nextGadget = *gadgets + (SizeOf(GadgetStructure) * c)
Wend
EndIf
EndIf
; bottom aligned
If *currentGadget\yAlign = #AlignVerticalBottom
y = wHeight - *currentGadget\Height
If group <> -1 ; only process the group if the gadget is in one
c = firstGroupGadget
*nextGadget = *gadgets + (SizeOf(GadgetStructure) * c)
While *nextGadget\group <> group
y = y + *nextGadget\height
c = c + 1
*nextGadget = *gadgets + (SizeOf(GadgetStructure) * c)
Wend
EndIf
EndIf
ProcedureReturn y
EndProcedure
Procedure.i Width2(window.i, gadget.i, *gadgets.GadgetStructure, numGadgets.i, *desktop.DesktopStructure)
Protected wWidth = WindowWidth(window, #PB_Window_InnerCoordinate)
Protected scaleAdjust.i = 0
Protected x1.i, x2.i
Protected *currentGadget.GadgetStructure = *gadgets + (SizeOf(GadgetStructure) * gadget)
If wWidth % 2 = 1 ;And *currentGadget\xAlign = #AlignHorizontalRight
scaleAdjust = Int(Round(*desktop\resolutionX, #PB_Round_Down)) ; this is used because sometimes it doesn't go all the way to the edge of the window due to the scale
EndIf
If *currentGadget\widthType = #DimensionNormal
ProcedureReturn *currentGadget\width + scaleAdjust
ElseIf *currentGadget\widthType = #DimensionPercentage
ProcedureReturn (wWidth * *currentGadget\width / 100) - *currentGadget\x + scaleAdjust
ElseIf *currentGadget\widthType = #DimensionCalculated
x1 = x2(window, gadget, *gadgets, numGadgets, *desktop)
x2 = x2(window, *currentGadget\widthCalc, *gadgets, numGadgets, *desktop)
ProcedureReturn x2-x1 + scaleAdjust
EndIf
EndProcedure
Procedure.i Height2(window.i, gadget.i, *gadgets.GadgetStructure, numGadgets.i, *desktop.DesktopStructure, *window.WindowStructure)
Protected wHeight = WindowHeight(window, #PB_Window_InnerCoordinate)
Protected menuHeight.i = 0
Protected scaleAdjust.i = 0
Protected y1.i, y2.i
Protected *currentGadget.GadgetStructure = *gadgets + (SizeOf(GadgetStructure) * gadget)
If *window\menuHeight > 0
menuHeight = *window\menuHeight
EndIf
If wHeight % 2 = 1 And *currentGadget\yAlign = #AlignVerticalBottom
scaleAdjust = Int(Round(*desktop\resolutionY, #PB_Round_Down)) ; this is used because sometimes it doesn't go all the way to the edge of the window due to the scale
EndIf
If *currentGadget\heightType = #DimensionNormal
ProcedureReturn *currentGadget\height + scaleAdjust
ElseIf *currentGadget\heightType = #DimensionPercentage
ProcedureReturn (wHeight * *currentGadget\Height / 100) - *currentGadget\y + menuHeight + scaleAdjust
ElseIf *currentGadget\heightType = #DimensionCalculated
y1 = y2(window, gadget, *gadgets, numGadgets, *desktop)
y2 = y2(window, *currentGadget\heightCalc, *gadgets, numGadgets, *desktop)
ProcedureReturn y2-y1 + scaleAdjust
EndIf
EndProcedure
Procedure.i MaxWidth(window.i, gadget.i, *gadgets.GadgetStructure)
Protected wWidth = WindowWidth(window, #PB_Window_InnerCoordinate)
Protected *currentGadget.GadgetStructure = *gadgets + (SizeOf(GadgetStructure) * gadget)
If *currentGadget\maxWidthType = #DimensionPercentage
ProcedureReturn wWidth * *currentGadget\maxWidth / 100
Else
ProcedureReturn *currentGadget\maxWidth
EndIf
EndProcedure
Procedure.i MaxHeight(window.i, gadget.i, *gadgets.GadgetStructure)
Protected wHeight = WindowHeight(window, #PB_Window_InnerCoordinate)
Protected *currentGadget.GadgetStructure = *gadgets + (SizeOf(GadgetStructure) * gadget)
If *currentGadget\maxWidthType = #DimensionPercentage
ProcedureReturn wHeight * *currentGadget\maxWidth / 100
Else
ProcedureReturn *currentGadget\maxHeight
EndIf
EndProcedure
Procedure.i DragWidth(MX.i, window.i, Array gadgets.GadgetStructure(1), gadget.i, dragEdge.i)
Protected wWidth.i
Protected newWidth.i
Protected minWidth.i
Protected maxWidth.i
wWidth = WindowWidth(window, #PB_Window_InnerCoordinate)
minWidth = gadgets(gadget)\minWidth
maxWidth = gadgets(gadget)\maxWidth
If gadgets(gadget)\maxWidthType = 1
; convert to percentage
maxWidth = wWidth * gadgets(gadget)\maxWidth / 100
EndIf
If gadgets(gadget)\minWidthType = 1
; convert to percentage
minWidth = wWidth * gadgets(gadget)\minWidth / 100
EndIf
Select dragEdge
Case #GadgetEdgeLeft
newWidth = wWidth - MX
Case #GadgetEdgeRight
newWidth = MX
EndSelect
If newWidth > maxWidth
newWidth = maxWidth
EndIf
If newWidth < minWidth
newWidth = minWidth
EndIf
ProcedureReturn newWidth
EndProcedure
Procedure.i DragHeight(MY.i, window.i, Array gadgets.GadgetStructure(1), gadget.i, dragEdge.i)
Protected wHeight.i
Protected newHeight.i
Protected minHeight.i
Protected maxHeight.i
wHeight = WindowHeight(window, #PB_Window_InnerCoordinate)
minHeight = gadgets(gadget)\minHeight
maxHeight = gadgets(gadget)\maxHeight
If gadgets(gadget)\maxHeightType = 1
; convert to percentage
maxHeight = wHeight * gadgets(gadget)\maxHeight / 100
EndIf
If gadgets(gadget)\minHeightType = 1
; convert to percentage
minHeight = wHeight * gadgets(gadget)\minHeight / 100
EndIf
Select dragEdge
Case #GadgetEdgeTop
newHeight = wHeight - MY
Case #GadgetEdgeBottom
newHeight = MY
EndSelect
;Debug "minHeight: " + minHeight + " maxHeight: " + maxHeight
If newHeight > maxHeight
newHeight = maxHeight
EndIf
If newHeight < minHeight
newHeight = minHeight
EndIf
ProcedureReturn newHeight
EndProcedure
Procedure AutoResizeMax(window.i, *gadgets.GadgetStructure, numGadgets.i, *windows.WindowStructure, *desktops.DesktopStructure, *settings.SettingsStructure)
Protected c.i
Protected maxWidth.i
Protected maxHeight.i
Protected *currentGadget.GadgetStructure
Protected *currentWindow.WindowStructure = *windows + SizeOf(WindowStructure) * window
; Resize gadgets that are too big for the window
; For example this happens with gadgets where the max size is a percentage of the window
For c = 0 To numGadgets-1
*currentGadget = *gadgets + SizeOf(GadgetStructure) * c
If *currentGadget\maxWidthType = #DimensionPercentage And *currentGadget\window = window
maxWidth = MaxWidth(window, c, *gadgets)
If *currentGadget\width > maxWidth
*currentGadget\width = maxWidth
ResizeGadget2(c, window, *gadgets, numGadgets, *desktops, *currentWindow, *settings)
EndIf
maxHeight = MaxHeight(window, c, *gadgets)
If *currentGadget\height > maxHeight
*currentGadget\height = maxHeight
ResizeGadget2(c, window, *gadgets, numGadgets, *desktops, *currentWindow, *settings)
EndIf
EndIf
Next c
EndProcedure
Procedure.i GetColour(colour.i, *settings.SettingsStructure)
Protected returnColour.i
Select colour
Case 0
returnColour = *settings\colours[*settings\colourScheme]\colour0
Case 1
returnColour = *settings\colours[*settings\colourScheme]\colour1
Case 2
returnColour = *settings\colours[*settings\colourScheme]\colour2
Case 3
returnColour = *settings\colours[*settings\colourScheme]\colour3
Case 4
returnColour = *settings\colours[*settings\colourScheme]\colour4
Case 5
returnColour = *settings\colours[*settings\colourScheme]\colour5
Case 6
returnColour = *settings\colours[*settings\colourScheme]\colour6
Default
returnColour = 0
EndSelect
ProcedureReturn returnColour
EndProcedure
Procedure CallbackQuit()
Protected window.i = EventWindow()
Protected *windowData.WindowDataStructure
*windowData = GetWindowData(window)
*WindowData\quit = 1
EndProcedure
Procedure WindowResize()
; Procedure to run when the window size is being changed, IE while dragging the corner
; While the mouse button is down no other events are triggered
Debug "WindowResize: window resized"
Protected c.i
Protected *windowData.WindowDataStructure
Protected *desktops.DesktopStructure
Protected *desktop.DesktopStructure
Protected *windows.WindowStructure
Protected *gadgets.GadgetStructure
Protected *gadget.GadgetStructure
Protected *settings.SettingsStructure
;Protected *windowsStart ; variable to store original address of *windowData\windows
Protected window.i = EventWindow()
Protected wWidth.i
Protected wHeight.i
Protected newWidth.i
Protected newHeight.i
Protected maxWidth.i
Protected numGadgets.i
*windowData = GetWindowData(window)
;*windowsStart = *windowData\windows
*desktops = *windowData\desktops
*windows = *windowData\windows
*gadgets = *windowData\gadgets
*settings = *windowData\settings
*windows = *windows + (SizeOf(WindowStructure) * window)
numGadgets = *windowData\numGadgets
If GetWindowState(window) = #PB_Window_Normal
; only change the width and height while the window is in normal stage otherwise it will change it when maximised
*windows\width = WindowWidth(window)
*windows\height = WindowHeight(window)
EndIf
wWidth = WindowWidth(window)
wHeight = WindowHeight(window)
; resize gadgets
AutoResizeMax(window, *gadgets, numGadgets, *windows, *desktops, *settings)
For c = 0 To numGadgets-1
*gadget = *gadgets + (SizeOf(GadgetStructure) * c)
If *gadget\window = -1
Break ; there are no more initialised gadgets
EndIf
If *gadget\window = window
ResizeGadget2(c, window, *gadgets, numGadgets, *desktops, *windows, *settings)
EndIf
Next c
; Set Windows pointer back to beginning
;*windowData\windows = *windowsStart
EndProcedure
Procedure Initialise(Array windows.WindowStructure(1), numWindows.i, Array gadgets.GadgetStructure(1), numGadgets.i, Array events.EventStructure(1), *windowData.WindowDataStructure, darkMode.i, *colours.ColoursStructure, *settings.SettingsStructure)
;CompilerIf #PB_Compiler_OS = #PB_OS_Windows
; If darkMode
; SetObjectTheme(#ObjectTheme_Dark)
; EndIf
;CompilerEndIf
CompilerIf #PB_Compiler_OS = #PB_OS_Linux
SetLinuxStyle()
CompilerEndIf
; Set the windowData so it points to various variables
*windowData\windows = @windows()
*windowData\gadgets = @gadgets()
*windowData\events = @events()
*windowData\settings = *settings
*windowData\numWindows = numWindows
*windowData\numGadgets = numGadgets
*windowData\quit = 0
*settings\colourScheme = 0
*settings\colours[0]\colour0 = $FFFFFF
*settings\colours[0]\colour1 = $F0F0F0
*settings\colours[0]\colour2 = $E0E0E0
*settings\colours[0]\colour3 = $D0D0D0
*settings\colours[0]\colour4 = $C0C0C0
*settings\colours[0]\colour5 = $B0B0B0
*settings\colours[0]\colour6 = $A0A0A0
*settings\debugOutline = 0
EndProcedure
Procedure InitResizeBinding()
BindEvent(#PB_Event_SizeWindow, @WindowResize())
EndProcedure
Procedure InitDesktop(Array desktops.DesktopStructure(1), *numMonitors.Integer, *windowData.WindowDataStructure)
; used to check which monitors are connected
Protected c.i
*numMonitors\i = ExamineDesktops()
Debug "InitDesktop: " + *numMonitors\i + " monitor(s) detected"
If *numMonitors\i > 0
ReDim desktops(*numMonitors\i)
For c = 0 To *numMonitors\i - 1
desktops(c)\name = DesktopName(c)
desktops(c)\width = DesktopWidth(c)
Debug "InitDesktop: Desktop(" + c + ")\Width: " + desktops(c)\Width
desktops(c)\height = DesktopHeight(c)
desktops(c)\depth = DesktopDepth(c)
desktops(c)\frequency = DesktopFrequency(c)
desktops(c)\resolutionX = DesktopResolutionX()
desktops(c)\resolutionY = DesktopResolutionY()
Next
Else
; ExamineDesktops() returned 0
Debug "InitDesktop: could not initialise desktop"
ProcedureReturn 0
EndIf
*windowData\desktops = @desktops()
ProcedureReturn 1
EndProcedure
Procedure.i InitWindows(Array windows.WindowStructure(1), numWindows.i, Array gadgets.GadgetStructure(1), numGadgets.i, *windowData.WindowDataStructure)
Protected result.i, c.i
result = 0
If numWindows > 0
;ReDim windows(numWindows)
For c = 0 To numWindows - 1
; set defaults
windows(c)\title = "Window #" + c
windows(c)\x = 30
windows(c)\y = 30
windows(c)\width = 640
windows(c)\height = 480
windows(c)\systemMenu = 1
windows(c)\minimiseEnable = 1
windows(c)\maximiseEnable = 1
windows(c)\minWidth = 0
windows(c)\minHeight = 0
windows(c)\allowResize = 1
windows(c)\saveState = 1
windows(c)\centerNew = 1
windows(c)\parent = -1
windows(c)\disableParent = 0
windows(c)\centerParent = 0
windows(c)\invisible = 0
; other variables
windows(c)\positionSet = 0
windows(c)\restoreFix = 0 ; See bug #1
windows(c)\maximised = 0
windows(c)\ratio = windows(0)\height / windows(0)\width
windows(c)\moved = 0
windows(c)\menuInit = 0
windows(c)\menuEnable = 0
windows(c)\backColour = -1 ; -1 means no back colour specified
Next
result = 1
Debug "Initialised " + c + " windows"
Else
Debug "InitWindows: numWindows must be set to 1 or greater"
EndIf
ProcedureReturn result
EndProcedure
Procedure InitGadgets(Array gadgets.GadgetStructure(1), *gadgetActions.GadgetActionStructure)
Protected c.i
For c = 0 To #MAX_GADGETS-1
gadgets(c)\window = -1 ; set windows to -1 so the end of the gadget set can be found
gadgets(c)\group = -1 ; -1 means no group
gadgets(c)\parent = -1 ; -1 means no group
Next c
*gadgetActions\dragID = -1
*gadgetActions\dragEdge = 0
*gadgetActions\hoverID = -1
*gadgetActions\hoverEdge = 0
EndProcedure
Procedure InitMenus(Array menuTitles.MenuTitleStructure(1), Array menuItems.MenuItemStructure(1))
Protected c.i
For c = 0 To #MAX_MENU_TITLES-1
menuTitles(c)\window = -1 ; set menus to -1 so the end of the menu set can be found
Next c
For c = 0 To #MAX_MENU_ITEMS-1
menuItems(c)\menuID = -1 ; set menus to -1 so the end of the menu item set can be found
Next c
EndProcedure
Procedure.i CheckGadgets(Array gadgets.GadgetStructure(1), numGadgets.i)
Protected c.i
Protected result.i = 1
For c = 0 To numGadgets-1
If gadgets(c)\window < 0
Debug "CheckGadgets: ERROR - gadget " + c + " is not set to a window"
result = 0
EndIf
If gadgets(c)\resizeLeft Or gadgets(c)\resizeRight Or gadgets(c)\resizeTop Or gadgets(c)\resizeBottom And gadgets(c)\resizeHandleSize <=0
Debug "CheckGadgets: ERROR - gadget " + c + " is resizeable but has no resize handle"
result = 0
EndIf
If (gadgets(c)\minHeightType = 1 And gadgets(c)\minHeight > 100) Or (gadgets(c)\maxHeightType = 1 And gadgets(c)\maxHeight > 100) Or
(gadgets(c)\minWidthType = 1 And gadgets(c)\minWidth > 100) Or (gadgets(c)\maxWidthType = 1 And gadgets(c)\maxWidth > 100)
Debug "CheckGadgets: ERROR - gadget " + c + " min/max out of range (0-100%)"
result = 0
EndIf
If gadgets(c)\window = -1
Debug "CheckGadgets: ERROR - gadget " + c + " window is set To -1. Please check configuration"
result = 0
EndIf
Next c
ProcedureReturn result
EndProcedure
Procedure MenuShow(window.i, Array windows.WindowStructure(1), Array menuTitles.MenuTitleStructure(1), Array menuItems.MenuItemStructure(1), *settings.SettingsStructure)
; Creates menu
Protected c.i = 0
Protected d.i = 0
Protected menuActive.i = 0 ; is set when a menu is active on the current window
Debug "MenuShow: showing menu for window: " + window
; find the first title for the window
While menuTitles(c)\window <> window And c < #MAX_MENU_TITLES
Debug "MenuTitle rejected: " + menuTitles(c)\window
c = c + 1
Wend
If c < #MAX_MENU_TITLES
;Debug "MenuShow: creating menu: " + c
CreateMenu(window, WindowID(window))
windows(window)\menuInit = 1
While menuTitles(c)\window = window
menuActive = 1
;Debug "MenuShow: creating menu title: " + c
MenuTitle(menuTitles(c)\text)
While menuItems(d)\menuID = c
;Debug "MenuShow: creating menu item: " + d
If menuItems(d)\bar
MenuBar()
Else
MenuItem(d, menuItems(d)\text)
If Not menuItems(d)\enabled
DisableMenuItem(window, d, 1)
EndIf
EndIf
d = d + 1
Wend
c = c + 1
Wend
Else
Debug "Window has no menu"
EndIf
; set up applicatiuon menu for macOS
CompilerIf #PB_Compiler_OS = #PB_OS_MacOS
MenuItem(#PB_Menu_About, "About")
MenuItem(#PB_Menu_Preferences, "Preferences")
MenuItem(#PB_Menu_Quit, "Quit")
BindMenuEvent(window, #PB_Menu_Quit, @CallbackQuit())
CompilerEndIf
If menuActive
CompilerSelect #PB_Compiler_OS
CompilerCase #PB_OS_Linux
windows(window)\menuHeight = 28
CompilerCase #PB_OS_Windows
windows(window)\menuHeight = 20
CompilerCase #PB_OS_MacOS
windows(window)\menuHeight = 0
CompilerEndSelect
EndIf
Debug "MenuShow: complete"
EndProcedure
Procedure MenuDisable(Array menusTitles.MenuTitleStructure(1), Array menuItems.MenuItemStructure(1), window.i, state.i)
; Disables all menu items in a menu
; The menu number coresponds to the window number
Protected c.i
Protected d.i
For c = 0 To #MAX_MENU_TITLES-1
If menusTitles(c)\window = window
Break
EndIf
Next c
If state
Debug "MenuDisable: disabling menu: " + c
Else
Debug "MenuDisable: enabling menu: " + c
EndIf
While menusTitles(c)\window = window
While menuItems(d)\menuID = c
; enable them only if the flag is set
If state = 1
; disable all
DisableMenuItem(window, d, 1)
Else
If menuItems(d)\enabled
DisableMenuItem(window, d, 0)
EndIf
EndIf
d = d + 1
Wend
c = c + 1
Wend
EndProcedure
Procedure.i WindowShow(window.i, *desktop.DesktopStructure, *window.WindowStructure, *activeWindow.Integer, *windowData.WindowDataStructure, darkMode.i, *settings.SettingsStructure)
Protected flags.i, result.i, c.i
Protected DwmSetWindowAttribute.DwmSetWindowAttribute ; used for dark mode
If Not *windowData
Debug "WindowShow: *windowData not set"
ProcedureReturn 0
EndIf
If *window\systemMenu
flags = flags | #PB_Window_SystemMenu
EndIf
If *window\minimiseEnable
flags = flags | #PB_Window_MinimizeGadget
EndIf
If *window\maximiseEnable
flags = flags | #PB_Window_MaximizeGadget
EndIf
If (Not *window\centerParent And *window\centerNew And Not *window\positionSet)
; don't center to screen if the centerParent flag is set
flags = flags | #PB_Window_ScreenCentered
EndIf
If *window\centerParent
flags = flags | #PB_Window_WindowCentered
EndIf
If *window\maximised
flags = flags | #PB_Window_Maximize
EndIf
If *window\allowResize
flags = flags | #PB_Window_SizeGadget
EndIf
If *window\invisible
flags = flags | #PB_Window_Invisible
EndIf
Debug "WindowShow: opening window " + window
;Debug "WindowShow: title: " + *window\title
Debug "WindowShow: width: " + *window\width + ", height: " + *window\height
Debug "WindowShow: X: " + *window\x + ", Y: " + *window\y
If *window\parent = -1
; Is the top parent window
result = OpenWindow(window, *window\x, *window\y, *window\width, *window\height, *window\title, flags)
Else
; Has a parent window
result = OpenWindow(window, *window\x, *window\y, *window\width, *window\height, *window\title, flags, WindowID(*window\parent))
EndIf
If *window\backColour >= 0
SetWindowColor(window, GetColour(*window\backColour, *settings))
EndIf
If Not result
Debug "WindowShow: could not initialise window"
ProcedureReturn 0
EndIf
CompilerIf #PB_Compiler_OS = #PB_OS_Windows
If darkMode
If OpenLibrary(0, "dwmapi")
DwmSetWindowAttribute = GetFunction(0, "DwmSetWindowAttribute")
DwmSetWindowAttribute(WindowID(window), #DWMWA_USE_IMMERSIVE_DARK_MODE, @darkMode, SizeOf(darkMode))
CloseLibrary(0)
EndIf
SetWindowColor(window, #DARK_MODE_BACKGROUND)
EndIf
CompilerEndIf
If *window\centerNew
; Update the x/y coordinates
*window\x = WindowX(window)
*window\y = WindowY(window)
EndIf
PokeI(*activeWindow, window) ; Set the ActiveWindow
If *window\parent >= 0 And *window\disableParent
; Disable the parent window
DisableWindow(*window\parent, #True)
EndIf
If *window\minWidth > 0 Or *window\minHeight > 0
WindowBounds(window, *window\minWidth, *window\minHeight, #PB_Ignore, #PB_Ignore)
EndIf
SetWindowData(window, *windowData)
CompilerIf #PB_Compiler_OS = #PB_OS_Windows
SmartWindowRefresh(window, #True)
CompilerEndIf
ProcedureReturn 1
EndProcedure
Procedure WindowClose(*activeWindow.Integer, parent.i, *quit.Integer)
If *activeWindow\i = 0
; Don't close Window 0, just set Quit variable
Debug "WindowClose: window 0 closed, quitting"
*quit\i = 1
*activeWindow\i = -1
Else
If parent >= 0
DisableWindow(parent, #False) ; enable the parent window
EndIf
CloseWindow(*activeWindow\i)
*activeWindow\i = parent
EndIf
EndProcedure
Procedure.i WindowMove(window.i, *window.WindowStructure)
If GetWindowState(window) = #PB_Window_Normal
*Window\moved = 1
*Window\x = WindowX(window)
*Window\y = WindowY(window)
*Window\positionSet = 1
Debug "WindowMove: window moved to X: " + *window\x + " Y: " + *window\y
EndIf
EndProcedure
Procedure WindowMaximise(*window.WindowStructure)
; Due to Bug #2 this procedure cannot be used for anything except setting maximised
Debug "WindowMaximise: window maximised"
*window\maximised = 1
EndProcedure
Procedure WindowRestore(window.i, *windows.WindowStructure, *gadgets.GadgetStructure, numGadgets.i, *desktops.DesktopStructure, *settings.SettingsStructure)
Protected *currentWindow.WindowStructure = *windows + SizeOf(WindowStructure) * window
Debug "WindowRestore: window restored"
*currentWindow\maximised = 0
AutoResizeMax(window, *gadgets, numGadgets, *windows, *desktops, *settings)
EndProcedure
Procedure WindowLoadSettings(filename.s, numWindows.i, *settingsLoaded.Integer, Array windows.WindowStructure(1), numGadgets.i, Array gadgets.GadgetStructure(1))
; Loads setting if available and sets defaults when no settings are available
Protected c.i, d.i
Debug "WindowLoadSettings: opening " + filename
OpenPreferences(filename)
Debug "WindowLoadSettings: loading window settings"
For c = 0 To numWindows - 1
If windows(c)\saveState ; only load windows with saveState flag
PreferenceGroup("Window " + c)
windows(c)\x = ReadPreferenceInteger("X", windows(c)\x)
windows(c)\y = ReadPreferenceInteger("Y", windows(c)\y)
If windows(c)\allowResize
windows(c)\width = ReadPreferenceInteger("Width", windows(c)\width)
windows(c)\height = ReadPreferenceInteger("Height", windows(c)\height)
EndIf
windows(c)\maximised = ReadPreferenceInteger("Maximised", windows(c)\maximised)
windows(c)\positionSet = ReadPreferenceInteger("Position_Set", windows(c)\positionSet)
EndIf
For d = 0 To numGadgets - 1
If gadgets(d)\window = c
If gadgets(d)\saveConfigWidth Or gadgets(d)\saveConfigHeight
PreferenceGroup("Gadget " + d)
EndIf
If gadgets(d)\saveConfigWidth
gadgets(d)\width = ReadPreferenceInteger("Width", gadgets(d)\width)
Debug "Read gadget " + d + " width: " + gadgets(d)\width
EndIf
If gadgets(d)\saveConfigHeight
gadgets(d)\height = ReadPreferenceInteger("Height", gadgets(d)\height)
EndIf
EndIf
Next d
Next c
*settingsLoaded\i = 1 ; set this so that SaveConfig can run
ClosePreferences()
ProcedureReturn 1
EndProcedure
Procedure WindowSaveSettings(filename.s, settingsLoaded.i, numWindows.i, Array windows.WindowStructure(1), numGadgets.i, Array gadgets.GadgetStructure(1))
; Always call LoadConfig before SaveConfig
Protected c.i, d.i
If settingsLoaded
; only save if the config has been loaded
; Create or open the config file
If FileSize(filename) = -1 Or #PB_Compiler_OS = #PB_OS_Linux
; file doesn't exist, need to create a new file
; linux requires creating the file every time
Debug "WindowSaveSettings: creating new settings file"
If Not CreatePreferences(filename)
Debug "WindowSaveSettings: ERROR - unable to create settings file"
ProcedureReturn 0
EndIf
Else
; Open the existing config file
If Not OpenPreferences(filename)
Debug "WindowSaveSettings: ERROR - unable to open existing settings file"
ProcedureReturn 0
EndIf
EndIf
CreatePreferences(filename)
; Window settings are automatically saved when closing the application
; or changing the window (while in window mode)
Debug "WindowSaveSettings: writing window preferences"
For c = 0 To numWindows - 1
If windows(c)\saveState ; only save windows with saveState flag
PreferenceGroup("Window " + c)
;Debug "Saving window settings " + c
WritePreferenceInteger("X", windows(c)\x)
WritePreferenceInteger("Y", windows(c)\y)
If windows(c)\allowResize
WritePreferenceInteger("Width", windows(c)\width)
WritePreferenceInteger("Height", windows(c)\height)
EndIf
WritePreferenceInteger("Maximised", windows(c)\maximised)
WritePreferenceInteger("Position_Set", windows(c)\positionSet)
For d = 0 To numGadgets - 1
If gadgets(d)\window = c
If gadgets(d)\saveConfigWidth Or gadgets(d)\saveConfigHeight
PreferenceGroup("Gadget " + d)
EndIf
If gadgets(d)\saveConfigWidth
WritePreferenceInteger("Width",gadgets(d)\width)
EndIf
If gadgets(d)\saveConfigHeight
WritePreferenceInteger("Height",gadgets(d)\height)
EndIf
EndIf
Next d
EndIf
Next c
ClosePreferences()
ProcedureReturn 1
Else
Debug "WindowSaveSettings: ERROR - cannot save settings because it hasn't been loaded yet"
ProcedureReturn 0
EndIf
EndProcedure
Procedure WindowActivate(*activeWindow.Integer)
Debug "WindowActivate: window activated"
*activeWindow\i = EventWindow()
EndProcedure
Procedure.i GetMouseX(window.i, *window.WindowStructure, *desktop.DesktopStructure)
Protected wMX.i, dMX.i, MX.i
wMX = WindowMouseX(window) / *desktop\resolutionX
dMX = DesktopMouseX() / *desktop\resolutionX
If wMX >= 0
MX = wMX ; when inside the window just use the window coordinates
Else
MX = dMX
If Not *window\maximised
MX = MX - *window\x
EndIf
EndIf
ProcedureReturn MX
EndProcedure
Procedure.i GetMouseY(window.i, *window.WindowStructure, *desktop.DesktopStructure)
Protected wMY.i, dMY.i, MY.i
wMY = WindowMouseY(window) / *desktop\resolutionY
dMY = DesktopMouseY() / *desktop\resolutionY
If wMY >= 0
MY = wMY ; when inside the window just use the window coordinates
Else
MY = dMY
If Not *window\maximised
MY = MY - *window\y - *window\titleHeight
EndIf
EndIf
ProcedureReturn MY
EndProcedure
Procedure GetMousePos(window, *window.WindowStructure, *desktop.DesktopStructure, *gadgetActions.GadgetActionStructure)
*gadgetActions\MX = GetMouseX(window, *window, *desktop)
*gadgetActions\MY = GetMouseY(window, *window, *desktop)
EndProcedure
Procedure.i GadgetHover(window.i, Array gadgets.GadgetStructure(1), numGadgets.i, *desktop.DesktopStructure, *window.WindowStructure)
; returns gadget number if mouse is hovering over a gadget
Protected c.i = 0
Protected MX.i, MY.i
Protected x.i, y.i
Protected width.i, height.i
Protected foundHover.i = -1
MX = GetMouseX(window, *window, *desktop)
MY = GetMouseY(window, *window, *desktop)
;Debug "MX: " + MX + " MY: " + MY
For c = 0 To numGadgets
If gadgets(c)\window = window
; first gadget found for this window
Break
EndIf
Next c
Repeat
x = x2(window, c, gadgets(), numGadgets, *desktop)
y = y2(window, c, gadgets(), numGadgets, *desktop)
width = width2(window, c, @gadgets(), numGadgets, *desktop)
height = height2(window, c, @gadgets(), numGadgets, *desktop, *window)
If gadgets(c)\type = #GadgetTypeScrollArea
If gadgets(c)\resizeRight ; only needed on the right side and bottom as they have scroll bars
width = width + gadgets(c)\resizeHandleSize ; move the resize handle over outside of the gadget
EndIf
If gadgets(c)\resizeBottom ; only needed on the right side and bottom as they have scroll bars
height = height + gadgets(c)\resizeHandleSize ; move the resize handle over outside of the gadget
EndIf
EndIf
If MX >= x And MX <= x + width And MY >= y And MY <= y + height
foundHover = c
EndIf
c = c + 1
Until c > numGadgets Or foundHover >= 0 Or gadgets(c)\window <> window
ProcedureReturn foundHover
EndProcedure
Procedure.i ResizeGadget2(gadget.i, window.i, *gadgets.GadgetStructure, numGadgets.i, *desktop.DesktopStructure, *window.WindowStructure, *settings.SettingsStructure)
; Resizes a gadget and also allows for percentage of window
; Note: this procedure takes a pointer to the gadget array, not a gadget
Protected width.i, height.i
Protected x.i, y.i
Protected *gadget.GadgetStructure
*gadget = *gadgets + (SizeOf(GadgetStructure) * gadget)
x = x2(window, gadget, *gadgets, numGadgets, *desktop)
y = y2(window, gadget, *gadgets, numGadgets, *desktop)
width = Width2(window, gadget, *gadgets, numGadgets, *desktop)
height = Height2(window, gadget, *gadgets, numGadgets, *desktop, *window)
If gadget < 0 Or gadget >= numGadgets
Debug "ResizeGadget2: ERROR invalid gadget " + gadget
ProcedureReturn 0
EndIf
If *gadget\id <> 0
ResizeGadget(gadget, x, y, width, height)
Else
Debug "ResizeGadget2: ERROR gadget " + gadget + " is not initialised"
ProcedureReturn 0
EndIf
Select *gadget\type
Case #GadgetTypeCanvas
StartDrawing(CanvasOutput(gadget))
DrawingMode(#PB_2DDrawing_Default)
Box(0, 0, width * *desktop\resolutionX, height * *desktop\resolutionY, GetColour(*gadget\backColour, *settings))
If *settings\debugOutline
DrawingMode(#PB_2DDrawing_Outlined)
Box(0, 0, width * *desktop\resolutionX, height * *desktop\resolutionY, #Blue)
EndIf
StopDrawing()
Case #GadgetTypeScrollArea
EndSelect
ProcedureReturn 1
EndProcedure
Procedure GetEvents(Array events.EventStructure(1), *numEvents.Integer)
Protected event.i
*numEvents\i = 0
event = WindowEvent()
While event And *numEvents\i < #MAX_EVENTS
events(*numEvents\i)\event = event
events(*numEvents\i)\eventGadget = EventGadget()
events(*numEvents\i)\eventType = EventType()
*numEvents\i = *numEvents\i + 1
event = WindowEvent()
Wend
EndProcedure
Procedure WindowProcessEvents(*event.EventStructure, *desktop.DesktopStructure, Array windows.WindowStructure(1), *activeWindow.Integer, Array gadgets.GadgetStructure(1), numGadgets.i, *gadgetActions.GadgetActionStructure, *quit.Integer, *saveSettings.Integer, *lastWindowMove.Quad, *settings.SettingsStructure)
Protected c.i
Protected gadget.i
Protected eventType.i
Protected MX.i
Protected MY.i
Protected x.i, y.i
Protected width.i, height.i
Protected newWidth.i
Protected newHeight.i
Protected maxWidth.i ; takes into account whether it is a percentaged based max values
Protected maxHeight.i
Protected minWidth.i ; takes into account whether it is a percentaged based max values
Protected minHeight.i
Protected wWidth.i
Protected wHeight.i
Protected gadgetHover.i
Protected window.i = *activeWindow\i
wWidth = WindowWidth(window)
wHeight = WindowHeight(window)
MX = *gadgetActions\MX
MY = *gadgetActions\MY
gadgetHover = GadgetHover(window, gadgets(), numGadgets, *desktop, @windows(window))
;Debug "Hover: " + gadgetHover + " MX: " + MX + " MY: " + MY
If gadgetHover >= 0
x = x2(window, gadgetHover, @gadgets(), numGadgets, *desktop)
y = y2(window, gadgetHover, @gadgets(), numGadgets, *desktop)
width = Width2(window, gadgetHover, @gadgets(), numGadgets, *desktop)
height = Height2(window, gadgetHover, @gadgets(), numGadgets, *desktop, @windows(window))
If gadgets(gadgetHover)\resizeLeft And MX >= x And MX <= x + gadgets(gadgetHover)\resizeHandleSize
SetGadgetAttribute(gadgetHover, #PB_Canvas_Cursor, #PB_Cursor_LeftRight)
*gadgetActions\hoverEdge = #GadgetEdgeLeft
ElseIf gadgets(gadgetHover)\resizeRight And MX >= x + width - gadgets(gadgetHover)\resizeHandleSize And MX <= x + width
SetGadgetAttribute(gadgetHover, #PB_Canvas_Cursor, #PB_Cursor_LeftRight)
;SetCursor(WindowID(window), MOUSE_CURSOR_SIZEWE)
*gadgetActions\hoverEdge = #GadgetEdgeRight
ElseIf gadgets(gadgetHover)\resizeTop And MY >= y And MY <= y + gadgets(gadgetHover)\resizeHandleSize
SetCursor(WindowID(window), MOUSE_CURSOR_SIZENS)
SetGadgetAttribute(gadgetHover, #PB_Canvas_Cursor, #PB_Cursor_UpDown)
*gadgetActions\hoverEdge = #GadgetEdgeTop
ElseIf gadgets(gadgetHover)\resizeBottom And MY >= y + height - gadgets(gadgetHover)\resizeHandleSize And MY <= y + height
SetGadgetAttribute(gadgetHover, #PB_Canvas_Cursor, #PB_Cursor_UpDown)
*gadgetActions\hoverEdge = #GadgetEdgeBottom
Else
If gadgets(gadgetHover)\type = #GadgetTypeCanvas
SetGadgetAttribute(gadgetHover, #PB_Canvas_Cursor, #PB_Cursor_Default)
EndIf
EndIf
Else
If *gadgetActions\dragEdge = 0 ; only set cursor to normal if not dragging
; not hovering over a gadget therefore the mouse should be normal
SetCursor(WindowID(window), MOUSE_CURSOR_ARROW)
*gadgetActions\hoverEdge = 0
EndIf
EndIf
If *gadgetActions\dragID >= 0 And *gadgetActions\dragEdge >= 0
Select *gadgetActions\dragEdge
Case #GadgetEdgeLeft, #GadgetEdgeRight
newWidth = DragWidth(MX, window, gadgets(), *gadgetActions\dragID, *gadgetActions\dragEdge)
gadgets(*gadgetActions\dragID)\width = newWidth
ResizeGadget2(*gadgetActions\dragID, window, @gadgets(), numGadgets, *desktop, @windows(window), *settings)
For c = 0 To numGadgets-1
If gadgets(c)\widthType = #DimensionCalculated And gadgets(c)\widthCalc = *gadgetActions\dragID
; the gadget's width depends on the dragged gadget's x
gadgets(c)\width = gadgets(*gadgetActions\dragID)\x - gadgets(c)\x
ResizeGadget2(c, window, @gadgets(), numGadgets, *desktop, @windows(window), *settings)
EndIf
If gadgets(c)\widthType = #DimensionCalculated And gadgets(c)\xCalc = *gadgetActions\dragID
; the gadget's x depends on the dragged gadget's width
gadgets(c)\x = gadgets(*gadgetActions\dragID)\x + gadgets(*gadgetActions\dragID)\width
ResizeGadget2(c, window, @gadgets(), numGadgets, *desktop, @windows(window), *settings)
EndIf
Next c
Case #GadgetEdgeTop, #GadgetEdgeBottom
newHeight = DragHeight(MY, window, gadgets(), *gadgetActions\dragID, *gadgetActions\dragEdge)
gadgets(*gadgetActions\dragID)\height = newHeight
ResizeGadget2(*gadgetActions\dragID, window, @gadgets(), numGadgets, *desktop, @windows(window), *settings)
EndSelect
EndIf
Select *event\event
Case #PB_Event_Gadget
If *event\eventGadget >= 0 ; not sure why there are gadgets events with -1
Select *event\eventType
Case #PB_EventType_MouseMove
Case #PB_EventType_MouseEnter
Case #PB_EventType_MouseLeave
;*gadgetActions\hoverID = -1
*gadgetActions\hoverEdge = 0
;Debug "Mouse leave gadget: " + *event\eventGadget
Case #PB_EventType_LeftButtonDown
Debug "Left button down"
If *gadgetActions\hoverEdge > #GadgetEdgeNone
; a draggable gadget edge is being hovered over
*gadgetActions\dragID = gadgetHover
*gadgetActions\dragEdge = *gadgetActions\hoverEdge
EndIf
Case #PB_EventType_LeftButtonUp
Debug "Left button up"
*gadgetActions\dragID = -1
*gadgetActions\dragEdge = #GadgetEdgeNone
EndSelect
EndIf
Case #PB_Event_LeftClick
Case #PB_Event_CloseWindow
Debug "WindowProcessEvents: closing window"
WindowClose(*activeWindow, windows(window)\parent, *quit)
*saveSettings\i = 1 ; trigger a save
Case #PB_Event_MoveWindow
WindowMove(window, @windows(window))
*lastWindowMove\q = ElapsedMilliseconds()
Case #PB_Event_MaximizeWindow
WindowMaximise(@windows(window))
*saveSettings\i = 1
Case #PB_Event_RestoreWindow
WindowRestore(window, @windows(), @gadgets(), numGadgets, *desktop, *settings)
*saveSettings\i = 1
Case #PB_Event_SizeWindow
; This event is not handled by WinApp, it should be handled using a Resize() callback
*lastWindowMove\q = ElapsedMilliseconds()
Case #PB_Event_ActivateWindow
WindowActivate(*activeWindow)
EndSelect
;Debug "Hover ID: " + *gadgetActions\hoverID + ", hover edge: " + *gadgetActions\hoverEdge + ", drag ID: " + *gadgetActions\dragID + ", drag edge: " + *gadgetActions\dragEdge
EndProcedure
Procedure WindowProcessMenus(*event.EventStructure, Array windows.WindowStructure(1), Array menuTitles.MenuTitleStructure(1), Array menuItems.MenuItemStructure(1), activeWindow.i, *settings.SettingsStructure)
; Used for macOS to automatically disable menus when a child window is opened
Protected parent.i
If activeWindow >= 0 And windows(activeWindow)\menuEnable ; dont process menus when the application has quit
parent = windows(activeWindow)\parent
Select *event\event
Case #PB_Event_CloseWindow
Case #PB_Event_ActivateWindow
CompilerIf (#PB_Compiler_OS = #PB_OS_MacOS)
; make sure the parent menu is freed for macOS
If parent >= 0
Debug "WindowProcessMenus: freeing parent menu"
;MenuDisable(menuTitles(), menuItems(), parent, #DISABLE_MENU)
If windows(parent)\menuInit
FreeMenu(parent)
windows(parent)\menuInit = 0
EndIf
Else
; display the menu on the main window
MenuShow(activeWindow, windows(), menuTitles(), menuItems(), *settings)
EndIf
CompilerElse
If activeWindow >= 0
If windows(activeWindow)\menuInit
Debug "WindowProcessMenus: enabling menu on active window"
MenuDisable(menuTitles(), menuItems(), activeWindow, #ENABLE_MENU)
Else
; menu has not been initialised
Debug "WindowProcessMenus: initialising menu " + activeWindow
MenuShow(activeWindow, windows(), menuTitles(), menuItems(), *settings)
windows(activeWindow)\menuInit = 1
EndIf
EndIf
CompilerEndIf
EndSelect
EndIf
EndProcedure
Procedure.i WindowProcessSaveSettings(Array windows.WindowStructure(1), *saveSettings.Integer, *lastWindowMove.Quad, settingsFilename.s, settingsLoaded.i, numWindows.i, Array gadgets.GadgetStructure(1), numGadgets.i)
; Saves settings based on various triggers
; save if saveSettings triggers it
If *saveSettings\i
Debug "WindowProcessSaveSettings: saving due to save flag"
WindowSaveSettings(settingsFilename, settingsLoaded, numWindows, windows(), numGadgets, gadgets())
*saveSettings\i = 0
ProcedureReturn 1
EndIf
; Save if window was moved 2 seconds ago
If (*lastWindowMove\q > 0) And (ElapsedMilliseconds() - *lastWindowMove\q > #MS_TO_SAVE_MOVED_WINDOW)
Debug "WindowProcessSaveSettings: saving due to window moving"
WindowSaveSettings(settingsFilename, settingsLoaded, numWindows, windows(), numGadgets, gadgets())
*lastWindowMove\q = 0
ProcedureReturn 1
EndIf
ProcedureReturn 0
EndProcedure
Procedure GadgetShow(gadget.i, window.i, Array gadgets.GadgetStructure(1), numGadgets, *desktop.DesktopStructure, darkMode.i, *window.SettingsStructure, *settings.SettingsStructure)
Protected wWidth.i, wHeight.i
Protected width.i, height.i
Protected x.i, y.i
Protected unknownGadget.i
Protected *gadget.GadgetStructure = @gadgets() + (SizeOf(GadgetStructure) * gadget)
wWidth = WindowWidth(window, #PB_Window_InnerCoordinate)
wHeight = WindowHeight(window, #PB_Window_InnerCoordinate)
x = x2(window, gadget, @gadgets(), numGadgets, *desktop)
y = y2(window, gadget, @gadgets(), numGadgets, *desktop)
width = Width2(window, gadget, @gadgets(), numGadgets, *desktop)
height = Height2(window, gadget, @gadgets(), numGadgets, *desktop, *window)
Debug "GadgetShow: showing gadget: " + gadget + " of type: " + *gadget\type
Select *gadget\type
Case #GadgetTypeText
If *gadget\parent >= 0:OpenGadgetList(*gadget\parent):EndIf
*gadget\id = TextGadget(gadget, x, y, *gadget\width, *gadget\height, *gadget\text, *gadget\flags)
SetGadgetColor(gadget, #PB_Gadget_BackColor, GetColour(*gadget\backColour, *settings))
;SetGadgetColor(gadget, #PB_Gadget_FrontColor, GetColour(*gadget\textColour, *settings))
;If darkMode
; SetGadgetColor(gadget, #PB_Gadget_BackColor, #DARK_MODE_BACKGROUND)
; SetGadgetColor(gadget, #PB_Gadget_FrontColor, #DARK_MODE_FOREGROUND)
;EndIf
If *settings\debugOutline
StartDrawing(WindowOutput(window))
DrawingMode(#PB_2DDrawing_Outlined)
Box(x * *desktop\resolutionX, y * *desktop\resolutionY, *gadget\width * *desktop\resolutionX, *gadget\height * *desktop\resolutionY, #Blue)
StopDrawing()
EndIf
If *gadget\parent >= 0:CloseGadgetList():EndIf
Case #GadgetTypeString
If *gadget\parent >= 0:OpenGadgetList(*gadget\parent):EndIf
*gadget\id = StringGadget(gadget, x, y, width, height, *gadget\text, *gadget\flags)
If *gadget\parent >= 0:CloseGadgetList():EndIf
Case #GadgetTypeButton
If *gadget\parent >= 0:OpenGadgetList(*gadget\parent):EndIf
*gadget\id = ButtonGadget(gadget, x, y, width, height, *gadget\text, *gadget\flags)
If *gadget\parent >= 0:CloseGadgetList():EndIf
Case #GadgetTypeButtonImage
If *gadget\parent >= 0:OpenGadgetList(*gadget\parent):EndIf
*gadget\id = ButtonImageGadget(gadget, x, y, width, height, ImageID(*gadget\imageID), *gadget\flags)
If *gadget\toolTip <> ""
GadgetToolTip(gadget, *gadget\toolTip)
EndIf
If *gadget\parent >= 0:CloseGadgetList():EndIf
Case #GadgetTypeCanvas
If *gadget\parent >= 0:OpenGadgetList(*gadget\parent):EndIf
;Debug "Show canvas: x:"+x+"-y:"+y+"-w:"+width+"-h:"+height
*gadget\id = CanvasGadget(gadget, x, y, width, height, *gadget\flags)
If *gadget\flags & #PB_Canvas_Container <> 0
; canvas was flagged as a container so close gadget list
CloseGadgetList()
EndIf
StartDrawing(CanvasOutput(gadget))
DrawingMode(#PB_2DDrawing_Default)
Box(0, 0, width * *desktop\resolutionX, height * *desktop\resolutionY, GetColour(*gadget\backColour, *settings))
If *settings\debugOutline
DrawingMode(#PB_2DDrawing_Outlined)
Box(0, 0, width * *desktop\resolutionX, height * *desktop\resolutionY, #Blue)
EndIf
StopDrawing()
If *gadget\parent >= 0:CloseGadgetList():EndIf
Case #GadgetTypeScrollArea
If *gadget\parent >= 0:OpenGadgetList(*gadget\parent):EndIf
*gadget\id = ScrollAreaGadget(gadget, x, y, width, height, *gadget\scrollAreaWidth, *gadget\scrollAreaHeight, *gadget\scrollStep, *gadget\flags)
SetGadgetColor(gadget, #PB_Gadget_BackColor, GetColour(*gadget\backColour, *settings))
CloseGadgetList()
If *gadget\parent >= 0:CloseGadgetList():EndIf
Default
unknownGadget = 1
Debug "GadgetShow: unknown gadget type: " + *gadget\type
EndSelect
If Not unknownGadget
If *gadget\disabled
DisableGadget(gadget, #True)
Else
DisableGadget(gadget, #False)
EndIf
If *gadget\active
SetActiveGadget(gadget)
EndIf
EndIf
EndProcedure
Procedure GadgetShowAll(window.i, *desktop.DesktopStructure, Array windows.WindowStructure(1), Array gadgets.GadgetStructure(1), numGadgets.i, darkMode.i, *settings.SettingsStructure)
Protected c.i
For c = 0 To numGadgets
If gadgets(c)\window = window
Break ; find the fist gadget for the current window
EndIf
Next c
While gadgets(c)\window = window
GadgetShow(c, window, gadgets(), numGadgets, *desktop, darkMode, windows(window), *settings)
c = c + 1
Wend
EndProcedure
Procedure ToolbarShow(toolBar.i, window.i, *window.WindowStructure, colour.i)
CreateToolBar(toolBar, WindowID(window), #PB_ToolBar_Small)
;CompilerIf #PB_Compiler_OS = #PB_OS_Windows
; *window\toolbarOverlay = ContainerGadget(#PB_Any, 0, -2, *window\width, 24, #PB_Container_BorderLess)
; SetClassLongPtr_(GadgetID(*window\toolbarOverlay), #GCL_HBRBACKGROUND, CreateSolidBrush_(colour))
;CompilerEndIf
EndProcedure
;- 90 - Initialisation
;- 100 - Self test code
CompilerIf #PB_Compiler_IsMainFile
Enumeration Windows
#WindowMain
#WindowNew
#WindowCount
EndEnumeration
Enumeration Menus
#MenuNew
#MenuBar1
#MenuOpen
#MenuBar2
#MenuSave
#MenuSaveAs
#MenuBar3
#MenuQuit
#MenuAbout
EndEnumeration
Enumeration Gadgets
#cnvToolbar
#cnvLeftCanvas
#cnvRightCanvas
#cnvCentreCanvas
#GadgetCount
EndEnumeration
Define c.i
activeWindow = 0
settingsLoaded = 0
settingsFilename = "self-test.cfg" ; override the standard
Initialise(windows(), #WindowCount, gadgets(), #GadgetCount, events(), @windowData, darkMode, @colours, @settings)
InitDesktop(desktops(), @numMonitors, @windowData)
InitWindows(windows(), #WindowCount, gadgets(), 0, @windowData)
InitMenus(menuTitles(), menuItems())
InitGadgets(gadgets(), @gadgetActions)
; Window #0
windows(0)\title = "Test"
windows(0)\x = 30
windows(0)\y = 30
windows(0)\width = 640
windows(0)\height = 480
windows(0)\backColour = #ColourPalette0
windows(0)\systemMenu = 1
windows(0)\minimiseEnable = 1
windows(0)\maximiseEnable = 1
windows(0)\minWidth = 600
windows(0)\minHeight = 440
windows(0)\allowResize = 1
windows(0)\saveState = 1
windows(0)\centerNew = 1
windows(0)\parent = -1
windows(0)\disableParent = 0
windows(0)\centerParent = 0
windows(0)\invisible = 0
windows(0)\positionSet = 0
windows(0)\restoreFix = 0 ; See bug #1
windows(0)\maximised = 0
windows(0)\ratio = windows(0)\height / windows(0)\width
windows(0)\moved = 0
windows(0)\menuInit = 0
windows(0)\titleHeight = 50
; Window #1
windows(1)\title = "Test2"
windows(1)\x = 30
windows(1)\y = 30
windows(1)\width = 300
windows(1)\height = 400
windows(1)\backColour = -1
windows(1)\systemMenu = 1
windows(1)\minimiseEnable = 0
windows(1)\maximiseEnable = 0
windows(1)\minWidth = 300
windows(1)\minHeight = 400
windows(1)\allowResize = 0
windows(1)\saveState = 1
windows(1)\centerNew = 1
windows(1)\parent = 0
windows(1)\disableParent = 1
windows(1)\centerParent = 0
windows(1)\invisible = 0
windows(1)\positionSet = 0
windows(1)\restoreFix = 0 ; See bug #1
windows(1)\maximised = 0
windows(1)\ratio = windows(1)\height / windows(1)\width
windows(1)\moved = 0
windows(1)\menuInit = 0
; Menu
menuTitles(0)\text = "File"
menuTitles(0)\window = 0
menuTitles(1)\text = "Help"
menuTitles(1)\window = 0
menuItems(#MenuNew)\menuID = 0
menuItems(#MenuNew)\text = "New..."
menuItems(#MenuNew)\checked = 0
menuItems(#MenuNew)\enabled = 1
menuItems(#MenuNew)\imageID = 0
menuItems(#MenuBar1)\bar = 1
menuItems(#MenuBar1)\menuID = 0
menuItems(#MenuOpen)\menuID = 0
menuItems(#MenuOpen)\text = "Open..."
menuItems(#MenuOpen)\checked = 0
menuItems(#MenuOpen)\enabled = 1
menuItems(#MenuOpen)\imageID = 0
menuItems(#MenuBar2)\bar = 1
menuItems(#MenuBar2)\menuID = 0
menuItems(#MenuSave)\menuID = 0
menuItems(#MenuSave)\text = "Save"
menuItems(#MenuSave)\checked = 0
menuItems(#MenuSave)\enabled = 1
menuItems(#MenuSave)\imageID = 0
menuItems(#MenuSaveAs)\menuID = 0
menuItems(#MenuSaveAs)\text = "Save As..."
menuItems(#MenuSaveAs)\checked = 0
menuItems(#MenuSaveAs)\enabled = 1
menuItems(#MenuSaveAs)\imageID = 0
menuItems(#MenuBar3)\bar = 1
menuItems(#MenuBar3)\menuID = 0
menuItems(#MenuQuit)\menuID = 0
menuItems(#MenuQuit)\text = "Quit"
menuItems(#MenuQuit)\checked = 0
menuItems(#MenuQuit)\enabled = 1
menuItems(#MenuQuit)\imageID = 0
menuItems(#MenuAbout)\menuID = 1
menuItems(#MenuAbout)\text = "About"
menuItems(#MenuAbout)\checked = 0
menuItems(#MenuAbout)\enabled = 1
menuItems(#MenuAbout)\imageID = 0
; gadgets
gadgets(#cnvToolbar)\window = #WindowMain
gadgets(#cnvToolbar)\type = #GadgetTypeCanvas
gadgets(#cnvToolbar)\backColour = #ColourPalette2
gadgets(#cnvToolbar)\x = 0
gadgets(#cnvToolbar)\y = 0
gadgets(#cnvToolbar)\width = 100
gadgets(#cnvToolbar)\widthType = 1 ; 0 = pixels, 1 = percent of window
gadgets(#cnvToolbar)\height = 32
gadgets(#cnvToolbar)\heightType = 0 ; 0 = pixels, 1 = percent of window
gadgets(#cnvToolbar)\text = ""
gadgets(#cnvToolbar)\flags = #PB_Canvas_Container ; toolbar is a container because it contains the search bar
gadgets(#cnvToolbar)\active = 0
gadgets(#cnvLeftCanvas)\window = #WindowMain
gadgets(#cnvLeftCanvas)\type = #GadgetTypeCanvas
gadgets(#cnvLeftCanvas)\backColour = #ColourPalette1
gadgets(#cnvLeftCanvas)\x = 0
gadgets(#cnvLeftCanvas)\y = 32
gadgets(#cnvLeftCanvas)\width = 200
gadgets(#cnvLeftCanvas)\widthType = 0 ; 0 = pixels, 1 = percent of window
gadgets(#cnvLeftCanvas)\height = 100
gadgets(#cnvLeftCanvas)\heightType = 1 ; 0 = pixels, 1 = percent of window
gadgets(#cnvLeftCanvas)\text = ""
gadgets(#cnvLeftCanvas)\flags = 0
gadgets(#cnvLeftCanvas)\active = 0
gadgets(#cnvLeftCanvas)\resizeRight = 1
gadgets(#cnvLeftCanvas)\resizeHandleSize = 8
gadgets(#cnvLeftCanvas)\saveConfigWidth = 1
gadgets(#cnvLeftCanvas)\minWidth = 100
gadgets(#cnvLeftCanvas)\maxWidth = 40
gadgets(#cnvLeftCanvas)\minWidthType = 0 ; 0 = pixels, 1 = percent of window
gadgets(#cnvLeftCanvas)\maxWidthType = 1 ; 0 = pixels, 1 = percent of window
gadgets(#cnvRightCanvas)\window = #WindowMain
gadgets(#cnvRightCanvas)\type = #GadgetTypeCanvas
gadgets(#cnvRightCanvas)\backColour = #ColourPalette1
gadgets(#cnvRightCanvas)\x = 0 ; not used when right aligned
gadgets(#cnvRightCanvas)\y = 32
gadgets(#cnvRightCanvas)\xAlign = #AlignHorizontalRight
gadgets(#cnvRightCanvas)\yAlign = 0
gadgets(#cnvRightCanvas)\width = 200
gadgets(#cnvRightCanvas)\widthType = 0 ; 0 = pixels, 1 = percent of window
gadgets(#cnvRightCanvas)\height = 100
gadgets(#cnvRightCanvas)\heightType = 1 ; 0 = pixels, 1 = percent of window
gadgets(#cnvRightCanvas)\text = ""
gadgets(#cnvRightCanvas)\flags = 0
gadgets(#cnvRightCanvas)\active = 0
gadgets(#cnvRightCanvas)\resizeLeft = 1
gadgets(#cnvRightCanvas)\resizeHandleSize = 8
gadgets(#cnvRightCanvas)\saveConfigWidth = 1
gadgets(#cnvRightCanvas)\minWidth = 100
gadgets(#cnvRightCanvas)\maxWidth = 40
gadgets(#cnvRightCanvas)\minWidthType = 0 ; 0 = pixels, 1 = percent of window
gadgets(#cnvRightCanvas)\maxWidthType = 1 ; 0 = pixels, 1 = percent of window
gadgets(#cnvCentreCanvas)\window = #WindowMain
gadgets(#cnvCentreCanvas)\type = #GadgetTypeCanvas
gadgets(#cnvCentreCanvas)\backColour = #ColourPalette0
gadgets(#cnvCentreCanvas)\x = 0
gadgets(#cnvCentreCanvas)\xType = 1 ; 0 = normal, 1 = calculated from a gadget x+width
gadgets(#cnvCentreCanvas)\xCalc = #cnvLeftCanvas
gadgets(#cnvCentreCanvas)\y = 32
gadgets(#cnvCentreCanvas)\yType = 0 ; 0 = normal, 1 = calculated from a gadget y+height
gadgets(#cnvCentreCanvas)\width = 0
gadgets(#cnvCentreCanvas)\widthType = #DimensionCalculated ; 0 = pixels, 1 = percent of window, 2 = calculated from a gadget x
gadgets(#cnvCentreCanvas)\widthCalc = #cnvRightCanvas
gadgets(#cnvCentreCanvas)\height = 100
gadgets(#cnvCentreCanvas)\heightType = 1 ; 0 = pixels, 1 = percent of window, 2 = calculated from a gadget y
gadgets(#cnvCentreCanvas)\flags = 0
gadgets(#cnvCentreCanvas)\active = 0
If Not CheckGadgets(gadgets(), #GadgetCount)
End 1
EndIf
WindowLoadSettings(settingsFilename, #WindowCount, @settingsLoaded, windows(), #GadgetCount, gadgets())
WindowSaveSettings(settingsFilename, settingsLoaded, #WindowCount, windows(), #GadgetCount, gadgets())
WindowShow(0, @desktops(activeDesktop), @windows(0), @activeWindow, @windowData, darkMode, @settings)
MenuShow(activeWindow, windows(), menuTitles(), menuItems(), @settings)
GadgetShowAll(activeWindow, desktops(activeDesktop), windows(), gadgets(), #GadgetCount, darkMode, @settings)
InitResizeBinding()
Repeat
Delay(10)
GetEvents(events(), @numEvents)
GetMousePos(activeWindow, windows(activeWindow), @desktops(activeDesktop), @gadgetActions)
;Debug "MX: " + gadgetActions\MX + " MY: " + gadgetActions\MY
For c = 0 To numEvents-1
WindowProcessEvents(@events(c), @desktops(activeDesktop), windows(), @activeWindow, gadgets(), #GadgetCount, gadgetActions.GadgetActionStructure, @quit, @saveSettings, @lastWindowMove, @settings)
WindowProcessSaveSettings(windows(), @saveSettings, @lastWindowMove, settingsFilename, settingsLoaded, #WindowCount, gadgets(), #GadgetCount)
WindowProcessMenus(events(c), windows(), menuTitles(), menuItems(), activeWindow, @settings)
If quit Or windowData\quit
Break
EndIf
Next c
Until quit
WindowSaveSettings(settingsFilename, settingsLoaded, #WindowCount, windows(), #GadgetCount, gadgets())
End 0
CompilerEndIf
;- 110 - Data section
DataSection
EndDataSection