Add to git.
[monolith.git] / src / ml_select_layout.c
1 /* Monolith select layout class.
2  * - by Richard W.M. Jones <rich@annexia.org>
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Library General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Library General Public License for more details.
13  *
14  * You should have received a copy of the GNU Library General Public
15  * License along with this library; if not, write to the Free
16  * Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17  *
18  * $Id: ml_select_layout.c,v 1.3 2002/12/02 10:27:18 rich Exp $
19  */
20
21 #include "config.h"
22
23 #include <assert.h>
24
25 #ifdef HAVE_STRING_H
26 #include <string.h>
27 #endif
28
29 #include <pool.h>
30 #include <vector.h>
31
32 #include <pthr_iolib.h>
33
34 #include "ml_widget.h"
35 #include "monolith.h"
36 #include "ml_smarttext.h"
37 #include "ml_select_layout.h"
38
39 static void repaint (void *, ml_session, const char *, io_handle);
40 static struct ml_widget_property properties[];
41
42 struct ml_widget_operations select_layout_ops =
43   {
44     repaint: repaint,
45     properties: properties,
46   };
47
48 struct ml_select_layout
49 {
50   struct ml_widget_operations *ops;
51   pool pool;                    /* Pool for allocations. */
52   ml_session session;           /* Current session. */
53   vector tabs;                  /* Vector of tabs. */
54   int selected;                 /* Index of selected tab. */
55   const char *clazz;            /* Class of top-level table. */
56   ml_widget top;                /* "Top" widget (see manpage). */
57   ml_widget bottom;             /* "Bottom" widget (see manpage). */
58 };
59
60 struct tab
61 {
62   const char *name;             /* Name of the tab. */
63   ml_widget w;                  /* Widget. */
64
65   /* Do not set this directly. Use make_action and del_action functions. */
66   const char *action_id;
67 };
68
69 static struct ml_widget_property properties[] =
70   {
71     { name: "class",
72       offset: ml_offsetof (struct ml_select_layout, clazz),
73       type: ML_PROP_STRING },
74     { name: "select_layout.top",
75       offset: ml_offsetof (struct ml_select_layout, top),
76       type: ML_PROP_WIDGET },
77     { name: "select_layout.bottom",
78       offset: ml_offsetof (struct ml_select_layout, bottom),
79       type: ML_PROP_WIDGET },
80     { 0 }
81   };
82
83 ml_select_layout
84 new_ml_select_layout (pool pool, ml_session session)
85 {
86   ml_select_layout w = pmalloc (pool, sizeof *w);
87
88   w->ops = &select_layout_ops;
89   w->pool = pool;
90   w->session = session;
91   w->tabs = new_vector (pool, struct tab);
92   w->selected = 0;
93   w->clazz = 0;
94   w->top = w->bottom = 0;
95
96   return w;
97 }
98
99 static void make_action (ml_select_layout w, struct tab *tab);
100 static void del_action (ml_select_layout w, struct tab *tab);
101
102 void
103 ml_select_layout_push_back (ml_select_layout w, const char *name, ml_widget _w)
104 {
105   struct tab tab;
106
107   tab.name = name;
108   tab.w = _w;
109   make_action (w, &tab);
110   vector_push_back (w->tabs, tab);
111 }
112
113 ml_widget
114 ml_select_layout_pop_back (ml_select_layout w)
115 {
116   struct tab tab;
117
118   vector_pop_back (w->tabs, tab);
119   del_action (w, &tab);
120   return tab.w;
121 }
122
123 void
124 ml_select_layout_push_front (ml_select_layout w,
125                              const char *name, ml_widget _w)
126 {
127   struct tab tab;
128
129   tab.name = name;
130   tab.w = _w;
131   make_action (w, &tab);
132   vector_push_front (w->tabs, tab);
133 }
134
135 ml_widget
136 ml_select_layout_pop_front (ml_select_layout w)
137 {
138   struct tab tab;
139
140   vector_pop_front (w->tabs, tab);
141   del_action (w, &tab);
142   return tab.w;
143 }
144
145 ml_widget
146 ml_select_layout_get (ml_select_layout w, int i)
147 {
148   struct tab tab;
149
150   vector_get (w->tabs, i, tab);
151   return tab.w;
152 }
153
154 void
155 ml_select_layout_insert (ml_select_layout w, int i,
156                          const char *name, ml_widget _w)
157 {
158   struct tab tab;
159
160   tab.name = name;
161   tab.w = _w;
162   make_action (w, &tab);
163   vector_insert (w->tabs, i, tab);
164 }
165
166 void
167 ml_select_layout_replace (ml_select_layout w, int i,
168                           const char *name, ml_widget _w)
169 {
170   struct tab tab;
171
172   vector_get (w->tabs, i, tab);
173   del_action (w, &tab);
174
175   tab.name = name;
176   tab.w = _w;
177   make_action (w, &tab);
178   vector_replace (w->tabs, i, tab);
179 }
180
181 void
182 ml_select_layout_erase (ml_select_layout w, int i)
183 {
184   struct tab tab;
185
186   vector_get (w->tabs, i, tab);
187   del_action (w, &tab);
188
189   vector_erase (w->tabs, i);
190 }
191
192 void
193 ml_select_layout_clear (ml_select_layout w)
194 {
195   int i;
196
197   for (i = 0; i < vector_size (w->tabs); ++i)
198     {
199       struct tab tab;
200
201       vector_get (w->tabs, i, tab);
202       del_action (w, &tab);
203     }
204
205   vector_clear (w->tabs);
206 }
207
208 int
209 ml_select_layout_size (ml_select_layout w)
210 {
211   return vector_size (w->tabs);
212 }
213
214 void
215 ml_select_layout_pack (ml_select_layout w, const char *name, ml_widget _w)
216 {
217   ml_select_layout_push_back (w, name, _w);
218 }
219
220 void
221 ml_select_layout_set_selection (ml_select_layout w, int i)
222 {
223   w->selected = i;
224 }
225
226 int
227 ml_select_layout_get_selection (ml_select_layout w)
228 {
229   return w->selected;
230 }
231
232 static void
233 repaint (void *vw, ml_session session, const char *windowid, io_handle io)
234 {
235   ml_select_layout w = (ml_select_layout) vw;
236   int i;
237   struct tab *tab;
238   const char *clazz = w->clazz ? : "ml_select_layout";
239
240   /* Verify the selection is in range. If not, bring it into range. */
241   if (w->selected < 0) w->selected = 0;
242   else if (w->selected >= vector_size (w->tabs))
243     w->selected = vector_size (w->tabs) - 1;
244
245   /* Begin the table. */
246   io_fprintf (io, "<table class=\"%s\"><tr><td valign=\"top\">", clazz);
247
248   /* Left hand column. */
249   if (w->top) ml_widget_repaint (w->top, session, windowid, io);
250
251   io_fputs ("<table class=\"ml_select_layout_left\">", io);
252
253   for (i = 0; i < vector_size (w->tabs); ++i)
254     {
255       vector_get_ptr (w->tabs, i, tab);
256
257       io_fputs ("<tr>", io);
258       if (i == w->selected) io_fputs ("<th>", io);
259       else io_fputs ("<td>", io);
260
261       io_fprintf (io, "<a href=\"%s?ml_action=%s&ml_window=%s\">",
262                   ml_session_script_name (w->session),
263                   tab->action_id, windowid);
264       ml_plaintext_print (io, tab->name);
265       io_fputs ("</a>", io);
266
267       if (i == w->selected) io_fputs ("</th>", io);
268       else io_fputs ("</td>", io);
269       io_fputs ("</tr>\n", io);
270     }
271
272   io_fputs ("</table>", io);
273
274   if (w->bottom) ml_widget_repaint (w->bottom, session, windowid, io);
275
276   io_fputs ("</td>\n<td valign=\"top\">", io);
277
278   /* Right hand column: the widget. */
279   vector_get_ptr (w->tabs, w->selected, tab);
280
281   if (tab->w) ml_widget_repaint (tab->w, session, windowid, io);
282
283   io_fputs ("</td></tr></table>", io);
284 }
285
286 static void do_select (ml_session session, void *vargs);
287
288 struct select_args
289 {
290   ml_select_layout w;           /* The widget. */
291   const char *action_id;        /* The action ID. */
292 };
293
294 static void
295 make_action (ml_select_layout w, struct tab *tab)
296 {
297   struct select_args *args = pmalloc (w->pool, sizeof *args);
298
299   args->w = w;
300   args->action_id = tab->action_id =
301     ml_register_action (w->session, do_select, args);
302 }
303
304 static void
305 del_action (ml_select_layout w, struct tab *tab)
306 {
307   ml_unregister_action (w->session, tab->action_id);
308 }
309
310 /* This function is called when the user clicks on one of the items on the
311  * left hand side.
312  *
313  * Because items can move around, we didn't store the absolute item number
314  * in the struct select_args. Instead, we stored the action_id, which we'll
315  * use to search through the current tabs to find out which tab the
316  * user was trying to click.
317  */
318 static void
319 do_select (ml_session session, void *vargs)
320 {
321   struct select_args *args = (struct select_args *) vargs;
322   const char *action_id = args->action_id;
323   ml_select_layout w = args->w;
324   int i;
325   struct tab *tab;
326
327   for (i = 0; i < vector_size (w->tabs); ++i)
328     {
329       vector_get_ptr (w->tabs, i, tab);
330
331       if (strcmp (tab->action_id, action_id) == 0)
332         {
333           /* Found it. */
334           w->selected = i;
335           return;
336         }
337     }
338
339   /* Don't worry if we don't find it. Perhaps the underlying code has
340    * deleted this item, but the browser window was not updated.
341    */
342 }