Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'source/blender/editors/interface/interface_panel.c')
-rw-r--r--source/blender/editors/interface/interface_panel.c268
1 files changed, 216 insertions, 52 deletions
diff --git a/source/blender/editors/interface/interface_panel.c b/source/blender/editors/interface/interface_panel.c
index d165e2719c5..665266edb9f 100644
--- a/source/blender/editors/interface/interface_panel.c
+++ b/source/blender/editors/interface/interface_panel.c
@@ -82,6 +82,14 @@
/* only show pin header button for pinned panels */
#define USE_PIN_HIDDEN
+/* the state of the mouse position relative to the panel */
+typedef enum uiPanelMouseState {
+ PANEL_MOUSE_OUTSIDE, /* mouse is not in the panel */
+ PANEL_MOUSE_INSIDE_CONTENT, /* mouse is in the actual panel content */
+ PANEL_MOUSE_INSIDE_HEADER, /* mouse is in the panel header */
+ PANEL_MOUSE_INSIDE_SCALE, /* mouse is inside panel scale widget */
+} uiPanelMouseState;
+
typedef enum uiHandlePanelState {
PANEL_STATE_DRAG,
PANEL_STATE_DRAG_SCALE,
@@ -202,8 +210,9 @@ static void ui_panel_copy_offset(Panel *pa, Panel *papar)
}
-/* XXX Disabled paneltab handling for now. Old 2.4x feature, *DO NOT* confuse it with new tool tabs in 2.70. ;)
- * See also T41704.
+/**
+ * XXX Disabled paneltab handling for now. Old 2.4x feature, *DO NOT* confuse it with new tool tabs in 2.70. ;)
+ * See also T41704.
*/
/* #define UI_USE_PANELTAB */
@@ -560,6 +569,8 @@ void ui_draw_aligned_panel(uiStyle *style, uiBlock *block, const rcti *rect, con
rcti headrect;
rctf itemrect;
int ofsx;
+ const bool is_closed_x = (panel->flag & PNL_CLOSEDX) ? true : false;
+ const bool is_closed_y = (panel->flag & PNL_CLOSEDY) ? true : false;
if (panel->paneltab) return;
if (panel->type && (panel->type->flag & PNL_NO_HEADER)) return;
@@ -572,7 +583,7 @@ void ui_draw_aligned_panel(uiStyle *style, uiBlock *block, const rcti *rect, con
{
float minx = rect->xmin;
- float maxx = rect->xmax;
+ float maxx = is_closed_x ? (minx + PNL_HEADER / block->aspect) : rect->xmax;
float y = headrect.ymax;
glEnable(GL_BLEND);
@@ -587,8 +598,11 @@ void ui_draw_aligned_panel(uiStyle *style, uiBlock *block, const rcti *rect, con
}
else if (!(panel->runtime_flag & PNL_FIRST)) {
/* draw embossed separator */
- minx += 5.0f / block->aspect;
- maxx -= 5.0f / block->aspect;
+
+ if (is_closed_x == false) {
+ minx += 5.0f / block->aspect;
+ maxx -= 5.0f / block->aspect;
+ }
glColor4f(0.0f, 0.0f, 0.0f, 0.5f);
fdrawline(minx, y, maxx, y);
@@ -615,7 +629,7 @@ void ui_draw_aligned_panel(uiStyle *style, uiBlock *block, const rcti *rect, con
}
/* horizontal title */
- if (!(panel->flag & PNL_CLOSEDX)) {
+ if (is_closed_x == false) {
ui_draw_aligned_panel_header(style, block, &headrect, 'h');
/* itemrect smaller */
@@ -631,9 +645,10 @@ void ui_draw_aligned_panel(uiStyle *style, uiBlock *block, const rcti *rect, con
/* if the panel is minimized vertically:
* (------)
*/
- if (panel->flag & PNL_CLOSEDY) {
+ if (is_closed_y) {
+ /* skip */
}
- else if (panel->flag & PNL_CLOSEDX) {
+ else if (is_closed_x) {
/* draw vertical title */
ui_draw_aligned_panel_header(style, block, &headrect, 'v');
}
@@ -680,9 +695,9 @@ void ui_draw_aligned_panel(uiStyle *style, uiBlock *block, const rcti *rect, con
BLI_rctf_scale(&itemrect, 0.35f);
- if (panel->flag & PNL_CLOSEDY)
+ if (is_closed_y)
ui_draw_tria_rect(&itemrect, 'h');
- else if (panel->flag & PNL_CLOSEDX)
+ else if (is_closed_x)
ui_draw_tria_rect(&itemrect, 'h');
else
ui_draw_tria_rect(&itemrect, 'v');
@@ -729,11 +744,13 @@ typedef struct PanelSort {
Panel *pa, *orig;
} PanelSort;
-/* note about sorting;
+/**
+ * \note about sorting;
* the sortorder has a lower value for new panels being added.
* however, that only works to insert a single panel, when more new panels get
* added the coordinates of existing panels and the previously stored to-be-inserted
- * panels do not match for sorting */
+ * panels do not match for sorting
+ */
static int find_leftmost_panel(const void *a1, const void *a2)
{
@@ -1128,6 +1145,157 @@ static void ui_do_drag(const bContext *C, const wmEvent *event, Panel *panel)
/******************* region level panel interaction *****************/
+static uiPanelMouseState ui_panel_mouse_state_get(const uiBlock *block, const Panel *pa, const int mx, const int my)
+{
+ /* open panel */
+ if (pa->flag & PNL_CLOSEDX) {
+ if ((block->rect.xmin <= mx) && (block->rect.xmin + PNL_HEADER >= mx)) {
+ return PANEL_MOUSE_INSIDE_HEADER;
+ }
+ }
+ /* outside left/right side */
+ else if ((block->rect.xmin > mx) || (block->rect.xmax < mx)) {
+ /* pass */
+ }
+ else if ((block->rect.ymax <= my) && (block->rect.ymax + PNL_HEADER >= my)) {
+ return PANEL_MOUSE_INSIDE_HEADER;
+ }
+ /* open panel */
+ else if (!(pa->flag & PNL_CLOSEDY)) {
+ if (pa->control & UI_PNL_SCALE) {
+ if (block->rect.xmax - PNL_HEADER <= mx) {
+ if (block->rect.ymin + PNL_HEADER >= my) {
+ return PANEL_MOUSE_INSIDE_SCALE;
+ }
+ }
+ }
+ if ((block->rect.xmin <= mx) && (block->rect.xmax >= mx)) {
+ if ((block->rect.ymin <= my) && (block->rect.ymax + PNL_HEADER >= my)) {
+ return PANEL_MOUSE_INSIDE_CONTENT;
+ }
+ }
+ }
+ return PANEL_MOUSE_OUTSIDE;
+}
+
+typedef struct uiPanelDragCollapseHandle {
+ bool was_first_open;
+ int xy_init[2];
+} uiPanelDragCollapseHandle;
+
+static void ui_panel_drag_collapse_handler_remove(bContext *UNUSED(C), void *userdata)
+{
+ uiPanelDragCollapseHandle *dragcol_data = userdata;
+ MEM_freeN(dragcol_data);
+}
+
+static void ui_panel_drag_collapse(bContext *C, uiPanelDragCollapseHandle *dragcol_data, const int xy_dst[2])
+{
+ ScrArea *sa = CTX_wm_area(C);
+ ARegion *ar = CTX_wm_region(C);
+ uiBlock *block;
+ Panel *pa;
+
+ for (block = ar->uiblocks.first; block; block = block->next) {
+ float xy_a_block[2] = {UNPACK2(dragcol_data->xy_init)};
+ float xy_b_block[2] = {UNPACK2(xy_dst)};
+ rctf rect = block->rect;
+ int oldflag;
+ const bool is_horizontal = (panel_aligned(sa, ar) == BUT_HORIZONTAL);
+
+ if ((pa = block->panel) == 0 || (pa->type && (pa->type->flag & PNL_NO_HEADER))) {
+ continue;
+ }
+ oldflag = pa->flag;
+
+ /* lock one axis */
+ if (is_horizontal) {
+ xy_b_block[1] = dragcol_data->xy_init[1];
+ }
+ else {
+ xy_b_block[0] = dragcol_data->xy_init[0];
+ }
+
+ /* use cursor coords in block space */
+ ui_window_to_block_fl(ar, block, &xy_a_block[0], &xy_a_block[1]);
+ ui_window_to_block_fl(ar, block, &xy_b_block[0], &xy_b_block[1]);
+
+ /* set up rect to match header size */
+ rect.ymin = rect.ymax;
+ rect.ymax = rect.ymin + PNL_HEADER;
+ if (pa->flag & PNL_CLOSEDX) {
+ rect.xmax = rect.xmin + PNL_HEADER;
+ }
+
+ /* touch all panels between last mouse coord and the current one */
+ if (BLI_rctf_isect_segment(&rect, xy_a_block, xy_b_block)) {
+ /* force panel to close */
+ if (dragcol_data->was_first_open == true) {
+ pa->flag |= (is_horizontal ? PNL_CLOSEDX : PNL_CLOSEDY);
+ }
+ /* force panel to open */
+ else {
+ pa->flag &= ~PNL_CLOSED;
+ }
+
+ /* if pa->flag has changed this means a panel was opened/closed here */
+ if (pa->flag != oldflag) {
+ panel_activate_state(C, pa, PANEL_STATE_ANIMATION);
+ }
+ }
+ }
+}
+
+/**
+ * Panel drag-collapse (modal handler)
+ * Clicking and dragging over panels toggles their collapse state based on the panel that was first
+ * dragged over. If it was open all affected panels incl the initial one are closed and vise versa.
+ */
+static int ui_panel_drag_collapse_handler(bContext *C, const wmEvent *event, void *userdata)
+{
+ wmWindow *win = CTX_wm_window(C);
+ uiPanelDragCollapseHandle *dragcol_data = userdata;
+ short retval = WM_UI_HANDLER_CONTINUE;
+
+ switch (event->type) {
+ case MOUSEMOVE:
+ ui_panel_drag_collapse(C, dragcol_data, &event->x);
+
+ retval = WM_UI_HANDLER_BREAK;
+ break;
+ case LEFTMOUSE:
+ if (event->val == KM_RELEASE) {
+ /* done! */
+ WM_event_remove_ui_handler(
+ &win->modalhandlers,
+ ui_panel_drag_collapse_handler,
+ ui_panel_drag_collapse_handler_remove,
+ dragcol_data, true);
+ ui_panel_drag_collapse_handler_remove(C, dragcol_data);
+ }
+ /* don't let any left-mouse event fall through! */
+ retval = WM_UI_HANDLER_BREAK;
+ break;
+ }
+
+ return retval;
+}
+
+static void ui_panel_drag_collapse_handler_add(const bContext *C, const bool was_open)
+{
+ wmWindow *win = CTX_wm_window(C);
+ wmEvent *event = win->eventstate;
+ uiPanelDragCollapseHandle *dragcol_data = MEM_mallocN(sizeof(*dragcol_data), __func__);
+
+ dragcol_data->was_first_open = was_open;
+ copy_v2_v2_int(dragcol_data->xy_init, &event->x);
+
+ WM_event_add_ui_handler(
+ C, &win->modalhandlers,
+ ui_panel_drag_collapse_handler,
+ ui_panel_drag_collapse_handler_remove,
+ dragcol_data, 0);
+}
/* this function is supposed to call general window drawing too */
/* also it supposes a block has panel, and isn't a menu */
@@ -1187,23 +1355,39 @@ static void ui_handle_panel_header(const bContext *C, uiBlock *block, int mx, in
ED_region_tag_redraw(ar);
}
else { /* collapse */
- if (ctrl)
+ if (ctrl) {
panels_collapse_all(sa, ar, block->panel);
+ /* reset the view - we don't want to display a view without content */
+ UI_view2d_offset(&ar->v2d, 0.0f, 1.0f);
+ }
+
if (block->panel->flag & PNL_CLOSED) {
block->panel->flag &= ~PNL_CLOSED;
/* snap back up so full panel aligns with screen edge */
if (block->panel->snap & PNL_SNAP_BOTTOM)
block->panel->ofsy = 0;
+
+ if (event == LEFTMOUSE) {
+ ui_panel_drag_collapse_handler_add(C, false);
+ }
}
else if (align == BUT_HORIZONTAL) {
block->panel->flag |= PNL_CLOSEDX;
+
+ if (event == LEFTMOUSE) {
+ ui_panel_drag_collapse_handler_add(C, true);
+ }
}
else {
- /* snap down to bottom screen edge*/
+ /* snap down to bottom screen edge */
block->panel->flag |= PNL_CLOSEDY;
if (block->panel->snap & PNL_SNAP_BOTTOM)
block->panel->ofsy = -block->panel->sizey;
+
+ if (event == LEFTMOUSE) {
+ ui_panel_drag_collapse_handler_add(C, true);
+ }
}
for (pa = ar->panels.first; pa; pa = pa->next) {
@@ -1332,10 +1516,11 @@ void UI_panel_category_clear_all(ARegion *ar)
}
/* based on UI_draw_roundbox_gl_mode, check on making a version which allows us to skip some sides */
-static void ui_panel_category_draw_tab(int mode, float minx, float miny, float maxx, float maxy, float rad,
- int roundboxtype,
- const bool use_highlight, const bool use_shadow,
- const unsigned char highlight_fade[3])
+static void ui_panel_category_draw_tab(
+ int mode, float minx, float miny, float maxx, float maxy, float rad,
+ int roundboxtype,
+ const bool use_highlight, const bool use_shadow,
+ const unsigned char highlight_fade[3])
{
float vec[4][2] = {
{0.195, 0.02},
@@ -1718,8 +1903,8 @@ int ui_handler_panel_region(bContext *C, const wmEvent *event, ARegion *ar)
}
for (block = ar->uiblocks.last; block; block = block->prev) {
- bool inside = false, inside_header = false, inside_scale = false;
-
+ uiPanelMouseState mouse_state;
+
mx = event->x;
my = event->y;
ui_window_to_block(ar, block, &mx, &my);
@@ -1731,32 +1916,11 @@ int ui_handler_panel_region(bContext *C, const wmEvent *event, ARegion *ar)
continue;
if (pa->type && pa->type->flag & PNL_NO_HEADER) /* XXX - accessed freed panels when scripts reload, need to fix. */
continue;
-
- /* clicked at panel header? */
- if (pa->flag & PNL_CLOSEDX) {
- if (block->rect.xmin <= mx && block->rect.xmin + PNL_HEADER >= mx)
- inside_header = true;
- }
- else if (block->rect.xmin > mx || block->rect.xmax < mx) {
- /* outside left/right side */
- }
- else if ((block->rect.ymax <= my) && (block->rect.ymax + PNL_HEADER >= my)) {
- inside_header = true;
- }
- else if (!(pa->flag & PNL_CLOSEDY)) {
- /* open panel */
- if (pa->control & UI_PNL_SCALE) {
- if (block->rect.xmax - PNL_HEADER <= mx)
- if (block->rect.ymin + PNL_HEADER >= my)
- inside_scale = true;
- }
- if (block->rect.xmin <= mx && block->rect.xmax >= mx)
- if (block->rect.ymin <= my && block->rect.ymax + PNL_HEADER >= my)
- inside = true;
- }
-
+
+ mouse_state = ui_panel_mouse_state_get(block, pa, mx, my);
+
/* XXX hardcoded key warning */
- if ((inside || inside_header) && event->val == KM_PRESS) {
+ if (ELEM(mouse_state, PANEL_MOUSE_INSIDE_CONTENT, PANEL_MOUSE_INSIDE_HEADER) && event->val == KM_PRESS) {
if (event->type == AKEY && ((event->ctrl + event->oskey + event->shift + event->alt) == 0)) {
if (pa->flag & PNL_CLOSEDY) {
@@ -1775,13 +1939,13 @@ int ui_handler_panel_region(bContext *C, const wmEvent *event, ARegion *ar)
if (ui_but_is_active(ar))
continue;
- if (inside || inside_header) {
+ if (ELEM(mouse_state, PANEL_MOUSE_INSIDE_CONTENT, PANEL_MOUSE_INSIDE_HEADER)) {
if (event->val == KM_PRESS) {
/* open close on header */
if (ELEM(event->type, RETKEY, PADENTER)) {
- if (inside_header) {
+ if (mouse_state == PANEL_MOUSE_INSIDE_HEADER) {
ui_handle_panel_header(C, block, mx, my, RETKEY, event->ctrl, event->shift);
retval = WM_UI_HANDLER_BREAK;
break;
@@ -1791,12 +1955,12 @@ int ui_handler_panel_region(bContext *C, const wmEvent *event, ARegion *ar)
/* all inside clicks should return in break - overlapping/float panels */
retval = WM_UI_HANDLER_BREAK;
- if (inside_header) {
- ui_handle_panel_header(C, block, mx, my, 0, event->ctrl, event->shift);
+ if (mouse_state == PANEL_MOUSE_INSIDE_HEADER) {
+ ui_handle_panel_header(C, block, mx, my, event->type, event->ctrl, event->shift);
retval = WM_UI_HANDLER_BREAK;
break;
}
- else if (inside_scale && !(pa->flag & PNL_CLOSED)) {
+ else if ((mouse_state == PANEL_MOUSE_INSIDE_SCALE) && !(pa->flag & PNL_CLOSED)) {
panel_activate_state(C, pa, PANEL_STATE_DRAG_SCALE);
retval = WM_UI_HANDLER_BREAK;
break;
@@ -1804,7 +1968,7 @@ int ui_handler_panel_region(bContext *C, const wmEvent *event, ARegion *ar)
}
else if (event->type == RIGHTMOUSE) {
- if (inside_header) {
+ if (mouse_state == PANEL_MOUSE_INSIDE_HEADER) {
ui_panel_menu(C, ar, block->panel);
retval = WM_UI_HANDLER_BREAK;
break;
@@ -1943,7 +2107,7 @@ static void panel_activate_state(const bContext *C, Panel *pa, uiHandlePanelStat
data = MEM_callocN(sizeof(uiHandlePanelData), "uiHandlePanelData");
pa->activedata = data;
- WM_event_add_ui_handler(C, &win->modalhandlers, ui_handler_panel, ui_handler_remove_panel, pa, false);
+ WM_event_add_ui_handler(C, &win->modalhandlers, ui_handler_panel, ui_handler_remove_panel, pa, 0);
}
if (ELEM(state, PANEL_STATE_ANIMATION, PANEL_STATE_DRAG))