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