Update URL's to GitLab.
[cboard.git] / src / message.c
blob3a805539338e4d6dfbe64a7e25eab7260db6cae4
1 /* vim:tw=78:ts=8:sw=4:set ft=c: */
2 /*
3 Copyright (C) 2002-2018 Ben Kibbey <bjk@luxsci.net>
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19 #ifdef HAVE_CONFIG_H
20 #include <config.h>
21 #endif
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <stdarg.h>
26 #include <string.h>
27 #include <wctype.h>
29 #ifdef HAVE_STDARG_H
30 #include <stdarg.h>
31 #endif
33 #ifdef HAVE_LIMITS_H
34 #include <limits.h>
35 #endif
37 #include "common.h"
38 #include "conf.h"
39 #include "colors.h"
40 #include "misc.h"
41 #include "window.h"
42 #include "message.h"
44 static void
45 wordwrap_lines (wchar_t *** olines, int *nlines, int *width)
47 int i;
48 wchar_t *buf = NULL, **lines = *olines;
49 int total = *nlines, w = *width;
51 for (i = 0; i < total; i++)
53 size_t len = wcslen (lines[i]);
55 if (buf)
57 size_t blen = wcslen (buf);
59 lines[i] = Realloc (lines[i], len + blen + 1 * sizeof (wchar_t *));
60 wmemmove (&lines[i][blen], lines[i], len);
61 wmemcpy (lines[i], buf, blen);
62 lines[i][blen + len] = 0;
63 free (buf);
64 buf = NULL;
65 len = wcslen (lines[i]);
68 if (len > w)
69 w = len;
71 if (len-- > MSG_WIDTH)
73 wchar_t *p;
75 for (p = lines[i] + len; *p && len > 0; p--, len--)
77 if (iswspace (*p) && len <= MSG_WIDTH)
79 *p++ = 0;
80 buf = wcsdup (p);
81 break;
85 /* Its a very long line without any unicode space. Create a
86 * new message line. */
87 if (!buf)
89 wchar_t *t, c, *bp;
90 size_t l;
92 t = lines[i] + MSG_WIDTH;
93 c = *t;
94 *t++ = 0;
95 l = wcslen (t) + 2;
96 buf = Malloc (len * sizeof (wchar_t));
97 bp = buf;
98 *bp++ = c;
99 wmemcpy (bp, t, l - 1);
104 *width = w;
106 if (buf)
108 lines = Realloc (lines, (total + 2) * sizeof (wchar_t *));
109 lines[total++] = buf;
110 lines[total] = NULL;
111 *nlines = total;
112 *olines = lines;
113 wordwrap_lines (olines, nlines, width);
117 static void
118 build_message_lines (const char *title, const char *prompt,
119 int force_trim, const char *extra, int *h,
120 int *w, wchar_t *** str, const char *fmt, va_list ap)
122 int n;
123 char *line;
124 wchar_t **lines = NULL;
125 int width = 0, height = 0, len;
126 int total = 0;
127 wchar_t *wc, *wc_tmp, *wc_line, wc_delim[] = { '\n', 0 };
129 #ifdef HAVE_VASPRINTF
130 vasprintf (&line, fmt, ap);
131 #else
132 line = Malloc (LINE_MAX);
133 vsnprintf (line, LINE_MAX, fmt, ap);
134 #endif
136 wc = str_to_wchar (line);
137 free (line);
138 total = n = 0;
139 for (wc_line = wcstok (wc, wc_delim, &wc_tmp); wc_line;
140 wc_line = wcstok (NULL, wc_delim, &wc_tmp))
142 lines = Realloc (lines, (total + 2) * sizeof (wchar_t *));
143 lines[total++] = wcsdup (wc_line);
144 lines[total] = NULL;
147 free (wc);
148 wordwrap_lines (&lines, &total, &width);
150 if (width > MSG_WIDTH)
151 width = MSG_WIDTH;
153 if (prompt)
155 wc = str_to_wchar (prompt);
156 len = wcslen (wc);
157 width = len > width ? len : width;
158 free (wc);
161 if (extra)
163 wc = str_to_wchar (extra);
164 len = wcslen (wc);
165 width = len > width ? len : width;
166 free (wc);
169 if (title)
171 wc = str_to_wchar (title);
172 len = wcslen (wc);
173 width = len > width ? len : width;
174 free (wc);
177 height = total;
179 if (extra)
180 height++;
182 if (title)
183 height++;
185 height += 4; // 1 padding, 2 box, 1 prompt
186 width += 4; // 2 padding, 2 box
187 *h = height;
188 *w = width;
189 *str = lines;
192 static void
193 message_free (WIN *w)
195 struct message_s *m = w->data;
196 int i;
197 void *p;
199 for (i = 0; m->lines[i]; i++)
200 free (m->lines[i]);
202 free (m->lines);
203 free (m->prompt);
204 free (m->extra);
205 p = m->arg;
206 free (m);
207 w->data = p;
210 static int
211 display_message (WIN * win)
213 struct message_s *m = win->data;
214 int i;
215 int n_lines = 0;
216 int r = 0;
218 keypad (win->w, TRUE);
219 window_draw_title (win->w, win->title, m->w, CP_MESSAGE_TITLE,
220 CP_MESSAGE_BORDER);
222 for (i = 0; m->lines[i]; i++)
224 n_lines++;
226 if (m->offset && i < m->offset)
227 continue;
229 mvwprintw (win->w, (win->title) ? 2 + r : 1 + r,
230 (m->center || (!i && !m->lines[i + 1])) ?
231 CENTERX (m->w, m->lines[i]) : 1, "%ls", m->lines[i]);
232 if (++r >= LINES - 5)
233 break;
236 if (m->extra)
237 window_draw_prompt (win->w, (m->prompt) ? m->h - 3 : m->h - 2, m->w,
238 m->extra, CP_MESSAGE_PROMPT);
240 if (m->prompt)
241 window_draw_prompt (win->w, m->h - 2, m->w, m->prompt, CP_MESSAGE_PROMPT);
243 if (m->func && win->c == m->c)
245 (*m->func) (m->arg);
246 return 1;
249 if (win->c != 0)
251 if (win->c == KEY_DOWN || win->c == 'k' || win->c == KEY_UP
252 || win->c == 'j')
254 int n = 3;
256 n += m->extra ? 1 : 0;
258 if ((n_lines + n) - m->offset >= LINES - 2)
259 m->offset = win->c == KEY_DOWN || win->c == 'k'
260 ? m->offset + 1 : m->offset - 1;
261 else if (win->c == KEY_UP || win->c == 'j')
262 m->offset--;
264 if (m->offset < 0)
265 m->offset = 0;
267 werase (win->w);
268 win->c = 0;
269 return display_message (win);
272 if (win->c == KEY_RESIZE)
273 return 1;
275 message_free (win);
276 return 0;
279 return 1;
282 static void
283 message_resize_func (WIN *w)
285 struct message_s *m = w->data;
286 size_t rows = wcharv_length (m->lines);
288 if (m->offset && rows >= LINES - 5)
289 m->offset--;
291 m->h = w->rows = rows >= LINES - 5 ? LINES - 1 : rows + 5;
292 m->w = w->cols = w->cols > COLS - 2 ? COLS - 2 : w->cols;
293 wresize (w->w, w->rows, w->cols);
294 move_panel (w->p, CALCPOSY (w->rows), CALCPOSX (w->cols));
295 wclear (w->w);
296 w->func (w);
300 * The force_trim parameter will trim whitespace reguardless if there is more
301 * than one line or not (help text vs. tag viewing).
303 WIN *
304 construct_message (const char *title, const char *prompt, int center,
305 int force_trim, const char *extra_help,
306 message_func * func, void *arg, window_exit_func * efunc,
307 wint_t ckey, int freedata, window_resize_func *rfunc,
308 const char *fmt, ...)
310 wchar_t **lines = NULL;
311 va_list ap;
312 struct message_s *m = NULL;
313 WIN *win = NULL;
314 int h, w;
316 va_start (ap, fmt);
317 build_message_lines (title, prompt, force_trim, extra_help, &h, &w, &lines,
318 fmt, ap);
319 va_end (ap);
321 m = Calloc (1, sizeof (struct message_s));
322 m->lines = lines;
323 m->w = w;
324 m->h = h > LINES - 2 ? LINES - 2 : h;
325 m->center = center;
326 m->c = ckey;
327 m->func = func;
328 m->arg = arg;
330 if (prompt)
331 m->prompt = strdup (prompt);
333 if (extra_help)
334 m->extra = strdup (extra_help);
336 win = window_create (title, m->h, m->w, CALCPOSY (m->h), CALCPOSX (m->w),
337 display_message, m, efunc,
338 rfunc ? rfunc : message_resize_func);
340 win->freedata = freedata;
341 wbkgd (win->w, CP_MESSAGE_WINDOW);
342 (*win->func) (win);
343 return win;