Slicer3:Interface Design and Usability:Open Questions

From Slicer Wiki
Revision as of 18:02, 15 May 2008 by Marianna (talk | contribs) (1 revision)
(diff) ← Older revision | Latest revision (diff) | Newer revision → (diff)
Jump to: navigation, search
Home < Slicer3:Interface Design and Usability:Open Questions

Contents

It appears that entering a vtkKWMultiColumnListBox sometimes causes the window to raise.

This is true: when the cursor enters the multicolumn list, the focus is re-claimed by the list automatically so that local keybindings can work (say, for example, navigation using the arrow keys). Can you show me what side-effects you are getting ?

The problem is on windows: a focus also causes a raise, meaning that if the window his lower in the stacking order and you move your mouse over the vtkKWMultiColumnListBox then the whole toplevel that it is in raises to the top of the window stacking order.

How to make global hot keys

For the moment, you can add the keybinding to the toplevel window. For example, say you need a Control-Z binding for your Undo framework; if win is your vtkKWWindow (or any subclass of vtkKWTopLevel):

 win->SetBinding("<Control-Key-z>", object, "MyUndoCallback");

Here is another (probably a little shorter) way. You will probably need an undo entry in the Edit menu. You can do it this way:

 int index = win->GetEditMenu()->AddCommand("&Undo", object, "MyUndoCallback");

...which adds an "Undo" entry to the edit menu (the letter 'U' is underlined here). Now you can add your key accelerator this way:

 win->GetEditMenu()->SetItemAccelerator(index, "Ctrl+Z");

...the "Ctrl+Z" label will show up on the right of the entry in the Edit menu; furthermore, it will interpreted automatically as "<Control-Key-z>" and the corresponding binding will be set on the toplevel this menu is a child of (i.e., the win->SetBinding(...) line is done for you).

It is true that we may need a separate class to hold a set of global keybindings, and save/restore those sets. Say, if a module is active it could bring its own global keybindings, but should remove them when another module is in control, etc. That should not be too difficult too do.

How best to control the global look/style (colors, fonts, pads).

vtkKWTheme and vtkKWOptionDataBase were coded during the meeting, and seems to make Wendy happy :) They will be in the CVS very soon.

Most efficient way to generate new CompositeWidgets

Can you elaborate ?

Any way to speed up application start time? Can we avoid loading all of vtk into the interpreter by breaking it up into smaller packages and only loading what we actually need.

I assume we are talking about a pure Tcl application here. I had not noticed any problem so far, since the first time you load the DLL, they get cached and any new restart usually happens quite fast. This is interesting though; at the moment, the vtkKWApplication::InitializeTcl(Tcl_Interp *interp, ostream *err) method is the one that loads all VTK commands in, so that users don't have too.

A workaround right now would be to create your own subclass of vtkKWApplication (which is probably the case already), and re-implement this method by copying its old contents and removing the calls that initialize the VTK packages you know you will not need(say, Vtkparalleltcl_Init(interp). Worth adding to the bug tracker as a feature request.

In a vtkKWWindow, in the MainPanelFrame, we want to create a set of panels that get selectively raised/lowered by choosing from a pull-down menu. Since there will be many panels, we don't want to display notebook tabs for each panel. Right now we're creating a vtkKWUserInterfacePanel and adding pages to it, and managing it with the MainUserInterfaceManager. This uses a notebook under the hood, thus gives us tabs which we can't seem to suppress. Is there either a way to make tabs invisible, or to use something other than a notebook in the MainPanelFrame?

Let's have a look at that this week. Yes, the user interface manager actually can do some tricks like that. At the vtkKWNoteBook level, you can already "group" tabs by specifying a "tag". Then you can selectively show/hide some tags (i.e. group of tabs). The vtkKWUserInterfaceManager actually works on top of that: each time you create a vtkKWUserInterfacePanel and associate it to a vtkKWUserInterfaceManagerNotebook, the panel gets its own "tag": by raising/lowering the panel, you automatically show/hide *all* the pages this panel belongs too. Yes, a panel can have multiple page using the AddPage() method. So for example:

  • vtkKWUserInterfacePanel foo: has several pages, say "Segment" and "Register"
  • vtkKWUserInterfacePanel bar: has several pages, say "Measure" and "Filter"

Note that the page is actually a logical "concept", it's just a placeholder to put some UI in. What is interesting here is that how the pages get packed depends on the user interface manager you use, so that you can create very different UI while keeping the panels the same:

  • If you use a vtkKWUserInterfaceManagerNotebook to manage all the panels, each page is mapped to a tab in a notebook. By calling Raise() on a panel, pages come and go automatically.
  • If you use a vtkKWUserInterfaceManagerDialog, you end up with something totally different, which is demonstrated by selecting the "Application Settings" entry in the "View" menu. The left part of the dialog list the "pages", the right part is the page itself.

By creating new kind of managers, you can actually shuffle around you panels the way you want, without having to rewrite them. Each panel is just a logical "feature", that has the ability to be put into different section called "pages". How they end up on the screen, as notebook pages or a dialog, is not the panel business anymore, but the manager.

Is there a widget to implement the collapse of the MainPanelFrame?

That's a small button on top to collapse the panels like F5. OK, to be added as a feature request: added.

Strange happenings: in one vtkKWFrameWithLabel, the LabelText is displayed in bold, even if its DefaultLabelFontWeight is set to normal. Other LabelTexts on other vtkKWFrameWithLabels are displayed normally.

Please show how to reproduce. Thanks. => Fixed.

We'd like to have more control of the default size, minimium size of the various frames within the vtkKWWindow, and of frames we create and pack inside its frames (like those that contain the vtkSlicerSliceWidgets). Is it possible to set the initial size of these frames, and to set their minimum (uncollapsed) height and width?

Yes. You can use, on your window:

 vtkKWTopLevel::SetSize
 vtkKWTopLevel::SetMinimumSize

also, in vtkKWWindow you can retrieve the "split frame", i.e. the container that actually splits the window into several areas/panels. There is one vertical, and one horizontal, usually at the bottom. The size and/or minimum size of the parts on each side of the "splitter" can be configured:

 vtkKWSplitFrame::SetFrame1MinimumSize
 vtkKWSplitFrame::SetFrame2MinimumSize

etc.

How to fix the resizing behavior of the SecondaryPanelFrame and widgets packed inside it?

See above ?

Design question: where is the best place to put the mediator functions for new vtkKWCompositeWidgets? According to the current design, a class derived from vtkSlicerComponentGUI (which is derived from a vtkKWObject) contains widgets, pointers to logic and mrml, and mediator functions. This means that currently, specialty composite widgets like vtkSlicerSliceWidget contains only widgets and methods to create them, but no mediator functionality that might be associated with them. One option is to break the mediator functions into a separate class so that composite widgets and associated mediator functions can be more easily reused...

I will need some drawings on this one.

Hotkey to bring up tcl interactor?

Wish granted. I added:

 this->GetWindowMenu()->SetItemAccelerator(idx, "Ctrl+T");

You could actually set any accelerator you want, for example:

 idx = win->GetWindowMenu()->GetIndexOfItem(win->GetTclInteractorMenuLabel());
 win->GetWindowMenu()->SetItemAccelerator(idx, "Ctrl+I");

option so tcl interactor can be raised/iconified independent of the window?

By default, the window creates the tcl interactor for you as a "dependent" toplevel for convenience reasons. But it only does so when the window gets created. You can therefore definitely solve your problem by creating the Tcl interactor yourself *right* before the window is created:

 vtkKWWindow *win = vtkKWWindow::New();
 win->GetTclInteractor()->SetApplication(app);
 win->GetTclInteractor()->Create();
 win->Create();

Great! This is now in vtkSlicerApplicationGUI and it works

kwwidget to override the default vtkOutputWindow (capture state in a more friendly way)

Yes, something we have considered for a while, and really needs to be done. Please add to the bug tracker as a feature request: added.

some core widgets don't invoke the events we need to implement undo functionality.

No problem, just send me email or invoke the bug tracker. It's usually pretty easy to do.

advice on how to clean up properly? I'm getting warnings about so many instances of classes still around on exit...

My advice is to usually fix them immediately. It's sadly one of the trickiest thing to debug in VTK. Some objects are "ref-counted", i.e. they depend on each other. Only when the ref-count of an object reaches 0 is it deleted (i.e., when no other object claims it needs it). One course of action is to override the Register and UnRegister method in your class, and put breakpoints in them.

on exit: warnings saying that a TkRenderWidget is being destroyed before its associated vtkRenderWindow is deleted...

The message comes from VTK. That's exactly the problem above: refcounts. You need to delete the objects in the proper order. This warning is here to insist that there is *really* something wrong here and that you could actually risk a more severe crash. Since this is a common problem, the vtkKWRenderWidget class, which is the only classes that uses VTK's TkRenderWidget, already re-implements Register/UnRegister so that you can put breakpoints right there, and check how is claiming ownership of that object (and most likely, did not un-claim that ownership).