Changeset View
Changeset View
Standalone View
Standalone View
source/blender/editors/interface/interface_panel.c
| Show First 20 Lines • Show All 128 Lines • ▼ Show 20 Lines | static void panel_title_color_get(bool show_background, uchar color[4]) | ||||
| 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 ************************/ | |||||
| /* 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) { | |||||
| return BUT_VERTICAL; | |||||
| } | |||||
| if (area->spacetype == SPACE_USERPREF && region->regiontype == RGN_TYPE_WINDOW) { | |||||
| return BUT_VERTICAL; | |||||
| } | |||||
| if (area->spacetype == SPACE_FILE && region->regiontype == RGN_TYPE_CHANNELS) { | |||||
| return BUT_VERTICAL; | |||||
| } | |||||
| if (area->spacetype == SPACE_IMAGE && region->regiontype == RGN_TYPE_PREVIEW) { | |||||
| return BUT_VERTICAL; | |||||
| } | |||||
| if (ELEM(region->regiontype, | |||||
| RGN_TYPE_UI, | |||||
| RGN_TYPE_TOOLS, | |||||
| RGN_TYPE_TOOL_PROPS, | |||||
| RGN_TYPE_HUD, | |||||
| RGN_TYPE_NAV_BAR, | |||||
| RGN_TYPE_EXECUTE)) { | |||||
| return BUT_VERTICAL; | |||||
| } | |||||
| return 0; | |||||
| } | |||||
| static bool panel_active_animation_changed(ListBase *lb, Panel **pa_animation, bool *no_animation) | static bool panel_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 & PNL_WAS_ACTIVE) && !(panel->runtime_flag & PNL_ACTIVE)) { | ||||
| return true; | return true; | ||||
| } | } | ||||
| ▲ Show 20 Lines • Show All 343 Lines • ▼ Show 20 Lines | |||||
| /** | /** | ||||
| * Recursive implementation for #UI_panel_set_expand_from_list_data. | * Recursive implementation for #UI_panel_set_expand_from_list_data. | ||||
| * | * | ||||
| * \return Whether the closed flag for the panel or any sub-panels changed. | * \return Whether the closed flag for the panel or any sub-panels changed. | ||||
| */ | */ | ||||
| static bool panel_set_expand_from_list_data_recursive(Panel *panel, short flag, short *flag_index) | static bool panel_set_expand_from_list_data_recursive(Panel *panel, short flag, short *flag_index) | ||||
| { | { | ||||
| bool open = (flag & (1 << *flag_index)); | bool open = (flag & (1 << *flag_index)); | ||||
| bool changed = (open == (bool)(panel->flag & PNL_CLOSEDY)); | bool changed = (open == (bool)(panel->flag & PNL_CLOSED)); | ||||
| if (open) { | SET_FLAG_FROM_TEST(panel->flag, !open, PNL_CLOSED); | ||||
| panel->flag &= ~PNL_CLOSEDY; | |||||
| } | |||||
| else { | |||||
| panel->flag |= PNL_CLOSEDY; | |||||
| } | |||||
| LISTBASE_FOREACH (Panel *, child, &panel->children) { | LISTBASE_FOREACH (Panel *, child, &panel->children) { | ||||
| *flag_index = *flag_index + 1; | *flag_index = *flag_index + 1; | ||||
| changed |= panel_set_expand_from_list_data_recursive(child, flag, flag_index); | changed |= panel_set_expand_from_list_data_recursive(child, flag, flag_index); | ||||
| } | } | ||||
| return changed; | return changed; | ||||
| } | } | ||||
| /** | /** | ||||
| Show All 19 Lines | void UI_panel_set_expand_from_list_data(const bContext *C, Panel *panel) | ||||
| } | } | ||||
| } | } | ||||
| /** | /** | ||||
| * Recursive implementation for #set_panels_list_data_expand_flag. | * Recursive implementation for #set_panels_list_data_expand_flag. | ||||
| */ | */ | ||||
| static void get_panel_expand_flag(Panel *panel, short *flag, short *flag_index) | static void get_panel_expand_flag(Panel *panel, short *flag, short *flag_index) | ||||
| { | { | ||||
| bool open = !(panel->flag & PNL_CLOSEDY); | bool open = !(panel->flag & PNL_CLOSED); | ||||
| if (open) { | SET_FLAG_FROM_TEST(*flag, open, (1 << *flag_index)); | ||||
| *flag |= (1 << *flag_index); | |||||
| } | |||||
| else { | |||||
| *flag &= ~(1 << *flag_index); | |||||
| } | |||||
| LISTBASE_FOREACH (Panel *, child, &panel->children) { | LISTBASE_FOREACH (Panel *, child, &panel->children) { | ||||
| *flag_index = *flag_index + 1; | *flag_index = *flag_index + 1; | ||||
| get_panel_expand_flag(child, flag, flag_index); | get_panel_expand_flag(child, flag, flag_index); | ||||
| } | } | ||||
| } | } | ||||
| /** | /** | ||||
| * Call the callback to store the panel and subpanel expansion settings in the list item that | * Call the callback to store the panel and subpanel expansion settings in the list item that | ||||
| Show All 40 Lines | static bool panel_set_flag_recursive(Panel *panel, int flag, bool value) | ||||
| LISTBASE_FOREACH (Panel *, child, &panel->children) { | LISTBASE_FOREACH (Panel *, child, &panel->children) { | ||||
| changed |= panel_set_flag_recursive(child, flag, value); | changed |= panel_set_flag_recursive(child, flag, value); | ||||
| } | } | ||||
| return changed; | return changed; | ||||
| } | } | ||||
| static void panels_collapse_all(const bContext *C, | static void panels_collapse_all(const bContext *C, ARegion *region, const Panel *from_panel) | ||||
| ScrArea *area, | |||||
| ARegion *region, | |||||
| 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 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; | |||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| set_panels_list_data_expand_flag(C, region); | set_panels_list_data_expand_flag(C, region); | ||||
| } | } | ||||
| static bool panel_type_context_poll(ARegion *region, | static bool panel_type_context_poll(ARegion *region, | ||||
| Show All 21 Lines | LISTBASE_FOREACH (Panel *, panel, lb) { | ||||
| } | } | ||||
| } | } | ||||
| return NULL; | return NULL; | ||||
| } | } | ||||
| /** | /** | ||||
| * \note \a panel should be return value from #UI_panel_find_by_type and can be NULL. | * \note \a panel should be return value from #UI_panel_find_by_type and can be NULL. | ||||
| */ | */ | ||||
| Panel *UI_panel_begin(ScrArea *area, | Panel *UI_panel_begin( | ||||
| ARegion *region, | ARegion *region, ListBase *lb, uiBlock *block, PanelType *pt, Panel *panel, bool *r_open) | ||||
| ListBase *lb, | |||||
| uiBlock *block, | |||||
| PanelType *pt, | |||||
| Panel *panel, | |||||
| 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); | |||||
| 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) { | panel->flag |= PNL_CLOSED; | ||||
| panel->flag |= PNL_CLOSEDY; | |||||
| } | |||||
| else { | |||||
| 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; | ||||
| ▲ Show 20 Lines • Show All 52 Lines • ▼ Show 20 Lines | 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 panel_region_offset_x_get(const ARegion *region) | ||||
| { | { | ||||
| if (UI_panel_category_is_visible(region)) { | if (UI_panel_category_is_visible(region)) { | ||||
| if (align == BUT_VERTICAL && | if (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 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. */ | ||||
| Show All 23 Lines | else { | ||||
| } | } | ||||
| /* 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 |= PNL_ANIM_ALIGN; | ||||
| panel->ofsy += old_sizey - panel->sizey; | panel->ofsy += old_sizey - panel->sizey; | ||||
| } | } | ||||
| int align = panel_aligned(area, region); | panel->runtime.region_ofsx = panel_region_offset_x_get(region); | ||||
| panel->runtime.region_ofsx = panel_region_offset_x_get(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 |= PNL_ANIM_ALIGN; | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| static void ui_offset_panel_block(uiBlock *block) | static void ui_offset_panel_block(uiBlock *block) | ||||
| { | { | ||||
| ▲ Show 20 Lines • Show All 94 Lines • ▼ Show 20 Lines | void ui_draw_aligned_panel(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_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 && | 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); | 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); | ||||
| Show All 20 Lines | void ui_draw_aligned_panel(uiStyle *style, | ||||
| 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, | ||||
| (is_closed_x || is_closed_y) ? headrect.ymin : rect->ymin, | (panel->flag & PNL_CLOSED) ? headrect.ymin : rect->ymin, | ||||
| headrect.ymax + U.pixelsize}; | headrect.ymax + U.pixelsize}; | ||||
| ui_draw_box_opaque(&box_rect, UI_CNR_ALL); | ui_draw_box_opaque(&box_rect, UI_CNR_ALL); | ||||
| /* Mimick the border between aligned box widgets for the bottom of the header. */ | /* Mimick the border between aligned box widgets for the bottom of the header. */ | ||||
| if (!(is_closed_x || is_closed_y)) { | if (!(panel->flag & PNL_CLOSED)) { | ||||
| immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); | immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); | ||||
| GPU_blend(GPU_BLEND_ALPHA); | GPU_blend(GPU_BLEND_ALPHA); | ||||
| immUniformColor4ubv(box_wcol->outline); | immUniformColor4ubv(box_wcol->outline); | ||||
| immRectf(pos, rect->xmin, headrect.ymin - U.pixelsize, rect->xmax, headrect.ymin); | immRectf(pos, rect->xmin, headrect.ymin - U.pixelsize, rect->xmax, headrect.ymin); | ||||
| uchar emboss_col[4]; | uchar emboss_col[4]; | ||||
| UI_GetThemeColor4ubv(TH_WIDGET_EMBOSS, emboss_col); | UI_GetThemeColor4ubv(TH_WIDGET_EMBOSS, emboss_col); | ||||
| immUniformColor4ubv(emboss_col); | immUniformColor4ubv(emboss_col); | ||||
| immRectf(pos, | immRectf(pos, | ||||
| rect->xmin, | rect->xmin, | ||||
| headrect.ymin - U.pixelsize, | headrect.ymin - U.pixelsize, | ||||
| rect->xmax, | rect->xmax, | ||||
| headrect.ymin - U.pixelsize - 1); | headrect.ymin - U.pixelsize - 1); | ||||
| GPU_blend(GPU_BLEND_NONE); | GPU_blend(GPU_BLEND_NONE); | ||||
| immUnbindProgram(); | immUnbindProgram(); | ||||
| } | } | ||||
| } | } | ||||
| /* Draw the header backdrop. */ | /* Draw the header backdrop. */ | ||||
| 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 y = headrect.ymax; | float y = headrect.ymax; | ||||
| immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); | immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR); | ||||
| GPU_blend(GPU_BLEND_ALPHA); | GPU_blend(GPU_BLEND_ALPHA); | ||||
| /* 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, rect->xmax, 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, rect->xmax, y); | ||||
| immVertex2f(pos, minx, y); | immVertex2f(pos, minx, y); | ||||
| immVertex2f(pos, maxx, y); | immVertex2f(pos, rect->xmax, y); | ||||
| immEnd(); | immEnd(); | ||||
| GPU_blend(GPU_BLEND_NONE); | GPU_blend(GPU_BLEND_NONE); | ||||
| immUnbindProgram(); | immUnbindProgram(); | ||||
| } | } | ||||
| /* draw optional pin icon */ | /* draw optional pin icon */ | ||||
| Show All 18 Lines | #endif | ||||
| GPU_blend(GPU_BLEND_NONE); | GPU_blend(GPU_BLEND_NONE); | ||||
| } | } | ||||
| /* 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) { | |||||
| ui_draw_aligned_panel_header(style, block, &titlerect, 'h', show_background); | ui_draw_aligned_panel_header(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(); | ||||
| GPU_matrix_translate_2f(itemrect.xmin, itemrect.ymin); | GPU_matrix_translate_2f(itemrect.xmin, itemrect.ymin); | ||||
| const int col_tint = 84; | const int col_tint = 84; | ||||
| float col_high[4], col_dark[4]; | float col_high[4], col_dark[4]; | ||||
| UI_GetThemeColorShade4fv(TH_PANEL_HEADER, col_tint, col_high); | UI_GetThemeColorShade4fv(TH_PANEL_HEADER, col_tint, col_high); | ||||
| UI_GetThemeColorShade4fv(TH_PANEL_BACK, -col_tint, col_dark); | UI_GetThemeColorShade4fv(TH_PANEL_BACK, -col_tint, col_dark); | ||||
| GPUBatch *batch = GPU_batch_preset_panel_drag_widget( | GPUBatch *batch = GPU_batch_preset_panel_drag_widget( | ||||
| U.pixelsize, col_high, col_dark, BLI_rcti_size_y(&headrect) * scale); | U.pixelsize, col_high, col_dark, BLI_rcti_size_y(&headrect) * scale); | ||||
| 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 (!(panel->flag & PNL_CLOSED)) { | ||||
| /* skip */ | |||||
| } | |||||
| else if (is_closed_x) { | |||||
| /* draw vertical title */ | |||||
| ui_draw_aligned_panel_header(style, block, &headrect, 'v', show_background); | |||||
| pos = GPU_vertformat_attr_add(immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT); | |||||
| } | |||||
| /* an open panel */ | |||||
| else { | |||||
| /* in some occasions, draw a border */ | /* in some occasions, draw a border */ | ||||
| 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 { | ||||
| ▲ Show 20 Lines • Show All 59 Lines • ▼ Show 20 Lines | #endif | ||||
| 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 (panel->flag & PNL_CLOSED) { | ||||
| ui_draw_anti_tria_rect(&itemrect, 'h', tria_color); | |||||
| } | |||||
| 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 *************************/ | /************************** panel alignment *************************/ | ||||
| static int get_panel_header(const Panel *panel) | |||||
| { | |||||
| if (panel->type && (panel->type->flag & PNL_NO_HEADER)) { | |||||
| return 0; | |||||
| } | |||||
| return PNL_HEADER; | |||||
| } | |||||
| static int get_panel_size_y(const Panel *panel) | static int get_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; | ||||
| } | } | ||||
| Show All 13 Lines | |||||
| { | { | ||||
| return get_panel_real_size_y(panel); | return get_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 sizey or location when closed */ | * change sizey or location when closed */ | ||||
| static int get_panel_real_ofsy(Panel *panel) | static int get_panel_real_ofsy(Panel *panel) | ||||
| { | { | ||||
| if (panel->flag & PNL_CLOSEDY) { | if (panel->flag & PNL_CLOSED) { | ||||
| return panel->ofsy + panel->sizey; | return panel->ofsy + panel->sizey; | ||||
| } | } | ||||
| return panel->ofsy; | return panel->ofsy; | ||||
| } | } | ||||
| static int get_panel_real_ofsx(Panel *panel) | |||||
| { | |||||
| if (panel->flag & PNL_CLOSEDX) { | |||||
| return panel->ofsx + get_panel_header(panel); | |||||
| } | |||||
| 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 the coordinates of existing panels and the previously stored to-be-inserted | * added the coordinates of existing panels and the previously stored to-be-inserted | ||||
| * panels do not match for sorting | * panels do not match for sorting | ||||
| */ | */ | ||||
| static int find_leftmost_panel(const void *a1, const void *a2) | |||||
| { | |||||
| const PanelSort *ps1 = a1, *ps2 = a2; | |||||
| if (ps1->panel->ofsx > ps2->panel->ofsx) { | |||||
| return 1; | |||||
| } | |||||
| if (ps1->panel->ofsx < ps2->panel->ofsx) { | |||||
| return -1; | |||||
| } | |||||
| if (ps1->panel->sortorder > ps2->panel->sortorder) { | |||||
| return 1; | |||||
| } | |||||
| if (ps1->panel->sortorder < ps2->panel->sortorder) { | |||||
| return -1; | |||||
| } | |||||
| 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 - | ||||
| * prevent them from being sorted (multiple header-less panels have to be sorted though) */ | * prevent them 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 */ | ||||
| ▲ Show 20 Lines • Show All 50 Lines • ▼ Show 20 Lines | if (pachild->runtime_flag & PNL_ACTIVE) { | ||||
| align_sub_panels(pachild); | align_sub_panels(pachild); | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| } | } | ||||
| /* this doesn't draw */ | /* this doesn't draw */ | ||||
| /* returns 1 when it did something */ | /* returns 1 when it did something */ | ||||
| static bool uiAlignPanelStep(ScrArea *area, ARegion *region, const float fac, const bool drag) | static bool uiAlignPanelStep(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); | |||||
| /* count active, not tabbed panels */ | /* count active, not tabbed panels */ | ||||
| LISTBASE_FOREACH (Panel *, panel, ®ion->panels) { | LISTBASE_FOREACH (Panel *, panel, ®ion->panels) { | ||||
| if (panel->runtime_flag & PNL_ACTIVE) { | if (panel->runtime_flag & PNL_ACTIVE) { | ||||
| tot++; | tot++; | ||||
| } | } | ||||
| } | } | ||||
| if (tot == 0) { | if (tot == 0) { | ||||
| return 0; | return 0; | ||||
| } | } | ||||
| /* extra; change close direction? */ | |||||
| LISTBASE_FOREACH (Panel *, panel, ®ion->panels) { | |||||
| if (panel->runtime_flag & PNL_ACTIVE) { | |||||
| if ((panel->flag & PNL_CLOSEDX) && (align == BUT_VERTICAL)) { | |||||
| panel->flag ^= PNL_CLOSED; | |||||
| } | |||||
| else if ((panel->flag & PNL_CLOSEDY) && (align == BUT_HORIZONTAL)) { | |||||
| 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 & PNL_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 we are dragging, we sort on location and update sortorder */ | ||||
| if (align == BUT_VERTICAL) { | |||||
| qsort(panelsort, tot, sizeof(PanelSort), find_highest_panel); | qsort(panelsort, tot, sizeof(PanelSort), find_highest_panel); | ||||
| } | |||||
| else { | |||||
| 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); | ||||
| } | } | ||||
| /* no smart other default start loc! this keeps switching f5/f6/etc compatible */ | /* no smart other default start loc! 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 = panel_region_offset_x_get(region); | ||||
| ps->panel->ofsx = 0; | ps->panel->ofsx = 0; | ||||
| ps->panel->ofsy = -get_panel_size_y(ps->panel); | ps->panel->ofsy = -get_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) { | |||||
| 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 = get_panel_real_ofsy(ps->panel) - get_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 { | |||||
| psnext->panel->ofsx = get_panel_real_ofsx(ps->panel); | |||||
| psnext->panel->ofsy = ps->panel->ofsy + get_panel_size_y(ps->panel) - | |||||
| get_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 */ | /* we interpolate */ | ||||
| done = false; | done = false; | ||||
| ps = panelsort; | ps = panelsort; | ||||
| Show All 22 Lines | static bool uiAlignPanelStep(ARegion *region, const float fac, const bool drag) | ||||
| 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) | static void ui_panels_size(ARegion *region, int *r_x, int *r_y) | ||||
| { | { | ||||
| int align = panel_aligned(area, region); | |||||
| 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 & PNL_ACTIVE) { | if (panel->runtime_flag & PNL_ACTIVE) { | ||||
| int pa_sizex, pa_sizey; | int pa_sizex = panel->ofsx + panel->sizex; | ||||
| int pa_sizey = get_panel_real_ofsy(panel); | |||||
| if (align == BUT_VERTICAL) { | |||||
| pa_sizex = panel->ofsx + panel->sizex; | |||||
| pa_sizey = get_panel_real_ofsy(panel); | |||||
| } | |||||
| else { | |||||
| pa_sizex = get_panel_real_ofsx(panel) + panel->sizex; | |||||
| pa_sizey = panel->ofsy + get_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 ui_do_animate(bContext *C, Panel *panel) | ||||
| { | { | ||||
| uiHandlePanelData *data = panel->activedata; | uiHandlePanelData *data = panel->activedata; | ||||
| 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 (uiAlignPanelStep(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 20 Lines • Show All 44 Lines • ▼ Show 20 Lines | void UI_panels_end(const bContext *C, ARegion *region, int *r_x, int *r_y) | ||||
| } | } | ||||
| /* re-align, possibly with animation */ | /* re-align, possibly with animation */ | ||||
| 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(area, region, 1.0, false); | uiAlignPanelStep(region, 1.0, false); | ||||
| } | } | ||||
| } | } | ||||
| /* tag first panel */ | /* tag first panel */ | ||||
| panel_first = NULL; | 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 |= PNL_FIRST; | ||||
| } | } | ||||
| /* compute size taken up by panel */ | /* compute size taken up by panel */ | ||||
| ui_panels_size(area, region, r_x, r_y); | ui_panels_size(region, r_x, r_y); | ||||
| } | } | ||||
| 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); | ||||
| } | } | ||||
| Show All 29 Lines | |||||
| } | } | ||||
| /************************ panel dragging ****************************/ | /************************ 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 ui_do_drag(const bContext *C, const wmEvent *event, Panel *panel) | ||||
| { | { | ||||
| uiHandlePanelData *data = panel->activedata; | uiHandlePanelData *data = panel->activedata; | ||||
| ScrArea *area = CTX_wm_area(C); | |||||
| ARegion *region = CTX_wm_region(C); | ARegion *region = CTX_wm_region(C); | ||||
| short align = panel_aligned(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); | ||||
| Show All 16 Lines | else { | ||||
| 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) { | uiAlignPanelStep(region, 0.2f, true); | ||||
| uiAlignPanelStep(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 *****************/ | /******************* region level panel interaction *****************/ | ||||
| static uiPanelMouseState ui_panel_mouse_state_get(const uiBlock *block, | static uiPanelMouseState ui_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) | ||||
| { | { | ||||
| /* open panel */ | if (!IN_RANGE((float)mx, block->rect.xmin, block->rect.xmax)) { | ||||
| if (panel->flag & PNL_CLOSEDX) { | return PANEL_MOUSE_OUTSIDE; | ||||
| if ((block->rect.xmin <= mx) && (block->rect.xmin + PNL_HEADER >= mx)) { | |||||
| return PANEL_MOUSE_INSIDE_HEADER; | |||||
| } | |||||
| } | |||||
| /* outside left/right side */ | |||||
| else if ((block->rect.xmin > mx) || (block->rect.xmax < mx)) { | |||||
| /* pass */ | |||||
| } | } | ||||
| else if ((block->rect.ymax <= my) && (block->rect.ymax + PNL_HEADER >= my)) { | |||||
| if (IN_RANGE((float)my, block->rect.ymax, block->rect.ymax + PNL_HEADER)) { | |||||
| return PANEL_MOUSE_INSIDE_HEADER; | return PANEL_MOUSE_INSIDE_HEADER; | ||||
| } | } | ||||
| /* open panel */ | |||||
| else if (!(panel->flag & PNL_CLOSEDY)) { | if (!(panel->flag & PNL_CLOSED)) { | ||||
| if ((block->rect.xmin <= mx) && (block->rect.xmax >= mx)) { | if (IN_RANGE((float)my, block->rect.ymin, block->rect.ymax + PNL_HEADER)) { | ||||
| 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 ui_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 ui_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); | |||||
| 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); | |||||
| 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 axis */ | ||||
| if (is_horizontal) { | |||||
| xy_b_block[1] = dragcol_data->xy_init[1]; | |||||
| } | |||||
| 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) { | |||||
| 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 open or close. */ | ||||
| if (dragcol_data->was_first_open == true) { | SET_FLAG_FROM_TEST(panel->flag, dragcol_data->was_first_open, PNL_CLOSED); | ||||
| panel->flag |= (is_horizontal ? PNL_CLOSEDX : PNL_CLOSEDY); | |||||
| } | |||||
| /* force panel to open */ | |||||
| else { | |||||
| 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. */ | ||||
| ▲ Show 20 Lines • Show All 50 Lines • ▼ Show 20 Lines | WM_event_add_ui_handler(C, | ||||
| ui_panel_drag_collapse_handler_remove, | ui_panel_drag_collapse_handler_remove, | ||||
| dragcol_data, | dragcol_data, | ||||
| 0); | 0); | ||||
| } | } | ||||
| /* this function is supposed to call general window drawing too */ | /* this function is supposed to call general window drawing too */ | ||||
| /* also it supposes a block has panel, and isn't a menu */ | /* also it supposes a block has panel, and isn't a menu */ | ||||
| static void ui_handle_panel_header( | static void ui_handle_panel_header( | ||||
| const bContext *C, uiBlock *block, int mx, int my, int event, short ctrl, short shift) | const bContext *C, uiBlock *block, int mx, int event, short ctrl, short shift) | ||||
| { | { | ||||
| 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 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 rect's */ | ||||
| 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; | ||||
| Show All 14 Lines | 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) { | |||||
| if (my >= block->rect.ymax) { | |||||
| 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) { | ||||
| if (block->panel->flag & PNL_CLOSED || BLI_listbase_is_empty(&block->panel->children)) { | if (block->panel->flag & PNL_CLOSED || BLI_listbase_is_empty(&block->panel->children)) { | ||||
| panels_collapse_all(C, area, region, block->panel); | panels_collapse_all(C, region, block->panel); | ||||
| /* Reset the view - we don't want to display a view without content. */ | /* Reset the view - we don't want to display a view without content. */ | ||||
| UI_view2d_offset(®ion->v2d, 0.0f, 1.0f); | UI_view2d_offset(®ion->v2d, 0.0f, 1.0f); | ||||
| } | } | ||||
| else { | else { | ||||
| const int closed_flag = (align == BUT_HORIZONTAL) ? PNL_CLOSEDX : PNL_CLOSEDY; | |||||
| /* If a panel has sub-panels and it's open, toggle the expansion | /* If a panel has sub-panels and it's open, toggle the expansion | ||||
| * of the sub-panels (based on the expansion of the first subpanel). */ | * of the sub-panels (based on the expansion of the first subpanel). */ | ||||
| Panel *first_child = block->panel->children.first; | Panel *first_child = block->panel->children.first; | ||||
| BLI_assert(first_child != NULL); | BLI_assert(first_child != NULL); | ||||
| panel_set_flag_recursive( | panel_set_flag_recursive(block->panel, PNL_CLOSED, !(first_child->flag & PNL_CLOSED)); | ||||
| block->panel, closed_flag, (first_child->flag & PNL_CLOSED) == 0); | block->panel->flag |= PNL_CLOSED; | ||||
| 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); | ui_panel_drag_collapse_handler_add(C, false); | ||||
| } | } | ||||
| } | } | ||||
| else if (align == BUT_HORIZONTAL) { | |||||
| block->panel->flag |= PNL_CLOSEDX; | |||||
| if (event == LEFTMOUSE) { | |||||
| ui_panel_drag_collapse_handler_add(C, true); | |||||
| } | |||||
| } | |||||
| else { | else { | ||||
| /* snap down to bottom screen edge */ | /* snap down to bottom screen edge */ | ||||
| block->panel->flag |= PNL_CLOSEDY; | block->panel->flag |= PNL_CLOSED; | ||||
| 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); | ui_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) { | |||||
| panel_activate_state(C, block->panel, PANEL_STATE_ANIMATION); | panel_activate_state(C, block->panel, PANEL_STATE_ANIMATION); | ||||
| } | } | ||||
| else { | |||||
| /* FIXME: this doesn't update the panel drawing, assert to avoid debugging why this is. | |||||
| * We could fix this in the future if it's ever needed. */ | |||||
| BLI_assert(0); | |||||
| ED_region_tag_redraw(region); | |||||
| } | |||||
| } | |||||
| else if (show_drag && BLI_rctf_isect_x(&rect_drag, mx)) { | else if (show_drag && BLI_rctf_isect_x(&rect_drag, mx)) { | ||||
| /* XXX, for now don't allow dragging in floating windows yet. */ | /* XXX, for now don't allow dragging in floating windows yet. */ | ||||
| if (region->alignment == RGN_ALIGN_FLOAT) { | if (region->alignment == RGN_ALIGN_FLOAT) { | ||||
| return; | return; | ||||
| } | } | ||||
| panel_activate_state(C, block->panel, PANEL_STATE_DRAG); | panel_activate_state(C, block->panel, PANEL_STATE_DRAG); | ||||
| } | } | ||||
| else if (show_pin && BLI_rctf_isect_x(&rect_pin, mx)) { | else if (show_pin && BLI_rctf_isect_x(&rect_pin, mx)) { | ||||
| ▲ Show 20 Lines • Show All 597 Lines • ▼ Show 20 Lines | int ui_handler_panel_region(bContext *C, | ||||
| const uiBut *active_but) | const uiBut *active_but) | ||||
| { | { | ||||
| Panel *panel; | Panel *panel; | ||||
| int retval, mx, my; | 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; | retval = WM_UI_HANDLER_CONTINUE; | ||||
| if (ELEM(event->type, MOUSEMOVE, INBETWEEN_MOUSEMOVE)) { | |||||
| return retval; | |||||
| } | |||||
| /* 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) { | ||||
| ▲ Show 20 Lines • Show All 42 Lines • ▼ Show 20 Lines | LISTBASE_FOREACH (uiBlock *, block, ®ion->uiblocks) { | ||||
| mouse_state = ui_panel_mouse_state_get(block, panel, mx, my); | mouse_state = ui_panel_mouse_state_get(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_CLOSED) { | ||||
| 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); | ui_handle_panel_header(C, block, mx, event->type, event->ctrl, event->shift); | ||||
| } | } | ||||
| } | } | ||||
| else { | else { | ||||
| ui_handle_panel_header(C, block, mx, my, event->type, event->ctrl, event->shift); | ui_handle_panel_header(C, block, mx, 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 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); | ui_handle_panel_header(C, block, mx, 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); | ui_handle_panel_header(C, block, mx, event->type, event->ctrl, event->shift); | ||||
| retval = WM_UI_HANDLER_BREAK; | 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; | retval = WM_UI_HANDLER_BREAK; | ||||
| break; | break; | ||||
| } | } | ||||
| ▲ Show 20 Lines • Show All 67 Lines • ▼ Show 20 Lines | |||||
| /* 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 ui_handler_panel(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); | |||||
| ARegion *region = CTX_wm_region(C); | |||||
| int align = panel_aligned(area, region); | |||||
| if (align) { | |||||
| panel_activate_state(C, panel, PANEL_STATE_ANIMATION); | panel_activate_state(C, panel, PANEL_STATE_ANIMATION); | ||||
| } | } | ||||
| else { | |||||
| 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); | ui_do_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); | ui_do_animate(C, panel); | ||||
| ▲ Show 20 Lines • Show All 105 Lines • Show Last 20 Lines | |||||