1 module fluid.default_theme;
2 
3 import fluid.node;
4 import fluid.frame;
5 import fluid.style;
6 import fluid.label;
7 import fluid.button;
8 import fluid.slider;
9 import fluid.backend;
10 import fluid.structs;
11 import fluid.checkbox;
12 import fluid.radiobox;
13 import fluid.typeface;
14 import fluid.drag_slot;
15 import fluid.separator;
16 import fluid.file_input;
17 import fluid.text_input;
18 import fluid.popup_frame;
19 import fluid.number_input;
20 import fluid.scroll_input;
21 
22 /// Theme with no properties set.
23 ///
24 /// Unlike `Theme.init` or `null`, which will be replaced by fluidDefaultTheme or the parent's theme, this can be used as
25 /// a valid theme for any node. This makes it useful for automatic tests, since it has guaranteed no margins, padding,
26 /// or other properties that may confuse the tester.
27 Theme nullTheme;
28 
29 /// Default theme that Fluid will use if no theme is supplied. It is a very simple theme that does the minimum to make
30 /// the role of each node understandable.
31 Theme fluidDefaultTheme;
32 
33 @NodeTag 
34 enum FluidTag {
35     warning,
36 }
37 
38 Rule warningRule;
39 
40 static this() {
41 
42     const warningColor = color("#ffe186");
43     const warningAccentColor = color("#ffc30f");
44 
45     Image loadBWImage(string filename)(int width, int height) @trusted {
46 
47         import std.array;
48         import std.format;
49         import std.algorithm;
50 
51         const area = width * height;
52 
53         auto file = cast(ubyte[]) import(filename);
54         auto data = file.map!(a => Color(0, 0, 0, a)).array;
55 
56         assert(data.length == area, format!"Wrong %s area %s, expected %s"(filename, data.length, area));
57 
58         // TODO use Format.alpha
59         return Image(data, width, height);
60 
61     }
62 
63     with (Rule) {
64 
65         warningRule = rule(
66             Rule.padding.sideX = 16,
67             Rule.padding.sideY = 6,
68             Rule.border = 1,
69             Rule.borderStyle = colorBorder(warningAccentColor),
70             Rule.backgroundColor = warningColor,
71             Rule.textColor = color("#000"),
72         );
73 
74         nullTheme.add(
75             rule!Node(),
76         );
77 
78         fluidDefaultTheme.add(
79             rule!Node(
80                 typeface = Typeface.defaultTypeface,
81                 textColor = color("#000"),
82                 selectionBackgroundColor = color("#55b9ff"),
83             ),
84             rule!Frame(
85                 backgroundColor = color("#fff"),
86             ),
87             rule!Button(
88                 backgroundColor = color("#dadada"),
89                 mouseCursor = FluidMouseCursor.pointer,
90                 margin.sideY = 2,
91                 padding.sideX = 6,
92 
93                 when!"a.isHovered"(backgroundColor = color("#ccc")),
94                 when!"a.isFocused"(backgroundColor = color("#ddd")),  // TODO use an outline for focus
95                 when!"a.isPressed"(backgroundColor = color("#aaa")),
96                 when!"a.isDisabled"(
97                     textColor = color("000a"),
98                     backgroundColor = color("eee5"),
99                     // TODO disabled should apply opacity, and should work for every node
100                 ),
101             ),
102             rule!FrameButton(
103                 mouseCursor = FluidMouseCursor.pointer,
104             ),
105             rule!TextInput(
106                 backgroundColor = color("#fff"),
107                 borderStyle = colorBorder(color("#aaa")),
108                 mouseCursor = FluidMouseCursor.text,
109 
110                 margin.sideY = 2,
111                 padding.sideX = 6,
112                 border.sideBottom = 2,
113 
114                 when!"a.isEmpty"(textColor = color("#000a")),
115                 when!"a.isFocused"(borderStyle = colorBorder(color("#555")))
116                     .otherwise(selectionBackgroundColor = color("#ccc")),
117                 when!"a.isDisabled"(
118                     textColor = color("#000a"),
119                     backgroundColor = color("#fff5"),
120                 ),
121             ),
122             rule!NumberInputSpinner(
123                 mouseCursor = FluidMouseCursor.pointer,
124                 extra = new NumberInputSpinner.Extra(loadBWImage!"arrows-alpha"(40, 64)),
125             ),
126             rule!AbstractSlider(
127                 backgroundColor = color("#ddd"),
128                 lineColor = color("#ddd"),
129             ),
130             rule!SliderHandle(
131                 backgroundColor = color("#aaa"),
132             ),
133             rule!ScrollInput(
134                 backgroundColor = color("#eee"),
135             ),
136             rule!ScrollInputHandle(
137                 backgroundColor = color("#aaa"),
138 
139                 when!"a.isHovered"(backgroundColor = color("#888")),
140                 when!"a.isFocused"(backgroundColor = color("#777")),
141                 when!"a.isPressed"(backgroundColor = color("#555")),
142                 when!"a.isDisabled"(backgroundColor = color("#aaa5")),
143             ),
144             rule!PopupFrame(
145                 border = 1,
146                 borderStyle = colorBorder(color("#555a")),
147                 children!Button(
148                     backgroundColor = Color.init,
149                     margin = 0,
150                 ),
151             ),
152             /*rule!FileInputSuggestion(
153                 margin = 0,
154                 backgroundColor = color("#fff"),
155                 when!"a.isSelected"(backgroundColor = color("#55b9ff"))
156             ),*/
157             rule!Checkbox(
158                 margin.sideX = 8,
159                 margin.sideY = 4,
160                 border = 1,
161                 padding = 1,
162                 borderStyle = colorBorder(color("#555")),
163                 mouseCursor = FluidMouseCursor.pointer,
164 
165                 when!"a.isFocused"(backgroundColor = color("#ddd")),
166                 when!"a.isChecked"(
167                     extra = new Checkbox.Extra(loadBWImage!"checkmark-alpha"(64, 50)),
168                 ),
169             ),
170             rule!Radiobox(
171                 margin.sideX = 8,
172                 margin.sideY = 4,
173                 border = 0,
174                 borderStyle = null,
175                 padding = 2,
176                 extra = new Radiobox.Extra(1, color("#555"), color("#5550")),
177 
178                 when!"a.isFocused"(backgroundColor = color("#ddd")),
179                 when!"a.isChecked"(
180                     extra = new Radiobox.Extra(1, color("#555"), color("#000"))
181                 ),
182             ),
183             rule!Separator(
184                 padding = 4,
185                 lineColor = color("#ccc"),
186             ),
187             rule!DragSlot(
188                 padding.sideX = 6,
189                 padding.sideY = 0,
190                 border = 1,
191                 borderStyle = colorBorder(color("#555a")),
192                 backgroundColor = color("#fff"),
193                 margin = 4,  // for testing
194             ),
195             rule!DragHandle(
196                 lineColor = color("#ccc"),
197                 padding.sideX = 8,
198                 padding.sideY = 6,
199                 extra = new DragHandle.Extra(5),
200             ),
201 
202             // Warning
203             rule!(Frame, FluidTag.warning)(
204                 warningRule,
205                 children(
206                     textColor = color("#000"),
207                 ),
208                 children!Button(
209                     border = 1,
210                     borderStyle = colorBorder(warningAccentColor),
211                     backgroundColor = color("#fff"),
212                 ),
213             ),
214             rule!(Label, FluidTag.warning)(
215                 warningRule,
216             ),
217         );
218 
219     }
220 
221 }