Mercurial > hg > nnchat
comparison ui.c @ 501:ca88945d8eda
Begin work on integrating the removal of ncurses "windowing" and transition
to internally managing the screen as whole.
author | Matti Hamalainen <ccr@tnsp.org> |
---|---|
date | Fri, 01 Jun 2012 12:00:11 +0300 |
parents | 012f106bf290 |
children | bac3f9af112c |
comparison
equal
deleted
inserted
replaced
500:78447d70f9d3 | 501:ca88945d8eda |
---|---|
4 * (C) Copyright 2008-2012 Tecnic Software productions (TNSP) | 4 * (C) Copyright 2008-2012 Tecnic Software productions (TNSP) |
5 */ | 5 */ |
6 #include "util.h" | 6 #include "util.h" |
7 #include "ui.h" | 7 #include "ui.h" |
8 | 8 |
9 #define STATUS_YPOS 0 | |
10 | |
9 nn_window_t *chatWindows[SET_MAX_WINDOWS], | 11 nn_window_t *chatWindows[SET_MAX_WINDOWS], |
10 *currWin = NULL; | 12 *currWin = NULL; |
11 | 13 |
12 BOOL cursesInit = FALSE; | 14 BOOL cursesInit = FALSE; |
13 int cursorVisible = ERR; | 15 int cursorVisible = ERR, |
14 WINDOW *mainWin = NULL, | 16 scrWidth, scrHeight; |
15 *statusWin = NULL, | |
16 *editWin = NULL; | |
17 | 17 |
18 | 18 |
19 static nn_window_t *nn_window_new(const char *id) | 19 static nn_window_t *nn_window_new(const char *id) |
20 { | 20 { |
21 nn_window_t *res = th_calloc(1, sizeof(nn_window_t)); | 21 nn_window_t *res = th_calloc(1, sizeof(nn_window_t)); |
61 } | 61 } |
62 | 62 |
63 | 63 |
64 BOOL nnwin_init(int delay) | 64 BOOL nnwin_init(int delay) |
65 { | 65 { |
66 // Sanity check the terminal size | |
66 if (LINES < 0 || LINES > 1000) LINES = 24; | 67 if (LINES < 0 || LINES > 1000) LINES = 24; |
67 if (COLS < 0 || COLS > 1000) COLS = 80; | 68 if (COLS < 0 || COLS > 1000) COLS = 80; |
68 | 69 |
70 // Initialize (n)curses library and terminal settings | |
69 initscr(); | 71 initscr(); |
70 raw(); | 72 raw(); |
71 keypad(stdscr, TRUE); | 73 keypad(stdscr, TRUE); |
72 noecho(); | 74 noecho(); |
73 meta(stdscr, TRUE); | 75 meta(stdscr, TRUE); |
74 timeout(delay); | 76 timeout(delay); |
75 cursorVisible = curs_set(0); | 77 scrollok(stdscr, FALSE); |
78 cursorVisible = curs_set(1); | |
76 | 79 |
77 if (has_colors()) | 80 if (has_colors()) |
78 { | 81 { |
79 start_color(); | 82 start_color(); |
80 | 83 |
95 init_pair(15, COLOR_MAGENTA, COLOR_RED); | 98 init_pair(15, COLOR_MAGENTA, COLOR_RED); |
96 init_pair(16, COLOR_CYAN, COLOR_RED); | 99 init_pair(16, COLOR_CYAN, COLOR_RED); |
97 } | 100 } |
98 | 101 |
99 cursesInit = TRUE; | 102 cursesInit = TRUE; |
100 | 103 nnwin_reset(); |
101 if (!nnwin_init_windows()) | |
102 return FALSE; | |
103 | 104 |
104 #ifdef PDCURSES | 105 #ifdef PDCURSES |
105 PDC_set_title("NNChat v" NN_VERSION); | 106 PDC_set_title("NNChat v" NN_VERSION); |
106 #endif | 107 #endif |
107 | 108 |
123 if (cursesInit) | 124 if (cursesInit) |
124 { | 125 { |
125 if (cursorVisible != ERR) | 126 if (cursorVisible != ERR) |
126 curs_set(cursorVisible); | 127 curs_set(cursorVisible); |
127 | 128 |
128 nnwin_close_windows(); | |
129 | |
130 endwin(); | 129 endwin(); |
131 THMSG(1, "NCurses deinitialized.\n"); | 130 THMSG(1, "NCurses deinitialized.\n"); |
132 } | 131 } |
132 } | |
133 | |
134 | |
135 void nnwin_reset(void) | |
136 { | |
137 getmaxyx(stdscr, scrHeight, scrWidth); | |
133 } | 138 } |
134 | 139 |
135 | 140 |
136 nn_window_t *nnwin_find(const char *id) | 141 nn_window_t *nnwin_find(const char *id) |
137 { | 142 { |
177 { | 182 { |
178 int i; | 183 int i; |
179 if (win == NULL) return; | 184 if (win == NULL) return; |
180 | 185 |
181 for (i = 1; i < SET_MAX_WINDOWS; i++) | 186 for (i = 1; i < SET_MAX_WINDOWS; i++) |
187 { | |
182 if (chatWindows[i] == win) | 188 if (chatWindows[i] == win) |
183 { | 189 { |
184 chatWindows[i] = NULL; | 190 chatWindows[i] = NULL; |
185 nn_window_free(win); | 191 nn_window_free(win); |
186 return; | 192 return; |
187 } | 193 } |
188 } | 194 } |
189 | 195 } |
190 | 196 |
191 void nnwin_update_statusline(char *optUserName, int optUserColor) | 197 |
192 { | 198 #define QPUTCH(ch) th_vputch(&(win->line->buf), &(win->line->bufsize), &(win->line->len), ch) |
193 char tmpStr[128]; | 199 |
194 int i; | 200 int nnwin_print(nn_window_t *win, const char *fmt) |
195 | |
196 if (statusWin == NULL) return; | |
197 | |
198 str_get_timestamp(tmpStr, sizeof(tmpStr), "%H:%M:%S"); | |
199 | |
200 wbkgdset(statusWin, COLOR_PAIR(10)); | |
201 werase(statusWin); | |
202 | |
203 wattrset(statusWin, A_BOLD | COLOR_PAIR(11)); | |
204 mvwaddstr(statusWin, 0, 1, tmpStr); | |
205 | |
206 wattrset(statusWin, A_BOLD | COLOR_PAIR(13)); | |
207 waddstr(statusWin, " | "); | |
208 wattrset(statusWin, A_BOLD | COLOR_PAIR(16)); | |
209 waddstr(statusWin, optUserName); | |
210 wattrset(statusWin, A_BOLD | COLOR_PAIR(13)); | |
211 | |
212 wattrset(statusWin, A_BOLD | COLOR_PAIR(13)); | |
213 waddstr(statusWin, " | "); | |
214 wattrset(statusWin, A_BOLD | COLOR_PAIR(11)); | |
215 snprintf(tmpStr, sizeof(tmpStr), "#%06x", optUserColor); | |
216 waddstr(statusWin, tmpStr); | |
217 | |
218 wattrset(statusWin, A_BOLD | COLOR_PAIR(13)); | |
219 waddstr(statusWin, " | WIN: "); | |
220 snprintf(tmpStr, sizeof(tmpStr), "%d: %s / %d", | |
221 currWin->num + 1, | |
222 currWin->id != NULL ? currWin->id : "MAIN", | |
223 currWin->pos); | |
224 waddstr(statusWin, tmpStr); | |
225 | |
226 wattrset(statusWin, A_BOLD | COLOR_PAIR(13)); | |
227 waddstr(statusWin, " | "); | |
228 wattrset(statusWin, A_BOLD | COLOR_PAIR(11)); | |
229 | |
230 for (i = 0; i < SET_MAX_WINDOWS; i++) | |
231 { | |
232 if (chatWindows[i] != NULL && chatWindows[i]->dirty) | |
233 { | |
234 snprintf(tmpStr, sizeof(tmpStr), "%d ", i + 1); | |
235 waddstr(statusWin, tmpStr); | |
236 } | |
237 } | |
238 | |
239 wrefresh(statusWin); | |
240 } | |
241 | |
242 | |
243 void nnwin_update_editbuf(nn_editbuf_t *buf) | |
244 { | |
245 char *tmp; | |
246 if (editWin == NULL || buf == NULL || !buf->dirty) | |
247 return; | |
248 | |
249 buf->dirty = FALSE; | |
250 buf->data[buf->len] = 0; | |
251 tmp = nn_username_decode(th_strdup(buf->data)); | |
252 | |
253 werase(editWin); | |
254 | |
255 wattrset(editWin, A_NORMAL); | |
256 | |
257 if (buf->pos < buf->len) | |
258 { | |
259 waddnstr(editWin, tmp, buf->pos); | |
260 wattrset(editWin, A_REVERSE); | |
261 waddch(editWin, tmp[buf->pos]); | |
262 wattrset(editWin, A_NORMAL); | |
263 waddnstr(editWin, tmp + buf->pos + 1, buf->len - buf->pos - 1); | |
264 } | |
265 else | |
266 { | |
267 waddnstr(editWin, tmp, buf->len); | |
268 wattrset(editWin, A_REVERSE); | |
269 waddch(editWin, ' '); | |
270 wattrset(editWin, A_NORMAL); | |
271 } | |
272 wrefresh(editWin); | |
273 th_free(tmp); | |
274 } | |
275 | |
276 | |
277 int nnwin_print(WINDOW *win, const char *fmt) | |
278 { | 201 { |
279 const char *s = fmt; | 202 const char *s = fmt; |
280 int col = 0; | 203 int col = 0; |
281 | 204 |
282 while (*s) | 205 while (*s) |
283 { | 206 { |
284 if (*s == '½') | 207 if (win->line == NULL) |
285 { | 208 { |
286 s++; | 209 win->line = th_calloc(1, sizeof(nn_line_t)); |
287 if (*s == '½') | 210 if (win->line == NULL) |
288 { | 211 return -15; |
289 waddch(win, ((unsigned char) *s) | col); | 212 } |
290 s++; | 213 |
291 } | |
292 else | |
293 { | |
294 memcpy(&col, s, sizeof(int)); | |
295 s += sizeof(int); | |
296 } | |
297 } | |
298 else | |
299 { | |
300 waddch(win, ((unsigned char) *s) | col); | |
301 s++; | |
302 } | |
303 } | |
304 return 0; | |
305 } | |
306 | |
307 | |
308 #define QPUTCH(ch) th_vputch(&(win->buf), &(win->bufsize), &(win->len), ch) | |
309 | |
310 int nnwin_print_buf(nn_window_t *win, const char *fmt) | |
311 { | |
312 const char *s = fmt; | |
313 int col = 0; | |
314 while (*s) | |
315 { | |
316 if (*s == '½') | 214 if (*s == '½') |
317 { | 215 { |
318 s++; | 216 s++; |
319 if (*s == '½') | 217 if (*s == '½') |
320 { | 218 { |
321 QPUTCH(*s); | 219 QPUTCH(*s); |
322 QPUTCH(*s); | 220 QPUTCH(*s); |
323 win->chlen++; | 221 win->line->chlen++; |
324 } | 222 } |
325 else | 223 else |
326 { | 224 { |
327 int val = 0; | 225 int val = 0; |
328 while (*s >= '0' && *s <= '9') | 226 while (*s >= '0' && *s <= '9') |
338 else if (val < 30) | 236 else if (val < 30) |
339 col = A_BOLD | COLOR_PAIR(val - 9); | 237 col = A_BOLD | COLOR_PAIR(val - 9); |
340 | 238 |
341 QPUTCH('½'); | 239 QPUTCH('½'); |
342 | 240 |
343 if (!th_growbuf(&(win->buf), &(win->bufsize), &(win->len), sizeof(int))) | 241 if (!th_growbuf(&(win->line->buf), &(win->line->bufsize), &(win->line->len), sizeof(int))) |
344 return -2; | 242 return -2; |
345 | 243 |
346 memcpy(win->buf + win->len, &col, sizeof(int)); | 244 memcpy(win->line->buf + win->line->len, &col, sizeof(int)); |
347 win->len += sizeof(int); | 245 win->line->len += sizeof(int); |
348 } | 246 } |
349 } | 247 } |
350 else if (*s == '\n') | 248 else if (*s == '\n') |
351 { | 249 { |
352 QPUTCH('\n'); | |
353 QPUTCH(0); | 250 QPUTCH(0); |
354 th_ringbuf_add(win->data, win->buf); | 251 th_ringbuf_add(win->data, win->line); |
355 win->buf = NULL; | 252 win->line = NULL; |
356 win->chlen = 0; | |
357 win->dirty = TRUE; | 253 win->dirty = TRUE; |
358 } | 254 } |
359 else if (*s != '\r') | 255 else if (*s != '\r') |
360 { | 256 { |
361 QPUTCH((unsigned char) *s == 255 ? ' ' : *s); | 257 QPUTCH((unsigned char) *s == 255 ? ' ' : *s); |
362 win->chlen++; | 258 win->line->chlen++; |
363 } | 259 } |
364 | 260 |
365 s++; | 261 s++; |
366 } | 262 } |
367 | 263 |
368 return 0; | 264 return 0; |
369 } | 265 } |
370 | 266 |
371 | 267 |
372 char *nnwin_prompt_requester(WINDOW *win, const char *info, BOOL allowEmpty) | 268 char *nnwin_prompt_requester(const char *info, BOOL allowEmpty) |
373 { | 269 { |
374 char tmpBuf[512], *ptr; | 270 char tmpBuf[512], *ptr; |
375 size_t pos; | |
376 int curSave = curs_set(1); | 271 int curSave = curs_set(1); |
377 | 272 |
378 echo(); | 273 echo(); |
379 waddstr(win, info); | 274 waddstr(stdscr, info); |
380 wgetnstr(win, tmpBuf, sizeof(tmpBuf) - 1); | 275 wgetnstr(stdscr, tmpBuf, sizeof(tmpBuf) - 1); |
381 noecho(); | 276 noecho(); |
382 | 277 |
383 if (curSave != ERR) | 278 if (curSave != ERR) |
384 curs_set(curSave); | 279 curs_set(curSave); |
385 | 280 |
386 for (pos = strlen(tmpBuf) - 1; pos > 0 && th_isspace(tmpBuf[pos]); pos--) | 281 str_trim_right(tmpBuf); |
387 tmpBuf[pos] = 0; | |
388 | |
389 ptr = str_trim_left(tmpBuf); | 282 ptr = str_trim_left(tmpBuf); |
390 | 283 |
391 if (allowEmpty || strlen(ptr) > 0) | 284 if (allowEmpty || ptr[0]) |
392 return th_strdup(ptr); | 285 return th_strdup(ptr); |
393 else | 286 else |
394 return NULL; | 287 return NULL; |
395 } | 288 } |
396 | 289 |
397 | 290 |
398 BOOL nnwin_update_main(BOOL force) | 291 void nnwin_update(BOOL force, nn_editbuf_t *ebuf, char *optUserName, int optUserColor) |
399 { | 292 { |
400 int h, offs; | 293 if (force) |
401 qringbuf_t *buf; | 294 { |
402 | 295 wattrset(stdscr, A_NORMAL); |
403 // Check pointers | 296 wbkgdset(stdscr, COLOR_PAIR(0)); |
404 if (mainWin == NULL || currWin == NULL) | 297 werase(stdscr); |
405 return FALSE; | 298 } |
406 | 299 |
407 // Check if update is forced or if the window is dirty | 300 // Check if update is forced or if the window is dirty |
408 if (!force && !currWin->dirty) | 301 if (currWin != NULL && (force || currWin->dirty)) |
409 return FALSE; | 302 { |
410 | 303 int h = scrHeight - 5, y, offs; |
411 // Compute how many lines from backbuffer fit on the screen | 304 qringbuf_t *buf = currWin->data; |
412 buf = currWin->data; | 305 |
413 h = getmaxy(mainWin); | 306 wattrset(stdscr, A_NORMAL); |
414 | 307 wbkgdset(stdscr, COLOR_PAIR(0)); |
415 // Clear and redraw window | 308 wmove(stdscr, 0, 0); |
416 werase(mainWin); | 309 |
417 scrollok(mainWin, 1); | 310 for (y = 0, offs = buf->size - h - currWin->pos; offs >= 0 && offs < buf->size - currWin->pos && offs < buf->size && y < h; offs++) |
418 for (offs = buf->size - h - currWin->pos; offs >= 0 && offs < buf->size - currWin->pos && offs < buf->size; offs++) | 311 { |
419 { | 312 int col = 0; |
420 if (buf->data[offs] != NULL) | 313 nn_line_t *line = buf->data[offs]; |
421 nnwin_print(mainWin, buf->data[offs]); | 314 if (line == NULL) |
422 } | 315 continue; |
423 | 316 |
424 currWin->dirty = FALSE; | 317 while (*s && y < h) |
425 wrefresh(mainWin); | 318 { |
426 return TRUE; | 319 if (*s == '½') |
427 } | 320 { |
428 | 321 s++; |
429 | 322 if (*s == '½') |
430 void nnwin_close_windows(void) | 323 { |
431 { | 324 waddch(stdscr, ((unsigned char) *s) | col); |
432 if (mainWin) delwin(mainWin); | 325 s++; |
433 if (statusWin) delwin(statusWin); | 326 } |
434 if (editWin) delwin(editWin); | 327 else |
435 } | 328 { |
436 | 329 memcpy(&col, s, sizeof(int)); |
437 | 330 s += sizeof(int); |
438 BOOL nnwin_init_windows(void) | 331 } |
439 { | 332 } |
440 int w, h; | 333 else |
441 | 334 { |
442 getmaxyx(stdscr, h, w); | 335 waddch(stdscr, ((unsigned char) *s) | col); |
443 | 336 s++; |
444 nnwin_close_windows(); | 337 } |
445 | 338 y = getcury(stdscr); |
446 mainWin = subwin(stdscr, h - 4, w, 0, 0); | 339 } |
447 statusWin = subwin(stdscr, 1, w, h - 4, 0); | 340 } |
448 editWin = subwin(stdscr, 3, w, h - 3, 0); | 341 |
449 | 342 currWin->dirty = FALSE; |
450 if (mainWin == NULL || statusWin == NULL || editWin == NULL) | 343 } |
451 return FALSE; | 344 |
452 | 345 { |
453 return TRUE; | 346 // Statusline |
454 } | 347 char tmpStr[128]; |
348 int i; | |
349 | |
350 str_get_timestamp(tmpStr, sizeof(tmpStr), "%H:%M:%S"); | |
351 | |
352 wmove(stdscr, scrHeight - 4, 0); | |
353 wbkgdset(stdscr, COLOR_PAIR(10)); | |
354 wclrtoeol(stdscr); | |
355 | |
356 wattrset(stdscr, A_BOLD | COLOR_PAIR(11)); | |
357 mvwaddstr(stdscr, scrHeight - 4, 1, tmpStr); | |
358 | |
359 wattrset(stdscr, A_BOLD | COLOR_PAIR(13)); | |
360 waddstr(stdscr, " | "); | |
361 wattrset(stdscr, A_BOLD | COLOR_PAIR(16)); | |
362 waddstr(stdscr, optUserName); | |
363 wattrset(stdscr, A_BOLD | COLOR_PAIR(13)); | |
364 | |
365 wattrset(stdscr, A_BOLD | COLOR_PAIR(13)); | |
366 waddstr(stdscr, " | "); | |
367 wattrset(stdscr, A_BOLD | COLOR_PAIR(11)); | |
368 snprintf(tmpStr, sizeof(tmpStr), "#%06x", optUserColor); | |
369 waddstr(stdscr, tmpStr); | |
370 | |
371 wattrset(stdscr, A_BOLD | COLOR_PAIR(13)); | |
372 waddstr(stdscr, " | WIN: "); | |
373 snprintf(tmpStr, sizeof(tmpStr), "%d: %s / %d", | |
374 currWin->num + 1, | |
375 currWin->id != NULL ? currWin->id : "MAIN", | |
376 currWin->pos); | |
377 waddstr(stdscr, tmpStr); | |
378 | |
379 wattrset(stdscr, A_BOLD | COLOR_PAIR(13)); | |
380 waddstr(stdscr, " | "); | |
381 wattrset(stdscr, A_BOLD | COLOR_PAIR(11)); | |
382 | |
383 for (i = 0; i < SET_MAX_WINDOWS; i++) | |
384 { | |
385 if (chatWindows[i] != NULL && chatWindows[i]->dirty) | |
386 { | |
387 snprintf(tmpStr, sizeof(tmpStr), "%d ", i + 1); | |
388 waddstr(stdscr, tmpStr); | |
389 } | |
390 } | |
391 } | |
392 | |
393 if (ebuf != NULL) | |
394 // && (force || ebuf->dirty)) | |
395 { | |
396 int yoffs = ebuf->pos / scrWidth, | |
397 xoffs = ebuf->pos % scrWidth; | |
398 char *tmp; | |
399 | |
400 ebuf->dirty = FALSE; | |
401 ebuf->data[ebuf->len] = 0; | |
402 tmp = nn_username_decode(th_strdup(ebuf->data)); | |
403 | |
404 wmove(stdscr, scrHeight - 3, 0); | |
405 wattrset(stdscr, A_NORMAL); | |
406 wbkgdset(stdscr, COLOR_PAIR(0)); | |
407 waddnstr(stdscr, tmp, ebuf->len); | |
408 wmove(stdscr, scrHeight - 3 + yoffs, xoffs); | |
409 | |
410 th_free(tmp); | |
411 } | |
412 | |
413 wrefresh(stdscr); | |
414 } |