Logo Search packages:      
Sourcecode: blender version File versions

interface_draw.c

/**
 * $Id: interface_draw.c,v 1.33 2004/12/03 15:28:48 ton Exp $
 *
 * ***** BEGIN GPL/BL DUAL LICENSE BLOCK *****
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License
 * as published by the Free Software Foundation; either version 2
 * of the License, or (at your option) any later version. The Blender
 * Foundation also sells licenses for use in proprietary software under
 * the Blender License.  See http://www.blender.org/BL/ for information
 * about this.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software Foundation,
 * Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
 *
 * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
 * All rights reserved.
 *
 * The Original Code is: all of this file.
 *
 * Contributor(s): none yet.
 *
 * ***** END GPL/BL DUAL LICENSE BLOCK *****
 */

/* 
     a full doc with API notes can be found in bf-blender/blender/doc/interface_API.txt

 */
 

#include <math.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

#ifndef WIN32
#include <unistd.h>
#else
#include <io.h>
#include "BLI_winstuff.h"
#endif   

#include "MEM_guardedalloc.h"

#include "PIL_time.h"

#include "BLI_blenlib.h"
#include "BLI_arithb.h"

#include "DNA_screen_types.h"
#include "DNA_space_types.h"
#include "DNA_userdef_types.h"
#include "DNA_vec_types.h"

#include "BKE_blender.h"
#include "BKE_utildefines.h"
#include "BKE_global.h"

#include "BIF_gl.h"
#include "BIF_graphics.h"
#include "BIF_keyval.h"
#include "BIF_mainqueue.h"

#include "BIF_screen.h"
#include "BIF_toolbox.h"
#include "BIF_mywindow.h"
#include "BIF_space.h"
#include "BIF_glutil.h"
#include "BIF_interface.h"
#include "BIF_butspace.h"
#include "BIF_language.h"

#include "BSE_view.h"

#include "mydevice.h"
#include "interface.h"
#include "blendef.h"

// globals
extern float UIwinmat[4][4];

/* ************** safe rasterpos for pixmap alignment with pixels ************* */

void ui_rasterpos_safe(float x, float y, float aspect)
{
      float vals[4], remainder;
      int doit=0;
      
      glRasterPos2f(x, y);
      glGetFloatv(GL_CURRENT_RASTER_POSITION, vals);

      remainder= vals[0] - floor(vals[0]);
      if(remainder > 0.4 && remainder < 0.6) {
            if(remainder < 0.5) x -= 0.1*aspect;
            else x += 0.1*aspect;
            doit= 1;
      }
      remainder= vals[1] - floor(vals[1]);
      if(remainder > 0.4 && remainder < 0.6) {
            if(remainder < 0.5) y -= 0.1*aspect;
            else y += 0.1*aspect;
            doit= 1;
      }
      
      if(doit) glRasterPos2f(x, y);
}

/* ************** generic embossed rect, for window sliders etc ************* */

void uiEmboss(float x1, float y1, float x2, float y2, int sel)
{
      
      /* below */
      if(sel) glColor3ub(200,200,200);
      else glColor3ub(50,50,50);
      fdrawline(x1, y1, x2, y1);

      /* right */
      fdrawline(x2, y1, x2, y2);
      
      /* top */
      if(sel) glColor3ub(50,50,50);
      else glColor3ub(200,200,200);
      fdrawline(x1, y2, x2, y2);

      /* left */
      fdrawline(x1, y1, x1, y2);
      
}

/* ************** GENERIC ICON DRAW, NO THEME HERE ************* */

static void ui_draw_icon(uiBut *but, BIFIconID icon)
{
      void BIF_icon_pos(float xs, float ys);
      int blend= 0;
      float xs=0, ys=0;

      // this icon doesn't need draw...
      if(icon==ICON_BLANK1) return;

      if(but->flag & UI_ICON_LEFT) {
            if (but->type==BUTM) {
                  xs= but->x1+1.0;
            }
            else if ((but->type==ICONROW) || (but->type==ICONTEXTROW)) {
                  xs= but->x1+4.0;
            }
            else {
                  xs= but->x1+6.0;
            }
            ys= (but->y1+but->y2- BIF_get_icon_height(icon))/2.0;
      }
      if(but->flag & UI_ICON_RIGHT) {
            xs= but->x2-17.0;
            ys= (but->y1+but->y2- BIF_get_icon_height(icon))/2.0;
      }
      if (!((but->flag & UI_ICON_RIGHT) || (but->flag & UI_ICON_LEFT))) {
            xs= (but->x1+but->x2- BIF_get_icon_width(icon))/2.0;
            ys= (but->y1+but->y2- BIF_get_icon_height(icon))/2.0;
      }

      glRasterPos2f(xs, ys);
      // BIF_icon_pos(xs, ys);

      if(but->aspect>1.1) glPixelZoom(1.0/but->aspect, 1.0/but->aspect);
      else if(but->aspect<0.9) glPixelZoom(1.0/but->aspect, 1.0/but->aspect);

      glEnable(GL_BLEND);
      glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

      /* calculate blend color */
      if ELEM4(but->type, ICONTOG, TOG, ROW, TOGN) {
            if(but->flag & UI_SELECT);
            else if(but->flag & UI_ACTIVE);
            else blend= -60;
      }
      BIF_draw_icon_blended(icon, but->themecol, blend);
      
      glBlendFunc(GL_ONE, GL_ZERO);
      glDisable(GL_BLEND);

      glPixelZoom(1.0, 1.0);
}


/* ************** DEFAULT THEME, SHADED BUTTONS ************* */


#define M_WHITE         BIF_ThemeColorShade(colorid, 80)

#define M_ACT_LIGHT     BIF_ThemeColorShade(colorid, 55)
#define M_LIGHT         BIF_ThemeColorShade(colorid, 45)
#define M_HILITE  BIF_ThemeColorShade(colorid, 25)
#define M_LMEDIUM BIF_ThemeColorShade(colorid, 10)
#define M_MEDIUM  BIF_ThemeColor(colorid)
#define M_LGREY         BIF_ThemeColorShade(colorid, -20)
#define M_GREY          BIF_ThemeColorShade(colorid, -45)
#define M_DARK          BIF_ThemeColorShade(colorid, -80)

#define M_NUMTEXT                   BIF_ThemeColorShade(colorid, 25)
#define M_NUMTEXT_ACT_LIGHT         BIF_ThemeColorShade(colorid, 35)

#define MM_WHITE  BIF_ThemeColorShade(TH_BUT_NEUTRAL, 120)

/* Used for the subtle sunken effect around buttons.
 * One option is to hardcode to white, with alpha, however it causes a 
 * weird 'building up' efect, so it's commented out for now.
 */
 
/*
#define MM_WHITE_OP     glColor4ub(255, 255, 255, 60)
#define MM_WHITE_TR     glColor4ub(255, 255, 255, 0)
 */

#define MM_WHITE_OP     BIF_ThemeColorShadeAlpha(TH_BACK, 55, -100)
#define MM_WHITE_TR     BIF_ThemeColorShadeAlpha(TH_BACK, 55, -255)

#define MM_LIGHT  BIF_ThemeColorShade(TH_BUT_OUTLINE, 45)
#define MM_MEDIUM BIF_ThemeColor(TH_BUT_OUTLINE)
#define MM_GREY         BIF_ThemeColorShade(TH_BUT_OUTLINE, -45)
#define MM_DARK         BIF_ThemeColorShade(TH_BUT_OUTLINE, -80)

/* base shaded button */
static void shaded_button(float x1, float y1, float x2, float y2, float asp, int colorid, int flag, int mid)
{
      /* 'mid' arg determines whether the button is in the middle of
       * an alignment group or not. 0 = not middle, 1 = is in the middle.
       * Done to allow cleaner drawing
       */
       
      /* *** SHADED BUTTON BASE *** */
      glShadeModel(GL_SMOOTH);
      glBegin(GL_QUADS);
      
      if(flag & UI_SELECT) {
            if(flag & UI_ACTIVE) M_MEDIUM;
            else M_LGREY;
      } else {
            if(flag & UI_ACTIVE) M_LIGHT;
            else M_HILITE;
      }

      glVertex2f(x1,y1);
      glVertex2f(x2,y1);

      if(flag & UI_SELECT) {
            if(flag & UI_ACTIVE) M_LGREY;
            else M_GREY;
      } else {
            if(flag & UI_ACTIVE) M_ACT_LIGHT;
            else M_LIGHT;
      }

      glVertex2f(x2,(y2-(y2-y1)/3));
      glVertex2f(x1,(y2-(y2-y1)/3));
      glEnd();
      

      glShadeModel(GL_FLAT);
      glBegin(GL_QUADS);
      
      if(flag & UI_SELECT) {
            if(flag & UI_ACTIVE) M_LGREY;
            else M_GREY;
      } else {
            if(flag & UI_ACTIVE) M_ACT_LIGHT;
            else M_LIGHT;
      }
      
      glVertex2f(x1,(y2-(y2-y1)/3));
      glVertex2f(x2,(y2-(y2-y1)/3));
      glVertex2f(x2,y2);
      glVertex2f(x1,y2);

      glEnd();
      /* *** END SHADED BUTTON BASE *** */
      
      /* *** INNER OUTLINE *** */
      /* left */
      if(!(flag & UI_SELECT)) {
            glShadeModel(GL_SMOOTH);
            glBegin(GL_LINES);
            M_MEDIUM;
            glVertex2f(x1+1,y1+2);
            M_WHITE;
            glVertex2f(x1+1,y2);
            glEnd();
      }
      
      /* right */
            if(!(flag & UI_SELECT)) {
            glShadeModel(GL_SMOOTH);
            glBegin(GL_LINES);
            M_MEDIUM;
            glVertex2f(x2-1,y1+2);
            M_WHITE;
            glVertex2f(x2-1,y2);
            glEnd();
      }
      
      glShadeModel(GL_FLAT);
      
      /* top */
      if(flag & UI_SELECT) {
            if(flag & UI_ACTIVE) M_LGREY;
            else M_GREY;
      } else {
            if(flag & UI_ACTIVE) M_WHITE;
            else M_WHITE;
      }

      fdrawline(x1, (y2-1), x2, (y2-1));
      
      /* bottom */
      if(flag & UI_SELECT) {
            if(flag & UI_ACTIVE) M_MEDIUM;
            else M_LGREY;
      } else {
            if(flag & UI_ACTIVE) M_LMEDIUM;
            else M_MEDIUM;
      }
      fdrawline(x1, (y1+1), x2, (y1+1));
      /* *** END INNER OUTLINE *** */
      
      /* *** OUTER OUTLINE *** */
      if (mid) {
            // we draw full outline, its not AA, and it works better button mouse-over hilite
            MM_DARK;
            
            // left right
            fdrawline(x1, y1, x1, y2);
            fdrawline(x2, y1, x2, y2);
      
            // top down
            fdrawline(x1, y2, x2, y2);
            fdrawline(x1, y1, x2, y1); 
      } else {
            MM_DARK;
            gl_round_box(GL_LINE_LOOP, x1, y1, x2, y2, 1.5);
      }
      /* END OUTER OUTLINE */
}

/* base flat button */
static void flat_button(float x1, float y1, float x2, float y2, float asp, int colorid, int flag, int mid)
{
      /* 'mid' arg determines whether the button is in the middle of
       * an alignment group or not. 0 = not middle, 1 = is in the middle.
       * Done to allow cleaner drawing
       */
       
      /* *** FLAT TEXT/NUM FIELD *** */
      glShadeModel(GL_FLAT);
      if(flag & UI_SELECT) {
            if(flag & UI_ACTIVE) M_LGREY;
            else M_GREY;
      }
      else {
            if(flag & UI_ACTIVE) M_NUMTEXT_ACT_LIGHT;
            else M_NUMTEXT;
      }

      glRectf(x1, y1, x2, y2);
      /* *** END FLAT TEXT/NUM FIELD *** */
      
      /* *** OUTER OUTLINE *** */
      if (mid) {
            // we draw full outline, its not AA, and it works better button mouse-over hilite
            MM_DARK;
            
            // left right
            fdrawline(x1, y1, x1, y2);
            fdrawline(x2, y1, x2, y2);
      
            // top down
            fdrawline(x1, y2, x2, y2);
            fdrawline(x1, y1, x2, y1); 
      } else {
            MM_DARK;
            gl_round_box(GL_LINE_LOOP, x1, y1, x2, y2, 1.5);
      }
      /* END OUTER OUTLINE */
}

/* small side double arrow for iconrow */
static void ui_default_iconrow_arrows(float x1, float y1, float x2, float y2)
{
      glEnable( GL_POLYGON_SMOOTH );
      glEnable( GL_BLEND );
      glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
      
      glShadeModel(GL_FLAT);
      glBegin(GL_TRIANGLES);
      glVertex2f((short)x2-2,(short)(y2-(y2-y1)/2)+1);
      glVertex2f((short)x2-6,(short)(y2-(y2-y1)/2)+1);
      glVertex2f((short)x2-4,(short)(y2-(y2-y1)/2)+4);
      glEnd();
            
      glBegin(GL_TRIANGLES);
      glVertex2f((short)x2-2,(short)(y2-(y2-y1)/2) -1);
      glVertex2f((short)x2-6,(short)(y2-(y2-y1)/2) -1);
      glVertex2f((short)x2-4,(short)(y2-(y2-y1)/2) -4);
      glEnd();
      
      glDisable( GL_BLEND );
      glDisable( GL_POLYGON_SMOOTH );
}

/* side double arrow for menu */
static void ui_default_menu_arrows(float x1, float y1, float x2, float y2)
{
      glEnable( GL_POLYGON_SMOOTH );
      glEnable( GL_BLEND );
      glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
      
      glShadeModel(GL_FLAT);
      glBegin(GL_TRIANGLES);
      glVertex2f((short)x2-4,(short)(y2-(y2-y1)/2)+1);
      glVertex2f((short)x2-12,(short)(y2-(y2-y1)/2)+1);
      glVertex2f((short)x2-8,(short)(y2-(y2-y1)/2)+4);
      glEnd();
            
      glBegin(GL_TRIANGLES);
      glVertex2f((short)x2-4,(short)(y2-(y2-y1)/2) -1);
      glVertex2f((short)x2-12,(short)(y2-(y2-y1)/2) -1);
      glVertex2f((short)x2-8,(short)(y2-(y2-y1)/2) -4);
      glEnd();
      
      glDisable( GL_BLEND );
      glDisable( GL_POLYGON_SMOOTH );
}

/* left/right arrows for number fields */
static void ui_default_num_arrows(float x1, float y1, float x2, float y2)
{
      if( x2-x1 > 25) { // 25 is a bit arbitrary, but small buttons cant have arrows

            glEnable( GL_POLYGON_SMOOTH );
            glEnable( GL_BLEND );
            glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );
            
            glShadeModel(GL_FLAT);
            glBegin(GL_TRIANGLES);
            
            glVertex2f((short)x1+5,(short)(y2-(y2-y1)/2));
            glVertex2f((short)x1+10,(short)(y2-(y2-y1)/2)+4);
            glVertex2f((short)x1+10,(short)(y2-(y2-y1)/2)-4);
            glEnd();

            /* right */
            glShadeModel(GL_FLAT);
            glBegin(GL_TRIANGLES);

            glVertex2f((short)x2-5,(short)(y2-(y2-y1)/2));
            glVertex2f((short)x2-10,(short)(y2-(y2-y1)/2)-4);
            glVertex2f((short)x2-10,(short)(y2-(y2-y1)/2)+4);
            glEnd();
            
            glDisable( GL_BLEND );
            glDisable( GL_POLYGON_SMOOTH );
      }
}

/* changing black/white for TOG3 buts */
static void ui_tog3_invert(float x1, float y1, float x2, float y2, int seltype)
{
      short alpha = 30;
      
      if (seltype == 0) {
            glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
            glEnable(GL_BLEND);
            
            glColor4ub(0, 0, 0, alpha);
            glRectf(x2-6, y1, x2, (y1+(y2-y1)/2));
            
            glColor4ub(255, 255, 255, alpha);
            glRectf(x2-6, (y1+(y2-y1)/2), x2, y2);
            
            glDisable(GL_BLEND);
      } else {
            glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
            glEnable(GL_BLEND);
            
            glColor4ub(255, 255, 255, alpha);
            glRectf(x2-6, y1, x2, (y1+(y2-y1)/2));
            
            glColor4ub(0, 0, 0, alpha);
            glRectf(x2-6, (y1+(y2-y1)/2), x2, y2);
            
            glDisable(GL_BLEND);
      }
}

/* button/popup menu/iconrow drawing code */
static void ui_default_button(int type, int colorid, float asp, float x1, float y1, float x2, float y2, int flag)
{
      int align= (flag & UI_BUT_ALIGN);

      if(align) {
      
            /* *** BOTTOM OUTER SUNKEN EFFECT *** */
            if (!((align == UI_BUT_ALIGN_DOWN) ||
                  (align == (UI_BUT_ALIGN_DOWN|UI_BUT_ALIGN_RIGHT)) ||
                  (align == (UI_BUT_ALIGN_DOWN|UI_BUT_ALIGN_LEFT)))) {
                  glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
                  glEnable(GL_BLEND);
                  MM_WHITE_OP;
                  fdrawline(x1, y1-1, x2, y1-1);      
                  glDisable(GL_BLEND);
            }
            /* *** END BOTTOM OUTER SUNKEN EFFECT *** */
            
            switch(align) {
            case UI_BUT_ALIGN_TOP:
                  uiSetRoundBox(12);
                  
                  /* last arg in shaded_button() determines whether the button is in the middle of
                   * an alignment group or not. 0 = not middle, 1 = is in the middle.
                   * Done to allow cleaner drawing
                   */
                   
                  shaded_button(x1, y1, x2, y2, asp, colorid, flag, 0);
                  break;
            case UI_BUT_ALIGN_DOWN:
                  uiSetRoundBox(3);
                  shaded_button(x1, y1, x2, y2, asp, colorid, flag, 0);
                  break;
            case UI_BUT_ALIGN_LEFT:
                  
                  /* RIGHT OUTER SUNKEN EFFECT */
                  glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
                  glEnable(GL_BLEND);
                  glShadeModel(GL_SMOOTH);
                  glBegin(GL_LINES);
                  MM_WHITE_OP;
                  glVertex2f(x2+1,y1);
                  MM_WHITE_TR;
                  glVertex2f(x2+1,y2);
                  glEnd();
                  glDisable(GL_BLEND);
                  
                  uiSetRoundBox(6);
                  shaded_button(x1, y1, x2, y2, asp, colorid, flag, 0);
                  break;
            case UI_BUT_ALIGN_RIGHT:
            
                  /* LEFT OUTER SUNKEN EFFECT */
                  glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
                  glEnable(GL_BLEND);
                  glShadeModel(GL_SMOOTH);
                  glBegin(GL_LINES);
                  MM_WHITE_OP;
                  glVertex2f(x1-1,y1);
                  MM_WHITE_TR;
                  glVertex2f(x1-1,y2);
                  glEnd();
                  glDisable(GL_BLEND);
            
                  uiSetRoundBox(9);
                  shaded_button(x1, y1, x2, y2, asp, colorid, flag, 0);
                  break;
                  
            case UI_BUT_ALIGN_DOWN|UI_BUT_ALIGN_RIGHT:
                  uiSetRoundBox(1);
                  shaded_button(x1, y1, x2, y2, asp, colorid, flag, 0);
                  break;
            case UI_BUT_ALIGN_DOWN|UI_BUT_ALIGN_LEFT:
                  uiSetRoundBox(2);
                  shaded_button(x1, y1, x2, y2, asp, colorid, flag, 0);
                  break;
            case UI_BUT_ALIGN_TOP|UI_BUT_ALIGN_RIGHT:
            
                  /* LEFT OUTER SUNKEN EFFECT */
                  glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
                  glEnable(GL_BLEND);
                  glShadeModel(GL_SMOOTH);
                  glBegin(GL_LINES);
                  MM_WHITE_OP;
                  glVertex2f(x1-1,y1);
                  MM_WHITE_TR;
                  glVertex2f(x1-1,y2);
                  glEnd();
                  glDisable(GL_BLEND);
            
                  uiSetRoundBox(8);
                  shaded_button(x1, y1, x2, y2, asp, colorid, flag, 0);
                  break;
            case UI_BUT_ALIGN_TOP|UI_BUT_ALIGN_LEFT:
            
                  /* RIGHT OUTER SUNKEN EFFECT */
                  glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
                  glEnable(GL_BLEND);
                  glShadeModel(GL_SMOOTH);
                  glBegin(GL_LINES);
                  MM_WHITE_OP;
                  glVertex2f(x2+1,y1);
                  MM_WHITE_TR;
                  glVertex2f(x2+1,y2);
                  glEnd();
                  glDisable(GL_BLEND);
                  
                  uiSetRoundBox(4);
                  shaded_button(x1, y1, x2, y2, asp, colorid, flag, 0);
                  break;
                  
            default:
                  shaded_button(x1, y1, x2, y2, asp, colorid, flag, 1);
                  break;
            }
      } 
      else {      
            glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
            glEnable(GL_BLEND);
            glShadeModel(GL_SMOOTH);
            
            /* BOTTOM OUTER SUNKEN EFFECT */
            MM_WHITE_OP;
            fdrawline(x1, y1-1, x2, y1-1);      
            
            /* LEFT OUTER SUNKEN EFFECT */
            glBegin(GL_LINES);
            MM_WHITE_OP;
            glVertex2f(x1-1,y1);
            MM_WHITE_TR;
            glVertex2f(x1-1,y2);
            glEnd();
            
            /* RIGHT OUTER SUNKEN EFFECT */
            glBegin(GL_LINES);
            MM_WHITE_OP;
            glVertex2f(x2+1,y1);
            MM_WHITE_TR;
            glVertex2f(x2+1,y2);
            glEnd();
            
            glDisable(GL_BLEND);
      
            uiSetRoundBox(15);
            shaded_button(x1, y1, x2, y2, asp, colorid, flag, 0);
      }
      
      /* *** EXTRA DRAWING FOR SPECIFIC CONTROL TYPES *** */
      switch(type) {
      case ICONROW:
      case ICONTEXTROW:
            /* DARKENED AREA */
            glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
            glEnable(GL_BLEND);
            
            glColor4ub(0, 0, 0, 30);
            glRectf(x2-9, y1, x2, y2);
      
            glDisable(GL_BLEND);
            /* END DARKENED AREA */
      
            /* ICONROW DOUBLE-ARROW  */
            M_DARK;
            ui_default_iconrow_arrows(x1, y1, x2, y2);
            /* END ICONROW DOUBLE-ARROW */
            break;
      case MENU:
            /* DARKENED AREA */
            glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
            glEnable(GL_BLEND);
            
            glColor4ub(0, 0, 0, 30);
            glRectf(x2-18, y1, x2, y2);
      
            glDisable(GL_BLEND);
            /* END DARKENED AREA */
      
            /* MENU DOUBLE-ARROW  */
            M_DARK;
            ui_default_menu_arrows(x1, y1, x2, y2);
            /* MENU DOUBLE-ARROW */
            break;
      }     
}


/* number/text field drawing code */
static void ui_default_flat(int type, int colorid, float asp, float x1, float y1, float x2, float y2, int flag)
{
      int align= (flag & UI_BUT_ALIGN);

      if(align) {
      
            /* *** BOTTOM OUTER SUNKEN EFFECT *** */
            if (!((align == UI_BUT_ALIGN_DOWN) ||
                  (align == (UI_BUT_ALIGN_DOWN|UI_BUT_ALIGN_RIGHT)) ||
                  (align == (UI_BUT_ALIGN_DOWN|UI_BUT_ALIGN_LEFT)))) {
                  glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
                  glEnable(GL_BLEND);
                  MM_WHITE_OP;
                  fdrawline(x1, y1-1, x2, y1-1);      
                  glDisable(GL_BLEND);
            }
            /* *** END BOTTOM OUTER SUNKEN EFFECT *** */
            
            switch(align) {
            case UI_BUT_ALIGN_TOP:
                  uiSetRoundBox(12);
                  
                  /* last arg in shaded_button() determines whether the button is in the middle of
                   * an alignment group or not. 0 = not middle, 1 = is in the middle.
                   * Done to allow cleaner drawing
                   */
                   
                  flat_button(x1, y1, x2, y2, asp, colorid, flag, 0);
                  break;
            case UI_BUT_ALIGN_DOWN:
                  uiSetRoundBox(3);
                  flat_button(x1, y1, x2, y2, asp, colorid, flag, 0);
                  break;
            case UI_BUT_ALIGN_LEFT:
                  
                  /* RIGHT OUTER SUNKEN EFFECT */
                  glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
                  glEnable(GL_BLEND);
                  glShadeModel(GL_SMOOTH);
                  glBegin(GL_LINES);
                  MM_WHITE_OP;
                  glVertex2f(x2+1,y1);
                  MM_WHITE_TR;
                  glVertex2f(x2+1,y2);
                  glEnd();
                  glDisable(GL_BLEND);
                  
                  uiSetRoundBox(6);
                  flat_button(x1, y1, x2, y2, asp, colorid, flag, 0);
                  break;
            case UI_BUT_ALIGN_RIGHT:
            
                  /* LEFT OUTER SUNKEN EFFECT */
                  glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
                  glEnable(GL_BLEND);
                  glShadeModel(GL_SMOOTH);
                  glBegin(GL_LINES);
                  MM_WHITE_OP;
                  glVertex2f(x1-1,y1);
                  MM_WHITE_TR;
                  glVertex2f(x1-1,y2);
                  glEnd();
                  glDisable(GL_BLEND);
            
                  uiSetRoundBox(9);
                  flat_button(x1, y1, x2, y2, asp, colorid, flag, 0);
                  break;
                  
            case UI_BUT_ALIGN_DOWN|UI_BUT_ALIGN_RIGHT:
                  uiSetRoundBox(1);
                  flat_button(x1, y1, x2, y2, asp, colorid, flag, 0);
                  break;
            case UI_BUT_ALIGN_DOWN|UI_BUT_ALIGN_LEFT:
                  uiSetRoundBox(2);
                  flat_button(x1, y1, x2, y2, asp, colorid, flag, 0);
                  break;
            case UI_BUT_ALIGN_TOP|UI_BUT_ALIGN_RIGHT:
            
                  /* LEFT OUTER SUNKEN EFFECT */
                  glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
                  glEnable(GL_BLEND);
                  glShadeModel(GL_SMOOTH);
                  glBegin(GL_LINES);
                  MM_WHITE_OP;
                  glVertex2f(x1-1,y1);
                  MM_WHITE_TR;
                  glVertex2f(x1-1,y2);
                  glEnd();
                  glDisable(GL_BLEND);
            
                  uiSetRoundBox(8);
                  flat_button(x1, y1, x2, y2, asp, colorid, flag, 0);
                  break;
            case UI_BUT_ALIGN_TOP|UI_BUT_ALIGN_LEFT:
            
                  /* RIGHT OUTER SUNKEN EFFECT */
                  glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
                  glEnable(GL_BLEND);
                  glShadeModel(GL_SMOOTH);
                  glBegin(GL_LINES);
                  MM_WHITE_OP;
                  glVertex2f(x2+1,y1);
                  MM_WHITE_TR;
                  glVertex2f(x2+1,y2);
                  glEnd();
                  glDisable(GL_BLEND);
                  
                  uiSetRoundBox(4);
                  flat_button(x1, y1, x2, y2, asp, colorid, flag, 0);
                  break;
                  
            default:
                  flat_button(x1, y1, x2, y2, asp, colorid, flag, 1);
                  break;
            }
      } 
      else {
      
            glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
            glEnable(GL_BLEND);
            glShadeModel(GL_SMOOTH);
            
            /* BOTTOM OUTER SUNKEN EFFECT */
            MM_WHITE_OP;
            fdrawline(x1, y1-1, x2, y1-1);      
            
            /* LEFT OUTER SUNKEN EFFECT */
            glBegin(GL_LINES);
            MM_WHITE_OP;
            glVertex2f(x1-1,y1);
            MM_WHITE_TR;
            glVertex2f(x1-1,y2);
            glEnd();
            
            /* RIGHT OUTER SUNKEN EFFECT */
            glBegin(GL_LINES);
            MM_WHITE_OP;
            glVertex2f(x2+1,y1);
            MM_WHITE_TR;
            glVertex2f(x2+1,y2);
            glEnd();
            
            glDisable(GL_BLEND);

            uiSetRoundBox(15);
            flat_button(x1, y1, x2, y2, asp, colorid, flag, 0);
      }
      
      /* *** EXTRA DRAWING FOR SPECIFIC CONTROL TYPES *** */
      switch(type) {
      case NUM:
            /* SIDE ARROWS */
            /* left */
            if(flag & UI_SELECT) {
                  if(flag & UI_ACTIVE) M_DARK;
                  else M_DARK;
            } else {
                  if(flag & UI_ACTIVE) M_GREY;
                  else M_LGREY;
            }
            
            ui_default_num_arrows(x1, y1, x2, y2);
            /* END SIDE ARROWS */
      }
}

static void ui_default_slider(int colorid, float fac, float aspect, float x1, float y1, float x2, float y2, int flag)
{
      float ymid, yc;

      /* the slider background line */
      ymid= (y1+y2)/2.0;
      //yc= 2.5*aspect; // height of center line
      yc = 2.3; // height of center line
      
      if(flag & UI_SELECT) 
                  BIF_ThemeColorShade(TH_BUT_NUM, -5);
      else
            if(flag & UI_ACTIVE) 
                  BIF_ThemeColorShade(TH_BUT_NUM, +35); 
            else
                  BIF_ThemeColorShade(TH_BUT_NUM, +25); 

      glRectf(x1, ymid-yc, x2, ymid+yc);
      
      /* top inner bevel */
      if(flag & UI_SELECT) BIF_ThemeColorShade(TH_BUT_NUM, -40); 
      else BIF_ThemeColorShade(TH_BUT_NUM, -5); 
      fdrawline(x1+1, ymid+yc, x2, ymid+yc);
      
      /* bottom inner bevel */
      if(flag & UI_SELECT) BIF_ThemeColorShade(TH_BUT_NUM, +15); 
      else BIF_ThemeColorShade(TH_BUT_NUM, +45); 
      fdrawline(x1+1, ymid-yc, x2, ymid-yc);
      
      
      /* the movable slider */
      if(flag & UI_SELECT) BIF_ThemeColorShade(TH_BUT_NUM, +80); 
      else BIF_ThemeColorShade(TH_BUT_NUM, -45); 

      glShadeModel(GL_SMOOTH);
      glBegin(GL_QUADS);

      BIF_ThemeColorShade(TH_BUT_NUM, -45); 

      glVertex2f(x1,     y1+2.5);
      glVertex2f(x1+fac, y1+2.5);

      BIF_ThemeColor(TH_BUT_NUM); 

      glVertex2f(x1+fac, y2-2.5);
      glVertex2f(x1,     y2-2.5);

      glEnd();
      

      /* slider handle center */
      glShadeModel(GL_SMOOTH);
      glBegin(GL_QUADS);

      BIF_ThemeColor(TH_BUT_NUM); 
      glVertex2f(x1+fac-3, y1+2);
      glVertex2f(x1+fac, y1+4);
      BIF_ThemeColorShade(TH_BUT_NUM, +80); 
      glVertex2f(x1+fac, y2-2);
      glVertex2f(x1+fac-3, y2-2);

      glEnd();
      
      /* slider handle left bevel */
      BIF_ThemeColorShade(TH_BUT_NUM, +70); 
      fdrawline(x1+fac-3, y2-2, x1+fac-3, y1+2);
      
      /* slider handle right bevel */
      BIF_ThemeColorShade(TH_BUT_NUM, -35); 
      fdrawline(x1+fac, y2-2, x1+fac, y1+2);

      glShadeModel(GL_FLAT);
}

/* default theme callback */
static void ui_draw_default(int type, int colorid, float aspect, float x1, float y1, float x2, float y2, int flag)
{

      switch(type) {
      case TEX:
      case IDPOIN:
      case NUM:
            ui_default_flat(type, colorid, aspect, x1, y1, x2, y2, flag);
            break;
      case ICONROW: 
      case ICONTEXTROW: 
      case MENU: 
      default: 
            ui_default_button(type, colorid, aspect, x1, y1, x2, y2, flag);
      }

}


/* *************** OLDSKOOL THEME ***************** */

static void ui_draw_outlineX(float x1, float y1, float x2, float y2, float asp1)
{
      float vec[2];
      
      glBegin(GL_LINE_LOOP);
      vec[0]= x1+asp1; vec[1]= y1-asp1;
      glVertex2fv(vec);
      vec[0]= x2-asp1; 
      glVertex2fv(vec);
      vec[0]= x2+asp1; vec[1]= y1+asp1;
      glVertex2fv(vec);
      vec[1]= y2-asp1;
      glVertex2fv(vec);
      vec[0]= x2-asp1; vec[1]= y2+asp1;
      glVertex2fv(vec);
      vec[0]= x1+asp1;
      glVertex2fv(vec);
      vec[0]= x1-asp1; vec[1]= y2-asp1;
      glVertex2fv(vec);
      vec[1]= y1+asp1;
      glVertex2fv(vec);
      glEnd();                
        
}


static void ui_draw_oldskool(int type, int colorid, float asp, float x1, float y1, float x2, float y2, int flag)
{
      /* paper */
      if(flag & UI_SELECT) {
            if(flag & UI_ACTIVE) BIF_ThemeColorShade(colorid, -40);
            else BIF_ThemeColorShade(colorid, -30);
      }
      else {
            if(flag & UI_ACTIVE) BIF_ThemeColorShade(colorid, +30);
            else BIF_ThemeColorShade(colorid, +20);
      }
      
      glRectf(x1+1, y1+1, x2-1, y2-1);

      x1+= asp;
      x2-= asp;
      y1+= asp;
      y2-= asp;

      /* below */
      if(flag & UI_SELECT) BIF_ThemeColorShade(colorid, 0);
      else BIF_ThemeColorShade(colorid, -30);
      fdrawline(x1, y1, x2, y1);

      /* right */
      fdrawline(x2, y1, x2, y2);
      
      /* top */
      if(flag & UI_SELECT) BIF_ThemeColorShade(colorid, -30);
      else BIF_ThemeColorShade(colorid, 0);
      fdrawline(x1, y2, x2, y2);

      /* left */
      fdrawline(x1, y1, x1, y2);
      
      /* outline */
      glColor3ub(0,0,0);
      ui_draw_outlineX(x1, y1, x2, y2, asp);
      
      
      /* special type decorations */
      switch(type) {
      case NUM:
            if(flag & UI_SELECT) BIF_ThemeColorShade(colorid, -60);
            else BIF_ThemeColorShade(colorid, -30);
            ui_default_num_arrows(x1, y1, x2, y2);
            break;

      case ICONROW: 
      case ICONTEXTROW: 
            if(flag & UI_ACTIVE) BIF_ThemeColorShade(colorid, 0);
            else BIF_ThemeColorShade(colorid, -10);
            glRectf(x2-9, y1+asp, x2-asp, y2-asp);

            BIF_ThemeColorShade(colorid, -50);
            ui_default_iconrow_arrows(x1, y1, x2, y2);
            break;
            
      case MENU: 
            if(flag & UI_ACTIVE) BIF_ThemeColorShade(colorid, 0);
            else BIF_ThemeColorShade(colorid, -10);
            glRectf(x2-17, y1+asp, x2-asp, y2-asp);

            BIF_ThemeColorShade(colorid, -50);
            ui_default_menu_arrows(x1, y1, x2, y2);
            break;
      }
      
}

/* *************** BASIC ROUNDED THEME ***************** */

static void round_button(float x1, float y1, float x2, float y2, float asp, 
                                     int colorid, int round, int menudeco, int curshade)
{
      float rad;
      char col[4];
      
      rad= (y2-y1)/2.0;
      if(rad>7.0) rad= 7.0;
      
      uiSetRoundBox(round);
      gl_round_box(GL_POLYGON, x1, y1, x2, y2, rad);

      if(menudeco) {
            uiSetRoundBox(round & ~9);
            BIF_ThemeColorShade(colorid, curshade-20);
            gl_round_box(GL_POLYGON, x2-menudeco, y1, x2, y2, rad);
      }
      
      /* fake AA */
      uiSetRoundBox(round);
      glEnable( GL_BLEND );
      glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA );

      BIF_GetThemeColor3ubv(colorid, col);
            
      if(col[0]<100) col[0]= 0; else col[0]-= 100;
      if(col[1]<100) col[1]= 0; else col[1]-= 100;
      if(col[2]<100) col[2]= 0; else col[2]-= 100;
      col[3]= 80;
      glColor4ubv(col);
      gl_round_box(GL_LINE_LOOP, x1, y1, x2, y2, rad - asp);
      gl_round_box(GL_LINE_LOOP, x1, y1, x2, y2, rad + asp);
      col[3]= 180;
      glColor4ubv(col);
      gl_round_box(GL_LINE_LOOP, x1, y1, x2, y2, rad);

      glDisable( GL_BLEND );
}

/* button in midst of alignment row */
static void round_button_mid(float x1, float y1, float x2, float y2, float asp, 
                                           int colorid, int align, int menudeco, int curshade)
{
      glRectf(x1, y1, x2, y2);
      
      if(menudeco) {
            BIF_ThemeColorShade(colorid, curshade-20);
            glRectf(x2-menudeco, y1, x2, y2);
      }
      
      BIF_ThemeColorBlendShade(colorid, TH_BACK, 0.5, -70);
      // we draw full outline, its not AA, and it works better button mouse-over hilite
      
      // left right
      fdrawline(x1, y1, x1, y2);
      fdrawline(x2, y1, x2, y2);

      // top down
      fdrawline(x1, y2, x2, y2);
      fdrawline(x1, y1, x2, y1);   
}

static void ui_draw_round(int type, int colorid, float asp, float x1, float y1, float x2, float y2, int flag)
{
      int align= (flag & UI_BUT_ALIGN);
      int curshade= 0, menudeco= 0;
      
      if(type==ICONROW || type==ICONTEXTROW) menudeco= 9;
      else if((type==MENU || type==BLOCK) && x2-x1>24) menudeco= 16;
      
      /* paper */
      if(flag & UI_SELECT) {
            if(flag & UI_ACTIVE) curshade= -40;
            else curshade= -30;
      }
      else {
            if(flag & UI_ACTIVE) curshade= 30;
            else curshade= +20;
      }
      
      BIF_ThemeColorShade(colorid, curshade);

      if(align) {
            switch(align) {
            case UI_BUT_ALIGN_TOP:
                  round_button(x1, y1, x2, y2, asp, colorid, 12, menudeco, curshade);
                  break;
            case UI_BUT_ALIGN_DOWN:
                  round_button(x1, y1, x2, y2, asp, colorid, 3, menudeco, curshade);
                  break;
            case UI_BUT_ALIGN_LEFT:
                  round_button(x1, y1, x2, y2, asp, colorid, 6, menudeco, curshade);
                  break;
            case UI_BUT_ALIGN_RIGHT:
                  round_button(x1, y1, x2, y2, asp, colorid, 9, menudeco, curshade);
                  break;
                  
            case UI_BUT_ALIGN_DOWN|UI_BUT_ALIGN_RIGHT:
                  round_button(x1, y1, x2, y2, asp, colorid, 1, menudeco, curshade);
                  break;
            case UI_BUT_ALIGN_DOWN|UI_BUT_ALIGN_LEFT:
                  round_button(x1, y1, x2, y2, asp, colorid, 2, menudeco, curshade);
                  break;
            case UI_BUT_ALIGN_TOP|UI_BUT_ALIGN_RIGHT:
                  round_button(x1, y1, x2, y2, asp, colorid, 8, menudeco, curshade);
                  break;
            case UI_BUT_ALIGN_TOP|UI_BUT_ALIGN_LEFT:
                  round_button(x1, y1, x2, y2, asp, colorid, 4, menudeco, curshade);
                  break;
                  
            default:
                  round_button_mid(x1, y1, x2, y2, asp, colorid, align, menudeco, curshade);
                  break;
            }
      } 
      else {
            round_button(x1, y1, x2, y2, asp, colorid, 15, menudeco, curshade);
      }

      /* special type decorations */
      switch(type) {
      case NUM:
            BIF_ThemeColorShade(colorid, curshade-60);
            ui_default_num_arrows(x1, y1, x2, y2);
            break;

      case ICONROW: 
      case ICONTEXTROW: 
            BIF_ThemeColorShade(colorid, curshade-60);
            ui_default_iconrow_arrows(x1, y1, x2, y2);
            break;
            
      case MENU: 
      case BLOCK: 
            BIF_ThemeColorShade(colorid, curshade-60);
            ui_default_menu_arrows(x1, y1, x2, y2);
            break;
      }
}

/* *************** MINIMAL THEME ***************** */

// theme can define an embosfunc and sliderfunc, text+icon drawing is standard, no theme.



/* super minimal button as used in logic menu */
static void ui_draw_minimal(int type, int colorid, float asp, float x1, float y1, float x2, float y2, int flag)
{
      
      x1+= asp;
      x2-= asp;
      y1+= asp;
      y2-= asp;

      /* paper */
      if(flag & UI_SELECT) {
            if(flag & UI_ACTIVE) BIF_ThemeColorShade(colorid, -40);
            else BIF_ThemeColorShade(colorid, -30);
      }
      else {
            if(flag & UI_ACTIVE) BIF_ThemeColorShade(colorid, +20);
            else BIF_ThemeColorShade(colorid, +10);
      }
      
      glRectf(x1, y1, x2, y2);

      if(flag & UI_SELECT) {
            BIF_ThemeColorShade(colorid, -60);

            /* top */
            fdrawline(x1, y2, x2, y2);
            /* left */
            fdrawline(x1, y1, x1, y2);
            BIF_ThemeColorShade(colorid, +40);

            /* below */
            fdrawline(x1, y1, x2, y1);
            /* right */
            fdrawline(x2, y1, x2, y2);
      }
      else {
            BIF_ThemeColorShade(colorid, +40);

            /* top */
            fdrawline(x1, y2, x2, y2);
            /* left */
            fdrawline(x1, y1, x1, y2);
            
            BIF_ThemeColorShade(colorid, -60);
            /* below */
            fdrawline(x1, y1, x2, y1);
            /* right */
            fdrawline(x2, y1, x2, y2);
      }
      
      /* special type decorations */
      switch(type) {
      case NUM:
            if(flag & UI_SELECT) BIF_ThemeColorShade(colorid, -60);
            else BIF_ThemeColorShade(colorid, -30);
            ui_default_num_arrows(x1, y1, x2, y2);
            break;

      case ICONROW: 
      case ICONTEXTROW: 
            if(flag & UI_ACTIVE) BIF_ThemeColorShade(colorid, 0);
            else BIF_ThemeColorShade(colorid, -10);
            glRectf(x2-9, y1+asp, x2-asp, y2-asp);

            BIF_ThemeColorShade(colorid, -50);
            ui_default_iconrow_arrows(x1, y1, x2, y2);
            break;
            
      case MENU: 
      case BLOCK: 
            if(flag & UI_ACTIVE) BIF_ThemeColorShade(colorid, 0);
            else BIF_ThemeColorShade(colorid, -10);
            glRectf(x2-17, y1+asp, x2-asp, y2-asp);

            BIF_ThemeColorShade(colorid, -50);
            ui_default_menu_arrows(x1, y1, x2, y2);
            break;
      }
      
      
}


/* fac is the slider handle position between x1 and x2 */
static void ui_draw_slider(int colorid, float fac, float aspect, float x1, float y1, float x2, float y2, int flag)
{
      float ymid, yc;

      /* the slider background line */
      ymid= (y1+y2)/2.0;
      yc= 1.7*aspect;   

      if(flag & UI_ACTIVE) 
            BIF_ThemeColorShade(colorid, -50); 
      else 
            BIF_ThemeColorShade(colorid, -40); 

      /* left part */
      glRectf(x1, ymid-2.0*yc, x1+fac, ymid+2.0*yc);
      /* right part */
      glRectf(x1+fac, ymid-yc, x2, ymid+yc);

      /* the movable slider */
      
      BIF_ThemeColorShade(colorid, +70); 
      glRectf(x1+fac-aspect, ymid-2.0*yc, x1+fac+aspect, ymid+2.0*yc);

}

/* ************** STANDARD MENU DRAWING FUNCTION ************* */


static void ui_shadowbox(float minx, float miny, float maxx, float maxy, float shadsize, unsigned char alpha)
{
      glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
      glEnable(GL_BLEND);
      glShadeModel(GL_SMOOTH);
      
      /* right quad */
      glBegin(GL_POLYGON);
      glColor4ub(0, 0, 0, alpha);
      glVertex2f(maxx, miny);
      glVertex2f(maxx, maxy-shadsize);
      glColor4ub(0, 0, 0, 0);
      glVertex2f(maxx+shadsize, maxy-shadsize-shadsize);
      glVertex2f(maxx+shadsize, miny);
      glEnd();
      
      /* corner shape */
      glBegin(GL_POLYGON);
      glColor4ub(0, 0, 0, alpha);
      glVertex2f(maxx, miny);
      glColor4ub(0, 0, 0, 0);
      glVertex2f(maxx+shadsize, miny);
      glVertex2f(maxx+0.7*shadsize, miny-0.7*shadsize);
      glVertex2f(maxx, miny-shadsize);
      glEnd();
      
      /* bottom quad */       
      glBegin(GL_POLYGON);
      glColor4ub(0, 0, 0, alpha);
      glVertex2f(minx+shadsize, miny);
      glVertex2f(maxx, miny);
      glColor4ub(0, 0, 0, 0);
      glVertex2f(maxx, miny-shadsize);
      glVertex2f(minx+shadsize+shadsize, miny-shadsize);
      glEnd();
      
      glDisable(GL_BLEND);
      glShadeModel(GL_FLAT);
}

void uiDrawBoxShadow(unsigned char alpha, float minx, float miny, float maxx, float maxy)
{
      /* accumulated outline boxes to make shade not linear, is more pleasant */
      ui_shadowbox(minx, miny, maxx, maxy, 6.0, (30*alpha)>>8);
      ui_shadowbox(minx, miny, maxx, maxy, 4.0, (70*alpha)>>8);
      ui_shadowbox(minx, miny, maxx, maxy, 2.0, (100*alpha)>>8);
      
}

// background for pulldowns, pullups, and other drawing temporal menus....
// has to be made themable still (now only color)

void uiDrawMenuBox(float minx, float miny, float maxx, float maxy, short flag)
{
      char col[4];
      BIF_GetThemeColor4ubv(TH_MENU_BACK, col);
      
      if( (flag & UI_BLOCK_NOSHADOW)==0) {
            /* accumulated outline boxes to make shade not linear, is more pleasant */
            ui_shadowbox(minx, miny, maxx, maxy, 6.0, (30*col[3])>>8);
            ui_shadowbox(minx, miny, maxx, maxy, 4.0, (70*col[3])>>8);
            ui_shadowbox(minx, miny, maxx, maxy, 2.0, (100*col[3])>>8);
            
            glEnable(GL_BLEND);
            glColor4ubv(col);
            glRectf(minx-1, miny, minx, maxy);  // 1 pixel on left, to distinguish sublevel menus
      }
      glEnable(GL_BLEND);
      glColor4ubv(col);
      glRectf(minx, miny, maxx, maxy);
      glDisable(GL_BLEND);
}



/* pulldown menu item */
static void ui_draw_pulldown_item(int type, int colorid, float asp, float x1, float y1, float x2, float y2, int flag)
{
      char col[4];
      
      BIF_GetThemeColor4ubv(TH_MENU_BACK, col);
      if(col[3]!=255) {
            glEnable(GL_BLEND);
            glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
      }
      
      if((flag & UI_ACTIVE) && type!=LABEL) {
            BIF_ThemeColor4(TH_MENU_HILITE);
            glRectf(x1, y1, x2, y2);
      

      } else {
            BIF_ThemeColor4(colorid);     // is set at TH_MENU_ITEM when pulldown opened.
            glRectf(x1, y1, x2, y2);
      }

      glDisable(GL_BLEND);
}

/* pulldown menu calling button */
static void ui_draw_pulldown_round(int type, int colorid, float asp, float x1, float y1, float x2, float y2, int flag)
{
      
      if(flag & UI_ACTIVE) {
            BIF_ThemeColor(TH_MENU_HILITE);

            uiSetRoundBox(15);
            gl_round_box(GL_POLYGON, x1, y1+3, x2, y2-3, 7.0);

            glEnable( GL_LINE_SMOOTH );
            glEnable( GL_BLEND );
            glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
            gl_round_box(GL_LINE_LOOP, x1, y1+3, x2, y2-3, 7.0);
            glDisable( GL_LINE_SMOOTH );
            glDisable( GL_BLEND );
            
      } else {
            BIF_ThemeColor(colorid);      // is set at TH_MENU_ITEM when pulldown opened.
            glRectf(x1-1, y1+2, x2+1, y2-2);
      }
      
}


/* ************** TEXT AND ICON DRAWING FUNCTIONS ************* */



/* draws text and icons for buttons */
static void ui_draw_text_icon(uiBut *but)
{
      float x;
      int len;
      char *cpoin;
      
      /* check for button text label */
      if (but->type == ICONTEXTROW) {
            ui_draw_icon(but, (BIFIconID) (but->icon+but->iconadd));
      }
      else {

            // text button cursor
            if(but->pos != -1) {
                  short t, pos, ch;
                  
                  pos= but->pos+strlen(but->str);
                  if(pos >= but->ofs) {
                        if(but->drawstr[0]!=0) {
                              ch= but->drawstr[pos];
                              but->drawstr[pos]= 0;
            
                              t= but->aspect*BIF_GetStringWidth(but->font, but->drawstr+but->ofs, (U.transopts & USER_TR_BUTTONS)) + 3;
            
                              but->drawstr[pos]= ch;
                        }
                        else t= 3;
                        
                        glColor3ub(255,0,0);
                        glRects(but->x1+t, but->y1+2, but->x1+t+3, but->y2-2);
                  }     
            }
            if(but->drawstr[0]!=0) {
                  int transopts;
                  
                  // cut string in 2 parts
                  cpoin= strchr(but->drawstr, '|');
                  if(cpoin) *cpoin= 0;

                  /* If there's an icon too (made with uiDefIconTextBut) then draw the icon
                  and offset the text label to accomodate it */
                  
                  if ( (but->flag & UI_HAS_ICON) && (but->flag & UI_ICON_LEFT) ) {
                        ui_draw_icon(but, but->icon);

                        if(but->flag & UI_TEXT_LEFT) x= but->x1+24.0;
                        else x= (but->x1+but->x2-but->strwidth+1)/2.0;
                  }
                  else {
                        if(but->flag & UI_TEXT_LEFT) x= but->x1+4.0;
                        else x= (but->x1+but->x2-but->strwidth+1)/2.0;
                  }
                  
                  /* text color, with pulldown item exception */
                  if(but->dt==UI_EMBOSSP) {
                        if((but->flag & (UI_SELECT|UI_ACTIVE)) && but->type!=LABEL) {     // LABEL = title in pulldowns
                              BIF_ThemeColor(TH_MENU_TEXT_HI);
                        } else {
                              BIF_ThemeColor(TH_MENU_TEXT);
                        }
                  }
                  else {
                        if(but->flag & UI_SELECT) {         
                              BIF_ThemeColor(TH_BUT_TEXT_HI);
                        } else {
                              BIF_ThemeColor(TH_BUT_TEXT);
                        }
                  }

                  /* tog3 button exception */
                  if(but->type==TOG3 && (but->flag & UI_SELECT)) {
                        int ok= 0;
                        
                        if( but->pointype==CHA ) {
                              if( BTST( *(but->poin+2), but->bitnr )) ok= 1;
                        }
                        else if( but->pointype ==SHO ) {
                              short *sp= (short *)but->poin;
                              if( BTST( sp[1], but->bitnr )) ok= 1;
                        }
                        
                        ui_tog3_invert(but->x1,but->y1,but->x2,but->y2, ok);
                        if (ok) glColor3ub(255, 255, 0);
                  }
                  
                  /* LABEL button exception */
                  if(but->type==LABEL && but->min!=0.0) BIF_ThemeColor(TH_BUT_TEXT_HI);
            
                  ui_rasterpos_safe(x, (but->y1+but->y2- 9.0)/2.0, but->aspect);
                  if(but->type==TEX || but->type==IDPOIN) transopts= 0; // no translation, of course!
                  else transopts= (U.transopts & USER_TR_BUTTONS);
                  BIF_DrawString(but->font, but->drawstr+but->ofs, transopts);

                  /* part text right aligned */
                  if(cpoin) {
                        len= BIF_GetStringWidth(but->font, cpoin+1, (U.transopts & USER_TR_BUTTONS));
                        ui_rasterpos_safe( but->x2 - len*but->aspect-3, (but->y1+but->y2- 9.0)/2.0, but->aspect);
                        BIF_DrawString(but->font, cpoin+1, (U.transopts & USER_TR_BUTTONS));
                        *cpoin= '|';
                  }
            }
            /* if there's no text label, then check to see if there's an icon only and draw it */
            else if( but->flag & UI_HAS_ICON ) {
                  ui_draw_icon(but, (BIFIconID) (but->icon+but->iconadd));
            }
      }
}

static void ui_draw_but_COL(uiBut *but)
{
      float *fp;
      char colr, colg, colb;
      
      if( but->pointype==FLO ) {
            fp= (float *)but->poin;
            colr= floor(255.0*fp[0]+0.5);
            colg= floor(255.0*fp[1]+0.5);
            colb= floor(255.0*fp[2]+0.5);
      }
      else {
            char *cp= (char *)but->poin;
            colr= cp[0];
            colg= cp[1];
            colb= cp[2];
      }
      
      /* exception... hrms, but can't simply use the emboss callback for this now. */
      /* this button type needs review, and nice integration with rest of API here */
      if(but->embossfunc == ui_draw_round) {
            char *cp= BIF_ThemeGetColorPtr(U.themes.first, 0, TH_CUSTOM);
            cp[0]= colr; cp[1]= colg; cp[2]= colb;
            but->flag &= ~UI_SELECT;
            but->embossfunc(but->type, TH_CUSTOM, but->aspect, but->x1, but->y1, but->x2, but->y2, but->flag);
      }
      else {
            
            glColor3ub(colr,  colg,  colb);
            glRectf((but->x1), (but->y1), (but->x2), (but->y2));
            glColor3ub(0,  0,  0);
            fdrawbox((but->x1), (but->y1), (but->x2), (but->y2));
      }
}

/* draws in resolution of 20x4 colors */
static void ui_draw_but_HSVCUBE(uiBut *but)
{
      int a;
      float h,s,v;
      float dx, dy, sx1, sx2, sy, x, y;
      float col0[4][3]; // left half, rect bottom to top
      float col1[4][3]; // right half, rect bottom to top
      
      h= but->hsv[0];
      s= but->hsv[1];
      v= but->hsv[2];
      
      /* draw series of gouraud rects */
      glShadeModel(GL_SMOOTH);
      
      if(but->a1==0) {  // H and V vary
            hsv_to_rgb(0.0, s, 0.0,   &col1[0][0], &col1[0][1], &col1[0][2]);
            hsv_to_rgb(0.0, s, 0.333, &col1[1][0], &col1[1][1], &col1[1][2]);
            hsv_to_rgb(0.0, s, 0.666, &col1[2][0], &col1[2][1], &col1[2][2]);
            hsv_to_rgb(0.0, s, 1.0,   &col1[3][0], &col1[3][1], &col1[3][2]);
            x= h; y= v;
      }
      else if(but->a1==1) {   // H and S vary
            hsv_to_rgb(0.0, 0.0, v,   &col1[0][0], &col1[0][1], &col1[0][2]);
            hsv_to_rgb(0.0, 0.333, v, &col1[1][0], &col1[1][1], &col1[1][2]);
            hsv_to_rgb(0.0, 0.666, v, &col1[2][0], &col1[2][1], &col1[2][2]);
            hsv_to_rgb(0.0, 1.0, v,   &col1[3][0], &col1[3][1], &col1[3][2]);
            x= h; y= s;
      }
      else if(but->a1==2) {   // S and V vary
            hsv_to_rgb(h, 0.0, 0.0,   &col1[0][0], &col1[0][1], &col1[0][2]);
            hsv_to_rgb(h, 0.333, 0.0, &col1[1][0], &col1[1][1], &col1[1][2]);
            hsv_to_rgb(h, 0.666, 0.0, &col1[2][0], &col1[2][1], &col1[2][2]);
            hsv_to_rgb(h, 1.0, 0.0,   &col1[3][0], &col1[3][1], &col1[3][2]);
            x= v; y= s;
      }
      else {            // only hue slider
            hsv_to_rgb(0.0, 1.0, 1.0,   &col1[0][0], &col1[0][1], &col1[0][2]);
            VECCOPY(col1[1], col1[0]);
            VECCOPY(col1[2], col1[0]);
            VECCOPY(col1[3], col1[0]);
            x= h; y= 0.5;
      }
      
      for(dx=0.0; dx<1.0; dx+= 0.05) {
            // previous color
            VECCOPY(col0[0], col1[0]);
            VECCOPY(col0[1], col1[1]);
            VECCOPY(col0[2], col1[2]);
            VECCOPY(col0[3], col1[3]);

            // new color
            if(but->a1==0) {  // H and V vary
                  hsv_to_rgb(dx, s, 0.0,   &col1[0][0], &col1[0][1], &col1[0][2]);
                  hsv_to_rgb(dx, s, 0.333, &col1[1][0], &col1[1][1], &col1[1][2]);
                  hsv_to_rgb(dx, s, 0.666, &col1[2][0], &col1[2][1], &col1[2][2]);
                  hsv_to_rgb(dx, s, 1.0,   &col1[3][0], &col1[3][1], &col1[3][2]);
            }
            else if(but->a1==1) {   // H and S vary
                  hsv_to_rgb(dx, 0.0, v,   &col1[0][0], &col1[0][1], &col1[0][2]);
                  hsv_to_rgb(dx, 0.333, v, &col1[1][0], &col1[1][1], &col1[1][2]);
                  hsv_to_rgb(dx, 0.666, v, &col1[2][0], &col1[2][1], &col1[2][2]);
                  hsv_to_rgb(dx, 1.0, v,   &col1[3][0], &col1[3][1], &col1[3][2]);
            }
            else if(but->a1==2) {   // S and V vary
                  hsv_to_rgb(h, 0.0, dx,   &col1[0][0], &col1[0][1], &col1[0][2]);
                  hsv_to_rgb(h, 0.333, dx, &col1[1][0], &col1[1][1], &col1[1][2]);
                  hsv_to_rgb(h, 0.666, dx, &col1[2][0], &col1[2][1], &col1[2][2]);
                  hsv_to_rgb(h, 1.0, dx,   &col1[3][0], &col1[3][1], &col1[3][2]);
            }
            else {      // only H
                  hsv_to_rgb(dx, 1.0, 1.0,   &col1[0][0], &col1[0][1], &col1[0][2]);
                  VECCOPY(col1[1], col1[0]);
                  VECCOPY(col1[2], col1[0]);
                  VECCOPY(col1[3], col1[0]);
            }
            
            // rect
            sx1= but->x1 + dx*(but->x2-but->x1);
            sx2= but->x1 + (dx+0.05)*(but->x2-but->x1);
            sy= but->y1;
            dy= (but->y2-but->y1)/3.0;
            
            glBegin(GL_QUADS);
            for(a=0; a<3; a++, sy+=dy) {
                  glColor3fv(col0[a]);
                  glVertex2f(sx1, sy);

                  glColor3fv(col1[a]);
                  glVertex2f(sx2, sy);
                  
                  glColor3fv(col1[a+1]);
                  glVertex2f(sx2, sy+dy);
                  
                  glColor3fv(col0[a+1]);
                  glVertex2f(sx1, sy+dy);
            }
            glEnd();
      }

      glShadeModel(GL_FLAT);

      /* cursor */
      x= but->x1 + x*(but->x2-but->x1);
      y= but->y1 + y*(but->y2-but->y1);
      CLAMP(x, but->x1+3.0, but->x2-3.0);
      CLAMP(y, but->y1+3.0, but->y2-3.0);
      
      fdrawXORcirc(x, y, 3.1);

      /* outline */
      glColor3ub(0,  0,  0);
      fdrawbox((but->x1), (but->y1), (but->x2), (but->y2));
}

/* nothing! */
static void ui_draw_nothing(int type, int colorid, float asp, float x1, float y1, float x2, float y2, int flag)
{
}


/* ************** EXTERN, called from interface.c ************* */
/* ************** MAIN CALLBACK FUNCTION          ************* */

void ui_set_embossfunc(uiBut *but, int drawtype)
{
      // this aded for evaluating textcolor for example
      but->dt= drawtype;
      
      // not really part of standard minimal themes, just make sure it is set
      but->sliderfunc= ui_draw_slider;

      // standard builtin first:
      if(but->type==LABEL) but->embossfunc= ui_draw_nothing;
      else if(but->type==PULLDOWN) but->embossfunc= ui_draw_pulldown_round;
      else if(drawtype==UI_EMBOSSM) but->embossfunc= ui_draw_minimal;
      else if(drawtype==UI_EMBOSSN) but->embossfunc= ui_draw_nothing;
      else if(drawtype==UI_EMBOSSP) but->embossfunc= ui_draw_pulldown_item;
      else {
            int theme= BIF_GetThemeValue(TH_BUT_DRAWTYPE);
            
            // and the themes
            if(theme==1) {
                  but->embossfunc= ui_draw_default;
                  but->sliderfunc= ui_default_slider;
            }
            else if(theme==2) {
                  but->embossfunc= ui_draw_round;
            }
            else if(theme==3) {
                  but->embossfunc= ui_draw_oldskool;
            }
            else {
                  but->embossfunc= ui_draw_minimal;
            }
      }
      
      // note: if you want aligning, adapt the call uiBlockEndAlign in interface.c 
}


void ui_draw_but(uiBut *but)
{
      double value;
      float x1, x2, y1, y2, fac;
      
      if(but==NULL) return;

      /* signal for frontbuf flush buttons and menus, not when normal drawing */
      if(but->block->in_use) ui_block_set_flush(but->block, but);
            
      switch (but->type) {

      case NUMSLI:
      case HSVSLI:
      
            but->embossfunc(but->type, but->themecol, but->aspect, but->x1, but->y1, but->x2, but->y2, but->flag);
            ui_draw_text_icon(but);

            x1= (but->x1+but->x2)/2;
            x2= but->x2 - 5.0*but->aspect;
            y1= but->y1 + 2.0*but->aspect;
            y2= but->y2 - 2.0*but->aspect;
            
            value= ui_get_but_val(but);
            fac= (value-but->min)*(x2-x1)/(but->max - but->min);
            
            but->sliderfunc(but->themecol, fac, but->aspect, x1, y1, x2, y2, but->flag);
            break;
            
      case SEPR:
            //  only background
            break;
            
      case COL:
            ui_draw_but_COL(but);  // black box with color
            break;

      case HSVCUBE:
            ui_draw_but_HSVCUBE(but);  // box for colorpicker, three types
            break;

      case LINK:
      case INLINK:
            ui_draw_icon(but, but->icon);
            break;

      default:
            but->embossfunc(but->type, but->themecol, but->aspect, but->x1, but->y1, but->x2, but->y2, but->flag);
            ui_draw_text_icon(but);
      
      }
}


Generated by  Doxygen 1.6.0   Back to index