- Modifier Panel, name label for "Virtual" modifiers was too short - On extrude Bones, "soft distance" now is always set based on length of the bone (also on CTRL+click, also when Envelope drawmode is not set) - Added undo-push for "Apply Bone Envelopees to VertexGroup" in WeightPaint. - Menu-buttons in floating panels sometimes gave drawing error - InfoWindow buttons were always allocated & drawn, even when window was zero sized... waste of cpu, tsk!
1824 lines
44 KiB
C
1824 lines
44 KiB
C
/**
|
||
* $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>
|
||
#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"
|
||
|
||
// globals
|
||
extern float UIwinmat[4][4];
|
||
|
||
// internal prototypes
|
||
static void stow_unstow(uiBlock *block);
|
||
|
||
|
||
/* --------- generic helper drawng calls ---------------- */
|
||
|
||
|
||
#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(int mode, 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;
|
||
}
|
||
|
||
glBegin(mode);
|
||
|
||
/* 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);
|
||
|
||
glEnd();
|
||
}
|
||
|
||
static void round_box_shade_col(float *col1, float *col2, float fac)
|
||
{
|
||
float col[3];
|
||
|
||
col[0]= (fac*col1[0] + (1.0-fac)*col2[0]);
|
||
col[1]= (fac*col1[1] + (1.0-fac)*col2[1]);
|
||
col[2]= (fac*col1[2] + (1.0-fac)*col2[2]);
|
||
|
||
glColor3fv(col);
|
||
}
|
||
|
||
/* linear horizontal shade within button or in outline */
|
||
void gl_round_box_shade(int mode, float minx, float miny, float maxx, float maxy, float rad, float shadetop, float shadedown)
|
||
{
|
||
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}};
|
||
float div= maxy-miny;
|
||
float coltop[3], coldown[3], color[4];
|
||
int a;
|
||
|
||
/* mult */
|
||
for(a=0; a<7; a++) {
|
||
vec[a][0]*= rad; vec[a][1]*= rad;
|
||
}
|
||
/* get current color, needs to be outside of glBegin/End */
|
||
glGetFloatv(GL_CURRENT_COLOR, color);
|
||
|
||
/* 'shade' defines strength of shading */
|
||
coltop[0]= color[0]+shadetop; if(coltop[0]>1.0) coltop[0]= 1.0;
|
||
coltop[1]= color[1]+shadetop; if(coltop[1]>1.0) coltop[1]= 1.0;
|
||
coltop[2]= color[2]+shadetop; if(coltop[2]>1.0) coltop[2]= 1.0;
|
||
coldown[0]= color[0]+shadedown; if(coldown[0]<0.0) coldown[0]= 0.0;
|
||
coldown[1]= color[1]+shadedown; if(coldown[1]<0.0) coldown[1]= 0.0;
|
||
coldown[2]= color[2]+shadedown; if(coldown[2]<0.0) coldown[2]= 0.0;
|
||
|
||
glShadeModel(GL_SMOOTH);
|
||
glBegin(mode);
|
||
|
||
/* start with corner right-bottom */
|
||
if(roundboxtype & 4) {
|
||
|
||
round_box_shade_col(coltop, coldown, 0.0);
|
||
glVertex2f( maxx-rad, miny);
|
||
|
||
for(a=0; a<7; a++) {
|
||
round_box_shade_col(coltop, coldown, vec[a][1]/div);
|
||
glVertex2f( maxx-rad+vec[a][0], miny+vec[a][1]);
|
||
}
|
||
|
||
round_box_shade_col(coltop, coldown, rad/div);
|
||
glVertex2f( maxx, miny+rad);
|
||
}
|
||
else {
|
||
round_box_shade_col(coltop, coldown, 0.0);
|
||
glVertex2f( maxx, miny);
|
||
}
|
||
|
||
/* corner right-top */
|
||
if(roundboxtype & 2) {
|
||
|
||
round_box_shade_col(coltop, coldown, (div-rad)/div);
|
||
glVertex2f( maxx, maxy-rad);
|
||
|
||
for(a=0; a<7; a++) {
|
||
round_box_shade_col(coltop, coldown, (div-rad+vec[a][1])/div);
|
||
glVertex2f( maxx-vec[a][1], maxy-rad+vec[a][0]);
|
||
}
|
||
round_box_shade_col(coltop, coldown, 1.0);
|
||
glVertex2f( maxx-rad, maxy);
|
||
}
|
||
else {
|
||
round_box_shade_col(coltop, coldown, 1.0);
|
||
glVertex2f( maxx, maxy);
|
||
}
|
||
|
||
/* corner left-top */
|
||
if(roundboxtype & 1) {
|
||
|
||
round_box_shade_col(coltop, coldown, 1.0);
|
||
glVertex2f( minx+rad, maxy);
|
||
|
||
for(a=0; a<7; a++) {
|
||
round_box_shade_col(coltop, coldown, (div-vec[a][1])/div);
|
||
glVertex2f( minx+rad-vec[a][0], maxy-vec[a][1]);
|
||
}
|
||
|
||
round_box_shade_col(coltop, coldown, (div-rad)/div);
|
||
glVertex2f( minx, maxy-rad);
|
||
}
|
||
else {
|
||
round_box_shade_col(coltop, coldown, 1.0);
|
||
glVertex2f( minx, maxy);
|
||
}
|
||
|
||
/* corner left-bottom */
|
||
if(roundboxtype & 8) {
|
||
|
||
round_box_shade_col(coltop, coldown, rad/div);
|
||
glVertex2f( minx, miny+rad);
|
||
|
||
for(a=0; a<7; a++) {
|
||
round_box_shade_col(coltop, coldown, (rad-vec[a][1])/div);
|
||
glVertex2f( minx+vec[a][1], miny+rad-vec[a][0]);
|
||
}
|
||
|
||
round_box_shade_col(coltop, coldown, 0.0);
|
||
glVertex2f( minx+rad, miny);
|
||
}
|
||
else {
|
||
round_box_shade_col(coltop, coldown, 0.0);
|
||
glVertex2f( minx, miny);
|
||
}
|
||
|
||
glEnd();
|
||
glShadeModel(GL_FLAT);
|
||
}
|
||
|
||
/* only for headers */
|
||
static 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();
|
||
}
|
||
|
||
/* for headers and floating panels */
|
||
void uiRoundBoxEmboss(float minx, float miny, float maxx, float maxy, float rad, int active)
|
||
{
|
||
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 */
|
||
//if(active)
|
||
// gl_round_box_shade(GL_POLYGON, minx, miny, maxx, maxy, rad, 0.10, -0.05);
|
||
// else
|
||
/* shading doesnt work for certain buttons yet (pulldown) need smarter buffer caching (ton) <20>*/
|
||
gl_round_box(GL_POLYGON, minx, miny, maxx, maxy, rad);
|
||
|
||
/* set antialias line */
|
||
glEnable( GL_LINE_SMOOTH );
|
||
glEnable( GL_BLEND );
|
||
glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
|
||
|
||
/* top shade */
|
||
gl_round_box_topshade(minx+1, miny+1, maxx-1, maxy-1, rad);
|
||
|
||
/* total outline */
|
||
if(roundboxtype & UI_RB_ALPHA) glColor4ub(0,0,0, 128); else glColor4ub(0,0,0, 200);
|
||
gl_round_box(GL_LINE_LOOP, minx, miny, maxx, maxy, rad);
|
||
|
||
glDisable( GL_LINE_SMOOTH );
|
||
|
||
/* bottom shade for header down */
|
||
if((roundboxtype & 12)==12) {
|
||
glColor4ub(0,0,0, 80);
|
||
fdrawline(minx+rad-1.0, miny+1.0, maxx-rad+1.0, miny+1.0);
|
||
}
|
||
glDisable( GL_BLEND );
|
||
}
|
||
|
||
|
||
/* 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 );
|
||
|
||
gl_round_box(GL_LINE_LOOP, minx, miny, maxx, maxy, rad);
|
||
|
||
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 */
|
||
gl_round_box(GL_POLYGON, minx, miny, maxx, maxy, rad);
|
||
|
||
/* set antialias line */
|
||
glEnable( GL_LINE_SMOOTH );
|
||
glEnable( GL_BLEND );
|
||
glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
|
||
|
||
gl_round_box(GL_LINE_LOOP, minx, miny, maxx, maxy, rad);
|
||
|
||
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;
|
||
}
|
||
|
||
|
||
|
||
/* 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_control= UI_PNL_TRANSP;
|
||
|
||
void uiPanelControl(int control)
|
||
{
|
||
pnl_control= control;
|
||
}
|
||
|
||
/* another global... */
|
||
static int pnl_handler= 0;
|
||
|
||
void uiSetPanelHandler(int handler)
|
||
{
|
||
pnl_handler= handler;
|
||
}
|
||
|
||
|
||
/* 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) {
|
||
if(pa->sizex != sizex) {
|
||
pa->sizex= sizex;
|
||
pa->ofsy+= (pa->sizey - sizey); // check uiNewPanelHeight()
|
||
pa->sizey= sizey;
|
||
}
|
||
}
|
||
else {
|
||
|
||
/* 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;
|
||
|
||
/* 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;
|
||
block->handler= pnl_handler;
|
||
pa->active= 1;
|
||
pa->control= pnl_control;
|
||
|
||
/* global control over this feature; UI_PNL_TO_MOUSE only called for hotkey panels */
|
||
if(U.uiflag & USER_PANELPINNED);
|
||
else if(pnl_control & UI_PNL_TO_MOUSE) {
|
||
short mval[2];
|
||
|
||
Mat4CpyMat4(UIwinmat, block->winmat); // can be first event here
|
||
uiGetMouse(block->win, mval);
|
||
pa->ofsx= mval[0]-pa->sizex/2;
|
||
pa->ofsy= mval[1]-pa->sizey/2;
|
||
|
||
if(pa->flag & PNL_CLOSED) pa->flag &= ~PNL_CLOSED;
|
||
}
|
||
|
||
if(pnl_control & UI_PNL_UNSTOW) {
|
||
if(pa->flag & PNL_CLOSEDY) {
|
||
pa->flag &= ~PNL_CLOSED;
|
||
stow_unstow(block); // toggles!
|
||
}
|
||
}
|
||
|
||
/* clear ugly globals */
|
||
panel_tabbed= group_tabbed= NULL;
|
||
pnl_handler= 0;
|
||
pnl_control= UI_PNL_TRANSP; // back to default
|
||
|
||
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 ) - 2*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 {
|
||
uiBlock *block;
|
||
|
||
G.v2d->tot.xmin= 0;
|
||
G.v2d->tot.xmax= 1280;
|
||
G.v2d->tot.ymin= 0;
|
||
G.v2d->tot.ymax= 228;
|
||
|
||
/* no panels, but old 'loose' buttons, as in old logic editor */
|
||
for(block= sa->uiblocks.first; block; block= block->next) {
|
||
if(block->win==sa->win) {
|
||
if(block->minx < G.v2d->tot.xmin) G.v2d->tot.xmin= block->minx;
|
||
if(block->maxx > G.v2d->tot.xmax) G.v2d->tot.xmax= block->maxx;
|
||
if(block->miny < G.v2d->tot.ymin) G.v2d->tot.ymin= block->miny;
|
||
if(block->maxy > G.v2d->tot.ymax) G.v2d->tot.ymax= block->maxy;
|
||
}
|
||
}
|
||
}
|
||
|
||
}
|
||
|
||
// make sure the panels are not outside 'tot' area
|
||
void uiMatchPanel_view2d(ScrArea *sa)
|
||
{
|
||
Panel *pa;
|
||
int done=0;
|
||
|
||
pa= sa->panels.first;
|
||
while(pa) {
|
||
if(pa->active) {
|
||
done= 1;
|
||
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;
|
||
}
|
||
if(done==0) {
|
||
uiBlock *block;
|
||
/* no panels, but old 'loose' buttons, as in old logic editor */
|
||
for(block= sa->uiblocks.first; block; block= block->next) {
|
||
if(block->win==sa->win) {
|
||
if(block->minx < G.v2d->tot.xmin) G.v2d->tot.xmin= block->minx;
|
||
if(block->maxx > G.v2d->tot.xmax) G.v2d->tot.xmax= block->maxx;
|
||
if(block->miny < G.v2d->tot.ymin) G.v2d->tot.ymin= block->miny;
|
||
if(block->maxy > G.v2d->tot.ymax) G.v2d->tot.ymax= block->maxy;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
/* extern used by 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 );
|
||
|
||
}
|
||
|
||
/* triangle 'icon' for panel header */
|
||
static void ui_draw_tria_icon(float x, float y, float aspect, char dir)
|
||
{
|
||
BIF_ThemeColor(TH_TEXT_HI);
|
||
|
||
if(dir=='h') {
|
||
ui_draw_anti_tria( x, y+1, x, y+10.0, x+7, y+6.25);
|
||
}
|
||
else {
|
||
ui_draw_anti_tria( x-2, y+8, x+9-2, y+8, x+4.75-2, y+1);
|
||
}
|
||
}
|
||
|
||
static void ui_draw_anti_x(float x1, float y1, float x2, float y2)
|
||
{
|
||
|
||
/* set antialias line */
|
||
glEnable( GL_LINE_SMOOTH );
|
||
glEnable( GL_BLEND );
|
||
glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
|
||
|
||
glLineWidth(2.0);
|
||
|
||
fdrawline(x1, y1, x2, y2);
|
||
fdrawline(x1, y2, x2, y1);
|
||
|
||
glLineWidth(1.0);
|
||
|
||
glDisable( GL_LINE_SMOOTH );
|
||
glDisable( GL_BLEND );
|
||
|
||
}
|
||
|
||
/* x 'icon' for panel header */
|
||
static void ui_draw_x_icon(float x, float y)
|
||
{
|
||
BIF_ThemeColor(TH_TEXT_HI);
|
||
|
||
ui_draw_anti_x( x, y, x+9.375, y+9.375);
|
||
|
||
}
|
||
|
||
#if 0
|
||
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);
|
||
}
|
||
#endif
|
||
|
||
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 & USER_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, pnl_icons;
|
||
char *str;
|
||
|
||
/* count */
|
||
pa= curarea->panels.first;
|
||
while(pa) {
|
||
if(pa->active) {
|
||
if(pa->paneltab==panel) nr++;
|
||
}
|
||
pa= pa->next;
|
||
}
|
||
|
||
pnl_icons= PNL_ICON+8;
|
||
if(panel->control & UI_PNL_CLOSE) pnl_icons+= PNL_ICON;
|
||
|
||
if(nr==1) {
|
||
// full header
|
||
BIF_ThemeColorShade(TH_HEADER, -30);
|
||
uiSetRoundBox(3);
|
||
uiRoundBox(block->minx, block->maxy, block->maxx, block->maxy+PNL_HEADER, 8);
|
||
|
||
/* active tab */
|
||
/* draw text label */
|
||
BIF_ThemeColor(TH_TEXT_HI);
|
||
ui_rasterpos_safe(4.0f+block->minx+pnl_icons, block->maxy+5.0f, block->aspect);
|
||
BIF_DrawString(block->curfont, block->panel->panelname, (U.transopts & USER_TR_BUTTONS));
|
||
return;
|
||
}
|
||
|
||
// tabbed, full header brighter
|
||
//BIF_ThemeColorShade(TH_HEADER, 0);
|
||
//uiSetRoundBox(3);
|
||
//uiRoundBox(block->minx, block->maxy, block->maxx, block->maxy+PNL_HEADER, 8);
|
||
|
||
a= 0;
|
||
width= (panel->sizex - 3 - pnl_icons - PNL_ICON)/nr;
|
||
pa= curarea->panels.first;
|
||
while(pa) {
|
||
if(pa->active==0);
|
||
else if(pa==panel) {
|
||
/* active tab */
|
||
|
||
/* draw the active tab */
|
||
uiSetRoundBox(3);
|
||
BIF_ThemeColorShade(TH_HEADER, -3);
|
||
uiRoundBox(2+pnl_icons+a*width, panel->sizey-1, pnl_icons+(a+1)*width, panel->sizey+PNL_HEADER-3, 8);
|
||
|
||
/* draw the active text label */
|
||
BIF_ThemeColor(TH_TEXT);
|
||
ui_rasterpos_safe(16+pnl_icons+a*width, panel->sizey+4, block->aspect);
|
||
str= ui_block_cut_str(block, pa->panelname, (short)(width-10));
|
||
BIF_DrawString(block->curfont, str, (U.transopts & USER_TR_BUTTONS));
|
||
|
||
a++;
|
||
}
|
||
else if(pa->paneltab==panel) {
|
||
/* draw an inactive tab */
|
||
uiSetRoundBox(3);
|
||
BIF_ThemeColorShade(TH_HEADER, -60);
|
||
uiRoundBox(2+pnl_icons+a*width, panel->sizey, pnl_icons+(a+1)*width, panel->sizey+PNL_HEADER-3, 8);
|
||
|
||
/* draw an inactive tab label */
|
||
BIF_ThemeColorShade(TH_TEXT_HI, -40);
|
||
ui_rasterpos_safe(16+pnl_icons+a*width, panel->sizey+4, block->aspect);
|
||
str= ui_block_cut_str(block, pa->panelname, (short)(width-10));
|
||
BIF_DrawString(block->curfont, str, (U.transopts & USER_TR_BUTTONS));
|
||
|
||
a++;
|
||
}
|
||
pa= pa->next;
|
||
}
|
||
|
||
// dragger
|
||
/*
|
||
uiSetRoundBox(15);
|
||
BIF_ThemeColorShade(TH_HEADER, -70);
|
||
uiRoundBox(panel->sizex-PNL_ICON+5, panel->sizey+5, panel->sizex-5, panel->sizey+PNL_HEADER-5, 5);
|
||
*/
|
||
|
||
}
|
||
|
||
void ui_draw_panel(uiBlock *block)
|
||
{
|
||
Panel *panel= block->panel;
|
||
int ofsx;
|
||
|
||
if(panel->paneltab) return;
|
||
|
||
/* if the panel is minimized vertically:
|
||
* (------)
|
||
*/
|
||
if(panel->flag & PNL_CLOSEDY) {
|
||
/* draw a little rounded box, the size of the header */
|
||
uiSetRoundBox(15);
|
||
BIF_ThemeColorShade(TH_HEADER, -30);
|
||
uiRoundBox(block->minx, block->maxy, block->maxx, block->maxy+PNL_HEADER, 8);
|
||
|
||
/* title */
|
||
ofsx= PNL_ICON+8;
|
||
if(panel->control & UI_PNL_CLOSE) ofsx+= PNL_ICON;
|
||
BIF_ThemeColor(TH_TEXT_HI);
|
||
ui_rasterpos_safe(4+block->minx+ofsx, block->maxy+5, block->aspect);
|
||
BIF_DrawString(block->curfont, panel->panelname, (U.transopts & USER_TR_BUTTONS));
|
||
|
||
/* border */
|
||
if(panel->flag & PNL_SELECT) {
|
||
BIF_ThemeColorShade(TH_HEADER, -120);
|
||
uiRoundRect(block->minx, block->maxy, block->maxx, block->maxy+PNL_HEADER, 8);
|
||
}
|
||
/* if it's being overlapped by a panel being dragged */
|
||
if(panel->flag & PNL_OVERLAP) {
|
||
BIF_ThemeColor(TH_TEXT_HI);
|
||
uiRoundRect(block->minx, block->maxy, block->maxx, block->maxy+PNL_HEADER, 8);
|
||
}
|
||
|
||
}
|
||
/* if the panel is minimized horizontally:
|
||
* /-\
|
||
* |
|
||
* |
|
||
* |
|
||
* \_/
|
||
*/
|
||
else if(panel->flag & PNL_CLOSEDX) {
|
||
char str[4];
|
||
int a, end, ofs;
|
||
|
||
/* draw a little rounded box, the size of the header, rotated 90 deg */
|
||
uiSetRoundBox(15);
|
||
BIF_ThemeColorShade(TH_HEADER, -30);
|
||
uiRoundBox(block->minx, block->miny, block->minx+PNL_HEADER, block->maxy+PNL_HEADER, 8);
|
||
|
||
/* title, only the initial character for now */
|
||
BIF_ThemeColor(TH_TEXT_HI);
|
||
str[1]= 0;
|
||
end= strlen(panel->panelname);
|
||
ofs= 20;
|
||
for(a=0; a<end; a++) {
|
||
str[0]= panel->panelname[a];
|
||
if( isupper(str[0]) ) {
|
||
ui_rasterpos_safe(block->minx+5, block->maxy-ofs, block->aspect);
|
||
BIF_DrawString(block->curfont, str, 0);
|
||
ofs+= 15;
|
||
}
|
||
}
|
||
|
||
/* border */
|
||
if(panel->flag & PNL_SELECT) {
|
||
BIF_ThemeColorShade(TH_HEADER, -120);
|
||
uiRoundRect(block->minx, block->miny, block->minx+PNL_HEADER, block->maxy+PNL_HEADER, 8);
|
||
}
|
||
if(panel->flag & PNL_OVERLAP) {
|
||
BIF_ThemeColor(TH_TEXT_HI);
|
||
uiRoundRect(block->minx, block->miny, block->minx+PNL_HEADER, block->maxy+PNL_HEADER, 8);
|
||
}
|
||
|
||
}
|
||
/* an open panel */
|
||
else {
|
||
/* all panels now... */
|
||
if(panel->control & UI_PNL_SOLID) {
|
||
BIF_ThemeColorShade(TH_HEADER, -30);
|
||
|
||
uiSetRoundBox(3);
|
||
uiRoundBox(block->minx, block->maxy, block->maxx, block->maxy+PNL_HEADER, 8);
|
||
|
||
// blend now for panels in 3d window, test...
|
||
glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
|
||
glEnable(GL_BLEND);
|
||
BIF_ThemeColor4(TH_PANEL);
|
||
|
||
uiSetRoundBox(12);
|
||
uiRoundBox(block->minx, block->miny, block->maxx, block->maxy, 8);
|
||
|
||
// glRectf(block->minx, block->miny, block->maxx, block->maxy);
|
||
|
||
/* shadow */
|
||
/*
|
||
glColor4ub(0, 0, 0, 40);
|
||
|
||
fdrawline(block->minx+2, block->miny-1, block->maxx+1, block->miny-1);
|
||
fdrawline(block->maxx+1, block->miny-1, block->maxx+1, block->maxy+7);
|
||
|
||
glColor4ub(0, 0, 0, 10);
|
||
|
||
fdrawline(block->minx+3, block->miny-2, block->maxx+2, block->miny-2);
|
||
fdrawline(block->maxx+2, block->miny-2, block->maxx+2, block->maxy+6);
|
||
|
||
*/
|
||
|
||
glDisable(GL_BLEND);
|
||
}
|
||
/* floating panel */
|
||
else if(panel->control & UI_PNL_TRANSP) {
|
||
BIF_ThemeColorShade(TH_HEADER, -30);
|
||
uiSetRoundBox(3);
|
||
uiRoundBox(block->minx, block->maxy, block->maxx, block->maxy+PNL_HEADER, 8);
|
||
|
||
glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
|
||
glEnable(GL_BLEND);
|
||
BIF_ThemeColor4(TH_PANEL);
|
||
glRectf(block->minx, block->miny, block->maxx, block->maxy);
|
||
|
||
glDisable(GL_BLEND);
|
||
}
|
||
|
||
/* draw the title, tabs, etc in the header */
|
||
ui_draw_panel_header(block);
|
||
|
||
/* in some occasions, draw a border */
|
||
if(panel->flag & PNL_SELECT) {
|
||
if(panel->control & UI_PNL_SOLID) uiSetRoundBox(15);
|
||
else uiSetRoundBox(3);
|
||
|
||
BIF_ThemeColorShade(TH_HEADER, -120);
|
||
uiRoundRect(block->minx, block->miny, block->maxx, block->maxy+PNL_HEADER, 8);
|
||
}
|
||
if(panel->flag & PNL_OVERLAP) {
|
||
if(panel->control & UI_PNL_SOLID) uiSetRoundBox(15);
|
||
else uiSetRoundBox(3);
|
||
|
||
BIF_ThemeColor(TH_TEXT_HI);
|
||
uiRoundRect(block->minx, block->miny, block->maxx, block->maxy+PNL_HEADER, 8);
|
||
}
|
||
|
||
/* 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 optional close icon */
|
||
|
||
ofsx= 6;
|
||
if(panel->control & UI_PNL_CLOSE) {
|
||
|
||
ui_draw_x_icon(block->minx+2+ofsx, block->maxy+5);
|
||
/*
|
||
if(block->aspect>1.1) glPixelZoom(1.0/block->aspect, 1.0/block->aspect);
|
||
BIF_draw_icon(block->minx+4, block->maxy+3, ICON_PANEL_CLOSE);
|
||
if(block->aspect>1.1) glPixelZoom(1.0, 1.0);
|
||
*/
|
||
ofsx= 22;
|
||
}
|
||
|
||
/* draw collapse icon */
|
||
|
||
if(panel->flag & PNL_CLOSEDY)
|
||
ui_draw_tria_icon(block->minx+6+ofsx, block->maxy+5, block->aspect, 'h');
|
||
else if(panel->flag & PNL_CLOSEDX)
|
||
ui_draw_tria_icon(block->minx+7, block->maxy+2, block->aspect, 'h');
|
||
else
|
||
ui_draw_tria_icon(block->minx+6+ofsx, block->maxy+5, 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;
|
||
|
||
/* note about sorting;
|
||
the sortcounter has a lower value for new panels being added.
|
||
however, that only works to insert a single panel, when more new panels get
|
||
added the coordinates of existing panels and the previously stored to-be-insterted
|
||
panels do not match for sorting */
|
||
|
||
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;
|
||
else if( ps1->pa->sortcounter > ps2->pa->sortcounter) return 1;
|
||
else if( ps1->pa->sortcounter < ps2->pa->sortcounter) 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;
|
||
else if( ps1->pa->sortcounter > ps2->pa->sortcounter) return 1;
|
||
else if( ps1->pa->sortcounter < ps2->pa->sortcounter) 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;
|
||
static int sortcounter= 0;
|
||
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 + ps->pa->sizey - psnext->pa->sizey;
|
||
}
|
||
}
|
||
|
||
/* 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);
|
||
}
|
||
}
|
||
|
||
/* set counter, used for sorting with newly added panels */
|
||
sortcounter++;
|
||
for(pa= sa->panels.first; pa; pa= pa->next) {
|
||
if(pa->active) pa->sortcounter= sortcounter;
|
||
}
|
||
|
||
/* 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);
|
||
|
||
/* clip panels (headers) for non-butspace situations (maybe make optimized event later) */
|
||
if(sa->spacetype!=SPACE_BUTS) {
|
||
SpaceLink *sl= sa->spacedata.first;
|
||
for(block= sa->uiblocks.first; block; block= block->next) {
|
||
if(block->panel && block->panel->active && block->panel->paneltab == NULL) {
|
||
float dx=0.0, dy=0.0, minx, miny, maxx, maxy;
|
||
|
||
minx= sl->blockscale*block->panel->ofsx;
|
||
maxx= sl->blockscale*(block->panel->ofsx+block->panel->sizex);
|
||
miny= sl->blockscale*(block->panel->ofsy+block->panel->sizey);
|
||
maxy= sl->blockscale*(block->panel->ofsy+block->panel->sizey+PNL_HEADER);
|
||
|
||
if(minx<0.0) dx= -minx;
|
||
else if(maxx > (float)sa->winx) dx= sa->winx-maxx;
|
||
if( minx + dx < 0.0) dx= -minx; // when panel cant fit, put it fixed here
|
||
|
||
if(miny<0.0) dy= -miny;
|
||
else if(maxy > (float)sa->winy) dy= sa->winy-maxy;
|
||
if( miny + dy < 0.0) dy= -miny; // when panel cant fit, put it fixed here
|
||
|
||
block->panel->ofsx+= dx/sl->blockscale;
|
||
block->panel->ofsy+= dy/sl->blockscale;
|
||
|
||
/* copy locations */
|
||
for(patest= sa->panels.first; patest; patest= patest->next) {
|
||
if(patest->paneltab==block->panel) copy_panel_offset(patest, block->panel);
|
||
}
|
||
|
||
}
|
||
}
|
||
}
|
||
|
||
/* 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 ---------------- */
|
||
|
||
|
||
static 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);
|
||
}
|
||
}
|
||
|
||
}
|
||
|
||
static void stow_unstow(uiBlock *block)
|
||
{
|
||
SpaceLink *sl= curarea->spacedata.first;
|
||
Panel *pa;
|
||
int ok=0, x, y, width;
|
||
|
||
if(block->panel->flag & PNL_CLOSEDY) { // flag has been set how it should become!
|
||
|
||
width= (curarea->winx-320)/sl->blockscale;
|
||
if(width<5) width= 5;
|
||
|
||
/* find empty spot in bottom */
|
||
for(y=4; y<100; y+= PNL_HEADER+4) {
|
||
for(x=4; x<width; x+= 324) {
|
||
ok= 1;
|
||
/* check overlap with other panels */
|
||
for(pa=curarea->panels.first; pa; pa=pa->next) {
|
||
if(pa!=block->panel && pa->active && pa->paneltab==NULL) {
|
||
if( abs(pa->ofsx-x)<320 ) {
|
||
if( abs(pa->ofsy+pa->sizey-y)<PNL_HEADER+4) ok= 0;
|
||
}
|
||
}
|
||
}
|
||
|
||
if(ok) break;
|
||
}
|
||
if(ok) break;
|
||
}
|
||
if(ok==0) printf("still primitive code... fix!\n");
|
||
|
||
block->panel->old_ofsx= block->panel->ofsx;
|
||
block->panel->old_ofsy= block->panel->ofsy;
|
||
|
||
block->panel->ofsx= x;
|
||
block->panel->ofsy= y-block->panel->sizey;
|
||
|
||
}
|
||
else {
|
||
block->panel->ofsx= block->panel->old_ofsx;
|
||
block->panel->ofsy= block->panel->old_ofsy;
|
||
|
||
}
|
||
/* copy locations */
|
||
for(pa= curarea->panels.first; pa; pa= pa->next) {
|
||
if(pa->paneltab==block->panel) copy_panel_offset(pa, block->panel);
|
||
}
|
||
|
||
}
|
||
|
||
|
||
/* 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/collapsed button */
|
||
if(block->panel->flag & PNL_CLOSEDX) {
|
||
if(uevent->mval[1] >= block->maxy) button= 1;
|
||
}
|
||
else if(block->panel->control & UI_PNL_CLOSE) {
|
||
if(uevent->mval[0] <= block->minx+PNL_ICON-2) button= 2;
|
||
else if(uevent->mval[0] <= block->minx+2*PNL_ICON+2) button= 1;
|
||
}
|
||
else if(uevent->mval[0] <= block->minx+PNL_ICON+2) {
|
||
button= 1;
|
||
}
|
||
|
||
if(button) {
|
||
|
||
if(button==2) { // close
|
||
rem_blockhandler(curarea, block->handler);
|
||
addqueue(curarea->win, REDRAW, 1);
|
||
}
|
||
else {
|
||
|
||
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;
|
||
}
|
||
}
|
||
// extra, for non-butspace: open/collapse at window header
|
||
if(curarea->spacetype!=SPACE_BUTS)
|
||
stow_unstow(block);
|
||
|
||
|
||
}
|
||
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);
|
||
}
|
||
}
|
||
}
|
||
|
||
|