[hyena/canvas: 3/5] [Hyena.Gui.Canvas] Copy from Cubano
- From: Gabriel Burt <gburt src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [hyena/canvas: 3/5] [Hyena.Gui.Canvas] Copy from Cubano
- Date: Fri, 22 Oct 2010 00:04:35 +0000 (UTC)
commit f3e3f5f5f61372595c7d8b27aff9351d7a86c6c7
Author: Gabriel Burt <gabriel burt gmail com>
Date: Thu Oct 21 18:51:48 2010 -0500
[Hyena.Gui.Canvas] Copy from Cubano
Except Size, Rect, and Thickness which were already here and more
updated than Cubano's version.
Hyena.Gui/Hyena.Gui.Canvas/AnimationManager.cs | 302 +++++++++++++++
Hyena.Gui/Hyena.Gui.Canvas/Brush.cs | 81 ++++
Hyena.Gui/Hyena.Gui.Canvas/CanvasHost.cs | 343 +++++++++++++++++
Hyena.Gui/Hyena.Gui.Canvas/CanvasItem.cs | 405 ++++++++++++++++++++
Hyena.Gui/Hyena.Gui.Canvas/CanvasItemCollection.cs | 106 +++++
Hyena.Gui/Hyena.Gui.Canvas/CanvasManager.cs | 64 +++
Hyena.Gui/Hyena.Gui.Canvas/FixedPanel.cs | 37 ++
Hyena.Gui/Hyena.Gui.Canvas/FontWeight.cs | 36 ++
Hyena.Gui/Hyena.Gui.Canvas/Image.cs | 67 ++++
Hyena.Gui/Hyena.Gui.Canvas/ImageBrush.cs | 82 ++++
Hyena.Gui/Hyena.Gui.Canvas/MarginStyle.cs | 43 ++
Hyena.Gui/Hyena.Gui.Canvas/Orientation.cs | 36 ++
Hyena.Gui/Hyena.Gui.Canvas/Panel.cs | 148 +++++++
Hyena.Gui/Hyena.Gui.Canvas/Rect.cs | 64 ++--
Hyena.Gui/Hyena.Gui.Canvas/ShadowMarginStyle.cs | 89 +++++
Hyena.Gui/Hyena.Gui.Canvas/Size.cs | 28 +-
Hyena.Gui/Hyena.Gui.Canvas/Slider.cs | 237 ++++++++++++
Hyena.Gui/Hyena.Gui.Canvas/StackPanel.cs | 153 ++++++++
Hyena.Gui/Hyena.Gui.Canvas/TestTile.cs | 62 +++
Hyena.Gui/Hyena.Gui.Canvas/TextBlock.cs | 260 +++++++++++++
Hyena.Gui/Hyena.Gui.Canvas/TextWrap.cs | 38 ++
Hyena.Gui/Hyena.Gui.Canvas/Thickness.cs | 42 +-
Hyena.Gui/Makefile.am | 29 ++-
23 files changed, 2681 insertions(+), 71 deletions(-)
---
diff --git a/Hyena.Gui/Hyena.Gui.Canvas/AnimationManager.cs b/Hyena.Gui/Hyena.Gui.Canvas/AnimationManager.cs
new file mode 100644
index 0000000..1646adf
--- /dev/null
+++ b/Hyena.Gui/Hyena.Gui.Canvas/AnimationManager.cs
@@ -0,0 +1,302 @@
+//
+// AnimationManager.cs
+//
+// Author:
+// Aaron Bockover <abockover novell com>
+//
+// Copyright 2009 Aaron Bockover
+//
+// 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 Hyena.Gui.Theatrics;
+
+namespace Hyena.Gui.Canvas
+{
+ public abstract class Animation
+ {
+ private Stage<Animation> stage;
+ internal protected Stage<Animation> Stage {
+ get { return stage; }
+ set { stage = value; }
+ }
+
+ private Actor<Animation> actor;
+ internal protected Actor<Animation> Actor {
+ get { return actor; }
+ set { actor = value; }
+ }
+
+ private uint duration = 1000;
+ public uint Duration {
+ get { return duration; }
+ set {
+ duration = value;
+ if (Actor != null) {
+ Actor.Reset (duration);
+ }
+ }
+ }
+
+ private CanvasItem item;
+ public CanvasItem Item {
+ get { return item; }
+ set { item = value; }
+ }
+
+ private string property;
+ public string Property {
+ get { return property; }
+ set { property = value; }
+ }
+
+ private bool is_expired;
+ public bool IsExpired {
+ get { return is_expired; }
+ set {
+ is_expired = value;
+ iterations = 0;
+ }
+ }
+
+ private int iterations;
+
+ private int repeat_times;
+ public int RepeatTimes {
+ get { return repeat_times; }
+ set { repeat_times = value; }
+ }
+
+ public virtual void Start ()
+ {
+ if (Stage.Contains (this)) {
+ Actor.Reset (Duration);
+ return;
+ }
+
+ Actor = Stage.Add (this, Duration);
+ IsExpired = false;
+ Actor.CanExpire = false;
+ }
+
+ public virtual bool Step (Actor<Animation> actor)
+ {
+ if (RepeatTimes > 0 && actor.Percent == 1) {
+ if (++iterations >= RepeatTimes) {
+ IsExpired = true;
+ }
+ }
+
+ return !IsExpired;
+ }
+ }
+
+ public delegate T AnimationComposeHandler<T> (Animation<T> animation, double percent);
+
+ public abstract class Animation<T> : Animation
+ {
+ private AnimationComposeHandler<T> compose_handler;
+ protected AnimationComposeHandler<T> ComposeHandler {
+ get { return compose_handler; }
+ }
+
+ private Easing easing = Easing.Linear;
+ protected Easing Easing {
+ get { return easing; }
+ }
+
+ private bool from_set;
+ protected bool FromSet {
+ get { return from_set; }
+ }
+
+ private T from_value;
+ public T FromValue {
+ get { return from_value; }
+ set {
+ from_set = true;
+ from_value = value;
+ }
+ }
+
+ private T to_value;
+ public T ToValue {
+ get { return to_value; }
+ set { to_value = value; }
+ }
+
+ private T start_state;
+ public T StartState {
+ get { return start_state; }
+ protected set { start_state = value; }
+ }
+
+ public override void Start ()
+ {
+ T check_state = FromSet ? FromValue : (T)Item[Property];
+
+ if (!check_state.Equals (ToValue)) {
+ base.Start ();
+ }
+ }
+
+ public Animation<T> ClearFromValue ()
+ {
+ from_set = false;
+ from_value = default (T);
+ return this;
+ }
+
+ public Animation<T> Animate ()
+ {
+ StartState = FromSet ? FromValue : (T)Item[Property];
+ return this;
+ }
+
+ public Animation<T> Animate (T toValue)
+ {
+ ClearFromValue ();
+ ToValue = toValue;
+ return Animate ();
+ }
+
+ public Animation<T> Animate (T fromValue, T toValue)
+ {
+ FromValue = fromValue;
+ ToValue = toValue;
+ return Animate ();
+ }
+
+ public Animation<T> Animate (string property, T toValue)
+ {
+ Property = property;
+ return Animate (toValue);
+ }
+
+ public Animation<T> Animate (string property, T fromValue, T toValue)
+ {
+ Property = property;
+ return Animate (fromValue, toValue);
+ }
+
+ public Animation<T> Compose (AnimationComposeHandler<T> handler)
+ {
+ compose_handler = handler;
+ return this;
+ }
+
+ public Animation<T> ClearCompose ()
+ {
+ compose_handler = null;
+ return this;
+ }
+
+ public Animation<T> To (T toValue)
+ {
+ ToValue = toValue;
+ return Animate ();
+ }
+
+ public Animation<T> From (T fromValue)
+ {
+ FromValue = fromValue;
+ return Animate ();
+ }
+
+ public Animation<T> Reverse ()
+ {
+ T from = FromValue;
+ FromValue = ToValue;
+ ToValue = from;
+ return Animate ();
+ }
+
+ public Animation<T> Ease (Easing easing)
+ {
+ this.easing = easing;
+ return this;
+ }
+
+ public Animation<T> Throttle (uint duration)
+ {
+ Duration = duration;
+ return this;
+ }
+
+ public Animation<T> Repeat (int count)
+ {
+ RepeatTimes = count;
+ return this;
+ }
+
+ public Animation<T> Expire ()
+ {
+ IsExpired = true;
+ return this;
+ }
+ }
+
+ public class DoubleAnimation : Animation<double>
+ {
+ public DoubleAnimation ()
+ {
+ }
+
+ public DoubleAnimation (string property)
+ {
+ Property = property;
+ }
+
+ public override bool Step (Actor<Animation> actor)
+ {
+ double result = ComposeHandler == null
+ ? StartState + (ToValue * actor.Percent)
+ : ComposeHandler (this, actor.Percent);
+
+ result = Easing == Easing.Linear
+ ? result
+ : Choreographer.Compose (result, Easing);
+
+ Item.SetValue<double> (Property, result);
+
+ return base.Step (actor);
+ }
+ }
+
+ public class AnimationManager
+ {
+ private static AnimationManager instance;
+ public static AnimationManager Instance {
+ get { return instance ?? (instance = new AnimationManager ()); }
+ }
+
+ private Stage<Animation> stage = new Stage<Animation> ();
+
+ public AnimationManager ()
+ {
+ stage.Play ();
+ stage.ActorStep += (actor) => actor.Target.Step (actor);
+ }
+
+ public void Animate (Animation animation)
+ {
+ animation.Stage = stage;
+ }
+ }
+}
diff --git a/Hyena.Gui/Hyena.Gui.Canvas/Brush.cs b/Hyena.Gui/Hyena.Gui.Canvas/Brush.cs
new file mode 100644
index 0000000..28df7b6
--- /dev/null
+++ b/Hyena.Gui/Hyena.Gui.Canvas/Brush.cs
@@ -0,0 +1,81 @@
+//
+// Brush.cs
+//
+// Author:
+// Aaron Bockover <abockover novell com>
+//
+// Copyright 2009 Aaron Bockover
+//
+// 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;
+
+namespace Hyena.Gui.Canvas
+{
+ public class Brush
+ {
+ private Cairo.Color color;
+
+ public Brush ()
+ {
+ }
+
+ public Brush (byte r, byte g, byte b) : this (r, g, b, 255)
+ {
+ }
+
+ public Brush (byte r, byte g, byte b, byte a)
+ : this ((double)r / 255.0, (double)g / 255.0, (double)b / 255.0, (double)a / 255.0)
+ {
+ }
+
+ public Brush (double r, double g, double b) : this (r, g, b, 1)
+ {
+ }
+
+ public Brush (double r, double g, double b, double a) : this (new Cairo.Color (r, g, b, a))
+ {
+ }
+
+ public Brush (Cairo.Color color)
+ {
+ this.color = color;
+ }
+
+ public virtual bool IsValid {
+ get { return true; }
+ }
+
+ public virtual void Apply (Cairo.Context cr)
+ {
+ cr.Color = color;
+ }
+
+ public static readonly Brush Black = new Brush (0.0, 0.0, 0.0);
+ public static readonly Brush White = new Brush (1.0, 1.0, 1.0);
+
+ public virtual double Width {
+ get { return Double.NaN; }
+ }
+
+ public virtual double Height {
+ get { return Double.NaN; }
+ }
+ }
+}
diff --git a/Hyena.Gui/Hyena.Gui.Canvas/CanvasHost.cs b/Hyena.Gui/Hyena.Gui.Canvas/CanvasHost.cs
new file mode 100644
index 0000000..db20cf5
--- /dev/null
+++ b/Hyena.Gui/Hyena.Gui.Canvas/CanvasHost.cs
@@ -0,0 +1,343 @@
+//
+// CanvasHost.cs
+//
+// Author:
+// Aaron Bockover <abockover novell com>
+//
+// Copyright 2009 Aaron Bockover
+//
+// 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 Gtk;
+using Gdk;
+
+using Hyena.Gui.Theming;
+
+namespace Hyena.Gui.Canvas
+{
+ public class FpsCalculator
+ {
+ private DateTime last_update;
+ private TimeSpan update_interval;
+ private int frame_count;
+ private double fps;
+
+ public FpsCalculator ()
+ {
+ update_interval = TimeSpan.FromSeconds (0.5);
+ }
+
+ public bool Update ()
+ {
+ bool updated = false;
+ DateTime current_time = DateTime.Now;
+ frame_count++;
+
+ if (current_time - last_update >= update_interval) {
+ fps = (double)frame_count / (current_time - last_update).TotalSeconds;
+ frame_count = 0;
+ updated = true;
+ last_update = current_time;
+ }
+
+ return updated;
+ }
+
+ public double FramesPerSecond {
+ get { return fps; }
+ }
+ }
+
+ public class CanvasHost : Widget
+ {
+ private Gdk.Window event_window;
+ private CanvasItem canvas_child;
+ private Theme theme;
+ private CanvasManager manager;
+ private bool debug = false;
+ private FpsCalculator fps = new FpsCalculator ();
+
+ public CanvasHost ()
+ {
+ WidgetFlags |= WidgetFlags.NoWindow;
+ manager = new CanvasManager (this);
+ }
+
+ protected CanvasHost (IntPtr native) : base (native)
+ {
+ }
+
+ protected override void OnRealized ()
+ {
+ base.OnRealized ();
+
+ WindowAttr attributes = new WindowAttr ();
+ attributes.WindowType = Gdk.WindowType.Child;
+ attributes.X = Allocation.X;
+ attributes.Y = Allocation.Y;
+ attributes.Width = Allocation.Width;
+ attributes.Height = Allocation.Height;
+ attributes.Wclass = WindowClass.InputOnly;
+ attributes.EventMask = (int)(
+ EventMask.PointerMotionMask |
+ EventMask.ButtonPressMask |
+ EventMask.ButtonReleaseMask |
+ EventMask.EnterNotifyMask |
+ EventMask.LeaveNotifyMask |
+ EventMask.ExposureMask);
+
+ WindowAttributesType attributes_mask =
+ WindowAttributesType.X | WindowAttributesType.Y | WindowAttributesType.Wmclass;
+
+ event_window = new Gdk.Window (GdkWindow, attributes, attributes_mask);
+ event_window.UserData = Handle;
+
+ AllocateChild ();
+ QueueResize ();
+ }
+
+ protected override void OnUnrealized ()
+ {
+ WidgetFlags ^= WidgetFlags.Realized;
+
+ event_window.UserData = IntPtr.Zero;
+ Hyena.Gui.GtkWorkarounds.WindowDestroy (event_window);
+ event_window = null;
+
+ base.OnUnrealized ();
+ }
+
+ protected override void OnMapped ()
+ {
+ event_window.Show ();
+ base.OnMapped ();
+ }
+
+ protected override void OnUnmapped ()
+ {
+ event_window.Hide ();
+ base.OnUnmapped ();
+ }
+
+ protected override void OnSizeAllocated (Gdk.Rectangle allocation)
+ {
+ base.OnSizeAllocated (allocation);
+
+ if (IsRealized) {
+ event_window.MoveResize (allocation);
+ AllocateChild ();
+ }
+ }
+
+ protected override void OnSizeRequested (ref Gtk.Requisition requisition)
+ {
+ if (canvas_child != null) {
+ Size size = canvas_child.Measure (Size.Empty);
+
+ if (size.Width > 0) {
+ requisition.Width = (int)Math.Ceiling (size.Width);
+ }
+
+ if (size.Height > 0) {
+ requisition.Height = (int)Math.Ceiling (size.Height);
+ }
+ }
+ }
+
+ private Random rand;
+
+ protected override bool OnExposeEvent (Gdk.EventExpose evnt)
+ {
+ if (canvas_child == null || !canvas_child.Visible || !Visible || !IsMapped) {
+ return true;
+ }
+
+ Cairo.Context cr = Gdk.CairoHelper.Create (evnt.Window);
+
+ foreach (Gdk.Rectangle damage in evnt.Region.GetRectangles ()) {
+ cr.Rectangle (damage.X, damage.Y, damage.Width, damage.Height);
+ cr.Clip ();
+
+ cr.Translate (Allocation.X, Allocation.Y);
+ canvas_child.Render (cr);
+ cr.Translate (-Allocation.X, -Allocation.Y);
+
+ if (Debug) {
+ cr.LineWidth = 1.0;
+ cr.Color = CairoExtensions.RgbToColor (
+ (uint)(rand = rand ?? new Random ()).Next (0, 0xffffff));
+ cr.Rectangle (damage.X + 0.5, damage.Y + 0.5, damage.Width - 1, damage.Height - 1);
+ cr.Stroke ();
+ }
+
+ cr.ResetClip ();
+ }
+
+ CairoExtensions.DisposeContext (cr);
+
+ if (fps.Update ()) {
+ // Console.WriteLine ("FPS: {0}", fps.FramesPerSecond);
+ }
+
+ return true;
+ }
+
+ private void AllocateChild ()
+ {
+ if (canvas_child != null) {
+ canvas_child.Allocation = new Rect (0, 0, Allocation.Width, Allocation.Height);
+ canvas_child.Measure (new Size (Allocation.Width, Allocation.Height));
+ canvas_child.Arrange ();
+ }
+ }
+
+ public void QueueRender (CanvasItem item, Rect rect)
+ {
+ double x = Allocation.X;
+ double y = Allocation.Y;
+ double w, h;
+
+ if (rect.IsEmpty) {
+ w = item.Allocation.Width;
+ h = item.Allocation.Height;
+ } else {
+ x += rect.X;
+ y += rect.Y;
+ w = rect.Width;
+ h = rect.Height;
+ }
+
+ while (item != null) {
+ x += item.ContentAllocation.X;
+ y += item.ContentAllocation.Y;
+ item = item.Parent;
+ }
+
+ QueueDrawArea (
+ (int)Math.Floor (x),
+ (int)Math.Floor (y),
+ (int)Math.Ceiling (w),
+ (int)Math.Ceiling (h)
+ );
+ }
+
+ private bool changing_style = false;
+
+ protected override void OnStyleSet (Style old_style)
+ {
+ if (changing_style) {
+ return;
+ }
+
+ changing_style = true;
+
+ theme = new GtkTheme (this);
+ if (canvas_child != null) {
+ canvas_child.Theme = theme;
+ }
+
+ changing_style = false;
+
+ base.OnStyleSet (old_style);
+ }
+
+ protected override bool OnButtonPressEvent (Gdk.EventButton evnt)
+ {
+ if (canvas_child != null) {
+ canvas_child.ButtonPress (evnt.X, evnt.Y, evnt.Button);
+ }
+ return true;
+ }
+
+ protected override bool OnButtonReleaseEvent (Gdk.EventButton evnt)
+ {
+ if (canvas_child != null) {
+ canvas_child.ButtonRelease ();
+ }
+ return true;
+ }
+
+ protected override bool OnMotionNotifyEvent (EventMotion evnt)
+ {
+ if (canvas_child != null) {
+ canvas_child.PointerMotion (evnt.X, evnt.Y);
+ }
+ return true;
+ }
+
+ public void Add (CanvasItem child)
+ {
+ if (Child != null) {
+ throw new InvalidOperationException ("Child is already set, remove it first");
+ }
+
+ Child = child;
+ }
+
+ public void Remove (CanvasItem child)
+ {
+ if (Child != child) {
+ throw new InvalidOperationException ("child does not already belong to host");
+ }
+
+ Child = null;
+ }
+
+ private void OnCanvasChildLayoutUpdated (object o, EventArgs args)
+ {
+ QueueDraw ();
+ }
+
+ private void OnCanvasChildSizeChanged (object o, EventArgs args)
+ {
+ QueueResize ();
+ }
+
+ public CanvasItem Child {
+ get { return canvas_child; }
+ set {
+ if (canvas_child == value) {
+ return;
+ } else if (canvas_child != null) {
+ canvas_child.Theme = null;
+ canvas_child.Manager = null;
+ canvas_child.LayoutUpdated -= OnCanvasChildLayoutUpdated;
+ canvas_child.SizeChanged -= OnCanvasChildSizeChanged;
+ }
+
+ canvas_child = value;
+
+ if (canvas_child != null) {
+ canvas_child.Theme = theme;
+ canvas_child.Manager = manager;
+ canvas_child.LayoutUpdated += OnCanvasChildLayoutUpdated;
+ canvas_child.SizeChanged += OnCanvasChildSizeChanged;
+ }
+
+ AllocateChild ();
+ }
+ }
+
+ public bool Debug {
+ get { return debug; }
+ set { debug = value; }
+ }
+ }
+}
diff --git a/Hyena.Gui/Hyena.Gui.Canvas/CanvasItem.cs b/Hyena.Gui/Hyena.Gui.Canvas/CanvasItem.cs
new file mode 100644
index 0000000..cd4121e
--- /dev/null
+++ b/Hyena.Gui/Hyena.Gui.Canvas/CanvasItem.cs
@@ -0,0 +1,405 @@
+//
+// CanvasItem.cs
+//
+// Author:
+// Aaron Bockover <abockover novell com>
+//
+// Copyright 2009 Aaron Bockover
+//
+// 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.Collections.Generic;
+
+using Hyena.Gui.Theming;
+
+namespace Hyena.Gui.Canvas
+{
+ public class CanvasItem
+ {
+ private CanvasManager manager;
+ private CanvasItem parent;
+ private Theme theme;
+ private Size desired_size;
+ private Dictionary<string, object> properties;
+ private Rect allocation;
+ private bool visible = true;
+
+ public event EventHandler<EventArgs> SizeChanged;
+ public event EventHandler<EventArgs> LayoutUpdated;
+
+ public CanvasItem ()
+ {
+ InstallProperty<double> ("Opacity", 1.0);
+ InstallProperty<double> ("Width", Double.NaN);
+ InstallProperty<double> ("Height", Double.NaN);
+ InstallProperty<Thickness> ("Margin", new Thickness (0));
+ InstallProperty<Brush> ("Foreground", Brush.Black);
+ InstallProperty<Brush> ("Background", Brush.White);
+ InstallProperty<MarginStyle> ("MarginStyle", MarginStyle.None);
+ }
+
+ public void InvalidateArrange ()
+ {
+ CanvasItem root = RootAncestor;
+ if (root != null && root.Manager != null) {
+ root.Manager.QueueArrange (this);
+ }
+ }
+
+ public void InvalidateMeasure ()
+ {
+ CanvasItem root = RootAncestor;
+ if (root != null && root.Manager != null) {
+ root.Manager.QueueMeasure (this);
+ }
+ }
+
+ protected void InvalidateRender ()
+ {
+ InvalidateRender (InvalidationRect);
+ }
+
+ protected void InvalidateRender (Rect area)
+ {
+ CanvasItem root = RootAncestor;
+ if (root != null && root.Manager != null) {
+ root.Manager.QueueRender (this, area);
+ }
+ }
+
+ public virtual void Arrange ()
+ {
+ }
+
+ public virtual Size Measure (Size available)
+ {
+ double m_x = Margin.Left + Margin.Right;
+ double m_y = Margin.Top + Margin.Bottom;
+
+ double a_w = available.Width - m_x;
+ double a_h = available.Height - m_y;
+
+ return DesiredSize = new Size (
+ Math.Max (0, Math.Min (a_w, Double.IsNaN (Width) ? a_w : Width + m_x)),
+ Math.Max (0, Math.Min (a_h, Double.IsNaN (Height) ? a_h : Height + m_y))
+ );
+ }
+
+ public virtual void Render (Cairo.Context cr)
+ {
+ double opacity = Opacity;
+
+ if (ContentAllocation.Width <= 0 || ContentAllocation.Height <= 0 || opacity <= 0) {
+ return;
+ }
+
+ cr.Save ();
+
+ if (opacity < 1.0) {
+ cr.PushGroup ();
+ }
+
+ MarginStyle margin_style = MarginStyle;
+ if (margin_style != null && margin_style != MarginStyle.None) {
+ cr.Translate (Math.Round (Allocation.X), Math.Round (Allocation.Y));
+ cr.Save ();
+ margin_style.Apply (this, cr);
+ cr.Restore ();
+ cr.Translate (Math.Round (Margin.Left), Math.Round (Margin.Top));
+ } else {
+ cr.Translate (Math.Round (ContentAllocation.X), Math.Round (ContentAllocation.Y));
+ }
+
+ cr.Antialias = Cairo.Antialias.Default;
+ ClippedRender (cr);
+
+ if (opacity < 1.0) {
+ cr.PopGroupToSource ();
+ cr.PaintWithAlpha (Opacity);
+ }
+
+ cr.Restore ();
+ }
+
+ protected virtual void ClippedRender (Cairo.Context cr)
+ {
+ }
+
+ protected virtual void OnSizeChanged ()
+ {
+ EventHandler<EventArgs> handler = SizeChanged;
+ if (handler != null) {
+ handler (this, EventArgs.Empty);
+ }
+ }
+
+ protected virtual void OnLayoutUpdated ()
+ {
+ EventHandler<EventArgs> handler = LayoutUpdated;
+ if (handler != null) {
+ handler (this, EventArgs.Empty);
+ }
+ }
+
+ internal CanvasManager Manager {
+ get { return manager ?? (Parent != null ? Parent.Manager : null); }
+ set { manager = value; }
+ }
+
+ public CanvasItem RootAncestor {
+ get {
+ CanvasItem root = Parent ?? this;
+ while (root != null && root.Parent != null) {
+ root = root.Parent;
+ }
+ return root;
+ }
+ }
+
+ public CanvasItem Parent {
+ get { return parent; }
+ set { parent = value; }
+ }
+
+ public Theme Theme {
+ get { return theme ?? (Parent != null ? Parent.Theme : null); }
+ set { theme = value; }
+ }
+
+ public Size DesiredSize {
+ get { return desired_size; }
+ protected set { desired_size = value; }
+ }
+
+ public Thickness Margin {
+ get { return GetValue<Thickness> ("Margin"); }
+ set { SetValue<Thickness> ("Margin", value); }
+ }
+
+ public MarginStyle MarginStyle {
+ get { return GetValue<MarginStyle> ("MarginStyle"); }
+ set { SetValue<MarginStyle> ("MarginStyle", value); }
+ }
+
+ public double Width {
+ get { return GetValue<double> ("Width"); }
+ set { SetValue<double> ("Width", value); }
+ }
+
+ public double Height {
+ get { return GetValue<double> ("Height"); }
+ set { SetValue<double> ("Height", value); }
+ }
+
+ public double Opacity {
+ get { return GetValue<double> ("Opacity"); }
+ set { SetValue<double> ("Opacity", value); }
+ }
+
+ public Brush Foreground {
+ get { return GetValue<Brush> ("Foreground"); }
+ set { SetValue<Brush> ("Foreground", value); }
+ }
+
+ public Brush Background {
+ get { return GetValue<Brush> ("Background"); }
+ set { SetValue<Brush> ("Background", value); }
+ }
+
+ public Rect Allocation {
+ get { return allocation; }
+ set { allocation = value; }
+ }
+
+ public Rect ContentAllocation {
+ get {
+ return new Rect (
+ Allocation.X + Margin.Left,
+ Allocation.Y + Margin.Top,
+ Math.Max (0, Allocation.Width - Margin.Left - Margin.Right),
+ Math.Max (0, Allocation.Height - Margin.Top - Margin.Bottom)
+ );
+ }
+ }
+
+ protected virtual Rect InvalidationRect {
+ get { return Rect.Empty; }
+ }
+
+ public Size ContentSize {
+ get { return new Size (ContentAllocation.Width, ContentAllocation.Height); }
+ }
+
+ protected Size RenderSize {
+ get { return new Size (Math.Round (ContentAllocation.Width), Math.Round (ContentAllocation.Height)); }
+ }
+
+ public bool Visible {
+ get { return visible; }
+ set { visible = value; }
+ }
+
+ protected void InstallProperty<T> (string property)
+ {
+ InstallProperty (property, default (T));
+ }
+
+ protected void InstallProperty<T> (string property, T defaultValue)
+ {
+ if (properties == null) {
+ properties = new Dictionary<string, object> ();
+ }
+
+ if (properties.ContainsKey (property)) {
+ throw new InvalidOperationException ("Property is already installed: " + property);
+ }
+
+ properties.Add (property, defaultValue);
+ }
+
+ protected virtual bool OnPropertyChange (string property, object value)
+ {
+ switch (property) {
+ case "Foreground":
+ case "Background":
+ case "MarginStyle":
+ case "Opacity":
+ InvalidateRender ();
+ return true;
+ /* case "Width":
+ case "Height":
+ case "Margin":
+ InvalidateArrange ();
+ InvalidateMeasure ();
+ return true; */
+ }
+
+ return false;
+ }
+
+ public object this[string property] {
+ get {
+ object result;
+ if (properties != null && properties.TryGetValue (property, out result)) {
+ return result;
+ }
+
+ return result;
+ }
+
+ set {
+ if (properties == null || !properties.ContainsKey (property)) {
+ throw new InvalidOperationException ("Property does not exist: " + property);
+ }
+
+ object existing = properties[property];
+
+ Type existing_type = existing.GetType ();
+ Type new_type = value.GetType ();
+
+ if (existing_type != new_type && !new_type.IsSubclassOf (existing_type)) {
+ throw new InvalidOperationException ("Invalid value type " +
+ value.GetType () + " for property: " + property);
+ }
+
+ if (existing != value) {
+ properties[property] = value;
+ OnPropertyChange (property, value);
+ }
+ }
+ }
+
+ public T GetValue<T> (string property)
+ {
+ return GetValue (property, default (T));
+ }
+
+ public T GetValue<T> (string property, T fallback)
+ {
+ object result = this[property];
+ if (result == null) {
+ return fallback;
+ }
+ return (T)result;
+ }
+
+ public void SetValue<T> (string property, T value)
+ {
+ this[property] = value;
+ }
+
+ public T Animate<T> (T animation) where T : Animation
+ {
+ animation.Item = this;
+ AnimationManager.Instance.Animate (animation);
+ return animation;
+ }
+
+ public DoubleAnimation AnimateDouble (string property)
+ {
+ return Animate (new DoubleAnimation (property));
+ }
+
+#region Input Events
+
+ public event EventHandler<EventArgs> Clicked;
+
+ private bool pointer_grabbed;
+ public virtual bool IsPointerGrabbed {
+ get { return pointer_grabbed; }
+ }
+
+ protected void GrabPointer ()
+ {
+ pointer_grabbed = true;
+ }
+
+ protected void ReleasePointer ()
+ {
+ pointer_grabbed = false;
+ }
+
+ public virtual void ButtonPress (double x, double y, uint button)
+ {
+ GrabPointer ();
+ }
+
+ public virtual void ButtonRelease ()
+ {
+ ReleasePointer ();
+ OnClicked ();
+ }
+
+ public virtual void PointerMotion (double x, double y)
+ {
+ }
+
+ protected virtual void OnClicked ()
+ {
+ var handler = Clicked;
+ if (handler != null) {
+ handler (this, EventArgs.Empty);
+ }
+ }
+
+#endregion
+
+ }
+}
diff --git a/Hyena.Gui/Hyena.Gui.Canvas/CanvasItemCollection.cs b/Hyena.Gui/Hyena.Gui.Canvas/CanvasItemCollection.cs
new file mode 100644
index 0000000..e1fa7db
--- /dev/null
+++ b/Hyena.Gui/Hyena.Gui.Canvas/CanvasItemCollection.cs
@@ -0,0 +1,106 @@
+//
+// CanvasItemCollection.cs
+//
+// Author:
+// Aaron Bockover <abockover novell com>
+//
+// Copyright 2009 Aaron Bockover
+//
+// 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.Collections.Generic;
+
+namespace Hyena.Gui.Canvas
+{
+ public class CanvasItemCollection : IEnumerable<CanvasItem>
+ {
+ private CanvasItem parent;
+ private List<CanvasItem> children = new List<CanvasItem> ();
+
+ public CanvasItemCollection (CanvasItem parent)
+ {
+ this.parent = parent;
+ }
+
+ public void Add (CanvasItem child)
+ {
+ if (!children.Contains (child)) {
+ children.Add (child);
+ child.Parent = parent;
+ parent.InvalidateArrange ();
+ }
+ }
+
+ private void Unparent (CanvasItem child)
+ {
+ child.Parent = null;
+ }
+
+ public void Remove (CanvasItem child)
+ {
+ if (children.Remove (child)) {
+ Unparent (child);
+ parent.InvalidateArrange ();
+ }
+ }
+
+ public void Move (CanvasItem child, int position)
+ {
+ if (children.Remove (child)) {
+ children.Insert (position, child);
+ parent.InvalidateArrange ();
+ }
+ }
+
+ public void Clear ()
+ {
+ foreach (var child in children) {
+ Unparent (child);
+ }
+ children.Clear ();
+ }
+
+ public IEnumerator<CanvasItem> GetEnumerator ()
+ {
+ foreach (var item in children) {
+ yield return item;
+ }
+ }
+
+ System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator ()
+ {
+ return GetEnumerator ();
+ }
+
+ public CanvasItem this[int index] {
+ get { return children[index]; }
+ }
+
+ public CanvasItem Parent {
+ get { return parent; }
+ }
+
+ public int Count {
+ get { return children.Count; }
+ }
+ }
+}
+
+
diff --git a/Hyena.Gui/Hyena.Gui.Canvas/CanvasManager.cs b/Hyena.Gui/Hyena.Gui.Canvas/CanvasManager.cs
new file mode 100644
index 0000000..ca5badb
--- /dev/null
+++ b/Hyena.Gui/Hyena.Gui.Canvas/CanvasManager.cs
@@ -0,0 +1,64 @@
+//
+// CanvasHost.cs
+//
+// Author:
+// Aaron Bockover <abockover novell com>
+//
+// Copyright 2009 Aaron Bockover
+//
+// 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;
+
+namespace Hyena.Gui.Canvas
+{
+ public class CanvasManager
+ {
+ private object host;
+
+ public CanvasManager (object host)
+ {
+ this.host = host;
+ }
+
+ public void QueueArrange (CanvasItem item)
+ {
+ item.Arrange ();
+ }
+
+ public void QueueMeasure (CanvasItem item)
+ {
+ item.Measure (item.ContentSize);
+ }
+
+ public void QueueRender (CanvasItem item, Rect rect)
+ {
+ CanvasHost host = Host as CanvasHost;
+ if (host == null) {
+ return;
+ }
+
+ host.QueueRender (item, rect);
+ }
+
+ public object Host {
+ get { return host; }
+ }
+ }
+}
diff --git a/Hyena.Gui/Hyena.Gui.Canvas/FixedPanel.cs b/Hyena.Gui/Hyena.Gui.Canvas/FixedPanel.cs
new file mode 100644
index 0000000..ae2aec5
--- /dev/null
+++ b/Hyena.Gui/Hyena.Gui.Canvas/FixedPanel.cs
@@ -0,0 +1,37 @@
+//
+// FixedPanel.cs
+//
+// Author:
+// Aaron Bockover <abockover novell com>
+//
+// Copyright 2009 Aaron Bockover
+//
+// 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;
+
+namespace Hyena.Gui.Canvas
+{
+ public class FixedPanel : Panel
+ {
+ public FixedPanel ()
+ {
+ }
+ }
+}
diff --git a/Hyena.Gui/Hyena.Gui.Canvas/FontWeight.cs b/Hyena.Gui/Hyena.Gui.Canvas/FontWeight.cs
new file mode 100644
index 0000000..b4fda51
--- /dev/null
+++ b/Hyena.Gui/Hyena.Gui.Canvas/FontWeight.cs
@@ -0,0 +1,36 @@
+//
+// FontWeight.cs
+//
+// Author:
+// Aaron Bockover <abockover novell com>
+//
+// Copyright 2009 Aaron Bockover
+//
+// 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;
+
+namespace Hyena.Gui.Canvas
+{
+ public enum FontWeight
+ {
+ Normal,
+ Bold
+ }
+}
diff --git a/Hyena.Gui/Hyena.Gui.Canvas/Image.cs b/Hyena.Gui/Hyena.Gui.Canvas/Image.cs
new file mode 100644
index 0000000..e013d5e
--- /dev/null
+++ b/Hyena.Gui/Hyena.Gui.Canvas/Image.cs
@@ -0,0 +1,67 @@
+//
+// Image.cs
+//
+// Author:
+// Aaron Bockover <abockover novell com>
+//
+// Copyright 2009 Aaron Bockover
+//
+// 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;
+
+namespace Hyena.Gui.Canvas
+{
+ public class Image : CanvasItem
+ {
+ public Image ()
+ {
+ }
+
+ protected override void ClippedRender (Cairo.Context cr)
+ {
+ Brush brush = Background;
+ if (!brush.IsValid) {
+ return;
+ }
+
+ double x = Double.IsNaN (brush.Width)
+ ? 0
+ : (RenderSize.Width - brush.Width) * XAlign;
+
+ double y = Double.IsNaN (brush.Height)
+ ? 0
+ : (RenderSize.Height - brush.Height) * YAlign;
+
+ cr.Rectangle (0, 0, RenderSize.Width, RenderSize.Height);
+ cr.ClipPreserve ();
+
+ if (x != 0 || y != 0) {
+ cr.Translate (x, y);
+ }
+
+ cr.Antialias = Cairo.Antialias.None;
+ brush.Apply (cr);
+ cr.Fill ();
+ }
+
+ public double XAlign { get; set; }
+ public double YAlign { get; set; }
+ }
+}
diff --git a/Hyena.Gui/Hyena.Gui.Canvas/ImageBrush.cs b/Hyena.Gui/Hyena.Gui.Canvas/ImageBrush.cs
new file mode 100644
index 0000000..e30405a
--- /dev/null
+++ b/Hyena.Gui/Hyena.Gui.Canvas/ImageBrush.cs
@@ -0,0 +1,82 @@
+//
+// ImageBrush.cs
+//
+// Author:
+// Aaron Bockover <abockover novell com>
+//
+// Copyright 2009 Aaron Bockover
+//
+// 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 Cairo;
+using Hyena.Gui;
+
+namespace Hyena.Gui.Canvas
+{
+ public class ImageBrush : Brush
+ {
+ private ImageSurface surface;
+ private bool surface_owner;
+
+ public ImageBrush ()
+ {
+ }
+
+ public ImageBrush (string path) : this (new Gdk.Pixbuf (path), true)
+ {
+ }
+
+ public ImageBrush (Gdk.Pixbuf pixbuf, bool disposePixbuf)
+ : this (new PixbufImageSurface (pixbuf, disposePixbuf), true)
+ {
+ }
+
+ public ImageBrush (ImageSurface surface, bool disposeSurface)
+ {
+ this.surface = surface;
+ this.surface_owner = disposeSurface;
+ }
+
+ protected ImageSurface Surface {
+ get { return surface; }
+ set { surface = value; }
+ }
+
+ public override bool IsValid {
+ get { return surface != null; }
+ }
+
+ public override void Apply (Cairo.Context cr)
+ {
+ if (surface != null) {
+ cr.SetSource (surface);
+ }
+ }
+
+ public override double Width {
+ get { return surface == null ? 0 : surface.Width; }
+ }
+
+ public override double Height {
+ get { return surface == null ? 0 : surface.Height; }
+ }
+ }
+}
diff --git a/Hyena.Gui/Hyena.Gui.Canvas/MarginStyle.cs b/Hyena.Gui/Hyena.Gui.Canvas/MarginStyle.cs
new file mode 100644
index 0000000..5afcc3c
--- /dev/null
+++ b/Hyena.Gui/Hyena.Gui.Canvas/MarginStyle.cs
@@ -0,0 +1,43 @@
+//
+// MarginStyle.cs
+//
+// Author:
+// Aaron Bockover <abockover novell com>
+//
+// Copyright 2009 Aaron Bockover
+//
+// 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;
+
+namespace Hyena.Gui.Canvas
+{
+ public class MarginStyle
+ {
+ public MarginStyle ()
+ {
+ }
+
+ public virtual void Apply (CanvasItem item, Cairo.Context cr)
+ {
+ }
+
+ public static readonly MarginStyle None = new MarginStyle ();
+ }
+}
diff --git a/Hyena.Gui/Hyena.Gui.Canvas/Orientation.cs b/Hyena.Gui/Hyena.Gui.Canvas/Orientation.cs
new file mode 100644
index 0000000..30e7234
--- /dev/null
+++ b/Hyena.Gui/Hyena.Gui.Canvas/Orientation.cs
@@ -0,0 +1,36 @@
+//
+// Orientation.cs
+//
+// Author:
+// Aaron Bockover <abockover novell com>
+//
+// Copyright 2009 Aaron Bockover
+//
+// 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;
+
+namespace Hyena.Gui.Canvas
+{
+ public enum Orientation
+ {
+ Horizontal,
+ Vertical
+ }
+}
diff --git a/Hyena.Gui/Hyena.Gui.Canvas/Panel.cs b/Hyena.Gui/Hyena.Gui.Canvas/Panel.cs
new file mode 100644
index 0000000..f2effc8
--- /dev/null
+++ b/Hyena.Gui/Hyena.Gui.Canvas/Panel.cs
@@ -0,0 +1,148 @@
+//
+// Panel.cs
+//
+// Author:
+// Aaron Bockover <abockover novell com>
+//
+// Copyright 2009 Aaron Bockover
+//
+// 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;
+
+namespace Hyena.Gui.Canvas
+{
+ public class Panel : CanvasItem
+ {
+ private CanvasItemCollection children;
+
+ public Panel ()
+ {
+ children = new CanvasItemCollection (this);
+ }
+
+ public override Size Measure (Size available)
+ {
+ Size result = new Size (0, 0);
+
+ foreach (var child in Children) {
+ if (child.Visible) {
+ Size size = child.Measure (available);
+ result.Width = Math.Max (result.Width, size.Width);
+ result.Height = Math.Max (result.Height, size.Height);
+ }
+ }
+
+ if (!Double.IsNaN (Width)) {
+ result.Width = Width;
+ }
+
+ if (!Double.IsNaN (Height)) {
+ result.Height = Height;
+ }
+
+ if (!available.IsEmpty) {
+ result.Width = Math.Min (result.Width, available.Width);
+ result.Height = Math.Min (result.Height, available.Height);
+ }
+
+ return DesiredSize = result;
+ }
+
+ public override void Arrange ()
+ {
+ foreach (var child in Children) {
+ if (!child.Visible) {
+ continue;
+ }
+
+ child.Allocation = new Rect (0, 0,
+ Math.Min (ContentAllocation.Width, child.DesiredSize.Width),
+ Math.Min (ContentAllocation.Height, child.DesiredSize.Height));
+
+ child.Arrange ();
+ }
+ }
+
+ protected override void ClippedRender (Cairo.Context cr)
+ {
+ foreach (var child in Children) {
+ if (child.Visible) {
+ child.Render (cr);
+ }
+ }
+ }
+
+ protected CanvasItem FindChildAt (double x, double y, bool grabHasPriority)
+ {
+ foreach (var child in Children) {
+ if (child.IsPointerGrabbed || (child.Visible && child.Allocation.Contains (x, y))) {
+ return child;
+ }
+ }
+
+ return null;
+ }
+
+ protected delegate void CanvasItemHandler (CanvasItem item);
+
+ protected void WithPointerGrabChild (CanvasItemHandler handler)
+ {
+ WithChildAt (-1, -1, true, handler);
+ }
+
+ protected void WithChildAt (double x, double y, CanvasItemHandler handler)
+ {
+ WithChildAt (x, y, true, handler);
+ }
+
+ protected void WithChildAt (double x, double y, bool grabHasPriority, CanvasItemHandler handler)
+ {
+ CanvasItem child = FindChildAt (x, y, grabHasPriority);
+ if (child != null) {
+ handler (child);
+ }
+ }
+
+ public override void ButtonPress (double x, double y, uint button)
+ {
+ WithChildAt (x, y, (item) => item.ButtonPress (
+ x - item.Allocation.X, y - item.Allocation.Y, button));
+ }
+
+ public override void ButtonRelease ()
+ {
+ WithPointerGrabChild ((item) => item.ButtonRelease ());
+ }
+
+ public override void PointerMotion (double x, double y)
+ {
+ WithChildAt (x, y, (item) => item.PointerMotion (
+ x - item.Allocation.X, y - item.Allocation.Y));
+ }
+
+ public override bool IsPointerGrabbed {
+ get { return base.IsPointerGrabbed || FindChildAt (-1, -1, true) != null; }
+ }
+
+ public CanvasItemCollection Children {
+ get { return children; }
+ }
+ }
+}
diff --git a/Hyena.Gui/Hyena.Gui.Canvas/Rect.cs b/Hyena.Gui/Hyena.Gui.Canvas/Rect.cs
index bb49fd7..0a1b406 100644
--- a/Hyena.Gui/Hyena.Gui.Canvas/Rect.cs
+++ b/Hyena.Gui/Hyena.Gui.Canvas/Rect.cs
@@ -30,7 +30,7 @@ using System;
namespace Hyena.Gui.Canvas
{
- public struct Rect
+ public struct Rect
{
private double x, y, w, h;
@@ -63,10 +63,10 @@ namespace Hyena.Gui.Canvas
if (IsEmpty) {
return "Empty";
}
-
+
return String.Format ("{0}+{1},{2}x{3}", x, y, w, h);
}
-
+
public double X {
get { return x; }
set { x = value; }
@@ -74,28 +74,28 @@ namespace Hyena.Gui.Canvas
public double Y {
get { return y; }
- set { y = value; }
+ set { y = value; }
}
public double Width {
get { return w; }
- set {
+ set {
if (value < 0) {
throw new ArgumentException ();
}
-
- w = value;
- }
+
+ w = value;
+ }
}
public double Height {
get { return h; }
- set {
+ set {
if (value < 0) {
throw new ArgumentException ();
}
-
- h = value;
+
+ h = value;
}
}
@@ -116,35 +116,35 @@ namespace Hyena.Gui.Canvas
Top > rect.Bottom ||
Bottom < rect.Top);
}
-
- public static Rect Empty {
- get {
+
+ public static Rect Empty {
+ get {
var empty = new Rect (Double.PositiveInfinity, Double.PositiveInfinity, 0, 0);
empty.w = empty.h = Double.NegativeInfinity;
return empty;
- }
+ }
}
-
- public bool IsEmpty {
+
+ public bool IsEmpty {
get { return w < 0 && h < 0; }
}
-
- public double Left {
+
+ public double Left {
get { return x; }
}
-
- public double Top {
+
+ public double Top {
get { return y; }
}
public double Right {
get { return IsEmpty ? Double.NegativeInfinity : x + w; }
}
-
- public double Bottom {
+
+ public double Bottom {
get { return IsEmpty ? Double.NegativeInfinity : y + h; }
}
-
+
public void Intersect (Rect rect)
{
if (IsEmpty || rect.IsEmpty) {
@@ -155,7 +155,7 @@ namespace Hyena.Gui.Canvas
double new_x = Math.Max (x, rect.x);
double new_y = Math.Max (y, rect.y);
double new_w = Math.Min (Right, rect.Right) - new_x;
- double new_h = Math.Min (Bottom, rect.Bottom) - new_y;
+ double new_h = Math.Min (Bottom, rect.Bottom) - new_y;
x = new_x;
y = new_y;
@@ -179,14 +179,14 @@ namespace Hyena.Gui.Canvas
double new_y = Math.Min (Top, rect.Top);
double new_w = Math.Max (Right, rect.Right) - new_x;
double new_h = Math.Max (Bottom, rect.Bottom) - new_y;
-
+
x = new_x;
y = new_y;
w = new_w;
h = new_h;
}
}
-
+
public void Union (Point point)
{
Union (new Rect (point, point));
@@ -209,17 +209,17 @@ namespace Hyena.Gui.Canvas
x += dx;
y += dy;
}
-
+
public static bool operator == (Rect rect1, Rect rect2)
{
return rect1.x == rect2.x && rect1.y == rect2.y && rect1.w == rect2.w && rect1.h == rect2.h;
}
-
+
public static bool operator != (Rect rect1, Rect rect2)
{
return !(rect1 == rect2);
}
-
+
public override bool Equals (object o)
{
if (o is Rect) {
@@ -227,12 +227,12 @@ namespace Hyena.Gui.Canvas
}
return false;
}
-
+
public bool Equals (Rect value)
{
return this == value;
}
-
+
public override int GetHashCode ()
{
return x.GetHashCode () ^ y.GetHashCode () ^ w.GetHashCode () ^ h.GetHashCode ();
diff --git a/Hyena.Gui/Hyena.Gui.Canvas/ShadowMarginStyle.cs b/Hyena.Gui/Hyena.Gui.Canvas/ShadowMarginStyle.cs
new file mode 100644
index 0000000..63648d6
--- /dev/null
+++ b/Hyena.Gui/Hyena.Gui.Canvas/ShadowMarginStyle.cs
@@ -0,0 +1,89 @@
+//
+// ShadowMarginStyle.cs
+//
+// Author:
+// Aaron Bockover <abockover novell com>
+//
+// Copyright 2009 Aaron Bockover
+//
+// 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 Cairo;
+
+namespace Hyena.Gui.Canvas
+{
+ public class ShadowMarginStyle : MarginStyle
+ {
+ private int shadow_size;
+ private double shadow_opacity = 0.75;
+ private Brush fill;
+
+ public ShadowMarginStyle ()
+ {
+ }
+
+ public override void Apply (CanvasItem item, Context cr)
+ {
+ int steps = ShadowSize;
+ double opacity_step = ShadowOpacity / ShadowSize;
+ Color color = new Color (0, 0, 0);
+
+ double width = Math.Round (item.Allocation.Width);
+ double height = Math.Round (item.Allocation.Height);
+
+ if (Fill != null) {
+ cr.Rectangle (shadow_size, shadow_size, width - ShadowSize * 2, height - ShadowSize * 2);
+ Fill.Apply (cr);
+ cr.Fill ();
+ }
+
+ cr.LineWidth = 1.0;
+
+ for (int i = 0; i < steps; i++) {
+ CairoExtensions.RoundedRectangle (cr,
+ i + 0.5,
+ i + 0.5,
+ (width - 2 * i) - 1,
+ (height - 2 * i) - 1,
+ steps - i);
+
+ color.A = opacity_step * (i + 1);
+ cr.Color = color;
+ cr.Stroke ();
+ }
+ }
+
+ public double ShadowOpacity {
+ get { return shadow_opacity; }
+ set { shadow_opacity = value; }
+ }
+
+ public int ShadowSize {
+ get { return shadow_size; }
+ set { shadow_size = value; }
+ }
+
+ public Brush Fill {
+ get { return fill; }
+ set { fill = value; }
+ }
+ }
+}
diff --git a/Hyena.Gui/Hyena.Gui.Canvas/Size.cs b/Hyena.Gui/Hyena.Gui.Canvas/Size.cs
index 4d2cca7..b626597 100644
--- a/Hyena.Gui/Hyena.Gui.Canvas/Size.cs
+++ b/Hyena.Gui/Hyena.Gui.Canvas/Size.cs
@@ -30,7 +30,7 @@ using System;
namespace Hyena.Gui.Canvas
{
- public struct Size
+ public struct Size
{
private double width;
private double height;
@@ -40,44 +40,44 @@ namespace Hyena.Gui.Canvas
Width = width;
Height = height;
}
-
+
public override bool Equals (object o)
{
if (!(o is Size)) {
return false;
}
-
+
return Equals ((Size)o);
}
-
+
public bool Equals (Size value)
{
return value.width == width && value.height == height;
}
-
+
public override int GetHashCode ()
{
return ((int)width) ^ ((int)height);
}
-
+
public static bool operator == (Size size1, Size size2)
{
return size1.width == size2.width && size1.height == size2.height;
}
-
+
public static bool operator != (Size size1, Size size2)
{
return size1.width != size2.width || size1.height != size2.height;
}
-
+
public double Height {
- get { return height; }
+ get { return height; }
set {
if (value < 0) {
throw new ArgumentException ();
}
-
- height = value;
+
+ height = value;
}
}
@@ -87,7 +87,7 @@ namespace Hyena.Gui.Canvas
if (value < 0) {
throw new ArgumentException ();
}
-
+
width = value;
}
}
@@ -95,7 +95,7 @@ namespace Hyena.Gui.Canvas
public bool IsEmpty {
get { return width == Double.NegativeInfinity && height == Double.NegativeInfinity; }
}
-
+
public static Size Empty {
get {
Size size = new Size ();
@@ -110,7 +110,7 @@ namespace Hyena.Gui.Canvas
if (IsEmpty) {
return "Empty";
}
-
+
return String.Format ("{0}x{1}", width, height);
}
}
diff --git a/Hyena.Gui/Hyena.Gui.Canvas/Slider.cs b/Hyena.Gui/Hyena.Gui.Canvas/Slider.cs
new file mode 100644
index 0000000..82dd6c1
--- /dev/null
+++ b/Hyena.Gui/Hyena.Gui.Canvas/Slider.cs
@@ -0,0 +1,237 @@
+//
+// Slider.cs
+//
+// Author:
+// Aaron Bockover <abockover novell com>
+//
+// Copyright 2009 Aaron Bockover
+//
+// 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 Cairo;
+
+using Hyena.Gui;
+using Hyena.Gui.Theming;
+
+namespace Hyena.Gui.Canvas
+{
+ public class Slider : CanvasItem
+ {
+ private uint value_changed_inhibit_ref = 0;
+
+ public event EventHandler<EventArgs> ValueChanged;
+ public event EventHandler<EventArgs> PendingValueChanged;
+
+ public Slider ()
+ {
+ Margin = new Thickness (3);
+ MarginStyle = new ShadowMarginStyle {
+ ShadowSize = 3,
+ ShadowOpacity = 0.25
+ };
+ }
+
+ protected virtual void OnValueChanged ()
+ {
+ if (value_changed_inhibit_ref != 0) {
+ return;
+ }
+
+ var handler = ValueChanged;
+ if (handler != null) {
+ handler (this, EventArgs.Empty);
+ }
+ }
+
+ protected virtual void OnPendingValueChanged ()
+ {
+ var handler = PendingValueChanged;
+ if (handler != null) {
+ handler (this, EventArgs.Empty);
+ }
+ }
+
+ public void InhibitValueChangeEvent ()
+ {
+ value_changed_inhibit_ref++;
+ }
+
+ public void UninhibitValueChangeEvent ()
+ {
+ value_changed_inhibit_ref--;
+ }
+
+ private void SetPendingValueFromX (double x)
+ {
+ IsValueUpdatePending = true;
+ PendingValue = Math.Max (0, Math.Min ((x - ThrobberSize / 2) / RenderSize.Width, 1));
+ }
+
+ public override void ButtonPress (double x, double y, uint button)
+ {
+ if (button == 1) {
+ GrabPointer ();
+ SetPendingValueFromX (x);
+ }
+ }
+
+ public override void ButtonRelease ()
+ {
+ if (IsPointerGrabbed) {
+ ReleasePointer ();
+ Value = PendingValue;
+ IsValueUpdatePending = false;
+ }
+ }
+
+ public override void PointerMotion (double x, double y)
+ {
+ if (IsPointerGrabbed) {
+ SetPendingValueFromX (x);
+ }
+ }
+
+ private double last_invalidate_value = -1;
+
+ private void Invalidate ()
+ {
+ double current_value = (IsValueUpdatePending ? PendingValue : Value);
+
+ // FIXME: Something is wrong with the updating below causing an
+ // invalid region when IsValueUpdatePending is true, so when
+ // that is the case for now, we trigger a full invalidation
+ if (last_invalidate_value < 0 || IsValueUpdatePending) {
+ last_invalidate_value = current_value;
+ InvalidateRender ();
+ return;
+ }
+
+ double max = Math.Max (last_invalidate_value, current_value) * RenderSize.Width;
+ double min = Math.Min (last_invalidate_value, current_value) * RenderSize.Width;
+
+ Rect region = new Rect (
+ InvalidationRect.X + min,
+ InvalidationRect.Y,
+ (max - min) + 2 * ThrobberSize,
+ InvalidationRect.Height
+ );
+
+ last_invalidate_value = current_value;
+ InvalidateRender (region);
+ }
+
+ protected override Rect InvalidationRect {
+ get { return new Rect (
+ -Margin.Left - ThrobberSize / 2,
+ -Margin.Top,
+ Allocation.Width + ThrobberSize,
+ Allocation.Height);
+ }
+ }
+
+ protected override void ClippedRender (Cairo.Context cr)
+ {
+ double throbber_r = ThrobberSize / 2.0;
+ double throbber_x = Math.Round (RenderSize.Width * (IsValueUpdatePending ? PendingValue : Value));
+ double throbber_y = (Allocation.Height - ThrobberSize) / 2.0 - Margin.Top + throbber_r;
+ double bar_w = RenderSize.Width * Value;
+
+ cr.Color = Theme.Colors.GetWidgetColor (GtkColorClass.Base, Gtk.StateType.Normal);
+ cr.Rectangle (0, 0, RenderSize.Width, RenderSize.Height);
+ cr.Fill ();
+
+ Color color = Theme.Colors.GetWidgetColor (GtkColorClass.Dark, Gtk.StateType.Active);
+ Color fill_color = CairoExtensions.ColorShade (color, 0.4);
+ Color light_fill_color = CairoExtensions.ColorShade (color, 0.3);
+ fill_color.A = 1.0;
+ light_fill_color.A = 1.0;
+
+ LinearGradient fill = new LinearGradient (0, 0, 0, RenderSize.Height);
+ fill.AddColorStop (0, light_fill_color);
+ fill.AddColorStop (0.5, fill_color);
+ fill.AddColorStop (1, light_fill_color);
+
+ cr.Rectangle (0, 0, bar_w, RenderSize.Height);
+ cr.Pattern = fill;
+ cr.Fill ();
+
+ cr.Color = fill_color;
+ cr.Arc (throbber_x, throbber_y, throbber_r, 0, Math.PI * 2);
+ cr.Fill ();
+ }
+
+ public override Size Measure (Size available)
+ {
+ Height = BarSize;
+ return DesiredSize = new Size (base.Measure (available).Width,
+ Height + Margin.Top + Margin.Bottom);
+ }
+
+ private double bar_size = 3;
+ public virtual double BarSize {
+ get { return bar_size; }
+ set { bar_size = value; }
+ }
+
+ private double throbber_size = 7;
+ public virtual double ThrobberSize {
+ get { return throbber_size; }
+ set { throbber_size = value; }
+ }
+
+ private double value;
+ public virtual double Value {
+ get { return this.value; }
+ set {
+ if (value < 0.0 || value > 1.0) {
+ throw new ArgumentOutOfRangeException ("Value", "Must be between 0.0 and 1.0 inclusive");
+ } else if (this.value == value) {
+ return;
+ }
+
+ this.value = value;
+ Invalidate ();
+ OnValueChanged ();
+ }
+ }
+
+ private bool is_value_update_pending;
+ public virtual bool IsValueUpdatePending {
+ get { return is_value_update_pending; }
+ set { is_value_update_pending = value; }
+ }
+
+ private double pending_value;
+ public virtual double PendingValue {
+ get { return pending_value; }
+ set {
+ if (value < 0.0 || value > 1.0) {
+ throw new ArgumentOutOfRangeException ("Value", "Must be between 0.0 and 1.0 inclusive");
+ } else if (pending_value == value) {
+ return;
+ }
+
+ pending_value = value;
+ Invalidate ();
+ OnPendingValueChanged ();
+ }
+ }
+ }
+}
diff --git a/Hyena.Gui/Hyena.Gui.Canvas/StackPanel.cs b/Hyena.Gui/Hyena.Gui.Canvas/StackPanel.cs
new file mode 100644
index 0000000..e02fbec
--- /dev/null
+++ b/Hyena.Gui/Hyena.Gui.Canvas/StackPanel.cs
@@ -0,0 +1,153 @@
+//
+// StackPanel.cs
+//
+// Author:
+// Aaron Bockover <abockover novell com>
+//
+// Copyright 2009 Aaron Bockover
+//
+// 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;
+
+namespace Hyena.Gui.Canvas
+{
+ public class StackPanel : Panel
+ {
+ private Orientation orientation;
+ public double spacing;
+
+ public StackPanel ()
+ {
+ }
+
+ public override Size Measure (Size available)
+ {
+ Size result = new Size (0, 0);
+
+ foreach (var child in Children) {
+ if (!child.Visible) {
+ continue;
+ }
+
+ Size size = child.Measure (available);
+
+ if (Orientation == Orientation.Vertical) {
+ result.Height += size.Height;
+ result.Width = Math.Max (result.Width, size.Width);
+ } else {
+ result.Width += size.Width;
+ result.Height = Math.Max (result.Height, size.Height);
+ }
+ }
+
+ if (!Double.IsNaN (Width)) {
+ result.Width = Width;
+ }
+
+ if (!Double.IsNaN (Height)) {
+ result.Height = Height;
+ }
+
+ if (!available.IsEmpty) {
+ result.Width = Math.Min (result.Width, available.Width);
+ result.Height = Math.Min (result.Height, available.Height);
+ }
+
+ if (Orientation == Orientation.Vertical) {
+ result.Height += Spacing * (Children.Count - 1);
+ } else {
+ result.Width += Spacing * (Children.Count - 1);
+ }
+
+ return DesiredSize = result;
+ }
+
+ public override void Arrange ()
+ {
+ int visible_child_count = 0;
+ int flex_count = 0;
+ double offset = 0;
+ double static_space = 0;
+ double flex_space = 0;
+
+ foreach (var child in Children) {
+ if (!child.Visible) {
+ continue;
+ }
+
+ child.Measure (ContentSize);
+
+ visible_child_count++;
+
+ if (Orientation == Orientation.Vertical) {
+ static_space += Double.IsNaN (child.Height) ? 0 : child.DesiredSize.Height;
+ flex_count += Double.IsNaN (child.Height) ? 1 : 0;
+ } else {
+ static_space += Double.IsNaN (child.Width) ? 0 : child.DesiredSize.Width;
+ flex_count += Double.IsNaN (child.Width) ? 1 : 0;
+ }
+ }
+
+ flex_space = (Orientation == Orientation.Vertical ? ContentAllocation.Height : ContentAllocation.Width) -
+ static_space - (visible_child_count - 1) * Spacing;
+ if (flex_space < 0) {
+ flex_space = 0;
+ }
+
+ foreach (var child in Children) {
+ if (!child.Visible) {
+ continue;
+ }
+
+ double variable_size = 0;
+
+ if ((Orientation == Orientation.Vertical && Double.IsNaN (child.Height)) ||
+ (Orientation == Orientation.Horizontal && Double.IsNaN (child.Width))) {
+ variable_size = flex_space / flex_count--;
+ flex_space -= variable_size;
+ if (flex_count == 0) {
+ variable_size += flex_space;
+ }
+ } else if (Orientation == Orientation.Vertical) {
+ variable_size = child.DesiredSize.Height;
+ } else {
+ variable_size = child.DesiredSize.Width;
+ }
+
+ child.Allocation = Orientation == Orientation.Vertical
+ ? new Rect (0, offset, ContentAllocation.Width, variable_size)
+ : new Rect (offset, 0, variable_size, ContentAllocation.Height);
+ child.Arrange ();
+
+ offset += variable_size + Spacing;
+ }
+ }
+
+ public Orientation Orientation {
+ get { return orientation; }
+ set { orientation = value; }
+ }
+
+ public double Spacing {
+ get { return spacing; }
+ set { spacing = value; }
+ }
+ }
+}
diff --git a/Hyena.Gui/Hyena.Gui.Canvas/TestTile.cs b/Hyena.Gui/Hyena.Gui.Canvas/TestTile.cs
new file mode 100644
index 0000000..3d58654
--- /dev/null
+++ b/Hyena.Gui/Hyena.Gui.Canvas/TestTile.cs
@@ -0,0 +1,62 @@
+//
+// TestTile.cs
+//
+// Author:
+// Aaron Bockover <abockover novell com>
+//
+// Copyright 2009 Aaron Bockover
+//
+// 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 Cairo;
+using Hyena.Gui;
+
+namespace Hyena.Gui.Canvas
+{
+ public class TestTile : CanvasItem
+ {
+ private static Random rand = new Random ();
+ private Color color;
+ private bool color_set;
+
+ private bool change_on_render = true;
+ public bool ChangeOnRender {
+ get { return change_on_render; }
+ set { change_on_render = value; }
+ }
+
+ public TestTile ()
+ {
+ }
+
+ protected override void ClippedRender (Context cr)
+ {
+ if (!color_set || ChangeOnRender) {
+ color = CairoExtensions.RgbToColor ((uint)rand.Next (0, 0xffffff));
+ color_set = true;
+ }
+
+ CairoExtensions.RoundedRectangle (cr, 0, 0, RenderSize.Width, RenderSize.Height, 5);
+ cr.Color = color;
+ cr.Fill ();
+ }
+ }
+}
diff --git a/Hyena.Gui/Hyena.Gui.Canvas/TextBlock.cs b/Hyena.Gui/Hyena.Gui.Canvas/TextBlock.cs
new file mode 100644
index 0000000..3569bd6
--- /dev/null
+++ b/Hyena.Gui/Hyena.Gui.Canvas/TextBlock.cs
@@ -0,0 +1,260 @@
+//
+// TextBlock.cs
+//
+// Author:
+// Aaron Bockover <abockover novell com>
+//
+// Copyright 2009 Aaron Bockover
+//
+// 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 Cairo;
+
+namespace Hyena.Gui.Canvas
+{
+ public class TextBlock : CanvasItem
+ {
+ private Pango.Layout layout;
+ private Rect text_alloc = Rect.Empty;
+ private Rect invalidation_rect = Rect.Empty;
+
+ public TextBlock ()
+ {
+ InstallProperty<string> ("Text", String.Empty);
+ InstallProperty<double> ("HorizontalAlignment", 0.0);
+ InstallProperty<double> ("VerticalAlignment", 0.0);
+ InstallProperty<FontWeight> ("FontWeight", FontWeight.Normal);
+ InstallProperty<TextWrap> ("TextWrap", TextWrap.None);
+ InstallProperty<bool> ("ForceSize", false);
+ }
+
+ private bool EnsureLayout ()
+ {
+ if (layout != null) {
+ return true;
+ }
+
+ Gtk.Widget widget = Manager == null ? null : Manager.Host as Gtk.Widget;
+ if (widget == null || widget.GdkWindow == null || !widget.IsRealized) {
+ return false;
+ }
+
+ using (var cr = Gdk.CairoHelper.Create (widget.GdkWindow)) {
+ layout = CairoExtensions.CreateLayout (widget, cr);
+ }
+
+ return layout != null;
+ }
+
+ public override Size Measure (Size available)
+ {
+ if (!EnsureLayout ()) {
+ return new Size (0, 0);
+ }
+
+ available = base.Measure (available);
+
+ int text_w, text_h;
+
+ TextWrap wrap = TextWrap;
+ layout.Width = wrap == TextWrap.None ? -1 : (int)(Pango.Scale.PangoScale * available.Width);
+ layout.Wrap = GetPangoWrapMode (wrap);
+ layout.FontDescription.Weight = GetPangoFontWeight (FontWeight);
+ layout.SetText (Text);
+ layout.GetPixelSize (out text_w, out text_h);
+
+ double width = text_w;
+ if (!available.IsEmpty && available.Width > 0) {
+ width = available.Width;
+ }
+
+ DesiredSize = new Size (
+ width + Margin.Left + Margin.Right,
+ text_h + Margin.Top + Margin.Bottom);
+
+ // Hack, as this prevents the TextBlock from
+ // being flexible in a Vertical StackPanel
+ Height = DesiredSize.Height;
+
+ if (ForceSize) {
+ Width = DesiredSize.Width;
+ }
+
+ return DesiredSize;
+ }
+
+ public override void Arrange ()
+ {
+ if (!EnsureLayout ()) {
+ return;
+ }
+
+ int layout_width = TextWrap == TextWrap.None
+ ? -1
+ : (int)(Pango.Scale.PangoScale * ContentAllocation.Width);
+ if (layout.Width != layout_width) {
+ layout.Width = layout_width;
+ }
+
+ int text_width, text_height;
+ layout.GetPixelSize (out text_width, out text_height);
+
+ Rect new_alloc = new Rect (
+ Math.Round ((RenderSize.Width - text_width) * HorizontalAlignment),
+ Math.Round ((RenderSize.Height - text_height) * VerticalAlignment),
+ text_width,
+ text_height);
+
+ if (text_alloc.IsEmpty) {
+ InvalidateRender (text_alloc);
+ } else {
+ invalidation_rect = text_alloc;
+ invalidation_rect.Union (new_alloc);
+
+ // Some padding, likely because of the pen size for
+ // showing the actual text layout in the render pass
+ invalidation_rect.X -= 2;
+ invalidation_rect.Y -= 2;
+ invalidation_rect.Width += 4;
+ invalidation_rect.Height += 4;
+
+ InvalidateRender (invalidation_rect);
+ }
+
+ text_alloc = new_alloc;
+ }
+
+ protected override void ClippedRender (Context cr)
+ {
+ if (!EnsureLayout ()) {
+ return;
+ }
+
+ Brush foreground = Foreground;
+ if (!foreground.IsValid) {
+ return;
+ }
+
+ cr.Rectangle (0, 0, RenderSize.Width, RenderSize.Height);
+ cr.Clip ();
+
+ bool fade = text_alloc.Width > RenderSize.Width;
+
+ if (fade) {
+ cr.PushGroup ();
+ }
+
+ cr.MoveTo (text_alloc.X, text_alloc.Y);
+ Foreground.Apply (cr);
+ Pango.CairoHelper.ShowLayout (cr, layout);
+ cr.Fill ();
+
+ if (fade) {
+ LinearGradient mask = new LinearGradient (RenderSize.Width - 20, 0, RenderSize.Width, 0);
+ mask.AddColorStop (0, new Color (0, 0, 0, 1));
+ mask.AddColorStop (1, new Color (0, 0, 0, 0));
+
+ cr.PopGroupToSource ();
+ cr.Mask (mask);
+ mask.Destroy ();
+ }
+
+ cr.ResetClip ();
+ }
+
+ private Pango.Weight GetPangoFontWeight (FontWeight weight)
+ {
+ switch (weight) {
+ case FontWeight.Bold: return Pango.Weight.Bold;
+ default: return Pango.Weight.Normal;
+ }
+ }
+
+ private Pango.WrapMode GetPangoWrapMode (TextWrap wrap)
+ {
+ switch (wrap) {
+ case TextWrap.Char: return Pango.WrapMode.Char;
+ case TextWrap.WordChar: return Pango.WrapMode.WordChar;
+ case TextWrap.None:
+ case TextWrap.Word:
+ default:
+ return Pango.WrapMode.Word;
+ }
+ }
+
+ protected override bool OnPropertyChange (string property, object value)
+ {
+ switch (property) {
+ case "FontWeight":
+ case "TextWrap":
+ case "Text":
+ case "ForceSize":
+ if (layout != null) {
+ InvalidateMeasure ();
+ InvalidateArrange ();
+ }
+ return true;
+ case "HorizontalAlignment":
+ case "VerticalAlignment":
+ if (layout != null) {
+ InvalidateArrange ();
+ }
+ return true;
+ }
+
+ return base.OnPropertyChange (property, value);
+ }
+
+ protected override Rect InvalidationRect {
+ get { return invalidation_rect; }
+ }
+
+ public string Text {
+ get { return GetValue<string> ("Text"); }
+ set { SetValue<string> ("Text", value); }
+ }
+
+ public FontWeight FontWeight {
+ get { return GetValue<FontWeight> ("FontWeight"); }
+ set { SetValue<FontWeight> ("FontWeight", value); }
+ }
+
+ public TextWrap TextWrap {
+ get { return GetValue<TextWrap> ("TextWrap"); }
+ set { SetValue<TextWrap> ("TextWrap", value); }
+ }
+
+ public bool ForceSize {
+ get { return GetValue<bool> ("ForceSize"); }
+ set { SetValue<bool> ("ForceSize", value); }
+ }
+
+ public double HorizontalAlignment {
+ get { return GetValue<double> ("HorizontalAlignment", 0.5); }
+ set { SetValue<double> ("HorizontalAlignment", value); }
+ }
+
+ public double VerticalAlignment {
+ get { return GetValue<double> ("VerticalAlignment", 0.0); }
+ set { SetValue<double> ("VerticalAlignment", value); }
+ }
+ }
+}
diff --git a/Hyena.Gui/Hyena.Gui.Canvas/TextWrap.cs b/Hyena.Gui/Hyena.Gui.Canvas/TextWrap.cs
new file mode 100644
index 0000000..f14624f
--- /dev/null
+++ b/Hyena.Gui/Hyena.Gui.Canvas/TextWrap.cs
@@ -0,0 +1,38 @@
+//
+// TextWrap.cs
+//
+// Author:
+// Aaron Bockover <abockover novell com>
+//
+// Copyright 2009 Aaron Bockover
+//
+// 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;
+
+namespace Hyena.Gui.Canvas
+{
+ public enum TextWrap
+ {
+ None,
+ Word,
+ Char,
+ WordChar
+ }
+}
diff --git a/Hyena.Gui/Hyena.Gui.Canvas/Thickness.cs b/Hyena.Gui/Hyena.Gui.Canvas/Thickness.cs
index 56fa88d..f0f59db 100644
--- a/Hyena.Gui/Hyena.Gui.Canvas/Thickness.cs
+++ b/Hyena.Gui/Hyena.Gui.Canvas/Thickness.cs
@@ -38,17 +38,17 @@ namespace Hyena.Gui.Canvas
private double bottom;
public static readonly Thickness Zero = new Thickness (0);
-
- public Thickness (double thickness)
+
+ public Thickness (double thickness)
: this (thickness, thickness, thickness, thickness)
{
}
-
- public Thickness (double xthickness, double ythickness)
+
+ public Thickness (double xthickness, double ythickness)
: this (xthickness, ythickness, xthickness, ythickness)
{
}
-
+
public Thickness (double left, double top, double right, double bottom)
{
this.left = left;
@@ -56,13 +56,13 @@ namespace Hyena.Gui.Canvas
this.right = right;
this.bottom = bottom;
}
-
+
public override string ToString ()
{
return string.Format ("{0},{1},{2},{3}", Double.IsNaN (left) ? "Auto" : left.ToString (),
- Double.IsNaN (top) ? "Auto" : top.ToString (),
- Double.IsNaN (right) ? "Auto" : right.ToString (),
- Double.IsNaN (bottom) ? "Auto" : bottom.ToString ());
+ Double.IsNaN (top) ? "Auto" : top.ToString (),
+ Double.IsNaN (right) ? "Auto" : right.ToString (),
+ Double.IsNaN (bottom) ? "Auto" : bottom.ToString ());
}
public override bool Equals (object o)
@@ -70,20 +70,20 @@ namespace Hyena.Gui.Canvas
if (!(o is Thickness)) {
return false;
}
-
+
return this == (Thickness)o;
}
-
+
public bool Equals (Thickness thickness)
{
return this == thickness;
}
-
+
public override int GetHashCode ()
{
return left.GetHashCode () ^ top.GetHashCode () ^ right.GetHashCode () ^ bottom.GetHashCode ();
}
-
+
public static bool operator == (Thickness t1, Thickness t2)
{
return t1.left == t2.left &&
@@ -91,28 +91,28 @@ namespace Hyena.Gui.Canvas
t1.top == t2.top &&
t1.bottom == t2.bottom;
}
-
+
public static bool operator != (Thickness t1, Thickness t2)
{
return !(t1 == t2);
}
-
+
public double Left {
get { return left; }
set { left = value; }
}
-
+
public double Top {
get { return top; }
- set { top = value; }
+ set { top = value; }
}
-
- public double Right {
+
+ public double Right {
get { return right; }
set { right = value; }
}
-
- public double Bottom {
+
+ public double Bottom {
get { return bottom; }
set { bottom = value; }
}
diff --git a/Hyena.Gui/Makefile.am b/Hyena.Gui/Makefile.am
index 27faf5d..e7b6c8c 100644
--- a/Hyena.Gui/Makefile.am
+++ b/Hyena.Gui/Makefile.am
@@ -43,10 +43,31 @@ SOURCES = \
Hyena.Data.Gui/ObjectListView.cs \
Hyena.Data.Gui/RowActivatedHandler.cs \
Hyena.Data.Gui/SortableColumn.cs \
- Hyena.Gui.Canvas/Point.cs \
- Hyena.Gui.Canvas/Rect.cs \
- Hyena.Gui.Canvas/Size.cs \
- Hyena.Gui.Canvas/Thickness.cs \
+ Hyena.Gui.Canvas/AnimationManager.cs \
+ Hyena.Gui.Canvas/Brush.cs \
+ Hyena.Gui.Canvas/CanvasHost.cs \
+ Hyena.Gui.Canvas/CanvasItem.cs \
+ Hyena.Gui.Canvas/CanvasItemCollection.cs \
+ Hyena.Gui.Canvas/CanvasManager.cs \
+ Hyena.Gui.Canvas/FixedPanel.cs \
+ Hyena.Gui.Canvas/FontWeight.cs \
+ Hyena.Gui.Canvas/FpsCalculator.cs \
+ Hyena.Gui.Canvas/ICanvasHost.cs \
+ Hyena.Gui.Canvas/Image.cs \
+ Hyena.Gui.Canvas/ImageBrush.cs \
+ Hyena.Gui.Canvas/MarginStyle.cs \
+ Hyena.Gui.Canvas/Orientation.cs \
+ Hyena.Gui.Canvas/Panel.cs \
+ Hyena.Gui.Canvas/Point.cs \
+ Hyena.Gui.Canvas/Rect.cs \
+ Hyena.Gui.Canvas/ShadowMarginStyle.cs \
+ Hyena.Gui.Canvas/Size.cs \
+ Hyena.Gui.Canvas/Slider.cs \
+ Hyena.Gui.Canvas/StackPanel.cs \
+ Hyena.Gui.Canvas/TestTile.cs \
+ Hyena.Gui.Canvas/TextBlock.cs \
+ Hyena.Gui.Canvas/TextWrap.cs \
+ Hyena.Gui.Canvas/Thickness.cs \
Hyena.Gui.Dialogs/ExceptionDialog.cs \
Hyena.Gui.Dialogs/VersionInformationDialog.cs \
Hyena.Gui.Theatrics/Actor.cs \
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]