Changeset View
Changeset View
Standalone View
Standalone View
source/blender/editors/interface/interface_panel.c
| Show First 20 Lines • Show All 123 Lines • ▼ Show 20 Lines | |||||
| typedef struct PanelSort { | typedef struct PanelSort { | ||||
| Panel *panel; | Panel *panel; | ||||
| int new_offset_x; | int new_offset_x; | ||||
| int new_offset_y; | int new_offset_y; | ||||
| } PanelSort; | } PanelSort; | ||||
| static void panel_set_expansion_from_list_data(const bContext *C, Panel *panel); | static void panel_set_expansion_from_list_data(const bContext *C, Panel *panel); | ||||
| static int get_panel_real_size_y(const Panel *panel); | static int panel_real_size_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 *a, const void *b); | static int panel_compare_sort_order(const void *a, const void *b); | ||||
| static bool panel_type_context_poll(ARegion *region, | static bool panel_type_context_poll(ARegion *region, | ||||
| const PanelType *panel_type, | const PanelType *panel_type, | ||||
| const char *context); | const char *context); | ||||
| /** \} */ | /** \} */ | ||||
| /* -------------------------------------------------------------------- */ | /* -------------------------------------------------------------------- */ | ||||
| /** \name Local Functions | /** \name Local Functions | ||||
| * \{ */ | * \{ */ | ||||
| static bool panel_active_animation_changed(ListBase *lb, | static bool panels_active_animation_changed(ListBase *lb, | ||||
| Panel **r_panel_animation, | Panel **r_panel_animation, | ||||
| bool *r_no_animation) | bool *r_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 & PANEL_WAS_ACTIVE) && !(panel->runtime_flag & PANEL_ACTIVE)) { | if ((panel->runtime_flag & PANEL_WAS_ACTIVE) && !(panel->runtime_flag & PANEL_ACTIVE)) { | ||||
| return true; | return true; | ||||
| } | } | ||||
| if (!(panel->runtime_flag & PANEL_WAS_ACTIVE) && (panel->runtime_flag & PANEL_ACTIVE)) { | if (!(panel->runtime_flag & PANEL_WAS_ACTIVE) && (panel->runtime_flag & PANEL_ACTIVE)) { | ||||
| return true; | return true; | ||||
| } | } | ||||
| } | } | ||||
| /* Detect changes in panel expansions. */ | /* Detect changes in panel expansions. */ | ||||
| if ((bool)(panel->runtime_flag & PANEL_WAS_CLOSED) != UI_panel_is_closed(panel)) { | if ((bool)(panel->runtime_flag & PANEL_WAS_CLOSED) != UI_panel_is_closed(panel)) { | ||||
| *r_panel_animation = panel; | *r_panel_animation = panel; | ||||
| return false; | return false; | ||||
| } | } | ||||
| if ((panel->runtime_flag & PANEL_ACTIVE) && !UI_panel_is_closed(panel)) { | if ((panel->runtime_flag & PANEL_ACTIVE) && !UI_panel_is_closed(panel)) { | ||||
| if (panel_active_animation_changed(&panel->children, r_panel_animation, r_no_animation)) { | if (panels_active_animation_changed(&panel->children, r_panel_animation, r_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) { | ||||
| Show All 34 Lines | static bool panels_need_realign(const ScrArea *area, ARegion *region, Panel **r_panel_animation) | ||||
| if (properties_space_needs_realign(area, region)) { | if (properties_space_needs_realign(area, region)) { | ||||
| 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; | ||||
| } | } | ||||
| ▲ Show 20 Lines • Show All 228 Lines • ▼ Show 20 Lines | if (panel->type) { | ||||
| if (panel->type->flag & PANEL_TYPE_INSTANCED) { | if (panel->type->flag & PANEL_TYPE_INSTANCED) { | ||||
| if (panel_type_context_poll(region, panel->type, context)) { | if (panel_type_context_poll(region, panel->type, context)) { | ||||
| sort_index->panel = panel; | sort_index->panel = 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), panel_compare_sort_order); | ||||
| /* 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].panel == drag_panel) { | if (panel_sort[move_to_index].panel == drag_panel) { | ||||
| break; | break; | ||||
| } | } | ||||
| } | } | ||||
| ▲ Show 20 Lines • Show All 61 Lines • ▼ Show 20 Lines | if (panel->runtime_flag & PANEL_ACTIVE) { | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| /** | /** | ||||
| * Recursive implementation for #set_panels_list_data_expand_flag. | * Recursive implementation for #set_panels_list_data_expand_flag. | ||||
| */ | */ | ||||
| static void get_panel_expand_flag(const Panel *panel, short *flag, short *flag_index) | static void panel_expand_flag_from_data_recursive(const Panel *panel, | ||||
| short *flag, | |||||
| short *flag_index) | |||||
| { | { | ||||
| const bool open = !(panel->flag & PNL_CLOSED); | const bool open = !(panel->flag & PNL_CLOSED); | ||||
| SET_FLAG_FROM_TEST(*flag, open, (1 << *flag_index)); | SET_FLAG_FROM_TEST(*flag, open, (1 << *flag_index)); | ||||
| LISTBASE_FOREACH (const Panel *, child, &panel->children) { | LISTBASE_FOREACH (const Panel *, child, &panel->children) { | ||||
| *flag_index = *flag_index + 1; | *flag_index = *flag_index + 1; | ||||
| get_panel_expand_flag(child, flag, flag_index); | panel_expand_flag_from_data_recursive(child, flag, flag_index); | ||||
| } | } | ||||
| } | } | ||||
| /** | /** | ||||
| * Call the callback to store the panel and sub-panel expansion settings in the list item that | * Call the callback to store the panel and sub-panel expansion settings in the list item that | ||||
| * corresponds to each instanced panel. | * corresponds to each instanced panel. | ||||
| * | * | ||||
| * \note This needs to iterate through all of the region's panels because the panel with changed | * \note This needs to iterate through all of the region's panels because the panel with changed | ||||
| * expansion might have been the sub-panel of an instanced panel, meaning it might not know | * expansion might have been the sub-panel of an instanced panel, meaning it might not know | ||||
| * which list item it corresponds to. | * which list item it corresponds to. | ||||
| */ | */ | ||||
| static void set_panels_list_data_expand_flag(const bContext *C, const ARegion *region) | static void set_panels_list_data_expand_flag(const bContext *C, const ARegion *region) | ||||
| { | { | ||||
| 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 #PANEL_ACTIVE so we only set the expand flag for active panels. */ | /* Check for #PANEL_ACTIVE so we only set the expand flag for active panels. */ | ||||
| if (panel_type->flag & PANEL_TYPE_INSTANCED && panel->runtime_flag & PANEL_ACTIVE) { | if (panel_type->flag & PANEL_TYPE_INSTANCED && panel->runtime_flag & PANEL_ACTIVE) { | ||||
| short expand_flag; | short expand_flag; | ||||
| short flag_index = 0; | short flag_index = 0; | ||||
| get_panel_expand_flag(panel, &expand_flag, &flag_index); | panel_expand_flag_from_data_recursive(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); | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| /** \} */ | /** \} */ | ||||
| ▲ Show 20 Lines • Show All 232 Lines • ▼ Show 20 Lines | |||||
| { | { | ||||
| int width = panel->blocksizex; | int width = panel->blocksizex; | ||||
| int height = panel->blocksizey; | int height = panel->blocksizey; | ||||
| LISTBASE_FOREACH (Panel *, child_panel, &panel->children) { | LISTBASE_FOREACH (Panel *, child_panel, &panel->children) { | ||||
| if (child_panel->runtime_flag & PANEL_ACTIVE) { | if (child_panel->runtime_flag & PANEL_ACTIVE) { | ||||
| panel_calculate_size_recursive(region, child_panel); | panel_calculate_size_recursive(region, child_panel); | ||||
| width = max_ii(width, child_panel->sizex); | width = max_ii(width, child_panel->sizex); | ||||
| height += get_panel_real_size_y(child_panel); | height += panel_real_size_y(child_panel); | ||||
| } | } | ||||
| } | } | ||||
| /* Update total panel size. */ | /* Update total panel size. */ | ||||
| if (panel->runtime_flag & PANEL_NEW_ADDED) { | if (panel->runtime_flag & PANEL_NEW_ADDED) { | ||||
| panel->runtime_flag &= ~PANEL_NEW_ADDED; | panel->runtime_flag &= ~PANEL_NEW_ADDED; | ||||
| panel->sizex = width; | panel->sizex = width; | ||||
| panel->sizey = height; | panel->sizey = height; | ||||
| Show All 26 Lines | |||||
| void UI_panel_end(Panel *panel, int width, int height) | void UI_panel_end(Panel *panel, int width, int height) | ||||
| { | { | ||||
| /* Store the size of the buttons layout in the panel. The actual panel size | /* Store the size of the buttons layout in the panel. The actual panel size | ||||
| * (including sub-panels) is calculated in #UI_panels_end. */ | * (including sub-panels) is calculated in #UI_panels_end. */ | ||||
| panel->blocksizex = width; | panel->blocksizex = width; | ||||
| panel->blocksizey = height; | panel->blocksizey = height; | ||||
| } | } | ||||
| static void ui_offset_panel_block(uiBlock *block) | static void panel_block_buttons_offset(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); | ||||
| const int ofsy = block->panel->sizey - style->panelspace; | const int ofsy = block->panel->sizey - style->panelspace; | ||||
| ▲ Show 20 Lines • Show All 432 Lines • ▼ Show 20 Lines | else { | ||||
| GPU_blend(GPU_BLEND_NONE); | GPU_blend(GPU_BLEND_NONE); | ||||
| immUnbindProgram(); | immUnbindProgram(); | ||||
| } | } | ||||
| } | } | ||||
| /** | /** | ||||
| * Draw a panel integrated in buttons-window, tool/property lists etc. | * Draw a panel integrated in buttons-window, tool/property lists etc. | ||||
| */ | */ | ||||
| void ui_draw_aligned_panel(const uiStyle *style, | void ui_panel_draw_aligned(const uiStyle *style, | ||||
| const uiBlock *block, | const uiBlock *block, | ||||
| const rcti *rect, | const rcti *rect, | ||||
| const bool show_pin, | const bool show_pin, | ||||
| const bool show_background, | const bool show_background, | ||||
| const bool region_search_filter_active) | const bool region_search_filter_active) | ||||
| { | { | ||||
| const Panel *panel = block->panel; | const Panel *panel = block->panel; | ||||
| Show All 32 Lines | |||||
| * \{ */ | * \{ */ | ||||
| #define TABS_PADDING_BETWEEN_FACTOR 4.0f | #define TABS_PADDING_BETWEEN_FACTOR 4.0f | ||||
| #define TABS_PADDING_TEXT_FACTOR 6.0f | #define TABS_PADDING_TEXT_FACTOR 6.0f | ||||
| /** | /** | ||||
| * Draw vertical tabs on the left side of the region, one tab per category. | * Draw vertical tabs on the left side of the region, one tab per category. | ||||
| */ | */ | ||||
| void UI_panel_category_draw_all(ARegion *region, const char *category_id_active) | void UI_panel_category_tabs_draw(ARegion *region, const char *category_id_active) | ||||
| { | { | ||||
| // #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; | ||||
| ▲ Show 20 Lines • Show All 223 Lines • ▼ Show 20 Lines | |||||
| #undef TABS_PADDING_TEXT_FACTOR | #undef TABS_PADDING_TEXT_FACTOR | ||||
| /** \} */ | /** \} */ | ||||
| /* -------------------------------------------------------------------- */ | /* -------------------------------------------------------------------- */ | ||||
| /** \name Panel Alignment | /** \name Panel Alignment | ||||
| * \{ */ | * \{ */ | ||||
| static int get_panel_size_y(const Panel *panel) | static int panel_size_y(const Panel *panel) | ||||
| { | { | ||||
| if (panel->type && (panel->type->flag & PANEL_TYPE_NO_HEADER)) { | if (panel->type && (panel->type->flag & PANEL_TYPE_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) | static int panel_real_size_y(const Panel *panel) | ||||
| { | { | ||||
| const int sizey = UI_panel_is_closed(panel) ? 0 : panel->sizey; | const int sizey = UI_panel_is_closed(panel) ? 0 : panel->sizey; | ||||
| if (panel->type && (panel->type->flag & PANEL_TYPE_NO_HEADER)) { | if (panel->type && (panel->type->flag & PANEL_TYPE_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_real_size_y(panel); | ||||
| } | } | ||||
| /** | /** | ||||
| * This function is needed because #uiBlock and Panel itself don't | * This function is needed because #uiBlock and Panel itself don't | ||||
| * change #Panel.sizey or location when closed. | * change #Panel.sizey or location when closed. | ||||
| */ | */ | ||||
| static int get_panel_real_ofsy(Panel *panel) | static int panel_real_offset_y(Panel *panel) | ||||
| { | { | ||||
| if (UI_panel_is_closed(panel)) { | if (UI_panel_is_closed(panel)) { | ||||
| return panel->ofsy + panel->sizey; | return panel->ofsy + panel->sizey; | ||||
| } | } | ||||
| return panel->ofsy; | return panel->ofsy; | ||||
| } | } | ||||
| bool UI_panel_is_dragging(const Panel *panel) | bool UI_panel_is_dragging(const Panel *panel) | ||||
| Show All 37 Lines | static int find_highest_panel(const void *a, const void *b) | ||||
| } | } | ||||
| if (panel_a->sortorder < panel_b->sortorder) { | if (panel_a->sortorder < panel_b->sortorder) { | ||||
| return -1; | return -1; | ||||
| } | } | ||||
| return 0; | return 0; | ||||
| } | } | ||||
| static int compare_panel(const void *a, const void *b) | static int panel_compare_sort_order(const void *a, const void *b) | ||||
| { | { | ||||
| const Panel *panel_a = ((PanelSort *)a)->panel; | const Panel *panel_a = ((PanelSort *)a)->panel; | ||||
| const Panel *panel_b = ((PanelSort *)b)->panel; | const Panel *panel_b = ((PanelSort *)b)->panel; | ||||
| if (panel_a->sortorder > panel_b->sortorder) { | if (panel_a->sortorder > panel_b->sortorder) { | ||||
| return 1; | return 1; | ||||
| } | } | ||||
| if (panel_a->sortorder < panel_b->sortorder) { | if (panel_a->sortorder < panel_b->sortorder) { | ||||
| return -1; | return -1; | ||||
| } | } | ||||
| return 0; | return 0; | ||||
| } | } | ||||
| static void align_sub_panels(Panel *panel) | static void align_sub_panels(Panel *panel) | ||||
| { | { | ||||
| /* Position sub panels. */ | /* 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 & PANEL_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_real_size_y(pachild); | ||||
| if (pachild->children.first) { | if (pachild->children.first) { | ||||
| align_sub_panels(pachild); | align_sub_panels(pachild); | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| /** | /** | ||||
| * Calculate the position and order of panels as they are opened, closed, and dragged. | * Calculate the position and order of panels as they are opened, closed, and dragged. | ||||
| */ | */ | ||||
| static bool uiAlignPanelStep(ARegion *region, const float factor, const bool drag) | static bool panels_align_step(ARegion *region, const float factor, const bool drag) | ||||
| { | { | ||||
| /* Count active panels. */ | /* Count active panels. */ | ||||
| int active_panels_len = 0; | int active_panels_len = 0; | ||||
| LISTBASE_FOREACH (Panel *, panel, ®ion->panels) { | LISTBASE_FOREACH (Panel *, panel, ®ion->panels) { | ||||
| if (panel->runtime_flag & PANEL_ACTIVE) { | if (panel->runtime_flag & PANEL_ACTIVE) { | ||||
| /* These panels should have types since they are currently displayed to the user. */ | /* These panels should have types since they are currently displayed to the user. */ | ||||
| BLI_assert(panel->type != NULL); | BLI_assert(panel->type != NULL); | ||||
| active_panels_len++; | active_panels_len++; | ||||
| Show All 19 Lines | if (drag) { | ||||
| /* While dragging, sort based on location and update #Panel.sortorder. */ | /* While dragging, sort based on location and update #Panel.sortorder. */ | ||||
| qsort(panel_sort, active_panels_len, sizeof(PanelSort), find_highest_panel); | qsort(panel_sort, active_panels_len, sizeof(PanelSort), find_highest_panel); | ||||
| for (int i = 0; i < active_panels_len; i++) { | for (int i = 0; i < active_panels_len; i++) { | ||||
| panel_sort[i].panel->sortorder = i; | panel_sort[i].panel->sortorder = i; | ||||
| } | } | ||||
| } | } | ||||
| else { | else { | ||||
| /* Otherwise use #Panel.sortorder. */ | /* Otherwise use #Panel.sortorder. */ | ||||
| qsort(panel_sort, active_panels_len, sizeof(PanelSort), compare_panel); | qsort(panel_sort, active_panels_len, sizeof(PanelSort), panel_compare_sort_order); | ||||
| } | } | ||||
| /* X offset. */ | /* X offset. */ | ||||
| const int region_offset_x = panel_region_offset_x_get(region); | const int region_offset_x = panel_region_offset_x_get(region); | ||||
| for (int i = 0; i < active_panels_len; i++) { | for (int i = 0; i < active_panels_len; i++) { | ||||
| PanelSort *ps = &panel_sort[i]; | PanelSort *ps = &panel_sort[i]; | ||||
| const bool use_box = ps->panel->type->flag & PANEL_TYPE_DRAW_BOX; | const bool use_box = ps->panel->type->flag & PANEL_TYPE_DRAW_BOX; | ||||
| ps->panel->runtime.region_ofsx = region_offset_x; | ps->panel->runtime.region_ofsx = region_offset_x; | ||||
| ps->new_offset_x = region_offset_x + ((use_box) ? UI_PANEL_BOX_STYLE_MARGIN : 0); | ps->new_offset_x = region_offset_x + ((use_box) ? UI_PANEL_BOX_STYLE_MARGIN : 0); | ||||
| } | } | ||||
| /* Y offset. */ | /* Y offset. */ | ||||
| for (int i = 0, y = 0; i < active_panels_len; i++) { | for (int i = 0, y = 0; i < active_panels_len; i++) { | ||||
| PanelSort *ps = &panel_sort[i]; | PanelSort *ps = &panel_sort[i]; | ||||
| y -= get_panel_real_size_y(ps->panel); | y -= panel_real_size_y(ps->panel); | ||||
| const bool use_box = ps->panel->type->flag & PANEL_TYPE_DRAW_BOX; | const bool use_box = ps->panel->type->flag & PANEL_TYPE_DRAW_BOX; | ||||
| if (use_box) { | if (use_box) { | ||||
| y -= UI_PANEL_BOX_STYLE_MARGIN; | y -= UI_PANEL_BOX_STYLE_MARGIN; | ||||
| } | } | ||||
| ps->new_offset_y = y; | ps->new_offset_y = y; | ||||
| /* The header still draws offset by the size of closed panels, so apply the offset here. */ | /* The header still draws offset by the size of closed panels, so apply the offset here. */ | ||||
| if (UI_panel_is_closed(ps->panel)) { | if (UI_panel_is_closed(ps->panel)) { | ||||
| Show All 30 Lines | LISTBASE_FOREACH (Panel *, panel, ®ion->panels) { | ||||
| } | } | ||||
| } | } | ||||
| MEM_freeN(panel_sort); | MEM_freeN(panel_sort); | ||||
| return changed; | return changed; | ||||
| } | } | ||||
| static void ui_panels_size(ARegion *region, int *r_x, int *r_y) | static void region_panels_size(ARegion *region, int *r_x, int *r_y) | ||||
| { | { | ||||
| int sizex = 0; | int sizex = 0; | ||||
| int sizey = 0; | int sizey = 0; | ||||
| /* Compute size taken up by panels, for setting in view2d. */ | /* 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 & PANEL_ACTIVE) { | if (panel->runtime_flag & PANEL_ACTIVE) { | ||||
| const int pa_sizex = panel->ofsx + panel->sizex; | const int pa_sizex = panel->ofsx + panel->sizex; | ||||
| const int pa_sizey = get_panel_real_ofsy(panel); | const int pa_sizey = panel_real_offset_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_animate(bContext *C, Panel *panel) | ||||
| { | { | ||||
| uiHandlePanelData *data = panel->activedata; | uiHandlePanelData *data = panel->activedata; | ||||
| ARegion *region = CTX_wm_region(C); | ARegion *region = CTX_wm_region(C); | ||||
| float fac = (PIL_check_seconds_timer() - data->starttime) / ANIMATION_TIME; | float fac = (PIL_check_seconds_timer() - data->starttime) / ANIMATION_TIME; | ||||
| fac = min_ff(sqrtf(fac), 1.0f); | fac = min_ff(sqrtf(fac), 1.0f); | ||||
| if (uiAlignPanelStep(region, fac, false)) { | if (panels_align_step(region, fac, false)) { | ||||
| ED_region_tag_redraw(region); | ED_region_tag_redraw(region); | ||||
| } | } | ||||
| else { | else { | ||||
| if (UI_panel_is_dragging(panel)) { | if (UI_panel_is_dragging(panel)) { | ||||
| /* Note: doing this in #panel_activate_state would require | /* Note: doing this in #panel_activate_state would require | ||||
| * removing `const` for context in many other places. */ | * removing `const` for context in many other places. */ | ||||
| reorder_instanced_panel_list(C, region, panel); | reorder_instanced_panel_list(C, region, panel); | ||||
| } | } | ||||
| ▲ Show 20 Lines • Show All 50 Lines • ▼ Show 20 Lines | if (panel->runtime_flag & PANEL_ACTIVE) { | ||||
| BLI_assert(panel->runtime.block != NULL); | BLI_assert(panel->runtime.block != NULL); | ||||
| panel_calculate_size_recursive(region, panel); | panel_calculate_size_recursive(region, panel); | ||||
| } | } | ||||
| } | } | ||||
| /* Offset contents. */ | /* Offset 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); | panel_block_buttons_offset(block); | ||||
| } | } | ||||
| } | } | ||||
| /* Re-align, possibly with animation. */ | /* Re-align, possibly with animation. */ | ||||
| Panel *panel; | Panel *panel; | ||||
| if (panels_need_realign(area, region, &panel)) { | if (panels_need_realign(area, region, &panel)) { | ||||
| if (panel) { | if (panel) { | ||||
| panel_activate_state(C, panel, PANEL_STATE_ANIMATION); | panel_activate_state(C, panel, PANEL_STATE_ANIMATION); | ||||
| } | } | ||||
| else { | else { | ||||
| uiAlignPanelStep(region, 1.0, false); | panels_align_step(region, 1.0, false); | ||||
| } | } | ||||
| } | } | ||||
| /* Compute size taken up by panels. */ | /* Compute size taken up by panels. */ | ||||
| ui_panels_size(region, r_x, r_y); | region_panels_size(region, r_x, r_y); | ||||
| } | } | ||||
| /** \} */ | /** \} */ | ||||
| /* -------------------------------------------------------------------- */ | /* -------------------------------------------------------------------- */ | ||||
| /** \name 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_handle_drag(const bContext *C, const wmEvent *event, Panel *panel) | ||||
| { | { | ||||
| uiHandlePanelData *data = panel->activedata; | uiHandlePanelData *data = panel->activedata; | ||||
| ARegion *region = CTX_wm_region(C); | ARegion *region = CTX_wm_region(C); | ||||
| /* 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. */ | ||||
| const int y = clamp_i(event->y, region->winrct.ymin, region->winrct.ymax + DRAG_REGION_PAD); | const int y = clamp_i(event->y, region->winrct.ymin, region->winrct.ymax + DRAG_REGION_PAD); | ||||
| float dy = (float)(y - data->starty); | float dy = (float)(y - data->starty); | ||||
| /* Adjust for region zoom. */ | /* Adjust for region zoom. */ | ||||
| dy *= BLI_rctf_size_y(®ion->v2d.cur) / (float)BLI_rcti_size_y(®ion->winrct); | dy *= BLI_rctf_size_y(®ion->v2d.cur) / (float)BLI_rcti_size_y(®ion->winrct); | ||||
| /* Add the movement of the view due to edge scrolling while dragging. */ | /* Add the movement of the view due to edge scrolling while dragging. */ | ||||
| dy += ((float)region->v2d.cur.ymin - data->start_cur_ymin); | dy += ((float)region->v2d.cur.ymin - data->start_cur_ymin); | ||||
| panel->ofsy = data->startofsy + round_fl_to_int(dy); | panel->ofsy = data->startofsy + round_fl_to_int(dy); | ||||
| uiAlignPanelStep(region, 0.2f, true); | panels_align_step(region, 0.2f, true); | ||||
| ED_region_tag_redraw(region); | ED_region_tag_redraw(region); | ||||
| } | } | ||||
| #undef DRAG_REGION_PAD | #undef DRAG_REGION_PAD | ||||
| /** \} */ | /** \} */ | ||||
| /* -------------------------------------------------------------------- */ | /* -------------------------------------------------------------------- */ | ||||
| /** \name Region Level Panel Interaction | /** \name Region Level Panel Interaction | ||||
| * \{ */ | * \{ */ | ||||
| static uiPanelMouseState ui_panel_mouse_state_get(const uiBlock *block, | static uiPanelMouseState panel_mouse_state_get(const uiBlock *block, | ||||
| const Panel *panel, | const Panel *panel, | ||||
| const int mx, | const int mx, | ||||
| const int my) | const int my) | ||||
| { | { | ||||
| if (!IN_RANGE((float)mx, block->rect.xmin, block->rect.xmax)) { | if (!IN_RANGE((float)mx, block->rect.xmin, block->rect.xmax)) { | ||||
| return PANEL_MOUSE_OUTSIDE; | return PANEL_MOUSE_OUTSIDE; | ||||
| } | } | ||||
| if (IN_RANGE((float)my, block->rect.ymax, block->rect.ymax + PNL_HEADER)) { | if (IN_RANGE((float)my, block->rect.ymax, block->rect.ymax + PNL_HEADER)) { | ||||
| return PANEL_MOUSE_INSIDE_HEADER; | return PANEL_MOUSE_INSIDE_HEADER; | ||||
| } | } | ||||
| if (!UI_panel_is_closed(panel)) { | if (!UI_panel_is_closed(panel)) { | ||||
| if (IN_RANGE((float)my, block->rect.ymin, block->rect.ymax + PNL_HEADER)) { | if (IN_RANGE((float)my, block->rect.ymin, block->rect.ymax + PNL_HEADER)) { | ||||
| 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(const bContext *C, | static void panels_drag_collapse(const bContext *C, | ||||
| const uiPanelDragCollapseHandle *dragcol_data, | const uiPanelDragCollapseHandle *dragcol_data, | ||||
| const int xy_dst[2]) | const int xy_dst[2]) | ||||
| { | { | ||||
| ARegion *region = CTX_wm_region(C); | ARegion *region = CTX_wm_region(C); | ||||
| 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)}; | ||||
| Panel *panel = block->panel; | Panel *panel = block->panel; | ||||
| Show All 31 Lines | |||||
| } | } | ||||
| /** | /** | ||||
| * Panel drag-collapse (modal handler). | * Panel drag-collapse (modal handler). | ||||
| * Clicking and dragging over panels toggles their collapse state based on the panel | * 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 including the initial | * that was first dragged over. If it was open all affected panels including the initial | ||||
| * one are closed and vice versa. | * one are closed and vice versa. | ||||
| */ | */ | ||||
| static int ui_panel_drag_collapse_handler(bContext *C, const wmEvent *event, void *userdata) | static int panel_handle_drag_collapse(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); | panels_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_handle_drag_collapse, | ||||
| 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 panels_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_handle_drag_collapse, | ||||
| ui_panel_drag_collapse_handler_remove, | panel_drag_collapse_handler_remove, | ||||
| dragcol_data, | dragcol_data, | ||||
| 0); | 0); | ||||
| } | } | ||||
| /** | /** | ||||
| * Supposing the block has a panel and isn't a menu, handle opening, closing, pinning, etc. | * Supposing the block has a panel and isn't a menu, handle opening, closing, pinning, etc. | ||||
| * Code currently assumes layout style for location of widgets | * Code currently assumes layout style for location of widgets | ||||
| * | * | ||||
| * \param mx: The mouse x coordinate, in panel space. | * \param mx: The mouse x coordinate, in panel space. | ||||
| */ | */ | ||||
| static void ui_handle_panel_header(const bContext *C, | static void panel_handle_header(const bContext *C, | ||||
| const uiBlock *block, | const uiBlock *block, | ||||
| const int mx, | const int mx, | ||||
| const int event_type, | const int event_type, | ||||
| const short ctrl, | const short ctrl, | ||||
| const short shift) | const short shift) | ||||
| { | { | ||||
| Panel *panel = block->panel; | Panel *panel = block->panel; | ||||
| ARegion *region = CTX_wm_region(C); | ARegion *region = CTX_wm_region(C); | ||||
| BLI_assert(panel->type != NULL); | BLI_assert(panel->type != NULL); | ||||
| BLI_assert(!(panel->type->flag & PANEL_TYPE_NO_HEADER)); | BLI_assert(!(panel->type->flag & PANEL_TYPE_NO_HEADER)); | ||||
| const bool is_subpanel = (panel->type->parent != NULL); | const bool is_subpanel = (panel->type->parent != NULL); | ||||
| Show All 34 Lines | if (ctrl && !is_subpanel) { | ||||
| panel_set_flag_recursive(panel, PNL_CLOSED, !UI_panel_is_closed(first_child)); | panel_set_flag_recursive(panel, PNL_CLOSED, !UI_panel_is_closed(first_child)); | ||||
| panel->flag |= PNL_CLOSED; | panel->flag |= PNL_CLOSED; | ||||
| } | } | ||||
| } | } | ||||
| SET_FLAG_FROM_TEST(panel->flag, !UI_panel_is_closed(panel), PNL_CLOSED); | SET_FLAG_FROM_TEST(panel->flag, !UI_panel_is_closed(panel), PNL_CLOSED); | ||||
| if (event_type == LEFTMOUSE) { | if (event_type == LEFTMOUSE) { | ||||
| ui_panel_drag_collapse_handler_add(C, UI_panel_is_closed(panel)); | panels_drag_collapse_handler_add(C, UI_panel_is_closed(panel)); | ||||
| } | } | ||||
| set_panels_list_data_expand_flag(C, region); | set_panels_list_data_expand_flag(C, region); | ||||
| panel_activate_state(C, panel, PANEL_STATE_ANIMATION); | panel_activate_state(C, panel, PANEL_STATE_ANIMATION); | ||||
| return; | return; | ||||
| } | } | ||||
| /* Handle panel dragging. For now don't allow dragging in floating regions. */ | /* Handle panel dragging. For now don't allow dragging in floating regions. */ | ||||
| Show All 31 Lines | |||||
| } | } | ||||
| 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 { | ||||
| Show All 24 Lines | while ((pc_act = pc_act_next)) { | ||||
| 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; | ||||
| } | } | ||||
| static PanelCategoryDyn *panel_categories_find_mouse_over(ARegion *region, const wmEvent *event) | static PanelCategoryDyn *panel_categories_find_mouse_over(ARegion *region, const wmEvent *event) | ||||
| ▲ Show 20 Lines • Show All 135 Lines • ▼ Show 20 Lines | LISTBASE_FOREACH (uiBlock *, block, ®ion->uiblocks) { | ||||
| if (panel->type->flag & PANEL_TYPE_NO_HEADER) { | if (panel->type->flag & PANEL_TYPE_NO_HEADER) { | ||||
| 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); | ||||
| const uiPanelMouseState mouse_state = ui_panel_mouse_state_get(block, panel, mx, my); | const uiPanelMouseState mouse_state = panel_mouse_state_get(block, panel, mx, my); | ||||
| if (mouse_state != PANEL_MOUSE_OUTSIDE) { | if (mouse_state != PANEL_MOUSE_OUTSIDE) { | ||||
| /* Mark panels that have been interacted with so their expansion | /* Mark panels that have been interacted with so their expansion | ||||
| * doesn't reset when property search finishes. */ | * doesn't reset when property search finishes. */ | ||||
| SET_FLAG_FROM_TEST(panel->flag, UI_panel_is_closed(panel), PNL_CLOSED); | SET_FLAG_FROM_TEST(panel->flag, UI_panel_is_closed(panel), PNL_CLOSED); | ||||
| panel->runtime_flag &= ~PANEL_USE_CLOSED_FROM_SEARCH; | panel->runtime_flag &= ~PANEL_USE_CLOSED_FROM_SEARCH; | ||||
| /* The panel collapse / expand key "A" is special as it takes priority over | /* The panel collapse / expand key "A" is special as it takes priority over | ||||
| * active button handling. */ | * active button handling. */ | ||||
| if (event->type == EVT_AKEY && !IS_EVENT_MOD(event, shift, ctrl, alt, oskey)) { | if (event->type == EVT_AKEY && !IS_EVENT_MOD(event, shift, ctrl, alt, oskey)) { | ||||
| retval = WM_UI_HANDLER_BREAK; | retval = WM_UI_HANDLER_BREAK; | ||||
| ui_handle_panel_header(C, block, mx, event->type, event->ctrl, event->shift); | panel_handle_header(C, block, mx, event->type, event->ctrl, event->shift); | ||||
| break; | break; | ||||
| } | } | ||||
| } | } | ||||
| /* Don't do any other panel handling with an active button. */ | /* Don't do any other panel handling with an active button. */ | ||||
| if (region_has_active_button) { | if (region_has_active_button) { | ||||
| continue; | continue; | ||||
| } | } | ||||
| if (mouse_state == PANEL_MOUSE_INSIDE_HEADER) { | if (mouse_state == PANEL_MOUSE_INSIDE_HEADER) { | ||||
| /* All mouse clicks inside panel headers should return in break. */ | /* All mouse clicks inside panel headers should return in break. */ | ||||
| if (ELEM(event->type, EVT_RETKEY, EVT_PADENTER, LEFTMOUSE)) { | if (ELEM(event->type, EVT_RETKEY, EVT_PADENTER, LEFTMOUSE)) { | ||||
| retval = WM_UI_HANDLER_BREAK; | retval = WM_UI_HANDLER_BREAK; | ||||
| ui_handle_panel_header(C, block, mx, event->type, event->ctrl, event->shift); | panel_handle_header(C, block, mx, event->type, event->ctrl, event->shift); | ||||
| } | } | ||||
| else if (event->type == RIGHTMOUSE) { | else if (event->type == RIGHTMOUSE) { | ||||
| retval = WM_UI_HANDLER_BREAK; | retval = WM_UI_HANDLER_BREAK; | ||||
| ui_popup_context_menu_for_panel(C, region, block->panel); | ui_popup_context_menu_for_panel(C, region, block->panel); | ||||
| } | } | ||||
| 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_panel_custom_data_get(const Panel *panel) | PointerRNA *UI_panel_custom_data_get(const Panel *panel) | ||||
| { | { | ||||
| return panel->runtime.custom_data_ptr; | return panel->runtime.custom_data_ptr; | ||||
| } | } | ||||
| 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); | ||||
| const int mouse_state = ui_panel_mouse_state_get(block, panel, mx, my); | const int mouse_state = panel_mouse_state_get(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; | ||||
| } | } | ||||
| return UI_panel_custom_data_get(panel); | return UI_panel_custom_data_get(panel); | ||||
| } | } | ||||
| /** \} */ | /** \} */ | ||||
| /* -------------------------------------------------------------------- */ | /* -------------------------------------------------------------------- */ | ||||
| /** \name Window Level Modal Panel Interaction | /** \name Window Level Modal Panel Interaction | ||||
| * \{ */ | * \{ */ | ||||
| /* Note, this is modal handler and should not swallow events for animation. */ | /* Note, this is modal handler and should not swallow events for animation. */ | ||||
| static int ui_handler_panel(bContext *C, const wmEvent *event, void *userdata) | static int panel_handle_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) { | ||||
| panel_activate_state(C, panel, PANEL_STATE_ANIMATION); | panel_activate_state(C, panel, PANEL_STATE_ANIMATION); | ||||
| } | } | ||||
| 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_handle_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_animate(C, panel); | ||||
| } | } | ||||
| else if (data->state == PANEL_STATE_DRAG) { | else if (data->state == PANEL_STATE_DRAG) { | ||||
| ui_do_drag(C, event, panel); | panel_handle_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_handler_modal_remove(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_handle_data_ensure(const bContext *C, | static void panel_handle_data_ensure(const bContext *C, | ||||
| wmWindow *win, | wmWindow *win, | ||||
| const ARegion *region, | const ARegion *region, | ||||
| Panel *panel, | Panel *panel, | ||||
| const uiHandlePanelState state) | const uiHandlePanelState state) | ||||
| { | { | ||||
| if (panel->activedata == NULL) { | if (panel->activedata == NULL) { | ||||
| panel->activedata = MEM_callocN(sizeof(uiHandlePanelData), __func__); | panel->activedata = MEM_callocN(sizeof(uiHandlePanelData), __func__); | ||||
| 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_handle_modal, panel_handler_modal_remove, panel, 0); | ||||
| } | } | ||||
| uiHandlePanelData *data = panel->activedata; | uiHandlePanelData *data = panel->activedata; | ||||
| 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); | ||||
| data->state = state; | data->state = state; | ||||
| data->startx = win->eventstate->x; | data->startx = win->eventstate->x; | ||||
| ▲ Show 20 Lines • Show All 44 Lines • ▼ Show 20 Lines | if (data->animtimer) { | ||||
| WM_event_remove_timer(CTX_wm_manager(C), win, data->animtimer); | WM_event_remove_timer(CTX_wm_manager(C), win, data->animtimer); | ||||
| data->animtimer = NULL; | data->animtimer = NULL; | ||||
| } | } | ||||
| 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_handle_modal, panel_handler_modal_remove, panel, false); | ||||
| } | } | ||||
| ED_region_tag_redraw(region); | ED_region_tag_redraw(region); | ||||
| } | } | ||||
| /** \} */ | /** \} */ | ||||