This repository has been archived on 2023-10-09. You can view files and clone it, but cannot push or open issues or pull requests.
Files
blender-archive/source/blender/editors/interface/interface_widgets.c

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

5490 lines
164 KiB
C
Raw Normal View History

/*
* 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,
2010-02-12 13:34:04 +00:00
* Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*
* The Original Code is Copyright (C) 2009 Blender Foundation.
* All rights reserved.
*/
/** \file
* \ingroup edinterface
2011-02-27 20:29:51 +00:00
*/
#include <limits.h>
#include <stdlib.h>
#include <string.h>
#include "DNA_brush_types.h"
#include "DNA_userdef_types.h"
#include "BLI_listbase.h"
#include "BLI_math.h"
#include "BLI_rect.h"
#include "BLI_string.h"
#include "BLI_string_utf8.h"
#include "BLI_utildefines.h"
#include "BKE_context.h"
Changes to Color Management After testing and feedback, I've decided to slightly modify the way color management works internally. While the previous method worked well for rendering, was a smaller transition and had some advantages over this new method, it was a bit more ambiguous, and was making things difficult for other areas such as compositing. This implementation now considers all color data (with only a couple of exceptions such as brush colors) to be stored in linear RGB color space, rather than sRGB as previously. This brings it in line with Nuke, which also operates this way, quite successfully. Color swatches, pickers, color ramp display are now gamma corrected to display gamma so you can see what you're doing, but the numbers themselves are considered linear. This makes understanding blending modes more clear (a 0.5 value on overlay will not change the result now) as well as making color swatches act more predictably in the compositor, however bringing over color values from applications like photoshop or gimp, that operate in a gamma space, will give identical results. This commit will convert over existing files saved by earlier 2.5 versions to work generally the same, though there may be some slight differences with things like textures. Now that we're set on changing other areas of shading, this won't be too disruptive overall. I've made a diagram explaining the pipeline here: http://mke3.net/blender/devel/2.5/25_linear_workflow_pipeline.png and some docs here: http://www.blender.org/development/release-logs/blender-250/color-management/
2009-12-02 07:56:34 +00:00
#include "RNA_access.h"
#include "BLF_api.h"
#include "ED_node.h"
#include "UI_interface.h"
#include "UI_interface_icons.h"
#include "interface_intern.h"
#include "GPU_batch.h"
#include "GPU_batch_presets.h"
#include "GPU_immediate.h"
#include "GPU_immediate_util.h"
#include "GPU_matrix.h"
#include "GPU_platform.h"
#include "GPU_state.h"
#ifdef WITH_INPUT_IME
# include "WM_types.h"
#endif
2019-09-06 16:12:47 +10:00
/* -------------------------------------------------------------------- */
/** \name Local Enums/Defines
* \{ */
/* 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))
/* 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_TOOLBAR_ITEM,
UI_WTYPE_TAB,
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_ICON_LABEL,
UI_WTYPE_SWATCH,
UI_WTYPE_RGB_PICKER,
UI_WTYPE_UNITVEC,
UI_WTYPE_BOX,
UI_WTYPE_SCROLL,
UI_WTYPE_LISTITEM,
UI_WTYPE_PROGRESSBAR,
UI_WTYPE_NODESOCKET,
UI_WTYPE_DATASETROW,
} uiWidgetTypeEnum;
/* Button state argument shares bits with 'uiBut.flag'.
* reuse flags that aren't needed for drawing to avoid collision. */
enum {
/* Show that holding the button opens a menu. */
UI_STATE_HOLD_ACTION = UI_BUT_UPDATE_DELAY,
UI_STATE_TEXT_INPUT = UI_BUT_UNDO,
UI_STATE_ACTIVE_LEFT = UI_BUT_VALUE_CLEAR,
UI_STATE_ACTIVE_RIGHT = UI_BUT_TEXTEDIT_UPDATE,
UI_STATE_TEXT_BEFORE_WIDGET = UI_BUT_IMMEDIATE,
UI_STATE_FLAGS_ALL = (UI_STATE_HOLD_ACTION | UI_STATE_TEXT_INPUT | UI_STATE_ACTIVE_LEFT |
UI_STATE_ACTIVE_RIGHT | UI_STATE_TEXT_BEFORE_WIDGET),
};
/* Prevent accidental use. */
#define UI_BUT_UPDATE_DELAY ((void)0)
#define UI_BUT_UNDO ((void)0)
2017-11-03 00:22:59 +11:00
2019-09-06 16:12:47 +10:00
/** \} */
/* -------------------------------------------------------------------- */
/** \name Internal Color Utilities
* \{ */
static void color_blend_v3_v3(uchar cp[3], const uchar cpstate[3], const float fac)
{
if (fac != 0.0f) {
cp[0] = (int)((1.0f - fac) * cp[0] + fac * cpstate[0]);
cp[1] = (int)((1.0f - fac) * cp[1] + fac * cpstate[1]);
cp[2] = (int)((1.0f - fac) * cp[2] + fac * cpstate[2]);
}
}
static void color_blend_v4_v4v4(uchar r_col[4],
const uchar col1[4],
const uchar col2[4],
const float fac)
{
const int faci = unit_float_to_uchar_clamp(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;
}
static void color_add_v3_i(uchar cp[3], int tint)
{
cp[0] = clamp_i(cp[0] + tint, 0, 255);
cp[1] = clamp_i(cp[1] + tint, 0, 255);
cp[2] = clamp_i(cp[2] + tint, 0, 255);
}
static void color_ensure_contrast_v3(uchar cp[3], const uchar cp_other[3], int contrast)
{
BLI_assert(contrast > 0);
const int item_value = rgb_to_grayscale_byte(cp);
const int inner_value = rgb_to_grayscale_byte(cp_other);
const int delta = item_value - inner_value;
if (delta >= 0) {
if (contrast > delta) {
color_add_v3_i(cp, contrast - delta);
}
}
else {
if (contrast > -delta) {
color_add_v3_i(cp, -contrast - delta);
}
}
}
static void color_mul_hsl_v3(uchar ch[3], float h_factor, float s_factor, float l_factor)
{
float rgb[3], hsl[3];
rgb_uchar_to_float(rgb, ch);
rgb_to_hsl_v(rgb, hsl);
hsl[0] *= h_factor;
hsl[1] *= s_factor;
hsl[2] *= l_factor;
hsl_to_rgb_v(hsl, rgb);
rgb_float_to_uchar(ch, rgb);
}
/** \} */
/* -------------------------------------------------------------------- */
/** \name Widget Base Type
2019-09-06 16:12:47 +10:00
* \{ */
2015-05-31 14:20:03 +10:00
/**
* - in: roundbox codes for corner types and radius
2015-05-31 14:20:03 +10:00
* - 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 */
typedef struct uiWidgetTrias {
2019-01-04 11:05:53 +11:00
uint tot;
int type;
float size, center[2];
2013-05-08 12:56:11 +00:00
float vec[16][2];
2019-01-04 11:05:53 +11:00
const uint (*index)[3];
} uiWidgetTrias;
/* max as used by round_box__edges */
/* Make sure to change widget_base_vert.glsl accordingly. */
#define WIDGET_CURVE_RESOLU 9
2012-03-30 01:51:25 +00:00
#define WIDGET_SIZE_MAX (WIDGET_CURVE_RESOLU * 4)
typedef struct uiWidgetBase {
/* TODO: remove these completely. */
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;
uiWidgetTrias tria1;
uiWidgetTrias tria2;
/* Widget shader parameters, must match the shader layout. */
uiWidgetBaseParameters uniform_params;
} uiWidgetBase;
/**
* For time being only for visual appearance,
* later, a handling callback can be added too.
*/
typedef struct uiWidgetType {
/* pointer to theme color definition */
const uiWidgetColors *wcol_theme;
uiWidgetStateColors *wcol_state;
/* converted colors for state */
uiWidgetColors wcol;
void (*state)(struct uiWidgetType *, int state, int drawflag, eUIEmbossType emboss);
void (*draw)(uiWidgetColors *, rcti *, int state, int roundboxalign);
void (*custom)(uiBut *, uiWidgetColors *, rcti *, int state, int roundboxalign);
void (*text)(const uiFontStyle *, const uiWidgetColors *, uiBut *, rcti *);
} uiWidgetType;
2019-09-06 16:12:47 +10:00
/** \} */
/* -------------------------------------------------------------------- */
/** \name Shape Preset Data
* \{ */
2013-04-30 01:51:25 +00:00
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},
};
2018-04-20 15:15:10 +02:00
const float ui_pixel_jitter[UI_PIXEL_AA_JITTER][2] = {
2012-03-30 01:51:25 +00:00
{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},
2012-03-30 01:51:25 +00:00
};
2018-04-20 15:15:10 +02:00
#define WIDGET_AA_JITTER UI_PIXEL_AA_JITTER
#define jit ui_pixel_jitter
2012-03-30 01:51:25 +00:00
static const float g_shape_preset_number_arrow_vert[3][2] = {
{-0.352077, 0.532607},
{-0.352077, -0.549313},
{0.330000, -0.008353},
2012-03-30 01:51:25 +00:00
};
static const uint g_shape_preset_number_arrow_face[1][3] = {
{0, 1, 2},
2012-03-30 01:51:25 +00:00
};
static const float g_shape_preset_scroll_circle_vert[16][2] = {
2012-03-30 01:51:25 +00:00
{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},
2012-03-30 01:51:25 +00:00
};
static const uint g_shape_preset_scroll_circle_face[14][3] = {
2012-03-30 01:51:25 +00:00
{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},
2012-03-30 01:51:25 +00:00
};
static const float g_shape_preset_menu_arrow_vert[6][2] = {
2012-06-05 21:54:21 +00:00
{-0.33, 0.16},
{0.33, 0.16},
{0, 0.82},
{0, -0.82},
{-0.33, -0.16},
{0.33, -0.16},
2012-06-05 21:54:21 +00:00
};
static const uint g_shape_preset_menu_arrow_face[2][3] = {{2, 0, 1}, {3, 5, 4}};
static const float g_shape_preset_checkmark_vert[6][2] = {
2012-03-30 01:51:25 +00:00
{-0.578579, 0.253369},
{-0.392773, 0.412794},
{-0.004241, -0.328551},
{-0.003001, 0.034320},
{1.055313, 0.864744},
{0.866408, 1.026895},
2012-03-30 01:51:25 +00:00
};
static const uint g_shape_preset_checkmark_face[4][3] = {
{3, 2, 4},
{3, 4, 5},
{1, 0, 3},
{0, 2, 3},
2012-03-30 01:51:25 +00:00
};
#define OY (-0.2 / 2)
#define SC (0.35 * 2)
static const float g_shape_preset_hold_action_vert[6][2] = {
{-0.5 + SC, 1.0 + OY},
{0.5, 1.0 + OY},
{0.5, 0.0 + OY + SC},
};
static const uint g_shape_preset_hold_action_face[2][3] = {{2, 0, 1}, {3, 5, 4}};
#undef OY
#undef SC
/** \} */
2019-09-06 16:12:47 +10:00
/* -------------------------------------------------------------------- */
/** \name #GPUBatch Creation
*
* In order to speed up UI drawing we create some batches that are then
* modified by specialized shaders to draw certain elements really fast.
* TODO: find a better place. Maybe its own file?
2019-09-06 16:12:47 +10:00
*
* \{ */
static struct {
GPUBatch *roundbox_widget;
GPUBatch *roundbox_shadow;
/* TODO: remove. */
GPUVertFormat format;
uint vflag_id;
} g_ui_batch_cache = {0};
static GPUVertFormat *vflag_format(void)
{
if (g_ui_batch_cache.format.attr_len == 0) {
GPUVertFormat *format = &g_ui_batch_cache.format;
g_ui_batch_cache.vflag_id = GPU_vertformat_attr_add(
format, "vflag", GPU_COMP_U32, 1, GPU_FETCH_INT);
}
return &g_ui_batch_cache.format;
}
#define INNER 0
#define OUTLINE 1
#define EMBOSS 2
#define NO_AA 0
static void set_roundbox_vertex_data(GPUVertBufRaw *vflag_step, uint32_t d)
{
uint32_t *data = GPU_vertbuf_raw_step(vflag_step);
*data = d;
}
static uint32_t set_roundbox_vertex(GPUVertBufRaw *vflag_step,
int corner_id,
int corner_v,
int jit_v,
bool inner,
bool emboss,
int color)
{
uint32_t *data = GPU_vertbuf_raw_step(vflag_step);
*data = corner_id;
*data |= corner_v << 2;
*data |= jit_v << 6;
*data |= color << 12;
*data |= (inner) ? (1 << 10) : 0; /* is inner vert */
*data |= (emboss) ? (1 << 11) : 0; /* is emboss vert */
return *data;
}
GPUBatch *ui_batch_roundbox_widget_get(void)
{
if (g_ui_batch_cache.roundbox_widget == NULL) {
GPUVertBuf *vbo = GPU_vertbuf_create_with_format(vflag_format());
GPU_vertbuf_data_alloc(vbo, 12);
GPUIndexBufBuilder ibuf;
GPU_indexbuf_init(&ibuf, GPU_PRIM_TRIS, 6, 12);
/* Widget */
GPU_indexbuf_add_tri_verts(&ibuf, 0, 1, 2);
GPU_indexbuf_add_tri_verts(&ibuf, 2, 1, 3);
/* Trias */
GPU_indexbuf_add_tri_verts(&ibuf, 4, 5, 6);
GPU_indexbuf_add_tri_verts(&ibuf, 6, 5, 7);
GPU_indexbuf_add_tri_verts(&ibuf, 8, 9, 10);
GPU_indexbuf_add_tri_verts(&ibuf, 10, 9, 11);
g_ui_batch_cache.roundbox_widget = GPU_batch_create_ex(
GPU_PRIM_TRIS, vbo, GPU_indexbuf_build(&ibuf), GPU_BATCH_OWNS_INDEX | GPU_BATCH_OWNS_VBO);
gpu_batch_presets_register(g_ui_batch_cache.roundbox_widget);
}
return g_ui_batch_cache.roundbox_widget;
}
GPUBatch *ui_batch_roundbox_shadow_get(void)
{
if (g_ui_batch_cache.roundbox_shadow == NULL) {
uint32_t last_data;
GPUVertBufRaw vflag_step;
GPUVertBuf *vbo = GPU_vertbuf_create_with_format(vflag_format());
const int vcount = (WIDGET_SIZE_MAX + 1) * 2 + 2 + WIDGET_SIZE_MAX;
GPU_vertbuf_data_alloc(vbo, vcount);
GPU_vertbuf_attr_get_raw_data(vbo, g_ui_batch_cache.vflag_id, &vflag_step);
for (int c = 0; c < 4; c++) {
for (int a = 0; a < WIDGET_CURVE_RESOLU; a++) {
set_roundbox_vertex(&vflag_step, c, a, NO_AA, true, false, INNER);
set_roundbox_vertex(&vflag_step, c, a, NO_AA, false, false, INNER);
}
}
/* close loop */
last_data = set_roundbox_vertex(&vflag_step, 0, 0, NO_AA, true, false, INNER);
last_data = set_roundbox_vertex(&vflag_step, 0, 0, NO_AA, false, false, INNER);
/* restart */
set_roundbox_vertex_data(&vflag_step, last_data);
set_roundbox_vertex(&vflag_step, 0, 0, NO_AA, true, false, INNER);
/* filled */
for (int c1 = 0, c2 = 3; c1 < 2; c1++, c2--) {
for (int a1 = 0, a2 = WIDGET_CURVE_RESOLU - 1; a2 >= 0; a1++, a2--) {
set_roundbox_vertex(&vflag_step, c1, a1, NO_AA, true, false, INNER);
set_roundbox_vertex(&vflag_step, c2, a2, NO_AA, true, false, INNER);
}
}
g_ui_batch_cache.roundbox_shadow = GPU_batch_create_ex(
GPU_PRIM_TRI_STRIP, vbo, NULL, GPU_BATCH_OWNS_VBO);
gpu_batch_presets_register(g_ui_batch_cache.roundbox_shadow);
}
return g_ui_batch_cache.roundbox_shadow;
}
#undef INNER
#undef OUTLINE
#undef EMBOSS
#undef NO_AA
2019-09-06 16:12:47 +10:00
/** \} */
/* -------------------------------------------------------------------- */
/** \name Draw Triangle Arrow
* \{ */
void UI_draw_anti_tria(
float x1, float y1, float x2, float y2, float x3, float y3, const float color[4])
{
const float tri_arr[3][2] = {{x1, y1}, {x2, y2}, {x3, y3}};
float draw_color[4];
copy_v4_v4(draw_color, color);
/* NOTE: This won't give back the original color. */
draw_color[3] *= 1.0f / WIDGET_AA_JITTER;
GPU_blend(GPU_BLEND_ALPHA);
const uint pos = GPU_vertformat_attr_add(
immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
immUniformColor4fv(draw_color);
immBegin(GPU_PRIM_TRIS, 3 * WIDGET_AA_JITTER);
/* for each AA step */
for (int j = 0; j < WIDGET_AA_JITTER; j++) {
immVertex2f(pos, tri_arr[0][0] + jit[j][0], tri_arr[0][1] + jit[j][1]);
immVertex2f(pos, tri_arr[1][0] + jit[j][0], tri_arr[1][1] + jit[j][1]);
immVertex2f(pos, tri_arr[2][0] + jit[j][0], tri_arr[2][1] + jit[j][1]);
}
immEnd();
immUnbindProgram();
GPU_blend(GPU_BLEND_NONE);
}
/* Triangle 'icon' for panel header and other cases. */
void UI_draw_icon_tri(float x, float y, char dir, const float color[4])
{
const float f3 = 0.05 * U.widget_unit;
const float f5 = 0.15 * U.widget_unit;
const float f7 = 0.25 * U.widget_unit;
if (dir == 'h') {
UI_draw_anti_tria(x - f3, y - f5, x - f3, y + f5, x + f7, y, color);
}
else if (dir == 't') {
UI_draw_anti_tria(x - f5, y - f7, x + f5, y - f7, x, y + f3, color);
}
else { /* 'v' = vertical, down. */
UI_draw_anti_tria(x - f5, y + f3, x + f5, y + f3, x, y - f7, color);
}
}
/* triangle 'icon' inside rect */
void ui_draw_anti_tria_rect(const rctf *rect, char dir, const float color[4])
{
if (dir == 'h') {
const float half = 0.5f * BLI_rctf_size_y(rect);
UI_draw_anti_tria(
rect->xmin, rect->ymin, rect->xmin, rect->ymax, rect->xmax, rect->ymin + half, color);
}
else {
const float half = 0.5f * BLI_rctf_size_x(rect);
UI_draw_anti_tria(
rect->xmin, rect->ymax, rect->xmax, rect->ymax, rect->xmin + half, rect->ymin, color);
}
}
2019-01-04 11:05:53 +11:00
void UI_draw_anti_fan(float tri_array[][2], uint length, const float color[4])
{
float draw_color[4];
copy_v4_v4(draw_color, color);
draw_color[3] *= 2.0f / WIDGET_AA_JITTER;
GPU_blend(GPU_BLEND_ALPHA);
const uint pos = GPU_vertformat_attr_add(
immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
immUniformColor4fv(draw_color);
/* for each AA step */
for (int j = 0; j < WIDGET_AA_JITTER; j++) {
immBegin(GPU_PRIM_TRI_FAN, length);
immVertex2f(pos, tri_array[0][0], tri_array[0][1]);
immVertex2f(pos, tri_array[1][0], tri_array[1][1]);
/* We jitter only the middle of the fan, the extremes are pinned. */
for (int i = 2; i < length - 1; i++) {
immVertex2f(pos, tri_array[i][0] + jit[j][0], tri_array[i][1] + jit[j][1]);
}
immVertex2f(pos, tri_array[length - 1][0], tri_array[length - 1][1]);
immEnd();
}
immUnbindProgram();
GPU_blend(GPU_BLEND_NONE);
}
static void widget_init(uiWidgetBase *wtb)
{
2012-03-30 01:51:25 +00:00
wtb->totvert = wtb->halfwayvert = 0;
wtb->tria1.tot = 0;
wtb->tria2.tot = 0;
wtb->tria1.type = ROUNDBOX_TRIA_NONE;
wtb->tria1.size = 0;
wtb->tria2.size = 0;
wtb->draw_inner = true;
wtb->draw_outline = true;
wtb->draw_emboss = true;
wtb->uniform_params.shade_dir = 1.0f;
wtb->uniform_params.alpha_discard = 1.0f;
}
2019-09-06 16:12:47 +10:00
/** \} */
/* -------------------------------------------------------------------- */
/** \name Draw Round Box
* \{ */
/* 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];
int tot = 0;
2012-03-30 01:51:25 +00:00
rad += step;
2019-03-25 10:15:20 +11:00
if (2.0f * rad > BLI_rcti_size_y(rect)) {
rad = 0.5f * BLI_rcti_size_y(rect);
2019-03-25 10:15:20 +11:00
}
const float minx = rect->xmin - step;
const float miny = rect->ymin - step;
const float maxx = rect->xmax + step;
const float maxy = rect->ymax + step;
2021-03-10 15:47:50 +11:00
/* Multiply. */
for (int a = 0; a < WIDGET_CURVE_RESOLU; a++) {
2012-03-30 01:51:25 +00:00
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 (int a = 0; a < WIDGET_CURVE_RESOLU; a++, tot++) {
2012-03-30 01:51:25 +00:00
vert[tot][0] = minx + rad - vec[a][0];
vert[tot][1] = maxy - vec[a][1];
}
}
else {
for (int a = 0; a < WIDGET_CURVE_RESOLU; a++, tot++) {
2012-03-30 01:51:25 +00:00
vert[tot][0] = minx;
vert[tot][1] = maxy;
}
}
if (roundboxalign & UI_CNR_BOTTOM_LEFT) {
for (int a = 0; a < WIDGET_CURVE_RESOLU; a++, tot++) {
2012-03-30 01:51:25 +00:00
vert[tot][0] = minx + vec[a][1];
vert[tot][1] = miny + rad - vec[a][0];
}
}
else {
for (int a = 0; a < WIDGET_CURVE_RESOLU; a++, tot++) {
2012-03-30 01:51:25 +00:00
vert[tot][0] = minx;
vert[tot][1] = miny;
}
}
if (roundboxalign & UI_CNR_BOTTOM_RIGHT) {
for (int a = 0; a < WIDGET_CURVE_RESOLU; a++, tot++) {
2012-03-30 01:51:25 +00:00
vert[tot][0] = maxx - rad + vec[a][0];
vert[tot][1] = miny + vec[a][1];
}
}
else {
for (int a = 0; a < WIDGET_CURVE_RESOLU; a++, tot++) {
2012-03-30 01:51:25 +00:00
vert[tot][0] = maxx;
vert[tot][1] = miny;
}
}
if (roundboxalign & UI_CNR_TOP_RIGHT) {
for (int a = 0; a < WIDGET_CURVE_RESOLU; a++, tot++) {
2012-03-30 01:51:25 +00:00
vert[tot][0] = maxx - vec[a][1];
vert[tot][1] = maxy - rad + vec[a][0];
}
}
else {
for (int a = 0; a < WIDGET_CURVE_RESOLU; a++, tot++) {
2012-03-30 01:51:25 +00:00
vert[tot][0] = maxx;
vert[tot][1] = maxy;
}
}
return tot;
}
/* this call has 1 extra arg to allow mask outline */
static void round_box__edges(
uiWidgetBase *wt, int roundboxalign, const rcti *rect, float rad, float radi)
{
float vec[WIDGET_CURVE_RESOLU][2], veci[WIDGET_CURVE_RESOLU][2];
const float minx = rect->xmin, miny = rect->ymin, maxx = rect->xmax, maxy = rect->ymax;
const float minxi = minx + U.pixelsize; /* boundbox inner */
const float maxxi = maxx - U.pixelsize;
const float minyi = miny + U.pixelsize;
const float maxyi = maxy - U.pixelsize;
/* for uv, can divide by zero */
const float facxi = (maxxi != minxi) ? 1.0f / (maxxi - minxi) : 0.0f;
const float facyi = (maxyi != minyi) ? 1.0f / (maxyi - minyi) : 0.0f;
int tot = 0;
2018-07-01 19:57:31 +02:00
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;
2021-01-04 17:02:13 +11:00
const int minsize = min_ii(BLI_rcti_size_x(rect) * hnum, BLI_rcti_size_y(rect) * vnum);
2019-03-25 10:15:20 +11:00
if (2.0f * rad > minsize) {
2012-03-30 01:51:25 +00:00
rad = 0.5f * minsize;
2019-03-25 10:15:20 +11:00
}
2019-03-25 10:15:20 +11:00
if (2.0f * (radi + 1.0f) > minsize) {
Holiday coding log :) Nice formatted version (pictures soon): http://wiki.blender.org/index.php/Dev:Ref/Release_Notes/2.66/Usability Short list of main changes: - Transparent region option (over main region), added code to blend in/out such panels. - Min size window now 640 x 480 - Fixed DPI for ui - lots of cleanup and changes everywhere. Icon image need correct size still, layer-in-use icon needs remake. - Macbook retina support, use command line --no-native-pixels to disable it - Timeline Marker label was drawing wrong - Trackpad and magic mouse: supports zoom (hold ctrl) - Fix for splash position: removed ghost function and made window size update after creation immediate - Fast undo buffer save now adds UI as well. Could be checked for regular file save even... Quit.blend and temp file saving use this now. - Dixed filename in window on reading quit.blend or temp saves, and they now add a warning in window title: "(Recovered)" - New Userpref option "Keep Session" - this always saves quit.blend, and loads on start. This allows keeping UI and data without actual saves, until you actually save. When you load startup.blend and quit, it recognises the quit.blend as a startup (no file name in header) - Added 3D view copy/paste buffers (selected objects). Shortcuts ctrl-c, ctrl-v (OSX, cmd-c, cmd-v). Coded partial file saving for it. Could be used for other purposes. Todo: use OS clipboards. - User preferences (themes, keymaps, user settings) now can be saved as a separate file. Old option is called "Save Startup File" the new one "Save User Settings". To visualise this difference, the 'save startup file' button has been removed from user preferences window. That option is available as CTRL+U and in File menu still. - OSX: fixed bug that stopped giving mouse events outside window. This also fixes "Continuous Grab" for OSX. (error since 2009)
2012-12-12 18:58:11 +00:00
radi = 0.5f * minsize - U.pixelsize;
2019-03-25 10:15:20 +11:00
}
wt->uniform_params.rad = rad;
wt->uniform_params.radi = radi;
wt->uniform_params.facxi = facxi;
wt->uniform_params.facyi = facyi;
wt->uniform_params.round_corners[0] = (roundboxalign & UI_CNR_BOTTOM_LEFT) ? 1.0f : 0.0f;
wt->uniform_params.round_corners[1] = (roundboxalign & UI_CNR_BOTTOM_RIGHT) ? 1.0f : 0.0f;
wt->uniform_params.round_corners[2] = (roundboxalign & UI_CNR_TOP_RIGHT) ? 1.0f : 0.0f;
wt->uniform_params.round_corners[3] = (roundboxalign & UI_CNR_TOP_LEFT) ? 1.0f : 0.0f;
BLI_rctf_rcti_copy(&wt->uniform_params.rect, rect);
BLI_rctf_init(&wt->uniform_params.recti, minxi, maxxi, minyi, maxyi);
2021-07-05 12:47:46 +10:00
/* Multiply by radius. */
for (int a = 0; a < WIDGET_CURVE_RESOLU; a++) {
2012-03-30 01:51:25 +00:00
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 (int a = 0; a < WIDGET_CURVE_RESOLU; a++, tot++) {
2012-03-30 01:51:25 +00:00
wt->inner_v[tot][0] = minxi + veci[a][1];
wt->inner_v[tot][1] = minyi + radi - veci[a][0];
2012-03-30 01:51:25 +00:00
wt->outer_v[tot][0] = minx + vec[a][1];
wt->outer_v[tot][1] = miny + rad - vec[a][0];
2012-03-30 01:51:25 +00:00
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 {
2012-03-30 01:51:25 +00:00
wt->inner_v[tot][0] = minxi;
wt->inner_v[tot][1] = minyi;
2012-03-30 01:51:25 +00:00
wt->outer_v[tot][0] = minx;
wt->outer_v[tot][1] = miny;
2012-03-30 01:51:25 +00:00
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 (int a = 0; a < WIDGET_CURVE_RESOLU; a++, tot++) {
2012-03-30 01:51:25 +00:00
wt->inner_v[tot][0] = maxxi - radi + veci[a][0];
wt->inner_v[tot][1] = minyi + veci[a][1];
2012-03-30 01:51:25 +00:00
wt->outer_v[tot][0] = maxx - rad + vec[a][0];
wt->outer_v[tot][1] = miny + vec[a][1];
2012-03-30 01:51:25 +00:00
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 {
2012-03-30 01:51:25 +00:00
wt->inner_v[tot][0] = maxxi;
wt->inner_v[tot][1] = minyi;
2012-03-30 01:51:25 +00:00
wt->outer_v[tot][0] = maxx;
wt->outer_v[tot][1] = miny;
2012-03-30 01:51:25 +00:00
wt->inner_uv[tot][0] = 1.0f;
wt->inner_uv[tot][1] = 0.0f;
tot++;
}
2012-03-30 01:51:25 +00:00
wt->halfwayvert = tot;
/* corner right-top */
if (roundboxalign & UI_CNR_TOP_RIGHT) {
for (int a = 0; a < WIDGET_CURVE_RESOLU; a++, tot++) {
2012-03-30 01:51:25 +00:00
wt->inner_v[tot][0] = maxxi - veci[a][1];
wt->inner_v[tot][1] = maxyi - radi + veci[a][0];
2012-03-30 01:51:25 +00:00
wt->outer_v[tot][0] = maxx - vec[a][1];
wt->outer_v[tot][1] = maxy - rad + vec[a][0];
2012-03-30 01:51:25 +00:00
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 {
2012-03-30 01:51:25 +00:00
wt->inner_v[tot][0] = maxxi;
wt->inner_v[tot][1] = maxyi;
2012-03-30 01:51:25 +00:00
wt->outer_v[tot][0] = maxx;
wt->outer_v[tot][1] = maxy;
2012-03-30 01:51:25 +00:00
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 (int a = 0; a < WIDGET_CURVE_RESOLU; a++, tot++) {
2012-03-30 01:51:25 +00:00
wt->inner_v[tot][0] = minxi + radi - veci[a][0];
wt->inner_v[tot][1] = maxyi - veci[a][1];
2012-03-30 01:51:25 +00:00
wt->outer_v[tot][0] = minx + rad - vec[a][0];
wt->outer_v[tot][1] = maxy - vec[a][1];
2012-03-30 01:51:25 +00:00
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 {
2012-03-30 01:51:25 +00:00
wt->inner_v[tot][0] = minxi;
wt->inner_v[tot][1] = maxyi;
2012-03-30 01:51:25 +00:00
wt->outer_v[tot][0] = minx;
wt->outer_v[tot][1] = maxy;
2012-03-30 01:51:25 +00:00
wt->inner_uv[tot][0] = 0.0f;
wt->inner_uv[tot][1] = 1.0f;
2012-03-30 01:51:25 +00:00
tot++;
}
BLI_assert(tot <= WIDGET_SIZE_MAX);
2012-03-30 01:51:25 +00:00
wt->totvert = tot;
}
static void round_box_edges(uiWidgetBase *wt, int roundboxalign, const rcti *rect, float rad)
{
Holiday coding log :) Nice formatted version (pictures soon): http://wiki.blender.org/index.php/Dev:Ref/Release_Notes/2.66/Usability Short list of main changes: - Transparent region option (over main region), added code to blend in/out such panels. - Min size window now 640 x 480 - Fixed DPI for ui - lots of cleanup and changes everywhere. Icon image need correct size still, layer-in-use icon needs remake. - Macbook retina support, use command line --no-native-pixels to disable it - Timeline Marker label was drawing wrong - Trackpad and magic mouse: supports zoom (hold ctrl) - Fix for splash position: removed ghost function and made window size update after creation immediate - Fast undo buffer save now adds UI as well. Could be checked for regular file save even... Quit.blend and temp file saving use this now. - Dixed filename in window on reading quit.blend or temp saves, and they now add a warning in window title: "(Recovered)" - New Userpref option "Keep Session" - this always saves quit.blend, and loads on start. This allows keeping UI and data without actual saves, until you actually save. When you load startup.blend and quit, it recognises the quit.blend as a startup (no file name in header) - Added 3D view copy/paste buffers (selected objects). Shortcuts ctrl-c, ctrl-v (OSX, cmd-c, cmd-v). Coded partial file saving for it. Could be used for other purposes. Todo: use OS clipboards. - User preferences (themes, keymaps, user settings) now can be saved as a separate file. Old option is called "Save Startup File" the new one "Save User Settings". To visualise this difference, the 'save startup file' button has been removed from user preferences window. That option is available as CTRL+U and in File menu still. - OSX: fixed bug that stopped giving mouse events outside window. This also fixes "Continuous Grab" for OSX. (error since 2009)
2012-12-12 18:58:11 +00:00
round_box__edges(wt, roundboxalign, rect, rad, rad - U.pixelsize);
}
2019-09-06 16:12:47 +10:00
/** \} */
/* -------------------------------------------------------------------- */
/** \name Shape Preset Mini API
* \{ */
/* based on button rect, return scaled array of triangles */
static void shape_preset_init_trias_ex(uiWidgetTrias *tria,
const rcti *rect,
float triasize,
char where,
/* input data */
const float verts[][2],
const int verts_tot,
2019-01-04 11:05:53 +11:00
const uint tris[][3],
const int tris_tot)
{
float sizex, sizey;
int i1 = 0, i2 = 1;
2021-01-04 17:02:13 +11:00
const float minsize = ELEM(where, 'r', 'l') ? BLI_rcti_size_y(rect) : BLI_rcti_size_x(rect);
/* center position and size */
float centx = (float)rect->xmin + 0.4f * minsize;
float centy = (float)rect->ymin + 0.5f * minsize;
tria->size = sizex = sizey = -0.5f * triasize * minsize;
2012-03-30 01:51:25 +00:00
if (where == 'r') {
centx = (float)rect->xmax - 0.4f * minsize;
2012-03-30 01:51:25 +00:00
sizex = -sizex;
}
2012-03-30 01:51:25 +00:00
else if (where == 't') {
centx = (float)rect->xmin + 0.5f * minsize;
2012-03-30 01:51:25 +00:00
centy = (float)rect->ymax - 0.5f * minsize;
sizey = -sizey;
i2 = 0;
i1 = 1;
}
2012-03-30 01:51:25 +00:00
else if (where == 'b') {
centx = (float)rect->xmin + 0.5f * minsize;
2012-03-30 01:51:25 +00:00
sizex = -sizex;
i2 = 0;
i1 = 1;
}
for (int 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->center[0] = centx;
tria->center[1] = centy;
tria->tot = tris_tot;
tria->index = tris;
}
static void shape_preset_init_number_arrows(uiWidgetTrias *tria,
const rcti *rect,
float triasize,
char where)
{
tria->type = ROUNDBOX_TRIA_ARROWS;
shape_preset_init_trias_ex(tria,
rect,
triasize,
where,
g_shape_preset_number_arrow_vert,
ARRAY_SIZE(g_shape_preset_number_arrow_vert),
g_shape_preset_number_arrow_face,
ARRAY_SIZE(g_shape_preset_number_arrow_face));
}
static void shape_preset_init_hold_action(uiWidgetTrias *tria,
const rcti *rect,
float triasize,
char where)
{
tria->type = ROUNDBOX_TRIA_HOLD_ACTION_ARROW;
/* With the current changes to use batches for widget drawing, the code
* below is doing almost nothing effectively. 'where' doesn't work either,
* shader is currently hardcoded to work for the button triangle pointing
* at the lower right. The same limitation applies to other trias as well.
* XXX Should be addressed. */
shape_preset_init_trias_ex(tria,
rect,
triasize,
where,
g_shape_preset_hold_action_vert,
ARRAY_SIZE(g_shape_preset_hold_action_vert),
g_shape_preset_hold_action_face,
ARRAY_SIZE(g_shape_preset_hold_action_face));
}
static void shape_preset_init_scroll_circle(uiWidgetTrias *tria,
const rcti *rect,
float triasize,
char where)
{
tria->type = ROUNDBOX_TRIA_SCROLL;
shape_preset_init_trias_ex(tria,
rect,
triasize,
where,
g_shape_preset_scroll_circle_vert,
ARRAY_SIZE(g_shape_preset_scroll_circle_vert),
g_shape_preset_scroll_circle_face,
ARRAY_SIZE(g_shape_preset_scroll_circle_face));
}
2019-01-04 11:05:53 +11:00
static void widget_draw_vertex_buffer(uint pos,
uint col,
int mode,
const float quads_pos[WIDGET_SIZE_MAX][2],
2019-01-04 11:05:53 +11:00
const uchar quads_col[WIDGET_SIZE_MAX][4],
uint totvert)
{
immBegin(mode, totvert);
for (int i = 0; i < totvert; i++) {
2019-03-25 10:15:20 +11:00
if (quads_col) {
immAttr4ubv(col, quads_col[i]);
2019-03-25 10:15:20 +11:00
}
immVertex2fv(pos, quads_pos[i]);
}
immEnd();
}
static void shape_preset_trias_from_rect_menu(uiWidgetTrias *tria, const rcti *rect)
{
const float width = BLI_rcti_size_x(rect);
const float height = BLI_rcti_size_y(rect);
float centx, centy, size;
tria->type = ROUNDBOX_TRIA_MENU;
/* Center position and size. */
tria->center[0] = centx = rect->xmin + 0.52f * BLI_rcti_size_y(rect);
tria->center[1] = centy = rect->ymin + 0.52f * BLI_rcti_size_y(rect);
tria->size = size = 0.4f * height;
if (width > height * 1.1f) {
/* For wider buttons align tighter to the right. */
tria->center[0] = centx = rect->xmax - 0.32f * height;
}
for (int a = 0; a < 6; a++) {
tria->vec[a][0] = size * g_shape_preset_menu_arrow_vert[a][0] + centx;
tria->vec[a][1] = size * g_shape_preset_menu_arrow_vert[a][1] + centy;
}
2012-03-30 01:51:25 +00:00
tria->tot = 2;
tria->index = g_shape_preset_menu_arrow_face;
}
static void shape_preset_trias_from_rect_checkmark(uiWidgetTrias *tria, const rcti *rect)
{
float centx, centy, size;
tria->type = ROUNDBOX_TRIA_CHECK;
/* Center position and size. */
tria->center[0] = centx = rect->xmin + 0.5f * BLI_rcti_size_y(rect);
tria->center[1] = centy = rect->ymin + 0.5f * BLI_rcti_size_y(rect);
tria->size = size = 0.5f * BLI_rcti_size_y(rect);
for (int a = 0; a < 6; a++) {
tria->vec[a][0] = size * g_shape_preset_checkmark_vert[a][0] + centx;
tria->vec[a][1] = size * g_shape_preset_checkmark_vert[a][1] + centy;
}
2012-03-30 01:51:25 +00:00
tria->tot = 4;
tria->index = g_shape_preset_checkmark_face;
}
/** \} */
2019-09-06 16:12:47 +10:00
/* -------------------------------------------------------------------- */
/** \name Widget Base Drawing
2019-09-06 16:12:47 +10:00
* \{ */
/* prepares shade colors */
static void shadecolors4(
uchar coltop[4], uchar coldown[4], const uchar *color, short shadetop, short shadedown)
{
2012-03-30 01:51:25 +00:00
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];
2012-03-30 01:51:25 +00:00
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 widget_verts_to_triangle_strip(uiWidgetBase *wtb,
const int totvert,
float triangle_strip[WIDGET_SIZE_MAX * 2 + 2][2])
{
int a;
2012-03-30 01:51:25 +00:00
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]);
}
2019-01-04 11:05:53 +11:00
static void widgetbase_outline(uiWidgetBase *wtb, uint pos)
{
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);
widget_draw_vertex_buffer(
pos, 0, GPU_PRIM_TRI_STRIP, triangle_strip, NULL, wtb->totvert * 2 + 2);
}
static void widgetbase_set_uniform_alpha_discard(uiWidgetBase *wtb,
const bool alpha_check,
const float discard_factor)
{
if (alpha_check) {
wtb->uniform_params.alpha_discard = -discard_factor;
}
else {
wtb->uniform_params.alpha_discard = discard_factor;
}
}
static void widgetbase_set_uniform_alpha_check(uiWidgetBase *wtb, const bool alpha_check)
{
const float discard_factor = fabs(wtb->uniform_params.alpha_discard);
widgetbase_set_uniform_alpha_discard(wtb, alpha_check, discard_factor);
}
static void widgetbase_set_uniform_discard_factor(uiWidgetBase *wtb, const float discard_factor)
{
const bool alpha_check = wtb->uniform_params.alpha_discard < 0.0f;
widgetbase_set_uniform_alpha_discard(wtb, alpha_check, discard_factor);
}
static void widgetbase_set_uniform_colors_ubv(uiWidgetBase *wtb,
2019-01-04 11:05:53 +11:00
const uchar *col1,
const uchar *col2,
const uchar *outline,
const uchar *emboss,
const uchar *tria,
const bool alpha_check)
{
widgetbase_set_uniform_alpha_check(wtb, alpha_check);
rgba_float_args_set_ch(wtb->uniform_params.color_inner1, col1[0], col1[1], col1[2], col1[3]);
rgba_float_args_set_ch(wtb->uniform_params.color_inner2, col2[0], col2[1], col2[2], col2[3]);
rgba_float_args_set_ch(
wtb->uniform_params.color_outline, outline[0], outline[1], outline[2], outline[3]);
rgba_float_args_set_ch(
wtb->uniform_params.color_emboss, emboss[0], emboss[1], emboss[2], emboss[3]);
rgba_float_args_set_ch(wtb->uniform_params.color_tria, tria[0], tria[1], tria[2], tria[3]);
}
/** \} */
/* -------------------------------------------------------------------- */
/** \name Widget Base Drawing #GPUBatch Cache
* \{ */
/* keep in sync with shader */
#define MAX_WIDGET_BASE_BATCH 6
#define MAX_WIDGET_PARAMETERS 12
2018-07-31 20:44:49 +10:00
static struct {
uiWidgetBaseParameters params[MAX_WIDGET_BASE_BATCH];
int count;
bool enabled;
} g_widget_base_batch = {{{{0}}}};
void UI_widgetbase_draw_cache_flush(void)
{
2019-09-14 08:10:50 +10:00
const float checker_params[3] = {
UI_ALPHA_CHECKER_DARK / 255.0f, UI_ALPHA_CHECKER_LIGHT / 255.0f, 8.0f};
2019-03-25 10:15:20 +11:00
if (g_widget_base_batch.count == 0) {
return;
2019-03-25 10:15:20 +11:00
}
GPUBatch *batch = ui_batch_roundbox_widget_get();
if (g_widget_base_batch.count == 1) {
/* draw single */
GPU_batch_program_set_builtin(batch, GPU_SHADER_2D_WIDGET_BASE);
GPU_batch_uniform_4fv_array(
2021-03-04 16:57:30 +11:00
batch, "parameters", MAX_WIDGET_PARAMETERS, (const float(*)[4])g_widget_base_batch.params);
GPU_batch_uniform_3fv(batch, "checkerColorAndSize", checker_params);
GPU_batch_draw(batch);
}
else {
GPU_batch_program_set_builtin(batch, GPU_SHADER_2D_WIDGET_BASE_INST);
GPU_batch_uniform_4fv_array(batch,
"parameters",
MAX_WIDGET_PARAMETERS * MAX_WIDGET_BASE_BATCH,
(float(*)[4])g_widget_base_batch.params);
GPU_batch_uniform_3fv(batch, "checkerColorAndSize", checker_params);
GPU_batch_draw_instanced(batch, g_widget_base_batch.count);
}
g_widget_base_batch.count = 0;
}
void UI_widgetbase_draw_cache_begin(void)
{
BLI_assert(g_widget_base_batch.enabled == false);
g_widget_base_batch.enabled = true;
}
void UI_widgetbase_draw_cache_end(void)
{
BLI_assert(g_widget_base_batch.enabled == true);
g_widget_base_batch.enabled = false;
GPU_blend(GPU_BLEND_ALPHA);
UI_widgetbase_draw_cache_flush();
GPU_blend(GPU_BLEND_NONE);
}
/* Disable cached/instanced drawing and enforce single widget drawing pipeline.
* Works around interface artifacts happening on certain driver and hardware
* configurations. */
static bool draw_widgetbase_batch_skip_draw_cache(void)
{
/* MacOS is known to have issues on Mac Mini and MacBook Pro with Intel Iris GPU.
* For example, T78307. */
if (GPU_type_matches(GPU_DEVICE_INTEL, GPU_OS_MAC, GPU_DRIVER_ANY)) {
return true;
}
return false;
}
static void draw_widgetbase_batch(uiWidgetBase *wtb)
{
wtb->uniform_params.tria_type = wtb->tria1.type;
wtb->uniform_params.tria1_size = wtb->tria1.size;
wtb->uniform_params.tria2_size = wtb->tria2.size;
copy_v2_v2(wtb->uniform_params.tria1_center, wtb->tria1.center);
copy_v2_v2(wtb->uniform_params.tria2_center, wtb->tria2.center);
if (g_widget_base_batch.enabled && !draw_widgetbase_batch_skip_draw_cache()) {
g_widget_base_batch.params[g_widget_base_batch.count] = wtb->uniform_params;
g_widget_base_batch.count++;
if (g_widget_base_batch.count == MAX_WIDGET_BASE_BATCH) {
UI_widgetbase_draw_cache_flush();
}
}
else {
2019-09-14 08:10:50 +10:00
const float checker_params[3] = {
UI_ALPHA_CHECKER_DARK / 255.0f, UI_ALPHA_CHECKER_LIGHT / 255.0f, 8.0f};
/* draw single */
GPUBatch *batch = ui_batch_roundbox_widget_get();
GPU_batch_program_set_builtin(batch, GPU_SHADER_2D_WIDGET_BASE);
2018-09-11 14:31:19 +10:00
GPU_batch_uniform_4fv_array(
batch, "parameters", MAX_WIDGET_PARAMETERS, (float(*)[4]) & wtb->uniform_params);
GPU_batch_uniform_3fv(batch, "checkerColorAndSize", checker_params);
GPU_batch_draw(batch);
}
}
2018-09-12 16:21:00 +10:00
static void widgetbase_draw_ex(uiWidgetBase *wtb,
const uiWidgetColors *wcol,
bool show_alpha_checkers)
{
2019-01-04 11:05:53 +11:00
uchar inner_col1[4] = {0};
uchar inner_col2[4] = {0};
uchar emboss_col[4] = {0};
uchar outline_col[4] = {0};
uchar tria_col[4] = {0};
/* For color widget. */
2018-09-12 16:21:00 +10:00
if (wcol->shaded != 0) {
show_alpha_checkers = false;
}
/* backdrop non AA */
if (wtb->draw_inner) {
2012-03-30 01:51:25 +00:00
if (wcol->shaded == 0) {
/* simple fill */
inner_col1[0] = inner_col2[0] = wcol->inner[0];
inner_col1[1] = inner_col2[1] = wcol->inner[1];
inner_col1[2] = inner_col2[2] = wcol->inner[2];
inner_col1[3] = inner_col2[3] = wcol->inner[3];
}
else {
/* gradient fill */
shadecolors4(inner_col1, inner_col2, wcol->inner, wcol->shadetop, wcol->shadedown);
}
}
if (wtb->draw_outline) {
outline_col[0] = wcol->outline[0];
outline_col[1] = wcol->outline[1];
outline_col[2] = wcol->outline[2];
outline_col[3] = wcol->outline[3];
/* emboss bottom shadow */
if (wtb->draw_emboss) {
UI_GetThemeColor4ubv(TH_WIDGET_EMBOSS, emboss_col);
}
}
2018-04-19 07:47:03 +02:00
if (wtb->tria1.type != ROUNDBOX_TRIA_NONE) {
tria_col[0] = wcol->item[0];
tria_col[1] = wcol->item[1];
tria_col[2] = wcol->item[2];
tria_col[3] = wcol->item[3];
}
2021-02-05 16:23:34 +11:00
/* Draw everything in one draw-call. */
2018-09-12 16:21:00 +10:00
if (inner_col1[3] || inner_col2[3] || outline_col[3] || emboss_col[3] || tria_col[3] ||
show_alpha_checkers) {
widgetbase_set_uniform_colors_ubv(
wtb, inner_col1, inner_col2, outline_col, emboss_col, tria_col, show_alpha_checkers);
GPU_blend(GPU_BLEND_ALPHA);
draw_widgetbase_batch(wtb);
GPU_blend(GPU_BLEND_NONE);
}
}
2018-09-12 16:21:00 +10:00
static void widgetbase_draw(uiWidgetBase *wtb, const uiWidgetColors *wcol)
{
widgetbase_draw_ex(wtb, wcol, false);
}
2019-09-06 16:12:47 +10:00
/** \} */
/* -------------------------------------------------------------------- */
/** \name Text/Icon Drawing
* \{ */
#define UI_TEXT_CLIP_MARGIN (0.25f * U.widget_unit / but->block->aspect)
2012-03-30 01:51:25 +00:00
#define PREVIEW_PAD 4
static float widget_alpha_factor(const int state)
{
if (state & (UI_BUT_INACTIVE | UI_BUT_DISABLED)) {
if (state & UI_SEARCH_FILTER_NO_MATCH) {
return 0.25f;
}
return 0.5f;
}
if (state & UI_SEARCH_FILTER_NO_MATCH) {
return 0.5f;
}
return 1.0f;
}
static void widget_draw_preview(BIFIconID icon, float alpha, const rcti *rect)
{
2019-03-25 10:15:20 +11:00
if (icon == ICON_NONE) {
return;
2019-03-25 10:15:20 +11:00
}
const int w = BLI_rcti_size_x(rect);
const int h = BLI_rcti_size_y(rect);
const int size = MIN2(w, h) - PREVIEW_PAD * 2;
if (size > 0) {
const int x = rect->xmin + w / 2 - size / 2;
const int y = rect->ymin + h / 2 - size / 2;
UI_icon_draw_preview(x, y, icon, 1.0f, alpha, size);
}
}
static int ui_but_draw_menu_icon(const uiBut *but)
{
return (but->flag & UI_BUT_ICON_SUBMENU) && (but->emboss == 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 uchar mono_color[4])
{
Holiday coding log :) Nice formatted version (pictures soon): http://wiki.blender.org/index.php/Dev:Ref/Release_Notes/2.66/Usability Short list of main changes: - Transparent region option (over main region), added code to blend in/out such panels. - Min size window now 640 x 480 - Fixed DPI for ui - lots of cleanup and changes everywhere. Icon image need correct size still, layer-in-use icon needs remake. - Macbook retina support, use command line --no-native-pixels to disable it - Timeline Marker label was drawing wrong - Trackpad and magic mouse: supports zoom (hold ctrl) - Fix for splash position: removed ghost function and made window size update after creation immediate - Fast undo buffer save now adds UI as well. Could be checked for regular file save even... Quit.blend and temp file saving use this now. - Dixed filename in window on reading quit.blend or temp saves, and they now add a warning in window title: "(Recovered)" - New Userpref option "Keep Session" - this always saves quit.blend, and loads on start. This allows keeping UI and data without actual saves, until you actually save. When you load startup.blend and quit, it recognises the quit.blend as a startup (no file name in header) - Added 3D view copy/paste buffers (selected objects). Shortcuts ctrl-c, ctrl-v (OSX, cmd-c, cmd-v). Coded partial file saving for it. Could be used for other purposes. Todo: use OS clipboards. - User preferences (themes, keymaps, user settings) now can be saved as a separate file. Old option is called "Save Startup File" the new one "Save User Settings". To visualise this difference, the 'save startup file' button has been removed from user preferences window. That option is available as CTRL+U and in File menu still. - OSX: fixed bug that stopped giving mouse events outside window. This also fixes "Continuous Grab" for OSX. (error since 2009)
2012-12-12 18:58:11 +00:00
float xs = 0.0f, ys = 0.0f;
if (but->flag & UI_BUT_ICON_PREVIEW) {
GPU_blend(GPU_BLEND_ALPHA);
widget_draw_preview(icon, alpha, rect);
GPU_blend(GPU_BLEND_NONE);
return;
}
/* this icon doesn't need draw... */
2019-03-25 10:15:20 +11:00
if (icon == ICON_BLANK1 && (but->flag & UI_BUT_ICON_SUBMENU) == 0) {
return;
}
2021-01-04 17:02:13 +11:00
const float aspect = but->block->aspect * U.inv_dpi_fac;
const float 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)) {
2019-03-25 10:15:20 +11:00
if (but->flag & UI_SELECT) {
/* pass */
}
else if (but->flag & UI_ACTIVE) {
/* pass */
}
else {
alpha = 0.75f;
}
2019-03-25 10:15:20 +11:00
}
else if ((but->type == UI_BTYPE_LABEL)) {
/* extra feature allows more alpha blending */
if (but->a1 == 1.0f) {
alpha *= but->a2;
}
}
else if (ELEM(but->type, UI_BTYPE_BUT, UI_BTYPE_DECORATOR)) {
alpha *= widget_alpha_factor(but->flag);
}
GPU_blend(GPU_BLEND_ALPHA);
2012-03-30 01:51:25 +00:00
if (icon && icon != ICON_BLANK1) {
const float ofs = 1.0f / aspect;
2017-03-17 16:47:19 +03:00
if (but->drawflag & UI_BUT_ICON_LEFT) {
2017-03-28 13:44:02 +03:00
/* special case - icon_only pie buttons */
2019-03-25 10:15:20 +11:00
if (ui_block_is_pie_menu(but->block) && !ELEM(but->type, UI_BTYPE_MENU, UI_BTYPE_POPOVER) &&
but->str && but->str[0] == '\0') {
2017-03-28 13:44:02 +03:00
xs = rect->xmin + 2.0f * ofs;
2019-03-25 10:15:20 +11:00
}
else if (but->emboss == UI_EMBOSS_NONE || but->type == UI_BTYPE_LABEL) {
2017-03-28 13:44:02 +03:00
xs = rect->xmin + 2.0f * ofs;
2019-03-25 10:15:20 +11:00
}
else {
2017-03-28 13:44:02 +03:00
xs = rect->xmin + 4.0f * ofs;
2019-03-25 10:15:20 +11:00
}
}
else {
Holiday coding log :) Nice formatted version (pictures soon): http://wiki.blender.org/index.php/Dev:Ref/Release_Notes/2.66/Usability Short list of main changes: - Transparent region option (over main region), added code to blend in/out such panels. - Min size window now 640 x 480 - Fixed DPI for ui - lots of cleanup and changes everywhere. Icon image need correct size still, layer-in-use icon needs remake. - Macbook retina support, use command line --no-native-pixels to disable it - Timeline Marker label was drawing wrong - Trackpad and magic mouse: supports zoom (hold ctrl) - Fix for splash position: removed ghost function and made window size update after creation immediate - Fast undo buffer save now adds UI as well. Could be checked for regular file save even... Quit.blend and temp file saving use this now. - Dixed filename in window on reading quit.blend or temp saves, and they now add a warning in window title: "(Recovered)" - New Userpref option "Keep Session" - this always saves quit.blend, and loads on start. This allows keeping UI and data without actual saves, until you actually save. When you load startup.blend and quit, it recognises the quit.blend as a startup (no file name in header) - Added 3D view copy/paste buffers (selected objects). Shortcuts ctrl-c, ctrl-v (OSX, cmd-c, cmd-v). Coded partial file saving for it. Could be used for other purposes. Todo: use OS clipboards. - User preferences (themes, keymaps, user settings) now can be saved as a separate file. Old option is called "Save Startup File" the new one "Save User Settings". To visualise this difference, the 'save startup file' button has been removed from user preferences window. That option is available as CTRL+U and in File menu still. - OSX: fixed bug that stopped giving mouse events outside window. This also fixes "Continuous Grab" for OSX. (error since 2009)
2012-12-12 18:58:11 +00:00
xs = (rect->xmin + rect->xmax - height) / 2.0f;
}
2017-03-28 13:44:02 +03:00
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);
}
/* Get theme color. */
uchar color[4] = {mono_color[0], mono_color[1], mono_color[2], mono_color[3]};
const bool has_theme = UI_icon_get_theme_color(icon, color);
Drag and drop 2.5 integration! Finally, slashdot regulars can use Blender too now! :) ** Drag works as follows: - drag-able items are defined by the standard interface ui toolkit - each button can get this feature, via uiButSetDragXXX(but, ...). There are calls to define drag-able images, ID blocks, RNA paths, file paths, and so on. By default you drag an icon, exceptionally an ImBuf - Drag items are registered centrally in the WM, it allows more drag items simultaneous too, but not implemented ** Drop works as follows: - On mouse release, and if drag items exist in the WM, it converts the mouse event to an EVT_DROP type. This event then gets the full drag info as customdata - drop regions are defined with WM_dropbox_add(), similar to keymaps you can make a "drop map" this way, which become 'drop map handlers' in the queues. - next to that the UI kit handles some common button types (like accepting ID or names) to be catching a drop event too. - Every "drop box" has two callbacks: - poll() = check if the event drag data is relevant for this box - copy() = fill in custom properties in the dropbox to initialize an operator - The dropbox handler then calls its standard Operator with its dropbox properties. ** Currently implemented Drag items: - ID icons in browse buttons - ID icons in context menu of properties region - ID icons in outliner and rna viewer - FileBrowser icons - FileBrowser preview images Drag-able icons are subtly visualized by making them brighter a bit on mouse-over. In case the icon is a button or UI element too (most cases), the drag-able feature will make the item react to mouse-release instead of mouse-press. Drop options: - UI buttons: ID and text buttons (paste name) - View3d: Object ID drop copies object - View3d: Material ID drop assigns to object under cursor - View3d: Image ID drop assigns to object UV texture under cursor - Sequencer: Path drop will add either Image or Movie strip - Image window: Path drop will open image ** Drag and drop Notes: - Dropping into another Blender window (from same application) works too. I've added code that passes on mousemoves and clicks to other windows, without activating them though. This does make using multi-window Blender a bit friendler. - Dropping a file path to an image, is not the same as dropping an Image ID... keep this in mind. Sequencer for example wants paths to be dropped, textures in 3d window wants an Image ID. - Although drop boxes could be defined via Python, I suggest they're part of the UI and editor design (= how we want an editor to work), and not default offered configurable like keymaps. - At the moment only one item can be dragged at a time. This is for several reasons.... For one, Blender doesn't have a well defined uniform way to define "what is selected" (files, outliner items, etc). Secondly there's potential conflicts on what todo when you drop mixed drag sets on spots. All undefined stuff... nice for later. - Example to bypass the above: a collection of images that form a strip, should be represented in filewindow as a single sequence anyway. This then will fit well and gets handled neatly by design. - Another option to check is to allow multiple options per drop... it could show the operator as a sort of menu, allowing arrow or scrollwheel to choose. For time being I'd prefer to try to design a singular drop though, just offer only one drop action per data type on given spots. - What does work already, but a tad slow, is to use a function that detects an object (type) under cursor, so a drag item's option can be further refined (like drop object on object = parent). (disabled) ** More notes - Added saving for Region layouts (like split points for toolbar) - Label buttons now handle mouse over - File list: added full path entry for drop feature. - Filesel bugfix: wm_operator_exec() got called there and fully handled, while WM event code tried same. Added new OPERATOR_HANDLED flag for this. Maybe python needs it too? - Cocoa: added window move event, so multi-win setups work OK (didnt save). - Interface_handlers.c: removed win->active - Severe area copy bug: area handlers were not set to NULL - Filesel bugfix: next/prev folder list was not copied on area copies ** Leftover todos - Cocoa windows seem to hang on cases still... needs check - Cocoa 'draw overlap' swap doesn't work - Cocoa window loses focus permanently on using Spotlight (for these reasons, makefile building has Carbon as default atm) - ListView templates in UI cannot become dragged yet, needs review... it consists of two overlapping UI elements, preventing handling icon clicks. - There's already Ghost library code to handle dropping from OS into Blender window. I've noticed this code is unfinished for Macs, but seems to be complete for Windows. Needs test... currently, an external drop event will print in console when succesfully delivered to Blender's WM.
2010-01-26 18:18:21 +00:00
/* to indicate draggable */
if (but->dragpoin && (but->flag & UI_ACTIVE)) {
UI_icon_draw_ex(xs, ys, icon, aspect, 1.25f, 0.0f, color, has_theme);
Drag and drop 2.5 integration! Finally, slashdot regulars can use Blender too now! :) ** Drag works as follows: - drag-able items are defined by the standard interface ui toolkit - each button can get this feature, via uiButSetDragXXX(but, ...). There are calls to define drag-able images, ID blocks, RNA paths, file paths, and so on. By default you drag an icon, exceptionally an ImBuf - Drag items are registered centrally in the WM, it allows more drag items simultaneous too, but not implemented ** Drop works as follows: - On mouse release, and if drag items exist in the WM, it converts the mouse event to an EVT_DROP type. This event then gets the full drag info as customdata - drop regions are defined with WM_dropbox_add(), similar to keymaps you can make a "drop map" this way, which become 'drop map handlers' in the queues. - next to that the UI kit handles some common button types (like accepting ID or names) to be catching a drop event too. - Every "drop box" has two callbacks: - poll() = check if the event drag data is relevant for this box - copy() = fill in custom properties in the dropbox to initialize an operator - The dropbox handler then calls its standard Operator with its dropbox properties. ** Currently implemented Drag items: - ID icons in browse buttons - ID icons in context menu of properties region - ID icons in outliner and rna viewer - FileBrowser icons - FileBrowser preview images Drag-able icons are subtly visualized by making them brighter a bit on mouse-over. In case the icon is a button or UI element too (most cases), the drag-able feature will make the item react to mouse-release instead of mouse-press. Drop options: - UI buttons: ID and text buttons (paste name) - View3d: Object ID drop copies object - View3d: Material ID drop assigns to object under cursor - View3d: Image ID drop assigns to object UV texture under cursor - Sequencer: Path drop will add either Image or Movie strip - Image window: Path drop will open image ** Drag and drop Notes: - Dropping into another Blender window (from same application) works too. I've added code that passes on mousemoves and clicks to other windows, without activating them though. This does make using multi-window Blender a bit friendler. - Dropping a file path to an image, is not the same as dropping an Image ID... keep this in mind. Sequencer for example wants paths to be dropped, textures in 3d window wants an Image ID. - Although drop boxes could be defined via Python, I suggest they're part of the UI and editor design (= how we want an editor to work), and not default offered configurable like keymaps. - At the moment only one item can be dragged at a time. This is for several reasons.... For one, Blender doesn't have a well defined uniform way to define "what is selected" (files, outliner items, etc). Secondly there's potential conflicts on what todo when you drop mixed drag sets on spots. All undefined stuff... nice for later. - Example to bypass the above: a collection of images that form a strip, should be represented in filewindow as a single sequence anyway. This then will fit well and gets handled neatly by design. - Another option to check is to allow multiple options per drop... it could show the operator as a sort of menu, allowing arrow or scrollwheel to choose. For time being I'd prefer to try to design a singular drop though, just offer only one drop action per data type on given spots. - What does work already, but a tad slow, is to use a function that detects an object (type) under cursor, so a drag item's option can be further refined (like drop object on object = parent). (disabled) ** More notes - Added saving for Region layouts (like split points for toolbar) - Label buttons now handle mouse over - File list: added full path entry for drop feature. - Filesel bugfix: wm_operator_exec() got called there and fully handled, while WM event code tried same. Added new OPERATOR_HANDLED flag for this. Maybe python needs it too? - Cocoa: added window move event, so multi-win setups work OK (didnt save). - Interface_handlers.c: removed win->active - Severe area copy bug: area handlers were not set to NULL - Filesel bugfix: next/prev folder list was not copied on area copies ** Leftover todos - Cocoa windows seem to hang on cases still... needs check - Cocoa 'draw overlap' swap doesn't work - Cocoa window loses focus permanently on using Spotlight (for these reasons, makefile building has Carbon as default atm) - ListView templates in UI cannot become dragged yet, needs review... it consists of two overlapping UI elements, preventing handling icon clicks. - There's already Ghost library code to handle dropping from OS into Blender window. I've noticed this code is unfinished for Macs, but seems to be complete for Windows. Needs test... currently, an external drop event will print in console when succesfully delivered to Blender's WM.
2010-01-26 18:18:21 +00:00
}
else if ((but->flag & (UI_ACTIVE | UI_SELECT | UI_SELECT_DRAW))) {
UI_icon_draw_ex(xs, ys, icon, aspect, alpha, 0.0f, color, has_theme);
}
else if (!((but->icon != ICON_NONE) && UI_but_is_tool(but))) {
if (has_theme) {
alpha *= 0.8f;
}
UI_icon_draw_ex(xs, ys, icon, aspect, alpha, 0.0f, color, has_theme);
}
else {
const bTheme *btheme = UI_GetTheme();
const float desaturate = 1.0 - btheme->tui.icon_saturation;
UI_icon_draw_ex(xs, ys, icon, aspect, alpha, desaturate, color, has_theme);
}
}
GPU_blend(GPU_BLEND_NONE);
}
static void widget_draw_submenu_tria(const uiBut *but,
const rcti *rect,
const uiWidgetColors *wcol)
{
const float aspect = but->block->aspect * U.inv_dpi_fac;
const int tria_height = (int)(ICON_DEFAULT_HEIGHT / aspect);
const int tria_width = (int)(ICON_DEFAULT_WIDTH / aspect) - 2 * U.pixelsize;
const int xs = rect->xmax - tria_width;
const int ys = (rect->ymin + rect->ymax - tria_height) / 2.0f;
float col[4];
rgba_uchar_to_float(col, wcol->text);
col[3] *= 0.8f;
rctf tria_rect;
BLI_rctf_init(&tria_rect, xs, xs + tria_width, ys, ys + tria_height);
BLI_rctf_scale(&tria_rect, 0.4f);
GPU_blend(GPU_BLEND_ALPHA);
UI_widgetbase_draw_cache_flush();
GPU_blend(GPU_BLEND_NONE);
ui_draw_anti_tria_rect(&tria_rect, 'h', col);
}
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);
const 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);
const int bytes = next_utf8 - (str + but->ofs);
but->ofs += bytes;
}
2015-05-31 14:20:03 +10:00
/**
* Helper.
* This func assumes things like kerning handling have already been handled!
* Return the length of modified (right-clipped + ellipsis) string.
*/
2015-05-05 03:13:47 +10:00
static void ui_text_clip_right_ex(const uiFontStyle *fstyle,
char *str,
const size_t max_len,
const float okwidth,
2015-05-05 03:13:47 +10:00
const char *sep,
const int sep_len,
const float sep_strwidth,
size_t *r_final_len)
{
BLI_assert(str[0]);
/* How many BYTES (not characters) of this utf-8 string can fit, along with appended ellipsis. */
int l_end = BLF_width_to_strlen(fstyle->uifont_id, str, max_len, okwidth - sep_strwidth, NULL);
if (l_end > 0) {
/* At least one character, so clip and add the ellipsis. */
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;
}
}
else {
/* Otherwise fit as much as we can without adding an ellipsis. */
l_end = BLF_width_to_strlen(fstyle->uifont_id, str, max_len, okwidth, NULL);
str[l_end] = '\0';
if (r_final_len) {
*r_final_len = (size_t)l_end;
}
}
}
/**
* Cut off the middle of the text to fit into the given width.
2019-04-17 08:44:38 +02:00
*
* \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(const uiFontStyle *fstyle,
char *str,
float okwidth,
const float minwidth,
const size_t max_len,
const char rpart_sep)
{
/* 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 ellipsis... */
okwidth += 1.0f + UI_DPI_FAC;
BLI_assert(str[0]);
/* need to set this first */
UI_fontstyle_set(fstyle);
2019-03-25 10:15:20 +11:00
if (fstyle->kerning == 1) {
/* for BLF_width */
BLF_enable(fstyle->uifont_id, BLF_KERNING_DEFAULT);
}
float strwidth = BLF_width(fstyle->uifont_id, str, max_len);
if ((okwidth > 0.0f) && (strwidth > okwidth)) {
/* Ellipsis. Some compilers complain with real literal string. */
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);
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;
}
}
}
2021-01-04 17:02:13 +11:00
const float parts_strwidth = (okwidth - sep_strwidth) / 2.0f;
if (rpart) {
strcpy(rpart_buf, rpart);
*rpart = '\0';
rpart = rpart_buf;
}
2021-01-04 17:02:13 +11:00
const size_t l_end = BLF_width_to_strlen(
fstyle->uifont_id, str, max_len, parts_strwidth, NULL);
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, NULL);
r_len = strlen(str + r_offset) + 1; /* +1 for the trailing '\0'. */
if (l_end + sep_len + r_len + rpart_len > max_len) {
2019-04-17 08:44:38 +02:00
/* 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);
/* -1 to remove trailing '\0'! */
final_lpart_len = (size_t)(l_end + sep_len + r_len - 1);
while (BLF_width(fstyle->uifont_id, str, max_len) > okwidth) {
/* This will happen because a lot of string width processing is done in integer pixels,
* which can introduce a rather high error in the end (about 2 pixels or so).
* Only one char removal shall ever be needed in real-life situation... */
r_len--;
final_lpart_len--;
char *c = str + l_end + sep_len;
memmove(c, c + 1, r_len);
}
}
}
if (rpart) {
/* Add back preserved right part to our shorten str. */
memcpy(str + final_lpart_len, rpart, rpart_len + 1); /* +1 for trailing '\0'. */
okwidth += rpart_width;
}
strwidth = BLF_width(fstyle->uifont_id, str, max_len);
}
if (fstyle->kerning == 1) {
BLF_disable(fstyle->uifont_id, BLF_KERNING_DEFAULT);
}
BLI_assert(strwidth <= okwidth);
return strwidth;
}
/**
* Wrapper around UI_text_clip_middle_ex.
*/
static void ui_text_clip_middle(const uiFontStyle *fstyle, uiBut *but, const rcti *rect)
{
/* No margin for labels! */
const int border = ELEM(but->type, UI_BTYPE_LABEL, UI_BTYPE_MENU, UI_BTYPE_POPOVER) ?
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');
}
/**
2019-04-17 08:44:38 +02:00
* 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(const 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, UI_BTYPE_POPOVER) ?
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(const 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);
2019-03-25 10:15:20 +11:00
if (fstyle->kerning == 1) {
/* for BLF_width */
BLF_enable(fstyle->uifont_id, BLF_KERNING_DEFAULT);
2019-03-25 10:15:20 +11:00
}
/* define ofs dynamically */
2019-03-25 10:15:20 +11:00
if (but->ofs > but->pos) {
but->ofs = but->pos;
2019-03-25 10:15:20 +11:00
}
2019-03-25 10:15:20 +11:00
if (BLF_width(fstyle->uifont_id, but->editstr, INT_MAX) <= okwidth) {
but->ofs = 0;
2019-03-25 10:15:20 +11:00
}
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 */
2019-03-25 10:15:20 +11:00
if (width < 20 && but->ofs > 0) {
ui_text_clip_give_prev_off(but, but->editstr);
2019-03-25 10:15:20 +11:00
}
bytes = BLI_str_utf8_size(BLI_str_find_prev_char_utf8(but->editstr, but->editstr + len));
2019-03-25 10:15:20 +11:00
if (bytes == -1) {
bytes = 1;
2019-03-25 10:15:20 +11:00
}
len -= bytes;
}
but->strwidth = BLF_width(fstyle->uifont_id, but->editstr + but->ofs, len - but->ofs);
2019-03-25 10:15:20 +11:00
if (but->strwidth < 10) {
break;
}
}
}
if (fstyle->kerning == 1) {
BugFix: [#20854] PROPERTIES STAMP: Rendering stamp flickers in output renders Blenfont was not thread safe, that is why one thread can change the font properties (size, dpi, color, etc) at the same time that the stamp draw on the image, and then the problem. To make blenfont thread safe I have to change two important things: 1) Every BLF_* function take one argument, the font id. 2) We have two new function to make font "thread safe": BLF_load_unique BLF_load_mem_unique This two function are for case like stamp, that need and own font that don't share the glyph cache, so can draw without problem in a different thread. Why the BLF_*_unique function ? Because blenfont keep only one copy of a font and keep a list of "glyph cache". Every glyph cache have size and dpi, so if two different thread access the same font at the same time, they can change value and finish with something like the stamp problem. Why don't remove the glyph cache ? Because if we do that, we finish with a font object for every size and dpi, and the stamp is really a special case that happen in the rendering process, so I really thing is better keep the glyph cache and make this two new function to handle this special case. (When I say "font object" I mean have the same freetype font multiple times just to have differents size and dpi) As Matt point we still can have one case that two thread access the BLF_*_unique function at the same time, but I am looking to fix this with some class of thread lock. For now I test and work fine, so if some one found problem, please let me know. Campbell I have to change the python api (python/generic/blf_api.c) to the new syntax, so maybe you can take a look at this.
2010-04-22 10:56:45 +00:00
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(const 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);
int drawstr_len = strlen(but->drawstr);
const char *cpend = but->drawstr + drawstr_len;
/* need to set this first */
UI_fontstyle_set(fstyle);
2019-03-25 10:15:20 +11:00
if (fstyle->kerning == 1) {
/* for BLF_width */
BugFix: [#20854] PROPERTIES STAMP: Rendering stamp flickers in output renders Blenfont was not thread safe, that is why one thread can change the font properties (size, dpi, color, etc) at the same time that the stamp draw on the image, and then the problem. To make blenfont thread safe I have to change two important things: 1) Every BLF_* function take one argument, the font id. 2) We have two new function to make font "thread safe": BLF_load_unique BLF_load_mem_unique This two function are for case like stamp, that need and own font that don't share the glyph cache, so can draw without problem in a different thread. Why the BLF_*_unique function ? Because blenfont keep only one copy of a font and keep a list of "glyph cache". Every glyph cache have size and dpi, so if two different thread access the same font at the same time, they can change value and finish with something like the stamp problem. Why don't remove the glyph cache ? Because if we do that, we finish with a font object for every size and dpi, and the stamp is really a special case that happen in the rendering process, so I really thing is better keep the glyph cache and make this two new function to handle this special case. (When I say "font object" I mean have the same freetype font multiple times just to have differents size and dpi) As Matt point we still can have one case that two thread access the BLF_*_unique function at the same time, but I am looking to fix this with some class of thread lock. For now I test and work fine, so if some one found problem, please let me know. Campbell I have to change the python api (python/generic/blf_api.c) to the new syntax, so maybe you can take a look at this.
2010-04-22 10:56:45 +00:00
BLF_enable(fstyle->uifont_id, BLF_KERNING_DEFAULT);
2019-03-25 10:15:20 +11:00
}
but->strwidth = BLF_width(fstyle->uifont_id, but->drawstr, sizeof(but->drawstr));
2012-03-30 01:51:25 +00:00
but->ofs = 0;
2021-03-12 00:46:41 +11:00
/* First shorten number-buttons eg,
* Translucency: 0.000
* becomes
* Trans: 0.000
*/
/* find the space after ':' separator */
char *cpoin = strrchr(but->drawstr, ':');
2012-03-30 01:51:25 +00:00
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);
const 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);
2012-03-30 01:51:25 +00:00
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);
2019-03-25 10:15:20 +11:00
if (but->strwidth < 10) {
break;
}
2019-03-25 10:15:20 +11:00
}
/* 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);
2019-03-25 10:15:20 +11:00
if (but->strwidth < 10) {
break;
}
2019-03-25 10:15:20 +11:00
}
}
/* Now just remove trailing chars */
/* once the label's gone, chop off the least significant digits */
if (but->strwidth > okwidth) {
float strwidth;
2018-07-01 19:57:31 +02:00
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;
}
2019-03-25 10:15:20 +11:00
if (fstyle->kerning == 1) {
BugFix: [#20854] PROPERTIES STAMP: Rendering stamp flickers in output renders Blenfont was not thread safe, that is why one thread can change the font properties (size, dpi, color, etc) at the same time that the stamp draw on the image, and then the problem. To make blenfont thread safe I have to change two important things: 1) Every BLF_* function take one argument, the font id. 2) We have two new function to make font "thread safe": BLF_load_unique BLF_load_mem_unique This two function are for case like stamp, that need and own font that don't share the glyph cache, so can draw without problem in a different thread. Why the BLF_*_unique function ? Because blenfont keep only one copy of a font and keep a list of "glyph cache". Every glyph cache have size and dpi, so if two different thread access the same font at the same time, they can change value and finish with something like the stamp problem. Why don't remove the glyph cache ? Because if we do that, we finish with a font object for every size and dpi, and the stamp is really a special case that happen in the rendering process, so I really thing is better keep the glyph cache and make this two new function to handle this special case. (When I say "font object" I mean have the same freetype font multiple times just to have differents size and dpi) As Matt point we still can have one case that two thread access the BLF_*_unique function at the same time, but I am looking to fix this with some class of thread lock. For now I test and work fine, so if some one found problem, please let me know. Campbell I have to change the python api (python/generic/blf_api.c) to the new syntax, so maybe you can take a look at this.
2010-04-22 10:56:45 +00:00
BLF_disable(fstyle->uifont_id, BLF_KERNING_DEFAULT);
2019-03-25 10:15:20 +11:00
}
}
#ifdef WITH_INPUT_IME
static void widget_draw_text_ime_underline(const uiFontStyle *fstyle,
const uiWidgetColors *wcol,
const 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;
float fcol[4];
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;
}
2018-07-01 19:57:31 +02:00
width = BLF_width(
fstyle->uifont_id, drawstr + but->ofs, ime_data->composite_len + but->pos - but->ofs);
rgba_uchar_to_float(fcol, wcol->text);
UI_draw_text_underline(rect->xmin + ofs_x,
rect->ymin + 6 * U.pixelsize,
min_ii(width, rect_x - 2) - ofs_x,
1,
fcol);
/* 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;
}
2018-07-01 19:57:31 +02:00
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,
fcol);
}
}
}
#endif /* WITH_INPUT_IME */
struct UnderlineData {
size_t str_offset; /* The string offset of the underlined character. */
int width_px; /* The underline width in pixels. */
int r_offset_px[2]; /* Write the X,Y offset here. */
};
static bool widget_draw_text_underline_calc_position(const char *UNUSED(str),
const size_t str_step_ofs,
const rcti *glyph_step_bounds,
const int UNUSED(glyph_advance_x),
const rctf *glyph_bounds,
const int UNUSED(glyph_bearing[2]),
void *user_data)
{
struct UnderlineData *ul_data = user_data;
if (ul_data->str_offset == str_step_ofs) {
/* Full width of this glyph including both bearings. */
const float width = glyph_bounds->xmin + BLI_rctf_size_x(glyph_bounds) + glyph_bounds->xmin;
ul_data->r_offset_px[0] = glyph_step_bounds->xmin + ((width - ul_data->width_px) * 0.5f);
/* One line-width below the lower glyph bounds. */
ul_data->r_offset_px[1] = glyph_bounds->ymin - U.pixelsize;
/* Early exit. */
return false;
}
return true;
}
static void widget_draw_text(const uiFontStyle *fstyle,
const uiWidgetColors *wcol,
uiBut *but,
rcti *rect)
{
int drawstr_left_len = UI_MAX_DRAW_STR;
const char *drawstr = but->drawstr;
const char *drawstr_right = NULL;
bool use_right_only = false;
#ifdef WITH_INPUT_IME
const wmIMEData *ime_data;
#endif
UI_fontstyle_set(fstyle);
eFontStyle_Align align;
if (but->editstr || (but->drawflag & UI_BUT_TEXT_LEFT)) {
align = UI_STYLE_TEXT_LEFT;
}
else if (but->drawflag & UI_BUT_TEXT_RIGHT) {
align = UI_STYLE_TEXT_RIGHT;
}
else {
align = UI_STYLE_TEXT_CENTER;
}
2019-03-25 10:15:20 +11:00
if (fstyle->kerning == 1) {
/* for BLF_width */
BugFix: [#20854] PROPERTIES STAMP: Rendering stamp flickers in output renders Blenfont was not thread safe, that is why one thread can change the font properties (size, dpi, color, etc) at the same time that the stamp draw on the image, and then the problem. To make blenfont thread safe I have to change two important things: 1) Every BLF_* function take one argument, the font id. 2) We have two new function to make font "thread safe": BLF_load_unique BLF_load_mem_unique This two function are for case like stamp, that need and own font that don't share the glyph cache, so can draw without problem in a different thread. Why the BLF_*_unique function ? Because blenfont keep only one copy of a font and keep a list of "glyph cache". Every glyph cache have size and dpi, so if two different thread access the same font at the same time, they can change value and finish with something like the stamp problem. Why don't remove the glyph cache ? Because if we do that, we finish with a font object for every size and dpi, and the stamp is really a special case that happen in the rendering process, so I really thing is better keep the glyph cache and make this two new function to handle this special case. (When I say "font object" I mean have the same freetype font multiple times just to have differents size and dpi) As Matt point we still can have one case that two thread access the BLF_*_unique function at the same time, but I am looking to fix this with some class of thread lock. For now I test and work fine, so if some one found problem, please let me know. Campbell I have to change the python api (python/generic/blf_api.c) to the new syntax, so maybe you can take a look at this.
2010-04-22 10:56:45 +00:00
BLF_enable(fstyle->uifont_id, BLF_KERNING_DEFAULT);
2019-03-25 10:15:20 +11:00
}
/* 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;
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`! */
2015-03-26 21:24:01 +01:00
ime_data = ui_but_ime_data_get(but);
if (ime_data && ime_data->composite_len) {
/* insert composite string into cursor pos */
2018-07-01 19:57:31 +02:00
BLI_snprintf((char *)drawstr,
UI_MAX_DRAW_STR,
"%.*s%s%s",
but->pos,
2018-07-01 19:57:31 +02:00
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;
/* Shape of the cursor for drawing. */
rcti but_cursor_shape;
/* text button selection */
if ((but->selend - but->selsta) > 0) {
int selsta_draw, selwidth_draw;
if (drawstr[0] != 0) {
/* We are drawing on top of widget bases. Flush cache. */
GPU_blend(GPU_BLEND_ALPHA);
UI_widgetbase_draw_cache_flush();
GPU_blend(GPU_BLEND_NONE);
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);
uint pos = GPU_vertformat_attr_add(
immVertexFormat(), "pos", GPU_COMP_I32, 2, GPU_FETCH_INT_TO_FLOAT);
immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
immUniformColor4ubv(wcol->item);
immRecti(pos,
rect->xmin + selsta_draw,
2019-11-25 12:09:25 +11:00
rect->ymin + U.pixelsize,
min_ii(rect->xmin + selwidth_draw, rect->xmax - 2),
2019-11-25 12:09:25 +11:00
rect->ymax - U.pixelsize);
immUnbindProgram();
}
}
/* 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;
}
/* We are drawing on top of widget bases. Flush cache. */
GPU_blend(GPU_BLEND_ALPHA);
UI_widgetbase_draw_cache_flush();
GPU_blend(GPU_BLEND_NONE);
uint pos = GPU_vertformat_attr_add(
immVertexFormat(), "pos", GPU_COMP_I32, 2, GPU_FETCH_INT_TO_FLOAT);
immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
immUniformThemeColor(TH_WIDGET_TEXT_CURSOR);
but_cursor_shape.xmin = (rect->xmin + t) - U.pixelsize;
but_cursor_shape.ymin = rect->ymin + U.pixelsize;
but_cursor_shape.xmax = (rect->xmin + t) + U.pixelsize;
but_cursor_shape.ymax = rect->ymax - U.pixelsize;
/* draw cursor */
2019-11-25 12:09:25 +11:00
immRecti(pos,
but_cursor_shape.xmin,
but_cursor_shape.ymin,
but_cursor_shape.xmax,
but_cursor_shape.ymax);
immUnbindProgram();
}
#ifdef WITH_INPUT_IME
if (ime_data && ime_data->composite_len) {
/* ime cursor following */
if (but->pos >= but->ofs) {
ui_but_ime_reposition(but, but_cursor_shape.xmax + 5, but_cursor_shape.ymin + 3, false);
}
/* composite underline */
widget_draw_text_ime_underline(fstyle, wcol, but, rect, ime_data, drawstr);
}
#endif
}
2019-03-25 10:15:20 +11:00
if (fstyle->kerning == 1) {
BugFix: [#20854] PROPERTIES STAMP: Rendering stamp flickers in output renders Blenfont was not thread safe, that is why one thread can change the font properties (size, dpi, color, etc) at the same time that the stamp draw on the image, and then the problem. To make blenfont thread safe I have to change two important things: 1) Every BLF_* function take one argument, the font id. 2) We have two new function to make font "thread safe": BLF_load_unique BLF_load_mem_unique This two function are for case like stamp, that need and own font that don't share the glyph cache, so can draw without problem in a different thread. Why the BLF_*_unique function ? Because blenfont keep only one copy of a font and keep a list of "glyph cache". Every glyph cache have size and dpi, so if two different thread access the same font at the same time, they can change value and finish with something like the stamp problem. Why don't remove the glyph cache ? Because if we do that, we finish with a font object for every size and dpi, and the stamp is really a special case that happen in the rendering process, so I really thing is better keep the glyph cache and make this two new function to handle this special case. (When I say "font object" I mean have the same freetype font multiple times just to have differents size and dpi) As Matt point we still can have one case that two thread access the BLF_*_unique function at the same time, but I am looking to fix this with some class of thread lock. For now I test and work fine, so if some one found problem, please let me know. Campbell I have to change the python api (python/generic/blf_api.c) to the new syntax, so maybe you can take a look at this.
2010-04-22 10:56:45 +00:00
BLF_disable(fstyle->uifont_id, BLF_KERNING_DEFAULT);
2019-03-25 10:15:20 +11:00
}
#if 0
ui_rasterpos_safe(x, y, but->aspect);
transopts = ui_translate_buttons();
#endif
bool use_drawstr_right_as_hint = false;
/* cut string in 2 parts - only for menu entries */
if (but->flag & UI_BUT_HAS_SEP_CHAR && (but->editstr == NULL)) {
drawstr_right = strrchr(drawstr, UI_SEP_CHAR);
if (drawstr_right) {
use_drawstr_right_as_hint = true;
drawstr_left_len = (drawstr_right - drawstr);
drawstr_right++;
}
}
#ifdef USE_NUMBUTS_LR_ALIGN
if (!drawstr_right && (but->drawflag & UI_BUT_TEXT_LEFT) &&
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 = strrchr(drawstr + but->ofs, ':');
if (drawstr_right) {
drawstr_right++;
drawstr_left_len = (drawstr_right - drawstr - 1);
while (*drawstr_right == ' ') {
drawstr_right++;
}
}
else {
/* no prefix, even so use only cpoin */
drawstr_right = drawstr + but->ofs;
use_right_only = true;
}
}
#endif
if (!use_right_only) {
/* for underline drawing */
int font_xofs, font_yofs;
int drawlen = (drawstr_left_len == INT_MAX) ? strlen(drawstr + but->ofs) :
(drawstr_left_len - but->ofs);
if (drawlen > 0) {
UI_fontstyle_draw_ex(fstyle,
rect,
drawstr + but->ofs,
wcol->text,
&(struct uiFontStyleDraw_Params){
.align = align,
},
drawlen,
&font_xofs,
&font_yofs,
NULL);
if (but->menu_key != '\0') {
const char *drawstr_ofs = drawstr + but->ofs;
int ul_index = -1;
{
/* Find upper case, fallback to lower case. */
const char *drawstr_end = drawstr_ofs + drawlen;
const char keys[] = {but->menu_key - 32, but->menu_key};
for (int i = 0; i < ARRAY_SIZE(keys); i++) {
const char *drawstr_menu = strchr(drawstr_ofs, keys[i]);
if (drawstr_menu != NULL && drawstr_menu < drawstr_end) {
ul_index = (int)(drawstr_menu - drawstr_ofs);
break;
}
}
2019-03-25 10:15:20 +11:00
}
if (ul_index != -1) {
if (fstyle->kerning == 1) {
BLF_enable(fstyle->uifont_id, BLF_KERNING_DEFAULT);
}
int ul_width = round_fl_to_int(BLF_width(fstyle->uifont_id, "_", 2));
struct UnderlineData ul_data = {
.str_offset = ul_index,
.width_px = ul_width,
};
BLF_boundbox_foreach_glyph(fstyle->uifont_id,
drawstr_ofs,
ul_index + 1,
widget_draw_text_underline_calc_position,
&ul_data);
const int pos_x = rect->xmin + font_xofs + ul_data.r_offset_px[0];
const int pos_y = rect->ymin + font_yofs + ul_data.r_offset_px[1];
/* Use text output because direct drawing doesn't always work. See T89246. */
BLF_position(fstyle->uifont_id, pos_x, pos_y, 0.0f);
BLF_color4ubv(fstyle->uifont_id, wcol->text);
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) {
uchar col[4];
copy_v4_v4_uchar(col, wcol->text);
if (use_drawstr_right_as_hint) {
col[3] *= 0.5f;
}
rect->xmax -= UI_TEXT_CLIP_MARGIN;
UI_fontstyle_draw(fstyle,
rect,
drawstr_right,
col,
&(struct uiFontStyleDraw_Params){
.align = UI_STYLE_TEXT_RIGHT,
});
}
}
static void widget_draw_extra_icons(const uiWidgetColors *wcol,
uiBut *but,
rcti *rect,
float alpha)
{
const float icon_size = ICON_SIZE_FROM_BUTRECT(rect);
/* Offset of icons from the right edge. Keep in sync
with 'ui_but_extra_operator_icon_mouse_over_get'. */
if (!BLI_listbase_is_empty(&but->extra_op_icons)) {
/* Eyeballed. */
rect->xmax -= 0.2 * icon_size;
}
/* Inverse order, from right to left. */
LISTBASE_FOREACH_BACKWARD (uiButExtraOpIcon *, op_icon, &but->extra_op_icons) {
rcti temp = *rect;
float alpha_this = alpha;
temp.xmin = temp.xmax - icon_size;
if (!op_icon->highlighted) {
alpha_this *= 0.75f;
}
/* Draw the icon at the center, and restore the flags after. */
const int old_drawflags = but->drawflag;
UI_but_drawflag_disable(but, UI_BUT_ICON_LEFT);
widget_draw_icon(but, op_icon->icon, alpha_this, &temp, wcol->text);
but->drawflag = old_drawflags;
rect->xmax -= icon_size;
}
}
static void widget_draw_node_link_socket(const uiWidgetColors *wcol,
const rcti *rect,
uiBut *but,
float alpha)
{
/* Node socket pointer can be passed as custom_data, see UI_but_node_link_set(). */
if (but->custom_data) {
const float scale = 0.9f / but->block->aspect;
float col[4];
rgba_uchar_to_float(col, but->col);
col[3] *= alpha;
GPU_blend(GPU_BLEND_ALPHA);
UI_widgetbase_draw_cache_flush();
GPU_blend(GPU_BLEND_NONE);
ED_node_socket_draw(but->custom_data, rect, col, scale);
}
else {
widget_draw_icon(but, ICON_LAYER_USED, alpha, rect, wcol->text);
}
}
/* draws text and icons for buttons */
static void widget_draw_text_icon(const uiFontStyle *fstyle,
const uiWidgetColors *wcol,
uiBut *but,
rcti *rect)
{
const bool show_menu_icon = ui_but_draw_menu_icon(but);
const float alpha = (float)wcol->text[3] / 255.0f;
char password_str[UI_MAX_DRAW_STR];
UI: Better split layout support for checkboxes Makes the following layout changes possible: {F8473498} {F8473499} {F8473502} The next commit will contain many layout changes to make good use of these new possibilities. The result should be more consistent, easier to read and should give a more organized impression. Additionally, it should be possible to replace many sub-panels with compacter layouts. Main changes: * Checkboxes now respect the property split layouts * Add support for row and column headers (i.e. `uiLayout.column(heading="Foo")`, `uiLayout.row(heading="Bar")`). If the first property added to this layout doesn't insert anything into the label split column, the heading is inserted there. Otherwise, it's inserted as own item. * Add support for manually inserting decorators for an existing item (`uiLayout.prop_decorator()`). That way layout creators can manually insert this, which was the only way I saw to support property split layouts with a checkbox before the actual property. {F8471883} * Autogenerated layouts for operator properties look bad if there are only checkboxes (which only use half the region width). So before creating the layout, we iterate over visible properties and disable split layout if all are booleans. I think this is fine, if needed we could also add layout hints to operators. * `uiTemplateOperatorPropertyButs()` now handles macros itself, the caller used to be responsible for this. Code that didn't handle these so far never used macros I think, so this change should be invisible. * Remove manual property split layout from autogenerated operator properties layout. * Padding of checkboxes is tweaked to make their label visually more connected to the checkboxes. * Support split layout for menus (should work for `uiLayout.menu()`, `.operator_menu_enum()`, `.prop_menu_enum()`, maybe more) Maniphest Task: https://developer.blender.org/T65965 Differential Revision: https://developer.blender.org/D7427 Reviewed by: Brecht Van Lommel, William Reynish, Pablo Vazques
2020-04-17 16:40:25 +02:00
bool no_text_padding = but->drawflag & UI_BUT_NO_TEXT_PADDING;
ui_but_text_password_hide(password_str, but, false);
/* check for button text label */
if (ELEM(but->type, UI_BTYPE_MENU, UI_BTYPE_POPOVER) && (but->flag & UI_BUT_NODE_LINK)) {
rcti temp = *rect;
const int size = BLI_rcti_size_y(rect) + 1; /* Not the icon size! */
if (but->drawflag & UI_BUT_ICON_LEFT) {
temp.xmax = rect->xmin + size;
rect->xmin = temp.xmax;
/* Further padding looks off. */
no_text_padding = true;
}
else {
temp.xmin = rect->xmax - size;
rect->xmax = temp.xmin;
}
widget_draw_node_link_socket(wcol, &temp, but, alpha);
}
/* 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)) {
2020-04-14 23:44:15 +10:00
const BIFIconID icon = ui_but_icon(but);
int icon_size = BLI_rcti_size_y(rect);
int text_size = 0;
2021-02-05 16:23:34 +11:00
/* This is a bit brittle, 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;
GPU_blend(GPU_BLEND_ALPHA);
2015-05-25 15:38:12 +01:00
widget_draw_preview(icon, alpha, rect);
GPU_blend(GPU_BLEND_NONE);
/* 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 bool is_tool = ((but->icon != ICON_NONE) & UI_but_is_tool(but));
/* XXX add way to draw icons at a different size!
* Use small icons for popup. */
#ifdef USE_UI_TOOLBAR_HACK
const float aspect_orig = but->block->aspect;
if (is_tool && (but->block->flag & UI_BLOCK_POPOVER)) {
but->block->aspect *= 2.0f;
}
#endif
2018-06-06 22:17:06 +02:00
2020-04-14 23:44:15 +10:00
const BIFIconID icon = ui_but_icon(but);
const int icon_size_init = is_tool ? ICON_DEFAULT_HEIGHT_TOOLBAR : ICON_DEFAULT_HEIGHT;
const float icon_size = icon_size_init / (but->block->aspect * U.inv_dpi_fac);
const float icon_padding = 2 * UI_DPI_FAC;
#ifdef USE_UI_TOOLBAR_HACK
if (is_tool) {
/* pass (even if its a menu toolbar) */
but->drawflag |= UI_BUT_TEXT_LEFT;
but->drawflag |= UI_BUT_ICON_LEFT;
}
#endif
/* 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 (is_tool) {
/* pass (even if its a menu toolbar) */
}
else if (ui_block_is_pie_menu(but->block)) {
if (but->emboss == UI_EMBOSS_RADIAL) {
2017-03-11 22:34:09 +03:00
rect->xmin += 0.3f * U.widget_unit;
2019-03-25 10:15:20 +11:00
}
2017-03-11 22:34:09 +03:00
}
/* Menu items, but only if they are not icon-only (rare). */
else if (ui_block_is_menu(but->block) && but->drawstr[0]) {
rect->xmin += 0.2f * U.widget_unit;
2019-03-25 10:15:20 +11:00
}
/* By default icon is the color of text, but can optionally override with but->col. */
widget_draw_icon(but, icon, alpha, rect, (but->col[3] != 0) ? but->col : wcol->text);
if (show_menu_icon) {
2018-09-11 15:08:08 +10:00
BLI_assert(but->block->content_hints & UI_BLOCK_CONTAINS_SUBMENU_BUT);
widget_draw_submenu_tria(but, rect, wcol);
}
#ifdef USE_UI_TOOLBAR_HACK
but->block->aspect = aspect_orig;
#endif
2018-06-06 22:17:06 +02:00
rect->xmin += round_fl_to_int(icon_size + icon_padding);
}
if (!no_text_padding) {
const int text_padding = round_fl_to_int((UI_TEXT_MARGIN_X * U.widget_unit) /
but->block->aspect);
if (but->editstr) {
rect->xmin += text_padding;
}
else if (but->flag & UI_BUT_DRAG_MULTI) {
const bool text_is_edited = ui_but_drag_multi_edit_get(but) != NULL;
if (text_is_edited || (but->drawflag & UI_BUT_TEXT_LEFT)) {
rect->xmin += text_padding;
}
}
else if (but->drawflag & UI_BUT_TEXT_LEFT) {
rect->xmin += text_padding;
}
else if (but->drawflag & UI_BUT_TEXT_RIGHT) {
rect->xmax -= text_padding;
}
}
else {
/* In case a separate text label and some other button are placed under each other,
and the outline of the button does not contrast with the background.
Add an offset (thickness of the outline) so that the text does not stick out visually. */
if (but->drawflag & UI_BUT_TEXT_LEFT) {
rect->xmin += U.pixelsize;
}
else if (but->drawflag & UI_BUT_TEXT_RIGHT) {
rect->xmax -= U.pixelsize;
}
}
/* Menu contains sub-menu items with triangle icon on their right. Shortcut
* strings should be drawn with some padding to the right then. */
2018-09-11 15:08:08 +10:00
if (ui_block_is_menu(but->block) &&
(but->block->content_hints & UI_BLOCK_CONTAINS_SUBMENU_BUT)) {
rect->xmax -= UI_MENU_SUBMENU_PADDING;
}
/* extra icons, e.g. 'x' icon to clear text or icon for eyedropper */
widget_draw_extra_icons(wcol, but, rect, alpha);
/* 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);
}
2021-07-05 12:47:46 +10:00
/* Always draw text for text-button cursor. */
widget_draw_text(fstyle, wcol, but, rect);
ui_but_text_password_hide(password_str, but, true);
/* if a widget uses font shadow it has to be deactivated now */
BLF_disable(fstyle->uifont_id, BLF_SHADOW);
}
#undef UI_TEXT_CLIP_MARGIN
2019-09-06 16:12:47 +10:00
/** \} */
2019-09-06 16:12:47 +10:00
/* -------------------------------------------------------------------- */
/** \name Widget State Management
*
* Adjust widget display based on animated, driven, overridden ... etc.
* \{ */
/* put all widget colors on half alpha, use local storage */
static void ui_widget_color_disabled(uiWidgetType *wt, const int state)
{
static uiWidgetColors wcol_theme_s;
wcol_theme_s = *wt->wcol_theme;
const float factor = widget_alpha_factor(state);
wcol_theme_s.outline[3] *= factor;
wcol_theme_s.inner[3] *= factor;
wcol_theme_s.inner_sel[3] *= factor;
wcol_theme_s.item[3] *= factor;
wcol_theme_s.text[3] *= factor;
wcol_theme_s.text_sel[3] *= factor;
wt->wcol_theme = &wcol_theme_s;
}
static void widget_active_color(uiWidgetColors *wcol)
{
const bool dark = (rgb_to_grayscale_byte(wcol->text) > rgb_to_grayscale_byte(wcol->inner));
color_mul_hsl_v3(wcol->inner, 1.0f, 1.15f, dark ? 1.2f : 1.1f);
color_mul_hsl_v3(wcol->outline, 1.0f, 1.15f, 1.15f);
color_mul_hsl_v3(wcol->text, 1.0f, 1.15f, dark ? 1.25f : 0.8f);
}
static const uchar *widget_color_blend_from_flags(const uiWidgetStateColors *wcol_state,
int state,
int drawflag,
const eUIEmbossType emboss)
{
/* Explicitly require #UI_EMBOSS_NONE_OR_STATUS for color blending with no emboss. */
if (emboss == UI_EMBOSS_NONE) {
return NULL;
}
if (drawflag & UI_BUT_ANIMATED_CHANGED) {
return wcol_state->inner_changed_sel;
}
if (state & UI_BUT_ANIMATED_KEY) {
return wcol_state->inner_key_sel;
}
if (state & UI_BUT_ANIMATED) {
return wcol_state->inner_anim_sel;
}
if (state & UI_BUT_DRIVEN) {
return wcol_state->inner_driven_sel;
}
if (state & UI_BUT_OVERRIDDEN) {
return wcol_state->inner_overridden_sel;
}
return NULL;
}
/* copy colors from theme, and set changes in it based on state */
static void widget_state(uiWidgetType *wt, int state, int drawflag, eUIEmbossType emboss)
{
2012-03-30 01:51:25 +00:00
uiWidgetStateColors *wcol_state = wt->wcol_state;
2017-11-03 00:22:59 +11:00
if ((state & UI_BUT_LIST_ITEM) && !(state & UI_STATE_TEXT_INPUT)) {
/* Override default widget's colors. */
bTheme *btheme = UI_GetTheme();
wt->wcol_theme = &btheme->tui.wcol_list_item;
if (state & (UI_BUT_DISABLED | UI_BUT_INACTIVE | UI_SEARCH_FILTER_NO_MATCH)) {
ui_widget_color_disabled(wt, state);
}
}
2012-03-30 01:51:25 +00:00
wt->wcol = *(wt->wcol_theme);
const uchar *color_blend = widget_color_blend_from_flags(wcol_state, state, drawflag, emboss);
if (state & UI_SELECT) {
copy_v4_v4_uchar(wt->wcol.inner, wt->wcol.inner_sel);
if (color_blend != NULL) {
color_blend_v3_v3(wt->wcol.inner, color_blend, wcol_state->blend);
2019-03-25 10:15:20 +11:00
}
copy_v3_v3_uchar(wt->wcol.text, wt->wcol.text_sel);
2019-03-25 10:15:20 +11:00
if (state & UI_SELECT) {
SWAP(short, wt->wcol.shadetop, wt->wcol.shadedown);
2019-03-25 10:15:20 +11:00
}
}
else {
if (state & UI_BUT_ACTIVE_DEFAULT) {
copy_v4_v4_uchar(wt->wcol.inner, wt->wcol.inner_sel);
copy_v4_v4_uchar(wt->wcol.text, wt->wcol.text_sel);
}
if (color_blend != NULL) {
color_blend_v3_v3(wt->wcol.inner, color_blend, wcol_state->blend);
2019-03-25 10:15:20 +11:00
}
/* Add "hover" highlight. Ideally this could apply in all cases,
* even if UI_SELECT. But currently this causes some flickering
* as buttons can be created and updated without respect to mouse
* position and so can draw without UI_ACTIVE set. See D6503. */
if (state & UI_ACTIVE) {
widget_active_color(&wt->wcol);
}
}
if (state & UI_BUT_REDALERT) {
const uchar red[4] = {255, 0, 0};
if (wt->draw && emboss != UI_EMBOSS_NONE) {
color_blend_v3_v3(wt->wcol.inner, red, 0.4f);
}
else {
color_blend_v3_v3(wt->wcol.text, red, 0.4f);
}
}
if (state & UI_BUT_DRAG_MULTI) {
/* the button isn't SELECT but we're editing this so draw with sel color */
copy_v4_v4_uchar(wt->wcol.inner, wt->wcol.inner_sel);
SWAP(short, wt->wcol.shadetop, wt->wcol.shadedown);
color_blend_v3_v3(wt->wcol.text, wt->wcol.text_sel, 0.85f);
}
if (state & UI_BUT_NODE_ACTIVE) {
const uchar blue[4] = {86, 128, 194};
color_blend_v3_v3(wt->wcol.inner, blue, 0.3f);
}
}
2019-09-06 16:12:47 +10:00
/** \} */
/* -------------------------------------------------------------------- */
/** \name Widget Types
* \{ */
/* sliders use special hack which sets 'item' as inner when drawing filling */
static void widget_state_numslider(uiWidgetType *wt, int state, int drawflag, eUIEmbossType emboss)
{
2012-03-30 01:51:25 +00:00
uiWidgetStateColors *wcol_state = wt->wcol_state;
/* call this for option button */
widget_state(wt, state, drawflag, emboss);
const uchar *color_blend = widget_color_blend_from_flags(wcol_state, state, drawflag, emboss);
if (color_blend != NULL) {
/* Set the slider 'item' so that it reflects state settings too.
* De-saturate so the color of the slider doesn't conflict with the blend color,
* which can make the color hard to see when the slider is set to full (see T66102). */
wt->wcol.item[0] = wt->wcol.item[1] = wt->wcol.item[2] = rgb_to_grayscale_byte(wt->wcol.item);
color_blend_v3_v3(wt->wcol.item, color_blend, wcol_state->blend);
color_ensure_contrast_v3(wt->wcol.item, wt->wcol.inner, 30);
}
if (state & UI_SELECT) {
SWAP(short, wt->wcol.shadetop, wt->wcol.shadedown);
}
}
/* labels use theme colors for text */
static void widget_state_option_menu(uiWidgetType *wt,
int state,
int drawflag,
eUIEmbossType emboss)
{
const bTheme *btheme = UI_GetTheme();
const uiWidgetColors *old_wcol = wt->wcol_theme;
uiWidgetColors wcol_menu_option = *wt->wcol_theme;
/* Override the checkbox theme colors to use the menu-back text colors. */
copy_v3_v3_uchar(wcol_menu_option.text, btheme->tui.wcol_menu_back.text);
copy_v3_v3_uchar(wcol_menu_option.text_sel, btheme->tui.wcol_menu_back.text_sel);
wt->wcol_theme = &wcol_menu_option;
widget_state(wt, state, drawflag, emboss);
wt->wcol_theme = old_wcol;
}
static void widget_state_nothing(uiWidgetType *wt,
int UNUSED(state),
int UNUSED(drawflag),
eUIEmbossType UNUSED(emboss))
{
2012-03-30 01:51:25 +00:00
wt->wcol = *(wt->wcol_theme);
}
2009-04-27 13:44:11 +00:00
/* special case, button that calls pulldown */
static void widget_state_pulldown(uiWidgetType *wt,
int UNUSED(state),
int UNUSED(drawflag),
eUIEmbossType UNUSED(emboss))
{
2012-03-30 01:51:25 +00:00
wt->wcol = *(wt->wcol_theme);
}
/* special case, pie menu items */
static void widget_state_pie_menu_item(uiWidgetType *wt,
int state,
int UNUSED(drawflag),
eUIEmbossType UNUSED(emboss))
{
wt->wcol = *(wt->wcol_theme);
/* active and disabled (not so common) */
if ((state & UI_BUT_DISABLED) && (state & UI_ACTIVE)) {
color_blend_v3_v3(wt->wcol.text, wt->wcol.text_sel, 0.5f);
/* draw the backdrop at low alpha, helps navigating with keys
* when disabled items are active */
copy_v4_v4_uchar(wt->wcol.inner, wt->wcol.item);
wt->wcol.inner[3] = 64;
}
else {
/* regular active */
if (state & (UI_SELECT | UI_ACTIVE)) {
copy_v3_v3_uchar(wt->wcol.text, wt->wcol.text_sel);
}
else if (state & (UI_BUT_DISABLED | UI_BUT_INACTIVE)) {
/* regular disabled */
color_blend_v3_v3(wt->wcol.text, wt->wcol.inner, 0.5f);
}
if (state & UI_SELECT) {
copy_v4_v4_uchar(wt->wcol.inner, wt->wcol.inner_sel);
}
else if (state & UI_ACTIVE) {
copy_v4_v4_uchar(wt->wcol.inner, wt->wcol.item);
}
}
}
/* special case, menu items */
static void widget_state_menu_item(uiWidgetType *wt,
int state,
int UNUSED(drawflag),
eUIEmbossType UNUSED(emboss))
{
2012-03-30 01:51:25 +00:00
wt->wcol = *(wt->wcol_theme);
/* active and disabled (not so common) */
if ((state & UI_BUT_DISABLED) && (state & UI_ACTIVE)) {
/* draw the backdrop at low alpha, helps navigating with keys
* when disabled items are active */
wt->wcol.text[3] = 128;
color_blend_v3_v3(wt->wcol.inner, wt->wcol.text, 0.5f);
wt->wcol.inner[3] = 64;
}
else {
/* regular active */
if (state & UI_ACTIVE) {
copy_v3_v3_uchar(wt->wcol.text, wt->wcol.text_sel);
}
else if (state & (UI_BUT_DISABLED | UI_BUT_INACTIVE)) {
/* regular disabled */
color_blend_v3_v3(wt->wcol.text, wt->wcol.inner, 0.5f);
}
if (state & UI_ACTIVE) {
copy_v4_v4_uchar(wt->wcol.inner, wt->wcol.inner_sel);
}
}
}
2019-09-06 16:12:47 +10:00
/** \} */
/* -------------------------------------------------------------------- */
/** \name Draw Menu Backdrop
2019-09-06 16:12:47 +10:00
* \{ */
/* outside of rect, rad to left/bottom/right */
static void widget_softshadow(const rcti *rect, int roundboxalign, const float radin)
{
bTheme *btheme = UI_GetTheme();
uiWidgetBase wtb;
2012-03-30 01:51:25 +00:00
rcti rect1 = *rect;
float triangle_strip[WIDGET_SIZE_MAX * 2 + 2][2];
const float radout = UI_ThemeMenuShadowWidth();
/* disabled shadow */
2019-03-25 10:15:20 +11:00
if (radout == 0.0f) {
return;
2019-03-25 10:15:20 +11:00
}
/* prevent tooltips to not show round shadow */
2019-03-25 10:15:20 +11:00
if (radout > 0.2f * BLI_rcti_size_y(&rect1)) {
rect1.ymax -= 0.2f * BLI_rcti_size_y(&rect1);
2019-03-25 10:15:20 +11:00
}
else {
Holiday coding log :) Nice formatted version (pictures soon): http://wiki.blender.org/index.php/Dev:Ref/Release_Notes/2.66/Usability Short list of main changes: - Transparent region option (over main region), added code to blend in/out such panels. - Min size window now 640 x 480 - Fixed DPI for ui - lots of cleanup and changes everywhere. Icon image need correct size still, layer-in-use icon needs remake. - Macbook retina support, use command line --no-native-pixels to disable it - Timeline Marker label was drawing wrong - Trackpad and magic mouse: supports zoom (hold ctrl) - Fix for splash position: removed ghost function and made window size update after creation immediate - Fast undo buffer save now adds UI as well. Could be checked for regular file save even... Quit.blend and temp file saving use this now. - Dixed filename in window on reading quit.blend or temp saves, and they now add a warning in window title: "(Recovered)" - New Userpref option "Keep Session" - this always saves quit.blend, and loads on start. This allows keeping UI and data without actual saves, until you actually save. When you load startup.blend and quit, it recognises the quit.blend as a startup (no file name in header) - Added 3D view copy/paste buffers (selected objects). Shortcuts ctrl-c, ctrl-v (OSX, cmd-c, cmd-v). Coded partial file saving for it. Could be used for other purposes. Todo: use OS clipboards. - User preferences (themes, keymaps, user settings) now can be saved as a separate file. Old option is called "Save Startup File" the new one "Save User Settings". To visualise this difference, the 'save startup file' button has been removed from user preferences window. That option is available as CTRL+U and in File menu still. - OSX: fixed bug that stopped giving mouse events outside window. This also fixes "Continuous Grab" for OSX. (error since 2009)
2012-12-12 18:58:11 +00:00
rect1.ymax -= radout;
2019-03-25 10:15:20 +11:00
}
/* inner part */
const int 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 */
const float alphastep = 3.0f * btheme->tui.menu_shadow_fac / radout;
const uint pos = GPU_vertformat_attr_add(
immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
for (int step = 1; step <= (int)radout; step++) {
const float expfac = sqrtf(step / radout);
round_box_shadow_edges(wtb.outer_v, &rect1, radin, UI_CNR_ALL, (float)step);
immUniformColor4f(0.0f, 0.0f, 0.0f, alphastep * (1.0f - expfac));
widget_verts_to_triangle_strip(&wtb, totvert, triangle_strip);
widget_draw_vertex_buffer(pos, 0, GPU_PRIM_TRI_STRIP, triangle_strip, NULL, totvert * 2);
}
immUnbindProgram();
}
static void widget_menu_back(uiWidgetColors *wcol, rcti *rect, int flag, int direction)
{
uiWidgetBase wtb;
2012-03-30 01:51:25 +00:00
int roundboxalign = UI_CNR_ALL;
widget_init(&wtb);
/* menu is 2nd level or deeper */
if (flag & UI_BLOCK_POPUP) {
// rect->ymin -= 4.0;
// rect->ymax += 4.0;
}
else if (direction == UI_DIR_DOWN) {
2012-03-30 01:51:25 +00:00
roundboxalign = (UI_CNR_BOTTOM_RIGHT | UI_CNR_BOTTOM_LEFT);
Holiday coding log :) Nice formatted version (pictures soon): http://wiki.blender.org/index.php/Dev:Ref/Release_Notes/2.66/Usability Short list of main changes: - Transparent region option (over main region), added code to blend in/out such panels. - Min size window now 640 x 480 - Fixed DPI for ui - lots of cleanup and changes everywhere. Icon image need correct size still, layer-in-use icon needs remake. - Macbook retina support, use command line --no-native-pixels to disable it - Timeline Marker label was drawing wrong - Trackpad and magic mouse: supports zoom (hold ctrl) - Fix for splash position: removed ghost function and made window size update after creation immediate - Fast undo buffer save now adds UI as well. Could be checked for regular file save even... Quit.blend and temp file saving use this now. - Dixed filename in window on reading quit.blend or temp saves, and they now add a warning in window title: "(Recovered)" - New Userpref option "Keep Session" - this always saves quit.blend, and loads on start. This allows keeping UI and data without actual saves, until you actually save. When you load startup.blend and quit, it recognises the quit.blend as a startup (no file name in header) - Added 3D view copy/paste buffers (selected objects). Shortcuts ctrl-c, ctrl-v (OSX, cmd-c, cmd-v). Coded partial file saving for it. Could be used for other purposes. Todo: use OS clipboards. - User preferences (themes, keymaps, user settings) now can be saved as a separate file. Old option is called "Save Startup File" the new one "Save User Settings". To visualise this difference, the 'save startup file' button has been removed from user preferences window. That option is available as CTRL+U and in File menu still. - OSX: fixed bug that stopped giving mouse events outside window. This also fixes "Continuous Grab" for OSX. (error since 2009)
2012-12-12 18:58:11 +00:00
rect->ymin -= 0.1f * U.widget_unit;
}
else if (direction == UI_DIR_UP) {
2012-03-30 01:51:25 +00:00
roundboxalign = UI_CNR_TOP_LEFT | UI_CNR_TOP_RIGHT;
Holiday coding log :) Nice formatted version (pictures soon): http://wiki.blender.org/index.php/Dev:Ref/Release_Notes/2.66/Usability Short list of main changes: - Transparent region option (over main region), added code to blend in/out such panels. - Min size window now 640 x 480 - Fixed DPI for ui - lots of cleanup and changes everywhere. Icon image need correct size still, layer-in-use icon needs remake. - Macbook retina support, use command line --no-native-pixels to disable it - Timeline Marker label was drawing wrong - Trackpad and magic mouse: supports zoom (hold ctrl) - Fix for splash position: removed ghost function and made window size update after creation immediate - Fast undo buffer save now adds UI as well. Could be checked for regular file save even... Quit.blend and temp file saving use this now. - Dixed filename in window on reading quit.blend or temp saves, and they now add a warning in window title: "(Recovered)" - New Userpref option "Keep Session" - this always saves quit.blend, and loads on start. This allows keeping UI and data without actual saves, until you actually save. When you load startup.blend and quit, it recognises the quit.blend as a startup (no file name in header) - Added 3D view copy/paste buffers (selected objects). Shortcuts ctrl-c, ctrl-v (OSX, cmd-c, cmd-v). Coded partial file saving for it. Could be used for other purposes. Todo: use OS clipboards. - User preferences (themes, keymaps, user settings) now can be saved as a separate file. Old option is called "Save Startup File" the new one "Save User Settings". To visualise this difference, the 'save startup file' button has been removed from user preferences window. That option is available as CTRL+U and in File menu still. - OSX: fixed bug that stopped giving mouse events outside window. This also fixes "Continuous Grab" for OSX. (error since 2009)
2012-12-12 18:58:11 +00:00
rect->ymax += 0.1f * U.widget_unit;
}
GPU_blend(GPU_BLEND_ALPHA);
2018-04-22 13:57:42 +02:00
widget_softshadow(rect, roundboxalign, wcol->roundness * U.widget_unit);
2018-04-22 13:57:42 +02:00
round_box_edges(&wtb, roundboxalign, rect, wcol->roundness * U.widget_unit);
wtb.draw_emboss = false;
widgetbase_draw(&wtb, wcol);
GPU_blend(GPU_BLEND_NONE);
}
static void ui_hsv_cursor(float x, float y)
{
const uint pos = GPU_vertformat_attr_add(
immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
immUniformColor3f(1.0f, 1.0f, 1.0f);
imm_draw_circle_fill_2d(pos, x, y, 3.0f * U.pixelsize, 8);
GPU_blend(GPU_BLEND_ALPHA);
GPU_line_smooth(true);
immUniformColor3f(0.0f, 0.0f, 0.0f);
imm_draw_circle_wire_2d(pos, x, y, 3.0f * U.pixelsize, 12);
GPU_blend(GPU_BLEND_NONE);
GPU_line_smooth(false);
immUnbindProgram();
}
2018-07-01 19:57:31 +02:00
void ui_hsvcircle_vals_from_pos(
2019-03-25 12:19:55 +11:00
const rcti *rect, const float mx, const float my, float *r_val_rad, float *r_val_dist)
{
/* duplication of code... well, simple is better now */
const float centx = BLI_rcti_cent_x_fl(rect);
const float centy = BLI_rcti_cent_y_fl(rect);
const float radius = (float)min_ii(BLI_rcti_size_x(rect), BLI_rcti_size_y(rect)) / 2.0f;
const float m_delta[2] = {mx - centx, my - centy};
const float dist_sq = len_squared_v2(m_delta);
2019-03-25 12:19:55 +11:00
*r_val_dist = (dist_sq < (radius * radius)) ? sqrtf(dist_sq) / radius : 1.0f;
*r_val_rad = atan2f(m_delta[0], m_delta[1]) / (2.0f * (float)M_PI) + 0.5f;
}
/* cursor in hsv circle, in float units -1 to 1, to map on radius */
void ui_hsvcircle_pos_from_vals(
const ColorPicker *cpicker, const rcti *rect, const float *hsv, float *r_xpos, float *r_ypos)
{
/* duplication of code... well, simple is better now */
const float centx = BLI_rcti_cent_x_fl(rect);
const float centy = BLI_rcti_cent_y_fl(rect);
2021-01-04 17:02:13 +11:00
const float radius = (float)min_ii(BLI_rcti_size_x(rect), BLI_rcti_size_y(rect)) / 2.0f;
const float ang = 2.0f * (float)M_PI * hsv[0] + (float)M_PI_2;
float radius_t;
2019-03-25 10:15:20 +11:00
if (cpicker->use_color_cubic && (U.color_picker_type == USER_CP_CIRCLE_HSV)) {
radius_t = (1.0f - pow3f(1.0f - hsv[1]));
2019-03-25 10:15:20 +11:00
}
else {
radius_t = hsv[1];
2019-03-25 10:15:20 +11:00
}
2021-01-04 17:02:13 +11:00
const float rad = clamp_f(radius_t, 0.0f, 1.0f) * radius;
*r_xpos = centx + cosf(-ang) * rad;
*r_ypos = centy + sinf(-ang) * rad;
}
static void ui_draw_but_HSVCIRCLE(uiBut *but, const uiWidgetColors *wcol, const rcti *rect)
{
/* TODO(merwin): reimplement as shader for pixel-perfect colors */
const int tot = 64;
const float radstep = 2.0f * (float)M_PI / (float)tot;
const float centx = BLI_rcti_cent_x_fl(rect);
const float centy = BLI_rcti_cent_y_fl(rect);
const float radius = (float)min_ii(BLI_rcti_size_x(rect), BLI_rcti_size_y(rect)) / 2.0f;
ColorPicker *cpicker = but->custom_data;
float rgb[3], hsv[3], rgb_center[3];
const bool is_color_gamma = ui_but_is_color_gamma(but);
/* Initialize for compatibility. */
copy_v3_v3(hsv, cpicker->hsv_perceptual);
/* Compute current hue. */
ui_but_v3_get(but, rgb);
ui_scene_linear_to_perceptual_space(but, rgb);
ui_color_picker_rgb_to_hsv_compat(rgb, hsv);
Fix T39228 Gamma/lift/gain are burned out in the circular color pickers and value/lightness slider stops midway. Issue here is manyfold: Color wheel does not support properties with different soft min/max values than 1.0 (which after experimenting a little I left as is), and also color management is completely destroying the mapping between the value slider and the RNA property value range. To solve this I have disabled color management by setting the property to gamma corrected (only in RNA, Sequence editor coders please check!), otherwise it will just become a big mess of tracking where color comes from and what kind of color transforms it needs in different color pickers (if property has non normalized range etc). HSL is not really meant to represent colors outside a normalized space so I have disabled setting lightness above 1.0 in this model. This will work, however it is hacking a color picker to do something other than what it is supposed to do: pick a color from the screen accurately. Which means normalized values always. The non normalized colors picked for lift/gain/gamma through the pickers do not correspond to any accurate colors; they are rather a user friendly way to 'sort of' choose a color and a gamma with an indication of maximum value. I think that lift/gamma/gain nodes need a dedicated widget for this (besides it is quite clear that some options are written for that use case) -or- a separate gamma multiplier for the picked color (which should itself be in a normalized space)
2014-03-18 01:08:24 +02:00
CLAMP(hsv[2], 0.0f, 1.0f); /* for display only */
/* exception: if 'lock' is set
* lock the value of the color wheel to 1.
2011-10-23 15:43:12 +00:00
* Useful for color correction tools where you're only interested in hue. */
if (cpicker->use_color_lock) {
if (U.color_picker_type == USER_CP_CIRCLE_HSV) {
hsv[2] = 1.0f;
}
else {
hsv[2] = 0.5f;
}
}
const float hsv_center[3] = {0.0f, 0.0f, hsv[2]};
ui_color_picker_hsv_to_rgb(hsv_center, rgb_center);
ui_perceptual_to_scene_linear_space(but, rgb_center);
if (!is_color_gamma) {
ui_block_cm_to_display_space_v3(but->block, rgb_center);
}
GPUVertFormat *format = immVertexFormat();
uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
const uint color = GPU_vertformat_attr_add(format, "color", GPU_COMP_F32, 3, GPU_FETCH_FLOAT);
immBindBuiltinProgram(GPU_SHADER_2D_SMOOTH_COLOR);
immBegin(GPU_PRIM_TRI_FAN, tot + 2);
immAttr3fv(color, rgb_center);
immVertex2f(pos, centx, centy);
float ang = 0.0f;
for (int a = 0; a <= tot; a++, ang += radstep) {
const float si = sinf(ang);
const float co = cosf(ang);
float hsv_ang[3];
float rgb_ang[3];
2019-03-25 12:19:55 +11:00
ui_hsvcircle_vals_from_pos(
rect, centx + co * radius, centy + si * radius, hsv_ang, hsv_ang + 1);
hsv_ang[2] = hsv[2];
ui_color_picker_hsv_to_rgb(hsv_ang, rgb_ang);
ui_perceptual_to_scene_linear_space(but, rgb_ang);
if (!is_color_gamma) {
ui_block_cm_to_display_space_v3(but->block, rgb_ang);
}
immAttr3fv(color, rgb_ang);
immVertex2f(pos, centx + co * radius, centy + si * radius);
}
immEnd();
immUnbindProgram();
/* fully rounded outline */
format = immVertexFormat();
pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
GPU_blend(GPU_BLEND_ALPHA);
GPU_line_smooth(true);
immUniformColor3ubv(wcol->outline);
imm_draw_circle_wire_2d(pos, centx, centy, radius, tot);
immUnbindProgram();
GPU_blend(GPU_BLEND_NONE);
GPU_line_smooth(false);
/* cursor */
copy_v3_v3(hsv, cpicker->hsv_perceptual);
ui_but_v3_get(but, rgb);
ui_scene_linear_to_perceptual_space(but, rgb);
ui_color_picker_rgb_to_hsv_compat(rgb, hsv);
float xpos, ypos;
ui_hsvcircle_pos_from_vals(cpicker, rect, hsv, &xpos, &ypos);
ui_hsv_cursor(xpos, ypos);
}
2019-09-06 16:12:47 +10:00
/** \} */
/* -------------------------------------------------------------------- */
/** \name Draw Custom Buttons
2019-09-06 16:12:47 +10:00
* \{ */
/* draws in resolution of 48x4 colors */
void ui_draw_gradient(const rcti *rect,
const float hsv[3],
const eButGradientType type,
const float alpha)
{
/* allows for 4 steps (red->yellow) */
const int steps = 48;
const float color_step = 1.0f / steps;
int a;
const float h = hsv[0], s = hsv[1], v = hsv[2];
float dx, dy, sx1, sx2, sy;
float col0[4][3]; /* left half, rect bottom to top */
float col1[4][3]; /* right half, rect bottom to top */
/* draw series of gouraud rects */
2012-03-30 01:51:25 +00:00
switch (type) {
case UI_GRAD_SV:
hsv_to_rgb(h, 0.0, 0.0, &col1[0][0], &col1[0][1], &col1[0][2]);
hsv_to_rgb(h, 0.0, 0.333, &col1[1][0], &col1[1][1], &col1[1][2]);
hsv_to_rgb(h, 0.0, 0.666, &col1[2][0], &col1[2][1], &col1[2][2]);
hsv_to_rgb(h, 0.0, 1.0, &col1[3][0], &col1[3][1], &col1[3][2]);
break;
case UI_GRAD_HV:
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]);
break;
case UI_GRAD_HS:
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]);
break;
case UI_GRAD_H:
hsv_to_rgb(0.0, 1.0, 1.0, &col1[0][0], &col1[0][1], &col1[0][2]);
copy_v3_v3(col1[1], col1[0]);
copy_v3_v3(col1[2], col1[0]);
copy_v3_v3(col1[3], col1[0]);
break;
case UI_GRAD_S:
hsv_to_rgb(1.0, 0.0, 1.0, &col1[1][0], &col1[1][1], &col1[1][2]);
copy_v3_v3(col1[0], col1[1]);
copy_v3_v3(col1[2], col1[1]);
copy_v3_v3(col1[3], col1[1]);
break;
case UI_GRAD_V:
hsv_to_rgb(1.0, 1.0, 0.0, &col1[2][0], &col1[2][1], &col1[2][2]);
copy_v3_v3(col1[0], col1[2]);
copy_v3_v3(col1[1], col1[2]);
copy_v3_v3(col1[3], col1[2]);
break;
default:
BLI_assert(!"invalid 'type' argument");
hsv_to_rgb(1.0, 1.0, 1.0, &col1[2][0], &col1[2][1], &col1[2][2]);
copy_v3_v3(col1[0], col1[2]);
copy_v3_v3(col1[1], col1[2]);
copy_v3_v3(col1[3], col1[2]);
break;
}
/* old below */
GPUVertFormat *format = immVertexFormat();
const uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
const uint col = GPU_vertformat_attr_add(format, "color", GPU_COMP_F32, 4, GPU_FETCH_FLOAT);
immBindBuiltinProgram(GPU_SHADER_2D_SMOOTH_COLOR);
immBegin(GPU_PRIM_TRIS, steps * 3 * 6);
/* 0.999 = prevent float inaccuracy for steps */
for (dx = 0.0f; dx < 0.999f; dx += color_step) {
const float dx_next = dx + color_step;
2012-08-19 10:41:27 +00:00
/* previous color */
copy_v3_v3(col0[0], col1[0]);
copy_v3_v3(col0[1], col1[1]);
copy_v3_v3(col0[2], col1[2]);
copy_v3_v3(col0[3], col1[3]);
2012-08-19 10:41:27 +00:00
/* new color */
2012-03-30 01:51:25 +00:00
switch (type) {
case UI_GRAD_SV:
hsv_to_rgb(h, dx, 0.0, &col1[0][0], &col1[0][1], &col1[0][2]);
hsv_to_rgb(h, dx, 0.333, &col1[1][0], &col1[1][1], &col1[1][2]);
hsv_to_rgb(h, dx, 0.666, &col1[2][0], &col1[2][1], &col1[2][2]);
hsv_to_rgb(h, dx, 1.0, &col1[3][0], &col1[3][1], &col1[3][2]);
break;
case UI_GRAD_HV:
hsv_to_rgb(dx_next, s, 0.0, &col1[0][0], &col1[0][1], &col1[0][2]);
hsv_to_rgb(dx_next, s, 0.333, &col1[1][0], &col1[1][1], &col1[1][2]);
hsv_to_rgb(dx_next, s, 0.666, &col1[2][0], &col1[2][1], &col1[2][2]);
hsv_to_rgb(dx_next, s, 1.0, &col1[3][0], &col1[3][1], &col1[3][2]);
break;
case UI_GRAD_HS:
hsv_to_rgb(dx_next, 0.0, v, &col1[0][0], &col1[0][1], &col1[0][2]);
hsv_to_rgb(dx_next, 0.333, v, &col1[1][0], &col1[1][1], &col1[1][2]);
hsv_to_rgb(dx_next, 0.666, v, &col1[2][0], &col1[2][1], &col1[2][2]);
hsv_to_rgb(dx_next, 1.0, v, &col1[3][0], &col1[3][1], &col1[3][2]);
break;
case UI_GRAD_H:
/* annoying but without this the color shifts - could be solved some other way
* - campbell */
hsv_to_rgb(dx_next, 1.0, 1.0, &col1[0][0], &col1[0][1], &col1[0][2]);
copy_v3_v3(col1[1], col1[0]);
copy_v3_v3(col1[2], col1[0]);
copy_v3_v3(col1[3], col1[0]);
break;
case UI_GRAD_S:
hsv_to_rgb(h, dx, 1.0, &col1[1][0], &col1[1][1], &col1[1][2]);
copy_v3_v3(col1[0], col1[1]);
copy_v3_v3(col1[2], col1[1]);
copy_v3_v3(col1[3], col1[1]);
break;
case UI_GRAD_V:
hsv_to_rgb(h, 1.0, dx, &col1[2][0], &col1[2][1], &col1[2][2]);
copy_v3_v3(col1[0], col1[2]);
copy_v3_v3(col1[1], col1[2]);
copy_v3_v3(col1[3], col1[2]);
break;
default:
break;
}
2012-08-19 10:41:27 +00:00
/* rect */
sx1 = rect->xmin + dx * BLI_rcti_size_x(rect);
sx2 = rect->xmin + dx_next * BLI_rcti_size_x(rect);
2012-03-30 01:51:25 +00:00
sy = rect->ymin;
dy = (float)BLI_rcti_size_y(rect) / 3.0f;
2012-03-30 01:51:25 +00:00
for (a = 0; a < 3; a++, sy += dy) {
immAttr4f(col, col0[a][0], col0[a][1], col0[a][2], alpha);
immVertex2f(pos, sx1, sy);
immAttr4f(col, col1[a][0], col1[a][1], col1[a][2], alpha);
immVertex2f(pos, sx2, sy);
immAttr4f(col, col1[a + 1][0], col1[a + 1][1], col1[a + 1][2], alpha);
immVertex2f(pos, sx2, sy + dy);
immAttr4f(col, col0[a][0], col0[a][1], col0[a][2], alpha);
immVertex2f(pos, sx1, sy);
immAttr4f(col, col1[a + 1][0], col1[a + 1][1], col1[a + 1][2], alpha);
immVertex2f(pos, sx2, sy + dy);
immAttr4f(col, col0[a + 1][0], col0[a + 1][1], col0[a + 1][2], alpha);
immVertex2f(pos, sx1, sy + dy);
}
}
immEnd();
immUnbindProgram();
}
void ui_hsvcube_pos_from_vals(
const uiButHSVCube *hsv_but, const rcti *rect, const float *hsv, float *r_xp, float *r_yp)
{
2014-01-06 15:05:21 +01:00
float x = 0.0f, y = 0.0f;
switch (hsv_but->gradient_type) {
case UI_GRAD_SV:
x = hsv[1];
y = hsv[2];
break;
case UI_GRAD_HV:
x = hsv[0];
y = hsv[2];
break;
case UI_GRAD_HS:
x = hsv[0];
y = hsv[1];
break;
case UI_GRAD_H:
x = hsv[0];
y = 0.5;
break;
case UI_GRAD_S:
x = hsv[1];
y = 0.5;
break;
case UI_GRAD_V:
x = hsv[2];
y = 0.5;
break;
case UI_GRAD_L_ALT:
Fix T39228 Gamma/lift/gain are burned out in the circular color pickers and value/lightness slider stops midway. Issue here is manyfold: Color wheel does not support properties with different soft min/max values than 1.0 (which after experimenting a little I left as is), and also color management is completely destroying the mapping between the value slider and the RNA property value range. To solve this I have disabled color management by setting the property to gamma corrected (only in RNA, Sequence editor coders please check!), otherwise it will just become a big mess of tracking where color comes from and what kind of color transforms it needs in different color pickers (if property has non normalized range etc). HSL is not really meant to represent colors outside a normalized space so I have disabled setting lightness above 1.0 in this model. This will work, however it is hacking a color picker to do something other than what it is supposed to do: pick a color from the screen accurately. Which means normalized values always. The non normalized colors picked for lift/gain/gamma through the pickers do not correspond to any accurate colors; they are rather a user friendly way to 'sort of' choose a color and a gamma with an indication of maximum value. I think that lift/gamma/gain nodes need a dedicated widget for this (besides it is quite clear that some options are written for that use case) -or- a separate gamma multiplier for the picked color (which should itself be in a normalized space)
2014-03-18 01:08:24 +02:00
x = 0.5f;
/* exception only for value strip - use the range set in but->min/max */
y = hsv[2];
break;
case UI_GRAD_V_ALT:
x = 0.5f;
/* exception only for value strip - use the range set in but->min/max */
y = (hsv[2] - hsv_but->but.softmin) / (hsv_but->but.softmax - hsv_but->but.softmin);
break;
}
/* cursor */
*r_xp = rect->xmin + x * BLI_rcti_size_x(rect);
*r_yp = rect->ymin + y * BLI_rcti_size_y(rect);
}
static void ui_draw_but_HSVCUBE(uiBut *but, const rcti *rect)
{
const uiButHSVCube *hsv_but = (uiButHSVCube *)but;
float rgb[3];
2012-03-30 01:51:25 +00:00
float x = 0.0f, y = 0.0f;
ColorPicker *cpicker = but->custom_data;
float *hsv = cpicker->hsv_perceptual;
float hsv_n[3];
/* Initialize for compatibility. */
copy_v3_v3(hsv_n, hsv);
ui_but_v3_get(but, rgb);
ui_scene_linear_to_perceptual_space(but, rgb);
rgb_to_hsv_compat_v(rgb, hsv_n);
ui_draw_gradient(rect, hsv_n, hsv_but->gradient_type, 1.0f);
ui_hsvcube_pos_from_vals(hsv_but, rect, hsv_n, &x, &y);
2012-03-30 01:51:25 +00:00
CLAMP(x, rect->xmin + 3.0f, rect->xmax - 3.0f);
CLAMP(y, rect->ymin + 3.0f, rect->ymax - 3.0f);
ui_hsv_cursor(x, y);
/* outline */
const uint pos = GPU_vertformat_attr_add(
immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
immUniformColor3ub(0, 0, 0);
2017-09-26 15:21:01 +10:00
imm_draw_box_wire_2d(pos, (rect->xmin), (rect->ymin), (rect->xmax), (rect->ymax));
immUnbindProgram();
}
/* vertical 'value' slider, using new widget code */
static void ui_draw_but_HSV_v(uiBut *but, const rcti *rect)
{
const uiButHSVCube *hsv_but = (uiButHSVCube *)but;
2018-04-22 13:57:42 +02:00
bTheme *btheme = UI_GetTheme();
uiWidgetColors *wcol = &btheme->tui.wcol_numslider;
uiWidgetBase wtb;
const float rad = wcol->roundness * BLI_rcti_size_x(rect);
float x, y;
Fix T39228 Gamma/lift/gain are burned out in the circular color pickers and value/lightness slider stops midway. Issue here is manyfold: Color wheel does not support properties with different soft min/max values than 1.0 (which after experimenting a little I left as is), and also color management is completely destroying the mapping between the value slider and the RNA property value range. To solve this I have disabled color management by setting the property to gamma corrected (only in RNA, Sequence editor coders please check!), otherwise it will just become a big mess of tracking where color comes from and what kind of color transforms it needs in different color pickers (if property has non normalized range etc). HSL is not really meant to represent colors outside a normalized space so I have disabled setting lightness above 1.0 in this model. This will work, however it is hacking a color picker to do something other than what it is supposed to do: pick a color from the screen accurately. Which means normalized values always. The non normalized colors picked for lift/gain/gamma through the pickers do not correspond to any accurate colors; they are rather a user friendly way to 'sort of' choose a color and a gamma with an indication of maximum value. I think that lift/gamma/gain nodes need a dedicated widget for this (besides it is quite clear that some options are written for that use case) -or- a separate gamma multiplier for the picked color (which should itself be in a normalized space)
2014-03-18 01:08:24 +02:00
float rgb[3], hsv[3], v;
ui_but_v3_get(but, rgb);
ui_scene_linear_to_perceptual_space(but, rgb);
if (hsv_but->gradient_type == UI_GRAD_L_ALT) {
rgb_to_hsl_v(rgb, hsv);
2019-03-25 10:15:20 +11:00
}
else {
rgb_to_hsv_v(rgb, hsv);
2019-03-25 10:15:20 +11:00
}
v = hsv[2];
/* map v from property range to [0,1] */
if (hsv_but->gradient_type == UI_GRAD_V_ALT) {
const float min = but->softmin, max = but->softmax;
v = (v - min) / (max - min);
Fix T39228 Gamma/lift/gain are burned out in the circular color pickers and value/lightness slider stops midway. Issue here is manyfold: Color wheel does not support properties with different soft min/max values than 1.0 (which after experimenting a little I left as is), and also color management is completely destroying the mapping between the value slider and the RNA property value range. To solve this I have disabled color management by setting the property to gamma corrected (only in RNA, Sequence editor coders please check!), otherwise it will just become a big mess of tracking where color comes from and what kind of color transforms it needs in different color pickers (if property has non normalized range etc). HSL is not really meant to represent colors outside a normalized space so I have disabled setting lightness above 1.0 in this model. This will work, however it is hacking a color picker to do something other than what it is supposed to do: pick a color from the screen accurately. Which means normalized values always. The non normalized colors picked for lift/gain/gamma through the pickers do not correspond to any accurate colors; they are rather a user friendly way to 'sort of' choose a color and a gamma with an indication of maximum value. I think that lift/gamma/gain nodes need a dedicated widget for this (besides it is quite clear that some options are written for that use case) -or- a separate gamma multiplier for the picked color (which should itself be in a normalized space)
2014-03-18 01:08:24 +02:00
}
widget_init(&wtb);
/* fully rounded */
round_box_edges(&wtb, UI_CNR_ALL, rect, rad);
/* setup temp colors */
widgetbase_draw(&wtb,
&((uiWidgetColors){
.outline = {0, 0, 0, 255},
.inner = {128, 128, 128, 255},
.shadetop = 127,
.shadedown = -128,
.shaded = 1,
}));
2018-04-10 17:42:33 +02:00
/* We are drawing on top of widget bases. Flush cache. */
GPU_blend(GPU_BLEND_ALPHA);
2018-04-10 17:42:33 +02:00
UI_widgetbase_draw_cache_flush();
GPU_blend(GPU_BLEND_NONE);
/* cursor */
x = rect->xmin + 0.5f * BLI_rcti_size_x(rect);
y = rect->ymin + v * BLI_rcti_size_y(rect);
2012-03-30 01:51:25 +00:00
CLAMP(y, rect->ymin + 3.0f, rect->ymax - 3.0f);
ui_hsv_cursor(x, y);
}
2019-09-06 16:12:47 +10:00
/** Separator for menus. */
static void ui_draw_separator(const rcti *rect, const uiWidgetColors *wcol)
{
const int y = rect->ymin + BLI_rcti_size_y(rect) / 2 - 1;
2019-09-14 08:10:50 +10:00
const uchar col[4] = {
wcol->text[0],
wcol->text[1],
wcol->text[2],
30,
};
const uint pos = GPU_vertformat_attr_add(
immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
GPU_blend(GPU_BLEND_ALPHA);
immUniformColor4ubv(col);
GPU_line_width(1.0f);
immBegin(GPU_PRIM_LINES, 2);
immVertex2f(pos, rect->xmin, y);
immVertex2f(pos, rect->xmax, y);
immEnd();
GPU_blend(GPU_BLEND_NONE);
immUnbindProgram();
}
2019-09-06 16:12:47 +10:00
/** \} */
/* -------------------------------------------------------------------- */
/** \name Button Draw Callbacks
* \{ */
static void widget_numbut_draw(
uiWidgetColors *wcol, rcti *rect, int state, int roundboxalign, bool emboss)
{
const float rad = wcol->roundness * BLI_rcti_size_y(rect);
const int handle_width = min_ii(BLI_rcti_size_x(rect) / 3, BLI_rcti_size_y(rect) * 0.7f);
2019-03-25 10:15:20 +11:00
if (state & UI_SELECT) {
SWAP(short, wcol->shadetop, wcol->shadedown);
2019-03-25 10:15:20 +11:00
}
uiWidgetBase wtb;
widget_init(&wtb);
if (!emboss) {
round_box_edges(&wtb, roundboxalign, rect, rad);
}
else {
wtb.draw_inner = false;
wtb.draw_outline = false;
}
/* decoration */
if ((state & UI_ACTIVE) && !(state & UI_STATE_TEXT_INPUT)) {
uiWidgetColors wcol_zone;
uiWidgetBase wtb_zone;
rcti rect_zone;
int roundboxalign_zone;
/* left arrow zone */
widget_init(&wtb_zone);
wtb_zone.draw_outline = false;
wtb_zone.draw_emboss = false;
wcol_zone = *wcol;
copy_v3_v3_uchar(wcol_zone.item, wcol->text);
if (state & UI_STATE_ACTIVE_LEFT) {
widget_active_color(&wcol_zone);
}
rect_zone = *rect;
rect_zone.xmax = rect->xmin + handle_width + U.pixelsize;
roundboxalign_zone = roundboxalign & ~(UI_CNR_TOP_RIGHT | UI_CNR_BOTTOM_RIGHT);
round_box_edges(&wtb_zone, roundboxalign_zone, &rect_zone, rad);
shape_preset_init_number_arrows(&wtb_zone.tria1, &rect_zone, 0.6f, 'l');
widgetbase_draw(&wtb_zone, &wcol_zone);
/* right arrow zone */
widget_init(&wtb_zone);
wtb_zone.draw_outline = false;
wtb_zone.draw_emboss = false;
wtb_zone.tria1.type = ROUNDBOX_TRIA_ARROWS;
wcol_zone = *wcol;
copy_v3_v3_uchar(wcol_zone.item, wcol->text);
if (state & UI_STATE_ACTIVE_RIGHT) {
widget_active_color(&wcol_zone);
}
rect_zone = *rect;
rect_zone.xmin = rect->xmax - handle_width - U.pixelsize;
roundboxalign_zone = roundboxalign & ~(UI_CNR_TOP_LEFT | UI_CNR_BOTTOM_LEFT);
round_box_edges(&wtb_zone, roundboxalign_zone, &rect_zone, rad);
shape_preset_init_number_arrows(&wtb_zone.tria2, &rect_zone, 0.6f, 'r');
widgetbase_draw(&wtb_zone, &wcol_zone);
/* middle highlight zone */
widget_init(&wtb_zone);
wtb_zone.draw_outline = false;
wtb_zone.draw_emboss = false;
wcol_zone = *wcol;
copy_v3_v3_uchar(wcol_zone.item, wcol->text);
2018-04-28 09:01:34 +02:00
if (!(state & (UI_STATE_ACTIVE_LEFT | UI_STATE_ACTIVE_RIGHT))) {
widget_active_color(&wcol_zone);
}
rect_zone = *rect;
rect_zone.xmin = rect->xmin + handle_width - U.pixelsize;
rect_zone.xmax = rect->xmax - handle_width + U.pixelsize;
round_box_edges(&wtb_zone, 0, &rect_zone, 0);
widgetbase_draw(&wtb_zone, &wcol_zone);
/* outline */
wtb.draw_inner = false;
widgetbase_draw(&wtb, wcol);
}
else {
/* inner and outline */
widgetbase_draw(&wtb, wcol);
}
2017-11-03 00:22:59 +11:00
if (!(state & UI_STATE_TEXT_INPUT)) {
2018-04-22 13:57:42 +02:00
const float textofs = 0.425f * BLI_rcti_size_y(rect);
/* text space */
rect->xmin += textofs;
rect->xmax -= textofs;
}
}
static void widget_numbut(uiWidgetColors *wcol, rcti *rect, int state, int roundboxalign)
{
widget_numbut_draw(wcol, rect, state, roundboxalign, false);
}
static void widget_menubut(uiWidgetColors *wcol, rcti *rect, int UNUSED(state), int roundboxalign)
{
uiWidgetBase wtb;
widget_init(&wtb);
const float rad = wcol->roundness * U.widget_unit;
round_box_edges(&wtb, roundboxalign, rect, rad);
/* decoration */
shape_preset_trias_from_rect_menu(&wtb.tria1, rect);
/* copy size and center to 2nd tria */
wtb.tria2 = wtb.tria1;
widgetbase_draw(&wtb, wcol);
/* text space, arrows are about 0.6 height of button */
rect->xmax -= (6 * BLI_rcti_size_y(rect)) / 10;
}
/**
* Draw menu buttons still with triangles when field is not embossed
*/
static void widget_menubut_embossn(const uiBut *UNUSED(but),
uiWidgetColors *wcol,
rcti *rect,
int UNUSED(state),
int UNUSED(roundboxalign))
{
uiWidgetBase wtb;
widget_init(&wtb);
wtb.draw_inner = false;
wtb.draw_outline = false;
/* decoration */
shape_preset_trias_from_rect_menu(&wtb.tria1, rect);
/* copy size and center to 2nd tria */
wtb.tria2 = wtb.tria1;
widgetbase_draw(&wtb, wcol);
}
2013-11-24 15:23:38 +11:00
/**
* Draw number buttons still with triangles when field is not embossed
2013-11-24 15:23:38 +11:00
*/
static void widget_numbut_embossn(
const uiBut *UNUSED(but), uiWidgetColors *wcol, rcti *rect, int state, int roundboxalign)
{
widget_numbut_draw(wcol, rect, state, roundboxalign, true);
}
/* function in use for buttons and for view2d sliders */
void UI_draw_widget_scroll(uiWidgetColors *wcol, const rcti *rect, const rcti *slider, int state)
{
uiWidgetBase wtb;
bool outline = false;
widget_init(&wtb);
/* determine horizontal/vertical */
2021-01-04 17:02:13 +11:00
const bool horizontal = (BLI_rcti_size_x(rect) > BLI_rcti_size_y(rect));
const float rad = (horizontal) ? wcol->roundness * BLI_rcti_size_y(rect) :
wcol->roundness * BLI_rcti_size_x(rect);
wtb.uniform_params.shade_dir = (horizontal) ? 1.0f : 0.0;
/* draw back part, colors swapped and shading inverted */
2019-03-25 10:15:20 +11:00
if (horizontal) {
SWAP(short, wcol->shadetop, wcol->shadedown);
2019-03-25 10:15:20 +11:00
}
round_box_edges(&wtb, UI_CNR_ALL, rect, rad);
widgetbase_draw(&wtb, wcol);
/* slider */
if ((BLI_rcti_size_x(slider) < 2) || (BLI_rcti_size_y(slider) < 2)) {
2012-08-20 23:06:17 +00:00
/* pass */
}
else {
SWAP(short, wcol->shadetop, wcol->shadedown);
copy_v4_v4_uchar(wcol->inner, wcol->item);
2019-03-25 10:15:20 +11:00
if (wcol->shadetop > wcol->shadedown) {
2012-03-30 01:51:25 +00:00
wcol->shadetop += 20; /* XXX violates themes... */
2019-03-25 10:15:20 +11:00
}
else {
wcol->shadedown += 20;
}
if (state & UI_SCROLL_PRESSED) {
2012-03-30 01:51:25 +00:00
wcol->inner[0] = wcol->inner[0] >= 250 ? 255 : wcol->inner[0] + 5;
wcol->inner[1] = wcol->inner[1] >= 250 ? 255 : wcol->inner[1] + 5;
wcol->inner[2] = wcol->inner[2] >= 250 ? 255 : wcol->inner[2] + 5;
}
/* draw */
wtb.draw_emboss = false; /* only emboss once */
/* exception for progress bar */
if (state & UI_SCROLL_NO_OUTLINE) {
SWAP(bool, outline, wtb.draw_outline);
}
round_box_edges(&wtb, UI_CNR_ALL, slider, rad);
if (state & UI_SCROLL_ARROWS) {
2019-03-25 10:15:20 +11:00
if (wcol->item[0] > 48) {
wcol->item[0] -= 48;
}
if (wcol->item[1] > 48) {
wcol->item[1] -= 48;
}
if (wcol->item[2] > 48) {
wcol->item[2] -= 48;
}
2012-03-30 01:51:25 +00:00
wcol->item[3] = 255;
if (horizontal) {
rcti slider_inset = *slider;
slider_inset.xmin += 0.05 * U.widget_unit;
slider_inset.xmax -= 0.05 * U.widget_unit;
shape_preset_init_scroll_circle(&wtb.tria1, &slider_inset, 0.6f, 'l');
shape_preset_init_scroll_circle(&wtb.tria2, &slider_inset, 0.6f, 'r');
}
else {
shape_preset_init_scroll_circle(&wtb.tria1, slider, 0.6f, 'b');
shape_preset_init_scroll_circle(&wtb.tria2, slider, 0.6f, 't');
}
}
widgetbase_draw(&wtb, wcol);
if (state & UI_SCROLL_NO_OUTLINE) {
SWAP(bool, outline, wtb.draw_outline);
}
}
}
static void widget_scroll(
uiBut *but, uiWidgetColors *wcol, rcti *rect, int state, int UNUSED(roundboxalign))
{
/* calculate slider part */
const float value = (float)ui_but_value_get(but);
const float size = max_ff((but->softmax + but->a1 - but->softmin), 2.0f);
/* position */
rcti rect1 = *rect;
/* determine horizontal/vertical */
const bool horizontal = (BLI_rcti_size_x(rect) > BLI_rcti_size_y(rect));
if (horizontal) {
const float fac = BLI_rcti_size_x(rect) / size;
rect1.xmin = rect1.xmin + ceilf(fac * (value - but->softmin));
2012-03-30 01:51:25 +00:00
rect1.xmax = rect1.xmin + ceilf(fac * (but->a1 - but->softmin));
2021-02-05 16:23:34 +11:00
/* Ensure minimum size. */
const float min = BLI_rcti_size_y(rect);
if (BLI_rcti_size_x(&rect1) < min) {
rect1.xmax = rect1.xmin + min;
if (rect1.xmax > rect->xmax) {
rect1.xmax = rect->xmax;
rect1.xmin = max_ii(rect1.xmax - min, rect->xmin);
}
}
}
else {
const float fac = BLI_rcti_size_y(rect) / size;
rect1.ymax = rect1.ymax - ceilf(fac * (value - but->softmin));
2012-03-30 01:51:25 +00:00
rect1.ymin = rect1.ymax - ceilf(fac * (but->a1 - but->softmin));
2021-02-05 16:23:34 +11:00
/* Ensure minimum size. */
2021-01-04 17:02:13 +11:00
const float min = BLI_rcti_size_x(rect);
if (BLI_rcti_size_y(&rect1) < min) {
rect1.ymax = rect1.ymin + min;
if (rect1.ymax > rect->ymax) {
rect1.ymax = rect->ymax;
rect1.ymin = max_ii(rect1.ymax - min, rect->ymin);
}
}
}
2019-03-25 10:15:20 +11:00
if (state & UI_SELECT) {
2012-03-30 01:51:25 +00:00
state = UI_SCROLL_PRESSED;
2019-03-25 10:15:20 +11:00
}
else {
2012-03-30 01:51:25 +00:00
state = 0;
2019-03-25 10:15:20 +11:00
}
UI_draw_widget_scroll(wcol, rect, &rect1, state);
}
static void widget_progressbar(
uiBut *but, uiWidgetColors *wcol, rcti *rect, int UNUSED(state), int roundboxalign)
{
uiButProgressbar *but_progressbar = (uiButProgressbar *)but;
rcti rect_prog = *rect, rect_bar = *rect;
uiWidgetBase wtb, wtb_bar;
widget_init(&wtb);
widget_init(&wtb_bar);
/* round corners */
const float value = but_progressbar->progress;
const float ofs = wcol->roundness * BLI_rcti_size_y(&rect_prog);
float w = value * BLI_rcti_size_x(&rect_prog);
2021-02-05 16:23:34 +11:00
/* Ensure minimum size. */
w = MAX2(w, ofs);
rect_bar.xmax = rect_bar.xmin + w;
round_box_edges(&wtb, roundboxalign, &rect_prog, ofs);
round_box_edges(&wtb_bar, roundboxalign, &rect_bar, ofs);
wtb.draw_outline = true;
widgetbase_draw(&wtb, wcol);
/* "slider" bar color */
copy_v3_v3_uchar(wcol->inner, wcol->item);
widgetbase_draw(&wtb_bar, wcol);
/* raise text a bit */
rect->xmin += (BLI_rcti_size_x(&rect_prog) / 2);
rect->xmax += (BLI_rcti_size_x(&rect_prog) / 2);
}
static void widget_datasetrow(
uiBut *but, uiWidgetColors *wcol, rcti *rect, int state, int UNUSED(roundboxalign))
{
uiButDatasetRow *but_componentrow = (uiButDatasetRow *)but;
uiWidgetBase wtb;
widget_init(&wtb);
/* no outline */
wtb.draw_outline = false;
const float rad = wcol->roundness * U.widget_unit;
round_box_edges(&wtb, UI_CNR_ALL, rect, rad);
if ((state & UI_ACTIVE) || (state & UI_SELECT)) {
widgetbase_draw(&wtb, wcol);
}
BLI_rcti_resize(rect,
BLI_rcti_size_x(rect) - UI_UNIT_X * but_componentrow->indentation,
BLI_rcti_size_y(rect));
BLI_rcti_translate(rect, 0.5f * UI_UNIT_X * but_componentrow->indentation, 0);
}
static void widget_nodesocket(
uiBut *but, uiWidgetColors *wcol, rcti *rect, int UNUSED(state), int UNUSED(roundboxalign))
{
const int radi = 5;
uiWidgetBase wtb;
widget_init(&wtb);
uchar old_inner[3], old_outline[3];
copy_v3_v3_uchar(old_inner, wcol->inner);
copy_v3_v3_uchar(old_outline, wcol->outline);
wcol->inner[0] = but->col[0];
wcol->inner[1] = but->col[1];
wcol->inner[2] = but->col[2];
wcol->outline[0] = 0;
wcol->outline[1] = 0;
wcol->outline[2] = 0;
wcol->outline[3] = 150;
const int cent_x = BLI_rcti_cent_x(rect);
const int cent_y = BLI_rcti_cent_y(rect);
rect->xmin = cent_x - radi;
rect->xmax = cent_x + radi;
rect->ymin = cent_y - radi;
rect->ymax = cent_y + radi;
wtb.draw_outline = true;
round_box_edges(&wtb, UI_CNR_ALL, rect, (float)radi);
widgetbase_draw(&wtb, wcol);
copy_v3_v3_uchar(wcol->inner, old_inner);
copy_v3_v3_uchar(wcol->outline, old_outline);
}
static void widget_numslider(
uiBut *but, uiWidgetColors *wcol, rcti *rect, int state, int roundboxalign)
{
uiWidgetBase wtb, wtb1;
widget_init(&wtb);
widget_init(&wtb1);
/* Backdrop first. */
const float ofs = wcol->roundness * BLI_rcti_size_y(rect);
const float toffs = ofs * 0.75f;
round_box_edges(&wtb, roundboxalign, rect, ofs);
wtb.draw_outline = false;
widgetbase_draw(&wtb, wcol);
/* Draw slider part only when not in text editing. */
2017-11-03 00:22:59 +11:00
if (!(state & UI_STATE_TEXT_INPUT)) {
int roundboxalign_slider = roundboxalign;
uchar outline[3];
copy_v3_v3_uchar(outline, wcol->outline);
copy_v3_v3_uchar(wcol->outline, wcol->item);
copy_v3_v3_uchar(wcol->inner, wcol->item);
if (!(state & UI_SELECT)) {
SWAP(short, wcol->shadetop, wcol->shadedown);
}
rcti rect1 = *rect;
float factor, factor_ui;
float factor_discard = 1.0f; /* No discard. */
const float value = (float)ui_but_value_get(but);
const float softmin = but->softmin;
const float softmax = but->softmax;
const float softrange = softmax - softmin;
const PropertyScaleType scale_type = ui_but_scale_type(but);
switch (scale_type) {
case PROP_SCALE_LINEAR: {
if (but->rnaprop && (RNA_property_subtype(but->rnaprop) == PROP_PERCENTAGE)) {
factor = value / softmax;
}
else {
factor = (value - softmin) / softrange;
}
break;
}
case PROP_SCALE_LOG: {
const float logmin = fmaxf(softmin, 0.5e-8f);
const float base = softmax / logmin;
factor = logf(value / logmin) / logf(base);
break;
}
case PROP_SCALE_CUBIC: {
const float cubicmin = cube_f(softmin);
const float cubicmax = cube_f(softmax);
const float cubicrange = cubicmax - cubicmin;
const float f = (value - softmin) * cubicrange / softrange + cubicmin;
factor = (cbrtf(f) - softmin) / softrange;
break;
}
}
const float width = (float)BLI_rcti_size_x(rect);
2018-05-01 18:35:11 +02:00
factor_ui = factor * width;
if (factor_ui <= ofs) {
/* Left part only. */
roundboxalign_slider &= ~(UI_CNR_TOP_RIGHT | UI_CNR_BOTTOM_RIGHT);
rect1.xmax = rect1.xmin + ofs;
factor_discard = factor_ui / ofs;
}
else if (factor_ui <= width - ofs) {
/* Left part + middle part. */
roundboxalign_slider &= ~(UI_CNR_TOP_RIGHT | UI_CNR_BOTTOM_RIGHT);
rect1.xmax = rect1.xmin + factor_ui;
}
else {
/* Left part + middle part + right part. */
factor_discard = factor;
}
round_box_edges(&wtb1, roundboxalign_slider, &rect1, ofs);
wtb1.draw_outline = false;
widgetbase_set_uniform_discard_factor(&wtb1, factor_discard);
widgetbase_draw(&wtb1, wcol);
copy_v3_v3_uchar(wcol->outline, outline);
if (!(state & UI_SELECT)) {
SWAP(short, wcol->shadetop, wcol->shadedown);
}
}
/* Outline. */
wtb.draw_outline = true;
wtb.draw_inner = false;
widgetbase_draw(&wtb, wcol);
2021-03-12 00:46:41 +11:00
/* Add space at either side of the button so text aligns with number-buttons
* (which have arrow icons). */
2017-11-03 00:22:59 +11:00
if (!(state & UI_STATE_TEXT_INPUT)) {
rect->xmax -= toffs;
rect->xmin += toffs;
}
}
/* I think 3 is sufficient border to indicate keyed status */
#define SWATCH_KEYED_BORDER 3
static void widget_swatch(
uiBut *but, uiWidgetColors *wcol, rcti *rect, int state, int roundboxalign)
{
BLI_assert(but->type == UI_BTYPE_COLOR);
uiButColor *color_but = (uiButColor *)but;
float col[4];
2012-03-30 01:51:25 +00:00
col[3] = 1.0f;
Changes to Color Management After testing and feedback, I've decided to slightly modify the way color management works internally. While the previous method worked well for rendering, was a smaller transition and had some advantages over this new method, it was a bit more ambiguous, and was making things difficult for other areas such as compositing. This implementation now considers all color data (with only a couple of exceptions such as brush colors) to be stored in linear RGB color space, rather than sRGB as previously. This brings it in line with Nuke, which also operates this way, quite successfully. Color swatches, pickers, color ramp display are now gamma corrected to display gamma so you can see what you're doing, but the numbers themselves are considered linear. This makes understanding blending modes more clear (a 0.5 value on overlay will not change the result now) as well as making color swatches act more predictably in the compositor, however bringing over color values from applications like photoshop or gimp, that operate in a gamma space, will give identical results. This commit will convert over existing files saved by earlier 2.5 versions to work generally the same, though there may be some slight differences with things like textures. Now that we're set on changing other areas of shading, this won't be too disruptive overall. I've made a diagram explaining the pipeline here: http://mke3.net/blender/devel/2.5/25_linear_workflow_pipeline.png and some docs here: http://www.blender.org/development/release-logs/blender-250/color-management/
2009-12-02 07:56:34 +00:00
if (but->rnaprop) {
BLI_assert(but->rnaindex == -1);
2012-03-30 01:51:25 +00:00
if (RNA_property_array_length(&but->rnapoin, but->rnaprop) == 4) {
col[3] = RNA_property_float_get_index(&but->rnapoin, but->rnaprop, 3);
}
Changes to Color Management After testing and feedback, I've decided to slightly modify the way color management works internally. While the previous method worked well for rendering, was a smaller transition and had some advantages over this new method, it was a bit more ambiguous, and was making things difficult for other areas such as compositing. This implementation now considers all color data (with only a couple of exceptions such as brush colors) to be stored in linear RGB color space, rather than sRGB as previously. This brings it in line with Nuke, which also operates this way, quite successfully. Color swatches, pickers, color ramp display are now gamma corrected to display gamma so you can see what you're doing, but the numbers themselves are considered linear. This makes understanding blending modes more clear (a 0.5 value on overlay will not change the result now) as well as making color swatches act more predictably in the compositor, however bringing over color values from applications like photoshop or gimp, that operate in a gamma space, will give identical results. This commit will convert over existing files saved by earlier 2.5 versions to work generally the same, though there may be some slight differences with things like textures. Now that we're set on changing other areas of shading, this won't be too disruptive overall. I've made a diagram explaining the pipeline here: http://mke3.net/blender/devel/2.5/25_linear_workflow_pipeline.png and some docs here: http://www.blender.org/development/release-logs/blender-250/color-management/
2009-12-02 07:56:34 +00:00
}
uiWidgetBase wtb;
widget_init(&wtb);
const float rad = wcol->roundness * U.widget_unit;
Holiday coding log :) Nice formatted version (pictures soon): http://wiki.blender.org/index.php/Dev:Ref/Release_Notes/2.66/Usability Short list of main changes: - Transparent region option (over main region), added code to blend in/out such panels. - Min size window now 640 x 480 - Fixed DPI for ui - lots of cleanup and changes everywhere. Icon image need correct size still, layer-in-use icon needs remake. - Macbook retina support, use command line --no-native-pixels to disable it - Timeline Marker label was drawing wrong - Trackpad and magic mouse: supports zoom (hold ctrl) - Fix for splash position: removed ghost function and made window size update after creation immediate - Fast undo buffer save now adds UI as well. Could be checked for regular file save even... Quit.blend and temp file saving use this now. - Dixed filename in window on reading quit.blend or temp saves, and they now add a warning in window title: "(Recovered)" - New Userpref option "Keep Session" - this always saves quit.blend, and loads on start. This allows keeping UI and data without actual saves, until you actually save. When you load startup.blend and quit, it recognises the quit.blend as a startup (no file name in header) - Added 3D view copy/paste buffers (selected objects). Shortcuts ctrl-c, ctrl-v (OSX, cmd-c, cmd-v). Coded partial file saving for it. Could be used for other purposes. Todo: use OS clipboards. - User preferences (themes, keymaps, user settings) now can be saved as a separate file. Old option is called "Save Startup File" the new one "Save User Settings". To visualise this difference, the 'save startup file' button has been removed from user preferences window. That option is available as CTRL+U and in File menu still. - OSX: fixed bug that stopped giving mouse events outside window. This also fixes "Continuous Grab" for OSX. (error since 2009)
2012-12-12 18:58:11 +00:00
round_box_edges(&wtb, roundboxalign, rect, rad);
ui_but_v3_get(but, col);
if ((state & (UI_BUT_ANIMATED | UI_BUT_ANIMATED_KEY | UI_BUT_DRIVEN | UI_BUT_OVERRIDDEN |
UI_BUT_REDALERT)) ||
(but->drawflag & UI_BUT_ANIMATED_CHANGED)) {
/* draw based on state - color for keyed etc */
widgetbase_draw(&wtb, wcol);
/* inset to draw swatch color */
2012-03-30 01:51:25 +00:00
rect->xmin += SWATCH_KEYED_BORDER;
rect->xmax -= SWATCH_KEYED_BORDER;
rect->ymin += SWATCH_KEYED_BORDER;
rect->ymax -= SWATCH_KEYED_BORDER;
Holiday coding log :) Nice formatted version (pictures soon): http://wiki.blender.org/index.php/Dev:Ref/Release_Notes/2.66/Usability Short list of main changes: - Transparent region option (over main region), added code to blend in/out such panels. - Min size window now 640 x 480 - Fixed DPI for ui - lots of cleanup and changes everywhere. Icon image need correct size still, layer-in-use icon needs remake. - Macbook retina support, use command line --no-native-pixels to disable it - Timeline Marker label was drawing wrong - Trackpad and magic mouse: supports zoom (hold ctrl) - Fix for splash position: removed ghost function and made window size update after creation immediate - Fast undo buffer save now adds UI as well. Could be checked for regular file save even... Quit.blend and temp file saving use this now. - Dixed filename in window on reading quit.blend or temp saves, and they now add a warning in window title: "(Recovered)" - New Userpref option "Keep Session" - this always saves quit.blend, and loads on start. This allows keeping UI and data without actual saves, until you actually save. When you load startup.blend and quit, it recognises the quit.blend as a startup (no file name in header) - Added 3D view copy/paste buffers (selected objects). Shortcuts ctrl-c, ctrl-v (OSX, cmd-c, cmd-v). Coded partial file saving for it. Could be used for other purposes. Todo: use OS clipboards. - User preferences (themes, keymaps, user settings) now can be saved as a separate file. Old option is called "Save Startup File" the new one "Save User Settings". To visualise this difference, the 'save startup file' button has been removed from user preferences window. That option is available as CTRL+U and in File menu still. - OSX: fixed bug that stopped giving mouse events outside window. This also fixes "Continuous Grab" for OSX. (error since 2009)
2012-12-12 18:58:11 +00:00
round_box_edges(&wtb, roundboxalign, rect, rad);
}
2019-03-25 10:15:20 +11:00
if (!ui_but_is_color_gamma(but)) {
ui_block_cm_to_display_space_v3(but->block, col);
2019-03-25 10:15:20 +11:00
}
rgba_float_to_uchar(wcol->inner, col);
const bool show_alpha_checkers = (wcol->inner[3] < 255);
wcol->shaded = 0;
/* Now we reduce alpha of the inner color (i.e. the color shown)
* so that this setting can look grayed out, while retaining
* the checkerboard (for transparent values). This is needed
* here as the effects of ui_widget_color_disabled() are overwritten. */
wcol->inner[3] *= widget_alpha_factor(state);
widgetbase_draw_ex(&wtb, wcol, show_alpha_checkers);
if (color_but->is_pallete_color &&
((Palette *)but->rnapoin.owner_id)->active_color == color_but->palette_color_index) {
const float width = rect->xmax - rect->xmin;
const float height = rect->ymax - rect->ymin;
/* find color luminance and change it slightly */
float bw = rgb_to_grayscale(col);
2015-01-31 17:23:30 +11:00
bw += (bw < 0.5f) ? 0.5f : -0.5f;
2018-04-10 17:42:33 +02:00
/* We are drawing on top of widget bases. Flush cache. */
GPU_blend(GPU_BLEND_ALPHA);
2018-04-10 17:42:33 +02:00
UI_widgetbase_draw_cache_flush();
GPU_blend(GPU_BLEND_NONE);
const uint pos = GPU_vertformat_attr_add(
immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
immUniformColor3f(bw, bw, bw);
immBegin(GPU_PRIM_TRIS, 3);
immVertex2f(pos, rect->xmin + 0.1f * width, rect->ymin + 0.9f * height);
immVertex2f(pos, rect->xmin + 0.1f * width, rect->ymin + 0.5f * height);
immVertex2f(pos, rect->xmin + 0.5f * width, rect->ymin + 0.9f * height);
immEnd();
immUnbindProgram();
}
}
static void widget_unitvec(
uiBut *but, uiWidgetColors *wcol, rcti *rect, int UNUSED(state), int UNUSED(roundboxalign))
{
ui_draw_but_UNITVEC(but, wcol, rect);
}
static void widget_icon_has_anim(
uiBut *but, uiWidgetColors *wcol, rcti *rect, int state, int roundboxalign)
{
if (state & (UI_BUT_ANIMATED | UI_BUT_ANIMATED_KEY | UI_BUT_DRIVEN | UI_BUT_REDALERT) &&
but->emboss != UI_EMBOSS_NONE) {
uiWidgetBase wtb;
widget_init(&wtb);
wtb.draw_outline = false;
const float rad = wcol->roundness * BLI_rcti_size_y(rect);
Holiday coding log :) Nice formatted version (pictures soon): http://wiki.blender.org/index.php/Dev:Ref/Release_Notes/2.66/Usability Short list of main changes: - Transparent region option (over main region), added code to blend in/out such panels. - Min size window now 640 x 480 - Fixed DPI for ui - lots of cleanup and changes everywhere. Icon image need correct size still, layer-in-use icon needs remake. - Macbook retina support, use command line --no-native-pixels to disable it - Timeline Marker label was drawing wrong - Trackpad and magic mouse: supports zoom (hold ctrl) - Fix for splash position: removed ghost function and made window size update after creation immediate - Fast undo buffer save now adds UI as well. Could be checked for regular file save even... Quit.blend and temp file saving use this now. - Dixed filename in window on reading quit.blend or temp saves, and they now add a warning in window title: "(Recovered)" - New Userpref option "Keep Session" - this always saves quit.blend, and loads on start. This allows keeping UI and data without actual saves, until you actually save. When you load startup.blend and quit, it recognises the quit.blend as a startup (no file name in header) - Added 3D view copy/paste buffers (selected objects). Shortcuts ctrl-c, ctrl-v (OSX, cmd-c, cmd-v). Coded partial file saving for it. Could be used for other purposes. Todo: use OS clipboards. - User preferences (themes, keymaps, user settings) now can be saved as a separate file. Old option is called "Save Startup File" the new one "Save User Settings". To visualise this difference, the 'save startup file' button has been removed from user preferences window. That option is available as CTRL+U and in File menu still. - OSX: fixed bug that stopped giving mouse events outside window. This also fixes "Continuous Grab" for OSX. (error since 2009)
2012-12-12 18:58:11 +00:00
round_box_edges(&wtb, UI_CNR_ALL, rect, rad);
widgetbase_draw(&wtb, wcol);
}
else if (but->type == UI_BTYPE_NUM) {
/* Draw number buttons still with left/right
* triangles when field is not embossed */
widget_numbut_embossn(but, wcol, rect, state, roundboxalign);
}
else if (but->type == UI_BTYPE_MENU) {
/* Draw menu buttons still with down arrow. */
widget_menubut_embossn(but, wcol, rect, state, roundboxalign);
}
}
static void widget_textbut(uiWidgetColors *wcol, rcti *rect, int state, int roundboxalign)
{
2019-03-25 10:15:20 +11:00
if (state & UI_SELECT) {
SWAP(short, wcol->shadetop, wcol->shadedown);
2019-03-25 10:15:20 +11:00
}
uiWidgetBase wtb;
widget_init(&wtb);
const float rad = wcol->roundness * U.widget_unit;
Holiday coding log :) Nice formatted version (pictures soon): http://wiki.blender.org/index.php/Dev:Ref/Release_Notes/2.66/Usability Short list of main changes: - Transparent region option (over main region), added code to blend in/out such panels. - Min size window now 640 x 480 - Fixed DPI for ui - lots of cleanup and changes everywhere. Icon image need correct size still, layer-in-use icon needs remake. - Macbook retina support, use command line --no-native-pixels to disable it - Timeline Marker label was drawing wrong - Trackpad and magic mouse: supports zoom (hold ctrl) - Fix for splash position: removed ghost function and made window size update after creation immediate - Fast undo buffer save now adds UI as well. Could be checked for regular file save even... Quit.blend and temp file saving use this now. - Dixed filename in window on reading quit.blend or temp saves, and they now add a warning in window title: "(Recovered)" - New Userpref option "Keep Session" - this always saves quit.blend, and loads on start. This allows keeping UI and data without actual saves, until you actually save. When you load startup.blend and quit, it recognises the quit.blend as a startup (no file name in header) - Added 3D view copy/paste buffers (selected objects). Shortcuts ctrl-c, ctrl-v (OSX, cmd-c, cmd-v). Coded partial file saving for it. Could be used for other purposes. Todo: use OS clipboards. - User preferences (themes, keymaps, user settings) now can be saved as a separate file. Old option is called "Save Startup File" the new one "Save User Settings". To visualise this difference, the 'save startup file' button has been removed from user preferences window. That option is available as CTRL+U and in File menu still. - OSX: fixed bug that stopped giving mouse events outside window. This also fixes "Continuous Grab" for OSX. (error since 2009)
2012-12-12 18:58:11 +00:00
round_box_edges(&wtb, roundboxalign, rect, rad);
widgetbase_draw(&wtb, wcol);
}
static void widget_menuiconbut(uiWidgetColors *wcol,
rcti *rect,
int UNUSED(state),
int roundboxalign)
{
uiWidgetBase wtb;
widget_init(&wtb);
const float rad = wcol->roundness * U.widget_unit;
Holiday coding log :) Nice formatted version (pictures soon): http://wiki.blender.org/index.php/Dev:Ref/Release_Notes/2.66/Usability Short list of main changes: - Transparent region option (over main region), added code to blend in/out such panels. - Min size window now 640 x 480 - Fixed DPI for ui - lots of cleanup and changes everywhere. Icon image need correct size still, layer-in-use icon needs remake. - Macbook retina support, use command line --no-native-pixels to disable it - Timeline Marker label was drawing wrong - Trackpad and magic mouse: supports zoom (hold ctrl) - Fix for splash position: removed ghost function and made window size update after creation immediate - Fast undo buffer save now adds UI as well. Could be checked for regular file save even... Quit.blend and temp file saving use this now. - Dixed filename in window on reading quit.blend or temp saves, and they now add a warning in window title: "(Recovered)" - New Userpref option "Keep Session" - this always saves quit.blend, and loads on start. This allows keeping UI and data without actual saves, until you actually save. When you load startup.blend and quit, it recognises the quit.blend as a startup (no file name in header) - Added 3D view copy/paste buffers (selected objects). Shortcuts ctrl-c, ctrl-v (OSX, cmd-c, cmd-v). Coded partial file saving for it. Could be used for other purposes. Todo: use OS clipboards. - User preferences (themes, keymaps, user settings) now can be saved as a separate file. Old option is called "Save Startup File" the new one "Save User Settings". To visualise this difference, the 'save startup file' button has been removed from user preferences window. That option is available as CTRL+U and in File menu still. - OSX: fixed bug that stopped giving mouse events outside window. This also fixes "Continuous Grab" for OSX. (error since 2009)
2012-12-12 18:58:11 +00:00
round_box_edges(&wtb, roundboxalign, rect, rad);
/* decoration */
widgetbase_draw(&wtb, wcol);
}
static void widget_pulldownbut(uiWidgetColors *wcol, rcti *rect, int state, int roundboxalign)
{
float back[4];
UI_GetThemeColor4fv(TH_BACK, back);
if ((state & UI_ACTIVE) || (back[3] < 1.0f)) {
uiWidgetBase wtb;
2018-04-22 13:57:42 +02:00
const float rad = wcol->roundness * U.widget_unit;
if (state & UI_ACTIVE) {
copy_v4_v4_uchar(wcol->inner, wcol->inner_sel);
copy_v3_v3_uchar(wcol->text, wcol->text_sel);
copy_v3_v3_uchar(wcol->outline, wcol->inner);
}
else {
wcol->inner[3] *= 1.0f - back[3];
wcol->outline[3] = 0.0f;
}
widget_init(&wtb);
/* half rounded */
round_box_edges(&wtb, roundboxalign, rect, rad);
widgetbase_draw(&wtb, wcol);
}
}
static void widget_menu_itembut(uiWidgetColors *wcol,
rcti *rect,
int UNUSED(state),
int UNUSED(roundboxalign))
{
uiWidgetBase wtb;
widget_init(&wtb);
/* not rounded, no outline */
wtb.draw_outline = false;
round_box_edges(&wtb, 0, rect, 0.0f);
widgetbase_draw(&wtb, wcol);
}
static void widget_menu_radial_itembut(
uiBut *but, uiWidgetColors *wcol, rcti *rect, int UNUSED(state), int UNUSED(roundboxalign))
{
const float fac = but->block->pie_data.alphafac;
uiWidgetBase wtb;
widget_init(&wtb);
wtb.draw_emboss = false;
const float rad = wcol->roundness * BLI_rcti_size_y(rect);
round_box_edges(&wtb, UI_CNR_ALL, rect, rad);
wcol->inner[3] *= fac;
wcol->inner_sel[3] *= fac;
wcol->item[3] *= fac;
wcol->text[3] *= fac;
wcol->text_sel[3] *= fac;
wcol->outline[3] *= fac;
widgetbase_draw(&wtb, wcol);
}
static void widget_list_itembut(uiWidgetColors *wcol,
rcti *rect,
int UNUSED(state),
int UNUSED(roundboxalign))
{
uiWidgetBase wtb;
widget_init(&wtb);
2018-04-22 13:57:42 +02:00
/* no outline */
wtb.draw_outline = false;
const float rad = wcol->roundness * U.widget_unit;
Holiday coding log :) Nice formatted version (pictures soon): http://wiki.blender.org/index.php/Dev:Ref/Release_Notes/2.66/Usability Short list of main changes: - Transparent region option (over main region), added code to blend in/out such panels. - Min size window now 640 x 480 - Fixed DPI for ui - lots of cleanup and changes everywhere. Icon image need correct size still, layer-in-use icon needs remake. - Macbook retina support, use command line --no-native-pixels to disable it - Timeline Marker label was drawing wrong - Trackpad and magic mouse: supports zoom (hold ctrl) - Fix for splash position: removed ghost function and made window size update after creation immediate - Fast undo buffer save now adds UI as well. Could be checked for regular file save even... Quit.blend and temp file saving use this now. - Dixed filename in window on reading quit.blend or temp saves, and they now add a warning in window title: "(Recovered)" - New Userpref option "Keep Session" - this always saves quit.blend, and loads on start. This allows keeping UI and data without actual saves, until you actually save. When you load startup.blend and quit, it recognises the quit.blend as a startup (no file name in header) - Added 3D view copy/paste buffers (selected objects). Shortcuts ctrl-c, ctrl-v (OSX, cmd-c, cmd-v). Coded partial file saving for it. Could be used for other purposes. Todo: use OS clipboards. - User preferences (themes, keymaps, user settings) now can be saved as a separate file. Old option is called "Save Startup File" the new one "Save User Settings". To visualise this difference, the 'save startup file' button has been removed from user preferences window. That option is available as CTRL+U and in File menu still. - OSX: fixed bug that stopped giving mouse events outside window. This also fixes "Continuous Grab" for OSX. (error since 2009)
2012-12-12 18:58:11 +00:00
round_box_edges(&wtb, UI_CNR_ALL, rect, rad);
widgetbase_draw(&wtb, wcol);
}
static void widget_optionbut(uiWidgetColors *wcol,
rcti *rect,
int state,
int UNUSED(roundboxalign))
{
const bool text_before_widget = (state & UI_STATE_TEXT_BEFORE_WIDGET);
2012-03-30 01:51:25 +00:00
rcti recttemp = *rect;
uiWidgetBase wtb;
widget_init(&wtb);
/* square */
if (text_before_widget) {
recttemp.xmin = recttemp.xmax - BLI_rcti_size_y(&recttemp);
}
else {
recttemp.xmax = recttemp.xmin + BLI_rcti_size_y(&recttemp);
}
/* smaller */
const int delta = (BLI_rcti_size_y(&recttemp) - 2 * U.pixelsize) / 6;
UI: Better split layout support for checkboxes Makes the following layout changes possible: {F8473498} {F8473499} {F8473502} The next commit will contain many layout changes to make good use of these new possibilities. The result should be more consistent, easier to read and should give a more organized impression. Additionally, it should be possible to replace many sub-panels with compacter layouts. Main changes: * Checkboxes now respect the property split layouts * Add support for row and column headers (i.e. `uiLayout.column(heading="Foo")`, `uiLayout.row(heading="Bar")`). If the first property added to this layout doesn't insert anything into the label split column, the heading is inserted there. Otherwise, it's inserted as own item. * Add support for manually inserting decorators for an existing item (`uiLayout.prop_decorator()`). That way layout creators can manually insert this, which was the only way I saw to support property split layouts with a checkbox before the actual property. {F8471883} * Autogenerated layouts for operator properties look bad if there are only checkboxes (which only use half the region width). So before creating the layout, we iterate over visible properties and disable split layout if all are booleans. I think this is fine, if needed we could also add layout hints to operators. * `uiTemplateOperatorPropertyButs()` now handles macros itself, the caller used to be responsible for this. Code that didn't handle these so far never used macros I think, so this change should be invisible. * Remove manual property split layout from autogenerated operator properties layout. * Padding of checkboxes is tweaked to make their label visually more connected to the checkboxes. * Support split layout for menus (should work for `uiLayout.menu()`, `.operator_menu_enum()`, `.prop_menu_enum()`, maybe more) Maniphest Task: https://developer.blender.org/T65965 Differential Revision: https://developer.blender.org/D7427 Reviewed by: Brecht Van Lommel, William Reynish, Pablo Vazques
2020-04-17 16:40:25 +02:00
BLI_rcti_resize(
&recttemp, BLI_rcti_size_x(&recttemp) - delta * 2, BLI_rcti_size_y(&recttemp) - delta * 2);
/* Keep one edge in place. */
BLI_rcti_translate(&recttemp, text_before_widget ? delta : -delta, 0);
const float rad = wcol->roundness * BLI_rcti_size_y(&recttemp);
Holiday coding log :) Nice formatted version (pictures soon): http://wiki.blender.org/index.php/Dev:Ref/Release_Notes/2.66/Usability Short list of main changes: - Transparent region option (over main region), added code to blend in/out such panels. - Min size window now 640 x 480 - Fixed DPI for ui - lots of cleanup and changes everywhere. Icon image need correct size still, layer-in-use icon needs remake. - Macbook retina support, use command line --no-native-pixels to disable it - Timeline Marker label was drawing wrong - Trackpad and magic mouse: supports zoom (hold ctrl) - Fix for splash position: removed ghost function and made window size update after creation immediate - Fast undo buffer save now adds UI as well. Could be checked for regular file save even... Quit.blend and temp file saving use this now. - Dixed filename in window on reading quit.blend or temp saves, and they now add a warning in window title: "(Recovered)" - New Userpref option "Keep Session" - this always saves quit.blend, and loads on start. This allows keeping UI and data without actual saves, until you actually save. When you load startup.blend and quit, it recognises the quit.blend as a startup (no file name in header) - Added 3D view copy/paste buffers (selected objects). Shortcuts ctrl-c, ctrl-v (OSX, cmd-c, cmd-v). Coded partial file saving for it. Could be used for other purposes. Todo: use OS clipboards. - User preferences (themes, keymaps, user settings) now can be saved as a separate file. Old option is called "Save Startup File" the new one "Save User Settings". To visualise this difference, the 'save startup file' button has been removed from user preferences window. That option is available as CTRL+U and in File menu still. - OSX: fixed bug that stopped giving mouse events outside window. This also fixes "Continuous Grab" for OSX. (error since 2009)
2012-12-12 18:58:11 +00:00
round_box_edges(&wtb, UI_CNR_ALL, &recttemp, rad);
/* decoration */
if (state & UI_SELECT) {
shape_preset_trias_from_rect_checkmark(&wtb.tria1, &recttemp);
}
widgetbase_draw(&wtb, wcol);
UI: Better split layout support for checkboxes Makes the following layout changes possible: {F8473498} {F8473499} {F8473502} The next commit will contain many layout changes to make good use of these new possibilities. The result should be more consistent, easier to read and should give a more organized impression. Additionally, it should be possible to replace many sub-panels with compacter layouts. Main changes: * Checkboxes now respect the property split layouts * Add support for row and column headers (i.e. `uiLayout.column(heading="Foo")`, `uiLayout.row(heading="Bar")`). If the first property added to this layout doesn't insert anything into the label split column, the heading is inserted there. Otherwise, it's inserted as own item. * Add support for manually inserting decorators for an existing item (`uiLayout.prop_decorator()`). That way layout creators can manually insert this, which was the only way I saw to support property split layouts with a checkbox before the actual property. {F8471883} * Autogenerated layouts for operator properties look bad if there are only checkboxes (which only use half the region width). So before creating the layout, we iterate over visible properties and disable split layout if all are booleans. I think this is fine, if needed we could also add layout hints to operators. * `uiTemplateOperatorPropertyButs()` now handles macros itself, the caller used to be responsible for this. Code that didn't handle these so far never used macros I think, so this change should be invisible. * Remove manual property split layout from autogenerated operator properties layout. * Padding of checkboxes is tweaked to make their label visually more connected to the checkboxes. * Support split layout for menus (should work for `uiLayout.menu()`, `.operator_menu_enum()`, `.prop_menu_enum()`, maybe more) Maniphest Task: https://developer.blender.org/T65965 Differential Revision: https://developer.blender.org/D7427 Reviewed by: Brecht Van Lommel, William Reynish, Pablo Vazques
2020-04-17 16:40:25 +02:00
/* Text space - factor is really just eyeballed. */
const float offset = delta * 0.9;
if (text_before_widget) {
UI: Better split layout support for checkboxes Makes the following layout changes possible: {F8473498} {F8473499} {F8473502} The next commit will contain many layout changes to make good use of these new possibilities. The result should be more consistent, easier to read and should give a more organized impression. Additionally, it should be possible to replace many sub-panels with compacter layouts. Main changes: * Checkboxes now respect the property split layouts * Add support for row and column headers (i.e. `uiLayout.column(heading="Foo")`, `uiLayout.row(heading="Bar")`). If the first property added to this layout doesn't insert anything into the label split column, the heading is inserted there. Otherwise, it's inserted as own item. * Add support for manually inserting decorators for an existing item (`uiLayout.prop_decorator()`). That way layout creators can manually insert this, which was the only way I saw to support property split layouts with a checkbox before the actual property. {F8471883} * Autogenerated layouts for operator properties look bad if there are only checkboxes (which only use half the region width). So before creating the layout, we iterate over visible properties and disable split layout if all are booleans. I think this is fine, if needed we could also add layout hints to operators. * `uiTemplateOperatorPropertyButs()` now handles macros itself, the caller used to be responsible for this. Code that didn't handle these so far never used macros I think, so this change should be invisible. * Remove manual property split layout from autogenerated operator properties layout. * Padding of checkboxes is tweaked to make their label visually more connected to the checkboxes. * Support split layout for menus (should work for `uiLayout.menu()`, `.operator_menu_enum()`, `.prop_menu_enum()`, maybe more) Maniphest Task: https://developer.blender.org/T65965 Differential Revision: https://developer.blender.org/D7427 Reviewed by: Brecht Van Lommel, William Reynish, Pablo Vazques
2020-04-17 16:40:25 +02:00
rect->xmax = recttemp.xmin - offset;
}
else {
UI: Better split layout support for checkboxes Makes the following layout changes possible: {F8473498} {F8473499} {F8473502} The next commit will contain many layout changes to make good use of these new possibilities. The result should be more consistent, easier to read and should give a more organized impression. Additionally, it should be possible to replace many sub-panels with compacter layouts. Main changes: * Checkboxes now respect the property split layouts * Add support for row and column headers (i.e. `uiLayout.column(heading="Foo")`, `uiLayout.row(heading="Bar")`). If the first property added to this layout doesn't insert anything into the label split column, the heading is inserted there. Otherwise, it's inserted as own item. * Add support for manually inserting decorators for an existing item (`uiLayout.prop_decorator()`). That way layout creators can manually insert this, which was the only way I saw to support property split layouts with a checkbox before the actual property. {F8471883} * Autogenerated layouts for operator properties look bad if there are only checkboxes (which only use half the region width). So before creating the layout, we iterate over visible properties and disable split layout if all are booleans. I think this is fine, if needed we could also add layout hints to operators. * `uiTemplateOperatorPropertyButs()` now handles macros itself, the caller used to be responsible for this. Code that didn't handle these so far never used macros I think, so this change should be invisible. * Remove manual property split layout from autogenerated operator properties layout. * Padding of checkboxes is tweaked to make their label visually more connected to the checkboxes. * Support split layout for menus (should work for `uiLayout.menu()`, `.operator_menu_enum()`, `.prop_menu_enum()`, maybe more) Maniphest Task: https://developer.blender.org/T65965 Differential Revision: https://developer.blender.org/D7427 Reviewed by: Brecht Van Lommel, William Reynish, Pablo Vazques
2020-04-17 16:40:25 +02:00
rect->xmin = recttemp.xmax + offset;
}
}
/* labels use Editor theme colors for text */
static void widget_state_label(uiWidgetType *wt, int state, int drawflag, eUIEmbossType emboss)
{
if (state & UI_BUT_LIST_ITEM) {
/* Override default label theme's colors. */
bTheme *btheme = UI_GetTheme();
wt->wcol_theme = &btheme->tui.wcol_list_item;
/* call this for option button */
widget_state(wt, state, drawflag, emboss);
}
else {
/* call this for option button */
widget_state(wt, state, drawflag, emboss);
2019-03-25 10:15:20 +11:00
if (state & UI_SELECT) {
UI_GetThemeColor3ubv(TH_TEXT_HI, wt->wcol.text);
2019-03-25 10:15:20 +11:00
}
else {
UI_GetThemeColor3ubv(TH_TEXT, wt->wcol.text);
2019-03-25 10:15:20 +11:00
}
}
if (state & UI_BUT_REDALERT) {
const uchar red[4] = {255, 0, 0};
color_blend_v3_v3(wt->wcol.text, red, 0.4f);
}
}
static void widget_radiobut(uiWidgetColors *wcol, rcti *rect, int UNUSED(state), int roundboxalign)
{
uiWidgetBase wtb;
widget_init(&wtb);
const float rad = wcol->roundness * U.widget_unit;
Holiday coding log :) Nice formatted version (pictures soon): http://wiki.blender.org/index.php/Dev:Ref/Release_Notes/2.66/Usability Short list of main changes: - Transparent region option (over main region), added code to blend in/out such panels. - Min size window now 640 x 480 - Fixed DPI for ui - lots of cleanup and changes everywhere. Icon image need correct size still, layer-in-use icon needs remake. - Macbook retina support, use command line --no-native-pixels to disable it - Timeline Marker label was drawing wrong - Trackpad and magic mouse: supports zoom (hold ctrl) - Fix for splash position: removed ghost function and made window size update after creation immediate - Fast undo buffer save now adds UI as well. Could be checked for regular file save even... Quit.blend and temp file saving use this now. - Dixed filename in window on reading quit.blend or temp saves, and they now add a warning in window title: "(Recovered)" - New Userpref option "Keep Session" - this always saves quit.blend, and loads on start. This allows keeping UI and data without actual saves, until you actually save. When you load startup.blend and quit, it recognises the quit.blend as a startup (no file name in header) - Added 3D view copy/paste buffers (selected objects). Shortcuts ctrl-c, ctrl-v (OSX, cmd-c, cmd-v). Coded partial file saving for it. Could be used for other purposes. Todo: use OS clipboards. - User preferences (themes, keymaps, user settings) now can be saved as a separate file. Old option is called "Save Startup File" the new one "Save User Settings". To visualise this difference, the 'save startup file' button has been removed from user preferences window. That option is available as CTRL+U and in File menu still. - OSX: fixed bug that stopped giving mouse events outside window. This also fixes "Continuous Grab" for OSX. (error since 2009)
2012-12-12 18:58:11 +00:00
round_box_edges(&wtb, roundboxalign, rect, rad);
widgetbase_draw(&wtb, wcol);
}
static void widget_box(
uiBut *but, uiWidgetColors *wcol, rcti *rect, int UNUSED(state), int roundboxalign)
{
uiWidgetBase wtb;
widget_init(&wtb);
uchar old_col[3];
copy_v3_v3_uchar(old_col, wcol->inner);
/* abuse but->hsv - if it's non-zero, use this color as the box's background */
UI: List Panel System This implements a general system to implement drag and drop, subpanels, and UI animation for the stack UIs in Blender. There are NO functional changes in this patch, but it makes it relatively trivial to implement these features for stacks. The biggest complication to using panels to implement the UI for lists is that there can be multiple modifiers of the same type. Currently there is an assumed 1 to 1 relationship between every panel and its type, but there can be multiple list items of the same type, so we have to break this relationship. The mapping between panels and their data is stored with an index in the panel's runtime struct. To make use the system for a list like modifiers, four components must be added: 1. A panel type defined and registered for each list data type, with a known mapping between list data types and panel idnames. 1. A function called by interface code to build the add the panel layouts with the provided helper functions. - UI_panel_list_matches_data will check if the panel list needs to be rebuilt. - UI_panels_free_instanced will remove the existing list panels - UI_panel_add_instanced adds a list panel of a given type. 3. An expand flag for the list data and implementations of get_list_data_expand_flag and set_list_data_expand_flag. 4. For reordering, the panel type's reorder callback. This is called when the instanced panels are drag-dropped. This requires implementing a "move to index" operator for the list data. Reviewed By: Severin, brecht Differential Revision: https://developer.blender.org/D7490
2020-05-26 15:39:49 -04:00
if (but != NULL && but->col[3]) {
wcol->inner[0] = but->col[0];
wcol->inner[1] = but->col[1];
wcol->inner[2] = but->col[2];
wcol->inner[3] = but->col[3];
}
const float rad = wcol->roundness * U.widget_unit;
Holiday coding log :) Nice formatted version (pictures soon): http://wiki.blender.org/index.php/Dev:Ref/Release_Notes/2.66/Usability Short list of main changes: - Transparent region option (over main region), added code to blend in/out such panels. - Min size window now 640 x 480 - Fixed DPI for ui - lots of cleanup and changes everywhere. Icon image need correct size still, layer-in-use icon needs remake. - Macbook retina support, use command line --no-native-pixels to disable it - Timeline Marker label was drawing wrong - Trackpad and magic mouse: supports zoom (hold ctrl) - Fix for splash position: removed ghost function and made window size update after creation immediate - Fast undo buffer save now adds UI as well. Could be checked for regular file save even... Quit.blend and temp file saving use this now. - Dixed filename in window on reading quit.blend or temp saves, and they now add a warning in window title: "(Recovered)" - New Userpref option "Keep Session" - this always saves quit.blend, and loads on start. This allows keeping UI and data without actual saves, until you actually save. When you load startup.blend and quit, it recognises the quit.blend as a startup (no file name in header) - Added 3D view copy/paste buffers (selected objects). Shortcuts ctrl-c, ctrl-v (OSX, cmd-c, cmd-v). Coded partial file saving for it. Could be used for other purposes. Todo: use OS clipboards. - User preferences (themes, keymaps, user settings) now can be saved as a separate file. Old option is called "Save Startup File" the new one "Save User Settings". To visualise this difference, the 'save startup file' button has been removed from user preferences window. That option is available as CTRL+U and in File menu still. - OSX: fixed bug that stopped giving mouse events outside window. This also fixes "Continuous Grab" for OSX. (error since 2009)
2012-12-12 18:58:11 +00:00
round_box_edges(&wtb, roundboxalign, rect, rad);
widgetbase_draw(&wtb, wcol);
copy_v3_v3_uchar(wcol->inner, old_col);
}
static void widget_but(uiWidgetColors *wcol, rcti *rect, int UNUSED(state), int roundboxalign)
{
uiWidgetBase wtb;
widget_init(&wtb);
const float rad = wcol->roundness * U.widget_unit;
Holiday coding log :) Nice formatted version (pictures soon): http://wiki.blender.org/index.php/Dev:Ref/Release_Notes/2.66/Usability Short list of main changes: - Transparent region option (over main region), added code to blend in/out such panels. - Min size window now 640 x 480 - Fixed DPI for ui - lots of cleanup and changes everywhere. Icon image need correct size still, layer-in-use icon needs remake. - Macbook retina support, use command line --no-native-pixels to disable it - Timeline Marker label was drawing wrong - Trackpad and magic mouse: supports zoom (hold ctrl) - Fix for splash position: removed ghost function and made window size update after creation immediate - Fast undo buffer save now adds UI as well. Could be checked for regular file save even... Quit.blend and temp file saving use this now. - Dixed filename in window on reading quit.blend or temp saves, and they now add a warning in window title: "(Recovered)" - New Userpref option "Keep Session" - this always saves quit.blend, and loads on start. This allows keeping UI and data without actual saves, until you actually save. When you load startup.blend and quit, it recognises the quit.blend as a startup (no file name in header) - Added 3D view copy/paste buffers (selected objects). Shortcuts ctrl-c, ctrl-v (OSX, cmd-c, cmd-v). Coded partial file saving for it. Could be used for other purposes. Todo: use OS clipboards. - User preferences (themes, keymaps, user settings) now can be saved as a separate file. Old option is called "Save Startup File" the new one "Save User Settings". To visualise this difference, the 'save startup file' button has been removed from user preferences window. That option is available as CTRL+U and in File menu still. - OSX: fixed bug that stopped giving mouse events outside window. This also fixes "Continuous Grab" for OSX. (error since 2009)
2012-12-12 18:58:11 +00:00
round_box_edges(&wtb, roundboxalign, rect, rad);
widgetbase_draw(&wtb, wcol);
}
#if 0
static void widget_roundbut(uiWidgetColors *wcol, rcti *rect, int UNUSED(state), int roundboxalign)
{
uiWidgetBase wtb;
2018-04-22 13:57:42 +02:00
const float rad = wcol->roundness * U.widget_unit;
widget_init(&wtb);
/* half rounded */
round_box_edges(&wtb, roundboxalign, rect, rad);
widgetbase_draw(&wtb, wcol);
}
#endif
static void widget_roundbut_exec(uiWidgetColors *wcol, rcti *rect, int state, int roundboxalign)
{
2018-04-22 13:57:42 +02:00
const float rad = wcol->roundness * U.widget_unit;
uiWidgetBase wtb;
widget_init(&wtb);
if (state & UI_STATE_HOLD_ACTION) {
/* Show that keeping pressed performs another action (typically a menu). */
shape_preset_init_hold_action(&wtb.tria1, rect, 0.75f, 'r');
}
/* half rounded */
round_box_edges(&wtb, roundboxalign, rect, rad);
widgetbase_draw(&wtb, wcol);
}
UI: New Global Top-Bar (WIP) == Main Features/Changes for Users * Add horizontal bar at top of all non-temp windows, consisting out of two horizontal sub-bars. * Upper sub-bar contains global menus (File, Render, etc.), tabs for workspaces and scene selector. * Lower sub-bar contains object mode selector, screen-layout and render-layer selector. Later operator and/or tool settings will be placed here. * Individual sections of the topbar are individually scrollable. * Workspace tabs can be double- or ctrl-clicked for renaming and contain 'x' icon for deleting. * Top-bar should scale nicely with DPI. * The lower half of the top-bar can be hided by dragging the lower top-bar edge up. Better hiding options are planned (e.g. hide in fullscreen modes). * Info editors at the top of the window and using the full window width with be replaced by the top-bar. * In fullscreen modes, no more info editor is added on top, the top-bar replaces it. == Technical Features/Changes * Adds initial support for global areas A global area is part of the window, not part of the regular screen-layout. I've added a macro iterator to iterate over both, global and screen-layout level areas. When iterating over areas, from now on developers should always consider if they have to include global areas. * Adds a TOPBAR editor type The editor type is hidden in the UI editor type menu. * Adds a variation of the ID template to display IDs as tab buttons (template_ID_tabs in BPY) * Does various changes to RNA button creation code to improve their appearance in the horizontal top-bar. * Adds support for dynamically sized regions. That is, regions that scale automatically to the layout bounds. The code for this is currently a big hack (it's based on drawing the UI multiple times). This should definitely be improved. * Adds a template for displaying operator properties optimized for the top-bar. This will probably change a lot still and is in fact disabled in code. Since the final top-bar design depends a lot on other 2.8 designs (mainly tool-system and workspaces), we decided to not show the operator or tool settings in the top-bar for now. That means most of the lower sub-bar is empty for the time being. NOTE: Top-bar or global area data is not written to files or SDNA. They are simply added to the window when opening Blender or reading a file. This allows us doing changes to the top-bar without having to care for compatibility. == ToDo's It's a bit hard to predict all the ToDo's here are the known main ones: * Add options for the new active-tool system and for operator redo to the topbar. * Automatically hide the top-bar in fullscreen modes. * General visual polish. * Top-bar drag & drop support (WIP in temp-tab_drag_drop). * Improve dynamic regions (should also fix some layout glitches). * Make internal terminology consistent. * Enable topbar file writing once design is more advanced. * Address TODO's and XXX's in code :) Thanks @brecht for the review! And @sergey for the complaining ;) Differential Revision: D2758
2018-04-20 17:14:03 +02:00
static void widget_tab(uiWidgetColors *wcol, rcti *rect, int state, int roundboxalign)
{
2018-04-22 13:57:42 +02:00
const float rad = wcol->roundness * U.widget_unit;
UI: New Global Top-Bar (WIP) == Main Features/Changes for Users * Add horizontal bar at top of all non-temp windows, consisting out of two horizontal sub-bars. * Upper sub-bar contains global menus (File, Render, etc.), tabs for workspaces and scene selector. * Lower sub-bar contains object mode selector, screen-layout and render-layer selector. Later operator and/or tool settings will be placed here. * Individual sections of the topbar are individually scrollable. * Workspace tabs can be double- or ctrl-clicked for renaming and contain 'x' icon for deleting. * Top-bar should scale nicely with DPI. * The lower half of the top-bar can be hided by dragging the lower top-bar edge up. Better hiding options are planned (e.g. hide in fullscreen modes). * Info editors at the top of the window and using the full window width with be replaced by the top-bar. * In fullscreen modes, no more info editor is added on top, the top-bar replaces it. == Technical Features/Changes * Adds initial support for global areas A global area is part of the window, not part of the regular screen-layout. I've added a macro iterator to iterate over both, global and screen-layout level areas. When iterating over areas, from now on developers should always consider if they have to include global areas. * Adds a TOPBAR editor type The editor type is hidden in the UI editor type menu. * Adds a variation of the ID template to display IDs as tab buttons (template_ID_tabs in BPY) * Does various changes to RNA button creation code to improve their appearance in the horizontal top-bar. * Adds support for dynamically sized regions. That is, regions that scale automatically to the layout bounds. The code for this is currently a big hack (it's based on drawing the UI multiple times). This should definitely be improved. * Adds a template for displaying operator properties optimized for the top-bar. This will probably change a lot still and is in fact disabled in code. Since the final top-bar design depends a lot on other 2.8 designs (mainly tool-system and workspaces), we decided to not show the operator or tool settings in the top-bar for now. That means most of the lower sub-bar is empty for the time being. NOTE: Top-bar or global area data is not written to files or SDNA. They are simply added to the window when opening Blender or reading a file. This allows us doing changes to the top-bar without having to care for compatibility. == ToDo's It's a bit hard to predict all the ToDo's here are the known main ones: * Add options for the new active-tool system and for operator redo to the topbar. * Automatically hide the top-bar in fullscreen modes. * General visual polish. * Top-bar drag & drop support (WIP in temp-tab_drag_drop). * Improve dynamic regions (should also fix some layout glitches). * Make internal terminology consistent. * Enable topbar file writing once design is more advanced. * Address TODO's and XXX's in code :) Thanks @brecht for the review! And @sergey for the complaining ;) Differential Revision: D2758
2018-04-20 17:14:03 +02:00
const bool is_active = (state & UI_SELECT);
/* Draw shaded outline - Disabled for now,
2019-04-18 07:21:26 +02:00
* seems incorrect and also looks nicer without it imho ;) */
UI: New Global Top-Bar (WIP) == Main Features/Changes for Users * Add horizontal bar at top of all non-temp windows, consisting out of two horizontal sub-bars. * Upper sub-bar contains global menus (File, Render, etc.), tabs for workspaces and scene selector. * Lower sub-bar contains object mode selector, screen-layout and render-layer selector. Later operator and/or tool settings will be placed here. * Individual sections of the topbar are individually scrollable. * Workspace tabs can be double- or ctrl-clicked for renaming and contain 'x' icon for deleting. * Top-bar should scale nicely with DPI. * The lower half of the top-bar can be hided by dragging the lower top-bar edge up. Better hiding options are planned (e.g. hide in fullscreen modes). * Info editors at the top of the window and using the full window width with be replaced by the top-bar. * In fullscreen modes, no more info editor is added on top, the top-bar replaces it. == Technical Features/Changes * Adds initial support for global areas A global area is part of the window, not part of the regular screen-layout. I've added a macro iterator to iterate over both, global and screen-layout level areas. When iterating over areas, from now on developers should always consider if they have to include global areas. * Adds a TOPBAR editor type The editor type is hidden in the UI editor type menu. * Adds a variation of the ID template to display IDs as tab buttons (template_ID_tabs in BPY) * Does various changes to RNA button creation code to improve their appearance in the horizontal top-bar. * Adds support for dynamically sized regions. That is, regions that scale automatically to the layout bounds. The code for this is currently a big hack (it's based on drawing the UI multiple times). This should definitely be improved. * Adds a template for displaying operator properties optimized for the top-bar. This will probably change a lot still and is in fact disabled in code. Since the final top-bar design depends a lot on other 2.8 designs (mainly tool-system and workspaces), we decided to not show the operator or tool settings in the top-bar for now. That means most of the lower sub-bar is empty for the time being. NOTE: Top-bar or global area data is not written to files or SDNA. They are simply added to the window when opening Blender or reading a file. This allows us doing changes to the top-bar without having to care for compatibility. == ToDo's It's a bit hard to predict all the ToDo's here are the known main ones: * Add options for the new active-tool system and for operator redo to the topbar. * Automatically hide the top-bar in fullscreen modes. * General visual polish. * Top-bar drag & drop support (WIP in temp-tab_drag_drop). * Improve dynamic regions (should also fix some layout glitches). * Make internal terminology consistent. * Enable topbar file writing once design is more advanced. * Address TODO's and XXX's in code :) Thanks @brecht for the review! And @sergey for the complaining ;) Differential Revision: D2758
2018-04-20 17:14:03 +02:00
// #define USE_TAB_SHADED_HIGHLIGHT
2019-01-04 11:05:53 +11:00
uchar theme_col_tab_highlight[3];
UI: New Global Top-Bar (WIP) == Main Features/Changes for Users * Add horizontal bar at top of all non-temp windows, consisting out of two horizontal sub-bars. * Upper sub-bar contains global menus (File, Render, etc.), tabs for workspaces and scene selector. * Lower sub-bar contains object mode selector, screen-layout and render-layer selector. Later operator and/or tool settings will be placed here. * Individual sections of the topbar are individually scrollable. * Workspace tabs can be double- or ctrl-clicked for renaming and contain 'x' icon for deleting. * Top-bar should scale nicely with DPI. * The lower half of the top-bar can be hided by dragging the lower top-bar edge up. Better hiding options are planned (e.g. hide in fullscreen modes). * Info editors at the top of the window and using the full window width with be replaced by the top-bar. * In fullscreen modes, no more info editor is added on top, the top-bar replaces it. == Technical Features/Changes * Adds initial support for global areas A global area is part of the window, not part of the regular screen-layout. I've added a macro iterator to iterate over both, global and screen-layout level areas. When iterating over areas, from now on developers should always consider if they have to include global areas. * Adds a TOPBAR editor type The editor type is hidden in the UI editor type menu. * Adds a variation of the ID template to display IDs as tab buttons (template_ID_tabs in BPY) * Does various changes to RNA button creation code to improve their appearance in the horizontal top-bar. * Adds support for dynamically sized regions. That is, regions that scale automatically to the layout bounds. The code for this is currently a big hack (it's based on drawing the UI multiple times). This should definitely be improved. * Adds a template for displaying operator properties optimized for the top-bar. This will probably change a lot still and is in fact disabled in code. Since the final top-bar design depends a lot on other 2.8 designs (mainly tool-system and workspaces), we decided to not show the operator or tool settings in the top-bar for now. That means most of the lower sub-bar is empty for the time being. NOTE: Top-bar or global area data is not written to files or SDNA. They are simply added to the window when opening Blender or reading a file. This allows us doing changes to the top-bar without having to care for compatibility. == ToDo's It's a bit hard to predict all the ToDo's here are the known main ones: * Add options for the new active-tool system and for operator redo to the topbar. * Automatically hide the top-bar in fullscreen modes. * General visual polish. * Top-bar drag & drop support (WIP in temp-tab_drag_drop). * Improve dynamic regions (should also fix some layout glitches). * Make internal terminology consistent. * Enable topbar file writing once design is more advanced. * Address TODO's and XXX's in code :) Thanks @brecht for the review! And @sergey for the complaining ;) Differential Revision: D2758
2018-04-20 17:14:03 +02:00
#ifdef USE_TAB_SHADED_HIGHLIGHT
/* create outline highlight colors */
if (is_active) {
interp_v3_v3v3_uchar(theme_col_tab_highlight, wcol->inner_sel, wcol->outline, 0.2f);
}
else {
interp_v3_v3v3_uchar(theme_col_tab_highlight, wcol->inner, wcol->outline, 0.12f);
}
UI: New Global Top-Bar (WIP) == Main Features/Changes for Users * Add horizontal bar at top of all non-temp windows, consisting out of two horizontal sub-bars. * Upper sub-bar contains global menus (File, Render, etc.), tabs for workspaces and scene selector. * Lower sub-bar contains object mode selector, screen-layout and render-layer selector. Later operator and/or tool settings will be placed here. * Individual sections of the topbar are individually scrollable. * Workspace tabs can be double- or ctrl-clicked for renaming and contain 'x' icon for deleting. * Top-bar should scale nicely with DPI. * The lower half of the top-bar can be hided by dragging the lower top-bar edge up. Better hiding options are planned (e.g. hide in fullscreen modes). * Info editors at the top of the window and using the full window width with be replaced by the top-bar. * In fullscreen modes, no more info editor is added on top, the top-bar replaces it. == Technical Features/Changes * Adds initial support for global areas A global area is part of the window, not part of the regular screen-layout. I've added a macro iterator to iterate over both, global and screen-layout level areas. When iterating over areas, from now on developers should always consider if they have to include global areas. * Adds a TOPBAR editor type The editor type is hidden in the UI editor type menu. * Adds a variation of the ID template to display IDs as tab buttons (template_ID_tabs in BPY) * Does various changes to RNA button creation code to improve their appearance in the horizontal top-bar. * Adds support for dynamically sized regions. That is, regions that scale automatically to the layout bounds. The code for this is currently a big hack (it's based on drawing the UI multiple times). This should definitely be improved. * Adds a template for displaying operator properties optimized for the top-bar. This will probably change a lot still and is in fact disabled in code. Since the final top-bar design depends a lot on other 2.8 designs (mainly tool-system and workspaces), we decided to not show the operator or tool settings in the top-bar for now. That means most of the lower sub-bar is empty for the time being. NOTE: Top-bar or global area data is not written to files or SDNA. They are simply added to the window when opening Blender or reading a file. This allows us doing changes to the top-bar without having to care for compatibility. == ToDo's It's a bit hard to predict all the ToDo's here are the known main ones: * Add options for the new active-tool system and for operator redo to the topbar. * Automatically hide the top-bar in fullscreen modes. * General visual polish. * Top-bar drag & drop support (WIP in temp-tab_drag_drop). * Improve dynamic regions (should also fix some layout glitches). * Make internal terminology consistent. * Enable topbar file writing once design is more advanced. * Address TODO's and XXX's in code :) Thanks @brecht for the review! And @sergey for the complaining ;) Differential Revision: D2758
2018-04-20 17:14:03 +02:00
#endif
uiWidgetBase wtb;
widget_init(&wtb);
/* half rounded */
round_box_edges(&wtb, roundboxalign, rect, rad);
/* draw inner */
UI: New Global Top-Bar (WIP) == Main Features/Changes for Users * Add horizontal bar at top of all non-temp windows, consisting out of two horizontal sub-bars. * Upper sub-bar contains global menus (File, Render, etc.), tabs for workspaces and scene selector. * Lower sub-bar contains object mode selector, screen-layout and render-layer selector. Later operator and/or tool settings will be placed here. * Individual sections of the topbar are individually scrollable. * Workspace tabs can be double- or ctrl-clicked for renaming and contain 'x' icon for deleting. * Top-bar should scale nicely with DPI. * The lower half of the top-bar can be hided by dragging the lower top-bar edge up. Better hiding options are planned (e.g. hide in fullscreen modes). * Info editors at the top of the window and using the full window width with be replaced by the top-bar. * In fullscreen modes, no more info editor is added on top, the top-bar replaces it. == Technical Features/Changes * Adds initial support for global areas A global area is part of the window, not part of the regular screen-layout. I've added a macro iterator to iterate over both, global and screen-layout level areas. When iterating over areas, from now on developers should always consider if they have to include global areas. * Adds a TOPBAR editor type The editor type is hidden in the UI editor type menu. * Adds a variation of the ID template to display IDs as tab buttons (template_ID_tabs in BPY) * Does various changes to RNA button creation code to improve their appearance in the horizontal top-bar. * Adds support for dynamically sized regions. That is, regions that scale automatically to the layout bounds. The code for this is currently a big hack (it's based on drawing the UI multiple times). This should definitely be improved. * Adds a template for displaying operator properties optimized for the top-bar. This will probably change a lot still and is in fact disabled in code. Since the final top-bar design depends a lot on other 2.8 designs (mainly tool-system and workspaces), we decided to not show the operator or tool settings in the top-bar for now. That means most of the lower sub-bar is empty for the time being. NOTE: Top-bar or global area data is not written to files or SDNA. They are simply added to the window when opening Blender or reading a file. This allows us doing changes to the top-bar without having to care for compatibility. == ToDo's It's a bit hard to predict all the ToDo's here are the known main ones: * Add options for the new active-tool system and for operator redo to the topbar. * Automatically hide the top-bar in fullscreen modes. * General visual polish. * Top-bar drag & drop support (WIP in temp-tab_drag_drop). * Improve dynamic regions (should also fix some layout glitches). * Make internal terminology consistent. * Enable topbar file writing once design is more advanced. * Address TODO's and XXX's in code :) Thanks @brecht for the review! And @sergey for the complaining ;) Differential Revision: D2758
2018-04-20 17:14:03 +02:00
#ifdef USE_TAB_SHADED_HIGHLIGHT
wtb.draw_outline = 0;
UI: New Global Top-Bar (WIP) == Main Features/Changes for Users * Add horizontal bar at top of all non-temp windows, consisting out of two horizontal sub-bars. * Upper sub-bar contains global menus (File, Render, etc.), tabs for workspaces and scene selector. * Lower sub-bar contains object mode selector, screen-layout and render-layer selector. Later operator and/or tool settings will be placed here. * Individual sections of the topbar are individually scrollable. * Workspace tabs can be double- or ctrl-clicked for renaming and contain 'x' icon for deleting. * Top-bar should scale nicely with DPI. * The lower half of the top-bar can be hided by dragging the lower top-bar edge up. Better hiding options are planned (e.g. hide in fullscreen modes). * Info editors at the top of the window and using the full window width with be replaced by the top-bar. * In fullscreen modes, no more info editor is added on top, the top-bar replaces it. == Technical Features/Changes * Adds initial support for global areas A global area is part of the window, not part of the regular screen-layout. I've added a macro iterator to iterate over both, global and screen-layout level areas. When iterating over areas, from now on developers should always consider if they have to include global areas. * Adds a TOPBAR editor type The editor type is hidden in the UI editor type menu. * Adds a variation of the ID template to display IDs as tab buttons (template_ID_tabs in BPY) * Does various changes to RNA button creation code to improve their appearance in the horizontal top-bar. * Adds support for dynamically sized regions. That is, regions that scale automatically to the layout bounds. The code for this is currently a big hack (it's based on drawing the UI multiple times). This should definitely be improved. * Adds a template for displaying operator properties optimized for the top-bar. This will probably change a lot still and is in fact disabled in code. Since the final top-bar design depends a lot on other 2.8 designs (mainly tool-system and workspaces), we decided to not show the operator or tool settings in the top-bar for now. That means most of the lower sub-bar is empty for the time being. NOTE: Top-bar or global area data is not written to files or SDNA. They are simply added to the window when opening Blender or reading a file. This allows us doing changes to the top-bar without having to care for compatibility. == ToDo's It's a bit hard to predict all the ToDo's here are the known main ones: * Add options for the new active-tool system and for operator redo to the topbar. * Automatically hide the top-bar in fullscreen modes. * General visual polish. * Top-bar drag & drop support (WIP in temp-tab_drag_drop). * Improve dynamic regions (should also fix some layout glitches). * Make internal terminology consistent. * Enable topbar file writing once design is more advanced. * Address TODO's and XXX's in code :) Thanks @brecht for the review! And @sergey for the complaining ;) Differential Revision: D2758
2018-04-20 17:14:03 +02:00
#endif
widgetbase_draw(&wtb, wcol);
2018-04-10 17:42:33 +02:00
/* We are drawing on top of widget bases. Flush cache. */
GPU_blend(GPU_BLEND_ALPHA);
2018-04-10 17:42:33 +02:00
UI_widgetbase_draw_cache_flush();
GPU_blend(GPU_BLEND_NONE);
2018-04-10 17:42:33 +02:00
UI: New Global Top-Bar (WIP) == Main Features/Changes for Users * Add horizontal bar at top of all non-temp windows, consisting out of two horizontal sub-bars. * Upper sub-bar contains global menus (File, Render, etc.), tabs for workspaces and scene selector. * Lower sub-bar contains object mode selector, screen-layout and render-layer selector. Later operator and/or tool settings will be placed here. * Individual sections of the topbar are individually scrollable. * Workspace tabs can be double- or ctrl-clicked for renaming and contain 'x' icon for deleting. * Top-bar should scale nicely with DPI. * The lower half of the top-bar can be hided by dragging the lower top-bar edge up. Better hiding options are planned (e.g. hide in fullscreen modes). * Info editors at the top of the window and using the full window width with be replaced by the top-bar. * In fullscreen modes, no more info editor is added on top, the top-bar replaces it. == Technical Features/Changes * Adds initial support for global areas A global area is part of the window, not part of the regular screen-layout. I've added a macro iterator to iterate over both, global and screen-layout level areas. When iterating over areas, from now on developers should always consider if they have to include global areas. * Adds a TOPBAR editor type The editor type is hidden in the UI editor type menu. * Adds a variation of the ID template to display IDs as tab buttons (template_ID_tabs in BPY) * Does various changes to RNA button creation code to improve their appearance in the horizontal top-bar. * Adds support for dynamically sized regions. That is, regions that scale automatically to the layout bounds. The code for this is currently a big hack (it's based on drawing the UI multiple times). This should definitely be improved. * Adds a template for displaying operator properties optimized for the top-bar. This will probably change a lot still and is in fact disabled in code. Since the final top-bar design depends a lot on other 2.8 designs (mainly tool-system and workspaces), we decided to not show the operator or tool settings in the top-bar for now. That means most of the lower sub-bar is empty for the time being. NOTE: Top-bar or global area data is not written to files or SDNA. They are simply added to the window when opening Blender or reading a file. This allows us doing changes to the top-bar without having to care for compatibility. == ToDo's It's a bit hard to predict all the ToDo's here are the known main ones: * Add options for the new active-tool system and for operator redo to the topbar. * Automatically hide the top-bar in fullscreen modes. * General visual polish. * Top-bar drag & drop support (WIP in temp-tab_drag_drop). * Improve dynamic regions (should also fix some layout glitches). * Make internal terminology consistent. * Enable topbar file writing once design is more advanced. * Address TODO's and XXX's in code :) Thanks @brecht for the review! And @sergey for the complaining ;) Differential Revision: D2758
2018-04-20 17:14:03 +02:00
#ifdef USE_TAB_SHADED_HIGHLIGHT
/* draw outline (3d look) */
ui_draw_but_TAB_outline(rect, rad, theme_col_tab_highlight, wcol->inner);
UI: New Global Top-Bar (WIP) == Main Features/Changes for Users * Add horizontal bar at top of all non-temp windows, consisting out of two horizontal sub-bars. * Upper sub-bar contains global menus (File, Render, etc.), tabs for workspaces and scene selector. * Lower sub-bar contains object mode selector, screen-layout and render-layer selector. Later operator and/or tool settings will be placed here. * Individual sections of the topbar are individually scrollable. * Workspace tabs can be double- or ctrl-clicked for renaming and contain 'x' icon for deleting. * Top-bar should scale nicely with DPI. * The lower half of the top-bar can be hided by dragging the lower top-bar edge up. Better hiding options are planned (e.g. hide in fullscreen modes). * Info editors at the top of the window and using the full window width with be replaced by the top-bar. * In fullscreen modes, no more info editor is added on top, the top-bar replaces it. == Technical Features/Changes * Adds initial support for global areas A global area is part of the window, not part of the regular screen-layout. I've added a macro iterator to iterate over both, global and screen-layout level areas. When iterating over areas, from now on developers should always consider if they have to include global areas. * Adds a TOPBAR editor type The editor type is hidden in the UI editor type menu. * Adds a variation of the ID template to display IDs as tab buttons (template_ID_tabs in BPY) * Does various changes to RNA button creation code to improve their appearance in the horizontal top-bar. * Adds support for dynamically sized regions. That is, regions that scale automatically to the layout bounds. The code for this is currently a big hack (it's based on drawing the UI multiple times). This should definitely be improved. * Adds a template for displaying operator properties optimized for the top-bar. This will probably change a lot still and is in fact disabled in code. Since the final top-bar design depends a lot on other 2.8 designs (mainly tool-system and workspaces), we decided to not show the operator or tool settings in the top-bar for now. That means most of the lower sub-bar is empty for the time being. NOTE: Top-bar or global area data is not written to files or SDNA. They are simply added to the window when opening Blender or reading a file. This allows us doing changes to the top-bar without having to care for compatibility. == ToDo's It's a bit hard to predict all the ToDo's here are the known main ones: * Add options for the new active-tool system and for operator redo to the topbar. * Automatically hide the top-bar in fullscreen modes. * General visual polish. * Top-bar drag & drop support (WIP in temp-tab_drag_drop). * Improve dynamic regions (should also fix some layout glitches). * Make internal terminology consistent. * Enable topbar file writing once design is more advanced. * Address TODO's and XXX's in code :) Thanks @brecht for the review! And @sergey for the complaining ;) Differential Revision: D2758
2018-04-20 17:14:03 +02:00
#endif
UI: New Global Top-Bar (WIP) == Main Features/Changes for Users * Add horizontal bar at top of all non-temp windows, consisting out of two horizontal sub-bars. * Upper sub-bar contains global menus (File, Render, etc.), tabs for workspaces and scene selector. * Lower sub-bar contains object mode selector, screen-layout and render-layer selector. Later operator and/or tool settings will be placed here. * Individual sections of the topbar are individually scrollable. * Workspace tabs can be double- or ctrl-clicked for renaming and contain 'x' icon for deleting. * Top-bar should scale nicely with DPI. * The lower half of the top-bar can be hided by dragging the lower top-bar edge up. Better hiding options are planned (e.g. hide in fullscreen modes). * Info editors at the top of the window and using the full window width with be replaced by the top-bar. * In fullscreen modes, no more info editor is added on top, the top-bar replaces it. == Technical Features/Changes * Adds initial support for global areas A global area is part of the window, not part of the regular screen-layout. I've added a macro iterator to iterate over both, global and screen-layout level areas. When iterating over areas, from now on developers should always consider if they have to include global areas. * Adds a TOPBAR editor type The editor type is hidden in the UI editor type menu. * Adds a variation of the ID template to display IDs as tab buttons (template_ID_tabs in BPY) * Does various changes to RNA button creation code to improve their appearance in the horizontal top-bar. * Adds support for dynamically sized regions. That is, regions that scale automatically to the layout bounds. The code for this is currently a big hack (it's based on drawing the UI multiple times). This should definitely be improved. * Adds a template for displaying operator properties optimized for the top-bar. This will probably change a lot still and is in fact disabled in code. Since the final top-bar design depends a lot on other 2.8 designs (mainly tool-system and workspaces), we decided to not show the operator or tool settings in the top-bar for now. That means most of the lower sub-bar is empty for the time being. NOTE: Top-bar or global area data is not written to files or SDNA. They are simply added to the window when opening Blender or reading a file. This allows us doing changes to the top-bar without having to care for compatibility. == ToDo's It's a bit hard to predict all the ToDo's here are the known main ones: * Add options for the new active-tool system and for operator redo to the topbar. * Automatically hide the top-bar in fullscreen modes. * General visual polish. * Top-bar drag & drop support (WIP in temp-tab_drag_drop). * Improve dynamic regions (should also fix some layout glitches). * Make internal terminology consistent. * Enable topbar file writing once design is more advanced. * Address TODO's and XXX's in code :) Thanks @brecht for the review! And @sergey for the complaining ;) Differential Revision: D2758
2018-04-20 17:14:03 +02:00
#ifndef USE_TAB_SHADED_HIGHLIGHT
UNUSED_VARS(is_active, theme_col_tab_highlight);
#endif
}
static void widget_draw_extra_mask(const bContext *C, uiBut *but, uiWidgetType *wt, rcti *rect)
{
2018-04-22 13:57:42 +02:00
bTheme *btheme = UI_GetTheme();
uiWidgetColors *wcol = &btheme->tui.wcol_radio;
const float rad = wcol->roundness * U.widget_unit;
/* state copy! */
2012-03-30 01:51:25 +00:00
wt->wcol = *(wt->wcol_theme);
uiWidgetBase wtb;
widget_init(&wtb);
if (but->block->drawextra) {
/* NOTE: drawextra can change rect +1 or -1, to match round errors of existing previews. */
but->block->drawextra(
C, but->poin, but->block->drawextra_arg1, but->block->drawextra_arg2, rect);
const uint pos = GPU_vertformat_attr_add(
immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
/* make mask to draw over image */
uchar col[4];
UI_GetThemeColor3ubv(TH_BACK, col);
immUniformColor3ubv(col);
Holiday coding log :) Nice formatted version (pictures soon): http://wiki.blender.org/index.php/Dev:Ref/Release_Notes/2.66/Usability Short list of main changes: - Transparent region option (over main region), added code to blend in/out such panels. - Min size window now 640 x 480 - Fixed DPI for ui - lots of cleanup and changes everywhere. Icon image need correct size still, layer-in-use icon needs remake. - Macbook retina support, use command line --no-native-pixels to disable it - Timeline Marker label was drawing wrong - Trackpad and magic mouse: supports zoom (hold ctrl) - Fix for splash position: removed ghost function and made window size update after creation immediate - Fast undo buffer save now adds UI as well. Could be checked for regular file save even... Quit.blend and temp file saving use this now. - Dixed filename in window on reading quit.blend or temp saves, and they now add a warning in window title: "(Recovered)" - New Userpref option "Keep Session" - this always saves quit.blend, and loads on start. This allows keeping UI and data without actual saves, until you actually save. When you load startup.blend and quit, it recognises the quit.blend as a startup (no file name in header) - Added 3D view copy/paste buffers (selected objects). Shortcuts ctrl-c, ctrl-v (OSX, cmd-c, cmd-v). Coded partial file saving for it. Could be used for other purposes. Todo: use OS clipboards. - User preferences (themes, keymaps, user settings) now can be saved as a separate file. Old option is called "Save Startup File" the new one "Save User Settings". To visualise this difference, the 'save startup file' button has been removed from user preferences window. That option is available as CTRL+U and in File menu still. - OSX: fixed bug that stopped giving mouse events outside window. This also fixes "Continuous Grab" for OSX. (error since 2009)
2012-12-12 18:58:11 +00:00
round_box__edges(&wtb, UI_CNR_ALL, rect, 0.0f, rad);
widgetbase_outline(&wtb, pos);
immUnbindProgram();
}
/* outline */
Holiday coding log :) Nice formatted version (pictures soon): http://wiki.blender.org/index.php/Dev:Ref/Release_Notes/2.66/Usability Short list of main changes: - Transparent region option (over main region), added code to blend in/out such panels. - Min size window now 640 x 480 - Fixed DPI for ui - lots of cleanup and changes everywhere. Icon image need correct size still, layer-in-use icon needs remake. - Macbook retina support, use command line --no-native-pixels to disable it - Timeline Marker label was drawing wrong - Trackpad and magic mouse: supports zoom (hold ctrl) - Fix for splash position: removed ghost function and made window size update after creation immediate - Fast undo buffer save now adds UI as well. Could be checked for regular file save even... Quit.blend and temp file saving use this now. - Dixed filename in window on reading quit.blend or temp saves, and they now add a warning in window title: "(Recovered)" - New Userpref option "Keep Session" - this always saves quit.blend, and loads on start. This allows keeping UI and data without actual saves, until you actually save. When you load startup.blend and quit, it recognises the quit.blend as a startup (no file name in header) - Added 3D view copy/paste buffers (selected objects). Shortcuts ctrl-c, ctrl-v (OSX, cmd-c, cmd-v). Coded partial file saving for it. Could be used for other purposes. Todo: use OS clipboards. - User preferences (themes, keymaps, user settings) now can be saved as a separate file. Old option is called "Save Startup File" the new one "Save User Settings". To visualise this difference, the 'save startup file' button has been removed from user preferences window. That option is available as CTRL+U and in File menu still. - OSX: fixed bug that stopped giving mouse events outside window. This also fixes "Continuous Grab" for OSX. (error since 2009)
2012-12-12 18:58:11 +00:00
round_box_edges(&wtb, UI_CNR_ALL, rect, rad);
wtb.draw_outline = true;
wtb.draw_inner = false;
widgetbase_draw(&wtb, &wt->wcol);
}
static uiWidgetType *widget_type(uiWidgetTypeEnum type)
{
2012-03-30 01:51:25 +00:00
bTheme *btheme = UI_GetTheme();
/* defaults */
static uiWidgetType wt;
2012-03-30 01:51:25 +00:00
wt.wcol_theme = &btheme->tui.wcol_regular;
wt.wcol_state = &btheme->tui.wcol_state;
wt.state = widget_state;
wt.draw = widget_but;
wt.custom = NULL;
wt.text = widget_draw_text_icon;
2012-03-30 01:51:25 +00:00
switch (type) {
case UI_WTYPE_REGULAR:
break;
2009-04-27 13:44:11 +00:00
case UI_WTYPE_LABEL:
2012-03-30 01:51:25 +00:00
wt.draw = NULL;
wt.state = widget_state_label;
2009-04-27 13:44:11 +00:00
break;
case UI_WTYPE_TOGGLE:
2012-03-30 01:51:25 +00:00
wt.wcol_theme = &btheme->tui.wcol_toggle;
break;
case UI_WTYPE_CHECKBOX:
2012-03-30 01:51:25 +00:00
wt.wcol_theme = &btheme->tui.wcol_option;
wt.draw = widget_optionbut;
break;
case UI_WTYPE_RADIO:
2012-03-30 01:51:25 +00:00
wt.wcol_theme = &btheme->tui.wcol_radio;
wt.draw = widget_radiobut;
break;
case UI_WTYPE_NUMBER:
2012-03-30 01:51:25 +00:00
wt.wcol_theme = &btheme->tui.wcol_num;
wt.draw = widget_numbut;
break;
case UI_WTYPE_SLIDER:
2012-03-30 01:51:25 +00:00
wt.wcol_theme = &btheme->tui.wcol_numslider;
wt.custom = widget_numslider;
wt.state = widget_state_numslider;
break;
case UI_WTYPE_EXEC:
2012-03-30 01:51:25 +00:00
wt.wcol_theme = &btheme->tui.wcol_tool;
wt.draw = widget_roundbut_exec;
break;
case UI_WTYPE_TOOLBAR_ITEM:
wt.wcol_theme = &btheme->tui.wcol_toolbar_item;
wt.draw = widget_roundbut_exec;
break;
case UI_WTYPE_TAB:
wt.wcol_theme = &btheme->tui.wcol_tab;
UI: New Global Top-Bar (WIP) == Main Features/Changes for Users * Add horizontal bar at top of all non-temp windows, consisting out of two horizontal sub-bars. * Upper sub-bar contains global menus (File, Render, etc.), tabs for workspaces and scene selector. * Lower sub-bar contains object mode selector, screen-layout and render-layer selector. Later operator and/or tool settings will be placed here. * Individual sections of the topbar are individually scrollable. * Workspace tabs can be double- or ctrl-clicked for renaming and contain 'x' icon for deleting. * Top-bar should scale nicely with DPI. * The lower half of the top-bar can be hided by dragging the lower top-bar edge up. Better hiding options are planned (e.g. hide in fullscreen modes). * Info editors at the top of the window and using the full window width with be replaced by the top-bar. * In fullscreen modes, no more info editor is added on top, the top-bar replaces it. == Technical Features/Changes * Adds initial support for global areas A global area is part of the window, not part of the regular screen-layout. I've added a macro iterator to iterate over both, global and screen-layout level areas. When iterating over areas, from now on developers should always consider if they have to include global areas. * Adds a TOPBAR editor type The editor type is hidden in the UI editor type menu. * Adds a variation of the ID template to display IDs as tab buttons (template_ID_tabs in BPY) * Does various changes to RNA button creation code to improve their appearance in the horizontal top-bar. * Adds support for dynamically sized regions. That is, regions that scale automatically to the layout bounds. The code for this is currently a big hack (it's based on drawing the UI multiple times). This should definitely be improved. * Adds a template for displaying operator properties optimized for the top-bar. This will probably change a lot still and is in fact disabled in code. Since the final top-bar design depends a lot on other 2.8 designs (mainly tool-system and workspaces), we decided to not show the operator or tool settings in the top-bar for now. That means most of the lower sub-bar is empty for the time being. NOTE: Top-bar or global area data is not written to files or SDNA. They are simply added to the window when opening Blender or reading a file. This allows us doing changes to the top-bar without having to care for compatibility. == ToDo's It's a bit hard to predict all the ToDo's here are the known main ones: * Add options for the new active-tool system and for operator redo to the topbar. * Automatically hide the top-bar in fullscreen modes. * General visual polish. * Top-bar drag & drop support (WIP in temp-tab_drag_drop). * Improve dynamic regions (should also fix some layout glitches). * Make internal terminology consistent. * Enable topbar file writing once design is more advanced. * Address TODO's and XXX's in code :) Thanks @brecht for the review! And @sergey for the complaining ;) Differential Revision: D2758
2018-04-20 17:14:03 +02:00
wt.draw = widget_tab;
break;
case UI_WTYPE_TOOLTIP:
wt.wcol_theme = &btheme->tui.wcol_tooltip;
wt.draw = widget_menu_back;
break;
2012-03-30 01:51:25 +00:00
/* strings */
case UI_WTYPE_NAME:
2012-03-30 01:51:25 +00:00
wt.wcol_theme = &btheme->tui.wcol_text;
wt.draw = widget_textbut;
break;
case UI_WTYPE_NAME_LINK:
break;
case UI_WTYPE_POINTER_LINK:
break;
case UI_WTYPE_FILENAME:
break;
2012-03-30 01:51:25 +00:00
/* start menus */
case UI_WTYPE_MENU_RADIO:
2012-03-30 01:51:25 +00:00
wt.wcol_theme = &btheme->tui.wcol_menu;
wt.draw = widget_menubut;
break;
case UI_WTYPE_MENU_ICON_RADIO:
case UI_WTYPE_MENU_NODE_LINK:
2012-03-30 01:51:25 +00:00
wt.wcol_theme = &btheme->tui.wcol_menu;
wt.draw = widget_menuiconbut;
break;
case UI_WTYPE_MENU_POINTER_LINK:
2012-03-30 01:51:25 +00:00
wt.wcol_theme = &btheme->tui.wcol_menu;
wt.draw = widget_menubut;
break;
case UI_WTYPE_PULLDOWN:
2012-03-30 01:51:25 +00:00
wt.wcol_theme = &btheme->tui.wcol_pulldown;
wt.draw = widget_pulldownbut;
wt.state = widget_state_pulldown;
break;
2012-03-30 01:51:25 +00:00
/* in menus */
case UI_WTYPE_MENU_ITEM:
2012-03-30 01:51:25 +00:00
wt.wcol_theme = &btheme->tui.wcol_menu_item;
wt.draw = widget_menu_itembut;
wt.state = widget_state_menu_item;
break;
case UI_WTYPE_MENU_BACK:
2012-03-30 01:51:25 +00:00
wt.wcol_theme = &btheme->tui.wcol_menu_back;
wt.draw = widget_menu_back;
break;
2012-03-30 01:51:25 +00:00
/* specials */
case UI_WTYPE_ICON:
wt.custom = widget_icon_has_anim;
break;
case UI_WTYPE_ICON_LABEL:
/* behave like regular labels (this is simply a label with an icon) */
wt.state = widget_state_label;
2012-03-30 01:51:25 +00:00
wt.custom = widget_icon_has_anim;
break;
case UI_WTYPE_SWATCH:
2012-03-30 01:51:25 +00:00
wt.custom = widget_swatch;
break;
case UI_WTYPE_BOX:
2012-03-30 01:51:25 +00:00
wt.custom = widget_box;
wt.wcol_theme = &btheme->tui.wcol_box;
break;
case UI_WTYPE_RGB_PICKER:
break;
case UI_WTYPE_UNITVEC:
wt.custom = widget_unitvec;
break;
case UI_WTYPE_SCROLL:
2012-03-30 01:51:25 +00:00
wt.wcol_theme = &btheme->tui.wcol_scroll;
wt.state = widget_state_nothing;
wt.custom = widget_scroll;
break;
case UI_WTYPE_LISTITEM:
2012-03-30 01:51:25 +00:00
wt.wcol_theme = &btheme->tui.wcol_list_item;
wt.draw = widget_list_itembut;
break;
case UI_WTYPE_PROGRESSBAR:
2012-03-30 01:51:25 +00:00
wt.wcol_theme = &btheme->tui.wcol_progress;
wt.custom = widget_progressbar;
break;
case UI_WTYPE_DATASETROW:
wt.custom = widget_datasetrow;
break;
case UI_WTYPE_NODESOCKET:
wt.custom = widget_nodesocket;
break;
case UI_WTYPE_MENU_ITEM_RADIAL:
wt.wcol_theme = &btheme->tui.wcol_pie_menu;
wt.custom = widget_menu_radial_itembut;
wt.state = widget_state_pie_menu_item;
break;
}
return &wt;
}
static int widget_roundbox_set(uiBut *but, rcti *rect)
{
int roundbox = UI_CNR_ALL;
/* alignment */
if ((but->drawflag & UI_BUT_ALIGN) && but->type != UI_BTYPE_PULLDOWN) {
/* ui_popup_block_position has this correction too, keep in sync */
2019-03-25 10:15:20 +11:00
if (but->drawflag & (UI_BUT_ALIGN_TOP | UI_BUT_ALIGN_STITCH_TOP)) {
Holiday coding log :) Nice formatted version (pictures soon): http://wiki.blender.org/index.php/Dev:Ref/Release_Notes/2.66/Usability Short list of main changes: - Transparent region option (over main region), added code to blend in/out such panels. - Min size window now 640 x 480 - Fixed DPI for ui - lots of cleanup and changes everywhere. Icon image need correct size still, layer-in-use icon needs remake. - Macbook retina support, use command line --no-native-pixels to disable it - Timeline Marker label was drawing wrong - Trackpad and magic mouse: supports zoom (hold ctrl) - Fix for splash position: removed ghost function and made window size update after creation immediate - Fast undo buffer save now adds UI as well. Could be checked for regular file save even... Quit.blend and temp file saving use this now. - Dixed filename in window on reading quit.blend or temp saves, and they now add a warning in window title: "(Recovered)" - New Userpref option "Keep Session" - this always saves quit.blend, and loads on start. This allows keeping UI and data without actual saves, until you actually save. When you load startup.blend and quit, it recognises the quit.blend as a startup (no file name in header) - Added 3D view copy/paste buffers (selected objects). Shortcuts ctrl-c, ctrl-v (OSX, cmd-c, cmd-v). Coded partial file saving for it. Could be used for other purposes. Todo: use OS clipboards. - User preferences (themes, keymaps, user settings) now can be saved as a separate file. Old option is called "Save Startup File" the new one "Save User Settings". To visualise this difference, the 'save startup file' button has been removed from user preferences window. That option is available as CTRL+U and in File menu still. - OSX: fixed bug that stopped giving mouse events outside window. This also fixes "Continuous Grab" for OSX. (error since 2009)
2012-12-12 18:58:11 +00:00
rect->ymax += U.pixelsize;
2019-03-25 10:15:20 +11:00
}
if (but->drawflag & (UI_BUT_ALIGN_LEFT | UI_BUT_ALIGN_STITCH_LEFT)) {
Holiday coding log :) Nice formatted version (pictures soon): http://wiki.blender.org/index.php/Dev:Ref/Release_Notes/2.66/Usability Short list of main changes: - Transparent region option (over main region), added code to blend in/out such panels. - Min size window now 640 x 480 - Fixed DPI for ui - lots of cleanup and changes everywhere. Icon image need correct size still, layer-in-use icon needs remake. - Macbook retina support, use command line --no-native-pixels to disable it - Timeline Marker label was drawing wrong - Trackpad and magic mouse: supports zoom (hold ctrl) - Fix for splash position: removed ghost function and made window size update after creation immediate - Fast undo buffer save now adds UI as well. Could be checked for regular file save even... Quit.blend and temp file saving use this now. - Dixed filename in window on reading quit.blend or temp saves, and they now add a warning in window title: "(Recovered)" - New Userpref option "Keep Session" - this always saves quit.blend, and loads on start. This allows keeping UI and data without actual saves, until you actually save. When you load startup.blend and quit, it recognises the quit.blend as a startup (no file name in header) - Added 3D view copy/paste buffers (selected objects). Shortcuts ctrl-c, ctrl-v (OSX, cmd-c, cmd-v). Coded partial file saving for it. Could be used for other purposes. Todo: use OS clipboards. - User preferences (themes, keymaps, user settings) now can be saved as a separate file. Old option is called "Save Startup File" the new one "Save User Settings". To visualise this difference, the 'save startup file' button has been removed from user preferences window. That option is available as CTRL+U and in File menu still. - OSX: fixed bug that stopped giving mouse events outside window. This also fixes "Continuous Grab" for OSX. (error since 2009)
2012-12-12 18:58:11 +00:00
rect->xmin -= U.pixelsize;
2019-03-25 10:15:20 +11:00
}
switch (but->drawflag & UI_BUT_ALIGN) {
case UI_BUT_ALIGN_TOP:
roundbox = UI_CNR_BOTTOM_LEFT | UI_CNR_BOTTOM_RIGHT;
break;
case UI_BUT_ALIGN_DOWN:
roundbox = UI_CNR_TOP_LEFT | UI_CNR_TOP_RIGHT;
break;
case UI_BUT_ALIGN_LEFT:
roundbox = UI_CNR_TOP_RIGHT | UI_CNR_BOTTOM_RIGHT;
break;
case UI_BUT_ALIGN_RIGHT:
roundbox = UI_CNR_TOP_LEFT | UI_CNR_BOTTOM_LEFT;
break;
case UI_BUT_ALIGN_DOWN | UI_BUT_ALIGN_RIGHT:
roundbox = UI_CNR_TOP_LEFT;
break;
case UI_BUT_ALIGN_DOWN | UI_BUT_ALIGN_LEFT:
roundbox = UI_CNR_TOP_RIGHT;
break;
case UI_BUT_ALIGN_TOP | UI_BUT_ALIGN_RIGHT:
roundbox = UI_CNR_BOTTOM_LEFT;
break;
case UI_BUT_ALIGN_TOP | UI_BUT_ALIGN_LEFT:
roundbox = UI_CNR_BOTTOM_RIGHT;
break;
default:
roundbox = 0;
break;
}
}
/* align with open menu */
if (but->active && (but->type != UI_BTYPE_POPOVER) && !ui_but_menu_draw_as_popover(but)) {
const int direction = ui_but_menu_direction(but);
2019-03-25 10:15:20 +11:00
if (direction == UI_DIR_UP) {
roundbox &= ~(UI_CNR_TOP_RIGHT | UI_CNR_TOP_LEFT);
}
else if (direction == UI_DIR_DOWN) {
roundbox &= ~(UI_CNR_BOTTOM_RIGHT | UI_CNR_BOTTOM_LEFT);
}
else if (direction == UI_DIR_LEFT) {
roundbox &= ~(UI_CNR_TOP_LEFT | UI_CNR_BOTTOM_LEFT);
}
else if (direction == UI_DIR_RIGHT) {
roundbox &= ~(UI_CNR_TOP_RIGHT | UI_CNR_BOTTOM_RIGHT);
}
}
return roundbox;
}
/* -------------------------------------------------------------------- */
/** \name Public API
* \{ */
/* conversion from old to new buttons, so still messy */
void ui_draw_but(const bContext *C, struct ARegion *region, uiStyle *style, uiBut *but, rcti *rect)
{
2012-03-30 01:51:25 +00:00
bTheme *btheme = UI_GetTheme();
const ThemeUI *tui = &btheme->tui;
const uiFontStyle *fstyle = &style->widget;
2012-03-30 01:51:25 +00:00
uiWidgetType *wt = NULL;
2009-11-02 17:25:15 +00:00
/* handle menus separately */
if (but->emboss == UI_EMBOSS_PULLDOWN) {
switch (but->type) {
case UI_BTYPE_LABEL:
2009-04-27 13:44:11 +00:00
widget_draw_text_icon(&style->widgetlabel, &tui->wcol_menu_back, but, rect);
break;
case UI_BTYPE_SEPR_LINE:
ui_draw_separator(rect, &tui->wcol_menu_item);
break;
default:
2012-03-30 01:51:25 +00:00
wt = widget_type(UI_WTYPE_MENU_ITEM);
break;
}
}
else if (ELEM(but->emboss, UI_EMBOSS_NONE, UI_EMBOSS_NONE_OR_STATUS)) {
/* Use the same widget types for both no emboss types. Later on,
* #UI_EMBOSS_NONE_OR_STATUS will blend state colors if they apply. */
switch (but->type) {
case UI_BTYPE_LABEL:
wt = widget_type(UI_WTYPE_ICON_LABEL);
break;
default:
wt = widget_type(UI_WTYPE_ICON);
break;
}
}
else if (but->emboss == UI_EMBOSS_RADIAL) {
wt = widget_type(UI_WTYPE_MENU_ITEM_RADIAL);
}
else {
BLI_assert(but->emboss == UI_EMBOSS);
switch (but->type) {
case UI_BTYPE_LABEL:
2017-07-27 10:27:29 +03:00
wt = widget_type(UI_WTYPE_LABEL);
fstyle = &style->widgetlabel;
if (but->drawflag & UI_BUT_BOX_ITEM) {
wt->wcol_theme = &tui->wcol_box;
wt->state = widget_state;
}
else if (but->block->theme_style == UI_BLOCK_THEME_STYLE_POPUP) {
2017-07-27 10:27:29 +03:00
wt->wcol_theme = &tui->wcol_menu_back;
wt->state = widget_state;
2009-04-27 13:44:11 +00:00
}
if (!(but->flag & UI_HAS_ICON)) {
but->drawflag |= UI_BUT_NO_TEXT_PADDING;
}
break;
case UI_BTYPE_SEPR:
case UI_BTYPE_SEPR_LINE:
case UI_BTYPE_SEPR_SPACER:
break;
case UI_BTYPE_BUT:
case UI_BTYPE_DECORATOR:
#ifdef USE_UI_TOOLBAR_HACK
if ((but->icon != ICON_NONE) && UI_but_is_tool(but)) {
wt = widget_type(UI_WTYPE_TOOLBAR_ITEM);
}
else {
wt = widget_type(UI_WTYPE_EXEC);
}
#else
2012-03-30 01:51:25 +00:00
wt = widget_type(UI_WTYPE_EXEC);
#endif
break;
case UI_BTYPE_NUM:
2012-03-30 01:51:25 +00:00
wt = widget_type(UI_WTYPE_NUMBER);
break;
case UI_BTYPE_NUM_SLIDER:
2012-03-30 01:51:25 +00:00
wt = widget_type(UI_WTYPE_SLIDER);
break;
case UI_BTYPE_ROW:
2012-03-30 01:51:25 +00:00
wt = widget_type(UI_WTYPE_RADIO);
break;
case UI_BTYPE_LISTROW:
2012-03-30 01:51:25 +00:00
wt = widget_type(UI_WTYPE_LISTITEM);
break;
case UI_BTYPE_TEXT:
2012-03-30 01:51:25 +00:00
wt = widget_type(UI_WTYPE_NAME);
break;
case UI_BTYPE_SEARCH_MENU:
2012-03-30 01:51:25 +00:00
wt = widget_type(UI_WTYPE_NAME);
break;
case UI_BTYPE_TAB:
wt = widget_type(UI_WTYPE_TAB);
break;
case UI_BTYPE_BUT_TOGGLE:
case UI_BTYPE_TOGGLE:
case UI_BTYPE_TOGGLE_N:
2012-03-30 01:51:25 +00:00
wt = widget_type(UI_WTYPE_TOGGLE);
break;
case UI_BTYPE_CHECKBOX:
case UI_BTYPE_CHECKBOX_N:
if (!(but->flag & UI_HAS_ICON)) {
wt = widget_type(UI_WTYPE_CHECKBOX);
UI: Better split layout support for checkboxes Makes the following layout changes possible: {F8473498} {F8473499} {F8473502} The next commit will contain many layout changes to make good use of these new possibilities. The result should be more consistent, easier to read and should give a more organized impression. Additionally, it should be possible to replace many sub-panels with compacter layouts. Main changes: * Checkboxes now respect the property split layouts * Add support for row and column headers (i.e. `uiLayout.column(heading="Foo")`, `uiLayout.row(heading="Bar")`). If the first property added to this layout doesn't insert anything into the label split column, the heading is inserted there. Otherwise, it's inserted as own item. * Add support for manually inserting decorators for an existing item (`uiLayout.prop_decorator()`). That way layout creators can manually insert this, which was the only way I saw to support property split layouts with a checkbox before the actual property. {F8471883} * Autogenerated layouts for operator properties look bad if there are only checkboxes (which only use half the region width). So before creating the layout, we iterate over visible properties and disable split layout if all are booleans. I think this is fine, if needed we could also add layout hints to operators. * `uiTemplateOperatorPropertyButs()` now handles macros itself, the caller used to be responsible for this. Code that didn't handle these so far never used macros I think, so this change should be invisible. * Remove manual property split layout from autogenerated operator properties layout. * Padding of checkboxes is tweaked to make their label visually more connected to the checkboxes. * Support split layout for menus (should work for `uiLayout.menu()`, `.operator_menu_enum()`, `.prop_menu_enum()`, maybe more) Maniphest Task: https://developer.blender.org/T65965 Differential Revision: https://developer.blender.org/D7427 Reviewed by: Brecht Van Lommel, William Reynish, Pablo Vazques
2020-04-17 16:40:25 +02:00
if ((but->drawflag & (UI_BUT_TEXT_LEFT | UI_BUT_TEXT_RIGHT)) == 0) {
but->drawflag |= UI_BUT_TEXT_LEFT;
}
2020-07-10 16:04:09 +10:00
/* #widget_optionbut() carefully sets the text rectangle for fine tuned paddings. If the
UI: Better split layout support for checkboxes Makes the following layout changes possible: {F8473498} {F8473499} {F8473502} The next commit will contain many layout changes to make good use of these new possibilities. The result should be more consistent, easier to read and should give a more organized impression. Additionally, it should be possible to replace many sub-panels with compacter layouts. Main changes: * Checkboxes now respect the property split layouts * Add support for row and column headers (i.e. `uiLayout.column(heading="Foo")`, `uiLayout.row(heading="Bar")`). If the first property added to this layout doesn't insert anything into the label split column, the heading is inserted there. Otherwise, it's inserted as own item. * Add support for manually inserting decorators for an existing item (`uiLayout.prop_decorator()`). That way layout creators can manually insert this, which was the only way I saw to support property split layouts with a checkbox before the actual property. {F8471883} * Autogenerated layouts for operator properties look bad if there are only checkboxes (which only use half the region width). So before creating the layout, we iterate over visible properties and disable split layout if all are booleans. I think this is fine, if needed we could also add layout hints to operators. * `uiTemplateOperatorPropertyButs()` now handles macros itself, the caller used to be responsible for this. Code that didn't handle these so far never used macros I think, so this change should be invisible. * Remove manual property split layout from autogenerated operator properties layout. * Padding of checkboxes is tweaked to make their label visually more connected to the checkboxes. * Support split layout for menus (should work for `uiLayout.menu()`, `.operator_menu_enum()`, `.prop_menu_enum()`, maybe more) Maniphest Task: https://developer.blender.org/T65965 Differential Revision: https://developer.blender.org/D7427 Reviewed by: Brecht Van Lommel, William Reynish, Pablo Vazques
2020-04-17 16:40:25 +02:00
* text drawing were to add its own padding, DPI and zoom factor would be applied twice
* in the final padding, so it's difficult to control it. */
but->drawflag |= UI_BUT_NO_TEXT_PADDING;
}
else {
2012-03-30 01:51:25 +00:00
wt = widget_type(UI_WTYPE_TOGGLE);
}
/* option buttons have strings outside, on menus use different colors */
if (but->block->theme_style == UI_BLOCK_THEME_STYLE_POPUP) {
2012-03-30 01:51:25 +00:00
wt->state = widget_state_option_menu;
}
break;
case UI_BTYPE_MENU:
case UI_BTYPE_BLOCK:
case UI_BTYPE_POPOVER:
if (but->flag & UI_BUT_NODE_LINK) {
/* new node-link button, not active yet XXX */
2012-03-30 01:51:25 +00:00
wt = widget_type(UI_WTYPE_MENU_NODE_LINK);
}
else {
/* with menu arrows */
2019-08-04 12:51:44 +10:00
/* We could use a flag for this, but for now just check size,
* add up/down arrows if there is room. */
if ((!but->str[0] && but->icon && (BLI_rcti_size_x(rect) < BLI_rcti_size_y(rect) + 2)) ||
/* disable for brushes also */
(but->flag & UI_BUT_ICON_PREVIEW)) {
/* no arrows */
wt = widget_type(UI_WTYPE_MENU_ICON_RADIO);
}
else {
wt = widget_type(UI_WTYPE_MENU_RADIO);
}
}
break;
case UI_BTYPE_PULLDOWN:
2012-03-30 01:51:25 +00:00
wt = widget_type(UI_WTYPE_PULLDOWN);
break;
case UI_BTYPE_BUT_MENU:
2012-03-30 01:51:25 +00:00
wt = widget_type(UI_WTYPE_MENU_ITEM);
break;
case UI_BTYPE_COLOR:
2012-03-30 01:51:25 +00:00
wt = widget_type(UI_WTYPE_SWATCH);
break;
case UI_BTYPE_ROUNDBOX:
case UI_BTYPE_LISTBOX:
2012-03-30 01:51:25 +00:00
wt = widget_type(UI_WTYPE_BOX);
break;
case UI_BTYPE_EXTRA:
widget_draw_extra_mask(C, but, widget_type(UI_WTYPE_BOX), rect);
break;
case UI_BTYPE_HSVCUBE: {
const uiButHSVCube *hsv_but = (uiButHSVCube *)but;
if (ELEM(hsv_but->gradient_type, UI_GRAD_V_ALT, UI_GRAD_L_ALT)) {
/* vertical V slider, uses new widget draw now */
ui_draw_but_HSV_v(but, rect);
2012-08-19 10:41:27 +00:00
}
else { /* other HSV pickers... */
ui_draw_but_HSVCUBE(but, rect);
2012-08-19 10:41:27 +00:00
}
break;
}
case UI_BTYPE_HSVCIRCLE:
ui_draw_but_HSVCIRCLE(but, &tui->wcol_regular, rect);
break;
case UI_BTYPE_COLORBAND:
/* do not draw right to edge of rect */
rect->xmin += (0.25f * UI_UNIT_X);
rect->xmax -= (0.3f * UI_UNIT_X);
2009-04-27 13:44:11 +00:00
ui_draw_but_COLORBAND(but, &tui->wcol_regular, rect);
break;
case UI_BTYPE_UNITVEC:
wt = widget_type(UI_WTYPE_UNITVEC);
break;
case UI_BTYPE_IMAGE:
ui_draw_but_IMAGE(region, but, &tui->wcol_regular, rect);
break;
case UI_BTYPE_HISTOGRAM:
ui_draw_but_HISTOGRAM(region, but, &tui->wcol_regular, rect);
break;
case UI_BTYPE_WAVEFORM:
ui_draw_but_WAVEFORM(region, but, &tui->wcol_regular, rect);
break;
case UI_BTYPE_VECTORSCOPE:
ui_draw_but_VECTORSCOPE(region, but, &tui->wcol_regular, rect);
break;
case UI_BTYPE_CURVE:
/* do not draw right to edge of rect */
rect->xmin += (0.2f * UI_UNIT_X);
rect->xmax -= (0.2f * UI_UNIT_X);
ui_draw_but_CURVE(region, but, &tui->wcol_regular, rect);
break;
case UI_BTYPE_CURVEPROFILE:
ui_draw_but_CURVEPROFILE(region, but, &tui->wcol_regular, rect);
break;
case UI_BTYPE_PROGRESS_BAR:
2012-03-30 01:51:25 +00:00
wt = widget_type(UI_WTYPE_PROGRESSBAR);
fstyle = &style->widgetlabel;
break;
case UI_BTYPE_DATASETROW:
wt = widget_type(UI_WTYPE_DATASETROW);
fstyle = &style->widgetlabel;
break;
case UI_BTYPE_SCROLL:
2012-03-30 01:51:25 +00:00
wt = widget_type(UI_WTYPE_SCROLL);
break;
case UI_BTYPE_GRIP:
wt = widget_type(UI_WTYPE_ICON);
break;
case UI_BTYPE_TRACK_PREVIEW:
ui_draw_but_TRACKPREVIEW(region, but, &tui->wcol_regular, rect);
Camera tracking integration =========================== Commiting camera tracking integration gsoc project into trunk. This commit includes: - Bundled version of libmv library (with some changes against official repo, re-sync with libmv repo a bit later) - New datatype ID called MovieClip which is optimized to work with movie clips (both of movie files and image sequences) and doing camera/motion tracking operations. - New editor called Clip Editor which is currently used for motion/tracking stuff only, but which can be easily extended to work with masks too. This editor supports: * Loading movie files/image sequences * Build proxies with different size for loaded movie clip, also supports building undistorted proxies to increase speed of playback in undistorted mode. * Manual lens distortion mode calibration using grid and grease pencil * Supervised 2D tracking using two different algorithms KLT and SAD. * Basic algorithm for feature detection * Camera motion solving. scene orientation - New constraints to "link" scene objects with solved motions from clip: * Follow Track (make object follow 2D motion of track with given name or parent object to reconstructed 3D position of track) * Camera Solver to make camera moving in the same way as reconstructed camera This commit NOT includes changes from tomato branch: - New nodes (they'll be commited as separated patch) - Automatic image offset guessing for image input node and image editor (need to do more tests and gather more feedback) - Code cleanup in libmv-capi. It's not so critical cleanup, just increasing readability and understanadability of code. Better to make this chaneg when Keir will finish his current patch. More details about this project can be found on this page: http://wiki.blender.org/index.php/User:Nazg-gul/GSoC-2011 Further development of small features would be done in trunk, bigger/experimental features would first be implemented in tomato branch.
2011-11-07 12:55:18 +00:00
break;
case UI_BTYPE_NODE_SOCKET:
wt = widget_type(UI_WTYPE_NODESOCKET);
Merge of the PyNodes branch (aka "custom nodes") into trunk. PyNodes opens up the node system in Blender to scripters and adds a number of UI-level improvements. === Dynamic node type registration === Node types can now be added at runtime, using the RNA registration mechanism from python. This enables addons such as render engines to create a complete user interface with nodes. Examples of how such nodes can be defined can be found in my personal wiki docs atm [1] and as a script template in release/scripts/templates_py/custom_nodes.py [2]. === Node group improvements === Each node editor now has a tree history of edited node groups, which allows opening and editing nested node groups. The node editor also supports pinning now, so that different spaces can be used to edit different node groups simultaneously. For more ramblings and rationale see (really old) blog post on code.blender.org [3]. The interface of node groups has been overhauled. Sockets of a node group are no longer displayed in columns on either side, but instead special input/output nodes are used to mirror group sockets inside a node tree. This solves the problem of long node lines in groups and allows more adaptable node layout. Internal sockets can be exposed from a group by either connecting to the extension sockets in input/output nodes (shown as empty circle) or by adding sockets from the node property bar in the "Interface" panel. Further details such as the socket name can also be changed there. [1] http://wiki.blender.org/index.php/User:Phonybone/Python_Nodes [2] http://projects.blender.org/scm/viewvc.php/trunk/blender/release/scripts/templates_py/custom_nodes.py?view=markup&root=bf-blender [3] http://code.blender.org/index.php/2012/01/improving-node-group-interface-editing/
2013-03-18 16:34:57 +00:00
break;
default:
2012-03-30 01:51:25 +00:00
wt = widget_type(UI_WTYPE_REGULAR);
break;
}
}
2020-12-21 09:43:54 -06:00
if (wt == NULL) {
return;
}
2020-12-21 09:43:54 -06:00
// rcti disablerect = *rect; /* rect gets clipped smaller for text */
2020-12-21 09:43:54 -06:00
const int roundboxalign = widget_roundbox_set(but, rect);
2020-12-21 09:43:54 -06:00
/* Mask out flags re-used for local state. */
int state = but->flag & ~UI_STATE_FLAGS_ALL;
const int drawflag = but->drawflag;
2020-12-21 09:43:54 -06:00
if (state & UI_SELECT_DRAW) {
state |= UI_SELECT;
}
2020-12-21 09:43:54 -06:00
if ((but->editstr) ||
(UNLIKELY(but->flag & UI_BUT_DRAG_MULTI) && ui_but_drag_multi_edit_get(but))) {
state |= UI_STATE_TEXT_INPUT;
}
2020-12-21 09:43:54 -06:00
if (but->hold_func) {
state |= UI_STATE_HOLD_ACTION;
}
2020-12-21 09:43:54 -06:00
if (state & UI_ACTIVE) {
if (but->drawflag & UI_BUT_ACTIVE_LEFT) {
state |= UI_STATE_ACTIVE_LEFT;
}
else if (but->drawflag & UI_BUT_ACTIVE_RIGHT) {
state |= UI_STATE_ACTIVE_RIGHT;
2019-03-25 10:15:20 +11:00
}
2020-12-21 09:43:54 -06:00
}
2020-12-21 09:43:54 -06:00
bool use_alpha_blend = false;
if (but->emboss != UI_EMBOSS_PULLDOWN) {
if (state & (UI_BUT_DISABLED | UI_BUT_INACTIVE | UI_SEARCH_FILTER_NO_MATCH)) {
use_alpha_blend = true;
ui_widget_color_disabled(wt, state);
}
2020-12-21 09:43:54 -06:00
}
if (drawflag & UI_BUT_TEXT_RIGHT) {
state |= UI_STATE_TEXT_BEFORE_WIDGET;
}
#ifdef USE_UI_POPOVER_ONCE
2020-12-21 09:43:54 -06:00
if (but->block->flag & UI_BLOCK_POPOVER_ONCE) {
if ((state & UI_ACTIVE) && ui_but_is_popover_once_compat(but)) {
state |= UI_BUT_ACTIVE_DEFAULT;
}
2020-12-21 09:43:54 -06:00
}
#endif
2020-12-21 09:43:54 -06:00
wt->state(wt, state, drawflag, but->emboss);
if (wt->custom) {
wt->custom(but, &wt->wcol, rect, state, roundboxalign);
}
else if (wt->draw) {
wt->draw(&wt->wcol, rect, state, roundboxalign);
}
2020-12-21 09:43:54 -06:00
if (use_alpha_blend) {
GPU_blend(GPU_BLEND_ALPHA);
}
2020-12-21 09:43:54 -06:00
wt->text(fstyle, &wt->wcol, but, rect);
if (use_alpha_blend) {
GPU_blend(GPU_BLEND_NONE);
}
}
static void ui_draw_clip_tri(uiBlock *block, rcti *rect, uiWidgetType *wt)
{
if (block) {
float draw_color[4];
const uchar *color = wt->wcol.text;
draw_color[0] = ((float)color[0]) / 255.0f;
draw_color[1] = ((float)color[1]) / 255.0f;
draw_color[2] = ((float)color[2]) / 255.0f;
draw_color[3] = 1.0f;
if (block->flag & UI_BLOCK_CLIPTOP) {
/* XXX no scaling for UI here yet */
UI_draw_icon_tri(BLI_rcti_cent_x(rect), rect->ymax - 6 * U.dpi_fac, 't', draw_color);
}
if (block->flag & UI_BLOCK_CLIPBOTTOM) {
/* XXX no scaling for UI here yet */
UI_draw_icon_tri(BLI_rcti_cent_x(rect), rect->ymin + 10 * U.dpi_fac, 'v', draw_color);
}
}
}
void ui_draw_menu_back(uiStyle *UNUSED(style), uiBlock *block, rcti *rect)
{
uiWidgetType *wt = widget_type(UI_WTYPE_MENU_BACK);
wt->state(wt, 0, 0, UI_EMBOSS_UNDEFINED);
2019-03-25 10:15:20 +11:00
if (block) {
wt->draw(&wt->wcol, rect, block->flag, block->direction);
2019-03-25 10:15:20 +11:00
}
else {
wt->draw(&wt->wcol, rect, 0, 0);
2019-03-25 10:15:20 +11:00
}
ui_draw_clip_tri(block, rect, wt);
}
UI: List Panel System This implements a general system to implement drag and drop, subpanels, and UI animation for the stack UIs in Blender. There are NO functional changes in this patch, but it makes it relatively trivial to implement these features for stacks. The biggest complication to using panels to implement the UI for lists is that there can be multiple modifiers of the same type. Currently there is an assumed 1 to 1 relationship between every panel and its type, but there can be multiple list items of the same type, so we have to break this relationship. The mapping between panels and their data is stored with an index in the panel's runtime struct. To make use the system for a list like modifiers, four components must be added: 1. A panel type defined and registered for each list data type, with a known mapping between list data types and panel idnames. 1. A function called by interface code to build the add the panel layouts with the provided helper functions. - UI_panel_list_matches_data will check if the panel list needs to be rebuilt. - UI_panels_free_instanced will remove the existing list panels - UI_panel_add_instanced adds a list panel of a given type. 3. An expand flag for the list data and implementations of get_list_data_expand_flag and set_list_data_expand_flag. 4. For reordering, the panel type's reorder callback. This is called when the instanced panels are drag-dropped. This requires implementing a "move to index" operator for the list data. Reviewed By: Severin, brecht Differential Revision: https://developer.blender.org/D7490
2020-05-26 15:39:49 -04:00
/**
* Uses the widget base drawing and colors from the box widget, but ensures an opaque
UI: List Panel System This implements a general system to implement drag and drop, subpanels, and UI animation for the stack UIs in Blender. There are NO functional changes in this patch, but it makes it relatively trivial to implement these features for stacks. The biggest complication to using panels to implement the UI for lists is that there can be multiple modifiers of the same type. Currently there is an assumed 1 to 1 relationship between every panel and its type, but there can be multiple list items of the same type, so we have to break this relationship. The mapping between panels and their data is stored with an index in the panel's runtime struct. To make use the system for a list like modifiers, four components must be added: 1. A panel type defined and registered for each list data type, with a known mapping between list data types and panel idnames. 1. A function called by interface code to build the add the panel layouts with the provided helper functions. - UI_panel_list_matches_data will check if the panel list needs to be rebuilt. - UI_panels_free_instanced will remove the existing list panels - UI_panel_add_instanced adds a list panel of a given type. 3. An expand flag for the list data and implementations of get_list_data_expand_flag and set_list_data_expand_flag. 4. For reordering, the panel type's reorder callback. This is called when the instanced panels are drag-dropped. This requires implementing a "move to index" operator for the list data. Reviewed By: Severin, brecht Differential Revision: https://developer.blender.org/D7490
2020-05-26 15:39:49 -04:00
* inner color.
*/
void ui_draw_box_opaque(rcti *rect, int roundboxalign)
{
uiWidgetType *wt = widget_type(UI_WTYPE_BOX);
/* Alpha blend with the region's background color to force an opaque background. */
uiWidgetColors *wcol = &wt->wcol;
wt->state(wt, 0, 0, UI_EMBOSS_UNDEFINED);
UI: List Panel System This implements a general system to implement drag and drop, subpanels, and UI animation for the stack UIs in Blender. There are NO functional changes in this patch, but it makes it relatively trivial to implement these features for stacks. The biggest complication to using panels to implement the UI for lists is that there can be multiple modifiers of the same type. Currently there is an assumed 1 to 1 relationship between every panel and its type, but there can be multiple list items of the same type, so we have to break this relationship. The mapping between panels and their data is stored with an index in the panel's runtime struct. To make use the system for a list like modifiers, four components must be added: 1. A panel type defined and registered for each list data type, with a known mapping between list data types and panel idnames. 1. A function called by interface code to build the add the panel layouts with the provided helper functions. - UI_panel_list_matches_data will check if the panel list needs to be rebuilt. - UI_panels_free_instanced will remove the existing list panels - UI_panel_add_instanced adds a list panel of a given type. 3. An expand flag for the list data and implementations of get_list_data_expand_flag and set_list_data_expand_flag. 4. For reordering, the panel type's reorder callback. This is called when the instanced panels are drag-dropped. This requires implementing a "move to index" operator for the list data. Reviewed By: Severin, brecht Differential Revision: https://developer.blender.org/D7490
2020-05-26 15:39:49 -04:00
float background[4];
UI_GetThemeColor4fv(TH_BACK, background);
float new_inner[4];
rgba_uchar_to_float(new_inner, wcol->inner);
new_inner[0] = (new_inner[0] * new_inner[3]) + (background[0] * (1.0f - new_inner[3]));
new_inner[1] = (new_inner[1] * new_inner[3]) + (background[1] * (1.0f - new_inner[3]));
new_inner[2] = (new_inner[2] * new_inner[3]) + (background[2] * (1.0f - new_inner[3]));
new_inner[3] = 1.0f;
rgba_float_to_uchar(wcol->inner, new_inner);
wt->custom(NULL, wcol, rect, 0, roundboxalign);
}
/**
* Similar to 'widget_menu_back', however we can't use the widget preset system
* because we need to pass in the original location so we know where to show the arrow.
*/
static void ui_draw_popover_back_impl(const uiWidgetColors *wcol,
rcti *rect,
int direction,
const float unit_size,
const float mval_origin[2])
{
/* tsk, this isn't nice. */
const float unit_half = unit_size / 2;
2019-10-07 15:17:44 +11:00
const float cent_x = mval_origin ? CLAMPIS(mval_origin[0],
rect->xmin + unit_size,
rect->xmax - unit_size) :
BLI_rcti_cent_x(rect);
GPU_blend(GPU_BLEND_ALPHA);
/* Extracted from 'widget_menu_back', keep separate to avoid menu changes breaking popovers */
{
uiWidgetBase wtb;
widget_init(&wtb);
const int roundboxalign = UI_CNR_ALL;
widget_softshadow(rect, roundboxalign, wcol->roundness * U.widget_unit);
round_box_edges(&wtb, roundboxalign, rect, wcol->roundness * U.widget_unit);
wtb.draw_emboss = false;
widgetbase_draw(&wtb, wcol);
}
/* Draw popover arrow (top/bottom) */
if (ELEM(direction, UI_DIR_UP, UI_DIR_DOWN)) {
const uint pos = GPU_vertformat_attr_add(
immVertexFormat(), "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
const bool is_down = (direction == UI_DIR_DOWN);
const int sign = is_down ? 1 : -1;
float y = is_down ? rect->ymax : rect->ymin;
GPU_blend(GPU_BLEND_ALPHA);
immBegin(GPU_PRIM_TRIS, 3);
immUniformColor4ubv(wcol->outline);
immVertex2f(pos, cent_x - unit_half, y);
immVertex2f(pos, cent_x + unit_half, y);
immVertex2f(pos, cent_x, y + sign * unit_half);
immEnd();
y = y - sign * round(U.pixelsize * 1.41);
GPU_blend(GPU_BLEND_NONE);
immBegin(GPU_PRIM_TRIS, 3);
immUniformColor4ub(0, 0, 0, 0);
immVertex2f(pos, cent_x - unit_half, y);
immVertex2f(pos, cent_x + unit_half, y);
immVertex2f(pos, cent_x, y + sign * unit_half);
immEnd();
GPU_blend(GPU_BLEND_ALPHA);
immBegin(GPU_PRIM_TRIS, 3);
immUniformColor4ubv(wcol->inner);
immVertex2f(pos, cent_x - unit_half, y);
immVertex2f(pos, cent_x + unit_half, y);
immVertex2f(pos, cent_x, y + sign * unit_half);
immEnd();
immUnbindProgram();
}
GPU_blend(GPU_BLEND_NONE);
}
void ui_draw_popover_back(struct ARegion *region,
uiStyle *UNUSED(style),
uiBlock *block,
rcti *rect)
{
uiWidgetType *wt = widget_type(UI_WTYPE_MENU_BACK);
if (block) {
float mval_origin[2] = {UNPACK2(block->bounds_offset)};
ui_window_to_block_fl(region, block, &mval_origin[0], &mval_origin[1]);
ui_draw_popover_back_impl(
wt->wcol_theme, rect, block->direction, U.widget_unit / block->aspect, mval_origin);
}
else {
wt->state(wt, 0, 0, UI_EMBOSS_UNDEFINED);
wt->draw(&wt->wcol, rect, 0, 0);
}
ui_draw_clip_tri(block, rect, wt);
}
static void draw_disk_shaded(float start,
float angle,
float radius_int,
float radius_ext,
int subd,
const uchar col1[4],
const uchar col2[4],
bool shaded)
{
const float radius_ext_scale = (0.5f / radius_ext); /* 1 / (2 * radius_ext) */
uint col;
GPUVertFormat *format = immVertexFormat();
2021-01-04 17:02:13 +11:00
const uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
if (shaded) {
col = GPU_vertformat_attr_add(format, "color", GPU_COMP_U8, 4, GPU_FETCH_INT_TO_FLOAT_UNIT);
immBindBuiltinProgram(GPU_SHADER_2D_SMOOTH_COLOR);
}
else {
immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
immUniformColor4ubv(col1);
}
immBegin(GPU_PRIM_TRI_STRIP, subd * 2);
2020-09-09 18:41:07 +02:00
for (int i = 0; i < subd; i++) {
2021-01-04 17:02:13 +11:00
const float a = start + ((i) / (float)(subd - 1)) * angle;
const float s = sinf(a);
const float c = cosf(a);
const float y1 = s * radius_int;
const float y2 = s * radius_ext;
if (shaded) {
2020-09-09 18:41:07 +02:00
uchar r_col[4];
2021-01-04 17:02:13 +11:00
const float fac = (y1 + radius_ext) * radius_ext_scale;
color_blend_v4_v4v4(r_col, col1, col2, fac);
immAttr4ubv(col, r_col);
}
immVertex2f(pos, c * radius_int, s * radius_int);
if (shaded) {
2020-09-09 18:41:07 +02:00
uchar r_col[4];
2021-01-04 17:02:13 +11:00
const float fac = (y2 + radius_ext) * radius_ext_scale;
color_blend_v4_v4v4(r_col, col1, col2, fac);
immAttr4ubv(col, r_col);
}
immVertex2f(pos, c * radius_ext, s * radius_ext);
}
immEnd();
immUnbindProgram();
}
void ui_draw_pie_center(uiBlock *block)
{
bTheme *btheme = UI_GetTheme();
const float cx = block->pie_data.pie_center_spawned[0];
const float cy = block->pie_data.pie_center_spawned[1];
float *pie_dir = block->pie_data.pie_dir;
const float pie_radius_internal = U.dpi_fac * U.pie_menu_threshold;
const float pie_radius_external = U.dpi_fac * (U.pie_menu_threshold + 7.0f);
const int subd = 40;
const float angle = atan2f(pie_dir[1], pie_dir[0]);
const float range = (block->pie_data.flags & UI_PIE_DEGREES_RANGE_LARGE) ? M_PI_2 : M_PI_4;
GPU_matrix_push();
GPU_matrix_translate_2f(cx, cy);
GPU_blend(GPU_BLEND_ALPHA);
if (btheme->tui.wcol_pie_menu.shaded) {
uchar col1[4], col2[4];
shadecolors4(col1,
col2,
btheme->tui.wcol_pie_menu.inner,
btheme->tui.wcol_pie_menu.shadetop,
btheme->tui.wcol_pie_menu.shadedown);
draw_disk_shaded(0.0f,
(float)(M_PI * 2.0),
pie_radius_internal,
pie_radius_external,
subd,
col1,
col2,
true);
}
else {
draw_disk_shaded(0.0f,
(float)(M_PI * 2.0),
pie_radius_internal,
pie_radius_external,
subd,
btheme->tui.wcol_pie_menu.inner,
NULL,
false);
}
if (!(block->pie_data.flags & UI_PIE_INVALID_DIR)) {
if (btheme->tui.wcol_pie_menu.shaded) {
uchar col1[4], col2[4];
shadecolors4(col1,
col2,
btheme->tui.wcol_pie_menu.inner_sel,
btheme->tui.wcol_pie_menu.shadetop,
btheme->tui.wcol_pie_menu.shadedown);
draw_disk_shaded(angle - range / 2.0f,
range,
pie_radius_internal,
pie_radius_external,
subd,
col1,
col2,
true);
}
else {
draw_disk_shaded(angle - range / 2.0f,
range,
pie_radius_internal,
pie_radius_external,
subd,
btheme->tui.wcol_pie_menu.inner_sel,
NULL,
false);
}
}
GPUVertFormat *format = immVertexFormat();
const uint pos = GPU_vertformat_attr_add(format, "pos", GPU_COMP_F32, 2, GPU_FETCH_FLOAT);
immBindBuiltinProgram(GPU_SHADER_2D_UNIFORM_COLOR);
immUniformColor4ubv(btheme->tui.wcol_pie_menu.outline);
imm_draw_circle_wire_2d(pos, 0.0f, 0.0f, pie_radius_internal, subd);
imm_draw_circle_wire_2d(pos, 0.0f, 0.0f, pie_radius_external, subd);
immUnbindProgram();
if (U.pie_menu_confirm > 0 &&
!(block->pie_data.flags & (UI_PIE_INVALID_DIR | UI_PIE_CLICK_STYLE))) {
const float pie_confirm_radius = U.dpi_fac * (pie_radius_internal + U.pie_menu_confirm);
const float pie_confirm_external = U.dpi_fac *
(pie_radius_internal + U.pie_menu_confirm + 7.0f);
const uchar col[4] = {UNPACK3(btheme->tui.wcol_pie_menu.text_sel), 64};
draw_disk_shaded(angle - range / 2.0f,
range,
pie_confirm_radius,
pie_confirm_external,
subd,
col,
NULL,
false);
}
GPU_blend(GPU_BLEND_NONE);
GPU_matrix_pop();
}
const uiWidgetColors *ui_tooltip_get_theme(void)
2012-04-24 22:50:49 +00:00
{
uiWidgetType *wt = widget_type(UI_WTYPE_TOOLTIP);
return wt->wcol_theme;
}
/**
* Generic drawing for background.
*/
static void ui_draw_widget_back_color(uiWidgetTypeEnum type,
2018-06-13 09:50:02 +02:00
bool use_shadow,
const rcti *rect,
const float color[4])
{
uiWidgetType *wt = widget_type(type);
if (use_shadow) {
GPU_blend(GPU_BLEND_ALPHA);
widget_softshadow(rect, UI_CNR_ALL, 0.25f * U.widget_unit);
GPU_blend(GPU_BLEND_NONE);
}
rcti rect_copy = *rect;
wt->state(wt, 0, 0, UI_EMBOSS_UNDEFINED);
2018-06-13 09:50:02 +02:00
if (color) {
rgba_float_to_uchar(wt->wcol.inner, color);
2018-06-13 09:50:02 +02:00
}
wt->draw(&wt->wcol, &rect_copy, 0, UI_CNR_ALL);
}
void ui_draw_widget_menu_back_color(const rcti *rect, bool use_shadow, const float color[4])
{
ui_draw_widget_back_color(UI_WTYPE_MENU_BACK, use_shadow, rect, color);
}
void ui_draw_widget_menu_back(const rcti *rect, bool use_shadow)
2018-06-13 09:50:02 +02:00
{
ui_draw_widget_back_color(UI_WTYPE_MENU_BACK, use_shadow, rect, NULL);
2018-06-13 09:50:02 +02:00
}
2020-03-15 17:32:25 +11:00
void ui_draw_tooltip_background(const uiStyle *UNUSED(style), uiBlock *UNUSED(block), rcti *rect)
{
uiWidgetType *wt = widget_type(UI_WTYPE_TOOLTIP);
wt->state(wt, 0, 0, UI_EMBOSS_UNDEFINED);
/* wt->draw ends up using same function to draw the tooltip as menu_back */
wt->draw(&wt->wcol, rect, 0, 0);
}
/**
* Helper call to draw a menu item without a button.
*
* \param state: The state of the button,
* typically #UI_ACTIVE, #UI_BUT_DISABLED, #UI_BUT_INACTIVE.
* \param separator_type: The kind of separator which controls if and how the string is clipped.
* \param r_xmax: The right hand position of the text, this takes into the icon,
* padding and text clipping when there is not enough room to display the full text.
*/
void ui_draw_menu_item(const uiFontStyle *fstyle,
rcti *rect,
const char *name,
int iconid,
int state,
uiMenuItemSeparatorType separator_type,
int *r_xmax)
{
2012-03-30 01:51:25 +00:00
uiWidgetType *wt = widget_type(UI_WTYPE_MENU_ITEM);
const rcti _rect = *rect;
const int row_height = BLI_rcti_size_y(rect);
int max_hint_width = INT_MAX;
int padding = 0.25f * row_height;
char *cpoin = NULL;
wt->state(wt, state, 0, UI_EMBOSS_UNDEFINED);
wt->draw(&wt->wcol, rect, 0, 0);
UI_fontstyle_set(fstyle);
/* text location offset */
rect->xmin += padding;
2019-03-25 10:15:20 +11:00
if (iconid) {
rect->xmin += row_height; /* Use square area for icon. */
2019-03-25 10:15:20 +11:00
}
/* cut string in 2 parts? */
if (separator_type != UI_MENU_ITEM_SEPARATOR_NONE) {
cpoin = strrchr(name, UI_SEP_CHAR);
if (cpoin) {
*cpoin = 0;
/* need to set this first */
UI_fontstyle_set(fstyle);
2019-03-25 10:15:20 +11:00
if (fstyle->kerning == 1) {
/* for BLF_width */
BLF_enable(fstyle->uifont_id, BLF_KERNING_DEFAULT);
}
if (separator_type == UI_MENU_ITEM_SEPARATOR_SHORTCUT) {
/* Shrink rect to exclude the shortcut string. */
rect->xmax -= BLF_width(fstyle->uifont_id, cpoin + 1, INT_MAX) + UI_DPI_ICON_SIZE;
}
else if (separator_type == UI_MENU_ITEM_SEPARATOR_HINT) {
/* Determine max-width for the hint string to leave the name string un-clipped (if there's
* enough space to display it). */
const int available_width = BLI_rcti_size_x(rect) - padding;
const int name_width = BLF_width(fstyle->uifont_id, name, INT_MAX);
const int hint_width = BLF_width(fstyle->uifont_id, cpoin + 1, INT_MAX) + padding;
if ((name_width + hint_width) > available_width) {
/* Clipping width for hint string. */
max_hint_width = available_width * 0.40f;
/* Clipping xmax for clipping of item name. */
rect->xmax = (hint_width < max_hint_width) ?
(rect->xmax - hint_width) :
(rect->xmin + (available_width - max_hint_width));
}
}
else {
BLI_assert(!"Unknwon menu item separator type");
}
if (fstyle->kerning == 1) {
BLF_disable(fstyle->uifont_id, BLF_KERNING_DEFAULT);
}
}
}
{
char drawstr[UI_MAX_DRAW_STR];
const float okwidth = (float)BLI_rcti_size_x(rect);
const size_t max_len = sizeof(drawstr);
const float minwidth = (float)(UI_DPI_ICON_SIZE);
BLI_strncpy(drawstr, name, sizeof(drawstr));
if (drawstr[0]) {
UI_text_clip_middle_ex(fstyle, drawstr, okwidth, minwidth, max_len, '\0');
}
int xofs = 0, yofs = 0;
struct ResultBLF info;
UI_fontstyle_draw_ex(fstyle,
rect,
drawstr,
wt->wcol.text,
&(struct uiFontStyleDraw_Params){
.align = UI_STYLE_TEXT_LEFT,
},
BLF_DRAW_STR_DUMMY_MAX,
&xofs,
&yofs,
&info);
if (r_xmax != NULL) {
*r_xmax = xofs + info.width;
}
}
/* restore rect, was messed with */
2012-03-30 01:51:25 +00:00
*rect = _rect;
if (iconid) {
Holiday coding log :) Nice formatted version (pictures soon): http://wiki.blender.org/index.php/Dev:Ref/Release_Notes/2.66/Usability Short list of main changes: - Transparent region option (over main region), added code to blend in/out such panels. - Min size window now 640 x 480 - Fixed DPI for ui - lots of cleanup and changes everywhere. Icon image need correct size still, layer-in-use icon needs remake. - Macbook retina support, use command line --no-native-pixels to disable it - Timeline Marker label was drawing wrong - Trackpad and magic mouse: supports zoom (hold ctrl) - Fix for splash position: removed ghost function and made window size update after creation immediate - Fast undo buffer save now adds UI as well. Could be checked for regular file save even... Quit.blend and temp file saving use this now. - Dixed filename in window on reading quit.blend or temp saves, and they now add a warning in window title: "(Recovered)" - New Userpref option "Keep Session" - this always saves quit.blend, and loads on start. This allows keeping UI and data without actual saves, until you actually save. When you load startup.blend and quit, it recognises the quit.blend as a startup (no file name in header) - Added 3D view copy/paste buffers (selected objects). Shortcuts ctrl-c, ctrl-v (OSX, cmd-c, cmd-v). Coded partial file saving for it. Could be used for other purposes. Todo: use OS clipboards. - User preferences (themes, keymaps, user settings) now can be saved as a separate file. Old option is called "Save Startup File" the new one "Save User Settings". To visualise this difference, the 'save startup file' button has been removed from user preferences window. That option is available as CTRL+U and in File menu still. - OSX: fixed bug that stopped giving mouse events outside window. This also fixes "Continuous Grab" for OSX. (error since 2009)
2012-12-12 18:58:11 +00:00
float height, aspect;
const int xs = rect->xmin + 0.2f * UI_UNIT_X;
const int ys = rect->ymin + 0.1f * BLI_rcti_size_y(rect);
height = ICON_SIZE_FROM_BUTRECT(rect);
Holiday coding log :) Nice formatted version (pictures soon): http://wiki.blender.org/index.php/Dev:Ref/Release_Notes/2.66/Usability Short list of main changes: - Transparent region option (over main region), added code to blend in/out such panels. - Min size window now 640 x 480 - Fixed DPI for ui - lots of cleanup and changes everywhere. Icon image need correct size still, layer-in-use icon needs remake. - Macbook retina support, use command line --no-native-pixels to disable it - Timeline Marker label was drawing wrong - Trackpad and magic mouse: supports zoom (hold ctrl) - Fix for splash position: removed ghost function and made window size update after creation immediate - Fast undo buffer save now adds UI as well. Could be checked for regular file save even... Quit.blend and temp file saving use this now. - Dixed filename in window on reading quit.blend or temp saves, and they now add a warning in window title: "(Recovered)" - New Userpref option "Keep Session" - this always saves quit.blend, and loads on start. This allows keeping UI and data without actual saves, until you actually save. When you load startup.blend and quit, it recognises the quit.blend as a startup (no file name in header) - Added 3D view copy/paste buffers (selected objects). Shortcuts ctrl-c, ctrl-v (OSX, cmd-c, cmd-v). Coded partial file saving for it. Could be used for other purposes. Todo: use OS clipboards. - User preferences (themes, keymaps, user settings) now can be saved as a separate file. Old option is called "Save Startup File" the new one "Save User Settings". To visualise this difference, the 'save startup file' button has been removed from user preferences window. That option is available as CTRL+U and in File menu still. - OSX: fixed bug that stopped giving mouse events outside window. This also fixes "Continuous Grab" for OSX. (error since 2009)
2012-12-12 18:58:11 +00:00
aspect = ICON_DEFAULT_HEIGHT / height;
GPU_blend(GPU_BLEND_ALPHA);
/* XXX scale weak get from fstyle? */
UI_icon_draw_ex(xs, ys, iconid, aspect, 1.0f, 0.0f, wt->wcol.text, false);
GPU_blend(GPU_BLEND_NONE);
}
/* part text right aligned */
if (separator_type != UI_MENU_ITEM_SEPARATOR_NONE) {
if (cpoin) {
/* Set inactive state for grayed out text. */
wt->state(wt, state | UI_BUT_INACTIVE, 0, UI_EMBOSS_UNDEFINED);
char hint_drawstr[UI_MAX_DRAW_STR];
{
const size_t max_len = sizeof(hint_drawstr);
const float minwidth = (float)(UI_DPI_ICON_SIZE);
BLI_strncpy(hint_drawstr, cpoin + 1, sizeof(hint_drawstr));
if (hint_drawstr[0] && (max_hint_width < INT_MAX)) {
UI_text_clip_middle_ex(fstyle, hint_drawstr, max_hint_width, minwidth, max_len, '\0');
}
}
rect->xmax = _rect.xmax - 5;
UI_fontstyle_draw(fstyle,
rect,
hint_drawstr,
wt->wcol.text,
&(struct uiFontStyleDraw_Params){
.align = UI_STYLE_TEXT_RIGHT,
});
*cpoin = UI_SEP_CHAR;
}
}
}
void ui_draw_preview_item(
const uiFontStyle *fstyle, rcti *rect, const char *name, int iconid, int state)
{
rcti trect = *rect;
const float text_size = UI_UNIT_Y;
float font_dims[2] = {0.0f, 0.0f};
2012-03-30 01:51:25 +00:00
uiWidgetType *wt = widget_type(UI_WTYPE_MENU_ITEM);
/* drawing button background */
wt->state(wt, state, 0, UI_EMBOSS_UNDEFINED);
wt->draw(&wt->wcol, rect, 0, 0);
/* draw icon in rect above the space reserved for the label */
rect->ymin += text_size;
GPU_blend(GPU_BLEND_ALPHA);
widget_draw_preview(iconid, 1.0f, rect);
GPU_blend(GPU_BLEND_NONE);
BLF_width_and_height(
fstyle->uifont_id, name, 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];
2019-03-25 10:15:20 +11:00
if (trect.xmax > rect->xmax - PREVIEW_PAD) {
trect.xmax = rect->xmax - PREVIEW_PAD;
2019-03-25 10:15:20 +11:00
}
{
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, name, sizeof(drawstr));
UI_text_clip_middle_ex(fstyle, drawstr, okwidth, minwidth, max_len, '\0');
UI_fontstyle_draw(fstyle,
&trect,
drawstr,
wt->wcol.text,
&(struct uiFontStyleDraw_Params){
.align = UI_STYLE_TEXT_CENTER,
});
}
}
/** \} */