eh, make ’em volatile, this is not time-critical code anyway
[alioth/magicpoint.git] / plist.c
1 /*
2  * Copyright (C) 1997 and 1998 WIDE Project.  All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  * 3. Neither the name of the project nor the names of its contributors
13  *    may be used to endorse or promote products derived from this software
14  *    without specific prior written permission.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
17  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19  * ARE DISCLAIMED.  IN NO EVENT SHALL THE PROJECT OR CONTRIBUTORS BE LIABLE
20  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
26  * SUCH DAMAGE.
27  */
28
29 #include "mgp.h"
30
31 #define PL_X_MARGIN     10
32
33 static Window pl_titlewin = None;
34 static Window pg_win = None;
35 static Pixmap pg_tmp;
36 static int pg_lastpage = -1;
37
38 static int draw_kstring(Drawable, char *, int, int);
39
40 /*
41  * Display Page List at the bottom of the window
42  */
43
44 void
45 pl_on(struct render_state *state)
46 {
47         XSetWindowAttributes wattr;
48         unsigned int i;
49         int ny, pl_x;
50         u_int pl_nx, pl_ny, pl_y;
51
52         if (pl_titlewin || !plfs)
53                 return;
54
55         /* number of pages in x-axis */
56         pl_nx = (window_width - 2 * PL_X_MARGIN) / pl_fw / 3;
57         /* number of pages in y-axis */
58         pl_ny = maxpage / pl_nx + 1;
59         /* page list coordinate */
60         pl_x = PL_X_MARGIN;
61         /* keep 5 for timebar*/
62         pl_y = window_height - (pl_ny + 1) * pl_fh - (t_fin ? 5 : 0);
63         pl_titlewin = XCreateSimpleWindow(display, window,
64                 0, pl_y - pl_fh, window_width, pl_fh, 0,
65                 BlackPixel(display, 0), back_color[caching]);
66         XSelectInput(display, pl_titlewin, StructureNotifyMask);
67
68         for (i = 1; i <= maxpage; i++) {
69                 ny = (i - 1) / pl_nx;
70                 plwin[i] = XCreateSimpleWindow(display, window,
71                         pl_x + 3 * ((i - 1) % pl_nx) * pl_fw,
72                         pl_y + pl_fh * ny,
73                         3 * pl_fw, pl_fh, 0,
74                         BlackPixel(display, 0), WhitePixel(display, 0));
75                 wattr.do_not_propagate_mask =
76                         ButtonPressMask|ButtonReleaseMask;
77                 XChangeWindowAttributes(display, plwin[i],
78                         CWDontPropagate, &wattr);
79                 XSelectInput(display, plwin[i],
80                         ButtonPressMask|EnterWindowMask|
81                         LeaveWindowMask|StructureNotifyMask);
82         }
83
84         XMapSubwindows(display, window);
85         for (i = 1; i <= maxpage; i++)
86                 pl_pdraw(state, i, gc_pl);
87 }
88
89 /*
90  * Turn off the page list
91  */
92 void
93 pl_off(void)
94 {
95         unsigned int i;
96
97         pg_lastpage = -1;
98         if (!pl_titlewin)
99                 return;
100         XUnmapSubwindows(display, window);
101         XDestroyWindow(display, pl_titlewin);
102         pl_titlewin = None;
103         for (i = 1; i <= maxpage; i++) {
104                 XDestroyWindow(display, plwin[i]);
105                 plwin[i] = None;
106         }
107         XMapSubwindows(display, window);
108         XFlush(display);
109 }
110
111 /*
112  * Draw page numbers in each small window
113  * Enbold the current page
114  */
115 void
116 pl_pdraw(struct render_state *state, unsigned int i, GC gc)
117 {
118         char buf[10];
119
120         if (!pl_titlewin)
121                 return;
122
123         sprintf(buf, "%02d", i % 100);
124         XDrawImageString(display, plwin[i], gc, (int)(pl_fw / 2),
125                 (int)(pl_fh / 1.2), buf, 2);
126         if (i == state->page)
127                 XDrawString(display, plwin[i], gc, (int)(pl_fw / 2) + 1,
128                         (int)(pl_fh / 1.2), buf, 2);
129 }
130
131 /*
132  * Show the title of the page when the mouse enters a window.
133  * Turn it off if the page number is zero.
134  */
135 void
136 pl_title(u_int page)
137 {
138         char buf[BUFSIZ];
139
140         if (!pl_titlewin)
141                 return;
142
143         XClearArea(display, pl_titlewin, 0, 0, window_width, pl_fh, 0);
144         if (page == 0)
145                 return;
146         sprintf(buf, "page %d: %s", page, page_title(page));
147         XSetForeground(display, gc_pta, ctrl_color[caching]);
148         XSetForeground(display, gc_ptk, ctrl_color[caching]);
149         XSetBackground(display, gc_pta, back_color[caching]);
150         XSetBackground(display, gc_ptk, back_color[caching]);
151         draw_kstring(pl_titlewin, buf,
152                 PL_X_MARGIN, pl_fh - plfs->max_bounds.descent);
153 }
154
155 /*
156  * Returns a pointer to title of specified page.
157  */
158 const char *
159 page_title(u_int page)
160 {
161         unsigned int l;
162         const char *p;
163         struct ctrl *cp;
164
165         if( page_attribute[page].pg_title_str &&
166                 *page_attribute[page].pg_title_str) {
167                 return page_attribute[page].pg_title_str ;
168         } else {
169         p = "";
170         for (l = 0; l <= page_attribute[page].pg_linenum; l++) {
171                 cp = page_control[page][l];
172                 while (cp && cp->ct_op != CTL_TEXT)
173                         cp = cp->ct_next;
174                 if (!cp)
175                         continue;
176                 if (cp->ctc_value && *cp->ctc_value) {
177                         p = cp->ctc_value;
178                         break;
179                 }
180         }
181
182         while (*p && isspace(*p))
183                 p++;
184
185         return p;
186         }
187 }
188
189 void
190 pg_on(void)
191 {
192         if (pg_win)
193                 return;
194
195         /* 5 for timebar*/
196         pg_win = XCreateSimpleWindow(display, window,
197                 0, window_height - pl_fh - (t_fin ? 5 : 0),
198                 window_width, pl_fh, 0,
199                 BlackPixel(display, screen), back_color[caching]);
200         XSelectInput(display, pg_win, StructureNotifyMask);
201         XMapSubwindows(display, window);
202
203         pg_tmp = XCreatePixmap(display, pg_win, window_width, pl_fh, depth);
204
205         pg_lastpage = -1;
206 }
207
208 void
209 pg_clean(void)
210 {
211         XClearArea(display, pg_win, 0, 0, window_width, pl_fh, 0);
212         pg_lastpage = -1;
213 }
214
215 void
216 pg_draw(struct render_state *state)
217 {
218         char buf[BUFSIZ], *p;
219         int n;
220         u_int page;
221         int showlast;
222
223         if (!pg_mode || !pg_win || !plfs)
224                 return;
225
226         page = state->page;
227         if (page == (unsigned int)pg_lastpage)
228                 return;
229
230         showlast = /* !state->cp || (state->cp->ct_op == CTL_PAUSE && state->cp->cti_value) */
231             !(page > 1 && page < maxpage);
232         XSetForeground(display, gc_pta, ctrl_color[caching]);
233         XSetForeground(display, gc_ptk, ctrl_color[caching]);
234         XSetBackground(display, gc_pta, back_color[caching]);
235         XSetBackground(display, gc_ptk, back_color[caching]);
236
237         pg_clean();
238         if (page > 1) {
239                 snprintf(buf, sizeof(buf), "\033$B\"+\033(B %s",
240                         page_title(page - 1));
241                 draw_kstring(pg_win, buf,
242                         PL_X_MARGIN, pl_fh - plfs->max_bounds.descent);
243         }
244         if (page < maxpage) {
245                 snprintf(buf, sizeof(buf), "%s \033$B\"*\033(B",
246                         page_title(page + 1));
247                 for (p = buf; *p; p++)
248                         if (*p == '\n')
249                                 *p = ' ';
250                 n = draw_kstring(pg_tmp, buf, 0, pl_fh);
251                 snprintf(buf, sizeof(buf), "%s \033$B\"*\033(B",
252                         page_title(page + 1));
253                 for (p = buf; *p; p++)
254                         if (*p == '\n')
255                                 *p = ' ';
256                 draw_kstring(pg_win, buf, window_width - 10 - n,
257                         pl_fh - plfs->max_bounds.descent);
258         }
259         if (showlast == 0) {
260                 snprintf(buf, sizeof(buf), "-- %d/%d --", page, maxpage);
261                 n = draw_kstring(pg_tmp, buf, 0, pl_fh);
262                 /*
263                  * The contents of buf is not destroyed by draw_kstring
264                  * as it doesnot include Kanji sequence.
265                  */
266                 draw_kstring(pg_win, buf, window_width / 2 - n / 2,
267                         pl_fh - plfs->max_bounds.descent);
268         }
269
270         pg_lastpage = state->page;
271 }
272
273 void
274 pg_off(void)
275 {
276         if (!pg_win)
277                 return;
278         XUnmapSubwindows(display, window);
279         XFreePixmap(display, pg_tmp);
280         XDestroyWindow(display, pg_win);
281         XMapSubwindows(display, window);
282         XFlush(display);
283         pg_win = None;
284         pg_lastpage = -1;
285 }
286
287 static int
288 draw_kstring(Drawable d, char *buf, int x, int y)
289 {
290         char *p;
291         int x0 = x;
292
293         p = buf + strlen(buf) - 1;
294         if (*p == '\n')
295                 *p = '\0';
296         for (p = buf; *p; p++) {
297                 if (strncmp(p, "\033$@", 3) == 0 ||
298                     strncmp(p, "\033$B", 3) == 0) {
299                         *p = '\0'; p += 3;
300                         /* draw 8bit char */
301                         XDrawImageString(display, d, gc_pta, x, y,
302                                 buf, strlen(buf));
303                         x += XTextWidth(plfs, buf, strlen(buf));
304                         buf = p--;
305                 } else if (strncmp(p, "\033(B", 3) == 0 ||
306                            strncmp(p, "\033-A", 3) == 0 ||
307                            strncmp(p, "\033(J", 3) == 0) {
308                         *p = '\0'; p += 3;
309                         /* draw 16bit char */
310                         XDrawImageString16(display, d, gc_ptk, x, y,
311                                 (XChar2b *)buf, strlen(buf)/2);
312                         x += XTextWidth16(plkfs, (XChar2b *)buf, strlen(buf)/2);
313                         buf = p--;
314                 }
315         }
316         /* draw 8bit char */
317         if (*buf != '\0') {     /* Assumed ASCII at the end of string */
318                 XDrawImageString(display, d, gc_pta, x, y, buf, strlen(buf));
319                 x += XTextWidth(plfs, buf, strlen(buf));
320         }
321         return x - x0;
322 }