prefix_filter now works on everything
authorEnrico Zini <enrico@enricozini.org>
Mon, 14 Dec 2009 18:16:49 +0000 (18:16 +0000)
committerEnrico Zini <enrico@enricozini.org>
Mon, 14 Dec 2009 18:16:49 +0000 (18:16 +0000)
gtkfisheyelist/gtkfisheyelistview.vala

index 88f0e96c525f05165ae81f9cc3670587ee809243..10b790f5d055502bff347f98d4475f7129f1854d 100644 (file)
@@ -46,12 +46,12 @@ protected class PrefixInfo
         * return true.
         * Else, return false.
         */
-       public bool refine(string s)
+       public bool refine(string s, int min_prefix_size=1)
        {
                size_t len;
                for (len = 0; prefix[len] != 0 && s[len] != 0 && s[len] == prefix[len]; ++len)
                        ;
-               if (len == 0) return false;
+               if (len < min_prefix_size) return false;
                if (len != pfx_len)
                {
                        prefix = prefix.substring(0, (int)len);
@@ -61,6 +61,12 @@ protected class PrefixInfo
        }
 }
 
+protected struct LabelInfo
+{
+       string label;
+       int index;
+}
+
 public class FisheyeListView : Gtk.DrawingArea
 {
        protected Gtk.TreeModel model;
@@ -74,7 +80,8 @@ public class FisheyeListView : Gtk.DrawingArea
        protected int max_renderer_size;
 
        // Labels to show, extracted from the model
-       protected string[] label_cache;
+       protected LabelInfo[] label_cache;
+       protected int label_count;
        protected bool base_layout_needed;
 
        // Prefix information
@@ -116,6 +123,16 @@ public class FisheyeListView : Gtk.DrawingArea
                }
        }
 
+       protected string _prefix_filter;
+       public string prefix_filter {
+               get { return _prefix_filter; }
+               set {
+                       _prefix_filter = value;
+                       base_layout_needed = true;
+                       queue_draw();
+               }
+       }
+
        //public virtual signal void cursor_changed ();
        public signal void row_activated(Gtk.TreePath path);
 
@@ -125,7 +142,9 @@ public class FisheyeListView : Gtk.DrawingArea
                backing_store = null;
 
                label_cache = null;
+               label_count = 0;
                prefixes = null;
+               prefix_filter = null;
 
                renderers = new Gtk.CellRendererText[steps];
                renderer_sizes = new int[steps];
@@ -191,13 +210,14 @@ public class FisheyeListView : Gtk.DrawingArea
                if (x < allocation.width / 3)
                {
                        Gtk.TreeIter iter;
-                       if (model.iter_nth_child(out iter, null, cur_el))
+                       if (model.iter_nth_child(out iter, null, label_cache[cur_el].index))
                        {
                                Gtk.TreePath path = model.get_path(iter);
                                row_activated(path);
                        }
                } else if (cur_pfx != null && x > allocation.width * 2 / 3) {
-                       stderr.printf("Mouse released on prefix %s\n", cur_pfx.prefix);
+                       //stderr.printf("Mouse released on prefix %s\n", cur_pfx.prefix);
+                       prefix_filter = cur_pfx.prefix;
                }
                return false;
        }
@@ -214,7 +234,7 @@ public class FisheyeListView : Gtk.DrawingArea
                        focus_locked = !focus_layout_needed && x < allocation.width/3 && y >= focus_area_start+focus_info[0].y && y < focus_area_start+focus_info[focus_end - focus_first].y;
 
                        if (!focus_locked || y < focus_area_start+focus_info[0].y || y >= focus_area_start+focus_info[focus_end - focus_first].y)
-                               cur_el = y * (label_cache.length+1) / allocation.height;
+                               cur_el = y * (label_count+1) / allocation.height;
                        else
                                for (int idx = 0; idx < focus_info.length; ++idx)
                                        if (y - focus_area_start < focus_info[idx].y + renderer_sizes[focus_info[idx].renderer])
@@ -236,8 +256,8 @@ public class FisheyeListView : Gtk.DrawingArea
                                focus_layout_needed = true;
                } else {
                        cur_el = y / max_renderer_size;
-                       if (cur_el >= label_cache.length)
-                               cur_el = label_cache.length - 1;
+                       if (cur_el >= label_count)
+                               cur_el = label_count - 1;
                }
 
                //stderr.printf("MOTION %f %f CE %d\n", event.x, event.y, cur_el);
@@ -291,39 +311,52 @@ public class FisheyeListView : Gtk.DrawingArea
        protected void base_layout()
        {
                // Rebuild label cache
+               cur_pfx = null;
                prefixes = new List<PrefixInfo>();
                if (model == null)
                {
-                       label_cache = new string[0];
+                       label_cache = null;
+                       label_count = 0;
                } else {
                        Gtk.TreeIter iter;
                        if (!model.get_iter_first(out iter))
                        {
-                               label_cache = new string[0];
+                               label_cache = null;
+                               label_count = 0;
                        }
                        else
                        {
                                int count = model.iter_n_children(null);
-                               label_cache = new string[count];
+                               label_cache = new LabelInfo[count];
 
-                               int i = 0;
+                               int lc_idx = 0;
+                               int model_idx = 0;
                                PrefixInfo pi = null;
+                               int min_prefix_size = _prefix_filter == null ? 1 : (int)_prefix_filter.size() + 1;
                                do {
                                        string val;
                                        model.get(iter, _label_column, out val, -1);
-                                       label_cache[i] = val;
-                                       if (pi == null || !pi.refine(val))
+
+                                       // Apply prefix filter
+                                       if (_prefix_filter == null || val.has_prefix(_prefix_filter))
                                        {
-                                               if (pi != null) prefixes.append(pi);
-                                               pi = new PrefixInfo(val, i);
+                                               label_cache[lc_idx].label = val;
+                                               label_cache[lc_idx].index = model_idx;
+                                               if (pi == null || !pi.refine(val, min_prefix_size))
+                                               {
+                                                       if (pi != null) prefixes.append(pi);
+                                                       pi = new PrefixInfo(val, lc_idx);
+                                               }
+                                               ++lc_idx;
                                        }
-                                       ++i;
+                                       ++model_idx;
                                } while (model.iter_next(ref iter));
                                prefixes.append(pi);
+                               label_count = lc_idx;
                        }
                }
                for (weak List<PrefixInfo> i = prefixes; i != null; i = i.next)
-                       i.data.layout_pos = i.data.pos * allocation.height / (label_cache.length+1);
+                       i.data.layout_pos = i.data.pos * allocation.height / (label_count+1);
 
                background = new Gdk.Pixmap(window, allocation.width, allocation.height, -1);
                backing_store = new Gdk.Pixmap(window, allocation.width, allocation.height, -1);
@@ -334,7 +367,7 @@ public class FisheyeListView : Gtk.DrawingArea
                renderers[renderers.length-1].get_size(this, null, null, null, null, out max_renderer_size);
                renderer_sizes[renderers.length-1] = max_renderer_size;
 
-               is_fisheye = label_cache.length * max_renderer_size > allocation.height;
+               is_fisheye = label_count * max_renderer_size > allocation.height;
 
                if (is_fisheye)
                {
@@ -382,7 +415,7 @@ public class FisheyeListView : Gtk.DrawingArea
 
        protected void focus_layout()
        {
-               if (!is_fisheye || label_cache.length == 0)
+               if (!is_fisheye || label_count == 0)
                {
                        focus_first = 0;
                        focus_end = 0;
@@ -392,8 +425,8 @@ public class FisheyeListView : Gtk.DrawingArea
 
                focus_first = cur_el - _focus_size/2 - steps;
                if (focus_first < 0) focus_first = 0;
-               if (focus_first + focus_info.length > label_cache.length)
-                       focus_first = label_cache.length - focus_info.length;
+               if (focus_first + focus_info.length > label_count)
+                       focus_first = label_count - focus_info.length;
 
                int cur_pos = 0;
                int cur_idx = 0;
@@ -405,7 +438,7 @@ public class FisheyeListView : Gtk.DrawingArea
                        focus_info[cur_idx].y = cur_pos;
                        focus_info[cur_idx].renderer = el_renderer(focus_first + cur_idx);
 //                     stderr.printf("LAYOUT %d+[0-%d-%d] item %d/%d: pos %d rend %d rsz %d\n",
-//                             focus_first, cur_idx, focus_info.length, focus_first + cur_idx, label_cache.length,
+//                             focus_first, cur_idx, focus_info.length, focus_first + cur_idx, label_count,
 //                             cur_pos, focus_info[cur_idx].renderer, renderer_sizes[focus_info[cur_idx].renderer]);
                        cur_pos += renderer_sizes[focus_info[cur_idx].renderer];
                        ++cur_idx;
@@ -415,7 +448,7 @@ public class FisheyeListView : Gtk.DrawingArea
                focus_info[cur_idx].renderer = 0;
                focus_end = focus_first + cur_idx;
 
-               int anchor_y = cur_el * allocation.height / (label_cache.length+1);
+               int anchor_y = cur_el * allocation.height / (label_count+1);
                int focus_area_size = cur_pos;
 
                focus_area_start = anchor_y - focus_area_pre;
@@ -462,13 +495,13 @@ public class FisheyeListView : Gtk.DrawingArea
                cell_area.x = 0;
                cell_area.width = allocation.width;
                cell_area.height = renderer_sizes[0];
-               if (label_cache.length * cell_area.height >= allocation.height)
+               if (label_count * cell_area.height >= allocation.height)
                {
                        for (int y = 0; y < allocation.height; y += cell_area.height)
                        {
-                               int idx = y * label_cache.length / allocation.height;
+                               int idx = y * label_count / allocation.height;
                                cell_area.y = y;
-                               renderers[0].text = label_cache[idx];
+                               renderers[0].text = label_cache[idx].label;
                                renderers[0].render((Gdk.Window*)drawable, this, 
                                                cell_area,
                                                cell_area,
@@ -476,11 +509,11 @@ public class FisheyeListView : Gtk.DrawingArea
                                                0);
                        }
                } else {
-                       int count = int.min(allocation.height/(2*cell_area.height), label_cache.length);
+                       int count = int.min(allocation.height/(2*cell_area.height), label_count);
                        for (int idx = 0; idx < count; ++idx)
                        {
                                cell_area.y = idx * cell_area.height;
-                               renderers[0].text = label_cache[idx];
+                               renderers[0].text = label_cache[idx].label;
                                renderers[0].render((Gdk.Window*)drawable, this, 
                                                cell_area,
                                                cell_area,
@@ -488,7 +521,7 @@ public class FisheyeListView : Gtk.DrawingArea
                                                0);
 
                                cell_area.y = allocation.height-cell_area.y;
-                               renderers[0].text = label_cache[label_cache.length-idx];
+                               renderers[0].text = label_cache[label_count-idx].label;
                                renderers[0].render((Gdk.Window*)drawable, this, 
                                                cell_area,
                                                cell_area,
@@ -571,7 +604,7 @@ public class FisheyeListView : Gtk.DrawingArea
                                                        cell_area.x, cell_area.y, allocation.width, cell_area.height);
                                }
                        
-                               renderer.text = label_cache[idx + focus_first];
+                               renderer.text = label_cache[idx + focus_first].label;
                                renderer.render((Gdk.Window*)drawable, this, 
                                                cell_area,
                                                cell_area,
@@ -587,7 +620,7 @@ public class FisheyeListView : Gtk.DrawingArea
                        cell_area.x = 0;
                        cell_area.width = allocation.width;
                        cell_area.height = max_renderer_size;
-                       for (int idx = 0; idx < label_cache.length; ++idx)
+                       for (int idx = 0; idx < label_count; ++idx)
                        {
                                cell_area.y = idx * cell_area.height;
 
@@ -599,7 +632,7 @@ public class FisheyeListView : Gtk.DrawingArea
                                                        cell_area.x, cell_area.y, cell_area.width, cell_area.height);
                                }
 
-                               renderer.text = label_cache[idx];
+                               renderer.text = label_cache[idx].label;
                                renderer.render((Gdk.Window*)drawable, this, 
                                                cell_area,
                                                cell_area,