diff options
| author | j-p <jp.bruyere@live.be> | 2018-04-14 12:15:08 +0200 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2018-04-14 12:15:08 +0200 |
| commit | 907358fed63b4a89e8dee5184cc9901a7107ab9f (patch) | |
| tree | 18c473a86b553dbe9f08cfe345b6278c71e9594e /src/Interface.cs | |
| parent | 7c735fa149bf23223eda734f19d5547797ca8ac2 (diff) | |
| parent | 5a06966fd4be89263988d0838556b78a7988b5a9 (diff) | |
Merge pull request #40 from jpbruyere/devel
Devel
Diffstat (limited to 'src/Interface.cs')
| -rw-r--r-- | src/Interface.cs | 234 |
1 files changed, 153 insertions, 81 deletions
diff --git a/src/Interface.cs b/src/Interface.cs index 8c3792d5..cc62a1aa 100644 --- a/src/Interface.cs +++ b/src/Interface.cs @@ -67,6 +67,10 @@ namespace Crow { #region CTOR static Interface(){ + if (Type.GetType ("Mono.Runtime") == null) { + throw new Exception (@"C.R.O.W. run only on Mono, download latest version at: http://www.mono-project.com/download/stable/"); + } + CrowConfigRoot = System.IO.Path.Combine( Environment.GetFolderPath(Environment.SpecialFolder.UserProfile), @@ -84,9 +88,6 @@ namespace Crow } } - loadCursors (); - findAvailableTemplates (); - FontRenderingOptions = new FontOptions (); FontRenderingOptions.Antialias = Antialias.Subpixel; FontRenderingOptions.HintMetrics = HintMetrics.On; @@ -94,13 +95,18 @@ namespace Crow FontRenderingOptions.SubpixelOrder = SubpixelOrder.Rgb; } public Interface(){ - CurrentInterface = this; CultureInfo.DefaultThreadCurrentCulture = System.Globalization.CultureInfo.InvariantCulture; + } + #endregion + + public void Init () { + CurrentInterface = this; + loadCursors (); loadStyling (); + findAvailableTemplates (); initTooltip (); initContextMenus (); } - #endregion #region Static and constants /// <summary> @@ -121,7 +127,7 @@ namespace Crow public static int DeviceRepeatInterval = 40; /// <summary>Tabulation size in Text controls</summary> public static int TabSize = 4; - public static string LineBreak = "\r\n"; + public static string LineBreak = "\n"; /// <summary> Allow rendering of interface in development environment </summary> public static bool DesignerMode = false; /// <summary> Disable caching for a widget if this threshold is reached </summary> @@ -206,10 +212,19 @@ namespace Crow /// <summary>each IML and fragments (such as inline Templates) are compiled as a Dynamic Method stored here /// on the first instance creation of a IML item. /// </summary> - public static Dictionary<String, Instantiator> Instantiators = new Dictionary<string, Instantiator>(); + public Dictionary<String, Instantiator> Instantiators = new Dictionary<string, Instantiator>(); public List<CrowThread> CrowThreads = new List<CrowThread>();//used to monitor thread finished public DragDropEventArgs DragAndDropOperation = null; + public Surface DragImage = null; + public int DragImageWidth, DragImageHeight, DragImageX, DragImageY; + public void ClearDragImage () { + lock (UpdateMutex) { + clipping.UnionRectangle(new Rectangle (DragImageX, DragImageY, DragImageWidth, DragImageHeight)); + DragImage.Dispose(); + DragImage = null; + } + } #endregion #region Private Fields @@ -250,22 +265,22 @@ namespace Crow .GetManifestResourceNames () .Where (r => r.EndsWith (".style", StringComparison.OrdinalIgnoreCase))) { using (Stream stream = assembly.GetManifestResourceStream (s)) { - new StyleReader (this, stream, s); + new StyleReader (this.Styling, stream, s); } } } - static void loadCursors(){ + void loadCursors(){ //Load cursors - XCursor.Cross = XCursorFile.Load("#Crow.Images.Icons.Cursors.cross").Cursors[0]; - XCursor.Default = XCursorFile.Load("#Crow.Images.Icons.Cursors.arrow").Cursors[0]; - XCursor.NW = XCursorFile.Load("#Crow.Images.Icons.Cursors.top_left_corner").Cursors[0]; - XCursor.NE = XCursorFile.Load("#Crow.Images.Icons.Cursors.top_right_corner").Cursors[0]; - XCursor.SW = XCursorFile.Load("#Crow.Images.Icons.Cursors.bottom_left_corner").Cursors[0]; - XCursor.SE = XCursorFile.Load("#Crow.Images.Icons.Cursors.bottom_right_corner").Cursors[0]; - XCursor.H = XCursorFile.Load("#Crow.Images.Icons.Cursors.sb_h_double_arrow").Cursors[0]; - XCursor.V = XCursorFile.Load("#Crow.Images.Icons.Cursors.sb_v_double_arrow").Cursors[0]; - XCursor.Text = XCursorFile.Load("#Crow.Images.Icons.Cursors.ibeam").Cursors[0]; + XCursor.Cross = XCursorFile.Load(this, "#Crow.Images.Icons.Cursors.cross").Cursors[0]; + XCursor.Default = XCursorFile.Load(this, "#Crow.Images.Icons.Cursors.arrow").Cursors[0]; + XCursor.NW = XCursorFile.Load(this, "#Crow.Images.Icons.Cursors.top_left_corner").Cursors[0]; + XCursor.NE = XCursorFile.Load(this, "#Crow.Images.Icons.Cursors.top_right_corner").Cursors[0]; + XCursor.SW = XCursorFile.Load(this, "#Crow.Images.Icons.Cursors.bottom_left_corner").Cursors[0]; + XCursor.SE = XCursorFile.Load(this, "#Crow.Images.Icons.Cursors.bottom_right_corner").Cursors[0]; + XCursor.H = XCursorFile.Load(this, "#Crow.Images.Icons.Cursors.sb_h_double_arrow").Cursors[0]; + XCursor.V = XCursorFile.Load(this, "#Crow.Images.Icons.Cursors.sb_v_double_arrow").Cursors[0]; + XCursor.Text = XCursorFile.Load(this, "#Crow.Images.Icons.Cursors.ibeam").Cursors[0]; } #endregion @@ -274,16 +289,17 @@ namespace Crow /// Resource ID must be 'fullClassName.template' (not case sensitive) /// Those found in application assembly have priority to the default Crow's one /// </summary> - public static Dictionary<string, string> DefaultTemplates = new Dictionary<string, string>(); + public Dictionary<string, string> DefaultTemplates; /// <summary>Finds available default templates at startup</summary> - static void findAvailableTemplates(){ + void findAvailableTemplates(){ + DefaultTemplates = new Dictionary<string, string>(); searchTemplatesOnDisk ("./"); string defTemplatePath = System.IO.Path.Combine (CrowConfigRoot, "defaultTemplates"); searchTemplatesOnDisk (defTemplatePath); searchTemplatesIn (Assembly.GetEntryAssembly ()); searchTemplatesIn (Assembly.GetExecutingAssembly ()); } - static void searchTemplatesOnDisk (string templatePath){ + void searchTemplatesOnDisk (string templatePath){ if (!Directory.Exists (templatePath)) return; foreach (string f in Directory.GetFiles(templatePath, "*.template",SearchOption.AllDirectories)) { @@ -293,7 +309,7 @@ namespace Crow DefaultTemplates [clsName] = f; } } - static void searchTemplatesIn(Assembly assembly){ + void searchTemplatesIn(Assembly assembly){ if (assembly == null) return; foreach (string resId in assembly @@ -312,7 +328,28 @@ namespace Crow /// <returns>A file or resource stream</returns> /// <param name="path">This could be a normal file path, or an embedded ressource ID /// Resource ID's must be prefixed with '#' character</param> - public static Stream GetStreamFromPath (string path) + public virtual Stream GetStreamFromPath (string path) + { + Stream stream = null; + + if (path.StartsWith ("#")) { + string resId = path.Substring (1); + //try/catch added to prevent nunit error + try { + stream = System.Reflection.Assembly.GetEntryAssembly ().GetManifestResourceStream (resId); + } catch{} + if (stream == null)//try to find ressource in Crow assembly + stream = System.Reflection.Assembly.GetExecutingAssembly ().GetManifestResourceStream (resId); + if (stream == null) + throw new Exception ("Resource not found: " + path); + } else { + if (!File.Exists (path)) + throw new FileNotFoundException ("File not found: ", path); + stream = new FileStream (path, FileMode.Open, FileAccess.Read); + } + return stream; + } + public static Stream StaticGetStreamFromPath (string path) { Stream stream = null; @@ -340,12 +377,20 @@ namespace Crow /// <param name="imlFragment">a valid IML string</param> public GraphicObject LoadIMLFragment (string imlFragment) { lock (UpdateMutex) { - GraphicObject tmp = Instantiator.CreateFromImlFragment (imlFragment).CreateInstance(this); + GraphicObject tmp = CreateITorFromIMLFragment (imlFragment).CreateInstance(); AddWidget (tmp); return tmp; } } /// <summary> + /// Add the content of the IML fragment to the graphic tree of this interface + /// </summary> + /// <returns>return the new instance for convenience, may be ignored</returns> + /// <param name="imlFragment">a valid IML string</param> + public Instantiator CreateITorFromIMLFragment (string imlFragment) { + return Instantiator.CreateFromImlFragment (this, imlFragment); + } + /// <summary> /// Create an instance of a GraphicObject and add it to the GraphicTree of this Interface /// </summary> /// <returns>new instance of graphic object created</returns> @@ -363,45 +408,33 @@ namespace Crow /// </summary> /// <returns>new instance of graphic object created</returns> /// <param name="path">path of the iml file to load</param> - public GraphicObject Load (string path) + public virtual GraphicObject Load (string path) { - //try { - return GetInstantiator (path).CreateInstance (this); - //} catch (Exception ex) { - // throw new Exception ("Error loading <" + path + ">:", ex); - //} + try { + return GetInstantiator (path).CreateInstance (); + } catch (Exception ex) { + throw new Exception ("Error loading <" + path + ">:", ex); + } } /// <summary> /// Fetch instantiator from cache or create it. /// </summary> /// <returns>new Instantiator</returns> /// <param name="path">path of the iml file to load</param> - public static Instantiator GetInstantiator(string path){ + public Instantiator GetInstantiator(string path){ if (!Instantiators.ContainsKey(path)) - Instantiators [path] = new Instantiator(path); + Instantiators [path] = new Instantiator(this, path); return Instantiators [path]; } /// <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){ + public virtual ItemTemplate GetItemTemplate(string path){ if (!Instantiators.ContainsKey(path)) - Instantiators [path] = new ItemTemplate(path); + Instantiators [path] = new ItemTemplate(this, path); return Instantiators [path] as ItemTemplate; } - //TODO: .Net xml serialisation is no longer used, it has been replaced with instantiators - public static void Save<T> (string file, T graphicObject) - { - XmlSerializerNamespaces xn = new XmlSerializerNamespaces (); - xn.Add ("", ""); - XmlSerializer xs = new XmlSerializer (typeof(T)); - - xs = new XmlSerializer (typeof(T)); - using (Stream s = new FileStream (file, FileMode.Create)) { - xs.Serialize (s, graphicObject, xn); - } - } #endregion #region focus @@ -443,13 +476,22 @@ namespace Crow set { if (_hoverWidget == value) return; + + if (_hoverWidget != null) + _hoverWidget.IsHover = false; + _hoverWidget = value; - #if DEBUG_FOCUS + if (_hoverWidget != null) - Debug.WriteLine("Hover => " + _hoverWidget.ToString()); - else - Debug.WriteLine("Hover => null"); - #endif + { + _hoverWidget.IsHover = true; + #if DEBUG_FOCUS + Debug.WriteLine("Hover => " + _hoverWidget.ToString()); + }else + Debug.WriteLine("Hover => null"); + #else + } + #endif } } /// <summary>Widget has the keyboard or mouse focus</summary> @@ -508,15 +550,7 @@ namespace Crow } } } - if (keyboardRepeatCount > 0) { - int mc = keyboardRepeatCount; - keyboardRepeatCount -= mc; - if (_focusedWidget != null) { - for (int i = 0; i < mc; i++) { - _focusedWidget.onKeyDown (this, lastKeyDownEvt); - } - } - } + CrowThread[] tmpThreads; lock (CrowThreads) { tmpThreads = new CrowThread[CrowThreads.Count]; @@ -556,7 +590,7 @@ namespace Crow /// <summary>Layouting loop, this is the first step of the udpate and process registered /// Layouting queue items. Failing LQI's are requeued in this cycle until MaxTry is reached which /// trigger an enqueue for the next Update Cycle</summary> - void processLayouting(){ + protected virtual void processLayouting(){ #if MEASURE_TIME layoutingMeasure.StartCycle(); #endif @@ -608,12 +642,15 @@ namespace Crow #if MEASURE_TIME drawingMeasure.StartCycle(); #endif + if (DragImage != null) + clipping.UnionRectangle(new Rectangle (DragImageX, DragImageY, DragImageWidth, DragImageHeight)); using (surf = new ImageSurface (bmp, Format.Argb32, ClientRectangle.Width, ClientRectangle.Height, ClientRectangle.Width * 4)) { using (ctx = new Context (surf)){ if (!clipping.IsEmpty) { for (int i = 0; i < clipping.NumRectangles; i++) ctx.Rectangle(clipping.GetRectangle(i)); + ctx.ClipPreserve(); ctx.Operator = Operator.Clear; ctx.Fill(); @@ -631,6 +668,22 @@ namespace Crow ctx.Restore (); } + if (DragAndDropOperation != null) { + if (DragImage != null) { + DirtyRect += new Rectangle (DragImageX, DragImageY, DragImageWidth, DragImageHeight); + DragImageX = Mouse.X - DragImageWidth / 2; + DragImageY = Mouse.Y - DragImageHeight / 2; + ctx.Save (); + ctx.ResetClip (); + ctx.SetSourceSurface (DragImage, DragImageX, DragImageY); + ctx.PaintWithAlpha (0.8); + ctx.Restore (); + DirtyRect += new Rectangle (DragImageX, DragImageY, DragImageWidth, DragImageHeight); + IsDirty = true; + //Console.WriteLine ("dragimage drawn: {0},{1}", DragImageX, DragImageY); + } + } + #if DEBUG_CLIP_RECTANGLE clipping.stroke (ctx, Color.Red.AdjustAlpha(0.5)); #endif @@ -829,13 +882,16 @@ namespace Crow MouseMoveEventArgs e = new MouseMoveEventArgs (x, y, deltaX, deltaY); e.Mouse = Mouse; - if (ActiveWidget != null&& DragAndDropOperation == null) { + if (ActiveWidget != null && DragAndDropOperation == null) { //TODO, ensure object is still in the graphic tree //send move evt even if mouse move outside bounds ActiveWidget.onMouseMove (this, e); return true; } + if (DragAndDropOperation != null)//drag source cant have hover event, so move has to be handle here + DragAndDropOperation.DragSource.onMouseMove (this, e); + if (HoverWidget != null) { resetTooltip (); //check topmost graphicobject first @@ -843,7 +899,7 @@ namespace Crow GraphicObject topc = null; while (tmp is GraphicObject) { topc = tmp; - tmp = tmp.LogicalParent as GraphicObject; + tmp = tmp.focusParent; } int idxhw = GraphicTree.IndexOf (topc); if (idxhw != 0) { @@ -995,9 +1051,9 @@ namespace Crow lastKeyDownEvt.IsRepeat = true; _focusedWidget.onKeyDown (this, e); - keyboardRepeatThread = new Thread (keyboardRepeatThreadFunc); - keyboardRepeatThread.IsBackground = true; - keyboardRepeatThread.Start (); +// keyboardRepeatThread = new Thread (keyboardRepeatThreadFunc); +// keyboardRepeatThread.IsBackground = true; +// keyboardRepeatThread.Start (); return true; } @@ -1014,11 +1070,11 @@ namespace Crow _focusedWidget.onKeyUp (this, e); - if (keyboardRepeatThread != null) { - keyboardRepeatOn = false; - keyboardRepeatThread.Abort(); - keyboardRepeatThread.Join (); - } +// if (keyboardRepeatThread != null) { +// keyboardRepeatOn = false; +// keyboardRepeatThread.Abort(); +// keyboardRepeatThread.Join (); +// } return true; } /// <summary> @@ -1040,7 +1096,7 @@ namespace Crow GraphicObject ToolTipContainer = null; volatile bool tooltipVisible = false; - void initTooltip () { + protected void initTooltip () { ToolTipContainer = Load ("#Crow.Tooltip.template"); Thread t = new Thread (toolTipThreadFunc); t.IsBackground = true; @@ -1081,22 +1137,38 @@ namespace Crow #region Contextual menu MenuItem ctxMenuContainer; - void initContextMenus (){ + protected void initContextMenus (){ ctxMenuContainer = Load ("#Crow.ContextMenu.template") as MenuItem; + ctxMenuContainer.LayoutChanged += CtxMenuContainer_LayoutChanged; + } + + void CtxMenuContainer_LayoutChanged (object sender, LayoutingEventArgs e) + { + Rectangle r = ctxMenuContainer.ScreenCoordinates (ctxMenuContainer.Slot); + if (e.LayoutType == LayoutingType.Width || e.LayoutType == LayoutingType.X) { + if (r.Right > this.clientRectangle.Right) + ctxMenuContainer.Left = this.clientRectangle.Right - ctxMenuContainer.Slot.Width; + }else if (e.LayoutType == LayoutingType.Width || e.LayoutType == LayoutingType.Y) { + if (r.Bottom > this.clientRectangle.Bottom) + ctxMenuContainer.Top = this.clientRectangle.Bottom - ctxMenuContainer.Slot.Height; + } + } public void ShowContextMenu (GraphicObject go) { - if (ctxMenuContainer.Parent == null) - this.AddWidget (ctxMenuContainer); - else - ctxMenuContainer.IsOpened = true; + lock (UpdateMutex) { + if (ctxMenuContainer.Parent == null) + this.AddWidget (ctxMenuContainer); + else + ctxMenuContainer.IsOpened = true; - ctxMenuContainer.isPopup = true; - ctxMenuContainer.LogicalParent = go; - ctxMenuContainer.DataSource = go; + ctxMenuContainer.isPopup = true; + ctxMenuContainer.LogicalParent = go; + ctxMenuContainer.DataSource = go; - PutOnTop (ctxMenuContainer, true); + PutOnTop (ctxMenuContainer, true); + } ctxMenuContainer.Left = Mouse.X - 5; ctxMenuContainer.Top = Mouse.Y - 5; |