Module: misc.GUI

Helper functions and classes for graphical interaction with Exudyn

  • Author: Johannes Gerstmayr

  • Date: 2020-01-25

  • Notes: This is an internal library, which is only used inside Exudyn for modifying settings.

Function: _ComplainOnce

_ComplainOnce(reason)

  • function description: say once per process that the renderer’s SystemContainer could not be used, and why

Function: GetRendererSystemContainer

GetRendererSystemContainer()

  • function description: The SystemContainer that is attached to the render engine, or None.

  • output: the container, or None when no renderer is running, when the entry names a container whose C++ object is gone, or when it names something else entirely

  • notes: None is the normal answer without a renderer and is not reported. Anything ELSE that goes wrong here says so once per process: a dialog that finds no container does nothing, and nothing being printed is how “the V key opens no dialog” became a reproduction rather than a message (#2691, maintainer 2026-09-26).

Function: MakeProcessDpiAware

MakeProcessDpiAware()

  • function description: tell Windows that this process draws at the real resolution of the display Without it, Windows renders the window at 96 dpi and stretches the bitmap, which is why a dialog opened from a shell looked soft while the same dialog opened from the render window was sharp: GLFW makes the process DPI aware when it creates the render window, and a dialog that comes after it inherits that. From “python -m exudyn dialogs” there is no GLFW (#2634). It must be called BEFORE the first window is created; afterwards Windows refuses, which is not an error here - something else has already set it, which is what we wanted.

  • output: True if this process is DPI aware afterwards

Function: TkFontSystemHint

TkFontSystemHint(platform, fontSystem)

  • function description: the hint for dialogs drawn without anti-aliasing, or ‘’ if there is nothing to say

  • input:

    • platform: sys.platform

    • fontSystem: what Tk reports as its font system, ‘xft’ or ‘x11’ on Linux

  • output: the text to print, ‘’ on Windows and macOS and for a Tk with Xft

Function: CheckTkFontSystem

CheckTkFontSystem(root)

  • function description: say once, on Linux, that the Tk of this Python has no Xft, which makes the dialog fonts jagged and coarse (#2890)

  • input:

    • root: the tkinter root that was just created

Function: ScaledFontSize

ScaledFontSize(size, fontScaling)

  • function description: a Tk font size in points, times dialogs.fontScaling A negative size is pixels - the named fonts of Tk on Linux are, e.g. -12 - and pixels do not follow the scaling of Tk, which made the buttons and edit fields stay small while the text of the tree grew (#2898). It is converted to points at 96 dpi first, so that every named font follows the display scaling once, through the scaling of Tk.

  • input:

    • size: the size as Tk gives it

    • fontScaling: dialogs.fontScaling; 0 or less is 1

  • output: the size in points, at least 6; 0 (the default of Tk) stays 0

Function: ApplyDialogFontScaling

ApplyDialogFontScaling(root)

  • function description: set the named fonts of Tk (TkDefaultFont, TkTextFont, TkFixedFont, …) in points, times dialogs.fontScaling, so that every widget of a dialog - text, buttons, edit fields, menus - takes the same font and follows the display scaling through the scaling of Tk (#2897, #2898) It is called before the widgets of a dialog are created, so nothing is rescaled while a window opens.

  • input:

    • root: the tkinter root, which owns the named fonts

Function: GetTkRootAndNewWindow

GetTkRootAndNewWindow()

  • function description: get new or current root and new window app; return list of [tkRoot, tkWindow, tkRuns]

Function: TkRootExists

TkRootExists()

  • function description: this function returns True, if tkinter has already a root window (which is assumed to have already a mainloop running)

Function: ColumnWidthFractions

ColumnWidthFractions(widths)

  • function description: the three column fractions, usable whatever was configured

  • input:

    • widths: [name, value, type], each a fraction of the dialog width

  • output: the same three, each at least 0.05, and scaled down together if they would leave the description column less than 10% of the dialog

  • notes: A settings dialog whose description column is a few pixels wide cannot be read, and the settings that produce it are three independent numbers a user may set in any order. So the rule is applied here rather than refused at the setting: what a user asks for, as far as it still leaves a dialog.

Function: DialogFontSize

DialogFontSize(fontFactor)

  • function description: the point size the tree, its headings and its tags use

  • input:

    • fontFactor: the multiplier DialogScaling returned

  • output: the size in points, never below 6

Function: DialogRowMetrics

DialogRowMetrics(root, fontFactor)

  • function description: how tall a row must be and how much wider the columns must be, MEASURED Both used to be computed from systemScaling, which is not what decides how large a glyph comes out: the point-to-pixel conversion follows the tk scaling of the display, so at dialogs.fontScaling=1 the rows were 13 pixels tall for a font with a linespace of 16 to 18 and the text was clipped, while the column factor max(1,int(round(systemScaling))) stayed at 1 for every value below 1.5 (#2631). The font is asked instead, which is right at any scaling and on any platform.

  • input:

    • root: the tkinter root, which the fonts are measured against

    • fontFactor: the multiplier DialogScaling returned

  • output: [rowHeight in pixels, columnScale relative to the unscaled font]

Function: GetExudynDisplayScaling

GetExudynDisplayScaling(root = None)

  • function description: the display scaling the dialogs size themselves by The renderer knows it and reports it in its state. Without a renderer this used to return 1, so a dialog opened from the command line came out at a different size than the same dialog opened with V in the render window (#2634); tkinter is asked instead, which knows it once MakeProcessDpiAware has been called.

  • input:

    • root: a tkinter root to ask when there is no renderer; without one the answer is 1

  • output: the scaling, 1 if nothing knows better

Function: DialogScaling

DialogScaling(root)

  • function description: How tall a row of a dialog is and how large its font is, as [systemScaling, fontFactor]. dialogs.fontScaling is 0 by default, and 0 means what every platform did before the setting existed: a fixed factor on MacOS, the system display scaling on Windows and Linux. A value > 0 sets the font on EVERY platform, which is what makes the dialogs readable on a Linux desktop - off MacOS the font factor used to be forced to 1 and nothing could change it (#2602).

  • input:

    • root: the tkinter root window, which knows the display scaling

  • output: [systemScaling, fontFactor]

Function: SplitStoredFromChanged

SplitStoredFromChanged(changes, overriddenPaths, fileName)

  • function description: The changed settings, with the ones the override file stores named separately.

  • input:

    • changes: [(path, line)] as SettingsCodeLines returns them - every setting that differs from the DEFAULT, which is what the difference is to

    • overriddenPaths: the paths that ~/.exudyn/config.json stores

    • fileName: the name of that file, for the comment line

  • output: (lines, storedCount): the same pairs, the stored ones last and behind a comment line, and how many of them there are

  • notes: The maintainer decided this on 2026-09-26: the difference is to the REAL default, and what the file already covers is named separately with a comment between them, so that a user can see what they would be copying and decide. Comparing against default-plus-override instead would hide exactly the settings that file is about.

Function: RenderStateCodeLines

RenderStateCodeLines(renderState, systemContainerName = 'SC')

  • function description: The lines that give a script the current model view of the render window, as CTRL+F3 prints them (#2862).

  • input:

    • renderState: the dictionary of SC.renderer.GetState()

    • systemContainerName: the name of the SystemContainer in the script

  • output: [(key, line)]: SC.renderer.Start() and SC.renderer.SetModelView with zoom, rotation vector and center point

Function: EditDictionaryWithTypeInfo

EditDictionaryWithTypeInfo(settingsStructure, exu = None, dictionaryName = 'edit')

  • function description: edit dictionaryData and return modified (new) dictionary

  • input:

    • settingsStructure: hierarchical settings structure, e.g., SC.visualizationSettings

    • exu: exudyn module

    • dictionaryName: name displayed in dialog

  • output: returns modified dictionary, which can be used, e.g., for SC.visualizationSettings.SetDictionary(…)

Function: StoreDialogPositions

StoreDialogPositions(settingsStructure = None)

  • function description: True if a dialog should store where it was left, when it closes.

  • input:

    • settingsStructure: the structure the dialog is editing, if it is a visualizationSettings; it is asked FIRST, because it is the one the user is looking at

  • output: the value of visualizationSettings.dialogs.storeDialogPositions, or False when there is nothing to ask

  • notes: This decides whether a dialog stores ITSELF on closing, and nothing else: a geometry that is already stored - by this flag, by the store button or by a script - is used whenever a dialog opens, see RestoreWindowGeometry (#2686). The structure is asked before the renderer’s SystemContainer because python -m exudyn dialogs has no container at all, and a script that has not started the renderer has none that can be found - so the flag used to be False there however it was set, and such a dialog could never store itself.

Function: RestoreWindowGeometry

RestoreWindowGeometry(tkWindow, name, width = None, height = None)

  • function description: Give a dialog the size and position it was left at, as far as that is safe.

  • input:

    • tkWindow: the window

    • name: the title of the dialog, which is what it is stored under

    • width: the width it would otherwise get, in pixels; None leaves the size to the layout when nothing is stored, which is what a dialog whose size is computed from its widgets needs

    • height: the height it would otherwise get, or None

  • output: None

  • notes: The size is restored always and the position only when the window would still be reachable on the current screen. A monitor that is gone, a resolution that changed, a laptop that was undocked: each of them would otherwise put the dialog where nobody can close it. A GEOMETRY THAT IS STORED IS USED, whatever dialogs.storeDialogPositions says (#2686). That flag decides whether a dialog stores ITSELF when it closes; this function only reads what is there, and it is there because the flag was on, or because the store button of the dialog wrote it, or because a script did. Asking the flag here is what made the store button (#2685) write something that nothing read back.

Function: RememberWindowGeometry

RememberWindowGeometry(tkWindow, name, settingsStructure = None)

  • function description: Record where a dialog is while it lives, so that it can be stored when it closes.

  • input:

    • tkWindow: the window

    • name: the title of the dialog, which is what it is stored under

    • settingsStructure: the structure being edited, which is asked for dialogs.storeDialogPositions before the renderer’s SystemContainer

  • output: a dictionary that StoreWindowGeometry reads; empty when nothing is to be stored

  • notes: The geometry cannot be read after the window is destroyed, and a dialog is left in three ways - the close button, Escape, and the window manager - so it is recorded on every <Configure> and the last value is the one that is stored.

Function: StoreGeometryString

StoreGeometryString(geometry, name)

  • function description: Store one ‘WIDTHxHEIGHT+X+Y’ under the name of a dialog.

  • input:

    • geometry: what tkWindow.geometry() reported

    • name: the title of the dialog

  • output: True if it was stored

  • notes: This does NOT ask whether storeDialogPositions is on: the flag decides whether a dialog remembers itself on closing, and the store button of the settings dialog stores on request (#2685). RememberWindowGeometry is where the flag is read.

Function: StoreWindowGeometry

StoreWindowGeometry(recorded, name)

  • function description: Store what RememberWindowGeometry recorded, after the dialog has closed.

  • input:

    • recorded: what RememberWindowGeometry returned

    • name: the title of the dialog

Function: ApplyDialogWindowSettings

ApplyDialogWindowSettings(tkWindow, alwaysTopmost = None, alphaTransparency = None)

  • function description: Apply what visualizationSettings.dialogs says about a dialog window.

  • input:

    • tkWindow: the window to configure

    • alwaysTopmost: None takes dialogs.alwaysTopmost; True or False overrides it

    • alphaTransparency: None takes dialogs.alphaTransparency; a float overrides it

  • output: None

Function: ShowHelpDialog

ShowHelpDialog()

  • function description: The keyboard and mouse commands of the renderer, in a read-only window; opened with H in the render window.

  • output: None

Function: ModelScope

ModelScope()

  • function description: the namespace a command of the command window runs in: the one the MODEL lives in __main__ is the script the user started, or the console they are typing in, so this is where mbs, SC and everything else the model defined are. The command window used to be a Python string that the C++ executed in exactly this namespace; as a function of this module it would otherwise see the module’s own globals, where there is no mbs (#2654).

  • output: the dictionary of __main__, which is written to as well as read: an assignment in the command window has to survive the command

Function: ShowPythonCommandDialog

ShowPythonCommandDialog()

  • function description: A window that executes a Python command in the global scope of the running model; opened with X in the render window. CTRL+RETURN runs what is in the text area.

  • output: None

Function: ShowVisualizationSettingsDialog

ShowVisualizationSettingsDialog()

  • function description: The settings tree of the renderer; opened with V in the render window.

  • output: None

Function: ShowRightMouseSelectionDialog

ShowRightMouseSelectionDialog()

  • function description: The properties of the item the right mouse button selected, read-only; the renderer has put them into exudyn.sys[‘currentRendererSelectionDict’] before calling this.

  • output: None

Function: AskQuitDialog

AskQuitDialog()

  • function description: Ask whether a long running simulation really shall be stopped; the answer goes back to the renderer in exudyn.sys[‘quitResponse’], as 2 (do not quit) or 3 (quit).

  • output: None

CLASS Tooltip (in module misc.GUI)

class description: The small yellow window that shows the description of the row under the mouse. tkinter has none, and the description used to be behind the key ‘h’ and a modal message box - which is not where a reader looks for it (#2601). It is a borderless Toplevel that is created when it is first needed and hidden afterwards, so a dialog that is never hovered never builds one. It is topmost, and that is not decoration: the dialog itself is topmost - it has to be, it blocks the render window - and on Windows a topmost window is always above one that is not, so a tooltip without the flag opens BEHIND the dialog and looks like a tooltip that never comes (#2639). The same mechanism hid the window of the changes in #2621. Turning dialogs.alwaysTopmost off made the tooltips work, which is what named the cause.

Class function: Show

Show(self, text, x, y)

  • class function description: show the tooltip after the delay, at the screen position (x, y) The delay is the maintainer’s (#2614): a description that appears the moment the pointer crosses a row is annoying, and with the find (#2607) nobody has to sweep the tree to find a setting any more.

Class function: Cancel

Cancel(self)

  • class function description: forget a tooltip that was scheduled and has not appeared yet

Class function: Bind

Bind(self, widget, text)

  • class function description: let a widget - a button, say - show this tooltip while the pointer rests on it

Class function: Place

Place(self, text, x, y)

  • class function description: place the tooltip at the screen position (x, y), a little below the pointer