From: Jean-Philippe Bruyère Date: Tue, 13 Mar 2018 16:16:24 +0000 (+0100) Subject: limit to html safe color plus several ones, crowIDE wip X-Git-Tag: 0.7.3~4^2~10 X-Git-Url: https://git.osiis.dedyn.io/?a=commitdiff_plain;h=5f1d0213e0dadecc8f93d44e36ea3a11a1aa9baa;p=jp%2Fcrow.git limit to html safe color plus several ones, crowIDE wip --- diff --git a/Crow.csproj b/Crow.csproj index f14b185a..db3da7bb 100644 --- a/Crow.csproj +++ b/Crow.csproj @@ -36,7 +36,7 @@ true - __linux__ + DESIGN_MODE $(SolutionDir)build\Release diff --git a/CrowIDE/CrowIDE.csproj b/CrowIDE/CrowIDE.csproj index 6f423c09..a92b4d9b 100644 --- a/CrowIDE/CrowIDE.csproj +++ b/CrowIDE/CrowIDE.csproj @@ -111,7 +111,6 @@ - @@ -122,6 +121,10 @@ + + + + @@ -135,6 +138,7 @@ + @@ -290,6 +294,8 @@ Crow.Coding.ui.TextEditor.crow + + diff --git a/CrowIDE/src/CrowIDE.cs b/CrowIDE/src/CrowIDE.cs index 12664f1b..783db5d1 100644 --- a/CrowIDE/src/CrowIDE.cs +++ b/CrowIDE/src/CrowIDE.cs @@ -42,7 +42,7 @@ namespace Crow.Coding CMDUndo, CMDRedo, CMDCut, CMDCopy, CMDPaste, CMDHelp, CMDAbout, CMDOptions, CMDViewGTExp, CMDViewProps, CMDViewProj, CMDViewProjProps, CMDViewErrors, CMDViewSolution, CMDViewEditor, CMDViewProperties, - CMDViewToolbox, CMDViewSchema, + CMDViewToolbox, CMDViewSchema, CMDViewStyling, CMDCompile; void initCommands () { @@ -57,7 +57,7 @@ namespace Crow.Coding CMDCopy = new Command(new Action(() => Quit (null, null))) { Caption = "Copy", Icon = new SvgPicture("#Crow.Coding.icons.copy-file.svg"), CanExecute = false}; CMDPaste = new Command(new Action(() => Quit (null, null))) { Caption = "Paste", Icon = new SvgPicture("#Crow.Coding.icons.paste-on-document.svg"), CanExecute = false}; CMDHelp = new Command(new Action(() => System.Diagnostics.Debug.WriteLine("help"))) { Caption = "Help", Icon = new SvgPicture("#Crow.Coding.icons.question.svg")}; - CMDOptions = new Command(new Action(() => openOptionsDialog())) { Caption = "Editor Options", Icon = new SvgPicture("#Crow.Coding.icons.tools.svg")}; + CMDOptions = new Command(new Action(() => loadWindow("#Crow.Coding.ui.Options.crow"))) { Caption = "Editor Options", Icon = new SvgPicture("#Crow.Coding.icons.tools.svg")}; cmdCloseSolution = new Command(new Action(() => closeSolution())) { Caption = "Close Solution", Icon = new SvgPicture("#Crow.Coding.ui.icons.paste-on-document.svg"), CanExecute = false}; @@ -74,6 +74,8 @@ namespace Crow.Coding { Caption = "Toolbox", CanExecute = false}; CMDViewSchema = new Command(new Action(() => loadDockWindow ("#Crow.Coding.ui.DockWindows.winSchema.crow"))) { Caption = "IML Shematic View", CanExecute = true}; + CMDViewStyling = new Command(new Action(() => loadDockWindow ("#Crow.Coding.ui.DockWindows.winStyleView.crow"))) + { Caption = "Styling Explorer", CanExecute = true}; CMDViewGTExp = new Command(new Action(() => loadDockWindow ("#Crow.Coding.ui.DockWindows.winGTExplorer.crow"))) { Caption = "Graphic Tree Explorer", CanExecute = false}; @@ -103,12 +105,13 @@ namespace Crow.Coding static void Main () { CrowIDE win = new CrowIDE (); + MainWin = win; win.Run (30); } public CrowIDE () : base(1024, 800,"UIEditor") - { + { } Instantiator instFileDlg; @@ -117,6 +120,7 @@ namespace Crow.Coding Docker mainDock; public static Interface MainIFace; + public static CrowIDE MainWin; protected override void OnLoad (EventArgs e) { diff --git a/CrowIDE/src/DesignInterface.cs b/CrowIDE/src/DesignInterface.cs index 4178e398..04666b11 100644 --- a/CrowIDE/src/DesignInterface.cs +++ b/CrowIDE/src/DesignInterface.cs @@ -66,21 +66,6 @@ namespace Crow.Coding return CreateITorFromIMLFragment (pi.Source).CreateInstance(); return null; } - public override Crow.IML.Instantiator GetInstantiator (string path) - { - System.Diagnostics.Debugger.Break (); - return null; - } - public override ItemTemplate GetItemTemplate (string path) - { - ProjectFile pi; - - if (ProjFile.Project.solution.GetProjectFileFromPath (path, out pi)) - return new ItemTemplate (this, pi.AbsolutePath); - - System.Diagnostics.Debugger.Break (); - return null; - } public override System.IO.Stream GetStreamFromPath (string path) { ProjectFile pi; diff --git a/CrowIDE/src/Editors/CodeBuffer/CodeBuffer.cs b/CrowIDE/src/Editors/CodeBuffer/CodeBuffer.cs index 13c422a6..7d5efec9 100644 --- a/CrowIDE/src/Editors/CodeBuffer/CodeBuffer.cs +++ b/CrowIDE/src/Editors/CodeBuffer/CodeBuffer.cs @@ -63,7 +63,7 @@ namespace Crow.Coding public CodeLine this[int i] { - get { return lines[i]; } + get { return i < LineCount ? lines[i] : null; } set { if (lines [i] == value) return; @@ -392,7 +392,9 @@ namespace Crow.Coding editMutex.EnterReadLock (); - if (value >= lines.Count) + if (LineCount == 0) + _currentLine = 0; + else if (value >= lines.Count) _currentLine = lines.Count-1; else if (value < 0) _currentLine = 0; diff --git a/CrowIDE/src/Editors/CodeBuffer/SourceEditor.cs b/CrowIDE/src/Editors/CodeBuffer/SourceEditor.cs deleted file mode 100644 index 48d634b3..00000000 --- a/CrowIDE/src/Editors/CodeBuffer/SourceEditor.cs +++ /dev/null @@ -1,1206 +0,0 @@ -// -// ScrollingTextBox.cs -// -// Author: -// Jean-Philippe Bruyère -// -// 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 Cairo; -using System.Text; -using System.Collections.Generic; -using System.Text.RegularExpressions; -using System.Linq; -using System.Diagnostics; -using System.IO; -using System.Threading; - -namespace Crow.Coding -{ - /// - /// Scrolling text box optimized for monospace fonts, for coding - /// - public class SourceEditor : Editor - { - #region CTOR - public SourceEditor (): base() - { - formatting.Add ((int)XMLParser.TokenType.AttributeName, new TextFormatting (Color.DarkJungleGreen, Color.Transparent)); - formatting.Add ((int)XMLParser.TokenType.ElementName, new TextFormatting (Color.DarkBlue, Color.Transparent)); - formatting.Add ((int)XMLParser.TokenType.ElementStart, new TextFormatting (Color.Black, Color.Transparent)); - formatting.Add ((int)XMLParser.TokenType.ElementEnd, new TextFormatting (Color.Black, Color.Transparent)); - formatting.Add ((int)XMLParser.TokenType.ElementClosing, new TextFormatting (Color.Black, Color.Transparent)); - - formatting.Add ((int)XMLParser.TokenType.AttributeValueOpening, new TextFormatting (Color.Carmine, Color.Transparent)); - formatting.Add ((int)XMLParser.TokenType.AttributeValueClosing, new TextFormatting (Color.Carmine, Color.Transparent)); - formatting.Add ((int)XMLParser.TokenType.AttributeValue, new TextFormatting (Color.TractorRed, Color.Transparent, false, true)); - formatting.Add ((int)XMLParser.TokenType.XMLDecl, new TextFormatting (Color.AoEnglish, Color.Transparent)); - - formatting.Add ((int)BufferParser.TokenType.BlockComment, new TextFormatting (Color.Gray, Color.Transparent, false, true)); - formatting.Add ((int)BufferParser.TokenType.LineComment, new TextFormatting (Color.Gray, Color.Transparent, false, true)); - formatting.Add ((int)BufferParser.TokenType.OperatorOrPunctuation, new TextFormatting (Color.Black, Color.Transparent)); - formatting.Add ((int)BufferParser.TokenType.Keyword, new TextFormatting (Color.Teal, Color.Transparent)); - //formatting.Add ((int)BufferParser.TokenType.Keyword, new TextFormatting (Color.DarkCyan, Color.Transparent)); - - parsing.Add (".crow", "Crow.Coding.XMLParser"); - parsing.Add (".svg", "Crow.Coding.XMLParser"); - parsing.Add (".template", "Crow.Coding.XMLParser"); - parsing.Add (".cs", "Crow.Coding.CSharpParser"); - parsing.Add (".style", "Crow.Coding.StyleParser"); - - buffer = new CodeBuffer (); - buffer.LineUpadateEvent += Buffer_LineUpadateEvent; - buffer.LineAdditionEvent += Buffer_LineAdditionEvent;; - buffer.LineRemoveEvent += Buffer_LineRemoveEvent; - buffer.BufferCleared += Buffer_BufferCleared; - buffer.SelectionChanged += Buffer_SelectionChanged; - buffer.PositionChanged += Buffer_PositionChanged; - buffer.FoldingEvent += Buffer_FoldingEvent; - buffer.Add (new CodeLine("")); - } - #endregion - - string oldSource = ""; - //save requested position on error, and try it on next move - int requestedLine = 0, requestedCol = 0; - volatile bool isDirty = false; - - const int leftMarginGap = 10;//gap between items in margin and text - const int foldSize = 9;//folding rectangles size - const int foldHSpace = 4;//folding level tabulation x - int foldMargin { get { return parser == null ? 0 : parser.SyntacticTreeMaxDepth * foldHSpace; }}//folding margin size - - #region private and protected fields - bool foldingEnabled = true; - int leftMargin = 0; //margin used to display line numbers, folding errors,etc... - int visibleLines = 1; - int visibleColumns = 1; - int firstPrintedLine = -1; - int printedCurrentLine = 0;//Index of the currentline in the PrintedLines array - - CodeBuffer buffer; - BufferParser parser; - List PrintedLines;//list of lines visible in the Editor depending on scrolling and folding - - Dictionary formatting = new Dictionary(); - Dictionary parsing = new Dictionary(); - - Color selBackground; - Color selForeground; - int selStartCol; - int selEndCol; - - protected Rectangle rText; - protected FontExtents fe; - protected TextExtents te; - - Point mouseLocalPos; - bool doubleClicked = false; - #endregion - - void measureLeftMargin () { - leftMargin = 0; - if (PrintLineNumbers) - leftMargin += (int)Math.Ceiling((double)buffer.LineCount.ToString().Length * fe.MaxXAdvance) +6; - if (foldingEnabled) - leftMargin += foldMargin; - if (leftMargin > 0) - leftMargin += leftMarginGap; - updateVisibleColumns (); - } - void findLongestLineAndUpdateMaxScrollX() { - buffer.FindLongestVisualLine (); - updateMaxScrollX (); -// Debug.WriteLine ("SourceEditor: Find Longest line and update maxscrollx: {0} visible cols:{1}", MaxScrollX, visibleColumns); - } - /// - /// Updates visible line in widget, adapt max scroll y and updatePrintedLines - /// - void updateVisibleLines(){ - visibleLines = (int)Math.Floor ((double)ClientRectangle.Height / (fe.Ascent+fe.Descent)); - NotifyValueChanged ("VisibleLines", visibleLines); - updateMaxScrollY (); - updatePrintedLines (); - RegisterForGraphicUpdate (); -// System.Diagnostics.Debug.WriteLine ("update visible lines: " + visibleLines); -// System.Diagnostics.Debug.WriteLine ("update MaxScrollY: " + MaxScrollY); - } - void updateVisibleColumns(){ - visibleColumns = (int)Math.Floor ((double)(ClientRectangle.Width - leftMargin)/ fe.MaxXAdvance); - NotifyValueChanged ("VisibleColumns", visibleColumns); - updateMaxScrollX (); -// System.Diagnostics.Debug.WriteLine ("update visible columns: {0} leftMargin:{1}",visibleColumns, leftMargin); -// System.Diagnostics.Debug.WriteLine ("update MaxScrollX: " + MaxScrollX); - } - void updateMaxScrollX () { - MaxScrollX = Math.Max (0, buffer.longestLineCharCount - visibleColumns); - if (buffer.longestLineCharCount > 0) - NotifyValueChanged ("ChildWidthRatio", Slot.Width * visibleColumns / buffer.longestLineCharCount); - } - void updateMaxScrollY () { - if (parser == null || !foldingEnabled) { - MaxScrollY = Math.Max (0, buffer.LineCount - visibleLines); - if (buffer.UnfoldedLines > 0) - NotifyValueChanged ("ChildHeightRatio", Slot.Height * visibleLines / buffer.UnfoldedLines); - } else { - MaxScrollY = Math.Max (0, buffer.UnfoldedLines - visibleLines); - if (buffer.UnfoldedLines > 0) - NotifyValueChanged ("ChildHeightRatio", Slot.Height * visibleLines / buffer.UnfoldedLines); - } - } - void updatePrintedLines () { - buffer.editMutex.EnterReadLock (); - editorMutex.EnterWriteLock (); - - PrintedLines = new List (); - int curL = 0; - int i = 0; - - while (curL < buffer.LineCount && i < ScrollY) { - if (buffer [curL].IsFolded) - curL = buffer.GetEndNodeIndex (curL); - curL++; - i++; - } - - firstPrintedLine = curL; - i = 0; - while (i < visibleLines && curL < buffer.LineCount) { - PrintedLines.Add (buffer [curL]); - - if (buffer [curL].IsFolded) - curL = buffer.GetEndNodeIndex (curL); - - curL++; - i++; - } - - buffer.editMutex.ExitReadLock (); - editorMutex.ExitWriteLock (); - } - void updateOnScreenCurLineFromBuffCurLine(){ - printedCurrentLine = PrintedLines.IndexOf (buffer.CurrentCodeLine); - } - void toogleFolding (int line) { - if (parser == null || !foldingEnabled) - return; - buffer.ToogleFolding (line); - } - - #region Editor overrides - protected override void updateEditorFromProjFile () - { - buffer.editMutex.EnterWriteLock (); - loadSource (); - buffer.editMutex.ExitWriteLock (); - - isDirty = false; - oldSource = projFile.Source; - CurrentLine = requestedLine; - CurrentColumn = requestedCol; - projFile.RegisteredEditors [this] = true; - } - protected override void updateProjFileFromEditor () - { - buffer.editMutex.EnterWriteLock (); - string newsrc = buffer.FullText; - buffer.editMutex.ExitWriteLock (); - projFile.UpdateSource (this, newsrc); - } - protected override bool EditorIsDirty { - get { return isDirty; } - set { isDirty = value; } - } - protected override bool IsReady { - get { return projFile != null && buffer != null; } - } - #endregion - - #region Buffer events handlers - void Buffer_BufferCleared (object sender, EventArgs e) - { - editorMutex.EnterWriteLock (); - - buffer.longestLineCharCount = 0; - buffer.longestLineIdx = 0; - measureLeftMargin (); - MaxScrollX = MaxScrollY = 0; - PrintedLines = null; - RegisterForGraphicUpdate (); - notifyPositionChanged (); - isDirty = true; - - editorMutex.ExitWriteLock (); - } - void Buffer_LineAdditionEvent (object sender, CodeBufferEventArgs e) - { - for (int i = 0; i < e.LineCount; i++) { - int lptr = e.LineStart + i; - int charCount = buffer[lptr].PrintableLength; - if (charCount > buffer.longestLineCharCount) { - buffer.longestLineIdx = lptr; - buffer.longestLineCharCount = charCount; - }else if (lptr <= buffer.longestLineIdx) - buffer.longestLineIdx++; - if (parser == null) - continue; - parser.TryParseBufferLine (e.LineStart + i); - } - - if (parser != null) - parser.reparseSource (); - - measureLeftMargin (); - - updatePrintedLines (); - updateMaxScrollY (); - RegisterForGraphicUpdate (); - notifyPositionChanged (); - isDirty = true; - } - void Buffer_LineRemoveEvent (object sender, CodeBufferEventArgs e) - { - bool trigFindLongestLine = false; - for (int i = 0; i < e.LineCount; i++) { - int lptr = e.LineStart + i; - if (lptr <= buffer.longestLineIdx) - trigFindLongestLine = true; - } - if (trigFindLongestLine) - findLongestLineAndUpdateMaxScrollX (); - - measureLeftMargin (); - updatePrintedLines (); - updateMaxScrollY (); - RegisterForGraphicUpdate (); - notifyPositionChanged (); - isDirty = true; - } - void Buffer_LineUpadateEvent (object sender, CodeBufferEventArgs e) - { - bool trigFindLongestLine = false; - for (int i = 0; i < e.LineCount; i++) { - - int lptr = e.LineStart + i; - if (lptr == buffer.longestLineIdx) - trigFindLongestLine = true; - else if (buffer[lptr].PrintableLength > buffer.longestLineCharCount) { - buffer.longestLineCharCount = buffer[lptr].PrintableLength; - buffer.longestLineIdx = lptr; - } - } - if (trigFindLongestLine) - findLongestLineAndUpdateMaxScrollX (); - - RegisterForGraphicUpdate (); - notifyPositionChanged (); - isDirty = true; - } - void Buffer_PositionChanged (object sender, EventArgs e) - { - Console.WriteLine ("Position changes: ({0},{1})", buffer.CurrentLine, buffer.CurrentColumn); - int cc = buffer.CurrentTabulatedColumn; - - if (cc > visibleColumns + ScrollX) { - ScrollX = cc - visibleColumns; - } else if (cc < ScrollX) - ScrollX = cc; - - RegisterForGraphicUpdate (); - updateOnScreenCurLineFromBuffCurLine (); - notifyPositionChanged (); - } - - void Buffer_SelectionChanged (object sender, EventArgs e) - { - RegisterForGraphicUpdate (); - } - void Buffer_FoldingEvent (object sender, CodeBufferEventArgs e) - { - updatePrintedLines (); - updateOnScreenCurLineFromBuffCurLine (); - updateMaxScrollY (); - RegisterForGraphicUpdate (); - } - #endregion - - void notifyPositionChanged (){ - try { - NotifyValueChanged ("CurrentLine", buffer.CurrentLine+1); - NotifyValueChanged ("CurrentColumn", buffer.CurrentColumn+1); - NotifyValueChanged ("CurrentLineHasError", CurrentLineHasError); - NotifyValueChanged ("CurrentLineError", CurrentLineError); - } catch (Exception ex) { - Console.WriteLine (ex.ToString ()); - } - } - - #region Public Crow Properties - public int CurrentLine{ - get { return buffer == null ? 0 : buffer.CurrentLine+1; } - set { - try { - int l = value - 1; - if (l == buffer.CurrentLine) - return; - buffer.CurrentLine = l; - if (buffer [l].IsFolded) - buffer.ToogleFolding (l); - } catch (Exception ex) { - requestedLine = value - 1; - Console.WriteLine ("Error cur column: " + ex.ToString ()); - } - } - } - public int CurrentColumn{ - get { return buffer == null ? 0 : buffer.CurrentColumn+1; } - set { - try { - if (value - 1 == buffer.CurrentColumn) - return; - buffer.CurrentColumn = value - 1; - } catch (Exception ex) { - requestedCol = value - 1; - Console.WriteLine ("Error cur column: " + ex.ToString ()); - } - } - } - public bool PrintLineNumbers - { - get { return Configuration.Global.Get ("PrintLineNumbers"); } - set { - if (PrintLineNumbers == value) - return; - Configuration.Global.Set ("PrintLineNumbers", value); - NotifyValueChanged ("PrintLineNumbers", PrintLineNumbers); - measureLeftMargin (); - RegisterForGraphicUpdate (); - } - } - [DefaultValue("BlueGray")] - 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 (); - } - } - public override int ScrollY { - get { - return base.ScrollY; - } - set { - if (value == base.ScrollY) - return; - base.ScrollY = value; - updatePrintedLines (); - updateOnScreenCurLineFromBuffCurLine (); - RegisterForGraphicUpdate (); - } - } - public ParserException CurrentLineError { - get { return buffer?.CurrentCodeLine?.exception; } - } - public bool CurrentLineHasError { - get { return buffer == null ? false : buffer.CurrentCodeLine == null ? false : - buffer.CurrentCodeLine.exception != null; } - } - public override ProjectFile ProjectNode { - get { - return base.ProjectNode; - } - set { - base.ProjectNode = value; - if (projFile != null) - parser = getParserFromExt (System.IO.Path.GetExtension (projFile.Extension)); - } - } - #endregion - - BufferParser getParserFromExt (string extension) { - if (string.IsNullOrEmpty(extension)) - return null; - if (!parsing.ContainsKey(extension)) - return null; - Type parserType = Type.GetType (parsing [extension]); - if (parserType == null) - return null; - return (BufferParser)Activator.CreateInstance (parserType, buffer ); - } - void loadSource () { - - try { - - if (parser == null) - buffer.Load (projFile.Source); - else//parser may have special linebrk rules - buffer.Load (projFile.Source, parser.LineBrkRegex); - - } catch (Exception ex) { - Debug.WriteLine (ex.ToString ()); - } - - projFile.RegisteredEditors [this] = true; - - updateMaxScrollY (); - MaxScrollX = Math.Max (0, buffer.longestLineCharCount - visibleColumns); - updatePrintedLines (); - - RegisterForGraphicUpdate (); - } - - /// - /// Current editor line, when set, update buffer.CurrentLine - /// - int PrintedCurrentLine { - get { return printedCurrentLine;} - set { - if (value < 0) { - ScrollY += value; - printedCurrentLine = 0; - } else if (PrintedLines.Count < visibleLines && value >= PrintedLines.Count) { - printedCurrentLine = PrintedLines.Count - 1; - }else if (value >= visibleLines) { - ScrollY += value - visibleLines + 1; - printedCurrentLine = visibleLines - 1; - }else - printedCurrentLine = value; - //Debug.WriteLine ("printed current line:" + printedCurrentLine.ToString ()); - //update position in buffer - buffer.CurrentLine = buffer.IndexOf (PrintedLines[printedCurrentLine]); - } - } - int getTabulatedColumn (int col, int line) { - return buffer [line].Content.Substring (0, col).Replace ("\t", new String (' ', Interface.TabSize)).Length; - } - int getTabulatedColumn (Point pos) { - return getTabulatedColumn (pos.X,pos.Y); - } - /// - /// Moves cursor one char to the left, move up if cursor reaches start of line - /// - /// true if move succeed - public bool MoveLeft(){ - if (buffer.CurrentColumn == 0) { - if (printedCurrentLine == 0) - return false; - PrintedCurrentLine--; - buffer.CurrentColumn = int.MaxValue; - } else - buffer.CurrentColumn--; - return true; - } - /// - /// Moves cursor one char to the right, move down if cursor reaches end of line - /// - /// true if move succeed - public bool MoveRight(){ - if (buffer.CurrentColumn >= buffer.CurrentCodeLine.Length) { - if (PrintedCurrentLine == buffer.UnfoldedLines - 1) - return false; - buffer.CurrentColumn = 0; - PrintedCurrentLine++; - } else - buffer.CurrentColumn++; - return true; - } - - #region Drawing - void drawLine(Context gr, Rectangle cb, int i) { - CodeLine cl = PrintedLines[i]; - int lineIndex = buffer.IndexOf(cl); - - double y = cb.Y + (fe.Ascent+fe.Descent) * i, x = cb.X; - - //Draw line numbering - Color mgFg = Color.Gray; - Color mgBg = Color.White; - if (PrintLineNumbers){ - Rectangle mgR = new Rectangle ((int)x, (int)y, leftMargin - leftMarginGap, (int)Math.Ceiling((fe.Ascent+fe.Descent))); - if (cl.exception != null) { - mgBg = Color.Red; - if (buffer.CurrentLine == lineIndex) - mgFg = Color.White; - else - mgFg = Color.LightGray; - }else if (buffer.CurrentLine == lineIndex) { - mgFg = Color.Black; - mgBg = Color.DarkGray; - } - string strLN = (lineIndex+1).ToString (); - gr.SetSourceColor (mgBg); - gr.Rectangle (mgR); - gr.Fill(); - gr.SetSourceColor (mgFg); - - gr.MoveTo (cb.X + (int)(gr.TextExtents (buffer.LineCount.ToString()).Width - gr.TextExtents (strLN).Width), y + fe.Ascent); - gr.ShowText (strLN); - gr.Fill (); - } - - - - //draw folding - if (foldingEnabled){ - - Rectangle rFld = new Rectangle (cb.X + leftMargin - leftMarginGap - foldMargin, - (int)(y + (fe.Ascent + fe.Descent) / 2.0 - foldSize / 2.0), foldSize, foldSize); - - gr.SetSourceColor (Color.Black); - gr.LineWidth = 1.0; - - int level = 0; - bool closingNode = false; - - if (currentNode != null) { - if (cl == currentNode.EndLine) { - currentNode = currentNode.Parent; - closingNode = true; - } - if (currentNode != null) - level = currentNode.Level - 1; - } - - for (int l = 0; l < level; l++) { - gr.MoveTo (rFld.Center.X + 0.5, y); - gr.LineTo (rFld.Center.X + 0.5, y + fe.Ascent + fe.Descent); - rFld.Left += foldHSpace; - } - if (closingNode) { - gr.MoveTo (rFld.Center.X + 0.5, y); - gr.LineTo (rFld.Center.X + 0.5, y + fe.Ascent / 2 + 0.5); - gr.LineTo (rFld.Center.X + 0.5 + foldSize / 2, y + fe.Ascent / 2 + 0.5); - closingNode = false; - } - gr.SetDash (new double[]{ 1.5 },0.0); - gr.SetSourceColor (Color.Gray); - gr.Stroke (); - gr.SetDash (new double[]{}, 0.0); - - if (cl.IsFoldable) { - gr.Rectangle (rFld); - gr.SetSourceColor (Color.White); - gr.Fill(); - gr.SetSourceColor (Color.Black); - gr.Rectangle (rFld, 1.0); - if (cl.IsFolded) { - gr.MoveTo (rFld.Center.X + 0.5, rFld.Y + 2); - gr.LineTo (rFld.Center.X + 0.5, rFld.Bottom - 2); - }else - currentNode = cl.SyntacticNode; - - gr.MoveTo (rFld.Left + 2, rFld.Center.Y + 0.5); - gr.LineTo (rFld.Right - 2, rFld.Center.Y + 0.5); - gr.Stroke (); - } - } - - gr.SetSourceColor (Foreground); - x += leftMargin; - - if (cl.Tokens == null) - drawRawCodeLine (gr, x, y, i, lineIndex); - else - drawParsedCodeLine (gr, x, y, i, lineIndex); - } - Node currentNode = null; -// void drawParsed(Context gr){ -// if (PrintedLines == null) -// return; -// -// gr.SelectFontFace (Font.Name, Font.Slant, Font.Wheight); -// gr.SetFontSize (Font.Size); -// gr.FontOptions = Interface.FontRenderingOptions; -// gr.Antialias = Interface.Antialias; -// -// Rectangle cb = ClientRectangle; -// gr.Save (); -// CairoHelpers.CairoRectangle (gr, cb, CornerRadius); -// gr.Clip (); -// -// bool selectionInProgress = false; -// -// Foreground.SetAsSource (gr); -// -// #region draw text cursor -// if (SelBegin != SelRelease) -// selectionInProgress = true; -// else if (HasFocus){ -// gr.LineWidth = 1.0; -// double cursorX = + leftMargin + cb.X + (CurrentColumn - ScrollX) * fe.MaxXAdvance; -// gr.MoveTo (0.5 + cursorX, cb.Y + printedCurrentLine * (fe.Ascent+fe.Descent)); -// gr.LineTo (0.5 + cursorX, cb.Y + (printedCurrentLine + 1) * (fe.Ascent+fe.Descent)); -// gr.Stroke(); -// } -// #endregion -// -// for (int i = 0; i < PrintedLines.Count; i++) -// drawTokenLine (gr, i, selectionInProgress, cb); -// -// gr.Restore (); -// } - void drawRawCodeLine(Context gr, double x, double y, int i, int lineIndex) { - string lstr = buffer[lineIndex].PrintableContent; - if (ScrollX < lstr.Length) - lstr = lstr.Substring (ScrollX); - else - lstr = ""; - - gr.MoveTo (x, y + fe.Ascent); - gr.ShowText (lstr); - gr.Fill (); - - if (!buffer.SelectionIsEmpty && lineIndex >= buffer.SelectionStart.Y && lineIndex <= buffer.SelectionEnd.Y) { - double rLineX = x, - rLineY = y, - rLineW = lstr.Length * fe.MaxXAdvance; - - //System.Diagnostics.Debug.WriteLine ("sel start: " + buffer.SelectionStart + " sel end: " + buffer.SelectionEnd); - if (lineIndex == buffer.SelectionStart.Y) { - rLineX += (selStartCol - ScrollX) * fe.MaxXAdvance; - rLineW -= selStartCol * fe.MaxXAdvance; - } - if (lineIndex == buffer.SelectionEnd.Y) - rLineW -= (lstr.Length - selEndCol) * fe.MaxXAdvance; - - gr.Save (); - gr.Operator = Operator.Source; - gr.Rectangle (rLineX, rLineY, rLineW, (fe.Ascent+fe.Descent)); - gr.SetSourceColor (SelectionBackground); - gr.FillPreserve (); - gr.Clip (); - gr.Operator = Operator.Over; - gr.SetSourceColor (SelectionForeground); - gr.MoveTo (x, y + fe.Ascent); - gr.ShowText (lstr); - gr.Fill (); - gr.Restore (); - } - } - void drawParsedCodeLine (Context gr, double x, double y, int i, int lineIndex) { - int lPtr = 0; - CodeLine cl = PrintedLines[i]; - - for (int t = 0; t < cl.Tokens.Count; t++) { - string lstr = cl.Tokens [t].PrintableContent; - if (lPtr < ScrollX) { - if (lPtr - ScrollX + lstr.Length <= 0) { - lPtr += lstr.Length; - continue; - } - lstr = lstr.Substring (ScrollX - lPtr); - lPtr += ScrollX - lPtr; - } - Color bg = this.Background; - Color fg = this.Foreground; - Color selbg = this.SelectionBackground; - Color selfg = this.SelectionForeground; - FontSlant fts = FontSlant.Normal; - FontWeight ftw = FontWeight.Normal; - - if (formatting.ContainsKey ((int)cl.Tokens [t].Type)) { - TextFormatting tf = formatting [(int)cl.Tokens [t].Type]; - bg = tf.Background; - fg = tf.Foreground; - if (tf.Bold) - ftw = FontWeight.Bold; - if (tf.Italic) - fts = FontSlant.Italic; - } - - gr.SelectFontFace (Font.Name, fts, ftw); - gr.SetSourceColor (fg); - - gr.MoveTo (x, y + fe.Ascent); - gr.ShowText (lstr); - gr.Fill (); - - if (buffer.SelectionInProgress && lineIndex >= buffer.SelectionStart.Y && lineIndex <= buffer.SelectionEnd.Y && - !(lineIndex == buffer.SelectionStart.Y && lPtr + lstr.Length <= selStartCol) && - !(lineIndex == buffer.SelectionEnd.Y && selEndCol <= lPtr)) { - - double rLineX = x, - rLineY = y, - rLineW = lstr.Length * fe.MaxXAdvance; - double startAdjust = 0.0; - - if ((lineIndex == buffer.SelectionStart.Y) && (selStartCol < lPtr + lstr.Length) && (selStartCol > lPtr)) - startAdjust = (selStartCol - lPtr) * fe.MaxXAdvance; - rLineX += startAdjust; - if ((lineIndex == buffer.SelectionEnd.Y) && (selEndCol < lPtr + lstr.Length)) - rLineW = (selEndCol - lPtr) * fe.MaxXAdvance; - rLineW -= startAdjust; - - gr.Save (); - gr.Operator = Operator.Source; - gr.Rectangle (rLineX, rLineY, rLineW, (fe.Ascent+fe.Descent)); - gr.SetSourceColor (selbg); - gr.FillPreserve (); - gr.Clip (); - gr.Operator = Operator.Over; - gr.SetSourceColor (selfg); - gr.MoveTo (x, y + fe.Ascent); - gr.ShowText (lstr); - gr.Fill (); - gr.Restore (); - } - x += (int)lstr.Length * fe.MaxXAdvance; - lPtr += lstr.Length; - } - } - - #endregion - - #region GraphicObject overrides - public override Font Font { - get { return base.Font; } - set { - base.Font = value; - - using (ImageSurface img = new ImageSurface (Format.Argb32, 1, 1)) { - using (Context gr = new Context (img)) { - gr.SelectFontFace (Font.Name, Font.Slant, Font.Wheight); - gr.SetFontSize (Font.Size); - - fe = gr.FontExtents; - } - } - MaxScrollY = 0; - RegisterForGraphicUpdate (); - } - } - protected override int measureRawSize(LayoutingType lt) - { - if (lt == LayoutingType.Height) - return (int)Math.Ceiling((fe.Ascent+fe.Descent) * buffer.LineCount) + Margin * 2; - - return (int)(fe.MaxXAdvance * buffer.longestLineCharCount) + Margin * 2 + leftMargin; - } - public override void OnLayoutChanges (LayoutingType layoutType) - { - base.OnLayoutChanges (layoutType); - - if (layoutType == LayoutingType.Height) - updateVisibleLines (); - else if (layoutType == LayoutingType.Width) - updateVisibleColumns (); - } - - 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; - - Rectangle cb = ClientRectangle; - - Foreground.SetAsSource (gr); - - buffer.editMutex.EnterReadLock (); - editorMutex.EnterReadLock (); - - #region draw text cursor - if (buffer.SelectionInProgress){ - selStartCol = getTabulatedColumn (buffer.SelectionStart); - selEndCol = getTabulatedColumn (buffer.SelectionEnd); - }else if (HasFocus && printedCurrentLine >= 0){ - gr.LineWidth = 1.0; - double cursorX = cb.X + (getTabulatedColumn(buffer.CurrentPosition) - ScrollX) * fe.MaxXAdvance + leftMargin; - gr.MoveTo (0.5 + cursorX, cb.Y + (printedCurrentLine) * (fe.Ascent+fe.Descent)); - gr.LineTo (0.5 + cursorX, cb.Y + (printedCurrentLine + 1) * (fe.Ascent+fe.Descent)); - gr.Stroke(); - } - #endregion - - if (PrintedLines?.Count > 0) { - int unfoldedLines = buffer.UnfoldedLines; - currentNode = null; - CodeLine cl = PrintedLines[0]; - int idx0 = buffer.IndexOf(cl); - int li = idx0-1; - while (li >= 0) { - if (buffer [li].IsFoldable && !buffer [li].IsFolded) { - if (buffer.IndexOf(buffer [li].SyntacticNode.EndLine) > idx0){ - currentNode = buffer [li].SyntacticNode; - break; - } - } - li--; - } - - for (int i = 0; i < visibleLines; i++) { - if (i + ScrollY >= unfoldedLines)//TODO:need optimize - break; - drawLine (gr, cb, i); - } - } - - editorMutex.ExitReadLock (); - - buffer.editMutex.ExitReadLock (); - - } - #endregion - - #region Mouse handling - - int hoverLine = -1; - public int HoverLine { - get { return hoverLine; } - set { - if (hoverLine == value) - return; - hoverLine = value; - NotifyValueChanged ("HoverLine", hoverLine); - } - } - void updateHoverLine () { - int hvl = (int)Math.Max (0, Math.Floor (mouseLocalPos.Y / (fe.Ascent+fe.Descent))); - hvl = Math.Min (PrintedLines.Count, hvl); - HoverLine = buffer.IndexOf (PrintedLines[hvl]); - } - void updateCurrentPosFromMouseLocalPos(){ - PrintedCurrentLine = (int)Math.Max (0, Math.Floor (mouseLocalPos.Y / (fe.Ascent+fe.Descent))); - int curVisualCol = ScrollX + (int)Math.Round ((mouseLocalPos.X - leftMargin) / fe.MaxXAdvance); - - int i = 0; - int buffCol = 0; - while (i < curVisualCol && buffCol < buffer.CurrentCodeLine.Length) { - if (buffer.CurrentCodeLine[buffCol] == '\t') - i += Interface.TabSize; - else - i++; - buffCol++; - } - buffer.CurrentColumn = buffCol; - } - public override void onMouseEnter (object sender, MouseMoveEventArgs e) - { - base.onMouseEnter (sender, e); - if (e.X - ScreenCoordinates(Slot).X < leftMargin + ClientRectangle.X) - IFace.MouseCursor = XCursor.Default; - else - IFace.MouseCursor = XCursor.Text; - } - public override void onMouseLeave (object sender, MouseMoveEventArgs e) - { - base.onMouseLeave (sender, e); - IFace.MouseCursor = XCursor.Default; - } - public override void onMouseMove (object sender, MouseMoveEventArgs e) - { - base.onMouseMove (sender, e); - - mouseLocalPos = e.Position - ScreenCoordinates(Slot).TopLeft - ClientRectangle.TopLeft; - - updateHoverLine (); - - if (!e.Mouse.IsButtonDown (MouseButton.Left)) { - if (mouseLocalPos.X < leftMargin) - IFace.MouseCursor = XCursor.Default; - else - IFace.MouseCursor = XCursor.Text; - return; - } - - if (!HasFocus || !buffer.SelectionInProgress) - return; - - //mouse is down - updateCurrentPosFromMouseLocalPos(); - buffer.SetSelEndPos (); - } - public override void onMouseDown (object sender, MouseButtonEventArgs e) - { - if (!this.Focusable) - return; - - if (mouseLocalPos.X >= leftMargin) - base.onMouseDown (sender, e); - - if (doubleClicked) { - doubleClicked = false; - return; - } - - if (mouseLocalPos.X < leftMargin) { - toogleFolding (buffer.IndexOf (PrintedLines [(int)Math.Max (0, Math.Floor (mouseLocalPos.Y / (fe.Ascent+fe.Descent)))])); - return; - } - - updateCurrentPosFromMouseLocalPos (); - buffer.SetSelStartPos (); - } - public override void onMouseUp (object sender, MouseButtonEventArgs e) - { - base.onMouseUp (sender, e); - - if (buffer.SelectionIsEmpty) - buffer.ResetSelection (); - } - - public override void onMouseDoubleClick (object sender, MouseButtonEventArgs e) - { - doubleClicked = true; - base.onMouseDoubleClick (sender, e); - - buffer.GotoWordStart (); - buffer.SetSelStartPos (); - buffer.GotoWordEnd (); - buffer.SetSelEndPos (); - } - - public override void onMouseWheel (object sender, MouseWheelEventArgs e) - { - base.onMouseWheel (sender, e); - } - #endregion - - #region Keyboard handling - public override void onKeyDown (object sender, KeyboardKeyEventArgs e) - { - //base.onKeyDown (sender, e); - - Key key = e.Key; - - if (e.Control) { - switch (key) { - case Key.S: - projFile.Save (); - break; - case Key.W: - editorMutex.EnterWriteLock (); - if (e.Shift) - projFile.Redo (null); - else - projFile.Undo (null); - editorMutex.ExitWriteLock (); - break; - default: - Console.WriteLine (""); - break; - } - } - - switch (key) - { - case Key.Back: - buffer.DeleteChar (); - break; - case Key.Clear: - break; - case Key.Delete: - if (buffer.SelectionIsEmpty) - MoveRight (); - else if (e.Shift) - IFace.Clipboard = buffer.SelectedText; - buffer.DeleteChar (); - break; - case Key.Enter: - case Key.KeypadEnter: - if (!buffer.SelectionIsEmpty) - buffer.DeleteChar (); - buffer.InsertLineBreak (); - break; - case Key.Escape: - buffer.ResetSelection (); - break; - case Key.Home: - if (e.Shift) { - if (buffer.SelectionIsEmpty) - buffer.SetSelStartPos (); - if (e.Control) - buffer.CurrentLine = 0; - buffer.CurrentColumn = 0; - buffer.SetSelEndPos (); - break; - } - buffer.ResetSelection (); - if (e.Control) - buffer.CurrentLine = 0; - buffer.CurrentColumn = 0; - break; - case Key.End: - if (e.Shift) { - if (buffer.SelectionIsEmpty) - buffer.SetSelStartPos (); - if (e.Control) - buffer.CurrentLine = int.MaxValue; - buffer.CurrentColumn = int.MaxValue; - buffer.SetSelEndPos (); - break; - } - buffer.ResetSelection (); - if (e.Control) - buffer.CurrentLine = int.MaxValue; - buffer.CurrentColumn = int.MaxValue; - break; - case Key.Insert: - if (e.Shift) - buffer.Insert (IFace.Clipboard); - else if (e.Control && !buffer.SelectionIsEmpty) - IFace.Clipboard = buffer.SelectedText; - break; - case Key.Left: - if (e.Shift) { - if (buffer.SelectionIsEmpty) - buffer.SetSelStartPos (); - if (e.Control) - buffer.GotoWordStart (); - else - MoveLeft (); - buffer.SetSelEndPos (); - break; - } - buffer.ResetSelection (); - if (e.Control) - buffer.GotoWordStart (); - else - MoveLeft(); - break; - case Key.Right: - if (e.Shift) { - if (buffer.SelectionIsEmpty) - buffer.SetSelStartPos (); - if (e.Control) - buffer.GotoWordEnd (); - else - MoveRight (); - buffer.SetSelEndPos (); - break; - } - buffer.ResetSelection (); - if (e.Control) - buffer.GotoWordEnd (); - else - MoveRight (); - break; - case Key.Up: - if (e.Shift) { - if (buffer.SelectionIsEmpty) - buffer.SetSelStartPos (); - PrintedCurrentLine--; - buffer.SetSelEndPos (); - break; - } - buffer.ResetSelection (); - PrintedCurrentLine--; - break; - case Key.Down: - if (e.Shift) { - if (buffer.SelectionIsEmpty) - buffer.SetSelStartPos (); - PrintedCurrentLine++; - buffer.SetSelEndPos (); - break; - } - buffer.ResetSelection (); - PrintedCurrentLine++; - break; - case Key.Menu: - break; - case Key.NumLock: - break; - case Key.PageDown: - if (e.Shift) { - if (buffer.SelectionIsEmpty) - buffer.SetSelStartPos (); - PrintedCurrentLine += visibleLines; - buffer.SetSelEndPos (); - break; - } - buffer.ResetSelection (); - PrintedCurrentLine += visibleLines; - break; - case Key.PageUp: - if (e.Shift) { - if (buffer.SelectionIsEmpty) - buffer.SetSelStartPos (); - PrintedCurrentLine -= visibleLines; - buffer.SetSelEndPos (); - break; - } - buffer.ResetSelection (); - PrintedCurrentLine -= visibleLines; - break; - case Key.RWin: - break; - case Key.Tab: - if (e.Shift) { - if (buffer.SelectionIsEmpty || - (buffer.SelectionStart.Y == buffer.SelectionEnd.Y)) { - //TODO - break; - } - for (int i = buffer.SelectionStart.Y; i <= buffer.SelectionEnd.Y; i++) - buffer.RemoveLeadingTab (i); - buffer.SetSelectionOnFullLines (); - } else { - if (buffer.SelectionIsEmpty || - (buffer.SelectionStart.Y == buffer.SelectionEnd.Y)) { - buffer.Insert ("\t"); - break; - } - for (int i = buffer.SelectionStart.Y; i <= buffer.SelectionEnd.Y; i++) { - buffer.UpdateLine (i, "\t" + buffer [i].Content); - } - } - - break; - case Key.F8: - toogleFolding (buffer.CurrentLine); - break; - default: - break; - } - RegisterForGraphicUpdate(); - } - public override void onKeyPress (object sender, KeyPressEventArgs e) - { - base.onKeyPress (sender, e); - - buffer.Insert (e.KeyChar.ToString()); - buffer.ResetSelection (); - } - #endregion - } -} \ No newline at end of file diff --git a/CrowIDE/src/Editors/CodeBuffer/TextBuffer.cs b/CrowIDE/src/Editors/CodeBuffer/TextBuffer.cs index a98aa08c..e8c87182 100644 --- a/CrowIDE/src/Editors/CodeBuffer/TextBuffer.cs +++ b/CrowIDE/src/Editors/CodeBuffer/TextBuffer.cs @@ -26,7 +26,7 @@ using System.Diagnostics; using System.Threading; using System.Text; -namespace Crow.Coding +namespace Crow.Text { /// /// Code buffer, lines are arranged in a List, new line chars are removed during string.split on '\n...', @@ -38,9 +38,9 @@ namespace Crow.Coding Regex reghexLineBrk = new Regex(@"\r\n|\r|\n|\\\n");//original text line break regex #region Events - public event EventHandler LineUpadateEvent; - public event EventHandler LineRemoveEvent; - public event EventHandler LineAdditionEvent; + public event EventHandler LineUpadateEvent; + public event EventHandler LineRemoveEvent; + public event EventHandler LineAdditionEvent; public event EventHandler BufferCleared; public event EventHandler SelectionChanged; public event EventHandler PositionChanged; @@ -137,7 +137,7 @@ namespace Crow.Coding buffer.Remove (GetBufferIndexOfLine (i), lineLength [i]); lineLength.RemoveAt (i); editMutex.ExitWriteLock (); - LineRemoveEvent.Raise (this, new CodeBufferEventArgs (i)); + LineRemoveEvent.Raise (this, new TextBufferEventArgs (i)); } /// /// insert string without linebreaks at position i in buff @@ -149,7 +149,7 @@ namespace Crow.Coding buffer.Insert (this [i], str); lineLength.Insert (i, str.Length); editMutex.ExitWriteLock (); - LineAdditionEvent.Raise (this, new CodeBufferEventArgs (i)); + LineAdditionEvent.Raise (this, new TextBufferEventArgs (i)); } public void AddLine(string str){ editMutex.EnterWriteLock (); @@ -159,7 +159,7 @@ namespace Crow.Coding lineLength.Add (0); } editMutex.ExitWriteLock (); - LineAdditionEvent.Raise (this, new CodeBufferEventArgs (lineLength.Count - 1)); + LineAdditionEvent.Raise (this, new TextBufferEventArgs (lineLength.Count - 1)); } public void AddRange (string[] items){ int start = lineLength.Count; @@ -167,7 +167,7 @@ namespace Crow.Coding for (int i = 0; i < items.Length; i++) AddLine (items [i]); editMutex.ExitWriteLock (); - LineAdditionEvent.Raise (this, new CodeBufferEventArgs (start, items.Length)); + LineAdditionEvent.Raise (this, new TextBufferEventArgs (start, items.Length)); } public void Clear () { editMutex.EnterWriteLock (); @@ -183,7 +183,7 @@ namespace Crow.Coding buffer.Insert (ptrL, newContent); lineLength [i] = newContent.Length; editMutex.ExitWriteLock (); - LineUpadateEvent.Raise (this, new CodeBufferEventArgs (i)); + LineUpadateEvent.Raise (this, new TextBufferEventArgs (i)); } public void AppenedLine(int i, string newContent){ editMutex.EnterWriteLock (); @@ -193,7 +193,7 @@ namespace Crow.Coding buffer.Insert(ptr, newContent); lineLength [i] += newContent.Length; editMutex.ExitWriteLock (); - LineUpadateEvent.Raise (this, new CodeBufferEventArgs (i)); + LineUpadateEvent.Raise (this, new TextBufferEventArgs (i)); } /// /// Insert new string at caret position, should be sure no line break is inside. diff --git a/CrowIDE/src/Editors/CodeBuffer/TextBufferEventArgs.cs b/CrowIDE/src/Editors/CodeBuffer/TextBufferEventArgs.cs new file mode 100644 index 00000000..3b67bb1c --- /dev/null +++ b/CrowIDE/src/Editors/CodeBuffer/TextBufferEventArgs.cs @@ -0,0 +1,20 @@ +using System; + +namespace Crow.Text +{ + public class TextBufferEventArgs : EventArgs { + public int LineStart; + public int LineCount; + + public TextBufferEventArgs(int lineNumber) { + LineStart = lineNumber; + LineCount = 1; + } + public TextBufferEventArgs(int lineStart, int lineCount) { + LineStart = lineStart; + LineCount = lineCount; + } + } + +} + diff --git a/CrowIDE/src/Editors/CodeBuffer/TextEditor.cs b/CrowIDE/src/Editors/CodeBuffer/TextEditor.cs index 69233e18..6b7234dc 100644 --- a/CrowIDE/src/Editors/CodeBuffer/TextEditor.cs +++ b/CrowIDE/src/Editors/CodeBuffer/TextEditor.cs @@ -37,12 +37,12 @@ using System.Diagnostics; using System.IO; using System.Threading; -namespace Crow.Coding +namespace Crow.Text { /// /// Scrolling text box optimized for monospace fonts, for coding /// - public class TextEditor : Editor + public class TextEditor : Crow.Coding.Editor { #region CTOR public TextEditor (): base() @@ -152,20 +152,20 @@ namespace Crow.Coding editorMutex.ExitWriteLock (); } - void Buffer_LineAdditionEvent (object sender, CodeBufferEventArgs e) + void Buffer_LineAdditionEvent (object sender, TextBufferEventArgs e) { updateMaxScrollY (); RegisterForGraphicUpdate (); isDirty = true; } - void Buffer_LineRemoveEvent (object sender, CodeBufferEventArgs e) + void Buffer_LineRemoveEvent (object sender, TextBufferEventArgs e) { updateMaxScrollY (); RegisterForGraphicUpdate (); notifyPositionChanged (); isDirty = true; } - void Buffer_LineUpadateEvent (object sender, CodeBufferEventArgs e) + void Buffer_LineUpadateEvent (object sender, TextBufferEventArgs e) { RegisterForGraphicUpdate (); notifyPositionChanged (); diff --git a/CrowIDE/src/Editors/ImlVisualEditor.cs b/CrowIDE/src/Editors/ImlVisualEditor.cs index 7a7a888b..76cb4009 100644 --- a/CrowIDE/src/Editors/ImlVisualEditor.cs +++ b/CrowIDE/src/Editors/ImlVisualEditor.cs @@ -28,6 +28,7 @@ using System.Collections.Generic; using Crow.IML; using System.Text; using System.Xml; +using System.Diagnostics; namespace Crow.Coding { @@ -46,7 +47,8 @@ namespace Crow.Coding Exception imlError = null; bool drawGrid, snapToGrid; - int gridSpacing; + int gridSpacing, zoom = 100; + Measure designWidth, designHeight; bool updateEnabled; [DefaultValue(true)] @@ -81,6 +83,42 @@ namespace Crow.Coding RegisterForRedraw (); } } + [DefaultValue(100)] + public int Zoom { + get { return zoom; } + set { + if (zoom == value) + return; + + zoom = value; + NotifyValueChanged ("Zoom", zoom); + Width = (int)(designWidth * zoom / 100.0); + Height = (int)(designHeight * zoom / 100.0); + } + } + [DefaultValue("512")] + public Measure DesignWidth { + get { return designWidth; } + set { + if (designWidth == value) + return; + designWidth = value; + NotifyValueChanged ("DesignWidth", designWidth); + Width = (int)(designWidth * zoom / 100.0); + } + } + [DefaultValue("512")] + public Measure DesignHeight { + get { return designHeight; } + set { + if (designHeight == value) + return; + designHeight = value; + NotifyValueChanged ("DesignHeight", designHeight); + Height = (int)(designHeight * zoom / 100.0); + } + } + public GraphicObject SelectedItem { get { return selectedItem; } set { @@ -149,6 +187,7 @@ namespace Crow.Coding protected override void updateProjFileFromEditor () { + Debug.WriteLine("\t\tImlEditor updateProjFileFromEditor"); try { projFile.UpdateSource(this, imlProjFile.Instance.GetIML()); } catch (Exception ex) { @@ -158,6 +197,7 @@ namespace Crow.Coding } } protected override void updateEditorFromProjFile () { + Debug.WriteLine("\t\tImlEditor updateEditorFromProjFile"); try { string selItemDesignID = null; if (SelectedItem!=null) @@ -196,7 +236,7 @@ namespace Crow.Coding } SelectedItem = go; } catch (Exception ex) { - Error = ex.InnerException; + Error = ex; if (Monitor.IsEntered(imlVE.UpdateMutex)) Monitor.Exit (imlVE.UpdateMutex); } @@ -223,11 +263,10 @@ namespace Crow.Coding switch (layoutType) { case LayoutingType.Width: case LayoutingType.Height: - imlVE.ProcessResize (this.ClientRectangle.Size); + imlVE.ProcessResize (new Size(designWidth,designHeight)); break; } } - public override void onMouseMove (object sender, MouseMoveEventArgs e) { base.onMouseMove (sender, e); @@ -264,29 +303,38 @@ namespace Crow.Coding protected override void onDraw (Cairo.Context gr) { base.onDraw (gr); - if (!drawGrid) - return; + Rectangle cb = new Rectangle (0, 0, designWidth, designHeight);// ClientRectangle; - Rectangle cb = ClientRectangle; - const double gridLineWidth = 0.1; - double glhw = gridLineWidth / 2.0; - int nbLines = cb.Width / gridSpacing ; - double d = cb.Left + gridSpacing; - for (int i = 0; i < nbLines; i++) { - gr.MoveTo (d-glhw, cb.Y); - gr.LineTo (d-glhw, cb.Bottom); - d += gridSpacing; - } - nbLines = cb.Height / gridSpacing; - d = cb.Top + gridSpacing; - for (int i = 0; i < nbLines; i++) { - gr.MoveTo (cb.X, d - glhw); - gr.LineTo (cb.Right, d -glhw); - d += gridSpacing; + gr.Save (); + + double z = zoom / 100.0; + + gr.Scale (z, z); + + if (drawGrid) { + double gridLineWidth = 0.2 / z; + double glhw = gridLineWidth / 2.0; + int nbLines = cb.Width / gridSpacing; + double d = cb.Left + gridSpacing; + for (int i = 0; i < nbLines; i++) { + gr.MoveTo (d - glhw, cb.Y); + gr.LineTo (d - glhw, cb.Bottom); + d += gridSpacing; + } + nbLines = cb.Height / gridSpacing; + d = cb.Top + gridSpacing; + for (int i = 0; i < nbLines; i++) { + gr.MoveTo (cb.X, d - glhw); + gr.LineTo (cb.Right, d - glhw); + d += gridSpacing; + } + gr.LineWidth = gridLineWidth; + Foreground.SetAsSource (gr, cb); + gr.Stroke (); } - gr.LineWidth = gridLineWidth; - Foreground.SetAsSource (gr, cb); + gr.SetSourceColor (Color.Black); + gr.Rectangle (cb, 1.0 / z); gr.Stroke (); lock (imlVE.RenderMutex) { @@ -310,14 +358,16 @@ namespace Crow.Coding gr.Rectangle (hr, 1.0); } - if (SelectedItem?.Parent == null) - return; - hr = SelectedItem.ScreenCoordinates(SelectedItem.getSlot ()); - hr.Inflate (1); - gr.LineWidth = 2; - gr.SetSourceColor (Color.Yellow); - gr.SetDash (new double[]{ 5.0, 3.0 },0.0); - gr.Rectangle (hr, 1.0); + if (SelectedItem?.Parent != null) { + + hr = SelectedItem.ScreenCoordinates (SelectedItem.getSlot ()); + hr.Inflate (1); + gr.LineWidth = 2; + gr.SetSourceColor (Color.Yellow); + gr.SetDash (new double[]{ 5.0, 3.0 }, 0.0); + gr.Rectangle (hr, 1.0); + } + gr.Restore (); } protected override void onDragEnter (object sender, DragDropEventArgs e) @@ -436,6 +486,7 @@ namespace Crow.Coding } void WidgetMouseMove (GraphicObject go, MouseMoveEventArgs e){} + public bool ProcessMouseMove(int x, int y) { int deltaX = x - imlVE.Mouse.X; @@ -459,22 +510,21 @@ namespace Crow.Coding GraphicObject topc = null; while (tmp is GraphicObject) { topc = tmp; - tmp = tmp.LogicalParent as GraphicObject; + tmp = tmp.focusParent; } int idxhw = imlVE.GraphicTree.IndexOf (topc); if (idxhw != 0) { int i = 0; - while (i < idxhw) { - if (imlVE.GraphicTree [i].LogicalParent == imlVE.GraphicTree [i].Parent) { - if (imlVE.GraphicTree [i].MouseIsIn (e.Position)) { - while (imlVE.HoverWidget != null) { - WidgetMouseLeave (imlVE.HoverWidget, e); - imlVE.HoverWidget = imlVE.HoverWidget.LogicalParent as GraphicObject; - } - - WidgetCheckOver (GraphicTree [i], e); - return true; + while (i < idxhw) { + if (GraphicTree [i].MouseIsIn (e.Position)) { + while (HoverWidget != null) { + WidgetMouseLeave (imlVE.HoverWidget, e); + HoverWidget = HoverWidget.focusParent; } + + GraphicTree [i].checkHoverWidget (e); + WidgetMouseMove (imlVE.HoverWidget, e); + return true; } i++; } @@ -483,14 +533,16 @@ namespace Crow.Coding if (imlVE.HoverWidget.MouseIsIn (e.Position)) { WidgetCheckOver (imlVE.HoverWidget, (e)); + WidgetMouseMove (imlVE.HoverWidget, e); return true; } else { WidgetMouseLeave (imlVE.HoverWidget, e); //seek upward from last focused graph obj's - while (imlVE.HoverWidget.LogicalParent as GraphicObject != null) { + while (imlVE.HoverWidget.focusParent != null) { imlVE.HoverWidget = imlVE.HoverWidget.LogicalParent as GraphicObject; if (imlVE.HoverWidget.MouseIsIn (e.Position)) { WidgetCheckOver (imlVE.HoverWidget, e); + WidgetMouseMove (imlVE.HoverWidget, e); return true; } else WidgetMouseLeave (imlVE.HoverWidget, e); @@ -504,6 +556,7 @@ namespace Crow.Coding GraphicObject g = imlVE.GraphicTree [i]; if (g.MouseIsIn (e.Position)) { WidgetCheckOver (g, e); + WidgetMouseMove (imlVE.HoverWidget, e); return true; } } diff --git a/CrowIDE/src/Editors/Parsers/BufferParser.cs b/CrowIDE/src/Editors/Parsers/BufferParser.cs index dfec17a3..c193c7db 100644 --- a/CrowIDE/src/Editors/Parsers/BufferParser.cs +++ b/CrowIDE/src/Editors/Parsers/BufferParser.cs @@ -266,7 +266,7 @@ namespace Crow.Coding /// Length. protected virtual string Peek(int length) { if (eol) - throw new ParserException (currentLine, currentColumn, "Unexpected End of Line"); + return "";//throw new ParserException (currentLine, currentColumn, "Unexpected End of Line"); int lg = Math.Min(length, Math.Max (buffer [currentLine].Length - currentColumn, buffer [currentLine].Length - currentColumn - length)); if (lg == 0) return ""; diff --git a/CrowIDE/src/Editors/Parsers2/Tokenizer.cs b/CrowIDE/src/Editors/Parsers2/Tokenizer.cs new file mode 100644 index 00000000..bcda1ec6 --- /dev/null +++ b/CrowIDE/src/Editors/Parsers2/Tokenizer.cs @@ -0,0 +1,67 @@ +// +// Tokenizer.cs +// +// Author: +// Jean-Philippe Bruyère +// +// 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.Text; +using System.Collections.Generic; +using System.Text.RegularExpressions; + +namespace Crow.Coding2 +{ + public static class TokenType { + public const int Undefine = 0; + public const int WhiteSpace = 0; + } + public class Token { + public int ptr; + public int length; + } + + public class Tokenizer + { + #region Regular Expression for validity checks + public Regex rxValidChar = new Regex(@"\p{Lu}|\p{Ll}|\p{Lt}|\p{Lm}|\p{Lo}|\p{Nl}|\p{Mn}|\p{Mc}|\p{Nd}|\p{Pc}|\p{Cf}"); + public Regex rxNameStartChar = new Regex(@"_|\p{Lu}|\p{Ll}|\p{Lt}|\p{Lm}|\p{Lo}|\p{Nl}"); + public Regex rxNameChar = new Regex(@"\p{Lu}|\p{Ll}|\p{Lt}|\p{Lm}|\p{Lo}|\p{Nl}|\p{Mn}|\p{Mc}|\p{Nd}|\p{Pc}|\p{Cf}"); + public Regex rxNewLineChar = new Regex(@"\u000D|\u000A|\u0085|\u2028|\u2029"); + public Regex rxWhiteSpaceChar = new Regex(@"\p{Zs}|\u0009|\u000B|\u000C"); + public Regex rxDecimal = new Regex(@"[0-9]+"); + public Regex rxHexadecimal = new Regex(@"[0-9a-fA-F]+"); + #endregion + + public List Tokens; + + public Tokenizer (TextBuffer buffer) + { + } + + + public void Tokenize () { + + } + + } +} + diff --git a/CrowIDE/src/Editors/SourceEditor.cs b/CrowIDE/src/Editors/SourceEditor.cs new file mode 100644 index 00000000..6ebe2c1f --- /dev/null +++ b/CrowIDE/src/Editors/SourceEditor.cs @@ -0,0 +1,1210 @@ +// +// ScrollingTextBox.cs +// +// Author: +// Jean-Philippe Bruyère +// +// 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 Cairo; +using System.Text; +using System.Collections.Generic; +using System.Text.RegularExpressions; +using System.Linq; +using System.Diagnostics; +using System.IO; +using System.Threading; + +namespace Crow.Coding +{ + /// + /// Scrolling text box optimized for monospace fonts, for coding + /// + public class SourceEditor : Editor + { + #region CTOR + public SourceEditor (): base() + { + formatting.Add ((int)XMLParser.TokenType.AttributeName, new TextFormatting (Color.DarkSlateGray, Color.Transparent)); + formatting.Add ((int)XMLParser.TokenType.ElementName, new TextFormatting (Color.DarkBlue, Color.Transparent)); + formatting.Add ((int)XMLParser.TokenType.ElementStart, new TextFormatting (Color.Black, Color.Transparent)); + formatting.Add ((int)XMLParser.TokenType.ElementEnd, new TextFormatting (Color.Black, Color.Transparent)); + formatting.Add ((int)XMLParser.TokenType.ElementClosing, new TextFormatting (Color.Black, Color.Transparent)); + + formatting.Add ((int)XMLParser.TokenType.AttributeValueOpening, new TextFormatting (Color.Crimson, Color.Transparent)); + formatting.Add ((int)XMLParser.TokenType.AttributeValueClosing, new TextFormatting (Color.Crimson, Color.Transparent)); + formatting.Add ((int)XMLParser.TokenType.AttributeValue, new TextFormatting (Color.FireBrick, Color.Transparent, false, true)); + formatting.Add ((int)XMLParser.TokenType.XMLDecl, new TextFormatting (Color.ForestGreen, Color.Transparent)); + + formatting.Add ((int)BufferParser.TokenType.BlockComment, new TextFormatting (Color.Gray, Color.Transparent, false, true)); + formatting.Add ((int)BufferParser.TokenType.LineComment, new TextFormatting (Color.Gray, Color.Transparent, false, true)); + formatting.Add ((int)BufferParser.TokenType.OperatorOrPunctuation, new TextFormatting (Color.Black, Color.Transparent)); + formatting.Add ((int)BufferParser.TokenType.Keyword, new TextFormatting (Color.Teal, Color.Transparent)); + //formatting.Add ((int)BufferParser.TokenType.Keyword, new TextFormatting (Color.DarkCyan, Color.Transparent)); + + parsing.Add (".crow", "Crow.Coding.XMLParser"); + parsing.Add (".svg", "Crow.Coding.XMLParser"); + parsing.Add (".template", "Crow.Coding.XMLParser"); + parsing.Add (".cs", "Crow.Coding.CSharpParser"); + parsing.Add (".style", "Crow.Coding.StyleParser"); + + buffer = new CodeBuffer (); + buffer.LineUpadateEvent += Buffer_LineUpadateEvent; + buffer.LineAdditionEvent += Buffer_LineAdditionEvent;; + buffer.LineRemoveEvent += Buffer_LineRemoveEvent; + buffer.BufferCleared += Buffer_BufferCleared; + buffer.SelectionChanged += Buffer_SelectionChanged; + buffer.PositionChanged += Buffer_PositionChanged; + buffer.FoldingEvent += Buffer_FoldingEvent; + buffer.Add (new CodeLine("")); + } + #endregion + + string oldSource = ""; + //save requested position on error, and try it on next move + int requestedLine = 0, requestedCol = 0; + volatile bool isDirty = false; + + const int leftMarginGap = 10;//gap between items in margin and text + const int foldSize = 9;//folding rectangles size + const int foldHSpace = 4;//folding level tabulation x + int foldMargin { get { return parser == null ? 0 : parser.SyntacticTreeMaxDepth * foldHSpace; }}//folding margin size + + #region private and protected fields + bool foldingEnabled = true; + int leftMargin = 0; //margin used to display line numbers, folding errors,etc... + int visibleLines = 1; + int visibleColumns = 1; + int firstPrintedLine = -1; + int printedCurrentLine = 0;//Index of the currentline in the PrintedLines array + + CodeBuffer buffer; + BufferParser parser; + List PrintedLines;//list of lines visible in the Editor depending on scrolling and folding + + Dictionary formatting = new Dictionary(); + Dictionary parsing = new Dictionary(); + + Color selBackground; + Color selForeground; + int selStartCol; + int selEndCol; + + protected Rectangle rText; + protected FontExtents fe; + protected TextExtents te; + + Point mouseLocalPos; + bool doubleClicked = false; + #endregion + + void measureLeftMargin () { + leftMargin = 0; + if (PrintLineNumbers) + leftMargin += (int)Math.Ceiling((double)buffer.LineCount.ToString().Length * fe.MaxXAdvance) +6; + if (foldingEnabled) + leftMargin += foldMargin; + if (leftMargin > 0) + leftMargin += leftMarginGap; + updateVisibleColumns (); + } + void findLongestLineAndUpdateMaxScrollX() { + buffer.FindLongestVisualLine (); + updateMaxScrollX (); +// Debug.WriteLine ("SourceEditor: Find Longest line and update maxscrollx: {0} visible cols:{1}", MaxScrollX, visibleColumns); + } + /// + /// Updates visible line in widget, adapt max scroll y and updatePrintedLines + /// + void updateVisibleLines(){ + visibleLines = (int)Math.Floor ((double)ClientRectangle.Height / (fe.Ascent+fe.Descent)); + NotifyValueChanged ("VisibleLines", visibleLines); + updateMaxScrollY (); + updatePrintedLines (); + RegisterForGraphicUpdate (); +// System.Diagnostics.Debug.WriteLine ("update visible lines: " + visibleLines); +// System.Diagnostics.Debug.WriteLine ("update MaxScrollY: " + MaxScrollY); + } + void updateVisibleColumns(){ + visibleColumns = (int)Math.Floor ((double)(ClientRectangle.Width - leftMargin)/ fe.MaxXAdvance); + NotifyValueChanged ("VisibleColumns", visibleColumns); + updateMaxScrollX (); +// System.Diagnostics.Debug.WriteLine ("update visible columns: {0} leftMargin:{1}",visibleColumns, leftMargin); +// System.Diagnostics.Debug.WriteLine ("update MaxScrollX: " + MaxScrollX); + } + void updateMaxScrollX () { + MaxScrollX = Math.Max (0, buffer.longestLineCharCount - visibleColumns); + if (buffer.longestLineCharCount > 0) + NotifyValueChanged ("ChildWidthRatio", Slot.Width * visibleColumns / buffer.longestLineCharCount); + } + void updateMaxScrollY () { + if (parser == null || !foldingEnabled) { + MaxScrollY = Math.Max (0, buffer.LineCount - visibleLines); + if (buffer.UnfoldedLines > 0) + NotifyValueChanged ("ChildHeightRatio", Slot.Height * visibleLines / buffer.UnfoldedLines); + } else { + MaxScrollY = Math.Max (0, buffer.UnfoldedLines - visibleLines); + if (buffer.UnfoldedLines > 0) + NotifyValueChanged ("ChildHeightRatio", Slot.Height * visibleLines / buffer.UnfoldedLines); + } + } + void updatePrintedLines () { + buffer.editMutex.EnterReadLock (); + editorMutex.EnterWriteLock (); + + PrintedLines = new List (); + int curL = 0; + int i = 0; + + while (curL < buffer.LineCount && i < ScrollY) { + if (buffer [curL].IsFolded) + curL = buffer.GetEndNodeIndex (curL); + curL++; + i++; + } + + firstPrintedLine = curL; + i = 0; + while (i < visibleLines && curL < buffer.LineCount) { + PrintedLines.Add (buffer [curL]); + + if (buffer [curL].IsFolded) + curL = buffer.GetEndNodeIndex (curL); + + curL++; + i++; + } + + buffer.editMutex.ExitReadLock (); + editorMutex.ExitWriteLock (); + } + void updateOnScreenCurLineFromBuffCurLine(){ + printedCurrentLine = PrintedLines.IndexOf (buffer.CurrentCodeLine); + } + void toogleFolding (int line) { + if (parser == null || !foldingEnabled) + return; + buffer.ToogleFolding (line); + } + + #region Editor overrides + protected override void updateEditorFromProjFile () + { + Debug.WriteLine("\t\tSourceEditor updateEditorFromProjFile"); + + buffer.editMutex.EnterWriteLock (); + loadSource (); + buffer.editMutex.ExitWriteLock (); + + isDirty = false; + oldSource = projFile.Source; + CurrentLine = requestedLine; + CurrentColumn = requestedCol; + projFile.RegisteredEditors [this] = true; + } + protected override void updateProjFileFromEditor () + { + Debug.WriteLine("\t\tSourceEditor updateProjFileFromEditor"); + + buffer.editMutex.EnterWriteLock (); + string newsrc = buffer.FullText; + buffer.editMutex.ExitWriteLock (); + projFile.UpdateSource (this, newsrc); + } + protected override bool EditorIsDirty { + get { return isDirty; } + set { isDirty = value; } + } + protected override bool IsReady { + get { return projFile != null && buffer != null; } + } + #endregion + + #region Buffer events handlers + void Buffer_BufferCleared (object sender, EventArgs e) + { + editorMutex.EnterWriteLock (); + + buffer.longestLineCharCount = 0; + buffer.longestLineIdx = 0; + measureLeftMargin (); + MaxScrollX = MaxScrollY = 0; + PrintedLines = null; + RegisterForGraphicUpdate (); + notifyPositionChanged (); + isDirty = true; + + editorMutex.ExitWriteLock (); + } + void Buffer_LineAdditionEvent (object sender, CodeBufferEventArgs e) + { + for (int i = 0; i < e.LineCount; i++) { + int lptr = e.LineStart + i; + int charCount = buffer[lptr].PrintableLength; + if (charCount > buffer.longestLineCharCount) { + buffer.longestLineIdx = lptr; + buffer.longestLineCharCount = charCount; + }else if (lptr <= buffer.longestLineIdx) + buffer.longestLineIdx++; + if (parser == null) + continue; + parser.TryParseBufferLine (e.LineStart + i); + } + + if (parser != null) + parser.reparseSource (); + + measureLeftMargin (); + + updatePrintedLines (); + updateMaxScrollY (); + RegisterForGraphicUpdate (); + notifyPositionChanged (); + isDirty = true; + } + void Buffer_LineRemoveEvent (object sender, CodeBufferEventArgs e) + { + bool trigFindLongestLine = false; + for (int i = 0; i < e.LineCount; i++) { + int lptr = e.LineStart + i; + if (lptr <= buffer.longestLineIdx) + trigFindLongestLine = true; + } + if (trigFindLongestLine) + findLongestLineAndUpdateMaxScrollX (); + + measureLeftMargin (); + updatePrintedLines (); + updateMaxScrollY (); + RegisterForGraphicUpdate (); + notifyPositionChanged (); + isDirty = true; + } + void Buffer_LineUpadateEvent (object sender, CodeBufferEventArgs e) + { + bool trigFindLongestLine = false; + for (int i = 0; i < e.LineCount; i++) { + + int lptr = e.LineStart + i; + if (lptr == buffer.longestLineIdx) + trigFindLongestLine = true; + else if (buffer[lptr].PrintableLength > buffer.longestLineCharCount) { + buffer.longestLineCharCount = buffer[lptr].PrintableLength; + buffer.longestLineIdx = lptr; + } + } + if (trigFindLongestLine) + findLongestLineAndUpdateMaxScrollX (); + + RegisterForGraphicUpdate (); + notifyPositionChanged (); + isDirty = true; + } + void Buffer_PositionChanged (object sender, EventArgs e) + { + Console.WriteLine ("Position changes: ({0},{1})", buffer.CurrentLine, buffer.CurrentColumn); + int cc = buffer.CurrentTabulatedColumn; + + if (cc > visibleColumns + ScrollX) { + ScrollX = cc - visibleColumns; + } else if (cc < ScrollX) + ScrollX = cc; + + RegisterForGraphicUpdate (); + updateOnScreenCurLineFromBuffCurLine (); + notifyPositionChanged (); + } + + void Buffer_SelectionChanged (object sender, EventArgs e) + { + RegisterForGraphicUpdate (); + } + void Buffer_FoldingEvent (object sender, CodeBufferEventArgs e) + { + updatePrintedLines (); + updateOnScreenCurLineFromBuffCurLine (); + updateMaxScrollY (); + RegisterForGraphicUpdate (); + } + #endregion + + void notifyPositionChanged (){ + try { + NotifyValueChanged ("CurrentLine", buffer.CurrentLine+1); + NotifyValueChanged ("CurrentColumn", buffer.CurrentColumn+1); + NotifyValueChanged ("CurrentLineHasError", CurrentLineHasError); + NotifyValueChanged ("CurrentLineError", CurrentLineError); + } catch (Exception ex) { + Console.WriteLine (ex.ToString ()); + } + } + + #region Public Crow Properties + public int CurrentLine{ + get { return buffer == null ? 0 : buffer.CurrentLine+1; } + set { + try { + int l = value - 1; + if (l == buffer.CurrentLine) + return; + buffer.CurrentLine = l; + if ((bool)buffer [l]?.IsFolded) + buffer.ToogleFolding (l); + } catch (Exception ex) { + requestedLine = value - 1; + Console.WriteLine ("Error cur column: " + ex.ToString ()); + } + } + } + public int CurrentColumn{ + get { return buffer == null ? 0 : buffer.CurrentColumn+1; } + set { + try { + if (value - 1 == buffer.CurrentColumn) + return; + buffer.CurrentColumn = value - 1; + } catch (Exception ex) { + requestedCol = value - 1; + Console.WriteLine ("Error cur column: " + ex.ToString ()); + } + } + } + public bool PrintLineNumbers + { + get { return Configuration.Global.Get ("PrintLineNumbers"); } + set { + if (PrintLineNumbers == value) + return; + Configuration.Global.Set ("PrintLineNumbers", value); + NotifyValueChanged ("PrintLineNumbers", PrintLineNumbers); + measureLeftMargin (); + RegisterForGraphicUpdate (); + } + } + [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 (); + } + } + public override int ScrollY { + get { + return base.ScrollY; + } + set { + if (value == base.ScrollY) + return; + base.ScrollY = value; + updatePrintedLines (); + updateOnScreenCurLineFromBuffCurLine (); + RegisterForGraphicUpdate (); + } + } + public ParserException CurrentLineError { + get { return buffer?.CurrentCodeLine?.exception; } + } + public bool CurrentLineHasError { + get { return buffer == null ? false : buffer.CurrentCodeLine == null ? false : + buffer.CurrentCodeLine.exception != null; } + } + public override ProjectFile ProjectNode { + get { + return base.ProjectNode; + } + set { + base.ProjectNode = value; + if (projFile != null) + parser = getParserFromExt (System.IO.Path.GetExtension (projFile.Extension)); + } + } + #endregion + + BufferParser getParserFromExt (string extension) { + if (string.IsNullOrEmpty(extension)) + return null; + if (!parsing.ContainsKey(extension)) + return null; + Type parserType = Type.GetType (parsing [extension]); + if (parserType == null) + return null; + return (BufferParser)Activator.CreateInstance (parserType, buffer ); + } + void loadSource () { + + try { + + if (parser == null) + buffer.Load (projFile.Source); + else//parser may have special linebrk rules + buffer.Load (projFile.Source, parser.LineBrkRegex); + + } catch (Exception ex) { + Debug.WriteLine (ex.ToString ()); + } + + projFile.RegisteredEditors [this] = true; + + updateMaxScrollY (); + MaxScrollX = Math.Max (0, buffer.longestLineCharCount - visibleColumns); + updatePrintedLines (); + + RegisterForGraphicUpdate (); + } + + /// + /// Current editor line, when set, update buffer.CurrentLine + /// + int PrintedCurrentLine { + get { return printedCurrentLine;} + set { + if (value < 0) { + ScrollY += value; + printedCurrentLine = 0; + } else if (PrintedLines.Count < visibleLines && value >= PrintedLines.Count) { + printedCurrentLine = PrintedLines.Count - 1; + }else if (value >= visibleLines) { + ScrollY += value - visibleLines + 1; + printedCurrentLine = visibleLines - 1; + }else + printedCurrentLine = value; + //Debug.WriteLine ("printed current line:" + printedCurrentLine.ToString ()); + //update position in buffer + buffer.CurrentLine = buffer.IndexOf (PrintedLines[printedCurrentLine]); + } + } + int getTabulatedColumn (int col, int line) { + return buffer [line].Content.Substring (0, col).Replace ("\t", new String (' ', Interface.TabSize)).Length; + } + int getTabulatedColumn (Point pos) { + return getTabulatedColumn (pos.X,pos.Y); + } + /// + /// Moves cursor one char to the left, move up if cursor reaches start of line + /// + /// true if move succeed + public bool MoveLeft(){ + if (buffer.CurrentColumn == 0) { + if (printedCurrentLine == 0) + return false; + PrintedCurrentLine--; + buffer.CurrentColumn = int.MaxValue; + } else + buffer.CurrentColumn--; + return true; + } + /// + /// Moves cursor one char to the right, move down if cursor reaches end of line + /// + /// true if move succeed + public bool MoveRight(){ + if (buffer.CurrentColumn >= buffer.CurrentCodeLine.Length) { + if (PrintedCurrentLine == buffer.UnfoldedLines - 1) + return false; + buffer.CurrentColumn = 0; + PrintedCurrentLine++; + } else + buffer.CurrentColumn++; + return true; + } + + #region Drawing + void drawLine(Context gr, Rectangle cb, int i) { + CodeLine cl = PrintedLines[i]; + int lineIndex = buffer.IndexOf(cl); + + double y = cb.Y + (fe.Ascent+fe.Descent) * i, x = cb.X; + + //Draw line numbering + Color mgFg = Color.Gray; + Color mgBg = Color.White; + if (PrintLineNumbers){ + Rectangle mgR = new Rectangle ((int)x, (int)y, leftMargin - leftMarginGap, (int)Math.Ceiling((fe.Ascent+fe.Descent))); + if (cl.exception != null) { + mgBg = Color.Red; + if (buffer.CurrentLine == lineIndex) + mgFg = Color.White; + else + mgFg = Color.LightGray; + }else if (buffer.CurrentLine == lineIndex) { + mgFg = Color.Black; + mgBg = Color.DarkGray; + } + string strLN = (lineIndex+1).ToString (); + gr.SetSourceColor (mgBg); + gr.Rectangle (mgR); + gr.Fill(); + gr.SetSourceColor (mgFg); + + gr.MoveTo (cb.X + (int)(gr.TextExtents (buffer.LineCount.ToString()).Width - gr.TextExtents (strLN).Width), y + fe.Ascent); + gr.ShowText (strLN); + gr.Fill (); + } + + + + //draw folding + if (foldingEnabled){ + + Rectangle rFld = new Rectangle (cb.X + leftMargin - leftMarginGap - foldMargin, + (int)(y + (fe.Ascent + fe.Descent) / 2.0 - foldSize / 2.0), foldSize, foldSize); + + gr.SetSourceColor (Color.Black); + gr.LineWidth = 1.0; + + int level = 0; + bool closingNode = false; + + if (currentNode != null) { + if (cl == currentNode.EndLine) { + currentNode = currentNode.Parent; + closingNode = true; + } + if (currentNode != null) + level = currentNode.Level - 1; + } + + for (int l = 0; l < level; l++) { + gr.MoveTo (rFld.Center.X + 0.5, y); + gr.LineTo (rFld.Center.X + 0.5, y + fe.Ascent + fe.Descent); + rFld.Left += foldHSpace; + } + if (closingNode) { + gr.MoveTo (rFld.Center.X + 0.5, y); + gr.LineTo (rFld.Center.X + 0.5, y + fe.Ascent / 2 + 0.5); + gr.LineTo (rFld.Center.X + 0.5 + foldSize / 2, y + fe.Ascent / 2 + 0.5); + closingNode = false; + } + gr.SetDash (new double[]{ 1.5 },0.0); + gr.SetSourceColor (Color.Gray); + gr.Stroke (); + gr.SetDash (new double[]{}, 0.0); + + if (cl.IsFoldable) { + gr.Rectangle (rFld); + gr.SetSourceColor (Color.White); + gr.Fill(); + gr.SetSourceColor (Color.Black); + gr.Rectangle (rFld, 1.0); + if (cl.IsFolded) { + gr.MoveTo (rFld.Center.X + 0.5, rFld.Y + 2); + gr.LineTo (rFld.Center.X + 0.5, rFld.Bottom - 2); + }else + currentNode = cl.SyntacticNode; + + gr.MoveTo (rFld.Left + 2, rFld.Center.Y + 0.5); + gr.LineTo (rFld.Right - 2, rFld.Center.Y + 0.5); + gr.Stroke (); + } + } + + gr.SetSourceColor (Foreground); + x += leftMargin; + + if (cl.Tokens == null) + drawRawCodeLine (gr, x, y, i, lineIndex); + else + drawParsedCodeLine (gr, x, y, i, lineIndex); + } + Node currentNode = null; +// void drawParsed(Context gr){ +// if (PrintedLines == null) +// return; +// +// gr.SelectFontFace (Font.Name, Font.Slant, Font.Wheight); +// gr.SetFontSize (Font.Size); +// gr.FontOptions = Interface.FontRenderingOptions; +// gr.Antialias = Interface.Antialias; +// +// Rectangle cb = ClientRectangle; +// gr.Save (); +// CairoHelpers.CairoRectangle (gr, cb, CornerRadius); +// gr.Clip (); +// +// bool selectionInProgress = false; +// +// Foreground.SetAsSource (gr); +// +// #region draw text cursor +// if (SelBegin != SelRelease) +// selectionInProgress = true; +// else if (HasFocus){ +// gr.LineWidth = 1.0; +// double cursorX = + leftMargin + cb.X + (CurrentColumn - ScrollX) * fe.MaxXAdvance; +// gr.MoveTo (0.5 + cursorX, cb.Y + printedCurrentLine * (fe.Ascent+fe.Descent)); +// gr.LineTo (0.5 + cursorX, cb.Y + (printedCurrentLine + 1) * (fe.Ascent+fe.Descent)); +// gr.Stroke(); +// } +// #endregion +// +// for (int i = 0; i < PrintedLines.Count; i++) +// drawTokenLine (gr, i, selectionInProgress, cb); +// +// gr.Restore (); +// } + void drawRawCodeLine(Context gr, double x, double y, int i, int lineIndex) { + string lstr = buffer[lineIndex].PrintableContent; + if (ScrollX < lstr.Length) + lstr = lstr.Substring (ScrollX); + else + lstr = ""; + + gr.MoveTo (x, y + fe.Ascent); + gr.ShowText (lstr); + gr.Fill (); + + if (!buffer.SelectionIsEmpty && lineIndex >= buffer.SelectionStart.Y && lineIndex <= buffer.SelectionEnd.Y) { + double rLineX = x, + rLineY = y, + rLineW = lstr.Length * fe.MaxXAdvance; + + //System.Diagnostics.Debug.WriteLine ("sel start: " + buffer.SelectionStart + " sel end: " + buffer.SelectionEnd); + if (lineIndex == buffer.SelectionStart.Y) { + rLineX += (selStartCol - ScrollX) * fe.MaxXAdvance; + rLineW -= selStartCol * fe.MaxXAdvance; + } + if (lineIndex == buffer.SelectionEnd.Y) + rLineW -= (lstr.Length - selEndCol) * fe.MaxXAdvance; + + gr.Save (); + gr.Operator = Operator.Source; + gr.Rectangle (rLineX, rLineY, rLineW, (fe.Ascent+fe.Descent)); + gr.SetSourceColor (SelectionBackground); + gr.FillPreserve (); + gr.Clip (); + gr.Operator = Operator.Over; + gr.SetSourceColor (SelectionForeground); + gr.MoveTo (x, y + fe.Ascent); + gr.ShowText (lstr); + gr.Fill (); + gr.Restore (); + } + } + void drawParsedCodeLine (Context gr, double x, double y, int i, int lineIndex) { + int lPtr = 0; + CodeLine cl = PrintedLines[i]; + + for (int t = 0; t < cl.Tokens.Count; t++) { + string lstr = cl.Tokens [t].PrintableContent; + if (lPtr < ScrollX) { + if (lPtr - ScrollX + lstr.Length <= 0) { + lPtr += lstr.Length; + continue; + } + lstr = lstr.Substring (ScrollX - lPtr); + lPtr += ScrollX - lPtr; + } + Color bg = this.Background; + Color fg = this.Foreground; + Color selbg = this.SelectionBackground; + Color selfg = this.SelectionForeground; + FontSlant fts = FontSlant.Normal; + FontWeight ftw = FontWeight.Normal; + + if (formatting.ContainsKey ((int)cl.Tokens [t].Type)) { + TextFormatting tf = formatting [(int)cl.Tokens [t].Type]; + bg = tf.Background; + fg = tf.Foreground; + if (tf.Bold) + ftw = FontWeight.Bold; + if (tf.Italic) + fts = FontSlant.Italic; + } + + gr.SelectFontFace (Font.Name, fts, ftw); + gr.SetSourceColor (fg); + + gr.MoveTo (x, y + fe.Ascent); + gr.ShowText (lstr); + gr.Fill (); + + if (buffer.SelectionInProgress && lineIndex >= buffer.SelectionStart.Y && lineIndex <= buffer.SelectionEnd.Y && + !(lineIndex == buffer.SelectionStart.Y && lPtr + lstr.Length <= selStartCol) && + !(lineIndex == buffer.SelectionEnd.Y && selEndCol <= lPtr)) { + + double rLineX = x, + rLineY = y, + rLineW = lstr.Length * fe.MaxXAdvance; + double startAdjust = 0.0; + + if ((lineIndex == buffer.SelectionStart.Y) && (selStartCol < lPtr + lstr.Length) && (selStartCol > lPtr)) + startAdjust = (selStartCol - lPtr) * fe.MaxXAdvance; + rLineX += startAdjust; + if ((lineIndex == buffer.SelectionEnd.Y) && (selEndCol < lPtr + lstr.Length)) + rLineW = (selEndCol - lPtr) * fe.MaxXAdvance; + rLineW -= startAdjust; + + gr.Save (); + gr.Operator = Operator.Source; + gr.Rectangle (rLineX, rLineY, rLineW, (fe.Ascent+fe.Descent)); + gr.SetSourceColor (selbg); + gr.FillPreserve (); + gr.Clip (); + gr.Operator = Operator.Over; + gr.SetSourceColor (selfg); + gr.MoveTo (x, y + fe.Ascent); + gr.ShowText (lstr); + gr.Fill (); + gr.Restore (); + } + x += (int)lstr.Length * fe.MaxXAdvance; + lPtr += lstr.Length; + } + } + + #endregion + + #region GraphicObject overrides + public override Font Font { + get { return base.Font; } + set { + base.Font = value; + + using (ImageSurface img = new ImageSurface (Format.Argb32, 1, 1)) { + using (Context gr = new Context (img)) { + gr.SelectFontFace (Font.Name, Font.Slant, Font.Wheight); + gr.SetFontSize (Font.Size); + + fe = gr.FontExtents; + } + } + MaxScrollY = 0; + RegisterForGraphicUpdate (); + } + } + protected override int measureRawSize(LayoutingType lt) + { + if (lt == LayoutingType.Height) + return (int)Math.Ceiling((fe.Ascent+fe.Descent) * buffer.LineCount) + Margin * 2; + + return (int)(fe.MaxXAdvance * buffer.longestLineCharCount) + Margin * 2 + leftMargin; + } + public override void OnLayoutChanges (LayoutingType layoutType) + { + base.OnLayoutChanges (layoutType); + + if (layoutType == LayoutingType.Height) + updateVisibleLines (); + else if (layoutType == LayoutingType.Width) + updateVisibleColumns (); + } + + 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; + + Rectangle cb = ClientRectangle; + + Foreground.SetAsSource (gr); + + buffer.editMutex.EnterReadLock (); + editorMutex.EnterReadLock (); + + #region draw text cursor + if (buffer.SelectionInProgress){ + selStartCol = getTabulatedColumn (buffer.SelectionStart); + selEndCol = getTabulatedColumn (buffer.SelectionEnd); + }else if (HasFocus && printedCurrentLine >= 0){ + gr.LineWidth = 1.0; + double cursorX = cb.X + (getTabulatedColumn(buffer.CurrentPosition) - ScrollX) * fe.MaxXAdvance + leftMargin; + gr.MoveTo (0.5 + cursorX, cb.Y + (printedCurrentLine) * (fe.Ascent+fe.Descent)); + gr.LineTo (0.5 + cursorX, cb.Y + (printedCurrentLine + 1) * (fe.Ascent+fe.Descent)); + gr.Stroke(); + } + #endregion + + if (PrintedLines?.Count > 0) { + int unfoldedLines = buffer.UnfoldedLines; + currentNode = null; + CodeLine cl = PrintedLines[0]; + int idx0 = buffer.IndexOf(cl); + int li = idx0-1; + while (li >= 0) { + if (buffer [li].IsFoldable && !buffer [li].IsFolded) { + if (buffer.IndexOf(buffer [li].SyntacticNode.EndLine) > idx0){ + currentNode = buffer [li].SyntacticNode; + break; + } + } + li--; + } + + for (int i = 0; i < visibleLines; i++) { + if (i + ScrollY >= unfoldedLines)//TODO:need optimize + break; + drawLine (gr, cb, i); + } + } + + editorMutex.ExitReadLock (); + + buffer.editMutex.ExitReadLock (); + + } + #endregion + + #region Mouse handling + + int hoverLine = -1; + public int HoverLine { + get { return hoverLine; } + set { + if (hoverLine == value) + return; + hoverLine = value; + NotifyValueChanged ("HoverLine", hoverLine); + } + } + void updateHoverLine () { + int hvl = (int)Math.Max (0, Math.Floor (mouseLocalPos.Y / (fe.Ascent+fe.Descent))); + hvl = Math.Min (PrintedLines.Count, hvl); + HoverLine = buffer.IndexOf (PrintedLines[hvl]); + } + void updateCurrentPosFromMouseLocalPos(){ + PrintedCurrentLine = (int)Math.Max (0, Math.Floor (mouseLocalPos.Y / (fe.Ascent+fe.Descent))); + int curVisualCol = ScrollX + (int)Math.Round ((mouseLocalPos.X - leftMargin) / fe.MaxXAdvance); + + int i = 0; + int buffCol = 0; + while (i < curVisualCol && buffCol < buffer.CurrentCodeLine.Length) { + if (buffer.CurrentCodeLine[buffCol] == '\t') + i += Interface.TabSize; + else + i++; + buffCol++; + } + buffer.CurrentColumn = buffCol; + } + public override void onMouseEnter (object sender, MouseMoveEventArgs e) + { + base.onMouseEnter (sender, e); + if (e.X - ScreenCoordinates(Slot).X < leftMargin + ClientRectangle.X) + IFace.MouseCursor = XCursor.Default; + else + IFace.MouseCursor = XCursor.Text; + } + public override void onMouseLeave (object sender, MouseMoveEventArgs e) + { + base.onMouseLeave (sender, e); + IFace.MouseCursor = XCursor.Default; + } + public override void onMouseMove (object sender, MouseMoveEventArgs e) + { + base.onMouseMove (sender, e); + + mouseLocalPos = e.Position - ScreenCoordinates(Slot).TopLeft - ClientRectangle.TopLeft; + + updateHoverLine (); + + if (!e.Mouse.IsButtonDown (MouseButton.Left)) { + if (mouseLocalPos.X < leftMargin) + IFace.MouseCursor = XCursor.Default; + else + IFace.MouseCursor = XCursor.Text; + return; + } + + if (!HasFocus || !buffer.SelectionInProgress) + return; + + //mouse is down + updateCurrentPosFromMouseLocalPos(); + buffer.SetSelEndPos (); + } + public override void onMouseDown (object sender, MouseButtonEventArgs e) + { + if (!this.Focusable) + return; + + if (mouseLocalPos.X >= leftMargin) + base.onMouseDown (sender, e); + + if (doubleClicked) { + doubleClicked = false; + return; + } + + if (mouseLocalPos.X < leftMargin) { + toogleFolding (buffer.IndexOf (PrintedLines [(int)Math.Max (0, Math.Floor (mouseLocalPos.Y / (fe.Ascent+fe.Descent)))])); + return; + } + + updateCurrentPosFromMouseLocalPos (); + buffer.SetSelStartPos (); + } + public override void onMouseUp (object sender, MouseButtonEventArgs e) + { + base.onMouseUp (sender, e); + + if (buffer.SelectionIsEmpty) + buffer.ResetSelection (); + } + + public override void onMouseDoubleClick (object sender, MouseButtonEventArgs e) + { + doubleClicked = true; + base.onMouseDoubleClick (sender, e); + + buffer.GotoWordStart (); + buffer.SetSelStartPos (); + buffer.GotoWordEnd (); + buffer.SetSelEndPos (); + } + + public override void onMouseWheel (object sender, MouseWheelEventArgs e) + { + base.onMouseWheel (sender, e); + } + #endregion + + #region Keyboard handling + public override void onKeyDown (object sender, KeyboardKeyEventArgs e) + { + //base.onKeyDown (sender, e); + + Key key = e.Key; + + if (e.Control) { + switch (key) { + case Key.S: + projFile.Save (); + break; + case Key.W: + editorMutex.EnterWriteLock (); + if (e.Shift) + projFile.Redo (null); + else + projFile.Undo (null); + editorMutex.ExitWriteLock (); + break; + default: + Console.WriteLine (""); + break; + } + } + + switch (key) + { + case Key.Back: + buffer.DeleteChar (); + break; + case Key.Clear: + break; + case Key.Delete: + if (buffer.SelectionIsEmpty) + MoveRight (); + else if (e.Shift) + IFace.Clipboard = buffer.SelectedText; + buffer.DeleteChar (); + break; + case Key.Enter: + case Key.KeypadEnter: + if (!buffer.SelectionIsEmpty) + buffer.DeleteChar (); + buffer.InsertLineBreak (); + break; + case Key.Escape: + buffer.ResetSelection (); + break; + case Key.Home: + if (e.Shift) { + if (buffer.SelectionIsEmpty) + buffer.SetSelStartPos (); + if (e.Control) + buffer.CurrentLine = 0; + buffer.CurrentColumn = 0; + buffer.SetSelEndPos (); + break; + } + buffer.ResetSelection (); + if (e.Control) + buffer.CurrentLine = 0; + buffer.CurrentColumn = 0; + break; + case Key.End: + if (e.Shift) { + if (buffer.SelectionIsEmpty) + buffer.SetSelStartPos (); + if (e.Control) + buffer.CurrentLine = int.MaxValue; + buffer.CurrentColumn = int.MaxValue; + buffer.SetSelEndPos (); + break; + } + buffer.ResetSelection (); + if (e.Control) + buffer.CurrentLine = int.MaxValue; + buffer.CurrentColumn = int.MaxValue; + break; + case Key.Insert: + if (e.Shift) + buffer.Insert (IFace.Clipboard); + else if (e.Control && !buffer.SelectionIsEmpty) + IFace.Clipboard = buffer.SelectedText; + break; + case Key.Left: + if (e.Shift) { + if (buffer.SelectionIsEmpty) + buffer.SetSelStartPos (); + if (e.Control) + buffer.GotoWordStart (); + else + MoveLeft (); + buffer.SetSelEndPos (); + break; + } + buffer.ResetSelection (); + if (e.Control) + buffer.GotoWordStart (); + else + MoveLeft(); + break; + case Key.Right: + if (e.Shift) { + if (buffer.SelectionIsEmpty) + buffer.SetSelStartPos (); + if (e.Control) + buffer.GotoWordEnd (); + else + MoveRight (); + buffer.SetSelEndPos (); + break; + } + buffer.ResetSelection (); + if (e.Control) + buffer.GotoWordEnd (); + else + MoveRight (); + break; + case Key.Up: + if (e.Shift) { + if (buffer.SelectionIsEmpty) + buffer.SetSelStartPos (); + PrintedCurrentLine--; + buffer.SetSelEndPos (); + break; + } + buffer.ResetSelection (); + PrintedCurrentLine--; + break; + case Key.Down: + if (e.Shift) { + if (buffer.SelectionIsEmpty) + buffer.SetSelStartPos (); + PrintedCurrentLine++; + buffer.SetSelEndPos (); + break; + } + buffer.ResetSelection (); + PrintedCurrentLine++; + break; + case Key.Menu: + break; + case Key.NumLock: + break; + case Key.PageDown: + if (e.Shift) { + if (buffer.SelectionIsEmpty) + buffer.SetSelStartPos (); + PrintedCurrentLine += visibleLines; + buffer.SetSelEndPos (); + break; + } + buffer.ResetSelection (); + PrintedCurrentLine += visibleLines; + break; + case Key.PageUp: + if (e.Shift) { + if (buffer.SelectionIsEmpty) + buffer.SetSelStartPos (); + PrintedCurrentLine -= visibleLines; + buffer.SetSelEndPos (); + break; + } + buffer.ResetSelection (); + PrintedCurrentLine -= visibleLines; + break; + case Key.RWin: + break; + case Key.Tab: + if (e.Shift) { + if (buffer.SelectionIsEmpty || + (buffer.SelectionStart.Y == buffer.SelectionEnd.Y)) { + //TODO + break; + } + for (int i = buffer.SelectionStart.Y; i <= buffer.SelectionEnd.Y; i++) + buffer.RemoveLeadingTab (i); + buffer.SetSelectionOnFullLines (); + } else { + if (buffer.SelectionIsEmpty || + (buffer.SelectionStart.Y == buffer.SelectionEnd.Y)) { + buffer.Insert ("\t"); + break; + } + for (int i = buffer.SelectionStart.Y; i <= buffer.SelectionEnd.Y; i++) { + buffer.UpdateLine (i, "\t" + buffer [i].Content); + } + } + + break; + case Key.F8: + toogleFolding (buffer.CurrentLine); + break; + default: + break; + } + RegisterForGraphicUpdate(); + } + public override void onKeyPress (object sender, KeyPressEventArgs e) + { + base.onKeyPress (sender, e); + + buffer.Insert (e.KeyChar.ToString()); + buffer.ResetSelection (); + } + #endregion + } +} \ No newline at end of file diff --git a/CrowIDE/src/MemberView/MembersView.cs b/CrowIDE/src/MemberView/MembersView.cs index e23a41ba..d8a9ddcd 100644 --- a/CrowIDE/src/MemberView/MembersView.cs +++ b/CrowIDE/src/MemberView/MembersView.cs @@ -37,7 +37,7 @@ namespace Crow.Coding public MembersView () : base() {} //cache property containers per type - Dictionary propContainersCache = new Dictionary(); + //Dictionary propContainersCache = new Dictionary(); Dictionary> categoryContainersCache = new Dictionary> (); [XmlAttributeAttribute][DefaultValue(null)] @@ -63,7 +63,7 @@ namespace Crow.Coding } Type it = instance.GetType (); - if (!propContainersCache.ContainsKey (it.FullName)) { + if (!categoryContainersCache.ContainsKey (it.FullName)) { MemberInfo[] members = it.GetMembers (BindingFlags.Public | BindingFlags.Instance); List props = new List (); foreach (MemberInfo m in members) { @@ -76,20 +76,24 @@ namespace Crow.Coding props.Add (new PropertyContainer (this, pi)); } } - propContainersCache.Add (it.FullName, props.OrderBy (p => p.Name).ToArray ()); - } - - List categories = new List (); + //propContainersCache.Add (it.FullName, props.OrderBy (p => p.Name).ToArray ()); + List categories = new List (); - foreach (IGrouping ig in propContainersCache[it.FullName].GroupBy(pc=>pc.DesignCategory)) { - categories.Add(new CategoryContainer(ig.Key, ig.ToArray())); + foreach (IGrouping ig in props.OrderBy (p => p.Name).GroupBy(pc=>pc.DesignCategory)) { + categories.Add(new CategoryContainer(ig.Key, ig.ToArray())); + } + categoryContainersCache.Add (it.FullName, categories); } - Data = categories; + + Data = categoryContainersCache[it.FullName]; if (lastInst != instance) { - foreach (PropertyContainer pc in propContainersCache [it.FullName]) { - pc.NotifyValueChanged ("Value", pc.Value); + foreach (CategoryContainer cc in categoryContainersCache [it.FullName]) { + foreach (PropertyContainer pc in cc.Properties) { + pc.NotifyValueChanged ("Value", pc.Value); + pc.NotifyValueChanged ("LabForeground", pc.LabForeground); + } } } } diff --git a/CrowIDE/src/MemberView/PropertyContainer.cs b/CrowIDE/src/MemberView/PropertyContainer.cs index 46cbbd74..19f4ed7f 100644 --- a/CrowIDE/src/MemberView/PropertyContainer.cs +++ b/CrowIDE/src/MemberView/PropertyContainer.cs @@ -73,6 +73,8 @@ namespace Crow.Coding } set { try { + if (value == Value) + return; GraphicObject g = Instance; string valstr = null, oldval = null; @@ -116,12 +118,14 @@ namespace Crow.Coding } }else pi.SetValue(g, value); - + + Debug.WriteLine("\t\tPropContainer set design_dirty to instance"); + mview.ProjectNode.Instance.design_HasChanged = true; NotifyValueChanged ("Value", value); NotifyValueChanged ("LabForeground", LabForeground); } catch (Exception ex) { - System.Diagnostics.Debug.WriteLine ("Error setting property:"+ ex.ToString()); + Debug.WriteLine ("Error setting property:"+ ex.ToString()); } // } @@ -184,8 +188,10 @@ namespace Crow.Coding if (!inst.design_iml_values.ContainsKey (Name)) return; inst.design_iml_values.Remove (Name); - //NotifyValueChanged ("Value", Value); - mview.ProjectNode.Instance.design_HasChanged = true; + + NotifyValueChanged ("LabForeground", LabForeground); + mview.ProjectNode.UpdateSource(this, mview.ProjectNode.Instance.GetIML()); + //mview.ProjectNode.Instance.design_HasChanged = true; //should reinstantiate to get default } public void GotoStyle(){ @@ -199,6 +205,7 @@ namespace Crow.Coding Solution s = mview.ProjectNode.Project.solution; if (!s.OpenedItems.Contains (pf)) s.OpenedItems.AddElement (pf); + Debug.WriteLine (fl); pf.CurrentLine = fl.Line; pf.CurrentColumn = fl.Column; } diff --git a/CrowIDE/src/Project.cs b/CrowIDE/src/Project.cs index 6aeb5be7..2c4eda59 100644 --- a/CrowIDE/src/Project.cs +++ b/CrowIDE/src/Project.cs @@ -170,8 +170,14 @@ namespace Crow.Coding switch (pn.Extension) { case ".crow": case ".template": + case ".goml": + case ".itemp": + case ".imtl": f = new ImlProjectItem (pn); break; + case ".style": + f = new StyleProjectItem (pn); + break; default: f = new ProjectFile (pn); break; diff --git a/CrowIDE/src/ProjectTree/ImlProjectItem.cs b/CrowIDE/src/ProjectTree/ImlProjectItem.cs index 7ce24ad7..0575d177 100644 --- a/CrowIDE/src/ProjectTree/ImlProjectItem.cs +++ b/CrowIDE/src/ProjectTree/ImlProjectItem.cs @@ -41,6 +41,7 @@ namespace Crow.Coding #endregion GraphicObject instance; + Measure designWidth, designHeight; /// /// instance created with an instantiator from the source by a DesignInterface, @@ -55,6 +56,26 @@ namespace Crow.Coding NotifyValueChanged ("Instance", instance); } } + + public Measure DesignWidth { + get { return designWidth; } + set { + if (designWidth == value) + return; + designWidth = value; + NotifyValueChanged ("DesignWidth", designWidth); + } + } + public Measure DesignHeight { + get { return designHeight; } + set { + if (designHeight == value) + return; + designHeight = value; + NotifyValueChanged ("DesignHeight", designHeight); + } + } + public List GraphicTree { get { return new List (new GraphicObject[] {instance}); } diff --git a/CrowIDE/src/ProjectTree/ProjectFile.cs b/CrowIDE/src/ProjectTree/ProjectFile.cs index 2c3dbbe4..2fac2f91 100644 --- a/CrowIDE/src/ProjectTree/ProjectFile.cs +++ b/CrowIDE/src/ProjectTree/ProjectFile.cs @@ -96,12 +96,24 @@ namespace Crow.Coding RegisteredEditors.Add (editor, false); } } - public void UpdateSource (object sender, string newSrc){ + public virtual void UpdateSource (object sender, string newSrc){ System.Diagnostics.Debug.WriteLine ("update source by {0}", sender); Source = newSrc; signalOtherRegisteredEditors (sender); } - void signalOtherRegisteredEditors (object sender) { + public void SignalEditorOfType (){ + lock (RegisteredEditors) { + object[] keys = RegisteredEditors.Keys.ToArray (); + foreach (object ed in keys) { + T editor = (T)ed; + if (editor == null) + continue; + RegisteredEditors [editor] = false; + break; + } + } + } + protected void signalOtherRegisteredEditors (object sender) { lock (RegisteredEditors) { object[] keys = RegisteredEditors.Keys.ToArray (); foreach (object editor in keys) { @@ -192,7 +204,7 @@ namespace Crow.Coding origSource = source; NotifyValueChanged ("IsDirty", false); } - public void Save () { + public virtual void Save () { if (!IsDirty) return; using (StreamWriter sw = new StreamWriter (AbsolutePath)) { @@ -201,7 +213,7 @@ namespace Crow.Coding origSource = source; NotifyValueChanged ("IsDirty", false); } - public void SaveAs () { + public virtual void SaveAs () { if (!IsDirty) return; using (StreamWriter sw = new StreamWriter (AbsolutePath)) { @@ -279,7 +291,6 @@ namespace Crow.Coding { Close (); } - void onClickSaveAndCloseNow (object sender, EventArgs e) { Save (); diff --git a/CrowIDE/src/ProjectTree/StyleProjectItem.cs b/CrowIDE/src/ProjectTree/StyleProjectItem.cs new file mode 100644 index 00000000..1de77cd7 --- /dev/null +++ b/CrowIDE/src/ProjectTree/StyleProjectItem.cs @@ -0,0 +1,50 @@ +// +// ProjectNodes.cs +// +// Author: +// Jean-Philippe Bruyère +// +// 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.Xml; +using System.IO; +using Crow; +using System.Threading; + +namespace Crow.Coding +{ + public class StyleProjectItem : ProjectFile + { + #region CTOR + public StyleProjectItem (ProjectItem pi) : base (pi){ + } + #endregion + + public override void UpdateSource (object sender, string newSrc) + { + base.UpdateSource (sender, newSrc); + Project.solution.ReloadStyling (); + } + } +} + diff --git a/CrowIDE/src/Solution.cs b/CrowIDE/src/Solution.cs index 1b89dc09..68922865 100644 --- a/CrowIDE/src/Solution.cs +++ b/CrowIDE/src/Solution.cs @@ -28,6 +28,51 @@ namespace Crow.Coding{ public string RelativePath; public string ProjectGuid; } + public class StyleItemContainer { + public object Value; + public string Name; + public StyleItemContainer(string name, object _value){ + Name = name; + Value = _value; + } + } + public class StyleContainer : IValueChange { + #region IValueChange implementation + public event EventHandler ValueChanged; + public virtual void NotifyValueChanged(string MemberName, object _value) + { + ValueChanged.Raise(this, new ValueChangeEventArgs(MemberName, _value)); + } + #endregion + + Style style; + bool isExpanded; + + public string Name; + public List Items; + public bool IsExpanded + { + get { return isExpanded; } + set + { + if (value == isExpanded) + return; + isExpanded = value; + NotifyValueChanged ("IsExpanded", isExpanded); + } + } + public StyleContainer(string name, Style _style){ + Name = name; + style = _style; + + Items = new List (); + foreach (string k in style.Keys) { + Items.Add(new StyleItemContainer(k, style[k])); + } + } + } + + /// /// .sln loaded into class. /// @@ -49,12 +94,21 @@ namespace Crow.Coding{ public Dictionary Styling; public Dictionary DefaultTemplates; + public List