Now, temp screens are hidden from being accessed directly, with a new 'Back to Previous' button appearing in place of the screen menu when (for example) fullscreen render image areas are present. Window type menus also get disabled here too, to prevent things from getting too mixed up.
1453 lines
36 KiB
C
1453 lines
36 KiB
C
/**
|
|
* $Id:
|
|
*
|
|
* ***** BEGIN GPL LICENSE BLOCK *****
|
|
*
|
|
* This program is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU General Public License
|
|
* as published by the Free Software Foundation; either version 2
|
|
* of the License, or (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software Foundation,
|
|
* Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
*
|
|
* The Original Code is Copyright (C) 2008 Blender Foundation.
|
|
* All rights reserved.
|
|
*
|
|
*
|
|
* Contributor(s): Blender Foundation
|
|
*
|
|
* ***** END GPL LICENSE BLOCK *****
|
|
*/
|
|
|
|
#include <string.h>
|
|
#include <stdio.h>
|
|
|
|
#include "MEM_guardedalloc.h"
|
|
|
|
#include "DNA_screen_types.h"
|
|
#include "DNA_userdef_types.h"
|
|
|
|
#include "BLI_blenlib.h"
|
|
#include "BLI_math.h"
|
|
#include "BLI_rand.h"
|
|
|
|
#include "BKE_context.h"
|
|
#include "BKE_global.h"
|
|
#include "BKE_screen.h"
|
|
#include "BKE_utildefines.h"
|
|
|
|
#include "WM_api.h"
|
|
#include "WM_types.h"
|
|
#include "wm_subwindow.h"
|
|
|
|
#include "ED_screen.h"
|
|
#include "ED_screen_types.h"
|
|
#include "ED_types.h"
|
|
|
|
#include "BIF_gl.h"
|
|
#include "BIF_glutil.h"
|
|
#include "BLF_api.h"
|
|
|
|
#include "UI_interface.h"
|
|
#include "UI_resources.h"
|
|
#include "UI_view2d.h"
|
|
|
|
#ifndef DISABLE_PYTHON
|
|
#include "BPY_extern.h"
|
|
#endif
|
|
|
|
#include "screen_intern.h"
|
|
|
|
/* general area and region code */
|
|
|
|
static void region_draw_emboss(ARegion *ar, rcti *scirct)
|
|
{
|
|
rcti rect;
|
|
|
|
/* translate scissor rect to region space */
|
|
rect.xmin= scirct->xmin - ar->winrct.xmin;
|
|
rect.ymin= scirct->ymin - ar->winrct.ymin;
|
|
rect.xmax= scirct->xmax - ar->winrct.xmin;
|
|
rect.ymax= scirct->ymax - ar->winrct.ymin;
|
|
|
|
/* set transp line */
|
|
glEnable( GL_BLEND );
|
|
glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
|
|
|
|
/* right */
|
|
glColor4ub(0,0,0, 50);
|
|
sdrawline(rect.xmax, rect.ymin, rect.xmax, rect.ymax);
|
|
|
|
/* bottom */
|
|
glColor4ub(0,0,0, 80);
|
|
sdrawline(rect.xmin, rect.ymin, rect.xmax, rect.ymin);
|
|
|
|
/* top */
|
|
glColor4ub(255,255,255, 60);
|
|
sdrawline(rect.xmin, rect.ymax, rect.xmax, rect.ymax);
|
|
|
|
/* left */
|
|
glColor4ub(255,255,255, 50);
|
|
sdrawline(rect.xmin, rect.ymin, rect.xmin, rect.ymax);
|
|
|
|
glDisable( GL_BLEND );
|
|
}
|
|
|
|
void ED_region_pixelspace(ARegion *ar)
|
|
{
|
|
int width= ar->winrct.xmax-ar->winrct.xmin+1;
|
|
int height= ar->winrct.ymax-ar->winrct.ymin+1;
|
|
|
|
wmOrtho2(-0.375, (float)width-0.375, -0.375, (float)height-0.375);
|
|
wmLoadIdentity();
|
|
}
|
|
|
|
/* only exported for WM */
|
|
void ED_region_do_listen(ARegion *ar, wmNotifier *note)
|
|
{
|
|
/* generic notes first */
|
|
switch(note->category) {
|
|
case NC_WM:
|
|
if(note->data==ND_FILEREAD)
|
|
ED_region_tag_redraw(ar);
|
|
break;
|
|
case NC_WINDOW:
|
|
ED_region_tag_redraw(ar);
|
|
break;
|
|
case NC_SCREEN:
|
|
if(note->action==NA_EDITED)
|
|
ED_region_tag_redraw(ar);
|
|
/* pass on */
|
|
default:
|
|
if(ar->type && ar->type->listener)
|
|
ar->type->listener(ar, note);
|
|
}
|
|
}
|
|
|
|
/* only exported for WM */
|
|
void ED_area_do_listen(ScrArea *sa, wmNotifier *note)
|
|
{
|
|
/* no generic notes? */
|
|
if(sa->type && sa->type->listener) {
|
|
sa->type->listener(sa, note);
|
|
}
|
|
}
|
|
|
|
/* only exported for WM */
|
|
void ED_area_do_refresh(bContext *C, ScrArea *sa)
|
|
{
|
|
/* no generic notes? */
|
|
if(sa->type && sa->type->refresh) {
|
|
sa->type->refresh(C, sa);
|
|
}
|
|
sa->do_refresh= 0;
|
|
}
|
|
|
|
/* 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(bContext *C, 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_in_rcti(&ar->winrct, xs, ys)) {
|
|
az->do_draw= 1;
|
|
}
|
|
}
|
|
}
|
|
|
|
static void area_draw_azone(short x1, short y1, short x2, short y2)
|
|
{
|
|
float xmin = x1;
|
|
float xmax = x2-2;
|
|
float ymin = y1-1;
|
|
float ymax = y2-3;
|
|
|
|
float dx= 0.3f*(xmax-xmin);
|
|
float dy= 0.3f*(ymax-ymin);
|
|
|
|
glColor4ub(255, 255, 255, 80);
|
|
fdrawline(xmin, ymax, xmax, ymin);
|
|
fdrawline(xmin, ymax-dy, xmax-dx, ymin);
|
|
fdrawline(xmin, ymax-2*dy, xmax-2*dx, ymin);
|
|
|
|
glColor4ub(0, 0, 0, 150);
|
|
fdrawline(xmin, ymax+1, xmax+1, ymin);
|
|
fdrawline(xmin, ymax-dy+1, xmax-dx+1, ymin);
|
|
fdrawline(xmin, ymax-2*dy+1, xmax-2*dx+1, ymin);
|
|
}
|
|
|
|
|
|
static void region_draw_azone(ScrArea *sa, AZone *az)
|
|
{
|
|
GLUquadricObj *qobj = NULL;
|
|
short midx = az->x1 + (az->x2 - az->x1)/2;
|
|
short midy = az->y1 + (az->y2 - az->y1)/2;
|
|
|
|
if(az->ar==NULL) return;
|
|
|
|
/* only display action zone icons when the region is hidden */
|
|
if (!(az->ar->flag & RGN_FLAG_HIDDEN)) return;
|
|
|
|
qobj = gluNewQuadric();
|
|
|
|
glPushMatrix();
|
|
glTranslatef(midx, midy, 0.);
|
|
|
|
/* outlined circle */
|
|
glEnable(GL_LINE_SMOOTH);
|
|
|
|
glColor4f(1.f, 1.f, 1.f, 0.8f);
|
|
|
|
gluQuadricDrawStyle(qobj, GLU_FILL);
|
|
gluDisk( qobj, 0.0, 4.25f, 16, 1);
|
|
|
|
glColor4f(0.2f, 0.2f, 0.2f, 0.9f);
|
|
|
|
gluQuadricDrawStyle(qobj, GLU_SILHOUETTE);
|
|
gluDisk( qobj, 0.0, 4.25f, 16, 1);
|
|
|
|
glDisable(GL_LINE_SMOOTH);
|
|
|
|
glPopMatrix();
|
|
gluDeleteQuadric(qobj);
|
|
|
|
/* + */
|
|
sdrawline(midx, midy-2, midx, midy+3);
|
|
sdrawline(midx-2, midy, midx+3, midy);
|
|
}
|
|
|
|
|
|
/* only exported for WM */
|
|
void ED_area_overdraw(bContext *C)
|
|
{
|
|
wmWindow *win= CTX_wm_window(C);
|
|
bScreen *screen= CTX_wm_screen(C);
|
|
ScrArea *sa;
|
|
|
|
/* Draw AZones, in screenspace */
|
|
wmSubWindowSet(win, screen->mainwin);
|
|
|
|
glEnable( GL_BLEND );
|
|
glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
|
|
|
|
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) {
|
|
region_draw_azone(sa, az);
|
|
}
|
|
|
|
az->do_draw= 0;
|
|
}
|
|
}
|
|
}
|
|
glDisable( GL_BLEND );
|
|
|
|
}
|
|
|
|
/* get scissor rect, checking overlapping regions */
|
|
void region_scissor_winrct(ARegion *ar, rcti *winrct)
|
|
{
|
|
*winrct= ar->winrct;
|
|
|
|
if(ELEM(ar->alignment, RGN_OVERLAP_LEFT, RGN_OVERLAP_RIGHT))
|
|
return;
|
|
|
|
while(ar->prev) {
|
|
ar= ar->prev;
|
|
|
|
if(BLI_isect_rcti(winrct, &ar->winrct, NULL)) {
|
|
if(ar->flag & RGN_FLAG_HIDDEN);
|
|
else if(ar->alignment & RGN_SPLIT_PREV);
|
|
else if(ar->alignment==RGN_OVERLAP_LEFT) {
|
|
winrct->xmin= ar->winrct.xmax + 1;
|
|
}
|
|
else if(ar->alignment==RGN_OVERLAP_RIGHT) {
|
|
winrct->xmax= ar->winrct.xmin - 1;
|
|
}
|
|
else break;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* only exported for WM */
|
|
/* makes region ready for drawing, sets pixelspace */
|
|
void ED_region_set(const bContext *C, ARegion *ar)
|
|
{
|
|
wmWindow *win= CTX_wm_window(C);
|
|
ScrArea *sa= CTX_wm_area(C);
|
|
rcti winrct;
|
|
|
|
/* checks other overlapping regions */
|
|
region_scissor_winrct(ar, &winrct);
|
|
|
|
ar->drawrct= winrct;
|
|
|
|
/* note; this sets state, so we can use wmOrtho and friends */
|
|
wmSubWindowScissorSet(win, ar->swinid, &ar->drawrct);
|
|
|
|
UI_SetTheme(sa?sa->spacetype:0, ar->type?ar->type->regionid:0);
|
|
|
|
ED_region_pixelspace(ar);
|
|
}
|
|
|
|
|
|
/* only exported for WM */
|
|
void ED_region_do_draw(bContext *C, ARegion *ar)
|
|
{
|
|
wmWindow *win= CTX_wm_window(C);
|
|
ScrArea *sa= CTX_wm_area(C);
|
|
ARegionType *at= ar->type;
|
|
rcti winrct;
|
|
|
|
/* checks other overlapping regions */
|
|
region_scissor_winrct(ar, &winrct);
|
|
|
|
/* if no partial draw rect set, full rect */
|
|
if(ar->drawrct.xmin == ar->drawrct.xmax)
|
|
ar->drawrct= winrct;
|
|
else {
|
|
/* extra clip for safety */
|
|
ar->drawrct.xmin= MAX2(winrct.xmin, ar->drawrct.xmin);
|
|
ar->drawrct.ymin= MAX2(winrct.ymin, ar->drawrct.ymin);
|
|
ar->drawrct.xmax= MIN2(winrct.xmax, ar->drawrct.xmax);
|
|
ar->drawrct.ymax= MIN2(winrct.ymax, ar->drawrct.ymax);
|
|
}
|
|
|
|
/* note; this sets state, so we can use wmOrtho and friends */
|
|
wmSubWindowScissorSet(win, ar->swinid, &ar->drawrct);
|
|
|
|
UI_SetTheme(sa?sa->spacetype:0, ar->type?ar->type->regionid:0);
|
|
|
|
/* optional header info instead? */
|
|
if(ar->headerstr) {
|
|
float col[3];
|
|
UI_GetThemeColor3fv(TH_HEADER, col);
|
|
glClearColor(col[0], col[1], col[2], 0.0);
|
|
glClear(GL_COLOR_BUFFER_BIT);
|
|
|
|
UI_ThemeColor(TH_TEXT);
|
|
BLF_draw_default(20, 8, 0.0f, ar->headerstr);
|
|
}
|
|
else if(at->draw) {
|
|
at->draw(C, ar);
|
|
}
|
|
|
|
uiFreeInactiveBlocks(C, &ar->uiblocks);
|
|
|
|
if(sa)
|
|
region_draw_emboss(ar, &winrct);
|
|
|
|
/* XXX test: add convention to end regions always in pixel space, for drawing of borders/gestures etc */
|
|
ED_region_pixelspace(ar);
|
|
|
|
ar->do_draw= 0;
|
|
memset(&ar->drawrct, 0, sizeof(ar->drawrct));
|
|
}
|
|
|
|
/* **********************************
|
|
maybe silly, but let's try for now
|
|
to keep these tags protected
|
|
********************************** */
|
|
|
|
void ED_region_tag_redraw(ARegion *ar)
|
|
{
|
|
if(ar) {
|
|
/* zero region means full region redraw */
|
|
ar->do_draw= 1;
|
|
memset(&ar->drawrct, 0, sizeof(ar->drawrct));
|
|
}
|
|
}
|
|
|
|
void ED_region_tag_redraw_partial(ARegion *ar, rcti *rct)
|
|
{
|
|
if(ar) {
|
|
if(!ar->do_draw) {
|
|
/* no redraw set yet, set partial region */
|
|
ar->do_draw= 1;
|
|
ar->drawrct= *rct;
|
|
}
|
|
else if(ar->drawrct.xmin != ar->drawrct.xmax) {
|
|
/* partial redraw already set, expand region */
|
|
ar->drawrct.xmin= MIN2(ar->drawrct.xmin, rct->xmin);
|
|
ar->drawrct.ymin= MIN2(ar->drawrct.ymin, rct->ymin);
|
|
ar->drawrct.xmax= MAX2(ar->drawrct.xmax, rct->xmax);
|
|
ar->drawrct.ymax= MAX2(ar->drawrct.ymax, rct->ymax);
|
|
}
|
|
}
|
|
}
|
|
|
|
void ED_area_tag_redraw(ScrArea *sa)
|
|
{
|
|
ARegion *ar;
|
|
|
|
if(sa)
|
|
for(ar= sa->regionbase.first; ar; ar= ar->next)
|
|
ED_region_tag_redraw(ar);
|
|
}
|
|
|
|
void ED_area_tag_refresh(ScrArea *sa)
|
|
{
|
|
if(sa)
|
|
sa->do_refresh= 1;
|
|
}
|
|
|
|
/* *************************************************************** */
|
|
|
|
/* use NULL to disable it */
|
|
void ED_area_headerprint(ScrArea *sa, const char *str)
|
|
{
|
|
ARegion *ar;
|
|
|
|
for(ar= sa->regionbase.first; ar; ar= ar->next) {
|
|
if(ar->regiontype==RGN_TYPE_HEADER) {
|
|
if(str) {
|
|
if(ar->headerstr==NULL)
|
|
ar->headerstr= MEM_mallocN(256, "headerprint");
|
|
BLI_strncpy(ar->headerstr, str, 256);
|
|
}
|
|
else if(ar->headerstr) {
|
|
MEM_freeN(ar->headerstr);
|
|
ar->headerstr= NULL;
|
|
}
|
|
ED_region_tag_redraw(ar);
|
|
}
|
|
}
|
|
}
|
|
|
|
/* ************************************************************ */
|
|
|
|
|
|
#define AZONESPOT 12
|
|
static void area_azone_initialize(ScrArea *sa)
|
|
{
|
|
AZone *az;
|
|
|
|
/* reinitalize entirely, regions add azones too */
|
|
BLI_freelistN(&sa->actionzones);
|
|
|
|
/* set area action zones */
|
|
az= (AZone *)MEM_callocN(sizeof(AZone), "actionzone");
|
|
BLI_addtail(&(sa->actionzones), az);
|
|
az->type= AZONE_AREA;
|
|
az->x1= sa->totrct.xmin;
|
|
az->y1= sa->totrct.ymin;
|
|
az->x2= sa->totrct.xmin + AZONESPOT-1;
|
|
az->y2= sa->totrct.ymin + AZONESPOT-1;
|
|
BLI_init_rcti(&az->rect, az->x1, az->x2, az->y1, az->y2);
|
|
|
|
az= (AZone *)MEM_callocN(sizeof(AZone), "actionzone");
|
|
BLI_addtail(&(sa->actionzones), az);
|
|
az->type= AZONE_AREA;
|
|
az->x1= sa->totrct.xmax+1;
|
|
az->y1= sa->totrct.ymax+1;
|
|
az->x2= sa->totrct.xmax-AZONESPOT+1;
|
|
az->y2= sa->totrct.ymax-AZONESPOT+1;
|
|
BLI_init_rcti(&az->rect, az->x1, az->x2, az->y1, az->y2);
|
|
}
|
|
|
|
#define AZONEPAD_EDGE 4
|
|
#define AZONEPAD_ICON 8
|
|
static void region_azone_edge(AZone *az, ARegion *ar)
|
|
{
|
|
if(az->edge=='t') {
|
|
az->x1= ar->winrct.xmin;
|
|
az->y1= ar->winrct.ymax - AZONEPAD_EDGE;
|
|
az->x2= ar->winrct.xmax;
|
|
az->y2= ar->winrct.ymax;
|
|
}
|
|
else if(az->edge=='b') {
|
|
az->x1= ar->winrct.xmin;
|
|
az->y1= ar->winrct.ymin + AZONEPAD_EDGE;
|
|
az->x2= ar->winrct.xmax;
|
|
az->y2= ar->winrct.ymin;
|
|
}
|
|
else if(az->edge=='l') {
|
|
az->x1= ar->winrct.xmin;
|
|
az->y1= ar->winrct.ymin;
|
|
az->x2= ar->winrct.xmin + AZONEPAD_EDGE;
|
|
az->y2= ar->winrct.ymax;
|
|
}
|
|
else { // if(az->edge=='r') {
|
|
az->x1= ar->winrct.xmax;
|
|
az->y1= ar->winrct.ymin;
|
|
az->x2= ar->winrct.xmax - AZONEPAD_EDGE;
|
|
az->y2= ar->winrct.ymax;
|
|
}
|
|
|
|
BLI_init_rcti(&az->rect, az->x1, az->x2, az->y1, az->y2);
|
|
}
|
|
|
|
static void region_azone_icon(ScrArea *sa, AZone *az, ARegion *ar)
|
|
{
|
|
AZone *azt;
|
|
int tot=0;
|
|
|
|
for(azt= sa->actionzones.first; azt; azt= azt->next) {
|
|
if(azt->edge == az->edge) tot++;
|
|
}
|
|
|
|
if(az->edge=='t') {
|
|
az->x1= ar->winrct.xmax - tot*2*AZONEPAD_ICON;
|
|
az->y1= ar->winrct.ymax + AZONEPAD_ICON;
|
|
az->x2= ar->winrct.xmax - tot*AZONEPAD_ICON;
|
|
az->y2= ar->winrct.ymax + 2*AZONEPAD_ICON;
|
|
}
|
|
else if(az->edge=='b') {
|
|
az->x1= ar->winrct.xmin + AZONEPAD_ICON;
|
|
az->y1= ar->winrct.ymin - AZONEPAD_ICON;
|
|
az->x2= ar->winrct.xmin + 2*AZONEPAD_ICON;
|
|
az->y2= ar->winrct.ymin - 2*AZONEPAD_ICON;
|
|
}
|
|
else if(az->edge=='l') {
|
|
az->x1= ar->winrct.xmin - 2*AZONEPAD_ICON;
|
|
az->y1= ar->winrct.ymax - tot*2*AZONEPAD_ICON;
|
|
az->x2= ar->winrct.xmin - AZONEPAD_ICON;
|
|
az->y2= ar->winrct.ymax - tot*AZONEPAD_ICON;
|
|
}
|
|
else { // if(az->edge=='r') {
|
|
az->x1= ar->winrct.xmax + AZONEPAD_ICON;
|
|
az->y1= ar->winrct.ymax - tot*2*AZONEPAD_ICON;
|
|
az->x2= ar->winrct.xmax + 2*AZONEPAD_ICON;
|
|
az->y2= ar->winrct.ymax - tot*AZONEPAD_ICON;
|
|
}
|
|
|
|
BLI_init_rcti(&az->rect, az->x1, az->x2, az->y1, az->y2);
|
|
|
|
/* if more azones on 1 spot, set offset */
|
|
for(azt= sa->actionzones.first; azt; azt= azt->next) {
|
|
if(az!=azt) {
|
|
if( ABS(az->x1-azt->x1) < 2 && ABS(az->y1-azt->y1) < 2) {
|
|
if(az->edge=='t' || az->edge=='b') {
|
|
az->x1+= AZONESPOT;
|
|
az->x2+= AZONESPOT;
|
|
BLI_init_rcti(&az->rect, az->x1, az->x2, az->y1, az->y2);
|
|
}
|
|
else {
|
|
az->y1-= AZONESPOT;
|
|
az->y2-= AZONESPOT;
|
|
BLI_init_rcti(&az->rect, az->x1, az->x2, az->y1, az->y2);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
static void region_azone_initialize(ScrArea *sa, ARegion *ar, char edge)
|
|
{
|
|
AZone *az;
|
|
|
|
az= (AZone *)MEM_callocN(sizeof(AZone), "actionzone");
|
|
BLI_addtail(&(sa->actionzones), az);
|
|
az->type= AZONE_REGION;
|
|
az->ar= ar;
|
|
az->edge= edge;
|
|
|
|
if (ar->flag & RGN_FLAG_HIDDEN) {
|
|
region_azone_icon(sa, az, ar);
|
|
} else {
|
|
region_azone_edge(az, ar);
|
|
}
|
|
|
|
}
|
|
|
|
|
|
/* *************************************************************** */
|
|
|
|
static void region_azone_add(ScrArea *sa, ARegion *ar, int alignment)
|
|
{
|
|
/* edge code (t b l r) is where azone will be drawn */
|
|
|
|
if(alignment==RGN_ALIGN_TOP)
|
|
region_azone_initialize(sa, ar, 'b');
|
|
else if(alignment==RGN_ALIGN_BOTTOM)
|
|
region_azone_initialize(sa, ar, 't');
|
|
else if(ELEM(alignment, RGN_ALIGN_RIGHT, RGN_OVERLAP_RIGHT))
|
|
region_azone_initialize(sa, ar, 'l');
|
|
else if(ELEM(alignment, RGN_ALIGN_LEFT, RGN_OVERLAP_LEFT))
|
|
region_azone_initialize(sa, ar, 'r');
|
|
|
|
}
|
|
|
|
/* dir is direction to check, not the splitting edge direction! */
|
|
static int rct_fits(rcti *rect, char dir, int size)
|
|
{
|
|
if(dir=='h') {
|
|
return rect->xmax-rect->xmin - size;
|
|
}
|
|
else { // 'v'
|
|
return rect->ymax-rect->ymin - size;
|
|
}
|
|
}
|
|
|
|
static void region_rect_recursive(ScrArea *sa, ARegion *ar, rcti *remainder, int quad)
|
|
{
|
|
rcti *remainder_prev= remainder;
|
|
int prefsizex, prefsizey;
|
|
int alignment;
|
|
|
|
if(ar==NULL)
|
|
return;
|
|
|
|
/* no returns in function, winrct gets set in the end again */
|
|
BLI_init_rcti(&ar->winrct, 0, 0, 0, 0);
|
|
|
|
/* for test; allow split of previously defined region */
|
|
if(ar->alignment & RGN_SPLIT_PREV)
|
|
if(ar->prev)
|
|
remainder= &ar->prev->winrct;
|
|
|
|
alignment = ar->alignment & ~RGN_SPLIT_PREV;
|
|
|
|
/* clear state flags first */
|
|
ar->flag &= ~RGN_FLAG_TOO_SMALL;
|
|
/* user errors */
|
|
if(ar->next==NULL && alignment!=RGN_ALIGN_QSPLIT)
|
|
alignment= RGN_ALIGN_NONE;
|
|
|
|
prefsizex= ar->type->minsizex;
|
|
prefsizey= ar->type->minsizey;
|
|
|
|
/* hidden is user flag */
|
|
if(ar->flag & RGN_FLAG_HIDDEN);
|
|
/* XXX floating area region, not handled yet here */
|
|
else if(alignment == RGN_ALIGN_FLOAT);
|
|
/* remainder is too small for any usage */
|
|
else if( rct_fits(remainder, 'v', 1)<0 || rct_fits(remainder, 'h', 1) < 0 ) {
|
|
ar->flag |= RGN_FLAG_TOO_SMALL;
|
|
}
|
|
else if(alignment==RGN_ALIGN_NONE) {
|
|
/* typically last region */
|
|
ar->winrct= *remainder;
|
|
BLI_init_rcti(remainder, 0, 0, 0, 0);
|
|
}
|
|
else if(alignment==RGN_ALIGN_TOP || alignment==RGN_ALIGN_BOTTOM) {
|
|
|
|
if( rct_fits(remainder, 'v', prefsizey) < 0 ) {
|
|
ar->flag |= RGN_FLAG_TOO_SMALL;
|
|
}
|
|
else {
|
|
int fac= rct_fits(remainder, 'v', prefsizey);
|
|
|
|
if(fac < 0 )
|
|
prefsizey += fac;
|
|
|
|
ar->winrct= *remainder;
|
|
|
|
if(alignment==RGN_ALIGN_TOP) {
|
|
ar->winrct.ymin= ar->winrct.ymax - prefsizey + 1;
|
|
remainder->ymax= ar->winrct.ymin - 1;
|
|
}
|
|
else {
|
|
ar->winrct.ymax= ar->winrct.ymin + prefsizey - 1;
|
|
remainder->ymin= ar->winrct.ymax + 1;
|
|
}
|
|
}
|
|
}
|
|
else if( ELEM4(alignment, RGN_ALIGN_LEFT, RGN_ALIGN_RIGHT, RGN_OVERLAP_LEFT, RGN_OVERLAP_RIGHT)) {
|
|
|
|
if( rct_fits(remainder, 'h', prefsizex) < 0 ) {
|
|
ar->flag |= RGN_FLAG_TOO_SMALL;
|
|
}
|
|
else {
|
|
int fac= rct_fits(remainder, 'h', prefsizex);
|
|
|
|
if(fac < 0 )
|
|
prefsizex += fac;
|
|
|
|
ar->winrct= *remainder;
|
|
|
|
if(ELEM(alignment, RGN_ALIGN_RIGHT, RGN_OVERLAP_RIGHT)) {
|
|
ar->winrct.xmin= ar->winrct.xmax - prefsizex + 1;
|
|
if(alignment==RGN_ALIGN_RIGHT)
|
|
remainder->xmax= ar->winrct.xmin - 1;
|
|
}
|
|
else {
|
|
ar->winrct.xmax= ar->winrct.xmin + prefsizex - 1;
|
|
if(alignment==RGN_ALIGN_LEFT)
|
|
remainder->xmin= ar->winrct.xmax + 1;
|
|
}
|
|
}
|
|
}
|
|
else if(alignment==RGN_ALIGN_VSPLIT || alignment==RGN_ALIGN_HSPLIT) {
|
|
/* percentage subdiv*/
|
|
ar->winrct= *remainder;
|
|
|
|
if(alignment==RGN_ALIGN_HSPLIT) {
|
|
if( rct_fits(remainder, 'h', prefsizex) > 4) {
|
|
ar->winrct.xmax= (remainder->xmin+remainder->xmax)/2;
|
|
remainder->xmin= ar->winrct.xmax+1;
|
|
}
|
|
else {
|
|
BLI_init_rcti(remainder, 0, 0, 0, 0);
|
|
}
|
|
}
|
|
else {
|
|
if( rct_fits(remainder, 'v', prefsizey) > 4) {
|
|
ar->winrct.ymax= (remainder->ymin+remainder->ymax)/2;
|
|
remainder->ymin= ar->winrct.ymax+1;
|
|
}
|
|
else {
|
|
BLI_init_rcti(remainder, 0, 0, 0, 0);
|
|
}
|
|
}
|
|
}
|
|
else if(alignment==RGN_ALIGN_QSPLIT) {
|
|
ar->winrct= *remainder;
|
|
|
|
/* test if there's still 4 regions left */
|
|
if(quad==0) {
|
|
ARegion *artest= ar->next;
|
|
int count= 1;
|
|
|
|
while(artest) {
|
|
artest->alignment= RGN_ALIGN_QSPLIT;
|
|
artest= artest->next;
|
|
count++;
|
|
}
|
|
|
|
if(count!=4) {
|
|
/* let's stop adding regions */
|
|
BLI_init_rcti(remainder, 0, 0, 0, 0);
|
|
printf("region quadsplit failed\n");
|
|
}
|
|
else quad= 1;
|
|
}
|
|
if(quad) {
|
|
if(quad==1) { /* left bottom */
|
|
ar->winrct.xmax = (remainder->xmin + remainder->xmax)/2;
|
|
ar->winrct.ymax = (remainder->ymin + remainder->ymax)/2;
|
|
}
|
|
else if(quad==2) { /* left top */
|
|
ar->winrct.xmax = (remainder->xmin + remainder->xmax)/2;
|
|
ar->winrct.ymin = 1 + (remainder->ymin + remainder->ymax)/2;
|
|
}
|
|
else if(quad==3) { /* right bottom */
|
|
ar->winrct.xmin = 1 + (remainder->xmin + remainder->xmax)/2;
|
|
ar->winrct.ymax = (remainder->ymin + remainder->ymax)/2;
|
|
}
|
|
else { /* right top */
|
|
ar->winrct.xmin = 1 + (remainder->xmin + remainder->xmax)/2;
|
|
ar->winrct.ymin = 1 + (remainder->ymin + remainder->ymax)/2;
|
|
BLI_init_rcti(remainder, 0, 0, 0, 0);
|
|
}
|
|
|
|
quad++;
|
|
}
|
|
}
|
|
|
|
/* for speedup */
|
|
ar->winx= ar->winrct.xmax - ar->winrct.xmin + 1;
|
|
ar->winy= ar->winrct.ymax - ar->winrct.ymin + 1;
|
|
|
|
/* restore test exception */
|
|
if(ar->alignment & RGN_SPLIT_PREV) {
|
|
if(ar->prev) {
|
|
remainder= remainder_prev;
|
|
ar->prev->winx= ar->prev->winrct.xmax - ar->prev->winrct.xmin + 1;
|
|
ar->prev->winy= ar->prev->winrct.ymax - ar->prev->winrct.ymin + 1;
|
|
}
|
|
}
|
|
|
|
/* set winrect for azones */
|
|
if(ar->flag & (RGN_FLAG_HIDDEN|RGN_FLAG_TOO_SMALL)) {
|
|
ar->winrct= *remainder;
|
|
|
|
if(alignment==RGN_ALIGN_TOP)
|
|
ar->winrct.ymin= ar->winrct.ymax;
|
|
else if(alignment==RGN_ALIGN_BOTTOM)
|
|
ar->winrct.ymax= ar->winrct.ymin;
|
|
else if(ELEM(alignment, RGN_ALIGN_RIGHT, RGN_OVERLAP_RIGHT))
|
|
ar->winrct.xmin= ar->winrct.xmax;
|
|
else if(ELEM(alignment, RGN_ALIGN_LEFT, RGN_OVERLAP_LEFT))
|
|
ar->winrct.xmax= ar->winrct.xmin;
|
|
else /* prevent winrct to be valid */
|
|
ar->winrct.xmax= ar->winrct.xmin;
|
|
}
|
|
/* in end, add azones, where appropriate */
|
|
region_azone_add(sa, ar, alignment);
|
|
|
|
|
|
region_rect_recursive(sa, ar->next, remainder, quad);
|
|
}
|
|
|
|
static void area_calc_totrct(ScrArea *sa, int sizex, int sizey)
|
|
{
|
|
short rt= CLAMPIS(G.rt, 0, 16);
|
|
|
|
if(sa->v1->vec.x>0) sa->totrct.xmin= sa->v1->vec.x+1+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;
|
|
else sa->totrct.xmax= sa->v4->vec.x;
|
|
|
|
if(sa->v1->vec.y>0) sa->totrct.ymin= sa->v1->vec.y+1+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;
|
|
else sa->totrct.ymax= sa->v2->vec.y;
|
|
|
|
/* for speedup */
|
|
sa->winx= sa->totrct.xmax-sa->totrct.xmin+1;
|
|
sa->winy= sa->totrct.ymax-sa->totrct.ymin+1;
|
|
}
|
|
|
|
|
|
/* used for area initialize below */
|
|
static void region_subwindow(wmWindowManager *wm, wmWindow *win, ARegion *ar)
|
|
{
|
|
if(ar->flag & (RGN_FLAG_HIDDEN|RGN_FLAG_TOO_SMALL)) {
|
|
if(ar->swinid)
|
|
wm_subwindow_close(win, ar->swinid);
|
|
ar->swinid= 0;
|
|
}
|
|
else if(ar->swinid==0)
|
|
ar->swinid= wm_subwindow_open(win, &ar->winrct);
|
|
else
|
|
wm_subwindow_position(win, ar->swinid, &ar->winrct);
|
|
}
|
|
|
|
static void ed_default_handlers(wmWindowManager *wm, ListBase *handlers, int flag)
|
|
{
|
|
/* note, add-handler checks if it already exists */
|
|
|
|
// XXX it would be good to have boundbox checks for some of these...
|
|
if(flag & ED_KEYMAP_UI) {
|
|
/* user interface widgets */
|
|
UI_add_region_handlers(handlers);
|
|
}
|
|
if(flag & ED_KEYMAP_VIEW2D) {
|
|
/* 2d-viewport handling+manipulation */
|
|
wmKeyMap *keymap= WM_keymap_find(wm->defaultconf, "View2D", 0, 0);
|
|
WM_event_add_keymap_handler(handlers, keymap);
|
|
}
|
|
if(flag & ED_KEYMAP_MARKERS) {
|
|
/* time-markers */
|
|
wmKeyMap *keymap= WM_keymap_find(wm->defaultconf, "Markers", 0, 0);
|
|
WM_event_add_keymap_handler(handlers, keymap);
|
|
// XXX need boundbox check urgently!!!
|
|
}
|
|
if(flag & ED_KEYMAP_ANIMATION) {
|
|
/* frame changing and timeline operators (for time spaces) */
|
|
wmKeyMap *keymap= WM_keymap_find(wm->defaultconf, "Animation", 0, 0);
|
|
WM_event_add_keymap_handler(handlers, keymap);
|
|
}
|
|
if(flag & ED_KEYMAP_FRAMES) {
|
|
/* frame changing/jumping (for all spaces) */
|
|
wmKeyMap *keymap= WM_keymap_find(wm->defaultconf, "Frames", 0, 0);
|
|
WM_event_add_keymap_handler(handlers, keymap);
|
|
}
|
|
if(flag & ED_KEYMAP_GPENCIL) {
|
|
/* grease pencil */
|
|
wmKeyMap *keymap= WM_keymap_find(wm->defaultconf, "Grease Pencil", 0, 0);
|
|
WM_event_add_keymap_handler(handlers, keymap);
|
|
}
|
|
if(flag & ED_KEYMAP_HEADER) {
|
|
/* standard keymap for headers regions */
|
|
wmKeyMap *keymap= WM_keymap_find(wm->defaultconf, "Header", 0, 0);
|
|
WM_event_add_keymap_handler(handlers, keymap);
|
|
}
|
|
}
|
|
|
|
|
|
/* called in screen_refresh, or screens_init, also area size changes */
|
|
void ED_area_initialize(wmWindowManager *wm, wmWindow *win, ScrArea *sa)
|
|
{
|
|
ARegion *ar;
|
|
rcti rect;
|
|
|
|
/* set typedefinitions */
|
|
sa->type= BKE_spacetype_from_id(sa->spacetype);
|
|
|
|
if(sa->type==NULL) {
|
|
sa->butspacetype= sa->spacetype= SPACE_VIEW3D;
|
|
sa->type= BKE_spacetype_from_id(sa->spacetype);
|
|
}
|
|
|
|
for(ar= sa->regionbase.first; ar; ar= ar->next)
|
|
ar->type= BKE_regiontype_from_id(sa->type, ar->regiontype);
|
|
|
|
/* area sizes */
|
|
area_calc_totrct(sa, win->sizex, win->sizey);
|
|
|
|
/* clear all azones, add the area triange widgets */
|
|
area_azone_initialize(sa);
|
|
|
|
/* region rect sizes */
|
|
rect= sa->totrct;
|
|
region_rect_recursive(sa, sa->regionbase.first, &rect, 0);
|
|
|
|
/* default area handlers */
|
|
ed_default_handlers(wm, &sa->handlers, sa->type->keymapflag);
|
|
/* checks spacedata, adds own handlers */
|
|
if(sa->type->init)
|
|
sa->type->init(wm, sa);
|
|
|
|
/* region windows, default and own handlers */
|
|
for(ar= sa->regionbase.first; ar; ar= ar->next) {
|
|
region_subwindow(wm, win, ar);
|
|
|
|
if(ar->swinid) {
|
|
/* default region handlers */
|
|
ed_default_handlers(wm, &ar->handlers, ar->type->keymapflag);
|
|
|
|
if(ar->type->init)
|
|
ar->type->init(wm, ar);
|
|
}
|
|
else {
|
|
/* prevent uiblocks to run */
|
|
uiFreeBlocks(NULL, &ar->uiblocks);
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
/* externally called for floating regions like menus */
|
|
void ED_region_init(bContext *C, ARegion *ar)
|
|
{
|
|
// ARegionType *at= ar->type;
|
|
|
|
/* refresh can be called before window opened */
|
|
region_subwindow(CTX_wm_manager(C), CTX_wm_window(C), ar);
|
|
|
|
ar->winx= ar->winrct.xmax - ar->winrct.xmin + 1;
|
|
ar->winy= ar->winrct.ymax - ar->winrct.ymin + 1;
|
|
|
|
/* UI convention */
|
|
wmLoadIdentity();
|
|
wmOrtho2(-0.01f, ar->winx-0.01f, -0.01f, ar->winy-0.01f);
|
|
|
|
}
|
|
|
|
void ED_region_toggle_hidden(bContext *C, ARegion *ar)
|
|
{
|
|
ScrArea *sa= CTX_wm_area(C);
|
|
|
|
ar->flag ^= RGN_FLAG_HIDDEN;
|
|
ar->v2d.flag &= ~V2D_IS_INITIALISED; /* XXX should become hide/unhide api? */
|
|
|
|
if(ar->flag & RGN_FLAG_HIDDEN)
|
|
WM_event_remove_handlers(C, &ar->handlers);
|
|
|
|
ED_area_initialize(CTX_wm_manager(C), CTX_wm_window(C), sa);
|
|
ED_area_tag_redraw(sa);
|
|
}
|
|
|
|
/* sa2 to sa1, we swap spaces for fullscreen to keep all allocated data */
|
|
/* area vertices were set */
|
|
void area_copy_data(ScrArea *sa1, ScrArea *sa2, int swap_space)
|
|
{
|
|
SpaceType *st;
|
|
ARegion *ar;
|
|
|
|
sa1->headertype= sa2->headertype;
|
|
sa1->spacetype= sa2->spacetype;
|
|
sa1->butspacetype= sa2->butspacetype;
|
|
|
|
if(swap_space == 1) {
|
|
SWAP(ListBase, sa1->spacedata, sa2->spacedata);
|
|
/* exception: ensure preview is reset */
|
|
// if(sa1->spacetype==SPACE_VIEW3D)
|
|
// XXX BIF_view3d_previewrender_free(sa1->spacedata.first);
|
|
}
|
|
else if (swap_space == 2) {
|
|
BKE_spacedata_copylist(&sa1->spacedata, &sa2->spacedata);
|
|
}
|
|
else {
|
|
BKE_spacedata_freelist(&sa1->spacedata);
|
|
BKE_spacedata_copylist(&sa1->spacedata, &sa2->spacedata);
|
|
}
|
|
|
|
/* Note; SPACE_EMPTY is possible on new screens */
|
|
|
|
/* regions */
|
|
if(swap_space == 1) {
|
|
SWAP(ListBase, sa1->regionbase, sa2->regionbase);
|
|
}
|
|
else {
|
|
if(swap_space<2) {
|
|
st= BKE_spacetype_from_id(sa1->spacetype);
|
|
for(ar= sa1->regionbase.first; ar; ar= ar->next)
|
|
BKE_area_region_free(st, ar);
|
|
BLI_freelistN(&sa1->regionbase);
|
|
}
|
|
|
|
st= BKE_spacetype_from_id(sa2->spacetype);
|
|
for(ar= sa2->regionbase.first; ar; ar= ar->next) {
|
|
ARegion *newar= BKE_area_region_copy(st, ar);
|
|
BLI_addtail(&sa1->regionbase, newar);
|
|
}
|
|
}
|
|
}
|
|
|
|
/* *********** Space switching code *********** */
|
|
|
|
void ED_area_swapspace(bContext *C, ScrArea *sa1, ScrArea *sa2)
|
|
{
|
|
ScrArea *tmp= MEM_callocN(sizeof(ScrArea), "addscrarea");
|
|
|
|
ED_area_exit(C, sa1);
|
|
ED_area_exit(C, sa2);
|
|
|
|
tmp->spacetype= sa1->spacetype;
|
|
tmp->butspacetype= sa1->butspacetype;
|
|
BKE_spacedata_copyfirst(&tmp->spacedata, &sa1->spacedata);
|
|
|
|
area_copy_data(tmp, sa1, 2);
|
|
area_copy_data(sa1, sa2, 0);
|
|
area_copy_data(sa2, tmp, 0);
|
|
ED_area_initialize(CTX_wm_manager(C), CTX_wm_window(C), sa1);
|
|
ED_area_initialize(CTX_wm_manager(C), CTX_wm_window(C), sa2);
|
|
|
|
BKE_screen_area_free(tmp);
|
|
MEM_freeN(tmp);
|
|
|
|
/* tell WM to refresh, cursor types etc */
|
|
WM_event_add_mousemove(C);
|
|
|
|
ED_area_tag_redraw(sa1);
|
|
ED_area_tag_refresh(sa1);
|
|
ED_area_tag_redraw(sa2);
|
|
ED_area_tag_refresh(sa2);
|
|
}
|
|
|
|
void ED_area_newspace(bContext *C, ScrArea *sa, int type)
|
|
{
|
|
if(sa->spacetype != type) {
|
|
SpaceType *st;
|
|
SpaceLink *slold;
|
|
SpaceLink *sl;
|
|
|
|
ED_area_exit(C, sa);
|
|
|
|
st= BKE_spacetype_from_id(type);
|
|
slold= sa->spacedata.first;
|
|
|
|
sa->spacetype= type;
|
|
sa->butspacetype= type;
|
|
sa->type= st;
|
|
|
|
/* check previously stored space */
|
|
for (sl= sa->spacedata.first; sl; sl= sl->next)
|
|
if(sl->spacetype==type)
|
|
break;
|
|
|
|
/* old spacedata... happened during work on 2.50, remove */
|
|
if(sl && sl->regionbase.first==NULL) {
|
|
st->free(sl);
|
|
BLI_freelinkN(&sa->spacedata, sl);
|
|
sl= NULL;
|
|
}
|
|
|
|
if (sl) {
|
|
|
|
/* swap regions */
|
|
slold->regionbase= sa->regionbase;
|
|
sa->regionbase= sl->regionbase;
|
|
sl->regionbase.first= sl->regionbase.last= NULL;
|
|
|
|
/* put in front of list */
|
|
BLI_remlink(&sa->spacedata, sl);
|
|
BLI_addhead(&sa->spacedata, sl);
|
|
}
|
|
else {
|
|
/* new space */
|
|
if(st) {
|
|
sl= st->new(C);
|
|
BLI_addhead(&sa->spacedata, sl);
|
|
|
|
/* swap regions */
|
|
if(slold)
|
|
slold->regionbase= sa->regionbase;
|
|
sa->regionbase= sl->regionbase;
|
|
sl->regionbase.first= sl->regionbase.last= NULL;
|
|
}
|
|
}
|
|
|
|
ED_area_initialize(CTX_wm_manager(C), CTX_wm_window(C), sa);
|
|
|
|
/* tell WM to refresh, cursor types etc */
|
|
WM_event_add_mousemove(C);
|
|
|
|
ED_area_tag_redraw(sa);
|
|
ED_area_tag_refresh(sa);
|
|
}
|
|
}
|
|
|
|
void ED_area_prevspace(bContext *C, ScrArea *sa)
|
|
{
|
|
SpaceLink *sl = (sa) ? sa->spacedata.first : CTX_wm_space_data(C);
|
|
|
|
if(sl->next) {
|
|
/* workaround for case of double prevspace, render window
|
|
with a file browser on top of it */
|
|
if(sl->next->spacetype == SPACE_FILE && sl->next->next)
|
|
ED_area_newspace(C, sa, sl->next->next->spacetype);
|
|
else
|
|
ED_area_newspace(C, sa, sl->next->spacetype);
|
|
}
|
|
else {
|
|
ED_area_newspace(C, sa, SPACE_INFO);
|
|
}
|
|
ED_area_tag_redraw(sa);
|
|
}
|
|
|
|
static char *windowtype_pup(void)
|
|
{
|
|
return(
|
|
"Window type:%t"
|
|
"|3D View %x1"
|
|
|
|
"|%l"
|
|
|
|
"|Timeline %x15"
|
|
"|Graph Editor %x2"
|
|
"|DopeSheet %x12"
|
|
"|NLA Editor %x13"
|
|
|
|
"|%l"
|
|
|
|
"|UV/Image Editor %x6"
|
|
|
|
"|Video Sequence Editor %x8"
|
|
"|Text Editor %x9"
|
|
"|Node Editor %x16"
|
|
"|Logic Editor %x17"
|
|
|
|
"|%l"
|
|
|
|
"|Properties %x4"
|
|
"|Outliner %x3"
|
|
"|User Preferences %x19"
|
|
"|Info%x7"
|
|
|
|
"|%l"
|
|
|
|
"|File Browser %x5"
|
|
|
|
"|%l"
|
|
|
|
"|Console %x18"
|
|
);
|
|
}
|
|
|
|
static void spacefunc(struct bContext *C, void *arg1, void *arg2)
|
|
{
|
|
ED_area_newspace(C, CTX_wm_area(C), CTX_wm_area(C)->butspacetype);
|
|
ED_area_tag_redraw(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;
|
|
int xco= 8;
|
|
|
|
but= uiDefIconTextButC(block, ICONTEXTROW, 0, ICON_VIEW3D,
|
|
windowtype_pup(), xco, yco, XIC+10, YIC,
|
|
&(sa->butspacetype), 1.0, SPACEICONMAX, 0, 0,
|
|
"Displays Current Window Type. "
|
|
"Click for menu of available types.");
|
|
uiButSetFunc(but, spacefunc, NULL, NULL);
|
|
|
|
return xco + XIC + 14;
|
|
}
|
|
|
|
int ED_area_header_standardbuttons(const bContext *C, uiBlock *block, int yco)
|
|
{
|
|
ScrArea *sa= CTX_wm_area(C);
|
|
int xco= 8;
|
|
|
|
if (!sa->full)
|
|
xco= ED_area_header_switchbutton(C, block, yco);
|
|
|
|
uiBlockSetEmboss(block, UI_EMBOSSN);
|
|
|
|
if (sa->flag & HEADER_NO_PULLDOWN) {
|
|
uiDefIconButBitS(block, TOG, HEADER_NO_PULLDOWN, 0,
|
|
ICON_DISCLOSURE_TRI_RIGHT,
|
|
xco,yco,XIC,YIC-2,
|
|
&(sa->flag), 0, 0, 0, 0,
|
|
"Show pulldown menus");
|
|
}
|
|
else {
|
|
uiDefIconButBitS(block, TOG, HEADER_NO_PULLDOWN, 0,
|
|
ICON_DISCLOSURE_TRI_DOWN,
|
|
xco,yco,XIC,YIC-2,
|
|
&(sa->flag), 0, 0, 0, 0,
|
|
"Hide pulldown menus");
|
|
}
|
|
|
|
uiBlockSetEmboss(block, UI_EMBOSS);
|
|
|
|
return xco + XIC;
|
|
}
|
|
|
|
/************************ standard UI regions ************************/
|
|
|
|
void ED_region_panels(const bContext *C, ARegion *ar, int vertical, char *context, int contextnr)
|
|
{
|
|
ScrArea *sa= CTX_wm_area(C);
|
|
uiStyle *style= U.uistyles.first;
|
|
uiBlock *block;
|
|
PanelType *pt;
|
|
Panel *panel;
|
|
View2D *v2d= &ar->v2d;
|
|
View2DScrollers *scrollers;
|
|
float col[3];
|
|
int xco, yco, x, y, miny=0, w, em, header, triangle, open, newcontext= 0;
|
|
|
|
if(contextnr >= 0)
|
|
newcontext= UI_view2d_tab_set(v2d, contextnr);
|
|
|
|
if(vertical) {
|
|
w= v2d->cur.xmax - v2d->cur.xmin;
|
|
em= (ar->type->minsizex)? 10: 20;
|
|
}
|
|
else {
|
|
w= UI_PANEL_WIDTH;
|
|
em= (ar->type->minsizex)? 10: 20;
|
|
}
|
|
|
|
x= 0;
|
|
y= -style->panelouter;
|
|
|
|
/* create panels */
|
|
uiBeginPanels(C, ar);
|
|
|
|
/* set view2d view matrix for scrolling (without scrollers) */
|
|
UI_view2d_view_ortho(C, v2d);
|
|
|
|
for(pt= ar->type->paneltypes.first; pt; pt= pt->next) {
|
|
/* verify context */
|
|
if(context)
|
|
if(pt->context[0] && strcmp(context, pt->context) != 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);
|
|
|
|
/* bad fixed values */
|
|
header= (pt->flag & PNL_NO_HEADER)? 0: 20;
|
|
triangle= 22;
|
|
|
|
if(vertical)
|
|
y -= header;
|
|
|
|
if(pt->draw_header && header && (open || vertical)) {
|
|
/* for enabled buttons */
|
|
panel->layout= uiBlockLayout(block, UI_LAYOUT_HORIZONTAL, UI_LAYOUT_HEADER,
|
|
triangle, header+style->panelspace, header, 1, style);
|
|
|
|
pt->draw_header(C, panel);
|
|
|
|
uiBlockLayoutResolve(block, &xco, &yco);
|
|
panel->labelofs= xco - triangle;
|
|
panel->layout= NULL;
|
|
}
|
|
|
|
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);
|
|
}
|
|
|
|
uiEndBlock(C, block);
|
|
|
|
if(vertical) {
|
|
if(pt->flag & PNL_NO_HEADER)
|
|
y += yco;
|
|
else
|
|
y += yco-style->panelouter;
|
|
}
|
|
else {
|
|
x += w;
|
|
miny= MIN2(y, yco-style->panelouter-header);
|
|
}
|
|
}
|
|
}
|
|
|
|
if(vertical)
|
|
x += w;
|
|
else
|
|
y= miny;
|
|
|
|
/* in case there are no panels */
|
|
if(x == 0 || y == 0) {
|
|
x= UI_PANEL_WIDTH;
|
|
y= UI_PANEL_WIDTH;
|
|
}
|
|
|
|
/* clear */
|
|
UI_GetThemeColor3fv(TH_BACK, col);
|
|
glClearColor(col[0], col[1], col[2], 0.0);
|
|
glClear(GL_COLOR_BUFFER_BIT);
|
|
|
|
/* before setting the view */
|
|
if(vertical) {
|
|
/* only allow scrolling in vertical direction */
|
|
v2d->keepofs |= V2D_LOCKOFS_X|V2D_KEEPOFS_Y;
|
|
v2d->keepofs &= ~(V2D_LOCKOFS_Y|V2D_KEEPOFS_X);
|
|
v2d->scroll |= V2D_SCROLL_HORIZONTAL_HIDE;
|
|
v2d->scroll &= ~V2D_SCROLL_VERTICAL_HIDE;
|
|
|
|
// don't jump back when panels close or hide
|
|
if(!newcontext)
|
|
y= MAX2(-y, -v2d->cur.ymin);
|
|
else
|
|
y= -y;
|
|
}
|
|
else {
|
|
/* for now, allow scrolling in both directions (since layouts are optimised for vertical,
|
|
* they often don't fit in horizontal layout)
|
|
*/
|
|
v2d->keepofs &= ~(V2D_LOCKOFS_X|V2D_LOCKOFS_Y|V2D_KEEPOFS_X|V2D_KEEPOFS_Y);
|
|
//v2d->keepofs |= V2D_LOCKOFS_Y|V2D_KEEPOFS_X;
|
|
//v2d->keepofs &= ~(V2D_LOCKOFS_X|V2D_KEEPOFS_Y);
|
|
v2d->scroll |= V2D_SCROLL_VERTICAL_HIDE;
|
|
v2d->scroll &= ~V2D_SCROLL_HORIZONTAL_HIDE;
|
|
|
|
// don't jump back when panels close or hide
|
|
if(!newcontext)
|
|
x= MAX2(x, v2d->cur.xmax);
|
|
y= -y;
|
|
}
|
|
|
|
// +V2D_SCROLL_HEIGHT is workaround to set the actual height
|
|
UI_view2d_totRect_set(v2d, x+V2D_SCROLL_WIDTH, y+V2D_SCROLL_HEIGHT);
|
|
|
|
/* set the view */
|
|
UI_view2d_view_ortho(C, v2d);
|
|
|
|
/* this does the actual drawing! */
|
|
uiEndPanels(C, ar);
|
|
|
|
/* restore view matrix */
|
|
UI_view2d_view_restore(C);
|
|
|
|
/* 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_view2d_scrollers_free(scrollers);
|
|
}
|
|
|
|
void ED_region_panels_init(wmWindowManager *wm, ARegion *ar)
|
|
{
|
|
wmKeyMap *keymap;
|
|
|
|
// XXX quick hacks for files saved with 2.5 already (i.e. the builtin defaults file)
|
|
// scrollbars for button regions
|
|
ar->v2d.scroll |= (V2D_SCROLL_RIGHT|V2D_SCROLL_BOTTOM);
|
|
ar->v2d.keepzoom |= V2D_KEEPZOOM;
|
|
|
|
// correctly initialised User-Prefs?
|
|
if(!(ar->v2d.align & V2D_ALIGN_NO_POS_Y))
|
|
ar->v2d.flag &= ~V2D_IS_INITIALISED;
|
|
|
|
UI_view2d_region_reinit(&ar->v2d, V2D_COMMONVIEW_PANELS_UI, ar->winx, ar->winy);
|
|
|
|
keymap= WM_keymap_find(wm->defaultconf, "View2D Buttons List", 0, 0);
|
|
WM_event_add_keymap_handler(&ar->handlers, keymap);
|
|
}
|
|
|
|
void ED_region_header(const bContext *C, ARegion *ar)
|
|
{
|
|
uiStyle *style= U.uistyles.first;
|
|
uiBlock *block;
|
|
uiLayout *layout;
|
|
HeaderType *ht;
|
|
Header header = {0};
|
|
float col[3];
|
|
int maxco, xco, yco;
|
|
|
|
/* clear */
|
|
if(ED_screen_area_active(C))
|
|
UI_GetThemeColor3fv(TH_HEADER, col);
|
|
else
|
|
UI_GetThemeColor3fv(TH_HEADERDESEL, col);
|
|
|
|
glClearColor(col[0], col[1], col[2], 0.0);
|
|
glClear(GL_COLOR_BUFFER_BIT);
|
|
|
|
/* set view2d view matrix for scrolling (without scrollers) */
|
|
UI_view2d_view_ortho(C, &ar->v2d);
|
|
|
|
xco= maxco= 8;
|
|
yco= HEADERY-3;
|
|
|
|
/* draw all headers types */
|
|
for(ht= ar->type->headertypes.first; ht; ht= ht->next) {
|
|
block= uiBeginBlock(C, ar, "header buttons", UI_EMBOSS);
|
|
layout= uiBlockLayout(block, UI_LAYOUT_HORIZONTAL, UI_LAYOUT_HEADER, xco, yco, HEADERY-6, 1, style);
|
|
|
|
if(ht->draw) {
|
|
header.type= ht;
|
|
header.layout= layout;
|
|
ht->draw(C, &header);
|
|
|
|
/* for view2d */
|
|
xco= uiLayoutGetWidth(layout);
|
|
if(xco > maxco)
|
|
maxco= xco;
|
|
}
|
|
|
|
uiBlockLayoutResolve(block, &xco, &yco);
|
|
|
|
/* for view2d */
|
|
if(xco > maxco)
|
|
maxco= xco;
|
|
|
|
uiEndBlock(C, block);
|
|
uiDrawBlock(C, block);
|
|
}
|
|
|
|
/* always as last */
|
|
UI_view2d_totRect_set(&ar->v2d, maxco+XIC+80, ar->v2d.tot.ymax-ar->v2d.tot.ymin);
|
|
|
|
/* restore view matrix? */
|
|
UI_view2d_view_restore(C);
|
|
}
|
|
|
|
void ED_region_header_init(ARegion *ar)
|
|
{
|
|
UI_view2d_region_reinit(&ar->v2d, V2D_COMMONVIEW_HEADER, ar->winx, ar->winy);
|
|
}
|
|
|