00001
00038 #include <stdint.h>
00039 #include <stdlib.h>
00040 #include <assert.h>
00041 #include <membag.h>
00042 #include <string.h>
00043 #include <util.h>
00044 #include <gfx/wtk.h>
00045
00054 enum wtk_radio_button_state {
00056 WTK_RADIOBUTTON_NORMAL,
00058 WTK_RADIOBUTTON_PRESSED,
00059 };
00060
00069 struct wtk_radio_group {
00071 wtk_radio_group_size_t num_references;
00073 struct wtk_radio_button *selected;
00074 };
00075
00084 struct wtk_radio_button {
00086 struct win_window *container;
00088 char *caption;
00090 struct wtk_radio_group *group;
00092 enum wtk_radio_button_state state;
00094 win_command_t command;
00095 };
00096
00105 struct win_window *wtk_radio_button_as_child(struct wtk_radio_button
00106 *radio_button)
00107 {
00108 assert(radio_button);
00109 return radio_button->container;
00110 }
00111
00119 void wtk_radio_button_select(struct wtk_radio_button *radio_button)
00120 {
00121 struct wtk_radio_button *old_selected;
00122
00123 assert(radio_button);
00124
00125
00126 if (radio_button->group->selected == radio_button) {
00127 return;
00128 }
00129
00130
00131 old_selected = radio_button->group->selected;
00132 radio_button->group->selected = radio_button;
00133 if (old_selected) {
00134 win_redraw(old_selected->container);
00135 }
00136
00137 win_redraw(radio_button->container);
00138 }
00139
00146 bool wtk_radio_button_is_selected(struct wtk_radio_button const *radio_button)
00147 {
00148 assert(radio_button);
00149 return (radio_button->group->selected == radio_button);
00150 }
00151
00162 static bool wtk_radio_button_handler(struct win_window *win,
00163 enum win_event_type type, void const *data)
00164 {
00165 struct win_command_event command;
00166
00167
00168 struct wtk_radio_button *radio_button =
00169 (struct wtk_radio_button *)win_get_custom_data(win);
00170
00171 switch (type) {
00172 case WIN_EVENT_DRAW:
00173 {
00174
00175
00176
00177 struct win_clip_region const *clip =
00178 (struct win_clip_region const *)data;
00179
00180
00181 assert(win == radio_button->container);
00182
00183
00184 gfx_draw_circle(clip->origin.x +
00185 WTK_RADIOBUTTON_BUTTON_X,
00186 clip->origin.y +
00187 WTK_RADIOBUTTON_BUTTON_Y,
00188 WTK_RADIOBUTTON_RADIUS,
00189 WTK_RADIOBUTTON_BUTTON_COLOR,
00190 GFX_WHOLE);
00191
00192
00193 if (radio_button->group->selected == radio_button) {
00194 gfx_draw_filled_circle(clip->origin.x +
00195 WTK_RADIOBUTTON_BUTTON_X,
00196 clip->origin.y +
00197 WTK_RADIOBUTTON_BUTTON_Y,
00198 WTK_RADIOBUTTON_RADIUS - 2,
00199 WTK_RADIOBUTTON_SELECT_COLOR,
00200 GFX_WHOLE);
00201 }
00202
00203
00204 gfx_draw_string(radio_button->caption,
00205 clip->origin.x +
00206 WTK_RADIOBUTTON_CAPTION_X,
00207 clip->origin.y +
00208 WTK_RADIOBUTTON_CAPTION_Y, &sysfont,
00209 WTK_RADIOBUTTON_CAPTION_COLOR,
00210 GFX_COLOR_TRANSPARENT);
00211
00212
00213
00214
00215 return true;
00216 }
00217
00218 case WIN_EVENT_POINTER:
00219 {
00220
00221 assert(win == radio_button->container);
00222
00223
00224
00225
00226 struct win_pointer_event const *event =
00227 (struct win_pointer_event const *)data;
00228
00229 switch (event->type) {
00230 case WIN_POINTER_PRESS:
00231
00232
00233
00234
00235
00236
00237 if (radio_button->state ==
00238 WTK_RADIOBUTTON_NORMAL) {
00239 win_grab_pointer(radio_button->
00240 container);
00241 radio_button->state =
00242 WTK_RADIOBUTTON_PRESSED;
00243 win_redraw(radio_button->container);
00244 }
00245 break;
00246
00247 case WIN_POINTER_RELEASE:
00248
00249
00250
00251 if (radio_button->state ==
00252 WTK_RADIOBUTTON_PRESSED) {
00253 bool is_inside;
00254
00255
00256 win_grab_pointer(NULL);
00257 radio_button->state =
00258 WTK_RADIOBUTTON_NORMAL;
00259 win_redraw(radio_button->container);
00260
00261
00262 is_inside = win_is_inside_window
00263 (radio_button->
00264 container,
00265 &(event->pos));
00266
00267
00268 if (is_inside) {
00269 wtk_radio_button_select
00270 (radio_button);
00271
00272
00273 if (radio_button->command) {
00274 command.sender =
00275 radio_button->container;
00276 command.recipient =
00277 radio_button->container;
00278 command.data =
00279 radio_button->command;
00280 win_queue_command_event
00281 (&command);
00282 }
00283 }
00284 }
00285 break;
00286
00287 default:
00288 break;
00289 }
00290
00291
00292
00293
00294 return true;
00295 }
00296
00297 case WIN_EVENT_DESTROY:
00298
00299 assert(win == radio_button->container);
00300
00301
00302
00303
00304 membag_free(radio_button->caption);
00305
00306
00307
00308
00309 --(radio_button->group->num_references);
00310 if (!radio_button->group->num_references) {
00311 membag_free(radio_button->group);
00312 } else {
00313 if (radio_button->group->selected == radio_button) {
00314 radio_button->group->selected = NULL;
00315 }
00316 }
00317
00318 membag_free(radio_button);
00319
00320
00321
00322
00323 return true;
00324
00325 default:
00326
00327 return false;
00328 }
00329 }
00330
00340 void wtk_radio_button_size_hint(struct win_point *size, const char *caption)
00341 {
00342 assert(size);
00343 assert(caption);
00344
00345 gfx_get_string_bounding_box(caption, &sysfont, &size->x, &size->y);
00346 size->x += WTK_RADIOBUTTON_CAPTION_X;
00347 size->y += max_s(WTK_RADIOBUTTON_CAPTION_Y + sysfont.height * sysfont.scale,
00348 WTK_RADIOBUTTON_BUTTON_Y + WTK_RADIOBUTTON_RADIUS);
00349 }
00350
00351
00372 struct wtk_radio_button *wtk_radio_button_create(struct win_window *parent,
00373 struct win_area const *area,
00374 char const *caption,
00375 bool selected,
00376 struct wtk_radio_group *group, win_command_t command)
00377 {
00378 struct wtk_radio_button *radio_button;
00379 struct win_attributes attr;
00380
00381 assert(group);
00382 assert(area);
00383 assert(caption);
00384 assert(parent);
00385
00386
00387 radio_button = membag_alloc(sizeof(struct wtk_radio_button));
00388 if (!radio_button) {
00389 goto outofmem_radio_button;
00390 }
00391
00392 radio_button->state = WTK_RADIOBUTTON_NORMAL;
00393 radio_button->group = group;
00394 radio_button->command = command;
00395
00396
00397 radio_button->caption = membag_alloc(
00398 (strlen(caption) + 1) * sizeof(char));
00399 if (!radio_button->caption) {
00400 goto outofmem_caption;
00401 }
00402
00403 wtk_copy_string(radio_button->caption, caption);
00404
00405
00406 attr.event_handler = wtk_radio_button_handler;
00407 attr.custom = radio_button;
00408
00409
00410 attr.area = *area;
00411 attr.background = NULL;
00412 attr.behavior = WIN_BEHAVIOR_REDRAW_PARENT;
00413
00414 radio_button->container = win_create(parent, &attr);
00415 if (!radio_button->container) {
00416 goto outofmem_container;
00417 }
00418
00419
00420 if (selected) {
00421 struct wtk_radio_button *old_selected = group->selected;
00422 group->selected = radio_button;
00423 if (old_selected) {
00424 win_redraw(old_selected->container);
00425 }
00426 }
00427
00428
00429 assert(group->num_references < (wtk_radio_group_size_t) - 1L);
00430 ++(group->num_references);
00431
00432 return radio_button;
00433
00434 outofmem_container:
00435 membag_free(radio_button->caption);
00436
00437 outofmem_caption:
00438 membag_free(radio_button);
00439
00440 outofmem_radio_button:
00441 return NULL;
00442 }
00443
00453 struct wtk_radio_group *wtk_radio_group_create(void)
00454 {
00455
00456 struct wtk_radio_group *radio_group =
00457 membag_alloc(sizeof(struct wtk_radio_group));
00458 if (!radio_group) {
00459 goto outofmem_radio_group;
00460 }
00461
00462
00463 radio_group->num_references = 0;
00464 radio_group->selected = NULL;
00465
00466 return radio_group;
00467
00468 outofmem_radio_group:
00469 return NULL;
00470 }
00471