Add to git.
[monolith.git] / src / ml_form_select.c
1 /* Monolith form select box input 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_form_select.c,v 1.4 2002/11/13 20:46:37 rich Exp $
19  */
20
21 #include "config.h"
22
23 #include <pthr_iolib.h>
24
25 #include "monolith.h"
26 #include "ml_widget.h"
27 #include "ml_form_input.h"
28 #include "ml_form_select.h"
29
30 static void repaint (void *, ml_session, const char *, io_handle);
31 static struct ml_widget_property properties[];
32 static void set_value (void *, const char *value);
33 static void clear_value (void *);
34
35 struct ml_widget_operations form_select_ops =
36   {
37     repaint: repaint,
38     properties: properties,
39   };
40
41 struct ml_form_input_operations form_select_input_ops =
42   {
43     set_value: set_value,
44     get_value: 0,
45     clear_value: clear_value
46   };
47
48 struct ml_form_select
49 {
50   struct ml_widget_operations *ops;
51   struct ml_form_input_operations *fops;
52   pool pool;                    /* Pool for allocations. */
53   const char *name;             /* Name of the input field. */
54   int size;                     /* Size property. */
55   int multiple;                 /* Multiple property. */
56   vector options;               /* Options (vector of strings). */
57   vector selections;            /* Selected options (vector of int). */
58   int selected;                 /* Single selection. */
59 };
60
61 static struct ml_widget_property properties[] =
62   {
63     { name: "form.select.size",
64       offset: ml_offsetof (struct ml_form_select, size),
65       type: ML_PROP_INT },
66     { name: "form.select.multiple",
67       offset: ml_offsetof (struct ml_form_select, multiple),
68       type: ML_PROP_BOOL },
69     { 0 }
70   };
71
72 ml_form_select
73 new_ml_form_select (pool pool, ml_form form)
74 {
75   ml_form_select w = pmalloc (pool, sizeof *w);
76
77   w->ops = &form_select_ops;
78   w->fops = &form_select_input_ops;
79   w->pool = pool;
80   w->size = 0;
81   w->multiple = 0;
82   w->options = new_vector (pool, const char *);
83   w->selections = 0;
84   w->selected = -1;
85
86   /* Register ourselves with the form. */
87   w->name = _ml_form_register_widget (form, w);
88
89   return w;
90 }
91
92 void
93 ml_form_select_push_back (ml_form_select w, const char *option)
94 {
95   vector_push_back (w->options, option);
96 }
97
98 const char *
99 ml_form_select_pop_back (ml_form_select w)
100 {
101   const char *option;
102
103   vector_pop_back (w->options, option);
104   return option;
105 }
106
107 void
108 ml_form_select_push_front (ml_form_select w, const char *option)
109 {
110   vector_push_front (w->options, option);
111 }
112
113 const char *
114 ml_form_select_pop_front (ml_form_select w)
115 {
116   const char *option;
117
118   vector_pop_front (w->options, option);
119   return option;
120 }
121
122 const char *
123 ml_form_select_get (ml_form_select w, int option_index)
124 {
125   const char *option;
126
127   vector_get (w->options, option_index, option);
128   return option;
129 }
130
131 void
132 ml_form_select_insert (ml_form_select w, int option_index, const char *option)
133 {
134   vector_insert (w->options, option_index, option);
135 }
136
137 void
138 ml_form_select_replace (ml_form_select w, int option_index, const char *option)
139 {
140   vector_replace (w->options, option_index, option);
141 }
142
143 void
144 ml_form_select_erase (ml_form_select w, int option_index)
145 {
146   vector_erase (w->options, option_index);
147 }
148
149 void
150 ml_form_select_clear (ml_form_select w)
151 {
152   vector_clear (w->options);
153 }
154
155 int
156 ml_form_select_size (ml_form_select w)
157 {
158   return vector_size (w->options);
159 }
160
161 void
162 ml_form_select_set_selection (ml_form_select w, int option_index)
163 {
164   if (!w->multiple)
165     w->selected = option_index;
166   else
167     abort ();
168 }
169
170 void
171 ml_form_select_set_selections (ml_form_select w, vector selected)
172 {
173   if (w->multiple)
174     w->selections = selected;
175   else
176     abort ();
177 }
178
179 int
180 ml_form_select_get_selection (ml_form_select w)
181 {
182   if (!w->multiple)
183     return w->selected;
184   else
185     abort ();
186 }
187
188 const vector
189 ml_form_select_get_selections (ml_form_select w)
190 {
191   if (w->multiple)
192     return w->selections;
193   else
194     abort ();
195 }
196
197 static void
198 clear_value (void *vw)
199 {
200   ml_form_select w = (ml_form_select) vw;
201
202   if (!w->multiple)
203     {
204       w->selected = -1;
205     }
206   else
207     {
208       int zero = 0;
209
210       w->selections = new_vector (w->pool, int);
211       vector_fill (w->selections, zero, vector_size (w->options));
212     }
213 }
214
215 static void
216 set_value (void *vw, const char *value)
217 {
218   ml_form_select w = (ml_form_select) vw;
219
220   sscanf (value, "%d", &w->selected);
221
222   if (w->multiple && w->selections &&
223       w->selected >= 0 && w->selected < vector_size (w->selections))
224     {
225       int one = 1;
226
227       vector_replace (w->selections, w->selected, one);
228     }
229 }
230
231 static inline int
232 is_selected (ml_form_select w, int index)
233 {
234   if (!w->multiple)
235     return index == w->selected;
236   else
237     {
238       if (w->selections && index < vector_size (w->selections))
239         {
240           int i;
241
242           vector_get (w->selections, index, i);
243           return i;
244         }
245       else
246         return 0;
247     }
248 }
249
250 static void
251 repaint (void *vw, ml_session session, const char *windowid, io_handle io)
252 {
253   ml_form_select w = (ml_form_select) vw;
254   int i;
255   const char *option;
256
257   io_fprintf (io, "<select class=\"ml_form_select\" name=\"%s\"", w->name);
258   if (w->size) io_fprintf (io, " size=\"%d\"", w->size);
259   if (w->multiple) io_fprintf (io, " multiple=\"1\"");
260   io_fprintf (io, ">");
261
262   for (i = 0; i < vector_size (w->options); ++i)
263     {
264       vector_get (w->options, i, option);
265
266       io_fprintf (io, "<option value=\"%d\"", i);
267       if (is_selected (w, i))
268         io_fprintf (io, " selected=\"1\"");
269       io_fprintf (io, ">%s</option>\n", option);
270     }
271
272   io_fprintf (io, "</select>");
273 }