Refactor MarkdownView into a more generalized RichTextView API
This commit is contained in:
Родитель
d5f31ff473
Коммит
c2f98712d0
|
@ -113,7 +113,7 @@
|
|||
<Compile Include="Xwt.GtkBackend\ExpanderBackend.cs" />
|
||||
<Compile Include="Xwt.GtkBackend\LinkLabelBackend.cs" />
|
||||
<Compile Include="Xwt.GtkBackend\SpinnerBackend.cs" />
|
||||
<Compile Include="Xwt.GtkBackend\MarkdownViewBackend.cs" />
|
||||
<Compile Include="Xwt.GtkBackend\RichTextViewBackend.cs" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
|
||||
<ItemGroup>
|
||||
|
|
|
@ -99,7 +99,7 @@ namespace Xwt.GtkBackend
|
|||
WidgetRegistry.RegisterBackend (typeof(Xwt.LinkLabel), typeof (LinkLabelBackend));
|
||||
WidgetRegistry.RegisterBackend (typeof(Xwt.Placement), typeof (BoxBackend));
|
||||
WidgetRegistry.RegisterBackend (typeof(Xwt.Spinner), typeof (SpinnerBackend));
|
||||
WidgetRegistry.RegisterBackend (typeof(Xwt.MarkdownView), typeof (MarkdownViewBackend));
|
||||
WidgetRegistry.RegisterBackend (typeof(Xwt.RichTextView), typeof (RichTextViewBackend));
|
||||
WidgetRegistry.RegisterBackend (typeof(Xwt.Expander), typeof (ExpanderBackend));
|
||||
}
|
||||
|
||||
|
|
|
@ -1,236 +0,0 @@
|
|||
//
|
||||
// MarkdownViewBackend.cs
|
||||
//
|
||||
// Author:
|
||||
// Jérémie Laval <jeremie.laval@xamarin.com>
|
||||
//
|
||||
// Copyright (c) 2012 Xamarin, Inc.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
using Xwt;
|
||||
using Xwt.Backends;
|
||||
using Xwt.Engine;
|
||||
|
||||
namespace Xwt.GtkBackend
|
||||
{
|
||||
public class MarkdownViewBackend : WidgetBackend, IMarkdownViewBackend
|
||||
{
|
||||
const string NewLine = "\n";
|
||||
Gtk.TextTagTable table;
|
||||
List<KeyValuePair<Gtk.TextChildAnchor, Gtk.Widget>> links = new List<KeyValuePair<Gtk.TextChildAnchor, Gtk.Widget>> ();
|
||||
|
||||
bool NavigateToUrlEnabled {
|
||||
get; set;
|
||||
}
|
||||
|
||||
public MarkdownViewBackend ()
|
||||
{
|
||||
Widget = new Gtk.TextView ();
|
||||
Widget.Show ();
|
||||
Widget.Editable = false;
|
||||
Widget.WrapMode = Gtk.WrapMode.Word;
|
||||
InitTagTable ();
|
||||
}
|
||||
|
||||
void InitTagTable ()
|
||||
{
|
||||
table = new Gtk.TextTagTable ();
|
||||
table.Add (new Gtk.TextTag ("bold") {
|
||||
Weight = Pango.Weight.Bold
|
||||
});
|
||||
table.Add (new Gtk.TextTag ("italic") {
|
||||
Style = Pango.Style.Italic
|
||||
});
|
||||
table.Add (new Gtk.TextTag ("tt") {
|
||||
Family = "Monospace"
|
||||
});
|
||||
table.Add (new Gtk.TextTag ("li") {
|
||||
LeftMargin = 14
|
||||
});
|
||||
table.Add (new Gtk.TextTag ("h1") {
|
||||
Weight = Pango.Weight.Bold,
|
||||
Scale = Pango.Scale.XXLarge
|
||||
});
|
||||
table.Add (new Gtk.TextTag ("h2") {
|
||||
Weight = Pango.Weight.Bold,
|
||||
Scale = Pango.Scale.XLarge
|
||||
});
|
||||
table.Add (new Gtk.TextTag ("h3") {
|
||||
Weight = Pango.Weight.Bold,
|
||||
Scale = Pango.Scale.Large
|
||||
});
|
||||
table.Add (new Gtk.TextTag ("h4") {
|
||||
Scale = Pango.Scale.Large
|
||||
});
|
||||
table.Add (new Gtk.TextTag ("pre") {
|
||||
Family = "Monospace",
|
||||
Indent = 14
|
||||
});
|
||||
}
|
||||
|
||||
protected new Gtk.TextView Widget {
|
||||
get {
|
||||
return (Gtk.TextView)base.Widget;
|
||||
}
|
||||
set {
|
||||
base.Widget = value;
|
||||
}
|
||||
}
|
||||
|
||||
public override void EnableEvent (object eventId)
|
||||
{
|
||||
base.EnableEvent (eventId);
|
||||
if (eventId is MarkdownViewEvent) {
|
||||
switch ((MarkdownViewEvent) eventId) {
|
||||
case MarkdownViewEvent.NavigateToUrl:
|
||||
NavigateToUrlEnabled = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override void DisableEvent (object eventId)
|
||||
{
|
||||
base.DisableEvent (eventId);
|
||||
if (eventId is MarkdownViewEvent) {
|
||||
switch ((MarkdownViewEvent) eventId) {
|
||||
case MarkdownViewEvent.NavigateToUrl:
|
||||
NavigateToUrlEnabled = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public object CreateBuffer ()
|
||||
{
|
||||
return new Gtk.TextBuffer (table);
|
||||
}
|
||||
|
||||
public void EmitText (object buffer, string text)
|
||||
{
|
||||
var b = ((Gtk.TextBuffer)buffer);
|
||||
var iter = b.EndIter;
|
||||
b.Insert (ref iter, text);
|
||||
}
|
||||
|
||||
public void EmitStyledText (object buffer, string text, MarkdownInlineStyle style)
|
||||
{
|
||||
var b = ((Gtk.TextBuffer)buffer);
|
||||
var iter = b.EndIter;
|
||||
var tagName = string.Empty;
|
||||
switch (style) {
|
||||
case MarkdownInlineStyle.Bold:
|
||||
tagName = "bold";
|
||||
break;
|
||||
case MarkdownInlineStyle.Italic:
|
||||
tagName = "italic";
|
||||
break;
|
||||
case MarkdownInlineStyle.Monospace:
|
||||
tagName = "tt";
|
||||
break;
|
||||
}
|
||||
if (string.IsNullOrEmpty (tagName))
|
||||
EmitText (buffer, text);
|
||||
else
|
||||
b.InsertWithTagsByName (ref iter, text, tagName);
|
||||
}
|
||||
|
||||
public void EmitHeader (object buffer, string title, int level)
|
||||
{
|
||||
var b = ((Gtk.TextBuffer)buffer);
|
||||
var iter = b.EndIter;
|
||||
b.Insert (ref iter, NewLine);
|
||||
b.InsertWithTagsByName (ref iter, title, "h" + level);
|
||||
b.Insert (ref iter, NewLine);
|
||||
}
|
||||
|
||||
public void EmitStartParagraph (object buffer)
|
||||
{
|
||||
EmitText (buffer, NewLine);
|
||||
}
|
||||
|
||||
public void EmitEndParagraph (object buffer)
|
||||
{
|
||||
EmitText (buffer, NewLine);
|
||||
}
|
||||
|
||||
public void EmitOpenList (object buffer)
|
||||
{
|
||||
EmitText (buffer, NewLine);
|
||||
}
|
||||
|
||||
public void EmitOpenBullet (object buffer)
|
||||
{
|
||||
var b = (Gtk.TextBuffer)buffer;
|
||||
var iter = b.EndIter;
|
||||
b.InsertWithTagsByName (ref iter, "• ", "li");
|
||||
}
|
||||
|
||||
public void EmitCloseBullet (object buffer)
|
||||
{
|
||||
EmitText (buffer, NewLine);
|
||||
}
|
||||
|
||||
public void EmitCloseList (object buffer)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public void EmitLink (object buffer, string href, string text)
|
||||
{
|
||||
var b = (Gtk.TextBuffer)buffer;
|
||||
var iter = b.EndIter;
|
||||
var anchor = b.CreateChildAnchor (ref iter);
|
||||
var link = new LinkLabel (text) { Uri = new Uri (href, UriKind.RelativeOrAbsolute) };
|
||||
link.NavigateToUrl += (sender, e) => {
|
||||
if (NavigateToUrlEnabled) {
|
||||
((IMarkdownViewEventSink) EventSink).OnNavigateToUrl (e.Uri);
|
||||
e.SetHandled ();
|
||||
}
|
||||
};
|
||||
var gtkWidget = (Gtk.Widget) WidgetRegistry.GetNativeWidget (link);
|
||||
links.Add (new KeyValuePair<Gtk.TextChildAnchor, Gtk.Widget> (anchor, gtkWidget));
|
||||
}
|
||||
|
||||
public void EmitCodeBlock (object buffer, string code)
|
||||
{
|
||||
var b = ((Gtk.TextBuffer)buffer);
|
||||
var iter = b.EndIter;
|
||||
b.Insert (ref iter, NewLine);
|
||||
b.InsertWithTagsByName (ref iter, code, "pre");
|
||||
}
|
||||
|
||||
public void EmitHorizontalRuler (object buffer)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public void SetBuffer (object buffer)
|
||||
{
|
||||
Widget.Buffer = (Gtk.TextBuffer)buffer;
|
||||
foreach (var l in links)
|
||||
Widget.AddChildAtAnchor (l.Value, l.Key);
|
||||
links.Clear ();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,270 @@
|
|||
//
|
||||
// RichTextViewBackend.cs
|
||||
//
|
||||
// Author:
|
||||
// Jérémie Laval <jeremie.laval@xamarin.com>
|
||||
//
|
||||
// Copyright (c) 2012 Xamarin, Inc.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
using Xwt;
|
||||
using Xwt.Backends;
|
||||
using Xwt.Engine;
|
||||
|
||||
namespace Xwt.GtkBackend
|
||||
{
|
||||
public class RichTextViewBackend : WidgetBackend, IRichTextViewBackend
|
||||
{
|
||||
Gtk.TextTagTable table;
|
||||
LinkLabel [] links;
|
||||
|
||||
bool NavigateToUrlEnabled {
|
||||
get; set;
|
||||
}
|
||||
|
||||
public RichTextViewBackend ()
|
||||
{
|
||||
Widget = new Gtk.TextView ();
|
||||
Widget.Show ();
|
||||
Widget.Editable = false;
|
||||
Widget.WrapMode = Gtk.WrapMode.Word;
|
||||
InitTagTable ();
|
||||
}
|
||||
|
||||
void InitTagTable ()
|
||||
{
|
||||
table = new Gtk.TextTagTable ();
|
||||
table.Add (new Gtk.TextTag ("bold") {
|
||||
Weight = Pango.Weight.Bold
|
||||
});
|
||||
table.Add (new Gtk.TextTag ("italic") {
|
||||
Style = Pango.Style.Italic
|
||||
});
|
||||
table.Add (new Gtk.TextTag ("tt") {
|
||||
Family = "Monospace"
|
||||
});
|
||||
table.Add (new Gtk.TextTag ("li") {
|
||||
LeftMargin = 14
|
||||
});
|
||||
table.Add (new Gtk.TextTag ("h1") {
|
||||
Weight = Pango.Weight.Bold,
|
||||
Scale = Pango.Scale.XXLarge
|
||||
});
|
||||
table.Add (new Gtk.TextTag ("h2") {
|
||||
Weight = Pango.Weight.Bold,
|
||||
Scale = Pango.Scale.XLarge
|
||||
});
|
||||
table.Add (new Gtk.TextTag ("h3") {
|
||||
Weight = Pango.Weight.Bold,
|
||||
Scale = Pango.Scale.Large
|
||||
});
|
||||
table.Add (new Gtk.TextTag ("h4") {
|
||||
Scale = Pango.Scale.Large
|
||||
});
|
||||
table.Add (new Gtk.TextTag ("pre") {
|
||||
Family = "Monospace",
|
||||
Indent = 14
|
||||
});
|
||||
}
|
||||
|
||||
protected new Gtk.TextView Widget {
|
||||
get {
|
||||
return (Gtk.TextView)base.Widget;
|
||||
}
|
||||
set {
|
||||
base.Widget = value;
|
||||
}
|
||||
}
|
||||
|
||||
public override void EnableEvent (object eventId)
|
||||
{
|
||||
base.EnableEvent (eventId);
|
||||
if (eventId is RichTextViewEvent) {
|
||||
switch ((RichTextViewEvent) eventId) {
|
||||
case RichTextViewEvent.NavigateToUrl:
|
||||
NavigateToUrlEnabled = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override void DisableEvent (object eventId)
|
||||
{
|
||||
base.DisableEvent (eventId);
|
||||
if (eventId is RichTextViewEvent) {
|
||||
switch ((RichTextViewEvent) eventId) {
|
||||
case RichTextViewEvent.NavigateToUrl:
|
||||
NavigateToUrlEnabled = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public IRichTextBuffer CreateBuffer ()
|
||||
{
|
||||
return new RichTextBuffer (table);
|
||||
}
|
||||
|
||||
public void SetBuffer (IRichTextBuffer buffer)
|
||||
{
|
||||
var buf = buffer as RichTextBuffer;
|
||||
if (buf == null)
|
||||
throw new ArgumentException ("Passed buffer is of incorrect type", "buffer");
|
||||
|
||||
if (links != null) {
|
||||
foreach (var link in links)
|
||||
link.NavigateToUrl -= HandleNavigateToUrl;
|
||||
}
|
||||
|
||||
Widget.Buffer = buf;
|
||||
links = new LinkLabel [buf.Links.Count];
|
||||
for (var i = 0; i < links.Length; i++) {
|
||||
var link = buf.Links [i];
|
||||
var label = new LinkLabel (link.Text)
|
||||
{
|
||||
Uri = link.Href
|
||||
};
|
||||
label.NavigateToUrl += HandleNavigateToUrl;
|
||||
Widget.AddChildAtAnchor ((Gtk.Widget) WidgetRegistry.GetNativeWidget (label), link.Anchor);
|
||||
links [i] = label;
|
||||
}
|
||||
}
|
||||
|
||||
void HandleNavigateToUrl (object sender, NavigateToUrlEventArgs e)
|
||||
{
|
||||
if (NavigateToUrlEnabled) {
|
||||
((IRichTextViewEventSink) EventSink).OnNavigateToUrl (e.Uri);
|
||||
e.SetHandled ();
|
||||
}
|
||||
}
|
||||
|
||||
struct Link {
|
||||
public string Text;
|
||||
public Uri Href;
|
||||
public Gtk.TextChildAnchor Anchor;
|
||||
}
|
||||
|
||||
class RichTextBuffer : Gtk.TextBuffer, IRichTextBuffer
|
||||
{
|
||||
const string NewLine = "\n";
|
||||
|
||||
public List<Link> Links {
|
||||
get; private set;
|
||||
}
|
||||
|
||||
public RichTextBuffer (Gtk.TextTagTable table) : base (table)
|
||||
{
|
||||
Links = new List<Link> ();
|
||||
}
|
||||
|
||||
public void EmitText (string text)
|
||||
{
|
||||
var iter = EndIter;
|
||||
Insert (ref iter, text);
|
||||
}
|
||||
|
||||
public void EmitStyledText (string text, RichTextInlineStyle style)
|
||||
{
|
||||
var iter = EndIter;
|
||||
var tagName = string.Empty;
|
||||
switch (style) {
|
||||
case RichTextInlineStyle.Bold:
|
||||
tagName = "bold";
|
||||
break;
|
||||
case RichTextInlineStyle.Italic:
|
||||
tagName = "italic";
|
||||
break;
|
||||
case RichTextInlineStyle.Monospace:
|
||||
tagName = "tt";
|
||||
break;
|
||||
}
|
||||
if (string.IsNullOrEmpty (tagName))
|
||||
EmitText (text);
|
||||
else
|
||||
InsertWithTagsByName (ref iter, text, tagName);
|
||||
}
|
||||
|
||||
public void EmitHeader (string title, int level)
|
||||
{
|
||||
var iter = EndIter;
|
||||
Insert (ref iter, NewLine);
|
||||
InsertWithTagsByName (ref iter, title, "h" + level);
|
||||
Insert (ref iter, NewLine);
|
||||
}
|
||||
|
||||
public void EmitStartParagraph ()
|
||||
{
|
||||
EmitText (NewLine);
|
||||
}
|
||||
|
||||
public void EmitEndParagraph ()
|
||||
{
|
||||
EmitText (NewLine);
|
||||
}
|
||||
|
||||
public void EmitOpenList ()
|
||||
{
|
||||
EmitText (NewLine);
|
||||
}
|
||||
|
||||
public void EmitOpenBullet ()
|
||||
{
|
||||
var iter = EndIter;
|
||||
InsertWithTagsByName (ref iter, "• ", "li");
|
||||
}
|
||||
|
||||
public void EmitCloseBullet ()
|
||||
{
|
||||
EmitText (NewLine);
|
||||
}
|
||||
|
||||
public void EmitCloseList ()
|
||||
{
|
||||
}
|
||||
|
||||
public void EmitLink (string href, string text)
|
||||
{
|
||||
var iter = EndIter;
|
||||
var anchor = CreateChildAnchor (ref iter);
|
||||
Links.Add (new Link ()
|
||||
{
|
||||
Text = text,
|
||||
Href = new Uri (href, UriKind.RelativeOrAbsolute),
|
||||
Anchor = anchor
|
||||
});
|
||||
}
|
||||
|
||||
public void EmitCodeBlock (string code)
|
||||
{
|
||||
var iter = EndIter;
|
||||
Insert (ref iter, NewLine);
|
||||
InsertWithTagsByName (ref iter, code, "pre");
|
||||
}
|
||||
|
||||
public void EmitHorizontalRuler ()
|
||||
{
|
||||
//FIXME
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -65,7 +65,6 @@
|
|||
<Compile Include="Xwt.WPFBackend\ComboBoxTextEntryBackend.cs" />
|
||||
<Compile Include="Xwt.WPFBackend\ExRichTextBox.cs" />
|
||||
<Compile Include="Xwt.WPFBackend\LinkLabelBackend.cs" />
|
||||
<Compile Include="Xwt.WPFBackend\MarkdownViewBackend.cs" />
|
||||
<Compile Include="Xwt.WPFBackend\PopoverBackend.cs" />
|
||||
<Compile Include="Xwt.WPFBackend\ProgressBarBackend.cs" />
|
||||
<Compile Include="Xwt.WPFBackend\CustomWidgetBackend.cs" />
|
||||
|
@ -133,6 +132,7 @@
|
|||
<Compile Include="Xwt.WPFBackend\NotebookBackend.cs" />
|
||||
<Compile Include="Xwt.WPFBackend\ScrollAdjustmentBackend.cs" />
|
||||
<Compile Include="Xwt.WPFBackend\CustomScrollViewPort.cs" />
|
||||
<Compile Include="Xwt.WPFBackend\RichTextViewBackend.cs" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
|
||||
<ItemGroup>
|
||||
|
|
|
@ -1,220 +0,0 @@
|
|||
//
|
||||
// MarkdownViewBackend.cs
|
||||
//
|
||||
// Author:
|
||||
// Alan McGovern <alan@xamarin.com>
|
||||
//
|
||||
// Copyright (c) 2012 Xamarin, Inc.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Xml;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Documents;
|
||||
using System.Windows.Markup;
|
||||
using Xwt.Backends;
|
||||
|
||||
using Xwt.WPFBackend.Utilities;
|
||||
using System.Windows.Data;
|
||||
using System.Windows.Navigation;
|
||||
|
||||
namespace Xwt.WPFBackend
|
||||
{
|
||||
class MarkdownViewBackend
|
||||
: WidgetBackend, IMarkdownViewBackend
|
||||
{
|
||||
int FontSize = 16;
|
||||
int HeaderIncrement = 8;
|
||||
|
||||
StringBuilder Builder {
|
||||
get; set;
|
||||
}
|
||||
|
||||
public new IMarkdownViewEventSink EventSink {
|
||||
get { return (IMarkdownViewEventSink) base.EventSink; }
|
||||
}
|
||||
|
||||
public new ExRichTextBox Widget
|
||||
{
|
||||
get { return (ExRichTextBox) base.Widget; }
|
||||
set { base.Widget = value; }
|
||||
}
|
||||
|
||||
XmlWriter Writer {
|
||||
get; set;
|
||||
}
|
||||
|
||||
public MarkdownViewBackend ()
|
||||
{
|
||||
Widget = new ExRichTextBox ();
|
||||
}
|
||||
|
||||
public override void EnableEvent (object eventId)
|
||||
{
|
||||
base.EnableEvent (eventId);
|
||||
if (eventId is MarkdownViewEvent) {
|
||||
switch ((MarkdownViewEvent) eventId) {
|
||||
case MarkdownViewEvent.NavigateToUrl:
|
||||
Widget.AddHandler (Hyperlink.RequestNavigateEvent, new RequestNavigateEventHandler (HyperlinkNavigated), true);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override void DisableEvent (object eventId)
|
||||
{
|
||||
base.DisableEvent (eventId);
|
||||
if (eventId is MarkdownViewEvent) {
|
||||
switch ((MarkdownViewEvent) eventId) {
|
||||
case MarkdownViewEvent.NavigateToUrl:
|
||||
Widget.RemoveHandler (Hyperlink.RequestNavigateEvent, new RequestNavigateEventHandler (HyperlinkNavigated));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void HyperlinkNavigated (object sender, System.Windows.Navigation.RequestNavigateEventArgs e)
|
||||
{
|
||||
Xwt.Engine.Toolkit.Invoke (() => {
|
||||
EventSink.OnNavigateToUrl (e.Uri);
|
||||
e.Handled = true;
|
||||
});
|
||||
}
|
||||
|
||||
object IMarkdownViewBackend.CreateBuffer ()
|
||||
{
|
||||
Builder = new StringBuilder ();
|
||||
Writer = XmlWriter.Create (Builder, new XmlWriterSettings () { OmitXmlDeclaration = true, NewLineOnAttributes = true, Indent = true, IndentChars = "\t" });
|
||||
Writer.WriteStartElement ("FlowDocument", "http://schemas.microsoft.com/winfx/2006/xaml/presentation");
|
||||
return Writer;
|
||||
}
|
||||
|
||||
void IMarkdownViewBackend.EmitText (object buffer, string text)
|
||||
{
|
||||
if (!string.IsNullOrEmpty (text))
|
||||
Writer.WriteElementString ("Run", text);
|
||||
}
|
||||
|
||||
void IMarkdownViewBackend.EmitHeader (object buffer, string title, int level)
|
||||
{
|
||||
((IMarkdownViewBackend) this).EmitStartParagraph (buffer);
|
||||
Writer.WriteStartElement ("Run");
|
||||
Writer.WriteAttributeString ("FontSize", (FontSize + HeaderIncrement * level).ToString ());
|
||||
Writer.WriteString (title);
|
||||
Writer.WriteEndElement ();
|
||||
((IMarkdownViewBackend) this).EmitEndParagraph (buffer);
|
||||
}
|
||||
|
||||
void IMarkdownViewBackend.EmitOpenList (object buffer)
|
||||
{
|
||||
Writer.WriteStartElement ("List");
|
||||
}
|
||||
|
||||
void IMarkdownViewBackend.EmitOpenBullet (object buffer)
|
||||
{
|
||||
Writer.WriteStartElement ("ListItem");
|
||||
((IMarkdownViewBackend) this).EmitStartParagraph (buffer);
|
||||
}
|
||||
|
||||
void IMarkdownViewBackend.EmitCloseBullet (object buffer)
|
||||
{
|
||||
Writer.WriteEndElement ();
|
||||
Writer.WriteEndElement ();
|
||||
}
|
||||
|
||||
void IMarkdownViewBackend.EmitCloseList (object buffer)
|
||||
{
|
||||
// Close the list
|
||||
Writer.WriteEndElement ();
|
||||
}
|
||||
|
||||
void IMarkdownViewBackend.EmitLink (object buffer, string href, string text)
|
||||
{
|
||||
Writer.WriteStartElement ("Hyperlink");
|
||||
Writer.WriteAttributeString ("NavigateUri", href);
|
||||
((IMarkdownViewBackend) this).EmitText (buffer, text);
|
||||
Writer.WriteEndElement ();
|
||||
}
|
||||
|
||||
void IMarkdownViewBackend.EmitCodeBlock (object buffer, string code)
|
||||
{
|
||||
((IMarkdownViewBackend) this).EmitStartParagraph (buffer);
|
||||
Writer.WriteAttributeString ("xml", "space", null, "preserve");
|
||||
Writer.WriteAttributeString ("TextIndent", "0");
|
||||
Writer.WriteAttributeString ("Margin", "50,0,0,0");
|
||||
Writer.WriteAttributeString ("FontFamily", "GlobalMonospace.CompositeFont");
|
||||
Writer.WriteString (code);
|
||||
((IMarkdownViewBackend) this).EmitEndParagraph (buffer);
|
||||
}
|
||||
|
||||
void IMarkdownViewBackend.SetBuffer (object buffer)
|
||||
{
|
||||
Writer.WriteEndElement ();
|
||||
Writer.Flush ();
|
||||
|
||||
if (Widget.Document != null)
|
||||
Widget.Document.ClearValue (FlowDocument.PageWidthProperty);
|
||||
Widget.Document = (FlowDocument) XamlReader.Parse (Builder.ToString ());
|
||||
Widget.Document.SetBinding (FlowDocument.PageWidthProperty, new Binding ("ActualWidth") { Source = Widget });
|
||||
Widget.IsDocumentEnabled = true;
|
||||
Widget.Document.IsEnabled = true;
|
||||
Widget.IsReadOnly = true;
|
||||
}
|
||||
|
||||
void IMarkdownViewBackend.EmitStyledText (object buffer, string text, MarkdownInlineStyle style)
|
||||
{
|
||||
switch (style) {
|
||||
case MarkdownInlineStyle.Bold:
|
||||
case MarkdownInlineStyle.Italic:
|
||||
Writer.WriteStartElement (style.ToString ());
|
||||
((IMarkdownViewBackend) this).EmitText (buffer, text);
|
||||
break;
|
||||
|
||||
case MarkdownInlineStyle.Monospace:
|
||||
Writer.WriteStartElement ("Run");
|
||||
Writer.WriteAttributeString ("FontFamily", "GlobalMonospace.CompositeFont");
|
||||
Writer.WriteString (text);
|
||||
break;
|
||||
}
|
||||
Writer.WriteEndElement ();
|
||||
}
|
||||
|
||||
void IMarkdownViewBackend.EmitStartParagraph (object buffer)
|
||||
{
|
||||
Writer.WriteStartElement ("Paragraph");
|
||||
}
|
||||
|
||||
void IMarkdownViewBackend.EmitEndParagraph (object buffer)
|
||||
{
|
||||
Writer.WriteEndElement ();
|
||||
}
|
||||
|
||||
void IMarkdownViewBackend.EmitHorizontalRuler (object buffer)
|
||||
{
|
||||
Writer.WriteStartElement("BlockUIContainer");
|
||||
Writer.WriteAttributeString ("Margin", "0,0,0,0");
|
||||
Writer.WriteElementString("Separator", "");
|
||||
Writer.WriteEndElement();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,238 @@
|
|||
//
|
||||
// RichTextViewBackend.cs
|
||||
//
|
||||
// Author:
|
||||
// Alan McGovern <alan@xamarin.com>
|
||||
//
|
||||
// Copyright (c) 2012 Xamarin, Inc.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Xml;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Documents;
|
||||
using System.Windows.Markup;
|
||||
using Xwt.Backends;
|
||||
|
||||
using Xwt.WPFBackend.Utilities;
|
||||
using System.Windows.Data;
|
||||
using System.Windows.Navigation;
|
||||
|
||||
namespace Xwt.WPFBackend
|
||||
{
|
||||
class RichTextViewBackend
|
||||
: WidgetBackend, IRichTextViewBackend
|
||||
{
|
||||
public new IRichTextViewEventSink EventSink {
|
||||
get { return (IRichTextViewEventSink) base.EventSink; }
|
||||
}
|
||||
|
||||
public new ExRichTextBox Widget
|
||||
{
|
||||
get { return (ExRichTextBox) base.Widget; }
|
||||
set { base.Widget = value; }
|
||||
}
|
||||
|
||||
public RichTextViewBackend ()
|
||||
{
|
||||
Widget = new ExRichTextBox ();
|
||||
}
|
||||
|
||||
public override void EnableEvent (object eventId)
|
||||
{
|
||||
base.EnableEvent (eventId);
|
||||
if (eventId is RichTextViewEvent) {
|
||||
switch ((RichTextViewEvent) eventId) {
|
||||
case RichTextViewEvent.NavigateToUrl:
|
||||
Widget.AddHandler (Hyperlink.RequestNavigateEvent, new RequestNavigateEventHandler (HyperlinkNavigated), true);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public override void DisableEvent (object eventId)
|
||||
{
|
||||
base.DisableEvent (eventId);
|
||||
if (eventId is RichTextViewEvent) {
|
||||
switch ((RichTextViewEvent) eventId) {
|
||||
case RichTextViewEvent.NavigateToUrl:
|
||||
Widget.RemoveHandler (Hyperlink.RequestNavigateEvent, new RequestNavigateEventHandler (HyperlinkNavigated));
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void HyperlinkNavigated (object sender, System.Windows.Navigation.RequestNavigateEventArgs e)
|
||||
{
|
||||
Xwt.Engine.Toolkit.Invoke (() => {
|
||||
EventSink.OnNavigateToUrl (e.Uri);
|
||||
e.Handled = true;
|
||||
});
|
||||
}
|
||||
|
||||
public IRichTextBuffer CreateBuffer ()
|
||||
{
|
||||
return new RichTextBuffer ();
|
||||
}
|
||||
|
||||
public void SetBuffer (IRichTextBuffer buffer)
|
||||
{
|
||||
var buf = buffer as RichTextBuffer;
|
||||
if (buf == null)
|
||||
throw new ArgumentException ("Passed buffer is of incorrect type", "buffer");
|
||||
|
||||
if (Widget.Document != null)
|
||||
Widget.Document.ClearValue (FlowDocument.PageWidthProperty);
|
||||
Widget.Document = buf.ToFlowDocument ();
|
||||
Widget.Document.SetBinding (FlowDocument.PageWidthProperty, new Binding ("ActualWidth") { Source = Widget });
|
||||
Widget.IsDocumentEnabled = true;
|
||||
Widget.Document.IsEnabled = true;
|
||||
Widget.IsReadOnly = true;
|
||||
}
|
||||
|
||||
class RichTextBuffer : IRichTextBuffer
|
||||
{
|
||||
const int FontSize = 16;
|
||||
const int HeaderIncrement = 8;
|
||||
|
||||
StringBuilder builder;
|
||||
XmlWriter writer;
|
||||
FlowDocument doc;
|
||||
|
||||
public RichTextBuffer ()
|
||||
{
|
||||
builder = new StringBuilder ();
|
||||
writer = XmlWriter.Create (builder, new XmlWriterSettings () { OmitXmlDeclaration = true, NewLineOnAttributes = true, Indent = true, IndentChars = "\t" });
|
||||
writer.WriteStartElement ("FlowDocument", "http://schemas.microsoft.com/winfx/2006/xaml/presentation");
|
||||
}
|
||||
|
||||
public void EmitText (string text)
|
||||
{
|
||||
if (!string.IsNullOrEmpty (text))
|
||||
writer.WriteElementString ("Run", text);
|
||||
}
|
||||
|
||||
public void EmitHeader (string title, int level)
|
||||
{
|
||||
EmitStartParagraph ();
|
||||
writer.WriteStartElement ("Run");
|
||||
writer.WriteAttributeString ("FontSize", (FontSize + HeaderIncrement * level).ToString ());
|
||||
writer.WriteString (title);
|
||||
writer.WriteEndElement ();
|
||||
EmitEndParagraph ();
|
||||
}
|
||||
|
||||
public void EmitOpenList ()
|
||||
{
|
||||
writer.WriteStartElement ("List");
|
||||
}
|
||||
|
||||
public void EmitOpenBullet ()
|
||||
{
|
||||
writer.WriteStartElement ("ListItem");
|
||||
EmitStartParagraph ();
|
||||
}
|
||||
|
||||
public void EmitCloseBullet ()
|
||||
{
|
||||
writer.WriteEndElement ();
|
||||
writer.WriteEndElement ();
|
||||
}
|
||||
|
||||
public void EmitCloseList ()
|
||||
{
|
||||
// Close the list
|
||||
writer.WriteEndElement ();
|
||||
}
|
||||
|
||||
public void EmitLink (string href, string text)
|
||||
{
|
||||
writer.WriteStartElement ("Hyperlink");
|
||||
writer.WriteAttributeString ("NavigateUri", href);
|
||||
EmitText (text);
|
||||
writer.WriteEndElement ();
|
||||
}
|
||||
|
||||
public void EmitCodeBlock (string code)
|
||||
{
|
||||
EmitStartParagraph ();
|
||||
writer.WriteAttributeString ("xml", "space", null, "preserve");
|
||||
writer.WriteAttributeString ("TextIndent", "0");
|
||||
writer.WriteAttributeString ("Margin", "50,0,0,0");
|
||||
writer.WriteAttributeString ("FontFamily", "GlobalMonospace.CompositeFont");
|
||||
writer.WriteString (code);
|
||||
EmitEndParagraph ();
|
||||
}
|
||||
|
||||
public void EmitStyledText (string text, RichTextInlineStyle style)
|
||||
{
|
||||
switch (style) {
|
||||
case RichTextInlineStyle.Bold:
|
||||
case RichTextInlineStyle.Italic:
|
||||
writer.WriteStartElement (style.ToString ());
|
||||
EmitText (text);
|
||||
break;
|
||||
|
||||
case RichTextInlineStyle.Monospace:
|
||||
writer.WriteStartElement ("Run");
|
||||
writer.WriteAttributeString ("FontFamily", "GlobalMonospace.CompositeFont");
|
||||
writer.WriteString (text);
|
||||
break;
|
||||
}
|
||||
writer.WriteEndElement ();
|
||||
}
|
||||
|
||||
public void EmitStartParagraph ()
|
||||
{
|
||||
writer.WriteStartElement ("Paragraph");
|
||||
}
|
||||
|
||||
public void EmitEndParagraph ()
|
||||
{
|
||||
writer.WriteEndElement ();
|
||||
}
|
||||
|
||||
public void EmitHorizontalRuler ()
|
||||
{
|
||||
writer.WriteStartElement("BlockUIContainer");
|
||||
writer.WriteAttributeString ("Margin", "0,0,0,0");
|
||||
writer.WriteElementString("Separator", "");
|
||||
writer.WriteEndElement();
|
||||
}
|
||||
|
||||
public FlowDocument ToFlowDocument ()
|
||||
{
|
||||
if (doc == null) {
|
||||
writer.WriteEndElement ();
|
||||
writer.Flush ();
|
||||
doc = (FlowDocument) XamlReader.Parse (builder.ToString ());
|
||||
builder = null;
|
||||
writer = null;
|
||||
}
|
||||
return doc;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
|
@ -94,7 +94,7 @@ namespace Xwt.WPFBackend
|
|||
WidgetRegistry.RegisterBackend (typeof (Placement), typeof (BoxBackend));
|
||||
WidgetRegistry.RegisterBackend (typeof (Popover), typeof (PopoverBackend));
|
||||
WidgetRegistry.RegisterBackend (typeof (ProgressBar), typeof (ProgressBarBackend));
|
||||
WidgetRegistry.RegisterBackend (typeof (MarkdownView), typeof (MarkdownViewBackend));
|
||||
WidgetRegistry.RegisterBackend (typeof (RichTextView), typeof (RichTextViewBackend));
|
||||
WidgetRegistry.RegisterBackend (typeof (LinkLabel), typeof (LinkLabelBackend));
|
||||
WidgetRegistry.RegisterBackend (typeof (Spinner), typeof (SpinnerBackend));
|
||||
}
|
||||
|
|
|
@ -1,67 +0,0 @@
|
|||
//
|
||||
// IMarkdownViewBackend.cs
|
||||
//
|
||||
// Author:
|
||||
// Jérémie Laval <jeremie.laval@xamarin.com>
|
||||
//
|
||||
// Copyright (c) 2012 Xamarin, Inc.
|
||||
using System;
|
||||
|
||||
namespace Xwt.Backends
|
||||
{
|
||||
[Flags]
|
||||
public enum MarkdownInlineStyle
|
||||
{
|
||||
Italic,
|
||||
Bold,
|
||||
Monospace
|
||||
}
|
||||
|
||||
public interface IMarkdownViewBackend : IWidgetBackend
|
||||
{
|
||||
object CreateBuffer ();
|
||||
|
||||
// Emit unstyled text
|
||||
void EmitText (object buffer, string text);
|
||||
|
||||
// Emit text using combination of the MarkdownInlineStyle
|
||||
void EmitStyledText (object buffer, string text, MarkdownInlineStyle style);
|
||||
|
||||
// Emit a header (h1, h2, ...)
|
||||
void EmitHeader (object buffer, string title, int level);
|
||||
|
||||
// What's outputed afterwards will be a in new paragrapgh
|
||||
void EmitStartParagraph (object buffer);
|
||||
void EmitEndParagraph (object buffer);
|
||||
|
||||
// Emit a list
|
||||
// Chain is:
|
||||
// open-list, open-bullet, <above methods>, close-bullet, close-list
|
||||
void EmitOpenList (object buffer);
|
||||
void EmitOpenBullet (object buffer);
|
||||
void EmitCloseBullet (object buffer);
|
||||
void EmitCloseList (object buffer);
|
||||
|
||||
// Emit a link displaying text and opening the href URL
|
||||
void EmitLink (object buffer, string href, string text);
|
||||
|
||||
// Emit code in a preformated blockquote
|
||||
void EmitCodeBlock (object buffer, string code);
|
||||
|
||||
// Emit an horizontal ruler
|
||||
void EmitHorizontalRuler (object buffer);
|
||||
|
||||
// Display the passed buffer
|
||||
void SetBuffer (object buffer);
|
||||
}
|
||||
|
||||
public interface IMarkdownViewEventSink : IWidgetEventSink
|
||||
{
|
||||
void OnNavigateToUrl (Uri uri);
|
||||
}
|
||||
|
||||
public enum MarkdownViewEvent
|
||||
{
|
||||
NavigateToUrl = 1
|
||||
}
|
||||
}
|
|
@ -0,0 +1,70 @@
|
|||
//
|
||||
// IMarkdownViewBackend.cs
|
||||
//
|
||||
// Author:
|
||||
// Jérémie Laval <jeremie.laval@xamarin.com>
|
||||
//
|
||||
// Copyright (c) 2012 Xamarin, Inc.
|
||||
using System;
|
||||
|
||||
namespace Xwt.Backends
|
||||
{
|
||||
[Flags]
|
||||
public enum RichTextInlineStyle
|
||||
{
|
||||
Italic,
|
||||
Bold,
|
||||
Monospace
|
||||
}
|
||||
|
||||
public interface IRichTextViewBackend : IWidgetBackend
|
||||
{
|
||||
IRichTextBuffer CreateBuffer ();
|
||||
|
||||
// Display the passed buffer
|
||||
void SetBuffer (IRichTextBuffer buffer);
|
||||
}
|
||||
|
||||
public interface IRichTextBuffer
|
||||
{
|
||||
// Emit unstyled text
|
||||
void EmitText (string text);
|
||||
|
||||
// Emit text using combination of the MarkdownInlineStyle
|
||||
void EmitStyledText (string text, RichTextInlineStyle style);
|
||||
|
||||
// Emit a header (h1, h2, ...)
|
||||
void EmitHeader (string title, int level);
|
||||
|
||||
// What's outputed afterwards will be a in new paragrapgh
|
||||
void EmitStartParagraph ();
|
||||
void EmitEndParagraph ();
|
||||
|
||||
// Emit a list
|
||||
// Chain is:
|
||||
// open-list, open-bullet, <above methods>, close-bullet, close-list
|
||||
void EmitOpenList ();
|
||||
void EmitOpenBullet ();
|
||||
void EmitCloseBullet ();
|
||||
void EmitCloseList ();
|
||||
|
||||
// Emit a link displaying text and opening the href URL
|
||||
void EmitLink (string href, string text);
|
||||
|
||||
// Emit code in a preformated blockquote
|
||||
void EmitCodeBlock (string code);
|
||||
|
||||
// Emit an horizontal ruler
|
||||
void EmitHorizontalRuler ();
|
||||
}
|
||||
|
||||
public interface IRichTextViewEventSink : IWidgetEventSink
|
||||
{
|
||||
void OnNavigateToUrl (Uri uri);
|
||||
}
|
||||
|
||||
public enum RichTextViewEvent
|
||||
{
|
||||
NavigateToUrl = 1
|
||||
}
|
||||
}
|
|
@ -1,10 +1,10 @@
|
|||
//
|
||||
// MarkdownView.cs
|
||||
// MarkdownTextFormat.cs
|
||||
//
|
||||
// Author:
|
||||
// Jérémie Laval <jeremie.laval@xamarin.com>
|
||||
// Alex Corrado <corrado@xamarin.com>
|
||||
//
|
||||
// Copyright (c) 2012 Xamarin, Inc.
|
||||
// Copyright (c) 2012 Xamarin Inc.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
|
@ -23,79 +23,25 @@
|
|||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using System.Text.RegularExpressions;
|
||||
using System.Collections.Generic;
|
||||
|
||||
using Xwt.Backends;
|
||||
|
||||
namespace Xwt
|
||||
namespace Xwt.Formats
|
||||
{
|
||||
public class MarkdownView : Widget
|
||||
public class MarkdownTextFormat : TextFormat
|
||||
{
|
||||
protected new class WidgetBackendHost : Widget.WidgetBackendHost, IMarkdownViewEventSink
|
||||
|
||||
public override void Parse (Stream input, IRichTextBuffer buffer)
|
||||
{
|
||||
public void OnNavigateToUrl (Uri uri)
|
||||
{
|
||||
((MarkdownView) Parent).OnNavigateToUrl (new NavigateToUrlEventArgs (uri));
|
||||
}
|
||||
}
|
||||
|
||||
string markdown;
|
||||
|
||||
IMarkdownViewBackend Backend {
|
||||
get { return (IMarkdownViewBackend) BackendHost.Backend; }
|
||||
}
|
||||
|
||||
public string Markdown
|
||||
{
|
||||
get
|
||||
{
|
||||
return markdown;
|
||||
}
|
||||
set
|
||||
{
|
||||
markdown = value;
|
||||
object buffer = ParseMarkdown (value);
|
||||
Backend.SetBuffer (buffer);
|
||||
}
|
||||
}
|
||||
|
||||
EventHandler<NavigateToUrlEventArgs> navigateToUrl;
|
||||
public event EventHandler<NavigateToUrlEventArgs> NavigateToUrl
|
||||
{
|
||||
add
|
||||
{
|
||||
BackendHost.OnBeforeEventAdd (MarkdownViewEvent.NavigateToUrl, navigateToUrl);
|
||||
navigateToUrl += value;
|
||||
}
|
||||
remove
|
||||
{
|
||||
navigateToUrl -= value;
|
||||
BackendHost.OnAfterEventRemove (MarkdownViewEvent.NavigateToUrl, navigateToUrl);
|
||||
}
|
||||
}
|
||||
|
||||
public MarkdownView ()
|
||||
{
|
||||
NavigateToUrl += delegate { }; // ensure the virtual method is always called
|
||||
Markdown = string.Empty;
|
||||
}
|
||||
|
||||
protected override BackendHost CreateBackendHost ()
|
||||
{
|
||||
return new WidgetBackendHost ();
|
||||
}
|
||||
|
||||
protected virtual void OnNavigateToUrl (NavigateToUrlEventArgs e)
|
||||
{
|
||||
if (navigateToUrl != null)
|
||||
navigateToUrl (this, e);
|
||||
|
||||
if (!e.Handled)
|
||||
Application.EngineBackend.ShowWebBrowser (e);
|
||||
using (var reader = new StreamReader (input))
|
||||
ParseMarkdown (reader.ReadToEnd (), buffer);
|
||||
}
|
||||
|
||||
/* The subset we support:
|
||||
|
@ -108,10 +54,9 @@ namespace Xwt
|
|||
* - Inline code is wrapped between the '`' character
|
||||
* - horizontal ruler, a line with at least 3 hyphens
|
||||
*/
|
||||
object ParseMarkdown (string markdown)
|
||||
void ParseMarkdown (string markdown, IRichTextBuffer buffer)
|
||||
{
|
||||
var lines = markdown.Replace ("\r\n", "\n").Split (new[] { '\n' });
|
||||
var buffer = Backend.CreateBuffer ();
|
||||
var wasParagraph = false;
|
||||
|
||||
for (int i = 0; i < lines.Length; i++) {
|
||||
|
@ -119,7 +64,7 @@ namespace Xwt
|
|||
// New paragraph
|
||||
if (string.IsNullOrWhiteSpace (line)) {
|
||||
if (wasParagraph) {
|
||||
Backend.EmitEndParagraph (buffer);
|
||||
buffer.EmitEndParagraph ();
|
||||
wasParagraph = false;
|
||||
}
|
||||
}
|
||||
|
@ -127,7 +72,7 @@ namespace Xwt
|
|||
// Title
|
||||
else if (line.StartsWith ("#")) {
|
||||
var level = line.TakeWhile (c => c == '#').Count ();
|
||||
Backend.EmitHeader (buffer, line.Trim (' ', '#'), level);
|
||||
buffer.EmitHeader (line.Trim (' ', '#'), level);
|
||||
}
|
||||
|
||||
// Title (setex-style)
|
||||
|
@ -142,15 +87,15 @@ namespace Xwt
|
|||
// must close the paragraph containing 'FooBarBaz' first. Or we should disallow this construct
|
||||
if (wasParagraph) {
|
||||
wasParagraph = false;
|
||||
Backend.EmitEndParagraph (buffer);
|
||||
buffer.EmitEndParagraph ();
|
||||
}
|
||||
Backend.EmitHeader (buffer, line, level);
|
||||
buffer.EmitHeader (line, level);
|
||||
i++;
|
||||
}
|
||||
|
||||
// Ruler
|
||||
else if (line.All (c => c == '-') && line.Length >= 3) {
|
||||
Backend.EmitHorizontalRuler (buffer);
|
||||
buffer.EmitHorizontalRuler ();
|
||||
}
|
||||
|
||||
// Code blocks
|
||||
|
@ -164,32 +109,32 @@ namespace Xwt
|
|||
}
|
||||
i--;
|
||||
if (wasParagraph) {
|
||||
Backend.EmitEndParagraph (buffer);
|
||||
buffer.EmitEndParagraph ();
|
||||
wasParagraph = false;
|
||||
}
|
||||
Backend.EmitCodeBlock (buffer, codeblock.Replace ("\n", Environment.NewLine).ToString ());
|
||||
buffer.EmitCodeBlock (codeblock.Replace ("\n", Environment.NewLine).ToString ());
|
||||
}
|
||||
|
||||
// List
|
||||
else if (new[] { '+', '-', '*' }.Contains (line.TrimStart()[0])) {
|
||||
Backend.EmitOpenList (buffer);
|
||||
buffer.EmitOpenList ();
|
||||
var bullet = line[0].ToString ();
|
||||
for (; i < lines.Length; i++) {
|
||||
line = lines[i];
|
||||
if (!line.StartsWith (bullet))
|
||||
break;
|
||||
Backend.EmitOpenBullet (buffer);
|
||||
buffer.EmitOpenBullet ();
|
||||
ParseText (buffer, line.TrimStart (' ', '-'));
|
||||
Backend.EmitCloseBullet (buffer);
|
||||
buffer.EmitCloseBullet ();
|
||||
}
|
||||
i--;
|
||||
Backend.EmitCloseList (buffer);
|
||||
buffer.EmitCloseList ();
|
||||
}
|
||||
|
||||
// Normal paragraph
|
||||
else {
|
||||
if (!wasParagraph)
|
||||
Backend.EmitStartParagraph (buffer);
|
||||
buffer.EmitStartParagraph ();
|
||||
ParseText (buffer, line);
|
||||
wasParagraph = true;
|
||||
}
|
||||
|
@ -197,12 +142,10 @@ namespace Xwt
|
|||
|
||||
// If we don't end in a newline we need to end the open paragrah
|
||||
if (wasParagraph)
|
||||
Backend.EmitEndParagraph (buffer);
|
||||
|
||||
return buffer;
|
||||
buffer.EmitEndParagraph ();
|
||||
}
|
||||
|
||||
void ParseText (object buffer, string line)
|
||||
void ParseText (IRichTextBuffer buffer, string line)
|
||||
{
|
||||
// First transform any embedded URL into a proper format
|
||||
line = autoUrl.Replace (line, m => string.Format ("[{0}]({1})", m.Value, m.Value));
|
||||
|
@ -213,34 +156,34 @@ namespace Xwt
|
|||
while (match.Success) {
|
||||
var text = line.Substring (currentIndex, match.Index - currentIndex);
|
||||
if (!string.IsNullOrEmpty (text))
|
||||
Backend.EmitText (buffer, text);
|
||||
buffer.EmitText (text);
|
||||
// Emphasis
|
||||
if (match.Groups["char"].Success) {
|
||||
MarkdownInlineStyle style = 0;
|
||||
RichTextInlineStyle style = 0;
|
||||
switch (match.Groups["char"].Value[0]) {
|
||||
case '*':
|
||||
style |= MarkdownInlineStyle.Bold;
|
||||
style |= RichTextInlineStyle.Bold;
|
||||
break;
|
||||
case '_':
|
||||
style |= MarkdownInlineStyle.Italic;
|
||||
style |= RichTextInlineStyle.Italic;
|
||||
break;
|
||||
case '`':
|
||||
style |= MarkdownInlineStyle.Monospace;
|
||||
style |= RichTextInlineStyle.Monospace;
|
||||
break;
|
||||
}
|
||||
Backend.EmitStyledText (buffer, match.Groups["emph"].Value, style);
|
||||
buffer.EmitStyledText (match.Groups["emph"].Value, style);
|
||||
}
|
||||
// Link
|
||||
else {
|
||||
var url = match.Groups["url"].Value;
|
||||
var name = match.Groups["name"].Value;
|
||||
Backend.EmitLink (buffer, url, name);
|
||||
buffer.EmitLink (url, name);
|
||||
}
|
||||
currentIndex = match.Index + match.Length;
|
||||
match = match.NextMatch ();
|
||||
}
|
||||
// Add remaining text
|
||||
Backend.EmitText (buffer, line.Substring (currentIndex));
|
||||
buffer.EmitText (line.Substring (currentIndex));
|
||||
}
|
||||
|
||||
static Regex richText = new Regex (@"\[(?<name>.+)\]\((?<url>.+)\)
|
|
@ -0,0 +1,42 @@
|
|||
//
|
||||
// TextFormat.cs
|
||||
//
|
||||
// Author:
|
||||
// Alex Corrado <corrado@xamarin.com>
|
||||
//
|
||||
// Copyright (c) 2012 Xamarin Inc.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
|
||||
using Xwt.Backends;
|
||||
|
||||
namespace Xwt.Formats
|
||||
{
|
||||
public abstract class TextFormat
|
||||
{
|
||||
public static readonly TextFormat Markdown = new MarkdownTextFormat ();
|
||||
|
||||
// Parses the given input stream into the given buffer
|
||||
public abstract void Parse (Stream input, IRichTextBuffer buffer);
|
||||
}
|
||||
}
|
||||
|
|
@ -351,15 +351,17 @@
|
|||
<SubType>Component</SubType>
|
||||
</Compile>
|
||||
<Compile Include="Xwt.Backends\ISpinnerBackend.cs" />
|
||||
<Compile Include="Xwt.Backends\IMarkdownViewBackend.cs" />
|
||||
<Compile Include="Xwt\MarkdownView.cs">
|
||||
<SubType>Component</SubType>
|
||||
</Compile>
|
||||
<Compile Include="Xwt\CloseRequestedHandler.cs" />
|
||||
<Compile Include="Xwt\CloseRequestedEventArgs.cs" />
|
||||
<Compile Include="Xwt\WrapMode.cs" />
|
||||
<Compile Include="Xwt\XwtTaskScheduler.cs" />
|
||||
<Compile Include="Xwt\ExceptionEventArgs.cs" />
|
||||
<Compile Include="Xwt\RichTextView.cs">
|
||||
<SubType>Component</SubType>
|
||||
</Compile>
|
||||
<Compile Include="Xwt.Backends\IRichTextViewBackend.cs" />
|
||||
<Compile Include="Xwt.Formats\TextFormat.cs" />
|
||||
<Compile Include="Xwt.Formats\MarkdownTextFormat.cs" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
|
||||
<ItemGroup />
|
||||
|
@ -372,4 +374,7 @@
|
|||
</Properties>
|
||||
</MonoDevelop>
|
||||
</ProjectExtensions>
|
||||
<ItemGroup>
|
||||
<Folder Include="Xwt.Formats\" />
|
||||
</ItemGroup>
|
||||
</Project>
|
|
@ -0,0 +1,128 @@
|
|||
//
|
||||
// RichTextView.cs
|
||||
//
|
||||
// Author:
|
||||
// Jérémie Laval <jeremie.laval@xamarin.com>
|
||||
// Alex Corrado <corrado@xamarin.com>
|
||||
//
|
||||
// Copyright (c) 2012 Xamarin, Inc.
|
||||
//
|
||||
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
// of this software and associated documentation files (the "Software"), to deal
|
||||
// in the Software without restriction, including without limitation the rights
|
||||
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
// copies of the Software, and to permit persons to whom the Software is
|
||||
// furnished to do so, subject to the following conditions:
|
||||
//
|
||||
// The above copyright notice and this permission notice shall be included in
|
||||
// all copies or substantial portions of the Software.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
// THE SOFTWARE.
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
using Xwt.Backends;
|
||||
using Xwt.Formats;
|
||||
|
||||
namespace Xwt
|
||||
{
|
||||
public class RichTextView : Widget
|
||||
{
|
||||
protected new class WidgetBackendHost : Widget.WidgetBackendHost, IRichTextViewEventSink
|
||||
{
|
||||
public void OnNavigateToUrl (Uri uri)
|
||||
{
|
||||
((RichTextView) Parent).OnNavigateToUrl (new NavigateToUrlEventArgs (uri));
|
||||
}
|
||||
}
|
||||
|
||||
IRichTextViewBackend Backend {
|
||||
get { return (IRichTextViewBackend) BackendHost.Backend; }
|
||||
}
|
||||
|
||||
EventHandler<NavigateToUrlEventArgs> navigateToUrl;
|
||||
public event EventHandler<NavigateToUrlEventArgs> NavigateToUrl
|
||||
{
|
||||
add
|
||||
{
|
||||
BackendHost.OnBeforeEventAdd (RichTextViewEvent.NavigateToUrl, navigateToUrl);
|
||||
navigateToUrl += value;
|
||||
}
|
||||
remove
|
||||
{
|
||||
navigateToUrl -= value;
|
||||
BackendHost.OnAfterEventRemove (RichTextViewEvent.NavigateToUrl, navigateToUrl);
|
||||
}
|
||||
}
|
||||
|
||||
public RichTextView ()
|
||||
{
|
||||
NavigateToUrl += delegate { }; // ensure the virtual method is always called
|
||||
}
|
||||
|
||||
public void LoadFile (string fileName, TextFormat format)
|
||||
{
|
||||
using (var stream = new FileStream (fileName, FileMode.Open, FileAccess.Read))
|
||||
LoadStream (stream, format);
|
||||
}
|
||||
|
||||
public void LoadText (string text, TextFormat format)
|
||||
{
|
||||
using (var stream = new MemoryStream (Encoding.UTF8.GetBytes (text), false))
|
||||
LoadStream (stream, format);
|
||||
}
|
||||
|
||||
public virtual void LoadStream (Stream input, TextFormat format)
|
||||
{
|
||||
var buffer = Backend.CreateBuffer ();
|
||||
format.Parse (input, buffer);
|
||||
Backend.SetBuffer (buffer);
|
||||
}
|
||||
|
||||
protected override BackendHost CreateBackendHost ()
|
||||
{
|
||||
return new WidgetBackendHost ();
|
||||
}
|
||||
|
||||
protected virtual void OnNavigateToUrl (NavigateToUrlEventArgs e)
|
||||
{
|
||||
if (navigateToUrl != null)
|
||||
navigateToUrl (this, e);
|
||||
|
||||
if (!e.Handled)
|
||||
Application.EngineBackend.ShowWebBrowser (e);
|
||||
}
|
||||
}
|
||||
|
||||
public class MarkdownView : RichTextView
|
||||
{
|
||||
string markdown;
|
||||
public string Markdown
|
||||
{
|
||||
get
|
||||
{
|
||||
return markdown;
|
||||
}
|
||||
set
|
||||
{
|
||||
markdown = value;
|
||||
LoadText (value, TextFormat.Markdown);
|
||||
}
|
||||
}
|
||||
|
||||
public MarkdownView ()
|
||||
{
|
||||
Markdown = string.Empty;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Загрузка…
Ссылка в новой задаче