Use a TreeModel
authorEnrico Zini <enrico@enricozini.org>
Wed, 9 Dec 2009 20:41:06 +0000 (20:41 +0000)
committerEnrico Zini <enrico@enricozini.org>
Wed, 9 Dec 2009 20:41:06 +0000 (20:41 +0000)
src/fisheye.vala

index 285d9cbd3c81f34e39f4bb6af3aa4efd8b379860..0e71ebbeece4b89a420406628db7681486bb8196 100644 (file)
@@ -25,19 +25,6 @@ public class FisheyeList : Gtk.DrawingArea
        protected Gtk.TreeModel model;
        protected Gdk.Pixmap backing_store;
 
-       private string[] list;
-       protected int cur_el;
-
-       protected int _distortion_factor;
-       public int distortion_factor {
-               get { return _distortion_factor; }
-               set {
-                       _distortion_factor = value;
-                       focus_layout_needed = true;
-               }
-       }
-
-
        // Pango layouts cached for speed
        // TODO: If you create and keep a PangoLayout using this context, you
        // must deal with changes to the context by calling
@@ -45,6 +32,12 @@ public class FisheyeList : Gtk.DrawingArea
        // "style-set" and "direction-changed" signals for the widget.
        protected Pango.Layout[] pango_cache;
 
+       // Labels to show, extracted from the model
+       protected string[] label_cache;
+       protected bool build_label_cache_needed;
+
+       protected int cur_el;
+
        // Layout information
        protected int focus_first;
        protected int focus_end;
@@ -60,6 +53,17 @@ public class FisheyeList : Gtk.DrawingArea
                        _focus_size = value;
                        focus_starts = new int[value+1];
                        focus_layout_needed = true;
+                       queue_draw();
+               }
+       }
+
+       protected int _distortion_factor;
+       public int distortion_factor {
+               get { return _distortion_factor; }
+               set {
+                       _distortion_factor = value;
+                       focus_layout_needed = true;
+                       queue_draw();
                }
        }
 
@@ -68,9 +72,8 @@ public class FisheyeList : Gtk.DrawingArea
                model = null;
                backing_store = null;
 
-               list = new string[300];
-               for (int i = 0; i < 300; ++i)
-                       list[i] = "Lorem Ipsum %d".printf(i);
+               label_cache = null;
+               build_label_cache_needed = true;
 
                pango_cache = new Pango.Layout[30];
                for (int i = 0; i < 30; ++i)
@@ -93,19 +96,21 @@ public class FisheyeList : Gtk.DrawingArea
        public void set_model (Gtk.TreeModel? model)
        {
                this.model = model;
+               build_label_cache_needed = true;
+               queue_draw();
        }
 
        /* Mouse button got pressed over widget */
        public override bool button_press_event(Gdk.EventButton event)
        {
-               stderr.printf("Mouse pressed on %d %s\n", cur_el, list[cur_el]);
+               stderr.printf("Mouse pressed on %d %s\n", cur_el, label_cache[cur_el]);
                return false;
        }
 
        /* Mouse button got released */
        public override bool button_release_event(Gdk.EventButton event)
        {
-               stderr.printf("Mouse released on %d %s\n", cur_el, list[cur_el]);
+               stderr.printf("Mouse released on %d %s\n", cur_el, label_cache[cur_el]);
                // ...
                return false;
        }
@@ -129,7 +134,7 @@ public class FisheyeList : Gtk.DrawingArea
                                }
 
                } else {
-                       cur_el = y * list.length / allocation.height;
+                       cur_el = y * label_cache.length / allocation.height;
                        if (old_cur_el != cur_el)
                                focus_layout_needed = true;
                }
@@ -172,39 +177,79 @@ public class FisheyeList : Gtk.DrawingArea
        protected int el_y(int idx)
        {
                // Undistorted Y
-               int undy = idx * allocation.height / list.length;
+               int undy = idx * allocation.height / label_cache.length;
                // Distorted position
                int pos = fisheye(undy, focus_centre, distortion_factor, 0, allocation.height);
                //stderr.printf("%d %f %f\n", idx, undy, pos);
                return pos;
        }
 
-       protected void focus_layout()
+       protected void build_label_cache()
        {
-               // Anchor point
-               focus_centre = cur_el*allocation.height/list.length;
+               if (model == null)
+               {
+                       label_cache = new string[0];
+               } else {
+                       Gtk.TreeIter iter;
+                       if (!model.get_iter_first(out iter))
+                       {
+                               label_cache = new string[0];
+                       }
+                       else
+                       {
+                               int count = model.iter_n_children(null);
+                               label_cache = new string[count];
+
+                               int i = 0;
+                               do {
+                                       string val;
+                                       model.get(iter, 0, out val, -1);
+                                       label_cache[i] = val;
+                                       ++i;
+                               } while (model.iter_next(ref iter));
+                       }
+               }
 
-               focus_first = cur_el > focus_size/2 ? cur_el-focus_size/2 : 0;
-               focus_end = focus_first + focus_size;
-               if (focus_end >= list.length) focus_end = list.length;
+               build_label_cache_needed = false;
+               focus_layout_needed = true;
+       }
 
-               // Compute starting positions for all items in focus
-               for (int idx = focus_first; idx < focus_end; ++idx)
+       protected void focus_layout()
+       {
+               if (label_cache.length == 0)
                {
-                       int posprev = idx == 0 ? 0 : el_y(idx-1);
-                       int pos = el_y(idx);
-                       int posnext = idx == list.length-1 ? 1 : el_y(idx+1);
-                       int y0 = (pos+posprev)/2;
-                       int y1 = (pos+posnext)/2;
-
-                       focus_starts[idx - focus_first] = y0;
-                       focus_starts[idx - focus_first + 1] = y1;
+                       focus_centre = 0;
+                       focus_first = 0;
+                       focus_end = 0;
+                       focus_starts[0] = 0;
+               } else {
+                       // Anchor point
+                       focus_centre = cur_el*allocation.height/label_cache.length;
+
+                       focus_first = cur_el > focus_size/2 ? cur_el-focus_size/2 : 0;
+                       focus_end = focus_first + focus_size;
+                       if (focus_end >= label_cache.length) focus_end = label_cache.length;
+
+                       // Compute starting positions for all items in focus
+                       for (int idx = focus_first; idx < focus_end; ++idx)
+                       {
+                               int posprev = idx == 0 ? 0 : el_y(idx-1);
+                               int pos = el_y(idx);
+                               int posnext = idx == label_cache.length-1 ? 1 : el_y(idx+1);
+                               int y0 = (pos+posprev)/2;
+                               int y1 = (pos+posnext)/2;
+
+                               focus_starts[idx - focus_first] = y0;
+                               focus_starts[idx - focus_first + 1] = y1;
+                       }
                }
                focus_layout_needed = false;
        }
 
        protected void draw(Gdk.Drawable drawable)
        {
+               if (build_label_cache_needed)
+                       build_label_cache();
                if (focus_layout_needed)
                        focus_layout();
 
@@ -252,7 +297,7 @@ public class FisheyeList : Gtk.DrawingArea
                                pc.set_font_description(fd);
                                pango_cache[size] = new Pango.Layout(pc);
                        }
-                       pango_cache[size].set_text(list[idx], -1);
+                       pango_cache[size].set_text(label_cache[idx], -1);
                        var layout = pango_cache[size];
                        //stderr.printf("AZAZA %p\n", layout.get_attributes());
                        //var attrlist = layout.get_attributes().copy();
@@ -316,6 +361,16 @@ public class Fisheye : Gtk.Window
 
                var list = new FisheyeList();
                add(list);
+
+               var store = new Gtk.ListStore(1, typeof(string));
+               Gtk.TreeIter iter;
+               for (int i = 0; i < 300; ++i)
+               {
+                       store.append(out iter);
+                       store.set(iter, 0, "Antani %d".printf(i), -1);
+               }
+
+               list.set_model(store);
        }
 }