Changeset View
Changeset View
Standalone View
Standalone View
source/blender/editors/interface/interface_panel.c
| Show First 20 Lines • Show All 58 Lines • ▼ Show 20 Lines | |||||
| #include "GPU_batch_presets.h" | #include "GPU_batch_presets.h" | ||||
| #include "GPU_immediate.h" | #include "GPU_immediate.h" | ||||
| #include "GPU_matrix.h" | #include "GPU_matrix.h" | ||||
| #include "GPU_state.h" | #include "GPU_state.h" | ||||
| #include "interface_intern.h" | #include "interface_intern.h" | ||||
| /*********************** defines and structs ************************/ | /* -------------------------------------------------------------------- */ | ||||
| /** \name Structs and Defines | |||||
| * \{ */ | |||||
| #define ANIMATION_TIME 0.30 | #define ANIMATION_TIME 2.0 | ||||
| #define ANIMATION_INTERVAL 0.02 | #define ANIMATION_INTERVAL 0.02 | ||||
| #define PNL_LAST_ADDED 1 | /* Only show pin header button for pinned panels. */ | ||||
| #define PNL_ACTIVE 2 | |||||
| #define PNL_WAS_ACTIVE 4 | |||||
| #define PNL_ANIM_ALIGN 8 | |||||
| #define PNL_NEW_ADDED 16 | |||||
| #define PNL_FIRST 32 | |||||
| /* only show pin header button for pinned panels */ | |||||
| #define USE_PIN_HIDDEN | #define USE_PIN_HIDDEN | ||||
| typedef enum uiPanelRuntimeFlag { | |||||
| PANEL_LAST_ADDED = (1 << 0), | |||||
| PANEL_ACTIVE = (1 << 1), | |||||
| PANEL_WAS_ACTIVE = (1 << 2), | |||||
| PANEL_ANIM_ALIGN = (1 << 3), | |||||
| PANEL_NEW_ADDED = (1 << 4), | |||||
| PANEL_FIRST = (1 << 5), | |||||
| } uiPanelRuntimeFlag; | |||||
| /* the state of the mouse position relative to the panel */ | /* the state of the mouse position relative to the panel */ | ||||
| typedef enum uiPanelMouseState { | typedef enum uiPanelMouseState { | ||||
| PANEL_MOUSE_OUTSIDE, /* mouse is not in the panel */ | PANEL_MOUSE_OUTSIDE, /* mouse is not in the panel */ | ||||
| PANEL_MOUSE_INSIDE_CONTENT, /* mouse is in the actual panel content */ | PANEL_MOUSE_INSIDE_CONTENT, /* mouse is in the actual panel content */ | ||||
| PANEL_MOUSE_INSIDE_HEADER, /* mouse is in the panel header */ | PANEL_MOUSE_INSIDE_HEADER, /* mouse is in the panel header */ | ||||
| PANEL_MOUSE_INSIDE_SCALE, /* mouse is inside panel scale widget */ | PANEL_MOUSE_INSIDE_SCALE, /* mouse is inside panel scale widget */ | ||||
| } uiPanelMouseState; | } uiPanelMouseState; | ||||
| typedef enum uiHandlePanelState { | typedef enum uiHandlePanelState { | ||||
| PANEL_STATE_DRAG, | PANEL_STATE_DRAG, | ||||
| PANEL_STATE_DRAG_SCALE, | PANEL_STATE_DRAG_SCALE, | ||||
| PANEL_STATE_WAIT_UNTAB, | PANEL_STATE_WAIT_UNTAB, | ||||
| PANEL_STATE_ANIMATION, | PANEL_STATE_ANIMATION, | ||||
| PANEL_STATE_EXIT, | PANEL_STATE_EXIT, | ||||
| } uiHandlePanelState; | } uiHandlePanelState; | ||||
| typedef struct uiHandlePanelData { | typedef struct uiHandlePanelData { | ||||
| uiHandlePanelState state; | uiHandlePanelState state; | ||||
| /* animation */ | /* Animation. */ | ||||
| wmTimer *animtimer; | wmTimer *animtimer; | ||||
| double starttime; | double starttime; | ||||
| /* dragging */ | /* Dragging. */ | ||||
| bool is_drag_drop; | bool is_drag_drop; | ||||
| int startx, starty; | int startx, starty; | ||||
| int startofsx, startofsy; | int startofsx, startofsy; | ||||
| int startsizex, startsizey; | int startsizex, startsizey; | ||||
| float start_cur_xmin, start_cur_ymin; | float start_cur_xmin, start_cur_ymin; | ||||
| } uiHandlePanelData; | } uiHandlePanelData; | ||||
| typedef struct PanelSort { | typedef struct PanelSort { | ||||
| Panel *panel, *orig; | Panel *panel; | ||||
| Panel *orig; | |||||
| } PanelSort; | } PanelSort; | ||||
| static int get_panel_real_size_y(const Panel *panel); | static int panel_size_real_y(const Panel *panel); | ||||
| static void panel_activate_state(const bContext *C, Panel *panel, uiHandlePanelState state); | static void panel_activate_state(const bContext *C, Panel *panel, uiHandlePanelState state); | ||||
| static int compare_panel(const void *a1, const void *a2); | static int compare_panel_sortorder(const void *a1, const void *a2); | ||||
| static bool panel_type_context_poll(PanelType *panel_type, const char *context); | static bool panel_type_context_poll(PanelType *panel_type, const char *context); | ||||
| /** \} */ | |||||
| /* -------------------------------------------------------------------- */ | |||||
| /** \name Space specific code | |||||
| * | |||||
| * Temporary code to remove all sbuts stuff from panel code. | |||||
| * \{ */ | |||||
| /* SpaceProperties.align */ | |||||
| typedef enum eSpaceButtons_Align { | |||||
| BUT_HORIZONTAL = 0, | |||||
| BUT_VERTICAL = 1, | |||||
| BUT_AUTO = 2, | |||||
| } eSpaceButtons_Align; | |||||
| static void panel_title_color_get(bool show_background, uchar color[4]) | static void panel_title_color_get(bool show_background, uchar color[4]) | ||||
| { | { | ||||
| if (show_background) { | if (show_background) { | ||||
| UI_GetThemeColor4ubv(TH_TITLE, color); | UI_GetThemeColor4ubv(TH_TITLE, color); | ||||
| } | } | ||||
| else { | else { | ||||
| /* Use menu colors for floating panels. */ | /* Use menu colors for floating panels. */ | ||||
| bTheme *btheme = UI_GetTheme(); | bTheme *btheme = UI_GetTheme(); | ||||
| const uiWidgetColors *wcol = &btheme->tui.wcol_menu_back; | const uiWidgetColors *wcol = &btheme->tui.wcol_menu_back; | ||||
| copy_v4_v4_uchar(color, (const uchar *)wcol->text); | copy_v4_v4_uchar(color, (const uchar *)wcol->text); | ||||
| } | } | ||||
| } | } | ||||
| /*********************** space specific code ************************/ | static int region_panel_alignment(const ScrArea *area, const ARegion *region) | ||||
| /* temporary code to remove all sbuts stuff from panel code */ | |||||
| /* SpaceProperties.align */ | |||||
| typedef enum eSpaceButtons_Align { | |||||
| BUT_HORIZONTAL = 0, | |||||
| BUT_VERTICAL = 1, | |||||
| BUT_AUTO = 2, | |||||
| } eSpaceButtons_Align; | |||||
| static int panel_aligned(const ScrArea *area, const ARegion *region) | |||||
| { | { | ||||
| if (area->spacetype == SPACE_PROPERTIES && region->regiontype == RGN_TYPE_WINDOW) { | if (area->spacetype == SPACE_PROPERTIES && region->regiontype == RGN_TYPE_WINDOW) { | ||||
| return BUT_VERTICAL; | return BUT_VERTICAL; | ||||
| } | } | ||||
| if (area->spacetype == SPACE_USERPREF && region->regiontype == RGN_TYPE_WINDOW) { | if (area->spacetype == SPACE_USERPREF && region->regiontype == RGN_TYPE_WINDOW) { | ||||
| return BUT_VERTICAL; | return BUT_VERTICAL; | ||||
| } | } | ||||
| if (area->spacetype == SPACE_FILE && region->regiontype == RGN_TYPE_CHANNELS) { | if (area->spacetype == SPACE_FILE && region->regiontype == RGN_TYPE_CHANNELS) { | ||||
| Show All 10 Lines | if (ELEM(region->regiontype, | ||||
| RGN_TYPE_NAV_BAR, | RGN_TYPE_NAV_BAR, | ||||
| RGN_TYPE_EXECUTE)) { | RGN_TYPE_EXECUTE)) { | ||||
| return BUT_VERTICAL; | return BUT_VERTICAL; | ||||
| } | } | ||||
| return 0; | return 0; | ||||
| } | } | ||||
| static bool panel_active_animation_changed(ListBase *lb, Panel **pa_animation, bool *no_animation) | static bool panels_active_animation_changed(ListBase *lb, Panel **pa_animation, bool *no_animation) | ||||
| { | { | ||||
| LISTBASE_FOREACH (Panel *, panel, lb) { | LISTBASE_FOREACH (Panel *, panel, lb) { | ||||
| /* Detect panel active flag changes. */ | /* Detect panel active flag changes. */ | ||||
| if (!(panel->type && panel->type->parent)) { | if (!(panel->type && panel->type->parent)) { | ||||
| if ((panel->runtime_flag & PNL_WAS_ACTIVE) && !(panel->runtime_flag & PNL_ACTIVE)) { | if ((panel->runtime_flag & PANEL_WAS_ACTIVE) && !(panel->runtime_flag & PANEL_ACTIVE)) { | ||||
| return true; | return true; | ||||
| } | } | ||||
| if (!(panel->runtime_flag & PNL_WAS_ACTIVE) && (panel->runtime_flag & PNL_ACTIVE)) { | if (!(panel->runtime_flag & PANEL_WAS_ACTIVE) && (panel->runtime_flag & PANEL_ACTIVE)) { | ||||
| return true; | return true; | ||||
| } | } | ||||
| } | } | ||||
| if ((panel->runtime_flag & PNL_ACTIVE) && !(panel->flag & PNL_CLOSED)) { | if ((panel->runtime_flag & PANEL_ACTIVE) && !(panel->flag & PNL_CLOSED)) { | ||||
| if (panel_active_animation_changed(&panel->children, pa_animation, no_animation)) { | if (panels_active_animation_changed(&panel->children, pa_animation, no_animation)) { | ||||
| return true; | return true; | ||||
| } | } | ||||
| } | } | ||||
| /* Detect animation. */ | /* Detect animation. */ | ||||
| if (panel->activedata) { | if (panel->activedata) { | ||||
| uiHandlePanelData *data = panel->activedata; | uiHandlePanelData *data = panel->activedata; | ||||
| if (data->state == PANEL_STATE_ANIMATION) { | if (data->state == PANEL_STATE_ANIMATION) { | ||||
| *pa_animation = panel; | *pa_animation = panel; | ||||
| } | } | ||||
| else { | else { | ||||
| /* Don't animate while handling other interaction. */ | /* Don't animate while handling other interaction. */ | ||||
| *no_animation = true; | *no_animation = true; | ||||
| } | } | ||||
| } | } | ||||
| if ((panel->runtime_flag & PNL_ANIM_ALIGN) && !(*pa_animation)) { | if ((panel->runtime_flag & PANEL_ANIM_ALIGN) && !(*pa_animation)) { | ||||
| *pa_animation = panel; | *pa_animation = panel; | ||||
| } | } | ||||
| } | } | ||||
| return false; | return false; | ||||
| } | } | ||||
| static bool panels_need_realign(ScrArea *area, ARegion *region, Panel **r_panel_animation) | static bool panels_need_realign(ScrArea *area, ARegion *region, Panel **r_panel_animation) | ||||
| Show All 12 Lines | static bool panels_need_realign(ScrArea *area, ARegion *region, Panel **r_panel_animation) | ||||
| } | } | ||||
| else if (area->spacetype == SPACE_FILE && region->regiontype == RGN_TYPE_CHANNELS) { | else if (area->spacetype == SPACE_FILE && region->regiontype == RGN_TYPE_CHANNELS) { | ||||
| return true; | return true; | ||||
| } | } | ||||
| /* Detect if a panel was added or removed. */ | /* Detect if a panel was added or removed. */ | ||||
| Panel *panel_animation = NULL; | Panel *panel_animation = NULL; | ||||
| bool no_animation = false; | bool no_animation = false; | ||||
| if (panel_active_animation_changed(®ion->panels, &panel_animation, &no_animation)) { | if (panels_active_animation_changed(®ion->panels, &panel_animation, &no_animation)) { | ||||
| return true; | return true; | ||||
| } | } | ||||
| /* Detect panel marked for animation, if we're not already animating. */ | /* Detect panel marked for animation, if we're not already animating. */ | ||||
| if (panel_animation) { | if (panel_animation) { | ||||
| if (!no_animation) { | if (!no_animation) { | ||||
| *r_panel_animation = panel_animation; | *r_panel_animation = panel_animation; | ||||
| } | } | ||||
| return true; | return true; | ||||
| } | } | ||||
| return false; | return false; | ||||
| } | } | ||||
| /********* Functions for instanced panels. ***********/ | /** \} */ | ||||
| /* -------------------------------------------------------------------- */ | |||||
| /** \name Instanced panels | |||||
| * | |||||
| * Functions for polyinstantiated panels (multiple panels of one type). | |||||
| * Used for stack interfaces like modifiers. | |||||
| * \{ */ | |||||
| static Panel *UI_panel_add_instanced_ex(ScrArea *area, | static Panel *UI_panel_add_instanced_ex(ScrArea *area, | ||||
| ARegion *region, | ARegion *region, | ||||
| ListBase *panels, | ListBase *panels, | ||||
| PanelType *panel_type, | PanelType *panel_type, | ||||
| int list_index, | int list_index, | ||||
| PointerRNA *custom_data) | PointerRNA *custom_data) | ||||
| { | { | ||||
| ▲ Show 20 Lines • Show All 228 Lines • ▼ Show 20 Lines | if (panel->type) { | ||||
| if (panel->type->flag & PNL_INSTANCED) { | if (panel->type->flag & PNL_INSTANCED) { | ||||
| sort_index->panel = MEM_dupallocN(panel); | sort_index->panel = MEM_dupallocN(panel); | ||||
| sort_index->orig = panel; | sort_index->orig = panel; | ||||
| sort_index++; | sort_index++; | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| qsort(panel_sort, list_panels_len, sizeof(*panel_sort), compare_panel); | qsort(panel_sort, list_panels_len, sizeof(*panel_sort), compare_panel_sortorder); | ||||
| /* Find how many of those panels are above this panel. */ | /* Find how many of those panels are above this panel. */ | ||||
| int move_to_index = 0; | int move_to_index = 0; | ||||
| for (; move_to_index < list_panels_len; move_to_index++) { | for (; move_to_index < list_panels_len; move_to_index++) { | ||||
| if (panel_sort[move_to_index].orig == drag_panel) { | if (panel_sort[move_to_index].orig == drag_panel) { | ||||
| break; | break; | ||||
| } | } | ||||
| } | } | ||||
| ▲ Show 20 Lines • Show All 92 Lines • ▼ Show 20 Lines | |||||
| { | { | ||||
| LISTBASE_FOREACH (Panel *, panel, ®ion->panels) { | LISTBASE_FOREACH (Panel *, panel, ®ion->panels) { | ||||
| PanelType *panel_type = panel->type; | PanelType *panel_type = panel->type; | ||||
| if (panel_type == NULL) { | if (panel_type == NULL) { | ||||
| continue; | continue; | ||||
| } | } | ||||
| /* Check for #PNL_ACTIVE so we only set the expand flag for active panels. */ | /* Check for #PNL_ACTIVE so we only set the expand flag for active panels. */ | ||||
| if (panel_type->flag & PNL_INSTANCED && panel->runtime_flag & PNL_ACTIVE) { | if (panel_type->flag & PNL_INSTANCED && panel->runtime_flag & PANEL_ACTIVE) { | ||||
| short expand_flag = 0; /* Initialize to quite complaining compiler, value not used. */ | short expand_flag = 0; /* Initialize to quite complaining compiler, value not used. */ | ||||
| short flag_index = 0; | short flag_index = 0; | ||||
| get_panel_expand_flag(panel, &expand_flag, &flag_index); | get_panel_expand_flag(panel, &expand_flag, &flag_index); | ||||
| if (panel->type->set_list_data_expand_flag) { | if (panel->type->set_list_data_expand_flag) { | ||||
| panel->type->set_list_data_expand_flag(C, panel, expand_flag); | panel->type->set_list_data_expand_flag(C, panel, expand_flag); | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| /****************************** panels ******************************/ | /** \} */ | ||||
| /* -------------------------------------------------------------------- */ | |||||
| /** \name General Panel Functions | |||||
| * \{ */ | |||||
| /** | /** | ||||
| * Set flag state for a panel and its sub-panels. | * Set flag state for a panel and its sub-panels. | ||||
| * | * | ||||
| * \return True if this function changed any of the flags, false if it didn't. | * \return True if this function changed any of the flags, false if it didn't. | ||||
| */ | */ | ||||
| static bool panel_set_flag_recursive(Panel *panel, int flag, bool value) | static bool panel_set_flag_recursive(Panel *panel, int flag, bool value) | ||||
| { | { | ||||
| Show All 12 Lines | |||||
| static void panels_collapse_all(const bContext *C, | static void panels_collapse_all(const bContext *C, | ||||
| ScrArea *area, | ScrArea *area, | ||||
| ARegion *region, | ARegion *region, | ||||
| const Panel *from_panel) | const Panel *from_panel) | ||||
| { | { | ||||
| const bool has_category_tabs = UI_panel_category_is_visible(region); | const bool has_category_tabs = UI_panel_category_is_visible(region); | ||||
| const char *category = has_category_tabs ? UI_panel_category_active_get(region, false) : NULL; | const char *category = has_category_tabs ? UI_panel_category_active_get(region, false) : NULL; | ||||
| const int flag = ((panel_aligned(area, region) == BUT_HORIZONTAL) ? PNL_CLOSEDX : PNL_CLOSEDY); | const int flag = ((region_panel_alignment(area, region) == BUT_HORIZONTAL) ? PNL_CLOSEDX : | ||||
| PNL_CLOSEDY); | |||||
| const PanelType *from_pt = from_panel->type; | const PanelType *from_pt = from_panel->type; | ||||
| LISTBASE_FOREACH (Panel *, panel, ®ion->panels) { | LISTBASE_FOREACH (Panel *, panel, ®ion->panels) { | ||||
| PanelType *pt = panel->type; | PanelType *pt = panel->type; | ||||
| /* close panels with headers in the same context */ | /* Close panels with headers in the same context. */ | ||||
| if (pt && from_pt && !(pt->flag & PNL_NO_HEADER)) { | if (pt && from_pt && !(pt->flag & PNL_NO_HEADER)) { | ||||
| if (!pt->context[0] || !from_pt->context[0] || STREQ(pt->context, from_pt->context)) { | if (!pt->context[0] || !from_pt->context[0] || STREQ(pt->context, from_pt->context)) { | ||||
| if ((panel->flag & PNL_PIN) || !category || !pt->category[0] || | if ((panel->flag & PNL_PIN) || !category || !pt->category[0] || | ||||
| STREQ(pt->category, category)) { | STREQ(pt->category, category)) { | ||||
| panel->flag &= ~PNL_CLOSED; | panel->flag &= ~PNL_CLOSED; | ||||
| panel->flag |= flag; | panel->flag |= flag; | ||||
| } | } | ||||
| } | } | ||||
| Show All 32 Lines | Panel *UI_panel_begin(ScrArea *area, | ||||
| PanelType *pt, | PanelType *pt, | ||||
| Panel *panel, | Panel *panel, | ||||
| bool *r_open) | bool *r_open) | ||||
| { | { | ||||
| Panel *panel_last; | Panel *panel_last; | ||||
| const char *drawname = CTX_IFACE_(pt->translation_context, pt->label); | const char *drawname = CTX_IFACE_(pt->translation_context, pt->label); | ||||
| const char *idname = pt->idname; | const char *idname = pt->idname; | ||||
| const bool newpanel = (panel == NULL); | const bool newpanel = (panel == NULL); | ||||
| int align = panel_aligned(area, region); | int align = region_panel_alignment(area, region); | ||||
| if (!newpanel) { | if (!newpanel) { | ||||
| panel->type = pt; | panel->type = pt; | ||||
| } | } | ||||
| else { | else { | ||||
| /* new panel */ | /* New panel. */ | ||||
| panel = MEM_callocN(sizeof(Panel), "new panel"); | panel = MEM_callocN(sizeof(Panel), "new panel"); | ||||
| panel->type = pt; | panel->type = pt; | ||||
| BLI_strncpy(panel->panelname, idname, sizeof(panel->panelname)); | BLI_strncpy(panel->panelname, idname, sizeof(panel->panelname)); | ||||
| if (pt->flag & PNL_DEFAULT_CLOSED) { | if (pt->flag & PNL_DEFAULT_CLOSED) { | ||||
| if (align == BUT_VERTICAL) { | if (align == BUT_VERTICAL) { | ||||
| panel->flag |= PNL_CLOSEDY; | panel->flag |= PNL_CLOSEDY; | ||||
| } | } | ||||
| else { | else { | ||||
| panel->flag |= PNL_CLOSEDX; | panel->flag |= PNL_CLOSEDX; | ||||
| } | } | ||||
| } | } | ||||
| panel->ofsx = 0; | panel->ofsx = 0; | ||||
| panel->ofsy = 0; | panel->ofsy = 0; | ||||
| panel->sizex = 0; | panel->sizex = 0; | ||||
| panel->sizey = 0; | panel->sizey = 0; | ||||
| panel->blocksizex = 0; | panel->blocksizex = 0; | ||||
| panel->blocksizey = 0; | panel->blocksizey = 0; | ||||
| panel->runtime_flag |= PNL_NEW_ADDED; | panel->runtime_flag |= PANEL_NEW_ADDED; | ||||
| BLI_addtail(lb, panel); | BLI_addtail(lb, panel); | ||||
| } | } | ||||
| /* Do not allow closed panels without headers! Else user could get "disappeared" UI! */ | /* Do not allow closed panels without headers! Else user could get "disappeared" UI! */ | ||||
| if ((pt->flag & PNL_NO_HEADER) && (panel->flag & PNL_CLOSED)) { | if ((pt->flag & PNL_NO_HEADER) && (panel->flag & PNL_CLOSED)) { | ||||
| panel->flag &= ~PNL_CLOSED; | panel->flag &= ~PNL_CLOSED; | ||||
| /* Force update of panels' positions! */ | /* Force update of panels' positions! */ | ||||
| panel->sizex = 0; | panel->sizex = 0; | ||||
| panel->sizey = 0; | panel->sizey = 0; | ||||
| panel->blocksizex = 0; | panel->blocksizex = 0; | ||||
| panel->blocksizey = 0; | panel->blocksizey = 0; | ||||
| } | } | ||||
| BLI_strncpy(panel->drawname, drawname, sizeof(panel->drawname)); | BLI_strncpy(panel->drawname, drawname, sizeof(panel->drawname)); | ||||
| /* if a new panel is added, we insert it right after the panel | /* If a new panel is added, we insert it right after the panel | ||||
| * that was last added. this way new panels are inserted in the | * that was last added. this way new panels are inserted in the | ||||
| * right place between versions */ | * right place between versions. */ | ||||
| for (panel_last = lb->first; panel_last; panel_last = panel_last->next) { | for (panel_last = lb->first; panel_last; panel_last = panel_last->next) { | ||||
| if (panel_last->runtime_flag & PNL_LAST_ADDED) { | if (panel_last->runtime_flag & PANEL_LAST_ADDED) { | ||||
| BLI_remlink(lb, panel); | BLI_remlink(lb, panel); | ||||
| BLI_insertlinkafter(lb, panel_last, panel); | BLI_insertlinkafter(lb, panel_last, panel); | ||||
| break; | break; | ||||
| } | } | ||||
| } | } | ||||
| if (newpanel) { | if (newpanel) { | ||||
| panel->sortorder = (panel_last) ? panel_last->sortorder + 1 : 0; | panel->sortorder = (panel_last) ? panel_last->sortorder + 1 : 0; | ||||
| LISTBASE_FOREACH (Panel *, panel_next, lb) { | LISTBASE_FOREACH (Panel *, panel_next, lb) { | ||||
| if (panel_next != panel && panel_next->sortorder >= panel->sortorder) { | if (panel_next != panel && panel_next->sortorder >= panel->sortorder) { | ||||
| panel_next->sortorder++; | panel_next->sortorder++; | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| if (panel_last) { | if (panel_last) { | ||||
| panel_last->runtime_flag &= ~PNL_LAST_ADDED; | panel_last->runtime_flag &= ~PANEL_LAST_ADDED; | ||||
| } | } | ||||
| /* assign to block */ | /* Assign to block. */ | ||||
| block->panel = panel; | block->panel = panel; | ||||
| panel->runtime_flag |= PNL_ACTIVE | PNL_LAST_ADDED; | panel->runtime_flag |= PANEL_ACTIVE | PANEL_LAST_ADDED; | ||||
| if (region->alignment == RGN_ALIGN_FLOAT) { | if (region->alignment == RGN_ALIGN_FLOAT) { | ||||
| UI_block_theme_style_set(block, UI_BLOCK_THEME_STYLE_POPUP); | UI_block_theme_style_set(block, UI_BLOCK_THEME_STYLE_POPUP); | ||||
| } | } | ||||
| *r_open = false; | *r_open = false; | ||||
| if (panel->flag & PNL_CLOSED) { | if (panel->flag & PNL_CLOSED) { | ||||
| return panel; | return panel; | ||||
| } | } | ||||
| *r_open = true; | *r_open = true; | ||||
| return panel; | return panel; | ||||
| } | } | ||||
| static float panel_region_offset_x_get(const ARegion *region, int align) | static float region_panel_offset_x(const ARegion *region, int align) | ||||
| { | { | ||||
| if (UI_panel_category_is_visible(region)) { | if (UI_panel_category_is_visible(region)) { | ||||
| if (align == BUT_VERTICAL && | if (align == BUT_VERTICAL && | ||||
| (RGN_ALIGN_ENUM_FROM_MASK(region->alignment) != RGN_ALIGN_RIGHT)) { | (RGN_ALIGN_ENUM_FROM_MASK(region->alignment) != RGN_ALIGN_RIGHT)) { | ||||
| return UI_PANEL_CATEGORY_MARGIN_WIDTH; | return UI_PANEL_CATEGORY_MARGIN_WIDTH; | ||||
| } | } | ||||
| } | } | ||||
| return 0; | return 0; | ||||
| } | } | ||||
| void UI_panel_end( | void UI_panel_end( | ||||
| const ScrArea *area, const ARegion *region, uiBlock *block, int width, int height, bool open) | const ScrArea *area, const ARegion *region, uiBlock *block, int width, int height, bool open) | ||||
| { | { | ||||
| Panel *panel = block->panel; | Panel *panel = block->panel; | ||||
| /* Set panel size excluding children. */ | /* Set panel size excluding children. */ | ||||
| panel->blocksizex = width; | panel->blocksizex = width; | ||||
| panel->blocksizey = height; | panel->blocksizey = height; | ||||
| /* Compute total panel size including children. */ | /* Compute total panel size including children. */ | ||||
| LISTBASE_FOREACH (Panel *, pachild, &panel->children) { | LISTBASE_FOREACH (Panel *, pachild, &panel->children) { | ||||
| if (pachild->runtime_flag & PNL_ACTIVE) { | if (pachild->runtime_flag & PANEL_ACTIVE) { | ||||
| width = max_ii(width, pachild->sizex); | width = max_ii(width, pachild->sizex); | ||||
| height += get_panel_real_size_y(pachild); | height += panel_size_real_y(pachild); | ||||
| } | } | ||||
| } | } | ||||
| /* Update total panel size. */ | /* Update total panel size. */ | ||||
| if (panel->runtime_flag & PNL_NEW_ADDED) { | if (panel->runtime_flag & PANEL_NEW_ADDED) { | ||||
| panel->runtime_flag &= ~PNL_NEW_ADDED; | panel->runtime_flag &= ~PANEL_NEW_ADDED; | ||||
| panel->sizex = width; | panel->sizex = width; | ||||
| panel->sizey = height; | panel->sizey = height; | ||||
| } | } | ||||
| else { | else { | ||||
| int old_sizex = panel->sizex, old_sizey = panel->sizey; | int old_sizex = panel->sizex, old_sizey = panel->sizey; | ||||
| int old_region_ofsx = panel->runtime.region_ofsx; | int old_region_ofsx = panel->runtime.region_ofsx; | ||||
| /* update width/height if non-zero */ | /* Update width/height if non-zero. */ | ||||
| if (width != 0) { | if (width != 0) { | ||||
| panel->sizex = width; | panel->sizex = width; | ||||
| } | } | ||||
| if (height != 0 || open) { | if (height != 0 || open) { | ||||
| panel->sizey = height; | panel->sizey = height; | ||||
| } | } | ||||
| /* check if we need to do an animation */ | /* Check if we need to do an animation. */ | ||||
| if (panel->sizex != old_sizex || panel->sizey != old_sizey) { | if (panel->sizex != old_sizex || panel->sizey != old_sizey) { | ||||
| panel->runtime_flag |= PNL_ANIM_ALIGN; | panel->runtime_flag |= PANEL_ANIM_ALIGN; | ||||
| panel->ofsy += old_sizey - panel->sizey; | panel->ofsy += old_sizey - panel->sizey; | ||||
| } | } | ||||
| int align = panel_aligned(area, region); | int align = region_panel_alignment(area, region); | ||||
| panel->runtime.region_ofsx = panel_region_offset_x_get(region, align); | panel->runtime.region_ofsx = region_panel_offset_x(region, align); | ||||
| if (old_region_ofsx != panel->runtime.region_ofsx) { | if (old_region_ofsx != panel->runtime.region_ofsx) { | ||||
| panel->runtime_flag |= PNL_ANIM_ALIGN; | panel->runtime_flag |= PANEL_ANIM_ALIGN; | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| static void ui_offset_panel_block(uiBlock *block) | static void offset_panel_block(uiBlock *block) | ||||
| { | { | ||||
| const uiStyle *style = UI_style_get_dpi(); | const uiStyle *style = UI_style_get_dpi(); | ||||
| /* compute bounds and offset */ | /* Compute bounds and offset. */ | ||||
| ui_block_bounds_calc(block); | ui_block_bounds_calc(block); | ||||
| int ofsy = block->panel->sizey - style->panelspace; | int ofsy = block->panel->sizey - style->panelspace; | ||||
| LISTBASE_FOREACH (uiBut *, but, &block->buttons) { | LISTBASE_FOREACH (uiBut *, but, &block->buttons) { | ||||
| but->rect.ymin += ofsy; | but->rect.ymin += ofsy; | ||||
| but->rect.ymax += ofsy; | but->rect.ymax += ofsy; | ||||
| } | } | ||||
| block->rect.xmax = block->panel->sizex; | block->rect.xmax = block->panel->sizex; | ||||
| block->rect.ymax = block->panel->sizey; | block->rect.ymax = block->panel->sizey; | ||||
| block->rect.xmin = block->rect.ymin = 0.0; | block->rect.xmin = block->rect.ymin = 0.0; | ||||
| } | } | ||||
| /**************************** drawing *******************************/ | /** \} */ | ||||
| /* -------------------------------------------------------------------- */ | |||||
| /** \name Panel Drawing | |||||
| * \{ */ | |||||
| #define PNL_ICON UI_UNIT_X /* Could be UI_UNIT_Y too. */ | |||||
| /* triangle 'icon' for panel header */ | /** | ||||
| * Draw the triangle 'icon' for panel headers. | |||||
| */ | |||||
| void UI_draw_icon_tri(float x, float y, char dir, const float color[4]) | void UI_draw_icon_tri(float x, float y, char dir, const float color[4]) | ||||
| { | { | ||||
| float f3 = 0.05 * U.widget_unit; | float f3 = 0.05 * U.widget_unit; | ||||
| float f5 = 0.15 * U.widget_unit; | float f5 = 0.15 * U.widget_unit; | ||||
| float f7 = 0.25 * U.widget_unit; | float f7 = 0.25 * U.widget_unit; | ||||
| if (dir == 'h') { | if (dir == 'h') { | ||||
| UI_draw_anti_tria(x - f3, y - f5, x - f3, y + f5, x + f7, y, color); | UI_draw_anti_tria(x - f3, y - f5, x - f3, y + f5, x + f7, y, color); | ||||
| } | } | ||||
| else if (dir == 't') { | else if (dir == 't') { | ||||
| UI_draw_anti_tria(x - f5, y - f7, x + f5, y - f7, x, y + f3, color); | UI_draw_anti_tria(x - f5, y - f7, x + f5, y - f7, x, y + f3, color); | ||||
| } | } | ||||
| else { /* 'v' = vertical, down */ | else { /* 'v' = vertical, down. */ | ||||
| UI_draw_anti_tria(x - f5, y + f3, x + f5, y + f3, x, y - f7, color); | UI_draw_anti_tria(x - f5, y + f3, x + f5, y + f3, x, y - f7, color); | ||||
| } | } | ||||
| } | } | ||||
| #define PNL_ICON UI_UNIT_X /* could be UI_UNIT_Y too */ | /** | ||||
| * Get the offset for button layout next to header labels. | |||||
| /* For button layout next to label. */ | */ | ||||
| void UI_panel_label_offset(uiBlock *block, int *r_x, int *r_y) | void UI_panel_label_offset(uiBlock *block, int *r_x, int *r_y) | ||||
| { | { | ||||
| Panel *panel = block->panel; | Panel *panel = block->panel; | ||||
| const bool is_subpanel = (panel->type && panel->type->parent); | const bool is_subpanel = (panel->type && panel->type->parent); | ||||
| *r_x = UI_UNIT_X * 1.0f; | *r_x = UI_UNIT_X * 1.0f; | ||||
| *r_y = UI_UNIT_Y * 1.5f; | *r_y = UI_UNIT_Y * 1.5f; | ||||
| if (is_subpanel) { | if (is_subpanel) { | ||||
| *r_x += (0.7f * UI_UNIT_X); | *r_x += (0.7f * UI_UNIT_X); | ||||
| } | } | ||||
| } | } | ||||
| static void ui_draw_aligned_panel_header( | static void panel_draw_header_aligned( | ||||
| uiStyle *style, uiBlock *block, const rcti *rect, char dir, const bool show_background) | uiStyle *style, uiBlock *block, const rcti *rect, char dir, const bool show_background) | ||||
| { | { | ||||
| Panel *panel = block->panel; | Panel *panel = block->panel; | ||||
| rcti hrect; | rcti hrect; | ||||
| int pnl_icons; | int pnl_icons; | ||||
| const char *activename = panel->drawname; | const char *activename = panel->drawname; | ||||
| const bool is_subpanel = (panel->type && panel->type->parent); | const bool is_subpanel = (panel->type && panel->type->parent); | ||||
| uiFontStyle *fontstyle = (is_subpanel) ? &style->widgetlabel : &style->paneltitle; | uiFontStyle *fontstyle = (is_subpanel) ? &style->widgetlabel : &style->paneltitle; | ||||
| uchar col_title[4]; | uchar col_title[4]; | ||||
| /* + 0.001f to avoid flirting with float inaccuracy */ | /* Add 0.001f to avoid flirting with float inaccuracy. */ | ||||
| pnl_icons = (panel->labelofs + (1.1f * PNL_ICON)) / block->aspect + 0.001f; | pnl_icons = (panel->labelofs + (1.1f * PNL_ICON)) / block->aspect + 0.001f; | ||||
| /* draw text label */ | /* Draw text label. */ | ||||
| panel_title_color_get(show_background, col_title); | panel_title_color_get(show_background, col_title); | ||||
| col_title[3] = 255; | col_title[3] = 255; | ||||
| hrect = *rect; | hrect = *rect; | ||||
| if (dir == 'h') { | if (dir == 'h') { | ||||
| hrect.xmin = rect->xmin + pnl_icons; | hrect.xmin = rect->xmin + pnl_icons; | ||||
| hrect.ymin -= 2.0f / block->aspect; | hrect.ymin -= 2.0f / block->aspect; | ||||
| UI_fontstyle_draw(fontstyle, | UI_fontstyle_draw(fontstyle, | ||||
| &hrect, | &hrect, | ||||
| activename, | activename, | ||||
| col_title, | col_title, | ||||
| &(struct uiFontStyleDraw_Params){ | &(struct uiFontStyleDraw_Params){ | ||||
| .align = UI_STYLE_TEXT_LEFT, | .align = UI_STYLE_TEXT_LEFT, | ||||
| }); | }); | ||||
| } | } | ||||
| else { | else { | ||||
| /* ignore 'pnl_icons', otherwise the text gets offset horizontally | /* Ignore 'pnl_icons', otherwise the text gets offset horizontally. | ||||
| * + 0.001f to avoid flirting with float inaccuracy | * Add 0.001f to avoid flirting with float inaccuracy. */ | ||||
| */ | |||||
| hrect.xmin = rect->xmin + (PNL_ICON + 5) / block->aspect + 0.001f; | hrect.xmin = rect->xmin + (PNL_ICON + 5) / block->aspect + 0.001f; | ||||
| UI_fontstyle_draw_rotated(fontstyle, &hrect, activename, col_title); | UI_fontstyle_draw_rotated(fontstyle, &hrect, activename, col_title); | ||||
| } | } | ||||
| } | } | ||||
| /* panel integrated in buttonswindow, tool/property lists etc */ | /** | ||||
| void ui_draw_aligned_panel(uiStyle *style, | * Draw panel integrated in buttons window, tool/property lists etc. | ||||
| */ | |||||
| void ui_panel_draw_aligned(uiStyle *style, | |||||
| uiBlock *block, | uiBlock *block, | ||||
| const rcti *rect, | const rcti *rect, | ||||
| const bool show_pin, | const bool show_pin, | ||||
| const bool show_background) | const bool show_background) | ||||
| { | { | ||||
| Panel *panel = block->panel; | Panel *panel = block->panel; | ||||
| rctf itemrect; | rctf itemrect; | ||||
| float color[4]; | float color[4]; | ||||
| const bool is_closed_x = (panel->flag & PNL_CLOSEDX) ? true : false; | const bool is_closed_x = (panel->flag & PNL_CLOSEDX) ? true : false; | ||||
| const bool is_closed_y = (panel->flag & PNL_CLOSEDY) ? true : false; | const bool is_closed_y = (panel->flag & PNL_CLOSEDY) ? true : false; | ||||
| const bool is_subpanel = (panel->type && panel->type->parent); | const bool is_subpanel = (panel->type && panel->type->parent); | ||||
| const bool show_drag = (!is_subpanel && | |||||
| /* FIXME(campbell): currently no background means floating panel which | /* FIXME(campbell): currently no background means floating panel which | ||||
| * can't be dragged. This may be changed in future. */ | * can't be dragged. This may be changed in future. */ | ||||
| show_background); | const bool show_drag = (!is_subpanel && show_background); | ||||
| const int panel_col = is_subpanel ? TH_PANEL_SUB_BACK : TH_PANEL_BACK; | const int panel_col = is_subpanel ? TH_PANEL_SUB_BACK : TH_PANEL_BACK; | ||||
| const bool draw_box_style = (panel->type && panel->type->flag & PNL_DRAW_BOX); | const bool draw_box_style = (panel->type && panel->type->flag & PNL_DRAW_BOX); | ||||
| /* Use the theme for box widgets for box-style panels. */ | /* Use the theme for box widgets for box-style panels. */ | ||||
| uiWidgetColors *box_wcol = NULL; | uiWidgetColors *box_wcol = NULL; | ||||
| if (draw_box_style) { | if (draw_box_style) { | ||||
| bTheme *btheme = UI_GetTheme(); | bTheme *btheme = UI_GetTheme(); | ||||
| box_wcol = &btheme->tui.wcol_box; | box_wcol = &btheme->tui.wcol_box; | ||||
| } | } | ||||
| uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT); | uint pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT); | ||||
| if (panel->type && (panel->type->flag & PNL_NO_HEADER)) { | if (panel->type && (panel->type->flag & PNL_NO_HEADER)) { | ||||
| if (show_background) { | if (show_background) { | ||||
| immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); | immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); | ||||
| immUniformThemeColor(panel_col); | immUniformThemeColor(panel_col); | ||||
| immRectf(pos, rect->xmin, rect->ymin, rect->xmax, rect->ymax); | immRectf(pos, rect->xmin, rect->ymin, rect->xmax, rect->ymax); | ||||
| immUnbindProgram(); | immUnbindProgram(); | ||||
| } | } | ||||
| return; | return; | ||||
| } | } | ||||
| /* Calculate header rect with + 0.001f to prevent flicker due to float inaccuracy */ | /* Calculate header rect with + 0.001f to prevent flicker due to float inaccuracy. */ | ||||
| rcti headrect = { | rcti headrect = { | ||||
| rect->xmin, rect->xmax, rect->ymax, rect->ymax + floor(PNL_HEADER / block->aspect + 0.001f)}; | rect->xmin, rect->xmax, rect->ymax, rect->ymax + floor(PNL_HEADER / block->aspect + 0.001f)}; | ||||
| /* Draw a panel and header backdrops with an opaque box backdrop for box style panels. */ | /* Draw a panel and header backdrops with an opaque box backdrop for box style panels. */ | ||||
| if (draw_box_style && !is_subpanel) { | if (draw_box_style && !is_subpanel) { | ||||
| /* Expand the top a tiny bit to give header buttons equal size above and below. */ | /* Expand the top a tiny bit to give header buttons equal size above and below. */ | ||||
| rcti box_rect = {rect->xmin, | rcti box_rect = {rect->xmin, | ||||
| rect->xmax, | rect->xmax, | ||||
| Show All 26 Lines | void ui_panel_draw_aligned(uiStyle *style, | ||||
| if (show_background && !is_subpanel && !draw_box_style) { | if (show_background && !is_subpanel && !draw_box_style) { | ||||
| float minx = rect->xmin; | float minx = rect->xmin; | ||||
| float maxx = is_closed_x ? (minx + PNL_HEADER / block->aspect) : rect->xmax; | float maxx = is_closed_x ? (minx + PNL_HEADER / block->aspect) : rect->xmax; | ||||
| float y = headrect.ymax; | float y = headrect.ymax; | ||||
| immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); | immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); | ||||
| GPU_blend(true); | GPU_blend(true); | ||||
| /* draw with background color */ | /* Draw with background color. */ | ||||
| immUniformThemeColor(TH_PANEL_HEADER); | immUniformThemeColor(TH_PANEL_HEADER); | ||||
| immRectf(pos, minx, headrect.ymin, maxx, y); | immRectf(pos, minx, headrect.ymin, maxx, y); | ||||
| immBegin(GPU_PRIM_LINES, 4); | immBegin(GPU_PRIM_LINES, 4); | ||||
| immVertex2f(pos, minx, y); | immVertex2f(pos, minx, y); | ||||
| immVertex2f(pos, maxx, y); | immVertex2f(pos, maxx, y); | ||||
| immVertex2f(pos, minx, y); | immVertex2f(pos, minx, y); | ||||
| immVertex2f(pos, maxx, y); | immVertex2f(pos, maxx, y); | ||||
| immEnd(); | immEnd(); | ||||
| GPU_blend(false); | GPU_blend(false); | ||||
| immUnbindProgram(); | immUnbindProgram(); | ||||
| } | } | ||||
| /* draw optional pin icon */ | /* Draw optional pin icon. */ | ||||
| #ifdef USE_PIN_HIDDEN | #ifdef USE_PIN_HIDDEN | ||||
| if (show_pin && (block->panel->flag & PNL_PIN)) | if (show_pin && (block->panel->flag & PNL_PIN)) | ||||
| #else | #else | ||||
| if (show_pin) | if (show_pin) | ||||
| #endif | #endif | ||||
| { | { | ||||
| uchar col_title[4]; | uchar col_title[4]; | ||||
| panel_title_color_get(show_background, col_title); | panel_title_color_get(show_background, col_title); | ||||
| GPU_blend(true); | GPU_blend(true); | ||||
| UI_icon_draw_ex(headrect.xmax - ((PNL_ICON * 2.2f) / block->aspect), | UI_icon_draw_ex(headrect.xmax - ((PNL_ICON * 2.2f) / block->aspect), | ||||
| headrect.ymin + (5.0f / block->aspect), | headrect.ymin + (5.0f / block->aspect), | ||||
| (panel->flag & PNL_PIN) ? ICON_PINNED : ICON_UNPINNED, | (panel->flag & PNL_PIN) ? ICON_PINNED : ICON_UNPINNED, | ||||
| (block->aspect * U.inv_dpi_fac), | (block->aspect * U.inv_dpi_fac), | ||||
| 1.0f, | 1.0f, | ||||
| 0.0f, | 0.0f, | ||||
| col_title, | col_title, | ||||
| false); | false); | ||||
| GPU_blend(false); | GPU_blend(false); | ||||
| } | } | ||||
| /* horizontal title */ | /* Horizontal title. */ | ||||
| rcti titlerect = headrect; | rcti titlerect = headrect; | ||||
| if (is_subpanel) { | if (is_subpanel) { | ||||
| titlerect.xmin += (0.7f * UI_UNIT_X) / block->aspect + 0.001f; | titlerect.xmin += (0.7f * UI_UNIT_X) / block->aspect + 0.001f; | ||||
| } | } | ||||
| if (is_closed_x == false) { | if (is_closed_x == false) { | ||||
| ui_draw_aligned_panel_header(style, block, &titlerect, 'h', show_background); | panel_draw_header_aligned(style, block, &titlerect, 'h', show_background); | ||||
| if (show_drag) { | if (show_drag) { | ||||
| /* itemrect smaller */ | /* Itemrect smaller. */ | ||||
| const float scale = 0.7; | const float scale = 0.7; | ||||
| itemrect.xmax = headrect.xmax - (0.2f * UI_UNIT_X); | itemrect.xmax = headrect.xmax - (0.2f * UI_UNIT_X); | ||||
| itemrect.xmin = itemrect.xmax - BLI_rcti_size_y(&headrect); | itemrect.xmin = itemrect.xmax - BLI_rcti_size_y(&headrect); | ||||
| itemrect.ymin = headrect.ymin; | itemrect.ymin = headrect.ymin; | ||||
| itemrect.ymax = headrect.ymax; | itemrect.ymax = headrect.ymax; | ||||
| BLI_rctf_scale(&itemrect, scale); | BLI_rctf_scale(&itemrect, scale); | ||||
| GPU_matrix_push(); | GPU_matrix_push(); | ||||
| Show All 9 Lines | if (show_drag) { | ||||
| GPU_batch_program_set_builtin(batch, GPU_SHADER_2D_FLAT_COLOR); | GPU_batch_program_set_builtin(batch, GPU_SHADER_2D_FLAT_COLOR); | ||||
| GPU_batch_draw(batch); | GPU_batch_draw(batch); | ||||
| GPU_matrix_pop(); | GPU_matrix_pop(); | ||||
| } | } | ||||
| } | } | ||||
| /* Draw panel backdrop. */ | /* Draw panel backdrop. */ | ||||
| if (is_closed_y) { | if (is_closed_y) { | ||||
| /* skip */ | /* Skip. */ | ||||
| } | } | ||||
| else if (is_closed_x) { | else if (is_closed_x) { | ||||
| /* draw vertical title */ | /* Draw vertical title. */ | ||||
| ui_draw_aligned_panel_header(style, block, &headrect, 'v', show_background); | panel_draw_header_aligned(style, block, &headrect, 'v', show_background); | ||||
| pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT); | pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT); | ||||
| } | } | ||||
| /* an open panel */ | /* An open panel. */ | ||||
| else { | else { | ||||
| /* in some occasions, draw a border */ | /* Draw a border while panel is selected (dragging). */ | ||||
| if (panel->flag & PNL_SELECT && !is_subpanel) { | if (panel->flag & PNL_SELECT && !is_subpanel) { | ||||
| float radius; | float radius; | ||||
| if (draw_box_style) { | if (draw_box_style) { | ||||
| UI_draw_roundbox_corner_set(UI_CNR_ALL); | UI_draw_roundbox_corner_set(UI_CNR_ALL); | ||||
| radius = box_wcol->roundness * U.widget_unit; | radius = box_wcol->roundness * U.widget_unit; | ||||
| } | } | ||||
| else { | else { | ||||
| UI_draw_roundbox_corner_set(UI_CNR_NONE); | UI_draw_roundbox_corner_set(UI_CNR_NONE); | ||||
| ▲ Show 20 Lines • Show All 43 Lines • ▼ Show 20 Lines | else { | ||||
| } | } | ||||
| immUnbindProgram(); | immUnbindProgram(); | ||||
| } | } | ||||
| uchar col_title[4]; | uchar col_title[4]; | ||||
| panel_title_color_get(show_background, col_title); | panel_title_color_get(show_background, col_title); | ||||
| /* draw collapse icon */ | /* Draw collapse icon. */ | ||||
| /* itemrect smaller */ | |||||
| itemrect.xmin = titlerect.xmin; | itemrect.xmin = titlerect.xmin; | ||||
| itemrect.xmax = itemrect.xmin + BLI_rcti_size_y(&titlerect); | itemrect.xmax = itemrect.xmin + BLI_rcti_size_y(&titlerect); | ||||
| itemrect.ymin = titlerect.ymin; | itemrect.ymin = titlerect.ymin; | ||||
| itemrect.ymax = titlerect.ymax; | itemrect.ymax = titlerect.ymax; | ||||
| BLI_rctf_scale(&itemrect, 0.25f); | BLI_rctf_scale(&itemrect, 0.25f); | ||||
| { | { | ||||
| float tria_color[4]; | float tria_color[4]; | ||||
| rgb_uchar_to_float(tria_color, col_title); | rgb_uchar_to_float(tria_color, col_title); | ||||
| tria_color[3] = 1.0f; | tria_color[3] = 1.0f; | ||||
| if (is_closed_y) { | if (is_closed_y) { | ||||
| ui_draw_anti_tria_rect(&itemrect, 'h', tria_color); | ui_draw_anti_tria_rect(&itemrect, 'h', tria_color); | ||||
| } | } | ||||
| else if (is_closed_x) { | else if (is_closed_x) { | ||||
| ui_draw_anti_tria_rect(&itemrect, 'h', tria_color); | ui_draw_anti_tria_rect(&itemrect, 'h', tria_color); | ||||
| } | } | ||||
| else { | else { | ||||
| ui_draw_anti_tria_rect(&itemrect, 'v', tria_color); | ui_draw_anti_tria_rect(&itemrect, 'v', tria_color); | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| /************************** panel alignment *************************/ | /** \} */ | ||||
| /* -------------------------------------------------------------------- */ | |||||
| /** \name Panel Alignment | |||||
| * | |||||
| * Deals with sorting and placing panels and their uiBlocks. Panels are ordered | |||||
| * by #sortorder rather than the order of the list. | |||||
| * \{ */ | |||||
| static int get_panel_header(const Panel *panel) | static int panel_header_size(const Panel *panel) | ||||
| { | { | ||||
| if (panel->type && (panel->type->flag & PNL_NO_HEADER)) { | if (panel->type && (panel->type->flag & PNL_NO_HEADER)) { | ||||
| return 0; | return 0; | ||||
| } | } | ||||
| return PNL_HEADER; | return PNL_HEADER; | ||||
| } | } | ||||
| static int get_panel_size_y(const Panel *panel) | static int panel_size_y(const Panel *panel) | ||||
| { | { | ||||
| if (panel->type && (panel->type->flag & PNL_NO_HEADER)) { | if (panel->type && (panel->type->flag & PNL_NO_HEADER)) { | ||||
| return panel->sizey; | return panel->sizey; | ||||
| } | } | ||||
| return PNL_HEADER + panel->sizey; | return PNL_HEADER + panel->sizey; | ||||
| } | } | ||||
| static int get_panel_real_size_y(const Panel *panel) | /** | ||||
| * Get the size of the panel, accounting for whether it's open or not. | |||||
| */ | |||||
| static int panel_size_real_y(const Panel *panel) | |||||
| { | { | ||||
| int sizey = (panel->flag & PNL_CLOSED) ? 0 : panel->sizey; | int sizey = (panel->flag & PNL_CLOSED) ? 0 : panel->sizey; | ||||
| if (panel->type && (panel->type->flag & PNL_NO_HEADER)) { | if (panel->type && (panel->type->flag & PNL_NO_HEADER)) { | ||||
| return sizey; | return sizey; | ||||
| } | } | ||||
| return PNL_HEADER + sizey; | return PNL_HEADER + sizey; | ||||
| } | } | ||||
| int UI_panel_size_y(const Panel *panel) | int UI_panel_size_y(const Panel *panel) | ||||
| { | { | ||||
| return get_panel_real_size_y(panel); | return panel_size_real_y(panel); | ||||
| } | } | ||||
| /* this function is needed because uiBlock and Panel itself don't | /** | ||||
| * change sizey or location when closed */ | * This function is needed because uiBlock and Panel don't | ||||
| static int get_panel_real_ofsy(Panel *panel) | * change their sizey or location values when closed. | ||||
| */ | |||||
| static int panel_offset_real_y(Panel *panel) | |||||
| { | { | ||||
| if (panel->flag & PNL_CLOSEDY) { | if (panel->flag & PNL_CLOSEDY) { | ||||
| return panel->ofsy + panel->sizey; | return panel->ofsy + panel->sizey; | ||||
| } | } | ||||
| return panel->ofsy; | return panel->ofsy; | ||||
| } | } | ||||
| static int get_panel_real_ofsx(Panel *panel) | static int panel_offset_real_x(Panel *panel) | ||||
| { | { | ||||
| if (panel->flag & PNL_CLOSEDX) { | if (panel->flag & PNL_CLOSEDX) { | ||||
| return panel->ofsx + get_panel_header(panel); | return panel->ofsx + panel_header_size(panel); | ||||
| } | } | ||||
| return panel->ofsx + panel->sizex; | return panel->ofsx + panel->sizex; | ||||
| } | } | ||||
| bool UI_panel_is_dragging(const struct Panel *panel) | bool UI_panel_is_dragging(const struct Panel *panel) | ||||
| { | { | ||||
| uiHandlePanelData *data = panel->activedata; | uiHandlePanelData *data = panel->activedata; | ||||
| if (!data) { | if (!data) { | ||||
| return false; | return false; | ||||
| } | } | ||||
| return data->is_drag_drop; | return data->is_drag_drop; | ||||
| } | } | ||||
| /** | /** | ||||
| * \note about sorting; | * \note About sorting: | ||||
| * the sortorder has a lower value for new panels being added. | * 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 | * However, that only works to insert a single panel; when more new panels get added | ||||
| * added the coordinates of existing panels and the previously stored to-be-inserted | * the coordinates of existing panels and the previously stored to-be-inserted panels | ||||
| * panels do not match for sorting | * do not match for sorting. | ||||
| */ | */ | ||||
| static int find_leftmost_panel(const void *a1, const void *a2) | static int find_leftmost_panel(const void *a1, const void *a2) | ||||
| { | { | ||||
| const PanelSort *ps1 = a1, *ps2 = a2; | const PanelSort *ps1 = a1, *ps2 = a2; | ||||
| if (ps1->panel->ofsx > ps2->panel->ofsx) { | if (ps1->panel->ofsx > ps2->panel->ofsx) { | ||||
| return 1; | return 1; | ||||
| Show All 10 Lines | static int find_leftmost_panel(const void *a1, const void *a2) | ||||
| return 0; | return 0; | ||||
| } | } | ||||
| static int find_highest_panel(const void *a1, const void *a2) | static int find_highest_panel(const void *a1, const void *a2) | ||||
| { | { | ||||
| const PanelSort *ps1 = a1, *ps2 = a2; | const PanelSort *ps1 = a1, *ps2 = a2; | ||||
| /* stick uppermost header-less panels to the top of the region - | /* Stick uppermost header-less panels to the top of the region, preventing them | ||||
| * prevent them from being sorted (multiple header-less panels have to be sorted though) */ | * from being sorted (multiple header-less panels have to be sorted though). */ | ||||
| if (ps1->panel->type->flag & PNL_NO_HEADER && ps2->panel->type->flag & PNL_NO_HEADER) { | if (ps1->panel->type->flag & PNL_NO_HEADER && ps2->panel->type->flag & PNL_NO_HEADER) { | ||||
| /* skip and check for ofs and sortorder below */ | /* Skip and check for ofs and sortorder below. */ | ||||
| } | } | ||||
| if (ps1->panel->type->flag & PNL_NO_HEADER) { | if (ps1->panel->type->flag & PNL_NO_HEADER) { | ||||
| return -1; | return -1; | ||||
| } | } | ||||
| if (ps2->panel->type->flag & PNL_NO_HEADER) { | if (ps2->panel->type->flag & PNL_NO_HEADER) { | ||||
| return 1; | return 1; | ||||
| } | } | ||||
| if (ps1->panel->ofsy + ps1->panel->sizey < ps2->panel->ofsy + ps2->panel->sizey) { | if (ps1->panel->ofsy + ps1->panel->sizey < ps2->panel->ofsy + ps2->panel->sizey) { | ||||
| return 1; | return 1; | ||||
| } | } | ||||
| if (ps1->panel->ofsy + ps1->panel->sizey > ps2->panel->ofsy + ps2->panel->sizey) { | if (ps1->panel->ofsy + ps1->panel->sizey > ps2->panel->ofsy + ps2->panel->sizey) { | ||||
| return -1; | return -1; | ||||
| } | } | ||||
| if (ps1->panel->sortorder > ps2->panel->sortorder) { | if (ps1->panel->sortorder > ps2->panel->sortorder) { | ||||
| return 1; | return 1; | ||||
| } | } | ||||
| if (ps1->panel->sortorder < ps2->panel->sortorder) { | if (ps1->panel->sortorder < ps2->panel->sortorder) { | ||||
| return -1; | return -1; | ||||
| } | } | ||||
| return 0; | return 0; | ||||
| } | } | ||||
| static int compare_panel(const void *a1, const void *a2) | static int compare_panel_sortorder(const void *a1, const void *a2) | ||||
| { | { | ||||
| const PanelSort *ps1 = a1, *ps2 = a2; | const PanelSort *ps1 = a1, *ps2 = a2; | ||||
| if (ps1->panel->sortorder > ps2->panel->sortorder) { | if (ps1->panel->sortorder > ps2->panel->sortorder) { | ||||
| return 1; | return 1; | ||||
| } | } | ||||
| if (ps1->panel->sortorder < ps2->panel->sortorder) { | if (ps1->panel->sortorder < ps2->panel->sortorder) { | ||||
| return -1; | return -1; | ||||
| } | } | ||||
| return 0; | return 0; | ||||
| } | } | ||||
| /** | |||||
| * Position a panel's sub panels. | |||||
| */ | |||||
| static void align_sub_panels(Panel *panel) | static void align_sub_panels(Panel *panel) | ||||
| { | { | ||||
| /* Position sub panels. */ | |||||
| int ofsy = panel->ofsy + panel->sizey - panel->blocksizey; | int ofsy = panel->ofsy + panel->sizey - panel->blocksizey; | ||||
| LISTBASE_FOREACH (Panel *, pachild, &panel->children) { | LISTBASE_FOREACH (Panel *, pachild, &panel->children) { | ||||
| if (pachild->runtime_flag & PNL_ACTIVE) { | if (pachild->runtime_flag & PANEL_ACTIVE) { | ||||
| pachild->ofsx = panel->ofsx; | pachild->ofsx = panel->ofsx; | ||||
| pachild->ofsy = ofsy - get_panel_size_y(pachild); | pachild->ofsy = ofsy - panel_size_y(pachild); | ||||
| ofsy -= get_panel_real_size_y(pachild); | ofsy -= panel_size_real_y(pachild); | ||||
| if (pachild->children.first) { | if (pachild->children.first) { | ||||
| align_sub_panels(pachild); | align_sub_panels(pachild); | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| /* this doesn't draw */ | /** | ||||
| /* returns 1 when it did something */ | * Run one step of the panel alignment. | ||||
| static bool uiAlignPanelStep(ScrArea *area, ARegion *region, const float fac, const bool drag) | * | ||||
| * \param fac Controls how much to interpolate to the goal locations. | |||||
| * | |||||
| * \note This function doesn't draw. | |||||
| * \return True when it made a change. | |||||
| */ | |||||
| static bool panels_align_step(ScrArea *area, ARegion *region, const float fac, const bool drag) | |||||
| { | { | ||||
| PanelSort *ps, *panelsort, *psnext; | PanelSort *ps, *panelsort, *psnext; | ||||
| int a, tot = 0; | int a, tot = 0; | ||||
| bool done; | bool done; | ||||
| int align = panel_aligned(area, region); | int align = region_panel_alignment(area, region); | ||||
| /* count active, not tabbed panels */ | /* Count active panels. */ | ||||
| LISTBASE_FOREACH (Panel *, panel, ®ion->panels) { | LISTBASE_FOREACH (Panel *, panel, ®ion->panels) { | ||||
| if (panel->runtime_flag & PNL_ACTIVE) { | if (panel->runtime_flag & PANEL_ACTIVE) { | ||||
| tot++; | tot++; | ||||
| } | } | ||||
| } | } | ||||
| if (tot == 0) { | if (tot == 0) { | ||||
| return 0; | return false; | ||||
| } | } | ||||
| /* extra; change close direction? */ | /* Extra: possibly change close direction. */ | ||||
| LISTBASE_FOREACH (Panel *, panel, ®ion->panels) { | LISTBASE_FOREACH (Panel *, panel, ®ion->panels) { | ||||
| if (panel->runtime_flag & PNL_ACTIVE) { | if (panel->runtime_flag & PANEL_ACTIVE) { | ||||
| if ((panel->flag & PNL_CLOSEDX) && (align == BUT_VERTICAL)) { | if ((panel->flag & PNL_CLOSEDX) && (align == BUT_VERTICAL)) { | ||||
| panel->flag ^= PNL_CLOSED; | panel->flag ^= PNL_CLOSED; | ||||
| } | } | ||||
| else if ((panel->flag & PNL_CLOSEDY) && (align == BUT_HORIZONTAL)) { | else if ((panel->flag & PNL_CLOSEDY) && (align == BUT_HORIZONTAL)) { | ||||
| panel->flag ^= PNL_CLOSED; | panel->flag ^= PNL_CLOSED; | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| /* sort panels */ | /* Sort panels. */ | ||||
| panelsort = MEM_callocN(tot * sizeof(PanelSort), "panelsort"); | panelsort = MEM_callocN(tot * sizeof(PanelSort), "panelsort"); | ||||
| ps = panelsort; | ps = panelsort; | ||||
| LISTBASE_FOREACH (Panel *, panel, ®ion->panels) { | LISTBASE_FOREACH (Panel *, panel, ®ion->panels) { | ||||
| if (panel->runtime_flag & PNL_ACTIVE) { | if (panel->runtime_flag & PANEL_ACTIVE) { | ||||
| ps->panel = MEM_dupallocN(panel); | ps->panel = MEM_dupallocN(panel); | ||||
| ps->orig = panel; | ps->orig = panel; | ||||
| ps++; | ps++; | ||||
| } | } | ||||
| } | } | ||||
| if (drag) { | if (drag) { | ||||
| /* while we are dragging, we sort on location and update sortorder */ | /* While a panel is being dragged, sort on location and update the sortorder. */ | ||||
| if (align == BUT_VERTICAL) { | if (align == BUT_VERTICAL) { | ||||
| qsort(panelsort, tot, sizeof(PanelSort), find_highest_panel); | qsort(panelsort, tot, sizeof(PanelSort), find_highest_panel); | ||||
| } | } | ||||
| else { | else { | ||||
| qsort(panelsort, tot, sizeof(PanelSort), find_leftmost_panel); | qsort(panelsort, tot, sizeof(PanelSort), find_leftmost_panel); | ||||
| } | } | ||||
| for (ps = panelsort, a = 0; a < tot; a++, ps++) { | for (ps = panelsort, a = 0; a < tot; a++, ps++) { | ||||
| ps->orig->sortorder = a; | ps->orig->sortorder = a; | ||||
| } | } | ||||
| } | } | ||||
| else { | else { | ||||
| /* otherwise use sortorder */ | /* Otherwise use sortorder. */ | ||||
| qsort(panelsort, tot, sizeof(PanelSort), compare_panel); | qsort(panelsort, tot, sizeof(PanelSort), compare_panel_sortorder); | ||||
| } | } | ||||
| /* no smart other default start loc! this keeps switching f5/f6/etc compatible */ | /* No smart other default start location! This keeps switching f5/f6/etc compatible. */ | ||||
| ps = panelsort; | ps = panelsort; | ||||
| ps->panel->runtime.region_ofsx = panel_region_offset_x_get(region, align); | ps->panel->runtime.region_ofsx = region_panel_offset_x(region, align); | ||||
| ps->panel->ofsx = 0; | ps->panel->ofsx = 0; | ||||
| ps->panel->ofsy = -get_panel_size_y(ps->panel); | ps->panel->ofsy = -panel_size_y(ps->panel); | ||||
| ps->panel->ofsx += ps->panel->runtime.region_ofsx; | ps->panel->ofsx += ps->panel->runtime.region_ofsx; | ||||
| for (a = 0; a < tot - 1; a++, ps++) { | for (a = 0; a < tot - 1; a++, ps++) { | ||||
| psnext = ps + 1; | psnext = ps + 1; | ||||
| if (align == BUT_VERTICAL) { | if (align == BUT_VERTICAL) { | ||||
| bool use_box = ps->panel->type && ps->panel->type->flag & PNL_DRAW_BOX; | bool use_box = ps->panel->type && ps->panel->type->flag & PNL_DRAW_BOX; | ||||
| bool use_box_next = psnext->panel->type && psnext->panel->type->flag & PNL_DRAW_BOX; | bool use_box_next = psnext->panel->type && psnext->panel->type->flag & PNL_DRAW_BOX; | ||||
| psnext->panel->ofsx = ps->panel->ofsx; | psnext->panel->ofsx = ps->panel->ofsx; | ||||
| psnext->panel->ofsy = get_panel_real_ofsy(ps->panel) - get_panel_size_y(psnext->panel); | psnext->panel->ofsy = panel_offset_real_y(ps->panel) - panel_size_y(psnext->panel); | ||||
| /* Extra margin for box style panels. */ | /* Extra margin for box style panels. */ | ||||
| ps->panel->ofsx += (use_box) ? UI_PANEL_BOX_STYLE_MARGIN : 0.0f; | ps->panel->ofsx += (use_box) ? UI_PANEL_BOX_STYLE_MARGIN : 0.0f; | ||||
| if (use_box || use_box_next) { | if (use_box || use_box_next) { | ||||
| psnext->panel->ofsy -= UI_PANEL_BOX_STYLE_MARGIN; | psnext->panel->ofsy -= UI_PANEL_BOX_STYLE_MARGIN; | ||||
| } | } | ||||
| } | } | ||||
| else { | else { | ||||
| psnext->panel->ofsx = get_panel_real_ofsx(ps->panel); | psnext->panel->ofsx = panel_offset_real_x(ps->panel); | ||||
| psnext->panel->ofsy = ps->panel->ofsy + get_panel_size_y(ps->panel) - | psnext->panel->ofsy = ps->panel->ofsy + panel_size_y(ps->panel) - | ||||
| get_panel_size_y(psnext->panel); | panel_size_y(psnext->panel); | ||||
| } | } | ||||
| } | } | ||||
| /* Extra margin for the last panel if it's a box-style panel. */ | /* Extra margin for the last panel if it's a box-style panel. */ | ||||
| if (panelsort[tot - 1].panel->type && panelsort[tot - 1].panel->type->flag & PNL_DRAW_BOX) { | if (panelsort[tot - 1].panel->type && panelsort[tot - 1].panel->type->flag & PNL_DRAW_BOX) { | ||||
| panelsort[tot - 1].panel->ofsx += UI_PANEL_BOX_STYLE_MARGIN; | panelsort[tot - 1].panel->ofsx += UI_PANEL_BOX_STYLE_MARGIN; | ||||
| } | } | ||||
| /* we interpolate */ | /* Interpolate. */ | ||||
| done = false; | done = false; | ||||
| ps = panelsort; | ps = panelsort; | ||||
| for (a = 0; a < tot; a++, ps++) { | for (a = 0; a < tot; a++, ps++) { | ||||
| if ((ps->panel->flag & PNL_SELECT) == 0) { | if ((ps->panel->flag & PNL_SELECT) == 0) { | ||||
| if ((ps->orig->ofsx != ps->panel->ofsx) || (ps->orig->ofsy != ps->panel->ofsy)) { | if ((ps->orig->ofsx != ps->panel->ofsx) || (ps->orig->ofsy != ps->panel->ofsy)) { | ||||
| ps->orig->ofsx = round_fl_to_int(fac * (float)ps->panel->ofsx + | ps->orig->ofsx = round_fl_to_int(fac * (float)ps->panel->ofsx + | ||||
| (1.0f - fac) * (float)ps->orig->ofsx); | (1.0f - fac) * (float)ps->orig->ofsx); | ||||
| ps->orig->ofsy = round_fl_to_int(fac * (float)ps->panel->ofsy + | ps->orig->ofsy = round_fl_to_int(fac * (float)ps->panel->ofsy + | ||||
| (1.0f - fac) * (float)ps->orig->ofsy); | (1.0f - fac) * (float)ps->orig->ofsy); | ||||
| done = true; | done = true; | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| /* set locations for tabbed and sub panels */ | /* Set locations for sub panels. */ | ||||
| LISTBASE_FOREACH (Panel *, panel, ®ion->panels) { | LISTBASE_FOREACH (Panel *, panel, ®ion->panels) { | ||||
| if (panel->runtime_flag & PNL_ACTIVE) { | if (panel->runtime_flag & PANEL_ACTIVE) { | ||||
| if (panel->children.first) { | if (panel->children.first) { | ||||
| align_sub_panels(panel); | align_sub_panels(panel); | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| /* free panelsort array */ | /* Free panelsort array. */ | ||||
| for (ps = panelsort, a = 0; a < tot; a++, ps++) { | for (ps = panelsort, a = 0; a < tot; a++, ps++) { | ||||
| MEM_freeN(ps->panel); | MEM_freeN(ps->panel); | ||||
| } | } | ||||
| MEM_freeN(panelsort); | MEM_freeN(panelsort); | ||||
| return done; | return done; | ||||
| } | } | ||||
| static void ui_panels_size(ScrArea *area, ARegion *region, int *r_x, int *r_y) | /** | ||||
| * Compute size taken up by panels for setting in view2d. | |||||
| */ | |||||
| static void panels_size(ScrArea *area, ARegion *region, int *r_x, int *r_y) | |||||
| { | { | ||||
| int align = panel_aligned(area, region); | int align = region_panel_alignment(area, region); | ||||
| int sizex = 0; | int sizex = 0; | ||||
| int sizey = 0; | int sizey = 0; | ||||
| /* compute size taken up by panels, for setting in view2d */ | |||||
| LISTBASE_FOREACH (Panel *, panel, ®ion->panels) { | LISTBASE_FOREACH (Panel *, panel, ®ion->panels) { | ||||
| if (panel->runtime_flag & PNL_ACTIVE) { | if (panel->runtime_flag & PANEL_ACTIVE) { | ||||
| int pa_sizex, pa_sizey; | int pa_sizex, pa_sizey; | ||||
| if (align == BUT_VERTICAL) { | if (align == BUT_VERTICAL) { | ||||
| pa_sizex = panel->ofsx + panel->sizex; | pa_sizex = panel->ofsx + panel->sizex; | ||||
| pa_sizey = get_panel_real_ofsy(panel); | pa_sizey = panel_offset_real_y(panel); | ||||
| } | } | ||||
| else { | else { | ||||
| pa_sizex = get_panel_real_ofsx(panel) + panel->sizex; | pa_sizex = panel_offset_real_x(panel) + panel->sizex; | ||||
| pa_sizey = panel->ofsy + get_panel_size_y(panel); | pa_sizey = panel->ofsy + panel_size_y(panel); | ||||
| } | } | ||||
| sizex = max_ii(sizex, pa_sizex); | sizex = max_ii(sizex, pa_sizex); | ||||
| sizey = min_ii(sizey, pa_sizey); | sizey = min_ii(sizey, pa_sizey); | ||||
| } | } | ||||
| } | } | ||||
| if (sizex == 0) { | if (sizex == 0) { | ||||
| sizex = UI_PANEL_WIDTH; | sizex = UI_PANEL_WIDTH; | ||||
| } | } | ||||
| if (sizey == 0) { | if (sizey == 0) { | ||||
| sizey = -UI_PANEL_WIDTH; | sizey = -UI_PANEL_WIDTH; | ||||
| } | } | ||||
| *r_x = sizex; | *r_x = sizex; | ||||
| *r_y = sizey; | *r_y = sizey; | ||||
| } | } | ||||
| static void ui_do_animate(bContext *C, Panel *panel) | static void panel_handle_animation(bContext *C, Panel *panel) | ||||
| { | { | ||||
| uiHandlePanelData *data = panel->activedata; | uiHandlePanelData *data = panel->activedata; | ||||
| ScrArea *area = CTX_wm_area(C); | ScrArea *area = CTX_wm_area(C); | ||||
| ARegion *region = CTX_wm_region(C); | ARegion *region = CTX_wm_region(C); | ||||
| float fac; | float fac; | ||||
| fac = (PIL_check_seconds_timer() - data->starttime) / ANIMATION_TIME; | fac = (PIL_check_seconds_timer() - data->starttime) / ANIMATION_TIME; | ||||
| fac = min_ff(sqrtf(fac), 1.0f); | fac = min_ff(sqrtf(fac), 1.0f); | ||||
| /* for max 1 second, interpolate positions */ | /* For max 1 second, interpolate positions. */ | ||||
| if (uiAlignPanelStep(area, region, fac, false)) { | if (panels_align_step(area, region, fac, false)) { | ||||
| ED_region_tag_redraw(region); | ED_region_tag_redraw(region); | ||||
| } | } | ||||
| else { | else { | ||||
| fac = 1.0f; | fac = 1.0f; | ||||
| } | } | ||||
| if (fac >= 1.0f) { | if (fac >= 1.0f) { | ||||
| /* Store before data is freed. */ | /* Store before data is freed. */ | ||||
| Show All 9 Lines | static void panel_handle_animation(bContext *C, Panel *panel) | ||||
| } | } | ||||
| } | } | ||||
| static void panel_list_clear_active(ListBase *lb) | static void panel_list_clear_active(ListBase *lb) | ||||
| { | { | ||||
| /* set all panels as inactive, so that at the end we know | /* set all panels as inactive, so that at the end we know | ||||
| * which ones were used */ | * which ones were used */ | ||||
| LISTBASE_FOREACH (Panel *, panel, lb) { | LISTBASE_FOREACH (Panel *, panel, lb) { | ||||
| if (panel->runtime_flag & PNL_ACTIVE) { | if (panel->runtime_flag & PANEL_ACTIVE) { | ||||
| panel->runtime_flag = PNL_WAS_ACTIVE; | panel->runtime_flag = PANEL_WAS_ACTIVE; | ||||
| } | } | ||||
| else { | else { | ||||
| panel->runtime_flag = 0; | panel->runtime_flag = 0; | ||||
| } | } | ||||
| panel_list_clear_active(&panel->children); | panel_list_clear_active(&panel->children); | ||||
| } | } | ||||
| } | } | ||||
| void UI_panels_begin(const bContext *UNUSED(C), ARegion *region) | void UI_panels_begin(const bContext *UNUSED(C), ARegion *region) | ||||
| { | { | ||||
| panel_list_clear_active(®ion->panels); | panel_list_clear_active(®ion->panels); | ||||
| } | } | ||||
| /* only draws blocks with panels */ | |||||
| void UI_panels_end(const bContext *C, ARegion *region, int *r_x, int *r_y) | void UI_panels_end(const bContext *C, ARegion *region, int *r_x, int *r_y) | ||||
| { | { | ||||
| ScrArea *area = CTX_wm_area(C); | ScrArea *area = CTX_wm_area(C); | ||||
| Panel *panel, *panel_first; | |||||
| /* offset contents */ | /* Offset block contents. */ | ||||
| LISTBASE_FOREACH (uiBlock *, block, ®ion->uiblocks) { | LISTBASE_FOREACH (uiBlock *, block, ®ion->uiblocks) { | ||||
| if (block->active && block->panel) { | if (block->active && block->panel) { | ||||
| ui_offset_panel_block(block); | offset_panel_block(block); | ||||
| } | } | ||||
| } | } | ||||
| /* re-align, possibly with animation */ | /* Re-align, possibly with animation. */ | ||||
| if (panels_need_realign(area, region, &panel)) { | Panel *panel_animation; | ||||
| if (panel) { | if (panels_need_realign(area, region, &panel_animation)) { | ||||
| panel_activate_state(C, panel, PANEL_STATE_ANIMATION); | if (panel_animation) { | ||||
| panel_activate_state(C, panel_animation, PANEL_STATE_ANIMATION); | |||||
| } | } | ||||
| else { | else { | ||||
| uiAlignPanelStep(area, region, 1.0, false); | panels_align_step(area, region, 1.0, false); | ||||
| } | } | ||||
| } | } | ||||
| /* tag first panel */ | /* Tag first panel. */ | ||||
| panel_first = NULL; | Panel *panel_first = NULL; | ||||
| LISTBASE_FOREACH (uiBlock *, block, ®ion->uiblocks) { | LISTBASE_FOREACH (uiBlock *, block, ®ion->uiblocks) { | ||||
| if (block->active && block->panel) { | if (block->active && block->panel) { | ||||
| if (!panel_first || block->panel->sortorder < panel_first->sortorder) { | if (!panel_first || block->panel->sortorder < panel_first->sortorder) { | ||||
| panel_first = block->panel; | panel_first = block->panel; | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| if (panel_first) { | if (panel_first) { | ||||
| panel_first->runtime_flag |= PNL_FIRST; | panel_first->runtime_flag |= PANEL_FIRST; | ||||
| } | } | ||||
| /* compute size taken up by panel */ | /* Compute size taken up by panels. */ | ||||
| ui_panels_size(area, region, r_x, r_y); | panels_size(area, region, r_x, r_y); | ||||
| } | } | ||||
| /** | |||||
| * Draw panels, selected on top. | |||||
| */ | |||||
| void UI_panels_draw(const bContext *C, ARegion *region) | void UI_panels_draw(const bContext *C, ARegion *region) | ||||
| { | { | ||||
| if (region->alignment != RGN_ALIGN_FLOAT) { | if (region->alignment != RGN_ALIGN_FLOAT) { | ||||
| UI_ThemeClearColor(TH_BACK); | UI_ThemeClearColor(TH_BACK); | ||||
| } | } | ||||
| /* Draw panels, selected on top. Also in reverse order, because | /* Draw in reverse order, because UI blocks are added in | ||||
| * UI blocks are added in reverse order and we need child panels | * reverse order and we need child panels to draw on top. */ | ||||
| * to draw on top. */ | |||||
| LISTBASE_FOREACH_BACKWARD (uiBlock *, block, ®ion->uiblocks) { | LISTBASE_FOREACH_BACKWARD (uiBlock *, block, ®ion->uiblocks) { | ||||
| if (block->active && block->panel && !(block->panel->flag & PNL_SELECT)) { | if (block->active && block->panel && !(block->panel->flag & PNL_SELECT)) { | ||||
| UI_block_draw(C, block); | UI_block_draw(C, block); | ||||
| } | } | ||||
| } | } | ||||
| LISTBASE_FOREACH_BACKWARD (uiBlock *, block, ®ion->uiblocks) { | LISTBASE_FOREACH_BACKWARD (uiBlock *, block, ®ion->uiblocks) { | ||||
| if (block->active && block->panel && (block->panel->flag & PNL_SELECT)) { | if (block->active && block->panel && (block->panel->flag & PNL_SELECT)) { | ||||
| Show All 12 Lines | if (block->panel) { | ||||
| LISTBASE_FOREACH (uiBut *, but, &block->buttons) { | LISTBASE_FOREACH (uiBut *, but, &block->buttons) { | ||||
| but->rect.xmin *= fac; | but->rect.xmin *= fac; | ||||
| but->rect.xmax *= fac; | but->rect.xmax *= fac; | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| /************************ panel dragging ****************************/ | /** \} */ | ||||
| /* -------------------------------------------------------------------- */ | |||||
| /** \name Panel Dragging | |||||
| * \{ */ | |||||
| #define DRAG_REGION_PAD (PNL_HEADER * 0.5) | #define DRAG_REGION_PAD (PNL_HEADER * 0.5) | ||||
| static void ui_do_drag(const bContext *C, const wmEvent *event, Panel *panel) | static void panel_drag(const bContext *C, const wmEvent *event, Panel *panel) | ||||
| { | { | ||||
| uiHandlePanelData *data = panel->activedata; | uiHandlePanelData *data = panel->activedata; | ||||
| ScrArea *area = CTX_wm_area(C); | ScrArea *area = CTX_wm_area(C); | ||||
| ARegion *region = CTX_wm_region(C); | ARegion *region = CTX_wm_region(C); | ||||
| short align = panel_aligned(area, region); | short align = region_panel_alignment(area, region); | ||||
| /* Keep the drag position in the region with a small pad to keep the panel visible. */ | /* Keep the drag position in the region with a small pad to keep the panel visible. */ | ||||
| int x = clamp_i(event->x, region->winrct.xmin, region->winrct.xmax + DRAG_REGION_PAD); | int x = clamp_i(event->x, region->winrct.xmin, region->winrct.xmax + DRAG_REGION_PAD); | ||||
| int y = clamp_i(event->y, region->winrct.ymin, region->winrct.ymax + DRAG_REGION_PAD); | int y = clamp_i(event->y, region->winrct.ymin, region->winrct.ymax + DRAG_REGION_PAD); | ||||
| float dx = (float)(x - data->startx); | float dx = (float)(x - data->startx); | ||||
| float dy = (float)(y - data->starty); | float dy = (float)(y - data->starty); | ||||
| /* Adjust for region zoom. */ | /* Adjust for region zoom. */ | ||||
| dx *= (float)BLI_rctf_size_x(®ion->v2d.cur) / (float)BLI_rcti_size_x(®ion->winrct); | dx *= (float)BLI_rctf_size_x(®ion->v2d.cur) / (float)BLI_rcti_size_x(®ion->winrct); | ||||
| dy *= (float)BLI_rctf_size_y(®ion->v2d.cur) / (float)BLI_rcti_size_y(®ion->winrct); | dy *= (float)BLI_rctf_size_y(®ion->v2d.cur) / (float)BLI_rcti_size_y(®ion->winrct); | ||||
| if (data->state == PANEL_STATE_DRAG_SCALE) { | if (data->state == PANEL_STATE_DRAG_SCALE) { | ||||
| panel->sizex = MAX2(data->startsizex + dx, UI_PANEL_MINX); | panel->sizex = MAX2(data->startsizex + dx, UI_PANEL_MINX); | ||||
| if (data->startsizey - dy < UI_PANEL_MINY) { | if (data->startsizey - dy < UI_PANEL_MINY) { | ||||
| dy = -UI_PANEL_MINY + data->startsizey; | dy = -UI_PANEL_MINY + data->startsizey; | ||||
| } | } | ||||
| panel->sizey = data->startsizey - dy; | panel->sizey = data->startsizey - dy; | ||||
| panel->ofsy = data->startofsy + dy; | panel->ofsy = data->startofsy + dy; | ||||
| } | } | ||||
| else { | else { | ||||
| /* reset the panel snapping, to allow dragging away from snapped edges */ | /* Reset the panel snapping, to allow dragging away from snapped edges. */ | ||||
| panel->snap = PNL_SNAP_NONE; | panel->snap = PNL_SNAP_NONE; | ||||
| /* Add the movement of the view due to edge scrolling while dragging. */ | /* Add the movement of the view due to edge scrolling while dragging. */ | ||||
| dx += ((float)region->v2d.cur.xmin - data->start_cur_xmin); | dx += ((float)region->v2d.cur.xmin - data->start_cur_xmin); | ||||
| dy += ((float)region->v2d.cur.ymin - data->start_cur_ymin); | dy += ((float)region->v2d.cur.ymin - data->start_cur_ymin); | ||||
| panel->ofsx = data->startofsx + round_fl_to_int(dx); | panel->ofsx = data->startofsx + round_fl_to_int(dx); | ||||
| panel->ofsy = data->startofsy + round_fl_to_int(dy); | panel->ofsy = data->startofsy + round_fl_to_int(dy); | ||||
| if (align) { | if (align) { | ||||
| uiAlignPanelStep(area, region, 0.2f, true); | panels_align_step(area, region, 0.2f, true); | ||||
| } | } | ||||
| } | } | ||||
| ED_region_tag_redraw(region); | ED_region_tag_redraw(region); | ||||
| } | } | ||||
| #undef DRAG_REGION_PAD | #undef DRAG_REGION_PAD | ||||
| /******************* region level panel interaction *****************/ | /** \} */ | ||||
| /* -------------------------------------------------------------------- */ | |||||
| /** \name Region Level Panel Interaction | |||||
| * \{ */ | |||||
| static uiPanelMouseState ui_panel_mouse_state_get(const uiBlock *block, | static uiPanelMouseState panel_mouse_state(const uiBlock *block, | ||||
| const Panel *panel, | const Panel *panel, | ||||
| const int mx, | const int mx, | ||||
| const int my) | const int my) | ||||
| { | { | ||||
| /* open panel */ | /* Open panel. */ | ||||
| if (panel->flag & PNL_CLOSEDX) { | if (panel->flag & PNL_CLOSEDX) { | ||||
| if ((block->rect.xmin <= mx) && (block->rect.xmin + PNL_HEADER >= mx)) { | if ((block->rect.xmin <= mx) && (block->rect.xmin + PNL_HEADER >= mx)) { | ||||
| return PANEL_MOUSE_INSIDE_HEADER; | return PANEL_MOUSE_INSIDE_HEADER; | ||||
| } | } | ||||
| } | } | ||||
| /* outside left/right side */ | /* Outside left/right side. */ | ||||
| else if ((block->rect.xmin > mx) || (block->rect.xmax < mx)) { | else if ((block->rect.xmin > mx) || (block->rect.xmax < mx)) { | ||||
| /* pass */ | /* Pass. */ | ||||
| } | } | ||||
| else if ((block->rect.ymax <= my) && (block->rect.ymax + PNL_HEADER >= my)) { | else if ((block->rect.ymax <= my) && (block->rect.ymax + PNL_HEADER >= my)) { | ||||
| return PANEL_MOUSE_INSIDE_HEADER; | return PANEL_MOUSE_INSIDE_HEADER; | ||||
| } | } | ||||
| /* open panel */ | /* Open panel. */ | ||||
| else if (!(panel->flag & PNL_CLOSEDY)) { | else if (!(panel->flag & PNL_CLOSEDY)) { | ||||
| if ((block->rect.xmin <= mx) && (block->rect.xmax >= mx)) { | if ((block->rect.xmin <= mx) && (block->rect.xmax >= mx)) { | ||||
| if ((block->rect.ymin <= my) && (block->rect.ymax + PNL_HEADER >= my)) { | if ((block->rect.ymin <= my) && (block->rect.ymax + PNL_HEADER >= my)) { | ||||
| return PANEL_MOUSE_INSIDE_CONTENT; | return PANEL_MOUSE_INSIDE_CONTENT; | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| return PANEL_MOUSE_OUTSIDE; | return PANEL_MOUSE_OUTSIDE; | ||||
| } | } | ||||
| typedef struct uiPanelDragCollapseHandle { | typedef struct uiPanelDragCollapseHandle { | ||||
| bool was_first_open; | bool was_first_open; | ||||
| int xy_init[2]; | int xy_init[2]; | ||||
| } uiPanelDragCollapseHandle; | } uiPanelDragCollapseHandle; | ||||
| static void ui_panel_drag_collapse_handler_remove(bContext *UNUSED(C), void *userdata) | static void panel_drag_collapse_handler_remove(bContext *UNUSED(C), void *userdata) | ||||
| { | { | ||||
| uiPanelDragCollapseHandle *dragcol_data = userdata; | uiPanelDragCollapseHandle *dragcol_data = userdata; | ||||
| MEM_freeN(dragcol_data); | MEM_freeN(dragcol_data); | ||||
| } | } | ||||
| static void ui_panel_drag_collapse(bContext *C, | static void panel_drag_collapse(bContext *C, | ||||
| uiPanelDragCollapseHandle *dragcol_data, | uiPanelDragCollapseHandle *dragcol_data, | ||||
| const int xy_dst[2]) | const int xy_dst[2]) | ||||
| { | { | ||||
| ScrArea *area = CTX_wm_area(C); | ScrArea *area = CTX_wm_area(C); | ||||
| ARegion *region = CTX_wm_region(C); | ARegion *region = CTX_wm_region(C); | ||||
| Panel *panel; | Panel *panel; | ||||
| LISTBASE_FOREACH (uiBlock *, block, ®ion->uiblocks) { | LISTBASE_FOREACH (uiBlock *, block, ®ion->uiblocks) { | ||||
| float xy_a_block[2] = {UNPACK2(dragcol_data->xy_init)}; | float xy_a_block[2] = {UNPACK2(dragcol_data->xy_init)}; | ||||
| float xy_b_block[2] = {UNPACK2(xy_dst)}; | float xy_b_block[2] = {UNPACK2(xy_dst)}; | ||||
| rctf rect = block->rect; | rctf rect = block->rect; | ||||
| int oldflag; | int oldflag; | ||||
| const bool is_horizontal = (panel_aligned(area, region) == BUT_HORIZONTAL); | const bool is_horizontal = (region_panel_alignment(area, region) == BUT_HORIZONTAL); | ||||
| if ((panel = block->panel) == 0 || (panel->type && (panel->type->flag & PNL_NO_HEADER))) { | if ((panel = block->panel) == 0 || (panel->type && (panel->type->flag & PNL_NO_HEADER))) { | ||||
| continue; | continue; | ||||
| } | } | ||||
| oldflag = panel->flag; | oldflag = panel->flag; | ||||
| /* lock one axis */ | /* Lock one axis. */ | ||||
| if (is_horizontal) { | if (is_horizontal) { | ||||
| xy_b_block[1] = dragcol_data->xy_init[1]; | xy_b_block[1] = dragcol_data->xy_init[1]; | ||||
| } | } | ||||
| else { | else { | ||||
| xy_b_block[0] = dragcol_data->xy_init[0]; | xy_b_block[0] = dragcol_data->xy_init[0]; | ||||
| } | } | ||||
| /* use cursor coords in block space */ | /* Use cursor coords in block space. */ | ||||
| ui_window_to_block_fl(region, block, &xy_a_block[0], &xy_a_block[1]); | ui_window_to_block_fl(region, block, &xy_a_block[0], &xy_a_block[1]); | ||||
| ui_window_to_block_fl(region, block, &xy_b_block[0], &xy_b_block[1]); | ui_window_to_block_fl(region, block, &xy_b_block[0], &xy_b_block[1]); | ||||
| /* set up rect to match header size */ | /* Set up rect to match header size. */ | ||||
| rect.ymin = rect.ymax; | rect.ymin = rect.ymax; | ||||
| rect.ymax = rect.ymin + PNL_HEADER; | rect.ymax = rect.ymin + PNL_HEADER; | ||||
| if (panel->flag & PNL_CLOSEDX) { | if (panel->flag & PNL_CLOSEDX) { | ||||
| rect.xmax = rect.xmin + PNL_HEADER; | rect.xmax = rect.xmin + PNL_HEADER; | ||||
| } | } | ||||
| /* touch all panels between last mouse coord and the current one */ | /* Touch all panels between last mouse coord and the current one. */ | ||||
| if (BLI_rctf_isect_segment(&rect, xy_a_block, xy_b_block)) { | if (BLI_rctf_isect_segment(&rect, xy_a_block, xy_b_block)) { | ||||
| /* force panel to close */ | /* Force panel to close. */ | ||||
| if (dragcol_data->was_first_open == true) { | if (dragcol_data->was_first_open == true) { | ||||
| panel->flag |= (is_horizontal ? PNL_CLOSEDX : PNL_CLOSEDY); | panel->flag |= (is_horizontal ? PNL_CLOSEDX : PNL_CLOSEDY); | ||||
| } | } | ||||
| /* force panel to open */ | /* Force panel to open. */ | ||||
| else { | else { | ||||
| panel->flag &= ~PNL_CLOSED; | panel->flag &= ~PNL_CLOSED; | ||||
| } | } | ||||
| /* if panel->flag has changed this means a panel was opened/closed here */ | /* If panel->flag has changed this means a panel was opened/closed here. */ | ||||
| if (panel->flag != oldflag) { | if (panel->flag != oldflag) { | ||||
| panel_activate_state(C, panel, PANEL_STATE_ANIMATION); | panel_activate_state(C, panel, PANEL_STATE_ANIMATION); | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| /* Update the instanced panel data expand flags with the changes made here. */ | /* Update the instanced panel data expand flags with the changes made here. */ | ||||
| set_panels_list_data_expand_flag(C, region); | set_panels_list_data_expand_flag(C, region); | ||||
| } | } | ||||
| /** | /** | ||||
| * Panel drag-collapse (modal handler) | * Panel drag-collapse (modal handler) | ||||
| * Clicking and dragging over panels toggles their collapse state based on the panel that was first | * 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 vice versa. | * dragged over. If it was open all affected panels incl the initial one are closed and vice versa. | ||||
| */ | */ | ||||
| static int ui_panel_drag_collapse_handler(bContext *C, const wmEvent *event, void *userdata) | static int panel_drag_collapse_handler(bContext *C, const wmEvent *event, void *userdata) | ||||
| { | { | ||||
| wmWindow *win = CTX_wm_window(C); | wmWindow *win = CTX_wm_window(C); | ||||
| uiPanelDragCollapseHandle *dragcol_data = userdata; | uiPanelDragCollapseHandle *dragcol_data = userdata; | ||||
| short retval = WM_UI_HANDLER_CONTINUE; | short retval = WM_UI_HANDLER_CONTINUE; | ||||
| switch (event->type) { | switch (event->type) { | ||||
| case MOUSEMOVE: | case MOUSEMOVE: | ||||
| ui_panel_drag_collapse(C, dragcol_data, &event->x); | panel_drag_collapse(C, dragcol_data, &event->x); | ||||
| retval = WM_UI_HANDLER_BREAK; | retval = WM_UI_HANDLER_BREAK; | ||||
| break; | break; | ||||
| case LEFTMOUSE: | case LEFTMOUSE: | ||||
| if (event->val == KM_RELEASE) { | if (event->val == KM_RELEASE) { | ||||
| /* done! */ | /* Done! */ | ||||
| WM_event_remove_ui_handler(&win->modalhandlers, | WM_event_remove_ui_handler(&win->modalhandlers, | ||||
| ui_panel_drag_collapse_handler, | panel_drag_collapse_handler, | ||||
| ui_panel_drag_collapse_handler_remove, | panel_drag_collapse_handler_remove, | ||||
| dragcol_data, | dragcol_data, | ||||
| true); | true); | ||||
| ui_panel_drag_collapse_handler_remove(C, dragcol_data); | panel_drag_collapse_handler_remove(C, dragcol_data); | ||||
| } | } | ||||
| /* don't let any left-mouse event fall through! */ | /* Don't let any left-mouse event fall through! */ | ||||
| retval = WM_UI_HANDLER_BREAK; | retval = WM_UI_HANDLER_BREAK; | ||||
| break; | break; | ||||
| } | } | ||||
| return retval; | return retval; | ||||
| } | } | ||||
| static void ui_panel_drag_collapse_handler_add(const bContext *C, const bool was_open) | static void panel_drag_collapse_handler_add(const bContext *C, const bool was_open) | ||||
| { | { | ||||
| wmWindow *win = CTX_wm_window(C); | wmWindow *win = CTX_wm_window(C); | ||||
| const wmEvent *event = win->eventstate; | const wmEvent *event = win->eventstate; | ||||
| uiPanelDragCollapseHandle *dragcol_data = MEM_mallocN(sizeof(*dragcol_data), __func__); | uiPanelDragCollapseHandle *dragcol_data = MEM_mallocN(sizeof(*dragcol_data), __func__); | ||||
| dragcol_data->was_first_open = was_open; | dragcol_data->was_first_open = was_open; | ||||
| copy_v2_v2_int(dragcol_data->xy_init, &event->x); | copy_v2_v2_int(dragcol_data->xy_init, &event->x); | ||||
| WM_event_add_ui_handler(C, | WM_event_add_ui_handler(C, | ||||
| &win->modalhandlers, | &win->modalhandlers, | ||||
| ui_panel_drag_collapse_handler, | panel_drag_collapse_handler, | ||||
| ui_panel_drag_collapse_handler_remove, | panel_drag_collapse_handler_remove, | ||||
| dragcol_data, | dragcol_data, | ||||
| 0); | 0); | ||||
| } | } | ||||
| /* this function is supposed to call general window drawing too */ | /** | ||||
| /* also it supposes a block has panel, and isn't a menu */ | * Handle interaction for panel headers. | ||||
| static void ui_handle_panel_header( | * | ||||
| * \note This function is supposed to call general window drawing too. | |||||
| * Also it supposes a block has panel, and isn't a menu. | |||||
| */ | |||||
| static void panel_handle_header( | |||||
| const bContext *C, uiBlock *block, int mx, int my, int event, short ctrl, short shift) | const bContext *C, uiBlock *block, int mx, int my, int event, short ctrl, short shift) | ||||
| { | { | ||||
| ScrArea *area = CTX_wm_area(C); | ScrArea *area = CTX_wm_area(C); | ||||
| ARegion *region = CTX_wm_region(C); | ARegion *region = CTX_wm_region(C); | ||||
| #ifdef USE_PIN_HIDDEN | #ifdef USE_PIN_HIDDEN | ||||
| const bool show_pin = UI_panel_category_is_visible(region) && | const bool show_pin = UI_panel_category_is_visible(region) && | ||||
| (block->panel->type->parent == NULL) && (block->panel->flag & PNL_PIN); | (block->panel->type->parent == NULL) && (block->panel->flag & PNL_PIN); | ||||
| #else | #else | ||||
| const bool show_pin = UI_panel_category_is_visible(region) && | const bool show_pin = UI_panel_category_is_visible(region) && | ||||
| (block->panel->type->parent == NULL); | (block->panel->type->parent == NULL); | ||||
| #endif | #endif | ||||
| const bool is_subpanel = (block->panel->type && block->panel->type->parent); | const bool is_subpanel = (block->panel->type && block->panel->type->parent); | ||||
| const bool show_drag = !is_subpanel; | const bool show_drag = !is_subpanel; | ||||
| int align = panel_aligned(area, region), button = 0; | int align = region_panel_alignment(area, region), button = 0; | ||||
| rctf rect_drag, rect_pin; | rctf rect_drag, rect_pin; | ||||
| float rect_leftmost; | float rect_leftmost; | ||||
| /* drag and pin rect's */ | /* Drag and pin rects. */ | ||||
| rect_drag = block->rect; | rect_drag = block->rect; | ||||
| rect_drag.xmin = block->rect.xmax - (PNL_ICON * 1.5f); | rect_drag.xmin = block->rect.xmax - (PNL_ICON * 1.5f); | ||||
| rect_pin = rect_drag; | rect_pin = rect_drag; | ||||
| if (show_pin) { | if (show_pin) { | ||||
| BLI_rctf_translate(&rect_pin, -PNL_ICON, 0.0f); | BLI_rctf_translate(&rect_pin, -PNL_ICON, 0.0f); | ||||
| } | } | ||||
| rect_leftmost = rect_pin.xmin; | rect_leftmost = rect_pin.xmin; | ||||
| /* mouse coordinates in panel space! */ | /* Mouse coordinates are in panel space! */ | ||||
| /* XXX weak code, currently it assumes layout style for location of widgets */ | /* XXX weak code, currently it assumes layout style for location of widgets. */ | ||||
| /* check open/collapsed button */ | /* Check open/collapsed button. */ | ||||
| if (event == EVT_RETKEY) { | if (event == EVT_RETKEY) { | ||||
| button = 1; | button = 1; | ||||
| } | } | ||||
| else if (event == EVT_AKEY) { | else if (event == EVT_AKEY) { | ||||
| button = 1; | button = 1; | ||||
| } | } | ||||
| else if (ELEM(event, 0, EVT_RETKEY, LEFTMOUSE) && shift) { | else if (ELEM(event, 0, EVT_RETKEY, LEFTMOUSE) && shift) { | ||||
| if (block->panel->type->parent == NULL) { | if (block->panel->type->parent == NULL) { | ||||
| block->panel->flag ^= PNL_PIN; | block->panel->flag ^= PNL_PIN; | ||||
| button = 2; | button = 2; | ||||
| } | } | ||||
| } | } | ||||
| else if (block->panel->flag & PNL_CLOSEDX) { | else if (block->panel->flag & PNL_CLOSEDX) { | ||||
| if (my >= block->rect.ymax) { | if (my >= block->rect.ymax) { | ||||
| button = 1; | button = 1; | ||||
| } | } | ||||
| } | } | ||||
| else if (mx < rect_leftmost) { | else if (mx < rect_leftmost) { | ||||
| button = 1; | button = 1; | ||||
| } | } | ||||
| if (button) { | if (button) { | ||||
| if (button == 2) { /* close */ | if (button == 2) { /* Close. */ | ||||
| ED_region_tag_redraw(region); | ED_region_tag_redraw(region); | ||||
| } | } | ||||
| else { | else { | ||||
| /* Collapse and expand panels. */ | /* Collapse and expand panels. */ | ||||
| if (ctrl) { | if (ctrl) { | ||||
| /* For parent panels, collapse all other panels or toggle children. */ | /* For parent panels, collapse all other panels or toggle children. */ | ||||
| if (block->panel->type != NULL && block->panel->type->parent == NULL) { | if (block->panel->type != NULL && block->panel->type->parent == NULL) { | ||||
| Show All 13 Lines | else { | ||||
| block->panel, closed_flag, (first_child->flag & PNL_CLOSED) == 0); | block->panel, closed_flag, (first_child->flag & PNL_CLOSED) == 0); | ||||
| block->panel->flag |= closed_flag; | block->panel->flag |= closed_flag; | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| if (block->panel->flag & PNL_CLOSED) { | if (block->panel->flag & PNL_CLOSED) { | ||||
| block->panel->flag &= ~PNL_CLOSED; | block->panel->flag &= ~PNL_CLOSED; | ||||
| /* snap back up so full panel aligns with screen edge */ | /* Snap back up so full panel aligns with screen edge. */ | ||||
| if (block->panel->snap & PNL_SNAP_BOTTOM) { | if (block->panel->snap & PNL_SNAP_BOTTOM) { | ||||
| block->panel->ofsy = 0; | block->panel->ofsy = 0; | ||||
| } | } | ||||
| if (event == LEFTMOUSE) { | if (event == LEFTMOUSE) { | ||||
| ui_panel_drag_collapse_handler_add(C, false); | panel_drag_collapse_handler_add(C, false); | ||||
| } | } | ||||
| } | } | ||||
| else if (align == BUT_HORIZONTAL) { | else if (align == BUT_HORIZONTAL) { | ||||
| block->panel->flag |= PNL_CLOSEDX; | block->panel->flag |= PNL_CLOSEDX; | ||||
| if (event == LEFTMOUSE) { | if (event == LEFTMOUSE) { | ||||
| ui_panel_drag_collapse_handler_add(C, true); | panel_drag_collapse_handler_add(C, true); | ||||
| } | } | ||||
| } | } | ||||
| else { | else { | ||||
| /* snap down to bottom screen edge */ | /* Snap down to bottom screen edge. */ | ||||
| block->panel->flag |= PNL_CLOSEDY; | block->panel->flag |= PNL_CLOSEDY; | ||||
| if (block->panel->snap & PNL_SNAP_BOTTOM) { | if (block->panel->snap & PNL_SNAP_BOTTOM) { | ||||
| block->panel->ofsy = -block->panel->sizey; | block->panel->ofsy = -block->panel->sizey; | ||||
| } | } | ||||
| if (event == LEFTMOUSE) { | if (event == LEFTMOUSE) { | ||||
| ui_panel_drag_collapse_handler_add(C, true); | panel_drag_collapse_handler_add(C, true); | ||||
| } | } | ||||
| } | } | ||||
| set_panels_list_data_expand_flag(C, region); | set_panels_list_data_expand_flag(C, region); | ||||
| } | } | ||||
| if (align) { | if (align) { | ||||
| panel_activate_state(C, block->panel, PANEL_STATE_ANIMATION); | panel_activate_state(C, block->panel, PANEL_STATE_ANIMATION); | ||||
| Show All 15 Lines | #endif | ||||
| else if (show_pin && BLI_rctf_isect_x(&rect_pin, mx)) { | else if (show_pin && BLI_rctf_isect_x(&rect_pin, mx)) { | ||||
| block->panel->flag ^= PNL_PIN; | block->panel->flag ^= PNL_PIN; | ||||
| ED_region_tag_redraw(region); | ED_region_tag_redraw(region); | ||||
| } | } | ||||
| } | } | ||||
| bool UI_panel_category_is_visible(const ARegion *region) | bool UI_panel_category_is_visible(const ARegion *region) | ||||
| { | { | ||||
| /* more than one */ | /* More than one */ | ||||
| return region->panels_category.first && | return region->panels_category.first && | ||||
| region->panels_category.first != region->panels_category.last; | region->panels_category.first != region->panels_category.last; | ||||
| } | } | ||||
| PanelCategoryDyn *UI_panel_category_find(ARegion *region, const char *idname) | PanelCategoryDyn *UI_panel_category_find(ARegion *region, const char *idname) | ||||
| { | { | ||||
| return BLI_findstring(®ion->panels_category, idname, offsetof(PanelCategoryDyn, idname)); | return BLI_findstring(®ion->panels_category, idname, offsetof(PanelCategoryDyn, idname)); | ||||
| } | } | ||||
| PanelCategoryStack *UI_panel_category_active_find(ARegion *region, const char *idname) | PanelCategoryStack *UI_panel_category_active_find(ARegion *region, const char *idname) | ||||
| { | { | ||||
| return BLI_findstring( | return BLI_findstring( | ||||
| ®ion->panels_category_active, idname, offsetof(PanelCategoryStack, idname)); | ®ion->panels_category_active, idname, offsetof(PanelCategoryStack, idname)); | ||||
| } | } | ||||
| static void ui_panel_category_active_set(ARegion *region, const char *idname, bool fallback) | static void panel_category_active_set(ARegion *region, const char *idname, bool fallback) | ||||
| { | { | ||||
| ListBase *lb = ®ion->panels_category_active; | ListBase *lb = ®ion->panels_category_active; | ||||
| PanelCategoryStack *pc_act = UI_panel_category_active_find(region, idname); | PanelCategoryStack *pc_act = UI_panel_category_active_find(region, idname); | ||||
| if (pc_act) { | if (pc_act) { | ||||
| BLI_remlink(lb, pc_act); | BLI_remlink(lb, pc_act); | ||||
| } | } | ||||
| else { | else { | ||||
| pc_act = MEM_callocN(sizeof(PanelCategoryStack), __func__); | pc_act = MEM_callocN(sizeof(PanelCategoryStack), __func__); | ||||
| BLI_strncpy(pc_act->idname, idname, sizeof(pc_act->idname)); | BLI_strncpy(pc_act->idname, idname, sizeof(pc_act->idname)); | ||||
| } | } | ||||
| if (fallback) { | if (fallback) { | ||||
| /* For fallbacks, add at the end so explicitly chosen categories have priority. */ | /* For fallbacks, add at the end so explicitly chosen categories have priority. */ | ||||
| BLI_addtail(lb, pc_act); | BLI_addtail(lb, pc_act); | ||||
| } | } | ||||
| else { | else { | ||||
| BLI_addhead(lb, pc_act); | BLI_addhead(lb, pc_act); | ||||
| } | } | ||||
| /* validate all active panels, we could do this on load, | /* Calidate all active panels, we could do this on load, | ||||
| * they are harmless - but we should remove somewhere. | * they are harmless - but we should remove somewhere. | ||||
| * (addons could define own and gather cruft over time) */ | * (addons could define categories and gather cruft over time). */ | ||||
| { | { | ||||
| PanelCategoryStack *pc_act_next; | PanelCategoryStack *pc_act_next; | ||||
| /* intentionally skip first */ | /* Intentionally skip first. */ | ||||
| pc_act_next = pc_act->next; | pc_act_next = pc_act->next; | ||||
| while ((pc_act = pc_act_next)) { | while ((pc_act = pc_act_next)) { | ||||
| pc_act_next = pc_act->next; | pc_act_next = pc_act->next; | ||||
| if (!BLI_findstring( | if (!BLI_findstring( | ||||
| ®ion->type->paneltypes, pc_act->idname, offsetof(PanelType, category))) { | ®ion->type->paneltypes, pc_act->idname, offsetof(PanelType, category))) { | ||||
| BLI_remlink(lb, pc_act); | BLI_remlink(lb, pc_act); | ||||
| MEM_freeN(pc_act); | MEM_freeN(pc_act); | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| void UI_panel_category_active_set(ARegion *region, const char *idname) | void UI_panel_category_active_set(ARegion *region, const char *idname) | ||||
| { | { | ||||
| ui_panel_category_active_set(region, idname, false); | panel_category_active_set(region, idname, false); | ||||
| } | } | ||||
| void UI_panel_category_active_set_default(ARegion *region, const char *idname) | void UI_panel_category_active_set_default(ARegion *region, const char *idname) | ||||
| { | { | ||||
| if (!UI_panel_category_active_find(region, idname)) { | if (!UI_panel_category_active_find(region, idname)) { | ||||
| ui_panel_category_active_set(region, idname, true); | panel_category_active_set(region, idname, true); | ||||
| } | } | ||||
| } | } | ||||
| const char *UI_panel_category_active_get(ARegion *region, bool set_fallback) | const char *UI_panel_category_active_get(ARegion *region, bool set_fallback) | ||||
| { | { | ||||
| LISTBASE_FOREACH (PanelCategoryStack *, pc_act, ®ion->panels_category_active) { | LISTBASE_FOREACH (PanelCategoryStack *, pc_act, ®ion->panels_category_active) { | ||||
| if (UI_panel_category_find(region, pc_act->idname)) { | if (UI_panel_category_find(region, pc_act->idname)) { | ||||
| return pc_act->idname; | return pc_act->idname; | ||||
| } | } | ||||
| } | } | ||||
| if (set_fallback) { | if (set_fallback) { | ||||
| PanelCategoryDyn *pc_dyn = region->panels_category.first; | PanelCategoryDyn *pc_dyn = region->panels_category.first; | ||||
| if (pc_dyn) { | if (pc_dyn) { | ||||
| ui_panel_category_active_set(region, pc_dyn->idname, true); | panel_category_active_set(region, pc_dyn->idname, true); | ||||
| return pc_dyn->idname; | return pc_dyn->idname; | ||||
| } | } | ||||
| } | } | ||||
| return NULL; | return NULL; | ||||
| } | } | ||||
| PanelCategoryDyn *UI_panel_category_find_mouse_over_ex(ARegion *region, const int x, const int y) | PanelCategoryDyn *UI_panel_category_find_mouse_over_ex(ARegion *region, const int x, const int y) | ||||
| Show All 14 Lines | |||||
| void UI_panel_category_add(ARegion *region, const char *name) | void UI_panel_category_add(ARegion *region, const char *name) | ||||
| { | { | ||||
| PanelCategoryDyn *pc_dyn = MEM_callocN(sizeof(*pc_dyn), __func__); | PanelCategoryDyn *pc_dyn = MEM_callocN(sizeof(*pc_dyn), __func__); | ||||
| BLI_addtail(®ion->panels_category, pc_dyn); | BLI_addtail(®ion->panels_category, pc_dyn); | ||||
| BLI_strncpy(pc_dyn->idname, name, sizeof(pc_dyn->idname)); | BLI_strncpy(pc_dyn->idname, name, sizeof(pc_dyn->idname)); | ||||
| /* 'pc_dyn->rect' must be set on draw */ | /* 'pc_dyn->rect' must be set on draw. */ | ||||
| } | } | ||||
| void UI_panel_category_clear_all(ARegion *region) | void UI_panel_category_clear_all(ARegion *region) | ||||
| { | { | ||||
| BLI_freelistN(®ion->panels_category); | BLI_freelistN(®ion->panels_category); | ||||
| } | } | ||||
| static void imm_buf_append( | static void imm_buf_append( | ||||
| float vbuf[][2], uchar cbuf[][3], float x, float y, const uchar col[3], int *index) | float vbuf[][2], uchar cbuf[][3], float x, float y, const uchar col[3], int *index) | ||||
| { | { | ||||
| ARRAY_SET_ITEMS(vbuf[*index], x, y); | ARRAY_SET_ITEMS(vbuf[*index], x, y); | ||||
| ARRAY_SET_ITEMS(cbuf[*index], UNPACK3(col)); | ARRAY_SET_ITEMS(cbuf[*index], UNPACK3(col)); | ||||
| (*index)++; | (*index)++; | ||||
| } | } | ||||
| /* based on UI_draw_roundbox, check on making a version which allows us to skip some sides */ | /** | ||||
| * \note Based on UI_draw_roundbox. | |||||
| * Check on making a version which allows us to skip some sides. | |||||
| */ | |||||
| static void ui_panel_category_draw_tab(bool filled, | static void ui_panel_category_draw_tab(bool filled, | ||||
| float minx, | float minx, | ||||
| float miny, | float miny, | ||||
| float maxx, | float maxx, | ||||
| float maxy, | float maxy, | ||||
| float rad, | float rad, | ||||
| const int roundboxtype, | const int roundboxtype, | ||||
| const bool use_highlight, | const bool use_highlight, | ||||
| const bool use_shadow, | const bool use_shadow, | ||||
| const bool use_flip_x, | const bool use_flip_x, | ||||
| const uchar highlight_fade[3], | const uchar highlight_fade[3], | ||||
| const uchar col[3]) | const uchar col[3]) | ||||
| { | { | ||||
| float vec[4][2] = {{0.195, 0.02}, {0.55, 0.169}, {0.831, 0.45}, {0.98, 0.805}}; | float vec[4][2] = {{0.195, 0.02}, {0.55, 0.169}, {0.831, 0.45}, {0.98, 0.805}}; | ||||
| int a; | int a; | ||||
| /* mult */ | |||||
| for (a = 0; a < 4; a++) { | for (a = 0; a < 4; a++) { | ||||
| mul_v2_fl(vec[a], rad); | mul_v2_fl(vec[a], rad); | ||||
| } | } | ||||
| uint vert_len = 0; | uint vert_len = 0; | ||||
| if (use_highlight) { | if (use_highlight) { | ||||
| vert_len += (roundboxtype & UI_CNR_TOP_RIGHT) ? 6 : 1; | vert_len += (roundboxtype & UI_CNR_TOP_RIGHT) ? 6 : 1; | ||||
| vert_len += (roundboxtype & UI_CNR_TOP_LEFT) ? 6 : 1; | vert_len += (roundboxtype & UI_CNR_TOP_LEFT) ? 6 : 1; | ||||
| } | } | ||||
| if (use_highlight && !use_shadow) { | if (use_highlight && !use_shadow) { | ||||
| vert_len++; | vert_len++; | ||||
| } | } | ||||
| else { | else { | ||||
| vert_len += (roundboxtype & UI_CNR_BOTTOM_RIGHT) ? 6 : 1; | vert_len += (roundboxtype & UI_CNR_BOTTOM_RIGHT) ? 6 : 1; | ||||
| vert_len += (roundboxtype & UI_CNR_BOTTOM_LEFT) ? 6 : 1; | vert_len += (roundboxtype & UI_CNR_BOTTOM_LEFT) ? 6 : 1; | ||||
| } | } | ||||
| /* Maximum size. */ | /* Maximum size. */ | ||||
| float vbuf[24][2]; | float vbuf[24][2]; | ||||
| uchar cbuf[24][3]; | uchar cbuf[24][3]; | ||||
| int buf_index = 0; | int buf_index = 0; | ||||
| /* start with corner right-top */ | /* Start with right top corner. */ | ||||
| if (use_highlight) { | if (use_highlight) { | ||||
| if (roundboxtype & UI_CNR_TOP_RIGHT) { | if (roundboxtype & UI_CNR_TOP_RIGHT) { | ||||
| imm_buf_append(vbuf, cbuf, maxx, maxy - rad, col, &buf_index); | imm_buf_append(vbuf, cbuf, maxx, maxy - rad, col, &buf_index); | ||||
| for (a = 0; a < 4; a++) { | for (a = 0; a < 4; a++) { | ||||
| imm_buf_append(vbuf, cbuf, maxx - vec[a][1], maxy - rad + vec[a][0], col, &buf_index); | imm_buf_append(vbuf, cbuf, maxx - vec[a][1], maxy - rad + vec[a][0], col, &buf_index); | ||||
| } | } | ||||
| imm_buf_append(vbuf, cbuf, maxx - rad, maxy, col, &buf_index); | imm_buf_append(vbuf, cbuf, maxx - rad, maxy, col, &buf_index); | ||||
| } | } | ||||
| else { | else { | ||||
| imm_buf_append(vbuf, cbuf, maxx, maxy, col, &buf_index); | imm_buf_append(vbuf, cbuf, maxx, maxy, col, &buf_index); | ||||
| } | } | ||||
| /* corner left-top */ | /* left top corner. */ | ||||
| if (roundboxtype & UI_CNR_TOP_LEFT) { | if (roundboxtype & UI_CNR_TOP_LEFT) { | ||||
| imm_buf_append(vbuf, cbuf, minx + rad, maxy, col, &buf_index); | imm_buf_append(vbuf, cbuf, minx + rad, maxy, col, &buf_index); | ||||
| for (a = 0; a < 4; a++) { | for (a = 0; a < 4; a++) { | ||||
| imm_buf_append(vbuf, cbuf, minx + rad - vec[a][0], maxy - vec[a][1], col, &buf_index); | imm_buf_append(vbuf, cbuf, minx + rad - vec[a][0], maxy - vec[a][1], col, &buf_index); | ||||
| } | } | ||||
| imm_buf_append(vbuf, cbuf, minx, maxy - rad, col, &buf_index); | imm_buf_append(vbuf, cbuf, minx, maxy - rad, col, &buf_index); | ||||
| } | } | ||||
| else { | else { | ||||
| imm_buf_append(vbuf, cbuf, minx, maxy, col, &buf_index); | imm_buf_append(vbuf, cbuf, minx, maxy, col, &buf_index); | ||||
| } | } | ||||
| } | } | ||||
| if (use_highlight && !use_shadow) { | if (use_highlight && !use_shadow) { | ||||
| imm_buf_append( | imm_buf_append( | ||||
| vbuf, cbuf, minx, miny + rad, highlight_fade ? col : highlight_fade, &buf_index); | vbuf, cbuf, minx, miny + rad, highlight_fade ? col : highlight_fade, &buf_index); | ||||
| } | } | ||||
| else { | else { | ||||
| /* corner left-bottom */ | /* Left bottom corner */ | ||||
| if (roundboxtype & UI_CNR_BOTTOM_LEFT) { | if (roundboxtype & UI_CNR_BOTTOM_LEFT) { | ||||
| imm_buf_append(vbuf, cbuf, minx, miny + rad, col, &buf_index); | imm_buf_append(vbuf, cbuf, minx, miny + rad, col, &buf_index); | ||||
| for (a = 0; a < 4; a++) { | for (a = 0; a < 4; a++) { | ||||
| imm_buf_append(vbuf, cbuf, minx + vec[a][1], miny + rad - vec[a][0], col, &buf_index); | imm_buf_append(vbuf, cbuf, minx + vec[a][1], miny + rad - vec[a][0], col, &buf_index); | ||||
| } | } | ||||
| imm_buf_append(vbuf, cbuf, minx + rad, miny, col, &buf_index); | imm_buf_append(vbuf, cbuf, minx + rad, miny, col, &buf_index); | ||||
| } | } | ||||
| else { | else { | ||||
| imm_buf_append(vbuf, cbuf, minx, miny, col, &buf_index); | imm_buf_append(vbuf, cbuf, minx, miny, col, &buf_index); | ||||
| } | } | ||||
| /* corner right-bottom */ | /* Right bottom corner. */ | ||||
| if (roundboxtype & UI_CNR_BOTTOM_RIGHT) { | if (roundboxtype & UI_CNR_BOTTOM_RIGHT) { | ||||
| imm_buf_append(vbuf, cbuf, maxx - rad, miny, col, &buf_index); | imm_buf_append(vbuf, cbuf, maxx - rad, miny, col, &buf_index); | ||||
| for (a = 0; a < 4; a++) { | for (a = 0; a < 4; a++) { | ||||
| imm_buf_append(vbuf, cbuf, maxx - rad + vec[a][0], miny + vec[a][1], col, &buf_index); | imm_buf_append(vbuf, cbuf, maxx - rad + vec[a][0], miny + vec[a][1], col, &buf_index); | ||||
| } | } | ||||
| imm_buf_append(vbuf, cbuf, maxx, miny + rad, col, &buf_index); | imm_buf_append(vbuf, cbuf, maxx, miny + rad, col, &buf_index); | ||||
| } | } | ||||
| else { | else { | ||||
| Show All 24 Lines | |||||
| } | } | ||||
| /** | /** | ||||
| * Draw vertical tabs on the left side of the region, | * Draw vertical tabs on the left side of the region, | ||||
| * one tab per category. | * one tab per category. | ||||
| */ | */ | ||||
| void UI_panel_category_draw_all(ARegion *region, const char *category_id_active) | void UI_panel_category_draw_all(ARegion *region, const char *category_id_active) | ||||
| { | { | ||||
| /* no tab outlines for */ | /* No tab outlines for inactive tabs. */ | ||||
| // #define USE_FLAT_INACTIVE | /* #define USE_FLAT_INACTIVE */ | ||||
| const bool is_left = RGN_ALIGN_ENUM_FROM_MASK(region->alignment != RGN_ALIGN_RIGHT); | const bool is_left = RGN_ALIGN_ENUM_FROM_MASK(region->alignment != RGN_ALIGN_RIGHT); | ||||
| View2D *v2d = ®ion->v2d; | View2D *v2d = ®ion->v2d; | ||||
| const uiStyle *style = UI_style_get(); | const uiStyle *style = UI_style_get(); | ||||
| const uiFontStyle *fstyle = &style->widget; | const uiFontStyle *fstyle = &style->widget; | ||||
| const int fontid = fstyle->uifont_id; | const int fontid = fstyle->uifont_id; | ||||
| short fstyle_points = fstyle->points; | short fstyle_points = fstyle->points; | ||||
| const float aspect = ((uiBlock *)region->uiblocks.first)->aspect; | const float aspect = ((uiBlock *)region->uiblocks.first)->aspect; | ||||
| const float zoom = 1.0f / aspect; | const float zoom = 1.0f / aspect; | ||||
| const int px = max_ii(1, round_fl_to_int(U.pixelsize)); | const int px = max_ii(1, round_fl_to_int(U.pixelsize)); | ||||
| const int px_x_sign = is_left ? px : -px; | const int px_x_sign = is_left ? px : -px; | ||||
| const int category_tabs_width = round_fl_to_int(UI_PANEL_CATEGORY_MARGIN_WIDTH * zoom); | const int category_tabs_width = round_fl_to_int(UI_PANEL_CATEGORY_MARGIN_WIDTH * zoom); | ||||
| const float dpi_fac = UI_DPI_FAC; | const float dpi_fac = UI_DPI_FAC; | ||||
| /* padding of tabs around text */ | /* Padding of tabs around text. */ | ||||
| const int tab_v_pad_text = round_fl_to_int((2 + ((px * 3) * dpi_fac)) * zoom); | const int tab_v_pad_text = round_fl_to_int((2 + ((px * 3) * dpi_fac)) * zoom); | ||||
| /* padding between tabs */ | /* Padding between tabs. */ | ||||
| const int tab_v_pad = round_fl_to_int((4 + (2 * px * dpi_fac)) * zoom); | const int tab_v_pad = round_fl_to_int((4 + (2 * px * dpi_fac)) * zoom); | ||||
| const float tab_curve_radius = ((px * 3) * dpi_fac) * zoom; | const float tab_curve_radius = ((px * 3) * dpi_fac) * zoom; | ||||
| /* We flip the tab drawing, so always use these flags. */ | /* We flip the tab drawing, so always use these flags. */ | ||||
| const int roundboxtype = UI_CNR_TOP_LEFT | UI_CNR_BOTTOM_LEFT; | const int roundboxtype = UI_CNR_TOP_LEFT | UI_CNR_BOTTOM_LEFT; | ||||
| bool is_alpha; | bool is_alpha; | ||||
| bool do_scaletabs = false; | bool do_scaletabs = false; | ||||
| #ifdef USE_FLAT_INACTIVE | #ifdef USE_FLAT_INACTIVE | ||||
| bool is_active_prev = false; | bool is_active_prev = false; | ||||
| #endif | #endif | ||||
| float scaletabs = 1.0f; | float scaletabs = 1.0f; | ||||
| /* same for all tabs */ | /* Same for all tabs. */ | ||||
| /* intentionally dont scale by 'px' */ | /* Intentionally dont scale by 'px'. */ | ||||
| const int rct_xmin = is_left ? v2d->mask.xmin + 3 : (v2d->mask.xmax - category_tabs_width); | const int rct_xmin = is_left ? v2d->mask.xmin + 3 : (v2d->mask.xmax - category_tabs_width); | ||||
| const int rct_xmax = is_left ? v2d->mask.xmin + category_tabs_width : (v2d->mask.xmax - 3); | const int rct_xmax = is_left ? v2d->mask.xmin + category_tabs_width : (v2d->mask.xmax - 3); | ||||
| const int text_v_ofs = (rct_xmax - rct_xmin) * 0.3f; | const int text_v_ofs = (rct_xmax - rct_xmin) * 0.3f; | ||||
| int y_ofs = tab_v_pad; | int y_ofs = tab_v_pad; | ||||
| /* Primary theme colors */ | /* Primary theme colors. */ | ||||
| uchar theme_col_back[4]; | uchar theme_col_back[4]; | ||||
| uchar theme_col_text[3]; | uchar theme_col_text[3]; | ||||
| uchar theme_col_text_hi[3]; | uchar theme_col_text_hi[3]; | ||||
| /* Tab colors */ | /* Tab colors. */ | ||||
| uchar theme_col_tab_bg[4]; | uchar theme_col_tab_bg[4]; | ||||
| uchar theme_col_tab_active[3]; | uchar theme_col_tab_active[3]; | ||||
| uchar theme_col_tab_inactive[3]; | uchar theme_col_tab_inactive[3]; | ||||
| /* Secondary theme colors */ | /* Secondary theme colors. */ | ||||
| uchar theme_col_tab_outline[3]; | uchar theme_col_tab_outline[3]; | ||||
| uchar theme_col_tab_divider[3]; /* line that divides tabs from the main region */ | uchar theme_col_tab_divider[3]; /* Line that divides tabs from the main region. */ | ||||
| uchar theme_col_tab_highlight[3]; | uchar theme_col_tab_highlight[3]; | ||||
| uchar theme_col_tab_highlight_inactive[3]; | uchar theme_col_tab_highlight_inactive[3]; | ||||
| UI_GetThemeColor4ubv(TH_BACK, theme_col_back); | UI_GetThemeColor4ubv(TH_BACK, theme_col_back); | ||||
| UI_GetThemeColor3ubv(TH_TEXT, theme_col_text); | UI_GetThemeColor3ubv(TH_TEXT, theme_col_text); | ||||
| UI_GetThemeColor3ubv(TH_TEXT_HI, theme_col_text_hi); | UI_GetThemeColor3ubv(TH_TEXT_HI, theme_col_text_hi); | ||||
| UI_GetThemeColor4ubv(TH_TAB_BACK, theme_col_tab_bg); | UI_GetThemeColor4ubv(TH_TAB_BACK, theme_col_tab_bg); | ||||
| Show All 9 Lines | #endif | ||||
| is_alpha = (region->overlap && (theme_col_back[3] != 255)); | is_alpha = (region->overlap && (theme_col_back[3] != 255)); | ||||
| if (fstyle->kerning == 1) { | if (fstyle->kerning == 1) { | ||||
| BLF_enable(fstyle->uifont_id, BLF_KERNING_DEFAULT); | BLF_enable(fstyle->uifont_id, BLF_KERNING_DEFAULT); | ||||
| } | } | ||||
| BLF_enable(fontid, BLF_ROTATION); | BLF_enable(fontid, BLF_ROTATION); | ||||
| BLF_rotation(fontid, M_PI_2); | BLF_rotation(fontid, M_PI_2); | ||||
| // UI_fontstyle_set(&style->widget); | /* UI_fontstyle_set(&style->widget); */ | ||||
| ui_fontscale(&fstyle_points, aspect / (U.pixelsize * 1.1f)); | ui_fontscale(&fstyle_points, aspect / (U.pixelsize * 1.1f)); | ||||
| BLF_size(fontid, fstyle_points, U.dpi); | BLF_size(fontid, fstyle_points, U.dpi); | ||||
| /* Check the region type supports categories to avoid an assert | /* Check the region type supports categories to avoid an assert | ||||
| * for showing 3D view panels in the properties space. */ | * for showing 3D view panels in the properties space. */ | ||||
| if ((1 << region->regiontype) & RGN_TYPE_HAS_CATEGORY_MASK) { | if ((1 << region->regiontype) & RGN_TYPE_HAS_CATEGORY_MASK) { | ||||
| BLI_assert(UI_panel_category_is_visible(region)); | BLI_assert(UI_panel_category_is_visible(region)); | ||||
| } | } | ||||
| /* calculate tab rect's and check if we need to scale down */ | /* Calculate tab rects and check if we need to scale down. */ | ||||
| LISTBASE_FOREACH (PanelCategoryDyn *, pc_dyn, ®ion->panels_category) { | LISTBASE_FOREACH (PanelCategoryDyn *, pc_dyn, ®ion->panels_category) { | ||||
| rcti *rct = &pc_dyn->rect; | rcti *rct = &pc_dyn->rect; | ||||
| const char *category_id = pc_dyn->idname; | const char *category_id = pc_dyn->idname; | ||||
| const char *category_id_draw = IFACE_(category_id); | const char *category_id_draw = IFACE_(category_id); | ||||
| const int category_width = BLF_width(fontid, category_id_draw, BLF_DRAW_STR_DUMMY_MAX); | const int category_width = BLF_width(fontid, category_id_draw, BLF_DRAW_STR_DUMMY_MAX); | ||||
| rct->xmin = rct_xmin; | rct->xmin = rct_xmin; | ||||
| Show All 12 Lines | LISTBASE_FOREACH (PanelCategoryDyn *, pc_dyn, ®ion->panels_category) { | ||||
| rcti *rct = &pc_dyn->rect; | rcti *rct = &pc_dyn->rect; | ||||
| rct->ymin = ((rct->ymin - v2d->mask.ymax) * scaletabs) + v2d->mask.ymax; | rct->ymin = ((rct->ymin - v2d->mask.ymax) * scaletabs) + v2d->mask.ymax; | ||||
| rct->ymax = ((rct->ymax - v2d->mask.ymax) * scaletabs) + v2d->mask.ymax; | rct->ymax = ((rct->ymax - v2d->mask.ymax) * scaletabs) + v2d->mask.ymax; | ||||
| } | } | ||||
| do_scaletabs = true; | do_scaletabs = true; | ||||
| } | } | ||||
| /* begin drawing */ | /* Begin drawing. */ | ||||
| GPU_line_smooth(true); | GPU_line_smooth(true); | ||||
| uint pos = GPU_vertformat_attr_add( | uint pos = GPU_vertformat_attr_add( | ||||
| immVertexFormat(), "pos", GPU_COMP_I32, 2, GPU_FETCH_INT_TO_FLOAT); | immVertexFormat(), "pos", GPU_COMP_I32, 2, GPU_FETCH_INT_TO_FLOAT); | ||||
| immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); | immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); | ||||
| /* draw the background */ | /* Draw the background. */ | ||||
| if (is_alpha) { | if (is_alpha) { | ||||
| GPU_blend(true); | GPU_blend(true); | ||||
| immUniformColor4ubv(theme_col_tab_bg); | immUniformColor4ubv(theme_col_tab_bg); | ||||
| } | } | ||||
| else { | else { | ||||
| immUniformColor3ubv(theme_col_tab_bg); | immUniformColor3ubv(theme_col_tab_bg); | ||||
| } | } | ||||
| Show All 18 Lines | const int divider_xmax = is_left ? (v2d->mask.xmin + category_tabs_width) : | ||||
| (v2d->mask.xmax - (category_tabs_width + px)) + px; | (v2d->mask.xmax - (category_tabs_width + px)) + px; | ||||
| LISTBASE_FOREACH (PanelCategoryDyn *, pc_dyn, ®ion->panels_category) { | LISTBASE_FOREACH (PanelCategoryDyn *, pc_dyn, ®ion->panels_category) { | ||||
| const rcti *rct = &pc_dyn->rect; | const rcti *rct = &pc_dyn->rect; | ||||
| const char *category_id = pc_dyn->idname; | const char *category_id = pc_dyn->idname; | ||||
| const char *category_id_draw = IFACE_(category_id); | const char *category_id_draw = IFACE_(category_id); | ||||
| int category_width = BLI_rcti_size_y(rct) - (tab_v_pad_text * 2); | int category_width = BLI_rcti_size_y(rct) - (tab_v_pad_text * 2); | ||||
| size_t category_draw_len = BLF_DRAW_STR_DUMMY_MAX; | size_t category_draw_len = BLF_DRAW_STR_DUMMY_MAX; | ||||
| // int category_width = BLF_width(fontid, category_id_draw, BLF_DRAW_STR_DUMMY_MAX); | /* int category_width = BLF_width(fontid, category_id_draw, BLF_DRAW_STR_DUMMY_MAX); */ | ||||
| const bool is_active = STREQ(category_id, category_id_active); | const bool is_active = STREQ(category_id, category_id_active); | ||||
| GPU_blend(true); | GPU_blend(true); | ||||
| #ifdef USE_FLAT_INACTIVE | #ifdef USE_FLAT_INACTIVE | ||||
| if (is_active) | if (is_active) | ||||
| #endif | #endif | ||||
| { | { | ||||
| const bool use_flip_x = !is_left; | const bool use_flip_x = !is_left; | ||||
| ui_panel_category_draw_tab(true, | ui_panel_category_draw_tab(true, | ||||
| rct->xmin, | rct->xmin, | ||||
| rct->ymin, | rct->ymin, | ||||
| rct->xmax, | rct->xmax, | ||||
| rct->ymax, | rct->ymax, | ||||
| tab_curve_radius - px, | tab_curve_radius - px, | ||||
| roundboxtype, | roundboxtype, | ||||
| true, | true, | ||||
| true, | true, | ||||
| use_flip_x, | use_flip_x, | ||||
| NULL, | NULL, | ||||
| is_active ? theme_col_tab_active : theme_col_tab_inactive); | is_active ? theme_col_tab_active : theme_col_tab_inactive); | ||||
| /* tab outline */ | /* Tab outline. */ | ||||
| ui_panel_category_draw_tab(false, | ui_panel_category_draw_tab(false, | ||||
| rct->xmin - px_x_sign, | rct->xmin - px_x_sign, | ||||
| rct->ymin - px, | rct->ymin - px, | ||||
| rct->xmax - px_x_sign, | rct->xmax - px_x_sign, | ||||
| rct->ymax + px, | rct->ymax + px, | ||||
| tab_curve_radius, | tab_curve_radius, | ||||
| roundboxtype, | roundboxtype, | ||||
| true, | true, | ||||
| true, | true, | ||||
| use_flip_x, | use_flip_x, | ||||
| NULL, | NULL, | ||||
| theme_col_tab_outline); | theme_col_tab_outline); | ||||
| /* tab highlight (3d look) */ | /* Tab highlight (3d look). */ | ||||
| ui_panel_category_draw_tab(false, | ui_panel_category_draw_tab(false, | ||||
| rct->xmin, | rct->xmin, | ||||
| rct->ymin, | rct->ymin, | ||||
| rct->xmax, | rct->xmax, | ||||
| rct->ymax, | rct->ymax, | ||||
| tab_curve_radius, | tab_curve_radius, | ||||
| roundboxtype, | roundboxtype, | ||||
| true, | true, | ||||
| false, | false, | ||||
| use_flip_x, | use_flip_x, | ||||
| is_active ? theme_col_back : theme_col_tab_inactive, | is_active ? theme_col_back : theme_col_tab_inactive, | ||||
| is_active ? theme_col_tab_highlight : | is_active ? theme_col_tab_highlight : | ||||
| theme_col_tab_highlight_inactive); | theme_col_tab_highlight_inactive); | ||||
| } | } | ||||
| /* tab blackline */ | /* Tab blackline. */ | ||||
| if (!is_active) { | if (!is_active) { | ||||
| pos = GPU_vertformat_attr_add( | pos = GPU_vertformat_attr_add( | ||||
| immVertexFormat(), "pos", GPU_COMP_I32, 2, GPU_FETCH_INT_TO_FLOAT); | immVertexFormat(), "pos", GPU_COMP_I32, 2, GPU_FETCH_INT_TO_FLOAT); | ||||
| immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); | immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); | ||||
| immUniformColor3ubv(theme_col_tab_divider); | immUniformColor3ubv(theme_col_tab_divider); | ||||
| immRecti(pos, divider_xmin, rct->ymin - tab_v_pad, divider_xmax, rct->ymax + tab_v_pad); | immRecti(pos, divider_xmin, rct->ymin - tab_v_pad, divider_xmax, rct->ymax + tab_v_pad); | ||||
| immUnbindProgram(); | immUnbindProgram(); | ||||
| } | } | ||||
| if (do_scaletabs) { | if (do_scaletabs) { | ||||
| category_draw_len = BLF_width_to_strlen( | category_draw_len = BLF_width_to_strlen( | ||||
| fontid, category_id_draw, category_draw_len, category_width, NULL); | fontid, category_id_draw, category_draw_len, category_width, NULL); | ||||
| } | } | ||||
| BLF_position(fontid, rct->xmax - text_v_ofs, rct->ymin + tab_v_pad_text, 0.0f); | BLF_position(fontid, rct->xmax - text_v_ofs, rct->ymin + tab_v_pad_text, 0.0f); | ||||
| /* tab titles */ | /* Tab titles. */ | ||||
| /* draw white shadow to give text more depth */ | /* Draw white shadow to give text more depth. */ | ||||
| BLF_color3ubv(fontid, theme_col_text); | BLF_color3ubv(fontid, theme_col_text); | ||||
| /* main tab title */ | /* Main tab title. */ | ||||
| BLF_draw(fontid, category_id_draw, category_draw_len); | BLF_draw(fontid, category_id_draw, category_draw_len); | ||||
| GPU_blend(false); | GPU_blend(false); | ||||
| /* tab blackline remaining (last tab) */ | /* Tab blackline remaining (last tab). */ | ||||
| pos = GPU_vertformat_attr_add( | pos = GPU_vertformat_attr_add( | ||||
| immVertexFormat(), "pos", GPU_COMP_I32, 2, GPU_FETCH_INT_TO_FLOAT); | immVertexFormat(), "pos", GPU_COMP_I32, 2, GPU_FETCH_INT_TO_FLOAT); | ||||
| immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); | immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); | ||||
| if (pc_dyn->prev == NULL) { | if (pc_dyn->prev == NULL) { | ||||
| immUniformColor3ubv(theme_col_tab_divider); | immUniformColor3ubv(theme_col_tab_divider); | ||||
| immRecti(pos, divider_xmin, rct->ymax + px, divider_xmax, v2d->mask.ymax); | immRecti(pos, divider_xmin, rct->ymax + px, divider_xmax, v2d->mask.ymax); | ||||
| } | } | ||||
| if (pc_dyn->next == NULL) { | if (pc_dyn->next == NULL) { | ||||
| immUniformColor3ubv(theme_col_tab_divider); | immUniformColor3ubv(theme_col_tab_divider); | ||||
| immRecti(pos, divider_xmin, 0, divider_xmax, rct->ymin); | immRecti(pos, divider_xmin, 0, divider_xmax, rct->ymin); | ||||
| } | } | ||||
| #ifdef USE_FLAT_INACTIVE | #ifdef USE_FLAT_INACTIVE | ||||
| /* draw line between inactive tabs */ | /* Draw line between inactive tabs. */ | ||||
| if (is_active == false && is_active_prev == false && pc_dyn->prev) { | if (is_active == false && is_active_prev == false && pc_dyn->prev) { | ||||
| immUniformColor3ubv(theme_col_tab_divider); | immUniformColor3ubv(theme_col_tab_divider); | ||||
| immRecti(pos, | immRecti(pos, | ||||
| v2d->mask.xmin + (category_tabs_width / 5), | v2d->mask.xmin + (category_tabs_width / 5), | ||||
| rct->ymax + px, | rct->ymax + px, | ||||
| (v2d->mask.xmin + category_tabs_width) - (category_tabs_width / 5), | (v2d->mask.xmin + category_tabs_width) - (category_tabs_width / 5), | ||||
| rct->ymax + (px * 3)); | rct->ymax + (px * 3)); | ||||
| } | } | ||||
| is_active_prev = is_active; | is_active_prev = is_active; | ||||
| #endif | #endif | ||||
| immUnbindProgram(); | immUnbindProgram(); | ||||
| /* not essential, but allows events to be handled right up until the region edge [#38171] */ | /* Not essential, but allows events to be handled right up to the region edge (T38171). */ | ||||
| if (is_left) { | if (is_left) { | ||||
| pc_dyn->rect.xmin = v2d->mask.xmin; | pc_dyn->rect.xmin = v2d->mask.xmin; | ||||
| } | } | ||||
| else { | else { | ||||
| pc_dyn->rect.xmax = v2d->mask.xmax; | pc_dyn->rect.xmax = v2d->mask.xmax; | ||||
| } | } | ||||
| } | } | ||||
| GPU_line_smooth(false); | GPU_line_smooth(false); | ||||
| BLF_disable(fontid, BLF_ROTATION); | BLF_disable(fontid, BLF_ROTATION); | ||||
| if (fstyle->kerning == 1) { | if (fstyle->kerning == 1) { | ||||
| BLF_disable(fstyle->uifont_id, BLF_KERNING_DEFAULT); | BLF_disable(fstyle->uifont_id, BLF_KERNING_DEFAULT); | ||||
| } | } | ||||
| #undef USE_FLAT_INACTIVE | #undef USE_FLAT_INACTIVE | ||||
| } | } | ||||
| static int ui_handle_panel_category_cycling(const wmEvent *event, | static int handle_panel_category_cycling(const wmEvent *event, | ||||
| ARegion *region, | ARegion *region, | ||||
| const uiBut *active_but) | const uiBut *active_but) | ||||
| { | { | ||||
| const bool is_mousewheel = ELEM(event->type, WHEELUPMOUSE, WHEELDOWNMOUSE); | const bool is_mousewheel = ELEM(event->type, WHEELUPMOUSE, WHEELDOWNMOUSE); | ||||
| const bool inside_tabregion = | const bool inside_tabregion = | ||||
| ((RGN_ALIGN_ENUM_FROM_MASK(region->alignment) != RGN_ALIGN_RIGHT) ? | ((RGN_ALIGN_ENUM_FROM_MASK(region->alignment) != RGN_ALIGN_RIGHT) ? | ||||
| (event->mval[0] < ((PanelCategoryDyn *)region->panels_category.first)->rect.xmax) : | (event->mval[0] < ((PanelCategoryDyn *)region->panels_category.first)->rect.xmax) : | ||||
| (event->mval[0] > ((PanelCategoryDyn *)region->panels_category.first)->rect.xmin)); | (event->mval[0] > ((PanelCategoryDyn *)region->panels_category.first)->rect.xmin)); | ||||
| /* if mouse is inside non-tab region, ctrl key is required */ | /* If mouse is inside non-tab region, ctrl key is required. */ | ||||
| if (is_mousewheel && !event->ctrl && !inside_tabregion) { | if (is_mousewheel && !event->ctrl && !inside_tabregion) { | ||||
| return WM_UI_HANDLER_CONTINUE; | return WM_UI_HANDLER_CONTINUE; | ||||
| } | } | ||||
| if (active_but && ui_but_supports_cycling(active_but)) { | if (active_but && ui_but_supports_cycling(active_but)) { | ||||
| /* skip - exception to make cycling buttons | /* Skip - exception to make cycling buttons using ctrl+mousewheel work in tabbed regions. */ | ||||
| * using ctrl+mousewheel work in tabbed regions */ | |||||
| } | } | ||||
| else { | else { | ||||
| const char *category = UI_panel_category_active_get(region, false); | const char *category = UI_panel_category_active_get(region, false); | ||||
| if (LIKELY(category)) { | if (LIKELY(category)) { | ||||
| PanelCategoryDyn *pc_dyn = UI_panel_category_find(region, category); | PanelCategoryDyn *pc_dyn = UI_panel_category_find(region, category); | ||||
| if (LIKELY(pc_dyn)) { | if (LIKELY(pc_dyn)) { | ||||
| if (is_mousewheel) { | if (is_mousewheel) { | ||||
| /* we can probably get rid of this and only allow ctrl+tabbing */ | /* We can probably get rid of this and only allow ctrl+tabbing. */ | ||||
| pc_dyn = (event->type == WHEELDOWNMOUSE) ? pc_dyn->next : pc_dyn->prev; | pc_dyn = (event->type == WHEELDOWNMOUSE) ? pc_dyn->next : pc_dyn->prev; | ||||
| } | } | ||||
| else { | else { | ||||
| const bool backwards = event->shift; | const bool backwards = event->shift; | ||||
| pc_dyn = backwards ? pc_dyn->prev : pc_dyn->next; | pc_dyn = backwards ? pc_dyn->prev : pc_dyn->next; | ||||
| if (!pc_dyn) { | if (!pc_dyn) { | ||||
| /* proper cyclic behavior, | /* Proper cyclic behavior, back to first/last category (only used for ctrl+tab). */ | ||||
| * back to first/last category (only used for ctrl+tab) */ | |||||
| pc_dyn = backwards ? region->panels_category.last : region->panels_category.first; | pc_dyn = backwards ? region->panels_category.last : region->panels_category.first; | ||||
| } | } | ||||
| } | } | ||||
| if (pc_dyn) { | if (pc_dyn) { | ||||
| /* intentionally don't reset scroll in this case, | /* Intentionally don't reset scroll in this case. | ||||
| * this allows for quick browsing between tabs */ | * This allows for quick browsing between tabs. */ | ||||
| UI_panel_category_active_set(region, pc_dyn->idname); | UI_panel_category_active_set(region, pc_dyn->idname); | ||||
| ED_region_tag_redraw(region); | ED_region_tag_redraw(region); | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| return WM_UI_HANDLER_BREAK; | return WM_UI_HANDLER_BREAK; | ||||
| } | } | ||||
| return WM_UI_HANDLER_CONTINUE; | return WM_UI_HANDLER_CONTINUE; | ||||
| } | } | ||||
| /* XXX should become modal keymap */ | /** | ||||
| /* AKey is opening/closing panels, independent of button state now */ | * Handle events for the panel region. | ||||
| * AKey is opening/closing panels, independent of button state. | |||||
| * XXX should become modal keymap. | |||||
| */ | |||||
| int ui_handler_panel_region(bContext *C, | int ui_handler_panel_region(bContext *C, | ||||
| const wmEvent *event, | const wmEvent *event, | ||||
| ARegion *region, | ARegion *region, | ||||
| const uiBut *active_but) | const uiBut *active_but) | ||||
| { | { | ||||
| Panel *panel; | int retval = WM_UI_HANDLER_CONTINUE; | ||||
| int retval, mx, my; | |||||
| bool has_category_tabs = UI_panel_category_is_visible(region); | bool has_category_tabs = UI_panel_category_is_visible(region); | ||||
| retval = WM_UI_HANDLER_CONTINUE; | |||||
| /* Scrollbars can overlap panels now, they have handling priority. */ | /* Scrollbars can overlap panels now, they have handling priority. */ | ||||
| if (UI_view2d_mouse_in_scrollers(region, ®ion->v2d, event->x, event->y)) { | if (UI_view2d_mouse_in_scrollers(region, ®ion->v2d, event->x, event->y)) { | ||||
| return retval; | return retval; | ||||
| } | } | ||||
| /* handle category tabs */ | /* Handle category tabs. */ | ||||
| if (has_category_tabs) { | if (has_category_tabs) { | ||||
| if (event->val == KM_PRESS) { | if (event->val == KM_PRESS) { | ||||
| if (event->type == LEFTMOUSE) { | if (event->type == LEFTMOUSE) { | ||||
| PanelCategoryDyn *pc_dyn = UI_panel_category_find_mouse_over(region, event); | PanelCategoryDyn *pc_dyn = UI_panel_category_find_mouse_over(region, event); | ||||
| if (pc_dyn) { | if (pc_dyn) { | ||||
| UI_panel_category_active_set(region, pc_dyn->idname); | UI_panel_category_active_set(region, pc_dyn->idname); | ||||
| ED_region_tag_redraw(region); | ED_region_tag_redraw(region); | ||||
| /* reset scroll to the top [#38348] */ | /* Reset scroll to the top (T38348). */ | ||||
| UI_view2d_offset(®ion->v2d, -1.0f, 1.0f); | UI_view2d_offset(®ion->v2d, -1.0f, 1.0f); | ||||
| retval = WM_UI_HANDLER_BREAK; | retval = WM_UI_HANDLER_BREAK; | ||||
| } | } | ||||
| } | } | ||||
| else if ((event->type == EVT_TABKEY && event->ctrl) || | else if ((event->type == EVT_TABKEY && event->ctrl) || | ||||
| ELEM(event->type, WHEELUPMOUSE, WHEELDOWNMOUSE)) { | ELEM(event->type, WHEELUPMOUSE, WHEELDOWNMOUSE)) { | ||||
| /* cycle tabs */ | /* Cycle tabs. */ | ||||
| retval = ui_handle_panel_category_cycling(event, region, active_but); | retval = handle_panel_category_cycling(event, region, active_but); | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| if (retval == WM_UI_HANDLER_BREAK) { | if (retval == WM_UI_HANDLER_BREAK) { | ||||
| return retval; | return retval; | ||||
| } | } | ||||
| LISTBASE_FOREACH (uiBlock *, block, ®ion->uiblocks) { | LISTBASE_FOREACH (uiBlock *, block, ®ion->uiblocks) { | ||||
| uiPanelMouseState mouse_state; | Panel *panel = block->panel; | ||||
| mx = event->x; | |||||
| my = event->y; | |||||
| ui_window_to_block(region, block, &mx, &my); | |||||
| /* checks for mouse position inside */ | |||||
| panel = block->panel; | |||||
| if (!panel) { | if (!panel) { | ||||
| continue; | continue; | ||||
| } | } | ||||
| /* XXX - accessed freed panels when scripts reload, need to fix. */ | /* XXX - accessed freed panels when scripts reload, need to fix. */ | ||||
| if (panel->type && panel->type->flag & PNL_NO_HEADER) { | if (panel->type && panel->type->flag & PNL_NO_HEADER) { | ||||
| continue; | continue; | ||||
| } | } | ||||
| mouse_state = ui_panel_mouse_state_get(block, panel, mx, my); | int mx = event->x; | ||||
| int my = event->y; | |||||
| ui_window_to_block(region, block, &mx, &my); | |||||
| /* Check for mouse position inside panel. */ | |||||
| uiPanelMouseState mouse_state = panel_mouse_state(block, panel, mx, my); | |||||
| /* XXX hardcoded key warning */ | /* XXX hardcoded key warning */ | ||||
| if (ELEM(mouse_state, PANEL_MOUSE_INSIDE_CONTENT, PANEL_MOUSE_INSIDE_HEADER) && | if (ELEM(mouse_state, PANEL_MOUSE_INSIDE_CONTENT, PANEL_MOUSE_INSIDE_HEADER) && | ||||
| event->val == KM_PRESS) { | event->val == KM_PRESS) { | ||||
| if (event->type == EVT_AKEY && | if (event->type == EVT_AKEY && | ||||
| ((event->ctrl + event->oskey + event->shift + event->alt) == 0)) { | ((event->ctrl + event->oskey + event->shift + event->alt) == 0)) { | ||||
| if (panel->flag & PNL_CLOSEDY) { | if (panel->flag & PNL_CLOSEDY) { | ||||
| if ((block->rect.ymax <= my) && (block->rect.ymax + PNL_HEADER >= my)) { | if ((block->rect.ymax <= my) && (block->rect.ymax + PNL_HEADER >= my)) { | ||||
| ui_handle_panel_header(C, block, mx, my, event->type, event->ctrl, event->shift); | panel_handle_header(C, block, mx, my, event->type, event->ctrl, event->shift); | ||||
| } | } | ||||
| } | } | ||||
| else { | else { | ||||
| ui_handle_panel_header(C, block, mx, my, event->type, event->ctrl, event->shift); | panel_handle_header(C, block, mx, my, event->type, event->ctrl, event->shift); | ||||
| } | } | ||||
| retval = WM_UI_HANDLER_BREAK; | retval = WM_UI_HANDLER_BREAK; | ||||
| continue; | continue; | ||||
| } | } | ||||
| } | } | ||||
| /* on active button, do not handle panels */ | /* On active button, do not handle panels. */ | ||||
| if (ui_region_find_active_but(region) != NULL) { | if (ui_region_find_active_but(region) != NULL) { | ||||
| continue; | continue; | ||||
| } | } | ||||
| if (ELEM(mouse_state, PANEL_MOUSE_INSIDE_CONTENT, PANEL_MOUSE_INSIDE_HEADER)) { | if (ELEM(mouse_state, PANEL_MOUSE_INSIDE_CONTENT, PANEL_MOUSE_INSIDE_HEADER)) { | ||||
| if (event->val == KM_PRESS) { | if (event->val == KM_PRESS) { | ||||
| /* open close on header */ | /* Open and close on header. */ | ||||
| if (ELEM(event->type, EVT_RETKEY, EVT_PADENTER)) { | if (ELEM(event->type, EVT_RETKEY, EVT_PADENTER)) { | ||||
| if (mouse_state == PANEL_MOUSE_INSIDE_HEADER) { | if (mouse_state == PANEL_MOUSE_INSIDE_HEADER) { | ||||
| ui_handle_panel_header(C, block, mx, my, EVT_RETKEY, event->ctrl, event->shift); | panel_handle_header(C, block, mx, my, EVT_RETKEY, event->ctrl, event->shift); | ||||
| retval = WM_UI_HANDLER_BREAK; | retval = WM_UI_HANDLER_BREAK; | ||||
| break; | break; | ||||
| } | } | ||||
| } | } | ||||
| else if (event->type == LEFTMOUSE) { | else if (event->type == LEFTMOUSE) { | ||||
| /* all inside clicks should return in break - overlapping/float panels */ | /* All inside clicks should return in break - overlapping/float panels. */ | ||||
| retval = WM_UI_HANDLER_BREAK; | retval = WM_UI_HANDLER_BREAK; | ||||
| if (mouse_state == PANEL_MOUSE_INSIDE_HEADER) { | if (mouse_state == PANEL_MOUSE_INSIDE_HEADER) { | ||||
| ui_handle_panel_header(C, block, mx, my, event->type, event->ctrl, event->shift); | panel_handle_header(C, block, mx, my, event->type, event->ctrl, event->shift); | ||||
| retval = WM_UI_HANDLER_BREAK; | |||||
| break; | break; | ||||
| } | } | ||||
| if ((mouse_state == PANEL_MOUSE_INSIDE_SCALE) && !(panel->flag & PNL_CLOSED)) { | if ((mouse_state == PANEL_MOUSE_INSIDE_SCALE) && !(panel->flag & PNL_CLOSED)) { | ||||
| panel_activate_state(C, panel, PANEL_STATE_DRAG_SCALE); | panel_activate_state(C, panel, PANEL_STATE_DRAG_SCALE); | ||||
| retval = WM_UI_HANDLER_BREAK; | |||||
| break; | break; | ||||
| } | } | ||||
| } | } | ||||
| else if (event->type == RIGHTMOUSE) { | else if (event->type == RIGHTMOUSE) { | ||||
| if (mouse_state == PANEL_MOUSE_INSIDE_HEADER) { | if (mouse_state == PANEL_MOUSE_INSIDE_HEADER) { | ||||
| ui_popup_context_menu_for_panel(C, region, block->panel); | ui_popup_context_menu_for_panel(C, region, block->panel); | ||||
| retval = WM_UI_HANDLER_BREAK; | retval = WM_UI_HANDLER_BREAK; | ||||
| break; | break; | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| return retval; | return retval; | ||||
| } | } | ||||
| static void ui_panel_custom_data_set_recursive(Panel *panel, PointerRNA *custom_data) | static void panel_custom_data_set_recursive(Panel *panel, PointerRNA *custom_data) | ||||
| { | { | ||||
| panel->runtime.custom_data_ptr = custom_data; | panel->runtime.custom_data_ptr = custom_data; | ||||
| LISTBASE_FOREACH (Panel *, child_panel, &panel->children) { | LISTBASE_FOREACH (Panel *, child_panel, &panel->children) { | ||||
| ui_panel_custom_data_set_recursive(child_panel, custom_data); | panel_custom_data_set_recursive(child_panel, custom_data); | ||||
| } | } | ||||
| } | } | ||||
| void UI_panel_custom_data_set(Panel *panel, PointerRNA *custom_data) | void UI_panel_custom_data_set(Panel *panel, PointerRNA *custom_data) | ||||
| { | { | ||||
| BLI_assert(panel->type != NULL); | BLI_assert(panel->type != NULL); | ||||
| /* Free the old custom data, which should be shared among all of the panel's sub-panels. */ | /* Free the old custom data, which should be shared among all of the panel's sub-panels. */ | ||||
| if (panel->runtime.custom_data_ptr != NULL) { | if (panel->runtime.custom_data_ptr != NULL) { | ||||
| MEM_freeN(panel->runtime.custom_data_ptr); | MEM_freeN(panel->runtime.custom_data_ptr); | ||||
| } | } | ||||
| ui_panel_custom_data_set_recursive(panel, custom_data); | panel_custom_data_set_recursive(panel, custom_data); | ||||
| } | } | ||||
| PointerRNA *UI_region_panel_custom_data_under_cursor(const bContext *C, const wmEvent *event) | PointerRNA *UI_region_panel_custom_data_under_cursor(const bContext *C, const wmEvent *event) | ||||
| { | { | ||||
| ARegion *region = CTX_wm_region(C); | ARegion *region = CTX_wm_region(C); | ||||
| Panel *panel = NULL; | Panel *panel = NULL; | ||||
| LISTBASE_FOREACH (uiBlock *, block, ®ion->uiblocks) { | LISTBASE_FOREACH (uiBlock *, block, ®ion->uiblocks) { | ||||
| panel = block->panel; | panel = block->panel; | ||||
| if (panel == NULL) { | if (panel == NULL) { | ||||
| continue; | continue; | ||||
| } | } | ||||
| int mx = event->x; | int mx = event->x; | ||||
| int my = event->y; | int my = event->y; | ||||
| ui_window_to_block(region, block, &mx, &my); | ui_window_to_block(region, block, &mx, &my); | ||||
| int mouse_state = ui_panel_mouse_state_get(block, panel, mx, my); | int mouse_state = panel_mouse_state(block, panel, mx, my); | ||||
| if (ELEM(mouse_state, PANEL_MOUSE_INSIDE_CONTENT, PANEL_MOUSE_INSIDE_HEADER)) { | if (ELEM(mouse_state, PANEL_MOUSE_INSIDE_CONTENT, PANEL_MOUSE_INSIDE_HEADER)) { | ||||
| break; | break; | ||||
| } | } | ||||
| } | } | ||||
| if (panel == NULL) { | if (panel == NULL) { | ||||
| return NULL; | return NULL; | ||||
| } | } | ||||
| PointerRNA *customdata = panel->runtime.custom_data_ptr; | PointerRNA *customdata = panel->runtime.custom_data_ptr; | ||||
| return customdata; | return customdata; | ||||
| } | } | ||||
| /**************** window level modal panel interaction **************/ | /** \} */ | ||||
| /* -------------------------------------------------------------------- */ | |||||
| /** \name Window Level Modal Panel Interaction | |||||
| * \{ */ | |||||
| /* note, this is modal handler and should not swallow events for animation */ | /** | ||||
| static int ui_handler_panel(bContext *C, const wmEvent *event, void *userdata) | * \note This is modal handler and should not swallow events for animation | ||||
| */ | |||||
| static int panel_handler_modal(bContext *C, const wmEvent *event, void *userdata) | |||||
| { | { | ||||
| Panel *panel = userdata; | Panel *panel = userdata; | ||||
| uiHandlePanelData *data = panel->activedata; | uiHandlePanelData *data = panel->activedata; | ||||
| /* verify if we can stop */ | /* Verify if we can stop. */ | ||||
| if (event->type == LEFTMOUSE && event->val == KM_RELEASE) { | if (event->type == LEFTMOUSE && event->val == KM_RELEASE) { | ||||
| ScrArea *area = CTX_wm_area(C); | ScrArea *area = CTX_wm_area(C); | ||||
| ARegion *region = CTX_wm_region(C); | ARegion *region = CTX_wm_region(C); | ||||
| int align = panel_aligned(area, region); | int align = region_panel_alignment(area, region); | ||||
| if (align) { | if (align) { | ||||
| panel_activate_state(C, panel, PANEL_STATE_ANIMATION); | panel_activate_state(C, panel, PANEL_STATE_ANIMATION); | ||||
| } | } | ||||
| else { | else { | ||||
| panel_activate_state(C, panel, PANEL_STATE_EXIT); | panel_activate_state(C, panel, PANEL_STATE_EXIT); | ||||
| } | } | ||||
| } | } | ||||
| else if (event->type == MOUSEMOVE) { | else if (event->type == MOUSEMOVE) { | ||||
| if (data->state == PANEL_STATE_DRAG) { | if (data->state == PANEL_STATE_DRAG) { | ||||
| ui_do_drag(C, event, panel); | panel_drag(C, event, panel); | ||||
| } | } | ||||
| } | } | ||||
| else if (event->type == TIMER && event->customdata == data->animtimer) { | else if (event->type == TIMER && event->customdata == data->animtimer) { | ||||
| if (data->state == PANEL_STATE_ANIMATION) { | if (data->state == PANEL_STATE_ANIMATION) { | ||||
| ui_do_animate(C, panel); | panel_handle_animation(C, panel); | ||||
| } | } | ||||
| else if (data->state == PANEL_STATE_DRAG) { | else if (data->state == PANEL_STATE_DRAG) { | ||||
| ui_do_drag(C, event, panel); | panel_drag(C, event, panel); | ||||
| } | } | ||||
| } | } | ||||
| data = panel->activedata; | data = panel->activedata; | ||||
| if (data && data->state == PANEL_STATE_ANIMATION) { | if (data && data->state == PANEL_STATE_ANIMATION) { | ||||
| return WM_UI_HANDLER_CONTINUE; | return WM_UI_HANDLER_CONTINUE; | ||||
| } | } | ||||
| return WM_UI_HANDLER_BREAK; | return WM_UI_HANDLER_BREAK; | ||||
| } | } | ||||
| static void ui_handler_remove_panel(bContext *C, void *userdata) | static void panel_remove_handler(bContext *C, void *userdata) | ||||
| { | { | ||||
| Panel *panel = userdata; | Panel *panel = userdata; | ||||
| panel_activate_state(C, panel, PANEL_STATE_EXIT); | panel_activate_state(C, panel, PANEL_STATE_EXIT); | ||||
| } | } | ||||
| static void panel_activate_state(const bContext *C, Panel *panel, uiHandlePanelState state) | static void panel_activate_state(const bContext *C, Panel *panel, uiHandlePanelState state) | ||||
| { | { | ||||
| Show All 21 Lines | if (data && data->animtimer) { | ||||
| data->animtimer = NULL; | data->animtimer = NULL; | ||||
| } | } | ||||
| if (state == PANEL_STATE_EXIT) { | if (state == PANEL_STATE_EXIT) { | ||||
| MEM_freeN(data); | MEM_freeN(data); | ||||
| panel->activedata = NULL; | panel->activedata = NULL; | ||||
| WM_event_remove_ui_handler( | WM_event_remove_ui_handler( | ||||
| &win->modalhandlers, ui_handler_panel, ui_handler_remove_panel, panel, false); | &win->modalhandlers, panel_handler_modal, panel_remove_handler, panel, false); | ||||
| } | } | ||||
| else { | else { | ||||
| if (!data) { | if (!data) { | ||||
| data = MEM_callocN(sizeof(uiHandlePanelData), "uiHandlePanelData"); | data = MEM_callocN(sizeof(uiHandlePanelData), "uiHandlePanelData"); | ||||
| panel->activedata = data; | panel->activedata = data; | ||||
| WM_event_add_ui_handler( | WM_event_add_ui_handler( | ||||
| C, &win->modalhandlers, ui_handler_panel, ui_handler_remove_panel, panel, 0); | C, &win->modalhandlers, panel_handler_modal, panel_remove_handler, panel, 0); | ||||
| } | } | ||||
| if (ELEM(state, PANEL_STATE_ANIMATION, PANEL_STATE_DRAG)) { | if (ELEM(state, PANEL_STATE_ANIMATION, PANEL_STATE_DRAG)) { | ||||
| data->animtimer = WM_event_add_timer(CTX_wm_manager(C), win, TIMER, ANIMATION_INTERVAL); | data->animtimer = WM_event_add_timer(CTX_wm_manager(C), win, TIMER, ANIMATION_INTERVAL); | ||||
| } | } | ||||
| /* Initiate edge panning during drags so we can move beyond the initial region view. */ | /* Initiate edge panning during drags so we can move beyond the initial region view. */ | ||||
| if (state == PANEL_STATE_DRAG) { | if (state == PANEL_STATE_DRAG) { | ||||
| Show All 28 Lines | PanelType *UI_paneltype_find(int space_id, int region_id, const char *idname) | ||||
| if (st) { | if (st) { | ||||
| ARegionType *art = BKE_regiontype_from_id(st, region_id); | ARegionType *art = BKE_regiontype_from_id(st, region_id); | ||||
| if (art) { | if (art) { | ||||
| return BLI_findstring(&art->paneltypes, idname, offsetof(PanelType, idname)); | return BLI_findstring(&art->paneltypes, idname, offsetof(PanelType, idname)); | ||||
| } | } | ||||
| } | } | ||||
| return NULL; | return NULL; | ||||
| } | } | ||||
| /** \} */ | |||||