diff options
author | Ton Roosendaal <ton@blender.org> | 2003-10-15 23:23:54 +0400 |
---|---|---|
committer | Ton Roosendaal <ton@blender.org> | 2003-10-15 23:23:54 +0400 |
commit | 10333bd1d39460efb2e71930f43342e6b5840c9a (patch) | |
tree | 856016c103836bba6030b7852130042cd1d23a66 /source/blender/src/interface_panel.c | |
parent | 478f61563a320d33b51fec02640e41ab4b05f825 (diff) |
- removed all #include "interface.h" from files. this is a local/internal
include only (use BIF_interface.h instead)
- split up interface.c in two files: NEW: interface_panel.c
- removed the temporal text files
WARN: FIX AUTOMAKE AND MSVC!
Diffstat (limited to 'source/blender/src/interface_panel.c')
-rw-r--r-- | source/blender/src/interface_panel.c | 1463 |
1 files changed, 1463 insertions, 0 deletions
diff --git a/source/blender/src/interface_panel.c b/source/blender/src/interface_panel.c new file mode 100644 index 00000000000..795f9765ad7 --- /dev/null +++ b/source/blender/src/interface_panel.c @@ -0,0 +1,1463 @@ +/** + * $Id$ + * + * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License + * as published by the Free Software Foundation; either version 2 + * of the License, or (at your option) any later version. The Blender + * Foundation also sells licenses for use in proprietary software under + * the Blender License. See http://www.blender.org/BL/ for information + * about this. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software Foundation, + * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * + * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV. + * All rights reserved. + * + * The Original Code is: all of this file. + * + * Contributor(s): none yet. + * + * ***** END GPL/BL DUAL LICENSE BLOCK ***** + */ + +/* + a full doc with API notes can be found in bf-blender/blender/doc/interface_API.txt + + */ + + +#include <math.h> +#include <stdlib.h> +#include <string.h> +#include <ctype.h> + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#ifndef WIN32 +#include <unistd.h> +#else +#include <io.h> +#include "BLI_winstuff.h" +#endif + +#include "MEM_guardedalloc.h" + +#include "PIL_time.h" + +#include "BLI_blenlib.h" +#include "BLI_arithb.h" + +#include "DNA_screen_types.h" +#include "DNA_space_types.h" +#include "DNA_userdef_types.h" +#include "DNA_vec_types.h" + +#include "BKE_blender.h" +#include "BKE_utildefines.h" +#include "BKE_global.h" + +#include "BIF_gl.h" +#include "BIF_graphics.h" +#include "BIF_keyval.h" +#include "BIF_mainqueue.h" + +#include "BIF_screen.h" +#include "BIF_toolbox.h" +#include "BIF_mywindow.h" +#include "BIF_space.h" +#include "BIF_glutil.h" +#include "BIF_interface.h" +#include "BIF_butspace.h" +#include "BIF_language.h" + +#include "BSE_view.h" + +#include "mydevice.h" +#include "interface.h" +#include "blendef.h" + + +extern float UIwinmat[4][4]; + +/* --------- generic helper drawng calls ---------------- */ + +/* supposes you draw the actual box atop of this. */ +void uiSoftShadow(float minx, float miny, float maxx, float maxy, float rad, int alpha) +{ + + glShadeModel(GL_SMOOTH); + glEnable(GL_BLEND); + glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA ); + + /* quads start left-top, clockwise */ + + /* left */ + glBegin(GL_POLYGON); + glColor4ub(0, 0, 0, 0); + glVertex2f( minx-rad, maxy-rad); + glColor4ub(0, 0, 0, alpha); + glVertex2f( minx+rad, maxy-rad); + glColor4ub(0, 0, 0, alpha); + glVertex2f( minx+rad, miny+rad); + glColor4ub(0, 0, 0, 0); + glVertex2f( minx-rad, miny-rad); + glEnd(); + + /* bottom */ + glBegin(GL_POLYGON); + glColor4ub(0, 0, 0, alpha); + glVertex2f( minx+rad, miny+rad); + glColor4ub(0, 0, 0, alpha); + glVertex2f( maxx-rad, miny+rad); + glColor4ub(0, 0, 0, 0); + glVertex2f( maxx+rad, miny-rad); + glColor4ub(0, 0, 0, 0); + glVertex2f( minx-rad, miny-rad); + glEnd(); + + /* right */ + glBegin(GL_POLYGON); + glColor4ub(0, 0, 0, alpha); + glVertex2f( maxx-rad, maxy-rad); + glColor4ub(0, 0, 0, 0); + glVertex2f( maxx+rad, maxy-rad); + glColor4ub(0, 0, 0, 0); + glVertex2f( maxx+rad, miny-rad); + glColor4ub(0, 0, 0, alpha); + glVertex2f( maxx-rad, miny+rad); + glEnd(); + + glDisable(GL_BLEND); + glShadeModel(GL_FLAT); +} + + +#define UI_RB_ALPHA 16 +static int roundboxtype= 15; + +void uiSetRoundBox(int type) +{ + roundboxtype= type; + + /* flags to set which corners will become rounded: + + 1------2 + | | + 8------4 + */ + +} + +void gl_round_box_topshade(float minx, float miny, float maxx, float maxy, float rad) +{ + float vec[7][2]= {{0.195, 0.02}, {0.383, 0.067}, {0.55, 0.169}, {0.707, 0.293}, + {0.831, 0.45}, {0.924, 0.617}, {0.98, 0.805}}; + char col[7]= {140, 165, 195, 210, 230, 245, 255}; + int a; + char alpha=255; + + if(roundboxtype & UI_RB_ALPHA) alpha= 128; + + /* mult */ + for(a=0; a<7; a++) { + vec[a][0]*= rad; vec[a][1]*= rad; + } + + /* shades from grey->white->grey */ + glBegin(GL_LINE_STRIP); + + if(roundboxtype & 3) { + /* corner right-top */ + glColor4ub(140, 140, 140, alpha); + glVertex2f( maxx, maxy-rad); + for(a=0; a<7; a++) { + glColor4ub(col[a], col[a], col[a], alpha); + glVertex2f( maxx-vec[a][1], maxy-rad+vec[a][0]); + } + glColor4ub(225, 225, 225, alpha); + glVertex2f( maxx-rad, maxy); + + + /* corner left-top */ + glVertex2f( minx+rad, maxy); + for(a=0; a<7; a++) { + glColor4ub(col[6-a], col[6-a], col[6-a], alpha); + glVertex2f( minx+rad-vec[a][0], maxy-vec[a][1]); + } + glVertex2f( minx, maxy-rad); + } + else { + glColor4ub(225, 225, 225, alpha); + glVertex2f( minx, maxy); + glVertex2f( maxx, maxy); + } + + glEnd(); +} + + +void gl_round_box(float minx, float miny, float maxx, float maxy, float rad) +{ + float vec[7][2]= {{0.195, 0.02}, {0.383, 0.067}, {0.55, 0.169}, {0.707, 0.293}, + {0.831, 0.45}, {0.924, 0.617}, {0.98, 0.805}}; + int a; + + /* mult */ + for(a=0; a<7; a++) { + vec[a][0]*= rad; vec[a][1]*= rad; + } + + /* start with corner right-bottom */ + if(roundboxtype & 4) { + glVertex2f( maxx-rad, miny); + for(a=0; a<7; a++) { + glVertex2f( maxx-rad+vec[a][0], miny+vec[a][1]); + } + glVertex2f( maxx, miny+rad); + } + else glVertex2f( maxx, miny); + + /* corner right-top */ + if(roundboxtype & 2) { + glVertex2f( maxx, maxy-rad); + for(a=0; a<7; a++) { + glVertex2f( maxx-vec[a][1], maxy-rad+vec[a][0]); + } + glVertex2f( maxx-rad, maxy); + } + else glVertex2f( maxx, maxy); + + /* corner left-top */ + if(roundboxtype & 1) { + glVertex2f( minx+rad, maxy); + for(a=0; a<7; a++) { + glVertex2f( minx+rad-vec[a][0], maxy-vec[a][1]); + } + glVertex2f( minx, maxy-rad); + } + else glVertex2f( minx, maxy); + + /* corner left-bottom */ + if(roundboxtype & 8) { + glVertex2f( minx, miny+rad); + for(a=0; a<7; a++) { + glVertex2f( minx+vec[a][1], miny+rad-vec[a][0]); + } + glVertex2f( minx+rad, miny); + } + else glVertex2f( minx, miny); + +} + +/* for headers and floating panels */ +void uiRoundBoxEmboss(float minx, float miny, float maxx, float maxy, float rad) +{ + float color[4]; + + if(roundboxtype & UI_RB_ALPHA) { + glGetFloatv(GL_CURRENT_COLOR, color); + color[3]= 0.5; + glColor4fv(color); + glEnable( GL_BLEND ); + glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA ); + } + + /* solid part */ + glBegin(GL_POLYGON); + gl_round_box(minx, miny, maxx, maxy, rad); + glEnd(); + + /* set antialias line */ + glEnable( GL_LINE_SMOOTH ); + glEnable( GL_BLEND ); + glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA ); + + gl_round_box_topshade(minx+1, miny+1, maxx-1, maxy-1, rad); + + if(roundboxtype & UI_RB_ALPHA) glColor4ub(0,0,0, 128); else glColor4ub(0,0,0, 255); + glBegin(GL_LINE_LOOP); + gl_round_box(minx, miny, maxx, maxy, rad); + glEnd(); + + glDisable( GL_BLEND ); + glDisable( GL_LINE_SMOOTH ); + +} + + +/* plain antialiased unfilled rectangle */ +void uiRoundRect(float minx, float miny, float maxx, float maxy, float rad) +{ + float color[4]; + + if(roundboxtype & UI_RB_ALPHA) { + glGetFloatv(GL_CURRENT_COLOR, color); + color[3]= 0.5; + glColor4fv(color); + glEnable( GL_BLEND ); + glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA ); + } + + /* set antialias line */ + glEnable( GL_LINE_SMOOTH ); + glEnable( GL_BLEND ); + glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA ); + + glBegin(GL_LINE_LOOP); + gl_round_box(minx, miny, maxx, maxy, rad); + glEnd(); + + glDisable( GL_BLEND ); + glDisable( GL_LINE_SMOOTH ); +} + + + +/* plain antialiased filled box */ +void uiRoundBox(float minx, float miny, float maxx, float maxy, float rad) +{ + float color[4]; + + if(roundboxtype & UI_RB_ALPHA) { + glGetFloatv(GL_CURRENT_COLOR, color); + color[3]= 0.5; + glColor4fv(color); + glEnable( GL_BLEND ); + glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA ); + } + + /* solid part */ + glBegin(GL_POLYGON); + gl_round_box(minx, miny, maxx, maxy, rad); + glEnd(); + + /* set antialias line */ + glEnable( GL_LINE_SMOOTH ); + glEnable( GL_BLEND ); + glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA ); + + glBegin(GL_LINE_LOOP); + gl_round_box(minx, miny, maxx, maxy, rad); + glEnd(); + + glDisable( GL_BLEND ); + glDisable( GL_LINE_SMOOTH ); +} + + +/* ************** panels ************* */ + +static void copy_panel_offset(Panel *pa, Panel *papar) +{ + /* with respect to sizes... papar is parent */ + + pa->ofsx= papar->ofsx; + pa->ofsy= papar->ofsy + papar->sizey-pa->sizey; +} + + + +/* ugly global... but will be NULLed after each 'newPanel' call */ +static char *panel_tabbed=NULL, *group_tabbed=NULL; + +void uiNewPanelTabbed(char *panelname, char *groupname) +{ + panel_tabbed= panelname; + group_tabbed= groupname; +} + +/* another global... */ +static int pnl_style= UI_PNL_TRANSP; + +void uiSetPanelStyle(int style) +{ + pnl_style= style; +} + + +/* ofsx/ofsy only used for new panel definitions */ +/* return 1 if visible (create buttons!) */ +int uiNewPanel(ScrArea *sa, uiBlock *block, char *panelname, char *tabname, int ofsx, int ofsy, int sizex, int sizey) +{ + Panel *pa, *palign; + + /* check if Panel exists, then use that one */ + pa= sa->panels.first; + while(pa) { + if( strncmp(pa->panelname, panelname, UI_MAX_NAME_STR)==0) { + if( strncmp(pa->tabname, tabname, UI_MAX_NAME_STR)==0) { + break; + } + } + pa= pa->next; + } + + if(pa==NULL) { + + /* new panel */ + pa= MEM_callocN(sizeof(Panel), "new panel"); + BLI_addtail(&sa->panels, pa); + strncpy(pa->panelname, panelname, UI_MAX_NAME_STR); + strncpy(pa->tabname, tabname, UI_MAX_NAME_STR); + + pa->ofsx= ofsx & ~(PNL_GRID-1); + pa->ofsy= ofsy & ~(PNL_GRID-1); + pa->sizex= sizex; + pa->sizey= sizey; + pa->style= pnl_style; + + /* pre align, for good sorting later on */ + if(sa->spacetype==SPACE_BUTS && pa->prev) { + SpaceButs *sbuts= sa->spacedata.first; + + palign= pa->prev; + if(sbuts->align==BUT_VERTICAL) { + pa->ofsy= palign->ofsy - pa->sizey - PNL_HEADER; + } + else if(sbuts->align==BUT_HORIZONTAL) { + pa->ofsx= palign->ofsx + palign->sizex; + } + } + /* make new Panel tabbed? */ + if(panel_tabbed && group_tabbed) { + Panel *papar; + for(papar= sa->panels.first; papar; papar= papar->next) { + if(papar->active && papar->paneltab==NULL) { + if( strncmp(panel_tabbed, papar->panelname, UI_MAX_NAME_STR)==0) { + if( strncmp(group_tabbed, papar->tabname, UI_MAX_NAME_STR)==0) { + pa->paneltab= papar; + copy_panel_offset(pa, papar); + break; + } + } + } + } + } + } + + block->panel= pa; + pa->active= 1; + + /* clear global */ + panel_tabbed= group_tabbed= NULL; + + if(block->panel->paneltab) return 0; + if(block->panel->flag & PNL_CLOSED) return 0; + + return 1; +} + +void uiFreePanels(ListBase *lb) +{ + Panel *panel; + + while( (panel= lb->first) ) { + BLI_remlink(lb, panel); + MEM_freeN(panel); + } +} + +void uiNewPanelHeight(uiBlock *block, int sizey) +{ + if(sizey<64) sizey= 64; + + if(block->panel) { + block->panel->ofsy+= (block->panel->sizey - sizey); + block->panel->sizey= sizey; + } +} + +static int panel_has_tabs(Panel *panel) +{ + Panel *pa= curarea->panels.first; + + if(panel==NULL) return 0; + + while(pa) { + if(pa->paneltab==panel) return 1; + pa= pa->next; + } + return 0; +} + +static void ui_scale_panel_block(uiBlock *block) +{ + uiBut *but; + float facx= 1.0, facy= 1.0; + int centrex= 0, topy=0, tabsy=0; + + if(block->panel==NULL) return; + + if(block->autofill) ui_autofill(block); + /* buttons min/max centered, offset calculated */ + uiBoundsBlock(block, 0); + + if( block->maxx-block->minx > block->panel->sizex - 2*PNL_SAFETY ) { + facx= (block->panel->sizex - (2*PNL_SAFETY))/( block->maxx-block->minx ); + } + else centrex= (block->panel->sizex-( block->maxx-block->minx ) - PNL_SAFETY)/2; + + // tabsy= PNL_HEADER*panel_has_tabs(block->panel); + if( (block->maxy-block->miny) > block->panel->sizey - 2*PNL_SAFETY - tabsy) { + facy= (block->panel->sizey - (2*PNL_SAFETY) - tabsy)/( block->maxy-block->miny ); + } + else topy= (block->panel->sizey- 2*PNL_SAFETY - tabsy) - ( block->maxy-block->miny ) ; + + but= block->buttons.first; + while(but) { + but->x1= PNL_SAFETY+centrex+ facx*(but->x1-block->minx); + but->y1= PNL_SAFETY+topy + facy*(but->y1-block->miny); + but->x2= PNL_SAFETY+centrex+ facx*(but->x2-block->minx); + but->y2= PNL_SAFETY+topy + facy*(but->y2-block->miny); + if(facx!=1.0) ui_check_but(but); /* for strlen */ + but= but->next; + } + + block->maxx= block->panel->sizex; + block->maxy= block->panel->sizey; + block->minx= block->miny= 0.0; + +} + +// for 'home' key +void uiSetPanel_view2d(ScrArea *sa) +{ + Panel *pa; + float minx=10000, maxx= -10000, miny=10000, maxy= -10000; + int done=0; + + pa= sa->panels.first; + while(pa) { + if(pa->active) { + done= 1; + if(pa->ofsx < minx) minx= pa->ofsx; + if(pa->ofsx+pa->sizex > maxx) maxx= pa->ofsx+pa->sizex; + if(pa->ofsy < miny) miny= pa->ofsy; + if(pa->ofsy+pa->sizey+PNL_HEADER > maxy) maxy= pa->ofsy+pa->sizey+PNL_HEADER; + } + pa= pa->next; + } + if(done) { + G.v2d->tot.xmin= minx-PNL_DIST; + G.v2d->tot.xmax= maxx+PNL_DIST; + G.v2d->tot.ymin= miny-PNL_DIST; + G.v2d->tot.ymax= maxy+PNL_DIST; + } + else { + G.v2d->tot.xmin= 0; + G.v2d->tot.xmax= 1280; + G.v2d->tot.ymin= 0; + G.v2d->tot.ymax= 228; + } + +} + +// make sure the panels are not outside 'tot' area +void uiMatchPanel_view2d(ScrArea *sa) +{ + Panel *pa; + + pa= sa->panels.first; + while(pa) { + if(pa->active) { + if(pa->ofsx < G.v2d->tot.xmin) G.v2d->tot.xmin= pa->ofsx; + if(pa->ofsx+pa->sizex > G.v2d->tot.xmax) + G.v2d->tot.xmax= pa->ofsx+pa->sizex; + if(pa->ofsy < G.v2d->tot.ymin) G.v2d->tot.ymin= pa->ofsy; + if(pa->ofsy+pa->sizey+PNL_HEADER > G.v2d->tot.ymax) + G.v2d->tot.ymax= pa->ofsy+pa->sizey+PNL_HEADER; + } + pa= pa->next; + } +} + +/* extern used ny previewrender */ +void uiPanelPush(uiBlock *block) +{ + glPushMatrix(); + if(block->panel) { + glTranslatef((float)block->panel->ofsx, (float)block->panel->ofsy, 0.0); + i_translate((float)block->panel->ofsx, (float)block->panel->ofsy, 0.0, UIwinmat); + } +} + +void uiPanelPop(uiBlock *block) +{ + glPopMatrix(); + Mat4CpyMat4(UIwinmat, block->winmat); +} + +uiBlock *uiFindOpenPanelBlockName(ListBase *lb, char *name) +{ + uiBlock *block; + + for(block= lb->first; block; block= block->next) { + if(block->panel && block->panel->active && block->panel->paneltab==NULL) { + if(block->panel->flag & PNL_CLOSED); + else if(strncmp(name, block->panel->panelname, UI_MAX_NAME_STR)==0) break; + } + } + return block; +} + +static void ui_draw_anti_tria(float x1, float y1, float x2, float y2, float x3, float y3) +{ + + // we draw twice, anti polygons not widely supported... + + glBegin(GL_POLYGON); + glVertex2f(x1, y1); + glVertex2f(x2, y2); + glVertex2f(x3, y3); + glEnd(); + + /* set antialias line */ + glEnable( GL_LINE_SMOOTH ); + glEnable( GL_BLEND ); + glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA ); + + glBegin(GL_LINE_LOOP); + glVertex2f(x1, y1); + glVertex2f(x2, y2); + glVertex2f(x3, y3); + glEnd(); + + glDisable( GL_LINE_SMOOTH ); + glDisable( GL_BLEND ); + +} + +/* 'icon' for panel header */ +static void ui_draw_tria_icon(float x, float y, float aspect, char dir) +{ + + + glColor3ub(240, 240, 240); + + if(dir=='h') { + ui_draw_anti_tria( x, y, x, y+12.0, x+10, y+6); + } + else { + ui_draw_anti_tria( x, y+10.0, x+12, y+10.0, x+6, y); + } + + +} + +static void ui_set_panel_pattern(char dir) +{ + static int firsttime= 1; + static GLubyte path[4*32], patv[4*32]; + int a,b,i=0; + + if(firsttime) { + firsttime= 0; + for(a=0; a<128; a++) patv[a]= 0x33; + for(a=0; a<8; a++) { + for(b=0; b<4; b++) path[i++]= 0xff; /* 1 scanlines */ + for(b=0; b<12; b++) path[i++]= 0x0; /* 3 lines */ + } + } + glEnable(GL_POLYGON_STIPPLE); + if(dir=='h') glPolygonStipple(path); + else glPolygonStipple(patv); +} + +static char *ui_block_cut_str(uiBlock *block, char *str, short okwidth) +{ + short width, ofs=strlen(str); + static char str1[128]; + + if(ofs>127) return str; + + width= block->aspect*BIF_GetStringWidth(block->curfont, str, (U.transopts & TR_BUTTONS)); + + if(width <= okwidth) return str; + strcpy(str1, str); + + while(width > okwidth && ofs>0) { + ofs--; + str1[ofs]= 0; + + width= block->aspect*BIF_GetStringWidth(block->curfont, str1, 0); + + if(width < 10) break; + } + return str1; +} + + +#define PNL_ICON 20 +#define PNL_DRAGGER 20 + + +static void ui_draw_panel_header(uiBlock *block) +{ + Panel *pa, *panel= block->panel; + float width; + int a, nr= 1; + char *str; + + /* count */ + pa= curarea->panels.first; + while(pa) { + if(pa->active) { + if(pa->paneltab==panel) nr++; + } + pa= pa->next; + } + + if(nr==1) { + glColor3ub(255,255,255); + glRasterPos2f(block->minx+40, block->maxy+5); + BIF_DrawString(block->curfont, block->panel->panelname, (U.transopts & TR_BUTTONS), 0); + return; + } + + a= 0; + width= (panel->sizex - 3 - 2*PNL_ICON)/nr; + pa= curarea->panels.first; + while(pa) { + if(pa->active==0); + else if(pa==panel) { + /* active tab */ + uiSetRoundBox(15); + glColor3ub(140, 140, 147); + uiRoundBox(2+PNL_ICON+a*width, panel->sizey+3, PNL_ICON+(a+1)*width, panel->sizey+PNL_HEADER-3, 8); + + glColor3ub(255,255,255); + glRasterPos2f(10+PNL_ICON+a*width, panel->sizey+5); + str= ui_block_cut_str(block, pa->panelname, (short)(width-10)); + BIF_DrawString(block->curfont, str, (U.transopts & TR_BUTTONS), 0); + + a++; + } + else if(pa->paneltab==panel) { + /* not active tab */ + + glColor3ub(95,95,95); + glRasterPos2f(10+PNL_ICON+a*width, panel->sizey+5); + str= ui_block_cut_str(block, pa->panelname, (short)(width-10)); + BIF_DrawString(block->curfont, str, (U.transopts & TR_BUTTONS), 0); + + a++; + } + pa= pa->next; + } + + // dragger + uiSetRoundBox(15); + glColor3ub(140, 140, 147); + uiRoundBox(panel->sizex-PNL_ICON+5, panel->sizey+5, panel->sizex-5, panel->sizey+PNL_HEADER-5, 5); + +} + +void ui_draw_panel(uiBlock *block) +{ + int align=0; + + if(block->panel->paneltab) return; + + if(curarea->spacetype==SPACE_BUTS) { + SpaceButs *sbuts= curarea->spacedata.first; + align= sbuts->align; + } + + if(block->panel->flag & PNL_CLOSEDY) { + uiSetRoundBox(15); + glColor3ub(160, 160, 167); + uiRoundBox(block->minx, block->maxy, block->maxx, block->maxy+PNL_HEADER, 10); + + // title + glColor3ub(255,255,255); + glRasterPos2f(block->minx+40, block->maxy+5); + BIF_DrawString(block->curfont, block->panel->panelname, (U.transopts & TR_BUTTONS), 0); + + // border + if(block->panel->flag & PNL_SELECT) { + glColor3ub(64, 64, 64); + uiRoundRect(block->minx, block->maxy, block->maxx, block->maxy+PNL_HEADER, 10); + } + if(block->panel->flag & PNL_OVERLAP) { + glColor3ub(240, 240, 240); + uiRoundRect(block->minx, block->maxy, block->maxx, block->maxy+PNL_HEADER, 10); + } + + } + else if(block->panel->flag & PNL_CLOSEDX) { + char str[4]; + int a, end, ofs; + + uiSetRoundBox(15); + glColor3ub(160, 160, 167); + uiRoundBox(block->minx, block->miny, block->minx+PNL_HEADER, block->maxy+PNL_HEADER, 10); + + // title, only capitals for now + glColor3ub(255,255,255); + str[1]= 0; + end= strlen(block->panel->panelname); + ofs= 20; + for(a=0; a<end; a++) { + str[0]= block->panel->panelname[a]; + if( isupper(str[0]) ) { + glRasterPos2f(block->minx+5, block->maxy-ofs); + BIF_DrawString(block->curfont, str, 0, 0); + ofs+= 15; + } + } + + // border + if(block->panel->flag & PNL_SELECT) { + glColor3ub(64, 64, 64); + uiRoundRect(block->minx, block->miny, block->minx+PNL_HEADER, block->maxy+PNL_HEADER, 10); + } + if(block->panel->flag & PNL_OVERLAP) { + glColor3ub(240, 240, 240); + uiRoundRect(block->minx, block->miny, block->minx+PNL_HEADER, block->maxy+PNL_HEADER, 10); + } + + } + else { + + uiSetRoundBox(3); + + if(block->panel->style== UI_PNL_SOLID) { + glColor3ub(160, 160, 167); + uiRoundBox(block->minx, block->maxy, block->maxx, block->maxy+PNL_HEADER, 10); + // blend now for panels in 3d window, test... + glEnable(GL_BLEND); + glColor4ub(198, 198, 198, 100); + glRectf(block->minx, block->miny, block->maxx, block->maxy); + + if(align) { + glColor4ub(206, 206, 206, 100); + if(align==BUT_HORIZONTAL) ui_set_panel_pattern('h'); + else ui_set_panel_pattern('v'); + + glRectf(block->minx, block->miny, block->maxx, block->maxy); + glDisable(GL_POLYGON_STIPPLE); + } + glDisable(GL_BLEND); + } + else { + glColor3ub(218, 218, 218); + uiRoundRect(block->minx, block->miny, block->maxx, block->maxy+PNL_HEADER, 10); + } + + + ui_draw_panel_header(block); + + // border + uiSetRoundBox(3); + if(block->panel->flag & PNL_SELECT) { + glColor3ub(64, 64, 64); + uiRoundRect(block->minx, block->miny, block->maxx, block->maxy+PNL_HEADER, 10); + } + if(block->panel->flag & PNL_OVERLAP) { + glColor3ub(240, 240, 240); + uiRoundRect(block->minx, block->miny, block->maxx, block->maxy+PNL_HEADER, 10); + } + + /* and a soft shadow-line for now */ + glEnable( GL_BLEND ); + glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA ); + glColor4ub(0, 0, 0, 50); + fdrawline(block->maxx, block->miny, block->maxx, block->maxy+PNL_HEADER/2); + fdrawline(block->minx, block->miny, block->maxx, block->miny); + glDisable(GL_BLEND); + + } + + /* draw close icon */ + + if(block->panel->flag & PNL_CLOSEDY) + ui_draw_tria_icon(block->minx+6, block->maxy+3, block->aspect, 'h'); + else if(block->panel->flag & PNL_CLOSEDX) + ui_draw_tria_icon(block->minx+4, block->maxy+2, block->aspect, 'h'); + else + ui_draw_tria_icon(block->minx+6, block->maxy+3, block->aspect, 'v'); + + +} + +static void ui_redraw_select_panel(ScrArea *sa) +{ + /* only for beauty, make sure the panel thats moved is on top */ + /* better solution later? */ + uiBlock *block; + + for(block= sa->uiblocks.first; block; block= block->next) { + if(block->panel && (block->panel->flag & PNL_SELECT)) { + uiDrawBlock(block); + } + } + +} + + +/* ------------ panel alignment ---------------- */ + + +/* this function is needed because uiBlock and Panel itself dont +change sizey or location when closed */ +static int get_panel_real_ofsy(Panel *pa) +{ + if(pa->flag & PNL_CLOSEDY) return pa->ofsy+pa->sizey; + else if(pa->paneltab && (pa->paneltab->flag & PNL_CLOSEDY)) return pa->ofsy+pa->sizey; + else return pa->ofsy; +} + +static int get_panel_real_ofsx(Panel *pa) +{ + if(pa->flag & PNL_CLOSEDX) return pa->ofsx+PNL_HEADER; + else if(pa->paneltab && (pa->paneltab->flag & PNL_CLOSEDX)) return pa->ofsx+PNL_HEADER; + else return pa->ofsx+pa->sizex; +} + + +typedef struct PanelSort { + Panel *pa, *orig; +} PanelSort; + +static int find_leftmost_panel(const void *a1, const void *a2) +{ + const PanelSort *ps1=a1, *ps2=a2; + + if( ps1->pa->ofsx > ps2->pa->ofsx) return 1; + else if( ps1->pa->ofsx < ps2->pa->ofsx) return -1; + + return 0; +} + + +static int find_highest_panel(const void *a1, const void *a2) +{ + const PanelSort *ps1=a1, *ps2=a2; + + if( ps1->pa->ofsy < ps2->pa->ofsy) return 1; + else if( ps1->pa->ofsy > ps2->pa->ofsy) return -1; + + return 0; +} + +/* this doesnt draw */ +/* returns 1 when it did something */ +int uiAlignPanelStep(ScrArea *sa, float fac) +{ + SpaceButs *sbuts= sa->spacedata.first; + Panel *pa; + PanelSort *ps, *panelsort, *psnext; + int a, tot=0, done; + + if(sa->spacetype!=SPACE_BUTS) { + return 0; + } + + /* count active, not tabbed Panels */ + for(pa= sa->panels.first; pa; pa= pa->next) { + if(pa->active && pa->paneltab==NULL) tot++; + } + + if(tot==0) return 0; + + /* extra; change close direction? */ + for(pa= sa->panels.first; pa; pa= pa->next) { + if(pa->active && pa->paneltab==NULL) { + if( (pa->flag & PNL_CLOSEDX) && (sbuts->align==BUT_VERTICAL) ) + pa->flag ^= PNL_CLOSED; + + else if( (pa->flag & PNL_CLOSEDY) && (sbuts->align==BUT_HORIZONTAL) ) + pa->flag ^= PNL_CLOSED; + + } + } + + panelsort= MEM_callocN( tot*sizeof(PanelSort), "panelsort"); + + /* fill panelsort array */ + ps= panelsort; + for(pa= sa->panels.first; pa; pa= pa->next) { + if(pa->active && pa->paneltab==NULL) { + ps->pa= MEM_dupallocN(pa); + ps->orig= pa; + ps++; + } + } + + if(sbuts->align==BUT_VERTICAL) + qsort(panelsort, tot, sizeof(PanelSort), find_highest_panel); + else + qsort(panelsort, tot, sizeof(PanelSort), find_leftmost_panel); + + + /* no smart other default start loc! this keeps switching f5/f6/etc compatible */ + ps= panelsort; + ps->pa->ofsx= 0; + ps->pa->ofsy= 0; + + for(a=0 ; a<tot-1; a++, ps++) { + psnext= ps+1; + + if(sbuts->align==BUT_VERTICAL) { + psnext->pa->ofsx = ps->pa->ofsx; + psnext->pa->ofsy = get_panel_real_ofsy(ps->pa) - psnext->pa->sizey-PNL_HEADER-PNL_DIST; + } + else { + psnext->pa->ofsx = get_panel_real_ofsx(ps->pa)+PNL_DIST; + psnext->pa->ofsy = ps->pa->ofsy; + } + } + + /* we interpolate */ + done= 0; + ps= panelsort; + for(a=0; a<tot; a++, ps++) { + if( (ps->pa->flag & PNL_SELECT)==0) { + if( (ps->orig->ofsx != ps->pa->ofsx) || (ps->orig->ofsy != ps->pa->ofsy)) { + ps->orig->ofsx= floor(0.5 + fac*ps->pa->ofsx + (1.0-fac)*ps->orig->ofsx); + ps->orig->ofsy= floor(0.5 + fac*ps->pa->ofsy + (1.0-fac)*ps->orig->ofsy); + done= 1; + } + } + } + + /* copy locations to tabs */ + for(pa= sa->panels.first; pa; pa= pa->next) { + if(pa->paneltab && pa->active) { + copy_panel_offset(pa, pa->paneltab); + } + } + + /* free panelsort array */ + ps= panelsort; + for(a=0; a<tot; a++, ps++) { + MEM_freeN(ps->pa); + } + MEM_freeN(panelsort); + + return done; +} + + +static void ui_animate_panels(ScrArea *sa) +{ + double time=0, ltime; + float result= 0.0, fac= 0.2; + + ltime = PIL_check_seconds_timer(); + + /* for max 1 second, interpolate positions */ + while(TRUE) { + + if( uiAlignPanelStep(sa, fac) ) { + /* warn: this re-allocs uiblocks! */ + scrarea_do_windraw(curarea); + ui_redraw_select_panel(curarea); + screen_swapbuffers(); + } + else { + addqueue(curarea->win, REDRAW,1 ); // because 'Animate' is also called as redraw + break; + } + + if(result >= 1.0) break; + + if(result==0.0) { // firsttime + time = PIL_check_seconds_timer()-ltime; + if(time > 0.5) fac= 0.7; + else if(time > 0.2) fac= 0.5; + else if(time > 0.1) fac= 0.4; + else if(time > 0.05) fac= 0.3; // 11 steps + } + + result= fac + (1.0-fac)*result; + + if(result > 0.98) { + result= 1.0; + fac= 1.0; + } + } +} + +/* only draws blocks with panels */ +void uiDrawBlocksPanels(ScrArea *sa, int re_align) +{ + uiBlock *block; + Panel *panot, *panew, *patest; + + /* scaling contents */ + block= sa->uiblocks.first; + while(block) { + if(block->panel) ui_scale_panel_block(block); + block= block->next; + } + + /* consistancy; are panels not made, whilst they have tabs */ + for(panot= sa->panels.first; panot; panot= panot->next) { + if(panot->active==0) { // not made + + for(panew= sa->panels.first; panew; panew= panew->next) { + if(panew->active) { + if(panew->paneltab==panot) { // panew is tab in notmade pa + break; + } + } + } + /* now panew can become the new parent, check all other tabs */ + if(panew) { + for(patest= sa->panels.first; patest; patest= patest->next) { + if(patest->paneltab == panot) { + patest->paneltab= panew; + } + } + panot->paneltab= panew; + panew->paneltab= NULL; + addqueue(sa->win, REDRAW, 1); // the buttons panew were not made + } + } + } + + /* re-align */ + if(re_align) uiAlignPanelStep(sa, 1.0); + + /* draw */ + block= sa->uiblocks.first; + while(block) { + if(block->panel) uiDrawBlock(block); + block= block->next; + } + +} + + + +/* ------------ panel merging ---------------- */ + +static void check_panel_overlap(ScrArea *sa, Panel *panel) +{ + Panel *pa= sa->panels.first; + + /* also called with panel==NULL for clear */ + + while(pa) { + pa->flag &= ~PNL_OVERLAP; + if(panel && (pa != panel)) { + if(pa->paneltab==NULL && pa->active) { + float safex= 0.2, safey= 0.2; + + if( pa->flag & PNL_CLOSEDX) safex= 0.05; + else if(pa->flag & PNL_CLOSEDY) safey= 0.05; + else if( panel->flag & PNL_CLOSEDX) safex= 0.05; + else if(panel->flag & PNL_CLOSEDY) safey= 0.05; + + if( pa->ofsx > panel->ofsx- safex*panel->sizex) + if( pa->ofsx+pa->sizex < panel->ofsx+ (1.0+safex)*panel->sizex) + if( pa->ofsy > panel->ofsy- safey*panel->sizey) + if( pa->ofsy+pa->sizey < panel->ofsy+ (1.0+safey)*panel->sizey) + pa->flag |= PNL_OVERLAP; + } + } + + pa= pa->next; + } +} + +static void test_add_new_tabs(ScrArea *sa) +{ + Panel *pa, *pasel=NULL, *palap=NULL; + /* search selected and overlapped panel */ + + pa= sa->panels.first; + while(pa) { + if(pa->active) { + if(pa->flag & PNL_SELECT) pasel= pa; + if(pa->flag & PNL_OVERLAP) palap= pa; + } + pa= pa->next; + } + + if(pasel && palap==NULL) { + + /* copy locations */ + pa= sa->panels.first; + while(pa) { + if(pa->paneltab==pasel) { + copy_panel_offset(pa, pasel); + } + pa= pa->next; + } + } + + if(pasel==NULL || palap==NULL) return; + + /* the overlapped panel becomes a tab */ + palap->paneltab= pasel; + + /* the selected panel gets coords of overlapped one */ + copy_panel_offset(pasel, palap); + + /* and its tabs */ + pa= sa->panels.first; + while(pa) { + if(pa->paneltab == pasel) { + copy_panel_offset(pa, palap); + } + pa= pa->next; + } + + /* but, the overlapped panel already can have tabs too! */ + pa= sa->panels.first; + while(pa) { + if(pa->paneltab == palap) { + pa->paneltab = pasel; + } + pa= pa->next; + } +} + +/* ------------ panel drag ---------------- */ + + +void ui_drag_panel(uiBlock *block) +{ + Panel *panel= block->panel; + short align=0, first=1, ofsx, ofsy, dx=0, dy=0, dxo=0, dyo=0, mval[2], mvalo[2]; + + if(curarea->spacetype==SPACE_BUTS) { + SpaceButs *sbuts= curarea->spacedata.first; + align= sbuts->align; + } + + uiGetMouse(block->win, mvalo); + ofsx= block->panel->ofsx; + ofsy= block->panel->ofsy; + + panel->flag |= PNL_SELECT; + + while(TRUE) { + + if( !(get_mbut() & L_MOUSE) ) break; + + /* first clip for window, no dragging outside */ + getmouseco_areawin(mval); + if( mval[0]>0 && mval[0]<curarea->winx && mval[1]>0 && mval[1]<curarea->winy) { + uiGetMouse(mywinget(), mval); + dx= (mval[0]-mvalo[0]) & ~(PNL_GRID-1); + dy= (mval[1]-mvalo[1]) & ~(PNL_GRID-1); + } + + if(dx!=dxo || dy!=dyo || first || align) { + dxo= dx; dyo= dy; + first= 0; + + panel->ofsx = ofsx+dx; + panel->ofsy = ofsy+dy; + + check_panel_overlap(curarea, panel); + + if(align) uiAlignPanelStep(curarea, 0.2); + + /* warn: this re-allocs blocks! */ + scrarea_do_windraw(curarea); + ui_redraw_select_panel(curarea); + screen_swapbuffers(); + + /* so, we find the new block */ + block= curarea->uiblocks.first; + while(block) { + if(block->panel == panel) break; + block= block->next; + } + // temporal debug + if(block==NULL) { + printf("block null while panel drag, should not happen\n"); + } + + /* restore */ + Mat4CpyMat4(UIwinmat, block->winmat); + + /* idle for align */ + if(dx==dxo && dy==dyo) PIL_sleep_ms(30); + } + /* idle for this poor code */ + else PIL_sleep_ms(30); + } + + test_add_new_tabs(curarea); // also copies locations of tabs in dragged panel + + panel->flag &= ~PNL_SELECT; + check_panel_overlap(curarea, NULL); // clears + + if(align==0) addqueue(block->win, REDRAW, 1); + else ui_animate_panels(curarea); +} + + +static void ui_panel_untab(uiBlock *block) +{ + Panel *panel= block->panel, *pa, *panew=NULL; + short nr, mval[2], mvalo[2]; + + /* while hold mouse, check for movement, then untab */ + + uiGetMouse(block->win, mvalo); + while(TRUE) { + + if( !(get_mbut() & L_MOUSE) ) break; + uiGetMouse(mywinget(), mval); + + if( abs(mval[0]-mvalo[0]) + abs(mval[1]-mvalo[1]) > 6 ) { + /* find new parent panel */ + nr= 0; + pa= curarea->panels.first; + while(pa) { + if(pa->paneltab==panel) { + panew= pa; + nr++; + } + pa= pa->next; + } + + /* make old tabs point to panew */ + if(panew==NULL) printf("panel untab: shouldnt happen\n"); + panew->paneltab= NULL; + + pa= curarea->panels.first; + while(pa) { + if(pa->paneltab==panel) { + pa->paneltab= panew; + } + pa= pa->next; + } + + ui_drag_panel(block); + break; + + } + /* idle for this poor code */ + else PIL_sleep_ms(50); + + } + +} + +/* ------------ panel events ---------------- */ + + +static void panel_clicked_tabs(uiBlock *block, int mousex) +{ + Panel *pa, *tabsel=NULL, *panel= block->panel; + int nr= 1, a, width; + + /* count */ + pa= curarea->panels.first; + while(pa) { + if(pa!=panel) { + if(pa->paneltab==panel) nr++; + } + pa= pa->next; + } + + if(nr==1) return; + + /* find clicked tab, mouse in panel coords */ + a= 0; + width= (panel->sizex - 3- 2*PNL_ICON)/nr; + pa= curarea->panels.first; + while(pa) { + if(pa==panel || pa->paneltab==panel) { + if( (mousex > PNL_ICON+a*width) && (mousex < PNL_ICON+(a+1)*width) ) { + tabsel= pa; + } + a++; + } + pa= pa->next; + } + + if(tabsel) { + + if(tabsel == panel) { + ui_panel_untab(block); + } + else { + /* tabsel now becomes parent for all others */ + panel->paneltab= tabsel; + tabsel->paneltab= NULL; + + pa= curarea->panels.first; + while(pa) { + if(pa->paneltab == panel) pa->paneltab = tabsel; + pa= pa->next; + } + + addqueue(curarea->win, REDRAW, 1); + } + } + +} + + +/* this function is supposed to call general window drawing too */ +/* also it supposes a block has panel, and isnt a menu */ +void ui_do_panel(uiBlock *block, uiEvent *uevent) +{ + Panel *pa; + int align= 0; + + if(curarea->spacetype==SPACE_BUTS) { + SpaceButs *sbuts= curarea->spacedata.first; + align= sbuts->align; + } + + /* mouse coordinates in panel space! */ + + if(uevent->event==LEFTMOUSE && block->panel->paneltab==NULL) { + int button= 0; + + /* check open/closed button */ + if(block->panel->flag & PNL_CLOSEDX) { + if(uevent->mval[1] >= block->maxy) button= 1; + } + else if(uevent->mval[0] <= block->minx+PNL_ICON+3) button= 1; + + if(button) { + if(block->panel->flag & PNL_CLOSED) block->panel->flag &= ~PNL_CLOSED; + else if(align==BUT_HORIZONTAL) block->panel->flag |= PNL_CLOSEDX; + else block->panel->flag |= PNL_CLOSEDY; + + for(pa= curarea->panels.first; pa; pa= pa->next) { + if(pa->paneltab==block->panel) { + if(block->panel->flag & PNL_CLOSED) pa->flag |= PNL_CLOSED; + else pa->flag &= ~PNL_CLOSED; + } + } + if(align==0) addqueue(block->win, REDRAW, 1); + else ui_animate_panels(curarea); + + } + else if(block->panel->flag & PNL_CLOSED) { + ui_drag_panel(block); + } + /* check if clicked in tabbed area */ + else if(uevent->mval[0] < block->maxx-PNL_ICON-3 && panel_has_tabs(block->panel)) { + panel_clicked_tabs(block, uevent->mval[0]); + } + else { + ui_drag_panel(block); + } + } +} + + |