Operators: Join Areas

add split area to screen manager
- RMB+ALT down on area edge activates
- mouse move interactively to area that is to be removed
- LMB to confirm, ESC to cancel
TODO: 
- notifications for interactive drawing to mark area to remove

Some fixes
- uninitialized var warning.
- exit function of operators need to run before modal handler is removed if operator is used there.
- replaced MEM_mallocN with MEM_callocN to get rid of uninitialized mem for wmOperator.
- respect return value of wm_handler_operator_call() and break out of operator handling.
This commit is contained in:
2008-01-15 20:42:00 +00:00
parent 9e9ebfc12c
commit da11a3f38e
6 changed files with 275 additions and 4 deletions

View File

@@ -972,6 +972,7 @@ static int move_areas_invoke (bContext *C, wmOperator *op, wmEvent *event)
{
/* operator arguments and storage */
op->properties = NULL;
op->delta= 0;
op->veci.x= event->x;
op->veci.y= event->y;
@@ -1011,8 +1012,8 @@ static int move_areas_modal (bContext *C, wmOperator *op, wmEvent *event)
case LEFTMOUSE:
if(event->val==0) {
WM_event_remove_modal_handler(&C->window->handlers, op);
move_areas_exit(C, op);
WM_event_remove_modal_handler(&C->window->handlers, op);
}
break;
@@ -1155,6 +1156,7 @@ static int split_area_init (bContext *C, wmOperator *op)
static int split_area_invoke(bContext *C, wmOperator *op, wmEvent *event)
{
/* operator arguments and storage */
op->customdata= NULL;
op->delta= 0;
op->veci.x= event->x;
op->veci.y= event->y;
@@ -1255,8 +1257,8 @@ static int split_area_modal(bContext *C, wmOperator *op, wmEvent *event)
case RIGHTMOUSE:
if(event->val==0) { /* mouse up */
WM_event_remove_modal_handler(&C->window->handlers, op);
split_area_exit(C, op);
WM_event_remove_modal_handler(&C->window->handlers, op);
}
break;
@@ -1286,3 +1288,267 @@ void ED_SCR_OT_split_area(wmOperatorType *ot)
ot->poll= ED_operator_screenactive;
//ot->poll= ED_operator_screen_mainwinactive;
}
/* ************** join area operator ********************************************** */
/* operator state vars used:
op->veci mouse coord near edge
op->delta movement of edge
callbacks:
init() find edge based on op->veci,
test if the edge divides two areas,
store active and nonactive area,
exec() remove active window,
recalc size,
make nonactive window active,
add notifier for redraw.
invoke() handler gets called on Alt+RMB near edge
call init()
add handler
modal() accept modal events while doing it
call exec() with active window and nonactive window
call exit() and remove handler when LMB confirm
exit() cleanup, send notifier
*/
typedef struct sAreaJoinData
{
int dir;
ScrArea *up;
ScrArea *down;
ScrArea *left;
ScrArea *right;
ScrArea *sa1; /* first area to be considered */
ScrArea *sa2; /* second area to be considered */
ScrArea *scr; /* designed for removal */
} sAreaJoinData;
/* validate selection inside screen, set variables OK */
/* return 0: init failed */
static int join_areas_init (bContext *C, wmOperator *op)
{
ScrEdge *actedge= screen_find_active_scredge(C->screen, op->veci.x, op->veci.y);
ScrArea *sa = C->curarea;
ScrEdge *se;
sAreaJoinData* jd= NULL;
short val = 0;
if(actedge==NULL) return 0;
jd = (sAreaJoinData*)MEM_callocN(sizeof (sAreaJoinData), "op_join_areas");
jd->dir= scredge_is_horizontal(actedge) ? 'h':'v';
op->customdata = jd;
select_connected_scredge(C->screen, actedge);
jd->sa1 = screen_test_edge_area(C->screen, sa, actedge);
if(jd->sa1==0) return 0;
/* find directions with same edge */
jd->sa2= C->screen->areabase.first;
while(jd->sa2) {
if(jd->sa2 != jd->sa1) {
se= screen_findedge(C->screen, jd->sa2->v1, jd->sa2->v2);
if(actedge==se) jd->right= jd->sa2;
se= screen_findedge(C->screen, jd->sa2->v2, jd->sa2->v3);
if(actedge==se) jd->down= jd->sa2;
se= screen_findedge(C->screen, jd->sa2->v3, jd->sa2->v4);
if(actedge==se) jd->left= jd->sa2;
se= screen_findedge(C->screen, jd->sa2->v4, jd->sa2->v1);
if(actedge==se) jd->up= jd->sa2;
}
jd->sa2= jd->sa2->next;
}
if(jd->left) val++;
if(jd->up) val++;
if(jd->right) val++;
if(jd->down) val++;
if(val==0) return 0;
else if(val==1) {
if(jd->left) {
jd->right = jd->sa1;
jd->sa2 = jd->left;
jd->dir = 'h';
}
else if(jd->right) {
jd->left = jd->sa1;
jd->sa2 = jd->right;
jd->dir = 'h';
}
else if(jd->up) {
jd->down = jd->sa1;
jd->sa2= jd->up;
jd->dir = 'v';
}
else if(jd->down) {
jd->up = jd->sa1;
jd->sa2 = jd->down;
jd->dir = 'v';
}
}
/* initial set up screen area asigned for destroying */
jd->scr = jd->sa2;
return 1;
}
/* apply the join of the areas (space types) */
static int join_areas_exec(bContext *C, wmOperator *op)
{
sAreaJoinData *jd = (sAreaJoinData *)op->customdata;
if (!jd) return 0;
if(jd->sa2!=jd->scr) {
jd->sa1 = jd->sa2;
jd->sa2 = jd->scr;
}
if(jd->sa2==jd->left) {
jd->sa1->v1= jd->sa2->v1;
jd->sa1->v2= jd->sa2->v2;
screen_addedge(C->screen, jd->sa1->v2, jd->sa1->v3);
screen_addedge(C->screen, jd->sa1->v1, jd->sa1->v4);
}
else if(jd->sa2==jd->up) {
jd->sa1->v2= jd->sa2->v2;
jd->sa1->v3= jd->sa2->v3;
screen_addedge(C->screen, jd->sa1->v1, jd->sa1->v2);
screen_addedge(C->screen, jd->sa1->v3, jd->sa1->v4);
}
else if(jd->sa2==jd->right) {
jd->sa1->v3= jd->sa2->v3;
jd->sa1->v4= jd->sa2->v4;
screen_addedge(C->screen, jd->sa1->v2,jd-> sa1->v3);
screen_addedge(C->screen, jd->sa1->v1, jd->sa1->v4);
}
else if(jd->sa2==jd->down) {
jd->sa1->v1= jd->sa2->v1;
jd->sa1->v4= jd->sa2->v4;
screen_addedge(C->screen, jd->sa1->v1, jd->sa1->v2);
screen_addedge(C->screen, jd->sa1->v3, jd->sa1->v4);
}
if (C->curarea == jd->sa2) {
C->curarea = NULL;
}
screen_delarea(C->screen, jd->sa2);
jd->sa2 = NULL;
return 1;
}
/* interaction callback */
/* return 0 = stop evaluating for next handlers */
static int join_areas_invoke (bContext *C, wmOperator *op, wmEvent *event)
{
/* operator arguments and storage */
op->delta= 0;
op->veci.x= event->x;
op->veci.y= event->y;
op->customdata = NULL;
if(0==join_areas_init(C, op))
return 1;
/* add temp handler */
WM_event_add_modal_handler(&C->window->handlers, op);
return 0;
}
static int is_inside_area(ScrArea *ar, short x, short y)
{
int is_inside = 0;
if ( (ar->v1->vec.x < x) && (x < ar->v3->vec.x) ) {
if ( (y<ar->v3->vec.y) && (ar->v1->vec.y<y) ) {
is_inside = 1;
}
}
return is_inside;
}
/* finish operation */
static int join_areas_exit(bContext *C, wmOperator *op)
{
if (op->customdata) {
MEM_freeN(op->customdata);
op->customdata = NULL;
}
/* this makes sure aligned edges will result in aligned grabbing */
removedouble_scredges(C->screen);
removenotused_scredges(C->screen);
removenotused_scrverts(C->screen);
return 1;
}
/* modal callback while selecting area (space) that will be removed */
/* return 0 = stop evaluating for next handlers */
static int join_areas_modal (bContext *C, wmOperator *op, wmEvent *event)
{
/* execute the events */
switch(event->type) {
case MOUSEMOVE:
{
sAreaJoinData *jd = (sAreaJoinData *)op->customdata;
ScrArea *sa = screen_areahascursor(C->screen, event->x, event->y);
if (sa && sa != jd->sa2) {
if (sa == jd->sa1) {
jd->scr = jd->sa1;
jd->sa1 = jd->sa2;
jd->sa2 = jd->scr;
printf("Changed area\n");
}
}
break;
}
case LEFTMOUSE:
if(event->val==0) {
join_areas_exec(C, op);
WM_event_add_notifier(C->wm, C->window, 0, WM_NOTE_SCREEN_CHANGED, 0);
join_areas_exit(C, op);
WM_event_remove_modal_handler(&C->window->handlers, op);
}
break;
case ESCKEY:
op->delta= 0;
join_areas_exit(C, op);
WM_event_remove_modal_handler(&C->window->handlers, op);
break;
}
return 1;
}
/* Operator for joining two areas (space types) */
void ED_SCR_OT_join_areas(wmOperatorType *ot)
{
/* identifiers */
ot->name= "Join area";
ot->idname= "ED_SCR_OT_join_areas";
/* api callbacks */
ot->init= join_areas_init;
ot->invoke= join_areas_invoke;
ot->modal= join_areas_modal;
ot->exec= join_areas_exec;
ot->exit= join_areas_exit;
ot->poll= ED_operator_screen_mainwinactive;
}

View File

@@ -41,7 +41,7 @@ int area_cursor_test(bContext *C, wmOperator *op, wmEvent *event);
void ED_SCR_OT_move_areas(wmOperatorType *ot);
void ED_SCR_OT_split_area(wmOperatorType *ot);
void ED_SCR_OT_join_areas(wmOperatorType *ot);
#endif /* ED_SCREEN_INTERN_H */

View File

@@ -87,6 +87,7 @@ void ED_operatortypes_screen(void)
ADD_OPTYPE( ED_SCR_OT_move_areas );
ADD_OPTYPE( ED_SCR_OT_cursor_type );
ADD_OPTYPE( ED_SCR_OT_split_area );
ADD_OPTYPE( ED_SCR_OT_join_areas );
WM_operatortypelist_append(&local_ops);
}
@@ -97,6 +98,7 @@ void ed_screen_keymap(wmWindowManager *wm)
WM_keymap_verify_item(&wm->screenkeymap, "ED_SCR_OT_cursor_type", MOUSEMOVE, 0, 0, 0);
WM_keymap_verify_item(&wm->screenkeymap, "ED_SCR_OT_move_areas", LEFTMOUSE, KM_PRESS, 0, 0);
WM_keymap_verify_item(&wm->screenkeymap, "ED_SCR_OT_split_area", RIGHTMOUSE, KM_PRESS, 0, 0);
WM_keymap_verify_item(&wm->screenkeymap, "ED_SCR_OT_join_areas", RIGHTMOUSE, KM_PRESS, KM_ALT, 0);
}

View File

@@ -53,7 +53,7 @@
/* called on event handling by event_system.c */
void wm_operator_register(wmWindowManager *wm, wmOperator *op)
{
wmOperator *opc= MEM_mallocN(sizeof(wmOperator), "operator registry");
wmOperator *opc= MEM_callocN(sizeof(wmOperator), "operator registry");
int tot;
*opc= *op;

View File

@@ -306,6 +306,8 @@ static int wm_handlers_do(bContext *C, wmEvent *event, ListBase *handlers)
else {
/* modal, swallows all */
action= wm_handler_operator_call(C, handler, event);
if(action==WM_HANDLER_BREAK)
break;
}
/* modal+blocking handler */

View File

@@ -165,6 +165,7 @@ IDProperty *op_get_property(wmOperator *op, char *name)
void op_init_property(wmOperator *op)
{
IDPropertyTemplate val;
val.i = 0; /* silence MSVC warning about uninitialized var when debugging */
op->properties= IDP_New(IDP_GROUP, val, "property");
}