1 #include <slang.h>
2 #include <stdlib.h>
3 #include <string.h>
4 
5 #include "newt.h"
6 #include "newt_pr.h"
7 
8 enum type { CHECK, RADIO };
9 
10 struct checkbox {
11     char * text;
12     char * seq;
13     char * result;
14     newtComponent prevButton, lastButton;
15     enum type type;
16     char value;
17     int active, inactive;
18     const void * data;
19     int flags;
20     int hasFocus;
21 };
22 
23 static void cbDraw(newtComponent c);
24 static void cbDestroy(newtComponent co);
25 struct eventResult cbEvent(newtComponent co, struct event ev);
26 
27 static struct componentOps cbOps = {
28     cbDraw,
29     cbEvent,
30     cbDestroy,
31     newtDefaultPlaceHandler,
32     newtDefaultMappedHandler,
33 } ;
34 
newtRadiobutton(int left,int top,const char * text,int isDefault,newtComponent prevButton)35 newtComponent newtRadiobutton(int left, int top, const char * text, int isDefault,
36 			      newtComponent prevButton) {
37     newtComponent co;
38     newtComponent curr;
39     struct checkbox * rb;
40     char initialValue;
41 
42     if (isDefault)
43 	initialValue = '*';
44     else
45 	initialValue = ' ';
46 
47     co = newtCheckbox(left, top, text, initialValue, " *", NULL);
48     rb = co->data;
49     rb->type = RADIO;
50 
51     rb->prevButton = prevButton;
52 
53     for (curr = co; curr; curr = rb->prevButton) {
54 	rb = curr->data;
55 	rb->lastButton = co;
56     }
57 
58     return co;
59 }
60 
newtRadioGetCurrent(newtComponent setMember)61 newtComponent newtRadioGetCurrent(newtComponent setMember) {
62     struct checkbox * rb = setMember->data;
63 
64     setMember = rb->lastButton;
65     rb = setMember->data;
66 
67     while (rb && rb->value != '*') {
68 	setMember = rb->prevButton;
69 	if (!setMember)
70 	  return NULL;
71 	rb = setMember->data;
72     }
73 
74     return setMember;
75 }
76 
newtRadioSetCurrent(newtComponent setMember)77 void newtRadioSetCurrent(newtComponent setMember) {
78     struct checkbox * cb = setMember->data;
79     struct checkbox * rb;
80     newtComponent curr;
81 
82     /* find the one that's turned on */
83     curr = cb->lastButton;
84     rb = curr->data;
85     while (curr && rb->value == rb->seq[0]) {
86         curr = rb->prevButton;
87         if (curr) rb = curr->data;
88     }
89     if (curr) {
90         rb->value = rb->seq[0];
91         cbDraw(curr);
92     }
93     cb->value = cb->seq[1];
94     cbDraw(setMember);
95 
96     if (setMember->callback)
97         setMember->callback(setMember, setMember->callbackData);
98 }
99 
newtCheckboxGetValue(newtComponent co)100 char newtCheckboxGetValue(newtComponent co) {
101     struct checkbox * cb = co->data;
102 
103     return cb->value;
104 }
105 
newtCheckboxSetValue(newtComponent co,char value)106 void newtCheckboxSetValue(newtComponent co, char value) {
107     struct checkbox * cb = co->data;
108 
109     *cb->result = value;
110     cbDraw(co);
111 }
112 
113 /*
114  * returns NULL on error.
115  * FIXME: Check all calls.
116  */
newtCheckbox(int left,int top,const char * text,char defValue,const char * seq,char * result)117 newtComponent newtCheckbox(int left, int top, const char * text, char defValue,
118 			   const char * seq, char * result) {
119     newtComponent co;
120     struct checkbox * cb;
121 
122     if (!seq) seq = " *";
123 
124     co = malloc(sizeof(*co));
125     if (co == NULL)
126    	return NULL;
127     cb = malloc(sizeof(struct checkbox));
128     if (cb == NULL) {
129 	free(co);
130 	return NULL;
131     }
132     co->data = cb;
133     cb->flags = 0;
134     if (result)
135 	cb->result = result;
136     else
137 	cb->result = &cb->value;
138 
139     cb->text = strdup(text);
140     cb->seq = strdup(seq);
141     cb->type = CHECK;
142     cb->hasFocus = 0;
143     cb->inactive = COLORSET_CHECKBOX;
144     cb->active = COLORSET_ACTCHECKBOX;
145     defValue ? (*cb->result = defValue) : (*cb->result = cb->seq[0]);
146 
147     co->ops = &cbOps;
148 
149     co->callback = NULL;
150     co->destroyCallback = NULL;
151     co->height = 1;
152     co->width = wstrlen(text, -1) + 4;
153     co->top = top;
154     co->left = left;
155     co->takesFocus = 1;
156     co->isMapped = 0;
157 
158     return co;
159 }
160 
newtCheckboxSetFlags(newtComponent co,int flags,enum newtFlagsSense sense)161 void newtCheckboxSetFlags(newtComponent co, int flags, enum newtFlagsSense sense) {
162     struct checkbox * cb = co->data;
163     int row, col;
164 
165     cb->flags = newtSetFlags(cb->flags, flags, sense);
166 
167     // If the flag just sets a property (eg. NEWT_FLAG_RETURNEXIT),
168     // don't redraw, etc. as the component might be 'hidden' and not to
169     // be drawn (eg. in a scrolled list)
170     if (flags == NEWT_FLAG_RETURNEXIT)
171 	    return;
172 
173     if (!(cb->flags & NEWT_FLAG_DISABLED))
174 	co->takesFocus = 1;
175     else
176 	co->takesFocus = 0;
177 
178     newtGetrc(&row, &col);
179     cbDraw(co);
180     newtGotorc(row, col);
181 }
182 
cbDraw(newtComponent c)183 static void cbDraw(newtComponent c) {
184     struct checkbox * cb = c->data;
185 
186     if (!c->isMapped) return;
187 
188     if (cb->flags & NEWT_FLAG_DISABLED) {
189 	cb->inactive = NEWT_COLORSET_DISENTRY;
190 	cb->active = NEWT_COLORSET_DISENTRY;
191     } else {
192 	cb->inactive = COLORSET_CHECKBOX;
193 	cb->active = COLORSET_ACTCHECKBOX;
194     }
195 
196     SLsmg_set_color(cb->inactive);
197 
198     newtGotorc(c->top, c->left);
199 
200     switch (cb->type) {
201       case RADIO:
202 	SLsmg_write_string("( ) ");
203 	break;
204 
205       case CHECK:
206 	SLsmg_write_string("[ ] ");
207 	break;
208 
209       default:
210 	break;
211     }
212 
213     SLsmg_write_string(cb->text);
214 
215     if (cb->hasFocus)
216 	SLsmg_set_color(cb->active);
217 
218     newtGotorc(c->top, c->left + 1);
219     SLsmg_write_char(*cb->result);
220     newtGotorc(c->top, c->left + 4);
221 }
222 
cbDestroy(newtComponent co)223 static void cbDestroy(newtComponent co) {
224     struct checkbox * cb = co->data;
225 
226     free(cb->text);
227     free(cb->seq);
228     free(cb);
229     free(co);
230 }
231 
cbEvent(newtComponent co,struct event ev)232 struct eventResult cbEvent(newtComponent co, struct event ev) {
233     struct checkbox * cb = co->data;
234     struct eventResult er;
235     const char * cur;
236 
237     er.result = ER_IGNORED;
238 
239     if (ev.when == EV_NORMAL) {
240 	switch (ev.event) {
241 	  case EV_FOCUS:
242 	    cb->hasFocus = 1;
243 	    cbDraw(co);
244 	    er.result = ER_SWALLOWED;
245 	    break;
246 
247 	  case EV_UNFOCUS:
248 	    cb->hasFocus = 0;
249 	    cbDraw(co);
250 	    er.result = ER_SWALLOWED;
251 	    break;
252 
253 	  case EV_KEYPRESS:
254 	    if (ev.u.key == ' ') {
255 		if (cb->type == RADIO) {
256 		    newtRadioSetCurrent(co);
257 		} else if (cb->type == CHECK) {
258 		    cur = strchr(cb->seq, *cb->result);
259 		    if (!cur)
260 			*cb->result = *cb->seq;
261 		    else {
262 			cur++;
263 			if (! *cur)
264 			    *cb->result = *cb->seq;
265 			else
266 			    *cb->result = *cur;
267 		    }
268 		    cbDraw(co);
269 		    er.result = ER_SWALLOWED;
270 
271 		    if (co->callback)
272 			co->callback(co, co->callbackData);
273 		} else {
274 		    er.result = ER_IGNORED;
275 		}
276 	    } else if(ev.u.key == NEWT_KEY_ENTER) {
277 		if (cb->flags & NEWT_FLAG_RETURNEXIT)
278 			er.result = ER_EXITFORM;
279 		else
280 			er.result = ER_IGNORED;
281 	    } else {
282 		er.result = ER_IGNORED;
283 	    }
284 	    break;
285    	  case EV_MOUSE:
286 	    if (ev.u.mouse.type == MOUSE_BUTTON_DOWN) {
287 		if (cb->type == RADIO) {
288 		    newtRadioSetCurrent(co);
289 		} else if (cb->type == CHECK) {
290 		    cur = strchr(cb->seq, *cb->result);
291 		    if (!cur)
292 			*cb->result = *cb->seq;
293 		    else {
294 			cur++;
295 			if (! *cur)
296 			    *cb->result = *cb->seq;
297 			else
298 			    *cb->result = *cur;
299 		    }
300 		    cbDraw(co);
301 		    er.result = ER_SWALLOWED;
302 
303 		    if (co->callback)
304 			co->callback(co, co->callbackData);
305 		}
306 	    }
307 	}
308     }
309 
310     return er;
311 }
312