Re: New menu ideas



Michael Meeks wrote:

Hi James,

	So - firstly, this is a really bad time for me to put any review into
this sort of thing at all. I'm working really hard on making Gnome 2.0
workable, and I must confess that I am dismaid that instead of working
up the heap, helping fix problems in real applications and getting Gnome
out - people are wanting to create more changes and new APIs at the
bottom levels, although there can be no sensible scrutiny.

This certainly wasn't the intention. I simply posted my ideas to get feedback (to see if I am on crack or not). I would prefer to find out before I get to committed to a particular design (although I don't think there are too many problems). Thank you for taking the time to comment on it, btw :)

	It would also be nice if you could cross post any new Gtk menu /
toolbar API discussion to gcl, since I will at least notice it there.

On Mon, 2002-03-25 at 07:05, James Henstridge wrote:

I was going to post this to the list earlier, but got a bit sidetracked. Attached is the design document for my new action based menu API. The merge support is not fully implemented (and will probably require changes to other bits of the code to get right). I am interested in feedback though.


	Merging is tricky, not least because I did a lot of work in bonobo and
I'm not convinced it was worth it or that I designed it right, now there
are more use cases a re-thing is merited I think. Again, I will be
extremely unhappy to see the same or different mistakes without input,
but I can't spend the hours of thinking time that this problem deserves
yet - in a month perhaps. Please don't set anything in stone.

 - a name (not translated)
 - text label
 - whether label indicates a stock id
 - tooltip (optional)
 - icon (optional, ignored with stock_id)
 - toolbar label (optional, shorter than label)


	Ok - there are problems we hit with this - you say lower that only an
action & a name is allowed for a dockitem, menuitem etc. - which is
great, and the design I was aiming for on bonobo. The problem is
accelerators / mnemonics. With a menuitem you want '_Open' with the
toolbar item with the same Action you want 'Open'. Moderately easy to
solve in several ways - which is the best ? what is a good
representation for that ?

That is why I put "toolbar label" as one of the attributes for action objects. Having mnemonics for toolbar buttons does not seem very useful (things work differently depending on whether toolbar labels are displayed or not, conflict with alt+letter accelerators (if you use them), etc).

We can have different types of actions:
 - check actions (can be toggled between two states)
 - radio actions (only one in a group can be in the "active" state)


	Ok - the problem with radio actions is how to group them; it's not
trivial - if I was to implement this again I would bin GtkRadioButton
for this - since it's idea of a RadioGroup is hard to sync with anyone
else's idea - and it's just not clear how to sync different sets of
different radio buttons to ensure that they get their state right.

In the proof of concept code I did (before even looking at menu merge), I ended up using togglebuttons/checkmenuitems for radio actions (which looks identical for toolbar buttons, but a gets the wrong check mark for menus). I think this is acceptable, and since it is targetted at a future version of gtk, we might be able to add support for getting a GtkCheckMenuItem to display as a radio item.

Each action can have one or more proxy menu item, toolbar button or
other proxy widgets.  Proxies mirror the state of the action (text
label, tooltip, icon, visible, sensitive, etc), and should change when
the action's state changes.  When the proxy is activated, it should
activate its action.

=> Actions are GObjects.
=> proxies all share the same accel path, so accels are consistent.
=> Action state is exported through properties, and should probably be
  propagated to proxies through the "notify::xxx" signal.


	Again in libbonoboui we binned the Gtk+ accelerator stuff where
possible, mostly because we need to be able to add remote accelerated
actions, and we didn't have a GObject per action that we could have a
signal on that we could add accelerators with.

Well, you don't need a GObject per accel with gtk 2.0. All you really need is to assign accel paths to each action (deriving them from the action names is a good idea), then set the accel path of proxy menu items and toolbar buttons. Let gtk take care of keeping the accels consistent.

Action Groups


	If this is essentially just an ActionFactory - it sounds fine; do you
anticipate it doing much more than manufacturing Actions by name /
listing actions ?

That is all I planned on providing. Currently I just have the lookup functionality, but listing/iterating through the actions would be good to add (would probably be necessary for a menu/toolbar editor/customisation dialog).

  It might be easier to get rid of the interface if bonobo could just
  subclass the local action group implementation -- if no action is
  found in the hash table, check for the remote action, and create a
  proxy action object to return (cache in the hash table).


	? it's not clear to me quite what you're suggesting here.

In the proof of concept code I did, I had ActionGroup as an interface, and ActionStore as an implementation using a hash table for the actions. It might be worth simplifying this and getting rid of the interface. The lookup function could be changed into a virtual function. Bonobo could derive a new ActionGroup type, that could query a remote CORBA object and construct proxy Action objects (these could be cached in the hash table, so the CORBA lookup would act as a fallback).

User Interface Definitions
--------------------------

...

See the documentation in libbonoboui for details on the structure.


	One thing that would have been fairly useful in bonobo I think is the
concept of a symbolic link - which sounds pretty crack smoking, but
could help substantially with merging - eliminating some of the
complexity arising from placeholders.

I am not quite sure what you mean by symbolic links here. Could you ellaborate? The placeholder ideas in bonobo don't seem that bad to me (once I worked out what you were on about -- maybe a different name would be more appropriate). It seems like quite a clean approach to merging entries into a particular positions in a container.

Interface definitions are parsed with a GMarkup based parser.  A tree
is built up from the elements in the UI tree.  The nodes in the tree
hold the name of the node, an (action, UI file) pair, a pointer to the
widget representing this node and a tag identifying which UI file it
came from.

When parsing subsequent UI files, the following rules are used for
merging:

1. if a particular node already exists, add another (action, UI file)
   pair to the node.
2. if it doesn't exist, create a new node, and append it to the list
   of children for the parent node.

More complex ordering of merged UI elements should be handled through
the use of <placeholder> elements (placeholders are essentially like
<submenu>, except that their children get pasted into the parent menu
directly).


	Sigh; I want to re-visit this decision and consider whether
placeholders are really that good, whether some sort of virtual link
concept might be better, and review how they are used around the place.

	Also for compound documents, we should go for a really different /
simpler approach IMHO, which is mostly a subset of the above.

The actual widgets are not constructed immediately.  Instead the new
nodes are marked "dirty", and an idle function is queued to update the
UI.  This should speed things up a bit.

To remove a UI file, we simply walk the tree and remove the (action,
UI file) pairs from all nodes that match.  If a node is not referenced
anywhere else, it is marked dirty (will get removed in the idle).  The
same if the node's controlling action would change due to the removal.


	There is a fair bit of logic to do this in bonobo - but also to reveal
things hidden by being merged over etc. again it's not clear to me what
is best to do with those concepts.

Registering and Unregistering Action Groups
-------------------------------------------

A list of action groups are used as the source for actions referenced
in the UI definitions.  When adding or removing action groups, diffent
actions may be exposed (adding a group may shadow existing actions of
the same name.  removing a group may expose different actions).
Therefore, all nodes in the tree are marked dirty when this sort of
change occurs, and the idle is scheduled.


	Curious. A relatively common thing to do is changing labels on toolbar
items. It'd be interesting to see how this worked with this scheme.

The idea would be to change the label associated with the action, and let the proxy menu items and toolbar buttons would update themselves (probably using the notify signal that gets called when a property changes).

The idle handler should be fairly high priority (it is merely to speed
up multiple changes performed in a row).  It walks the tree doing the
following:

1. is this node dirty, and do any UI defs reference it?  If so:

     a. if there is no widget constructed ask the action to create a
        proxy, and store it on the node.  This widget should also be
        added to the parent node's widget (for placeholders,
        recursively ascend the tree finding a non placeholder
        parent).

     b. if there is a widget, but it is associated with a different
        action than the correct one, destroy the widget and create a
        new one (or if possible, disconnect the proxy from the old
        action and reconnect it to the new action).

2. if there are any child nodes, recurse down to them.

3. if this node is not referenced by any UI defs, destroy its widget
   (if any exists), and remove the node.


	NB. the process of synchronizing an arbitrary container with the widget
list is really extremely and un-necessarily complicated. My feeling is
that it would be considerably better to have a custom container
associated with the nodes a 'node view' container; and that this would
simply be queue_resized' [ or whatever ] when a change happens - thus
avoiding the 'dirty concept' - and hopefully also avoiding constructing
lots of unneccessary / invisible widgets at any given time. Yes this
would probably involve re-writing GtkMenu / GtkMenuItem - and yes it's
worth doing.

Does bonobo create menu items for node positions that have been shadowed by other UI descriptions? My plan was to only create one proxy widget per node, and disconnecting/reconnecting it (if necessary) when adding/removing UI descriptions from the merged UI.


	Anyway - just some thoughts; I'd like to sit down and discuss it at
GUADEC with any interested parties - or subsequently. Preferably not
now.

Good idea. As I said earlier, it wasn't the intention to draw attention away from gnome 2.0 work -- just get some ideas out for discussion.

James.

--
Email: james daa com au
WWW:   http://www.daa.com.au/~james/






[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]