00001
00038 #include <stdint.h>
00039 #include <stdlib.h>
00040 #include <assert.h>
00041 #include <membag.h>
00042 #include <string.h>
00043 #include <gfx/wtk.h>
00044
00054 enum wtk_slider_state {
00056 WTK_SLIDER_NORMAL,
00058 WTK_SLIDER_MOVING,
00059 };
00060
00072 struct wtk_slider {
00074 struct win_window *container;
00076 struct win_point root_pos;
00078 enum wtk_slider_state state;
00080 uint8_t maximum;
00082 uint8_t value;
00084 uint8_t position;
00086 uint8_t option;
00088 win_command_t command;
00089 };
00090
00101 struct win_window *wtk_slider_as_child(struct wtk_slider *slider)
00102 {
00103 assert(slider);
00104 return slider->container;
00105 }
00106
00117 bool wtk_slider_is_moving(struct wtk_slider const *slider)
00118 {
00119 assert(slider);
00120 return slider->state == WTK_SLIDER_MOVING;
00121 }
00122
00132 uint8_t wtk_slider_get_value(struct wtk_slider const *slider)
00133 {
00134 assert(slider);
00135
00136 if (slider->option & WTK_SLIDER_INVERT) {
00137 return slider->maximum - slider->value;
00138 } else {
00139 return slider->value;
00140 }
00141 }
00142
00155 bool wtk_slider_set_value(struct wtk_slider *slider, uint8_t value)
00156 {
00157 struct win_area const *area;
00158 uint8_t length;
00159 uint8_t option;
00160
00161 assert(slider);
00162 assert(value <= slider->maximum);
00163
00164 option = slider->option;
00165
00166 if (option & WTK_SLIDER_INVERT) {
00167 value = slider->maximum - value;
00168 }
00169
00170 if (slider->value != value) {
00171 slider->value = value;
00172 area = win_get_area(slider->container);
00173
00174
00175
00176
00177 if (option & WTK_SLIDER_VERTICAL) {
00178 length = area->size.y;
00179 } else {
00180 length = area->size.x;
00181 }
00182
00183 length -= WTK_SLIDER_KNOB_WIDTH;
00184 slider->position = wtk_rescale_value(value, slider->maximum,
00185 length);
00186
00187 win_redraw(slider->container);
00188
00189 return true;
00190 } else {
00191 return false;
00192 }
00193 }
00194
00213 static bool wtk_slider_handler(struct win_window *win, enum win_event_type type,
00214 void const *data)
00215 {
00216 struct win_pointer_event const *event;
00217 struct win_clip_region const *clip;
00218 struct win_command_event command;
00219 struct win_area const *area;
00220 struct wtk_slider *slider;
00221 struct win_point origin;
00222 gfx_color_t knob_color;
00223 gfx_coord_t position;
00224 gfx_coord_t length;
00225 uint8_t option;
00226 uint8_t value;
00227 bool send_command;
00228
00229 slider = (struct wtk_slider *)win_get_custom_data(win);
00230
00231
00232 assert(win == slider->container);
00233
00234 switch (type) {
00235 case WIN_EVENT_DRAW:
00236
00237
00238
00239 clip = (struct win_clip_region const *)data;
00240 area = win_get_area(win);
00241 option = slider->option;
00242
00243 if (slider->state == WTK_SLIDER_NORMAL) {
00244 knob_color = WTK_SLIDER_KNOB_COLOR_NORMAL;
00245 } else {
00246 knob_color = WTK_SLIDER_KNOB_COLOR_MOVING;
00247 }
00248
00249
00250 gfx_draw_rect(clip->origin.x,
00251 clip->origin.y,
00252 area->size.x,
00253 area->size.y, WTK_SLIDER_BORDER_COLOR);
00254
00255
00256 gfx_draw_filled_rect(clip->origin.x + 1,
00257 clip->origin.y + 1,
00258 area->size.x - 2,
00259 area->size.y - 2, WTK_SLIDER_BACKGROUND_COLOR);
00260
00261
00262 if (option & WTK_SLIDER_VERTICAL) {
00263
00264 gfx_draw_rect(clip->origin.x,
00265 clip->origin.y + slider->position,
00266 area->size.x,
00267 WTK_SLIDER_KNOB_WIDTH,
00268 WTK_SLIDER_BORDER_COLOR);
00269
00270
00271 gfx_draw_filled_rect(clip->origin.x + 1,
00272 clip->origin.y + slider->position + 1,
00273 area->size.x - 2,
00274 WTK_SLIDER_KNOB_WIDTH - 2, knob_color);
00275 } else {
00276 gfx_draw_rect(clip->origin.x + slider->position,
00277 clip->origin.y,
00278 WTK_SLIDER_KNOB_WIDTH,
00279 area->size.y, WTK_SLIDER_BORDER_COLOR);
00280
00281 gfx_draw_filled_rect(clip->origin.x + slider->position
00282 + 1,
00283 clip->origin.y + 1,
00284 WTK_SLIDER_KNOB_WIDTH - 2,
00285 area->size.y - 2, knob_color);
00286 }
00287
00288
00289
00290
00291 return true;
00292
00293
00294 case WIN_EVENT_POINTER:
00295
00296
00297
00298 event = (struct win_pointer_event const *)data;
00299 area = win_get_area(win);
00300 option = slider->option;
00301 send_command = false;
00302 origin = slider->root_pos;
00303
00304 switch (event->type) {
00305 case WIN_POINTER_PRESS:
00306
00307
00308
00309 if (slider->state == WTK_SLIDER_NORMAL) {
00310 slider->state = WTK_SLIDER_MOVING;
00311 win_grab_pointer(win);
00312 win_redraw(win);
00313 };
00314
00315 #if WTK_SLIDER_PARENT_MOVE_SUPPORT
00316
00317 win_translate_win_to_root(win, &slider->root_pos);
00318 #endif
00319 break;
00320
00321 case WIN_POINTER_MOVE:
00322
00323
00324
00325
00326
00327
00328 if (slider->state == WTK_SLIDER_MOVING) {
00329
00330
00331
00332
00333 if (option & WTK_SLIDER_VERTICAL) {
00334 position = event->pos.y - origin.y;
00335 length = area->size.y;
00336 } else {
00337 position = event->pos.x - origin.x;
00338 length = area->size.x;
00339 }
00340
00341
00342 position -= WTK_SLIDER_KNOB_WIDTH / 2;
00343 length -= WTK_SLIDER_KNOB_WIDTH;
00344
00345
00346
00347
00348
00349 if (position < 0) {
00350 value = 0;
00351 } else if (position > length) {
00352 value = slider->maximum;
00353 } else {
00354 value = wtk_rescale_value(position,
00355 length,
00356 slider->maximum);
00357 }
00358
00359
00360 if (slider->value != value) {
00361 slider->value = value;
00362
00363
00364
00365
00366 slider->position =
00367 wtk_rescale_value(value,
00368 slider->maximum,
00369 length);
00370
00371 if (option & WTK_SLIDER_CMD_MOVE) {
00372 send_command = true;
00373 }
00374
00375 win_redraw(win);
00376 }
00377 }
00378 break;
00379
00380 case WIN_POINTER_RELEASE:
00381
00382
00383
00384
00385
00386 if (slider->state == WTK_SLIDER_MOVING) {
00387 slider->state = WTK_SLIDER_NORMAL;
00388 win_grab_pointer(NULL);
00389 win_redraw(win);
00390
00391 if (option & WTK_SLIDER_CMD_RELEASE) {
00392 send_command = true;
00393 }
00394 }
00395 break;
00396
00397 default:
00398 break;
00399 }
00400
00401
00402 if (send_command) {
00403 command.sender = slider->container;
00404 command.recipient = slider->container;
00405 command.data = slider->command;
00406 win_queue_command_event(&command);
00407 }
00408
00409
00410
00411
00412 return true;
00413
00414 case WIN_EVENT_DESTROY:
00415
00416
00417
00418 membag_free(slider);
00419
00420
00421
00422
00423 return true;
00424
00425 default:
00426
00427 return false;
00428 }
00429 }
00430
00466 struct wtk_slider *wtk_slider_create(struct win_window *parent,
00467 struct win_area const *area, uint8_t maximum, uint8_t value,
00468 uint8_t option, win_command_t command)
00469 {
00470 struct win_attributes attr;
00471 struct wtk_slider *slider;
00472 uint8_t length;
00473
00474
00475 assert(maximum > 0);
00476 assert(area);
00477 assert(parent);
00478
00479
00480 slider = membag_alloc(sizeof(struct wtk_slider));
00481 if (!slider) {
00482 goto outofmem_slider;
00483 }
00484
00485
00486 slider->state = WTK_SLIDER_NORMAL;
00487 slider->maximum = maximum;
00488 slider->value = value;
00489 slider->option = option;
00490
00491
00492 if (option & WTK_SLIDER_INVERT) {
00493 value = maximum - value;
00494 }
00495
00496 slider->value = value;
00497
00498
00499 if (option & (WTK_SLIDER_CMD_MOVE | WTK_SLIDER_CMD_RELEASE)) {
00500 assert(command > 0);
00501 slider->command = command;
00502 }
00503
00504
00505 attr.event_handler = wtk_slider_handler;
00506 attr.custom = slider;
00507
00508
00509 attr.area = *area;
00510 assert(attr.area.size.x > 0);
00511 assert(attr.area.size.y > 0);
00512
00513 if (option & WTK_SLIDER_VERTICAL) {
00514 assert(attr.area.size.x > 3);
00515 assert(attr.area.size.x <= (uint8_t) ~ 0);
00516 assert(attr.area.size.y > WTK_SLIDER_KNOB_WIDTH);
00517 length = attr.area.size.y;
00518 } else {
00519 assert(attr.area.size.x > WTK_SLIDER_KNOB_WIDTH);
00520 assert(attr.area.size.y <= (uint8_t) ~ 0);
00521 assert(attr.area.size.y > 3);
00522 length = attr.area.size.x;
00523 }
00524
00525
00526 length -= WTK_SLIDER_KNOB_WIDTH;
00527 slider->position = wtk_rescale_value(value, maximum, length);
00528
00529
00530
00531
00532 attr.background = NULL;
00533 attr.behavior = 0;
00534
00535
00536 slider->container = win_create(parent, &attr);
00537 if (!slider->container) {
00538 goto outofmem_container;
00539 }
00540
00541
00542 win_translate_win_to_root(slider->container, &slider->root_pos);
00543 return slider;
00544
00545 outofmem_container:
00546 membag_free(slider);
00547
00548 outofmem_slider:
00549 return NULL;
00550 }
00551