UI: Color Icon Theme Internal Parts #125146
@ -1 +1 @@
|
||||
<svg id="svg2" height="1200" viewBox="0 0 1200 1200" width="1200" xmlns="http://www.w3.org/2000/svg" xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"><sodipodi:namedview pagecolor="#303030" showgrid="true"><inkscape:grid id="grid5" units="px" spacingx="100" spacingy="100" color="#4772b3" opacity="0.2" visible="true" /></sodipodi:namedview><path id="path1" d="m286 622c-2.7555 0-5 2.2445-5 5s2.2445 5 5 5 5-2.2445 5-5-2.2445-5-5-5z" fill="#fff" transform="matrix(100 0 0 100 -27999.994 -62100)"/></svg>
|
||||
<svg id="svg2" height="1200" viewBox="0 0 1200 1200" width="1200" xmlns="http://www.w3.org/2000/svg" xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"><sodipodi:namedview pagecolor="#303030" showgrid="true"><inkscape:grid id="grid5" units="px" spacingx="100" spacingy="100" color="#4772b3" opacity="0.2" visible="true" /></sodipodi:namedview><g><g id="blender.red_alert" fill="#ffffff" transform="matrix(1 0 0 .99407813 0 5.93843)"><path id="path1" d="m599.97471 191.39126c-220.28631 0-403.19327 185.73026-403.19327 406.16752 0 229.42349 172.48512 404.04942 403.19327 404.04942 230.70813 0 401.14369-178.37144 401.89049-404.04942.7445-224.93037-181.60419-406.16752-401.89049-406.16752z" stroke-width="79.9717"/></g><g id="blender.text" fill="#ffffff" opacity=".8"><path id="path1-1" d="m599.88703 100.19229c-275.55 0-499.81389 224.2639-499.81389 499.8139s224.26389 499.81391 499.81389 499.81391 499.81387-224.45002 499.81387-500.00002-224.26387-499.62779-499.81387-499.62779zm0 99.62779c221.506 0 400.18607 178.68011 400.18607 400.18611s-178.68007 400.18611-400.18607 400.18611-400.55831-175.88855-400.55831-397.39455 179.05231-402.97767 400.55831-402.97767z" stroke-width="100"/></g></g></svg>
|
Before Width: | Height: | Size: 583 B After Width: | Height: | Size: 1.2 KiB |
@ -11,6 +11,7 @@
|
||||
#include "BLI_array.hh"
|
||||
#include "BLI_bounds_types.hh"
|
||||
#include "BLI_compiler_attrs.h"
|
||||
#include "BLI_function_ref.hh"
|
||||
#include "BLI_string_ref.hh"
|
||||
#include "BLI_sys_types.h"
|
||||
#include "BLI_vector.hh"
|
||||
@ -152,7 +153,8 @@ void BLF_draw_svg_icon(uint icon_id,
|
||||
float size,
|
||||
float color[4] = nullptr,
|
||||
float outline_alpha = 1.0f,
|
||||
bool multicolor = false);
|
||||
bool multicolor = false,
|
||||
blender::FunctionRef<void(std::string &)> edit_source_cb = nullptr);
|
||||
|
||||
blender::Array<uchar> BLF_svg_icon_bitmap(
|
||||
uint icon_id, float size, int *r_width, int *r_height, bool multicolor = false);
|
||||
|
@ -615,7 +615,8 @@ void BLF_draw_svg_icon(uint icon_id,
|
||||
float size,
|
||||
float color[4],
|
||||
float outline_alpha,
|
||||
bool multicolor)
|
||||
bool multicolor,
|
||||
blender::FunctionRef<void(std::string &)> edit_source_cb)
|
||||
{
|
||||
#ifndef WITH_HEADLESS
|
||||
FontBLF *font = global_font[0];
|
||||
@ -623,11 +624,11 @@ void BLF_draw_svg_icon(uint icon_id,
|
||||
/* Avoid bgl usage to corrupt BLF drawing. */
|
||||
GPU_bgl_end();
|
||||
blf_draw_gpu__start(font);
|
||||
blf_draw_svg_icon(font, icon_id, x, y, size, color, outline_alpha, multicolor);
|
||||
blf_draw_svg_icon(font, icon_id, x, y, size, color, outline_alpha, multicolor, edit_source_cb);
|
||||
blf_draw_gpu__end(font);
|
||||
}
|
||||
#else
|
||||
UNUSED_VARS(icon_id, x, y, size, color, outline_alpha, multicolor);
|
||||
UNUSED_VARS(icon_id, x, y, size, color, outline_alpha, multicolor, edit_source_cb);
|
||||
#endif /* WITH_HEADLESS */
|
||||
}
|
||||
|
||||
|
@ -532,7 +532,8 @@ void blf_draw_svg_icon(FontBLF *font,
|
||||
float size,
|
||||
float color[4],
|
||||
float outline_alpha,
|
||||
bool multicolor)
|
||||
bool multicolor,
|
||||
blender::FunctionRef<void(std::string &)> edit_source_cb)
|
||||
{
|
||||
blf_font_size(font, size);
|
||||
font->pos[0] = int(x);
|
||||
@ -557,7 +558,7 @@ void blf_draw_svg_icon(FontBLF *font,
|
||||
GlyphCacheBLF *gc = blf_glyph_cache_acquire(font);
|
||||
blf_batch_draw_begin(font);
|
||||
|
||||
GlyphBLF *g = blf_glyph_ensure_icon(gc, icon_id, multicolor);
|
||||
GlyphBLF *g = blf_glyph_ensure_icon(gc, icon_id, multicolor, edit_source_cb);
|
||||
if (g) {
|
||||
blf_glyph_draw(font, gc, g, 0, 0);
|
||||
}
|
||||
|
@ -352,13 +352,18 @@ static GlyphBLF *blf_glyph_cache_add_blank(GlyphCacheBLF *gc, uint charcode)
|
||||
return result;
|
||||
}
|
||||
|
||||
static GlyphBLF *blf_glyph_cache_add_svg(GlyphCacheBLF *gc, uint charcode, bool color)
|
||||
static GlyphBLF *blf_glyph_cache_add_svg(
|
||||
GlyphCacheBLF *gc,
|
||||
uint charcode,
|
||||
bool color,
|
||||
blender::FunctionRef<void(std::string &)> edit_source_cb = nullptr)
|
||||
{
|
||||
const char *svg_source = blf_get_icon_svg(int(charcode) - BLF_ICON_OFFSET);
|
||||
/* NanoSVG alters the source file while parsing. */
|
||||
char *writeable = BLI_strdup(svg_source);
|
||||
NSVGimage *image = nsvgParse(writeable, "px", 96.0f);
|
||||
MEM_freeN(writeable);
|
||||
std::string svg_source = blf_get_icon_svg(int(charcode) - BLF_ICON_OFFSET);
|
||||
if (edit_source_cb) {
|
||||
edit_source_cb(svg_source);
|
||||
}
|
||||
|
||||
NSVGimage *image = nsvgParse(svg_source.data(), "px", 96.0f);
|
||||
|
||||
if (image == nullptr) {
|
||||
return blf_glyph_cache_add_blank(gc, charcode);
|
||||
@ -1393,13 +1398,16 @@ GlyphBLF *blf_glyph_ensure(FontBLF *font, GlyphCacheBLF *gc, const uint charcode
|
||||
}
|
||||
|
||||
#ifndef WITH_HEADLESS
|
||||
GlyphBLF *blf_glyph_ensure_icon(GlyphCacheBLF *gc, const uint icon_id, bool color)
|
||||
GlyphBLF *blf_glyph_ensure_icon(GlyphCacheBLF *gc,
|
||||
const uint icon_id,
|
||||
bool color,
|
||||
blender::FunctionRef<void(std::string &)> edit_source_cb)
|
||||
{
|
||||
GlyphBLF *g = blf_glyph_cache_find_glyph(gc, icon_id + BLF_ICON_OFFSET, 0);
|
||||
if (g) {
|
||||
return g;
|
||||
}
|
||||
return blf_glyph_cache_add_svg(gc, icon_id + BLF_ICON_OFFSET, color);
|
||||
return blf_glyph_cache_add_svg(gc, icon_id + BLF_ICON_OFFSET, color, edit_source_cb);
|
||||
}
|
||||
#endif /* WITH_HEADLESS */
|
||||
|
||||
|
@ -10,6 +10,7 @@
|
||||
|
||||
#include "BLI_array.hh"
|
||||
#include "BLI_bounds_types.hh"
|
||||
#include "BLI_function_ref.hh"
|
||||
#include "BLI_string_ref.hh"
|
||||
#include "BLI_vector.hh"
|
||||
|
||||
@ -107,7 +108,8 @@ void blf_draw_svg_icon(FontBLF *font,
|
||||
float size,
|
||||
float color[4] = nullptr,
|
||||
float outline_alpha = 1.0f,
|
||||
bool multicolor = false);
|
||||
bool multicolor = false,
|
||||
blender::FunctionRef<void(std::string &)> edit_source_cb = nullptr);
|
||||
|
||||
Harley marked this conversation as resolved
Outdated
|
||||
blender::Array<uchar> blf_svg_icon_bitmap(
|
||||
FontBLF *font, uint icon_id, float size, int *r_width, int *r_height, bool multicolor = false);
|
||||
@ -185,7 +187,11 @@ GlyphBLF *blf_glyph_ensure(FontBLF *font, GlyphCacheBLF *gc, uint charcode, uint
|
||||
GlyphBLF *blf_glyph_ensure_subpixel(FontBLF *font, GlyphCacheBLF *gc, GlyphBLF *g, int32_t pen_x);
|
||||
#endif
|
||||
|
||||
GlyphBLF *blf_glyph_ensure_icon(GlyphCacheBLF *gc, uint icon_id, bool color = false);
|
||||
GlyphBLF *blf_glyph_ensure_icon(
|
||||
GlyphCacheBLF *gc,
|
||||
uint icon_id,
|
||||
bool color = false,
|
||||
blender::FunctionRef<void(std::string &)> edit_source_cb = nullptr);
|
||||
|
||||
/**
|
||||
* Convert a character's outlines into curves.
|
||||
|
@ -49,6 +49,8 @@
|
||||
|
||||
#include "interface_intern.hh"
|
||||
|
||||
#include "fmt/format.h"
|
||||
|
||||
struct IconImage {
|
||||
int w;
|
||||
int h;
|
||||
@ -1295,6 +1297,155 @@ static int get_draw_size(enum eIconSizes size)
|
||||
}
|
||||
}
|
||||
|
||||
static void svg_replace_color_attributes(std::string &svg,
|
||||
const std::string &name,
|
||||
Harley marked this conversation as resolved
Outdated
Hans Goudey
commented
Pass Generally I'm a bit concerned by the performance of this function when it starts acting on thousands of icons. There are a lot of incremental updates to the text, and then it's called once for every theme color. I don't want to get in the way or request premature optimizations, but I'd just suggest keeping an eye on this as more SVG icons are processed with this function. It shouldn't have an impact on startup time for example. Pass `std::string` by const reference rather than by value.
Generally I'm a bit concerned by the performance of this function when it starts acting on thousands of icons. There are a lot of incremental updates to the text, and then it's called once for every theme color.
I don't want to get in the way or request premature optimizations, but I'd just suggest keeping an eye on this as more SVG icons are processed with this function. It shouldn't have an impact on startup time for example.
Harley Acheson
commented
Agreed. I'll add a "Todo" comment to Agreed. I'll add a "Todo" comment to `icon_source_edit_cb` indicating that this text processing is suboptimal with all the inserts and has lots of room for optimization.
Harley Acheson
commented
Actually re-wrote that section so the processing is done by scanning the string by group, only for those that start with "blender." Actually re-wrote that section so the processing is done by scanning the string by group, only for those that start with "blender."
|
||||
const size_t start,
|
||||
const size_t end)
|
||||
{
|
||||
bTheme *btheme = UI_GetTheme();
|
||||
|
||||
uchar white[] = {255, 255, 255, 255};
|
||||
uchar black[] = {0, 0, 0, 255};
|
||||
uchar logo_orange[] = {232, 125, 13, 255};
|
||||
uchar logo_blue[] = {38, 87, 135, 255};
|
||||
|
||||
/* Tool colors hardcoded for now. */
|
||||
uchar tool_add[] = {117, 255, 175, 255};
|
||||
uchar tool_remove[] = {245, 107, 91, 255};
|
||||
uchar tool_select[] = {255, 176, 43, 255};
|
||||
uchar tool_transform[] = {217, 175, 245, 255};
|
||||
uchar tool_white[] = {255, 255, 255, 255};
|
||||
uchar tool_red[] = {214, 45, 48, 255};
|
||||
|
||||
struct ColorItem {
|
||||
const char *name;
|
||||
uchar *col = nullptr;
|
||||
int colorid = TH_UNDEFINED;
|
||||
int spacetype = SPACE_TYPE_ANY;
|
||||
} items[] = {
|
||||
{"blender.white", white},
|
||||
{"blender.black", black},
|
||||
{"blender.logo_orange", logo_orange},
|
||||
{"blender.logo_blue", logo_blue},
|
||||
{"blender.selected", btheme->tui.wcol_regular.inner},
|
||||
{"blender.mesh_selected", btheme->space_view3d.vertex_select},
|
||||
{"blender.back", nullptr, TH_BACK},
|
||||
{"blender.text", nullptr, TH_TEXT},
|
||||
{"blender.text_hi", nullptr, TH_TEXT_HI},
|
||||
{"blender.red_alert", nullptr, TH_REDALERT},
|
||||
{"blender.error", nullptr, TH_INFO_ERROR, SPACE_INFO},
|
||||
{"blender.warning", nullptr, TH_INFO_WARNING, SPACE_INFO},
|
||||
{"blender.info", nullptr, TH_INFO_INFO, SPACE_INFO},
|
||||
{"blender.scene", nullptr, TH_ICON_SCENE},
|
||||
Harley marked this conversation as resolved
Outdated
Hans Goudey
commented
Why not just Why not just `name != item.name`?
|
||||
{"blender.collection", nullptr, TH_ICON_COLLECTION},
|
||||
{"blender.object", nullptr, TH_ICON_OBJECT},
|
||||
{"blender.object_data", nullptr, TH_ICON_OBJECT_DATA},
|
||||
{"blender.modifier", nullptr, TH_ICON_MODIFIER},
|
||||
{"blender.shading", nullptr, TH_ICON_SHADING},
|
||||
{"blender.folder", nullptr, TH_ICON_FOLDER},
|
||||
{"blender.fund", nullptr, TH_ICON_FUND},
|
||||
{"blender.tool_add", tool_add},
|
||||
{"blender.tool_remove", tool_remove},
|
||||
{"blender.tool_select", tool_select},
|
||||
{"blender.tool_transform", tool_transform},
|
||||
{"blender.tool_white", tool_white},
|
||||
{"blender.tool_red", tool_red},
|
||||
};
|
||||
|
||||
for (const ColorItem &item : items) {
|
||||
if (name != item.name) {
|
||||
continue;
|
||||
}
|
||||
|
||||
uchar color[4];
|
||||
if (item.col) {
|
||||
memcpy(color, item.col, sizeof(color));
|
||||
}
|
||||
else if (item.colorid != TH_UNDEFINED) {
|
||||
if (item.spacetype != SPACE_TYPE_ANY) {
|
||||
UI_GetThemeColorType4ubv(item.colorid, item.spacetype, color);
|
||||
}
|
||||
else {
|
||||
Harley marked this conversation as resolved
Outdated
Hans Goudey
commented
These numbers 6, 20, 14, 16, should come from somewhere. I imagine they're the length of some string? Probably better to compute it at compile time then. For example with These numbers 6, 20, 14, 16, should come from somewhere. I imagine they're the length of some string? Probably better to compute it at compile time then. For example with `StringRef::size()`.
|
||||
UI_GetThemeColor4ubv(item.colorid, color);
|
||||
}
|
||||
}
|
||||
else {
|
||||
continue;
|
||||
}
|
||||
|
||||
std::string hexcolor = fmt::format(
|
||||
"{:02x}{:02x}{:02x}{:02x}", color[0], color[1], color[2], color[3]);
|
||||
|
||||
size_t att_start = start;
|
||||
while (1) {
|
||||
constexpr static blender::StringRef key = "fill=\"";
|
||||
att_start = svg.find(key, att_start);
|
||||
if (att_start == std::string::npos || att_start > end) {
|
||||
break;
|
||||
}
|
||||
const size_t att_end = svg.find("\"", att_start + key.size());
|
||||
if (att_end != std::string::npos && att_end < end) {
|
||||
svg.replace(att_start, att_end - att_start, key + "#" + hexcolor);
|
||||
}
|
||||
att_start += blender::StringRef(key + "#rrggbbaa\"").size();
|
||||
}
|
||||
|
||||
att_start = start;
|
||||
while (1) {
|
||||
constexpr static blender::StringRef key = "fill:";
|
||||
att_start = svg.find(key, att_start);
|
||||
if (att_start == std::string::npos || att_start > end) {
|
||||
break;
|
||||
}
|
||||
const size_t att_end = svg.find(";", att_start + key.size());
|
||||
if (att_end != std::string::npos && att_end - att_start < end) {
|
||||
svg.replace(att_start, att_end - att_start, key + "#" + hexcolor);
|
||||
}
|
||||
att_start += blender::StringRef(key + "#rrggbbaa").size();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void icon_source_edit_cb(std::string &svg)
|
||||
{
|
||||
size_t g_start = 0;
|
||||
|
||||
/* Scan string, processing only groups with our keyword ids. */
|
||||
|
||||
while (1) {
|
||||
/* Look for a blender id, quick exit if not found. */
|
||||
constexpr static blender::StringRef key = "id=\"";
|
||||
const size_t id_start = svg.find(key + "blender.", g_start);
|
||||
if (id_start == std::string::npos) {
|
||||
return;
|
||||
}
|
||||
|
||||
/* Scan back to beginning of this group element. */
|
||||
g_start = svg.rfind("<g", id_start);
|
||||
if (g_start == std::string::npos) {
|
||||
/* Malformed. */
|
||||
return;
|
||||
}
|
||||
|
||||
/* Scan forward to end of the group. */
|
||||
const size_t g_end = svg.find("</g>", id_start);
|
||||
if (g_end == std::string::npos) {
|
||||
/* Malformed. */
|
||||
return;
|
||||
}
|
||||
|
||||
/* Get group id name. */
|
||||
const size_t id_end = svg.find("\"", id_start + key.size());
|
||||
if (id_end != std::string::npos) {
|
||||
std::string id_name = svg.substr(id_start + key.size(), id_end - id_start - key.size());
|
||||
/* Replace this group's colors. */
|
||||
svg_replace_color_attributes(svg, id_name, g_start, g_end);
|
||||
}
|
||||
|
||||
g_start = g_end;
|
||||
}
|
||||
}
|
||||
|
||||
static void icon_draw_size(float x,
|
||||
float y,
|
||||
int icon_id,
|
||||
@ -1398,13 +1549,27 @@ static void icon_draw_size(float x,
|
||||
}
|
||||
|
||||
color[3] *= alpha;
|
||||
BLF_draw_svg_icon(uint(icon_id),
|
||||
x,
|
||||
y,
|
||||
float(draw_size) / aspect,
|
||||
color,
|
||||
outline_intensity,
|
||||
di->type == ICON_TYPE_SVG_COLOR);
|
||||
|
||||
if (di->type == ICON_TYPE_SVG_COLOR) {
|
||||
BLF_draw_svg_icon(uint(icon_id),
|
||||
x,
|
||||
y,
|
||||
float(draw_size) / aspect,
|
||||
color,
|
||||
outline_intensity,
|
||||
true,
|
||||
icon_source_edit_cb);
|
||||
}
|
||||
else {
|
||||
BLF_draw_svg_icon(uint(icon_id),
|
||||
x,
|
||||
y,
|
||||
float(draw_size) / aspect,
|
||||
color,
|
||||
outline_intensity,
|
||||
false,
|
||||
nullptr);
|
||||
}
|
||||
|
||||
if (text_overlay && text_overlay->text[0] != '\0') {
|
||||
/* Handle the little numbers on top of the icon. */
|
||||
|
FunctionRef
would be a better fit here.std::function
is only used when it needs to own data (i.e. the function is passed around and saved for later).