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
00050
00051
00052
00053 static bool wtk_frame_handler(struct win_window *win,
00054 enum win_event_type type, void const *data);
00055 static void wtk_handle_frame_press(struct wtk_frame *frame,
00056 struct win_pointer_event const *event);
00057 static void wtk_handle_frame_move(struct wtk_frame *frame,
00058 struct win_pointer_event const *event);
00059 static void wtk_handle_frame_release(struct wtk_frame *frame,
00060 struct win_pointer_event const *event);
00061
00062 static void wtk_handle_resize_press(struct wtk_frame *frame,
00063 struct win_pointer_event const *event);
00064 static void wtk_handle_resize_move(struct wtk_frame *frame,
00065 struct win_pointer_event const *event);
00066 static void wtk_handle_resize_release(struct wtk_frame *frame,
00067 struct win_pointer_event const *event);
00068 static void wtk_resize_frame(struct wtk_frame *frame,
00069 struct win_area const *contents_area);
00070
00071 static void wtk_prepare_drag(struct win_point const *pos);
00072 static bool wtk_is_drag_threshold_exceeded(struct win_point const *pos);
00073 static void wtk_start_drag(struct win_point const *pos);
00074 static void wtk_continue_drag(struct win_point const *last_pos,
00075 struct win_point const *pos);
00076 static void wtk_stop_drag(struct win_point const *last_pos);
00077
00078 #if (WTK_FRAME_SHADESIZE > 0)
00079
00080 static void wtk_shade_frame(struct win_point const *origin,
00081 struct win_point const *size);
00082 #endif
00083
00085 static struct win_point wtk_drag_origin;
00086
00088 static gfx_color_t *wtk_drag_origin_pixmap;
00089
00091 static gfx_color_t *wtk_drag_target_pixmap;
00092
00093 #if (WTK_FRAME_SHADESIZE > 0)
00094
00095 static DEFINE_PROGMEM(uint8_t, wtk_frame_shades[WTK_FRAME_SHADESIZE]) =
00096 WTK_FRAME_SHADES;
00097 #endif
00098
00100 static struct gfx_bitmap wtk_frame_background = {
00101 .type = BITMAP_SOLID,
00102 .data.color = WTK_FRAME_BACKGROUND_COLOR,
00103 };
00104
00109 enum wtk_frame_state {
00111 WTK_FRAME_NORMAL,
00113 WTK_FRAME_AWAITING_MOVE,
00115 WTK_FRAME_MOVING,
00117 WTK_FRAME_AWAITING_RESIZE,
00119 WTK_FRAME_RESIZING
00120 };
00121
00132 struct wtk_frame {
00134 struct win_window *container;
00136 struct win_window *contents;
00138 struct win_window *resize;
00140 char *caption;
00142 enum wtk_frame_state state;
00143
00145 wtk_frame_handler_t frame_handler;
00147 void *custom_data;
00148 };
00149
00159 struct win_window *wtk_frame_as_parent(struct wtk_frame *frame)
00160 {
00161 assert(frame);
00162 return frame->contents;
00163 }
00164
00173 struct win_window *wtk_frame_as_child(struct wtk_frame *frame)
00174 {
00175 assert(frame);
00176 return frame->container;
00177 }
00178
00187 void *wtk_frame_get_custom_data(struct wtk_frame const *frame)
00188 {
00189 assert(frame);
00190 return frame->custom_data;
00191 }
00192
00201 static void wtk_handle_frame_press(struct wtk_frame *frame,
00202 struct win_pointer_event const *event)
00203 {
00204 switch (frame->state) {
00205
00206 case WTK_FRAME_NORMAL:
00207 wtk_prepare_drag(&(event->pos));
00208 win_grab_pointer(frame->container);
00209
00210 frame->state = WTK_FRAME_AWAITING_MOVE;
00211 break;
00212
00213 default:
00214 break;
00215 }
00216 }
00217
00227 static void wtk_handle_frame_move(struct wtk_frame *frame,
00228 struct win_pointer_event const *event)
00229 {
00230 switch (frame->state) {
00231
00232
00233
00234 case WTK_FRAME_AWAITING_MOVE:
00235 if (wtk_is_drag_threshold_exceeded(&(event->pos))) {
00236 wtk_start_drag(&(event->pos));
00237 frame->state = WTK_FRAME_MOVING;
00238 }
00239 break;
00240
00241
00242 case WTK_FRAME_MOVING:
00243 wtk_continue_drag(&(event->last_pos), &(event->pos));
00244 break;
00245
00246 default:
00247 break;
00248 }
00249 }
00250
00260 static void wtk_handle_frame_release(struct wtk_frame *frame,
00261 struct win_pointer_event const *event)
00262 {
00263 bool is_inside;
00264
00265 switch (frame->state) {
00266
00267
00268
00269 case WTK_FRAME_MOVING:
00270
00271 wtk_stop_drag(&(event->last_pos));
00272 win_grab_pointer(NULL);
00273 frame->state = WTK_FRAME_NORMAL;
00274
00275
00276 is_inside = win_is_inside_window(win_get_parent(frame->
00277 container), &(event->pos));
00278
00279
00280 if (is_inside) {
00281 struct win_area area = *win_get_area(frame->container);
00282 area.pos.x += event->pos.x - wtk_drag_origin.x;
00283 area.pos.y += event->pos.y - wtk_drag_origin.y;
00284 win_set_area(frame->container, &area,
00285 WIN_ATTR_POSITION);
00286 }
00287 break;
00288
00289 default:
00290 break;
00291 }
00292 }
00293
00302 static void wtk_handle_resize_press(struct wtk_frame *frame,
00303 struct win_pointer_event const *event)
00304 {
00305 switch (frame->state) {
00306
00307 case WTK_FRAME_NORMAL:
00308 wtk_prepare_drag(&(event->pos));
00309 win_grab_pointer(frame->resize);
00310
00311 frame->state = WTK_FRAME_AWAITING_RESIZE;
00312 break;
00313
00314 default:
00315 break;
00316 }
00317 }
00318
00328 static void wtk_handle_resize_move(struct wtk_frame *frame,
00329 struct win_pointer_event const *event)
00330 {
00331 switch (frame->state) {
00332
00333
00334
00335 case WTK_FRAME_AWAITING_RESIZE:
00336 if (wtk_is_drag_threshold_exceeded(&(event->pos))) {
00337 wtk_start_drag(&(event->pos));
00338 frame->state = WTK_FRAME_RESIZING;
00339 }
00340 break;
00341
00342
00343 case WTK_FRAME_RESIZING:
00344 wtk_continue_drag(&(event->last_pos), &(event->pos));
00345 break;
00346
00347 default:
00348 break;
00349 }
00350 }
00351
00361 static void wtk_handle_resize_release(struct wtk_frame *frame,
00362 struct win_pointer_event const *event)
00363 {
00364 bool is_inside;
00365
00366 switch (frame->state) {
00367
00368
00369
00370 case WTK_FRAME_RESIZING:
00371
00372 wtk_stop_drag(&(event->last_pos));
00373 win_grab_pointer(NULL);
00374 frame->state = WTK_FRAME_NORMAL;
00375
00376
00377 is_inside = win_is_inside_window(win_get_parent(frame->
00378 container), &(event->pos));
00379
00380
00381 if (is_inside) {
00382 struct win_area contents_area =
00383 *win_get_area(frame->contents);
00384
00385 contents_area.size.x += event->pos.x - wtk_drag_origin.x;
00386 contents_area.size.y += event->pos.y - wtk_drag_origin.y;
00387
00388 wtk_resize_frame(frame, &contents_area);
00389 }
00390
00391 break;
00392
00393 default:
00394 break;
00395 }
00396 }
00397
00407 static void wtk_resize_frame(struct wtk_frame *frame,
00408 struct win_area const *contents_area)
00409 {
00410 struct win_area container_area;
00411
00412 struct win_area area = *contents_area;
00413
00414
00415 if (area.size.x < WTK_FRAME_MIN_WIDTH) {
00416 area.size.x = WTK_FRAME_MIN_WIDTH;
00417 }
00418
00419 if (area.size.y < WTK_FRAME_MIN_HEIGHT) {
00420 area.size.y = WTK_FRAME_MIN_HEIGHT;
00421 }
00422
00423
00424 win_set_area(frame->contents, &area, WIN_ATTR_SIZE);
00425
00426
00427
00428
00429 area = *win_get_area(frame->contents);
00430
00431
00432
00433
00434 container_area = *win_get_area(frame->container);
00435
00436 container_area.size.x = area.size.x +
00437 WTK_FRAME_SHADESIZE + WTK_FRAME_LEFTBORDER +
00438 WTK_FRAME_RIGHTBORDER + WTK_FRAME_SHADESIZE;
00439
00440 container_area.size.y = area.size.y +
00441 WTK_FRAME_TOPBORDER + WTK_FRAME_TITLEBAR_HEIGHT +
00442 WTK_FRAME_BOTTOMBORDER + WTK_FRAME_SHADESIZE;
00443
00444 win_set_area(frame->container, &container_area, WIN_ATTR_SIZE);
00445
00446 if (frame->resize) {
00447
00448
00449
00450
00451 struct win_area resize_area = *win_get_area(frame->resize);
00452
00453 resize_area.pos.x = container_area.size.x -
00454 WTK_FRAME_SHADESIZE - WTK_FRAME_RESIZE_WIDTH;
00455
00456 resize_area.pos.y = container_area.size.y -
00457 WTK_FRAME_SHADESIZE - WTK_FRAME_RESIZE_HEIGHT;
00458
00459 win_set_area(frame->resize, &resize_area, WIN_ATTR_POSITION);
00460 }
00461 }
00462
00471 static void wtk_prepare_drag(struct win_point const *pos)
00472 {
00473
00474
00475
00476 wtk_drag_origin = *pos;
00477 }
00478
00489 static bool wtk_is_drag_threshold_exceeded(struct win_point const *pos)
00490 {
00491 bool isExceeded =
00492 (pos->x < (wtk_drag_origin.x - WTK_DRAG_THRESHOLD)) ||
00493 (pos->x > (wtk_drag_origin.x + WTK_DRAG_THRESHOLD)) ||
00494 (pos->y < (wtk_drag_origin.y - WTK_DRAG_THRESHOLD)) ||
00495 (pos->y > (wtk_drag_origin.y + WTK_DRAG_THRESHOLD));
00496
00497 return isExceeded;
00498 }
00499
00510 static void wtk_start_drag(struct win_point const *pos)
00511 {
00512
00513 wtk_drag_origin_pixmap = membag_alloc(
00514 (WTK_DRAG_PIXMAP_SIZE * WTK_DRAG_PIXMAP_SIZE) *
00515 sizeof(gfx_color_t)
00516 );
00517 if (!wtk_drag_origin_pixmap) {
00518 goto outofmem_origin;
00519 }
00520
00521 wtk_drag_target_pixmap = membag_alloc(
00522 (WTK_DRAG_PIXMAP_SIZE * WTK_DRAG_PIXMAP_SIZE) *
00523 sizeof(gfx_color_t)
00524 );
00525 if (!wtk_drag_target_pixmap) {
00526 goto outofmem_target;
00527 }
00528
00529
00530
00531
00532 gfx_set_clipping(0, 0, gfx_get_width() - 1, gfx_get_height() - 1);
00533
00534
00535 gfx_get_pixmap(wtk_drag_origin_pixmap, WTK_DRAG_PIXMAP_SIZE, 0, 0,
00536 wtk_drag_origin.x - WTK_DRAG_HANDLE_RADIUS,
00537 wtk_drag_origin.y - WTK_DRAG_HANDLE_RADIUS,
00538 WTK_DRAG_PIXMAP_SIZE, WTK_DRAG_PIXMAP_SIZE);
00539
00540 gfx_draw_filled_circle(wtk_drag_origin.x, wtk_drag_origin.y,
00541 WTK_DRAG_HANDLE_RADIUS,
00542 WTK_DRAG_ORIGIN_COLOR, GFX_WHOLE);
00543
00544
00545 gfx_get_pixmap(wtk_drag_target_pixmap, WTK_DRAG_PIXMAP_SIZE, 0, 0,
00546 pos->x - WTK_DRAG_HANDLE_RADIUS,
00547 pos->y - WTK_DRAG_HANDLE_RADIUS,
00548 WTK_DRAG_PIXMAP_SIZE, WTK_DRAG_PIXMAP_SIZE);
00549
00550 gfx_draw_filled_circle(pos->x, pos->y,
00551 WTK_DRAG_HANDLE_RADIUS,
00552 WTK_DRAG_TARGET_COLOR, GFX_WHOLE);
00553
00554 return;
00555
00556 outofmem_target:
00557 membag_free(wtk_drag_origin_pixmap);
00558 wtk_drag_origin_pixmap = NULL;
00559
00560 outofmem_origin:
00561 return;
00562 }
00563
00575 static void wtk_continue_drag(struct win_point const *last_pos,
00576 struct win_point const *pos)
00577 {
00578
00579 if (!wtk_drag_origin_pixmap || !wtk_drag_target_pixmap) {
00580 return;
00581 }
00582
00583
00584
00585
00586 gfx_set_clipping(0, 0, gfx_get_width() - 1, gfx_get_height() - 1);
00587
00588
00589 gfx_put_pixmap(wtk_drag_target_pixmap, WTK_DRAG_PIXMAP_SIZE, 0, 0,
00590 last_pos->x - WTK_DRAG_HANDLE_RADIUS,
00591 last_pos->y - WTK_DRAG_HANDLE_RADIUS,
00592 WTK_DRAG_PIXMAP_SIZE, WTK_DRAG_PIXMAP_SIZE);
00593
00594
00595 gfx_get_pixmap(wtk_drag_target_pixmap, WTK_DRAG_PIXMAP_SIZE, 0, 0,
00596 pos->x - WTK_DRAG_HANDLE_RADIUS,
00597 pos->y - WTK_DRAG_HANDLE_RADIUS,
00598 WTK_DRAG_PIXMAP_SIZE, WTK_DRAG_PIXMAP_SIZE);
00599
00600 gfx_draw_filled_circle(pos->x, pos->y,
00601 WTK_DRAG_HANDLE_RADIUS,
00602 WTK_DRAG_TARGET_COLOR, GFX_WHOLE);
00603 }
00604
00612 static void wtk_stop_drag(struct win_point const *last_pos)
00613 {
00614
00615 if (!wtk_drag_origin_pixmap || !wtk_drag_target_pixmap) {
00616 return;
00617 }
00618
00619
00620
00621
00622 gfx_set_clipping(0, 0, gfx_get_width() - 1, gfx_get_height() - 1);
00623
00624
00625 gfx_put_pixmap(wtk_drag_origin_pixmap, WTK_DRAG_PIXMAP_SIZE, 0, 0,
00626 wtk_drag_origin.x - WTK_DRAG_HANDLE_RADIUS,
00627 wtk_drag_origin.y - WTK_DRAG_HANDLE_RADIUS,
00628 WTK_DRAG_PIXMAP_SIZE, WTK_DRAG_PIXMAP_SIZE);
00629
00630
00631 gfx_put_pixmap(wtk_drag_target_pixmap, WTK_DRAG_PIXMAP_SIZE, 0, 0,
00632 last_pos->x - WTK_DRAG_HANDLE_RADIUS,
00633 last_pos->y - WTK_DRAG_HANDLE_RADIUS,
00634 WTK_DRAG_PIXMAP_SIZE, WTK_DRAG_PIXMAP_SIZE);
00635
00636
00637 membag_free(wtk_drag_origin_pixmap);
00638 membag_free(wtk_drag_target_pixmap);
00639 }
00640
00641 #if (WTK_FRAME_SHADESIZE > 0)
00642
00652 static void wtk_shade_frame(struct win_point const *origin,
00653 struct win_point const *size)
00654 {
00655
00656
00657
00658
00659
00660
00661
00662
00663
00664
00665
00666
00667
00668
00669
00670
00671
00672
00673
00674
00675
00676
00677
00678
00679
00680
00681 gfx_color_t *pixmap = membag_alloc((size->x - 2) * sizeof(gfx_color_t));
00682 if (!pixmap) {
00683 return;
00684 }
00685
00686
00687 for (gfx_coord_t i = 0; i < WTK_FRAME_SHADESIZE; ++i) {
00688 gfx_coord_t length = size->x - 2 - (i * 2);
00689 uint8_t alpha = progmem_read8(wtk_frame_shades + i);
00690 uint16_t idx;
00691
00692
00693 gfx_get_pixmap(pixmap, length, 0, 0, origin->x + 1 + i,
00694 origin->y + size->y - 1 - i, length, 1);
00695
00696
00697 for (idx = 0; idx < length; ++idx) {
00698 wtk_shade_pixel(pixmap + idx, alpha);
00699 }
00700
00701
00702 gfx_put_pixmap(pixmap, length, 0, 0, origin->x + 1 + i,
00703 origin->y + size->y - 1 - i, length, 1);
00704 }
00705
00706
00707 membag_free(pixmap);
00708
00709
00710 pixmap = membag_alloc((size->y - WTK_FRAME_SHADESIZE) *
00711 sizeof(gfx_color_t));
00712 if (!pixmap) {
00713 return;
00714 }
00715
00716
00717 for (gfx_coord_t i = 0; i < WTK_FRAME_SHADESIZE; ++i) {
00718 gfx_coord_t length = size->y - WTK_FRAME_SHADESIZE;
00719 uint8_t alpha = progmem_read8(wtk_frame_shades + i);
00720 uint16_t idx;
00721
00722
00723 gfx_get_pixmap(pixmap, 1, 0, 0, origin->x + i,
00724 origin->y + WTK_FRAME_SHADESIZE - i, 1, length);
00725
00726
00727 for (idx = 0; idx < length; ++idx) {
00728 wtk_shade_pixel(pixmap + idx, alpha);
00729 }
00730
00731
00732 gfx_put_pixmap(pixmap, 1, 0, 0, origin->x + i,
00733 origin->y + WTK_FRAME_SHADESIZE - i, 1, length);
00734
00735
00736 gfx_get_pixmap(pixmap, 1, 0, 0, origin->x + size->x - 1 - i,
00737 origin->y + WTK_FRAME_SHADESIZE - i, 1, length);
00738
00739
00740 for (idx = 0; idx < length; ++idx) {
00741 wtk_shade_pixel(pixmap + idx, alpha);
00742 }
00743
00744
00745 gfx_put_pixmap(pixmap, 1, 0, 0, origin->x + size->x - 1 - i,
00746 origin->y + WTK_FRAME_SHADESIZE - i, 1, length);
00747 }
00748
00749
00750 membag_free(pixmap);
00751 }
00752 #endif
00753
00764 static bool wtk_frame_handler(struct win_window *win,
00765 enum win_event_type type, void const *data)
00766 {
00767
00768 struct wtk_frame *frame = (struct wtk_frame *)win_get_custom_data(win);
00769
00770 switch (type) {
00771 case WIN_EVENT_DRAW:
00772 {
00773
00774
00775
00776 struct win_clip_region const *clip =
00777 (struct win_clip_region const *)data;
00778
00779 struct win_area const *area = win_get_area(win);
00780
00781
00782 if (win == frame->container) {
00783
00784 gfx_draw_filled_rect(clip->origin.x +
00785 WTK_FRAME_SHADESIZE,
00786 clip->origin.y,
00787 WTK_FRAME_LEFTBORDER,
00788 area->size.y -
00789 WTK_FRAME_SHADESIZE,
00790 WTK_FRAME_BORDER_COLOR);
00791
00792
00793 gfx_draw_filled_rect(clip->origin.x +
00794 area->size.x -
00795 WTK_FRAME_SHADESIZE -
00796 WTK_FRAME_RIGHTBORDER,
00797 clip->origin.y,
00798 WTK_FRAME_RIGHTBORDER,
00799 area->size.y -
00800 WTK_FRAME_SHADESIZE,
00801 WTK_FRAME_BORDER_COLOR);
00802
00803
00804 gfx_draw_filled_rect(clip->origin.x +
00805 WTK_FRAME_SHADESIZE +
00806 WTK_FRAME_LEFTBORDER,
00807 clip->origin.y,
00808 area->size.x -
00809 (WTK_FRAME_SHADESIZE * 2) -
00810 WTK_FRAME_LEFTBORDER -
00811 WTK_FRAME_RIGHTBORDER,
00812 WTK_FRAME_TOPBORDER,
00813 WTK_FRAME_BORDER_COLOR);
00814
00815
00816 gfx_draw_filled_rect(clip->origin.x +
00817 WTK_FRAME_SHADESIZE +
00818 WTK_FRAME_LEFTBORDER,
00819 clip->origin.y + area->size.y -
00820 WTK_FRAME_SHADESIZE -
00821 WTK_FRAME_BOTTOMBORDER,
00822 area->size.x -
00823 (WTK_FRAME_SHADESIZE * 2) -
00824 WTK_FRAME_LEFTBORDER -
00825 WTK_FRAME_RIGHTBORDER,
00826 WTK_FRAME_BOTTOMBORDER,
00827 WTK_FRAME_BORDER_COLOR);
00828
00829
00830 gfx_draw_filled_rect(clip->origin.x +
00831 WTK_FRAME_SHADESIZE +
00832 WTK_FRAME_LEFTBORDER,
00833 clip->origin.y +
00834 WTK_FRAME_TOPBORDER,
00835 area->size.x -
00836 WTK_FRAME_LEFTBORDER -
00837 WTK_FRAME_RIGHTBORDER -
00838 (WTK_FRAME_SHADESIZE * 2),
00839 WTK_FRAME_TITLEBAR_HEIGHT,
00840 WTK_FRAME_TITLEBAR_COLOR);
00841
00842
00843 gfx_draw_string(frame->caption,
00844 clip->origin.x +
00845 WTK_FRAME_SHADESIZE +
00846 WTK_FRAME_LEFTBORDER +
00847 WTK_FRAME_CAPTION_X,
00848 clip->origin.y +
00849 WTK_FRAME_TOPBORDER +
00850 WTK_FRAME_CAPTION_Y, &sysfont,
00851 WTK_FRAME_CAPTION_COLOR,
00852 GFX_COLOR_TRANSPARENT);
00853
00854 #if (WTK_FRAME_SHADESIZE > 0)
00855
00856 wtk_shade_frame(&(clip->origin), &(area->size));
00857 #endif
00858 }
00859
00860 else if (win == frame->resize) {
00861 gfx_draw_filled_circle(clip->origin.x +
00862 area->size.x - 1,
00863 clip->origin.y + area->size.y -
00864 1, WTK_FRAME_RESIZE_RADIUS,
00865 WTK_FRAME_RESIZE_COLOR,
00866 GFX_QUADRANT1);
00867 }
00868
00869
00870
00871
00872 return true;
00873 }
00874
00875 case WIN_EVENT_POINTER:
00876 {
00877
00878
00879
00880 struct win_pointer_event const *event =
00881 (struct win_pointer_event const *)data;
00882
00883
00884 if (win == frame->container) {
00885 switch (event->type) {
00886
00887 case WIN_POINTER_PRESS:
00888 wtk_handle_frame_press(frame, event);
00889 break;
00890
00891 case WIN_POINTER_MOVE:
00892 wtk_handle_frame_move(frame, event);
00893 break;
00894
00895 case WIN_POINTER_RELEASE:
00896 wtk_handle_frame_release(frame, event);
00897 break;
00898
00899 default:
00900 break;
00901 }
00902 }
00903
00904 else if (win == frame->resize) {
00905 switch (event->type) {
00906
00907 case WIN_POINTER_PRESS:
00908 wtk_handle_resize_press(frame, event);
00909 break;
00910
00911 case WIN_POINTER_MOVE:
00912 wtk_handle_resize_move(frame, event);
00913 break;
00914
00915 case WIN_POINTER_RELEASE:
00916 wtk_handle_resize_release(frame, event);
00917 break;
00918
00919 default:
00920 break;
00921 }
00922 }
00923
00924
00925
00926
00927 return true;
00928 }
00929
00930 case WIN_EVENT_DESTROY:
00931 {
00932
00933
00934
00935 if (win == frame->container) {
00936
00937
00938
00939
00940 membag_free(frame->caption);
00941 membag_free(frame);
00942 }
00943
00944
00945
00946
00947 return true;
00948 }
00949
00950 case WIN_EVENT_COMMAND:
00951 {
00952
00953
00954
00955
00956 if (win == frame->container) {
00957 if (frame->frame_handler) {
00958
00959
00960
00961
00962
00963 bool shouldDestroy =
00964 frame->frame_handler(frame,
00965 (win_command_t)
00966 data);
00967
00968
00969
00970
00971
00972
00973
00974 if (shouldDestroy) {
00975 win_destroy(frame->container);
00976 }
00977
00978
00979
00980
00981 return true;
00982 }
00983 }
00984
00985
00986
00987
00988 return false;
00989 }
00990
00991 default:
00992
00993 return false;
00994
00995 }
00996 }
00997
01018 struct wtk_frame *wtk_frame_create(struct win_window *parent,
01019 struct win_area const *area,
01020 char const *caption,
01021 bool allow_resize,
01022 wtk_frame_handler_t frame_handler, void *custom_data)
01023 {
01024 struct win_attributes attr;
01025 struct wtk_frame *frame;
01026
01027 assert(area);
01028 assert(caption);
01029 assert(parent);
01030
01031
01032 frame = membag_alloc(sizeof(struct wtk_frame));
01033 if (!frame) {
01034 goto outofmem_frame;
01035 }
01036
01037 frame->state = WTK_FRAME_NORMAL;
01038 frame->frame_handler = frame_handler;
01039 frame->custom_data = custom_data;
01040
01041
01042 frame->caption = membag_alloc((strlen(caption) + 1) * sizeof(char));
01043 if (!frame->caption) {
01044 goto outofmem_caption;
01045 }
01046
01047 wtk_copy_string(frame->caption, caption);
01048
01049
01050
01051
01052
01053
01054 attr.area = *area;
01055 attr.event_handler = wtk_frame_handler;
01056 attr.custom = frame;
01057
01058
01059
01060
01061 attr.background = NULL;
01062 #if (WTK_FRAME_SHADESIZE == 0)
01063 attr.behavior = WIN_BEHAVIOR_RAISE_ON_PRESS;
01064 #else
01065 attr.behavior = WIN_BEHAVIOR_RAISE_ON_PRESS |
01066 WIN_BEHAVIOR_REDRAW_PARENT;
01067 #endif
01068
01069
01070 frame->container = win_create(parent, &attr);
01071 if (!frame->container) {
01072 goto outofmem_container;
01073 }
01074
01075
01076
01077
01078 attr.area.pos.x = WTK_FRAME_SHADESIZE + WTK_FRAME_LEFTBORDER;
01079 attr.area.pos.y = WTK_FRAME_TOPBORDER + WTK_FRAME_TITLEBAR_HEIGHT;
01080 attr.background = &wtk_frame_background;
01081 attr.behavior = 0;
01082
01083 frame->contents = win_create(frame->container, &attr);
01084 if (!frame->contents) {
01085 goto outofmem_contents;
01086 }
01087
01088
01089 if (allow_resize) {
01090
01091
01092
01093 attr.area.size.x = WTK_FRAME_RESIZE_WIDTH;
01094 attr.area.size.y = WTK_FRAME_RESIZE_HEIGHT;
01095 attr.background = NULL;
01096 attr.behavior = 0;
01097
01098 frame->resize = win_create(frame->container, &attr);
01099 if (!frame->resize) {
01100 goto outofmem_resize;
01101 }
01102
01103 win_show(frame->resize);
01104 } else {
01105 frame->resize = NULL;
01106 }
01107
01108
01109
01110
01111 wtk_resize_frame(frame, area);
01112
01113
01114 win_show(frame->contents);
01115
01116 return frame;
01117
01118 outofmem_resize:
01119 win_destroy(frame->contents);
01120
01121 outofmem_contents:
01122 win_destroy(frame->container);
01123
01124 outofmem_container:
01125 membag_free(frame->caption);
01126
01127 outofmem_caption:
01128 membag_free(frame);
01129
01130 outofmem_frame:
01131 return NULL;
01132 }
01133