Requirements For A New Layout System

55 views
Skip to first unread message

Thomas Passin

unread,
Jul 30, 2024, 4:04:20 PM7/30/24
to leo-editor
We've had several threads about layouts recently, since with the demise of the nested splitter there's no way for a user to apply other layouts except by using a script, and no way to return to a previous layout without another script. Edward is off and running with his plans.  I have been working on scripts to create and remove layouts (which can't be done in general with out a lot of new complexity).

What's been missing is much discussion of what the requirements for new layouts should be.  I've learned a lot as I've been working on a layout restoration script, and I've thought about how I think things to work.  I'd like to invite your input too.  Here's what I have come up with so far:

A user should be able to:
1. specify a default global startup layout using a setting.
2. specify a per-outline startup layout using a setting.
3. discover alternate layouts.
4. change an outline's layout to one of the alternatives by command or menu without re-opening the outline.
5. return the current outline's layout to its default, preferably without reloading the outline.

A script writer should be able to:
6. specify a new layout in a simple way.
7. assign a command to activate a layout so that a user can use it.
8. if necessary, write a teardown script that will delete all objects created for that layout and associate the script with the layout.
9. have a way for a plugin that defines layouts to make those layouts known to a user.

Leo should provide:
10. a standard way for an instantiated layout to be deleted or inactivated without leaving undeleted or dangling layout-specific objects.
11. a standard way for new layouts to be made available.


One or another of these may turn out not to be practical but I hope that won't be the case.  What else have I missed? 

Jacob Peck

unread,
Jul 30, 2024, 5:21:03 PM7/30/24
to leo-e...@googlegroups.com
I’m loath to suggest it due to Edward’s apparent dislike of the old regime, but the old free-layout plugin allowed plugins to register a ‘provider’ class that would allow free placement of a widget.  A framework akin to that — that allows *naming* plugin-defined widgets and referencing those names for placement in layouts — would be supremely useful.

Jake

On Jul 30, 2024, at 5:04 PM, Thomas Passin <tbp1...@gmail.com> wrote:

We've had several threads about layouts recently, since with the demise of the nested splitter there's no way for a user to apply other layouts except by using a script, and no way to return to a previous layout without another script. Edward is off and running with his plans.  I have been working on scripts to create and remove layouts (which can't be done in general with out a lot of new complexity).
--
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 leo-editor+...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/leo-editor/5f7dba63-083b-4dd7-aea0-2345f71d2c2fn%40googlegroups.com.

Thomas Passin

unread,
Jul 30, 2024, 5:59:23 PM7/30/24
to leo-editor
I think the old framework had a lot of virtues.  But I found it awfully hard to work with, either as a user or when writing scripts.  I thought that maybe we could come up with some interface improvements to make it easier to work with, but it ended getting yanked out instead.

I've come up with a layout descriptor that is reminiscent of the old layout descriptors but much less cryptic.  The problem is, for custom objects like plugin widgets how to get the code that builds the layout from the descriptor and how to get it to remove an added widget when it's time to change the layout.

I think that could be handled by a combination of a registration system and some conventions.  I haven't thought very much about how that might work. A registration system might not even be needed. What's needed is to know the object names that have been added and how to instantiate and delete them.  If we have that in place, the code to replace a layout with another one isn't very complicated.  I've already got a working prototype.  As long as the only added widgets are VR/VR3, it can change the layout to another one that doesn't have them.

Edward K. Ream

unread,
Jul 30, 2024, 7:53:32 PM7/30/24
to leo-e...@googlegroups.com
On Tue, Jul 30, 2024 at 3:04 PM Thomas Passin <tbp1...@gmail.com> wrote:

Here [are the requirement]  I have come up with so far:

A user should be able to:
1. specify a default global startup layout using a setting.
2. specify a per-outline startup layout using a setting.
3. discover alternate layouts.
4. change an outline's layout to one of the alternatives by command or menu without re-opening the outline.
5. return the current outline's layout to its default, preferably without reloading the outline.

All reasonable.

A script writer should be able to:
6. specify a new layout in a simple way.
7. assign a command to activate a layout so that a user can use it.
8. if necessary, write a teardown script that will delete all objects created for that layout and associate the script with the layout.
9. have a way for a plugin that defines layouts to make those layouts known to a user.

Imo, 6 and 8 will never be easy. I'm ready to give up on QtDesigner.

Summary

Some layouts are easy to provide. Some will be much harder.

Don't expect that magic tools will make all layouts easy to create.

The PR provides the machinery to:
- Put VR panes anywhere.
- Allow plugins to define layouts.

I'm ready for a vacation. I'll let others try their hand at new layouts.

Edward

Edward K. Ream

unread,
Jul 31, 2024, 3:56:36 AM7/31/24
to leo-e...@googlegroups.com
On Tue, Jul 30, 2024 at 6:53 PM Edward K. Ream <edre...@gmail.com> wrote:

> Some layouts are easy to provide. Some will be much harder.

I was too pessimistic.  An easy rule of thumb clarifies matters: The main splitter corresponds to the longest vertical or horizontal line.

For example, I was having trouble with the "render-focused" layout:

        ┌────────────────┬──────────┐
     │    outline     │          │
     ├────────────────┤          │
     │     body       │    vr    │
     ├────────────────┤          │
     │     log        │          │
     └────────────────┴──────────┘

The rule of thumb says that the main splitter splits horizontally. It contains the three panes on the left and a single (initially hidden) VR pane on the right. The secondary splitter (or splitters) split vertically.

> Don't expect that magic tools will make all layouts easy to create.

Focusing on splitters clarifies matters. QtDesigner isn't going to help.

Two more rules of thumb:

- All layouts should be independent of each other.
- Don't use settings to modify layouts.

Summary

Leo will soon have a library of official layouts. Plugins can provide more. Leo's existing features will suffice to discover and select layouts.

I expect to complete layout work soon after returning from vacation. Please be patient until then :-)

Edward

Edward K. Ream

unread,
Jul 31, 2024, 8:30:06 AM7/31/24
to leo-e...@googlegroups.com
On Wed, Jul 31, 2024 at 2:56 AM Edward K. Ream <edre...@gmail.com> wrote:

> The main splitter corresponds to the longest vertical or horizontal line.

Once this rule of thumb became clear, I saw that the "render-focused" layout must define its own QHBoxLayout widget. Otherwise, Qt will position the VR pane vertically.

To put this statement in context, all the new layout-creation methods must place their outer widget/layout in the dw.verticalLayout layout. This standard layout contains the icon and menu bars at the top and the minibuffer and status areas at the bottom

A new info item will tell script writers how to create their own layouts using the methods of the DynamicWindow class.

Edward

P.S. The dw.createBodyPane helper may need to be generalized.

EKR

Thomas Passin

unread,
Jul 31, 2024, 8:34:57 AM7/31/24
to leo-editor
There will always be the main and secondary splitters. They should never be removed.  The secondary splitter is contained in the main one.  Once I realized that, things got much clearer.  Any of Leo's standard frames - body editor, tree, log - can be placed into any splitter, and any of the splitters can be set for vertical or horizontal orientation independent of the others.  To change a layout, reparent all known widgets to their new targets (inserting each according to its prescribed index), delete other added widgets from their containers, then delete no-longer-used splitters.

"- Don't use settings to modify layouts." Yes, but settings *can* be used to create new layout script commands.

Here is an example of a layout description that can be instantiated by a script.  It uses composable sublayouts:

SUBLAYOUTS
---------------------

MAIN_SPLITTER = {'name': 'main_splitter', 'orientation': 'horizontal',
                'children': ((1, 'secondary_splitter'), (2, 'bodyFrame'))}

SECONDARY_SPLITTER = {'name': 'secondary_splitter', 'orientation': 'vertical',
                    'children': ((1, 'outlineFrame'), (2, 'logFrame'))}

Known Splitter Name Sequence (used to remove unwanted splitters)
-----------------------------------------------------
BASE_SPLITTERS = ('main_splitter', 'secondary_splitter')

Overall Sequence Of SUBLAYOUTS
-------------------------------
BASE_LAYOUT = (MAIN_SPLITTER, SECONDARY_SPLITTER)

A Complete Layout
------------------
LAYOUT = {'sub_layouts': BASE_LAYOUT, 'known_splitters': BASE_SPLITTERS}

Edward K. Ream

unread,
Jul 31, 2024, 8:53:18 AM7/31/24
to leo-e...@googlegroups.com
On Wed, Jul 31, 2024 at 7:34 AM Thomas Passin <tbp1...@gmail.com> wrote:

> There will always be the main and secondary splitters. They should never be removed. 

Yes! I forgot to mention this "new" constraint. And their must always be a vertical layout.

> "- Don't use settings to modify layouts." Yes, but settings *can* be used to create new layout script commands.

That's fine with me. And the PR defines a new setting: @string qt-layout-name.


> Here is an example of a layout description that can be instantiated by a script.  It uses composable sublayouts:

Thanks for your continued work on this project. I'll take a close look later.

Edward

Thomas Passin

unread,
Jul 31, 2024, 8:54:09 AM7/31/24
to leo-editor
"Once this rule of thumb became clear, I saw that the "render-focused" layout must define its own QHBoxLayout widgetOtherwise, Qt will position the VR pane vertically." 

Not so. The "render-focused" layout can be achieved without any new layout widgets.  They would just complicate matters. How you get the layout is to re-parent the body frame into the main splitter at index 2, and re-parent VR/VRx into the secondary splitter.  Then you set the secondary splitter to vertical orientation. Jake has already presented a script that does just this. If a VR/VR3 widget doesn't exist, then one needs to be created first.

Even when you need a new container, you don't need to use a layout widget. You make a new splitter and insert it into an existing splitter using insertWidget(index, widget). Jake's script for his "quadrant" layout (or my minor update to it) does this.

How I get VR3 to overlay the body editor is to reparent it right into the body frame, which puts it into the body's stacked widget.  That way the frame can be swapped between showing the editor and showing VR3.

IOW, you can get any layout you want by reparenting widgets, re-orienting splitters, and if necessary creating new splitters.  That's all it takes. The layout descriptors I posted a few posts above captures all that information in a human-readable and scriptable way.  The only real challenge is how to represent, create, and destroy new widgets such as VR/VR3.

Reply all
Reply to author
Forward
0 new messages