Blender V2.61 - r43446

interface_panel.c

Go to the documentation of this file.
00001 /*
00002  * ***** BEGIN GPL LICENSE BLOCK *****
00003  *
00004  * This program is free software; you can redistribute it and/or
00005  * modify it under the terms of the GNU General Public License
00006  * as published by the Free Software Foundation; either version 2
00007  * of the License, or (at your option) any later version.
00008  *
00009  * This program is distributed in the hope that it will be useful,
00010  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012  * GNU General Public License for more details.
00013  *
00014  * You should have received a copy of the GNU General Public License
00015  * along with this program; if not, write to the Free Software Foundation,
00016  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
00017  *
00018  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
00019  * All rights reserved.
00020  *
00021  * Contributor(s): Blender Foundation, 2003-2009 full recode.
00022  *
00023  * ***** END GPL LICENSE BLOCK *****
00024  */
00025 
00031 /* a full doc with API notes can be found in bf-blender/trunk/blender/doc/guides/interface_API.txt */
00032  
00033 #include <math.h>
00034 #include <stdlib.h>
00035 #include <string.h>
00036 #include <ctype.h>
00037 
00038 #include "MEM_guardedalloc.h"
00039 
00040 #include "PIL_time.h"
00041 
00042 #include "BLI_blenlib.h"
00043 #include "BLI_math.h"
00044 #include "BLI_utildefines.h"
00045 
00046 #include "BLF_translation.h"
00047 
00048 #include "DNA_userdef_types.h"
00049 
00050 #include "BKE_context.h"
00051 #include "BKE_screen.h"
00052 
00053 #include "BIF_gl.h"
00054 #include "BIF_glutil.h"
00055 
00056 #include "WM_api.h"
00057 #include "WM_types.h"
00058 
00059 #include "ED_screen.h"
00060 
00061 #include "UI_interface.h"
00062 #include "UI_resources.h"
00063 
00064 #include "interface_intern.h"
00065 
00066 /*********************** defines and structs ************************/
00067 
00068 #define ANIMATION_TIME      0.30
00069 #define ANIMATION_INTERVAL  0.02
00070 
00071 #define PNL_LAST_ADDED      1
00072 #define PNL_ACTIVE          2
00073 #define PNL_WAS_ACTIVE      4
00074 #define PNL_ANIM_ALIGN      8
00075 #define PNL_NEW_ADDED       16
00076 #define PNL_FIRST           32
00077 
00078 typedef enum uiHandlePanelState {
00079     PANEL_STATE_DRAG,
00080     PANEL_STATE_DRAG_SCALE,
00081     PANEL_STATE_WAIT_UNTAB,
00082     PANEL_STATE_ANIMATION,
00083     PANEL_STATE_EXIT
00084 } uiHandlePanelState;
00085 
00086 typedef struct uiHandlePanelData {
00087     uiHandlePanelState state;
00088 
00089     /* animation */
00090     wmTimer *animtimer;
00091     double starttime;
00092 
00093     /* dragging */
00094     int startx, starty;
00095     int startofsx, startofsy;
00096     int startsizex, startsizey;
00097 } uiHandlePanelData;
00098 
00099 static void panel_activate_state(const bContext *C, Panel *pa, uiHandlePanelState state);
00100 
00101 /*********************** space specific code ************************/
00102 /* temporary code to remove all sbuts stuff from panel code         */
00103 
00104 static int panel_aligned(ScrArea *sa, ARegion *ar)
00105 {
00106     if(sa->spacetype==SPACE_BUTS && ar->regiontype == RGN_TYPE_WINDOW) {
00107         SpaceButs *sbuts= sa->spacedata.first;
00108         return sbuts->align;
00109     }
00110     else if(sa->spacetype==SPACE_USERPREF && ar->regiontype == RGN_TYPE_WINDOW)
00111         return BUT_VERTICAL;
00112     else if(sa->spacetype==SPACE_FILE && ar->regiontype == RGN_TYPE_CHANNELS)
00113         return BUT_VERTICAL;
00114     else if(sa->spacetype==SPACE_IMAGE && ar->regiontype == RGN_TYPE_PREVIEW)
00115         return BUT_VERTICAL; 
00116     else if(ELEM3(ar->regiontype, RGN_TYPE_UI, RGN_TYPE_TOOLS, RGN_TYPE_TOOL_PROPS))
00117         return BUT_VERTICAL;
00118     
00119     return 0;
00120 }
00121 
00122 static int panels_re_align(ScrArea *sa, ARegion *ar, Panel **r_pa)
00123 {
00124     Panel *pa;
00125     int active= 0;
00126 
00127     *r_pa= NULL;
00128 
00129     if(sa->spacetype==SPACE_BUTS && ar->regiontype == RGN_TYPE_WINDOW) {
00130         SpaceButs *sbuts= sa->spacedata.first;
00131 
00132         if(sbuts->align)
00133             if(sbuts->re_align || sbuts->mainbo!=sbuts->mainb)
00134                 return 1;
00135     }
00136     else if(ar->regiontype==RGN_TYPE_UI)
00137         return 1;
00138     else if(sa->spacetype==SPACE_IMAGE && ar->regiontype == RGN_TYPE_PREVIEW)
00139         return 1;
00140     else if(sa->spacetype==SPACE_FILE && ar->regiontype == RGN_TYPE_CHANNELS)
00141         return 1;
00142 
00143     /* in case panel is added or disappears */
00144     for(pa=ar->panels.first; pa; pa=pa->next) {
00145         if((pa->runtime_flag & PNL_WAS_ACTIVE) && !(pa->runtime_flag & PNL_ACTIVE))
00146             return 1;
00147         if(!(pa->runtime_flag & PNL_WAS_ACTIVE) && (pa->runtime_flag & PNL_ACTIVE))
00148             return 1;
00149         if(pa->activedata)
00150             active= 1;
00151     }
00152 
00153     /* in case we need to do an animation (size changes) */
00154     for(pa=ar->panels.first; pa; pa=pa->next) {
00155         if(pa->runtime_flag & PNL_ANIM_ALIGN) {
00156             if(!active)
00157                 *r_pa= pa;
00158             return 1;
00159         }
00160     }
00161     
00162     return 0;
00163 }
00164 
00165 /****************************** panels ******************************/
00166 
00167 static void ui_panel_copy_offset(Panel *pa, Panel *papar)
00168 {
00169     /* with respect to sizes... papar is parent */
00170 
00171     pa->ofsx= papar->ofsx;
00172     pa->ofsy= papar->ofsy + papar->sizey-pa->sizey;
00173 }
00174 
00175 Panel *uiBeginPanel(ScrArea *sa, ARegion *ar, uiBlock *block, PanelType *pt, int *open)
00176 {
00177     Panel *pa, *patab, *palast, *panext;
00178     char *drawname= pt->label;
00179     char *idname= pt->idname;
00180     char *tabname= pt->idname;
00181     char *hookname= NULL;
00182     int newpanel;
00183     int align= panel_aligned(sa, ar);
00184     
00185     /* check if Panel exists, then use that one */
00186     for(pa=ar->panels.first; pa; pa=pa->next)
00187         if(strncmp(pa->panelname, idname, UI_MAX_NAME_STR)==0)
00188             if(strncmp(pa->tabname, tabname, UI_MAX_NAME_STR)==0)
00189                 break;
00190     
00191     newpanel= (pa == NULL);
00192 
00193     if(!newpanel) {
00194         pa->type= pt;
00195     }
00196     else {
00197         /* new panel */
00198         pa= MEM_callocN(sizeof(Panel), "new panel");
00199         pa->type= pt;
00200         BLI_strncpy(pa->panelname, idname, UI_MAX_NAME_STR);
00201         BLI_strncpy(pa->tabname, tabname, UI_MAX_NAME_STR);
00202 
00203         if(pt->flag & PNL_DEFAULT_CLOSED) {
00204             if(align == BUT_VERTICAL)
00205                 pa->flag |= PNL_CLOSEDY;
00206             else
00207                 pa->flag |= PNL_CLOSEDX;
00208         }
00209     
00210         pa->ofsx= 0;
00211         pa->ofsy= 0;
00212         pa->sizex= 0;
00213         pa->sizey= 0;
00214         pa->runtime_flag |= PNL_NEW_ADDED;
00215 
00216         BLI_addtail(&ar->panels, pa);
00217         
00218         /* make new Panel tabbed? */
00219         if(hookname) {
00220             for(patab= ar->panels.first; patab; patab= patab->next) {
00221                 if((patab->runtime_flag & PNL_ACTIVE) && patab->paneltab==NULL) {
00222                     if(strncmp(hookname, patab->panelname, UI_MAX_NAME_STR)==0) {
00223                         if(strncmp(tabname, patab->tabname, UI_MAX_NAME_STR)==0) {
00224                             pa->paneltab= patab;
00225                             ui_panel_copy_offset(pa, patab);
00226                             break;
00227                         }
00228                     }
00229                 }
00230             } 
00231         }
00232     }
00233 
00234     BLI_strncpy(pa->drawname, drawname, UI_MAX_NAME_STR);
00235 
00236     /* if a new panel is added, we insert it right after the panel
00237      * that was last added. this way new panels are inserted in the
00238      * right place between versions */
00239     for(palast=ar->panels.first; palast; palast=palast->next)
00240         if(palast->runtime_flag & PNL_LAST_ADDED)
00241             break;
00242     
00243     if(newpanel) {
00244         pa->sortorder= (palast)? palast->sortorder+1: 0;
00245 
00246         for(panext=ar->panels.first; panext; panext=panext->next)
00247             if(panext != pa && panext->sortorder >= pa->sortorder)
00248                 panext->sortorder++;
00249     }
00250 
00251     if(palast)
00252         palast->runtime_flag &= ~PNL_LAST_ADDED;
00253 
00254     /* assign to block */
00255     block->panel= pa;
00256     pa->runtime_flag |= PNL_ACTIVE|PNL_LAST_ADDED;
00257 
00258     *open= 0;
00259 
00260     if(pa->paneltab) return pa;
00261     if(pa->flag & PNL_CLOSED) return pa;
00262 
00263     *open= 1;
00264     
00265     return pa;
00266 }
00267 
00268 void uiEndPanel(uiBlock *block, int width, int height)
00269 {
00270     Panel *pa= block->panel;
00271 
00272     if(pa->runtime_flag & PNL_NEW_ADDED) {
00273         pa->runtime_flag &= ~PNL_NEW_ADDED;
00274         pa->sizex= width;
00275         pa->sizey= height;
00276     }
00277     else {
00278         /* check if we need to do an animation */
00279         if(!ELEM(width, 0, pa->sizex) || !ELEM(height, 0, pa->sizey)) {
00280             pa->runtime_flag |= PNL_ANIM_ALIGN;
00281             if(height != 0)
00282                 pa->ofsy += pa->sizey-height;
00283         }
00284 
00285         /* update width/height if non-zero */
00286         if(width != 0)
00287             pa->sizex= width;
00288         if(height != 0)
00289             pa->sizey= height;
00290     }
00291 }
00292 
00293 static void ui_offset_panel_block(uiBlock *block)
00294 {
00295     uiStyle *style= UI_GetStyle();
00296     uiBut *but;
00297     int ofsy;
00298 
00299     /* compute bounds and offset */
00300     ui_bounds_block(block);
00301 
00302     ofsy= block->panel->sizey - style->panelspace;
00303 
00304     for(but= block->buttons.first; but; but=but->next) {
00305         but->y1 += ofsy;
00306         but->y2 += ofsy;
00307     }
00308 
00309     block->maxx= block->panel->sizex;
00310     block->maxy= block->panel->sizey;
00311     block->minx= block->miny= 0.0;
00312 }
00313 
00314 /**************************** drawing *******************************/
00315 
00316 /* extern used by previewrender */
00317 #if 0 /*UNUSED 2.5*/
00318 static void uiPanelPush(uiBlock *block)
00319 {
00320     glPushMatrix(); 
00321 
00322     if(block->panel)
00323         glTranslatef((float)block->panel->ofsx, (float)block->panel->ofsy, 0.0);
00324 }
00325 
00326 static void uiPanelPop(uiBlock *UNUSED(block))
00327 {
00328     glPopMatrix();
00329 }
00330 #endif
00331 
00332 /* triangle 'icon' for panel header */
00333 void UI_DrawTriIcon(float x, float y, char dir)
00334 {
00335     if(dir=='h') {
00336         ui_draw_anti_tria( x-3, y-5, x-3, y+5, x+7,y );
00337     }
00338     else if(dir=='t') {
00339         ui_draw_anti_tria( x-5, y-7, x+5, y-7, x, y+3); 
00340     }
00341     else { /* 'v' = vertical, down */
00342         ui_draw_anti_tria( x-5, y+3, x+5, y+3, x, y-7); 
00343     }
00344 }
00345 
00346 /* triangle 'icon' inside rect */
00347 static void ui_draw_tria_rect(rctf *rect, char dir)
00348 {
00349     if(dir=='h') {
00350         float half= 0.5f*(rect->ymax - rect->ymin);
00351         ui_draw_anti_tria(rect->xmin, rect->ymin, rect->xmin, rect->ymax, rect->xmax, rect->ymin+half);
00352     }
00353     else {
00354         float half= 0.5f*(rect->xmax - rect->xmin);
00355         ui_draw_anti_tria(rect->xmin, rect->ymax, rect->xmax, rect->ymax, rect->xmin+half, rect->ymin);
00356     }
00357 }
00358 
00359 static void ui_draw_anti_x(float x1, float y1, float x2, float y2)
00360 {
00361 
00362     /* set antialias line */
00363     glEnable(GL_LINE_SMOOTH);
00364     glEnable(GL_BLEND);
00365 
00366     glLineWidth(2.0);
00367     
00368     fdrawline(x1, y1, x2, y2);
00369     fdrawline(x1, y2, x2, y1);
00370     
00371     glLineWidth(1.0);
00372     
00373     glDisable(GL_LINE_SMOOTH);
00374     glDisable(GL_BLEND);
00375     
00376 }
00377 
00378 /* x 'icon' for panel header */
00379 static void ui_draw_x_icon(float x, float y)
00380 {
00381 
00382     ui_draw_anti_x(x, y, x+9.375f, y+9.375f);
00383 
00384 }
00385 
00386 #define PNL_ICON    UI_UNIT_X  /* could be UI_UNIT_Y too */
00387 
00388 static void ui_draw_panel_scalewidget(rcti *rect)
00389 {
00390     float xmin, xmax, dx;
00391     float ymin, ymax, dy;
00392     
00393     xmin= rect->xmax-PNL_HEADER+2;
00394     xmax= rect->xmax-3;
00395     ymin= rect->ymin+3;
00396     ymax= rect->ymin+PNL_HEADER-2;
00397         
00398     dx= 0.5f*(xmax-xmin);
00399     dy= 0.5f*(ymax-ymin);
00400     
00401     glEnable(GL_BLEND);
00402     glColor4ub(255, 255, 255, 50);
00403     fdrawline(xmin, ymin, xmax, ymax);
00404     fdrawline(xmin+dx, ymin, xmax, ymax-dy);
00405     
00406     glColor4ub(0, 0, 0, 50);
00407     fdrawline(xmin, ymin+1, xmax, ymax+1);
00408     fdrawline(xmin+dx, ymin+1, xmax, ymax-dy+1);
00409     glDisable(GL_BLEND);
00410 }
00411 
00412 static void ui_draw_panel_dragwidget(rctf *rect)
00413 {
00414     float xmin, xmax, dx;
00415     float ymin, ymax, dy;
00416     
00417     xmin= rect->xmin;
00418     xmax= rect->xmax;
00419     ymin= rect->ymin;
00420     ymax= rect->ymax;
00421     
00422     dx= 0.333f*(xmax-xmin);
00423     dy= 0.333f*(ymax-ymin);
00424     
00425     glEnable(GL_BLEND);
00426     glColor4ub(255, 255, 255, 50);
00427     fdrawline(xmin, ymax, xmax, ymin);
00428     fdrawline(xmin+dx, ymax, xmax, ymin+dy);
00429     fdrawline(xmin+2*dx, ymax, xmax, ymin+2*dy);
00430     
00431     glColor4ub(0, 0, 0, 50);
00432     fdrawline(xmin, ymax+1, xmax, ymin+1);
00433     fdrawline(xmin+dx, ymax+1, xmax, ymin+dy+1);
00434     fdrawline(xmin+2*dx, ymax+1, xmax, ymin+2*dy+1);
00435     glDisable(GL_BLEND);
00436 }
00437 
00438 
00439 static void ui_draw_aligned_panel_header(uiStyle *style, uiBlock *block, rcti *rect, char dir)
00440 {
00441     Panel *panel= block->panel;
00442     rcti hrect;
00443     int  pnl_icons;
00444     const char *activename= IFACE_(panel->drawname[0] ? panel->drawname : panel->panelname);
00445 
00446     /* + 0.001f to avoid flirting with float inaccuracy */
00447     if(panel->control & UI_PNL_CLOSE) pnl_icons=(panel->labelofs+2*PNL_ICON+5)/block->aspect + 0.001f;
00448     else pnl_icons= (panel->labelofs+PNL_ICON+5)/block->aspect + 0.001f;
00449     
00450     /* active tab */
00451     /* draw text label */
00452     UI_ThemeColor(TH_TITLE);
00453     
00454     hrect= *rect;
00455     if(dir == 'h') {
00456         hrect.xmin= rect->xmin+pnl_icons;
00457         hrect.ymin += 2.0f/block->aspect;
00458         uiStyleFontDraw(&style->paneltitle, &hrect, activename);
00459     }
00460     else {
00461         /* ignore 'pnl_icons', otherwise the text gets offset horizontally 
00462          * + 0.001f to avoid flirting with float inaccuracy
00463          */
00464         hrect.xmin= rect->xmin + (PNL_ICON+5)/block->aspect + 0.001f;
00465         uiStyleFontDrawRotated(&style->paneltitle, &hrect, activename);
00466     }
00467 }
00468 
00469 static void rectf_scale(rctf *rect, float scale)
00470 {
00471     float centx= 0.5f*(rect->xmin+rect->xmax);
00472     float centy= 0.5f*(rect->ymin+rect->ymax);
00473     float sizex= 0.5f*scale*(rect->xmax - rect->xmin);
00474     float sizey= 0.5f*scale*(rect->ymax - rect->ymin);
00475     
00476     rect->xmin= centx - sizex;
00477     rect->xmax= centx + sizex;
00478     rect->ymin= centy - sizey;
00479     rect->ymax= centy + sizey;
00480 }
00481 
00482 /* panel integrated in buttonswindow, tool/property lists etc */
00483 void ui_draw_aligned_panel(uiStyle *style, uiBlock *block, rcti *rect)
00484 {
00485     bTheme *btheme= UI_GetTheme();
00486     Panel *panel= block->panel;
00487     rcti headrect;
00488     rctf itemrect;
00489     int ofsx;
00490     
00491     if(panel->paneltab) return;
00492     if(panel->type && (panel->type->flag & PNL_NO_HEADER)) return;
00493 
00494     /* calculate header rect */
00495     /* + 0.001f to prevent flicker due to float inaccuracy */
00496     headrect= *rect;
00497     headrect.ymin= headrect.ymax;
00498     headrect.ymax= headrect.ymin + floor(PNL_HEADER/block->aspect + 0.001f);
00499     
00500     {
00501         float minx= rect->xmin;
00502         float maxx= rect->xmax;
00503         float y= headrect.ymax;
00504 
00505         glEnable(GL_BLEND);
00506 
00507         if(btheme->tui.panel.show_header) {
00508             /* draw with background color */
00509             glEnable(GL_BLEND);
00510             glColor4ubv((unsigned char*)btheme->tui.panel.header);
00511             glRectf(minx, headrect.ymin+1, maxx, y);
00512 
00513             fdrawline(minx, y, maxx, y);
00514             fdrawline(minx, y, maxx, y);
00515         }
00516         else if(!(panel->runtime_flag & PNL_FIRST)) {
00517             /* draw embossed separator */
00518             minx += 5.0f/block->aspect;
00519             maxx -= 5.0f/block->aspect;
00520             
00521             glColor4f(0.0f, 0.0f, 0.0f, 0.5f);
00522             fdrawline(minx, y, maxx, y);
00523             glColor4f(1.0f, 1.0f, 1.0f, 0.25f);
00524             fdrawline(minx, y-1, maxx, y-1);
00525             glDisable(GL_BLEND);
00526         }
00527 
00528         glDisable(GL_BLEND);
00529     }
00530     
00531     /* horizontal title */
00532     if(!(panel->flag & PNL_CLOSEDX)) {
00533         ui_draw_aligned_panel_header(style, block, &headrect, 'h');
00534         
00535         /* itemrect smaller */  
00536         itemrect.xmax= headrect.xmax - 5.0f/block->aspect;
00537         itemrect.xmin= itemrect.xmax - (headrect.ymax-headrect.ymin);
00538         itemrect.ymin= headrect.ymin;
00539         itemrect.ymax= headrect.ymax;
00540 
00541         rectf_scale(&itemrect, 0.7f);
00542         ui_draw_panel_dragwidget(&itemrect);
00543     }
00544     
00545     /* if the panel is minimized vertically:
00546         * (------)
00547         */
00548     if(panel->flag & PNL_CLOSEDY) {
00549         
00550     }
00551     else if(panel->flag & PNL_CLOSEDX) {
00552         /* draw vertical title */
00553         ui_draw_aligned_panel_header(style, block, &headrect, 'v');
00554     }
00555     /* an open panel */
00556     else {
00557         
00558         /* in some occasions, draw a border */
00559         if(panel->flag & PNL_SELECT) {
00560             if(panel->control & UI_PNL_SOLID) uiSetRoundBox(UI_CNR_ALL);
00561             else uiSetRoundBox(UI_CNR_NONE);
00562             
00563             UI_ThemeColorShade(TH_BACK, -120);
00564             uiRoundRect(0.5f + rect->xmin, 0.5f + rect->ymin, 0.5f + rect->xmax, 0.5f + headrect.ymax+1, 8);
00565         }
00566         
00567         if(panel->control & UI_PNL_SCALE)
00568             ui_draw_panel_scalewidget(rect);
00569     }
00570     
00571     /* draw optional close icon */
00572     
00573     ofsx= 6;
00574     if(panel->control & UI_PNL_CLOSE) {
00575         
00576         UI_ThemeColor(TH_TEXT);
00577         ui_draw_x_icon(rect->xmin+2+ofsx, rect->ymax+2);
00578         ofsx= 22;
00579     }
00580     
00581     /* draw collapse icon */
00582     UI_ThemeColor(TH_TEXT);
00583     
00584     /* itemrect smaller */  
00585     itemrect.xmin= headrect.xmin + 5.0f/block->aspect;
00586     itemrect.xmax= itemrect.xmin + (headrect.ymax-headrect.ymin);
00587     itemrect.ymin= headrect.ymin;
00588     itemrect.ymax= headrect.ymax;
00589     
00590     rectf_scale(&itemrect, 0.35f);
00591     
00592     if(panel->flag & PNL_CLOSEDY)
00593         ui_draw_tria_rect(&itemrect, 'h');
00594     else if(panel->flag & PNL_CLOSEDX)
00595         ui_draw_tria_rect(&itemrect, 'h');
00596     else
00597         ui_draw_tria_rect(&itemrect, 'v');
00598 
00599     (void)ofsx;
00600 }
00601 
00602 /************************** panel alignment *************************/
00603 
00604 static int get_panel_header(Panel *pa)
00605 {
00606     if(pa->type && (pa->type->flag & PNL_NO_HEADER))
00607         return 0;
00608 
00609     return PNL_HEADER;
00610 }
00611 
00612 static int get_panel_size_y(Panel *pa)
00613 {
00614     if(pa->type && (pa->type->flag & PNL_NO_HEADER))
00615         return pa->sizey;
00616 
00617     return PNL_HEADER + pa->sizey;
00618 }
00619 
00620 /* this function is needed because uiBlock and Panel itself dont
00621 change sizey or location when closed */
00622 static int get_panel_real_ofsy(Panel *pa)
00623 {
00624     if(pa->flag & PNL_CLOSEDY) return pa->ofsy+pa->sizey;
00625     else if(pa->paneltab && (pa->paneltab->flag & PNL_CLOSEDY)) return pa->ofsy+pa->sizey;
00626     else if(pa->paneltab) return pa->paneltab->ofsy;
00627     else return pa->ofsy;
00628 }
00629 
00630 static int get_panel_real_ofsx(Panel *pa)
00631 {
00632     if(pa->flag & PNL_CLOSEDX) return pa->ofsx+get_panel_header(pa);
00633     else if(pa->paneltab && (pa->paneltab->flag & PNL_CLOSEDX)) return pa->ofsx+get_panel_header(pa);
00634     else return pa->ofsx+pa->sizex;
00635 }
00636 
00637 typedef struct PanelSort {
00638     Panel *pa, *orig;
00639 } PanelSort;
00640 
00641 /* note about sorting;
00642    the sortorder has a lower value for new panels being added.
00643    however, that only works to insert a single panel, when more new panels get
00644    added the coordinates of existing panels and the previously stored to-be-insterted
00645    panels do not match for sorting */
00646 
00647 static int find_leftmost_panel(const void *a1, const void *a2)
00648 {
00649     const PanelSort *ps1=a1, *ps2=a2;
00650     
00651     if(ps1->pa->ofsx > ps2->pa->ofsx) return 1;
00652     else if(ps1->pa->ofsx < ps2->pa->ofsx) return -1;
00653     else if(ps1->pa->sortorder > ps2->pa->sortorder) return 1;
00654     else if(ps1->pa->sortorder < ps2->pa->sortorder) return -1;
00655 
00656     return 0;
00657 }
00658 
00659 
00660 static int find_highest_panel(const void *a1, const void *a2)
00661 {
00662     const PanelSort *ps1=a1, *ps2=a2;
00663     
00664     /* stick uppermost header-less panels to the top of the region -
00665      * prevent them from being sorted */
00666     if (ps1->pa->sortorder < ps2->pa->sortorder && ps1->pa->type->flag & PNL_NO_HEADER) return -1;
00667     
00668     if(ps1->pa->ofsy+ps1->pa->sizey < ps2->pa->ofsy+ps2->pa->sizey) return 1;
00669     else if(ps1->pa->ofsy+ps1->pa->sizey > ps2->pa->ofsy+ps2->pa->sizey) return -1;
00670     else if(ps1->pa->sortorder > ps2->pa->sortorder) return 1;
00671     else if(ps1->pa->sortorder < ps2->pa->sortorder) return -1;
00672     
00673     return 0;
00674 }
00675 
00676 static int compare_panel(const void *a1, const void *a2)
00677 {
00678     const PanelSort *ps1=a1, *ps2=a2;
00679     
00680     if(ps1->pa->sortorder > ps2->pa->sortorder) return 1;
00681     else if(ps1->pa->sortorder < ps2->pa->sortorder) return -1;
00682     
00683     return 0;
00684 }
00685 
00686 /* this doesnt draw */
00687 /* returns 1 when it did something */
00688 static int uiAlignPanelStep(ScrArea *sa, ARegion *ar, float fac, int drag)
00689 {
00690     Panel *pa;
00691     PanelSort *ps, *panelsort, *psnext;
00692     int a, tot=0, done;
00693     int align= panel_aligned(sa, ar);
00694     
00695     /* count active, not tabbed panels */
00696     for(pa= ar->panels.first; pa; pa= pa->next)
00697         if((pa->runtime_flag & PNL_ACTIVE) && pa->paneltab==NULL)
00698             tot++;
00699 
00700     if(tot==0) return 0;
00701 
00702     /* extra; change close direction? */
00703     for(pa= ar->panels.first; pa; pa= pa->next) {
00704         if((pa->runtime_flag & PNL_ACTIVE) && pa->paneltab==NULL) {
00705             if((pa->flag & PNL_CLOSEDX) && (align==BUT_VERTICAL))
00706                 pa->flag ^= PNL_CLOSED;
00707             else if((pa->flag & PNL_CLOSEDY) && (align==BUT_HORIZONTAL))
00708                 pa->flag ^= PNL_CLOSED;
00709         }
00710     }
00711 
00712     /* sort panels */
00713     panelsort= MEM_callocN(tot*sizeof(PanelSort), "panelsort");
00714     
00715     ps= panelsort;
00716     for(pa= ar->panels.first; pa; pa= pa->next) {
00717         if((pa->runtime_flag & PNL_ACTIVE) && pa->paneltab==NULL) {
00718             ps->pa= MEM_dupallocN(pa);
00719             ps->orig= pa;
00720             ps++;
00721         }
00722     }
00723     
00724     if(drag) {
00725         /* while we are dragging, we sort on location and update sortorder */
00726         if(align==BUT_VERTICAL) 
00727             qsort(panelsort, tot, sizeof(PanelSort), find_highest_panel);
00728         else
00729             qsort(panelsort, tot, sizeof(PanelSort), find_leftmost_panel);
00730 
00731         for(ps=panelsort, a=0; a<tot; a++, ps++)
00732             ps->orig->sortorder= a;
00733     }
00734     else
00735         /* otherwise use sortorder */
00736         qsort(panelsort, tot, sizeof(PanelSort), compare_panel);
00737     
00738     /* no smart other default start loc! this keeps switching f5/f6/etc compatible */
00739     ps= panelsort;
00740     ps->pa->ofsx= 0;
00741     ps->pa->ofsy= -get_panel_size_y(ps->pa);
00742 
00743     for(a=0; a<tot-1; a++, ps++) {
00744         psnext= ps+1;
00745     
00746         if(align==BUT_VERTICAL) {
00747             psnext->pa->ofsx= ps->pa->ofsx;
00748             psnext->pa->ofsy= get_panel_real_ofsy(ps->pa) - get_panel_size_y(psnext->pa);
00749         }
00750         else {
00751             psnext->pa->ofsx= get_panel_real_ofsx(ps->pa);
00752             psnext->pa->ofsy= ps->pa->ofsy + get_panel_size_y(ps->pa) - get_panel_size_y(psnext->pa);
00753         }
00754     }
00755     
00756     /* we interpolate */
00757     done= 0;
00758     ps= panelsort;
00759     for(a=0; a<tot; a++, ps++) {
00760         if((ps->pa->flag & PNL_SELECT)==0) {
00761             if((ps->orig->ofsx != ps->pa->ofsx) || (ps->orig->ofsy != ps->pa->ofsy)) {
00762                 ps->orig->ofsx= floorf(0.5f + fac*(float)ps->pa->ofsx + (1.0f-fac)*(float)ps->orig->ofsx);
00763                 ps->orig->ofsy= floorf(0.5f + fac*(float)ps->pa->ofsy + (1.0f-fac)*(float)ps->orig->ofsy);
00764                 done= 1;
00765             }
00766         }
00767     }
00768 
00769     /* copy locations to tabs */
00770     for(pa= ar->panels.first; pa; pa= pa->next)
00771         if(pa->paneltab && (pa->runtime_flag & PNL_ACTIVE))
00772             ui_panel_copy_offset(pa, pa->paneltab);
00773 
00774     /* free panelsort array */
00775     for(ps= panelsort, a=0; a<tot; a++, ps++)
00776         MEM_freeN(ps->pa);
00777     MEM_freeN(panelsort);
00778     
00779     return done;
00780 }
00781 
00782 static void ui_panels_size(ScrArea *sa, ARegion *ar, int *x, int *y)
00783 {
00784     Panel *pa;
00785     int align= panel_aligned(sa, ar);
00786     int sizex = UI_PANEL_WIDTH;
00787     int sizey = UI_PANEL_WIDTH;
00788 
00789     /* compute size taken up by panels, for setting in view2d */
00790     for(pa= ar->panels.first; pa; pa= pa->next) {
00791         if(pa->runtime_flag & PNL_ACTIVE) {
00792             int pa_sizex, pa_sizey;
00793 
00794             if(align==BUT_VERTICAL) {
00795                 pa_sizex= pa->ofsx + pa->sizex;
00796                 pa_sizey= get_panel_real_ofsy(pa);
00797             }
00798             else {
00799                 pa_sizex= get_panel_real_ofsx(pa) + pa->sizex;
00800                 pa_sizey= pa->ofsy + get_panel_size_y(pa);
00801             }
00802 
00803             sizex= MAX2(sizex, pa_sizex);
00804             sizey= MIN2(sizey, pa_sizey);
00805         }
00806     }
00807 
00808     *x= sizex;
00809     *y= sizey;
00810 }
00811 
00812 static void ui_do_animate(const bContext *C, Panel *panel)
00813 {
00814     uiHandlePanelData *data= panel->activedata;
00815     ScrArea *sa= CTX_wm_area(C);
00816     ARegion *ar= CTX_wm_region(C);
00817     float fac;
00818 
00819     fac= (PIL_check_seconds_timer()-data->starttime)/ANIMATION_TIME;
00820     fac= sqrt(fac);
00821     fac= MIN2(fac, 1.0f);
00822 
00823     /* for max 1 second, interpolate positions */
00824     if(uiAlignPanelStep(sa, ar, fac, 0))
00825         ED_region_tag_redraw(ar);
00826     else
00827         fac= 1.0f;
00828 
00829     if(fac >= 1.0f) {
00830         panel_activate_state(C, panel, PANEL_STATE_EXIT);
00831         return;
00832     }
00833 }
00834 
00835 void uiBeginPanels(const bContext *UNUSED(C), ARegion *ar)
00836 {
00837     Panel *pa;
00838   
00839       /* set all panels as inactive, so that at the end we know
00840      * which ones were used */
00841     for(pa=ar->panels.first; pa; pa=pa->next) {
00842         if(pa->runtime_flag & PNL_ACTIVE)
00843             pa->runtime_flag= PNL_WAS_ACTIVE;
00844         else
00845             pa->runtime_flag= 0;
00846     }
00847 }
00848 
00849 /* only draws blocks with panels */
00850 void uiEndPanels(const bContext *C, ARegion *ar, int *x, int *y)
00851 {
00852     ScrArea *sa= CTX_wm_area(C);
00853     uiBlock *block;
00854     Panel *panot, *panew, *patest, *pa, *firstpa;
00855     
00856     /* offset contents */
00857     for(block= ar->uiblocks.first; block; block= block->next)
00858         if(block->active && block->panel)
00859             ui_offset_panel_block(block);
00860 
00861     /* consistency; are panels not made, whilst they have tabs */
00862     for(panot= ar->panels.first; panot; panot= panot->next) {
00863         if((panot->runtime_flag & PNL_ACTIVE)==0) { // not made
00864 
00865             for(panew= ar->panels.first; panew; panew= panew->next) {
00866                 if((panew->runtime_flag & PNL_ACTIVE)) {
00867                     if(panew->paneltab==panot) { // panew is tab in notmade pa
00868                         break;
00869                     }
00870                 }
00871             }
00872             /* now panew can become the new parent, check all other tabs */
00873             if(panew) {
00874                 for(patest= ar->panels.first; patest; patest= patest->next) {
00875                     if(patest->paneltab == panot) {
00876                         patest->paneltab= panew;
00877                     }
00878                 }
00879                 panot->paneltab= panew;
00880                 panew->paneltab= NULL;
00881                 ED_region_tag_redraw(ar); // the buttons panew were not made
00882             }
00883         }   
00884     }
00885 
00886     /* re-align, possibly with animation */
00887     if(panels_re_align(sa, ar, &pa)) {
00888         if(pa)
00889             panel_activate_state(C, pa, PANEL_STATE_ANIMATION);
00890         else
00891             uiAlignPanelStep(sa, ar, 1.0, 0);
00892     }
00893 
00894     /* tag first panel */
00895     firstpa= NULL;
00896     for(block= ar->uiblocks.first; block; block=block->next)
00897         if(block->active && block->panel)
00898             if(!firstpa || block->panel->sortorder < firstpa->sortorder)
00899                 firstpa= block->panel;
00900     
00901     if(firstpa)
00902         firstpa->runtime_flag |= PNL_FIRST;
00903     
00904     /* compute size taken up by panel */
00905     ui_panels_size(sa, ar, x, y);
00906 }
00907 
00908 void uiDrawPanels(const bContext *C, ARegion *ar)
00909 {
00910     uiBlock *block;
00911 
00912     UI_ThemeClearColor(TH_BACK);
00913     
00914     /* draw panels, selected on top */
00915     for(block= ar->uiblocks.first; block; block=block->next) {
00916         if(block->active && block->panel && !(block->panel->flag & PNL_SELECT)) {
00917             uiDrawBlock(C, block);
00918         }
00919     }
00920 
00921     for(block= ar->uiblocks.first; block; block=block->next) {
00922         if(block->active && block->panel && (block->panel->flag & PNL_SELECT)) {
00923             uiDrawBlock(C, block);
00924         }
00925     }
00926 }
00927 
00928 /* ------------ panel merging ---------------- */
00929 
00930 static void check_panel_overlap(ARegion *ar, Panel *panel)
00931 {
00932     Panel *pa;
00933 
00934     /* also called with panel==NULL for clear */
00935     
00936     for(pa=ar->panels.first; pa; pa=pa->next) {
00937         pa->flag &= ~PNL_OVERLAP;
00938         if(panel && (pa != panel)) {
00939             if(pa->paneltab==NULL && (pa->runtime_flag & PNL_ACTIVE)) {
00940                 float safex= 0.2, safey= 0.2;
00941                 
00942                 if(pa->flag & PNL_CLOSEDX) safex= 0.05;
00943                 else if(pa->flag & PNL_CLOSEDY) safey= 0.05;
00944                 else if(panel->flag & PNL_CLOSEDX) safex= 0.05;
00945                 else if(panel->flag & PNL_CLOSEDY) safey= 0.05;
00946                 
00947                 if(pa->ofsx > panel->ofsx- safex*panel->sizex)
00948                 if(pa->ofsx+pa->sizex < panel->ofsx+ (1.0f+safex)*panel->sizex)
00949                 if(pa->ofsy > panel->ofsy- safey*panel->sizey)
00950                 if(pa->ofsy+pa->sizey < panel->ofsy+ (1.0f+safey)*panel->sizey)
00951                     pa->flag |= PNL_OVERLAP;
00952             }
00953         }
00954     }
00955 }
00956 
00957 /************************ panel dragging ****************************/
00958 
00959 static void ui_do_drag(const bContext *C, wmEvent *event, Panel *panel)
00960 {
00961     uiHandlePanelData *data= panel->activedata;
00962     ScrArea *sa= CTX_wm_area(C);
00963     ARegion *ar= CTX_wm_region(C);
00964     short align= panel_aligned(sa, ar), dx=0, dy=0;
00965     
00966     /* first clip for window, no dragging outside */
00967     if(!BLI_in_rcti(&ar->winrct, event->x, event->y))
00968         return;
00969 
00970     dx= (event->x-data->startx) & ~(PNL_GRID-1);
00971     dy= (event->y-data->starty) & ~(PNL_GRID-1);
00972 
00973     dx *= (float)(ar->v2d.cur.xmax - ar->v2d.cur.xmin)/(float)(ar->winrct.xmax - ar->winrct.xmin);
00974     dy *= (float)(ar->v2d.cur.ymax - ar->v2d.cur.ymin)/(float)(ar->winrct.ymax - ar->winrct.ymin);
00975     
00976     if(data->state == PANEL_STATE_DRAG_SCALE) {
00977         panel->sizex = MAX2(data->startsizex+dx, UI_PANEL_MINX);
00978         
00979         if(data->startsizey-dy < UI_PANEL_MINY)
00980             dy= -UI_PANEL_MINY+data->startsizey;
00981 
00982         panel->sizey= data->startsizey-dy;
00983         panel->ofsy= data->startofsy+dy;
00984     }
00985     else {
00986         /* reset the panel snapping, to allow dragging away from snapped edges */
00987         panel->snap = PNL_SNAP_NONE;
00988         
00989         panel->ofsx = data->startofsx+dx;
00990         panel->ofsy = data->startofsy+dy;
00991         check_panel_overlap(ar, panel);
00992         
00993         if(align) uiAlignPanelStep(sa, ar, 0.2, 1);
00994     }
00995 
00996     ED_region_tag_redraw(ar);
00997 }
00998 
00999 /******************* region level panel interaction *****************/
01000 
01001 
01002 /* this function is supposed to call general window drawing too */
01003 /* also it supposes a block has panel, and isnt a menu */
01004 static void ui_handle_panel_header(const bContext *C, uiBlock *block, int mx, int my, int event)
01005 {
01006     ScrArea *sa= CTX_wm_area(C);
01007     ARegion *ar= CTX_wm_region(C);
01008     Panel *pa;
01009     int align= panel_aligned(sa, ar), button= 0;
01010 
01011     /* mouse coordinates in panel space! */
01012     
01013     /* XXX weak code, currently it assumes layout style for location of widgets */
01014     
01015     /* check open/collapsed button */
01016     if(event==RETKEY)
01017         button= 1;
01018     else if(event==AKEY)
01019         button= 1;
01020     else if(block->panel->flag & PNL_CLOSEDX) {
01021         if(my >= block->maxy) button= 1;
01022     }
01023     else if(block->panel->control & UI_PNL_CLOSE) {
01024         /* whole of header can be used to collapse panel (except top-right corner) */
01025         if(mx <= block->maxx-8-PNL_ICON) button= 2;
01026         //else if(mx <= block->minx+10+2*PNL_ICON+2) button= 1;
01027     }
01028     else if(mx <= block->maxx-PNL_ICON-12) {
01029         button= 1;
01030     }
01031     
01032     if(button) {
01033         if(button==2) { // close
01034             ED_region_tag_redraw(ar);
01035         }
01036         else {  // collapse
01037             if(block->panel->flag & PNL_CLOSED) {
01038                 block->panel->flag &= ~PNL_CLOSED;
01039                 /* snap back up so full panel aligns with screen edge */
01040                 if (block->panel->snap & PNL_SNAP_BOTTOM) 
01041                     block->panel->ofsy= 0;
01042             }
01043             else if(align==BUT_HORIZONTAL) {
01044                 block->panel->flag |= PNL_CLOSEDX;
01045             }
01046             else {
01047                 /* snap down to bottom screen edge*/
01048                 block->panel->flag |= PNL_CLOSEDY;
01049                 if (block->panel->snap & PNL_SNAP_BOTTOM) 
01050                     block->panel->ofsy= -block->panel->sizey;
01051             }
01052             
01053             for(pa= ar->panels.first; pa; pa= pa->next) {
01054                 if(pa->paneltab==block->panel) {
01055                     if(block->panel->flag & PNL_CLOSED) pa->flag |= PNL_CLOSED;
01056                     else pa->flag &= ~PNL_CLOSED;
01057                 }
01058             }
01059         }
01060 
01061         if(align)
01062             panel_activate_state(C, block->panel, PANEL_STATE_ANIMATION);
01063         else
01064             ED_region_tag_redraw(ar);
01065     }
01066     else if(mx <= (block->maxx-PNL_ICON-12)+PNL_ICON+2) {
01067         panel_activate_state(C, block->panel, PANEL_STATE_DRAG);
01068     }
01069 }
01070 
01071 /* XXX should become modal keymap */
01072 /* AKey is opening/closing panels, independent of button state now */
01073 
01074 int ui_handler_panel_region(bContext *C, wmEvent *event)
01075 {
01076     ARegion *ar= CTX_wm_region(C);
01077     uiBlock *block;
01078     Panel *pa;
01079     int retval, mx, my, inside_header= 0, inside_scale= 0, inside;
01080 
01081     retval= WM_UI_HANDLER_CONTINUE;
01082     for(block=ar->uiblocks.last; block; block=block->prev) {
01083         mx= event->x;
01084         my= event->y;
01085         ui_window_to_block(ar, block, &mx, &my);
01086 
01087         /* check if inside boundbox */
01088         inside= 0;
01089         pa= block->panel;
01090 
01091         if(!pa || pa->paneltab!=NULL)
01092             continue;
01093         if(pa->type && pa->type->flag & PNL_NO_HEADER) // XXX - accessed freed panels when scripts reload, need to fix.
01094             continue;
01095 
01096         if(block->minx <= mx && block->maxx >= mx)
01097             if(block->miny <= my && block->maxy+PNL_HEADER >= my)
01098                 inside= 1;
01099         
01100         if(inside && event->val==KM_PRESS) {
01101             if(event->type == AKEY && !ELEM4(KM_MOD_FIRST, event->ctrl, event->oskey, event->shift, event->alt)) {
01102                 
01103                 if(pa->flag & PNL_CLOSEDY) {
01104                     if((block->maxy <= my) && (block->maxy+PNL_HEADER >= my))
01105                         ui_handle_panel_header(C, block, mx, my, event->type);
01106                 }
01107                 else
01108                     ui_handle_panel_header(C, block, mx, my, event->type);
01109                 
01110                 continue;
01111             }
01112         }
01113         
01114         /* on active button, do not handle panels */
01115         if(ui_button_is_active(ar))
01116             continue;
01117         
01118         if(inside) {
01119             /* clicked at panel header? */
01120             if(pa->flag & PNL_CLOSEDX) {
01121                 if(block->minx <= mx && block->minx+PNL_HEADER >= mx) 
01122                     inside_header= 1;
01123             }
01124             else if((block->maxy <= my) && (block->maxy+PNL_HEADER >= my)) {
01125                 inside_header= 1;
01126             }
01127             else if(pa->control & UI_PNL_SCALE) {
01128                 if(block->maxx-PNL_HEADER <= mx)
01129                     if(block->miny+PNL_HEADER >= my)
01130                         inside_scale= 1;
01131             }
01132 
01133             if(event->val==KM_PRESS) {
01134                 /* open close on header */
01135                 if(ELEM(event->type, RETKEY, PADENTER)) {
01136                     if(inside_header) {
01137                         ui_handle_panel_header(C, block, mx, my, RETKEY);
01138                         break;
01139                     }
01140                 }
01141                 else if(event->type == LEFTMOUSE) {
01142                     if(inside_header) {
01143                         ui_handle_panel_header(C, block, mx, my, 0);
01144                         break;
01145                     }
01146                     else if(inside_scale && !(pa->flag & PNL_CLOSED)) {
01147                         panel_activate_state(C, pa, PANEL_STATE_DRAG_SCALE);
01148                         break;
01149                     }
01150                 }
01151                 else if(event->type == ESCKEY) {
01152                     /*XXX 2.50 if(block->handler) {
01153                         rem_blockhandler(sa, block->handler);
01154                         ED_region_tag_redraw(ar);
01155                         retval= WM_UI_HANDLER_BREAK;
01156                     }*/
01157                 }
01158                 else if(event->type==PADPLUSKEY || event->type==PADMINUS) {
01159 #if 0 // XXX make float panel exception?
01160                     int zoom=0;
01161                 
01162                     /* if panel is closed, only zoom if mouse is over the header */
01163                     if (pa->flag & (PNL_CLOSEDX|PNL_CLOSEDY)) {
01164                         if (inside_header)
01165                             zoom=1;
01166                     }
01167                     else
01168                         zoom=1;
01169 
01170                     if(zoom) {
01171                         ScrArea *sa= CTX_wm_area(C);
01172                         SpaceLink *sl= sa->spacedata.first;
01173 
01174                         if(sa->spacetype!=SPACE_BUTS) {
01175                             if(!(pa->control & UI_PNL_SCALE)) {
01176                                 if(event->type==PADPLUSKEY) sl->blockscale+= 0.1;
01177                                 else sl->blockscale-= 0.1;
01178                                 CLAMP(sl->blockscale, 0.6, 1.0);
01179 
01180                                 ED_region_tag_redraw(ar);
01181                                 retval= WM_UI_HANDLER_BREAK;
01182                             }                       
01183                         }
01184                     }
01185 #endif
01186                 }
01187             }
01188         }
01189     }
01190 
01191     return retval;
01192 }
01193 
01194 /**************** window level modal panel interaction **************/
01195 
01196 /* note, this is modal handler and should not swallow events for animation */
01197 static int ui_handler_panel(bContext *C, wmEvent *event, void *userdata)
01198 {
01199     Panel *panel= userdata;
01200     uiHandlePanelData *data= panel->activedata;
01201 
01202     /* verify if we can stop */
01203     if(event->type == LEFTMOUSE && event->val!=KM_PRESS) {
01204         ScrArea *sa= CTX_wm_area(C);
01205         ARegion *ar= CTX_wm_region(C);
01206         int align= panel_aligned(sa, ar);
01207 
01208         if(align)
01209             panel_activate_state(C, panel, PANEL_STATE_ANIMATION);
01210         else
01211             panel_activate_state(C, panel, PANEL_STATE_EXIT);
01212     }
01213     else if(event->type == MOUSEMOVE) {
01214         if(data->state == PANEL_STATE_DRAG)
01215             ui_do_drag(C, event, panel);
01216     }
01217     else if(event->type == TIMER && event->customdata == data->animtimer) {
01218         if(data->state == PANEL_STATE_ANIMATION)
01219             ui_do_animate(C, panel);
01220         else if(data->state == PANEL_STATE_DRAG)
01221             ui_do_drag(C, event, panel);
01222     }
01223 
01224     data= panel->activedata;
01225 
01226     if(data && data->state == PANEL_STATE_ANIMATION)
01227         return WM_UI_HANDLER_CONTINUE;
01228     else
01229         return WM_UI_HANDLER_BREAK;
01230 }
01231 
01232 static void ui_handler_remove_panel(bContext *C, void *userdata)
01233 {
01234     Panel *pa= userdata;
01235 
01236     panel_activate_state(C, pa, PANEL_STATE_EXIT);
01237 }
01238 
01239 static void panel_activate_state(const bContext *C, Panel *pa, uiHandlePanelState state)
01240 {
01241     uiHandlePanelData *data= pa->activedata;
01242     wmWindow *win= CTX_wm_window(C);
01243     ARegion *ar= CTX_wm_region(C);
01244     
01245     if(data && data->state == state)
01246         return;
01247 
01248     if(state == PANEL_STATE_EXIT || state == PANEL_STATE_ANIMATION) {
01249         if(data && data->state != PANEL_STATE_ANIMATION) {
01250             /* XXX:
01251              *  - the panel tabbing function call below (test_add_new_tabs()) has been commented out
01252              *    "It is too easy to do by accident when reordering panels, is very hard to control and use, and has no real benefit." - BillRey
01253              * Aligorith, 2009Sep
01254              */
01255             //test_add_new_tabs(ar);   // also copies locations of tabs in dragged panel
01256             check_panel_overlap(ar, NULL);  // clears
01257         }
01258 
01259         pa->flag &= ~PNL_SELECT;
01260     }
01261     else
01262         pa->flag |= PNL_SELECT;
01263 
01264     if(data && data->animtimer) {
01265         WM_event_remove_timer(CTX_wm_manager(C), win, data->animtimer);
01266         data->animtimer= NULL;
01267     }
01268 
01269     if(state == PANEL_STATE_EXIT) {
01270         MEM_freeN(data);
01271         pa->activedata= NULL;
01272 
01273         WM_event_remove_ui_handler(&win->modalhandlers, ui_handler_panel, ui_handler_remove_panel, pa, 0);
01274     }
01275     else {
01276         if(!data) {
01277             data= MEM_callocN(sizeof(uiHandlePanelData), "uiHandlePanelData");
01278             pa->activedata= data;
01279 
01280             WM_event_add_ui_handler(C, &win->modalhandlers, ui_handler_panel, ui_handler_remove_panel, pa);
01281         }
01282 
01283         if(ELEM(state, PANEL_STATE_ANIMATION, PANEL_STATE_DRAG))
01284             data->animtimer= WM_event_add_timer(CTX_wm_manager(C), win, TIMER, ANIMATION_INTERVAL);
01285 
01286         data->state= state;
01287         data->startx= win->eventstate->x;
01288         data->starty= win->eventstate->y;
01289         data->startofsx= pa->ofsx;
01290         data->startofsy= pa->ofsy;
01291         data->startsizex= pa->sizex;
01292         data->startsizey= pa->sizey;
01293         data->starttime= PIL_check_seconds_timer();
01294     }
01295 
01296     ED_region_tag_redraw(ar);
01297 
01298     /* XXX exception handling, 3d window preview panel */
01299     /* if(block->drawextra==BIF_view3d_previewdraw)
01300         BIF_view3d_previewrender_clear(curarea);*/
01301     
01302     /* XXX exception handling, 3d window preview panel */
01303     /* if(block->drawextra==BIF_view3d_previewdraw)
01304         BIF_view3d_previewrender_signal(curarea, PR_DISPRECT);
01305     else if(strcmp(block->name, "image_panel_preview")==0)
01306         image_preview_event(2); */
01307 }
01308