<?xml version="1.0"?>
<Border BorderWidth="1" Background="{./Background}">
<HorizontalStack Margin="1">
- <Scroller Name="scroller1"
+ <Scroller Name="ItemsScroller"
Margin="2">
<VerticalStack Height="Fit" MinimumSize="10,10"
Name="ItemsContainer" Margin="0" VerticalAlignment="Top"/>
</Scroller>
- <ScrollBar Name="scrollbar1" Value="{²../scroller1.ScrollY}"
- LargeIncrement="{../scroller1.PageHeight}" SmallIncrement="30" CursorSize="{../scroller1.ChildHeightRatio}"
- Maximum="{../scroller1.MaxScrollY}" Orientation="Vertical"
- Width="14" />
+ <ScrollBar Name="scrollbar1" Value="{²../ItemsScroller.ScrollY}"
+ LargeIncrement="{../ItemsScroller.PageHeight}" SmallIncrement="30" CursorSize="{../ItemsScroller.ChildHeightRatio}"
+ Maximum="{../ItemsScroller.MaxScrollY}" Orientation="Vertical"
+ Width="12" />
</HorizontalStack>
</Border>
#if DEBUG_LOG
static bool logevt (DbgEvtType evtType)
//=> IncludeEvents != DbgEvtType.None && (evtType & DiscardEvents) == 0 && (evtType & IncludeEvents) == IncludeEvents;
- /*=> IncludeEvents == DbgEvtType.All ||
- IncludeEvents != DbgEvtType.None && (evtType & DiscardEvents) == 0 && (evtType & IncludeEvents) == IncludeEvents;*/
+ //=> IncludeEvents != DbgEvtType.None && (evtType & DiscardEvents) == 0 && (evtType & IncludeEvents) == IncludeEvents;
=> IncludeEvents == DbgEvtType.All || (IncludeEvents != DbgEvtType.None && (evtType & IncludeEvents) == IncludeEvents);
while (reader.NodeType != XmlNodeType.Element)
reader.Read ();
root = reader.Name;
- Type t = tryGetGOType (root);
+ Type t = GetWidgetTypeFromName (root);
if (t == null)
throw new Exception ("IML parsing error: undefined root type (" + root + ")");
return t;
ctx.il.Emit (OpCodes.Ldloc_0);
ctx.il.Emit (OpCodes.Ldloc_0);
- Type t = tryGetGOType (reader.Name);
+ Type t = GetWidgetTypeFromName (reader.Name);
if (t == null)
throw new Exception (reader.Name + " type not found");
ConstructorInfo ci = t.GetConstructor (
/// </remarks>
/// <returns>the corresponding type object</returns>
/// <param name="typeName">graphic object type name without its namespace</param>
- internal static Type tryGetGOType (string typeName){
+ public static Type GetWidgetTypeFromName (string typeName){
if (knownGOTypes.ContainsKey (typeName))
return knownGOTypes [typeName];
Type t = Type.GetType ("Crow." + typeName);
public Dictionary<string, string> StylingConstants;
/// <summary> parse all styling data's during application startup and build global Styling Dictionary </summary>
protected virtual void loadStyling() {
- //fetch styling info in this order, if member styling is alreadey referenced in previous
- //assembly, it's ignored.
- loadThemeStyle ();
-
loadStylingFromAssembly (Assembly.GetExecutingAssembly ());
foreach (Assembly a in crowAssemblies) {
loadStylingFromAssembly (a);
}
loadStylingFromAssembly (Assembly.GetEntryAssembly ());
+ loadThemeStyle ();
}
/// <summary> Search for .style resources in assembly </summary>
protected void loadStylingFromAssembly (Assembly assembly) {
}
throw new NotImplementedException();
}
+ buff[encodedBytes] = 0;
return encodedBytes;
}
childrenRWLock.ExitWriteLock ();
+ //largestChild = tallestChild = null;
if (g.LastSlots.Width > contentSize.Width) {
largestChild = g;
contentSize.Width = g.LastSlots.Width;
tallestChild = g;
contentSize.Height = g.LastSlots.Height;
}
-
g.LayoutChanged += OnChildLayoutChanges;
+ g.RegisteredLayoutings = LayoutingType.None;
g.RegisterForLayouting (LayoutingType.Sizing | LayoutingType.ArrangeChildren);
}
public override void ClearChildren()
{
if (Children.Count > 0) {
if (lt == LayoutingType.Width) {
- if (largestChild == null)
+ //if (largestChild == null)
searchLargestChild ();
} else {
- if (tallestChild == null)
+ //if (tallestChild == null)
searchTallestChild ();
}
}
}
public override void OnLayoutChanges (LayoutingType layoutType)
- {
+ {
+ /*if (!IsVisible)
+ return;*/
base.OnLayoutChanges (layoutType);
childrenRWLock.EnterReadLock ();
int cw = 0;
if (forceMeasure)
cw = Children [i].measureRawSize (LayoutingType.Width);
- else if (Children [i].RegisteredLayoutings.HasFlag (LayoutingType.Width))
+ else if (Children[i].Width.IsRelativeToParent || Children [i].RegisteredLayoutings.HasFlag (LayoutingType.Width))
continue;
else
cw = Children [i].Slot.Width;
int ch = 0;
if (forceMeasure)
ch = Children [i].measureRawSize (LayoutingType.Height);
- else if (Children [i].RegisteredLayoutings.HasFlag (LayoutingType.Height))
+ else if (Children[i].Height.IsRelativeToParent || Children [i].RegisteredLayoutings.HasFlag (LayoutingType.Height))
continue;
else
ch = Children [i].Slot.Height;
int hoverLine = _multiline ?
(int)Math.Min (Math.Max (0, Math.Floor (mouseLocalPos.Y / (fe.Ascent + fe.Descent))), lines.Count - 1) : 0;
hoverLoc = new CharLocation (hoverLine, -1, mouseLocalPos.X);
+ using (Context gr = new Context (IFace.surf)) {
+ gr.SelectFontFace (Font.Name, Font.Slant, Font.Wheight);
+ gr.SetFontSize (Font.Size);
+ gr.FontOptions = Interface.FontRenderingOptions;
+ gr.Antialias = Interface.Antialias;
+
+ updateLocation (gr, ClientRectangle.Width, ref hoverLoc);
+ }
}
protected virtual bool cancelLinePrint (double lineHeght, double y, int clientHeight) => false;
RectangleD? textCursor = null;
--- /dev/null
+// Copyright (c) 2013-2021 Jean-Philippe Bruyère <jp_bruyere@hotmail.com>
+//
+// This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT)
+
+using System;
+using System.ComponentModel;
+using Crow.Cairo;
+
+namespace Crow {
+ public class ScrollingStack : GenericStack {
+ int scroll, maxScroll, itemSize = -1, visibleItems;
+
+ [DefaultValue (0)]public virtual int Scroll {
+ get { return scroll; }
+ set {
+ //cancelAdjustScroll = true;
+
+ if (scroll == value)
+ return;
+
+ int newS = value;
+ if (newS < 0)
+ newS = 0;
+ else if (newS > maxScroll)
+ newS = maxScroll;
+
+ if (newS == scroll)
+ return;
+
+ scroll = newS;
+
+ NotifyValueChangedAuto (scroll);
+ RegisterForGraphicUpdate ();
+ }
+ }
+ [DefaultValue (0)]public virtual int MaxScroll {
+ get { return maxScroll; }
+ set {
+ if (maxScroll == value)
+ return;
+
+ maxScroll = Math.Max (0, value);
+
+ if (scroll > maxScroll)
+ Scroll = maxScroll;
+
+ NotifyValueChangedAuto (maxScroll);
+ //RegisterForGraphicUpdate ();
+ }
+ }
+
+
+
+ public override void RemoveChild(Widget child){
+ base.RemoveChild (child);
+ updateMaxScroll ();
+ }
+ public override void InsertChild (int idx, Widget g) {
+ base.InsertChild (idx, g);
+ updateMaxScroll ();
+ }
+ public override void ClearChildren() {
+ MaxScroll = 0;
+ itemSize = -1;
+ visibleItems = 0;
+ base.ClearChildren ();
+ }
+
+ public override void OnLayoutChanges(LayoutingType layoutType)
+ {
+ if (Orientation == Orientation.Horizontal) {
+ if (layoutType == LayoutingType.Width && itemSize > 0) {
+ visibleItems = (int)Math.Ceiling ((double)ClientRectangle.Width / itemSize);
+ updateMaxScroll ();
+ }
+ } else if (layoutType == LayoutingType.Height && itemSize > 0) {
+ visibleItems = (int)Math.Ceiling ((double)ClientRectangle.Height / itemSize);
+ updateMaxScroll ();
+ }
+ base.OnLayoutChanges(layoutType);
+ }
+ public override void OnChildLayoutChanges (object sender, LayoutingEventArgs arg) {
+ DbgLogger.StartEvent(DbgEvtType.GOOnChildLayoutChange, this);
+ Widget go = sender as Widget;
+
+ if (Orientation == Orientation.Horizontal) {
+ if (arg.LayoutType == LayoutingType.Width && itemSize < go.Slot.Width)
+ itemSize = go.Slot.Width;
+ } else if (arg.LayoutType == LayoutingType.Height && itemSize < go.Slot.Height)
+ itemSize = go.Slot.Height;
+
+ base.OnChildLayoutChanges (sender, arg);
+ DbgLogger.EndEvent(DbgEvtType.GOOnChildLayoutChange);
+ }
+
+ void updateMaxScroll () {
+ if (visibleItems <= 0)
+ return;
+ MaxScroll = Children.Count - visibleItems;
+ NotifyValueChanged ("PageSize", visibleItems);
+ NotifyValueChanged ("ChildRatio", Math.Min (1.0, (double)Children.Count / visibleItems));
+ }
+
+ protected override void onDraw (Context gr)
+ {
+ DbgLogger.StartEvent (DbgEvtType.GODraw, this);
+
+ base.onDraw (gr);
+
+ if (ClipToClientRect) {
+ gr.Save ();
+ //clip to client zone
+ CairoHelpers.CairoRectangle (gr, ClientRectangle, CornerRadius);
+ gr.Clip ();
+ }
+
+ try
+ {
+ childrenRWLock.EnterReadLock ();
+
+ for (int i = Scroll; i < Children.Count && i < Scroll + visibleItems; i++) {
+ if (!Children[i].IsVisible)
+ continue;
+ /*if (Clipping.Contains (c.Slot + ClientRectangle.Position) == RegionOverlap.Out)
+ continue;*/
+ Children[i].Paint (gr);
+ }
+
+ childrenRWLock.ExitReadLock ();
+ }
+ catch (System.Exception)
+ {
+ childrenRWLock.ExitReadLock ();
+ throw;
+ }
+
+ if (ClipToClientRect)
+ gr.Restore ();
+
+ DbgLogger.EndEvent (DbgEvtType.GODraw);
+ }
+ protected override void UpdateCache (Context ctx)
+ {
+ DbgLogger.StartEvent(DbgEvtType.GOUpdateCache, this);
+ if (!Clipping.IsEmpty) {
+ using (Context gr = new Context (bmp)) {
+ for (int i = 0; i < Clipping.NumRectangles; i++)
+ gr.Rectangle(Clipping.GetRectangle(i));
+ gr.ClipPreserve();
+ gr.Operator = Operator.Clear;
+ gr.Fill();
+ gr.Operator = Operator.Over;
+
+ base.onDraw (gr);
+
+ if (ClipToClientRect) {
+ CairoHelpers.CairoRectangle (gr, ClientRectangle, CornerRadius);
+ gr.Clip ();
+ }
+
+ childrenRWLock.EnterReadLock ();
+
+ for (int i = Scroll; i < Children.Count && i < Scroll + visibleItems; i++) {
+ if (!Children[i].IsVisible)
+ continue;
+ /*if (Clipping.Contains (c.Slot + ClientRectangle.Position) == RegionOverlap.Out)
+ continue;*/
+ Children[i].Paint (gr);
+ }
+
+ childrenRWLock.ExitReadLock ();
+
+ #if DEBUG_CLIP_RECTANGLE
+ /*gr.LineWidth = 1;
+ gr.SetSourceColor(Color.DarkMagenta.AdjustAlpha (0.8));
+ for (int i = 0; i < Clipping.NumRectangles; i++)
+ gr.Rectangle(Clipping.GetRectangle(i));
+ gr.Stroke ();*/
+ #endif
+ }
+ DbgLogger.AddEvent (DbgEvtType.GOResetClip, this);
+ Clipping.Reset ();
+ }/*else
+ Console.WriteLine("GROUP REPAINT WITH EMPTY CLIPPING");*/
+ paintCache (ctx, Slot + Parent.ClientRectangle.Position);
+ DbgLogger.EndEvent(DbgEvtType.GOUpdateCache);
+ }
+
+
+ public override void checkHoverWidget (MouseMoveEventArgs e) {
+ base.checkHoverWidget (e);//TODO:check if not possible to put it at beginning of meth to avoid doubled check to DropTarget.
+ if (!childrenRWLock.TryEnterReadLock (10))
+ return;
+ for (int i = Children.Count - 1; i >= 0; i--) {
+ if (Children[i].MouseIsIn (e.Position)) {
+ Children[i].checkHoverWidget (e);
+ childrenRWLock.ExitReadLock ();
+ return;
+ }
+ }
+ childrenRWLock.ExitReadLock ();
+ }
+ /// <summary> Process scrolling vertically, or if shift is down, vertically </summary>
+ public override void onMouseWheel (object sender, MouseWheelEventArgs e) {
+ e.Handled = true;
+ Scroll += e.Delta * itemSize;
+ base.onMouseWheel (sender, e);
+ }
+ }
+}
\ No newline at end of file
#endregion
protected Group itemsContainer;
+ //if scroller name 'ItemsScroller' is found in template, scroll will adapt to selected items change.
+ protected Scroller scroller;
string _itemTemplate, dataTest;
#region events
CrowThread loadingThread = null;
bool isPaged = false;
+ bool useLoadingThread;
+ /// <summary>
+ /// Use anothred thread for loading items, default value is true.
+ /// </summary>
+ [DefaultValue(true)]
+ public bool UseLoadingThread {
+ get => useLoadingThread;
+ set {
+ if (useLoadingThread == value)
+ return;
+ useLoadingThread = value;
+ NotifyValueChangedAuto (useLoadingThread);
+ }
+ }
#region Templating
//TODO: dont instantiate ItemTemplates if not used
itemsContainer = this.child.FindByName ("ItemsContainer") as Group;
if (itemsContainer == null)
throw new Exception ("TemplatedGroup template Must contain a Group named 'ItemsContainer'");
+ scroller = child.FindByName ("ItemsScroller") as Scroller;
NotifyValueChanged ("Items", Items);
if (itemsContainer.Children.Count == 0)
NotifyValueChanged ("HasChildren", false);
[XmlIgnore]public virtual object SelectedItem{
get => selectedItem;
set {
- if (SelectedItem == value)
+ if (selectedItem == value)
return;
if (selectedItem is ISelectable oldItem)
newItem.IsSelected = true;
NotifyValueChanged ("SelectedItem", SelectedItem);
+ NotifyValueChanged ("SelectedIndex", SelectedIndex);
SelectedItemChanged.Raise (this, new SelectionChangeEventArgs (SelectedItem));
}
}
+ [XmlIgnore]public virtual int SelectedIndex{
+ get => selectedItemContainer == null ? -1 : itemsContainer.Children.IndexOf (selectedItemContainer);
+ set {
+ if (SelectedIndex == value)
+ return;
+ if (value < 0 || itemsContainer.Children.Count == 0)
+ Li_Selected (null, null);
+ if (value < itemsContainer.Children.Count)
+ Li_Selected (itemsContainer.Children[value], null);
+ else
+ Li_Selected (itemsContainer.Children[itemsContainer.Children.Count - 1], null);
+ }
+ }
[XmlIgnore]public bool HasItems {
get { return Items.Count > 0; }
}
return;
}
}
-
- loadingThread = new CrowThread (this, loading);
- loadingThread.Finished += (object sender, EventArgs e) => (sender as TemplatedGroup).Loaded.Raise (sender, e);
- loadingThread.Start ();
+
+ if (useLoadingThread) {
+ loadingThread = new CrowThread (this, loading);
+ loadingThread.Finished += (object sender, EventArgs e) => (sender as TemplatedGroup).Loaded.Raise (sender, e);
+ loadingThread.Start ();
+ } else {
+ loading();
+ Loaded.Raise (this, null);
+ }
//NotifyValueChanged ("SelectedIndex", _selectedIndex);
//NotifyValueChanged ("SelectedItem", SelectedItem);
}
}
-
-
protected void raiseSelectedItemChanged(){
SelectedItemChanged.Raise (this, new SelectionChangeEventArgs (SelectedItem));
}
-
-
public virtual void AddItem(Widget g){
itemsContainer.AddChild (g);
loadPage (data, itemsContainer, dataTest);
} catch (Exception ex) {
while (Monitor.IsEntered (IFace.UpdateMutex))
- Monitor.Exit (IFace.UpdateMutex);
+ Monitor.Exit (IFace.UpdateMutex);
while (Monitor.IsEntered (IFace.LayoutMutex))
Monitor.Exit (IFace.LayoutMutex);
System.Diagnostics.Debug.WriteLine ("loading thread aborted: " + ex.ToString());
foreach (object d in _data) {
loadItem (d, page, _dataTest);
- if (loadingThread.cancelRequested)
+ if (loadingThread != null && loadingThread.cancelRequested)
break;
}
{
if (sender == selectedItemContainer)
return;
- if (selectedItemContainer is ISelectable li)
- li.IsSelected = false;
+ if (selectedItemContainer is ISelectable lo)
+ lo.IsSelected = false;
selectedItemContainer = sender as Widget;
- SelectedItem = selectedItemContainer.DataSource;
+ if (selectedItemContainer is ISelectable ln)
+ ln.IsSelected = true;
+ SelectedItem = selectedItemContainer?.DataSource;
+
+ if (scroller != null && selectedItemContainer != null && itemsContainer is GenericStack gs) {
+ Rectangle scrollerCb = scroller.ClientRectangle;
+ Rectangle cb = gs.Slot;
+ Rectangle rItem = selectedItemContainer.Slot + new Point (gs.Margin);
+ if (gs.Orientation == Orientation.Vertical) {
+ if (rItem.Y - scroller.ScrollY < 0)
+ scroller.ScrollY = rItem.Y;
+ else if (rItem.Bottom - scroller.ScrollY > scrollerCb.Height)
+ scroller.ScrollY = rItem.Bottom - scrollerCb.Height;
+ } else if (rItem.X - scroller.ScrollX < 0)
+ scroller.ScrollX = rItem.X;
+ else if (rItem.Right - scroller.ScrollX > scrollerCb.Width)
+ scroller.ScrollX = rItem.Right - scrollerCb.Width;
+ }
SelectedItemContainerChanged.Raise (this, new SelectionChangeEventArgs (sender));
}
selectedItemContainer = sender as Widget;
if (selectedItemContainer == null)
return;
- SelectedItem = selectedItemContainer.DataSource;
- //SelectedIndex = items.Children.IndexOf(sender as Widget);
+ SelectedItem = selectedItemContainer.DataSource;
}
bool emitHelperIsAlreadyExpanded (Widget go){
void onDatasChanged (object sender, ValueChangeEventArgs e) {
}
+
+ public override void onKeyDown(object sender, KeyEventArgs e)
+ {
+ switch (e.Key) {
+ case Glfw.Key.Up:
+ if (SelectedIndex > 0)
+ SelectedIndex--;
+ break;
+ case Glfw.Key.Down:
+ if (SelectedIndex < Items.Count - 1)
+ SelectedIndex++;
+ break;
+ default:
+ base.onKeyDown(sender, e);
+ break;
+ }
+ }
}
}
-// Copyright (c) 2013-2020 Jean-Philippe Bruyère <jp_bruyere@hotmail.com>
+// Copyright (c) 2013-2021 Jean-Philippe Bruyère <jp_bruyere@hotmail.com>
//
// This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT)
namespace Crow
{
- public class TextBox : Label
- {
- #region CTOR
- protected TextBox () { }
- public TextBox (Interface iface, string style = null) : base (iface, style) { }
- #endregion
-
- /// <summary>
- /// Validate content of the text box. Occurs in non multiline TextBox when 'Enter' key
- /// is pressed.
- /// </summary>
- public event EventHandler<ValidateEventArgs> Validate;
- public virtual void OnValidate (Object sender, ValidateEventArgs e) {
- Validate.Raise (this, e);
- }
+ public class TextBox : Label
+ {
+ #region CTOR
+ protected TextBox () { }
+ public TextBox (Interface iface, string style = null) : base (iface, style) { }
+ #endregion
+
+ /// <summary>
+ /// Validate content of the text box. Occurs in non multiline TextBox when 'Enter' key
+ /// is pressed.
+ /// </summary>
+ public event EventHandler<ValidateEventArgs> Validate;
+ public virtual void OnValidate (Object sender, ValidateEventArgs e) {
+ Validate.Raise (this, e);
+ }
#region Scrolling
int scrollX, scrollY, maxScrollX, maxScrollY, mouseWheelSpeed;
/// if true, key stroke are handled in derrived class
/// </summary>
protected bool KeyEventsOverrides = false;
- bool autoAdjustScroll = false;//if scrollXY is changed directly, dont try adjust scroll to cursor
+ bool autoAdjustScroll = false;//if scrollXY is changed directly, dont try adjust scroll to cursor
/// <summary> Horizontal Scrolling Position </summary>
[DefaultValue (0)]
public virtual int ScrollX {
get { return scrollX; }
set {
- //cancelAdjustScroll = true;
+ //cancelAdjustScroll = true;
if (scrollX == value)
return;
public virtual int ScrollY {
get { return scrollY; }
set {
- //cancelAdjustScroll = true;
+ //cancelAdjustScroll = true;
- if (scrollY == value)
+ if (scrollY == value)
return;
int newS = value;
base.onMouseWheel (sender, e);
}
- public override void onMouseMove (object sender, MouseMoveEventArgs e) {
- if (!HasFocus || !IFace.IsDown (MouseButton.Left)) {
- base.onMouseMove (sender, e);
+ public override void onMouseMove (object sender, MouseMoveEventArgs e) {
+ if (!HasFocus || !IFace.IsDown (MouseButton.Left)) {
+ base.onMouseMove (sender, e);
return;
}
- Rectangle cb = ClientRectangle;
+ Rectangle cb = ClientRectangle;
- if (CurrentLoc.Value.VisualCharXPosition < scrollX)
- ScrollX = (int)CurrentLoc.Value.VisualCharXPosition;
- else if (CurrentLoc.Value.VisualCharXPosition > cb.Width + scrollX)
- ScrollX = (int)CurrentLoc.Value.VisualCharXPosition - cb.Width;
+ if (CurrentLoc.Value.VisualCharXPosition < scrollX)
+ ScrollX = (int)CurrentLoc.Value.VisualCharXPosition;
+ else if (CurrentLoc.Value.VisualCharXPosition > cb.Width + scrollX)
+ ScrollX = (int)CurrentLoc.Value.VisualCharXPosition - cb.Width;
- double lineHeight = fe.Ascent + fe.Descent;
- int firstLine = (int)Math.Ceiling((double)scrollY / lineHeight);
- int lastLine = (int)Math.Floor((double)(scrollY + cb.Height) / lineHeight) - 1;
- //Console.WriteLine ($"current: {currentLoc.Value.Line} first:{firstLine} last:{lastLine}");
+ double lineHeight = fe.Ascent + fe.Descent;
+ int firstLine = (int)Math.Ceiling((double)scrollY / lineHeight);
+ int lastLine = (int)Math.Floor((double)(scrollY + cb.Height) / lineHeight) - 1;
+ //Console.WriteLine ($"current: {currentLoc.Value.Line} first:{firstLine} last:{lastLine}");
- if (CurrentLoc.Value.Line < firstLine)
- ScrollY = (int)(lineHeight * CurrentLoc.Value.Line);
- else if (CurrentLoc.Value.Line > lastLine)
- ScrollY = (int)(lineHeight * (CurrentLoc.Value.Line + 1)) - cb.Height;
+ if (CurrentLoc.Value.Line < firstLine)
+ ScrollY = (int)(lineHeight * CurrentLoc.Value.Line);
+ else if (CurrentLoc.Value.Line > lastLine)
+ ScrollY = (int)(lineHeight * (CurrentLoc.Value.Line + 1)) - cb.Height;
e.Handled = true;
base.onMouseMove (sender, e);
- }
- #endregion
- public override void OnLayoutChanges (LayoutingType layoutType) {
- base.OnLayoutChanges (layoutType);
- updateMaxScrolls (layoutType);
- }
- protected override void drawContent (Context gr) {
- gr.Translate (-scrollX, -scrollY);
- base.drawContent (gr);
- gr.Translate (scrollX, scrollY);
- }
- protected override bool cancelLinePrint (double lineHeght, double y, int clientHeight) =>
- y + lineHeght < scrollY || y - lineHeght > clientHeight + scrollY;
- protected override void updateHoverLocation (Point mouseLocalPos) {
- base.updateHoverLocation (mouseLocalPos + new Point (ScrollX, ScrollY));
- }
- protected override void measureTextBounds (Context gr) {
- base.measureTextBounds (gr);
- updateMaxScrolls (LayoutingType.Height);
- updateMaxScrolls (LayoutingType.Width);
- }
- internal override RectangleD? computeTextCursor (Rectangle cursor) {
- Rectangle cb = ClientRectangle;
- cursor -= new Point (scrollX, scrollY);
-
- if (autoAdjustScroll) {
- autoAdjustScroll = false;
- int goodMsrs = 0;
- if (cursor.Right < 0)
- ScrollX += cursor.Right;
- else if (cursor.X > cb.Width)
- ScrollX += cursor.X - cb.Width;
- else
- goodMsrs++;
-
- if (cursor.Y < 0)
- ScrollY += cursor.Y;
- else if (cursor.Bottom > cb.Height)
- ScrollY += cursor.Bottom - cb.Height;
- else
- goodMsrs++;
-
- if (goodMsrs < 2)
- return null;
- } else if (cursor.Right < 0 || cursor.X > cb.Width || cursor.Y < 0 || cursor.Bottom > cb.Height)
- return null;
-
- return cursor;
- }
-
- void updateMaxScrolls (LayoutingType layout) {
- Rectangle cb = ClientRectangle;
- if (layout == LayoutingType.Width) {
- MaxScrollX = cachedTextSize.Width - cb.Width;
- NotifyValueChanged ("PageWidth", ClientRectangle.Width);
- if (cachedTextSize.Width > 0)
- NotifyValueChanged ("ChildWidthRatio", Math.Min (1.0, (double)cb.Width / cachedTextSize.Width));
- } else if (layout == LayoutingType.Height) {
- MaxScrollY = cachedTextSize.Height - cb.Height;
- NotifyValueChanged ("PageHeight", ClientRectangle.Height);
- if (cachedTextSize.Height > 0)
- NotifyValueChanged ("ChildHeightRatio", Math.Min (1.0, (double)cb.Height / cachedTextSize.Height));
- }
- }
-
- #region Keyboard handling
- public override void onKeyDown (object sender, KeyEventArgs e) {
- Key key = e.Key;
- TextSpan selection = Selection;
- switch (key) {
- case Key.Backspace:
- if (selection.IsEmpty) {
- if (selection.Start == 0)
- return;
- if (CurrentLoc.Value.Column == 0) {
- int lbLength = lines[CurrentLoc.Value.Line - 1].LineBreakLength;
- update (new TextChange (selection.Start - lbLength, lbLength, ""));
- }else
- update (new TextChange (selection.Start - 1, 1, ""));
- } else
- update (new TextChange (selection.Start, selection.Length, ""));
- break;
- case Key.Delete:
- if (selection.IsEmpty) {
- if (selection.Start == Text.Length)
- return;
- if (CurrentLoc.Value.Column >= lines[CurrentLoc.Value.Line].Length)
- update (new TextChange (selection.Start, lines[CurrentLoc.Value.Line].LineBreakLength, ""));
- else
- update (new TextChange (selection.Start, 1, ""));
- } else {
- if (IFace.Shift)
- IFace.Clipboard = SelectedText;
- update (new TextChange (selection.Start, selection.Length, ""));
- }
- break;
- case Key.Insert:
- if (IFace.Shift)
- update (new TextChange (selection.Start, selection.Length, IFace.Clipboard));
- else if (IFace.Ctrl && !selection.IsEmpty)
- IFace.Clipboard = SelectedText;
- break;
- case Key.KeypadEnter:
- case Key.Enter:
- if (Multiline) {
- if (string.IsNullOrEmpty (LineBreak))
- detectLineBreak ();
- update (new TextChange (selection.Start, selection.Length, LineBreak));
- } else
- OnValidate (this, new ValidateEventArgs (_text));
- break;
- case Key.Escape:
- selectionStart = null;
- CurrentLoc = lines.GetLocation (selection.Start);
- RegisterForRedraw ();
- break;
- case Key.Tab:
- update (new TextChange (selection.Start, selection.Length, "\t"));
- break;
- case Key.PageUp:
- checkShift ();
- LineMove (-visibleLines);
- RegisterForRedraw ();
- break;
- case Key.PageDown:
- checkShift ();
- LineMove (visibleLines);
- RegisterForRedraw ();
- break;
- default:
- base.onKeyDown (sender, e);
- break;
- }
- autoAdjustScroll = true;
- e.Handled = true;
- }
- public override void onKeyPress (object sender, KeyPressEventArgs e) {
- base.onKeyPress (sender, e);
-
- TextSpan selection = Selection;
- update (new TextChange (selection.Start, selection.Length, e.KeyChar.ToString ()));
-
- /*Insert (e.KeyChar.ToString());
+ }
+ #endregion
+ public override void OnLayoutChanges (LayoutingType layoutType) {
+ base.OnLayoutChanges (layoutType);
+ updateMaxScrolls (layoutType);
+ }
+ protected override void drawContent (Context gr) {
+ gr.Translate (-scrollX, -scrollY);
+ base.drawContent (gr);
+ gr.Translate (scrollX, scrollY);
+ }
+ protected override bool cancelLinePrint (double lineHeght, double y, int clientHeight) =>
+ y + lineHeght < scrollY || y - lineHeght > clientHeight + scrollY;
+ protected override void updateHoverLocation (Point mouseLocalPos) {
+ base.updateHoverLocation (mouseLocalPos + new Point (ScrollX, ScrollY));
+ }
+ protected override void measureTextBounds (Context gr) {
+ base.measureTextBounds (gr);
+ updateMaxScrolls (LayoutingType.Height);
+ updateMaxScrolls (LayoutingType.Width);
+ }
+ internal override RectangleD? computeTextCursor (Rectangle cursor) {
+ Rectangle cb = ClientRectangle;
+ cursor -= new Point (scrollX, scrollY);
+
+ if (autoAdjustScroll) {
+ autoAdjustScroll = false;
+ int goodMsrs = 0;
+ if (cursor.Right < 0)
+ ScrollX += cursor.Right;
+ else if (cursor.X > cb.Width)
+ ScrollX += cursor.X - cb.Width;
+ else
+ goodMsrs++;
+
+ if (cursor.Y < 0)
+ ScrollY += cursor.Y;
+ else if (cursor.Bottom > cb.Height)
+ ScrollY += cursor.Bottom - cb.Height;
+ else
+ goodMsrs++;
+
+ if (goodMsrs < 2)
+ return null;
+ } else if (cursor.Right < 0 || cursor.X > cb.Width || cursor.Y < 0 || cursor.Bottom > cb.Height)
+ return null;
+
+ return cursor;
+ }
+
+ void updateMaxScrolls (LayoutingType layout) {
+ Rectangle cb = ClientRectangle;
+ if (layout == LayoutingType.Width) {
+ MaxScrollX = cachedTextSize.Width - cb.Width;
+ NotifyValueChanged ("PageWidth", ClientRectangle.Width);
+ if (cachedTextSize.Width > 0)
+ NotifyValueChanged ("ChildWidthRatio", Math.Min (1.0, (double)cb.Width / cachedTextSize.Width));
+ } else if (layout == LayoutingType.Height) {
+ MaxScrollY = cachedTextSize.Height - cb.Height;
+ NotifyValueChanged ("PageHeight", ClientRectangle.Height);
+ if (cachedTextSize.Height > 0)
+ NotifyValueChanged ("ChildHeightRatio", Math.Min (1.0, (double)cb.Height / cachedTextSize.Height));
+ }
+ }
+
+ #region Keyboard handling
+ public override void onKeyDown (object sender, KeyEventArgs e) {
+ Key key = e.Key;
+ TextSpan selection = Selection;
+ switch (key) {
+ case Key.Backspace:
+ if (selection.IsEmpty) {
+ if (selection.Start == 0)
+ return;
+ if (CurrentLoc.Value.Column == 0) {
+ int lbLength = lines[CurrentLoc.Value.Line - 1].LineBreakLength;
+ update (new TextChange (selection.Start - lbLength, lbLength, ""));
+ }else
+ update (new TextChange (selection.Start - 1, 1, ""));
+ } else
+ update (new TextChange (selection.Start, selection.Length, ""));
+ break;
+ case Key.Delete:
+ if (selection.IsEmpty) {
+ if (selection.Start == Text.Length)
+ return;
+ if (CurrentLoc.Value.Column >= lines[CurrentLoc.Value.Line].Length)
+ update (new TextChange (selection.Start, lines[CurrentLoc.Value.Line].LineBreakLength, ""));
+ else
+ update (new TextChange (selection.Start, 1, ""));
+ } else {
+ if (IFace.Shift)
+ IFace.Clipboard = SelectedText;
+ update (new TextChange (selection.Start, selection.Length, ""));
+ }
+ break;
+ case Key.Insert:
+ if (IFace.Shift)
+ update (new TextChange (selection.Start, selection.Length, IFace.Clipboard));
+ else if (IFace.Ctrl && !selection.IsEmpty)
+ IFace.Clipboard = SelectedText;
+ break;
+ case Key.KeypadEnter:
+ case Key.Enter:
+ if (Multiline) {
+ if (string.IsNullOrEmpty (LineBreak))
+ detectLineBreak ();
+ update (new TextChange (selection.Start, selection.Length, LineBreak));
+ } else
+ OnValidate (this, new ValidateEventArgs (_text));
+ break;
+ case Key.Escape:
+ selectionStart = null;
+ CurrentLoc = lines.GetLocation (selection.Start);
+ RegisterForRedraw ();
+ break;
+ case Key.Tab:
+ update (new TextChange (selection.Start, selection.Length, "\t"));
+ break;
+ case Key.PageUp:
+ checkShift ();
+ LineMove (-visibleLines);
+ RegisterForRedraw ();
+ break;
+ case Key.PageDown:
+ checkShift ();
+ LineMove (visibleLines);
+ RegisterForRedraw ();
+ break;
+ default:
+ base.onKeyDown (sender, e);
+ break;
+ }
+ autoAdjustScroll = true;
+ e.Handled = true;
+ }
+ public override void onKeyPress (object sender, KeyPressEventArgs e) {
+ base.onKeyPress (sender, e);
+
+ TextSpan selection = Selection;
+ update (new TextChange (selection.Start, selection.Length, e.KeyChar.ToString ()));
+
+ /*Insert (e.KeyChar.ToString());
SelRelease = -1;
SelBegin = new Point(CurrentColumn, SelBegin.Y);
RegisterForGraphicUpdate();*/
- }
- #endregion
-
- protected void update (TextChange change) {
- lock (linesMutex) {
- Span<char> tmp = stackalloc char[Text.Length + (change.ChangedText.Length - change.Length)];
- //Console.WriteLine ($"{Text.Length,-4} {change.Start,-4} {change.Length,-4} {change.ChangedText.Length,-4} tmp:{tmp.Length,-4}");
- ReadOnlySpan<char> src = Text.AsSpan ();
- src.Slice (0, change.Start).CopyTo (tmp);
- change.ChangedText.AsSpan ().CopyTo (tmp.Slice (change.Start));
- src.Slice (change.End).CopyTo (tmp.Slice (change.Start + change.ChangedText.Length));
-
- _text = tmp.ToString ();
- lines.Update (change);
- //lines.Update (_text);
- selectionStart = null;
-
- CurrentLoc = lines.GetLocation (change.Start + change.ChangedText.Length);
- textMeasureIsUpToDate = false;
- IFace.forceTextCursor = true;
- }
-
-
- NotifyValueChanged ("Text", Text);
- OnTextChanged (this, new TextChangeEventArgs (change));
-
- RegisterForGraphicUpdate ();
- }
- }
+ }
+ #endregion
+
+ protected void update (TextChange change) {
+ lock (linesMutex) {
+ Span<char> tmp = stackalloc char[Text.Length + (change.ChangedText.Length - change.Length)];
+ //Console.WriteLine ($"{Text.Length,-4} {change.Start,-4} {change.Length,-4} {change.ChangedText.Length,-4} tmp:{tmp.Length,-4}");
+ ReadOnlySpan<char> src = Text.AsSpan ();
+ src.Slice (0, change.Start).CopyTo (tmp);
+ change.ChangedText.AsSpan ().CopyTo (tmp.Slice (change.Start));
+ src.Slice (change.End).CopyTo (tmp.Slice (change.Start + change.ChangedText.Length));
+
+ _text = tmp.ToString ();
+ lines.Update (change);
+ //lines.Update (_text);
+ selectionStart = null;
+
+ CurrentLoc = lines.GetLocation (change.Start + change.ChangedText.Length);
+ textMeasureIsUpToDate = false;
+ IFace.forceTextCursor = true;
+ }
+
+
+ NotifyValueChanged ("Text", Text);
+ OnTextChanged (this, new TextChangeEventArgs (change));
+
+ RegisterForGraphicUpdate ();
+ }
+ }
}
} else {
unshownPostActions ();
}
- RegisterForLayouting(LayoutingType.Sizing);
-
+ RegisterForLayouting(LayoutingType.Sizing);
NotifyValueChangedAuto (isVisible);
}
{
switch (layoutType) {
case LayoutingType.Width:
+ /*if (Parent is Widget p) {
+ if (p.Width.IsFit)
+ p.RegisterForLayouting (LayoutingType.Width);
+ }*/
RegisterForLayouting (LayoutingType.X);
break;
case LayoutingType.Height:
+ /*if (Parent is Widget pp) {
+ if (pp.Height.IsFit)
+ pp.RegisterForLayouting (LayoutingType.Height);
+ }*/
RegisterForLayouting (LayoutingType.Y);
break;
}
throw new ParserException (line, column, "Unexpected end of statement", resId);
ReadChar ();
if (targetsClasses.Count == 0) {
- //style constants, only the first occurence is kept
- if (!StylingConstants.ContainsKey (currentProperty))
- StylingConstants[currentProperty] = token.ToString ();
+ //style constants override previous values.
+ StylingConstants[currentProperty] = token.ToString ();
curState = States.classNames;
} else {
foreach (string tc in targetsClasses) {
</Border>
</Template>
</CheckBox>
- <Menu Data="{../../../../dbgIfaceWidget.LoggerCommands}" Height="Stretched" Width="Fit">
+ <Menu Data="{../../../../dbgIfaceWidget.LoggerCommands}" Height="Fit" Width="Stretched">
+ <Template>
+ <Wrapper Orientation="Vertical" Name="ItemsContainer" Margin="0" Background="{./Background}"/>
+ </Template>
<ItemTemplate>
<Button Command="{}" Height="Stretched" Width="Fit"/>
</ItemTemplate>
<Project>
<PropertyGroup>
<TargetFrameworks>netcoreapp3.1</TargetFrameworks>
+ <!--<TargetFrameworks>net5</TargetFrameworks>-->
<OutputType>Exe</OutputType>
<SolutionDir>$(MSBuildThisFileDirectory)..\</SolutionDir>
<EmbeddedResource Include="$(SamplesDir)common\samples.style" >
<Link>common\%(Filename)%(Extension)</Link>
</EmbeddedResource>
- <Compile Include="$(SamplesDir)common\*.cs">
+ <Compile Include="$(SamplesDir)common\src\**\*.cs">
<Link>common\%(Filename)%(Extension)</Link>
</Compile>
</ItemGroup>
{
static void Main ()
{
- DbgLogger.IncludeEvents = DbgEvtType.None;
- DbgLogger.DiscardEvents = DbgEvtType.All;
- DbgLogger.ConsoleOutput = !Configuration.Global.Get<bool> (nameof (DebugLogToFile));
+ DbgLogger.IncludeEvents = DbgEvtType.Layouting;
+ //DbgLogger.DiscardEvents = DbgEvtType.All;
+ //DbgLogger.ConsoleOutput = !Configuration.Global.Get<bool> (nameof (DebugLogToFile));
Environment.SetEnvironmentVariable ("FONTCONFIG_PATH", @"C:\Users\Jean-Philippe\source\vcpkg\installed\x64-windows\tools\fontconfig\fonts");
+++ /dev/null
-using System.Security.Principal;
-using System.Threading;
-// Copyright (c) 2013-2019 Bruyère Jean-Philippe <jp_bruyere@hotmail.com>
-//
-// This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT)
-
-using System;
-using Glfw;
-using Crow.Text;
-using System.Collections.Generic;
-using Crow.Cairo;
-using System.Threading.Tasks;
-using System.Linq;
-
-namespace Crow
-{
- [Flags]
- public enum TokenType {
- Unknown,
- Trivia = 0x0100,
- WhiteSpace = 0x4100,
- Tabulation = 0x4101,
- LineBreak = 0x4102,
- LineComment = 0x0103,
- BlockCommentStart = 0x0104,
- BlockComment = 0x0105,
- BlockCommentEnd = 0x0106,
- Name = 0x0200,
- ElementName = 0x0201,
- AttributeName = 0x0202,
- PI_Target = 0x0203,
- Punctuation = 0x0400,
- PI_Start = 0x0401,// '<?'
- PI_End = 0x0402,// '?>'
- Operator = 0x0800,
- EqualSign = 0x0801,
- AttributeValue = 0x2000,
- Keyword = 0x1000,
- ElementOpen = 0x0403,// '<'
- EndElementOpen = 0x0404,// '</'
- EmptyElementClosing = 0x0405,// '/>'
- ClosingSign = 0x0406,// '>'
- DTDObjectOpen = 0x04A0,// '<!'
- Content,
- }
-
- public struct Token {
- public readonly TokenType Type;
- public int Start;
- public readonly int Length;
- public int End => Start + Length;
- public TextSpan Span => new TextSpan (Start, End);
-
- public Token (TokenType type, int pos) {
- Type = type;
- Start = pos;
- Length = 1;
- }
- public Token (TokenType type, int start, int end) {
- Type = type;
- Start = start;
- Length = end - start;
- }
- public override string ToString() => $"{Type},{Start} {Length}";
- }
- public class XmlSource {
- public Token[] Tokens;
- public readonly string Source;
-
- public XmlSource (string _source) {
- Source = _source;
- Tokenizer tokenizer = new Tokenizer();
- Tokens = tokenizer.Tokenize (Source);
-
- /*foreach (Token t in Tokens)
- Console.WriteLine ($"{t,-40} {Source.AsSpan(t.Start, t.Length).ToString()}");*/
- }
- public class TokenizerException : Exception {
- public readonly int Position;
- public TokenizerException(string message, int position, Exception innerException = null)
- : base (message, innerException) {
- Position = position;
- }
- }
-
- class Tokenizer {
- enum States
- {
- Init,//first statement of prolog, xmldecl should only apear in this state
- prolog,//misc before doctypedecl
- ProcessingInstrucitons,
- DTD,
- DTDObject,//doctype finished
- Xml,
- StartTag,//inside start tag
- Content,//after start tag with no closing slash
- EndTag
- }
-
- States curState = States.Init;
- List<Token> Toks = new List<Token>(100);
-
- public Tokenizer () {}
-
- void skipWhiteSpaces (ref SpanCharReader reader) {
- while(!reader.EndOfSpan) {
- switch (reader.Peak) {
- case '\x85':
- case '\x2028':
- case '\xA':
- reader.Read();
- addTok (ref reader, TokenType.LineBreak);
- break;
- case '\xD':
- reader.Read();
- if (reader.IsNextCharIn ('\xA', '\x85'))
- reader.Read();
- addTok (ref reader, TokenType.LineBreak);
- break;
- case '\x20':
- case '\x9':
- char c = reader.Read();
- while (reader.TryPeak (c))
- reader.Read();
- addTok (ref reader, c == '\x20' ? TokenType.WhiteSpace : TokenType.Tabulation);
- break;
- default:
- return;
- }
- }
- }
- bool readName (ref SpanCharReader reader) {
- if (reader.EndOfSpan)
- return false;
- char c = reader.Peak;
- if (char.IsLetter(c) || c == '_' || c == ':') {
- reader.Advance ();
- while (reader.TryPeak (ref c)) {
- if (!(char.IsLetterOrDigit(c) || c == '.' || c == '-' || c == '\xB7'))
- return true;
- reader.Advance ();
- }
- return true;
- }
- return false;
- }
-
- int startOfTok;
- void addTok (ref SpanCharReader reader, TokenType tokType) {
- if (reader.CurrentPosition == startOfTok)
- return;
- Toks.Add (new Token(tokType, startOfTok, reader.CurrentPosition));
- startOfTok = reader.CurrentPosition;
- }
- public Token[] Tokenize (string source) {
- SpanCharReader reader = new SpanCharReader(source);
-
- startOfTok = 0;
- int curObjectLevel = 0;
- curState = States.Init;
-
- while(!reader.EndOfSpan) {
-
- skipWhiteSpaces (ref reader);
-
- if (reader.EndOfSpan)
- break;
-
- switch (reader.Peak) {
- case '<':
- reader.Advance ();
- if (reader.TryPeak ('?')) {
- reader.Advance ();
- addTok (ref reader, TokenType.PI_Start);
- readName (ref reader);
- addTok (ref reader, TokenType.PI_Target);
- curState = States.ProcessingInstrucitons;
- } else if (reader.TryPeak ('!')) {
- reader.Advance ();
- if (reader.TryPeak ("--")) {
- reader.Advance (2);
- addTok (ref reader, TokenType.BlockCommentStart);
- if (reader.TryReadUntil ("-->")) {
- addTok (ref reader, TokenType.BlockComment);
- reader.Advance (3);
- addTok (ref reader, TokenType.BlockCommentEnd);
- } else if (reader.TryPeak ("-->")) {
- reader.Advance (3);
- addTok (ref reader, TokenType.BlockCommentEnd);
- }
- } else {
- addTok (ref reader, TokenType.DTDObjectOpen);
- if (readName (ref reader)) {
- addTok (ref reader, TokenType.Keyword);
- curState = States.DTDObject;
- }
- }
- } else if (reader.TryPeak('/')) {
- reader.Advance ();
- addTok (ref reader, TokenType.EndElementOpen);
- if (readName (ref reader)) {
- addTok (ref reader, TokenType.ElementName);
- if (reader.TryPeak('>')) {
- reader.Advance ();
- addTok (ref reader, TokenType.ClosingSign);
-
- if (--curObjectLevel > 0)
- curState = States.Content;
- else
- curState = States.Xml;
- }
- }
- }else{
- addTok (ref reader, TokenType.ElementOpen);
- if (readName (ref reader)) {
- addTok (ref reader, TokenType.ElementName);
- curState = States.StartTag;
- }
- }
- break;
- case '?':
- reader.Advance ();
- if (reader.TryPeak ('>')){
- reader.Advance ();
- addTok (ref reader, TokenType.PI_End);
- }else
- addTok (ref reader, TokenType.Unknown);
- curState = States.prolog;
- break;
- case '\'':
- case '"':
- char q = reader.Read();
- if (reader.TryReadUntil (q)) {
- reader.Advance ();
- addTok (ref reader, TokenType.AttributeValue);
- } else
- addTok (ref reader, TokenType.Unknown);
- break;
- case '=':
- reader.Advance();
- addTok (ref reader, TokenType.EqualSign);
- break;
- case '>':
- reader.Advance();
- addTok (ref reader, TokenType.ClosingSign);
- curObjectLevel++;
- curState = States.Content;
- break;
- case '/':
- reader.Advance();
- if (reader.TryRead ('>')) {
- addTok (ref reader, TokenType.EmptyElementClosing);
- if (--curObjectLevel > 0)
- curState = States.Content;
- else
- curState = States.Xml;
- }else
- addTok (ref reader, TokenType.Unknown);
- break;
- default:
- if (curState == States.StartTag || curState == States.ProcessingInstrucitons) {
- if (readName(ref reader))
- addTok (ref reader, TokenType.AttributeName);
- else if (reader.TryAdvance())
- addTok (ref reader, TokenType.Unknown);
- } else {
- reader.TryReadUntil ('<');
- addTok (ref reader, TokenType.Content);
- }
- break;
- }
- }
-
- return Toks.ToArray();
- }
-
- }
-
- }
- public class Editor : TextBox {
- XmlSource source;
- object TokenMutex = new object();
-
- void parse () {
- XmlSource tmp = new XmlSource(_text);
- lock(TokenMutex)
- source = tmp;
- RegisterForGraphicUpdate();
- }
- protected override void onInitialized(object sender, EventArgs e)
- {
- base.onInitialized(sender, e);
-
- }
- Widget overlay;
- public override void OnTextChanged(object sender, TextChangeEventArgs e)
- {
- base.OnTextChanged(sender, e);
- //Task.Run(()=>parse());
- parse();
-
- /*if (overlay == null && HasFocus)
- overlay = IFace.LoadIMLFragment(@"<Widget Width='50' Height='50' Background='Jet'/>");*/
- }
- public override void onKeyDown(object sender, KeyEventArgs e)
- {
- TextSpan selection = Selection;
- if (e.Key == Key.Tab && !selection.IsEmpty) {
- int lineStart = lines.GetLocation (selection.Start).Line;
- int lineEnd = lines.GetLocation (selection.End).Line;
-
- if (IFace.Shift) {
- for (int l = lineStart; l <= lineEnd; l++) {
- if (Text[lines[l].Start] == '\t')
- update (new TextChange (lines[l].Start, 1, ""));
- else if (Char.IsWhiteSpace (Text[lines[l].Start])) {
- int i = 1;
- while (i < lines[l].Length && i < Interface.TAB_SIZE && Char.IsWhiteSpace (Text[i]))
- i++;
- update (new TextChange (lines[l].Start, i, ""));
- }
- }
-
- }else{
- for (int l = lineStart; l <= lineEnd; l++)
- update (new TextChange (lines[l].Start, 0, "\t"));
- }
-
- selectionStart = new CharLocation (lineStart, 0);
- CurrentLoc = new CharLocation (lineEnd, lines[lineEnd].Length);
-
- return;
- }
- base.onKeyDown(sender, e);
- }
- int tabSize = 4;
-
- protected override void drawContent (Context gr) {
- try {
- lock(TokenMutex) {
- if (source == null || source.Tokens.Length == 0) {
- base.drawContent (gr);
- return;
- }
-
- Rectangle cb = ClientRectangle;
- fe = gr.FontExtents;
- double lineHeight = fe.Ascent + fe.Descent;
-
- CharLocation selStart = default, selEnd = default;
- bool selectionNotEmpty = false;
-
- if (HasFocus) {
- if (currentLoc?.Column < 0) {
- updateLocation (gr, cb.Width, ref currentLoc);
- NotifyValueChanged ("CurrentColumn", CurrentColumn);
- } else
- updateLocation (gr, cb.Width, ref currentLoc);
-
- if (overlay != null) {
- Point p = new Point((int)currentLoc.Value.VisualCharXPosition, (int)(lineHeight * (currentLoc.Value.Line + 1)));
- p += ScreenCoordinates (Slot).TopLeft;
- overlay.Left = p.X;
- overlay.Top = p.Y;
- }
- if (selectionStart.HasValue) {
- updateLocation (gr, cb.Width, ref selectionStart);
- if (CurrentLoc.Value != selectionStart.Value)
- selectionNotEmpty = true;
- }
- if (selectionNotEmpty) {
- if (CurrentLoc.Value.Line < selectionStart.Value.Line) {
- selStart = CurrentLoc.Value;
- selEnd = selectionStart.Value;
- } else if (CurrentLoc.Value.Line > selectionStart.Value.Line) {
- selStart = selectionStart.Value;
- selEnd = CurrentLoc.Value;
- } else if (CurrentLoc.Value.Column < selectionStart.Value.Column) {
- selStart = CurrentLoc.Value;
- selEnd = selectionStart.Value;
- } else {
- selStart = selectionStart.Value;
- selEnd = CurrentLoc.Value;
- }
- } else
- IFace.forceTextCursor = true;
- }
-
- double spacePixelWidth = gr.TextExtents (" ").XAdvance;
- int x = 0, y = 0;
- double pixX = cb.Left;
-
-
- Foreground.SetAsSource (IFace, gr);
- gr.Translate (-ScrollX, -ScrollY);
-
-
- ReadOnlySpan<char> sourceBytes = source.Source.AsSpan();
- Span<byte> bytes = stackalloc byte[128];
- TextExtents extents;
- int tokPtr = 0;
- Token tok = source.Tokens[tokPtr];
- bool multilineToken = false;
-
- ReadOnlySpan<char> buff = sourceBytes;
-
-
- for (int i = 0; i < lines.Count; i++) {
- //if (!cancelLinePrint (lineHeight, lineHeight * y, cb.Height)) {
-
- if (multilineToken) {
- if (tok.End < lines[i].End) {//last incomplete line of multiline token
- buff = sourceBytes.Slice (lines[i].Start, tok.End - lines[i].Start);
- } else {//print full line
- buff = sourceBytes.Slice (lines[i].Start, lines[i].Length);
- }
- }
-
- while (tok.Start < lines[i].End) {
- if (!multilineToken) {
- if (tok.End > lines[i].End) {//first line of multiline
- multilineToken = true;
- buff = sourceBytes.Slice (tok.Start, lines[i].End - tok.Start);
- } else
- buff = sourceBytes.Slice (tok.Start, tok.Length);
-
- if (tok.Type.HasFlag (TokenType.Punctuation))
- gr.SetSource(Colors.DarkGrey);
- else if (tok.Type.HasFlag (TokenType.Trivia))
- gr.SetSource(Colors.DimGrey);
- else if (tok.Type == TokenType.ElementName) {
- gr.SetSource(Colors.Green);
- }else if (tok.Type == TokenType.AttributeName) {
- gr.SetSource(Colors.Blue);
- }else if (tok.Type == TokenType.AttributeValue) {
- gr.SetSource(Colors.OrangeRed);
- }else if (tok.Type == TokenType.EqualSign) {
- gr.SetSource(Colors.Black);
- }else if (tok.Type == TokenType.PI_Target) {
- gr.SetSource(Colors.DarkSlateBlue);
- }else {
- gr.SetSource(Colors.Red);
- }
- }
-
- int size = buff.Length * 4 + 1;
- if (bytes.Length < size)
- bytes = size > 512 ? new byte[size] : stackalloc byte[size];
-
- int encodedBytes = Crow.Text.Encoding.ToUtf8 (buff, bytes);
-
- if (encodedBytes > 0) {
- bytes[encodedBytes++] = 0;
- gr.TextExtents (bytes.Slice (0, encodedBytes), out extents);
- gr.MoveTo (pixX, lineHeight * y + fe.Ascent);
- gr.ShowText (bytes.Slice (0, encodedBytes));
- pixX += extents.XAdvance;
- x += buff.Length;
- }
-
- if (multilineToken) {
- if (tok.End < lines[i].End)//last incomplete line of multiline token
- multilineToken = false;
- else
- break;
- }
-
- if (++tokPtr >= source.Tokens.Length)
- break;
- tok = source.Tokens[tokPtr];
- }
-
- if (HasFocus && selectionNotEmpty) {
- RectangleD lineRect = new RectangleD (cb.X, lineHeight * y + cb.Top, pixX, lineHeight);
- RectangleD selRect = lineRect;
-
- if (i >= selStart.Line && i <= selEnd.Line) {
- if (selStart.Line == selEnd.Line) {
- selRect.X = selStart.VisualCharXPosition + cb.X;
- selRect.Width = selEnd.VisualCharXPosition - selStart.VisualCharXPosition;
- } else if (i == selStart.Line) {
- double newX = selStart.VisualCharXPosition + cb.X;
- selRect.Width -= (newX - selRect.X) - 10.0;
- selRect.X = newX;
- } else if (i == selEnd.Line)
- selRect.Width = selEnd.VisualCharXPosition - selRect.X + cb.X;
- else
- selRect.Width += 10.0;
-
- buff = sourceBytes.Slice(lines[i].Start, lines[i].Length);
- int size = buff.Length * 4 + 1;
- if (bytes.Length < size)
- bytes = size > 512 ? new byte[size] : stackalloc byte[size];
-
- int encodedBytes = Crow.Text.Encoding.ToUtf8 (buff, bytes);
-
- gr.SetSource (SelectionBackground);
- gr.Rectangle (selRect);
- if (encodedBytes < 0)
- gr.Fill ();
- else {
- gr.FillPreserve ();
- gr.Save ();
- gr.Clip ();
- gr.SetSource (SelectionForeground);
- gr.MoveTo (lineRect.X, lineRect.Y + fe.Ascent);
- gr.ShowText (bytes.Slice (0, encodedBytes));
- gr.Restore ();
- }
- Foreground.SetAsSource (IFace, gr);
- }
- }
-
- if (!multilineToken) {
- if (++tokPtr >= source.Tokens.Length)
- break;
- tok = source.Tokens[tokPtr];
- }
-
- x = 0;
- pixX = 0;
-
- y++;
-
-
- /* } else if (tok2.Type == TokenType.Tabulation) {
- int spaceRounding = x % tabSize;
- int spaces = spaceRounding == 0 ?
- tabSize * tok2.Length :
- spaceRounding + tabSize * (tok2.Length - 1);
- x += spaces;
- pixX += spacePixelWidth * spaces;
- continue;
- } else if (tok2.Type == TokenType.WhiteSpace) {
- x += tok2.Length;
- pixX += spacePixelWidth * tok2.Length;*/
- }
- gr.Translate (ScrollX, ScrollY);
- }
- } catch {
-
- }
- }
- }
-}
\ No newline at end of file
+++ /dev/null
-using Crow;
-using Glfw;
-using System;
-using System.Collections.Generic;
-using System.IO;
-using System.Linq;
-using System.Net.NetworkInformation;
-using System.Reflection;
-using System.Runtime.CompilerServices;
-using System.Runtime.InteropServices;
-using System.Threading;
-
-namespace Crow
-{
- public class SampleBase : Interface
- {
-#if NETCOREAPP
- static IntPtr resolveUnmanaged(Assembly assembly, String libraryName)
- {
-
- switch (libraryName)
- {
- case "glfw3":
- return NativeLibrary.Load("glfw", assembly, null);
- case "rsvg-2.40":
- return NativeLibrary.Load("rsvg-2", assembly, null);
- }
- Console.WriteLine($"[UNRESOLVE] {assembly} {libraryName}");
- return IntPtr.Zero;
- }
-
- static SampleBase()
- {
- System.Runtime.Loader.AssemblyLoadContext.GetLoadContext(Assembly.GetExecutingAssembly()).ResolvingUnmanagedDll += resolveUnmanaged;
- }
-#endif
- public SampleBase(IntPtr hWin) : base(800, 600, hWin) { }
- public SampleBase() : base(800, 600, true, true) { }
- public SampleBase(int width, int height, bool startUIThread, bool createSurface) :
- base(width, height, startUIThread, createSurface)
- {
-
- }
-
- public Version CrowVersion => Assembly.GetAssembly(typeof(Widget)).GetName().Version;
-
- #region Test values for Binding
- public CommandGroup Commands, AllCommands;
- public CommandGroup EditCommands = new CommandGroup("Edit Commands",
- new Command("Edit command 1", (sender) => MessageBox.ShowModal((sender as Widget).IFace, MessageBox.Type.Information, "Edit comand 1 clicked")),
- new Command("Edit command 2 a bit longer", (sender) => MessageBox.ShowModal((sender as Widget).IFace, MessageBox.Type.Information, "Edit comand 2 clicked"), null, false),
- new Command("Edit command three", (sender) => MessageBox.ShowModal((sender as Widget).IFace, MessageBox.Type.Information, "Edit comand 3 clicked"))
- );
- public CommandGroup FileCommands = new CommandGroup("File Commands",
- new Command("File command 1", (sender) => MessageBox.ShowModal((sender as Widget).IFace, MessageBox.Type.Information, "File comand 1 clicked")),
- new Command("File command 2 a bit longer", (sender) => MessageBox.ShowModal((sender as Widget).IFace, MessageBox.Type.Information, "File comand 2 clicked")),
- new Command("File command three", (sender) => MessageBox.ShowModal((sender as Widget).IFace, MessageBox.Type.Information, "File comand 3 clicked"))
- );
-
- void initCommands()
- {
- Commands = new CommandGroup("commands msg boxes",
- new Command("Action 1", () => MessageBox.ShowModal(this, MessageBox.Type.Information, "context menu 1 clicked")),
- new Command("Action two", () => MessageBox.ShowModal(this, MessageBox.Type.Information, "context menu 2 clicked"), null, false),
- new Command("Action three", () => MessageBox.ShowModal(this, MessageBox.Type.Information, "context menu 3 clicked"))
- );
- AllCommands = new CommandGroup ("All Commands",
- FileCommands,
- EditCommands,
- new CommandGroup ("Combined commands", FileCommands, EditCommands),
- new Command("Action A", () => MessageBox.ShowModal(this, MessageBox.Type.Information, "context menu A clicked"))
- );
- }
- public int intValue = 500;
- VerticalAlignment currentVAlign;
-
- DirectoryInfo curDir = new DirectoryInfo(Path.GetDirectoryName(Assembly.GetEntryAssembly().Location));
- public FileSystemInfo[] CurDirectory => curDir.GetFileSystemInfos();
- public string MultilineText =
- $"Lorem ipsum dolor sit amet,\nconsectetur adipiscing elit. Sed non risus.\n\nSuspendisse lectus tortor,\nLorem ipsum dolor sit amet,\nconsectetur adipiscing elit. Sed non risus.\n\nSuspendisse lectus tortor,";
- //public string MultilineText = $"a\n";
- TextAlignment textAlignment = TextAlignment.Left;
- public TextAlignment TextAlignment
- {
- get => textAlignment;
- set
- {
- if (textAlignment == value)
- return;
- textAlignment = value;
- NotifyValueChanged(textAlignment);
- }
- }
-
- public int IntValue
- {
- get => intValue;
- set
- {
- if (IntValue == value)
- return;
- intValue = value;
- NotifyValueChanged("IntValue", intValue);
- }
- }
- public VerticalAlignment CurrentVAlign
- {
- get => currentVAlign;
- set
- {
- if (currentVAlign == value)
- return;
- currentVAlign = value;
- NotifyValueChanged("CurrentVAlign", currentVAlign);
- }
- }
- void onSpinnerValueChange(object sender, ValueChangeEventArgs e)
- {
- if (e.MemberName != "Value")
- return;
- intValue = Convert.ToInt32(e.NewValue);
- }
- void change_alignment(object sender, EventArgs e)
- {
- RadioButton rb = sender as RadioButton;
- if (rb == null)
- return;
- NotifyValueChanged("alignment", Enum.Parse(typeof(Alignment), rb.Caption));
- }
- public IEnumerable<String> List2 = new List<string>(new string[]
- {
- "string1",
- "string2",
- "string3",
- "string4",
- "string5",
- "string6",
- "string7",
- "string8",
- "string8",
- "string8",
- "string8",
- "string8",
- "string8",
- "string9"
- }
- );
- public IEnumerable<String> TestList2
- {
- set
- {
- List2 = value;
- NotifyValueChanged("TestList2", testList);
- }
- get { return List2; }
- }
- public class TestClass
- {
- public string Prop1 { get; set; }
- public string Prop2 { get; set; }
-
- public override string ToString()
- => $"{Prop1}, {Prop2}";
-
- public void OnValidateCommand(Object sender, ValidateEventArgs e)
- {
- Console.WriteLine($"Validation: {e.ValidatedText}");
- }
- }
- public class TestClassVC : IValueChange
- {
- public event EventHandler<ValueChangeEventArgs> ValueChanged;
- public void NotifyValueChanged(object _value, [CallerMemberName] string caller = null)
- => ValueChanged.Raise(this, new ValueChangeEventArgs(caller, _value));
- string prop1, prop2;
- public string Prop1
- {
- get => prop1;
- set
- {
- if (prop1 == value)
- return;
- prop1 = value;
- NotifyValueChanged(prop1);
- }
- }
- public string Prop2
- {
- get => prop2;
- set
- {
- if (prop2 == value)
- return;
- prop2 = value;
- NotifyValueChanged(prop2);
- }
-
-
-
- }
-
- public override string ToString()
- => $"{Prop1}, {Prop2}";
-
- }
- TestClass tcInstance = new TestClass() { Prop1 = "instance 0 prop1 value", Prop2 = "instance 0 prop2 value" };
- TestClassVC tcVCInstance;// = new TestClassVC () { Prop1 = "instance 0 prop1 value", Prop2 = "instance 0 prop2 value" };
- TestClass tcInstance1 = new TestClass() { Prop1 = "instance 1 prop1 value", Prop2 = "instance 1 prop2 value" };
- TestClassVC tcVCInstance1 = new TestClassVC() { Prop1 = "instance 1 prop1 value", Prop2 = "instance 1 prop2 value" };
- TestClass tcInstance2 = new TestClass() { Prop1 = "instance 2 prop1 value", Prop2 = "instance 2 prop2 value" };
- TestClassVC tcVCInstance2 = new TestClassVC() { Prop1 = "instance 2 prop1 value", Prop2 = "instance 2 prop2 value" };
-
- public TestClass TcInstance
- {
- get => tcInstance;
- set
- {
- if (tcInstance == value)
- return;
- tcInstance = value;
- NotifyValueChanged(tcInstance);
- }
- }
- public TestClassVC TcVCInstance
- {
- get => tcVCInstance;
- set
- {
- if (tcVCInstance == value)
- return;
- tcVCInstance = value;
- NotifyValueChanged(tcVCInstance);
- }
- }
-
- void tcInstance_ChangeProperties_MouseClick(object sender, MouseButtonEventArgs e)
- {
- }
- public void tcInstance_ChangeInstance_MouseClick(object sender, MouseButtonEventArgs e)
- {
- if (TcInstance == tcInstance1)
- TcInstance = tcInstance2;
- else
- TcInstance = tcInstance1;
- }
- void tcVCInstance_ChangeInstance_MouseClick(object sender, MouseButtonEventArgs e)
- {
- TcVCInstance = new TestClassVC() { Prop1 = "prop1 value changed", Prop2 = "prop2 value changed" };
- }
-
- public IEnumerable<TestClass> List3 = new List<TestClass>(new TestClass[]
- {
- new TestClass { Prop1 = "string1", Prop2="prop2-1" },
- new TestClass { Prop1 = "string2", Prop2="prop2-2" },
- new TestClass { Prop1 = "string3", Prop2="prop2-3" },
- }
- );
- public IEnumerable<string> TestList3Props1 => List3.Select(sc => sc.Prop1).ToList();
- public IEnumerable<TestClass> TestList3
- {
- set
- {
- List3 = value;
- NotifyValueChanged("TestList3", testList);
- }
- get { return List3; }
- }
- string testString;
- public string TestString
- {
- get => testString;
- set
- {
- if (testString == value)
- return;
- testString = value;
-
- NotifyValueChanged(testString);
- }
- }
- string prop1;
- public string TestList3SelProp1
- {
- get => prop1;
- set
- {
- if (prop1 == value)
- return;
- prop1 = value;
-
- NotifyValueChanged(prop1);
- }
- }
-
- string selString;
- public string TestList2SelectedString
- {
- get => selString;
- set
- {
- if (selString == value)
- return;
- selString = value;
- NotifyValueChanged(selString);
- }
- }
-
-
- IList<Colors> testList = (IList<Colors>)FastEnumUtility.FastEnum.GetValues<Colors>().ToList();//.ColorDic.Values//.OrderBy(c=>c.Hue)
- //.ThenBy(c=>c.Value).ThenBy(c=>c.Saturation)
- //.ToList ();
- public IList<Colors> TestList
- {
- set
- {
- testList = value;
- NotifyValueChanged("TestList", testList);
- }
- get { return testList; }
- }
- void OnClear(object sender, MouseButtonEventArgs e) => TestList = null;
- void OnLoadList(object sender, MouseButtonEventArgs e) => TestList = (IList<Colors>)FastEnumUtility.FastEnum.GetValues<Colors>().ToList();
-
-
- string curSources = "";
- public string CurSources
- {
- get { return curSources; }
- set
- {
- if (value == curSources)
- return;
- curSources = value;
- NotifyValueChanged(curSources);
- }
- }
- bool boolVal = true;
- public bool BoolVal
- {
- get { return boolVal; }
- set
- {
- if (boolVal == value)
- return;
- boolVal = value;
- NotifyValueChanged(boolVal);
- }
- }
-
-
-
- #endregion
-
- protected override void OnInitialized()
- {
- initCommands();
- base.OnInitialized();
- }
-
- public override bool OnKeyDown(Key key)
- {
-
- switch (key)
- {
- case Key.F5:
- Load("Interfaces/Divers/testFileDialog.crow").DataSource = this;
- return true;
- case Key.F6:
- Load("Interfaces/Divers/0.crow").DataSource = this;
- return true;
- case Key.F7:
- Load("Interfaces/Divers/perfMeasures.crow").DataSource = this;
- return true;
- case Key.F2:
- if (IsKeyDown(Key.LeftShift))
- DbgLogger.Reset();
- DbgLogger.Save(this);
- return true;
- }
- return base.OnKeyDown(key);
- }
- }
-}
\ No newline at end of file
smallLabel {
Font="consolas, 8";
}
+suggestionsListBox {
+ Template = "#ui.Suggestions.template";
+ Width = "Fit";
+ Height = "Fit";
+ MaximumSize = "300, 120";
+ Background = "Jet";
+ UseLoadingThread = "false";
+}
--- /dev/null
+// Copyright (c) 2013-2021 Bruyère Jean-Philippe <jp_bruyere@hotmail.com>
+//
+// This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT)
+
+using System;
+using Glfw;
+using Crow.Text;
+using System.Collections.Generic;
+using Crow.Cairo;
+using System.Threading.Tasks;
+using System.Linq;
+using System.Diagnostics.CodeAnalysis;
+using System.Reflection;
+
+namespace Crow
+{
+ public class Editor : TextBox {
+ XmlSource source;
+ object TokenMutex = new object();
+
+ void parse () {
+ XmlSource tmp = new XmlSource(_text);
+ lock(TokenMutex)
+ source = tmp;
+ RegisterForGraphicUpdate();
+ }
+ protected override void onInitialized(object sender, EventArgs e)
+ {
+ base.onInitialized(sender, e);
+
+ }
+ ListBox overlay;
+ List<String> suggestions;
+ public List<String> Suggestions {
+ get => suggestions;
+ set {
+ suggestions = value;
+ NotifyValueChangedAuto (suggestions);
+ if (suggestions == null || suggestions.Count == 0)
+ hideOverlay ();
+ else
+ showOverlay ();
+ }
+ }
+ bool suggestionsActive => overlay != null && overlay.IsVisible;
+ Token currentToken;
+ SyntaxNode currentNode;
+ string[] allWidgetNames = typeof (Widget).Assembly.GetExportedTypes ().Where(t=>typeof(Widget).IsAssignableFrom (t))
+ .Select (s => s.Name).ToArray ();
+
+
+ string [] getAllCrowTypeMembers (string crowTypeName) {
+ Type crowType = IML.Instantiator.GetWidgetTypeFromName (crowTypeName);
+ return crowType.GetMembers (BindingFlags.Public | BindingFlags.Instance).
+ Where (m=>((m is PropertyInfo pi && pi.CanWrite) || (m is EventInfo)) &&
+ m.GetCustomAttribute<XmlIgnoreAttribute>() == null).Select (mb=>mb.Name).ToArray();
+ }
+ public override void OnTextChanged(object sender, TextChangeEventArgs e)
+ {
+ base.OnTextChanged(sender, e);
+ //Task.Run(()=>parse());
+
+ parse();
+ tryGetSuggestions ();
+
+ //Console.WriteLine ($"{pos}: {suggestionTok.AsString (_text)} {suggestionTok}");
+ }
+ void tryGetSuggestions () {
+ if (!currentLoc.HasValue)
+ return;
+ int pos = lines.GetAbsolutePosition (CurrentLoc.Value);
+ currentToken = source.FindTokenIncludingPosition (pos);
+ currentNode = source.FindNodeIncludingPosition (pos);
+
+ Console.WriteLine ($"Current Token: {currentToken} Current Node: {currentNode}");
+
+ if (currentToken.Type == TokenType.ElementOpen) {
+ Suggestions = new List<string> (allWidgetNames);
+ } else if (currentToken.Type == TokenType.ElementName) {
+ Suggestions = allWidgetNames.Where (s => s.StartsWith (currentToken.AsString (_text), StringComparison.OrdinalIgnoreCase)).ToList ();
+ } else if (currentNode is AttributeSyntax attribNode) {
+ if (currentNode.Parent is ElementTagSyntax eltTag) {
+ if (currentToken.Type == TokenType.AttributeName && eltTag.NameToken.HasValue) {
+ Suggestions = getAllCrowTypeMembers (eltTag.NameToken.Value.AsString (_text))
+ .Where (s => s.StartsWith (currentToken.AsString (_text), StringComparison.OrdinalIgnoreCase)).ToList ();
+ }
+ }
+ } else if (currentNode is ElementStartTagSyntax eltStartTag) {
+ Suggestions = getAllCrowTypeMembers (eltStartTag.NameToken.Value.AsString (_text)).ToList ();
+ } else {
+ /*SyntaxNode curNode = source.FindNodeIncludingPosition (pos);
+ Console.WriteLine ($"Current Node: {curNode}");
+ if (curNode is ElementStartTagSyntax eltStartTag &&
+ (currentToken.Type != TokenType.ClosingSign && currentToken.Type != TokenType.EmptyElementClosing && currentToken.Type != TokenType.Unknown)) {
+ Suggestions = getAllCrowTypeMembers (eltStartTag.NameToken.Value.AsString (_text)).ToList ();
+ } else*/
+ hideOverlay ();
+ }
+ }
+ void showOverlay () {
+ lock (IFace.UpdateMutex) {
+ if (overlay == null) {
+ overlay = IFace.LoadIMLFragment<ListBox>(@"
+ <ListBox Style='suggestionsListBox' Data='{Suggestions}' />
+ ");
+ overlay.DataSource = this;
+ overlay.Loaded += (sender, arg) => (sender as ListBox).SelectedIndex = 0;
+ } else
+ overlay.IsVisible = true;
+ overlay.RegisterForLayouting(LayoutingType.Sizing);
+ }
+ }
+ void hideOverlay () {
+ if (overlay == null)
+ return;
+ overlay.IsVisible = false;
+ }
+ void completeToken () {
+ string selectedSugg = overlay.SelectedItem as string;
+ if (selectedSugg == null)
+ return;
+ if (currentToken.Type == TokenType.ElementOpen || currentToken.Type == TokenType.WhiteSpace)
+ update (new TextChange (currentToken.End, 0, selectedSugg));
+ else
+ update (new TextChange (currentToken.Start, currentToken.Length, selectedSugg));
+ hideOverlay ();
+ }
+ public override void onMouseDown (object sender, MouseButtonEventArgs e) {
+ hideOverlay ();
+ base.onMouseDown (sender, e);
+ }
+ public override void onKeyDown(object sender, KeyEventArgs e)
+ {
+ if (suggestionsActive) {
+ switch (e.Key) {
+ case Key.Escape:
+ hideOverlay ();
+ return;
+ case Key.Left:
+ case Key.Right:
+ hideOverlay ();
+ break;
+ case Key.End:
+ case Key.Home:
+ case Key.Down:
+ case Key.Up:
+ case Key.PageDown:
+ case Key.PageUp:
+ overlay.onKeyDown (this, e);
+ return;
+ case Key.Tab:
+ completeToken ();
+ return;
+ }
+ } else if (e.Key == Key.Space && IFace.Ctrl) {
+ tryGetSuggestions ();
+ return;
+ }
+
+ TextSpan selection = Selection;
+ if (e.Key == Key.Tab && !selection.IsEmpty) {
+ int lineStart = lines.GetLocation (selection.Start).Line;
+ int lineEnd = lines.GetLocation (selection.End).Line;
+
+ if (IFace.Shift) {
+ for (int l = lineStart; l <= lineEnd; l++) {
+ if (Text[lines[l].Start] == '\t')
+ update (new TextChange (lines[l].Start, 1, ""));
+ else if (Char.IsWhiteSpace (Text[lines[l].Start])) {
+ int i = 1;
+ while (i < lines[l].Length && i < Interface.TAB_SIZE && Char.IsWhiteSpace (Text[i]))
+ i++;
+ update (new TextChange (lines[l].Start, i, ""));
+ }
+ }
+
+ }else{
+ for (int l = lineStart; l <= lineEnd; l++)
+ update (new TextChange (lines[l].Start, 0, "\t"));
+ }
+
+ selectionStart = new CharLocation (lineStart, 0);
+ CurrentLoc = new CharLocation (lineEnd, lines[lineEnd].Length);
+
+ return;
+ }
+ base.onKeyDown(sender, e);
+ }
+
+ protected override void drawContent (Context gr) {
+ try {
+ lock(TokenMutex) {
+ if (source == null || source.Tokens.Length == 0) {
+ base.drawContent (gr);
+ return;
+ }
+
+ Rectangle cb = ClientRectangle;
+ fe = gr.FontExtents;
+ double lineHeight = fe.Ascent + fe.Descent;
+
+ CharLocation selStart = default, selEnd = default;
+ bool selectionNotEmpty = false;
+
+ if (HasFocus) {
+ if (currentLoc?.Column < 0) {
+ updateLocation (gr, cb.Width, ref currentLoc);
+ NotifyValueChanged ("CurrentColumn", CurrentColumn);
+ } else
+ updateLocation (gr, cb.Width, ref currentLoc);
+
+ if (overlay != null && overlay.IsVisible) {
+ Point p = new Point((int)currentLoc.Value.VisualCharXPosition - ScrollX, (int)(lineHeight * (currentLoc.Value.Line + 1) - ScrollY));
+ if (p.Y < 0 || p.X < 0)
+ hideOverlay ();
+ else {
+ p += ScreenCoordinates (Slot).TopLeft;
+ overlay.Left = p.X;
+ overlay.Top = p.Y;
+ }
+ }
+ if (selectionStart.HasValue) {
+ updateLocation (gr, cb.Width, ref selectionStart);
+ if (CurrentLoc.Value != selectionStart.Value)
+ selectionNotEmpty = true;
+ }
+ if (selectionNotEmpty) {
+ if (CurrentLoc.Value.Line < selectionStart.Value.Line) {
+ selStart = CurrentLoc.Value;
+ selEnd = selectionStart.Value;
+ } else if (CurrentLoc.Value.Line > selectionStart.Value.Line) {
+ selStart = selectionStart.Value;
+ selEnd = CurrentLoc.Value;
+ } else if (CurrentLoc.Value.Column < selectionStart.Value.Column) {
+ selStart = CurrentLoc.Value;
+ selEnd = selectionStart.Value;
+ } else {
+ selStart = selectionStart.Value;
+ selEnd = CurrentLoc.Value;
+ }
+ } else
+ IFace.forceTextCursor = true;
+ }
+
+ double spacePixelWidth = gr.TextExtents (" ").XAdvance;
+ int x = 0, y = 0;
+ double pixX = cb.Left;
+
+
+ Foreground.SetAsSource (IFace, gr);
+ gr.Translate (-ScrollX, -ScrollY);
+
+
+ ReadOnlySpan<char> sourceBytes = source.Source.AsSpan();
+ Span<byte> bytes = stackalloc byte[128];
+ TextExtents extents;
+ int tokPtr = 0;
+ Token tok = source.Tokens[tokPtr];
+ bool multilineToken = false;
+
+ ReadOnlySpan<char> buff = sourceBytes;
+
+
+ for (int i = 0; i < lines.Count; i++) {
+ //if (!cancelLinePrint (lineHeight, lineHeight * y, cb.Height)) {
+
+ if (multilineToken) {
+ if (tok.End < lines[i].End) {//last incomplete line of multiline token
+ buff = sourceBytes.Slice (lines[i].Start, tok.End - lines[i].Start);
+ } else {//print full line
+ buff = sourceBytes.Slice (lines[i].Start, lines[i].Length);
+ }
+ }
+
+ while (tok.Start < lines[i].End) {
+ if (!multilineToken) {
+ if (tok.End > lines[i].End) {//first line of multiline
+ multilineToken = true;
+ buff = sourceBytes.Slice (tok.Start, lines[i].End - tok.Start);
+ } else
+ buff = sourceBytes.Slice (tok.Start, tok.Length);
+
+ if (tok.Type.HasFlag (TokenType.Punctuation))
+ gr.SetSource(Colors.DarkGrey);
+ else if (tok.Type.HasFlag (TokenType.Trivia))
+ gr.SetSource(Colors.DimGrey);
+ else if (tok.Type == TokenType.ElementName) {
+ gr.SetSource(Colors.Green);
+ }else if (tok.Type == TokenType.AttributeName) {
+ gr.SetSource(Colors.Blue);
+ }else if (tok.Type == TokenType.AttributeValue) {
+ gr.SetSource(Colors.OrangeRed);
+ }else if (tok.Type == TokenType.EqualSign) {
+ gr.SetSource(Colors.Black);
+ }else if (tok.Type == TokenType.PI_Target) {
+ gr.SetSource(Colors.DarkSlateBlue);
+ }else {
+ gr.SetSource(Colors.Red);
+ }
+ }
+
+ int size = buff.Length * 4 + 1;
+ if (bytes.Length < size)
+ bytes = size > 512 ? new byte[size] : stackalloc byte[size];
+
+ int encodedBytes = Crow.Text.Encoding.ToUtf8 (buff, bytes);
+
+ if (encodedBytes > 0) {
+ bytes[encodedBytes++] = 0;
+ gr.TextExtents (bytes.Slice (0, encodedBytes), out extents);
+ gr.MoveTo (pixX, lineHeight * y + fe.Ascent);
+ gr.ShowText (bytes.Slice (0, encodedBytes));
+ pixX += extents.XAdvance;
+ x += buff.Length;
+ }
+
+ if (multilineToken) {
+ if (tok.End < lines[i].End)//last incomplete line of multiline token
+ multilineToken = false;
+ else
+ break;
+ }
+
+ if (++tokPtr >= source.Tokens.Length)
+ break;
+ tok = source.Tokens[tokPtr];
+ }
+
+ if (HasFocus && selectionNotEmpty) {
+ RectangleD lineRect = new RectangleD (cb.X, lineHeight * y + cb.Top, pixX, lineHeight);
+ RectangleD selRect = lineRect;
+
+ if (i >= selStart.Line && i <= selEnd.Line) {
+ if (selStart.Line == selEnd.Line) {
+ selRect.X = selStart.VisualCharXPosition + cb.X;
+ selRect.Width = selEnd.VisualCharXPosition - selStart.VisualCharXPosition;
+ } else if (i == selStart.Line) {
+ double newX = selStart.VisualCharXPosition + cb.X;
+ selRect.Width -= (newX - selRect.X) - 10.0;
+ selRect.X = newX;
+ } else if (i == selEnd.Line)
+ selRect.Width = selEnd.VisualCharXPosition - selRect.X + cb.X;
+ else
+ selRect.Width += 10.0;
+
+ buff = sourceBytes.Slice(lines[i].Start, lines[i].Length);
+ int size = buff.Length * 4 + 1;
+ if (bytes.Length < size)
+ bytes = size > 512 ? new byte[size] : stackalloc byte[size];
+
+ int encodedBytes = Crow.Text.Encoding.ToUtf8 (buff, bytes);
+
+ gr.SetSource (SelectionBackground);
+ gr.Rectangle (selRect);
+ if (encodedBytes < 0)
+ gr.Fill ();
+ else {
+ gr.FillPreserve ();
+ gr.Save ();
+ gr.Clip ();
+ gr.SetSource (SelectionForeground);
+ gr.MoveTo (lineRect.X, lineRect.Y + fe.Ascent);
+ gr.ShowText (bytes.Slice (0, encodedBytes));
+ gr.Restore ();
+ }
+ Foreground.SetAsSource (IFace, gr);
+ }
+ }
+
+ if (!multilineToken) {
+ if (++tokPtr >= source.Tokens.Length)
+ break;
+ tok = source.Tokens[tokPtr];
+ }
+
+ x = 0;
+ pixX = 0;
+
+ y++;
+
+
+ /* } else if (tok2.Type == TokenType.Tabulation) {
+ int spaceRounding = x % tabSize;
+ int spaces = spaceRounding == 0 ?
+ tabSize * tok2.Length :
+ spaceRounding + tabSize * (tok2.Length - 1);
+ x += spaces;
+ pixX += spacePixelWidth * spaces;
+ continue;
+ } else if (tok2.Type == TokenType.WhiteSpace) {
+ x += tok2.Length;
+ pixX += spacePixelWidth * tok2.Length;*/
+ }
+ //gr.Translate (ScrollX, ScrollY);
+ }
+ } catch {
+
+ }
+ }
+ }
+}
\ No newline at end of file
--- /dev/null
+// Copyright (c) 2013-2021 Bruyère Jean-Philippe <jp_bruyere@hotmail.com>
+//
+// This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT)
+using System;
+using System.Collections.Generic;
+using System.Linq;
+
+namespace Crow
+{
+ public class SyntaxException : Exception {
+ public readonly Token Token;
+ public SyntaxException(string message, Token token = default, Exception innerException = null)
+ : base (message, innerException) {
+ Token = token;
+ }
+ }
+ public class SyntaxAnalyser {
+ XmlSource source;
+ IEnumerable<Token> tokens => source.Tokens;
+ public SyntaxNode Root => CurrentNode;
+ public SyntaxAnalyser (XmlSource source) {
+ this.source = source;
+ //tokens = source.Tokens.Where (t => !t.Type.HasFlag (TokenType.Trivia));
+ }
+
+
+ /*List<SyntaxNode> readAttributes (IEnumerator<Token> iter) {
+ List<SyntaxNode> attributes = new List<SyntaxNode> (10);
+ while (iter.MoveNext ()) {
+ switch (iter.Current.Type) {
+ case TokenType.EmptyElementClosing:
+ case TokenType.ClosingSign:
+ return attributes;
+ case TokenType.AttributeName:
+ Token attribName = iter.Current;
+ moveNextOrThrow (iter);
+ Token equalSign = accept (iter, TokenType.EqualSign);
+ moveNextOrThrow (iter);
+ Token attribValue = accept (iter, TokenType.AttributeValue);
+ attributes.Add (new AttributeSyntax (source, attribName, equalSign, attribValue));
+ break;
+ }
+ }
+ throw new SyntaxException ("Unexpected end of source");
+ }
+
+ Token accept (IEnumerator<Token> iter, TokenType acceptedTokenType) {
+ if (iter.Current.Type == acceptedTokenType)
+ return iter.Current;
+ else
+ throw new SyntaxException ("Unexpected token", iter.Current);
+ }
+ void moveNextOrThrow (IEnumerator<Token> iter) {
+ if (!iter.MoveNext ())
+ throw new SyntaxException ("Unexpected end of source");
+ }
+ ElementStartTagSyntax readElementStart (IEnumerator<Token> iter) {
+ Token eltOpen = iter.Current;
+ moveNextOrThrow (iter);
+ Token eltName = accept (iter, TokenType.ElementName);
+
+ List<SyntaxNode> attributes = readAttributes (iter);
+
+ if (iter.Current.Type == TokenType.EmptyElementClosing || iter.Current.Type == TokenType.ClosingSign)
+ return new ElementStartTagSyntax(source, eltOpen, eltName, iter.Current, attributes);
+
+ throw new SyntaxException ("Unexpected token", iter.Current);
+ }
+ ElementEndTagSyntax readElementEnd (IEnumerator<Token> iter) {
+ Token eltOpen = iter.Current;
+ moveNextOrThrow (iter);
+ Token eltName = accept (iter, TokenType.ElementName);
+ moveNextOrThrow (iter);
+ return new ElementEndTagSyntax(source, eltOpen, eltName, accept (iter, TokenType.ClosingSign));
+ }*/
+
+ SyntaxNode CurrentNode;
+ Token previousTok;
+ IEnumerator<Token> iter;
+ public List<SyntaxException> Exceptions { get; private set; }
+
+ void finishCurrentNode () {
+
+ }
+
+ public void Process () {
+ Exceptions = new List<SyntaxException> ();
+ CurrentNode = new IMLRootSyntax (source);
+ previousTok = default;
+ iter = tokens.GetEnumerator ();
+
+ bool notEndOfSource = iter.MoveNext ();
+ while (notEndOfSource) {
+ if (!iter.Current.Type.HasFlag (TokenType.Trivia)) {
+ if (CurrentNode is ElementStartTagSyntax tag) {
+ if (iter.Current.Type == TokenType.AttributeName) {
+ AttributeSyntax attribute = new AttributeSyntax (iter.Current);
+ attribute.NameToken = iter.Current;
+ CurrentNode = CurrentNode.AddChild (attribute);
+ } else if (iter.Current.Type == TokenType.ElementName)
+ tag.NameToken = iter.Current;
+ else if (iter.Current.Type == TokenType.ClosingSign) {
+ tag.EndToken = iter.Current;
+ CurrentNode = tag.Parent;
+ CurrentNode.RemoveChild (tag);
+ CurrentNode = CurrentNode.AddChild (new ElementSyntax (tag));
+ } else if (iter.Current.Type == TokenType.EmptyElementClosing) {
+ tag.EndToken = iter.Current;
+ CurrentNode = tag.Parent;
+ CurrentNode.RemoveChild (tag);
+ CurrentNode.AddChild (new EmptyElementSyntax (tag));
+ } else {
+ Exceptions.Add (new SyntaxException ("Unexpected Token", iter.Current));
+ CurrentNode.EndToken = previousTok;
+ CurrentNode = CurrentNode.Parent;
+ continue;
+ }
+ } else if (CurrentNode is ElementSyntax elt) {
+ if (iter.Current.Type == TokenType.ElementOpen)
+ CurrentNode = CurrentNode.AddChild (new ElementStartTagSyntax (iter.Current));
+ else if (iter.Current.Type == TokenType.EndElementOpen) {
+ elt.EndTag = new ElementEndTagSyntax (iter.Current);
+ CurrentNode = elt.AddChild (elt.EndTag);
+ }
+ } else if (CurrentNode is AttributeSyntax attrib) {
+ if (iter.Current.Type == TokenType.EqualSign)
+ if (attrib.EqualToken.HasValue)
+ Exceptions.Add (new SyntaxException ("Extra equal sign in attribute syntax", iter.Current));
+ else
+ attrib.EqualToken = iter.Current;
+ else if (iter.Current.Type == TokenType.AttributeValue) {
+ attrib.ValueToken = attrib.EndToken = iter.Current;
+ CurrentNode = CurrentNode.Parent;
+ } else {
+ Exceptions.Add (new SyntaxException ("Unexpected Token", iter.Current));
+ CurrentNode.EndToken = previousTok;
+ CurrentNode = CurrentNode.Parent;
+ continue;
+ }
+ } else if (CurrentNode is ElementEndTagSyntax eltEndTag) {
+ if (iter.Current.Type == TokenType.ElementName)
+ eltEndTag.NameToken = iter.Current;
+ else if (iter.Current.Type == TokenType.ClosingSign) {
+ eltEndTag.EndToken = eltEndTag.Parent.EndToken = iter.Current;
+ CurrentNode = eltEndTag.Parent.Parent;
+ } else {
+ Exceptions.Add (new SyntaxException ("Unexpected Token", iter.Current));
+ eltEndTag.EndToken = eltEndTag.Parent.EndToken = previousTok;
+ CurrentNode = CurrentNode.Parent.Parent;
+ continue;
+ }
+ } else if (CurrentNode is IMLRootSyntax) {
+ switch (iter.Current.Type) {
+ case TokenType.ElementOpen:
+ CurrentNode = CurrentNode.AddChild (new ElementStartTagSyntax (iter.Current));
+ break;
+ case TokenType.PI_Start:
+ CurrentNode = CurrentNode.AddChild (new ProcessingInstructionSyntax (iter.Current));
+ break;
+ default:
+ Exceptions.Add (new SyntaxException ("Unexpected Token", iter.Current));
+ break;
+ }
+ } else if (CurrentNode is ProcessingInstructionSyntax pi) {
+ if (iter.Current.Type == TokenType.PI_Target)
+ pi.NameToken = iter.Current;
+ else if (iter.Current.Type == TokenType.PI_End) {
+ pi.EndToken = iter.Current;
+ CurrentNode = CurrentNode.Parent;
+ } else if (iter.Current.Type == TokenType.AttributeName) {
+ AttributeSyntax attribute = new AttributeSyntax (iter.Current);
+ attribute.NameToken = iter.Current;
+ CurrentNode = CurrentNode.AddChild (attribute);
+ } else {
+ Exceptions.Add (new SyntaxException ("Unexpected Token", iter.Current));
+ pi.EndToken = previousTok;
+ CurrentNode = CurrentNode.Parent;
+ continue;
+ }
+ }
+ }
+
+ previousTok = iter.Current;
+ notEndOfSource = iter.MoveNext ();
+ }
+ while (CurrentNode.Parent != null) {
+ if (!CurrentNode.EndToken.HasValue)
+ CurrentNode.EndToken = previousTok;
+ CurrentNode = CurrentNode.Parent;
+ }
+ }
+ }
+ public class SyntaxNode {
+ public SyntaxNode Parent { get; private set; }
+ List<SyntaxNode> children = new List<SyntaxNode> ();
+
+ public readonly Token StartToken;
+ public Token? EndToken { get; internal set; }
+ public SyntaxNode (Token tokStart, Token? tokEnd = null) {
+ StartToken = tokStart;
+ EndToken = tokEnd;
+ }
+
+ public virtual bool IsComplete => EndToken.HasValue;
+
+ internal SyntaxNode AddChild (SyntaxNode child) {
+ children.Add (child);
+ child.Parent = this;
+ return child;
+ }
+ internal void RemoveChild (SyntaxNode child) {
+ children.Remove (child);
+ child.Parent = null;
+ }
+ public T GetChild<T> () => children.OfType<T> ().FirstOrDefault ();
+ public SyntaxNode FindNodeIncludingPosition (int pos) {
+ foreach (SyntaxNode node in children) {
+ if (node.Contains (pos))
+ return node.FindNodeIncludingPosition (pos);
+ }
+ return this;
+ }
+ public T FindNodeIncludingPosition<T> (int pos) {
+ foreach (SyntaxNode node in children) {
+ if (node.Contains (pos))
+ return node.FindNodeIncludingPosition<T> (pos);
+ }
+
+ return this is T tt ? tt : default;
+ }
+ public virtual IMLRootSyntax Root => Parent.Root;
+ public XmlSource Source => Root.source;
+ public bool Contains (int pos) =>
+ EndToken.HasValue ?
+ StartToken.Start <= pos && EndToken.Value.End >= pos : false;
+
+ public void Dump (int level = 0) {
+ Console.WriteLine ($"{new string('\t', level)}{this}");
+ foreach (SyntaxNode node in children)
+ node.Dump (level + 1);
+ }
+ public override string ToString() => $"{this.GetType().Name}: {StartToken} -> {EndToken}";
+ }
+ public class IMLRootSyntax : SyntaxNode {
+ internal readonly XmlSource source;
+ public override IMLRootSyntax Root => this;
+ public IMLRootSyntax (XmlSource source)
+ : base (source.Tokens.FirstOrDefault (), source.Tokens.LastOrDefault ()) {
+ this.source = source;
+ }
+ }
+ public class ProcessingInstructionSyntax : SyntaxNode {
+ public Token PIStartToken => StartToken;
+ public Token? PIEndToken => EndToken.HasValue && EndToken.Value.Type == TokenType.PI_End ? EndToken : null;
+ public Token? NameToken { get; internal set; }
+ public override bool IsComplete => base.IsComplete & NameToken.HasValue;
+ public ProcessingInstructionSyntax (Token startTok)
+ : base (startTok) {
+ }
+ }
+
+ public abstract class ElementTagSyntax : SyntaxNode {
+ public Token OpenToken => StartToken;
+ public Token? NameToken { get; internal set; }
+ public Token? CloseToken => EndToken.HasValue && EndToken.Value.Type == TokenType.ClosingSign ? EndToken : null;
+ public override bool IsComplete => base.IsComplete & NameToken.HasValue & CloseToken.HasValue;
+ protected ElementTagSyntax (Token startTok)
+ : base (startTok) {
+ }
+ }
+ public class ElementStartTagSyntax : ElementTagSyntax {
+ public ElementStartTagSyntax (Token startTok)
+ : base (startTok) {
+ }
+ }
+ public class ElementEndTagSyntax : ElementTagSyntax {
+ public ElementEndTagSyntax (Token startTok)
+ : base (startTok) {
+ }
+ }
+
+ public class EmptyElementSyntax : SyntaxNode {
+ public readonly ElementStartTagSyntax StartTag;
+ public EmptyElementSyntax (ElementStartTagSyntax startNode) : base (startNode.StartToken, startNode.EndToken) {
+ StartTag = startNode;
+ AddChild (StartTag);
+ }
+ }
+
+ public class ElementSyntax : SyntaxNode {
+ public readonly ElementStartTagSyntax StartTag;
+ public ElementEndTagSyntax EndTag { get; internal set; }
+
+ public override bool IsComplete => base.IsComplete & StartTag.IsComplete & (EndTag != null && EndTag.IsComplete);
+
+ public ElementSyntax (ElementStartTagSyntax startTag)
+ : base (startTag.StartToken) {
+ StartTag = startTag;
+ AddChild (StartTag);
+ }
+ }
+
+ public class AttributeSyntax : SyntaxNode {
+ public Token? NameToken { get; internal set; }
+ public Token? EqualToken { get; internal set; }
+ public Token? ValueToken { get; internal set; }
+ public AttributeSyntax (Token startTok) : base (startTok) {}
+ public override bool IsComplete => base.IsComplete & NameToken.HasValue & EqualToken.HasValue & ValueToken.HasValue;
+ }
+}
\ No newline at end of file
--- /dev/null
+// Copyright (c) 2013-2021 Bruyère Jean-Philippe <jp_bruyere@hotmail.com>
+//
+// This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT)
+
+using System;
+using Crow.Text;
+using System.Diagnostics.CodeAnalysis;
+
+namespace Crow
+{
+ public struct Token : IComparable<Token>, IEquatable<Token> {
+ public readonly TokenType Type;
+ public int Start;
+ public readonly int Length;
+ public int End => Start + Length;
+ public TextSpan Span => new TextSpan (Start, End);
+ public string AsString (ReadOnlySpan<char> source)
+ => source.Slice (Start, Length).ToString();
+
+ public Token (TokenType type, int pos) {
+ Type = type;
+ Start = pos;
+ Length = 1;
+ }
+ public Token (TokenType type, int start, int end) {
+ Type = type;
+ Start = start;
+ Length = end - start;
+ }
+
+ public int CompareTo([AllowNull] Token other)
+ => Start - other.Start;
+ public bool Equals([AllowNull] Token other)
+ => Type == other.Type && Start == other.Start && Length == other.Length;
+ public override bool Equals(object obj)
+ => obj is Token other ? Equals (other) : false;
+ public override int GetHashCode() => HashCode.Combine (Type, Start, Length);
+ public override string ToString() => $"{Type}:{Start},{Length};";
+ }
+}
\ No newline at end of file
--- /dev/null
+// Copyright (c) 2013-2021 Bruyère Jean-Philippe <jp_bruyere@hotmail.com>
+//
+// This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT)
+
+using System;
+
+namespace Crow
+{
+ [Flags]
+ public enum TokenType {
+ Unknown,
+ Trivia = 0x0100,
+ WhiteSpace = 0x4100,
+ Tabulation = 0x4101,
+ LineBreak = 0x4102,
+ LineComment = 0x0103,
+ BlockCommentStart = 0x0104,
+ BlockComment = 0x0105,
+ BlockCommentEnd = 0x0106,
+ Name = 0x0200,
+ ElementName = 0x0201,
+ AttributeName = 0x0202,
+ PI_Target = 0x0203,
+ Punctuation = 0x0400,
+ PI_Start = 0x0401,// '<?'
+ PI_End = 0x0402,// '?>'
+ Operator = 0x0800,
+ EqualSign = 0x0801,
+ AttributeValue = 0x2000,
+ Keyword = 0x1000,
+ ElementOpen = 0x0403,// '<'
+ EndElementOpen = 0x0404,// '</'
+ EmptyElementClosing = 0x0405,// '/>'
+ ClosingSign = 0x0406,// '>'
+ DTDObjectOpen = 0x04A0,// '<!'
+ Content,
+ }
+}
\ No newline at end of file
--- /dev/null
+// Copyright (c) 2013-2021 Bruyère Jean-Philippe <jp_bruyere@hotmail.com>
+//
+// This code is licensed under the MIT license (MIT) (http://opensource.org/licenses/MIT)
+
+using System;
+using Crow.Text;
+using System.Collections.Generic;
+using System.Diagnostics;
+
+namespace Crow
+{
+ public class XmlSource {
+ public Token[] Tokens;
+ public readonly string Source;
+
+ SyntaxNode RootNode;
+
+ public XmlSource (string _source) {
+ Source = _source;
+ Tokenizer tokenizer = new Tokenizer();
+ Tokens = tokenizer.Tokenize (Source);
+
+ SyntaxAnalyser syntaxAnalyser = new SyntaxAnalyser (this);
+ Stopwatch sw = Stopwatch.StartNew ();
+ syntaxAnalyser.Process ();
+ sw.Stop();
+
+ foreach (Token t in Tokens)
+ Console.WriteLine ($"{t,-40} {Source.AsSpan(t.Start, t.Length).ToString()}");
+ syntaxAnalyser.Root.Dump();
+ Console.WriteLine ($"Syntax Analysis done in {sw.ElapsedMilliseconds}(ms) {sw.ElapsedTicks}(ticks)");
+ foreach (SyntaxException ex in syntaxAnalyser.Exceptions)
+ Console.WriteLine ($"{ex}");
+
+ RootNode = syntaxAnalyser.Root;
+ }
+
+ public Token FindTokenIncludingPosition (int pos) {
+ if (Tokens == null || Tokens.Length == 0)
+ return default;
+ int idx = Array.BinarySearch (Tokens, 0, Tokens.Length, new Token () {Start = pos});
+
+ return idx == 0 ? Tokens[0] : idx < 0 ? Tokens[~idx - 1] : Tokens[idx - 1];
+ }
+ public SyntaxNode FindNodeIncludingPosition (int pos) {
+ if (RootNode == null)
+ return null;
+ if (!RootNode.Contains (pos))
+ return null;
+ return RootNode.FindNodeIncludingPosition (pos);
+ }
+ public T FindNodeIncludingPosition<T> (int pos) {
+ if (RootNode == null)
+ return default;
+ if (!RootNode.Contains (pos))
+ return default;
+ return RootNode.FindNodeIncludingPosition<T> (pos);
+ }
+
+ public class TokenizerException : Exception {
+ public readonly int Position;
+ public TokenizerException(string message, int position, Exception innerException = null)
+ : base (message, innerException) {
+ Position = position;
+ }
+ }
+
+ class Tokenizer {
+ enum States
+ {
+ Init,//first statement of prolog, xmldecl should only apear in this state
+ prolog,//misc before doctypedecl
+ ProcessingInstrucitons,
+ DTD,
+ DTDObject,//doctype finished
+ Xml,
+ StartTag,//inside start tag
+ Content,//after start tag with no closing slash
+ EndTag
+ }
+
+ States curState = States.Init;
+ List<Token> Toks = new List<Token>(100);
+
+ public Tokenizer () {}
+
+ void skipWhiteSpaces (ref SpanCharReader reader) {
+ while(!reader.EndOfSpan) {
+ switch (reader.Peak) {
+ case '\x85':
+ case '\x2028':
+ case '\xA':
+ reader.Read();
+ addTok (ref reader, TokenType.LineBreak);
+ break;
+ case '\xD':
+ reader.Read();
+ if (reader.IsNextCharIn ('\xA', '\x85'))
+ reader.Read();
+ addTok (ref reader, TokenType.LineBreak);
+ break;
+ case '\x20':
+ case '\x9':
+ char c = reader.Read();
+ while (reader.TryPeak (c))
+ reader.Read();
+ addTok (ref reader, c == '\x20' ? TokenType.WhiteSpace : TokenType.Tabulation);
+ break;
+ default:
+ return;
+ }
+ }
+ }
+ bool readName (ref SpanCharReader reader) {
+ if (reader.EndOfSpan)
+ return false;
+ char c = reader.Peak;
+ if (char.IsLetter(c) || c == '_' || c == ':') {
+ reader.Advance ();
+ while (reader.TryPeak (ref c)) {
+ if (!(char.IsLetterOrDigit(c) || c == '.' || c == '-' || c == '\xB7'))
+ return true;
+ reader.Advance ();
+ }
+ return true;
+ }
+ return false;
+ }
+
+ int startOfTok;
+ void addTok (ref SpanCharReader reader, TokenType tokType) {
+ if (reader.CurrentPosition == startOfTok)
+ return;
+ Toks.Add (new Token(tokType, startOfTok, reader.CurrentPosition));
+ startOfTok = reader.CurrentPosition;
+ }
+ public Token[] Tokenize (string source) {
+ SpanCharReader reader = new SpanCharReader(source);
+
+ startOfTok = 0;
+ int curObjectLevel = 0;
+ curState = States.Init;
+
+ while(!reader.EndOfSpan) {
+
+ skipWhiteSpaces (ref reader);
+
+ if (reader.EndOfSpan)
+ break;
+
+ switch (reader.Peak) {
+ case '<':
+ reader.Advance ();
+ if (reader.TryPeak ('?')) {
+ reader.Advance ();
+ addTok (ref reader, TokenType.PI_Start);
+ readName (ref reader);
+ addTok (ref reader, TokenType.PI_Target);
+ curState = States.ProcessingInstrucitons;
+ } else if (reader.TryPeak ('!')) {
+ reader.Advance ();
+ if (reader.TryPeak ("--")) {
+ reader.Advance (2);
+ addTok (ref reader, TokenType.BlockCommentStart);
+ if (reader.TryReadUntil ("-->")) {
+ addTok (ref reader, TokenType.BlockComment);
+ reader.Advance (3);
+ addTok (ref reader, TokenType.BlockCommentEnd);
+ } else if (reader.TryPeak ("-->")) {
+ reader.Advance (3);
+ addTok (ref reader, TokenType.BlockCommentEnd);
+ }
+ } else {
+ addTok (ref reader, TokenType.DTDObjectOpen);
+ if (readName (ref reader)) {
+ addTok (ref reader, TokenType.Keyword);
+ curState = States.DTDObject;
+ }
+ }
+ } else if (reader.TryPeak('/')) {
+ reader.Advance ();
+ addTok (ref reader, TokenType.EndElementOpen);
+ if (readName (ref reader)) {
+ addTok (ref reader, TokenType.ElementName);
+ if (reader.TryPeak('>')) {
+ reader.Advance ();
+ addTok (ref reader, TokenType.ClosingSign);
+
+ if (--curObjectLevel > 0)
+ curState = States.Content;
+ else
+ curState = States.Xml;
+ }
+ }
+ }else{
+ addTok (ref reader, TokenType.ElementOpen);
+ if (readName (ref reader)) {
+ addTok (ref reader, TokenType.ElementName);
+ curState = States.StartTag;
+ }
+ }
+ break;
+ case '?':
+ reader.Advance ();
+ if (reader.TryPeak ('>')){
+ reader.Advance ();
+ addTok (ref reader, TokenType.PI_End);
+ }else
+ addTok (ref reader, TokenType.Unknown);
+ curState = States.prolog;
+ break;
+ case '\'':
+ case '"':
+ char q = reader.Read();
+ if (reader.TryReadUntil (q))
+ reader.Advance ();
+ addTok (ref reader, TokenType.AttributeValue);
+ break;
+ case '=':
+ reader.Advance();
+ addTok (ref reader, TokenType.EqualSign);
+ break;
+ case '>':
+ reader.Advance();
+ addTok (ref reader, TokenType.ClosingSign);
+ curObjectLevel++;
+ curState = States.Content;
+ break;
+ case '/':
+ reader.Advance();
+ if (reader.TryRead ('>')) {
+ addTok (ref reader, TokenType.EmptyElementClosing);
+ if (--curObjectLevel > 0)
+ curState = States.Content;
+ else
+ curState = States.Xml;
+ }else
+ addTok (ref reader, TokenType.Unknown);
+ break;
+ default:
+ if (curState == States.StartTag || curState == States.ProcessingInstrucitons) {
+ if (readName(ref reader))
+ addTok (ref reader, TokenType.AttributeName);
+ else if (reader.TryAdvance())
+ addTok (ref reader, TokenType.Unknown);
+ } else {
+ reader.TryReadUntil ('<');
+ addTok (ref reader, TokenType.Content);
+ }
+ break;
+ }
+ }
+
+ return Toks.ToArray();
+ }
+
+ }
+
+ }
+}
\ No newline at end of file
--- /dev/null
+using Crow;
+using Glfw;
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Linq;
+using System.Net.NetworkInformation;
+using System.Reflection;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+using System.Threading;
+
+namespace Crow
+{
+ public class SampleBase : Interface
+ {
+#if NETCOREAPP
+ static IntPtr resolveUnmanaged(Assembly assembly, String libraryName)
+ {
+
+ switch (libraryName)
+ {
+ case "glfw3":
+ return NativeLibrary.Load("glfw", assembly, null);
+ case "rsvg-2.40":
+ return NativeLibrary.Load("rsvg-2", assembly, null);
+ }
+ Console.WriteLine($"[UNRESOLVE] {assembly} {libraryName}");
+ return IntPtr.Zero;
+ }
+
+ static SampleBase()
+ {
+ System.Runtime.Loader.AssemblyLoadContext.GetLoadContext(Assembly.GetExecutingAssembly()).ResolvingUnmanagedDll += resolveUnmanaged;
+ }
+#endif
+ public SampleBase(IntPtr hWin) : base(800, 600, hWin) { }
+ public SampleBase() : base(800, 600, true, true) { }
+ public SampleBase(int width, int height, bool startUIThread, bool createSurface) :
+ base(width, height, startUIThread, createSurface)
+ {
+
+ }
+
+ public Version CrowVersion => Assembly.GetAssembly(typeof(Widget)).GetName().Version;
+
+ #region Test values for Binding
+ public CommandGroup Commands, AllCommands;
+ public CommandGroup EditCommands = new CommandGroup("Edit Commands",
+ new Command("Edit command 1", (sender) => MessageBox.ShowModal((sender as Widget).IFace, MessageBox.Type.Information, "Edit comand 1 clicked")),
+ new Command("Edit command 2 a bit longer", (sender) => MessageBox.ShowModal((sender as Widget).IFace, MessageBox.Type.Information, "Edit comand 2 clicked"), null, false),
+ new Command("Edit command three", (sender) => MessageBox.ShowModal((sender as Widget).IFace, MessageBox.Type.Information, "Edit comand 3 clicked"))
+ );
+ public CommandGroup FileCommands = new CommandGroup("File Commands",
+ new Command("File command 1", (sender) => MessageBox.ShowModal((sender as Widget).IFace, MessageBox.Type.Information, "File comand 1 clicked")),
+ new Command("File command 2 a bit longer", (sender) => MessageBox.ShowModal((sender as Widget).IFace, MessageBox.Type.Information, "File comand 2 clicked")),
+ new Command("File command three", (sender) => MessageBox.ShowModal((sender as Widget).IFace, MessageBox.Type.Information, "File comand 3 clicked"))
+ );
+
+ void initCommands()
+ {
+ Commands = new CommandGroup("commands msg boxes",
+ new Command("Action 1", () => MessageBox.ShowModal(this, MessageBox.Type.Information, "context menu 1 clicked")),
+ new Command("Action two", () => MessageBox.ShowModal(this, MessageBox.Type.Information, "context menu 2 clicked"), null, false),
+ new Command("Action three", () => MessageBox.ShowModal(this, MessageBox.Type.Information, "context menu 3 clicked"))
+ );
+ AllCommands = new CommandGroup ("All Commands",
+ FileCommands,
+ EditCommands,
+ new CommandGroup ("Combined commands", FileCommands, EditCommands),
+ new Command("Action A", () => MessageBox.ShowModal(this, MessageBox.Type.Information, "context menu A clicked"))
+ );
+ }
+ public int intValue = 500;
+ VerticalAlignment currentVAlign;
+
+ DirectoryInfo curDir = new DirectoryInfo(Path.GetDirectoryName(Assembly.GetEntryAssembly().Location));
+ public FileSystemInfo[] CurDirectory => curDir.GetFileSystemInfos();
+ public string MultilineText =
+ $"Lorem ipsum dolor sit amet,\nconsectetur adipiscing elit. Sed non risus.\n\nSuspendisse lectus tortor,\nLorem ipsum dolor sit amet,\nconsectetur adipiscing elit. Sed non risus.\n\nSuspendisse lectus tortor,";
+ //public string MultilineText = $"a\n";
+ TextAlignment textAlignment = TextAlignment.Left;
+ public TextAlignment TextAlignment
+ {
+ get => textAlignment;
+ set
+ {
+ if (textAlignment == value)
+ return;
+ textAlignment = value;
+ NotifyValueChanged(textAlignment);
+ }
+ }
+
+ public int IntValue
+ {
+ get => intValue;
+ set
+ {
+ if (IntValue == value)
+ return;
+ intValue = value;
+ NotifyValueChanged("IntValue", intValue);
+ }
+ }
+ public VerticalAlignment CurrentVAlign
+ {
+ get => currentVAlign;
+ set
+ {
+ if (currentVAlign == value)
+ return;
+ currentVAlign = value;
+ NotifyValueChanged("CurrentVAlign", currentVAlign);
+ }
+ }
+ void onSpinnerValueChange(object sender, ValueChangeEventArgs e)
+ {
+ if (e.MemberName != "Value")
+ return;
+ intValue = Convert.ToInt32(e.NewValue);
+ }
+ void change_alignment(object sender, EventArgs e)
+ {
+ RadioButton rb = sender as RadioButton;
+ if (rb == null)
+ return;
+ NotifyValueChanged("alignment", Enum.Parse(typeof(Alignment), rb.Caption));
+ }
+ public IEnumerable<String> List2 = new List<string>(new string[]
+ {
+ "string1",
+ "string2",
+ "string3",
+ "string4",
+ "string5",
+ "string6",
+ "string7",
+ "string8",
+ "string8",
+ "string8",
+ "string8",
+ "string8",
+ "string8",
+ "string9"
+ }
+ );
+ public IEnumerable<String> TestList2
+ {
+ set
+ {
+ List2 = value;
+ NotifyValueChanged("TestList2", testList);
+ }
+ get { return List2; }
+ }
+ public class TestClass
+ {
+ public string Prop1 { get; set; }
+ public string Prop2 { get; set; }
+
+ public override string ToString()
+ => $"{Prop1}, {Prop2}";
+
+ public void OnValidateCommand(Object sender, ValidateEventArgs e)
+ {
+ Console.WriteLine($"Validation: {e.ValidatedText}");
+ }
+ }
+ public class TestClassVC : IValueChange
+ {
+ public event EventHandler<ValueChangeEventArgs> ValueChanged;
+ public void NotifyValueChanged(object _value, [CallerMemberName] string caller = null)
+ => ValueChanged.Raise(this, new ValueChangeEventArgs(caller, _value));
+ string prop1, prop2;
+ public string Prop1
+ {
+ get => prop1;
+ set
+ {
+ if (prop1 == value)
+ return;
+ prop1 = value;
+ NotifyValueChanged(prop1);
+ }
+ }
+ public string Prop2
+ {
+ get => prop2;
+ set
+ {
+ if (prop2 == value)
+ return;
+ prop2 = value;
+ NotifyValueChanged(prop2);
+ }
+
+
+
+ }
+
+ public override string ToString()
+ => $"{Prop1}, {Prop2}";
+
+ }
+ TestClass tcInstance = new TestClass() { Prop1 = "instance 0 prop1 value", Prop2 = "instance 0 prop2 value" };
+ TestClassVC tcVCInstance;// = new TestClassVC () { Prop1 = "instance 0 prop1 value", Prop2 = "instance 0 prop2 value" };
+ TestClass tcInstance1 = new TestClass() { Prop1 = "instance 1 prop1 value", Prop2 = "instance 1 prop2 value" };
+ TestClassVC tcVCInstance1 = new TestClassVC() { Prop1 = "instance 1 prop1 value", Prop2 = "instance 1 prop2 value" };
+ TestClass tcInstance2 = new TestClass() { Prop1 = "instance 2 prop1 value", Prop2 = "instance 2 prop2 value" };
+ TestClassVC tcVCInstance2 = new TestClassVC() { Prop1 = "instance 2 prop1 value", Prop2 = "instance 2 prop2 value" };
+
+ public TestClass TcInstance
+ {
+ get => tcInstance;
+ set
+ {
+ if (tcInstance == value)
+ return;
+ tcInstance = value;
+ NotifyValueChanged(tcInstance);
+ }
+ }
+ public TestClassVC TcVCInstance
+ {
+ get => tcVCInstance;
+ set
+ {
+ if (tcVCInstance == value)
+ return;
+ tcVCInstance = value;
+ NotifyValueChanged(tcVCInstance);
+ }
+ }
+
+ void tcInstance_ChangeProperties_MouseClick(object sender, MouseButtonEventArgs e)
+ {
+ }
+ public void tcInstance_ChangeInstance_MouseClick(object sender, MouseButtonEventArgs e)
+ {
+ if (TcInstance == tcInstance1)
+ TcInstance = tcInstance2;
+ else
+ TcInstance = tcInstance1;
+ }
+ void tcVCInstance_ChangeInstance_MouseClick(object sender, MouseButtonEventArgs e)
+ {
+ TcVCInstance = new TestClassVC() { Prop1 = "prop1 value changed", Prop2 = "prop2 value changed" };
+ }
+
+ public IEnumerable<TestClass> List3 = new List<TestClass>(new TestClass[]
+ {
+ new TestClass { Prop1 = "string1", Prop2="prop2-1" },
+ new TestClass { Prop1 = "string2", Prop2="prop2-2" },
+ new TestClass { Prop1 = "string3", Prop2="prop2-3" },
+ }
+ );
+ public IEnumerable<string> TestList3Props1 => List3.Select(sc => sc.Prop1).ToList();
+ public IEnumerable<TestClass> TestList3
+ {
+ set
+ {
+ List3 = value;
+ NotifyValueChanged("TestList3", testList);
+ }
+ get { return List3; }
+ }
+ string testString;
+ public string TestString
+ {
+ get => testString;
+ set
+ {
+ if (testString == value)
+ return;
+ testString = value;
+
+ NotifyValueChanged(testString);
+ }
+ }
+ string prop1;
+ public string TestList3SelProp1
+ {
+ get => prop1;
+ set
+ {
+ if (prop1 == value)
+ return;
+ prop1 = value;
+
+ NotifyValueChanged(prop1);
+ }
+ }
+
+ string selString;
+ public string TestList2SelectedString
+ {
+ get => selString;
+ set
+ {
+ if (selString == value)
+ return;
+ selString = value;
+ NotifyValueChanged(selString);
+ }
+ }
+
+
+ IList<Colors> testList = (IList<Colors>)FastEnumUtility.FastEnum.GetValues<Colors>().ToList();//.ColorDic.Values//.OrderBy(c=>c.Hue)
+ //.ThenBy(c=>c.Value).ThenBy(c=>c.Saturation)
+ //.ToList ();
+ public IList<Colors> TestList
+ {
+ set
+ {
+ testList = value;
+ NotifyValueChanged("TestList", testList);
+ }
+ get { return testList; }
+ }
+ void OnClear(object sender, MouseButtonEventArgs e) => TestList = null;
+ void OnLoadList(object sender, MouseButtonEventArgs e) => TestList = (IList<Colors>)FastEnumUtility.FastEnum.GetValues<Colors>().ToList();
+
+
+ string curSources = "";
+ public string CurSources
+ {
+ get { return curSources; }
+ set
+ {
+ if (value == curSources)
+ return;
+ curSources = value;
+ NotifyValueChanged(curSources);
+ }
+ }
+ bool boolVal = true;
+ public bool BoolVal
+ {
+ get { return boolVal; }
+ set
+ {
+ if (boolVal == value)
+ return;
+ boolVal = value;
+ NotifyValueChanged(boolVal);
+ }
+ }
+
+
+
+ #endregion
+
+ protected override void OnInitialized()
+ {
+ initCommands();
+ base.OnInitialized();
+ }
+
+ public override bool OnKeyDown(Key key)
+ {
+
+ switch (key)
+ {
+ case Key.F5:
+ Load("Interfaces/Divers/testFileDialog.crow").DataSource = this;
+ return true;
+ case Key.F6:
+ Load("Interfaces/Divers/0.crow").DataSource = this;
+ return true;
+ case Key.F7:
+ Load("Interfaces/Divers/perfMeasures.crow").DataSource = this;
+ return true;
+ case Key.F2:
+ if (IsKeyDown(Key.LeftShift))
+ DbgLogger.Reset();
+ DbgLogger.Save(this);
+ return true;
+ }
+ return base.OnKeyDown(key);
+ }
+ }
+}
\ No newline at end of file
</VerticalStack>
<Splitter />
<VerticalStack Width="30%" Margin="5">
- <ListBox Name="colorList" Data="{TestList}" Margin="5" ItemTemplate="Interfaces/colorItem.crow" />
+ <ListBox Focusable="true" Name="colorList" Data="{TestList}" Margin="5" ItemTemplate="Interfaces/colorItem.crow" />
</VerticalStack>
</HorizontalStack>
</Window>
\ No newline at end of file
<?xml version="1.0"?>
-<ListBox Data="{TestList}" Width="Fit" >
+<ListBox Data="{TestList}" Width="Fit" Focusable="true" >
<Template>
- <Scroller Height="Stretched" Background="DarkRed" Margin="1">
+ <Scroller Name="ItemsScroller" Height="Stretched" Background="Onyx" Margin="10">
<VerticalStack Name="ItemsContainer" Orientation="Horizontal" VerticalAlignment="Top" Height="Fit" Background="Grey" Margin="20"/>
</Scroller>
</Template>
<ItemTemplate>
<!--<Label Text="{}" TextAlignment="Center" Font="mono, 9" Foreground="Black" Margin="10" Width="Stretched" Background="{}"/>-->
- <Label Text="{}" TextAlignment="Center" Font="mono, 9" Foreground="Black" Margin="10" Background="{}" Width="Stretched" />
+ <ListItem Width="Stretched" Margin="1" CornerRadius="5"
+ Selected="{Background=Yellow}"
+ Unselected="{Background=Transparent}">
+ <Label Text="{}" TextAlignment="Center" Font="mono, 9" Foreground="Black" Margin="6" Background="{}" Width="Stretched" />
+ </ListItem>
</ItemTemplate>
</ListBox>
--- /dev/null
+<VerticalStack>
+ <Label Text='Hello World' Background='MediumSeaGreen' Margin='10'/>
+ <CheckBox I
+</VerticalStack>
\ No newline at end of file
<Template>
<Popper Margin="0" Caption="{./CurrentColor}" Background="{./Background}" >
<Template>
- <CheckBox Margin="0" Caption="{./Caption}" IsChecked="{²./IsPopped}" Background="{./Background}">
- <Template>
- <HorizontalStack Margin="3" Spacing="3" Background="{./Background}">
- <Border Width="18" Height="12" CornerRadius="3"
- Background="{../../../../CurrentColor}">
- </Border>
- <Label Width="Stretched" Text="{./Caption}" />
- </HorizontalStack>
- </Template>/>{}
- </CheckBox>
- </Template>
- <TabView MinimumSize="{../../MinimumPopupSize}" Width="Fit" Height="Fit" >
+ <HorizontalStack Margin="3" Spacing="3" Background="{./Background}">
+ <Border Width="18" Height="12" CornerRadius="3"
+ Background="{../../../CurrentColor}">
+ </Border>
+ <Label Width="Stretched" Text="{./Caption}" />
+ </HorizontalStack>
+ </Template>/>
+ <TabView MinimumSize="{../MinimumPopupSize}" Width="200" Height="200" >
<ColorPicker Name="HSV" CurrentColor="{²../../../CurrentColor}" Background="Onyx"/>
<ColorPicker IsVisible="false" Name="Names" CurrentColor="{²../../../CurrentColor}" Height="Stretched" Background="Onyx">
<Template>
<Label Width="Stretched" Text="{./Caption}" />
</HorizontalStack>
</Template>
- <TabView MinimumSize="{../../MinimumPopupSize}" Width="Fit" Height="Fit" >
+ <TabView MinimumSize="{../MinimumPopupSize}" Width="200" Height="200" >
<ColorPicker Name="HSV" CurrentColor="{²../../../CurrentColor}" Background="Onyx"/>
<ColorPicker IsVisible="false" Name="Names" CurrentColor="{²../../../CurrentColor}" Height="Stretched" Background="Onyx">
<Template>
--- /dev/null
+<?xml version="1.0"?>
+<Border BorderWidth="1" Background="{./Background}" Height="Stretched">
+ <!--<HorizontalStack Margin="1">-->
+ <Scroller Name="ItemsScroller" Margin="2">
+ <VerticalStack Height="Fit" MinimumSize="10,10"
+ Name="ItemsContainer" Margin="0" VerticalAlignment="Top"/>
+ </Scroller>
+ <!--<ScrollBar Name="scrollbar1" Value="{²../ItemsScroller.ScrollY}"
+ LargeIncrement="{../ItemsScroller.PageHeight}" SmallIncrement="30" CursorSize="{../ItemsScroller.ChildHeightRatio}"
+ Maximum="{../ItemsScroller.MaxScrollY}" Orientation="Vertical"
+ Width="12" />
+ </HorizontalStack>-->
+</Border>
--- /dev/null
+#!/bin/bash
+sed -i.bak ':a;s/^\(\t*\) \{4\}/\1\t/;/^\t* \{4\}/ba' $1
+rm $1.bak