1 module fluid.showcase.buttons;
2 
3 import std.range;
4 
5 import fluid;
6 import fluid.showcase;
7 
8 
9 @safe:
10 
11 
12 @(
13     () => label("Buttons are the most basic node when it comes to user input. Pressing a button triggers an event, "
14         ~ "and that's about the functionality of the button. Under the hood, buttons are labels — but they're modified "
15         ~ "to react to user clicks."),
16     () => label("To initialize a button, you need to pass a delegate to dictate the button's effect. Here's one that "
17         ~ "does nothing:"),
18 )
19 Label buttonExample() {
20 
21     return button("Hello, World!", delegate { });
22 
23 }
24 
25 @(
26     () => label("Naturally, user interfaces are made to react to user input and other events that happen in the "
27         ~ "system. The interface needs to change to keep displayed information up to date. Glui nodes expose "
28         ~ "properties that make them possible to change. So, we can make the button change its text when clicked."),
29     () => label("Just note that to refer to the button within itself we need to declare it beforehand."),
30 )
31 Label mutableLabelExample() {
32 
33     import std.range : cycle;
34 
35     Button!() myButton;
36     auto texts = cycle(["Hello!", "Bonjour!", "¡Hola!", "Здравствуйте!"]);
37 
38     // Create the button
39     myButton = button(texts.front, delegate {
40 
41         // Switch to the next text when clicked
42         texts.popFront;
43         myButton.text = texts.front;
44 
45     });
46 
47     return myButton;
48 
49 }
50 
51 @(
52     () => label("Let's try making this a bit more complex. Once we connect a few nodes, we need to retain access to "
53         ~ "all the nodes we're interested. If we place a label in a frame, we still need to keep a reference to the "
54         ~ "label if we intend to change it. Fortunately, we can assign variables while building the tree. This is "
55         ~ "somewhat unconventional, since a typical user interface system would instead have you query nodes by ID, "
56         ~ "but this is simpler and more flexible."),
57 )
58 Frame nestedLabelFirstExample() {
59 
60     Label myLabel;
61     auto texts = cycle(["Hello!", "Bonjour!", "¡Hola!", "Здравствуйте!"]);
62 
63     return vframe(
64         myLabel = label(texts.front),
65         button("Change text", delegate {
66 
67             // Change text of the button when clicked
68             texts.popFront;
69             myLabel.text = texts.front;
70 
71         }),
72     );
73 
74 }
75 
76 @(
77     () => label("Of course, we also have the choice to assign the label on the same line it was declared "
78         ~ "on. The downside of that usage is that it is usually helpful to keep each component of the tree united "
79         ~ "for easier analysis. However, it might be preferrable if the tree is becoming complex, so you might need "
80         ~ "to find the right balance."),
81 
82     () => label(.headingTheme, "Editing layouts"),
83     () => label("Frame contents can be changed at runtime by changing their 'children' property. The operation is a "
84         ~ "bit more complex than updating labels, and you have to pay attention to this one if you intend to rearrange "
85         ~ "frames this way."),
86 )
87 Frame mutableFrameExample() {
88 
89     import std.algorithm : bringToFront;
90 
91     Frame myFrame;
92 
93     return vframe(
94         myFrame = hframe(
95             label("Foo, "),
96             label("Bar, "),
97             label("Baz, "),
98         ),
99         button("Reorder nodes", delegate {
100 
101             // Move the last node to start
102             bringToFront(
103                 myFrame.children[0..$-1],
104                 myFrame.children[$-1..$]
105             );
106             myFrame.updateSize();
107 
108         }),
109     );
110 
111 }
112 
113 // TODO cover .layout?
114 
115 @(
116     () => label("Fluid frames provide full control over their contents, making it possible to use the power of D "
117         ~ "libraries for the job. See, to move the nodes around in the example above, we use 'bringToFront' from "
118         ~ "std.algorithm. As a downside to this, Fluid is not able to detect changes and resize ahead of time, like it "
119         ~ "does with labels, so you must call 'updateSize()' on the frame for the changes to apply. Fluid will issue "
120         ~ "an error at runtime if you don't do this, so be careful!"),
121     () => label("Do not worry though, a lot of layout management can be made easier with helpers like nodeSlot, which "
122         ~ "we'll cover later."),
123 )
124 void endExample() { }