Enlightenment CVS committal

Author  : dj2
Project : e17
Module  : libs/ewl

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


Modified Files:
        Makefile.am ewl_tree_test.c 


Log Message:
- API BREAK -- move tree2 over to tree

===================================================================
RCS file: /cvs/e/e17/libs/ewl/src/bin/tests/tree/Makefile.am,v
retrieving revision 1.3
retrieving revision 1.4
diff -u -3 -r1.3 -r1.4
--- Makefile.am 4 Dec 2007 05:28:05 -0000       1.3
+++ Makefile.am 11 Dec 2007 05:51:21 -0000      1.4
@@ -6,6 +6,7 @@
 -I$(top_builddir)/src/lib \
 -I$(top_srcdir)/src/bin \
 -I$(top_builddir)/src/bin \
+-DPACKAGE_DATA_DIR=\"$(datadir)\" \
 @EDJE_CFLAGS@ \
 @ECORE_CFLAGS@ \
 @EVAS_CFLAGS@ \
===================================================================
RCS file: /cvs/e/e17/libs/ewl/src/bin/tests/tree/ewl_tree_test.c,v
retrieving revision 1.1
retrieving revision 1.2
diff -u -3 -r1.1 -r1.2
--- ewl_tree_test.c     4 Dec 2007 05:28:05 -0000       1.1
+++ ewl_tree_test.c     11 Dec 2007 05:51:21 -0000      1.2
@@ -2,19 +2,974 @@
 #include "Ewl_Test.h"
 #include "ewl_test_private.h"
 #include "ewl_button.h"
+#include "ewl_checkbutton.h"
+#include "ewl_image.h"
+#include "ewl_label.h"
+#include "ewl_spinner.h"
 #include "ewl_tree.h"
+#include "ewl_tree_view_plain.h"
+#include "ewl_tree_view_scrolled.h"
 
 #include <stdio.h>
-#include <limits.h>
-#include <string.h>
 #include <stdlib.h>
+#include <string.h>
+
+/**
+ * @addtogroup Ewl_Tree
+ * @section tree_tut Tutorial
+ *
+ * Finding the Tree in the Forest
+ * (originally at http://everburning.com/news/finding-the-tree-in-the-forest)
+ * We've been doing a bunch of work on Ewl_Tree 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_Tree 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_Tree. They are, Ewl_Tree, 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 tree 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 tree_test.c and using the following to compile
+ * the code as I go.
+ *
+ * @code
+ * oni:~/dev/tree_test$ gcc -o tree_test tree_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, unsigned 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 unsigned 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), "tree example");
+ *      ewl_window_class_set(EWL_WINDOW(o), "tree_example");
+ *      ewl_window_name_set(EWL_WINDOW(o), "tree_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_data_fetch_set(model, test_data_fetch);
+ *      ewl_model_data_sort_set(model, test_data_sort);
+ *      ewl_model_data_count_set(model, test_data_count_get);
+ *
+ *      tree = ewl_tree_new();
+ *      ewl_container_child_append(EWL_CONTAINER(box), tree);
+ *      ewl_object_fill_policy_set(EWL_OBJECT(tree), EWL_FLAG_FILL_ALL);
+ *      ewl_tree_data_set(EWL_TREE(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_tree_column_append(EWL_TREE(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_tree_column_append(EWL_TREE(tree), model, view);
+ *
+ *      // we don't want this one sortable
+ *      model = ewl_model_new();
+ *      ewl_model_data_fetch_set(model, test_data_fetch);
+ *      ewl_model_data_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_tree_column_append(EWL_TREE(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 , unsigned 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 unsigned 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_Tree *tree;
+ *
+ *      tree = data;
+ *      ewl_tree_scroll_headers_set(tree,
+ *              ewl_checkbutton_is_checked(EWL_CHECKBUTTON(w)));
+ * }
+ *
+ * static void
+ * cb_scroll_visible(Ewl_Widget *w, void *ev , void *data)
+ * {
+ *      Ewl_Tree *tree;
+ *
+ *      tree = data;
+ *      ewl_tree_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, unsigned 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 unsigned 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), "tree example");
+ *      ewl_window_class_set(EWL_WINDOW(o), "tree_example");
+ *      ewl_window_name_set(EWL_WINDOW(o), "tree_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 640x480. 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_data_fetch_set(model, test_data_fetch);
+ *      ewl_model_data_sort_set(model, test_data_sort);
+ *      ewl_model_data_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_data_fetch_set(), and the function
+ * to get a count of the number of rows of data, set with
+ * ewl_model_data_count_set(). I'm using the third ewl_model_data_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_tree_new();
+ *      ewl_container_child_append(EWL_CONTAINER(box), tree);
+ *      ewl_object_fill_policy_set(EWL_OBJECT(tree), EWL_FLAG_FILL_ALL);
+ *      ewl_tree_data_set(EWL_TREE(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_tree_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_tree_column_append(EWL_TREE(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_tree_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_tree_column_append(EWL_TREE(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_data_fetch_set(model, test_data_fetch);
+ *      ewl_model_data_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_tree_column_append(EWL_TREE(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 unsigned 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_Tree *tree;
+ *
+ *      tree = data;
+ *      ewl_tree_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_tree_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_Tree *tree;
+ *
+ *      tree = data;
+ *      ewl_tree_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_Tree 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_tree_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 TREE_DATA_ELEMENTS 5
+
+typedef struct Tree_Test_Data Tree_Test_Data;
+typedef struct Tree_Test_Row_Data Tree_Test_Row_Data;
+struct Tree_Test_Row_Data
+{
+       char *image;
+       char *text;
+       Tree_Test_Data *subdata;
+
+       int expandable;
+};
 
-#define ROWS 50
-#define COLS 4
-#define NEST 3
+struct Tree_Test_Data
+{
+       unsigned int count;
+       unsigned int row_count;
+       Tree_Test_Row_Data **rows;
+};
 
-static int create_test(Ewl_Container *box);
-static void cb_get_rows(Ewl_Widget *w, void *ev, void *data);
+static int create_test(Ewl_Container *win);
+static void *tree_test_data_setup(void);
+static Ewl_Widget *tree_test_cb_widget_fetch(void *data, unsigned int row,
+                                               unsigned int column);
+static void *tree_test_cb_header_data_fetch(void *data, unsigned int column);
+static Ewl_Widget *tree_test_cb_header_fetch(void *data, unsigned int column);
+static void *tree_test_data_fetch(void *data, unsigned int row,
+                                               unsigned int column);
+static int tree_test_column_sortable(void *data, unsigned int column);
+static void tree_test_data_sort(void *data, unsigned int column,
+                                               Ewl_Sort_Direction sort);
+static unsigned int tree_test_data_count_get(void *data);
+static int tree_test_data_expandable_get(void *data, unsigned int row);
+static void *tree_test_data_expansion_fetch(void *data, unsigned int row);
+
+static void ewl_tree_cb_scroll_headers(Ewl_Widget *w, void *ev, void *data);
+static void ewl_tree_cb_hide_headers(Ewl_Widget *w, void *ev, void *data);
+static void ewl_tree_cb_plain_view(Ewl_Widget *w, void *ev, void *data);
+static void ewl_tree_cb_set_rows_clicked(Ewl_Widget *w, void *ev, void *data);
+static void tree_cb_value_changed(Ewl_Widget *w, void *ev, void *data);
+static void tree_cb_select_mode_change(Ewl_Widget *w, void *ev, void *data);
 
 void
 test_info(Ewl_Test *test)
@@ -30,88 +985,503 @@
 static int
 create_test(Ewl_Container *box)
 {
-       int row, col;
-       char buf[PATH_MAX];
-       char *headers[COLS], *entries[COLS];
-       Ewl_Widget *tree, *prow = NULL;
-       Ewl_Widget *hbox, *button;
-
-       hbox = ewl_hbox_new();
-       ewl_container_child_append(EWL_CONTAINER(box), hbox);
-       ewl_object_fill_policy_set(EWL_OBJECT(hbox), EWL_FLAG_FILL_SHRINK |
-                                                   EWL_FLAG_FILL_HFILL);
-       ewl_widget_show(hbox);
-
-       tree = ewl_tree_new(COLS);
-       ewl_tree_mode_set(EWL_TREE(tree), EWL_SELECTION_MODE_SINGLE);
-
-       button = ewl_button_new();
-       ewl_button_label_set(EWL_BUTTON(button), "Number of selected rows");
-       ewl_container_child_append(EWL_CONTAINER(hbox), button);
-       ewl_object_fill_policy_set(EWL_OBJECT(button), EWL_FLAG_FILL_HFILL);
-       ewl_callback_append(button, EWL_CALLBACK_CLICKED, cb_get_rows, tree);
-       ewl_widget_show(button);
-
-       button = ewl_button_new();
-       ewl_button_label_set(EWL_BUTTON(button), "Clear selection");
-       ewl_container_child_append(EWL_CONTAINER(hbox), button);
-       ewl_object_fill_policy_set(EWL_OBJECT(button), EWL_FLAG_FILL_HFILL);
-       ewl_callback_append(button, EWL_CALLBACK_CLICKED, cb_get_rows, tree);
-       ewl_widget_show(button);
+       Ewl_Widget *tree, *o, *o2, *o3;
+       Ewl_Model *model;
+       Ewl_View *view;
+       void *data;
 
-       for (col = 0; col < COLS; col++)
-       {
-               snprintf(buf, PATH_MAX, "Column %d", col);
-               headers[col] = strdup(buf);
-       }
+       o2 = ewl_hbox_new();
+       ewl_container_child_append(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 = tree_test_data_setup();
+
+       /* the tree will only use one model. We could use a model per
+        * column, but a single model will work fine for this test */
+       model = ewl_model_new();
+       ewl_model_data_fetch_set(model, tree_test_data_fetch);
+       ewl_model_data_header_fetch_set(model,
+                               tree_test_cb_header_data_fetch);
+       ewl_model_data_sort_set(model, tree_test_data_sort);
+       ewl_model_column_sortable_set(model, tree_test_column_sortable);
+       ewl_model_data_count_set(model, tree_test_data_count_get);
+       ewl_model_data_expandable_set(model, tree_test_data_expandable_get);
+       ewl_model_expansion_data_fetch_set(model,
+                               tree_test_data_expansion_fetch);
 
+       view = ewl_view_new();
+       ewl_view_widget_fetch_set(view, tree_test_cb_widget_fetch);
+       ewl_view_header_fetch_set(view, tree_test_cb_header_fetch);
+
+       tree = ewl_tree_new();
        ewl_container_child_append(EWL_CONTAINER(box), tree);
-       ewl_tree_headers_set(EWL_TREE(tree), headers);
+       ewl_object_fill_policy_set(EWL_OBJECT(tree), EWL_FLAG_FILL_ALL);
+       ewl_callback_append(tree, EWL_CALLBACK_VALUE_CHANGED,
+                                       tree_cb_value_changed, NULL);
+       ewl_mvc_data_set(EWL_MVC(tree), data);
+       ewl_mvc_model_set(EWL_MVC(tree), model);
+       ewl_mvc_view_set(EWL_MVC(tree), view);
+       ewl_mvc_selection_mode_set(EWL_MVC(tree), EWL_SELECTION_MODE_MULTI);
+       ewl_tree_column_count_set(EWL_TREE(tree), 3);
+       ewl_tree_row_expand(EWL_TREE(tree), data, 2);
+       ewl_widget_name_set(tree, "tree");
        ewl_widget_show(tree);
 
-       memset(entries, 0, COLS * sizeof(char *));
+       o3 = ewl_vbox_new();
+       ewl_container_child_append(EWL_CONTAINER(o2), o3);
+       ewl_widget_show(o3);
+
+       /* create the checkbuttons for the top box */
+       o = ewl_checkbutton_new();
+       ewl_object_alignment_set(EWL_OBJECT(o), EWL_FLAG_ALIGN_LEFT);
+       ewl_button_label_set(EWL_BUTTON(o), "Scroll headers");
+       ewl_container_child_append(EWL_CONTAINER(o3), o);
+       ewl_callback_append(o, EWL_CALLBACK_CLICKED,
+                               ewl_tree_cb_scroll_headers, tree);
+       ewl_widget_show(o);
+
+       o = ewl_checkbutton_new();
+       ewl_object_alignment_set(EWL_OBJECT(o), EWL_FLAG_ALIGN_LEFT);
+       ewl_button_label_set(EWL_BUTTON(o), "Hide headers");
+       ewl_container_child_append(EWL_CONTAINER(o3), o);
+       ewl_callback_append(o, EWL_CALLBACK_CLICKED,
+                               ewl_tree_cb_hide_headers, tree);
+       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,
+                               ewl_tree_cb_plain_view, tree);
+       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);
+       ewl_range_maximum_value_set(EWL_RANGE(o), 10000);
+       ewl_range_value_set(EWL_RANGE(o), 5);
+       ewl_range_step_set(EWL_RANGE(o), 1);
+       ewl_widget_name_set(o, "rows_spinner");
+       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,
+                               ewl_tree_cb_set_rows_clicked, NULL);
+       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,
+                               tree_cb_select_mode_change, NULL);
+       ewl_widget_show(o);
+
+       return 1;
+}
+
+static void *
+tree_test_data_setup(void)
+{
+       Tree_Test_Data *data;
+       Tree_Test_Row_Data **dt;
+
+       data = calloc(1, sizeof(Tree_Test_Data));
+       dt = calloc(TREE_DATA_ELEMENTS, sizeof(Tree_Test_Row_Data *));
+
+       dt[0] = calloc(1, sizeof(Tree_Test_Row_Data));
+       dt[0]->image = strdup(PACKAGE_DATA_DIR"/ewl/images/e-logo.png");
+       dt[0]->text = strdup("The E logo");
+       dt[0]->expandable = 0;
+
+       dt[1] = calloc(1, sizeof(Tree_Test_Row_Data));
+       dt[1]->image = strdup(PACKAGE_DATA_DIR"/ewl/images/elicit.png");
+       dt[1]->text = strdup("The Elicit image");
+       dt[1]->expandable = 1;
+
+       dt[1]->subdata = calloc(1, sizeof(Tree_Test_Data));
+       dt[1]->subdata->count = 1;
+       dt[1]->subdata->row_count = 1;
+       dt[1]->subdata->rows = calloc(dt[1]->subdata->count, 
sizeof(Tree_Test_Row_Data *));
+       dt[1]->subdata->rows[0] = calloc(1, sizeof(Tree_Test_Row_Data));
+       dt[1]->subdata->rows[0]->image = 
strdup(PACKAGE_DATA_DIR"/ewl/images/e-logo.png");
+       dt[1]->subdata->rows[0]->text = strdup("The First Subrow");
+
+       dt[2] = calloc(1, sizeof(Tree_Test_Row_Data));
+       dt[2]->image = strdup(PACKAGE_DATA_DIR"/ewl/images/entrance.png");
+       dt[2]->text = strdup("The Entrance image");
+       dt[2]->expandable = 1;
+
+       dt[2]->subdata = calloc(1, sizeof(Tree_Test_Data));
+       dt[2]->subdata->count = 6;
+       dt[2]->subdata->row_count = 6;
+       dt[2]->subdata->rows = calloc(dt[2]->subdata->count, 
sizeof(Tree_Test_Row_Data *));
+       dt[2]->subdata->rows[0] = calloc(1, sizeof(Tree_Test_Row_Data));
+       dt[2]->subdata->rows[0]->image = 
strdup(PACKAGE_DATA_DIR"/ewl/images/e-logo.png");
+       dt[2]->subdata->rows[0]->text = strdup("Squee. 1.");
+       dt[2]->subdata->rows[1] = calloc(1, sizeof(Tree_Test_Row_Data));
+       dt[2]->subdata->rows[1]->image = 
strdup(PACKAGE_DATA_DIR"/ewl/images/e-logo.png");
+       dt[2]->subdata->rows[1]->text = strdup("Splat. 2.");
+       dt[2]->subdata->rows[2] = calloc(1, sizeof(Tree_Test_Row_Data));
+       dt[2]->subdata->rows[2]->image = 
strdup(PACKAGE_DATA_DIR"/ewl/images/e-logo.png");
+       dt[2]->subdata->rows[2]->text = strdup("Squee. 3.");
+       dt[2]->subdata->rows[3] = calloc(1, sizeof(Tree_Test_Row_Data));
+       dt[2]->subdata->rows[3]->image = 
strdup(PACKAGE_DATA_DIR"/ewl/images/e-logo.png");
+       dt[2]->subdata->rows[3]->text = strdup("Splat. 4.");
+       dt[2]->subdata->rows[4] = calloc(1, sizeof(Tree_Test_Row_Data));
+       dt[2]->subdata->rows[4]->image = 
strdup(PACKAGE_DATA_DIR"/ewl/images/e-logo.png");
+       dt[2]->subdata->rows[4]->text = strdup("Squee. 5.");
+       dt[2]->subdata->rows[5] = calloc(1, sizeof(Tree_Test_Row_Data));
+       dt[2]->subdata->rows[5]->image = 
strdup(PACKAGE_DATA_DIR"/ewl/images/e-logo.png");
+       dt[2]->subdata->rows[5]->text = strdup("Splat. 6.");
+
+       dt[3] = calloc(1, sizeof(Tree_Test_Row_Data));
+       dt[3]->image = strdup(PACKAGE_DATA_DIR"/ewl/images/End.png");
+       dt[3]->text = strdup("Zebra");
+       dt[3]->expandable = 0;
+
+       dt[4] = calloc(1, sizeof(Tree_Test_Row_Data));
+       dt[4]->image = strdup(PACKAGE_DATA_DIR"/ewl/images/banner-top.png");
+       dt[4]->text = strdup("Ant");
+       dt[4]->expandable = 0;
+
+       data->rows = dt;
+       data->count = TREE_DATA_ELEMENTS;
+       data->row_count = TREE_DATA_ELEMENTS;
+
+       return data;
+}
+
+static Ewl_Widget *
+tree_test_cb_widget_fetch(void *data, unsigned int row __UNUSED__,
+                                       unsigned int column)
+{
+       Ewl_Widget *w = NULL;
+
+       switch (column) {
+               case 0:
+                       w = ewl_label_new();
+                       ewl_label_text_set(EWL_LABEL(w), data);
+                       break;
+               case 1:
+                       w = ewl_image_new();
+                       ewl_image_file_path_set(EWL_IMAGE(w), data);
+                       break;
+               case 2:
+                       {
+                               Tree_Test_Row_Data *d;
+                               d = data;
 
-       for (row = 0; row < ROWS; row++)
+                               w = ewl_button_new();
+                               ewl_button_label_set(EWL_BUTTON(w), d->text);
+                               ewl_button_image_set(EWL_BUTTON(w), d->image, 
NULL);
+                       }
+                       break;
+       }
+       ewl_widget_show(w);
+
+       return w;
+}
+
+static void *
+tree_test_cb_header_data_fetch(void *data __UNUSED__, unsigned int column)
+{
+       if (column == 0)
+               return "Title";
+
+       if (column == 1)
+               return "Image";
+
+       return "Button";
+}
+
+static Ewl_Widget *
+tree_test_cb_header_fetch(void *data, unsigned int column __UNUSED__)
+{
+       Ewl_Widget *l;
+
+       l = ewl_label_new();
+       ewl_label_text_set(EWL_LABEL(l), data);
+       ewl_widget_show(l);
+
+       return l;
+}
+
+static void *
+tree_test_data_fetch(void *data, unsigned int row, unsigned int column)
+{
+       Tree_Test_Data *d;
+       void *val = NULL;
+
+       d = data;
+
+       /* NOTE: this is just for testing purposes, should not be needed in a
+        * normal app */
+       if (row >= d->row_count)
        {
+               printf("Asking for too many rows %d (count == %d)\n",
+                                                       row, d->row_count);
+               return NULL;
+       }
 
-               for (col = 0; col < COLS; col++)
-               {
-                       snprintf(buf, 1024, "Row %d Col %d", row, col);
-                       entries[col] = strdup(buf);
-               }
+       if (column == 0)
+               val = d->rows[row % d->count]->text;
 
-               if (row % NEST == 0)
-                       prow = ewl_tree_text_row_add(EWL_TREE(tree), NULL,
-                                       entries);
-               else
-                       prow = ewl_tree_text_row_add(EWL_TREE(tree),
-                                       EWL_ROW(prow), entries);
+       else if (column == 1)
+               val = d->rows[row % d->count]->image;
 
-               for (col = 0; col < COLS; col++)
-               {
-                       if (entries[col])
-                               free(entries[col]);
-                       entries[col] = NULL;
-               }
+       else if (column == 2)
+               val = d->rows[row % d->count];
+
+       else
+       {
+               /* NOTE: this is just for testing purposes, should not be
+                * needed in a normal app */
+               printf("Unknown column %d\n", column);
        }
 
-       for (col = 0; col < COLS; col++)
+       return val;
+}
+
+static void
+tree_test_data_sort(void *data, unsigned int column, Ewl_Sort_Direction sort)
+{
+       int i;
+       Tree_Test_Data *d;
+
+       /* just leave it if we're in sort none. */
+       if (sort == EWL_SORT_DIRECTION_NONE)
+               return;
+
+       d = data;
+
+       for (i = (d->count - 1); i >= 0; i--)
        {
-               if (headers[col])
-                       free(headers[col]);
+               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;
+                       }
+               }
        }
+}
 
-       return 1;
+static int
+tree_test_column_sortable(void *data __UNUSED__, unsigned int column)
+{
+       return ((column == 0) || (column == 1));
+}
+
+static unsigned int
+tree_test_data_count_get(void *data)
+{
+       Tree_Test_Data *d;
+
+       d = data;
+
+       return d->row_count;
+}
+
+static int
+tree_test_data_expandable_get(void *data, unsigned int row)
+{
+       Tree_Test_Data *d;
+       int ret = FALSE;
+
+       d = data;
+
+       if (d && d->rows[row % d->count])
+               ret = d->rows[row % d->count]->expandable;
+
+       return ret;
+}
+
+static void *
+tree_test_data_expansion_fetch(void *data, unsigned int parent)
+{
+       Tree_Test_Data *d;
+
+       d = data;
+
+       return d->rows[parent]->subdata;
 }
 
+
 static void
-cb_get_rows(Ewl_Widget *w __UNUSED__, void *ev __UNUSED__, void *data)
+ewl_tree_cb_scroll_headers(Ewl_Widget *w, void *ev __UNUSED__, void *data)
+{
+       Ewl_Tree *tree;
+       Ewl_Widget *view;
+
+       tree = data;
+       view = ewl_tree_content_widget_get(tree);
+
+       if (EWL_TREE_VIEW_SCROLLED_IS(view))
+               ewl_tree_view_scrolled_scroll_headers_set(EWL_TREE_VIEW(view),
+                       ewl_checkbutton_is_checked(EWL_CHECKBUTTON(w)));
+}
+
+static void
+ewl_tree_cb_hide_headers(Ewl_Widget *w __UNUSED__, void *ev __UNUSED__, void 
*data)
+{
+       Ewl_Tree *tree;
+       int vis = TRUE;
+
+       tree = data;
+
+       if (ewl_tree_headers_visible_get(tree))
+               vis = FALSE;
+
+       ewl_tree_headers_visible_set(tree, vis);
+}
+
+static void
+ewl_tree_cb_plain_view(Ewl_Widget *w, void *ev __UNUSED__, void *data)
 {
-       Ecore_List *selected;
        Ewl_Tree *tree;
+       Ewl_View *view;
 
        tree = data;
-       selected = ewl_tree_selected_get(tree);
-       printf("Selected %d rows\n", ecore_list_count(selected));
+       if (ewl_checkbutton_is_checked(EWL_CHECKBUTTON(w)))
+               view = ewl_tree_view_plain_get();
+       else
+               view = ewl_tree_view_scrolled_get();
+
+       ewl_tree_content_view_set(EWL_TREE(tree), view);
+}
+
+static void
+ewl_tree_cb_set_rows_clicked(Ewl_Widget *w __UNUSED__, void *ev __UNUSED__,
+                                               void *data __UNUSED__)
+{
+       Ewl_Widget *spinner, *tree;
+       Tree_Test_Data *d;
+
+       tree = ewl_widget_name_find("tree");
+       spinner = ewl_widget_name_find("rows_spinner");
+
+       d = ewl_mvc_data_get(EWL_MVC(tree));
+       d->row_count = ewl_range_value_get(EWL_RANGE(spinner));
+
+       ewl_mvc_dirty_set(EWL_MVC(tree), TRUE);
+}
+
+static void
+tree_cb_value_changed(Ewl_Widget *w, void *ev __UNUSED__,
+                                       void *data __UNUSED__)
+{
+       Ecore_List *selected;
+       Ewl_Selection *sel;
+
+       printf("Selected:\n");
+       selected = ewl_mvc_selected_list_get(EWL_MVC(w));
+       ecore_list_first_goto(selected);
+       while ((sel = ecore_list_next(selected)))
+       {
+               if (sel->type == EWL_SELECTION_TYPE_INDEX)
+               {
+                       char *val;
+                       unsigned int col;
+                       Ewl_Selection_Idx *idx;
+
+                       idx = EWL_SELECTION_IDX(sel);
+                       col = idx->column;
+                       if (col != 3)
+                               val = sel->model->fetch(sel->data, idx->row, 
col);
+                       else
+                       {
+                               Tree_Test_Row_Data *d;
+                               d = sel->model->fetch(sel->data, idx->row, col);
+                               val = d->text;
+                       }
+
+                       printf("    [%d,%d] %s\n", idx->row, idx->column, val);
+               }
+               else
+               {
+                       Ewl_Selection_Range *idx;
+                       unsigned int i, k;
+
+                       idx = EWL_SELECTION_RANGE(sel);
+                       for (i = idx->start.row; i <= idx->end.row; i++)
+                       {
+                               for (k = idx->start.column; k <=
+                                                       idx->end.column; k++)
+                               {
+                                       char *val;
+
+                                       if (k != 3)
+                                               val = 
sel->model->fetch(sel->data,
+                                                                       i, k);
+                                       else
+                                       {
+                                               Tree_Test_Row_Data *d;
+                                               d = sel->model->fetch(sel->data,
+                                                                       i, k);
+                                               val = d->text;
+                                       }
+                                       printf("    [%d,%d] %s\n", i, k, val);
+                               }
+                       }
+               }
+       }
 }
+
+static void
+tree_cb_select_mode_change(Ewl_Widget *w __UNUSED__, void *ev __UNUSED__,
+                                               void *data __UNUSED__)
+{
+       Ewl_Widget *tree;
+
+       tree = ewl_widget_name_find("tree");
+       if (!strcmp(ewl_button_label_get(EWL_BUTTON(w)), "Row select"))
+       {
+               ewl_button_label_set(EWL_BUTTON(w), "Cell select");
+               ewl_tree_selection_type_set(EWL_TREE(tree),
+                                       EWL_TREE_SELECTION_TYPE_ROW);
+       }
+       else
+       {
+               ewl_button_label_set(EWL_BUTTON(w), "Row select");
+               ewl_tree_selection_type_set(EWL_TREE(tree),
+                                       EWL_TREE_SELECTION_TYPE_CELL);
+       }
+}
+
 



-------------------------------------------------------------------------
SF.Net email is sponsored by: 
Check out the new SourceForge.net Marketplace.
It's the best place to buy or sell services for
just about anything Open Source.
http://sourceforge.net/services/buy/index.php
_______________________________________________
enlightenment-cvs mailing list
enlightenment-cvs@lists.sourceforge.net
https://lists.sourceforge.net/lists/listinfo/enlightenment-cvs

Reply via email to