diff --git a/samples/TestApplication/App.cs b/samples/TestApplication/App.cs index 8f3a2451d9..6c3ae2f2b7 100644 --- a/samples/TestApplication/App.cs +++ b/samples/TestApplication/App.cs @@ -12,8 +12,9 @@ namespace TestApplication public App() { RegisterServices(); - InitializeSubsystems((int)Environment.OSVersion.Platform); + InitializeSubsystems((int)Environment.OSVersion.Platform); Styles = new DefaultTheme(); + Styles.Add(new SampleTabStyle()); } } } diff --git a/samples/TestApplication/GalleryStyle.cs b/samples/TestApplication/GalleryStyle.cs new file mode 100644 index 0000000000..15cbb5749b --- /dev/null +++ b/samples/TestApplication/GalleryStyle.cs @@ -0,0 +1,123 @@ +using Perspex; +using Perspex.Controls; +using Perspex.Controls.Presenters; +using Perspex.Controls.Primitives; +using Perspex.Controls.Templates; +using Perspex.Media; +using Perspex.Styling; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace TestApplication +{ + internal class SampleTabStyle : Styles + { + public SampleTabStyle() + { + this.AddRange(new[] + { + new Style (s => s.Class(":container").OfType ()) + { + Setters = new[] + { + new Setter (TemplatedControl.TemplateProperty, new ControlTemplate (TabControlTemplate)) + } + }, + + new Style(s => s.Class(":container").OfType().Child().Child().Child().Child().Child().OfType()) + { + Setters = new[] + { + new Setter (TemplatedControl.TemplateProperty, new ControlTemplate (TabItemTemplate)), + } + }, + + new Style(s => s.Name("internalStrip").OfType().Child().OfType()) + { + Setters = new[] + { + new Setter(TemplatedControl.FontSizeProperty, 14.0), + new Setter(TemplatedControl.ForegroundProperty, Brushes.White) + } + }, + + new Style(s => s.Name("internalStrip").OfType().Child().OfType().Class("selected")) + { + Setters = new[] + { + new Setter(TemplatedControl.ForegroundProperty, Brushes.White), + new Setter(TemplatedControl.BackgroundProperty, new SolidColorBrush(Colors.White) { Opacity = 0.1 }), + }, + }, + }); + } + + public static Control TabItemTemplate(TabItem control) + { + return new ContentPresenter + { + DataTemplates = new DataTemplates + { + new DataTemplate(x => new Border + { + [~Border.BackgroundProperty] = control[~TemplatedControl.BackgroundProperty], + Padding = new Thickness(10), + Child = new TextBlock + { + VerticalAlignment = Perspex.Layout.VerticalAlignment.Center, + Text = x + } + }) + }, + Name = "headerPresenter", + [~ContentPresenter.ContentProperty] = control[~HeaderedContentControl.HeaderProperty], + }; + } + + public static Control TabControlTemplate(TabControl control) + { + return new Grid + { + ColumnDefinitions = new ColumnDefinitions + { + new ColumnDefinition(GridLength.Auto), + new ColumnDefinition(new GridLength(1, GridUnitType.Star)), + }, + Children = new Controls + { + new Border + { + Width = 190, + Background = SolidColorBrush.Parse("#1976D2"), + Child = new ScrollViewer + { + Content = new TabStrip + { + ItemsPanel = new FuncTemplate(() => new StackPanel { Orientation = Orientation.Vertical, Gap = 4 }), + Margin = new Thickness(0, 10, 0, 0), + Name = "internalStrip", + [!ItemsControl.ItemsProperty] = control[!ItemsControl.ItemsProperty], + [!!SelectingItemsControl.SelectedItemProperty] = control[!!SelectingItemsControl.SelectedItemProperty], + } + } + }, + new Deck + { + Name = "deck", + DataTemplates = new DataTemplates + { + new DataTemplate(x => (Control)control.MaterializeDataTemplate(x.Content)), + }, + [~Deck.TransitionProperty] = control[~TabControl.TransitionProperty], + [!ItemsControl.ItemsProperty] = control[!ItemsControl.ItemsProperty], + [!SelectingItemsControl.SelectedItemProperty] = control[!SelectingItemsControl.SelectedItemProperty], + [Grid.ColumnProperty] = 1, + } + } + }; + } + } +} \ No newline at end of file diff --git a/samples/TestApplication/Item.cs b/samples/TestApplication/Item.cs new file mode 100644 index 0000000000..4898274686 --- /dev/null +++ b/samples/TestApplication/Item.cs @@ -0,0 +1,8 @@ +namespace TestApplication +{ + internal class Item + { + public string Name { get; set; } + public string Value { get; set; } + } +} diff --git a/samples/TestApplication/Node.cs b/samples/TestApplication/Node.cs new file mode 100644 index 0000000000..2856598ad6 --- /dev/null +++ b/samples/TestApplication/Node.cs @@ -0,0 +1,16 @@ +using Perspex.Collections; + +namespace TestApplication +{ + internal class Node + { + public Node() + { + Children = new PerspexList(); + } + + public string Name { get; set; } + public PerspexList Children { get; set; } + } + +} diff --git a/samples/TestApplication/Program.cs b/samples/TestApplication/Program.cs index 54f7686e8c..f77ecd0ef8 100644 --- a/samples/TestApplication/Program.cs +++ b/samples/TestApplication/Program.cs @@ -2,6 +2,7 @@ // Licensed under the MIT license. See licence.md file in the project root for full license information. using System; +using System.Linq; using System.IO; using System.Reactive.Linq; using Perspex; @@ -23,23 +24,6 @@ using ReactiveUI; namespace TestApplication { - internal class Item - { - public string Name { get; set; } - public string Value { get; set; } - } - - internal class Node - { - public Node() - { - Children = new PerspexList(); - } - - public string Name { get; set; } - public PerspexList Children { get; set; } - } - internal class Program { private static readonly PerspexList s_treeData = new PerspexList @@ -94,17 +78,11 @@ namespace TestApplication private static void Main(string[] args) { - //Log.Logger = new LoggerConfiguration() - // .Filter.ByIncludingOnly(Matching.WithProperty("Area", "Layout")) - // .MinimumLevel.Verbose() - // .WriteTo.Trace(outputTemplate: "[{Id:X8}] [{SourceContext}] {Message}") - // .CreateLogger(); - // The version of ReactiveUI currently included is for WPF and so expects a WPF // dispatcher. This makes sure it's initialized. System.Windows.Threading.Dispatcher foo = System.Windows.Threading.Dispatcher.CurrentDispatcher; - App application = new App + new App { DataTemplates = new DataTemplates { @@ -115,15 +93,13 @@ namespace TestApplication }, }; - TextBlock fps; - - var testCommand = ReactiveCommand.Create(); - testCommand.Subscribe(_ => System.Diagnostics.Debug.WriteLine("Test command executed.")); + TabControl container; Window window = new Window { Title = "Perspex Test Application", - SizeToContent = SizeToContent.WidthAndHeight, + Width = 900, + Height = 480, Content = new Grid { ColumnDefinitions = new ColumnDefinitions @@ -139,126 +115,28 @@ namespace TestApplication }, Children = new Controls { - new Menu - { - Items = new[] - { - new MenuItem - { - Header = "_File", - Items = new[] - { - new MenuItem - { - Header = "_Open...", - Icon = new Image - { - Source = new Bitmap("github_icon.png"), - }, - }, - new MenuItem - { - Header = "_Save", - Items = new[] - { - new MenuItem - { - Header = "Sub Item _1", - }, - new MenuItem - { - Header = "Sub Item _2", - }, - } - }, - new MenuItem - { - Header = "Save _As", - Items = new[] - { - new MenuItem - { - Header = "Sub Item _1", - }, - new MenuItem - { - Header = "Sub Item _2", - }, - } - }, - new MenuItem - { - Header = "E_xit", - Command = testCommand, - }, - } - }, - new MenuItem - { - Header = "_Edit", - Items = new[] - { - new MenuItem - { - Header = "Cu_t", - }, - new MenuItem - { - Header = "_Copy", - }, - new MenuItem - { - Header = "_Paste", - }, - } - } - }, - [Grid.ColumnSpanProperty] = 2, - }, - new TabControl + (container = new TabControl { + Padding = new Thickness(5), Items = new[] { ButtonsTab(), TextTab(), HtmlTab(), - ImagesTab(), + ImagesTab(), ListsTab(), LayoutTab(), AnimationsTab(), }, - Transition = new PageSlide(TimeSpan.FromSeconds(0.25)), + Transition = new CrossFade(TimeSpan.FromSeconds(0.25)), [Grid.RowProperty] = 1, [Grid.ColumnSpanProperty] = 2, - }, - (fps = new TextBlock - { - HorizontalAlignment = HorizontalAlignment.Left, - Margin = new Thickness(2), - [Grid.RowProperty] = 2, - }), - new TextBlock - { - Text = "Press F12 for Dev Tools", - HorizontalAlignment = HorizontalAlignment.Right, - Margin = new Thickness(2), - [Grid.ColumnProperty] = 1, - [Grid.RowProperty] = 2, - }, + }) } }, }; - DevTools.Attach(window); - - //var renderer = ((IRenderRoot)window).Renderer; - //var last = renderer.RenderCount; - //DispatcherTimer.Run(() => - //{ - // fps.Text = "FPS: " + (renderer.RenderCount - last); - // last = renderer.RenderCount; - // return true; - //}, TimeSpan.FromSeconds(1)); + container.Classes.Add(":container"); window.Show(); Application.Current.Run(window); @@ -266,319 +144,540 @@ namespace TestApplication private static TabItem ButtonsTab() { - Button defaultButton; - - var showDialog = ReactiveCommand.Create(); - Button showDialogButton; - var result = new TabItem { - Header = "Buttons", - Content = new StackPanel - { - Orientation = Orientation.Vertical, - HorizontalAlignment = HorizontalAlignment.Center, - VerticalAlignment = VerticalAlignment.Center, - Gap = 8, - MinWidth = 120, - Children = new Controls - { - (showDialogButton = new Button - { - Content = "Button", - Command = showDialog, - [ToolTip.TipProperty] = "Hello World!", - }), - new Button - { - Content = "Button", - Background = new SolidColorBrush(0xcc119eda), - [ToolTip.TipProperty] = "Goodbye Cruel World!", - }, - (defaultButton = new Button - { - Content = "Default", - IsDefault = true, - }), - new Button - { - Content = "Disabled", - IsEnabled = false, - }, - new Button - { - Content = "Disabled", - IsEnabled = false, - Background = new SolidColorBrush(0xcc119eda), - }, - new ToggleButton - { - Content = "Toggle", - }, - new ToggleButton - { - Content = "Disabled", - IsEnabled = false, - }, - new CheckBox - { - Content = "Checkbox", - }, - new RadioButton - { - Content = "RadioButton 1", - IsChecked = true, - }, - new RadioButton - { - Content = "RadioButton 2", - }, - } + Header = "Button", + Content = new ScrollViewer() + { + CanScrollHorizontally = false, + Content = new StackPanel + { + Margin = new Thickness(10), + Orientation = Orientation.Vertical, + Gap = 4, + Children = new Controls + { + new TextBlock + { + Text = "Button", + FontWeight = FontWeight.Medium, + FontSize = 20, + Foreground = SolidColorBrush.Parse("#212121"), + }, + new TextBlock + { + Text = "A button control", + FontSize = 13, + Foreground = SolidColorBrush.Parse("#727272"), + Margin = new Thickness(0, 0, 0, 10) + }, + new Button + { + Width = 150, + Content = "Button" + }, + new Button + { + Width = 150, + Content = "Disabled", + IsEnabled = false, + }, + new TextBlock + { + Margin = new Thickness(0, 40, 0, 0), + Text = "ToggleButton", + FontWeight = FontWeight.Medium, + FontSize = 20, + Foreground = SolidColorBrush.Parse("#212121"), + }, + new TextBlock + { + Text = "A toggle button control", + FontSize = 13, + Foreground = SolidColorBrush.Parse("#727272"), + Margin = new Thickness(0, 0, 0, 10) + }, + new ToggleButton + { + Width = 150, + IsChecked = true, + Content = "On" + }, + new ToggleButton + { + Width = 150, + IsChecked = false, + Content = "Off" + }, + } + } }, }; - - defaultButton.Click += (s, e) => - { - defaultButton.Content = ((string)defaultButton.Content == "Default") ? "Clicked" : "Default"; - }; - - showDialog.Subscribe(async _ => - { - var close = ReactiveCommand.Create(); - - var dialog = new Window - { - Content = new StackPanel - { - Width = 200, - Height = 200, - Children = new Controls - { - new Button { Content = "Yes", Command = close, CommandParameter = "Yes" }, - new Button { Content = "No", Command = close, CommandParameter = "No" }, - } - } - }; - - close.Subscribe(x => dialog.Close(x)); - - showDialogButton.Content = await dialog.ShowDialog(); - }); + return result; } private static TabItem HtmlTab() - { - var htmlText = - new StreamReader(typeof (Program).Assembly.GetManifestResourceStream("TestApplication.html.htm")) - .ReadToEnd(); - return new TabItem - { - Header = "Html", - Content = new ScrollViewer() - { - Width = 600, - MaxHeight = 600, - HorizontalAlignment = HorizontalAlignment.Center, - CanScrollHorizontally = false, - VerticalScrollBarVisibility = ScrollBarVisibility.Visible, - Content = - new HtmlLabel() - { - Text = htmlText - } - } - }; - } - - private static TabItem TextTab() { return new TabItem { Header = "Text", - Content = new StackPanel - { - Orientation = Orientation.Vertical, - HorizontalAlignment = HorizontalAlignment.Center, - VerticalAlignment = VerticalAlignment.Center, - Gap = 8, - Width = 120, - Children = new Controls - { - new TextBlock - { - Text = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Proin venenatis dui quis libero suscipit tincidunt.", - TextWrapping = TextWrapping.Wrap, - TextAlignment = TextAlignment.Center, - }, - new TextBlock - { - Text = "Italic text.", - FontStyle = FontStyle.Italic, - TextAlignment = TextAlignment.Left, - }, - new TextBlock - { - Text = "Bold text.", - FontWeight = FontWeight.Bold, - TextAlignment = TextAlignment.Right, - }, - new TextBox - { - Text = "A non-wrapping text box. Lorem ipsum dolor sit amet.", - TextWrapping = TextWrapping.NoWrap, - }, - new TextBox - { - AcceptsReturn = true, - Text = "A wrapping text box. " + - "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Proin venenatis dui quis libero suscipit tincidunt. " + - "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Proin venenatis dui quis libero suscipit tincidunt.", - TextWrapping = TextWrapping.Wrap, - MaxHeight = 100, - }, - } - }, + Content = new ScrollViewer() + { + CanScrollHorizontally = false, + Content = new StackPanel() + { + Margin = new Thickness(10), + Orientation = Orientation.Vertical, + Gap = 4, + Children = new Controls + { + new TextBlock + { + Text = "TextBlock", + FontWeight = FontWeight.Medium, + FontSize = 20, + Foreground = SolidColorBrush.Parse("#212121"), + }, + new TextBlock + { + Text = "A control for displaying text.", + FontSize = 13, + Foreground = SolidColorBrush.Parse("#727272"), + Margin = new Thickness(0, 0, 0, 10) + }, + new TextBlock + { + Text = "Lorem ipsum dolor sit amet, consectetuer adipiscing elit.", + FontSize = 11 + }, + new TextBlock + { + Text = "Lorem ipsum dolor sit amet, consectetuer adipiscing elit.", + FontSize = 11, + FontWeight = FontWeight.Medium + }, + new TextBlock + { + Text = "Lorem ipsum dolor sit amet, consectetuer adipiscing elit.", + FontSize = 11, + FontWeight = FontWeight.Bold + }, + new TextBlock + { + Text = "Lorem ipsum dolor sit amet, consectetuer adipiscing elit.", + FontSize = 11, + FontStyle = FontStyle.Italic, + }, + new TextBlock + { + Margin = new Thickness(0, 40, 0, 0), + Text = "HtmlLabel", + FontWeight = FontWeight.Medium, + FontSize = 20, + Foreground = SolidColorBrush.Parse("#212121"), + }, + new TextBlock + { + Text = "A label capable of displaying HTML content", + FontSize = 13, + Foreground = SolidColorBrush.Parse("#727272"), + Margin = new Thickness(0, 0, 0, 10) + }, + new HtmlLabel + { + Background = SolidColorBrush.Parse("#CCCCCC"), + Padding = new Thickness(5), + Text = @"

Pellentesque habitant morbi tristique senectus et netus et malesuada fames ac turpis egestas. Vestibulum tortor quam, feugiat vitae, ultricies eget, tempor sit amet, ante. Donec eu libero sit amet quam egestas semper. Aenean ultricies mi vitae est. Mauris placerat eleifend leo. Quisque sit amet est et sapien ullamcorper pharetra. Vestibulum erat wisi, condimentum sed, commodo vitae, ornare sit amet, wisi. Aenean fermentum, elit eget tincidunt condimentum, eros ipsum rutrum orci, sagittis tempus lacus enim ac dui. Donec non enim in turpis pulvinar facilisis. Ut felis.

+

Header Level 2

+ +
    +
  1. Lorem ipsum dolor sit amet, consectetuer adipiscing elit.
  2. +
  3. Aliquam tincidunt mauris eu risus.
  4. +
+ +

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus magna. Cras in mi at felis aliquet congue. Ut a est eget ligula molestie gravida. Curabitur massa. Donec eleifend, libero at sagittis mollis, tellus est malesuada tellus, at luctus turpis elit sit amet quam. Vivamus pretium ornare est.

+ +

Header Level 3

+ +
    +
  • Lorem ipsum dolor sit amet, consectetuer adipiscing elit.
  • +
  • Aliquam tincidunt mauris eu risus.
  • +
" + } + } + } + } }; } - private static TabItem ImagesTab() + private static TabItem TextTab() { - ScrollBar size; - return new TabItem { - Header = "Images", - Content = new StackPanel - { - Orientation = Orientation.Vertical, - HorizontalAlignment = HorizontalAlignment.Center, - VerticalAlignment = VerticalAlignment.Center, - Gap = 8, - Children = new Controls - { - (size = new ScrollBar - { - Minimum = 100, - Maximum = 400, - Value = 100, - Orientation = Orientation.Horizontal, - }), - new ScrollViewer - { - Width = 200, - Height = 200, - CanScrollHorizontally = true, - Content = new Image - { - Source = new Bitmap("github_icon.png"), - [!Layoutable.WidthProperty] = size[!RangeBase.ValueProperty], - [!Layoutable.HeightProperty] = size[!RangeBase.ValueProperty], - }, - }, - new ProgressBar - { - [!RangeBase.MinimumProperty] = size[!RangeBase.MinimumProperty], - [!RangeBase.MaximumProperty] = size[!RangeBase.MaximumProperty], - [!RangeBase.ValueProperty] = size[!RangeBase.ValueProperty], - } - } - }, + Header = "Input", + Content = new ScrollViewer() + { + Content = new StackPanel + { + Margin = new Thickness(10), + Orientation = Orientation.Vertical, + Gap = 4, + Children = new Controls + { + new TextBlock + { + Text = "TextBox", + FontWeight = FontWeight.Medium, + FontSize = 20, + Foreground = SolidColorBrush.Parse("#212121"), + }, + new TextBlock + { + Text = "A text box control", + FontSize = 13, + Foreground = SolidColorBrush.Parse("#727272"), + Margin = new Thickness(0, 0, 0, 10) + }, + new TextBox { Text = "Lorem ipsum dolor sit amet, consectetur adipiscing elit.", Width = 200 }, + new TextBox { AcceptsReturn = true, TextWrapping = TextWrapping.Wrap, Width = 200, Height = 150, Text = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Vivamus magna. Cras in mi at felis aliquet congue. Ut a est eget ligula molestie gravida. Curabitur massa. Donec eleifend, libero at sagittis mollis, tellus est malesuada tellus, at luctus turpis elit sit amet quam. Vivamus pretium ornare est." }, + new TextBlock + { + Margin = new Thickness(0, 40, 0, 0), + Text = "CheckBox", + FontWeight = FontWeight.Medium, + FontSize = 20, + Foreground = SolidColorBrush.Parse("#212121"), + }, + new TextBlock + { + Text = "A check box control", + FontSize = 13, + Foreground = SolidColorBrush.Parse("#727272"), + Margin = new Thickness(0, 0, 0, 10) + }, + new CheckBox { IsChecked = true, Margin = new Thickness(0, 0, 0, 5), Content = "Checked" }, + new CheckBox { IsChecked = false, Content = "Unchecked" }, + new TextBlock + { + Margin = new Thickness(0, 40, 0, 0), + Text = "RadioButton", + FontWeight = FontWeight.Medium, + FontSize = 20, + Foreground = SolidColorBrush.Parse("#212121"), + }, + new TextBlock + { + Text = "A radio button control", + FontSize = 13, + Foreground = SolidColorBrush.Parse("#727272"), + Margin = new Thickness(0, 0, 0, 10) + }, + new RadioButton { IsChecked = true, Content = "Option 1" }, + new RadioButton { IsChecked = false, Content = "Option 2" }, + new RadioButton { IsChecked = false, Content = "Option 3" }, + } + } + } }; } + private static TabItem ListsTab() { - ListBox listBox; - return new TabItem { Header = "Lists", - Content = new StackPanel - { - DataTemplates = new DataTemplates - { - new DataTemplate(x => - new StackPanel - { - Children = new Controls - { - new TextBlock { Text = x.Name, FontSize = 24 }, - new TextBlock { Text = x.Value }, - } - }) - }, - Orientation = Orientation.Horizontal, - HorizontalAlignment = HorizontalAlignment.Center, - VerticalAlignment = VerticalAlignment.Center, - Gap = 8, - Children = new Controls - { - new TreeView - { - Name = "treeView", - Items = s_treeData, - }, - (listBox = new ListBox - { - Items = s_listBoxData, - MaxHeight = 300, - }), - new DropDown - { - Items = s_listBoxData, - SelectedItem = s_listBoxData[0], - VerticalAlignment = VerticalAlignment.Center, - } - } - }, + Content = new ScrollViewer() + { + CanScrollHorizontally = false, + Content = new StackPanel + { + HorizontalAlignment = HorizontalAlignment.Left, + Orientation = Orientation.Vertical, + VerticalAlignment = VerticalAlignment.Top, + Gap = 4, + Margin = new Thickness(10), + DataTemplates = new DataTemplates + { + new DataTemplate(x => + new StackPanel + { + Gap = 4, + Orientation = Orientation.Horizontal, + Children = new Controls + { + new Image { Width = 50, Height = 50, Source = new Bitmap("github_icon.png") }, + new TextBlock { Text = x.Name, FontSize = 18 } + } + }) + }, + Children = new Controls + { + new TextBlock + { + Text = "ListBox", + FontWeight = FontWeight.Medium, + FontSize = 20, + Foreground = SolidColorBrush.Parse("#212121"), + }, + new TextBlock + { + Text = "A list box control.", + FontSize = 13, + Foreground = SolidColorBrush.Parse("#727272"), + Margin = new Thickness(0, 0, 0, 10) + }, + new ListBox + { + BorderThickness = 2, + Items = s_listBoxData, + Height = 300, + Width = 300, + }, + new TextBlock + { + Margin = new Thickness(0, 40, 0, 0), + Text = "TreeView", + FontWeight = FontWeight.Medium, + FontSize = 20, + Foreground = SolidColorBrush.Parse("#212121"), + }, + new TextBlock + { + Text = "A tree view control.", + FontSize = 13, + Foreground = SolidColorBrush.Parse("#727272"), + Margin = new Thickness(0, 0, 0, 10) + }, + new TreeView + { + Name = "treeView", + Items = s_treeData, + Height = 300, + BorderThickness = 2, + Width = 300, + } + } + }, + } }; } + private static TabItem ImagesTab() + { + var imageDeck = new Deck + { + Width = 400, + Height = 400, + Transition = new PageSlide(TimeSpan.FromSeconds(0.25)), + Items = new[] + { + new Image { Source = new Bitmap("github_icon.png"), Width = 400, Height = 400 }, + new Image { Source = new Bitmap("pattern.jpg"), Width = 400, Height = 400 }, + } + }; + + imageDeck.AutoSelect = true; + + var next = new Button + { + VerticalAlignment = VerticalAlignment.Center, + Padding = new Thickness(20), + Content = new Perspex.Controls.Shapes.Path + { + Data = StreamGeometry.Parse("M4,11V13H16L10.5,18.5L11.92,19.92L19.84,12L11.92,4.08L10.5,5.5L16,11H4Z"), + Fill = Brushes.Black + } + }; + + var prev = new Button + { + VerticalAlignment = VerticalAlignment.Center, + Padding = new Thickness(20), + Content = new Perspex.Controls.Shapes.Path + { + Data = StreamGeometry.Parse("M20,11V13H8L13.5,18.5L12.08,19.92L4.16,12L12.08,4.08L13.5,5.5L8,11H20Z"), + Fill = Brushes.Black + } + }; + + prev.Click += (s, e) => + { + if (imageDeck.SelectedIndex == 0) + imageDeck.SelectedIndex = 1; + else + imageDeck.SelectedIndex--; + }; + + next.Click += (s, e) => + { + if (imageDeck.SelectedIndex == 1) + imageDeck.SelectedIndex = 0; + else + imageDeck.SelectedIndex++; + }; + + return new TabItem + { + Header = "Images", + Content = new ScrollViewer + { + Content = new StackPanel + { + HorizontalAlignment = HorizontalAlignment.Left, + Orientation = Orientation.Vertical, + VerticalAlignment = VerticalAlignment.Top, + Gap = 4, + Margin = new Thickness(10), + Children = new Controls + { + new TextBlock + { + Text = "Deck", + FontWeight = FontWeight.Medium, + FontSize = 20, + Foreground = SolidColorBrush.Parse("#212121"), + }, + new TextBlock + { + Text = "An items control that displays its items as pages that fill the controls.", + FontSize = 13, + Foreground = SolidColorBrush.Parse("#727272"), + Margin = new Thickness(0, 0, 0, 10) + }, + new StackPanel + { + Name = "deckVisual", + Orientation = Orientation.Horizontal, + Gap = 4, + Children = new Controls + { + prev, + imageDeck, + next + } + } + } + } + } + }; + } + private static TabItem LayoutTab() { return new TabItem { Header = "Layout", - Content = new Grid - { - ColumnDefinitions = new ColumnDefinitions - { - new ColumnDefinition(1, GridUnitType.Star), - new ColumnDefinition(1, GridUnitType.Star), - }, - Margin = new Thickness(50), - Children = new Controls - { - new StackPanel - { - Orientation = Orientation.Vertical, - Gap = 8, - Children = new Controls - { - new Button { HorizontalAlignment = HorizontalAlignment.Left, Content = "Left Aligned" }, - new Button { HorizontalAlignment = HorizontalAlignment.Center, Content = "Center Aligned" }, - new Button { HorizontalAlignment = HorizontalAlignment.Right, Content = "Right Aligned" }, - new Button { HorizontalAlignment = HorizontalAlignment.Stretch, Content = "Stretch" }, - }, - [Grid.ColumnProperty] = 0, - }, - new StackPanel - { - Orientation = Orientation.Horizontal, - Gap = 8, - Children = new Controls - { - new Button { VerticalAlignment = VerticalAlignment.Top, Content = "Top Aligned" }, - new Button { VerticalAlignment = VerticalAlignment.Center, Content = "Center Aligned" }, - new Button { VerticalAlignment = VerticalAlignment.Bottom, Content = "Bottom Aligned" }, - new Button { VerticalAlignment = VerticalAlignment.Stretch, Content = "Stretch" }, - }, - [Grid.ColumnProperty] = 1, - }, - }, - } + Content = new ScrollViewer + { + Content = new StackPanel + { + HorizontalAlignment = HorizontalAlignment.Left, + Orientation = Orientation.Vertical, + VerticalAlignment = VerticalAlignment.Top, + Gap = 4, + Margin = new Thickness(10), + Children = new Controls + { + new TextBlock + { + Text = "Grid", + FontWeight = FontWeight.Medium, + FontSize = 20, + Foreground = SolidColorBrush.Parse("#212121"), + }, + new TextBlock + { + Text = "Lays out child controls according to a grid.", + FontSize = 13, + Foreground = SolidColorBrush.Parse("#727272"), + Margin = new Thickness(0, 0, 0, 10) + }, + new Grid + { + Width = 600, + ColumnDefinitions = new ColumnDefinitions + { + new ColumnDefinition(1, GridUnitType.Star), + new ColumnDefinition(1, GridUnitType.Star), + }, + + RowDefinitions = new RowDefinitions + { + new RowDefinition(1, GridUnitType.Auto), + new RowDefinition(1, GridUnitType.Auto) + }, + Children = new Controls + { + + new Rectangle + { + Fill = SolidColorBrush.Parse("#FF5722"), + [Grid.ColumnSpanProperty] = 2, + Height = 200, + Margin = new Thickness(2.5) + }, + new Rectangle + { + Fill = SolidColorBrush.Parse("#FF5722"), + [Grid.RowProperty] = 1, + Height = 100, + Margin = new Thickness(2.5) + }, + new Rectangle + { + Fill = SolidColorBrush.Parse("#FF5722"), + [Grid.RowProperty] = 1, + [Grid.ColumnProperty] = 1, + Height = 100, + Margin = new Thickness(2.5) + }, + }, + }, + new TextBlock + { + Margin = new Thickness(0, 40, 0, 0), + Text = "StackPanel", + FontWeight = FontWeight.Medium, + FontSize = 20, + Foreground = SolidColorBrush.Parse("#212121"), + }, + new TextBlock + { + Text = "A panel which lays out its children horizontally or vertically.", + FontSize = 13, + Foreground = SolidColorBrush.Parse("#727272"), + Margin = new Thickness(0, 0, 0, 10) + }, + new StackPanel + { + Orientation = Orientation.Vertical, + Gap = 4, + Width = 300, + Children = new Controls + { + new Rectangle + { + Fill = SolidColorBrush.Parse("#FFC107"), + Height = 50, + }, + new Rectangle + { + Fill = SolidColorBrush.Parse("#FFC107"), + Height = 50, + }, + new Rectangle + { + Fill = SolidColorBrush.Parse("#FFC107"), + Height = 50, + }, + } + }, + } + } + } }; } @@ -592,70 +691,88 @@ namespace TestApplication var result = new TabItem { Header = "Animations", - Content = new Grid + Content = new StackPanel { - ColumnDefinitions = new ColumnDefinitions - { - new ColumnDefinition(1, GridUnitType.Star), - new ColumnDefinition(1, GridUnitType.Star), - }, - RowDefinitions = new RowDefinitions - { - new RowDefinition(1, GridUnitType.Star), - new RowDefinition(GridLength.Auto), - }, + HorizontalAlignment = HorizontalAlignment.Left, + Orientation = Orientation.Vertical, + VerticalAlignment = VerticalAlignment.Top, + Gap = 4, + Margin = new Thickness(10), Children = new Controls { - (border1 = new Border - { - Width = 100, - Height = 100, - HorizontalAlignment = HorizontalAlignment.Center, - VerticalAlignment = VerticalAlignment.Center, - Background = Brushes.Crimson, - RenderTransform = new RotateTransform(), - Child = new TextBox - { - Background = Brushes.White, - Text = "Hello!", - HorizontalAlignment = HorizontalAlignment.Center, - VerticalAlignment = VerticalAlignment.Center, - }, - }), - (border2 = new Border - { - Width = 100, - Height = 100, - HorizontalAlignment = HorizontalAlignment.Center, - VerticalAlignment = VerticalAlignment.Center, - Background = Brushes.Coral, - Child = new Image - { - Source = new Bitmap("github_icon.png"), - HorizontalAlignment = HorizontalAlignment.Center, - VerticalAlignment = VerticalAlignment.Center, - }, - RenderTransform = (rotate = new RotateTransform - { - PropertyTransitions = new PropertyTransitions - { - RotateTransform.AngleProperty.Transition(500), - } - }), - PropertyTransitions = new PropertyTransitions - { - Layoutable.WidthProperty.Transition(300), - Layoutable.HeightProperty.Transition(1000), - }, - [Grid.ColumnProperty] = 1, - }), - (button1 = new Button - { - HorizontalAlignment = HorizontalAlignment.Center, - Content = "Animate", - [Grid.ColumnProperty] = 1, - [Grid.RowProperty] = 1, - }), + new TextBlock + { + Text = "Animations", + FontWeight = FontWeight.Medium, + FontSize = 20, + Foreground = SolidColorBrush.Parse("#212121"), + }, + new TextBlock + { + Text = "A few animations showcased below", + FontSize = 13, + Foreground = SolidColorBrush.Parse("#727272"), + Margin = new Thickness(0, 0, 0, 10) + }, + (button1 = new Button + { + Content = "Animate", + Width = 120, + [Grid.ColumnProperty] = 1, + [Grid.RowProperty] = 1, + }), + new Canvas + { + Children = new Controls + { + (border1 = new Border + { + Width = 100, + Height = 100, + HorizontalAlignment = HorizontalAlignment.Center, + VerticalAlignment = VerticalAlignment.Center, + Background = Brushes.Crimson, + RenderTransform = new RotateTransform(), + Child = new TextBox + { + Background = Brushes.White, + Text = "Hello!", + HorizontalAlignment = HorizontalAlignment.Center, + VerticalAlignment = VerticalAlignment.Center, + }, + [Canvas.LeftProperty] = 100, + [Canvas.TopProperty] = 100, + }), + (border2 = new Border + { + Width = 100, + Height = 100, + HorizontalAlignment = HorizontalAlignment.Center, + VerticalAlignment = VerticalAlignment.Center, + Background = Brushes.Coral, + Child = new Image + { + Source = new Bitmap("github_icon.png"), + HorizontalAlignment = HorizontalAlignment.Center, + VerticalAlignment = VerticalAlignment.Center, + }, + RenderTransform = (rotate = new RotateTransform + { + PropertyTransitions = new PropertyTransitions + { + RotateTransform.AngleProperty.Transition(500), + } + }), + PropertyTransitions = new PropertyTransitions + { + Layoutable.WidthProperty.Transition(300), + Layoutable.HeightProperty.Transition(1000), + }, + [Canvas.LeftProperty] = 400, + [Canvas.TopProperty] = 100, + }), + } + } }, }, }; diff --git a/samples/TestApplication/TestApplication.csproj b/samples/TestApplication/TestApplication.csproj index 480572df6f..4ccecb2cd0 100644 --- a/samples/TestApplication/TestApplication.csproj +++ b/samples/TestApplication/TestApplication.csproj @@ -72,6 +72,9 @@ + + + @@ -80,6 +83,10 @@ + + {FB05AC90-89BA-4F2F-A924-F37875FB547C} + Perspex.Cairo + {D211E587-D8BC-45B9-95A4-F297C8FA5200} Perspex.Animation @@ -146,6 +153,9 @@ PreserveNewest + + PreserveNewest + diff --git a/samples/TestApplication/pattern.jpg b/samples/TestApplication/pattern.jpg new file mode 100644 index 0000000000..72b35e0692 Binary files /dev/null and b/samples/TestApplication/pattern.jpg differ diff --git a/src/Gtk/Perspex.Cairo/CairoExtensions.cs b/src/Gtk/Perspex.Cairo/CairoExtensions.cs index 5798796a37..fa66837194 100644 --- a/src/Gtk/Perspex.Cairo/CairoExtensions.cs +++ b/src/Gtk/Perspex.Cairo/CairoExtensions.cs @@ -43,37 +43,7 @@ namespace Perspex.Cairo public static Pango.Weight ToCairo(this Perspex.Media.FontWeight weight) { - if (weight == Perspex.Media.FontWeight.Light) - { - return Pango.Weight.Light; - } - - if (weight == Perspex.Media.FontWeight.Normal || weight == Perspex.Media.FontWeight.Regular) - { - return Pango.Weight.Normal; - } - - if (weight == Perspex.Media.FontWeight.DemiBold || weight == Perspex.Media.FontWeight.Medium) - { - return Pango.Weight.Semibold; - } - - if (weight == Perspex.Media.FontWeight.Bold) - { - return Pango.Weight.Bold; - } - - if (weight == Perspex.Media.FontWeight.UltraBold || weight == Perspex.Media.FontWeight.ExtraBold) - { - return Pango.Weight.Ultrabold; - } - - if (weight == Perspex.Media.FontWeight.Black || weight == Perspex.Media.FontWeight.Heavy || weight == Perspex.Media.FontWeight.UltraBlack) - { - return Pango.Weight.Heavy; - } - - return Pango.Weight.Ultralight; + return (Pango.Weight)weight; } public static Pango.Alignment ToCairo(this Perspex.Media.TextAlignment alignment) diff --git a/src/Gtk/Perspex.Cairo/Media/DrawingContext.cs b/src/Gtk/Perspex.Cairo/Media/DrawingContext.cs index 324ba136e1..e1d5360509 100644 --- a/src/Gtk/Perspex.Cairo/Media/DrawingContext.cs +++ b/src/Gtk/Perspex.Cairo/Media/DrawingContext.cs @@ -74,14 +74,31 @@ namespace Perspex.Cairo.Media _context.Scale(scale.X, scale.Y); destRect /= scale; - Gdk.CairoHelper.SetSourcePixbuf( - _context, - impl.Surface, - -sourceRect.X + destRect.X, - -sourceRect.Y + destRect.Y); - - _context.Rectangle(destRect.ToCairo()); - _context.Fill(); + if (opacityOverride < 1.0f) { + _context.PushGroup (); + Gdk.CairoHelper.SetSourcePixbuf ( + _context, + impl.Surface, + -sourceRect.X + destRect.X, + -sourceRect.Y + destRect.Y); + + _context.Rectangle (destRect.ToCairo ()); + _context.Fill (); + _context.PopGroupToSource (); + _context.PaintWithAlpha (opacityOverride); + } else { + _context.PushGroup (); + Gdk.CairoHelper.SetSourcePixbuf ( + _context, + impl.Surface, + -sourceRect.X + destRect.X, + -sourceRect.Y + destRect.Y); + + _context.Rectangle (destRect.ToCairo ()); + _context.Fill (); + _context.PopGroupToSource (); + _context.PaintWithAlpha (opacityOverride); + } _context.Restore(); } @@ -203,11 +220,14 @@ namespace Perspex.Cairo.Media /// A disposable used to undo the opacity. public IDisposable PushOpacity(double opacity) { - opacityOverride = opacity; + var tmp = opacityOverride; + + if (opacity < 1.0f) + opacityOverride = opacity; return Disposable.Create(() => { - opacityOverride = 1.0f; + opacityOverride = tmp; }); } @@ -228,8 +248,10 @@ namespace Perspex.Cairo.Media private double opacityOverride = 1.0f; - private BrushImpl SetBrush(Brush brush, Size destinationSize) + private IDisposable SetBrush(Brush brush, Size destinationSize) { + _context.Save (); + var solid = brush as SolidColorBrush; var linearGradientBrush = brush as LinearGradientBrush; var imageBrush = brush as ImageBrush; @@ -254,15 +276,17 @@ namespace Perspex.Cairo.Media } else { - impl = new SolidColorBrushImpl(null, 1.0f); + impl = new SolidColorBrushImpl(null, opacityOverride); } _context.SetSource(impl.PlatformBrush); - - return impl; + return Disposable.Create(() => + { + _context.Restore(); + }); } - private BrushImpl SetPen(Pen pen, Size destinationSize) + private IDisposable SetPen(Pen pen, Size destinationSize) { if (pen.DashStyle != null) { @@ -282,6 +306,9 @@ namespace Perspex.Cairo.Media _context.LineJoin = Cairo.LineJoin.Miter; _context.LineCap = Cairo.LineCap.Butt; + if (pen.Brush == null) + return Disposable.Empty; + return SetBrush(pen.Brush, destinationSize); } } diff --git a/src/Gtk/Perspex.Cairo/Media/SolidColorBrushImpl.cs b/src/Gtk/Perspex.Cairo/Media/SolidColorBrushImpl.cs index 53db187a0a..10e63f0382 100644 --- a/src/Gtk/Perspex.Cairo/Media/SolidColorBrushImpl.cs +++ b/src/Gtk/Perspex.Cairo/Media/SolidColorBrushImpl.cs @@ -9,11 +9,13 @@ namespace Perspex.Cairo { var color = brush?.Color.ToCairo() ?? new Color(); - if (brush != null && brush.Opacity > 1) + if (brush != null) color.A = Math.Min(brush.Opacity, color.A); - color.A = Math.Min(opacityOverride, color.A); - this.PlatformBrush = new SolidPattern(brush?.Color.ToCairo() ?? new Color()); + if (opacityOverride < 1.0f) + color.A = Math.Min(opacityOverride, color.A); + + this.PlatformBrush = new SolidPattern(color); } } } diff --git a/src/Gtk/Perspex.Cairo/Media/StreamGeometryContextImpl.cs b/src/Gtk/Perspex.Cairo/Media/StreamGeometryContextImpl.cs index b287146806..a49ac7ef90 100644 --- a/src/Gtk/Perspex.Cairo/Media/StreamGeometryContextImpl.cs +++ b/src/Gtk/Perspex.Cairo/Media/StreamGeometryContextImpl.cs @@ -12,12 +12,17 @@ namespace Perspex.Cairo.Media public class StreamGeometryContextImpl : IStreamGeometryContextImpl { - private readonly StreamGeometryImpl _impl; - public StreamGeometryContextImpl(StreamGeometryImpl imp) + public StreamGeometryContextImpl(Cairo.Path path = null) { - _impl = imp; - _surf = new Cairo.ImageSurface(Cairo.Format.Argb32, 0, 0); - _context = new Cairo.Context(_surf); + + _surf = new Cairo.ImageSurface (Cairo.Format.Argb32, 0, 0); + _context = new Cairo.Context (_surf); + this.Path = path; + + if (this.Path != null) + { + _context.AppendPath(this.Path); + } } public void ArcTo(Point point, Size size, double rotationAngle, bool isLargeArc, SweepDirection sweepDirection) @@ -26,35 +31,43 @@ namespace Perspex.Cairo.Media public void BeginFigure(Point startPoint, bool isFilled) { - _context.MoveTo(startPoint.ToCairo()); + if (this.Path == null) + _context.MoveTo(startPoint.ToCairo()); } public void BezierTo(Point point1, Point point2, Point point3) { - _context.CurveTo(point1.ToCairo(), point2.ToCairo(), point3.ToCairo()); + if (this.Path == null) + _context.CurveTo(point1.ToCairo(), point2.ToCairo(), point3.ToCairo()); } public void LineTo(Point point) { - _context.LineTo(point.ToCairo()); + if (this.Path == null) + _context.LineTo(point.ToCairo()); } private readonly Cairo.Context _context; private readonly Cairo.ImageSurface _surf; + public Cairo.Path Path { get; private set; } + public Rect Bounds { get; private set; } public void EndFigure(bool isClosed) { - if (isClosed) - _context.ClosePath(); + if (this.Path == null) + { + if (isClosed) + _context.ClosePath (); - _impl.Bounds = _context.FillExtents().ToPerspex(); - _impl.Path = _context.CopyPath(); + Path = _context.CopyPath (); + Bounds = _context.FillExtents ().ToPerspex (); + } } public void Dispose() { - _context.Dispose(); - _surf.Dispose(); + _context.Dispose (); + _surf.Dispose (); } } } diff --git a/src/Gtk/Perspex.Cairo/Media/StreamGeometryImpl.cs b/src/Gtk/Perspex.Cairo/Media/StreamGeometryImpl.cs index a9e0266d4a..7e7f520f02 100644 --- a/src/Gtk/Perspex.Cairo/Media/StreamGeometryImpl.cs +++ b/src/Gtk/Perspex.Cairo/Media/StreamGeometryImpl.cs @@ -15,26 +15,23 @@ namespace Perspex.Cairo.Media { public StreamGeometryImpl() { - _impl = new StreamGeometryContextImpl(this); + _impl = new StreamGeometryContextImpl(null); } - public StreamGeometryImpl(Cairo.Path path) + public StreamGeometryImpl(StreamGeometryContextImpl impl) { - _impl = new StreamGeometryContextImpl(this); - Path = path; - } - - public Cairo.Path Path - { - get; - set; + _impl = impl; } public Rect Bounds { - get; - set; - } + get { return _impl.Bounds; } + } + + public Cairo.Path Path + { + get { return _impl.Path; } + } private readonly StreamGeometryContextImpl _impl; @@ -55,14 +52,14 @@ namespace Perspex.Cairo.Media } public IStreamGeometryImpl Clone() - { - return new StreamGeometryImpl(Path); + { + return new StreamGeometryImpl(_impl); } public Rect GetRenderBounds(double strokeThickness) { // TODO: Calculate properly. - return Bounds; + return Bounds.Inflate(strokeThickness); } public IStreamGeometryContextImpl Open() diff --git a/src/Gtk/Perspex.Cairo/Media/TileBrushes.cs b/src/Gtk/Perspex.Cairo/Media/TileBrushes.cs index 026729f26f..e08565785a 100644 --- a/src/Gtk/Perspex.Cairo/Media/TileBrushes.cs +++ b/src/Gtk/Perspex.Cairo/Media/TileBrushes.cs @@ -30,7 +30,7 @@ namespace Perspex.Cairo.Media var translate = CalculateTranslate(brush, sourceRect, destinationRect, scale); var intermediateSize = CalculateIntermediateSize(tileMode, targetSize, destinationRect.Size); - using (var intermediate = new ImageSurface(Format.ARGB32, (int)intermediateSize.Width, (int)intermediateSize.Height)) + var intermediate = new ImageSurface (Format.ARGB32, (int)intermediateSize.Width, (int)intermediateSize.Height); using (var context = new Context(intermediate)) { Rect drawRect; diff --git a/src/Gtk/Perspex.Cairo/Perspex.Cairo.csproj b/src/Gtk/Perspex.Cairo/Perspex.Cairo.csproj index 7d3aef2ec0..baa60a428a 100644 --- a/src/Gtk/Perspex.Cairo/Perspex.Cairo.csproj +++ b/src/Gtk/Perspex.Cairo/Perspex.Cairo.csproj @@ -96,11 +96,11 @@ - - \ No newline at end of file + diff --git a/src/Gtk/Perspex.Cairo/packages.config b/src/Gtk/Perspex.Cairo/packages.config index a47f593bc8..b554ddfc08 100644 --- a/src/Gtk/Perspex.Cairo/packages.config +++ b/src/Gtk/Perspex.Cairo/packages.config @@ -3,4 +3,4 @@ - \ No newline at end of file + diff --git a/src/Gtk/Perspex.Gtk/WindowImpl.cs b/src/Gtk/Perspex.Gtk/WindowImpl.cs index ba9964165e..a844a3a5dd 100644 --- a/src/Gtk/Perspex.Gtk/WindowImpl.cs +++ b/src/Gtk/Perspex.Gtk/WindowImpl.cs @@ -31,7 +31,7 @@ namespace Perspex.Gtk public WindowImpl() : base(Gtk.WindowType.Toplevel) { - DefaultSize = new Gdk.Size(640, 480); + DefaultSize = new Gdk.Size(900, 480); Init(); } @@ -89,7 +89,6 @@ namespace Perspex.Gtk public void Invalidate(Rect rect) { base.GdkWindow.InvalidateRect (new Rectangle ((int)rect.X, (int)rect.Y, (int)rect.Width, (int)rect.Height), true); - } public Point PointToScreen(Point point) diff --git a/src/Perspex.Themes.Default/ButtonStyle.cs b/src/Perspex.Themes.Default/ButtonStyle.cs index fc9f9917a8..fb383100e8 100644 --- a/src/Perspex.Themes.Default/ButtonStyle.cs +++ b/src/Perspex.Themes.Default/ButtonStyle.cs @@ -30,8 +30,8 @@ namespace Perspex.Themes.Default { Setters = new[] { - new Setter(TemplatedControl.BackgroundProperty, new SolidColorBrush(0xffdddddd)), - new Setter(TemplatedControl.BorderBrushProperty, new SolidColorBrush(0xff707070)), + new Setter(TemplatedControl.BackgroundProperty, new SolidColorBrush(0xffaaaaaa)), + new Setter(TemplatedControl.BorderBrushProperty, new SolidColorBrush(0xffaaaaaa)), new Setter(TemplatedControl.BorderThicknessProperty, 2), new Setter(TemplatedControl.ForegroundProperty, new SolidColorBrush(0xff000000)), new Setter(Control.FocusAdornerProperty, new FuncTemplate(FocusAdornerTemplate)), @@ -44,22 +44,15 @@ namespace Perspex.Themes.Default { Setters = new[] { - new Setter(TemplatedControl.BackgroundProperty, new SolidColorBrush(0xffbee6fd)), - new Setter(TemplatedControl.BorderBrushProperty, new SolidColorBrush(0xff3c7fb1)), + new Setter(TemplatedControl.BorderBrushProperty, new SolidColorBrush(0xff888888)), }, }, new Style(x => x.OfType