UI: change tool-tips to be stored in the screen
authorCampbell Barton <ideasman42@gmail.com>
Thu, 25 Jan 2018 05:17:25 +0000 (16:17 +1100)
committerCampbell Barton <ideasman42@gmail.com>
Thu, 25 Jan 2018 05:22:21 +0000 (16:22 +1100)
Move timer and tip out of button code,
now the only requests a tooltip,
passing a creation callback to run.

Needed for manipulators in 2.8,
also helps de-duplicate logic - since we never want
multiple tool-tips showing at once.

source/blender/blenkernel/intern/screen.c
source/blender/blenloader/intern/readfile.c
source/blender/editors/include/UI_interface.h
source/blender/editors/interface/interface_handlers.c
source/blender/editors/interface/interface_region_tooltip.c
source/blender/makesdna/DNA_screen_types.h
source/blender/windowmanager/CMakeLists.txt
source/blender/windowmanager/WM_api.h
source/blender/windowmanager/WM_types.h
source/blender/windowmanager/intern/wm_event_system.c
source/blender/windowmanager/intern/wm_tooltip.c [new file with mode: 0644]

index df47b89fadcb8aa3f9ec28588433896c69584758..78caf1fe1f3996ea44a4fb43182664e137300d8d 100644 (file)
@@ -381,6 +381,9 @@ void BKE_screen_free(bScreen *sc)
        BLI_freelistN(&sc->vertbase);
        BLI_freelistN(&sc->edgebase);
        BLI_freelistN(&sc->areabase);
+
+       /* Region and timer are freed by the window manager. */
+       MEM_SAFE_FREE(sc->tool_tip);
 }
 
 /* for depsgraph */
index 775eafb8fe26db1142ec9baf292eeb5cbc3ce869..4c1beb78bbfadf1cb8bb311720e607cfea93d5dd 100644 (file)
@@ -6410,6 +6410,7 @@ static void lib_link_screen(FileData *fd, Main *main)
                                sc->scene = main->scene.first;
 
                        sc->animtimer = NULL; /* saved in rare cases */
+                       sc->tool_tip = NULL;
                        sc->scrubbing = false;
                        
                        for (ScrArea *sa = sc->areabase.first; sa; sa = sa->next) {
index c07fa2913b6c8f25dcd09d12075cbdaaff431946..d6c6f0a2eb691ed8dd9cd97f806ca6b885f1ed13 100644 (file)
@@ -1081,6 +1081,8 @@ void UI_context_active_but_prop_get_templateID(
         struct bContext *C,
         struct PointerRNA *r_ptr, struct PropertyRNA **r_prop);
 
+uiBut *UI_region_active_but_get(struct ARegion *ar);
+
 /* Styled text draw */
 void UI_fontstyle_set(const struct uiFontStyle *fs);
 void UI_fontstyle_draw_ex(
@@ -1124,7 +1126,7 @@ void UI_butstore_unregister(uiButStore *bs_handle, uiBut **but_p);
 
 /* ui_interface_region_tooltip.c */
 struct ARegion *UI_tooltip_create_from_button(struct bContext *C, struct ARegion *butregion, uiBut *but);
-void UI_tooltip_free(struct bContext *C, struct ARegion *ar);
+void UI_tooltip_free(struct bContext *C, struct bScreen *sc, struct ARegion *ar);
 
 /* How long before a tool-tip shows. */
 #define UI_TOOLTIP_DELAY 0.5
index e6b91233f4ab0b85ff3868bfeae1b455e714892b..2f7359da308cb483b365bb1b510412eec16d305d 100644 (file)
@@ -295,8 +295,6 @@ typedef struct uiHandleButtonData {
        ColorBand *coba;
 
        /* tooltip */
-       ARegion *tooltip;
-       wmTimer *tooltiptimer;
        unsigned int tooltip_force : 1;
        
        /* auto open */
@@ -7652,12 +7650,12 @@ static bool button_modal_state(uiHandleButtonState state)
  */
 void UI_but_tooltip_refresh(bContext *C, uiBut *but)
 {
-       uiHandleButtonData *data;
-
-       data = but->active;
-       if (data && data->tooltip) {
-               UI_tooltip_free(C, data->tooltip);
-               data->tooltip = UI_tooltip_create_from_button(C, data->region, but);
+       uiHandleButtonData *data = but->active;
+       if (data) {
+               bScreen *sc = data->window->screen;
+               if (sc->tool_tip && sc->tool_tip->region) {
+                       WM_tooltip_refresh(C, data->window);
+               }
        }
 }
 
@@ -7668,39 +7666,36 @@ void UI_but_tooltip_timer_remove(bContext *C, uiBut *but)
 
        data = but->active;
        if (data) {
-
-               if (data->tooltiptimer) {
-                       WM_event_remove_timer(data->wm, data->window, data->tooltiptimer);
-                       data->tooltiptimer = NULL;
-               }
-               if (data->tooltip) {
-                       UI_tooltip_free(C, data->tooltip);
-                       data->tooltip = NULL;
-               }
-
                if (data->autoopentimer) {
                        WM_event_remove_timer(data->wm, data->window, data->autoopentimer);
                        data->autoopentimer = NULL;
                }
+
+               WM_tooltip_clear(C, data->window);
        }
 }
 
+static ARegion *ui_but_tooltip_init(bContext *C, ARegion *ar, bool *r_exit_on_event)
+{
+       uiBut *but = UI_region_active_but_get(ar);
+       *r_exit_on_event = false;
+       if (but) {
+               return UI_tooltip_create_from_button(C, ar, but);
+       }
+       return NULL;
+}
+
 static void button_tooltip_timer_reset(bContext *C, uiBut *but)
 {
        wmWindowManager *wm = CTX_wm_manager(C);
-       uiHandleButtonData *data;
-
-       data = but->active;
+       uiHandleButtonData *data = but->active;
 
-       if (data->tooltiptimer) {
-               WM_event_remove_timer(data->wm, data->window, data->tooltiptimer);
-               data->tooltiptimer = NULL;
-       }
+       WM_tooltip_timer_clear(C, data->window);
 
        if ((U.flag & USER_TOOLTIPS) || (data->tooltip_force)) {
                if (!but->block->tooltipdisabled) {
                        if (!wm->drags.first) {
-                               data->tooltiptimer = WM_event_add_timer(data->wm, data->window, TIMER, UI_TOOLTIP_DELAY);
+                               WM_tooltip_timer_init(C, data->window, data->region, ui_but_tooltip_init);
                        }
                }
        }
@@ -8060,12 +8055,10 @@ void ui_but_active_free(const bContext *C, uiBut *but)
 }
 
 /* returns the active button with an optional checking function */
-static uiBut *ui_context_button_active(const bContext *C, bool (*but_check_cb)(uiBut *))
+static uiBut *ui_context_button_active(ARegion *ar, bool (*but_check_cb)(uiBut *))
 {
        uiBut *but_found = NULL;
 
-       ARegion *ar = CTX_wm_region(C);
-
        while (ar) {
                uiBlock *block;
                uiBut *but, *activebut = NULL;
@@ -8108,12 +8101,17 @@ static bool ui_context_rna_button_active_test(uiBut *but)
 }
 static uiBut *ui_context_rna_button_active(const bContext *C)
 {
-       return ui_context_button_active(C, ui_context_rna_button_active_test);
+       return ui_context_button_active(CTX_wm_region(C), ui_context_rna_button_active_test);
 }
 
 uiBut *UI_context_active_but_get(const struct bContext *C)
 {
-       return ui_context_button_active(C, NULL);
+       return ui_context_button_active(CTX_wm_region(C), NULL);
+}
+
+uiBut *UI_region_active_but_get(ARegion *ar)
+{
+       return ui_context_button_active(ar, NULL);
 }
 
 /**
@@ -8395,16 +8393,8 @@ static int ui_handle_button_event(bContext *C, const wmEvent *event, uiBut *but)
                        }
                        case TIMER:
                        {
-                               /* handle tooltip timer */
-                               if (event->customdata == data->tooltiptimer) {
-                                       WM_event_remove_timer(data->wm, data->window, data->tooltiptimer);
-                                       data->tooltiptimer = NULL;
-
-                                       if (!data->tooltip)
-                                               data->tooltip = UI_tooltip_create_from_button(C, data->region, but);
-                               }
                                /* handle menu auto open timer */
-                               else if (event->customdata == data->autoopentimer) {
+                               if (event->customdata == data->autoopentimer) {
                                        WM_event_remove_timer(data->wm, data->window, data->autoopentimer);
                                        data->autoopentimer = NULL;
 
index bc271d0a9fe31d9ff636dd611a96954f027dd385..1eec37372150d42a3171ffbff5af784a7a1032c8 100644 (file)
@@ -756,9 +756,9 @@ ARegion *UI_tooltip_create_from_button(bContext *C, ARegion *butregion, uiBut *b
        return ui_tooltip_create_with_data(C, data, init_position, aspect);
 }
 
-void UI_tooltip_free(bContext *C, ARegion *ar)
+void UI_tooltip_free(bContext *C, bScreen *sc, ARegion *ar)
 {
-       ui_region_temp_remove(C, CTX_wm_screen(C), ar);
+       ui_region_temp_remove(C, sc, ar);
 }
 
 /** \} */
index a33aad4f343376c27a44d0ccaba6fd8866220f15..a7718883438094d05a90c1802aa3154cc05f15e9 100644 (file)
@@ -44,6 +44,7 @@ struct PanelType;
 struct Scene;
 struct uiLayout;
 struct wmTimer;
+struct wmTooltipState;
 
 typedef struct bScreen {
        ID id;
@@ -76,6 +77,8 @@ typedef struct bScreen {
 
        struct wmTimer *animtimer;                      /* if set, screen has timer handler added in window */
        void *context;                                          /* context callback */
+
+       struct wmTooltipState *tool_tip;        /* runtime */
 } bScreen;
 
 typedef struct ScrVert {
index a8b3c994d24e72d77b6ae5377218a95c5ec75f48..c9278822b9a925ec97a73049ab9ac1500cd36d7b 100644 (file)
@@ -67,6 +67,7 @@ set(SRC
        intern/wm_operator_props.c
        intern/wm_operators.c
        intern/wm_subwindow.c
+       intern/wm_tooltip.c
        intern/wm_window.c
        intern/wm_stereo.c
 
index e84239f1c67a3214413238018422f6ef004a60cd..965eb2b258a2e4b4bae259378c91b38c92529097 100644 (file)
@@ -536,6 +536,17 @@ bool        WM_event_is_tablet(const struct wmEvent *event);
 bool        WM_event_is_ime_switch(const struct wmEvent *event);
 #endif
 
+/* wm_tooltip.c */
+typedef struct ARegion *(*wmTooltipInitFn)(struct bContext *, struct ARegion *, bool *);
+
+void WM_tooltip_timer_init(
+        struct bContext *C, struct wmWindow *win, struct ARegion *ar,
+        wmTooltipInitFn init);
+void WM_tooltip_timer_clear(struct bContext *C, struct wmWindow *win);
+void WM_tooltip_clear(struct bContext *C, struct wmWindow *win);
+void WM_tooltip_init(struct bContext *C, struct wmWindow *win);
+void WM_tooltip_refresh(struct bContext *C, struct wmWindow *win);
+
 #ifdef __cplusplus
 }
 #endif
index cd78a519dbf700455993c130408686d2d15aadbf..ded96619a883d0d1ff84708580ed7561494f3c34 100644 (file)
@@ -690,6 +690,15 @@ typedef struct wmDropBox {
 
 } wmDropBox;
 
+typedef struct wmTooltipState {
+       struct wmTimer *timer;
+       struct ARegion *region_from;
+       struct ARegion *region;
+       struct ARegion *(*init)(struct bContext *, struct ARegion *, bool *r_exit_on_event);
+       /* Exit on any event, not needed for buttons since their highlight state is used. */
+       bool exit_on_event;
+} wmTooltipState;
+
 /* *************** migrated stuff, clean later? ************** */
 
 typedef struct RecentFile {
index 61c144a63d4f3c1c2242b04bf4cfa0b80a21aff9..d36702b4df7628b62db141c20ec4b8458219d60d 100644 (file)
@@ -2474,6 +2474,13 @@ void wm_event_do_handlers(bContext *C)
 
                        CTX_wm_window_set(C, win);
 
+                       /* Clear tool-tip on mouse move. */
+                       if (win->screen->tool_tip && win->screen->tool_tip->exit_on_event) {
+                               if (ISMOUSE(event->type)) {
+                                       WM_tooltip_clear(C, win);
+                               }
+                       }
+
                        /* we let modal handlers get active area/region, also wm_paintcursor_test needs it */
                        CTX_wm_area_set(C, area_event_inside(C, &event->x));
                        CTX_wm_region_set(C, region_event_inside(C, &event->x));
@@ -2490,7 +2497,17 @@ void wm_event_do_handlers(bContext *C)
                        /* fileread case */
                        if (CTX_wm_window(C) == NULL)
                                return;
-                       
+
+                       /* check for a tooltip */
+                       {
+                               bScreen *screen = CTX_wm_window(C)->screen;
+                               if (screen->tool_tip && screen->tool_tip->timer) {
+                                       if ((event->type == TIMER) && (event->customdata == screen->tool_tip->timer)) {
+                                               WM_tooltip_init(C, win);
+                                       }
+                               }
+                       }
+
                        /* check dragging, creates new event or frees, adds draw tag */
                        wm_event_drag_test(wm, win, event);
                        
diff --git a/source/blender/windowmanager/intern/wm_tooltip.c b/source/blender/windowmanager/intern/wm_tooltip.c
new file mode 100644 (file)
index 0000000..86ca95e
--- /dev/null
@@ -0,0 +1,106 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version. 
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/windowmanager/intern/wm_tooltip.c
+ *  \ingroup wm
+ *
+ * Manages a per-window tool-tip.
+ */
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_utildefines.h"
+
+#include "BKE_context.h"
+
+#include "ED_screen.h"
+
+#include "UI_interface.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+
+void WM_tooltip_timer_init(
+        bContext *C, wmWindow *win, ARegion *ar,
+        wmTooltipInitFn init)
+{
+       bScreen *screen = win->screen;
+       wmWindowManager *wm = CTX_wm_manager(C);
+       if (screen->tool_tip == NULL) {
+               screen->tool_tip = MEM_callocN(sizeof(*screen->tool_tip), __func__);
+       }
+       screen->tool_tip->region_from = ar;
+       screen->tool_tip->timer = WM_event_add_timer(wm, win, TIMER, UI_TOOLTIP_DELAY);
+       screen->tool_tip->init = init;
+}
+
+void WM_tooltip_timer_clear(bContext *C, wmWindow *win)
+{
+       wmWindowManager *wm = CTX_wm_manager(C);
+       bScreen *screen = win->screen;
+       if (screen->tool_tip != NULL) {
+               if (screen->tool_tip->timer != NULL) {
+                       WM_event_remove_timer(wm, win, screen->tool_tip->timer);
+                       screen->tool_tip->timer = NULL;
+               }
+       }
+}
+
+void WM_tooltip_clear(bContext *C, wmWindow *win)
+{
+       WM_tooltip_timer_clear(C, win);
+       bScreen *screen = win->screen;
+       if (screen->tool_tip != NULL) {
+               if (screen->tool_tip->region) {
+                       UI_tooltip_free(C, screen, screen->tool_tip->region);
+                       screen->tool_tip->region = NULL;
+               }
+               MEM_freeN(screen->tool_tip);
+               screen->tool_tip = NULL;
+       }
+}
+
+void WM_tooltip_init(bContext *C, wmWindow *win)
+{
+       WM_tooltip_timer_clear(C, win);
+       bScreen *screen = win->screen;
+       if (screen->tool_tip->region) {
+               UI_tooltip_free(C, screen, screen->tool_tip->region);
+               screen->tool_tip->region = NULL;
+       }
+       screen->tool_tip->region = screen->tool_tip->init(
+               C, screen->tool_tip->region_from, &screen->tool_tip->exit_on_event);
+       if (screen->tool_tip->region == NULL) {
+               WM_tooltip_clear(C, win);
+       }
+}
+
+void WM_tooltip_refresh(bContext *C, wmWindow *win)
+{
+       WM_tooltip_timer_clear(C, win);
+       bScreen *screen = win->screen;
+       if (screen->tool_tip != NULL) {
+               if (screen->tool_tip->region) {
+                       UI_tooltip_free(C, screen, screen->tool_tip->region);
+                       screen->tool_tip->region = NULL;
+               }
+               WM_tooltip_init(C, win);
+       }
+}