Re: a Wizard/Druid/Assistant widget for gtk



Matthias Clasen <maclas gmx de> writes:

> Over the last few days, I have started to work on a wizard widget for
> GTK+, GtkAssistant. I looked at GnomeDruid, EggDruid and GtkNotebook for
> prior art and at the Java LAF
> (http://java.sun.com/products/jlf/at/book/index.html) for requirements.

Rock!  This and GnomeApp are two of the major things keeping libgnomeui
around.  Getting this into GTK+ would be really nice.

> The main difference to GnomeDruid is that I avoided GnomeDruidPage and
> its subclasses. Instead, pages are arbitrary widgets, and their page
> type (introduction page, content page, confirmation page, summary page
> in the terminology of the Java LAF) is determined by a child property.

This probably is the right thing to do.  People had a lot of trouble
with that aspect of GnomeDruid system.  I don't think the flexibility
you get by doing that is worth the confusion.  It does mean that
converting branching code that used GnomeDruid will be more complicated
than s/GnomeDruid/GtkAssistant/.

That being said, having a function like:

void prepare (GtkAssistant *assistant, GtkWidget *page, MyData *data)
{
  if (page == data->page_one)
    prepare_page_one (page, data)
  else if (page == data->page_two)
    prepare_page_two (page, data)
  else if (page == data->page_three)
    prepare_page_three (page, data)
...
}

seems ugly.  I personally liked having the signals on the pages
themselves as libglade saved me from this type of nastiness.

> As a consequence, the ::back, ::next and other signals from
> GnomeDruidPage are now signals on the assistant itself.

Just to confirm, are we happy with "next" and "back" as terminology?  To
me, forward/back and next/previous are logical language pairings.  It
would be good to get confirmation from the UI team before writing this
in an API.

> The assistant decides which buttons to display, based on the page type:
> 
> introduction page/initial content page: cancel, next
> content page: cancel, back, next
> confirmation page/final content page: cancel, back, finish
> summary page: close

This seems a little inflexible.  I've seen pages which change types
based upon a toggle button.  As an example, take a wizard in which you
have a list of items to select from.  There's a '[ ] Select custom
properties' button at the bottom that toggles between 'Next' and
'Finish'.  This way you can either create a simple object, or set up all
the I can mock something up if this was unclear.  Also, some
dialogs like adding their own buttons.  'Help' is an obvious one, but
sometimes applications add other buttons.  I vaguely recall bug-buddy
had a 'Get Backtrace' button or something.

> Simple linear wizards can be constructed by simply adding the required
> pages with the default page type. More complicated nonlinear wizards can
> be done in much the same way as with GnomeDruid, by setting the page
> type appropriately on nonfinal pages which should act as confirmation
> pages, and connecting to the ::next, ::back and ::finish signals. The
> page types should allow to implement the LAF guidelines for wizards
> faithfully. 
> 
> I'm not completely satisfied with the API yet (e.g. the decoration stuff
> taken from EggDruid could be done as properties or child properties),
> but I'd like to post it here for some feedback before tweaking it
> further. The existing documentation is appended below. I'll attach an
> inmplementation and examples to
> http://bugzilla.gnome.org/show_bug.cgi?id=115348 when they're ready.

Other thoughts:

 * Does the GtkAssistant take care of drawing the decorations?  Are we
   going to have problems when people want to make their own assistants?
   Would it make sense to have GtkAssistant/GtkAssistantPage that
   handled drawing all the decorations.  It would let us hedge against
   changes in best-practices/fashion here.

 * One thing that confused people about GnomeDruid was that it didn't
   inherit from GnomeDialog ("you mean I have to put it in its own
   window?").  While the rationale for that was so that it could be
   embedded more easily in another app, in practice no one else has ever
   done that.  I don't know if having the "reponse" style API is good
   here, but it does provide us with a well-known way to add extra
   buttons, handle secondary buttons, etc.

 * Do we have a proposed look for the Assistant?  I think we need that
   before we write the look API.  There's a danger here of ending up
   with the current problem with GtkMessageDialog API with no way to do
   Primary/Secondary text nicely.  Additionally, I am pretty sure that
   people found the GnomeDruidPageStandard API limiting, though I can't
   remember the specifics.  Perhaps they just found it ugly, as they
   kept modifying the canvas directly. (-;

 * How will control-flow work?  How would you handle hitting next and
   preventing it from automagically going to the next page?  Would you
   have to call set_page() to the current page?  Will that retrigger
   "prepare"?  Do you stop the signal emission.  For example, consider
   an app with a slow operation.  You might want to popup a dialog
   "Searching for new hardware [ Cancel ]" and not actually switch pages
   until that task is finished.  When they hit next, you basically want
   the Assistant to do nothing.

[Some comments on the API ]

> void gtk_assistant_set_buttons_sensitive (GtkAssistant  *assistant,
>                                           gboolean       back_sensitive,
>                                           gboolean      
> forward_sensitive, 
>                                           gboolean      
> cancel_sensitive);

What about finish?  Is that a different button?

> /* managing pages */
> void gtk_assistant_insert_page (GtkAssistant  *assistant,
>                                 GtkWidget     *sibling,
>                                 GtkWidget     *page);

Is sibling before or after page when this is done?  I did insert_column
with an integer in gtktreeview.h.  How about
gtk_assistant_insert_page_{before,after} that take a sibling while
insert takes an int?

> void gtk_assistant_append_page (GtkAssistant  *assistant,
>                                 GtkWidget     *page);
> void gtk_assistant_prepend_page (GtkAssistant  *assistant,
>                                  GtkWidget     *page);
> gint gtk_assistant_get_n_pages (GtkAssistant  *assistant);
> GtkWidget *gtk_assistant_get_nth_page (GtkAssistant  *assistant,
>                                        gint           page_num);

insert/append/prepend should return the offset into the page it is.
Well, I guess prepend is always 0, but perhaps the other two should.

> /* current page */
> void gtk_assistant_set_current_page (GtkAssistant  *assistant,
>                                      GtkWidget     *page);
> 
> GtkWidget *gtk_assistant_get_current_page (GtkAssistant  *assistant);
> 
> void gtk_assistant_set_current_page_num (GtkAssistant  *assistant,
>                                          gint           page_num);
> gint gtk_assistant_get_current_page_num (GtkAssistant  *assistant);

> /* child properties */
> void gtk_assistant_set_page_type (GtkAssistant        *assistant,
>                                   GtkWidget           *page,
>                                   GtkAssistantPageType type);
> GtkAssistantPageType gtk_assistant_get_page_type (GtkAssistant 
> *assistant,
>                                                   GtkWidget     *page);
> void gtk_assistant_set_page_title (GtkAssistant  *assistant,
>                                    GtkWidget     *page,
>                                    const gchar   *title);
> gchar *gtk_assistant_get_page_title (GtkAssistant  *assistant,
>                                      GtkWidget     *page);

Is this persistent for a given page?  Is there a way to go back to the
default title?  Is there a default title?


Thanks,
-Jonathan



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