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 }