Commit e8e76925 authored by BST 1998  Tony Gale's avatar BST 1998 Tony Gale Committed by Tony Gale
Browse files

- Tidy up of the menufactory example from Andy Kahn <kahn@zk3.dec.com> -

Thu Aug 13 09:11:11 BST 1998  Tony Gale  <gale@gtk.org>

        * docs/gtk_tut.sgml:
          - Tidy up of the menufactory example from
            Andy Kahn <kahn@zk3.dec.com>
          - New section on Range Widgets from
            David Huggins-Daines <bn711@freenet.carleton.ca>
          - Started a new section on 'Advanced Event and Signal
            Handling' - used an email from Owen.
          - New appendix on Gdk Event Types
          - Added the tictactoe full example code to the
            'Code Examples' appendix
parent 7a235648
Thu Aug 13 09:11:11 BST 1998 Tony Gale <gale@gtk.org>
* docs/gtk_tut.sgml:
- Tidy up of the menufactory example from
Andy Kahn <kahn@zk3.dec.com>
- New section on Range Widgets from
David Huggins-Daines <bn711@freenet.carleton.ca>
- Started a new section on 'Advanced Event and Signal
Handling' - used an email from Owen.
- New appendix on Gdk Event Types
- Added the tictactoe full example code to the
'Code Examples' appendix
Tue Jul 21 12:42:01 1998 Owen Taylor <otaylor@redhat.com>
* gdk/gdk.h gdk/gdkfont.c: Added gdk_text/string_extents() -
......
Thu Aug 13 09:11:11 BST 1998 Tony Gale <gale@gtk.org>
* docs/gtk_tut.sgml:
- Tidy up of the menufactory example from
Andy Kahn <kahn@zk3.dec.com>
- New section on Range Widgets from
David Huggins-Daines <bn711@freenet.carleton.ca>
- Started a new section on 'Advanced Event and Signal
Handling' - used an email from Owen.
- New appendix on Gdk Event Types
- Added the tictactoe full example code to the
'Code Examples' appendix
Tue Jul 21 12:42:01 1998 Owen Taylor <otaylor@redhat.com>
* gdk/gdk.h gdk/gdkfont.c: Added gdk_text/string_extents() -
......
Thu Aug 13 09:11:11 BST 1998 Tony Gale <gale@gtk.org>
* docs/gtk_tut.sgml:
- Tidy up of the menufactory example from
Andy Kahn <kahn@zk3.dec.com>
- New section on Range Widgets from
David Huggins-Daines <bn711@freenet.carleton.ca>
- Started a new section on 'Advanced Event and Signal
Handling' - used an email from Owen.
- New appendix on Gdk Event Types
- Added the tictactoe full example code to the
'Code Examples' appendix
Tue Jul 21 12:42:01 1998 Owen Taylor <otaylor@redhat.com>
* gdk/gdk.h gdk/gdkfont.c: Added gdk_text/string_extents() -
......
Thu Aug 13 09:11:11 BST 1998 Tony Gale <gale@gtk.org>
* docs/gtk_tut.sgml:
- Tidy up of the menufactory example from
Andy Kahn <kahn@zk3.dec.com>
- New section on Range Widgets from
David Huggins-Daines <bn711@freenet.carleton.ca>
- Started a new section on 'Advanced Event and Signal
Handling' - used an email from Owen.
- New appendix on Gdk Event Types
- Added the tictactoe full example code to the
'Code Examples' appendix
Tue Jul 21 12:42:01 1998 Owen Taylor <otaylor@redhat.com>
* gdk/gdk.h gdk/gdkfont.c: Added gdk_text/string_extents() -
......
Thu Aug 13 09:11:11 BST 1998 Tony Gale <gale@gtk.org>
* docs/gtk_tut.sgml:
- Tidy up of the menufactory example from
Andy Kahn <kahn@zk3.dec.com>
- New section on Range Widgets from
David Huggins-Daines <bn711@freenet.carleton.ca>
- Started a new section on 'Advanced Event and Signal
Handling' - used an email from Owen.
- New appendix on Gdk Event Types
- Added the tictactoe full example code to the
'Code Examples' appendix
Tue Jul 21 12:42:01 1998 Owen Taylor <otaylor@redhat.com>
* gdk/gdk.h gdk/gdkfont.c: Added gdk_text/string_extents() -
......
Thu Aug 13 09:11:11 BST 1998 Tony Gale <gale@gtk.org>
* docs/gtk_tut.sgml:
- Tidy up of the menufactory example from
Andy Kahn <kahn@zk3.dec.com>
- New section on Range Widgets from
David Huggins-Daines <bn711@freenet.carleton.ca>
- Started a new section on 'Advanced Event and Signal
Handling' - used an email from Owen.
- New appendix on Gdk Event Types
- Added the tictactoe full example code to the
'Code Examples' appendix
Tue Jul 21 12:42:01 1998 Owen Taylor <otaylor@redhat.com>
* gdk/gdk.h gdk/gdkfont.c: Added gdk_text/string_extents() -
......
Thu Aug 13 09:11:11 BST 1998 Tony Gale <gale@gtk.org>
* docs/gtk_tut.sgml:
- Tidy up of the menufactory example from
Andy Kahn <kahn@zk3.dec.com>
- New section on Range Widgets from
David Huggins-Daines <bn711@freenet.carleton.ca>
- Started a new section on 'Advanced Event and Signal
Handling' - used an email from Owen.
- New appendix on Gdk Event Types
- Added the tictactoe full example code to the
'Code Examples' appendix
Tue Jul 21 12:42:01 1998 Owen Taylor <otaylor@redhat.com>
* gdk/gdk.h gdk/gdkfont.c: Added gdk_text/string_extents() -
......
......@@ -10,7 +10,7 @@
name="&lt;imain@gtk.org&gt;"></tt>,
Tony Gale <tt><htmlurl url="mailto:gale@gtk.org"
name="&lt;gale@gtk.org&gt;"></tt>
<date>July 25th, 1998
<date>August 13th, 1998
<!-- ***************************************************************** -->
<sect>Introduction
......@@ -482,14 +482,17 @@ static gint button_press_event (GtkWidget *widget,
Note that we can declare the second argument as type <tt/GdkEventButton/
as we know what type of event will occur for this function to be called.
<!-- Need an Annex with all the event types in it - TRG -->
<!-- Need to check this - TRG
The value returned from this function indicates whether the event should
be processed further by the GTK event handling mechanism. Returning
be propagated further by the GTK event handling mechanism. Returning
TRUE indicates that the event has been handled, and that it should not
propogate further. Returning FALSE continues the normal event handling.
-->
propagate further. Returning FALSE continues the normal event handling.
See the section on
<ref id="sec_Adv_Events_and_Signals"
name="Advanced Event and Signal Handling"> for more details on this
propagation process.
For details on the GdkEvent data types, see the appendix entitled
<ref id="sec_GDK_Event_Types" name="GDK Event Types">.
<!-- ----------------------------------------------------------------- -->
<sect1>Stepping Through Hello World
......@@ -2085,6 +2088,775 @@ removes the need for a variable to hold the list of buttons:
<!-- TODO: checout out gtk_radio_button_new_from_widget function - TRG -->
<!-- ***************************************************************** -->
<sect>Range Widgets
<!-- ***************************************************************** -->
<p>
The category of range widgets includes the ubiquitous <em>scrollbar</em>
widget and the less common <em>scale</em> widget. Though these two
types of widgets are typically used for vastly different
purposes, they are quite similar in function and implementation.
Range widgets allow the user to visually manipulate a value
within a specified range (hence the name).
All range widgets share a set of common graphic elements, each
of which has its own X window and receives events. They all
contain a "trough" and a "slider" (what is sometimes called a
"thumbwheel" in other GUI environments). Dragging the slider
with the pointer moves it back and forth within the trough,
while clicking in the trough advances the slider towards the
location of the click, either completely, or by a designated
amount (called a "page"), depending on which button was used.
<!-- ----------------------------------------------------------------- -->
<sect1>The Scale Widgets
<p>
Scale widgets are used to set an explicitly numeric parameter
which has a visual correlate, and which the user might be
expected to adjust primarily by sight. For example, the
GtkColorSelection compound widget contains scale widgets which
control the components of the colour being selected.
Typically, the precise value of the number is less important
here than its side-effects, and thus the user should be spared
the effort of reaching for the keyboard.
<!-- ----------------------------------------------------------------- -->
<sect2>Creating a Scale Widget
<p>
There are actually two types of scale widget: GtkHScale
widgets, which are horizontal, and GtkVScale widgets, which
are vertical. (Most programmers seem to favour horizontal
scale widgets). Since they work essentially the same way,
there's no need to treat them separately here. The
following functions, defined in
<tt>&lt;gtk/gtkvscale.h&gt;</tt> and
<tt>&lt;gtk/gtkhscale.h&gt;</tt>, create vertical and
horizontal scale widgets, respectively:
<tscreen><verb>
GtkWidget* gtk_vscale_new( GtkAdjustment *adjustment );
GtkWidget* gtk_hscale_new( GtkAdjustment *adjustment );
</verb></tscreen>
<tt/adjustment/ can either be an adjustment which has
already been created with <tt/gtk_adjustment_new()/, or
<tt/NULL/, in which case, an anonymous GtkAdjustment is
created with all of its values set to <tt/0.0/. If you're
thoroughly confused by now, see <ref
id="sec_Range_GtkAdjustment" name="The Adjustment Object">
below for an explanation of what exactly the <tt/adjustment/
argument does and how to create and manipulate it.
<!-- ----------------------------------------------------------------- -->
<sect2>Functions, Signals, and Macros
<p>
Scale widgets can display their current value as a number
beside the trough. The default behaviour is to show the
value, but you can change this with this function:
<tscreen><verb>
void gtk_scale_set_draw_value( GtkScale *scale,
gint draw_value );
</verb></tscreen>
As you might have guessed, <tt/draw_value/ is either
<tt/TRUE/ or <tt/FALSE/, with predictable consequences for
either one.
The value displayed by a scale widget is rounded to one
decimal point by default (as is the <tt/value/ field in its
GtkAdjustment... but I digress). You can change this with:
<tscreen><verb>
void gtk_scale_set_digits( GtkScale *scale,
gint digits);
</verb></tscreen>
where <tt/digits/ is the number of decimal places you want.
You can set <tt/digits/ to anything you like, but no more
than 13 decimal places will actually be drawn on screen.
This probably isn't too horribly restrictive.
Finally, the value can be drawn in different positions
relative to the trough:
<tscreen><verb>
void gtk_scale_set_value_pos( GtkScale *scale,
GtkPositionType pos );
</verb></tscreen>
If you've read the section on the notebook widget, then you
know what the possible values of <tt/pos/ are. They are
defined as type <tt>GtkPositionType</tt> and can take one
of the following values:
<itemize>
<item>GTK_POS_LEFT
<item>GTK_POS_RIGHT
<item>GTK_POS_TOP
<item>GTK_POS_BOTTOM
</itemize>
If you position the value on the "side"
of the trough (e.g. on the top or bottom of a horizontal
scale widget), then it will follow the slider up and down
the trough.
All the preceding functions are defined in
<tt>&lt;gtk/gtkscale.h&gt;</tt>. The other signals and
functions defined in the header files for the scale widgets
are either not useful for anyone other than writers of scale
widgets, or are the standard GTK+ type-casting macros and
functions.
<!-- ----------------------------------------------------------------- -->
<sect1>The Scrollbar Widgets
<p>
These are your standard, run-of-the-mill scrollbars. As with
the scale widgets, there are separate types for horizontal and
vertical scrollbars. There really isn't much to say about
these. You create them with the following functions:
<tscreen><verb>
GtkWidget* gtk_hscrollbar_new( GtkAdjustment *adjustment );
GtkWidget* gtk_vscrollbar_new( GtkAdjustment *adjustment );
</verb></tscreen>
and that's about it (if you don't believe me, look in the
header files!). Again, <tt/adjustment/ can either be a
pointer to an existing GtkAdjustment, or NULL, in which case
one will be created for you.
<!-- ----------------------------------------------------------------- -->
<sect1>The Adjustment Object<label id="sec_Range_GtkAdjustment">
<p>
As you might have noticed, there really isn't much to the
various range widgets themselves from the programmer's point
of view. Most of your program's interaction with these
widgets will take place by way of the heretofore mysterious
<tt/adjustment/ object.
Every range widget contains a pointer to a GtkAdjustment
object. You'll usually create one of these in order to pass
it to the <tt/gtk_*_new()/ function which creates a range
widget, or some compound widget that uses range widgets, such
as GtkScrolledWindow or GtkCList.
Aside from specifying some characteristics related to the
range widget's appearance and behaviour, the GtkAdjustment you
pass to this function becomes "attached" to the newly-created
range widget and from that point on will always contain the
numerical value corresponding to the position of the slider
(unless, at some point in the future, you set a new adjustment
for the range widget).
One adjustment object can be shared between many range
widgets. Reusing the same adjustment object across several
range widgets will cause them all to change when one of them
is changed.
<!-- ----------------------------------------------------------------- -->
<sect2>Creating a GtkAdjustment
<p>
You create an adjustment using:
<tscreen><verb>
GtkObject* gtk_adjustment_new( gfloat value,
gfloat lower,
gfloat upper,
gfloat step_increment,
gfloat page_increment,
gfloat page_size );
</verb></tscreen>
It may or may not be obvious by now that the values given to
<tt/gtk_adjustment_new()/ are simply arbitrary floating-point
values. The mapping between these values and the on-screen
size of the range widget and its constituent parts is
handled by the range widget. Thus, you're free to use
whatever numbers are most meaningful to your program.
The <tt/value/ argument is the initial value you want to
give to the adjustment. The <tt/lower/ argument specifies
the lowest value which the adjustment can hold, or, in other
words, the lowest value which the user can select using the
range widget which uses this adjustment. The
<tt/step_increment/ argument specifies the "smaller" of the
two increments by which the user can change the value, while
the <tt/page_increment/ is the "larger" one. <ref
id="sec_Range_Bindings" name="Key and Mouse Bindings"> below
describes the default key and mouse bindings for range
widgets, and how they relate to these increments. The
<tt/page_size/ argument is only relevant for scrollbars.
Its most obvious effect is that it determines the size of
the slider; however, you should set it based on the "size"
of the visible area of whatever you're scrolling.
As an example, say you're writing a text editor. You might
want to have the value of the vertical scrollbar beside the
editing area correspond to the line number
of the first visible line in the editing area. In that
case, you might call <tt/gtk_adjustment_new()/ like this:
<tscreen><verb>
GtkObject *adj;
adj = gtk_adjustment_new (0, first_line, last_line, 1,
window_height - 2, window_height);
</verb></tscreen>
where <tt/window_height/ is the number of visible lines in
the window.
Finally, with regard to the <tt/upper/ argument to
<tt/gtk_adjustment_new/, you'll notice that, since the value
of the adjustment corresponds to the <em/first/ visible line
in the window, the maximum value in the adjustment is not
actually <tt/last_line/, but rather <tt>last_line -
window_height</tt> (or, in more general terms, <tt>upper -
page_height</tt>). This is a little confusing at first, but
it makes sense if you think about it in terms of what the
user expects to see in a scrolled window when the
scrollbar's slider is moved all the way to the end of the
trough.
Since the size of the slider on scale widgets is invariable,
to avoid excessive confusion, it's a good idea to set the
<tt/page_size/ to <tt/0.0/ for adjustments that are only
going to be used for scale widgets.
<!-- ----------------------------------------------------------------- -->
<sect2>Inside the GtkAdjustment object
<p>
OK, you say, that's nice, but how do I get at all these
values, and, more importantly, how do I know when the user
has moved the slider around? To answer these questions and
more, let's start by taking a look at <tt/struct _GtkAdjustment/ itself:
<tscreen><verb>
struct _GtkAdjustment
{
GtkData data;
gfloat lower;
gfloat upper;
gfloat value;
gfloat step_increment;
gfloat page_increment;
gfloat page_size;
};
struct _GtkAdjustmentClass
{
GtkDataClass parent_class;
void (* changed) (GtkAdjustment *adjustment);
void (* value_changed) (GtkAdjustment *adjustment);
};
</verb></tscreen>
The first thing you should know is that there aren't any
handy-dandy macros or accessor functions for getting the
<tt/value/ out of a GtkAdjustment, so you'll have to (horror
of horrors) do it like a <em/real/ C programmer. Don't
worry - the <tt>GTK_ADJUSTMENT (Object)</tt> macro does
run-time type checking (as do all the GTK+ type-casting
macros, actually). On the other hand, unless you're writing
a new type of range widget, you probably don't want to
<em/set/ these fields directly. To set <tt/value/, you can
use:
<tscreen><verb>
void gtk_adjustment_set_value( GtkAdjustment *adjustment,
gfloat value );
</verb></tscreen>
If you need to change the other fields, and you don't intend
to do this very frequently, it's best to create a new
GtkAdjustment and set it with
<tt/gtk_range_set_adjustment()/, as detailed in <ref
id="sec_Range_Functions" name="Common Functions, Signals,
and Macros"> below.
You might have noticed that, while adjustments are not
widgets, they are still a "subclass" of GtkObject.
Therefore, they can (and do) emit signals of their own.
The various widgets that use the GtkAdjustment object will
emit the "value_changed" signal on an adjustment whenever
they change its value (see <ref id="sec_Range_UpdatePolicy"
name="Update Policies"> below for more detail). This
happens both when user input causes the slider to move on a
range widget, as well as when the program explicitly changes
the value with <tt/gtk_adjustment_set_value()/. So, for
example, if you have a scale widget, and you want to change
the rotation of a picture whenever its value changes, you
would create a callback like this:
<tscreen><verb>
void cb_rotate_picture (GtkAdjustment *adj, GtkWidget *picture)
{
set_picture_rotation (picture, adj->value);
...
</verb></tscreen>
and connect it to the scale widget's adjustment like this:
<tscreen><verb>
gtk_signal_connect (GTK_OBJECT (adj), "value_changed",
GTK_SIGNAL_FUNC (cb_rotate_picture), picture);
</verb></tscreen>
The "changed" signal is somewhat more elusive. It is never
emitted directly due to the <em/user's/ actions. Rather,
programs or other widgets should emit it on a GtkAdjustment
when they modify any of its fields directly. This will
force any range widgets that use this adjustment to
recalculate and redraw if necessary. This is useful if you
have a number of range widgets using the same GtkAdjustment,
and don't want to call <tt/gtk_range_set_adjustment()/ for
all of them. It's also handy if you are going to be
continuously changing these values, such as in our
hypothetical text editor, where the <tt/upper/ field will
have to change every time a new line is added, and you don't
want the extra overhead of creating a new GtkAdjustment
object every time.
<!-- ----------------------------------------------------------------- -->
<sect1>Common Functions, Signals, and Macros<label id="sec_Range_Functions">
<p>
The GtkRange widget class is fairly complicated internally,
but, like all the "base class" widgets, most of its complexity
is only interesting if you want to hack on it. Also, almost
all of the functions and signals it defines are only really
used in writing derived widgets. There are, however, a few
useful functions and concepts that are defined in gtkrange.h
and are common to all range widgets.
<!-- ----------------------------------------------------------------- -->
<sect2>Update Policies<label id="sec_Range_UpdatePolicy">
<p>
The "update policy" of a range widget defines at what points
during user interaction it will change the <tt/value/ field
of its GtkAdjustment and emit the "value_changed" signal on
this GtkAdjustment. The update policies, defined in
<tt>&lt;gtk/gtkenums.h&gt;</tt> as the <tt>enum
GtkUpdateType</tt>, are:
<itemize>
<item>GTK_UPDATE_POLICY_CONTINUOUS - This is the default.
The "value_changed" signal is emitted continuously,
i.e. whenever the slider is moved by even the tiniest
amount.
</item>
<item>GTK_UPDATE_POLICY_DISCONTINUOUS - The
"value_changed" signal is only emitted once the slider
has stopped moving and the user has released the mouse
button.
</item>
<item>GTK_UPDATE_POLICY_DELAYED - The "value_change"
signal is emitted when the user releases the mouse button,
or if the slider stops moving for a short period of
time.
</item>
</itemize>
The update policy of a range widget can be set by casting it
using the <tt>GTK_RANGE (Widget)</tt> macro and passing it
to this function:
<tscreen><verb>
void gtk_range_set_update_policy( GtkRange *range,
GtkUpdateType policy );
</verb></tscreen>
<!-- ----------------------------------------------------------------- -->
<sect2>Getting and setting adjustments
<p>
Getting and setting the adjustment for a range widget "on
the fly" is done, predictably, with:
<tscreen><verb>
GtkAdjustment* gtk_range_get_adjustment( GtkRange *range );
void gtk_range_set_adjustment( GtkRange *range,
GtkAdjustment *adjustment );
</verb>
</tscreen>
<tt/gtk_range_get_adjustment()/ returns a pointer to the
adjustment to which <tt/range/ is connected.
<tt/gtk_range_set_adjustment()/ does absolutely nothing if
you pass it the adjustment that <tt/range/ is already using,
regardless of whether you changed any of its fields or not.
If you pass it a new GtkAdjustment, it will unreference the
old one if it exists (possibly destroying it), connect the
appropriate signals to the new one, and call the private
function <tt/gtk_range_adjustment_changed()/, which will (or
at least, is supposed to...) recalculate the size and/or
position of the slider and redraw if necessary. As
mentioned above, if you wish to reuse the same
GtkAdjustment, when you modify its values directly, you
should emit the "changed" signal on it, like this:
<tscreen><verb>
gtk_signal_emit_by_name (GTK_OBJECT (adjustment), "changed");
</verb></tscreen>
<!-- ----------------------------------------------------------------- -->
<sect1>Key and Mouse bindings<label id="sec_Range_Bindings">
<p>
All of the GTK+ range widgets react to mouse clicks in more
or less the same way. Clicking button 1 in the trough will
cause its adjustment's <tt/page_increment/ to be added or
subtracted from its <tt/value/, and the slider to be moved
accordingly. Clicking button 2 in the trough will jump the
slider to the point at which the button was clicked.
Clicking any button on a scrollbar's arrows will cause its
adjustment's value to change <tt/step_increment/ at a time.
The key bindings, by contrast, are slightly different
between horizontal and vertical range widgets, for obvious
reasons. They are also not quite the same for scale widgets
as they are for scrollbars, for somewhat less obvious
reasons (possibly to avoid confusion between the keys for
horizontal and vertical scrollbars in scrolled windows,
where both operate on the same area).
<!-- ----------------------------------------------------------------- -->
<sect2>Vertical Range Widgets
<p>
All vertical range widgets can be operated with the up and
down arrow keys, as well as with the <tt/Page Up/ and
<tt/Page Down/ keys. The arrows move the slider up and
down by <tt/step_increment/, while <tt/Page Up/ and
<tt/Page Down/ move it by <tt/page_increment/.
The user can also move the slider all the way to one end
or the other of the trough using the keyboard. With the
GtkVScale widget, this is done with the <tt/Home/ and
<tt/End/ keys, whereas with the GtkVScrollbar widget, this
is done by typing <tt>Control-Page Up</tt> and
<tt>Control-Page Down</tt>.
<!-- ----------------------------------------------------------------- -->
<sect2>Horizontal Range Widgets
<p>
The left and right arrow keys work as you might expect in
these widgets, moving the slider back and forth by
<tt/step_increment/. The <tt/Home/ and <tt/End/ keys move
the slider to the ends of the trough. For the GtkHScale
widget, moving the slider by <tt/page_increment/ is
accomplished with <tt>Control-Left</tt> and
<tt>Control-Right</tt>, while for GtkHScrollbar, it's done
with <tt>Control-Home</tt> and <tt>Control-End</tt>.
<!-- ----------------------------------------------------------------- -->
<sect1>Example<label id="sec_Range_Example"></heading>
<p>
This example is a somewhat modified version of the "range
widgets" test from <tt/testgtk.c/. It basically puts up a
window with three range widgets all connected to the same
adjustment, and a couple of controls for adjusting some of the
parameters for scale widgets mentioned above, so you can see
how they affect the way these widgets work for the user.
<tscreen><verb>
/* example-start rangewidgets rangewidgets.c */
#include <gtk/gtk.h>
GtkWidget *hscale, *vscale;
void cb_pos_menu_select (GtkWidget *item, GtkPositionType pos)