Global cosmetic changes.
[crypto.git] / apps / silc / screen.c
1 /*
2
3   screen.c
4
5   Author: Pekka Riikonen <priikone@poseidon.pspt.fi>
6
7   Copyright (C) 1997 - 2000 Pekka Riikonen
8
9   This program is free software; you can redistribute it and/or modify
10   it under the terms of the GNU General Public License as published by
11   the Free Software Foundation; either version 2 of the License, or
12   (at your option) any later version.
13   
14   This program is distributed in the hope that it will be useful,
15   but WITHOUT ANY WARRANTY; without even the implied warranty of
16   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17   GNU General Public License for more details.
18
19 */
20 /*
21  * SILC client screen routines. These implement the user interface
22  * on ncurses routines. Most of these routines were taken from the
23  * old version of the SILC client dating back to 1997.
24  */
25 /* XXX: Input line handling is really buggy! */
26 /*
27  * $Id$
28  * $Log$
29  * Revision 1.2  2000/07/05 06:12:05  priikone
30  *      Global cosmetic changes.
31  *
32  * Revision 1.1.1.1  2000/06/27 11:36:56  priikone
33  *      Imported from internal CVS/Added Log headers.
34  *
35  *
36  */
37
38 #include "clientincludes.h"
39
40 SilcScreen silc_screen_init()
41 {
42   SilcScreen new;
43
44   new = silc_malloc(sizeof(*new));
45   new->output_win_count = 0;
46   new->input_pos = 0;
47   new->cursor_pos = 0;
48   new->virtual_window = 0;
49   new->insert = TRUE;
50
51   initscr();
52   cbreak();
53   nonl();
54   noecho();
55
56   silc_screen_create_output_window(new);
57   silc_screen_create_input_window(new);
58
59   return new;
60 }
61
62 /* Creates one (main) output window. Returns new created physical 
63    window. */
64
65 WINDOW *silc_screen_create_output_window(SilcScreen screen)
66 {
67   assert(screen != NULL);
68
69   screen->output_win = silc_malloc(sizeof(*screen->output_win) * 1);
70   screen->output_win_count = 1;
71   screen->output_win[0] = newwin(LINES - 3, COLS, 1, 0);
72   scrollok(screen->output_win[0], TRUE);
73   idlok(screen->output_win[0], TRUE);
74   wrefresh(screen->output_win[0]);
75
76   return screen->output_win[0];
77 }
78
79 /* Adds new output window. Return new created physical window. */
80
81 WINDOW *silc_screen_add_output_window(SilcScreen screen)
82 {
83   int i;
84
85   assert(screen != NULL);
86
87   screen->output_win = silc_realloc(screen->output_win, 
88                                     (screen->output_win_count + 1) *
89                                     sizeof(*screen->output_win));
90   i = screen->output_win_count;
91   screen->output_win[i] = newwin(LINES - 3, COLS, 1, 0);
92   scrollok(screen->output_win[i], TRUE);
93   idlok(screen->output_win[i], TRUE);
94   wrefresh(screen->output_win[i]);
95   screen->output_win_count++;
96
97   return screen->output_win[i];
98 }
99
100 void silc_screen_create_input_window(SilcScreen screen)
101 {
102   assert(screen != NULL);
103
104   screen->input_win = newwin(0, COLS, LINES - 1, 0);
105   scrollok(screen->input_win, TRUE);
106   keypad(screen->input_win, TRUE);
107   wrefresh(screen->input_win);
108 }
109
110 void silc_screen_init_upper_status_line(SilcScreen screen)
111 {
112   int i;
113   int justify;
114   
115   assert(screen != NULL);
116
117   /* Create upper status line */
118   screen->upper_stat_line = newwin(0, COLS, 0, 0);
119   scrollok(screen->upper_stat_line, FALSE);
120   wattrset(screen->upper_stat_line, A_REVERSE);
121   
122   /* Print empty line */
123   for (i = 0; i < COLS - 1; i++)
124     mvwprintw(screen->upper_stat_line, 0, i, " ");
125   
126   /* Print stuff with justify */
127   justify = COLS / 5;
128   mvwprintw(screen->upper_stat_line, 0, 1, "%s %s", 
129             screen->u_stat_line.program_name, 
130             screen->u_stat_line.program_version);
131   /*
132   mvwprintw(screen->upper_stat_line, 0, justify, "[Your Connection: %s]", 
133             stat.uconnect_status[stat.uconnect]);
134   mvwprintw(screen->upper_stat_line, 0, 
135             (justify + justify + justify), "[SILC: %s]", 
136             stat.silc_status[stat.silc]);
137   */
138
139   /* Prints clock on upper stat line */ 
140   silc_screen_print_clock(screen);
141   wrefresh(screen->upper_stat_line);
142 }
143
144 void silc_screen_init_output_status_line(SilcScreen screen)
145 {
146   int i;
147
148   assert(screen != NULL);
149
150   screen->output_stat_line = silc_calloc(1, sizeof(*screen->output_stat_line));
151   
152   screen->output_stat_line[0] = newwin(1, COLS, LINES - 2, 0);
153   scrollok(screen->output_stat_line[0], FALSE);
154   wattrset(screen->output_stat_line[0], A_REVERSE);
155   
156   /* print first just blank line */
157   for (i = 0; i < COLS - 1; i++)
158     mvwprintw(screen->output_stat_line[0], 0, i, " ");
159
160   /* Allocate bottom line */
161   screen->bottom_line = silc_calloc(1, sizeof(*screen->bottom_line));
162
163   wattrset(screen->output_stat_line[0], A_NORMAL);
164   wrefresh(screen->output_stat_line[0]);
165 }
166
167 void silc_screen_print_clock(SilcScreen screen)
168 {
169   time_t curtime;
170   struct tm *tp;
171
172   curtime = time(0);
173   tp = localtime(&curtime);
174
175   mvwprintw(screen->upper_stat_line, 0, COLS - 8, "[%02d:%02d] ", 
176             tp->tm_hour, tp->tm_min);
177   wrefresh(screen->upper_stat_line);
178 }
179
180 /* Prints current cursor coordinates on some output stat line */
181
182 void silc_screen_print_coordinates(SilcScreen screen, int win_index)
183 {
184   wattrset(screen->output_stat_line[win_index], A_REVERSE);
185   mvwprintw(screen->output_stat_line[win_index], 0, COLS - 10,
186             "[%4d,%3d]", screen->input_pos, LINES);
187   wrefresh(screen->output_stat_line[win_index]);
188   wattrset(screen->output_stat_line[win_index], A_NORMAL);
189 }
190
191 /* Prints bottom line (the status line) of the screen. */
192
193 void silc_screen_print_bottom_line(SilcScreen screen, int win_index)
194 {
195   char buf[512];
196   SilcScreenBottomLine line = screen->bottom_line;
197   int i, len;
198
199   memset(buf, 0, sizeof(buf));
200
201   if (line->mode) {
202     len = strlen(line->mode);
203     strncat(buf, line->mode, len);
204   }
205
206   if (line->nickname) {
207     len = strlen(line->nickname);
208     strncat(buf, line->nickname, len > SILC_SCREEN_MAX_NICK_LEN ? 
209             SILC_SCREEN_MAX_NICK_LEN : len);
210   }
211
212   if (line->connection) {
213     len = strlen(line->connection);
214     strncat(buf, " via ", 5);
215     strncat(buf, line->connection, len > SILC_SCREEN_MAX_CONN_LEN ? 
216             SILC_SCREEN_MAX_CONN_LEN : len);
217   }
218
219   if (line->channel) {
220     len = strlen(line->channel);
221     strncat(buf, " ", 1);
222     strncat(buf, line->channel, len > SILC_SCREEN_MAX_CHANNEL_LEN ?
223             SILC_SCREEN_MAX_CHANNEL_LEN : len);
224   }
225
226   wattrset(screen->output_stat_line[win_index], A_REVERSE);
227
228   for (i = 0; i < COLS - 10; i++)
229     mvwprintw(screen->output_stat_line[win_index], 0, i, " ");
230
231   mvwprintw(screen->output_stat_line[win_index], 0, 0, " %s", buf);
232   silc_screen_print_coordinates(screen, win_index);
233   wrefresh(screen->output_stat_line[win_index]);
234   wattrset(screen->output_stat_line[win_index], A_NORMAL);
235 }
236
237 /* Refresh all windows */
238
239 void silc_screen_refresh_all(SilcScreen screen)
240 {
241   int i;
242
243   assert(screen != NULL);
244
245   redrawwin(screen->upper_stat_line);
246
247   for (i = 0; i < screen->output_win_count; i++) {
248     wrefresh(screen->output_win[i]);
249     redrawwin(screen->output_win[i]);
250   }
251
252   wrefresh(screen->input_win);
253   redrawwin(screen->input_win);
254 }
255
256 /* Refreshes a window */
257
258 void silc_screen_refresh_win(WINDOW *win)
259 {
260   assert(win != NULL);
261
262   redrawwin(win);
263   wrefresh(win);
264 }
265
266 /* Resets input window */
267
268 void silc_screen_input_reset(SilcScreen screen)
269 {
270   int i;
271
272   assert(screen != NULL);
273   for (i = 0; i < COLS - 1; i++)
274     mvwprintw(screen->input_win, 0, i, " ");
275   mvwprintw(screen->input_win, 0, 0, "");
276   wrefresh(screen->input_win);
277   screen->input_pos = 0;
278   screen->input_end = 0;
279   screen->cursor_pos = 0;
280   screen->virtual_window = 0;
281 }
282
283 /* Backspace. Removes one character from input windows. */
284
285 void silc_screen_input_backspace(SilcScreen screen)
286 {
287   WINDOW *win;
288   char *buffer;
289
290   assert(screen != NULL);
291   buffer = screen->input_buffer;
292   win = screen->input_win;
293
294   /* Return directly if at the start of input line */
295   if (screen->input_pos == 0)
296     return;
297
298   if (screen->virtual_window) {
299     if (screen->cursor_pos <= 10) {
300       int i;
301
302       /* Clear line */
303       for (i = 0; i < COLS; i++)
304         mvwprintw(win, 0, i, " ");
305       mvwprintw(win, 0, 0, "");
306
307       screen->virtual_window--;
308       
309       waddnstr(win, &buffer[screen->virtual_window * (COLS - 5)], COLS);
310       screen->input_pos = ((screen->virtual_window + 1) * (COLS - 5)) + 1;
311       screen->input_end = ((screen->virtual_window + 1) * (COLS - 5)) + 1;
312       screen->cursor_pos = (COLS - 5) + 1;
313       wrefresh(win);
314     }
315   }
316
317   screen->cursor_pos--;
318   screen->input_pos--;
319   screen->input_end--;
320   mvwdelch(win, 0, screen->cursor_pos);
321
322   if (screen->input_pos < screen->input_end)
323     /* Delete from inside the input line */
324     SILC_SCREEN_INPUT_DELETE(buffer, screen->input_pos, screen->input_end);
325   else
326     /* Delete from the end of the input line */
327     buffer[screen->input_pos] = 0;
328
329   wrefresh(win);
330 }
331
332 /* Switches insert on input window on/off */
333
334 void silc_screen_input_insert(SilcScreen screen)
335 {
336   assert(screen != NULL);
337
338   screen->insert = screen->insert == TRUE ? FALSE : TRUE;
339 }
340
341 /* Moves cursor one character length to rightward */
342
343 void silc_screen_input_cursor_right(SilcScreen screen)
344 {
345   WINDOW *win;
346   char *buffer;
347
348   assert(screen != NULL);
349   buffer = screen->input_buffer;
350   win = screen->input_win;
351
352   /* Return directly if we are at the end of input line */
353   if (screen->cursor_pos >= SILC_SCREEN_INPUT_WIN_SIZE)
354     return;
355
356   /* Make sure cursor doesn't advance over the end of the line */
357   if (screen->input_pos >= screen->input_end)
358     return;
359
360   /* When cursor advances enough we switch to new window and show
361      rest of the typed characters on the screen. */
362   if (screen->cursor_pos >= (COLS - 5)) {
363     int i;
364
365     /* Clear line */
366     for (i = 0; i < COLS; i++)
367       mvwprintw(win, 0, i, " ");
368     mvwprintw(win, 0, 0, "");
369
370     waddnstr(win, &buffer[screen->input_pos - 10], 
371              ((screen->input_pos - 10) - screen->input_end >= COLS) ?
372              COLS : (screen->input_pos - 10) - screen->input_end);
373     screen->cursor_pos = 10;
374     wrefresh(win);
375
376     screen->virtual_window++;
377   }
378
379   screen->cursor_pos++;
380   screen->input_pos++;
381   wmove(win, 0, screen->cursor_pos);
382   wrefresh(win);
383 }
384
385 /* Moves cursor one character length to leftward */
386
387 void silc_screen_input_cursor_left(SilcScreen screen)
388 {
389   WINDOW *win;
390   char *buffer;
391
392   assert(screen != NULL);
393   buffer = screen->input_buffer;
394   win = screen->input_win;
395
396   /* Return directly if at the start of input line */
397   if (screen->input_pos == 0)
398     return;
399
400   /* When cursor advances enough we switch to new window and show
401      rest of the typed characters on the screen. */
402   if (screen->virtual_window) {
403     if (screen->cursor_pos <= 10) {
404       int i;
405
406       /* Clear line */
407       for (i = 0; i < COLS; i++)
408         mvwprintw(win, 0, i, " ");
409       mvwprintw(win, 0, 0, "");
410
411       screen->virtual_window--;
412       
413       waddnstr(win, &buffer[screen->virtual_window * (COLS - 5)], COLS);
414       screen->input_pos = ((screen->virtual_window + 1) * (COLS - 5)) + 1;
415       screen->cursor_pos = (COLS - 5) + 1;
416       wrefresh(win);
417     }
418   }
419
420   screen->cursor_pos--;
421   screen->input_pos--;
422   wmove(win, 0, screen->cursor_pos);
423   wrefresh(win);
424 }
425
426 /* Moves cursor at the very start of the input line */
427
428 void silc_screen_input_cursor_home(SilcScreen screen)
429 {
430   WINDOW *win;
431   char *buffer;
432
433   assert(screen != NULL);
434   buffer = screen->input_buffer;
435   win = screen->input_win;
436
437   wclear(win);
438   waddnstr(win, &buffer[0], COLS);
439   wrefresh(win);
440
441   screen->input_pos = 0;
442   screen->cursor_pos = 0;
443   screen->virtual_window = 0;
444 }
445
446 /* Moves cursor at the very end of the input line */
447
448 void silc_screen_input_cursor_end(SilcScreen screen)
449 {
450   WINDOW *win;
451   char *buffer;
452
453   assert(screen != NULL);
454   buffer = screen->input_buffer;
455   win = screen->input_win;
456
457   wclear(win);
458   waddnstr(win, &buffer[screen->input_end - 10], 10);
459   wrefresh(win);
460
461   screen->input_pos = screen->input_end;
462   screen->cursor_pos = 10;
463   /* XXX */
464   screen->virtual_window = 0;
465 }
466
467 /* Prints typed character into the input window for user to see. Character 
468    attributes must be set separately outside this function. */
469
470 void silc_screen_input_print(SilcScreen screen, unsigned char c)
471 {
472   WINDOW *win;
473   char *buffer;
474
475   assert(screen != NULL);
476   buffer = screen->input_buffer;
477   win = screen->input_win;
478
479   /* Return directly if input window is full */
480   if (screen->input_pos >= SILC_SCREEN_INPUT_WIN_SIZE)
481     return;
482
483   /* The input window is COLS wide but one can type into it at most
484      SILC_SCREEN_INPUT_SIZE characters. When COLS - 5 characters is
485      typed the window is cleared and the cursor is moved at the tenth
486      character in the input window. Ten last typed character is then
487      showed at the start of the window. */
488   if (screen->cursor_pos >= (COLS - 5)) {
489     int i;
490
491     /* Clear line */
492     for (i = 0; i < COLS; i++)
493       mvwprintw(win, 0, i, " ");
494     mvwprintw(win, 0, 0, "");
495
496     /* Show ten last typed characters from the buffer on the screen */
497     waddnstr(win, &buffer[screen->input_pos - 10], 10);
498     screen->cursor_pos = 10;
499     wrefresh(win);
500
501     screen->virtual_window++;
502   }
503
504   if (screen->input_pos < screen->input_end) {
505     /* User moved cursor into the typed line. We are not adding 
506        character at the end of the line anymore */
507
508     if (screen->insert == FALSE) {
509       /* Add new character somewhere inside typed line. The input
510          line position is not advanced since a character was replaced
511          by the new character. */
512       waddch(win, c);
513       buffer[screen->input_pos] = c;
514       screen->cursor_pos++;
515       screen->input_pos++;
516       screen->input_end = screen->input_pos;
517     } else {
518       /* Insert new character somewhere inside typed line. Other
519          characters are moved forward. We must advance the input line
520          posititon. */
521       winsch(win, c);
522       wmove(win, 0, screen->cursor_pos + 1);
523       SILC_SCREEN_INPUT_INSERT(buffer, screen->input_pos, 
524                                c, screen->input_end);
525       screen->cursor_pos++;
526       screen->input_pos++;
527       screen->input_end++;
528     }
529   } else {
530     /* Add new character at the end of input line */
531     waddch(win, c);
532     buffer[screen->input_pos] = c;
533     screen->input_pos++;
534     screen->cursor_pos++;
535     screen->input_end = screen->input_pos;
536   }
537
538   /* Advance the cursor position. Cursor moves one to rightward always */
539   wrefresh(win);
540 }
541
542 /* Prints prompt to the input window. Cursors position aftern printing
543    is length of the prompt. */
544
545 void silc_screen_input_print_prompt(SilcScreen screen, char *prompt)
546 {
547   WINDOW *win;
548
549   assert(screen != NULL);
550   win = screen->input_win;
551
552   wclear(win);
553   waddnstr(win, prompt, strlen(prompt));
554   wrefresh(win);
555
556   screen->input_pos = strlen(prompt);
557   screen->cursor_pos = strlen(prompt);
558   screen->virtual_window = 0;
559 }