+++ /dev/null
-//
-// Border.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.Xml.Serialization;
-using System.ComponentModel;
-using System.Diagnostics;
-using Crow.Cairo;
-
-namespace Crow
-{
- /// <summary>
- /// provide an easy way to get 3d border for buttons
- /// </summary>
- public enum BorderStyle {
- Normal,
- Raised,
- Sunken
- };
-
- /// <summary>
- /// simple container with border
- /// </summary>
- public class Border : Container
- {
- #region CTOR
- protected Border () : base(){}
- public Border (Interface iface) : base(iface){}
- #endregion
-
- #region private fields
- int _borderWidth;
- BorderStyle _borderStyle;
- Fill raisedColor = Color.Grey;
- Fill sunkenColor = Color.DimGrey;
- #endregion
-
- #region public properties
- /// <summary>
- /// use to define the colors of the 3d border
- /// </summary>
-
- public virtual Fill RaisedColor {
- get { return raisedColor; }
- set {
- if (raisedColor == value)
- return;
- raisedColor = value;
- NotifyValueChanged ("RaisedColor", raisedColor);
- RegisterForRedraw ();
- }
- }
- /// <summary>
- /// use to define the colors of the 3d border
- /// </summary>
-
- public virtual Fill SunkenColor {
- get { return sunkenColor; }
- set {
- if (sunkenColor == value)
- return;
- sunkenColor = value;
- NotifyValueChanged ("SunkenColor", sunkenColor);
- RegisterForRedraw ();
- }
- }
- /// <summary>
- /// border width in pixels
- /// </summary>
- [DefaultValue(1)]
- public virtual int BorderWidth {
- get { return _borderWidth; }
- set {
- _borderWidth = value;
- RegisterForGraphicUpdate ();
- }
- }
- /// <summary>
- /// allow 3d border effects
- /// </summary>
- [DefaultValue(BorderStyle.Normal)]
- public virtual BorderStyle BorderStyle {
- get { return _borderStyle; }
- set {
- if (_borderStyle == value)
- return;
- _borderStyle = value;
- RegisterForGraphicUpdate ();
- }
- }
- #endregion
-
- #region GraphicObject override
- [XmlIgnore]public override Rectangle ClientRectangle {
- get {
- Rectangle cb = base.ClientRectangle;
- cb.Inflate (- BorderWidth);
- return cb;
- }
- }
-
- protected override int measureRawSize (LayoutingType lt)
- {
- int tmp = base.measureRawSize (lt);
- return tmp < 0 ? tmp : tmp + 2 * BorderWidth;
- }
- protected override void onDraw (Context gr)
- {
- drawborder2 (gr);
-
- gr.Save ();
- if (ClipToClientRect) {
- //clip to client zone
- CairoHelpers.CairoRectangle (gr, ClientRectangle,Math.Max(0.0, CornerRadius-Margin));
- gr.Clip ();
- }
-
- if (child != null)
- child.Paint (ref gr);
- gr.Restore ();
- }
- void drawborder2(Context gr){
- Rectangle rBack = new Rectangle (Slot.Size);
-
- //rBack.Inflate (-Margin);
- // if (BorderWidth > 0)
- // rBack.Inflate (-BorderWidth / 2);
-
- Background.SetAsSource (gr, rBack);
- CairoHelpers.CairoRectangle(gr, rBack, CornerRadius);
- gr.Fill ();
-
-
- if (BorderStyle == BorderStyle.Normal) {
- if (BorderWidth > 0) {
- Foreground.SetAsSource (gr, rBack);
- CairoHelpers.CairoRectangle (gr, rBack, CornerRadius, BorderWidth);
- }
- } else {
- gr.LineWidth = 1.0;
- if (CornerRadius > 0.0) {
- double radius = CornerRadius;
- if ((radius > rBack.Height / 2.0) || (radius > rBack.Width / 2.0))
- radius = Math.Min (rBack.Height / 2.0, rBack.Width / 2.0);
- gr.SetSourceColor (sunkenColor);
- gr.MoveTo (0.5 + rBack.Left, -0.5 + rBack.Bottom - radius);
- gr.ArcNegative (0.5 + rBack.Left + radius, -0.5 + rBack.Bottom - radius, radius, Math.PI, Math.PI * 0.75);
- gr.MoveTo (0.5 + rBack.Left, -0.5 + rBack.Bottom - radius);
- gr.LineTo (0.5 + rBack.Left, 0.5 + rBack.Top + radius);
- gr.Arc (0.5 + rBack.Left + radius, 0.5 + rBack.Top + radius, radius, Math.PI, Math.PI * 1.5);
- gr.LineTo (-0.5 + rBack.Right - radius, 0.5 + rBack.Top);
- gr.Arc (-0.5 + rBack.Right - radius, 0.5 + rBack.Top + radius, radius, Math.PI * 1.5, Math.PI * 1.75);
- gr.Stroke ();
- if (BorderStyle == BorderStyle.Raised) {
- gr.MoveTo (-1.5 + rBack.Right, 1.5 + rBack.Top + radius);
- gr.ArcNegative (-0.5 + rBack.Right - radius, 0.5 + rBack.Top + radius, radius - 1.0, 0, -Math.PI * 0.25);
- gr.MoveTo (-1.5 + rBack.Right, 1.5 + rBack.Top + radius);
- gr.LineTo (-1.5 + rBack.Right, -1.5 + rBack.Bottom - radius);
- gr.Arc (-0.5 + rBack.Right - radius, -0.5 + rBack.Bottom - radius, radius - 1.0, 0, Math.PI / 2.0);
- gr.LineTo (1.5 + rBack.Left + radius, -1.5 + rBack.Bottom);
- gr.Arc (0.5 + rBack.Left + radius, -0.5 + rBack.Bottom - radius, radius - 1.0, Math.PI / 2.0, Math.PI * 0.75);
- gr.Stroke ();
-
- gr.SetSourceColor (raisedColor);
- gr.MoveTo (1.5 + rBack.Left, -1.5 + rBack.Bottom - radius);
- gr.ArcNegative (0.5 + rBack.Left + radius, -0.5 + rBack.Bottom - radius, radius - 1.0, Math.PI, Math.PI * 0.75);
- gr.MoveTo (1.5 + rBack.Left, -1.5 + rBack.Bottom - radius);
- gr.LineTo (1.5 + rBack.Left, 1.5 + rBack.Top + radius);
- gr.Arc (0.5 + rBack.Left + radius, 0.5 + rBack.Top + radius, radius - 1.0, Math.PI, Math.PI * 1.5);
- gr.LineTo (-1.5 + rBack.Right - radius, 1.5 + rBack.Top);
- gr.Arc (-0.5 + rBack.Right - radius, 0.5 + rBack.Top + radius, radius - 1.0, Math.PI * 1.5, Math.PI * 1.75);
- } else {
- gr.Stroke ();
- gr.SetSourceColor (raisedColor);
- }
- gr.MoveTo (-0.5 + rBack.Right, 0.5 + rBack.Top + radius);
- gr.ArcNegative (-0.5 + rBack.Right - radius, 0.5 + rBack.Top + radius, radius, 0, -Math.PI * 0.25);
- gr.MoveTo (-0.5 + rBack.Right, 0.5 + rBack.Top + radius);
- gr.LineTo (-0.5 + rBack.Right, -0.5 + rBack.Bottom - radius);
- gr.Arc (-0.5 + rBack.Right - radius, -0.5 + rBack.Bottom - radius, radius, 0, Math.PI / 2.0);
- gr.LineTo (0.5 + rBack.Left + radius, -0.5 + rBack.Bottom);
- gr.Arc (0.5 + rBack.Left + radius, -0.5 + rBack.Bottom - radius, radius, Math.PI / 2.0, Math.PI * 0.75);
- gr.Stroke ();
- } else {
- gr.SetSourceColor (sunkenColor);
- gr.MoveTo (0.5 + rBack.Left, rBack.Bottom);
- gr.LineTo (0.5 + rBack.Left, 0.5 + rBack.Y);
- gr.LineTo (rBack.Right, 0.5 + rBack.Y);
- if (BorderStyle == BorderStyle.Raised) {
- gr.MoveTo (-1.5 + rBack.Right, 2.0 + rBack.Y);
- gr.LineTo (-1.5 + rBack.Right, -1.5 + rBack.Bottom);
- gr.LineTo (2.0 + rBack.Left, -1.5 + rBack.Bottom);
- gr.Stroke ();
- gr.SetSourceColor (raisedColor);
- gr.MoveTo (1.5 + rBack.Left, -1.0 + rBack.Bottom);
- gr.LineTo (1.5 + rBack.Left, 1.5 + rBack.Y);
- gr.LineTo (rBack.Right, 1.5 + rBack.Y);
- } else {
- gr.Stroke ();
- gr.SetSourceColor (raisedColor);
- }
- gr.MoveTo (-0.5 + rBack.Right, 1.5 + rBack.Y);
- gr.LineTo (-0.5 + rBack.Right, -0.5 + rBack.Bottom);
- gr.LineTo (1.0 + rBack.Left, -0.5 + rBack.Bottom);
- gr.Stroke ();
- }
- }
- }
- void drawborder1(Context gr){
- Rectangle rBack = new Rectangle (Slot.Size);
-
- //rBack.Inflate (-Margin);
- // if (BorderWidth > 0)
- // rBack.Inflate (-BorderWidth / 2);
-
- Background.SetAsSource (gr, rBack);
- CairoHelpers.CairoRectangle(gr, rBack, CornerRadius);
- gr.Fill ();
-
- double bw = _borderWidth;
- double crad = CornerRadius;
-
- if (bw > 0) {
- if (BorderStyle == BorderStyle.Normal)
- Foreground.SetAsSource (gr, rBack);
- else {
- if (BorderStyle == BorderStyle.Sunken)
- gr.SetSourceColor (raisedColor);
- else
- gr.SetSourceColor (sunkenColor);
-
- CairoHelpers.CairoRectangle (gr, rBack, crad, bw);
-
- if (BorderStyle == BorderStyle.Sunken)
- gr.SetSourceColor (sunkenColor);
- else
- gr.SetSourceColor (raisedColor);
-
- bw /= 2.0;
- rBack.Width -= (int)Math.Round(bw);
- rBack.Height -= (int)Math.Round(bw);
- }
-
- CairoHelpers.CairoRectangle (gr, rBack, crad, bw);
- }
- }
- #endregion
- }
-}
-
+++ /dev/null
-//
-// Button.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.Linq;
-using System.Text;
-//using OpenTK.Graphics.OpenGL;
-
-using System.Diagnostics;
-
-using System.Xml.Serialization;
-using Crow.Cairo;
-using System.ComponentModel;
-
-namespace Crow
-{
- /// <summary>
- /// templated button control
- /// </summary>
- public class Button : TemplatedContainer
- {
- #region CTOR
- protected Button() : base() {}
- public Button (Interface iface) : base(iface){}
- #endregion
-
- string image;
- bool isPressed;
-
- public event EventHandler Pressed;
- public event EventHandler Released;
-
- #region GraphicObject Overrides
- public override void onMouseDown (object sender, MouseButtonEventArgs e)
- {
- IsPressed = true;
-
- base.onMouseDown (sender, e);
-
- //TODO:remove
- NotifyValueChanged ("State", "pressed");
- }
- public override void onMouseUp (object sender, MouseButtonEventArgs e)
- {
- IsPressed = false;
-
- base.onMouseUp (sender, e);
-
- //TODO:remove
- NotifyValueChanged ("State", "normal");
- }
- #endregion
-
- [DefaultValue("#Crow.Images.button.svg")]
- public string Image {
- get { return image; }
- set {
- if (image == value)
- return;
- image = value;
- NotifyValueChanged ("Image", image);
- }
- }
- [DefaultValue(false)]
- public bool IsPressed
- {
- get { return isPressed; }
- set
- {
- if (isPressed == value)
- return;
-
- isPressed = value;
-
- NotifyValueChanged ("IsPressed", isPressed);
-
- if (isPressed)
- Pressed.Raise (this, null);
- else
- Released.Raise (this, null);
- }
- }
- }
-}
+++ /dev/null
-//
-// CheckBox.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.ComponentModel;
-using System.Xml.Serialization;
-
-namespace Crow
-{
- /// <summary>
- /// templated checkbox control
- /// </summary>
- public class CheckBox : TemplatedControl
- {
- #region CTOR
- protected CheckBox() : base(){}
- public CheckBox (Interface iface) : base(iface){}
- #endregion
-
- bool isChecked;
-
- public event EventHandler Checked;
- public event EventHandler Unchecked;
-
- [DefaultValue(false)]
- public bool IsChecked
- {
- get { return isChecked; }
- set
- {
- if (isChecked == value)
- return;
-
- isChecked = value;
-
- NotifyValueChanged ("IsChecked", value);
-
- if (isChecked)
- Checked.Raise (this, null);
- else
- Unchecked.Raise (this, null);
- }
- }
-
- public override void onMouseClick (object sender, MouseButtonEventArgs e)
- {
- IsChecked = !IsChecked;
- base.onMouseClick (sender, e);
- }
- }
-}
+++ /dev/null
-//
-// ColorPicker.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.Xml.Serialization;
-using System.ComponentModel;
-
-namespace Crow
-{
- /// <summary>
- /// templated color selector control
- /// </summary>
- public class ColorPicker : TemplatedControl
- {
- #region CTOR
- protected ColorPicker() : base(){}
- public ColorPicker (Interface iface) : base(iface){}
- #endregion
-
- const double div = 255.0;
- const double colDiv = 1.0 / div;
-
- Color curColor;
- double h,s,v;
-
-
- public virtual double R {
- get { return Math.Round(curColor.R * div); }
- set {
- if (R == value)
- return;
- curColor.R = value * colDiv;
- NotifyValueChanged ("R", R);
- hsvFromRGB ();
- notifyCurColorHasChanged ();
- }
- }
-
- public virtual double G {
- get { return Math.Round(curColor.G * div); }
- set {
- if (G == value)
- return;
- curColor.G = value * colDiv;
- NotifyValueChanged ("G", G);
- notifyCurColorHasChanged ();
- hsvFromRGB ();
- }
- }
-
- public virtual double B {
- get { return Math.Round(curColor.B * div); }
- set {
- if (B == value)
- return;
- curColor.B = value * colDiv;
- NotifyValueChanged ("B", B);
- notifyCurColorHasChanged ();
- hsvFromRGB ();
- }
- }
-
- public virtual double A {
- get { return Math.Round(curColor.A * div); }
- set {
- if (A == value)
- return;
- curColor.A = value * colDiv;
- NotifyValueChanged ("A", A);
- notifyCurColorHasChanged ();
- hsvFromRGB ();
- }
- }
-
- public virtual double H {
- get { return Math.Round (h, 3); }
- set {
- if (H == value)
- return;
- h = value;
- NotifyValueChanged ("H", H);
- rgbFromHSV ();
- }
- }
-
- public virtual double S {
- get { return Math.Round (s, 2); }
- set {
- if (s == value)
- return;
- s = value;
- NotifyValueChanged ("S", S);
- rgbFromHSV ();
- }
- }
-
- public virtual double V {
- get { return Math.Round (v, 2); }
- set {
- if (v == value)
- return;
- v = value;
- NotifyValueChanged ("V", V);
- rgbFromHSV ();
- }
- }
-
-
- public virtual Fill SelectedColor {
- get { return new SolidColor(curColor); }
- set {
- if (value == null)
- curColor = Color.White;
- else if (value is SolidColor) {
- Color c = (value as SolidColor).color;
- if (curColor == c)
- return;
- curColor = c;
- }
- notifyCurColorHasChanged ();
- notifyRGBAHasChanged ();
- hsvFromRGB ();
- }
- }
-
- public virtual Color SelectedRawColor {
- get { return curColor; }
- set {
- if (curColor == value)
- return;
- curColor = value;
- notifyCurColorHasChanged ();
- notifyRGBAHasChanged ();
- hsvFromRGB ();
- }
- }
- void notifyCurColorHasChanged(){
- NotifyValueChanged ("SelectedColor", SelectedColor);
- NotifyValueChanged ("SelectedRawColor", curColor);
- string n = curColor.ToString ();
- if (char.IsLetter(n[0]))
- NotifyValueChanged ("SelectedColorName", n);
- else
- NotifyValueChanged ("SelectedColorName", "-");
- string tmp = ((int)Math.Round (R)).ToString ("X2") +
- ((int)Math.Round (G)).ToString ("X2") +
- ((int)Math.Round (B)).ToString ("X2");
- if (curColor.A < 1.0)
- tmp += ((int)Math.Round (A)).ToString ("X2");
- NotifyValueChanged ("HexColor", tmp);
- }
- void notifyRGBAHasChanged(){
- NotifyValueChanged ("R", R);
- NotifyValueChanged ("G", G);
- NotifyValueChanged ("B", B);
- NotifyValueChanged ("A", A);
- }
- void notifyHSVHasChanged(){
- NotifyValueChanged ("H", H);
- NotifyValueChanged ("S", S);
- NotifyValueChanged ("V", V);
- }
- void hsvFromRGB(){
- Color c = curColor;
- c.ResetName ();
- double min = Math.Min (c.R, Math.Min (c.G, c.B)); //Min. value of RGB
- double max = Math.Max (c.R, Math.Max (c.G, c.B)); //Max. value of RGB
- double diff = max - min; //Delta RGB value
-
- v = max;
-
- if ( diff == 0 )//This is a gray, no chroma...
- {
- h = 0;
- s = 0;
- }else{//Chromatic data...
- s = diff / max;
-
- double diffR = (((max - c.R) / 6.0) + (diff / 2.0)) / diff;
- double diffG = (((max - c.G) / 6.0) + (diff / 2.0)) / diff;
- double diffB = (((max - c.B) / 6.0) + (diff / 2.0)) / diff;
-
- if (c.R == max)
- h = diffB - diffG;
- else if (c.G == max)
- h = (1.0 / 3.0) + diffR - diffB;
- else if (c.B == max)
- h = (2.0 / 3.0) + diffG - diffR;
-
- if (h < 0)
- h += 1;
- if (h > 1)
- h -= 1;
-
- }
- notifyHSVHasChanged ();
- }
- void rgbFromHSV(){
- curColor = Color.FromHSV (h, v, s, curColor.A);
- notifyCurColorHasChanged ();
- notifyRGBAHasChanged ();
- }
- }
-}
-
+++ /dev/null
-//
-// ColorSelector.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.Xml.Serialization;
-using System.ComponentModel;
-
-namespace Crow
-{
- /// <summary>
- /// simple squarred rgb color selector
- /// </summary>
- [DesignIgnore]
- public class ColorSelector : Widget
- {
- #region CTOR
- protected ColorSelector() : base(){}
- public ColorSelector (Interface iface) : base(iface){}
- #endregion
-
- protected Point mousePos;
-
- public override void onMouseMove (object sender, MouseMoveEventArgs e)
- {
- base.onMouseMove (sender, e);
- if (IFace.Mouse.LeftButton == ButtonState.Released)
- return;
- updateMouseLocalPos (e.Position);
- }
- public override void onMouseDown (object sender, MouseButtonEventArgs e)
- {
- base.onMouseDown (sender, e);
- if (e.Button == MouseButton.Left)
- updateMouseLocalPos (e.Position);
- }
-
- protected virtual void updateMouseLocalPos(Point mPos){
- Rectangle r = ScreenCoordinates (Slot);
- Rectangle cb = ClientRectangle;
- mousePos = mPos - r.Position;
-
- mousePos.X = Math.Max(cb.X, mousePos.X);
- mousePos.X = Math.Min(cb.Right, mousePos.X);
- mousePos.Y = Math.Max(cb.Y, mousePos.Y);
- mousePos.Y = Math.Min(cb.Bottom, mousePos.Y);
-
- RegisterForRedraw ();
- }
- }
-}
-
+++ /dev/null
-// Copyright (c) 2013-2019 Bruyère Jean-Philippe jp_bruyere@hotmail.com
-//
-// This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT)
-
-using System;
-using System.ComponentModel;
-using Crow.Cairo;
-
-namespace Crow
-{
- /// <summary>
- /// simple squarred rgb color selector
- /// </summary>
- [DesignIgnore]
- public class ColorSlider : Widget
- {
- #region CTOR
- protected ColorSlider() : base(){}
- public ColorSlider (Interface iface) : base(iface){}
- #endregion
-
- protected Point mousePos;
- Orientation orientation;
- CursorType cursorType = CursorType.Pentagone;
- ColorComponent component;
- Color currentColor = Color.Black;
- double currentValue;
-
- [DefaultValue (Orientation.Horizontal)]
- public Orientation Orientation {
- get => orientation;
- set {
- if (orientation == value)
- return;
- orientation = value;
- NotifyValueChanged ("Orientation", orientation);
- RegisterForGraphicUpdate ();
- }
- }
- [DefaultValue (CursorType.Pentagone)]
- public CursorType CursorType {
- get => cursorType;
- set {
- if (cursorType == value)
- return;
- cursorType = value;
- NotifyValueChanged ("CursorType", cursorType);
- RegisterForRedraw ();
- }
- }
- [DefaultValue (ColorComponent.Value)]
- public ColorComponent Component {
- get => component;
- set {
- if (component == value)
- return;
- component = value;
- NotifyValueChanged ("Component", component);
- RegisterForRedraw ();
- }
- }
- public Color CurrentColor {
- get => currentColor;
- set {
- if (currentColor == value)
- return;
- currentColor = value;
- switch (component) {
- case ColorComponent.Red:
- if (currentValue != currentColor.R) {
- currentValue = currentColor.R;
- updateMousePosFromComponentValue ();
- }
- break;
- case ColorComponent.Green:
- if (currentValue != currentColor.G) {
- currentValue = currentColor.G;
- updateMousePosFromComponentValue ();
- }
- break;
- case ColorComponent.Blue:
- if (currentValue != currentColor.B) {
- currentValue = currentColor.B;
- updateMousePosFromComponentValue ();
- }
- break;
- case ColorComponent.Alpha:
- if (currentValue != currentColor.A) {
- currentValue = currentColor.A;
- updateMousePosFromComponentValue ();
- }
- break;
- case ColorComponent.Hue:
- if (currentValue != currentColor.Hue) {
- currentValue = currentColor.Hue;
- updateMousePosFromComponentValue ();
- }
- break;
- case ColorComponent.Saturation:
- if (currentValue != currentColor.Saturation) {
- currentValue = currentColor.Saturation;
- updateMousePosFromComponentValue ();
- }
- break;
- case ColorComponent.Value:
- if (currentValue != currentColor.Value) {
- currentValue = currentColor.Value;
- updateMousePosFromComponentValue ();
- }
- break;
- }
- NotifyValueChanged ("CurrentColor", currentColor);
- RegisterForRedraw ();
- }
- }
- public override void onMouseMove (object sender, MouseMoveEventArgs e)
- {
- base.onMouseMove (sender, e);
- if (IFace.Mouse.LeftButton == ButtonState.Released)
- return;
- updateMouseLocalPos (e.Position);
- }
- public override void onMouseDown (object sender, MouseButtonEventArgs e)
- {
- base.onMouseDown (sender, e);
- if (e.Button == MouseButton.Left)
- updateMouseLocalPos (e.Position);
- }
-
- protected override void onDraw (Context gr) {
- base.onDraw (gr);
-
- RectangleD r = ClientRectangle;
- r.Height -= 4;
- r.Y += 2;
-
- Gradient.Type gt = Gradient.Type.Horizontal;
- if (Orientation == Orientation.Vertical)
- gt = Gradient.Type.Vertical;
-
- Gradient grad = new Gradient (gt);
- Color c = currentColor;
-
- switch (component) {
- case ColorComponent.Red:
- grad.Stops.Add (new Gradient.ColorStop (0, new Color (0, c.G, c.B, c.A)));
- grad.Stops.Add (new Gradient.ColorStop (1, new Color (1, c.G, c.B, c.A)));
- break;
- case ColorComponent.Green:
- grad.Stops.Add (new Gradient.ColorStop (0, new Color (c.R, 0, c.B, c.A)));
- grad.Stops.Add (new Gradient.ColorStop (1, new Color (c.R, 1, c.B, c.A)));
- break;
- case ColorComponent.Blue:
- grad.Stops.Add (new Gradient.ColorStop (0, new Color (c.R, c.G, 0, c.A)));
- grad.Stops.Add (new Gradient.ColorStop (1, new Color (c.R, c.G, 1, c.A)));
- break;
- case ColorComponent.Alpha:
- grad.Stops.Add (new Gradient.ColorStop (0, new Color (c.R, c.G, c.B, 0)));
- grad.Stops.Add (new Gradient.ColorStop (1, new Color (c.R, c.G, c.B, 1)));
- break;
- case ColorComponent.Hue:
- grad.Stops.Add (new Gradient.ColorStop (0, new Color (1, 0, 0, 1)));
- grad.Stops.Add (new Gradient.ColorStop (0.167, new Color (1, 1, 0, 1)));
- grad.Stops.Add (new Gradient.ColorStop (0.333, new Color (0, 1, 0, 1)));
- grad.Stops.Add (new Gradient.ColorStop (0.5, new Color (0, 1, 1, 1)));
- grad.Stops.Add (new Gradient.ColorStop (0.667, new Color (0, 0, 1, 1)));
- grad.Stops.Add (new Gradient.ColorStop (0.833, new Color (1, 0, 1, 1)));
- grad.Stops.Add (new Gradient.ColorStop (1, new Color (1, 0, 0, 1)));
- break;
- case ColorComponent.Saturation:
- grad.Stops.Add (new Gradient.ColorStop (0, Color.FromHSV (c.Hue, c.Value, 0.0, c.A)));
- grad.Stops.Add (new Gradient.ColorStop (1, Color.FromHSV (c.Hue, c.Value, 1.0, c.A)));
- break;
- case ColorComponent.Value:
- grad.Stops.Add (new Gradient.ColorStop (0, Color.FromHSV (c.Hue, 0.0, c.Saturation, c.A)));
- grad.Stops.Add (new Gradient.ColorStop (1, Color.FromHSV (c.Hue, 1.0, c.Saturation, c.A)));
- break;
- }
-
- grad.SetAsSource (gr, r);
- CairoHelpers.CairoRectangle (gr, r, CornerRadius);
- gr.Fill ();
-
- r = ClientRectangle;
-
- switch (cursorType) {
- case CursorType.Rectangle:
- if (Orientation == Orientation.Horizontal) {
- r.Width = 5;
- r.X = mousePos.X - 2.5;
- } else {
- r.Height = 5;
- r.Y = mousePos.Y - 2.5;
- }
- CairoHelpers.CairoRectangle (gr, r, 1);
- break;
- case CursorType.Circle:
- if (Orientation == Orientation.Horizontal)
- gr.Arc (mousePos.X, r.Center.Y, 3.5, 0, Math.PI * 2.0);
- else
- gr.Arc (r.Center.X, mousePos.Y, 3.5, 0, Math.PI * 2.0);
- break;
- case CursorType.Pentagone:
- if (Orientation == Orientation.Horizontal) {
- r.Width = 5;
- r.X = mousePos.X - 2.5;
- double y = r.CenterD.Y - r.Height * 0.2;
- gr.MoveTo (mousePos.X, y);
- y += r.Height * 0.15;
- gr.LineTo (r.Right, y);
- gr.LineTo (r.Right, r.Bottom - 0.5);
- gr.LineTo (r.Left, r.Bottom - 0.5);
- gr.LineTo (r.Left, y);
- gr.ClosePath ();
- } else {
- }
- break;
- }
-
- gr.SetSourceColor (Color.Black);
- gr.LineWidth = 2.0;
- gr.StrokePreserve ();
- gr.SetSourceColor (Color.White);
- gr.LineWidth = 1.0;
- gr.Stroke ();
- }
- public override void OnLayoutChanges (LayoutingType layoutType) {
- base.OnLayoutChanges (layoutType);
-
- if (Orientation == Orientation.Horizontal) {
- if (layoutType == LayoutingType.Width)
- updateMousePosFromComponentValue ();
- } else if (layoutType == LayoutingType.Height)
- updateMousePosFromComponentValue ();
- }
- void updateMousePosFromComponentValue () {
- if (Orientation == Orientation.Horizontal)
- mousePos.X = (int)Math.Floor (currentValue * ClientRectangle.Width);
- else
- mousePos.Y = (int)Math.Floor (currentValue * ClientRectangle.Height);
- RegisterForRedraw ();
- }
-
- protected virtual void updateMouseLocalPos(Point mPos){
- Rectangle r = ScreenCoordinates (Slot);
- Rectangle cb = ClientRectangle;
- mousePos = mPos - r.Position;
-
- mousePos.X = Math.Max(cb.X, mousePos.X);
- mousePos.X = Math.Min(cb.Right, mousePos.X);
- mousePos.Y = Math.Max(cb.Y, mousePos.Y);
- mousePos.Y = Math.Min(cb.Bottom, mousePos.Y);
-
- if (Orientation == Orientation.Horizontal)
- currentValue = (double)mousePos.X / ClientRectangle.Width;
- else
- currentValue = (double)mousePos.Y / ClientRectangle.Height;
- Color c = currentColor;
- switch (component) {
- case ColorComponent.Red:
- CurrentColor = new Color(currentValue, c.G, c.B, c.A);
- break;
- case ColorComponent.Green:
- CurrentColor = new Color (c.R, currentValue, c.B, c.A);
- break;
- case ColorComponent.Blue:
- CurrentColor = new Color (c.R, c.G, currentValue, c.A);
- break;
- case ColorComponent.Alpha:
- CurrentColor = new Color (c.R, c.G, c.B, currentValue);
- break;
- case ColorComponent.Hue:
- CurrentColor = Color.FromHSV (currentValue, c.Value, c.Saturation, c.A);
- break;
- case ColorComponent.Saturation:
- CurrentColor = Color.FromHSV (c.Hue, c.Value, currentValue, c.A);
- break;
- case ColorComponent.Value:
- CurrentColor = Color.FromHSV (c.Hue, currentValue, c.Saturation, c.A);
- break;
- }
- //NotifyValueChanged ("CurrentColor", currentColor);
- //RegisterForRedraw ();
- }
- }
-}
-
+++ /dev/null
-//
-// ComboBox.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.Xml.Serialization;
-
-namespace Crow
-{
- /// <summary>
- /// templated control for selecting value in a pop up list
- /// </summary>
- public class ComboBox : ListBox
- {
- #region CTOR
- protected ComboBox() : base(){}
- public ComboBox (Interface iface) : base(iface){}
- #endregion
-
- Size minimumPopupSize = "10,10";
- [XmlIgnore]public Size MinimumPopupSize{
- get { return minimumPopupSize; }
- set {
- minimumPopupSize = value;
- NotifyValueChanged ("MinimumPopupSize", minimumPopupSize);
- }
- }
-
- public override void OnLayoutChanges (LayoutingType layoutType)
- {
- base.OnLayoutChanges (layoutType);
-
- if (layoutType == LayoutingType.Width)
- MinimumPopupSize = new Size (this.Slot.Width, minimumPopupSize.Height);
- }
- }
-}
+++ /dev/null
-//
-// Container.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.Xml.Serialization;
-using System.Reflection;
-using System.ComponentModel;
-using System.Linq;
-using System.Threading;
-
-namespace Crow
-{
- /// <summary>
- /// simple container accepting one child
- /// </summary>
- public class Container : PrivateContainer
- {
- #if DESIGN_MODE
- public override void getIML (System.Xml.XmlDocument doc, System.Xml.XmlNode parentElem)
- {
- if (this.design_isTGItem)
- return;
- base.getIML (doc, parentElem);
- if (child == null)
- return;
- child.getIML (doc, parentElem.LastChild);
- }
- #endif
-
- #region CTOR
- protected Container() : base(){}
- public Container (Interface iface) : base(iface){}
- #endregion
-
- [XmlIgnore]public Widget Child {
- get { return child; }
- set { base.SetChild(value); }
- }
- /// <summary>
- /// override this to handle specific steps in child addition in derived class,
- /// and don't forget to call the base.SetChild
- /// </summary>
- public new virtual void SetChild(Widget _child)
- {
- base.SetChild (_child);
- }
- }
-}
-
+++ /dev/null
-//
-// DataSourceChangeEventArgs.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;
-
-namespace Crow
-{
- public class DataSourceChangeEventArgs : EventArgs
- {
- public object OldDataSource;
- public object NewDataSource;
-
- public DataSourceChangeEventArgs (object oldDataSource, object newDataSource) : base()
- {
- OldDataSource = oldDataSource;
- NewDataSource = newDataSource;
- }
- public override string ToString ()
- {
- return string.Format ("DSChangeEA: {0} => {1}", OldDataSource, NewDataSource);
- }
- }
-}
-
+++ /dev/null
-//
-// DirectoryView.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.Xml.Serialization;
-using System.ComponentModel;
-using System.IO;
-using System.Collections.Generic;
-using System.Linq;
-
-namespace Crow
-{
- /// <summary>
- /// templated directory viewer
- /// </summary>
- public class DirectoryView : TemplatedControl
- {
- #region CTOR
- protected DirectoryView() : base(){}
- public DirectoryView (Interface iface) : base(iface){}
- #endregion
-
- #region events
- public event EventHandler<SelectionChangeEventArgs> SelectedItemChanged;
- #endregion
-
- string currentDirectory = "/";
- bool showFiles, showHidden;
- string fileMask = "*.*";
-
- object _selectedItem;
- [XmlIgnore]public object SelectedItem {
- get {
- return _selectedItem;
- }
- set {
- if (value == _selectedItem)
- return;
- _selectedItem = value;
- NotifyValueChanged ("SelectedItem", _selectedItem);
- }
- }
- [DefaultValue(true)]
- public virtual bool ShowFiles {
- get { return showFiles; }
- set {
- if (showFiles == value)
- return;
- showFiles = value;
- NotifyValueChanged ("ShowFiles", showFiles);
- NotifyValueChanged ("FileSystemEntries", FileSystemEntries);
- }
- }
- [DefaultValue(false)]
- public virtual bool ShowHidden {
- get { return showHidden; }
- set {
- if (showHidden == value)
- return;
- showHidden = value;
- NotifyValueChanged ("ShowHidden", showHidden);
- NotifyValueChanged ("FileSystemEntries", FileSystemEntries);
- }
- }
- [DefaultValue("*.*")]
- public virtual string FileMask {
- get { return fileMask; }
- set {
- if (fileMask == value)
- return;
- fileMask = value;
- NotifyValueChanged ("FileMask", fileMask);
- NotifyValueChanged ("FileSystemEntries", FileSystemEntries);
- }
- }
- [DefaultValue("/")]
- public virtual string CurrentDirectory {
- get { return currentDirectory; }
- set {
- if (currentDirectory == value)
- return;
- currentDirectory = value;
- NotifyValueChanged ("CurrentDirectory", currentDirectory);
- NotifyValueChanged ("FileSystemEntries", FileSystemEntries);
- }
- }
- [XmlIgnore]public FileSystemInfo[] FileSystemEntries {
- get {
- try {
- if (string.IsNullOrEmpty(CurrentDirectory))
- return null;
- DirectoryInfo di = new DirectoryInfo(CurrentDirectory);
- List<FileSystemInfo> fi = new List<FileSystemInfo> (di.GetDirectories());
- if (showFiles && !string.IsNullOrEmpty(fileMask))
- fi.AddRange(di.GetFiles(fileMask));
- return showHidden ?
- fi.ToArray() :
- fi.Where(f=>!f.Attributes.HasFlag (FileAttributes.Hidden)).ToArray();
- } catch (Exception ex) {
- Console.WriteLine (ex.ToString ());
- return null;
- }
- }
- }
- public void onSelectedItemChanged (object sender, SelectionChangeEventArgs e){
- if (e.NewValue == SelectedItem)
- return;
- SelectedItem = e.NewValue;
- SelectedItemChanged.Raise (this, e);
- }
- }
-}
-
+++ /dev/null
-//
-// DockStack.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 Crow.IML;
-using System.Linq;
-using System.Text;
-using System.IO;
-
-namespace Crow
-{
- [DesignIgnore]
- public class DockStack : GenericStack
- {
- #region CTor
- public DockStack () {}
- public DockStack (Interface iface) : base (iface) {}
- #endregion
-
- /*static int color = 10;
-
- protected override void onInitialized (object sender, EventArgs e)
- {
- base.onInitialized (sender, e);
- Background = Color.ColorDic.Values.ToList()[color++];
- }*/
- public override void AddChild (Widget g)
- {
- base.AddChild (g);
- if (localLogicalParentIsNull)
- g.LogicalParent = this;
- else
- g.LogicalParent = this.LogicalParent;
- }
- public override void InsertChild (int idx, Widget g)
- {
- base.InsertChild (idx, g);
- g.LogicalParent = this.LogicalParent;
- }
-
- public override bool PointIsIn (ref Point m)
- {
- if (!base.PointIsIn(ref m))
- return false;
-
- Group p = Parent as Group;
- if (p != null) {
- childrenRWLock.EnterReadLock ();
- for (int i = p.Children.Count - 1; i >= 0; i--) {
- if (p.Children [i] == this)
- break;
- if (p.Children [i].IsDragged)
- continue;
- if (p.Children [i].Slot.ContainsOrIsEqual (m)) {
- childrenRWLock.ExitReadLock ();
- return false;
- }
- }
- childrenRWLock.ExitReadLock ();
- }
-
- return Slot.ContainsOrIsEqual(m);
- }
-
-// public override void OnLayoutChanges (LayoutingType layoutType)
-// {
-// base.OnLayoutChanges (layoutType);
-//
-// if ((layoutType & LayoutingType.Sizing) > 0)
-// computeRects();
-// }
-
- Rectangle rIn = default(Rectangle);
- double dockThresh = 0.2;
- Widget focusedChild;
- internal Widget stretchedChild;
-
- void getFocusedChild (Point lm) {
- Rectangle cb = ClientRectangle;
-
- childrenRWLock.EnterReadLock ();
- foreach (Widget c in Children) {
- Rectangle bounds = c.Slot + cb.Position;
- if (!bounds.ContainsOrIsEqual (lm))
- continue;
- rIn = bounds;
- focusedChild = c;
- break;
- }
- childrenRWLock.ExitReadLock ();
- }
-
- public override void onMouseMove (object sender, MouseMoveEventArgs e)
- {
- if (IsDropTarget) {
- DockWindow dw = IFace.DragAndDropOperation.DragSource as DockWindow;
- if (dw == null || dw.IsDocked) {
- base.onMouseMove (sender, e);
- return;
- }
-
- Alignment curDockPos = dw.DockingPosition;
- dw.DockingPosition = Alignment.Undefined;
-
- Rectangle cb = ClientRectangle;
- Point lm = ScreenPointToLocal (e.Position);
-
- if (Children.Count == 0) {
- Rectangle r = cb;
- r.Inflate (r.Width / -5, r.Height / -5);
- if (r.ContainsOrIsEqual(lm))
- dw.DockingPosition = Alignment.Center;
- } else {
- rIn = cb;
-
- if (Orientation == Orientation.Horizontal || Children.Count == 1) {
- if (lm.Y > cb.Top + cb.Height / 3 && lm.Y < cb.Bottom - cb.Height / 3) {
- if (lm.X < cb.Left + cb.Width / 3)
- dw.DockingPosition = Alignment.Left;
- else if (lm.X > cb.Right - cb.Width / 3)
- dw.DockingPosition = Alignment.Right;
- } else {
- getFocusedChild (lm);
- if (focusedChild != null) {
- if (lm.Y < rIn.Top + rIn.Height / 3)
- dw.DockingPosition = Alignment.Top;
- else if (lm.Y > rIn.Bottom - rIn.Height / 3)
- dw.DockingPosition = Alignment.Bottom;
- }
- }
- }
- if (Orientation == Orientation.Vertical || Children.Count == 1) {
- if (lm.X > cb.Left + cb.Width / 3 && lm.X < cb.Right - cb.Width / 3) {
- if (lm.Y < cb.Top + cb.Height / 3)
- dw.DockingPosition = Alignment.Top;
- else if (lm.Y > cb.Bottom - cb.Height / 3)
- dw.DockingPosition = Alignment.Bottom;
- } else {
- getFocusedChild (lm);
- if (focusedChild != null) {
- if (lm.X < rIn.Left + rIn.Width / 3)
- dw.DockingPosition = Alignment.Left;
- else if (lm.X > rIn.Right - rIn.Width / 3)
- dw.DockingPosition = Alignment.Right;
- }
- }
- }
- }
-
- if (curDockPos != dw.DockingPosition)
- RegisterForGraphicUpdate ();
- }
- base.onMouseMove (sender, e);
- }
-
- protected override void onDragEnter (object sender, DragDropEventArgs e)
- {
- base.onDragEnter (sender, e);
- RegisterForGraphicUpdate ();
- }
- protected override void onDragLeave (object sender, DragDropEventArgs e)
- {
- DockWindow dw = e.DragSource as DockWindow;
- //if (dw != null)
- // dw.DockingPosition = Alignment.Undefined;
- base.onDragLeave (sender, e);
- RegisterForGraphicUpdate ();
- }
-
- protected override void onDraw (Cairo.Context gr)
- {
- gr.Save ();
-
- Rectangle rBack = new Rectangle (Slot.Size);
-
- Background.SetAsSource (gr, rBack);
- CairoHelpers.CairoRectangle (gr, rBack, CornerRadius);
- gr.Fill ();
-
- if (ClipToClientRect) {
- //clip to client zone
- CairoHelpers.CairoRectangle (gr, ClientRectangle, CornerRadius);
- gr.Clip ();
- }
-
- childrenRWLock.EnterReadLock ();
-
- foreach (Widget g in Children)
- g.Paint (ref gr);
-
- childrenRWLock.ExitReadLock ();
-
-
- if (!IsDropTarget) {
- gr.Restore ();
- return;
- }
-
- DockWindow dw = IFace.DragAndDropOperation.DragSource as DockWindow;
- if (dw == null)
- return;
- if (!dw.IsDocked) {
- Rectangle cb = ClientRectangle;
- double minDim = Math.Min (cb.Width, cb.Height);
-
- Rectangle r = rIn;
- if (Children.Count <= 1 || dw.DockingPosition.GetOrientation()==Orientation )
- r = cb;
-
- switch (dw.DockingPosition) {
- case Alignment.Top:
- gr.Rectangle (r.Left, r.Top, r.Width, r.Height * dockThresh);
- break;
- case Alignment.Bottom:
- gr.Rectangle (r.Left, r.Bottom - r.Height * dockThresh, r.Width, r.Height * dockThresh);
- break;
- case Alignment.Left:
- gr.Rectangle (r.Left, r.Top, r.Width * dockThresh, r.Height);
- break;
- case Alignment.Right:
- gr.Rectangle (r.Right - r.Width * dockThresh, r.Top, r.Width * dockThresh, r.Height);
- break;
- case Alignment.Center:
- r.Inflate ((int)Math.Ceiling (Math.Min (r.Width, r.Height) * -0.05));
- gr.Rectangle (r);
- break;
- }
- gr.LineWidth = 1;
- gr.SetSourceRGBA (0.4, 0.4, 0.9, 0.4);
- gr.FillPreserve ();
- gr.SetSourceRGBA (0.9, 0.9, 1.0, 0.8);
- gr.Stroke ();
- }
- gr.Restore ();
- }
-
- public void Dock(DockWindow dw){
- DockStack activeStack = this;
-
- if (Children.Count == 1) {
- Orientation = dw.DockingPosition.GetOrientation ();
- if (Children [0] is DockWindow) {
- (Children [0] as DockWindow).DockingPosition = dw.DockingPosition.GetOpposite ();
- }
- } else if (Children.Count > 0 && dw.DockingPosition.GetOrientation () != Orientation) {
- activeStack = new DockStack (IFace);
- activeStack.Orientation = dw.DockingPosition.GetOrientation ();
- activeStack.Width = focusedChild.Width;
- activeStack.Height = focusedChild.Height;
- int idx = Children.IndexOf (focusedChild);
- RemoveChild (focusedChild);
- focusedChild.Height = Measure.Stretched;
- focusedChild.Width = Measure.Stretched;
- InsertChild (idx, activeStack);
- activeStack.AddChild (focusedChild);
- activeStack.stretchedChild = focusedChild;
- if (focusedChild is DockWindow)
- (focusedChild as DockWindow).DockingPosition = dw.DockingPosition.GetOpposite ();
- focusedChild = null;
- }
-
- Rectangle r = ClientRectangle;
- int vTreshold = (int)(r.Height * dockThresh);
- int hTreshold = (int)(r.Width * dockThresh);
-
- Console.WriteLine ("Docking {0} as {2} in {1}", dw.Name, activeStack.Name, dw.DockingPosition);
- switch (dw.DockingPosition) {
- case Alignment.Top:
- dw.Height = vTreshold;
- dw.Width = Measure.Stretched;
- activeStack.InsertChild (0, dw);
- activeStack.InsertChild (1, new Splitter(IFace));
- break;
- case Alignment.Bottom:
- dw.Height = vTreshold;
- dw.Width = Measure.Stretched;
- activeStack.AddChild (new Splitter(IFace));
- activeStack.AddChild (dw);
- break;
- case Alignment.Left:
- dw.Width = hTreshold;
- dw.Height = Measure.Stretched;
- activeStack.InsertChild (0, dw);
- activeStack.InsertChild (1, new Splitter(IFace));
- break;
- case Alignment.Right:
- dw.Width = hTreshold;
- dw.Height = Measure.Stretched;
- activeStack.AddChild (new Splitter(IFace));
- activeStack.AddChild (dw);
- break;
- case Alignment.Center:
- dw.Width = dw.Height = Measure.Stretched;
- AddChild (dw);
- stretchedChild = dw;
- break;
- }
- }
- public void Undock (DockWindow dw){
- int idx = Children.IndexOf(dw);
-
- Console.WriteLine ("undocking child index: {0} ; name={1}; pos:{2} ; childcount:{3}",idx, dw.Name, dw.DockingPosition, Children.Count);
-
- RemoveChild(dw);
-
- if (Children.Count == 0)
- return;
-
- if (dw.DockingPosition == Alignment.Left || dw.DockingPosition == Alignment.Top) {
- RemoveChild (idx);
- if (stretchedChild == dw) {
- stretchedChild = Children [idx];
- stretchedChild.Width = stretchedChild.Height = Measure.Stretched;
- }
- } else {
- RemoveChild (idx - 1);
- if (stretchedChild == dw) {
- stretchedChild = Children [idx-2];
- stretchedChild.Width = stretchedChild.Height = Measure.Stretched;
- }
- }
-
- if (Children.Count == 1) {
- DockStack dsp = Parent as DockStack;
- if (dsp == null) {
- Children [0].Width = Children [0].Height = Measure.Stretched;
- return;
- }
- //remove level and move remaining obj to level above
- Widget g = Children [0];
- RemoveChild (g);
- idx = dsp.Children.IndexOf (this);
- dsp.RemoveChild (this);
- dsp.InsertChild (idx, g);
- g.Width = this.Width;
- g.Height = this.Height;
- if (dsp.stretchedChild == this)
- dsp.stretchedChild = g;
- dsp.checkAlignments ();
- } else
- checkAlignments ();
- }
-
- internal void checkAlignments () {
- DockWindow dw = Children[0] as DockWindow;
- if (dw != null)
- dw.DockingPosition = (Orientation == Orientation.Horizontal ? Alignment.Left : Alignment.Top);
- dw = Children[Children.Count - 1] as DockWindow;
- if (dw != null)
- dw.DockingPosition = (Orientation == Orientation.Horizontal ? Alignment.Right : Alignment.Bottom);
- }
-
- //read next value in config string until next ';'
- string getConfAttrib (string conf, ref int i) {
- int nextI = conf.Substring (i).IndexOf (';');
- string tmp = conf.Substring (i, nextI);
- i += nextI + 1;
- return tmp;
- }
- /// <summary>
- /// Imports the config.
- /// </summary>
- /// <param name="conf">Conf.</param>
- /// <param name="dataSource">Data source for the docked windows</param>
- public void ImportConfig (string conf, object dataSource = null) {
- lock (IFace.UpdateMutex) {
- ClearChildren ();
- stretchedChild = null;
- int i = 0;
- Orientation = (Orientation)Enum.Parse (typeof(Orientation), getConfAttrib (conf, ref i));
- importConfig (conf, ref i, dataSource);
- }
- }
- public string ExportConfig () {
- return Orientation.ToString() + ";" + exportConfig();
- }
- void importConfig (string conf, ref int i, object dataSource) {
- if (conf [i++] != '(')
- return;
- while (i < conf.Length - 4) {
- string sc = conf.Substring (i, 4);
- i += 4;
- switch (sc) {
- case "WIN;":
- DockWindow dw = null;
- string wName = getConfAttrib (conf, ref i);
- try {
- dw = IFace.CreateInstance (wName) as DockWindow;
- } catch {
- dw = new DockWindow (IFace);
- }
-
- dw.Name = wName;
- dw.Width = Measure.Parse (getConfAttrib (conf, ref i));
- dw.Height = Measure.Parse (getConfAttrib (conf, ref i));
- dw.DockingPosition = (Alignment)Enum.Parse (typeof(Alignment), getConfAttrib (conf, ref i));
- dw.savedSlot = Rectangle.Parse (getConfAttrib (conf, ref i));
- dw.wasResizable = Boolean.Parse (getConfAttrib (conf, ref i));
-
- dw.IsDocked = true;
- dw.DataSource = dataSource;
- this.AddChild (dw);
-
- break;
- case "STK;":
- DockStack ds = new DockStack (IFace);
- ds.Width = Measure.Parse (getConfAttrib (conf, ref i));
- ds.Height = Measure.Parse (getConfAttrib (conf, ref i));
- ds.Orientation = (Orientation)Enum.Parse (typeof(Orientation), getConfAttrib (conf, ref i));
-
- this.AddChild (ds);
-
- ds.importConfig (conf, ref i, dataSource);
- break;
- case "SPL;":
- Splitter sp = new Splitter (IFace);
- sp.Width = Measure.Parse (getConfAttrib (conf, ref i));
- sp.Height = Measure.Parse (getConfAttrib (conf, ref i));
- sp.Thickness = int.Parse (getConfAttrib (conf, ref i));
- this.AddChild (sp);
- break;
- }
- char nextC = conf [i++];
- if (nextC == ')')
- break;
- }
- }
- string exportConfig () {
- StringBuilder tmp = new StringBuilder("(");
-
- for (int i = 0; i < Children.Count; i++) {
- if (Children [i] is DockWindow) {
- DockWindow dw = Children [i] as DockWindow;
- tmp.Append (string.Format("WIN;{0};{1};{2};{3};{4};{5};",dw.Name, dw.Width, dw.Height, dw.DockingPosition, dw.savedSlot, dw.wasResizable));
- } else if (Children [i] is DockStack) {
- DockStack ds = Children [i] as DockStack;
- tmp.Append (string.Format("STK;{0};{1};{2};{3}", ds.Width, ds.Height, ds.Orientation, ds.exportConfig()));
- } else if (Children [i] is Splitter) {
- Splitter sp = Children [i] as Splitter;
- tmp.Append (string.Format("SPL;{0};{1};{2};", sp.Width, sp.Height, sp.Thickness));
- }
- if (i < Children.Count - 1)
- tmp.Append ("|");
- }
-
- tmp.Append (")");
- return tmp.ToString ();
- }
- }
-}
-
+++ /dev/null
-//
-// DockingView.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.Xml.Serialization;
-
-namespace Crow
-{
- public class DockWindow : Window
- {
- #region CTOR
- public DockWindow () {}
- public DockWindow (Interface iface) : base (iface) {}
- #endregion
-
- int undockThreshold = 10;
- bool isDocked = false;
- Alignment docking = Alignment.Undefined;
-
- Point undockingMousePosOrig; //mouse pos when docking was donne, use for undocking on mouse move
- internal Rectangle savedSlot; //last undocked slot recalled when view is undocked
- internal bool wasResizable;
-
- public bool IsDocked {
- get { return isDocked; }
- set {
- if (isDocked == value)
- return;
- isDocked = value;
- NotifyValueChanged ("IsDocked", isDocked);
- NotifyValueChanged ("IsFloating", !isDocked);
- }
- }
- [XmlIgnore] public bool IsFloating { get { return !isDocked; }}
-
- public Alignment DockingPosition {
- get { return docking; }
- set {
- if (docking == value)
- return;
- docking = value;
- NotifyValueChanged ("DockingPosition", DockingPosition);
- }
- }
- public override bool PointIsIn (ref Point m)
- {
- if (!base.PointIsIn(ref m))
- return false;
-
- Group p = Parent as Group;
- if (p != null) {
- lock (p.Children) {
- for (int i = p.Children.Count - 1; i >= 0; i--) {
- if (p.Children [i] == this)
- break;
- if (p.Children [i].IsDragged)
- continue;
- if (p.Children [i].Slot.ContainsOrIsEqual (m)) {
- return false;
- }
- }
- }
- }
- return Slot.ContainsOrIsEqual(m);
- }
-
- public override void onMouseMove (object sender, MouseMoveEventArgs e)
- {
-// if (this.HasFocus && e.Mouse.IsButtonDown (MouseButton.Left) && IsDocked) {
-// if (Math.Abs (e.Position.X - undockingMousePosOrig.X) > 10 ||
-// Math.Abs (e.Position.X - undockingMousePosOrig.X) > 10)
-// Undock ();
-// }
-
- if (this.HasFocus && e.Mouse.IsButtonDown (MouseButton.Left) && IsDocked)
- CheckUndock (e.Position);
-
- base.onMouseMove (sender, e);
- }
- public override void onMouseDown (object sender, MouseButtonEventArgs e)
- {
- e.Handled = true;
- base.onMouseDown (sender, e);
-
- if (this.HasFocus && IsDocked && e.Button == MouseButton.Left)
- undockingMousePosOrig = e.Position;
- }
- public bool CheckUndock (Point mousePos) {
- //if (DockingPosition == Alignment.Center)
- // return false;
- Console.WriteLine ($"{mousePos.X},{mousePos.Y}");
- if (Math.Abs (mousePos.X - undockingMousePosOrig.X) < undockThreshold ||
- Math.Abs (mousePos.X - undockingMousePosOrig.X) < undockThreshold)
- return false;
- Undock ();
- return true;
- }
-
- protected override void onStartDrag (object sender, DragDropEventArgs e)
- {
- base.onStartDrag (sender, e);
-
- undockingMousePosOrig = IFace.Mouse.Position;
- }
- protected override void onDrop (object sender, DragDropEventArgs e)
- {
- if (!isDocked && DockingPosition != Alignment.Undefined && e.DropTarget is DockStack)
- Dock (e.DropTarget as DockStack);
- base.onDrop (sender, e);
- }
- public void Undock () {
- lock (IFace.UpdateMutex) {
- DockStack ds = Parent as DockStack;
- ds.Undock (this);
-
- IFace.AddWidget (this);
-
- Left = savedSlot.Left;
- Top = savedSlot.Top;
- Width = savedSlot.Width;
- Height = savedSlot.Height;
-
- IsDocked = false;
- DockingPosition = Alignment.Undefined;
- Resizable = wasResizable;
- }
- }
-
- public void Dock (DockStack target){
- lock (IFace.UpdateMutex) {
- IsDocked = true;
- //undockingMousePosOrig = lastMousePos;
- savedSlot = this.LastPaintedSlot;
- wasResizable = Resizable;
- Resizable = false;
- LastSlots = LastPaintedSlot = Slot = default(Rectangle);
- Left = Top = 0;
-
- IFace.RemoveWidget (this);
-
- target.Dock (this);
- }
- }
-
- protected override void close ()
- {
- if (isDocked)
- Undock ();
- base.close ();
- }
- }
-}
-
+++ /dev/null
-// Copyright (c) 2019 Bruyère Jean-Philippe jp_bruyere@hotmail.com
-//
-// This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT)
-
-using System;
-using System.ComponentModel;
-
-namespace Crow
-{
- /// <summary>
- /// Convenient widget for selecting value from enum
- /// </summary>
- public class EnumSelector : GenericStack
- {
- #region CTOR
- protected EnumSelector () : base(){}
- public EnumSelector (Interface iface) : base(iface){}
- #endregion
-
- #region private fields
- Enum enumValue;
- Type enumType;
- #endregion
-
- #region public properties
- /// <summary>
- /// use to define the colors of the 3d border
- /// </summary>
- [DefaultValue(null)]
- public virtual Enum EnumValue {
- get { return enumValue; }
- set {
- if (enumValue == value)
- return;
-
- enumValue = value;
-
- if (enumValue != null) {
- if (enumType != enumValue.GetType ()) {
- ClearChildren ();
- enumType = enumValue.GetType ();
- foreach (string en in enumType.GetEnumNames ()) {
- RadioButton rb = new RadioButton (IFace);
- rb.Caption = en;
- if (enumValue.ToString() == en)
- rb.IsChecked = true;
- rb.Checked += (sender, e) => (((RadioButton)sender).Parent as EnumSelector).EnumValue = (Enum)Enum.Parse (enumType, (sender as RadioButton).Caption);
- AddChild (rb);
- RegisterForLayouting (LayoutingType.All);
- }
- }
- } else
- ClearChildren ();
-
- NotifyValueChanged ("EnumValue", enumValue);
- RegisterForRedraw ();
- }
- }
- #endregion
-
- }
-}
-
+++ /dev/null
-//
-// Expandable.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.ComponentModel;
-using System.Xml.Serialization;
-
-namespace Crow
-{
- /// <summary>
- /// templated control whose content can be hidden and shown on demand
- /// </summary>
- public class Expandable : TemplatedContainer
- {
- #region CTOR
- protected Expandable() : base(){}
- public Expandable (Interface iface) : base(iface){}
- #endregion
-
- #region Private fields
- bool _isExpanded;
- string image;
- #endregion
-
- #region Event Handlers
- /// <summary>
- /// Occurs when control is expanded.
- /// </summary>
- public event EventHandler Expand;
- /// <summary>
- /// Occurs when control is collapsed.
- /// </summary>
- public event EventHandler Collapse;
- #endregion
-
- public BooleanTestOnInstance GetIsExpandable;
-
- /// <summary>
- /// mouse click event handler for easy expand triggering in IML
- /// </summary>
- public void onClickForExpand (object sender, MouseButtonEventArgs e)
- {
- IsExpanded = !IsExpanded;
- }
-
- #region Public properties
- [DefaultValue("#Crow.Icons.expandable.svg")]
- public string Image {
- get { return image; }
- set {
- if (image == value)
- return;
- image = value;
- NotifyValueChanged ("Image", image);
- }
- }
- [DefaultValue(false)]
- public bool IsExpanded
- {
- get { return _isExpanded; }
- set
- {
- if (value == _isExpanded)
- return;
-
- _isExpanded = value;
-
- bool isExp = IsExpandable;
- NotifyValueChanged ("IsExpandable", isExp);
- if (!isExp)
- _isExpanded = false;
-
- NotifyValueChanged ("IsExpanded", _isExpanded);
-
- if (_isExpanded)
- onExpand (this, null);
- else
- onCollapse (this, null);
- }
- }
- [XmlIgnore]public bool IsExpandable {
- get {
- try {
- return GetIsExpandable == null ? true : GetIsExpandable (this);
- } catch (Exception ex) {
- System.Diagnostics.Debug.WriteLine ("Not Expandable error: " + ex.ToString ());
- return false;
- }
- }
- }
- #endregion
-
- public virtual void onExpand(object sender, EventArgs e)
- {
- if (_contentContainer != null)
- _contentContainer.Visible = true;
-
- Expand.Raise (this, e);
- }
- public virtual void onCollapse(object sender, EventArgs e)
- {
- if (_contentContainer != null)
- _contentContainer.Visible = false;
-
- Collapse.Raise (this, e);
- }
- }
-}
+++ /dev/null
-//
-// FileDialog.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.Xml.Serialization;
-using System.ComponentModel;
-using System.IO;
-using System.Collections.Generic;
-using System.Diagnostics;
-using System.Linq;
-using System.Text.RegularExpressions;
-
-namespace Crow
-{
- /// <summary>
- /// templated control for selecting files
- /// </summary>
- public class FileDialog: Window
- {
- #region CTOR
- protected FileDialog() : base(){}
- public FileDialog (Interface iface) : base(iface){}
- #endregion
-
- string searchPattern, curDir, _selectedFile, _selectedDir;
- bool showHidden, showFiles;
-
- #region events
- public event EventHandler OkClicked;
- #endregion
-
- public string SelectedFileFullPath {
- get { return Path.Combine (SelectedDirectory, SelectedFile); }
- }
- [DefaultValue("/home")]
- public virtual string CurrentDirectory {
- get { return curDir; }
- set {
- if (curDir == value)
- return;
- curDir = value;
- NotifyValueChanged ("CurrentDirectory", curDir);
- SelectedDirectory = curDir;
- }
- }
-
- [DefaultValue("*")]
- public virtual string SearchPattern {
- get { return searchPattern; }
- set {
- if (searchPattern == value)
- return;
- searchPattern = value;
- NotifyValueChanged ("SearchPattern", searchPattern);
-
- }
- }
- [DefaultValue(false)]
- public virtual bool ShowHidden {
- get { return showHidden; }
- set {
- if (showHidden == value)
- return;
- showHidden = value;
- NotifyValueChanged ("ShowHidden", showHidden);
- }
- }
- [DefaultValue(true)]
- public virtual bool ShowFiles {
- get { return showFiles; }
- set {
- if (showFiles == value)
- return;
- showFiles = value;
- NotifyValueChanged ("ShowFiles", showFiles);
- }
- }
- public string SelectedFile {
- get { return _selectedFile; }
- set {
- if (value == _selectedFile)
- return;
- _selectedFile = value;
- NotifyValueChanged ("SelectedFile", _selectedFile);
- }
- }
- public string SelectedDirectory {
- get { return _selectedDir; }
- set {
- if (value == _selectedDir)
- return;
- _selectedDir = value;
- NotifyValueChanged ("SelectedDirectory", _selectedDir);
- }
- }
-
- public void onFVSelectedItemChanged (object sender, SelectionChangeEventArgs e){
- if (e.NewValue != null) {
- if (File.GetAttributes (e.NewValue.ToString ()).HasFlag (FileAttributes.Directory)) {
- SelectedDirectory = e.NewValue.ToString ();
- SelectedFile = "";
- } else {
- SelectedDirectory = Path.GetDirectoryName (e.NewValue.ToString ());
- SelectedFile = Path.GetFileName (e.NewValue.ToString ());
- }
- }
- }
- public void onDVSelectedItemChanged (object sender, SelectionChangeEventArgs e){
- if (e.NewValue != null)
- SelectedDirectory = e.NewValue.ToString();
- }
- public void goUpDirClick (object sender, MouseButtonEventArgs e){
- string root = Directory.GetDirectoryRoot(CurrentDirectory);
- if (CurrentDirectory == root)
- return;
- CurrentDirectory = Directory.GetParent(CurrentDirectory).FullName;
- }
- void onFileSelect(object sender, MouseButtonEventArgs e){
- if (string.IsNullOrEmpty (SelectedFile))
- CurrentDirectory = SelectedDirectory;
- else {
- OkClicked.Raise (this, null);
- IFace.DeleteWidget (this);
- }
- }
- void onCancel(object sender, MouseButtonEventArgs e){
- IFace.DeleteWidget (this);
- }
-
- }
-}
-
+++ /dev/null
-//
-// GenericStack.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.ComponentModel;
-using System.Diagnostics;
-using System.Xml.Serialization;
-using System;
-using System.Linq;
-
-namespace Crow
-{
- /// <summary>
- /// group container that stacked its children horizontally or vertically
- /// </summary>
- public class GenericStack : Group
- {
- #region CTOR
- protected GenericStack() : base(){}
- public GenericStack(Interface iface) : base(iface){}
- #endregion
-
- #region Private fields
- int _spacing;
- Orientation _orientation;
- #endregion
-
- #region Public Properties
- [DefaultValue(2)]
- public int Spacing
- {
- get { return _spacing; }
- set {
- if (_spacing == value)
- return;
- _spacing = value;
- NotifyValueChanged ("Spacing", Spacing);
- RegisterForLayouting (LayoutingType.Sizing|LayoutingType.ArrangeChildren);
- }
- }
- [DefaultValue(Orientation.Horizontal)]
- public virtual Orientation Orientation
- {
- get { return _orientation; }
- set { _orientation = value; }
- }
- #endregion
-
- #region GraphicObject Overrides
- public override bool ArrangeChildren { get { return true; } }
- public override void ChildrenLayoutingConstraints (ref LayoutingType layoutType)
- {
- //Prevent child repositionning in the direction of stacking
- if (Orientation == Orientation.Horizontal)
- layoutType &= (~LayoutingType.X);
- else
- layoutType &= (~LayoutingType.Y);
- }
- protected override int measureRawSize (LayoutingType lt)
- {
- int totSpace = Math.Max(0, Spacing * (Children.Count (c => c.Visible) - 1));
- if (lt == LayoutingType.Width) {
- if (Orientation == Orientation.Horizontal)
- return contentSize.Width + totSpace + 2 * Margin;
- }else if (Orientation == Orientation.Vertical)
- return contentSize.Height + totSpace + 2 * Margin;
-
- return base.measureRawSize (lt);
- }
- public virtual void ComputeChildrenPositions()
- {
- int d = 0;
- if (Orientation == Orientation.Horizontal) {
- foreach (Widget c in Children) {
- if (!c.Visible)
- continue;
- c.Slot.X = d;
- d += c.Slot.Width + Spacing;
- }
- } else {
- foreach (Widget c in Children) {
- if (!c.Visible)
- continue;
- c.Slot.Y = d;
- d += c.Slot.Height + Spacing;
- }
- }
- IsDirty = true;
- }
- Widget stretchedGO = null;
- public override bool UpdateLayout (LayoutingType layoutType)
- {
- RegisteredLayoutings &= (~layoutType);
-
- if (layoutType == LayoutingType.ArrangeChildren) {
- //allow 1 child to have size to 0 if stack has fixed or streched size policy,
- //this child will occupy remaining space
- //if stack size policy is Fit, no child may have stretch enabled
- //in the direction of stacking.
- ComputeChildrenPositions ();
-
- //if no layouting remains in queue for item, registre for redraw
- if (RegisteredLayoutings == LayoutingType.None && IsDirty)
- IFace.EnqueueForRepaint (this);
-
- return true;
- }
-
- return base.UpdateLayout(layoutType);
- }
-
- void adjustStretchedGo (LayoutingType lt){
- if (stretchedGO == null)
- return;
- if (lt == LayoutingType.Width) {
- int newW = Math.Max (
- this.ClientRectangle.Width - contentSize.Width - Spacing * (Children.Count - 1),
- stretchedGO.MinimumSize.Width);
- if (stretchedGO.MaximumSize.Width > 0)
- newW = Math.Min (newW, stretchedGO.MaximumSize.Width);
- if (newW != stretchedGO.Slot.Width) {
- stretchedGO.Slot.Width = newW;
- stretchedGO.IsDirty = true;
- #if DEBUG_LAYOUTING
- Debug.WriteLine ("\tAdjusting Width of " + stretchedGO.ToString());
- #endif
- stretchedGO.LayoutChanged -= OnChildLayoutChanges;
- stretchedGO.OnLayoutChanges (LayoutingType.Width);
- stretchedGO.LayoutChanged += OnChildLayoutChanges;
- stretchedGO.LastSlots.Width = stretchedGO.Slot.Width;
- }
- } else {
- int newH = Math.Max (
- this.ClientRectangle.Height - contentSize.Height - Spacing * (Children.Count - 1),
- stretchedGO.MinimumSize.Height);
- if (stretchedGO.MaximumSize.Height > 0)
- newH = Math.Min (newH, stretchedGO.MaximumSize.Height);
- if (newH != stretchedGO.Slot.Height) {
- stretchedGO.Slot.Height = newH;
- stretchedGO.IsDirty = true;
- #if DEBUG_LAYOUTING
- Debug.WriteLine ("\tAdjusting Height of " + stretchedGO.ToString());
- #endif
- stretchedGO.LayoutChanged -= OnChildLayoutChanges;
- stretchedGO.OnLayoutChanges (LayoutingType.Height);
- stretchedGO.LayoutChanged += OnChildLayoutChanges;
- stretchedGO.LastSlots.Height = stretchedGO.Slot.Height;
- }
- }
- }
-
- public override void OnChildLayoutChanges (object sender, LayoutingEventArgs arg)
- {
- Widget go = sender as Widget;
- //Debug.WriteLine ("child layout change: " + go.LastSlots.ToString() + " => " + go.Slot.ToString());
- switch (arg.LayoutType) {
- case LayoutingType.Width:
- if (Orientation == Orientation.Horizontal) {
- if (go.Width == Measure.Stretched) {
- if (stretchedGO == null && Width != Measure.Fit)
- stretchedGO = go;
- else if (stretchedGO != go) {
- go.Slot.Width = 0;
- go.Width = Measure.Fit;
- return;
- }
- } else
- contentSize.Width += go.Slot.Width - go.LastSlots.Width;
-
- adjustStretchedGo (LayoutingType.Width);
-
- if (Width == Measure.Fit)
- this.RegisterForLayouting (LayoutingType.Width);
-
- this.RegisterForLayouting (LayoutingType.ArrangeChildren);
- return;
- }
- break;
- case LayoutingType.Height:
- if (Orientation == Orientation.Vertical) {
- if (go.Height == Measure.Stretched) {
- if (stretchedGO == null && Height != Measure.Fit)
- stretchedGO = go;
- else if (stretchedGO != go){
- go.Slot.Height = 0;
- go.Height = Measure.Fit;
- return;
- }
- } else
- contentSize.Height += go.Slot.Height - go.LastSlots.Height;
-
- adjustStretchedGo (LayoutingType.Height);
-
- if (Height == Measure.Fit)
- this.RegisterForLayouting (LayoutingType.Height);
-
- this.RegisterForLayouting (LayoutingType.ArrangeChildren);
- return;
- }
- break;
- }
- base.OnChildLayoutChanges (sender, arg);
- }
- #endregion
-
- public override void RemoveChild (Widget child)
- {
- if (child != stretchedGO) {
- if (Orientation == Orientation.Horizontal)
- contentSize.Width -= child.LastSlots.Width;
- else
- contentSize.Height -= child.LastSlots.Height;
- }
- base.RemoveChild (child);
- if (child == stretchedGO) {
- stretchedGO = null;
- RegisterForLayouting (LayoutingType.Sizing);
- }else if (Orientation == Orientation.Horizontal)
- adjustStretchedGo (LayoutingType.Width);
- else
- adjustStretchedGo (LayoutingType.Height);
- }
-
- public override void ClearChildren ()
- {
- base.ClearChildren ();
- stretchedGO = null;
- }
- }
-}
+++ /dev/null
-//
-// GraduatedSlider.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.Linq;
-using System.Text;
-using Crow.Cairo;
-using System.Xml.Serialization;
-
-namespace Crow
-{
- [DesignIgnore]
- public class GraduatedSlider : Slider
- {
- #region CTOR
- protected GraduatedSlider() : base(){}
- public GraduatedSlider(Interface iface) : base(iface)
- {}
-// public GraduatedSlider(double minimum, double maximum, double step)
-// : base()
-// {
-// Minimum = minimum;
-// Maximum = maximum;
-// SmallIncrement = step;
-// LargeIncrement = step * 5;
-// }
- #endregion
-
- protected override void DrawGraduations(Context gr, PointD pStart, PointD pEnd)
- {
- Rectangle r = ClientRectangle;
- Foreground.SetAsSource (gr);
-
- gr.LineWidth = 2;
- gr.MoveTo(pStart);
- gr.LineTo(pEnd);
-
- gr.Stroke();
- gr.LineWidth = 1;
-
- double sst = unity * SmallIncrement;
- double bst = unity * LargeIncrement;
-
-
- PointD vBar = new PointD(0, sst);
- for (double x = Minimum; x <= Maximum - Minimum; x += SmallIncrement)
- {
- double lineLength = r.Height / 3;
- if (x % LargeIncrement != 0)
- lineLength /= 3;
- PointD p = new PointD(pStart.X + x * unity, pStart.Y);
- gr.MoveTo(p);
- gr.LineTo(new PointD(p.X, p.Y + lineLength));
- }
- gr.Stroke();
- }
- }
-}
+++ /dev/null
-//
-// Grid.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.Diagnostics;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Xml.Serialization;
-using System.ComponentModel;
-
-namespace Crow
-{
- /// <summary>
- /// Simple grid container
- /// Allow symetric placement of children on a grid,
- /// excedental child (above grid sizing) are ignored
- /// and invisible child keep their place in the grid
- /// </summary>
- public class Grid : Group
- {
- #region CTOR
- protected Grid () : base(){}
- public Grid(Interface iface) : base(iface)
- {
- }
- #endregion
-
- #region Private fields
- int _spacing;
- int _columnCount;
- int _rowCount;
- #endregion
-
- #region Public Properties
- [DefaultValue(2)]
- public int Spacing
- {
- get { return _spacing; }
- set { _spacing = value; }
- }
- [DefaultValue(2)]
- public virtual int ColumnCount
- {
- get { return _columnCount; }
- set {
- if (_columnCount == value)
- return;
-
- _columnCount = value;
-
- NotifyValueChanged ("ColumnCount", ColumnCount);
- this.RegisterForLayouting (LayoutingType.ArrangeChildren);
- }
- }
- [DefaultValue(2)]
- public virtual int RowCount
- {
- get { return _rowCount; }
- set {
- if (_rowCount == value)
- return;
-
- _rowCount = value;
-
- NotifyValueChanged ("RowCount", RowCount);
- this.RegisterForLayouting (LayoutingType.ArrangeChildren);
- }
- }
- public virtual int CaseWidth {
- get { return (Slot.Width - (ColumnCount - 1) * Spacing) / ColumnCount; }
- }
- public virtual int CaseHeight {
- get { return (Slot.Height - (RowCount - 1) * Spacing) / RowCount; }
- }
-
- #endregion
-
- #region GraphicObject Overrides
-// protected override Size measureRawSize ()
-// {
-// Size tmp = new Size ();
-//
-// foreach (GraphicObject c in Children.Where(ch=>ch.Visible)) {
-// tmp.Width = Math.Max (tmp.Width, c.Slot.Width);
-// tmp.Height = Math.Max (tmp.Height, c.Slot.Height);
-// }
-//
-// tmp.Width *= (ColumnCount - 1) * Spacing / ColumnCount;;
-// tmp.Height *= (RowCount - 1) * Spacing / RowCount;
-// tmp.Width += 2 * Margin;
-// tmp.Height += 2 * Margin;
-//
-// return tmp;
-// }
- public override void ChildrenLayoutingConstraints (ref LayoutingType layoutType)
- {
- //Prevent child repositionning
- layoutType &= (~LayoutingType.Positioning);
- }
- public override bool ArrangeChildren { get { return true; } }
- public virtual void ComputeChildrenPositions()
- {
- int slotWidth = CaseWidth;
- int slotHeight = CaseHeight;
- for (int curY = 0; curY < RowCount; curY++) {
- for (int curX = 0; curX < ColumnCount; curX++) {
- int idx = curY * ColumnCount + curX;
- if (idx >= Children.Count)
- return;
- Widget c = Children [idx];
- if (!c.Visible)
- continue;
- c.Slot.X = curX * (slotWidth + Spacing);
- c.Slot.Y = curY * (slotHeight + Spacing);
- //c.Slot.Width = slotWidth;
- //c.Slot.Height = slotHeight;
- }
- }
- IsDirty = true;
- }
- public override void OnChildLayoutChanges (object sender, LayoutingEventArgs arg)
- {
- //base.OnChildLayoutChanges (sender, arg);
- }
-
- public override bool UpdateLayout (LayoutingType layoutType)
- {
- RegisteredLayoutings &= (~layoutType);
-
- if (layoutType == LayoutingType.ArrangeChildren) {
-
- ComputeChildrenPositions ();
-
- //if no layouting remains in queue for item, registre for redraw
- if (RegisteredLayoutings == LayoutingType.None && IsDirty)
- IFace.EnqueueForRepaint (this);
-
- return true;
- }
-
- return base.UpdateLayout(layoutType);
- }
- #endregion
-
-
- }
-}
+++ /dev/null
-//
-// Group.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 Crow.Cairo;
-using System.Diagnostics;
-using System.Reflection;
-using System.Threading;
-
-
-namespace Crow
-{
- public class Group : Widget
- {
- #if DESIGN_MODE
- public override bool FindByDesignID(string designID, out Widget go){
- go = null;
- if (base.FindByDesignID (designID, out go))
- return true;
- childrenRWLock.EnterReadLock ();
- foreach (Widget w in Children) {
- if (!w.FindByDesignID (designID, out go))
- continue;
- childrenRWLock.ExitReadLock ();
- return true;
- }
- childrenRWLock.ExitReadLock ();
- return false;
- }
- public override void getIML (System.Xml.XmlDocument doc, System.Xml.XmlNode parentElem)
- {
- if (this.design_isTGItem)
- return;
- base.getIML (doc, parentElem);
- foreach (Widget g in Children) {
- g.getIML (doc, parentElem.LastChild);
- }
- }
- #endif
-
- protected ReaderWriterLockSlim childrenRWLock = new ReaderWriterLockSlim(LockRecursionPolicy.SupportsRecursion);
-
- #region CTOR
- public Group () : base() {}
- public Group(Interface iface) : base(iface){}
- #endregion
-
- #region EVENT HANDLERS
- public event EventHandler<EventArgs> ChildrenCleared;
- #endregion
-
- internal Widget largestChild = null;
- internal Widget tallestChild = null;
-
- bool _multiSelect = false;
- List<Widget> children = new List<Widget>();
-
- public virtual List<Widget> Children {
- get { return children; }
- }
- [DefaultValue(false)]
- public bool MultiSelect
- {
- get { return _multiSelect; }
- set { _multiSelect = value; }
- }
- public virtual void AddChild(Widget g){
- childrenRWLock.EnterWriteLock();
-
- g.Parent = this;
- Children.Add (g);
-
- childrenRWLock.ExitWriteLock();
-
- g.RegisteredLayoutings = LayoutingType.None;
- g.LayoutChanged += OnChildLayoutChanges;
- g.RegisterForLayouting (LayoutingType.Sizing | LayoutingType.ArrangeChildren);
- }
- public virtual void RemoveChild(Widget child)
- {
- child.LayoutChanged -= OnChildLayoutChanges;
- //check if HoverWidget is removed from Tree
- if (IFace.HoverWidget != null) {
- if (this.Contains (IFace.HoverWidget))
- IFace.HoverWidget = null;
- }
-
- childrenRWLock.EnterWriteLock ();
-
- Children.Remove(child);
- child.Parent = null;
-
- childrenRWLock.ExitWriteLock ();
-
- if (child == largestChild && Width == Measure.Fit)
- searchLargestChild ();
- if (child == tallestChild && Height == Measure.Fit)
- searchTallestChild ();
-
- this.RegisterForLayouting (LayoutingType.Sizing | LayoutingType.ArrangeChildren);
-
- }
- public virtual void DeleteChild(Widget child)
- {
- RemoveChild (child);
- child.Dispose ();
- }
- public virtual void InsertChild (int idx, Widget g) {
- childrenRWLock.EnterWriteLock ();
-
- g.Parent = this;
- Children.Insert (idx, g);
-
- childrenRWLock.ExitWriteLock ();
-
- g.RegisteredLayoutings = LayoutingType.None;
- g.LayoutChanged += OnChildLayoutChanges;
- g.RegisterForLayouting (LayoutingType.Sizing | LayoutingType.ArrangeChildren);
- }
- public virtual void RemoveChild (int idx) {
- RemoveChild (children[idx]);
- }
- public virtual void DeleteChild (int idx) {
- DeleteChild (children[idx]);
- }
- public virtual void ClearChildren()
- {
- childrenRWLock.EnterWriteLock ();
-
- while (Children.Count > 0) {
- Widget g = Children [Children.Count - 1];
- g.LayoutChanged -= OnChildLayoutChanges;
- Children.RemoveAt (Children.Count - 1);
- g.Dispose ();
- }
-
- childrenRWLock.ExitWriteLock ();
-
- resetChildrenMaxSize ();
-
- this.RegisterForLayouting (LayoutingType.Sizing);
- ChildrenCleared.Raise (this, new EventArgs ());
- }
- public override void OnDataSourceChanged (object sender, DataSourceChangeEventArgs e)
- {
- base.OnDataSourceChanged (this, e);
-
- childrenRWLock.EnterReadLock ();
- foreach (Widget g in Children) {
- if (g.localDataSourceIsNull & g.localLogicalParentIsNull)
- g.OnDataSourceChanged (g, e);
- }
- childrenRWLock.ExitReadLock ();
- }
-
- public void putWidgetOnTop(Widget w)
- {
- if (Children.Contains(w))
- {
- childrenRWLock.EnterWriteLock ();
-
- Children.Remove (w);
- Children.Add (w);
-
- childrenRWLock.ExitWriteLock ();
- }
- }
- public void putWidgetOnBottom(Widget w)
- {
- if (Children.Contains(w))
- {
- childrenRWLock.EnterWriteLock ();
-
- Children.Remove (w);
- Children.Insert (0, w);
-
- childrenRWLock.ExitWriteLock ();
- }
- }
-
- #region GraphicObject overrides
-
- public override Widget FindByName (string nameToFind)
- {
- if (Name == nameToFind)
- return this;
- Widget tmp = null;
-
- childrenRWLock.EnterReadLock ();
-
- foreach (Widget w in Children) {
- tmp = w.FindByName (nameToFind);
- if (tmp != null)
- break;
- }
-
- childrenRWLock.ExitReadLock ();
-
- return tmp;
- }
- public override bool Contains (Widget goToFind)
- {
- foreach (Widget w in Children) {
- if (w == goToFind)
- return true;
- if (w.Contains (goToFind))
- return true;
- }
- return false;
- }
- protected override int measureRawSize (LayoutingType lt)
- {
- if (Children.Count > 0) {
- if (lt == LayoutingType.Width) {
- if (largestChild == null)
- searchLargestChild ();
- if (largestChild == null) {
- //if still null, not possible to determine a width
- //because all children are stretched, force first one to fit
- Children [0].Width = Measure.Fit;
- return -1;//cancel actual sizing to let child computation take place
- }
- } else {
- if (tallestChild == null)
- searchTallestChild ();
- if (tallestChild == null) {
- Children [0].Height = Measure.Fit;
- return -1;
- }
- }
- }
- return base.measureRawSize (lt);
- }
-
- public override void OnLayoutChanges (LayoutingType layoutType)
- {
- base.OnLayoutChanges (layoutType);
-
- childrenRWLock.EnterReadLock ();
- //position smaller objects in group when group size is fit
- switch (layoutType) {
- case LayoutingType.Width:
- foreach (Widget c in Children) {
- if (c.Width.IsRelativeToParent)
- c.RegisterForLayouting (LayoutingType.Width);
- else
- c.RegisterForLayouting (LayoutingType.X);
- }
- break;
- case LayoutingType.Height:
- foreach (Widget c in Children) {
- if (c.Height.IsRelativeToParent)
- c.RegisterForLayouting (LayoutingType.Height);
- else
- c.RegisterForLayouting (LayoutingType.Y);
- }
- break;
- }
- childrenRWLock.ExitReadLock ();
- }
- protected override void onDraw (Context gr)
- {
- base.onDraw (gr);
-
- gr.Save ();
-
- if (ClipToClientRect) {
- //clip to client zone
- CairoHelpers.CairoRectangle (gr, ClientRectangle, CornerRadius);
- gr.Clip ();
- }
-
- childrenRWLock.EnterReadLock ();
-
- for (int i = 0; i < Children.Count; i++)
- Children[i].Paint (ref gr);
-
- childrenRWLock.ExitReadLock ();
- gr.Restore ();
- }
- protected override void UpdateCache (Context ctx)
- {
- Rectangle rb = Slot + Parent.ClientRectangle.Position;
-
-
- Context gr = new Context (bmp);
-
- if (!Clipping.IsEmpty) {
- for (int i = 0; i < Clipping.NumRectangles; i++)
- gr.Rectangle(Clipping.GetRectangle(i));
- gr.ClipPreserve();
- gr.Operator = Operator.Clear;
- gr.Fill();
- gr.Operator = Operator.Over;
-
- base.onDraw (gr);
-
- if (ClipToClientRect) {
- CairoHelpers.CairoRectangle (gr, ClientRectangle, CornerRadius);
- gr.Clip ();
- }
-
- childrenRWLock.EnterReadLock ();
-
- foreach (Widget c in Children) {
- if (!c.Visible)
- continue;
- if (Clipping.Contains (c.Slot + ClientRectangle.Position) == RegionOverlap.Out)
- continue;
- c.Paint (ref gr);
- }
-
- childrenRWLock.ExitReadLock ();
-
- #if DEBUG_CLIP_RECTANGLE
- /*gr.LineWidth = 1;
- gr.SetSourceColor(Color.DarkMagenta.AdjustAlpha (0.8));
- for (int i = 0; i < Clipping.NumRectangles; i++)
- gr.Rectangle(Clipping.GetRectangle(i));
- gr.Stroke ();*/
- #endif
- }
- gr.Dispose ();
-
- ctx.SetSourceSurface (bmp, rb.X, rb.Y);
- ctx.Paint ();
-
- Clipping.Dispose();
- Clipping = new Region ();
- }
- #endregion
-
- public virtual void OnChildLayoutChanges (object sender, LayoutingEventArgs arg)
- {
- Widget g = sender as Widget;
-
- switch (arg.LayoutType) {
- case LayoutingType.Width:
- if (Width != Measure.Fit)
- return;
- if (g.Slot.Width > contentSize.Width) {
- largestChild = g;
- contentSize.Width = g.Slot.Width;
- } else if (g == largestChild)
- searchLargestChild ();
-
- this.RegisterForLayouting (LayoutingType.Width);
- break;
- case LayoutingType.Height:
- if (Height != Measure.Fit)
- return;
- if (g.Slot.Height > contentSize.Height) {
- tallestChild = g;
- contentSize.Height = g.Slot.Height;
- } else if (g == tallestChild)
- searchTallestChild ();
-
- this.RegisterForLayouting (LayoutingType.Height);
- break;
- }
- }
- //TODO: x,y position should be taken in account for computation of width and height
- void resetChildrenMaxSize(){
- largestChild = null;
- tallestChild = null;
- contentSize = 0;
- }
- void searchLargestChild(){
- #if DEBUG_LAYOUTING
- Debug.WriteLine("\tSearch largest child");
- #endif
- largestChild = null;
- contentSize.Width = 0;
- for (int i = 0; i < Children.Count; i++) {
- if (!Children [i].Visible)
- continue;
- if (children [i].RegisteredLayoutings.HasFlag (LayoutingType.Width))
- continue;
- if (Children [i].Slot.Width > contentSize.Width) {
- contentSize.Width = Children [i].Slot.Width;
- largestChild = Children [i];
- }
- }
- }
- void searchTallestChild(){
- #if DEBUG_LAYOUTING
- Debug.WriteLine("\tSearch tallest child");
- #endif
- tallestChild = null;
- contentSize.Height = 0;
- for (int i = 0; i < Children.Count; i++) {
- if (!Children [i].Visible)
- continue;
- if (children [i].RegisteredLayoutings.HasFlag (LayoutingType.Height))
- continue;
- if (Children [i].Slot.Height > contentSize.Height) {
- contentSize.Height = Children [i].Slot.Height;
- tallestChild = Children [i];
- }
- }
- }
-
-
- #region Mouse handling
- public override void checkHoverWidget (MouseMoveEventArgs e)
- {
- if (IFace.HoverWidget != this) {
- IFace.HoverWidget = this;
- onMouseEnter (this, e);
- }
- for (int i = Children.Count - 1; i >= 0; i--) {
- if (Children[i].MouseIsIn(e.Position))
- {
- Children[i].checkHoverWidget (e);
- return;
- }
- }
- base.checkHoverWidget (e);
- }
-// public override bool PointIsIn (ref Point m)
-// {
-// if (!base.PointIsIn (ref m))
-// return false;
-// if (CurrentInterface.HoverWidget == this)
-// return true;
-// lock (Children) {
-// for (int i = Children.Count - 1; i >= 0; i--) {
-// if (Children [i].Slot.ContainsOrIsEqual (m) && !(bool)CurrentInterface.HoverWidget?.IsOrIsInside(Children[i])) {
-// return false;
-// }
-// }
-// }
-// return true;
-// }
- #endregion
-
- protected override void Dispose (bool disposing)
- {
- if (disposing) {
- foreach (Widget c in children)
- c.Dispose ();
- }
- base.Dispose (disposing);
- }
- }
-}
+++ /dev/null
-//
-// GroupBox.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.Xml.Serialization;
-using System.ComponentModel;
-
-namespace Crow
-{
- /// <summary>
- /// templated container accepting one child
- /// </summary>
- public class GroupBox : TemplatedContainer
- {
- #region CTOR
- protected GroupBox () : base(){}
- public GroupBox(Interface iface) : base(iface){}
- #endregion
- }
-}
+++ /dev/null
-//
-// HorizontalStack.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.Linq;
-using System.Text;
-using System.Xml.Serialization;
-
-namespace Crow
-{
- /// <summary>
- /// group control stacking its children horizontally
- /// </summary>
- public class HorizontalStack : GenericStack
- {
- #region CTOR
- protected HorizontalStack () : base(){}
- public HorizontalStack(Interface iface) : base(iface)
- {
- }
- #endregion
-
- [XmlIgnore]
- public override Orientation Orientation
- {
- get { return Orientation.Horizontal; }
- }
- }
-}
+++ /dev/null
-//
-// HueSelector.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.Xml.Serialization;
-using System.ComponentModel;
-using Crow.Cairo;
-
-namespace Crow
-{
- [DesignIgnore]
- public class HueSelector : ColorSelector
- {
- #region CTOR
- protected HueSelector () : base(){}
- public HueSelector (Interface iface) : base(iface)
- {
- }
- #endregion
-
- Orientation _orientation;
- double hue;
- CursorType cursor = CursorType.Pentagone;
-
- [DefaultValue(Orientation.Horizontal)]
- public virtual Orientation Orientation
- {
- get { return _orientation; }
- set {
- if (_orientation == value)
- return;
- _orientation = value;
- NotifyValueChanged ("Orientation", _orientation);
- RegisterForGraphicUpdate ();
- }
- }
-
- public virtual double Hue {
- get { return hue; }
- set {
- if (hue == value)
- return;
- hue = value;
- notifyHueChanged ();
- updateMousePosFromHue ();
- RegisterForRedraw ();
- }
- }
- protected override void onDraw (Context gr)
- {
- base.onDraw (gr);
-
- RectangleD r = ClientRectangle;
- r.Height -= 4;
- r.Y += 2;
-
- Gradient.Type gt = Gradient.Type.Horizontal;
- if (Orientation == Orientation.Vertical)
- gt = Gradient.Type.Vertical;
-
- Gradient grad = new Gradient (gt);
-
- grad.Stops.Add (new Gradient.ColorStop (0, new Color (1, 0, 0, 1)));
- grad.Stops.Add (new Gradient.ColorStop (0.167, new Color (1, 1, 0, 1)));
- grad.Stops.Add (new Gradient.ColorStop (0.333, new Color (0, 1, 0, 1)));
- grad.Stops.Add (new Gradient.ColorStop (0.5, new Color (0, 1, 1, 1)));
- grad.Stops.Add (new Gradient.ColorStop (0.667, new Color (0, 0, 1, 1)));
- grad.Stops.Add (new Gradient.ColorStop (0.833, new Color (1, 0, 1, 1)));
- grad.Stops.Add (new Gradient.ColorStop (1, new Color (1, 0, 0, 1)));
-
- grad.SetAsSource (gr, r);
- CairoHelpers.CairoRectangle (gr, r, CornerRadius);
- gr.Fill();
-
- r = ClientRectangle;
-
- switch (cursor) {
- case CursorType.Rectangle:
- if (Orientation == Orientation.Horizontal) {
- r.Width = 5;
- r.X = mousePos.X - 2.5;
- } else {
- r.Height = 5;
- r.Y = mousePos.Y - 2.5;
- }
- CairoHelpers.CairoRectangle (gr, r, 1);
- break;
- case CursorType.Circle:
- if (Orientation == Orientation.Horizontal)
- gr.Arc (mousePos.X, r.Center.Y, 3.5, 0, Math.PI * 2.0);
- else
- gr.Arc (r.Center.X, mousePos.Y, 3.5, 0, Math.PI * 2.0);
- break;
- case CursorType.Pentagone:
- if (Orientation == Orientation.Horizontal) {
- r.Width = 5;
- r.X = mousePos.X - 2.5;
- double y = r.CenterD.Y-r.Height*0.2;
- gr.MoveTo (mousePos.X, y);
- y += r.Height * 0.15;
- gr.LineTo (r.Right, y);
- gr.LineTo (r.Right, r.Bottom-0.5);
- gr.LineTo (r.Left, r.Bottom-0.5);
- gr.LineTo (r.Left, y);
- gr.ClosePath ();
- } else {
- }
- break;
- }
-
- gr.SetSourceColor (Color.Black);
- gr.LineWidth = 2.0;
- gr.StrokePreserve ();
- gr.SetSourceColor (Color.White);
- gr.LineWidth = 1.0;
- gr.Stroke ();
- }
-
- public override void OnLayoutChanges (LayoutingType layoutType)
- {
- base.OnLayoutChanges (layoutType);
-
- if (Orientation == Orientation.Horizontal) {
- if (layoutType == LayoutingType.Width)
- updateMousePosFromHue ();
- } else if (layoutType == LayoutingType.Height)
- updateMousePosFromHue ();
- }
- protected override void updateMouseLocalPos (Point mPos)
- {
- base.updateMouseLocalPos (mPos);
- if (Orientation == Orientation.Horizontal)
- hue = (double)mousePos.X / (double)ClientRectangle.Width;
- else
- hue = (double)mousePos.Y / (double)ClientRectangle.Height;
- notifyHueChanged ();
- RegisterForRedraw ();
- }
- void updateMousePosFromHue(){
- if (Orientation == Orientation.Horizontal)
- mousePos.X = (int)Math.Floor(hue * (double)ClientRectangle.Width);
- else
- mousePos.Y = (int)Math.Floor(hue * (double)ClientRectangle.Height);
- }
- void notifyHueChanged(){
- NotifyValueChanged ("Hue", hue);
- NotifyValueChanged ("HueColor", new SolidColor (Color.FromHSV (hue)));
- }
- }
-}
-
+++ /dev/null
-//
-// ILayoutable.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;
-
-namespace Crow
-{
- public interface ILayoutable
- {
- /// <summary> Parent in the graphic tree </summary>
- ILayoutable Parent { get; set; }
- /// <summary> The logical parent (used mainly for bindings) as opposed
- /// to the parent in the graphic tree </summary>
- ILayoutable LogicalParent { get; set; }
-
- Rectangle ClientRectangle { get; }
- Rectangle getSlot();
-
- bool ArrangeChildren { get; }
- LayoutingType RegisteredLayoutings { get; set; }
- void RegisterForLayouting(LayoutingType layoutType);
- void RegisterClip(Rectangle clip);
- bool UpdateLayout(LayoutingType layoutType);
- bool PointIsIn(ref Point m);
-
- Rectangle ContextCoordinates(Rectangle r);
- Rectangle ScreenCoordinates (Rectangle r);
-
- }
-}
-
+++ /dev/null
-//
-// IMLContainer.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;
-
-namespace Crow
-{
- public class IMLContainer : PrivateContainer
- {
- public IMLContainer () : base()
- {
- }
-
- string path;
-
- public string Path {
- get { return path; }
- set {
- if (path == value)
- return;
- path = value;
- this.SetChild (IFace.CreateInstance (path));
- NotifyValueChanged ("Path", path);
- }
- }
- }
-}
-
+++ /dev/null
-//
-// IValueChange.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;
-
-namespace Crow
-{
- public interface IValueChange
- {
- event EventHandler<ValueChangeEventArgs> ValueChanged;
- }
-}
-
+++ /dev/null
-//
-// Image.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 Crow.Cairo;
-using System.Xml.Serialization;
-using System.ComponentModel;
-using System.Diagnostics;
-
-
-namespace Crow
-{
- /// <summary>
- /// Base widget to display an image. Accepts bitmaps and SVGs.
- /// </summary>
- /// <remarks>
- /// </remarks>
- public class Image : Widget
- {
- Picture _pic;
- string _svgSub;
- bool scaled, keepProps;
- double opacity;
-
- #region Public properties
- /// <summary>
- /// If false, original size will be kept in any case.
- /// </summary>
- [DefaultValue(true)]
- public virtual bool Scaled {
- get { return scaled; }
- set {
- if (scaled == value)
- return;
- scaled = value;
- NotifyValueChanged ("Scaled", scaled);
- if (_pic == null)
- return;
- _pic.Scaled = scaled;
- RegisterForGraphicUpdate ();
- }
- }
- /// <summary>
- /// If image is scaled, proportions will be preserved.
- /// </summary>
- [DefaultValue(true)]
- public virtual bool KeepProportions {
- get { return keepProps; }
- set {
- if (keepProps == value)
- return;
- keepProps = value;
- NotifyValueChanged ("KeepProportions", keepProps);
- if (_pic == null)
- return;
- _pic.KeepProportions = keepProps;
- RegisterForGraphicUpdate ();
- }
- }
- /// <summary>
- /// Image file path, may be on disk or embedded. Accepts bitmaps or SVG drawings.
- /// </summary>
-
- public string Path {
- get { return _pic == null ? "" : _pic.Path; }
- set {
- if (value == Path)
- return;
- try {
- if (string.IsNullOrEmpty(value))
- Picture = null;
- else {
- //lock(IFace.LayoutMutex){
- LoadImage (value);
- //}
- }
- } catch (Exception ex) {
- Debug.WriteLine (ex.Message);
- _pic = null;
- }
- NotifyValueChanged ("Path", Path);
- }
- }
- /// <summary>
- /// Used only for svg images, repaint only node named referenced in SvgSub.
- /// If null, all the svg is rendered
- /// </summary>
-
- public string SvgSub {
- get { return _svgSub; }
- set {
- if (_svgSub == value)
- return;
- _svgSub = value;
- RegisterForGraphicUpdate ();
- }
- }
- /// <summary>
- /// Object holding the image data once loaded, may be used directely to pupulate this control without
- /// specifying a path.
- /// </summary>
-
- public Picture Picture {
- get { return _pic; }
- set {
- if (_pic == value)
- return;
- _pic = value;
- NotifyValueChanged ("Picture", _pic);
- RegisterForGraphicUpdate ();
- }
- }
- /// <summary>
- /// Opacity parameter for the image
- /// </summary>
- // TODO:could be moved in GraphicObject
- [DefaultValue(1.0)]
- public virtual double Opacity {
- get { return opacity; }
- set {
- if (opacity == value)
- return;
- opacity = value;
- NotifyValueChanged ("Faded", opacity);
- RegisterForRedraw ();
- }
- }
- #endregion
-
- #region CTOR
- /// <summary>
- /// Initializes a new instance of the <see cref="Crow.Image"/> class.
- /// </summary>
- protected Image () : base(){}
- /// <summary>
- /// Initializes a new instance of the <see cref="Crow.Image"/> class from code
- /// </summary>
- /// <param name="iface">interface to bound to</param>
- public Image (Interface iface) : base(iface)
- {
- }
- #endregion
-
- #region Image Loading
- public void LoadImage (string path)
- {
- Picture pic;
- if (path.EndsWith (".svg", true, System.Globalization.CultureInfo.InvariantCulture))
- pic = new SvgPicture (path);
- else
- pic = new BmpPicture (path);
-
-
- pic.Scaled = scaled;
- pic.KeepProportions = keepProps;
-
- Picture = pic;
- }
- #endregion
-
- #region GraphicObject overrides
- protected override int measureRawSize (LayoutingType lt)
- {
- if (_pic == null)
- return 2 * Margin;
- //_pic = "#Crow.Images.Icons.IconAlerte.svg";
- //TODO:take scalling in account
- if (lt == LayoutingType.Width)
- return _pic.Dimensions.Width + 2 * Margin;
- else
- return _pic.Dimensions.Height + 2 * Margin;
- }
- protected override void onDraw (Context gr)
- {
- base.onDraw (gr);
-
- if (_pic == null)
- return;
-
- _pic.Paint (gr, ClientRectangle, _svgSub);
-
- if (Opacity<1.0) {
- gr.SetSourceRGBA (0.0, 0.0, 0.0, 1.0-Opacity);
- gr.Operator = Operator.DestOut;
- gr.Rectangle (ClientRectangle);
- gr.Fill ();
- gr.Operator = Operator.Over;
- }
- }
- #endregion
- }
-}
+++ /dev/null
-//
-// Label.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.Linq;
-using System.Diagnostics;
-using Crow.Cairo;
-using System.Text.RegularExpressions;
-using System.Xml.Serialization;
-using System.ComponentModel;
-
-namespace Crow
-{
- public class Label : Widget
- {
- #region CTOR
- protected Label () : base(){}
-
- public Label(Interface iface) : base(iface)
- {
-
- }
-// public Label(string _text)
-// : base()
-// {
-// Text = _text;
-// }
- #endregion
-
- public event EventHandler<TextChangeEventArgs> TextChanged;
-
- public virtual void OnTextChanged(Object sender, TextChangeEventArgs e)
- {
- textMeasureIsUpToDate = false;
- NotifyValueChanged ("Text", Text);
- TextChanged.Raise (this, e);
- }
- //TODO:change protected to private
-
- #region private and protected fields
- string _text = "label";
- Alignment _textAlignment;
- bool horizontalStretch;
- bool verticalStretch;
- bool _selectable;
- bool _multiline;
- Color selBackground;
- Color selForeground;
- Point mouseLocalPos = -1;//mouse coord in widget space, filled only when clicked
- int _currentCol; //0 based cursor position in string
- int _currentLine;
- Point _selBegin = -1; //selection start (row,column)
- Point _selRelease = -1; //selection end (row,column)
- double textCursorPos; //cursor position in cairo units in widget client coord.
- double SelStartCursorPos = -1;
- double SelEndCursorPos = -1;
- bool SelectionInProgress = false;
-
- protected Rectangle rText;
- protected float widthRatio = 1f;
- protected float heightRatio = 1f;
- protected FontExtents fe;
- protected TextExtents te;
- #endregion
-
- [DefaultValue("SteelBlue")]
- public virtual Color SelectionBackground {
- get { return selBackground; }
- set {
- if (value == selBackground)
- return;
- selBackground = value;
- NotifyValueChanged ("SelectionBackground", selBackground);
- RegisterForRedraw ();
- }
- }
- [DefaultValue("White")]
- public virtual Color SelectionForeground {
- get { return selForeground; }
- set {
- if (value == selForeground)
- return;
- selForeground = value;
- NotifyValueChanged ("SelectionForeground", selForeground);
- RegisterForRedraw ();
- }
- }
- [DefaultValue(Alignment.Left)]
- public Alignment TextAlignment
- {
- get { return _textAlignment; }
- set {
- if (value == _textAlignment)
- return;
- _textAlignment = value;
- RegisterForRedraw ();
- NotifyValueChanged ("TextAlignment", _textAlignment);
- }
- }
- [DefaultValue(false)]
- public virtual bool HorizontalStretch {
- get { return horizontalStretch; }
- set {
- if (horizontalStretch == value)
- return;
- horizontalStretch = value;
- RegisterForRedraw ();
- NotifyValueChanged ("HorizontalStretch", horizontalStretch);
- }
- }
- [DefaultValue(false)]
- public virtual bool VerticalStretch {
- get { return verticalStretch; }
- set {
- if (verticalStretch == value)
- return;
- verticalStretch = value;
- RegisterForRedraw ();
- NotifyValueChanged ("VerticalStretch", verticalStretch);
- }
- }
- [DefaultValue("label")]
- public string Text
- {
- get {
- return lines == null ?
- _text : lines.Aggregate((i, j) => i + Interface.LineBreak + j);
- }
- set
- {
- if (string.Equals (value, _text, StringComparison.Ordinal))
- return;
-
- _text = value;
-
- if (string.IsNullOrEmpty(_text))
- _text = "";
-
- lines = getLines;
-
- OnTextChanged (this, new TextChangeEventArgs (Text));
- RegisterForGraphicUpdate ();
- }
- }
- [DefaultValue(false)]
- public bool Selectable
- {
- get { return _selectable; }
- set
- {
- if (value == _selectable)
- return;
- _selectable = value;
- NotifyValueChanged ("Selectable", _selectable);
- SelBegin = -1;
- SelRelease = -1;
- RegisterForRedraw ();
- }
- }
- [DefaultValue(false)]
- public bool Multiline
- {
- get { return _multiline; }
- set
- {
- if (value == _multiline)
- return;
- _multiline = value;
- NotifyValueChanged ("Multiline", _multiline);
- RegisterForGraphicUpdate();
- }
- }
- [DefaultValue(0)]
- public int CurrentColumn{
- get { return _currentCol; }
- set {
- if (value == _currentCol)
- return;
- if (value < 0)
- _currentCol = 0;
- else if (value > lines [_currentLine].Length)
- _currentCol = lines [_currentLine].Length;
- else
- _currentCol = value;
- NotifyValueChanged ("CurrentColumn", _currentCol);
- }
- }
- [DefaultValue(0)]
- public int CurrentLine{
- get { return _currentLine; }
- set {
- if (value == _currentLine)
- return;
- if (value >= lines.Count)
- _currentLine = lines.Count-1;
- else if (value < 0)
- _currentLine = 0;
- else
- _currentLine = value;
- //force recheck of currentCol for bounding
- int cc = _currentCol;
- _currentCol = 0;
- CurrentColumn = cc;
- NotifyValueChanged ("CurrentLine", _currentLine);
- }
- }
- [XmlIgnore]public Point CurrentPosition {
- get { return new Point(_currentCol, CurrentLine); }
- }
- //TODO:using HasFocus for drawing selection cause SelBegin and Release binding not to work
- /// <summary>
- /// Selection begin position in char units
- /// </summary>
- [DefaultValue("-1")]
- public Point SelBegin {
- get {
- return _selBegin;
- }
- set {
- if (value == _selBegin)
- return;
- _selBegin = value;
- NotifyValueChanged ("SelBegin", _selBegin);
- NotifyValueChanged ("SelectedText", SelectedText);
- }
- }
- [DefaultValue("-1")]
- public Point SelRelease {
- get {
- return _selRelease;
- }
- set {
- if (value == _selRelease)
- return;
- _selRelease = value;
- NotifyValueChanged ("SelRelease", _selRelease);
- NotifyValueChanged ("SelectedText", SelectedText);
- }
- }
- /// <summary>
- /// return char at CurrentLine, CurrentColumn
- /// </summary>
- [XmlIgnore]protected Char CurrentChar
- {
- get {
- return lines [CurrentLine] [CurrentColumn];
- }
- }
- /// <summary>
- /// ordered selection start and end positions in char units
- /// </summary>
- [XmlIgnore]protected Point selectionStart
- {
- get {
- return SelRelease < 0 || SelBegin.Y < SelRelease.Y ? SelBegin :
- SelBegin.Y > SelRelease.Y ? SelRelease :
- SelBegin.X < SelRelease.X ? SelBegin : SelRelease;
- }
- }
- [XmlIgnore]public Point selectionEnd
- {
- get {
- return SelRelease < 0 || SelBegin.Y > SelRelease.Y ? SelBegin :
- SelBegin.Y < SelRelease.Y ? SelRelease :
- SelBegin.X > SelRelease.X ? SelBegin : SelRelease;
- }
- }
- [XmlIgnore]public string SelectedText
- {
- get {
-
- if (SelRelease < 0 || SelBegin < 0)
- return "";
- if (selectionStart.Y == selectionEnd.Y)
- return lines [selectionStart.Y].Substring (selectionStart.X, selectionEnd.X - selectionStart.X);
- string tmp = "";
- tmp = lines [selectionStart.Y].Substring (selectionStart.X);
- for (int l = selectionStart.Y + 1; l < selectionEnd.Y; l++) {
- tmp += Interface.LineBreak + lines [l];
- }
- tmp += Interface.LineBreak + lines [selectionEnd.Y].Substring (0, selectionEnd.X);
- return tmp;
- }
- }
- [XmlIgnore]public bool selectionIsEmpty
- { get { return SelRelease < 0; } }
-
- List<string> lines;
- List<string> getLines {
- get {
- return _multiline ?
- Regex.Split (_text, "\r\n|\r|\n|\\\\n").ToList() :
- new List<string>(new string[] { _text });
- }
- }
- /// <summary>
- /// Moves cursor one char to the left.
- /// </summary>
- /// <returns><c>true</c> if move succeed</returns>
- public bool MoveLeft(){
- int tmp = _currentCol - 1;
- if (tmp < 0) {
- if (_currentLine == 0)
- return false;
- CurrentLine--;
- CurrentColumn = int.MaxValue;
- } else
- CurrentColumn = tmp;
- return true;
- }
- /// <summary>
- /// Moves cursor one char to the right.
- /// </summary>
- /// <returns><c>true</c> if move succeed</returns>
- public bool MoveRight(){
- int tmp = _currentCol + 1;
- if (tmp > lines [_currentLine].Length){
- if (CurrentLine == lines.Count - 1)
- return false;
- CurrentLine++;
- CurrentColumn = 0;
- } else
- CurrentColumn = tmp;
- return true;
- }
- public void GotoWordStart(){
- CurrentColumn--;
- //skip white spaces
- while (!char.IsLetterOrDigit (this.CurrentChar) && CurrentColumn > 0)
- CurrentColumn--;
- while (char.IsLetterOrDigit (lines [CurrentLine] [CurrentColumn]) && CurrentColumn > 0)
- CurrentColumn--;
- if (!char.IsLetterOrDigit (this.CurrentChar))
- CurrentColumn++;
- }
- public void GotoWordEnd(){
- //skip white spaces
- if (CurrentColumn >= lines [CurrentLine].Length - 1)
- return;
- while (!char.IsLetterOrDigit (this.CurrentChar) && CurrentColumn < lines [CurrentLine].Length-1)
- CurrentColumn++;
- while (char.IsLetterOrDigit (this.CurrentChar) && CurrentColumn < lines [CurrentLine].Length-1)
- CurrentColumn++;
- if (char.IsLetterOrDigit (this.CurrentChar))
- CurrentColumn++;
- }
- public void DeleteChar()
- {
- if (selectionIsEmpty) {
- if (CurrentColumn == 0) {
- if (CurrentLine == 0 && lines.Count == 1)
- return;
- CurrentLine--;
- CurrentColumn = lines [CurrentLine].Length;
- lines [CurrentLine] += lines [CurrentLine + 1];
- lines.RemoveAt (CurrentLine + 1);
-
- OnTextChanged (this, new TextChangeEventArgs (Text));
- return;
- }
- CurrentColumn--;
- lines [CurrentLine] = lines [CurrentLine].Remove (CurrentColumn, 1);
- } else {
- int linesToRemove = selectionEnd.Y - selectionStart.Y + 1;
- int l = selectionStart.Y;
-
- if (linesToRemove > 0) {
- lines [l] = lines [l].Remove (selectionStart.X, lines [l].Length - selectionStart.X) +
- lines [selectionEnd.Y].Substring (selectionEnd.X, lines [selectionEnd.Y].Length - selectionEnd.X);
- l++;
- for (int c = 0; c < linesToRemove-1; c++)
- lines.RemoveAt (l);
- CurrentLine = selectionStart.Y;
- CurrentColumn = selectionStart.X;
- } else
- lines [l] = lines [l].Remove (selectionStart.X, selectionEnd.X - selectionStart.X);
- CurrentColumn = selectionStart.X;
- SelBegin = -1;
- SelRelease = -1;
- }
- OnTextChanged (this, new TextChangeEventArgs (Text));
- }
- /// <summary>
- /// Insert new string at caret position, should be sure no line break is inside.
- /// </summary>
- /// <param name="str">String.</param>
- protected void Insert(string str)
- {
- if (!selectionIsEmpty)
- this.DeleteChar ();
- if (_multiline) {
- string[] strLines = Regex.Split (str, "\r\n|\r|\n|" + @"\\n").ToArray();
- lines [CurrentLine] = lines [CurrentLine].Insert (CurrentColumn, strLines[0]);
- CurrentColumn += strLines[0].Length;
- for (int i = 1; i < strLines.Length; i++) {
- InsertLineBreak ();
- lines [CurrentLine] = lines [CurrentLine].Insert (CurrentColumn, strLines[i]);
- CurrentColumn += strLines[i].Length;
- }
- } else {
- lines [CurrentLine] = lines [CurrentLine].Insert (CurrentColumn, str);
- CurrentColumn += str.Length;
- }
- OnTextChanged (this, new TextChangeEventArgs (Text));
- }
- /// <summary>
- /// Insert a line break.
- /// </summary>
- protected void InsertLineBreak()
- {
- lines.Insert(CurrentLine + 1, lines[CurrentLine].Substring(CurrentColumn));
- lines [CurrentLine] = lines [CurrentLine].Substring (0, CurrentColumn);
- CurrentLine++;
- CurrentColumn = 0;
- OnTextChanged (this, new TextChangeEventArgs (Text));
- }
- bool textMeasureIsUpToDate = false;
- Size cachedTextSize = default(Size);
-
- #region GraphicObject overrides
- protected override int measureRawSize(LayoutingType lt)
- {
- if (lines == null)
- lines = getLines;
- if (!textMeasureIsUpToDate) {
- using (Context gr = new Context (IFace.surf)) {
- //Cairo.FontFace cf = gr.GetContextFontFace ();
-
- gr.SelectFontFace (Font.Name, Font.Slant, Font.Wheight);
- gr.SetFontSize (Font.Size);
- gr.FontOptions = Interface.FontRenderingOptions;
- gr.Antialias = Interface.Antialias;
-
- fe = gr.FontExtents;
- te = new TextExtents ();
-
- cachedTextSize.Height = (int)Math.Ceiling ((fe.Ascent+fe.Descent) * Math.Max (1, lines.Count)) + Margin * 2;
-
- try {
- for (int i = 0; i < lines.Count; i++) {
- string l = lines[i].Replace ("\t", new String (' ', Interface.TAB_SIZE));
-
- TextExtents tmp = gr.TextExtents (l);
-
- if (tmp.XAdvance > te.XAdvance)
- te = tmp;
- }
- cachedTextSize.Width = (int)Math.Ceiling (te.XAdvance) + Margin * 2;
- textMeasureIsUpToDate = true;
- } catch {
- return -1;
- }
- }
- }
- return lt == LayoutingType.Height ? cachedTextSize.Height : cachedTextSize.Width;
- }
- protected override void onDraw (Context gr)
- {
- base.onDraw (gr);
-
- gr.SelectFontFace (Font.Name, Font.Slant, Font.Wheight);
- gr.SetFontSize (Font.Size);
- gr.FontOptions = Interface.FontRenderingOptions;
- gr.Antialias = Interface.Antialias;
-
- rText = new Rectangle(new Size(
- measureRawSize(LayoutingType.Width), measureRawSize(LayoutingType.Height)));
- rText.Width -= 2 * Margin;
- rText.Height -= 2 * Margin;
-
- widthRatio = 1f;
- heightRatio = 1f;
-
- Rectangle cb = ClientRectangle;
-
- rText.X = cb.X;
- rText.Y = cb.Y;
-
- if (horizontalStretch) {
- widthRatio = (float)cb.Width / (float)rText.Width;
- if (!verticalStretch)
- heightRatio = widthRatio;
- }
-
- if (verticalStretch) {
- heightRatio = (float)cb.Height / (float)rText.Height;
- if (!horizontalStretch)
- widthRatio = heightRatio;
- }
-
- rText.Width = (int)(widthRatio * (float)rText.Width);
- rText.Height = (int)(heightRatio * (float)rText.Height);
-
- switch (TextAlignment)
- {
- case Alignment.TopLeft: //ok
- rText.X = cb.X;
- rText.Y = cb.Y;
- break;
- case Alignment.Top: //ok
- rText.Y = cb.Y;
- rText.X = cb.X + cb.Width / 2 - rText.Width / 2;
- break;
- case Alignment.TopRight: //ok
- rText.Y = cb.Y;
- rText.X = cb.Right - rText.Width;
- break;
- case Alignment.Left://ok
- rText.X = cb.X;
- rText.Y = cb.Y + cb.Height / 2 - rText.Height / 2;
- break;
- case Alignment.Right://ok
- rText.X = cb.X + cb.Width - rText.Width;
- rText.Y = cb.Y + cb.Height / 2 - rText.Height / 2;
- break;
- case Alignment.Bottom://ok
- rText.X = cb.Width / 2 - rText.Width / 2;
- rText.Y = cb.Height - rText.Height;
- break;
- case Alignment.BottomLeft://ok
- rText.X = cb.X;
- rText.Y = cb.Bottom - rText.Height;
- break;
- case Alignment.BottomRight://ok
- rText.Y = cb.Bottom - rText.Height;
- rText.X = cb.Right - rText.Width;
- break;
- case Alignment.Center://ok
- rText.X = cb.X + cb.Width / 2 - rText.Width / 2;
- //rText.Y = cb.Y + cb.Height / 2 - rText.Height / 2;
- rText.Y = cb.Y + (int)Math.Floor((double)cb.Height / 2.0 - (double)rText.Height / 2.0);
- break;
- }
-
- //gr.FontMatrix = new Matrix(widthRatio * (float)Font.Size, 0, 0, heightRatio * (float)Font.Size, 0, 0);
- fe = gr.FontExtents;
-
- #region draw text cursor
- if (HasFocus && Selectable)
- {
- if (mouseLocalPos >= 0)
- {
- computeTextCursor(gr);
-
- if (SelectionInProgress)
- {
- if (SelBegin < 0){
- SelBegin = new Point(CurrentColumn, CurrentLine);
- SelStartCursorPos = textCursorPos;
- SelRelease = -1;
- }else{
- SelRelease = new Point(CurrentColumn, CurrentLine);
- if (SelRelease == SelBegin)
- SelRelease = -1;
- else
- SelEndCursorPos = textCursorPos;
- }
- }else
- computeTextCursorPosition(gr);
- }else
- computeTextCursorPosition(gr);
-
- Foreground.SetAsSource (gr);
- gr.LineWidth = 1.0;
- gr.MoveTo (0.5 + textCursorPos + rText.X, rText.Y + CurrentLine * (fe.Ascent+fe.Descent));
- gr.LineTo (0.5 + textCursorPos + rText.X, rText.Y + (CurrentLine + 1) * (fe.Ascent+fe.Descent));
- gr.Stroke();
- }
- #endregion
-
- //****** debug selection *************
-// if (SelRelease >= 0) {
-// new SolidColor(Color.DarkGreen).SetAsSource(gr);
-// Rectangle R = new Rectangle (
-// rText.X + (int)SelEndCursorPos - 3,
-// rText.Y + (int)(SelRelease.Y * (fe.Ascent+fe.Descent)),
-// 6,
-// (int)(fe.Ascent+fe.Descent));
-// gr.Rectangle (R);
-// gr.Fill ();
-// }
-// if (SelBegin >= 0) {
-// new SolidColor(Color.DarkRed).SetAsSource(gr);
-// Rectangle R = new Rectangle (
-// rText.X + (int)SelStartCursorPos - 3,
-// rText.Y + (int)(SelBegin.Y * (fe.Ascent+fe.Descent)),
-// 6,
-// (int)(fe.Ascent+fe.Descent));
-// gr.Rectangle (R);
-// gr.Fill ();
-// }
- //*******************
-
- for (int i = 0; i < lines.Count; i++) {
- string l = lines [i].Replace ("\t", new String (' ', Interface.TAB_SIZE));
- int lineLength = (int)gr.TextExtents (l).XAdvance;
- Rectangle lineRect = new Rectangle (
- rText.X,
- rText.Y + i * (int)(fe.Ascent+fe.Descent),
- lineLength,
- (int)(fe.Ascent+fe.Descent));
-
-// if (TextAlignment == Alignment.Center ||
-// TextAlignment == Alignment.Top ||
-// TextAlignment == Alignment.Bottom)
-// lineRect.X += (rText.Width - lineLength) / 2;
-// else if (TextAlignment == Alignment.Right ||
-// TextAlignment == Alignment.TopRight ||
-// TextAlignment == Alignment.BottomRight)
-// lineRect.X += (rText.Width - lineLength);
- if (string.IsNullOrWhiteSpace (l))
- continue;
-
- Foreground.SetAsSource (gr);
- gr.MoveTo (lineRect.X,(double)rText.Y + fe.Ascent + (fe.Ascent+fe.Descent) * i) ;
-
- gr.ShowText (l);
- gr.Fill ();
-
- if (Selectable) {
- if (SelRelease >= 0 && i >= selectionStart.Y && i <= selectionEnd.Y) {
- gr.SetSourceColor (selBackground);
-
- Rectangle selRect = lineRect;
-
- int cpStart = (int)SelStartCursorPos,
- cpEnd = (int)SelEndCursorPos;
-
- if (SelBegin.Y > SelRelease.Y) {
- cpStart = cpEnd;
- cpEnd = (int)SelStartCursorPos;
- }
-
- if (i == selectionStart.Y) {
- selRect.Width -= cpStart;
- selRect.Left += cpStart;
- }
- if (i == selectionEnd.Y)
- selRect.Width -= (lineLength - cpEnd);
-
- gr.Rectangle (selRect);
- gr.FillPreserve ();
- gr.Save ();
- gr.Clip ();
- gr.SetSourceColor (SelectionForeground);
- gr.MoveTo (lineRect.X, rText.Y + fe.Ascent + (fe.Ascent+fe.Descent) * i);
- gr.ShowText (l);
- gr.Fill ();
- gr.Restore ();
- }
- }
- }
- }
- #endregion
-
- #region Mouse handling
- void updatemouseLocalPos(Point mpos){
- mouseLocalPos = mpos - ScreenCoordinates(Slot).TopLeft - ClientRectangle.TopLeft;
- if (mouseLocalPos.X < 0)
- mouseLocalPos.X = 0;
- if (mouseLocalPos.Y < 0)
- mouseLocalPos.Y = 0;
- }
- protected override void onFocused (object sender, EventArgs e)
- {
- base.onFocused (sender, e);
-
- if (!_selectable)
- return;
- SelBegin = new Point(0,0);
- SelRelease = new Point (lines.LastOrDefault ().Length, lines.Count-1);
- RegisterForRedraw ();
- }
- protected override void onUnfocused (object sender, EventArgs e)
- {
- base.onUnfocused (sender, e);
-
- SelBegin = -1;
- SelRelease = -1;
- RegisterForRedraw ();
- }
- public override void onMouseMove (object sender, MouseMoveEventArgs e)
- {
- base.onMouseMove (sender, e);
-
- if (!(SelectionInProgress && HasFocus && _selectable))
- return;
-
- updatemouseLocalPos (e.Position);
-
- RegisterForRedraw();
- }
- public override void onMouseDown (object sender, MouseButtonEventArgs e)
- {
- if (this.HasFocus && _selectable){
- updatemouseLocalPos (e.Position);
- SelBegin = -1;
- SelRelease = -1;
- SelectionInProgress = true;
- RegisterForRedraw();//TODO:should put it in properties
- }
-
- //done at the end to set 'hasFocus' value after testing it
- base.onMouseDown (sender, e);
- }
- public override void onMouseUp (object sender, MouseButtonEventArgs e)
- {
- base.onMouseUp (sender, e);
- if (!(this.HasFocus || _selectable))
- return;
- if (!SelectionInProgress)
- return;
-
- updatemouseLocalPos (e.Position);
- SelectionInProgress = false;
- RegisterForRedraw ();
- }
- public override void onMouseDoubleClick (object sender, MouseButtonEventArgs e)
- {
- base.onMouseDoubleClick (sender, e);
- if (!(this.HasFocus || _selectable))
- return;
-
- GotoWordStart ();
- SelBegin = CurrentPosition;
- GotoWordEnd ();
- SelRelease = CurrentPosition;
- SelectionInProgress = false;
- RegisterForRedraw ();
- }
- #endregion
-
- /// <summary>
- /// Update Current Column, line and TextCursorPos
- /// from mouseLocalPos
- /// </summary>
- void computeTextCursor(Context gr)
- {
- TextExtents te;
-
- double cPos = 0f;
-
- CurrentLine = (int)(mouseLocalPos.Y / (fe.Ascent+fe.Descent));
-
- //fix cu
- if (CurrentLine >= lines.Count)
- CurrentLine = lines.Count - 1;
-
- switch (TextAlignment) {
- case Alignment.Center:
- case Alignment.Top:
- case Alignment.Bottom:
- cPos+= ClientRectangle.Width - gr.TextExtents(lines [CurrentLine]).Width/2.0;
- break;
- case Alignment.Right:
- case Alignment.TopRight:
- case Alignment.BottomRight:
- cPos += ClientRectangle.Width - gr.TextExtents(lines [CurrentLine]).Width;
- break;
- }
-
- for (int i = 0; i < lines[CurrentLine].Length; i++)
- {
- string c = lines [CurrentLine].Substring (i, 1);
- if (c == "\t")
- c = new string (' ', Interface.TAB_SIZE);
-
- te = gr.TextExtents(c);
-
- double halfWidth = te.XAdvance / 2;
-
- if (mouseLocalPos.X <= cPos + halfWidth)
- {
- CurrentColumn = i;
- textCursorPos = cPos;
- mouseLocalPos = -1;
- return;
- }
-
- cPos += te.XAdvance;
- }
- CurrentColumn = lines[CurrentLine].Length;
- textCursorPos = cPos;
-
- //reset mouseLocalPos
- mouseLocalPos = -1;
- }
- /// <summary> Computes offsets in cairo units </summary>
- void computeTextCursorPosition(Context gr)
- {
- if (SelBegin >= 0)
- SelStartCursorPos = GetXFromTextPointer (gr, SelBegin);
- if (SelRelease >= 0)
- SelEndCursorPos = GetXFromTextPointer (gr, SelRelease);
- textCursorPos = GetXFromTextPointer (gr, new Point(CurrentColumn, CurrentLine));
- }
- /// <summary> Compute x offset in cairo unit from text position </summary>
- double GetXFromTextPointer(Context gr, Point pos)
- {
- try {
- string l = lines [pos.Y].Substring (0, pos.X).
- Replace ("\t", new String (' ', Interface.TAB_SIZE));
- return gr.TextExtents (l).XAdvance;
- } catch{
- return -1;
- }
- }
- }
-}
+++ /dev/null
-//
-// ListBox.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;
-using System.Xml.Serialization;
-using System.ComponentModel;
-using System.IO;
-using System.Diagnostics;
-using System.Xml;
-using System.Collections.Generic;
-using System.Threading;
-
-namespace Crow
-{
- public class ListBox : TemplatedGroup
- {
- #region CTOR
- protected ListBox () : base(){}
- public ListBox (Interface iface) : base(iface) {}
- #endregion
-
- }
-}
-
+++ /dev/null
-//
-// Menu.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.Xml.Serialization;
-using System.ComponentModel;
-
-namespace Crow
-{
- public class Menu : TemplatedGroup
- {
- #region CTOR
- protected Menu () : base(){}
- public Menu (Interface iface) : base(iface) {}
- #endregion
-
- Orientation orientation;
- bool autoOpen = false;
-
- #region Public properties
- [DefaultValue(Orientation.Horizontal)]
- public Orientation Orientation {
- get { return orientation; }
- set {
- if (orientation == value)
- return;
- orientation = value;
- NotifyValueChanged ("Orientation", orientation);
- }
- }
- [XmlIgnore]public bool AutomaticOpening
- {
- get { return autoOpen; }
- set {
- if (autoOpen == value)
- return;
- autoOpen = value;
- NotifyValueChanged ("AutomaticOpening", autoOpen);
- }
- }
- #endregion
-
- public override void AddItem (Widget g)
- {
- base.AddItem (g);
-
- if (orientation == Orientation.Horizontal)
- g.NotifyValueChanged ("PopDirection", Alignment.Bottom);
- else
- g.NotifyValueChanged ("PopDirection", Alignment.Right);
- }
- public override void onMouseLeave (object sender, MouseMoveEventArgs e)
- {
- base.onMouseLeave (sender, e);
- AutomaticOpening = false;
- }
- }
-}
-
+++ /dev/null
-//
-// MenuItem.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.Xml.Serialization;
-using System.ComponentModel;
-
-namespace Crow
-{
- public class MenuItem : Menu
- {
- #region CTOR
- protected MenuItem () : base(){}
- public MenuItem (Interface iface) : base(iface) {}
- #endregion
-
- public event EventHandler Open;
- public event EventHandler Close;
-
- Command command;
- Picture icon;
- bool isOpened;
- Measure popWidth, popHeight;
-
- #region Public properties
- [DefaultValue(false)]
- public bool IsOpened {
- get { return isOpened; }
- set {
- if (isOpened == value)
- return;
- isOpened = value;
- NotifyValueChanged ("IsOpened", isOpened);
-
- if (isOpened) {
- onOpen (this, null);
- if (LogicalParent is Menu)
- (LogicalParent as Menu).AutomaticOpening = true;
- }else
- onClose (this, null);
- }
- }
- [DefaultValue(null)]
- public virtual Command Command {
- get { return command; }
- set {
- if (command == value)
- return;
-
- if (command != null) {
- command.raiseAllValuesChanged ();
- command.ValueChanged -= Command_ValueChanged;
- }
-
- command = value;
-
- if (command != null) {
- command.ValueChanged += Command_ValueChanged;
- command.raiseAllValuesChanged ();
- }
-
- NotifyValueChanged ("Command", command);
- }
- }
-
- public override bool IsEnabled {
- get { return Command == null ? base.IsEnabled : Command.CanExecute; }
- set { base.IsEnabled = value; }
- }
-
- public override string Caption {
- get { return Command == null ? base.Caption : Command.Caption; }
- set { base.Caption = value; }
- }
-
- public Picture Icon {
- get { return Command == null ? icon : Command.Icon;; }
- set {
- if (icon == value)
- return;
- icon = value;
- if (command == null)
- NotifyValueChanged ("Icon", icon);
- }
- }
- [DefaultValue("Fit")]
- public virtual Measure PopWidth {
- get { return popWidth; }
- set {
- if (popWidth == value)
- return;
- popWidth = value;
- NotifyValueChanged ("PopWidth", popWidth);
- }
- }
- [DefaultValue("Fit")]
- public virtual Measure PopHeight {
- get { return popHeight; }
- set {
- if (popHeight == value)
- return;
- popHeight = value;
- NotifyValueChanged ("PopHeight", popHeight);
- }
- }
- #endregion
-
- public override void AddItem (Widget g)
- {
- base.AddItem (g);
- g.NotifyValueChanged ("PopDirection", Alignment.Right);
- }
-
- void Command_ValueChanged (object sender, ValueChangeEventArgs e)
- {
- string mName = e.MemberName;
- if (mName == "CanExecute")
- mName = "IsEnabled";
- NotifyValueChanged (mName, e.NewValue);
- }
- protected virtual void onOpen (object sender, EventArgs e){
- Open.Raise (this, null);
- }
- protected virtual void onClose (object sender, EventArgs e){
- System.Diagnostics.Debug.WriteLine ("close: " + this.ToString());
- Close.Raise (this, null);
- }
- public override bool MouseIsIn (Point m)
- {
- return IsEnabled && !IsDragged ? base.MouseIsIn (m) || child.MouseIsIn (m) : false;
- }
- public override void onMouseEnter (object sender, MouseMoveEventArgs e)
- {
- base.onMouseEnter (sender, e);
- Menu menu = LogicalParent as Menu;
- if (menu == null)
- return;
- if (menu.AutomaticOpening && items.Children.Count>0)
- IsOpened = true;
- }
- public override void onMouseLeave (object sender, MouseMoveEventArgs e)
- {
- if (IsOpened)
- IsOpened = false;
- base.onMouseLeave (this, e);
- }
- public override void onMouseClick (object sender, MouseButtonEventArgs e)
- {
-#if DEBUG_FOCUS
- System.Diagnostics.Debug.WriteLine ("MENU CLICK => " + this.ToString ());
-#endif
- if (command != null) {
- command.Execute ();
- closeMenu ();
- }
- if (hasClick)
- base.onMouseClick (sender, e);
-
- if (!IsOpened)
- (LogicalParent as Menu).AutomaticOpening = false;
- }
- void closeMenu () {
- MenuItem tmp = LogicalParent as MenuItem;
- while (tmp != null) {
- tmp.IsOpened = false;
- tmp.Background = Color.Transparent;
- tmp.AutomaticOpening = false;
- tmp = tmp.LogicalParent as MenuItem;
- }
- }
- }
-}
-
+++ /dev/null
-//
-// MessageBox.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.Xml.Serialization;
-using System.ComponentModel;
-
-namespace Crow
-{
- public class MessageBox : Window
- {
- #region CTOR
- protected MessageBox () : base(){}
- public MessageBox (Interface iface) : base(iface){}
- #endregion
-
- public enum Type {
- None,
- Information,
- Alert,
- Error,
- YesNo,
- YesNoCancel,
-
- }
-
- protected override void loadTemplate (Widget template)
- {
- base.loadTemplate (template);
- NotifyValueChanged ("MsgIcon", "#Crow.Icons.iconInfo.svg");
- }
- string message, okMessage, cancelMessage, noMessage;
- Type msgType = Type.None;
-
- public event EventHandler Yes;
- public event EventHandler No;
- public event EventHandler Cancel;
-
- [DefaultValue("Informations")]
- public virtual string Message
- {
- get { return message; }
- set {
- if (message == value)
- return;
- message = value;
- NotifyValueChanged ("Message", message);
- }
- }
- [DefaultValue("Ok")]
- public virtual string OkMessage
- {
- get { return okMessage; }
- set {
- if (okMessage == value)
- return;
- okMessage = value;
- NotifyValueChanged ("OkMessage", okMessage);
- }
- }
- [DefaultValue("Cancel")]
- public virtual string CancelMessage
- {
- get { return cancelMessage; }
- set {
- if (cancelMessage == value)
- return;
- cancelMessage = value;
- NotifyValueChanged ("CancelMessage", cancelMessage);
- }
- }
- [DefaultValue("No")]
- public virtual string NoMessage
- {
- get { return noMessage; }
- set {
- if (noMessage == value)
- return;
- noMessage = value;
- NotifyValueChanged ("NoMessage", noMessage);
- }
- }
- [DefaultValue("Information")]
- public virtual Type MsgType
- {
- get { return msgType; }
- set {
- if (msgType == value)
- return;
- msgType = value;
- NotifyValueChanged ("MsgType", msgType);
- switch (msgType) {
- case Type.Information:
- MsgIcon = "#Crow.Icons.iconInfo.svg";
- Caption = "Informations";
- OkMessage = "Ok";
- NotifyValueChanged ("CancelButIsVisible", false);
- NotifyValueChanged ("NoButIsVisible", false);
- break;
- case Type.YesNo:
- case Type.YesNoCancel:
- MsgIcon = "#Crow.Icons.question.svg";
- Caption = "Choice";
- OkMessage = "Yes";
- NoMessage = "No";
- NotifyValueChanged ("CancelButIsVisible", msgType == Type.YesNoCancel);
- NotifyValueChanged ("NoButIsVisible", true);
- break;
- case Type.Alert:
- MsgIcon = "#Crow.Icons.IconAlerte.svg";
- Caption = "Alert";
- OkMessage = "Ok";
- CancelMessage = "Cancel";
- NotifyValueChanged ("CancelButIsVisible", true);
- NotifyValueChanged ("NoButIsVisible", false);
- break;
- case Type.Error:
- MsgIcon = "#Crow.Icons.exit.svg";
- Caption = "Error";
- OkMessage = "Ok";
- NotifyValueChanged ("CancelButIsVisible", false);
- NotifyValueChanged ("NoButIsVisible", false);
- break;
- }
- }
- }
-
- string msgIcon = null;
- public string MsgIcon {
- get { return msgIcon; }
- set {
- if (value == MsgIcon)
- return;
- msgIcon = value;
- NotifyValueChanged ("MsgIcon", MsgIcon);
- }
- }
- void onOkButtonClick (object sender, EventArgs e)
- {
- Yes.Raise (this, null);
- close ();
- }
- void onNoButtonClick (object sender, EventArgs e)
- {
- No.Raise (this, null);
- close ();
- }
- void onCancelButtonClick (object sender, EventArgs e)
- {
- Cancel.Raise (this, null);
- close ();
- }
- public static MessageBox Show (Interface iface, Type msgBoxType, string message, string okMsg = "", string cancelMsg = ""){
- lock (iface.UpdateMutex) {
- MessageBox mb = new MessageBox (iface);
- mb.IFace.AddWidget (mb);
- mb.MsgType = msgBoxType;
- mb.Message = message;
- if (!string.IsNullOrEmpty(okMsg))
- mb.OkMessage = okMsg;
- if (!string.IsNullOrEmpty(cancelMsg))
- mb.CancelMessage = cancelMsg;
- return mb;
- }
- }
- public static MessageBox ShowModal (Interface iface, Type msgBoxType, string message){
- lock (iface.UpdateMutex) {
- MessageBox mb = new MessageBox (iface) {
- Modal = true,
- MsgType = msgBoxType,
- Message = message
- };
-
- iface.AddWidget (mb);
- return mb;
- }
- }
- }
-}
-
+++ /dev/null
-//
-// NumericControl.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.Xml.Serialization;
-using System.ComponentModel;
-
-namespace Crow
-{
- public abstract class NumericControl : TemplatedControl
- {
- #region CTOR
- protected NumericControl () : base(){}
- public NumericControl (Interface iface) : base(iface)
- {
- }
-// public NumericControl(double minimum, double maximum, double step)
-// : base()
-// {
-// }
- #endregion
-
- #region protected fields
- protected double _actualValue, minValue, maxValue, smallStep, bigStep;
- protected int _decimals;
- #endregion
-
- #region public properties
- [DefaultValue(2)]
- public int Decimals
- {
- get { return _decimals; }
- set
- {
- if (value == _decimals)
- return;
- _decimals = value;
- NotifyValueChanged("Decimals", _decimals);
- RegisterForGraphicUpdate();
- }
- }
- [DefaultValue(0.0)]
- public virtual double Minimum {
- get { return minValue; }
- set {
- if (minValue == value)
- return;
-
- minValue = value;
- NotifyValueChanged ("Minimum", minValue);
- RegisterForRedraw ();
- }
- }
- [DefaultValue(100.0)]
- public virtual double Maximum
- {
- get { return maxValue; }
- set {
- if (maxValue == value)
- return;
-
- maxValue = value;
- NotifyValueChanged ("Maximum", maxValue);
- RegisterForRedraw ();
- }
- }
- [DefaultValue(1.0)]
- public virtual double SmallIncrement
- {
- get { return smallStep; }
- set {
- if (smallStep == value)
- return;
-
- smallStep = value;
- NotifyValueChanged ("SmallIncrement", smallStep);
- RegisterForRedraw ();
- }
- }
- [DefaultValue(5.0)]
- public virtual double LargeIncrement
- {
- get { return bigStep; }
- set {
- if (bigStep == value)
- return;
-
- bigStep = value;
- NotifyValueChanged ("LargeIncrement", bigStep);
- RegisterForRedraw ();
- }
- }
- [DefaultValue(0.0)]
- public virtual double Value
- {
- get { return _actualValue; }
- set
- {
- if (value == _actualValue)
- return;
-
- if (value < minValue)
- _actualValue = minValue;
- else if (value > maxValue)
- _actualValue = maxValue;
- else
- _actualValue = value;
-
- _actualValue = Math.Round (_actualValue, _decimals);
-
- NotifyValueChanged("Value", _actualValue);
- RegisterForGraphicUpdate();
- }
- }
- #endregion
-
- }
-}
-
+++ /dev/null
-//
-// Popper.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.Xml.Serialization;
-using System.ComponentModel;
-
-namespace Crow
-{
- public class Popper : TemplatedContainer
- {
- #region CTOR
- protected Popper () : base(){}
- public Popper (Interface iface) : base(iface){}
- #endregion
-
- bool _isPopped, _canPop;
- Alignment popDirection;
- Widget _content;
- Measure popWidth, popHeight;
-
- public event EventHandler Popped;
- public event EventHandler Unpoped;
-
- #region Public Properties
- [DefaultValue("Fit")]
- public virtual Measure PopWidth {
- get { return popWidth; }
- set {
- if (popWidth == value)
- return;
- popWidth = value;
- NotifyValueChanged ("PopWidth", popWidth);
- }
- }
- [DefaultValue("Fit")]
- public virtual Measure PopHeight {
- get { return popHeight; }
- set {
- if (popHeight == value)
- return;
- popHeight = value;
- NotifyValueChanged ("PopHeight", popHeight);
- }
- }
- [DefaultValue(false)]
- public bool IsPopped
- {
- get { return _isPopped; }
- set
- {
- if (!_canPop & value)
- return;
-
- if (value == _isPopped)
- return;
-
- _isPopped = value;
-
- NotifyValueChanged ("IsPopped", _isPopped);
-
- if (_isPopped)
- onPop (this, null);
- else
- onUnpop (this, null);
-
- }
- }
- [DefaultValue(true)]
- public bool CanPop
- {
- get { return _canPop; }
- set
- {
- if (value == _canPop)
- return;
-
- _canPop = value;
- NotifyValueChanged ("CanPop", _canPop);
- }
- }
- [DefaultValue(Alignment.Bottom)]
- public virtual Alignment PopDirection {
- get { return popDirection; }
- set {
- if (popDirection == value)
- return;
- popDirection = value;
- NotifyValueChanged ("PopDirection", popDirection);
- }
- }
- #endregion
-
- public override Widget Content {
- get { return _content; }
- set {
- if (_content != null) {
- _content.LogicalParent = null;
- //_content.isPopup = false;
- _content.LayoutChanged -= _content_LayoutChanged;
- }
-
- _content = value;
-
- if (_content == null)
- return;
-
- _content.LogicalParent = this;
- //_content.isPopup = true;
- _content.HorizontalAlignment = HorizontalAlignment.Left;
- _content.VerticalAlignment = VerticalAlignment.Top;
- _content.LayoutChanged += _content_LayoutChanged;
- }
- }
- void positionContent(LayoutingType lt){
- ILayoutable tc = Content.Parent;
- if (tc == null)
- return;
- Rectangle r = this.ScreenCoordinates (this.Slot);
- if (lt == LayoutingType.X) {
- if (popDirection.HasFlag (Alignment.Right)) {
- if (r.Right + Content.Slot.Width > tc.ClientRectangle.Right)
- Content.Left = r.Left - Content.Slot.Width;
- else
- Content.Left = r.Right;
- } else if (popDirection.HasFlag (Alignment.Left)) {
- if (r.Left - Content.Slot.Width < tc.ClientRectangle.Left)
- Content.Left = r.Right;
- else
- Content.Left = r.Left - Content.Slot.Width;
- } else {
- if (Content.Slot.Width < tc.ClientRectangle.Width) {
- if (r.Left + Content.Slot.Width > tc.ClientRectangle.Right)
- Content.Left = tc.ClientRectangle.Right - Content.Slot.Width;
- else
- Content.Left = r.Left;
- } else
- Content.Left = 0;
- }
- }else if (lt == LayoutingType.Y) {
- if (Content.Slot.Height < tc.ClientRectangle.Height) {
- if (PopDirection.HasFlag (Alignment.Bottom)) {
- if (r.Bottom + Content.Slot.Height > tc.ClientRectangle.Bottom)
- Content.Top = r.Top - Content.Slot.Height;
- else
- Content.Top = r.Bottom;
- } else if (PopDirection.HasFlag (Alignment.Top)) {
- if (r.Top - Content.Slot.Height < tc.ClientRectangle.Top)
- Content.Top = r.Bottom;
- else
- Content.Top = r.Top - Content.Slot.Height;
- } else
- Content.Top = r.Top;
- }else
- Content.Top = 0;
- }
- }
- protected void _content_LayoutChanged (object sender, LayoutingEventArgs e)
- {
- if (e.LayoutType.HasFlag (LayoutingType.Width))
- positionContent (LayoutingType.X);
- if (e.LayoutType.HasFlag(LayoutingType.Height))
- positionContent (LayoutingType.Y);
- }
-
- #region GraphicObject overrides
- public override void onMouseLeave (object sender, MouseMoveEventArgs e)
- {
- base.onMouseLeave (this, e);
- IsPopped = false;
- }
- public override bool MouseIsIn (Point m)
- {
- if (Content?.Parent != null)
- if (Content.MouseIsIn (m))
- return true;
- return base.MouseIsIn (m);
- }
- public override void checkHoverWidget (MouseMoveEventArgs e)
- {
- if (IFace.HoverWidget != this) {
- IFace.HoverWidget = this;
- onMouseEnter (this, e);
- }
- if (Content != null){
- if (Content.Parent != null) {
- if (Content.MouseIsIn (e.Position)) {
- Content.checkHoverWidget (e);
- return;
- }
- }
- }
- base.checkHoverWidget (e);
- }
- #endregion
-
- public virtual void onPop(object sender, EventArgs e)
- {
- if (Content != null) {
- Content.Visible = true;
- if (Content.Parent == null)
- IFace.AddWidget (Content);
- //if (Content.LogicalParent != this)
- Content.LogicalParent = this;
- IFace.PutOnTop (Content, true);
- _content_LayoutChanged (this, new LayoutingEventArgs (LayoutingType.Sizing));
- }
- Popped.Raise (this, e);
- }
- public virtual void onUnpop(object sender, EventArgs e)
- {
- if (Content != null) {
- Content.Visible = false;
- }
- Unpoped.Raise (this, e);
- }
-
- protected override void Dispose (bool disposing)
- {
- if (_content != null && disposing) {
- if (_content.Parent == null)
- _content.Dispose ();
- }
- base.Dispose (disposing);
- }
- }
-}
+++ /dev/null
-//
-// PrivateContainer.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.Xml.Serialization;
-using System.ComponentModel;
-using Crow.Cairo;
-
-namespace Crow
-{
- /// <summary>
- /// Implement drawing and layouting for a single child, but
- /// does not expose child to allow reuse of container
- /// behaviour for widgets that have other xml hierarchy: example
- /// TemplatedControl may have 3 children (template,templateItem,content) but
- /// behave exactely as a container for layouting and drawing
- /// </summary>
- [DesignIgnore]
- public class PrivateContainer : Widget
- {
- #region CTOR
- protected PrivateContainer () : base(){}
- public PrivateContainer (Interface iface) : base(iface){}
- #endregion
-
- #if DESIGN_MODE
- public override bool FindByDesignID(string designID, out Widget go){
- go = null;
- if (base.FindByDesignID (designID, out go))
- return true;
- if (child == null)
- return false;
- return child.FindByDesignID (designID, out go);
- }
- #endif
- protected Widget child;
- #if DEBUG_LOG
- internal GraphicObject getTemplateRoot {
- get { return child; }
- }
- #endif
-
- protected virtual void SetChild(Widget _child)
- {
-
- if (child != null) {
- //check if HoverWidget is removed from Tree
- if (IFace.HoverWidget != null) {
- if (this.Contains (IFace.HoverWidget))
- IFace.HoverWidget = null;
- }
- contentSize = default(Size);
- child.LayoutChanged -= OnChildLayoutChanges;
- this.RegisterForGraphicUpdate ();
- child.Dispose ();
- }
-
- child = _child as Widget;
-
- if (child != null) {
- child.Parent = this;
- child.LayoutChanged += OnChildLayoutChanges;
- contentSize = child.Slot.Size;
- child.RegisteredLayoutings = LayoutingType.None;
- child.RegisterForLayouting (LayoutingType.Sizing);
- }
- }
- //dispose child if not null
- protected virtual void deleteChild () {
- Widget g = child;
- SetChild (null);
- if (g != null)
- g.Dispose ();
- }
-
- #region GraphicObject Overrides
-
- public override Widget FindByName (string nameToFind)
- {
- if (Name == nameToFind)
- return this;
-
- return child == null ? null : child.FindByName (nameToFind);
- }
- public override bool Contains (Widget goToFind)
- {
- return child == goToFind ? true :
- child == null ? false : child.Contains(goToFind);
- }
- public override void OnDataSourceChanged (object sender, DataSourceChangeEventArgs e)
- {
- base.OnDataSourceChanged (this, e);
- if (child != null)
- if (child.localDataSourceIsNull & child.localLogicalParentIsNull)
- child.OnDataSourceChanged (child, e);
- }
- public override bool UpdateLayout (LayoutingType layoutType)
- {
- if (child != null) {
- //force sizing to fit if sizing on children and child has stretched size
- switch (layoutType) {
- case LayoutingType.Width:
- if (Width == Measure.Fit && child.Width.IsRelativeToParent)
- child.Width = Measure.Fit;
- break;
- case LayoutingType.Height:
- if (Height == Measure.Fit && child.Height.IsRelativeToParent)
- child.Height = Measure.Fit;
- break;
- }
- }
- return base.UpdateLayout (layoutType);
- }
- public override void OnLayoutChanges (LayoutingType layoutType)
- {
- base.OnLayoutChanges (layoutType);
-
- if (child == null)
- return;
-
- LayoutingType ltChild = LayoutingType.None;
-
- if (layoutType == LayoutingType.Width) {
- if (child.Width.IsRelativeToParent) {
- ltChild |= LayoutingType.Width;
- if (child.Width.Value < 100 && child.Left == 0)
- ltChild |= LayoutingType.X;
- } else if (child.Left == 0)
- ltChild |= LayoutingType.X;
- } else if (layoutType == LayoutingType.Height) {
- if (child.Height.IsRelativeToParent) {
- ltChild |= LayoutingType.Height;
- if (child.Height.Value < 100 && child.Top == 0)
- ltChild |= LayoutingType.Y;
- } else if (child.Top == 0)
- ltChild |= LayoutingType.Y;
- }
- if (ltChild == LayoutingType.None)
- return;
- child.RegisterForLayouting (ltChild);
- }
- public virtual void OnChildLayoutChanges (object sender, LayoutingEventArgs arg)
- {
- Widget g = sender as Widget;
-
- if (arg.LayoutType == LayoutingType.Width) {
- if (Width != Measure.Fit)
- return;
- contentSize.Width = g.Slot.Width;
- this.RegisterForLayouting (LayoutingType.Width);
- }else if (arg.LayoutType == LayoutingType.Height){
- if (Height != Measure.Fit)
- return;
- contentSize.Height = g.Slot.Height;
- this.RegisterForLayouting (LayoutingType.Height);
- }
- }
- protected override void onDraw (Context gr)
- {
- base.onDraw (gr);
-
- gr.Save ();
-
- if (ClipToClientRect) {
- //clip to client zone
- CairoHelpers.CairoRectangle (gr, ClientRectangle, CornerRadius);
- gr.Clip ();
- }
-
- if (child != null) {
- if (child.Visible)
- child.Paint (ref gr);
- }
- gr.Restore ();
- }
- protected override void UpdateCache (Context ctx)
- {
- Rectangle rb = Slot + Parent.ClientRectangle.Position;
-
-
- Context gr = new Context (bmp);
-
- if (!Clipping.IsEmpty) {
- for (int i = 0; i < Clipping.NumRectangles; i++)
- gr.Rectangle(Clipping.GetRectangle(i));
- gr.ClipPreserve();
- gr.Operator = Operator.Clear;
- gr.Fill();
- gr.Operator = Operator.Over;
-
- onDraw (gr);
- }
-
- gr.Dispose ();
-
- ctx.SetSourceSurface (bmp, rb.X, rb.Y);
- ctx.Paint ();
- Clipping.Dispose();
- Clipping = new Region ();
- }
- #endregion
-
- #region Mouse handling
- public override void checkHoverWidget (MouseMoveEventArgs e)
- {
- base.checkHoverWidget (e);
-
- if (child != null)
- if (child.MouseIsIn (e.Position))
- child.checkHoverWidget (e);
- }
- #endregion
-
- protected override void Dispose (bool disposing)
- {
- if (disposing && child != null)
- child.Dispose ();
- base.Dispose (disposing);
- }
- }
-}
-
+++ /dev/null
-//
-// ProgressBar.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.Linq;
-using System.Text;
-using Crow.Cairo;
-using System.Diagnostics;
-using System.Xml.Serialization;
-using System.ComponentModel;
-
-namespace Crow
-{
-
- public class ProgressBar : NumericControl
- {
- #region CTOR
- protected ProgressBar () : base(){}
- public ProgressBar(Interface iface) : base(iface){}
- #endregion
-
- protected override void loadTemplate (Widget template)
- {
-
- }
-
- #region GraphicObject overrides
- protected override void onDraw (Context gr)
- {
- base.onDraw (gr);
-
- if (Maximum == 0)
- return;
-
- Rectangle rBack = ClientRectangle;
- rBack.Width = (int)((double)rBack.Width / Maximum * Value);
- Foreground.SetAsSource (gr, rBack);
-
- CairoHelpers.CairoRectangle(gr,rBack,CornerRadius);
- gr.Fill();
- }
- #endregion
- }
-}
+++ /dev/null
-//
-// RadioButton.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.ComponentModel;
-using System.Xml.Serialization;
-
-namespace Crow
-{
- public class RadioButton : TemplatedControl
- {
- bool isChecked;
-
- #region CTOR
- protected RadioButton () : base(){}
- public RadioButton(Interface iface) : base(iface){}
- #endregion
-
- public event EventHandler Checked;
- public event EventHandler Unchecked;
-
- #region GraphicObject overrides
- public override void onMouseDown (object sender, MouseButtonEventArgs e)
- {
- Group pg = Parent as Group;
- if (pg != null) {
- for (int i = 0; i < pg.Children.Count; i++) {
- RadioButton c = pg.Children [i] as RadioButton;
- if (c == null)
- continue;
- c.IsChecked = (c == this);
- }
- } else
- IsChecked = !IsChecked;
-
- base.onMouseDown (sender, e);
- }
- #endregion
-
- [DefaultValue(false)]
- public bool IsChecked
- {
- get { return isChecked; }
- set
- {
- if (isChecked == value)
- return;
-
- isChecked = value;
-
- NotifyValueChanged ("IsChecked", value);
-
- if (isChecked)
- Checked.Raise (this, null);
- else
- Unchecked.Raise (this, null);
- }
- }
- }
-}
+++ /dev/null
-//
-// SaturationValueSelector.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 Crow.Cairo;
-using System.Xml.Serialization;
-
-namespace Crow
-{
- [DesignIgnore]
- public class SaturationValueSelector : ColorSelector
- {
- public SaturationValueSelector () : base(){}
- public SaturationValueSelector (Interface iface) : base(iface)
- {
- }
-
- double v, s;
-
- public virtual double V {
- get { return v; }
- set {
- if (v == value)
- return;
- v = value;
- NotifyValueChanged ("V", v);
- mousePos.Y = (int)Math.Floor((1.0-v) * (double)ClientRectangle.Height);
-
- RegisterForRedraw ();
- }
- }
-
- public virtual double S {
- get { return s; }
- set {
- if (s == value)
- return;
- s = value;
- NotifyValueChanged ("S", s);
- mousePos.X = (int)Math.Floor(s * (double)ClientRectangle.Width);
-
- RegisterForRedraw ();
- }
- }
- protected override void onDraw (Context gr)
- {
- base.onDraw (gr);
-
- Rectangle r = ClientRectangle;
-
- if (Foreground != null) {//TODO:test if null should be removed
- Foreground.SetAsSource (gr, r);
- CairoHelpers.CairoRectangle (gr, r, CornerRadius);
- gr.Fill ();
- }
-
- Crow.Gradient grad = new Gradient (Gradient.Type.Horizontal);
- grad.Stops.Add (new Gradient.ColorStop (0, new Color (1, 1, 1, 1)));
- grad.Stops.Add (new Gradient.ColorStop (1, new Color (1, 1, 1, 0)));
- grad.SetAsSource (gr, r);
- CairoHelpers.CairoRectangle (gr, r, CornerRadius);
- gr.Fill();
- grad = new Gradient (Gradient.Type.Vertical);
- grad.Stops.Add (new Gradient.ColorStop (0, new Color (0, 0, 0, 0)));
- grad.Stops.Add (new Gradient.ColorStop (1, new Color (0, 0, 0, 1)));
- grad.SetAsSource (gr, r);
- CairoHelpers.CairoRectangle (gr, r, CornerRadius);
- gr.Fill();
-
-
- gr.Arc (mousePos.X, mousePos.Y, 3.5, 0, Math.PI * 2.0);
- gr.SetSourceColor (Color.Black);
- gr.LineWidth = 2.0;
- gr.StrokePreserve ();
- gr.SetSourceColor (Color.White);
- gr.LineWidth = 1.0;
- gr.Stroke ();
- }
-
- //public override void Paint (ref Context ctx)
- //{
- // base.Paint (ref ctx);
-
- // Rectangle rb = Slot + Parent.ClientRectangle.Position;
- // ctx.Save ();
-
- // ctx.Translate (rb.X, rb.Y);
-
- // ctx.SetSourceColor (Color.DimGrey);
- // ctx.Arc (mousePos.X, mousePos.Y, 3.5, 0, Math.PI * 2.0);
- // ctx.LineWidth = 0.5;
- // ctx.Stroke ();
- // ctx.Translate (-0.5, -0.5);
- // ctx.Arc (mousePos.X, mousePos.Y, 3.5, 0, Math.PI * 2.0);
- // ctx.SetSourceColor (Color.White);
- // ctx.Stroke ();
-
- // ctx.Restore ();
- //}
-
- protected override void updateMouseLocalPos (Point mPos)
- {
- base.updateMouseLocalPos (mPos);
-
- Rectangle cb = ClientRectangle;
- s = (double)mousePos.X / (double)cb.Width;
- v = 1.0 - (double)mousePos.Y / (double)cb.Height;
- NotifyValueChanged ("S", s);
- NotifyValueChanged ("V", v);
-
- RegisterForRedraw ();
- }
- public override void OnLayoutChanges (LayoutingType layoutType)
- {
- base.OnLayoutChanges (layoutType);
- switch (layoutType) {
- case LayoutingType.Width:
- mousePos.X = (int)Math.Floor(s * (double)ClientRectangle.Width);
- break;
- case LayoutingType.Height:
- mousePos.Y = (int)Math.Floor((1.0-v) * (double)ClientRectangle.Height);
- break;
- }
- }
- }
-}
-
+++ /dev/null
-//
-// ScrollBar.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.Xml.Serialization;
-using System.ComponentModel;
-
-namespace Crow
-{
- /// <summary>
- /// templeted numeric control
- /// </summary>
- public class ScrollBar : NumericControl
- {
- //TODO:could be replaced by a template for a Slider
-
- Orientation _orientation;
- int _cursorSize;
-
- #region CTOR
- protected ScrollBar () : base(){}
- public ScrollBar(Interface iface) : base(iface) {}
- #endregion
-
- [DefaultValue(Orientation.Vertical)]
- public virtual Orientation Orientation
- {
- get { return _orientation; }
- set {
- if (_orientation == value)
- return;
- _orientation = value;
- NotifyValueChanged ("Orientation", _orientation);
- if (_orientation == Orientation.Horizontal)
- NotifyValueChanged ("ScrollBackShape", "M 1.5,3.5 L 6.5,0.5 L 6.5,6.5 Z");
- else
- NotifyValueChanged ("ScrollBackShape", "M 4.5,0.5 L 9.5,9.5 L 0.5,9.5 Z");
-
- RegisterForGraphicUpdate ();
- }
- }
- [DefaultValue(20)]
- public virtual int CursorSize {
- get { return _cursorSize; }
- set {
- if (_cursorSize == value)
- return;
- _cursorSize = value;
- RegisterForGraphicUpdate ();
- NotifyValueChanged ("CursorSize", _cursorSize);
- }
- }
- public void onScrollBack (object sender, MouseButtonEventArgs e)
- {
- Value -= SmallIncrement;
- }
- public void onScrollForth (object sender, MouseButtonEventArgs e)
- {
- Value += SmallIncrement;
- }
-
- public void onSliderValueChange(object sender, ValueChangeEventArgs e){
- if (e.MemberName == "Value")
- Value = Convert.ToDouble(e.NewValue);
- }
- }
-}
+++ /dev/null
-//
-// Scroller.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.Xml.Serialization;
-using System.ComponentModel;
-using System.Diagnostics;
-using Crow.Cairo;
-
-namespace Crow
-{
- /// <summary>
- /// scrolling surface, to be contained in a smaller container in which it will be scrolled
- /// </summary>
- public class Scroller : Container
- {
- #region CTOR
- protected Scroller () : base(){}
- public Scroller (Interface iface) : base(iface){}
- #endregion
-
- //public event EventHandler<ScrollingEventArgs> Scrolled;
-
- int scrollX, scrollY, maxScrollX, maxScrollY, scrollSpeed;
-
- /// <summary>
- /// if true, key stroke are handled in derrived class
- /// </summary>
- protected bool KeyEventsOverrides = false;
-
- #region public properties
- /// <summary> Horizontal Scrolling Position </summary>
- [DefaultValue(0)]
- public virtual int ScrollX {
- get { return scrollX; }
- set {
- if (scrollX == value)
- return;
-
- int newS = value;
- if (newS < 0)
- newS = 0;
- else if (newS > maxScrollX)
- newS = maxScrollX;
-
- if (newS == scrollX)
- return;
-
- scrollX = value;
-
- NotifyValueChanged ("ScrollX", scrollX);
- RegisterForGraphicUpdate ();
- }
- }
- /// <summary> Vertical Scrolling Position </summary>
- [DefaultValue(0)]
- public virtual int ScrollY {
- get { return scrollY; }
- set {
- if (scrollY == value)
- return;
-
- int newS = value;
- if (newS < 0)
- newS = 0;
- else if (newS > maxScrollY)
- newS = maxScrollY;
-
- if (newS == scrollY)
- return;
-
- scrollY = value;
-
- NotifyValueChanged ("ScrollY", scrollY);
- RegisterForGraphicUpdate ();
- }
- }
- /// <summary> Horizontal Scrolling maximum value </summary>
- [DefaultValue(0)]
- public virtual int MaxScrollX {
- get { return maxScrollX; }
- set {
- if (maxScrollX == value)
- return;
-
- maxScrollX = value;
-
- if (scrollX > maxScrollX)
- ScrollX = maxScrollX;
-
- NotifyValueChanged ("MaxScrollX", maxScrollX);
- RegisterForGraphicUpdate ();
- }
- }
- /// <summary> Vertical Scrolling maximum value </summary>
- [DefaultValue(0)]
- public virtual int MaxScrollY {
- get { return maxScrollY; }
- set {
- if (maxScrollY == value)
- return;
-
- maxScrollY = value;
-
- if (scrollY > maxScrollY)
- ScrollY = maxScrollY;
-
- NotifyValueChanged ("MaxScrollY", maxScrollY);
- RegisterForGraphicUpdate ();
- }
- }
- /// <summary> Mouse Wheel Scrolling multiplier </summary>
- [DefaultValue(50)]
- public virtual int ScrollSpeed {
- get { return scrollSpeed; }
- set {
- if (scrollSpeed == value)
- return;
-
- scrollSpeed = value;
-
- NotifyValueChanged ("ScrollSpeed", scrollSpeed);
- }
- }
- #endregion
-
- public override void SetChild (Widget _child)
- {
- Group g = child as Group;
- if (g != null)
- g.ChildrenCleared -= onChildListCleared;
-
- base.SetChild (_child);
-
- g = _child as Group;
- if (g != null)
- g.ChildrenCleared += onChildListCleared;
- }
- public override void OnChildLayoutChanges (object sender, LayoutingEventArgs arg)
- {
- base.OnChildLayoutChanges (sender, arg);
- updateMaxScroll (arg.LayoutType);
- }
-
-
- #region GraphicObject Overrides
- public override Rectangle ScreenCoordinates (Rectangle r)
- {
- return base.ScreenCoordinates (r) - new Point((int)ScrollX,(int)ScrollY);
- }
- public override bool PointIsIn (ref Point m)
- {
- if (!base.PointIsIn(ref m))
- return false;
- if (!Slot.ContainsOrIsEqual (m) || child==null)
- return false;
- m += new Point (ScrollX, ScrollY);
- return true;
- }
- public override void RegisterClip (Rectangle clip)
- {
- base.RegisterClip (clip - new Point(ScrollX,ScrollY));
- }
- public override void OnLayoutChanges (LayoutingType layoutType)
- {
- base.OnLayoutChanges (layoutType);
-
- if (layoutType == LayoutingType.Height)
- NotifyValueChanged ("PageHeight", Slot.Height);
- else if (layoutType == LayoutingType.Width)
- NotifyValueChanged ("PageWidth", Slot.Width);
- else
- return;
- updateMaxScroll(layoutType);
- }
- protected override void onDraw (Context gr)
- {
- Rectangle rBack = new Rectangle (Slot.Size);
-
- Background.SetAsSource (gr, rBack);
- CairoHelpers.CairoRectangle(gr,rBack, CornerRadius);
- gr.Fill ();
-
- gr.Save ();
- if (ClipToClientRect) {
- //clip to scrolled client zone
- CairoHelpers.CairoRectangle (gr, ClientRectangle, CornerRadius);
- gr.Clip ();
- }
-
- gr.Translate (-ScrollX, -ScrollY);
- if (child != null)
- child.Paint (ref gr);
- gr.Restore ();
- }
-
- #region Mouse & Keyboard
- /// <summary> Process scrolling vertically, or if shift is down, vertically </summary>
- public override void onMouseWheel (object sender, MouseWheelEventArgs e)
- {
- if (IFace.Shift)
- ScrollX += e.Delta * ScrollSpeed;
- else
- ScrollY -= e.Delta * ScrollSpeed;
- e.Handled = true;
- base.onMouseWheel (sender, e);
- }
- /// <summary> Process scrolling with arrow keys, home and end keys. </summary>
- public override void onKeyDown (object sender, KeyEventArgs e)
- {
- base.onKeyDown (sender, e);
-
- if (KeyEventsOverrides)
- return;
-
- switch (e.Key) {
- case Key.Up:
- ScrollY--;
- break;
- case Key.Down:
- ScrollY++;
- break;
- case Key.Left:
- ScrollX--;
- break;
- case Key.Right:
- ScrollX++;
- break;
- case Key.Home:
- ScrollX = 0;
- ScrollY = 0;
- break;
- case Key.End:
- ScrollX = MaxScrollX;
- ScrollY = MaxScrollY;
- break;
- }
- }
- #endregion
-
- #endregion
-
- void updateMaxScroll (LayoutingType lt){
- if (Child == null) {
- MaxScrollX = 0;
- MaxScrollY = 0;
- return;
- }
-
- Rectangle cb = ClientRectangle;
-
- if (lt == LayoutingType.Height) {
- MaxScrollY = child.Slot.Height - cb.Height;
- if (child.Slot.Height > 0)
- NotifyValueChanged ("ChildHeightRatio", Slot.Height * Slot.Height / child.Slot.Height);
- } else if (lt == LayoutingType.Width) {
- MaxScrollX = child.Slot.Width - cb.Width;
- if (child.Slot.Width > 0)
- NotifyValueChanged ("ChildWidthRatio", Slot.Width * Slot.Width / child.Slot.Width);
- }
- }
- void onChildListCleared(object sender, EventArgs e){
- ScrollY = 0;
- ScrollX = 0;
- }
-
-
- }
-}
+++ /dev/null
-//
-// ScrollingObject.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.Xml.Serialization;
-using System.ComponentModel;
-using System.Collections;
-using Crow.Cairo;
-
-
-namespace Crow
-{
- /// <summary>
- /// generic class to build scrolling control in both directions
- /// </summary>
- [DesignIgnore]
- public class ScrollingObject : Widget
- {
- #region CTOR
- protected ScrollingObject ():base(){}
- public ScrollingObject (Interface iface):base(iface){}
- #endregion
-
- int scrollX, scrollY, maxScrollX, maxScrollY, mouseWheelSpeed;
-
- /// <summary>
- /// if true, key stroke are handled in derrived class
- /// </summary>
- protected bool KeyEventsOverrides = false;
-
- /// <summary> Horizontal Scrolling Position </summary>
- [DefaultValue(0)]
- public virtual int ScrollX {
- get { return scrollX; }
- set {
- if (scrollX == value)
- return;
-
- int newS = value;
- if (newS < 0)
- newS = 0;
- else if (newS > maxScrollX)
- newS = maxScrollX;
-
- if (newS == scrollX)
- return;
-
- scrollX = newS;
-
- NotifyValueChanged ("ScrollX", scrollX);
- RegisterForGraphicUpdate ();
- }
- }
- /// <summary> Vertical Scrolling Position </summary>
- [DefaultValue(0)]
- public virtual int ScrollY {
- get { return scrollY; }
- set {
- if (scrollY == value)
- return;
-
- int newS = value;
- if (newS < 0)
- newS = 0;
- else if (newS > maxScrollY)
- newS = maxScrollY;
-
- if (newS == scrollY)
- return;
-
- scrollY = newS;
-
- NotifyValueChanged ("ScrollY", scrollY);
- RegisterForGraphicUpdate ();
- }
- }
- /// <summary> Horizontal Scrolling maximum value </summary>
- [DefaultValue(0)]
- public virtual int MaxScrollX {
- get { return maxScrollX; }
- set {
- if (maxScrollX == value)
- return;
-
- maxScrollX = value;
-
- if (scrollX > maxScrollX)
- ScrollX = maxScrollX;
-
- NotifyValueChanged ("MaxScrollX", maxScrollX);
- RegisterForGraphicUpdate ();
- }
- }
- /// <summary> Vertical Scrolling maximum value </summary>
- [DefaultValue(0)]
- public virtual int MaxScrollY {
- get { return maxScrollY; }
- set {
- if (maxScrollY == value)
- return;
-
- maxScrollY = value;
-
- if (scrollY > maxScrollY)
- ScrollY = maxScrollY;
-
- NotifyValueChanged ("MaxScrollY", maxScrollY);
- RegisterForGraphicUpdate ();
- }
- }
- /// <summary> Mouse Wheel Scrolling multiplier </summary>
- [DefaultValue(1)]
- public virtual int MouseWheelSpeed {
- get { return mouseWheelSpeed; }
- set {
- if (mouseWheelSpeed == value)
- return;
-
- mouseWheelSpeed = value;
-
- NotifyValueChanged ("MouseWheelSpeed", mouseWheelSpeed);
- }
- }
-
- /// <summary> Process scrolling vertically, or if shift is down, vertically </summary>
- public override void onMouseWheel (object sender, MouseWheelEventArgs e)
- {
- base.onMouseWheel (sender, e);
- if (IFace.Shift)
- ScrollX += e.Delta * MouseWheelSpeed;
- else
- ScrollY -= e.Delta * MouseWheelSpeed;
- }
- /// <summary> Process scrolling with arrow keys, home and end keys. </summary>
- public override void onKeyDown (object sender, KeyEventArgs e)
- {
- base.onKeyDown (sender, e);
-
- if (KeyEventsOverrides)
- return;
-
- switch (e.Key) {
- case Key.Up:
- ScrollY--;
- break;
- case Key.Down:
- ScrollY++;
- break;
- case Key.Left:
- ScrollX--;
- break;
- case Key.Right:
- ScrollX++;
- break;
- case Key.Home:
- ScrollX = 0;
- ScrollY = 0;
- break;
- case Key.End:
- ScrollX = MaxScrollX;
- ScrollY = MaxScrollY;
- break;
- }
- }
- }
-}
-
+++ /dev/null
-// Copyright (c) 2013-2019 Bruyère Jean-Philippe jp_bruyere@hotmail.com
-//
-// This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT)
-
-using System;
-using System.ComponentModel;
-using System.IO;
-using System.Text;
-using Crow.Cairo;
-
-namespace Crow
-{
- public class PathParser : StringReader
- {
- public PathParser (string str) : base (str) {}
-
- double readDouble () {
- StringBuilder tmp = new StringBuilder();
-
- while (Peek () >= 0) {
- char c = (char)Read();
- if (c.IsWhiteSpaceOrNewLine()) {
- if (tmp.Length == 0)
- continue;
- else
- break;
- } else if (c == ',')
- break;
- tmp.Append (c);
- }
- return double.Parse (tmp.ToString ());
- }
- public void Draw (Context gr) {
- while (Peek () >= 0) {
- char c = (char)Read ();
- if (c.IsWhiteSpaceOrNewLine ())
- continue;
- switch (c) {
- case 'M':
- gr.MoveTo (readDouble (), readDouble ());
- break;
- case 'm':
- gr.RelMoveTo (readDouble (), readDouble ());
- break;
- case 'L':
- gr.LineTo (readDouble (), readDouble ());
- break;
- case 'l':
- gr.RelLineTo (readDouble (), readDouble ());
- break;
- case 'C':
- gr.CurveTo (readDouble (), readDouble (), readDouble (), readDouble (), readDouble (), readDouble ());
- break;
- case 'c':
- gr.RelCurveTo (readDouble (), readDouble (), readDouble (), readDouble (), readDouble (), readDouble ());
- break;
- case 'Z':
- gr.ClosePath ();
- break;
- case 'F':
- gr.Fill ();
- break;
- case 'G':
- gr.Stroke ();
- break;
- default:
- throw new Exception ("Invalid character in path string of Shape control");
- }
- }
- }
- }
- public class Shape : Widget
- {
- #region CTOR
- protected Shape () : base() {}
- public Shape (Interface iface) : base (iface) {}
- #endregion
-
- string path;
- double strokeWidth;
- Size size;
-
- public string Path {
- get { return path; }
- set {
- if (path == value)
- return;
- path = value;
- contentSize = default (Size);
- NotifyValueChanged ("Path", path);
- RegisterForGraphicUpdate ();
- }
- }
- [DefaultValue(1.0)]
- public double StokeWidth {
- get { return strokeWidth; }
- set {
- if (strokeWidth == value)
- return;
- strokeWidth = value;
- contentSize = default (Size);
- NotifyValueChanged ("StrokeWidth", strokeWidth);
- RegisterForGraphicUpdate ();
- }
- }
- [DefaultValue("0,0")]
- public Size Size
- {
- get { return size; }
- set
- {
- if (size == value)
- return;
- size = value;
- contentSize = default(Size);
- NotifyValueChanged("Size", size);
- RegisterForLayouting(LayoutingType.Sizing);
- }
- }
- protected override void onDraw(Context gr)
- {
-
- if (string.IsNullOrEmpty(path))
- return;
-
- gr.Save();
-
- Rectangle r = ClientRectangle;
-
-
- double sx = (double)r.Width / (double)(contentSize.Width == 0? size.Width : contentSize.Width);
- double sy = (double)r.Height / (double)(contentSize.Height == 0 ? size.Height : contentSize.Height);
-
- gr.Translate(r.Left, r.Top);
- gr.Scale (sx,sy);
-
- using (PathParser parser = new PathParser (path))
- parser.Draw (gr);
-
- Background.SetAsSource (gr, r);
- gr.FillPreserve ();
- gr.LineWidth = strokeWidth;
- Foreground.SetAsSource (gr, r);
- gr.Stroke ();
- gr.Restore();
- }
-
-
- protected override int measureRawSize (LayoutingType lt)
- {
- if ((lt == LayoutingType.Width && contentSize.Width == 0) || (lt == LayoutingType.Height && contentSize.Height == 0)) {
- if (size != default(Size))
- contentSize = size;
- else
- {
- using (Surface drawing = new ImageSurface(Format.A1, 1, 1))
- {
- using (Context ctx = new Context(drawing))
- {
- using (PathParser parser = new PathParser (path))
- parser.Draw (ctx);
- Rectangle r = ctx.StrokeExtents();
- contentSize = new Size(r.Right, r.Bottom);
- }
- }
- }
- }
- return lt == LayoutingType.Width ?
- contentSize.Width + 2 * Margin: contentSize.Height + 2 * Margin;
- }
- }
-}
-
+++ /dev/null
-//
-// Slider.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 Crow.Cairo;
-using System.Xml.Serialization;
-using System.ComponentModel;
-using System.Diagnostics;
-
-namespace Crow
-{
- /// <summary>
- /// templated numeric control to select a value
- /// by slidding a cursor
- /// </summary>
- public class Slider : NumericControl
- {
- #region CTOR
- protected Slider() : base(){}
- public Slider(Interface iface) : base(iface)
- {}
-// public Slider(double minimum, double maximum, double step)
-// : base(minimum,maximum,step)
-// {
-// }
- #endregion
-
- #region implemented abstract members of TemplatedControl
-
- protected override void loadTemplate (Widget template = null)
- {
-
- }
-
- #endregion
-
- #region private fields
- Rectangle cursor;
- int _cursorSize;
- Fill _cursorColor;
- Orientation _orientation;
- bool holdCursor = false;
- #endregion
-
- protected double unity;
-
- #region Public properties
- [DefaultValue("vgradient|0:White|0,1:LightGrey|0,9:LightGrey|1:DimGrey")]
- public virtual Fill CursorColor {
- get { return _cursorColor; }
- set {
- if (_cursorColor == value)
- return;
- _cursorColor = value;
- RegisterForRedraw ();
- NotifyValueChanged ("CursorColor", _cursorColor);
- }
- }
- [DefaultValue(20)]
- public virtual int CursorSize {
- get { return _cursorSize; }
- set {
- if (_cursorSize == value || value < 8)
- return;
- _cursorSize = value;
- RegisterForGraphicUpdate ();
- NotifyValueChanged ("CursorSize", _cursorSize);
- }
- }
- [DefaultValue(Orientation.Horizontal)]
- public virtual Orientation Orientation
- {
- get { return _orientation; }
- set {
- if (_orientation == value)
- return;
- _orientation = value;
-
- RegisterForLayouting (LayoutingType.All);
- NotifyValueChanged ("Orientation", _orientation);
- }
- }
- #endregion
-
- //[DefaultValue(10.0)]
- //public override double Maximum {
- // get { return base.Maximum; }
- // set {
- // if (value == base.Maximum)
- // return;
- // base.Maximum = value;
- // LargeIncrement = base.Maximum / 10.0;
- // SmallIncrement = LargeIncrement / 5.0;
- // }
- //}
-
- #region GraphicObject Overrides
- protected override void onDraw (Context gr)
- {
- base.onDraw (gr);
-
- if (Maximum <= 0)
- return;
-
- computeCursorPosition ();
-
- Rectangle r = ClientRectangle;
- PointD pStart;
- PointD pEnd;
- if (_orientation == Orientation.Horizontal) {
- pStart = r.TopLeft + new Point (_cursorSize / 2, r.Height / 2);
- pEnd = r.TopRight + new Point (-_cursorSize / 2, r.Height / 2);
- pStart.Y += 0.5;
- pEnd.Y += 0.5;
- } else {
- pStart = r.TopLeft + new Point (r.Width / 2, _cursorSize / 2);
- pEnd = r.BottomLeft + new Point (r.Width / 2,- _cursorSize / 2);
- pStart.X += 0.5;
- pEnd.X += 0.5;
-
- }
-
- Background.SetAsSource(gr, r);
- gr.Rectangle (r);
- gr.Fill ();
-
- DrawGraduations (gr, pStart,pEnd);
-
- DrawCursor (gr, cursor);
- }
- #endregion
-
- protected virtual void DrawGraduations(Context gr, PointD pStart, PointD pEnd)
- {
- Foreground.SetAsSource (gr);
-
- gr.LineWidth = 1;
- gr.MoveTo(pStart);
- gr.LineTo(pEnd);
-
- gr.Stroke();
-
- }
- protected virtual void DrawCursor(Context gr, Rectangle _cursor)
- {
- CairoHelpers.CairoRectangle (gr, _cursor, CornerRadius);
- Foreground.SetAsSource(gr, _cursor);
- gr.StrokePreserve();
- CursorColor.SetAsSource(gr, _cursor);
- gr.Fill();
- }
-
- void computeCursorPosition()
- {
- Rectangle r = ClientRectangle;
- PointD p1;
-
- if (_orientation == Orientation.Horizontal) {
- cursor = new Rectangle (new Size (_cursorSize, (int)(r.Height)));
- p1 = r.TopLeft + new Point (_cursorSize / 2, r.Height / 2);
- unity = (double)(r.Width - _cursorSize) / (Maximum - Minimum);
- cursor.TopLeft = new Point (r.Left + (int)((Value - Minimum) * unity),
- (int)(p1.Y - cursor.Height / 2));
- } else {
- cursor = new Rectangle (new Size ((int)(r.Width), _cursorSize));
- p1 = r.TopLeft + new Point (r.Width / 2, _cursorSize / 2);
- unity = (double)(r.Height - _cursorSize) / (Maximum - Minimum);
- cursor.TopLeft = new Point ((int)(p1.X - r.Width / 2),
- r.Top + (int)((Value - Minimum) * unity));
- }
- //cursor.Inflate (-1);
- }
- Point mouseDownInit;
- double mouseDownInitValue;
-
- #region mouse handling
- public override void onMouseDown (object sender, MouseButtonEventArgs e)
- {
- base.onMouseDown (sender, e);
- mouseDownInit = ScreenPointToLocal (e.Position);
- mouseDownInitValue = Value;
- Rectangle cursInScreenCoord = ScreenCoordinates (cursor + Slot.Position);
- if (cursInScreenCoord.ContainsOrIsEqual (e.Position)){
-// Rectangle r = ClientRectangle;
-// if (r.Width - _cursorSize > 0) {
-// double unit = (Maximum - Minimum) / (double)(r.Width - _cursorSize);
-// mouseDownInit += new Point ((int)(Value / unit), (int)(Value / unit));
-// }
- holdCursor = true;
- }else if (_orientation == Orientation.Horizontal) {
- if (e.Position.X < cursInScreenCoord.Left)
- Value -= LargeIncrement;
- else
- Value += LargeIncrement;
- } else {
- if (e.Position.Y < cursInScreenCoord.Top)
- Value -= LargeIncrement;
- else
- Value += LargeIncrement;
- }
- }
- public override void onMouseUp (object sender,MouseButtonEventArgs e)
- {
- base.onMouseUp (sender, e);
-
- holdCursor = false;
- }
- public override void onMouseMove (object sender, MouseMoveEventArgs e)
- {
- if (holdCursor) {
- Point m = ScreenPointToLocal (e.Position) - mouseDownInit;
- Rectangle r = ClientRectangle;
-
- if (_orientation == Orientation.Horizontal) {
- if (r.Width - _cursorSize == 0)
- return;
- double unit = (Maximum - Minimum) / (double)(r.Width - _cursorSize);
- double tmp = mouseDownInitValue + (double)m.X * unit;
- tmp -= tmp % SmallIncrement;
- Value = tmp;
- } else {
- if (r.Height - _cursorSize == 0)
- return;
- double unit = (Maximum - Minimum) / (double)(r.Height - _cursorSize);
- double tmp = mouseDownInitValue + (double)m.Y * unit;
- tmp -= tmp % SmallIncrement;
- Value = tmp;
- }
- }
-
- base.onMouseMove (sender, e);
- }
- #endregion
- }
-}
+++ /dev/null
-// Copyright (c) 2013-2019 Bruyère Jean-Philippe <jp_bruyere@hotmail.com>
-//
-// This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT)
-
-namespace Crow
-{
- /// <summary>
- /// templated control for selecting a numeric value by clicking on
- /// up and down buttons
- /// </summary>
- public class Spinner : NumericControl
- {
- #region CTOR
- protected Spinner() : base(){}
- public Spinner (Interface iface) : base(iface)
- {
- }
- #endregion
-
- void onUp (object sender, MouseButtonEventArgs e)
- {
- Value += this.SmallIncrement;
- }
- void onDown (object sender, MouseButtonEventArgs e)
- {
- Value -= this.SmallIncrement;
- }
-
- }
-}
-
+++ /dev/null
-//
-// Splitter.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.Xml.Serialization;
-using System.ComponentModel;
-
-namespace Crow
-{
- /// <summary>
- /// control to add between children of a Stack to allow them to be resized
- /// with the pointer
- /// </summary>
- public class Splitter : Widget
- {
- #region CTOR
- protected Splitter() : base(){}
- public Splitter (Interface iface) : base(iface){}
- #endregion
-
- int thickness;
-
- [DefaultValue(1)]
- public virtual int Thickness {
- get { return thickness; }
- set {
- if (thickness == value)
- return;
- thickness = value;
- NotifyValueChanged ("Thickness", thickness);
- RegisterForLayouting (LayoutingType.Sizing);
- RegisterForGraphicUpdate ();
- }
- }
-
- Unit u1, u2;
- int init1 = -1, init2 = -1, delta = 0, min1, min2, max1 , max2;
- Widget go1 = null, go2 = null;
-
- void initSplit(Measure m1, int size1, Measure m2, int size2){
- if (m1 != Measure.Stretched) {
- init1 = size1;
- u1 = m1.Units;
- }
- if (m2 != Measure.Stretched) {
- init2 = size2;
- u2 = m2.Units;
- }
- }
- void convertSizeInPix(Widget g1){
-
- }
-
- #region GraphicObject override
- public override ILayoutable Parent {
- get { return base.Parent; }
- set {
- if (value != null) {
- GenericStack gs = value as GenericStack;
- if (gs == null)
- throw new Exception ("Splitter may only be chil of stack");
-
- }
- base.Parent = value;
- }
- }
- public override void onMouseEnter (object sender, MouseMoveEventArgs e)
- {
- base.onMouseEnter (sender, e);
- if ((Parent as GenericStack).Orientation == Orientation.Horizontal)
- IFace.MouseCursor = MouseCursor.H;
- else
- IFace.MouseCursor = MouseCursor.V;
- }
- public override void onMouseDown (object sender, MouseButtonEventArgs e)
- {
- base.onMouseDown (sender, e);
- go1 = go2 = null;
- init1 = init2 = -1;
- delta = 0;
-
- GenericStack gs = Parent as GenericStack;
- int ptrSplit = gs.Children.IndexOf (this);
- if (ptrSplit == 0 || ptrSplit == gs.Children.Count - 1)
- return;
-
- go1 = gs.Children [ptrSplit - 1];
- go2 = gs.Children [ptrSplit + 1];
-
- if (gs.Orientation == Orientation.Horizontal) {
- initSplit (go1.Width, go1.Slot.Width, go2.Width, go2.Slot.Width);
- min1 = go1.MinimumSize.Width;
- min2 = go2.MinimumSize.Width;
- max1 = go1.MaximumSize.Width;
- max2 = go2.MaximumSize.Width;
- if (init1 >= 0)
- go1.Width = init1;
- if (init2 >= 0)
- go2.Width = init2;
- } else {
- initSplit (go1.Height, go1.Slot.Height, go2.Height, go2.Slot.Height);
- min1 = go1.MinimumSize.Height;
- min2 = go2.MinimumSize.Height;
- max1 = go1.MaximumSize.Height;
- max2 = go2.MaximumSize.Height;
- if (init1 >= 0)
- go1.Height = init1;
- if (init2 >= 0)
- go2.Height = init2;
- }
- }
- public override void onMouseMove (object sender, MouseMoveEventArgs e)
- {
- base.onMouseMove (sender, e);
-
- if (!IsActive || go1 == null || go2 == null)
- return;
-
- GenericStack gs = Parent as GenericStack;
- int newDelta = delta, size1 = init1 , size2 = init2;
- if (gs.Orientation == Orientation.Horizontal) {
- newDelta -= e.XDelta;
- if (size1 < 0)
- size1 = go1.Slot.Width + delta;
- if (size2 < 0)
- size2 = go2.Slot.Width - delta;
- } else {
- newDelta -= e.YDelta;
- if (size1 < 0)
- size1 = go1.Slot.Height + delta;
- if (size2 < 0)
- size2 = go2.Slot.Height - delta;
- }
-
- if (size1 - newDelta < min1 || (max1 > 0 && size1 - newDelta > max1) ||
- size2 + newDelta < min2 || (max2 > 0 && size2 + newDelta > max2))
- return;
-
- delta = newDelta;
-
- if (gs.Orientation == Orientation.Horizontal) {
- if (init1 >= 0)
- go1.Width = init1 - delta;
- if (init2 >= 0)
- go2.Width = init2 + delta;
- } else {
- if (init1 >= 0)
- go1.Height = init1 - delta;
- if (init2 >= 0)
- go2.Height = init2 + delta;
- }
- }
- public override void onMouseUp (object sender, MouseButtonEventArgs e)
- {
- base.onMouseUp (sender, e);
-
- GenericStack gs = Parent as GenericStack;
-
- if (init1 >= 0 && u1 == Unit.Percent) {
- if (gs.Orientation == Orientation.Horizontal)
- go1.Width = new Measure ((int)Math.Ceiling (
- go1.Width.Value * 100.0 / (double)gs.Slot.Width), Unit.Percent);
- else
- go1.Height = new Measure ((int)Math.Ceiling (
- go1.Height.Value * 100.0 / (double)gs.Slot.Height), Unit.Percent);
- }
- if (init2 >= 0 && u2 == Unit.Percent) {
- if (gs.Orientation == Orientation.Horizontal)
- go2.Width = new Measure ((int)Math.Floor (
- go2.Width.Value * 100.0 / (double)gs.Slot.Width), Unit.Percent);
- else
- go2.Height = new Measure ((int)Math.Floor (
- go2.Height.Value * 100.0 / (double)gs.Slot.Height), Unit.Percent);
- }
- }
- public override bool UpdateLayout (LayoutingType layoutType)
- {
- GenericStack gs = Parent as GenericStack;
- if (layoutType == LayoutingType.Width){
- if (gs.Orientation == Orientation.Horizontal)
- Width = thickness;
- else
- Width = Measure.Stretched;
- } else if (layoutType == LayoutingType.Height){
- if (gs.Orientation == Orientation.Vertical)
- Height = thickness;
- else
- Height = Measure.Stretched;
- }
- return base.UpdateLayout (layoutType);
- }
- public override 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) ;
- Rectangle r = Slot;
- if (Width == Measure.Stretched)
- r.Inflate (0, 5);
- else
- r.Inflate (5, 0);
- return r.ContainsOrIsEqual (m);
- }
- #endregion
- }
-}
-
+++ /dev/null
-//
-// TabItem.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.Xml.Serialization;
-using System.ComponentModel;
-using System.Diagnostics;
-using Crow.Cairo;
-using System.Linq;
-
-namespace Crow
-{
- public class TabItem : TemplatedContainer
- {
- #region CTOR
- protected TabItem() : base(){}
- public TabItem (Interface iface) : base(iface){}
- #endregion
-
- public event EventHandler QueryClose;
-
- internal TabView tview = null;
-
- #region Private fields
- Widget titleWidget;
- int tabOffset;
- bool isSelected;
- //Measure tabThickness;
- Fill selectedBackground = Color.Transparent;
- #endregion
-
- #region TemplatedControl overrides
- public override Widget Content {
- get {
- return _contentContainer == null ? null : _contentContainer.Child;
- }
- set {
- if (Content != null) {
- Content.LogicalParent = null;
- _contentContainer.SetChild (null);
- }
- _contentContainer.SetChild(value);
- if (value != null)
- value.LogicalParent = this;
- }
- }
- protected override void loadTemplate(Widget template = null)
- {
- base.loadTemplate (template);
-
- titleWidget = this.child.FindByName ("TabTitle");
- }
- internal Widget TabTitle { get { return titleWidget; }}
- #endregion
-
- /// <summary>
- /// order of redrawing, items can't be reordered in TemplatedGroup due to data linked, so we need another index
- /// instead of children list order
- /// </summary>
- public int viewIndex = 0;
- public virtual int ViewIndex {
- get { return viewIndex; }
- set {
- if (viewIndex == value)
- return;
- viewIndex = value;
- NotifyValueChanged ("ViewIndex", viewIndex);
- }
- }
-
- [DefaultValue(0)]
- public int TabOffset {
- get { return tabOffset; }
- set {
- if (tabOffset == value)
- return;
- tabOffset = value;
- NotifyValueChanged ("TabOffset", tabOffset);
-
- RegisterForLayouting (LayoutingType.X);
- RegisterForGraphicUpdate ();
- }
- }
- public Measure TabHeight {
- get { return tview == null ? Measure.Fit : tview.TabHeight; }
- }
- public Measure TabWidth {
- get { return tview == null ? Measure.Fit : tview.TabWidth; }
- }
- [DefaultValue(false)]
- public virtual bool IsSelected {
- get { return isSelected; }
- set {
- if (isSelected == value)
- return;
-
- if (tview != null)
- tview.SelectedTab = tview.Children.IndexOf(this);
-
- isSelected = value;
- NotifyValueChanged ("IsSelected", isSelected);
- RegisterForRedraw ();
- }
- }
-
- /// <summary>
- /// background fill of the control, maybe solid color, gradient, image, or svg
- /// </summary>
- [DesignCategory ("Appearance")][DefaultValue("DimGrey")]
- public virtual Fill SelectedBackground {
- get { return selectedBackground; }
- set {
- if (selectedBackground == value)
- return;
- if (value == null)
- return;
- selectedBackground = value;
- NotifyValueChanged ("SelectedBackground", selectedBackground);
- RegisterForRedraw ();
- }
- }
- protected override void onDraw (Context gr)
- {
- gr.Save ();
-
- TabView tv = Parent as TabView;
-
- Rectangle r = TabTitle.Slot;
- r.Width = TabWidth;
-
- gr.MoveTo (0.5, r.Bottom-0.5);
- gr.LineTo (r.Left - tv.LeftSlope, r.Bottom-0.5);
- gr.CurveTo (
- r.Left - tv.LeftSlope / 2, r.Bottom-0.5,
- r.Left - tv.LeftSlope / 2, 0.5,
- r.Left, 0.5);
- gr.LineTo (r.Right, 0.5);
- gr.CurveTo (
- r.Right + tv.RightSlope / 2, 0.5,
- r.Right + tv.RightSlope / 2, r.Bottom-0.5,
- r.Right + tv.RightSlope, r.Bottom-0.5);
- gr.LineTo (Slot.Width-0.5, r.Bottom-0.5);
-
-
- gr.LineTo (Slot.Width-0.5, Slot.Height-0.5);
- gr.LineTo (0.5, Slot.Height-0.5);
- gr.ClosePath ();
- gr.LineWidth = 1;
- Foreground.SetAsSource (gr);
- gr.StrokePreserve ();
- gr.ClipPreserve ();
-
- if (IsSelected)
- SelectedBackground.SetAsSource (gr, ClientRectangle);
- else
- Background.SetAsSource (gr, ClientRectangle);
-
- gr.Fill ();
-
- base.onDraw (gr);
-
- gr.Restore ();
- }
-
- Point dragStartPoint;
- int dragThreshold = 16;
- int dis = 128;
- internal TabView savedParent = null;
-
-
- void makeFloating (TabView tv) {
- lock (IFace.UpdateMutex) {
- ImageSurface di = new ImageSurface (Format.Argb32, dis, dis);
- IFace.DragImageHeight = dis;
- IFace.DragImageWidth = dis;
- using (Context ctx = new Context (di)) {
- double div = Math.Max (LastPaintedSlot.Width, LastPaintedSlot.Height);
- double s = (double)dis / 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 ();
- }
- }
- IFace.DragImage = di;
- }
- tv.RemoveChild (this);
- savedParent = tv;
- }
-
- public override ILayoutable Parent {
- get {
- return base.Parent;
- }
- set {
- base.Parent = value;
- if (value != null) {
- dragStartPoint = IFace.Mouse.Position;
- savedParent = value as TabView;
- }
- }
- }
- protected override void onStartDrag (object sender, DragDropEventArgs e)
- {
- base.onStartDrag (sender, e);
-
- dragStartPoint = IFace.Mouse.Position;
- }
- protected override void onEndDrag (object sender, DragDropEventArgs e)
- {
- base.onEndDrag (sender, e);
-
- if (Parent != null)
- return;
-
- savedParent.AddChild (this);
-
- IFace.ClearDragImage ();
- }
- protected override void onDrop (object sender, DragDropEventArgs e)
- {
- base.onDrop (sender, e);
- if (Parent != null)
- return;
- TabView tv = e.DropTarget as TabView;
- if (tv == null)
- return;
-
- IFace.ClearDragImage ();
-
- tv.AddChild (this);
- }
- #region Mouse Handling
- public override bool PointIsIn (ref Point m)
- {
- if (!base.PointIsIn (ref m))
- return false;
- if (tview == null)//double check this, just added to prevent exception
- return false;
- if (m.Y < tview.TabHeight)
- return TabTitle.Slot.ContainsOrIsEqual (m);
- else
- return this.isSelected;
- }
- public override void onMouseUp (object sender, MouseButtonEventArgs e)
- {
- base.onMouseUp (sender, e);
- tview?.UpdateLayout (LayoutingType.ArrangeChildren);
- }
- public override void onMouseMove (object sender, MouseMoveEventArgs e)
- {
- base.onMouseMove (sender, e);
-
- if (Parent == null)
- return;
-
- if (!IsDragged)
- return;
-
- TabView tv = Parent as TabView;
- if (Math.Abs (e.Position.Y - dragStartPoint.Y) > dragThreshold ||
- Math.Abs (e.Position.X - dragStartPoint.X) > dragThreshold) {
- makeFloating (tv);
- return;
- }
-
- Rectangle cb = ClientRectangle;
-
- int tmp = TabOffset + e.XDelta;
- if (tmp < tview.LeftSlope) {
- TabOffset = tview.LeftSlope;
- } else if (tmp > cb.Width - tv.RightSlope - tv.TabWidth) {
- TabOffset = cb.Width - tv.RightSlope - tv.TabWidth;
- }else{
- dragStartPoint.X = e.Position.X;
- TabItem[] tabItms = tv.Children.Cast<TabItem>().OrderBy (t=>t.ViewIndex).ToArray();
- if (ViewIndex > 0 && e.XDelta < 0) {
- TabItem previous = tabItms [ViewIndex - 1];
- if (tmp < previous.TabOffset + tview.TabWidth / 2) {
- previous.ViewIndex = ViewIndex;
- ViewIndex--;
- tv.UpdateLayout (LayoutingType.ArrangeChildren);
- }
-
- }else if (ViewIndex < tabItms.Length - 1 && e.XDelta > 0) {
- TabItem next = tabItms [ViewIndex + 1];
- if (tmp > next.TabOffset - tview.TabWidth / 2){
- next.ViewIndex = ViewIndex;
- ViewIndex++;
- tv.UpdateLayout (LayoutingType.ArrangeChildren);
- }
- }
- TabOffset = tmp;
- }
- }
- public void butCloseTabClick (object sender, MouseButtonEventArgs e){
- QueryClose.Raise (this, null);
- //if tab is used as a templated item root in a templatedGroup, local datasource
- //is not null, in this case, removing the data entries will delete automatically the item
- if (localDataSourceIsNull)
- (Parent as TabView)?.DeleteChild (this);
- }
- #endregion
-
- }
-}
-
+++ /dev/null
-//
-// TabView.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.Xml.Serialization;
-using System.ComponentModel;
-using Crow.Cairo;
-using System.Diagnostics;
-using System.Linq;
-
-namespace Crow
-{
- public class TabView : Group
- {
- #region CTOR
- public TabView() : base(){}
- public TabView (Interface iface) : base(iface){}
- #endregion
-
- #region Private fields
- int adjustedTab = -1;
- int leftSlope;
- int rightSlope;
- Measure tabHeight, tabWidth;
- Orientation _orientation;
- int selectedTab;
- #endregion
-
- #region public properties
- [DefaultValue(Orientation.Horizontal)]
- public virtual Orientation Orientation
- {
- get { return _orientation; }
- set {
- if (_orientation == value)
- return;
- _orientation = value;
- NotifyValueChanged ("Orientation", _orientation);
- if (_orientation == Orientation.Horizontal)
- NotifyValueChanged ("TabOrientation", Orientation.Vertical);
- else
- NotifyValueChanged ("TabOrientation", Orientation.Horizontal);
- this.RegisterForLayouting (LayoutingType.ArrangeChildren);
- }
- }
- [DefaultValue(16)]
- public int LeftSlope
- {
- get { return leftSlope; }
- set {
- if (leftSlope == value)
- return;
- leftSlope = value;
- NotifyValueChanged ("leftSlope", leftSlope);
- //tabSizeHasChanged = true;
- //RegisterForLayouting (LayoutingType.ArrangeChildren);
- }
- }
- //bool tabSizeHasChanged = false;
- [DefaultValue(16)]
- public int RightSlope
- {
- get { return rightSlope; }
- set {
- if (rightSlope == value)
- return;
- rightSlope = value;
- NotifyValueChanged ("RightSlope", rightSlope);
- //tabSizeHasChanged = true;
- //RegisterForLayouting (LayoutingType.ArrangeChildren);
- }
- }
- [DefaultValue("18")]
- public Measure TabHeight {
- get { return tabHeight; }
- set {
- if (tabHeight == value)
- return;
- tabHeight = value;
- NotifyValueChanged ("TabHeight", tabHeight);
-// childrenRWLock.EnterReadLock ();
-// foreach (GraphicObject ti in Children) {
-// ti.NotifyValueChanged ("TabHeight", tabHeight);
-// }
-// childrenRWLock.ExitReadLock ();
- RegisterForLayouting (LayoutingType.ArrangeChildren);
- }
- }
- [DefaultValue("120")]
- public Measure TabWidth {
- get { return adjustedTab > 0 ? (Measure)adjustedTab : tabWidth; }
- set {
- if (tabWidth == value)
- return;
- tabWidth = value;
- NotifyValueChanged ("TabWidth", TabWidth);
-//
-// childrenRWLock.EnterReadLock ();
-// foreach (GraphicObject ti in Children) {
-// ti.NotifyValueChanged ("TabWidth", tabWidth);
-// }
-// childrenRWLock.ExitReadLock ();
- RegisterForLayouting (LayoutingType.ArrangeChildren);
- }
- }
-
- public virtual int SelectedTab {
- get { return selectedTab; }
- set {
- if (value == selectedTab)
- return;
-
- if (selectedTab < Children.Count && selectedTab >= 0)
- (Children [selectedTab] as TabItem).IsSelected = false;
-
- selectedTab = value;
-
- if (selectedTab < Children.Count && selectedTab >= 0)
- (Children [selectedTab] as TabItem).IsSelected = true;
-
- NotifyValueChanged ("SelectedTab", selectedTab);
- RegisterForRedraw ();
- }
- }
- #endregion
-
- public override void AddChild (Widget child)
- {
- TabItem ti = child as TabItem;
- if (ti == null)
- throw new Exception ("TabView control accept only TabItem as child.");
-
- ti.MouseDown += Ti_MouseDown;
- ti.TabTitle.LayoutChanged += Ti_TabTitle_LayoutChanged;
- ti.tview = this;
-
- base.AddChild (child);
-
- SelectedTab = ti.ViewIndex = Children.Count - 1;
- this.RegisterForLayouting (LayoutingType.ArrangeChildren);
- }
- public override void RemoveChild (Widget child)
- {
- TabItem ti = child as TabItem;
- if (ti == null)
- throw new Exception ("TabView control accept only TabItem as child.");
-
- ti.MouseDown -= Ti_MouseDown;
- ti.TabTitle.LayoutChanged -= Ti_TabTitle_LayoutChanged;
- ti.tview = null;
-
- childrenRWLock.EnterReadLock ();
-
- TabItem[] tabItms = Children.Cast<TabItem>().OrderBy (t=>t.ViewIndex).ToArray();
- int selTabViewIdx = -1;
-
- if (SelectedTab < tabItms.Length && SelectedTab >= 0)
- selTabViewIdx = (Children [SelectedTab] as TabItem).ViewIndex;
-
- for (int i = selTabViewIdx+1; i < tabItms.Length; i++)
- tabItms [i].ViewIndex--;
-
- if (selTabViewIdx > tabItms.Length - 2)
- selTabViewIdx = tabItms.Length - 2;
-
- if (selTabViewIdx < 0)
- SelectedTab = -1;
- else
- SelectedTab = Children.IndexOf (tabItms [selTabViewIdx]);
-
- childrenRWLock.ExitReadLock ();
-
- base.RemoveChild (child);
- }
-
- public override bool ArrangeChildren { get { return true; } }
- public override bool UpdateLayout (LayoutingType layoutType)
- {
- RegisteredLayoutings &= (~layoutType);
-
- if (layoutType == LayoutingType.ArrangeChildren && Children.Count > 0) {
- Rectangle cb = ClientRectangle;
-
- int tabSpace = tabWidth + leftSlope;
- int tc = Children.Count (c => c.Visible == true);
-
- if (tc > 0)
- tabSpace = Math.Min(tabSpace, (cb.Width-rightSlope) / tc);
-
- if (tabSpace < tabWidth + leftSlope)
- adjustedTab = tabSpace - leftSlope;
- else
- adjustedTab = -1;
-
- //Console.WriteLine ("tabspace: {0} tw:{1}", tabSpace, tabWidth);
-
- childrenRWLock.EnterReadLock();
- TabItem[] tabItms = Children.Cast<TabItem>().OrderBy (t=>t.ViewIndex).ToArray();
- childrenRWLock.ExitReadLock();
- int curOffset = leftSlope;
-
- for (int i = 0; i < tabItms.Length; i++) {
- if (!tabItms [i].Visible)
- continue;
- tabItms [i].NotifyValueChanged ("TabHeight", tabHeight);
- tabItms [i].NotifyValueChanged ("TabWidth", TabWidth);
- if (!tabItms [i].IsDragged) {
- tabItms [i].TabOffset = curOffset;
- //Console.WriteLine ("offset: {0}=>{1}", tabItms [i].Name, tabItms [i].TabOffset);
- }
- if (Orientation == Orientation.Horizontal) {
- curOffset += tabSpace;
- } else
- curOffset += tabSpace;
- }
-
- //if no layouting remains in queue for item, registre for redraw
- if (RegisteredLayoutings == LayoutingType.None && IsDirty)
- IFace.EnqueueForRepaint (this);
-
- return true;
- }
-
- return base.UpdateLayout(layoutType);
- }
- public override void OnLayoutChanges (LayoutingType layoutType)
- {
- if (_orientation == Orientation.Horizontal) {
- if (layoutType == LayoutingType.Width)
- RegisterForLayouting (LayoutingType.ArrangeChildren);
- } else if (layoutType == LayoutingType.Height)
- RegisterForLayouting (LayoutingType.ArrangeChildren);
-
- base.OnLayoutChanges (layoutType);
- }
-
- protected override void onDraw (Context gr)
- {
- Rectangle rBack = new Rectangle (Slot.Size);
-
- Background.SetAsSource (gr, rBack);
- CairoHelpers.CairoRectangle(gr,rBack, CornerRadius);
- gr.Fill ();
-
- gr.Save ();
-
- if (ClipToClientRect) {
- //clip to client zone
- CairoHelpers.CairoRectangle (gr, ClientRectangle, CornerRadius);
- gr.Clip ();
- }
-
- childrenRWLock.EnterReadLock ();
-
- TabItem[] tabItms = Children.Where(tt=>tt.Visible).Cast<TabItem> ().
- OrderBy (t => t.ViewIndex).ToArray ();
-
- int selTabViewIdx = -1;
- if (SelectedTab < tabItms.Length && SelectedTab >= 0)
- selTabViewIdx = (Children [SelectedTab] as TabItem).ViewIndex;
-
- childrenRWLock.ExitReadLock ();
-
- int i = 0;
- while (i < selTabViewIdx) {
- tabItms [i].Paint (ref gr);
- i++;
- }
- i = tabItms.Length - 1;
- while (i > selTabViewIdx) {
- tabItms [i].Paint (ref gr);
- i--;
- }
-
- if (selTabViewIdx >= 0)
- tabItms [selTabViewIdx].Paint (ref gr);
-
- gr.Restore ();
- }
-
- protected override void onDragEnter (object sender, DragDropEventArgs e)
- {
- base.onDragEnter (sender, e);
-
- TabItem ti = e.DragSource as TabItem;
- if (ti == null)
- return;
- if (ti.Parent != null || ti.savedParent == this)
- return;
-
- this.AddChild (ti);
-
- Point p = ScreenPointToLocal (IFace.Mouse.Position) - Margin;
-
- p.X = Math.Max (leftSlope, p.X);
- p.X = Math.Min (ClientRectangle.Width - rightSlope - TabWidth, p.X);
- ti.TabOffset = p.X;
-
- IFace.ClearDragImage ();
-
- }
-
- void Ti_TabTitle_LayoutChanged (object sender, LayoutingEventArgs e)
- {
- if (e.LayoutType == LayoutingType.X)
- RegisterForLayouting (LayoutingType.ArrangeChildren);
- }
- void Ti_MouseDown (object sender, MouseButtonEventArgs e)
- {
- SelectedTab = Children.IndexOf (sender as Widget);
- }
- }
-}
-
+++ /dev/null
-// Copyright (c) 2013-2019 Bruyère Jean-Philippe jp_bruyere@hotmail.com
-//
-// This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT)
-
-using System;
-using System.Xml.Serialization;
-using System.Xml;
-using System.Reflection;
-
-namespace Crow
-{
- /// <summary>
- /// base class for new containers that will use templates.
- ///
- /// TemplatedControl's **must** provide a widget of the [`Container`](Container) class named **_'Content'_** inside their template tree
- /// </summary>
- public class TemplatedContainer : TemplatedControl
- {
- #if DESIGN_MODE
- public override void getIML (System.Xml.XmlDocument doc, System.Xml.XmlNode parentElem)
- {
- if (this.design_isTGItem)
- return;
- base.getIML (doc, parentElem);
- if (!HasContent)
- return;
- Content.getIML (doc, parentElem.LastChild);
- }
- #endif
-
- #region CTOR
- protected TemplatedContainer() : base(){}
- public TemplatedContainer (Interface iface) : base(iface){}
- #endregion
-
- protected Container _contentContainer;
-
- /// <summary>
- /// Single child of this templated container.
- /// </summary>
- public virtual Widget Content {
- get {
- return _contentContainer == null ? null : _contentContainer.Child;
- }
- set {
- _contentContainer.SetChild(value);
- NotifyValueChanged ("HasContent", HasContent);
- }
- }
- [XmlIgnore]public bool HasContent {
- get { return _contentContainer?.Child != null; }
- }
- //TODO: move loadTemplate and ResolveBinding in TemplatedContainer
- protected override void loadTemplate(Widget template = null)
- {
- base.loadTemplate (template);
- _contentContainer = this.child.FindByName ("Content") as Container;
- }
-
- #region GraphicObject overrides
- public override Widget FindByName (string nameToFind)
- {
- if (Name == nameToFind)
- return this;
-
- return Content == null ? null : Content.FindByName (nameToFind);
- }
- public override bool Contains (Widget goToFind)
- {
- if (Content == goToFind)
- return true;
- if (Content?.Contains (goToFind) == true)
- return true;
- return base.Contains (goToFind);
- }
- #endregion
- }
-}
-
+++ /dev/null
-// Copyright (c) 2013-2019 Bruyère Jean-Philippe jp_bruyere@hotmail.com
-//
-// This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT)
-
-using System;
-using System.ComponentModel;
-using System.IO;
-using System.Reflection;
-using System.Xml;
-using Crow.Cairo;
-
-namespace Crow
-{
- /// <summary>
- /// Base class for all templated widget
- /// </summary>
- public abstract class TemplatedControl : PrivateContainer
- {
- #if DESIGN_MODE
- public bool design_inlineTemplate = false;
- public override void getIML (XmlDocument doc, XmlNode parentElem)
- {
- if (this.design_isTGItem)
- return;
- base.getIML (doc, parentElem);
- if (child == null || !design_inlineTemplate)
- return;
- XmlElement xe = doc.CreateElement("Template");
- child.getIML (doc, xe);
- parentElem.LastChild.AppendChild (xe);
- }
- #endif
-
- #region CTOR
- protected TemplatedControl() : base(){}
- public TemplatedControl (Interface iface) : base(iface){}
- #endregion
-
- string _template;
- string caption;
-
- /// <summary>
- /// Template path
- /// </summary>
- //TODO: this property should be renamed 'TemplatePath'
- [DefaultValue(null)]
- public string Template {
- get { return _template; }
- set {
- if (_template == value)
- return;
- _template = value;
-
- if (string.IsNullOrEmpty(_template))
- loadTemplate ();
- else
- loadTemplate (IFace.CreateTemplateInstance (_template, this.GetType()));
- }
- }
- /// <summary>
- /// a caption being recurrent need in templated widget, it is declared here.
- /// </summary>
- [DefaultValue("Templated Control")]
- public virtual string Caption {
- get { return caption; }
- set {
- if (caption == value)
- return;
- caption = value;
- NotifyValueChanged ("Caption", caption);
- }
- }
-
- #region GraphicObject overrides
-
- public override void Initialize ()
- {
- loadTemplate ();
- base.Initialize ();
- }
- /// <summary>
- /// override search method from GraphicObject to prevent
- /// searching inside template
- /// </summary>
- /// <returns>widget identified by name, or null if not found</returns>
- /// <param name="nameToFind">widget's name to find</param>
- public override Widget FindByName (string nameToFind) => nameToFind == this.Name ? this : null;
-
- /// <summary>
- ///onDraw is overrided to prevent default drawing of background, template top container
- ///may have a binding to root background or a fixed one.
- ///this allow applying root background to random template's component
- /// </summary>
- /// <param name="gr">Backend context</param>
- protected override void onDraw (Context gr)
- {
- gr.Save ();
-
- if (ClipToClientRect) {
- //clip to client zone
- CairoHelpers.CairoRectangle (gr, ClientRectangle, CornerRadius);
- gr.Clip ();
- }
-
- if (child != null)
- child.Paint (ref gr);
- gr.Restore ();
- }
- #endregion
-
- /// <summary>
- /// Loads the template. Each TemplatedControl MUST provide a default template
- /// It must be an embedded ressource with ID = fullTypeName.template
- /// Entry assembly is search first, then the one where the type is defined
- /// </summary>
- /// <param name="template">Optional template instance</param>
- protected virtual void loadTemplate(Widget template = null)
- {
- if (this.child != null)//template change, bindings has to be reset
- this.ClearTemplateBinding();
-
- if (template == null) {
- int mdTok = this.GetType ().MetadataToken;
-
- if (!IFace.DefaultTemplates.ContainsKey (mdTok)) {
- string defTmpId = this.GetType ().FullName + ".template";
- Stream s = Assembly.GetEntryAssembly ().GetManifestResourceStream (defTmpId);
- if (s == null)
- s = Assembly.GetAssembly (this.GetType ()).GetManifestResourceStream (defTmpId);
- if (s == null)
- throw new Exception (string.Format ("No default template found for '{0}'", this.GetType ().FullName));
- IFace.DefaultTemplates [mdTok] = new IML.Instantiator (IFace, s, defTmpId);
- }
- this.SetChild (IFace.DefaultTemplates[mdTok].CreateInstance());
- }else
- this.SetChild (template);
- }
- }
-}
-
+++ /dev/null
-//
-// TemplatedGroup.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;
-using System.Collections.Generic;
-using System.ComponentModel;
-using System.Linq;
-using System.Threading;
-using Crow.IML;
-
-namespace Crow {
- public abstract class TemplatedGroup : TemplatedControl
- {
- #if DESIGN_MODE
- public override void getIML (System.Xml.XmlDocument doc, System.Xml.XmlNode parentElem)
- {
- if (this.design_isTGItem)
- return;
- base.getIML (doc, parentElem);
-
- if (string.IsNullOrEmpty(_itemTemplate)) {
- foreach (ItemTemplate it in ItemTemplates.Values)
- it.getIML (doc, parentElem.LastChild);
- }
-
- foreach (Widget g in Items) {
- g.getIML (doc, parentElem.LastChild);
- }
- }
- #endif
-
- #region CTOR
- protected TemplatedGroup() : base(){}
- public TemplatedGroup (Interface iface) : base(iface){}
- #endregion
-
- protected Group items;
- string _itemTemplate, dataTest;
-
- #region events
- public event EventHandler<SelectionChangeEventArgs> SelectedItemChanged;
- public event EventHandler Loaded;
- #endregion
-
- IEnumerable data;
- int _selectedIndex = -1;
- Color selBackground, selForeground;
-
- int itemPerPage = 50;
- CrowThread loadingThread = null;
-
- bool isPaged = false;
-
- #region Templating
- //TODO: dont instantiate ItemTemplates if not used
- //but then i should test if null in msil gen
- public Dictionary<string, ItemTemplate> ItemTemplates = new Dictionary<string, ItemTemplate>();
-
- /// <summary>
- /// Keep track of expanded subnodes and closed time to unload
- /// </summary>
- //Dictionary<GraphicObject, Stopwatch> nodes = new Dictionary<GraphicObject, Stopwatch>();
- internal List<Widget> nodes = new List<Widget>();
- /// <summary>
- /// Item templates file path, on disk or embedded.
- ///
- /// ItemTemplate file may contains either a single template without the
- /// ItemTemplate enclosing tag, or several item templates each enclosed
- /// in a separate tag.
- /// </summary>
- public string ItemTemplate {
- get { return _itemTemplate; }
- set {
- if (value == _itemTemplate)
- return;
-
- _itemTemplate = value;
-
- //TODO:reload list with new template?
- NotifyValueChanged("ItemTemplate", _itemTemplate);
- }
- }
- protected override void loadTemplate(Widget template = null)
- {
- base.loadTemplate (template);
-
- items = this.child.FindByName ("ItemsContainer") as Group;
- if (items == null)
- throw new Exception ("TemplatedGroup template Must contain a Group named 'ItemsContainer'");
- if (items.Children.Count == 0)
- NotifyValueChanged ("HasChildren", false);
- else
- NotifyValueChanged ("HasChildren", true);
- }
- /// <summary>
- /// Use to define condition on Data item for selecting among ItemTemplates.
- /// Default value is 'TypeOf' for selecting Template depending on Type of Data.
- /// Other possible values are properties of Data
- /// </summary>
- /// <value>The data property test.</value>
- [DefaultValue("TypeOf")]
- public string DataTest {
- get { return dataTest; }
- set {
- if (value == dataTest)
- return;
-
- dataTest = value;
-
- NotifyValueChanged("DataTest", dataTest);
- }
- }
- #endregion
-
- public virtual List<Widget> Items{
- get {
- return isPaged ? items.Children.SelectMany(x => (x as Group).Children).ToList()
- : items.Children;
- }
- }
- [DefaultValue(-1)]public virtual int SelectedIndex{
- get { return _selectedIndex; }
- set {
- if (value == _selectedIndex)
- return;
-
- /*if (_selectedIndex >= 0 && Items.Count > _selectedIndex) {
- Items[_selectedIndex].Foreground = Color.Transparent;
- Items[_selectedIndex].Background = Color.Transparent;
- }*/
-
- _selectedIndex = value;
-
- /*if (_selectedIndex >= 0 && Items.Count > _selectedIndex) {
- Items[_selectedIndex].Foreground = SelectionForeground;
- Items[_selectedIndex].Background = SelectionBackground;
- }*/
-
- NotifyValueChanged ("SelectedIndex", _selectedIndex);
- NotifyValueChanged ("SelectedItem", SelectedItem);
- SelectedItemChanged.Raise (this, new SelectionChangeEventArgs (SelectedItem));
- }
- }
- [XmlIgnore]public virtual object SelectedItem{
- get { return data == null ? null : _selectedIndex < 0 ? data.GetDefaultValue() : ((IList)data)?[_selectedIndex]; }
- set {
- if (data == null) {
- SelectedIndex = -1;
- return;
- }
- //TODO:double check if value type will be notified to binding sys
- if (value == SelectedItem)
- return;
-
- SelectedIndex = (int)((IList)data)?.IndexOf (value);
- }
- }
- [XmlIgnore]public bool HasItems {
- get { return Items.Count > 0; }
- }
- public IEnumerable Data {
- get { return data; }
- set {
- if (value == data)
- return;
-
- cancelLoadingThread ();
-
- if (data is IObservableList) {
- IObservableList ol = data as IObservableList;
- ol.ListAdd -= Ol_ListAdd;
- ol.ListRemove -= Ol_ListRemove;
- }
-
- data = value;
-
- if (data is IObservableList) {
- IObservableList ol = data as IObservableList;
- ol.ListAdd += Ol_ListAdd;
- ol.ListRemove += Ol_ListRemove;
- }
-
- NotifyValueChanged ("Data", data);
-
- lock (IFace.UpdateMutex)
- ClearItems ();
-
- if (data == null)
- return;
-
- loadingThread = new CrowThread (this, loading);
- loadingThread.Finished += (object sender, EventArgs e) => (sender as TemplatedGroup).Loaded.Raise (sender, e);
- loadingThread.Start ();
-
- NotifyValueChanged ("SelectedIndex", _selectedIndex);
- NotifyValueChanged ("SelectedItem", SelectedItem);
- SelectedItemChanged.Raise (this, new SelectionChangeEventArgs (SelectedItem));
- NotifyValueChanged ("HasItems", HasItems);
- }
- }
-
- void Ol_ListRemove (object sender, ListChangedEventArg e)
- {
- if (this.isPaged) {
- int p = e.Index / itemPerPage;
- int i = e.Index % itemPerPage;
- (items.Children [p] as Group).DeleteChild (i);
- } else
- items.DeleteChild (e.Index);
- }
-
- void Ol_ListAdd (object sender, ListChangedEventArg e)
- {
- if (this.isPaged) {
- throw new NotImplementedException();
-// int p = e.Index / itemPerPage;
-// int i = e.Index % itemPerPage;
-// (items.Children [p] as Group).InsertChild (i, e.Element);
- } else
- loadItem (e.Element, items, dataTest);
- }
-
- [DefaultValue("SteelBlue")]
- public virtual Color SelectionBackground {
- get { return selBackground; }
- set {
- if (value == selBackground)
- return;
- selBackground = value;
- NotifyValueChanged ("SelectionBackground", selBackground);
- RegisterForRedraw ();
- }
- }
- [DefaultValue("White")]
- public virtual Color SelectionForeground {
- get { return selForeground; }
- set {
- if (value == selForeground)
- return;
- selForeground = value;
- NotifyValueChanged ("SelectionForeground", selForeground);
- RegisterForRedraw ();
- }
- }
-
- protected void raiseSelectedItemChanged(){
- SelectedItemChanged.Raise (this, new SelectionChangeEventArgs (SelectedItem));
- }
-
-
- public virtual void AddItem(Widget g){
- items.AddChild (g);
- g.LogicalParent = this;
- NotifyValueChanged ("HasChildren", true);
- }
- public virtual void RemoveItem(Widget g)
- {
- g.LogicalParent = null;
- items.DeleteChild (g);
- if (items.Children.Count == 0)
- NotifyValueChanged ("HasChildren", false);
- }
-
- public virtual void ClearItems()
- {
- _selectedIndex = -1;
- NotifyValueChanged ("SelectedIndex", _selectedIndex);
- NotifyValueChanged ("SelectedItem", null);
-
- items.ClearChildren ();
- NotifyValueChanged ("HasChildren", false);
- }
-
-
- #region GraphicObject overrides
- public override Widget FindByName (string nameToFind)
- {
- if (Name == nameToFind)
- return this;
-
- foreach (Widget w in Items) {
- Widget r = w.FindByName (nameToFind);
- if (r != null)
- return r;
- }
- return null;
- }
- public override bool Contains (Widget goToFind)
- {
- foreach (Widget w in Items) {
- if (w == goToFind)
- return true;
- if (w.Contains (goToFind))
- return true;
- }
- return base.Contains(goToFind);
- }
-// public override void ClearBinding ()
-// {
-// if (items != null)
-// items.ClearBinding ();
-//
-// base.ClearBinding ();
-// }
-// public override void ResolveBindings ()
-// {
-// base.ResolveBindings ();
-// if (items != null)
-// items.ResolveBindings ();
-// }
- #endregion
-
- /// <summary>
- /// Items loading thread
- /// </summary>
- void loading(){
- try {
- loadPage (data, items, dataTest);
- } catch {
- if (Monitor.IsEntered (IFace.LayoutMutex))
- Monitor.Exit (IFace.LayoutMutex);
- Console.WriteLine ("loading thread aborted");
- }
-
- }
-// //if (!ItemTemplates.ContainsKey ("default"))
-// // ItemTemplates ["default"] = Interface.GetItemTemplate (ItemTemplate);
-//
-// for (int i = 1; i <= (data.Count / itemPerPage) + 1; i++) {
-// if ((bool)loadingThread?.cancelRequested) {
-// this.Dispose ();
-// return;
-// }
-// loadPage (i);
-// Thread.Sleep (1);
-// }
-// }
- void cancelLoadingThread(){
- if (loadingThread != null)
- loadingThread.Cancel ();
- }
- void loadPage(IEnumerable _data, Group page, string _dataTest)
- {
- #if DEBUG_LOAD
- Stopwatch loadingTime = Stopwatch.StartNew ();
- #endif
-
-
-// if (typeof(TabView).IsAssignableFrom (items.GetType ())||
-// typeof(Menu).IsAssignableFrom (this.GetType())||
-// typeof(Wrapper).IsAssignableFrom (items.GetType ())) {
- //page = items;
- itemPerPage = int.MaxValue;
- // } else if (typeof(GenericStack).IsAssignableFrom (items.GetType ())) {
- // GenericStack gs = new GenericStack (items.CurrentInterface);
- // gs.Orientation = (items as GenericStack).Orientation;
- // gs.Width = items.Width;
- // gs.Height = items.Height;
- // gs.VerticalAlignment = items.VerticalAlignment;
- // gs.HorizontalAlignment = items.HorizontalAlignment;
- // page = gs;
- // page.Name = "page" + pageNum;
- // isPaged = true;
- // } else {
- // page = Activator.CreateInstance (items.GetType ()) as Group;
- // page.CurrentInterface = items.CurrentInterface;
- // page.Initialize ();
- // page.Name = "page" + pageNum;
- // isPaged = true;
- // }
-
- if (_data == null)
- return;
-
- foreach (object d in _data) {
- loadItem (d, page, _dataTest);
- if (loadingThread.cancelRequested)
- break;
- }
-
-// if (page == items)
-// return;
-// lock (CurrentInterface.LayoutMutex)
-// items.AddChild (page);
-
-#if DEBUG_LOAD
- loadingTime.Stop ();
- using (StreamWriter sw = new StreamWriter ("loading.log", true)) {
- sw.WriteLine ($"NEW ;{this.ToString(),-50};{loadingTime.ElapsedTicks,8};{loadingTime.ElapsedMilliseconds,8}");
- }
-#endif
- }
-
- protected void loadItem(object o, Group page, string _dataTest){
- if (o == null)//TODO:surely a threading sync problem
- return;
- Widget g = null;
- ItemTemplate iTemp = null;
- Type dataType = o.GetType ();
- string itempKey = dataType.FullName;
-
- //if item template selection is not done depending on the type of item
- //dataTest must contains a member name of the item
- if (_dataTest != "TypeOf") {
- try {
- itempKey = CompilerServices.getValue (dataType, o, _dataTest)?.ToString ();
- } catch {
- itempKey = dataType.FullName;
- }
- }
-
- if (ItemTemplates.ContainsKey (itempKey))
- iTemp = ItemTemplates [itempKey];
- else {
- foreach (string it in ItemTemplates.Keys) {
- if (it == "default")
- continue;
- Type t = CompilerServices.getTypeFromName (it);
- if (t == null)
- continue;
- if (t.IsAssignableFrom (dataType)) {//TODO:types could be cached
- iTemp = ItemTemplates [it];
- break;
- }
- }
- if (iTemp == null)
- iTemp = ItemTemplates ["default"];
- }
-
- Monitor.Enter (IFace.LayoutMutex);
- g = iTemp.CreateInstance();
- #if DESIGN_MODE
- g.design_isTGItem = true;
- #endif
- page.AddChild (g);
-// if (isPaged)
- g.LogicalParent = this;
- g.MouseClick += itemClick;
- Monitor.Exit (IFace.LayoutMutex);
-
- if (iTemp.Expand != null && g is Expandable) {
- Expandable e = g as Expandable;
- e.Expand += iTemp.Expand;
- if ((o as ICollection) == null)
- e.GetIsExpandable = new BooleanTestOnInstance((instance) => true);
- else
- e.GetIsExpandable = iTemp.HasSubItems;
- }
-
- g.DataSource = o;
- }
-
-
- // protected void _list_LayoutChanged (object sender, LayoutingEventArgs e)
- // {
- // #if DEBUG_LAYOUTING
- // Debug.WriteLine("list_LayoutChanged");
- // #endif
- // if (_gsList.Orientation == Orientation.Horizontal) {
- // if (e.LayoutType == LayoutingType.Width)
- // _gsList.Width = approxSize;
- // } else if (e.LayoutType == LayoutingType.Height)
- // _gsList.Height = approxSize;
- // }
- int approxSize
- {
- get {
- if (data == null)
- return -1;
- GenericStack page1 = items.FindByName ("page1") as GenericStack;
- if (page1 == null)
- return -1;
-
- return page1.Orientation == Orientation.Horizontal ?
- (data as ICollection)?.Count < itemPerPage ?
- -1:
- (int)Math.Ceiling ((double)page1.Slot.Width / (double)itemPerPage * (double)((data as ICollection)?.Count+1)):
- (data as ICollection)?.Count < itemPerPage ?
- -1:
- (int)Math.Ceiling ((double)page1.Slot.Height / (double)itemPerPage * (double)((data as ICollection)?.Count+1));
- }
- }
- internal virtual void itemClick(object sender, MouseButtonEventArgs e){
- SelectedIndex = (int)((IList)data)?.IndexOf((sender as Widget).DataSource);
- }
-
- bool emitHelperIsAlreadyExpanded (Widget go){
- if (nodes.Contains (go))
- return true;
- nodes.Add (go);
- return false;
- }
-
- protected override void Dispose (bool disposing)
- {
- if (disposing && loadingThread != null)
- loadingThread.Cancel ();
- base.Dispose (disposing);
- }
-
- public override void OnDataSourceChanged (object sender, DataSourceChangeEventArgs e)
- {
- base.OnDataSourceChanged (sender, e);
- }
- }
-}
+++ /dev/null
-//
-// TestCairoPatch.cs
-//
-// Author:
-// jp <>
-//
-// 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 Crow.Cairo;
-
-namespace Crow
-{
- public class TestCairoPatch : Widget
- {
- void computeControlPoints (
- double xc, double yc,
- double x1, double y1,
- out double x2, out double y2,
- out double x3, out double y3,
- double x4, double y4){
- double ax = x1 - xc;
- double ay = y1 - yc;
- double bx = x4 - xc;
- double byy = y4 - yc;
- double q1 = ax * ax + ay * ay;
- double q2 = q1 + ax * bx + ay * byy;
- double k2 = 4.0/3.0 * (Math.Sqrt(2.0 * q1 * q2) - q2) / (ax * byy - ay * bx);
-
-
- x2 = xc + ax - k2 * ay;
- y2 = yc + ay + k2 * ax;
- x3 = xc + bx + k2 * byy;
- y3 = yc + byy - k2 * bx;
- }
- protected override void onDraw (Context gr)
- {
- base.onDraw (gr);
-
- double radius = Math.Min (ClientRectangle.Width, ClientRectangle.Height) / 2;
-
- double pi3 = Math.PI / 3.0;
-
- MeshPattern mp = new MeshPattern ();
-
- double x1 = radius,y1 = 0,
- x2 = 0, y2 = 0, x3 = 0, y3 = 0, x4 = 0, y4 = 0,
- xc = radius,yc = radius;
-
- double dx = Math.Sin (pi3) * radius;
- double dy = Math.Cos (pi3) * radius;
-
- mp.BeginPatch ();
- mp.MoveTo (xc, yc);
- mp.LineTo (x1, y1);
- x4 = xc + dx;
- y4 = yc - dy;
- computeControlPoints (xc, yc, x1, y1, out x2, out y2, out x3, out y3, x4, y4);
- mp.CurveTo (x2, y2, x3, y3, x4, y4);
-
- mp.SetCornerColorRGB (0, 1, 1, 1);
- mp.SetCornerColorRGB (1, 1, 0, 0);
- mp.SetCornerColorRGB (2, 1, 1, 0);
-
- x1 = x4;
- y1 = y4;
- y4 = yc + dy;
-
- computeControlPoints (xc, yc, x1, y1, out x2, out y2, out x3, out y3, x4, y4);
- mp.CurveTo (x2, y2, x3, y3, x4, y4);
-
- mp.SetCornerColorRGB (3, 0, 1, 0);
- mp.EndPatch ();
-
- x1 = x4;
- y1 = y4;
- x4 = xc;
- y4 = yc * 2.0;
-
- mp.BeginPatch ();
- mp.MoveTo (xc, yc);
- mp.LineTo (x1, y1);
- computeControlPoints (xc, yc, x1, y1, out x2, out y2, out x3, out y3, x4, y4);
- mp.CurveTo (x2, y2, x3, y3, x4, y4);
-
- mp.SetCornerColorRGB (0, 1, 1, 1);
- mp.SetCornerColorRGB (1, 0, 1, 0);
- mp.SetCornerColorRGB (2, 0, 1, 1);
-
- x1 = x4;
- y1 = y4;
- x4 = xc-dx;
- y4 = yc+dy;
-
- computeControlPoints (xc, yc, x1, y1, out x2, out y2, out x3, out y3, x4, y4);
- mp.CurveTo (x2, y2, x3, y3, x4, y4);
-
- mp.SetCornerColorRGB (3, 0, 0, 1);
- mp.EndPatch ();
-
- x1 = x4;
- y1 = y4;
- y4 = yc - dy;
-
- mp.BeginPatch ();
- mp.MoveTo (xc, yc);
- mp.LineTo (x1, y1);
- computeControlPoints (xc, yc, x1, y1, out x2, out y2, out x3, out y3, x4, y4);
- mp.CurveTo (x2, y2, x3, y3, x4, y4);
-
- mp.SetCornerColorRGB (0, 1, 1, 1);
- mp.SetCornerColorRGB (1, 0, 0, 1);
- mp.SetCornerColorRGB (2, 1, 0, 1);
-
- x1 = x4;
- y1 = y4;
- x4 = radius;
- y4 = 0;
-
- computeControlPoints (xc, yc, x1, y1, out x2, out y2, out x3, out y3, x4, y4);
- mp.CurveTo (x2, y2, x3, y3, x4, y4);
-
- mp.SetCornerColorRGB (3, 1, 0, 0);
- mp.EndPatch ();
-
- gr.SetSource (mp);
- gr.Paint ();
- }
- }
-}
-
+++ /dev/null
-//
-// TextBox.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 Crow.Cairo;
-using System.Diagnostics;
-using System.Xml.Serialization;
-
-namespace Crow
-{
- public class TextBox : Label
- {
- #region CTOR
- protected TextBox() : base(){}
- public TextBox(Interface iface) : base(iface)
- { }
-// public TextBox(string _initialValue)
-// : base(_initialValue)
-// {
-//
-// }
- #endregion
-
- #region GraphicObject overrides
- [XmlIgnore]public override bool HasFocus //trigger update when lost focus to errase text beam
- {
- get
- {
- return base.HasFocus;
- }
- set
- {
- base.HasFocus = value;
- RegisterForRedraw();
- }
- }
-
- protected override void onDraw (Context gr)
- {
- base.onDraw (gr);
- FontExtents fe = gr.FontExtents;
- }
- #endregion
-
- #region Keyboard handling
- public override void onKeyDown (object sender, KeyEventArgs e)
- {
- base.onKeyDown (sender, e);
-
- Key key = e.Key;
-
- switch (key)
- {
- case Key.BackSpace:
- if (CurrentPosition == 0)
- return;
- this.DeleteChar();
- break;
- case Key.Clear:
- break;
- case Key.Delete:
- if (selectionIsEmpty) {
- if (!MoveRight ())
- return;
- }else if (IFace.Shift)
- IFace.Clipboard = this.SelectedText;
- this.DeleteChar ();
- break;
- case Key.KP_Enter:
- case Key.Return:
- if (!selectionIsEmpty)
- this.DeleteChar ();
- if (Multiline)
- this.InsertLineBreak ();
- else
- OnTextChanged(this,new TextChangeEventArgs(Text));
- break;
- case Key.Escape:
- Text = "";
- CurrentColumn = 0;
- SelRelease = -1;
- break;
- case Key.Home:
- if (IFace.Shift) {
- if (selectionIsEmpty)
- SelBegin = new Point (CurrentColumn, CurrentLine);
- if (IFace.Ctrl)
- CurrentLine = 0;
- CurrentColumn = 0;
- SelRelease = new Point (CurrentColumn, CurrentLine);
- break;
- }
- SelRelease = -1;
- if (IFace.Ctrl)
- CurrentLine = 0;
- CurrentColumn = 0;
- break;
- case Key.End:
- if (IFace.Shift) {
- if (selectionIsEmpty)
- SelBegin = CurrentPosition;
- if (IFace.Ctrl)
- CurrentLine = int.MaxValue;
- CurrentColumn = int.MaxValue;
- SelRelease = CurrentPosition;
- break;
- }
- SelRelease = -1;
- if (IFace.Ctrl)
- CurrentLine = int.MaxValue;
- CurrentColumn = int.MaxValue;
- break;
- case Key.Insert:
- if (IFace.Shift)
- this.Insert (IFace.Clipboard);
- else if (IFace.Ctrl && !selectionIsEmpty)
- IFace.Clipboard = this.SelectedText;
- break;
- case Key.Left:
- if (IFace.Shift) {
- if (selectionIsEmpty)
- SelBegin = new Point(CurrentColumn, CurrentLine);
- if (IFace.Ctrl)
- GotoWordStart ();
- else if (!MoveLeft ())
- return;
- SelRelease = CurrentPosition;
- break;
- }
- SelRelease = -1;
- if (IFace.Ctrl)
- GotoWordStart ();
- else
- MoveLeft();
- break;
- case Key.Right:
- if (IFace.Shift) {
- if (selectionIsEmpty)
- SelBegin = CurrentPosition;
- if (IFace.Ctrl)
- GotoWordEnd ();
- else if (!MoveRight ())
- return;
- SelRelease = CurrentPosition;
- break;
- }
- SelRelease = -1;
- if (IFace.Ctrl)
- GotoWordEnd ();
- else
- MoveRight ();
- break;
- case Key.Up:
- if (IFace.Shift) {
- if (selectionIsEmpty)
- SelBegin = CurrentPosition;
- CurrentLine--;
- SelRelease = CurrentPosition;
- break;
- }
- SelRelease = -1;
- CurrentLine--;
- break;
- case Key.Down:
- if (IFace.Shift) {
- if (selectionIsEmpty)
- SelBegin = CurrentPosition;
- CurrentLine++;
- SelRelease = CurrentPosition;
- break;
- }
- SelRelease = -1;
- CurrentLine++;
- break;
- case Key.Menu:
- break;
- case Key.Num_Lock:
- break;
- case Key.Page_Down:
- break;
- case Key.Page_Up:
- break;
- case Key.Tab:
- this.Insert ("\t");
- break;
- default:
- break;
- }
-
- RegisterForGraphicUpdate();
- }
- public override void onKeyPress (object sender, KeyPressEventArgs e)
- {
- base.onKeyPress (sender, e);
-
- this.Insert (e.KeyChar.ToString());
-
- SelRelease = -1;
- SelBegin = new Point(CurrentColumn, SelBegin.Y);
-
- RegisterForGraphicUpdate();
- }
- #endregion
- }
-}
+++ /dev/null
-//
-// TextRun.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.Linq;
-using System.Text;
-using System.Diagnostics;
-using Crow.Cairo;
-using System.Text.RegularExpressions;
-using System.Xml.Serialization;
-using System.ComponentModel;
-
-namespace Crow
-{
- [DesignIgnore]
- public class TextRun : Widget
- {
- #region CTOR
- protected TextRun () : base(){}
- public TextRun (Interface iface) : base (iface){}
- #endregion
-
- //TODO:change protected to private
-
- #region private and protected fields
- protected string _text = "label";
- Alignment _textAlignment = Alignment.Left;
- bool horizontalStretch = false;
- bool verticalStretch = false;
- bool _multiline;
- bool wordWrap;
- protected Rectangle rText;
- protected float widthRatio = 1f;
- protected float heightRatio = 1f;
- protected FontExtents fe;
- protected TextExtents te;
- #endregion
-
-
-
- [DefaultValue (Alignment.Left)]
- public Alignment TextAlignment {
- get { return _textAlignment; }
- set { _textAlignment = value; }
- }
-
- [DefaultValue (false)]
- public virtual bool HorizontalStretch {
- get { return horizontalStretch; }
- set {
- if (horizontalStretch == value)
- return;
- horizontalStretch = value;
- RegisterForRedraw ();
- NotifyValueChanged ("HorizontalStretch", horizontalStretch);
- }
- }
-
- [DefaultValue (false)]
- public virtual bool VerticalStretch {
- get { return verticalStretch; }
- set {
- if (verticalStretch == value)
- return;
- verticalStretch = value;
- RegisterForRedraw ();
- NotifyValueChanged ("VerticalStretch", verticalStretch);
- }
- }
-
- [DefaultValue ("label")]
- public string Text {
- get {
- return lines == null ?
- _text : lines.Aggregate ((i, j) => i + Interface.LineBreak + j);
- }
- set {
- if (_text == value)
- return;
-
- RegisterForGraphicUpdate ();
-
- _text = value;
-
- if (string.IsNullOrEmpty (_text))
- _text = "";
-
- lines = getLines;
- }
- }
-
- [DefaultValue (false)]
- public bool Multiline {
- get { return _multiline; }
- set {
- _multiline = value;
- RegisterForGraphicUpdate ();
- }
- }
-
- [DefaultValue (false)]
- public bool WordWrap {
- get {
- return wordWrap;
- }
- set {
- if (wordWrap == value)
- return;
- wordWrap = value;
- RegisterForGraphicUpdate ();
- }
- }
-
- List<string> lines;
- List<string> getLines {
- get {
- return _multiline ?
- Regex.Split (_text, "\r\n|\r|\n").ToList () :
- new List<string> (new string [] { _text });
- }
- }
-
- #region GraphicObject overrides
- protected override int measureRawSize (LayoutingType lt)
- {
- if (lines == null)
- lines = getLines;
-
- using (Context gr = new Context (IFace.surf)) {
- //Cairo.FontFace cf = gr.GetContextFontFace ();
-
- gr.SelectFontFace (Font.Name, Font.Slant, Font.Wheight);
- gr.SetFontSize (Font.Size);
-
-
- fe = gr.FontExtents;
- te = new TextExtents ();
-
- if (lt == LayoutingType.Height) {
- int lc = lines.Count;
- //ensure minimal height = text line height
- if (lc == 0)
- lc = 1;
-
- return (int)(fe.Height * lc) + Margin * 2;
- }
-
- foreach (string s in lines) {
- string l = s.Replace("\t", new String (' ', Interface.TAB_SIZE));
- TextExtents tmp = gr.TextExtents (l);
- if (tmp.XAdvance > te.XAdvance)
- te = tmp;
- }
- return (int)Math.Ceiling (te.XAdvance) + Margin * 2;
- }
- }
- protected override void onDraw (Context gr)
- {
- base.onDraw (gr);
-
- gr.SelectFontFace (Font.Name, Font.Slant, Font.Wheight);
- gr.SetFontSize (Font.Size);
- gr.FontOptions = Interface.FontRenderingOptions;
- gr.Antialias = Interface.Antialias;
-
- rText = new Rectangle (new Size (
- measureRawSize (LayoutingType.Width), measureRawSize (LayoutingType.Height)));
- rText.Width -= 2 * Margin;
- rText.Height -= 2 * Margin;
-
- widthRatio = 1f;
- heightRatio = 1f;
-
- Rectangle cb = ClientRectangle;
-
- //ignore text alignment if size to content = true
- //or if text size is larger than client bounds
- if (Width < 0 || Height < 0 || rText.Width > cb.Width) {
- rText.X = cb.X;
- rText.Y = cb.Y;
- } else {
- if (horizontalStretch) {
- widthRatio = (float)cb.Width / rText.Width;
- if (!verticalStretch)
- heightRatio = widthRatio;
- }
- if (verticalStretch) {
- heightRatio = (float)cb.Height / rText.Height;
- if (!horizontalStretch)
- widthRatio = heightRatio;
- }
-
- rText.Width = (int)(widthRatio * cb.Width);
- rText.Height = (int)(heightRatio * cb.Height);
-
- switch (TextAlignment) {
- case Alignment.TopLeft: //ok
- rText.X = cb.X;
- rText.Y = cb.Y;
- break;
- case Alignment.Top: //ok
- rText.Y = cb.Y;
- rText.X = cb.X + cb.Width / 2 - rText.Width / 2;
- break;
- case Alignment.TopRight: //ok
- rText.Y = cb.Y;
- rText.X = cb.Right - rText.Width;
- break;
- case Alignment.Left://ok
- rText.X = cb.X;
- rText.Y = cb.Y + cb.Height / 2 - rText.Height / 2;
- break;
- case Alignment.Right://ok
- rText.X = cb.X + cb.Width - rText.Width;
- rText.Y = cb.Y + cb.Height / 2 - rText.Height / 2;
- break;
- case Alignment.Bottom://ok
- rText.X = cb.Width / 2 - rText.Width / 2;
- rText.Y = cb.Height - rText.Height;
- break;
- case Alignment.BottomLeft://ok
- rText.X = cb.X;
- rText.Y = cb.Bottom - rText.Height;
- break;
- case Alignment.BottomRight://ok
- rText.Y = cb.Bottom - rText.Height;
- rText.X = cb.Right - rText.Width;
- break;
- case Alignment.Center://ok
- rText.X = cb.X + cb.Width / 2 - rText.Width / 2;
- rText.Y = cb.Y + cb.Height / 2 - rText.Height / 2;
- break;
- }
- }
-
- gr.FontMatrix = new Matrix (widthRatio * Font.Size, 0, 0, heightRatio * Font.Size, 0, 0);
-
-
- int curLineCount = 0;
- for (int i = 0; i < lines.Count; i++) {
- string l = lines [i].Replace ("\t", new String (' ', Interface.TAB_SIZE));
- List<string> wl = new List<string> ();
- int lineLength = (int)gr.TextExtents (l).XAdvance;
-
- if (wordWrap && lineLength > cb.Width) {
- string tmpLine = "";
- int curChar = 0;
- while (curChar < l.Length) {
- tmpLine += l [curChar];
- if ((int)gr.TextExtents (tmpLine).XAdvance > cb.Width) {
- tmpLine = tmpLine.Remove (tmpLine.Length - 1);
- wl.Add (tmpLine);
- tmpLine = "";
- continue;
- }
- curChar++;
- }
- wl.Add (tmpLine);
- } else
- wl.Add (l);
-
- foreach (string ll in wl) {
- lineLength = (int)gr.TextExtents (ll).XAdvance;
-
-
- if (string.IsNullOrWhiteSpace (ll)) {
- curLineCount++;
- continue;
- }
-
- Foreground.SetAsSource (gr);
- gr.MoveTo (rText.X, rText.Y + fe.Ascent + fe.Height * curLineCount);
-
- gr.ShowText (ll);
- gr.Fill ();
-
- curLineCount++;
- }
- }
- }
- #endregion
- }
-}
+++ /dev/null
-//
-// TreeView.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.Xml.Serialization;
-using System.Diagnostics;
-using System.ComponentModel;
-
-namespace Crow
-{
- //treeview expect expandable child (or not)
- //if their are expandable, some functions and events are added
- public class TreeView : TemplatedGroup
- {
- Widget selectedItemContainer = null;
- bool isRoot;
-
- #region CTOR
- protected TreeView() : base(){}
- public TreeView (Interface iface) : base(iface)
- {
- }
- #endregion
-
- [DefaultValue(false)]
- public virtual bool IsRoot {
- get { return isRoot; }
- set {
- if (isRoot == value)
- return;
- isRoot = value;
- NotifyValueChanged ("IsRoot", isRoot);
- }
- }
- [XmlIgnore]public override object SelectedItem {
- get {
- return selectedItemContainer == null ?
- "" : selectedItemContainer.DataSource;
- }
- }
-
- internal override void itemClick (object sender, MouseButtonEventArgs e)
- {
- Widget tmp = sender as Widget;
- //if (!tmp.HasFocus)
- // return;
- /*if (selectedItemContainer != null) {
- selectedItemContainer.Foreground = Color.Transparent;
- selectedItemContainer.Background = Color.Transparent;
- }*/
- selectedItemContainer = tmp;
- //selectedItemContainer.Foreground = SelectionForeground;
- //selectedItemContainer.Background = SelectionBackground;
- NotifyValueChanged ("SelectedItem", SelectedItem);
- raiseSelectedItemChanged ();
- }
-
- void onExpandAll_MouseClick (object sender, MouseButtonEventArgs e)
- {
- ExpandAll ();
- }
-
- public void ExpandAll(){
- foreach (Group grp in items.Children) {
- foreach (Widget go in grp.Children) {
- Expandable exp = go as Expandable;
- if (exp == null)
- continue;
- TreeView subTV = exp.FindByName ("List") as TreeView;
- if (subTV == null)
- continue;
- EventHandler handler = null;
- handler = delegate(object sender, EventArgs e) {
- TreeView tv = sender as TreeView;
- tv.Loaded -= handler;
- tv.ExpandAll ();
- };
- subTV.Loaded += handler;
- exp.IsExpanded = true;
- }
- }
- }
- }
-}
-
+++ /dev/null
-//
-// Trend.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.Xml.Serialization;
-using System.ComponentModel;
-using Crow.Cairo;
-
-namespace Crow
-{
- public class Trend : Widget
- {
- #region private fields
- double minValue, maxValue, lowThreshold, highThreshold;
- Fill lowThresholdFill, highThresholdFill;
- int nbValues;
- List<double> values = new List<double>();
- #endregion
-
-
-
- public virtual void AddValue(double _value)
- {
- values.Add (_value);
- while (values.Count > nbValues)
- values.RemoveAt (0);
- RegisterForRedraw ();
- }
- #region CTOR
- protected Trend () : base()
- {
- }
- #endregion
- [XmlIgnore]public virtual int NewValue {
- set {
- AddValue (value);
- }
- }
- [DefaultValue(400)]
- public virtual int NbValues {
- get { return nbValues; }
- set {
- if (nbValues == value)
- return;
-
- nbValues = value;
- NotifyValueChanged ("NbValues", minValue);
- RegisterForRedraw ();
- }
- }
- [DefaultValue(0.0)]
- public virtual double Minimum {
- get { return minValue; }
- set {
- if (minValue == value)
- return;
-
- minValue = value;
- NotifyValueChanged ("Minimum", minValue);
- RegisterForRedraw ();
- }
- }
- [DefaultValue(100.0)]
- public virtual double Maximum
- {
- get { return maxValue; }
- set {
- if (maxValue == value)
- return;
-
- maxValue = value;
- NotifyValueChanged ("Maximum", maxValue);
- RegisterForRedraw ();
- }
- }
- [DefaultValue(1.0)]
- public virtual double LowThreshold {
- get { return lowThreshold; }
- set {
- if (lowThreshold == value)
- return;
- lowThreshold = value;
- NotifyValueChanged ("LowThreshold", lowThreshold);
- RegisterForGraphicUpdate ();
- }
- }
- [DefaultValue(80.0)]
- public virtual double HighThreshold {
- get { return highThreshold; }
- set {
- if (highThreshold == value)
- return;
- highThreshold = value;
- NotifyValueChanged ("HighThreshold", highThreshold);
- RegisterForGraphicUpdate ();
- }
- }
- [DefaultValue("DarkRed")]
- public virtual Fill LowThresholdFill {
- get { return lowThresholdFill; }
- set {
- if (lowThresholdFill == value)
- return;
- lowThresholdFill = value;
- NotifyValueChanged ("LowThresholdFill", lowThresholdFill);
- RegisterForRedraw ();
- }
- }
- [DefaultValue("DarkGreen")]
- public virtual Fill HighThresholdFill {
- get { return highThresholdFill; }
- set {
- if (highThresholdFill == value)
- return;
- highThresholdFill = value;
- NotifyValueChanged ("HighThresholdFill", highThresholdFill);
- RegisterForRedraw ();
- }
- }
- protected override void onDraw (Context gr)
- {
- base.onDraw (gr);
-
- if (values.Count == 0)
- return;
- Rectangle r = ClientRectangle;
-
- int i = values.Count -1;
-
- double ptrX = (double)r.Right;
- double scaleY = (double)r.Height / (Maximum - Minimum);
- double stepX = (double)r.Width / (double)(nbValues-1);
-
- gr.LineWidth = 1.0;
- gr.SetDash (new double[]{ 1.0 },0.0);
-
-
-
- LowThresholdFill.SetAsSource (gr);
- gr.MoveTo (r.Left, r.Bottom - LowThreshold * scaleY);
- gr.LineTo (r.Right, r.Bottom - LowThreshold * scaleY);
-// gr.Rectangle (r.Left, r.Bottom - LowThreshold * scaleY, r.Width, LowThreshold * scaleY);
- gr.Stroke();
-
- HighThresholdFill.SetAsSource (gr);
- gr.MoveTo (r.Left, (Maximum - HighThreshold) * scaleY);
- gr.LineTo (r.Right, (Maximum - HighThreshold) * scaleY);
-// gr.Rectangle (r.Left, r.Top, r.Width, (Maximum - HighThreshold) * scaleY);
- gr.Stroke();
-
- gr.MoveTo (ptrX, values [i] * scaleY);
-
- Foreground.SetAsSource (gr);
- gr.SetDash (new double[]{ }, 0.0);
-
- while (i >= 0) {
- gr.LineTo (ptrX, r.Bottom - values [i] * scaleY);
- ptrX -= stepX;
- i--;
- }
- gr.Stroke ();
- }
- }
-}
-
+++ /dev/null
-//
-// VerticalStack.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.Linq;
-using System.Text;
-
-namespace Crow
-{
- /// <summary>
- /// group control stacking its children vertically
- /// </summary>
- public class VerticalStack : GenericStack
- {
- #region CTOR
- protected VerticalStack() : base(){}
- public VerticalStack(Interface iface) : base(iface)
- {
- }
- #endregion
-
- [XmlIgnore]
- public override Orientation Orientation
- {
- get { return Orientation.Vertical; }
- }
-
-
- }
-}
+++ /dev/null
-//
-// 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 Crow.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 Widget : ILayoutable, IValueChange, IDisposable
- {
- internal ReaderWriterLockSlim parentRWLock = new ReaderWriterLockSlim();
- #if DEBUG_LOG
- //0 is the main graphic tree, for other obj tree not added to main tree, it range from 1->n
- //useful to track events for obj shown later, not on start, or never added to main tree
- public int treeIndex;
- public int yIndex;//absolute index in the graphic tree for debug draw
- public int xLevel;//x increment for debug draw
- #endif
- #if DESIGN_MODE
- static MethodInfo miDesignAddDefLoc = typeof(Widget).GetMethod("design_add_style_location",
- BindingFlags.Instance | BindingFlags.NonPublic);
- static MethodInfo miDesignAddValLoc = typeof(Widget).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 Widget 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;
- }
- public string DesignName {
- get { return GetType ().Name + design_id; }
- }
- #endif
-
- #region IDisposable implementation
- protected bool disposed = false;
-
- public void Dispose(){
- Dispose(true);
- GC.SuppressFinalize(this);
- }
- ~Widget(){
- Console.WriteLine(this.ToString() + " not disposed by user");
- Dispose(false);
- }
- protected virtual void Dispose(bool disposing){
- if (disposed){
- #if DEBUG_DISPOSE
- Console.WriteLine ("Trying to dispose already disposed obj: {0}", this.ToString());
- #endif
- return;
- }
-
- if (disposing) {
- #if DEBUG_DISPOSE
- Console.WriteLine ("Disposing: {0}", this.ToString());
- //if ()
- //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
-
- #if DEBUG_LOG
- internal static List<GraphicObject> GraphicObjects = new List<GraphicObject>();
- #endif
-
- //internal bool isPopup = false;
- //public Widget focusParent {
- // get { return (isPopup ? LogicalParent : parent) as Widget; }
- //}
-
- /// <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 Widget () {
- Clipping = new Region ();
- #if DEBUG_LOG
- GraphicObjects.Add (this);
- DebugLog.AddEvent(DbgEvtType.GOClassCreation, this);
- #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 Widget (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 ();
- }
- #region private fields
- LayoutingType registeredLayoutings = LayoutingType.All;
- ILayoutable logicalParent;
- ILayoutable parent;
- string name;
- Fill background = Color.Transparent;
- Fill foreground = Color.White;
- Font font = "sans, 10";
- protected Measure width, height;
- int left, top;
- double cornerRadius;
- int margin;
- bool focusable ;
- bool hasFocus;
- bool isActive;
- bool isHover;
- bool mouseRepeat;
- MouseCursor mouseCursor = MouseCursor.Arrow;
- 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;
- bool clipToClientRect = true;
- Type dataSourceType;
- 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);
- }
- }
- /// <summary>
- /// Mouse routing need to go back to logical parent for popups
- /// </summary>
- public Widget FocusParent => (parent is Interface ? LogicalParent : parent) as Widget;
-
- [XmlIgnore]public ILayoutable LogicalParent {
- get { return logicalParent == null ? Parent : logicalParent; }
- set {
- if (logicalParent == value)
- return;
- if (logicalParent is Widget)
- (logicalParent as Widget).DataSourceChanged -= onLogicalParentDataSourceChanged;
- DataSourceChangeEventArgs dsce = new DataSourceChangeEventArgs (LogicalParent, null);
- logicalParent = value;
- dsce.NewDataSource = LogicalParent;
- if (logicalParent is Widget)
- (logicalParent as Widget).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){
- Widget go = Parent as Widget;
- 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<KeyEventArgs> KeyDown;
- /// <summary>Occurs when key is released when this object is active</summary>
- public event EventHandler<KeyEventArgs> 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
-
- internal bool hasDoubleClick => MouseDoubleClick != null;
- internal bool hasClick => MouseClick != null;
-
- #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_LOG
- [XmlIgnore]public string TreePath {
- get { return this.GetType().Name + GraphicObjects.IndexOf(this).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_LOG
- return string.IsNullOrEmpty(name) ? this.GetType().Name + GraphicObjects.IndexOf(this).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 Widget ? (Parent as Widget).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 Widget ? (Parent as Widget).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)
- Hover.Raise (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);
- }
- }
- /// <summary>
- /// Determine Cursor when mouse is Hover.
- /// </summary>
- [DesignCategory ("Behaviour")]
- [DefaultValue (MouseCursor.Arrow)]
- public virtual MouseCursor MouseCursor {
- get { return mouseCursor; }
- set {
- if (mouseCursor == value)
- return;
- mouseCursor = value;
- NotifyValueChanged ("MouseCursor", mouseCursor);
- this.RegisterForRedraw ();
-
- if (isHover)
- IFace.MouseCursor = mouseCursor;
- }
- }
-
- /// <summary>
- /// forward mouse events even if an handle is bound
- /// </summary>
- //[DesignCategory ("Behaviour")][DefaultValue (false)]
- //public bool ForwardMouseEvents {
- // get { return forwardMouseEvents; }
- // set {
- // if (forwardMouseEvents == value)
- // return;
- // forwardMouseEvents = value;
- // NotifyValueChanged ("ForwardMouseEvents", forwardMouseEvents);
- // }
- //}
- 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 && IFace.HoverWidget != null) {
- if (IFace.HoverWidget.IsOrIsInside (this)) {
- //IFace.HoverWidget = null;
- IFace.OnMouseMove (IFace.Mouse.X, IFace.Mouse.Y);
- }
- }
-
- 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 (nameof(MaximumSize), maximumSize);
- RegisterForLayouting (LayoutingType.Sizing);
- }
- }
- /// <summary>
- /// Fully qualify type name of expected data source.
- /// If set, datasource bindings will be speedup by avoiding reflexion in generated dyn methods.
- /// If an object of a different type is set as datasource, bindings will be canceled.
- /// It accepts all derived type.
- /// </summary>
- [DesignCategory ("Data")]
- public Type DataSourceType {
- get { return dataSourceType; }
- set { dataSourceType = value; }
- }
- /// <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;
-
- #if DEBUG_LOG
- DbgEvent dbgEvt = DebugLog.AddEvent(DbgEvtType.GOLockLayouting, this);
- #endif
- lock (IFace.UpdateMutex) {
- OnDataSourceChanged (this, dse);
- NotifyValueChanged ("DataSource", DataSource);
- }
- #if DEBUG_LOG
- dbgEvt.end = DebugLog.chrono.ElapsedTicks;
- #endif
- }
- get {
- return rootDataLevel ? dataSource : dataSource == null ?
- LogicalParent == null ? null :
- LogicalParent is Widget ? (LogicalParent as Widget).DataSource : null :
- dataSource;
- }
- }
- /// <summary>
- /// If true, lock datasource seeking upward in logic or graphic tree to this widget
- /// </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_LOG
- DebugLog.AddEvent(DbgEvtType.GONewDataSource, this);
- #endif
-
- #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_LOG
- DbgEvent dbgEvt = DebugLog.AddEvent(DbgEvtType.GOInitialization, this);
- #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", null, new Type[] { typeof (object) }, thisType, true);
-
- il = dm.GetILGenerator(256);
- il.DeclareLocal(typeof (object));//store root
- 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.Ordinal)){
- 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.Call, 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;
-
- int styleIndex = -1;
- if (styling.Count > 0){
- for (int i = 0; i < styling.Count; i++) {
- if (styling[i].ContainsKey (pi.Name)){
- styleIndex = i;
- break;
- }
- }
- }
- if (styleIndex >= 0){
- if (pi.PropertyType.IsEnum)//maybe should be in parser..
- defaultValue = Enum.Parse(pi.PropertyType, (string)styling[styleIndex] [pi.Name], true);
- else
- defaultValue = styling[styleIndex] [pi.Name];
-
- #if DESIGN_MODE
- if (defaultValue != null){
- FileLocation fl = styling[styleIndex].Locations[pi.Name];
- il.Emit (OpCodes.Ldloc_0);
- il.Emit (OpCodes.Ldstr, pi.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(Widget).GetField("design_style_values"));
- il.Emit (OpCodes.Ldstr, pi.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);
- }
-
- #if DEBUG_LOG
- dbgEvt.end = DebugLog.chrono.ElapsedTicks;
- #endif
-
- 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 Widget FindByName(string nameToFind){
- return string.Equals(nameToFind, name, StringComparison.Ordinal) ? this : null;
- }
- public virtual bool Contains(Widget goToFind){
- return false;
- }
- /// <summary>
- /// return true if this is contained inside go
- /// </summary>
- public bool IsOrIsInside(Widget 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_LOG
- DbgEvent dbgEvt = DebugLog.AddEvent(DbgEvtType.GOClippingRegistration, this);
- #endif
- parentRWLock.EnterReadLock ();
- if (parent != null) {
- Parent.RegisterClip (LastPaintedSlot);
- Parent.RegisterClip (Slot);
- }
- parentRWLock.ExitReadLock ();
- #if DEBUG_LOG
- dbgEvt.end = DebugLog.chrono.ElapsedTicks;
- #endif
- }
- /// <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_LOG
- DbgEvent dbgEvt = DebugLog.AddEvent(DbgEvtType.GORegisterClip, this);
- #endif
- Rectangle cb = ClientRectangle;
- Rectangle r = clip + cb.Position;
- if (r.Right > cb.Right)
- r.Width -= r.Right - cb.Right;
- if (r.Bottom > cb.Bottom)
- r.Height -= r.Bottom - cb.Bottom;
- if (cacheEnabled && !IsDirty)
- Clipping.UnionRectangle (r);
- if (Parent == null)
- return;
- Widget p = Parent as Widget;
- if (p?.IsDirty == true && p?.CacheEnabled == true)
- return;
- Parent.RegisterClip (r + Slot.Position);
- #if DEBUG_LOG
- dbgEvt.end = DebugLog.chrono.ElapsedTicks;
- #endif
- }
- /// <summary> Full update, content and layouting, taking care of sizing policy </summary>
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public void RegisterForGraphicUpdate ()
- {
- 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 without layouting changes</summary>
- [MethodImpl(MethodImplOptions.AggressiveInlining)]
- public void RegisterForRedraw ()
- {
- 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 Widget)
- (Parent as Widget).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)
- {
- //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 (isVisible) {
- 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 (isVisible) {
- 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_LOG
- DbgEvent dbgEvt = DebugLog.AddEvent(DbgEvtType.GODraw, this);
- #endif
-
- Rectangle rBack = new Rectangle (Slot.Size);
-
- background.SetAsSource (gr, rBack);
- CairoHelpers.CairoRectangle (gr, rBack, cornerRadius);
- gr.Fill ();
-
- #if DEBUG_LOG
- dbgEvt.end = DebugLog.chrono.ElapsedTicks;
- #endif
- }
-
- /// <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_LOG
- DbgEvent dbgEvt = DebugLog.AddEvent(DbgEvtType.GORecreateCache, this);
- #endif
-
- /*if (bmp == null)
- bmp = IFace.surf.CreateSimilar (Content.ColorAlpha, Slot.Width, Slot.Height);
- else if (LastPaintedSlot.Width != Slot.Width || LastPaintedSlot.Height != Slot.Height)
- bmp.SetSize (Slot.Width, Slot.Height);*/
- bmp?.Dispose ();
- //bmp = IFace.surf.CreateSimilar (Content.ColorAlpha, Slot.Width, Slot.Height);
- bmp = new ImageSurface(Format.Argb32, Slot.Width, Slot.Height);
-
- using (Context gr = new Context (bmp)) {
- gr.Antialias = Interface.Antialias;
- onDraw (gr);
- }
-
- IsDirty = false;
-
- #if DEBUG_LOG
- dbgEvt.end = DebugLog.chrono.ElapsedTicks;
- #endif
- }
- protected virtual void UpdateCache(Context ctx){
- #if DEBUG_LOG
- DbgEvent dbgEvt = DebugLog.AddEvent(DbgEvtType.GOUpdateCacheAndPaintOnCTX, this);
- #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 ();
- #if DEBUG_LOG
- dbgEvt.end = DebugLog.chrono.ElapsedTicks;
- #endif
- }
- /// <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_LOG
- DebugLog.AddEvent(DbgEvtType.GOPaint, this);
- #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, KeyEventArgs e){
- if (KeyDown != null)
- KeyDown.Invoke (this, e);
- else if (!e.Handled)
- FocusParent?.onKeyDown (sender, e);
- }
- public virtual void onKeyUp(object sender, KeyEventArgs e){
- if (KeyUp != null)
- KeyUp.Invoke (this, e);
- else if (!e.Handled)
- FocusParent?.onKeyUp (sender, e);
- }
- public virtual void onKeyPress(object sender, KeyPressEventArgs e){
- if (KeyPress != null)
- KeyPress.Invoke (this, e);
- else if (!e.Handled)
- FocusParent?.onKeyPress (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 (parent == null)
- return false;
- if (!(isVisible & 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 (!(isVisible & 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;
-
- if (MouseMove != null)
- MouseMove.Invoke (this, e);
- else if (!e.Handled)
- FocusParent?.onMouseMove (sender, e);
-
-
- }
- public virtual void onMouseDown(object sender, MouseButtonEventArgs e){
-#if DEBUG_FOCUS
- Debug.WriteLine("MOUSE DOWN => " + this.ToString());
-#endif
-
- if (e.Button == MouseButton.Right && contextCommands != null) {
- IFace.ShowContextMenu (this);
- e.Handled = true;
- }
-
- if (MouseDown != null)
- MouseDown?.Invoke (this, e);
- else if (!e.Handled)
- FocusParent?.onMouseDown (sender, 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;
- }
- }
- if (MouseUp != null)
- MouseUp.Invoke (this, e);
- else if (!e.Handled)
- FocusParent?.onMouseUp (sender, e);
- }
- public virtual void onMouseClick(object sender, MouseButtonEventArgs e){
-#if DEBUG_FOCUS
- Debug.WriteLine("CLICK => " + this.ToString());
-#endif
- if (MouseClick != null)
- MouseClick.Invoke (this, e);
- else if (!e.Handled)
- FocusParent?.onMouseClick (sender, e);
- }
- public virtual void onMouseDoubleClick(object sender, MouseButtonEventArgs e){
-#if DEBUG_FOCUS
- Debug.WriteLine("DOUBLE CLICK => " + this.ToString());
-#endif
- if (MouseDoubleClick != null)
- MouseDoubleClick.Invoke (this, e);
- else if (!e.Handled)
- FocusParent?.onMouseDoubleClick (sender, e);
- }
- public virtual void onMouseWheel(object sender, MouseWheelEventArgs e){
- if (MouseWheelChanged != null)
- MouseWheelChanged.Invoke (this, e);
- else if (!e.Handled)
- FocusParent?.onMouseWheel (sender, e);
- }
- public virtual void onMouseEnter(object sender, MouseMoveEventArgs e)
- {
- #if DEBUG_FOCUS
- Debug.WriteLine("MouseEnter => " + this.ToString());
-#endif
-
- IFace.MouseCursor = mouseCursor;
-
- if (IFace.DragAndDropOperation != null) {
- Widget 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;
- }
- }
-
- 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);
- }
-
- #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) {
- 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 + GraphicObjects.IndexOf(this).ToString(): tmp + "." + Name;
- #else
- return string.IsNullOrEmpty(Name) ? 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.HoverWidget != null) {
- if (IFace.HoverWidget.IsOrIsInside (this)) {
- IFace.HoverWidget = null;
- IFace.OnMouseMove (IFace.Mouse.X, IFace.Mouse.Y);
- }
- }
- if (IFace.ActiveWidget != null) {
- if (IFace.ActiveWidget.IsOrIsInside (this))
- IFace.ActiveWidget = null;
- }
- if (IFace.FocusedWidget != null) {
- if (IFace.FocusedWidget.IsOrIsInside (this))
- IFace.FocusedWidget = null;
- }
- }
- }
-}
+++ /dev/null
-//
-// Window.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.Xml.Serialization;
-using System.ComponentModel;
-using System.Diagnostics;
-
-namespace Crow
-{
- public class Window : TemplatedContainer
- {
- public enum Direction
- {
- None,
- N,
- S,
- E,
- W,
- NW,
- NE,
- SW,
- SE,
- }
-
- string _icon;
- bool resizable;
- bool movable;
- bool modal;
- protected bool hoverBorder = false;
- bool alwaysOnTop = false;
- Fill titleBarBackground = Color.SteelBlue;
- Fill titleBarForeground = Color.White;
-
- Rectangle savedBounds;
- bool _minimized = false;
-
- Direction currentDirection = Direction.None;
-
- #region Events
- public event EventHandler Closing;
- public event EventHandler Maximized;
- public event EventHandler Unmaximized;
- public event EventHandler Minimize;
- #endregion
-
- #region CTOR
- protected Window() : base(){}
- public Window (Interface iface) : base(iface){}
- #endregion
-
- #region TemplatedContainer overrides
- protected override void loadTemplate(Widget template = null)
- {
- base.loadTemplate (template);
-
- NotifyValueChanged ("ShowNormal", false);
- NotifyValueChanged ("ShowMinimize", true);
- NotifyValueChanged ("ShowMaximize", true);
- }
- #endregion
-
- #region public properties
- [DefaultValue("#Crow.Icons.crow.svg")]
- public string Icon {
- get { return _icon; }
- set {
- if (_icon == value)
- return;
- _icon = value;
- NotifyValueChanged ("Icon", _icon);
- }
- }
- /// <summary>
- /// Background of the title bar if any.
- /// </summary>
- [DefaultValue("vgradient|0:Onyx|1:SteelBlue")]
- public virtual Fill TitleBarBackground {
- get { return titleBarBackground; }
- set {
- if (titleBarBackground == value)
- return;
- titleBarBackground = value;
- NotifyValueChanged ("TitleBarBackground", titleBarBackground);
- RegisterForRedraw ();
- }
- }
- /// <summary>
- /// Foreground of the title bar, usualy used for the window caption color.
- /// </summary>
- [DefaultValue("White")]
- public virtual Fill TitleBarForeground {
- get { return titleBarForeground; }
- set {
- if (titleBarForeground == value)
- return;
- titleBarForeground = value;
- NotifyValueChanged ("TitleBarForeground", titleBarForeground);
- RegisterForRedraw ();
- }
- }
- [DefaultValue(true)]
- public bool Resizable {
- get {
- return resizable;
- }
- set {
- if (resizable == value)
- return;
- resizable = value;
- NotifyValueChanged ("Resizable", resizable);
- }
- }
- [DefaultValue(true)]
- public bool Movable {
- get {
- return movable;
- }
- set {
- if (movable == value)
- return;
- movable = value;
- NotifyValueChanged ("Movable", movable);
- }
- }
- [DefaultValue(false)]
- public bool Modal {
- get {
- return modal;
- }
- set {
- if (modal == value)
- return;
- modal = value;
- NotifyValueChanged ("Modal", modal);
- }
- }
- [DefaultValue(false)]
- public bool IsMinimized {
- get { return _minimized; }
- set{
- if (value == IsMinimized)
- return;
-
- _minimized = value;
- _contentContainer.Visible = !_minimized;
-
- NotifyValueChanged ("IsMinimized", _minimized);
- }
- }
- [XmlIgnore]public bool IsMaximized {
- get { return Width == Measure.Stretched & Height == Measure.Stretched & !_minimized; }
- }
- [XmlIgnore]public bool IsNormal {
- get { return !(IsMaximized|_minimized); }
- }
- [DefaultValue(false)]
- public bool AlwaysOnTop {
- get {
- return modal ? true : alwaysOnTop;
- }
- set {
- if (alwaysOnTop == value)
- return;
-
- alwaysOnTop = value;
-
- if (AlwaysOnTop && Parent != null)
- IFace.PutOnTop (this);
-
- NotifyValueChanged ("AlwaysOnTop", AlwaysOnTop);
- }
- }
-// [DefaultValue(WindowState.Normal)]
-// public virtual WindowState State {
-// get { return _state; }
-// set {
-// if (_state == value)
-// return;
-// _state = value;
-// NotifyValueChanged ("State", _state);
-// NotifyValueChanged ("IsNormal", IsNormal);
-// NotifyValueChanged ("IsMaximized", IsMaximized);
-// NotifyValueChanged ("IsMinimized", IsMinimized);
-// NotifyValueChanged ("IsNotMinimized", IsNotMinimized);
-// }
-// }
- #endregion
-
- /// <summary>
- /// Moves the and resize with the same function entry point, the direction give the kind of move or resize
- /// </summary>
- /// <param name="XDelta">mouse delta on the X axis</param>
- /// <param name="YDelta">mouse delta on the Y axis</param>
- /// <param name="currentDirection">Current Direction of the operation, none for moving, other value for resizing in the given direction</param>
- public void MoveAndResize (int XDelta, int YDelta, Direction currentDirection = (Direction)0) {
- int currentLeft = this.Left;
- int currentTop = this.Top;
- int currentWidth, currentHeight;
-
- if (currentLeft == 0) {
- currentLeft = this.Slot.Left;
- this.Left = currentLeft;
- }
- if (currentTop == 0) {
- currentTop = this.Slot.Top;
- this.Top = currentTop;
- }
- if (this.Width.IsFixed)
- currentWidth = this.Width;
- else
- currentWidth = this.Slot.Width;
-
- if (this.Height.IsFixed)
- currentHeight = this.Height;
- else
- currentHeight = this.Slot.Height;
-
- switch (currentDirection) {
- case Direction.None:
- this.Left = currentLeft + XDelta;
- this.Top = currentTop + YDelta;
- break;
- case Direction.N:
- this.Height = currentHeight - YDelta;
- if (this.Height == currentHeight - YDelta)
- this.Top = currentTop + YDelta;
- break;
- case Direction.S:
- this.Height = currentHeight + YDelta;
- break;
- case Direction.W:
- this.Width = currentWidth - XDelta;
- if (this.Width == currentWidth - XDelta)
- this.Left = currentLeft + XDelta;
- break;
- case Direction.E:
- this.Width = currentWidth + XDelta;
- break;
- case Direction.NW:
- this.Height = currentHeight - YDelta;
- if (this.Height == currentHeight - YDelta)
- this.Top = currentTop + YDelta;
- this.Width = currentWidth - XDelta;
- if (this.Width == currentWidth - XDelta)
- this.Left = currentLeft + XDelta;
- break;
- case Direction.NE:
- this.Height = currentHeight - YDelta;
- if (this.Height == currentHeight - YDelta)
- this.Top = currentTop + YDelta;
- this.Width = currentWidth + XDelta;
- break;
- case Direction.SW:
- this.Width = currentWidth - XDelta;
- if (this.Width == currentWidth - XDelta)
- this.Left = currentLeft + XDelta;
- this.Height = currentHeight + YDelta;
- break;
- case Direction.SE:
- this.Height = currentHeight + YDelta;
- this.Width = currentWidth + XDelta;
- break;
- }
- }
-
- #region GraphicObject Overrides
- public override void onMouseMove (object sender, MouseMoveEventArgs e)
- {
- base.onMouseMove (sender, e);
-
- Interface otkgw = IFace;
-
- /*if (!hoverBorder) {
- currentDirection = Direction.None;
- IFace.MouseCursor = MouseCursor.Arrow;
- return;
- }*/
-
- if (this.HasFocus && movable) {
- if (e.Mouse.IsButtonDown (MouseButton.Left)) {
- MoveAndResize (e.XDelta, e.YDelta, currentDirection);
- return;
- }
- }
- if (Resizable) {
- Direction lastDir = currentDirection;
-
- if (Math.Abs (e.Position.Y - this.Slot.Y) < Interface.BorderThreshold) {
- if (Math.Abs (e.Position.X - this.Slot.X) < Interface.BorderThreshold)
- currentDirection = Direction.NW;
- else if (Math.Abs (e.Position.X - this.Slot.Right) < Interface.BorderThreshold)
- currentDirection = Direction.NE;
- else
- currentDirection = Direction.N;
- } else if (Math.Abs (e.Position.Y - this.Slot.Bottom) < Interface.BorderThreshold) {
- if (Math.Abs (e.Position.X - this.Slot.X) < Interface.BorderThreshold)
- currentDirection = Direction.SW;
- else if (Math.Abs (e.Position.X - this.Slot.Right) < Interface.BorderThreshold)
- currentDirection = Direction.SE;
- else
- currentDirection = Direction.S;
- } else if (Math.Abs (e.Position.X - this.Slot.X) < Interface.BorderThreshold)
- currentDirection = Direction.W;
- else if (Math.Abs (e.Position.X - this.Slot.Right) < Interface.BorderThreshold)
- currentDirection = Direction.E;
- else
- currentDirection = Direction.None;
-
- if (currentDirection != lastDir) {
- switch (currentDirection) {
- case Direction.None:
- otkgw.MouseCursor = MouseCursor.Move;
- break;
- case Direction.N:
- otkgw.MouseCursor = MouseCursor.Top;
- break;
- case Direction.S:
- otkgw.MouseCursor = MouseCursor.Bottom;
- break;
- case Direction.E:
- otkgw.MouseCursor = MouseCursor.Right;
- break;
- case Direction.W:
- otkgw.MouseCursor = MouseCursor.Left;
- break;
- case Direction.NW:
- otkgw.MouseCursor = MouseCursor.TopLeft;
- break;
- case Direction.NE:
- otkgw.MouseCursor = MouseCursor.TopRight;
- break;
- case Direction.SW:
- otkgw.MouseCursor = MouseCursor.BottomLeft;
- break;
- case Direction.SE:
- otkgw.MouseCursor = MouseCursor.BottomRight;
- break;
- }
- }
- }
- }
- public override void onMouseDown (object sender, MouseButtonEventArgs e)
- {
- base.onMouseDown (sender, e);
- }
- public override bool MouseIsIn (Point m)
- {
- return modal ? true : base.MouseIsIn (m);
- }
- #endregion
-
- protected void onMaximized (object sender, EventArgs e){
- lock (IFace.LayoutMutex) {
- if (!IsMinimized)
- savedBounds = this.LastPaintedSlot;
- this.Left = this.Top = 0;
- this.RegisterForLayouting (LayoutingType.Positioning);
- this.Width = this.Height = Measure.Stretched;
- IsMinimized = false;
- Resizable = false;
- NotifyValueChanged ("ShowNormal", true);
- NotifyValueChanged ("ShowMinimize", true);
- NotifyValueChanged ("ShowMaximize", false);
- }
-
- Maximized.Raise (sender, e);
- }
- protected void onUnmaximized (object sender, EventArgs e){
- lock (IFace.LayoutMutex) {
- this.Left = savedBounds.Left;
- this.Top = savedBounds.Top;
- this.Width = savedBounds.Width;
- this.Height = savedBounds.Height;
- IsMinimized = false;
- Resizable = true;
- NotifyValueChanged ("ShowNormal", false);
- NotifyValueChanged ("ShowMinimize", true);
- NotifyValueChanged ("ShowMaximize", true);
- }
-
- Unmaximized.Raise (sender, e);
- }
- protected void onMinimized (object sender, EventArgs e){
- lock (IFace.LayoutMutex) {
- if (IsNormal)
- savedBounds = this.LastPaintedSlot;
- Width = 200;
- Height = 20;
- Resizable = false;
- IsMinimized = true;
- NotifyValueChanged ("ShowNormal", true);
- NotifyValueChanged ("ShowMinimize", false);
- NotifyValueChanged ("ShowMaximize", true);
- }
-
- Minimize.Raise (sender, e);
- }
- protected virtual void onBorderMouseLeave (object sender, MouseMoveEventArgs e)
- {
- hoverBorder = false;
- currentDirection = Direction.None;
- IFace.MouseCursor = MouseCursor.Arrow;
- }
- protected virtual void onBorderMouseEnter (object sender, MouseMoveEventArgs e)
- {
- hoverBorder = true;
- }
-
-
- protected void butQuitPress (object sender, MouseButtonEventArgs e)
- {
- IFace.MouseCursor = MouseCursor.Arrow;
- close ();
- }
-
- protected virtual void close(){
- Closing.Raise (this, null);
- if (Parent is Interface)
- (Parent as Interface).DeleteWidget (this);
- else {
- Widget p = Parent as Widget;
- if (p is Group) {
- lock (IFace.UpdateMutex) {
- RegisterClip (p.ScreenCoordinates (p.LastPaintedSlot));
- (p as Group).DeleteChild (this);
- }
- //(Parent as Group).RegisterForRedraw ();
- } else if (Parent is PrivateContainer)
- (Parent as Container).Child = null;
- }
- }
-
- public static Window Show (Interface iface, string imlPath, bool modal = false){
- lock (iface.UpdateMutex) {
- Window w = iface.Load (imlPath) as Window;
- w.Modal = modal;
- return w;
- }
- }
- }
-}
-
+++ /dev/null
-//
-// Wrapper.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;
-
-namespace Crow
-{
- /// <summary>
- /// group control that arrange its children in a direction and jump to
- /// the next line or row when no room is left
- /// </summary>
- public class Wrapper : GenericStack
- {
- #region CTOR
- protected Wrapper() : base(){}
- public Wrapper (Interface iface) : base(iface){}
- #endregion
-
- #region Group Overrides
- public override void ChildrenLayoutingConstraints (ref LayoutingType layoutType)
- {
- layoutType &= (~LayoutingType.Positioning);
- }
- public override void ComputeChildrenPositions()
- {
- int dx = 0;
- int dy = 0;
-
- if (Orientation == Orientation.Vertical) {
- int tallestChild = 0;
- foreach (Widget c in Children) {
- if (!c.Visible)
- continue;
- if (dx + c.Slot.Width > ClientRectangle.Width) {
- dx = 0;
- dy += tallestChild + Spacing;
- c.Slot.X = dx;
- c.Slot.Y = dy;
- tallestChild = c.Slot.Height;
- } else {
- if (tallestChild < c.Slot.Height)
- tallestChild = c.Slot.Height;
- c.Slot.X = dx;
- c.Slot.Y = dy;
- }
- dx += c.Slot.Width + Spacing;
- }
- } else {
- int largestChild = 0;
- foreach (Widget c in Children) {
- if (!c.Visible)
- continue;
- if (dy + c.Slot.Height > ClientRectangle.Height) {
- dy = 0;
- dx += largestChild + Spacing;
- c.Slot.X = dx;
- c.Slot.Y = dy;
- largestChild = c.Slot.Width;
- } else {
- if (largestChild < c.Slot.Width)
- largestChild = c.Slot.Width;
- c.Slot.X = dx;
- c.Slot.Y = dy;
- }
- dy += c.Slot.Height + Spacing;
- }
- }
- IsDirty = true;
- }
- public override void OnChildLayoutChanges (object sender, LayoutingEventArgs arg)
- {
- //children can't stretch in a wrapper
- Widget go = sender as Widget;
- //System.Diagnostics.Debug.WriteLine ("wrapper child layout change: " + go.LastSlots.ToString() + " => " + go.Slot.ToString());
- switch (arg.LayoutType) {
- case LayoutingType.Width:
- if (Orientation == Orientation.Horizontal && go.Width.Units == Unit.Percent){
- go.Width = Measure.Fit;
- return;
- }
- this.RegisterForLayouting (LayoutingType.Width);
- break;
- case LayoutingType.Height:
- if (Orientation == Orientation.Vertical && go.Height.IsRelativeToParent) {
- go.Height = Measure.Fit;
- return;
- }
- this.RegisterForLayouting (LayoutingType.Height);
- break;
- default:
- return;
- }
- this.RegisterForLayouting (LayoutingType.ArrangeChildren);
- }
- #endregion
-
- #region GraphicObject Overrides
- protected override int measureRawSize (LayoutingType lt)
- {
- int tmp = 0;
- //Wrapper can't fit in the opposite direction of the wrapper, this func is called only if Fit
- if (lt == LayoutingType.Width) {
- if (Orientation == Orientation.Vertical) {
- Width = Measure.Stretched;
- return -1;
- } else if (RegisteredLayoutings.HasFlag (LayoutingType.Height))
- return -1;
- else {
- int dy = 0;
- int largestChild = 0;
-
- childrenRWLock.EnterReadLock();
-
- foreach (Widget c in Children) {
- if (!c.Visible)
- continue;
- if (c.Height.IsRelativeToParent &&
- c.RegisteredLayoutings.HasFlag (LayoutingType.Height)) {
- childrenRWLock.ExitReadLock();
- return -1;
- }
- if (dy + c.Slot.Height > ClientRectangle.Height) {
- dy = 0;
- tmp += largestChild + Spacing;
- largestChild = c.Slot.Width;
- } else if (largestChild < c.Slot.Width)
- largestChild = c.Slot.Width;
-
- dy += c.Slot.Height + Spacing;
- }
-
- childrenRWLock.ExitReadLock ();
-
- if (dy == 0)
- tmp -= Spacing;
- return tmp + largestChild + 2 * Margin;
- }
- } else if (Orientation == Orientation.Horizontal) {
- Height = Measure.Stretched;
- return -1;
- } else if (RegisteredLayoutings.HasFlag (LayoutingType.Width))
- return -1;
- else {
- int dx = 0;
- int tallestChild = 0;
-
- childrenRWLock.EnterReadLock();
-
- foreach (Widget c in Children) {
- if (!c.Visible)
- continue;
- if (c.Width.IsRelativeToParent &&
- c.RegisteredLayoutings.HasFlag (LayoutingType.Width)) {
- childrenRWLock.ExitReadLock();
- return -1;
- }
- if (dx + c.Slot.Width > ClientRectangle.Width) {
- dx = 0;
- tmp += tallestChild + Spacing;
- tallestChild = c.Slot.Height;
- } else if (tallestChild < c.Slot.Height)
- tallestChild = c.Slot.Height;
-
- dx += c.Slot.Width + Spacing;
- }
-
- childrenRWLock.ExitReadLock();
-
- if (dx == 0)
- tmp -= Spacing;
- return tmp + tallestChild + 2 * Margin;
- }
- }
-
- public override bool UpdateLayout (LayoutingType layoutType)
- {
- RegisteredLayoutings &= (~layoutType);
-
- if (layoutType == LayoutingType.ArrangeChildren) {
- if ((RegisteredLayoutings & LayoutingType.Sizing) != 0)
- return false;
-
- ComputeChildrenPositions ();
-
- //if no layouting remains in queue for item, registre for redraw
- if (RegisteredLayoutings == LayoutingType.None && IsDirty)
- IFace.EnqueueForRepaint (this);
-
- return true;
- }
-
- return base.UpdateLayout(layoutType);
- }
- public override void OnLayoutChanges (LayoutingType layoutType)
- {
- #if DEBUG_LAYOUTING
- IFace.currentLQI.Slot = LastSlots;
- IFace.currentLQI.Slot = Slot;
- #endif
- switch (layoutType) {
- case LayoutingType.Width:
- foreach (Widget c in Children) {
- if (c.Width.IsRelativeToParent)
- c.RegisterForLayouting (LayoutingType.Width);
- }
- if (Height == Measure.Fit)
- RegisterForLayouting (LayoutingType.Height);
- RegisterForLayouting (LayoutingType.X);
- break;
- case LayoutingType.Height:
- foreach (Widget c in Children) {
- if (c.Height.IsRelativeToParent)
- c.RegisterForLayouting (LayoutingType.Height);
- }
- if (Width == Measure.Fit)
- RegisterForLayouting (LayoutingType.Width);
- RegisterForLayouting (LayoutingType.Y);
- break;
- default:
- return;
- }
- RegisterForLayouting (LayoutingType.ArrangeChildren);
- raiseLayoutChanged (new LayoutingEventArgs (layoutType));
- }
- #endregion
- }
-}
-
+++ /dev/null
-//
-// Expandable.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;
-
-namespace Crow
-{
- public class XmlIgnoreAttribute : Attribute
- {
- }
-}
\ No newline at end of file
--- /dev/null
+//
+// Border.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.Xml.Serialization;
+using System.ComponentModel;
+using System.Diagnostics;
+using Crow.Cairo;
+
+namespace Crow
+{
+ /// <summary>
+ /// provide an easy way to get 3d border for buttons
+ /// </summary>
+ public enum BorderStyle {
+ Normal,
+ Raised,
+ Sunken
+ };
+
+ /// <summary>
+ /// simple container with border
+ /// </summary>
+ public class Border : Container
+ {
+ #region CTOR
+ protected Border () : base(){}
+ public Border (Interface iface) : base(iface){}
+ #endregion
+
+ #region private fields
+ int _borderWidth;
+ BorderStyle _borderStyle;
+ Fill raisedColor = Color.Grey;
+ Fill sunkenColor = Color.DimGrey;
+ #endregion
+
+ #region public properties
+ /// <summary>
+ /// use to define the colors of the 3d border
+ /// </summary>
+
+ public virtual Fill RaisedColor {
+ get { return raisedColor; }
+ set {
+ if (raisedColor == value)
+ return;
+ raisedColor = value;
+ NotifyValueChanged ("RaisedColor", raisedColor);
+ RegisterForRedraw ();
+ }
+ }
+ /// <summary>
+ /// use to define the colors of the 3d border
+ /// </summary>
+
+ public virtual Fill SunkenColor {
+ get { return sunkenColor; }
+ set {
+ if (sunkenColor == value)
+ return;
+ sunkenColor = value;
+ NotifyValueChanged ("SunkenColor", sunkenColor);
+ RegisterForRedraw ();
+ }
+ }
+ /// <summary>
+ /// border width in pixels
+ /// </summary>
+ [DefaultValue(1)]
+ public virtual int BorderWidth {
+ get { return _borderWidth; }
+ set {
+ _borderWidth = value;
+ RegisterForGraphicUpdate ();
+ }
+ }
+ /// <summary>
+ /// allow 3d border effects
+ /// </summary>
+ [DefaultValue(BorderStyle.Normal)]
+ public virtual BorderStyle BorderStyle {
+ get { return _borderStyle; }
+ set {
+ if (_borderStyle == value)
+ return;
+ _borderStyle = value;
+ RegisterForGraphicUpdate ();
+ }
+ }
+ #endregion
+
+ #region GraphicObject override
+ [XmlIgnore]public override Rectangle ClientRectangle {
+ get {
+ Rectangle cb = base.ClientRectangle;
+ cb.Inflate (- BorderWidth);
+ return cb;
+ }
+ }
+
+ protected override int measureRawSize (LayoutingType lt)
+ {
+ int tmp = base.measureRawSize (lt);
+ return tmp < 0 ? tmp : tmp + 2 * BorderWidth;
+ }
+ protected override void onDraw (Context gr)
+ {
+ drawborder2 (gr);
+
+ gr.Save ();
+ if (ClipToClientRect) {
+ //clip to client zone
+ CairoHelpers.CairoRectangle (gr, ClientRectangle,Math.Max(0.0, CornerRadius-Margin));
+ gr.Clip ();
+ }
+
+ if (child != null)
+ child.Paint (ref gr);
+ gr.Restore ();
+ }
+ void drawborder2(Context gr){
+ Rectangle rBack = new Rectangle (Slot.Size);
+
+ //rBack.Inflate (-Margin);
+ // if (BorderWidth > 0)
+ // rBack.Inflate (-BorderWidth / 2);
+
+ Background.SetAsSource (gr, rBack);
+ CairoHelpers.CairoRectangle(gr, rBack, CornerRadius);
+ gr.Fill ();
+
+
+ if (BorderStyle == BorderStyle.Normal) {
+ if (BorderWidth > 0) {
+ Foreground.SetAsSource (gr, rBack);
+ CairoHelpers.CairoRectangle (gr, rBack, CornerRadius, BorderWidth);
+ }
+ } else {
+ gr.LineWidth = 1.0;
+ if (CornerRadius > 0.0) {
+ double radius = CornerRadius;
+ if ((radius > rBack.Height / 2.0) || (radius > rBack.Width / 2.0))
+ radius = Math.Min (rBack.Height / 2.0, rBack.Width / 2.0);
+ gr.SetSourceColor (sunkenColor);
+ gr.MoveTo (0.5 + rBack.Left, -0.5 + rBack.Bottom - radius);
+ gr.ArcNegative (0.5 + rBack.Left + radius, -0.5 + rBack.Bottom - radius, radius, Math.PI, Math.PI * 0.75);
+ gr.MoveTo (0.5 + rBack.Left, -0.5 + rBack.Bottom - radius);
+ gr.LineTo (0.5 + rBack.Left, 0.5 + rBack.Top + radius);
+ gr.Arc (0.5 + rBack.Left + radius, 0.5 + rBack.Top + radius, radius, Math.PI, Math.PI * 1.5);
+ gr.LineTo (-0.5 + rBack.Right - radius, 0.5 + rBack.Top);
+ gr.Arc (-0.5 + rBack.Right - radius, 0.5 + rBack.Top + radius, radius, Math.PI * 1.5, Math.PI * 1.75);
+ gr.Stroke ();
+ if (BorderStyle == BorderStyle.Raised) {
+ gr.MoveTo (-1.5 + rBack.Right, 1.5 + rBack.Top + radius);
+ gr.ArcNegative (-0.5 + rBack.Right - radius, 0.5 + rBack.Top + radius, radius - 1.0, 0, -Math.PI * 0.25);
+ gr.MoveTo (-1.5 + rBack.Right, 1.5 + rBack.Top + radius);
+ gr.LineTo (-1.5 + rBack.Right, -1.5 + rBack.Bottom - radius);
+ gr.Arc (-0.5 + rBack.Right - radius, -0.5 + rBack.Bottom - radius, radius - 1.0, 0, Math.PI / 2.0);
+ gr.LineTo (1.5 + rBack.Left + radius, -1.5 + rBack.Bottom);
+ gr.Arc (0.5 + rBack.Left + radius, -0.5 + rBack.Bottom - radius, radius - 1.0, Math.PI / 2.0, Math.PI * 0.75);
+ gr.Stroke ();
+
+ gr.SetSourceColor (raisedColor);
+ gr.MoveTo (1.5 + rBack.Left, -1.5 + rBack.Bottom - radius);
+ gr.ArcNegative (0.5 + rBack.Left + radius, -0.5 + rBack.Bottom - radius, radius - 1.0, Math.PI, Math.PI * 0.75);
+ gr.MoveTo (1.5 + rBack.Left, -1.5 + rBack.Bottom - radius);
+ gr.LineTo (1.5 + rBack.Left, 1.5 + rBack.Top + radius);
+ gr.Arc (0.5 + rBack.Left + radius, 0.5 + rBack.Top + radius, radius - 1.0, Math.PI, Math.PI * 1.5);
+ gr.LineTo (-1.5 + rBack.Right - radius, 1.5 + rBack.Top);
+ gr.Arc (-0.5 + rBack.Right - radius, 0.5 + rBack.Top + radius, radius - 1.0, Math.PI * 1.5, Math.PI * 1.75);
+ } else {
+ gr.Stroke ();
+ gr.SetSourceColor (raisedColor);
+ }
+ gr.MoveTo (-0.5 + rBack.Right, 0.5 + rBack.Top + radius);
+ gr.ArcNegative (-0.5 + rBack.Right - radius, 0.5 + rBack.Top + radius, radius, 0, -Math.PI * 0.25);
+ gr.MoveTo (-0.5 + rBack.Right, 0.5 + rBack.Top + radius);
+ gr.LineTo (-0.5 + rBack.Right, -0.5 + rBack.Bottom - radius);
+ gr.Arc (-0.5 + rBack.Right - radius, -0.5 + rBack.Bottom - radius, radius, 0, Math.PI / 2.0);
+ gr.LineTo (0.5 + rBack.Left + radius, -0.5 + rBack.Bottom);
+ gr.Arc (0.5 + rBack.Left + radius, -0.5 + rBack.Bottom - radius, radius, Math.PI / 2.0, Math.PI * 0.75);
+ gr.Stroke ();
+ } else {
+ gr.SetSourceColor (sunkenColor);
+ gr.MoveTo (0.5 + rBack.Left, rBack.Bottom);
+ gr.LineTo (0.5 + rBack.Left, 0.5 + rBack.Y);
+ gr.LineTo (rBack.Right, 0.5 + rBack.Y);
+ if (BorderStyle == BorderStyle.Raised) {
+ gr.MoveTo (-1.5 + rBack.Right, 2.0 + rBack.Y);
+ gr.LineTo (-1.5 + rBack.Right, -1.5 + rBack.Bottom);
+ gr.LineTo (2.0 + rBack.Left, -1.5 + rBack.Bottom);
+ gr.Stroke ();
+ gr.SetSourceColor (raisedColor);
+ gr.MoveTo (1.5 + rBack.Left, -1.0 + rBack.Bottom);
+ gr.LineTo (1.5 + rBack.Left, 1.5 + rBack.Y);
+ gr.LineTo (rBack.Right, 1.5 + rBack.Y);
+ } else {
+ gr.Stroke ();
+ gr.SetSourceColor (raisedColor);
+ }
+ gr.MoveTo (-0.5 + rBack.Right, 1.5 + rBack.Y);
+ gr.LineTo (-0.5 + rBack.Right, -0.5 + rBack.Bottom);
+ gr.LineTo (1.0 + rBack.Left, -0.5 + rBack.Bottom);
+ gr.Stroke ();
+ }
+ }
+ }
+ void drawborder1(Context gr){
+ Rectangle rBack = new Rectangle (Slot.Size);
+
+ //rBack.Inflate (-Margin);
+ // if (BorderWidth > 0)
+ // rBack.Inflate (-BorderWidth / 2);
+
+ Background.SetAsSource (gr, rBack);
+ CairoHelpers.CairoRectangle(gr, rBack, CornerRadius);
+ gr.Fill ();
+
+ double bw = _borderWidth;
+ double crad = CornerRadius;
+
+ if (bw > 0) {
+ if (BorderStyle == BorderStyle.Normal)
+ Foreground.SetAsSource (gr, rBack);
+ else {
+ if (BorderStyle == BorderStyle.Sunken)
+ gr.SetSourceColor (raisedColor);
+ else
+ gr.SetSourceColor (sunkenColor);
+
+ CairoHelpers.CairoRectangle (gr, rBack, crad, bw);
+
+ if (BorderStyle == BorderStyle.Sunken)
+ gr.SetSourceColor (sunkenColor);
+ else
+ gr.SetSourceColor (raisedColor);
+
+ bw /= 2.0;
+ rBack.Width -= (int)Math.Round(bw);
+ rBack.Height -= (int)Math.Round(bw);
+ }
+
+ CairoHelpers.CairoRectangle (gr, rBack, crad, bw);
+ }
+ }
+ #endregion
+ }
+}
+
--- /dev/null
+//
+// Button.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.Linq;
+using System.Text;
+//using OpenTK.Graphics.OpenGL;
+
+using System.Diagnostics;
+
+using System.Xml.Serialization;
+using Crow.Cairo;
+using System.ComponentModel;
+
+namespace Crow
+{
+ /// <summary>
+ /// templated button control
+ /// </summary>
+ public class Button : TemplatedContainer
+ {
+ #region CTOR
+ protected Button() : base() {}
+ public Button (Interface iface) : base(iface){}
+ #endregion
+
+ string image;
+ bool isPressed;
+
+ public event EventHandler Pressed;
+ public event EventHandler Released;
+
+ #region GraphicObject Overrides
+ public override void onMouseDown (object sender, MouseButtonEventArgs e)
+ {
+ IsPressed = true;
+
+ base.onMouseDown (sender, e);
+
+ //TODO:remove
+ NotifyValueChanged ("State", "pressed");
+ }
+ public override void onMouseUp (object sender, MouseButtonEventArgs e)
+ {
+ IsPressed = false;
+
+ base.onMouseUp (sender, e);
+
+ //TODO:remove
+ NotifyValueChanged ("State", "normal");
+ }
+ #endregion
+
+ [DefaultValue("#Crow.Images.button.svg")]
+ public string Image {
+ get { return image; }
+ set {
+ if (image == value)
+ return;
+ image = value;
+ NotifyValueChanged ("Image", image);
+ }
+ }
+ [DefaultValue(false)]
+ public bool IsPressed
+ {
+ get { return isPressed; }
+ set
+ {
+ if (isPressed == value)
+ return;
+
+ isPressed = value;
+
+ NotifyValueChanged ("IsPressed", isPressed);
+
+ if (isPressed)
+ Pressed.Raise (this, null);
+ else
+ Released.Raise (this, null);
+ }
+ }
+ }
+}
--- /dev/null
+//
+// CheckBox.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.ComponentModel;
+using System.Xml.Serialization;
+
+namespace Crow
+{
+ /// <summary>
+ /// templated checkbox control
+ /// </summary>
+ public class CheckBox : TemplatedControl
+ {
+ #region CTOR
+ protected CheckBox() : base(){}
+ public CheckBox (Interface iface) : base(iface){}
+ #endregion
+
+ bool isChecked;
+
+ public event EventHandler Checked;
+ public event EventHandler Unchecked;
+
+ [DefaultValue(false)]
+ public bool IsChecked
+ {
+ get { return isChecked; }
+ set
+ {
+ if (isChecked == value)
+ return;
+
+ isChecked = value;
+
+ NotifyValueChanged ("IsChecked", value);
+
+ if (isChecked)
+ Checked.Raise (this, null);
+ else
+ Unchecked.Raise (this, null);
+ }
+ }
+
+ public override void onMouseClick (object sender, MouseButtonEventArgs e)
+ {
+ IsChecked = !IsChecked;
+ base.onMouseClick (sender, e);
+ }
+ }
+}
--- /dev/null
+//
+// ColorPicker.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.Xml.Serialization;
+using System.ComponentModel;
+
+namespace Crow
+{
+ /// <summary>
+ /// templated color selector control
+ /// </summary>
+ public class ColorPicker : TemplatedControl
+ {
+ #region CTOR
+ protected ColorPicker() : base(){}
+ public ColorPicker (Interface iface) : base(iface){}
+ #endregion
+
+ const double div = 255.0;
+ const double colDiv = 1.0 / div;
+
+ Color curColor;
+ double h,s,v;
+
+
+ public virtual double R {
+ get { return Math.Round(curColor.R * div); }
+ set {
+ if (R == value)
+ return;
+ curColor.R = value * colDiv;
+ NotifyValueChanged ("R", R);
+ hsvFromRGB ();
+ notifyCurColorHasChanged ();
+ }
+ }
+
+ public virtual double G {
+ get { return Math.Round(curColor.G * div); }
+ set {
+ if (G == value)
+ return;
+ curColor.G = value * colDiv;
+ NotifyValueChanged ("G", G);
+ notifyCurColorHasChanged ();
+ hsvFromRGB ();
+ }
+ }
+
+ public virtual double B {
+ get { return Math.Round(curColor.B * div); }
+ set {
+ if (B == value)
+ return;
+ curColor.B = value * colDiv;
+ NotifyValueChanged ("B", B);
+ notifyCurColorHasChanged ();
+ hsvFromRGB ();
+ }
+ }
+
+ public virtual double A {
+ get { return Math.Round(curColor.A * div); }
+ set {
+ if (A == value)
+ return;
+ curColor.A = value * colDiv;
+ NotifyValueChanged ("A", A);
+ notifyCurColorHasChanged ();
+ hsvFromRGB ();
+ }
+ }
+
+ public virtual double H {
+ get { return Math.Round (h, 3); }
+ set {
+ if (H == value)
+ return;
+ h = value;
+ NotifyValueChanged ("H", H);
+ rgbFromHSV ();
+ }
+ }
+
+ public virtual double S {
+ get { return Math.Round (s, 2); }
+ set {
+ if (s == value)
+ return;
+ s = value;
+ NotifyValueChanged ("S", S);
+ rgbFromHSV ();
+ }
+ }
+
+ public virtual double V {
+ get { return Math.Round (v, 2); }
+ set {
+ if (v == value)
+ return;
+ v = value;
+ NotifyValueChanged ("V", V);
+ rgbFromHSV ();
+ }
+ }
+
+
+ public virtual Fill SelectedColor {
+ get { return new SolidColor(curColor); }
+ set {
+ if (value == null)
+ curColor = Color.White;
+ else if (value is SolidColor) {
+ Color c = (value as SolidColor).color;
+ if (curColor == c)
+ return;
+ curColor = c;
+ }
+ notifyCurColorHasChanged ();
+ notifyRGBAHasChanged ();
+ hsvFromRGB ();
+ }
+ }
+
+ public virtual Color SelectedRawColor {
+ get { return curColor; }
+ set {
+ if (curColor == value)
+ return;
+ curColor = value;
+ notifyCurColorHasChanged ();
+ notifyRGBAHasChanged ();
+ hsvFromRGB ();
+ }
+ }
+ void notifyCurColorHasChanged(){
+ NotifyValueChanged ("SelectedColor", SelectedColor);
+ NotifyValueChanged ("SelectedRawColor", curColor);
+ string n = curColor.ToString ();
+ if (char.IsLetter(n[0]))
+ NotifyValueChanged ("SelectedColorName", n);
+ else
+ NotifyValueChanged ("SelectedColorName", "-");
+ string tmp = ((int)Math.Round (R)).ToString ("X2") +
+ ((int)Math.Round (G)).ToString ("X2") +
+ ((int)Math.Round (B)).ToString ("X2");
+ if (curColor.A < 1.0)
+ tmp += ((int)Math.Round (A)).ToString ("X2");
+ NotifyValueChanged ("HexColor", tmp);
+ }
+ void notifyRGBAHasChanged(){
+ NotifyValueChanged ("R", R);
+ NotifyValueChanged ("G", G);
+ NotifyValueChanged ("B", B);
+ NotifyValueChanged ("A", A);
+ }
+ void notifyHSVHasChanged(){
+ NotifyValueChanged ("H", H);
+ NotifyValueChanged ("S", S);
+ NotifyValueChanged ("V", V);
+ }
+ void hsvFromRGB(){
+ Color c = curColor;
+ c.ResetName ();
+ double min = Math.Min (c.R, Math.Min (c.G, c.B)); //Min. value of RGB
+ double max = Math.Max (c.R, Math.Max (c.G, c.B)); //Max. value of RGB
+ double diff = max - min; //Delta RGB value
+
+ v = max;
+
+ if ( diff == 0 )//This is a gray, no chroma...
+ {
+ h = 0;
+ s = 0;
+ }else{//Chromatic data...
+ s = diff / max;
+
+ double diffR = (((max - c.R) / 6.0) + (diff / 2.0)) / diff;
+ double diffG = (((max - c.G) / 6.0) + (diff / 2.0)) / diff;
+ double diffB = (((max - c.B) / 6.0) + (diff / 2.0)) / diff;
+
+ if (c.R == max)
+ h = diffB - diffG;
+ else if (c.G == max)
+ h = (1.0 / 3.0) + diffR - diffB;
+ else if (c.B == max)
+ h = (2.0 / 3.0) + diffG - diffR;
+
+ if (h < 0)
+ h += 1;
+ if (h > 1)
+ h -= 1;
+
+ }
+ notifyHSVHasChanged ();
+ }
+ void rgbFromHSV(){
+ curColor = Color.FromHSV (h, v, s, curColor.A);
+ notifyCurColorHasChanged ();
+ notifyRGBAHasChanged ();
+ }
+ }
+}
+
--- /dev/null
+// Copyright (c) 2013-2019 Bruyère Jean-Philippe jp_bruyere@hotmail.com
+//
+// This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT)
+
+using System;
+
+namespace Crow
+{
+ /// <summary>
+ /// simple squarred rgb color selector
+ /// </summary>
+ [DesignIgnore]
+ public class ColorSelector : Widget
+ {
+ #region CTOR
+ protected ColorSelector() : base(){}
+ public ColorSelector (Interface iface) : base(iface){}
+ #endregion
+
+ protected Point mousePos;
+
+ public override void onMouseMove (object sender, MouseMoveEventArgs e)
+ {
+ base.onMouseMove (sender, e);
+ if (IFace.Mouse.LeftButton == ButtonState.Released)
+ return;
+ updateMouseLocalPos (e.Position);
+ }
+ public override void onMouseDown (object sender, MouseButtonEventArgs e)
+ {
+ base.onMouseDown (sender, e);
+ if (e.Button == MouseButton.Left)
+ updateMouseLocalPos (e.Position);
+ }
+
+ protected virtual void updateMouseLocalPos(Point mPos){
+ Rectangle r = ScreenCoordinates (Slot);
+ Rectangle cb = ClientRectangle;
+ mousePos = mPos - r.Position;
+
+ mousePos.X = Math.Max(cb.X, mousePos.X);
+ mousePos.X = Math.Min(cb.Right, mousePos.X);
+ mousePos.Y = Math.Max(cb.Y, mousePos.Y);
+ mousePos.Y = Math.Min(cb.Bottom, mousePos.Y);
+
+ RegisterForRedraw ();
+ }
+ }
+}
+
--- /dev/null
+// Copyright (c) 2013-2019 Bruyère Jean-Philippe jp_bruyere@hotmail.com
+//
+// This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT)
+
+using System;
+using System.ComponentModel;
+using Crow.Cairo;
+
+namespace Crow
+{
+ /// <summary>
+ /// Color component slider with background gradient ranging from 0 to 1 for this component value.
+ /// </summary>
+ [DesignIgnore]
+ public class ColorSlider : Widget
+ {
+ #region CTOR
+ protected ColorSlider() : base(){}
+ public ColorSlider (Interface iface) : base(iface){}
+ #endregion
+
+ protected Point mousePos;//store local mouse pos sync with currentValue
+ Orientation orientation;
+ CursorType cursorType = CursorType.Pentagone;
+ ColorComponent component;
+ Color currentColor = Color.Black;
+ double currentValue = -1;//force notify for property less binding 'CurrentValue'
+
+ [DefaultValue (Orientation.Horizontal)]
+ public Orientation Orientation {
+ get => orientation;
+ set {
+ if (orientation == value)
+ return;
+ orientation = value;
+ NotifyValueChanged ("Orientation", orientation);
+ RegisterForGraphicUpdate ();
+ }
+ }
+ [DefaultValue (CursorType.Pentagone)]
+ public CursorType CursorType {
+ get => cursorType;
+ set {
+ if (cursorType == value)
+ return;
+ cursorType = value;
+ NotifyValueChanged ("CursorType", cursorType);
+ RegisterForRedraw ();
+ }
+ }
+ [DefaultValue (ColorComponent.Value)]
+ public ColorComponent Component {
+ get => component;
+ set {
+ if (component == value)
+ return;
+ component = value;
+ NotifyValueChanged ("Component", component);
+ RegisterForRedraw ();
+ }
+ }
+ public Color CurrentColor {
+ get => currentColor;
+ set {
+ if (currentColor == value)
+ return;
+
+ currentColor = value;
+
+ NotifyValueChanged ("CurrentColor", currentColor);
+ RegisterForRedraw ();
+
+ switch (component) {
+ case ColorComponent.Red:
+ if (currentValue == currentColor.R)
+ return;
+ currentValue = currentColor.R;
+ break;
+ case ColorComponent.Green:
+ if (currentValue == currentColor.G)
+ return;
+ currentValue = currentColor.G;
+ break;
+ case ColorComponent.Blue:
+ if (currentValue == currentColor.B)
+ return;
+ currentValue = currentColor.B;
+ break;
+ case ColorComponent.Alpha:
+ if (currentValue == currentColor.A)
+ return;
+ currentValue = currentColor.A;
+ break;
+ case ColorComponent.Hue:
+ if (currentValue == currentColor.Hue)
+ return;
+ currentValue = currentColor.Hue;
+ break;
+ case ColorComponent.Saturation:
+ if (currentValue == currentColor.Saturation)
+ return;
+ currentValue = currentColor.Saturation;
+ break;
+ case ColorComponent.Value:
+ if (currentValue == currentColor.Value)
+ return;
+ currentValue = currentColor.Value;
+ break;
+ }
+
+ NotifyValueChanged ("CurrentValue", $"{currentValue:0.000}");
+
+ if (Orientation == Orientation.Horizontal)
+ mousePos.X = (int)Math.Floor (currentValue * ClientRectangle.Width);
+ else
+ mousePos.Y = (int)Math.Floor (currentValue * ClientRectangle.Height);
+ }
+ }
+ public override void onMouseMove (object sender, MouseMoveEventArgs e)
+ {
+ base.onMouseMove (sender, e);
+ if (IFace.Mouse.LeftButton == ButtonState.Released)
+ return;
+ updateMouseLocalPos (e.Position);
+ }
+ public override void onMouseDown (object sender, MouseButtonEventArgs e)
+ {
+ base.onMouseDown (sender, e);
+ if (e.Button == MouseButton.Left)
+ updateMouseLocalPos (e.Position);
+ }
+
+ protected override void onDraw (Context gr) {
+ base.onDraw (gr);
+
+ RectangleD r = ClientRectangle;
+ r.Height -= 4;
+ r.Y += 2;
+
+ Gradient.Type gt = Gradient.Type.Horizontal;
+ if (Orientation == Orientation.Vertical)
+ gt = Gradient.Type.Vertical;
+
+ Gradient grad = new Gradient (gt);
+ Color c = currentColor;
+
+ switch (component) {
+ case ColorComponent.Red:
+ grad.Stops.Add (new Gradient.ColorStop (0, new Color (0, c.G, c.B, c.A)));
+ grad.Stops.Add (new Gradient.ColorStop (1, new Color (1, c.G, c.B, c.A)));
+ break;
+ case ColorComponent.Green:
+ grad.Stops.Add (new Gradient.ColorStop (0, new Color (c.R, 0, c.B, c.A)));
+ grad.Stops.Add (new Gradient.ColorStop (1, new Color (c.R, 1, c.B, c.A)));
+ break;
+ case ColorComponent.Blue:
+ grad.Stops.Add (new Gradient.ColorStop (0, new Color (c.R, c.G, 0, c.A)));
+ grad.Stops.Add (new Gradient.ColorStop (1, new Color (c.R, c.G, 1, c.A)));
+ break;
+ case ColorComponent.Alpha:
+ grad.Stops.Add (new Gradient.ColorStop (0, new Color (c.R, c.G, c.B, 0)));
+ grad.Stops.Add (new Gradient.ColorStop (1, new Color (c.R, c.G, c.B, 1)));
+ break;
+ case ColorComponent.Hue:
+ grad.Stops.Add (new Gradient.ColorStop (0, new Color (1, 0, 0, 1)));
+ grad.Stops.Add (new Gradient.ColorStop (0.167, new Color (1, 1, 0, 1)));
+ grad.Stops.Add (new Gradient.ColorStop (0.333, new Color (0, 1, 0, 1)));
+ grad.Stops.Add (new Gradient.ColorStop (0.5, new Color (0, 1, 1, 1)));
+ grad.Stops.Add (new Gradient.ColorStop (0.667, new Color (0, 0, 1, 1)));
+ grad.Stops.Add (new Gradient.ColorStop (0.833, new Color (1, 0, 1, 1)));
+ grad.Stops.Add (new Gradient.ColorStop (1, new Color (1, 0, 0, 1)));
+ break;
+ case ColorComponent.Saturation:
+ grad.Stops.Add (new Gradient.ColorStop (0, Color.FromHSV (c.Hue, c.Value, 0.0, c.A)));
+ grad.Stops.Add (new Gradient.ColorStop (1, Color.FromHSV (c.Hue, c.Value, 1.0, c.A)));
+ break;
+ case ColorComponent.Value:
+ grad.Stops.Add (new Gradient.ColorStop (0, Color.FromHSV (c.Hue, 0.0, c.Saturation, c.A)));
+ grad.Stops.Add (new Gradient.ColorStop (1, Color.FromHSV (c.Hue, 1.0, c.Saturation, c.A)));
+ break;
+ }
+
+ grad.SetAsSource (gr, r);
+ CairoHelpers.CairoRectangle (gr, r, CornerRadius);
+ gr.Fill ();
+
+ r = ClientRectangle;
+
+ switch (cursorType) {
+ case CursorType.Rectangle:
+ if (Orientation == Orientation.Horizontal) {
+ r.Width = 5;
+ r.X = mousePos.X - 2.5;
+ } else {
+ r.Height = 5;
+ r.Y = mousePos.Y - 2.5;
+ }
+ CairoHelpers.CairoRectangle (gr, r, 1);
+ break;
+ case CursorType.Circle:
+ if (Orientation == Orientation.Horizontal)
+ gr.Arc (mousePos.X, r.Center.Y, 3.5, 0, Math.PI * 2.0);
+ else
+ gr.Arc (r.Center.X, mousePos.Y, 3.5, 0, Math.PI * 2.0);
+ break;
+ case CursorType.Pentagone:
+ if (Orientation == Orientation.Horizontal) {
+ r.Width = 5;
+ r.X = mousePos.X - 2.5;
+ double y = r.CenterD.Y - r.Height * 0.2;
+ gr.MoveTo (mousePos.X, y);
+ y += r.Height * 0.15;
+ gr.LineTo (r.Right, y);
+ gr.LineTo (r.Right, r.Bottom - 0.5);
+ gr.LineTo (r.Left, r.Bottom - 0.5);
+ gr.LineTo (r.Left, y);
+ gr.ClosePath ();
+ } else {
+ }
+ break;
+ }
+
+ gr.SetSourceColor (Color.Black);
+ gr.LineWidth = 2.0;
+ gr.StrokePreserve ();
+ gr.SetSourceColor (Color.White);
+ gr.LineWidth = 1.0;
+ gr.Stroke ();
+ }
+ public override void OnLayoutChanges (LayoutingType layoutType) {
+ base.OnLayoutChanges (layoutType);
+
+ if (Orientation == Orientation.Horizontal) {
+ if (layoutType == LayoutingType.Width)
+ mousePos.X = (int)Math.Floor (currentValue * ClientRectangle.Width);
+ } else if (layoutType == LayoutingType.Height)
+ mousePos.Y = (int)Math.Floor (currentValue * ClientRectangle.Height);
+ }
+
+ protected virtual void updateMouseLocalPos(Point mPos){
+ Rectangle r = ScreenCoordinates (Slot);
+ Rectangle cb = ClientRectangle;
+ mousePos = mPos - r.Position;
+
+ mousePos.X = Math.Max(cb.X, mousePos.X);
+ mousePos.X = Math.Min(cb.Right, mousePos.X);
+ mousePos.Y = Math.Max(cb.Y, mousePos.Y);
+ mousePos.Y = Math.Min(cb.Bottom, mousePos.Y);
+
+ if (Orientation == Orientation.Horizontal)
+ currentValue = (double)mousePos.X / ClientRectangle.Width;
+ else
+ currentValue = (double)mousePos.Y / ClientRectangle.Height;
+
+ NotifyValueChanged ("CurrentValue", $"{currentValue:0.000}");
+
+ Color c = currentColor;
+ switch (component) {
+ case ColorComponent.Red:
+ CurrentColor = new Color(currentValue, c.G, c.B, c.A);
+ break;
+ case ColorComponent.Green:
+ CurrentColor = new Color (c.R, currentValue, c.B, c.A);
+ break;
+ case ColorComponent.Blue:
+ CurrentColor = new Color (c.R, c.G, currentValue, c.A);
+ break;
+ case ColorComponent.Alpha:
+ CurrentColor = new Color (c.R, c.G, c.B, currentValue);
+ break;
+ case ColorComponent.Hue:
+ CurrentColor = Color.FromHSV (currentValue, c.Value, c.Saturation, c.A);
+ break;
+ case ColorComponent.Saturation:
+ CurrentColor = Color.FromHSV (c.Hue, c.Value, currentValue, c.A);
+ break;
+ case ColorComponent.Value:
+ CurrentColor = Color.FromHSV (c.Hue, currentValue, c.Saturation, c.A);
+ break;
+ }
+ }
+ }
+}
+
--- /dev/null
+//
+// ComboBox.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.Xml.Serialization;
+
+namespace Crow
+{
+ /// <summary>
+ /// templated control for selecting value in a pop up list
+ /// </summary>
+ public class ComboBox : ListBox
+ {
+ #region CTOR
+ protected ComboBox() : base(){}
+ public ComboBox (Interface iface) : base(iface){}
+ #endregion
+
+ Size minimumPopupSize = "10,10";
+ [XmlIgnore]public Size MinimumPopupSize{
+ get { return minimumPopupSize; }
+ set {
+ minimumPopupSize = value;
+ NotifyValueChanged ("MinimumPopupSize", minimumPopupSize);
+ }
+ }
+
+ public override void OnLayoutChanges (LayoutingType layoutType)
+ {
+ base.OnLayoutChanges (layoutType);
+
+ if (layoutType == LayoutingType.Width)
+ MinimumPopupSize = new Size (this.Slot.Width, minimumPopupSize.Height);
+ }
+ }
+}
--- /dev/null
+//
+// Container.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.Xml.Serialization;
+using System.Reflection;
+using System.ComponentModel;
+using System.Linq;
+using System.Threading;
+
+namespace Crow
+{
+ /// <summary>
+ /// simple container accepting one child
+ /// </summary>
+ public class Container : PrivateContainer
+ {
+ #if DESIGN_MODE
+ public override void getIML (System.Xml.XmlDocument doc, System.Xml.XmlNode parentElem)
+ {
+ if (this.design_isTGItem)
+ return;
+ base.getIML (doc, parentElem);
+ if (child == null)
+ return;
+ child.getIML (doc, parentElem.LastChild);
+ }
+ #endif
+
+ #region CTOR
+ protected Container() : base(){}
+ public Container (Interface iface) : base(iface){}
+ #endregion
+
+ [XmlIgnore]public Widget Child {
+ get { return child; }
+ set { base.SetChild(value); }
+ }
+ /// <summary>
+ /// override this to handle specific steps in child addition in derived class,
+ /// and don't forget to call the base.SetChild
+ /// </summary>
+ public new virtual void SetChild(Widget _child)
+ {
+ base.SetChild (_child);
+ }
+ }
+}
+
--- /dev/null
+//
+// DataSourceChangeEventArgs.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;
+
+namespace Crow
+{
+ public class DataSourceChangeEventArgs : EventArgs
+ {
+ public object OldDataSource;
+ public object NewDataSource;
+
+ public DataSourceChangeEventArgs (object oldDataSource, object newDataSource) : base()
+ {
+ OldDataSource = oldDataSource;
+ NewDataSource = newDataSource;
+ }
+ public override string ToString ()
+ {
+ return string.Format ("DSChangeEA: {0} => {1}", OldDataSource, NewDataSource);
+ }
+ }
+}
+
--- /dev/null
+//
+// DirectoryView.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.Xml.Serialization;
+using System.ComponentModel;
+using System.IO;
+using System.Collections.Generic;
+using System.Linq;
+
+namespace Crow
+{
+ /// <summary>
+ /// templated directory viewer
+ /// </summary>
+ public class DirectoryView : TemplatedControl
+ {
+ #region CTOR
+ protected DirectoryView() : base(){}
+ public DirectoryView (Interface iface) : base(iface){}
+ #endregion
+
+ #region events
+ public event EventHandler<SelectionChangeEventArgs> SelectedItemChanged;
+ #endregion
+
+ string currentDirectory = "/";
+ bool showFiles, showHidden;
+ string fileMask = "*.*";
+
+ object _selectedItem;
+ [XmlIgnore]public object SelectedItem {
+ get {
+ return _selectedItem;
+ }
+ set {
+ if (value == _selectedItem)
+ return;
+ _selectedItem = value;
+ NotifyValueChanged ("SelectedItem", _selectedItem);
+ }
+ }
+ [DefaultValue(true)]
+ public virtual bool ShowFiles {
+ get { return showFiles; }
+ set {
+ if (showFiles == value)
+ return;
+ showFiles = value;
+ NotifyValueChanged ("ShowFiles", showFiles);
+ NotifyValueChanged ("FileSystemEntries", FileSystemEntries);
+ }
+ }
+ [DefaultValue(false)]
+ public virtual bool ShowHidden {
+ get { return showHidden; }
+ set {
+ if (showHidden == value)
+ return;
+ showHidden = value;
+ NotifyValueChanged ("ShowHidden", showHidden);
+ NotifyValueChanged ("FileSystemEntries", FileSystemEntries);
+ }
+ }
+ [DefaultValue("*.*")]
+ public virtual string FileMask {
+ get { return fileMask; }
+ set {
+ if (fileMask == value)
+ return;
+ fileMask = value;
+ NotifyValueChanged ("FileMask", fileMask);
+ NotifyValueChanged ("FileSystemEntries", FileSystemEntries);
+ }
+ }
+ [DefaultValue("/")]
+ public virtual string CurrentDirectory {
+ get { return currentDirectory; }
+ set {
+ if (currentDirectory == value)
+ return;
+ currentDirectory = value;
+ NotifyValueChanged ("CurrentDirectory", currentDirectory);
+ NotifyValueChanged ("FileSystemEntries", FileSystemEntries);
+ }
+ }
+ [XmlIgnore]public FileSystemInfo[] FileSystemEntries {
+ get {
+ try {
+ if (string.IsNullOrEmpty(CurrentDirectory))
+ return null;
+ DirectoryInfo di = new DirectoryInfo(CurrentDirectory);
+ List<FileSystemInfo> fi = new List<FileSystemInfo> (di.GetDirectories());
+ if (showFiles && !string.IsNullOrEmpty(fileMask))
+ fi.AddRange(di.GetFiles(fileMask));
+ return showHidden ?
+ fi.ToArray() :
+ fi.Where(f=>!f.Attributes.HasFlag (FileAttributes.Hidden)).ToArray();
+ } catch (Exception ex) {
+ Console.WriteLine (ex.ToString ());
+ return null;
+ }
+ }
+ }
+ public void onSelectedItemChanged (object sender, SelectionChangeEventArgs e){
+ if (e.NewValue == SelectedItem)
+ return;
+ SelectedItem = e.NewValue;
+ SelectedItemChanged.Raise (this, e);
+ }
+ }
+}
+
--- /dev/null
+//
+// DockStack.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 Crow.IML;
+using System.Linq;
+using System.Text;
+using System.IO;
+
+namespace Crow
+{
+ [DesignIgnore]
+ public class DockStack : GenericStack
+ {
+ #region CTor
+ public DockStack () {}
+ public DockStack (Interface iface) : base (iface) {}
+ #endregion
+
+ /*static int color = 10;
+
+ protected override void onInitialized (object sender, EventArgs e)
+ {
+ base.onInitialized (sender, e);
+ Background = Color.ColorDic.Values.ToList()[color++];
+ }*/
+ public override void AddChild (Widget g)
+ {
+ base.AddChild (g);
+ if (localLogicalParentIsNull)
+ g.LogicalParent = this;
+ else
+ g.LogicalParent = this.LogicalParent;
+ }
+ public override void InsertChild (int idx, Widget g)
+ {
+ base.InsertChild (idx, g);
+ g.LogicalParent = this.LogicalParent;
+ }
+
+ public override bool PointIsIn (ref Point m)
+ {
+ if (!base.PointIsIn(ref m))
+ return false;
+
+ Group p = Parent as Group;
+ if (p != null) {
+ childrenRWLock.EnterReadLock ();
+ for (int i = p.Children.Count - 1; i >= 0; i--) {
+ if (p.Children [i] == this)
+ break;
+ if (p.Children [i].IsDragged)
+ continue;
+ if (p.Children [i].Slot.ContainsOrIsEqual (m)) {
+ childrenRWLock.ExitReadLock ();
+ return false;
+ }
+ }
+ childrenRWLock.ExitReadLock ();
+ }
+
+ return Slot.ContainsOrIsEqual(m);
+ }
+
+// public override void OnLayoutChanges (LayoutingType layoutType)
+// {
+// base.OnLayoutChanges (layoutType);
+//
+// if ((layoutType & LayoutingType.Sizing) > 0)
+// computeRects();
+// }
+
+ Rectangle rIn = default(Rectangle);
+ double dockThresh = 0.2;
+ Widget focusedChild;
+ internal Widget stretchedChild;
+
+ void getFocusedChild (Point lm) {
+ Rectangle cb = ClientRectangle;
+
+ childrenRWLock.EnterReadLock ();
+ foreach (Widget c in Children) {
+ Rectangle bounds = c.Slot + cb.Position;
+ if (!bounds.ContainsOrIsEqual (lm))
+ continue;
+ rIn = bounds;
+ focusedChild = c;
+ break;
+ }
+ childrenRWLock.ExitReadLock ();
+ }
+
+ public override void onMouseMove (object sender, MouseMoveEventArgs e)
+ {
+ if (IsDropTarget) {
+ DockWindow dw = IFace.DragAndDropOperation.DragSource as DockWindow;
+ if (dw == null || dw.IsDocked) {
+ base.onMouseMove (sender, e);
+ return;
+ }
+
+ Alignment curDockPos = dw.DockingPosition;
+ dw.DockingPosition = Alignment.Undefined;
+
+ Rectangle cb = ClientRectangle;
+ Point lm = ScreenPointToLocal (e.Position);
+
+ if (Children.Count == 0) {
+ Rectangle r = cb;
+ r.Inflate (r.Width / -5, r.Height / -5);
+ if (r.ContainsOrIsEqual(lm))
+ dw.DockingPosition = Alignment.Center;
+ } else {
+ rIn = cb;
+
+ if (Orientation == Orientation.Horizontal || Children.Count == 1) {
+ if (lm.Y > cb.Top + cb.Height / 3 && lm.Y < cb.Bottom - cb.Height / 3) {
+ if (lm.X < cb.Left + cb.Width / 3)
+ dw.DockingPosition = Alignment.Left;
+ else if (lm.X > cb.Right - cb.Width / 3)
+ dw.DockingPosition = Alignment.Right;
+ } else {
+ getFocusedChild (lm);
+ if (focusedChild != null) {
+ if (lm.Y < rIn.Top + rIn.Height / 3)
+ dw.DockingPosition = Alignment.Top;
+ else if (lm.Y > rIn.Bottom - rIn.Height / 3)
+ dw.DockingPosition = Alignment.Bottom;
+ }
+ }
+ }
+ if (Orientation == Orientation.Vertical || Children.Count == 1) {
+ if (lm.X > cb.Left + cb.Width / 3 && lm.X < cb.Right - cb.Width / 3) {
+ if (lm.Y < cb.Top + cb.Height / 3)
+ dw.DockingPosition = Alignment.Top;
+ else if (lm.Y > cb.Bottom - cb.Height / 3)
+ dw.DockingPosition = Alignment.Bottom;
+ } else {
+ getFocusedChild (lm);
+ if (focusedChild != null) {
+ if (lm.X < rIn.Left + rIn.Width / 3)
+ dw.DockingPosition = Alignment.Left;
+ else if (lm.X > rIn.Right - rIn.Width / 3)
+ dw.DockingPosition = Alignment.Right;
+ }
+ }
+ }
+ }
+
+ if (curDockPos != dw.DockingPosition)
+ RegisterForGraphicUpdate ();
+ }
+ base.onMouseMove (sender, e);
+ }
+
+ protected override void onDragEnter (object sender, DragDropEventArgs e)
+ {
+ base.onDragEnter (sender, e);
+ RegisterForGraphicUpdate ();
+ }
+ protected override void onDragLeave (object sender, DragDropEventArgs e)
+ {
+ DockWindow dw = e.DragSource as DockWindow;
+ //if (dw != null)
+ // dw.DockingPosition = Alignment.Undefined;
+ base.onDragLeave (sender, e);
+ RegisterForGraphicUpdate ();
+ }
+
+ protected override void onDraw (Cairo.Context gr)
+ {
+ gr.Save ();
+
+ Rectangle rBack = new Rectangle (Slot.Size);
+
+ Background.SetAsSource (gr, rBack);
+ CairoHelpers.CairoRectangle (gr, rBack, CornerRadius);
+ gr.Fill ();
+
+ if (ClipToClientRect) {
+ //clip to client zone
+ CairoHelpers.CairoRectangle (gr, ClientRectangle, CornerRadius);
+ gr.Clip ();
+ }
+
+ childrenRWLock.EnterReadLock ();
+
+ foreach (Widget g in Children)
+ g.Paint (ref gr);
+
+ childrenRWLock.ExitReadLock ();
+
+
+ if (!IsDropTarget) {
+ gr.Restore ();
+ return;
+ }
+
+ DockWindow dw = IFace.DragAndDropOperation.DragSource as DockWindow;
+ if (dw == null)
+ return;
+ if (!dw.IsDocked) {
+ Rectangle cb = ClientRectangle;
+ double minDim = Math.Min (cb.Width, cb.Height);
+
+ Rectangle r = rIn;
+ if (Children.Count <= 1 || dw.DockingPosition.GetOrientation()==Orientation )
+ r = cb;
+
+ switch (dw.DockingPosition) {
+ case Alignment.Top:
+ gr.Rectangle (r.Left, r.Top, r.Width, r.Height * dockThresh);
+ break;
+ case Alignment.Bottom:
+ gr.Rectangle (r.Left, r.Bottom - r.Height * dockThresh, r.Width, r.Height * dockThresh);
+ break;
+ case Alignment.Left:
+ gr.Rectangle (r.Left, r.Top, r.Width * dockThresh, r.Height);
+ break;
+ case Alignment.Right:
+ gr.Rectangle (r.Right - r.Width * dockThresh, r.Top, r.Width * dockThresh, r.Height);
+ break;
+ case Alignment.Center:
+ r.Inflate ((int)Math.Ceiling (Math.Min (r.Width, r.Height) * -0.05));
+ gr.Rectangle (r);
+ break;
+ }
+ gr.LineWidth = 1;
+ gr.SetSourceRGBA (0.4, 0.4, 0.9, 0.4);
+ gr.FillPreserve ();
+ gr.SetSourceRGBA (0.9, 0.9, 1.0, 0.8);
+ gr.Stroke ();
+ }
+ gr.Restore ();
+ }
+
+ public void Dock(DockWindow dw){
+ DockStack activeStack = this;
+
+ if (Children.Count == 1) {
+ Orientation = dw.DockingPosition.GetOrientation ();
+ if (Children [0] is DockWindow) {
+ (Children [0] as DockWindow).DockingPosition = dw.DockingPosition.GetOpposite ();
+ }
+ } else if (Children.Count > 0 && dw.DockingPosition.GetOrientation () != Orientation) {
+ activeStack = new DockStack (IFace);
+ activeStack.Orientation = dw.DockingPosition.GetOrientation ();
+ activeStack.Width = focusedChild.Width;
+ activeStack.Height = focusedChild.Height;
+ int idx = Children.IndexOf (focusedChild);
+ RemoveChild (focusedChild);
+ focusedChild.Height = Measure.Stretched;
+ focusedChild.Width = Measure.Stretched;
+ InsertChild (idx, activeStack);
+ activeStack.AddChild (focusedChild);
+ activeStack.stretchedChild = focusedChild;
+ if (focusedChild is DockWindow)
+ (focusedChild as DockWindow).DockingPosition = dw.DockingPosition.GetOpposite ();
+ focusedChild = null;
+ }
+
+ Rectangle r = ClientRectangle;
+ int vTreshold = (int)(r.Height * dockThresh);
+ int hTreshold = (int)(r.Width * dockThresh);
+
+ Console.WriteLine ("Docking {0} as {2} in {1}", dw.Name, activeStack.Name, dw.DockingPosition);
+ switch (dw.DockingPosition) {
+ case Alignment.Top:
+ dw.Height = vTreshold;
+ dw.Width = Measure.Stretched;
+ activeStack.InsertChild (0, dw);
+ activeStack.InsertChild (1, new Splitter(IFace));
+ break;
+ case Alignment.Bottom:
+ dw.Height = vTreshold;
+ dw.Width = Measure.Stretched;
+ activeStack.AddChild (new Splitter(IFace));
+ activeStack.AddChild (dw);
+ break;
+ case Alignment.Left:
+ dw.Width = hTreshold;
+ dw.Height = Measure.Stretched;
+ activeStack.InsertChild (0, dw);
+ activeStack.InsertChild (1, new Splitter(IFace));
+ break;
+ case Alignment.Right:
+ dw.Width = hTreshold;
+ dw.Height = Measure.Stretched;
+ activeStack.AddChild (new Splitter(IFace));
+ activeStack.AddChild (dw);
+ break;
+ case Alignment.Center:
+ dw.Width = dw.Height = Measure.Stretched;
+ AddChild (dw);
+ stretchedChild = dw;
+ break;
+ }
+ }
+ public void Undock (DockWindow dw){
+ int idx = Children.IndexOf(dw);
+
+ Console.WriteLine ("undocking child index: {0} ; name={1}; pos:{2} ; childcount:{3}",idx, dw.Name, dw.DockingPosition, Children.Count);
+
+ RemoveChild(dw);
+
+ if (Children.Count == 0)
+ return;
+
+ if (dw.DockingPosition == Alignment.Left || dw.DockingPosition == Alignment.Top) {
+ RemoveChild (idx);
+ if (stretchedChild == dw) {
+ stretchedChild = Children [idx];
+ stretchedChild.Width = stretchedChild.Height = Measure.Stretched;
+ }
+ } else {
+ RemoveChild (idx - 1);
+ if (stretchedChild == dw) {
+ stretchedChild = Children [idx-2];
+ stretchedChild.Width = stretchedChild.Height = Measure.Stretched;
+ }
+ }
+
+ if (Children.Count == 1) {
+ DockStack dsp = Parent as DockStack;
+ if (dsp == null) {
+ Children [0].Width = Children [0].Height = Measure.Stretched;
+ return;
+ }
+ //remove level and move remaining obj to level above
+ Widget g = Children [0];
+ RemoveChild (g);
+ idx = dsp.Children.IndexOf (this);
+ dsp.RemoveChild (this);
+ dsp.InsertChild (idx, g);
+ g.Width = this.Width;
+ g.Height = this.Height;
+ if (dsp.stretchedChild == this)
+ dsp.stretchedChild = g;
+ dsp.checkAlignments ();
+ } else
+ checkAlignments ();
+ }
+
+ internal void checkAlignments () {
+ DockWindow dw = Children[0] as DockWindow;
+ if (dw != null)
+ dw.DockingPosition = (Orientation == Orientation.Horizontal ? Alignment.Left : Alignment.Top);
+ dw = Children[Children.Count - 1] as DockWindow;
+ if (dw != null)
+ dw.DockingPosition = (Orientation == Orientation.Horizontal ? Alignment.Right : Alignment.Bottom);
+ }
+
+ //read next value in config string until next ';'
+ string getConfAttrib (string conf, ref int i) {
+ int nextI = conf.Substring (i).IndexOf (';');
+ string tmp = conf.Substring (i, nextI);
+ i += nextI + 1;
+ return tmp;
+ }
+ /// <summary>
+ /// Imports the config.
+ /// </summary>
+ /// <param name="conf">Conf.</param>
+ /// <param name="dataSource">Data source for the docked windows</param>
+ public void ImportConfig (string conf, object dataSource = null) {
+ lock (IFace.UpdateMutex) {
+ ClearChildren ();
+ stretchedChild = null;
+ int i = 0;
+ Orientation = (Orientation)Enum.Parse (typeof(Orientation), getConfAttrib (conf, ref i));
+ importConfig (conf, ref i, dataSource);
+ }
+ }
+ public string ExportConfig () {
+ return Orientation.ToString() + ";" + exportConfig();
+ }
+ void importConfig (string conf, ref int i, object dataSource) {
+ if (conf [i++] != '(')
+ return;
+ while (i < conf.Length - 4) {
+ string sc = conf.Substring (i, 4);
+ i += 4;
+ switch (sc) {
+ case "WIN;":
+ DockWindow dw = null;
+ string wName = getConfAttrib (conf, ref i);
+ try {
+ dw = IFace.CreateInstance (wName) as DockWindow;
+ } catch {
+ dw = new DockWindow (IFace);
+ }
+
+ dw.Name = wName;
+ dw.Width = Measure.Parse (getConfAttrib (conf, ref i));
+ dw.Height = Measure.Parse (getConfAttrib (conf, ref i));
+ dw.DockingPosition = (Alignment)Enum.Parse (typeof(Alignment), getConfAttrib (conf, ref i));
+ dw.savedSlot = Rectangle.Parse (getConfAttrib (conf, ref i));
+ dw.wasResizable = Boolean.Parse (getConfAttrib (conf, ref i));
+
+ dw.IsDocked = true;
+ dw.DataSource = dataSource;
+ this.AddChild (dw);
+
+ break;
+ case "STK;":
+ DockStack ds = new DockStack (IFace);
+ ds.Width = Measure.Parse (getConfAttrib (conf, ref i));
+ ds.Height = Measure.Parse (getConfAttrib (conf, ref i));
+ ds.Orientation = (Orientation)Enum.Parse (typeof(Orientation), getConfAttrib (conf, ref i));
+
+ this.AddChild (ds);
+
+ ds.importConfig (conf, ref i, dataSource);
+ break;
+ case "SPL;":
+ Splitter sp = new Splitter (IFace);
+ sp.Width = Measure.Parse (getConfAttrib (conf, ref i));
+ sp.Height = Measure.Parse (getConfAttrib (conf, ref i));
+ sp.Thickness = int.Parse (getConfAttrib (conf, ref i));
+ this.AddChild (sp);
+ break;
+ }
+ char nextC = conf [i++];
+ if (nextC == ')')
+ break;
+ }
+ }
+ string exportConfig () {
+ StringBuilder tmp = new StringBuilder("(");
+
+ for (int i = 0; i < Children.Count; i++) {
+ if (Children [i] is DockWindow) {
+ DockWindow dw = Children [i] as DockWindow;
+ tmp.Append (string.Format("WIN;{0};{1};{2};{3};{4};{5};",dw.Name, dw.Width, dw.Height, dw.DockingPosition, dw.savedSlot, dw.wasResizable));
+ } else if (Children [i] is DockStack) {
+ DockStack ds = Children [i] as DockStack;
+ tmp.Append (string.Format("STK;{0};{1};{2};{3}", ds.Width, ds.Height, ds.Orientation, ds.exportConfig()));
+ } else if (Children [i] is Splitter) {
+ Splitter sp = Children [i] as Splitter;
+ tmp.Append (string.Format("SPL;{0};{1};{2};", sp.Width, sp.Height, sp.Thickness));
+ }
+ if (i < Children.Count - 1)
+ tmp.Append ("|");
+ }
+
+ tmp.Append (")");
+ return tmp.ToString ();
+ }
+ }
+}
+
--- /dev/null
+//
+// DockingView.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.Xml.Serialization;
+
+namespace Crow
+{
+ public class DockWindow : Window
+ {
+ #region CTOR
+ public DockWindow () {}
+ public DockWindow (Interface iface) : base (iface) {}
+ #endregion
+
+ int undockThreshold = 10;
+ bool isDocked = false;
+ Alignment docking = Alignment.Undefined;
+
+ Point undockingMousePosOrig; //mouse pos when docking was donne, use for undocking on mouse move
+ internal Rectangle savedSlot; //last undocked slot recalled when view is undocked
+ internal bool wasResizable;
+
+ public bool IsDocked {
+ get { return isDocked; }
+ set {
+ if (isDocked == value)
+ return;
+ isDocked = value;
+ NotifyValueChanged ("IsDocked", isDocked);
+ NotifyValueChanged ("IsFloating", !isDocked);
+ }
+ }
+ [XmlIgnore] public bool IsFloating { get { return !isDocked; }}
+
+ public Alignment DockingPosition {
+ get { return docking; }
+ set {
+ if (docking == value)
+ return;
+ docking = value;
+ NotifyValueChanged ("DockingPosition", DockingPosition);
+ }
+ }
+ public override bool PointIsIn (ref Point m)
+ {
+ if (!base.PointIsIn(ref m))
+ return false;
+
+ Group p = Parent as Group;
+ if (p != null) {
+ lock (p.Children) {
+ for (int i = p.Children.Count - 1; i >= 0; i--) {
+ if (p.Children [i] == this)
+ break;
+ if (p.Children [i].IsDragged)
+ continue;
+ if (p.Children [i].Slot.ContainsOrIsEqual (m)) {
+ return false;
+ }
+ }
+ }
+ }
+ return Slot.ContainsOrIsEqual(m);
+ }
+
+ public override void onMouseMove (object sender, MouseMoveEventArgs e)
+ {
+// if (this.HasFocus && e.Mouse.IsButtonDown (MouseButton.Left) && IsDocked) {
+// if (Math.Abs (e.Position.X - undockingMousePosOrig.X) > 10 ||
+// Math.Abs (e.Position.X - undockingMousePosOrig.X) > 10)
+// Undock ();
+// }
+
+ if (this.HasFocus && e.Mouse.IsButtonDown (MouseButton.Left) && IsDocked)
+ CheckUndock (e.Position);
+
+ base.onMouseMove (sender, e);
+ }
+ public override void onMouseDown (object sender, MouseButtonEventArgs e)
+ {
+ e.Handled = true;
+ base.onMouseDown (sender, e);
+
+ if (this.HasFocus && IsDocked && e.Button == MouseButton.Left)
+ undockingMousePosOrig = e.Position;
+ }
+ public bool CheckUndock (Point mousePos) {
+ //if (DockingPosition == Alignment.Center)
+ // return false;
+ Console.WriteLine ($"{mousePos.X},{mousePos.Y}");
+ if (Math.Abs (mousePos.X - undockingMousePosOrig.X) < undockThreshold ||
+ Math.Abs (mousePos.X - undockingMousePosOrig.X) < undockThreshold)
+ return false;
+ Undock ();
+ return true;
+ }
+
+ protected override void onStartDrag (object sender, DragDropEventArgs e)
+ {
+ base.onStartDrag (sender, e);
+
+ undockingMousePosOrig = IFace.Mouse.Position;
+ }
+ protected override void onDrop (object sender, DragDropEventArgs e)
+ {
+ if (!isDocked && DockingPosition != Alignment.Undefined && e.DropTarget is DockStack)
+ Dock (e.DropTarget as DockStack);
+ base.onDrop (sender, e);
+ }
+ public void Undock () {
+ lock (IFace.UpdateMutex) {
+ DockStack ds = Parent as DockStack;
+ ds.Undock (this);
+
+ IFace.AddWidget (this);
+
+ Left = savedSlot.Left;
+ Top = savedSlot.Top;
+ Width = savedSlot.Width;
+ Height = savedSlot.Height;
+
+ IsDocked = false;
+ DockingPosition = Alignment.Undefined;
+ Resizable = wasResizable;
+ }
+ }
+
+ public void Dock (DockStack target){
+ lock (IFace.UpdateMutex) {
+ IsDocked = true;
+ //undockingMousePosOrig = lastMousePos;
+ savedSlot = this.LastPaintedSlot;
+ wasResizable = Resizable;
+ Resizable = false;
+ LastSlots = LastPaintedSlot = Slot = default(Rectangle);
+ Left = Top = 0;
+
+ IFace.RemoveWidget (this);
+
+ target.Dock (this);
+ }
+ }
+
+ protected override void close ()
+ {
+ if (isDocked)
+ Undock ();
+ base.close ();
+ }
+ }
+}
+
--- /dev/null
+// Copyright (c) 2019 Bruyère Jean-Philippe jp_bruyere@hotmail.com
+//
+// This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT)
+
+using System;
+using System.ComponentModel;
+
+namespace Crow
+{
+ /// <summary>
+ /// Convenient widget for selecting value from enum
+ /// </summary>
+ public class EnumSelector : GenericStack
+ {
+ #region CTOR
+ protected EnumSelector () : base(){}
+ public EnumSelector (Interface iface) : base(iface){}
+ #endregion
+
+ #region private fields
+ Enum enumValue;
+ Type enumType;
+ #endregion
+
+ #region public properties
+ /// <summary>
+ /// use to define the colors of the 3d border
+ /// </summary>
+ [DefaultValue(null)]
+ public virtual Enum EnumValue {
+ get { return enumValue; }
+ set {
+ if (enumValue == value)
+ return;
+
+ enumValue = value;
+
+ if (enumValue != null) {
+ if (enumType != enumValue.GetType ()) {
+ ClearChildren ();
+ enumType = enumValue.GetType ();
+ foreach (string en in enumType.GetEnumNames ()) {
+ RadioButton rb = new RadioButton (IFace);
+ rb.Caption = en;
+ if (enumValue.ToString() == en)
+ rb.IsChecked = true;
+ rb.Checked += (sender, e) => (((RadioButton)sender).Parent as EnumSelector).EnumValue = (Enum)Enum.Parse (enumType, (sender as RadioButton).Caption);
+ AddChild (rb);
+ RegisterForLayouting (LayoutingType.All);
+ }
+ }
+ } else
+ ClearChildren ();
+
+ NotifyValueChanged ("EnumValue", enumValue);
+ RegisterForRedraw ();
+ }
+ }
+ #endregion
+
+ }
+}
+
--- /dev/null
+//
+// Expandable.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.ComponentModel;
+using System.Xml.Serialization;
+
+namespace Crow
+{
+ /// <summary>
+ /// templated control whose content can be hidden and shown on demand
+ /// </summary>
+ public class Expandable : TemplatedContainer
+ {
+ #region CTOR
+ protected Expandable() : base(){}
+ public Expandable (Interface iface) : base(iface){}
+ #endregion
+
+ #region Private fields
+ bool _isExpanded;
+ string image;
+ #endregion
+
+ #region Event Handlers
+ /// <summary>
+ /// Occurs when control is expanded.
+ /// </summary>
+ public event EventHandler Expand;
+ /// <summary>
+ /// Occurs when control is collapsed.
+ /// </summary>
+ public event EventHandler Collapse;
+ #endregion
+
+ public BooleanTestOnInstance GetIsExpandable;
+
+ /// <summary>
+ /// mouse click event handler for easy expand triggering in IML
+ /// </summary>
+ public void onClickForExpand (object sender, MouseButtonEventArgs e)
+ {
+ IsExpanded = !IsExpanded;
+ }
+
+ #region Public properties
+ [DefaultValue("#Crow.Icons.expandable.svg")]
+ public string Image {
+ get { return image; }
+ set {
+ if (image == value)
+ return;
+ image = value;
+ NotifyValueChanged ("Image", image);
+ }
+ }
+ [DefaultValue(false)]
+ public bool IsExpanded
+ {
+ get { return _isExpanded; }
+ set
+ {
+ if (value == _isExpanded)
+ return;
+
+ _isExpanded = value;
+
+ bool isExp = IsExpandable;
+ NotifyValueChanged ("IsExpandable", isExp);
+ if (!isExp)
+ _isExpanded = false;
+
+ NotifyValueChanged ("IsExpanded", _isExpanded);
+
+ if (_isExpanded)
+ onExpand (this, null);
+ else
+ onCollapse (this, null);
+ }
+ }
+ [XmlIgnore]public bool IsExpandable {
+ get {
+ try {
+ return GetIsExpandable == null ? true : GetIsExpandable (this);
+ } catch (Exception ex) {
+ System.Diagnostics.Debug.WriteLine ("Not Expandable error: " + ex.ToString ());
+ return false;
+ }
+ }
+ }
+ #endregion
+
+ public virtual void onExpand(object sender, EventArgs e)
+ {
+ if (_contentContainer != null)
+ _contentContainer.Visible = true;
+
+ Expand.Raise (this, e);
+ }
+ public virtual void onCollapse(object sender, EventArgs e)
+ {
+ if (_contentContainer != null)
+ _contentContainer.Visible = false;
+
+ Collapse.Raise (this, e);
+ }
+ }
+}
--- /dev/null
+//
+// FileDialog.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.Xml.Serialization;
+using System.ComponentModel;
+using System.IO;
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.Linq;
+using System.Text.RegularExpressions;
+
+namespace Crow
+{
+ /// <summary>
+ /// templated control for selecting files
+ /// </summary>
+ public class FileDialog: Window
+ {
+ #region CTOR
+ protected FileDialog() : base(){}
+ public FileDialog (Interface iface) : base(iface){}
+ #endregion
+
+ string searchPattern, curDir, _selectedFile, _selectedDir;
+ bool showHidden, showFiles;
+
+ #region events
+ public event EventHandler OkClicked;
+ #endregion
+
+ public string SelectedFileFullPath {
+ get { return Path.Combine (SelectedDirectory, SelectedFile); }
+ }
+ [DefaultValue("/home")]
+ public virtual string CurrentDirectory {
+ get { return curDir; }
+ set {
+ if (curDir == value)
+ return;
+ curDir = value;
+ NotifyValueChanged ("CurrentDirectory", curDir);
+ SelectedDirectory = curDir;
+ }
+ }
+
+ [DefaultValue("*")]
+ public virtual string SearchPattern {
+ get { return searchPattern; }
+ set {
+ if (searchPattern == value)
+ return;
+ searchPattern = value;
+ NotifyValueChanged ("SearchPattern", searchPattern);
+
+ }
+ }
+ [DefaultValue(false)]
+ public virtual bool ShowHidden {
+ get { return showHidden; }
+ set {
+ if (showHidden == value)
+ return;
+ showHidden = value;
+ NotifyValueChanged ("ShowHidden", showHidden);
+ }
+ }
+ [DefaultValue(true)]
+ public virtual bool ShowFiles {
+ get { return showFiles; }
+ set {
+ if (showFiles == value)
+ return;
+ showFiles = value;
+ NotifyValueChanged ("ShowFiles", showFiles);
+ }
+ }
+ public string SelectedFile {
+ get { return _selectedFile; }
+ set {
+ if (value == _selectedFile)
+ return;
+ _selectedFile = value;
+ NotifyValueChanged ("SelectedFile", _selectedFile);
+ }
+ }
+ public string SelectedDirectory {
+ get { return _selectedDir; }
+ set {
+ if (value == _selectedDir)
+ return;
+ _selectedDir = value;
+ NotifyValueChanged ("SelectedDirectory", _selectedDir);
+ }
+ }
+
+ public void onFVSelectedItemChanged (object sender, SelectionChangeEventArgs e){
+ if (e.NewValue != null) {
+ if (File.GetAttributes (e.NewValue.ToString ()).HasFlag (FileAttributes.Directory)) {
+ SelectedDirectory = e.NewValue.ToString ();
+ SelectedFile = "";
+ } else {
+ SelectedDirectory = Path.GetDirectoryName (e.NewValue.ToString ());
+ SelectedFile = Path.GetFileName (e.NewValue.ToString ());
+ }
+ }
+ }
+ public void onDVSelectedItemChanged (object sender, SelectionChangeEventArgs e){
+ if (e.NewValue != null)
+ SelectedDirectory = e.NewValue.ToString();
+ }
+ public void goUpDirClick (object sender, MouseButtonEventArgs e){
+ string root = Directory.GetDirectoryRoot(CurrentDirectory);
+ if (CurrentDirectory == root)
+ return;
+ CurrentDirectory = Directory.GetParent(CurrentDirectory).FullName;
+ }
+ void onFileSelect(object sender, MouseButtonEventArgs e){
+ if (string.IsNullOrEmpty (SelectedFile))
+ CurrentDirectory = SelectedDirectory;
+ else {
+ OkClicked.Raise (this, null);
+ IFace.DeleteWidget (this);
+ }
+ }
+ void onCancel(object sender, MouseButtonEventArgs e){
+ IFace.DeleteWidget (this);
+ }
+
+ }
+}
+
--- /dev/null
+//
+// GenericStack.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.ComponentModel;
+using System.Diagnostics;
+using System.Xml.Serialization;
+using System;
+using System.Linq;
+
+namespace Crow
+{
+ /// <summary>
+ /// group container that stacked its children horizontally or vertically
+ /// </summary>
+ public class GenericStack : Group
+ {
+ #region CTOR
+ protected GenericStack() : base(){}
+ public GenericStack(Interface iface) : base(iface){}
+ #endregion
+
+ #region Private fields
+ int _spacing;
+ Orientation _orientation;
+ #endregion
+
+ #region Public Properties
+ [DefaultValue(2)]
+ public int Spacing
+ {
+ get { return _spacing; }
+ set {
+ if (_spacing == value)
+ return;
+ _spacing = value;
+ NotifyValueChanged ("Spacing", Spacing);
+ RegisterForLayouting (LayoutingType.Sizing|LayoutingType.ArrangeChildren);
+ }
+ }
+ [DefaultValue(Orientation.Horizontal)]
+ public virtual Orientation Orientation
+ {
+ get { return _orientation; }
+ set { _orientation = value; }
+ }
+ #endregion
+
+ #region GraphicObject Overrides
+ public override bool ArrangeChildren { get { return true; } }
+ public override void ChildrenLayoutingConstraints (ref LayoutingType layoutType)
+ {
+ //Prevent child repositionning in the direction of stacking
+ if (Orientation == Orientation.Horizontal)
+ layoutType &= (~LayoutingType.X);
+ else
+ layoutType &= (~LayoutingType.Y);
+ }
+ protected override int measureRawSize (LayoutingType lt)
+ {
+ int totSpace = Math.Max(0, Spacing * (Children.Count (c => c.Visible) - 1));
+ if (lt == LayoutingType.Width) {
+ if (Orientation == Orientation.Horizontal)
+ return contentSize.Width + totSpace + 2 * Margin;
+ }else if (Orientation == Orientation.Vertical)
+ return contentSize.Height + totSpace + 2 * Margin;
+
+ return base.measureRawSize (lt);
+ }
+ public virtual void ComputeChildrenPositions()
+ {
+ int d = 0;
+ if (Orientation == Orientation.Horizontal) {
+ foreach (Widget c in Children) {
+ if (!c.Visible)
+ continue;
+ c.Slot.X = d;
+ d += c.Slot.Width + Spacing;
+ }
+ } else {
+ foreach (Widget c in Children) {
+ if (!c.Visible)
+ continue;
+ c.Slot.Y = d;
+ d += c.Slot.Height + Spacing;
+ }
+ }
+ IsDirty = true;
+ }
+ Widget stretchedGO = null;
+ public override bool UpdateLayout (LayoutingType layoutType)
+ {
+ RegisteredLayoutings &= (~layoutType);
+
+ if (layoutType == LayoutingType.ArrangeChildren) {
+ //allow 1 child to have size to 0 if stack has fixed or streched size policy,
+ //this child will occupy remaining space
+ //if stack size policy is Fit, no child may have stretch enabled
+ //in the direction of stacking.
+ ComputeChildrenPositions ();
+
+ //if no layouting remains in queue for item, registre for redraw
+ if (RegisteredLayoutings == LayoutingType.None && IsDirty)
+ IFace.EnqueueForRepaint (this);
+
+ return true;
+ }
+
+ return base.UpdateLayout(layoutType);
+ }
+
+ void adjustStretchedGo (LayoutingType lt){
+ if (stretchedGO == null)
+ return;
+ if (lt == LayoutingType.Width) {
+ int newW = Math.Max (
+ this.ClientRectangle.Width - contentSize.Width - Spacing * (Children.Count - 1),
+ stretchedGO.MinimumSize.Width);
+ if (stretchedGO.MaximumSize.Width > 0)
+ newW = Math.Min (newW, stretchedGO.MaximumSize.Width);
+ if (newW != stretchedGO.Slot.Width) {
+ stretchedGO.Slot.Width = newW;
+ stretchedGO.IsDirty = true;
+ #if DEBUG_LAYOUTING
+ Debug.WriteLine ("\tAdjusting Width of " + stretchedGO.ToString());
+ #endif
+ stretchedGO.LayoutChanged -= OnChildLayoutChanges;
+ stretchedGO.OnLayoutChanges (LayoutingType.Width);
+ stretchedGO.LayoutChanged += OnChildLayoutChanges;
+ stretchedGO.LastSlots.Width = stretchedGO.Slot.Width;
+ }
+ } else {
+ int newH = Math.Max (
+ this.ClientRectangle.Height - contentSize.Height - Spacing * (Children.Count - 1),
+ stretchedGO.MinimumSize.Height);
+ if (stretchedGO.MaximumSize.Height > 0)
+ newH = Math.Min (newH, stretchedGO.MaximumSize.Height);
+ if (newH != stretchedGO.Slot.Height) {
+ stretchedGO.Slot.Height = newH;
+ stretchedGO.IsDirty = true;
+ #if DEBUG_LAYOUTING
+ Debug.WriteLine ("\tAdjusting Height of " + stretchedGO.ToString());
+ #endif
+ stretchedGO.LayoutChanged -= OnChildLayoutChanges;
+ stretchedGO.OnLayoutChanges (LayoutingType.Height);
+ stretchedGO.LayoutChanged += OnChildLayoutChanges;
+ stretchedGO.LastSlots.Height = stretchedGO.Slot.Height;
+ }
+ }
+ }
+
+ public override void OnChildLayoutChanges (object sender, LayoutingEventArgs arg)
+ {
+ Widget go = sender as Widget;
+ //Debug.WriteLine ("child layout change: " + go.LastSlots.ToString() + " => " + go.Slot.ToString());
+ switch (arg.LayoutType) {
+ case LayoutingType.Width:
+ if (Orientation == Orientation.Horizontal) {
+ if (go.Width == Measure.Stretched) {
+ if (stretchedGO == null && Width != Measure.Fit)
+ stretchedGO = go;
+ else if (stretchedGO != go) {
+ go.Slot.Width = 0;
+ go.Width = Measure.Fit;
+ return;
+ }
+ } else
+ contentSize.Width += go.Slot.Width - go.LastSlots.Width;
+
+ adjustStretchedGo (LayoutingType.Width);
+
+ if (Width == Measure.Fit)
+ this.RegisterForLayouting (LayoutingType.Width);
+
+ this.RegisterForLayouting (LayoutingType.ArrangeChildren);
+ return;
+ }
+ break;
+ case LayoutingType.Height:
+ if (Orientation == Orientation.Vertical) {
+ if (go.Height == Measure.Stretched) {
+ if (stretchedGO == null && Height != Measure.Fit)
+ stretchedGO = go;
+ else if (stretchedGO != go){
+ go.Slot.Height = 0;
+ go.Height = Measure.Fit;
+ return;
+ }
+ } else
+ contentSize.Height += go.Slot.Height - go.LastSlots.Height;
+
+ adjustStretchedGo (LayoutingType.Height);
+
+ if (Height == Measure.Fit)
+ this.RegisterForLayouting (LayoutingType.Height);
+
+ this.RegisterForLayouting (LayoutingType.ArrangeChildren);
+ return;
+ }
+ break;
+ }
+ base.OnChildLayoutChanges (sender, arg);
+ }
+ #endregion
+
+ public override void RemoveChild (Widget child)
+ {
+ if (child != stretchedGO) {
+ if (Orientation == Orientation.Horizontal)
+ contentSize.Width -= child.LastSlots.Width;
+ else
+ contentSize.Height -= child.LastSlots.Height;
+ }
+ base.RemoveChild (child);
+ if (child == stretchedGO) {
+ stretchedGO = null;
+ RegisterForLayouting (LayoutingType.Sizing);
+ }else if (Orientation == Orientation.Horizontal)
+ adjustStretchedGo (LayoutingType.Width);
+ else
+ adjustStretchedGo (LayoutingType.Height);
+ }
+
+ public override void ClearChildren ()
+ {
+ base.ClearChildren ();
+ stretchedGO = null;
+ }
+ }
+}
--- /dev/null
+//
+// GraduatedSlider.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.Linq;
+using System.Text;
+using Crow.Cairo;
+using System.Xml.Serialization;
+
+namespace Crow
+{
+ [DesignIgnore]
+ public class GraduatedSlider : Slider
+ {
+ #region CTOR
+ protected GraduatedSlider() : base(){}
+ public GraduatedSlider(Interface iface) : base(iface)
+ {}
+// public GraduatedSlider(double minimum, double maximum, double step)
+// : base()
+// {
+// Minimum = minimum;
+// Maximum = maximum;
+// SmallIncrement = step;
+// LargeIncrement = step * 5;
+// }
+ #endregion
+
+ protected override void DrawGraduations(Context gr, PointD pStart, PointD pEnd)
+ {
+ Rectangle r = ClientRectangle;
+ Foreground.SetAsSource (gr);
+
+ gr.LineWidth = 2;
+ gr.MoveTo(pStart);
+ gr.LineTo(pEnd);
+
+ gr.Stroke();
+ gr.LineWidth = 1;
+
+ double sst = unity * SmallIncrement;
+ double bst = unity * LargeIncrement;
+
+
+ PointD vBar = new PointD(0, sst);
+ for (double x = Minimum; x <= Maximum - Minimum; x += SmallIncrement)
+ {
+ double lineLength = r.Height / 3;
+ if (x % LargeIncrement != 0)
+ lineLength /= 3;
+ PointD p = new PointD(pStart.X + x * unity, pStart.Y);
+ gr.MoveTo(p);
+ gr.LineTo(new PointD(p.X, p.Y + lineLength));
+ }
+ gr.Stroke();
+ }
+ }
+}
--- /dev/null
+//
+// Grid.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.Diagnostics;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Xml.Serialization;
+using System.ComponentModel;
+
+namespace Crow
+{
+ /// <summary>
+ /// Simple grid container
+ /// Allow symetric placement of children on a grid,
+ /// excedental child (above grid sizing) are ignored
+ /// and invisible child keep their place in the grid
+ /// </summary>
+ public class Grid : Group
+ {
+ #region CTOR
+ protected Grid () : base(){}
+ public Grid(Interface iface) : base(iface)
+ {
+ }
+ #endregion
+
+ #region Private fields
+ int _spacing;
+ int _columnCount;
+ int _rowCount;
+ #endregion
+
+ #region Public Properties
+ [DefaultValue(2)]
+ public int Spacing
+ {
+ get { return _spacing; }
+ set { _spacing = value; }
+ }
+ [DefaultValue(2)]
+ public virtual int ColumnCount
+ {
+ get { return _columnCount; }
+ set {
+ if (_columnCount == value)
+ return;
+
+ _columnCount = value;
+
+ NotifyValueChanged ("ColumnCount", ColumnCount);
+ this.RegisterForLayouting (LayoutingType.ArrangeChildren);
+ }
+ }
+ [DefaultValue(2)]
+ public virtual int RowCount
+ {
+ get { return _rowCount; }
+ set {
+ if (_rowCount == value)
+ return;
+
+ _rowCount = value;
+
+ NotifyValueChanged ("RowCount", RowCount);
+ this.RegisterForLayouting (LayoutingType.ArrangeChildren);
+ }
+ }
+ public virtual int CaseWidth {
+ get { return (Slot.Width - (ColumnCount - 1) * Spacing) / ColumnCount; }
+ }
+ public virtual int CaseHeight {
+ get { return (Slot.Height - (RowCount - 1) * Spacing) / RowCount; }
+ }
+
+ #endregion
+
+ #region GraphicObject Overrides
+// protected override Size measureRawSize ()
+// {
+// Size tmp = new Size ();
+//
+// foreach (GraphicObject c in Children.Where(ch=>ch.Visible)) {
+// tmp.Width = Math.Max (tmp.Width, c.Slot.Width);
+// tmp.Height = Math.Max (tmp.Height, c.Slot.Height);
+// }
+//
+// tmp.Width *= (ColumnCount - 1) * Spacing / ColumnCount;;
+// tmp.Height *= (RowCount - 1) * Spacing / RowCount;
+// tmp.Width += 2 * Margin;
+// tmp.Height += 2 * Margin;
+//
+// return tmp;
+// }
+ public override void ChildrenLayoutingConstraints (ref LayoutingType layoutType)
+ {
+ //Prevent child repositionning
+ layoutType &= (~LayoutingType.Positioning);
+ }
+ public override bool ArrangeChildren { get { return true; } }
+ public virtual void ComputeChildrenPositions()
+ {
+ int slotWidth = CaseWidth;
+ int slotHeight = CaseHeight;
+ for (int curY = 0; curY < RowCount; curY++) {
+ for (int curX = 0; curX < ColumnCount; curX++) {
+ int idx = curY * ColumnCount + curX;
+ if (idx >= Children.Count)
+ return;
+ Widget c = Children [idx];
+ if (!c.Visible)
+ continue;
+ c.Slot.X = curX * (slotWidth + Spacing);
+ c.Slot.Y = curY * (slotHeight + Spacing);
+ //c.Slot.Width = slotWidth;
+ //c.Slot.Height = slotHeight;
+ }
+ }
+ IsDirty = true;
+ }
+ public override void OnChildLayoutChanges (object sender, LayoutingEventArgs arg)
+ {
+ //base.OnChildLayoutChanges (sender, arg);
+ }
+
+ public override bool UpdateLayout (LayoutingType layoutType)
+ {
+ RegisteredLayoutings &= (~layoutType);
+
+ if (layoutType == LayoutingType.ArrangeChildren) {
+
+ ComputeChildrenPositions ();
+
+ //if no layouting remains in queue for item, registre for redraw
+ if (RegisteredLayoutings == LayoutingType.None && IsDirty)
+ IFace.EnqueueForRepaint (this);
+
+ return true;
+ }
+
+ return base.UpdateLayout(layoutType);
+ }
+ #endregion
+
+
+ }
+}
--- /dev/null
+//
+// Group.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 Crow.Cairo;
+using System.Diagnostics;
+using System.Reflection;
+using System.Threading;
+
+
+namespace Crow
+{
+ public class Group : Widget
+ {
+ #if DESIGN_MODE
+ public override bool FindByDesignID(string designID, out Widget go){
+ go = null;
+ if (base.FindByDesignID (designID, out go))
+ return true;
+ childrenRWLock.EnterReadLock ();
+ foreach (Widget w in Children) {
+ if (!w.FindByDesignID (designID, out go))
+ continue;
+ childrenRWLock.ExitReadLock ();
+ return true;
+ }
+ childrenRWLock.ExitReadLock ();
+ return false;
+ }
+ public override void getIML (System.Xml.XmlDocument doc, System.Xml.XmlNode parentElem)
+ {
+ if (this.design_isTGItem)
+ return;
+ base.getIML (doc, parentElem);
+ foreach (Widget g in Children) {
+ g.getIML (doc, parentElem.LastChild);
+ }
+ }
+ #endif
+
+ protected ReaderWriterLockSlim childrenRWLock = new ReaderWriterLockSlim(LockRecursionPolicy.SupportsRecursion);
+
+ #region CTOR
+ public Group () : base() {}
+ public Group(Interface iface) : base(iface){}
+ #endregion
+
+ #region EVENT HANDLERS
+ public event EventHandler<EventArgs> ChildrenCleared;
+ #endregion
+
+ internal Widget largestChild = null;
+ internal Widget tallestChild = null;
+
+ bool _multiSelect = false;
+ List<Widget> children = new List<Widget>();
+
+ public virtual List<Widget> Children {
+ get { return children; }
+ }
+ [DefaultValue(false)]
+ public bool MultiSelect
+ {
+ get { return _multiSelect; }
+ set { _multiSelect = value; }
+ }
+ public virtual void AddChild(Widget g){
+ childrenRWLock.EnterWriteLock();
+
+ g.Parent = this;
+ Children.Add (g);
+
+ childrenRWLock.ExitWriteLock();
+
+ g.RegisteredLayoutings = LayoutingType.None;
+ g.LayoutChanged += OnChildLayoutChanges;
+ g.RegisterForLayouting (LayoutingType.Sizing | LayoutingType.ArrangeChildren);
+ }
+ public virtual void RemoveChild(Widget child)
+ {
+ child.LayoutChanged -= OnChildLayoutChanges;
+ //check if HoverWidget is removed from Tree
+ if (IFace.HoverWidget != null) {
+ if (this.Contains (IFace.HoverWidget))
+ IFace.HoverWidget = null;
+ }
+
+ childrenRWLock.EnterWriteLock ();
+
+ Children.Remove(child);
+ child.Parent = null;
+
+ childrenRWLock.ExitWriteLock ();
+
+ if (child == largestChild && Width == Measure.Fit)
+ searchLargestChild ();
+ if (child == tallestChild && Height == Measure.Fit)
+ searchTallestChild ();
+
+ this.RegisterForLayouting (LayoutingType.Sizing | LayoutingType.ArrangeChildren);
+
+ }
+ public virtual void DeleteChild(Widget child)
+ {
+ RemoveChild (child);
+ child.Dispose ();
+ }
+ public virtual void InsertChild (int idx, Widget g) {
+ childrenRWLock.EnterWriteLock ();
+
+ g.Parent = this;
+ Children.Insert (idx, g);
+
+ childrenRWLock.ExitWriteLock ();
+
+ g.RegisteredLayoutings = LayoutingType.None;
+ g.LayoutChanged += OnChildLayoutChanges;
+ g.RegisterForLayouting (LayoutingType.Sizing | LayoutingType.ArrangeChildren);
+ }
+ public virtual void RemoveChild (int idx) {
+ RemoveChild (children[idx]);
+ }
+ public virtual void DeleteChild (int idx) {
+ DeleteChild (children[idx]);
+ }
+ public virtual void ClearChildren()
+ {
+ childrenRWLock.EnterWriteLock ();
+
+ while (Children.Count > 0) {
+ Widget g = Children [Children.Count - 1];
+ g.LayoutChanged -= OnChildLayoutChanges;
+ Children.RemoveAt (Children.Count - 1);
+ g.Dispose ();
+ }
+
+ childrenRWLock.ExitWriteLock ();
+
+ resetChildrenMaxSize ();
+
+ this.RegisterForLayouting (LayoutingType.Sizing);
+ ChildrenCleared.Raise (this, new EventArgs ());
+ }
+ public override void OnDataSourceChanged (object sender, DataSourceChangeEventArgs e)
+ {
+ base.OnDataSourceChanged (this, e);
+
+ childrenRWLock.EnterReadLock ();
+ foreach (Widget g in Children) {
+ if (g.localDataSourceIsNull & g.localLogicalParentIsNull)
+ g.OnDataSourceChanged (g, e);
+ }
+ childrenRWLock.ExitReadLock ();
+ }
+
+ public void putWidgetOnTop(Widget w)
+ {
+ if (Children.Contains(w))
+ {
+ childrenRWLock.EnterWriteLock ();
+
+ Children.Remove (w);
+ Children.Add (w);
+
+ childrenRWLock.ExitWriteLock ();
+ }
+ }
+ public void putWidgetOnBottom(Widget w)
+ {
+ if (Children.Contains(w))
+ {
+ childrenRWLock.EnterWriteLock ();
+
+ Children.Remove (w);
+ Children.Insert (0, w);
+
+ childrenRWLock.ExitWriteLock ();
+ }
+ }
+
+ #region GraphicObject overrides
+
+ public override Widget FindByName (string nameToFind)
+ {
+ if (Name == nameToFind)
+ return this;
+ Widget tmp = null;
+
+ childrenRWLock.EnterReadLock ();
+
+ foreach (Widget w in Children) {
+ tmp = w.FindByName (nameToFind);
+ if (tmp != null)
+ break;
+ }
+
+ childrenRWLock.ExitReadLock ();
+
+ return tmp;
+ }
+ public override bool Contains (Widget goToFind)
+ {
+ foreach (Widget w in Children) {
+ if (w == goToFind)
+ return true;
+ if (w.Contains (goToFind))
+ return true;
+ }
+ return false;
+ }
+ protected override int measureRawSize (LayoutingType lt)
+ {
+ if (Children.Count > 0) {
+ if (lt == LayoutingType.Width) {
+ if (largestChild == null)
+ searchLargestChild ();
+ if (largestChild == null) {
+ //if still null, not possible to determine a width
+ //because all children are stretched, force first one to fit
+ Children [0].Width = Measure.Fit;
+ return -1;//cancel actual sizing to let child computation take place
+ }
+ } else {
+ if (tallestChild == null)
+ searchTallestChild ();
+ if (tallestChild == null) {
+ Children [0].Height = Measure.Fit;
+ return -1;
+ }
+ }
+ }
+ return base.measureRawSize (lt);
+ }
+
+ public override void OnLayoutChanges (LayoutingType layoutType)
+ {
+ base.OnLayoutChanges (layoutType);
+
+ childrenRWLock.EnterReadLock ();
+ //position smaller objects in group when group size is fit
+ switch (layoutType) {
+ case LayoutingType.Width:
+ foreach (Widget c in Children) {
+ if (c.Width.IsRelativeToParent)
+ c.RegisterForLayouting (LayoutingType.Width);
+ else
+ c.RegisterForLayouting (LayoutingType.X);
+ }
+ break;
+ case LayoutingType.Height:
+ foreach (Widget c in Children) {
+ if (c.Height.IsRelativeToParent)
+ c.RegisterForLayouting (LayoutingType.Height);
+ else
+ c.RegisterForLayouting (LayoutingType.Y);
+ }
+ break;
+ }
+ childrenRWLock.ExitReadLock ();
+ }
+ protected override void onDraw (Context gr)
+ {
+ base.onDraw (gr);
+
+ gr.Save ();
+
+ if (ClipToClientRect) {
+ //clip to client zone
+ CairoHelpers.CairoRectangle (gr, ClientRectangle, CornerRadius);
+ gr.Clip ();
+ }
+
+ childrenRWLock.EnterReadLock ();
+
+ for (int i = 0; i < Children.Count; i++)
+ Children[i].Paint (ref gr);
+
+ childrenRWLock.ExitReadLock ();
+ gr.Restore ();
+ }
+ protected override void UpdateCache (Context ctx)
+ {
+ Rectangle rb = Slot + Parent.ClientRectangle.Position;
+
+
+ Context gr = new Context (bmp);
+
+ if (!Clipping.IsEmpty) {
+ for (int i = 0; i < Clipping.NumRectangles; i++)
+ gr.Rectangle(Clipping.GetRectangle(i));
+ gr.ClipPreserve();
+ gr.Operator = Operator.Clear;
+ gr.Fill();
+ gr.Operator = Operator.Over;
+
+ base.onDraw (gr);
+
+ if (ClipToClientRect) {
+ CairoHelpers.CairoRectangle (gr, ClientRectangle, CornerRadius);
+ gr.Clip ();
+ }
+
+ childrenRWLock.EnterReadLock ();
+
+ foreach (Widget c in Children) {
+ if (!c.Visible)
+ continue;
+ if (Clipping.Contains (c.Slot + ClientRectangle.Position) == RegionOverlap.Out)
+ continue;
+ c.Paint (ref gr);
+ }
+
+ childrenRWLock.ExitReadLock ();
+
+ #if DEBUG_CLIP_RECTANGLE
+ /*gr.LineWidth = 1;
+ gr.SetSourceColor(Color.DarkMagenta.AdjustAlpha (0.8));
+ for (int i = 0; i < Clipping.NumRectangles; i++)
+ gr.Rectangle(Clipping.GetRectangle(i));
+ gr.Stroke ();*/
+ #endif
+ }
+ gr.Dispose ();
+
+ ctx.SetSourceSurface (bmp, rb.X, rb.Y);
+ ctx.Paint ();
+
+ Clipping.Dispose();
+ Clipping = new Region ();
+ }
+ #endregion
+
+ public virtual void OnChildLayoutChanges (object sender, LayoutingEventArgs arg)
+ {
+ Widget g = sender as Widget;
+
+ switch (arg.LayoutType) {
+ case LayoutingType.Width:
+ if (Width != Measure.Fit)
+ return;
+ if (g.Slot.Width > contentSize.Width) {
+ largestChild = g;
+ contentSize.Width = g.Slot.Width;
+ } else if (g == largestChild)
+ searchLargestChild ();
+
+ this.RegisterForLayouting (LayoutingType.Width);
+ break;
+ case LayoutingType.Height:
+ if (Height != Measure.Fit)
+ return;
+ if (g.Slot.Height > contentSize.Height) {
+ tallestChild = g;
+ contentSize.Height = g.Slot.Height;
+ } else if (g == tallestChild)
+ searchTallestChild ();
+
+ this.RegisterForLayouting (LayoutingType.Height);
+ break;
+ }
+ }
+ //TODO: x,y position should be taken in account for computation of width and height
+ void resetChildrenMaxSize(){
+ largestChild = null;
+ tallestChild = null;
+ contentSize = 0;
+ }
+ void searchLargestChild(){
+ #if DEBUG_LAYOUTING
+ Debug.WriteLine("\tSearch largest child");
+ #endif
+ largestChild = null;
+ contentSize.Width = 0;
+ for (int i = 0; i < Children.Count; i++) {
+ if (!Children [i].Visible)
+ continue;
+ if (children [i].RegisteredLayoutings.HasFlag (LayoutingType.Width))
+ continue;
+ if (Children [i].Slot.Width > contentSize.Width) {
+ contentSize.Width = Children [i].Slot.Width;
+ largestChild = Children [i];
+ }
+ }
+ }
+ void searchTallestChild(){
+ #if DEBUG_LAYOUTING
+ Debug.WriteLine("\tSearch tallest child");
+ #endif
+ tallestChild = null;
+ contentSize.Height = 0;
+ for (int i = 0; i < Children.Count; i++) {
+ if (!Children [i].Visible)
+ continue;
+ if (children [i].RegisteredLayoutings.HasFlag (LayoutingType.Height))
+ continue;
+ if (Children [i].Slot.Height > contentSize.Height) {
+ contentSize.Height = Children [i].Slot.Height;
+ tallestChild = Children [i];
+ }
+ }
+ }
+
+
+ #region Mouse handling
+ public override void checkHoverWidget (MouseMoveEventArgs e)
+ {
+ if (IFace.HoverWidget != this) {
+ IFace.HoverWidget = this;
+ onMouseEnter (this, e);
+ }
+ for (int i = Children.Count - 1; i >= 0; i--) {
+ if (Children[i].MouseIsIn(e.Position))
+ {
+ Children[i].checkHoverWidget (e);
+ return;
+ }
+ }
+ base.checkHoverWidget (e);
+ }
+// public override bool PointIsIn (ref Point m)
+// {
+// if (!base.PointIsIn (ref m))
+// return false;
+// if (CurrentInterface.HoverWidget == this)
+// return true;
+// lock (Children) {
+// for (int i = Children.Count - 1; i >= 0; i--) {
+// if (Children [i].Slot.ContainsOrIsEqual (m) && !(bool)CurrentInterface.HoverWidget?.IsOrIsInside(Children[i])) {
+// return false;
+// }
+// }
+// }
+// return true;
+// }
+ #endregion
+
+ protected override void Dispose (bool disposing)
+ {
+ if (disposing) {
+ foreach (Widget c in children)
+ c.Dispose ();
+ }
+ base.Dispose (disposing);
+ }
+ }
+}
--- /dev/null
+//
+// GroupBox.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.Xml.Serialization;
+using System.ComponentModel;
+
+namespace Crow
+{
+ /// <summary>
+ /// templated container accepting one child
+ /// </summary>
+ public class GroupBox : TemplatedContainer
+ {
+ #region CTOR
+ protected GroupBox () : base(){}
+ public GroupBox(Interface iface) : base(iface){}
+ #endregion
+ }
+}
--- /dev/null
+//
+// HorizontalStack.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.Linq;
+using System.Text;
+using System.Xml.Serialization;
+
+namespace Crow
+{
+ /// <summary>
+ /// group control stacking its children horizontally
+ /// </summary>
+ public class HorizontalStack : GenericStack
+ {
+ #region CTOR
+ protected HorizontalStack () : base(){}
+ public HorizontalStack(Interface iface) : base(iface)
+ {
+ }
+ #endregion
+
+ [XmlIgnore]
+ public override Orientation Orientation
+ {
+ get { return Orientation.Horizontal; }
+ }
+ }
+}
--- /dev/null
+//
+// HueSelector.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.Xml.Serialization;
+using System.ComponentModel;
+using Crow.Cairo;
+
+namespace Crow
+{
+ [DesignIgnore]
+ public class HueSelector : ColorSelector
+ {
+ #region CTOR
+ protected HueSelector () : base(){}
+ public HueSelector (Interface iface) : base(iface)
+ {
+ }
+ #endregion
+
+ Orientation _orientation;
+ double hue;
+ CursorType cursor = CursorType.Pentagone;
+
+ [DefaultValue(Orientation.Horizontal)]
+ public virtual Orientation Orientation
+ {
+ get { return _orientation; }
+ set {
+ if (_orientation == value)
+ return;
+ _orientation = value;
+ NotifyValueChanged ("Orientation", _orientation);
+ RegisterForGraphicUpdate ();
+ }
+ }
+
+ public virtual double Hue {
+ get { return hue; }
+ set {
+ if (hue == value)
+ return;
+ hue = value;
+ notifyHueChanged ();
+ updateMousePosFromHue ();
+ RegisterForRedraw ();
+ }
+ }
+ protected override void onDraw (Context gr)
+ {
+ base.onDraw (gr);
+
+ RectangleD r = ClientRectangle;
+ r.Height -= 4;
+ r.Y += 2;
+
+ Gradient.Type gt = Gradient.Type.Horizontal;
+ if (Orientation == Orientation.Vertical)
+ gt = Gradient.Type.Vertical;
+
+ Gradient grad = new Gradient (gt);
+
+ grad.Stops.Add (new Gradient.ColorStop (0, new Color (1, 0, 0, 1)));
+ grad.Stops.Add (new Gradient.ColorStop (0.167, new Color (1, 1, 0, 1)));
+ grad.Stops.Add (new Gradient.ColorStop (0.333, new Color (0, 1, 0, 1)));
+ grad.Stops.Add (new Gradient.ColorStop (0.5, new Color (0, 1, 1, 1)));
+ grad.Stops.Add (new Gradient.ColorStop (0.667, new Color (0, 0, 1, 1)));
+ grad.Stops.Add (new Gradient.ColorStop (0.833, new Color (1, 0, 1, 1)));
+ grad.Stops.Add (new Gradient.ColorStop (1, new Color (1, 0, 0, 1)));
+
+ grad.SetAsSource (gr, r);
+ CairoHelpers.CairoRectangle (gr, r, CornerRadius);
+ gr.Fill();
+
+ r = ClientRectangle;
+
+ switch (cursor) {
+ case CursorType.Rectangle:
+ if (Orientation == Orientation.Horizontal) {
+ r.Width = 5;
+ r.X = mousePos.X - 2.5;
+ } else {
+ r.Height = 5;
+ r.Y = mousePos.Y - 2.5;
+ }
+ CairoHelpers.CairoRectangle (gr, r, 1);
+ break;
+ case CursorType.Circle:
+ if (Orientation == Orientation.Horizontal)
+ gr.Arc (mousePos.X, r.Center.Y, 3.5, 0, Math.PI * 2.0);
+ else
+ gr.Arc (r.Center.X, mousePos.Y, 3.5, 0, Math.PI * 2.0);
+ break;
+ case CursorType.Pentagone:
+ if (Orientation == Orientation.Horizontal) {
+ r.Width = 5;
+ r.X = mousePos.X - 2.5;
+ double y = r.CenterD.Y-r.Height*0.2;
+ gr.MoveTo (mousePos.X, y);
+ y += r.Height * 0.15;
+ gr.LineTo (r.Right, y);
+ gr.LineTo (r.Right, r.Bottom-0.5);
+ gr.LineTo (r.Left, r.Bottom-0.5);
+ gr.LineTo (r.Left, y);
+ gr.ClosePath ();
+ } else {
+ }
+ break;
+ }
+
+ gr.SetSourceColor (Color.Black);
+ gr.LineWidth = 2.0;
+ gr.StrokePreserve ();
+ gr.SetSourceColor (Color.White);
+ gr.LineWidth = 1.0;
+ gr.Stroke ();
+ }
+
+ public override void OnLayoutChanges (LayoutingType layoutType)
+ {
+ base.OnLayoutChanges (layoutType);
+
+ if (Orientation == Orientation.Horizontal) {
+ if (layoutType == LayoutingType.Width)
+ updateMousePosFromHue ();
+ } else if (layoutType == LayoutingType.Height)
+ updateMousePosFromHue ();
+ }
+ protected override void updateMouseLocalPos (Point mPos)
+ {
+ base.updateMouseLocalPos (mPos);
+ if (Orientation == Orientation.Horizontal)
+ hue = (double)mousePos.X / (double)ClientRectangle.Width;
+ else
+ hue = (double)mousePos.Y / (double)ClientRectangle.Height;
+ notifyHueChanged ();
+ RegisterForRedraw ();
+ }
+ void updateMousePosFromHue(){
+ if (Orientation == Orientation.Horizontal)
+ mousePos.X = (int)Math.Floor(hue * (double)ClientRectangle.Width);
+ else
+ mousePos.Y = (int)Math.Floor(hue * (double)ClientRectangle.Height);
+ }
+ void notifyHueChanged(){
+ NotifyValueChanged ("Hue", hue);
+ NotifyValueChanged ("HueColor", new SolidColor (Color.FromHSV (hue)));
+ }
+ }
+}
+
--- /dev/null
+//
+// ILayoutable.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;
+
+namespace Crow
+{
+ public interface ILayoutable
+ {
+ /// <summary> Parent in the graphic tree </summary>
+ ILayoutable Parent { get; set; }
+ /// <summary> The logical parent (used mainly for bindings) as opposed
+ /// to the parent in the graphic tree </summary>
+ ILayoutable LogicalParent { get; set; }
+
+ Rectangle ClientRectangle { get; }
+ Rectangle getSlot();
+
+ bool ArrangeChildren { get; }
+ LayoutingType RegisteredLayoutings { get; set; }
+ void RegisterForLayouting(LayoutingType layoutType);
+ void RegisterClip(Rectangle clip);
+ bool UpdateLayout(LayoutingType layoutType);
+ bool PointIsIn(ref Point m);
+
+ Rectangle ContextCoordinates(Rectangle r);
+ Rectangle ScreenCoordinates (Rectangle r);
+
+ }
+}
+
--- /dev/null
+//
+// IMLContainer.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;
+
+namespace Crow
+{
+ public class IMLContainer : PrivateContainer
+ {
+ public IMLContainer () : base()
+ {
+ }
+
+ string path;
+
+ public string Path {
+ get { return path; }
+ set {
+ if (path == value)
+ return;
+ path = value;
+ this.SetChild (IFace.CreateInstance (path));
+ NotifyValueChanged ("Path", path);
+ }
+ }
+ }
+}
+
--- /dev/null
+//
+// IValueChange.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;
+
+namespace Crow
+{
+ public interface IValueChange
+ {
+ event EventHandler<ValueChangeEventArgs> ValueChanged;
+ }
+}
+
--- /dev/null
+//
+// Image.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 Crow.Cairo;
+using System.Xml.Serialization;
+using System.ComponentModel;
+using System.Diagnostics;
+
+
+namespace Crow
+{
+ /// <summary>
+ /// Base widget to display an image. Accepts bitmaps and SVGs.
+ /// </summary>
+ /// <remarks>
+ /// </remarks>
+ public class Image : Widget
+ {
+ Picture _pic;
+ string _svgSub;
+ bool scaled, keepProps;
+ double opacity;
+
+ #region Public properties
+ /// <summary>
+ /// If false, original size will be kept in any case.
+ /// </summary>
+ [DefaultValue(true)]
+ public virtual bool Scaled {
+ get { return scaled; }
+ set {
+ if (scaled == value)
+ return;
+ scaled = value;
+ NotifyValueChanged ("Scaled", scaled);
+ if (_pic == null)
+ return;
+ _pic.Scaled = scaled;
+ RegisterForGraphicUpdate ();
+ }
+ }
+ /// <summary>
+ /// If image is scaled, proportions will be preserved.
+ /// </summary>
+ [DefaultValue(true)]
+ public virtual bool KeepProportions {
+ get { return keepProps; }
+ set {
+ if (keepProps == value)
+ return;
+ keepProps = value;
+ NotifyValueChanged ("KeepProportions", keepProps);
+ if (_pic == null)
+ return;
+ _pic.KeepProportions = keepProps;
+ RegisterForGraphicUpdate ();
+ }
+ }
+ /// <summary>
+ /// Image file path, may be on disk or embedded. Accepts bitmaps or SVG drawings.
+ /// </summary>
+
+ public string Path {
+ get { return _pic == null ? "" : _pic.Path; }
+ set {
+ if (value == Path)
+ return;
+ try {
+ if (string.IsNullOrEmpty(value))
+ Picture = null;
+ else {
+ //lock(IFace.LayoutMutex){
+ LoadImage (value);
+ //}
+ }
+ } catch (Exception ex) {
+ Debug.WriteLine (ex.Message);
+ _pic = null;
+ }
+ NotifyValueChanged ("Path", Path);
+ }
+ }
+ /// <summary>
+ /// Used only for svg images, repaint only node named referenced in SvgSub.
+ /// If null, all the svg is rendered
+ /// </summary>
+
+ public string SvgSub {
+ get { return _svgSub; }
+ set {
+ if (_svgSub == value)
+ return;
+ _svgSub = value;
+ RegisterForGraphicUpdate ();
+ }
+ }
+ /// <summary>
+ /// Object holding the image data once loaded, may be used directely to pupulate this control without
+ /// specifying a path.
+ /// </summary>
+
+ public Picture Picture {
+ get { return _pic; }
+ set {
+ if (_pic == value)
+ return;
+ _pic = value;
+ NotifyValueChanged ("Picture", _pic);
+ RegisterForGraphicUpdate ();
+ }
+ }
+ /// <summary>
+ /// Opacity parameter for the image
+ /// </summary>
+ // TODO:could be moved in GraphicObject
+ [DefaultValue(1.0)]
+ public virtual double Opacity {
+ get { return opacity; }
+ set {
+ if (opacity == value)
+ return;
+ opacity = value;
+ NotifyValueChanged ("Faded", opacity);
+ RegisterForRedraw ();
+ }
+ }
+ #endregion
+
+ #region CTOR
+ /// <summary>
+ /// Initializes a new instance of the <see cref="Crow.Image"/> class.
+ /// </summary>
+ protected Image () : base(){}
+ /// <summary>
+ /// Initializes a new instance of the <see cref="Crow.Image"/> class from code
+ /// </summary>
+ /// <param name="iface">interface to bound to</param>
+ public Image (Interface iface) : base(iface)
+ {
+ }
+ #endregion
+
+ #region Image Loading
+ public void LoadImage (string path)
+ {
+ Picture pic;
+ if (path.EndsWith (".svg", true, System.Globalization.CultureInfo.InvariantCulture))
+ pic = new SvgPicture (path);
+ else
+ pic = new BmpPicture (path);
+
+
+ pic.Scaled = scaled;
+ pic.KeepProportions = keepProps;
+
+ Picture = pic;
+ }
+ #endregion
+
+ #region GraphicObject overrides
+ protected override int measureRawSize (LayoutingType lt)
+ {
+ if (_pic == null)
+ return 2 * Margin;
+ //_pic = "#Crow.Images.Icons.IconAlerte.svg";
+ //TODO:take scalling in account
+ if (lt == LayoutingType.Width)
+ return _pic.Dimensions.Width + 2 * Margin;
+ else
+ return _pic.Dimensions.Height + 2 * Margin;
+ }
+ protected override void onDraw (Context gr)
+ {
+ base.onDraw (gr);
+
+ if (_pic == null)
+ return;
+
+ _pic.Paint (gr, ClientRectangle, _svgSub);
+
+ if (Opacity<1.0) {
+ gr.SetSourceRGBA (0.0, 0.0, 0.0, 1.0-Opacity);
+ gr.Operator = Operator.DestOut;
+ gr.Rectangle (ClientRectangle);
+ gr.Fill ();
+ gr.Operator = Operator.Over;
+ }
+ }
+ #endregion
+ }
+}
--- /dev/null
+//
+// Label.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.Linq;
+using System.Diagnostics;
+using Crow.Cairo;
+using System.Text.RegularExpressions;
+using System.Xml.Serialization;
+using System.ComponentModel;
+
+namespace Crow
+{
+ public class Label : Widget
+ {
+ #region CTOR
+ protected Label () : base(){}
+
+ public Label(Interface iface) : base(iface)
+ {
+
+ }
+// public Label(string _text)
+// : base()
+// {
+// Text = _text;
+// }
+ #endregion
+
+ public event EventHandler<TextChangeEventArgs> TextChanged;
+
+ public virtual void OnTextChanged(Object sender, TextChangeEventArgs e)
+ {
+ textMeasureIsUpToDate = false;
+ NotifyValueChanged ("Text", Text);
+ TextChanged.Raise (this, e);
+ }
+ //TODO:change protected to private
+
+ #region private and protected fields
+ string _text = "label";
+ Alignment _textAlignment;
+ bool horizontalStretch;
+ bool verticalStretch;
+ bool _selectable;
+ bool _multiline;
+ Color selBackground;
+ Color selForeground;
+ Point mouseLocalPos = -1;//mouse coord in widget space, filled only when clicked
+ int _currentCol; //0 based cursor position in string
+ int _currentLine;
+ Point _selBegin = -1; //selection start (row,column)
+ Point _selRelease = -1; //selection end (row,column)
+ double textCursorPos; //cursor position in cairo units in widget client coord.
+ double SelStartCursorPos = -1;
+ double SelEndCursorPos = -1;
+ bool SelectionInProgress = false;
+
+ protected Rectangle rText;
+ protected float widthRatio = 1f;
+ protected float heightRatio = 1f;
+ protected FontExtents fe;
+ protected TextExtents te;
+ #endregion
+
+ [DefaultValue("SteelBlue")]
+ public virtual Color SelectionBackground {
+ get { return selBackground; }
+ set {
+ if (value == selBackground)
+ return;
+ selBackground = value;
+ NotifyValueChanged ("SelectionBackground", selBackground);
+ RegisterForRedraw ();
+ }
+ }
+ [DefaultValue("White")]
+ public virtual Color SelectionForeground {
+ get { return selForeground; }
+ set {
+ if (value == selForeground)
+ return;
+ selForeground = value;
+ NotifyValueChanged ("SelectionForeground", selForeground);
+ RegisterForRedraw ();
+ }
+ }
+ [DefaultValue(Alignment.Left)]
+ public Alignment TextAlignment
+ {
+ get { return _textAlignment; }
+ set {
+ if (value == _textAlignment)
+ return;
+ _textAlignment = value;
+ RegisterForRedraw ();
+ NotifyValueChanged ("TextAlignment", _textAlignment);
+ }
+ }
+ [DefaultValue(false)]
+ public virtual bool HorizontalStretch {
+ get { return horizontalStretch; }
+ set {
+ if (horizontalStretch == value)
+ return;
+ horizontalStretch = value;
+ RegisterForRedraw ();
+ NotifyValueChanged ("HorizontalStretch", horizontalStretch);
+ }
+ }
+ [DefaultValue(false)]
+ public virtual bool VerticalStretch {
+ get { return verticalStretch; }
+ set {
+ if (verticalStretch == value)
+ return;
+ verticalStretch = value;
+ RegisterForRedraw ();
+ NotifyValueChanged ("VerticalStretch", verticalStretch);
+ }
+ }
+ [DefaultValue("label")]
+ public string Text
+ {
+ get {
+ return lines == null ?
+ _text : lines.Aggregate((i, j) => i + Interface.LineBreak + j);
+ }
+ set
+ {
+ if (string.Equals (value, _text, StringComparison.Ordinal))
+ return;
+
+ _text = value;
+
+ if (string.IsNullOrEmpty(_text))
+ _text = "";
+
+ lines = getLines;
+
+ OnTextChanged (this, new TextChangeEventArgs (Text));
+ RegisterForGraphicUpdate ();
+ }
+ }
+ [DefaultValue(false)]
+ public bool Selectable
+ {
+ get { return _selectable; }
+ set
+ {
+ if (value == _selectable)
+ return;
+ _selectable = value;
+ NotifyValueChanged ("Selectable", _selectable);
+ SelBegin = -1;
+ SelRelease = -1;
+ RegisterForRedraw ();
+ }
+ }
+ [DefaultValue(false)]
+ public bool Multiline
+ {
+ get { return _multiline; }
+ set
+ {
+ if (value == _multiline)
+ return;
+ _multiline = value;
+ NotifyValueChanged ("Multiline", _multiline);
+ RegisterForGraphicUpdate();
+ }
+ }
+ [DefaultValue(0)]
+ public int CurrentColumn{
+ get { return _currentCol; }
+ set {
+ if (value == _currentCol)
+ return;
+ if (value < 0)
+ _currentCol = 0;
+ else if (value > lines [_currentLine].Length)
+ _currentCol = lines [_currentLine].Length;
+ else
+ _currentCol = value;
+ NotifyValueChanged ("CurrentColumn", _currentCol);
+ }
+ }
+ [DefaultValue(0)]
+ public int CurrentLine{
+ get { return _currentLine; }
+ set {
+ if (value == _currentLine)
+ return;
+ if (value >= lines.Count)
+ _currentLine = lines.Count-1;
+ else if (value < 0)
+ _currentLine = 0;
+ else
+ _currentLine = value;
+ //force recheck of currentCol for bounding
+ int cc = _currentCol;
+ _currentCol = 0;
+ CurrentColumn = cc;
+ NotifyValueChanged ("CurrentLine", _currentLine);
+ }
+ }
+ [XmlIgnore]public Point CurrentPosition {
+ get { return new Point(_currentCol, CurrentLine); }
+ }
+ //TODO:using HasFocus for drawing selection cause SelBegin and Release binding not to work
+ /// <summary>
+ /// Selection begin position in char units
+ /// </summary>
+ [DefaultValue("-1")]
+ public Point SelBegin {
+ get {
+ return _selBegin;
+ }
+ set {
+ if (value == _selBegin)
+ return;
+ _selBegin = value;
+ NotifyValueChanged ("SelBegin", _selBegin);
+ NotifyValueChanged ("SelectedText", SelectedText);
+ }
+ }
+ [DefaultValue("-1")]
+ public Point SelRelease {
+ get {
+ return _selRelease;
+ }
+ set {
+ if (value == _selRelease)
+ return;
+ _selRelease = value;
+ NotifyValueChanged ("SelRelease", _selRelease);
+ NotifyValueChanged ("SelectedText", SelectedText);
+ }
+ }
+ /// <summary>
+ /// return char at CurrentLine, CurrentColumn
+ /// </summary>
+ [XmlIgnore]protected Char CurrentChar
+ {
+ get {
+ return lines [CurrentLine] [CurrentColumn];
+ }
+ }
+ /// <summary>
+ /// ordered selection start and end positions in char units
+ /// </summary>
+ [XmlIgnore]protected Point selectionStart
+ {
+ get {
+ return SelRelease < 0 || SelBegin.Y < SelRelease.Y ? SelBegin :
+ SelBegin.Y > SelRelease.Y ? SelRelease :
+ SelBegin.X < SelRelease.X ? SelBegin : SelRelease;
+ }
+ }
+ [XmlIgnore]public Point selectionEnd
+ {
+ get {
+ return SelRelease < 0 || SelBegin.Y > SelRelease.Y ? SelBegin :
+ SelBegin.Y < SelRelease.Y ? SelRelease :
+ SelBegin.X > SelRelease.X ? SelBegin : SelRelease;
+ }
+ }
+ [XmlIgnore]public string SelectedText
+ {
+ get {
+
+ if (SelRelease < 0 || SelBegin < 0)
+ return "";
+ if (selectionStart.Y == selectionEnd.Y)
+ return lines [selectionStart.Y].Substring (selectionStart.X, selectionEnd.X - selectionStart.X);
+ string tmp = "";
+ tmp = lines [selectionStart.Y].Substring (selectionStart.X);
+ for (int l = selectionStart.Y + 1; l < selectionEnd.Y; l++) {
+ tmp += Interface.LineBreak + lines [l];
+ }
+ tmp += Interface.LineBreak + lines [selectionEnd.Y].Substring (0, selectionEnd.X);
+ return tmp;
+ }
+ }
+ [XmlIgnore]public bool selectionIsEmpty
+ { get { return SelRelease < 0; } }
+
+ List<string> lines;
+ List<string> getLines {
+ get {
+ return _multiline ?
+ Regex.Split (_text, "\r\n|\r|\n|\\\\n").ToList() :
+ new List<string>(new string[] { _text });
+ }
+ }
+ /// <summary>
+ /// Moves cursor one char to the left.
+ /// </summary>
+ /// <returns><c>true</c> if move succeed</returns>
+ public bool MoveLeft(){
+ int tmp = _currentCol - 1;
+ if (tmp < 0) {
+ if (_currentLine == 0)
+ return false;
+ CurrentLine--;
+ CurrentColumn = int.MaxValue;
+ } else
+ CurrentColumn = tmp;
+ return true;
+ }
+ /// <summary>
+ /// Moves cursor one char to the right.
+ /// </summary>
+ /// <returns><c>true</c> if move succeed</returns>
+ public bool MoveRight(){
+ int tmp = _currentCol + 1;
+ if (tmp > lines [_currentLine].Length){
+ if (CurrentLine == lines.Count - 1)
+ return false;
+ CurrentLine++;
+ CurrentColumn = 0;
+ } else
+ CurrentColumn = tmp;
+ return true;
+ }
+ public void GotoWordStart(){
+ CurrentColumn--;
+ //skip white spaces
+ while (!char.IsLetterOrDigit (this.CurrentChar) && CurrentColumn > 0)
+ CurrentColumn--;
+ while (char.IsLetterOrDigit (lines [CurrentLine] [CurrentColumn]) && CurrentColumn > 0)
+ CurrentColumn--;
+ if (!char.IsLetterOrDigit (this.CurrentChar))
+ CurrentColumn++;
+ }
+ public void GotoWordEnd(){
+ //skip white spaces
+ if (CurrentColumn >= lines [CurrentLine].Length - 1)
+ return;
+ while (!char.IsLetterOrDigit (this.CurrentChar) && CurrentColumn < lines [CurrentLine].Length-1)
+ CurrentColumn++;
+ while (char.IsLetterOrDigit (this.CurrentChar) && CurrentColumn < lines [CurrentLine].Length-1)
+ CurrentColumn++;
+ if (char.IsLetterOrDigit (this.CurrentChar))
+ CurrentColumn++;
+ }
+ public void DeleteChar()
+ {
+ if (selectionIsEmpty) {
+ if (CurrentColumn == 0) {
+ if (CurrentLine == 0 && lines.Count == 1)
+ return;
+ CurrentLine--;
+ CurrentColumn = lines [CurrentLine].Length;
+ lines [CurrentLine] += lines [CurrentLine + 1];
+ lines.RemoveAt (CurrentLine + 1);
+
+ OnTextChanged (this, new TextChangeEventArgs (Text));
+ return;
+ }
+ CurrentColumn--;
+ lines [CurrentLine] = lines [CurrentLine].Remove (CurrentColumn, 1);
+ } else {
+ int linesToRemove = selectionEnd.Y - selectionStart.Y + 1;
+ int l = selectionStart.Y;
+
+ if (linesToRemove > 0) {
+ lines [l] = lines [l].Remove (selectionStart.X, lines [l].Length - selectionStart.X) +
+ lines [selectionEnd.Y].Substring (selectionEnd.X, lines [selectionEnd.Y].Length - selectionEnd.X);
+ l++;
+ for (int c = 0; c < linesToRemove-1; c++)
+ lines.RemoveAt (l);
+ CurrentLine = selectionStart.Y;
+ CurrentColumn = selectionStart.X;
+ } else
+ lines [l] = lines [l].Remove (selectionStart.X, selectionEnd.X - selectionStart.X);
+ CurrentColumn = selectionStart.X;
+ SelBegin = -1;
+ SelRelease = -1;
+ }
+ OnTextChanged (this, new TextChangeEventArgs (Text));
+ }
+ /// <summary>
+ /// Insert new string at caret position, should be sure no line break is inside.
+ /// </summary>
+ /// <param name="str">String.</param>
+ protected void Insert(string str)
+ {
+ if (!selectionIsEmpty)
+ this.DeleteChar ();
+ if (_multiline) {
+ string[] strLines = Regex.Split (str, "\r\n|\r|\n|" + @"\\n").ToArray();
+ lines [CurrentLine] = lines [CurrentLine].Insert (CurrentColumn, strLines[0]);
+ CurrentColumn += strLines[0].Length;
+ for (int i = 1; i < strLines.Length; i++) {
+ InsertLineBreak ();
+ lines [CurrentLine] = lines [CurrentLine].Insert (CurrentColumn, strLines[i]);
+ CurrentColumn += strLines[i].Length;
+ }
+ } else {
+ lines [CurrentLine] = lines [CurrentLine].Insert (CurrentColumn, str);
+ CurrentColumn += str.Length;
+ }
+ OnTextChanged (this, new TextChangeEventArgs (Text));
+ }
+ /// <summary>
+ /// Insert a line break.
+ /// </summary>
+ protected void InsertLineBreak()
+ {
+ lines.Insert(CurrentLine + 1, lines[CurrentLine].Substring(CurrentColumn));
+ lines [CurrentLine] = lines [CurrentLine].Substring (0, CurrentColumn);
+ CurrentLine++;
+ CurrentColumn = 0;
+ OnTextChanged (this, new TextChangeEventArgs (Text));
+ }
+ bool textMeasureIsUpToDate = false;
+ Size cachedTextSize = default(Size);
+
+ #region GraphicObject overrides
+ protected override int measureRawSize(LayoutingType lt)
+ {
+ if (lines == null)
+ lines = getLines;
+ if (!textMeasureIsUpToDate) {
+ using (Context gr = new Context (IFace.surf)) {
+ //Cairo.FontFace cf = gr.GetContextFontFace ();
+
+ gr.SelectFontFace (Font.Name, Font.Slant, Font.Wheight);
+ gr.SetFontSize (Font.Size);
+ gr.FontOptions = Interface.FontRenderingOptions;
+ gr.Antialias = Interface.Antialias;
+
+ fe = gr.FontExtents;
+ te = new TextExtents ();
+
+ cachedTextSize.Height = (int)Math.Ceiling ((fe.Ascent+fe.Descent) * Math.Max (1, lines.Count)) + Margin * 2;
+
+ try {
+ for (int i = 0; i < lines.Count; i++) {
+ string l = lines[i].Replace ("\t", new String (' ', Interface.TAB_SIZE));
+
+ TextExtents tmp = gr.TextExtents (l);
+
+ if (tmp.XAdvance > te.XAdvance)
+ te = tmp;
+ }
+ cachedTextSize.Width = (int)Math.Ceiling (te.XAdvance) + Margin * 2;
+ textMeasureIsUpToDate = true;
+ } catch {
+ return -1;
+ }
+ }
+ }
+ return lt == LayoutingType.Height ? cachedTextSize.Height : cachedTextSize.Width;
+ }
+ protected override void onDraw (Context gr)
+ {
+ base.onDraw (gr);
+
+ gr.SelectFontFace (Font.Name, Font.Slant, Font.Wheight);
+ gr.SetFontSize (Font.Size);
+ gr.FontOptions = Interface.FontRenderingOptions;
+ gr.Antialias = Interface.Antialias;
+
+ rText = new Rectangle(new Size(
+ measureRawSize(LayoutingType.Width), measureRawSize(LayoutingType.Height)));
+ rText.Width -= 2 * Margin;
+ rText.Height -= 2 * Margin;
+
+ widthRatio = 1f;
+ heightRatio = 1f;
+
+ Rectangle cb = ClientRectangle;
+
+ rText.X = cb.X;
+ rText.Y = cb.Y;
+
+ if (horizontalStretch) {
+ widthRatio = (float)cb.Width / (float)rText.Width;
+ if (!verticalStretch)
+ heightRatio = widthRatio;
+ }
+
+ if (verticalStretch) {
+ heightRatio = (float)cb.Height / (float)rText.Height;
+ if (!horizontalStretch)
+ widthRatio = heightRatio;
+ }
+
+ rText.Width = (int)(widthRatio * (float)rText.Width);
+ rText.Height = (int)(heightRatio * (float)rText.Height);
+
+ switch (TextAlignment)
+ {
+ case Alignment.TopLeft: //ok
+ rText.X = cb.X;
+ rText.Y = cb.Y;
+ break;
+ case Alignment.Top: //ok
+ rText.Y = cb.Y;
+ rText.X = cb.X + cb.Width / 2 - rText.Width / 2;
+ break;
+ case Alignment.TopRight: //ok
+ rText.Y = cb.Y;
+ rText.X = cb.Right - rText.Width;
+ break;
+ case Alignment.Left://ok
+ rText.X = cb.X;
+ rText.Y = cb.Y + cb.Height / 2 - rText.Height / 2;
+ break;
+ case Alignment.Right://ok
+ rText.X = cb.X + cb.Width - rText.Width;
+ rText.Y = cb.Y + cb.Height / 2 - rText.Height / 2;
+ break;
+ case Alignment.Bottom://ok
+ rText.X = cb.Width / 2 - rText.Width / 2;
+ rText.Y = cb.Height - rText.Height;
+ break;
+ case Alignment.BottomLeft://ok
+ rText.X = cb.X;
+ rText.Y = cb.Bottom - rText.Height;
+ break;
+ case Alignment.BottomRight://ok
+ rText.Y = cb.Bottom - rText.Height;
+ rText.X = cb.Right - rText.Width;
+ break;
+ case Alignment.Center://ok
+ rText.X = cb.X + cb.Width / 2 - rText.Width / 2;
+ //rText.Y = cb.Y + cb.Height / 2 - rText.Height / 2;
+ rText.Y = cb.Y + (int)Math.Floor((double)cb.Height / 2.0 - (double)rText.Height / 2.0);
+ break;
+ }
+
+ //gr.FontMatrix = new Matrix(widthRatio * (float)Font.Size, 0, 0, heightRatio * (float)Font.Size, 0, 0);
+ fe = gr.FontExtents;
+
+ #region draw text cursor
+ if (HasFocus && Selectable)
+ {
+ if (mouseLocalPos >= 0)
+ {
+ computeTextCursor(gr);
+
+ if (SelectionInProgress)
+ {
+ if (SelBegin < 0){
+ SelBegin = new Point(CurrentColumn, CurrentLine);
+ SelStartCursorPos = textCursorPos;
+ SelRelease = -1;
+ }else{
+ SelRelease = new Point(CurrentColumn, CurrentLine);
+ if (SelRelease == SelBegin)
+ SelRelease = -1;
+ else
+ SelEndCursorPos = textCursorPos;
+ }
+ }else
+ computeTextCursorPosition(gr);
+ }else
+ computeTextCursorPosition(gr);
+
+ Foreground.SetAsSource (gr);
+ gr.LineWidth = 1.0;
+ gr.MoveTo (0.5 + textCursorPos + rText.X, rText.Y + CurrentLine * (fe.Ascent+fe.Descent));
+ gr.LineTo (0.5 + textCursorPos + rText.X, rText.Y + (CurrentLine + 1) * (fe.Ascent+fe.Descent));
+ gr.Stroke();
+ }
+ #endregion
+
+ //****** debug selection *************
+// if (SelRelease >= 0) {
+// new SolidColor(Color.DarkGreen).SetAsSource(gr);
+// Rectangle R = new Rectangle (
+// rText.X + (int)SelEndCursorPos - 3,
+// rText.Y + (int)(SelRelease.Y * (fe.Ascent+fe.Descent)),
+// 6,
+// (int)(fe.Ascent+fe.Descent));
+// gr.Rectangle (R);
+// gr.Fill ();
+// }
+// if (SelBegin >= 0) {
+// new SolidColor(Color.DarkRed).SetAsSource(gr);
+// Rectangle R = new Rectangle (
+// rText.X + (int)SelStartCursorPos - 3,
+// rText.Y + (int)(SelBegin.Y * (fe.Ascent+fe.Descent)),
+// 6,
+// (int)(fe.Ascent+fe.Descent));
+// gr.Rectangle (R);
+// gr.Fill ();
+// }
+ //*******************
+
+ for (int i = 0; i < lines.Count; i++) {
+ string l = lines [i].Replace ("\t", new String (' ', Interface.TAB_SIZE));
+ int lineLength = (int)gr.TextExtents (l).XAdvance;
+ Rectangle lineRect = new Rectangle (
+ rText.X,
+ rText.Y + i * (int)(fe.Ascent+fe.Descent),
+ lineLength,
+ (int)(fe.Ascent+fe.Descent));
+
+// if (TextAlignment == Alignment.Center ||
+// TextAlignment == Alignment.Top ||
+// TextAlignment == Alignment.Bottom)
+// lineRect.X += (rText.Width - lineLength) / 2;
+// else if (TextAlignment == Alignment.Right ||
+// TextAlignment == Alignment.TopRight ||
+// TextAlignment == Alignment.BottomRight)
+// lineRect.X += (rText.Width - lineLength);
+ if (string.IsNullOrWhiteSpace (l))
+ continue;
+
+ Foreground.SetAsSource (gr);
+ gr.MoveTo (lineRect.X,(double)rText.Y + fe.Ascent + (fe.Ascent+fe.Descent) * i) ;
+
+ gr.ShowText (l);
+ gr.Fill ();
+
+ if (Selectable) {
+ if (SelRelease >= 0 && i >= selectionStart.Y && i <= selectionEnd.Y) {
+ gr.SetSourceColor (selBackground);
+
+ Rectangle selRect = lineRect;
+
+ int cpStart = (int)SelStartCursorPos,
+ cpEnd = (int)SelEndCursorPos;
+
+ if (SelBegin.Y > SelRelease.Y) {
+ cpStart = cpEnd;
+ cpEnd = (int)SelStartCursorPos;
+ }
+
+ if (i == selectionStart.Y) {
+ selRect.Width -= cpStart;
+ selRect.Left += cpStart;
+ }
+ if (i == selectionEnd.Y)
+ selRect.Width -= (lineLength - cpEnd);
+
+ gr.Rectangle (selRect);
+ gr.FillPreserve ();
+ gr.Save ();
+ gr.Clip ();
+ gr.SetSourceColor (SelectionForeground);
+ gr.MoveTo (lineRect.X, rText.Y + fe.Ascent + (fe.Ascent+fe.Descent) * i);
+ gr.ShowText (l);
+ gr.Fill ();
+ gr.Restore ();
+ }
+ }
+ }
+ }
+ #endregion
+
+ #region Mouse handling
+ void updatemouseLocalPos(Point mpos){
+ mouseLocalPos = mpos - ScreenCoordinates(Slot).TopLeft - ClientRectangle.TopLeft;
+ if (mouseLocalPos.X < 0)
+ mouseLocalPos.X = 0;
+ if (mouseLocalPos.Y < 0)
+ mouseLocalPos.Y = 0;
+ }
+ protected override void onFocused (object sender, EventArgs e)
+ {
+ base.onFocused (sender, e);
+
+ if (!_selectable)
+ return;
+ SelBegin = new Point(0,0);
+ SelRelease = new Point (lines.LastOrDefault ().Length, lines.Count-1);
+ RegisterForRedraw ();
+ }
+ protected override void onUnfocused (object sender, EventArgs e)
+ {
+ base.onUnfocused (sender, e);
+
+ SelBegin = -1;
+ SelRelease = -1;
+ RegisterForRedraw ();
+ }
+ public override void onMouseMove (object sender, MouseMoveEventArgs e)
+ {
+ base.onMouseMove (sender, e);
+
+ if (!(SelectionInProgress && HasFocus && _selectable))
+ return;
+
+ updatemouseLocalPos (e.Position);
+
+ RegisterForRedraw();
+ }
+ public override void onMouseDown (object sender, MouseButtonEventArgs e)
+ {
+ if (this.HasFocus && _selectable){
+ updatemouseLocalPos (e.Position);
+ SelBegin = -1;
+ SelRelease = -1;
+ SelectionInProgress = true;
+ RegisterForRedraw();//TODO:should put it in properties
+ }
+
+ //done at the end to set 'hasFocus' value after testing it
+ base.onMouseDown (sender, e);
+ }
+ public override void onMouseUp (object sender, MouseButtonEventArgs e)
+ {
+ base.onMouseUp (sender, e);
+ if (!(this.HasFocus || _selectable))
+ return;
+ if (!SelectionInProgress)
+ return;
+
+ updatemouseLocalPos (e.Position);
+ SelectionInProgress = false;
+ RegisterForRedraw ();
+ }
+ public override void onMouseDoubleClick (object sender, MouseButtonEventArgs e)
+ {
+ base.onMouseDoubleClick (sender, e);
+ if (!(this.HasFocus || _selectable))
+ return;
+
+ GotoWordStart ();
+ SelBegin = CurrentPosition;
+ GotoWordEnd ();
+ SelRelease = CurrentPosition;
+ SelectionInProgress = false;
+ RegisterForRedraw ();
+ }
+ #endregion
+
+ /// <summary>
+ /// Update Current Column, line and TextCursorPos
+ /// from mouseLocalPos
+ /// </summary>
+ void computeTextCursor(Context gr)
+ {
+ TextExtents te;
+
+ double cPos = 0f;
+
+ CurrentLine = (int)(mouseLocalPos.Y / (fe.Ascent+fe.Descent));
+
+ //fix cu
+ if (CurrentLine >= lines.Count)
+ CurrentLine = lines.Count - 1;
+
+ switch (TextAlignment) {
+ case Alignment.Center:
+ case Alignment.Top:
+ case Alignment.Bottom:
+ cPos+= ClientRectangle.Width - gr.TextExtents(lines [CurrentLine]).Width/2.0;
+ break;
+ case Alignment.Right:
+ case Alignment.TopRight:
+ case Alignment.BottomRight:
+ cPos += ClientRectangle.Width - gr.TextExtents(lines [CurrentLine]).Width;
+ break;
+ }
+
+ for (int i = 0; i < lines[CurrentLine].Length; i++)
+ {
+ string c = lines [CurrentLine].Substring (i, 1);
+ if (c == "\t")
+ c = new string (' ', Interface.TAB_SIZE);
+
+ te = gr.TextExtents(c);
+
+ double halfWidth = te.XAdvance / 2;
+
+ if (mouseLocalPos.X <= cPos + halfWidth)
+ {
+ CurrentColumn = i;
+ textCursorPos = cPos;
+ mouseLocalPos = -1;
+ return;
+ }
+
+ cPos += te.XAdvance;
+ }
+ CurrentColumn = lines[CurrentLine].Length;
+ textCursorPos = cPos;
+
+ //reset mouseLocalPos
+ mouseLocalPos = -1;
+ }
+ /// <summary> Computes offsets in cairo units </summary>
+ void computeTextCursorPosition(Context gr)
+ {
+ if (SelBegin >= 0)
+ SelStartCursorPos = GetXFromTextPointer (gr, SelBegin);
+ if (SelRelease >= 0)
+ SelEndCursorPos = GetXFromTextPointer (gr, SelRelease);
+ textCursorPos = GetXFromTextPointer (gr, new Point(CurrentColumn, CurrentLine));
+ }
+ /// <summary> Compute x offset in cairo unit from text position </summary>
+ double GetXFromTextPointer(Context gr, Point pos)
+ {
+ try {
+ string l = lines [pos.Y].Substring (0, pos.X).
+ Replace ("\t", new String (' ', Interface.TAB_SIZE));
+ return gr.TextExtents (l).XAdvance;
+ } catch{
+ return -1;
+ }
+ }
+ }
+}
--- /dev/null
+//
+// ListBox.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;
+using System.Xml.Serialization;
+using System.ComponentModel;
+using System.IO;
+using System.Diagnostics;
+using System.Xml;
+using System.Collections.Generic;
+using System.Threading;
+
+namespace Crow
+{
+ public class ListBox : TemplatedGroup
+ {
+ #region CTOR
+ protected ListBox () : base(){}
+ public ListBox (Interface iface) : base(iface) {}
+ #endregion
+
+ }
+}
+
--- /dev/null
+//
+// Menu.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.Xml.Serialization;
+using System.ComponentModel;
+
+namespace Crow
+{
+ public class Menu : TemplatedGroup
+ {
+ #region CTOR
+ protected Menu () : base(){}
+ public Menu (Interface iface) : base(iface) {}
+ #endregion
+
+ Orientation orientation;
+ bool autoOpen = false;
+
+ #region Public properties
+ [DefaultValue(Orientation.Horizontal)]
+ public Orientation Orientation {
+ get { return orientation; }
+ set {
+ if (orientation == value)
+ return;
+ orientation = value;
+ NotifyValueChanged ("Orientation", orientation);
+ }
+ }
+ [XmlIgnore]public bool AutomaticOpening
+ {
+ get { return autoOpen; }
+ set {
+ if (autoOpen == value)
+ return;
+ autoOpen = value;
+ NotifyValueChanged ("AutomaticOpening", autoOpen);
+ }
+ }
+ #endregion
+
+ public override void AddItem (Widget g)
+ {
+ base.AddItem (g);
+
+ if (orientation == Orientation.Horizontal)
+ g.NotifyValueChanged ("PopDirection", Alignment.Bottom);
+ else
+ g.NotifyValueChanged ("PopDirection", Alignment.Right);
+ }
+ public override void onMouseLeave (object sender, MouseMoveEventArgs e)
+ {
+ base.onMouseLeave (sender, e);
+ AutomaticOpening = false;
+ }
+ }
+}
+
--- /dev/null
+//
+// MenuItem.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.Xml.Serialization;
+using System.ComponentModel;
+
+namespace Crow
+{
+ public class MenuItem : Menu
+ {
+ #region CTOR
+ protected MenuItem () : base(){}
+ public MenuItem (Interface iface) : base(iface) {}
+ #endregion
+
+ public event EventHandler Open;
+ public event EventHandler Close;
+
+ Command command;
+ Picture icon;
+ bool isOpened;
+ Measure popWidth, popHeight;
+
+ #region Public properties
+ [DefaultValue(false)]
+ public bool IsOpened {
+ get { return isOpened; }
+ set {
+ if (isOpened == value)
+ return;
+ isOpened = value;
+ NotifyValueChanged ("IsOpened", isOpened);
+
+ if (isOpened) {
+ onOpen (this, null);
+ if (LogicalParent is Menu)
+ (LogicalParent as Menu).AutomaticOpening = true;
+ }else
+ onClose (this, null);
+ }
+ }
+ [DefaultValue(null)]
+ public virtual Command Command {
+ get { return command; }
+ set {
+ if (command == value)
+ return;
+
+ if (command != null) {
+ command.raiseAllValuesChanged ();
+ command.ValueChanged -= Command_ValueChanged;
+ }
+
+ command = value;
+
+ if (command != null) {
+ command.ValueChanged += Command_ValueChanged;
+ command.raiseAllValuesChanged ();
+ }
+
+ NotifyValueChanged ("Command", command);
+ }
+ }
+
+ public override bool IsEnabled {
+ get { return Command == null ? base.IsEnabled : Command.CanExecute; }
+ set { base.IsEnabled = value; }
+ }
+
+ public override string Caption {
+ get { return Command == null ? base.Caption : Command.Caption; }
+ set { base.Caption = value; }
+ }
+
+ public Picture Icon {
+ get { return Command == null ? icon : Command.Icon;; }
+ set {
+ if (icon == value)
+ return;
+ icon = value;
+ if (command == null)
+ NotifyValueChanged ("Icon", icon);
+ }
+ }
+ [DefaultValue("Fit")]
+ public virtual Measure PopWidth {
+ get { return popWidth; }
+ set {
+ if (popWidth == value)
+ return;
+ popWidth = value;
+ NotifyValueChanged ("PopWidth", popWidth);
+ }
+ }
+ [DefaultValue("Fit")]
+ public virtual Measure PopHeight {
+ get { return popHeight; }
+ set {
+ if (popHeight == value)
+ return;
+ popHeight = value;
+ NotifyValueChanged ("PopHeight", popHeight);
+ }
+ }
+ #endregion
+
+ public override void AddItem (Widget g)
+ {
+ base.AddItem (g);
+ g.NotifyValueChanged ("PopDirection", Alignment.Right);
+ }
+
+ void Command_ValueChanged (object sender, ValueChangeEventArgs e)
+ {
+ string mName = e.MemberName;
+ if (mName == "CanExecute")
+ mName = "IsEnabled";
+ NotifyValueChanged (mName, e.NewValue);
+ }
+ protected virtual void onOpen (object sender, EventArgs e){
+ Open.Raise (this, null);
+ }
+ protected virtual void onClose (object sender, EventArgs e){
+ System.Diagnostics.Debug.WriteLine ("close: " + this.ToString());
+ Close.Raise (this, null);
+ }
+ public override bool MouseIsIn (Point m)
+ {
+ return IsEnabled && !IsDragged ? base.MouseIsIn (m) || child.MouseIsIn (m) : false;
+ }
+ public override void onMouseEnter (object sender, MouseMoveEventArgs e)
+ {
+ base.onMouseEnter (sender, e);
+ Menu menu = LogicalParent as Menu;
+ if (menu == null)
+ return;
+ if (menu.AutomaticOpening && items.Children.Count>0)
+ IsOpened = true;
+ }
+ public override void onMouseLeave (object sender, MouseMoveEventArgs e)
+ {
+ if (IsOpened)
+ IsOpened = false;
+ base.onMouseLeave (this, e);
+ }
+ public override void onMouseClick (object sender, MouseButtonEventArgs e)
+ {
+#if DEBUG_FOCUS
+ System.Diagnostics.Debug.WriteLine ("MENU CLICK => " + this.ToString ());
+#endif
+ if (command != null) {
+ command.Execute ();
+ closeMenu ();
+ }
+ if (hasClick)
+ base.onMouseClick (sender, e);
+
+ if (!IsOpened)
+ (LogicalParent as Menu).AutomaticOpening = false;
+ }
+ void closeMenu () {
+ MenuItem tmp = LogicalParent as MenuItem;
+ while (tmp != null) {
+ tmp.IsOpened = false;
+ tmp.Background = Color.Transparent;
+ tmp.AutomaticOpening = false;
+ tmp = tmp.LogicalParent as MenuItem;
+ }
+ }
+ }
+}
+
--- /dev/null
+//
+// MessageBox.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.Xml.Serialization;
+using System.ComponentModel;
+
+namespace Crow
+{
+ public class MessageBox : Window
+ {
+ #region CTOR
+ protected MessageBox () : base(){}
+ public MessageBox (Interface iface) : base(iface){}
+ #endregion
+
+ public enum Type {
+ None,
+ Information,
+ Alert,
+ Error,
+ YesNo,
+ YesNoCancel,
+
+ }
+
+ protected override void loadTemplate (Widget template)
+ {
+ base.loadTemplate (template);
+ NotifyValueChanged ("MsgIcon", "#Crow.Icons.iconInfo.svg");
+ }
+ string message, okMessage, cancelMessage, noMessage;
+ Type msgType = Type.None;
+
+ public event EventHandler Yes;
+ public event EventHandler No;
+ public event EventHandler Cancel;
+
+ [DefaultValue("Informations")]
+ public virtual string Message
+ {
+ get { return message; }
+ set {
+ if (message == value)
+ return;
+ message = value;
+ NotifyValueChanged ("Message", message);
+ }
+ }
+ [DefaultValue("Ok")]
+ public virtual string OkMessage
+ {
+ get { return okMessage; }
+ set {
+ if (okMessage == value)
+ return;
+ okMessage = value;
+ NotifyValueChanged ("OkMessage", okMessage);
+ }
+ }
+ [DefaultValue("Cancel")]
+ public virtual string CancelMessage
+ {
+ get { return cancelMessage; }
+ set {
+ if (cancelMessage == value)
+ return;
+ cancelMessage = value;
+ NotifyValueChanged ("CancelMessage", cancelMessage);
+ }
+ }
+ [DefaultValue("No")]
+ public virtual string NoMessage
+ {
+ get { return noMessage; }
+ set {
+ if (noMessage == value)
+ return;
+ noMessage = value;
+ NotifyValueChanged ("NoMessage", noMessage);
+ }
+ }
+ [DefaultValue("Information")]
+ public virtual Type MsgType
+ {
+ get { return msgType; }
+ set {
+ if (msgType == value)
+ return;
+ msgType = value;
+ NotifyValueChanged ("MsgType", msgType);
+ switch (msgType) {
+ case Type.Information:
+ MsgIcon = "#Crow.Icons.iconInfo.svg";
+ Caption = "Informations";
+ OkMessage = "Ok";
+ NotifyValueChanged ("CancelButIsVisible", false);
+ NotifyValueChanged ("NoButIsVisible", false);
+ break;
+ case Type.YesNo:
+ case Type.YesNoCancel:
+ MsgIcon = "#Crow.Icons.question.svg";
+ Caption = "Choice";
+ OkMessage = "Yes";
+ NoMessage = "No";
+ NotifyValueChanged ("CancelButIsVisible", msgType == Type.YesNoCancel);
+ NotifyValueChanged ("NoButIsVisible", true);
+ break;
+ case Type.Alert:
+ MsgIcon = "#Crow.Icons.IconAlerte.svg";
+ Caption = "Alert";
+ OkMessage = "Ok";
+ CancelMessage = "Cancel";
+ NotifyValueChanged ("CancelButIsVisible", true);
+ NotifyValueChanged ("NoButIsVisible", false);
+ break;
+ case Type.Error:
+ MsgIcon = "#Crow.Icons.exit.svg";
+ Caption = "Error";
+ OkMessage = "Ok";
+ NotifyValueChanged ("CancelButIsVisible", false);
+ NotifyValueChanged ("NoButIsVisible", false);
+ break;
+ }
+ }
+ }
+
+ string msgIcon = null;
+ public string MsgIcon {
+ get { return msgIcon; }
+ set {
+ if (value == MsgIcon)
+ return;
+ msgIcon = value;
+ NotifyValueChanged ("MsgIcon", MsgIcon);
+ }
+ }
+ void onOkButtonClick (object sender, EventArgs e)
+ {
+ Yes.Raise (this, null);
+ close ();
+ }
+ void onNoButtonClick (object sender, EventArgs e)
+ {
+ No.Raise (this, null);
+ close ();
+ }
+ void onCancelButtonClick (object sender, EventArgs e)
+ {
+ Cancel.Raise (this, null);
+ close ();
+ }
+ public static MessageBox Show (Interface iface, Type msgBoxType, string message, string okMsg = "", string cancelMsg = ""){
+ lock (iface.UpdateMutex) {
+ MessageBox mb = new MessageBox (iface);
+ mb.IFace.AddWidget (mb);
+ mb.MsgType = msgBoxType;
+ mb.Message = message;
+ if (!string.IsNullOrEmpty(okMsg))
+ mb.OkMessage = okMsg;
+ if (!string.IsNullOrEmpty(cancelMsg))
+ mb.CancelMessage = cancelMsg;
+ return mb;
+ }
+ }
+ public static MessageBox ShowModal (Interface iface, Type msgBoxType, string message){
+ lock (iface.UpdateMutex) {
+ MessageBox mb = new MessageBox (iface) {
+ Modal = true,
+ MsgType = msgBoxType,
+ Message = message
+ };
+
+ iface.AddWidget (mb);
+ return mb;
+ }
+ }
+ }
+}
+
--- /dev/null
+//
+// NumericControl.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.Xml.Serialization;
+using System.ComponentModel;
+
+namespace Crow
+{
+ public abstract class NumericControl : TemplatedControl
+ {
+ #region CTOR
+ protected NumericControl () : base(){}
+ public NumericControl (Interface iface) : base(iface)
+ {
+ }
+// public NumericControl(double minimum, double maximum, double step)
+// : base()
+// {
+// }
+ #endregion
+
+ #region protected fields
+ protected double _actualValue, minValue, maxValue, smallStep, bigStep;
+ protected int _decimals;
+ #endregion
+
+ #region public properties
+ [DefaultValue(2)]
+ public int Decimals
+ {
+ get { return _decimals; }
+ set
+ {
+ if (value == _decimals)
+ return;
+ _decimals = value;
+ NotifyValueChanged("Decimals", _decimals);
+ RegisterForGraphicUpdate();
+ }
+ }
+ [DefaultValue(0.0)]
+ public virtual double Minimum {
+ get { return minValue; }
+ set {
+ if (minValue == value)
+ return;
+
+ minValue = value;
+ NotifyValueChanged ("Minimum", minValue);
+ RegisterForRedraw ();
+ }
+ }
+ [DefaultValue(100.0)]
+ public virtual double Maximum
+ {
+ get { return maxValue; }
+ set {
+ if (maxValue == value)
+ return;
+
+ maxValue = value;
+ NotifyValueChanged ("Maximum", maxValue);
+ RegisterForRedraw ();
+ }
+ }
+ [DefaultValue(1.0)]
+ public virtual double SmallIncrement
+ {
+ get { return smallStep; }
+ set {
+ if (smallStep == value)
+ return;
+
+ smallStep = value;
+ NotifyValueChanged ("SmallIncrement", smallStep);
+ RegisterForRedraw ();
+ }
+ }
+ [DefaultValue(5.0)]
+ public virtual double LargeIncrement
+ {
+ get { return bigStep; }
+ set {
+ if (bigStep == value)
+ return;
+
+ bigStep = value;
+ NotifyValueChanged ("LargeIncrement", bigStep);
+ RegisterForRedraw ();
+ }
+ }
+ [DefaultValue(0.0)]
+ public virtual double Value
+ {
+ get { return _actualValue; }
+ set
+ {
+ if (value == _actualValue)
+ return;
+
+ if (value < minValue)
+ _actualValue = minValue;
+ else if (value > maxValue)
+ _actualValue = maxValue;
+ else
+ _actualValue = value;
+
+ _actualValue = Math.Round (_actualValue, _decimals);
+
+ NotifyValueChanged("Value", _actualValue);
+ RegisterForGraphicUpdate();
+ }
+ }
+ #endregion
+
+ }
+}
+
--- /dev/null
+//
+// Popper.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.Xml.Serialization;
+using System.ComponentModel;
+
+namespace Crow
+{
+ public class Popper : TemplatedContainer
+ {
+ #region CTOR
+ protected Popper () : base(){}
+ public Popper (Interface iface) : base(iface){}
+ #endregion
+
+ bool _isPopped, _canPop;
+ Alignment popDirection;
+ Widget _content;
+ Measure popWidth, popHeight;
+
+ public event EventHandler Popped;
+ public event EventHandler Unpoped;
+
+ #region Public Properties
+ [DefaultValue("Fit")]
+ public virtual Measure PopWidth {
+ get { return popWidth; }
+ set {
+ if (popWidth == value)
+ return;
+ popWidth = value;
+ NotifyValueChanged ("PopWidth", popWidth);
+ }
+ }
+ [DefaultValue("Fit")]
+ public virtual Measure PopHeight {
+ get { return popHeight; }
+ set {
+ if (popHeight == value)
+ return;
+ popHeight = value;
+ NotifyValueChanged ("PopHeight", popHeight);
+ }
+ }
+ [DefaultValue(false)]
+ public bool IsPopped
+ {
+ get { return _isPopped; }
+ set
+ {
+ if (!_canPop & value)
+ return;
+
+ if (value == _isPopped)
+ return;
+
+ _isPopped = value;
+
+ NotifyValueChanged ("IsPopped", _isPopped);
+
+ if (_isPopped)
+ onPop (this, null);
+ else
+ onUnpop (this, null);
+
+ }
+ }
+ [DefaultValue(true)]
+ public bool CanPop
+ {
+ get { return _canPop; }
+ set
+ {
+ if (value == _canPop)
+ return;
+
+ _canPop = value;
+ NotifyValueChanged ("CanPop", _canPop);
+ }
+ }
+ [DefaultValue(Alignment.Bottom)]
+ public virtual Alignment PopDirection {
+ get { return popDirection; }
+ set {
+ if (popDirection == value)
+ return;
+ popDirection = value;
+ NotifyValueChanged ("PopDirection", popDirection);
+ }
+ }
+ #endregion
+
+ public override Widget Content {
+ get { return _content; }
+ set {
+ if (_content != null) {
+ _content.LogicalParent = null;
+ //_content.isPopup = false;
+ _content.LayoutChanged -= _content_LayoutChanged;
+ }
+
+ _content = value;
+
+ if (_content == null)
+ return;
+
+ _content.LogicalParent = this;
+ //_content.isPopup = true;
+ _content.HorizontalAlignment = HorizontalAlignment.Left;
+ _content.VerticalAlignment = VerticalAlignment.Top;
+ _content.LayoutChanged += _content_LayoutChanged;
+ }
+ }
+ void positionContent(LayoutingType lt){
+ ILayoutable tc = Content.Parent;
+ if (tc == null)
+ return;
+ Rectangle r = this.ScreenCoordinates (this.Slot);
+ if (lt == LayoutingType.X) {
+ if (popDirection.HasFlag (Alignment.Right)) {
+ if (r.Right + Content.Slot.Width > tc.ClientRectangle.Right)
+ Content.Left = r.Left - Content.Slot.Width;
+ else
+ Content.Left = r.Right;
+ } else if (popDirection.HasFlag (Alignment.Left)) {
+ if (r.Left - Content.Slot.Width < tc.ClientRectangle.Left)
+ Content.Left = r.Right;
+ else
+ Content.Left = r.Left - Content.Slot.Width;
+ } else {
+ if (Content.Slot.Width < tc.ClientRectangle.Width) {
+ if (r.Left + Content.Slot.Width > tc.ClientRectangle.Right)
+ Content.Left = tc.ClientRectangle.Right - Content.Slot.Width;
+ else
+ Content.Left = r.Left;
+ } else
+ Content.Left = 0;
+ }
+ }else if (lt == LayoutingType.Y) {
+ if (Content.Slot.Height < tc.ClientRectangle.Height) {
+ if (PopDirection.HasFlag (Alignment.Bottom)) {
+ if (r.Bottom + Content.Slot.Height > tc.ClientRectangle.Bottom)
+ Content.Top = r.Top - Content.Slot.Height;
+ else
+ Content.Top = r.Bottom;
+ } else if (PopDirection.HasFlag (Alignment.Top)) {
+ if (r.Top - Content.Slot.Height < tc.ClientRectangle.Top)
+ Content.Top = r.Bottom;
+ else
+ Content.Top = r.Top - Content.Slot.Height;
+ } else
+ Content.Top = r.Top;
+ }else
+ Content.Top = 0;
+ }
+ }
+ protected void _content_LayoutChanged (object sender, LayoutingEventArgs e)
+ {
+ if (e.LayoutType.HasFlag (LayoutingType.Width))
+ positionContent (LayoutingType.X);
+ if (e.LayoutType.HasFlag(LayoutingType.Height))
+ positionContent (LayoutingType.Y);
+ }
+
+ #region GraphicObject overrides
+ public override void onMouseLeave (object sender, MouseMoveEventArgs e)
+ {
+ base.onMouseLeave (this, e);
+ IsPopped = false;
+ }
+ public override bool MouseIsIn (Point m)
+ {
+ if (Content?.Parent != null)
+ if (Content.MouseIsIn (m))
+ return true;
+ return base.MouseIsIn (m);
+ }
+ public override void checkHoverWidget (MouseMoveEventArgs e)
+ {
+ if (IFace.HoverWidget != this) {
+ IFace.HoverWidget = this;
+ onMouseEnter (this, e);
+ }
+ if (Content != null){
+ if (Content.Parent != null) {
+ if (Content.MouseIsIn (e.Position)) {
+ Content.checkHoverWidget (e);
+ return;
+ }
+ }
+ }
+ base.checkHoverWidget (e);
+ }
+ #endregion
+
+ public virtual void onPop(object sender, EventArgs e)
+ {
+ if (Content != null) {
+ Content.Visible = true;
+ if (Content.Parent == null)
+ IFace.AddWidget (Content);
+ //if (Content.LogicalParent != this)
+ Content.LogicalParent = this;
+ IFace.PutOnTop (Content, true);
+ _content_LayoutChanged (this, new LayoutingEventArgs (LayoutingType.Sizing));
+ }
+ Popped.Raise (this, e);
+ }
+ public virtual void onUnpop(object sender, EventArgs e)
+ {
+ if (Content != null) {
+ Content.Visible = false;
+ }
+ Unpoped.Raise (this, e);
+ }
+
+ protected override void Dispose (bool disposing)
+ {
+ if (_content != null && disposing) {
+ if (_content.Parent == null)
+ _content.Dispose ();
+ }
+ base.Dispose (disposing);
+ }
+ }
+}
--- /dev/null
+//
+// PrivateContainer.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.Xml.Serialization;
+using System.ComponentModel;
+using Crow.Cairo;
+
+namespace Crow
+{
+ /// <summary>
+ /// Implement drawing and layouting for a single child, but
+ /// does not expose child to allow reuse of container
+ /// behaviour for widgets that have other xml hierarchy: example
+ /// TemplatedControl may have 3 children (template,templateItem,content) but
+ /// behave exactely as a container for layouting and drawing
+ /// </summary>
+ [DesignIgnore]
+ public class PrivateContainer : Widget
+ {
+ #region CTOR
+ protected PrivateContainer () : base(){}
+ public PrivateContainer (Interface iface) : base(iface){}
+ #endregion
+
+ #if DESIGN_MODE
+ public override bool FindByDesignID(string designID, out Widget go){
+ go = null;
+ if (base.FindByDesignID (designID, out go))
+ return true;
+ if (child == null)
+ return false;
+ return child.FindByDesignID (designID, out go);
+ }
+ #endif
+ protected Widget child;
+ #if DEBUG_LOG
+ internal GraphicObject getTemplateRoot {
+ get { return child; }
+ }
+ #endif
+
+ protected virtual void SetChild(Widget _child)
+ {
+
+ if (child != null) {
+ //check if HoverWidget is removed from Tree
+ if (IFace.HoverWidget != null) {
+ if (this.Contains (IFace.HoverWidget))
+ IFace.HoverWidget = null;
+ }
+ contentSize = default(Size);
+ child.LayoutChanged -= OnChildLayoutChanges;
+ this.RegisterForGraphicUpdate ();
+ child.Dispose ();
+ }
+
+ child = _child as Widget;
+
+ if (child != null) {
+ child.Parent = this;
+ child.LayoutChanged += OnChildLayoutChanges;
+ contentSize = child.Slot.Size;
+ child.RegisteredLayoutings = LayoutingType.None;
+ child.RegisterForLayouting (LayoutingType.Sizing);
+ }
+ }
+ //dispose child if not null
+ protected virtual void deleteChild () {
+ Widget g = child;
+ SetChild (null);
+ if (g != null)
+ g.Dispose ();
+ }
+
+ #region GraphicObject Overrides
+
+ public override Widget FindByName (string nameToFind)
+ {
+ if (Name == nameToFind)
+ return this;
+
+ return child == null ? null : child.FindByName (nameToFind);
+ }
+ public override bool Contains (Widget goToFind)
+ {
+ return child == goToFind ? true :
+ child == null ? false : child.Contains(goToFind);
+ }
+ public override void OnDataSourceChanged (object sender, DataSourceChangeEventArgs e)
+ {
+ base.OnDataSourceChanged (this, e);
+ if (child != null)
+ if (child.localDataSourceIsNull & child.localLogicalParentIsNull)
+ child.OnDataSourceChanged (child, e);
+ }
+ public override bool UpdateLayout (LayoutingType layoutType)
+ {
+ if (child != null) {
+ //force sizing to fit if sizing on children and child has stretched size
+ switch (layoutType) {
+ case LayoutingType.Width:
+ if (Width == Measure.Fit && child.Width.IsRelativeToParent)
+ child.Width = Measure.Fit;
+ break;
+ case LayoutingType.Height:
+ if (Height == Measure.Fit && child.Height.IsRelativeToParent)
+ child.Height = Measure.Fit;
+ break;
+ }
+ }
+ return base.UpdateLayout (layoutType);
+ }
+ public override void OnLayoutChanges (LayoutingType layoutType)
+ {
+ base.OnLayoutChanges (layoutType);
+
+ if (child == null)
+ return;
+
+ LayoutingType ltChild = LayoutingType.None;
+
+ if (layoutType == LayoutingType.Width) {
+ if (child.Width.IsRelativeToParent) {
+ ltChild |= LayoutingType.Width;
+ if (child.Width.Value < 100 && child.Left == 0)
+ ltChild |= LayoutingType.X;
+ } else if (child.Left == 0)
+ ltChild |= LayoutingType.X;
+ } else if (layoutType == LayoutingType.Height) {
+ if (child.Height.IsRelativeToParent) {
+ ltChild |= LayoutingType.Height;
+ if (child.Height.Value < 100 && child.Top == 0)
+ ltChild |= LayoutingType.Y;
+ } else if (child.Top == 0)
+ ltChild |= LayoutingType.Y;
+ }
+ if (ltChild == LayoutingType.None)
+ return;
+ child.RegisterForLayouting (ltChild);
+ }
+ public virtual void OnChildLayoutChanges (object sender, LayoutingEventArgs arg)
+ {
+ Widget g = sender as Widget;
+
+ if (arg.LayoutType == LayoutingType.Width) {
+ if (Width != Measure.Fit)
+ return;
+ contentSize.Width = g.Slot.Width;
+ this.RegisterForLayouting (LayoutingType.Width);
+ }else if (arg.LayoutType == LayoutingType.Height){
+ if (Height != Measure.Fit)
+ return;
+ contentSize.Height = g.Slot.Height;
+ this.RegisterForLayouting (LayoutingType.Height);
+ }
+ }
+ protected override void onDraw (Context gr)
+ {
+ base.onDraw (gr);
+
+ gr.Save ();
+
+ if (ClipToClientRect) {
+ //clip to client zone
+ CairoHelpers.CairoRectangle (gr, ClientRectangle, CornerRadius);
+ gr.Clip ();
+ }
+
+ if (child != null) {
+ if (child.Visible)
+ child.Paint (ref gr);
+ }
+ gr.Restore ();
+ }
+ protected override void UpdateCache (Context ctx)
+ {
+ Rectangle rb = Slot + Parent.ClientRectangle.Position;
+
+
+ Context gr = new Context (bmp);
+
+ if (!Clipping.IsEmpty) {
+ for (int i = 0; i < Clipping.NumRectangles; i++)
+ gr.Rectangle(Clipping.GetRectangle(i));
+ gr.ClipPreserve();
+ gr.Operator = Operator.Clear;
+ gr.Fill();
+ gr.Operator = Operator.Over;
+
+ onDraw (gr);
+ }
+
+ gr.Dispose ();
+
+ ctx.SetSourceSurface (bmp, rb.X, rb.Y);
+ ctx.Paint ();
+ Clipping.Dispose();
+ Clipping = new Region ();
+ }
+ #endregion
+
+ #region Mouse handling
+ public override void checkHoverWidget (MouseMoveEventArgs e)
+ {
+ base.checkHoverWidget (e);
+
+ if (child != null)
+ if (child.MouseIsIn (e.Position))
+ child.checkHoverWidget (e);
+ }
+ #endregion
+
+ protected override void Dispose (bool disposing)
+ {
+ if (disposing && child != null)
+ child.Dispose ();
+ base.Dispose (disposing);
+ }
+ }
+}
+
--- /dev/null
+//
+// ProgressBar.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.Linq;
+using System.Text;
+using Crow.Cairo;
+using System.Diagnostics;
+using System.Xml.Serialization;
+using System.ComponentModel;
+
+namespace Crow
+{
+
+ public class ProgressBar : NumericControl
+ {
+ #region CTOR
+ protected ProgressBar () : base(){}
+ public ProgressBar(Interface iface) : base(iface){}
+ #endregion
+
+ protected override void loadTemplate (Widget template)
+ {
+
+ }
+
+ #region GraphicObject overrides
+ protected override void onDraw (Context gr)
+ {
+ base.onDraw (gr);
+
+ if (Maximum == 0)
+ return;
+
+ Rectangle rBack = ClientRectangle;
+ rBack.Width = (int)((double)rBack.Width / Maximum * Value);
+ Foreground.SetAsSource (gr, rBack);
+
+ CairoHelpers.CairoRectangle(gr,rBack,CornerRadius);
+ gr.Fill();
+ }
+ #endregion
+ }
+}
--- /dev/null
+//
+// RadioButton.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.ComponentModel;
+using System.Xml.Serialization;
+
+namespace Crow
+{
+ public class RadioButton : TemplatedControl
+ {
+ bool isChecked;
+
+ #region CTOR
+ protected RadioButton () : base(){}
+ public RadioButton(Interface iface) : base(iface){}
+ #endregion
+
+ public event EventHandler Checked;
+ public event EventHandler Unchecked;
+
+ #region GraphicObject overrides
+ public override void onMouseDown (object sender, MouseButtonEventArgs e)
+ {
+ Group pg = Parent as Group;
+ if (pg != null) {
+ for (int i = 0; i < pg.Children.Count; i++) {
+ RadioButton c = pg.Children [i] as RadioButton;
+ if (c == null)
+ continue;
+ c.IsChecked = (c == this);
+ }
+ } else
+ IsChecked = !IsChecked;
+
+ base.onMouseDown (sender, e);
+ }
+ #endregion
+
+ [DefaultValue(false)]
+ public bool IsChecked
+ {
+ get { return isChecked; }
+ set
+ {
+ if (isChecked == value)
+ return;
+
+ isChecked = value;
+
+ NotifyValueChanged ("IsChecked", value);
+
+ if (isChecked)
+ Checked.Raise (this, null);
+ else
+ Unchecked.Raise (this, null);
+ }
+ }
+ }
+}
--- /dev/null
+//
+// SaturationValueSelector.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 Crow.Cairo;
+using System.Xml.Serialization;
+
+namespace Crow
+{
+ [DesignIgnore]
+ public class SaturationValueSelector : ColorSelector
+ {
+ public SaturationValueSelector () : base(){}
+ public SaturationValueSelector (Interface iface) : base(iface)
+ {
+ }
+
+ double v, s;
+
+ public virtual double V {
+ get { return v; }
+ set {
+ if (v == value)
+ return;
+ v = value;
+ NotifyValueChanged ("V", v);
+ mousePos.Y = (int)Math.Floor((1.0-v) * (double)ClientRectangle.Height);
+
+ RegisterForRedraw ();
+ }
+ }
+
+ public virtual double S {
+ get { return s; }
+ set {
+ if (s == value)
+ return;
+ s = value;
+ NotifyValueChanged ("S", s);
+ mousePos.X = (int)Math.Floor(s * (double)ClientRectangle.Width);
+
+ RegisterForRedraw ();
+ }
+ }
+ protected override void onDraw (Context gr)
+ {
+ base.onDraw (gr);
+
+ Rectangle r = ClientRectangle;
+
+ if (Foreground != null) {//TODO:test if null should be removed
+ Foreground.SetAsSource (gr, r);
+ CairoHelpers.CairoRectangle (gr, r, CornerRadius);
+ gr.Fill ();
+ }
+
+ Crow.Gradient grad = new Gradient (Gradient.Type.Horizontal);
+ grad.Stops.Add (new Gradient.ColorStop (0, new Color (1, 1, 1, 1)));
+ grad.Stops.Add (new Gradient.ColorStop (1, new Color (1, 1, 1, 0)));
+ grad.SetAsSource (gr, r);
+ CairoHelpers.CairoRectangle (gr, r, CornerRadius);
+ gr.Fill();
+ grad = new Gradient (Gradient.Type.Vertical);
+ grad.Stops.Add (new Gradient.ColorStop (0, new Color (0, 0, 0, 0)));
+ grad.Stops.Add (new Gradient.ColorStop (1, new Color (0, 0, 0, 1)));
+ grad.SetAsSource (gr, r);
+ CairoHelpers.CairoRectangle (gr, r, CornerRadius);
+ gr.Fill();
+
+
+ gr.Arc (mousePos.X, mousePos.Y, 3.5, 0, Math.PI * 2.0);
+ gr.SetSourceColor (Color.Black);
+ gr.LineWidth = 2.0;
+ gr.StrokePreserve ();
+ gr.SetSourceColor (Color.White);
+ gr.LineWidth = 1.0;
+ gr.Stroke ();
+ }
+
+ //public override void Paint (ref Context ctx)
+ //{
+ // base.Paint (ref ctx);
+
+ // Rectangle rb = Slot + Parent.ClientRectangle.Position;
+ // ctx.Save ();
+
+ // ctx.Translate (rb.X, rb.Y);
+
+ // ctx.SetSourceColor (Color.DimGrey);
+ // ctx.Arc (mousePos.X, mousePos.Y, 3.5, 0, Math.PI * 2.0);
+ // ctx.LineWidth = 0.5;
+ // ctx.Stroke ();
+ // ctx.Translate (-0.5, -0.5);
+ // ctx.Arc (mousePos.X, mousePos.Y, 3.5, 0, Math.PI * 2.0);
+ // ctx.SetSourceColor (Color.White);
+ // ctx.Stroke ();
+
+ // ctx.Restore ();
+ //}
+
+ protected override void updateMouseLocalPos (Point mPos)
+ {
+ base.updateMouseLocalPos (mPos);
+
+ Rectangle cb = ClientRectangle;
+ s = (double)mousePos.X / (double)cb.Width;
+ v = 1.0 - (double)mousePos.Y / (double)cb.Height;
+ NotifyValueChanged ("S", s);
+ NotifyValueChanged ("V", v);
+
+ RegisterForRedraw ();
+ }
+ public override void OnLayoutChanges (LayoutingType layoutType)
+ {
+ base.OnLayoutChanges (layoutType);
+ switch (layoutType) {
+ case LayoutingType.Width:
+ mousePos.X = (int)Math.Floor(s * (double)ClientRectangle.Width);
+ break;
+ case LayoutingType.Height:
+ mousePos.Y = (int)Math.Floor((1.0-v) * (double)ClientRectangle.Height);
+ break;
+ }
+ }
+ }
+}
+
--- /dev/null
+//
+// ScrollBar.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.Xml.Serialization;
+using System.ComponentModel;
+
+namespace Crow
+{
+ /// <summary>
+ /// templeted numeric control
+ /// </summary>
+ public class ScrollBar : NumericControl
+ {
+ //TODO:could be replaced by a template for a Slider
+
+ Orientation _orientation;
+ int _cursorSize;
+
+ #region CTOR
+ protected ScrollBar () : base(){}
+ public ScrollBar(Interface iface) : base(iface) {}
+ #endregion
+
+ [DefaultValue(Orientation.Vertical)]
+ public virtual Orientation Orientation
+ {
+ get { return _orientation; }
+ set {
+ if (_orientation == value)
+ return;
+ _orientation = value;
+ NotifyValueChanged ("Orientation", _orientation);
+ if (_orientation == Orientation.Horizontal)
+ NotifyValueChanged ("ScrollBackShape", "M 1.5,3.5 L 6.5,0.5 L 6.5,6.5 Z");
+ else
+ NotifyValueChanged ("ScrollBackShape", "M 4.5,0.5 L 9.5,9.5 L 0.5,9.5 Z");
+
+ RegisterForGraphicUpdate ();
+ }
+ }
+ [DefaultValue(20)]
+ public virtual int CursorSize {
+ get { return _cursorSize; }
+ set {
+ if (_cursorSize == value)
+ return;
+ _cursorSize = value;
+ RegisterForGraphicUpdate ();
+ NotifyValueChanged ("CursorSize", _cursorSize);
+ }
+ }
+ public void onScrollBack (object sender, MouseButtonEventArgs e)
+ {
+ Value -= SmallIncrement;
+ }
+ public void onScrollForth (object sender, MouseButtonEventArgs e)
+ {
+ Value += SmallIncrement;
+ }
+
+ public void onSliderValueChange(object sender, ValueChangeEventArgs e){
+ if (e.MemberName == "Value")
+ Value = Convert.ToDouble(e.NewValue);
+ }
+ }
+}
--- /dev/null
+//
+// Scroller.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.Xml.Serialization;
+using System.ComponentModel;
+using System.Diagnostics;
+using Crow.Cairo;
+
+namespace Crow
+{
+ /// <summary>
+ /// scrolling surface, to be contained in a smaller container in which it will be scrolled
+ /// </summary>
+ public class Scroller : Container
+ {
+ #region CTOR
+ protected Scroller () : base(){}
+ public Scroller (Interface iface) : base(iface){}
+ #endregion
+
+ //public event EventHandler<ScrollingEventArgs> Scrolled;
+
+ int scrollX, scrollY, maxScrollX, maxScrollY, scrollSpeed;
+
+ /// <summary>
+ /// if true, key stroke are handled in derrived class
+ /// </summary>
+ protected bool KeyEventsOverrides = false;
+
+ #region public properties
+ /// <summary> Horizontal Scrolling Position </summary>
+ [DefaultValue(0)]
+ public virtual int ScrollX {
+ get { return scrollX; }
+ set {
+ if (scrollX == value)
+ return;
+
+ int newS = value;
+ if (newS < 0)
+ newS = 0;
+ else if (newS > maxScrollX)
+ newS = maxScrollX;
+
+ if (newS == scrollX)
+ return;
+
+ scrollX = value;
+
+ NotifyValueChanged ("ScrollX", scrollX);
+ RegisterForGraphicUpdate ();
+ }
+ }
+ /// <summary> Vertical Scrolling Position </summary>
+ [DefaultValue(0)]
+ public virtual int ScrollY {
+ get { return scrollY; }
+ set {
+ if (scrollY == value)
+ return;
+
+ int newS = value;
+ if (newS < 0)
+ newS = 0;
+ else if (newS > maxScrollY)
+ newS = maxScrollY;
+
+ if (newS == scrollY)
+ return;
+
+ scrollY = value;
+
+ NotifyValueChanged ("ScrollY", scrollY);
+ RegisterForGraphicUpdate ();
+ }
+ }
+ /// <summary> Horizontal Scrolling maximum value </summary>
+ [DefaultValue(0)]
+ public virtual int MaxScrollX {
+ get { return maxScrollX; }
+ set {
+ if (maxScrollX == value)
+ return;
+
+ maxScrollX = value;
+
+ if (scrollX > maxScrollX)
+ ScrollX = maxScrollX;
+
+ NotifyValueChanged ("MaxScrollX", maxScrollX);
+ RegisterForGraphicUpdate ();
+ }
+ }
+ /// <summary> Vertical Scrolling maximum value </summary>
+ [DefaultValue(0)]
+ public virtual int MaxScrollY {
+ get { return maxScrollY; }
+ set {
+ if (maxScrollY == value)
+ return;
+
+ maxScrollY = value;
+
+ if (scrollY > maxScrollY)
+ ScrollY = maxScrollY;
+
+ NotifyValueChanged ("MaxScrollY", maxScrollY);
+ RegisterForGraphicUpdate ();
+ }
+ }
+ /// <summary> Mouse Wheel Scrolling multiplier </summary>
+ [DefaultValue(50)]
+ public virtual int ScrollSpeed {
+ get { return scrollSpeed; }
+ set {
+ if (scrollSpeed == value)
+ return;
+
+ scrollSpeed = value;
+
+ NotifyValueChanged ("ScrollSpeed", scrollSpeed);
+ }
+ }
+ #endregion
+
+ public override void SetChild (Widget _child)
+ {
+ Group g = child as Group;
+ if (g != null)
+ g.ChildrenCleared -= onChildListCleared;
+
+ base.SetChild (_child);
+
+ g = _child as Group;
+ if (g != null)
+ g.ChildrenCleared += onChildListCleared;
+ }
+ public override void OnChildLayoutChanges (object sender, LayoutingEventArgs arg)
+ {
+ base.OnChildLayoutChanges (sender, arg);
+ updateMaxScroll (arg.LayoutType);
+ }
+
+
+ #region GraphicObject Overrides
+ public override Rectangle ScreenCoordinates (Rectangle r)
+ {
+ return base.ScreenCoordinates (r) - new Point((int)ScrollX,(int)ScrollY);
+ }
+ public override bool PointIsIn (ref Point m)
+ {
+ if (!base.PointIsIn(ref m))
+ return false;
+ if (!Slot.ContainsOrIsEqual (m) || child==null)
+ return false;
+ m += new Point (ScrollX, ScrollY);
+ return true;
+ }
+ public override void RegisterClip (Rectangle clip)
+ {
+ base.RegisterClip (clip - new Point(ScrollX,ScrollY));
+ }
+ public override void OnLayoutChanges (LayoutingType layoutType)
+ {
+ base.OnLayoutChanges (layoutType);
+
+ if (layoutType == LayoutingType.Height)
+ NotifyValueChanged ("PageHeight", Slot.Height);
+ else if (layoutType == LayoutingType.Width)
+ NotifyValueChanged ("PageWidth", Slot.Width);
+ else
+ return;
+ updateMaxScroll(layoutType);
+ }
+ protected override void onDraw (Context gr)
+ {
+ Rectangle rBack = new Rectangle (Slot.Size);
+
+ Background.SetAsSource (gr, rBack);
+ CairoHelpers.CairoRectangle(gr,rBack, CornerRadius);
+ gr.Fill ();
+
+ gr.Save ();
+ if (ClipToClientRect) {
+ //clip to scrolled client zone
+ CairoHelpers.CairoRectangle (gr, ClientRectangle, CornerRadius);
+ gr.Clip ();
+ }
+
+ gr.Translate (-ScrollX, -ScrollY);
+ if (child != null)
+ child.Paint (ref gr);
+ gr.Restore ();
+ }
+
+ #region Mouse & Keyboard
+ /// <summary> Process scrolling vertically, or if shift is down, vertically </summary>
+ public override void onMouseWheel (object sender, MouseWheelEventArgs e)
+ {
+ if (IFace.Shift)
+ ScrollX += e.Delta * ScrollSpeed;
+ else
+ ScrollY -= e.Delta * ScrollSpeed;
+ e.Handled = true;
+ base.onMouseWheel (sender, e);
+ }
+ /// <summary> Process scrolling with arrow keys, home and end keys. </summary>
+ public override void onKeyDown (object sender, KeyEventArgs e)
+ {
+ base.onKeyDown (sender, e);
+
+ if (KeyEventsOverrides)
+ return;
+
+ switch (e.Key) {
+ case Key.Up:
+ ScrollY--;
+ break;
+ case Key.Down:
+ ScrollY++;
+ break;
+ case Key.Left:
+ ScrollX--;
+ break;
+ case Key.Right:
+ ScrollX++;
+ break;
+ case Key.Home:
+ ScrollX = 0;
+ ScrollY = 0;
+ break;
+ case Key.End:
+ ScrollX = MaxScrollX;
+ ScrollY = MaxScrollY;
+ break;
+ }
+ }
+ #endregion
+
+ #endregion
+
+ void updateMaxScroll (LayoutingType lt){
+ if (Child == null) {
+ MaxScrollX = 0;
+ MaxScrollY = 0;
+ return;
+ }
+
+ Rectangle cb = ClientRectangle;
+
+ if (lt == LayoutingType.Height) {
+ MaxScrollY = child.Slot.Height - cb.Height;
+ if (child.Slot.Height > 0)
+ NotifyValueChanged ("ChildHeightRatio", Slot.Height * Slot.Height / child.Slot.Height);
+ } else if (lt == LayoutingType.Width) {
+ MaxScrollX = child.Slot.Width - cb.Width;
+ if (child.Slot.Width > 0)
+ NotifyValueChanged ("ChildWidthRatio", Slot.Width * Slot.Width / child.Slot.Width);
+ }
+ }
+ void onChildListCleared(object sender, EventArgs e){
+ ScrollY = 0;
+ ScrollX = 0;
+ }
+
+
+ }
+}
--- /dev/null
+//
+// ScrollingObject.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.Xml.Serialization;
+using System.ComponentModel;
+using System.Collections;
+using Crow.Cairo;
+
+
+namespace Crow
+{
+ /// <summary>
+ /// generic class to build scrolling control in both directions
+ /// </summary>
+ [DesignIgnore]
+ public class ScrollingObject : Widget
+ {
+ #region CTOR
+ protected ScrollingObject ():base(){}
+ public ScrollingObject (Interface iface):base(iface){}
+ #endregion
+
+ int scrollX, scrollY, maxScrollX, maxScrollY, mouseWheelSpeed;
+
+ /// <summary>
+ /// if true, key stroke are handled in derrived class
+ /// </summary>
+ protected bool KeyEventsOverrides = false;
+
+ /// <summary> Horizontal Scrolling Position </summary>
+ [DefaultValue(0)]
+ public virtual int ScrollX {
+ get { return scrollX; }
+ set {
+ if (scrollX == value)
+ return;
+
+ int newS = value;
+ if (newS < 0)
+ newS = 0;
+ else if (newS > maxScrollX)
+ newS = maxScrollX;
+
+ if (newS == scrollX)
+ return;
+
+ scrollX = newS;
+
+ NotifyValueChanged ("ScrollX", scrollX);
+ RegisterForGraphicUpdate ();
+ }
+ }
+ /// <summary> Vertical Scrolling Position </summary>
+ [DefaultValue(0)]
+ public virtual int ScrollY {
+ get { return scrollY; }
+ set {
+ if (scrollY == value)
+ return;
+
+ int newS = value;
+ if (newS < 0)
+ newS = 0;
+ else if (newS > maxScrollY)
+ newS = maxScrollY;
+
+ if (newS == scrollY)
+ return;
+
+ scrollY = newS;
+
+ NotifyValueChanged ("ScrollY", scrollY);
+ RegisterForGraphicUpdate ();
+ }
+ }
+ /// <summary> Horizontal Scrolling maximum value </summary>
+ [DefaultValue(0)]
+ public virtual int MaxScrollX {
+ get { return maxScrollX; }
+ set {
+ if (maxScrollX == value)
+ return;
+
+ maxScrollX = value;
+
+ if (scrollX > maxScrollX)
+ ScrollX = maxScrollX;
+
+ NotifyValueChanged ("MaxScrollX", maxScrollX);
+ RegisterForGraphicUpdate ();
+ }
+ }
+ /// <summary> Vertical Scrolling maximum value </summary>
+ [DefaultValue(0)]
+ public virtual int MaxScrollY {
+ get { return maxScrollY; }
+ set {
+ if (maxScrollY == value)
+ return;
+
+ maxScrollY = value;
+
+ if (scrollY > maxScrollY)
+ ScrollY = maxScrollY;
+
+ NotifyValueChanged ("MaxScrollY", maxScrollY);
+ RegisterForGraphicUpdate ();
+ }
+ }
+ /// <summary> Mouse Wheel Scrolling multiplier </summary>
+ [DefaultValue(1)]
+ public virtual int MouseWheelSpeed {
+ get { return mouseWheelSpeed; }
+ set {
+ if (mouseWheelSpeed == value)
+ return;
+
+ mouseWheelSpeed = value;
+
+ NotifyValueChanged ("MouseWheelSpeed", mouseWheelSpeed);
+ }
+ }
+
+ /// <summary> Process scrolling vertically, or if shift is down, vertically </summary>
+ public override void onMouseWheel (object sender, MouseWheelEventArgs e)
+ {
+ base.onMouseWheel (sender, e);
+ if (IFace.Shift)
+ ScrollX += e.Delta * MouseWheelSpeed;
+ else
+ ScrollY -= e.Delta * MouseWheelSpeed;
+ }
+ /// <summary> Process scrolling with arrow keys, home and end keys. </summary>
+ public override void onKeyDown (object sender, KeyEventArgs e)
+ {
+ base.onKeyDown (sender, e);
+
+ if (KeyEventsOverrides)
+ return;
+
+ switch (e.Key) {
+ case Key.Up:
+ ScrollY--;
+ break;
+ case Key.Down:
+ ScrollY++;
+ break;
+ case Key.Left:
+ ScrollX--;
+ break;
+ case Key.Right:
+ ScrollX++;
+ break;
+ case Key.Home:
+ ScrollX = 0;
+ ScrollY = 0;
+ break;
+ case Key.End:
+ ScrollX = MaxScrollX;
+ ScrollY = MaxScrollY;
+ break;
+ }
+ }
+ }
+}
+
--- /dev/null
+// Copyright (c) 2013-2019 Bruyère Jean-Philippe jp_bruyere@hotmail.com
+//
+// This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT)
+
+using System;
+using System.ComponentModel;
+using System.IO;
+using System.Text;
+using Crow.Cairo;
+
+namespace Crow
+{
+ public class PathParser : StringReader
+ {
+ public PathParser (string str) : base (str) {}
+
+ double readDouble () {
+ StringBuilder tmp = new StringBuilder();
+
+ while (Peek () >= 0) {
+ char c = (char)Read();
+ if (c.IsWhiteSpaceOrNewLine()) {
+ if (tmp.Length == 0)
+ continue;
+ else
+ break;
+ } else if (c == ',')
+ break;
+ tmp.Append (c);
+ }
+ return double.Parse (tmp.ToString ());
+ }
+ public void Draw (Context gr) {
+ while (Peek () >= 0) {
+ char c = (char)Read ();
+ if (c.IsWhiteSpaceOrNewLine ())
+ continue;
+ switch (c) {
+ case 'M':
+ gr.MoveTo (readDouble (), readDouble ());
+ break;
+ case 'm':
+ gr.RelMoveTo (readDouble (), readDouble ());
+ break;
+ case 'L':
+ gr.LineTo (readDouble (), readDouble ());
+ break;
+ case 'l':
+ gr.RelLineTo (readDouble (), readDouble ());
+ break;
+ case 'C':
+ gr.CurveTo (readDouble (), readDouble (), readDouble (), readDouble (), readDouble (), readDouble ());
+ break;
+ case 'c':
+ gr.RelCurveTo (readDouble (), readDouble (), readDouble (), readDouble (), readDouble (), readDouble ());
+ break;
+ case 'Z':
+ gr.ClosePath ();
+ break;
+ case 'F':
+ gr.Fill ();
+ break;
+ case 'G':
+ gr.Stroke ();
+ break;
+ default:
+ throw new Exception ("Invalid character in path string of Shape control");
+ }
+ }
+ }
+ }
+ public class Shape : Widget
+ {
+ #region CTOR
+ protected Shape () : base() {}
+ public Shape (Interface iface) : base (iface) {}
+ #endregion
+
+ string path;
+ double strokeWidth;
+ Size size;
+
+ public string Path {
+ get { return path; }
+ set {
+ if (path == value)
+ return;
+ path = value;
+ contentSize = default (Size);
+ NotifyValueChanged ("Path", path);
+ RegisterForGraphicUpdate ();
+ }
+ }
+ [DefaultValue(1.0)]
+ public double StokeWidth {
+ get { return strokeWidth; }
+ set {
+ if (strokeWidth == value)
+ return;
+ strokeWidth = value;
+ contentSize = default (Size);
+ NotifyValueChanged ("StrokeWidth", strokeWidth);
+ RegisterForGraphicUpdate ();
+ }
+ }
+ [DefaultValue("0,0")]
+ public Size Size
+ {
+ get { return size; }
+ set
+ {
+ if (size == value)
+ return;
+ size = value;
+ contentSize = default(Size);
+ NotifyValueChanged("Size", size);
+ RegisterForLayouting(LayoutingType.Sizing);
+ }
+ }
+ protected override void onDraw(Context gr)
+ {
+
+ if (string.IsNullOrEmpty(path))
+ return;
+
+ gr.Save();
+
+ Rectangle r = ClientRectangle;
+
+
+ double sx = (double)r.Width / (double)(contentSize.Width == 0? size.Width : contentSize.Width);
+ double sy = (double)r.Height / (double)(contentSize.Height == 0 ? size.Height : contentSize.Height);
+
+ gr.Translate(r.Left, r.Top);
+ gr.Scale (sx,sy);
+
+ using (PathParser parser = new PathParser (path))
+ parser.Draw (gr);
+
+ Background.SetAsSource (gr, r);
+ gr.FillPreserve ();
+ gr.LineWidth = strokeWidth;
+ Foreground.SetAsSource (gr, r);
+ gr.Stroke ();
+ gr.Restore();
+ }
+
+
+ protected override int measureRawSize (LayoutingType lt)
+ {
+ if ((lt == LayoutingType.Width && contentSize.Width == 0) || (lt == LayoutingType.Height && contentSize.Height == 0)) {
+ if (size != default(Size))
+ contentSize = size;
+ else
+ {
+ using (Surface drawing = new ImageSurface(Format.A1, 1, 1))
+ {
+ using (Context ctx = new Context(drawing))
+ {
+ using (PathParser parser = new PathParser (path))
+ parser.Draw (ctx);
+ Rectangle r = ctx.StrokeExtents();
+ contentSize = new Size(r.Right, r.Bottom);
+ }
+ }
+ }
+ }
+ return lt == LayoutingType.Width ?
+ contentSize.Width + 2 * Margin: contentSize.Height + 2 * Margin;
+ }
+ }
+}
+
--- /dev/null
+//
+// Slider.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 Crow.Cairo;
+using System.Xml.Serialization;
+using System.ComponentModel;
+using System.Diagnostics;
+
+namespace Crow
+{
+ /// <summary>
+ /// templated numeric control to select a value
+ /// by slidding a cursor
+ /// </summary>
+ public class Slider : NumericControl
+ {
+ #region CTOR
+ protected Slider() : base(){}
+ public Slider(Interface iface) : base(iface)
+ {}
+// public Slider(double minimum, double maximum, double step)
+// : base(minimum,maximum,step)
+// {
+// }
+ #endregion
+
+ #region implemented abstract members of TemplatedControl
+
+ protected override void loadTemplate (Widget template = null)
+ {
+
+ }
+
+ #endregion
+
+ #region private fields
+ Rectangle cursor;
+ int _cursorSize;
+ Fill _cursorColor;
+ Orientation _orientation;
+ bool holdCursor = false;
+ #endregion
+
+ protected double unity;
+
+ #region Public properties
+ [DefaultValue("vgradient|0:White|0,1:LightGrey|0,9:LightGrey|1:DimGrey")]
+ public virtual Fill CursorColor {
+ get { return _cursorColor; }
+ set {
+ if (_cursorColor == value)
+ return;
+ _cursorColor = value;
+ RegisterForRedraw ();
+ NotifyValueChanged ("CursorColor", _cursorColor);
+ }
+ }
+ [DefaultValue(20)]
+ public virtual int CursorSize {
+ get { return _cursorSize; }
+ set {
+ if (_cursorSize == value || value < 8)
+ return;
+ _cursorSize = value;
+ RegisterForGraphicUpdate ();
+ NotifyValueChanged ("CursorSize", _cursorSize);
+ }
+ }
+ [DefaultValue(Orientation.Horizontal)]
+ public virtual Orientation Orientation
+ {
+ get { return _orientation; }
+ set {
+ if (_orientation == value)
+ return;
+ _orientation = value;
+
+ RegisterForLayouting (LayoutingType.All);
+ NotifyValueChanged ("Orientation", _orientation);
+ }
+ }
+ #endregion
+
+ //[DefaultValue(10.0)]
+ //public override double Maximum {
+ // get { return base.Maximum; }
+ // set {
+ // if (value == base.Maximum)
+ // return;
+ // base.Maximum = value;
+ // LargeIncrement = base.Maximum / 10.0;
+ // SmallIncrement = LargeIncrement / 5.0;
+ // }
+ //}
+
+ #region GraphicObject Overrides
+ protected override void onDraw (Context gr)
+ {
+ base.onDraw (gr);
+
+ if (Maximum <= 0)
+ return;
+
+ computeCursorPosition ();
+
+ Rectangle r = ClientRectangle;
+ PointD pStart;
+ PointD pEnd;
+ if (_orientation == Orientation.Horizontal) {
+ pStart = r.TopLeft + new Point (_cursorSize / 2, r.Height / 2);
+ pEnd = r.TopRight + new Point (-_cursorSize / 2, r.Height / 2);
+ pStart.Y += 0.5;
+ pEnd.Y += 0.5;
+ } else {
+ pStart = r.TopLeft + new Point (r.Width / 2, _cursorSize / 2);
+ pEnd = r.BottomLeft + new Point (r.Width / 2,- _cursorSize / 2);
+ pStart.X += 0.5;
+ pEnd.X += 0.5;
+
+ }
+
+ Background.SetAsSource(gr, r);
+ gr.Rectangle (r);
+ gr.Fill ();
+
+ DrawGraduations (gr, pStart,pEnd);
+
+ DrawCursor (gr, cursor);
+ }
+ #endregion
+
+ protected virtual void DrawGraduations(Context gr, PointD pStart, PointD pEnd)
+ {
+ Foreground.SetAsSource (gr);
+
+ gr.LineWidth = 1;
+ gr.MoveTo(pStart);
+ gr.LineTo(pEnd);
+
+ gr.Stroke();
+
+ }
+ protected virtual void DrawCursor(Context gr, Rectangle _cursor)
+ {
+ CairoHelpers.CairoRectangle (gr, _cursor, CornerRadius);
+ Foreground.SetAsSource(gr, _cursor);
+ gr.StrokePreserve();
+ CursorColor.SetAsSource(gr, _cursor);
+ gr.Fill();
+ }
+
+ void computeCursorPosition()
+ {
+ Rectangle r = ClientRectangle;
+ PointD p1;
+
+ if (_orientation == Orientation.Horizontal) {
+ cursor = new Rectangle (new Size (_cursorSize, (int)(r.Height)));
+ p1 = r.TopLeft + new Point (_cursorSize / 2, r.Height / 2);
+ unity = (double)(r.Width - _cursorSize) / (Maximum - Minimum);
+ cursor.TopLeft = new Point (r.Left + (int)((Value - Minimum) * unity),
+ (int)(p1.Y - cursor.Height / 2));
+ } else {
+ cursor = new Rectangle (new Size ((int)(r.Width), _cursorSize));
+ p1 = r.TopLeft + new Point (r.Width / 2, _cursorSize / 2);
+ unity = (double)(r.Height - _cursorSize) / (Maximum - Minimum);
+ cursor.TopLeft = new Point ((int)(p1.X - r.Width / 2),
+ r.Top + (int)((Value - Minimum) * unity));
+ }
+ //cursor.Inflate (-1);
+ }
+ Point mouseDownInit;
+ double mouseDownInitValue;
+
+ #region mouse handling
+ public override void onMouseDown (object sender, MouseButtonEventArgs e)
+ {
+ base.onMouseDown (sender, e);
+ mouseDownInit = ScreenPointToLocal (e.Position);
+ mouseDownInitValue = Value;
+ Rectangle cursInScreenCoord = ScreenCoordinates (cursor + Slot.Position);
+ if (cursInScreenCoord.ContainsOrIsEqual (e.Position)){
+// Rectangle r = ClientRectangle;
+// if (r.Width - _cursorSize > 0) {
+// double unit = (Maximum - Minimum) / (double)(r.Width - _cursorSize);
+// mouseDownInit += new Point ((int)(Value / unit), (int)(Value / unit));
+// }
+ holdCursor = true;
+ }else if (_orientation == Orientation.Horizontal) {
+ if (e.Position.X < cursInScreenCoord.Left)
+ Value -= LargeIncrement;
+ else
+ Value += LargeIncrement;
+ } else {
+ if (e.Position.Y < cursInScreenCoord.Top)
+ Value -= LargeIncrement;
+ else
+ Value += LargeIncrement;
+ }
+ }
+ public override void onMouseUp (object sender,MouseButtonEventArgs e)
+ {
+ base.onMouseUp (sender, e);
+
+ holdCursor = false;
+ }
+ public override void onMouseMove (object sender, MouseMoveEventArgs e)
+ {
+ if (holdCursor) {
+ Point m = ScreenPointToLocal (e.Position) - mouseDownInit;
+ Rectangle r = ClientRectangle;
+
+ if (_orientation == Orientation.Horizontal) {
+ if (r.Width - _cursorSize == 0)
+ return;
+ double unit = (Maximum - Minimum) / (double)(r.Width - _cursorSize);
+ double tmp = mouseDownInitValue + (double)m.X * unit;
+ tmp -= tmp % SmallIncrement;
+ Value = tmp;
+ } else {
+ if (r.Height - _cursorSize == 0)
+ return;
+ double unit = (Maximum - Minimum) / (double)(r.Height - _cursorSize);
+ double tmp = mouseDownInitValue + (double)m.Y * unit;
+ tmp -= tmp % SmallIncrement;
+ Value = tmp;
+ }
+ }
+
+ base.onMouseMove (sender, e);
+ }
+ #endregion
+ }
+}
--- /dev/null
+// Copyright (c) 2013-2019 Bruyère Jean-Philippe <jp_bruyere@hotmail.com>
+//
+// This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT)
+
+namespace Crow
+{
+ /// <summary>
+ /// templated control for selecting a numeric value by clicking on
+ /// up and down buttons
+ /// </summary>
+ public class Spinner : NumericControl
+ {
+ #region CTOR
+ protected Spinner() : base(){}
+ public Spinner (Interface iface) : base(iface)
+ {
+ }
+ #endregion
+
+ void onUp (object sender, MouseButtonEventArgs e)
+ {
+ Value += this.SmallIncrement;
+ }
+ void onDown (object sender, MouseButtonEventArgs e)
+ {
+ Value -= this.SmallIncrement;
+ }
+
+ }
+}
+
--- /dev/null
+//
+// Splitter.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.Xml.Serialization;
+using System.ComponentModel;
+
+namespace Crow
+{
+ /// <summary>
+ /// control to add between children of a Stack to allow them to be resized
+ /// with the pointer
+ /// </summary>
+ public class Splitter : Widget
+ {
+ #region CTOR
+ protected Splitter() : base(){}
+ public Splitter (Interface iface) : base(iface){}
+ #endregion
+
+ int thickness;
+
+ [DefaultValue(1)]
+ public virtual int Thickness {
+ get { return thickness; }
+ set {
+ if (thickness == value)
+ return;
+ thickness = value;
+ NotifyValueChanged ("Thickness", thickness);
+ RegisterForLayouting (LayoutingType.Sizing);
+ RegisterForGraphicUpdate ();
+ }
+ }
+
+ Unit u1, u2;
+ int init1 = -1, init2 = -1, delta = 0, min1, min2, max1 , max2;
+ Widget go1 = null, go2 = null;
+
+ void initSplit(Measure m1, int size1, Measure m2, int size2){
+ if (m1 != Measure.Stretched) {
+ init1 = size1;
+ u1 = m1.Units;
+ }
+ if (m2 != Measure.Stretched) {
+ init2 = size2;
+ u2 = m2.Units;
+ }
+ }
+ void convertSizeInPix(Widget g1){
+
+ }
+
+ #region GraphicObject override
+ public override ILayoutable Parent {
+ get { return base.Parent; }
+ set {
+ if (value != null) {
+ GenericStack gs = value as GenericStack;
+ if (gs == null)
+ throw new Exception ("Splitter may only be chil of stack");
+
+ }
+ base.Parent = value;
+ }
+ }
+ public override void onMouseEnter (object sender, MouseMoveEventArgs e)
+ {
+ base.onMouseEnter (sender, e);
+ if ((Parent as GenericStack).Orientation == Orientation.Horizontal)
+ IFace.MouseCursor = MouseCursor.H;
+ else
+ IFace.MouseCursor = MouseCursor.V;
+ }
+ public override void onMouseDown (object sender, MouseButtonEventArgs e)
+ {
+ base.onMouseDown (sender, e);
+ go1 = go2 = null;
+ init1 = init2 = -1;
+ delta = 0;
+
+ GenericStack gs = Parent as GenericStack;
+ int ptrSplit = gs.Children.IndexOf (this);
+ if (ptrSplit == 0 || ptrSplit == gs.Children.Count - 1)
+ return;
+
+ go1 = gs.Children [ptrSplit - 1];
+ go2 = gs.Children [ptrSplit + 1];
+
+ if (gs.Orientation == Orientation.Horizontal) {
+ initSplit (go1.Width, go1.Slot.Width, go2.Width, go2.Slot.Width);
+ min1 = go1.MinimumSize.Width;
+ min2 = go2.MinimumSize.Width;
+ max1 = go1.MaximumSize.Width;
+ max2 = go2.MaximumSize.Width;
+ if (init1 >= 0)
+ go1.Width = init1;
+ if (init2 >= 0)
+ go2.Width = init2;
+ } else {
+ initSplit (go1.Height, go1.Slot.Height, go2.Height, go2.Slot.Height);
+ min1 = go1.MinimumSize.Height;
+ min2 = go2.MinimumSize.Height;
+ max1 = go1.MaximumSize.Height;
+ max2 = go2.MaximumSize.Height;
+ if (init1 >= 0)
+ go1.Height = init1;
+ if (init2 >= 0)
+ go2.Height = init2;
+ }
+ }
+ public override void onMouseMove (object sender, MouseMoveEventArgs e)
+ {
+ base.onMouseMove (sender, e);
+
+ if (!IsActive || go1 == null || go2 == null)
+ return;
+
+ GenericStack gs = Parent as GenericStack;
+ int newDelta = delta, size1 = init1 , size2 = init2;
+ if (gs.Orientation == Orientation.Horizontal) {
+ newDelta -= e.XDelta;
+ if (size1 < 0)
+ size1 = go1.Slot.Width + delta;
+ if (size2 < 0)
+ size2 = go2.Slot.Width - delta;
+ } else {
+ newDelta -= e.YDelta;
+ if (size1 < 0)
+ size1 = go1.Slot.Height + delta;
+ if (size2 < 0)
+ size2 = go2.Slot.Height - delta;
+ }
+
+ if (size1 - newDelta < min1 || (max1 > 0 && size1 - newDelta > max1) ||
+ size2 + newDelta < min2 || (max2 > 0 && size2 + newDelta > max2))
+ return;
+
+ delta = newDelta;
+
+ if (gs.Orientation == Orientation.Horizontal) {
+ if (init1 >= 0)
+ go1.Width = init1 - delta;
+ if (init2 >= 0)
+ go2.Width = init2 + delta;
+ } else {
+ if (init1 >= 0)
+ go1.Height = init1 - delta;
+ if (init2 >= 0)
+ go2.Height = init2 + delta;
+ }
+ }
+ public override void onMouseUp (object sender, MouseButtonEventArgs e)
+ {
+ base.onMouseUp (sender, e);
+
+ GenericStack gs = Parent as GenericStack;
+
+ if (init1 >= 0 && u1 == Unit.Percent) {
+ if (gs.Orientation == Orientation.Horizontal)
+ go1.Width = new Measure ((int)Math.Ceiling (
+ go1.Width.Value * 100.0 / (double)gs.Slot.Width), Unit.Percent);
+ else
+ go1.Height = new Measure ((int)Math.Ceiling (
+ go1.Height.Value * 100.0 / (double)gs.Slot.Height), Unit.Percent);
+ }
+ if (init2 >= 0 && u2 == Unit.Percent) {
+ if (gs.Orientation == Orientation.Horizontal)
+ go2.Width = new Measure ((int)Math.Floor (
+ go2.Width.Value * 100.0 / (double)gs.Slot.Width), Unit.Percent);
+ else
+ go2.Height = new Measure ((int)Math.Floor (
+ go2.Height.Value * 100.0 / (double)gs.Slot.Height), Unit.Percent);
+ }
+ }
+ public override bool UpdateLayout (LayoutingType layoutType)
+ {
+ GenericStack gs = Parent as GenericStack;
+ if (layoutType == LayoutingType.Width){
+ if (gs.Orientation == Orientation.Horizontal)
+ Width = thickness;
+ else
+ Width = Measure.Stretched;
+ } else if (layoutType == LayoutingType.Height){
+ if (gs.Orientation == Orientation.Vertical)
+ Height = thickness;
+ else
+ Height = Measure.Stretched;
+ }
+ return base.UpdateLayout (layoutType);
+ }
+ public override 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) ;
+ Rectangle r = Slot;
+ if (Width == Measure.Stretched)
+ r.Inflate (0, 5);
+ else
+ r.Inflate (5, 0);
+ return r.ContainsOrIsEqual (m);
+ }
+ #endregion
+ }
+}
+
--- /dev/null
+//
+// TabItem.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.Xml.Serialization;
+using System.ComponentModel;
+using System.Diagnostics;
+using Crow.Cairo;
+using System.Linq;
+
+namespace Crow
+{
+ public class TabItem : TemplatedContainer
+ {
+ #region CTOR
+ protected TabItem() : base(){}
+ public TabItem (Interface iface) : base(iface){}
+ #endregion
+
+ public event EventHandler QueryClose;
+
+ internal TabView tview = null;
+
+ #region Private fields
+ Widget titleWidget;
+ int tabOffset;
+ bool isSelected;
+ //Measure tabThickness;
+ Fill selectedBackground = Color.Transparent;
+ #endregion
+
+ #region TemplatedControl overrides
+ public override Widget Content {
+ get {
+ return _contentContainer == null ? null : _contentContainer.Child;
+ }
+ set {
+ if (Content != null) {
+ Content.LogicalParent = null;
+ _contentContainer.SetChild (null);
+ }
+ _contentContainer.SetChild(value);
+ if (value != null)
+ value.LogicalParent = this;
+ }
+ }
+ protected override void loadTemplate(Widget template = null)
+ {
+ base.loadTemplate (template);
+
+ titleWidget = this.child.FindByName ("TabTitle");
+ }
+ internal Widget TabTitle { get { return titleWidget; }}
+ #endregion
+
+ /// <summary>
+ /// order of redrawing, items can't be reordered in TemplatedGroup due to data linked, so we need another index
+ /// instead of children list order
+ /// </summary>
+ public int viewIndex = 0;
+ public virtual int ViewIndex {
+ get { return viewIndex; }
+ set {
+ if (viewIndex == value)
+ return;
+ viewIndex = value;
+ NotifyValueChanged ("ViewIndex", viewIndex);
+ }
+ }
+
+ [DefaultValue(0)]
+ public int TabOffset {
+ get { return tabOffset; }
+ set {
+ if (tabOffset == value)
+ return;
+ tabOffset = value;
+ NotifyValueChanged ("TabOffset", tabOffset);
+
+ RegisterForLayouting (LayoutingType.X);
+ RegisterForGraphicUpdate ();
+ }
+ }
+ public Measure TabHeight {
+ get { return tview == null ? Measure.Fit : tview.TabHeight; }
+ }
+ public Measure TabWidth {
+ get { return tview == null ? Measure.Fit : tview.TabWidth; }
+ }
+ [DefaultValue(false)]
+ public virtual bool IsSelected {
+ get { return isSelected; }
+ set {
+ if (isSelected == value)
+ return;
+
+ if (tview != null)
+ tview.SelectedTab = tview.Children.IndexOf(this);
+
+ isSelected = value;
+ NotifyValueChanged ("IsSelected", isSelected);
+ RegisterForRedraw ();
+ }
+ }
+
+ /// <summary>
+ /// background fill of the control, maybe solid color, gradient, image, or svg
+ /// </summary>
+ [DesignCategory ("Appearance")][DefaultValue("DimGrey")]
+ public virtual Fill SelectedBackground {
+ get { return selectedBackground; }
+ set {
+ if (selectedBackground == value)
+ return;
+ if (value == null)
+ return;
+ selectedBackground = value;
+ NotifyValueChanged ("SelectedBackground", selectedBackground);
+ RegisterForRedraw ();
+ }
+ }
+ protected override void onDraw (Context gr)
+ {
+ gr.Save ();
+
+ TabView tv = Parent as TabView;
+
+ Rectangle r = TabTitle.Slot;
+ r.Width = TabWidth;
+
+ gr.MoveTo (0.5, r.Bottom-0.5);
+ gr.LineTo (r.Left - tv.LeftSlope, r.Bottom-0.5);
+ gr.CurveTo (
+ r.Left - tv.LeftSlope / 2, r.Bottom-0.5,
+ r.Left - tv.LeftSlope / 2, 0.5,
+ r.Left, 0.5);
+ gr.LineTo (r.Right, 0.5);
+ gr.CurveTo (
+ r.Right + tv.RightSlope / 2, 0.5,
+ r.Right + tv.RightSlope / 2, r.Bottom-0.5,
+ r.Right + tv.RightSlope, r.Bottom-0.5);
+ gr.LineTo (Slot.Width-0.5, r.Bottom-0.5);
+
+
+ gr.LineTo (Slot.Width-0.5, Slot.Height-0.5);
+ gr.LineTo (0.5, Slot.Height-0.5);
+ gr.ClosePath ();
+ gr.LineWidth = 1;
+ Foreground.SetAsSource (gr);
+ gr.StrokePreserve ();
+ gr.ClipPreserve ();
+
+ if (IsSelected)
+ SelectedBackground.SetAsSource (gr, ClientRectangle);
+ else
+ Background.SetAsSource (gr, ClientRectangle);
+
+ gr.Fill ();
+
+ base.onDraw (gr);
+
+ gr.Restore ();
+ }
+
+ Point dragStartPoint;
+ int dragThreshold = 16;
+ int dis = 128;
+ internal TabView savedParent = null;
+
+
+ void makeFloating (TabView tv) {
+ lock (IFace.UpdateMutex) {
+ ImageSurface di = new ImageSurface (Format.Argb32, dis, dis);
+ IFace.DragImageHeight = dis;
+ IFace.DragImageWidth = dis;
+ using (Context ctx = new Context (di)) {
+ double div = Math.Max (LastPaintedSlot.Width, LastPaintedSlot.Height);
+ double s = (double)dis / 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 ();
+ }
+ }
+ IFace.DragImage = di;
+ }
+ tv.RemoveChild (this);
+ savedParent = tv;
+ }
+
+ public override ILayoutable Parent {
+ get {
+ return base.Parent;
+ }
+ set {
+ base.Parent = value;
+ if (value != null) {
+ dragStartPoint = IFace.Mouse.Position;
+ savedParent = value as TabView;
+ }
+ }
+ }
+ protected override void onStartDrag (object sender, DragDropEventArgs e)
+ {
+ base.onStartDrag (sender, e);
+
+ dragStartPoint = IFace.Mouse.Position;
+ }
+ protected override void onEndDrag (object sender, DragDropEventArgs e)
+ {
+ base.onEndDrag (sender, e);
+
+ if (Parent != null)
+ return;
+
+ savedParent.AddChild (this);
+
+ IFace.ClearDragImage ();
+ }
+ protected override void onDrop (object sender, DragDropEventArgs e)
+ {
+ base.onDrop (sender, e);
+ if (Parent != null)
+ return;
+ TabView tv = e.DropTarget as TabView;
+ if (tv == null)
+ return;
+
+ IFace.ClearDragImage ();
+
+ tv.AddChild (this);
+ }
+ #region Mouse Handling
+ public override bool PointIsIn (ref Point m)
+ {
+ if (!base.PointIsIn (ref m))
+ return false;
+ if (tview == null)//double check this, just added to prevent exception
+ return false;
+ if (m.Y < tview.TabHeight)
+ return TabTitle.Slot.ContainsOrIsEqual (m);
+ else
+ return this.isSelected;
+ }
+ public override void onMouseUp (object sender, MouseButtonEventArgs e)
+ {
+ base.onMouseUp (sender, e);
+ tview?.UpdateLayout (LayoutingType.ArrangeChildren);
+ }
+ public override void onMouseMove (object sender, MouseMoveEventArgs e)
+ {
+ base.onMouseMove (sender, e);
+
+ if (Parent == null)
+ return;
+
+ if (!IsDragged)
+ return;
+
+ TabView tv = Parent as TabView;
+ if (Math.Abs (e.Position.Y - dragStartPoint.Y) > dragThreshold ||
+ Math.Abs (e.Position.X - dragStartPoint.X) > dragThreshold) {
+ makeFloating (tv);
+ return;
+ }
+
+ Rectangle cb = ClientRectangle;
+
+ int tmp = TabOffset + e.XDelta;
+ if (tmp < tview.LeftSlope) {
+ TabOffset = tview.LeftSlope;
+ } else if (tmp > cb.Width - tv.RightSlope - tv.TabWidth) {
+ TabOffset = cb.Width - tv.RightSlope - tv.TabWidth;
+ }else{
+ dragStartPoint.X = e.Position.X;
+ TabItem[] tabItms = tv.Children.Cast<TabItem>().OrderBy (t=>t.ViewIndex).ToArray();
+ if (ViewIndex > 0 && e.XDelta < 0) {
+ TabItem previous = tabItms [ViewIndex - 1];
+ if (tmp < previous.TabOffset + tview.TabWidth / 2) {
+ previous.ViewIndex = ViewIndex;
+ ViewIndex--;
+ tv.UpdateLayout (LayoutingType.ArrangeChildren);
+ }
+
+ }else if (ViewIndex < tabItms.Length - 1 && e.XDelta > 0) {
+ TabItem next = tabItms [ViewIndex + 1];
+ if (tmp > next.TabOffset - tview.TabWidth / 2){
+ next.ViewIndex = ViewIndex;
+ ViewIndex++;
+ tv.UpdateLayout (LayoutingType.ArrangeChildren);
+ }
+ }
+ TabOffset = tmp;
+ }
+ }
+ public void butCloseTabClick (object sender, MouseButtonEventArgs e){
+ QueryClose.Raise (this, null);
+ //if tab is used as a templated item root in a templatedGroup, local datasource
+ //is not null, in this case, removing the data entries will delete automatically the item
+ if (localDataSourceIsNull)
+ (Parent as TabView)?.DeleteChild (this);
+ }
+ #endregion
+
+ }
+}
+
--- /dev/null
+//
+// TabView.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.Xml.Serialization;
+using System.ComponentModel;
+using Crow.Cairo;
+using System.Diagnostics;
+using System.Linq;
+
+namespace Crow
+{
+ public class TabView : Group
+ {
+ #region CTOR
+ public TabView() : base(){}
+ public TabView (Interface iface) : base(iface){}
+ #endregion
+
+ #region Private fields
+ int adjustedTab = -1;
+ int leftSlope;
+ int rightSlope;
+ Measure tabHeight, tabWidth;
+ Orientation _orientation;
+ int selectedTab;
+ #endregion
+
+ #region public properties
+ [DefaultValue(Orientation.Horizontal)]
+ public virtual Orientation Orientation
+ {
+ get { return _orientation; }
+ set {
+ if (_orientation == value)
+ return;
+ _orientation = value;
+ NotifyValueChanged ("Orientation", _orientation);
+ if (_orientation == Orientation.Horizontal)
+ NotifyValueChanged ("TabOrientation", Orientation.Vertical);
+ else
+ NotifyValueChanged ("TabOrientation", Orientation.Horizontal);
+ this.RegisterForLayouting (LayoutingType.ArrangeChildren);
+ }
+ }
+ [DefaultValue(16)]
+ public int LeftSlope
+ {
+ get { return leftSlope; }
+ set {
+ if (leftSlope == value)
+ return;
+ leftSlope = value;
+ NotifyValueChanged ("leftSlope", leftSlope);
+ //tabSizeHasChanged = true;
+ //RegisterForLayouting (LayoutingType.ArrangeChildren);
+ }
+ }
+ //bool tabSizeHasChanged = false;
+ [DefaultValue(16)]
+ public int RightSlope
+ {
+ get { return rightSlope; }
+ set {
+ if (rightSlope == value)
+ return;
+ rightSlope = value;
+ NotifyValueChanged ("RightSlope", rightSlope);
+ //tabSizeHasChanged = true;
+ //RegisterForLayouting (LayoutingType.ArrangeChildren);
+ }
+ }
+ [DefaultValue("18")]
+ public Measure TabHeight {
+ get { return tabHeight; }
+ set {
+ if (tabHeight == value)
+ return;
+ tabHeight = value;
+ NotifyValueChanged ("TabHeight", tabHeight);
+// childrenRWLock.EnterReadLock ();
+// foreach (GraphicObject ti in Children) {
+// ti.NotifyValueChanged ("TabHeight", tabHeight);
+// }
+// childrenRWLock.ExitReadLock ();
+ RegisterForLayouting (LayoutingType.ArrangeChildren);
+ }
+ }
+ [DefaultValue("120")]
+ public Measure TabWidth {
+ get { return adjustedTab > 0 ? (Measure)adjustedTab : tabWidth; }
+ set {
+ if (tabWidth == value)
+ return;
+ tabWidth = value;
+ NotifyValueChanged ("TabWidth", TabWidth);
+//
+// childrenRWLock.EnterReadLock ();
+// foreach (GraphicObject ti in Children) {
+// ti.NotifyValueChanged ("TabWidth", tabWidth);
+// }
+// childrenRWLock.ExitReadLock ();
+ RegisterForLayouting (LayoutingType.ArrangeChildren);
+ }
+ }
+
+ public virtual int SelectedTab {
+ get { return selectedTab; }
+ set {
+ if (value == selectedTab)
+ return;
+
+ if (selectedTab < Children.Count && selectedTab >= 0)
+ (Children [selectedTab] as TabItem).IsSelected = false;
+
+ selectedTab = value;
+
+ if (selectedTab < Children.Count && selectedTab >= 0)
+ (Children [selectedTab] as TabItem).IsSelected = true;
+
+ NotifyValueChanged ("SelectedTab", selectedTab);
+ RegisterForRedraw ();
+ }
+ }
+ #endregion
+
+ public override void AddChild (Widget child)
+ {
+ TabItem ti = child as TabItem;
+ if (ti == null)
+ throw new Exception ("TabView control accept only TabItem as child.");
+
+ ti.MouseDown += Ti_MouseDown;
+ ti.TabTitle.LayoutChanged += Ti_TabTitle_LayoutChanged;
+ ti.tview = this;
+
+ base.AddChild (child);
+
+ SelectedTab = ti.ViewIndex = Children.Count - 1;
+ this.RegisterForLayouting (LayoutingType.ArrangeChildren);
+ }
+ public override void RemoveChild (Widget child)
+ {
+ TabItem ti = child as TabItem;
+ if (ti == null)
+ throw new Exception ("TabView control accept only TabItem as child.");
+
+ ti.MouseDown -= Ti_MouseDown;
+ ti.TabTitle.LayoutChanged -= Ti_TabTitle_LayoutChanged;
+ ti.tview = null;
+
+ childrenRWLock.EnterReadLock ();
+
+ TabItem[] tabItms = Children.Cast<TabItem>().OrderBy (t=>t.ViewIndex).ToArray();
+ int selTabViewIdx = -1;
+
+ if (SelectedTab < tabItms.Length && SelectedTab >= 0)
+ selTabViewIdx = (Children [SelectedTab] as TabItem).ViewIndex;
+
+ for (int i = selTabViewIdx+1; i < tabItms.Length; i++)
+ tabItms [i].ViewIndex--;
+
+ if (selTabViewIdx > tabItms.Length - 2)
+ selTabViewIdx = tabItms.Length - 2;
+
+ if (selTabViewIdx < 0)
+ SelectedTab = -1;
+ else
+ SelectedTab = Children.IndexOf (tabItms [selTabViewIdx]);
+
+ childrenRWLock.ExitReadLock ();
+
+ base.RemoveChild (child);
+ }
+
+ public override bool ArrangeChildren { get { return true; } }
+ public override bool UpdateLayout (LayoutingType layoutType)
+ {
+ RegisteredLayoutings &= (~layoutType);
+
+ if (layoutType == LayoutingType.ArrangeChildren && Children.Count > 0) {
+ Rectangle cb = ClientRectangle;
+
+ int tabSpace = tabWidth + leftSlope;
+ int tc = Children.Count (c => c.Visible == true);
+
+ if (tc > 0)
+ tabSpace = Math.Min(tabSpace, (cb.Width-rightSlope) / tc);
+
+ if (tabSpace < tabWidth + leftSlope)
+ adjustedTab = tabSpace - leftSlope;
+ else
+ adjustedTab = -1;
+
+ //Console.WriteLine ("tabspace: {0} tw:{1}", tabSpace, tabWidth);
+
+ childrenRWLock.EnterReadLock();
+ TabItem[] tabItms = Children.Cast<TabItem>().OrderBy (t=>t.ViewIndex).ToArray();
+ childrenRWLock.ExitReadLock();
+ int curOffset = leftSlope;
+
+ for (int i = 0; i < tabItms.Length; i++) {
+ if (!tabItms [i].Visible)
+ continue;
+ tabItms [i].NotifyValueChanged ("TabHeight", tabHeight);
+ tabItms [i].NotifyValueChanged ("TabWidth", TabWidth);
+ if (!tabItms [i].IsDragged) {
+ tabItms [i].TabOffset = curOffset;
+ //Console.WriteLine ("offset: {0}=>{1}", tabItms [i].Name, tabItms [i].TabOffset);
+ }
+ if (Orientation == Orientation.Horizontal) {
+ curOffset += tabSpace;
+ } else
+ curOffset += tabSpace;
+ }
+
+ //if no layouting remains in queue for item, registre for redraw
+ if (RegisteredLayoutings == LayoutingType.None && IsDirty)
+ IFace.EnqueueForRepaint (this);
+
+ return true;
+ }
+
+ return base.UpdateLayout(layoutType);
+ }
+ public override void OnLayoutChanges (LayoutingType layoutType)
+ {
+ if (_orientation == Orientation.Horizontal) {
+ if (layoutType == LayoutingType.Width)
+ RegisterForLayouting (LayoutingType.ArrangeChildren);
+ } else if (layoutType == LayoutingType.Height)
+ RegisterForLayouting (LayoutingType.ArrangeChildren);
+
+ base.OnLayoutChanges (layoutType);
+ }
+
+ protected override void onDraw (Context gr)
+ {
+ Rectangle rBack = new Rectangle (Slot.Size);
+
+ Background.SetAsSource (gr, rBack);
+ CairoHelpers.CairoRectangle(gr,rBack, CornerRadius);
+ gr.Fill ();
+
+ gr.Save ();
+
+ if (ClipToClientRect) {
+ //clip to client zone
+ CairoHelpers.CairoRectangle (gr, ClientRectangle, CornerRadius);
+ gr.Clip ();
+ }
+
+ childrenRWLock.EnterReadLock ();
+
+ TabItem[] tabItms = Children.Where(tt=>tt.Visible).Cast<TabItem> ().
+ OrderBy (t => t.ViewIndex).ToArray ();
+
+ int selTabViewIdx = -1;
+ if (SelectedTab < tabItms.Length && SelectedTab >= 0)
+ selTabViewIdx = (Children [SelectedTab] as TabItem).ViewIndex;
+
+ childrenRWLock.ExitReadLock ();
+
+ int i = 0;
+ while (i < selTabViewIdx) {
+ tabItms [i].Paint (ref gr);
+ i++;
+ }
+ i = tabItms.Length - 1;
+ while (i > selTabViewIdx) {
+ tabItms [i].Paint (ref gr);
+ i--;
+ }
+
+ if (selTabViewIdx >= 0)
+ tabItms [selTabViewIdx].Paint (ref gr);
+
+ gr.Restore ();
+ }
+
+ protected override void onDragEnter (object sender, DragDropEventArgs e)
+ {
+ base.onDragEnter (sender, e);
+
+ TabItem ti = e.DragSource as TabItem;
+ if (ti == null)
+ return;
+ if (ti.Parent != null || ti.savedParent == this)
+ return;
+
+ this.AddChild (ti);
+
+ Point p = ScreenPointToLocal (IFace.Mouse.Position) - Margin;
+
+ p.X = Math.Max (leftSlope, p.X);
+ p.X = Math.Min (ClientRectangle.Width - rightSlope - TabWidth, p.X);
+ ti.TabOffset = p.X;
+
+ IFace.ClearDragImage ();
+
+ }
+
+ void Ti_TabTitle_LayoutChanged (object sender, LayoutingEventArgs e)
+ {
+ if (e.LayoutType == LayoutingType.X)
+ RegisterForLayouting (LayoutingType.ArrangeChildren);
+ }
+ void Ti_MouseDown (object sender, MouseButtonEventArgs e)
+ {
+ SelectedTab = Children.IndexOf (sender as Widget);
+ }
+ }
+}
+
--- /dev/null
+// Copyright (c) 2013-2019 Bruyère Jean-Philippe jp_bruyere@hotmail.com
+//
+// This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT)
+
+using System;
+using System.Xml.Serialization;
+using System.Xml;
+using System.Reflection;
+
+namespace Crow
+{
+ /// <summary>
+ /// base class for new containers that will use templates.
+ ///
+ /// TemplatedControl's **must** provide a widget of the [`Container`](Container) class named **_'Content'_** inside their template tree
+ /// </summary>
+ public class TemplatedContainer : TemplatedControl
+ {
+ #if DESIGN_MODE
+ public override void getIML (System.Xml.XmlDocument doc, System.Xml.XmlNode parentElem)
+ {
+ if (this.design_isTGItem)
+ return;
+ base.getIML (doc, parentElem);
+ if (!HasContent)
+ return;
+ Content.getIML (doc, parentElem.LastChild);
+ }
+ #endif
+
+ #region CTOR
+ protected TemplatedContainer() : base(){}
+ public TemplatedContainer (Interface iface) : base(iface){}
+ #endregion
+
+ protected Container _contentContainer;
+
+ /// <summary>
+ /// Single child of this templated container.
+ /// </summary>
+ public virtual Widget Content {
+ get {
+ return _contentContainer == null ? null : _contentContainer.Child;
+ }
+ set {
+ _contentContainer.SetChild(value);
+ NotifyValueChanged ("HasContent", HasContent);
+ }
+ }
+ [XmlIgnore]public bool HasContent {
+ get { return _contentContainer?.Child != null; }
+ }
+ //TODO: move loadTemplate and ResolveBinding in TemplatedContainer
+ protected override void loadTemplate(Widget template = null)
+ {
+ base.loadTemplate (template);
+ _contentContainer = this.child.FindByName ("Content") as Container;
+ }
+
+ #region GraphicObject overrides
+ public override Widget FindByName (string nameToFind)
+ {
+ if (Name == nameToFind)
+ return this;
+
+ return Content == null ? null : Content.FindByName (nameToFind);
+ }
+ public override bool Contains (Widget goToFind)
+ {
+ if (Content == goToFind)
+ return true;
+ if (Content?.Contains (goToFind) == true)
+ return true;
+ return base.Contains (goToFind);
+ }
+ #endregion
+ }
+}
+
--- /dev/null
+// Copyright (c) 2013-2019 Bruyère Jean-Philippe jp_bruyere@hotmail.com
+//
+// This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT)
+
+using System;
+using System.ComponentModel;
+using System.IO;
+using System.Reflection;
+using System.Xml;
+using Crow.Cairo;
+
+namespace Crow
+{
+ /// <summary>
+ /// Base class for all templated widget
+ /// </summary>
+ public abstract class TemplatedControl : PrivateContainer
+ {
+ #if DESIGN_MODE
+ public bool design_inlineTemplate = false;
+ public override void getIML (XmlDocument doc, XmlNode parentElem)
+ {
+ if (this.design_isTGItem)
+ return;
+ base.getIML (doc, parentElem);
+ if (child == null || !design_inlineTemplate)
+ return;
+ XmlElement xe = doc.CreateElement("Template");
+ child.getIML (doc, xe);
+ parentElem.LastChild.AppendChild (xe);
+ }
+ #endif
+
+ #region CTOR
+ protected TemplatedControl() : base(){}
+ public TemplatedControl (Interface iface) : base(iface){}
+ #endregion
+
+ string _template;
+ string caption;
+
+ /// <summary>
+ /// Template path
+ /// </summary>
+ //TODO: this property should be renamed 'TemplatePath'
+ [DefaultValue(null)]
+ public string Template {
+ get { return _template; }
+ set {
+ if (_template == value)
+ return;
+ _template = value;
+
+ if (string.IsNullOrEmpty(_template))
+ loadTemplate ();
+ else
+ loadTemplate (IFace.CreateTemplateInstance (_template, this.GetType()));
+ }
+ }
+ /// <summary>
+ /// a caption being recurrent need in templated widget, it is declared here.
+ /// </summary>
+ [DefaultValue("Templated Control")]
+ public virtual string Caption {
+ get { return caption; }
+ set {
+ if (caption == value)
+ return;
+ caption = value;
+ NotifyValueChanged ("Caption", caption);
+ }
+ }
+
+ #region GraphicObject overrides
+
+ public override void Initialize ()
+ {
+ loadTemplate ();
+ base.Initialize ();
+ }
+ /// <summary>
+ /// override search method from GraphicObject to prevent
+ /// searching inside template
+ /// </summary>
+ /// <returns>widget identified by name, or null if not found</returns>
+ /// <param name="nameToFind">widget's name to find</param>
+ public override Widget FindByName (string nameToFind) => nameToFind == this.Name ? this : null;
+
+ /// <summary>
+ ///onDraw is overrided to prevent default drawing of background, template top container
+ ///may have a binding to root background or a fixed one.
+ ///this allow applying root background to random template's component
+ /// </summary>
+ /// <param name="gr">Backend context</param>
+ protected override void onDraw (Context gr)
+ {
+ gr.Save ();
+
+ if (ClipToClientRect) {
+ //clip to client zone
+ CairoHelpers.CairoRectangle (gr, ClientRectangle, CornerRadius);
+ gr.Clip ();
+ }
+
+ if (child != null)
+ child.Paint (ref gr);
+ gr.Restore ();
+ }
+ #endregion
+
+ /// <summary>
+ /// Loads the template. Each TemplatedControl MUST provide a default template
+ /// It must be an embedded ressource with ID = fullTypeName.template
+ /// Entry assembly is search first, then the one where the type is defined
+ /// </summary>
+ /// <param name="template">Optional template instance</param>
+ protected virtual void loadTemplate(Widget template = null)
+ {
+ if (this.child != null)//template change, bindings has to be reset
+ this.ClearTemplateBinding();
+
+ if (template == null) {
+ int mdTok = this.GetType ().MetadataToken;
+
+ if (!IFace.DefaultTemplates.ContainsKey (mdTok)) {
+ string defTmpId = this.GetType ().FullName + ".template";
+ Stream s = Assembly.GetEntryAssembly ().GetManifestResourceStream (defTmpId);
+ if (s == null)
+ s = Assembly.GetAssembly (this.GetType ()).GetManifestResourceStream (defTmpId);
+ if (s == null)
+ throw new Exception (string.Format ("No default template found for '{0}'", this.GetType ().FullName));
+ IFace.DefaultTemplates [mdTok] = new IML.Instantiator (IFace, s, defTmpId);
+ }
+ this.SetChild (IFace.DefaultTemplates[mdTok].CreateInstance());
+ }else
+ this.SetChild (template);
+ }
+ }
+}
+
--- /dev/null
+//
+// TemplatedGroup.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;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.Linq;
+using System.Threading;
+using Crow.IML;
+
+namespace Crow {
+ public abstract class TemplatedGroup : TemplatedControl
+ {
+ #if DESIGN_MODE
+ public override void getIML (System.Xml.XmlDocument doc, System.Xml.XmlNode parentElem)
+ {
+ if (this.design_isTGItem)
+ return;
+ base.getIML (doc, parentElem);
+
+ if (string.IsNullOrEmpty(_itemTemplate)) {
+ foreach (ItemTemplate it in ItemTemplates.Values)
+ it.getIML (doc, parentElem.LastChild);
+ }
+
+ foreach (Widget g in Items) {
+ g.getIML (doc, parentElem.LastChild);
+ }
+ }
+ #endif
+
+ #region CTOR
+ protected TemplatedGroup() : base(){}
+ public TemplatedGroup (Interface iface) : base(iface){}
+ #endregion
+
+ protected Group items;
+ string _itemTemplate, dataTest;
+
+ #region events
+ public event EventHandler<SelectionChangeEventArgs> SelectedItemChanged;
+ public event EventHandler Loaded;
+ #endregion
+
+ IEnumerable data;
+ int _selectedIndex = -1;
+ Color selBackground, selForeground;
+
+ int itemPerPage = 50;
+ CrowThread loadingThread = null;
+
+ bool isPaged = false;
+
+ #region Templating
+ //TODO: dont instantiate ItemTemplates if not used
+ //but then i should test if null in msil gen
+ public Dictionary<string, ItemTemplate> ItemTemplates = new Dictionary<string, ItemTemplate>();
+
+ /// <summary>
+ /// Keep track of expanded subnodes and closed time to unload
+ /// </summary>
+ //Dictionary<GraphicObject, Stopwatch> nodes = new Dictionary<GraphicObject, Stopwatch>();
+ internal List<Widget> nodes = new List<Widget>();
+ /// <summary>
+ /// Item templates file path, on disk or embedded.
+ ///
+ /// ItemTemplate file may contains either a single template without the
+ /// ItemTemplate enclosing tag, or several item templates each enclosed
+ /// in a separate tag.
+ /// </summary>
+ public string ItemTemplate {
+ get { return _itemTemplate; }
+ set {
+ if (value == _itemTemplate)
+ return;
+
+ _itemTemplate = value;
+
+ //TODO:reload list with new template?
+ NotifyValueChanged("ItemTemplate", _itemTemplate);
+ }
+ }
+ protected override void loadTemplate(Widget template = null)
+ {
+ base.loadTemplate (template);
+
+ items = this.child.FindByName ("ItemsContainer") as Group;
+ if (items == null)
+ throw new Exception ("TemplatedGroup template Must contain a Group named 'ItemsContainer'");
+ if (items.Children.Count == 0)
+ NotifyValueChanged ("HasChildren", false);
+ else
+ NotifyValueChanged ("HasChildren", true);
+ }
+ /// <summary>
+ /// Use to define condition on Data item for selecting among ItemTemplates.
+ /// Default value is 'TypeOf' for selecting Template depending on Type of Data.
+ /// Other possible values are properties of Data
+ /// </summary>
+ /// <value>The data property test.</value>
+ [DefaultValue("TypeOf")]
+ public string DataTest {
+ get { return dataTest; }
+ set {
+ if (value == dataTest)
+ return;
+
+ dataTest = value;
+
+ NotifyValueChanged("DataTest", dataTest);
+ }
+ }
+ #endregion
+
+ public virtual List<Widget> Items{
+ get {
+ return isPaged ? items.Children.SelectMany(x => (x as Group).Children).ToList()
+ : items.Children;
+ }
+ }
+ [DefaultValue(-1)]public virtual int SelectedIndex{
+ get { return _selectedIndex; }
+ set {
+ if (value == _selectedIndex)
+ return;
+
+ /*if (_selectedIndex >= 0 && Items.Count > _selectedIndex) {
+ Items[_selectedIndex].Foreground = Color.Transparent;
+ Items[_selectedIndex].Background = Color.Transparent;
+ }*/
+
+ _selectedIndex = value;
+
+ /*if (_selectedIndex >= 0 && Items.Count > _selectedIndex) {
+ Items[_selectedIndex].Foreground = SelectionForeground;
+ Items[_selectedIndex].Background = SelectionBackground;
+ }*/
+
+ NotifyValueChanged ("SelectedIndex", _selectedIndex);
+ NotifyValueChanged ("SelectedItem", SelectedItem);
+ SelectedItemChanged.Raise (this, new SelectionChangeEventArgs (SelectedItem));
+ }
+ }
+ [XmlIgnore]public virtual object SelectedItem{
+ get { return data == null ? null : _selectedIndex < 0 ? data.GetDefaultValue() : ((IList)data)?[_selectedIndex]; }
+ set {
+ if (data == null) {
+ SelectedIndex = -1;
+ return;
+ }
+ //TODO:double check if value type will be notified to binding sys
+ if (value == SelectedItem)
+ return;
+
+ SelectedIndex = (int)((IList)data)?.IndexOf (value);
+ }
+ }
+ [XmlIgnore]public bool HasItems {
+ get { return Items.Count > 0; }
+ }
+ public IEnumerable Data {
+ get { return data; }
+ set {
+ if (value == data)
+ return;
+
+ cancelLoadingThread ();
+
+ if (data is IObservableList) {
+ IObservableList ol = data as IObservableList;
+ ol.ListAdd -= Ol_ListAdd;
+ ol.ListRemove -= Ol_ListRemove;
+ }
+
+ data = value;
+
+ if (data is IObservableList) {
+ IObservableList ol = data as IObservableList;
+ ol.ListAdd += Ol_ListAdd;
+ ol.ListRemove += Ol_ListRemove;
+ }
+
+ NotifyValueChanged ("Data", data);
+
+ lock (IFace.UpdateMutex)
+ ClearItems ();
+
+ if (data == null)
+ return;
+
+ loadingThread = new CrowThread (this, loading);
+ loadingThread.Finished += (object sender, EventArgs e) => (sender as TemplatedGroup).Loaded.Raise (sender, e);
+ loadingThread.Start ();
+
+ NotifyValueChanged ("SelectedIndex", _selectedIndex);
+ NotifyValueChanged ("SelectedItem", SelectedItem);
+ SelectedItemChanged.Raise (this, new SelectionChangeEventArgs (SelectedItem));
+ NotifyValueChanged ("HasItems", HasItems);
+ }
+ }
+
+ void Ol_ListRemove (object sender, ListChangedEventArg e)
+ {
+ if (this.isPaged) {
+ int p = e.Index / itemPerPage;
+ int i = e.Index % itemPerPage;
+ (items.Children [p] as Group).DeleteChild (i);
+ } else
+ items.DeleteChild (e.Index);
+ }
+
+ void Ol_ListAdd (object sender, ListChangedEventArg e)
+ {
+ if (this.isPaged) {
+ throw new NotImplementedException();
+// int p = e.Index / itemPerPage;
+// int i = e.Index % itemPerPage;
+// (items.Children [p] as Group).InsertChild (i, e.Element);
+ } else
+ loadItem (e.Element, items, dataTest);
+ }
+
+ [DefaultValue("SteelBlue")]
+ public virtual Color SelectionBackground {
+ get { return selBackground; }
+ set {
+ if (value == selBackground)
+ return;
+ selBackground = value;
+ NotifyValueChanged ("SelectionBackground", selBackground);
+ RegisterForRedraw ();
+ }
+ }
+ [DefaultValue("White")]
+ public virtual Color SelectionForeground {
+ get { return selForeground; }
+ set {
+ if (value == selForeground)
+ return;
+ selForeground = value;
+ NotifyValueChanged ("SelectionForeground", selForeground);
+ RegisterForRedraw ();
+ }
+ }
+
+ protected void raiseSelectedItemChanged(){
+ SelectedItemChanged.Raise (this, new SelectionChangeEventArgs (SelectedItem));
+ }
+
+
+ public virtual void AddItem(Widget g){
+ items.AddChild (g);
+ g.LogicalParent = this;
+ NotifyValueChanged ("HasChildren", true);
+ }
+ public virtual void RemoveItem(Widget g)
+ {
+ g.LogicalParent = null;
+ items.DeleteChild (g);
+ if (items.Children.Count == 0)
+ NotifyValueChanged ("HasChildren", false);
+ }
+
+ public virtual void ClearItems()
+ {
+ _selectedIndex = -1;
+ NotifyValueChanged ("SelectedIndex", _selectedIndex);
+ NotifyValueChanged ("SelectedItem", null);
+
+ items.ClearChildren ();
+ NotifyValueChanged ("HasChildren", false);
+ }
+
+
+ #region GraphicObject overrides
+ public override Widget FindByName (string nameToFind)
+ {
+ if (Name == nameToFind)
+ return this;
+
+ foreach (Widget w in Items) {
+ Widget r = w.FindByName (nameToFind);
+ if (r != null)
+ return r;
+ }
+ return null;
+ }
+ public override bool Contains (Widget goToFind)
+ {
+ foreach (Widget w in Items) {
+ if (w == goToFind)
+ return true;
+ if (w.Contains (goToFind))
+ return true;
+ }
+ return base.Contains(goToFind);
+ }
+// public override void ClearBinding ()
+// {
+// if (items != null)
+// items.ClearBinding ();
+//
+// base.ClearBinding ();
+// }
+// public override void ResolveBindings ()
+// {
+// base.ResolveBindings ();
+// if (items != null)
+// items.ResolveBindings ();
+// }
+ #endregion
+
+ /// <summary>
+ /// Items loading thread
+ /// </summary>
+ void loading(){
+ try {
+ loadPage (data, items, dataTest);
+ } catch {
+ if (Monitor.IsEntered (IFace.LayoutMutex))
+ Monitor.Exit (IFace.LayoutMutex);
+ Console.WriteLine ("loading thread aborted");
+ }
+
+ }
+// //if (!ItemTemplates.ContainsKey ("default"))
+// // ItemTemplates ["default"] = Interface.GetItemTemplate (ItemTemplate);
+//
+// for (int i = 1; i <= (data.Count / itemPerPage) + 1; i++) {
+// if ((bool)loadingThread?.cancelRequested) {
+// this.Dispose ();
+// return;
+// }
+// loadPage (i);
+// Thread.Sleep (1);
+// }
+// }
+ void cancelLoadingThread(){
+ if (loadingThread != null)
+ loadingThread.Cancel ();
+ }
+ void loadPage(IEnumerable _data, Group page, string _dataTest)
+ {
+ #if DEBUG_LOAD
+ Stopwatch loadingTime = Stopwatch.StartNew ();
+ #endif
+
+
+// if (typeof(TabView).IsAssignableFrom (items.GetType ())||
+// typeof(Menu).IsAssignableFrom (this.GetType())||
+// typeof(Wrapper).IsAssignableFrom (items.GetType ())) {
+ //page = items;
+ itemPerPage = int.MaxValue;
+ // } else if (typeof(GenericStack).IsAssignableFrom (items.GetType ())) {
+ // GenericStack gs = new GenericStack (items.CurrentInterface);
+ // gs.Orientation = (items as GenericStack).Orientation;
+ // gs.Width = items.Width;
+ // gs.Height = items.Height;
+ // gs.VerticalAlignment = items.VerticalAlignment;
+ // gs.HorizontalAlignment = items.HorizontalAlignment;
+ // page = gs;
+ // page.Name = "page" + pageNum;
+ // isPaged = true;
+ // } else {
+ // page = Activator.CreateInstance (items.GetType ()) as Group;
+ // page.CurrentInterface = items.CurrentInterface;
+ // page.Initialize ();
+ // page.Name = "page" + pageNum;
+ // isPaged = true;
+ // }
+
+ if (_data == null)
+ return;
+
+ foreach (object d in _data) {
+ loadItem (d, page, _dataTest);
+ if (loadingThread.cancelRequested)
+ break;
+ }
+
+// if (page == items)
+// return;
+// lock (CurrentInterface.LayoutMutex)
+// items.AddChild (page);
+
+#if DEBUG_LOAD
+ loadingTime.Stop ();
+ using (StreamWriter sw = new StreamWriter ("loading.log", true)) {
+ sw.WriteLine ($"NEW ;{this.ToString(),-50};{loadingTime.ElapsedTicks,8};{loadingTime.ElapsedMilliseconds,8}");
+ }
+#endif
+ }
+
+ protected void loadItem(object o, Group page, string _dataTest){
+ if (o == null)//TODO:surely a threading sync problem
+ return;
+ Widget g = null;
+ ItemTemplate iTemp = null;
+ Type dataType = o.GetType ();
+ string itempKey = dataType.FullName;
+
+ //if item template selection is not done depending on the type of item
+ //dataTest must contains a member name of the item
+ if (_dataTest != "TypeOf") {
+ try {
+ itempKey = CompilerServices.getValue (dataType, o, _dataTest)?.ToString ();
+ } catch {
+ itempKey = dataType.FullName;
+ }
+ }
+
+ if (ItemTemplates.ContainsKey (itempKey))
+ iTemp = ItemTemplates [itempKey];
+ else {
+ foreach (string it in ItemTemplates.Keys) {
+ if (it == "default")
+ continue;
+ Type t = CompilerServices.getTypeFromName (it);
+ if (t == null)
+ continue;
+ if (t.IsAssignableFrom (dataType)) {//TODO:types could be cached
+ iTemp = ItemTemplates [it];
+ break;
+ }
+ }
+ if (iTemp == null)
+ iTemp = ItemTemplates ["default"];
+ }
+
+ Monitor.Enter (IFace.LayoutMutex);
+ g = iTemp.CreateInstance();
+ #if DESIGN_MODE
+ g.design_isTGItem = true;
+ #endif
+ page.AddChild (g);
+// if (isPaged)
+ g.LogicalParent = this;
+ g.MouseClick += itemClick;
+ Monitor.Exit (IFace.LayoutMutex);
+
+ if (iTemp.Expand != null && g is Expandable) {
+ Expandable e = g as Expandable;
+ e.Expand += iTemp.Expand;
+ if ((o as ICollection) == null)
+ e.GetIsExpandable = new BooleanTestOnInstance((instance) => true);
+ else
+ e.GetIsExpandable = iTemp.HasSubItems;
+ }
+
+ g.DataSource = o;
+ }
+
+
+ // protected void _list_LayoutChanged (object sender, LayoutingEventArgs e)
+ // {
+ // #if DEBUG_LAYOUTING
+ // Debug.WriteLine("list_LayoutChanged");
+ // #endif
+ // if (_gsList.Orientation == Orientation.Horizontal) {
+ // if (e.LayoutType == LayoutingType.Width)
+ // _gsList.Width = approxSize;
+ // } else if (e.LayoutType == LayoutingType.Height)
+ // _gsList.Height = approxSize;
+ // }
+ int approxSize
+ {
+ get {
+ if (data == null)
+ return -1;
+ GenericStack page1 = items.FindByName ("page1") as GenericStack;
+ if (page1 == null)
+ return -1;
+
+ return page1.Orientation == Orientation.Horizontal ?
+ (data as ICollection)?.Count < itemPerPage ?
+ -1:
+ (int)Math.Ceiling ((double)page1.Slot.Width / (double)itemPerPage * (double)((data as ICollection)?.Count+1)):
+ (data as ICollection)?.Count < itemPerPage ?
+ -1:
+ (int)Math.Ceiling ((double)page1.Slot.Height / (double)itemPerPage * (double)((data as ICollection)?.Count+1));
+ }
+ }
+ internal virtual void itemClick(object sender, MouseButtonEventArgs e){
+ SelectedIndex = (int)((IList)data)?.IndexOf((sender as Widget).DataSource);
+ }
+
+ bool emitHelperIsAlreadyExpanded (Widget go){
+ if (nodes.Contains (go))
+ return true;
+ nodes.Add (go);
+ return false;
+ }
+
+ protected override void Dispose (bool disposing)
+ {
+ if (disposing && loadingThread != null)
+ loadingThread.Cancel ();
+ base.Dispose (disposing);
+ }
+
+ public override void OnDataSourceChanged (object sender, DataSourceChangeEventArgs e)
+ {
+ base.OnDataSourceChanged (sender, e);
+ }
+ }
+}
--- /dev/null
+//
+// TestCairoPatch.cs
+//
+// Author:
+// jp <>
+//
+// 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 Crow.Cairo;
+
+namespace Crow
+{
+ public class TestCairoPatch : Widget
+ {
+ void computeControlPoints (
+ double xc, double yc,
+ double x1, double y1,
+ out double x2, out double y2,
+ out double x3, out double y3,
+ double x4, double y4){
+ double ax = x1 - xc;
+ double ay = y1 - yc;
+ double bx = x4 - xc;
+ double byy = y4 - yc;
+ double q1 = ax * ax + ay * ay;
+ double q2 = q1 + ax * bx + ay * byy;
+ double k2 = 4.0/3.0 * (Math.Sqrt(2.0 * q1 * q2) - q2) / (ax * byy - ay * bx);
+
+
+ x2 = xc + ax - k2 * ay;
+ y2 = yc + ay + k2 * ax;
+ x3 = xc + bx + k2 * byy;
+ y3 = yc + byy - k2 * bx;
+ }
+ protected override void onDraw (Context gr)
+ {
+ base.onDraw (gr);
+
+ double radius = Math.Min (ClientRectangle.Width, ClientRectangle.Height) / 2;
+
+ double pi3 = Math.PI / 3.0;
+
+ MeshPattern mp = new MeshPattern ();
+
+ double x1 = radius,y1 = 0,
+ x2 = 0, y2 = 0, x3 = 0, y3 = 0, x4 = 0, y4 = 0,
+ xc = radius,yc = radius;
+
+ double dx = Math.Sin (pi3) * radius;
+ double dy = Math.Cos (pi3) * radius;
+
+ mp.BeginPatch ();
+ mp.MoveTo (xc, yc);
+ mp.LineTo (x1, y1);
+ x4 = xc + dx;
+ y4 = yc - dy;
+ computeControlPoints (xc, yc, x1, y1, out x2, out y2, out x3, out y3, x4, y4);
+ mp.CurveTo (x2, y2, x3, y3, x4, y4);
+
+ mp.SetCornerColorRGB (0, 1, 1, 1);
+ mp.SetCornerColorRGB (1, 1, 0, 0);
+ mp.SetCornerColorRGB (2, 1, 1, 0);
+
+ x1 = x4;
+ y1 = y4;
+ y4 = yc + dy;
+
+ computeControlPoints (xc, yc, x1, y1, out x2, out y2, out x3, out y3, x4, y4);
+ mp.CurveTo (x2, y2, x3, y3, x4, y4);
+
+ mp.SetCornerColorRGB (3, 0, 1, 0);
+ mp.EndPatch ();
+
+ x1 = x4;
+ y1 = y4;
+ x4 = xc;
+ y4 = yc * 2.0;
+
+ mp.BeginPatch ();
+ mp.MoveTo (xc, yc);
+ mp.LineTo (x1, y1);
+ computeControlPoints (xc, yc, x1, y1, out x2, out y2, out x3, out y3, x4, y4);
+ mp.CurveTo (x2, y2, x3, y3, x4, y4);
+
+ mp.SetCornerColorRGB (0, 1, 1, 1);
+ mp.SetCornerColorRGB (1, 0, 1, 0);
+ mp.SetCornerColorRGB (2, 0, 1, 1);
+
+ x1 = x4;
+ y1 = y4;
+ x4 = xc-dx;
+ y4 = yc+dy;
+
+ computeControlPoints (xc, yc, x1, y1, out x2, out y2, out x3, out y3, x4, y4);
+ mp.CurveTo (x2, y2, x3, y3, x4, y4);
+
+ mp.SetCornerColorRGB (3, 0, 0, 1);
+ mp.EndPatch ();
+
+ x1 = x4;
+ y1 = y4;
+ y4 = yc - dy;
+
+ mp.BeginPatch ();
+ mp.MoveTo (xc, yc);
+ mp.LineTo (x1, y1);
+ computeControlPoints (xc, yc, x1, y1, out x2, out y2, out x3, out y3, x4, y4);
+ mp.CurveTo (x2, y2, x3, y3, x4, y4);
+
+ mp.SetCornerColorRGB (0, 1, 1, 1);
+ mp.SetCornerColorRGB (1, 0, 0, 1);
+ mp.SetCornerColorRGB (2, 1, 0, 1);
+
+ x1 = x4;
+ y1 = y4;
+ x4 = radius;
+ y4 = 0;
+
+ computeControlPoints (xc, yc, x1, y1, out x2, out y2, out x3, out y3, x4, y4);
+ mp.CurveTo (x2, y2, x3, y3, x4, y4);
+
+ mp.SetCornerColorRGB (3, 1, 0, 0);
+ mp.EndPatch ();
+
+ gr.SetSource (mp);
+ gr.Paint ();
+ }
+ }
+}
+
--- /dev/null
+//
+// TextBox.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 Crow.Cairo;
+using System.Diagnostics;
+using System.Xml.Serialization;
+
+namespace Crow
+{
+ public class TextBox : Label
+ {
+ #region CTOR
+ protected TextBox() : base(){}
+ public TextBox(Interface iface) : base(iface)
+ { }
+// public TextBox(string _initialValue)
+// : base(_initialValue)
+// {
+//
+// }
+ #endregion
+
+ #region GraphicObject overrides
+ [XmlIgnore]public override bool HasFocus //trigger update when lost focus to errase text beam
+ {
+ get
+ {
+ return base.HasFocus;
+ }
+ set
+ {
+ base.HasFocus = value;
+ RegisterForRedraw();
+ }
+ }
+
+ protected override void onDraw (Context gr)
+ {
+ base.onDraw (gr);
+ FontExtents fe = gr.FontExtents;
+ }
+ #endregion
+
+ #region Keyboard handling
+ public override void onKeyDown (object sender, KeyEventArgs e)
+ {
+ base.onKeyDown (sender, e);
+
+ Key key = e.Key;
+
+ switch (key)
+ {
+ case Key.BackSpace:
+ if (CurrentPosition == 0)
+ return;
+ this.DeleteChar();
+ break;
+ case Key.Clear:
+ break;
+ case Key.Delete:
+ if (selectionIsEmpty) {
+ if (!MoveRight ())
+ return;
+ }else if (IFace.Shift)
+ IFace.Clipboard = this.SelectedText;
+ this.DeleteChar ();
+ break;
+ case Key.KP_Enter:
+ case Key.Return:
+ if (!selectionIsEmpty)
+ this.DeleteChar ();
+ if (Multiline)
+ this.InsertLineBreak ();
+ else
+ OnTextChanged(this,new TextChangeEventArgs(Text));
+ break;
+ case Key.Escape:
+ Text = "";
+ CurrentColumn = 0;
+ SelRelease = -1;
+ break;
+ case Key.Home:
+ if (IFace.Shift) {
+ if (selectionIsEmpty)
+ SelBegin = new Point (CurrentColumn, CurrentLine);
+ if (IFace.Ctrl)
+ CurrentLine = 0;
+ CurrentColumn = 0;
+ SelRelease = new Point (CurrentColumn, CurrentLine);
+ break;
+ }
+ SelRelease = -1;
+ if (IFace.Ctrl)
+ CurrentLine = 0;
+ CurrentColumn = 0;
+ break;
+ case Key.End:
+ if (IFace.Shift) {
+ if (selectionIsEmpty)
+ SelBegin = CurrentPosition;
+ if (IFace.Ctrl)
+ CurrentLine = int.MaxValue;
+ CurrentColumn = int.MaxValue;
+ SelRelease = CurrentPosition;
+ break;
+ }
+ SelRelease = -1;
+ if (IFace.Ctrl)
+ CurrentLine = int.MaxValue;
+ CurrentColumn = int.MaxValue;
+ break;
+ case Key.Insert:
+ if (IFace.Shift)
+ this.Insert (IFace.Clipboard);
+ else if (IFace.Ctrl && !selectionIsEmpty)
+ IFace.Clipboard = this.SelectedText;
+ break;
+ case Key.Left:
+ if (IFace.Shift) {
+ if (selectionIsEmpty)
+ SelBegin = new Point(CurrentColumn, CurrentLine);
+ if (IFace.Ctrl)
+ GotoWordStart ();
+ else if (!MoveLeft ())
+ return;
+ SelRelease = CurrentPosition;
+ break;
+ }
+ SelRelease = -1;
+ if (IFace.Ctrl)
+ GotoWordStart ();
+ else
+ MoveLeft();
+ break;
+ case Key.Right:
+ if (IFace.Shift) {
+ if (selectionIsEmpty)
+ SelBegin = CurrentPosition;
+ if (IFace.Ctrl)
+ GotoWordEnd ();
+ else if (!MoveRight ())
+ return;
+ SelRelease = CurrentPosition;
+ break;
+ }
+ SelRelease = -1;
+ if (IFace.Ctrl)
+ GotoWordEnd ();
+ else
+ MoveRight ();
+ break;
+ case Key.Up:
+ if (IFace.Shift) {
+ if (selectionIsEmpty)
+ SelBegin = CurrentPosition;
+ CurrentLine--;
+ SelRelease = CurrentPosition;
+ break;
+ }
+ SelRelease = -1;
+ CurrentLine--;
+ break;
+ case Key.Down:
+ if (IFace.Shift) {
+ if (selectionIsEmpty)
+ SelBegin = CurrentPosition;
+ CurrentLine++;
+ SelRelease = CurrentPosition;
+ break;
+ }
+ SelRelease = -1;
+ CurrentLine++;
+ break;
+ case Key.Menu:
+ break;
+ case Key.Num_Lock:
+ break;
+ case Key.Page_Down:
+ break;
+ case Key.Page_Up:
+ break;
+ case Key.Tab:
+ this.Insert ("\t");
+ break;
+ default:
+ break;
+ }
+
+ RegisterForGraphicUpdate();
+ }
+ public override void onKeyPress (object sender, KeyPressEventArgs e)
+ {
+ base.onKeyPress (sender, e);
+
+ this.Insert (e.KeyChar.ToString());
+
+ SelRelease = -1;
+ SelBegin = new Point(CurrentColumn, SelBegin.Y);
+
+ RegisterForGraphicUpdate();
+ }
+ #endregion
+ }
+}
--- /dev/null
+//
+// TextRun.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.Linq;
+using System.Text;
+using System.Diagnostics;
+using Crow.Cairo;
+using System.Text.RegularExpressions;
+using System.Xml.Serialization;
+using System.ComponentModel;
+
+namespace Crow
+{
+ [DesignIgnore]
+ public class TextRun : Widget
+ {
+ #region CTOR
+ protected TextRun () : base(){}
+ public TextRun (Interface iface) : base (iface){}
+ #endregion
+
+ //TODO:change protected to private
+
+ #region private and protected fields
+ protected string _text = "label";
+ Alignment _textAlignment = Alignment.Left;
+ bool horizontalStretch = false;
+ bool verticalStretch = false;
+ bool _multiline;
+ bool wordWrap;
+ protected Rectangle rText;
+ protected float widthRatio = 1f;
+ protected float heightRatio = 1f;
+ protected FontExtents fe;
+ protected TextExtents te;
+ #endregion
+
+
+
+ [DefaultValue (Alignment.Left)]
+ public Alignment TextAlignment {
+ get { return _textAlignment; }
+ set { _textAlignment = value; }
+ }
+
+ [DefaultValue (false)]
+ public virtual bool HorizontalStretch {
+ get { return horizontalStretch; }
+ set {
+ if (horizontalStretch == value)
+ return;
+ horizontalStretch = value;
+ RegisterForRedraw ();
+ NotifyValueChanged ("HorizontalStretch", horizontalStretch);
+ }
+ }
+
+ [DefaultValue (false)]
+ public virtual bool VerticalStretch {
+ get { return verticalStretch; }
+ set {
+ if (verticalStretch == value)
+ return;
+ verticalStretch = value;
+ RegisterForRedraw ();
+ NotifyValueChanged ("VerticalStretch", verticalStretch);
+ }
+ }
+
+ [DefaultValue ("label")]
+ public string Text {
+ get {
+ return lines == null ?
+ _text : lines.Aggregate ((i, j) => i + Interface.LineBreak + j);
+ }
+ set {
+ if (_text == value)
+ return;
+
+ RegisterForGraphicUpdate ();
+
+ _text = value;
+
+ if (string.IsNullOrEmpty (_text))
+ _text = "";
+
+ lines = getLines;
+ }
+ }
+
+ [DefaultValue (false)]
+ public bool Multiline {
+ get { return _multiline; }
+ set {
+ _multiline = value;
+ RegisterForGraphicUpdate ();
+ }
+ }
+
+ [DefaultValue (false)]
+ public bool WordWrap {
+ get {
+ return wordWrap;
+ }
+ set {
+ if (wordWrap == value)
+ return;
+ wordWrap = value;
+ RegisterForGraphicUpdate ();
+ }
+ }
+
+ List<string> lines;
+ List<string> getLines {
+ get {
+ return _multiline ?
+ Regex.Split (_text, "\r\n|\r|\n").ToList () :
+ new List<string> (new string [] { _text });
+ }
+ }
+
+ #region GraphicObject overrides
+ protected override int measureRawSize (LayoutingType lt)
+ {
+ if (lines == null)
+ lines = getLines;
+
+ using (Context gr = new Context (IFace.surf)) {
+ //Cairo.FontFace cf = gr.GetContextFontFace ();
+
+ gr.SelectFontFace (Font.Name, Font.Slant, Font.Wheight);
+ gr.SetFontSize (Font.Size);
+
+
+ fe = gr.FontExtents;
+ te = new TextExtents ();
+
+ if (lt == LayoutingType.Height) {
+ int lc = lines.Count;
+ //ensure minimal height = text line height
+ if (lc == 0)
+ lc = 1;
+
+ return (int)(fe.Height * lc) + Margin * 2;
+ }
+
+ foreach (string s in lines) {
+ string l = s.Replace("\t", new String (' ', Interface.TAB_SIZE));
+ TextExtents tmp = gr.TextExtents (l);
+ if (tmp.XAdvance > te.XAdvance)
+ te = tmp;
+ }
+ return (int)Math.Ceiling (te.XAdvance) + Margin * 2;
+ }
+ }
+ protected override void onDraw (Context gr)
+ {
+ base.onDraw (gr);
+
+ gr.SelectFontFace (Font.Name, Font.Slant, Font.Wheight);
+ gr.SetFontSize (Font.Size);
+ gr.FontOptions = Interface.FontRenderingOptions;
+ gr.Antialias = Interface.Antialias;
+
+ rText = new Rectangle (new Size (
+ measureRawSize (LayoutingType.Width), measureRawSize (LayoutingType.Height)));
+ rText.Width -= 2 * Margin;
+ rText.Height -= 2 * Margin;
+
+ widthRatio = 1f;
+ heightRatio = 1f;
+
+ Rectangle cb = ClientRectangle;
+
+ //ignore text alignment if size to content = true
+ //or if text size is larger than client bounds
+ if (Width < 0 || Height < 0 || rText.Width > cb.Width) {
+ rText.X = cb.X;
+ rText.Y = cb.Y;
+ } else {
+ if (horizontalStretch) {
+ widthRatio = (float)cb.Width / rText.Width;
+ if (!verticalStretch)
+ heightRatio = widthRatio;
+ }
+ if (verticalStretch) {
+ heightRatio = (float)cb.Height / rText.Height;
+ if (!horizontalStretch)
+ widthRatio = heightRatio;
+ }
+
+ rText.Width = (int)(widthRatio * cb.Width);
+ rText.Height = (int)(heightRatio * cb.Height);
+
+ switch (TextAlignment) {
+ case Alignment.TopLeft: //ok
+ rText.X = cb.X;
+ rText.Y = cb.Y;
+ break;
+ case Alignment.Top: //ok
+ rText.Y = cb.Y;
+ rText.X = cb.X + cb.Width / 2 - rText.Width / 2;
+ break;
+ case Alignment.TopRight: //ok
+ rText.Y = cb.Y;
+ rText.X = cb.Right - rText.Width;
+ break;
+ case Alignment.Left://ok
+ rText.X = cb.X;
+ rText.Y = cb.Y + cb.Height / 2 - rText.Height / 2;
+ break;
+ case Alignment.Right://ok
+ rText.X = cb.X + cb.Width - rText.Width;
+ rText.Y = cb.Y + cb.Height / 2 - rText.Height / 2;
+ break;
+ case Alignment.Bottom://ok
+ rText.X = cb.Width / 2 - rText.Width / 2;
+ rText.Y = cb.Height - rText.Height;
+ break;
+ case Alignment.BottomLeft://ok
+ rText.X = cb.X;
+ rText.Y = cb.Bottom - rText.Height;
+ break;
+ case Alignment.BottomRight://ok
+ rText.Y = cb.Bottom - rText.Height;
+ rText.X = cb.Right - rText.Width;
+ break;
+ case Alignment.Center://ok
+ rText.X = cb.X + cb.Width / 2 - rText.Width / 2;
+ rText.Y = cb.Y + cb.Height / 2 - rText.Height / 2;
+ break;
+ }
+ }
+
+ gr.FontMatrix = new Matrix (widthRatio * Font.Size, 0, 0, heightRatio * Font.Size, 0, 0);
+
+
+ int curLineCount = 0;
+ for (int i = 0; i < lines.Count; i++) {
+ string l = lines [i].Replace ("\t", new String (' ', Interface.TAB_SIZE));
+ List<string> wl = new List<string> ();
+ int lineLength = (int)gr.TextExtents (l).XAdvance;
+
+ if (wordWrap && lineLength > cb.Width) {
+ string tmpLine = "";
+ int curChar = 0;
+ while (curChar < l.Length) {
+ tmpLine += l [curChar];
+ if ((int)gr.TextExtents (tmpLine).XAdvance > cb.Width) {
+ tmpLine = tmpLine.Remove (tmpLine.Length - 1);
+ wl.Add (tmpLine);
+ tmpLine = "";
+ continue;
+ }
+ curChar++;
+ }
+ wl.Add (tmpLine);
+ } else
+ wl.Add (l);
+
+ foreach (string ll in wl) {
+ lineLength = (int)gr.TextExtents (ll).XAdvance;
+
+
+ if (string.IsNullOrWhiteSpace (ll)) {
+ curLineCount++;
+ continue;
+ }
+
+ Foreground.SetAsSource (gr);
+ gr.MoveTo (rText.X, rText.Y + fe.Ascent + fe.Height * curLineCount);
+
+ gr.ShowText (ll);
+ gr.Fill ();
+
+ curLineCount++;
+ }
+ }
+ }
+ #endregion
+ }
+}
--- /dev/null
+//
+// TreeView.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.Xml.Serialization;
+using System.Diagnostics;
+using System.ComponentModel;
+
+namespace Crow
+{
+ //treeview expect expandable child (or not)
+ //if their are expandable, some functions and events are added
+ public class TreeView : TemplatedGroup
+ {
+ Widget selectedItemContainer = null;
+ bool isRoot;
+
+ #region CTOR
+ protected TreeView() : base(){}
+ public TreeView (Interface iface) : base(iface)
+ {
+ }
+ #endregion
+
+ [DefaultValue(false)]
+ public virtual bool IsRoot {
+ get { return isRoot; }
+ set {
+ if (isRoot == value)
+ return;
+ isRoot = value;
+ NotifyValueChanged ("IsRoot", isRoot);
+ }
+ }
+ [XmlIgnore]public override object SelectedItem {
+ get {
+ return selectedItemContainer == null ?
+ "" : selectedItemContainer.DataSource;
+ }
+ }
+
+ internal override void itemClick (object sender, MouseButtonEventArgs e)
+ {
+ Widget tmp = sender as Widget;
+ //if (!tmp.HasFocus)
+ // return;
+ /*if (selectedItemContainer != null) {
+ selectedItemContainer.Foreground = Color.Transparent;
+ selectedItemContainer.Background = Color.Transparent;
+ }*/
+ selectedItemContainer = tmp;
+ //selectedItemContainer.Foreground = SelectionForeground;
+ //selectedItemContainer.Background = SelectionBackground;
+ NotifyValueChanged ("SelectedItem", SelectedItem);
+ raiseSelectedItemChanged ();
+ }
+
+ void onExpandAll_MouseClick (object sender, MouseButtonEventArgs e)
+ {
+ ExpandAll ();
+ }
+
+ public void ExpandAll(){
+ foreach (Group grp in items.Children) {
+ foreach (Widget go in grp.Children) {
+ Expandable exp = go as Expandable;
+ if (exp == null)
+ continue;
+ TreeView subTV = exp.FindByName ("List") as TreeView;
+ if (subTV == null)
+ continue;
+ EventHandler handler = null;
+ handler = delegate(object sender, EventArgs e) {
+ TreeView tv = sender as TreeView;
+ tv.Loaded -= handler;
+ tv.ExpandAll ();
+ };
+ subTV.Loaded += handler;
+ exp.IsExpanded = true;
+ }
+ }
+ }
+ }
+}
+
--- /dev/null
+//
+// Trend.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.Xml.Serialization;
+using System.ComponentModel;
+using Crow.Cairo;
+
+namespace Crow
+{
+ public class Trend : Widget
+ {
+ #region private fields
+ double minValue, maxValue, lowThreshold, highThreshold;
+ Fill lowThresholdFill, highThresholdFill;
+ int nbValues;
+ List<double> values = new List<double>();
+ #endregion
+
+
+
+ public virtual void AddValue(double _value)
+ {
+ values.Add (_value);
+ while (values.Count > nbValues)
+ values.RemoveAt (0);
+ RegisterForRedraw ();
+ }
+ #region CTOR
+ protected Trend () : base()
+ {
+ }
+ #endregion
+ [XmlIgnore]public virtual int NewValue {
+ set {
+ AddValue (value);
+ }
+ }
+ [DefaultValue(400)]
+ public virtual int NbValues {
+ get { return nbValues; }
+ set {
+ if (nbValues == value)
+ return;
+
+ nbValues = value;
+ NotifyValueChanged ("NbValues", minValue);
+ RegisterForRedraw ();
+ }
+ }
+ [DefaultValue(0.0)]
+ public virtual double Minimum {
+ get { return minValue; }
+ set {
+ if (minValue == value)
+ return;
+
+ minValue = value;
+ NotifyValueChanged ("Minimum", minValue);
+ RegisterForRedraw ();
+ }
+ }
+ [DefaultValue(100.0)]
+ public virtual double Maximum
+ {
+ get { return maxValue; }
+ set {
+ if (maxValue == value)
+ return;
+
+ maxValue = value;
+ NotifyValueChanged ("Maximum", maxValue);
+ RegisterForRedraw ();
+ }
+ }
+ [DefaultValue(1.0)]
+ public virtual double LowThreshold {
+ get { return lowThreshold; }
+ set {
+ if (lowThreshold == value)
+ return;
+ lowThreshold = value;
+ NotifyValueChanged ("LowThreshold", lowThreshold);
+ RegisterForGraphicUpdate ();
+ }
+ }
+ [DefaultValue(80.0)]
+ public virtual double HighThreshold {
+ get { return highThreshold; }
+ set {
+ if (highThreshold == value)
+ return;
+ highThreshold = value;
+ NotifyValueChanged ("HighThreshold", highThreshold);
+ RegisterForGraphicUpdate ();
+ }
+ }
+ [DefaultValue("DarkRed")]
+ public virtual Fill LowThresholdFill {
+ get { return lowThresholdFill; }
+ set {
+ if (lowThresholdFill == value)
+ return;
+ lowThresholdFill = value;
+ NotifyValueChanged ("LowThresholdFill", lowThresholdFill);
+ RegisterForRedraw ();
+ }
+ }
+ [DefaultValue("DarkGreen")]
+ public virtual Fill HighThresholdFill {
+ get { return highThresholdFill; }
+ set {
+ if (highThresholdFill == value)
+ return;
+ highThresholdFill = value;
+ NotifyValueChanged ("HighThresholdFill", highThresholdFill);
+ RegisterForRedraw ();
+ }
+ }
+ protected override void onDraw (Context gr)
+ {
+ base.onDraw (gr);
+
+ if (values.Count == 0)
+ return;
+ Rectangle r = ClientRectangle;
+
+ int i = values.Count -1;
+
+ double ptrX = (double)r.Right;
+ double scaleY = (double)r.Height / (Maximum - Minimum);
+ double stepX = (double)r.Width / (double)(nbValues-1);
+
+ gr.LineWidth = 1.0;
+ gr.SetDash (new double[]{ 1.0 },0.0);
+
+
+
+ LowThresholdFill.SetAsSource (gr);
+ gr.MoveTo (r.Left, r.Bottom - LowThreshold * scaleY);
+ gr.LineTo (r.Right, r.Bottom - LowThreshold * scaleY);
+// gr.Rectangle (r.Left, r.Bottom - LowThreshold * scaleY, r.Width, LowThreshold * scaleY);
+ gr.Stroke();
+
+ HighThresholdFill.SetAsSource (gr);
+ gr.MoveTo (r.Left, (Maximum - HighThreshold) * scaleY);
+ gr.LineTo (r.Right, (Maximum - HighThreshold) * scaleY);
+// gr.Rectangle (r.Left, r.Top, r.Width, (Maximum - HighThreshold) * scaleY);
+ gr.Stroke();
+
+ gr.MoveTo (ptrX, values [i] * scaleY);
+
+ Foreground.SetAsSource (gr);
+ gr.SetDash (new double[]{ }, 0.0);
+
+ while (i >= 0) {
+ gr.LineTo (ptrX, r.Bottom - values [i] * scaleY);
+ ptrX -= stepX;
+ i--;
+ }
+ gr.Stroke ();
+ }
+ }
+}
+
--- /dev/null
+//
+// VerticalStack.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.Linq;
+using System.Text;
+
+namespace Crow
+{
+ /// <summary>
+ /// group control stacking its children vertically
+ /// </summary>
+ public class VerticalStack : GenericStack
+ {
+ #region CTOR
+ protected VerticalStack() : base(){}
+ public VerticalStack(Interface iface) : base(iface)
+ {
+ }
+ #endregion
+
+ [XmlIgnore]
+ public override Orientation Orientation
+ {
+ get { return Orientation.Vertical; }
+ }
+
+
+ }
+}
--- /dev/null
+//
+// 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 Crow.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 Widget : ILayoutable, IValueChange, IDisposable
+ {
+ internal ReaderWriterLockSlim parentRWLock = new ReaderWriterLockSlim();
+ #if DEBUG_LOG
+ //0 is the main graphic tree, for other obj tree not added to main tree, it range from 1->n
+ //useful to track events for obj shown later, not on start, or never added to main tree
+ public int treeIndex;
+ public int yIndex;//absolute index in the graphic tree for debug draw
+ public int xLevel;//x increment for debug draw
+ #endif
+ #if DESIGN_MODE
+ static MethodInfo miDesignAddDefLoc = typeof(Widget).GetMethod("design_add_style_location",
+ BindingFlags.Instance | BindingFlags.NonPublic);
+ static MethodInfo miDesignAddValLoc = typeof(Widget).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 Widget 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;
+ }
+ public string DesignName {
+ get { return GetType ().Name + design_id; }
+ }
+ #endif
+
+ #region IDisposable implementation
+ protected bool disposed = false;
+
+ public void Dispose(){
+ Dispose(true);
+ GC.SuppressFinalize(this);
+ }
+ ~Widget(){
+ Console.WriteLine(this.ToString() + " not disposed by user");
+ Dispose(false);
+ }
+ protected virtual void Dispose(bool disposing){
+ if (disposed){
+ #if DEBUG_DISPOSE
+ Console.WriteLine ("Trying to dispose already disposed obj: {0}", this.ToString());
+ #endif
+ return;
+ }
+
+ if (disposing) {
+ #if DEBUG_DISPOSE
+ Console.WriteLine ("Disposing: {0}", this.ToString());
+ //if ()
+ //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
+
+ #if DEBUG_LOG
+ internal static List<GraphicObject> GraphicObjects = new List<GraphicObject>();
+ #endif
+
+ //internal bool isPopup = false;
+ //public Widget focusParent {
+ // get { return (isPopup ? LogicalParent : parent) as Widget; }
+ //}
+
+ /// <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 Widget () {
+ Clipping = new Region ();
+ #if DEBUG_LOG
+ GraphicObjects.Add (this);
+ DebugLog.AddEvent(DbgEvtType.GOClassCreation, this);
+ #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 Widget (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 ();
+ }
+ #region private fields
+ LayoutingType registeredLayoutings = LayoutingType.All;
+ ILayoutable logicalParent;
+ ILayoutable parent;
+ string name;
+ Fill background = Color.Transparent;
+ Fill foreground = Color.White;
+ Font font = "sans, 10";
+ protected Measure width, height;
+ int left, top;
+ double cornerRadius;
+ int margin;
+ bool focusable ;
+ bool hasFocus;
+ bool isActive;
+ bool isHover;
+ bool mouseRepeat;
+ MouseCursor mouseCursor = MouseCursor.Arrow;
+ 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;
+ bool clipToClientRect = true;
+ Type dataSourceType;
+ 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);
+ }
+ }
+ /// <summary>
+ /// Mouse routing need to go back to logical parent for popups
+ /// </summary>
+ public Widget FocusParent => (parent is Interface ? LogicalParent : parent) as Widget;
+
+ [XmlIgnore]public ILayoutable LogicalParent {
+ get { return logicalParent == null ? Parent : logicalParent; }
+ set {
+ if (logicalParent == value)
+ return;
+ if (logicalParent is Widget)
+ (logicalParent as Widget).DataSourceChanged -= onLogicalParentDataSourceChanged;
+ DataSourceChangeEventArgs dsce = new DataSourceChangeEventArgs (LogicalParent, null);
+ logicalParent = value;
+ dsce.NewDataSource = LogicalParent;
+ if (logicalParent is Widget)
+ (logicalParent as Widget).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){
+ Widget go = Parent as Widget;
+ 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<KeyEventArgs> KeyDown;
+ /// <summary>Occurs when key is released when this object is active</summary>
+ public event EventHandler<KeyEventArgs> 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
+
+ internal bool hasDoubleClick => MouseDoubleClick != null;
+ internal bool hasClick => MouseClick != null;
+
+ #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_LOG
+ [XmlIgnore]public string TreePath {
+ get { return this.GetType().Name + GraphicObjects.IndexOf(this).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_LOG
+ return string.IsNullOrEmpty(name) ? this.GetType().Name + GraphicObjects.IndexOf(this).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 Widget ? (Parent as Widget).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 Widget ? (Parent as Widget).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)
+ Hover.Raise (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);
+ }
+ }
+ /// <summary>
+ /// Determine Cursor when mouse is Hover.
+ /// </summary>
+ [DesignCategory ("Behaviour")]
+ [DefaultValue (MouseCursor.Arrow)]
+ public virtual MouseCursor MouseCursor {
+ get { return mouseCursor; }
+ set {
+ if (mouseCursor == value)
+ return;
+ mouseCursor = value;
+ NotifyValueChanged ("MouseCursor", mouseCursor);
+ this.RegisterForRedraw ();
+
+ if (isHover)
+ IFace.MouseCursor = mouseCursor;
+ }
+ }
+
+ /// <summary>
+ /// forward mouse events even if an handle is bound
+ /// </summary>
+ //[DesignCategory ("Behaviour")][DefaultValue (false)]
+ //public bool ForwardMouseEvents {
+ // get { return forwardMouseEvents; }
+ // set {
+ // if (forwardMouseEvents == value)
+ // return;
+ // forwardMouseEvents = value;
+ // NotifyValueChanged ("ForwardMouseEvents", forwardMouseEvents);
+ // }
+ //}
+ 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 && IFace.HoverWidget != null) {
+ if (IFace.HoverWidget.IsOrIsInside (this)) {
+ //IFace.HoverWidget = null;
+ IFace.OnMouseMove (IFace.Mouse.X, IFace.Mouse.Y);
+ }
+ }
+
+ 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 (nameof(MaximumSize), maximumSize);
+ RegisterForLayouting (LayoutingType.Sizing);
+ }
+ }
+ /// <summary>
+ /// Fully qualify type name of expected data source.
+ /// If set, datasource bindings will be speedup by avoiding reflexion in generated dyn methods.
+ /// If an object of a different type is set as datasource, bindings will be canceled.
+ /// It accepts all derived type.
+ /// </summary>
+ [DesignCategory ("Data")]
+ public Type DataSourceType {
+ get { return dataSourceType; }
+ set { dataSourceType = value; }
+ }
+ /// <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;
+
+ #if DEBUG_LOG
+ DbgEvent dbgEvt = DebugLog.AddEvent(DbgEvtType.GOLockLayouting, this);
+ #endif
+ lock (IFace.UpdateMutex) {
+ OnDataSourceChanged (this, dse);
+ NotifyValueChanged ("DataSource", DataSource);
+ }
+ #if DEBUG_LOG
+ dbgEvt.end = DebugLog.chrono.ElapsedTicks;
+ #endif
+ }
+ get {
+ return rootDataLevel ? dataSource : dataSource == null ?
+ LogicalParent == null ? null :
+ LogicalParent is Widget ? (LogicalParent as Widget).DataSource : null :
+ dataSource;
+ }
+ }
+ /// <summary>
+ /// If true, lock datasource seeking upward in logic or graphic tree to this widget
+ /// </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_LOG
+ DebugLog.AddEvent(DbgEvtType.GONewDataSource, this);
+ #endif
+
+ #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_LOG
+ DbgEvent dbgEvt = DebugLog.AddEvent(DbgEvtType.GOInitialization, this);
+ #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", null, new Type[] { typeof (object) }, thisType, true);
+
+ il = dm.GetILGenerator(256);
+ il.DeclareLocal(typeof (object));//store root
+ 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.Ordinal)){
+ 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.Call, 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;
+
+ int styleIndex = -1;
+ if (styling.Count > 0){
+ for (int i = 0; i < styling.Count; i++) {
+ if (styling[i].ContainsKey (pi.Name)){
+ styleIndex = i;
+ break;
+ }
+ }
+ }
+ if (styleIndex >= 0){
+ if (pi.PropertyType.IsEnum)//maybe should be in parser..
+ defaultValue = Enum.Parse(pi.PropertyType, (string)styling[styleIndex] [pi.Name], true);
+ else
+ defaultValue = styling[styleIndex] [pi.Name];
+
+ #if DESIGN_MODE
+ if (defaultValue != null){
+ FileLocation fl = styling[styleIndex].Locations[pi.Name];
+ il.Emit (OpCodes.Ldloc_0);
+ il.Emit (OpCodes.Ldstr, pi.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(Widget).GetField("design_style_values"));
+ il.Emit (OpCodes.Ldstr, pi.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);
+ }
+
+ #if DEBUG_LOG
+ dbgEvt.end = DebugLog.chrono.ElapsedTicks;
+ #endif
+
+ 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 Widget FindByName(string nameToFind){
+ return string.Equals(nameToFind, name, StringComparison.Ordinal) ? this : null;
+ }
+ public virtual bool Contains(Widget goToFind){
+ return false;
+ }
+ /// <summary>
+ /// return true if this is contained inside go
+ /// </summary>
+ public bool IsOrIsInside(Widget 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_LOG
+ DbgEvent dbgEvt = DebugLog.AddEvent(DbgEvtType.GOClippingRegistration, this);
+ #endif
+ parentRWLock.EnterReadLock ();
+ if (parent != null) {
+ Parent.RegisterClip (LastPaintedSlot);
+ Parent.RegisterClip (Slot);
+ }
+ parentRWLock.ExitReadLock ();
+ #if DEBUG_LOG
+ dbgEvt.end = DebugLog.chrono.ElapsedTicks;
+ #endif
+ }
+ /// <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_LOG
+ DbgEvent dbgEvt = DebugLog.AddEvent(DbgEvtType.GORegisterClip, this);
+ #endif
+ Rectangle cb = ClientRectangle;
+ Rectangle r = clip + cb.Position;
+ if (r.Right > cb.Right)
+ r.Width -= r.Right - cb.Right;
+ if (r.Bottom > cb.Bottom)
+ r.Height -= r.Bottom - cb.Bottom;
+ if (cacheEnabled && !IsDirty)
+ Clipping.UnionRectangle (r);
+ if (Parent == null)
+ return;
+ Widget p = Parent as Widget;
+ if (p?.IsDirty == true && p?.CacheEnabled == true)
+ return;
+ Parent.RegisterClip (r + Slot.Position);
+ #if DEBUG_LOG
+ dbgEvt.end = DebugLog.chrono.ElapsedTicks;
+ #endif
+ }
+ /// <summary> Full update, content and layouting, taking care of sizing policy </summary>
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public void RegisterForGraphicUpdate ()
+ {
+ 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 without layouting changes</summary>
+ [MethodImpl(MethodImplOptions.AggressiveInlining)]
+ public void RegisterForRedraw ()
+ {
+ 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 Widget)
+ (Parent as Widget).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)
+ {
+ //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 (isVisible) {
+ 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 (isVisible) {
+ 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_LOG
+ DbgEvent dbgEvt = DebugLog.AddEvent(DbgEvtType.GODraw, this);
+ #endif
+
+ Rectangle rBack = new Rectangle (Slot.Size);
+
+ background.SetAsSource (gr, rBack);
+ CairoHelpers.CairoRectangle (gr, rBack, cornerRadius);
+ gr.Fill ();
+
+ #if DEBUG_LOG
+ dbgEvt.end = DebugLog.chrono.ElapsedTicks;
+ #endif
+ }
+
+ /// <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_LOG
+ DbgEvent dbgEvt = DebugLog.AddEvent(DbgEvtType.GORecreateCache, this);
+ #endif
+
+ /*if (bmp == null)
+ bmp = IFace.surf.CreateSimilar (Content.ColorAlpha, Slot.Width, Slot.Height);
+ else if (LastPaintedSlot.Width != Slot.Width || LastPaintedSlot.Height != Slot.Height)
+ bmp.SetSize (Slot.Width, Slot.Height);*/
+ bmp?.Dispose ();
+ //bmp = IFace.surf.CreateSimilar (Content.ColorAlpha, Slot.Width, Slot.Height);
+ bmp = new ImageSurface(Format.Argb32, Slot.Width, Slot.Height);
+
+ using (Context gr = new Context (bmp)) {
+ gr.Antialias = Interface.Antialias;
+ onDraw (gr);
+ }
+
+ IsDirty = false;
+
+ #if DEBUG_LOG
+ dbgEvt.end = DebugLog.chrono.ElapsedTicks;
+ #endif
+ }
+ protected virtual void UpdateCache(Context ctx){
+ #if DEBUG_LOG
+ DbgEvent dbgEvt = DebugLog.AddEvent(DbgEvtType.GOUpdateCacheAndPaintOnCTX, this);
+ #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 ();
+ #if DEBUG_LOG
+ dbgEvt.end = DebugLog.chrono.ElapsedTicks;
+ #endif
+ }
+ /// <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_LOG
+ DebugLog.AddEvent(DbgEvtType.GOPaint, this);
+ #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, KeyEventArgs e){
+ if (KeyDown != null)
+ KeyDown.Invoke (this, e);
+ else if (!e.Handled)
+ FocusParent?.onKeyDown (sender, e);
+ }
+ public virtual void onKeyUp(object sender, KeyEventArgs e){
+ if (KeyUp != null)
+ KeyUp.Invoke (this, e);
+ else if (!e.Handled)
+ FocusParent?.onKeyUp (sender, e);
+ }
+ public virtual void onKeyPress(object sender, KeyPressEventArgs e){
+ if (KeyPress != null)
+ KeyPress.Invoke (this, e);
+ else if (!e.Handled)
+ FocusParent?.onKeyPress (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 (parent == null)
+ return false;
+ if (!(isVisible & 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 (!(isVisible & 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;
+
+ if (MouseMove != null)
+ MouseMove.Invoke (this, e);
+ else if (!e.Handled)
+ FocusParent?.onMouseMove (sender, e);
+
+
+ }
+ public virtual void onMouseDown(object sender, MouseButtonEventArgs e){
+#if DEBUG_FOCUS
+ Debug.WriteLine("MOUSE DOWN => " + this.ToString());
+#endif
+
+ if (e.Button == MouseButton.Right && contextCommands != null) {
+ IFace.ShowContextMenu (this);
+ e.Handled = true;
+ }
+
+ if (MouseDown != null)
+ MouseDown?.Invoke (this, e);
+ else if (!e.Handled)
+ FocusParent?.onMouseDown (sender, 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;
+ }
+ }
+ if (MouseUp != null)
+ MouseUp.Invoke (this, e);
+ else if (!e.Handled)
+ FocusParent?.onMouseUp (sender, e);
+ }
+ public virtual void onMouseClick(object sender, MouseButtonEventArgs e){
+#if DEBUG_FOCUS
+ Debug.WriteLine("CLICK => " + this.ToString());
+#endif
+ if (MouseClick != null)
+ MouseClick.Invoke (this, e);
+ else if (!e.Handled)
+ FocusParent?.onMouseClick (sender, e);
+ }
+ public virtual void onMouseDoubleClick(object sender, MouseButtonEventArgs e){
+#if DEBUG_FOCUS
+ Debug.WriteLine("DOUBLE CLICK => " + this.ToString());
+#endif
+ if (MouseDoubleClick != null)
+ MouseDoubleClick.Invoke (this, e);
+ else if (!e.Handled)
+ FocusParent?.onMouseDoubleClick (sender, e);
+ }
+ public virtual void onMouseWheel(object sender, MouseWheelEventArgs e){
+ if (MouseWheelChanged != null)
+ MouseWheelChanged.Invoke (this, e);
+ else if (!e.Handled)
+ FocusParent?.onMouseWheel (sender, e);
+ }
+ public virtual void onMouseEnter(object sender, MouseMoveEventArgs e)
+ {
+ #if DEBUG_FOCUS
+ Debug.WriteLine("MouseEnter => " + this.ToString());
+#endif
+
+ IFace.MouseCursor = mouseCursor;
+
+ if (IFace.DragAndDropOperation != null) {
+ Widget 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;
+ }
+ }
+
+ 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);
+ }
+
+ #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) {
+ 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 + GraphicObjects.IndexOf(this).ToString(): tmp + "." + Name;
+ #else
+ return string.IsNullOrEmpty(Name) ? 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.HoverWidget != null) {
+ if (IFace.HoverWidget.IsOrIsInside (this)) {
+ IFace.HoverWidget = null;
+ IFace.OnMouseMove (IFace.Mouse.X, IFace.Mouse.Y);
+ }
+ }
+ if (IFace.ActiveWidget != null) {
+ if (IFace.ActiveWidget.IsOrIsInside (this))
+ IFace.ActiveWidget = null;
+ }
+ if (IFace.FocusedWidget != null) {
+ if (IFace.FocusedWidget.IsOrIsInside (this))
+ IFace.FocusedWidget = null;
+ }
+ }
+ }
+}
--- /dev/null
+//
+// Window.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.Xml.Serialization;
+using System.ComponentModel;
+using System.Diagnostics;
+
+namespace Crow
+{
+ public class Window : TemplatedContainer
+ {
+ public enum Direction
+ {
+ None,
+ N,
+ S,
+ E,
+ W,
+ NW,
+ NE,
+ SW,
+ SE,
+ }
+
+ string _icon;
+ bool resizable;
+ bool movable;
+ bool modal;
+ protected bool hoverBorder = false;
+ bool alwaysOnTop = false;
+ Fill titleBarBackground = Color.SteelBlue;
+ Fill titleBarForeground = Color.White;
+
+ Rectangle savedBounds;
+ bool _minimized = false;
+
+ Direction currentDirection = Direction.None;
+
+ #region Events
+ public event EventHandler Closing;
+ public event EventHandler Maximized;
+ public event EventHandler Unmaximized;
+ public event EventHandler Minimize;
+ #endregion
+
+ #region CTOR
+ protected Window() : base(){}
+ public Window (Interface iface) : base(iface){}
+ #endregion
+
+ #region TemplatedContainer overrides
+ protected override void loadTemplate(Widget template = null)
+ {
+ base.loadTemplate (template);
+
+ NotifyValueChanged ("ShowNormal", false);
+ NotifyValueChanged ("ShowMinimize", true);
+ NotifyValueChanged ("ShowMaximize", true);
+ }
+ #endregion
+
+ #region public properties
+ [DefaultValue("#Crow.Icons.crow.svg")]
+ public string Icon {
+ get { return _icon; }
+ set {
+ if (_icon == value)
+ return;
+ _icon = value;
+ NotifyValueChanged ("Icon", _icon);
+ }
+ }
+ /// <summary>
+ /// Background of the title bar if any.
+ /// </summary>
+ [DefaultValue("vgradient|0:Onyx|1:SteelBlue")]
+ public virtual Fill TitleBarBackground {
+ get { return titleBarBackground; }
+ set {
+ if (titleBarBackground == value)
+ return;
+ titleBarBackground = value;
+ NotifyValueChanged ("TitleBarBackground", titleBarBackground);
+ RegisterForRedraw ();
+ }
+ }
+ /// <summary>
+ /// Foreground of the title bar, usualy used for the window caption color.
+ /// </summary>
+ [DefaultValue("White")]
+ public virtual Fill TitleBarForeground {
+ get { return titleBarForeground; }
+ set {
+ if (titleBarForeground == value)
+ return;
+ titleBarForeground = value;
+ NotifyValueChanged ("TitleBarForeground", titleBarForeground);
+ RegisterForRedraw ();
+ }
+ }
+ [DefaultValue(true)]
+ public bool Resizable {
+ get {
+ return resizable;
+ }
+ set {
+ if (resizable == value)
+ return;
+ resizable = value;
+ NotifyValueChanged ("Resizable", resizable);
+ }
+ }
+ [DefaultValue(true)]
+ public bool Movable {
+ get {
+ return movable;
+ }
+ set {
+ if (movable == value)
+ return;
+ movable = value;
+ NotifyValueChanged ("Movable", movable);
+ }
+ }
+ [DefaultValue(false)]
+ public bool Modal {
+ get {
+ return modal;
+ }
+ set {
+ if (modal == value)
+ return;
+ modal = value;
+ NotifyValueChanged ("Modal", modal);
+ }
+ }
+ [DefaultValue(false)]
+ public bool IsMinimized {
+ get { return _minimized; }
+ set{
+ if (value == IsMinimized)
+ return;
+
+ _minimized = value;
+ _contentContainer.Visible = !_minimized;
+
+ NotifyValueChanged ("IsMinimized", _minimized);
+ }
+ }
+ [XmlIgnore]public bool IsMaximized {
+ get { return Width == Measure.Stretched & Height == Measure.Stretched & !_minimized; }
+ }
+ [XmlIgnore]public bool IsNormal {
+ get { return !(IsMaximized|_minimized); }
+ }
+ [DefaultValue(false)]
+ public bool AlwaysOnTop {
+ get {
+ return modal ? true : alwaysOnTop;
+ }
+ set {
+ if (alwaysOnTop == value)
+ return;
+
+ alwaysOnTop = value;
+
+ if (AlwaysOnTop && Parent != null)
+ IFace.PutOnTop (this);
+
+ NotifyValueChanged ("AlwaysOnTop", AlwaysOnTop);
+ }
+ }
+// [DefaultValue(WindowState.Normal)]
+// public virtual WindowState State {
+// get { return _state; }
+// set {
+// if (_state == value)
+// return;
+// _state = value;
+// NotifyValueChanged ("State", _state);
+// NotifyValueChanged ("IsNormal", IsNormal);
+// NotifyValueChanged ("IsMaximized", IsMaximized);
+// NotifyValueChanged ("IsMinimized", IsMinimized);
+// NotifyValueChanged ("IsNotMinimized", IsNotMinimized);
+// }
+// }
+ #endregion
+
+ /// <summary>
+ /// Moves the and resize with the same function entry point, the direction give the kind of move or resize
+ /// </summary>
+ /// <param name="XDelta">mouse delta on the X axis</param>
+ /// <param name="YDelta">mouse delta on the Y axis</param>
+ /// <param name="currentDirection">Current Direction of the operation, none for moving, other value for resizing in the given direction</param>
+ public void MoveAndResize (int XDelta, int YDelta, Direction currentDirection = (Direction)0) {
+ int currentLeft = this.Left;
+ int currentTop = this.Top;
+ int currentWidth, currentHeight;
+
+ if (currentLeft == 0) {
+ currentLeft = this.Slot.Left;
+ this.Left = currentLeft;
+ }
+ if (currentTop == 0) {
+ currentTop = this.Slot.Top;
+ this.Top = currentTop;
+ }
+ if (this.Width.IsFixed)
+ currentWidth = this.Width;
+ else
+ currentWidth = this.Slot.Width;
+
+ if (this.Height.IsFixed)
+ currentHeight = this.Height;
+ else
+ currentHeight = this.Slot.Height;
+
+ switch (currentDirection) {
+ case Direction.None:
+ this.Left = currentLeft + XDelta;
+ this.Top = currentTop + YDelta;
+ break;
+ case Direction.N:
+ this.Height = currentHeight - YDelta;
+ if (this.Height == currentHeight - YDelta)
+ this.Top = currentTop + YDelta;
+ break;
+ case Direction.S:
+ this.Height = currentHeight + YDelta;
+ break;
+ case Direction.W:
+ this.Width = currentWidth - XDelta;
+ if (this.Width == currentWidth - XDelta)
+ this.Left = currentLeft + XDelta;
+ break;
+ case Direction.E:
+ this.Width = currentWidth + XDelta;
+ break;
+ case Direction.NW:
+ this.Height = currentHeight - YDelta;
+ if (this.Height == currentHeight - YDelta)
+ this.Top = currentTop + YDelta;
+ this.Width = currentWidth - XDelta;
+ if (this.Width == currentWidth - XDelta)
+ this.Left = currentLeft + XDelta;
+ break;
+ case Direction.NE:
+ this.Height = currentHeight - YDelta;
+ if (this.Height == currentHeight - YDelta)
+ this.Top = currentTop + YDelta;
+ this.Width = currentWidth + XDelta;
+ break;
+ case Direction.SW:
+ this.Width = currentWidth - XDelta;
+ if (this.Width == currentWidth - XDelta)
+ this.Left = currentLeft + XDelta;
+ this.Height = currentHeight + YDelta;
+ break;
+ case Direction.SE:
+ this.Height = currentHeight + YDelta;
+ this.Width = currentWidth + XDelta;
+ break;
+ }
+ }
+
+ #region GraphicObject Overrides
+ public override void onMouseMove (object sender, MouseMoveEventArgs e)
+ {
+ base.onMouseMove (sender, e);
+
+ Interface otkgw = IFace;
+
+ /*if (!hoverBorder) {
+ currentDirection = Direction.None;
+ IFace.MouseCursor = MouseCursor.Arrow;
+ return;
+ }*/
+
+ if (this.HasFocus && movable) {
+ if (e.Mouse.IsButtonDown (MouseButton.Left)) {
+ MoveAndResize (e.XDelta, e.YDelta, currentDirection);
+ return;
+ }
+ }
+ if (Resizable) {
+ Direction lastDir = currentDirection;
+
+ if (Math.Abs (e.Position.Y - this.Slot.Y) < Interface.BorderThreshold) {
+ if (Math.Abs (e.Position.X - this.Slot.X) < Interface.BorderThreshold)
+ currentDirection = Direction.NW;
+ else if (Math.Abs (e.Position.X - this.Slot.Right) < Interface.BorderThreshold)
+ currentDirection = Direction.NE;
+ else
+ currentDirection = Direction.N;
+ } else if (Math.Abs (e.Position.Y - this.Slot.Bottom) < Interface.BorderThreshold) {
+ if (Math.Abs (e.Position.X - this.Slot.X) < Interface.BorderThreshold)
+ currentDirection = Direction.SW;
+ else if (Math.Abs (e.Position.X - this.Slot.Right) < Interface.BorderThreshold)
+ currentDirection = Direction.SE;
+ else
+ currentDirection = Direction.S;
+ } else if (Math.Abs (e.Position.X - this.Slot.X) < Interface.BorderThreshold)
+ currentDirection = Direction.W;
+ else if (Math.Abs (e.Position.X - this.Slot.Right) < Interface.BorderThreshold)
+ currentDirection = Direction.E;
+ else
+ currentDirection = Direction.None;
+
+ if (currentDirection != lastDir) {
+ switch (currentDirection) {
+ case Direction.None:
+ otkgw.MouseCursor = MouseCursor.Move;
+ break;
+ case Direction.N:
+ otkgw.MouseCursor = MouseCursor.Top;
+ break;
+ case Direction.S:
+ otkgw.MouseCursor = MouseCursor.Bottom;
+ break;
+ case Direction.E:
+ otkgw.MouseCursor = MouseCursor.Right;
+ break;
+ case Direction.W:
+ otkgw.MouseCursor = MouseCursor.Left;
+ break;
+ case Direction.NW:
+ otkgw.MouseCursor = MouseCursor.TopLeft;
+ break;
+ case Direction.NE:
+ otkgw.MouseCursor = MouseCursor.TopRight;
+ break;
+ case Direction.SW:
+ otkgw.MouseCursor = MouseCursor.BottomLeft;
+ break;
+ case Direction.SE:
+ otkgw.MouseCursor = MouseCursor.BottomRight;
+ break;
+ }
+ }
+ }
+ }
+ public override void onMouseDown (object sender, MouseButtonEventArgs e)
+ {
+ base.onMouseDown (sender, e);
+ }
+ public override bool MouseIsIn (Point m)
+ {
+ return modal ? true : base.MouseIsIn (m);
+ }
+ #endregion
+
+ protected void onMaximized (object sender, EventArgs e){
+ lock (IFace.LayoutMutex) {
+ if (!IsMinimized)
+ savedBounds = this.LastPaintedSlot;
+ this.Left = this.Top = 0;
+ this.RegisterForLayouting (LayoutingType.Positioning);
+ this.Width = this.Height = Measure.Stretched;
+ IsMinimized = false;
+ Resizable = false;
+ NotifyValueChanged ("ShowNormal", true);
+ NotifyValueChanged ("ShowMinimize", true);
+ NotifyValueChanged ("ShowMaximize", false);
+ }
+
+ Maximized.Raise (sender, e);
+ }
+ protected void onUnmaximized (object sender, EventArgs e){
+ lock (IFace.LayoutMutex) {
+ this.Left = savedBounds.Left;
+ this.Top = savedBounds.Top;
+ this.Width = savedBounds.Width;
+ this.Height = savedBounds.Height;
+ IsMinimized = false;
+ Resizable = true;
+ NotifyValueChanged ("ShowNormal", false);
+ NotifyValueChanged ("ShowMinimize", true);
+ NotifyValueChanged ("ShowMaximize", true);
+ }
+
+ Unmaximized.Raise (sender, e);
+ }
+ protected void onMinimized (object sender, EventArgs e){
+ lock (IFace.LayoutMutex) {
+ if (IsNormal)
+ savedBounds = this.LastPaintedSlot;
+ Width = 200;
+ Height = 20;
+ Resizable = false;
+ IsMinimized = true;
+ NotifyValueChanged ("ShowNormal", true);
+ NotifyValueChanged ("ShowMinimize", false);
+ NotifyValueChanged ("ShowMaximize", true);
+ }
+
+ Minimize.Raise (sender, e);
+ }
+ protected virtual void onBorderMouseLeave (object sender, MouseMoveEventArgs e)
+ {
+ hoverBorder = false;
+ currentDirection = Direction.None;
+ IFace.MouseCursor = MouseCursor.Arrow;
+ }
+ protected virtual void onBorderMouseEnter (object sender, MouseMoveEventArgs e)
+ {
+ hoverBorder = true;
+ }
+
+
+ protected void butQuitPress (object sender, MouseButtonEventArgs e)
+ {
+ IFace.MouseCursor = MouseCursor.Arrow;
+ close ();
+ }
+
+ protected virtual void close(){
+ Closing.Raise (this, null);
+ if (Parent is Interface)
+ (Parent as Interface).DeleteWidget (this);
+ else {
+ Widget p = Parent as Widget;
+ if (p is Group) {
+ lock (IFace.UpdateMutex) {
+ RegisterClip (p.ScreenCoordinates (p.LastPaintedSlot));
+ (p as Group).DeleteChild (this);
+ }
+ //(Parent as Group).RegisterForRedraw ();
+ } else if (Parent is PrivateContainer)
+ (Parent as Container).Child = null;
+ }
+ }
+
+ public static Window Show (Interface iface, string imlPath, bool modal = false){
+ lock (iface.UpdateMutex) {
+ Window w = iface.Load (imlPath) as Window;
+ w.Modal = modal;
+ return w;
+ }
+ }
+ }
+}
+
--- /dev/null
+//
+// Wrapper.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;
+
+namespace Crow
+{
+ /// <summary>
+ /// group control that arrange its children in a direction and jump to
+ /// the next line or row when no room is left
+ /// </summary>
+ public class Wrapper : GenericStack
+ {
+ #region CTOR
+ protected Wrapper() : base(){}
+ public Wrapper (Interface iface) : base(iface){}
+ #endregion
+
+ #region Group Overrides
+ public override void ChildrenLayoutingConstraints (ref LayoutingType layoutType)
+ {
+ layoutType &= (~LayoutingType.Positioning);
+ }
+ public override void ComputeChildrenPositions()
+ {
+ int dx = 0;
+ int dy = 0;
+
+ if (Orientation == Orientation.Vertical) {
+ int tallestChild = 0;
+ foreach (Widget c in Children) {
+ if (!c.Visible)
+ continue;
+ if (dx + c.Slot.Width > ClientRectangle.Width) {
+ dx = 0;
+ dy += tallestChild + Spacing;
+ c.Slot.X = dx;
+ c.Slot.Y = dy;
+ tallestChild = c.Slot.Height;
+ } else {
+ if (tallestChild < c.Slot.Height)
+ tallestChild = c.Slot.Height;
+ c.Slot.X = dx;
+ c.Slot.Y = dy;
+ }
+ dx += c.Slot.Width + Spacing;
+ }
+ } else {
+ int largestChild = 0;
+ foreach (Widget c in Children) {
+ if (!c.Visible)
+ continue;
+ if (dy + c.Slot.Height > ClientRectangle.Height) {
+ dy = 0;
+ dx += largestChild + Spacing;
+ c.Slot.X = dx;
+ c.Slot.Y = dy;
+ largestChild = c.Slot.Width;
+ } else {
+ if (largestChild < c.Slot.Width)
+ largestChild = c.Slot.Width;
+ c.Slot.X = dx;
+ c.Slot.Y = dy;
+ }
+ dy += c.Slot.Height + Spacing;
+ }
+ }
+ IsDirty = true;
+ }
+ public override void OnChildLayoutChanges (object sender, LayoutingEventArgs arg)
+ {
+ //children can't stretch in a wrapper
+ Widget go = sender as Widget;
+ //System.Diagnostics.Debug.WriteLine ("wrapper child layout change: " + go.LastSlots.ToString() + " => " + go.Slot.ToString());
+ switch (arg.LayoutType) {
+ case LayoutingType.Width:
+ if (Orientation == Orientation.Horizontal && go.Width.Units == Unit.Percent){
+ go.Width = Measure.Fit;
+ return;
+ }
+ this.RegisterForLayouting (LayoutingType.Width);
+ break;
+ case LayoutingType.Height:
+ if (Orientation == Orientation.Vertical && go.Height.IsRelativeToParent) {
+ go.Height = Measure.Fit;
+ return;
+ }
+ this.RegisterForLayouting (LayoutingType.Height);
+ break;
+ default:
+ return;
+ }
+ this.RegisterForLayouting (LayoutingType.ArrangeChildren);
+ }
+ #endregion
+
+ #region GraphicObject Overrides
+ protected override int measureRawSize (LayoutingType lt)
+ {
+ int tmp = 0;
+ //Wrapper can't fit in the opposite direction of the wrapper, this func is called only if Fit
+ if (lt == LayoutingType.Width) {
+ if (Orientation == Orientation.Vertical) {
+ Width = Measure.Stretched;
+ return -1;
+ } else if (RegisteredLayoutings.HasFlag (LayoutingType.Height))
+ return -1;
+ else {
+ int dy = 0;
+ int largestChild = 0;
+
+ childrenRWLock.EnterReadLock();
+
+ foreach (Widget c in Children) {
+ if (!c.Visible)
+ continue;
+ if (c.Height.IsRelativeToParent &&
+ c.RegisteredLayoutings.HasFlag (LayoutingType.Height)) {
+ childrenRWLock.ExitReadLock();
+ return -1;
+ }
+ if (dy + c.Slot.Height > ClientRectangle.Height) {
+ dy = 0;
+ tmp += largestChild + Spacing;
+ largestChild = c.Slot.Width;
+ } else if (largestChild < c.Slot.Width)
+ largestChild = c.Slot.Width;
+
+ dy += c.Slot.Height + Spacing;
+ }
+
+ childrenRWLock.ExitReadLock ();
+
+ if (dy == 0)
+ tmp -= Spacing;
+ return tmp + largestChild + 2 * Margin;
+ }
+ } else if (Orientation == Orientation.Horizontal) {
+ Height = Measure.Stretched;
+ return -1;
+ } else if (RegisteredLayoutings.HasFlag (LayoutingType.Width))
+ return -1;
+ else {
+ int dx = 0;
+ int tallestChild = 0;
+
+ childrenRWLock.EnterReadLock();
+
+ foreach (Widget c in Children) {
+ if (!c.Visible)
+ continue;
+ if (c.Width.IsRelativeToParent &&
+ c.RegisteredLayoutings.HasFlag (LayoutingType.Width)) {
+ childrenRWLock.ExitReadLock();
+ return -1;
+ }
+ if (dx + c.Slot.Width > ClientRectangle.Width) {
+ dx = 0;
+ tmp += tallestChild + Spacing;
+ tallestChild = c.Slot.Height;
+ } else if (tallestChild < c.Slot.Height)
+ tallestChild = c.Slot.Height;
+
+ dx += c.Slot.Width + Spacing;
+ }
+
+ childrenRWLock.ExitReadLock();
+
+ if (dx == 0)
+ tmp -= Spacing;
+ return tmp + tallestChild + 2 * Margin;
+ }
+ }
+
+ public override bool UpdateLayout (LayoutingType layoutType)
+ {
+ RegisteredLayoutings &= (~layoutType);
+
+ if (layoutType == LayoutingType.ArrangeChildren) {
+ if ((RegisteredLayoutings & LayoutingType.Sizing) != 0)
+ return false;
+
+ ComputeChildrenPositions ();
+
+ //if no layouting remains in queue for item, registre for redraw
+ if (RegisteredLayoutings == LayoutingType.None && IsDirty)
+ IFace.EnqueueForRepaint (this);
+
+ return true;
+ }
+
+ return base.UpdateLayout(layoutType);
+ }
+ public override void OnLayoutChanges (LayoutingType layoutType)
+ {
+ #if DEBUG_LAYOUTING
+ IFace.currentLQI.Slot = LastSlots;
+ IFace.currentLQI.Slot = Slot;
+ #endif
+ switch (layoutType) {
+ case LayoutingType.Width:
+ foreach (Widget c in Children) {
+ if (c.Width.IsRelativeToParent)
+ c.RegisterForLayouting (LayoutingType.Width);
+ }
+ if (Height == Measure.Fit)
+ RegisterForLayouting (LayoutingType.Height);
+ RegisterForLayouting (LayoutingType.X);
+ break;
+ case LayoutingType.Height:
+ foreach (Widget c in Children) {
+ if (c.Height.IsRelativeToParent)
+ c.RegisterForLayouting (LayoutingType.Height);
+ }
+ if (Width == Measure.Fit)
+ RegisterForLayouting (LayoutingType.Width);
+ RegisterForLayouting (LayoutingType.Y);
+ break;
+ default:
+ return;
+ }
+ RegisterForLayouting (LayoutingType.ArrangeChildren);
+ raiseLayoutChanged (new LayoutingEventArgs (layoutType));
+ }
+ #endregion
+ }
+}
+
--- /dev/null
+//
+// Expandable.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;
+
+namespace Crow
+{
+ public class XmlIgnoreAttribute : Attribute
+ {
+ }
+}
\ No newline at end of file