1 /** 2 * Color demo for dcell. 3 * 4 * Copyright: Copyright 2025 Garrett D'Amore 5 * Authors: Garrett D'Amore 6 * License: 7 * Distributed under the Boost Software License, Version 1.0. 8 * (See accompanying file LICENSE or https://www.boost.org/LICENSE_1_0.txt) 9 * SPDX-License-Identifier: BSL-1.0 10 */ 11 module color; 12 13 import core.time; 14 import std.stdio; 15 import std.string; 16 import std.random; 17 import std.range; 18 import dcell; 19 20 class ColorBoxes 21 { 22 import std.random; 23 24 int r; 25 int g; 26 int b; 27 int ri; 28 int gi; 29 int bi; 30 Random rng; 31 enum inc = 8; 32 int cnt; 33 bool done; 34 Screen s; 35 36 bool flip() @safe 37 { 38 return (rng.uniform!ubyte() & 0x1) != 0; 39 } 40 41 this(Screen scr) 42 { 43 rng = rndGen(); 44 r = rng.uniform!ubyte(); 45 g = rng.uniform!ubyte(); 46 b = rng.uniform!ubyte(); 47 ri = inc; 48 gi = inc / 4; // humans are very sensitive to green 49 bi = inc; 50 s = scr; 51 } 52 53 void makeBox() @safe 54 { 55 Coord wsz = s.size(); 56 dchar dc = ' '; 57 Style style; 58 cnt++; 59 60 if (s.colors() == 0) 61 { 62 dchar[] glyphs = ['@', '#', '&', '*', '=', '%', 'Z', 'A']; 63 dc = choice(glyphs, rng); 64 if (flip()) 65 style.attr |= Attr.reverse; 66 else 67 style.attr &= ~Attr.reverse; 68 } 69 else 70 { 71 r += ri; 72 g += gi; 73 b += bi; 74 if (r >= 256 || r < 0) 75 { 76 ri = -ri; 77 r += ri; 78 } 79 if (g >= 256 || g < 0) 80 { 81 gi = -gi; 82 g += gi; 83 } 84 if (b >= 256 || b < 0) 85 { 86 bi = -bi; 87 b += bi; 88 } 89 if (cnt % (256 / inc) == 0) 90 { 91 if (flip()) 92 { 93 ri = -ri; 94 } 95 96 if (flip()) 97 { 98 gi = -gi; 99 } 100 101 if (flip()) 102 { 103 bi = -bi; 104 } 105 } 106 style.bg = fromHex( 107 int(r) << 16 | int(g) << 8 | int(b)); 108 } 109 110 // half the width and half the height 111 Coord c1 = Coord(wsz.x / 4, wsz.y / 4); 112 Coord c2 = Coord(c1.x + wsz.x / 2, c1.y + wsz.y / 2); 113 Coord pos = c1; 114 Cell cell = Cell(dc, style); 115 for (pos.y = c1.y; pos.y <= c2.y; pos.y++) 116 { 117 for (pos.x = c1.x; pos.x <= c2.x; pos.x++) 118 { 119 s[pos] = cell; 120 } 121 } 122 s.show(); 123 } 124 125 void handleEvent(Event ev) @safe 126 { 127 switch (ev.type) 128 { 129 case EventType.key: 130 switch (ev.key.key) 131 { 132 case Key.esc, Key.enter: 133 done = true; 134 break; 135 case Key.graph: 136 // Ctrl-L (without other modifiers) used to force a redraw. 137 if (ev.key.ch == 'l' && ev.key.mod == Modifiers.ctrl) 138 { 139 s.resize(); 140 s.sync(); 141 } 142 break; 143 default: 144 145 } 146 break; 147 case EventType.resize: 148 s.resize(); 149 break; 150 case EventType.closed: 151 done = true; 152 break; 153 case EventType.error: 154 assert(0, "error received"); 155 default: 156 } 157 } 158 159 void run() @safe 160 { 161 s.start(); 162 scope (exit) 163 { 164 s.stop(); 165 } 166 done = false; 167 makeBox(); 168 while (!done) 169 { 170 loop: foreach (ev; s.events()) 171 { 172 switch (ev.type) 173 { 174 case EventType.key: 175 switch (ev.key.key) 176 { 177 case Key.esc, Key.enter: 178 done = true; 179 break loop; 180 case Key.graph: 181 // Ctrl-L (without other modifiers) used to force a redraw. 182 if (ev.key.ch == 'l' && ev.key.mod == Modifiers.ctrl) 183 { 184 s.resize(); 185 s.sync(); 186 } 187 break; 188 default: 189 } 190 break; 191 case EventType.resize: 192 s.resize(); 193 break; 194 case EventType.closed: 195 done = true; 196 break loop; 197 case EventType.error: 198 assert(0, "error received"); 199 default: 200 } 201 } 202 makeBox(); 203 s.position = Coord(1, 1); 204 s.waitForEvent(msecs(50)); 205 } 206 } 207 } 208 209 void main() 210 { 211 import std.stdio; 212 import core.time; 213 import core.stdc.stdlib; 214 215 ColorBoxes cb = new ColorBoxes(newScreen()); 216 217 auto now = MonoTime.currTime(); 218 cb.run(); 219 auto end = MonoTime.currTime(); 220 writefln("Drew %d boxes in %s.", cb.cnt, end - now); 221 writefln("Average per box %s.", (end - now) / cb.cnt); 222 }