From e735ac6c86bd97fb62dd157ab3a4ec9661427547 Mon Sep 17 00:00:00 2001 From: GMT 1999 Tony Gale Date: Fri, 29 Jan 1999 09:29:02 +0000 Subject: - New sections on the Fixed and Frame containers - Rearrange the Fri Jan 29 09:18:41 GMT 1999 Tony Gale * docs/gtk_tut.sgml: - New sections on the Fixed and Frame containers - Rearrange the Containers section so the easier ones are first - Move the List widget section to an appendix --- docs/tutorial/gtk_tut.sgml | 5382 +++++++++++++++++++++++--------------------- 1 file changed, 2800 insertions(+), 2582 deletions(-) (limited to 'docs/tutorial') diff --git a/docs/tutorial/gtk_tut.sgml b/docs/tutorial/gtk_tut.sgml index c85e11796d..30c962a6c4 100644 --- a/docs/tutorial/gtk_tut.sgml +++ b/docs/tutorial/gtk_tut.sgml @@ -11,7 +11,7 @@ Tony Gale Ian Main , -January 27th, 1999 +January 28th, 1999 Introduction @@ -4782,471 +4782,409 @@ int main (int argc, char *argv[]) Container Widgets - - Notebooks -

-The NoteBook Widget is a collection of 'pages' that overlap each -other, each page contains different information. This widget has -become more common lately in GUI programming, and it is a good way to -show blocks of similar information that warrant separation in their -display. + +The EventBox

+Some GTK widgets don't have associated X windows, so they just draw on +their parents. Because of this, they cannot receive events and if they +are incorrectly sized, they don't clip so you can get messy +overwriting etc. If you require more from these widgets, the EventBox +is for you. -The first function call you will need to know, as you can probably -guess by now, is used to create a new notebook widget. +At first glance, the EventBox widget might appear to be totally +useless. It draws nothing on the screen and responds to no +events. However, it does serve a function - it provides an X window +for its child widget. This is important as many GTK widgets do not +have an associated X window. Not having an X window saves memory and +improves performance, but also has some drawbacks. A widget without an +X window cannot receive events, and does not perform any clipping on +its contents. Although the name -GtkWidget *gtk_notebook_new( void ); +GtkWidget *gtk_event_box_new( void ); -Once the notebook has been created, there are a number of functions -that operate on the notebook widget. Let's look at them individually. - -The first one we will look at is how to position the page indicators. -These page indicators or 'tabs' as they are referred to, can be -positioned in four ways: top, bottom, left, or right. +A child widget can then be added to this EventBox: -void gtk_notebook_set_tab_pos( GtkNotebook *notebook, - GtkPositionType pos ); +gtk_container_add( GTK_CONTAINER(event_box), widget ); -GtkPostionType will be one of the following, and they are pretty self explanatory: - - GTK_POS_LEFT - GTK_POS_RIGHT - GTK_POS_TOP - GTK_POS_BOTTOM - - -GTK_POS_TOP is the default. - -Next we will look at how to add pages to the notebook. There are three -ways to add pages to the NoteBook. Let's look at the first two -together as they are quite similar. +The following example demonstrates both uses of an EventBox - a label +is created that is clipped to a small box, and set up so that a +mouse-click on the label causes the program to exit. Resizing the +window reveals varying amounts of the label. -void gtk_notebook_append_page( GtkNotebook *notebook, - GtkWidget *child, - GtkWidget *tab_label ); +/* example-start eventbox eventbox.c */ -void gtk_notebook_prepend_page( GtkNotebook *notebook, - GtkWidget *child, - GtkWidget *tab_label ); +#include + +int +main (int argc, char *argv[]) +{ + GtkWidget *window; + GtkWidget *event_box; + GtkWidget *label; + + gtk_init (&argc, &argv); + + window = gtk_window_new (GTK_WINDOW_TOPLEVEL); + + gtk_window_set_title (GTK_WINDOW (window), "Event Box"); + + gtk_signal_connect (GTK_OBJECT (window), "destroy", + GTK_SIGNAL_FUNC (gtk_exit), NULL); + + gtk_container_set_border_width (GTK_CONTAINER (window), 10); + + /* Create an EventBox and add it to our toplevel window */ + + event_box = gtk_event_box_new (); + gtk_container_add (GTK_CONTAINER(window), event_box); + gtk_widget_show (event_box); + + /* Create a long label */ + + label = gtk_label_new ("Click here to quit, quit, quit, quit, quit"); + gtk_container_add (GTK_CONTAINER (event_box), label); + gtk_widget_show (label); + + /* Clip it short. */ + gtk_widget_set_usize (label, 110, 20); + + /* And bind an action to it */ + gtk_widget_set_events (event_box, GDK_BUTTON_PRESS_MASK); + gtk_signal_connect (GTK_OBJECT(event_box), "button_press_event", + GTK_SIGNAL_FUNC (gtk_exit), NULL); + + /* Yet one more thing you need an X window for ... */ + + gtk_widget_realize (event_box); + gdk_window_set_cursor (event_box->window, gdk_cursor_new (GDK_HAND1)); + + gtk_widget_show (window); + + gtk_main (); + + return(0); +} +/* example-end */ -These functions add pages to the notebook by inserting them from the -back of the notebook (append), or the front of the notebook (prepend). - + Fixed Container +

+The Fixed container allows you to place widgets at a fixed position +within it's window, relative to it's upper left hand corner. The +position of the widgets can be changed dynamically. -The final function for adding a page to the notebook contains all of -the properties of the previous two, but it allows you to specify what -position you want the page to be in the notebook. +There are only three functions associated with the fixed widget: -void gtk_notebook_insert_page( GtkNotebook *notebook, - GtkWidget *child, - GtkWidget *tab_label, - gint position ); +GtkWidget* gtk_fixed_new( void ); + +void gtk_fixed_put( GtkFixed *fixed, + GtkWidget *widget, + gint16 x, + gint16 y ); + +void gtk_fixed_move( GtkFixed *fixed, + GtkWidget *widget, + gint16 x, + gint16 y ); -The parameters are the same as _append_ and _prepend_ except it -contains an extra parameter, -void gtk_notebook_remove_page( GtkNotebook *notebook, - gint page_num ); - +/* example-start fixed fixed.c */ -This function takes the page specified by -To find out what the current page is in a notebook use the function: +/* I'm going to be lazy and use some global variables to + * store the position of the widget within the fixed + * container */ +gint x=50; +gint y=50; - -gint gtk_notebook_get_current_page( GtkNotebook *notebook ); - +/* This callback function moves the button to a new position + * in the Fixed container. */ +void move_button( GtkWidget *widget, + GtkWidget *fixed ) +{ + x = (x+30)%300; + y = (y+50)%300; + gtk_fixed_move( GTK_FIXED(fixed), widget, x, y); +} -These next two functions are simple calls to move the notebook page -forward or backward. Simply provide the respective function call with -the notebook widget you wish to operate on. Note: when the NoteBook is -currently on the last page, and gtk_notebook_next_page is called, the -notebook will wrap back to the first page. Likewise, if the NoteBook -is on the first page, and gtk_notebook_prev_page is called, the -notebook will wrap to the last page. +int main( int argc, + char *argv[] ) +{ + /* GtkWidget is the storage type for widgets */ + GtkWidget *window; + GtkWidget *fixed; + GtkWidget *button; + gint i; - -void gtk_notebook_next_page( GtkNoteBook *notebook ); + /* Initialise GTK */ + gtk_init(&argc, &argv); + + /* Create a new window */ + window = gtk_window_new (GTK_WINDOW_TOPLEVEL); + gtk_window_set_title(GTK_WINDOW(window), "Fixed Container"); -void gtk_notebook_prev_page( GtkNoteBook *notebook ); + /* Here we connect the "destroy" event to a signal handler */ + gtk_signal_connect (GTK_OBJECT (window), "destroy", + GTK_SIGNAL_FUNC (gtk_main_quit), NULL); + + /* Sets the border width of the window. */ + gtk_container_set_border_width (GTK_CONTAINER (window), 10); + + /* Create a Fixed Container */ + fixed = gtk_fixed_new(); + gtk_container_add(GTK_CONTAINER(window), fixed); + gtk_widget_show(fixed); + + for (i = 1 ; i <= 3 ; i++) { + /* Creates a new button with the label "Press me" */ + button = gtk_button_new_with_label ("Press me"); + + /* When the button receives the "clicked" signal, it will call the + * function move_button() passing it the Fixed Containter as its + * argument. */ + gtk_signal_connect (GTK_OBJECT (button), "clicked", + GTK_SIGNAL_FUNC (move_button), fixed); + + /* This packs the button into the fixed containers window. */ + gtk_fixed_put (GTK_FIXED (fixed), button, i*50, i*50); + + /* The final step is to display this newly created widget. */ + gtk_widget_show (button); + } + + /* Display the window */ + gtk_widget_show (window); + + /* Enter the event loop */ + gtk_main (); + + return(0); +} +/* example-end */ -This next function sets the 'active' page. If you wish the notebook to -be opened to page 5 for example, you would use this function. Without -using this function, the notebook defaults to the first page. + + Frames +

+Frames can be used to enclose one or a group of widgets with a box +which can optionally be labelled. The position of the label and the +style of the box can be altered to suit. + +A Frame can be created with the following function: -void gtk_notebook_set_page( GtkNotebook *notebook, - gint page_num ); +GtkWidget *gtk_frame_new( const gchar *label ); -The next two functions add or remove the notebook page tabs and the -notebook border respectively. +The label is by default placed in the upper left hand corner of the +frame. A value of NULL for the -void gtk_notebook_set_show_tabs( GtkNotebook *notebook, - gboolean show_tabs); +void gtk_frame_set_label( GtkFrame *frame, + const gchar *label ); + -void gtk_notebook_set_show_border( GtkNotebook *notebook, - gboolean show_border ); +The position of the label can be changed using this function: + + +void gtk_frame_set_label_align( GtkFrame *frame, + gfloat xalign, + gfloat yalign ); -The next function is useful when the you have a large number of pages, -and the tabs don't fit on the page. It allows the tabs to be scrolled -through using two arrow buttons. + -void gtk_notebook_set_scrollable( GtkNotebook *notebook, - gboolean scrollable ); +void gtk_frame_set_shadow_type( GtkFrame *frame, + GtkShadowType type); - + GTK_SHADOW_NONE + GTK_SHADOW_IN + GTK_SHADOW_OUT + GTK_SHADOW_ETCHED_IN (the default) + GTK_SHADOW_ETCHED_OUT + -Now lets look at an example, it is expanded from the testgtk.c code -that comes with the GTK distribution. This small program creates a -window with a notebook and six buttons. The notebook contains 11 -pages, added in three different ways, appended, inserted, and -prepended. The buttons allow you rotate the tab positions, add/remove -the tabs and border, remove a page, change pages in both a forward and -backward manner, and exit the program. +The following code example illustrates the use of the Frame widget. -/* example-start notebook notebook.c */ +/* example-start frame frame.c */ #include -/* This function rotates the position of the tabs */ -void rotate_book (GtkButton *button, GtkNotebook *notebook) +int main( int argc, + char *argv[] ) { - gtk_notebook_set_tab_pos (notebook, (notebook->tab_pos +1) %4); -} + /* GtkWidget is the storage type for widgets */ + GtkWidget *window; + GtkWidget *frame; + GtkWidget *button; + gint i; -/* Add/Remove the page tabs and the borders */ -void tabsborder_book (GtkButton *button, GtkNotebook *notebook) -{ - gint tval = FALSE; - gint bval = FALSE; - if (notebook->show_tabs == 0) - tval = TRUE; - if (notebook->show_border == 0) - bval = TRUE; + /* Initialise GTK */ + gtk_init(&argc, &argv); - gtk_notebook_set_show_tabs (notebook, tval); - gtk_notebook_set_show_border (notebook, bval); -} + /* Create a new window */ + window = gtk_window_new (GTK_WINDOW_TOPLEVEL); + gtk_window_set_title(GTK_WINDOW(window), "Frame Example"); -/* Remove a page from the notebook */ -void remove_book (GtkButton *button, GtkNotebook *notebook) -{ - gint page; - - page = gtk_notebook_get_current_page(notebook); - gtk_notebook_remove_page (notebook, page); - /* Need to refresh the widget -- - This forces the widget to redraw itself. */ - gtk_widget_draw(GTK_WIDGET(notebook), NULL); -} + /* Here we connect the "destroy" event to a signal handler */ + gtk_signal_connect (GTK_OBJECT (window), "destroy", + GTK_SIGNAL_FUNC (gtk_main_quit), NULL); -void delete (GtkWidget *widget, GtkWidget *event, gpointer data) -{ - gtk_main_quit (); -} + gtk_widget_set_usize(window, 300, 300); + /* Sets the border width of the window. */ + gtk_container_set_border_width (GTK_CONTAINER (window), 10); -int main (int argc, char *argv[]) -{ - GtkWidget *window; - GtkWidget *button; - GtkWidget *table; - GtkWidget *notebook; - GtkWidget *frame; - GtkWidget *label; - GtkWidget *checkbutton; - int i; - char bufferf[32]; - char bufferl[32]; - - gtk_init (&argc, &argv); - - window = gtk_window_new (GTK_WINDOW_TOPLEVEL); - - gtk_signal_connect (GTK_OBJECT (window), "delete_event", - GTK_SIGNAL_FUNC (delete), NULL); - - gtk_container_set_border_width (GTK_CONTAINER (window), 10); + /* Create a Frame */ + frame = gtk_frame_new(NULL); + gtk_container_add(GTK_CONTAINER(window), frame); - table = gtk_table_new(3,6,FALSE); - gtk_container_add (GTK_CONTAINER (window), table); - - /* Create a new notebook, place the position of the tabs */ - notebook = gtk_notebook_new (); - gtk_notebook_set_tab_pos (GTK_NOTEBOOK (notebook), GTK_POS_TOP); - gtk_table_attach_defaults(GTK_TABLE(table), notebook, 0,6,0,1); - gtk_widget_show(notebook); - - /* Lets append a bunch of pages to the notebook */ - for (i=0; i < 5; i++) { - sprintf(bufferf, "Append Frame %d", i+1); - sprintf(bufferl, "Page %d", i+1); - - frame = gtk_frame_new (bufferf); - gtk_container_set_border_width (GTK_CONTAINER (frame), 10); - gtk_widget_set_usize (frame, 100, 75); - gtk_widget_show (frame); - - label = gtk_label_new (bufferf); - gtk_container_add (GTK_CONTAINER (frame), label); - gtk_widget_show (label); - - label = gtk_label_new (bufferl); - gtk_notebook_append_page (GTK_NOTEBOOK (notebook), frame, label); - } - - /* Now lets add a page to a specific spot */ - checkbutton = gtk_check_button_new_with_label ("Check me please!"); - gtk_widget_set_usize(checkbutton, 100, 75); - gtk_widget_show (checkbutton); - - label = gtk_label_new ("Add page"); - gtk_notebook_insert_page (GTK_NOTEBOOK (notebook), checkbutton, label, 2); - - /* Now finally lets prepend pages to the notebook */ - for (i=0; i < 5; i++) { - sprintf(bufferf, "Prepend Frame %d", i+1); - sprintf(bufferl, "PPage %d", i+1); - - frame = gtk_frame_new (bufferf); - gtk_container_set_border_width (GTK_CONTAINER (frame), 10); - gtk_widget_set_usize (frame, 100, 75); - gtk_widget_show (frame); - - label = gtk_label_new (bufferf); - gtk_container_add (GTK_CONTAINER (frame), label); - gtk_widget_show (label); - - label = gtk_label_new (bufferl); - gtk_notebook_prepend_page (GTK_NOTEBOOK(notebook), frame, label); - } - - /* Set what page to start at (page 4) */ - gtk_notebook_set_page (GTK_NOTEBOOK(notebook), 3); + /* Set the frames label */ + gtk_frame_set_label( GTK_FRAME(frame), "GTK Frame Widget" ); - /* Create a bunch of buttons */ - button = gtk_button_new_with_label ("close"); - gtk_signal_connect_object (GTK_OBJECT (button), "clicked", - GTK_SIGNAL_FUNC (delete), NULL); - gtk_table_attach_defaults(GTK_TABLE(table), button, 0,1,1,2); - gtk_widget_show(button); - - button = gtk_button_new_with_label ("next page"); - gtk_signal_connect_object (GTK_OBJECT (button), "clicked", - (GtkSignalFunc) gtk_notebook_next_page, - GTK_OBJECT (notebook)); - gtk_table_attach_defaults(GTK_TABLE(table), button, 1,2,1,2); - gtk_widget_show(button); - - button = gtk_button_new_with_label ("prev page"); - gtk_signal_connect_object (GTK_OBJECT (button), "clicked", - (GtkSignalFunc) gtk_notebook_prev_page, - GTK_OBJECT (notebook)); - gtk_table_attach_defaults(GTK_TABLE(table), button, 2,3,1,2); - gtk_widget_show(button); - - button = gtk_button_new_with_label ("tab position"); - gtk_signal_connect (GTK_OBJECT (button), "clicked", - (GtkSignalFunc) rotate_book, GTK_OBJECT(notebook)); - gtk_table_attach_defaults(GTK_TABLE(table), button, 3,4,1,2); - gtk_widget_show(button); - - button = gtk_button_new_with_label ("tabs/border on/off"); - gtk_signal_connect (GTK_OBJECT (button), "clicked", - (GtkSignalFunc) tabsborder_book, - GTK_OBJECT (notebook)); - gtk_table_attach_defaults(GTK_TABLE(table), button, 4,5,1,2); - gtk_widget_show(button); - - button = gtk_button_new_with_label ("remove page"); - gtk_signal_connect (GTK_OBJECT (button), "clicked", - (GtkSignalFunc) remove_book, - GTK_OBJECT(notebook)); - gtk_table_attach_defaults(GTK_TABLE(table), button, 5,6,1,2); - gtk_widget_show(button); - - gtk_widget_show(table); - gtk_widget_show(window); + /* Align the label at the right of the frame */ + gtk_frame_set_label_align( GTK_FRAME(frame), 1.0, 0.0); + + /* Set the style of the frame */ + gtk_frame_set_shadow_type( GTK_FRAME(frame), GTK_SHADOW_ETCHED_OUT); + + gtk_widget_show(frame); + + /* Display the window */ + gtk_widget_show (window); - gtk_main (); + /* Enter the event loop */ + gtk_main (); - return(0); + return(0); } /* example-end */ - - -Hopefully this helps you on your way with creating notebooks for your -GTK applications. - - -Scrolled Windows -

-Scrolled windows are used to create a scrollable area inside a real -window. You may insert any type of widget into a scrolled window, and -it will be accessible regardless of the size by using the scrollbars. -The following function is used to create a new scrolled window. - - -GtkWidget *gtk_scrolled_window_new( GtkAdjustment *hadjustment, - GtkAdjustment *vadjustment ); -Where the first argument is the adjustment for the horizontal -direction, and the second, the adjustment for the vertical direction. -These are almost always set to NULL. - + + Aspect Frames +

+The aspect frame widget is like a frame widget, except that it also +enforces the aspect ratio (that is, the ratio of the width to the +height) of the child widget to have a certain value, adding extra +space if necessary. This is useful, for instance, if you want to +preview a larger image. The size of the preview should vary when the +user resizes the window, but the aspect ratio needs to always match +the original image. + +To create a new aspect frame use: + -void gtk_scrolled_window_set_policy( GtkScrolledWindow *scrolled_window, - GtkPolicyType hscrollbar_policy, - GtkPolicyType vscrollbar_policy ); +GtkWidget *gtk_aspect_frame_new( const gchar *label, + gfloat xalign, + gfloat yalign, + gfloat ratio, + gint obey_child); - -This sets the policy to be used with respect to the scrollbars. -The first argument is the scrolled window you wish to change. The second -sets the policy for the horizontal scrollbar, and the third the policy for -the vertical scrollbar. - -The policy may be one of GTK_POLICY_AUTOMATIC, or GTK_POLICY_ALWAYS. -GTK_POLICY_AUTOMATIC will automatically decide whether you need -scrollbars, whereas GTK_POLICY_ALWAYS will always leave the scrollbars -there. - -You can then place your object into the scrolled window using the -following function. - + + -void gtk_scrolled_window_add_with_viewport( GtkScrolledWindow *scrolled_window, - GtkWidget *child); +void gtk_aspect_frame_set( GtkAspectFrame *aspect_frame, + gfloat xalign, + gfloat yalign, + gfloat ratio, + gint obey_child); - -Here is a simple example that packs 100 toggle buttons into a scrolled -window. I've only commented on the parts that may be new to you. - + +As an example, the following program uses an AspectFrame to present a +drawing area whose aspect ratio will always be 2:1, no matter how the +user resizes the top-level window. + -/* example-start scrolledwin scrolledwin.c */ +/* example-start aspectframe aspectframe.c */ #include - -void destroy(GtkWidget *widget, gpointer data) -{ - gtk_main_quit(); -} - -int main (int argc, char *argv[]) + +int +main (int argc, char *argv[]) { - static GtkWidget *window; - GtkWidget *scrolled_window; - GtkWidget *table; - GtkWidget *button; - char buffer[32]; - int i, j; - + GtkWidget *window; + GtkWidget *aspect_frame; + GtkWidget *drawing_area; gtk_init (&argc, &argv); - - /* Create a new dialog window for the scrolled window to be - * packed into. A dialog is just like a normal window except it has a - * vbox and a horizontal separator packed into it. It's just a shortcut - * for creating dialogs */ - window = gtk_dialog_new (); + + window = gtk_window_new (GTK_WINDOW_TOPLEVEL); + gtk_window_set_title (GTK_WINDOW (window), "Aspect Frame"); gtk_signal_connect (GTK_OBJECT (window), "destroy", - (GtkSignalFunc) destroy, NULL); - gtk_window_set_title (GTK_WINDOW (window), "GtkScrolledWindow example"); - gtk_container_set_border_width (GTK_CONTAINER (window), 0); - gtk_widget_set_usize(window, 300, 300); - - /* create a new scrolled window. */ - scrolled_window = gtk_scrolled_window_new (NULL, NULL); - - gtk_container_set_border_width (GTK_CONTAINER (scrolled_window), 10); - - /* the policy is one of GTK_POLICY AUTOMATIC, or GTK_POLICY_ALWAYS. - * GTK_POLICY_AUTOMATIC will automatically decide whether you need - * scrollbars, whereas GTK_POLICY_ALWAYS will always leave the scrollbars - * there. The first one is the horizontal scrollbar, the second, - * the vertical. */ - gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_window), - GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS); - /* The dialog window is created with a vbox packed into it. */ - gtk_box_pack_start (GTK_BOX (GTK_DIALOG(window)->vbox), scrolled_window, - TRUE, TRUE, 0); - gtk_widget_show (scrolled_window); - - /* create a table of 10 by 10 squares. */ - table = gtk_table_new (10, 10, FALSE); - - /* set the spacing to 10 on x and 10 on y */ - gtk_table_set_row_spacings (GTK_TABLE (table), 10); - gtk_table_set_col_spacings (GTK_TABLE (table), 10); - - /* pack the table into the scrolled window */ - gtk_scrolled_window_add_with_viewport (GTK_SCROLLED_WINDOW (scrolled_window), - table); - gtk_widget_show (table); - - /* this simply creates a grid of toggle buttons on the table - * to demonstrate the scrolled window. */ - for (i = 0; i < 10; i++) - for (j = 0; j < 10; j++) { - sprintf (buffer, "button (%d,%d)\n", i, j); - button = gtk_toggle_button_new_with_label (buffer); - gtk_table_attach_defaults (GTK_TABLE (table), button, - i, i+1, j, j+1); - gtk_widget_show (button); - } - - /* Add a "close" button to the bottom of the dialog */ - button = gtk_button_new_with_label ("close"); - gtk_signal_connect_object (GTK_OBJECT (button), "clicked", - (GtkSignalFunc) gtk_widget_destroy, - GTK_OBJECT (window)); - - /* this makes it so the button is the default. */ - - GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT); - gtk_box_pack_start (GTK_BOX (GTK_DIALOG (window)->action_area), button, TRUE, TRUE, 0); - - /* This grabs this button to be the default button. Simply hitting - * the "Enter" key will cause this button to activate. */ - gtk_widget_grab_default (button); - gtk_widget_show (button); - + GTK_SIGNAL_FUNC (gtk_main_quit), NULL); + gtk_container_set_border_width (GTK_CONTAINER (window), 10); + + /* Create an aspect_frame and add it to our toplevel window */ + + aspect_frame = gtk_aspect_frame_new ("2x1", /* label */ + 0.5, /* center x */ + 0.5, /* center y */ + 2, /* xsize/ysize = 2 */ + FALSE /* ignore child's aspect */); + + gtk_container_add (GTK_CONTAINER(window), aspect_frame); + gtk_widget_show (aspect_frame); + + /* Now add a child widget to the aspect frame */ + + drawing_area = gtk_drawing_area_new (); + + /* Ask for a 200x200 window, but the AspectFrame will give us a 200x100 + * window since we are forcing a 2x1 aspect ratio */ + gtk_widget_set_usize (drawing_area, 200, 200); + gtk_container_add (GTK_CONTAINER(aspect_frame), drawing_area); + gtk_widget_show (drawing_area); + gtk_widget_show (window); - - gtk_main(); - - return(0); + gtk_main (); + return 0; } /* example-end */ -Try playing with resizing the window. You'll notice how the scrollbars -react. You may also wish to use the gtk_widget_set_usize() call to set -the default size of the window or other widgets. - Paned Window Widgets

@@ -5451,6 +5389,152 @@ main (int argc, char *argv[]) /* example-end */ + +Scrolled Windows +

+Scrolled windows are used to create a scrollable area inside a real +window. You may insert any type of widget into a scrolled window, and +it will be accessible regardless of the size by using the scrollbars. + +The following function is used to create a new scrolled window. + + +GtkWidget *gtk_scrolled_window_new( GtkAdjustment *hadjustment, + GtkAdjustment *vadjustment ); + + +Where the first argument is the adjustment for the horizontal +direction, and the second, the adjustment for the vertical direction. +These are almost always set to NULL. + + +void gtk_scrolled_window_set_policy( GtkScrolledWindow *scrolled_window, + GtkPolicyType hscrollbar_policy, + GtkPolicyType vscrollbar_policy ); + + +This sets the policy to be used with respect to the scrollbars. +The first argument is the scrolled window you wish to change. The second +sets the policy for the horizontal scrollbar, and the third the policy for +the vertical scrollbar. + +The policy may be one of GTK_POLICY_AUTOMATIC, or GTK_POLICY_ALWAYS. +GTK_POLICY_AUTOMATIC will automatically decide whether you need +scrollbars, whereas GTK_POLICY_ALWAYS will always leave the scrollbars +there. + +You can then place your object into the scrolled window using the +following function. + + +void gtk_scrolled_window_add_with_viewport( GtkScrolledWindow *scrolled_window, + GtkWidget *child); + + +Here is a simple example that packs 100 toggle buttons into a scrolled +window. I've only commented on the parts that may be new to you. + + +/* example-start scrolledwin scrolledwin.c */ + +#include + +void destroy(GtkWidget *widget, gpointer data) +{ + gtk_main_quit(); +} + +int main (int argc, char *argv[]) +{ + static GtkWidget *window; + GtkWidget *scrolled_window; + GtkWidget *table; + GtkWidget *button; + char buffer[32]; + int i, j; + + gtk_init (&argc, &argv); + + /* Create a new dialog window for the scrolled window to be + * packed into. A dialog is just like a normal window except it has a + * vbox and a horizontal separator packed into it. It's just a shortcut + * for creating dialogs */ + window = gtk_dialog_new (); + gtk_signal_connect (GTK_OBJECT (window), "destroy", + (GtkSignalFunc) destroy, NULL); + gtk_window_set_title (GTK_WINDOW (window), "GtkScrolledWindow example"); + gtk_container_set_border_width (GTK_CONTAINER (window), 0); + gtk_widget_set_usize(window, 300, 300); + + /* create a new scrolled window. */ + scrolled_window = gtk_scrolled_window_new (NULL, NULL); + + gtk_container_set_border_width (GTK_CONTAINER (scrolled_window), 10); + + /* the policy is one of GTK_POLICY AUTOMATIC, or GTK_POLICY_ALWAYS. + * GTK_POLICY_AUTOMATIC will automatically decide whether you need + * scrollbars, whereas GTK_POLICY_ALWAYS will always leave the scrollbars + * there. The first one is the horizontal scrollbar, the second, + * the vertical. */ + gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scrolled_window), + GTK_POLICY_AUTOMATIC, GTK_POLICY_ALWAYS); + /* The dialog window is created with a vbox packed into it. */ + gtk_box_pack_start (GTK_BOX (GTK_DIALOG(window)->vbox), scrolled_window, + TRUE, TRUE, 0); + gtk_widget_show (scrolled_window); + + /* create a table of 10 by 10 squares. */ + table = gtk_table_new (10, 10, FALSE); + + /* set the spacing to 10 on x and 10 on y */ + gtk_table_set_row_spacings (GTK_TABLE (table), 10); + gtk_table_set_col_spacings (GTK_TABLE (table), 10); + + /* pack the table into the scrolled window */ + gtk_scrolled_window_add_with_viewport (GTK_SCROLLED_WINDOW (scrolled_window), + table); + gtk_widget_show (table); + + /* this simply creates a grid of toggle buttons on the table + * to demonstrate the scrolled window. */ + for (i = 0; i < 10; i++) + for (j = 0; j < 10; j++) { + sprintf (buffer, "button (%d,%d)\n", i, j); + button = gtk_toggle_button_new_with_label (buffer); + gtk_table_attach_defaults (GTK_TABLE (table), button, + i, i+1, j, j+1); + gtk_widget_show (button); + } + + /* Add a "close" button to the bottom of the dialog */ + button = gtk_button_new_with_label ("close"); + gtk_signal_connect_object (GTK_OBJECT (button), "clicked", + (GtkSignalFunc) gtk_widget_destroy, + GTK_OBJECT (window)); + + /* this makes it so the button is the default. */ + + GTK_WIDGET_SET_FLAGS (button, GTK_CAN_DEFAULT); + gtk_box_pack_start (GTK_BOX (GTK_DIALOG (window)->action_area), button, TRUE, TRUE, 0); + + /* This grabs this button to be the default button. Simply hitting + * the "Enter" key will cause this button to activate. */ + gtk_widget_grab_default (button); + gtk_widget_show (button); + + gtk_widget_show (window); + + gtk_main(); + + return(0); +} +/* example-end */ + + +Try playing with resizing the window. You'll notice how the scrollbars +react. You may also wish to use the gtk_widget_set_usize() call to set +the default size of the window or other widgets. + Toolbar

@@ -5884,226 +5968,364 @@ static char * gtk_xpm[] = { ".............++++..............."}; - - Aspect Frames + + Notebooks

-The aspect frame widget is like a frame widget, except that it also -enforces the aspect ratio (that is, the ratio of the width to the -height) of the child widget to have a certain value, adding extra -space if necessary. This is useful, for instance, if you want to -preview a larger image. The size of the preview should vary when the -user resizes the window, but the aspect ratio needs to always match -the original image. - -To create a new aspect frame use: - - -GtkWidget *gtk_aspect_frame_new( const gchar *label, - gfloat xalign, - gfloat yalign, - gfloat ratio, - gint obey_child); - - - -void gtk_aspect_frame_set( GtkAspectFrame *aspect_frame, - gfloat xalign, - gfloat yalign, - gfloat ratio, - gint obey_child); +GtkWidget *gtk_notebook_new( void ); - -As an example, the following program uses an AspectFrame to present a -drawing area whose aspect ratio will always be 2:1, no matter how the -user resizes the top-level window. - - -/* example-start aspectframe aspectframe.c */ -#include - -int -main (int argc, char *argv[]) -{ - GtkWidget *window; - GtkWidget *aspect_frame; - GtkWidget *drawing_area; - gtk_init (&argc, &argv); - - window = gtk_window_new (GTK_WINDOW_TOPLEVEL); - gtk_window_set_title (GTK_WINDOW (window), "Aspect Frame"); - gtk_signal_connect (GTK_OBJECT (window), "destroy", - GTK_SIGNAL_FUNC (gtk_main_quit), NULL); - gtk_container_set_border_width (GTK_CONTAINER (window), 10); - - /* Create an aspect_frame and add it to our toplevel window */ - - aspect_frame = gtk_aspect_frame_new ("2x1", /* label */ - 0.5, /* center x */ - 0.5, /* center y */ - 2, /* xsize/ysize = 2 */ - FALSE /* ignore child's aspect */); - - gtk_container_add (GTK_CONTAINER(window), aspect_frame); - gtk_widget_show (aspect_frame); - - /* Now add a child widget to the aspect frame */ - - drawing_area = gtk_drawing_area_new (); - - /* Ask for a 200x200 window, but the AspectFrame will give us a 200x100 - * window since we are forcing a 2x1 aspect ratio */ - gtk_widget_set_usize (drawing_area, 200, 200); - gtk_container_add (GTK_CONTAINER(aspect_frame), drawing_area); - gtk_widget_show (drawing_area); - - gtk_widget_show (window); - gtk_main (); - return 0; -} -/* example-end */ +Once the notebook has been created, there are a number of functions +that operate on the notebook widget. Let's look at them individually. + +The first one we will look at is how to position the page indicators. +These page indicators or 'tabs' as they are referred to, can be +positioned in four ways: top, bottom, left, or right. + + +void gtk_notebook_set_tab_pos( GtkNotebook *notebook, + GtkPositionType pos ); - -The EventBox

-Some gtk widgets don't have associated X windows, so they just draw on -their parents. Because of this, they cannot receive events and if they -are incorrectly sized, they don't clip so you can get messy -overwriting etc. If you require more from these widgets, the EventBox -is for you. +GtkPostionType will be one of the following, and they are pretty self explanatory: + + GTK_POS_LEFT + GTK_POS_RIGHT + GTK_POS_TOP + GTK_POS_BOTTOM + -At first glance, the EventBox widget might appear to be totally -useless. It draws nothing on the screen and responds to no -events. However, it does serve a function - it provides an X window -for its child widget. This is important as many GTK widgets do not -have an associated X window. Not having an X window saves memory and -improves performance, but also has some drawbacks. A widget without an -X window cannot receive events, and does not perform any clipping on -its contents. Although the name -GtkWidget *gtk_event_box_new( void ); +void gtk_notebook_append_page( GtkNotebook *notebook, + GtkWidget *child, + GtkWidget *tab_label ); + +void gtk_notebook_prepend_page( GtkNotebook *notebook, + GtkWidget *child, + GtkWidget *tab_label ); -A child widget can then be added to this EventBox: +These functions add pages to the notebook by inserting them from the +back of the notebook (append), or the front of the notebook (prepend). + -gtk_container_add( GTK_CONTAINER(event_box), widget ); +void gtk_notebook_insert_page( GtkNotebook *notebook, + GtkWidget *child, + GtkWidget *tab_label, + gint position ); -The following example demonstrates both uses of an EventBox - a label -is created that is clipped to a small box, and set up so that a -mouse-click on the label causes the program to exit. Resizing the -window reveals varying amounts of the label. - - -/* example-start eventbox eventbox.c */ +The parameters are the same as _append_ and _prepend_ except it +contains an extra parameter, +Now that we know how to add a page, lets see how we can remove a page +from the notebook. -int -main (int argc, char *argv[]) -{ - GtkWidget *window; - GtkWidget *event_box; - GtkWidget *label; - - gtk_init (&argc, &argv); - - window = gtk_window_new (GTK_WINDOW_TOPLEVEL); - - gtk_window_set_title (GTK_WINDOW (window), "Event Box"); - - gtk_signal_connect (GTK_OBJECT (window), "destroy", - GTK_SIGNAL_FUNC (gtk_exit), NULL); - - gtk_container_set_border_width (GTK_CONTAINER (window), 10); - - /* Create an EventBox and add it to our toplevel window */ - - event_box = gtk_event_box_new (); - gtk_container_add (GTK_CONTAINER(window), event_box); - gtk_widget_show (event_box); - - /* Create a long label */ - - label = gtk_label_new ("Click here to quit, quit, quit, quit, quit"); - gtk_container_add (GTK_CONTAINER (event_box), label); - gtk_widget_show (label); - - /* Clip it short. */ - gtk_widget_set_usize (label, 110, 20); - - /* And bind an action to it */ - gtk_widget_set_events (event_box, GDK_BUTTON_PRESS_MASK); - gtk_signal_connect (GTK_OBJECT(event_box), "button_press_event", - GTK_SIGNAL_FUNC (gtk_exit), NULL); - - /* Yet one more thing you need an X window for ... */ - - gtk_widget_realize (event_box); - gdk_window_set_cursor (event_box->window, gdk_cursor_new (GDK_HAND1)); - - gtk_widget_show (window); - - gtk_main (); - - return(0); -} -/* example-end */ + +void gtk_notebook_remove_page( GtkNotebook *notebook, + gint page_num ); - -CList Widget - - - -

-The GtkCList widget has replaced the GtkList widget (which is still -available). +This function takes the page specified by -Creating a GtkCList widget -

-Creating a GtkCList is quite straightforward, once you have learned -about widgets in general. It provides the almost standard two ways, -that is the hard way, and the easy way. But before we create it, there -is one thing we should figure out beforehand: how many columns should -it have? + +gint gtk_notebook_get_current_page( GtkNotebook *notebook ); + -Not all columns have to be visible and can be used to store data that -is related to a certain cell in the list. +These next two functions are simple calls to move the notebook page +forward or backward. Simply provide the respective function call with +the notebook widget you wish to operate on. Note: when the NoteBook is +currently on the last page, and gtk_notebook_next_page is called, the +notebook will wrap back to the first page. Likewise, if the NoteBook +is on the first page, and gtk_notebook_prev_page is called, the +notebook will wrap to the last page. -GtkWidget *gtk_clist_new ( gint columns ); +void gtk_notebook_next_page( GtkNoteBook *notebook ); -GtkWidget *gtk_clist_new_with_titles( gint columns, - gchar *titles[] ); +void gtk_notebook_prev_page( GtkNoteBook *notebook ); -The first form is very straight forward, the second might require some -explanation. Each column can have a title associated with it, and this -title can be a label or a button that reacts when we click on it. If -we use the second form, we must provide pointers to the title texts, -and the number of pointers should equal the number of columns -specified. Of course we can always use the first form, and manually +This next function sets the 'active' page. If you wish the notebook to +be opened to page 5 for example, you would use this function. Without +using this function, the notebook defaults to the first page. + + +void gtk_notebook_set_page( GtkNotebook *notebook, + gint page_num ); + + +The next two functions add or remove the notebook page tabs and the +notebook border respectively. + + +void gtk_notebook_set_show_tabs( GtkNotebook *notebook, + gboolean show_tabs); + +void gtk_notebook_set_show_border( GtkNotebook *notebook, + gboolean show_border ); + + +The next function is useful when the you have a large number of pages, +and the tabs don't fit on the page. It allows the tabs to be scrolled +through using two arrow buttons. + + +void gtk_notebook_set_scrollable( GtkNotebook *notebook, + gboolean scrollable ); + + + +/* example-start notebook notebook.c */ + +#include + +/* This function rotates the position of the tabs */ +void rotate_book (GtkButton *button, GtkNotebook *notebook) +{ + gtk_notebook_set_tab_pos (notebook, (notebook->tab_pos +1) %4); +} + +/* Add/Remove the page tabs and the borders */ +void tabsborder_book (GtkButton *button, GtkNotebook *notebook) +{ + gint tval = FALSE; + gint bval = FALSE; + if (notebook->show_tabs == 0) + tval = TRUE; + if (notebook->show_border == 0) + bval = TRUE; + + gtk_notebook_set_show_tabs (notebook, tval); + gtk_notebook_set_show_border (notebook, bval); +} + +/* Remove a page from the notebook */ +void remove_book (GtkButton *button, GtkNotebook *notebook) +{ + gint page; + + page = gtk_notebook_get_current_page(notebook); + gtk_notebook_remove_page (notebook, page); + /* Need to refresh the widget -- + This forces the widget to redraw itself. */ + gtk_widget_draw(GTK_WIDGET(notebook), NULL); +} + +void delete (GtkWidget *widget, GtkWidget *event, gpointer data) +{ + gtk_main_quit (); +} + +int main (int argc, char *argv[]) +{ + GtkWidget *window; + GtkWidget *button; + GtkWidget *table; + GtkWidget *notebook; + GtkWidget *frame; + GtkWidget *label; + GtkWidget *checkbutton; + int i; + char bufferf[32]; + char bufferl[32]; + + gtk_init (&argc, &argv); + + window = gtk_window_new (GTK_WINDOW_TOPLEVEL); + + gtk_signal_connect (GTK_OBJECT (window), "delete_event", + GTK_SIGNAL_FUNC (delete), NULL); + + gtk_container_set_border_width (GTK_CONTAINER (window), 10); + + table = gtk_table_new(3,6,FALSE); + gtk_container_add (GTK_CONTAINER (window), table); + + /* Create a new notebook, place the position of the tabs */ + notebook = gtk_notebook_new (); + gtk_notebook_set_tab_pos (GTK_NOTEBOOK (notebook), GTK_POS_TOP); + gtk_table_attach_defaults(GTK_TABLE(table), notebook, 0,6,0,1); + gtk_widget_show(notebook); + + /* Lets append a bunch of pages to the notebook */ + for (i=0; i < 5; i++) { + sprintf(bufferf, "Append Frame %d", i+1); + sprintf(bufferl, "Page %d", i+1); + + frame = gtk_frame_new (bufferf); + gtk_container_set_border_width (GTK_CONTAINER (frame), 10); + gtk_widget_set_usize (frame, 100, 75); + gtk_widget_show (frame); + + label = gtk_label_new (bufferf); + gtk_container_add (GTK_CONTAINER (frame), label); + gtk_widget_show (label); + + label = gtk_label_new (bufferl); + gtk_notebook_append_page (GTK_NOTEBOOK (notebook), frame, label); + } + + /* Now lets add a page to a specific spot */ + checkbutton = gtk_check_button_new_with_label ("Check me please!"); + gtk_widget_set_usize(checkbutton, 100, 75); + gtk_widget_show (checkbutton); + + label = gtk_label_new ("Add page"); + gtk_notebook_insert_page (GTK_NOTEBOOK (notebook), checkbutton, label, 2); + + /* Now finally lets prepend pages to the notebook */ + for (i=0; i < 5; i++) { + sprintf(bufferf, "Prepend Frame %d", i+1); + sprintf(bufferl, "PPage %d", i+1); + + frame = gtk_frame_new (bufferf); + gtk_container_set_border_width (GTK_CONTAINER (frame), 10); + gtk_widget_set_usize (frame, 100, 75); + gtk_widget_show (frame); + + label = gtk_label_new (bufferf); + gtk_container_add (GTK_CONTAINER (frame), label); + gtk_widget_show (label); + + label = gtk_label_new (bufferl); + gtk_notebook_prepend_page (GTK_NOTEBOOK(notebook), frame, label); + } + + /* Set what page to start at (page 4) */ + gtk_notebook_set_page (GTK_NOTEBOOK(notebook), 3); + + /* Create a bunch of buttons */ + button = gtk_button_new_with_label ("close"); + gtk_signal_connect_object (GTK_OBJECT (button), "clicked", + GTK_SIGNAL_FUNC (delete), NULL); + gtk_table_attach_defaults(GTK_TABLE(table), button, 0,1,1,2); + gtk_widget_show(button); + + button = gtk_button_new_with_label ("next page"); + gtk_signal_connect_object (GTK_OBJECT (button), "clicked", + (GtkSignalFunc) gtk_notebook_next_page, + GTK_OBJECT (notebook)); + gtk_table_attach_defaults(GTK_TABLE(table), button, 1,2,1,2); + gtk_widget_show(button); + + button = gtk_button_new_with_label ("prev page"); + gtk_signal_connect_object (GTK_OBJECT (button), "clicked", + (GtkSignalFunc) gtk_notebook_prev_page, + GTK_OBJECT (notebook)); + gtk_table_attach_defaults(GTK_TABLE(table), button, 2,3,1,2); + gtk_widget_show(button); + + button = gtk_button_new_with_label ("tab position"); + gtk_signal_connect (GTK_OBJECT (button), "clicked", + (GtkSignalFunc) rotate_book, GTK_OBJECT(notebook)); + gtk_table_attach_defaults(GTK_TABLE(table), button, 3,4,1,2); + gtk_widget_show(button); + + button = gtk_button_new_with_label ("tabs/border on/off"); + gtk_signal_connect (GTK_OBJECT (button), "clicked", + (GtkSignalFunc) tabsborder_book, + GTK_OBJECT (notebook)); + gtk_table_attach_defaults(GTK_TABLE(table), button, 4,5,1,2); + gtk_widget_show(button); + + button = gtk_button_new_with_label ("remove page"); + gtk_signal_connect (GTK_OBJECT (button), "clicked", + (GtkSignalFunc) remove_book, + GTK_OBJECT(notebook)); + gtk_table_attach_defaults(GTK_TABLE(table), button, 5,6,1,2); + gtk_widget_show(button); + + gtk_widget_show(table); + gtk_widget_show(window); + + gtk_main (); + + return(0); +} +/* example-end */ + + +Hopefully this helps you on your way with creating notebooks for your +GTK applications. + + +CList Widget + + + +

+The GtkCList widget has replaced the GtkList widget (which is still +available). + +The GtkCList widget is a multi-column list widget that is capable of +handling literally thousands of rows of information. Each column can +optionally have a title, which itself is optionally active, allowing +us to bind a function to its selection. + + +Creating a GtkCList widget +

+Creating a GtkCList is quite straightforward, once you have learned +about widgets in general. It provides the almost standard two ways, +that is the hard way, and the easy way. But before we create it, there +is one thing we should figure out beforehand: how many columns should +it have? + +Not all columns have to be visible and can be used to store data that +is related to a certain cell in the list. + + +GtkWidget *gtk_clist_new ( gint columns ); + +GtkWidget *gtk_clist_new_with_titles( gint columns, + gchar *titles[] ); + + +The first form is very straight forward, the second might require some +explanation. Each column can have a title associated with it, and this +title can be a label or a button that reacts when we click on it. If +we use the second form, we must provide pointers to the title texts, +and the number of pointers should equal the number of columns +specified. Of course we can always use the first form, and manually add titles later. Note: the GtkCList widget does not have it's own scrollbars and should @@ -6781,1059 +7003,446 @@ void selection_made( GtkWidget *clist, gint row, gint column, - List Widget + Tree Widget

-NOTE: The GtkList widget has been superseded by the GtkCList widget. - -The GtkList widget is designed to act as a vertical container for -widgets that should be of the type GtkListItem. +The purpose of tree widgets is to display hierarchically-organized +data. The GtkTree widget itself is a vertical container for widgets of +type GtkTreeItem. GtkTree itself is not terribly different from +GtkList - both are derived directly from GtkContainer, and the +GtkContainer methods work in the same way on GtkTree widgets as on +GtkList widgets. The difference is that GtkTree widgets can be nested +within other GtkTree widgets. We'll see how to do this shortly. -A GtkList widget has its own window to receive events and its own -background color which is usually white. As it is directly derived -from a GtkContainer it can be treated as such by using the -GTK_CONTAINER(List) macro, see the GtkContainer widget for more on -this. One should already be familiar with the usage of a GList and -its related functions g_list_*() to be able to use the GtkList widget -to it full extent. +The GtkTree widget has its own window, and defaults to a white +background, as does GtkList. Also, most of the GtkTree methods work in +the same way as the corresponding GtkList ones. However, GtkTree is +not derived from GtkList, so you cannot use them interchangeably. -There is one field inside the structure definition of the GtkList -widget that will be of greater interest to us, this is: + Creating a Tree +

+A GtkTree is created in the usual way, using: -struct _GtkList -{ - ... - GList *selection; - guint selection_mode; - ... -}; +GtkWidget* gtk_tree_new( void ); -The selection field of a GtkList points to a linked list of all items -that are currently selected, or NULL if the selection is empty. So to -learn about the current selection we read the GTK_LIST()->selection -field, but do not modify it since the internal fields are maintained -by the gtk_list_*() functions. +Like the GtkList widget, a GtkTree will simply keep growing as more +items are added to it, as well as when subtrees are expanded. For +this reason, they are almost always packed into a +GtkScrolledWindow. You might want to use gtk_widget_set_usize() on the +scrolled window to ensure that it is big enough to see the tree's +items, as the default size for GtkScrolledWindow is quite small. -The selection_mode of the GtkList determines the selection facilities -of a GtkList and therefore the contents of the GTK_LIST()->selection -field. The selection_mode may be one of the following: +Now that you have a tree, you'll probably want to add some items to +it. below +explains the gory details of GtkTreeItem. For now, it'll suffice to +create one, using: - - GTK_SELECTION_SINGLE - The selection is either NULL - or contains a GList pointer - for a single selected item. + +GtkWidget* gtk_tree_item_new_with_label( gchar *label ); + - GTK_SELECTION_BROWSE - The selection is NULL if the list - contains no widgets or insensitive - ones only, otherwise it contains - a GList pointer for one GList - structure, and therefore exactly - one list item. +You can then add it to the tree using one of the following (see + +below for more options): - GTK_SELECTION_MULTIPLE - The selection is NULL if no list - items are selected or a GList pointer - for the first selected item. That - in turn points to a GList structure - for the second selected item and so - on. + +void gtk_tree_append( GtkTree *tree, + GtkWidget *tree_item ); - GTK_SELECTION_EXTENDED - The selection is always NULL. - +void gtk_tree_prepend( GtkTree *tree, + GtkWidget *tree_item ); + -The default is GTK_SELECTION_MULTIPLE. +Note that you must add items to a GtkTree one at a time - there is no +equivalent to gtk_list_*_items(). - Signals + Adding a Subtree

+A subtree is created like any other GtkTree widget. A subtree is added +to another tree beneath a tree item, using: + -void selection_changed( GtkList *list ); +void gtk_tree_item_set_subtree( GtkTreeItem *tree_item, + GtkWidget *subtree ); -This signal will be invoked whenever the selection field of a GtkList -has changed. This happens when a child of the GtkList got selected or -deselected. +You do not need to call gtk_widget_show() on a subtree before or after +adding it to a GtkTreeItem. However, you must have added the +GtkTreeItem in question to a parent tree before calling +gtk_tree_item_set_subtree(). This is because, technically, the parent +of the subtree is not the GtkTreeItem which "owns" it, but +rather the GtkTree which holds that GtkTreeItem. - -void select_child( GtkList *list, - GtkWidget *child); - +When you add a subtree to a GtkTreeItem, a plus or minus sign appears +beside it, which the user can click on to "expand" or "collapse" it, +meaning, to show or hide its subtree. GtkTreeItems are collapsed by +default. Note that when you collapse a GtkTreeItem, any selected +items in its subtree remain selected, which may not be what the user +expects. -This signal is invoked when a child of the GtkList is about to get -selected. This happens mainly on calls to gtk_list_select_item(), -gtk_list_select_child(), button presses and sometimes indirectly -triggered on some else occasions where children get added to or -removed from the GtkList. + + Handling the Selection List +

+As with GtkList, the GtkTree type has a selection field, and +it is possible to control the behaviour of the tree (somewhat) by +setting the selection type using: -void unselect_child( GtkList *list, - GtkWidget *child ); +void gtk_tree_set_selection_mode( GtkTree *tree, + GtkSelectionMode mode ); -This signal is invoked when a child of the GtkList is about to get -deselected. This happens mainly on calls to gtk_list_unselect_item(), -gtk_list_unselect_child(), button presses and sometimes indirectly -triggered on some else occasions where children get added to or -removed from the GtkList. +The semantics associated with the various selection modes are +described in the section on the GtkList widget. As with the GtkList +widget, the "select_child", "unselect_child" (not really - see below for an explanation), +and "selection_changed" signals are emitted when list items are +selected or unselected. However, in order to take advantage of these +signals, you need to know which GtkTree widget they will be +emitted by, and where to find the list of selected items. - - Functions +This is a source of potential confusion. The best way to explain this +is that though all GtkTree widgets are created equal, some are more +equal than others. All GtkTree widgets have their own X window, and +can therefore receive events such as mouse clicks (if their +GtkTreeItems or their children don't catch them first!). However, to +make GTK_SELECTION_SINGLE and GTK_SELECTION_BROWSE selection types +behave in a sane manner, the list of selected items is specific to the +topmost GtkTree widget in a hierarchy, known as the "root tree". + +Thus, accessing the selectionfield directly in an arbitrary +GtkTree widget is not a good idea unless you know it's the +root tree. Instead, use the GTK_TREE_SELECTION (Tree) macro, which +gives the root tree's selection list as a GList pointer. Of course, +this list can include items that are not in the subtree in question if +the selection type is GTK_SELECTION_MULTIPLE. + +Finally, the "select_child" (and "unselect_child", in theory) signals +are emitted by all trees, but the "selection_changed" signal is only +emitted by the root tree. Consequently, if you want to handle the +"select_child" signal for a tree and all its subtrees, you will have +to call gtk_signal_connect() for every subtree. + + Tree Widget Internals

+The GtkTree's struct definition looks like this: + -guint gtk_list_get_type( void ); +struct _GtkTree +{ + GtkContainer container; + + GList *children; + + GtkTree* root_tree; /* owner of selection list */ + GtkWidget* tree_owner; + GList *selection; + guint level; + guint indent_value; + guint current_indent; + guint selection_mode : 2; + guint view_mode : 1; + guint view_line : 1; +}; -Returns the `GtkList' type identifier. +The perils associated with accessing the selection field +directly have already been mentioned. The other important fields of +the struct can also be accessed with handy macros or class functions. +GTK_TREE_IS_ROOT_TREE (Tree) returns a boolean value which indicates +whether a tree is the root tree in a GtkTree hierarchy, while +GTK_TREE_ROOT_TREE (Tree) returns the root tree, an object of type +GtkTree (so, remember to cast it using GTK_WIDGET (Tree) if you want +to use one of the gtk_widget_*() functions on it). + +Instead of directly accessing the children field of a GtkTree widget, +it's probably best to cast it using GTK_CONTAINER (Tree), and pass it +to the gtk_container_children() function. This creates a duplicate of +the original list, so it's advisable to free it up using g_list_free() +after you're done with it, or to iterate on it destructively, like +this: -GtkWidget *gtk_list_new( void ); + children = gtk_container_children (GTK_CONTAINER (tree)); + while (children) { + do_something_nice (GTK_TREE_ITEM (children->data)); + children = g_list_remove_link (children, children); +} -Create a new GtkList object. The new widget is returned as a pointer -to a GtkWidget object. NULL is returned on failure. +The tree_owner field is defined only in subtrees, where it +points to the GtkTreeItem widget which holds the tree in question. +The level field indicates how deeply nested a particular tree +is; root trees have level 0, and each successive level of subtrees has +a level one greater than the parent level. This field is set only +after a GtkTree widget is actually mapped (i.e. drawn on the screen). + Signals

-void gtk_list_insert_items( GtkList *list, - GList *items, - gint position ); +void selection_changed( GtkTree *tree ); -Insert list items into the list, starting at selection field of a +GtkTree has changed. This happens when a child of the GtkTree is +selected or deselected. -void gtk_list_append_items( GtkList *list, - GList *items); +void select_child( GtkTree *tree, + GtkWidget *child ); -Insert list items just like gtk_list_insert_items() at the end of the -list. The GList nodes of all button presses and calls to +gtk_tree_item_toggle() and gtk_item_toggle(). It may sometimes be +indirectly triggered on other occasions where children get added to or +removed from the GtkTree. -void gtk_list_prepend_items( GtkList *list, - GList *items); +void unselect_child (GtkTree *tree, + GtkWidget *child); -Insert list items just like gtk_list_insert_items() at the very -beginning of the list. The GList nodes of not when a button press deselects a +child, nor on emission of the "toggle" signal by gtk_item_toggle(). + Functions and Macros

-void gtk_list_remove_items( GtkList *list, - GList *items); +guint gtk_tree_get_type( void ); -Remove list items from the list. -void gtk_list_clear_items( GtkList *list, - gint start, - gint end ); +GtkWidget* gtk_tree_new( void ); -Remove and destroy list items from the list. A widget is affected if -its current position within the list is in the range specified by - -void gtk_list_select_item( GtkList *list, +void gtk_tree_append( GtkTree *tree, + GtkWidget *tree_item ); + + +Append a tree item to a GtkTree. + + +void gtk_tree_prepend( GtkTree *tree, + GtkWidget *tree_item ); + + +Prepend a tree item to a GtkTree. + + +void gtk_tree_insert( GtkTree *tree, + GtkWidget *tree_item, + gint position ); + + +Insert a tree item into a GtkTree at the position in the list +specified by position. + + +void gtk_tree_remove_items( GtkTree *tree, + GList *items ); + + +Remove a list of items (in the form of a GList *) from a GtkTree. +Note that removing an item from a tree dereferences (and thus usually) +destroys it and its subtree, if it has one, and all +subtrees in that subtree. If you want to remove only one item, you +can use gtk_container_remove(). + + +void gtk_tree_clear_items( GtkTree *tree, + gint start, + gint end ); + + +Remove the items from position start to position end +from a GtkTree. The same warning about dereferencing applies here, as +gtk_tree_clear_items() simply constructs a list and passes it to +gtk_tree_remove_items(). + + +void gtk_tree_select_item( GtkTree *tree, gint item ); -Invoke the select_child signal for a list item specified through its -current position within the list. +Emits the "select_item" signal for the child at position +item, thus selecting the child (unless you unselect it in a +signal handler). -void gtk_list_unselect_item( GtkList *list, - gint item); +void gtk_tree_unselect_item( GtkTree *tree, + gint item ); -Invoke the unselect_child signal for a list item specified through its -current position within the list. +Emits the "unselect_item" signal for the child at position +item, thus unselecting the child. -void gtk_list_select_child( GtkList *list, - GtkWidget *child); +void gtk_tree_select_child( GtkTree *tree, + GtkWidget *tree_item ); -Invoke the select_child signal for the specified child. +Emits the "select_item" signal for the child tree_item, thus +selecting it. -void gtk_list_unselect_child( GtkList *list, - GtkWidget *child); +void gtk_tree_unselect_child( GtkTree *tree, + GtkWidget *tree_item ); -Invoke the unselect_child signal for the specified child. +Emits the "unselect_item" signal for the child tree_item, +thus unselecting it. -gint gtk_list_child_position( GtkList *list, - GtkWidget *child); +gint gtk_tree_child_position( GtkTree *tree, + GtkWidget *child ); -Return the position of child, unless +child is not in the tree, in which case it returns -1. -void gtk_list_set_selection_mode( GtkList *list, - GtkSelectionMode mode ); +void gtk_tree_set_selection_mode( GtkTree *tree, + GtkSelectionMode mode ); -Set the selection mode MODE which can be of GTK_SELECTION_SINGLE, -GTK_SELECTION_BROWSE, GTK_SELECTION_MULTIPLE or -GTK_SELECTION_EXTENDED. +Sets the selection mode, which can be one of GTK_SELECTION_SINGLE (the +default), GTK_SELECTION_BROWSE, GTK_SELECTION_MULTIPLE, or +GTK_SELECTION_EXTENDED. This is only defined for root trees, which +makes sense, since the root tree "owns" the selection. Setting it for +subtrees has no effect at all; the value is simply ignored. -GtkList *GTK_LIST( gpointer obj ); +void gtk_tree_set_view_mode( GtkTree *tree, + GtkTreeViewMode mode ); -Cast a generic pointer to `GtkList *'. *Note Standard Macros::, for -more info. +Sets the "view mode", which can be either GTK_TREE_VIEW_LINE (the +default) or GTK_TREE_VIEW_ITEM. The view mode propagates from a tree +to its subtrees, and can't be set exclusively to a subtree (this is +not exactly true - see the example code comments). + +The term "view mode" is rather ambiguous - basically, it controls the +way the highlight is drawn when one of a tree's children is selected. +If it's GTK_TREE_VIEW_LINE, the entire GtkTreeItem widget is +highlighted, while for GTK_TREE_VIEW_ITEM, only the child widget +(i.e. usually the label) is highlighted. -GtkListClass *GTK_LIST_CLASS( gpointer class); +void gtk_tree_set_view_lines( GtkTree *tree, + guint flag ); -Cast a generic pointer to `GtkListClass*'. *Note Standard Macros::, -for more info. +Controls whether connecting lines between tree items are drawn. +flag is either TRUE, in which case they are, or FALSE, in +which case they aren't. -gint GTK_IS_LIST( gpointer obj); +GtkTree *GTK_TREE (gpointer obj); -Determine if a generic pointer refers to a `GtkList' object. *Note -Standard Macros::, for more info. +Cast a generic pointer to `GtkTree *'. - - Example + +GtkTreeClass *GTK_TREE_CLASS (gpointer class); + + +Cast a generic pointer to `GtkTreeClass*'. + + +gint GTK_IS_TREE (gpointer obj); + + +Determine if a generic pointer refers to a `GtkTree' object. + + +gint GTK_IS_ROOT_TREE (gpointer obj) + + +Determine if a generic pointer refers to a `GtkTree' object +and is a root tree. Though this will accept any pointer, the +results of passing it a pointer that does not refer to a GtkTree are +undefined and possibly harmful. + + +GtkTree *GTK_TREE_ROOT_TREE (gpointer obj) + + +Return the root tree of a pointer to a `GtkTree' object. The above +warning applies. + + +GList *GTK_TREE_SELECTION( gpointer obj) + + +Return the selection list of the root tree of a `GtkTree' object. The +above warning applies here, too. + + Tree Item Widget

-Following is an example program that will print out the changes of the -selection of a GtkList, and lets you "arrest" list items into a prison -by selecting them with the rightmost mouse button. +The GtkTreeItem widget, like GtkListItem, is derived from GtkItem, +which in turn is derived from GtkBin. Therefore, the item itself is a +generic container holding exactly one child widget, which can be of +any type. The GtkTreeItem widget has a number of extra fields, but +the only one we need be concerned with is the subtree field. + +The definition for the GtkTreeItem struct looks like this: -/* example-start list list.c */ +struct _GtkTreeItem +{ + GtkItem item; -/* Include the gtk+ header files - * Include stdio.h, we need that for the printf() function - */ -#include -#include + GtkWidget *subtree; + GtkWidget *pixmaps_box; + GtkWidget *plus_pix_widget, *minus_pix_widget; -/* This is our data identification string to store - * data in list items - */ -const gchar *list_item_data_key="list_item_data"; + GList *pixmaps; /* pixmap node for this items color depth */ + guint expanded : 1; +}; + -/* prototypes for signal handler that we are going to connect - * to the GtkList widget - */ -static void sigh_print_selection( GtkWidget *gtklist, - gpointer func_data); +The pixmaps_box field is a GtkEventBox which catches clicks +on the plus/minus symbol which controls expansion and collapsing. The +pixmaps field points to an internal data structure. Since +you can always obtain the subtree of a GtkTreeItem in a (relatively) +type-safe manner with the GTK_TREE_ITEM_SUBTREE (Item) macro, it's +probably advisable never to touch the insides of a GtkTreeItem unless +you really know what you're doing. -static void sigh_button_event( GtkWidget *gtklist, - GdkEventButton *event, - GtkWidget *frame ); +Since it is directly derived from a GtkItem it can be treated as such +by using the GTK_ITEM (TreeItem) macro. A GtkTreeItem usually holds a +label, so the convenience function gtk_list_item_new_with_label() is +provided. The same effect can be achieved using code like the +following, which is actually copied verbatim from +gtk_tree_item_new_with_label(): + +tree_item = gtk_tree_item_new (); +label_widget = gtk_label_new (label); +gtk_misc_set_alignment (GTK_MISC (label_widget), 0.0, 0.5); -/* Main function to set up the user interface */ +gtk_container_add (GTK_CONTAINER (tree_item), label_widget); +gtk_widget_show (label_widget); + -gint main (int argc, - gchar *argv[]) -{ - GtkWidget *separator; - GtkWidget *window; - GtkWidget *vbox; - GtkWidget *scrolled_window; - GtkWidget *frame; - GtkWidget *gtklist; - GtkWidget *button; - GtkWidget *list_item; - GList *dlist; - guint i; - gchar buffer[64]; - - - /* Initialize gtk+ (and subsequently gdk) */ - - gtk_init(&argc, &argv); - - - /* Create a window to put all the widgets in - * connect gtk_main_quit() to the "destroy" event of - * the window to handle window manager close-window-events - */ - window=gtk_window_new(GTK_WINDOW_TOPLEVEL); - gtk_window_set_title(GTK_WINDOW(window), "GtkList Example"); - gtk_signal_connect(GTK_OBJECT(window), - "destroy", - GTK_SIGNAL_FUNC(gtk_main_quit), - NULL); - - - /* Inside the window we need a box to arrange the widgets - * vertically */ - vbox=gtk_vbox_new(FALSE, 5); - gtk_container_set_border_width(GTK_CONTAINER(vbox), 5); - gtk_container_add(GTK_CONTAINER(window), vbox); - gtk_widget_show(vbox); - - /* This is the scrolled window to put the GtkList widget inside */ - scrolled_window=gtk_scrolled_window_new(NULL, NULL); - gtk_widget_set_usize(scrolled_window, 250, 150); - gtk_container_add(GTK_CONTAINER(vbox), scrolled_window); - gtk_widget_show(scrolled_window); - - /* Create the GtkList widget. - * Connect the sigh_print_selection() signal handler - * function to the "selection_changed" signal of the GtkList - * to print out the selected items each time the selection - * has changed */ - gtklist=gtk_list_new(); - gtk_scrolled_window_add_with_viewport( GTK_SCROLLED_WINDOW(scrolled_window), - gtklist); - gtk_widget_show(gtklist); - gtk_signal_connect(GTK_OBJECT(gtklist), - "selection_changed", - GTK_SIGNAL_FUNC(sigh_print_selection), - NULL); - - /* We create a "Prison" to put a list item in ;) */ - frame=gtk_frame_new("Prison"); - gtk_widget_set_usize(frame, 200, 50); - gtk_container_set_border_width(GTK_CONTAINER(frame), 5); - gtk_frame_set_shadow_type(GTK_FRAME(frame), GTK_SHADOW_OUT); - gtk_container_add(GTK_CONTAINER(vbox), frame); - gtk_widget_show(frame); - - /* Connect the sigh_button_event() signal handler to the GtkList - * which will handle the "arresting" of list items - */ - gtk_signal_connect(GTK_OBJECT(gtklist), - "button_release_event", - GTK_SIGNAL_FUNC(sigh_button_event), - frame); - - /* Create a separator */ - separator=gtk_hseparator_new(); - gtk_container_add(GTK_CONTAINER(vbox), separator); - gtk_widget_show(separator); - - /* Finally create a button and connect it's "clicked" signal - * to the destruction of the window */ - button=gtk_button_new_with_label("Close"); - gtk_container_add(GTK_CONTAINER(vbox), button); - gtk_widget_show(button); - gtk_signal_connect_object(GTK_OBJECT(button), - "clicked", - GTK_SIGNAL_FUNC(gtk_widget_destroy), - GTK_OBJECT(window)); - - - /* Now we create 5 list items, each having it's own - * label and add them to the GtkList using gtk_container_add() - * Also we query the text string from the label and - * associate it with the list_item_data_key for each list item - */ - for (i=0; i<5; i++) { - GtkWidget *label; - gchar *string; - - sprintf(buffer, "ListItemContainer with Label #%d", i); - label=gtk_label_new(buffer); - list_item=gtk_list_item_new(); - gtk_container_add(GTK_CONTAINER(list_item), label); - gtk_widget_show(label); - gtk_container_add(GTK_CONTAINER(gtklist), list_item); - gtk_widget_show(list_item); - gtk_label_get(GTK_LABEL(label), &string); - gtk_object_set_data(GTK_OBJECT(list_item), - list_item_data_key, - string); - } - /* Here, we are creating another 5 labels, this time - * we use gtk_list_item_new_with_label() for the creation - * we can't query the text string from the label because - * we don't have the labels pointer and therefore - * we just associate the list_item_data_key of each - * list item with the same text string. - * For adding of the list items we put them all into a doubly - * linked list (GList), and then add them by a single call to - * gtk_list_append_items(). - * Because we use g_list_prepend() to put the items into the - * doubly linked list, their order will be descending (instead - * of ascending when using g_list_append()) - */ - dlist=NULL; - for (; i<10; i++) { - sprintf(buffer, "List Item with Label %d", i); - list_item=gtk_list_item_new_with_label(buffer); - dlist=g_list_prepend(dlist, list_item); - gtk_widget_show(list_item); - gtk_object_set_data(GTK_OBJECT(list_item), - list_item_data_key, - "ListItem with integrated Label"); - } - gtk_list_append_items(GTK_LIST(gtklist), dlist); - - /* Finally we want to see the window, don't we? ;) */ - gtk_widget_show(window); - - /* Fire up the main event loop of gtk */ - gtk_main(); - - /* We get here after gtk_main_quit() has been called which - * happens if the main window gets destroyed - */ - return(0); -} - -/* This is the signal handler that got connected to button - * press/release events of the GtkList - */ -void sigh_button_event( GtkWidget *gtklist, - GdkEventButton *event, - GtkWidget *frame ) -{ - /* We only do something if the third (rightmost mouse button - * was released - */ - if (event->type==GDK_BUTTON_RELEASE && - event->button==3) { - GList *dlist, *free_list; - GtkWidget *new_prisoner; - - /* Fetch the currently selected list item which - * will be our next prisoner ;) - */ - dlist=GTK_LIST(gtklist)->selection; - if (dlist) - new_prisoner=GTK_WIDGET(dlist->data); - else - new_prisoner=NULL; - - /* Look for already imprisoned list items, we - * will put them back into the list. - * Remember to free the doubly linked list that - * gtk_container_children() returns - */ - dlist=gtk_container_children(GTK_CONTAINER(frame)); - free_list=dlist; - while (dlist) { - GtkWidget *list_item; - - list_item=dlist->data; - - gtk_widget_reparent(list_item, gtklist); - - dlist=dlist->next; - } - g_list_free(free_list); - - /* If we have a new prisoner, remove him from the - * GtkList and put him into the frame "Prison". - * We need to unselect the item first. - */ - if (new_prisoner) { - GList static_dlist; - - static_dlist.data=new_prisoner; - static_dlist.next=NULL; - static_dlist.prev=NULL; - - gtk_list_unselect_child(GTK_LIST(gtklist), - new_prisoner); - gtk_widget_reparent(new_prisoner, frame); - } - } -} - -/* This is the signal handler that gets called if GtkList - * emits the "selection_changed" signal - */ -void sigh_print_selection( GtkWidget *gtklist, - gpointer func_data) -{ - GList *dlist; - - /* Fetch the doubly linked list of selected items - * of the GtkList, remember to treat this as read-only! - */ - dlist=GTK_LIST(gtklist)->selection; - - /* If there are no selected items there is nothing more - * to do than just telling the user so - */ - if (!dlist) { - g_print("Selection cleared\n"); - return; - } - /* Ok, we got a selection and so we print it - */ - g_print("The selection is a "); - - /* Get the list item from the doubly linked list - * and then query the data associated with list_item_data_key. - * We then just print it */ - while (dlist) { - GtkObject *list_item; - gchar *item_data_string; - - list_item=GTK_OBJECT(dlist->data); - item_data_string=gtk_object_get_data(list_item, - list_item_data_key); - g_print("%s ", item_data_string); - - dlist=dlist->next; - } - g_print("\n"); -} -/* example-end */ - - - - List Item Widget -

-The GtkListItem widget is designed to act as a container holding up to -one child, providing functions for selection/deselection just like the -GtkList widget requires them for its children. - -A GtkListItem has its own window to receive events and has its own -background color which is usually white. - -As it is directly derived from a GtkItem it can be treated as such by -using the GTK_ITEM(ListItem) macro, see the GtkItem widget for more on -this. Usually a GtkListItem just holds a label to identify e.g. a -filename within a GtkList -- therefore the convenience function -gtk_list_item_new_with_label() is provided. The same effect can be -achieved by creating a GtkLabel on its own, setting its alignment to -xalign=0 and yalign=0.5 with a subsequent container addition to the -GtkListItem. - -As one is not forced to add a GtkLabel to a GtkListItem, you could -also add a GtkVBox or a GtkArrow etc. to the GtkListItem. - - - Signals -

-A GtkListItem does not create new signals on its own, but inherits -the signals of a GtkItem. *Note GtkItem::, for more info. - - - Functions -

- -guint gtk_list_item_get_type( void ); - - -Returns the `GtkListItem' type identifier. - - -GtkWidget *gtk_list_item_new( void ); - - -Create a new GtkListItem object. The new widget is returned as a -pointer to a GtkWidget object. NULL is returned on failure. - - -GtkWidget *gtk_list_item_new_with_label( gchar *label ); - - -Create a new GtkListItem object, having a single GtkLabel as the sole -child. The new widget is returned as a pointer to a GtkWidget -object. NULL is returned on failure. - - -void gtk_list_item_select( GtkListItem *list_item ); - - -This function is basically a wrapper around a call to gtk_item_select -(GTK_ITEM (list_item)) which will emit the select signal. *Note -GtkItem::, for more info. - - -void gtk_list_item_deselect( GtkListItem *list_item ); - - -This function is basically a wrapper around a call to -gtk_item_deselect (GTK_ITEM (list_item)) which will emit the deselect -signal. *Note GtkItem::, for more info. - - -GtkListItem *GTK_LIST_ITEM( gpointer obj ); - - -Cast a generic pointer to `GtkListItem*'. *Note Standard Macros::, for -more info. - - -GtkListItemClass *GTK_LIST_ITEM_CLASS( gpointer class ); - - -Cast a generic pointer to GtkListItemClass*. *Note Standard Macros::, -for more info. - - -gint GTK_IS_LIST_ITEM( gpointer obj ); - - -Determine if a generic pointer refers to a `GtkListItem' object. -*Note Standard Macros::, for more info. - - - Example -

-Please see the GtkList example on this, which covers the usage of a -GtkListItem as well. - - - Tree Widget

-The purpose of tree widgets is to display hierarchically-organized -data. The GtkTree widget itself is a vertical container for widgets of -type GtkTreeItem. GtkTree itself is not terribly different from -GtkList - both are derived directly from GtkContainer, and the -GtkContainer methods work in the same way on GtkTree widgets as on -GtkList widgets. The difference is that GtkTree widgets can be nested -within other GtkTree widgets. We'll see how to do this shortly. - -The GtkTree widget has its own window, and defaults to a white -background, as does GtkList. Also, most of the GtkTree methods work in -the same way as the corresponding GtkList ones. However, GtkTree is -not derived from GtkList, so you cannot use them interchangeably. - - Creating a Tree -

-A GtkTree is created in the usual way, using: - - -GtkWidget* gtk_tree_new( void ); - - -Like the GtkList widget, a GtkTree will simply keep growing as more -items are added to it, as well as when subtrees are expanded. For -this reason, they are almost always packed into a -GtkScrolledWindow. You might want to use gtk_widget_set_usize() on the -scrolled window to ensure that it is big enough to see the tree's -items, as the default size for GtkScrolledWindow is quite small. - -Now that you have a tree, you'll probably want to add some items to -it. below -explains the gory details of GtkTreeItem. For now, it'll suffice to -create one, using: - - -GtkWidget* gtk_tree_item_new_with_label( gchar *label ); - - -You can then add it to the tree using one of the following (see - -below for more options): - - -void gtk_tree_append( GtkTree *tree, - GtkWidget *tree_item ); - -void gtk_tree_prepend( GtkTree *tree, - GtkWidget *tree_item ); - - -Note that you must add items to a GtkTree one at a time - there is no -equivalent to gtk_list_*_items(). - - - Adding a Subtree -

-A subtree is created like any other GtkTree widget. A subtree is added -to another tree beneath a tree item, using: - - -void gtk_tree_item_set_subtree( GtkTreeItem *tree_item, - GtkWidget *subtree ); - - -You do not need to call gtk_widget_show() on a subtree before or after -adding it to a GtkTreeItem. However, you must have added the -GtkTreeItem in question to a parent tree before calling -gtk_tree_item_set_subtree(). This is because, technically, the parent -of the subtree is not the GtkTreeItem which "owns" it, but -rather the GtkTree which holds that GtkTreeItem. - -When you add a subtree to a GtkTreeItem, a plus or minus sign appears -beside it, which the user can click on to "expand" or "collapse" it, -meaning, to show or hide its subtree. GtkTreeItems are collapsed by -default. Note that when you collapse a GtkTreeItem, any selected -items in its subtree remain selected, which may not be what the user -expects. - - - Handling the Selection List -

-As with GtkList, the GtkTree type has a selection field, and -it is possible to control the behaviour of the tree (somewhat) by -setting the selection type using: - - -void gtk_tree_set_selection_mode( GtkTree *tree, - GtkSelectionMode mode ); - - -The semantics associated with the various selection modes are -described in the section on the GtkList widget. As with the GtkList -widget, the "select_child", "unselect_child" (not really - see below for an explanation), -and "selection_changed" signals are emitted when list items are -selected or unselected. However, in order to take advantage of these -signals, you need to know which GtkTree widget they will be -emitted by, and where to find the list of selected items. - -This is a source of potential confusion. The best way to explain this -is that though all GtkTree widgets are created equal, some are more -equal than others. All GtkTree widgets have their own X window, and -can therefore receive events such as mouse clicks (if their -GtkTreeItems or their children don't catch them first!). However, to -make GTK_SELECTION_SINGLE and GTK_SELECTION_BROWSE selection types -behave in a sane manner, the list of selected items is specific to the -topmost GtkTree widget in a hierarchy, known as the "root tree". - -Thus, accessing the selectionfield directly in an arbitrary -GtkTree widget is not a good idea unless you know it's the -root tree. Instead, use the GTK_TREE_SELECTION (Tree) macro, which -gives the root tree's selection list as a GList pointer. Of course, -this list can include items that are not in the subtree in question if -the selection type is GTK_SELECTION_MULTIPLE. - -Finally, the "select_child" (and "unselect_child", in theory) signals -are emitted by all trees, but the "selection_changed" signal is only -emitted by the root tree. Consequently, if you want to handle the -"select_child" signal for a tree and all its subtrees, you will have -to call gtk_signal_connect() for every subtree. - - Tree Widget Internals -

-The GtkTree's struct definition looks like this: - - -struct _GtkTree -{ - GtkContainer container; - - GList *children; - - GtkTree* root_tree; /* owner of selection list */ - GtkWidget* tree_owner; - GList *selection; - guint level; - guint indent_value; - guint current_indent; - guint selection_mode : 2; - guint view_mode : 1; - guint view_line : 1; -}; - - -The perils associated with accessing the selection field -directly have already been mentioned. The other important fields of -the struct can also be accessed with handy macros or class functions. -GTK_TREE_IS_ROOT_TREE (Tree) returns a boolean value which indicates -whether a tree is the root tree in a GtkTree hierarchy, while -GTK_TREE_ROOT_TREE (Tree) returns the root tree, an object of type -GtkTree (so, remember to cast it using GTK_WIDGET (Tree) if you want -to use one of the gtk_widget_*() functions on it). - -Instead of directly accessing the children field of a GtkTree widget, -it's probably best to cast it using GTK_CONTAINER (Tree), and pass it -to the gtk_container_children() function. This creates a duplicate of -the original list, so it's advisable to free it up using g_list_free() -after you're done with it, or to iterate on it destructively, like -this: - - - children = gtk_container_children (GTK_CONTAINER (tree)); - while (children) { - do_something_nice (GTK_TREE_ITEM (children->data)); - children = g_list_remove_link (children, children); -} - - -The tree_owner field is defined only in subtrees, where it -points to the GtkTreeItem widget which holds the tree in question. -The level field indicates how deeply nested a particular tree -is; root trees have level 0, and each successive level of subtrees has -a level one greater than the parent level. This field is set only -after a GtkTree widget is actually mapped (i.e. drawn on the screen). - - Signals

- -void selection_changed( GtkTree *tree ); - - -This signal will be emitted whenever the selection field of a -GtkTree has changed. This happens when a child of the GtkTree is -selected or deselected. - - -void select_child( GtkTree *tree, - GtkWidget *child ); - - -This signal is emitted when a child of the GtkTree is about to get -selected. This happens on calls to gtk_tree_select_item(), -gtk_tree_select_child(), on all button presses and calls to -gtk_tree_item_toggle() and gtk_item_toggle(). It may sometimes be -indirectly triggered on other occasions where children get added to or -removed from the GtkTree. - - -void unselect_child (GtkTree *tree, - GtkWidget *child); - - -This signal is emitted when a child of the GtkTree is about to get -deselected. As of GTK+ 1.0.4, this seems to only occur on calls to -gtk_tree_unselect_item() or gtk_tree_unselect_child(), and perhaps on -other occasions, but not when a button press deselects a -child, nor on emission of the "toggle" signal by gtk_item_toggle(). - - Functions and Macros

- -guint gtk_tree_get_type( void ); - - -Returns the `GtkTree' type identifier. - - -GtkWidget* gtk_tree_new( void ); - - -Create a new GtkTree object. The new widget is returned as a pointer -to a GtkWidget object. NULL is returned on failure. - - -void gtk_tree_append( GtkTree *tree, - GtkWidget *tree_item ); - - -Append a tree item to a GtkTree. - - -void gtk_tree_prepend( GtkTree *tree, - GtkWidget *tree_item ); - - -Prepend a tree item to a GtkTree. - - -void gtk_tree_insert( GtkTree *tree, - GtkWidget *tree_item, - gint position ); - - -Insert a tree item into a GtkTree at the position in the list -specified by position. - - -void gtk_tree_remove_items( GtkTree *tree, - GList *items ); - - -Remove a list of items (in the form of a GList *) from a GtkTree. -Note that removing an item from a tree dereferences (and thus usually) -destroys it and its subtree, if it has one, and all -subtrees in that subtree. If you want to remove only one item, you -can use gtk_container_remove(). - - -void gtk_tree_clear_items( GtkTree *tree, - gint start, - gint end ); - - -Remove the items from position start to position end -from a GtkTree. The same warning about dereferencing applies here, as -gtk_tree_clear_items() simply constructs a list and passes it to -gtk_tree_remove_items(). - - -void gtk_tree_select_item( GtkTree *tree, - gint item ); - - -Emits the "select_item" signal for the child at position -item, thus selecting the child (unless you unselect it in a -signal handler). - - -void gtk_tree_unselect_item( GtkTree *tree, - gint item ); - - -Emits the "unselect_item" signal for the child at position -item, thus unselecting the child. - - -void gtk_tree_select_child( GtkTree *tree, - GtkWidget *tree_item ); - - -Emits the "select_item" signal for the child tree_item, thus -selecting it. - - -void gtk_tree_unselect_child( GtkTree *tree, - GtkWidget *tree_item ); - - -Emits the "unselect_item" signal for the child tree_item, -thus unselecting it. - - -gint gtk_tree_child_position( GtkTree *tree, - GtkWidget *child ); - - -Returns the position in the tree of child, unless -child is not in the tree, in which case it returns -1. - - -void gtk_tree_set_selection_mode( GtkTree *tree, - GtkSelectionMode mode ); - - -Sets the selection mode, which can be one of GTK_SELECTION_SINGLE (the -default), GTK_SELECTION_BROWSE, GTK_SELECTION_MULTIPLE, or -GTK_SELECTION_EXTENDED. This is only defined for root trees, which -makes sense, since the root tree "owns" the selection. Setting it for -subtrees has no effect at all; the value is simply ignored. - - -void gtk_tree_set_view_mode( GtkTree *tree, - GtkTreeViewMode mode ); - - -Sets the "view mode", which can be either GTK_TREE_VIEW_LINE (the -default) or GTK_TREE_VIEW_ITEM. The view mode propagates from a tree -to its subtrees, and can't be set exclusively to a subtree (this is -not exactly true - see the example code comments). - -The term "view mode" is rather ambiguous - basically, it controls the -way the highlight is drawn when one of a tree's children is selected. -If it's GTK_TREE_VIEW_LINE, the entire GtkTreeItem widget is -highlighted, while for GTK_TREE_VIEW_ITEM, only the child widget -(i.e. usually the label) is highlighted. - - -void gtk_tree_set_view_lines( GtkTree *tree, - guint flag ); - - -Controls whether connecting lines between tree items are drawn. -flag is either TRUE, in which case they are, or FALSE, in -which case they aren't. - - -GtkTree *GTK_TREE (gpointer obj); - - -Cast a generic pointer to `GtkTree *'. - - -GtkTreeClass *GTK_TREE_CLASS (gpointer class); - - -Cast a generic pointer to `GtkTreeClass*'. - - -gint GTK_IS_TREE (gpointer obj); - - -Determine if a generic pointer refers to a `GtkTree' object. - - -gint GTK_IS_ROOT_TREE (gpointer obj) - - -Determine if a generic pointer refers to a `GtkTree' object -and is a root tree. Though this will accept any pointer, the -results of passing it a pointer that does not refer to a GtkTree are -undefined and possibly harmful. - - -GtkTree *GTK_TREE_ROOT_TREE (gpointer obj) - - -Return the root tree of a pointer to a `GtkTree' object. The above -warning applies. - - -GList *GTK_TREE_SELECTION( gpointer obj) - - -Return the selection list of the root tree of a `GtkTree' object. The -above warning applies here, too. - - Tree Item Widget

-The GtkTreeItem widget, like GtkListItem, is derived from GtkItem, -which in turn is derived from GtkBin. Therefore, the item itself is a -generic container holding exactly one child widget, which can be of -any type. The GtkTreeItem widget has a number of extra fields, but -the only one we need be concerned with is the subtree field. - -The definition for the GtkTreeItem struct looks like this: - - -struct _GtkTreeItem -{ - GtkItem item; - - GtkWidget *subtree; - GtkWidget *pixmaps_box; - GtkWidget *plus_pix_widget, *minus_pix_widget; - - GList *pixmaps; /* pixmap node for this items color depth */ - - guint expanded : 1; -}; - - -The pixmaps_box field is a GtkEventBox which catches clicks -on the plus/minus symbol which controls expansion and collapsing. The -pixmaps field points to an internal data structure. Since -you can always obtain the subtree of a GtkTreeItem in a (relatively) -type-safe manner with the GTK_TREE_ITEM_SUBTREE (Item) macro, it's -probably advisable never to touch the insides of a GtkTreeItem unless -you really know what you're doing. - -Since it is directly derived from a GtkItem it can be treated as such -by using the GTK_ITEM (TreeItem) macro. A GtkTreeItem usually holds a -label, so the convenience function gtk_list_item_new_with_label() is -provided. The same effect can be achieved using code like the -following, which is actually copied verbatim from -gtk_tree_item_new_with_label(): - - -tree_item = gtk_tree_item_new (); -label_widget = gtk_label_new (label); -gtk_misc_set_alignment (GTK_MISC (label_widget), 0.0, 0.5); - -gtk_container_add (GTK_CONTAINER (tree_item), label_widget); -gtk_widget_show (label_widget); - - -As one is not forced to add a GtkLabel to a GtkTreeItem, you could -also add a GtkHBox or a GtkArrow, or even a GtkNotebook (though your -app will likely be quite unpopular in this case) to the GtkTreeItem. +As one is not forced to add a GtkLabel to a GtkTreeItem, you could +also add a GtkHBox or a GtkArrow, or even a GtkNotebook (though your +app will likely be quite unpopular in this case) to the GtkTreeItem. If you remove all the items from a subtree, it will be destroyed and unparented, unless you reference it beforehand, and the GtkTreeItem @@ -9139,12 +8748,6 @@ from your time. Drawing Area

- Fixed Container -

- - Frame -

- Font Selection Dialog

@@ -14188,283 +13791,574 @@ The other event type that is different from the others is data types, which allows it to be cast to a specific event data type within a signal handler. - -So, the event data types are defined as follows: + +So, the event data types are defined as follows: + + +struct _GdkEventAny +{ + GdkEventType type; + GdkWindow *window; + gint8 send_event; +}; + +struct _GdkEventExpose +{ + GdkEventType type; + GdkWindow *window; + gint8 send_event; + GdkRectangle area; + gint count; /* If non-zero, how many more events follow. */ +}; + +struct _GdkEventNoExpose +{ + GdkEventType type; + GdkWindow *window; + gint8 send_event; + /* XXX: does anyone need the X major_code or minor_code fields? */ +}; + +struct _GdkEventVisibility +{ + GdkEventType type; + GdkWindow *window; + gint8 send_event; + GdkVisibilityState state; +}; + +struct _GdkEventMotion +{ + GdkEventType type; + GdkWindow *window; + gint8 send_event; + guint32 time; + gdouble x; + gdouble y; + gdouble pressure; + gdouble xtilt; + gdouble ytilt; + guint state; + gint16 is_hint; + GdkInputSource source; + guint32 deviceid; + gdouble x_root, y_root; +}; + +struct _GdkEventButton +{ + GdkEventType type; + GdkWindow *window; + gint8 send_event; + guint32 time; + gdouble x; + gdouble y; + gdouble pressure; + gdouble xtilt; + gdouble ytilt; + guint state; + guint button; + GdkInputSource source; + guint32 deviceid; + gdouble x_root, y_root; +}; + +struct _GdkEventKey +{ + GdkEventType type; + GdkWindow *window; + gint8 send_event; + guint32 time; + guint state; + guint keyval; + gint length; + gchar *string; +}; + +struct _GdkEventCrossing +{ + GdkEventType type; + GdkWindow *window; + gint8 send_event; + GdkWindow *subwindow; + GdkNotifyType detail; +}; + +struct _GdkEventFocus +{ + GdkEventType type; + GdkWindow *window; + gint8 send_event; + gint16 in; +}; + +struct _GdkEventConfigure +{ + GdkEventType type; + GdkWindow *window; + gint8 send_event; + gint16 x, y; + gint16 width; + gint16 height; +}; + +struct _GdkEventProperty +{ + GdkEventType type; + GdkWindow *window; + gint8 send_event; + GdkAtom atom; + guint32 time; + guint state; +}; + +struct _GdkEventSelection +{ + GdkEventType type; + GdkWindow *window; + gint8 send_event; + GdkAtom selection; + GdkAtom target; + GdkAtom property; + guint32 requestor; + guint32 time; +}; + +/* This event type will be used pretty rarely. It only is important + for XInput aware programs that are drawing their own cursor */ + +struct _GdkEventProximity +{ + GdkEventType type; + GdkWindow *window; + gint8 send_event; + guint32 time; + GdkInputSource source; + guint32 deviceid; +}; + +struct _GdkEventDragRequest +{ + GdkEventType type; + GdkWindow *window; + gint8 send_event; + guint32 requestor; + union { + struct { + guint protocol_version:4; + guint sendreply:1; + guint willaccept:1; + guint delete_data:1; /* Do *not* delete if link is sent, only + if data is sent */ + guint senddata:1; + guint reserved:22; + } flags; + glong allflags; + } u; + guint8 isdrop; /* This gdk event can be generated by a couple of + X events - this lets the app know whether the + drop really occurred or we just set the data */ + + GdkPoint drop_coords; + gchar *data_type; + guint32 timestamp; +}; - -struct _GdkEventAny +struct _GdkEventDragBegin { GdkEventType type; GdkWindow *window; gint8 send_event; + union { + struct { + guint protocol_version:4; + guint reserved:28; + } flags; + glong allflags; + } u; }; -struct _GdkEventExpose +struct _GdkEventDropEnter { GdkEventType type; GdkWindow *window; gint8 send_event; - GdkRectangle area; - gint count; /* If non-zero, how many more events follow. */ + guint32 requestor; + union { + struct { + guint protocol_version:4; + guint sendreply:1; + guint extended_typelist:1; + guint reserved:26; + } flags; + glong allflags; + } u; }; -struct _GdkEventNoExpose +struct _GdkEventDropLeave { GdkEventType type; GdkWindow *window; gint8 send_event; - /* XXX: does anyone need the X major_code or minor_code fields? */ + guint32 requestor; + union { + struct { + guint protocol_version:4; + guint reserved:28; + } flags; + glong allflags; + } u; }; -struct _GdkEventVisibility +struct _GdkEventDropDataAvailable { GdkEventType type; GdkWindow *window; gint8 send_event; - GdkVisibilityState state; + guint32 requestor; + union { + struct { + guint protocol_version:4; + guint isdrop:1; + guint reserved:25; + } flags; + glong allflags; + } u; + gchar *data_type; /* MIME type */ + gulong data_numbytes; + gpointer data; + guint32 timestamp; + GdkPoint coords; }; -struct _GdkEventMotion +struct _GdkEventClient { GdkEventType type; GdkWindow *window; gint8 send_event; - guint32 time; - gdouble x; - gdouble y; - gdouble pressure; - gdouble xtilt; - gdouble ytilt; - guint state; - gint16 is_hint; - GdkInputSource source; - guint32 deviceid; - gdouble x_root, y_root; + GdkAtom message_type; + gushort data_format; + union { + char b[20]; + short s[10]; + long l[5]; + } data; }; -struct _GdkEventButton +struct _GdkEventOther { GdkEventType type; GdkWindow *window; gint8 send_event; - guint32 time; - gdouble x; - gdouble y; - gdouble pressure; - gdouble xtilt; - gdouble ytilt; - guint state; - guint button; - GdkInputSource source; - guint32 deviceid; - gdouble x_root, y_root; + GdkXEvent *xevent; +}; + + + + Code Examples + +

+Below are the code examples that are used in the above text +which are not included in complete form elsewhere. + + +Tictactoe + +tictactoe.h +

+ +/* example-start tictactoe tictactoe.h */ + +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ +#ifndef __TICTACTOE_H__ +#define __TICTACTOE_H__ + + +#include +#include + + +#ifdef __cplusplus +extern "C" { +#endif /* __cplusplus */ + +#define TICTACTOE(obj) GTK_CHECK_CAST (obj, tictactoe_get_type (), Tictactoe) +#define TICTACTOE_CLASS(klass) GTK_CHECK_CLASS_CAST (klass, tictactoe_get_type (), TictactoeClass) +#define IS_TICTACTOE(obj) GTK_CHECK_TYPE (obj, tictactoe_get_type ()) + + +typedef struct _Tictactoe Tictactoe; +typedef struct _TictactoeClass TictactoeClass; + +struct _Tictactoe +{ + GtkVBox vbox; + + GtkWidget *buttons[3][3]; +}; + +struct _TictactoeClass +{ + GtkVBoxClass parent_class; + + void (* tictactoe) (Tictactoe *ttt); +}; + +guint tictactoe_get_type (void); +GtkWidget* tictactoe_new (void); +void tictactoe_clear (Tictactoe *ttt); + +#ifdef __cplusplus +} +#endif /* __cplusplus */ + +#endif /* __TICTACTOE_H__ */ + +/* example-end */ + + + +tictactoe.c +

+ +/* example-start tictactoe tictactoe.c */ + +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ +#include "gtk/gtksignal.h" +#include "gtk/gtktable.h" +#include "gtk/gtktogglebutton.h" +#include "tictactoe.h" + +enum { + TICTACTOE_SIGNAL, + LAST_SIGNAL }; -struct _GdkEventKey +static void tictactoe_class_init (TictactoeClass *klass); +static void tictactoe_init (Tictactoe *ttt); +static void tictactoe_toggle (GtkWidget *widget, Tictactoe *ttt); + +static gint tictactoe_signals[LAST_SIGNAL] = { 0 }; + +guint +tictactoe_get_type () +{ + static guint ttt_type = 0; + + if (!ttt_type) + { + GtkTypeInfo ttt_info = + { + "Tictactoe", + sizeof (Tictactoe), + sizeof (TictactoeClass), + (GtkClassInitFunc) tictactoe_class_init, + (GtkObjectInitFunc) tictactoe_init, + (GtkArgSetFunc) NULL, + (GtkArgGetFunc) NULL + }; + + ttt_type = gtk_type_unique (gtk_vbox_get_type (), &ttt_info); + } + + return ttt_type; +} + +static void +tictactoe_class_init (TictactoeClass *class) { - GdkEventType type; - GdkWindow *window; - gint8 send_event; - guint32 time; - guint state; - guint keyval; - gint length; - gchar *string; -}; + GtkObjectClass *object_class; -struct _GdkEventCrossing -{ - GdkEventType type; - GdkWindow *window; - gint8 send_event; - GdkWindow *subwindow; - GdkNotifyType detail; -}; + object_class = (GtkObjectClass*) class; + + tictactoe_signals[TICTACTOE_SIGNAL] = gtk_signal_new ("tictactoe", + GTK_RUN_FIRST, + object_class->type, + GTK_SIGNAL_OFFSET (TictactoeClass, tictactoe), + gtk_signal_default_marshaller, GTK_TYPE_NONE, 0); -struct _GdkEventFocus -{ - GdkEventType type; - GdkWindow *window; - gint8 send_event; - gint16 in; -}; -struct _GdkEventConfigure -{ - GdkEventType type; - GdkWindow *window; - gint8 send_event; - gint16 x, y; - gint16 width; - gint16 height; -}; + gtk_object_class_add_signals (object_class, tictactoe_signals, LAST_SIGNAL); -struct _GdkEventProperty -{ - GdkEventType type; - GdkWindow *window; - gint8 send_event; - GdkAtom atom; - guint32 time; - guint state; -}; + class->tictactoe = NULL; +} -struct _GdkEventSelection +static void +tictactoe_init (Tictactoe *ttt) { - GdkEventType type; - GdkWindow *window; - gint8 send_event; - GdkAtom selection; - GdkAtom target; - GdkAtom property; - guint32 requestor; - guint32 time; -}; + GtkWidget *table; + gint i,j; + + table = gtk_table_new (3, 3, TRUE); + gtk_container_add (GTK_CONTAINER(ttt), table); + gtk_widget_show (table); -/* This event type will be used pretty rarely. It only is important - for XInput aware programs that are drawing their own cursor */ + for (i=0;i<3; i++) + for (j=0;j<3; j++) + { + ttt->buttons[i][j] = gtk_toggle_button_new (); + gtk_table_attach_defaults (GTK_TABLE(table), ttt->buttons[i][j], + i, i+1, j, j+1); + gtk_signal_connect (GTK_OBJECT (ttt->buttons[i][j]), "toggled", + GTK_SIGNAL_FUNC (tictactoe_toggle), ttt); + gtk_widget_set_usize (ttt->buttons[i][j], 20, 20); + gtk_widget_show (ttt->buttons[i][j]); + } +} -struct _GdkEventProximity +GtkWidget* +tictactoe_new () { - GdkEventType type; - GdkWindow *window; - gint8 send_event; - guint32 time; - GdkInputSource source; - guint32 deviceid; -}; + return GTK_WIDGET ( gtk_type_new (tictactoe_get_type ())); +} -struct _GdkEventDragRequest +void +tictactoe_clear (Tictactoe *ttt) { - GdkEventType type; - GdkWindow *window; - gint8 send_event; - guint32 requestor; - union { - struct { - guint protocol_version:4; - guint sendreply:1; - guint willaccept:1; - guint delete_data:1; /* Do *not* delete if link is sent, only - if data is sent */ - guint senddata:1; - guint reserved:22; - } flags; - glong allflags; - } u; - guint8 isdrop; /* This gdk event can be generated by a couple of - X events - this lets the app know whether the - drop really occurred or we just set the data */ + int i,j; - GdkPoint drop_coords; - gchar *data_type; - guint32 timestamp; -}; + for (i=0;i<3;i++) + for (j=0;j<3;j++) + { + gtk_signal_handler_block_by_data (GTK_OBJECT(ttt->buttons[i][j]), ttt); + gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (ttt->buttons[i][j]), + FALSE); + gtk_signal_handler_unblock_by_data (GTK_OBJECT(ttt->buttons[i][j]), ttt); + } +} -struct _GdkEventDragBegin +static void +tictactoe_toggle (GtkWidget *widget, Tictactoe *ttt) { - GdkEventType type; - GdkWindow *window; - gint8 send_event; - union { - struct { - guint protocol_version:4; - guint reserved:28; - } flags; - glong allflags; - } u; -}; + int i,k; -struct _GdkEventDropEnter -{ - GdkEventType type; - GdkWindow *window; - gint8 send_event; - guint32 requestor; - union { - struct { - guint protocol_version:4; - guint sendreply:1; - guint extended_typelist:1; - guint reserved:26; - } flags; - glong allflags; - } u; -}; + static int rwins[8][3] = { { 0, 0, 0 }, { 1, 1, 1 }, { 2, 2, 2 }, + { 0, 1, 2 }, { 0, 1, 2 }, { 0, 1, 2 }, + { 0, 1, 2 }, { 0, 1, 2 } }; + static int cwins[8][3] = { { 0, 1, 2 }, { 0, 1, 2 }, { 0, 1, 2 }, + { 0, 0, 0 }, { 1, 1, 1 }, { 2, 2, 2 }, + { 0, 1, 2 }, { 2, 1, 0 } }; -struct _GdkEventDropLeave -{ - GdkEventType type; - GdkWindow *window; - gint8 send_event; - guint32 requestor; - union { - struct { - guint protocol_version:4; - guint reserved:28; - } flags; - glong allflags; - } u; -}; + int success, found; -struct _GdkEventDropDataAvailable -{ - GdkEventType type; - GdkWindow *window; - gint8 send_event; - guint32 requestor; - union { - struct { - guint protocol_version:4; - guint isdrop:1; - guint reserved:25; - } flags; - glong allflags; - } u; - gchar *data_type; /* MIME type */ - gulong data_numbytes; - gpointer data; - guint32 timestamp; - GdkPoint coords; -}; + for (k=0; k<8; k++) + { + success = TRUE; + found = FALSE; -struct _GdkEventClient -{ - GdkEventType type; - GdkWindow *window; - gint8 send_event; - GdkAtom message_type; - gushort data_format; - union { - char b[20]; - short s[10]; - long l[5]; - } data; -}; + for (i=0;i<3;i++) + { + success = success && + GTK_TOGGLE_BUTTON(ttt->buttons[rwins[k][i]][cwins[k][i]])->active; + found = found || + ttt->buttons[rwins[k][i]][cwins[k][i]] == widget; + } + + if (success && found) + { + gtk_signal_emit (GTK_OBJECT (ttt), + tictactoe_signals[TICTACTOE_SIGNAL]); + break; + } + } +} + +/* example-end */ + + + +ttt_test.c +

+ +/* example-start tictactoe ttt_test.c */ + +#include +#include "tictactoe.h" + +void +win (GtkWidget *widget, gpointer data) +{ + g_print ("Yay!\n"); + tictactoe_clear (TICTACTOE (widget)); +} -struct _GdkEventOther +int +main (int argc, char *argv[]) { - GdkEventType type; - GdkWindow *window; - gint8 send_event; - GdkXEvent *xevent; -}; - + GtkWidget *window; + GtkWidget *ttt; + + gtk_init (&argc, &argv); - - Code Examples - -

-Below are the code examples that are used in the above text -which are not included in complete form elsewhere. + window = gtk_window_new (GTK_WINDOW_TOPLEVEL); + + gtk_window_set_title (GTK_WINDOW (window), "Aspect Frame"); + + gtk_signal_connect (GTK_OBJECT (window), "destroy", + GTK_SIGNAL_FUNC (gtk_exit), NULL); + + gtk_container_set_border_width (GTK_CONTAINER (window), 10); + + ttt = tictactoe_new (); + + gtk_container_add (GTK_CONTAINER (window), ttt); + gtk_widget_show (ttt); + + gtk_signal_connect (GTK_OBJECT (ttt), "tictactoe", + GTK_SIGNAL_FUNC (win), NULL); + + gtk_widget_show (window); + + gtk_main (); + + return 0; +} + +/* example-end */ + -Tictactoe + GtkDial + -tictactoe.h + gtkdial.h

-/* example-start tictactoe tictactoe.h */ +/* example-start gtkdial gtkdial.h */ /* GTK - The GIMP Toolkit * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald @@ -14484,58 +14378,85 @@ which are not included in complete form elsewhere. * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ -#ifndef __TICTACTOE_H__ -#define __TICTACTOE_H__ +#ifndef __GTK_DIAL_H__ +#define __GTK_DIAL_H__ #include -#include +#include +#include #ifdef __cplusplus extern "C" { #endif /* __cplusplus */ -#define TICTACTOE(obj) GTK_CHECK_CAST (obj, tictactoe_get_type (), Tictactoe) -#define TICTACTOE_CLASS(klass) GTK_CHECK_CLASS_CAST (klass, tictactoe_get_type (), TictactoeClass) -#define IS_TICTACTOE(obj) GTK_CHECK_TYPE (obj, tictactoe_get_type ()) +#define GTK_DIAL(obj) GTK_CHECK_CAST (obj, gtk_dial_get_type (), GtkDial) +#define GTK_DIAL_CLASS(klass) GTK_CHECK_CLASS_CAST (klass, gtk_dial_get_type (), GtkDialClass) +#define GTK_IS_DIAL(obj) GTK_CHECK_TYPE (obj, gtk_dial_get_type ()) -typedef struct _Tictactoe Tictactoe; -typedef struct _TictactoeClass TictactoeClass; -struct _Tictactoe +typedef struct _GtkDial GtkDial; +typedef struct _GtkDialClass GtkDialClass; + +struct _GtkDial { - GtkVBox vbox; - - GtkWidget *buttons[3][3]; + GtkWidget widget; + + /* update policy (GTK_UPDATE_[CONTINUOUS/DELAYED/DISCONTINUOUS]) */ + guint policy : 2; + + /* Button currently pressed or 0 if none */ + guint8 button; + + /* Dimensions of dial components */ + gint radius; + gint pointer_width; + + /* ID of update timer, or 0 if none */ + guint32 timer; + + /* Current angle */ + gfloat angle; + + /* Old values from adjustment stored so we know when something changes */ + gfloat old_value; + gfloat old_lower; + gfloat old_upper; + + /* The adjustment object that stores the data for this dial */ + GtkAdjustment *adjustment; }; -struct _TictactoeClass +struct _GtkDialClass { - GtkVBoxClass parent_class; - - void (* tictactoe) (Tictactoe *ttt); + GtkWidgetClass parent_class; }; -guint tictactoe_get_type (void); -GtkWidget* tictactoe_new (void); -void tictactoe_clear (Tictactoe *ttt); +GtkWidget* gtk_dial_new (GtkAdjustment *adjustment); +guint gtk_dial_get_type (void); +GtkAdjustment* gtk_dial_get_adjustment (GtkDial *dial); +void gtk_dial_set_update_policy (GtkDial *dial, + GtkUpdateType policy); + +void gtk_dial_set_adjustment (GtkDial *dial, + GtkAdjustment *adjustment); #ifdef __cplusplus } #endif /* __cplusplus */ -#endif /* __TICTACTOE_H__ */ +#endif /* __GTK_DIAL_H__ */ /* example-end */ -tictactoe.c + gtkdial.c

-/* example-start tictactoe tictactoe.c */ +/* example-start gtkdial gtkdial.c */ /* GTK - The GIMP Toolkit * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald @@ -14555,1082 +14476,1379 @@ void tictactoe_clear (Tictactoe *ttt); * Free Software Foundation, Inc., 59 Temple Place - Suite 330, * Boston, MA 02111-1307, USA. */ -#include "gtk/gtksignal.h" -#include "gtk/gtktable.h" -#include "gtk/gtktogglebutton.h" -#include "tictactoe.h" +#include +#include +#include +#include -enum { - TICTACTOE_SIGNAL, - LAST_SIGNAL -}; +#include "gtkdial.h" -static void tictactoe_class_init (TictactoeClass *klass); -static void tictactoe_init (Tictactoe *ttt); -static void tictactoe_toggle (GtkWidget *widget, Tictactoe *ttt); +#define SCROLL_DELAY_LENGTH 300 +#define DIAL_DEFAULT_SIZE 100 -static gint tictactoe_signals[LAST_SIGNAL] = { 0 }; +/* Forward declarations */ + +static void gtk_dial_class_init (GtkDialClass *klass); +static void gtk_dial_init (GtkDial *dial); +static void gtk_dial_destroy (GtkObject *object); +static void gtk_dial_realize (GtkWidget *widget); +static void gtk_dial_size_request (GtkWidget *widget, + GtkRequisition *requisition); +static void gtk_dial_size_allocate (GtkWidget *widget, + GtkAllocation *allocation); +static gint gtk_dial_expose (GtkWidget *widget, + GdkEventExpose *event); +static gint gtk_dial_button_press (GtkWidget *widget, + GdkEventButton *event); +static gint gtk_dial_button_release (GtkWidget *widget, + GdkEventButton *event); +static gint gtk_dial_motion_notify (GtkWidget *widget, + GdkEventMotion *event); +static gint gtk_dial_timer (GtkDial *dial); + +static void gtk_dial_update_mouse (GtkDial *dial, gint x, gint y); +static void gtk_dial_update (GtkDial *dial); +static void gtk_dial_adjustment_changed (GtkAdjustment *adjustment, + gpointer data); +static void gtk_dial_adjustment_value_changed (GtkAdjustment *adjustment, + gpointer data); + +/* Local data */ + +static GtkWidgetClass *parent_class = NULL; guint -tictactoe_get_type () +gtk_dial_get_type () { - static guint ttt_type = 0; + static guint dial_type = 0; - if (!ttt_type) + if (!dial_type) { - GtkTypeInfo ttt_info = + GtkTypeInfo dial_info = { - "Tictactoe", - sizeof (Tictactoe), - sizeof (TictactoeClass), - (GtkClassInitFunc) tictactoe_class_init, - (GtkObjectInitFunc) tictactoe_init, - (GtkArgSetFunc) NULL, - (GtkArgGetFunc) NULL + "GtkDial", + sizeof (GtkDial), + sizeof (GtkDialClass), + (GtkClassInitFunc) gtk_dial_class_init, + (GtkObjectInitFunc) gtk_dial_init, + (GtkArgSetFunc) NULL, + (GtkArgGetFunc) NULL, }; - ttt_type = gtk_type_unique (gtk_vbox_get_type (), &ttt_info); + dial_type = gtk_type_unique (gtk_widget_get_type (), &dial_info); } - return ttt_type; + return dial_type; } static void -tictactoe_class_init (TictactoeClass *class) +gtk_dial_class_init (GtkDialClass *class) { GtkObjectClass *object_class; + GtkWidgetClass *widget_class; + + object_class = (GtkObjectClass*) class; + widget_class = (GtkWidgetClass*) class; + + parent_class = gtk_type_class (gtk_widget_get_type ()); + + object_class->destroy = gtk_dial_destroy; + + widget_class->realize = gtk_dial_realize; + widget_class->expose_event = gtk_dial_expose; + widget_class->size_request = gtk_dial_size_request; + widget_class->size_allocate = gtk_dial_size_allocate; + widget_class->button_press_event = gtk_dial_button_press; + widget_class->button_release_event = gtk_dial_button_release; + widget_class->motion_notify_event = gtk_dial_motion_notify; +} + +static void +gtk_dial_init (GtkDial *dial) +{ + dial->button = 0; + dial->policy = GTK_UPDATE_CONTINUOUS; + dial->timer = 0; + dial->radius = 0; + dial->pointer_width = 0; + dial->angle = 0.0; + dial->old_value = 0.0; + dial->old_lower = 0.0; + dial->old_upper = 0.0; + dial->adjustment = NULL; +} + +GtkWidget* +gtk_dial_new (GtkAdjustment *adjustment) +{ + GtkDial *dial; + + dial = gtk_type_new (gtk_dial_get_type ()); + + if (!adjustment) + adjustment = (GtkAdjustment*) gtk_adjustment_new (0.0, 0.0, 0.0, 0.0, 0.0, 0.0); + + gtk_dial_set_adjustment (dial, adjustment); + + return GTK_WIDGET (dial); +} + +static void +gtk_dial_destroy (GtkObject *object) +{ + GtkDial *dial; - object_class = (GtkObjectClass*) class; - - tictactoe_signals[TICTACTOE_SIGNAL] = gtk_signal_new ("tictactoe", - GTK_RUN_FIRST, - object_class->type, - GTK_SIGNAL_OFFSET (TictactoeClass, tictactoe), - gtk_signal_default_marshaller, GTK_TYPE_NONE, 0); + g_return_if_fail (object != NULL); + g_return_if_fail (GTK_IS_DIAL (object)); + dial = GTK_DIAL (object); - gtk_object_class_add_signals (object_class, tictactoe_signals, LAST_SIGNAL); + if (dial->adjustment) + gtk_object_unref (GTK_OBJECT (dial->adjustment)); - class->tictactoe = NULL; + if (GTK_OBJECT_CLASS (parent_class)->destroy) + (* GTK_OBJECT_CLASS (parent_class)->destroy) (object); } -static void -tictactoe_init (Tictactoe *ttt) +GtkAdjustment* +gtk_dial_get_adjustment (GtkDial *dial) { - GtkWidget *table; - gint i,j; - - table = gtk_table_new (3, 3, TRUE); - gtk_container_add (GTK_CONTAINER(ttt), table); - gtk_widget_show (table); + g_return_val_if_fail (dial != NULL, NULL); + g_return_val_if_fail (GTK_IS_DIAL (dial), NULL); - for (i=0;i<3; i++) - for (j=0;j<3; j++) - { - ttt->buttons[i][j] = gtk_toggle_button_new (); - gtk_table_attach_defaults (GTK_TABLE(table), ttt->buttons[i][j], - i, i+1, j, j+1); - gtk_signal_connect (GTK_OBJECT (ttt->buttons[i][j]), "toggled", - GTK_SIGNAL_FUNC (tictactoe_toggle), ttt); - gtk_widget_set_usize (ttt->buttons[i][j], 20, 20); - gtk_widget_show (ttt->buttons[i][j]); - } + return dial->adjustment; } -GtkWidget* -tictactoe_new () +void +gtk_dial_set_update_policy (GtkDial *dial, + GtkUpdateType policy) { - return GTK_WIDGET ( gtk_type_new (tictactoe_get_type ())); + g_return_if_fail (dial != NULL); + g_return_if_fail (GTK_IS_DIAL (dial)); + + dial->policy = policy; } -void -tictactoe_clear (Tictactoe *ttt) +void +gtk_dial_set_adjustment (GtkDial *dial, + GtkAdjustment *adjustment) { - int i,j; + g_return_if_fail (dial != NULL); + g_return_if_fail (GTK_IS_DIAL (dial)); - for (i=0;i<3;i++) - for (j=0;j<3;j++) - { - gtk_signal_handler_block_by_data (GTK_OBJECT(ttt->buttons[i][j]), ttt); - gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (ttt->buttons[i][j]), - FALSE); - gtk_signal_handler_unblock_by_data (GTK_OBJECT(ttt->buttons[i][j]), ttt); - } + if (dial->adjustment) + { + gtk_signal_disconnect_by_data (GTK_OBJECT (dial->adjustment), (gpointer) dial); + gtk_object_unref (GTK_OBJECT (dial->adjustment)); + } + + dial->adjustment = adjustment; + gtk_object_ref (GTK_OBJECT (dial->adjustment)); + + gtk_signal_connect (GTK_OBJECT (adjustment), "changed", + (GtkSignalFunc) gtk_dial_adjustment_changed, + (gpointer) dial); + gtk_signal_connect (GTK_OBJECT (adjustment), "value_changed", + (GtkSignalFunc) gtk_dial_adjustment_value_changed, + (gpointer) dial); + + dial->old_value = adjustment->value; + dial->old_lower = adjustment->lower; + dial->old_upper = adjustment->upper; + + gtk_dial_update (dial); } static void -tictactoe_toggle (GtkWidget *widget, Tictactoe *ttt) +gtk_dial_realize (GtkWidget *widget) { - int i,k; + GtkDial *dial; + GdkWindowAttr attributes; + gint attributes_mask; - static int rwins[8][3] = { { 0, 0, 0 }, { 1, 1, 1 }, { 2, 2, 2 }, - { 0, 1, 2 }, { 0, 1, 2 }, { 0, 1, 2 }, - { 0, 1, 2 }, { 0, 1, 2 } }; - static int cwins[8][3] = { { 0, 1, 2 }, { 0, 1, 2 }, { 0, 1, 2 }, - { 0, 0, 0 }, { 1, 1, 1 }, { 2, 2, 2 }, - { 0, 1, 2 }, { 2, 1, 0 } }; + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_DIAL (widget)); - int success, found; + GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED); + dial = GTK_DIAL (widget); - for (k=0; k<8; k++) - { - success = TRUE; - found = FALSE; + attributes.x = widget->allocation.x; + attributes.y = widget->allocation.y; + attributes.width = widget->allocation.width; + attributes.height = widget->allocation.height; + attributes.wclass = GDK_INPUT_OUTPUT; + attributes.window_type = GDK_WINDOW_CHILD; + attributes.event_mask = gtk_widget_get_events (widget) | + GDK_EXPOSURE_MASK | GDK_BUTTON_PRESS_MASK | + GDK_BUTTON_RELEASE_MASK | GDK_POINTER_MOTION_MASK | + GDK_POINTER_MOTION_HINT_MASK; + attributes.visual = gtk_widget_get_visual (widget); + attributes.colormap = gtk_widget_get_colormap (widget); - for (i=0;i<3;i++) - { - success = success && - GTK_TOGGLE_BUTTON(ttt->buttons[rwins[k][i]][cwins[k][i]])->active; - found = found || - ttt->buttons[rwins[k][i]][cwins[k][i]] == widget; - } - - if (success && found) - { - gtk_signal_emit (GTK_OBJECT (ttt), - tictactoe_signals[TICTACTOE_SIGNAL]); - break; - } - } -} + attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP; + widget->window = gdk_window_new (widget->parent->window, &attributes, attributes_mask); -/* example-end */ - + widget->style = gtk_style_attach (widget->style, widget->window); - -ttt_test.c -

- -/* example-start tictactoe ttt_test.c */ + gdk_window_set_user_data (widget->window, widget); -#include -#include "tictactoe.h" + gtk_style_set_background (widget->style, widget->window, GTK_STATE_ACTIVE); +} -void -win (GtkWidget *widget, gpointer data) +static void +gtk_dial_size_request (GtkWidget *widget, + GtkRequisition *requisition) { - g_print ("Yay!\n"); - tictactoe_clear (TICTACTOE (widget)); + requisition->width = DIAL_DEFAULT_SIZE; + requisition->height = DIAL_DEFAULT_SIZE; } -int -main (int argc, char *argv[]) +static void +gtk_dial_size_allocate (GtkWidget *widget, + GtkAllocation *allocation) { - GtkWidget *window; - GtkWidget *ttt; - - gtk_init (&argc, &argv); + GtkDial *dial; - window = gtk_window_new (GTK_WINDOW_TOPLEVEL); - - gtk_window_set_title (GTK_WINDOW (window), "Aspect Frame"); - - gtk_signal_connect (GTK_OBJECT (window), "destroy", - GTK_SIGNAL_FUNC (gtk_exit), NULL); - - gtk_container_set_border_width (GTK_CONTAINER (window), 10); + g_return_if_fail (widget != NULL); + g_return_if_fail (GTK_IS_DIAL (widget)); + g_return_if_fail (allocation != NULL); - ttt = tictactoe_new (); - - gtk_container_add (GTK_CONTAINER (window), ttt); - gtk_widget_show (ttt); + widget->allocation = *allocation; + dial = GTK_DIAL (widget); - gtk_signal_connect (GTK_OBJECT (ttt), "tictactoe", - GTK_SIGNAL_FUNC (win), NULL); + if (GTK_WIDGET_REALIZED (widget)) + { - gtk_widget_show (window); - - gtk_main (); - - return 0; + gdk_window_move_resize (widget->window, + allocation->x, allocation->y, + allocation->width, allocation->height); + + } + dial->radius = MIN(allocation->width,allocation->height) * 0.45; + dial->pointer_width = dial->radius / 5; } -/* example-end */ - +static gint +gtk_dial_expose (GtkWidget *widget, + GdkEventExpose *event) +{ + GtkDial *dial; + GdkPoint points[3]; + gdouble s,c; + gdouble theta; + gint xc, yc; + gint tick_length; + gint i; - - GtkDial + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (GTK_IS_DIAL (widget), FALSE); + g_return_val_if_fail (event != NULL, FALSE); - - gtkdial.h -

- -/* example-start gtkdial gtkdial.h */ + if (event->count > 0) + return FALSE; + + dial = GTK_DIAL (widget); -/* GTK - The GIMP Toolkit - * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - */ -#ifndef __GTK_DIAL_H__ -#define __GTK_DIAL_H__ + gdk_window_clear_area (widget->window, + 0, 0, + widget->allocation.width, + widget->allocation.height); + + xc = widget->allocation.width/2; + yc = widget->allocation.height/2; + /* Draw ticks */ -#include -#include -#include + for (i=0; i<25; i++) + { + theta = (i*M_PI/18. - M_PI/6.); + s = sin(theta); + c = cos(theta); + tick_length = (i%6 == 0) ? dial->pointer_width : dial->pointer_width/2; + + gdk_draw_line (widget->window, + widget->style->fg_gc[widget->state], + xc + c*(dial->radius - tick_length), + yc - s*(dial->radius - tick_length), + xc + c*dial->radius, + yc - s*dial->radius); + } -#ifdef __cplusplus -extern "C" { -#endif /* __cplusplus */ + /* Draw pointer */ + s = sin(dial->angle); + c = cos(dial->angle); -#define GTK_DIAL(obj) GTK_CHECK_CAST (obj, gtk_dial_get_type (), GtkDial) -#define GTK_DIAL_CLASS(klass) GTK_CHECK_CLASS_CAST (klass, gtk_dial_get_type (), GtkDialClass) -#define GTK_IS_DIAL(obj) GTK_CHECK_TYPE (obj, gtk_dial_get_type ()) + points[0].x = xc + s*dial->pointer_width/2; + points[0].y = yc + c*dial->pointer_width/2; + points[1].x = xc + c*dial->radius; + points[1].y = yc - s*dial->radius; + points[2].x = xc - s*dial->pointer_width/2; + points[2].y = yc - c*dial->pointer_width/2; -typedef struct _GtkDial GtkDial; -typedef struct _GtkDialClass GtkDialClass; + gtk_draw_polygon (widget->style, + widget->window, + GTK_STATE_NORMAL, + GTK_SHADOW_OUT, + points, 3, + TRUE); + + return FALSE; +} -struct _GtkDial +static gint +gtk_dial_button_press (GtkWidget *widget, + GdkEventButton *event) { - GtkWidget widget; - - /* update policy (GTK_UPDATE_[CONTINUOUS/DELAYED/DISCONTINUOUS]) */ - guint policy : 2; + GtkDial *dial; + gint dx, dy; + double s, c; + double d_parallel; + double d_perpendicular; - /* Button currently pressed or 0 if none */ - guint8 button; + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (GTK_IS_DIAL (widget), FALSE); + g_return_val_if_fail (event != NULL, FALSE); - /* Dimensions of dial components */ - gint radius; - gint pointer_width; + dial = GTK_DIAL (widget); - /* ID of update timer, or 0 if none */ - guint32 timer; + /* Determine if button press was within pointer region - we + do this by computing the parallel and perpendicular distance of + the point where the mouse was pressed from the line passing through + the pointer */ + + dx = event->x - widget->allocation.width / 2; + dy = widget->allocation.height / 2 - event->y; + + s = sin(dial->angle); + c = cos(dial->angle); + + d_parallel = s*dy + c*dx; + d_perpendicular = fabs(s*dx - c*dy); + + if (!dial->button && + (d_perpendicular < dial->pointer_width/2) && + (d_parallel > - dial->pointer_width)) + { + gtk_grab_add (widget); - /* Current angle */ - gfloat angle; + dial->button = event->button; - /* Old values from adjustment stored so we know when something changes */ - gfloat old_value; - gfloat old_lower; - gfloat old_upper; + gtk_dial_update_mouse (dial, event->x, event->y); + } - /* The adjustment object that stores the data for this dial */ - GtkAdjustment *adjustment; -}; + return FALSE; +} -struct _GtkDialClass +static gint +gtk_dial_button_release (GtkWidget *widget, + GdkEventButton *event) { - GtkWidgetClass parent_class; -}; + GtkDial *dial; + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (GTK_IS_DIAL (widget), FALSE); + g_return_val_if_fail (event != NULL, FALSE); -GtkWidget* gtk_dial_new (GtkAdjustment *adjustment); -guint gtk_dial_get_type (void); -GtkAdjustment* gtk_dial_get_adjustment (GtkDial *dial); -void gtk_dial_set_update_policy (GtkDial *dial, - GtkUpdateType policy); + dial = GTK_DIAL (widget); -void gtk_dial_set_adjustment (GtkDial *dial, - GtkAdjustment *adjustment); -#ifdef __cplusplus -} -#endif /* __cplusplus */ + if (dial->button == event->button) + { + gtk_grab_remove (widget); + dial->button = 0; -#endif /* __GTK_DIAL_H__ */ -/* example-end */ - + if (dial->policy == GTK_UPDATE_DELAYED) + gtk_timeout_remove (dial->timer); + + if ((dial->policy != GTK_UPDATE_CONTINUOUS) && + (dial->old_value != dial->adjustment->value)) + gtk_signal_emit_by_name (GTK_OBJECT (dial->adjustment), "value_changed"); + } - - gtkdial.c -

- -/* example-start gtkdial gtkdial.c */ + return FALSE; +} -/* GTK - The GIMP Toolkit - * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. - */ -#include -#include -#include -#include +static gint +gtk_dial_motion_notify (GtkWidget *widget, + GdkEventMotion *event) +{ + GtkDial *dial; + GdkModifierType mods; + gint x, y, mask; -#include "gtkdial.h" + g_return_val_if_fail (widget != NULL, FALSE); + g_return_val_if_fail (GTK_IS_DIAL (widget), FALSE); + g_return_val_if_fail (event != NULL, FALSE); -#define SCROLL_DELAY_LENGTH 300 -#define DIAL_DEFAULT_SIZE 100 + dial = GTK_DIAL (widget); -/* Forward declarations */ + if (dial->button != 0) + { + x = event->x; + y = event->y; -static void gtk_dial_class_init (GtkDialClass *klass); -static void gtk_dial_init (GtkDial *dial); -static void gtk_dial_destroy (GtkObject *object); -static void gtk_dial_realize (GtkWidget *widget); -static void gtk_dial_size_request (GtkWidget *widget, - GtkRequisition *requisition); -static void gtk_dial_size_allocate (GtkWidget *widget, - GtkAllocation *allocation); -static gint gtk_dial_expose (GtkWidget *widget, - GdkEventExpose *event); -static gint gtk_dial_button_press (GtkWidget *widget, - GdkEventButton *event); -static gint gtk_dial_button_release (GtkWidget *widget, - GdkEventButton *event); -static gint gtk_dial_motion_notify (GtkWidget *widget, - GdkEventMotion *event); -static gint gtk_dial_timer (GtkDial *dial); + if (event->is_hint || (event->window != widget->window)) + gdk_window_get_pointer (widget->window, &x, &y, &mods); -static void gtk_dial_update_mouse (GtkDial *dial, gint x, gint y); -static void gtk_dial_update (GtkDial *dial); -static void gtk_dial_adjustment_changed (GtkAdjustment *adjustment, - gpointer data); -static void gtk_dial_adjustment_value_changed (GtkAdjustment *adjustment, - gpointer data); + switch (dial->button) + { + case 1: + mask = GDK_BUTTON1_MASK; + break; + case 2: + mask = GDK_BUTTON2_MASK; + break; + case 3: + mask = GDK_BUTTON3_MASK; + break; + default: + mask = 0; + break; + } -/* Local data */ + if (mods & mask) + gtk_dial_update_mouse (dial, x,y); + } -static GtkWidgetClass *parent_class = NULL; + return FALSE; +} -guint -gtk_dial_get_type () +static gint +gtk_dial_timer (GtkDial *dial) { - static guint dial_type = 0; - - if (!dial_type) - { - GtkTypeInfo dial_info = - { - "GtkDial", - sizeof (GtkDial), - sizeof (GtkDialClass), - (GtkClassInitFunc) gtk_dial_class_init, - (GtkObjectInitFunc) gtk_dial_init, - (GtkArgSetFunc) NULL, - (GtkArgGetFunc) NULL, - }; + g_return_val_if_fail (dial != NULL, FALSE); + g_return_val_if_fail (GTK_IS_DIAL (dial), FALSE); - dial_type = gtk_type_unique (gtk_widget_get_type (), &dial_info); - } + if (dial->policy == GTK_UPDATE_DELAYED) + gtk_signal_emit_by_name (GTK_OBJECT (dial->adjustment), "value_changed"); - return dial_type; + return FALSE; } static void -gtk_dial_class_init (GtkDialClass *class) +gtk_dial_update_mouse (GtkDial *dial, gint x, gint y) { - GtkObjectClass *object_class; - GtkWidgetClass *widget_class; + gint xc, yc; + gfloat old_value; - object_class = (GtkObjectClass*) class; - widget_class = (GtkWidgetClass*) class; + g_return_if_fail (dial != NULL); + g_return_if_fail (GTK_IS_DIAL (dial)); - parent_class = gtk_type_class (gtk_widget_get_type ()); + xc = GTK_WIDGET(dial)->allocation.width / 2; + yc = GTK_WIDGET(dial)->allocation.height / 2; - object_class->destroy = gtk_dial_destroy; + old_value = dial->adjustment->value; + dial->angle = atan2(yc-y, x-xc); - widget_class->realize = gtk_dial_realize; - widget_class->expose_event = gtk_dial_expose; - widget_class->size_request = gtk_dial_size_request; - widget_class->size_allocate = gtk_dial_size_allocate; - widget_class->button_press_event = gtk_dial_button_press; - widget_class->button_release_event = gtk_dial_button_release; - widget_class->motion_notify_event = gtk_dial_motion_notify; -} + if (dial->angle < -M_PI/2.) + dial->angle += 2*M_PI; -static void -gtk_dial_init (GtkDial *dial) -{ - dial->button = 0; - dial->policy = GTK_UPDATE_CONTINUOUS; - dial->timer = 0; - dial->radius = 0; - dial->pointer_width = 0; - dial->angle = 0.0; - dial->old_value = 0.0; - dial->old_lower = 0.0; - dial->old_upper = 0.0; - dial->adjustment = NULL; -} + if (dial->angle < -M_PI/6) + dial->angle = -M_PI/6; -GtkWidget* -gtk_dial_new (GtkAdjustment *adjustment) -{ - GtkDial *dial; + if (dial->angle > 7.*M_PI/6.) + dial->angle = 7.*M_PI/6.; - dial = gtk_type_new (gtk_dial_get_type ()); + dial->adjustment->value = dial->adjustment->lower + (7.*M_PI/6 - dial->angle) * + (dial->adjustment->upper - dial->adjustment->lower) / (4.*M_PI/3.); - if (!adjustment) - adjustment = (GtkAdjustment*) gtk_adjustment_new (0.0, 0.0, 0.0, 0.0, 0.0, 0.0); + if (dial->adjustment->value != old_value) + { + if (dial->policy == GTK_UPDATE_CONTINUOUS) + { + gtk_signal_emit_by_name (GTK_OBJECT (dial->adjustment), "value_changed"); + } + else + { + gtk_widget_draw (GTK_WIDGET(dial), NULL); - gtk_dial_set_adjustment (dial, adjustment); + if (dial->policy == GTK_UPDATE_DELAYED) + { + if (dial->timer) + gtk_timeout_remove (dial->timer); - return GTK_WIDGET (dial); + dial->timer = gtk_timeout_add (SCROLL_DELAY_LENGTH, + (GtkFunction) gtk_dial_timer, + (gpointer) dial); + } + } + } } static void -gtk_dial_destroy (GtkObject *object) +gtk_dial_update (GtkDial *dial) { - GtkDial *dial; - - g_return_if_fail (object != NULL); - g_return_if_fail (GTK_IS_DIAL (object)); + gfloat new_value; + + g_return_if_fail (dial != NULL); + g_return_if_fail (GTK_IS_DIAL (dial)); - dial = GTK_DIAL (object); + new_value = dial->adjustment->value; + + if (new_value < dial->adjustment->lower) + new_value = dial->adjustment->lower; - if (dial->adjustment) - gtk_object_unref (GTK_OBJECT (dial->adjustment)); + if (new_value > dial->adjustment->upper) + new_value = dial->adjustment->upper; - if (GTK_OBJECT_CLASS (parent_class)->destroy) - (* GTK_OBJECT_CLASS (parent_class)->destroy) (object); -} + if (new_value != dial->adjustment->value) + { + dial->adjustment->value = new_value; + gtk_signal_emit_by_name (GTK_OBJECT (dial->adjustment), "value_changed"); + } -GtkAdjustment* -gtk_dial_get_adjustment (GtkDial *dial) -{ - g_return_val_if_fail (dial != NULL, NULL); - g_return_val_if_fail (GTK_IS_DIAL (dial), NULL); + dial->angle = 7.*M_PI/6. - (new_value - dial->adjustment->lower) * 4.*M_PI/3. / + (dial->adjustment->upper - dial->adjustment->lower); - return dial->adjustment; + gtk_widget_draw (GTK_WIDGET(dial), NULL); } -void -gtk_dial_set_update_policy (GtkDial *dial, - GtkUpdateType policy) +static void +gtk_dial_adjustment_changed (GtkAdjustment *adjustment, + gpointer data) { - g_return_if_fail (dial != NULL); - g_return_if_fail (GTK_IS_DIAL (dial)); + GtkDial *dial; - dial->policy = policy; -} + g_return_if_fail (adjustment != NULL); + g_return_if_fail (data != NULL); -void -gtk_dial_set_adjustment (GtkDial *dial, - GtkAdjustment *adjustment) -{ - g_return_if_fail (dial != NULL); - g_return_if_fail (GTK_IS_DIAL (dial)); + dial = GTK_DIAL (data); - if (dial->adjustment) + if ((dial->old_value != adjustment->value) || + (dial->old_lower != adjustment->lower) || + (dial->old_upper != adjustment->upper)) { - gtk_signal_disconnect_by_data (GTK_OBJECT (dial->adjustment), (gpointer) dial); - gtk_object_unref (GTK_OBJECT (dial->adjustment)); - } - - dial->adjustment = adjustment; - gtk_object_ref (GTK_OBJECT (dial->adjustment)); - - gtk_signal_connect (GTK_OBJECT (adjustment), "changed", - (GtkSignalFunc) gtk_dial_adjustment_changed, - (gpointer) dial); - gtk_signal_connect (GTK_OBJECT (adjustment), "value_changed", - (GtkSignalFunc) gtk_dial_adjustment_value_changed, - (gpointer) dial); - - dial->old_value = adjustment->value; - dial->old_lower = adjustment->lower; - dial->old_upper = adjustment->upper; + gtk_dial_update (dial); - gtk_dial_update (dial); + dial->old_value = adjustment->value; + dial->old_lower = adjustment->lower; + dial->old_upper = adjustment->upper; + } } static void -gtk_dial_realize (GtkWidget *widget) +gtk_dial_adjustment_value_changed (GtkAdjustment *adjustment, + gpointer data) { GtkDial *dial; - GdkWindowAttr attributes; - gint attributes_mask; - g_return_if_fail (widget != NULL); - g_return_if_fail (GTK_IS_DIAL (widget)); + g_return_if_fail (adjustment != NULL); + g_return_if_fail (data != NULL); - GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED); - dial = GTK_DIAL (widget); + dial = GTK_DIAL (data); - attributes.x = widget->allocation.x; - attributes.y = widget->allocation.y; - attributes.width = widget->allocation.width; - attributes.height = widget->allocation.height; - attributes.wclass = GDK_INPUT_OUTPUT; - attributes.window_type = GDK_WINDOW_CHILD; - attributes.event_mask = gtk_widget_get_events (widget) | - GDK_EXPOSURE_MASK | GDK_BUTTON_PRESS_MASK | - GDK_BUTTON_RELEASE_MASK | GDK_POINTER_MOTION_MASK | - GDK_POINTER_MOTION_HINT_MASK; - attributes.visual = gtk_widget_get_visual (widget); - attributes.colormap = gtk_widget_get_colormap (widget); + if (dial->old_value != adjustment->value) + { + gtk_dial_update (dial); - attributes_mask = GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP; - widget->window = gdk_window_new (widget->parent->window, &attributes, attributes_mask); + dial->old_value = adjustment->value; + } +} +/* example-end */ + - widget->style = gtk_style_attach (widget->style, widget->window); + + Scribble +

+ +/* example-start scribble-simple scribble-simple.c */ - gdk_window_set_user_data (widget->window, widget); +/* GTK - The GIMP Toolkit + * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Library General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Library General Public License for more details. + * + * You should have received a copy of the GNU Library General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 59 Temple Place - Suite 330, + * Boston, MA 02111-1307, USA. + */ - gtk_style_set_background (widget->style, widget->window, GTK_STATE_ACTIVE); +#include + +/* Backing pixmap for drawing area */ +static GdkPixmap *pixmap = NULL; + +/* Create a new backing pixmap of the appropriate size */ +static gint +configure_event (GtkWidget *widget, GdkEventConfigure *event) +{ + if (pixmap) + gdk_pixmap_unref(pixmap); + + pixmap = gdk_pixmap_new(widget->window, + widget->allocation.width, + widget->allocation.height, + -1); + gdk_draw_rectangle (pixmap, + widget->style->white_gc, + TRUE, + 0, 0, + widget->allocation.width, + widget->allocation.height); + + return TRUE; } -static void -gtk_dial_size_request (GtkWidget *widget, - GtkRequisition *requisition) +/* Redraw the screen from the backing pixmap */ +static gint +expose_event (GtkWidget *widget, GdkEventExpose *event) { - requisition->width = DIAL_DEFAULT_SIZE; - requisition->height = DIAL_DEFAULT_SIZE; + gdk_draw_pixmap(widget->window, + widget->style->fg_gc[GTK_WIDGET_STATE (widget)], + pixmap, + event->area.x, event->area.y, + event->area.x, event->area.y, + event->area.width, event->area.height); + + return FALSE; } +/* Draw a rectangle on the screen */ static void -gtk_dial_size_allocate (GtkWidget *widget, - GtkAllocation *allocation) +draw_brush (GtkWidget *widget, gdouble x, gdouble y) { - GtkDial *dial; + GdkRectangle update_rect; - g_return_if_fail (widget != NULL); - g_return_if_fail (GTK_IS_DIAL (widget)); - g_return_if_fail (allocation != NULL); + update_rect.x = x - 5; + update_rect.y = y - 5; + update_rect.width = 10; + update_rect.height = 10; + gdk_draw_rectangle (pixmap, + widget->style->black_gc, + TRUE, + update_rect.x, update_rect.y, + update_rect.width, update_rect.height); + gtk_widget_draw (widget, &update_rect); +} - widget->allocation = *allocation; - dial = GTK_DIAL (widget); +static gint +button_press_event (GtkWidget *widget, GdkEventButton *event) +{ + if (event->button == 1 && pixmap != NULL) + draw_brush (widget, event->x, event->y); - if (GTK_WIDGET_REALIZED (widget)) - { + return TRUE; +} - gdk_window_move_resize (widget->window, - allocation->x, allocation->y, - allocation->width, allocation->height); +static gint +motion_notify_event (GtkWidget *widget, GdkEventMotion *event) +{ + int x, y; + GdkModifierType state; + if (event->is_hint) + gdk_window_get_pointer (event->window, &x, &y, &state); + else + { + x = event->x; + y = event->y; + state = event->state; } - dial->radius = MIN(allocation->width,allocation->height) * 0.45; - dial->pointer_width = dial->radius / 5; + + if (state & GDK_BUTTON1_MASK && pixmap != NULL) + draw_brush (widget, x, y); + + return TRUE; } -static gint -gtk_dial_expose (GtkWidget *widget, - GdkEventExpose *event) +void +quit () { - GtkDial *dial; - GdkPoint points[3]; - gdouble s,c; - gdouble theta; - gint xc, yc; - gint tick_length; - gint i; + gtk_exit (0); +} - g_return_val_if_fail (widget != NULL, FALSE); - g_return_val_if_fail (GTK_IS_DIAL (widget), FALSE); - g_return_val_if_fail (event != NULL, FALSE); +int +main (int argc, char *argv[]) +{ + GtkWidget *window; + GtkWidget *drawing_area; + GtkWidget *vbox; - if (event->count > 0) - return FALSE; - - dial = GTK_DIAL (widget); + GtkWidget *button; - gdk_window_clear_area (widget->window, - 0, 0, - widget->allocation.width, - widget->allocation.height); + gtk_init (&argc, &argv); - xc = widget->allocation.width/2; - yc = widget->allocation.height/2; + window = gtk_window_new (GTK_WINDOW_TOPLEVEL); + gtk_widget_set_name (window, "Test Input"); - /* Draw ticks */ + vbox = gtk_vbox_new (FALSE, 0); + gtk_container_add (GTK_CONTAINER (window), vbox); + gtk_widget_show (vbox); - for (i=0; i<25; i++) - { - theta = (i*M_PI/18. - M_PI/6.); - s = sin(theta); - c = cos(theta); + gtk_signal_connect (GTK_OBJECT (window), "destroy", + GTK_SIGNAL_FUNC (quit), NULL); - tick_length = (i%6 == 0) ? dial->pointer_width : dial->pointer_width/2; - - gdk_draw_line (widget->window, - widget->style->fg_gc[widget->state], - xc + c*(dial->radius - tick_length), - yc - s*(dial->radius - tick_length), - xc + c*dial->radius, - yc - s*dial->radius); - } + /* Create the drawing area */ - /* Draw pointer */ + drawing_area = gtk_drawing_area_new (); + gtk_drawing_area_size (GTK_DRAWING_AREA (drawing_area), 200, 200); + gtk_box_pack_start (GTK_BOX (vbox), drawing_area, TRUE, TRUE, 0); - s = sin(dial->angle); - c = cos(dial->angle); + gtk_widget_show (drawing_area); + /* Signals used to handle backing pixmap */ - points[0].x = xc + s*dial->pointer_width/2; - points[0].y = yc + c*dial->pointer_width/2; - points[1].x = xc + c*dial->radius; - points[1].y = yc - s*dial->radius; - points[2].x = xc - s*dial->pointer_width/2; - points[2].y = yc - c*dial->pointer_width/2; + gtk_signal_connect (GTK_OBJECT (drawing_area), "expose_event", + (GtkSignalFunc) expose_event, NULL); + gtk_signal_connect (GTK_OBJECT(drawing_area),"configure_event", + (GtkSignalFunc) configure_event, NULL); - gtk_draw_polygon (widget->style, - widget->window, - GTK_STATE_NORMAL, - GTK_SHADOW_OUT, - points, 3, - TRUE); - - return FALSE; -} + /* Event signals */ -static gint -gtk_dial_button_press (GtkWidget *widget, - GdkEventButton *event) -{ - GtkDial *dial; - gint dx, dy; - double s, c; - double d_parallel; - double d_perpendicular; + gtk_signal_connect (GTK_OBJECT (drawing_area), "motion_notify_event", + (GtkSignalFunc) motion_notify_event, NULL); + gtk_signal_connect (GTK_OBJECT (drawing_area), "button_press_event", + (GtkSignalFunc) button_press_event, NULL); - g_return_val_if_fail (widget != NULL, FALSE); - g_return_val_if_fail (GTK_IS_DIAL (widget), FALSE); - g_return_val_if_fail (event != NULL, FALSE); + gtk_widget_set_events (drawing_area, GDK_EXPOSURE_MASK + | GDK_LEAVE_NOTIFY_MASK + | GDK_BUTTON_PRESS_MASK + | GDK_POINTER_MOTION_MASK + | GDK_POINTER_MOTION_HINT_MASK); - dial = GTK_DIAL (widget); + /* .. And a quit button */ + button = gtk_button_new_with_label ("Quit"); + gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0); - /* Determine if button press was within pointer region - we - do this by computing the parallel and perpendicular distance of - the point where the mouse was pressed from the line passing through - the pointer */ - - dx = event->x - widget->allocation.width / 2; - dy = widget->allocation.height / 2 - event->y; - - s = sin(dial->angle); - c = cos(dial->angle); - - d_parallel = s*dy + c*dx; - d_perpendicular = fabs(s*dx - c*dy); - - if (!dial->button && - (d_perpendicular < dial->pointer_width/2) && - (d_parallel > - dial->pointer_width)) - { - gtk_grab_add (widget); + gtk_signal_connect_object (GTK_OBJECT (button), "clicked", + GTK_SIGNAL_FUNC (gtk_widget_destroy), + GTK_OBJECT (window)); + gtk_widget_show (button); - dial->button = event->button; + gtk_widget_show (window); - gtk_dial_update_mouse (dial, event->x, event->y); - } + gtk_main (); - return FALSE; + return 0; } +/* example-end */ + -static gint -gtk_dial_button_release (GtkWidget *widget, - GdkEventButton *event) + + List Widget + +

+NOTE: The GtkList widget has been superseded by the GtkCList +widget. It is detailed here just for completeness. + +The GtkList widget is designed to act as a vertical container for +widgets that should be of the type GtkListItem. + +A GtkList widget has its own window to receive events and its own +background color which is usually white. As it is directly derived +from a GtkContainer it can be treated as such by using the +GTK_CONTAINER(List) macro, see the GtkContainer widget for more on +this. One should already be familiar with the usage of a GList and +its related functions g_list_*() to be able to use the GtkList widget +to it full extent. + +There is one field inside the structure definition of the GtkList +widget that will be of greater interest to us, this is: + + +struct _GtkList { - GtkDial *dial; + ... + GList *selection; + guint selection_mode; + ... +}; + - g_return_val_if_fail (widget != NULL, FALSE); - g_return_val_if_fail (GTK_IS_DIAL (widget), FALSE); - g_return_val_if_fail (event != NULL, FALSE); +The selection field of a GtkList points to a linked list of all items +that are currently selected, or NULL if the selection is empty. So to +learn about the current selection we read the GTK_LIST()->selection +field, but do not modify it since the internal fields are maintained +by the gtk_list_*() functions. - dial = GTK_DIAL (widget); +The selection_mode of the GtkList determines the selection facilities +of a GtkList and therefore the contents of the GTK_LIST()->selection +field. The selection_mode may be one of the following: - if (dial->button == event->button) - { - gtk_grab_remove (widget); + + GTK_SELECTION_SINGLE - The selection is either NULL + or contains a GList pointer + for a single selected item. - dial->button = 0; + GTK_SELECTION_BROWSE - The selection is NULL if the list + contains no widgets or insensitive + ones only, otherwise it contains + a GList pointer for one GList + structure, and therefore exactly + one list item. - if (dial->policy == GTK_UPDATE_DELAYED) - gtk_timeout_remove (dial->timer); - - if ((dial->policy != GTK_UPDATE_CONTINUOUS) && - (dial->old_value != dial->adjustment->value)) - gtk_signal_emit_by_name (GTK_OBJECT (dial->adjustment), "value_changed"); - } + GTK_SELECTION_MULTIPLE - The selection is NULL if no list + items are selected or a GList pointer + for the first selected item. That + in turn points to a GList structure + for the second selected item and so + on. - return FALSE; -} + GTK_SELECTION_EXTENDED - The selection is always NULL. + -static gint -gtk_dial_motion_notify (GtkWidget *widget, - GdkEventMotion *event) -{ - GtkDial *dial; - GdkModifierType mods; - gint x, y, mask; +The default is GTK_SELECTION_MULTIPLE. - g_return_val_if_fail (widget != NULL, FALSE); - g_return_val_if_fail (GTK_IS_DIAL (widget), FALSE); - g_return_val_if_fail (event != NULL, FALSE); + + Signals +

+ +void selection_changed( GtkList *list ); + - dial = GTK_DIAL (widget); +This signal will be invoked whenever the selection field of a GtkList +has changed. This happens when a child of the GtkList got selected or +deselected. - if (dial->button != 0) - { - x = event->x; - y = event->y; + +void select_child( GtkList *list, + GtkWidget *child); + - if (event->is_hint || (event->window != widget->window)) - gdk_window_get_pointer (widget->window, &x, &y, &mods); +This signal is invoked when a child of the GtkList is about to get +selected. This happens mainly on calls to gtk_list_select_item(), +gtk_list_select_child(), button presses and sometimes indirectly +triggered on some else occasions where children get added to or +removed from the GtkList. - switch (dial->button) - { - case 1: - mask = GDK_BUTTON1_MASK; - break; - case 2: - mask = GDK_BUTTON2_MASK; - break; - case 3: - mask = GDK_BUTTON3_MASK; - break; - default: - mask = 0; - break; - } + +void unselect_child( GtkList *list, + GtkWidget *child ); + - if (mods & mask) - gtk_dial_update_mouse (dial, x,y); - } +This signal is invoked when a child of the GtkList is about to get +deselected. This happens mainly on calls to gtk_list_unselect_item(), +gtk_list_unselect_child(), button presses and sometimes indirectly +triggered on some else occasions where children get added to or +removed from the GtkList. - return FALSE; -} + + Functions +

+ +guint gtk_list_get_type( void ); + -static gint -gtk_dial_timer (GtkDial *dial) -{ - g_return_val_if_fail (dial != NULL, FALSE); - g_return_val_if_fail (GTK_IS_DIAL (dial), FALSE); +Returns the `GtkList' type identifier. - if (dial->policy == GTK_UPDATE_DELAYED) - gtk_signal_emit_by_name (GTK_OBJECT (dial->adjustment), "value_changed"); + +GtkWidget *gtk_list_new( void ); + - return FALSE; -} +Create a new GtkList object. The new widget is returned as a pointer +to a GtkWidget object. NULL is returned on failure. -static void -gtk_dial_update_mouse (GtkDial *dial, gint x, gint y) -{ - gint xc, yc; - gfloat old_value; + +void gtk_list_insert_items( GtkList *list, + GList *items, + gint position ); + - g_return_if_fail (dial != NULL); - g_return_if_fail (GTK_IS_DIAL (dial)); +Insert list items into the list, starting at allocation.width / 2; - yc = GTK_WIDGET(dial)->allocation.height / 2; + +void gtk_list_append_items( GtkList *list, + GList *items); + - old_value = dial->adjustment->value; - dial->angle = atan2(yc-y, x-xc); +Insert list items just like gtk_list_insert_items() at the end of the +list. The GList nodes of angle < -M_PI/2.) - dial->angle += 2*M_PI; + +void gtk_list_prepend_items( GtkList *list, + GList *items); + - if (dial->angle < -M_PI/6) - dial->angle = -M_PI/6; +Insert list items just like gtk_list_insert_items() at the very +beginning of the list. The GList nodes of angle > 7.*M_PI/6.) - dial->angle = 7.*M_PI/6.; + +void gtk_list_remove_items( GtkList *list, + GList *items); + - dial->adjustment->value = dial->adjustment->lower + (7.*M_PI/6 - dial->angle) * - (dial->adjustment->upper - dial->adjustment->lower) / (4.*M_PI/3.); +Remove list items from the list. adjustment->value != old_value) - { - if (dial->policy == GTK_UPDATE_CONTINUOUS) - { - gtk_signal_emit_by_name (GTK_OBJECT (dial->adjustment), "value_changed"); - } - else - { - gtk_widget_draw (GTK_WIDGET(dial), NULL); + +void gtk_list_clear_items( GtkList *list, + gint start, + gint end ); + - if (dial->policy == GTK_UPDATE_DELAYED) - { - if (dial->timer) - gtk_timeout_remove (dial->timer); +Remove and destroy list items from the list. A widget is affected if +its current position within the list is in the range specified by +timer = gtk_timeout_add (SCROLL_DELAY_LENGTH, - (GtkFunction) gtk_dial_timer, - (gpointer) dial); - } - } - } -} + +void gtk_list_select_item( GtkList *list, + gint item ); + -static void -gtk_dial_update (GtkDial *dial) -{ - gfloat new_value; - - g_return_if_fail (dial != NULL); - g_return_if_fail (GTK_IS_DIAL (dial)); +Invoke the select_child signal for a list item specified through its +current position within the list. - new_value = dial->adjustment->value; - - if (new_value < dial->adjustment->lower) - new_value = dial->adjustment->lower; + +void gtk_list_unselect_item( GtkList *list, + gint item); + - if (new_value > dial->adjustment->upper) - new_value = dial->adjustment->upper; +Invoke the unselect_child signal for a list item specified through its +current position within the list. - if (new_value != dial->adjustment->value) - { - dial->adjustment->value = new_value; - gtk_signal_emit_by_name (GTK_OBJECT (dial->adjustment), "value_changed"); - } + +void gtk_list_select_child( GtkList *list, + GtkWidget *child); + - dial->angle = 7.*M_PI/6. - (new_value - dial->adjustment->lower) * 4.*M_PI/3. / - (dial->adjustment->upper - dial->adjustment->lower); +Invoke the select_child signal for the specified child. - gtk_widget_draw (GTK_WIDGET(dial), NULL); -} + +void gtk_list_unselect_child( GtkList *list, + GtkWidget *child); + -static void -gtk_dial_adjustment_changed (GtkAdjustment *adjustment, - gpointer data) -{ - GtkDial *dial; +Invoke the unselect_child signal for the specified child. - g_return_if_fail (adjustment != NULL); - g_return_if_fail (data != NULL); + +gint gtk_list_child_position( GtkList *list, + GtkWidget *child); + - dial = GTK_DIAL (data); +Return the position of old_value != adjustment->value) || - (dial->old_lower != adjustment->lower) || - (dial->old_upper != adjustment->upper)) - { - gtk_dial_update (dial); + +void gtk_list_set_selection_mode( GtkList *list, + GtkSelectionMode mode ); + - dial->old_value = adjustment->value; - dial->old_lower = adjustment->lower; - dial->old_upper = adjustment->upper; - } -} +Set the selection mode MODE which can be of GTK_SELECTION_SINGLE, +GTK_SELECTION_BROWSE, GTK_SELECTION_MULTIPLE or +GTK_SELECTION_EXTENDED. -static void -gtk_dial_adjustment_value_changed (GtkAdjustment *adjustment, - gpointer data) -{ - GtkDial *dial; + +GtkList *GTK_LIST( gpointer obj ); + - g_return_if_fail (adjustment != NULL); - g_return_if_fail (data != NULL); +Cast a generic pointer to `GtkList *'. *Note Standard Macros::, for +more info. - dial = GTK_DIAL (data); + +GtkListClass *GTK_LIST_CLASS( gpointer class); + - if (dial->old_value != adjustment->value) - { - gtk_dial_update (dial); +Cast a generic pointer to `GtkListClass*'. *Note Standard Macros::, +for more info. - dial->old_value = adjustment->value; - } -} -/* example-end */ + +gint GTK_IS_LIST( gpointer obj); +Determine if a generic pointer refers to a `GtkList' object. *Note +Standard Macros::, for more info. + - Scribble + Example

+Following is an example program that will print out the changes of the +selection of a GtkList, and lets you "arrest" list items into a prison +by selecting them with the rightmost mouse button. + -/* example-start scribble-simple scribble-simple.c */ +/* example-start list list.c */ -/* GTK - The GIMP Toolkit - * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Library General Public - * License as published by the Free Software Foundation; either - * version 2 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Library General Public License for more details. - * - * You should have received a copy of the GNU Library General Public - * License along with this library; if not, write to the - * Free Software Foundation, Inc., 59 Temple Place - Suite 330, - * Boston, MA 02111-1307, USA. +/* Include the gtk+ header files + * Include stdio.h, we need that for the printf() function */ +#include +#include -#include - -/* Backing pixmap for drawing area */ -static GdkPixmap *pixmap = NULL; +/* This is our data identification string to store + * data in list items + */ +const gchar *list_item_data_key="list_item_data"; -/* Create a new backing pixmap of the appropriate size */ -static gint -configure_event (GtkWidget *widget, GdkEventConfigure *event) -{ - if (pixmap) - gdk_pixmap_unref(pixmap); - pixmap = gdk_pixmap_new(widget->window, - widget->allocation.width, - widget->allocation.height, - -1); - gdk_draw_rectangle (pixmap, - widget->style->white_gc, - TRUE, - 0, 0, - widget->allocation.width, - widget->allocation.height); +/* prototypes for signal handler that we are going to connect + * to the GtkList widget + */ +static void sigh_print_selection( GtkWidget *gtklist, + gpointer func_data); - return TRUE; -} +static void sigh_button_event( GtkWidget *gtklist, + GdkEventButton *event, + GtkWidget *frame ); -/* Redraw the screen from the backing pixmap */ -static gint -expose_event (GtkWidget *widget, GdkEventExpose *event) -{ - gdk_draw_pixmap(widget->window, - widget->style->fg_gc[GTK_WIDGET_STATE (widget)], - pixmap, - event->area.x, event->area.y, - event->area.x, event->area.y, - event->area.width, event->area.height); - return FALSE; -} +/* Main function to set up the user interface */ -/* Draw a rectangle on the screen */ -static void -draw_brush (GtkWidget *widget, gdouble x, gdouble y) -{ - GdkRectangle update_rect; +gint main (int argc, + gchar *argv[]) +{ + GtkWidget *separator; + GtkWidget *window; + GtkWidget *vbox; + GtkWidget *scrolled_window; + GtkWidget *frame; + GtkWidget *gtklist; + GtkWidget *button; + GtkWidget *list_item; + GList *dlist; + guint i; + gchar buffer[64]; + + + /* Initialize gtk+ (and subsequently gdk) */ - update_rect.x = x - 5; - update_rect.y = y - 5; - update_rect.width = 10; - update_rect.height = 10; - gdk_draw_rectangle (pixmap, - widget->style->black_gc, - TRUE, - update_rect.x, update_rect.y, - update_rect.width, update_rect.height); - gtk_widget_draw (widget, &update_rect); + gtk_init(&argc, &argv); + + + /* Create a window to put all the widgets in + * connect gtk_main_quit() to the "destroy" event of + * the window to handle window manager close-window-events + */ + window=gtk_window_new(GTK_WINDOW_TOPLEVEL); + gtk_window_set_title(GTK_WINDOW(window), "GtkList Example"); + gtk_signal_connect(GTK_OBJECT(window), + "destroy", + GTK_SIGNAL_FUNC(gtk_main_quit), + NULL); + + + /* Inside the window we need a box to arrange the widgets + * vertically */ + vbox=gtk_vbox_new(FALSE, 5); + gtk_container_set_border_width(GTK_CONTAINER(vbox), 5); + gtk_container_add(GTK_CONTAINER(window), vbox); + gtk_widget_show(vbox); + + /* This is the scrolled window to put the GtkList widget inside */ + scrolled_window=gtk_scrolled_window_new(NULL, NULL); + gtk_widget_set_usize(scrolled_window, 250, 150); + gtk_container_add(GTK_CONTAINER(vbox), scrolled_window); + gtk_widget_show(scrolled_window); + + /* Create the GtkList widget. + * Connect the sigh_print_selection() signal handler + * function to the "selection_changed" signal of the GtkList + * to print out the selected items each time the selection + * has changed */ + gtklist=gtk_list_new(); + gtk_scrolled_window_add_with_viewport( GTK_SCROLLED_WINDOW(scrolled_window), + gtklist); + gtk_widget_show(gtklist); + gtk_signal_connect(GTK_OBJECT(gtklist), + "selection_changed", + GTK_SIGNAL_FUNC(sigh_print_selection), + NULL); + + /* We create a "Prison" to put a list item in ;) */ + frame=gtk_frame_new("Prison"); + gtk_widget_set_usize(frame, 200, 50); + gtk_container_set_border_width(GTK_CONTAINER(frame), 5); + gtk_frame_set_shadow_type(GTK_FRAME(frame), GTK_SHADOW_OUT); + gtk_container_add(GTK_CONTAINER(vbox), frame); + gtk_widget_show(frame); + + /* Connect the sigh_button_event() signal handler to the GtkList + * which will handle the "arresting" of list items + */ + gtk_signal_connect(GTK_OBJECT(gtklist), + "button_release_event", + GTK_SIGNAL_FUNC(sigh_button_event), + frame); + + /* Create a separator */ + separator=gtk_hseparator_new(); + gtk_container_add(GTK_CONTAINER(vbox), separator); + gtk_widget_show(separator); + + /* Finally create a button and connect it's "clicked" signal + * to the destruction of the window */ + button=gtk_button_new_with_label("Close"); + gtk_container_add(GTK_CONTAINER(vbox), button); + gtk_widget_show(button); + gtk_signal_connect_object(GTK_OBJECT(button), + "clicked", + GTK_SIGNAL_FUNC(gtk_widget_destroy), + GTK_OBJECT(window)); + + + /* Now we create 5 list items, each having it's own + * label and add them to the GtkList using gtk_container_add() + * Also we query the text string from the label and + * associate it with the list_item_data_key for each list item + */ + for (i=0; i<5; i++) { + GtkWidget *label; + gchar *string; + + sprintf(buffer, "ListItemContainer with Label #%d", i); + label=gtk_label_new(buffer); + list_item=gtk_list_item_new(); + gtk_container_add(GTK_CONTAINER(list_item), label); + gtk_widget_show(label); + gtk_container_add(GTK_CONTAINER(gtklist), list_item); + gtk_widget_show(list_item); + gtk_label_get(GTK_LABEL(label), &string); + gtk_object_set_data(GTK_OBJECT(list_item), + list_item_data_key, + string); + } + /* Here, we are creating another 5 labels, this time + * we use gtk_list_item_new_with_label() for the creation + * we can't query the text string from the label because + * we don't have the labels pointer and therefore + * we just associate the list_item_data_key of each + * list item with the same text string. + * For adding of the list items we put them all into a doubly + * linked list (GList), and then add them by a single call to + * gtk_list_append_items(). + * Because we use g_list_prepend() to put the items into the + * doubly linked list, their order will be descending (instead + * of ascending when using g_list_append()) + */ + dlist=NULL; + for (; i<10; i++) { + sprintf(buffer, "List Item with Label %d", i); + list_item=gtk_list_item_new_with_label(buffer); + dlist=g_list_prepend(dlist, list_item); + gtk_widget_show(list_item); + gtk_object_set_data(GTK_OBJECT(list_item), + list_item_data_key, + "ListItem with integrated Label"); + } + gtk_list_append_items(GTK_LIST(gtklist), dlist); + + /* Finally we want to see the window, don't we? ;) */ + gtk_widget_show(window); + + /* Fire up the main event loop of gtk */ + gtk_main(); + + /* We get here after gtk_main_quit() has been called which + * happens if the main window gets destroyed + */ + return(0); } -static gint -button_press_event (GtkWidget *widget, GdkEventButton *event) +/* This is the signal handler that got connected to button + * press/release events of the GtkList + */ +void sigh_button_event( GtkWidget *gtklist, + GdkEventButton *event, + GtkWidget *frame ) { - if (event->button == 1 && pixmap != NULL) - draw_brush (widget, event->x, event->y); - - return TRUE; + /* We only do something if the third (rightmost mouse button + * was released + */ + if (event->type==GDK_BUTTON_RELEASE && + event->button==3) { + GList *dlist, *free_list; + GtkWidget *new_prisoner; + + /* Fetch the currently selected list item which + * will be our next prisoner ;) + */ + dlist=GTK_LIST(gtklist)->selection; + if (dlist) + new_prisoner=GTK_WIDGET(dlist->data); + else + new_prisoner=NULL; + + /* Look for already imprisoned list items, we + * will put them back into the list. + * Remember to free the doubly linked list that + * gtk_container_children() returns + */ + dlist=gtk_container_children(GTK_CONTAINER(frame)); + free_list=dlist; + while (dlist) { + GtkWidget *list_item; + + list_item=dlist->data; + + gtk_widget_reparent(list_item, gtklist); + + dlist=dlist->next; + } + g_list_free(free_list); + + /* If we have a new prisoner, remove him from the + * GtkList and put him into the frame "Prison". + * We need to unselect the item first. + */ + if (new_prisoner) { + GList static_dlist; + + static_dlist.data=new_prisoner; + static_dlist.next=NULL; + static_dlist.prev=NULL; + + gtk_list_unselect_child(GTK_LIST(gtklist), + new_prisoner); + gtk_widget_reparent(new_prisoner, frame); + } + } } -static gint -motion_notify_event (GtkWidget *widget, GdkEventMotion *event) +/* This is the signal handler that gets called if GtkList + * emits the "selection_changed" signal + */ +void sigh_print_selection( GtkWidget *gtklist, + gpointer func_data) { - int x, y; - GdkModifierType state; - - if (event->is_hint) - gdk_window_get_pointer (event->window, &x, &y, &state); - else - { - x = event->x; - y = event->y; - state = event->state; + GList *dlist; + + /* Fetch the doubly linked list of selected items + * of the GtkList, remember to treat this as read-only! + */ + dlist=GTK_LIST(gtklist)->selection; + + /* If there are no selected items there is nothing more + * to do than just telling the user so + */ + if (!dlist) { + g_print("Selection cleared\n"); + return; } + /* Ok, we got a selection and so we print it + */ + g_print("The selection is a "); - if (state & GDK_BUTTON1_MASK && pixmap != NULL) - draw_brush (widget, x, y); - - return TRUE; + /* Get the list item from the doubly linked list + * and then query the data associated with list_item_data_key. + * We then just print it */ + while (dlist) { + GtkObject *list_item; + gchar *item_data_string; + + list_item=GTK_OBJECT(dlist->data); + item_data_string=gtk_object_get_data(list_item, + list_item_data_key); + g_print("%s ", item_data_string); + + dlist=dlist->next; + } + g_print("\n"); } +/* example-end */ + -void -quit () -{ - gtk_exit (0); -} + + List Item Widget +

+The GtkListItem widget is designed to act as a container holding up to +one child, providing functions for selection/deselection just like the +GtkList widget requires them for its children. -int -main (int argc, char *argv[]) -{ - GtkWidget *window; - GtkWidget *drawing_area; - GtkWidget *vbox; +A GtkListItem has its own window to receive events and has its own +background color which is usually white. - GtkWidget *button; +As it is directly derived from a GtkItem it can be treated as such by +using the GTK_ITEM(ListItem) macro, see the GtkItem widget for more on +this. Usually a GtkListItem just holds a label to identify e.g. a +filename within a GtkList -- therefore the convenience function +gtk_list_item_new_with_label() is provided. The same effect can be +achieved by creating a GtkLabel on its own, setting its alignment to +xalign=0 and yalign=0.5 with a subsequent container addition to the +GtkListItem. - gtk_init (&argc, &argv); +As one is not forced to add a GtkLabel to a GtkListItem, you could +also add a GtkVBox or a GtkArrow etc. to the GtkListItem. - window = gtk_window_new (GTK_WINDOW_TOPLEVEL); - gtk_widget_set_name (window, "Test Input"); + + Signals +

+A GtkListItem does not create new signals on its own, but inherits +the signals of a GtkItem. *Note GtkItem::, for more info. - vbox = gtk_vbox_new (FALSE, 0); - gtk_container_add (GTK_CONTAINER (window), vbox); - gtk_widget_show (vbox); + + Functions +

+ +guint gtk_list_item_get_type( void ); + - gtk_signal_connect (GTK_OBJECT (window), "destroy", - GTK_SIGNAL_FUNC (quit), NULL); +Returns the `GtkListItem' type identifier. - /* Create the drawing area */ + +GtkWidget *gtk_list_item_new( void ); + - drawing_area = gtk_drawing_area_new (); - gtk_drawing_area_size (GTK_DRAWING_AREA (drawing_area), 200, 200); - gtk_box_pack_start (GTK_BOX (vbox), drawing_area, TRUE, TRUE, 0); +Create a new GtkListItem object. The new widget is returned as a +pointer to a GtkWidget object. NULL is returned on failure. - gtk_widget_show (drawing_area); + +GtkWidget *gtk_list_item_new_with_label( gchar *label ); + - /* Signals used to handle backing pixmap */ +Create a new GtkListItem object, having a single GtkLabel as the sole +child. The new widget is returned as a pointer to a GtkWidget +object. NULL is returned on failure. - gtk_signal_connect (GTK_OBJECT (drawing_area), "expose_event", - (GtkSignalFunc) expose_event, NULL); - gtk_signal_connect (GTK_OBJECT(drawing_area),"configure_event", - (GtkSignalFunc) configure_event, NULL); + +void gtk_list_item_select( GtkListItem *list_item ); + - /* Event signals */ +This function is basically a wrapper around a call to gtk_item_select +(GTK_ITEM (list_item)) which will emit the select signal. *Note +GtkItem::, for more info. - gtk_signal_connect (GTK_OBJECT (drawing_area), "motion_notify_event", - (GtkSignalFunc) motion_notify_event, NULL); - gtk_signal_connect (GTK_OBJECT (drawing_area), "button_press_event", - (GtkSignalFunc) button_press_event, NULL); + +void gtk_list_item_deselect( GtkListItem *list_item ); + - gtk_widget_set_events (drawing_area, GDK_EXPOSURE_MASK - | GDK_LEAVE_NOTIFY_MASK - | GDK_BUTTON_PRESS_MASK - | GDK_POINTER_MOTION_MASK - | GDK_POINTER_MOTION_HINT_MASK); +This function is basically a wrapper around a call to +gtk_item_deselect (GTK_ITEM (list_item)) which will emit the deselect +signal. *Note GtkItem::, for more info. - /* .. And a quit button */ - button = gtk_button_new_with_label ("Quit"); - gtk_box_pack_start (GTK_BOX (vbox), button, FALSE, FALSE, 0); + +GtkListItem *GTK_LIST_ITEM( gpointer obj ); + - gtk_signal_connect_object (GTK_OBJECT (button), "clicked", - GTK_SIGNAL_FUNC (gtk_widget_destroy), - GTK_OBJECT (window)); - gtk_widget_show (button); +Cast a generic pointer to `GtkListItem*'. *Note Standard Macros::, for +more info. - gtk_widget_show (window); + +GtkListItemClass *GTK_LIST_ITEM_CLASS( gpointer class ); + - gtk_main (); +Cast a generic pointer to GtkListItemClass*. *Note Standard Macros::, +for more info. - return 0; -} -/* example-end */ + +gint GTK_IS_LIST_ITEM( gpointer obj ); +Determine if a generic pointer refers to a `GtkListItem' object. +*Note Standard Macros::, for more info. + + + Example +

+Please see the GtkList example on this, which covers the usage of a +GtkListItem as well. + + -- cgit v1.2.1