aboutsummaryrefslogtreecommitdiffstatsci
path: root/src/GraphicObjects/GraphicObject.cs
diff options
context:
space:
mode:
authorj-p <jp.bruyere@live.be>2018-12-11 23:20:54 +0100
committerGitHub <noreply@github.com>2018-12-11 23:20:54 +0100
commiteef19b533a0e2ce17f2762d3acfc5990496eaaa0 (patch)
tree6f09101bd8097c1a4ca6a216597bb5d4941453fa /src/GraphicObjects/GraphicObject.cs
parent65820f61457262b631eba35283c55135aecbc5f2 (diff)
parentf6732851fe211e22ff91716ac83dffc0cf09d620 (diff)
Merge pull request #44 from jpbruyere/xlib
Xlib
Diffstat (limited to 'src/GraphicObjects/GraphicObject.cs')
-rw-r--r--src/GraphicObjects/GraphicObject.cs1959
1 files changed, 0 insertions, 1959 deletions
diff --git a/src/GraphicObjects/GraphicObject.cs b/src/GraphicObjects/GraphicObject.cs
deleted file mode 100644
index bc955368..00000000
--- a/src/GraphicObjects/GraphicObject.cs
+++ /dev/null
@@ -1,1959 +0,0 @@
-//
-// GraphicObject.cs
-//
-// Author:
-// Jean-Philippe Bruyère <jp.bruyere@hotmail.com>
-//
-// Copyright (c) 2013-2017 Jean-Philippe Bruyère
-//
-// 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 System.ComponentModel;
-using System.Xml.Serialization;
-using System.Reflection;
-using System.Reflection.Emit;
-using System.Runtime.CompilerServices;
-using Cairo;
-using System.Diagnostics;
-using Crow.IML;
-using System.Threading;
-
-
-#if DESIGN_MODE
-using System.Xml;
-using System.IO;
-#endif
-
-namespace Crow
-{
- /// <summary>
- /// The base class for all the graphic tree elements.
- /// </summary>
- public class GraphicObject : ILayoutable, IValueChange, IDisposable
- {
- internal ReaderWriterLockSlim parentRWLock = new ReaderWriterLockSlim();
-
- #if DESIGN_MODE
- static MethodInfo miDesignAddDefLoc = typeof(GraphicObject).GetMethod("design_add_style_location",
- BindingFlags.Instance | BindingFlags.NonPublic);
- static MethodInfo miDesignAddValLoc = typeof(GraphicObject).GetMethod("design_add_iml_location",
- BindingFlags.Instance | BindingFlags.NonPublic);
-
- public volatile bool design_HasChanged = false;
- public string design_id;
- public int design_line;
- public int design_column;
- public string design_imlPath;
- public bool design_isTGItem = false;//true if this is a templated item's root
- public Dictionary<string,string> design_iml_values = new Dictionary<string, string>();
- public Dictionary<string,string> design_style_values = new Dictionary<string, string>();
- //public Dictionary<string,FileLocation> design_iml_locations = new Dictionary<string, FileLocation>();
- public Dictionary<string,FileLocation> design_style_locations = new Dictionary<string, FileLocation>();
-
- internal void design_add_style_location (string memberName, string path, int line, int col) {
- if (design_style_locations.ContainsKey(memberName)){
- Console.WriteLine ("default value localtion already set for {0}{1}.{2}", this.GetType().Name, this.design_id, memberName);
- return;
- }
- design_style_locations.Add(memberName, new FileLocation(path,line,col));
- }
-// internal void design_add_iml_location (string memberName, string path, int line, int col) {
-// if (design_iml_locations.ContainsKey(memberName)){
-// Console.WriteLine ("IML value localtion already set for {0}{1}.{2}", this.GetType().Name, this.design_id, memberName);
-// return;
-// }
-// design_iml_locations.Add(memberName, new FileLocation(path,line,col));
-// }
-
- public virtual bool FindByDesignID(string designID, out GraphicObject go){
- go = null;
- if (this.design_id == designID){
- go = this;
- return true;
- }
- return false;
- }
-
- public string GetIML(){
- XmlDocument doc = new XmlDocument( );
-
- using (StringWriter sw = new StringWriter ()) {
- XmlWriterSettings settings = new XmlWriterSettings {
- Indent = true,
- IndentChars = "\t",
- };
- using (XmlWriter xtw = XmlWriter.Create (sw, settings)) {
- //(1) the xml declaration is recommended, but not mandatory
- XmlDeclaration xmlDeclaration = doc.CreateXmlDeclaration ("1.0", "UTF-8", null);
- doc.InsertBefore (xmlDeclaration, null);
- getIML (doc, (XmlNode)doc);
- doc.WriteTo (xtw);
- }
- this.design_HasChanged = false;
- return sw.ToString ();
- }
- }
-
- public virtual void getIML(XmlDocument doc, XmlNode parentElem) {
- if (this.design_isTGItem)
- return;
-
- XmlElement xe = doc.CreateElement(this.GetType().Name);
-
- foreach (KeyValuePair<string,string> kv in design_iml_values) {
- XmlAttribute xa = doc.CreateAttribute (kv.Key);
- xa.Value = kv.Value;
- xe.Attributes.Append (xa);
- }
-
- parentElem.AppendChild (xe);
- }
- public Surface CreateIcon (int dragIconSize = 32) {
- ImageSurface di = new ImageSurface (Format.Argb32, dragIconSize, dragIconSize);
- using (Context ctx = new Context (di)) {
- double div = Math.Max (LastPaintedSlot.Width, LastPaintedSlot.Height);
- double s = (double)dragIconSize / div;
- ctx.Scale (s, s);
- if (bmp == null)
- this.onDraw (ctx);
- else {
- if (LastPaintedSlot.Width>LastPaintedSlot.Height)
- ctx.SetSourceSurface (bmp, 0, (LastPaintedSlot.Width-LastPaintedSlot.Height)/2);
- else
- ctx.SetSourceSurface (bmp, (LastPaintedSlot.Height-LastPaintedSlot.Width)/2, 0);
- ctx.Paint ();
- }
- }
- return di;
- }
- #endif
-
- #region IDisposable implementation
- protected bool disposed = false;
-
- public void Dispose(){
- Dispose(true);
- GC.SuppressFinalize(this);
- }
- ~GraphicObject(){
- Debug.WriteLine(this.ToString() + " not disposed by user");
- Dispose(false);
- }
- protected virtual void Dispose(bool disposing){
- if (disposed){
- #if DEBUG_DISPOSE
- Debug.WriteLine ("Trying to dispose already disposed obj: {0}", this.ToString());
- #endif
- return;
- }
-
- if (disposing) {
- #if DEBUG_DISPOSE
- Debug.WriteLine ("Disposing: {0}", this.ToString());
- if (IsQueueForRedraw)
- throw new Exception("Trying to dispose an object queued for Redraw: " + this.ToString());
- #endif
-
- unshownPostActions ();
-
- if (!localDataSourceIsNull)
- DataSource = null;
-
- parentRWLock.EnterWriteLock();
- parent = null;
- parentRWLock.ExitWriteLock();
- } else
- Debug.WriteLine ("!!! Finalized by GC: {0}", this.ToString ());
- Clipping?.Dispose ();
- bmp?.Dispose ();
- disposed = true;
- }
- #endregion
-
- internal static ulong currentUid = 0;
- internal ulong uid = 0;
-
- internal bool isPopup = false;
- public GraphicObject focusParent {
- get { return (isPopup ? LogicalParent : parent) as GraphicObject; }
- }
-
- /// <summary>
- /// interface this widget is bound to, this should not be changed once the instance is created
- /// </summary>
- public Interface IFace = null;
-
- /// <summary>
- /// contains the dirty rectangles in the coordinate system of the cache. those dirty zones
- /// are repeated at each cached levels of the tree with correspondig coordinate system. This is done
- /// in a dedicated step of the update between layouting and drawing.
- /// </summary>
- public Region Clipping;
-
- #region IValueChange implementation
- /// <summary>
- /// Raise to notify that the value of a property has changed, the binding system
- /// rely mainly on this event. the member name may not be present in the class, this is
- /// used in **propertyless** bindings, this allow to raise custom named events without needing
- /// to create an new one in the class or a new property.
- /// </summary>
- public event EventHandler<ValueChangeEventArgs> ValueChanged;
- /// <summary>
- /// Helper function to raise the value changed event
- /// </summary>
- public virtual void NotifyValueChanged(string MemberName, object _value)
- {
- //Debug.WriteLine ("Value changed: {0}->{1} = {2}", this, MemberName, _value);
- ValueChanged.Raise(this, new ValueChangeEventArgs(MemberName, _value));
- }
- #endregion
-
- #region CTOR
- /// <summary>
- /// default private parameter less constructor use in instantiators, it should not be used
- /// when creating widget from code because widgets has to be bound to an interface before any other
- /// action.
- /// </summary>
- protected GraphicObject () {
- Clipping = new Region ();
- #if DEBUG
- uid = currentUid;
- currentUid++;
- #endif
- }
- /// <summary>
- /// This constructor **must** be used when creating widget from code.
- ///
- /// When creating new widgets derived from GraphicObject, both parameterless and this constructors are
- /// facultatives, the compiler will create the parameterless one automaticaly if no other one exists.
- /// But if you intend to be able to create instances of the new widget in code and override the constructor
- /// with the Interface parameter, you **must** also provide the override of the parameterless constructor because
- /// compiler will not create it automatically because of the presence of the other one.
- /// </summary>
- /// <param name="iface">Iface.</param>
- public GraphicObject (Interface iface) : this()
- {
- IFace = iface;
- Initialize ();
- }
- #endregion
- //internal bool initialized = false;
- /// <summary>
- /// Initialize this Graphic object instance by setting style and default values and loading template if required
- /// </summary>
- public virtual void Initialize(){
- loadDefaultValues ();
- //initialized = true;
- }
- #region private fields
- LayoutingType registeredLayoutings = LayoutingType.All;
- ILayoutable logicalParent;
- ILayoutable parent;
- string name;
- Fill background = Color.Transparent;
- Fill foreground = Color.White;
- Font font = "droid, 10";
- Measure width, height;
- int left, top;
- double cornerRadius = 0;
- int margin = 0;
- bool focusable = false;
- bool hasFocus = false;
- bool isActive = false;
- bool isHover = false;
- bool mouseRepeat;
- protected bool isVisible = true;
- bool isEnabled = true;
- VerticalAlignment verticalAlignment = VerticalAlignment.Center;
- HorizontalAlignment horizontalAlignment = HorizontalAlignment.Center;
- Size maximumSize = "0,0";
- Size minimumSize = "0,0";
- bool cacheEnabled = false;
- bool clipToClientRect = true;
- protected object dataSource;
- bool rootDataLevel;
- string style;
- object tag;
- bool isDragged;
- bool allowDrag;
- bool allowDrop;
- string tooltip;
- IList<Command> contextCommands;
- #endregion
-
- #region public fields
- /// <summary>
- /// Current size and position computed during layouting pass
- /// </summary>
- public Rectangle Slot = new Rectangle ();
- /// <summary>
- /// keep last slot components for each layouting pass to track
- /// changes and trigger update of other component accordingly
- /// </summary>
- public Rectangle LastSlots;
- /// <summary>
- /// keep last slot painted on screen to clear traces if moved or resized
- /// version to clear effective oldslot if parents have been moved or resized.
- /// IDEA is to add a ScreenCoordinates function that use only lastPaintedSlots
- /// </summary>
- //TODO: we should ensure the whole parsed widget tree is the last painted
- public Rectangle LastPaintedSlot;
- /// <summary>Prevent requeuing multiple times the same widget</summary>
- public bool IsQueueForClipping = false;
- /// <summary>drawing Cache, if null, a redraw is done, cached or not</summary>
- public Surface bmp;
- public bool IsDirty = true;
- /// <summary>
- /// This size is computed on each child' layout changes.
- /// In stacking widget, it is used to compute the remaining space for the stretched
- /// widget inside the stack, which is never added to the contentSize, instead, its size
- /// is deducted from (parent.ClientRectangle - contentSize)
- /// </summary>
- internal Size contentSize;
- #endregion
-
- #region ILayoutable
- [XmlIgnore]public LayoutingType RegisteredLayoutings { get { return registeredLayoutings; } set { registeredLayoutings = value; } }
- //TODO: it would save the recurent cost of a cast in event bubbling if parent type was GraphicObject
- // or we could add to the interface the mouse events
- /// <summary>
- /// Parent in the graphic tree, used for rendering and layouting
- /// </summary>
- [XmlIgnore]public virtual ILayoutable Parent {
- get { return parent; }
- set {
- if (parent == value)
- return;
- DataSourceChangeEventArgs e = new DataSourceChangeEventArgs (parent, value);
-
- parentRWLock.EnterWriteLock();
- parent = value;
- Slot = LastSlots = default(Rectangle);
- parentRWLock.ExitWriteLock();
-
- onParentChanged (this, e);
- }
- }
- [XmlIgnore]public ILayoutable LogicalParent {
- get { return logicalParent == null ? Parent : logicalParent; }
- set {
- if (logicalParent == value)
- return;
- if (logicalParent != null)
- (logicalParent as GraphicObject).DataSourceChanged -= onLogicalParentDataSourceChanged;
- DataSourceChangeEventArgs dsce = new DataSourceChangeEventArgs (LogicalParent, null);
- logicalParent = value;
- dsce.NewDataSource = LogicalParent;
- if (logicalParent != null)
- (logicalParent as GraphicObject).DataSourceChanged += onLogicalParentDataSourceChanged;
- onLogicalParentChanged (this, dsce);
- }
- }
- [XmlIgnore]public virtual Rectangle ClientRectangle {
- get {
- Rectangle cb = Slot.Size;
- cb.Inflate ( - Margin);
- return cb;
- }
- }
- public virtual Rectangle ContextCoordinates(Rectangle r){
- GraphicObject go = Parent as GraphicObject;
- if (go == null)
- return r + Parent.ClientRectangle.Position;
- return go.CacheEnabled ?
- r + Parent.ClientRectangle.Position :
- Parent.ContextCoordinates (r);
- }
- public virtual Rectangle ScreenCoordinates (Rectangle r){
- try {
- return
- Parent.ScreenCoordinates(r) + Parent.getSlot().Position + Parent.ClientRectangle.Position;
- } catch (Exception ex) {
- Debug.WriteLine (ex);
- return default(Rectangle);
- }
- }
- public virtual Rectangle getSlot () { return Slot;}
- #endregion
- public Point ScreenPointToLocal(Point p){
- Point pt = p - ScreenCoordinates(Slot).TopLeft - ClientRectangle.TopLeft;
- if (pt.X < 0)
- pt.X = 0;
- if (pt.Y < 0)
- pt.Y = 0;
- return pt;
- }
-
- #region EVENT HANDLERS
- /// <summary>Occurs when mouse wheel is rolled in this object. It bubbles to the root</summary>
- public event EventHandler<MouseWheelEventArgs> MouseWheelChanged;
- /// <summary>Occurs when mouse button is released in this object. It bubbles to the root</summary>
- public event EventHandler<MouseButtonEventArgs> MouseUp;
- /// <summary>Occurs when mouse button is pressed in this object. It bubbles to the root</summary>
- public event EventHandler<MouseButtonEventArgs> MouseDown;
- /// <summary>Occurs when mouse button has been pressed then relesed in this object. It bubbles to the root</summary>
- public event EventHandler<MouseButtonEventArgs> MouseClick;
- /// <summary>Occurs when mouse button has been pressed then relesed 2 times in this object. It bubbles to the root</summary>
- public event EventHandler<MouseButtonEventArgs> MouseDoubleClick;
- /// <summary>Occurs when mouse mouve in this object. It bubbles to the root</summary>
- public event EventHandler<MouseMoveEventArgs> MouseMove;
- /// <summary>Occurs when mouse enter this object</summary>
- public event EventHandler<MouseMoveEventArgs> MouseEnter;
- /// <summary>Occurs when mouse leave this object</summary>
- public event EventHandler<MouseMoveEventArgs> MouseLeave;
- /// <summary>Occurs when key is pressed when this object is active</summary>
- public event EventHandler<KeyboardKeyEventArgs> KeyDown;
- /// <summary>Occurs when key is released when this object is active</summary>
- public event EventHandler<KeyboardKeyEventArgs> KeyUp;
- /// <summary>Occurs when translated key event occurs in the host when this object is active</summary>
- public event EventHandler<KeyPressEventArgs> KeyPress;
- /// <summary>Occurs when this object received focus</summary>
- public event EventHandler Focused;
- /// <summary>Occurs when this object loose focus</summary>
- public event EventHandler Unfocused;
- /// <summary>Occurs when mouse is over</summary>
- public event EventHandler Hover;
- /// <summary>Occurs when this control is no longer the Hover one</summary>
- public event EventHandler UnHover;
- /// <summary>Occurs when this object loose focus</summary>
- public event EventHandler Enabled;
- /// <summary>Occurs when the enabled state this object is set to false</summary>
- public event EventHandler Disabled;
-
- #region DragAndDrop Events
- public event EventHandler<DragDropEventArgs> StartDrag;
- public event EventHandler<DragDropEventArgs> DragEnter;
- public event EventHandler<DragDropEventArgs> DragLeave;
- public event EventHandler<DragDropEventArgs> EndDrag;
- public event EventHandler<DragDropEventArgs> Drop;
- #endregion
-
- /// <summary>
- /// Occurs when default value and styling are loaded, and for templated control,
- /// template is also loaded. Bindings should be functionnal as well.
- /// </summary>
- public event EventHandler Initialized;
-
- /// <summary>Occurs when one part of the rendering slot changed</summary>
- public event EventHandler<LayoutingEventArgs> LayoutChanged;
- /// <summary>Occurs when DataSource changed</summary>
- public event EventHandler<DataSourceChangeEventArgs> DataSourceChanged;
- /// <summary>Occurs when the parent has changed</summary>
- public event EventHandler<DataSourceChangeEventArgs> ParentChanged;
- /// <summary>Occurs when the logical parent has changed</summary>
- public event EventHandler<DataSourceChangeEventArgs> LogicalParentChanged;
- #endregion
-
- #region public properties
- /// <summary>Random value placeholder</summary>
- [DesignCategory ("Divers")]
- public object Tag {
- get { return tag; }
- set {
- if (tag == value)
- return;
- tag = value;
- NotifyValueChanged ("Tag", tag);
- }
- }
- /// <summary>
- /// If enabled, resulting bitmap of graphic object is cached
- /// speeding up rendering of complex object. Default is enabled.
- /// </summary>
- [DesignCategory ("Behavior")][DefaultValue(true)]
- public virtual bool CacheEnabled {
- get { return cacheEnabled; }
- set {
- if (cacheEnabled == value)
- return;
- cacheEnabled = value;
- NotifyValueChanged ("CacheEnabled", cacheEnabled);
- }
- }
- /// <summary>
- /// If true, rendering of GraphicObject is clipped inside client rectangle
- /// </summary>
- [DesignCategory ("Appearance")][DefaultValue(true)]
- public virtual bool ClipToClientRect {
- get { return clipToClientRect; }
- set {
- if (clipToClientRect == value)
- return;
- clipToClientRect = value;
- NotifyValueChanged ("ClipToClientRect", clipToClientRect);
- this.RegisterForRedraw ();
- }
- }
- #if DEBUG
- [XmlIgnore]public string TreePath {
- get { return this.GetType().Name + uid.ToString (); }
- }
- #endif
- /// <summary>
- /// Name is used in binding to reference other GraphicObjects inside the graphic tree
- /// and by template controls to find special element in their template implementation such
- /// as a container or a group to put children in.
- /// </summary>
- [DesignCategory ("Divers")][DefaultValue(null)]
- public virtual string Name {
- get {
- #if DEBUG
- return string.IsNullOrEmpty(name) ? this.GetType().Name + uid.ToString () : name;
- #else
- return name;
- #endif
- }
- set {
- if (name == value)
- return;
- name = value;
- NotifyValueChanged("Name", name);
- }
- }
- /// <summary>
- /// Vertical alignment inside parent, disabled if height is stretched
- /// or top coordinate is not null
- /// </summary>
- [DesignCategory ("Layout")][DefaultValue(VerticalAlignment.Center)]
- public virtual VerticalAlignment VerticalAlignment {
- get { return verticalAlignment; }
- set {
- if (verticalAlignment == value)
- return;
-
- verticalAlignment = value;
- NotifyValueChanged("VerticalAlignment", verticalAlignment);
- RegisterForLayouting (LayoutingType.Y);
- }
- }
- /// <summary>
- /// Horizontal alignment inside parent, disabled if width is stretched
- /// or left coordinate is not null
- /// </summary>
- [DesignCategory ("Layout")][DefaultValue(HorizontalAlignment.Center)]
- public virtual HorizontalAlignment HorizontalAlignment {
- get { return horizontalAlignment; }
- set {
- if (horizontalAlignment == value)
- return;
- horizontalAlignment = value;
- NotifyValueChanged("HorizontalAlignment", horizontalAlignment);
- RegisterForLayouting (LayoutingType.X);
- }
- }
- /// <summary>
- /// x position inside parent
- /// </summary>
- [DesignCategory ("Layout")][DefaultValue(0)]
- public virtual int Left {
- get { return left; }
- set {
- if (left == value)
- return;
- left = value;
- NotifyValueChanged ("Left", left);
- this.RegisterForLayouting (LayoutingType.X);
- }
- }
- /// <summary>
- /// y position inside parent
- /// </summary>
- [DesignCategory ("Layout")][DefaultValue(0)]
- public virtual int Top {
- get { return top; }
- set {
- if (top == value)
- return;
- top = value;
- NotifyValueChanged ("Top", top);
- this.RegisterForLayouting (LayoutingType.Y);
- }
- }
- /// <summary>
- /// Helper property used to set width and height to fit in one call
- /// </summary>
- [DesignCategory ("Layout")][DefaultValue(false)]
- public virtual bool Fit {
- get { return Width == Measure.Fit && Height == Measure.Fit ? true : false; }
- set {
- if (value == Fit)
- return;
-
- Width = Height = Measure.Fit;
- }
- }
- /// <summary>
- /// Width of this control, by default inherited from parent. May have special values
- /// such as Stretched or Fit. It may be proportionnal or absolute.
- /// </summary>
- [DesignCategory ("Layout")][DefaultValue("Inherit")]
- public virtual Measure Width {
- get {
- return width.Units == Unit.Inherit ?
- Parent is GraphicObject ? (Parent as GraphicObject).WidthPolicy :
- Measure.Stretched : width;
- }
- set {
- if (width == value)
- return;
- if (value.IsFixed) {
- if (value < MinimumSize.Width || (value > MaximumSize.Width && MaximumSize.Width > 0))
- return;
- }
- Measure old = width;
- width = value;
- NotifyValueChanged ("Width", width);
- if (width == Measure.Stretched || old == Measure.Stretched) {
- //NotifyValueChanged ("WidthPolicy", width.Policy);
- //contentSize in Stacks are only update on childLayoutChange, and the single stretched
- //child of the stack is not counted in contentSize, so when changing size policy of a child
- //we should adapt contentSize
- //TODO:check case when child become stretched, and another stretched item already exists.
- GenericStack gs = Parent as GenericStack;
- if (gs != null){ //TODO:check if I should test Group instead
- if (gs.Orientation == Orientation.Horizontal) {
- if (width == Measure.Stretched)
- gs.contentSize.Width -= this.LastSlots.Width;
- else
- gs.contentSize.Width += this.LastSlots.Width;
- }
- }
- }
-
- this.RegisterForLayouting (LayoutingType.Width);
- }
- }
- /// <summary>
- /// Height of this control, by default inherited from parent. May have special values
- /// such as Stretched or Fit. It may be proportionnal or absolute.
- /// </summary>
- [DesignCategory ("Layout")][DefaultValue("Inherit")]
- public virtual Measure Height {
- get {
- return height.Units == Unit.Inherit ?
- Parent is GraphicObject ? (Parent as GraphicObject).HeightPolicy :
- Measure.Stretched : height;
- }
- set {
- if (height == value)
- return;
- if (value.IsFixed) {
- if (value < MinimumSize.Height || (value > MaximumSize.Height && MaximumSize.Height > 0))
- return;
- }
- Measure old = height;
- height = value;
- NotifyValueChanged ("Height", height);
- if (height == Measure.Stretched || old == Measure.Stretched) {
- //NotifyValueChanged ("HeightPolicy", HeightPolicy);
- GenericStack gs = Parent as GenericStack;
- if (gs != null){ //TODO:check if I should test Group instead
- if (gs.Orientation == Orientation.Vertical) {
- if (height == Measure.Stretched)
- gs.contentSize.Height -= this.LastSlots.Height;
- else
- gs.contentSize.Height += this.LastSlots.Height;
- }
- }
- }
-
- this.RegisterForLayouting (LayoutingType.Height);
- }
- }
- /// <summary>
- /// Was Used for binding on dimensions, this property will never hold fixed size, but instead only
- /// Fit or Stretched, **with inherited state implementation, it is not longer used in binding**
- /// </summary>
- [XmlIgnore]public virtual Measure WidthPolicy { get {
- return Width.IsFit ? Measure.Fit : Measure.Stretched; } }
- /// <summary>
- /// Was Used for binding on dimensions, this property will never hold fixed size, but instead only
- /// Fit or Stretched, **with inherited state implementation, it is not longer used in binding**
- /// </summary>
- [XmlIgnore]public virtual Measure HeightPolicy { get {
- return Height.IsFit ? Measure.Fit : Measure.Stretched; } }
- /// <summary>
- /// Indicate that this object may received focus or not, if not focusable all the descendants are
- /// affected.
- /// </summary>
- [DesignCategory ("Behaviour")][DefaultValue(false)]
- public virtual bool Focusable {
- get { return focusable; }
- set {
- if (focusable == value)
- return;
- focusable = value;
- NotifyValueChanged ("Focusable", focusable);
- }
- }
- /// <summary>
- /// True when this control has the focus, only one control per interface may have it.
- /// </summary>
- [XmlIgnore]public virtual bool HasFocus {
- get { return hasFocus; }
- set {
- if (value == hasFocus)
- return;
-
- hasFocus = value;
- if (hasFocus)
- onFocused (this, null);
- else
- onUnfocused (this, null);
- NotifyValueChanged ("HasFocus", hasFocus);
- }
- }
- /// <summary>
- /// true if this control is active, this means that mouse has been pressed in it and not yet released. It could
- /// be used for other two states periferic action.
- /// </summary>
- [XmlIgnore]public virtual bool IsActive {
- get { return isActive; }
- set {
- if (value == isActive)
- return;
-
- isActive = value;
- NotifyValueChanged ("IsActive", isActive);
- }
- }
- /// <summary>
- /// true if this control has the pointer hover
- /// </summary>
- [XmlIgnore]public virtual bool IsHover {
- get { return isHover; }
- set {
- if (value == isHover)
- return;
-
- isHover = value;
-
- if (isHover)
- onHover (this, null);
- else
- onUnHover (this, null);
-
- NotifyValueChanged ("IsHover", isHover);
- }
- }
- /// <summary>
- /// true if holding mouse button down should trigger multiple click events
- /// </summary>
- [DesignCategory ("Behaviour")][DefaultValue(false)]
- public virtual bool MouseRepeat {
- get { return mouseRepeat; }
- set {
- if (mouseRepeat == value)
- return;
- mouseRepeat = value;
- NotifyValueChanged ("MouseRepeat", mouseRepeat);
- }
- }
- bool clearBackground = false;
- /// <summary>
- /// background fill of the control, maybe solid color, gradient, image, or svg
- /// </summary>
- [DesignCategory ("Appearance")][DefaultValue("Transparent")]
- public virtual Fill Background {
- get { return background; }
- set {
- if (background == value)
- return;
- clearBackground = false;
- if (value == null)
- return;
- background = value;
- NotifyValueChanged ("Background", background);
- RegisterForRedraw ();
- if (background is SolidColor) {
- if ((Background as SolidColor).Equals (Color.Clear))
- clearBackground = true;
- }
- }
- }
- /// <summary>
- /// Foreground fill of the control, usage may be different among derived controls
- /// </summary>
- [DesignCategory ("Appearance")][DefaultValue("White")]
- public virtual Fill Foreground {
- get { return foreground; }
- set {
- if (foreground == value)
- return;
- foreground = value;
- NotifyValueChanged ("Foreground", foreground);
- RegisterForRedraw ();
- }
- }
- /// <summary>
- /// Font being used in many controls, it is defined in the base GraphicObject class.
- /// </summary>
- [DesignCategory ("Appearance")][DefaultValue("sans,10")]
- public virtual Font Font {
- get { return font; }
- set {
- if (value == font)
- return;
- font = value;
- NotifyValueChanged ("Font", font);
- RegisterForGraphicUpdate ();
- }
- }
- /// <summary>
- /// to get rounded corners
- /// </summary>
- [DesignCategory ("Appearance")][DefaultValue(0.0)]
- public virtual double CornerRadius {
- get { return cornerRadius; }
- set {
- if (value == cornerRadius)
- return;
- cornerRadius = value;
- NotifyValueChanged ("CornerRadius", cornerRadius);
- RegisterForRedraw ();
- }
- }
- /// <summary>
- /// This is a single integer for the 4 direction, a gap between the control and it's container,
- /// by default it is filled with the background.
- /// </summary>
- [DesignCategory ("Layout")][DefaultValue(0)]
- public virtual int Margin {
- get { return margin; }
- set {
- if (value == margin)
- return;
- margin = value;
- NotifyValueChanged ("Margin", margin);
- RegisterForGraphicUpdate ();
- }
- }
- /// <summary>
- /// set the visible state of the control, invisible controls does reserve space in the layouting system.
- /// </summary>
- [DesignCategory ("Appearance")][DefaultValue(true)]
- public virtual bool Visible {
- get { return isVisible; }
- set {
- if (value == isVisible)
- return;
-
- isVisible = value;
-
- RegisterForLayouting (LayoutingType.Sizing);
-
- if (!isVisible)
- unshownPostActions ();
-
- NotifyValueChanged ("Visible", isVisible);
- }
- }
- /// <summary>
- /// get or set the enabled state, disabling a control will affect focuability and
- /// also it's rendering which will be grayed
- /// </summary>
- [DesignCategory ("Behaviour")][DefaultValue(true)]
- public virtual bool IsEnabled {
- get { return isEnabled; }
- set {
- if (value == isEnabled)
- return;
-
- isEnabled = value;
-
- if (isEnabled)
- onEnable (this, null);
- else
- onDisable (this, null);
-
- NotifyValueChanged ("IsEnabled", isEnabled);
- RegisterForRedraw ();
- }
- }
- /// <summary>
- /// Minimal width and height for this control
- /// </summary>
- [DesignCategory ("Layout")][DefaultValue("1,1")]
- public virtual Size MinimumSize {
- get { return minimumSize; }
- set {
- if (value == minimumSize)
- return;
-
- minimumSize = value;
-
- NotifyValueChanged ("MinimumSize", minimumSize);
- RegisterForLayouting (LayoutingType.Sizing);
- }
- }
- /// <summary>
- /// Maximum width and height for this control, unlimited if null.
- /// </summary>
- [DesignCategory ("Layout")][DefaultValue("0,0")]
- public virtual Size MaximumSize {
- get { return maximumSize; }
- set {
- if (value == maximumSize)
- return;
-
- maximumSize = value;
-
- NotifyValueChanged ("MaximumSize", maximumSize);
- RegisterForLayouting (LayoutingType.Sizing);
- }
- }
- /// <summary>
- /// Seek first logical tree upward if logicalParent is set, or seek graphic tree for
- /// a not null dataSource that will be active for all descendants having dataSource=null
- /// </summary>
- [DesignCategory ("Data")]
- public virtual object DataSource {
- set {
- if (DataSource == value)
- return;
-
- DataSourceChangeEventArgs dse = new DataSourceChangeEventArgs (DataSource, null);
- dataSource = value;
- dse.NewDataSource = DataSource;
-
- if (dse.NewDataSource == dse.OldDataSource)
- return;
-
- if (value != null)
- rootDataLevel = true;
-
- lock (IFace.LayoutMutex) {
- OnDataSourceChanged (this, dse);
- NotifyValueChanged ("DataSource", DataSource);
- }
- }
- get {
- return rootDataLevel ? dataSource : dataSource == null ?
- LogicalParent == null ? null :
- LogicalParent is GraphicObject ? (LogicalParent as GraphicObject).DataSource : null :
- dataSource;
- }
- }
- /// <summary>
- /// If true, rendering of GraphicObject is clipped inside client rectangle
- /// </summary>
- [DesignCategory ("Data")][DefaultValue(false)]
- public virtual bool RootDataLevel {
- get { return rootDataLevel; }
- set {
- if (rootDataLevel == value)
- return;
- rootDataLevel = value;
- NotifyValueChanged ("RootDataLevel", rootDataLevel);
- this.RegisterForRedraw ();
- }
- }
- protected virtual void onLogicalParentDataSourceChanged(object sender, DataSourceChangeEventArgs e){
- if (localDataSourceIsNull)
- OnDataSourceChanged (this, e);
- }
- internal bool localDataSourceIsNull { get { return dataSource == null; } }
- public bool localLogicalParentIsNull { get { return logicalParent == null; } }
-
- public virtual void OnDataSourceChanged(object sender, DataSourceChangeEventArgs e){
- DataSourceChanged.Raise (this, e);
- #if DEBUG_BINDING
- Debug.WriteLine("New DataSource for => {0} \n\t{1}=>{2}", this.ToString(),e.OldDataSource,e.NewDataSource);
- #endif
- }
- /// <summary>
- /// Style key to use for this control
- /// </summary>
- [DesignCategory ("Appearance")]
- public virtual string Style {
- get { return style; }
- set {
- if (value == style)
- return;
-
- style = value;
-
- NotifyValueChanged ("Style", style);
- }
- }
- [DesignCategory ("Divers")]
- public virtual string Tooltip {
- get { return tooltip; }
- set {
- if (tooltip == value)
- return;
- tooltip = value;
- NotifyValueChanged("Tooltip", tooltip);
- }
- }
- [DesignCategory ("Divers")]
- public IList<Command> ContextCommands {
- get { return contextCommands; }
- set {
- if (contextCommands == value)
- return;
- contextCommands = value;
- NotifyValueChanged("ContextCommands", contextCommands);
- }
- }
- #endregion
-
- #region Default and Style Values loading
- /// <summary> Loads the default values from XML attributes default </summary>
- public void loadDefaultValues()
- {
-// #if DEBUG_LOAD
-// Debug.WriteLine ("LoadDefValues for " + this.ToString ());
-// #endif
-
- Type thisType = this.GetType ();
-
- if (!string.IsNullOrEmpty (Style)) {
- if (IFace.DefaultValuesLoader.ContainsKey (Style)) {
- IFace.DefaultValuesLoader [Style] (this);
- onInitialized (this, null);
- return;
- }
- } else if (IFace.DefaultValuesLoader.ContainsKey (thisType.FullName)) {
- IFace.DefaultValuesLoader [thisType.FullName] (this);
- onInitialized (this, null);
- return;
- } else if (IFace.DefaultValuesLoader.ContainsKey (thisType.Name)) {
- IFace.DefaultValuesLoader [thisType.Name] (this);
- onInitialized (this, null);
- return;
- }
-
- List<Style> styling = new List<Style>();
-
- //Search for a style matching :
- //1: Full class name, with full namespace
- //2: class name
- //3: style may have been registered with their ressource ID minus .style extention
- // those files being placed in a Styles folder
- string styleKey = Style;
- if (!string.IsNullOrEmpty (Style)) {
- if (IFace.Styling.ContainsKey (Style)) {
- styling.Add (IFace.Styling [Style]);
- }
- }
- if (IFace.Styling.ContainsKey (thisType.FullName)) {
- styling.Add (IFace.Styling [thisType.FullName]);
- if (string.IsNullOrEmpty (styleKey))
- styleKey = thisType.FullName;
- }
- if (IFace.Styling.ContainsKey (thisType.Name)) {
- styling.Add (IFace.Styling [thisType.Name]);
- if (string.IsNullOrEmpty (styleKey))
- styleKey = thisType.Name;
- }
-
- if (string.IsNullOrEmpty (styleKey))
- styleKey = thisType.FullName;
-
- //Reflexion being very slow compared to dyn method or delegates,
- //I compile the initial values coded in the CustomAttribs of the class,
- //all other instance of this type would not longer use reflexion to init properly
- //but will fetch the dynamic initialisation method compiled for this precise type
- //TODO:measure speed gain.
- #region Delfault values Loading dynamic compilation
- DynamicMethod dm = null;
- ILGenerator il = null;
-
- dm = new DynamicMethod("dyn_loadDefValues",
- MethodAttributes.Family | MethodAttributes.FamANDAssem | MethodAttributes.NewSlot,
- CallingConventions.Standard,
- typeof(void),new Type[] {CompilerServices.TObject},thisType,true);
-
- il = dm.GetILGenerator(256);
- il.DeclareLocal(CompilerServices.TObject);
- il.Emit(OpCodes.Nop);
- //set local GraphicObject to root object passed as 1st argument
- il.Emit (OpCodes.Ldarg_0);
- il.Emit (OpCodes.Stloc_0);
-
- foreach (EventInfo ei in thisType.GetEvents(BindingFlags.Public | BindingFlags.Instance)) {
- string expression;
- if (!getDefaultEvent(ei, styling, out expression))
- continue;
- //TODO:dynEventHandler could be cached somewhere, maybe a style instanciator class holding the styling delegate and bound to it.
- foreach (string exp in CompilerServices.splitOnSemiColumnOutsideAccolades(expression)) {
- string trimed = exp.Trim();
- if (trimed.StartsWith ("{", StringComparison.OrdinalIgnoreCase)){
- il.Emit (OpCodes.Ldloc_0);//load this as 1st arg of event Add
-
- //push eventInfo as 1st arg of compile
- il.Emit (OpCodes.Ldloc_0);
- il.Emit (OpCodes.Call, CompilerServices.miGetType);
- il.Emit (OpCodes.Ldstr, ei.Name);//push event name
- il.Emit (OpCodes.Call, CompilerServices.miGetEvent);
- //push expression as 2nd arg of compile
- il.Emit (OpCodes.Ldstr, trimed.Substring (1, trimed.Length - 2));
- //push null as 3rd arg, currentNode, not known when instanciing
- il.Emit (OpCodes.Ldnull);
- il.Emit (OpCodes.Callvirt, CompilerServices.miCompileDynEventHandler);
- il.Emit (OpCodes.Castclass, ei.EventHandlerType);
- il.Emit (OpCodes.Callvirt, ei.AddMethod);
- }else
- Debug.WriteLine("error in styling, event not handled : " + trimed);
- }
- }
-
- foreach (PropertyInfo pi in thisType.GetProperties(BindingFlags.Public | BindingFlags.Instance)) {
- if (pi.GetSetMethod () == null)
- continue;
- XmlIgnoreAttribute xia = (XmlIgnoreAttribute)pi.GetCustomAttribute (typeof(XmlIgnoreAttribute));
- if (xia != null)
- continue;
-
- object defaultValue;
- string name = "";
- XmlAttributeAttribute xaa = (XmlAttributeAttribute)pi.GetCustomAttribute (typeof(XmlAttributeAttribute));
- if (xaa != null) {
- if (string.IsNullOrEmpty (xaa.AttributeName))
- name = pi.Name;
- else
- name = xaa.AttributeName;
- }else
- name = pi.Name;
-
- int styleIndex = -1;
- if (styling.Count > 0){
- for (int i = 0; i < styling.Count; i++) {
- if (styling[i].ContainsKey (name)){
- styleIndex = i;
- break;
- }
- }
- }
- if (styleIndex >= 0){
- if (pi.PropertyType.IsEnum)//maybe should be in parser..
- defaultValue = Enum.Parse(pi.PropertyType, (string)styling[styleIndex] [name], true);
- else
- defaultValue = styling[styleIndex] [name];
-
- #if DESIGN_MODE
- if (defaultValue != null){
- FileLocation fl = styling[styleIndex].Locations[name];
- il.Emit (OpCodes.Ldloc_0);
- il.Emit (OpCodes.Ldstr, name);
- il.Emit (OpCodes.Ldstr, fl.FilePath);
- il.Emit (OpCodes.Ldc_I4, fl.Line);
- il.Emit (OpCodes.Ldc_I4, fl.Column);
- il.Emit (OpCodes.Call, miDesignAddDefLoc);
-
- il.Emit (OpCodes.Ldloc_0);
- il.Emit (OpCodes.Ldfld, typeof(GraphicObject).GetField("design_style_values"));
- il.Emit (OpCodes.Ldstr, name);
- il.Emit (OpCodes.Ldstr, defaultValue.ToString());
- il.Emit (OpCodes.Call, CompilerServices.miDicStrStrAdd);
- }
- #endif
-
- }else {
- DefaultValueAttribute dv = (DefaultValueAttribute)pi.GetCustomAttribute (typeof (DefaultValueAttribute));
- if (dv == null)
- continue;
- defaultValue = dv.Value;
- }
-
- CompilerServices.EmitSetValue (il, pi, defaultValue);
- }
- il.Emit(OpCodes.Ret);
- #endregion
-
- try {
- IFace.DefaultValuesLoader[styleKey] = (Interface.LoaderInvoker)dm.CreateDelegate(typeof(Interface.LoaderInvoker));
- IFace.DefaultValuesLoader[styleKey] (this);
- } catch (Exception ex) {
- throw new Exception ("Error applying style <" + styleKey + ">:", ex);
- }
- onInitialized (this, null);
- }
- protected virtual void onInitialized (object sender, EventArgs e){
- Initialized.Raise(sender, e);
- }
- bool getDefaultEvent(EventInfo ei, List<Style> styling,
- out string expression){
- expression = "";
- if (styling.Count > 0){
- for (int i = 0; i < styling.Count; i++) {
- if (styling[i].ContainsKey (ei.Name)){
- expression = (string)styling[i] [ei.Name];
- return true;
- }
- }
- }
- return false;
- }
- #endregion
-
- public virtual GraphicObject FindByName(string nameToFind){
- return string.Equals(nameToFind, name, StringComparison.Ordinal) ? this : null;
- }
- public virtual bool Contains(GraphicObject goToFind){
- return false;
- }
- /// <summary>
- /// return true if this is contained inside go
- /// </summary>
- public bool IsOrIsInside(GraphicObject go){
- if (this == go)
- return true;
- ILayoutable p = this.Parent;
- while (p != null) {
- if (p == go)
- return true;
- p = p.Parent;
- }
- return false;
- }
-
- #region Drag&Drop
- [DesignCategory ("DragAndDrop")][DefaultValue(false)]
- public virtual bool AllowDrag {
- get { return allowDrag; }
- set {
- if (allowDrag == value)
- return;
- allowDrag = value;
- NotifyValueChanged ("AllowDrag", allowDrag);
- }
- }
- [DesignCategory ("DragAndDrop")][DefaultValue(false)]
- public virtual bool AllowDrop {
- get { return allowDrop; }
- set {
- if (allowDrop == value)
- return;
- allowDrop = value;
- NotifyValueChanged ("AllowDrop", allowDrop);
- }
- }
-
-// public List<Type> AllowedDroppedTypes;
-// public void AddAllowedDroppedType (Type newType){
-// if (AllowedDroppedTypes == null)
-// AllowedDroppedTypes = new List<Type> ();
-// AllowedDroppedTypes.Add (newType);
-// NotifyValueChanged ("AllowDrop", AllowDrop);
-// }
-// [XmlIgnore]public virtual bool AllowDrop {
-// get { return AllowedDroppedTypes?.Count>0; }
-// }
- [XmlIgnore]public virtual bool IsDragged {
- get { return isDragged; }
- set {
- if (isDragged == value)
- return;
- isDragged = value;
-
- NotifyValueChanged ("IsDragged", IsDragged);
- }
- }
- /// <summary>
- /// fired when drag and drop operation start
- /// </summary>
- protected virtual void onStartDrag (object sender, DragDropEventArgs e){
- IFace.HoverWidget = null;
- IsDragged = true;
- StartDrag.Raise (this, e);
- #if DEBUG_DRAGNDROP
- Debug.WriteLine(this.ToString() + " : START DRAG => " + e.ToString());
- #endif
- }
- /// <summary>
- /// Occured when dragging ends without dropping
- /// </summary>
- protected virtual void onEndDrag (object sender, DragDropEventArgs e){
- IsDragged = false;
- EndDrag.Raise (this, e);
- #if DEBUG_DRAGNDROP
- Debug.WriteLine(this.ToString() + " : END DRAG => " + e.ToString());
- #endif
- }
- protected virtual void onDragEnter (object sender, DragDropEventArgs e){
- e.DropTarget = this;
- DragEnter.Raise (this, e);
- #if DEBUG_DRAGNDROP
- Debug.WriteLine(this.ToString() + " : DRAG Enter => " + e.ToString());
- #endif
- }
- protected virtual void onDragLeave (object sender, DragDropEventArgs e){
- e.DropTarget = null;
- DragLeave.Raise (this, e);
- #if DEBUG_DRAGNDROP
- Debug.WriteLine(this.ToString() + " : DRAG Leave => " + e.ToString());
- #endif
- }
- protected virtual void onDrop (object sender, DragDropEventArgs e){
- IsDragged = false;
- Drop.Raise (this, e);
- //e.DropTarget.onDragLeave (this, e);//raise drag leave in target
- #if DEBUG_DRAGNDROP
- Debug.WriteLine(this.ToString() + " : DROP => " + e.ToString());
- #endif
- }
- public bool IsDropTarget {
- get { return IFace.DragAndDropOperation?.DropTarget == this; }
- }
-
- #endregion
-
- #region Queuing
- /// <summary>
- /// Register old and new slot for clipping
- /// </summary>
- public virtual void ClippingRegistration(){
- #if DEBUG_UPDATE
- Debug.WriteLine (string.Format("ClippingRegistration -> {0}", this.ToString ()));
- #endif
- parentRWLock.EnterReadLock ();
- if (parent != null) {
- Parent.RegisterClip (LastPaintedSlot);
- Parent.RegisterClip (Slot);
- }
- parentRWLock.ExitReadLock ();
- }
- /// <summary>
- /// Add clip rectangle to this.clipping and propagate up to root
- /// </summary>
- /// <param name="clip">Clip rectangle</param>
- public virtual void RegisterClip(Rectangle clip){
- #if DEBUG_UPDATE
- Debug.WriteLine (string.Format("RegisterClip -> {1}:{0}", clip, this.ToString ()));
- #endif
- Rectangle r = clip + ClientRectangle.Position;
- if (CacheEnabled && !IsDirty)
- Clipping.UnionRectangle (r);
- if (Parent == null)
- return;
- GraphicObject p = Parent as GraphicObject;
- if (p?.IsDirty == true && p?.CacheEnabled == true)
- return;
- Parent.RegisterClip (r + Slot.Position);
- }
- /// <summary> Full update, taking care of sizing policy </summary>
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public void RegisterForGraphicUpdate ()
- {
- #if DEBUG_UPDATE
- Debug.WriteLine (string.Format("RegisterForGraphicUpdate (IsDirty set)-> {0}", this.ToString ()));
- #endif
- IsDirty = true;
- if (Width.IsFit || Height.IsFit)
- RegisterForLayouting (LayoutingType.Sizing);
- else if (RegisteredLayoutings == LayoutingType.None)
- IFace.EnqueueForRepaint (this);
- }
- /// <summary> query an update of the content, a redraw </summary>
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public void RegisterForRedraw ()
- {
- #if DEBUG_UPDATE
- Debug.WriteLine (string.Format("RegisterForRedraw (IsDirty set)-> {0}", this.ToString ()));
- #endif
- IsDirty = true;
- if (RegisteredLayoutings == LayoutingType.None)
- IFace.EnqueueForRepaint (this);
- }
- #endregion
-
- #region Layouting
-
- /// <summary> return size of content + margins </summary>
- protected virtual int measureRawSize (LayoutingType lt) {
- return lt == LayoutingType.Width ?
- contentSize.Width + 2 * Margin: contentSize.Height + 2 * Margin;
- }
- /// <summary> By default in groups, LayoutingType.ArrangeChildren is reset </summary>
- public virtual void ChildrenLayoutingConstraints(ref LayoutingType layoutType){
- }
- public virtual bool ArrangeChildren { get { return false; } }
- public virtual void RegisterForLayouting(LayoutingType layoutType){
- if (Parent == null)
- return;
- lock (IFace.LayoutMutex) {
- //prevent queueing same LayoutingType for this
- layoutType &= (~RegisteredLayoutings);
-
- if (layoutType == LayoutingType.None)
- return;
- //dont set position for stretched item
- if (Width == Measure.Stretched)
- layoutType &= (~LayoutingType.X);
- if (Height == Measure.Stretched)
- layoutType &= (~LayoutingType.Y);
-
- if (!ArrangeChildren)
- layoutType &= (~LayoutingType.ArrangeChildren);
-
- //apply constraints depending on parent type
- if (Parent is GraphicObject)
- (Parent as GraphicObject).ChildrenLayoutingConstraints (ref layoutType);
-
-// //prevent queueing same LayoutingType for this
-// layoutType &= (~RegisteredLayoutings);
-
- if (layoutType == LayoutingType.None)
- return;
-
- //enqueue LQI LayoutingTypes separately
- if (layoutType.HasFlag (LayoutingType.Width))
- IFace.LayoutingQueue.Enqueue (new LayoutingQueueItem (LayoutingType.Width, this));
- if (layoutType.HasFlag (LayoutingType.Height))
- IFace.LayoutingQueue.Enqueue (new LayoutingQueueItem (LayoutingType.Height, this));
- if (layoutType.HasFlag (LayoutingType.X))
- IFace.LayoutingQueue.Enqueue (new LayoutingQueueItem (LayoutingType.X, this));
- if (layoutType.HasFlag (LayoutingType.Y))
- IFace.LayoutingQueue.Enqueue (new LayoutingQueueItem (LayoutingType.Y, this));
- if (layoutType.HasFlag (LayoutingType.ArrangeChildren))
- IFace.LayoutingQueue.Enqueue (new LayoutingQueueItem (LayoutingType.ArrangeChildren, this));
- }
- }
-
- /// <summary> trigger dependant sizing component update </summary>
- public virtual void OnLayoutChanges(LayoutingType layoutType)
- {
- switch (layoutType) {
- case LayoutingType.Width:
- RegisterForLayouting (LayoutingType.X);
- break;
- case LayoutingType.Height:
- RegisterForLayouting (LayoutingType.Y);
- break;
- }
- LayoutChanged.Raise (this, new LayoutingEventArgs (layoutType));
- }
- internal protected void raiseLayoutChanged(LayoutingEventArgs e){
- LayoutChanged.Raise (this, e);
- }
- /// <summary> Update layout component only one at a time, this is where the computation of alignement
- /// and size take place.
- /// The redrawing will only be triggered if final slot size has changed </summary>
- /// <returns><c>true</c>, if layouting was possible, <c>false</c> if conditions were not
- /// met and LQI has to be re-queued</returns>
- public virtual bool UpdateLayout (LayoutingType layoutType)
- {
- #if DEBUG_UPDATE
- Debug.WriteLine (string.Format("UpdateLayout ({1})-> {0}", this.ToString (), layoutType));
- #endif
- //unset bit, it would be reset if LQI is re-queued
- registeredLayoutings &= (~layoutType);
-
- switch (layoutType) {
- case LayoutingType.X:
- if (Left == 0) {
-
- if (Parent.RegisteredLayoutings.HasFlag (LayoutingType.Width) ||
- RegisteredLayoutings.HasFlag (LayoutingType.Width))
- return false;
-
- switch (HorizontalAlignment) {
- case HorizontalAlignment.Left:
- Slot.X = 0;
- break;
- case HorizontalAlignment.Right:
- Slot.X = Parent.ClientRectangle.Width - Slot.Width;
- break;
- case HorizontalAlignment.Center:
- Slot.X = Parent.ClientRectangle.Width / 2 - Slot.Width / 2;
- break;
- }
- } else
- Slot.X = Left;
-
- if (LastSlots.X == Slot.X)
- break;
-
- IsDirty = true;
-
- OnLayoutChanges (layoutType);
-
- LastSlots.X = Slot.X;
- break;
- case LayoutingType.Y:
- if (Top == 0) {
-
- if (Parent.RegisteredLayoutings.HasFlag (LayoutingType.Height) ||
- RegisteredLayoutings.HasFlag (LayoutingType.Height))
- return false;
-
- switch (VerticalAlignment) {
- case VerticalAlignment.Top://this could be processed even if parent Height is not known
- Slot.Y = 0;
- break;
- case VerticalAlignment.Bottom:
- Slot.Y = Parent.ClientRectangle.Height - Slot.Height;
- break;
- case VerticalAlignment.Center:
- Slot.Y = Parent.ClientRectangle.Height / 2 - Slot.Height / 2;
- break;
- }
- } else
- Slot.Y = Top;
-
- if (LastSlots.Y == Slot.Y)
- break;
-
- IsDirty = true;
-
- OnLayoutChanges (layoutType);
-
- LastSlots.Y = Slot.Y;
- break;
- case LayoutingType.Width:
- if (Visible) {
- if (Width.IsFixed)
- Slot.Width = Width;
- else if (Width == Measure.Fit) {
- Slot.Width = measureRawSize (LayoutingType.Width);
- } else if (Parent.RegisteredLayoutings.HasFlag (LayoutingType.Width))
- return false;
- else if (Width == Measure.Stretched)
- Slot.Width = Parent.ClientRectangle.Width;
- else
- Slot.Width = (int)Math.Round ((double)(Parent.ClientRectangle.Width * Width) / 100.0);
-
- if (Slot.Width < 0)
- return false;
-
- //size constrain
- if (Slot.Width < MinimumSize.Width) {
- Slot.Width = MinimumSize.Width;
- //NotifyValueChanged ("WidthPolicy", Measure.Stretched);
- } else if (Slot.Width > MaximumSize.Width && MaximumSize.Width > 0) {
- Slot.Width = MaximumSize.Width;
- //NotifyValueChanged ("WidthPolicy", Measure.Stretched);
- }
- } else
- Slot.Width = 0;
-
- if (LastSlots.Width == Slot.Width)
- break;
-
- IsDirty = true;
-
- OnLayoutChanges (layoutType);
-
- LastSlots.Width = Slot.Width;
- break;
- case LayoutingType.Height:
- if (Visible) {
- if (Height.IsFixed)
- Slot.Height = Height;
- else if (Height == Measure.Fit) {
- Slot.Height = measureRawSize (LayoutingType.Height);
- } else if (Parent.RegisteredLayoutings.HasFlag (LayoutingType.Height))
- return false;
- else if (Height == Measure.Stretched)
- Slot.Height = Parent.ClientRectangle.Height;
- else
- Slot.Height = (int)Math.Round ((double)(Parent.ClientRectangle.Height * Height) / 100.0);
-
- if (Slot.Height < 0)
- return false;
-
- //size constrain
- if (Slot.Height < MinimumSize.Height) {
- Slot.Height = MinimumSize.Height;
- //NotifyValueChanged ("HeightPolicy", Measure.Stretched);
- } else if (Slot.Height > MaximumSize.Height && MaximumSize.Height > 0) {
- Slot.Height = MaximumSize.Height;
- //NotifyValueChanged ("HeightPolicy", Measure.Stretched);
- }
- } else
- Slot.Height = 0;
-
- if (LastSlots.Height == Slot.Height)
- break;
-
- IsDirty = true;
-
- OnLayoutChanges (layoutType);
-
- LastSlots.Height = Slot.Height;
- break;
- }
-
- //if no layouting remains in queue for item, registre for redraw
- if (this.registeredLayoutings == LayoutingType.None && IsDirty)
- IFace.EnqueueForRepaint (this);
-
- return true;
- }
- #endregion
-
- #region Rendering
- /// <summary> This is the common overridable drawing routine to create new widget </summary>
- protected virtual void onDraw(Context gr)
- {
- #if DEBUG_UPDATE
- Debug.WriteLine (string.Format("OnDraw -> {0}", this.ToString ()));
- #endif
-
- Rectangle rBack = new Rectangle (Slot.Size);
-
- Background.SetAsSource (gr, rBack);
- CairoHelpers.CairoRectangle (gr, rBack, cornerRadius);
- gr.Fill ();
- }
-
- /// <summary>
- /// Internal drawing context creation on a cached surface limited to slot size
- /// this trigger the effective drawing routine </summary>
- protected virtual void RecreateCache ()
- {
- #if DEBUG_UPDATE
- Debug.WriteLine (string.Format("RecreateCache -> {0}", this.ToString ()));
- #endif
- IsDirty = false;
- if (bmp != null)
- bmp.Dispose ();
- bmp = new ImageSurface (Format.Argb32, Slot.Width, Slot.Height);
- using (Context gr = new Context (bmp)) {
- gr.Antialias = Interface.Antialias;
- onDraw (gr);
- }
- bmp.Flush ();
- }
- protected virtual void UpdateCache(Context ctx){
- #if DEBUG_UPDATE
- Debug.WriteLine (string.Format("UpdateCache -> {0}", this.ToString ()));
- #endif
- Rectangle rb = Slot + Parent.ClientRectangle.Position;
- if (clearBackground) {
- ctx.Save ();
- ctx.Operator = Operator.Clear;
- ctx.Rectangle (rb);
- ctx.Fill ();
- ctx.Restore ();
- }
- ctx.SetSourceSurface (bmp, rb.X, rb.Y);
- ctx.Paint ();
- Clipping.Dispose ();
- Clipping = new Region ();
- }
- /// <summary> Chained painting routine on the parent context of the actual cached version
- /// of the widget </summary>
- public virtual void Paint (ref Context ctx)
- {
- #if DEBUG_UPDATE
- Debug.WriteLine (string.Format("Paint -> {0}", this.ToString ()));
- #endif
- //TODO:this test should not be necessary
- if (Slot.Height < 0 || Slot.Width < 0 || parent == null)
- return;
- lock (this) {
- if (cacheEnabled) {
- if (Slot.Width > Interface.MaxCacheSize || Slot.Height > Interface.MaxCacheSize)
- cacheEnabled = false;
- }
-
- if (cacheEnabled) {
- if (IsDirty)
- RecreateCache ();
-
- UpdateCache (ctx);
- if (!isEnabled)
- paintDisabled (ctx, Slot + Parent.ClientRectangle.Position);
- } else {
- Rectangle rb = Slot + Parent.ClientRectangle.Position;
- ctx.Save ();
-
- ctx.Translate (rb.X, rb.Y);
-
- onDraw (ctx);
- if (!isEnabled)
- paintDisabled (ctx, Slot);
-
- ctx.Restore ();
- }
- LastPaintedSlot = Slot;
- }
- }
- void paintDisabled(Context gr, Rectangle rb){
- gr.Operator = Operator.Xor;
- gr.SetSourceRGBA (0.6, 0.6, 0.6, 0.3);
- gr.Rectangle (rb);
- gr.Fill ();
- gr.Operator = Operator.Over;
- }
- #endregion
-
- #region Keyboard handling
- public virtual void onKeyDown(object sender, KeyboardKeyEventArgs e){
- KeyDown.Raise (sender, e);
- }
- public virtual void onKeyUp(object sender, KeyboardKeyEventArgs e){
- KeyUp.Raise (sender, e);
- }
- public virtual void onKeyPress(object sender, KeyPressEventArgs e){
- KeyPress.Raise (sender, e);
- }
- #endregion
-
- #region Mouse handling
- /// <summary>
- /// Recursive local coordinate point test.
- /// After test on parent, point m is in local coord system.
- /// </summary>
- /// <returns>return true, if point is in the bounds of this control</returns>
- /// <param name="m">by ref point to test, init value is not kept</param>
- public virtual bool PointIsIn(ref Point m)
- {
- if (!(Visible & isEnabled)||IsDragged)
- return false;
- if (!parent.PointIsIn(ref m))
- return false;
- m -= (parent.getSlot().Position + parent.ClientRectangle.Position) ;
- return Slot.ContainsOrIsEqual (m);
- }
- public virtual bool MouseIsIn(Point m)
- {
- return (!(Visible & isEnabled)||IsDragged) ? false : PointIsIn (ref m);
- }
- public virtual void checkHoverWidget(MouseMoveEventArgs e)
- {
- if (IFace.HoverWidget != this) {
- IFace.HoverWidget = this;
- onMouseEnter (this, e);
- }
-
- //this.onMouseMove (this, e);//without this, window border doesn't work, should be removed
- }
- public virtual void onMouseMove(object sender, MouseMoveEventArgs e)
- {
- if (AllowDrag & HasFocus & e.Mouse.LeftButton == ButtonState.Pressed) {
- if (IFace.DragAndDropOperation == null) {
- IFace.DragAndDropOperation = new DragDropEventArgs (this);
- onStartDrag (this, IFace.DragAndDropOperation);
- }
- }
-
- //dont bubble event if dragged, mouse move is routed directely from iface
- //to let other control behind have mouse entering
- if (isDragged)
- return;
-
- //bubble event to the top
- GraphicObject p = focusParent;
- if (p != null)
- p.onMouseMove(sender,e);
-
- MouseMove.Raise (this, e);
- }
- public virtual void onMouseDown(object sender, MouseButtonEventArgs e){
- #if DEBUG_FOCUS
- Debug.WriteLine("MOUSE DOWN => " + this.ToString());
- #endif
-
- if (IFace.ActiveWidget == null)
- IFace.ActiveWidget = this;
- if (this.Focusable && !Interface.FocusOnHover) {
- BubblingMouseButtonEventArg be = e as BubblingMouseButtonEventArg;
- if (be.Focused == null) {
- be.Focused = this;
- IFace.FocusedWidget = this;
- if (e.Button == MouseButton.Right && this.ContextCommands != null)
- IFace.ShowContextMenu (this);
- }
- }
- //bubble event to the top
- GraphicObject p = focusParent;
- if (p != null)
- p.onMouseDown(sender,e);
-
- MouseDown.Raise (this, e);
- }
- public virtual void onMouseUp(object sender, MouseButtonEventArgs e){
- #if DEBUG_FOCUS
- Debug.WriteLine("MOUSE UP => " + this.ToString());
- #endif
-
- if (IFace.DragAndDropOperation != null){
- if (IFace.DragAndDropOperation.DragSource == this) {
- if (IFace.DragAndDropOperation.DropTarget != null)
- onDrop (this, IFace.DragAndDropOperation);
- else
- onEndDrag (this, IFace.DragAndDropOperation);
- IFace.DragAndDropOperation = null;
- }
- }
-
- //bubble event to the top
- GraphicObject p = focusParent;
- if (p != null)
- p.onMouseUp(sender,e);
-
- MouseUp.Raise (this, e);
- }
- public virtual void onMouseClick(object sender, MouseButtonEventArgs e){
- #if DEBUG_FOCUS
- Debug.WriteLine("CLICK => " + this.ToString());
- #endif
- GraphicObject p = focusParent;
- if (p != null)
- p.onMouseClick(sender,e);
- MouseClick.Raise (this, e);
- }
- public virtual void onMouseDoubleClick(object sender, MouseButtonEventArgs e){
- #if DEBUG_FOCUS
- Debug.WriteLine("DOUBLE CLICK => " + this.ToString());
- #endif
- GraphicObject p = focusParent;
- if (p != null)
- p.onMouseDoubleClick(sender,e);
- MouseDoubleClick.Raise (this, e);
- }
- public virtual void onMouseWheel(object sender, MouseWheelEventArgs e){
- GraphicObject p = focusParent;
- if (p != null)
- p.onMouseWheel(sender,e);
-
- MouseWheelChanged.Raise (this, e);
- }
- public virtual void onMouseEnter(object sender, MouseMoveEventArgs e)
- {
- #if DEBUG_FOCUS
- Debug.WriteLine("MouseEnter => " + this.ToString());
- #endif
- MouseEnter.Raise (this, e);
- }
- public virtual void onMouseLeave(object sender, MouseMoveEventArgs e)
- {
- #if DEBUG_FOCUS
- Debug.WriteLine("MouseLeave => " + this.ToString());
- #endif
- MouseLeave.Raise (this, e);
- }
- public virtual void onHover(object sender, EventArgs e)
- {
- #if DEBUG_FOCUS
- Debug.WriteLine("MouseHover => " + this.ToString());
- #endif
- if (IFace.DragAndDropOperation != null) {
- GraphicObject g = this;
- while (g != null) {
- if (g.AllowDrop) {
- if (IFace.DragAndDropOperation.DragSource != this && IFace.DragAndDropOperation.DropTarget != this) {
- if (IFace.DragAndDropOperation.DropTarget != null)
- IFace.DragAndDropOperation.DropTarget.onDragLeave (this, IFace.DragAndDropOperation);
- g.onDragEnter (this, IFace.DragAndDropOperation);
- }
- break;
- }
- g = g.focusParent;
- }
- }
- Hover.Raise (this, e);
- }
- public virtual void onUnHover(object sender, EventArgs e)
- {
- #if DEBUG_FOCUS
- Debug.WriteLine("MouseUnHover => " + this.ToString());
- #endif
- UnHover.Raise (this, e);
- }
- #endregion
-
- protected virtual void onFocused(object sender, EventArgs e){
- #if DEBUG_FOCUS
- Debug.WriteLine("Focused => " + this.ToString());
- #endif
- Focused.Raise (this, e);
- }
- protected virtual void onUnfocused(object sender, EventArgs e){
- #if DEBUG_FOCUS
- Debug.WriteLine("UnFocused => " + this.ToString());
- #endif
- Unfocused.Raise (this, e);
- }
- public virtual void onEnable(object sender, EventArgs e){
- Enabled.Raise (this, e);
- }
- public virtual void onDisable(object sender, EventArgs e){
- Disabled.Raise (this, e);
- }
- protected virtual void onParentChanged(object sender, DataSourceChangeEventArgs e) {
-// if (e.NewDataSource != null) {
-// if (width == Measure.Inherit)
-// RegisterForLayouting (LayoutingType.Width);
-// if (height == Measure.Inherit)
-// RegisterForLayouting (LayoutingType.Height);
-// }
-
- ParentChanged.Raise (this, e);
- if (logicalParent == null)
- LogicalParentChanged.Raise (this, e);
- }
- protected virtual void onLogicalParentChanged(object sender, DataSourceChangeEventArgs e) {
- LogicalParentChanged.Raise (this, e);
- }
- internal void ClearTemplateBinding(){
- #if DEBUG_UPDATE
- Debug.WriteLine (string.Format("ClearTemplateBinding: {0}", this.ToString()));
- #endif
- if (ValueChanged == null)
- return;
- EventInfo eiEvt = this.GetType().GetEvent ("ValueChanged");
- foreach (Delegate d in ValueChanged.GetInvocationList()) {
- if (d.Method.Name == "dyn_tmpValueChanged") {
- eiEvt.RemoveEventHandler (this, d);
- #if DEBUG_BINDING
- Debug.WriteLine ("\t{0} template binding handler removed in {1} for: {2}", d.Method.Name, this, "ValueChanged");
- #endif
- }
- }
- }
- public override string ToString ()
- {
- string tmp ="";
-
- if (Parent != null)
- tmp = Parent.ToString () + tmp;
- #if DEBUG_LAYOUTING
- return Name == "unamed" ? tmp + "." + this.GetType ().Name + uid.ToString(): tmp + "." + Name;
- #else
- return Name == "unamed" ? tmp + "." + this.GetType ().Name : tmp + "." + Name;
- #endif
- }
- /// <summary>
- /// Checks to handle when widget is removed from the visible graphic tree
- /// </summary>
- void unshownPostActions () {
- if (IFace.ActiveWidget != null) {
- if (IFace.ActiveWidget.IsOrIsInside (this))
- IFace.ActiveWidget = null;
- }
- if (IFace.FocusedWidget != null) {
- if (IFace.FocusedWidget.IsOrIsInside (this))
- IFace.FocusedWidget = null;
- }
- if (IFace.HoverWidget != null) {
- if (IFace.HoverWidget.IsOrIsInside (this)) {
- IFace.HoverWidget = null;
- IFace.ProcessMouseMove (IFace.Mouse.X, IFace.Mouse.Y);
- }
- }
- }
- }
-}