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("#aaa")), 94 when!"a.isFocused"(backgroundColor = color("#bbb")), // TODO use an outline for focus 95 when!"a.isPressed"(backgroundColor = color("#888")), 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("#0000"), 149 margin = 0, 150 when!"a.isHovered"(backgroundColor = color("#dadada")), 151 when!"a.isFocused"(backgroundColor = color("#ccc")), 152 when!"a.isPressed"(backgroundColor = color("#aaa")), 153 when!"a.isDisabled"( 154 textColor = color("000a"), 155 backgroundColor = color("eee5"), 156 ), 157 ), 158 ), 159 /*rule!FileInputSuggestion( 160 margin = 0, 161 backgroundColor = color("#fff"), 162 when!"a.isSelected"(backgroundColor = color("#55b9ff")) 163 ),*/ 164 rule!Checkbox( 165 margin.sideX = 8, 166 margin.sideY = 4, 167 border = 1, 168 padding = 1, 169 borderStyle = colorBorder(color("#555")), 170 mouseCursor = FluidMouseCursor.pointer, 171 172 when!"a.isFocused"(backgroundColor = color("#ddd")), 173 when!"a.isChecked"( 174 extra = new Checkbox.Extra(loadBWImage!"checkmark-alpha"(64, 50)), 175 ), 176 ), 177 rule!Radiobox( 178 margin.sideX = 8, 179 margin.sideY = 4, 180 border = 0, 181 borderStyle = null, 182 padding = 2, 183 extra = new Radiobox.Extra(1, color("#555"), color("#5552")), 184 185 when!"a.isFocused"(backgroundColor = color("#ddd")), 186 when!"a.isChecked"( 187 extra = new Radiobox.Extra(1, color("#555"), color("#000")) 188 ), 189 ), 190 rule!Separator( 191 padding = 4, 192 lineColor = color("#ccc"), 193 ), 194 rule!DragSlot( 195 padding.sideX = 6, 196 padding.sideY = 0, 197 border = 1, 198 borderStyle = colorBorder(color("#555a")), 199 backgroundColor = color("#fff"), 200 margin = 4, // for testing 201 ), 202 rule!DragHandle( 203 lineColor = color("#ccc"), 204 padding.sideX = 8, 205 padding.sideY = 6, 206 extra = new DragHandle.Extra(5), 207 ), 208 209 // Warning 210 rule!(Frame, FluidTag.warning)( 211 warningRule, 212 children( 213 textColor = color("#000"), 214 ), 215 children!Button( 216 border = 1, 217 borderStyle = colorBorder(warningAccentColor), 218 backgroundColor = color("#fff"), 219 ), 220 ), 221 rule!(Label, FluidTag.warning)( 222 warningRule, 223 ), 224 ); 225 226 } 227 228 }