diff --git a/1.0/FirstFloor.ModernUI/FirstFloor.ModernUI.App/Content/ControlsModernBBCodeBlock.xaml b/1.0/FirstFloor.ModernUI/FirstFloor.ModernUI.App/Content/ControlsModernBBCodeBlock.xaml
index 13e0d2a9..a5eb7d23 100644
--- a/1.0/FirstFloor.ModernUI/FirstFloor.ModernUI.App/Content/ControlsModernBBCodeBlock.xaml
+++ b/1.0/FirstFloor.ModernUI/FirstFloor.ModernUI.App/Content/ControlsModernBBCodeBlock.xaml
@@ -10,7 +10,7 @@
-
+
diff --git a/1.0/FirstFloor.ModernUI/FirstFloor.ModernUI.App/Content/ControlsModernBBCodeBlock.xaml.cs b/1.0/FirstFloor.ModernUI/FirstFloor.ModernUI.App/Content/ControlsModernBBCodeBlock.xaml.cs
index e25f6e5b..c6399d5b 100644
--- a/1.0/FirstFloor.ModernUI/FirstFloor.ModernUI.App/Content/ControlsModernBBCodeBlock.xaml.cs
+++ b/1.0/FirstFloor.ModernUI/FirstFloor.ModernUI.App/Content/ControlsModernBBCodeBlock.xaml.cs
@@ -1,28 +1,28 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-using System.Text;
-using System.Threading.Tasks;
-using System.Windows;
-using System.Windows.Controls;
-using System.Windows.Data;
-using System.Windows.Documents;
-using System.Windows.Input;
-using System.Windows.Media;
-using System.Windows.Media.Imaging;
-using System.Windows.Navigation;
-using System.Windows.Shapes;
-
-namespace FirstFloor.ModernUI.App.Content
-{
- ///
- /// Interaction logic for ControlsModernBBCodeBlock.xaml
- ///
- public partial class ControlsModernBBCodeBlock : UserControl
- {
- public ControlsModernBBCodeBlock()
- {
- InitializeComponent();
- }
- }
-}
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Windows;
+using System.Windows.Controls;
+using System.Windows.Data;
+using System.Windows.Documents;
+using System.Windows.Input;
+using System.Windows.Media;
+using System.Windows.Media.Imaging;
+using System.Windows.Navigation;
+using System.Windows.Shapes;
+
+namespace FirstFloor.ModernUI.App.Content
+{
+ ///
+ /// Interaction logic for ControlsModernBBCodeBlock.xaml
+ ///
+ public partial class ControlsModernBBCodeBlock : UserControl
+ {
+ public ControlsModernBBCodeBlock()
+ {
+ InitializeComponent();
+ }
+ }
+}
diff --git a/1.0/FirstFloor.ModernUI/FirstFloor.ModernUI.App/MainWindow.xaml b/1.0/FirstFloor.ModernUI/FirstFloor.ModernUI.App/MainWindow.xaml
index 48fd7f22..26d8c68e 100644
--- a/1.0/FirstFloor.ModernUI/FirstFloor.ModernUI.App/MainWindow.xaml
+++ b/1.0/FirstFloor.ModernUI/FirstFloor.ModernUI.App/MainWindow.xaml
@@ -3,8 +3,12 @@
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mui="http://firstfloorsoftware.com/ModernUI"
xmlns:app="clr-namespace:FirstFloor.ModernUI.App"
- Title="Modern UI for WPF Demo" IsTitleVisible="True"
+ Title="Modern UI for WPF Demo"
+ BBCodeTitle="[b]Modern UI[/b] for [b]WPF[/b] [i]Demo[/i]"
+ IsTitleVisible="True"
LogoData="F1 M 24.9015,43.0378L 25.0963,43.4298C 26.1685,49.5853 31.5377,54.2651 38,54.2651C 44.4623,54.2651 49.8315,49.5854 50.9037,43.4299L 51.0985,43.0379C 51.0985,40.7643 52.6921,39.2955 54.9656,39.2955C 56.9428,39.2955 58.1863,41.1792 58.5833,43.0379C 57.6384,52.7654 47.9756,61.75 38,61.75C 28.0244,61.75 18.3616,52.7654 17.4167,43.0378C 17.8137,41.1792 19.0572,39.2954 21.0344,39.2954C 23.3079,39.2954 24.9015,40.7643 24.9015,43.0378 Z M 26.7727,20.5833C 29.8731,20.5833 32.3864,23.0966 32.3864,26.197C 32.3864,29.2973 29.8731,31.8106 26.7727,31.8106C 23.6724,31.8106 21.1591,29.2973 21.1591,26.197C 21.1591,23.0966 23.6724,20.5833 26.7727,20.5833 Z M 49.2273,20.5833C 52.3276,20.5833 54.8409,23.0966 54.8409,26.197C 54.8409,29.2973 52.3276,31.8106 49.2273,31.8106C 46.127,31.8106 43.6136,29.2973 43.6136,26.197C 43.6136,23.0966 46.127,20.5833 49.2273,20.5833 Z"
+ LogoCommand="mui:LinkCommands.NavigateLink"
+ LogoCommandParameter="https://github.com/firstfloorsoftware/mui"
ContentSource="/Pages/Introduction.xaml"
Width="800" Height="700">
diff --git a/1.0/FirstFloor.ModernUI/FirstFloor.ModernUI/Themes/ModernWindow.xaml b/1.0/FirstFloor.ModernUI/FirstFloor.ModernUI/Themes/ModernWindow.xaml
index 9db7dbf2..6dd2b722 100644
--- a/1.0/FirstFloor.ModernUI/FirstFloor.ModernUI/Themes/ModernWindow.xaml
+++ b/1.0/FirstFloor.ModernUI/FirstFloor.ModernUI/Themes/ModernWindow.xaml
@@ -59,9 +59,23 @@
-
+
+
+
+
+
@@ -91,11 +105,33 @@
-
-
-
+
+
+
+
+
diff --git a/1.0/FirstFloor.ModernUI/Shared/Windows/Controls/BBCode/BBCodeLexer.cs b/1.0/FirstFloor.ModernUI/Shared/Windows/Controls/BBCode/BBCodeLexer.cs
index c228db68..560f5846 100644
--- a/1.0/FirstFloor.ModernUI/Shared/Windows/Controls/BBCode/BBCodeLexer.cs
+++ b/1.0/FirstFloor.ModernUI/Shared/Windows/Controls/BBCode/BBCodeLexer.cs
@@ -99,6 +99,17 @@ private Token Text()
return new Token(GetMark(), TokenText);
}
+ private Token EscapedTag()
+ {
+ Mark();
+ Consume();
+ while (LA(1) != '[' && LA(1) != char.MaxValue && !IsInRange(NewlineChars)) {
+ Consume();
+ }
+ var result = GetMark();
+ return new Token(result.Substring(0, 1) + result.Substring(2), TokenText);
+ }
+
private Token Attribute()
{
Match('=');
@@ -153,6 +164,9 @@ public override Token NextToken()
if (State == StateNormal) {
if (LA(1) == '[') {
+ if (LA(2) == '\\') {
+ return EscapedTag();
+ }
if (LA(2) == '/') {
return CloseTag();
}
diff --git a/1.0/FirstFloor.ModernUI/Shared/Windows/Controls/BBCode/BBCodeParser.cs b/1.0/FirstFloor.ModernUI/Shared/Windows/Controls/BBCode/BBCodeParser.cs
index 008bd085..c2bdc033 100644
--- a/1.0/FirstFloor.ModernUI/Shared/Windows/Controls/BBCode/BBCodeParser.cs
+++ b/1.0/FirstFloor.ModernUI/Shared/Windows/Controls/BBCode/BBCodeParser.cs
@@ -24,6 +24,11 @@ internal class BBCodeParser
private const string TagSize = "size";
private const string TagUnderline = "u";
private const string TagUrl = "url";
+ private const string TagStrikethrough = "s";
+ private const string TagQuote = "quote";
+ private const string TagList = "list";
+ private const string TagOrderedList = "ol";
+ private const string TagListItem = "li";
class ParseContext
{
@@ -36,8 +41,14 @@ public ParseContext(Span parent)
public FontWeight? FontWeight { get; set; }
public FontStyle? FontStyle { get; set; }
public Brush Foreground { get; set; }
+ public Brush Background { get; set; }
public TextDecorationCollection TextDecorations { get; set; }
public string NavigateUri { get; set; }
+ public bool IsList { get; set; }
+ public bool IsOrderedList { get; set; }
+ public int ListCounter { get; set; }
+ public bool IsListItem { get; set; }
+ public bool IsFirstListItem { get; set; }
///
/// Creates a run reflecting the current context settings.
@@ -58,6 +69,10 @@ public Run CreateRun(string text)
if (this.Foreground != null) {
run.Foreground = this.Foreground;
}
+ if (this.Background != null)
+ {
+ run.Background = this.Background;
+ }
run.TextDecorations = this.TextDecorations;
return run;
@@ -65,19 +80,22 @@ public Run CreateRun(string text)
}
private FrameworkElement source;
+ private Brush quoteBrush;
///
/// Initializes a new instance of the class.
///
/// The value.
/// The framework source element this parser operates in.
- public BBCodeParser(string value, FrameworkElement source)
+ /// The Brush used for quoting
+ public BBCodeParser(string value, FrameworkElement source, Brush quoteBrush = null)
: base(new BBCodeLexer(value))
{
if (source == null) {
throw new ArgumentNullException("source");
}
this.source = source;
+ this.quoteBrush = quoteBrush;
}
///
@@ -131,6 +149,10 @@ private void ParseTag(string tag, bool start, ParseContext context)
else if (tag == TagUnderline) {
context.TextDecorations = start ? TextDecorations.Underline : null;
}
+ else if (tag == TagStrikethrough)
+ {
+ context.TextDecorations = start ? TextDecorations.Strikethrough : null;
+ }
else if (tag == TagUrl) {
if (start) {
Token token = LA(1);
@@ -143,20 +165,59 @@ private void ParseTag(string tag, bool start, ParseContext context)
context.NavigateUri = null;
}
}
+ else if (tag == TagQuote) {
+ if (start) {
+ context.Background = quoteBrush;
+ }
+ else {
+ context.Background = null;
+ }
+ }
+ else if (tag == TagList) {
+ context.IsList = start;
+ context.IsFirstListItem = true;
+ }
+ else if (tag == TagOrderedList) {
+ context.IsOrderedList = start;
+ context.ListCounter = 0;
+ context.IsFirstListItem = true;
+ }
+ else if (tag == TagListItem) {
+ context.IsListItem = start;
+ }
}
private void Parse(Span span)
{
var context = new ParseContext(span);
-
+
while (true) {
Token token = LA(1);
Consume();
if (token.TokenType == BBCodeLexer.TokenStartTag) {
+ var parent = span;
+ if (token.Value == TagListItem)
+ {
+ if (context.IsFirstListItem)
+ {
+ context.IsFirstListItem = false;
+ parent.Inlines.Add(new LineBreak());
+ }
+
+ parent.Inlines.Add(
+ new Run(string.Format("\u0020\u0020{0}\u0020\u0020",
+ context.IsOrderedList ? string.Format("{0}.", ++context.ListCounter) : "\u2022")));
+ }
+
ParseTag(token.Value, true, context);
}
else if (token.TokenType == BBCodeLexer.TokenEndTag) {
+ var parent = span;
+ if (context.IsListItem && token.Value == TagListItem)
+ {
+ parent.Inlines.Add(new LineBreak());
+ }
ParseTag(token.Value, false, context);
}
else if (token.TokenType == BBCodeLexer.TokenText) {
@@ -183,10 +244,20 @@ private void Parse(Span span)
link.TargetName = parameter;
}
parent = link;
+ if (context.Foreground != null) {
+ link.Foreground = context.Foreground;
+ }
span.Inlines.Add(parent);
}
- var run = context.CreateRun(token.Value);
- parent.Inlines.Add(run);
+
+ if (context.IsListItem) {
+ parent.Inlines.Add(context.CreateRun(token.Value));
+ }
+ else {
+ var run = context.CreateRun(token.Value);
+ parent.Inlines.Add(run);
+ }
+
}
else if (token.TokenType == BBCodeLexer.TokenLineBreak) {
span.Inlines.Add(new LineBreak());
diff --git a/1.0/FirstFloor.ModernUI/Shared/Windows/Controls/BBCodeBlock.cs b/1.0/FirstFloor.ModernUI/Shared/Windows/Controls/BBCodeBlock.cs
index fb16f446..96447249 100644
--- a/1.0/FirstFloor.ModernUI/Shared/Windows/Controls/BBCodeBlock.cs
+++ b/1.0/FirstFloor.ModernUI/Shared/Windows/Controls/BBCodeBlock.cs
@@ -32,6 +32,10 @@ public class BBCodeBlock
/// Identifies the LinkNavigator dependency property.
///
public static DependencyProperty LinkNavigatorProperty = DependencyProperty.Register("LinkNavigator", typeof(ILinkNavigator), typeof(BBCodeBlock), new PropertyMetadata(new DefaultLinkNavigator(), OnLinkNavigatorChanged));
+ ///
+ /// Identifies the BBCodeQuote dependency property.
+ ///
+ public static DependencyProperty BBCodeQuoteBackgroundProperty = DependencyProperty.Register("BBCodeQuoteBackground", typeof(Brush), typeof(BBCodeBlock), new PropertyMetadata(new PropertyChangedCallback(OnBBCodeQuoteBackgroundChanged)));
private bool dirty = false;
@@ -52,6 +56,11 @@ private static void OnBBCodeChanged(DependencyObject o, DependencyPropertyChange
((BBCodeBlock)o).UpdateDirty();
}
+ private static void OnBBCodeQuoteBackgroundChanged(DependencyObject o, DependencyPropertyChangedEventArgs e)
+ {
+ ((BBCodeBlock)o).UpdateDirty();
+ }
+
private static void OnLinkNavigatorChanged(DependencyObject o, DependencyPropertyChangedEventArgs e)
{
if (e.NewValue == null) {
@@ -86,7 +95,7 @@ private void Update()
if (!string.IsNullOrWhiteSpace(bbcode)) {
Inline inline;
try {
- var parser = new BBCodeParser(bbcode, this) {
+ var parser = new BBCodeParser(bbcode, this, BBCodeQuoteBackground) {
Commands = this.LinkNavigator.Commands
};
inline = parser.Parse();
@@ -131,5 +140,16 @@ public ILinkNavigator LinkNavigator
get { return (ILinkNavigator)GetValue(LinkNavigatorProperty); }
set { SetValue(LinkNavigatorProperty, value); }
}
+
+ ///
+ /// Gets or sets the BB quote background.
+ ///
+ /// The BB code.
+ public Brush BBCodeQuoteBackground
+ {
+ get { return (Brush)GetValue(BBCodeQuoteBackgroundProperty); }
+ set { SetValue(BBCodeQuoteBackgroundProperty, value); }
+ }
+
}
}
diff --git a/1.0/FirstFloor.ModernUI/Shared/Windows/Controls/ModernWindow.cs b/1.0/FirstFloor.ModernUI/Shared/Windows/Controls/ModernWindow.cs
index cac6cddb..e3f8403e 100644
--- a/1.0/FirstFloor.ModernUI/Shared/Windows/Controls/ModernWindow.cs
+++ b/1.0/FirstFloor.ModernUI/Shared/Windows/Controls/ModernWindow.cs
@@ -41,6 +41,14 @@ public class ModernWindow
///
public static readonly DependencyProperty LogoDataProperty = DependencyProperty.Register("LogoData", typeof(Geometry), typeof(ModernWindow));
///
+ /// Identifies the LogoCommand dependency property.
+ ///
+ public static readonly DependencyProperty LogoCommandProperty = DependencyProperty.Register("LogoCommand", typeof(ICommand), typeof(ModernWindow));
+ ///
+ /// Identifies the LogoCommandParameter dependency property.
+ ///
+ public static readonly DependencyProperty LogoCommandParameterProperty = DependencyProperty.Register("LogoCommandParameter", typeof(object), typeof(ModernWindow));
+ ///
/// Defines the ContentSource dependency property.
///
public static readonly DependencyProperty ContentSourceProperty = DependencyProperty.Register("ContentSource", typeof(Uri), typeof(ModernWindow));
@@ -53,6 +61,11 @@ public class ModernWindow
///
public static DependencyProperty LinkNavigatorProperty = DependencyProperty.Register("LinkNavigator", typeof(ILinkNavigator), typeof(ModernWindow), new PropertyMetadata(new DefaultLinkNavigator()));
+ ///
+ /// Identifies the BBCodeTitle dependency property.
+ ///
+ public static DependencyProperty BBCodeTitleProperty = DependencyProperty.Register("BBCodeTitle", typeof(string), typeof(ModernWindow), new PropertyMetadata(null));
+
private Storyboard backgroundAnimation;
///
@@ -248,6 +261,24 @@ public Geometry LogoData
set { SetValue(LogoDataProperty, value); }
}
+ ///
+ /// Gets or sets the command for the logo.
+ ///
+ public ICommand LogoCommand
+ {
+ get { return (ICommand)GetValue(LogoCommandProperty); }
+ set { SetValue(LogoCommandProperty, value); }
+ }
+
+ ///
+ /// Gets or sets the command parameter for the logo.
+ ///
+ public object LogoCommandParameter
+ {
+ get { return (object)GetValue(LogoCommandParameterProperty); }
+ set { SetValue(LogoCommandParameterProperty, value); }
+ }
+
///
/// Gets or sets the source uri of the current content.
///
@@ -275,5 +306,15 @@ public ILinkNavigator LinkNavigator
get { return (ILinkNavigator)GetValue(LinkNavigatorProperty); }
set { SetValue(LinkNavigatorProperty, value); }
}
+
+ ///
+ /// Gets or sets the BBCode Title.
+ ///
+ /// The link navigator.
+ public string BBCodeTitle
+ {
+ get { return (string)GetValue(BBCodeTitleProperty); }
+ set { SetValue(BBCodeTitleProperty, value); }
+ }
}
}