Using the Play button in timeline, now uses an event-driven system to update the animation system and signal windows to redraw. Meaning the full UI remains responsive! Check the new Pulldown "Playback" to set which windows you like to see updated. Same settings is used for LMB 'dragging' frames in Timeline. Implementation notes; - the Icon for 'Pause' (or stop) has to be made yet, I commit this from my laptop... all was coded during a 2 x 5 hour train ride to germany - the anim playback system (ALT+A too) now uses correct "frames per second" as maximum speed. Buttons can be found in 3 places in the UI, also added it as pulldown item - The system works with 'screen handlers', which has been coded with using Python (networked) events or verse in mind too. A doc on that will follow. - the buttons code has been made 'resistant' to animated UIs too, preventing flashing of hilites. - All subloops (like transform) stop playback, with exception of MMB view manipulations. As extra; found tweak to make Textured AA fonts draw without distortion. Looks perfect here on laptop now (like Pixmap fonts) and is 20x faster.
5229 lines
125 KiB
C
5229 lines
125 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 "BMF_Api.h"
|
|
#include "BIF_language.h"
|
|
#ifdef INTERNATIONAL
|
|
#include "FTF_Api.h"
|
|
#endif // INTERNATIONAL
|
|
|
|
#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_resources.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 "BSE_view.h"
|
|
|
|
#include "mydevice.h"
|
|
#include "interface.h"
|
|
#include "blendef.h"
|
|
|
|
/* naming conventions:
|
|
*
|
|
* uiBlahBlah() external function
|
|
* ui_blah_blah() internal function
|
|
*/
|
|
|
|
/***/
|
|
/* ************ GLOBALS ************* */
|
|
|
|
float UIwinmat[4][4];
|
|
static int UIlock= 0, UIafterval;
|
|
static char *UIlockstr=NULL;
|
|
static void (*UIafterfunc)(void *arg, int event);
|
|
static void *UIafterfunc_arg;
|
|
|
|
static uiFont UIfont[UI_ARRAY]; // no init needed
|
|
uiBut *UIbuttip;
|
|
|
|
/* ************* PROTOTYPES ***************** */
|
|
|
|
static void ui_set_but_val(uiBut *but, double value);
|
|
static void ui_set_ftf_font(uiBlock *block);
|
|
static void ui_do_but_tip(uiBut *buttip);
|
|
|
|
/* ****************************** */
|
|
|
|
static int uibut_contains_pt(uiBut *but, short *pt)
|
|
{
|
|
return ((but->x1<pt[0] && but->x2>=pt[0]) &&
|
|
(but->y1<pt[1] && but->y2>=pt[1]));
|
|
}
|
|
|
|
static void uibut_do_func(uiBut *but)
|
|
{
|
|
if (but->func) {
|
|
but->func(but->func_arg1, but->func_arg2);
|
|
}
|
|
}
|
|
|
|
/* ************* window matrix ************** */
|
|
|
|
|
|
void ui_graphics_to_window(int win, float *x, float *y) /* for rectwrite */
|
|
{
|
|
float gx, gy;
|
|
int sx, sy;
|
|
int getsizex, getsizey;
|
|
|
|
bwin_getsize(win, &getsizex, &getsizey);
|
|
bwin_getsuborigin(win, &sx, &sy);
|
|
|
|
gx= *x;
|
|
gy= *y;
|
|
*x= ((float)sx) + ((float)getsizex)*(0.5+ 0.5*(gx*UIwinmat[0][0]+ gy*UIwinmat[1][0]+ UIwinmat[3][0]));
|
|
*y= ((float)sy) + ((float)getsizey)*(0.5+ 0.5*(gx*UIwinmat[0][1]+ gy*UIwinmat[1][1]+ UIwinmat[3][1]));
|
|
}
|
|
|
|
|
|
|
|
void ui_window_to_graphics(int win, float *x, float *y) /* for mouse cursor */
|
|
{
|
|
float a, b, c, d, e, f, px, py;
|
|
int getsizex, getsizey;
|
|
|
|
bwin_getsize(win, &getsizex, &getsizey);
|
|
|
|
a= .5*((float)getsizex)*UIwinmat[0][0];
|
|
b= .5*((float)getsizex)*UIwinmat[1][0];
|
|
c= .5*((float)getsizex)*(1.0+UIwinmat[3][0]);
|
|
|
|
d= .5*((float)getsizey)*UIwinmat[0][1];
|
|
e= .5*((float)getsizey)*UIwinmat[1][1];
|
|
f= .5*((float)getsizey)*(1.0+UIwinmat[3][1]);
|
|
|
|
px= *x;
|
|
py= *y;
|
|
|
|
*y= (a*(py-f) + d*(c-px))/(a*e-d*b);
|
|
*x= (px- b*(*y)- c)/a;
|
|
|
|
}
|
|
|
|
|
|
/* ************* SAVE UNDER ************ */
|
|
|
|
/* new method:
|
|
|
|
OverDraw *ui_begin_overdraw(int minx, int miny, int maxx, int maxy);
|
|
- enforces mainwindow to become active
|
|
- grabs copy from frontbuffer, pastes in back
|
|
|
|
void ui_flush_overdraw(OverDraw *od);
|
|
- copies backbuffer to front
|
|
|
|
void ui_refresh_overdraw(Overdraw *od);
|
|
- pastes in back copy of frontbuffer again for fresh drawing
|
|
|
|
void ui_end_overdraw(OverDraw *od);
|
|
- puts back on frontbuffer saved image
|
|
- frees copy
|
|
- sets back active blender area
|
|
- signals backbuffer to be corrupt (sel buffer!)
|
|
|
|
*/
|
|
|
|
/* frontbuffer updates now glCopyPixels too, with block->flush rect */
|
|
|
|
/* new idea for frontbuffer updates:
|
|
|
|
- hilites: with blended poly?
|
|
|
|
- full updates... thats harder, but:
|
|
- copy original
|
|
- before draw, always paste to backbuf
|
|
- flush
|
|
- always end with redraw event for full update
|
|
|
|
*/
|
|
|
|
static void myglCopyPixels(int a, int b, int c, int d, int e)
|
|
{
|
|
if(G.rt==2) {
|
|
unsigned int *buf= MEM_mallocN(4*c*d, "temp glcopypixels");
|
|
glReadPixels(a, b, c, d, GL_RGBA, GL_UNSIGNED_BYTE, buf);
|
|
glDrawPixels(c, d, GL_RGBA, GL_UNSIGNED_BYTE, buf);
|
|
MEM_freeN(buf);
|
|
}
|
|
else glCopyPixels(a, b, c, d, e);
|
|
}
|
|
|
|
typedef struct {
|
|
short x, y, sx, sy, oldwin;
|
|
unsigned int *rect;
|
|
} uiOverDraw;
|
|
|
|
|
|
static uiOverDraw *ui_begin_overdraw(int minx, int miny, int maxx, int maxy)
|
|
{
|
|
uiOverDraw *od=NULL;
|
|
|
|
// dirty patch removed for sun and sgi to mywindow.c commented out
|
|
|
|
/* clip with actual window size */
|
|
if(minx < 0) minx= 0;
|
|
if(miny < 0) miny= 0;
|
|
if(maxx >= G.curscreen->sizex) maxx= G.curscreen->sizex-1;
|
|
if(maxy >= G.curscreen->sizey) maxy= G.curscreen->sizey-1;
|
|
|
|
if(minx<maxx && miny<maxy) {
|
|
od= MEM_callocN(sizeof(uiOverDraw), "overdraw");
|
|
|
|
od->x= minx;
|
|
od->y= miny;
|
|
od->sx= maxx-minx;
|
|
od->sy= maxy-miny;
|
|
od->rect= MEM_mallocN(od->sx*od->sy*4, "temp_frontbuffer_image");
|
|
|
|
od->oldwin= mywinget();
|
|
mywinset(G.curscreen->mainwin);
|
|
/* grab front */
|
|
glReadBuffer(GL_FRONT);
|
|
glReadPixels(od->x, od->y, od->sx, od->sy, GL_RGBA, GL_UNSIGNED_BYTE, od->rect);
|
|
glReadBuffer(GL_BACK);
|
|
/* paste in back */
|
|
glDisable(GL_DITHER);
|
|
glRasterPos2f(od->x, od->y);
|
|
glDrawPixels(od->sx, od->sy, GL_RGBA, GL_UNSIGNED_BYTE, od->rect);
|
|
glEnable(GL_DITHER);
|
|
}
|
|
|
|
return od;
|
|
}
|
|
|
|
static void ui_flush_overdraw(uiOverDraw *od)
|
|
{
|
|
|
|
if(od==NULL) return;
|
|
glDisable(GL_DITHER);
|
|
glReadBuffer(GL_BACK);
|
|
glDrawBuffer(GL_FRONT);
|
|
glRasterPos2s(od->x, od->y);
|
|
myglCopyPixels(od->x, od->y, od->sx, od->sy, GL_COLOR);
|
|
glEnable(GL_DITHER);
|
|
glFlush();
|
|
glDrawBuffer(GL_BACK);
|
|
}
|
|
|
|
/* special flush version to enable transparent menus */
|
|
static void ui_block_flush_overdraw(uiBlock *block)
|
|
{
|
|
|
|
if(block->flag & UI_BLOCK_LOOP) {
|
|
char col[4];
|
|
|
|
BIF_GetThemeColor4ubv(TH_MENU_BACK, col);
|
|
if(col[3]!=255) {
|
|
uiBut *bt;
|
|
uiOverDraw *od= block->overdraw;
|
|
|
|
/* completely draw all! */
|
|
glRasterPos2s(od->x, od->y);
|
|
glDrawPixels(od->sx, od->sy, GL_RGBA, GL_UNSIGNED_BYTE, od->rect);
|
|
|
|
uiDrawMenuBox(block->minx, block->miny, block->maxx, block->maxy, block->flag);
|
|
for (bt= block->buttons.first; bt; bt= bt->next) {
|
|
ui_draw_but(bt);
|
|
}
|
|
}
|
|
}
|
|
|
|
ui_flush_overdraw(block->overdraw);
|
|
}
|
|
|
|
static void ui_end_overdraw(uiOverDraw *od)
|
|
{
|
|
if(od==NULL) return;
|
|
|
|
glDisable(GL_DITHER);
|
|
|
|
// clear in back
|
|
glRasterPos2s(od->x, od->y);
|
|
glDrawPixels(od->sx, od->sy, GL_RGBA, GL_UNSIGNED_BYTE, od->rect);
|
|
|
|
// clear in front
|
|
glDrawBuffer(GL_FRONT);
|
|
glRasterPos2s(od->x, od->y);
|
|
glDrawPixels(od->sx, od->sy, GL_RGBA, GL_UNSIGNED_BYTE, od->rect);
|
|
|
|
glFlush();
|
|
glDrawBuffer(GL_BACK);
|
|
glEnable(GL_DITHER);
|
|
|
|
if(od->oldwin) mywinset(od->oldwin);
|
|
|
|
MEM_freeN(od->rect);
|
|
MEM_freeN(od);
|
|
|
|
markdirty_all_back(); // sets flags only
|
|
}
|
|
|
|
/* ****************** live updates for hilites and button presses *********** */
|
|
|
|
void ui_block_flush_back(uiBlock *block)
|
|
{
|
|
int minx, miny, sizex, sizey;
|
|
|
|
/* note; this routine also has to work for block loop */
|
|
if(block->needflush==0) return;
|
|
|
|
/* exception, when we cannot use backbuffer for draw... */
|
|
if(block->flag & UI_BLOCK_FRONTBUFFER) {
|
|
glFlush();
|
|
glDrawBuffer(GL_BACK);
|
|
block->needflush= 0;
|
|
return;
|
|
}
|
|
|
|
/* copy pixels works on window coords, so we move to window space */
|
|
|
|
ui_graphics_to_window(block->win, &block->flush.xmin, &block->flush.ymin);
|
|
ui_graphics_to_window(block->win, &block->flush.xmax, &block->flush.ymax);
|
|
minx= floor(block->flush.xmin);
|
|
miny= floor(block->flush.ymin);
|
|
sizex= ceil(block->flush.xmax-block->flush.xmin);
|
|
sizey= ceil(block->flush.ymax-block->flush.ymin);
|
|
|
|
if(sizex>0 && sizey>0) {
|
|
glPushMatrix();
|
|
mywinset(G.curscreen->mainwin);
|
|
|
|
glDisable(GL_DITHER);
|
|
glReadBuffer(GL_BACK);
|
|
glDrawBuffer(GL_FRONT);
|
|
glRasterPos2i(minx, miny);
|
|
#ifdef __sun__
|
|
myglCopyPixels(minx, miny+1, sizex, sizey, GL_COLOR);
|
|
#else
|
|
myglCopyPixels(minx, miny, sizex, sizey, GL_COLOR);
|
|
#endif
|
|
glEnable(GL_DITHER);
|
|
glFlush();
|
|
glDrawBuffer(GL_BACK);
|
|
|
|
mywinset(block->win);
|
|
glPopMatrix();
|
|
|
|
markdirty_win_back(block->win);
|
|
}
|
|
|
|
block->needflush= 0;
|
|
}
|
|
|
|
/* merge info for live updates in frontbuf */
|
|
void ui_block_set_flush(uiBlock *block, uiBut *but)
|
|
{
|
|
/* clear signal */
|
|
if(but==NULL) {
|
|
block->needflush= 0;
|
|
|
|
block->flush.xmin= 0.0;
|
|
block->flush.xmax= 0.0;
|
|
}
|
|
else {
|
|
/* exception, when we cannot use backbuffer for draw... */
|
|
if(block->flag & UI_BLOCK_FRONTBUFFER) {
|
|
glDrawBuffer(GL_FRONT);
|
|
}
|
|
else if(block->needflush==0) {
|
|
/* first rect */
|
|
block->flush.xmin= but->x1;
|
|
block->flush.xmax= but->x2;
|
|
block->flush.ymin= but->y1;
|
|
block->flush.ymax= but->y2;
|
|
|
|
}
|
|
else {
|
|
/* union of rects */
|
|
if(block->flush.xmin > but->x1) block->flush.xmin= but->x1;
|
|
if(block->flush.xmax < but->x2) block->flush.xmax= but->x2;
|
|
if(block->flush.ymin > but->y1) block->flush.ymin= but->y1;
|
|
if(block->flush.ymax < but->y2) block->flush.ymax= but->y2;
|
|
}
|
|
|
|
block->needflush= 1;
|
|
|
|
}
|
|
}
|
|
|
|
/* ******************* copy and paste ******************** */
|
|
|
|
/* c = copy, v = paste */
|
|
/* return 1 when something changed */
|
|
static int ui_but_copy_paste(uiBut *but, char mode)
|
|
{
|
|
static char str[256]="";
|
|
static double butval=0.0;
|
|
static float rgb[3];
|
|
void *poin;
|
|
|
|
poin= but->poin;
|
|
|
|
|
|
if ELEM3(but->type, NUM, NUMSLI, HSVSLI) {
|
|
|
|
if(mode=='c') {
|
|
butval= ui_get_but_val(but);
|
|
}
|
|
else {
|
|
ui_set_but_val(but, butval);
|
|
ui_check_but(but);
|
|
return 1;
|
|
}
|
|
}
|
|
else if(but->type==COL) {
|
|
|
|
if(mode=='c') {
|
|
if(but->pointype==FLO) {
|
|
float *fp= (float *) poin;
|
|
rgb[0]= fp[0];
|
|
rgb[1]= fp[1];
|
|
rgb[2]= fp[2];
|
|
}
|
|
else if (but->pointype==CHA) {
|
|
char *cp= (char *) poin;
|
|
rgb[0]= (float)(cp[0]/255.0);
|
|
rgb[1]= (float)(cp[1]/255.0);
|
|
rgb[2]= (float)(cp[2]/255.0);
|
|
}
|
|
|
|
}
|
|
else {
|
|
if(but->pointype==FLO) {
|
|
float *fp= (float *) poin;
|
|
fp[0] = rgb[0];
|
|
fp[1] = rgb[1];
|
|
fp[2] = rgb[2];
|
|
return 1;
|
|
}
|
|
else if (but->pointype==CHA) {
|
|
char *cp= (char *) poin;
|
|
cp[0] = (char)(rgb[0]*255.0);
|
|
cp[1] = (char)(rgb[1]*255.0);
|
|
cp[2] = (char)(rgb[2]*255.0);
|
|
|
|
return 1;
|
|
}
|
|
|
|
}
|
|
}
|
|
else if(but->type==TEX) {
|
|
|
|
if(mode=='c') {
|
|
strncpy(str, but->poin, but->max);
|
|
}
|
|
else {
|
|
strncpy(but->poin, str, but->max);
|
|
uibut_do_func(but);
|
|
ui_check_but(but);
|
|
return 1;
|
|
}
|
|
}
|
|
else if(but->type==IDPOIN) {
|
|
|
|
if(mode=='c') {
|
|
ID *id= *but->idpoin_idpp;
|
|
if(id) strncpy(str, id->name+2, 22);
|
|
}
|
|
else {
|
|
but->idpoin_func(str, but->idpoin_idpp);
|
|
ui_check_but(but);
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
|
|
return 0;
|
|
}
|
|
|
|
/* ******************* block calc ************************* */
|
|
|
|
void uiTextBoundsBlock(uiBlock *block, int addval)
|
|
{
|
|
uiBut *bt;
|
|
int i = 0, j;
|
|
|
|
bt= block->buttons.first;
|
|
while(bt) {
|
|
if(bt->type!=SEPR) {
|
|
int transopts= (U.transopts & USER_TR_BUTTONS);
|
|
if(bt->type==TEX || bt->type==IDPOIN) transopts= 0;
|
|
j= BIF_GetStringWidth(bt->font, bt->drawstr, transopts);
|
|
|
|
if(j > i) i = j;
|
|
}
|
|
bt= bt->next;
|
|
}
|
|
|
|
|
|
bt= block->buttons.first;
|
|
while(bt) {
|
|
bt->x2 = i + addval;
|
|
ui_check_but(bt); // clips text again
|
|
bt= bt->next;
|
|
}
|
|
}
|
|
|
|
|
|
void uiBoundsBlock(uiBlock *block, int addval)
|
|
{
|
|
uiBut *bt;
|
|
int xof;
|
|
|
|
if(block->buttons.first==NULL) {
|
|
if(block->panel) {
|
|
block->minx= 0.0; block->maxx= block->panel->sizex;
|
|
block->miny= 0.0; block->maxy= block->panel->sizey;
|
|
}
|
|
}
|
|
else {
|
|
|
|
block->minx= block->miny= 10000;
|
|
block->maxx= block->maxy= -10000;
|
|
|
|
bt= block->buttons.first;
|
|
while(bt) {
|
|
if(bt->x1 < block->minx) block->minx= bt->x1;
|
|
if(bt->y1 < block->miny) block->miny= bt->y1;
|
|
|
|
if(bt->x2 > block->maxx) block->maxx= bt->x2;
|
|
if(bt->y2 > block->maxy) block->maxy= bt->y2;
|
|
|
|
bt= bt->next;
|
|
}
|
|
|
|
block->minx -= addval;
|
|
block->miny -= addval;
|
|
block->maxx += addval;
|
|
block->maxy += addval;
|
|
}
|
|
|
|
/* hardcoded exception... but that one is annoying with larger safety */
|
|
bt= block->buttons.first;
|
|
if(bt && strncmp(bt->str, "ERROR", 5)==0) xof= 10;
|
|
else xof= 40;
|
|
|
|
block->safety.xmin= block->minx-xof;
|
|
block->safety.ymin= block->miny-xof;
|
|
block->safety.xmax= block->maxx+xof;
|
|
block->safety.ymax= block->maxy+xof;
|
|
}
|
|
|
|
static void ui_positionblock(uiBlock *block, uiBut *but)
|
|
{
|
|
/* position block relative to but */
|
|
uiBut *bt;
|
|
rctf butrct;
|
|
int xsize, ysize, xof=0, yof=0, centre;
|
|
short dir1= 0, dir2=0;
|
|
|
|
/* first transform to screen coords, assuming matrix is stil OK */
|
|
/* the UIwinmat is in panelspace */
|
|
|
|
butrct.xmin= but->x1; butrct.xmax= but->x2;
|
|
butrct.ymin= but->y1; butrct.ymax= but->y2;
|
|
|
|
ui_graphics_to_window(block->win, &butrct.xmin, &butrct.ymin);
|
|
ui_graphics_to_window(block->win, &butrct.xmax, &butrct.ymax);
|
|
block->parentrct= butrct; // will use that for pulldowns later
|
|
|
|
/* calc block rect */
|
|
if(block->buttons.first) {
|
|
block->minx= block->miny= 10000;
|
|
block->maxx= block->maxy= -10000;
|
|
|
|
bt= block->buttons.first;
|
|
while(bt) {
|
|
if(bt->x1 < block->minx) block->minx= bt->x1;
|
|
if(bt->y1 < block->miny) block->miny= bt->y1;
|
|
|
|
if(bt->x2 > block->maxx) block->maxx= bt->x2;
|
|
if(bt->y2 > block->maxy) block->maxy= bt->y2;
|
|
|
|
bt= bt->next;
|
|
}
|
|
}
|
|
else {
|
|
/* we're nice and allow empty blocks too */
|
|
block->minx= block->miny= 0;
|
|
block->maxx= block->maxy= 20;
|
|
}
|
|
|
|
ui_graphics_to_window(block->win, &block->minx, &block->miny);
|
|
ui_graphics_to_window(block->win, &block->maxx, &block->maxy);
|
|
|
|
//block->minx-= 2.0; block->miny-= 2.0;
|
|
//block->maxx+= 2.0; block->maxy+= 2.0;
|
|
|
|
xsize= block->maxx - block->minx+4; // 4 for shadow
|
|
ysize= block->maxy - block->miny+4;
|
|
|
|
if(but) {
|
|
short left=0, right=0, top=0, down=0;
|
|
|
|
if(block->direction & UI_CENTRE) centre= ysize/2;
|
|
else centre= 0;
|
|
|
|
if( butrct.xmin-xsize > 0.0) left= 1;
|
|
if( butrct.xmax+xsize < G.curscreen->sizex) right= 1;
|
|
if( butrct.ymin-ysize+centre > 0.0) down= 1;
|
|
if( butrct.ymax+ysize-centre < G.curscreen->sizey) top= 1;
|
|
|
|
dir1= block->direction & UI_DIRECTION;
|
|
|
|
/* secundary directions */
|
|
if(dir1 & (UI_TOP|UI_DOWN)) {
|
|
if(dir1 & UI_LEFT) dir2= UI_LEFT;
|
|
else if(dir1 & UI_RIGHT) dir2= UI_RIGHT;
|
|
dir1 &= (UI_TOP|UI_DOWN);
|
|
}
|
|
|
|
if(dir2==0) if(dir1==UI_LEFT || dir1==UI_RIGHT) dir2= UI_DOWN;
|
|
if(dir2==0) if(dir1==UI_TOP || dir1==UI_DOWN) dir2= UI_LEFT;
|
|
|
|
/* no space at all? dont change */
|
|
if(left || right) {
|
|
if(dir1==UI_LEFT && left==0) dir1= UI_RIGHT;
|
|
if(dir1==UI_RIGHT && right==0) dir1= UI_LEFT;
|
|
/* this is aligning, not append! */
|
|
if(dir2==UI_LEFT && right==0) dir2= UI_RIGHT;
|
|
if(dir2==UI_RIGHT && left==0) dir2= UI_LEFT;
|
|
}
|
|
if(down || top) {
|
|
if(dir1==UI_TOP && top==0) dir1= UI_DOWN;
|
|
if(dir1==UI_DOWN && down==0) dir1= UI_TOP;
|
|
if(dir2==UI_TOP && top==0) dir2= UI_DOWN;
|
|
if(dir2==UI_DOWN && down==0) dir2= UI_TOP;
|
|
}
|
|
|
|
if(dir1==UI_LEFT) {
|
|
xof= butrct.xmin - block->maxx;
|
|
if(dir2==UI_TOP) yof= butrct.ymin - block->miny-centre;
|
|
else yof= butrct.ymax - block->maxy+centre;
|
|
}
|
|
else if(dir1==UI_RIGHT) {
|
|
xof= butrct.xmax - block->minx;
|
|
if(dir2==UI_TOP) yof= butrct.ymin - block->miny-centre;
|
|
else yof= butrct.ymax - block->maxy+centre;
|
|
}
|
|
else if(dir1==UI_TOP) {
|
|
yof= butrct.ymax - block->miny;
|
|
if(dir2==UI_RIGHT) xof= butrct.xmax - block->maxx;
|
|
else xof= butrct.xmin - block->minx;
|
|
// changed direction?
|
|
if((dir1 & block->direction)==0) {
|
|
if(block->direction & UI_SHIFT_FLIPPED)
|
|
xof+= dir2==UI_LEFT?25:-25;
|
|
uiBlockFlipOrder(block);
|
|
}
|
|
}
|
|
else if(dir1==UI_DOWN) {
|
|
yof= butrct.ymin - block->maxy;
|
|
if(dir2==UI_RIGHT) xof= butrct.xmax - block->maxx;
|
|
else xof= butrct.xmin - block->minx;
|
|
// changed direction?
|
|
if((dir1 & block->direction)==0) {
|
|
if(block->direction & UI_SHIFT_FLIPPED)
|
|
xof+= dir2==UI_LEFT?25:-25;
|
|
uiBlockFlipOrder(block);
|
|
}
|
|
}
|
|
|
|
/* and now we handle the exception; no space below or to right */
|
|
if(top==0 && down==0) {
|
|
if(dir1==UI_LEFT || dir1==UI_RIGHT) {
|
|
// align with bottom of screen
|
|
yof= ysize;
|
|
}
|
|
}
|
|
|
|
// apply requested offset in the block
|
|
xof += block->xofs/block->aspect;
|
|
yof += block->yofs/block->aspect;
|
|
|
|
}
|
|
|
|
/* apply */
|
|
bt= block->buttons.first;
|
|
while(bt) {
|
|
|
|
ui_graphics_to_window(block->win, &bt->x1, &bt->y1);
|
|
ui_graphics_to_window(block->win, &bt->x2, &bt->y2);
|
|
|
|
bt->x1 += xof;
|
|
bt->x2 += xof;
|
|
bt->y1 += yof;
|
|
bt->y2 += yof;
|
|
|
|
bt->aspect= 1.0;
|
|
// ui_check_but recalculates drawstring size in pixels
|
|
ui_check_but(bt);
|
|
|
|
bt= bt->next;
|
|
}
|
|
|
|
block->minx += xof;
|
|
block->miny += yof;
|
|
block->maxx += xof;
|
|
block->maxy += yof;
|
|
|
|
/* safety calculus */
|
|
if(but) {
|
|
float midx= (block->parentrct.xmin+block->parentrct.xmax)/2.0;
|
|
float midy= (block->parentrct.ymin+block->parentrct.ymax)/2.0;
|
|
|
|
/* when you are outside parent button, safety there should be smaller */
|
|
|
|
// parent button to left
|
|
if( midx < block->minx ) block->safety.xmin= block->minx-3;
|
|
else block->safety.xmin= block->minx-40;
|
|
// parent button to right
|
|
if( midx > block->maxx ) block->safety.xmax= block->maxx+3;
|
|
else block->safety.xmax= block->maxx+40;
|
|
|
|
// parent button on bottom
|
|
if( midy < block->miny ) block->safety.ymin= block->miny-3;
|
|
else block->safety.ymin= block->miny-40;
|
|
// parent button on top
|
|
if( midy > block->maxy ) block->safety.ymax= block->maxy+3;
|
|
else block->safety.ymax= block->maxy+40;
|
|
|
|
// exception for switched pulldowns...
|
|
if(dir1 && (dir1 & block->direction)==0) {
|
|
if(dir2==UI_RIGHT) block->safety.xmax= block->maxx+3;
|
|
if(dir2==UI_LEFT) block->safety.xmin= block->minx-3;
|
|
}
|
|
block->direction= dir1;
|
|
}
|
|
else {
|
|
block->safety.xmin= block->minx-40;
|
|
block->safety.ymin= block->miny-40;
|
|
block->safety.xmax= block->maxx+40;
|
|
block->safety.ymax= block->maxy+40;
|
|
}
|
|
|
|
}
|
|
|
|
|
|
void ui_autofill(uiBlock *block)
|
|
{
|
|
uiBut *but;
|
|
float *maxw, *maxh, startx = 0, starty, height = 0;
|
|
float totmaxh;
|
|
int rows=0, /* cols=0, */ i, lasti;
|
|
|
|
/* first count rows */
|
|
but= block->buttons.last;
|
|
rows= but->x1+1;
|
|
|
|
/* calculate max width / height for each row */
|
|
maxw= MEM_callocN(sizeof(float)*rows, "maxw");
|
|
maxh= MEM_callocN(sizeof(float)*rows, "maxh");
|
|
but= block->buttons.first;
|
|
while(but) {
|
|
i= but->x1;
|
|
if( maxh[i] < but->y2) maxh[i]= but->y2;
|
|
maxw[i] += but->x2;
|
|
but= but->next;
|
|
}
|
|
|
|
totmaxh= 0.0;
|
|
for(i=0; i<rows; i++) totmaxh+= maxh[i];
|
|
|
|
/* apply widths/heights */
|
|
starty= block->maxy;
|
|
but= block->buttons.first;
|
|
lasti= -1;
|
|
while(but) {
|
|
// signal for aligning code
|
|
but->flag |= UI_BUT_ALIGN_DOWN;
|
|
|
|
i= but->x1;
|
|
|
|
if(i!=lasti) {
|
|
startx= block->minx;
|
|
height= (maxh[i]*(block->maxy-block->miny))/totmaxh;
|
|
starty-= height;
|
|
lasti= i;
|
|
}
|
|
|
|
but->y1= starty+but->aspect;
|
|
but->y2= but->y1+height-but->aspect;
|
|
|
|
but->x2= (but->x2*(block->maxx-block->minx))/maxw[i];
|
|
but->x1= startx+but->aspect;
|
|
|
|
startx+= but->x2;
|
|
but->x2+= but->x1-but->aspect;
|
|
|
|
ui_check_but(but);
|
|
|
|
but= but->next;
|
|
}
|
|
|
|
uiBlockEndAlign(block);
|
|
|
|
MEM_freeN(maxw); MEM_freeN(maxh);
|
|
block->autofill= 0;
|
|
}
|
|
|
|
/* ************** LINK LINE DRAWING ************* */
|
|
|
|
/* link line drawing is not part of buttons or theme.. so we stick with it here */
|
|
|
|
static void ui_draw_linkline(uiBut *but, uiLinkLine *line)
|
|
{
|
|
float vec1[2], vec2[2];
|
|
|
|
if(line->from==NULL || line->to==NULL) return;
|
|
|
|
vec1[0]= (line->from->x1+line->from->x2)/2.0;
|
|
vec1[1]= (line->from->y1+line->from->y2)/2.0;
|
|
vec2[0]= (line->to->x1+line->to->x2)/2.0;
|
|
vec2[1]= (line->to->y1+line->to->y2)/2.0;
|
|
|
|
if(line->flag & UI_SELECT) BIF_ThemeColorShade(but->themecol, 80);
|
|
else glColor3ub(0,0,0);
|
|
fdrawline(vec1[0], vec1[1], vec2[0], vec2[1]);
|
|
}
|
|
|
|
static void ui_draw_links(uiBlock *block)
|
|
{
|
|
uiBut *but;
|
|
uiLinkLine *line;
|
|
|
|
but= block->buttons.first;
|
|
while(but) {
|
|
if(but->type==LINK && but->link) {
|
|
line= but->link->lines.first;
|
|
while(line) {
|
|
ui_draw_linkline(but, line);
|
|
line= line->next;
|
|
}
|
|
}
|
|
but= but->next;
|
|
}
|
|
}
|
|
|
|
/* ************** BLOCK DRAWING FUNCTION ************* */
|
|
|
|
|
|
void uiDrawBlock(uiBlock *block)
|
|
{
|
|
uiBut *but;
|
|
short testmouse=0, mouse[2];
|
|
|
|
/* handle pending stuff */
|
|
if(block->autofill) ui_autofill(block);
|
|
if(block->minx==0.0 && block->maxx==0.0) uiBoundsBlock(block, 0);
|
|
if(block->flag & UI_BUT_ALIGN) uiBlockEndAlign(block);
|
|
|
|
/* we set active flag on a redraw again */
|
|
if((block->flag & UI_BLOCK_LOOP)==0) {
|
|
testmouse= 1;
|
|
Mat4CpyMat4(UIwinmat, block->winmat);
|
|
uiGetMouse(block->win, mouse);
|
|
}
|
|
|
|
uiPanelPush(block); // panel matrix
|
|
|
|
if(block->flag & UI_BLOCK_LOOP) {
|
|
uiDrawMenuBox(block->minx, block->miny, block->maxx, block->maxy, block->flag);
|
|
}
|
|
else {
|
|
if(block->panel) ui_draw_panel(block);
|
|
}
|
|
|
|
if(block->drawextra) block->drawextra();
|
|
|
|
for (but= block->buttons.first; but; but= but->next) {
|
|
|
|
if(testmouse && uibut_contains_pt(but, mouse))
|
|
but->flag |= UI_ACTIVE;
|
|
else
|
|
but->flag &= ~UI_ACTIVE;
|
|
|
|
ui_draw_but(but);
|
|
}
|
|
|
|
ui_draw_links(block);
|
|
|
|
uiPanelPop(block); // matrix restored
|
|
}
|
|
|
|
/* ************* MENUBUTS *********** */
|
|
|
|
typedef struct {
|
|
char *str;
|
|
int retval;
|
|
int icon;
|
|
} MenuEntry;
|
|
|
|
typedef struct {
|
|
char *instr;
|
|
char *title;
|
|
|
|
MenuEntry *items;
|
|
int nitems, itemssize;
|
|
} MenuData;
|
|
|
|
static MenuData *menudata_new(char *instr) {
|
|
MenuData *md= MEM_mallocN(sizeof(*md), "MenuData");
|
|
|
|
md->instr= instr;
|
|
md->title= NULL;
|
|
md->items= NULL;
|
|
md->nitems= md->itemssize= 0;
|
|
|
|
return md;
|
|
}
|
|
|
|
static void menudata_set_title(MenuData *md, char *title) {
|
|
if (!md->title)
|
|
md->title= title;
|
|
}
|
|
|
|
static void menudata_add_item(MenuData *md, char *str, int retval, int icon) {
|
|
if (md->nitems==md->itemssize) {
|
|
int nsize= md->itemssize?(md->itemssize<<1):1;
|
|
MenuEntry *oitems= md->items;
|
|
|
|
md->items= MEM_mallocN(nsize*sizeof(*md->items), "md->items");
|
|
if (oitems) {
|
|
memcpy(md->items, oitems, md->nitems*sizeof(*md->items));
|
|
MEM_freeN(oitems);
|
|
}
|
|
|
|
md->itemssize= nsize;
|
|
}
|
|
|
|
md->items[md->nitems].str= str;
|
|
md->items[md->nitems].retval= retval;
|
|
md->items[md->nitems].icon= icon;
|
|
md->nitems++;
|
|
}
|
|
|
|
static void menudata_free(MenuData *md) {
|
|
MEM_freeN(md->instr);
|
|
if (md->items)
|
|
MEM_freeN(md->items);
|
|
MEM_freeN(md);
|
|
}
|
|
|
|
/**
|
|
* Parse menu description strings, string is of the
|
|
* form "[sss%t|]{(sss[%xNN]|), (%l|)}", ssss%t indicates the
|
|
* menu title, sss or sss%xNN indicates an option,
|
|
* if %xNN is given then NN is the return value if
|
|
* that option is selected otherwise the return value
|
|
* is the index of the option (starting with 1). %l
|
|
* indicates a seperator.
|
|
*
|
|
* @param str String to be parsed.
|
|
* @retval new menudata structure, free with menudata_free()
|
|
*/
|
|
static MenuData *decompose_menu_string(char *str)
|
|
{
|
|
char *instr= BLI_strdup(str);
|
|
MenuData *md= menudata_new(instr);
|
|
char *nitem= NULL, *s= instr;
|
|
int nicon=0, nretval= 1, nitem_is_title= 0;
|
|
|
|
while (1) {
|
|
char c= *s;
|
|
|
|
if (c=='%') {
|
|
if (s[1]=='x') {
|
|
nretval= atoi(s+2);
|
|
|
|
*s= '\0';
|
|
s++;
|
|
} else if (s[1]=='t') {
|
|
nitem_is_title= 1;
|
|
|
|
*s= '\0';
|
|
s++;
|
|
} else if (s[1]=='l') {
|
|
nitem= "%l";
|
|
s++;
|
|
} else if (s[1]=='i') {
|
|
nicon= atoi(s+2);
|
|
s++;
|
|
}
|
|
} else if (c=='|' || c=='\0') {
|
|
if (nitem) {
|
|
*s= '\0';
|
|
|
|
if (nitem_is_title) {
|
|
menudata_set_title(md, nitem);
|
|
nitem_is_title= 0;
|
|
} else {
|
|
menudata_add_item(md, nitem, nretval, nicon);
|
|
nretval= md->nitems+1;
|
|
}
|
|
|
|
nitem= NULL;
|
|
nicon= 0;
|
|
}
|
|
|
|
if (c=='\0')
|
|
break;
|
|
} else if (!nitem)
|
|
nitem= s;
|
|
|
|
s++;
|
|
}
|
|
|
|
return md;
|
|
}
|
|
|
|
static void ui_set_name_menu(uiBut *but, int value)
|
|
{
|
|
MenuData *md;
|
|
int i;
|
|
|
|
md= decompose_menu_string(but->str);
|
|
for (i=0; i<md->nitems; i++)
|
|
if (md->items[i].retval==value)
|
|
strcpy(but->drawstr, md->items[i].str);
|
|
menudata_free(md);
|
|
}
|
|
|
|
static void ui_warp_pointer(short x, short y)
|
|
{
|
|
/* OSX has very poor mousewarp support, it sends events;
|
|
this causes a menu being pressed immediately ... */
|
|
#ifndef __APPLE__
|
|
warp_pointer(x, y);
|
|
#endif
|
|
}
|
|
|
|
|
|
static int ui_do_but_MENU(uiBut *but)
|
|
{
|
|
uiBlock *block;
|
|
uiBut *bt;
|
|
ListBase listb={NULL, NULL}, lb;
|
|
double fvalue;
|
|
int width, height=0, a, xmax, starty;
|
|
short startx;
|
|
int columns=1, rows=0, boxh, event;
|
|
short x1, y1, active= -1;
|
|
short mval[2];
|
|
MenuData *md;
|
|
|
|
but->flag |= UI_SELECT;
|
|
ui_draw_but(but);
|
|
ui_block_flush_back(but->block); // flush because this button creates own blocks loop
|
|
|
|
block= uiNewBlock(&listb, "menu", UI_EMBOSSP, UI_HELV, but->win);
|
|
block->flag= UI_BLOCK_LOOP|UI_BLOCK_REDRAW|UI_BLOCK_NUMSELECT;
|
|
block->themecol= TH_MENU_ITEM;
|
|
|
|
md= decompose_menu_string(but->str);
|
|
|
|
/* columns and row calculation */
|
|
columns= (md->nitems+20)/20;
|
|
if (columns<1) columns= 1;
|
|
|
|
rows= (int) md->nitems/columns;
|
|
if (rows<1) rows= 1;
|
|
|
|
while (rows*columns<md->nitems) rows++;
|
|
|
|
/* size and location */
|
|
if(md->title)
|
|
width= 1.5*but->aspect*strlen(md->title)+BIF_GetStringWidth(block->curfont, md->title, (U.transopts & USER_TR_MENUS));
|
|
else
|
|
width= 0;
|
|
|
|
for(a=0; a<md->nitems; a++) {
|
|
xmax= but->aspect*BIF_GetStringWidth(block->curfont, md->items[a].str, (U.transopts & USER_TR_MENUS));
|
|
if(xmax>width) width= xmax;
|
|
}
|
|
|
|
width+= 10;
|
|
if (width < (but->x2 - but->x1)) width = (but->x2 - but->x1);
|
|
if (width<50) width=50;
|
|
|
|
boxh= TBOXH;
|
|
|
|
height= rows*boxh;
|
|
if (md->title) height+= boxh;
|
|
|
|
getmouseco_sc(mval);
|
|
|
|
/* find active item */
|
|
fvalue= ui_get_but_val(but);
|
|
for(active=0; active<md->nitems; active++) {
|
|
if( md->items[active].retval== (int)fvalue ) break;
|
|
}
|
|
/* no active item? */
|
|
if(active==md->nitems) {
|
|
if(md->title) active= -1;
|
|
else active= 0;
|
|
}
|
|
|
|
/* for now disabled... works confusing because you think it's a title or so.... */
|
|
active= -1;
|
|
|
|
/* here we go! */
|
|
startx= but->x1;
|
|
starty= but->y1;
|
|
|
|
if(md->title) {
|
|
uiBut *bt;
|
|
uiSetCurFont(block, block->font+1);
|
|
bt= uiDefBut(block, LABEL, 0, md->title, startx, (short)(starty+rows*boxh), (short)width, (short)boxh, NULL, 0.0, 0.0, 0, 0, "");
|
|
uiSetCurFont(block, block->font);
|
|
bt->flag= UI_TEXT_LEFT;
|
|
}
|
|
|
|
for(a=0; a<md->nitems; a++) {
|
|
|
|
x1= but->x1 + width*((int)(md->nitems-a-1)/rows);
|
|
y1= but->y1 - boxh*(rows - ((md->nitems - a - 1)%rows)) + (rows*boxh);
|
|
|
|
if (strcmp(md->items[md->nitems-a-1].str, "%l")==0) {
|
|
uiDefBut(block, SEPR, B_NOP, "", x1, y1,(short)(width-(rows>1)), (short)(boxh-1), NULL, 0.0, 0.0, 0, 0, "");
|
|
}
|
|
else if(md->items[md->nitems-a-1].icon) {
|
|
uiBut *bt= uiDefIconTextBut(block, BUTM|but->pointype, but->retval, md->items[md->nitems-a-1].icon ,md->items[md->nitems-a-1].str, x1, y1,(short)(width-(rows>1)), (short)(boxh-1), but->poin, (float) md->items[md->nitems-a-1].retval, 0.0, 0, 0, "");
|
|
if(active==a) bt->flag |= UI_ACTIVE;
|
|
}
|
|
else {
|
|
uiBut *bt= uiDefBut(block, BUTM|but->pointype, but->retval, md->items[md->nitems-a-1].str, x1, y1,(short)(width-(rows>1)), (short)(boxh-1), but->poin, (float) md->items[md->nitems-a-1].retval, 0.0, 0, 0, "");
|
|
if(active==a) bt->flag |= UI_ACTIVE;
|
|
}
|
|
}
|
|
|
|
/* the code up here has flipped locations, because of change of preferred order */
|
|
/* thats why we have to switch list order too, to make arrowkeys work */
|
|
|
|
lb.first= lb.last= NULL;
|
|
bt= block->buttons.first;
|
|
while(bt) {
|
|
uiBut *next= bt->next;
|
|
BLI_remlink(&block->buttons, bt);
|
|
BLI_addhead(&lb, bt);
|
|
bt= next;
|
|
}
|
|
block->buttons= lb;
|
|
|
|
/* and lets go */
|
|
block->direction= UI_TOP;
|
|
ui_positionblock(block, but);
|
|
|
|
/* blocks can come (and get scaled) from a normal window, now we go to screenspace */
|
|
block->win= G.curscreen->mainwin;
|
|
for(bt= block->buttons.first; bt; bt= bt->next) bt->win= block->win;
|
|
bwin_getsinglematrix(block->win, block->winmat);
|
|
|
|
event= uiDoBlocks(&listb, 0);
|
|
|
|
menudata_free(md);
|
|
|
|
but->flag &= ~UI_SELECT;
|
|
ui_check_but(but);
|
|
ui_draw_but(but);
|
|
|
|
uibut_do_func(but);
|
|
|
|
return event;
|
|
}
|
|
|
|
|
|
|
|
/* ************* EVENTS ************* */
|
|
|
|
void uiGetMouse(int win, short *adr)
|
|
{
|
|
int x, y;
|
|
float xwin, ywin;
|
|
|
|
getmouseco_sc(adr);
|
|
if (win == G.curscreen->mainwin) return;
|
|
|
|
bwin_getsuborigin(win, &x, &y);
|
|
|
|
adr[0]-= x;
|
|
adr[1]-= y;
|
|
|
|
xwin= adr[0];
|
|
ywin= adr[1];
|
|
|
|
ui_window_to_graphics(win, &xwin, &ywin);
|
|
|
|
adr[0]= (short)(xwin+0.5);
|
|
adr[1]= (short)(ywin+0.5);
|
|
}
|
|
|
|
static void ui_is_but_sel(uiBut *but)
|
|
{
|
|
double value;
|
|
int lvalue;
|
|
short push=0, true=1;
|
|
|
|
value= ui_get_but_val(but);
|
|
|
|
if( but->type==TOGN ) true= 0;
|
|
|
|
if( but->bit ) {
|
|
lvalue= (int)value;
|
|
if( BTST(lvalue, (but->bitnr)) ) push= true;
|
|
else push= !true;
|
|
}
|
|
else {
|
|
switch(but->type) {
|
|
case BUT:
|
|
push= 0;
|
|
break;
|
|
case KEYEVT:
|
|
if (value==-1) push= 1;
|
|
break;
|
|
case TOG:
|
|
case TOGR:
|
|
case TOG3:
|
|
case ICONTOG:
|
|
if(value!=but->min) push= 1;
|
|
break;
|
|
case TOGN:
|
|
if(value==0.0) push= 1;
|
|
break;
|
|
case ROW:
|
|
if(value == but->max) push= 1;
|
|
break;
|
|
case COL:
|
|
push= 1;
|
|
break;
|
|
default:
|
|
push= 2;
|
|
break;
|
|
}
|
|
}
|
|
|
|
if(push==2);
|
|
else if(push==1) but->flag |= UI_SELECT;
|
|
else but->flag &= ~UI_SELECT;
|
|
}
|
|
|
|
static int ui_do_but_BUT(uiBut *but)
|
|
{
|
|
int activated;
|
|
|
|
do {
|
|
int oflag= but->flag;
|
|
short mval[2];
|
|
|
|
uiGetMouse(mywinget(), mval);
|
|
|
|
if (uibut_contains_pt(but, mval))
|
|
but->flag |= UI_SELECT;
|
|
else
|
|
but->flag &= ~UI_SELECT;
|
|
|
|
if (but->flag != oflag) {
|
|
ui_draw_but(but);
|
|
ui_block_flush_back(but->block);
|
|
}
|
|
|
|
PIL_sleep_ms(10);
|
|
} while (get_mbut() & L_MOUSE);
|
|
|
|
activated= (but->flag & UI_SELECT);
|
|
|
|
if(activated) {
|
|
uibut_do_func(but);
|
|
}
|
|
|
|
but->flag &= ~UI_SELECT;
|
|
ui_draw_but(but);
|
|
|
|
return activated?but->retval:0;
|
|
}
|
|
|
|
static int ui_do_but_KEYEVT(uiBut *but)
|
|
{
|
|
unsigned short event= 0;
|
|
short val;
|
|
|
|
/* flag for ui_check_but */
|
|
ui_set_but_val(but, -1);
|
|
ui_check_but(but);
|
|
ui_draw_but(but);
|
|
ui_block_flush_back(but->block);
|
|
|
|
do {
|
|
event= extern_qread(&val);
|
|
} while (!event || !val || ELEM(event, MOUSEX, MOUSEY));
|
|
|
|
if (!key_event_to_string(event)[0]) event= 0;
|
|
|
|
ui_set_but_val(but, (double) event);
|
|
ui_check_but(but);
|
|
ui_draw_but(but);
|
|
|
|
return (event!=0);
|
|
}
|
|
|
|
static int ui_do_but_TOG(uiBlock *block, uiBut *but)
|
|
{
|
|
uiBut *bt;
|
|
double value;
|
|
int w, lvalue, push;
|
|
|
|
value= ui_get_but_val(but);
|
|
lvalue= (int)value;
|
|
|
|
if(but->bit) {
|
|
w= BTST(lvalue, but->bitnr);
|
|
if(w) lvalue = BCLR(lvalue, but->bitnr);
|
|
else lvalue = BSET(lvalue, but->bitnr);
|
|
|
|
if(but->type==TOGR) {
|
|
if( (get_qual() & LR_SHIFTKEY)==0 ) {
|
|
lvalue= 1<<(but->bitnr);
|
|
|
|
ui_set_but_val(but, (double)lvalue);
|
|
|
|
bt= block->buttons.first;
|
|
while(bt) {
|
|
if( bt!=but && bt->poin==but->poin ) {
|
|
ui_is_but_sel(bt);
|
|
ui_draw_but(bt);
|
|
}
|
|
bt= bt->next;
|
|
}
|
|
}
|
|
else {
|
|
if(lvalue==0) lvalue= 1<<(but->bitnr);
|
|
}
|
|
}
|
|
ui_set_but_val(but, (double)lvalue);
|
|
if(but->type==ICONTOG) ui_check_but(but);
|
|
// no frontbuffer draw for this one
|
|
if((but->flag & UI_NO_HILITE)==0) ui_draw_but(but);
|
|
}
|
|
else {
|
|
|
|
if(value==0.0) push= 1;
|
|
else push= 0;
|
|
|
|
if(but->type==TOGN) push= !push;
|
|
ui_set_but_val(but, (double)push);
|
|
if(but->type==ICONTOG) ui_check_but(but);
|
|
// no frontbuffer draw for this one
|
|
if((but->flag & UI_NO_HILITE)==0) ui_draw_but(but);
|
|
}
|
|
|
|
/* no while loop...this button is used for viewmove */
|
|
|
|
uibut_do_func(but);
|
|
|
|
return but->retval;
|
|
}
|
|
|
|
static int ui_do_but_ROW(uiBlock *block, uiBut *but)
|
|
{
|
|
uiBut *bt;
|
|
|
|
ui_set_but_val(but, but->max);
|
|
ui_draw_but(but);
|
|
|
|
bt= block->buttons.first;
|
|
while(bt) {
|
|
if( bt!=but && bt->type==ROW ) {
|
|
if(bt->min==but->min) {
|
|
ui_is_but_sel(bt);
|
|
ui_draw_but(bt);
|
|
}
|
|
}
|
|
bt= bt->next;
|
|
}
|
|
return but->retval;
|
|
}
|
|
|
|
static int ui_do_but_TEX(uiBut *but)
|
|
{
|
|
unsigned short dev;
|
|
short x, mval[2], len=0, dodraw;
|
|
char *str, backstr[UI_MAX_DRAW_STR];
|
|
short capturing;
|
|
|
|
str= (char *)but->poin;
|
|
|
|
but->flag |= UI_SELECT;
|
|
|
|
uiGetMouse(mywinget(), mval);
|
|
|
|
/* calculate cursor pos with current mousecoords */
|
|
BLI_strncpy(backstr, but->drawstr, UI_MAX_DRAW_STR);
|
|
but->pos= strlen(backstr)-but->ofs;
|
|
|
|
while((but->aspect*BIF_GetStringWidth(but->font, backstr+but->ofs, 0) + but->x1) > mval[0]) {
|
|
if (but->pos <= 0) break;
|
|
but->pos--;
|
|
backstr[but->pos+but->ofs] = 0;
|
|
}
|
|
|
|
but->pos -= strlen(but->str);
|
|
but->pos += but->ofs;
|
|
if(but->pos<0) but->pos= 0;
|
|
|
|
/* backup */
|
|
BLI_strncpy(backstr, but->poin, UI_MAX_DRAW_STR);
|
|
|
|
ui_draw_but(but);
|
|
ui_block_flush_back(but->block);
|
|
|
|
while (get_mbut() & L_MOUSE) BIF_wait_for_statechange();
|
|
len= strlen(str);
|
|
but->min= 0.0;
|
|
|
|
capturing = TRUE;
|
|
while(capturing) {
|
|
char ascii;
|
|
short val;
|
|
|
|
dodraw= 0;
|
|
dev = extern_qread_ext(&val, &ascii);
|
|
|
|
if(dev==INPUTCHANGE) break;
|
|
else if(get_mbut() & L_MOUSE) break;
|
|
else if(get_mbut() & R_MOUSE) break;
|
|
else if(dev==ESCKEY) break;
|
|
else if(dev==MOUSEX) val= 0;
|
|
else if(dev==MOUSEY) val= 0;
|
|
|
|
if(ascii) {
|
|
if(len < but->max) {
|
|
for(x= but->max; x>but->pos; x--)
|
|
str[x]= str[x-1];
|
|
str[but->pos]= ascii;
|
|
but->pos++;
|
|
len++;
|
|
str[len]= '\0';
|
|
dodraw= 1;
|
|
}
|
|
}
|
|
else if(val) {
|
|
|
|
switch (dev) {
|
|
|
|
case RIGHTARROWKEY:
|
|
if(G.qual & LR_SHIFTKEY) but->pos= strlen(str);
|
|
else but->pos++;
|
|
if(but->pos>strlen(str)) but->pos= strlen(str);
|
|
dodraw= 1;
|
|
break;
|
|
|
|
case LEFTARROWKEY:
|
|
if(G.qual & LR_SHIFTKEY) but->pos= 0;
|
|
else if(but->pos>0) but->pos--;
|
|
dodraw= 1;
|
|
break;
|
|
|
|
case ENDKEY:
|
|
but->pos= strlen(str);
|
|
dodraw= 1;
|
|
break;
|
|
|
|
case HOMEKEY:
|
|
but->pos= 0;
|
|
dodraw= 1;
|
|
break;
|
|
|
|
case PADENTER:
|
|
case RETKEY:
|
|
capturing = FALSE;
|
|
break;
|
|
|
|
case DELKEY:
|
|
if(but->pos>=0 && but->pos<strlen(str)) {
|
|
for(x=but->pos; x<=strlen(str); x++)
|
|
str[x]= str[x+1];
|
|
str[--len]='\0';
|
|
dodraw= 1;
|
|
}
|
|
break;
|
|
|
|
case BACKSPACEKEY:
|
|
if(len!=0) {
|
|
if(get_qual() & LR_SHIFTKEY) {
|
|
str[0]= 0;
|
|
but->pos= 0;
|
|
len= 0;
|
|
dodraw= 1;
|
|
}
|
|
else if(but->pos>0) {
|
|
for(x=but->pos; x<=strlen(str); x++)
|
|
str[x-1]= str[x];
|
|
but->pos--;
|
|
str[--len]='\0';
|
|
dodraw= 1;
|
|
}
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
|
|
if(dodraw) {
|
|
ui_check_but(but);
|
|
ui_draw_but(but);
|
|
ui_block_flush_back(but->block);
|
|
}
|
|
}
|
|
|
|
if(dev==ESCKEY) strcpy(but->poin, backstr);
|
|
but->pos= -1;
|
|
but->flag &= ~UI_SELECT;
|
|
|
|
uibut_do_func(but);
|
|
|
|
ui_check_but(but);
|
|
ui_draw_but(but);
|
|
|
|
if(dev!=ESCKEY) return but->retval;
|
|
else return 0;
|
|
}
|
|
|
|
|
|
static int uiActAsTextBut(uiBut *but)
|
|
{
|
|
void *but_func;
|
|
double value;
|
|
float min, max;
|
|
int temp, retval, textleft;
|
|
char str[UI_MAX_DRAW_STR], *point;
|
|
|
|
|
|
value= ui_get_but_val(but);
|
|
if( but->pointype==FLO ) {
|
|
if(but->a2) { /* amount of digits defined */
|
|
if(but->a2==1) sprintf(str, "%.1f", value);
|
|
else if(but->a2==2) sprintf(str, "%.2f", value);
|
|
else if(but->a2==3) sprintf(str, "%.3f", value);
|
|
else sprintf(str, "%.4f", value);
|
|
}
|
|
else sprintf(str, "%.3f", value);
|
|
}
|
|
else {
|
|
sprintf(str, "%d", (int)value);
|
|
}
|
|
/* store values before calling as text button */
|
|
point= but->poin;
|
|
but->poin= str;
|
|
but_func= but->func;
|
|
but->func= NULL;
|
|
min= but->min;
|
|
max= but->max;
|
|
but->min= 0.0;
|
|
but->max= 15.0;
|
|
temp= but->type;
|
|
but->type= TEX;
|
|
textleft= but->flag & UI_TEXT_LEFT;
|
|
but->flag |= UI_TEXT_LEFT;
|
|
ui_check_but(but);
|
|
|
|
retval= ui_do_but_TEX(but);
|
|
|
|
/* restore values */
|
|
but->type= temp;
|
|
but->poin= point;
|
|
but->func= but_func;
|
|
but->min= min;
|
|
but->max= max;
|
|
if(textleft==0) but->flag &= ~UI_TEXT_LEFT;
|
|
|
|
if( but->pointype==FLO ) value= atof(str);
|
|
else value= atoi(str);
|
|
|
|
if(value<min) value= min;
|
|
if(value>max) value= max;
|
|
|
|
ui_set_but_val(but, value);
|
|
ui_check_but(but);
|
|
ui_draw_but(but);
|
|
|
|
return retval;
|
|
}
|
|
|
|
static int ui_do_but_NUM(uiBut *but)
|
|
{
|
|
double value;
|
|
float deler, fstart, f, tempf;
|
|
int lvalue, temp; /* , firsttime=1; */
|
|
short retval=0, qual, sx, mval[2], pos=0;
|
|
|
|
but->flag |= UI_SELECT;
|
|
ui_draw_but(but);
|
|
ui_block_flush_back(but->block);
|
|
|
|
uiGetMouse(mywinget(), mval);
|
|
value= ui_get_but_val(but);
|
|
|
|
sx= mval[0];
|
|
fstart= (value - but->min)/(but->max-but->min);
|
|
f= fstart;
|
|
|
|
temp= (int)value;
|
|
tempf= value;
|
|
|
|
if(get_qual() & LR_SHIFTKEY) { /* make it textbut */
|
|
if( uiActAsTextBut(but) ) retval= but->retval;
|
|
}
|
|
else {
|
|
retval= but->retval;
|
|
/* firsttime: this button can be approached with enter as well */
|
|
while (get_mbut() & L_MOUSE) {
|
|
qual= get_qual();
|
|
|
|
deler= 500;
|
|
if( but->pointype!=FLO ) {
|
|
|
|
if( (but->max-but->min)<100 ) deler= 200.0;
|
|
if( (but->max-but->min)<25 ) deler= 50.0;
|
|
|
|
}
|
|
if(qual & LR_SHIFTKEY) deler*= 10.0;
|
|
if(qual & LR_ALTKEY) deler*= 20.0;
|
|
|
|
uiGetMouse(mywinget(), mval);
|
|
|
|
if(mval[0] != sx) {
|
|
|
|
f+= ((float)(mval[0]-sx))/deler;
|
|
if(f>1.0) f= 1.0;
|
|
if(f<0.0) f= 0.0;
|
|
sx= mval[0];
|
|
tempf= ( but->min + f*(but->max-but->min));
|
|
|
|
if( but->pointype!=FLO ) {
|
|
|
|
temp= floor(tempf+.5);
|
|
|
|
if(tempf==but->min || tempf==but->max);
|
|
else if(qual & LR_CTRLKEY) {
|
|
if(qual & LR_SHIFTKEY) temp= 100*(temp/100);
|
|
else temp= 10*(temp/10);
|
|
}
|
|
if( temp>=but->min && temp<=but->max) {
|
|
|
|
value= ui_get_but_val(but);
|
|
lvalue= (int)value;
|
|
|
|
if(temp != lvalue ) {
|
|
pos= 1;
|
|
ui_set_but_val(but, (double)temp);
|
|
ui_check_but(but);
|
|
ui_draw_but(but);
|
|
ui_block_flush_back(but->block);
|
|
|
|
uibut_do_func(but);
|
|
}
|
|
}
|
|
|
|
}
|
|
else {
|
|
temp= 0;
|
|
if(qual & LR_CTRLKEY) {
|
|
if(qual & LR_SHIFTKEY) {
|
|
if(tempf==but->min || tempf==but->max);
|
|
else if(but->max-but->min < 2.10) tempf= 0.01*floor(100.0*tempf);
|
|
else if(but->max-but->min < 21.0) tempf= 0.1*floor(10.0*tempf);
|
|
else tempf= floor(tempf);
|
|
}
|
|
else {
|
|
if(tempf==but->min || tempf==but->max);
|
|
else if(but->max-but->min < 2.10) tempf= 0.1*floor(10*tempf);
|
|
else if(but->max-but->min < 21.0) tempf= floor(tempf);
|
|
else tempf= 10.0*floor(tempf/10.0);
|
|
}
|
|
}
|
|
|
|
if( tempf>=but->min && tempf<=but->max) {
|
|
value= ui_get_but_val(but);
|
|
|
|
if(tempf != value ) {
|
|
pos= 1;
|
|
ui_set_but_val(but, tempf);
|
|
ui_check_but(but);
|
|
ui_draw_but(but);
|
|
ui_block_flush_back(but->block);
|
|
}
|
|
}
|
|
|
|
}
|
|
}
|
|
BIF_wait_for_statechange();
|
|
}
|
|
|
|
/* click on the side arrows to increment/decrement, click inside
|
|
* to edit the value directly */
|
|
if(pos==0) { /* plus 1 or minus 1 */
|
|
if( but->pointype!=FLO ) {
|
|
|
|
if(sx < (but->x1 + (but->x2 - but->x1)/3 - 3)) {
|
|
temp--;
|
|
if( temp>=but->min && temp<=but->max) ui_set_but_val(but, (double)temp);
|
|
}
|
|
else if(sx > (but->x1 + (2*(but->x2 - but->x1)/3) + 3)) {
|
|
temp++;
|
|
if( temp>=but->min && temp<=but->max) ui_set_but_val(but, (double)temp);
|
|
}
|
|
else {
|
|
if( uiActAsTextBut(but) ); else retval= 0;
|
|
}
|
|
}
|
|
else {
|
|
|
|
if(sx < (but->x1 + (but->x2 - but->x1)/3 - 3)) {
|
|
tempf-= 0.01*but->a1;
|
|
if (tempf < but->min) tempf = but->min;
|
|
ui_set_but_val(but, tempf);
|
|
}
|
|
else if(sx > but->x1 + (2*((but->x2 - but->x1)/3) + 3)) {
|
|
tempf+= 0.01*but->a1;
|
|
if (tempf < but->min) tempf = but->min;
|
|
ui_set_but_val(but, tempf);
|
|
}
|
|
else {
|
|
if( uiActAsTextBut(but) ); else retval= 0;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
but->flag &= ~UI_SELECT;
|
|
ui_check_but(but);
|
|
ui_draw_but(but);
|
|
ui_block_flush_back(but->block);
|
|
|
|
uibut_do_func(but);
|
|
|
|
return retval;
|
|
}
|
|
|
|
static int ui_do_but_TOG3(uiBut *but)
|
|
{
|
|
|
|
if( but->pointype==SHO ) {
|
|
short *sp= (short *)but->poin;
|
|
|
|
if( BTST(sp[1], but->bitnr)) {
|
|
sp[1]= BCLR(sp[1], but->bitnr);
|
|
sp[0]= BCLR(sp[0], but->bitnr);
|
|
}
|
|
else if( BTST(sp[0], but->bitnr)) {
|
|
sp[1]= BSET(sp[1], but->bitnr);
|
|
} else {
|
|
sp[0]= BSET(sp[0], but->bitnr);
|
|
}
|
|
}
|
|
else {
|
|
if( BTST(*(but->poin+2), but->bitnr)) {
|
|
*(but->poin+2)= BCLR(*(but->poin+2), but->bitnr);
|
|
*(but->poin)= BCLR(*(but->poin), but->bitnr);
|
|
}
|
|
else if( BTST(*(but->poin), but->bitnr)) {
|
|
*(but->poin+2)= BSET(*(but->poin+2), but->bitnr);
|
|
} else {
|
|
*(but->poin)= BSET(*(but->poin), but->bitnr);
|
|
}
|
|
}
|
|
|
|
ui_is_but_sel(but);
|
|
ui_draw_but(but);
|
|
|
|
return but->retval;
|
|
}
|
|
|
|
static int ui_do_but_ICONROW(uiBut *but)
|
|
{
|
|
ListBase listb= {NULL, NULL};
|
|
uiBlock *block;
|
|
int a;
|
|
|
|
but->flag |= UI_SELECT;
|
|
ui_draw_but(but);
|
|
ui_block_flush_back(but->block); // flush because this button creates own blocks loop
|
|
|
|
/* here we go! */
|
|
block= uiNewBlock(&listb, "menu", UI_EMBOSSP, UI_HELV, but->win);
|
|
block->flag= UI_BLOCK_LOOP|UI_BLOCK_REDRAW|UI_BLOCK_NUMSELECT;
|
|
block->themecol= TH_MENU_ITEM;
|
|
|
|
for(a=(int)but->min; a<=(int)but->max; a++) {
|
|
uiDefIconBut(block, BUTM|but->pointype, but->retval, but->icon+(a-but->min), 0, (short)(18*a), (short)(but->x2-but->x1-4), 18, but->poin, (float)a, 0.0, 0, 0, "");
|
|
}
|
|
block->direction= UI_TOP;
|
|
ui_positionblock(block, but);
|
|
|
|
/* the block is made with but-win, but is handled in mainwin space...
|
|
this is needs better implementation */
|
|
block->win= G.curscreen->mainwin;
|
|
|
|
uiDoBlocks(&listb, 0);
|
|
|
|
but->flag &= ~UI_SELECT;
|
|
ui_check_but(but);
|
|
ui_draw_but(but);
|
|
|
|
return but->retval;
|
|
}
|
|
|
|
static int ui_do_but_ICONTEXTROW(uiBut *but)
|
|
{
|
|
uiBlock *block;
|
|
ListBase listb={NULL, NULL};
|
|
int width, a, xmax, ypos;
|
|
MenuData *md;
|
|
|
|
but->flag |= UI_SELECT;
|
|
ui_draw_but(but);
|
|
ui_block_flush_back(but->block); // flush because this button creates own blocks loop
|
|
|
|
block= uiNewBlock(&listb, "menu", UI_EMBOSSP, UI_HELV, but->win);
|
|
block->flag= UI_BLOCK_LOOP|UI_BLOCK_REDRAW|UI_BLOCK_NUMSELECT;
|
|
block->themecol= TH_MENU_ITEM;
|
|
|
|
md= decompose_menu_string(but->str);
|
|
|
|
/* size and location */
|
|
/* expand menu width to fit labels */
|
|
if(md->title)
|
|
width= 2*strlen(md->title)+BIF_GetStringWidth(block->curfont, md->title, (U.transopts & USER_TR_MENUS));
|
|
else
|
|
width= 0;
|
|
|
|
for(a=0; a<md->nitems; a++) {
|
|
xmax= BIF_GetStringWidth(block->curfont, md->items[a].str, (U.transopts & USER_TR_MENUS));
|
|
if(xmax>width) width= xmax;
|
|
}
|
|
|
|
width+= 30;
|
|
if (width<50) width=50;
|
|
|
|
ypos = 1;
|
|
|
|
/* loop through the menu options and draw them out with icons & text labels */
|
|
for(a=0; a<md->nitems; a++) {
|
|
|
|
/* add a space if there's a separator (%l) */
|
|
if (strcmp(md->items[a].str, "%l")==0) {
|
|
ypos +=3;
|
|
}
|
|
else {
|
|
uiDefIconTextBut(block, BUTM|but->pointype, but->retval, (short)((but->icon)+(md->items[a].retval-but->min)), md->items[a].str, 0, ypos,(short)width, 19, but->poin, (float) md->items[a].retval, 0.0, 0, 0, "");
|
|
ypos += 20;
|
|
}
|
|
}
|
|
|
|
if(md->title) {
|
|
uiBut *bt;
|
|
uiSetCurFont(block, block->font+1);
|
|
bt= uiDefBut(block, LABEL, 0, md->title, 0, ypos, (short)width, 19, NULL, 0.0, 0.0, 0, 0, "");
|
|
uiSetCurFont(block, block->font);
|
|
bt->flag= UI_TEXT_LEFT;
|
|
}
|
|
|
|
block->direction= UI_TOP;
|
|
ui_positionblock(block, but);
|
|
|
|
/* the block is made with but-win, but is handled in mainwin space...
|
|
this is needs better implementation */
|
|
block->win= G.curscreen->mainwin;
|
|
|
|
uiBoundsBlock(block, 3);
|
|
|
|
uiDoBlocks(&listb, 0);
|
|
|
|
menudata_free(md);
|
|
|
|
but->flag &= ~UI_SELECT;
|
|
ui_check_but(but);
|
|
ui_draw_but(but);
|
|
|
|
uibut_do_func(but);
|
|
|
|
return but->retval;
|
|
|
|
}
|
|
|
|
static int ui_do_but_IDPOIN(uiBut *but)
|
|
{
|
|
char str[UI_MAX_DRAW_STR];
|
|
ID *id;
|
|
|
|
id= *but->idpoin_idpp;
|
|
if(id) strcpy(str, id->name+2);
|
|
else str[0]= 0;
|
|
|
|
but->type= TEX;
|
|
but->poin= str;
|
|
but->min= 0.0;
|
|
but->max= 22.0;
|
|
ui_do_but_TEX(but);
|
|
but->poin= NULL;
|
|
but->type= IDPOIN;
|
|
|
|
but->idpoin_func(str, but->idpoin_idpp);
|
|
ui_check_but(but);
|
|
ui_draw_but(but);
|
|
|
|
return but->retval;
|
|
}
|
|
|
|
static int ui_do_but_SLI(uiBut *but)
|
|
{
|
|
float f, fstart, tempf = 0.0, deler, value;
|
|
int sx, h, temp, pos=0, lvalue, redraw;
|
|
short mval[2], qual;
|
|
float curmatrix[4][4];
|
|
|
|
value= ui_get_but_val(but);
|
|
uiGetMouse(mywinget(), mval);
|
|
|
|
sx= mval[0];
|
|
h= but->y2-but->y1;
|
|
fstart= but->max-but->min;
|
|
fstart= (value - but->min)/fstart;
|
|
temp= 32767;
|
|
|
|
if( but->type==NUMSLI) deler= ( (but->x2-but->x1)/2 - 5.0*but->aspect);
|
|
else if( but->type==HSVSLI) deler= ( (but->x2-but->x1)/2 - 5.0*but->aspect);
|
|
else deler= (but->x2-but->x1- 5.0*but->aspect);
|
|
|
|
|
|
while (get_mbut() & L_MOUSE) {
|
|
|
|
qual= get_qual();
|
|
uiGetMouse(mywinget(), mval);
|
|
|
|
f= (float)(mval[0]-sx)/deler +fstart;
|
|
|
|
if (qual & LR_SHIFTKEY) {
|
|
f= (f-fstart)/10.0 + fstart;
|
|
}
|
|
|
|
CLAMP(f, 0.0, 1.0);
|
|
tempf= but->min+f*(but->max-but->min);
|
|
temp= floor(tempf+.5);
|
|
|
|
if(qual & LR_CTRLKEY) {
|
|
if(tempf==but->min || tempf==but->max);
|
|
else if( but->pointype==FLO ) {
|
|
|
|
if(qual & LR_SHIFTKEY) {
|
|
if(tempf==but->min || tempf==but->max);
|
|
else if(but->max-but->min < 2.10) tempf= 0.01*floor(100.0*tempf);
|
|
else if(but->max-but->min < 21.0) tempf= 0.1*floor(10.0*tempf);
|
|
else tempf= floor(tempf);
|
|
}
|
|
else {
|
|
if(but->max-but->min < 2.10) tempf= 0.1*floor(10*tempf);
|
|
else if(but->max-but->min < 21.0) tempf= floor(tempf);
|
|
else tempf= 10.0*floor(tempf/10.0);
|
|
}
|
|
}
|
|
else {
|
|
temp= 10*(temp/10);
|
|
tempf= temp;
|
|
}
|
|
}
|
|
|
|
value= ui_get_but_val(but);
|
|
lvalue= floor(value+0.5);
|
|
|
|
if( but->pointype!=FLO )
|
|
redraw= (temp != lvalue);
|
|
else
|
|
redraw= (tempf != value);
|
|
|
|
if (redraw) {
|
|
pos= 1;
|
|
ui_set_but_val(but, tempf);
|
|
ui_check_but(but);
|
|
ui_draw_but(but);
|
|
ui_block_flush_back(but->block);
|
|
|
|
if(but->a1) { /* color number */
|
|
uiBut *bt= but->prev;
|
|
while(bt) {
|
|
if(bt->a2 == but->a1) ui_draw_but(bt);
|
|
bt= bt->prev;
|
|
}
|
|
bt= but->next;
|
|
while(bt) {
|
|
if(bt->a2 == but->a1) ui_draw_but(bt);
|
|
bt= bt->next;
|
|
}
|
|
}
|
|
/* save current window matrix (global UIwinmat)
|
|
because button callback function MIGHT change it
|
|
- which has until now occured through the Python API
|
|
*/
|
|
Mat4CpyMat4(curmatrix, UIwinmat);
|
|
uibut_do_func(but);
|
|
Mat4CpyMat4(UIwinmat, curmatrix);
|
|
}
|
|
else BIF_wait_for_statechange();
|
|
}
|
|
|
|
|
|
if(temp!=32767 && pos==0) { /* plus 1 or minus 1 */
|
|
|
|
if( but->type==SLI) f= (float)(mval[0]-but->x1)/(but->x2-but->x1-h);
|
|
else f= (float)(mval[0]- (but->x1+but->x2)/2)/( (but->x2-but->x1)/2 - h);
|
|
|
|
f= but->min+f*(but->max-but->min);
|
|
|
|
if( but->pointype!=FLO ) {
|
|
|
|
if(f<temp) temp--;
|
|
else temp++;
|
|
if( temp>=but->min && temp<=but->max)
|
|
ui_set_but_val(but, (float)temp);
|
|
|
|
}
|
|
else {
|
|
|
|
if(f<tempf) tempf-=.01;
|
|
else tempf+=.01;
|
|
if( tempf>=but->min && tempf<=but->max)
|
|
ui_set_but_val(but, tempf);
|
|
|
|
}
|
|
}
|
|
ui_check_but(but);
|
|
ui_draw_but(but);
|
|
ui_block_flush_back(but->block);
|
|
|
|
return but->retval;
|
|
}
|
|
|
|
static int ui_do_but_NUMSLI(uiBut *but)
|
|
{
|
|
short mval[2];
|
|
|
|
/* first define if it's a slider or textbut */
|
|
uiGetMouse(mywinget(), mval);
|
|
|
|
if(mval[0]>= -6+(but->x1+but->x2)/2 ) { /* slider */
|
|
but->flag |= UI_SELECT;
|
|
ui_draw_but(but);
|
|
ui_do_but_SLI(but);
|
|
but->flag &= ~UI_SELECT;
|
|
}
|
|
else {
|
|
uiActAsTextBut(but);
|
|
uibut_do_func(but); // this is done in ui_do_but_SLI() not in uiActAsTextBut()
|
|
}
|
|
|
|
while(get_mbut() & L_MOUSE) BIF_wait_for_statechange();
|
|
|
|
ui_draw_but(but);
|
|
|
|
/* hsv patch */
|
|
if(but->type==HSVSLI) {
|
|
|
|
if(but->str[0]=='H') {
|
|
ui_draw_but(but->next);
|
|
ui_draw_but(but->next->next);
|
|
}
|
|
else if(but->str[0]=='S') {
|
|
ui_draw_but(but->next);
|
|
ui_draw_but(but->prev);
|
|
}
|
|
else if(but->str[0]=='V') {
|
|
ui_draw_but(but->prev);
|
|
ui_draw_but(but->prev->prev);
|
|
}
|
|
}
|
|
|
|
return but->retval;
|
|
}
|
|
|
|
static int ui_do_but_BLOCK(uiBut *but)
|
|
{
|
|
uiBlock *block;
|
|
uiBut *bt;
|
|
|
|
but->flag |= UI_SELECT;
|
|
ui_draw_but(but);
|
|
|
|
block= but->block_func(but->poin);
|
|
|
|
block->xofs = -2; /* for proper alignment */
|
|
|
|
/* only used for automatic toolbox, so can set the shift flag */
|
|
if(but->flag & UI_MAKE_TOP) {
|
|
block->direction= UI_TOP|UI_SHIFT_FLIPPED;
|
|
uiBlockFlipOrder(block);
|
|
}
|
|
if(but->flag & UI_MAKE_DOWN) block->direction= UI_DOWN|UI_SHIFT_FLIPPED;
|
|
if(but->flag & UI_MAKE_LEFT) block->direction |= UI_LEFT;
|
|
if(but->flag & UI_MAKE_RIGHT) block->direction |= UI_RIGHT;
|
|
|
|
ui_positionblock(block, but);
|
|
block->flag |= UI_BLOCK_LOOP;
|
|
|
|
/* blocks can come (and get scaled) from a normal window, now we go to screenspace */
|
|
block->win= G.curscreen->mainwin;
|
|
for(bt= block->buttons.first; bt; bt= bt->next) bt->win= block->win;
|
|
bwin_getsinglematrix(block->win, block->winmat);
|
|
|
|
/* postpone draw, this will cause a new window matrix, first finish all other buttons */
|
|
block->flag |= UI_BLOCK_REDRAW;
|
|
|
|
but->flag &= ~UI_SELECT;
|
|
uibut_do_func(but);
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int ui_do_but_BUTM(uiBut *but)
|
|
{
|
|
|
|
ui_set_but_val(but, but->min);
|
|
UIafterfunc= but->butm_func;
|
|
UIafterfunc_arg= but->butm_func_arg;
|
|
UIafterval= but->a2;
|
|
|
|
return but->retval;
|
|
}
|
|
|
|
static int ui_do_but_LABEL(uiBut *but)
|
|
{
|
|
|
|
uibut_do_func(but);
|
|
return but->retval;
|
|
}
|
|
|
|
static uiBut *ui_get_valid_link_button(uiBlock *block, uiBut *but, short *mval)
|
|
{
|
|
uiBut *bt;
|
|
|
|
/* find button to link to */
|
|
for (bt= block->buttons.first; bt; bt= bt->next)
|
|
if(bt!=but && uibut_contains_pt(bt, mval))
|
|
break;
|
|
|
|
if (bt) {
|
|
if (but->type==LINK && bt->type==INLINK) {
|
|
if( but->link->tocode == (int)bt->min ) {
|
|
return bt;
|
|
}
|
|
}
|
|
else if(but->type==INLINK && bt->type==LINK) {
|
|
if( bt->link->tocode == (int)but->min ) {
|
|
return bt;
|
|
}
|
|
}
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
static int ui_is_a_link(uiBut *from, uiBut *to)
|
|
{
|
|
uiLinkLine *line;
|
|
uiLink *link;
|
|
|
|
link= from->link;
|
|
if(link) {
|
|
line= link->lines.first;
|
|
while(line) {
|
|
if(line->from==from && line->to==to) return 1;
|
|
line= line->next;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
static uiBut *ui_find_inlink(uiBlock *block, void *poin)
|
|
{
|
|
uiBut *but;
|
|
|
|
but= block->buttons.first;
|
|
while(but) {
|
|
if(but->type==INLINK) {
|
|
if(but->poin == poin) return but;
|
|
}
|
|
but= but->next;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
static void ui_add_link_line(ListBase *listb, uiBut *but, uiBut *bt)
|
|
{
|
|
uiLinkLine *line;
|
|
|
|
line= MEM_callocN(sizeof(uiLinkLine), "linkline");
|
|
BLI_addtail(listb, line);
|
|
line->from= but;
|
|
line->to= bt;
|
|
}
|
|
|
|
|
|
void uiComposeLinks(uiBlock *block)
|
|
{
|
|
uiBut *but, *bt;
|
|
uiLink *link;
|
|
void ***ppoin;
|
|
int a;
|
|
|
|
but= block->buttons.first;
|
|
while(but) {
|
|
if(but->type==LINK) {
|
|
link= but->link;
|
|
|
|
/* for all pointers in the array */
|
|
if(link) {
|
|
if(link->ppoin) {
|
|
ppoin= link->ppoin;
|
|
for(a=0; a < *(link->totlink); a++) {
|
|
bt= ui_find_inlink(block, (*ppoin)[a] );
|
|
if(bt) {
|
|
ui_add_link_line(&link->lines, but, bt);
|
|
}
|
|
}
|
|
}
|
|
else if(link->poin) {
|
|
bt= ui_find_inlink(block, *(link->poin) );
|
|
if(bt) {
|
|
ui_add_link_line(&link->lines, but, bt);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
but= but->next;
|
|
}
|
|
}
|
|
|
|
static void ui_add_link(uiBut *from, uiBut *to)
|
|
{
|
|
/* in 'from' we have to add a link to 'to' */
|
|
uiLink *link;
|
|
void **oldppoin;
|
|
int a;
|
|
|
|
if(ui_is_a_link(from, to)) {
|
|
printf("already exists\n");
|
|
return;
|
|
}
|
|
|
|
link= from->link;
|
|
|
|
/* are there more pointers allowed? */
|
|
if(link->ppoin) {
|
|
oldppoin= *(link->ppoin);
|
|
|
|
(*(link->totlink))++;
|
|
*(link->ppoin)= MEM_callocN( *(link->totlink)*sizeof(void *), "new link");
|
|
|
|
for(a=0; a< (*(link->totlink))-1; a++) {
|
|
(*(link->ppoin))[a]= oldppoin[a];
|
|
}
|
|
(*(link->ppoin))[a]= to->poin;
|
|
|
|
if(oldppoin) MEM_freeN(oldppoin);
|
|
}
|
|
else {
|
|
*(link->poin)= to->poin;
|
|
}
|
|
|
|
}
|
|
|
|
static int ui_do_but_LINK(uiBlock *block, uiBut *but)
|
|
{
|
|
/*
|
|
* This button only visualizes, the dobutton mode
|
|
* can add a new link, but then the whole system
|
|
* should be redrawn/initialized.
|
|
*
|
|
*/
|
|
uiBut *bt=0, *bto=NULL;
|
|
short sval[2], mval[2], mvalo[2], first= 1;
|
|
|
|
uiGetMouse(curarea->win, sval);
|
|
mvalo[0]= sval[0];
|
|
mvalo[1]= sval[1];
|
|
|
|
while (get_mbut() & L_MOUSE) {
|
|
uiGetMouse(curarea->win, mval);
|
|
|
|
if(mval[0]!=mvalo[0] || mval[1]!=mvalo[1] || first) {
|
|
/* clear completely, because of drawbuttons */
|
|
bt= ui_get_valid_link_button(block, but, mval);
|
|
if(bt) {
|
|
bt->flag |= UI_ACTIVE;
|
|
ui_draw_but(bt);
|
|
}
|
|
if(bto && bto!=bt) {
|
|
bto->flag &= ~UI_ACTIVE;
|
|
ui_draw_but(bto);
|
|
}
|
|
bto= bt;
|
|
|
|
if (!first) {
|
|
glutil_draw_front_xor_line(sval[0], sval[1], mvalo[0], mvalo[1]);
|
|
}
|
|
glutil_draw_front_xor_line(sval[0], sval[1], mval[0], mval[1]);
|
|
|
|
mvalo[0]= mval[0];
|
|
mvalo[1]= mval[1];
|
|
|
|
first= 0;
|
|
}
|
|
else BIF_wait_for_statechange();
|
|
}
|
|
|
|
if (!first) {
|
|
glutil_draw_front_xor_line(sval[0], sval[1], mvalo[0], mvalo[1]);
|
|
}
|
|
|
|
if(bt) {
|
|
if(but->type==LINK) ui_add_link(but, bt);
|
|
else ui_add_link(bt, but);
|
|
|
|
scrarea_queue_winredraw(curarea);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/* picker sizes S hsize, F full size, D spacer, B button/pallette height */
|
|
#define SPICK 110.0
|
|
#define FPICK 180.0
|
|
#define DPICK 6.0
|
|
#define BPICK 24.0
|
|
|
|
#define UI_PALETTE_TOT 16
|
|
/* note; in tot+1 the old color is stored */
|
|
static float palette[UI_PALETTE_TOT+1][3]= {
|
|
{0.93, 0.83, 0.81}, {0.88, 0.89, 0.73}, {0.69, 0.81, 0.57}, {0.51, 0.76, 0.64},
|
|
{0.37, 0.56, 0.61}, {0.33, 0.29, 0.55}, {0.46, 0.21, 0.51}, {0.40, 0.12, 0.18},
|
|
{1.0, 1.0, 1.0}, {0.85, 0.85, 0.85}, {0.7, 0.7, 0.7}, {0.56, 0.56, 0.56},
|
|
{0.42, 0.42, 0.42}, {0.28, 0.28, 0.28}, {0.14, 0.14, 0.14}, {0.0, 0.0, 0.0}
|
|
};
|
|
|
|
/* for picker, while editing hsv */
|
|
static void ui_set_but_hsv(uiBut *but)
|
|
{
|
|
float col[3];
|
|
|
|
hsv_to_rgb(but->hsv[0], but->hsv[1], but->hsv[2], col, col+1, col+2);
|
|
ui_set_but_vectorf(but, col);
|
|
}
|
|
|
|
static void update_picker_buts(uiBlock *block, float *hsv)
|
|
{
|
|
uiBut *bt;
|
|
float r, g, b;
|
|
|
|
// this updates button strings, is hackish... but button pointers are on stack of caller function
|
|
hsv_to_rgb(hsv[0], hsv[1], hsv[2], &r, &g, &b);
|
|
|
|
for(bt= block->buttons.first; bt; bt= bt->next) {
|
|
if(bt->type==HSVCUBE) {
|
|
VECCOPY(bt->hsv, hsv);
|
|
ui_set_but_hsv(bt);
|
|
}
|
|
else if(bt->str[1]==' ') {
|
|
if(bt->str[0]=='R') {
|
|
ui_set_but_val(bt, r);
|
|
ui_check_but(bt);
|
|
}
|
|
else if(bt->str[0]=='G') {
|
|
ui_set_but_val(bt, g);
|
|
ui_check_but(bt);
|
|
}
|
|
else if(bt->str[0]=='B') {
|
|
ui_set_but_val(bt, b);
|
|
ui_check_but(bt);
|
|
}
|
|
else if(bt->str[0]=='H') {
|
|
ui_set_but_val(bt, hsv[0]);
|
|
ui_check_but(bt);
|
|
}
|
|
else if(bt->str[0]=='S') {
|
|
ui_set_but_val(bt, hsv[1]);
|
|
ui_check_but(bt);
|
|
}
|
|
else if(bt->str[0]=='V') {
|
|
ui_set_but_val(bt, hsv[2]);
|
|
ui_check_but(bt);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/* bt1 is palette but, col1 is original color */
|
|
/* callback to copy from/to palette */
|
|
static void do_palette_cb(void *bt1, void *col1)
|
|
{
|
|
uiBut *but1= (uiBut *)bt1;
|
|
uiBut *but;
|
|
float *col= (float *)col1;
|
|
float *fp, hsv[3];
|
|
|
|
fp= (float *)but1->poin;
|
|
|
|
if( (get_qual() & LR_CTRLKEY) ) {
|
|
VECCOPY(fp, col);
|
|
}
|
|
else {
|
|
VECCOPY(col, fp);
|
|
}
|
|
|
|
rgb_to_hsv(col[0], col[1], col[2], hsv, hsv+1, hsv+2);
|
|
update_picker_buts(but1->block, hsv);
|
|
|
|
for (but= but1->block->buttons.first; but; but= but->next) {
|
|
ui_draw_but(but);
|
|
}
|
|
but= but1->block->buttons.first;
|
|
ui_block_flush_back(but->block);
|
|
}
|
|
|
|
/* bt1 is num but, col1 is pointer to original color */
|
|
/* callback to handle changes in num-buts in picker */
|
|
static void do_palette1_cb(void *bt1, void *hsv1)
|
|
{
|
|
uiBut *but1= (uiBut *)bt1;
|
|
uiBut *but;
|
|
float *hsv= (float *)hsv1;
|
|
float *fp= NULL;
|
|
|
|
if(but1->str[0]=='R') fp= (float *)but1->poin;
|
|
else if(but1->str[0]=='G') fp= ((float *)but1->poin)-1;
|
|
else if(but1->str[0]=='B') fp= ((float *)but1->poin)-2;
|
|
|
|
if(fp) {
|
|
rgb_to_hsv(fp[0], fp[1], fp[2], hsv, hsv+1, hsv+2);
|
|
}
|
|
|
|
update_picker_buts(but1->block, hsv);
|
|
|
|
for (but= but1->block->buttons.first; but; but= but->next) {
|
|
ui_draw_but(but);
|
|
}
|
|
|
|
but= but1->block->buttons.first;
|
|
ui_block_flush_back(but->block);
|
|
|
|
}
|
|
|
|
/* color picker, Gimp version. mode: 'f' = floating panel, 'p' = popup */
|
|
/* col = read/write to, hsv/old = memory for temporal use */
|
|
void uiBlockPickerButtons(uiBlock *block, float *col, float *hsv, float *old, char mode, short retval)
|
|
{
|
|
uiBut *bt;
|
|
float h, offs;
|
|
int a;
|
|
|
|
VECCOPY(old, col); // old color stored there, for palette_cb to work
|
|
|
|
// the cube intersection
|
|
bt= uiDefButF(block, HSVCUBE, retval, "", 0,DPICK+BPICK,FPICK,FPICK, col, 0.0, 0.0, 2, 0, "");
|
|
uiButSetFlag(bt, UI_NO_HILITE);
|
|
|
|
bt= uiDefButF(block, HSVCUBE, retval, "", 0,0,FPICK,BPICK, col, 0.0, 0.0, 3, 0, "");
|
|
uiButSetFlag(bt, UI_NO_HILITE);
|
|
|
|
// palette
|
|
|
|
uiBlockSetEmboss(block, UI_EMBOSSP);
|
|
|
|
bt=uiDefButF(block, COL, retval, "", FPICK+DPICK, 0, BPICK,BPICK, old, 0.0, 0.0, -1, 0, "Old color, click to restore");
|
|
uiButSetFunc(bt, do_palette_cb, bt, col);
|
|
uiDefButF(block, COL, retval, "", FPICK+DPICK, BPICK+DPICK, BPICK,60-BPICK-DPICK, col, 0.0, 0.0, -1, 0, "Active color");
|
|
|
|
h= (DPICK+BPICK+FPICK-64)/(UI_PALETTE_TOT/2.0);
|
|
uiBlockBeginAlign(block);
|
|
for(a= -1+UI_PALETTE_TOT/2; a>=0; a--) {
|
|
bt= uiDefButF(block, COL, retval, "", FPICK+DPICK, 65.0+(float)a*h, BPICK/2, h, palette[a+UI_PALETTE_TOT/2], 0.0, 0.0, -1, 0, "Click to choose, hold CTRL to store in palette");
|
|
uiButSetFunc(bt, do_palette_cb, bt, col);
|
|
bt= uiDefButF(block, COL, retval, "", FPICK+DPICK+BPICK/2, 65.0+(float)a*h, BPICK/2, h, palette[a], 0.0, 0.0, -1, 0, "Click to choose, hold CTRL to store in palette");
|
|
uiButSetFunc(bt, do_palette_cb, bt, col);
|
|
}
|
|
uiBlockEndAlign(block);
|
|
|
|
uiBlockSetEmboss(block, UI_EMBOSSX);
|
|
|
|
// buttons
|
|
rgb_to_hsv(col[0], col[1], col[2], hsv, hsv+1, hsv+2);
|
|
|
|
offs= FPICK+2*DPICK+BPICK;
|
|
|
|
|
|
uiBlockBeginAlign(block);
|
|
bt= uiDefButF(block, NUM, retval, "R ", offs, 110, 80,20, col, 0.0, 1.0, 10, 2, "");
|
|
uiButSetFunc(bt, do_palette1_cb, bt, hsv);
|
|
bt= uiDefButF(block, NUM, retval, "G ", offs, 90, 80,20, col+1, 0.0, 1.0, 10, 2, "");
|
|
uiButSetFunc(bt, do_palette1_cb, bt, hsv);
|
|
bt= uiDefButF(block, NUM, retval, "B ", offs, 70, 80,20, col+2, 0.0, 1.0, 10, 2, "");
|
|
uiButSetFunc(bt, do_palette1_cb, bt, hsv);
|
|
|
|
uiBlockBeginAlign(block);
|
|
bt= uiDefButF(block, NUM, retval, "H ", offs, 40, 80,20, hsv, 0.0, 1.0, 10, 2, "");
|
|
uiButSetFunc(bt, do_palette1_cb, bt, hsv);
|
|
bt= uiDefButF(block, NUM, retval, "S ", offs, 20, 80,20, hsv+1, 0.0, 1.0, 10, 2, "");
|
|
uiButSetFunc(bt, do_palette1_cb, bt, hsv);
|
|
bt= uiDefButF(block, NUM, retval, "V ", offs, 0, 80,20, hsv+2, 0.0, 1.0, 10, 2, "");
|
|
uiButSetFunc(bt, do_palette1_cb, bt, hsv);
|
|
uiBlockEndAlign(block);
|
|
}
|
|
|
|
|
|
static int ui_do_but_COL(uiBut *but)
|
|
{
|
|
uiBlock *block;
|
|
uiBut *bt;
|
|
ListBase listb={NULL, NULL};
|
|
float hsv[3], old[3], *poin= NULL, colstore[3];
|
|
short event;
|
|
|
|
// signal to prevent calling up color picker
|
|
if(but->a1 == -1) {
|
|
uibut_do_func(but);
|
|
return but->retval;
|
|
}
|
|
|
|
// enable char button too, use temporal colstore for color
|
|
if(but->pointype!=FLO) {
|
|
if(but->pointype==CHA) {
|
|
ui_get_but_vectorf(but, colstore);
|
|
poin= colstore;
|
|
}
|
|
else return but->retval;
|
|
}
|
|
else poin= (float *)but->poin;
|
|
|
|
block= uiNewBlock(&listb, "colorpicker", UI_EMBOSSX, UI_HELV, but->win);
|
|
block->flag= UI_BLOCK_LOOP|UI_BLOCK_REDRAW;
|
|
block->themecol= TH_BUT_NUM;
|
|
|
|
uiBlockPickerButtons(block, poin, hsv, old, 'p', 0);
|
|
|
|
/* and lets go */
|
|
block->direction= UI_TOP;
|
|
ui_positionblock(block, but);
|
|
uiBoundsBlock(block, 3);
|
|
|
|
/* blocks can come from a normal window, but we go to screenspace */
|
|
block->win= G.curscreen->mainwin;
|
|
for(bt= block->buttons.first; bt; bt= bt->next) bt->win= block->win;
|
|
bwin_getsinglematrix(block->win, block->winmat);
|
|
|
|
event= uiDoBlocks(&listb, 0);
|
|
|
|
if(but->pointype==CHA) ui_set_but_vectorf(but, colstore);
|
|
|
|
return but->retval;
|
|
|
|
}
|
|
|
|
static int ui_do_but_HSVCUBE(uiBut *but)
|
|
{
|
|
uiBut *bt;
|
|
float x, y;
|
|
short mval[2], mvalo[2];
|
|
|
|
mvalo[0]= mvalo[1]= -32000;
|
|
|
|
/* we work on persistant hsv, to prevent it being converted back and forth all the time */
|
|
|
|
while (get_mbut() & L_MOUSE) {
|
|
|
|
uiGetMouse(mywinget(), mval);
|
|
|
|
if(mval[0]!=mvalo[0] || mval[1]!=mvalo[1]) {
|
|
mvalo[0]= mval[0];
|
|
mvalo[1]= mval[1];
|
|
|
|
/* relative position within box */
|
|
x= ((float)mval[0]-but->x1)/(but->x2-but->x1);
|
|
y= ((float)mval[1]-but->y1)/(but->y2-but->y1);
|
|
CLAMP(x, 0.0, 1.0);
|
|
CLAMP(y, 0.0, 1.0);
|
|
|
|
if(but->a1==0) {
|
|
but->hsv[0]= x;
|
|
but->hsv[2]= y;
|
|
// hsv_to_rgb(x, s, y, col, col+1, col+2);
|
|
}
|
|
else if(but->a1==1) {
|
|
but->hsv[0]= x;
|
|
but->hsv[1]= y;
|
|
// hsv_to_rgb(x, y, v, col, col+1, col+2);
|
|
}
|
|
else if(but->a1==2) {
|
|
but->hsv[2]= x;
|
|
but->hsv[1]= y;
|
|
// hsv_to_rgb(h, y, x, col, col+1, col+2);
|
|
}
|
|
else {
|
|
but->hsv[0]= x;
|
|
// hsv_to_rgb(x, s, v, col, col+1, col+2);
|
|
}
|
|
|
|
ui_set_but_hsv(but); // converts to rgb
|
|
|
|
// update button values and strings
|
|
update_picker_buts(but->block, but->hsv);
|
|
|
|
/* we redraw the entire block */
|
|
for (bt= but->block->buttons.first; bt; bt= bt->next) {
|
|
if(but->poin == bt->poin) VECCOPY(bt->hsv, but->hsv);
|
|
ui_draw_but(bt);
|
|
}
|
|
ui_block_flush_back(but->block);
|
|
}
|
|
else BIF_wait_for_statechange();
|
|
}
|
|
|
|
return but->retval;
|
|
}
|
|
|
|
|
|
/* ************************************************ */
|
|
|
|
void uiSetButLock(int val, char *lockstr)
|
|
{
|
|
UIlock |= val;
|
|
if (val) UIlockstr= lockstr;
|
|
}
|
|
|
|
void uiClearButLock()
|
|
{
|
|
UIlock= 0;
|
|
UIlockstr= NULL;
|
|
}
|
|
|
|
/* ********************** NEXT/PREV for arrowkeys etc ************** */
|
|
|
|
static uiBut *ui_but_prev(uiBut *but)
|
|
{
|
|
while(but->prev) {
|
|
but= but->prev;
|
|
if(but->type!=LABEL && but->type!=SEPR) return but;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
static uiBut *ui_but_next(uiBut *but)
|
|
{
|
|
while(but->next) {
|
|
but= but->next;
|
|
if(but->type!=LABEL && but->type!=SEPR) return but;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
static uiBut *ui_but_first(uiBlock *block)
|
|
{
|
|
uiBut *but;
|
|
|
|
but= block->buttons.first;
|
|
while(but) {
|
|
if(but->type!=LABEL && but->type!=SEPR) return but;
|
|
but= but->next;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
static uiBut *ui_but_last(uiBlock *block)
|
|
{
|
|
uiBut *but;
|
|
|
|
but= block->buttons.last;
|
|
while(but) {
|
|
if(but->type!=LABEL && but->type!=SEPR) return but;
|
|
but= but->prev;
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
/* *************************************************************** */
|
|
|
|
static void setup_file(uiBlock *block)
|
|
{
|
|
uiBut *but;
|
|
FILE *fp;
|
|
|
|
fp= fopen("butsetup","w");
|
|
if(fp==NULL);
|
|
else {
|
|
but= block->buttons.first;
|
|
while(but) {
|
|
ui_check_but(but);
|
|
fprintf(fp,"%d,%d,%d,%d %s %s\n", (int)but->x1, (int)but->y1, (int)( but->x2-but->x1), (int)(but->y2-but->y1), but->str, but->tip);
|
|
but= but->next;
|
|
}
|
|
fclose(fp);
|
|
}
|
|
}
|
|
|
|
|
|
static void edit_but(uiBlock *block, uiBut *but, uiEvent *uevent)
|
|
{
|
|
short dx, dy, mval[2], mvalo[2], didit=0;
|
|
|
|
getmouseco_sc(mvalo);
|
|
while(TRUE) {
|
|
if( !(get_mbut() & L_MOUSE) ) break;
|
|
|
|
getmouseco_sc(mval);
|
|
dx= (mval[0]-mvalo[0]);
|
|
dy= (mval[1]-mvalo[1]);
|
|
|
|
if(dx!=0 || dy!=0) {
|
|
mvalo[0]= mval[0];
|
|
mvalo[1]= mval[1];
|
|
|
|
cpack(0xc0c0c0);
|
|
glRectf(but->x1-2, but->y1-2, but->x2+2, but->y2+2);
|
|
|
|
if((uevent->qual & LR_SHIFTKEY)==0) {
|
|
but->x1 += dx;
|
|
but->y1 += dy;
|
|
}
|
|
but->x2 += dx;
|
|
but->y2 += dy;
|
|
|
|
ui_draw_but(but);
|
|
ui_block_flush_back(but->block);
|
|
didit= 1;
|
|
|
|
}
|
|
/* idle for this poor code */
|
|
else PIL_sleep_ms(30);
|
|
}
|
|
if(didit) setup_file(block);
|
|
}
|
|
|
|
|
|
/* is called when LEFTMOUSE is pressed or released
|
|
* return: butval or zero
|
|
*/
|
|
static int ui_do_button(uiBlock *block, uiBut *but, uiEvent *uevent)
|
|
{
|
|
int retval= 0;
|
|
|
|
if(but->lock) {
|
|
if (but->lockstr) {
|
|
error("%s", but->lockstr);
|
|
return 0;
|
|
}
|
|
}
|
|
else {
|
|
if( but->pointype ) { /* there's a pointer needed */
|
|
if(but->poin==0 ) {
|
|
printf("DoButton pointer error: %s\n",but->str);
|
|
return 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
if(G.rt==1 && (uevent->qual & LR_CTRLKEY)) {
|
|
edit_but(block, but, uevent);
|
|
return 0;
|
|
}
|
|
|
|
block->flag |= UI_BLOCK_BUSY;
|
|
|
|
switch(but->type) {
|
|
case BUT:
|
|
if(uevent->val) retval= ui_do_but_BUT(but);
|
|
break;
|
|
|
|
case KEYEVT:
|
|
if(uevent->val) retval= ui_do_but_KEYEVT(but);
|
|
break;
|
|
|
|
case TOG:
|
|
case TOGR:
|
|
case ICONTOG:
|
|
case TOGN:
|
|
if(uevent->val) {
|
|
retval= ui_do_but_TOG(block, but);
|
|
}
|
|
break;
|
|
|
|
case ROW:
|
|
if(uevent->val) retval= ui_do_but_ROW(block, but);
|
|
break;
|
|
|
|
case SCROLL:
|
|
/* DrawBut(b, 1); */
|
|
/* do_scrollbut(b); */
|
|
/* DrawBut(b,0); */
|
|
break;
|
|
|
|
case NUM:
|
|
if(uevent->val) retval= ui_do_but_NUM(but);
|
|
break;
|
|
|
|
case SLI:
|
|
case NUMSLI:
|
|
case HSVSLI:
|
|
if(uevent->val) retval= ui_do_but_NUMSLI(but);
|
|
break;
|
|
|
|
case LABEL:
|
|
if(uevent->val) retval= ui_do_but_LABEL(but);
|
|
break;
|
|
|
|
case TOG3:
|
|
if(uevent->val) retval= ui_do_but_TOG3(but);
|
|
break;
|
|
|
|
case TEX:
|
|
if(uevent->val) retval= ui_do_but_TEX(but);
|
|
break;
|
|
|
|
case MENU:
|
|
if(uevent->val) retval= ui_do_but_MENU(but);
|
|
break;
|
|
|
|
case ICONROW:
|
|
if(uevent->val) retval= ui_do_but_ICONROW(but);
|
|
break;
|
|
|
|
case ICONTEXTROW:
|
|
if(uevent->val) retval= ui_do_but_ICONTEXTROW(but);
|
|
break;
|
|
|
|
case IDPOIN:
|
|
if(uevent->val) retval= ui_do_but_IDPOIN(but);
|
|
break;
|
|
|
|
case BLOCK:
|
|
case PULLDOWN:
|
|
if(uevent->val) {
|
|
retval= ui_do_but_BLOCK(but);
|
|
if(block->auto_open==0) block->auto_open= 1;
|
|
}
|
|
break;
|
|
|
|
case BUTM:
|
|
retval= ui_do_but_BUTM(but);
|
|
break;
|
|
|
|
case LINK:
|
|
case INLINK:
|
|
retval= ui_do_but_LINK(block, but);
|
|
break;
|
|
|
|
case COL:
|
|
if(uevent->val) retval= ui_do_but_COL(but);
|
|
break;
|
|
|
|
case HSVCUBE:
|
|
retval= ui_do_but_HSVCUBE(but);
|
|
break;
|
|
}
|
|
|
|
block->flag &= ~UI_BLOCK_BUSY;
|
|
|
|
return retval;
|
|
}
|
|
|
|
static void ui_delete_active_linkline(uiBlock *block)
|
|
{
|
|
uiBut *but;
|
|
uiLink *link;
|
|
uiLinkLine *line, *nline;
|
|
int a, b;
|
|
|
|
but= block->buttons.first;
|
|
while(but) {
|
|
if(but->type==LINK && but->link) {
|
|
line= but->link->lines.first;
|
|
while(line) {
|
|
|
|
nline= line->next;
|
|
|
|
if(line->flag & UI_SELECT) {
|
|
BLI_remlink(&but->link->lines, line);
|
|
|
|
link= line->from->link;
|
|
|
|
/* are there more pointers allowed? */
|
|
if(link->ppoin) {
|
|
|
|
if(*(link->totlink)==1) {
|
|
*(link->totlink)= 0;
|
|
MEM_freeN(*(link->ppoin));
|
|
*(link->ppoin)= NULL;
|
|
}
|
|
else {
|
|
b= 0;
|
|
for(a=0; a< (*(link->totlink)); a++) {
|
|
|
|
if( (*(link->ppoin))[a] != line->to->poin ) {
|
|
(*(link->ppoin))[b]= (*(link->ppoin))[a];
|
|
b++;
|
|
}
|
|
}
|
|
(*(link->totlink))--;
|
|
}
|
|
}
|
|
else {
|
|
*(link->poin)= NULL;
|
|
}
|
|
|
|
MEM_freeN(line);
|
|
}
|
|
line= nline;
|
|
}
|
|
}
|
|
but= but->next;
|
|
}
|
|
|
|
/* temporal! these buttons can be everywhere... */
|
|
allqueue(REDRAWBUTSLOGIC, 0);
|
|
}
|
|
|
|
static void ui_do_active_linklines(uiBlock *block, short *mval)
|
|
{
|
|
uiBut *but;
|
|
uiLinkLine *line, *act= NULL;
|
|
float mindist= 12.0, fac, v1[2], v2[2], v3[3];
|
|
int foundone= 0;
|
|
|
|
if(mval) {
|
|
v1[0]= mval[0];
|
|
v1[1]= mval[1];
|
|
|
|
/* find a line close to the mouse */
|
|
but= block->buttons.first;
|
|
while(but) {
|
|
if(but->type==LINK && but->link) {
|
|
foundone= 1;
|
|
line= but->link->lines.first;
|
|
while(line) {
|
|
v2[0]= line->from->x2;
|
|
v2[1]= (line->from->y1+line->from->y2)/2.0;
|
|
v3[0]= line->to->x1;
|
|
v3[1]= (line->to->y1+line->to->y2)/2.0;
|
|
|
|
fac= PdistVL2Dfl(v1, v2, v3);
|
|
if(fac < mindist) {
|
|
mindist= fac;
|
|
act= line;
|
|
}
|
|
line= line->next;
|
|
}
|
|
}
|
|
but= but->next;
|
|
}
|
|
}
|
|
|
|
/* check for a 'found one' to prevent going to 'frontbuffer' mode.
|
|
this slows done gfx quite some, and at OSX the 'finish' forces a swapbuffer */
|
|
if(foundone) {
|
|
glDrawBuffer(GL_FRONT);
|
|
|
|
/* draw */
|
|
but= block->buttons.first;
|
|
while(but) {
|
|
if(but->type==LINK && but->link) {
|
|
line= but->link->lines.first;
|
|
while(line) {
|
|
if(line==act) {
|
|
if((line->flag & UI_SELECT)==0) {
|
|
line->flag |= UI_SELECT;
|
|
ui_draw_linkline(but, line);
|
|
}
|
|
}
|
|
else if(line->flag & UI_SELECT) {
|
|
line->flag &= ~UI_SELECT;
|
|
ui_draw_linkline(but, line);
|
|
}
|
|
line= line->next;
|
|
}
|
|
}
|
|
but= but->next;
|
|
}
|
|
glFlush();
|
|
glDrawBuffer(GL_BACK);
|
|
}
|
|
}
|
|
|
|
|
|
/* only to be used to prevent an 'outside' event when using nested pulldowns */
|
|
/* only one checks:
|
|
- while mouse moves in triangular area defined old mouse position and left/right side of new menu
|
|
- only for 1 second
|
|
|
|
return 0: check outside
|
|
*/
|
|
static int ui_mouse_motion_towards_block(uiBlock *block, uiEvent *uevent)
|
|
{
|
|
short mvalo[2], dx, dy, domx, domy;
|
|
int counter=0;
|
|
|
|
if((block->direction & UI_TOP) || (block->direction & UI_DOWN)) return 0;
|
|
if(uevent->event!= MOUSEX && uevent->event!= MOUSEY) return 0;
|
|
|
|
/* calculate dominant direction */
|
|
domx= ( -uevent->mval[0] + (block->maxx+block->minx)/2 );
|
|
domy= ( -uevent->mval[1] + (block->maxy+block->miny)/2 );
|
|
/* we need some accuracy */
|
|
if( abs(domx)<4 ) return 0;
|
|
|
|
uiGetMouse(mywinget(), mvalo);
|
|
|
|
while(TRUE) {
|
|
uiGetMouse(mywinget(), uevent->mval);
|
|
|
|
/* check inside, if so return */
|
|
if( block->minx <= uevent->mval[0] && block->maxx >= uevent->mval[0] ) {
|
|
if( block->miny <= uevent->mval[1] && block->maxy >= uevent->mval[1] ) {
|
|
return 1;
|
|
}
|
|
}
|
|
|
|
/* check direction */
|
|
dx= uevent->mval[0] - mvalo[0];
|
|
dy= uevent->mval[1] - mvalo[1];
|
|
|
|
if( abs(dx)+abs(dy)>4 ) { // threshold
|
|
/* menu to right */
|
|
if(domx>0) {
|
|
int fac= (uevent->mval[0] - mvalo[0])*(mvalo[1] - (short)(block->maxy +20)) + (uevent->mval[1] - mvalo[1])*(-mvalo[0] + (short)block->minx);
|
|
if( (fac>0)) {
|
|
// printf("Left outside 1, Fac %d\n", fac);
|
|
return 0;
|
|
}
|
|
|
|
fac= (uevent->mval[0] - mvalo[0])*(mvalo[1] - (short)(block->miny-20)) + (uevent->mval[1] - mvalo[1])*(-mvalo[0] + (short)block->minx);
|
|
if( (fac<0)) {
|
|
//printf("Left outside 2, Fac %d\n", fac);
|
|
return 0;
|
|
}
|
|
}
|
|
else {
|
|
int fac= (uevent->mval[0] - mvalo[0])*(mvalo[1] - (short)(block->maxy+20)) + (uevent->mval[1] - mvalo[1])*(-mvalo[0] + (short)block->maxx);
|
|
if( (fac<0)) {
|
|
// printf("Left outside 1, Fac %d\n", fac);
|
|
return 0;
|
|
}
|
|
|
|
fac= (uevent->mval[0] - mvalo[0])*(mvalo[1] - (short)(block->miny-20)) + (uevent->mval[1] - mvalo[1])*(-mvalo[0] + (short)block->maxx);
|
|
if( (fac>0)) {
|
|
// printf("Left outside 2, Fac %d\n", fac);
|
|
return 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* idle for this poor code */
|
|
PIL_sleep_ms(10);
|
|
counter++;
|
|
if(counter > 100) {
|
|
//printf("left because of timer (1 sec)\n");
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
static void ui_set_ftf_font(uiBlock *block)
|
|
{
|
|
|
|
#ifdef INTERNATIONAL
|
|
if(block->aspect<1.15) {
|
|
FTF_SetFontSize('l');
|
|
}
|
|
else if(block->aspect<1.59) {
|
|
FTF_SetFontSize('m');
|
|
}
|
|
else {
|
|
FTF_SetFontSize('s');
|
|
}
|
|
#endif
|
|
}
|
|
|
|
|
|
/* return:
|
|
* UI_NOTHING pass event to other ui's
|
|
* UI_CONT don't pass event to other ui's
|
|
* UI_RETURN something happened, return, swallow event
|
|
*/
|
|
static int ui_do_block(uiBlock *block, uiEvent *uevent)
|
|
{
|
|
uiBut *but, *bt;
|
|
int butevent, event, retval=UI_NOTHING, count, act=0;
|
|
int inside= 0, active=0;
|
|
|
|
if(block->win != mywinget()) return UI_NOTHING;
|
|
|
|
/* filter some unwanted events */
|
|
/* btw: we allow event==0 for first time in menus, draws the hilited item */
|
|
if(uevent==0 || uevent->event==LEFTSHIFTKEY || uevent->event==RIGHTSHIFTKEY) return UI_NOTHING;
|
|
|
|
if(block->flag & UI_BLOCK_ENTER_OK) {
|
|
if((uevent->event==RETKEY || uevent->event==PADENTER) && uevent->val) {
|
|
// printf("qual: %d %d %d\n", uevent->qual, get_qual(), G.qual);
|
|
if ((G.qual & LR_SHIFTKEY) == 0) {
|
|
return UI_RETURN_OK;
|
|
}
|
|
}
|
|
}
|
|
|
|
ui_set_ftf_font(block); // sets just a pointer in ftf lib... the button dont have ftf handles
|
|
|
|
// added this for panels in windows with buttons...
|
|
// maybe speed optimize should require test
|
|
if((block->flag & UI_BLOCK_LOOP)==0) {
|
|
glMatrixMode(GL_PROJECTION);
|
|
bwin_load_winmatrix(block->win, block->winmat);
|
|
glMatrixMode(GL_MODELVIEW);
|
|
glLoadIdentity();
|
|
}
|
|
|
|
Mat4CpyMat4(UIwinmat, block->winmat);
|
|
uiPanelPush(block); // push matrix; no return without pop!
|
|
|
|
uiGetMouse(mywinget(), uevent->mval); /* transformed mouseco */
|
|
|
|
/* check boundbox and panel events */
|
|
if( block->minx <= uevent->mval[0] && block->maxx >= uevent->mval[0] ) {
|
|
// inside block
|
|
if( block->miny <= uevent->mval[1] && block->maxy >= uevent->mval[1] ) inside= 1;
|
|
|
|
if(block->panel && block->panel->paneltab==NULL) {
|
|
|
|
/* clicked at panel header? */
|
|
if( block->panel->flag & PNL_CLOSEDX) {
|
|
if(block->minx <= uevent->mval[0] && block->minx+PNL_HEADER >= uevent->mval[0])
|
|
inside= 2;
|
|
}
|
|
else if( (block->maxy <= uevent->mval[1]) && (block->maxy+PNL_HEADER >= uevent->mval[1]) )
|
|
inside= 2;
|
|
|
|
if(inside) { // this stuff should move to do_panel
|
|
|
|
if(uevent->event==LEFTMOUSE) {
|
|
if(inside==2) {
|
|
uiPanelPop(block); // pop matrix; no return without pop!
|
|
ui_do_panel(block, uevent);
|
|
return UI_EXIT_LOOP; // exit loops because of moving panels
|
|
}
|
|
}
|
|
else if(uevent->event==ESCKEY) {
|
|
if(block->handler) {
|
|
rem_blockhandler(curarea, block->handler);
|
|
addqueue(curarea->win, REDRAW, 1);
|
|
}
|
|
}
|
|
else if(uevent->event==PADPLUSKEY || uevent->event==PADMINUS) {
|
|
SpaceLink *sl= curarea->spacedata.first;
|
|
if(curarea->spacetype!=SPACE_BUTS) {
|
|
if(uevent->event==PADPLUSKEY) sl->blockscale+= 0.1;
|
|
else sl->blockscale-= 0.1;
|
|
CLAMP(sl->blockscale, 0.6, 1.0);
|
|
addqueue(block->winq, REDRAW, 1);
|
|
retval= UI_CONT;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
switch(uevent->event) {
|
|
case LEFTARROWKEY: // later on implement opening/closing sublevels of pupmenus
|
|
case RIGHTARROWKEY:
|
|
break;
|
|
|
|
case PAD8: case PAD2:
|
|
case UPARROWKEY:
|
|
case DOWNARROWKEY:
|
|
if(inside || (block->flag & UI_BLOCK_LOOP)) {
|
|
/* arrowkeys: only handle for block_loop blocks */
|
|
event= 0;
|
|
if(block->flag & UI_BLOCK_LOOP) {
|
|
event= uevent->event;
|
|
if(event==PAD8) event= UPARROWKEY;
|
|
if(event==PAD2) event= DOWNARROWKEY;
|
|
}
|
|
else {
|
|
if(uevent->event==PAD8) event= UPARROWKEY;
|
|
if(uevent->event==PAD2) event= DOWNARROWKEY;
|
|
}
|
|
if(event && uevent->val) {
|
|
|
|
for(but= block->buttons.first; but; but= but->next) {
|
|
but->flag &= ~UI_MOUSE_OVER;
|
|
|
|
if(but->flag & UI_ACTIVE) {
|
|
but->flag &= ~UI_ACTIVE;
|
|
ui_draw_but(but);
|
|
|
|
if(event==UPARROWKEY) {
|
|
if(block->direction & UI_TOP) bt= ui_but_next(but);
|
|
else bt= ui_but_prev(but);
|
|
}
|
|
else {
|
|
if(block->direction & UI_TOP) bt= ui_but_prev(but);
|
|
else bt= ui_but_next(but);
|
|
}
|
|
|
|
if(bt) {
|
|
bt->flag |= UI_ACTIVE;
|
|
ui_draw_but(bt);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
/* nothing done */
|
|
if(but==NULL) {
|
|
|
|
if(event==UPARROWKEY) {
|
|
if(block->direction & UI_TOP) but= ui_but_first(block);
|
|
else but= ui_but_last(block);
|
|
}
|
|
else {
|
|
if(block->direction & UI_TOP) but= ui_but_last(block);
|
|
else but= ui_but_first(block);
|
|
}
|
|
if(but) {
|
|
but->flag |= UI_ACTIVE;
|
|
ui_draw_but(but);
|
|
}
|
|
}
|
|
retval= UI_CONT;
|
|
}
|
|
}
|
|
break;
|
|
|
|
case ONEKEY: act= 1;
|
|
case TWOKEY: if(act==0) act= 2;
|
|
case THREEKEY: if(act==0) act= 3;
|
|
case FOURKEY: if(act==0) act= 4;
|
|
case FIVEKEY: if(act==0) act= 5;
|
|
case SIXKEY: if(act==0) act= 6;
|
|
case SEVENKEY: if(act==0) act= 7;
|
|
case EIGHTKEY: if(act==0) act= 8;
|
|
case NINEKEY: if(act==0) act= 9;
|
|
case ZEROKEY: if(act==0) act= 10;
|
|
|
|
if( block->flag & UI_BLOCK_NUMSELECT ) {
|
|
|
|
if(get_qual() & LR_ALTKEY) act+= 10;
|
|
|
|
count= 0;
|
|
for(but= block->buttons.first; but; but= but->next) {
|
|
int doit= 0;
|
|
|
|
if(but->type!=LABEL && but->type!=SEPR) count++;
|
|
/* exception for menus like layer buts, with button aligning they're not drawn in order */
|
|
if(but->type==TOGR) {
|
|
if(but->bitnr==act-1) doit= 1;
|
|
} else if(count==act) doit=1;
|
|
|
|
if(doit) {
|
|
but->flag |= UI_ACTIVE;
|
|
if(uevent->val==1) ui_draw_but(but);
|
|
else if(block->flag & UI_BLOCK_RET_1) { /* to make UI_BLOCK_RET_1 working */
|
|
uevent->event= RETKEY;
|
|
uevent->val= 1;
|
|
//addqueue(block->winq, RIGHTARROWKEY, 1); (why! (ton))
|
|
}
|
|
else {
|
|
uevent->event= LEFTMOUSE; /* to make sure the button is handled further on */
|
|
uevent->val= 1;
|
|
}
|
|
}
|
|
else if(but->flag & UI_ACTIVE) {
|
|
but->flag &= ~UI_ACTIVE;
|
|
ui_draw_but(but);
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
case BUT_ACTIVATE:
|
|
for(but= block->buttons.first; but; but= but->next) {
|
|
if(but->retval==uevent->val) but->flag |= UI_ACTIVE;
|
|
}
|
|
break;
|
|
case VKEY:
|
|
case CKEY:
|
|
if(uevent->val && (uevent->qual & (LR_CTRLKEY|LR_COMMANDKEY))) {
|
|
for(but= block->buttons.first; but; but= but->next) {
|
|
if(but->type!=LABEL) {
|
|
if(but->flag & UI_ACTIVE) {
|
|
int doit=0;
|
|
|
|
if(uevent->event==VKEY) doit= ui_but_copy_paste(but, 'v');
|
|
else ui_but_copy_paste(but, 'c');
|
|
|
|
if(doit) {
|
|
ui_draw_but(but);
|
|
|
|
if(but->retval) addqueue(block->winq, UI_BUT_EVENT, (short)but->retval);
|
|
if((but->type==NUMSLI && but->a1) || (but->type==COL)) addqueue(block->winq, REDRAW, 1); // col button update
|
|
|
|
BIF_undo_push(but->str);
|
|
}
|
|
// but we do return, to prevent passing event through other queues */
|
|
if( (block->flag & UI_BLOCK_LOOP) && but->type==BLOCK);
|
|
else if(but->retval) retval= UI_RETURN_OK;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
break;
|
|
|
|
case PADENTER:
|
|
case RETKEY: // prevent treating this as mousemove. for example when you enter at popup
|
|
if(block->flag & UI_BLOCK_LOOP) break;
|
|
|
|
default:
|
|
|
|
for(but= block->buttons.first; but; but= but->next) {
|
|
|
|
// active flag clear, it can have been set with number keys or arrows, prevents next loop from wrong selection on click
|
|
if(uevent->event==LEFTMOUSE) but->flag &= ~UI_ACTIVE;
|
|
|
|
but->flag &= ~UI_MOUSE_OVER;
|
|
|
|
/* check boundbox */
|
|
if (uibut_contains_pt(but, uevent->mval)) {
|
|
but->flag |= UI_MOUSE_OVER;
|
|
UIbuttip= but;
|
|
}
|
|
/* hilite case 1 */
|
|
if(but->flag & UI_MOUSE_OVER) {
|
|
if( (but->flag & UI_ACTIVE)==0) {
|
|
but->flag |= UI_ACTIVE;
|
|
if(but->type != LABEL && (but->flag & UI_NO_HILITE)==0) ui_draw_but(but);
|
|
}
|
|
}
|
|
/* hilite case 2 */
|
|
if(but->flag & UI_ACTIVE) {
|
|
if( (but->flag & UI_MOUSE_OVER)==0) {
|
|
/* we dont clear active flag until mouse move, for Menu buttons to remain showing active item when opened */
|
|
if (uevent->event==MOUSEY) {
|
|
but->flag &= ~UI_ACTIVE;
|
|
if(but->type != LABEL && (but->flag & UI_NO_HILITE)==0) ui_draw_but(but);
|
|
}
|
|
}
|
|
else if(but->type==BLOCK || but->type==MENU || but->type==PULLDOWN || but->type==ICONTEXTROW) { // automatic opens block button (pulldown)
|
|
int time;
|
|
if(uevent->event!=LEFTMOUSE ) {
|
|
if(block->auto_open==2) time= 1; // test for toolbox
|
|
else if(block->auto_open) time= 5*U.menuthreshold2;
|
|
else if(U.uiflag & USER_MENUOPENAUTO) time= 5*U.menuthreshold1;
|
|
else time= -1;
|
|
|
|
for (; time>0; time--) {
|
|
if (qtest()) break;
|
|
else PIL_sleep_ms(20);
|
|
}
|
|
|
|
if(time==0) {
|
|
uevent->val= 1; // otherwise buttons dont react
|
|
ui_do_button(block, but, uevent);
|
|
}
|
|
}
|
|
}
|
|
if(but->flag & UI_ACTIVE) active= 1;
|
|
}
|
|
}
|
|
|
|
/* if there are no active buttons... otherwise clear lines */
|
|
if(active) ui_do_active_linklines(block, 0);
|
|
else ui_do_active_linklines(block, uevent->mval);
|
|
|
|
}
|
|
|
|
/* middlemouse exception, not for regular blocks */
|
|
if( (block->flag & UI_BLOCK_LOOP) && uevent->event==MIDDLEMOUSE) uevent->event= LEFTMOUSE;
|
|
|
|
/* the final dobutton */
|
|
for(but= block->buttons.first; but; but= but->next) {
|
|
if(but->flag & UI_ACTIVE) {
|
|
|
|
/* UI_BLOCK_RET_1: not return when val==0 */
|
|
|
|
if(uevent->val || (block->flag & UI_BLOCK_RET_1)==0) {
|
|
if ELEM4(uevent->event, LEFTMOUSE, PADENTER, RETKEY, BUT_ACTIVATE) {
|
|
/* when mouse outside, don't do button */
|
|
if(inside || uevent->event!=LEFTMOUSE) {
|
|
butevent= ui_do_button(block, but, uevent);
|
|
|
|
/* add undo pushes if... */
|
|
if( !(block->flag & UI_BLOCK_LOOP)) {
|
|
if(!G.obedit) {
|
|
if ELEM4(but->type, BLOCK, BUT, LABEL, PULLDOWN);
|
|
else {
|
|
/* define which string to use for undo */
|
|
if ELEM(but->type, LINK, INLINK) screen_delayed_undo_push("Add button link");
|
|
else if ELEM(but->type, MENU, ICONTEXTROW) screen_delayed_undo_push(but->drawstr);
|
|
else if(but->drawstr[0]) screen_delayed_undo_push(but->drawstr);
|
|
else screen_delayed_undo_push(but->tip);
|
|
}
|
|
}
|
|
}
|
|
|
|
if(butevent) addqueue(block->winq, UI_BUT_EVENT, (short)butevent);
|
|
|
|
/* i doubt about the next line! */
|
|
/* if(but->func) mywinset(block->win); */
|
|
|
|
if( (block->flag & UI_BLOCK_LOOP) && but->type==BLOCK);
|
|
else
|
|
if(/*but->func ||*/ butevent) retval= UI_RETURN_OK;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/* flush to frontbuffer */
|
|
if((block->flag & UI_BLOCK_LOOP)==0) { // no loop, might need total flush in uidoblocks()
|
|
ui_block_flush_back(block);
|
|
}
|
|
|
|
uiPanelPop(block); // pop matrix; no return without pop!
|
|
|
|
|
|
/* the linkines... why not make buttons from it? Speed? Memory? */
|
|
if(uevent->val && (uevent->event==XKEY || uevent->event==DELKEY))
|
|
ui_delete_active_linkline(block);
|
|
|
|
if(block->flag & UI_BLOCK_LOOP) {
|
|
|
|
if(inside==0 && uevent->val==1) {
|
|
if ELEM3(uevent->event, LEFTMOUSE, MIDDLEMOUSE, RIGHTMOUSE) {
|
|
if(BLI_in_rctf(&block->parentrct, (float)uevent->mval[0], (float)uevent->mval[1]));
|
|
else return UI_RETURN_OUT;
|
|
}
|
|
}
|
|
|
|
if(uevent->event==ESCKEY && uevent->val==1) return UI_RETURN_CANCEL;
|
|
|
|
if((uevent->event==RETKEY || uevent->event==PADENTER) && uevent->val==1) return UI_RETURN_OK;
|
|
|
|
/* check outside */
|
|
if(inside==0) {
|
|
/* strict check, and include the parent rect */
|
|
if( BLI_in_rctf(&block->parentrct, (float)uevent->mval[0], (float)uevent->mval[1]));
|
|
else if( ui_mouse_motion_towards_block(block, uevent));
|
|
else if( BLI_in_rctf(&block->safety, (float)uevent->mval[0], (float)uevent->mval[1]));
|
|
else return UI_RETURN_OUT;
|
|
}
|
|
}
|
|
|
|
return retval;
|
|
}
|
|
|
|
static uiOverDraw *ui_draw_but_tip(uiBut *but)
|
|
{
|
|
uiOverDraw *od;
|
|
float x1, x2, y1, y2;
|
|
|
|
#ifdef INTERNATIONAL
|
|
if(G.ui_international == TRUE) {
|
|
float llx,lly,llz,urx,ury,urz; //for FTF_GetBoundingBox()
|
|
|
|
if(U.transopts & USER_TR_TOOLTIPS) {
|
|
FTF_GetBoundingBox(but->tip, &llx,&lly,&llz,&urx,&ury,&urz, FTF_USE_GETTEXT | FTF_INPUT_UTF8);
|
|
|
|
x1= (but->x1+but->x2)/2; x2= 10+x1+ but->aspect*FTF_GetStringWidth(but->tip, FTF_USE_GETTEXT | FTF_INPUT_UTF8); //BMF_GetStringWidth(but->font, but->tip);
|
|
y1= but->y1-(ury+FTF_GetSize())-12; y2= but->y1-12;
|
|
} else {
|
|
FTF_GetBoundingBox(but->tip, &llx,&lly,&llz,&urx,&ury,&urz, FTF_NO_TRANSCONV | FTF_INPUT_UTF8);
|
|
|
|
x1= (but->x1+but->x2)/2; x2= 10+x1+ but->aspect*FTF_GetStringWidth(but->tip, FTF_NO_TRANSCONV | FTF_INPUT_UTF8); //BMF_GetStringWidth(but->font, but->tip);
|
|
y1= but->y1-(ury+FTF_GetSize())-12; y2= but->y1-12;
|
|
}
|
|
} else {
|
|
x1= (but->x1+but->x2)/2; x2= 10+x1+ but->aspect*BMF_GetStringWidth(but->font, but->tip);
|
|
y1= but->y1-30; y2= but->y1-12;
|
|
}
|
|
#else
|
|
x1= (but->x1+but->x2)/2; x2= 10+x1+ but->aspect*BMF_GetStringWidth(but->font, but->tip);
|
|
y1= but->y1-30; y2= but->y1-12;
|
|
#endif
|
|
|
|
/* for pulldown menus it doesnt work */
|
|
if(mywinget()==G.curscreen->mainwin);
|
|
else {
|
|
ui_graphics_to_window(mywinget(), &x1, &y1);
|
|
ui_graphics_to_window(mywinget(), &x2, &y2);
|
|
}
|
|
|
|
if(x2 > G.curscreen->sizex) {
|
|
x1 -= x2-G.curscreen->sizex;
|
|
x2= G.curscreen->sizex;
|
|
}
|
|
if(y1 < 0) {
|
|
y1 += 36;
|
|
y2 += 36;
|
|
}
|
|
|
|
// adjust tooltip heights
|
|
if(mywinget()==G.curscreen->mainwin)
|
|
y2 -= G.ui_international ? 4:1; //tip is from pulldownmenu
|
|
else if(curarea->win != mywinget())
|
|
y2 -= G.ui_international ? 5:1; //tip is from a windowheader
|
|
// else y2 += 1; //tip is from button area
|
|
|
|
od= ui_begin_overdraw((int)(x1-1), (int)(y1-2), (int)(x2+4), (int)(y2+4));
|
|
|
|
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
|
glEnable(GL_BLEND);
|
|
|
|
glColor4ub(0, 0, 0, 20);
|
|
|
|
gl_round_box(GL_POLYGON, x1+3, y1-1, x2+1, y2-2, 2.0);
|
|
gl_round_box(GL_POLYGON, x1+3, y1-2, x2+2, y2-2, 3.0);
|
|
|
|
glColor4ub(0, 0, 0, 8);
|
|
|
|
gl_round_box(GL_POLYGON, x1+3, y1-3, x2+3, y2-3, 4.0);
|
|
gl_round_box(GL_POLYGON, x1+3, y1-4, x2+4, y2-3, 5.0);
|
|
|
|
glDisable(GL_BLEND);
|
|
|
|
glColor3ub(0xFF, 0xFF, 0xDD);
|
|
glRectf(x1, y1, x2, y2);
|
|
|
|
glColor3ub(0,0,0);
|
|
ui_rasterpos_safe( x1+3, y1+5.0/but->aspect, but->aspect);
|
|
BIF_SetScale(1.0);
|
|
|
|
BIF_DrawString(but->font, but->tip, (U.transopts & USER_TR_TOOLTIPS));
|
|
|
|
ui_flush_overdraw(od); /* to show it in the frontbuffer */
|
|
return od;
|
|
}
|
|
|
|
/* inside this function no global UIbuttip... qread is not safe */
|
|
static void ui_do_but_tip(uiBut *buttip)
|
|
{
|
|
uiOverDraw *od;
|
|
int time;
|
|
|
|
if (buttip && buttip->tip && buttip->tip[0]) {
|
|
/* Pause for a moment to see if we
|
|
* should really display the tip
|
|
* or if the user will keep moving
|
|
* the pointer.
|
|
*/
|
|
for (time= 0; time<25; time++) {
|
|
if (anyqtest())
|
|
return;
|
|
else
|
|
PIL_sleep_ms(20);
|
|
}
|
|
|
|
/* Display the tip, and keep it displayed
|
|
* as long as the mouse remains on top
|
|
* of the button that owns it.
|
|
*/
|
|
uiPanelPush(buttip->block); // panel matrix
|
|
od= ui_draw_but_tip(buttip);
|
|
|
|
while (1) {
|
|
char ascii;
|
|
short val;
|
|
unsigned short evt= extern_qread_ext(&val, &ascii);
|
|
|
|
if (evt==MOUSEX || evt==MOUSEY) {
|
|
short mouse[2];
|
|
uiGetMouse(od->oldwin, mouse);
|
|
|
|
if (!uibut_contains_pt(buttip, mouse))
|
|
break;
|
|
} else {
|
|
mainqpushback(evt, val, ascii);
|
|
break;
|
|
}
|
|
}
|
|
|
|
ui_end_overdraw(od);
|
|
uiPanelPop(buttip->block); // panel matrix
|
|
/* still the evil global.... */
|
|
UIbuttip= NULL;
|
|
}
|
|
}
|
|
|
|
/* returns UI_NOTHING, if nothing happened */
|
|
int uiDoBlocks(ListBase *lb, int event)
|
|
{
|
|
/* return when: firstblock != BLOCK_LOOP
|
|
*
|
|
* 'cont' is used to make sure you can press another button while a looping menu
|
|
* is active. otherwise you have to press twice...
|
|
*/
|
|
|
|
uiBlock *block, *first;
|
|
uiEvent uevent;
|
|
int retval= UI_NOTHING, cont= 1;
|
|
|
|
if(lb->first==0) return UI_NOTHING;
|
|
|
|
/* for every pixel both x and y events are generated, overloads the system! */
|
|
if(event==MOUSEX) return UI_NOTHING;
|
|
|
|
UIbuttip= NULL;
|
|
UIafterfunc= NULL; /* to prevent infinite loops, this shouldnt be a global! */
|
|
|
|
uevent.qual= G.qual;
|
|
uevent.event= event;
|
|
uevent.val= 1;
|
|
|
|
/* this is a caching mechanism, to prevent too many calls to glFrontBuffer and glFlush, which slows down interface */
|
|
block= lb->first;
|
|
while(block) {
|
|
ui_block_set_flush(block, NULL); // clears all flushing info
|
|
block= block->next;
|
|
}
|
|
|
|
/* main loop, needed when you click outside a looping block (menu) then it uses that
|
|
event to immediately evaluate the other uiBlocks again. */
|
|
while(cont) {
|
|
|
|
/* first loop, for the normal blocks */
|
|
block= lb->first;
|
|
while(block) {
|
|
|
|
/* for pupmenus, the bgnpupdraw sets (and later restores) the active
|
|
window. Then mousecoords get transformed OK.
|
|
It looks double... but a call to ui_do_block otherwise doesnt get handled properly
|
|
*/
|
|
if(block->flag & UI_BLOCK_REDRAW) {
|
|
if( block->flag & UI_BLOCK_LOOP) {
|
|
block->overdraw= ui_begin_overdraw((int)block->minx-1, (int)block->miny-10, (int)block->maxx+10, (int)block->maxy+1);
|
|
}
|
|
block->in_use= 1; // is always a menu
|
|
uiDrawBlock(block);
|
|
block->flag &= ~UI_BLOCK_REDRAW;
|
|
}
|
|
|
|
block->in_use= 1; // bit awkward, but now we can detect if frontbuf flush should be set
|
|
retval= ui_do_block(block, &uevent);
|
|
block->in_use= 0;
|
|
if(retval==UI_EXIT_LOOP) break;
|
|
|
|
/* now a new block could be created for menus, this is
|
|
inserted in the beginning of a list */
|
|
|
|
/* is there a flush cached? */
|
|
if(block->needflush) {
|
|
ui_block_flush_overdraw(block);
|
|
block->needflush= 0;
|
|
}
|
|
|
|
/* to make sure the matrix of the panel works for menus too */
|
|
if(retval==UI_CONT || (retval & UI_RETURN)) break;
|
|
first= lb->first; if(first->flag & UI_BLOCK_LOOP) break;
|
|
|
|
block= block->next;
|
|
}
|
|
|
|
/* second loop, for menus (looping blocks). works for sub->menus too */
|
|
block= lb->first;
|
|
if(block==NULL || (block->flag & UI_BLOCK_LOOP)==0) cont= 0;
|
|
|
|
while( (block= lb->first) && (block->flag & UI_BLOCK_LOOP)) {
|
|
if(block->auto_open==0) block->auto_open= 1;
|
|
|
|
/* this here, for menu buts */
|
|
if(block->flag & UI_BLOCK_REDRAW) {
|
|
|
|
if( block->flag & UI_BLOCK_LOOP) {
|
|
block->overdraw= ui_begin_overdraw((int)block->minx-1, (int)block->miny-6, (int)block->maxx+6, (int)block->maxy+1);
|
|
}
|
|
uiDrawBlock(block);
|
|
block->flag &= ~UI_BLOCK_REDRAW;
|
|
ui_flush_overdraw(block->overdraw);
|
|
block->needflush= 0;
|
|
}
|
|
|
|
uevent.event= extern_qread(&uevent.val);
|
|
uevent.qual= G.qual;
|
|
|
|
if(uevent.event) {
|
|
block->in_use= 1; // bit awkward, but now we can detect if frontbuf flush should be set
|
|
retval= ui_do_block(block, &uevent);
|
|
block->in_use= 0;
|
|
|
|
if(block->needflush) { // flush (old menu) now, maybe new menu was opened
|
|
ui_block_flush_overdraw(block);
|
|
block->needflush= 0;
|
|
}
|
|
|
|
if(retval & UI_RETURN) {
|
|
ui_end_overdraw(block->overdraw);
|
|
BLI_remlink(lb, block);
|
|
uiFreeBlock(block);
|
|
}
|
|
if(retval & (UI_RETURN_OK|UI_RETURN_CANCEL)) {
|
|
/* free other menus */
|
|
while( (block= lb->first) && (block->flag & UI_BLOCK_LOOP)) {
|
|
ui_end_overdraw(block->overdraw);
|
|
BLI_remlink(lb, block);
|
|
uiFreeBlock(block);
|
|
}
|
|
}
|
|
}
|
|
|
|
/* tooltip */
|
|
if(retval==UI_NOTHING && (uevent.event==MOUSEX || uevent.event==MOUSEY)) {
|
|
if(U.flag & USER_TOOLTIPS) ui_do_but_tip(UIbuttip);
|
|
}
|
|
}
|
|
|
|
/* else it does the first part of this loop again, maybe another menu needs to be opened */
|
|
if(retval==UI_CONT || (retval & UI_RETURN_OK)) cont= 0;
|
|
}
|
|
|
|
/* afterfunc is used for fileloading too, so after this call, the blocks pointers are invalid */
|
|
if(retval & UI_RETURN_OK) {
|
|
if(UIafterfunc) {
|
|
mywinset(curarea->win);
|
|
UIafterfunc(UIafterfunc_arg, UIafterval);
|
|
}
|
|
UIafterfunc= NULL;
|
|
}
|
|
|
|
/* tooltip */
|
|
if(retval==UI_NOTHING && (uevent.event==MOUSEX || uevent.event==MOUSEY)) {
|
|
if(U.flag & USER_TOOLTIPS) ui_do_but_tip(UIbuttip);
|
|
}
|
|
|
|
return retval;
|
|
}
|
|
|
|
/* ************** DATA *************** */
|
|
|
|
/* for buttons pointing to color for example */
|
|
void ui_get_but_vectorf(uiBut *but, float *vec)
|
|
{
|
|
void *poin;
|
|
|
|
poin= but->poin;
|
|
|
|
if( but->pointype == CHA ) {
|
|
char *cp= (char *)poin;
|
|
vec[0]= ((float)cp[0])/255.0;
|
|
vec[1]= ((float)cp[1])/255.0;
|
|
vec[2]= ((float)cp[2])/255.0;
|
|
}
|
|
else if( but->pointype == FLO ) {
|
|
float *fp= (float *)poin;
|
|
VECCOPY(vec, fp);
|
|
}
|
|
}
|
|
/* for buttons pointing to color for example */
|
|
void ui_set_but_vectorf(uiBut *but, float *vec)
|
|
{
|
|
void *poin;
|
|
|
|
poin= but->poin;
|
|
|
|
if( but->pointype == CHA ) {
|
|
char *cp= (char *)poin;
|
|
cp[0]= (char)(0.5 +vec[0]*255.0);
|
|
cp[1]= (char)(0.5 +vec[1]*255.0);
|
|
cp[2]= (char)(0.5 +vec[2]*255.0);
|
|
}
|
|
else if( but->pointype == FLO ) {
|
|
float *fp= (float *)poin;
|
|
VECCOPY(fp, vec);
|
|
}
|
|
}
|
|
|
|
double ui_get_but_val(uiBut *but)
|
|
{
|
|
void *poin;
|
|
double value = 0.0;
|
|
|
|
poin= but->poin;
|
|
|
|
if(but->type== HSVSLI) {
|
|
float h, s, v, *fp= (float *) poin;
|
|
|
|
rgb_to_hsv(fp[0], fp[1], fp[2], &h, &s, &v);
|
|
|
|
switch(but->str[0]) {
|
|
case 'H': value= h; break;
|
|
case 'S': value= s; break;
|
|
case 'V': value= v; break;
|
|
}
|
|
|
|
}
|
|
else if( but->pointype == CHA ) {
|
|
value= *(char *)poin;
|
|
}
|
|
else if( but->pointype == SHO ) {
|
|
value= *(short *)poin;
|
|
}
|
|
else if( but->pointype == INT ) {
|
|
value= *(int *)poin;
|
|
}
|
|
else if( but->pointype == FLO ) {
|
|
value= *(float *)poin;
|
|
}
|
|
|
|
return value;
|
|
}
|
|
|
|
static void ui_set_but_val(uiBut *but, double value)
|
|
{
|
|
void *poin;
|
|
|
|
if(but->pointype==0) return;
|
|
poin= but->poin;
|
|
|
|
/* value is a hsv value: convert to rgb */
|
|
if( but->type==HSVSLI ) {
|
|
float h, s, v, *fp= (float *)but->poin;
|
|
|
|
rgb_to_hsv(fp[0], fp[1], fp[2], &h, &s, &v);
|
|
|
|
switch(but->str[0]) {
|
|
case 'H': h= value; break;
|
|
case 'S': s= value; break;
|
|
case 'V': v= value; break;
|
|
}
|
|
|
|
hsv_to_rgb(h, s, v, fp, fp+1, fp+2);
|
|
|
|
}
|
|
else if( but->pointype==CHA )
|
|
*((char *)poin)= (char)floor(value+0.5);
|
|
else if( but->pointype==SHO ) {
|
|
/* gcc 3.2.1 seems to have problems
|
|
* casting a double like 32772.0 to
|
|
* a short so we cast to an int, then
|
|
to a short */
|
|
int gcckludge;
|
|
gcckludge = (int) floor(value+0.5);
|
|
*((short *)poin)= (short) gcckludge;
|
|
}
|
|
else if( but->pointype==INT )
|
|
*((int *)poin)= (int)floor(value+0.5);
|
|
else if( but->pointype==FLO )
|
|
*((float *)poin)= value;
|
|
|
|
/* update select flag */
|
|
ui_is_but_sel(but);
|
|
|
|
}
|
|
|
|
void uiSetCurFont(uiBlock *block, int index)
|
|
{
|
|
|
|
ui_set_ftf_font(block);
|
|
|
|
if(block->aspect<0.60) {
|
|
block->curfont= UIfont[index].xl;
|
|
}
|
|
else if(block->aspect<1.15) {
|
|
block->curfont= UIfont[index].large;
|
|
}
|
|
else if(block->aspect<1.59) {
|
|
block->curfont= UIfont[index].medium;
|
|
}
|
|
else {
|
|
block->curfont= UIfont[index].small;
|
|
}
|
|
|
|
if(block->curfont==NULL) block->curfont= UIfont[index].large;
|
|
if(block->curfont==NULL) block->curfont= UIfont[index].medium;
|
|
if(block->curfont==NULL) printf("error block no font %s\n", block->name);
|
|
|
|
}
|
|
|
|
void uiDefFont(unsigned int index, void *xl, void *large, void *medium, void *small)
|
|
{
|
|
if(index>=UI_ARRAY) return;
|
|
|
|
UIfont[index].xl= xl;
|
|
UIfont[index].large= large;
|
|
UIfont[index].medium= medium;
|
|
UIfont[index].small= small;
|
|
}
|
|
|
|
static void ui_free_link(uiLink *link)
|
|
{
|
|
if(link) {
|
|
BLI_freelistN(&link->lines);
|
|
MEM_freeN(link);
|
|
}
|
|
}
|
|
|
|
static void ui_free_but(uiBut *but)
|
|
{
|
|
if(but->str && but->str != but->strdata) MEM_freeN(but->str);
|
|
ui_free_link(but->link);
|
|
|
|
MEM_freeN(but);
|
|
}
|
|
|
|
void uiFreeBlock(uiBlock *block)
|
|
{
|
|
uiBut *but;
|
|
|
|
if(block->flag & UI_BLOCK_BUSY) printf("attempt to free busy buttonblock: %p\n", block);
|
|
|
|
while( (but= block->buttons.first) ) {
|
|
BLI_remlink(&block->buttons, but);
|
|
ui_free_but(but);
|
|
}
|
|
|
|
if(block->panel) block->panel->active= 0;
|
|
|
|
|
|
MEM_freeN(block);
|
|
UIbuttip= NULL;
|
|
}
|
|
|
|
void uiFreeBlocks(ListBase *lb)
|
|
{
|
|
uiBlock *block;
|
|
|
|
while( (block= lb->first) ) {
|
|
BLI_remlink(lb, block);
|
|
uiFreeBlock(block);
|
|
}
|
|
}
|
|
|
|
void uiFreeBlocksWin(ListBase *lb, int win)
|
|
{
|
|
uiBlock *block, *blockn;
|
|
|
|
block= lb->first;
|
|
while(block) {
|
|
blockn= block->next;
|
|
if(block->win==win) {
|
|
BLI_remlink(lb, block);
|
|
uiFreeBlock(block);
|
|
}
|
|
block= blockn;
|
|
}
|
|
}
|
|
|
|
uiBlock *uiNewBlock(ListBase *lb, char *name, short dt, short font, short win)
|
|
{
|
|
uiBlock *block;
|
|
|
|
/* each listbase only has one block with this name */
|
|
if(lb) {
|
|
for (block= lb->first; block; block= block->next)
|
|
if (BLI_streq(block->name, name))
|
|
break;
|
|
if (block) {
|
|
BLI_remlink(lb, block);
|
|
uiFreeBlock(block);
|
|
}
|
|
}
|
|
|
|
block= MEM_callocN(sizeof(uiBlock), "uiBlock");
|
|
if(lb) BLI_addhead(lb, block); /* at the beginning of the list! for dynamical menus/blocks */
|
|
|
|
strcpy(block->name, name);
|
|
/* draw win */
|
|
block->win= win;
|
|
/* window where queue event should be added, pretty weak this way!
|
|
this is because the 'mainwin' pup menu's */
|
|
block->winq= mywinget();
|
|
block->dt= dt;
|
|
block->themecol= TH_AUTO;
|
|
|
|
/* aspect */
|
|
bwin_getsinglematrix(win, block->winmat);
|
|
|
|
if (win==G.curscreen->mainwin) {
|
|
block->aspect= 1.0;
|
|
block->auto_open= 2;
|
|
} else {
|
|
int getsizex, getsizey;
|
|
|
|
bwin_getsize(win, &getsizex, &getsizey);
|
|
block->aspect= 2.0/( (getsizex)*block->winmat[0][0]);
|
|
}
|
|
|
|
uiSetCurFont(block, font);
|
|
|
|
return block;
|
|
}
|
|
|
|
uiBlock *uiGetBlock(char *name, ScrArea *sa)
|
|
{
|
|
uiBlock *block= sa->uiblocks.first;
|
|
|
|
while(block) {
|
|
if( strcmp(name, block->name)==0 ) return block;
|
|
block= block->next;
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
#if 0
|
|
/* used for making screenshots for menus, called in screendump.c */
|
|
static int uiIsMenu(int *x, int *y, int *sizex, int *sizey)
|
|
{
|
|
uiBlock *block= curarea->uiblocks.first;
|
|
int minx, miny, maxx, maxy;
|
|
|
|
minx= 1<<30;
|
|
miny= 1<<30;
|
|
maxx= 0;
|
|
maxy= 0;
|
|
|
|
while(block) {
|
|
if(block->flag & UI_BLOCK_LOOP) {
|
|
if(block->minx < minx) minx= (int)block->minx;
|
|
if(block->miny < miny) miny= (int)block->miny;
|
|
if(block->maxx > maxx) maxx= (int)block->maxx;
|
|
if(block->maxy > maxy) maxy= (int)block->maxy;
|
|
}
|
|
block= block->next;
|
|
}
|
|
printf("%d %d %d %d\n", minx, miny, maxx, maxy);
|
|
if(maxx!=0 && maxy!=0) {
|
|
*x= minx-10<0?0:minx;
|
|
*y= miny-10<0?0:miny;
|
|
*sizex= maxx-minx+10;
|
|
*sizey= maxy-miny+10;
|
|
return 1;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
#endif
|
|
|
|
void ui_check_but(uiBut *but)
|
|
{
|
|
/* if something changed in the button */
|
|
ID *id;
|
|
double value;
|
|
float okwidth;
|
|
int transopts= (U.transopts & USER_TR_BUTTONS);
|
|
short pos;
|
|
|
|
ui_is_but_sel(but);
|
|
|
|
if(but->type==TEX || but->type==IDPOIN) transopts= 0;
|
|
|
|
/* test for min and max, icon sliders, etc */
|
|
switch( but->type ) {
|
|
case NUM:
|
|
case SLI:
|
|
case SCROLL:
|
|
case NUMSLI:
|
|
case HSVSLI:
|
|
value= ui_get_but_val(but);
|
|
if(value < but->min) value= but->min;
|
|
if(value > but->max) value= but->max;
|
|
ui_set_but_val(but, value);
|
|
break;
|
|
|
|
case ICONTOG:
|
|
if(but->flag & UI_SELECT) but->iconadd= 1;
|
|
else but->iconadd= 0;
|
|
break;
|
|
|
|
case ICONROW:
|
|
value= ui_get_but_val(but);
|
|
but->iconadd= (int)value- (int)(but->min);
|
|
break;
|
|
|
|
case ICONTEXTROW:
|
|
value= ui_get_but_val(but);
|
|
but->iconadd= (int)value- (int)(but->min);
|
|
break;
|
|
}
|
|
|
|
|
|
/* safety is 4 to enable small number buttons (like 'users') */
|
|
if(but->type==NUMSLI || but->type==HSVSLI)
|
|
okwidth= -4 + (but->x2 - but->x1)/2.0;
|
|
else
|
|
okwidth= -4 + (but->x2 - but->x1);
|
|
|
|
/* name: */
|
|
switch( but->type ) {
|
|
|
|
case MENU:
|
|
case ICONTEXTROW:
|
|
|
|
if(but->x2 - but->x1 > 24) {
|
|
value= ui_get_but_val(but);
|
|
ui_set_name_menu(but, (int)value);
|
|
}
|
|
break;
|
|
|
|
case NUM:
|
|
case NUMSLI:
|
|
case HSVSLI:
|
|
|
|
value= ui_get_but_val(but);
|
|
|
|
if( but->pointype==FLO ) {
|
|
if(but->a2) { /* amount of digits defined */
|
|
if(but->a2==1) sprintf(but->drawstr, "%s%.1f", but->str, value);
|
|
else if(but->a2==2) sprintf(but->drawstr, "%s%.2f", but->str, value);
|
|
else if(but->a2==3) sprintf(but->drawstr, "%s%.3f", but->str, value);
|
|
else sprintf(but->drawstr, "%s%.4f", but->str, value);
|
|
}
|
|
else {
|
|
if(but->max<10.001) sprintf(but->drawstr, "%s%.3f", but->str, value);
|
|
else sprintf(but->drawstr, "%s%.2f", but->str, value);
|
|
}
|
|
}
|
|
else {
|
|
sprintf(but->drawstr, "%s%d", but->str, (int)value);
|
|
}
|
|
break;
|
|
|
|
case LABEL:
|
|
if( but->pointype==FLO && but->poin) {
|
|
value= ui_get_but_val(but);
|
|
if(but->a2) { /* amount of digits defined */
|
|
if(but->a2==1) sprintf(but->drawstr, "%s%.1f", but->str, value);
|
|
else if(but->a2==2) sprintf(but->drawstr, "%s%.2f", but->str, value);
|
|
else if(but->a2==3) sprintf(but->drawstr, "%s%.3f", but->str, value);
|
|
else sprintf(but->drawstr, "%s%.4f", but->str, value);
|
|
}
|
|
else {
|
|
sprintf(but->drawstr, "%s%.2f", but->str, value);
|
|
}
|
|
}
|
|
else strcpy(but->drawstr, but->str);
|
|
|
|
break;
|
|
|
|
case IDPOIN:
|
|
id= *(but->idpoin_idpp);
|
|
strcpy(but->drawstr, but->str);
|
|
if(id) strcat(but->drawstr, id->name+2);
|
|
break;
|
|
|
|
case TEX:
|
|
strcpy(but->drawstr, but->str);
|
|
strcat(but->drawstr, but->poin);
|
|
break;
|
|
|
|
case KEYEVT:
|
|
strcpy(but->drawstr, but->str);
|
|
if (but->flag & UI_SELECT) {
|
|
strcat(but->drawstr, "Press a key");
|
|
} else {
|
|
strcat(but->drawstr, key_event_to_string((short) ui_get_but_val(but)));
|
|
}
|
|
break;
|
|
|
|
default:
|
|
strcpy(but->drawstr, but->str);
|
|
|
|
}
|
|
|
|
if(but->drawstr[0]) {
|
|
but->strwidth= but->aspect*BIF_GetStringWidth(but->font, but->drawstr, transopts);
|
|
// here should be check for less space for icon offsets...
|
|
if(but->type==MENU) okwidth -= 15;
|
|
}
|
|
else
|
|
but->strwidth= 0;
|
|
|
|
/* automatic width */
|
|
if(but->x2==0.0) {
|
|
but->x2= (but->x1+but->strwidth+6);
|
|
}
|
|
|
|
if(but->strwidth==0) but->drawstr[0]= 0;
|
|
else if(but->type==BUTM); // clip string
|
|
else {
|
|
|
|
/* calc but->ofs, to draw the string shorter if too long */
|
|
but->ofs= 0;
|
|
while(but->strwidth > (int)okwidth ) {
|
|
but->ofs++;
|
|
|
|
if(but->drawstr[but->ofs])
|
|
but->strwidth= but->aspect*BIF_GetStringWidth(but->font, but->drawstr+but->ofs, transopts);
|
|
else but->strwidth= 0;
|
|
|
|
/* textbut exception */
|
|
if(but->pos != -1) {
|
|
pos= but->pos+strlen(but->str);
|
|
if(pos-1 < but->ofs) {
|
|
pos= but->ofs-pos+1;
|
|
but->ofs -= pos;
|
|
if(but->ofs<0) {
|
|
but->ofs= 0;
|
|
pos--;
|
|
}
|
|
but->drawstr[ strlen(but->drawstr)-pos ]= 0;
|
|
}
|
|
}
|
|
|
|
if(but->strwidth < 10) break;
|
|
}
|
|
|
|
/* fix for buttons that better not have text cut off to the right */
|
|
if(but->ofs) {
|
|
if ELEM(but->type, NUM, TEX); // only these cut off left
|
|
else {
|
|
but->drawstr[ strlen(but->drawstr)-but->ofs ]= 0;
|
|
but->ofs= 0;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
static int ui_auto_themecol(uiBut *but)
|
|
{
|
|
|
|
switch(but->type) {
|
|
case BUT:
|
|
return TH_BUT_ACTION;
|
|
case ROW:
|
|
case TOG:
|
|
case TOG3:
|
|
case TOGR:
|
|
case TOGN:
|
|
return TH_BUT_SETTING;
|
|
case SLI:
|
|
case NUM:
|
|
case NUMSLI:
|
|
case HSVSLI:
|
|
return TH_BUT_NUM;
|
|
case TEX:
|
|
return TH_BUT_TEXTFIELD;
|
|
case PULLDOWN:
|
|
case BLOCK:
|
|
case MENU:
|
|
case BUTM:
|
|
// (weak!) detect if it is a blockloop
|
|
if(UIbuttip) return TH_MENU_ITEM;
|
|
return TH_BUT_POPUP;
|
|
default:
|
|
return TH_BUT_NEUTRAL;
|
|
}
|
|
}
|
|
|
|
void uiBlockBeginAlign(uiBlock *block)
|
|
{
|
|
/* if other align was active, end it */
|
|
if(block->flag & UI_BUT_ALIGN) uiBlockEndAlign(block);
|
|
|
|
block->flag |= UI_BUT_ALIGN_DOWN;
|
|
/* buttons declared after this call will this align flag */
|
|
}
|
|
|
|
static int buts_are_horiz(uiBut *but1, uiBut *but2)
|
|
{
|
|
float dx, dy;
|
|
|
|
dx= fabs( but1->x2 - but2->x1);
|
|
dy= fabs( but1->y1 - but2->y2);
|
|
|
|
if(dx > dy) return 0;
|
|
return 1;
|
|
}
|
|
|
|
void uiBlockEndAlign(uiBlock *block)
|
|
{
|
|
uiBut *prev, *but=NULL, *next;
|
|
int flag= 0, cols=0, rows=0;
|
|
|
|
if ( !((BIF_GetThemeValue(TH_BUT_DRAWTYPE) == 1) || (BIF_GetThemeValue(TH_BUT_DRAWTYPE) == 2))) return;
|
|
|
|
/* auto align:
|
|
- go back to first button of align start (ALIGN_DOWN)
|
|
- compare triples, and define flags
|
|
*/
|
|
prev= block->buttons.last;
|
|
while(prev) {
|
|
if( (prev->flag & UI_BUT_ALIGN_DOWN)) but= prev;
|
|
else break;
|
|
|
|
if(but && but->next) {
|
|
if(buts_are_horiz(but, but->next)) cols++;
|
|
else rows++;
|
|
}
|
|
|
|
prev= prev->prev;
|
|
}
|
|
if(but==NULL) return;
|
|
|
|
/* rows==0: 1 row, cols==0: 1 collumn */
|
|
|
|
prev= NULL;
|
|
while(but) {
|
|
next= but->next;
|
|
|
|
/* clear old flag */
|
|
but->flag &= ~UI_BUT_ALIGN_DOWN;
|
|
|
|
if(flag==0) { /* first case */
|
|
if(next) {
|
|
if(buts_are_horiz(but, next)) {
|
|
if(rows==0)
|
|
flag= UI_BUT_ALIGN_RIGHT;
|
|
else
|
|
flag= UI_BUT_ALIGN_DOWN|UI_BUT_ALIGN_RIGHT;
|
|
}
|
|
else {
|
|
flag= UI_BUT_ALIGN_DOWN;
|
|
}
|
|
}
|
|
}
|
|
else if(next==NULL) { /* last case */
|
|
if(prev) {
|
|
if(buts_are_horiz(prev, but)) {
|
|
if(rows==0)
|
|
flag= UI_BUT_ALIGN_LEFT;
|
|
else
|
|
flag= UI_BUT_ALIGN_TOP|UI_BUT_ALIGN_LEFT;
|
|
}
|
|
else flag= UI_BUT_ALIGN_TOP;
|
|
}
|
|
}
|
|
else if(buts_are_horiz(but, next)) {
|
|
/* check if this is already second row */
|
|
if( prev && buts_are_horiz(prev, but)==0) {
|
|
flag |= UI_BUT_ALIGN_TOP;
|
|
/* exception case: bottom row */
|
|
if(rows>0) {
|
|
uiBut *bt= but;
|
|
while(bt) {
|
|
if(bt->next && buts_are_horiz(bt, bt->next)==0 ) break;
|
|
bt= bt->next;
|
|
}
|
|
if(bt==0) flag= UI_BUT_ALIGN_TOP|UI_BUT_ALIGN_RIGHT;
|
|
}
|
|
}
|
|
else flag |= UI_BUT_ALIGN_LEFT;
|
|
}
|
|
else {
|
|
if(cols==0) {
|
|
flag |= UI_BUT_ALIGN_TOP;
|
|
}
|
|
else { /* next button switches to new row */
|
|
if( (flag & UI_BUT_ALIGN_TOP)==0) { /* stil top row */
|
|
flag= UI_BUT_ALIGN_DOWN|UI_BUT_ALIGN_LEFT;
|
|
}
|
|
else flag |= UI_BUT_ALIGN_TOP;
|
|
}
|
|
}
|
|
|
|
but->flag |= flag;
|
|
|
|
/* merge coordinates */
|
|
if(prev) {
|
|
// simple cases
|
|
if(rows==0) {
|
|
but->x1= (prev->x2+but->x1)/2.0;
|
|
prev->x2= but->x1;
|
|
}
|
|
else if(cols==0) {
|
|
but->y2= (prev->y1+but->y2)/2.0;
|
|
prev->y1= but->y2;
|
|
}
|
|
else {
|
|
if(buts_are_horiz(prev, but)) {
|
|
but->x1= (prev->x2+but->x1)/2.0;
|
|
prev->x2= but->x1;
|
|
/* copy height too */
|
|
but->y2= prev->y2;
|
|
}
|
|
else if(prev->prev && buts_are_horiz(prev->prev, prev)==0) {
|
|
/* the previous button is a single one in its row */
|
|
but->y2= (prev->y1+but->y2)/2.0;
|
|
prev->y1= but->y2;
|
|
}
|
|
else {
|
|
/* the previous button is not a single one in its row */
|
|
but->y2= prev->y1;
|
|
}
|
|
}
|
|
}
|
|
|
|
prev= but;
|
|
but= next;
|
|
}
|
|
|
|
block->flag &= ~UI_BUT_ALIGN; // all 4 flags
|
|
}
|
|
|
|
#if 0
|
|
static void uiBlockEndAligno(uiBlock *block)
|
|
{
|
|
uiBut *but;
|
|
|
|
/* correct last defined button */
|
|
but= block->buttons.last;
|
|
if(but) {
|
|
/* vertical align case */
|
|
if( (block->flag & UI_BUT_ALIGN) == (UI_BUT_ALIGN_TOP|UI_BUT_ALIGN_DOWN) ) {
|
|
but->flag &= ~UI_BUT_ALIGN_DOWN;
|
|
}
|
|
/* horizontal align case */
|
|
if( (block->flag & UI_BUT_ALIGN) == (UI_BUT_ALIGN_LEFT|UI_BUT_ALIGN_RIGHT) ) {
|
|
but->flag &= ~UI_BUT_ALIGN_RIGHT;
|
|
}
|
|
/* else do nothing, manually provided flags */
|
|
}
|
|
block->flag &= ~UI_BUT_ALIGN; // all 4 flags
|
|
}
|
|
#endif
|
|
|
|
static uiBut *ui_def_but(uiBlock *block, int type, int retval, char *str, short x1, short y1, short x2, short y2, void *poin, float min, float max, float a1, float a2, char *tip)
|
|
{
|
|
uiBut *but;
|
|
short slen;
|
|
|
|
if(type & BUTPOIN) { /* a pointer is required */
|
|
if(poin==0) {
|
|
/* if pointer is zero, button is removed and not drawn */
|
|
BIF_ThemeColor(block->themecol);
|
|
glRects(x1, y1, x1+x2, y1+y2);
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
but= MEM_callocN(sizeof(uiBut), "uiBut");
|
|
|
|
but->type= type & BUTTYPE;
|
|
but->pointype= type & BUTPOIN;
|
|
but->bit= type & BIT;
|
|
but->bitnr= type & 31;
|
|
|
|
BLI_addtail(&block->buttons, but);
|
|
|
|
but->retval= retval;
|
|
if( strlen(str)>=UI_MAX_NAME_STR-1 ) {
|
|
but->str= MEM_callocN( strlen(str)+2, "uiDefBut");
|
|
strcpy(but->str, str);
|
|
}
|
|
else {
|
|
but->str= but->strdata;
|
|
strcpy(but->str, str);
|
|
}
|
|
but->x1= x1;
|
|
but->y1= y1;
|
|
if(block->autofill) {
|
|
but->x2= x2;
|
|
but->y2= y2;
|
|
}
|
|
else {
|
|
but->x2= (x1+x2);
|
|
but->y2= (y1+y2);
|
|
}
|
|
but->poin= poin;
|
|
but->min= min;
|
|
but->max= max;
|
|
but->a1= a1;
|
|
but->a2= a2;
|
|
but->tip= tip;
|
|
|
|
but->font= block->curfont;
|
|
|
|
but->lock= UIlock;
|
|
but->lockstr= UIlockstr;
|
|
|
|
but->aspect= block->aspect;
|
|
but->win= block->win;
|
|
but->block= block; // pointer back, used for frontbuffer status, and picker
|
|
|
|
if(block->themecol==TH_AUTO) but->themecol= ui_auto_themecol(but);
|
|
else but->themecol= block->themecol;
|
|
|
|
if (but->type==BUTM) {
|
|
but->butm_func= block->butm_func;
|
|
but->butm_func_arg= block->butm_func_arg;
|
|
} else {
|
|
but->func= block->func;
|
|
but->func_arg1= block->func_arg1;
|
|
but->func_arg2= block->func_arg2;
|
|
}
|
|
|
|
ui_set_embossfunc(but, block->dt);
|
|
|
|
but->pos= -1; /* cursor invisible */
|
|
|
|
if(but->type==NUM) { /* add a space to name */
|
|
slen= strlen(but->str);
|
|
if(slen>0 && slen<UI_MAX_NAME_STR-2) {
|
|
if(but->str[slen-1]!=' ') {
|
|
but->str[slen]= ' ';
|
|
but->str[slen+1]= 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
if(but->type==HSVCUBE) { /* hsv buttons temp storage */
|
|
float rgb[3];
|
|
ui_get_but_vectorf(but, rgb);
|
|
rgb_to_hsv(rgb[0], rgb[1], rgb[2], but->hsv, but->hsv+1, but->hsv+2);
|
|
}
|
|
|
|
if ELEM8(but->type, HSVSLI , NUMSLI, MENU, TEX, LABEL, IDPOIN, BLOCK, BUTM) {
|
|
but->flag |= UI_TEXT_LEFT;
|
|
}
|
|
|
|
but->flag |= (block->flag & UI_BUT_ALIGN);
|
|
|
|
return but;
|
|
}
|
|
|
|
uiBut *uiDefBut(uiBlock *block, int type, int retval, char *str, short x1, short y1, short x2, short y2, void *poin, float min, float max, float a1, float a2, char *tip)
|
|
{
|
|
uiBut *but= ui_def_but(block, type, retval, str, x1, y1, x2, y2, poin, min, max, a1, a2, tip);
|
|
|
|
ui_check_but(but);
|
|
|
|
return but;
|
|
}
|
|
|
|
/* if _x_ is a power of two (only one bit) return the power,
|
|
* otherwise return -1.
|
|
* (1<<findBitIndex(x))==x for powers of two.
|
|
*/
|
|
static int findBitIndex(unsigned int x) {
|
|
if (!x || (x&(x-1))!=0) { /* x&(x-1) strips lowest bit */
|
|
return -1;
|
|
} else {
|
|
int idx= 0;
|
|
|
|
if (x&0xFFFF0000) idx+=16, x>>=16;
|
|
if (x&0xFF00) idx+=8, x>>=8;
|
|
if (x&0xF0) idx+=4, x>>=4;
|
|
if (x&0xC) idx+=2, x>>=2;
|
|
if (x&0x2) idx+=1;
|
|
|
|
return idx;
|
|
}
|
|
}
|
|
static uiBut *uiDefButBit(uiBlock *block, int type, int bit, int retval, char *str, short x1, short y1, short x2, short y2, void *poin, float min, float max, float a1, float a2, char *tip)
|
|
{
|
|
int bitIdx= findBitIndex(bit);
|
|
if (bitIdx==-1) {
|
|
return NULL;
|
|
} else {
|
|
return uiDefBut(block, type|BIT|bitIdx, retval, str, x1, y1, x2, y2, poin, min, max, a1, a2, tip);
|
|
}
|
|
}
|
|
uiBut *uiDefButF(uiBlock *block, int type, int retval, char *str, short x1, short y1, short x2, short y2, float *poin, float min, float max, float a1, float a2, char *tip)
|
|
{
|
|
return uiDefBut(block, type|FLO, retval, str, x1, y1, x2, y2, (void*) poin, min, max, a1, a2, tip);
|
|
}
|
|
uiBut *uiDefButBitF(uiBlock *block, int type, int bit, int retval, char *str, short x1, short y1, short x2, short y2, float *poin, float min, float max, float a1, float a2, char *tip)
|
|
{
|
|
return uiDefButBit(block, type|FLO, bit, retval, str, x1, y1, x2, y2, (void*) poin, min, max, a1, a2, tip);
|
|
}
|
|
uiBut *uiDefButI(uiBlock *block, int type, int retval, char *str, short x1, short y1, short x2, short y2, int *poin, float min, float max, float a1, float a2, char *tip)
|
|
{
|
|
return uiDefBut(block, type|INT, retval, str, x1, y1, x2, y2, (void*) poin, min, max, a1, a2, tip);
|
|
}
|
|
uiBut *uiDefButBitI(uiBlock *block, int type, int bit, int retval, char *str, short x1, short y1, short x2, short y2, int *poin, float min, float max, float a1, float a2, char *tip)
|
|
{
|
|
return uiDefButBit(block, type|INT, bit, retval, str, x1, y1, x2, y2, (void*) poin, min, max, a1, a2, tip);
|
|
}
|
|
uiBut *uiDefButS(uiBlock *block, int type, int retval, char *str, short x1, short y1, short x2, short y2, short *poin, float min, float max, float a1, float a2, char *tip)
|
|
{
|
|
return uiDefBut(block, type|SHO, retval, str, x1, y1, x2, y2, (void*) poin, min, max, a1, a2, tip);
|
|
}
|
|
uiBut *uiDefButBitS(uiBlock *block, int type, int bit, int retval, char *str, short x1, short y1, short x2, short y2, short *poin, float min, float max, float a1, float a2, char *tip)
|
|
{
|
|
return uiDefButBit(block, type|SHO, bit, retval, str, x1, y1, x2, y2, (void*) poin, min, max, a1, a2, tip);
|
|
}
|
|
uiBut *uiDefButC(uiBlock *block, int type, int retval, char *str, short x1, short y1, short x2, short y2, char *poin, float min, float max, float a1, float a2, char *tip)
|
|
{
|
|
return uiDefBut(block, type|CHA, retval, str, x1, y1, x2, y2, (void*) poin, min, max, a1, a2, tip);
|
|
}
|
|
uiBut *uiDefButBitC(uiBlock *block, int type, int bit, int retval, char *str, short x1, short y1, short x2, short y2, char *poin, float min, float max, float a1, float a2, char *tip)
|
|
{
|
|
return uiDefButBit(block, type|CHA, bit, retval, str, x1, y1, x2, y2, (void*) poin, min, max, a1, a2, tip);
|
|
}
|
|
|
|
uiBut *uiDefIconBut(uiBlock *block, int type, int retval, int icon, short x1, short y1, short x2, short y2, void *poin, float min, float max, float a1, float a2, char *tip)
|
|
{
|
|
uiBut *but= ui_def_but(block, type, retval, "", x1, y1, x2, y2, poin, min, max, a1, a2, tip);
|
|
|
|
but->icon= (BIFIconID) icon;
|
|
but->flag|= UI_HAS_ICON;
|
|
|
|
ui_check_but(but);
|
|
|
|
return but;
|
|
}
|
|
static uiBut *uiDefIconButBit(uiBlock *block, int type, int bit, int retval, int icon, short x1, short y1, short x2, short y2, void *poin, float min, float max, float a1, float a2, char *tip)
|
|
{
|
|
int bitIdx= findBitIndex(bit);
|
|
if (bitIdx==-1) {
|
|
return NULL;
|
|
} else {
|
|
return uiDefIconBut(block, type|BIT|bitIdx, retval, icon, x1, y1, x2, y2, poin, min, max, a1, a2, tip);
|
|
}
|
|
}
|
|
|
|
uiBut *uiDefIconButF(uiBlock *block, int type, int retval, int icon, short x1, short y1, short x2, short y2, float *poin, float min, float max, float a1, float a2, char *tip)
|
|
{
|
|
return uiDefIconBut(block, type|FLO, retval, icon, x1, y1, x2, y2, (void*) poin, min, max, a1, a2, tip);
|
|
}
|
|
uiBut *uiDefIconButBitF(uiBlock *block, int type, int bit, int retval, int icon, short x1, short y1, short x2, short y2, float *poin, float min, float max, float a1, float a2, char *tip)
|
|
{
|
|
return uiDefIconButBit(block, type|FLO, bit, retval, icon, x1, y1, x2, y2, (void*) poin, min, max, a1, a2, tip);
|
|
}
|
|
uiBut *uiDefIconButI(uiBlock *block, int type, int retval, int icon, short x1, short y1, short x2, short y2, int *poin, float min, float max, float a1, float a2, char *tip)
|
|
{
|
|
return uiDefIconBut(block, type|INT, retval, icon, x1, y1, x2, y2, (void*) poin, min, max, a1, a2, tip);
|
|
}
|
|
uiBut *uiDefIconButBitI(uiBlock *block, int type, int bit, int retval, int icon, short x1, short y1, short x2, short y2, int *poin, float min, float max, float a1, float a2, char *tip)
|
|
{
|
|
return uiDefIconButBit(block, type|INT, bit, retval, icon, x1, y1, x2, y2, (void*) poin, min, max, a1, a2, tip);
|
|
}
|
|
uiBut *uiDefIconButS(uiBlock *block, int type, int retval, int icon, short x1, short y1, short x2, short y2, short *poin, float min, float max, float a1, float a2, char *tip)
|
|
{
|
|
return uiDefIconBut(block, type|SHO, retval, icon, x1, y1, x2, y2, (void*) poin, min, max, a1, a2, tip);
|
|
}
|
|
uiBut *uiDefIconButBitS(uiBlock *block, int type, int bit, int retval, int icon, short x1, short y1, short x2, short y2, short *poin, float min, float max, float a1, float a2, char *tip)
|
|
{
|
|
return uiDefIconButBit(block, type|SHO, bit, retval, icon, x1, y1, x2, y2, (void*) poin, min, max, a1, a2, tip);
|
|
}
|
|
uiBut *uiDefIconButC(uiBlock *block, int type, int retval, int icon, short x1, short y1, short x2, short y2, char *poin, float min, float max, float a1, float a2, char *tip)
|
|
{
|
|
return uiDefIconBut(block, type|CHA, retval, icon, x1, y1, x2, y2, (void*) poin, min, max, a1, a2, tip);
|
|
}
|
|
uiBut *uiDefIconButBitC(uiBlock *block, int type, int bit, int retval, int icon, short x1, short y1, short x2, short y2, char *poin, float min, float max, float a1, float a2, char *tip)
|
|
{
|
|
return uiDefIconButBit(block, type|CHA, bit, retval, icon, x1, y1, x2, y2, (void*) poin, min, max, a1, a2, tip);
|
|
}
|
|
|
|
/* Button containing both string label and icon */
|
|
uiBut *uiDefIconTextBut(uiBlock *block, int type, int retval, int icon, char *str, short x1, short y1, short x2, short y2, void *poin, float min, float max, float a1, float a2, char *tip)
|
|
{
|
|
uiBut *but= ui_def_but(block, type, retval, str, x1, y1, x2, y2, poin, min, max, a1, a2, tip);
|
|
|
|
but->icon= (BIFIconID) icon;
|
|
but->flag|= UI_HAS_ICON;
|
|
|
|
but->flag|= UI_ICON_LEFT;
|
|
|
|
ui_check_but(but);
|
|
|
|
return but;
|
|
}
|
|
static uiBut *uiDefIconTextButBit(uiBlock *block, int type, int bit, int retval, int icon, char *str, short x1, short y1, short x2, short y2, void *poin, float min, float max, float a1, float a2, char *tip)
|
|
{
|
|
int bitIdx= findBitIndex(bit);
|
|
if (bitIdx==-1) {
|
|
return NULL;
|
|
} else {
|
|
return uiDefIconTextBut(block, type|BIT|bitIdx, retval, icon, str, x1, y1, x2, y2, poin, min, max, a1, a2, tip);
|
|
}
|
|
}
|
|
|
|
uiBut *uiDefIconTextButF(uiBlock *block, int type, int retval, int icon, char *str, short x1, short y1, short x2, short y2, float *poin, float min, float max, float a1, float a2, char *tip)
|
|
{
|
|
return uiDefIconTextBut(block, type|FLO, retval, icon, str, x1, y1, x2, y2, (void*) poin, min, max, a1, a2, tip);
|
|
}
|
|
uiBut *uiDefIconTextButBitF(uiBlock *block, int type, int bit, int retval, int icon, char *str, short x1, short y1, short x2, short y2, float *poin, float min, float max, float a1, float a2, char *tip)
|
|
{
|
|
return uiDefIconTextButBit(block, type|FLO, bit, retval, icon, str, x1, y1, x2, y2, (void*) poin, min, max, a1, a2, tip);
|
|
}
|
|
uiBut *uiDefIconTextButI(uiBlock *block, int type, int retval, int icon, char *str, short x1, short y1, short x2, short y2, int *poin, float min, float max, float a1, float a2, char *tip)
|
|
{
|
|
return uiDefIconTextBut(block, type|INT, retval, icon, str, x1, y1, x2, y2, (void*) poin, min, max, a1, a2, tip);
|
|
}
|
|
uiBut *uiDefIconTextButBitI(uiBlock *block, int type, int bit, int retval, int icon, char *str, short x1, short y1, short x2, short y2, int *poin, float min, float max, float a1, float a2, char *tip)
|
|
{
|
|
return uiDefIconTextButBit(block, type|INT, bit, retval, icon, str, x1, y1, x2, y2, (void*) poin, min, max, a1, a2, tip);
|
|
}
|
|
uiBut *uiDefIconTextButS(uiBlock *block, int type, int retval, int icon, char *str, short x1, short y1, short x2, short y2, short *poin, float min, float max, float a1, float a2, char *tip)
|
|
{
|
|
return uiDefIconTextBut(block, type|SHO, retval, icon, str, x1, y1, x2, y2, (void*) poin, min, max, a1, a2, tip);
|
|
}
|
|
uiBut *uiDefIconTextButBitS(uiBlock *block, int type, int bit, int retval, int icon, char *str, short x1, short y1, short x2, short y2, short *poin, float min, float max, float a1, float a2, char *tip)
|
|
{
|
|
return uiDefIconTextButBit(block, type|SHO, bit, retval, icon, str, x1, y1, x2, y2, (void*) poin, min, max, a1, a2, tip);
|
|
}
|
|
uiBut *uiDefIconTextButC(uiBlock *block, int type, int retval, int icon, char *str, short x1, short y1, short x2, short y2, char *poin, float min, float max, float a1, float a2, char *tip)
|
|
{
|
|
return uiDefIconTextBut(block, type|CHA, retval, icon, str, x1, y1, x2, y2, (void*) poin, min, max, a1, a2, tip);
|
|
}
|
|
uiBut *uiDefIconTextButBitC(uiBlock *block, int type, int bit, int retval, int icon, char *str, short x1, short y1, short x2, short y2, char *poin, float min, float max, float a1, float a2, char *tip)
|
|
{
|
|
return uiDefIconTextButBit(block, type|CHA, bit, retval, icon, str, x1, y1, x2, y2, (void*) poin, min, max, a1, a2, tip);
|
|
}
|
|
|
|
/* END Button containing both string label and icon */
|
|
|
|
void uiAutoBlock(uiBlock *block, float minx, float miny, float sizex, float sizey, int flag)
|
|
{
|
|
block->minx= minx;
|
|
block->maxx= minx+sizex;
|
|
block->miny= miny;
|
|
block->maxy= miny+sizey;
|
|
|
|
block->autofill= flag; /* also check for if it has to be done */
|
|
|
|
}
|
|
|
|
void uiSetButLink(uiBut *but, void **poin, void ***ppoin, short *tot, int from, int to)
|
|
{
|
|
uiLink *link;
|
|
|
|
link= but->link= MEM_callocN(sizeof(uiLink), "new uilink");
|
|
|
|
link->poin= poin;
|
|
link->ppoin= ppoin;
|
|
link->totlink= tot;
|
|
link->fromcode= from;
|
|
link->tocode= to;
|
|
}
|
|
|
|
/* cruft to make uiBlock and uiBut private */
|
|
|
|
int uiBlocksGetYMin(ListBase *lb)
|
|
{
|
|
uiBlock *block;
|
|
int min= 0;
|
|
|
|
for (block= lb->first; block; block= block->next)
|
|
if (block==lb->first || block->miny<min)
|
|
min= block->miny;
|
|
|
|
return min;
|
|
}
|
|
|
|
int uiBlockGetCol(uiBlock *block)
|
|
{
|
|
return block->themecol;
|
|
}
|
|
void uiBlockSetCol(uiBlock *block, int col)
|
|
{
|
|
block->themecol= col;
|
|
}
|
|
void uiBlockSetEmboss(uiBlock *block, int emboss)
|
|
{
|
|
block->dt= emboss;
|
|
}
|
|
void uiBlockSetDirection(uiBlock *block, int direction)
|
|
{
|
|
block->direction= direction;
|
|
}
|
|
|
|
/* this call escapes if there's alignment flags */
|
|
void uiBlockFlipOrder(uiBlock *block)
|
|
{
|
|
ListBase lb;
|
|
uiBut *but, *next;
|
|
float centy, miny=10000, maxy= -10000;
|
|
|
|
for(but= block->buttons.first; but; but= but->next) {
|
|
if(but->flag & UI_BUT_ALIGN) return;
|
|
if(but->y1 < miny) miny= but->y1;
|
|
if(but->y2 > maxy) maxy= but->y2;
|
|
}
|
|
/* mirror trick */
|
|
centy= (miny+maxy)/2.0;
|
|
for(but= block->buttons.first; but; but= but->next) {
|
|
but->y1 = centy-(but->y1-centy);
|
|
but->y2 = centy-(but->y2-centy);
|
|
SWAP(float, but->y1, but->y2);
|
|
}
|
|
|
|
/* also flip order in block itself, for example for arrowkey */
|
|
lb.first= lb.last= NULL;
|
|
but= block->buttons.first;
|
|
while(but) {
|
|
next= but->next;
|
|
BLI_remlink(&block->buttons, but);
|
|
BLI_addtail(&lb, but);
|
|
but= next;
|
|
}
|
|
block->buttons= lb;
|
|
}
|
|
|
|
|
|
void uiBlockSetFlag(uiBlock *block, int flag)
|
|
{
|
|
block->flag= flag;
|
|
}
|
|
void uiBlockSetXOfs(uiBlock *block, int xofs)
|
|
{
|
|
block->xofs= xofs;
|
|
}
|
|
void* uiBlockGetCurFont(uiBlock *block)
|
|
{
|
|
return block->curfont;
|
|
}
|
|
|
|
void uiButSetFlag(uiBut *but, int flag)
|
|
{
|
|
but->flag|= flag;
|
|
}
|
|
void uiButClearFlag(uiBut *but, int flag)
|
|
{
|
|
but->flag&= ~flag;
|
|
}
|
|
|
|
int uiButGetRetVal(uiBut *but)
|
|
{
|
|
return but->retval;
|
|
}
|
|
|
|
|
|
void uiBlockSetButmFunc(uiBlock *block, void (*menufunc)(void *arg, int event), void *arg)
|
|
{
|
|
block->butm_func= menufunc;
|
|
block->butm_func_arg= arg;
|
|
}
|
|
|
|
void uiBlockSetFunc(uiBlock *block, void (*func)(void *arg1, void *arg2), void *arg1, void *arg2)
|
|
{
|
|
block->func= func;
|
|
block->func_arg1= arg1;
|
|
block->func_arg2= arg2;
|
|
}
|
|
|
|
void uiBlockSetDrawExtraFunc(uiBlock *block, void (*func)())
|
|
{
|
|
block->drawextra= func;
|
|
}
|
|
|
|
void uiButSetFunc(uiBut *but, void (*func)(void *arg1, void *arg2), void *arg1, void *arg2)
|
|
{
|
|
but->func= func;
|
|
but->func_arg1= arg1;
|
|
but->func_arg2= arg2;
|
|
}
|
|
|
|
void uiDefIDPoinBut(uiBlock *block, uiIDPoinFuncFP func, int retval, char *str, short x1, short y1, short x2, short y2, void *idpp, char *tip)
|
|
{
|
|
uiBut *but= ui_def_but(block, IDPOIN, retval, str, x1, y1, x2, y2, NULL, 0.0, 0.0, 0.0, 0.0, tip);
|
|
but->idpoin_func= func;
|
|
but->idpoin_idpp= (ID**) idpp;
|
|
ui_check_but(but);
|
|
}
|
|
|
|
uiBut *uiDefBlockBut(uiBlock *block, uiBlockFuncFP func, void *arg, char *str, short x1, short y1, short x2, short y2, char *tip)
|
|
{
|
|
uiBut *but= ui_def_but(block, BLOCK, 0, str, x1, y1, x2, y2, arg, 0.0, 0.0, 0.0, 0.0, tip);
|
|
but->block_func= func;
|
|
ui_check_but(but);
|
|
return but;
|
|
}
|
|
|
|
uiBut *uiDefPulldownBut(uiBlock *block, uiBlockFuncFP func, void *arg, char *str, short x1, short y1, short x2, short y2, char *tip)
|
|
{
|
|
uiBut *but= ui_def_but(block, PULLDOWN, 0, str, x1, y1, x2, y2, arg, 0.0, 0.0, 0.0, 0.0, tip);
|
|
but->block_func= func;
|
|
ui_check_but(but);
|
|
return but;
|
|
}
|
|
|
|
/* Block button containing both string label and icon */
|
|
uiBut *uiDefIconTextBlockBut(uiBlock *block, uiBlockFuncFP func, void *arg, int icon, char *str, short x1, short y1, short x2, short y2, char *tip)
|
|
{
|
|
uiBut *but= ui_def_but(block, BLOCK, 0, str, x1, y1, x2, y2, arg, 0.0, 0.0, 0.0, 0.0, tip);
|
|
|
|
but->icon= (BIFIconID) icon;
|
|
but->flag|= UI_HAS_ICON;
|
|
|
|
but->flag|= UI_ICON_LEFT;
|
|
but->flag|= UI_ICON_RIGHT;
|
|
|
|
but->block_func= func;
|
|
ui_check_but(but);
|
|
|
|
return but;
|
|
}
|
|
|
|
void uiDefKeyevtButS(uiBlock *block, int retval, char *str, short x1, short y1, short x2, short y2, short *spoin, char *tip)
|
|
{
|
|
uiBut *but= ui_def_but(block, KEYEVT|SHO, retval, str, x1, y1, x2, y2, spoin, 0.0, 0.0, 0.0, 0.0, tip);
|
|
ui_check_but(but);
|
|
}
|
|
|
|
/* ******************** PUPmenu ****************** */
|
|
|
|
static int pupmenu_set= 0;
|
|
|
|
void pupmenu_set_active(int val)
|
|
{
|
|
pupmenu_set= val;
|
|
}
|
|
|
|
/* value== -1 read, otherwise set */
|
|
static int pupmenu_memory(char *str, int value)
|
|
{
|
|
static char mem[256], first=1;
|
|
int val=0, nr=0;
|
|
|
|
if(first) {
|
|
memset(mem, 0, 256);
|
|
first= 0;
|
|
}
|
|
while(str[nr]) {
|
|
val+= str[nr];
|
|
nr++;
|
|
}
|
|
|
|
if(value >= 0) mem[ val & 255 ]= value;
|
|
else return mem[ val & 255 ];
|
|
|
|
return 0;
|
|
}
|
|
|
|
#define PUP_LABELH 6
|
|
short pupmenu(char *instr)
|
|
{
|
|
uiBlock *block;
|
|
ListBase listb= {NULL, NULL};
|
|
int event;
|
|
short lastselected, width, height=0, mousexmove = 0, mouseymove, xmax, ymax, mval[2], val= -1;
|
|
short a, startx, starty, endx, endy, boxh=TBOXH, x1, y1;
|
|
MenuData *md;
|
|
|
|
/* block stuff first, need to know the font */
|
|
block= uiNewBlock(&listb, "menu", UI_EMBOSSP, UI_HELV, G.curscreen->mainwin);
|
|
uiBlockSetFlag(block, UI_BLOCK_LOOP|UI_BLOCK_REDRAW|UI_BLOCK_RET_1|UI_BLOCK_NUMSELECT);
|
|
block->themecol= TH_MENU_ITEM;
|
|
|
|
md= decompose_menu_string(instr);
|
|
|
|
/* size and location, title slightly bigger for bold */
|
|
if(md->title) width= 2*strlen(md->title)+BIF_GetStringWidth(uiBlockGetCurFont(block), md->title, (U.transopts && USER_TR_BUTTONS));
|
|
else width= 0;
|
|
for(a=0; a<md->nitems; a++) {
|
|
char *name= md->items[a].str;
|
|
|
|
xmax= BIF_GetStringWidth(uiBlockGetCurFont(block), md->items[a].str, (U.transopts && USER_TR_BUTTONS));
|
|
if(xmax>width) width= xmax;
|
|
|
|
if( strcmp(name, "%l")==0) height+= PUP_LABELH;
|
|
else height+= boxh;
|
|
}
|
|
|
|
width+= 10;
|
|
|
|
xmax = G.curscreen->sizex;
|
|
ymax = G.curscreen->sizey;
|
|
|
|
getmouseco_sc(mval);
|
|
|
|
/* set first item */
|
|
lastselected= 0;
|
|
if(pupmenu_set) {
|
|
lastselected= pupmenu_set-1;
|
|
pupmenu_set= 0;
|
|
}
|
|
else if(md->nitems>1) {
|
|
lastselected= pupmenu_memory(instr, -1);
|
|
}
|
|
|
|
startx= mval[0]-(0.8*(width));
|
|
starty= mval[1]-height+boxh/2;
|
|
if(lastselected>=0 && lastselected<md->nitems) {
|
|
for(a=0; a<md->nitems; a++) {
|
|
if(a==lastselected) break;
|
|
if( strcmp(md->items[a].str, "%l")==0) starty+= PUP_LABELH;
|
|
else starty+=boxh;
|
|
}
|
|
|
|
//starty= mval[1]-height+boxh/2+lastselected*boxh;
|
|
}
|
|
|
|
mouseymove= 0;
|
|
|
|
if(startx<10) startx= 10;
|
|
if(starty<10) {
|
|
mouseymove= 10-starty;
|
|
starty= 10;
|
|
}
|
|
|
|
endx= startx+width;
|
|
endy= starty+height;
|
|
if(endx>xmax) {
|
|
endx= xmax-10;
|
|
startx= endx-width;
|
|
}
|
|
if(endy>ymax-20) {
|
|
mouseymove= ymax-endy-20;
|
|
endy= ymax-20;
|
|
starty= endy-height;
|
|
|
|
}
|
|
|
|
if(mouseymove) {
|
|
ui_warp_pointer(mval[0], mouseymove+mval[1]);
|
|
mousexmove= mval[0];
|
|
mouseymove= mval[1];
|
|
}
|
|
|
|
/* here we go! */
|
|
if(md->title) {
|
|
uiBut *bt;
|
|
uiSetCurFont(block, UI_HELVB);
|
|
bt= uiDefBut(block, LABEL, 0, md->title, startx, (short)(starty+height), width, boxh, NULL, 0.0, 0.0, 0, 0, "");
|
|
bt->flag= UI_TEXT_LEFT;
|
|
uiSetCurFont(block, UI_HELV);
|
|
}
|
|
|
|
y1= starty + height - boxh;
|
|
x1= startx;
|
|
|
|
for(a=0; a<md->nitems; a++) {
|
|
char *name= md->items[a].str;
|
|
|
|
if( strcmp(name, "%l")==0) {
|
|
uiDefBut(block, SEPR, B_NOP, "", x1, y1, width, PUP_LABELH, NULL, 0, 0.0, 0, 0, "");
|
|
y1 -= PUP_LABELH;
|
|
}
|
|
else {
|
|
uiDefButS(block, BUTM, B_NOP, name, x1, y1, width, boxh-1, &val, (float) md->items[a].retval, 0.0, 0, 0, "");
|
|
y1 -= boxh;
|
|
}
|
|
}
|
|
|
|
uiBoundsBlock(block, 2);
|
|
|
|
event= uiDoBlocks(&listb, 0);
|
|
|
|
/* calculate last selected */
|
|
if(event & UI_RETURN_OK) {
|
|
lastselected= 0;
|
|
for(a=0; a<md->nitems; a++) {
|
|
if(val==md->items[a].retval) lastselected= a;
|
|
}
|
|
|
|
pupmenu_memory(instr, lastselected);
|
|
}
|
|
menudata_free(md);
|
|
|
|
if(mouseymove && (event & UI_RETURN_OUT)==0) ui_warp_pointer(mousexmove, mouseymove);
|
|
return val;
|
|
}
|
|
|
|
short pupmenu_col(char *instr, int maxrow)
|
|
{
|
|
uiBlock *block;
|
|
ListBase listb= {NULL, NULL};
|
|
int columns, rows;
|
|
short mousemove[2], mval[2], event;
|
|
int width, height, xmax, ymax, val= -1;
|
|
int a, startx, starty, endx, endy, boxh=TBOXH, x1, y1;
|
|
MenuData *md;
|
|
|
|
block= uiNewBlock(&listb, "menu", UI_EMBOSSP, UI_HELV, G.curscreen->mainwin);
|
|
uiBlockSetFlag(block, UI_BLOCK_LOOP|UI_BLOCK_REDRAW|UI_BLOCK_RET_1|UI_BLOCK_NUMSELECT);
|
|
block->themecol= TH_MENU_ITEM;
|
|
|
|
md= decompose_menu_string(instr);
|
|
|
|
/* collumns and row calculation */
|
|
columns= (md->nitems+maxrow)/maxrow;
|
|
if (columns<1) columns= 1;
|
|
|
|
rows= (int) md->nitems/columns;
|
|
if (rows<1) rows= 1;
|
|
|
|
while (rows*columns<(md->nitems+columns) ) rows++;
|
|
|
|
/* size and location */
|
|
if(md->title) width= 2*strlen(md->title)+BIF_GetStringWidth(uiBlockGetCurFont(block), md->title, (U.transopts & USER_TR_BUTTONS));
|
|
else width= 0;
|
|
for(a=0; a<md->nitems; a++) {
|
|
xmax= BIF_GetStringWidth(uiBlockGetCurFont(block), md->items[a].str, (U.transopts & USER_TR_BUTTONS));
|
|
if(xmax>width) width= xmax;
|
|
}
|
|
|
|
width+= 10;
|
|
if (width<50) width=50;
|
|
|
|
boxh= TBOXH;
|
|
|
|
height= rows*boxh;
|
|
if (md->title) height+= boxh;
|
|
|
|
xmax = G.curscreen->sizex;
|
|
ymax = G.curscreen->sizey;
|
|
|
|
getmouseco_sc(mval);
|
|
|
|
/* find active item */
|
|
#if 0
|
|
fvalue= ui_get_but_val(but);
|
|
for(a=0; a<md->nitems; a++) {
|
|
if( md->items[a].retval== (int)fvalue ) break;
|
|
}
|
|
#endif
|
|
/* no active item? */
|
|
if(a==md->nitems) {
|
|
if(md->title) a= -1;
|
|
else a= 0;
|
|
}
|
|
|
|
if(a>0)
|
|
startx = mval[0]-width/2 - ((int)(a)/rows)*width;
|
|
else
|
|
startx= mval[0]-width/2;
|
|
starty = mval[1]-height + boxh/2 + ((a)%rows)*boxh;
|
|
|
|
if (md->title) starty+= boxh;
|
|
|
|
mousemove[0]= mousemove[1]= 0;
|
|
|
|
if(startx<10) {
|
|
mousemove[0]= 10-startx;
|
|
startx= 10;
|
|
}
|
|
if(starty<10) {
|
|
mousemove[1]= 10-starty;
|
|
starty= 10;
|
|
}
|
|
|
|
endx= startx+width*columns;
|
|
endy= starty+height;
|
|
|
|
if(endx>xmax) {
|
|
mousemove[0]= xmax-endx-10;
|
|
endx= xmax-10;
|
|
startx= endx-width*columns;
|
|
}
|
|
if(endy>ymax) {
|
|
mousemove[1]= ymax-endy-10;
|
|
endy= ymax-10;
|
|
starty= endy-height;
|
|
}
|
|
|
|
ui_warp_pointer(mval[0]+mousemove[0], mval[1]+mousemove[1]);
|
|
|
|
mousemove[0]= mval[0];
|
|
mousemove[1]= mval[1];
|
|
|
|
/* here we go! */
|
|
|
|
if(md->title) {
|
|
uiBut *bt;
|
|
uiSetCurFont(block, UI_HELVB);
|
|
bt= uiDefBut(block, LABEL, 0, md->title, startx, (short)(starty+rows*boxh), (short)width, (short)boxh, NULL, 0.0, 0.0, 0, 0, "");
|
|
uiSetCurFont(block, UI_HELV);
|
|
bt->flag= UI_TEXT_LEFT;
|
|
}
|
|
|
|
for(a=0; a<md->nitems; a++) {
|
|
char *name= md->items[a].str;
|
|
|
|
x1= startx + width*((int)a/rows);
|
|
y1= starty - boxh*(a%rows) + (rows-1)*boxh;
|
|
|
|
if( strcmp(name, "%l")==0){
|
|
uiDefBut(block, SEPR, B_NOP, "", x1, y1, width, PUP_LABELH, NULL, 0, 0.0, 0, 0, "");
|
|
y1 -= PUP_LABELH;
|
|
}
|
|
else {
|
|
uiDefButI(block, BUTM, B_NOP, name, x1, y1, width, boxh-1, &val, (float) md->items[a].retval, 0.0, 0, 0, "");
|
|
y1 -= boxh;
|
|
}
|
|
//uiDefButI(block, BUTM, B_NOP, md->items[a].str, x1, y1, (short)(width-(rows>1)), (short)(boxh-1), &val, (float)md->items[a].retval, 0.0, 0, 0, "");
|
|
}
|
|
|
|
uiBoundsBlock(block, 3);
|
|
|
|
event= uiDoBlocks(&listb, 0);
|
|
|
|
menudata_free(md);
|
|
|
|
if((event & UI_RETURN_OUT)==0) ui_warp_pointer(mousemove[0], mousemove[1]);
|
|
|
|
return val;
|
|
}
|
|
|