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 }