// 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;
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 {
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);
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];
}
}
+ 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);
// 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);
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);
}
}