Fix the mega board to show both the move history window and tree.
[cboard.git] / src / message.c
blob9d180dd3aefe2e88d1dfe42a2a8be54e56d6976c
1 /* vim:tw=78:ts=8:sw=4:set ft=c: */
2 /*
3 Copyright (C) 2002-2013 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 wordwrap_lines (wchar_t ***olines, int *nlines, int *width)
46 int i;
47 wchar_t *buf = NULL, **lines = *olines;
48 int total = *nlines, w = *width;
50 for (i = 0; i < total; i++) {
51 size_t len = wcslen (lines[i]);
53 if (buf) {
54 size_t blen = wcslen (buf);
56 lines[i] = Realloc (lines[i], len+blen+1*sizeof(wchar_t *));
57 wmemmove (&lines[i][blen], lines[i], len);
58 wmemcpy (lines[i], buf, blen);
59 lines[i][blen+len] = 0;
60 free (buf);
61 buf = NULL;
62 len = wcslen (lines[i]);
65 if (len > w)
66 w = len;
68 if (len-- > MSG_WIDTH) {
69 wchar_t *p;
71 for (p = lines[i]+len; *p && len > 0; p--, len--) {
72 if (iswspace (*p) && len <= MSG_WIDTH) {
73 *p++ = 0;
74 buf = wcsdup (p);
75 break;
79 /* Its a very long line without any unicode space. Create a
80 * new message line. */
81 if (!buf) {
82 wchar_t *p, c, *bp;
83 size_t len;
85 p = lines[i]+MSG_WIDTH;
86 c = *p;
87 *p++ = 0;
88 len = wcslen (p)+2;
89 buf = Malloc (len*sizeof(wchar_t));
90 bp = buf;
91 *bp++ = c;
92 wmemcpy (bp, p, len-1);
97 *width = w;
99 if (buf) {
100 lines = Realloc (lines, (total+2)*sizeof(wchar_t **));
101 lines[total++] = buf;
102 lines[total] = NULL;
103 *nlines = total;
104 *olines = lines;
105 wordwrap_lines (olines, nlines, width);
109 static void build_message_lines(const char *title, const char *prompt,
110 int force_trim, const char *extra, int *h, int *w, wchar_t ***str,
111 const char *fmt, va_list ap)
113 int n;
114 char *line;
115 wchar_t **lines = NULL;
116 int width = 0, height = 0, len;
117 int total = 0;
118 wchar_t *wc, *wc_tmp, *wc_line, wc_delim[] = { '\n', 0 };
120 #ifdef HAVE_VASPRINTF
121 vasprintf(&line, fmt, ap);
122 #else
123 line = Malloc(LINE_MAX);
124 vsnprintf(line, LINE_MAX, fmt, ap);
125 #endif
127 wc = str_to_wchar (line);
128 free (line);
129 total = n = 0;
130 for (wc_line = wcstok (wc, wc_delim, &wc_tmp); wc_line; wc_line = wcstok (NULL, wc_delim, &wc_tmp)) {
131 lines = Realloc (lines, (total+2)*sizeof(wchar_t **));
132 lines[total++] = wcsdup (wc_line);
133 lines[total] = NULL;
136 free (wc);
137 wordwrap_lines (&lines, &total, &width);
139 if (width > MSG_WIDTH)
140 width = MSG_WIDTH;
142 if (prompt) {
143 wc = str_to_wchar (prompt);
144 len = wcslen (wc);
145 width = len > width ? len : width;
146 free (wc);
149 if (extra) {
150 wc = str_to_wchar (extra);
151 len = wcslen (wc);
152 width = len > width ? len : width;
153 free (wc);
156 if (title) {
157 wc = str_to_wchar (title);
158 len = wcslen (wc);
159 width = len > width ? len : width;
160 free (wc);
163 height = total;
165 if (extra)
166 height++;
168 if (title)
169 height++;
171 height += 4; // 1 padding, 2 box, 1 prompt
172 width += 4; // 2 padding, 2 box
173 *h = height;
174 *w = width;
175 *str = lines;
178 static int display_message(WIN *win)
180 struct message_s *m = win->data;
181 int i;
182 void *p = NULL;
184 keypad(win->w, TRUE);
185 window_draw_title(win->w, win->title, m->w, CP_MESSAGE_TITLE,
186 CP_MESSAGE_BORDER);
188 for (i = 0; m->lines[i]; i++)
189 mvwprintw(win->w, (win->title) ? 2 + i: 1 + i,
190 (m->center || (!i && !m->lines[i+1])) ?
191 CENTERX(m->w, m->lines[i]) : 1, "%ls", m->lines[i]);
193 if (m->extra)
194 window_draw_prompt(win->w, (m->prompt) ? m->h - 3 : m->h - 2, m->w,
195 m->extra, CP_MESSAGE_PROMPT);
197 if (m->prompt)
198 window_draw_prompt(win->w, m->h - 2, m->w, m->prompt, CP_MESSAGE_PROMPT);
200 if (m->func && win->c == m->c) {
201 (*m->func)(m->arg);
202 return 1;
205 if (win->c != 0) {
206 for (i = 0; m->lines[i]; i++)
207 free(m->lines[i]);
209 free(m->lines);
210 free(m->prompt);
211 free(m->extra);
212 p = m->arg;
213 free(m);
214 win->data = p;
215 return 0;
218 return 1;
222 * The force_trim parameter will trim whitespace reguardless if there is more
223 * than one line or not (help text vs. tag viewing).
225 WIN *construct_message(const char *title, const char *prompt, int center,
226 int force_trim, const char *extra_help,
227 message_func *func, void *arg, window_exit_func *efunc,
228 wint_t ckey, int freedata, const char *fmt, ...)
230 wchar_t **lines = NULL;
231 va_list ap;
232 struct message_s *m = NULL;
233 WIN *win = NULL;
234 int h, w;
236 va_start(ap, fmt);
237 build_message_lines(title, prompt, force_trim, extra_help, &h, &w, &lines, fmt, ap);
238 va_end(ap);
240 m = Calloc(1, sizeof(struct message_s));
241 m->lines = lines;
242 m->w = w;
243 m->h = h;
244 m->center = center;
245 m->c = ckey;
246 m->func = func;
247 m->arg = arg;
249 if (prompt)
250 m->prompt = strdup(prompt);
252 if (extra_help)
253 m->extra = strdup(extra_help);
255 win = window_create(title, h, w, CALCPOSY(h), CALCPOSX(w), display_message,
256 m, efunc);
258 win->freedata = freedata;
259 wbkgd(win->w, CP_MESSAGE_WINDOW);
260 (*win->func)(win);
261 return win;