This Engineering Notebook discusses a script-based approach to changing and
restoring the arrangement of Leo's panes, including the body editor, the
nav pane, the Viewrendered and Viewrendered3 plugins' panes, and
potentially others. In a recent discussion thread here in Leo's Google
Groups site (About layouts and their settings
<https://groups.google.com/g/leo-editor/c/R4TeA5qqr8Y>), Edward asked if I
thought I could extend my experimental layout scripts in a way that we
could avoid having to reload an outline or restart Leo just to change
layouts.
I've been able to do this. In this ENB I want to explain how the system
works and the key idea that makes it feasible to restore a default layout.
It's not hard to write a script to change to a different layout. I've got
several of I've written, and Jacob recently posted some examples of his
own. These scripts can be easily put into @command nodes and into custom
menu items. The trick is to undo them and restore a default layout. The
hard part is dealing with user widgets, like the VR pane, or additional
splitters or other Qt elements that some layout script might install. It
can be hard to identify them and to know how to remove them.
In the case of user widgets, there is no general way to destroy them, and
if it's not done right, Leo's event system will stay hooked up to the
remains of a dead widget. This could spell trouble. If the widgets are
stored somewhere so they don't get garbage-collected then they have to be
found the next time the user wants to see them again. If they are stored
outside of Leo's GUI structures, then they won't be found by the new method
g.app.gui.find_widget_by_name. There is no other consistent way to find
them, either. It's these problems that I have solved.
The solution is to add a new, hidden QWidget to the main splitter. It acts
as a place to store hidden and unused widgets. This cache widget will never
become visible, and it will never get lost because there must always be a
main splitter. A widget can be removed from its location simply by changing
its parent to the cache widget. Qt will handle all the bookkeeping when we
move a widget into and out of the cache so we don't have to write *any*
caching code ourselves. The widgets will remain hidden but whole and
active, ready to be relocated from the cache to a new layout at any time.
With this idea, it becomes feasible to find and cache all user objects (I
mean ones that are not PyQt widgets) whether we know anything about them or
not. They just have to have an objectName, so if they have been cached
they can be found and put into a layout.
To make this whole system work, there needs to be code to create the cache
widget and initialize some data structures, which are stored in
*c.user_dict*. This code must be called by the command that restores the
default layout. Where should this command be?
It could be added to Leo core code. But it doesn't have to be. It can be
put into LeoSettings.leo or myLeoSettings.leo, or for testing purposes,
into the settings tree of an outline.
During the implementation of this plan, I did all the work right in my
workbook.leo outline. Now I've moved it over to myLeoSettings.leo. I think
that at some point, LeoSettings.leo would be a good home for the key code..
The command to restore the default layout runs the initialization command
using c.doCommandByName(), and if the initialization has already happened
then it will be skipped.
My prototype commands are working well for me. I'm sure some edge cases
and bugs will surface as others try them out. In a following post I will
include the scripts. There is the matter of how Leo can first apply a
default layout when an outline is opened. The simplest way is to stick with
what Leo already does in the current devel branch. However, my command to
restore the "default layout" might restore to a different one than the Leo
setting. We can work that out.
Another way would be to have Leo execute my restore command after the
outline's key widgets have been created. There could be different versions
of my initialization script for different default layouts.
A third way would be to use parametrized layout values. The initialization
code is structured to make that feasible, I think. The restore code already
uses structure parameters it gets from the initialization code and I don't
think it would need to be changed.
This post has gotten long but I want to say something about how I developed
the restore code and how Leo made it readable and quick to do. I first
worked out the algorithm in pseudo-code. Then I used named sections for
the main steps so that the top-level node reads almost exactly like the top
level of the algorithm's pseudo-code. Each named section is short and so
easy to write and debug.
What, you didn't know you could use named sections in a minibuffer command?
Sure you can, and @others too. These commands are complete Python programs,
and there is nothing that says they have to be short or confined to a
single node. Here's the top-level restore node:
c.doCommandByName('layout-initialize')
def find_widget(name):
return g.app.gui.find_widget_by_name(c, name)
ms = find_widget('main_splitter')
ss = find_widget('secondary_splitter')
initialized = True
<< initialize data structures >>
if initialized:
<< rehome body editor >>
<< cache known added widgets >>
<< set default orientations >>
<< handle bodyTabWidget >>
<< rehome essential widgets >>
<< clean up splitters >>
<< resize splitters >>
editor.show()
Summary:
1. A script-based approach to applying and restoring layouts is feasible
and practical.
2. The key new idea is to use a long-lived QWidget as a cache to hold
widgets that get removed from a layout.
3. The prototype implementation is working well.
4. The approach is compatible with the layout methods currently used in the
devel branch in the sense that it can undo the those layout changes and
return to a clean default state.
5. There are several potential ways to integrate these scripts with Leo
core code.
--
You received this message because you are subscribed to the Google Groups
"leo-editor" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
To view this discussion on the web visit
https://groups.google.com/d/msgid/leo-editor/4b3d9b7e-92f0-49cd-b272-703a75c58222n%40googlegroups.com.