Handle not fisheye case nicely
authorEnrico Zini <enrico@enricozini.org>
Thu, 10 Dec 2009 11:13:33 +0000 (11:13 +0000)
committerEnrico Zini <enrico@enricozini.org>
Thu, 10 Dec 2009 11:13:33 +0000 (11:13 +0000)
src/fisheye.vala

index 7053aed4569253bf1ca5e030be1aac226895d22e..c2e0b6bb71dd663e7228218a2fc6005bb64c2850 100644 (file)
@@ -29,6 +29,7 @@ public class FisheyeList : Gtk.DrawingArea
        // Pango layouts cached for speed
        protected const int steps = 5;
        protected Gtk.CellRendererText[] renderers;
+       protected int max_renderer_size;
 
        // Labels to show, extracted from the model
        protected string[] label_cache;
@@ -42,6 +43,7 @@ public class FisheyeList : Gtk.DrawingArea
        protected int[] focus_starts;
        protected bool focus_locked;
        protected bool focus_layout_needed;
+       protected bool is_fisheye;
 
        protected int _focus_size;
        public int focus_size {
@@ -149,21 +151,28 @@ public class FisheyeList : Gtk.DrawingArea
                int x = (int)event.x;
                int y = (int)event.y;
 
-               focus_locked = !focus_layout_needed && x < allocation.width/2 && y >= focus_starts[0] && y < focus_starts[focus_end - focus_first];
-
-               if (focus_locked)
+               if (is_fisheye)
                {
-                       for (int idx = focus_first; idx < focus_end; ++idx)
-                               if (y < focus_starts[idx-focus_first+1])
-                               {
-                                       cur_el = idx;
-                                       break;
-                               }
+                       focus_locked = !focus_layout_needed && x < allocation.width/2 && y >= focus_starts[0] && y < focus_starts[focus_end - focus_first];
 
+                       if (focus_locked)
+                       {
+                               for (int idx = focus_first; idx < focus_end; ++idx)
+                                       if (y < focus_starts[idx-focus_first+1])
+                                       {
+                                               cur_el = idx;
+                                               break;
+                                       }
+
+                       } else {
+                               cur_el = y * label_cache.length / allocation.height;
+                               if (old_cur_el != cur_el)
+                                       focus_layout_needed = true;
+                       }
                } else {
-                       cur_el = y * label_cache.length / allocation.height;
-                       if (old_cur_el != cur_el)
-                               focus_layout_needed = true;
+                       cur_el = y / max_renderer_size;
+                       if (cur_el >= label_cache.length)
+                               cur_el = label_cache.length - 1;
                }
 
                //stderr.printf("MOTION %f %f CE %d\n", event.x, event.y, cur_el);
@@ -224,24 +233,7 @@ public class FisheyeList : Gtk.DrawingArea
 
        protected void base_layout()
        {
-               background = new Gdk.Pixmap(window, allocation.width, allocation.height, -1);
-               backing_store = new Gdk.Pixmap(window, allocation.width, allocation.height, -1);
-
-               // Recreate the renderers
-               renderers[renderers.length-1] = make_cell_renderer();
-               renderers[renderers.length-1].set_fixed_height_from_font(1);
-
-               renderers[0] = make_cell_renderer();
-               renderers[0].size = Pango.SCALE;
-               renderers[0].set_fixed_height_from_font(1);
-
-               for (int i = 1; i < renderers.length-1; ++i)
-               {
-                       renderers[i] = make_cell_renderer();
-                       renderers[i].scale = (double)i / renderers.length;
-                       renderers[i].set_fixed_height_from_font(1);
-               }
-
+               // Rebuild label cache
                if (model == null)
                {
                        label_cache = new string[0];
@@ -266,6 +258,38 @@ public class FisheyeList : Gtk.DrawingArea
                        }
                }
 
+               background = new Gdk.Pixmap(window, allocation.width, allocation.height, -1);
+               backing_store = new Gdk.Pixmap(window, allocation.width, allocation.height, -1);
+
+               // Recreate the renderers
+               renderers[renderers.length-1] = make_cell_renderer();
+               renderers[renderers.length-1].set_fixed_height_from_font(1);
+               renderers[renderers.length-1].get_size(this, null, null, null, null, out max_renderer_size);
+
+               is_fisheye = label_cache.length * max_renderer_size > allocation.height;
+
+               if (is_fisheye)
+               {
+                       renderers[0] = make_cell_renderer();
+                       renderers[0].size = Pango.SCALE;
+                       renderers[0].set_fixed_height_from_font(1);
+
+                       int step_size = 0;      // Size of the diminishing area
+                       for (int i = 1; i < renderers.length-1; ++i)
+                       {
+                               renderers[i] = make_cell_renderer();
+                               renderers[i].scale = (double)i / renderers.length;
+                               renderers[i].set_fixed_height_from_font(1);
+                               int size;
+                               renderers[i].get_size(this, null, null, null, null, out size);
+                               step_size += size;
+                       }
+
+                       //int focus_lines_count = allocation.height / (2 * max_renderer_size);
+                       //int focus_area_size = 2 * step_size + focus_lines_count * max_renderer_size;
+                       //int focus_area_start = pos(cur_el) - focus_lines_count*max_renderer_size/2 - step_size;
+               }
+
                // Draw background
                draw_background(background);
 
@@ -311,6 +335,9 @@ public class FisheyeList : Gtk.DrawingArea
                // Background
                drawable.draw_rectangle(style.bg_gc[Gtk.StateType.NORMAL], true, 0, 0, allocation.width, allocation.height);
 
+               if (!is_fisheye)
+                       return;
+
                // Focus movement area
                drawable.draw_rectangle(style.bg_gc[Gtk.StateType.INSENSITIVE], true,
                        allocation.width/2, 0, allocation.width, allocation.height);
@@ -391,40 +418,69 @@ public class FisheyeList : Gtk.DrawingArea
                        0, 0, 0, 0,
                        allocation.width, allocation.height);
 
-               // Focus lock area
-               drawable.draw_rectangle(style.bg_gc[Gtk.StateType.ACTIVE], true,
-                       0, focus_starts[0], allocation.width/2, focus_starts[focus_end - focus_first]-focus_starts[0]);
-
-               // Paint items around focus
-               Gdk.Rectangle cell_area = Gdk.Rectangle();
-               cell_area.x = 0;
-               cell_area.width = allocation.width;
-               for (int idx = 0; idx < focus_end-focus_first; ++idx)
+               if (is_fisheye)
                {
-                       int y0 = focus_starts[idx];
-                       int y1 = focus_starts[idx + 1];
-                       cell_area.y = y0;
-                       cell_area.height = y1-y0;
+                       // Focus lock area
+                       drawable.draw_rectangle(style.bg_gc[Gtk.StateType.ACTIVE], true,
+                               0, focus_starts[0], allocation.width/2, focus_starts[focus_end - focus_first]-focus_starts[0]);
+
+                       // Paint items around focus
+                       Gdk.Rectangle cell_area = Gdk.Rectangle();
+                       cell_area.x = 0;
+                       cell_area.width = allocation.width;
+                       for (int idx = 0; idx < focus_end-focus_first; ++idx)
+                       {
+                               int y0 = focus_starts[idx];
+                               int y1 = focus_starts[idx + 1];
+                               cell_area.y = y0;
+                               cell_area.height = y1-y0;
+
+                               Gtk.CellRendererState rflags = 0;
+                               if (idx + focus_first == cur_el)
+                               {
+                                       rflags |= Gtk.CellRendererState.SELECTED | Gtk.CellRendererState.FOCUSED;
+                                       drawable.draw_rectangle(style.bg_gc[Gtk.StateType.SELECTED], true,
+                                                       cell_area.x, cell_area.y, cell_area.width, cell_area.height);
+                               }
+                       
+                               int size = (y1-y0);
+                               if (size <= 0) size = 1;
+                               if (size >= renderers.length) size = renderers.length - 1;
+                               renderers[size].text = label_cache[idx + focus_first];
+                               renderers[size].render((Gdk.Window*)drawable, this, 
+                                               cell_area,
+                                               cell_area,
+                                               expose_area,
+                                               rflags);
 
-                       Gtk.CellRendererState rflags = 0;
-                       if (idx + focus_first == cur_el)
+                               //Gdk.draw_line(drawable, style.fg_gc[itemState], 0, y0, allocation.width, y0);
+                       }
+               } else {
+                       // Paint all items sequentially
+                       var renderer = renderers[renderers.length-1];
+                       Gdk.Rectangle cell_area = Gdk.Rectangle();
+                       cell_area.x = 0;
+                       cell_area.width = allocation.width;
+                       cell_area.height = max_renderer_size;
+                       for (int idx = 0; idx < label_cache.length; ++idx)
                        {
-                               rflags |= Gtk.CellRendererState.SELECTED | Gtk.CellRendererState.FOCUSED;
-                               drawable.draw_rectangle(style.bg_gc[Gtk.StateType.SELECTED], true,
-                                               cell_area.x, cell_area.y, cell_area.width, cell_area.height);
+                               cell_area.y = idx * cell_area.height;
+
+                               Gtk.CellRendererState rflags = 0;
+                               if (idx == cur_el)
+                               {
+                                       rflags |= Gtk.CellRendererState.SELECTED | Gtk.CellRendererState.FOCUSED;
+                                       drawable.draw_rectangle(style.bg_gc[Gtk.StateType.SELECTED], true,
+                                                       cell_area.x, cell_area.y, cell_area.width, cell_area.height);
+                               }
+
+                               renderer.text = label_cache[idx];
+                               renderer.render((Gdk.Window*)drawable, this, 
+                                               cell_area,
+                                               cell_area,
+                                               expose_area,
+                                               rflags);
                        }
-               
-                       int size = (y1-y0);
-                       if (size <= 0) size = 1;
-                       if (size >= renderers.length) size = renderers.length - 1;
-                       renderers[size].text = label_cache[idx + focus_first];
-                       renderers[size].render((Gdk.Window*)drawable, this, 
-                                       cell_area,
-                                       cell_area,
-                                       expose_area,
-                                       rflags);
-
-                       //Gdk.draw_line(drawable, style.fg_gc[itemState], 0, y0, allocation.width, y0);
                }
        }