summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorAlexander Larsson <alexl@redhat.com>2012-05-16 14:56:29 +0200
committerAlexander Larsson <alexl@redhat.com>2012-05-16 14:56:29 +0200
commitbb9e41d6204ed5f0793ecea2d0dd70e9e30ea944 (patch)
treec648b03611a77778c048d4208e6e41dc639bbd09 /src
parent661e6d465ceee51d27f283b2d11335c7b2bbe146 (diff)
parent736f1c9e3c5c8c539958532b3ea81b19fe822067 (diff)
downloadgnome-contacts-bb9e41d6204ed5f0793ecea2d0dd70e9e30ea944.tar.gz
Merge commit '736f1c9e3c5c8c539958532b3ea81b19fe822067'
Diffstat (limited to 'src')
-rw-r--r--src/listbox/Makefile.am8
-rw-r--r--src/listbox/egg-list-box.vala237
-rw-r--r--src/listbox/test-list.vala14
-rw-r--r--src/listbox/test-scrolled.vala97
4 files changed, 269 insertions, 87 deletions
diff --git a/src/listbox/Makefile.am b/src/listbox/Makefile.am
index d98958a..f2770ef 100644
--- a/src/listbox/Makefile.am
+++ b/src/listbox/Makefile.am
@@ -9,7 +9,7 @@ AM_VALAFLAGS = \
@LISTBOX_PACKAGES@ \
$(NULL)
-noinst_PROGRAMS = test-list
+noinst_PROGRAMS = test-list test-scrolled
test_list_SOURCES = \
egg-list-box.vala \
@@ -17,6 +17,12 @@ test_list_SOURCES = \
$(NULL)
test_list_LDADD = $(LISTBOX_LIBS)
+test_scrolled_SOURCES = \
+ egg-list-box.vala \
+ test-scrolled.vala \
+ $(NULL)
+test_scrolled_LDADD = $(LISTBOX_LIBS)
+
CLEANFILES = \
$(test_list_SOURCES:.vala=.c) \
*.vapi *.stamp
diff --git a/src/listbox/egg-list-box.vala b/src/listbox/egg-list-box.vala
index d0db9dd..c10bceb 100644
--- a/src/listbox/egg-list-box.vala
+++ b/src/listbox/egg-list-box.vala
@@ -22,24 +22,30 @@ public class Egg.ListBox : Container {
public delegate bool FilterFunc (Widget child);
public delegate void UpdateSeparatorFunc (ref Widget? separator, Widget child, Widget? before);
- private struct ChildInfo {
- Widget widget;
- Widget? separator;
- SequenceIter<ChildInfo?> iter;
- int y;
- int height;
+ private class ChildInfo {
+ public Widget widget;
+ public Widget? separator;
+ public SequenceIter<ChildInfo> iter;
+ public int y;
+ public int height;
+
+ public ChildInfo (Widget widget) {
+ this.widget = widget;
+ }
}
- private Sequence<ChildInfo?> children;
- private HashTable<unowned Widget, unowned ChildInfo?> child_hash;
+ private Sequence<ChildInfo> children;
+ private HashTable<unowned Widget, unowned ChildInfo> child_hash;
private CompareDataFunc<Widget>? sort_func;
private FilterFunc? filter_func;
private UpdateSeparatorFunc? update_separator_func;
- private unowned ChildInfo? selected_child;
- private unowned ChildInfo? prelight_child;
- private unowned ChildInfo? cursor_child;
+ private unowned ChildInfo selected_child;
+ private unowned ChildInfo prelight_child;
+ private unowned ChildInfo cursor_child;
+ bool active_child_active;
+ private unowned ChildInfo active_child;
private SelectionMode selection_mode;
-
+ private Adjustment? adjustment;
public ListBox () {
set_can_focus (true);
@@ -48,11 +54,11 @@ public class Egg.ListBox : Container {
selection_mode = SelectionMode.SINGLE;
- children = new Sequence<ChildInfo?>();
- child_hash = new HashTable<unowned Widget, unowned ChildInfo?> (GLib.direct_hash, GLib.direct_equal);
+ children = new Sequence<ChildInfo>();
+ child_hash = new HashTable<unowned Widget, unowned ChildInfo> (GLib.direct_hash, GLib.direct_equal);
}
- public Widget? get_selected_child (){
+ public unowned Widget? get_selected_child (){
if (selected_child != null)
return selected_child.widget;
@@ -62,7 +68,7 @@ public class Egg.ListBox : Container {
public void select_child (Widget? child) {
unowned ChildInfo? info = null;
if (child != null)
- info = child_hash.get (child);
+ info = lookup_info (child);
update_selected (info);
}
@@ -72,6 +78,15 @@ public class Egg.ListBox : Container {
public virtual signal void child_activated (Widget? child) {
}
+ public void set_adjustment (Adjustment? adjustment) {
+ this.adjustment = adjustment;
+ this.set_focus_vadjustment (adjustment);
+ }
+
+ public void add_to_scrolled (ScrolledWindow scrolled) {
+ scrolled.add_with_viewport (this);
+ this.set_adjustment (scrolled.get_vadjustment ());
+ }
public void set_selection_mode (SelectionMode mode) {
if (mode == SelectionMode.MULTIPLE) {
@@ -129,18 +144,20 @@ public class Egg.ListBox : Container {
this.queue_resize ();
}
apply_filter (info.widget);
- update_separator (info.iter);
- update_separator (get_next_visible (info.iter));
- update_separator (prev_next);
+ if (this.get_visible ()) {
+ update_separator (info.iter);
+ update_separator (get_next_visible (info.iter));
+ update_separator (prev_next);
+ }
}
/****** Implementation ***********/
- private int do_sort (ChildInfo? a, ChildInfo? b) {
+ private int do_sort (ChildInfo a, ChildInfo b) {
return sort_func (a.widget, b.widget);
}
-
+
[Signal (action=true)]
public virtual signal void activate_cursor_child () {
select_and_activate (cursor_child);
@@ -170,7 +187,7 @@ public class Egg.ListBox : Container {
modify_selection_pressed = true;
}
- unowned ChildInfo? child = null;
+ ChildInfo? child = null;
switch (step) {
case MovementStep.BUFFER_ENDS:
if (count < 0)
@@ -180,7 +197,7 @@ public class Egg.ListBox : Container {
break;
case MovementStep.DISPLAY_LINES:
if (cursor_child != null) {
- SequenceIter<ChildInfo?>? iter = cursor_child.iter;
+ SequenceIter<ChildInfo>? iter = cursor_child.iter;
while (count < 0 && iter != null) {
iter = get_previous_visible (iter);
@@ -197,14 +214,13 @@ public class Egg.ListBox : Container {
break;
case MovementStep.PAGES:
int page_size = 100;
- var vadj = get_focus_vadjustment ();
- if (vadj != null)
- page_size = (int) vadj.get_page_increment ();
+ if (adjustment != null)
+ page_size = (int) adjustment.get_page_increment ();
if (cursor_child != null) {
int start_y = cursor_child.y;
int end_y = start_y;
- SequenceIter<ChildInfo?>? iter = cursor_child.iter;
+ SequenceIter<ChildInfo>? iter = cursor_child.iter;
child = cursor_child;
if (count < 0) {
@@ -214,7 +230,7 @@ public class Egg.ListBox : Container {
iter = get_previous_visible (iter);
if (iter == null)
break;
- unowned ChildInfo? prev = iter.get ();
+ ChildInfo prev = iter.get ();
if (prev.y < start_y - page_size)
break;
child = prev;
@@ -226,15 +242,15 @@ public class Egg.ListBox : Container {
iter = get_next_visible (iter);
if (iter.is_end ())
break;
- unowned ChildInfo? next = iter.get ();
+ ChildInfo next = iter.get ();
if (next.y > start_y + page_size)
break;
child = next;
}
}
end_y = child.y;
- if (end_y != start_y && vadj != null)
- vadj.value += end_y - start_y;
+ if (end_y != start_y && adjustment != null)
+ adjustment.value += end_y - start_y;
}
break;
@@ -312,7 +328,7 @@ public class Egg.ListBox : Container {
unowned ChildInfo? find_child_at_y (int y) {
unowned ChildInfo? child_info = null;
for (var iter = children.get_begin_iter (); !iter.is_end (); iter = iter.next ()) {
- unowned ChildInfo? info = iter.get ();
+ unowned ChildInfo info = iter.get ();
if (y >= info.y && y < info.y + info.height) {
child_info = info;
break;
@@ -325,10 +341,9 @@ public class Egg.ListBox : Container {
cursor_child = child;
this.grab_focus ();
this.queue_draw ();
- var vadj = get_focus_vadjustment ();
- if (child != null && vadj != null)
- vadj.clamp_page (cursor_child.y,
- cursor_child.y + cursor_child.height);
+ if (child != null && adjustment != null)
+ adjustment.clamp_page (cursor_child.y,
+ cursor_child.y + cursor_child.height);
}
private void update_selected (ChildInfo? child) {
@@ -343,7 +358,7 @@ public class Egg.ListBox : Container {
}
private void select_and_activate (ChildInfo? child) {
- Widget? w = null;
+ unowned Widget? w = null;
if (child != null)
w = child.widget;
update_selected (child);
@@ -358,12 +373,21 @@ public class Egg.ListBox : Container {
}
}
+ private void update_active (ChildInfo? child) {
+ bool val = active_child == child;
+ if (active_child != null && val != active_child_active) {
+ active_child_active = val;
+ queue_draw ();
+ }
+ }
+
public override bool enter_notify_event (Gdk.EventCrossing event) {
if (event.window != get_window ())
return false;
unowned ChildInfo? child = find_child_at_y ((int)event.y);
update_prelight (child);
+ update_active (child);
return false;
}
@@ -372,12 +396,14 @@ public class Egg.ListBox : Container {
if (event.window != get_window ())
return false;
+ unowned ChildInfo? child;
if (event.detail != Gdk.NotifyType.INFERIOR) {
- update_prelight (null);
+ child = null;
} else {
- unowned ChildInfo? child = find_child_at_y ((int)event.y);
- update_prelight (child);
+ child = find_child_at_y ((int)event.y);
}
+ update_prelight (child);
+ update_active (child);
return false;
}
@@ -385,15 +411,19 @@ public class Egg.ListBox : Container {
public override bool motion_notify_event (Gdk.EventMotion event) {
unowned ChildInfo? child = find_child_at_y ((int)event.y);
update_prelight (child);
+ update_active (child);
+
return false;
}
- private Widget? button_down_child;
public override bool button_press_event (Gdk.EventButton event) {
if (event.button == 1) {
unowned ChildInfo? child = find_child_at_y ((int)event.y);
- if (child != null)
- button_down_child = child.widget;
+ if (child != null) {
+ active_child = child;
+ active_child_active = true;
+ queue_draw ();
+ }
/* TODO: Should mark as active while down, and handle grab breaks */
}
@@ -402,18 +432,24 @@ public class Egg.ListBox : Container {
public override bool button_release_event (Gdk.EventButton event) {
if (event.button == 1) {
- unowned ChildInfo? child = find_child_at_y ((int)event.y);
- if (child != null && child.widget == button_down_child)
- select_and_activate (child);
- button_down_child = null;
+ if (active_child != null && active_child_active)
+ select_and_activate (active_child);
+ active_child = null;
+ active_child_active = false;
+ queue_draw ();
}
return false;
}
+ public override void show () {
+ reseparate ();
+ base.show ();
+ }
+
public override bool focus (DirectionType direction) {
bool had_focus;
bool focus_into;
- Widget recurse_into = null;
+ unowned Widget recurse_into = null;
focus_into = true;
had_focus = has_focus;
@@ -523,28 +559,55 @@ public class Egg.ListBox : Container {
return true;
}
+ private struct ChildFlags {
+ unowned ChildInfo child;
+ StateFlags state;
+
+ public static ChildFlags *find_or_add (ref ChildFlags[] array, ChildInfo to_find) {
+ for (int i = 0; i < array.length; i++) {
+ if (array[i].child == to_find)
+ return &array[i];
+ }
+ array.resize (array.length+1);
+ array[array.length-1].child = to_find;
+ array[array.length-1].state = 0;
+ return &array[array.length-1];
+ }
+ }
+
public override bool draw (Cairo.Context cr) {
Allocation allocation;
this.get_allocation (out allocation);
- var context = this.get_style_context ();
+ unowned StyleContext context = this.get_style_context ();
- context.save ();
context.render_background (cr,
0, 0, allocation.width, allocation.height);
+ ChildFlags[] flags = {};
+
if (selected_child != null) {
- context.set_state (StateFlags.SELECTED);
- context.render_background (cr,
- 0, selected_child.y,
- allocation.width, selected_child.height);
+ var found = ChildFlags.find_or_add (ref flags, selected_child);
+ found.state |= StateFlags.SELECTED;
}
- if (prelight_child != null && prelight_child != selected_child) {
- context.set_state (StateFlags.PRELIGHT);
+ if (prelight_child != null) {
+ var found = ChildFlags.find_or_add (ref flags, prelight_child);
+ found.state |= StateFlags.PRELIGHT;
+ }
+
+ if (active_child != null && active_child_active) {
+ var found = ChildFlags.find_or_add (ref flags, active_child);
+ found.state |= StateFlags.ACTIVE;
+ }
+
+ foreach (unowned ChildFlags? flag in flags) {
+ context.save ();
+ context.set_state (flag.state);
context.render_background (cr,
- 0, prelight_child.y,
- allocation.width, prelight_child.height);
+ 0, flag.child.y,
+ allocation.width, flag.child.height);
+ context.restore ();
}
if (has_visible_focus() && cursor_child != null) {
@@ -552,8 +615,6 @@ public class Egg.ListBox : Container {
allocation.width, cursor_child.height);
}
- context.restore ();
-
base.draw (cr);
return true;
@@ -595,14 +656,14 @@ public class Egg.ListBox : Container {
private void apply_filter_all () {
for (var iter = children.get_begin_iter (); !iter.is_end (); iter = iter.next ()) {
- unowned ChildInfo? child_info = iter.get ();
+ unowned ChildInfo child_info = iter.get ();
apply_filter (child_info.widget);
}
}
private unowned ChildInfo? get_first_visible () {
for (var iter = children.get_begin_iter (); !iter.is_end (); iter = iter.next ()) {
- unowned ChildInfo? child_info = iter.get ();
+ unowned ChildInfo child_info = iter.get ();
unowned Widget widget = child_info.widget;
if (widget.get_visible () && widget.get_child_visible ())
return child_info;
@@ -614,7 +675,7 @@ public class Egg.ListBox : Container {
var iter = children.get_end_iter ();
while (!iter.is_begin ()) {
iter = iter.prev ();
- unowned ChildInfo? child_info = iter.get ();
+ unowned ChildInfo child_info = iter.get ();
unowned Widget widget = child_info.widget;
if (widget.get_visible () && widget.get_child_visible ())
return child_info;
@@ -622,7 +683,7 @@ public class Egg.ListBox : Container {
return null;
}
- private SequenceIter<ChildInfo?>? get_previous_visible (SequenceIter<ChildInfo?> _iter) {
+ private SequenceIter<ChildInfo>? get_previous_visible (SequenceIter<ChildInfo> _iter) {
if (_iter.is_begin())
return null;
var iter = _iter;
@@ -630,7 +691,7 @@ public class Egg.ListBox : Container {
do {
iter = iter.prev ();
- unowned ChildInfo? child_info = iter.get ();
+ unowned ChildInfo child_info = iter.get ();
unowned Widget widget = child_info.widget;
if (widget.get_visible () && widget.get_child_visible ())
return iter;
@@ -639,7 +700,7 @@ public class Egg.ListBox : Container {
return null;
}
- private SequenceIter<ChildInfo?>? get_next_visible (SequenceIter<ChildInfo?> _iter) {
+ private SequenceIter<ChildInfo>? get_next_visible (SequenceIter<ChildInfo> _iter) {
if (_iter.is_end())
return _iter;
@@ -648,7 +709,7 @@ public class Egg.ListBox : Container {
iter = iter.next ();
if (!iter.is_end ()) {
- unowned ChildInfo? child_info = iter.get ();
+ unowned ChildInfo child_info = iter.get ();
unowned Widget widget = child_info.widget;
if (widget.get_visible () && widget.get_child_visible ())
return iter;
@@ -658,16 +719,16 @@ public class Egg.ListBox : Container {
return iter;
}
- private void update_separator (SequenceIter<ChildInfo?>? iter) {
+ private void update_separator (SequenceIter<ChildInfo>? iter) {
if (iter == null || iter.is_end ())
return;
- unowned ChildInfo? info = iter.get ();
+ unowned ChildInfo info = iter.get ();
var before_iter = get_previous_visible (iter);
var widget = info.widget;
Widget? before_widget = null;
if (before_iter != null) {
- unowned ChildInfo? before_info = before_iter.get ();
+ unowned ChildInfo before_info = before_iter.get ();
before_widget = before_info.widget;
}
@@ -697,23 +758,24 @@ public class Egg.ListBox : Container {
}
public override void add (Widget widget) {
- ChildInfo? the_info = { widget };
- unowned ChildInfo? info = the_info;
- SequenceIter<ChildInfo?> iter;
+ ChildInfo info = new ChildInfo (widget);
+ SequenceIter<ChildInfo> iter;
child_hash.set (widget, info);
if (sort_func != null)
- iter = children.insert_sorted ((owned) the_info, do_sort);
+ iter = children.insert_sorted (info, do_sort);
else
- iter = children.append ((owned) the_info);
+ iter = children.append (info);
apply_filter (widget);
- var prev_next = get_next_visible (iter);
- update_separator (iter);
- update_separator (get_next_visible (iter));
- update_separator (prev_next);
+ if (this.get_visible ()) {
+ var prev_next = get_next_visible (iter);
+ update_separator (iter);
+ update_separator (get_next_visible (iter));
+ update_separator (prev_next);
+ }
info.iter = iter;
@@ -733,6 +795,8 @@ public class Egg.ListBox : Container {
prelight_child = null;
if (info == cursor_child)
cursor_child = null;
+ if (info == active_child)
+ active_child = null;
var next = get_next_visible (info.iter);
@@ -742,7 +806,8 @@ public class Egg.ListBox : Container {
child_hash.remove (widget);
children.remove (info.iter);
- update_separator (next);
+ if (this.get_visible ())
+ update_separator (next);
if (was_visible && this.get_visible ())
this.queue_resize ();
@@ -751,7 +816,7 @@ public class Egg.ListBox : Container {
public override void forall_internal (bool include_internals,
Gtk.Callback callback) {
for (var iter = children.get_begin_iter (); !iter.is_end (); iter = iter.next ()) {
- unowned ChildInfo? child_info = iter.get ();
+ unowned ChildInfo child_info = iter.get ();
if (child_info.separator != null && include_internals)
callback (child_info.separator);
callback (child_info.widget);
@@ -780,12 +845,12 @@ public class Egg.ListBox : Container {
public override void get_preferred_height_for_width (int width, out int minimum_height, out int natural_height) {
minimum_height = 0;
- var context = this.get_style_context ();
+ unowned StyleContext context = this.get_style_context ();
int focus_width, focus_pad;
context.get_style ("focus-line-width", out focus_width,
"focus-padding", out focus_pad);
for (var iter = children.get_begin_iter (); !iter.is_end (); iter = iter.next ()) {
- unowned ChildInfo? child_info = iter.get ();
+ unowned ChildInfo child_info = iter.get ();
unowned Widget widget = child_info.widget;
int child_min;
@@ -811,14 +876,14 @@ public class Egg.ListBox : Container {
}
public override void get_preferred_width (out int minimum_width, out int natural_width) {
- var context = this.get_style_context ();
+ unowned StyleContext context = this.get_style_context ();
int focus_width, focus_pad;
context.get_style ("focus-line-width", out focus_width,
"focus-padding", out focus_pad);
minimum_width = 0;
natural_width = 0;
for (var iter = children.get_begin_iter (); !iter.is_end (); iter = iter.next ()) {
- unowned ChildInfo? child_info = iter.get ();
+ unowned ChildInfo child_info = iter.get ();
unowned Widget widget = child_info.widget;
int child_min, child_nat;
@@ -867,7 +932,7 @@ public class Egg.ListBox : Container {
separator_allocation.width = allocation.width;
for (var iter = children.get_begin_iter (); !iter.is_end (); iter = iter.next ()) {
- unowned ChildInfo? child_info = iter.get ();
+ unowned ChildInfo child_info = iter.get ();
unowned Widget widget = child_info.widget;
int child_min;
diff --git a/src/listbox/test-list.vala b/src/listbox/test-list.vala
index 0c1c06a..e18d258 100644
--- a/src/listbox/test-list.vala
+++ b/src/listbox/test-list.vala
@@ -183,6 +183,20 @@ main (string[] args) {
w.show_all ();
+ var provider = new Gtk.CssProvider ();
+ provider.load_from_data (
+"""
+EggListBox:prelight {
+background-color: green;
+}
+EggListBox:active {
+background-color: red;
+}
+""", -1);
+ Gtk.StyleContext.add_provider_for_screen (Gdk.Screen.get_default (),
+ provider,
+ 600);
+
Gtk.main ();
return 0;
diff --git a/src/listbox/test-scrolled.vala b/src/listbox/test-scrolled.vala
new file mode 100644
index 0000000..669b91e
--- /dev/null
+++ b/src/listbox/test-scrolled.vala
@@ -0,0 +1,97 @@
+/* -*- Mode: vala; indent-tabs-mode: t; c-basic-offset: 2; tab-width: 8 -*- */
+/*
+ * Copyright (C) 2011 Alexander Larsson <alexl@redhat.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+using Gtk;
+using Egg;
+
+class Row : Grid {
+ public int32 value;
+ public Row () {
+ value = Random.int_range (0, 10000);
+ var l = new Label ("Value %u".printf (value));
+ this.add (l);
+ l.show ();
+ }
+
+
+}
+public static int
+compare (Widget a, Widget b) {
+ return (int32)(b as Row).value - (int32)(a as Row).value;
+}
+
+public static bool
+filter (Widget widget) {
+ return (widget as Row).value % 2 == 0;
+}
+
+public static int
+main (string[] args) {
+ int num_rows = 0;
+
+ Gtk.init (ref args);
+
+ if (args.length > 1)
+ num_rows = int.parse (args[1]);
+
+ if (num_rows == 0)
+ num_rows = 1000;
+
+ var w = new Window ();
+ var hbox = new Box(Orientation.HORIZONTAL, 0);
+ w.add (hbox);
+
+ var scrolled = new ScrolledWindow (null, null);
+ scrolled.set_policy (PolicyType.NEVER, PolicyType.AUTOMATIC);
+ hbox.add (scrolled);
+
+ var list = new ListBox();
+ list.add_to_scrolled (scrolled);
+
+ for (int i = 0; i < num_rows; i++) {
+ var row = new Row ();
+ list.add (row);
+ }
+ var vbox = new Box(Orientation.VERTICAL, 0);
+ hbox.add (vbox);
+
+ var b = new Button.with_label ("sort");
+ vbox.add (b);
+ b.clicked.connect ( () => {
+ list.set_sort_func (compare);
+ });
+
+ b = new Button.with_label ("filter");
+ vbox.add (b);
+ b.clicked.connect ( () => {
+ list.set_filter_func (filter);
+ });
+
+ b = new Button.with_label ("unfilter");
+ vbox.add (b);
+ b.clicked.connect ( () => {
+ list.set_filter_func (null);
+ });
+
+ w.show_all ();
+
+
+ Gtk.main ();
+
+ return 0;
+}