#include "BLI_blenlib.h"
#include "BLI_math.h"
#include "BLI_utildefines.h"
+#include "BLI_alloca.h"
+#include "BLI_linklist_stack.h"
#include "BLF_translation.h"
#include "BKE_global.h"
#include "BKE_screen.h"
+#include "RNA_access.h"
+#include "RNA_types.h"
+
#include "WM_api.h"
#include "WM_types.h"
#include "wm_subwindow.h"
}
/* only exported for WM */
-void ED_region_do_listen(ARegion *ar, wmNotifier *note)
+void ED_region_do_listen(bScreen *sc, ScrArea *sa, ARegion *ar, wmNotifier *note)
{
/* generic notes first */
switch (note->category) {
}
if (ar->type && ar->type->listener)
- ar->type->listener(ar, note);
+ ar->type->listener(sc, sa, ar, note);
}
/* only exported for WM */
-void ED_area_do_listen(ScrArea *sa, wmNotifier *note)
+void ED_area_do_listen(bScreen *sc, ScrArea *sa, wmNotifier *note)
{
/* no generic notes? */
if (sa->type && sa->type->listener) {
- sa->type->listener(sa, note);
+ sa->type->listener(sc, sa, note);
}
}
sa->do_refresh = FALSE;
}
-/* based on screen region draw tags, set draw tags in azones, and future region tabs etc */
-/* only exported for WM */
-void ED_area_overdraw_flush(ScrArea *sa, ARegion *ar)
-{
- AZone *az;
-
- for (az = sa->actionzones.first; az; az = az->next) {
- int xs, ys;
-
- xs = (az->x1 + az->x2) / 2;
- ys = (az->y1 + az->y2) / 2;
-
- /* test if inside */
- if (BLI_rcti_isect_pt(&ar->winrct, xs, ys)) {
- az->do_draw = TRUE;
- }
- }
-}
-
/**
* \brief Corner widgets use for dragging and splitting the view.
*/
int dx = x2 - x1;
int dy = y2 - y1;
- dx = copysign(ceilf(0.3f * fabsf(dx)), dx);
- dy = copysign(ceilf(0.3f * fabsf(dy)), dy);
+ dx = copysign(ceilf(0.3f * abs(dx)), dx);
+ dy = copysign(ceilf(0.3f * abs(dy)), dy);
glEnable(GL_BLEND);
glEnable(GL_LINE_SMOOTH);
glDisable(GL_BLEND);
}
-/* only exported for WM */
-void ED_area_overdraw(bContext *C)
+static void region_draw_azones(ScrArea *sa, ARegion *ar)
{
- wmWindow *win = CTX_wm_window(C);
- bScreen *screen = CTX_wm_screen(C);
- ScrArea *sa;
-
- /* Draw AZones, in screenspace */
- wmSubWindowSet(win, screen->mainwin);
+ AZone *az;
+
+ if (!sa)
+ return;
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+
+ glPushMatrix();
+ glTranslatef(-ar->winrct.xmin, -ar->winrct.ymin, 0.0f);
- for (sa = screen->areabase.first; sa; sa = sa->next) {
- AZone *az;
- for (az = sa->actionzones.first; az; az = az->next) {
- if (az->do_draw) {
- if (az->type == AZONE_AREA) {
- area_draw_azone(az->x1, az->y1, az->x2, az->y2);
- }
- else if (az->type == AZONE_REGION) {
-
- if (az->ar) {
- /* only display tab or icons when the region is hidden */
- if (az->ar->flag & (RGN_FLAG_HIDDEN | RGN_FLAG_TOO_SMALL)) {
- if (G.debug_value == 3)
- region_draw_azone_icon(az);
- else if (G.debug_value == 2)
- region_draw_azone_tria(az);
- else if (G.debug_value == 1)
- region_draw_azone_tab(az);
- else
- region_draw_azone_tab_plus(az);
- }
+ for (az = sa->actionzones.first; az; az = az->next) {
+ /* test if action zone is over this region */
+ rcti azrct;
+ BLI_rcti_init(&azrct, az->x1, az->x2, az->y1, az->y2);
+
+ if (BLI_rcti_isect(&ar->drawrct, &azrct, NULL)) {
+ if (az->type == AZONE_AREA) {
+ area_draw_azone(az->x1, az->y1, az->x2, az->y2);
+ }
+ else if (az->type == AZONE_REGION) {
+
+ if (az->ar) {
+ /* only display tab or icons when the region is hidden */
+ if (az->ar->flag & (RGN_FLAG_HIDDEN | RGN_FLAG_TOO_SMALL)) {
+ if (G.debug_value == 3)
+ region_draw_azone_icon(az);
+ else if (G.debug_value == 2)
+ region_draw_azone_tria(az);
+ else if (G.debug_value == 1)
+ region_draw_azone_tab(az);
+ else
+ region_draw_azone_tab_plus(az);
}
}
-
- az->do_draw = FALSE;
}
}
}
+
+ glPopMatrix();
+
glDisable(GL_BLEND);
-
}
/* only exported for WM */
ar->drawrct = ar->winrct;
/* note; this sets state, so we can use wmOrtho and friends */
- wmSubWindowScissorSet(win, ar->swinid, &ar->drawrct);
+ wmSubWindowScissorSet(win, ar->swinid, &ar->drawrct, true);
UI_SetTheme(sa ? sa->spacetype : 0, ar->type ? ar->type->regionid : 0);
wmWindow *win = CTX_wm_window(C);
ScrArea *sa = CTX_wm_area(C);
ARegionType *at = ar->type;
-
+ bool scissor_pad;
+
/* see BKE_spacedata_draw_locks() */
if (at->do_lock)
return;
/* if no partial draw rect set, full rect */
- if (ar->drawrct.xmin == ar->drawrct.xmax)
+ if (ar->drawrct.xmin == ar->drawrct.xmax) {
ar->drawrct = ar->winrct;
+ scissor_pad = true;
+ }
else {
- /* extra clip for safety (intersect the rects, could use API func) */
- ar->drawrct.xmin = max_ii(ar->winrct.xmin, ar->drawrct.xmin);
- ar->drawrct.ymin = max_ii(ar->winrct.ymin, ar->drawrct.ymin);
- ar->drawrct.xmax = min_ii(ar->winrct.xmax, ar->drawrct.xmax);
- ar->drawrct.ymax = min_ii(ar->winrct.ymax, ar->drawrct.ymax);
+ /* extra clip for safety */
+ BLI_rcti_isect(&ar->winrct, &ar->drawrct, &ar->drawrct);
+ scissor_pad = false;
}
+
+ ar->do_draw |= RGN_DRAWING;
/* note; this sets state, so we can use wmOrtho and friends */
- wmSubWindowScissorSet(win, ar->swinid, &ar->drawrct);
+ wmSubWindowScissorSet(win, ar->swinid, &ar->drawrct, scissor_pad);
- UI_SetTheme(sa ? sa->spacetype : 0, ar->type ? ar->type->regionid : 0);
+ UI_SetTheme(sa ? sa->spacetype : 0, at->regionid);
/* optional header info instead? */
if (ar->headerstr) {
ED_region_draw_cb_draw(C, ar, REGION_DRAW_POST_PIXEL);
+ region_draw_azones(sa, ar);
+
/* for debugging unneeded area redraws and partial redraw */
#if 0
glEnable(GL_BLEND);
glDisable(GL_BLEND);
#endif
- ar->do_draw = FALSE;
+ ar->do_draw = 0;
memset(&ar->drawrct, 0, sizeof(ar->drawrct));
uiFreeInactiveBlocks(C, &ar->uiblocks);
void ED_region_tag_redraw(ARegion *ar)
{
- if (ar) {
+ /* don't tag redraw while drawing, it shouldn't happen normally
+ * but python scripts can cause this to happen indirectly */
+ if (ar && !(ar->do_draw & RGN_DRAWING)) {
/* zero region means full region redraw */
ar->do_draw = RGN_DRAW;
memset(&ar->drawrct, 0, sizeof(ar->drawrct));
void ED_region_tag_redraw_partial(ARegion *ar, rcti *rct)
{
- if (ar) {
+ if (ar && !(ar->do_draw & RGN_DRAWING)) {
if (!ar->do_draw) {
/* no redraw set yet, set partial region */
ar->do_draw = RGN_DRAW_PARTIAL;
static int rct_fits(rcti *rect, char dir, int size)
{
if (dir == 'h') {
- return BLI_rcti_size_x(rect) - size;
+ return BLI_rcti_size_x(rect) + 1 - size;
}
else { /* 'v' */
- return BLI_rcti_size_y(rect) - size;
+ return BLI_rcti_size_y(rect) + 1 - size;
}
}
/* overlapping regions only in the following restricted cases */
static int region_is_overlap(wmWindow *win, ScrArea *sa, ARegion *ar)
{
- if (U.uiflag2 & USER_REGION_OVERLAP)
- if (WM_is_draw_triple(win))
- if (ELEM4(sa->spacetype, SPACE_VIEW3D, SPACE_IMAGE, SPACE_SEQ, SPACE_CLIP))
+ if (U.uiflag2 & USER_REGION_OVERLAP) {
+ if (WM_is_draw_triple(win)) {
+ if (ELEM(sa->spacetype, SPACE_VIEW3D, SPACE_SEQ)) {
if (ELEM3(ar->regiontype, RGN_TYPE_TOOLS, RGN_TYPE_UI, RGN_TYPE_TOOL_PROPS))
return 1;
+ }
+ else if (sa->spacetype == SPACE_IMAGE) {
+ if (ELEM4(ar->regiontype, RGN_TYPE_TOOLS, RGN_TYPE_UI, RGN_TYPE_TOOL_PROPS, RGN_TYPE_PREVIEW))
+ return 1;
+ }
+ }
+ }
+
return 0;
}
static void area_calc_totrct(ScrArea *sa, int sizex, int sizey)
{
- short rt = U.pixelsize > 1.0f ? 1 : 0;
+ short rt = (short) U.pixelsize;
- if (sa->v1->vec.x > 0) sa->totrct.xmin = sa->v1->vec.x + 1 + rt;
+ if (sa->v1->vec.x > 0) sa->totrct.xmin = sa->v1->vec.x + rt;
else sa->totrct.xmin = sa->v1->vec.x;
- if (sa->v4->vec.x < sizex - 1) sa->totrct.xmax = sa->v4->vec.x - 1 - rt;
+ if (sa->v4->vec.x < sizex - 1) sa->totrct.xmax = sa->v4->vec.x - rt;
else sa->totrct.xmax = sa->v4->vec.x;
- if (sa->v1->vec.y > 0) sa->totrct.ymin = sa->v1->vec.y + 1 + rt;
+ if (sa->v1->vec.y > 0) sa->totrct.ymin = sa->v1->vec.y + rt;
else sa->totrct.ymin = sa->v1->vec.y;
- if (sa->v2->vec.y < sizey - 1) sa->totrct.ymax = sa->v2->vec.y - 1 - rt;
+ if (sa->v2->vec.y < sizey - 1) sa->totrct.ymax = sa->v2->vec.y - rt;
else sa->totrct.ymax = sa->v2->vec.y;
/* for speedup */
sa1->headertype = sa2->headertype;
sa1->spacetype = sa2->spacetype;
+ sa1->type = sa2->type;
sa1->butspacetype = sa2->butspacetype;
if (swap_space == 1) {
}
if (sl) {
-
/* swap regions */
slold->regionbase = sa->regionbase;
sa->regionbase = sl->regionbase;
WM_event_add_notifier(C, NC_SPACE | ND_SPACE_CHANGED, sa);
}
-static const char *editortype_pup(void)
-{
- const char *types = N_(
- "Editor type: %t"
- "|3D View %x1"
-
- "|%l"
-
- "|Timeline %x15"
- "|Graph Editor %x2"
- "|Dope Sheet %x12"
- "|NLA Editor %x13"
-
- "|%l"
-
- "|UV/Image Editor %x6"
-
- "|Video Sequence Editor %x8"
- "|Movie Clip Editor %x20"
- "|Text Editor %x9"
- "|Node Editor %x16"
- "|Logic Editor %x17"
-
- "|%l"
-
- "|Properties %x4"
- "|Outliner %x3"
- "|User Preferences %x19"
- "|Info %x7"
-
- "|%l"
-
- "|File Browser %x5"
-
- "|%l"
-
- "|Python Console %x18"
- );
-
- return IFACE_(types);
-}
-
-static void spacefunc(struct bContext *C, void *UNUSED(arg1), void *UNUSED(arg2))
-{
- ED_area_newspace(C, CTX_wm_area(C), CTX_wm_area(C)->butspacetype);
- ED_area_tag_redraw(CTX_wm_area(C));
-
- /* send space change notifier */
- WM_event_add_notifier(C, NC_SPACE | ND_SPACE_CHANGED, CTX_wm_area(C));
-}
-
/* returns offset for next button in header */
int ED_area_header_switchbutton(const bContext *C, uiBlock *block, int yco)
{
ScrArea *sa = CTX_wm_area(C);
- uiBut *but;
+ bScreen *scr = CTX_wm_screen(C);
+ PointerRNA areaptr;
int xco = 0.4 * U.widget_unit;
-
- but = uiDefIconTextButC(block, ICONTEXTROW, 0, ICON_VIEW3D,
- editortype_pup(), xco, yco, 1.5 * U.widget_unit, U.widget_unit,
- &(sa->butspacetype), 1.0, SPACEICONMAX, 0, 0,
- TIP_("Display current editor type (click for a menu of available types)"));
- uiButSetFunc(but, spacefunc, NULL, NULL);
- uiButClearFlag(but, UI_BUT_UNDO); /* skip undo on screen buttons */
-
+
+ RNA_pointer_create(&(scr->id), &RNA_Area, sa, &areaptr);
+
+ uiDefButR(block, MENU, 0, NULL, xco, yco, 1.5 * U.widget_unit, U.widget_unit,
+ &areaptr, "type", 0, 0.0f, 0.0f, 0.0f, 0.0f, "");
+
return xco + 1.7 * U.widget_unit;
}
Panel *panel;
View2D *v2d = &ar->v2d;
View2DScrollers *scrollers;
- int x, y, xco, yco, w, em, triangle, open, newcontext = 0;
+ int x, y, xco, yco, w, em, triangle;
+ bool is_context_new = 0;
int redo;
int scroll;
+ bool use_category_tabs = (ar->regiontype == RGN_TYPE_TOOLS); /* XXX, should use some better check? */
+ /* offset panels for small vertical tab area */
+ const char *category = NULL;
+ const int category_tabs_width = UI_PANEL_CATEGORY_MARGIN_WIDTH;
+ int margin_x = 0;
+
+ BLI_SMALLSTACK_DECLARE(pt_stack, PanelType *);
+
if (contextnr >= 0)
- newcontext = UI_view2d_tab_set(v2d, contextnr);
+ is_context_new = UI_view2d_tab_set(v2d, contextnr);
/* before setting the view */
if (vertical) {
}
scroll = v2d->scroll;
-
+
+
+ /* collect panels to draw */
+ for (pt = ar->type->paneltypes.last; pt; pt = pt->prev) {
+ /* verify context */
+ if (context && pt->context[0] && !STREQ(context, pt->context)) {
+ continue;
+ }
+
+ /* draw panel */
+ if (pt->draw && (!pt->poll || pt->poll(C, pt))) {
+ BLI_SMALLSTACK_PUSH(pt_stack, pt);
+ }
+ }
+
+
+ /* collect categories */
+ if (use_category_tabs) {
+ UI_panel_category_clear_all(ar);
+
+ /* gather unique categories */
+ BLI_SMALLSTACK_ITER_BEGIN(pt_stack, pt)
+ {
+ if (pt->category[0]) {
+ if (!UI_panel_category_find(ar, pt->category)) {
+ UI_panel_category_add(ar, pt->category);
+ }
+ }
+ }
+ BLI_SMALLSTACK_ITER_END;
+
+ if (!UI_panel_category_is_visible(ar)) {
+ use_category_tabs = false;
+ }
+ else {
+ category = UI_panel_category_active_get(ar, true);
+ margin_x = category_tabs_width;
+ }
+ }
+
+
/* sortof hack - but we cannot predict the height of panels, until it's being generated */
/* the layout engine works with fixed width (from v2d->cur), which is being set at end of the loop */
/* in case scroller settings (hide flags) differ from previous, the whole loop gets done again */
if (vertical) {
w = BLI_rctf_size_x(&v2d->cur);
- em = (ar->type->prefsizex) ? UI_UNIT_Y / 2 : UI_UNIT_Y;
+ em = (ar->type->prefsizex) ? 10 : 20; /* works out to 10*UI_UNIT_X or 20*UI_UNIT_X */
}
else {
w = UI_PANEL_WIDTH;
- em = (ar->type->prefsizex) ? UI_UNIT_Y / 2 : UI_UNIT_Y;
+ em = (ar->type->prefsizex) ? 10 : 20;
}
+
+ w -= margin_x;
/* create panels */
uiBeginPanels(C, ar);
/* set view2d view matrix - uiBeginBlock() stores it */
UI_view2d_view_ortho(v2d);
- for (pt = ar->type->paneltypes.first; pt; pt = pt->next) {
- /* verify context */
- if (context)
- if (pt->context[0] && strcmp(context, pt->context) != 0)
+ BLI_SMALLSTACK_ITER_BEGIN(pt_stack, pt)
+ {
+ bool open;
+
+ panel = uiPanelFindByType(ar, pt);
+
+ if (use_category_tabs && pt->category[0] && !STREQ(category, pt->category)) {
+ if ((panel == NULL) || ((panel->flag & PNL_PIN) == 0)) {
continue;
+ }
+ }
/* draw panel */
- if (pt->draw && (!pt->poll || pt->poll(C, pt))) {
- block = uiBeginBlock(C, ar, pt->idname, UI_EMBOSS);
- panel = uiBeginPanel(sa, ar, block, pt, &open);
+ block = uiBeginBlock(C, ar, pt->idname, UI_EMBOSS);
+ panel = uiBeginPanel(sa, ar, block, pt, panel, &open);
- /* bad fixed values */
- triangle = (int)(UI_UNIT_Y * 1.1f);
+ /* bad fixed values */
+ triangle = (int)(UI_UNIT_Y * 1.1f);
- if (pt->draw_header && !(pt->flag & PNL_NO_HEADER) && (open || vertical)) {
- /* for enabled buttons */
- panel->layout = uiBlockLayout(block, UI_LAYOUT_HORIZONTAL, UI_LAYOUT_HEADER,
- triangle, (UI_UNIT_Y * 1.1f) + style->panelspace, UI_UNIT_Y, 1, style);
+ if (pt->draw_header && !(pt->flag & PNL_NO_HEADER) && (open || vertical)) {
+ /* for enabled buttons */
+ panel->layout = uiBlockLayout(block, UI_LAYOUT_HORIZONTAL, UI_LAYOUT_HEADER,
+ triangle, (UI_UNIT_Y * 1.1f) + style->panelspace, UI_UNIT_Y, 1, style);
- pt->draw_header(C, panel);
+ pt->draw_header(C, panel);
- uiBlockLayoutResolve(block, &xco, &yco);
- panel->labelofs = xco - triangle;
- panel->layout = NULL;
- }
- else {
- panel->labelofs = 0;
- }
+ uiBlockLayoutResolve(block, &xco, &yco);
+ panel->labelofs = xco - triangle;
+ panel->layout = NULL;
+ }
+ else {
+ panel->labelofs = 0;
+ }
- if (open) {
- short panelContext;
-
- /* panel context can either be toolbar region or normal panels region */
- if (ar->regiontype == RGN_TYPE_TOOLS)
- panelContext = UI_LAYOUT_TOOLBAR;
- else
- panelContext = UI_LAYOUT_PANEL;
-
- panel->layout = uiBlockLayout(block, UI_LAYOUT_VERTICAL, panelContext,
- style->panelspace, 0, w - 2 * style->panelspace, em, style);
-
- pt->draw(C, panel);
-
- uiBlockLayoutResolve(block, &xco, &yco);
- panel->layout = NULL;
-
- yco -= 2 * style->panelspace;
- uiEndPanel(block, w, -yco);
- }
- else {
- yco = 0;
- uiEndPanel(block, w, 0);
- }
+ if (open) {
+ short panelContext;
+
+ /* panel context can either be toolbar region or normal panels region */
+ if (ar->regiontype == RGN_TYPE_TOOLS)
+ panelContext = UI_LAYOUT_TOOLBAR;
+ else
+ panelContext = UI_LAYOUT_PANEL;
+
+ panel->layout = uiBlockLayout(block, UI_LAYOUT_VERTICAL, panelContext,
+ style->panelspace, 0, w - 2 * style->panelspace, em, style);
- uiEndBlock(C, block);
+ pt->draw(C, panel);
+
+ uiBlockLayoutResolve(block, &xco, &yco);
+ panel->layout = NULL;
+
+ yco -= 2 * style->panelspace;
+ uiEndPanel(block, w, -yco);
+ }
+ else {
+ yco = 0;
+ uiEndPanel(block, w, 0);
}
+
+ uiEndBlock(C, block);
}
+ BLI_SMALLSTACK_ITER_END;
/* align panels and return size */
uiEndPanels(C, ar, &x, &y);
}
else {
/* don't jump back when panels close or hide */
- if (!newcontext)
+ if (!is_context_new)
x = max_ii(x, v2d->cur.xmax);
y = -y;
}
/* Note: this code scales fine, but because of rounding differences, positions of elements
* flip +1 or -1 pixel compared to redoing the entire layout again.
* Leaving in commented code for future tests */
- /* uiScalePanels(ar, BLI_rctf_size_x(&v2d->cur));
- break; */
+#if 0
+ uiScalePanels(ar, BLI_rctf_size_x(&v2d->cur));
+ break;
+#endif
}
else {
break;
}
}
+ BLI_SMALLSTACK_FREE(pt_stack);
/* clear */
if (ar->overlap) {
/* restore view matrix */
UI_view2d_view_restore(C);
+ if (use_category_tabs) {
+ UI_panel_category_draw_all(ar, category);
+ }
+
/* scrollers */
scrollers = UI_view2d_scrollers_calc(C, v2d, V2D_ARG_DUMMY, V2D_ARG_DUMMY, V2D_ARG_DUMMY, V2D_ARG_DUMMY);
UI_view2d_scrollers_draw(C, v2d, scrollers);
/* UI_UNIT_Y is defined as U variable now, depending dpi */
int ED_area_headersize(void)
{
- return (int)(1.3f * UI_UNIT_Y);
+ return (int)(HEADERY * UI_DPI_FAC);
}
void ED_region_info_draw(ARegion *ar, const char *text, int block, float fill_color[4])
/* box fill entire width or just around text */
if (!block)
- rect.xmax = min_ii(rect.xmax, rect.xmin + BLF_width(fontid, text) + 1.2f * U.widget_unit);
+ rect.xmax = min_ii(rect.xmax, rect.xmin + BLF_width(fontid, text, BLF_DRAW_STR_DUMMY_MAX) + 1.2f * U.widget_unit);
rect.ymax = BLI_rcti_size_y(&ar->winrct);