1
1

Compare commits

...

42 Commits

Author SHA1 Message Date
Julian Eisel
8d09ca96a7 Some tweaks for introduction of draw-styles 2015-08-15 01:56:54 +02:00
Julian Eisel
d693aa3590 Merge branch 'master' into temp-ui-widget-refactor
Conflicts:
	source/blender/editors/interface/interface_widgets.c
2015-08-15 01:00:03 +02:00
Julian Eisel
8dbe598192 Merge branch 'master' into temp-ui-widget-refactor 2015-08-03 23:50:08 +02:00
Julian Eisel
76a74e2c58 Merge branch 'master' into temp-ui-widget-refactor 2015-08-03 16:18:15 +02:00
Julian Eisel
ae50da6ea6 Cleanup: Naming, get rid of a XXX 2015-08-03 16:17:02 +02:00
Julian Eisel
73310f25fe Add widget type for search menu back 2015-08-03 01:02:05 +02:00
Julian Eisel
4db51cf00e Add widget type for preview widget 2015-08-03 00:29:31 +02:00
Julian Eisel
e28f359007 Merge branch 'master' into temp-ui-widget-refactor 2015-08-02 23:58:23 +02:00
Julian Eisel
e022e44af0 Minor Cleanup 2015-08-02 23:57:51 +02:00
Julian Eisel
6cad17291c Merge branch 'master' into temp-ui-widget-refactor 2015-07-31 13:46:37 +02:00
Julian Eisel
b284667681 Merge branch 'master' into temp-ui-widget-refactor 2015-07-25 00:53:16 +02:00
Julian Eisel
f2c6b7cdda Fix search menus being drawn transparent
Reverts rBb22061e98946a. Don't think it's worth using an extra widget type for this.
2015-07-20 13:33:45 +02:00
Julian Eisel
d2fc12d73e Add widget type for separator line 2015-07-20 12:50:57 +02:00
Julian Eisel
50bd598a17 Correct prev commit: Remove unused functions and quiet warning 2015-07-20 12:14:49 +02:00
Julian Eisel
bd46a92deb New widget type for colorband 2015-07-20 12:07:09 +02:00
Julian Eisel
b2e18d25b0 Merge branch 'master' into temp-ui-widget-refactor 2015-07-20 11:11:27 +02:00
Julian Eisel
08b3e9a49c New widget types for HSV circle and cube 2015-07-20 11:09:46 +02:00
Julian Eisel
74eb56fe7e New widget type for vertical HSV slider 2015-07-19 14:39:56 +02:00
Julian Eisel
2b73dff7cf Add and use widget API function for draw callback routine
Had to make some further tweaks to make this work nicely, but everything should work fine.
2015-07-18 16:39:01 +02:00
Julian Eisel
eba5bd3340 Merge branch 'master' into temp-ui-widget-refactor 2015-07-18 10:00:09 +02:00
Julian Eisel
b22061e989 Remove redundant draw call 2015-07-18 09:59:11 +02:00
Julian Eisel
5d021e3331 Fix uninitialized usage of uiWidgetDrawBase 2015-07-18 09:56:49 +02:00
Julian Eisel
b947998a51 New widget types for drawing scrollbars using widget pipeline
Had to add UI_WTYPE_SCROLL_BACK and UI_WTYPE_SCROLL_INNER since they need different rectangles, drawing and states. Also renamed UI_WTYPE_SCROLL to UI_WTYPE_LISTSCROLL as it's only used for lists.
2015-07-17 02:48:25 +02:00
Julian Eisel
2a325a0eb9 Cleanup: Naming, comments, redundant defines, ... 2015-07-17 00:50:00 +02:00
Julian Eisel
94adf2cc5f Cleanup: Move widget_type function to widgets.c and widget type enum to widget.h
And suddenly, things are soooo much nicer ;)
2015-07-16 23:22:48 +02:00
Julian Eisel
80af1f10fc Merge branch 'master' into temp-ui-widget-refactor 2015-07-16 21:55:59 +02:00
Julian Eisel
56c6bd646a New widget type for preview menu items
Also to avoid special draw calls.

Note: This adds iconid and str args to uiWidgetDrawType->text callback, which is currently only needed for preview menu items (could also be done differently), but in future this might be handy to get rid of uiBut usage on this level.
2015-07-16 21:44:42 +02:00
Julian Eisel
85eb2ea3bb Avoid special drawing calls for labels within menus by adding a widget type for them 2015-07-16 19:50:21 +02:00
Julian Eisel
f45c2a9cb5 Aaaand finally: Use new pipeline for text drawing as well 2015-07-16 19:09:51 +02:00
Julian Eisel
a3a56d9aaf Time to use new pipeline for widget states
Still don't really like having this on low draw level, think a better solution would be to handle this via flags and update widgets based on these flags before drawing, but old logic is pretty confusing and spaghettiish here, so would prefer to rework states from scratch at some point.
2015-07-16 03:43:59 +02:00
Julian Eisel
03bfc42f74 Merge branch 'master' into temp-ui-widget-refactor 2015-07-16 01:20:35 +02:00
Julian Eisel
e50904f9c9 Merge branch 'master' into temp-ui-widget-refactor 2015-07-14 21:09:26 +02:00
Julian Eisel
0e06f4c491 Fix weirdly appearing and disappearing compile error 2015-07-14 21:06:59 +02:00
Julian Eisel
52ce543f4d Merge branch 'master' into temp-ui-widget-refactor 2015-07-14 02:11:52 +02:00
Julian Eisel
0a202fdfce Get rid of uiWidgetType drawing callbacks (which are now used on a lower level) 2015-07-14 02:07:45 +02:00
Julian Eisel
d032de3bae Let's not use default callbacks for uiWidgetType->draw 2015-07-14 01:49:08 +02:00
Julian Eisel
29166b3ae3 Fix drawing glitch with menu items 2015-07-13 23:45:00 +02:00
Julian Eisel
d6c93298b5 Use new pipeline for link line drawing as well 2015-07-13 23:31:33 +02:00
Julian Eisel
9ebe875dcc Porting second half of widgets to new drawing pipeline 2015-07-10 03:31:22 +02:00
Julian Eisel
58c50e786a Merge branch 'master' into temp-ui-widget-refactor 2015-07-10 01:10:03 +02:00
Julian Eisel
0d3a3347f0 Port first half of the widgets to new pipeline (drawing only)
Also lots of structuring and cleanup.

Tested each button individually, seems everything is fine (menu items are doing weird things though, didn't investigate yet).
2015-07-09 04:19:41 +02:00
Julian Eisel
db5e89ad5c Initial refactor of interface widget architecture
Initial refactor of interface widget architecture towards the following goals:
* Widget Draw Styles (see T45025 - heavily overlaps with this)
* Isolating widget code to make it more future proof
* Adding callback based widgets handling module (currently handled in interface_handler.c)

Adds the following folders/files:
interface/widgets/
interface/widgets/widgets.c
interface/widgets/widgets.h
interface/widgets/widgets_draw/
interface/widgets/widgets_draw/drawstyle_classic.c
interface/widgets/widgets_draw/widgets_draw.c
interface/widgets/widgets_draw/widgets_draw_intern.h

Not sure if editors/interface/ is the right place for this, but depends on some further decisions.
2015-07-09 01:13:22 +02:00
11 changed files with 4091 additions and 3128 deletions

View File

@@ -19,6 +19,8 @@
# ***** END GPL LICENSE BLOCK ***** # ***** END GPL LICENSE BLOCK *****
set(INC set(INC
widgets
widgets/widgets_draw
../include ../include
../../blenfont ../../blenfont
../../blenkernel ../../blenkernel
@@ -55,8 +57,14 @@ set(SRC
resources.c resources.c
view2d.c view2d.c
view2d_ops.c view2d_ops.c
widgets/widgets.c
widgets/widgets_draw/drawstyle_classic.c
widgets/widgets_draw/widgets_draw.c
widgets/widgets_draw/widgets_draw_text.c
interface_intern.h interface_intern.h
widgets/widgets.h
widgets/widgets_draw/widgets_draw_intern.h
) )
if(WITH_INTERNATIONAL) if(WITH_INTERNATIONAL)

View File

@@ -1384,7 +1384,7 @@ void UI_block_draw(const bContext *C, uiBlock *block)
/* XXX: figure out why invalid coordinates happen when closing render window */ /* XXX: figure out why invalid coordinates happen when closing render window */
/* and material preview is redrawn in main window (temp fix for bug #23848) */ /* and material preview is redrawn in main window (temp fix for bug #23848) */
if (rect.xmin < rect.xmax && rect.ymin < rect.ymax) if (rect.xmin < rect.xmax && rect.ymin < rect.ymax)
ui_draw_but(C, ar, &style, but, &rect); ui_draw_but(ar, &style, but, &rect);
} }
} }

View File

@@ -953,266 +953,6 @@ void ui_draw_but_VECTORSCOPE(ARegion *ar, uiBut *but, uiWidgetColors *UNUSED(wco
glDisable(GL_BLEND); glDisable(GL_BLEND);
} }
static void ui_draw_colorband_handle_tri_hlight(float x1, float y1, float halfwidth, float height)
{
float v[2];
glEnable(GL_LINE_SMOOTH);
glBegin(GL_LINE_STRIP);
copy_v2_fl2(v, x1 + halfwidth, y1);
glVertex2fv(v);
copy_v2_fl2(v, x1, y1 + height);
glVertex2fv(v);
copy_v2_fl2(v, x1 - halfwidth, y1);
glVertex2fv(v);
glEnd();
glDisable(GL_LINE_SMOOTH);
}
static void ui_draw_colorband_handle_tri(float x1, float y1, float halfwidth, float height, bool fill)
{
float v[2];
if (fill) {
glPolygonMode(GL_FRONT, GL_FILL);
glEnable(GL_POLYGON_SMOOTH);
}
else {
glPolygonMode(GL_FRONT, GL_LINE);
glEnable(GL_LINE_SMOOTH);
}
glBegin(GL_TRIANGLES);
copy_v2_fl2(v, x1 + halfwidth, y1);
glVertex2fv(v);
copy_v2_fl2(v, x1, y1 + height);
glVertex2fv(v);
copy_v2_fl2(v, x1 - halfwidth, y1);
glVertex2fv(v);
glEnd();
if (fill) {
glDisable(GL_POLYGON_SMOOTH);
}
else {
glDisable(GL_LINE_SMOOTH);
glPolygonMode(GL_FRONT, GL_FILL);
}
}
static void ui_draw_colorband_handle_box(float x1, float y1, float x2, float y2, bool fill)
{
float v[2];
if (fill) {
glPolygonMode(GL_FRONT, GL_FILL);
}
else {
glPolygonMode(GL_FRONT, GL_LINE);
}
glBegin(GL_QUADS);
copy_v2_fl2(v, x1, y1);
glVertex2fv(v);
copy_v2_fl2(v, x1, y2);
glVertex2fv(v);
copy_v2_fl2(v, x2, y2);
glVertex2fv(v);
copy_v2_fl2(v, x2, y1);
glVertex2fv(v);
glEnd();
if (!fill) {
glPolygonMode(GL_FRONT, GL_FILL);
}
}
static void ui_draw_colorband_handle(
const rcti *rect, float x,
const float rgb[3], struct ColorManagedDisplay *display,
bool active)
{
const float sizey = BLI_rcti_size_y(rect);
const float min_width = 3.0f;
float half_width, height, y1, y2;
float colf[3] = {UNPACK3(rgb)};
half_width = floorf(sizey / 3.5f);
height = half_width * 1.4f;
y1 = rect->ymin + (sizey * 0.16f);
y2 = rect->ymax;
/* align to pixels */
x = floorf(x + 0.5f);
y1 = floorf(y1 + 0.5f);
if (active || half_width < min_width) {
glBegin(GL_LINES);
glColor3ub(0, 0, 0);
glVertex2f(x, y1);
glVertex2f(x, y2);
glEnd();
setlinestyle(active ? 2 : 1);
glBegin(GL_LINES);
glColor3ub(200, 200, 200);
glVertex2f(x, y1);
glVertex2f(x, y2);
glEnd();
setlinestyle(0);
/* hide handles when zoomed out too far */
if (half_width < min_width) {
return;
}
}
/* shift handle down */
y1 = y1 - half_width;
glColor3ub(0, 0, 0);
ui_draw_colorband_handle_box(x - half_width, y1 - 1, x + half_width, y1 + height, false);
/* draw all triangles blended */
glEnable(GL_BLEND);
ui_draw_colorband_handle_tri(x, y1 + height, half_width, half_width, true);
if (active)
glColor3ub(196, 196, 196);
else
glColor3ub(96, 96, 96);
ui_draw_colorband_handle_tri(x, y1 + height, half_width, half_width, true);
if (active)
glColor3ub(255, 255, 255);
else
glColor3ub(128, 128, 128);
ui_draw_colorband_handle_tri_hlight(x, y1 + height - 1, (half_width - 1), (half_width - 1));
glColor3ub(0, 0, 0);
ui_draw_colorband_handle_tri_hlight(x, y1 + height, half_width, half_width);
glDisable(GL_BLEND);
glColor3ub(128, 128, 128);
ui_draw_colorband_handle_box(x - (half_width - 1), y1, x + (half_width - 1), y1 + height, true);
if (display) {
IMB_colormanagement_scene_linear_to_display_v3(colf, display);
}
glColor3fv(colf);
ui_draw_colorband_handle_box(x - (half_width - 2), y1 + 1, x + (half_width - 2), y1 + height - 2, true);
}
void ui_draw_but_COLORBAND(uiBut *but, uiWidgetColors *UNUSED(wcol), const rcti *rect)
{
ColorBand *coba;
CBData *cbd;
float x1, y1, sizex, sizey, sizey_solid;
float v1[2], v2[2];
int a;
float pos, colf[4] = {0, 0, 0, 0}; /* initialize in case the colorband isn't valid */
struct ColorManagedDisplay *display = NULL;
coba = (ColorBand *)(but->editcoba ? but->editcoba : but->poin);
if (coba == NULL) return;
if (but->block->color_profile)
display = ui_block_cm_display_get(but->block);
x1 = rect->xmin;
sizex = rect->xmax - x1;
sizey = BLI_rcti_size_y(rect);
sizey_solid = sizey / 4;
y1 = rect->ymin;
/* layer: background, to show tranparency */
glColor4ub(UI_ALPHA_CHECKER_DARK, UI_ALPHA_CHECKER_DARK, UI_ALPHA_CHECKER_DARK, 255);
glRectf(x1, y1, x1 + sizex, rect->ymax);
glEnable(GL_POLYGON_STIPPLE);
glColor4ub(UI_ALPHA_CHECKER_LIGHT, UI_ALPHA_CHECKER_LIGHT, UI_ALPHA_CHECKER_LIGHT, 255);
glPolygonStipple(stipple_checker_8px);
glRectf(x1, y1, x1 + sizex, rect->ymax);
glDisable(GL_POLYGON_STIPPLE);
/* layer: color ramp */
glShadeModel(GL_FLAT);
glEnable(GL_BLEND);
cbd = coba->data;
v1[1] = y1 + sizey_solid;
v2[1] = rect->ymax;
glBegin(GL_TRIANGLE_STRIP);
for (a = 0; a <= sizex; a++) {
pos = ((float)a) / sizex;
do_colorband(coba, pos, colf);
if (display)
IMB_colormanagement_scene_linear_to_display_v3(colf, display);
v1[0] = v2[0] = x1 + a;
glColor4fv(colf);
glVertex2fv(v1);
glVertex2fv(v2);
}
glEnd();
/* layer: color ramp without alpha for reference when manipulating ramp properties */
v1[1] = y1;
v2[1] = y1 + sizey_solid;
glBegin(GL_TRIANGLE_STRIP);
for (a = 0; a <= sizex; a++) {
pos = ((float)a) / sizex;
do_colorband(coba, pos, colf);
if (display)
IMB_colormanagement_scene_linear_to_display_v3(colf, display);
v1[0] = v2[0] = x1 + a;
glColor4f(colf[0], colf[1], colf[2], 1.0f);
glVertex2fv(v1);
glVertex2fv(v2);
}
glEnd();
glDisable(GL_BLEND);
glShadeModel(GL_SMOOTH);
/* layer: box outline */
glColor4f(0.0, 0.0, 0.0, 1.0);
fdrawbox(x1, y1, x1 + sizex, rect->ymax);
/* layer: box outline */
glEnable(GL_BLEND);
glColor4f(0.0f, 0.0f, 0.0f, 0.5f);
fdrawline(x1, y1, x1 + sizex, y1);
glColor4f(1.0f, 1.0f, 1.0f, 0.25f);
fdrawline(x1, y1 - 1, x1 + sizex, y1 - 1);
glDisable(GL_BLEND);
/* layer: draw handles */
for (a = 0; a < coba->tot; a++, cbd++) {
if (a != coba->cur) {
pos = x1 + cbd->pos * (sizex - 1) + 1;
ui_draw_colorband_handle(rect, pos, &cbd->r, display, false);
}
}
/* layer: active handle */
if (coba->tot != 0) {
cbd = &coba->data[coba->cur];
pos = x1 + cbd->pos * (sizex - 1) + 1;
ui_draw_colorband_handle(rect, pos, &cbd->r, display, true);
}
}
void ui_draw_but_UNITVEC(uiBut *but, uiWidgetColors *wcol, const rcti *rect) void ui_draw_but_UNITVEC(uiBut *but, uiWidgetColors *wcol, const rcti *rect)
{ {
static GLuint displist = 0; static GLuint displist = 0;

View File

@@ -57,50 +57,6 @@ struct ImBuf;
#define RNA_NO_INDEX -1 #define RNA_NO_INDEX -1
#define RNA_ENUM_VALUE -2 #define RNA_ENUM_VALUE -2
/* visual types for drawing */
/* for time being separated from functional types */
typedef enum {
/* default */
UI_WTYPE_REGULAR,
/* standard set */
UI_WTYPE_LABEL,
UI_WTYPE_TOGGLE,
UI_WTYPE_CHECKBOX,
UI_WTYPE_RADIO,
UI_WTYPE_NUMBER,
UI_WTYPE_SLIDER,
UI_WTYPE_EXEC,
UI_WTYPE_TOOLTIP,
/* strings */
UI_WTYPE_NAME,
UI_WTYPE_NAME_LINK,
UI_WTYPE_POINTER_LINK,
UI_WTYPE_FILENAME,
/* menus */
UI_WTYPE_MENU_RADIO,
UI_WTYPE_MENU_ICON_RADIO,
UI_WTYPE_MENU_POINTER_LINK,
UI_WTYPE_MENU_NODE_LINK,
UI_WTYPE_PULLDOWN,
UI_WTYPE_MENU_ITEM,
UI_WTYPE_MENU_ITEM_RADIAL,
UI_WTYPE_MENU_BACK,
/* specials */
UI_WTYPE_ICON,
UI_WTYPE_SWATCH,
UI_WTYPE_RGB_PICKER,
UI_WTYPE_UNITVEC,
UI_WTYPE_BOX,
UI_WTYPE_SCROLL,
UI_WTYPE_LISTITEM,
UI_WTYPE_PROGRESSBAR,
} uiWidgetTypeEnum;
/* menu scrolling */ /* menu scrolling */
#define UI_MENU_SCROLL_ARROW 12 #define UI_MENU_SCROLL_ARROW 12
#define UI_MENU_SCROLL_MOUSE (UI_MENU_SCROLL_ARROW + 2) #define UI_MENU_SCROLL_MOUSE (UI_MENU_SCROLL_ARROW + 2)
@@ -619,7 +575,6 @@ void ui_draw_gradient(const rcti *rect, const float hsv[3], const int type, cons
void ui_draw_but_HISTOGRAM(ARegion *ar, uiBut *but, struct uiWidgetColors *wcol, const rcti *rect); void ui_draw_but_HISTOGRAM(ARegion *ar, uiBut *but, struct uiWidgetColors *wcol, const rcti *rect);
void ui_draw_but_WAVEFORM(ARegion *ar, uiBut *but, struct uiWidgetColors *wcol, const rcti *rect); void ui_draw_but_WAVEFORM(ARegion *ar, uiBut *but, struct uiWidgetColors *wcol, const rcti *rect);
void ui_draw_but_VECTORSCOPE(ARegion *ar, uiBut *but, struct uiWidgetColors *wcol, const rcti *rect); void ui_draw_but_VECTORSCOPE(ARegion *ar, uiBut *but, struct uiWidgetColors *wcol, const rcti *rect);
void ui_draw_but_COLORBAND(uiBut *but, struct uiWidgetColors *wcol, const rcti *rect);
void ui_draw_but_UNITVEC(uiBut *but, struct uiWidgetColors *wcol, const rcti *rect); void ui_draw_but_UNITVEC(uiBut *but, struct uiWidgetColors *wcol, const rcti *rect);
void ui_draw_but_CURVE(ARegion *ar, uiBut *but, struct uiWidgetColors *wcol, const rcti *rect); void ui_draw_but_CURVE(ARegion *ar, uiBut *but, struct uiWidgetColors *wcol, const rcti *rect);
void ui_draw_but_IMAGE(ARegion *ar, uiBut *but, struct uiWidgetColors *wcol, const rcti *rect); void ui_draw_but_IMAGE(ARegion *ar, uiBut *but, struct uiWidgetColors *wcol, const rcti *rect);
@@ -666,7 +621,7 @@ void ui_draw_search_back(struct uiStyle *style, uiBlock *block, rcti *rect);
bool ui_link_bezier_points(const rcti *rect, float coord_array[][2], int resol); bool ui_link_bezier_points(const rcti *rect, float coord_array[][2], int resol);
void ui_draw_link_bezier(const rcti *rect); void ui_draw_link_bezier(const rcti *rect);
extern void ui_draw_but(const struct bContext *C, ARegion *ar, struct uiStyle *style, uiBut *but, rcti *rect); extern void ui_draw_but(ARegion *ar, struct uiStyle *style, uiBut *but, rcti *rect);
/* theme color init */ /* theme color init */
struct ThemeUI; struct ThemeUI;
void ui_widget_color_init(struct ThemeUI *tui); void ui_widget_color_init(struct ThemeUI *tui);

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,295 @@
/*
* ***** BEGIN GPL 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.
*
* 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* Contributor(s): none yet.
*
* ***** END GPL LICENSE BLOCK *****
*/
/** \file blender/editors/interface/widgets/widgets.c
* \ingroup edinterface
*/
#include "BIF_gl.h"
#include "BLI_utildefines.h"
#include "DNA_screen_types.h"
#include "UI_interface.h"
#include "UI_resources.h"
#include "widgets.h" /* own include */
uiWidgetDrawStyle *widget_drawstyle_get(const short drawstyle_type) /* TODO widget draw styles are for later */
{
#if 0
switch (widget_style_type) {
case WIDGETSTYLE_TYPE_CLASSIC:
return &WidgetStyle_Classic;
break;
default:
BLI_assert(0);
}
return NULL;
#else
return &WidgetStyle_Classic;
(void)drawstyle_type;
#endif
}
uiWidgetType *WidgetTypeInit(const uiWidgetTypeEnum type)
{
bTheme *btheme = UI_GetTheme();
const uiWidgetDrawStyle *draw_style = widget_drawstyle_get(0); /* TODO drawstyles aren't in use yet */
static uiWidgetType wt;
/* defaults */
wt.wcol_theme = &btheme->tui.wcol_regular;
wt.wcol_state = &btheme->tui.wcol_state;
wt.draw_type = NULL;
switch (type) {
/* let's keep this in a nice alphabetical order! */
case UI_WTYPE_BOX:
wt.wcol_theme = &btheme->tui.wcol_box;
wt.draw_type = draw_style->box;
break;
case UI_WTYPE_CHECKBOX:
wt.wcol_theme = &btheme->tui.wcol_option;
wt.draw_type = draw_style->checkbox;
break;
case UI_WTYPE_COLORBAND:
wt.draw_type = draw_style->colorband;
break;
case UI_WTYPE_EXEC:
wt.wcol_theme = &btheme->tui.wcol_tool;
wt.draw_type = draw_style->exec;
break;
case UI_WTYPE_EXTRA:
wt.draw_type = draw_style->extra_mask;
break;
case UI_WTYPE_FILENAME:
break;
case UI_WTYPE_HSV_CIRCLE:
wt.draw_type = draw_style->hsv_circle;
break;
case UI_WTYPE_HSV_CUBE:
wt.draw_type = draw_style->hsv_cube;
break;
case UI_WTYPE_HSV_VERT:
wt.draw_type = draw_style->hsv_vert;
break;
case UI_WTYPE_ICON:
wt.draw_type = draw_style->icon;
break;
case UI_WTYPE_LABEL:
wt.draw_type = draw_style->label;
break;
case UI_WTYPE_LINK:
wt.draw_type = draw_style->link;
break;
case UI_WTYPE_LISTITEM:
wt.wcol_theme = &btheme->tui.wcol_list_item;
wt.draw_type = draw_style->listitem;
break;
case UI_WTYPE_LISTSCROLL:
wt.wcol_theme = &btheme->tui.wcol_scroll;
wt.draw_type = draw_style->listscroll;
break;
case UI_WTYPE_MENU_BACK:
wt.wcol_theme = &btheme->tui.wcol_menu_back;
wt.draw_type = draw_style->menu_back;
break;
case UI_WTYPE_MENU_ICON_RADIO:
wt.wcol_theme = &btheme->tui.wcol_menu;
wt.draw_type = draw_style->menu_icon_radio;
break;
case UI_WTYPE_MENU_ITEM:
wt.wcol_theme = &btheme->tui.wcol_menu_item;
wt.draw_type = draw_style->menu_item;
break;
case UI_WTYPE_MENU_ITEM_PREVIEW:
wt.wcol_theme = &btheme->tui.wcol_menu_item;
wt.draw_type = draw_style->menu_item_preview;
break;
case UI_WTYPE_MENU_ITEM_RADIAL:
wt.wcol_theme = &btheme->tui.wcol_pie_menu;
wt.draw_type = draw_style->menu_item_radial;
break;
case UI_WTYPE_MENU_LABEL:
wt.wcol_theme = &btheme->tui.wcol_menu_back;
wt.draw_type = draw_style->menu_label;
break;
case UI_WTYPE_MENU_NODE_LINK:
wt.wcol_theme = &btheme->tui.wcol_menu;
wt.draw_type = draw_style->menu_node_link;
break;
case UI_WTYPE_MENU_POINTER_LINK:
wt.wcol_theme = &btheme->tui.wcol_menu;
wt.draw_type = draw_style->pointer_link;
break;
case UI_WTYPE_MENU_RADIO:
wt.wcol_theme = &btheme->tui.wcol_menu;
wt.draw_type = draw_style->menu_radio;
break;
case UI_WTYPE_NAME:
wt.wcol_theme = &btheme->tui.wcol_text;
wt.draw_type = draw_style->name;
break;
case UI_WTYPE_NAME_LINK:
break;
case UI_WTYPE_NUMBER:
wt.wcol_theme = &btheme->tui.wcol_num;
wt.draw_type = draw_style->number;
break;
case UI_WTYPE_POINTER_LINK:
break;
case UI_WTYPE_PROGRESSBAR:
wt.wcol_theme = &btheme->tui.wcol_progress;
wt.draw_type = draw_style->progressbar;
break;
case UI_WTYPE_PULLDOWN:
wt.wcol_theme = &btheme->tui.wcol_pulldown;
wt.draw_type = draw_style->pulldown;
break;
case UI_WTYPE_RADIO:
wt.wcol_theme = &btheme->tui.wcol_radio;
wt.draw_type = draw_style->radio;
break;
case UI_WTYPE_REGULAR:
wt.draw_type = draw_style->regular;
break;
case UI_WTYPE_RGB_PICKER:
break;
case UI_WTYPE_SCROLL_BACK:
wt.draw_type = draw_style->scroll_back;
break;
case UI_WTYPE_SCROLL_INNER:
wt.draw_type = draw_style->scroll_inner;
break;
case UI_WTYPE_SEARCH_BACK:
wt.wcol_theme = &btheme->tui.wcol_box;
wt.draw_type = draw_style->search_back;
break;
case UI_WTYPE_SEPARATOR:
wt.wcol_theme = &btheme->tui.wcol_menu_item;
wt.draw_type = draw_style->separator;
break;
case UI_WTYPE_SLIDER:
wt.wcol_theme = &btheme->tui.wcol_numslider;
wt.draw_type = draw_style->slider;
break;
case UI_WTYPE_SWATCH:
wt.draw_type = draw_style->swatch;
break;
case UI_WTYPE_TOGGLE:
wt.wcol_theme = &btheme->tui.wcol_toggle;
wt.draw_type = draw_style->toggle;
break;
case UI_WTYPE_TOOLTIP:
wt.wcol_theme = &btheme->tui.wcol_tooltip;
wt.draw_type = draw_style->tooltip;
break;
case UI_WTYPE_UNITVEC:
wt.draw_type = draw_style->unitvec;
break;
}
return &wt;
}
/**
* \brief Widget main draw routine
*
* passing NULL for \a but disables draw_type->custom and draw_type->text,
* passing NULl for \a fstyle or \a str disables draw_type->text
*/
void WidgetDraw(
uiWidgetType *wt,
uiFontStyle *fstyle, uiBut *but, rcti *rect,
int state, int roundboxalign, const int iconid, const char *str,
const bool use_text_blend)
{
uiWidgetDrawType *dtype = wt->draw_type;
if (dtype->state) {
dtype->state(wt, state);
}
if (dtype->custom && but) {
dtype->custom(but, &wt->wcol, rect, state, roundboxalign);
}
else if (dtype->draw) {
dtype->draw(&wt->wcol, rect, state, roundboxalign);
}
if (dtype->text && but && fstyle && str) {
if (use_text_blend) {
glEnable(GL_BLEND);
}
dtype->text(fstyle, &wt->wcol, but, rect, str, iconid);
if (use_text_blend) {
glDisable(GL_BLEND);
}
}
}

View File

@@ -0,0 +1,181 @@
/*
* ***** BEGIN GPL 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.
*
* 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* Contributor(s): none yet.
*
* ***** END GPL LICENSE BLOCK *****
*/
#ifndef __WIDGETS_H__
#define __WIDGETS_H__
/** \file blender/editors/interface/widgets/widgets.h
* \ingroup edinterface
*
* \brief Blender widget API and internal functions
*
* Seems a bit overkill do have such an isolated module just for widget drawing but plan is to
* use this for widget handling as well and basically make it a standalone blenwidget module
*/
#include "DNA_userdef_types.h"
struct uiBut;
struct uiWidgetType;
typedef enum {
/* default */
UI_WTYPE_REGULAR,
/* standard set */
UI_WTYPE_LABEL,
UI_WTYPE_TOGGLE,
UI_WTYPE_CHECKBOX,
UI_WTYPE_RADIO,
UI_WTYPE_NUMBER,
UI_WTYPE_SLIDER,
UI_WTYPE_EXEC,
UI_WTYPE_TOOLTIP,
/* strings */
UI_WTYPE_NAME,
UI_WTYPE_NAME_LINK,
UI_WTYPE_POINTER_LINK,
UI_WTYPE_FILENAME,
/* menus */
UI_WTYPE_MENU_RADIO,
UI_WTYPE_MENU_ICON_RADIO,
UI_WTYPE_MENU_POINTER_LINK,
UI_WTYPE_MENU_NODE_LINK,
UI_WTYPE_PULLDOWN,
UI_WTYPE_MENU_LABEL,
UI_WTYPE_MENU_ITEM,
UI_WTYPE_MENU_ITEM_PREVIEW,
UI_WTYPE_MENU_ITEM_RADIAL,
UI_WTYPE_MENU_BACK,
UI_WTYPE_SEARCH_BACK,
/* specials */
UI_WTYPE_ICON,
UI_WTYPE_EXTRA,
UI_WTYPE_SWATCH,
UI_WTYPE_RGB_PICKER,
UI_WTYPE_UNITVEC,
UI_WTYPE_COLORBAND,
UI_WTYPE_HSV_CIRCLE,
UI_WTYPE_HSV_CUBE,
UI_WTYPE_HSV_VERT,
UI_WTYPE_BOX,
UI_WTYPE_SCROLL_BACK,
UI_WTYPE_SCROLL_INNER,
UI_WTYPE_LISTSCROLL, /* scroll widget within lists */
UI_WTYPE_LISTITEM,
UI_WTYPE_PROGRESSBAR,
UI_WTYPE_LINK,
UI_WTYPE_SEPARATOR,
} uiWidgetTypeEnum;
/** uiWidgetType: for time being only for visual appearance,
* later, a handling callback can be added too
*/
typedef struct uiWidgetType {
/* pointer to theme color definition */
uiWidgetColors *wcol_theme;
uiWidgetStateColors *wcol_state;
/* converted colors for state */
uiWidgetColors wcol;
struct uiWidgetDrawType *draw_type;
} uiWidgetType;
typedef struct uiWidgetDrawType {
void (*state)(struct uiWidgetType *, int state);
void (*draw)(struct uiWidgetColors *, rcti *, int state, int roundboxalign);
/* XXX uiBut and uiFontStyle shouldn't be needed/used at this level,
* the needed data should be transferred using uiWidget API instead */
void (*custom)(struct uiBut *, struct uiWidgetColors *, rcti *, int state, int roundboxalign);
void (*text)(struct uiFontStyle *, struct uiWidgetColors *, struct uiBut *, rcti *, const char *str, const int iconid);
} uiWidgetDrawType;
typedef struct uiWidgetDrawStyle {
/* let's keep this in a nice alphabetical order! */
uiWidgetDrawType *box,
*checkbox,
*colorband,
*exec,
*extra_mask,
*filename,
*hsv_circle,
*hsv_cube,
*hsv_vert,
*icon,
*label,
*link,
*listitem,
*listscroll,
*menu_back,
*menu_icon_radio,
*menu_item,
*menu_item_preview,
*menu_item_radial,
*menu_label,
*menu_node_link,
*menu_pointer_link,
*menu_radio,
*name,
*name_link,
*number,
*pointer_link,
*progressbar,
*pulldown,
*radio,
*regular,
*rgb_picker,
*scroll_back,
*scroll_inner,
*search_back,
*separator,
*slider,
*swatch,
*toggle,
*tooltip,
*unitvec;
} uiWidgetDrawStyle;
/* *** external API *** */
uiWidgetType *WidgetTypeInit(const uiWidgetTypeEnum type);
void WidgetDraw(
uiWidgetType *wt,
uiFontStyle *fstyle, uiBut *but, rcti *rect,
int state, int roundboxalign, const int iconid, const char *str,
const bool use_text_blend);
/* *** internal *** */
uiWidgetDrawStyle *widget_drawstyle_get(const short drawstyle_type);
/* draw-styles */
extern struct uiWidgetDrawStyle WidgetStyle_Classic;
#endif /* __WIDGETS_H__ */

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,879 @@
/*
* ***** BEGIN GPL 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.
*
* 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* Contributor(s): none yet.
*
* ***** END GPL LICENSE BLOCK *****
*/
/** \file blender/editors/interface/widgets/widgets_draw/widgets_draw.c
* \ingroup edinterface
*
* \brief Shared low-level widget drawing functions
*/
#include "BIF_gl.h"
#include "BIF_glutil.h"
#include "BLI_math.h"
#include "BLI_rect.h"
#include "IMB_colormanagement.h"
#include "DNA_userdef_types.h"
#include "DNA_screen_types.h"
#include "UI_interface.h"
#include "UI_resources.h"
#include "widgets_draw_intern.h" /* own include */
/* draw defines ************************************ */
static const float cornervec[WIDGET_CURVE_RESOLU][2] = {
{0.0, 0.0}, {0.195, 0.02}, {0.383, 0.067},
{0.55, 0.169}, {0.707, 0.293}, {0.831, 0.45},
{0.924, 0.617}, {0.98, 0.805}, {1.0, 1.0}
};
#define WIDGET_AA_JITTER 8
static const float jit[WIDGET_AA_JITTER][2] = {
{ 0.468813, -0.481430}, {-0.155755, -0.352820},
{ 0.219306, -0.238501}, {-0.393286, -0.110949},
{-0.024699, 0.013908}, { 0.343805, 0.147431},
{-0.272855, 0.269918}, { 0.095909, 0.388710}
};
static const float num_tria_vert[3][2] = {
{-0.352077, 0.532607}, {-0.352077, -0.549313}, {0.330000, -0.008353}
};
static const unsigned int num_tria_face[1][3] = {
{0, 1, 2}
};
static const float check_tria_vert[6][2] = {
{-0.578579, 0.253369}, {-0.392773, 0.412794}, {-0.004241, -0.328551},
{-0.003001, 0.034320}, {1.055313, 0.864744}, {0.866408, 1.026895}
};
static const unsigned int check_tria_face[4][3] = {
{3, 2, 4}, {3, 4, 5}, {1, 0, 3}, {0, 2, 3}
};
static const float menu_tria_vert[6][2] = {
{-0.33, 0.16}, {0.33, 0.16}, {0, 0.82},
{0, -0.82}, {-0.33, -0.16}, {0.33, -0.16}
};
static const float scroll_circle_vert[16][2] = {
{0.382684, 0.923879}, {0.000001, 1.000000}, {-0.382683, 0.923880}, {-0.707107, 0.707107},
{-0.923879, 0.382684}, {-1.000000, 0.000000}, {-0.923880, -0.382684}, {-0.707107, -0.707107},
{-0.382683, -0.923880}, {0.000000, -1.000000}, {0.382684, -0.923880}, {0.707107, -0.707107},
{0.923880, -0.382684}, {1.000000, -0.000000}, {0.923880, 0.382683}, {0.707107, 0.707107}
};
static const unsigned int scroll_circle_face[14][3] = {
{0, 1, 2}, {2, 0, 3}, {3, 0, 15}, {3, 15, 4}, {4, 15, 14}, {4, 14, 5}, {5, 14, 13}, {5, 13, 6},
{6, 13, 12}, {6, 12, 7}, {7, 12, 11}, {7, 11, 8}, {8, 11, 10}, {8, 10, 9}
};
static const unsigned int menu_tria_face[2][3] = {{2, 0, 1}, {3, 5, 4}};
/* prepare drawing ********************************* */
/* roundbox stuff ************* */
/* this call has 1 extra arg to allow mask outline */
void round_box__edges(uiWidgetDrawBase *wt, int roundboxalign, const rcti *rect, float rad, float radi)
{
float vec[WIDGET_CURVE_RESOLU][2], veci[WIDGET_CURVE_RESOLU][2];
float minx = rect->xmin, miny = rect->ymin, maxx = rect->xmax, maxy = rect->ymax;
float minxi = minx + U.pixelsize; /* boundbox inner */
float maxxi = maxx - U.pixelsize;
float minyi = miny + U.pixelsize;
float maxyi = maxy - U.pixelsize;
float facxi = (maxxi != minxi) ? 1.0f / (maxxi - minxi) : 0.0f; /* for uv, can divide by zero */
float facyi = (maxyi != minyi) ? 1.0f / (maxyi - minyi) : 0.0f;
int a, tot = 0, minsize;
const int hnum = ((roundboxalign & (UI_CNR_TOP_LEFT | UI_CNR_TOP_RIGHT)) == (UI_CNR_TOP_LEFT | UI_CNR_TOP_RIGHT) ||
(roundboxalign & (UI_CNR_BOTTOM_RIGHT | UI_CNR_BOTTOM_LEFT)) == (UI_CNR_BOTTOM_RIGHT | UI_CNR_BOTTOM_LEFT)) ? 1 : 2;
const int vnum = ((roundboxalign & (UI_CNR_TOP_LEFT | UI_CNR_BOTTOM_LEFT)) == (UI_CNR_TOP_LEFT | UI_CNR_BOTTOM_LEFT) ||
(roundboxalign & (UI_CNR_TOP_RIGHT | UI_CNR_BOTTOM_RIGHT)) == (UI_CNR_TOP_RIGHT | UI_CNR_BOTTOM_RIGHT)) ? 1 : 2;
minsize = min_ii(BLI_rcti_size_x(rect) * hnum,
BLI_rcti_size_y(rect) * vnum);
if (2.0f * rad > minsize)
rad = 0.5f * minsize;
if (2.0f * (radi + 1.0f) > minsize)
radi = 0.5f * minsize - U.pixelsize;
/* mult */
for (a = 0; a < WIDGET_CURVE_RESOLU; a++) {
veci[a][0] = radi * cornervec[a][0];
veci[a][1] = radi * cornervec[a][1];
vec[a][0] = rad * cornervec[a][0];
vec[a][1] = rad * cornervec[a][1];
}
/* corner left-bottom */
if (roundboxalign & UI_CNR_BOTTOM_LEFT) {
for (a = 0; a < WIDGET_CURVE_RESOLU; a++, tot++) {
wt->inner_v[tot][0] = minxi + veci[a][1];
wt->inner_v[tot][1] = minyi + radi - veci[a][0];
wt->outer_v[tot][0] = minx + vec[a][1];
wt->outer_v[tot][1] = miny + rad - vec[a][0];
wt->inner_uv[tot][0] = facxi * (wt->inner_v[tot][0] - minxi);
wt->inner_uv[tot][1] = facyi * (wt->inner_v[tot][1] - minyi);
}
}
else {
wt->inner_v[tot][0] = minxi;
wt->inner_v[tot][1] = minyi;
wt->outer_v[tot][0] = minx;
wt->outer_v[tot][1] = miny;
wt->inner_uv[tot][0] = 0.0f;
wt->inner_uv[tot][1] = 0.0f;
tot++;
}
/* corner right-bottom */
if (roundboxalign & UI_CNR_BOTTOM_RIGHT) {
for (a = 0; a < WIDGET_CURVE_RESOLU; a++, tot++) {
wt->inner_v[tot][0] = maxxi - radi + veci[a][0];
wt->inner_v[tot][1] = minyi + veci[a][1];
wt->outer_v[tot][0] = maxx - rad + vec[a][0];
wt->outer_v[tot][1] = miny + vec[a][1];
wt->inner_uv[tot][0] = facxi * (wt->inner_v[tot][0] - minxi);
wt->inner_uv[tot][1] = facyi * (wt->inner_v[tot][1] - minyi);
}
}
else {
wt->inner_v[tot][0] = maxxi;
wt->inner_v[tot][1] = minyi;
wt->outer_v[tot][0] = maxx;
wt->outer_v[tot][1] = miny;
wt->inner_uv[tot][0] = 1.0f;
wt->inner_uv[tot][1] = 0.0f;
tot++;
}
wt->halfwayvert = tot;
/* corner right-top */
if (roundboxalign & UI_CNR_TOP_RIGHT) {
for (a = 0; a < WIDGET_CURVE_RESOLU; a++, tot++) {
wt->inner_v[tot][0] = maxxi - veci[a][1];
wt->inner_v[tot][1] = maxyi - radi + veci[a][0];
wt->outer_v[tot][0] = maxx - vec[a][1];
wt->outer_v[tot][1] = maxy - rad + vec[a][0];
wt->inner_uv[tot][0] = facxi * (wt->inner_v[tot][0] - minxi);
wt->inner_uv[tot][1] = facyi * (wt->inner_v[tot][1] - minyi);
}
}
else {
wt->inner_v[tot][0] = maxxi;
wt->inner_v[tot][1] = maxyi;
wt->outer_v[tot][0] = maxx;
wt->outer_v[tot][1] = maxy;
wt->inner_uv[tot][0] = 1.0f;
wt->inner_uv[tot][1] = 1.0f;
tot++;
}
/* corner left-top */
if (roundboxalign & UI_CNR_TOP_LEFT) {
for (a = 0; a < WIDGET_CURVE_RESOLU; a++, tot++) {
wt->inner_v[tot][0] = minxi + radi - veci[a][0];
wt->inner_v[tot][1] = maxyi - veci[a][1];
wt->outer_v[tot][0] = minx + rad - vec[a][0];
wt->outer_v[tot][1] = maxy - vec[a][1];
wt->inner_uv[tot][0] = facxi * (wt->inner_v[tot][0] - minxi);
wt->inner_uv[tot][1] = facyi * (wt->inner_v[tot][1] - minyi);
}
}
else {
wt->inner_v[tot][0] = minxi;
wt->inner_v[tot][1] = maxyi;
wt->outer_v[tot][0] = minx;
wt->outer_v[tot][1] = maxy;
wt->inner_uv[tot][0] = 0.0f;
wt->inner_uv[tot][1] = 1.0f;
tot++;
}
BLI_assert(tot <= WIDGET_SIZE_MAX);
wt->totvert = tot;
}
void widget_drawbase_roundboxedges_set(uiWidgetDrawBase *wt, int roundboxalign, const rcti *rect, float rad)
{
round_box__edges(wt, roundboxalign, rect, rad, rad - U.pixelsize);
}
/* prepares shade colors */
static void shadecolors4(char coltop[4], char coldown[4], const char *color, short shadetop, short shadedown)
{
coltop[0] = CLAMPIS(color[0] + shadetop, 0, 255);
coltop[1] = CLAMPIS(color[1] + shadetop, 0, 255);
coltop[2] = CLAMPIS(color[2] + shadetop, 0, 255);
coltop[3] = color[3];
coldown[0] = CLAMPIS(color[0] + shadedown, 0, 255);
coldown[1] = CLAMPIS(color[1] + shadedown, 0, 255);
coldown[2] = CLAMPIS(color[2] + shadedown, 0, 255);
coldown[3] = color[3];
}
static void round_box_shade_col4_r(unsigned char r_col[4], const char col1[4], const char col2[4], const float fac)
{
const int faci = FTOCHAR(fac);
const int facm = 255 - faci;
r_col[0] = (faci * col1[0] + facm * col2[0]) / 256;
r_col[1] = (faci * col1[1] + facm * col2[1]) / 256;
r_col[2] = (faci * col1[2] + facm * col2[2]) / 256;
r_col[3] = (faci * col1[3] + facm * col2[3]) / 256;
}
/* triangle stuff ************* */
static void widget_verts_to_triangle_strip(uiWidgetDrawBase *wtb, const int totvert, float triangle_strip[WIDGET_SIZE_MAX * 2 + 2][2])
{
int a;
for (a = 0; a < totvert; a++) {
copy_v2_v2(triangle_strip[a * 2], wtb->outer_v[a]);
copy_v2_v2(triangle_strip[a * 2 + 1], wtb->inner_v[a]);
}
copy_v2_v2(triangle_strip[a * 2], wtb->outer_v[0]);
copy_v2_v2(triangle_strip[a * 2 + 1], wtb->inner_v[0]);
}
static void widget_verts_to_triangle_strip_open(uiWidgetDrawBase *wtb, const int totvert, float triangle_strip[WIDGET_SIZE_MAX * 2][2])
{
int a;
for (a = 0; a < totvert; a++) {
triangle_strip[a * 2][0] = wtb->outer_v[a][0];
triangle_strip[a * 2][1] = wtb->outer_v[a][1];
triangle_strip[a * 2 + 1][0] = wtb->outer_v[a][0];
triangle_strip[a * 2 + 1][1] = wtb->outer_v[a][1] - 1.0f;
}
}
/* based on button rect, return scaled array of triangles */
static void widget_drawbase_tria_ex(
uiWidgetDrawBaseTrias *tria, const rcti *rect, float triasize, char where,
/* input data */
const float verts[][2], const int verts_tot,
const unsigned int tris[][3], const int tris_tot)
{
float centx, centy, sizex, sizey, minsize;
int a, i1 = 0, i2 = 1;
minsize = min_ii(BLI_rcti_size_x(rect), BLI_rcti_size_y(rect));
/* center position and size */
centx = (float)rect->xmin + 0.4f * minsize;
centy = (float)rect->ymin + 0.5f * minsize;
sizex = sizey = -0.5f * triasize * minsize;
if (where == 'r') {
centx = (float)rect->xmax - 0.4f * minsize;
sizex = -sizex;
}
else if (where == 't') {
centy = (float)rect->ymax - 0.5f * minsize;
sizey = -sizey;
i2 = 0; i1 = 1;
}
else if (where == 'b') {
sizex = -sizex;
i2 = 0; i1 = 1;
}
for (a = 0; a < verts_tot; a++) {
tria->vec[a][0] = sizex * verts[a][i1] + centx;
tria->vec[a][1] = sizey * verts[a][i2] + centy;
}
tria->tot = tris_tot;
tria->index = tris;
}
void widget_drawbase_num_tria(uiWidgetDrawBaseTrias *tria, const rcti *rect, float triasize, char where)
{
widget_drawbase_tria_ex(
tria, rect, triasize, where,
num_tria_vert, ARRAY_SIZE(num_tria_vert),
num_tria_face, ARRAY_SIZE(num_tria_face));
}
void widget_drawbase_menu_trias(uiWidgetDrawBaseTrias *tria, const rcti *rect)
{
float centx, centy, size;
int a;
/* center position and size */
centx = rect->xmax - 0.32f * BLI_rcti_size_y(rect);
centy = rect->ymin + 0.50f * BLI_rcti_size_y(rect);
size = 0.4f * BLI_rcti_size_y(rect);
for (a = 0; a < 6; a++) {
tria->vec[a][0] = size * menu_tria_vert[a][0] + centx;
tria->vec[a][1] = size * menu_tria_vert[a][1] + centy;
}
tria->tot = 2;
tria->index = menu_tria_face;
}
void widget_drawbase_check_trias(uiWidgetDrawBaseTrias *tria, const rcti *rect)
{
float centx, centy, size;
int a;
/* center position and size */
centx = rect->xmin + 0.5f * BLI_rcti_size_y(rect);
centy = rect->ymin + 0.5f * BLI_rcti_size_y(rect);
size = 0.5f * BLI_rcti_size_y(rect);
for (a = 0; a < 6; a++) {
tria->vec[a][0] = size * check_tria_vert[a][0] + centx;
tria->vec[a][1] = size * check_tria_vert[a][1] + centy;
}
tria->tot = 4;
tria->index = check_tria_face;
}
void widget_drawbase_scroll_circle(uiWidgetDrawBaseTrias *tria, const rcti *rect, float triasize, char where)
{
widget_drawbase_tria_ex(
tria, rect, triasize, where,
scroll_circle_vert, ARRAY_SIZE(scroll_circle_vert),
scroll_circle_face, ARRAY_SIZE(scroll_circle_face));
}
/* menu backdrop stuff ******** */
/* helper call, makes shadow rect, with 'sun' above menu, so only shadow to left/right/bottom */
/* return tot */
static int round_box_shadow_edges(float (*vert)[2], const rcti *rect, float rad, int roundboxalign, float step)
{
float vec[WIDGET_CURVE_RESOLU][2];
float minx, miny, maxx, maxy;
int a, tot = 0;
rad += step;
if (2.0f * rad > BLI_rcti_size_y(rect))
rad = 0.5f * BLI_rcti_size_y(rect);
minx = rect->xmin - step;
miny = rect->ymin - step;
maxx = rect->xmax + step;
maxy = rect->ymax + step;
/* mult */
for (a = 0; a < WIDGET_CURVE_RESOLU; a++) {
vec[a][0] = rad * cornervec[a][0];
vec[a][1] = rad * cornervec[a][1];
}
/* start with left-top, anti clockwise */
if (roundboxalign & UI_CNR_TOP_LEFT) {
for (a = 0; a < WIDGET_CURVE_RESOLU; a++, tot++) {
vert[tot][0] = minx + rad - vec[a][0];
vert[tot][1] = maxy - vec[a][1];
}
}
else {
for (a = 0; a < WIDGET_CURVE_RESOLU; a++, tot++) {
vert[tot][0] = minx;
vert[tot][1] = maxy;
}
}
if (roundboxalign & UI_CNR_BOTTOM_LEFT) {
for (a = 0; a < WIDGET_CURVE_RESOLU; a++, tot++) {
vert[tot][0] = minx + vec[a][1];
vert[tot][1] = miny + rad - vec[a][0];
}
}
else {
for (a = 0; a < WIDGET_CURVE_RESOLU; a++, tot++) {
vert[tot][0] = minx;
vert[tot][1] = miny;
}
}
if (roundboxalign & UI_CNR_BOTTOM_RIGHT) {
for (a = 0; a < WIDGET_CURVE_RESOLU; a++, tot++) {
vert[tot][0] = maxx - rad + vec[a][0];
vert[tot][1] = miny + vec[a][1];
}
}
else {
for (a = 0; a < WIDGET_CURVE_RESOLU; a++, tot++) {
vert[tot][0] = maxx;
vert[tot][1] = miny;
}
}
if (roundboxalign & UI_CNR_TOP_RIGHT) {
for (a = 0; a < WIDGET_CURVE_RESOLU; a++, tot++) {
vert[tot][0] = maxx - vec[a][1];
vert[tot][1] = maxy - rad + vec[a][0];
}
}
else {
for (a = 0; a < WIDGET_CURVE_RESOLU; a++, tot++) {
vert[tot][0] = maxx;
vert[tot][1] = maxy;
}
}
return tot;
}
/* actual drawing ********************************** */
/* outside of rect, rad to left/bottom/right */
void widget_drawbase_softshadow(const rcti *rect, int roundboxalign, const float radin)
{
bTheme *btheme = UI_GetTheme();
uiWidgetDrawBase wtb;
rcti rect1 = *rect;
float alphastep;
int step, totvert;
float triangle_strip[WIDGET_SIZE_MAX * 2 + 2][2];
const float radout = UI_ThemeMenuShadowWidth();
/* disabled shadow */
if (radout == 0.0f)
return;
/* prevent tooltips to not show round shadow */
if (radout > 0.2f * BLI_rcti_size_y(&rect1))
rect1.ymax -= 0.2f * BLI_rcti_size_y(&rect1);
else
rect1.ymax -= radout;
/* inner part */
totvert = round_box_shadow_edges(wtb.inner_v, &rect1, radin, roundboxalign & (UI_CNR_BOTTOM_RIGHT | UI_CNR_BOTTOM_LEFT), 0.0f);
/* we draw a number of increasing size alpha quad strips */
alphastep = 3.0f * btheme->tui.menu_shadow_fac / radout;
glEnableClientState(GL_VERTEX_ARRAY);
for (step = 1; step <= (int)radout; step++) {
float expfac = sqrtf(step / radout);
round_box_shadow_edges(wtb.outer_v, &rect1, radin, UI_CNR_ALL, (float)step);
glColor4f(0.0f, 0.0f, 0.0f, alphastep * (1.0f - expfac));
widget_verts_to_triangle_strip(&wtb, totvert, triangle_strip);
glVertexPointer(2, GL_FLOAT, 0, triangle_strip);
glDrawArrays(GL_TRIANGLE_STRIP, 0, totvert * 2); /* add + 2 for getting a complete soft rect. Now it skips top edge to allow transparent menus */
}
glDisableClientState(GL_VERTEX_ARRAY);
}
static void widget_trias_draw(uiWidgetDrawBaseTrias *tria)
{
glEnableClientState(GL_VERTEX_ARRAY);
glVertexPointer(2, GL_FLOAT, 0, tria->vec);
glDrawElements(GL_TRIANGLES, tria->tot * 3, GL_UNSIGNED_INT, tria->index);
glDisableClientState(GL_VERTEX_ARRAY);
}
void widget_drawbase_outline(uiWidgetDrawBase *wtb)
{
float triangle_strip[WIDGET_SIZE_MAX * 2 + 2][2]; /* + 2 because the last pair is wrapped */
widget_verts_to_triangle_strip(wtb, wtb->totvert, triangle_strip);
glEnableClientState(GL_VERTEX_ARRAY);
glVertexPointer(2, GL_FLOAT, 0, triangle_strip);
glDrawArrays(GL_TRIANGLE_STRIP, 0, wtb->totvert * 2 + 2);
glDisableClientState(GL_VERTEX_ARRAY);
}
void widget_drawbase_draw(uiWidgetDrawBase *wtb, uiWidgetColors *wcol)
{
int j, a;
glEnable(GL_BLEND);
/* backdrop non AA */
if (wtb->draw_inner) {
if (wcol->shaded == 0) {
if (wcol->alpha_check) {
float inner_v_half[WIDGET_SIZE_MAX][2];
float x_mid = 0.0f; /* used for dumb clamping of values */
/* dark checkers */
glColor4ub(UI_ALPHA_CHECKER_DARK, UI_ALPHA_CHECKER_DARK, UI_ALPHA_CHECKER_DARK, 255);
glEnableClientState(GL_VERTEX_ARRAY);
glVertexPointer(2, GL_FLOAT, 0, wtb->inner_v);
glDrawArrays(GL_POLYGON, 0, wtb->totvert);
/* light checkers */
glEnable(GL_POLYGON_STIPPLE);
glColor4ub(UI_ALPHA_CHECKER_LIGHT, UI_ALPHA_CHECKER_LIGHT, UI_ALPHA_CHECKER_LIGHT, 255);
glPolygonStipple(stipple_checker_8px);
glVertexPointer(2, GL_FLOAT, 0, wtb->inner_v);
glDrawArrays(GL_POLYGON, 0, wtb->totvert);
glDisable(GL_POLYGON_STIPPLE);
/* alpha fill */
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glColor4ubv((unsigned char *)wcol->inner);
for (a = 0; a < wtb->totvert; a++) {
x_mid += wtb->inner_v[a][0];
}
x_mid /= wtb->totvert;
glVertexPointer(2, GL_FLOAT, 0, wtb->inner_v);
glDrawArrays(GL_POLYGON, 0, wtb->totvert);
/* 1/2 solid color */
glColor4ub(wcol->inner[0], wcol->inner[1], wcol->inner[2], 255);
for (a = 0; a < wtb->totvert; a++) {
inner_v_half[a][0] = MIN2(wtb->inner_v[a][0], x_mid);
inner_v_half[a][1] = wtb->inner_v[a][1];
}
glVertexPointer(2, GL_FLOAT, 0, inner_v_half);
glDrawArrays(GL_POLYGON, 0, wtb->totvert);
glDisableClientState(GL_VERTEX_ARRAY);
}
else {
/* simple fill */
glColor4ubv((unsigned char *)wcol->inner);
glEnableClientState(GL_VERTEX_ARRAY);
glVertexPointer(2, GL_FLOAT, 0, wtb->inner_v);
glDrawArrays(GL_POLYGON, 0, wtb->totvert);
glDisableClientState(GL_VERTEX_ARRAY);
}
}
else {
char col1[4], col2[4];
unsigned char col_array[WIDGET_SIZE_MAX * 4];
unsigned char *col_pt = col_array;
shadecolors4(col1, col2, wcol->inner, wcol->shadetop, wcol->shadedown);
glShadeModel(GL_SMOOTH);
for (a = 0; a < wtb->totvert; a++, col_pt += 4) {
round_box_shade_col4_r(col_pt, col1, col2, wtb->inner_uv[a][wtb->draw_shadedir ? 1 : 0]);
}
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_COLOR_ARRAY);
glVertexPointer(2, GL_FLOAT, 0, wtb->inner_v);
glColorPointer(4, GL_UNSIGNED_BYTE, 0, col_array);
glDrawArrays(GL_POLYGON, 0, wtb->totvert);
glDisableClientState(GL_VERTEX_ARRAY);
glDisableClientState(GL_COLOR_ARRAY);
glShadeModel(GL_FLAT);
}
}
/* for each AA step */
if (wtb->draw_outline) {
float triangle_strip[WIDGET_SIZE_MAX * 2 + 2][2]; /* + 2 because the last pair is wrapped */
float triangle_strip_emboss[WIDGET_SIZE_MAX * 2][2]; /* only for emboss */
const unsigned char tcol[4] = {wcol->outline[0],
wcol->outline[1],
wcol->outline[2],
wcol->outline[3] / WIDGET_AA_JITTER};
widget_verts_to_triangle_strip(wtb, wtb->totvert, triangle_strip);
if (wtb->draw_emboss) {
widget_verts_to_triangle_strip_open(wtb, wtb->halfwayvert, triangle_strip_emboss);
}
glEnableClientState(GL_VERTEX_ARRAY);
for (j = 0; j < WIDGET_AA_JITTER; j++) {
unsigned char emboss[4];
glTranslatef(jit[j][0], jit[j][1], 0.0f);
/* outline */
glColor4ubv(tcol);
glVertexPointer(2, GL_FLOAT, 0, triangle_strip);
glDrawArrays(GL_TRIANGLE_STRIP, 0, wtb->totvert * 2 + 2);
/* emboss bottom shadow */
if (wtb->draw_emboss) {
UI_GetThemeColor4ubv(TH_WIDGET_EMBOSS, emboss);
if (emboss[3]) {
glColor4ubv(emboss);
glVertexPointer(2, GL_FLOAT, 0, triangle_strip_emboss);
glDrawArrays(GL_TRIANGLE_STRIP, 0, wtb->halfwayvert * 2);
}
}
glTranslatef(-jit[j][0], -jit[j][1], 0.0f);
}
glDisableClientState(GL_VERTEX_ARRAY);
}
/* decoration */
if (wtb->tria1.tot || wtb->tria2.tot) {
const unsigned char tcol[4] = {wcol->item[0],
wcol->item[1],
wcol->item[2],
(unsigned char)((float)wcol->item[3] / WIDGET_AA_JITTER)};
/* for each AA step */
for (j = 0; j < WIDGET_AA_JITTER; j++) {
glTranslatef(jit[j][0], jit[j][1], 0.0f);
if (wtb->tria1.tot) {
glColor4ubv(tcol);
widget_trias_draw(&wtb->tria1);
}
if (wtb->tria2.tot) {
glColor4ubv(tcol);
widget_trias_draw(&wtb->tria2);
}
glTranslatef(-jit[j][0], -jit[j][1], 0.0f);
}
}
glDisable(GL_BLEND);
}
void ui_hsv_cursor(float x, float y)
{
glPushMatrix();
glTranslatef(x, y, 0.0f);
glColor3f(1.0f, 1.0f, 1.0f);
glutil_draw_filled_arc(0.0f, M_PI * 2.0, 3.0f * U.pixelsize, 8);
glEnable(GL_BLEND);
glEnable(GL_LINE_SMOOTH);
glColor3f(0.0f, 0.0f, 0.0f);
glutil_draw_lined_arc(0.0f, M_PI * 2.0, 3.0f * U.pixelsize, 12);
glDisable(GL_BLEND);
glDisable(GL_LINE_SMOOTH);
glPopMatrix();
}
static void ui_draw_colorband_handle_tri_hlight(float x1, float y1, float halfwidth, float height)
{
float v[2];
glEnable(GL_LINE_SMOOTH);
glBegin(GL_LINE_STRIP);
copy_v2_fl2(v, x1 + halfwidth, y1);
glVertex2fv(v);
copy_v2_fl2(v, x1, y1 + height);
glVertex2fv(v);
copy_v2_fl2(v, x1 - halfwidth, y1);
glVertex2fv(v);
glEnd();
glDisable(GL_LINE_SMOOTH);
}
static void ui_draw_colorband_handle_tri(float x1, float y1, float halfwidth, float height, bool fill)
{
float v[2];
if (fill) {
glPolygonMode(GL_FRONT, GL_FILL);
glEnable(GL_POLYGON_SMOOTH);
}
else {
glPolygonMode(GL_FRONT, GL_LINE);
glEnable(GL_LINE_SMOOTH);
}
glBegin(GL_TRIANGLES);
copy_v2_fl2(v, x1 + halfwidth, y1);
glVertex2fv(v);
copy_v2_fl2(v, x1, y1 + height);
glVertex2fv(v);
copy_v2_fl2(v, x1 - halfwidth, y1);
glVertex2fv(v);
glEnd();
if (fill) {
glDisable(GL_POLYGON_SMOOTH);
}
else {
glDisable(GL_LINE_SMOOTH);
glPolygonMode(GL_FRONT, GL_FILL);
}
}
static void ui_draw_colorband_handle_box(float x1, float y1, float x2, float y2, bool fill)
{
float v[2];
if (fill) {
glPolygonMode(GL_FRONT, GL_FILL);
}
else {
glPolygonMode(GL_FRONT, GL_LINE);
}
glBegin(GL_QUADS);
copy_v2_fl2(v, x1, y1);
glVertex2fv(v);
copy_v2_fl2(v, x1, y2);
glVertex2fv(v);
copy_v2_fl2(v, x2, y2);
glVertex2fv(v);
copy_v2_fl2(v, x2, y1);
glVertex2fv(v);
glEnd();
if (!fill) {
glPolygonMode(GL_FRONT, GL_FILL);
}
}
void ui_draw_colorband_handle(
const rcti *rect, float x,
const float rgb[3], struct ColorManagedDisplay *display,
bool active)
{
const float sizey = BLI_rcti_size_y(rect);
const float min_width = 3.0f;
float half_width, height, y1, y2;
float colf[3] = {UNPACK3(rgb)};
half_width = floorf(sizey / 3.5f);
height = half_width * 1.4f;
y1 = rect->ymin + (sizey * 0.16f);
y2 = rect->ymax;
/* align to pixels */
x = floorf(x + 0.5f);
y1 = floorf(y1 + 0.5f);
if (active || half_width < min_width) {
glBegin(GL_LINES);
glColor3ub(0, 0, 0);
glVertex2f(x, y1);
glVertex2f(x, y2);
glEnd();
setlinestyle(active ? 2 : 1);
glBegin(GL_LINES);
glColor3ub(200, 200, 200);
glVertex2f(x, y1);
glVertex2f(x, y2);
glEnd();
setlinestyle(0);
/* hide handles when zoomed out too far */
if (half_width < min_width) {
return;
}
}
/* shift handle down */
y1 = y1 - half_width;
glColor3ub(0, 0, 0);
ui_draw_colorband_handle_box(x - half_width, y1 - 1, x + half_width, y1 + height, false);
/* draw all triangles blended */
glEnable(GL_BLEND);
ui_draw_colorband_handle_tri(x, y1 + height, half_width, half_width, true);
if (active)
glColor3ub(196, 196, 196);
else
glColor3ub(96, 96, 96);
ui_draw_colorband_handle_tri(x, y1 + height, half_width, half_width, true);
if (active)
glColor3ub(255, 255, 255);
else
glColor3ub(128, 128, 128);
ui_draw_colorband_handle_tri_hlight(x, y1 + height - 1, (half_width - 1), (half_width - 1));
glColor3ub(0, 0, 0);
ui_draw_colorband_handle_tri_hlight(x, y1 + height, half_width, half_width);
glDisable(GL_BLEND);
glColor3ub(128, 128, 128);
ui_draw_colorband_handle_box(x - (half_width - 1), y1, x + (half_width - 1), y1 + height, true);
if (display) {
IMB_colormanagement_scene_linear_to_display_v3(colf, display);
}
glColor3fv(colf);
ui_draw_colorband_handle_box(x - (half_width - 2), y1 + 1, x + (half_width - 2), y1 + height - 2, true);
}

View File

@@ -0,0 +1,109 @@
/*
* ***** BEGIN GPL 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.
*
* 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* Contributor(s): none yet.
*
* ***** END GPL LICENSE BLOCK *****
*/
#ifndef __WIDGETS_DRAW_INTERN_H__
#define __WIDGETS_DRAW_INTERN_H__
/** \file blender/editors/interface/widgets/widgets_draw/widgets_draw_intern.h
* \ingroup edinterface
*
* \brief Blender widget drawing module
*/
/* Struct Declarations */
struct uiBut;
struct uiFontStyle;
struct uiWidgetType;
struct rcti;
struct ColorManagedDisplay;
/* ************** widget base functions ************** */
/**
* - in: roundbox codes for corner types and radius
* - return: array of `[size][2][x, y]` points, the edges of the roundbox, + UV coords
*
* - draw black box with alpha 0 on exact button boundbox
* - for every AA step:
* - draw the inner part for a round filled box, with color blend codes or texture coords
* - draw outline in outline color
* - draw outer part, bottom half, extruded 1 pixel to bottom, for emboss shadow
* - draw extra decorations
* - draw background color box with alpha 1 on exact button boundbox
*/
/* fill this struct with polygon info to draw AA'ed */
/* it has outline, back, and two optional tria meshes */
/* max as used by round_box__edges */
#define WIDGET_CURVE_RESOLU 9
#define WIDGET_SIZE_MAX (WIDGET_CURVE_RESOLU * 4)
typedef struct uiWidgetDrawBaseTrias {
unsigned int tot;
float vec[16][2];
const unsigned int (*index)[3];
} uiWidgetDrawBaseTrias;
typedef struct uiWidgetDrawBase {
int totvert, halfwayvert;
float outer_v[WIDGET_SIZE_MAX][2];
float inner_v[WIDGET_SIZE_MAX][2];
float inner_uv[WIDGET_SIZE_MAX][2];
bool draw_inner, draw_outline, draw_emboss, draw_shadedir;
uiWidgetDrawBaseTrias tria1;
uiWidgetDrawBaseTrias tria2;
} uiWidgetDrawBase;
/* widgets_draw.c - shared low-level drawing functions */
void widget_drawbase_roundboxedges_set(uiWidgetDrawBase *wt, int roundboxalign, const rcti *rect, float rad);
void round_box__edges(uiWidgetDrawBase *wt, int roundboxalign, const rcti *rect, float rad, float radi);
void widget_drawbase_num_tria(uiWidgetDrawBaseTrias *tria, const rcti *rect, float triasize, char where);
void widget_drawbase_menu_trias(uiWidgetDrawBaseTrias *tria, const rcti *rect);
void widget_drawbase_check_trias(uiWidgetDrawBaseTrias *tria, const rcti *rect);
void widget_drawbase_softshadow(const rcti *rect, int roundboxalign, const float radin);
void widget_drawbase_draw(uiWidgetDrawBase *wtb, struct uiWidgetColors *wcol);
void widget_drawbase_outline(uiWidgetDrawBase *wtb);
void widget_drawbase_scroll_circle(uiWidgetDrawBaseTrias *tria, const rcti *rect, float triasize, char where);
void ui_hsv_cursor(float x, float y);
void ui_draw_colorband_handle(
const rcti *rect, float x,
const float rgb[3], struct ColorManagedDisplay *display,
bool active);
/* widgets_draw_text.c - shared low-level text formatting/drawing functions */
void widget_draw_text_icon(
uiFontStyle *fstyle, uiWidgetColors *wcol, uiBut *but,
rcti *rect, const char *str, const int iconid);
void widget_draw_text_preview_item(
uiFontStyle *fstyle, uiWidgetColors *wcol, uiBut *UNUSED(but),
rcti *rect, const char *str, const int iconid);
#endif /* __WIDGETS_DRAW_INTERN_H__ */

View File

@@ -0,0 +1,911 @@
/*
* ***** BEGIN GPL 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.
*
* 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* Contributor(s): none yet.
*
* ***** END GPL LICENSE BLOCK *****
*/
/** \file blender/editors/interface/widgets/widgets_draw/widgets_draw_text.c
* \ingroup edinterface
*/
#include <limits.h>
#include <string.h>
#include "BIF_gl.h"
#include "BLF_api.h"
#include "BLI_math_base.h"
#include "BLI_rect.h"
#include "BLI_string.h"
#include "BLI_string_utf8.h"
#include "DNA_screen_types.h"
#include "DNA_userdef_types.h"
#include "UI_interface.h"
#include "UI_interface_icons.h"
#include "../interface_intern.h" /* XXX currently needed, but not so nice on this level */
#include "widgets_draw_intern.h"
#define UI_TEXT_CLIP_MARGIN (0.25f * U.widget_unit / but->block->aspect)
/* icons are 80% of height of button (16 pixels inside 20 height) */
#define ICON_SIZE_FROM_BUTRECT(rect) (0.8f * BLI_rcti_size_y(rect))
#define PREVIEW_PAD 4
static void widget_draw_preview(BIFIconID icon, float alpha, const rcti *rect)
{
int w, h, size;
if (icon == ICON_NONE)
return;
w = BLI_rcti_size_x(rect);
h = BLI_rcti_size_y(rect);
size = MIN2(w, h);
size -= PREVIEW_PAD * 2; /* padding */
if (size > 0) {
int x = rect->xmin + w / 2 - size / 2;
int y = rect->ymin + h / 2 - size / 2;
UI_icon_draw_preview_aspect_size(x, y, icon, 1.0f, alpha, size);
}
}
void widget_draw_text_preview_item(
uiFontStyle *fstyle, uiWidgetColors *wcol, uiBut *UNUSED(but),
rcti *rect, const char *str, const int iconid)
{
rcti trect = *rect;
const float text_size = UI_UNIT_Y;
float font_dims[2] = {0.0f, 0.0f};
/* draw icon in rect above the space reserved for the label */
rect->ymin += text_size;
glEnable(GL_BLEND);
widget_draw_preview(iconid, 1.0f, rect);
glDisable(GL_BLEND);
BLF_width_and_height(fstyle->uifont_id, str, BLF_DRAW_STR_DUMMY_MAX, &font_dims[0], &font_dims[1]);
/* text rect */
trect.xmin += 0;
trect.xmax = trect.xmin + font_dims[0] + U.widget_unit / 2;
trect.ymin += U.widget_unit / 2;
trect.ymax = trect.ymin + font_dims[1];
if (trect.xmax > rect->xmax - PREVIEW_PAD)
trect.xmax = rect->xmax - PREVIEW_PAD;
{
char drawstr[UI_MAX_DRAW_STR];
const float okwidth = (float)BLI_rcti_size_x(&trect);
const size_t max_len = sizeof(drawstr);
const float minwidth = (float)(UI_DPI_ICON_SIZE);
BLI_strncpy(drawstr, str, sizeof(drawstr));
UI_text_clip_middle_ex(fstyle, drawstr, okwidth, minwidth, max_len, '\0');
glColor4ubv((unsigned char *)wcol->text);
UI_fontstyle_draw(fstyle, &trect, drawstr);
}
}
static int ui_but_draw_menu_icon(const uiBut *but)
{
return (but->flag & UI_BUT_ICON_SUBMENU) && (but->dt == UI_EMBOSS_PULLDOWN);
}
/* icons have been standardized... and this call draws in untransformed coordinates */
static void widget_draw_icon(
const uiBut *but, BIFIconID icon, float alpha, const rcti *rect,
const bool show_menu_icon)
{
float xs = 0.0f, ys = 0.0f;
float aspect, height;
if (but->flag & UI_BUT_ICON_PREVIEW) {
glEnable(GL_BLEND);
widget_draw_preview(icon, alpha, rect);
glDisable(GL_BLEND);
return;
}
/* this icon doesn't need draw... */
if (icon == ICON_BLANK1 && (but->flag & UI_BUT_ICON_SUBMENU) == 0) return;
aspect = but->block->aspect / UI_DPI_FAC;
height = ICON_DEFAULT_HEIGHT / aspect;
/* calculate blend color */
if (ELEM(but->type, UI_BTYPE_TOGGLE, UI_BTYPE_ROW, UI_BTYPE_TOGGLE_N, UI_BTYPE_LISTROW)) {
if (but->flag & UI_SELECT) {}
else if (but->flag & UI_ACTIVE) {}
else alpha = 0.5f;
}
/* extra feature allows more alpha blending */
if ((but->type == UI_BTYPE_LABEL) && but->a1 == 1.0f)
alpha *= but->a2;
glEnable(GL_BLEND);
if (icon && icon != ICON_BLANK1) {
float ofs = 1.0f / aspect;
if (but->drawflag & UI_BUT_ICON_LEFT) {
if (but->block->flag & UI_BLOCK_LOOP) {
if (but->type == UI_BTYPE_SEARCH_MENU)
xs = rect->xmin + 4.0f * ofs;
else
xs = rect->xmin + ofs;
}
else {
xs = rect->xmin + 4.0f * ofs;
}
ys = (rect->ymin + rect->ymax - height) / 2.0f;
}
else {
xs = (rect->xmin + rect->xmax - height) / 2.0f;
ys = (rect->ymin + rect->ymax - height) / 2.0f;
}
/* force positions to integers, for zoom levels near 1. draws icons crisp. */
if (aspect > 0.95f && aspect < 1.05f) {
xs = (int)(xs + 0.1f);
ys = (int)(ys + 0.1f);
}
/* to indicate draggable */
if (but->dragpoin && (but->flag & UI_ACTIVE)) {
float rgb[3] = {1.25f, 1.25f, 1.25f};
UI_icon_draw_aspect_color(xs, ys, icon, aspect, rgb);
}
else
UI_icon_draw_aspect(xs, ys, icon, aspect, alpha);
}
if (show_menu_icon) {
xs = rect->xmax - UI_DPI_ICON_SIZE - aspect;
ys = (rect->ymin + rect->ymax - height) / 2.0f;
UI_icon_draw_aspect(xs, ys, ICON_RIGHTARROW_THIN, aspect, alpha);
}
glDisable(GL_BLEND);
}
static void ui_text_clip_give_prev_off(uiBut *but, const char *str)
{
const char *prev_utf8 = BLI_str_find_prev_char_utf8(str, str + but->ofs);
int bytes = str + but->ofs - prev_utf8;
but->ofs -= bytes;
}
static void ui_text_clip_give_next_off(uiBut *but, const char *str)
{
const char *next_utf8 = BLI_str_find_next_char_utf8(str + but->ofs, NULL);
int bytes = next_utf8 - (str + but->ofs);
but->ofs += bytes;
}
/**
* Helper.
* This func assumes things like kerning handling have already been handled!
* Return the length of modified (right-clipped + ellipsis) string.
*/
static void ui_text_clip_right_ex(
uiFontStyle *fstyle, char *str, const size_t max_len, const float okwidth,
const char *sep, const int sep_len, const float sep_strwidth, size_t *r_final_len)
{
float tmp;
int l_end;
BLI_assert(str[0]);
/* If the trailing ellipsis takes more than 20% of all available width, just cut the string
* (as using the ellipsis would remove even more useful chars, and we cannot show much already!).
*/
if (sep_strwidth / okwidth > 0.2f) {
l_end = BLF_width_to_strlen(fstyle->uifont_id, str, max_len, okwidth, &tmp);
str[l_end] = '\0';
if (r_final_len) {
*r_final_len = (size_t)l_end;
}
}
else {
l_end = BLF_width_to_strlen(fstyle->uifont_id, str, max_len, okwidth - sep_strwidth, &tmp);
memcpy(str + l_end, sep, sep_len + 1); /* +1 for trailing '\0'. */
if (r_final_len) {
*r_final_len = (size_t)(l_end + sep_len);
}
}
}
/**
* Cut off the middle of the text to fit into the given width.
* Note in case this middle clipping would just remove a few chars, it rather clips right, which is more readable.
* If rpart_sep is not Null, the part of str starting to first occurrence of rpart_sep is preserved at all cost (useful
* for strings with shortcuts, like 'AVeryLongFooBarLabelForMenuEntry|Ctrl O' -> 'AVeryLong...MenuEntry|Ctrl O').
*/
float UI_text_clip_middle_ex(
uiFontStyle *fstyle, char *str, float okwidth, const float minwidth,
const size_t max_len, const char rpart_sep)
{
float strwidth;
/* Add some epsilon to OK width, avoids 'ellipsing' text that nearly fits!
* Better to have a small piece of the last char cut out, than two remaining chars replaced by an allipsis... */
okwidth += 1.0f + UI_DPI_FAC;
BLI_assert(str[0]);
/* need to set this first */
UI_fontstyle_set(fstyle);
if (fstyle->kerning == 1) { /* for BLF_width */
BLF_enable(fstyle->uifont_id, BLF_KERNING_DEFAULT);
}
strwidth = BLF_width(fstyle->uifont_id, str, max_len);
if ((okwidth > 0.0f) && (strwidth > okwidth)) {
/* utf8 ellipsis '...', some compilers complain */
const char sep[] = {0xe2, 0x80, 0xa6, 0x0};
const int sep_len = sizeof(sep) - 1;
const float sep_strwidth = BLF_width(fstyle->uifont_id, sep, sep_len + 1);
float parts_strwidth;
size_t l_end;
char *rpart = NULL, rpart_buf[UI_MAX_DRAW_STR];
float rpart_width = 0.0f;
size_t rpart_len = 0;
size_t final_lpart_len;
if (rpart_sep) {
rpart = strrchr(str, rpart_sep);
if (rpart) {
rpart_len = strlen(rpart);
rpart_width = BLF_width(fstyle->uifont_id, rpart, rpart_len);
okwidth -= rpart_width;
strwidth -= rpart_width;
if (okwidth < 0.0f) {
/* Not enough place for actual label, just display protected right part.
* Here just for safety, should never happen in real life! */
memmove(str, rpart, rpart_len + 1);
rpart = NULL;
okwidth += rpart_width;
strwidth = rpart_width;
}
}
}
parts_strwidth = (okwidth - sep_strwidth) / 2.0f;
if (rpart) {
strcpy(rpart_buf, rpart);
*rpart = '\0';
rpart = rpart_buf;
}
l_end = BLF_width_to_strlen(fstyle->uifont_id, str, max_len, parts_strwidth, &rpart_width);
if (l_end < 10 || min_ff(parts_strwidth, strwidth - okwidth) < minwidth) {
/* If we really have no place, or we would clip a very small piece of string in the middle,
* only show start of string.
*/
ui_text_clip_right_ex(fstyle, str, max_len, okwidth, sep, sep_len, sep_strwidth, &final_lpart_len);
}
else {
size_t r_offset, r_len;
r_offset = BLF_width_to_rstrlen(fstyle->uifont_id, str, max_len, parts_strwidth, &rpart_width);
r_len = strlen(str + r_offset) + 1; /* +1 for the trailing '\0'. */
if (l_end + sep_len + r_len + rpart_len > max_len) {
/* Corner case, the str already takes all available mem, and the ellipsis chars would actually
* add more chars...
* Better to just trim one or two letters to the right in this case...
* Note: with a single-char ellipsis, this should never happen! But better be safe here...
*/
ui_text_clip_right_ex(fstyle, str, max_len, okwidth, sep, sep_len, sep_strwidth, &final_lpart_len);
}
else {
memmove(str + l_end + sep_len, str + r_offset, r_len);
memcpy(str + l_end, sep, sep_len);
final_lpart_len = (size_t)(l_end + sep_len + r_len - 1); /* -1 to remove trailing '\0'! */
}
}
if (rpart) {
/* Add back preserved right part to our shorten str. */
memcpy(str + final_lpart_len, rpart, rpart_len + 1); /* +1 for trailing '\0'. */
}
strwidth = BLF_width(fstyle->uifont_id, str, max_len);
}
if (fstyle->kerning == 1) {
BLF_disable(fstyle->uifont_id, BLF_KERNING_DEFAULT);
}
return strwidth;
}
/**
* Wrapper around UI_text_clip_middle_ex.
*/
static void ui_text_clip_middle(uiFontStyle *fstyle, uiBut *but, const rcti *rect)
{
/* No margin for labels! */
const int border = ELEM(but->type, UI_BTYPE_LABEL, UI_BTYPE_MENU) ? 0 : (int)(UI_TEXT_CLIP_MARGIN + 0.5f);
const float okwidth = (float)max_ii(BLI_rcti_size_x(rect) - border, 0);
const size_t max_len = sizeof(but->drawstr);
const float minwidth = (float)(UI_DPI_ICON_SIZE) / but->block->aspect * 2.0f;
but->ofs = 0;
but->strwidth = UI_text_clip_middle_ex(fstyle, but->drawstr, okwidth, minwidth, max_len, '\0');
}
/**
* Like ui_text_clip_middle(), but protect/preserve at all cost the right part of the string after sep.
* Useful for strings with shortcuts (like 'AVeryLongFooBarLabelForMenuEntry|Ctrl O' -> 'AVeryLong...MenuEntry|Ctrl O').
*/
static void ui_text_clip_middle_protect_right(uiFontStyle *fstyle, uiBut *but, const rcti *rect, const char rsep)
{
/* No margin for labels! */
const int border = ELEM(but->type, UI_BTYPE_LABEL, UI_BTYPE_MENU) ? 0 : (int)(UI_TEXT_CLIP_MARGIN + 0.5f);
const float okwidth = (float)max_ii(BLI_rcti_size_x(rect) - border, 0);
const size_t max_len = sizeof(but->drawstr);
const float minwidth = (float)(UI_DPI_ICON_SIZE) / but->block->aspect * 2.0f;
but->ofs = 0;
but->strwidth = UI_text_clip_middle_ex(fstyle, but->drawstr, okwidth, minwidth, max_len, rsep);
}
/**
* Cut off the text, taking into account the cursor location (text display while editing).
*/
static void ui_text_clip_cursor(uiFontStyle *fstyle, uiBut *but, const rcti *rect)
{
const int border = (int)(UI_TEXT_CLIP_MARGIN + 0.5f);
const int okwidth = max_ii(BLI_rcti_size_x(rect) - border, 0);
BLI_assert(but->editstr && but->pos >= 0);
/* need to set this first */
UI_fontstyle_set(fstyle);
if (fstyle->kerning == 1) /* for BLF_width */
BLF_enable(fstyle->uifont_id, BLF_KERNING_DEFAULT);
/* define ofs dynamically */
if (but->ofs > but->pos)
but->ofs = but->pos;
if (BLF_width(fstyle->uifont_id, but->editstr, INT_MAX) <= okwidth)
but->ofs = 0;
but->strwidth = BLF_width(fstyle->uifont_id, but->editstr + but->ofs, INT_MAX);
if (but->strwidth > okwidth) {
int len = strlen(but->editstr);
while (but->strwidth > okwidth) {
float width;
/* string position of cursor */
width = BLF_width(fstyle->uifont_id, but->editstr + but->ofs, (but->pos - but->ofs));
/* if cursor is at 20 pixels of right side button we clip left */
if (width > okwidth - 20) {
ui_text_clip_give_next_off(but, but->editstr);
}
else {
int bytes;
/* shift string to the left */
if (width < 20 && but->ofs > 0)
ui_text_clip_give_prev_off(but, but->editstr);
bytes = BLI_str_utf8_size(BLI_str_find_prev_char_utf8(but->editstr, but->editstr + len));
if (bytes == -1)
bytes = 1;
len -= bytes;
}
but->strwidth = BLF_width(fstyle->uifont_id, but->editstr + but->ofs, len - but->ofs);
if (but->strwidth < 10) break;
}
}
if (fstyle->kerning == 1) {
BLF_disable(fstyle->uifont_id, BLF_KERNING_DEFAULT);
}
}
/**
* Cut off the end of text to fit into the width of \a rect.
*
* \note deals with ': ' especially for number buttons
*/
static void ui_text_clip_right_label(uiFontStyle *fstyle, uiBut *but, const rcti *rect)
{
const int border = UI_TEXT_CLIP_MARGIN + 1;
const int okwidth = max_ii(BLI_rcti_size_x(rect) - border, 0);
char *cpoin = NULL;
int drawstr_len = strlen(but->drawstr);
const char *cpend = but->drawstr + drawstr_len;
/* need to set this first */
UI_fontstyle_set(fstyle);
if (fstyle->kerning == 1) /* for BLF_width */
BLF_enable(fstyle->uifont_id, BLF_KERNING_DEFAULT);
but->strwidth = BLF_width(fstyle->uifont_id, but->drawstr, sizeof(but->drawstr));
but->ofs = 0;
/* First shorten num-buttons eg,
* Translucency: 0.000
* becomes
* Trans: 0.000
*/
/* find the space after ':' separator */
cpoin = strrchr(but->drawstr, ':');
if (cpoin && (cpoin < cpend - 2)) {
char *cp2 = cpoin;
/* chop off the leading text, starting from the right */
while (but->strwidth > okwidth && cp2 > but->drawstr) {
const char *prev_utf8 = BLI_str_find_prev_char_utf8(but->drawstr, cp2);
int bytes = cp2 - prev_utf8;
/* shift the text after and including cp2 back by 1 char, +1 to include null terminator */
memmove(cp2 - bytes, cp2, drawstr_len + 1);
cp2 -= bytes;
drawstr_len -= bytes;
// BLI_assert(strlen(but->drawstr) == drawstr_len);
but->strwidth = BLF_width(fstyle->uifont_id, but->drawstr + but->ofs, sizeof(but->drawstr) - but->ofs);
if (but->strwidth < 10) break;
}
/* after the leading text is gone, chop off the : and following space, with ofs */
while ((but->strwidth > okwidth) && (but->ofs < 2)) {
ui_text_clip_give_next_off(but, but->drawstr);
but->strwidth = BLF_width(fstyle->uifont_id, but->drawstr + but->ofs, sizeof(but->drawstr) - but->ofs);
if (but->strwidth < 10) break;
}
}
/* Now just remove trailing chars */
/* once the label's gone, chop off the least significant digits */
if (but->strwidth > okwidth) {
float strwidth;
drawstr_len = BLF_width_to_strlen(fstyle->uifont_id, but->drawstr + but->ofs,
drawstr_len - but->ofs, okwidth, &strwidth) + but->ofs;
but->strwidth = strwidth;
but->drawstr[drawstr_len] = 0;
}
if (fstyle->kerning == 1)
BLF_disable(fstyle->uifont_id, BLF_KERNING_DEFAULT);
}
#ifdef WITH_INPUT_IME
static void widget_draw_text_ime_underline(
uiFontStyle *fstyle, uiWidgetColors *wcol, uiBut *but, const rcti *rect,
const wmIMEData *ime_data, const char *drawstr)
{
int ofs_x, width;
int rect_x = BLI_rcti_size_x(rect);
int sel_start = ime_data->sel_start, sel_end = ime_data->sel_end;
if (drawstr[0] != 0) {
if (but->pos >= but->ofs) {
ofs_x = BLF_width(fstyle->uifont_id, drawstr + but->ofs, but->pos - but->ofs);
}
else {
ofs_x = 0;
}
width = BLF_width(fstyle->uifont_id, drawstr + but->ofs,
ime_data->composite_len + but->pos - but->ofs);
glColor4ubv((unsigned char *)wcol->text);
UI_draw_text_underline(rect->xmin + ofs_x, rect->ymin + 6 * U.pixelsize, min_ii(width, rect_x - 2) - ofs_x, 1);
/* draw the thick line */
if (sel_start != -1 && sel_end != -1) {
sel_end -= sel_start;
sel_start += but->pos;
if (sel_start >= but->ofs) {
ofs_x = BLF_width(fstyle->uifont_id, drawstr + but->ofs, sel_start - but->ofs);
}
else {
ofs_x = 0;
}
width = BLF_width(fstyle->uifont_id, drawstr + but->ofs,
sel_end + sel_start - but->ofs);
UI_draw_text_underline(rect->xmin + ofs_x, rect->ymin + 6 * U.pixelsize, min_ii(width, rect_x - 2) - ofs_x, 2);
}
}
}
#endif /* WITH_INPUT_IME */
static void widget_draw_text(uiFontStyle *fstyle, uiWidgetColors *wcol, uiBut *but, rcti *rect, const char *drawstr)
{
int drawstr_left_len = UI_MAX_DRAW_STR;
const char *drawstr_right = NULL;
bool use_right_only = false;
#ifdef WITH_INPUT_IME
const wmIMEData *ime_data;
#endif
UI_fontstyle_set(fstyle);
if (but->editstr || (but->drawflag & UI_BUT_TEXT_LEFT))
fstyle->align = UI_STYLE_TEXT_LEFT;
else if (but->drawflag & UI_BUT_TEXT_RIGHT)
fstyle->align = UI_STYLE_TEXT_RIGHT;
else
fstyle->align = UI_STYLE_TEXT_CENTER;
if (fstyle->kerning == 1) /* for BLF_width */
BLF_enable(fstyle->uifont_id, BLF_KERNING_DEFAULT);
/* Special case: when we're entering text for multiple buttons,
* don't draw the text for any of the multi-editing buttons */
if (UNLIKELY(but->flag & UI_BUT_DRAG_MULTI)) {
uiBut *but_edit = ui_but_drag_multi_edit_get(but);
if (but_edit) {
drawstr = but_edit->editstr;
fstyle->align = UI_STYLE_TEXT_LEFT;
}
}
else {
if (but->editstr) {
/* max length isn't used in this case,
* we rely on string being NULL terminated. */
drawstr_left_len = INT_MAX;
#ifdef WITH_INPUT_IME
/* FIXME, IME is modifying 'const char *drawstr! */
ime_data = ui_but_ime_data_get(but);
if (ime_data && ime_data->composite_len) {
/* insert composite string into cursor pos */
BLI_snprintf((char *)drawstr, UI_MAX_DRAW_STR, "%s%s%s",
but->editstr, ime_data->str_composite,
but->editstr + but->pos);
}
else
#endif
{
drawstr = but->editstr;
}
}
}
/* text button selection, cursor, composite underline */
if (but->editstr && but->pos != -1) {
int but_pos_ofs;
int tx, ty;
/* text button selection */
if ((but->selend - but->selsta) > 0) {
int selsta_draw, selwidth_draw;
if (drawstr[0] != 0) {
if (but->selsta >= but->ofs) {
selsta_draw = BLF_width(fstyle->uifont_id, drawstr + but->ofs, but->selsta - but->ofs);
}
else {
selsta_draw = 0;
}
selwidth_draw = BLF_width(fstyle->uifont_id, drawstr + but->ofs, but->selend - but->ofs);
glColor4ubv((unsigned char *)wcol->item);
glRecti(rect->xmin + selsta_draw,
rect->ymin + 2,
min_ii(rect->xmin + selwidth_draw, rect->xmax - 2),
rect->ymax - 2);
}
}
/* text cursor */
but_pos_ofs = but->pos;
#ifdef WITH_INPUT_IME
/* if is ime compositing, move the cursor */
if (ime_data && ime_data->composite_len && ime_data->cursor_pos != -1) {
but_pos_ofs += ime_data->cursor_pos;
}
#endif
if (but->pos >= but->ofs) {
int t;
if (drawstr[0] != 0) {
t = BLF_width(fstyle->uifont_id, drawstr + but->ofs, but_pos_ofs - but->ofs);
}
else {
t = 0;
}
glColor3f(0.2, 0.6, 0.9);
tx = rect->xmin + t + 2;
ty = rect->ymin + 2;
/* draw cursor */
glRecti(rect->xmin + t, ty, tx, rect->ymax - 2);
}
#ifdef WITH_INPUT_IME
if (ime_data && ime_data->composite_len) {
/* ime cursor following */
if (but->pos >= but->ofs) {
ui_but_ime_reposition(but, tx + 5, ty + 3, false);
}
/* composite underline */
widget_draw_text_ime_underline(fstyle, wcol, but, rect, ime_data, drawstr);
}
#endif
}
if (fstyle->kerning == 1)
BLF_disable(fstyle->uifont_id, BLF_KERNING_DEFAULT);
#if 0
ui_rasterpos_safe(x, y, but->aspect);
transopts = ui_translate_buttons();
#endif
/* cut string in 2 parts - only for menu entries */
if ((but->block->flag & UI_BLOCK_LOOP) &&
(but->editstr == NULL))
{
if (but->flag & UI_BUT_HAS_SEP_CHAR) {
drawstr_right = strrchr(drawstr, UI_SEP_CHAR);
if (drawstr_right) {
drawstr_left_len = (drawstr_right - drawstr);
drawstr_right++;
}
}
}
#ifdef USE_NUMBUTS_LR_ALIGN
if (!drawstr_right && ELEM(but->type, UI_BTYPE_NUM, UI_BTYPE_NUM_SLIDER) &&
/* if we're editing or multi-drag (fake editing), then use left alignment */
(but->editstr == NULL) && (drawstr == but->drawstr))
{
drawstr_right = strchr(drawstr + but->ofs, ':');
if (drawstr_right) {
drawstr_right++;
drawstr_left_len = (drawstr_right - drawstr);
while (*drawstr_right == ' ') {
drawstr_right++;
}
}
else {
/* no prefix, even so use only cpoin */
drawstr_right = drawstr + but->ofs;
use_right_only = true;
}
}
#endif
glColor4ubv((unsigned char *)wcol->text);
if (!use_right_only) {
/* for underline drawing */
float font_xofs, font_yofs;
UI_fontstyle_draw_ex(fstyle, rect, drawstr + but->ofs,
drawstr_left_len - but->ofs, &font_xofs, &font_yofs);
if (but->menu_key != '\0') {
char fixedbuf[128];
const char *str;
BLI_strncpy(fixedbuf, drawstr + but->ofs, min_ii(sizeof(fixedbuf), drawstr_left_len));
str = strchr(fixedbuf, but->menu_key - 32); /* upper case */
if (str == NULL)
str = strchr(fixedbuf, but->menu_key);
if (str) {
int ul_index = -1;
float ul_advance;
ul_index = (int)(str - fixedbuf);
if (fstyle->kerning == 1) {
BLF_enable(fstyle->uifont_id, BLF_KERNING_DEFAULT);
}
fixedbuf[ul_index] = '\0';
ul_advance = BLF_width(fstyle->uifont_id, fixedbuf, ul_index);
BLF_position(fstyle->uifont_id, rect->xmin + font_xofs + ul_advance, rect->ymin + font_yofs, 0.0f);
BLF_draw(fstyle->uifont_id, "_", 2);
if (fstyle->kerning == 1) {
BLF_disable(fstyle->uifont_id, BLF_KERNING_DEFAULT);
}
}
}
}
/* part text right aligned */
if (drawstr_right) {
fstyle->align = UI_STYLE_TEXT_RIGHT;
rect->xmax -= UI_TEXT_CLIP_MARGIN;
UI_fontstyle_draw(fstyle, rect, drawstr_right);
}
}
/* draws text and icons for buttons */
void widget_draw_text_icon(
uiFontStyle *fstyle, uiWidgetColors *wcol, uiBut *but,
rcti *rect, const char *str, const int iconid)
{
const bool show_menu_icon = ui_but_draw_menu_icon(but);
float alpha = (float)wcol->text[3] / 255.0f;
char password_str[UI_MAX_DRAW_STR];
uiButExtraIconType extra_icon_type;
ui_but_text_password_hide(password_str, but, false);
/* check for button text label */
if (but->type == UI_BTYPE_MENU && (but->flag & UI_BUT_NODE_LINK)) {
rcti temp = *rect;
temp.xmin = rect->xmax - BLI_rcti_size_y(rect) - 1;
widget_draw_icon(but, ICON_LAYER_USED, alpha, &temp, false);
}
/* If there's an icon too (made with uiDefIconTextBut) then draw the icon
* and offset the text label to accommodate it */
/* Big previews with optional text label below */
if (but->flag & UI_BUT_ICON_PREVIEW && ui_block_is_menu(but->block)) {
const BIFIconID icon = (but->flag & UI_HAS_ICON) ? iconid + but->iconadd : ICON_NONE;
int icon_size = BLI_rcti_size_y(rect);
int text_size = 0;
/* This is a bit britle, but avoids adding an 'UI_BUT_HAS_LABEL' flag to but... */
if (icon_size > BLI_rcti_size_x(rect)) {
/* button is not square, it has extra height for label */
text_size = UI_UNIT_Y;
icon_size -= text_size;
}
/* draw icon in rect above the space reserved for the label */
rect->ymin += text_size;
glEnable(GL_BLEND);
widget_draw_preview(icon, alpha, rect);
glDisable(GL_BLEND);
/* offset rect to draw label in */
rect->ymin -= text_size;
rect->ymax -= icon_size;
/* vertically centering text */
rect->ymin += UI_UNIT_Y / 2;
}
/* Icons on the left with optional text label on the right */
else if (but->flag & UI_HAS_ICON || show_menu_icon) {
const BIFIconID icon = (but->flag & UI_HAS_ICON) ? iconid + but->iconadd : ICON_NONE;
const float icon_size = ICON_SIZE_FROM_BUTRECT(rect);
/* menu item - add some more padding so menus don't feel cramped. it must
* be part of the button so that this area is still clickable */
if (ui_block_is_menu(but->block))
rect->xmin += 0.3f * U.widget_unit;
widget_draw_icon(but, icon, alpha, rect, show_menu_icon);
rect->xmin += icon_size;
/* without this menu keybindings will overlap the arrow icon [#38083] */
if (show_menu_icon) {
rect->xmax -= icon_size / 2.0f;
}
}
if (but->editstr || (but->drawflag & UI_BUT_TEXT_LEFT)) {
rect->xmin += (UI_TEXT_MARGIN_X * U.widget_unit) / but->block->aspect;
}
else if ((but->drawflag & UI_BUT_TEXT_RIGHT)) {
rect->xmax -= (UI_TEXT_MARGIN_X * U.widget_unit) / but->block->aspect;
}
/* unlink icon for this button type */
if ((but->type == UI_BTYPE_SEARCH_MENU) &&
((extra_icon_type = ui_but_icon_extra_get(but)) != UI_BUT_ICONEXTRA_NONE))
{
rcti temp = *rect;
temp.xmin = temp.xmax - (BLI_rcti_size_y(rect) * 1.08f);
if (extra_icon_type == UI_BUT_ICONEXTRA_UNLINK) {
widget_draw_icon(but, ICON_X, alpha, &temp, false);
}
else if (extra_icon_type == UI_BUT_ICONEXTRA_EYEDROPPER) {
widget_draw_icon(but, ICON_EYEDROPPER, alpha, &temp, false);
}
else {
BLI_assert(0);
}
rect->xmax -= ICON_SIZE_FROM_BUTRECT(rect);
}
/* clip but->drawstr to fit in available space */
if (but->editstr && but->pos >= 0) {
ui_text_clip_cursor(fstyle, but, rect);
}
else if (but->drawstr[0] == '\0') {
/* bypass text clipping on icon buttons */
but->ofs = 0;
but->strwidth = 0;
}
else if (ELEM(but->type, UI_BTYPE_NUM, UI_BTYPE_NUM_SLIDER)) {
ui_text_clip_right_label(fstyle, but, rect);
}
else if (but->flag & UI_BUT_HAS_SEP_CHAR) {
/* Clip middle, but protect in all case right part containing the shortcut, if any. */
ui_text_clip_middle_protect_right(fstyle, but, rect, UI_SEP_CHAR);
}
else {
ui_text_clip_middle(fstyle, but, rect);
}
/* always draw text for textbutton cursor */
widget_draw_text(fstyle, wcol, but, rect, str);
ui_but_text_password_hide(password_str, but, true);
}
#undef UI_TEXT_CLIP_MARGIN