<EmbeddedResource Include="Templates\DockWindow.template">
<LogicalName>Crow.DockWindow.template</LogicalName>
</EmbeddedResource>
+ <EmbeddedResource Include="Templates\HScrollBar.template">
+ <LogicalName>Crow.HScrollBar.template</LogicalName>
+ </EmbeddedResource>
</ItemGroup>
<ItemGroup>
<None Include="Crow.dll.config">
<EmbeddedResource Include="icons\compile.svg" />
<EmbeddedResource Include="icons\edit.svg" />
<EmbeddedResource Include="icons\text-file.svg" />
+ <EmbeddedResource Include="icons\undo.svg" />
+ <EmbeddedResource Include="icons\redo.svg" />
<EmbeddedResource Include="ui\SourceEditor.crow" />
</ItemGroup>
<ItemGroup>
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Generated by IcoMoon.io -->
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="16" height="16" viewBox="0 0 16 16">
+<path fill="#444444" d="M5.3 6.7l1.4-1.4-3-3 1.3-1.3h-4v4l1.3-1.3z"></path>
+<path fill="#444444" d="M6.7 10.7l-1.4-1.4-3 3-1.3-1.3v4h4l-1.3-1.3z"></path>
+<path fill="#444444" d="M10.7 9.3l-1.4 1.4 3 3-1.3 1.3h4v-4l-1.3 1.3z"></path>
+<path fill="#444444" d="M11 1l1.3 1.3-3 3 1.4 1.4 3-3 1.3 1.3v-4z"></path>
+</svg>
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Generated by IcoMoon.io -->
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="16" height="16" viewBox="0 0 16 16">
+<path fill="#444444" d="M16 7.9l-6-4.9v3c-0.5 0-1.1 0-2 0-8 0-8 8-8 8s1-4 7.8-4c1.1 0 1.8 0 2.2 0v2.9l6-5z"></path>
+</svg>
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<!-- Generated by IcoMoon.io -->
+<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
+<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="16" height="16" viewBox="0 0 16 16">
+<path fill="#444444" d="M0 7.9l6-4.9v3c0 0 1.1 0 2 0 8 0 8 8 8 8s-1-4-7.8-4c-1.1 0-1.8 0-2.2 0v2.9l-6-5z"></path>
+</svg>
internal ReaderWriterLockSlim srcEditMtx = new ReaderWriterLockSlim();
public Dictionary<object, bool> RegisteredEditors = new Dictionary<object, bool>();
+ List<String> undoStack = new List<string>();
+ List<String> redoStack = new List<string>();
- Crow.Command cmdSave, cmdOpen;
+ public Crow.Command cmdSave, cmdSaveAs, cmdOpen, cmdUndo, cmdRedo;
public ProjectFile (ProjectItem pi)
: base (pi.Project, pi.node) {
cmdSave = new Crow.Command (new Action (() => Save ()))
- { Caption = "Save", Icon = new SvgPicture ("#Crow.Coding.ui.icons.inbox.svg"), CanExecute = true };
+ { Caption = "Save", Icon = new SvgPicture ("#Crow.Coding.ui.icons.inbox.svg"), CanExecute = false };
+ cmdSave = new Crow.Command (new Action (() => SaveAs ()))
+ { Caption = "Save As ..", Icon = new SvgPicture ("#Crow.Coding.ui.icons.inbox.svg"), CanExecute = false };
cmdOpen = new Crow.Command (new Action (() => Open ()))
{ Caption = "Open", Icon = new SvgPicture ("#Crow.Coding.ui.icons.outbox.svg"), CanExecute = false };
-
+ cmdUndo = new Crow.Command (new Action (() => Undo (null)))
+ { Caption = "Undo", Icon = new SvgPicture ("#Crow.Coding.icons.undo.svg"), CanExecute = false };
+ cmdRedo = new Crow.Command (new Action (() => Redo (null)))
+ { Caption = "Redo", Icon = new SvgPicture ("#Crow.Coding.icons.redo.svg"), CanExecute = false };
+
Commands.Insert (0, cmdOpen);
Commands.Insert (1, cmdSave);
+
+ //Commands.Add (cmdUndo);
+ //Commands.Add (cmdRedo);
}
public string ResourceID {
public void UpdateSource (object sender, string newSrc){
System.Diagnostics.Debug.WriteLine ("update source by {0}", sender);
Source = newSrc;
+ signalOtherRegisteredEditors (sender);
+ }
+ void signalOtherRegisteredEditors (object sender) {
lock (RegisteredEditors) {
object[] keys = RegisteredEditors.Keys.ToArray ();
foreach (object editor in keys) {
srcEditMtx.EnterWriteLock ();
+ undoStack.Add (source);
+ cmdUndo.CanExecute = true;
+ redoStack.Clear ();
+ cmdRedo.CanExecute = false;
source = value;
+
NotifyValueChanged ("Source", source);
NotifyValueChanged ("IsDirty", IsDirty);
- cmdSave.CanExecute = IsDirty;
+ cmdSave.CanExecute = cmdSaveAs.CanExecute = IsDirty;
srcEditMtx.ExitWriteLock ();
}
origSource = source;
NotifyValueChanged ("IsDirty", false);
}
+ public void SaveAs () {
+ if (!IsDirty)
+ return;
+ using (StreamWriter sw = new StreamWriter (AbsolutePath)) {
+ sw.Write (source);
+ }
+ origSource = source;
+ NotifyValueChanged ("IsDirty", false);
+ }
public void Close () {
origSource = null;
isOpened = false;
Project.solution.CloseItem (this);
}
+ public void Undo(object sender){
+ undo();
+ signalOtherRegisteredEditors (sender);
+ }
+ public void Redo(object sender){
+ redo();
+ signalOtherRegisteredEditors (sender);
+ }
+
+ void undo () {
+ if (undoStack.Count == 0)
+ return;
+
+ srcEditMtx.EnterWriteLock ();
+ string step = undoStack [undoStack.Count -1];
+ redoStack.Add (source);
+ cmdRedo.CanExecute = true;
+ undoStack.RemoveAt(undoStack.Count -1);
+
+ source = step;
+
+ NotifyValueChanged ("Source", source);
+ NotifyValueChanged ("IsDirty", IsDirty);
+ cmdSave.CanExecute = IsDirty;
+
+ if (undoStack.Count == 0)
+ cmdUndo.CanExecute = false;
+ srcEditMtx.ExitWriteLock ();
+ }
+
+ void redo () {
+ if (redoStack.Count == 0)
+ return;
+ srcEditMtx.EnterWriteLock ();
+ string step = redoStack [redoStack.Count -1];
+ undoStack.Add (source);
+ cmdUndo.CanExecute = true;
+ redoStack.RemoveAt(redoStack.Count -1);
+ source = step;
+ NotifyValueChanged ("Source", source);
+ NotifyValueChanged ("IsDirty", IsDirty);
+ cmdSave.CanExecute = IsDirty;
+
+ if (redoStack.Count == 0)
+ cmdRedo.CanExecute = false;
+ srcEditMtx.ExitWriteLock ();
+
+ }
+
public void OnQueryClose (object sender, EventArgs e){
if (IsDirty) {
buffer.ToogleFolding (line);
}
+ #region Editor overrides
protected override void updateEditorFromProjFile ()
{
+ buffer.editMutex.EnterWriteLock ();
loadSource ();
+ buffer.editMutex.ExitWriteLock ();
+
isDirty = false;
oldSource = projFile.Source;
CurrentLine = requestedLine;
protected override bool IsReady {
get { return buffer != null; }
}
+ #endregion
#region Buffer events handlers
void Buffer_BufferCleared (object sender, EventArgs e)
Foreground.SetAsSource (gr);
buffer.editMutex.EnterReadLock ();
+ editorMutex.EnterReadLock ();
+
#region draw text cursor
if (buffer.SelectionInProgress){
selStartCol = getTabulatedColumn (buffer.SelectionStart);
}
#endregion
- editorMutex.EnterReadLock ();
-
if (PrintedLines != null) {
int unfoldedLines = buffer.UnfoldedLines;
currentNode = null;
case Key.S:
projFile.Save ();
break;
+ case Key.W:
+ editorMutex.EnterWriteLock ();
+ if (e.Shift)
+ projFile.Redo (null);
+ else
+ projFile.Undo (null);
+ editorMutex.ExitWriteLock ();
+ break;
+ default:
+ Console.WriteLine ("");
+ break;
}
}
{
SvgPicture _pic = new SvgPicture();
+ int zoom;
+
+ [DefaultValue(100)]
+ public int Zoom {
+ get { return zoom; }
+ set {
+ if (zoom == value)
+ return;
+ zoom = value;
+ NotifyValueChanged ("Zoom", zoom);
+ updateMaxScrolls ();
+ RegisterForGraphicUpdate ();
+ }
+ }
+
+ void updateMaxScrolls() {
+ MaxScrollX = Math.Max(0, _pic.Dimensions.Width * zoom / 100 - Slot.Width);
+ MaxScrollY = Math.Max(0, _pic.Dimensions.Height * zoom / 100 - Slot.Height);
+
+ if (Slot.Width + MaxScrollX > 0)
+ NotifyValueChanged ("ChildWidthRatio", Slot.Width * Slot.Width / (Slot.Width + MaxScrollX));
+ else
+ NotifyValueChanged ("ChildWidthRatio", 0);
+
+ if (Slot.Height + MaxScrollY > 0)
+ NotifyValueChanged ("ChildHeightRatio", Slot.Height * Slot.Height / (Slot.Height + MaxScrollY));
+ else
+ NotifyValueChanged ("ChildHeightRatio", 0);
+ }
+ #region editor overrides
protected override void updateEditorFromProjFile ()
{
Error = null;
try {
editorMutex.EnterWriteLock();
_pic.LoadSvgFragment (projFile.Source);
- _pic.Scaled = false;
+ _pic.Scaled = true;
_pic.KeepProportions = true;
} catch (Exception ex) {
Error = ex;
}
editorMutex.ExitWriteLock ();
+ updateMaxScrolls ();
RegisterForGraphicUpdate ();
}
protected override void updateProjFileFromEditor ()
throw new NotImplementedException ();
}
}
+ #endregion
#region GraphicObject overrides
protected override int measureRawSize (LayoutingType lt)
{
base.onDraw (gr);
+ Rectangle r = ClientRectangle;
+ Foreground.SetAsSource (gr, r);
+ gr.Rectangle (r, 0.1);
+ gr.Stroke ();
+
+ r.Width = _pic.Dimensions.Width * zoom / 100;
+ r.Height = _pic.Dimensions.Height * zoom / 100;
+
+ gr.Save ();
+
editorMutex.EnterReadLock ();
+
+ gr.Translate (-ScrollX, -ScrollY);
if (_pic != null)
- _pic.Paint (gr, ClientRectangle);
+ _pic.Paint (gr, r);
editorMutex.ExitReadLock ();
+
+ gr.Restore ();
+ }
+ public override void OnLayoutChanges (LayoutingType layoutType)
+ {
+ base.OnLayoutChanges (layoutType);
+ if ((layoutType | LayoutingType.Sizing) > 0)
+ updateMaxScrolls ();
}
#endregion
}
<Window Height="Stretched" Width="Stretched" >
<VerticalStack>
<Menu>
- <MenuItem Caption="File" Width="Fit" PopWidth="120">
+ <MenuItem Caption="File" Width="Fit" PopWidth="120" DataSource="{CurrentSolution}">
<MenuItem Command="{CMDNew}" />
<MenuItem Command="{CMDOpen}" />
- <MenuItem Command="{CMDSave}" />
- <MenuItem Command="{CMDSaveAs}" />
+ <MenuItem DataSource="{SelectedItem}" Command="{cmdSave}" />
+ <MenuItem DataSource="{SelectedItem}" Command="{cmdSaveAs}" />
<MenuItem Command="{CMDQuit}" />
</MenuItem>
- <MenuItem Caption="Edit" Name="edit" Width="Fit" PopWidth="100">
- <MenuItem Command="{CMDUndo}" />
- <MenuItem Command="{CMDRedo}" />
+ <MenuItem Caption="Edit" Name="edit" Width="Fit" PopWidth="100" DataSource="{CurrentSolution}">
+ <MenuItem DataSource="{SelectedItem}" Command="{cmdUndo}" />
+ <MenuItem DataSource="{SelectedItem}" Command="{cmdRedo}" />
<MenuItem Command="{CMDCut}" />
<MenuItem Command="{CMDCopy}" />
<MenuItem Command="{CMDPaste}" />
<TabItem Caption="{DisplayName}" QueryClose="OnQueryClose">
<VerticalStack>
<HorizontalStack Height="50%" >
- <SvgEditor ProjectNode="{}" Focusable="true" Name="editor"/>
+ <SvgEditor Margin="10" ProjectNode="{}" Focusable="true" Name="editor" MouseWheelSpeed="20" Foreground="Black"/>
<ScrollBar Name="scrollbarY" Value="{²../editor.ScrollY}"
- LargeIncrement="{../editor.VisibleLines}"
+ LargeIncrement="10"
CursorSize="{../editor.ChildHeightRatio}"
Maximum="{../editor.MaxScrollY}" Orientation="Vertical"
Width="14" />
</HorizontalStack>
- <ScrollBar Name="scrollbarX" Value="{²../editor.ScrollX}"
+ <ScrollBar Style="HScrollBar" Name="scrollbarX" Value="{²../editor.ScrollX}"
Maximum="{../editor.MaxScrollX}" Orientation="Horizontal"
- LargeIncrement="{../editor.VisibleColumns}"
+ LargeIncrement="10"
CursorSize="{../editor.ChildWidthRatio}"
- Height="14" />
+ Height="14" />
+ <HorizontalStack Height="Fit" Margin="3">
+ <Label Text="Zoom:"/>
+ <Label Text="{../../editor.Zoom}" Fit="true"/>
+ <!--<Spinner Name="sldZoom" Value="{²../../editor.Zoom}" Maximum="800" Minimum="1" SmallIncrement="10" LargeIncrement="50" Width="40" />-->
+ <Slider Value="{²../../editor.Zoom}" CursorSize="2" Height="8" Maximum="800" Minimum="1" SmallIncrement="1" LargeIncrement="10" Width="100" />
+ </HorizontalStack>
+
<Splitter/>
<IMLContainer Path="#Crow.Coding.ui.SourceEditor.crow"/>
<Label DataSource="{../editor.Error}" Text="{Message}"
Maximum="{../editor.MaxScrollY}" Orientation="Vertical"
Width="14" />
</HorizontalStack>
- <ScrollBar Name="scrollbarX" Value="{²../editor.ScrollX}"
+ <ScrollBar Style="HScrollBar" Name="scrollbarX" Value="{²../editor.ScrollX}"
Maximum="{../editor.MaxScrollX}" Orientation="Horizontal"
LargeIncrement="{../editor.VisibleColumns}"
CursorSize="{../editor.ChildWidthRatio}"
Maximum = "0";
Value = "0";
}
+HScrollBar {
+ Template = "#Crow.HScrollBar.template";
+ Maximum = "0";
+ Value = "0";
+}
Scroller {
CacheEnabled = "false";
}
MouseUp="{Background=hgradient|0:Gray|1:Jet}";
MouseEnter="{Foreground=Black}";
MouseLeave="{Foreground=Jet}";
+}
+HArrowBut {
+ MouseRepeat="true";
+ Height="Fit";
+ Width="Fit";
+ Focusable="true";
+ Foreground="Jet";
+ Background="vgradient|0:Gray|1:Jet";
+ MouseDown="{Background=vgradient|0:White|0.4:BlueCrayola|1:Jet}";
+ MouseUp="{Background=vgradient|0:Gray|1:Jet}";
+ MouseEnter="{Foreground=Black}";
+ MouseLeave="{Foreground=Jet}";
}
\ No newline at end of file
--- /dev/null
+<?xml version="1.0"?>
+<Border BorderWidth="1" Foreground="Jet">
+ <GenericStack Orientation="{./Orientation}" Spacing="0">
+ <Shape Style="HArrowBut" MouseDown="./onScrollBack" Path="M 0.5,5.5 L 10.5,0.5 L 10.5,10.5 Z"/>
+ <Slider Name="Slider"
+ Orientation="{./Orientation}"
+ Value="{²./Value}"
+ Maximum="{./Maximum}"
+ CursorSize="{./CursorSize}"
+ Height="{./HeightPolicy}" Width="{./WidthPolicy}"
+ LargeIncrement="{./LargeIncrement}"
+ SmallIncrement="{./SmallIncrement}"
+ CursorColor="vgradient|0:Gray|1:Jet"
+ Foreground="Jet"
+ Background="vgradient|0:DimGray|0.1:Gray|0.95:Gray|1:White"/>
+ <Shape Style="HArrowBut" MouseDown="./onScrollForth" Path="M 0.5,0.5 L 10.5,5.5 L 0.5,10.5 Z"/>
+ </GenericStack>
+</Border>
\ No newline at end of file
void onCancel(object sender, MouseButtonEventArgs e){
IFace.DeleteWidget (this);
}
+
}
}
protected double unity;
#region Public properties
- [XmlAttributeAttribute()][DefaultValue("vgradient|0:White|0,1:LightGray|0,9:LightGray|1:DimGray")]
+ [DefaultValue("vgradient|0:White|0,1:LightGray|0,9:LightGray|1:DimGray")]
public virtual Fill CursorColor {
get { return _cursorColor; }
set {
NotifyValueChanged ("CursorColor", _cursorColor);
}
}
- [XmlAttributeAttribute()][DefaultValue(20)]
+ [DefaultValue(20)]
public virtual int CursorSize {
get { return _cursorSize; }
set {
NotifyValueChanged ("CursorSize", _cursorSize);
}
}
- [XmlAttributeAttribute()][DefaultValue(Orientation.Horizontal)]
+ [DefaultValue(Orientation.Horizontal)]
public virtual Orientation Orientation
{
get { return _orientation; }
}
#endregion
- [XmlAttributeAttribute()][DefaultValue(10.0)]
+ [DefaultValue(10.0)]
public override double Maximum {
get { return base.Maximum; }
set {
MenuItem ctxMenuContainer;
protected void initContextMenus (){
ctxMenuContainer = Load ("#Crow.ContextMenu.template") as MenuItem;
+ ctxMenuContainer.LayoutChanged += CtxMenuContainer_LayoutChanged;
}
void CtxMenuContainer_LayoutChanged (object sender, LayoutingEventArgs e)
{
Rectangle r = ctxMenuContainer.ScreenCoordinates (ctxMenuContainer.Slot);
- if (e.LayoutType == LayoutingType.Width) {
+ if (e.LayoutType == LayoutingType.Width || e.LayoutType == LayoutingType.X) {
if (r.Right > this.clientRectangle.Right)
ctxMenuContainer.Left = this.clientRectangle.Right - ctxMenuContainer.Slot.Width;
- }else if (e.LayoutType == LayoutingType.Width) {
+ }else if (e.LayoutType == LayoutingType.Width || e.LayoutType == LayoutingType.Y) {
if (r.Bottom > this.clientRectangle.Bottom)
ctxMenuContainer.Top = this.clientRectangle.Bottom - ctxMenuContainer.Slot.Height;
}