Re: [Banshee-List] More ListView Performance Goodness!
- From: "Scott Peterson" <lunchtimemama gmail com>
- To: banshee-list gnome org
- Subject: Re: [Banshee-List] More ListView Performance Goodness!
- Date: Mon, 11 Feb 2008 22:12:26 -0500
And here is the patch which fixes all of the bug I know about. I'd
like to hold off on committing until some other people (abock?) get a
chance to review/test this. Inline FTW!
Index: src/Core/Hyena.Gui/Hyena.Data.Gui/ListView/ListView_Windowing.cs
===================================================================
--- src/Core/Hyena.Gui/Hyena.Data.Gui/ListView/ListView_Windowing.cs (revision
3222)
+++ src/Core/Hyena.Gui/Hyena.Data.Gui/ListView/ListView_Windowing.cs (working
copy)
@@ -159,6 +159,8 @@
graphics = new ListViewGraphics (this);
graphics.RefreshColors ();
+ CreateCanvases ();
+
OnDragSourceSet ();
}
@@ -184,6 +186,11 @@
list_window.Destroy ();
list_window = null;
+ list_canvas.Dispose ();
+ list_canvas = null;
+ list_canvas_b.Dispose ();
+ list_canvas = null;
+
base.OnUnrealized ();
}
@@ -233,6 +240,12 @@
list_alloc.Width = allocation.Width - 2 * left_border_alloc.Width;
list_alloc.Height = allocation.Height -
header_alloc.Height - footer_alloc.Height;
list_window.MoveResize (left_border_alloc.Width,
header_alloc.Height, list_alloc.Width, list_alloc.Height);
+
+ list_canvas_alloc.Width = list_alloc.Width;
+ list_canvas_size = (int)Math.Ceiling ((list_alloc.Height
+ RowHeight) / (double)RowHeight);
+ list_canvas_alloc.Height = list_canvas_size * RowHeight;
+
+ CreateCanvases ();
}
protected override void OnSizeRequested (ref Requisition requisition)
Index: src/Core/Hyena.Gui/Hyena.Data.Gui/ListView/ListView_Rendering.cs
===================================================================
--- src/Core/Hyena.Gui/Hyena.Data.Gui/ListView/ListView_Rendering.cs (revision
3222)
+++ src/Core/Hyena.Gui/Hyena.Data.Gui/ListView/ListView_Rendering.cs (working
copy)
@@ -52,6 +52,13 @@
private Pango.Layout header_pango_layout;
private Pango.Layout list_pango_layout;
+ private Gdk.Drawable list_canvas;
+ private Gdk.Drawable list_canvas_b;
+ private Gdk.Rectangle list_canvas_alloc;
+ private int list_canvas_size;
+ private int list_canvas_index;
+ private int list_canvas_offset;
+
public new void QueueDraw ()
{
base.QueueDraw ();
@@ -60,6 +67,16 @@
InvalidateListWindow ();
InvalidateFooterWindow ();
}
+
+ private void CreateCanvases ()
+ {
+ if (list_canvas != null) {
+ list_canvas.Dispose ();
+ list_canvas_b.Dispose ();
+ }
+ list_canvas = new Gdk.Pixmap (GdkWindow,
list_canvas_alloc.Width, list_canvas_alloc.Height);
+ list_canvas_b = new Gdk.Pixmap (GdkWindow,
list_canvas_alloc.Width, list_canvas_alloc.Height);
+ }
protected override bool OnExposeEvent (Gdk.EventExpose evnt)
{
@@ -69,41 +86,58 @@
return true;
}
+
+ private delegate void Painter (Gdk.EventExpose evnt,
Gdk.Rectangle clip);
+
+ private static Pango.Layout default_pango_layout;
+
+ private static void Paint (Painter code, Gdk.EventExpose
evnt, Gdk.Rectangle clip, ref Cairo.Context context)
+ {
+ Paint (code, evnt, clip, evnt.Window, ref context, ref
default_pango_layout, false);
+ }
+
+ private static void Paint (Painter code, Gdk.EventExpose
evnt, Gdk.Rectangle clip, ref Cairo.Context context, ref Pango.Layout
layout)
+ {
+ Paint (code, evnt, clip, evnt.Window, ref context, ref
layout, true);
+ }
+
+ private static void Paint (Painter code, Gdk.EventExpose
evnt, Gdk.Rectangle clip, Gdk.Drawable canvas, ref Cairo.Context
context, ref Pango.Layout layout, bool has_layout)
+ {
+ context = CairoHelper.CreateCairoDrawable (canvas);
+ context.Rectangle (clip.X, clip.Y, clip.Width, clip.Height);
+ context.Clip ();
+
+ Paint (code, evnt, clip, context, ref layout, has_layout);
+ }
+
+ private static void Paint (Painter code, Gdk.EventExpose
evnt, Gdk.Rectangle clip, Cairo.Context context, ref Pango.Layout
layout, bool has_layout)
+ {
+ if (has_layout && layout == null) {
+ layout = Pango.CairoHelper.CreateLayout (context);
+ }
+
+ code (evnt, clip);
+
+ ((IDisposable)context.Target).Dispose ();
+ ((IDisposable)context).Dispose ();
+ }
private void PaintRegion (Gdk.EventExpose evnt, Gdk.Rectangle clip)
{
- Cairo.Context cr = CairoHelper.CreateCairoDrawable (evnt.Window);
- cr.Rectangle (clip.X, clip.Y, clip.Width, clip.Height);
- cr.Clip ();
-
if (evnt.Window == header_window) {
- header_cr = cr;
- if (header_pango_layout == null) {
- header_pango_layout =
Pango.CairoHelper.CreateLayout (header_cr);
- }
- PaintHeader (evnt.Area);
+ Paint (PaintHeader, evnt, clip, ref header_cr, ref
header_pango_layout);
} else if (evnt.Window == footer_window) {
- footer_cr = cr;
- PaintFooter (evnt, clip);
+ Paint (PaintFooter, evnt, clip, ref footer_cr);
} else if (evnt.Window == left_border_window) {
- left_border_cr = cr;
- PaintLeftBorder(evnt, clip);
+ Paint (PaintLeftBorder, evnt, clip, ref left_border_cr);
} else if (evnt.Window == right_border_window) {
- right_border_cr = cr;
- PaintRightBorder(evnt, clip);
+ Paint (PaintRightBorder, evnt, clip, ref right_border_cr);
} else if (evnt.Window == list_window) {
- list_cr = cr;
- if (list_pango_layout == null) {
- list_pango_layout =
Pango.CairoHelper.CreateLayout (list_cr);
- }
PaintList (evnt, clip);
}
-
- ((IDisposable)cr.Target).Dispose ();
- ((IDisposable)cr).Dispose ();
}
- private void PaintHeader (Gdk.Rectangle clip)
+ private void PaintHeader (Gdk.EventExpose evnt, Gdk.Rectangle clip)
{
graphics.DrawHeaderBackground (header_cr, header_alloc,
2, header_visible);
@@ -185,22 +219,94 @@
if (model == null) {
return;
}
-
+
+ bool paint = false;
int vadjustment_value = (int)vadjustment.Value;
- int first_row = vadjustment_value / RowHeight;
- int last_row = Math.Min (model.Count, first_row + RowsInView);
+ list_canvas_offset = vadjustment_value % RowHeight;
+
+ if (scroll_delta == 0) {
+ clip = list_canvas_alloc;
+ paint = true;
+ list_canvas.DrawRectangle (Style.WhiteGC, true,
list_canvas_alloc);
+ } else {
+ int index = vadjustment_value / RowHeight;
+
+ if (index > list_canvas_index) {
+ int delta = index - list_canvas_index;
+ clip.X = 0;
+ clip.Width = list_canvas_alloc.Width;
+
+ if (delta < list_canvas_size) {
+ clip.Height = delta * RowHeight;
+ clip.Y = list_canvas_alloc.Height - clip.Height;
+ int height = list_canvas_alloc.Height - clip.Height;
+ list_canvas_b.DrawRectangle (Style.WhiteGC,
true, list_canvas_alloc);
+ list_canvas_b.DrawDrawable (Style.WhiteGC,
list_canvas, 0, clip.Height, 0, 0, clip.Width, height);
+ Gdk.Drawable tmp = list_canvas;
+ list_canvas = list_canvas_b;
+ list_canvas_b = tmp;
+ } else {
+ clip.Height = list_canvas_alloc.Height;
+ clip.Y = 0;
+ list_canvas.DrawRectangle (Style.WhiteGC,
true, list_canvas_alloc);
+ }
+
+ paint = true;
+ } else if (index < list_canvas_index) {
+ int delta = list_canvas_index - index;
+ clip.X = 0;
+ clip.Y = 0;
+ clip.Width = list_canvas_alloc.Width;
+
+ if (delta < list_canvas_size) {
+ clip.Height = delta * RowHeight;
+ int height = list_canvas_alloc.Height - clip.Height;
+ list_canvas_b.DrawRectangle (Style.WhiteGC,
true, list_canvas_alloc);
+ list_canvas_b.DrawDrawable (Style.WhiteGC,
list_canvas, 0, 0, 0, clip.Height, clip.Width, height);
+ Gdk.Drawable tmp = list_canvas;
+ list_canvas = list_canvas_b;
+ list_canvas_b = tmp;
+ } else {
+ clip.Height = list_canvas_alloc.Height;
+ list_canvas.DrawRectangle (Style.WhiteGC,
true, list_canvas_alloc);
+ }
+
+ paint = true;
+ }
+
+ list_canvas_index = index;
+ scroll_delta = 0;
+ previous_scroll_value = vadjustment.Value;
+ }
+
+ if (paint) {
+ list_cr = CairoHelper.CreateCairoDrawable (list_canvas);
+ list_cr.Rectangle (list_canvas_alloc.X,
list_canvas_alloc.Y, list_canvas_alloc.Width,
list_canvas_alloc.Height);
+ list_cr.Clip ();
+
+ Paint (PaintRows, evnt, clip, list_cr, ref
list_pango_layout, true);
+ }
+
+ list_window.DrawDrawable (Style.WhiteGC, list_canvas, 0,
list_canvas_offset, 0, 0, list_alloc.Width, list_alloc.Height);
+ }
- Gdk.Rectangle selected_focus_alloc = Gdk.Rectangle.Zero;
+ private void PaintRows (Gdk.EventExpose evnt, Gdk.Rectangle clip)
+ {
+ int first_row = list_canvas_index + clip.Y / RowHeight;
+ int last_row = Math.Min (model.Count, first_row +
clip.Height / RowHeight);
+
Gdk.Rectangle single_list_alloc = new Gdk.Rectangle ();
- single_list_alloc.Width = list_alloc.Width;
+ single_list_alloc.Width = clip.Width;
single_list_alloc.Height = RowHeight;
- single_list_alloc.X = list_alloc.X;
- single_list_alloc.Y = list_alloc.Y - vadjustment_value +
(first_row * single_list_alloc.Height);
+ single_list_alloc.X = clip.X;
+ single_list_alloc.Y = clip.Y;
int selection_height = 0;
int selection_y = 0;
List<int> selected_rows = new List<int> ();
+
+ bool focused_row_in_view = false;
for (int ri = first_row; ri < last_row; ri++) {
if (Selection.Contains (ri)) {
@@ -211,9 +317,31 @@
selection_height += single_list_alloc.Height;
selected_rows.Add (ri);
- if (focused_row_index == ri) {
- selected_focus_alloc = single_list_alloc;
+ if (ri == focused_row_index) {
+ focused_row_in_view = true;
}
+
+ if (last_row - first_row < list_canvas_size) {
+ if (ri == last_row - 1 && first_row ==
list_canvas_index) {
+ while (Selection.Contains (++ri) && ri <
list_canvas_index + list_canvas_size) {
+ selection_height += single_list_alloc.Height;
+ selected_rows.Add (ri);
+ if (ri == focused_row_index) {
+ focused_row_in_view = true;
+ }
+ }
+ } else if (ri == first_row && (last_row ==
list_canvas_index + list_canvas_size || last_row == model.Count)) {
+ int i = ri;
+ while (Selection.Contains (--i) && i >=
list_canvas_index) {
+ selection_height += single_list_alloc.Height;
+ selection_y -= single_list_alloc.Height;
+ selected_rows.Add (i);
+ if (i == focused_row_index) {
+ focused_row_in_view = true;
+ }
+ }
+ }
+ }
} else {
if (rules_hint && ri % 2 != 0) {
graphics.DrawRowRule (list_cr,
single_list_alloc.X, single_list_alloc.Y,
@@ -238,7 +366,7 @@
if (selection_height > 0) {
graphics.DrawRowSelection (
- list_cr, list_alloc.X, list_alloc.Y +
selection_y, list_alloc.Width, selection_height);
+ list_cr, list_canvas_alloc.X,
list_canvas_alloc.Y + selection_y, list_canvas_alloc.Width,
selection_height);
selection_height = 0;
}
@@ -249,18 +377,19 @@
}
if (selection_height > 0) {
- graphics.DrawRowSelection (list_cr, list_alloc.X,
list_alloc.Y + selection_y,
- list_alloc.Width, selection_height);
+ graphics.DrawRowSelection (list_cr,
list_canvas_alloc.X, selection_y,
+ list_canvas_alloc.Width, selection_height);
}
- if (Selection.Count > 1 && !selected_focus_alloc.Equals
(Gdk.Rectangle.Zero)) {
- graphics.DrawRowSelection (list_cr,
selected_focus_alloc.X, selected_focus_alloc.Y,
- selected_focus_alloc.Width,
selected_focus_alloc.Height, false, true,
+ if (focused_row_in_view) {
+ int focused_y = (focused_row_index -
list_canvas_index) * single_list_alloc.Height;
+ graphics.DrawRowSelection (list_cr,
single_list_alloc.X, focused_y,
+ single_list_alloc.Width,
single_list_alloc.Height, false, true,
graphics.GetWidgetColor (GtkColorClass.Dark,
StateType.Selected));
}
foreach (int ri in selected_rows) {
- single_list_alloc.Y = ri * single_list_alloc.Height -
vadjustment_value;
+ single_list_alloc.Y = (ri - list_canvas_index) *
single_list_alloc.Height;
PaintRow (ri, clip, single_list_alloc, StateType.Selected);
}
@@ -312,7 +441,7 @@
list_cr.Save ();
list_cr.Translate (clip.X, clip.Y);
- cell.Render (new CellContext (list_cr, list_pango_layout,
this, list_window, graphics, area),
+ cell.Render (new CellContext (list_cr, list_pango_layout,
this, list_canvas, graphics, area),
dragging? StateType.Normal : state, area.Width, area.Height);
list_cr.Restore ();
}
@@ -326,6 +455,7 @@
CachedColumn column = column_cache[pressed_column_index];
int x = pressed_column_x_drag;
+ int y = list_alloc.Y + list_canvas_offset;
Cairo.Color fill_color = graphics.GetWidgetColor
(GtkColorClass.Base, StateType.Normal);
fill_color.A = 0.45;
@@ -334,14 +464,14 @@
GtkColorClass.Base, StateType.Normal), 0.0);
stroke_color.A = 0.3;
- list_cr.Rectangle (x, list_alloc.Y, column.Width,
list_alloc.Height);
+ list_cr.Rectangle (x, y, column.Width, list_alloc.Height);
list_cr.Color = fill_color;
list_cr.Fill ();
- list_cr.MoveTo (x, list_alloc.Y);
- list_cr.LineTo (x, list_alloc.Y + list_alloc.Height - 1.0);
- list_cr.LineTo (x + column.Width, list_alloc.Y +
list_alloc.Height - 1.0);
- list_cr.LineTo (x + column.Width, list_alloc.Y);
+ list_cr.MoveTo (x, y);
+ list_cr.LineTo (x, y + list_alloc.Height - 1.0);
+ list_cr.LineTo (x + column.Width, y + list_alloc.Height - 1.0);
+ list_cr.LineTo (x + column.Width, y);
list_cr.Color = stroke_color;
list_cr.Antialias = Cairo.Antialias.None;
Index: src/Core/Hyena.Gui/Hyena.Data.Gui/ListView/ListView_Interaction.cs
===================================================================
--- src/Core/Hyena.Gui/Hyena.Data.Gui/ListView/ListView_Interaction.cs (revision
3222)
+++ src/Core/Hyena.Gui/Hyena.Data.Gui/ListView/ListView_Interaction.cs (working
copy)
@@ -458,8 +458,12 @@
vadjustment.Change ();
}
+ private double previous_scroll_value;
+ private double scroll_delta;
+
private void OnAdjustmentChanged (object o, EventArgs args)
{
+ scroll_delta = vadjustment.Value - previous_scroll_value;
InvalidateListWindow ();
}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]