[hyena] [Hyena.Data.Gui] Work to unify list and grid modes
- From: Gabriel Burt <gburt src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [hyena] [Hyena.Data.Gui] Work to unify list and grid modes
- Date: Tue, 19 Oct 2010 23:31:02 +0000 (UTC)
commit 832077bc3e8515e065d0cbbd69b46b0484904444
Author: Gabriel Burt <gabriel burt gmail com>
Date: Tue Oct 19 15:18:36 2010 -0500
[Hyena.Data.Gui] Work to unify list and grid modes
Make ColumnCell subclass from DataViewChild, and add DataViewChildBox
that can be used to pack multiple DataViewChild objects (including other
boxes) into a single cell. Can be used to construct the album browser
grid cells from an image cell and two text cells, instead of one
monolithic cell with complicated, repetitive drawing/measuring logic.
Hyena.Gui/Hyena.Data.Gui/CellContext.cs | 1 +
Hyena.Gui/Hyena.Data.Gui/Column.cs | 2 +-
Hyena.Gui/Hyena.Data.Gui/ColumnCell.cs | 99 +++---------
Hyena.Gui/Hyena.Data.Gui/ColumnCellCheckBox.cs | 22 ++-
Hyena.Gui/Hyena.Data.Gui/ColumnCellRating.cs | 24 ++-
Hyena.Gui/Hyena.Data.Gui/ColumnCellText.cs | 62 +++++--
Hyena.Gui/Hyena.Data.Gui/ColumnHeaderCellText.cs | 6 +-
Hyena.Gui/Hyena.Data.Gui/DataViewChild.cs | 98 ++++++++++-
Hyena.Gui/Hyena.Data.Gui/DataViewChildBox.cs | 181 ++++++++++++++++++++
Hyena.Gui/Hyena.Data.Gui/IInteractiveCell.cs | 9 +-
Hyena.Gui/Hyena.Data.Gui/ListView/ListView.cs | 1 +
Hyena.Gui/Hyena.Data.Gui/ListView/ListViewBase.cs | 4 +-
.../ListView/ListView_Interaction.cs | 9 +-
.../Hyena.Data.Gui/ListView/ListView_Rendering.cs | 17 ++
Hyena.Gui/Hyena.Gui.Canvas/Thickness.cs | 2 +
Hyena.Gui/Makefile.am | 1 +
16 files changed, 407 insertions(+), 131 deletions(-)
---
diff --git a/Hyena.Gui/Hyena.Data.Gui/CellContext.cs b/Hyena.Gui/Hyena.Data.Gui/CellContext.cs
index 8927060..3bdb05e 100644
--- a/Hyena.Gui/Hyena.Data.Gui/CellContext.cs
+++ b/Hyena.Gui/Hyena.Data.Gui/CellContext.cs
@@ -52,5 +52,6 @@ namespace Hyena.Data.Gui
public int ViewRowIndex { get; set; }
public int ViewColumnIndex { get; set; }
public int ModelRowIndex { get; set; }
+ public bool IsRtl { get; set; }
}
}
diff --git a/Hyena.Gui/Hyena.Data.Gui/Column.cs b/Hyena.Gui/Hyena.Data.Gui/Column.cs
index 5840764..90e4238 100644
--- a/Hyena.Gui/Hyena.Data.Gui/Column.cs
+++ b/Hyena.Gui/Hyena.Data.Gui/Column.cs
@@ -156,7 +156,7 @@ namespace Hyena.Data.Gui
// Pretty sure the 3* is needed here only b/c of the " - 8" in ColumnCellText;
// See TODO there
- w += 3 * ColumnHeaderCellText.Spacing;
+ w += 3 * (int)header_cell.Padding.Left;
if (this is ISortableColumn) {
w += ColumnHeaderCellText.GetArrowWidth (headerHeight);
}
diff --git a/Hyena.Gui/Hyena.Data.Gui/ColumnCell.cs b/Hyena.Gui/Hyena.Data.Gui/ColumnCell.cs
index 20e8c57..89512e0 100644
--- a/Hyena.Gui/Hyena.Data.Gui/ColumnCell.cs
+++ b/Hyena.Gui/Hyena.Data.Gui/ColumnCell.cs
@@ -31,18 +31,13 @@ using System.Reflection;
using Gtk;
using Cairo;
+using Hyena.Gui.Canvas;
using Hyena.Data.Gui.Accessibility;
namespace Hyena.Data.Gui
{
- public abstract class ColumnCell
+ public abstract class ColumnCell : DataViewChild
{
- private bool expand;
- private string property, sub_property;
- private PropertyInfo property_info, sub_property_info;
- private object bound_object;
- private object bound_object_parent;
-
public virtual Atk.Object GetAccessible (ICellAccessibleParent parent)
{
return new ColumnCellAccessible (BoundObject, this, parent);
@@ -61,98 +56,44 @@ namespace Hyena.Data.Gui
public void BindListItem (object item)
{
- if (item == null) {
- bound_object_parent = null;
- bound_object = null;
- return;
- }
-
- bound_object_parent = item;
-
- if (property != null) {
- EnsurePropertyInfo ();
- bound_object = property_info.GetValue (bound_object_parent, null);
-
- if (sub_property != null) {
- EnsurePropertyInfo (sub_property, ref sub_property_info, bound_object);
- bound_object = sub_property_info.GetValue (bound_object, null);
- }
- } else {
- bound_object = bound_object_parent;
- }
+ BindDataItem (item);
}
- private void EnsurePropertyInfo ()
+ public virtual void NotifyThemeChange ()
{
- EnsurePropertyInfo (property, ref property_info, bound_object_parent);
}
- private void EnsurePropertyInfo (string name, ref PropertyInfo prop, object obj)
+ public virtual Gdk.Size Measure (Widget widget)
{
- if (prop == null || prop.ReflectedType != obj.GetType ()) {
- prop = obj.GetType ().GetProperty (name);
- if (prop == null) {
- throw new Exception (String.Format (
- "In {0}, type {1} does not have property {2}",
- this, obj.GetType (), name
- ));
- }
- }
+ return Gdk.Size.Empty;
}
- public virtual void NotifyThemeChange ()
+ protected override void RenderCore (CellContext context)
{
+ Render (context, context.State, Allocation.Width, Allocation.Height);
}
- protected Type BoundType {
- get { return bound_object.GetType (); }
- }
-
- protected object BoundObject {
- get { return bound_object; }
- set {
- if (property != null) {
- EnsurePropertyInfo ();
- property_info.SetValue (bound_object_parent, value, null);
- }
- }
- }
+ public abstract void Render (CellContext context, StateType state, double cellWidth, double cellHeight);
- protected object BoundObjectParent {
- get { return bound_object_parent; }
- }
+ public bool Expand { get; set; }
- public abstract void Render (CellContext context, StateType state, double cellWidth, double cellHeight);
+ public Size? FixedSize { get; set; }
- public virtual Gdk.Size Measure (Gtk.Widget widget)
+ public override Size Measure (Size available)
{
- return Gdk.Size.Empty;
+ // FIXME
+ return FixedSize ?? new Size (0, 0);
}
- public bool Expand {
- get { return expand; }
- set { expand = value; }
- }
-
- public DataViewLayout ViewLayout { get; set; }
-
- public string Property {
- get { return property; }
- set {
- property = value;
- if (value != null) {
- int i = value.IndexOf (".");
- if (i != -1) {
- property = value.Substring (0, i);
- SubProperty = value.Substring (i + 1, value.Length - i - 1);
- }
- }
+ public override void Invalidate ()
+ {
+ if (ParentLayout != null) {
+ base.Invalidate ();
}
}
- public string SubProperty {
- get { return sub_property; }
- set { sub_property = value; }
+ public override void Arrange ()
+ {
}
}
}
diff --git a/Hyena.Gui/Hyena.Data.Gui/ColumnCellCheckBox.cs b/Hyena.Gui/Hyena.Data.Gui/ColumnCellCheckBox.cs
index 0697080..444083a 100644
--- a/Hyena.Gui/Hyena.Data.Gui/ColumnCellCheckBox.cs
+++ b/Hyena.Gui/Hyena.Data.Gui/ColumnCellCheckBox.cs
@@ -29,6 +29,8 @@
using System;
using Gtk;
+using Hyena.Gui.Canvas;
+
namespace Hyena.Data.Gui
{
public class ColumnCellCheckBox : ColumnCell, IInteractiveCell, ISizeRequestCell
@@ -39,10 +41,15 @@ namespace Hyena.Data.Gui
{
}
+ public override Size Measure (Size available)
+ {
+ return new Size (Size + 2 * Xpad, Size + 2 * Ypad);
+ }
+
public override void Render (CellContext context, StateType state, double cellWidth, double cellHeight)
{
- int cell_width = context.Area.Width - 2 * Xpad;
- int cell_height = context.Area.Height - 2 * Ypad;
+ int cell_width = (int)cellWidth - 2 * Xpad;
+ int cell_height = (int)cellHeight - 2 * Ypad;
int x = context.Area.X + xpad + ((cell_width - Size) / 2);
int y = context.Area.Y + ypad + ((cell_height - Size) / 2);
@@ -58,7 +65,7 @@ namespace Hyena.Data.Gui
private object last_pressed_bound;
private object last_hover_bound;
- public bool ButtonEvent (int x, int y, bool pressed, Gdk.EventButton evnt)
+ public override bool ButtonEvent (Point press, bool pressed, uint button)
{
if (pressed) {
last_pressed_bound = BoundObjectParent;
@@ -73,24 +80,29 @@ namespace Hyena.Data.Gui
if (handler != null) {
handler (BoundObjectParent, EventArgs.Empty);
}
+
+ Invalidate ();
}
return true;
}
- public bool MotionEvent (int x, int y, Gdk.EventMotion evnt)
+ public override bool CursorMotionEvent (Point motion)
{
if (last_hover_bound == BoundObjectParent) {
return false;
}
last_hover_bound = BoundObjectParent;
+ Invalidate ();
return true;
}
- public bool PointerLeaveEvent ()
+ public override bool CursorLeaveEvent ()
{
+ base.CursorLeaveEvent ();
last_hover_bound = null;
+ Invalidate ();
return true;
}
diff --git a/Hyena.Gui/Hyena.Data.Gui/ColumnCellRating.cs b/Hyena.Gui/Hyena.Data.Gui/ColumnCellRating.cs
index e1efeb2..640cd93 100644
--- a/Hyena.Gui/Hyena.Data.Gui/ColumnCellRating.cs
+++ b/Hyena.Gui/Hyena.Data.Gui/ColumnCellRating.cs
@@ -30,6 +30,7 @@ using System;
using Gtk;
using Hyena.Gui;
+using Hyena.Gui.Canvas;
using Hyena.Gui.Theming;
namespace Hyena.Data.Gui
@@ -47,9 +48,14 @@ namespace Hyena.Data.Gui
Xpad = 0;
}
+ public override Size Measure (Size available)
+ {
+ return new Size (renderer.Width, renderer.Height);
+ }
+
public override void Render (CellContext context, StateType state, double cellWidth, double cellHeight)
{
- Gdk.Rectangle area = new Gdk.Rectangle (0, 0, context.Area.Width, context.Area.Height);
+ Gdk.Rectangle area = new Gdk.Rectangle (0, 0, (int)cellWidth, (int)cellHeight);
// FIXME: Compute font height and set to renderer.Size
@@ -65,7 +71,7 @@ namespace Hyena.Data.Gui
actual_area_hack = area;
}
- public bool ButtonEvent (int x, int y, bool pressed, Gdk.EventButton evnt)
+ public override bool ButtonEvent (Point press, bool pressed, uint button)
{
if (ReadOnly) {
return false;
@@ -76,21 +82,22 @@ namespace Hyena.Data.Gui
return false;
}
- if (last_pressed_bound == BoundObjectParent) {
- Value = RatingFromPosition (x);
+ if (last_pressed_bound == BoundObjectParent && last_pressed_bound != null) {
+ Value = RatingFromPosition (press.X);
+ Invalidate ();
last_pressed_bound = null;
}
return true;
}
- public bool MotionEvent (int x, int y, Gdk.EventMotion evnt)
+ public override bool CursorMotionEvent (Point motion)
{
if (ReadOnly) {
return false;
}
- int value = RatingFromPosition (x);
+ int value = RatingFromPosition (motion.X);
if (hover_bound == BoundObjectParent && value == hover_value) {
return false;
@@ -98,13 +105,16 @@ namespace Hyena.Data.Gui
hover_bound = BoundObjectParent;
hover_value = value;
+ Invalidate ();
return true;
}
- public bool PointerLeaveEvent ()
+ public override bool CursorLeaveEvent ()
{
+ base.CursorLeaveEvent ();
hover_bound = null;
hover_value = MinRating - 1;
+ Invalidate ();
return true;
}
diff --git a/Hyena.Gui/Hyena.Data.Gui/ColumnCellText.cs b/Hyena.Gui/Hyena.Data.Gui/ColumnCellText.cs
index 0a2c126..7662b69 100644
--- a/Hyena.Gui/Hyena.Data.Gui/ColumnCellText.cs
+++ b/Hyena.Gui/Hyena.Data.Gui/ColumnCellText.cs
@@ -31,6 +31,7 @@ using Gtk;
using Cairo;
using Hyena.Gui;
+using Hyena.Gui.Canvas;
using Hyena.Gui.Theming;
using Hyena.Data.Gui.Accessibility;
@@ -38,8 +39,6 @@ namespace Hyena.Data.Gui
{
public class ColumnCellText : ColumnCell, ISizeRequestCell, ITextCell, ITooltipCell
{
- internal const int Spacing = 4;
-
public delegate string DataHandler ();
private Pango.Weight font_weight = Pango.Weight.Normal;
@@ -54,6 +53,7 @@ namespace Hyena.Data.Gui
public ColumnCellText (string property, bool expand) : base (property, expand)
{
+ Padding = new Thickness (4, 0);
}
public override Atk.Object GetAccessible (ICellAccessibleParent parent)
@@ -79,6 +79,25 @@ namespace Hyena.Data.Gui
RestrictSize = true;
}
+ int? height;
+ public override Size Measure (Size available)
+ {
+ //int min, max;
+ //GetWidthRange (ParentLayout.View.PangoLayout, out min, out max);
+ //
+ if (height == null) {
+ using (var layout = new Pango.Layout (ParentLayout.View.PangoContext)) {
+ if (layout.FontDescription == null) {
+ layout.FontDescription = new Pango.FontDescription ();
+ }
+ UpdateText (layout, 100, "Woo Mar");
+ height = TextHeight;
+ }
+ }
+
+ return FixedSize ?? new Size (0, (double)height + Padding.Y);
+ }
+
public override void Render (CellContext context, StateType state, double cellWidth, double cellHeight)
{
UpdateText (context, cellWidth);
@@ -86,34 +105,37 @@ namespace Hyena.Data.Gui
return;
}
- context.Context.Rectangle (0, 0, cellWidth, cellHeight);
- context.Context.Clip ();
- context.Context.MoveTo (Spacing, ((int)cellHeight - text_height) / 2);
+ //context.Context.Rectangle (0, 0, cellWidth, cellHeight);
+ //context.Context.Clip ();
+ context.Context.MoveTo (Padding.Left, ((int)cellHeight - text_height) / 2);
Cairo.Color color = context.Theme.Colors.GetWidgetColor (
context.TextAsForeground ? GtkColorClass.Foreground : GtkColorClass.Text, state);
- color.A = context.Opaque ? 1.0 : 0.5;
+ color.A = Alpha ?? (context.Opaque ? 1.0 : 0.5);
context.Context.Color = color;
PangoCairoHelper.ShowLayout (context.Context, context.Layout);
- context.Context.ResetClip ();
+ //context.Context.ResetClip ();
}
public void UpdateText (CellContext context, double cellWidth)
{
string text = last_text = GetText (BoundObject);
+ UpdateText (context.Layout, cellWidth, text);
+ }
+
+ public void UpdateText (Pango.Layout layout, double cellWidth, string text)
+ {
if (String.IsNullOrEmpty (text)) {
return;
}
- // TODO why doesn't Spacing (eg 4 atm) work here instead of 8? Rendering
- // seems to be off when changed to Spacing/4
- context.Layout.Width = (int)((cellWidth - 8) * Pango.Scale.PangoScale);
- context.Layout.FontDescription.Weight = font_weight;
- context.Layout.Ellipsize = EllipsizeMode;
- context.Layout.Alignment = alignment;
- UpdateLayout (context.Layout, text);
- context.Layout.GetPixelSize (out text_width, out text_height);
- is_ellipsized = context.Layout.IsEllipsized;
+ layout.Width = (int)((cellWidth - Padding.X) * Pango.Scale.PangoScale);
+ layout.FontDescription.Weight = font_weight;
+ layout.Ellipsize = EllipsizeMode;
+ layout.Alignment = alignment;
+ UpdateLayout (layout, text);
+ layout.GetPixelSize (out text_width, out text_height);
+ is_ellipsized = layout.IsEllipsized;
}
private static char[] lfcr = new char[] {'\n', '\r'};
@@ -146,7 +168,7 @@ namespace Hyena.Data.Gui
if (text_format == null) {
return text;
}
- return String.Format (text_format, text);
+ return String.Format (text_format, UseMarkup ? GLib.Markup.EscapeText (text) : text);
}
private bool is_ellipsized = false;
@@ -206,14 +228,14 @@ namespace Hyena.Data.Gui
if (!String.IsNullOrEmpty (MinString)) {
UpdateLayout (layout, MinString);
layout.GetPixelSize (out min, out height);
- min += 2*Spacing;
+ min += (int)Padding.X;
//Console.WriteLine ("for {0} got min {1} for {2}", this, min, MinString);
}
if (!String.IsNullOrEmpty (MaxString)) {
UpdateLayout (layout, MaxString);
layout.GetPixelSize (out max, out height);
- max += 2*Spacing;
+ max += (int)Padding.X;
//Console.WriteLine ("for {0} got max {1} for {2}", this, max, MaxString);
}
}
@@ -229,6 +251,8 @@ namespace Hyena.Data.Gui
set { use_markup = value; }
}
+ public double? Alpha { get; set; }
+
#endregion
}
}
diff --git a/Hyena.Gui/Hyena.Data.Gui/ColumnHeaderCellText.cs b/Hyena.Gui/Hyena.Data.Gui/ColumnHeaderCellText.cs
index 167cd2f..e661627 100644
--- a/Hyena.Gui/Hyena.Data.Gui/ColumnHeaderCellText.cs
+++ b/Hyena.Gui/Hyena.Data.Gui/ColumnHeaderCellText.cs
@@ -66,10 +66,10 @@ namespace Hyena.Data.Gui
Gdk.Rectangle arrow_alloc = new Gdk.Rectangle ();
arrow_alloc.Width = (int)(cellHeight / 3.0);
arrow_alloc.Height = (int)((double)arrow_alloc.Width / 1.6);
- arrow_alloc.X = (int)cellWidth - arrow_alloc.Width - Spacing;
+ arrow_alloc.X = (int)cellWidth - arrow_alloc.Width - (int)Padding.Left;
arrow_alloc.Y = ((int)cellHeight - arrow_alloc.Height) / 2;
- double textWidth = arrow_alloc.X - Spacing;
+ double textWidth = arrow_alloc.X - Padding.Left;
if (textWidth > 0) {
base.Render (context, state, textWidth, cellHeight);
}
@@ -92,7 +92,7 @@ namespace Hyena.Data.Gui
public static int GetArrowWidth (int headerHeight)
{
- return (int)(headerHeight / 3.0) + Spacing;
+ return (int)(headerHeight / 3.0) + 4;
}
}
}
diff --git a/Hyena.Gui/Hyena.Data.Gui/DataViewChild.cs b/Hyena.Gui/Hyena.Data.Gui/DataViewChild.cs
index 30c3886..963b298 100644
--- a/Hyena.Gui/Hyena.Data.Gui/DataViewChild.cs
+++ b/Hyena.Gui/Hyena.Data.Gui/DataViewChild.cs
@@ -29,13 +29,28 @@
using System;
using System.Reflection;
+using Hyena.Gui;
using Hyena.Gui.Canvas;
+using Hyena.Gui.Theatrics;
namespace Hyena.Data.Gui
{
public abstract class DataViewChild : CanvasItem
{
- public DataViewLayout ParentLayout { get; set; }
+ private DataViewLayout layout;
+ public DataViewLayout ParentLayout {
+ get {
+ if (layout == null) {
+ var parent = Parent as DataViewChild;
+ if (parent != null) {
+ layout = parent.ParentLayout;
+ }
+ }
+ return layout;
+ }
+ set { layout = value; }
+ }
+
public int ModelRowIndex { get; set; }
protected override void OnInvalidate (Rect area)
@@ -43,12 +58,25 @@ namespace Hyena.Data.Gui
ParentLayout.View.QueueDirtyRegion (area);
}
+ protected Rect TopLevelAllocation {
+ get {
+ var alloc = Allocation;
+ var top = (CanvasItem)this;
+ while (top.Parent != null) {
+ alloc.Offset (top.Parent.Allocation);
+ top = top.Parent;
+ }
+
+ return alloc;
+ }
+ }
+
#region Data Binding
private PropertyInfo property_info;
private PropertyInfo sub_property_info;
- public void BindDataItem (object item)
+ public virtual void BindDataItem (object item)
{
if (item == null) {
BoundObjectParent = null;
@@ -130,7 +158,15 @@ namespace Hyena.Data.Gui
public Thickness Margin { get; set; }
public Thickness Padding { get; set; }
- public abstract void Render (CellContext context);
+ public void Render (CellContext context)
+ {
+ RenderCore (context);
+ if (HasPrelight && prelight_opacity > 0) {
+ RenderPrelight (context);
+ }
+ }
+
+ protected abstract void RenderCore (CellContext context);
public abstract void Arrange ();
public abstract Size Measure (Size available);
@@ -140,11 +176,15 @@ namespace Hyena.Data.Gui
public void Invalidate (Rect area)
{
- area.Offset (Allocation.X, Allocation.Y);
- OnInvalidate (area);
+ if (Parent == null) {
+ OnInvalidate (area);
+ } else {
+ area.Offset (Parent.Allocation.X, Parent.Allocation.Y);
+ Parent.Invalidate (area);
+ }
}
- public void Invalidate ()
+ public virtual void Invalidate ()
{
Invalidate (Allocation);
}
@@ -161,10 +201,54 @@ namespace Hyena.Data.Gui
public virtual void CursorEnterEvent ()
{
+ if (HasPrelight) {
+ prelight_in = true;
+ prelight_stage.AddOrReset (this);
+ }
}
- public virtual void CursorLeaveEvent ()
+ public virtual bool CursorLeaveEvent ()
+ {
+ if (HasPrelight) {
+ prelight_in = false;
+ prelight_stage.AddOrReset (this);
+ }
+ return false;
+ }
+
+ private static Stage<CanvasItem> prelight_stage = new Stage<CanvasItem> (250);
+ private bool prelight_in;
+ private double prelight_opacity;
+
+ static CanvasItem ()
+ {
+ prelight_stage.ActorStep += actor => {
+ var alpha = actor.Target.prelight_opacity;
+ alpha += actor.Target.prelight_in
+ ? actor.StepDeltaPercent
+ : -actor.StepDeltaPercent;
+ actor.Target.prelight_opacity = alpha = Math.Max (0.0, Math.Min (1.0, alpha));
+ actor.Target.Invalidate ();
+ return alpha > 0 && alpha < 1;
+ };
+ }
+
+ public bool HasPrelight { get; set; }
+
+ protected virtual void RenderPrelight (CellContext context)
{
+ var cr = context.Context;
+
+ var x = Allocation.Width / 2.0;
+ var y = Allocation.Height / 2.0;
+ var grad = new Cairo.RadialGradient (x, y, 0, x, y, Allocation.Width / 2.0);
+ grad.AddColorStop (0, new Cairo.Color (0, 0, 0, 0.1 * prelight_opacity));
+ grad.AddColorStop (1, new Cairo.Color (0, 0, 0, 0.35 * prelight_opacity));
+ cr.Pattern = grad;
+ CairoExtensions.RoundedRectangle (cr, 0, 0,
+ Allocation.Width, Allocation.Height, context.Theme.Context.Radius);
+ cr.Fill ();
+ grad.Destroy ();
}
}
}
diff --git a/Hyena.Gui/Hyena.Data.Gui/DataViewChildBox.cs b/Hyena.Gui/Hyena.Data.Gui/DataViewChildBox.cs
new file mode 100644
index 0000000..d70a48e
--- /dev/null
+++ b/Hyena.Gui/Hyena.Data.Gui/DataViewChildBox.cs
@@ -0,0 +1,181 @@
+//
+// DataViewChildBox.cs
+//
+// Author:
+// Gabriel Burt <gburt novell com>
+//
+// Copyright 2010 Novell, Inc.
+//
+// Permission is hereby granted, free of charge, to any person obtaining
+// a copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to
+// permit persons to whom the Software is furnished to do so, subject to
+// the following conditions:
+//
+// The above copyright notice and this permission notice shall be
+// included in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+//
+
+using System;
+using System.Linq;
+using System.Collections.Generic;
+using System.Reflection;
+
+using Hyena.Gui.Canvas;
+
+namespace Hyena.Data.Gui
+{
+ public class DataViewChildBox : DataViewChild
+ {
+ public bool Horizontal { get; set; }
+
+ private List<DataViewChild> children = new List<DataViewChild> ();
+ public IEnumerable<DataViewChild> Children { get { return children; } }
+
+ public DataViewChildBox (params DataViewChild [] children)
+ {
+ Add (children);
+ }
+
+ public void Add (params DataViewChild [] children)
+ {
+ this.children.AddRange (children);
+ ForEach (child => child.Parent = this);
+ }
+
+ private void ForEach (Action<DataViewChild> action)
+ {
+ foreach (var child in Children) {
+ action (child);
+ }
+ }
+
+ public override void BindDataItem (object item)
+ {
+ base.BindDataItem (item);
+ ForEach (child => child.BindDataItem (item));
+ }
+
+ protected override void RenderCore (CellContext context)
+ {
+ var itr = Horizontal && context.IsRtl ? Children.Reverse () : Children;
+ foreach (var child in itr) {
+ RenderChild (child, context);
+ }
+ }
+
+ private void RenderChild (DataViewChild child, CellContext context)
+ {
+ var cairo_context = context.Context;
+ var child_allocation = child.Allocation;
+
+ context.Area = (Gdk.Rectangle) TopLevelAllocation;
+ cairo_context.Save ();
+ cairo_context.Translate (child_allocation.X, child_allocation.Y);
+ //cairo_context.Rectangle (0, 0, child_allocation.Width, child_allocation.Height);
+ //cairo_context.Clip ();
+ child.Render (context);
+ cairo_context.Restore ();
+ }
+
+ public override void Arrange ()
+ {
+ ForEach (child => child.Arrange ());
+ }
+
+ public override Size Measure (Size available)
+ {
+ double x = Padding.Left, y = Padding.Top;
+ double width = 0, height = 0;
+ foreach (var child in Children) {
+ var size = child.Measure (available);
+ child.Allocation = new Rect (x, y, size.Width, size.Height);
+
+ // TODO account for childrens' padding/margin
+ if (Horizontal) {
+ width += size.Width;
+ height = Math.Max (height, size.Height);
+ x += size.Width;
+ } else {
+ width = Math.Max (width, size.Width);
+ height += size.Height;
+ y += size.Height;
+ }
+ }
+
+ foreach (var child in Children) {
+ var a = child.Allocation;
+ if (Horizontal) {
+ child.Allocation = new Rect (a.X, a.Y, a.Width, height);
+ } else {
+ child.Allocation = new Rect (a.X, a.Y, width, a.Height);
+ }
+ }
+
+ return new Size (width + Padding.X, height + Padding.Y);
+ }
+
+ public override bool ButtonEvent (Point cursor, bool pressed, uint button)
+ {
+ var child = FindChildAt (cursor);
+ return child == null ? false : child.ButtonEvent (ChildCoord (cursor, child), pressed, button);
+ }
+
+ DataViewChild last_motion_child;
+ public override bool CursorMotionEvent (Point cursor)
+ {
+ var child = FindChildAt (cursor);
+
+ bool new_child = child != last_motion_child;
+ if (new_child) {
+ if (last_motion_child != null) {
+ last_motion_child.CursorLeaveEvent ();
+ }
+ last_motion_child = child;
+ }
+
+ if (child == null) {
+ return false;
+ }
+
+ if (new_child) {
+ child.CursorEnterEvent ();
+ }
+
+ child.CursorMotionEvent (ChildCoord (cursor, child));
+ return true;
+ }
+
+ public override bool CursorLeaveEvent ()
+ {
+ bool ret = base.CursorLeaveEvent ();
+
+ if (last_motion_child != null) {
+ ret |= last_motion_child.CursorLeaveEvent ();
+ last_motion_child = null;
+ }
+
+ return ret;
+ }
+
+ private DataViewChild FindChildAt (Point pt)
+ {
+ return Children.LastOrDefault (c => pt.X >= c.Allocation.X && pt.Y >= c.Allocation.Y);
+ }
+
+ private Point ChildCoord (Point pt, DataViewChild child)
+ {
+ return new Point (pt.X - child.Allocation.X, pt.Y - child.Allocation.Y);
+ }
+ }
+}
diff --git a/Hyena.Gui/Hyena.Data.Gui/IInteractiveCell.cs b/Hyena.Gui/Hyena.Data.Gui/IInteractiveCell.cs
index f3ed4df..811afb3 100644
--- a/Hyena.Gui/Hyena.Data.Gui/IInteractiveCell.cs
+++ b/Hyena.Gui/Hyena.Data.Gui/IInteractiveCell.cs
@@ -27,14 +27,13 @@
//
using System;
-using Gdk;
namespace Hyena.Data.Gui
{
public interface IInteractiveCell
{
- bool ButtonEvent (int x, int y, bool pressed, Gdk.EventButton evnt);
- bool MotionEvent (int x, int y, Gdk.EventMotion evnt);
- bool PointerLeaveEvent ();
+ bool ButtonEvent (Hyena.Gui.Canvas.Point cursor, bool pressed, uint button);
+ bool CursorMotionEvent (Hyena.Gui.Canvas.Point cursor);
+ bool CursorLeaveEvent ();
}
-}
\ No newline at end of file
+}
diff --git a/Hyena.Gui/Hyena.Data.Gui/ListView/ListView.cs b/Hyena.Gui/Hyena.Data.Gui/ListView/ListView.cs
index e5398c6..d1340fe 100644
--- a/Hyena.Gui/Hyena.Data.Gui/ListView/ListView.cs
+++ b/Hyena.Gui/Hyena.Data.Gui/ListView/ListView.cs
@@ -44,6 +44,7 @@ namespace Hyena.Data.Gui
HasTooltip = true;
QueryTooltip += OnQueryTooltip;
+ DirectionChanged += (o, a) => SetDirection ();
}
private void OnQueryTooltip (object o, Gtk.QueryTooltipArgs args)
diff --git a/Hyena.Gui/Hyena.Data.Gui/ListView/ListViewBase.cs b/Hyena.Gui/Hyena.Data.Gui/ListView/ListViewBase.cs
index da18c63..c9f59b0 100644
--- a/Hyena.Gui/Hyena.Data.Gui/ListView/ListViewBase.cs
+++ b/Hyena.Gui/Hyena.Data.Gui/ListView/ListViewBase.cs
@@ -31,7 +31,7 @@ using Gtk;
namespace Hyena.Data.Gui
{
- public class ListViewBase : Widget
+ public abstract class ListViewBase : Widget
{
protected ListViewBase (IntPtr ptr) : base (ptr)
{
@@ -61,5 +61,7 @@ namespace Hyena.Data.Gui
Height = (int)Math.Ceiling (region.Height)
});
}
+
+ public abstract Pango.Layout PangoLayout { get; }
}
}
diff --git a/Hyena.Gui/Hyena.Data.Gui/ListView/ListView_Interaction.cs b/Hyena.Gui/Hyena.Data.Gui/ListView/ListView_Interaction.cs
index adc1df7..6b99953 100644
--- a/Hyena.Gui/Hyena.Data.Gui/ListView/ListView_Interaction.cs
+++ b/Hyena.Gui/Hyena.Data.Gui/ListView/ListView_Interaction.cs
@@ -337,6 +337,7 @@ namespace Hyena.Data.Gui
return false;
}
+ point.Offset (-list_interaction_alloc.X, -list_interaction_alloc.Y);
point.Offset (-child.VirtualAllocation.X, -child.VirtualAllocation.Y);
if (evnt_motion != null) {
@@ -370,7 +371,7 @@ namespace Hyena.Data.Gui
private void InvalidateLastIcell ()
{
- if (last_icell != null && last_icell.PointerLeaveEvent ()) {
+ if (last_icell != null && last_icell.CursorLeaveEvent ()) {
QueueDirtyRegion (last_icell_area);
last_icell = null;
last_icell_area = Gdk.Rectangle.Zero;
@@ -387,7 +388,7 @@ namespace Hyena.Data.Gui
int yoffset = VadjustmentValue;
if (last_icell_area != icell_area) {
- if (last_icell != null && last_icell.PointerLeaveEvent ()) {
+ if (last_icell != null && last_icell.CursorLeaveEvent ()) {
QueueDirtyRegion (new Gdk.Rectangle () {
X = last_icell_area.X - xoffset,
Y = last_icell_area.Y - yoffset,
@@ -456,9 +457,9 @@ namespace Hyena.Data.Gui
// Send the cell a synthesized input event
if (evnt_motion != null) {
- return icell.MotionEvent (x, y, evnt_motion);
+ return icell.CursorMotionEvent (new Hyena.Gui.Canvas.Point (x, y));
} else {
- return icell.ButtonEvent (x, y, press, evnt_button);
+ return icell.ButtonEvent (new Hyena.Gui.Canvas.Point (x, y), press, evnt_button.Button);
}
}
diff --git a/Hyena.Gui/Hyena.Data.Gui/ListView/ListView_Rendering.cs b/Hyena.Gui/Hyena.Data.Gui/ListView/ListView_Rendering.cs
index 5f0288c..b89b3bd 100644
--- a/Hyena.Gui/Hyena.Data.Gui/ListView/ListView_Rendering.cs
+++ b/Hyena.Gui/Hyena.Data.Gui/ListView/ListView_Rendering.cs
@@ -47,6 +47,10 @@ namespace Hyena.Data.Gui
private CellContext cell_context;
private Pango.Layout pango_layout;
+ public override Pango.Layout PangoLayout {
+ get { return cell_context.Layout; }
+ }
+
private List<int> selected_rows = new List<int> ();
private Theme theme;
@@ -95,6 +99,19 @@ namespace Hyena.Data.Gui
cell_context.Theme = theme;
cell_context.Widget = this;
cell_context.Drawable = drawable;
+ SetDirection ();
+ }
+
+ private void SetDirection ()
+ {
+ var dir = Direction;
+ if (dir == Gtk.TextDirection.None) {
+ dir = Gtk.Widget.DefaultDirection;
+ }
+
+ if (cell_context != null) {
+ cell_context.IsRtl = dir == Gtk.TextDirection.Rtl;
+ }
}
protected override bool OnExposeEvent (EventExpose evnt)
diff --git a/Hyena.Gui/Hyena.Gui.Canvas/Thickness.cs b/Hyena.Gui/Hyena.Gui.Canvas/Thickness.cs
index 9d25150..56fa88d 100644
--- a/Hyena.Gui/Hyena.Gui.Canvas/Thickness.cs
+++ b/Hyena.Gui/Hyena.Gui.Canvas/Thickness.cs
@@ -36,6 +36,8 @@ namespace Hyena.Gui.Canvas
private double top;
private double right;
private double bottom;
+
+ public static readonly Thickness Zero = new Thickness (0);
public Thickness (double thickness)
: this (thickness, thickness, thickness, thickness)
diff --git a/Hyena.Gui/Makefile.am b/Hyena.Gui/Makefile.am
index a3a5018..27faf5d 100644
--- a/Hyena.Gui/Makefile.am
+++ b/Hyena.Gui/Makefile.am
@@ -21,6 +21,7 @@ SOURCES = \
Hyena.Data.Gui/ColumnController.cs \
Hyena.Data.Gui/ColumnHeaderCellText.cs \
Hyena.Data.Gui/DataViewChild.cs \
+ Hyena.Data.Gui/DataViewChildBox.cs \
Hyena.Data.Gui/DataViewLayout.cs \
Hyena.Data.Gui/DataViewLayoutGrid.cs \
Hyena.Data.Gui/IHeaderCell.cs \
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]