namespace Crow
{
+ /// <summary>
+ /// This is the base class for all the graphic trees elements
+ /// </summary>
public class GraphicObject : ILayoutable, IValueChange, IDisposable
{
#region IDisposable implementation
internal static ulong currentUid = 0;
internal ulong uid = 0;
+ /// <summary>
+ /// interface this widget is bound to, this should not be changed once the instance is created
+ /// </summary>
public Interface CurrentInterface = 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);
#region CTOR
/// <summary>
- /// default private parameter less constructor use in instantiators
+ /// default private parameter less constructor use in instantiators, it should not be used
+ /// when creating widget from code because widgets has to be bound to an interface before any other
+ /// action.
/// </summary>
protected GraphicObject () {
Clipping = new Region ();
currentUid++;
#endif
}
+ /// <summary>
+ /// This constructor **must** be used when creating widget from code.
+ ///
+ /// When creating new widgets derived from GraphicObject, both parameterless and this constructors are
+ /// facultatives, the compiler will create the parameterless one automaticaly if no other one exists.
+ /// But if you intend to be able to create instances of the new widget in code and override the constructor
+ /// with the Interface parameter, you **must** also provide the override of the parameterless constructor because
+ /// compiler will not create it automatically because of the presence of the other one.
+ /// </summary>
+ /// <param name="iface">Iface.</param>
public GraphicObject (Interface iface) : this()
{
CurrentInterface = iface;
/// Initialize this Graphic object instance by setting style and default values and loading template if required
/// </summary>
public virtual void Initialize(){
-// if (CurrentInterface == null)
-// CurrentInterface = Interface.CurrentInterface;
loadDefaultValues ();
initialized = true;
}
#endregion
#region EVENT HANDLERS
+ /// <summary>Occurs when mouse wheel is rolled in this object. It bubbles to the root</summary>
public event EventHandler<MouseWheelEventArgs> MouseWheelChanged;
+ /// <summary>Occurs when mouse button is released in this object. It bubbles to the root</summary>
public event EventHandler<MouseButtonEventArgs> MouseUp;
+ /// <summary>Occurs when mouse button is pressed in this object. It bubbles to the root</summary>
public event EventHandler<MouseButtonEventArgs> MouseDown;
+ /// <summary>Occurs when mouse button has been pressed then relesed in this object. It bubbles to the root</summary>
public event EventHandler<MouseButtonEventArgs> MouseClick;
+ /// <summary>Occurs when mouse button has been pressed then relesed 2 times in this object. It bubbles to the root</summary>
public event EventHandler<MouseButtonEventArgs> MouseDoubleClick;
+ /// <summary>Occurs when mouse mouve in this object. It bubbles to the root</summary>
public event EventHandler<MouseMoveEventArgs> MouseMove;
+ /// <summary>Occurs when mouse enter this object</summary>
public event EventHandler<MouseMoveEventArgs> MouseEnter;
+ /// <summary>Occurs when mouse leave this object</summary>
public event EventHandler<MouseMoveEventArgs> MouseLeave;
+ /// <summary>Occurs when key is pressed when this object is active</summary>
public event EventHandler<KeyboardKeyEventArgs> KeyDown;
+ /// <summary>Occurs when key is released when this object is active</summary>
public event EventHandler<KeyboardKeyEventArgs> KeyUp;
+ /// <summary>Occurs when translated key event occurs in the host when this object is active</summary>
public event EventHandler<KeyPressEventArgs> KeyPress;
+ /// <summary>Occurs when this object received focus</summary>
public event EventHandler Focused;
+ /// <summary>Occurs when this object loose focus</summary>
public event EventHandler Unfocused;
+ /// <summary>Occurs when the enabled state this object is set to true</summary>
public event EventHandler Enabled;
+ /// <summary>Occurs when the enabled state this object is set to false</summary>
public event EventHandler Disabled;
+ /// <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
}
}
/// <summary>
- /// If enabled, resulting bitmap of graphic object is cached in an byte array
+ /// If enabled, resulting bitmap of graphic object is cached
/// speeding up rendering of complex object. Default is enabled.
/// </summary>
[XmlAttributeAttribute][DefaultValue(true)]
}
/// <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>
[XmlAttributeAttribute][DefaultValue(null)]
public virtual string Name {
NotifyValueChanged("Name", name);
}
}
+ /// <summary>
+ /// Vertical alignment inside parent, disabled if height is stretched
+ /// or top coordinate is not null
+ /// </summary>
[XmlAttributeAttribute ()][DefaultValue(VerticalAlignment.Center)]
public virtual VerticalAlignment VerticalAlignment {
get { return verticalAlignment; }
RegisterForLayouting (LayoutingType.Y);
}
}
+ /// <summary>
+ /// Horizontal alignment inside parent, disabled if width is stretched
+ /// or left coordinate is not null
+ /// </summary>
[XmlAttributeAttribute()][DefaultValue(HorizontalAlignment.Center)]
public virtual HorizontalAlignment HorizontalAlignment {
get { return horizontalAlignment; }
RegisterForLayouting (LayoutingType.X);
}
}
+ /// <summary>
+ /// x position inside parent
+ /// </summary>
[XmlAttributeAttribute()][DefaultValue(0)]
public virtual int Left {
get { return left; }
this.RegisterForLayouting (LayoutingType.X);
}
}
+ /// <summary>
+ /// y position inside parent
+ /// </summary>
[XmlAttributeAttribute()][DefaultValue(0)]
public virtual int Top {
get { return top; }
}
}
/// <summary>
- /// When set to True, the <see cref="T:Crow.GraphicObject"/>'s width and height will be set to Fit.
+ /// Helper property used to set width and height to fit in one call
/// </summary>
[XmlAttributeAttribute()][DefaultValue(false)]
public virtual bool Fit {
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>
[XmlAttributeAttribute()][DefaultValue("Inherit")]
public virtual Measure Width {
get {
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>
[XmlAttributeAttribute()][DefaultValue("Inherit")]
public virtual Measure Height {
get {
}
/// <summary>
/// Used for binding on dimensions, this property will never hold fixed size, but instead only
- /// Fit or Stretched
+ /// 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>
/// Used for binding on dimensions, this property will never hold fixed size, but instead only
- /// Fit or Stretched
+ /// 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>
[XmlAttributeAttribute()][DefaultValue(false)]
public virtual bool Focusable {
get { return focusable; }
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 {
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 {
NotifyValueChanged ("IsActive", isActive);
}
}
+ /// <summary>
+ /// true if holding mouse button down should trigger multiple click events
+ /// </summary>
[XmlAttributeAttribute()][DefaultValue(false)]
public virtual bool MouseRepeat {
get { return mouseRepeat; }
}
}
bool clearBackground = false;
+ /// <summary>
+ /// background fill of the control, maybe solid color, gradient, image, or svg
+ /// </summary>
[XmlAttributeAttribute()][DefaultValue("Transparent")]
public virtual Fill Background {
get { return background; }
}
}
}
+ /// <summary>
+ /// Foreground fill of the control, usage may be different among derived controls
+ /// </summary>
[XmlAttributeAttribute()][DefaultValue("White")]
public virtual Fill Foreground {
get { return foreground; }
RegisterForRedraw ();
}
}
+ /// <summary>
+ /// Font being used in many controls, it is defined in the base GraphicObject class.
+ /// </summary>
[XmlAttributeAttribute()][DefaultValue("sans,10")]
public virtual Font Font {
get { return font; }
RegisterForGraphicUpdate ();
}
}
+ /// <summary>
+ /// to get rounded corners
+ /// </summary>
[XmlAttributeAttribute()][DefaultValue(0.0)]
public virtual double CornerRadius {
get { return 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>
[XmlAttributeAttribute()][DefaultValue(0)]
public virtual int Margin {
get { return margin; }
RegisterForGraphicUpdate ();
}
}
+ /// <summary>
+ /// set the visible state of the control, invisible controls does reserve space in the layouting system.
+ /// </summary>
[XmlAttributeAttribute][DefaultValue(true)]
public virtual bool Visible {
get { return isVisible; }
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>
[XmlAttributeAttribute][DefaultValue(true)]
public virtual bool IsEnabled {
get { return isEnabled; }
RegisterForRedraw ();
}
}
+ /// <summary>
+ /// Minimal width and height for this control
+ /// </summary>
[XmlAttributeAttribute()][DefaultValue("1,1")]
public virtual Size MinimumSize {
get { return minimumSize; }
RegisterForLayouting (LayoutingType.Sizing);
}
}
+ /// <summary>
+ /// Maximum width and height for this control, unlimited if null.
+ /// </summary>
[XmlAttributeAttribute()][DefaultValue("0,0")]
public virtual Size MaximumSize {
get { return maximumSize; }
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>
[XmlAttributeAttribute]
public virtual string Style {
get { return style; }
namespace Crow
{
/// <summary>
- /// The Interface Class is the top container of the application.
- /// It provides the Dirty bitmap and zone of the interface to be drawn on screen
+ /// The Interface Class is the root of crow graphic trees. It is thread safe allowing
+ /// application to run multiple interfaces in different threads.
+ /// It provides the Dirty bitmap and zone of the interface to be drawn on screen.
///
/// The Interface contains :
/// - rendering and layouting queues and logic.
- /// - helpers to load XML interfaces files
- /// - global constants and variables of CROW
+ /// - helpers to load XML interfaces files directely bound to this interface
+ /// - global static constants and variables of CROW
/// - Keyboard and Mouse logic
/// - the resulting bitmap of the interface
+ ///
+ /// the master branch and the nuget package includes an OpenTK renderer which allows
+ /// the creation of multiple threaded interfaces.
+ ///
+ /// If you intend to create another renderer (GDK, vulkan, etc) the minimal step is to
+ /// put an interface instance as member of your root object and call (optionally in another thread) the update function
+ /// at regular interval. Then you have to call
+ /// mouse, keyboard and resize functions of the interface when those events occurs in the host app.
+ ///
+ /// The resulting surface (a byte array in the OpenTK renderer) is made available and protected with the
+ /// RenderMutex of the interface.
/// </summary>
public class Interface : ILayoutable
{
throw new Exception ("Error loading <" + path + ">:", ex);
}
}
- /// <summary>Fetch it from cache or create it</summary>
+ /// <summary>Fetch instantiator it from cache or create it</summary>
public static Instantiator GetInstantiator(string path){
if (!Instantiators.ContainsKey(path))
Instantiators [path] = new Instantiator(path);
return Instantiators [path];
}
- /// <summary>Item templates have additional properties for recursivity and
+ /// <summary>Item templates are derived from instantiator, this function
+ /// try to fetch the requested one in the cache or create it.
+ /// They have additional properties for recursivity and
/// custom display per item type</summary>
public static ItemTemplate GetItemTemplate(string path){
if (!Instantiators.ContainsKey(path))
}
#endregion
-
#region UPDATE Loops
/// <summary>Enqueue Graphic object for Repaint, DrawingQueue is locked because
/// GraphObj's property Set methods could trigger an update from another thread
- /// Once in that queue, the layouting of obj and childs is ok, the next step
- /// when dequeued is clipping registration</summary>
+ /// Once in that queue, that means that the layouting of obj and childs have succeed,
+ /// the next step when dequeued will be clipping registration</summary>
public void EnqueueForRepaint(GraphicObject g)
{
#if DEBUG_UPDATE
g.IsQueueForRedraw = true;
}
}
- /// <summary>Main Update loop, executed in this interface thread, lock the UpdateMutex
+ /// <summary>Main Update loop, executed in this interface thread, protected by the UpdateMutex
/// Steps:
/// - execute device Repeat events
/// - Layouting
}
#endregion
+ /// <summary>
+ /// Resize the interface. This function should be called by the host
+ /// when window resize event occurs.
+ /// </summary>
+ /// <param name="bounds">bounding box of the interface</param>
public void ProcessResize(Rectangle bounds){
lock (UpdateMutex) {
clientRectangle = bounds;
MouseCursorChanged.Raise (this,new MouseCursorChangedEventArgs(cursor));
}
}
- /// <summary>Processes mouse move events from the root container</summary>
- /// <returns><c>true</c>if mouse is in the interface</returns>
+ /// <summary>Processes mouse move events from the root container, this function
+ /// should be called by the host on mouse move event to forward events to crow interfaces</summary>
+ /// <returns>true if mouse is in the interface</returns>
public bool ProcessMouseMove(int x, int y)
{
int deltaX = x - Mouse.X;
HoverWidget = null;
return false;
}
+ /// <summary>
+ /// Forward the mouse up event from the host to the crow interface
+ /// </summary>
+ /// <returns>return true, if interface handled the event, false otherwise.</returns>
+ /// <param name="button">Button index</param>
public bool ProcessMouseButtonUp(int button)
{
Mouse.DisableBit (button);
ActiveWidget = null;
return true;
}
+ /// <summary>
+ /// Forward the mouse down event from the host to the crow interface
+ /// </summary>
+ /// <returns>return true, if interface handled the event, false otherwise.</returns>
+ /// <param name="button">Button index</param>
public bool ProcessMouseButtonDown(int button)
{
Mouse.EnableBit (button);
mouseRepeatThread.Start ();
return true;
}
+ /// <summary>
+ /// Forward the mouse wheel event from the host to the crow interface
+ /// </summary>
+ /// <returns>return true, if interface handled the event, false otherwise.</returns>
+ /// <param name="button">Button index</param>
public bool ProcessMouseWheelChanged(float delta)
{
Mouse.SetScrollRelative (0, delta);
HoverWidget.onMouseWheel (this, e);
return true;
}
+ /// <summary>
+ /// Forward key down event from the host to the crow interface
+ /// </summary>
+ /// <returns>return true, if interface handled the event, false otherwise.</returns>
+ /// <param name="button">Button index</param>
public bool ProcessKeyDown(int Key){
Keyboard.SetKeyState((Crow.Key)Key,true);
if (_focusedWidget == null)
return true;
}
+ /// <summary>
+ /// Forward key up event from the host to the crow interface
+ /// </summary>
+ /// <returns>return true, if interface handled the event, false otherwise.</returns>
+ /// <param name="button">Button index</param>
public bool ProcessKeyUp(int Key){
Keyboard.SetKeyState((Crow.Key)Key,false);
if (_focusedWidget == null)
}
return true;
}
+ /// <summary>
+ /// Forward a translated key press event from the host to the crow interface
+ /// </summary>
+ /// <returns>return true, if interface handled the event, false otherwise.</returns>
+ /// <param name="button">Button index</param>
public bool ProcessKeyPress(char Key){
if (_focusedWidget == null)
return false;