1 /* $Id: draw.c,v 1.4 2007/02/28 12:47:35 tamentis Exp $
2 *
3 * Copyright (c) 2007 Bertrand Janin <tamentis@neopulsar.org>
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE.
26 */
27
28
29 #include <sys/ioctl.h>
30 #if !defined(__DragonFly__) && !defined(__FreeBSD__)
31 #include <sys/termios.h>
32 #else
33 #include <termios.h>
34 #endif
35
36 #include <unistd.h>
37 #include <string.h>
38 #include <stdlib.h>
39 #include <signal.h>
40 #include <err.h>
41 #include <curses.h>
42
43 #include "tbclock.h"
44
45
46 extern struct tbclock_data tbc;
47 static WINDOW *screen;
48
49 /* tbc_draw_helpers - draw the currently selected reading help */
50 void
tbc_draw_helpers(int res,int hour,int min,int sec,int dsec)51 tbc_draw_helpers(int res, int hour, int min, int sec, int dsec)
52 {
53 int space;
54 char st[12];
55
56 /* display bottom (full) helper */
57 if (tbc.format.height > 3 && tbc.options.helper > 1) {
58 unsigned i;
59
60 /* do we need to show tenth of sec ? */
61 if (res > 3)
62 i = snprintf(st, 12, "%02u:%02u:%02u:%02d",
63 hour, min, sec, dsec);
64 else
65 i = snprintf(st, 9, "%02u:%02u:%02u", hour, min, sec);
66
67 bkgdset(COLOR_PAIR(TEXT_DEFAULT));
68 mvprintw(tbc.format.height - 1 - tbc.options.frame,
69 tbc.format.width / 2 - (i / 2), st);
70 }
71
72 /* side helper if opt_helper == 1 or 3 and not vertical mode */
73 if (!tbc.options.vertical && tbc.options.helper & 1) {
74 unsigned int tm, lm;
75
76 tm = tbc.format.top_margin + tbc.format.dot_h / 2;
77 lm = tbc.format.width - 2 - tbc.options.frame;
78 space = tbc.format.dot_h + tbc.options.border;
79
80 bkgdset(COLOR_PAIR(TEXT_DEFAULT));
81 snprintf(st, 3, "%02u", hour);
82 mvprintw(tm, lm, st);
83 snprintf(st, 3, "%02u", min);
84 mvprintw(tm + space, lm, st);
85 snprintf(st, 3, "%02u", sec);
86 mvprintw(tm + space * 2, lm, st);
87 if (res > 3) {
88 snprintf(st, 3, "%02u", dsec);
89 mvprintw(tm + space * 3, lm, st);
90 }
91 }
92
93 /* bottom helper if opt_helper == 3 or 1 in vertical mode */
94 if (tbc.options.vertical && tbc.options.helper == 1) {
95 unsigned int tm, lm;
96
97 tm = tbc.format.height - tbc.options.frame - 1;
98 lm = tbc.format.left_margin + ((tbc.format.dot_w - 1) * 2
99 + tbc.options.border) / 2;
100 space = (tbc.options.border + tbc.format.dot_w) * 2;
101
102 bkgdset(COLOR_PAIR(TEXT_DEFAULT));
103 snprintf(st, 3, "%02u", hour);
104 mvprintw(tm, lm, st);
105 snprintf(st, 3, "%02u", min);
106 mvprintw(tm, lm + space, st);
107 snprintf(st, 3, "%02u", sec);
108 mvprintw(tm, lm + space * 2, st);
109 if (res > 3) {
110 snprintf(st, 3, "%02u", dsec);
111 mvprintw(tm, lm + space * 3, st);
112 }
113 }
114 }
115
116
117 /* tbc_draw_dot - prints one dot if valid */
118 void
tbc_draw_dot(int valid,int x,int y,short color)119 tbc_draw_dot(int valid, int x, int y, short color)
120 {
121 int i;
122 char *s, c = '#';
123
124 /* display alternative character for empty 'dots' */
125 if (!valid) {
126 color = BLOCK_DEFAULT;
127 if (tbc.options.dots)
128 c = '.';
129 else
130 c = ' ';
131 }
132
133 /* generate a NULL-terminated line of this character */
134 s = malloc(tbc.format.dot_w + 1);
135 memset(s, c, tbc.format.dot_w);
136 s[tbc.format.dot_w] = 0;
137
138 /* print this line a few times */
139 bkgdset(COLOR_PAIR(color));
140 for (i = 0; i < tbc.format.dot_h; i++) {
141 mvprintw(y + i, x, s);
142 }
143
144 free(s);
145 }
146
147
148 /* tbc_draw_line - prints 6 dots with the same color */
149 void
tbc_draw_line(int hms,int y,short color)150 tbc_draw_line(int hms, int y, short color)
151 {
152 int k;
153 unsigned int x;
154
155 for (k = 0; k < 6; k++) {
156 x = tbc.format.left_margin
157 + (tbc.format.dot_w + tbc.options.border) * (5 - k);
158 tbc_draw_dot(hms & (1 << k), x, y + tbc.format.top_margin,
159 color);
160 }
161 }
162
163
164 /* tbc_draw_line_a - prints a vertical line (-a) */
165 void
tbc_draw_line_a(int hms,int x,short color,short max)166 tbc_draw_line_a(int hms, int x, short color, short max)
167 {
168 int k;
169 unsigned int y;
170
171 for (k = 0; k < 4; k++) {
172 y = tbc.format.top_margin
173 + (tbc.format.dot_h + tbc.options.border) * (3 - k);
174 if (k < max)
175 tbc_draw_dot( hms & (1<<k), x, y, color);
176 }
177 }
178
179
180 /* tbc_draw_time - draw the time, with or without tenth of seconds (res) */
181 void
tbc_draw_time(int res,int hour,int min,int sec,int dsec)182 tbc_draw_time(int res, int hour, int min, int sec, int dsec)
183 {
184 int space;
185 unsigned int ml = tbc.format.left_margin;
186
187 if (tbc.options.ampm && hour > 12)
188 hour -= 12;
189
190 if (tbc.options.vertical) {
191 space = tbc.options.border + tbc.format.dot_w;
192 tbc_draw_line_a(hour / 10, ml, BLOCK_HOUR, 2);
193 tbc_draw_line_a(hour % 10, ml + space, BLOCK_HOUR, 4);
194 tbc_draw_line_a(min / 10, ml + space * 2, BLOCK_MINUTE, 3);
195 tbc_draw_line_a(min % 10, ml + space * 3, BLOCK_MINUTE, 4);
196 tbc_draw_line_a(sec / 10, ml + space * 4, BLOCK_SECOND, 3);
197 tbc_draw_line_a(sec % 10, ml + space * 5, BLOCK_SECOND, 4);
198 if (res > 3)
199 tbc_draw_line_a(dsec, ml + space * 6, BLOCK_TENTH, 4);
200 } else {
201 space = tbc.format.dot_h + tbc.options.border;
202 tbc_draw_line(hour, 0, BLOCK_HOUR);
203 tbc_draw_line(min, space, BLOCK_MINUTE);
204 tbc_draw_line(sec, space * 2, BLOCK_SECOND);
205 if (res > 3)
206 tbc_draw_line(dsec, space * 3, BLOCK_TENTH);
207 }
208
209 tbc_draw_helpers(res, hour, min, sec, dsec);
210
211 move(0, 0);
212 }
213
214
215 /* resize - called when the terminal is resized ... */
216 void
resize(int signal)217 resize(int signal)
218 {
219 struct winsize ws;
220
221 clear();
222
223 if (ioctl(STDIN_FILENO, TIOCGWINSZ, &ws) != -1) {
224 resizeterm(ws.ws_row, ws.ws_col);
225 tbc.format.width = ws.ws_col;
226 tbc.format.height = ws.ws_row;
227 } else {
228 return;
229 }
230
231 tbc_configure();
232 }
233
234
235 /* tbc_clear - clear everything and redraw frame if needed */
236 void
tbc_clear(void)237 tbc_clear(void)
238 {
239 bkgdset(COLOR_PAIR(TEXT_DEFAULT));
240 clear();
241
242 /* prepare inside frame */
243 if (tbc.options.frame) {
244 box(screen, ACS_VLINE, ACS_HLINE);
245 mvprintw(0, tbc.format.width-14, TBCVER);
246 }
247 }
248
249
250 /* tbc_display_init - starts curses, obtains term size, set colors */
251 void
tbc_display_init()252 tbc_display_init()
253 {
254 struct winsize ws;
255
256 /* terminal size stuff */
257 signal(SIGWINCH, resize);
258 if (ioctl(STDIN_FILENO, TIOCGWINSZ, &ws) != -1) {
259 tbc.format.width = ws.ws_col;
260 tbc.format.height = ws.ws_row;
261 }
262
263 /* curses screen init */
264 screen = initscr();
265 noecho();
266 cbreak();
267 curs_set(0);
268 nodelay(screen, TRUE);
269
270 /* prepare colors */
271 start_color();
272 if (use_default_colors() != ERR) {
273 init_pair(TEXT_DEFAULT, -1, -1);
274 init_pair(BLOCK_HOUR, tbc.colors.hour, tbc.colors.hour);
275 init_pair(BLOCK_MINUTE, tbc.colors.minute, tbc.colors.minute);
276 init_pair(BLOCK_SECOND, tbc.colors.second, tbc.colors.second);
277 init_pair(BLOCK_TENTH, tbc.colors.tenth, tbc.colors.tenth);
278 init_pair(BLOCK_GREEN, COLOR_GREEN, COLOR_GREEN);
279 init_pair(BLOCK_BLUE, COLOR_BLUE, COLOR_BLUE);
280 init_pair(BLOCK_YELLOW, COLOR_YELLOW, COLOR_YELLOW);
281 init_pair(BLOCK_RED, COLOR_RED, COLOR_RED);
282 init_pair(BLOCK_GREEN, COLOR_GREEN, COLOR_GREEN);
283 init_pair(BLOCK_BLUE, COLOR_BLUE, COLOR_BLUE);
284 init_pair(BLOCK_YELLOW, COLOR_YELLOW, COLOR_YELLOW);
285 init_pair(TEXT_RED, COLOR_RED, -1);
286 init_pair(TEXT_GREEN, COLOR_GREEN, -1);
287 init_pair(TEXT_BLACK, COLOR_BLACK, -1);
288 init_pair(BACK_YELLOW, COLOR_BLACK, COLOR_YELLOW);
289 }
290 }
291
292