Mercurial > hg > nnchat
comparison ui.c @ 466:796508f828f6
Refactor much of the "windowing" UI code into a new module, ui.[ch]
author | Matti Hamalainen <ccr@tnsp.org> |
---|---|
date | Sat, 26 May 2012 06:56:18 +0300 |
parents | |
children | 56689f94e827 |
comparison
equal
deleted
inserted
replaced
465:c3b3b6d89084 | 466:796508f828f6 |
---|---|
1 /* | |
2 * NNChat - Custom chat client for NewbieNudes.com chatrooms | |
3 * Written by Matti 'ccr' Hämäläinen | |
4 * (C) Copyright 2008-2012 Tecnic Software productions (TNSP) | |
5 */ | |
6 #include "util.h" | |
7 #include "ui.h" | |
8 | |
9 nn_window_t *chatWindows[SET_MAX_WINDOWS], | |
10 *currWin = NULL; | |
11 | |
12 BOOL cursesInit = FALSE; | |
13 int cursorVisible = ERR; | |
14 WINDOW *mainWin = NULL, | |
15 *statusWin = NULL, | |
16 *editWin = NULL; | |
17 | |
18 | |
19 static nn_window_t *nn_window_new(const char *id) | |
20 { | |
21 nn_window_t *res = th_calloc(1, sizeof(nn_window_t)); | |
22 | |
23 if (res == NULL) return NULL; | |
24 | |
25 res->data = th_ringbuf_new(NN_BACKBUF_LEN, th_free); | |
26 if (res->data == NULL) | |
27 { | |
28 th_free(res); | |
29 return NULL; | |
30 } | |
31 | |
32 res->id = th_strdup(id); | |
33 | |
34 return res; | |
35 } | |
36 | |
37 | |
38 static void nn_window_free(nn_window_t *win) | |
39 { | |
40 if (win != NULL) | |
41 { | |
42 th_ringbuf_free(win->data); | |
43 th_free(win->id); | |
44 th_free(win); | |
45 } | |
46 } | |
47 | |
48 | |
49 nn_window_t *nnwin_main_window() | |
50 { | |
51 return chatWindows[0]; | |
52 } | |
53 | |
54 | |
55 nn_window_t *nnwin_get(const int index) | |
56 { | |
57 if (index >= 1 && index <= SET_MAX_WINDOWS) | |
58 return chatWindows[index - 1]; | |
59 else | |
60 return 0; | |
61 | |
62 } | |
63 | |
64 | |
65 BOOL nnwin_init(int delay) | |
66 { | |
67 if (LINES < 0 || LINES > 1000) LINES = 24; | |
68 if (COLS < 0 || COLS > 1000) COLS = 80; | |
69 | |
70 initscr(); | |
71 raw(); | |
72 keypad(stdscr, TRUE); | |
73 noecho(); | |
74 meta(stdscr, TRUE); | |
75 timeout(delay); | |
76 cursorVisible = curs_set(0); | |
77 | |
78 if (has_colors()) | |
79 { | |
80 start_color(); | |
81 | |
82 init_pair( 1, COLOR_RED, COLOR_BLACK); | |
83 init_pair( 2, COLOR_GREEN, COLOR_BLACK); | |
84 init_pair( 3, COLOR_YELLOW, COLOR_BLACK); | |
85 init_pair( 4, COLOR_BLUE, COLOR_BLACK); | |
86 init_pair( 5, COLOR_MAGENTA, COLOR_BLACK); | |
87 init_pair( 6, COLOR_CYAN, COLOR_BLACK); | |
88 init_pair( 7, COLOR_WHITE, COLOR_BLACK); | |
89 init_pair( 8, COLOR_BLACK, COLOR_BLACK); | |
90 | |
91 init_pair(10, COLOR_BLACK, COLOR_RED); | |
92 init_pair(11, COLOR_WHITE, COLOR_RED); | |
93 init_pair(12, COLOR_GREEN, COLOR_RED); | |
94 init_pair(13, COLOR_YELLOW, COLOR_RED); | |
95 init_pair(14, COLOR_BLUE, COLOR_RED); | |
96 init_pair(15, COLOR_MAGENTA, COLOR_RED); | |
97 init_pair(16, COLOR_CYAN, COLOR_RED); | |
98 } | |
99 | |
100 cursesInit = TRUE; | |
101 | |
102 if (!nnwin_init_windows()) | |
103 return FALSE; | |
104 | |
105 #ifdef PDCURSES | |
106 PDC_set_title("NNChat v" NN_VERSION); | |
107 #endif | |
108 | |
109 memset(chatWindows, 0, sizeof(chatWindows)); | |
110 chatWindows[0] = nn_window_new(NULL); | |
111 currWin = chatWindows[0]; | |
112 | |
113 return TRUE; | |
114 } | |
115 | |
116 | |
117 void nnwin_shutdown() | |
118 { | |
119 int i; | |
120 | |
121 for (i = 0; i < SET_MAX_WINDOWS; i++) | |
122 nn_window_free(chatWindows[i]); | |
123 | |
124 if (cursesInit) | |
125 { | |
126 if (cursorVisible != ERR) | |
127 curs_set(cursorVisible); | |
128 | |
129 nnwin_close_windows(); | |
130 | |
131 endwin(); | |
132 THMSG(1, "NCurses deinitialized.\n"); | |
133 } | |
134 } | |
135 | |
136 | |
137 nn_window_t *nnwin_find(const char *id) | |
138 { | |
139 int i; | |
140 | |
141 for (i = 0; i < SET_MAX_WINDOWS; i++) | |
142 { | |
143 if (chatWindows[i] != NULL && | |
144 chatWindows[i]->id != NULL && | |
145 th_strcasecmp(id, chatWindows[i]->id) == 0) | |
146 return chatWindows[i]; | |
147 } | |
148 | |
149 return NULL; | |
150 } | |
151 | |
152 | |
153 BOOL nnwin_open(const char *name, BOOL curwin) | |
154 { | |
155 int i; | |
156 nn_window_t *res; | |
157 if (name == NULL) | |
158 return FALSE; | |
159 | |
160 if ((res = nn_window_new(name)) == NULL) | |
161 return FALSE; | |
162 | |
163 for (i = 1; i < SET_MAX_WINDOWS; i++) | |
164 if (chatWindows[i] == NULL) | |
165 { | |
166 res->num = i; | |
167 chatWindows[i] = res; | |
168 if (curwin) | |
169 currWin = res; | |
170 return TRUE; | |
171 } | |
172 | |
173 return FALSE; | |
174 } | |
175 | |
176 | |
177 void nnwin_close(nn_window_t *win) | |
178 { | |
179 int i; | |
180 if (win == NULL) return; | |
181 | |
182 for (i = 1; i < SET_MAX_WINDOWS; i++) | |
183 if (chatWindows[i] == win) | |
184 { | |
185 chatWindows[i] = NULL; | |
186 nn_window_free(win); | |
187 return; | |
188 } | |
189 } | |
190 | |
191 | |
192 void nnwin_update_statusline(char *optUserName, int optUserColor) | |
193 { | |
194 char tmpStr[128]; | |
195 int i; | |
196 | |
197 if (statusWin == NULL) return; | |
198 | |
199 str_get_timestamp(tmpStr, sizeof(tmpStr), "%H:%M:%S"); | |
200 | |
201 wbkgdset(statusWin, COLOR_PAIR(10)); | |
202 werase(statusWin); | |
203 | |
204 wattrset(statusWin, A_BOLD | COLOR_PAIR(11)); | |
205 mvwaddstr(statusWin, 0, 1, tmpStr); | |
206 | |
207 wattrset(statusWin, A_BOLD | COLOR_PAIR(13)); | |
208 waddstr(statusWin, " | "); | |
209 wattrset(statusWin, A_BOLD | COLOR_PAIR(16)); | |
210 waddstr(statusWin, optUserName); | |
211 wattrset(statusWin, A_BOLD | COLOR_PAIR(13)); | |
212 | |
213 wattrset(statusWin, A_BOLD | COLOR_PAIR(13)); | |
214 waddstr(statusWin, " | "); | |
215 wattrset(statusWin, A_BOLD | COLOR_PAIR(11)); | |
216 snprintf(tmpStr, sizeof(tmpStr), "#%06x", optUserColor); | |
217 waddstr(statusWin, tmpStr); | |
218 | |
219 wattrset(statusWin, A_BOLD | COLOR_PAIR(13)); | |
220 waddstr(statusWin, " | WIN: "); | |
221 snprintf(tmpStr, sizeof(tmpStr), "%d: %s / %d", | |
222 currWin->num + 1, | |
223 currWin->id != NULL ? currWin->id : "MAIN", | |
224 currWin->pos); | |
225 waddstr(statusWin, tmpStr); | |
226 | |
227 wattrset(statusWin, A_BOLD | COLOR_PAIR(13)); | |
228 waddstr(statusWin, " | "); | |
229 wattrset(statusWin, A_BOLD | COLOR_PAIR(11)); | |
230 | |
231 for (i = 0; i < SET_MAX_WINDOWS; i++) | |
232 { | |
233 if (chatWindows[i] != NULL && chatWindows[i]->dirty) | |
234 { | |
235 snprintf(tmpStr, sizeof(tmpStr), "%d ", i + 1); | |
236 waddstr(statusWin, tmpStr); | |
237 } | |
238 } | |
239 | |
240 wrefresh(statusWin); | |
241 } | |
242 | |
243 | |
244 void nnwin_update_editbuf(nn_editbuf_t *buf) | |
245 { | |
246 char *tmp; | |
247 if (editWin == NULL || buf == NULL) return; | |
248 | |
249 buf->data[buf->len] = 0; | |
250 tmp = nn_username_decode(th_strdup(buf->data)); | |
251 | |
252 werase(editWin); | |
253 | |
254 wattrset(editWin, A_NORMAL); | |
255 | |
256 if (buf->pos < buf->len) | |
257 { | |
258 waddnstr(editWin, tmp, buf->pos); | |
259 wattrset(editWin, A_REVERSE); | |
260 waddch(editWin, tmp[buf->pos]); | |
261 wattrset(editWin, A_NORMAL); | |
262 waddnstr(editWin, tmp + buf->pos + 1, buf->len - buf->pos - 1); | |
263 } | |
264 else | |
265 { | |
266 waddnstr(editWin, tmp, buf->len); | |
267 wattrset(editWin, A_REVERSE); | |
268 waddch(editWin, ' '); | |
269 wattrset(editWin, A_NORMAL); | |
270 } | |
271 wrefresh(editWin); | |
272 th_free(tmp); | |
273 } | |
274 | |
275 | |
276 int nnwin_print(WINDOW *win, const char *fmt) | |
277 { | |
278 const char *s = fmt; | |
279 int col = 0; | |
280 | |
281 while (*s) | |
282 { | |
283 if (*s == '½') | |
284 { | |
285 s++; | |
286 if (*s == '½') | |
287 { | |
288 waddch(win, ((unsigned char) *s) | col); | |
289 s++; | |
290 } | |
291 else | |
292 { | |
293 memcpy(&col, s, sizeof(int)); | |
294 s += sizeof(int); | |
295 } | |
296 } | |
297 else | |
298 { | |
299 waddch(win, ((unsigned char) *s) | col); | |
300 s++; | |
301 } | |
302 } | |
303 return 0; | |
304 } | |
305 | |
306 | |
307 #define QPUTCH(ch) th_vputch(&(win->buf), &(win->bufsize), &(win->len), ch) | |
308 | |
309 int nnwin_print_buf(nn_window_t *win, const char *fmt) | |
310 { | |
311 const char *s = fmt; | |
312 int col = 0; | |
313 while (*s) | |
314 { | |
315 if (*s == '½') | |
316 { | |
317 s++; | |
318 if (*s == '½') | |
319 { | |
320 QPUTCH(*s); | |
321 QPUTCH(*s); | |
322 win->chlen++; | |
323 } | |
324 else | |
325 { | |
326 int val = 0; | |
327 while (*s >= '0' && *s <= '9') | |
328 { | |
329 val *= 10; | |
330 val += (*s - '0'); | |
331 s++; | |
332 } | |
333 if (*s != '½') return -1; | |
334 | |
335 if (val < 9) | |
336 col = A_DIM | COLOR_PAIR(val); | |
337 else if (val < 30) | |
338 col = A_BOLD | COLOR_PAIR(val - 9); | |
339 | |
340 QPUTCH('½'); | |
341 | |
342 if (!th_growbuf(&(win->buf), &(win->bufsize), &(win->len), sizeof(int))) | |
343 return -2; | |
344 | |
345 memcpy(win->buf + win->len, &col, sizeof(int)); | |
346 win->len += sizeof(int); | |
347 } | |
348 } | |
349 else if (*s == '\n') | |
350 { | |
351 QPUTCH('\n'); | |
352 QPUTCH(0); | |
353 th_ringbuf_add(win->data, win->buf); | |
354 win->buf = NULL; | |
355 win->chlen = 0; | |
356 win->dirty = TRUE; | |
357 } | |
358 else if (*s != '\r') | |
359 { | |
360 QPUTCH((unsigned char) *s == 255 ? ' ' : *s); | |
361 win->chlen++; | |
362 } | |
363 | |
364 s++; | |
365 } | |
366 | |
367 return 0; | |
368 } | |
369 | |
370 | |
371 void nnwin_update_all(void) | |
372 { | |
373 if (mainWin) redrawwin(mainWin); | |
374 if (statusWin) redrawwin(statusWin); | |
375 if (editWin) redrawwin(editWin); | |
376 } | |
377 | |
378 | |
379 char *nnwin_prompt_requester(WINDOW *win, const char *info, BOOL allowEmpty) | |
380 { | |
381 char tmpBuf[512], *ptr; | |
382 size_t pos; | |
383 int curSave = curs_set(1); | |
384 | |
385 echo(); | |
386 waddstr(win, info); | |
387 wgetnstr(win, tmpBuf, sizeof(tmpBuf) - 1); | |
388 noecho(); | |
389 | |
390 if (curSave != ERR) | |
391 curs_set(curSave); | |
392 | |
393 for (pos = strlen(tmpBuf) - 1; pos > 0 && th_isspace(tmpBuf[pos]); pos--) | |
394 tmpBuf[pos] = 0; | |
395 | |
396 ptr = str_trim_left(tmpBuf); | |
397 | |
398 if (allowEmpty || strlen(ptr) > 0) | |
399 return th_strdup(ptr); | |
400 else | |
401 return NULL; | |
402 } | |
403 | |
404 | |
405 BOOL nnwin_update_main(BOOL force) | |
406 { | |
407 int h, offs; | |
408 qringbuf_t *buf; | |
409 | |
410 // Check pointers | |
411 if (mainWin == NULL || currWin == NULL) | |
412 return FALSE; | |
413 | |
414 // Check if update is forced or if the window is dirty | |
415 if (!force && !currWin->dirty) | |
416 return FALSE; | |
417 | |
418 // Compute how many lines from backbuffer fit on the screen | |
419 buf = currWin->data; | |
420 h = getmaxy(mainWin); | |
421 | |
422 // Clear and redraw window | |
423 werase(mainWin); | |
424 scrollok(mainWin, 1); | |
425 for (offs = buf->size - h - currWin->pos; offs >= 0 && offs < buf->size - currWin->pos && offs < buf->size; offs++) | |
426 { | |
427 if (buf->data[offs] != NULL) | |
428 nnwin_print(mainWin, buf->data[offs]); | |
429 } | |
430 | |
431 currWin->dirty = FALSE; | |
432 wrefresh(mainWin); | |
433 return TRUE; | |
434 } | |
435 | |
436 | |
437 void nnwin_close_windows(void) | |
438 { | |
439 if (mainWin) delwin(mainWin); | |
440 if (statusWin) delwin(statusWin); | |
441 if (editWin) delwin(editWin); | |
442 } | |
443 | |
444 | |
445 BOOL nnwin_init_windows(void) | |
446 { | |
447 int w, h; | |
448 | |
449 getmaxyx(stdscr, h, w); | |
450 | |
451 nnwin_close_windows(); | |
452 | |
453 mainWin = subwin(stdscr, h - 4, w, 0, 0); | |
454 statusWin = subwin(stdscr, 1, w, h - 4, 0); | |
455 editWin = subwin(stdscr, 3, w, h - 3, 0); | |
456 | |
457 if (mainWin == NULL || statusWin == NULL || editWin == NULL) | |
458 return FALSE; | |
459 | |
460 return TRUE; | |
461 } |