Blender too now! :)
** Drag works as follows:
- drag-able items are defined by the standard interface ui toolkit
- each button can get this feature, via uiButSetDragXXX(but, ...).
There are calls to define drag-able images, ID blocks, RNA paths,
file paths, and so on. By default you drag an icon, exceptionally
an ImBuf
- Drag items are registered centrally in the WM, it allows more drag
items simultaneous too, but not implemented
** Drop works as follows:
- On mouse release, and if drag items exist in the WM, it converts
the mouse event to an EVT_DROP type. This event then gets the full
drag info as customdata
- drop regions are defined with WM_dropbox_add(), similar to keymaps
you can make a "drop map" this way, which become 'drop map handlers'
in the queues.
- next to that the UI kit handles some common button types (like
accepting ID or names) to be catching a drop event too.
- Every "drop box" has two callbacks:
- poll() = check if the event drag data is relevant for this box
- copy() = fill in custom properties in the dropbox to initialize
an operator
- The dropbox handler then calls its standard Operator with its
dropbox properties.
** Currently implemented
Drag items:
- ID icons in browse buttons
- ID icons in context menu of properties region
- ID icons in outliner and rna viewer
- FileBrowser icons
- FileBrowser preview images
Drag-able icons are subtly visualized by making them brighter a bit
on mouse-over. In case the icon is a button or UI element too (most
cases), the drag-able feature will make the item react to
mouse-release instead of mouse-press.
Drop options:
- UI buttons: ID and text buttons (paste name)
- View3d: Object ID drop copies object
- View3d: Material ID drop assigns to object under cursor
- View3d: Image ID drop assigns to object UV texture under cursor
- Sequencer: Path drop will add either Image or Movie strip
- Image window: Path drop will open image
** Drag and drop Notes:
- Dropping into another Blender window (from same application) works
too. I've added code that passes on mousemoves and clicks to other
windows, without activating them though. This does make using multi-window
Blender a bit friendler.
- Dropping a file path to an image, is not the same as dropping an
Image ID... keep this in mind. Sequencer for example wants paths to
be dropped, textures in 3d window wants an Image ID.
- Although drop boxes could be defined via Python, I suggest they're
part of the UI and editor design (= how we want an editor to work), and
not default offered configurable like keymaps.
- At the moment only one item can be dragged at a time. This is for
several reasons.... For one, Blender doesn't have a well defined
uniform way to define "what is selected" (files, outliner items, etc).
Secondly there's potential conflicts on what todo when you drop mixed
drag sets on spots. All undefined stuff... nice for later.
- Example to bypass the above: a collection of images that form a strip,
should be represented in filewindow as a single sequence anyway.
This then will fit well and gets handled neatly by design.
- Another option to check is to allow multiple options per drop... it
could show the operator as a sort of menu, allowing arrow or scrollwheel
to choose. For time being I'd prefer to try to design a singular drop
though, just offer only one drop action per data type on given spots.
- What does work already, but a tad slow, is to use a function that
detects an object (type) under cursor, so a drag item's option can be
further refined (like drop object on object = parent). (disabled)
** More notes
- Added saving for Region layouts (like split points for toolbar)
- Label buttons now handle mouse over
- File list: added full path entry for drop feature.
- Filesel bugfix: wm_operator_exec() got called there and fully handled,
while WM event code tried same. Added new OPERATOR_HANDLED flag for this.
Maybe python needs it too?
- Cocoa: added window move event, so multi-win setups work OK (didnt save).
- Interface_handlers.c: removed win->active
- Severe area copy bug: area handlers were not set to NULL
- Filesel bugfix: next/prev folder list was not copied on area copies
** Leftover todos
- Cocoa windows seem to hang on cases still... needs check
- Cocoa 'draw overlap' swap doesn't work
- Cocoa window loses focus permanently on using Spotlight
(for these reasons, makefile building has Carbon as default atm)
- ListView templates in UI cannot become dragged yet, needs review...
it consists of two overlapping UI elements, preventing handling icon clicks.
- There's already Ghost library code to handle dropping from OS
into Blender window. I've noticed this code is unfinished for Macs, but
seems to be complete for Windows. Needs test... currently, an external
drop event will print in console when succesfully delivered to Blender's WM.
1749 lines
40 KiB
C
1749 lines
40 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.
|
|
*
|
|
*
|
|
* ***** END GPL LICENSE BLOCK *****
|
|
*/
|
|
|
|
#include <string.h>
|
|
|
|
#include "MEM_guardedalloc.h"
|
|
|
|
#include "DNA_vec_types.h"
|
|
#include "DNA_scene_types.h"
|
|
#include "DNA_screen_types.h"
|
|
#include "DNA_texture_types.h"
|
|
#include "DNA_userdef_types.h"
|
|
|
|
#include "BLI_blenlib.h"
|
|
|
|
#include "BKE_context.h"
|
|
#include "BKE_global.h"
|
|
#include "BKE_library.h"
|
|
#include "BKE_main.h"
|
|
#include "BKE_node.h"
|
|
#include "BKE_screen.h"
|
|
#include "BKE_scene.h"
|
|
#include "BKE_utildefines.h"
|
|
|
|
#include "BIF_gl.h"
|
|
#include "BIF_glutil.h"
|
|
|
|
#include "WM_api.h"
|
|
#include "WM_types.h"
|
|
|
|
#include "ED_screen.h"
|
|
#include "ED_screen_types.h"
|
|
|
|
#include "UI_interface.h"
|
|
|
|
/* XXX actually should be not here... solve later */
|
|
#include "wm_subwindow.h"
|
|
|
|
#include "screen_intern.h" /* own module include */
|
|
|
|
|
|
/* ******************* screen vert, edge, area managing *********************** */
|
|
|
|
static ScrVert *screen_addvert(bScreen *sc, short x, short y)
|
|
{
|
|
ScrVert *sv= MEM_callocN(sizeof(ScrVert), "addscrvert");
|
|
sv->vec.x= x;
|
|
sv->vec.y= y;
|
|
|
|
BLI_addtail(&sc->vertbase, sv);
|
|
return sv;
|
|
}
|
|
|
|
static void sortscrvert(ScrVert **v1, ScrVert **v2)
|
|
{
|
|
ScrVert *tmp;
|
|
|
|
if (*v1 > *v2) {
|
|
tmp= *v1;
|
|
*v1= *v2;
|
|
*v2= tmp;
|
|
}
|
|
}
|
|
|
|
static ScrEdge *screen_addedge(bScreen *sc, ScrVert *v1, ScrVert *v2)
|
|
{
|
|
ScrEdge *se= MEM_callocN(sizeof(ScrEdge), "addscredge");
|
|
|
|
sortscrvert(&v1, &v2);
|
|
se->v1= v1;
|
|
se->v2= v2;
|
|
|
|
BLI_addtail(&sc->edgebase, se);
|
|
return se;
|
|
}
|
|
|
|
|
|
ScrEdge *screen_findedge(bScreen *sc, ScrVert *v1, ScrVert *v2)
|
|
{
|
|
ScrEdge *se;
|
|
|
|
sortscrvert(&v1, &v2);
|
|
for (se= sc->edgebase.first; se; se= se->next)
|
|
if(se->v1==v1 && se->v2==v2)
|
|
return se;
|
|
|
|
return NULL;
|
|
}
|
|
|
|
void removedouble_scrverts(bScreen *sc)
|
|
{
|
|
ScrVert *v1, *verg;
|
|
ScrEdge *se;
|
|
ScrArea *sa;
|
|
|
|
verg= sc->vertbase.first;
|
|
while(verg) {
|
|
if(verg->newv==NULL) { /* !!! */
|
|
v1= verg->next;
|
|
while(v1) {
|
|
if(v1->newv==NULL) { /* !?! */
|
|
if(v1->vec.x==verg->vec.x && v1->vec.y==verg->vec.y) {
|
|
/* printf("doublevert\n"); */
|
|
v1->newv= verg;
|
|
}
|
|
}
|
|
v1= v1->next;
|
|
}
|
|
}
|
|
verg= verg->next;
|
|
}
|
|
|
|
/* replace pointers in edges and faces */
|
|
se= sc->edgebase.first;
|
|
while(se) {
|
|
if(se->v1->newv) se->v1= se->v1->newv;
|
|
if(se->v2->newv) se->v2= se->v2->newv;
|
|
/* edges changed: so.... */
|
|
sortscrvert(&(se->v1), &(se->v2));
|
|
se= se->next;
|
|
}
|
|
sa= sc->areabase.first;
|
|
while(sa) {
|
|
if(sa->v1->newv) sa->v1= sa->v1->newv;
|
|
if(sa->v2->newv) sa->v2= sa->v2->newv;
|
|
if(sa->v3->newv) sa->v3= sa->v3->newv;
|
|
if(sa->v4->newv) sa->v4= sa->v4->newv;
|
|
sa= sa->next;
|
|
}
|
|
|
|
/* remove */
|
|
verg= sc->vertbase.first;
|
|
while(verg) {
|
|
v1= verg->next;
|
|
if(verg->newv) {
|
|
BLI_remlink(&sc->vertbase, verg);
|
|
MEM_freeN(verg);
|
|
}
|
|
verg= v1;
|
|
}
|
|
|
|
}
|
|
|
|
void removenotused_scrverts(bScreen *sc)
|
|
{
|
|
ScrVert *sv, *svn;
|
|
ScrEdge *se;
|
|
|
|
/* we assume edges are ok */
|
|
|
|
se= sc->edgebase.first;
|
|
while(se) {
|
|
se->v1->flag= 1;
|
|
se->v2->flag= 1;
|
|
se= se->next;
|
|
}
|
|
|
|
sv= sc->vertbase.first;
|
|
while(sv) {
|
|
svn= sv->next;
|
|
if(sv->flag==0) {
|
|
BLI_remlink(&sc->vertbase, sv);
|
|
MEM_freeN(sv);
|
|
}
|
|
else sv->flag= 0;
|
|
sv= svn;
|
|
}
|
|
}
|
|
|
|
void removedouble_scredges(bScreen *sc)
|
|
{
|
|
ScrEdge *verg, *se, *sn;
|
|
|
|
/* compare */
|
|
verg= sc->edgebase.first;
|
|
while(verg) {
|
|
se= verg->next;
|
|
while(se) {
|
|
sn= se->next;
|
|
if(verg->v1==se->v1 && verg->v2==se->v2) {
|
|
BLI_remlink(&sc->edgebase, se);
|
|
MEM_freeN(se);
|
|
}
|
|
se= sn;
|
|
}
|
|
verg= verg->next;
|
|
}
|
|
}
|
|
|
|
void removenotused_scredges(bScreen *sc)
|
|
{
|
|
ScrEdge *se, *sen;
|
|
ScrArea *sa;
|
|
int a=0;
|
|
|
|
/* sets flags when edge is used in area */
|
|
sa= sc->areabase.first;
|
|
while(sa) {
|
|
se= screen_findedge(sc, sa->v1, sa->v2);
|
|
if(se==0) printf("error: area %d edge 1 doesn't exist\n", a);
|
|
else se->flag= 1;
|
|
se= screen_findedge(sc, sa->v2, sa->v3);
|
|
if(se==0) printf("error: area %d edge 2 doesn't exist\n", a);
|
|
else se->flag= 1;
|
|
se= screen_findedge(sc, sa->v3, sa->v4);
|
|
if(se==0) printf("error: area %d edge 3 doesn't exist\n", a);
|
|
else se->flag= 1;
|
|
se= screen_findedge(sc, sa->v4, sa->v1);
|
|
if(se==0) printf("error: area %d edge 4 doesn't exist\n", a);
|
|
else se->flag= 1;
|
|
sa= sa->next;
|
|
a++;
|
|
}
|
|
se= sc->edgebase.first;
|
|
while(se) {
|
|
sen= se->next;
|
|
if(se->flag==0) {
|
|
BLI_remlink(&sc->edgebase, se);
|
|
MEM_freeN(se);
|
|
}
|
|
else se->flag= 0;
|
|
se= sen;
|
|
}
|
|
}
|
|
|
|
int scredge_is_horizontal(ScrEdge *se)
|
|
{
|
|
return (se->v1->vec.y == se->v2->vec.y);
|
|
}
|
|
|
|
ScrEdge *screen_find_active_scredge(bScreen *sc, int mx, int my)
|
|
{
|
|
ScrEdge *se;
|
|
|
|
for (se= sc->edgebase.first; se; se= se->next) {
|
|
if (scredge_is_horizontal(se)) {
|
|
short min, max;
|
|
min= MIN2(se->v1->vec.x, se->v2->vec.x);
|
|
max= MAX2(se->v1->vec.x, se->v2->vec.x);
|
|
|
|
if (abs(my-se->v1->vec.y)<=2 && mx>=min && mx<=max)
|
|
return se;
|
|
}
|
|
else {
|
|
short min, max;
|
|
min= MIN2(se->v1->vec.y, se->v2->vec.y);
|
|
max= MAX2(se->v1->vec.y, se->v2->vec.y);
|
|
|
|
if (abs(mx-se->v1->vec.x)<=2 && my>=min && my<=max)
|
|
return se;
|
|
}
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
|
|
|
|
/* adds no space data */
|
|
static ScrArea *screen_addarea(bScreen *sc, ScrVert *v1, ScrVert *v2, ScrVert *v3, ScrVert *v4, short headertype, short spacetype)
|
|
{
|
|
ScrArea *sa= MEM_callocN(sizeof(ScrArea), "addscrarea");
|
|
sa->v1= v1;
|
|
sa->v2= v2;
|
|
sa->v3= v3;
|
|
sa->v4= v4;
|
|
sa->headertype= headertype;
|
|
sa->spacetype= sa->butspacetype= spacetype;
|
|
|
|
BLI_addtail(&sc->areabase, sa);
|
|
|
|
return sa;
|
|
}
|
|
|
|
static void screen_delarea(bContext *C, bScreen *sc, ScrArea *sa)
|
|
{
|
|
|
|
ED_area_exit(C, sa);
|
|
|
|
BKE_screen_area_free(sa);
|
|
|
|
BLI_remlink(&sc->areabase, sa);
|
|
MEM_freeN(sa);
|
|
}
|
|
|
|
/* return 0: no split possible */
|
|
/* else return (integer) screencoordinate split point */
|
|
static short testsplitpoint(wmWindow *win, ScrArea *sa, char dir, float fac)
|
|
{
|
|
short x, y;
|
|
|
|
// area big enough?
|
|
if(dir=='v' && (sa->v4->vec.x- sa->v1->vec.x <= 2*AREAMINX)) return 0;
|
|
if(dir=='h' && (sa->v2->vec.y- sa->v1->vec.y <= 2*AREAMINY)) return 0;
|
|
|
|
// to be sure
|
|
if(fac<0.0) fac= 0.0;
|
|
if(fac>1.0) fac= 1.0;
|
|
|
|
if(dir=='h') {
|
|
y= sa->v1->vec.y+ fac*(sa->v2->vec.y- sa->v1->vec.y);
|
|
|
|
if(y- sa->v1->vec.y < AREAMINY)
|
|
y= sa->v1->vec.y+ AREAMINY;
|
|
else if(sa->v2->vec.y- y < AREAMINY)
|
|
y= sa->v2->vec.y- AREAMINY;
|
|
else y-= (y % AREAGRID);
|
|
|
|
return y;
|
|
}
|
|
else {
|
|
x= sa->v1->vec.x+ fac*(sa->v4->vec.x- sa->v1->vec.x);
|
|
|
|
if(x- sa->v1->vec.x < AREAMINX)
|
|
x= sa->v1->vec.x+ AREAMINX;
|
|
else if(sa->v4->vec.x- x < AREAMINX)
|
|
x= sa->v4->vec.x- AREAMINX;
|
|
else x-= (x % AREAGRID);
|
|
|
|
return x;
|
|
}
|
|
}
|
|
|
|
ScrArea *area_split(wmWindow *win, bScreen *sc, ScrArea *sa, char dir, float fac)
|
|
{
|
|
ScrArea *newa=NULL;
|
|
ScrVert *sv1, *sv2;
|
|
short split;
|
|
|
|
if(sa==NULL) return NULL;
|
|
|
|
split= testsplitpoint(win, sa, dir, fac);
|
|
if(split==0) return NULL;
|
|
|
|
if(dir=='h') {
|
|
/* new vertices */
|
|
sv1= screen_addvert(sc, sa->v1->vec.x, split);
|
|
sv2= screen_addvert(sc, sa->v4->vec.x, split);
|
|
|
|
/* new edges */
|
|
screen_addedge(sc, sa->v1, sv1);
|
|
screen_addedge(sc, sv1, sa->v2);
|
|
screen_addedge(sc, sa->v3, sv2);
|
|
screen_addedge(sc, sv2, sa->v4);
|
|
screen_addedge(sc, sv1, sv2);
|
|
|
|
/* new areas: top */
|
|
newa= screen_addarea(sc, sv1, sa->v2, sa->v3, sv2, sa->headertype, sa->spacetype);
|
|
area_copy_data(newa, sa, 0);
|
|
|
|
/* area below */
|
|
sa->v2= sv1;
|
|
sa->v3= sv2;
|
|
|
|
}
|
|
else {
|
|
/* new vertices */
|
|
sv1= screen_addvert(sc, split, sa->v1->vec.y);
|
|
sv2= screen_addvert(sc, split, sa->v2->vec.y);
|
|
|
|
/* new edges */
|
|
screen_addedge(sc, sa->v1, sv1);
|
|
screen_addedge(sc, sv1, sa->v4);
|
|
screen_addedge(sc, sa->v2, sv2);
|
|
screen_addedge(sc, sv2, sa->v3);
|
|
screen_addedge(sc, sv1, sv2);
|
|
|
|
/* new areas: left */
|
|
newa= screen_addarea(sc, sa->v1, sa->v2, sv2, sv1, sa->headertype, sa->spacetype);
|
|
area_copy_data(newa, sa, 0);
|
|
|
|
/* area right */
|
|
sa->v1= sv1;
|
|
sa->v2= sv2;
|
|
}
|
|
|
|
/* remove double vertices en edges */
|
|
removedouble_scrverts(sc);
|
|
removedouble_scredges(sc);
|
|
removenotused_scredges(sc);
|
|
|
|
return newa;
|
|
}
|
|
|
|
/* empty screen, with 1 dummy area without spacedata */
|
|
/* uses window size */
|
|
bScreen *ED_screen_add(wmWindow *win, Scene *scene, char *name)
|
|
{
|
|
bScreen *sc;
|
|
ScrVert *sv1, *sv2, *sv3, *sv4;
|
|
|
|
sc= alloc_libblock(&G.main->screen, ID_SCR, name);
|
|
sc->scene= scene;
|
|
sc->do_refresh= 1;
|
|
sc->winid= win->winid;
|
|
|
|
sv1= screen_addvert(sc, 0, 0);
|
|
sv2= screen_addvert(sc, 0, win->sizey-1);
|
|
sv3= screen_addvert(sc, win->sizex-1, win->sizey-1);
|
|
sv4= screen_addvert(sc, win->sizex-1, 0);
|
|
|
|
screen_addedge(sc, sv1, sv2);
|
|
screen_addedge(sc, sv2, sv3);
|
|
screen_addedge(sc, sv3, sv4);
|
|
screen_addedge(sc, sv4, sv1);
|
|
|
|
/* dummy type, no spacedata */
|
|
screen_addarea(sc, sv1, sv2, sv3, sv4, HEADERDOWN, SPACE_EMPTY);
|
|
|
|
return sc;
|
|
}
|
|
|
|
static void screen_copy(bScreen *to, bScreen *from)
|
|
{
|
|
ScrVert *s1, *s2;
|
|
ScrEdge *se;
|
|
ScrArea *sa, *saf;
|
|
|
|
/* free contents of 'to', is from blenkernel screen.c */
|
|
free_screen(to);
|
|
|
|
BLI_duplicatelist(&to->vertbase, &from->vertbase);
|
|
BLI_duplicatelist(&to->edgebase, &from->edgebase);
|
|
BLI_duplicatelist(&to->areabase, &from->areabase);
|
|
to->regionbase.first= to->regionbase.last= NULL;
|
|
|
|
s2= to->vertbase.first;
|
|
for(s1= from->vertbase.first; s1; s1= s1->next, s2= s2->next) {
|
|
s1->newv= s2;
|
|
}
|
|
|
|
for(se= to->edgebase.first; se; se= se->next) {
|
|
se->v1= se->v1->newv;
|
|
se->v2= se->v2->newv;
|
|
sortscrvert(&(se->v1), &(se->v2));
|
|
}
|
|
|
|
saf= from->areabase.first;
|
|
for(sa= to->areabase.first; sa; sa= sa->next, saf= saf->next) {
|
|
sa->v1= sa->v1->newv;
|
|
sa->v2= sa->v2->newv;
|
|
sa->v3= sa->v3->newv;
|
|
sa->v4= sa->v4->newv;
|
|
|
|
sa->spacedata.first= sa->spacedata.last= NULL;
|
|
sa->regionbase.first= sa->regionbase.last= NULL;
|
|
sa->actionzones.first= sa->actionzones.last= NULL;
|
|
sa->handlers.first= sa->handlers.last= NULL;
|
|
|
|
area_copy_data(sa, saf, 0);
|
|
}
|
|
|
|
/* put at zero (needed?) */
|
|
for(s1= from->vertbase.first; s1; s1= s1->next)
|
|
s1->newv= NULL;
|
|
|
|
}
|
|
|
|
|
|
/* with sa as center, sb is located at: 0=W, 1=N, 2=E, 3=S */
|
|
/* -1 = not valid check */
|
|
/* used with join operator */
|
|
int area_getorientation(bScreen *screen, ScrArea *sa, ScrArea *sb)
|
|
{
|
|
ScrVert *sav1, *sav2, *sav3, *sav4;
|
|
ScrVert *sbv1, *sbv2, *sbv3, *sbv4;
|
|
|
|
if(sa==NULL || sb==NULL) return -1;
|
|
|
|
sav1= sa->v1;
|
|
sav2= sa->v2;
|
|
sav3= sa->v3;
|
|
sav4= sa->v4;
|
|
sbv1= sb->v1;
|
|
sbv2= sb->v2;
|
|
sbv3= sb->v3;
|
|
sbv4= sb->v4;
|
|
|
|
if(sav1==sbv4 && sav2==sbv3) { /* sa to right of sb = W */
|
|
return 0;
|
|
}
|
|
else if(sav2==sbv1 && sav3==sbv4) { /* sa to bottom of sb = N */
|
|
return 1;
|
|
}
|
|
else if(sav3==sbv2 && sav4==sbv1) { /* sa to left of sb = E */
|
|
return 2;
|
|
}
|
|
else if(sav1==sbv2 && sav4==sbv3) { /* sa on top of sb = S*/
|
|
return 3;
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
/* Helper function to join 2 areas, it has a return value, 0=failed 1=success
|
|
* used by the split, join operators
|
|
*/
|
|
int screen_area_join(bContext *C, bScreen* scr, ScrArea *sa1, ScrArea *sa2)
|
|
{
|
|
int dir;
|
|
|
|
dir = area_getorientation(scr, sa1, sa2);
|
|
/*printf("dir is : %i \n", dir);*/
|
|
|
|
if (dir < 0)
|
|
{
|
|
if (sa1 ) sa1->flag &= ~AREA_FLAG_DRAWJOINFROM;
|
|
if (sa2 ) sa2->flag &= ~AREA_FLAG_DRAWJOINTO;
|
|
return 0;
|
|
}
|
|
|
|
if(dir == 0) {
|
|
sa1->v1= sa2->v1;
|
|
sa1->v2= sa2->v2;
|
|
screen_addedge(scr, sa1->v2, sa1->v3);
|
|
screen_addedge(scr, sa1->v1, sa1->v4);
|
|
}
|
|
else if(dir == 1) {
|
|
sa1->v2= sa2->v2;
|
|
sa1->v3= sa2->v3;
|
|
screen_addedge(scr, sa1->v1, sa1->v2);
|
|
screen_addedge(scr, sa1->v3, sa1->v4);
|
|
}
|
|
else if(dir == 2) {
|
|
sa1->v3= sa2->v3;
|
|
sa1->v4= sa2->v4;
|
|
screen_addedge(scr, sa1->v2, sa1->v3);
|
|
screen_addedge(scr, sa1->v1, sa1->v4);
|
|
}
|
|
else if(dir == 3) {
|
|
sa1->v1= sa2->v1;
|
|
sa1->v4= sa2->v4;
|
|
screen_addedge(scr, sa1->v1, sa1->v2);
|
|
screen_addedge(scr, sa1->v3, sa1->v4);
|
|
}
|
|
|
|
screen_delarea(C, scr, sa2);
|
|
removedouble_scrverts(scr);
|
|
sa1->flag &= ~AREA_FLAG_DRAWJOINFROM;
|
|
|
|
return 1;
|
|
}
|
|
|
|
void select_connected_scredge(bScreen *sc, ScrEdge *edge)
|
|
{
|
|
ScrEdge *se;
|
|
ScrVert *sv;
|
|
int oneselected;
|
|
char dir;
|
|
|
|
/* select connected, only in the right direction */
|
|
/* 'dir' is the direction of EDGE */
|
|
|
|
if(edge->v1->vec.x==edge->v2->vec.x) dir= 'v';
|
|
else dir= 'h';
|
|
|
|
sv= sc->vertbase.first;
|
|
while(sv) {
|
|
sv->flag = 0;
|
|
sv= sv->next;
|
|
}
|
|
|
|
edge->v1->flag= 1;
|
|
edge->v2->flag= 1;
|
|
|
|
oneselected= 1;
|
|
while(oneselected) {
|
|
se= sc->edgebase.first;
|
|
oneselected= 0;
|
|
while(se) {
|
|
if(se->v1->flag + se->v2->flag==1) {
|
|
if(dir=='h') if(se->v1->vec.y==se->v2->vec.y) {
|
|
se->v1->flag= se->v2->flag= 1;
|
|
oneselected= 1;
|
|
}
|
|
if(dir=='v') if(se->v1->vec.x==se->v2->vec.x) {
|
|
se->v1->flag= se->v2->flag= 1;
|
|
oneselected= 1;
|
|
}
|
|
}
|
|
se= se->next;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* test if screen vertices should be scaled */
|
|
static void screen_test_scale(bScreen *sc, int winsizex, int winsizey)
|
|
{
|
|
ScrVert *sv=NULL;
|
|
ScrArea *sa;
|
|
int sizex, sizey;
|
|
float facx, facy, tempf, min[2], max[2];
|
|
|
|
/* calculate size */
|
|
min[0]= min[1]= 10000.0f;
|
|
max[0]= max[1]= 0.0f;
|
|
|
|
for(sv= sc->vertbase.first; sv; sv= sv->next) {
|
|
min[0]= MIN2(min[0], sv->vec.x);
|
|
min[1]= MIN2(min[1], sv->vec.y);
|
|
max[0]= MAX2(max[0], sv->vec.x);
|
|
max[1]= MAX2(max[1], sv->vec.y);
|
|
}
|
|
|
|
/* always make 0.0 left under */
|
|
for(sv= sc->vertbase.first; sv; sv= sv->next) {
|
|
sv->vec.x -= min[0];
|
|
sv->vec.y -= min[1];
|
|
}
|
|
|
|
sizex= max[0]-min[0];
|
|
sizey= max[1]-min[1];
|
|
|
|
if(sizex!= winsizex || sizey!= winsizey) {
|
|
facx= winsizex;
|
|
facx/= (float)sizex;
|
|
facy= winsizey;
|
|
facy/= (float)sizey;
|
|
|
|
/* make sure it fits! */
|
|
for(sv= sc->vertbase.first; sv; sv= sv->next) {
|
|
tempf= ((float)sv->vec.x)*facx;
|
|
sv->vec.x= (short)(tempf+0.5);
|
|
sv->vec.x+= AREAGRID-1;
|
|
sv->vec.x-= (sv->vec.x % AREAGRID);
|
|
|
|
CLAMP(sv->vec.x, 0, winsizex);
|
|
|
|
tempf= ((float)sv->vec.y )*facy;
|
|
sv->vec.y= (short)(tempf+0.5);
|
|
sv->vec.y+= AREAGRID-1;
|
|
sv->vec.y-= (sv->vec.y % AREAGRID);
|
|
|
|
CLAMP(sv->vec.y, 0, winsizey);
|
|
}
|
|
}
|
|
|
|
/* test for collapsed areas. This could happen in some blender version... */
|
|
/* ton: removed option now, it needs Context... */
|
|
|
|
/* make each window at least HEADERY high */
|
|
for(sa= sc->areabase.first; sa; sa= sa->next) {
|
|
int headery= HEADERY+1;
|
|
|
|
if(sa->v1->vec.y+headery > sa->v2->vec.y) {
|
|
/* lower edge */
|
|
ScrEdge *se= screen_findedge(sc, sa->v4, sa->v1);
|
|
if(se && sa->v1!=sa->v2 ) {
|
|
int yval;
|
|
|
|
select_connected_scredge(sc, se);
|
|
|
|
/* all selected vertices get the right offset */
|
|
yval= sa->v2->vec.y-headery;
|
|
sv= sc->vertbase.first;
|
|
while(sv) {
|
|
/* if is a collapsed area */
|
|
if(sv!=sa->v2 && sv!=sa->v3) {
|
|
if(sv->flag) sv->vec.y= yval;
|
|
}
|
|
sv= sv->next;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
/* *********************** DRAWING **************************************** */
|
|
|
|
|
|
#define SCR_BACK 0.55
|
|
#define SCR_ROUND 12
|
|
|
|
/* draw vertical shape visualising future joining (left as well
|
|
* right direction of future joining) */
|
|
static void draw_horizontal_join_shape(ScrArea *sa, char dir)
|
|
{
|
|
vec2f points[10];
|
|
short i;
|
|
float w, h;
|
|
float width = sa->v3->vec.x - sa->v1->vec.x;
|
|
float height = sa->v3->vec.y - sa->v1->vec.y;
|
|
|
|
if(height<width) {
|
|
h = height/8;
|
|
w = height/4;
|
|
}
|
|
else {
|
|
h = width/8;
|
|
w = width/4;
|
|
}
|
|
|
|
points[0].x = sa->v1->vec.x;
|
|
points[0].y = sa->v1->vec.y + height/2;
|
|
|
|
points[1].x = sa->v1->vec.x;
|
|
points[1].y = sa->v1->vec.y;
|
|
|
|
points[2].x = sa->v4->vec.x - w;
|
|
points[2].y = sa->v4->vec.y;
|
|
|
|
points[3].x = sa->v4->vec.x - w;
|
|
points[3].y = sa->v4->vec.y + height/2 - 2*h;
|
|
|
|
points[4].x = sa->v4->vec.x - 2*w;
|
|
points[4].y = sa->v4->vec.y + height/2;
|
|
|
|
points[5].x = sa->v4->vec.x - w;
|
|
points[5].y = sa->v4->vec.y + height/2 + 2*h;
|
|
|
|
points[6].x = sa->v3->vec.x - w;
|
|
points[6].y = sa->v3->vec.y;
|
|
|
|
points[7].x = sa->v2->vec.x;
|
|
points[7].y = sa->v2->vec.y;
|
|
|
|
points[8].x = sa->v4->vec.x;
|
|
points[8].y = sa->v4->vec.y + height/2 - h;
|
|
|
|
points[9].x = sa->v4->vec.x;
|
|
points[9].y = sa->v4->vec.y + height/2 + h;
|
|
|
|
if(dir=='l') {
|
|
/* when direction is left, then we flip direction of arrow */
|
|
float cx = sa->v1->vec.x + width;
|
|
for(i=0;i<10;i++) {
|
|
points[i].x -= cx;
|
|
points[i].x = -points[i].x;
|
|
points[i].x += sa->v1->vec.x;
|
|
}
|
|
}
|
|
|
|
glBegin(GL_POLYGON);
|
|
for(i=0;i<5;i++)
|
|
glVertex2f(points[i].x, points[i].y);
|
|
glEnd();
|
|
glBegin(GL_POLYGON);
|
|
for(i=4;i<8;i++)
|
|
glVertex2f(points[i].x, points[i].y);
|
|
glVertex2f(points[0].x, points[0].y);
|
|
glEnd();
|
|
|
|
glRectf(points[2].x, points[2].y, points[8].x, points[8].y);
|
|
glRectf(points[6].x, points[6].y, points[9].x, points[9].y);
|
|
}
|
|
|
|
/* draw vertical shape visualising future joining (up/down direction) */
|
|
static void draw_vertical_join_shape(ScrArea *sa, char dir)
|
|
{
|
|
vec2f points[10];
|
|
short i;
|
|
float w, h;
|
|
float width = sa->v3->vec.x - sa->v1->vec.x;
|
|
float height = sa->v3->vec.y - sa->v1->vec.y;
|
|
|
|
if(height<width) {
|
|
h = height/4;
|
|
w = height/8;
|
|
}
|
|
else {
|
|
h = width/4;
|
|
w = width/8;
|
|
}
|
|
|
|
points[0].x = sa->v1->vec.x + width/2;
|
|
points[0].y = sa->v3->vec.y;
|
|
|
|
points[1].x = sa->v2->vec.x;
|
|
points[1].y = sa->v2->vec.y;
|
|
|
|
points[2].x = sa->v1->vec.x;
|
|
points[2].y = sa->v1->vec.y + h;
|
|
|
|
points[3].x = sa->v1->vec.x + width/2 - 2*w;
|
|
points[3].y = sa->v1->vec.y + h;
|
|
|
|
points[4].x = sa->v1->vec.x + width/2;
|
|
points[4].y = sa->v1->vec.y + 2*h;
|
|
|
|
points[5].x = sa->v1->vec.x + width/2 + 2*w;
|
|
points[5].y = sa->v1->vec.y + h;
|
|
|
|
points[6].x = sa->v4->vec.x;
|
|
points[6].y = sa->v4->vec.y + h;
|
|
|
|
points[7].x = sa->v3->vec.x;
|
|
points[7].y = sa->v3->vec.y;
|
|
|
|
points[8].x = sa->v1->vec.x + width/2 - w;
|
|
points[8].y = sa->v1->vec.y;
|
|
|
|
points[9].x = sa->v1->vec.x + width/2 + w;
|
|
points[9].y = sa->v1->vec.y;
|
|
|
|
if(dir=='u') {
|
|
/* when direction is up, then we flip direction of arrow */
|
|
float cy = sa->v1->vec.y + height;
|
|
for(i=0;i<10;i++) {
|
|
points[i].y -= cy;
|
|
points[i].y = -points[i].y;
|
|
points[i].y += sa->v1->vec.y;
|
|
}
|
|
}
|
|
|
|
glBegin(GL_POLYGON);
|
|
for(i=0;i<5;i++)
|
|
glVertex2f(points[i].x, points[i].y);
|
|
glEnd();
|
|
glBegin(GL_POLYGON);
|
|
for(i=4;i<8;i++)
|
|
glVertex2f(points[i].x, points[i].y);
|
|
glVertex2f(points[0].x, points[0].y);
|
|
glEnd();
|
|
|
|
glRectf(points[2].x, points[2].y, points[8].x, points[8].y);
|
|
glRectf(points[6].x, points[6].y, points[9].x, points[9].y);
|
|
}
|
|
|
|
/* draw join shape due to direction of joining */
|
|
static void draw_join_shape(ScrArea *sa, char dir)
|
|
{
|
|
if(dir=='u' || dir=='d')
|
|
draw_vertical_join_shape(sa, dir);
|
|
else
|
|
draw_horizontal_join_shape(sa, dir);
|
|
}
|
|
|
|
/* draw screen area darker with arrow (visualisation of future joining) */
|
|
static void scrarea_draw_shape_dark(ScrArea *sa, char dir)
|
|
{
|
|
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
|
glEnable(GL_BLEND);
|
|
glColor4ub(0, 0, 0, 50);
|
|
draw_join_shape(sa, dir);
|
|
glDisable(GL_BLEND);
|
|
}
|
|
|
|
/* draw screen area ligher with arrow shape ("eraser" of previous dark shape) */
|
|
static void scrarea_draw_shape_light(ScrArea *sa, char dir)
|
|
{
|
|
glBlendFunc(GL_DST_COLOR, GL_SRC_ALPHA);
|
|
glEnable(GL_BLEND);
|
|
/* value 181 was hardly computed: 181~105 */
|
|
glColor4ub(255, 255, 255, 50);
|
|
/* draw_join_shape(sa, dir); */
|
|
glRecti(sa->v1->vec.x, sa->v1->vec.y, sa->v3->vec.x, sa->v3->vec.y);
|
|
glDisable(GL_BLEND);
|
|
}
|
|
|
|
static void drawscredge_area_draw(int sizex, int sizey, short x1, short y1, short x2, short y2, short a)
|
|
{
|
|
/* right border area */
|
|
if(x2<sizex-1)
|
|
sdrawline(x2+a, y1, x2+a, y2);
|
|
|
|
/* left border area */
|
|
if(x1>0) /* otherwise it draws the emboss of window over */
|
|
sdrawline(x1+a, y1, x1+a, y2);
|
|
|
|
/* top border area */
|
|
if(y2<sizey-1)
|
|
sdrawline(x1, y2+a, x2, y2+a);
|
|
|
|
/* bottom border area */
|
|
if(y1>0)
|
|
sdrawline(x1, y1+a, x2, y1+a);
|
|
|
|
}
|
|
|
|
/** screen edges drawing **/
|
|
static void drawscredge_area(ScrArea *sa, int sizex, int sizey, int center)
|
|
{
|
|
short x1= sa->v1->vec.x;
|
|
short y1= sa->v1->vec.y;
|
|
short x2= sa->v3->vec.x;
|
|
short y2= sa->v3->vec.y;
|
|
short a, rt;
|
|
|
|
rt= CLAMPIS(G.rt, 0, 16);
|
|
|
|
if(center==0) {
|
|
cpack(0x505050);
|
|
for(a=-rt; a<=rt; a++)
|
|
if(a!=0)
|
|
drawscredge_area_draw(sizex, sizey, x1, y1, x2, y2, a);
|
|
}
|
|
else {
|
|
cpack(0x0);
|
|
drawscredge_area_draw(sizex, sizey, x1, y1, x2, y2, 0);
|
|
}
|
|
}
|
|
|
|
/* ****************** EXPORTED API TO OTHER MODULES *************************** */
|
|
|
|
bScreen *ED_screen_duplicate(wmWindow *win, bScreen *sc)
|
|
{
|
|
bScreen *newsc;
|
|
|
|
if(sc->full != SCREENNORMAL) return NULL; /* XXX handle this case! */
|
|
|
|
/* make new empty screen: */
|
|
newsc= ED_screen_add(win, sc->scene, sc->id.name+2);
|
|
/* copy all data */
|
|
screen_copy(newsc, sc);
|
|
|
|
return newsc;
|
|
}
|
|
|
|
/* screen sets cursor based on swinid */
|
|
static void region_cursor_set(wmWindow *win, int swinid)
|
|
{
|
|
ScrArea *sa= win->screen->areabase.first;
|
|
|
|
for(;sa; sa= sa->next) {
|
|
ARegion *ar= sa->regionbase.first;
|
|
for(;ar; ar= ar->next) {
|
|
if(ar->swinid == swinid) {
|
|
if(ar->type && ar->type->cursor)
|
|
ar->type->cursor(win, sa, ar);
|
|
else
|
|
WM_cursor_set(win, CURSOR_STD);
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void ED_screen_do_listen(wmWindow *win, wmNotifier *note)
|
|
{
|
|
|
|
/* generic notes */
|
|
switch(note->category) {
|
|
case NC_WM:
|
|
if(note->data==ND_FILEREAD)
|
|
win->screen->do_draw= 1;
|
|
break;
|
|
case NC_WINDOW:
|
|
win->screen->do_draw= 1;
|
|
break;
|
|
case NC_SCREEN:
|
|
if(note->action==NA_EDITED)
|
|
win->screen->do_draw= win->screen->do_refresh= 1;
|
|
case NC_SCENE:
|
|
if(note->data==ND_MODE)
|
|
region_cursor_set(win, note->swinid);
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* only for edge lines between areas, and the blended join arrows */
|
|
void ED_screen_draw(wmWindow *win)
|
|
{
|
|
ScrArea *sa;
|
|
ScrArea *sa1=NULL;
|
|
ScrArea *sa2=NULL;
|
|
int dir = -1;
|
|
int dira = -1;
|
|
|
|
wmSubWindowSet(win, win->screen->mainwin);
|
|
|
|
for(sa= win->screen->areabase.first; sa; sa= sa->next) {
|
|
if (sa->flag & AREA_FLAG_DRAWJOINFROM) sa1 = sa;
|
|
if (sa->flag & AREA_FLAG_DRAWJOINTO) sa2 = sa;
|
|
drawscredge_area(sa, win->sizex, win->sizey, 0);
|
|
}
|
|
for(sa= win->screen->areabase.first; sa; sa= sa->next)
|
|
drawscredge_area(sa, win->sizex, win->sizey, 1);
|
|
|
|
/* blended join arrow */
|
|
if (sa1 && sa2) {
|
|
dir = area_getorientation(win->screen, sa1, sa2);
|
|
if (dir >= 0) {
|
|
switch(dir) {
|
|
case 0: /* W */
|
|
dir = 'r';
|
|
dira = 'l';
|
|
break;
|
|
case 1: /* N */
|
|
dir = 'd';
|
|
dira = 'u';
|
|
break;
|
|
case 2: /* E */
|
|
dir = 'l';
|
|
dira = 'r';
|
|
break;
|
|
case 3: /* S */
|
|
dir = 'u';
|
|
dira = 'd';
|
|
break;
|
|
}
|
|
}
|
|
scrarea_draw_shape_dark(sa2, dir);
|
|
scrarea_draw_shape_light(sa1, dira);
|
|
}
|
|
|
|
// if(G.f & G_DEBUG) printf("draw screen\n");
|
|
win->screen->do_draw= 0;
|
|
}
|
|
|
|
/* make this screen usable */
|
|
/* for file read and first use, for scaling window, area moves */
|
|
void ED_screen_refresh(wmWindowManager *wm, wmWindow *win)
|
|
{
|
|
ScrArea *sa;
|
|
rcti winrct= {0, win->sizex-1, 0, win->sizey-1};
|
|
|
|
screen_test_scale(win->screen, win->sizex, win->sizey);
|
|
|
|
if(win->screen->mainwin==0)
|
|
win->screen->mainwin= wm_subwindow_open(win, &winrct);
|
|
else
|
|
wm_subwindow_position(win, win->screen->mainwin, &winrct);
|
|
|
|
for(sa= win->screen->areabase.first; sa; sa= sa->next) {
|
|
/* set spacetype and region callbacks, calls init() */
|
|
/* sets subwindows for regions, adds handlers */
|
|
ED_area_initialize(wm, win, sa);
|
|
}
|
|
|
|
/* wake up animtimer */
|
|
if(win->screen->animtimer)
|
|
WM_event_timer_sleep(wm, win, win->screen->animtimer, 0);
|
|
|
|
if(G.f & G_DEBUG) printf("set screen\n");
|
|
win->screen->do_refresh= 0;
|
|
|
|
win->screen->context= ed_screen_context;
|
|
}
|
|
|
|
/* file read, set all screens, ... */
|
|
void ED_screens_initialize(wmWindowManager *wm)
|
|
{
|
|
wmWindow *win;
|
|
|
|
for(win= wm->windows.first; win; win= win->next) {
|
|
|
|
if(win->screen==NULL)
|
|
win->screen= G.main->screen.first;
|
|
|
|
ED_screen_refresh(wm, win);
|
|
}
|
|
}
|
|
|
|
|
|
/* *********** exit calls are for closing running stuff ******** */
|
|
|
|
void ED_region_exit(bContext *C, ARegion *ar)
|
|
{
|
|
ARegion *prevar= CTX_wm_region(C);
|
|
|
|
CTX_wm_region_set(C, ar);
|
|
WM_event_remove_handlers(C, &ar->handlers);
|
|
if(ar->swinid)
|
|
wm_subwindow_close(CTX_wm_window(C), ar->swinid);
|
|
ar->swinid= 0;
|
|
|
|
if(ar->headerstr)
|
|
MEM_freeN(ar->headerstr);
|
|
ar->headerstr= NULL;
|
|
|
|
CTX_wm_region_set(C, prevar);
|
|
}
|
|
|
|
void ED_area_exit(bContext *C, ScrArea *sa)
|
|
{
|
|
ScrArea *prevsa= CTX_wm_area(C);
|
|
ARegion *ar;
|
|
|
|
CTX_wm_area_set(C, sa);
|
|
for(ar= sa->regionbase.first; ar; ar= ar->next)
|
|
ED_region_exit(C, ar);
|
|
|
|
WM_event_remove_handlers(C, &sa->handlers);
|
|
CTX_wm_area_set(C, prevsa);
|
|
}
|
|
|
|
void ED_screen_exit(bContext *C, wmWindow *window, bScreen *screen)
|
|
{
|
|
wmWindowManager *wm= CTX_wm_manager(C);
|
|
wmWindow *prevwin= CTX_wm_window(C);
|
|
ScrArea *sa;
|
|
ARegion *ar;
|
|
|
|
CTX_wm_window_set(C, window);
|
|
|
|
if(screen->animtimer)
|
|
WM_event_remove_timer(wm, window, screen->animtimer);
|
|
screen->animtimer= NULL;
|
|
|
|
if(screen->mainwin)
|
|
wm_subwindow_close(window, screen->mainwin);
|
|
screen->mainwin= 0;
|
|
screen->subwinactive= 0;
|
|
|
|
for(ar= screen->regionbase.first; ar; ar= ar->next)
|
|
ED_region_exit(C, ar);
|
|
|
|
for(sa= screen->areabase.first; sa; sa= sa->next)
|
|
ED_area_exit(C, sa);
|
|
|
|
/* mark it available for use for other windows */
|
|
screen->winid= 0;
|
|
|
|
/* before deleting the temp screen or we get invalid access */
|
|
if (prevwin->screen->full != SCREENTEMP) {
|
|
/* use previous window if possible */
|
|
CTX_wm_window_set(C, prevwin);
|
|
} else {
|
|
/* none otherwise */
|
|
CTX_wm_window_set(C, NULL);
|
|
}
|
|
|
|
/* if temp screen, delete it */
|
|
if(screen->full == SCREENTEMP) {
|
|
Main *bmain= CTX_data_main(C);
|
|
free_libblock(&bmain->screen, screen);
|
|
}
|
|
}
|
|
|
|
/* *********************************** */
|
|
|
|
/* case when on area-edge or in azones, or outside window */
|
|
static void screen_cursor_set(wmWindow *win, wmEvent *event)
|
|
{
|
|
AZone *az= NULL;
|
|
ScrArea *sa;
|
|
|
|
for(sa= win->screen->areabase.first; sa; sa= sa->next)
|
|
if((az=is_in_area_actionzone(sa, event->x, event->y)))
|
|
break;
|
|
|
|
if(sa) {
|
|
if(az->type==AZONE_AREA)
|
|
WM_cursor_set(win, CURSOR_EDIT);
|
|
else if(az->type==AZONE_REGION) {
|
|
if(az->edge == 'l' || az->edge == 'r')
|
|
WM_cursor_set(win, CURSOR_X_MOVE);
|
|
else
|
|
WM_cursor_set(win, CURSOR_Y_MOVE);
|
|
}
|
|
}
|
|
else {
|
|
ScrEdge *actedge= screen_find_active_scredge(win->screen, event->x, event->y);
|
|
|
|
if (actedge) {
|
|
if(scredge_is_horizontal(actedge))
|
|
WM_cursor_set(win, CURSOR_Y_MOVE);
|
|
else
|
|
WM_cursor_set(win, CURSOR_X_MOVE);
|
|
}
|
|
else
|
|
WM_cursor_set(win, CURSOR_STD);
|
|
}
|
|
}
|
|
|
|
|
|
/* called in wm_event_system.c. sets state vars in screen, cursors */
|
|
/* event type is mouse move */
|
|
void ED_screen_set_subwinactive(wmWindow *win, wmEvent *event)
|
|
{
|
|
if(win->screen) {
|
|
bScreen *scr= win->screen;
|
|
ScrArea *sa;
|
|
ARegion *ar;
|
|
int oldswin= scr->subwinactive;
|
|
|
|
for(sa= scr->areabase.first; sa; sa= sa->next) {
|
|
if(event->x > sa->totrct.xmin && event->x < sa->totrct.xmax)
|
|
if(event->y > sa->totrct.ymin && event->y < sa->totrct.ymax)
|
|
if(NULL==is_in_area_actionzone(sa, event->x, event->y))
|
|
break;
|
|
}
|
|
if(sa) {
|
|
for(ar= sa->regionbase.first; ar; ar= ar->next) {
|
|
if(BLI_in_rcti(&ar->winrct, event->x, event->y))
|
|
scr->subwinactive= ar->swinid;
|
|
}
|
|
}
|
|
else
|
|
scr->subwinactive= scr->mainwin;
|
|
|
|
/* check for redraw headers */
|
|
if(oldswin!=scr->subwinactive) {
|
|
|
|
for(sa= scr->areabase.first; sa; sa= sa->next) {
|
|
int do_draw= 0;
|
|
|
|
for(ar= sa->regionbase.first; ar; ar= ar->next)
|
|
if(ar->swinid==oldswin || ar->swinid==scr->subwinactive)
|
|
do_draw= 1;
|
|
|
|
if(do_draw) {
|
|
for(ar= sa->regionbase.first; ar; ar= ar->next)
|
|
if(ar->regiontype==RGN_TYPE_HEADER)
|
|
ED_region_tag_redraw(ar);
|
|
}
|
|
}
|
|
}
|
|
|
|
/* cursors, for time being set always on edges, otherwise aregion doesnt switch */
|
|
if(scr->subwinactive==scr->mainwin) {
|
|
screen_cursor_set(win, event);
|
|
}
|
|
else if(oldswin!=scr->subwinactive) {
|
|
region_cursor_set(win, scr->subwinactive);
|
|
}
|
|
}
|
|
}
|
|
|
|
int ED_screen_area_active(const bContext *C)
|
|
{
|
|
bScreen *sc= CTX_wm_screen(C);
|
|
ScrArea *sa= CTX_wm_area(C);
|
|
|
|
if(sc && sa) {
|
|
ARegion *ar;
|
|
for(ar= sa->regionbase.first; ar; ar= ar->next)
|
|
if(ar->swinid == sc->subwinactive)
|
|
return 1;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/* operator call, WM + Window + screen already existed before */
|
|
/* Do NOT call in area/region queues! */
|
|
void ED_screen_set(bContext *C, bScreen *sc)
|
|
{
|
|
wmWindowManager *wm= CTX_wm_manager(C);
|
|
wmWindow *win= CTX_wm_window(C);
|
|
bScreen *oldscreen= CTX_wm_screen(C);
|
|
ID *id;
|
|
|
|
/* validate screen, it's called with notifier reference */
|
|
for(id= CTX_data_main(C)->screen.first; id; id= id->next)
|
|
if(sc == (bScreen *)id)
|
|
break;
|
|
if(id==NULL)
|
|
return;
|
|
|
|
/* check for valid winid */
|
|
if(sc->winid!=0 && sc->winid!=win->winid)
|
|
return;
|
|
|
|
if(sc->full) { /* find associated full */
|
|
bScreen *sc1;
|
|
for(sc1= CTX_data_main(C)->screen.first; sc1; sc1= sc1->id.next) {
|
|
ScrArea *sa= sc1->areabase.first;
|
|
if(sa->full==sc) {
|
|
sc= sc1;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (oldscreen != sc) {
|
|
wmTimer *wt= oldscreen->animtimer;
|
|
ScrArea *sa;
|
|
|
|
/* remove handlers referencing areas in old screen */
|
|
for(sa = oldscreen->areabase.first; sa; sa = sa->next) {
|
|
WM_event_remove_area_handler(&win->modalhandlers, sa);
|
|
}
|
|
|
|
/* we put timer to sleep, so screen_exit has to think there's no timer */
|
|
oldscreen->animtimer= NULL;
|
|
if(wt)
|
|
WM_event_timer_sleep(wm, win, wt, 1);
|
|
|
|
ED_screen_exit(C, win, oldscreen);
|
|
oldscreen->animtimer= wt;
|
|
|
|
win->screen= sc;
|
|
CTX_wm_window_set(C, win); // stores C->wm.screen... hrmf
|
|
|
|
/* prevent multiwin errors */
|
|
sc->winid= win->winid;
|
|
|
|
ED_screen_refresh(CTX_wm_manager(C), CTX_wm_window(C));
|
|
WM_event_add_notifier(C, NC_WINDOW, NULL);
|
|
|
|
/* makes button hilites work */
|
|
WM_event_add_mousemove(C);
|
|
}
|
|
}
|
|
|
|
static int ed_screen_used(wmWindowManager *wm, bScreen *sc)
|
|
{
|
|
wmWindow *win;
|
|
|
|
for(win=wm->windows.first; win; win=win->next)
|
|
if(win->screen == sc)
|
|
return 1;
|
|
|
|
return 0;
|
|
}
|
|
|
|
/* only call outside of area/region loops */
|
|
void ED_screen_delete(bContext *C, bScreen *sc)
|
|
{
|
|
Main *bmain= CTX_data_main(C);
|
|
wmWindowManager *wm= CTX_wm_manager(C);
|
|
wmWindow *win= CTX_wm_window(C);
|
|
bScreen *newsc;
|
|
int delete= 1;
|
|
|
|
/* don't allow deleting temp fullscreens for now */
|
|
if (sc->full == SCREENFULL) {
|
|
return;
|
|
}
|
|
|
|
|
|
/* screen can only be in use by one window at a time, so as
|
|
long as we are able to find a screen that is unused, we
|
|
can safely assume ours is not in use anywhere an delete it */
|
|
|
|
for(newsc= sc->id.prev; newsc; newsc=newsc->id.prev)
|
|
if(!ed_screen_used(wm, newsc))
|
|
break;
|
|
|
|
if(!newsc) {
|
|
for(newsc= sc->id.next; newsc; newsc=newsc->id.next)
|
|
if(!ed_screen_used(wm, newsc))
|
|
break;
|
|
}
|
|
|
|
if(!newsc)
|
|
return;
|
|
|
|
ED_screen_set(C, newsc);
|
|
|
|
if(delete && win->screen != sc)
|
|
free_libblock(&bmain->screen, sc);
|
|
}
|
|
|
|
/* only call outside of area/region loops */
|
|
void ED_screen_set_scene(bContext *C, Scene *scene)
|
|
{
|
|
bScreen *sc;
|
|
bScreen *curscreen= CTX_wm_screen(C);
|
|
|
|
for(sc= CTX_data_main(C)->screen.first; sc; sc= sc->id.next) {
|
|
if((U.flag & USER_SCENEGLOBAL) || sc==curscreen) {
|
|
|
|
if(scene != sc->scene) {
|
|
/* all areas endlocalview */
|
|
// XXX ScrArea *sa= sc->areabase.first;
|
|
// while(sa) {
|
|
// endlocalview(sa);
|
|
// sa= sa->next;
|
|
// }
|
|
sc->scene= scene;
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
// copy_view3d_lock(0); /* space.c */
|
|
|
|
/* are there cameras in the views that are not in the scene? */
|
|
for(sc= CTX_data_main(C)->screen.first; sc; sc= sc->id.next) {
|
|
if( (U.flag & USER_SCENEGLOBAL) || sc==curscreen) {
|
|
ScrArea *sa= sc->areabase.first;
|
|
while(sa) {
|
|
SpaceLink *sl= sa->spacedata.first;
|
|
while(sl) {
|
|
if(sl->spacetype==SPACE_VIEW3D) {
|
|
View3D *v3d= (View3D*) sl;
|
|
if (!v3d->camera || !object_in_scene(v3d->camera, scene)) {
|
|
v3d->camera= scene_find_camera(sc->scene);
|
|
// XXX if (sc==curscreen) handle_view3d_lock();
|
|
if (!v3d->camera) {
|
|
ARegion *ar;
|
|
for(ar=v3d->regionbase.first; ar; ar= ar->next) {
|
|
if(ar->regiontype == RGN_TYPE_WINDOW) {
|
|
RegionView3D *rv3d= ar->regiondata;
|
|
|
|
if(rv3d->persp==RV3D_CAMOB)
|
|
rv3d->persp= RV3D_PERSP;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
sl= sl->next;
|
|
}
|
|
sa= sa->next;
|
|
}
|
|
}
|
|
}
|
|
|
|
CTX_data_scene_set(C, scene);
|
|
set_scene_bg(scene);
|
|
|
|
ED_update_for_newframe(C, 1);
|
|
|
|
/* complete redraw */
|
|
WM_event_add_notifier(C, NC_WINDOW, NULL);
|
|
|
|
}
|
|
|
|
/* only call outside of area/region loops */
|
|
void ED_screen_delete_scene(bContext *C, Scene *scene)
|
|
{
|
|
Main *bmain= CTX_data_main(C);
|
|
Scene *newscene;
|
|
|
|
if(scene->id.prev)
|
|
newscene= scene->id.prev;
|
|
else if(scene->id.next)
|
|
newscene= scene->id.next;
|
|
else
|
|
return;
|
|
|
|
ED_screen_set_scene(C, newscene);
|
|
|
|
unlink_scene(bmain, scene, newscene);
|
|
}
|
|
|
|
/* this function toggles: if area is full then the parent will be restored */
|
|
ScrArea *ed_screen_fullarea(bContext *C, wmWindow *win, ScrArea *sa)
|
|
{
|
|
bScreen *sc, *oldscreen;
|
|
ARegion *ar;
|
|
|
|
if(sa) {
|
|
/* ensure we don't have a button active anymore, can crash when
|
|
switching screens with tooltip open because region and tooltip
|
|
are no longer in the same screen */
|
|
for(ar=sa->regionbase.first; ar; ar=ar->next)
|
|
uiFreeBlocks(C, &ar->uiblocks);
|
|
}
|
|
|
|
if(sa && sa->full) {
|
|
short fulltype;
|
|
|
|
sc= sa->full; /* the old screen to restore */
|
|
oldscreen= win->screen; /* the one disappearing */
|
|
|
|
fulltype = sc->full;
|
|
|
|
/* refuse to go out of SCREENAUTOPLAY as long as G_FLAGS_AUTOPLAY
|
|
is set */
|
|
|
|
if (fulltype != SCREENAUTOPLAY || (G.flags & G_FILE_AUTOPLAY) == 0) {
|
|
ScrArea *old;
|
|
|
|
sc->full= 0;
|
|
|
|
/* find old area */
|
|
for(old= sc->areabase.first; old; old= old->next)
|
|
if(old->full) break;
|
|
if(old==NULL) {
|
|
if (G.f & G_DEBUG)
|
|
printf("something wrong in areafullscreen\n");
|
|
return NULL;
|
|
}
|
|
// old feature described below (ton)
|
|
// in autoplay screens the headers are disabled by
|
|
// default. So use the old headertype instead
|
|
|
|
area_copy_data(old, sa, 1); /* 1 = swap spacelist */
|
|
if (sa->flag & AREA_TEMP_INFO) sa->flag &= ~AREA_TEMP_INFO;
|
|
old->full= NULL;
|
|
|
|
/* animtimer back */
|
|
sc->animtimer= oldscreen->animtimer;
|
|
oldscreen->animtimer= NULL;
|
|
|
|
ED_screen_set(C, sc);
|
|
|
|
free_screen(oldscreen);
|
|
free_libblock(&CTX_data_main(C)->screen, oldscreen);
|
|
}
|
|
}
|
|
else {
|
|
ScrArea *newa;
|
|
char newname[20];
|
|
|
|
oldscreen= win->screen;
|
|
|
|
/* nothing wrong with having only 1 area, as far as I can see...
|
|
// is there only 1 area?
|
|
if(oldscreen->areabase.first==oldscreen->areabase.last)
|
|
return NULL;
|
|
*/
|
|
|
|
oldscreen->full = SCREENFULL;
|
|
BLI_snprintf(newname, sizeof(newname), "%s-%s", oldscreen->id.name+2, "temp");
|
|
sc= ED_screen_add(win, oldscreen->scene, newname);
|
|
sc->full = SCREENFULL; // XXX
|
|
|
|
/* timer */
|
|
sc->animtimer= oldscreen->animtimer;
|
|
oldscreen->animtimer= NULL;
|
|
|
|
/* returns the top small area */
|
|
newa= area_split(win, sc, (ScrArea *)sc->areabase.first, 'h', 0.99f);
|
|
ED_area_newspace(C, newa, SPACE_INFO);
|
|
|
|
/* use random area when we have no active one, e.g. when the
|
|
mouse is outside of the window and we open a file browser */
|
|
if(!sa)
|
|
sa= oldscreen->areabase.first;
|
|
|
|
/* copy area */
|
|
newa= newa->prev;
|
|
area_copy_data(newa, sa, 1); /* 1 = swap spacelist */
|
|
sa->flag |= AREA_TEMP_INFO;
|
|
|
|
sa->full= oldscreen;
|
|
newa->full= oldscreen;
|
|
newa->next->full= oldscreen; // XXX
|
|
|
|
ED_screen_set(C, sc);
|
|
}
|
|
|
|
/* XXX bad code: setscreen() ends with first area active. fullscreen render assumes this too */
|
|
CTX_wm_area_set(C, sc->areabase.first);
|
|
|
|
/* XXX retopo_force_update(); */
|
|
|
|
return sc->areabase.first;
|
|
}
|
|
|
|
int ED_screen_full_newspace(bContext *C, ScrArea *sa, int type)
|
|
{
|
|
wmWindow *win= CTX_wm_window(C);
|
|
bScreen *screen= CTX_wm_screen(C);
|
|
ScrArea *newsa= NULL;
|
|
|
|
if(!sa || sa->full==0) {
|
|
newsa= ed_screen_fullarea(C, win, sa);
|
|
}
|
|
|
|
if(!newsa) {
|
|
if (sa->full) {
|
|
/* if this has been called from the temporary info header generated in
|
|
* temp fullscreen layouts, find the correct fullscreen area to change
|
|
* to create a new space inside */
|
|
for (newsa = screen->areabase.first; newsa; newsa=newsa->next) {
|
|
if (!(sa->flag & AREA_TEMP_INFO))
|
|
break;
|
|
}
|
|
} else
|
|
newsa= sa;
|
|
}
|
|
|
|
ED_area_newspace(C, newsa, type);
|
|
|
|
return 1;
|
|
}
|
|
|
|
void ED_screen_full_prevspace(bContext *C, ScrArea *sa)
|
|
{
|
|
wmWindow *win= CTX_wm_window(C);
|
|
|
|
ED_area_prevspace(C, sa);
|
|
|
|
if(sa->full)
|
|
ed_screen_fullarea(C, win, sa);
|
|
}
|
|
|
|
/* restore a screen / area back to default operation, after temp fullscreen modes */
|
|
void ED_screen_full_restore(bContext *C, ScrArea *sa)
|
|
{
|
|
wmWindow *win= CTX_wm_window(C);
|
|
SpaceLink *sl = sa->spacedata.first;
|
|
|
|
/* if fullscreen area has a secondary space (such as as file browser or fullscreen render
|
|
* overlaid on top of a existing setup) then return to the previous space */
|
|
|
|
if (sl->next) {
|
|
/* specific checks for space types */
|
|
if (sl->spacetype == SPACE_IMAGE) {
|
|
SpaceImage *sima= sa->spacedata.first;
|
|
if (sima->flag & SI_PREVSPACE)
|
|
sima->flag &= ~SI_PREVSPACE;
|
|
if (sima->flag & SI_FULLWINDOW) {
|
|
sima->flag &= ~SI_FULLWINDOW;
|
|
ED_screen_full_prevspace(C, sa);
|
|
}
|
|
} else if (sl->spacetype == SPACE_FILE) {
|
|
ED_screen_full_prevspace(C, sa);
|
|
} else
|
|
ed_screen_fullarea(C, win, sa);
|
|
}
|
|
/* otherwise just tile the area again */
|
|
else {
|
|
ed_screen_fullarea(C, win, sa);
|
|
}
|
|
}
|
|
|
|
/* redraws: uses defines from stime->redraws
|
|
* enable: 1 - forward on, -1 - backwards on, 0 - off
|
|
*/
|
|
void ED_screen_animation_timer(bContext *C, int redraws, int sync, int enable)
|
|
{
|
|
bScreen *screen= CTX_wm_screen(C);
|
|
wmWindowManager *wm= CTX_wm_manager(C);
|
|
wmWindow *win= CTX_wm_window(C);
|
|
Scene *scene= CTX_data_scene(C);
|
|
|
|
if(screen->animtimer)
|
|
WM_event_remove_timer(wm, win, screen->animtimer);
|
|
screen->animtimer= NULL;
|
|
|
|
if(enable) {
|
|
ScreenAnimData *sad= MEM_callocN(sizeof(ScreenAnimData), "ScreenAnimData");
|
|
|
|
screen->animtimer= WM_event_add_timer(wm, win, TIMER0, (1.0/FPS));
|
|
sad->ar= CTX_wm_region(C);
|
|
sad->sfra = scene->r.cfra;
|
|
sad->redraws= redraws;
|
|
sad->flag |= (enable < 0)? ANIMPLAY_FLAG_REVERSE: 0;
|
|
sad->flag |= (sync == 0)? ANIMPLAY_FLAG_NO_SYNC: (sync == 1)? ANIMPLAY_FLAG_SYNC: 0;
|
|
screen->animtimer->customdata= sad;
|
|
|
|
}
|
|
/* notifier catched by top header, for button */
|
|
WM_event_add_notifier(C, NC_SCREEN|ND_ANIMPLAY, screen);
|
|
}
|
|
|
|
/* helper for screen_animation_play() - only to be used for TimeLine */
|
|
static ARegion *time_top_left_3dwindow(bScreen *screen)
|
|
{
|
|
ARegion *aret= NULL;
|
|
ScrArea *sa;
|
|
int min= 10000;
|
|
|
|
for(sa= screen->areabase.first; sa; sa= sa->next) {
|
|
if(sa->spacetype==SPACE_VIEW3D) {
|
|
ARegion *ar;
|
|
for(ar= sa->regionbase.first; ar; ar= ar->next) {
|
|
if(ar->regiontype==RGN_TYPE_WINDOW) {
|
|
if(ar->winrct.xmin - ar->winrct.ymin < min) {
|
|
aret= ar;
|
|
min= ar->winrct.xmin - ar->winrct.ymin;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return aret;
|
|
}
|
|
|
|
void ED_screen_animation_timer_update(bScreen *screen, int redraws)
|
|
{
|
|
if(screen && screen->animtimer) {
|
|
wmTimer *wt= screen->animtimer;
|
|
ScreenAnimData *sad= wt->customdata;
|
|
|
|
sad->redraws= redraws;
|
|
sad->ar= NULL;
|
|
if(redraws & TIME_REGION)
|
|
sad->ar= time_top_left_3dwindow(screen);
|
|
}
|
|
}
|
|
|
|
/* results in fully updated anim system */
|
|
void ED_update_for_newframe(const bContext *C, int mute)
|
|
{
|
|
bScreen *screen= CTX_wm_screen(C);
|
|
Scene *scene= CTX_data_scene(C);
|
|
|
|
#ifdef DURIAN_CAMERA_SWITCH
|
|
void *camera= scene_find_camera_switch(scene);
|
|
if(camera && scene->camera != camera) {
|
|
|
|
if(camera && scene->camera && (camera != scene->camera)) {
|
|
bScreen *sc;
|
|
/* are there cameras in the views that are not in the scene? */
|
|
for(sc= CTX_data_main(C)->screen.first; sc; sc= sc->id.next) {
|
|
ScrArea *sa= sc->areabase.first;
|
|
while(sa) {
|
|
SpaceLink *sl= sa->spacedata.first;
|
|
while(sl) {
|
|
if(sl->spacetype==SPACE_VIEW3D) {
|
|
View3D *v3d= (View3D*) sl;
|
|
if (v3d->scenelock) {
|
|
v3d->camera= camera;
|
|
}
|
|
}
|
|
sl= sl->next;
|
|
}
|
|
sa= sa->next;
|
|
}
|
|
}
|
|
}
|
|
|
|
scene->camera= camera;
|
|
}
|
|
#endif
|
|
|
|
//extern void audiostream_scrub(unsigned int frame); /* seqaudio.c */
|
|
|
|
/* this function applies the changes too */
|
|
/* XXX future: do all windows */
|
|
scene_update_for_newframe(scene, BKE_screen_visible_layers(screen, scene)); /* BKE_scene.h */
|
|
|
|
//if ( (CFRA>1) && (!mute) && (scene->r.audio.flag & AUDIO_SCRUB))
|
|
// audiostream_scrub( CFRA );
|
|
|
|
/* 3d window, preview */
|
|
//BIF_view3d_previewrender_signal(curarea, PR_DBASE|PR_DISPRECT);
|
|
|
|
/* all movie/sequence images */
|
|
//BIF_image_update_frame();
|
|
|
|
/* composite */
|
|
if(scene->use_nodes && scene->nodetree)
|
|
ntreeCompositTagAnimated(scene->nodetree);
|
|
|
|
/* update animated texture nodes */
|
|
{
|
|
Tex *tex;
|
|
for(tex= CTX_data_main(C)->tex.first; tex; tex= tex->id.next)
|
|
if( tex->use_nodes && tex->nodetree ) {
|
|
ntreeTexTagAnimated( tex->nodetree );
|
|
}
|
|
}
|
|
}
|
|
|
|
|