[gnome-devel-docs] demos: Added C-style image-viewer demo



commit bf0e4c9eb1d3ffcbbfaa43c30dba7b39fcf72b88
Author: Johannes Schmid <jhs gnome org>
Date:   Sat Mar 19 17:18:44 2011 -0400

    demos: Added C-style image-viewer demo

 demos/C/image-viewer.c.page         |  208 +++++++++++++++++++++++++++++++++--
 demos/C/image-viewer/image_viewer.c |  162 ++++++++++++++-------------
 2 files changed, 283 insertions(+), 87 deletions(-)
---
diff --git a/demos/C/image-viewer.c.page b/demos/C/image-viewer.c.page
index 879bfaf..a213f44 100644
--- a/demos/C/image-viewer.c.page
+++ b/demos/C/image-viewer.c.page
@@ -7,29 +7,208 @@
     
     <desc>A little bit more than a simple "Hello world" Gtk application.</desc>
     
-    <revision pkgversion="0.1" version="0.1" date="2010-12-03" status="stub"/>
+    <revision pkgversion="0.1" version="0.1" date="2011-03-18" status="review"/>
     <credit type="author">
       <name>GNOME Documentation Project</name>
       <email>gnome-doc-list gnome org</email>
     </credit>
-    
+    <credit type="author">
+      <name>Johannes Schmid</name>
+      <email>jhs gnome org</email>
+    </credit>    
   </info>
 
 <title>Image Viewer</title>
 
-<!-- FIXME: actually need to write it for the C demo rather than JavaScript! -->
-
 <synopsis>
   <p>In this tutorial, you will learn:</p>
   <list>
-    <item><p>Some basic concepts of the Javascript language, specially the best practices when developing for GNOME</p></item>
-    <item><p>How to write a Gtk application in Javascript</p></item>
+    <item><p>Some basic concepts of the C/GObject programming</p></item>
+    <item><p>How to write a Gtk application in C</p></item>
   </list>
 </synopsis>
 
 <section>
-  <title>Introduction</title>
-  <p></p>
+  <title>Create a project in Anjuta</title>
+  <p>Before you start coding, you'll need to set up a new project in Anjuta. This will create all of the files you need to build and run the code later on. It's also useful for keeping everything together.</p>
+  <steps>
+    <item>
+    <p>Start Anjuta and click <guiseq><gui>File</gui><gui>New</gui><gui>Project</gui></guiseq> to open the project wizard.</p>
+    </item>
+    <item>
+    <p>Choose <gui>Gtk+ (Simple)</gui> from the <gui>C</gui> tab, click <gui>Forward</gui>, and fill-out your details on the next few pages. Use <file>image-viewer</file> as project name and directory.</p>
+   	</item>
+    <item>
+    <p>Make sure that <gui>Use GtkBuilder for user interface</gui> is disabled as we will
+    create the UI manually in this tutorial. Check the <link xref="guitar-tuner.c">Guitar-Tuner</link>
+    tutorial using the interface builder.</p>
+    </item>
+    <item>
+    <p>Click <gui>Finished</gui> and the project will be created for you. Open <file>src/main.c</file> from the <gui>Project</gui> or <gui>File</gui> tabs. You should see some code which starts with the lines:</p>
+    <code mime="text/x-csrc"><![CDATA[
+#include <config.h>
+#include <gtk/gtk.h>]]></code>
+    </item>
+  </steps>
+</section>
+
+<section>
+  <title>Build the code for the first time</title>
+  <p>C is a rather verbose language, so don't be surprised that the file contains quite a lot of code. Most of it is template code. It loads an (empty) window from the user interface description file and shows it. More details are given below; skip this list if you understand the basics:</p>
+  
+  <list>
+  <item>
+    <p>The three <code>#include</code> lines at the top include the <code>config</code> (useful autoconf build defines), <code>gtk</code> (user interface) and <code>gi18n</code> (internationalization) libraries. Functions from these libraries are used in the rest of the code.</p>
+   </item>
+   <item>
+    <p>The <code>create_window</code> function creates a new (empty) and connects a signal to exit the application when that window is closed.</p>
+    <p>Connecting signals is how you define what happens when you push a button, or when some other event happens. Here, the <code>destroy</code> function is called (and quits the app) when you close the window.</p>
+   </item>
+   <item>
+    <p>The <code>main</code> function is run by default when you start a C application. It calls a few functions which set-up and then run the application. The <code>gtk_main</code> function start the GTK mainloop, which runs the user interface and starts listening for events (like clicks and key presses).</p>
+   </item>
+   <item>
+    <p>The <code>ENABLE_NLS</code> conditional definition sets-up <code>gettext</code>, which is a framework for translating applications. These functions specify how translation tools should handle your app when you run them.</p>
+   </item>
+  </list>
+
+  <p>This code is ready to be used, so you can compile it by clicking <guiseq><gui>Build</gui><gui>Build Project</gui></guiseq> (or press <keyseq><key>Shift</key><key>F7</key></keyseq>).</p>
+  <p>Press <gui>Configure</gui> on the next window that appears to configure a debug build. You only need to do this once, for the first build.</p>
+</section>
+
+<section>
+<title>Creating the user interface</title>
+<p>Now we will bring live into the empty window. <em>Gtk+</em> organizes the user interface
+with <em>GtkContainer</em> that can contain other widgets and even other containers. Here we
+will use the simplest available container, a <em>GtkBox</em>:</p>
+<code mime="text/x-csrc"><![CDATA[
+static GtkWidget*
+create_window (void)
+{
+	GtkWidget *window;
+	GtkWidget *button;
+	GtkWidget *image;
+	GtkWidget *box;
+
+	/* Setup the UI */
+	window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
+	gtk_window_set_title (GTK_WINDOW (window), "image-viewer-c");
+
+	box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 5);
+	button = gtk_button_new_with_label (_("Open image"));
+	image = gtk_image_new ();
+
+	gtk_box_pack_start (GTK_BOX (box), image, TRUE, TRUE, 0);
+	gtk_box_pack_start (GTK_BOX (box), button, FALSE, FALSE, 0);
+
+	gtk_container_add (GTK_CONTAINER (window), box);
+
+	/* Connect signals */
+
+	/* Show open dialog when opening a file */
+	g_signal_connect (button, "clicked", G_CALLBACK (on_open_image), image);
+	
+	/* Exit when the window is closed */
+	g_signal_connect (window, "destroy", G_CALLBACK (gtk_main_quit), NULL);
+	
+	return window;
+}
+]]></code>
+  <steps>
+    <item>
+    <p>The first lines create the widgets we want to use, a button for opening up an image, the image view widget itself and
+    the box we will use at container. The macros like <code>GTK_BOX()</code> are used for dynamic type checking and casting
+    which is needed as C doesn't support object-orientation out-of-the-box.</p>
+    </item>
+    <item>
+    <p>The calls to <code>gtk_box_pack_start()</code> add the two widgets to the box and define their behaviour. The image will
+    expand to any available space while the button will just be as big as needed. You will notice that we don't set
+    explicit sizes on the widgets. In <em>GTK+</em> this is usually not needed at makes it much easier to have a layout that
+    looks good in different window sizes. Next, the box is added to the window.</p>
+    </item>
+    <item>
+    <p>>We need to define what happens when the user clicks on the button. <em>Gtk+</em> uses the concept of <em>signals</em> and
+    the buttons fires the <em>clicked</em> signal that we can connect to some action. This is done using the <code>g_signal_connect()</code>
+    method which tells <em>Gtk+</em> to call the <code>on_image_open</code> when the button is clicked and
+    to pass the image as additional argument to that function. We will define the <em>callback</em> in the next section.</p>
+    </item>
+    <item>
+    <p>The last <code>g_signal_connect()</code> makes sure that the application exits when the window is closed.</p>
+    </item>
+  </steps>
+</section>
+
+<section>
+<title>Showing the image</title>
+<p>We will now define the signal handler for the <em>click</em>-signal or the 
+button we mentioned before. Add this code before the <code>create_window()</code>
+method.</p>
+<code mime="text/x-csrc"><![CDATA[
+static void
+on_open_image (GtkButton* button, gpointer user_data)
+{
+	GtkWidget *image = GTK_WIDGET (user_data);
+	GtkWidget *toplevel = gtk_widget_get_toplevel (image);
+	GtkFileFilter *filter = gtk_file_filter_new ();
+	GtkWidget *dialog = gtk_file_chooser_dialog_new (_("Open image"),
+	                                                 GTK_WINDOW (toplevel),
+	                                                 GTK_FILE_CHOOSER_ACTION_OPEN,
+	                                                 GTK_STOCK_OK, GTK_RESPONSE_ACCEPT,
+	                                                 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
+	                                                 NULL);
+
+	gtk_file_filter_add_pixbuf_formats (filter);
+	gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog),
+	                             filter);
+	
+	switch (gtk_dialog_run (GTK_DIALOG (dialog)))
+	{
+		case GTK_RESPONSE_ACCEPT:
+		{
+			gchar *filename = 
+				gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog));
+			gtk_image_set_from_file (GTK_IMAGE (image), filename);
+			break;
+		}
+		default:
+			break;
+	}
+	gtk_widget_destroy (dialog);
+}
+]]></code>
+  <p>This is a bit more complicated than anything we've attempted so far, so let's break it down:</p>
+  <list>
+    <item><p>The first argument of the signal is always the widget that send the signal, then several 
+    other arguments related to the signal could come but <em>clicked</em> doesn't have any. Next is
+    the <code>user_data</code> argumemt which is a pointer to the data we passed when connecting the signal.
+    In this case it is our<em>GtkImage</em> object.</p>
+    </item> 
+    <item>
+      <p>The next interesting line is where the dialog for choosing the file is created using
+      <code>gtk_file_chooser_dialog_new()</code>. The function takes the title of the dialog, the
+      parent window of the dialog and several options like the number of buttons and their corresponding
+      values.</p>
+    <p>Notice that we are using <em>stock</em> button names from Gtk, instead of manually typing "Cancel" or "Open". The advantage of using stock names is that the button labels will already be translated into the user's language.</p>
+    </item>
+    <item>
+    <p>The next two lines restrict the <gui>Open</gui> dialog to only display files which can be opened by GtkImage. A filter object is created first; we then add all kinds of files supported by GtkPixbuf (which includes most image formats like PNG and JPEG) to the filter. Finally, we set this filter to be the <gui>Open</gui> dialog's filter.</p>
+    </item>
+    <item>
+    <p><code>gtk_dialog_run ()</code> displays the <gui>Open</gui> dialog. The dialog will wait for the user to choose an image; when they do, <code>gtk_dialog_run ()</code> will return the value <code>GTK_RESPONSE_ACCEPT</code> (it would return <code>GTK_RESPONSE_CANCEL</code> if the user clicked <gui>Cancel</gui>). The <code>switch</code> statement tests for this.</p>
+    </item>
+    <item><p>Assuming that the user did click <gui>Open</gui>, the next line sets the <code>file</code> property of the GtkImage to the filename of the image selected by the user. The GtkImage will then load and display the chosen image.</p>
+    </item>
+    <item>
+    <p>In the final line of this method, we destroy the <gui>Open</gui> dialog because we don't need it any more.
+    Destroying automatically hides the dialog.</p>
+    </item>
+  </list>
+</section>
+
+<section>
+  <title>Build and run the application</title>
+  <p>All of the code should now be ready to go. Click <guiseq><gui>Build</gui><gui>Build Project</gui></guiseq> to build everything again, and then <guiseq><gui>Run</gui><gui>Run</gui></guiseq> to start the application.</p>
+  <p>If you haven't already done so, choose the <file>Debug/src/image-viewer</file> application in the dialog that appears. Finally, hit <gui>Run</gui> and enjoy!</p>
 </section>
 
 <section>
@@ -39,12 +218,21 @@
 
 <section>
   <title>Next steps</title>
-  <p>Here are some ideas for how you can extend this simple demonstration file:</p>
+  <p>Here are some ideas for how you can extend this simple demonstration:</p>
   <list>
    <item>
-   <p>XXX</p>
+   <p>Have the user select a directory rather than a file, and provide controls to cycle through all of the images in a directory.</p>
+   </item>
+   <item>
+   <p>Apply random filters and effects to the image when it is loaded and allow the user to save the modified image.</p>
+   <p><link href="http://www.gegl.org/api.html";>GEGL</link> provides powerful image manipulation capabilities.</p>
+   </item>
+   <item>
+   <p>Allow the user to load images from network shares, scanners, and other more complicated sources.</p>
+   <p>You can use <link href="http://library.gnome.org/devel/gio/unstable/";>GIO</link> to handle network file tranfers and the like, and <link href="http://library.gnome.org/devel/gnome-scan/unstable/";>GNOME Scan</link> to handle scanning.</p>
    </item>
   </list>
 </section>
 
+
 </page>
diff --git a/demos/C/image-viewer/image_viewer.c b/demos/C/image-viewer/image_viewer.c
index f5ed6e8..7b953af 100644
--- a/demos/C/image-viewer/image_viewer.c
+++ b/demos/C/image-viewer/image_viewer.c
@@ -1,87 +1,95 @@
+/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 4; tab-width: 4 -*- */
+
+#include <config.h>
 #include <gtk/gtk.h>
 
-typedef struct _AppWidgets AppWidgets;
 
-struct _AppWidgets
+#include <glib/gi18n.h>
+
+static void
+on_open_image (GtkButton* button, gpointer user_data)
 {
-   GtkWidget *window;
-   GtkWidget *image;
-};
+	GtkWidget *image = GTK_WIDGET (user_data);
+	GtkWidget *toplevel = gtk_widget_get_toplevel (image);
+	GtkFileFilter *filter = gtk_file_filter_new ();
+	GtkWidget *dialog = gtk_file_chooser_dialog_new (_("Open image"),
+	                                                 GTK_WINDOW (toplevel),
+	                                                 GTK_FILE_CHOOSER_ACTION_OPEN,
+	                                                 GTK_STOCK_OK, GTK_RESPONSE_ACCEPT,
+	                                                 GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
+	                                                 NULL);
 
-void on_open_button_clicked (GtkWidget *button, gpointer data);
+	gtk_file_filter_add_pixbuf_formats (filter);
+	gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (dialog),
+	                             filter);
+	
+	switch (gtk_dialog_run (GTK_DIALOG (dialog)))
+	{
+		case GTK_RESPONSE_ACCEPT:
+		{
+			gchar *filename = 
+				gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog));
+			gtk_image_set_from_file (GTK_IMAGE (image), filename);
+			break;
+		}
+		default:
+			break;
+	}
+	gtk_widget_destroy (dialog);
+}
+	
 
-int main( int   argc,
-          char *argv[] )
+static GtkWidget*
+create_window (void)
 {
-    GtkWidget *scroll_window = NULL;
-    GtkWidget *open_button = NULL;
-    GtkWidget *hbox = NULL;
-    GtkWidget *vbox;
-    AppWidgets app_widgets;
- 
-    gtk_init (&argc, &argv);
-    
-    app_widgets.window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
-    gtk_window_set_default_size (GTK_WINDOW (app_widgets.window), 400, 400);
-    gtk_window_set_title (GTK_WINDOW (app_widgets.window), "Image Viewer Demo");
-    g_signal_connect (app_widgets.window, "destroy", G_CALLBACK (gtk_main_quit), NULL);
-
-    /* Sets the image.*/
-    app_widgets.image = gtk_image_new_from_file ("gtk_test.png");
-
-    /* Make window scrollable. */
-    scroll_window = gtk_scrolled_window_new (NULL, NULL); 
-    gtk_scrolled_window_add_with_viewport (GTK_SCROLLED_WINDOW (scroll_window), app_widgets.image);
-
-    /* Button's box. */
-    hbox = gtk_box_new (GTK_HORIENTATION_HORIZONTAL, 5);
-
-    open_button = gtk_button_new_with_label( "Open...");
-    gtk_box_pack_start (GTK_BOX (hbox), open_button, TRUE, TRUE, 0);
-    g_signal_connect (open_button, "clicked",
-                      G_CALLBACK (on_open_button_clicked), &app_widgets);
-
-    /* Main window layout. */
-    vbox = gtk_box_new (GTK_HORIENTATION_VERTICAL, 0);
-
-    gtk_box_pack_start (GTK_BOX (vbox), scroll_window, TRUE, TRUE, 0);
-    gtk_box_pack_start (GTK_BOX (vbox), hbox, FALSE, FALSE, 0);
-
-    gtk_container_add (GTK_CONTAINER (app_widgets.window), vbox);
-
-    gtk_widget_show_all  (app_widgets.window);
-    
-    gtk_main ();
-    
-    return 0;
+	GtkWidget *window;
+	GtkWidget *button;
+	GtkWidget *image;
+	GtkWidget *box;
+
+	/* Setup the UI */
+	window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
+	gtk_window_set_title (GTK_WINDOW (window), "image-viewer-c");
+
+	box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 5);
+	button = gtk_button_new_with_label (_("Open image"));
+	image = gtk_image_new ();
+
+	gtk_box_pack_start (GTK_BOX (box), image, TRUE, TRUE, 0);
+	gtk_box_pack_start (GTK_BOX (box), button, FALSE, FALSE, 0);
+
+	gtk_container_add (GTK_CONTAINER (window), box);
+
+	/* Connect signals */
+
+	/* Show open dialog when opening a file */
+	g_signal_connect (button, "clicked", G_CALLBACK (on_open_image), image);
+	
+	/* Exit when the window is closed */
+	g_signal_connect (window, "destroy", G_CALLBACK (gtk_main_quit), NULL);
+	
+	return window;
 }
-void on_open_button_clicked (GtkWidget *button, gpointer data)
+
+
+int
+main (int argc, char *argv[])
 {
-   GtkWidget *file_chooser_dialog = NULL;
-   GtkFileFilter *filter = NULL;
-   GFile *file = NULL;
-   char *filename;
-   AppWidgets *app_widgets = (AppWidgets *) data;
-
-   file_chooser_dialog = gtk_file_chooser_dialog_new ("Open file",
-                                         GTK_WINDOW (app_widgets->window),
-                                         GTK_FILE_CHOOSER_ACTION_OPEN,
-                                         GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
-                                         GTK_STOCK_OPEN, GTK_RESPONSE_ACCEPT,
-                                         NULL);
-
-   /* Show just image files. */
-   filter = gtk_file_filter_new ();
-   gtk_file_filter_add_pixbuf_formats (filter);
-   gtk_file_chooser_add_filter (GTK_FILE_CHOOSER (file_chooser_dialog), filter); 
-
-   if (gtk_dialog_run (GTK_DIALOG (file_chooser_dialog)) == GTK_RESPONSE_ACCEPT)
-   {
-      file = gtk_file_chooser_get_file (GTK_FILE_CHOOSER (file_chooser_dialog));
-      filename = g_file_get_basename (file);
-      gtk_image_set_from_file (GTK_IMAGE (app_widgets->image), filename);
-      
-      g_free (filename);
-   }
-   gtk_widget_destroy (file_chooser_dialog);
+ 	GtkWidget *window;
+
+
+#ifdef ENABLE_NLS
+	bindtextdomain (GETTEXT_PACKAGE, PACKAGE_LOCALE_DIR);
+	bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
+	textdomain (GETTEXT_PACKAGE);
+#endif
+
+	
+	gtk_init (&argc, &argv);
+
+	window = create_window ();
+	gtk_widget_show_all (window);
+
+	gtk_main ();
+	return 0;
 }



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