Enlightenment CVS committal

Author  : ningerso
Project : e17
Module  : libs/ewl

Dir     : e17/libs/ewl/src/bin/tests/tree2


Modified Files:
        ewl_tree2.c 


Log Message:
Add tree2 tutorial from dan's website.

===================================================================
RCS file: /cvs/e/e17/libs/ewl/src/bin/tests/tree2/ewl_tree2.c,v
retrieving revision 1.5
retrieving revision 1.6
diff -u -3 -r1.5 -r1.6
--- ewl_tree2.c 4 Jan 2007 05:09:45 -0000       1.5
+++ ewl_tree2.c 5 Jan 2007 13:13:15 -0000       1.6
@@ -5,6 +5,924 @@
 #include <stdlib.h>
 #include <string.h>
 
+/**
+ * @addtogroup Ewl_Tree2
+ * @section tree2_tut Tutorial
+ *
+ * Finding the Tree in the Forest
+ * (originally at http://everburning.com/news/finding-the-tree-in-the-forest)
+ * Weve been doing a bunch of work on Ewl_Tree2 lately. Its been shaping up
+ * nicely at the moment. To that end, I thought Id do a quick write up on how 
it
+ * works and what you can do with it.
+ *
+ * Ewl_Tree2 is built based on an MVC (model/view/controller) framework. This
+ * makes it a lot easier for developers to keep their data up to date without
+ * having to go through all kinds of contortions using the tree nodes and
+ * widgets as they do with the current Ewl_Tree widget.
+ *
+ * There are three basic items youll need to become familiar with in order to
+ * use Ewl_Tree2. They are, Ewl_Tree2, of course, Ewl_Model and Ewl_View. These
+ * three will allow you to setup your columns and the tree.
+ *
+ * The best way to show something is through an example, so thats what Ill do.
+ * This is basically the tree2 test case from ewl_test ported to run in a
+ * window. The case is pretty simple. We store an array of data, this array
+ * contains nodes that specify the text and an image to be displayed.
+ *
+ * We then create a three column tree. The first column will show the text as 
an
+ * Ewl_Label widget. The second column will display an Ewl_Image. The third 
will
+ * be an Ewl_Button. The third column doesnt use the ewl_button code directly 
as
+ * we want to set two pieces of information so we write our own methods to
+ * handle the creating and assignment functions.
+ *
+ * I'll be putting the code into tree2_test.c and using the following to 
compile
+ * the code as I go.
+ *
+ * @code
+ * oni:~/dev/tree2_test$ gcc -o tree2_test tree2_test.c `ewl-config --cflags
+ * --libs`
+ * @endcode
+ *
+ * With that out of the way, on with the show. Im going to start by listing all
+ * of the code and then Ill go through it piece by piece.
+ *
+ * @code
+ * #include <Ewl.h>
+ * #include <stdio.h>
+ * #include <stdlib.h>
+ * #include <string.h>
+ *
+ * #define DATA_ELEMENTS 5
+ *
+ * typedef struct Test_Row_Data Test_Row_Data;
+ * struct Test_Row_Data
+ * {
+ *     char *image;
+ *     char *text;
+ * };
+ *
+ * typedef struct Test_Data Test_Data;
+ * struct Test_Data
+ * {
+ *     unsigned int count;
+ *     Test_Row_Data **rows;
+ * };
+ *
+ * static void *test_data_setup(void);
+ *
+ * static Ewl_Widget *test_custom_new(void);
+ * static void test_custom_assign_set(Ewl_Widget *w, void *data);
+ *
+ * static Ewl_Widget *test_data_header_fetch(void *data, int column);
+ * static void *test_data_fetch(void *data, unsigned int row, unsigned int 
column);
+ * static void test_data_sort(void *data, unsigned int column, 
Ewl_Sort_Direction sort);
+ * static int test_data_count_get(void *data);
+ *
+ * static void cb_delete_window(Ewl_Widget *w, void *ev, void *data);
+ * static void cb_scroll_headers(Ewl_Widget *w, void *ev, void *data);
+ * static void cb_scroll_visible(Ewl_Widget *w, void *ev, void *data);
+ *
+ * int
+ * main(int argc, char ** argv)
+ * {
+ *     Ewl_Widget *tree, *box, *o, *o2;
+ *     Ewl_Model *model;
+ *     Ewl_View *view;
+ *     void *data;
+ *
+ *      // make sure we can setup ewl
+ *      if (!ewl_init(&argc, argv))
+ *      {
+ *          fprintf(stderr, "Unable to init ewl.n");
+ *          return 1;
+ *      }
+ *
+ *      // create the window
+ *      o = ewl_window_new();
+ *      ewl_window_title_set(EWL_WINDOW(o), "tree2 example");
+ *      ewl_window_class_set(EWL_WINDOW(o), "tree2_example");
+ *      ewl_window_name_set(EWL_WINDOW(o), "tree2_example");
+ *      ewl_object_size_request(EWL_OBJECT(o), 640, 480);
+ *      ewl_callback_append(o, EWL_CALLBACK_DELETE_WINDOW, cb_delete_window, 
NULL);
+ *      ewl_widget_show(o);
+ *
+ *      box = ewl_vbox_new();
+ *      ewl_container_child_append(EWL_CONTAINER(o), box);
+ *      ewl_widget_show(box);
+ *
+ *      o2 = ewl_hbox_new();
+ *      ewl_container_child_append(EWL_CONTAINER(box), o2);
+ *      ewl_object_fill_policy_set(EWL_OBJECT(o2),
+ *                  EWL_FLAG_FILL_VSHRINK | EWL_FLAG_FILL_HFILL);
+ *      ewl_widget_show(o2);
+ *
+ *      // create our data
+ *      data = test_data_setup();
+ *
+ *      // create the model that'll be used for the first two columns
+ *      model = ewl_model_new();
+ *      ewl_model_fetch_set(model, test_data_fetch);
+ *      ewl_model_sort_set(model, test_data_sort);
+ *      ewl_model_count_set(model, test_data_count_get);
+ *
+ *      tree = ewl_tree2_new();
+ *      ewl_container_child_append(EWL_CONTAINER(box), tree);
+ *      ewl_object_fill_policy_set(EWL_OBJECT(tree), EWL_FLAG_FILL_ALL);
+ *      ewl_tree2_data_set(EWL_TREE2(tree), data);
+ *      ewl_widget_show(tree);
+ *
+ *      // create a view for the first column that just has an ewl label
+ *      view = ewl_view_new();
+ *      ewl_view_constructor_set(view, ewl_label_new);
+ *      ewl_view_assign_set(view, EWL_VIEW_ASSIGN(ewl_label_text_set));
+ *      ewl_view_header_fetch_set(view, test_data_header_fetch);
+ *      ewl_tree2_column_append(EWL_TREE2(tree), model, view);
+ *
+ *      // create a view for the second column that just has an ewl image
+ *      view = ewl_view_new();
+ *      ewl_view_constructor_set(view, ewl_image_new);
+ *      ewl_view_assign_set(view, EWL_VIEW_ASSIGN(ewl_image_file_path_set));
+ *      ewl_view_header_fetch_set(view, test_data_header_fetch);
+ *      ewl_tree2_column_append(EWL_TREE2(tree), model, view);
+ *
+ *      // we don't want this one sortable
+ *      model = ewl_model_new();
+ *      ewl_model_fetch_set(model, test_data_fetch);
+ *      ewl_model_count_set(model, test_data_count_get);
+ *
+ *      // create a view for the third column that has a custom widget
+ *      view = ewl_view_new();
+ *      ewl_view_constructor_set(view, test_custom_new);
+ *      ewl_view_assign_set(view, test_custom_assign_set);
+ *      ewl_view_header_fetch_set(view, test_data_header_fetch);
+ *      ewl_tree2_column_append(EWL_TREE2(tree), model, view);
+ *
+ *      // create the checkbuttons for the top box
+ *      o = ewl_checkbutton_new();
+ *      ewl_button_label_set(EWL_BUTTON(o), "Scroll headers");
+ *      ewl_container_child_append(EWL_CONTAINER(o2), o);
+ *      ewl_callback_append(o, EWL_CALLBACK_CLICKED,
+ *                  cb_scroll_headers, tree);
+ *      ewl_widget_show(o);
+ *
+ *      o = ewl_checkbutton_new();
+ *      ewl_button_label_set(EWL_BUTTON(o), "Scroll visible");
+ *      ewl_container_child_append(EWL_CONTAINER(o2), o);
+ *      ewl_checkbutton_checked_set(EWL_CHECKBUTTON(o), TRUE);
+ *      ewl_callback_append(o, EWL_CALLBACK_CLICKED,
+ *                  cb_scroll_visible, tree);
+ *      ewl_widget_show(o);
+ *
+ *      ewl_main();
+ *      return 0;
+ * }
+ *
+ * // setup our data
+ * static void *
+ * test_data_setup(void)
+ * {
+ *      Test_Data *data;
+ *      Test_Row_Data **dt;
+ *
+ *      data = calloc(1, sizeof(Test_Data));
+ *      dt = calloc(DATA_ELEMENTS, sizeof(Test_Row_Data *));
+ *
+ *      dt[0] = calloc(1, sizeof(Test_Row_Data));
+ *      dt[0]->image = strdup("/usr/local/share/ewl/images/e-logo.png");
+ *      dt[0]->text = strdup("The E logo");
+ *
+ *      dt[1] = calloc(1, sizeof(Test_Row_Data));
+ *      dt[1]->image = strdup("/usr/local/share/ewl/images/elicit.png");
+ *      dt[1]->text = strdup("The Elicit image");
+ *
+ *      dt[2] = calloc(1, sizeof(Test_Row_Data));
+ *      dt[2]->image = strdup("/usr/local/share/ewl/images/entrance.png");
+ *      dt[2]->text = strdup("The Entrance image");
+ *
+ *      dt[3] = calloc(1, sizeof(Test_Row_Data));
+ *      dt[3]->image = strdup("/usr/local/share/ewl/images/End.png");
+ *      dt[3]->text = strdup("Zebra");
+ *
+ *      dt[4] = calloc(1, sizeof(Test_Row_Data));
+ *      dt[4]->image = strdup("/usr/local/share/ewl/images/banner-top.png");
+ *      dt[4]->text = strdup("Ant");
+ *
+ *      data->rows = dt;
+ *      data->count = DATA_ELEMENTS;
+ *
+ *      return data;
+ * }
+ *
+ * static Ewl_Widget *
+ * test_custom_new(void)
+ * {
+ *      Ewl_Widget *button;
+ *
+ *      button = ewl_button_new();
+ *
+ *      return button;
+ * }
+ *
+ * static void
+ * test_custom_assign_set(Ewl_Widget *w, void *data)
+ * {
+ *      Test_Row_Data *d;
+ *
+ *      d = data;
+ *      ewl_button_label_set(EWL_BUTTON(w), d->text);
+ *      ewl_button_image_set(EWL_BUTTON(w), d->image, NULL);
+ * }
+ *
+ * static Ewl_Widget *
+ * test_data_header_fetch(void *data , int column)
+ * {
+ *      Ewl_Widget *l;
+ *
+ *      l = ewl_label_new();
+ *      if (column == 0)
+ *          ewl_label_text_set(EWL_LABEL(l), "Title");
+ *      else if (column == 1)
+ *          ewl_label_text_set(EWL_LABEL(l), "Image");
+ *      else
+ *          ewl_label_text_set(EWL_LABEL(l), "Button");
+ *      ewl_widget_show(l);
+ *
+ *      return l;
+ * }
+ *
+ * static void *
+ * test_data_fetch(void *data, unsigned int row, unsigned int column)
+ * {
+ *      Test_Data *d;
+ *      void *val = NULL;
+ *
+ *      d = data;
+ *
+ *      if (column == 0)
+ *          val = d->rows[row]->text;
+ *
+ *      else if (column == 1)
+ *          val = d->rows[row]->image;
+ *
+ *      else if (column == 2)
+ *          val = d->rows[row];
+ *
+ *      return val;
+ * }
+ *
+ * static void
+ * test_data_sort(void *data, unsigned int column, Ewl_Sort_Direction sort)
+ * {
+ *      Test_Data *d;
+ *      int i;
+ *
+ *      // just leave it if we're in sort none.
+ *      if (sort == EWL_SORT_DIRECTION_NONE)
+ *          return;
+ *
+ *      d = data;
+ *
+ *      for (i = (DATA_ELEMENTS - 1); i >= 0; i--)
+ *      {
+ *          int j;
+ *
+ *          for (j = 1; j <= i; j++)
+ *          {
+ *              char *a, *b;
+ *
+ *              if (column == 0)
+ *              {
+ *                  a = d->rows[j - 1]->text;
+ *                  b = d->rows[j]->text;
+ *              }
+ *              else
+ *              {
+ *                  a = d->rows[j - 1]->image;
+ *                  b = d->rows[j]->image;
+ *              }
+ *
+ *              if (((sort == EWL_SORT_DIRECTION_ASCENDING) && strcmp(a, b) > 
0)
+ *                      || ((sort == EWL_SORT_DIRECTION_DESCENDING)
+ *                          && strcmp(a, b) < 0))
+ *              {
+ *                  char *temp;
+ *
+ *                  temp = d->rows[j - 1]->text;
+ *                  d->rows[j - 1]->text = d->rows[j]->text;
+ *                  d->rows[j]->text = temp;
+ *
+ *                  temp = d->rows[j - 1]->image;
+ *                  d->rows[j - 1]->image = d->rows[j]->image;
+ *                  d->rows[j]->image = temp;
+ *              }
+ *          }
+ *      }
+ * }
+ *
+ * static int
+ * test_data_count_get(void *data)
+ * {
+ *      Test_Data *d;
+ *
+ *      d = data;
+ *
+ *      return d->count;
+ * }
+ *
+ * static void
+ * cb_delete_window(Ewl_Widget *w, void *ev, void *data)
+ * {
+ *      ewl_widget_destroy(w);
+ *      ewl_main_quit();
+ * }
+ *
+ * static void
+ * cb_scroll_headers(Ewl_Widget *w, void *ev , void *data)
+ * {
+ *      Ewl_Tree2 *tree;
+ *
+ *      tree = data;
+ *      ewl_tree2_scroll_headers_set(tree,
+ *              ewl_checkbutton_is_checked(EWL_CHECKBUTTON(w)));
+ * }
+ *
+ * static void
+ * cb_scroll_visible(Ewl_Widget *w, void *ev , void *data)
+ * {
+ *      Ewl_Tree2 *tree;
+ *
+ *      tree = data;
+ *      ewl_tree2_scroll_visible_set(tree,
+ *              ewl_checkbutton_is_checked(EWL_CHECKBUTTON(w)));
+ * }
+ * @endcode
+ *
+ * Simple enough, eh? Ok, maybe I should go through it then.
+ *
+ * @code
+ * #include <Ewl.h>
+ * #include <stdio.h>
+ * #include <stdlib.h>
+ * #include <string.h>
+ * @endcode
+ *
+ * We start off with the standard set of includes. Ewl.h is obviously required
+ * to do any EWL programming. The others are needed as well be using functions
+ * they define throughout the application.
+ *
+ * @code
+ * #define DATA_ELEMENTS 5
+ *
+ * typedef struct Test_Row_Data Test_Row_Data;
+ * struct Test_Row_Data
+ * {
+ *      char *image;
+ *      char *text;
+ * };
+ *
+ * typedef struct Test_Data Test_Data;
+ * struct Test_Data
+ * {
+ *      unsigned int count;
+ *      Test_Row_Data **rows;
+ * };
+ * @endcode
+ *
+ * I'm not planning on doing anything fancy with my data. Just keeping an array
+ * with five elements. Im using a define DATA_ELEMENTS to store the number of
+ * elements as Ill be using this in a few places. The data will be stored in a
+ * Test_Data structure. This struct will store the number of items in the array
+ * and an array of Test_Row_Data pointers. Test_Row_Data structs just store the
+ * text and image strings for each of our rows.
+ *
+ * @code
+ * static void *test_data_setup(void);
+ *
+ * static Ewl_Widget *test_custom_new(void);
+ * static void test_custom_assign_set(Ewl_Widget *w, void *data);
+ *
+ * static Ewl_Widget *test_data_header_fetch(void *data, int column);
+ * static void *test_data_fetch(void *data, unsigned int row, unsigned int 
column);
+ * static void test_data_sort(void *data, unsigned int column, 
Ewl_Sort_Direction sort);
+ * static int test_data_count_get(void *data);
+ *
+ * static void cb_delete_window(Ewl_Widget *w, void *ev, void *data);
+ * static void cb_scroll_headers(Ewl_Widget *w, void *ev, void *data);
+ * static void cb_scroll_visible(Ewl_Widget *w, void *ev, void *data);
+ * @endcode
+ *
+ * As you can see, a bunch of pre-declarations next. Well be seeing, and 
getting
+ * the explanation for these as we go along.
+ *
+ * @code
+ * int
+ * main(int argc, char ** argv)
+ * {
+ *      Ewl_Widget *tree, *box, *o, *o2;
+ *      Ewl_Model *model;
+ *      Ewl_View *view;
+ *      void *data;
+ *
+ *      // make sure we can setup ewl
+ *      if (!ewl_init(&argc, argv))
+ *      {
+ *          fprintf(stderr, "Unable to init ewl.n");
+ *          return 1;
+ *      }
+ * @endcode
+ *
+ * The first step in any EWL application is to initialize EWL itself. This is
+ * done with a call to ewl_init(). ewl_init() accepts two parameters, the argc
+ * and argv arguments that were passed to your application. ewl_init() will
+ * return TRUE if EWL was successfully initialized or FALSE otherwise. The
+ * reason to pass the args to ewl_init() is so that EWL can parse out any EWL
+ * specific arguments. Things like setting the rendering engine or printing the
+ * EWL help documentation. These parameters can both be safely set to NULL if
+ * desired.
+ *
+ * With EWL setup we can get down the the fun bit of creating the UI.
+ *
+ * @code
+ *      // create the window
+ *      o = ewl_window_new();
+ *      ewl_window_title_set(EWL_WINDOW(o), "tree2 example");
+ *      ewl_window_class_set(EWL_WINDOW(o), "tree2_example");
+ *      ewl_window_name_set(EWL_WINDOW(o), "tree2_example");
+ *      ewl_object_size_request(EWL_OBJECT(o), 640, 480);
+ *      ewl_callback_append(o, EWL_CALLBACK_DELETE_WINDOW, cb_delete_window, 
NULL);
+ *      ewl_widget_show(o);
+ *
+ *      box = ewl_vbox_new();
+ *      ewl_container_child_append(EWL_CONTAINER(o), box);
+ *      ewl_widget_show(box);
+ *
+ *      o2 = ewl_hbox_new();
+ *      ewl_container_child_append(EWL_CONTAINER(box), o2);
+ *      ewl_object_fill_policy_set(EWL_OBJECT(o2), EWL_FLAG_FILL_VSHRINK | 
EWL_FLAG_FILL_HFILL);
+ *      ewl_widget_show(o2);
+ * @endcode
+ *
+ * This little chunks sets up our base UI. We create the Ewl_Window first using
+ * ewl_window_new(). We set the title, class and name for the window and then
+ * give it a default size of 640×480. Once this is done we set a callback for
+ * when the window is destroyed. This is done with ewl_callback_append() call.
+ * We want to get notified when the window receives the
+ * EWL_CALLBACK_DELETE_WINDOW callback by having the cb_delete_window() 
function
+ * executed.
+ *
+ * With the main window setup we create an Ewl_Box inside of it. An Ewl_Window
+ * by default has no layout policy so if you pack several widgets into it 
theyll
+ * all be sitting on top of each other. You have to pack a box, or something, 
in
+ * there to handle the layout of the contents. Youll see we use
+ * ewl_container_child_append() to add the box to the window. Youll be seeing
+ * this a lot as we pack the UI together. There are also
+ * ewl_container_child_prepend() and ewl_container_child_insert() calls that 
can
+ * be used.
+ *
+ * We also create a second Ewl_Box to hold some checkbuttons that well create
+ * later. Were creating the box here just because I like to keep things order.
+ * Its the first item in the window so I create and pack it first. We could 
also
+ * use ewl_container_child_prepend() later to add it to the box if we wished.
+ * Were setting a custom fill policy on this box with
+ * ewl_object_fill_policy_set(). The policy were setting is
+ * EWL_FLAG_FILL_VSHIRNK | EWL_FLAG_FILL_HFILL. Were telling the widget that we
+ * want it to be as small as possible vertically but take up as much space as
+ * possible horizontally. The fill policy is just a bit mask so were bit wise
+ * oring the values together.
+ *
+ * I guess a quick note about EWL inheritance is necessary at some point. EWL
+ * uses an object oriented approach to its widgets. All widgets inherit from
+ * Ewl_Widget. Ewl_Widget inherits from Ewl_Object. So any ewl_widget_* or
+ * ewl_object_* call can be called on any widgets. You just need to cast to the
+ * correct type first. The casts are done with the EWL_WIDGET() or EWL_OBJECT()
+ * macros. All widgets in EWL have an EWL_WIDGET_NAME() macro. Theres a lot of
+ * inheritance going on in EWL. The Ewl_Box code inherits from the 
Ewl_Container
+ * code. So any ewl_container_* call will work on an Ewl_Box, you just have to
+ * wrap the box variable with an EWL_CONTAINER() call. Take a look at the EWL
+ * docs for a complete listing of the inheritance. (Or if youre looking at the
+ * header files the inheritance is always the first item in the
+ * struct.)
+ *
+ * @code
+ *      // create our data
+ *      data = test_data_setup();
+ * @endcode
+ *
+ * This is just a convenience function to create our data array. I like to keep
+ * stuff separated out whenever possible. Well see what this does later.
+ *
+ * @code
+ *      // create the model that'll be used for the first two columns
+ *      model = ewl_model_new();
+ *      ewl_model_fetch_set(model, test_data_fetch);
+ *      ewl_model_sort_set(model, test_data_sort);
+ *      ewl_model_count_set(model, test_data_count_get);
+ * @endcode
+ *
+ * Our first two columns in the tree will actually use the same data model. I
+ * dont want the third column to be sortable so we need to use a slightly
+ * different model (although its almost the same). We need to set at a of
+ * minimum two pieces of data into the Ewl_Model. These are, the function to
+ * fetch the model data, set with ewl_model_fetch_set(), and the function to 
get
+ * a count of the number of rows of data, set with ewl_model_count_set(). Im
+ * using the third ewl_model_sort_set() to set a sort function for the first 
two
+ * columns. Each of these calls takes the model and a function pointer. You can
+ * see the function signature at the top of the file. Well take a closer look 
at
+ * these functions a bit later.
+ *
+ * @code
+ *      tree = ewl_tree2_new();
+ *      ewl_container_child_append(EWL_CONTAINER(box), tree);
+ *      ewl_object_fill_policy_set(EWL_OBJECT(tree), EWL_FLAG_FILL_ALL);
+ *      ewl_tree2_data_set(EWL_TREE2(tree), data);
+ *      ewl_widget_show(tree);
+ * @endcode
+ *
+ * Next we create the tree itself. The tree is packed into the box we created
+ * earlier. We set the box with a fill policy of EWL_FLAG_FILL_ALL so it will
+ * take as much, or as little space as necesary. We then set the data we 
created
+ * into the tree with ewl_tree2_data_set() function. This data will be passed
+ * around to our various functions as the tree does its work.
+ *
+ * @code
+ *      // create a view for the first column that just has an ewl label
+ *      view = ewl_view_new();
+ *      ewl_view_constructor_set(view, ewl_label_new);
+ *      ewl_view_assign_set(view, EWL_VIEW_ASSIGN(ewl_label_text_set));
+ *      ewl_view_header_fetch_set(view, test_data_header_fetch);
+ *      ewl_tree2_column_append(EWL_TREE2(tree), model, view);
+ * @endcode
+ *
+ * Ok, with our tree created we can start to add columns. Weve already created
+ * the Ewl_Model for the first two columns so we just need to create the views.
+ *
+ * As I mentioned before the first column is using Ewl_Label to display the 
text
+ * of the data item. So, we create a new Ewl_View with ewl_view_new(). We then
+ * set the constructor for this column with ewl_view_constructor_set(). This
+ * will be used to create a new widget for the item in the column. Then we use
+ * ewl_view_assign_set() to set the function that will be used to assign data
+ * into our widget for a given cell. Tree columns need a header. Well set a
+ * third callback function to get the header data for the tree. We use
+ * ewl_view_header_fetch_set() to set this function.
+ *
+ * Once our view is created we call ewl_tree2_column_append() to create a new
+ * column in the tree using our model and view.
+ *
+ * @code
+ *      // create a view for the second column that just has an ewl image view 
=
+ *      ewl_view_new();
+ *      ewl_view_constructor_set(view, ewl_image_new);
+ *      ewl_view_assign_set(view, EWL_VIEW_ASSIGN(ewl_image_file_path_set));
+ *      ewl_view_header_fetch_set(view, test_data_header_fetch);
+ *      ewl_tree2_column_append(EWL_TREE2(tree), model, view);
+ * @endcode
+ *
+ * The second column in the tree is created the same as the first except we use
+ * the Ewl_Image functions instead of the Ewl_Label functions. You can use any
+ * widget within EWL to setup a view. This gives the tree the flexibility of
+ * being able to display any desired widget, even custom designed widgets.
+ *
+ * @code
+ *      // we don't want this one sortable
+ *      model = ewl_model_new();
+ *      ewl_model_fetch_set(model, test_data_fetch);
+ *      ewl_model_count_set(model, test_data_count_get);
+ *
+ *      // create a view for the third column that has a custom widget
+ *      view = ewl_view_new();
+ *      ewl_view_constructor_set(view, test_custom_new);
+ *      ewl_view_assign_set(view, test_custom_assign_set);
+ *      ewl_view_header_fetch_set(view, test_data_header_fetch);
+ *      ewl_tree2_column_append(EWL_TREE2(tree), model, view);
+ * @endcode
+ *
+ * The third column in the tree is similar to the first two except we dont want
+ * it sortable. So, we create a new Ewl_Model and set the fetch and count
+ * functions as before but skip the sort function. We then create the view and
+ * use our custom constructor and assignment functions instead of a standard 
EWL
+ * set. With the model and view created we append the column into the tree.
+ *
+ * @code
+ *      // create the checkbuttons for the top box
+ *      o = ewl_checkbutton_new();
+ *      ewl_button_label_set(EWL_BUTTON(o), "Scroll headers");
+ *      ewl_container_child_append(EWL_CONTAINER(o2), o);
+ *      ewl_callback_append(o, EWL_CALLBACK_CLICKED, cb_scroll_headers, tree);
+ *      ewl_widget_show(o);
+ *
+ *      o = ewl_checkbutton_new();
+ *      ewl_button_label_set(EWL_BUTTON(o), "Scroll visible");
+ *      ewl_container_child_append(EWL_CONTAINER(o2), o);
+ *      ewl_checkbutton_checked_set(EWL_CHECKBUTTON(o), TRUE);
+ *      ewl_callback_append(o, EWL_CALLBACK_CLICKED, cb_scroll_visible, tree);
+ *      ewl_widget_show(o);
+ * @endcode
+ *
+ * The final piece of the UI to be added are the two checkbuttons. These will 
be
+ * used to change some settings of the tree so we can see some of the different
+ * options. The both respond to EWL_CALLBACK_CLICKED callbacks the first 
calling
+ * the cb_scroll_headers() function and the second calling cb_scroll_visible()
+ * function.
+ *
+ * @code
+ *      ewl_main();
+ *      return 0;
+ * }
+ * @endcode
+ *
+ * Finally we call ewl_main() to kick off the main EWL event loop. When
+ * ewl_main() is done then were finished so just return. ewl_main_quit() will
+ * actually call ewl_shutdown() for us so we dont have to worry about it.
+ *
+ * Ok, with our UI out of the way all we need to deal with are all the
+ * functions weve referenced. First up is creating our data. For this
+ * example were just using an array but the thing to keep in mind is you can 
use
+ * anything to store your data. EWL never accesses this data directly it always
+ * does it through the calls you specified. So, if you want to use an Evas_List
+ * or an Ecore_List or a tree or some other structure its up to you. EWL doesnt
+ * care.
+ *
+ * @code
+ * // setup our data
+ * static void *
+ * test_data_setup(void)
+ * {
+ *          Test_Data *data;
+ *          Test_Row_Data **dt;
+ *
+ *          data = calloc(1, sizeof(Test_Data));
+ *          dt = calloc(DATA_ELEMENTS, sizeof(Test_Row_Data *));
+ *
+ *          dt[0] = calloc(1, sizeof(Test_Row_Data));
+ *          dt[0]->image = strdup("/usr/local/share/ewl/images/e-logo.png");
+ *          dt[0]->text = strdup("The E logo");
+ *
+ *          dt[1] = calloc(1, sizeof(Test_Row_Data));
+ *          dt[1]->image = strdup("/usr/local/share/ewl/images/elicit.png");
+ *          dt[1]->text = strdup("The Elicit image");
+ *
+ *          dt[2] = calloc(1, sizeof(Test_Row_Data));
+ *          dt[2]->image = strdup("/usr/local/share/ewl/images/entrance.png");
+ *          dt[2]->text = strdup("The Entrance image");
+ *
+ *          dt[3] = calloc(1, sizeof(Test_Row_Data));
+ *          dt[3]->image = strdup("/usr/local/share/ewl/images/End.png");
+ *          dt[3]->text = strdup("Zebra");
+ *
+ *          dt[4] = calloc(1, sizeof(Test_Row_Data));
+ *          dt[4]->image = 
strdup("/usr/local/share/ewl/images/banner-top.png");
+ *          dt[4]->text = strdup("Ant");
+ *
+ *          data->rows = dt;
+ *          data->count = DATA_ELEMENTS;
+ *
+ *          return data;
+ * }
+ * @endcode
+ *
+ * Nothing fancy in there so Im not going to bother explaining it.
+ *
+ * @code
+ * static Ewl_Widget *
+ * test_custom_new(void)
+ * {
+ *      Ewl_Widget *button;
+ *
+ *      button = ewl_button_new();
+ *
+ *      return button;
+ * }
+ * @endcode
+ *
+ * As I mentioned for our third column were using a custom constructor and
+ * assignment calls. The reason for this, since we just want a simple button, 
is
+ * that we want to set two pieces of data into the widget instead of just one.
+ * We could actually just use ewl_button_new() in the view and have a custom
+ * assignment function, but this makes for a better example. For the 
constructor
+ * all we do is create our widget and return it. Its as simple as that.
+ *
+ * @code
+ * static void
+ * test_custom_assign_set(Ewl_Widget *w, void *data)
+ * {
+ *      Test_Row_Data *d;
+ *
+ *      d = data;
+ *      ewl_button_label_set(EWL_BUTTON(w), d->text);
+ *      ewl_button_image_set(EWL_BUTTON(w), d->image, NULL);
+ * }
+ * @endcode
+ *
+ * For the assignment part of the custom widget EWL will provide the widget
+ * created with the view, w, and the piece of data that the rows model returned
+ * for the current cell in the tree, data. Using these we can setup the widget
+ * however we see fit. In this case were setting the label and image of the
+ * button.
+ *
+ * @code
+ * static Ewl_Widget *
+ * test_data_header_fetch(void *data , int column)
+ * {
+ *      Ewl_Widget *l;
+ *
+ *      l = ewl_label_new();
+ *      if (column == 0)
+ *          ewl_label_text_set(EWL_LABEL(l), "Title");
+ *      else if (column == 1)
+ *          ewl_label_text_set(EWL_LABEL(l), "Image");
+ *      else
+ *          ewl_label_text_set(EWL_LABEL(l), "Button");
+ *
+ *      ewl_widget_show(l);
+ *
+ *      return l;
+ * }
+ * @endcode
+ *
+ * The last view function we need to worry about is
+ * test_data_header_fetch(). EWL will call this function for each column to get
+ * the widget to display in the header. The data pointer is the data set on the
+ * tree itself and the column is the column number to return the header for
+ * (column numbers start at 0).
+ *
+ * In this case were just creating an Ewl_Label and setting and appropriate bit
+ * of text to describe the column.
+ *
+ * Not too bad so far, right?
+ *
+ * With the view code out of the way lets move on to model code. We start with
+ * the fetch function. This is called whenever EWL needs to know what
+ * information to pass to the views assign function.
+ *
+ * @code
+ * static void *
+ * test_data_fetch(void *data, unsigned int row, unsigned int column)
+ * {
+ *      Test_Data *d;
+ *      void *val = NULL;
+ *
+ *      d = data;
+ *
+ *      if (column == 0)
+ *          val = d->rows[row]->text;
+ *      else if (column == 1)
+ *          val = d->rows[row]->image;
+ *      else if (column == 2)
+ *          val = d->rows[row]; 
+ *
+ *      return val;
+ * }
+ * @endcode
+ *
+ * The fetch function returns a void * as EWL is making no assumptions about
+ * what type of data youll need to pass into your assign function. In this case
+ * we return a char * for the first two columns and a Tree_Row_Data * struct 
for
+ * the third column. The fetch function is passed the data set into the tree,
+ * the row and the column that we are interested in.
+ *
+ * If youve set a sort function into your model then the tree headers become
+ * clickable. When the user clicks a header the sort function is called for the
+ * given column. With this app Im just using a simple bubble sort. Youll
+ * possibly want to use something a bit better for a real application.
+ *
+ * @code
+ * static void
+ * test_data_sort(void *data, unsigned int column, Ewl_Sort_Direction sort)
+ * {
+ *      Test_Data *d;
+ *      int i;
+ *
+ *      // just leave it if we're in sort none.
+ *      if (sort == EWL_SORT_DIRECTION_NONE)
+ *          return;
+ *
+ *      d = data;
+ *
+ *      for (i = (DATA_ELEMENTS - 1); i >= 0; i--)
+ *      {
+ *          int j;
+ *
+ *          for (j = 1; j <= i; j++)
+ *          {
+ *              char *a, *b;
+ *
+ *              if (column == 0)
+ *              {
+ *                  a = d->rows[j - 1]->text;
+ *                  b = d->rows[j]->text;
+ *              }
+ *              else
+ *              {
+ *                  a = d->rows[j - 1]->image;
+ *                  b = d->rows[j]->image;
+ *              }
+ *
+ *              if (((sort == EWL_SORT_DIRECTION_ASCENDING) && strcmp(a, b) > 
0)
+ *                      || ((sort == EWL_SORT_DIRECTION_DESCENDING)
+ *                          && strcmp(a, b) < 0))
+ *              {
+ *                  char *temp;
+ *
+ *                  temp = d->rows[j - 1]->text;
+ *                  d->rows[j - 1]->text = d->rows[j]->text;
+ *                  d->rows[j]->text = temp;
+ *
+ *                  temp = d->rows[j - 1]->image;
+ *                  d->rows[j - 1]->image = d->rows[j]->image;
+ *                  d->rows[j]->image = temp;
+ *              }
+ *          }
+ *      }
+ * }
+ * @endcode
+ *
+ * The sort call has three parameters. The the data we set on the tree, the
+ * column number that we are sorting and the direction of the sort. The three
+ * possible sort directions are EWL_SORT_DIRECTION_NONE,
+ * EWL_SORT_DIRECTION_ASCENDING and EWL_SORT_DIRECTION_DESCENDING. In this 
case,
+ * we dont bother doing anything if we are set to a sort of
+ * EWL_SORT_DIRECTION_NONE. We then sort the data as needed in either ascending
+ * or descending order based on the sort parameter.
+ *
+ * @code
+ * static int
+ * test_data_count_get(void *data)
+ * {
+ *      Test_Data *d;
+ *
+ *      d = data;
+ *
+ *      return d->count;
+ * }
+ * @endcode
+ *
+ * The last model function we need to implement is the count function. This is
+ * just a way for your application to tell EWL how many rows are in your data.
+ * In this case we just return the count parameter.
+ *
+ * Thats it for the model code. All thats left are the three callbacks we
+ * defined for the UI.
+ *
+ * @code
+ * static void
+ * cb_delete_window(Ewl_Widget *w, void *ev, void *data)
+ * {
+ *      ewl_widget_destroy(w);
+ *      ewl_main_quit();
+ * }
+ * @endcode
+ *
+ * cb_delete_window() will be called when the window is deleted. All we do is
+ * destroy the window with a call to ewl_widget_destroy() and quit the
+ * application with ewl_main_quit(). Because we attached this callback to the
+ * Ewl_Window widget the first parameter *w is our window. You dont technically
+ * need to ewl_widget_destroy() the window but its nice to clean up after
+ * yourself.
+ *
+ * @code
+ * static void
+ * cb_scroll_headers(Ewl_Widget *w, void *ev , void *data)
+ * {
+ *      Ewl_Tree2 *tree;
+ *
+ *      tree = data;
+ *      ewl_tree2_scroll_headers_set(tree, 
ewl_checkbutton_is_checked(EWL_CHECKBUTTON(w)));
+ * }
+ * @endcode
+ *
+ * The cb_scroll_headers() function toggles if the headers in the tree should 
be
+ * scrolled. This is done by calling ewl_tree2_scroll_headers_set() and passing
+ * either TRUE or FALSE depending on if we want the headers scrolled. This is
+ * conveniently the same as the return of ewl_checkbutton_is_checked().
+ *
+ * @code
+ * static void
+ * cb_scroll_visible(Ewl_Widget *w, void *ev , void *data)
+ * {
+ *      Ewl_Tree2 *tree;
+ *
+ *      tree = data;
+ *      ewl_tree2_scroll_visible_set(tree, 
ewl_checkbutton_is_checked(EWL_CHECKBUTTON(w)));
+ * }
+ * @endcode
+ *
+ * The cb_scroll_visible() function works in the same way as the
+ * cb_scroll_headers() function except that it either enables or disables the
+ * display of the scrollbars in the tree.
+ *
+ * With that, were at the end of our code. If you use the compilation line 
given
+ * above everything should work out and when you run the app you should seeing
+ * something similar too:
+ *
+ * Hopefully that wasnt too painful and you can see how easily it is to work
+ * with the new Ewl_Tree2 code.
+ *
+ * Oh, before I forget. If you're updating your model and you want EWL to 
redraw
+ * the tree you just need to call ewl_tree2_dirty_set() and pass TRUE as the
+ * second parameter. This will signal EWL that something has changed in the
+ * model and the tree will be redrawn.
+ */
+
 #define TREE2_DATA_ELEMENTS 5
 
 typedef struct Tree2_Test_Row_Data Tree2_Test_Row_Data;
@@ -12,6 +930,7 @@
 {
        char *image;
        char *text;
+       Tree2_Test_Row_Data *subdata;
 
        int expandable;
        Tree2_Test_Row_Data **rows;
@@ -119,6 +1038,7 @@
 
        /* create the checkbuttons for the top box */
        o = ewl_checkbutton_new();
+       ewl_object_alignment_set(EWL_OBJECT(o), EWL_FLAG_ALIGN_CENTER);
        ewl_button_label_set(EWL_BUTTON(o), "Scroll headers");
        ewl_container_child_append(EWL_CONTAINER(o2), o);
        ewl_callback_append(o, EWL_CALLBACK_CLICKED, 
@@ -126,6 +1046,7 @@
        ewl_widget_show(o);
 
        o = ewl_checkbutton_new();
+       ewl_object_alignment_set(EWL_OBJECT(o), EWL_FLAG_ALIGN_CENTER);
        ewl_button_label_set(EWL_BUTTON(o), "Plain view");
        ewl_container_child_append(EWL_CONTAINER(o2), o);
        ewl_callback_append(o, EWL_CALLBACK_CLICKED,
@@ -133,6 +1054,7 @@
        ewl_widget_show(o);
 
        o = ewl_spinner_new();
+       ewl_object_alignment_set(EWL_OBJECT(o), EWL_FLAG_ALIGN_CENTER);
        ewl_container_child_append(EWL_CONTAINER(o2), o);
        ewl_spinner_digits_set(EWL_SPINNER(o), 0);
        ewl_range_minimum_value_set(EWL_RANGE(o), 0);
@@ -143,6 +1065,7 @@
        ewl_widget_show(o);
 
        o = ewl_button_new();
+       ewl_object_alignment_set(EWL_OBJECT(o), EWL_FLAG_ALIGN_CENTER);
        ewl_button_label_set(EWL_BUTTON(o), "Set number of rows");
        ewl_container_child_append(EWL_CONTAINER(o2), o);
        ewl_callback_append(o, EWL_CALLBACK_CLICKED, 
@@ -150,6 +1073,7 @@
        ewl_widget_show(o);
 
        o = ewl_button_new();
+       ewl_object_alignment_set(EWL_OBJECT(o), EWL_FLAG_ALIGN_CENTER);
        ewl_button_label_set(EWL_BUTTON(o), "Row select");
        ewl_container_child_append(EWL_CONTAINER(o2), o);
        ewl_callback_append(o, EWL_CALLBACK_CLICKED, 
@@ -176,7 +1100,11 @@
        dt[1] = calloc(1, sizeof(Tree2_Test_Row_Data));
        dt[1]->image = strdup(PACKAGE_DATA_DIR"/ewl/images/elicit.png");
        dt[1]->text = strdup("The Elicit image");
-       dt[1]->expandable = 0;
+       dt[1]->expandable = 1;
+
+       dt[1]->subdata = calloc(1, sizeof(Tree2_Test_Row_Data));
+       dt[1]->subdata->image = 
strdup(PACKAGE_DATA_DIR"/ewl/images/e-logo.png");
+       dt[1]->subdata->text = strdup("The E logo");
 
        dt[2] = calloc(1, sizeof(Tree2_Test_Row_Data));
        dt[2]->image = strdup(PACKAGE_DATA_DIR"/ewl/images/entrance.png");
@@ -338,7 +1266,8 @@
 
        d = data;
 
-       return d->rows[row]->expandable;
+       printf("Data %p row %d\n", d, row);
+       return (d ? (d->rows[row] ? d->rows[row]->expandable : FALSE) : FALSE);
 }
 
 static void *



-------------------------------------------------------------------------
Take Surveys. Earn Cash. Influence the Future of IT
Join SourceForge.net's Techsay panel and you'll get the chance to share your
opinions on IT & business topics through brief surveys - and earn cash
http://www.techsay.com/default.php?page=join.php&p=sourceforge&CID=DEVDEV
_______________________________________________
enlightenment-cvs mailing list
enlightenment-cvs@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/enlightenment-cvs

Reply via email to