From d615692585c59eab2cbfaf207a063323b08c79d4 Mon Sep 17 00:00:00 2001
From: Mooffie <mooffie@gmail.com>
Date: Fri, 26 Feb 2016 16:31:02 +0200
Subject: [PATCH] Make it possible to drag dialogs.
---
lib/widget/dialog.c | 107 +++++++++++++++++++++++++++++++++++++++++++++++++++-
lib/widget/dialog.h | 6 ++-
2 files changed, 111 insertions(+), 2 deletions(-)
diff --git a/lib/widget/dialog.c b/lib/widget/dialog.c
index a53c046..96108f6 100644
a
|
b
|
|
41 | 41 | #include "lib/tty/key.h" |
42 | 42 | #include "lib/strutil.h" |
43 | 43 | #include "lib/widget.h" |
| 44 | #include "lib/widget/mouse.h" |
44 | 45 | #include "lib/fileloc.h" /* MC_HISTORY_FILE */ |
45 | 46 | #include "lib/event.h" /* mc_event_raise() */ |
46 | 47 | |
… |
… |
dlg_handle_key (WDialog * h, int d_key) |
355 | 356 | return MSG_NOT_HANDLED; |
356 | 357 | } |
357 | 358 | |
| 359 | |
358 | 360 | /* --------------------------------------------------------------------------------------------- */ |
359 | 361 | |
360 | 362 | static int |
361 | 363 | dlg_mouse_event (WDialog * h, Gpm_Event * event) |
362 | 364 | { |
363 | 365 | Widget *wh = WIDGET (h); |
| 366 | gboolean mouse_post_processing = ((h->flags & DLG_MOUSE_POST_PROCESSING) != 0); |
364 | 367 | |
365 | 368 | GList *p, *first; |
366 | 369 | |
… |
… |
dlg_mouse_event (WDialog * h, Gpm_Event * event) |
373 | 376 | return MOU_NORMAL; |
374 | 377 | } |
375 | 378 | |
376 | | if (wh->mouse != NULL) |
| 379 | if (!mouse_post_processing && wh->mouse != NULL) |
377 | 380 | { |
378 | 381 | int mou; |
379 | 382 | |
… |
… |
dlg_mouse_event (WDialog * h, Gpm_Event * event) |
403 | 406 | } |
404 | 407 | while (p != first); |
405 | 408 | |
| 409 | if (mouse_post_processing && wh->mouse != NULL) |
| 410 | { |
| 411 | int mou; |
| 412 | |
| 413 | mou = wh->mouse (event, wh); |
| 414 | if (mou != MOU_UNHANDLED) |
| 415 | return mou; |
| 416 | } |
| 417 | |
406 | 418 | return MOU_UNHANDLED; |
407 | 419 | } |
408 | 420 | |
… |
… |
dlg_default_repaint (WDialog * h) |
604 | 616 | |
605 | 617 | tty_setcolor (h->color[DLG_COLOR_NORMAL]); |
606 | 618 | dlg_erase (h); |
| 619 | if (h->is_dragging) |
| 620 | { |
| 621 | /* Give feedback to the user when dragging. |
| 622 | * |
| 623 | * @FIXME: Have skins define a dedicated color for dragging. We pick |
| 624 | * 'dtitle' because there doesn't seem to be something better. |
| 625 | * @TODO: Make WHLine too use this color (when owner is dragged). */ |
| 626 | tty_setcolor (h->color[DLG_COLOR_TITLE]); |
| 627 | } |
607 | 628 | tty_draw_box (wh->y + space, wh->x + space, wh->lines - 2 * space, wh->cols - 2 * space, FALSE); |
608 | 629 | |
609 | 630 | if (h->title != NULL) |
… |
… |
dlg_default_callback (Widget * w, Widget * sender, widget_msg_t msg, int parm, v |
769 | 790 | } |
770 | 791 | |
771 | 792 | /* --------------------------------------------------------------------------------------------- */ |
| 793 | /** |
| 794 | * Default dialog mouse callback |
| 795 | * |
| 796 | * It lets you drag the dialog by dragging any "empty" space in it (any space |
| 797 | * that doesn't respond to the mouse, to be exact). |
| 798 | */ |
| 799 | |
| 800 | static void |
| 801 | dlg_default_mouse_callback (Widget * w, mouse_msg_t msg, mouse_event_t * event) |
| 802 | { |
| 803 | WDialog *h = DIALOG (w); |
| 804 | static int drag_start_x, drag_start_y; |
| 805 | |
| 806 | if (!h->fullscreen) |
| 807 | { |
| 808 | switch (msg) |
| 809 | { |
| 810 | case MSG_MOUSE_DOWN: |
| 811 | h->is_dragging = TRUE; |
| 812 | drag_start_x = event->x; |
| 813 | drag_start_y = event->y; |
| 814 | /* Update the dialog frame (and, in future, HLines) so user sees feedback: */ |
| 815 | do_refresh (); /* FIXME: why doesn't `widget_redraw (w)` work? No need to paint the whole screen. */ |
| 816 | break; |
| 817 | case MSG_MOUSE_UP: |
| 818 | h->is_dragging = FALSE; |
| 819 | /* Update the dialog frame: */ |
| 820 | do_refresh (); |
| 821 | break; |
| 822 | case MSG_MOUSE_DRAG: |
| 823 | /* The is_idle() check isn't mandatory. It just prevents sluggish |
| 824 | * drag when the dialogs beneath are CPU-intensive to draw. */ |
| 825 | if (is_idle ()) |
| 826 | { |
| 827 | dlg_move (h, w->x + (event->x - drag_start_x), w->y + (event->y - drag_start_y)); |
| 828 | do_refresh (); /* Draw the whole screen. */ |
| 829 | } |
| 830 | break; |
| 831 | default: |
| 832 | break; |
| 833 | } |
| 834 | } |
| 835 | } |
| 836 | |
| 837 | /* --------------------------------------------------------------------------------------------- */ |
772 | 838 | |
773 | 839 | WDialog * |
774 | 840 | dlg_create (gboolean modal, int y1, int x1, int lines, int cols, |
… |
… |
dlg_create (gboolean modal, int y1, int x1, int lines, int cols, |
784 | 850 | mouse_handler); |
785 | 851 | widget_want_cursor (w, FALSE); |
786 | 852 | |
| 853 | if (mouse_handler == NULL) |
| 854 | { |
| 855 | set_easy_mouse_callback (w, dlg_default_mouse_callback); |
| 856 | flags |= DLG_MOUSE_POST_PROCESSING; |
| 857 | } |
| 858 | |
787 | 859 | new_d->state = DLG_CONSTRUCT; |
788 | 860 | new_d->modal = modal; |
789 | 861 | new_d->color = colors; |
790 | 862 | new_d->help_ctx = help_ctx; |
791 | 863 | new_d->flags = flags; |
| 864 | new_d->is_dragging = FALSE; |
792 | 865 | new_d->data = NULL; |
793 | 866 | |
794 | 867 | dlg_set_size (new_d, lines, cols); |
… |
… |
dlg_destroy (WDialog * h) |
1289 | 1362 | /* --------------------------------------------------------------------------------------------- */ |
1290 | 1363 | |
1291 | 1364 | /** |
| 1365 | * Moves a dialog to (x, y). |
| 1366 | * |
| 1367 | * We need to traverse the child widgets as well because their coordinates |
| 1368 | * are in aboslute screen coordinates. |
| 1369 | */ |
| 1370 | void |
| 1371 | dlg_move (WDialog * h, int x, int y) |
| 1372 | { |
| 1373 | Widget *wh = WIDGET (h); |
| 1374 | int dx, dy; |
| 1375 | |
| 1376 | dx = x - wh->x; |
| 1377 | dy = y - wh->y; |
| 1378 | |
| 1379 | wh->x = x; |
| 1380 | wh->y = y; |
| 1381 | |
| 1382 | { |
| 1383 | GList *w; |
| 1384 | |
| 1385 | for (w = h->widgets; w != NULL; w = g_list_next (w)) |
| 1386 | { |
| 1387 | /* FIXME: exclude the WButtonBar (as in the Help dialog). */ |
| 1388 | WIDGET (w->data)->x += dx; |
| 1389 | WIDGET (w->data)->y += dy; |
| 1390 | } |
| 1391 | } |
| 1392 | } |
| 1393 | |
| 1394 | /* --------------------------------------------------------------------------------------------- */ |
| 1395 | |
| 1396 | /** |
1292 | 1397 | * Write history to the ${XDG_CACHE_HOME}/mc/history file |
1293 | 1398 | */ |
1294 | 1399 | void |
diff --git a/lib/widget/dialog.h b/lib/widget/dialog.h
index 789e5e2..6d886af 100644
a
|
b
|
typedef enum |
37 | 37 | DLG_CENTER = (1 << 0), /* Center the dialog */ |
38 | 38 | DLG_TRYUP = (1 << 1), /* Try to move two lines up the dialog */ |
39 | 39 | DLG_COMPACT = (1 << 2), /* Suppress spaces around the frame */ |
40 | | DLG_WANT_TAB = (1 << 3) /* Should the tab key be sent to the dialog? */ |
| 40 | DLG_WANT_TAB = (1 << 3), /* Should the tab key be sent to the dialog? */ |
| 41 | DLG_MOUSE_POST_PROCESSING = (1 << 4) /* Whether mouse events are handed to the dialog *after* child widgets see them (instead of before). */ |
41 | 42 | } dlg_flags_t; |
42 | 43 | |
43 | 44 | /* Dialog state */ |
… |
… |
struct WDialog |
94 | 95 | dlg_state_t state; |
95 | 96 | gboolean fullscreen; /* Parents dialogs don't need refresh */ |
96 | 97 | gboolean winch_pending; /* SIGWINCH signal has been got. Resize dialog after rise */ |
| 98 | gboolean is_dragging; /* Whether the dialog is being dragged. */ |
97 | 99 | int mouse_status; /* For the autorepeat status of the mouse */ |
98 | 100 | |
99 | 101 | /* Internal variables */ |
… |
… |
char *dlg_get_title (const WDialog * h, size_t len); |
157 | 159 | |
158 | 160 | void dlg_redraw (WDialog * h); |
159 | 161 | |
| 162 | void dlg_move (WDialog * h, int x, int y); |
| 163 | |
160 | 164 | void dlg_broadcast_msg (WDialog * h, widget_msg_t message); |
161 | 165 | |
162 | 166 | /* Default callback for dialogs */ |