Add to git.
[monolith.git] / src / ml_menu.c
1 /* Monolith menubar, menu, menuitem classes.
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_menu.c,v 1.2 2003/01/11 16:39:10 rich Exp $
19  */
20
21 #include "config.h"
22
23 #ifdef HAVE_STRING_H
24 #include <string.h>
25 #endif
26
27 #include <pool.h>
28 #include <pstring.h>
29 #include <pthr_iolib.h>
30
31 #include "monolith.h"
32 #include "ml_widget.h"
33 #include "ml_smarttext.h"
34 #include "ml_menu.h"
35
36 static void menubar_repaint (void *, ml_session, const char *, io_handle);
37 static struct ml_widget_property menubar_properties[];
38
39 struct ml_widget_operations menubar_ops =
40   {
41     repaint: menubar_repaint,
42     properties: menubar_properties,
43   };
44
45 struct ml_menubar
46 {
47   struct ml_widget_operations *ops;
48   pool pool;                    /* Pool for allocations. */
49   vector menus;                 /* Menus contained here. */
50   ml_widget w;                  /* Widget for main application area. */
51 };
52
53 static struct ml_widget_property menubar_properties[] =
54   {
55     { 0 }
56   };
57
58 struct menu
59 {
60   const char *name;
61   ml_menu menu;
62 };
63
64 static void menu_repaint (void *, ml_session, const char *, io_handle);
65 static struct ml_widget_property menu_properties[];
66
67 struct ml_widget_operations menu_ops =
68   {
69     repaint: menu_repaint,
70     properties: menu_properties,
71   };
72
73 struct ml_menu
74 {
75   struct ml_widget_operations *ops;
76   pool pool;                    /* Pool for allocations. */
77   vector items;                 /* Menu items. */
78 };
79
80 static struct ml_widget_property menu_properties[] =
81   {
82     { 0 }
83   };
84
85 static void menuitem_button_repaint (void *, ml_session, const char *, io_handle);
86 static struct ml_widget_property menuitem_button_properties[];
87
88 struct ml_widget_operations menuitem_button_ops =
89   {
90     repaint: menuitem_button_repaint,
91     properties: menuitem_button_properties,
92   };
93
94 struct ml_menuitem_button
95 {
96   struct ml_widget_operations *ops;
97   pool pool;                    /* Pool for allocations. */
98   const char *text;             /* Text on the button. */
99   const char *action_id;        /* Action. */
100   const char *title;            /* Tooltip. */
101 };
102
103 static struct ml_widget_property menuitem_button_properties[] =
104   {
105     { 0 }
106   };
107
108 static void menuitem_separator_repaint (void *, ml_session, const char *, io_handle);
109 static struct ml_widget_property menuitem_separator_properties[];
110
111 struct ml_widget_operations menuitem_separator_ops =
112   {
113     repaint: menuitem_separator_repaint,
114     properties: menuitem_separator_properties,
115   };
116
117 struct ml_menuitem_separator
118 {
119   struct ml_widget_operations *ops;
120   pool pool;                    /* Pool for allocations. */
121 };
122
123 static struct ml_widget_property menuitem_separator_properties[] =
124   {
125     { 0 }
126   };
127
128 ml_menubar
129 new_ml_menubar (pool pool)
130 {
131   ml_menubar w = pmalloc (pool, sizeof *w);
132
133   w->ops = &menubar_ops;
134   w->pool = pool;
135   w->menus = new_vector (pool, struct menu);
136   w->w = 0;
137
138   return w;
139 }
140
141 void
142 ml_menubar_push_back (ml_menubar w, const char *name, ml_menu menu)
143 {
144   struct menu m = { name, menu };
145
146   vector_push_back (w->menus, m);
147 }
148
149 ml_menu
150 ml_menubar_pop_back (ml_menubar w)
151 {
152   struct menu m;
153
154   vector_pop_back (w->menus, m);
155   return m.menu;
156 }
157
158 void
159 ml_menubar_push_front (ml_menubar w, const char *name, ml_menu menu)
160 {
161   struct menu m = { name, menu };
162
163   vector_push_front (w->menus, m);
164 }
165
166 ml_menu
167 ml_menubar_pop_front (ml_menubar w)
168 {
169   struct menu m;
170
171   vector_pop_front (w->menus, m);
172   return m.menu;
173 }
174
175 ml_menu
176 ml_menubar_get (ml_menubar w, int i)
177 {
178   struct menu m;
179
180   vector_get (w->menus, i, m);
181   return m.menu;
182 }
183
184 void
185 ml_menubar_insert (ml_menubar w, int i, const char *name, ml_menu menu)
186 {
187   struct menu m = { name, menu };
188
189   vector_insert (w->menus, i, m);
190 }
191
192 void
193 ml_menubar_replace (ml_menubar w, int i, const char *name, ml_menu menu)
194 {
195   struct menu m = { name, menu };
196
197   vector_replace (w->menus, i, m);
198 }
199
200 void
201 ml_menubar_erase (ml_menubar w, int i)
202 {
203   vector_erase (w->menus, i);
204 }
205
206 void
207 ml_menubar_clear (ml_menubar w)
208 {
209   vector_clear (w->menus);
210 }
211
212 int
213 ml_menubar_size (ml_menubar w)
214 {
215   return vector_size (w->menus);
216 }
217
218 void
219 ml_menubar_pack (ml_menubar w, ml_widget _w)
220 {
221   w->w = _w;
222 }
223
224 static void
225 menubar_repaint (void *vw, ml_session session,
226                  const char *windowid, io_handle io)
227 {
228   ml_menubar w = (ml_menubar) vw;
229   struct menu m;
230   int i;
231
232   io_fputs ("<table class=\"ml_menubar\"><tr>", io);
233
234   for (i = 0; i < vector_size (w->menus); ++i)
235     {
236       vector_get (w->menus, i, m);
237
238       io_fprintf (io, "<td class=\"ml_menubar_item\">%s", m.name);
239       menu_repaint (m.menu, session, windowid, io);
240       io_fputs ("</td>\n", io);
241     }
242
243   io_fputs ("<td width=\"100%\"></td></tr></table>", io);
244
245   if (w->w) ml_widget_repaint (w->w, session, windowid, io);
246 }
247
248 ml_menu
249 new_ml_menu (pool pool)
250 {
251   ml_menu w = pmalloc (pool, sizeof *w);
252
253   w->ops = &menu_ops;
254   w->pool = pool;
255   w->items = new_vector (pool, ml_widget);
256
257   return w;
258 }
259
260 void
261 ml_menu_push_back (ml_menu w, ml_widget menu_or_menuitem)
262 {
263   vector_push_back (w->items, menu_or_menuitem);
264 }
265
266 void
267 ml_menu_push_back_button (ml_menu w, const char *text, void (*fn) (ml_session, void *), ml_session session, void *data)
268 {
269   ml_menuitem_button b = new_ml_menuitem_button (w->pool, text);
270
271   ml_menuitem_button_set_callback (b, fn, session, data);
272   vector_push_back (w->items, b);
273 }
274
275 void
276 ml_menu_push_back_inactive_button (ml_menu w, const char *text)
277 {
278   ml_menuitem_button b = new_ml_menuitem_button (w->pool, text);
279
280   vector_push_back (w->items, b);
281 }
282
283 void
284 ml_menu_push_back_separator (ml_menu w)
285 {
286   ml_menuitem_separator b = new_ml_menuitem_separator (w->pool);
287
288   vector_push_back (w->items, b);
289 }
290
291 ml_widget
292 ml_menu_pop_back (ml_menu w)
293 {
294   ml_widget menu_or_menuitem;
295
296   vector_pop_back (w->items, menu_or_menuitem);
297   return menu_or_menuitem;
298 }
299
300 void
301 ml_menu_push_front (ml_menu w, ml_widget menu_or_menuitem)
302 {
303   vector_push_front (w->items, menu_or_menuitem);
304 }
305
306 ml_widget
307 ml_menu_pop_front (ml_menu w)
308 {
309   ml_widget menu_or_menuitem;
310
311   vector_pop_front (w->items, menu_or_menuitem);
312   return menu_or_menuitem;
313 }
314
315 ml_widget
316 ml_menu_get (ml_menu w, int i)
317 {
318   ml_widget menu_or_menuitem;
319
320   vector_get (w->items, i, menu_or_menuitem);
321   return menu_or_menuitem;
322 }
323
324 void
325 ml_menu_insert (ml_menu w, int i, ml_widget menu_or_menuitem)
326 {
327   vector_insert (w->items, i, menu_or_menuitem);
328 }
329
330 void
331 ml_menu_replace (ml_menu w, int i, ml_widget menu_or_menuitem)
332 {
333   vector_replace (w->items, i, menu_or_menuitem);
334 }
335
336 void
337 ml_menu_erase (ml_menu w, int i)
338 {
339   vector_erase (w->items, i);
340 }
341
342 void
343 ml_menu_clear (ml_menu w)
344 {
345   vector_clear (w->items);
346 }
347
348 int
349 ml_menu_size (ml_menu w)
350 {
351   return vector_size (w->items);
352 }
353
354 void
355 ml_menu_pack (ml_menu w, ml_widget menu_or_menuitem)
356 {
357   vector_push_back (w->items, menu_or_menuitem);
358 }
359
360 static void
361 menu_repaint (void *vw, ml_session session,
362               const char *windowid, io_handle io)
363 {
364   ml_menu w = (ml_menu) vw;
365   int i;
366   ml_widget m;
367
368   io_fputs ("<ul>", io);
369
370   for (i = 0; i < vector_size (w->items); ++i)
371     {
372       vector_get (w->items, i, m);
373
374       io_fputs ("<li>", io);
375       ml_widget_repaint (m, session, windowid, io);
376       io_fputs ("</li>\n", io);
377     }
378
379   io_fputs ("</ul>\n", io);
380 }
381
382 ml_menuitem_button
383 new_ml_menuitem_button (pool pool, const char *text)
384 {
385   ml_menuitem_button w = pmalloc (pool, sizeof *w);
386
387   w->ops = &menuitem_button_ops;
388   w->pool = pool;
389   w->text = text;
390   w->action_id = 0;
391   w->title = 0;
392
393   return w;
394 }
395
396 void
397 ml_menuitem_button_set_callback (ml_menuitem_button w,
398                                  void (*fn) (ml_session, void *),
399                                  ml_session session, void *data)
400 {
401   if (w->action_id)
402     ml_unregister_action (session, w->action_id);
403   w->action_id = 0;
404
405   if (fn)
406     w->action_id = ml_register_action (session, fn, data);
407 }
408
409 static void
410 menuitem_button_repaint (void *vw, ml_session session,
411                          const char *windowid, io_handle io)
412 {
413   ml_menuitem_button w = (ml_menuitem_button) vw;
414
415   if (w->text)
416     {
417       if (w->action_id)
418         {
419           pool tmp = new_subpool (w->pool);
420
421           const char *link =
422             psprintf (tmp, "%s?ml_action=%s&ml_window=%s",
423                       ml_session_script_name (session),
424                       w->action_id,
425                       windowid);
426
427           io_fprintf (io, "<a href=\"%s\"", link);
428
429           if (w->title)
430             {
431               io_fputs (" title=\"", io);
432               ml_plaintext_print (io, w->title);
433               io_fputc ('"', io);
434             }
435
436           io_fprintf (io, ">%s</a>", w->text);
437
438           delete_pool (tmp);
439         }
440       else
441         io_fprintf (io, "<span>%s</span>", w->text);
442     }
443 }
444
445 ml_menuitem_separator
446 new_ml_menuitem_separator (pool pool)
447 {
448   ml_menuitem_separator w = pmalloc (pool, sizeof *w);
449
450   w->ops = &menuitem_separator_ops;
451   w->pool = pool;
452
453   return w;
454 }
455
456 static void
457 menuitem_separator_repaint (void *vw, ml_session session,
458                             const char *windowid, io_handle io)
459 {
460   io_fputs ("<hr />", io);
461 }