Skip to content

Changing GUI code in the renderer

Tom Clarke edited this page Mar 17, 2019 · 3 revisions

Note on debugging Electron apps

Always run with dev tools open

  • Run Visual2 via yarn launch
  • Open developer tools window: View->Toggle Dev Tools.
  • This will be remembered on hot reload.
  • View the *console window` tab - this is normally open by default.
  • That will alert you to fatal code errors from failwithf or an unsafe F# construct lst.Tail etc. It will also allow you to view printout via printf etc.

Debugging Failwithf (or code exceptions)

When code is running under the renderer in the electron GUI failwithf in code does not (usually) terminate the GUI. It terminates the specific action being executed and typically what you observe is nothing happening.

Debugging code in the Renderer it is therefore a good idea to have browser developer tools (dev tools) open.

Hanging on startup

If the app hangs on startup for any reason you cannot open dev tools normally.

  • Kills the yarn launch process with Ctrl-C followed by Y in the console window
  • restart with yarn launch -D

The crash will be reported in the dev tools console window.

Tracing execution

Especially to debug a crash you may need to trace execution. Add printfn to anywhere in the code to get dev tools console printout.

Technology

See the Wiki page on the F# / FABLE / electron framework for writing desktop apps using HTML and CSS.

Viewing the DOM

  • Start Visual2 via yarn launch
  • View -> Toggle Dev Tools
  • Make dev tools pane large
  • Select Elements tab in dev tools pane
    • open nodes as needed to explore DOM tree
    • click on a node to select and view all its classes and styles
    • click top leftmost button in dev tools pane (Elements tab) to select DOM node by using mouse over and/or click on element in Visual2 window.

Introduction

The Visual2 GUI is defined by:

  • CSS with most of the custom Visual2 CSS in vistally.css
  • Fable.import.Browser.document top-level DOM node of the main window: accessible from F# as F# type HTMLElement.
  • HTML with the initial skeleton defined statically in the index.html file.
  • DOM elements defined dynamically for the memory and symbols parts of the View pane by functions in views.fs using DOM create and mutate convenience functions defined in Refs.fs
  • References to useful DOM elements in the skeleton (Buttons etc) are defined in Refs.fs using getHTML which locates a
  • listeners attached to html elements (to implement button clicks) are defined in Renderer.fs

In addition the editor window is implemented by the Monaco Editor JS component.

  • The Monaco Playground shows how to interact with editor windows.
  • The tab headings above each editor buffer are defined dynamically in tabs.fs.
  • The editors themselves (needed to interact with characters) are kept in an F# global Refs.editors which maps numeric tab ids to editors. There is one editor (and one file) for each tab, but only the current tab is actually visible.

App State and Changing the DOM

The DOM nodes with text content can have text overwritten, new child DOM nodes can be added to any node, etc. Generally it is good practice, where possible, to create new DOM functionally, without mutating nodes, and insert it into the visible document just once.

To prevent performance issues (for example the Views memory tab display). It is possible to cache inputs that change the DOM and where they have not changed, even when a new screen write is required, simply leave the existing DOM unchanged. This is done to great effect in the memory generation code.

It is good practice to have a small number of mutable variable that represent the entire app state and write out the entire DOM from them with pure functions. Visual2 almost keeps to this, with mutable values all shown in Refs.fs. However some elements, like tab names, are written whenever they are changed (typically by file load/save), rather than whenever the screen is refreshed. This is probably not the cleanest solution but because tab changes are fairly isolated it works OK.

Visual2 is not consistent when it comes to tabs, where some of the app state (the file names of each loaded file) is actually stored in the DOM itself rather than in an F# variable. Convenience functions in Refs.fs access this state, but it is bad practice and that whole section of code should be rewritten, a painful exercise.

Sample GUI Code

A module GuiExamples containing sample GUI code has been added to branch hlp2019-test.

Clone this wiki locally