Program.cs 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695
  1. // Copyright (c) The Perspex Project. All rights reserved.
  2. // Licensed under the MIT license. See licence.md file in the project root for full license information.
  3. using System;
  4. using System.IO;
  5. using System.Reactive.Linq;
  6. using Perspex;
  7. using Perspex.Animation;
  8. using Perspex.Collections;
  9. using Perspex.Controls;
  10. using Perspex.Controls.Html;
  11. using Perspex.Controls.Primitives;
  12. using Perspex.Controls.Shapes;
  13. using Perspex.Controls.Templates;
  14. using Perspex.Diagnostics;
  15. using Perspex.Layout;
  16. using Perspex.Media;
  17. using Perspex.Media.Imaging;
  18. #if PERSPEX_GTK
  19. using Perspex.Gtk;
  20. #endif
  21. using ReactiveUI;
  22. namespace TestApplication
  23. {
  24. internal class Item
  25. {
  26. public string Name { get; set; }
  27. public string Value { get; set; }
  28. }
  29. internal class Node
  30. {
  31. public Node()
  32. {
  33. Children = new PerspexList<Node>();
  34. }
  35. public string Name { get; set; }
  36. public PerspexList<Node> Children { get; set; }
  37. }
  38. internal class Program
  39. {
  40. private static readonly PerspexList<Node> s_treeData = new PerspexList<Node>
  41. {
  42. new Node
  43. {
  44. Name = "Root 1",
  45. Children = new PerspexList<Node>
  46. {
  47. new Node
  48. {
  49. Name = "Child 1",
  50. },
  51. new Node
  52. {
  53. Name = "Child 2",
  54. Children = new PerspexList<Node>
  55. {
  56. new Node
  57. {
  58. Name = "Grandchild 1",
  59. },
  60. new Node
  61. {
  62. Name = "Grandmaster Flash",
  63. },
  64. }
  65. },
  66. new Node
  67. {
  68. Name = "Child 3",
  69. },
  70. }
  71. },
  72. new Node
  73. {
  74. Name = "Root 2",
  75. },
  76. };
  77. private static readonly PerspexList<Item> s_listBoxData = new PerspexList<Item>
  78. {
  79. new Item { Name = "Item 1", Value = "Item 1 Value" },
  80. new Item { Name = "Item 2", Value = "Item 2 Value" },
  81. new Item { Name = "Item 3", Value = "Item 3 Value" },
  82. new Item { Name = "Item 4", Value = "Item 4 Value" },
  83. new Item { Name = "Item 5", Value = "Item 5 Value" },
  84. new Item { Name = "Item 6", Value = "Item 6 Value" },
  85. new Item { Name = "Item 7", Value = "Item 7 Value" },
  86. new Item { Name = "Item 8", Value = "Item 8 Value" },
  87. };
  88. private static void Main(string[] args)
  89. {
  90. //Log.Logger = new LoggerConfiguration()
  91. // .Filter.ByIncludingOnly(Matching.WithProperty("Area", "Layout"))
  92. // .MinimumLevel.Verbose()
  93. // .WriteTo.Trace(outputTemplate: "[{Id:X8}] [{SourceContext}] {Message}")
  94. // .CreateLogger();
  95. // The version of ReactiveUI currently included is for WPF and so expects a WPF
  96. // dispatcher. This makes sure it's initialized.
  97. System.Windows.Threading.Dispatcher foo = System.Windows.Threading.Dispatcher.CurrentDispatcher;
  98. App application = new App
  99. {
  100. DataTemplates = new DataTemplates
  101. {
  102. new TreeDataTemplate<Node>(
  103. x => new TextBlock { Text = x.Name },
  104. x => x.Children,
  105. x => true),
  106. },
  107. };
  108. TextBlock fps;
  109. var testCommand = ReactiveCommand.Create();
  110. testCommand.Subscribe(_ => System.Diagnostics.Debug.WriteLine("Test command executed."));
  111. Window window = new Window
  112. {
  113. Title = "Perspex Test Application",
  114. SizeToContent = SizeToContent.WidthAndHeight,
  115. Content = new Grid
  116. {
  117. ColumnDefinitions = new ColumnDefinitions
  118. {
  119. new ColumnDefinition(1, GridUnitType.Star),
  120. new ColumnDefinition(1, GridUnitType.Star),
  121. },
  122. RowDefinitions = new RowDefinitions
  123. {
  124. new RowDefinition(GridLength.Auto),
  125. new RowDefinition(1, GridUnitType.Star),
  126. new RowDefinition(GridLength.Auto),
  127. },
  128. Children = new Controls
  129. {
  130. new Menu
  131. {
  132. Items = new[]
  133. {
  134. new MenuItem
  135. {
  136. Header = "_File",
  137. Items = new[]
  138. {
  139. new MenuItem
  140. {
  141. Header = "_Open...",
  142. Icon = new Image
  143. {
  144. Source = new Bitmap("github_icon.png"),
  145. },
  146. },
  147. new MenuItem
  148. {
  149. Header = "_Save",
  150. Items = new[]
  151. {
  152. new MenuItem
  153. {
  154. Header = "Sub Item _1",
  155. },
  156. new MenuItem
  157. {
  158. Header = "Sub Item _2",
  159. },
  160. }
  161. },
  162. new MenuItem
  163. {
  164. Header = "Save _As",
  165. Items = new[]
  166. {
  167. new MenuItem
  168. {
  169. Header = "Sub Item _1",
  170. },
  171. new MenuItem
  172. {
  173. Header = "Sub Item _2",
  174. },
  175. }
  176. },
  177. new MenuItem
  178. {
  179. Header = "E_xit",
  180. Command = testCommand,
  181. },
  182. }
  183. },
  184. new MenuItem
  185. {
  186. Header = "_Edit",
  187. Items = new[]
  188. {
  189. new MenuItem
  190. {
  191. Header = "Cu_t",
  192. },
  193. new MenuItem
  194. {
  195. Header = "_Copy",
  196. },
  197. new MenuItem
  198. {
  199. Header = "_Paste",
  200. },
  201. }
  202. }
  203. },
  204. [Grid.ColumnSpanProperty] = 2,
  205. },
  206. new TabControl
  207. {
  208. Items = new[]
  209. {
  210. ButtonsTab(),
  211. TextTab(),
  212. HtmlTab(),
  213. ImagesTab(),
  214. ListsTab(),
  215. LayoutTab(),
  216. AnimationsTab(),
  217. },
  218. Transition = new PageSlide(TimeSpan.FromSeconds(0.25)),
  219. [Grid.RowProperty] = 1,
  220. [Grid.ColumnSpanProperty] = 2,
  221. },
  222. (fps = new TextBlock
  223. {
  224. HorizontalAlignment = HorizontalAlignment.Left,
  225. Margin = new Thickness(2),
  226. [Grid.RowProperty] = 2,
  227. }),
  228. new TextBlock
  229. {
  230. Text = "Press F12 for Dev Tools",
  231. HorizontalAlignment = HorizontalAlignment.Right,
  232. Margin = new Thickness(2),
  233. [Grid.ColumnProperty] = 1,
  234. [Grid.RowProperty] = 2,
  235. },
  236. }
  237. },
  238. };
  239. DevTools.Attach(window);
  240. //var renderer = ((IRenderRoot)window).Renderer;
  241. //var last = renderer.RenderCount;
  242. //DispatcherTimer.Run(() =>
  243. //{
  244. // fps.Text = "FPS: " + (renderer.RenderCount - last);
  245. // last = renderer.RenderCount;
  246. // return true;
  247. //}, TimeSpan.FromSeconds(1));
  248. window.Show();
  249. Application.Current.Run(window);
  250. }
  251. private static TabItem ButtonsTab()
  252. {
  253. Button defaultButton;
  254. var showDialog = ReactiveCommand.Create();
  255. Button showDialogButton;
  256. var result = new TabItem
  257. {
  258. Header = "Buttons",
  259. Content = new StackPanel
  260. {
  261. Orientation = Orientation.Vertical,
  262. HorizontalAlignment = HorizontalAlignment.Center,
  263. VerticalAlignment = VerticalAlignment.Center,
  264. Gap = 8,
  265. MinWidth = 120,
  266. Children = new Controls
  267. {
  268. (showDialogButton = new Button
  269. {
  270. Content = "Button",
  271. Command = showDialog,
  272. [ToolTip.TipProperty] = "Hello World!",
  273. }),
  274. new Button
  275. {
  276. Content = "Button",
  277. Background = new SolidColorBrush(0xcc119eda),
  278. [ToolTip.TipProperty] = "Goodbye Cruel World!",
  279. },
  280. (defaultButton = new Button
  281. {
  282. Content = "Default",
  283. IsDefault = true,
  284. }),
  285. new Button
  286. {
  287. Content = "Disabled",
  288. IsEnabled = false,
  289. },
  290. new Button
  291. {
  292. Content = "Disabled",
  293. IsEnabled = false,
  294. Background = new SolidColorBrush(0xcc119eda),
  295. },
  296. new ToggleButton
  297. {
  298. Content = "Toggle",
  299. },
  300. new ToggleButton
  301. {
  302. Content = "Disabled",
  303. IsEnabled = false,
  304. },
  305. new CheckBox
  306. {
  307. Content = "Checkbox",
  308. },
  309. new RadioButton
  310. {
  311. Content = "RadioButton 1",
  312. IsChecked = true,
  313. },
  314. new RadioButton
  315. {
  316. Content = "RadioButton 2",
  317. },
  318. }
  319. },
  320. };
  321. defaultButton.Click += (s, e) =>
  322. {
  323. defaultButton.Content = ((string)defaultButton.Content == "Default") ? "Clicked" : "Default";
  324. };
  325. showDialog.Subscribe(async _ =>
  326. {
  327. var close = ReactiveCommand.Create();
  328. var dialog = new Window
  329. {
  330. Content = new StackPanel
  331. {
  332. Width = 200,
  333. Height = 200,
  334. Children = new Controls
  335. {
  336. new Button { Content = "Yes", Command = close, CommandParameter = "Yes" },
  337. new Button { Content = "No", Command = close, CommandParameter = "No" },
  338. }
  339. }
  340. };
  341. close.Subscribe(x => dialog.Close(x));
  342. showDialogButton.Content = await dialog.ShowDialog<string>();
  343. });
  344. return result;
  345. }
  346. private static TabItem HtmlTab()
  347. {
  348. var htmlText =
  349. new StreamReader(typeof (Program).Assembly.GetManifestResourceStream("TestApplication.html.htm"))
  350. .ReadToEnd();
  351. return new TabItem
  352. {
  353. Header = "Html",
  354. Content = new ScrollViewer()
  355. {
  356. Width = 600,
  357. MaxHeight = 600,
  358. HorizontalAlignment = HorizontalAlignment.Center,
  359. CanScrollHorizontally = false,
  360. VerticalScrollBarVisibility = ScrollBarVisibility.Visible,
  361. Content =
  362. new HtmlLabel()
  363. {
  364. Text = htmlText
  365. }
  366. }
  367. };
  368. }
  369. private static TabItem TextTab()
  370. {
  371. return new TabItem
  372. {
  373. Header = "Text",
  374. Content = new StackPanel
  375. {
  376. Orientation = Orientation.Vertical,
  377. HorizontalAlignment = HorizontalAlignment.Center,
  378. VerticalAlignment = VerticalAlignment.Center,
  379. Gap = 8,
  380. Width = 120,
  381. Children = new Controls
  382. {
  383. new TextBlock
  384. {
  385. Text = "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Proin venenatis dui quis libero suscipit tincidunt.",
  386. TextWrapping = TextWrapping.Wrap,
  387. TextAlignment = TextAlignment.Center,
  388. },
  389. new TextBlock
  390. {
  391. Text = "Italic text.",
  392. FontStyle = FontStyle.Italic,
  393. TextAlignment = TextAlignment.Left,
  394. },
  395. new TextBlock
  396. {
  397. Text = "Bold text.",
  398. FontWeight = FontWeight.Bold,
  399. TextAlignment = TextAlignment.Right,
  400. },
  401. new TextBox
  402. {
  403. Text = "A non-wrapping text box. Lorem ipsum dolor sit amet.",
  404. TextWrapping = TextWrapping.NoWrap,
  405. },
  406. new TextBox
  407. {
  408. AcceptsReturn = true,
  409. Text = "A wrapping text box. " +
  410. "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Proin venenatis dui quis libero suscipit tincidunt. " +
  411. "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Proin venenatis dui quis libero suscipit tincidunt.",
  412. TextWrapping = TextWrapping.Wrap,
  413. MaxHeight = 100,
  414. },
  415. }
  416. },
  417. };
  418. }
  419. private static TabItem ImagesTab()
  420. {
  421. ScrollBar size;
  422. return new TabItem
  423. {
  424. Header = "Images",
  425. Content = new StackPanel
  426. {
  427. Orientation = Orientation.Vertical,
  428. HorizontalAlignment = HorizontalAlignment.Center,
  429. VerticalAlignment = VerticalAlignment.Center,
  430. Gap = 8,
  431. Children = new Controls
  432. {
  433. (size = new ScrollBar
  434. {
  435. Minimum = 100,
  436. Maximum = 400,
  437. Value = 100,
  438. Orientation = Orientation.Horizontal,
  439. }),
  440. new ScrollViewer
  441. {
  442. Width = 200,
  443. Height = 200,
  444. CanScrollHorizontally = true,
  445. Content = new Image
  446. {
  447. Source = new Bitmap("github_icon.png"),
  448. [!Layoutable.WidthProperty] = size[!RangeBase.ValueProperty],
  449. [!Layoutable.HeightProperty] = size[!RangeBase.ValueProperty],
  450. },
  451. },
  452. new ProgressBar
  453. {
  454. [!RangeBase.MinimumProperty] = size[!RangeBase.MinimumProperty],
  455. [!RangeBase.MaximumProperty] = size[!RangeBase.MaximumProperty],
  456. [!RangeBase.ValueProperty] = size[!RangeBase.ValueProperty],
  457. }
  458. }
  459. },
  460. };
  461. }
  462. private static TabItem ListsTab()
  463. {
  464. ListBox listBox;
  465. return new TabItem
  466. {
  467. Header = "Lists",
  468. Content = new StackPanel
  469. {
  470. DataTemplates = new DataTemplates
  471. {
  472. new DataTemplate<Item>(x =>
  473. new StackPanel
  474. {
  475. Children = new Controls
  476. {
  477. new TextBlock { Text = x.Name, FontSize = 24 },
  478. new TextBlock { Text = x.Value },
  479. }
  480. })
  481. },
  482. Orientation = Orientation.Horizontal,
  483. HorizontalAlignment = HorizontalAlignment.Center,
  484. VerticalAlignment = VerticalAlignment.Center,
  485. Gap = 8,
  486. Children = new Controls
  487. {
  488. new TreeView
  489. {
  490. Name = "treeView",
  491. Items = s_treeData,
  492. },
  493. (listBox = new ListBox
  494. {
  495. Items = s_listBoxData,
  496. MaxHeight = 300,
  497. }),
  498. new DropDown
  499. {
  500. Items = s_listBoxData,
  501. SelectedItem = s_listBoxData[0],
  502. VerticalAlignment = VerticalAlignment.Center,
  503. }
  504. }
  505. },
  506. };
  507. }
  508. private static TabItem LayoutTab()
  509. {
  510. return new TabItem
  511. {
  512. Header = "Layout",
  513. Content = new Grid
  514. {
  515. ColumnDefinitions = new ColumnDefinitions
  516. {
  517. new ColumnDefinition(1, GridUnitType.Star),
  518. new ColumnDefinition(1, GridUnitType.Star),
  519. },
  520. Margin = new Thickness(50),
  521. Children = new Controls
  522. {
  523. new StackPanel
  524. {
  525. Orientation = Orientation.Vertical,
  526. Gap = 8,
  527. Children = new Controls
  528. {
  529. new Button { HorizontalAlignment = HorizontalAlignment.Left, Content = "Left Aligned" },
  530. new Button { HorizontalAlignment = HorizontalAlignment.Center, Content = "Center Aligned" },
  531. new Button { HorizontalAlignment = HorizontalAlignment.Right, Content = "Right Aligned" },
  532. new Button { HorizontalAlignment = HorizontalAlignment.Stretch, Content = "Stretch" },
  533. },
  534. [Grid.ColumnProperty] = 0,
  535. },
  536. new StackPanel
  537. {
  538. Orientation = Orientation.Horizontal,
  539. Gap = 8,
  540. Children = new Controls
  541. {
  542. new Button { VerticalAlignment = VerticalAlignment.Top, Content = "Top Aligned" },
  543. new Button { VerticalAlignment = VerticalAlignment.Center, Content = "Center Aligned" },
  544. new Button { VerticalAlignment = VerticalAlignment.Bottom, Content = "Bottom Aligned" },
  545. new Button { VerticalAlignment = VerticalAlignment.Stretch, Content = "Stretch" },
  546. },
  547. [Grid.ColumnProperty] = 1,
  548. },
  549. },
  550. }
  551. };
  552. }
  553. private static TabItem AnimationsTab()
  554. {
  555. Border border1;
  556. Border border2;
  557. RotateTransform rotate;
  558. Button button1;
  559. var result = new TabItem
  560. {
  561. Header = "Animations",
  562. Content = new Grid
  563. {
  564. ColumnDefinitions = new ColumnDefinitions
  565. {
  566. new ColumnDefinition(1, GridUnitType.Star),
  567. new ColumnDefinition(1, GridUnitType.Star),
  568. },
  569. RowDefinitions = new RowDefinitions
  570. {
  571. new RowDefinition(1, GridUnitType.Star),
  572. new RowDefinition(GridLength.Auto),
  573. },
  574. Children = new Controls
  575. {
  576. (border1 = new Border
  577. {
  578. Width = 100,
  579. Height = 100,
  580. HorizontalAlignment = HorizontalAlignment.Center,
  581. VerticalAlignment = VerticalAlignment.Center,
  582. Background = Brushes.Crimson,
  583. RenderTransform = new RotateTransform(),
  584. Child = new TextBox
  585. {
  586. Background = Brushes.White,
  587. Text = "Hello!",
  588. HorizontalAlignment = HorizontalAlignment.Center,
  589. VerticalAlignment = VerticalAlignment.Center,
  590. },
  591. }),
  592. (border2 = new Border
  593. {
  594. Width = 100,
  595. Height = 100,
  596. HorizontalAlignment = HorizontalAlignment.Center,
  597. VerticalAlignment = VerticalAlignment.Center,
  598. Background = Brushes.Coral,
  599. Child = new Image
  600. {
  601. Source = new Bitmap("github_icon.png"),
  602. HorizontalAlignment = HorizontalAlignment.Center,
  603. VerticalAlignment = VerticalAlignment.Center,
  604. },
  605. RenderTransform = (rotate = new RotateTransform
  606. {
  607. PropertyTransitions = new PropertyTransitions
  608. {
  609. RotateTransform.AngleProperty.Transition(500),
  610. }
  611. }),
  612. PropertyTransitions = new PropertyTransitions
  613. {
  614. Layoutable.WidthProperty.Transition(300),
  615. Layoutable.HeightProperty.Transition(1000),
  616. },
  617. [Grid.ColumnProperty] = 1,
  618. }),
  619. (button1 = new Button
  620. {
  621. HorizontalAlignment = HorizontalAlignment.Center,
  622. Content = "Animate",
  623. [Grid.ColumnProperty] = 1,
  624. [Grid.RowProperty] = 1,
  625. }),
  626. },
  627. },
  628. };
  629. button1.Click += (s, e) =>
  630. {
  631. if (border2.Width == 100)
  632. {
  633. border2.Width = border2.Height = 400;
  634. rotate.Angle = 180;
  635. }
  636. else
  637. {
  638. border2.Width = border2.Height = 100;
  639. rotate.Angle = 0;
  640. }
  641. };
  642. var start = Animate.Stopwatch.Elapsed;
  643. var degrees = Animate.Timer
  644. .Select(x =>
  645. {
  646. var elapsed = (x - start).TotalSeconds;
  647. var cycles = elapsed / 4;
  648. var progress = cycles % 1;
  649. return 360.0 * progress;
  650. });
  651. border1.RenderTransform.Bind(
  652. RotateTransform.AngleProperty,
  653. degrees,
  654. BindingPriority.Animation);
  655. return result;
  656. }
  657. }
  658. }