Skip to content

Commit

Permalink
Add ability to specify font scale for RichTextLabel
Browse files Browse the repository at this point in the history
Also fixes godotengine#5557.
  • Loading branch information
eligt committed Dec 25, 2019
1 parent d711c57 commit 60cf7dc
Show file tree
Hide file tree
Showing 7 changed files with 130 additions and 52 deletions.
6 changes: 3 additions & 3 deletions editor/editor_help.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -508,6 +508,9 @@ void EditorHelp::_update_doc() {

_add_text(cd.properties[i].name);

class_desc->pop();
class_desc->pop();

if (describe) {
class_desc->pop();
property_descr = true;
Expand All @@ -525,9 +528,6 @@ void EditorHelp::_update_doc() {
class_desc->pop();
}

class_desc->pop();
class_desc->pop();

class_desc->pop();
}

Expand Down
112 changes: 85 additions & 27 deletions scene/gui/rich_text_label.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
/*************************************************************************/
/*************************************************************************/
/* rich_text_label.cpp */
/*************************************************************************/
/* This file is part of: */
Expand Down Expand Up @@ -194,10 +194,11 @@ int RichTextLabel::_process_line(ItemFrame *p_frame, const Vector2 &p_ofs, int &
if (cfont.is_null())
cfont = p_base_font;

real_t cfont_scale = _find_font_scale(it);
//line height should be the font height for the first time, this ensures that an empty line will never have zero height and successive newlines are displayed
int line_height = cfont->get_height();
int line_ascent = cfont->get_ascent();
int line_descent = cfont->get_descent();
int line_height = cfont->get_height() * cfont_scale;
int line_ascent = cfont->get_ascent() * cfont_scale;
int line_descent = cfont->get_descent() * cfont_scale;

int nonblank_line_count = 0; //number of nonblank lines as counted during PROCESS_DRAW

Expand Down Expand Up @@ -230,6 +231,7 @@ int RichTextLabel::_process_line(ItemFrame *p_frame, const Vector2 &p_ofs, int &
l.ascent_caches.push_back(line_ascent); \
l.descent_caches.push_back(line_descent); \
l.space_caches.push_back(spaces); \
wofs = begin; \
} \
line_wrapped = false; \
y += line_height + get_constant(SceneStringNames::get_singleton()->line_separation); \
Expand All @@ -238,7 +240,6 @@ int RichTextLabel::_process_line(ItemFrame *p_frame, const Vector2 &p_ofs, int &
line_descent = 0; \
spaces = 0; \
spaces_size = 0; \
wofs = begin; \
align_ofs = 0; \
if (p_mode != PROCESS_CACHE) { \
lh = line < l.height_caches.size() ? l.height_caches[line] : 1; \
Expand Down Expand Up @@ -322,7 +323,13 @@ int RichTextLabel::_process_line(ItemFrame *p_frame, const Vector2 &p_ofs, int &
if (it != l.from) {
ItemIndent *indent_it = static_cast<ItemIndent *>(it);

int indent = indent_it->level * tab_size * cfont->get_char_size(' ').width;
Ref<Font> font = _find_font(it);
if (font.is_null())
font = p_base_font;

real_t font_scale = _find_font_scale(it);

int indent = indent_it->level * tab_size * Math::round(cfont->get_char_size(' ').width * font_scale);
margin += indent;
begin += indent;
wofs += indent;
Expand All @@ -337,10 +344,11 @@ int RichTextLabel::_process_line(ItemFrame *p_frame, const Vector2 &p_ofs, int &
if (font.is_null())
font = p_base_font;

real_t font_scale = _find_font_scale(it);
const CharType *c = text->text.c_str();
const CharType *cf = c;
int ascent = font->get_ascent();
int descent = font->get_descent();
int ascent = Math::round(font->get_ascent() * font_scale);
int descent = Math::round(font->get_descent() * font_scale);

Color color;
Color font_color_shadow;
Expand Down Expand Up @@ -391,9 +399,9 @@ int RichTextLabel::_process_line(ItemFrame *p_frame, const Vector2 &p_ofs, int &
}
while (c[end] != 0 && !(end && c[end - 1] == ' ' && c[end] != ' ')) {

int cw = font->get_char_size(c[end], c[end + 1]).width;
int cw = Math::round(font->get_char_size(c[end], c[end + 1]).width * font_scale);
if (c[end] == '\t') {
cw = tab_size * font->get_char_size(' ').width;
cw = Math::round(tab_size * font->get_char_size(' ').width * font_scale);
}

if (end > 0 && w + cw + begin > p_width) {
Expand All @@ -414,7 +422,7 @@ int RichTextLabel::_process_line(ItemFrame *p_frame, const Vector2 &p_ofs, int &

if (end && c[end - 1] == ' ') {
if (p_mode == PROCESS_CACHE) {
spaces_size += font->get_char_size(' ').width;
spaces_size += Math::round(font->get_char_size(' ').width * font_scale);
} else if (align == ALIGN_FILL) {
int ln = MIN(l.offset_caches.size() - 1, line);
if (l.space_caches[ln]) {
Expand All @@ -434,10 +442,10 @@ int RichTextLabel::_process_line(ItemFrame *p_frame, const Vector2 &p_ofs, int &
if (p_mode == PROCESS_POINTER && r_click_char && p_click_pos.y >= p_ofs.y + y && p_click_pos.y <= p_ofs.y + y + lh) {
//int o = (wofs+w)-p_click_pos.x;

int cw = font->get_char_size(c[i], c[i + 1]).x;
int cw = Math::round(font->get_char_size(c[i], c[i + 1]).x * font_scale);

if (c[i] == '\t') {
cw = tab_size * font->get_char_size(' ').width;
cw = tab_size * Math::round(font->get_char_size(' ').width * font_scale);
}

if (p_click_pos.x - cw / 2 > p_ofs.x + align_ofs + pofs) {
Expand Down Expand Up @@ -548,32 +556,32 @@ int RichTextLabel::_process_line(ItemFrame *p_frame, const Vector2 &p_ofs, int &
if (visible) {

if (selected) {
cw = font->get_char_size(fx_char, c[i + 1]).x;
cw = font->get_char_size(fx_char, c[i + 1]).x * font_scale;
draw_rect(Rect2(p_ofs.x + pofs, p_ofs.y + y, cw, lh), selection_bg);
}

if (p_font_color_shadow.a > 0) {
float x_ofs_shadow = align_ofs + pofs;
float y_ofs_shadow = y + lh - line_descent;
font->draw_char(ci, Point2(x_ofs_shadow, y_ofs_shadow) + shadow_ofs + fx_offset, fx_char, c[i + 1], p_font_color_shadow);
font->draw_char_scaled(ci, Point2(x_ofs_shadow, y_ofs_shadow) + shadow_ofs + fx_offset, font_scale, fx_char, c[i + 1], p_font_color_shadow);

if (p_shadow_as_outline) {
font->draw_char(ci, Point2(x_ofs_shadow, y_ofs_shadow) + Vector2(-shadow_ofs.x, shadow_ofs.y) + fx_offset, fx_char, c[i + 1], p_font_color_shadow);
font->draw_char(ci, Point2(x_ofs_shadow, y_ofs_shadow) + Vector2(shadow_ofs.x, -shadow_ofs.y) + fx_offset, fx_char, c[i + 1], p_font_color_shadow);
font->draw_char(ci, Point2(x_ofs_shadow, y_ofs_shadow) + Vector2(-shadow_ofs.x, -shadow_ofs.y) + fx_offset, fx_char, c[i + 1], p_font_color_shadow);
font->draw_char_scaled(ci, Point2(x_ofs_shadow, y_ofs_shadow) + Vector2(-shadow_ofs.x, shadow_ofs.y) + fx_offset, font_scale, fx_char, c[i + 1], p_font_color_shadow);
font->draw_char_scaled(ci, Point2(x_ofs_shadow, y_ofs_shadow) + Vector2(shadow_ofs.x, -shadow_ofs.y) + fx_offset, font_scale, fx_char, c[i + 1], p_font_color_shadow);
font->draw_char_scaled(ci, Point2(x_ofs_shadow, y_ofs_shadow) + Vector2(-shadow_ofs.x, -shadow_ofs.y) + fx_offset, font_scale, fx_char, c[i + 1], p_font_color_shadow);
}
}

if (selected) {
drawer.draw_char(ci, p_ofs + Point2(align_ofs + pofs, y + lh - line_descent), fx_char, c[i + 1], override_selected_font_color ? selection_fg : fx_color);
drawer.draw_char_scaled(ci, p_ofs + Point2(align_ofs + pofs, y + lh - line_descent), font_scale, fx_char, c[i + 1], override_selected_font_color ? selection_fg : fx_color);
} else {
cw = drawer.draw_char(ci, p_ofs + Point2(align_ofs + pofs, y + lh - line_descent) + fx_offset, fx_char, c[i + 1], fx_color);
cw = drawer.draw_char_scaled(ci, p_ofs + Point2(align_ofs + pofs, y + lh - line_descent) + fx_offset, font_scale, fx_char, c[i + 1], fx_color);
}
}

p_char_count++;
if (c[i] == '\t') {
cw = tab_size * font->get_char_size(' ').width;
cw = tab_size * Math::round(font->get_char_size(' ').width * font_scale);
}

ofs += cw;
Expand Down Expand Up @@ -621,22 +629,25 @@ int RichTextLabel::_process_line(ItemFrame *p_frame, const Vector2 &p_ofs, int &
if (font.is_null())
font = p_base_font;

real_t font_scale = _find_font_scale(it);

if (p_mode == PROCESS_POINTER && r_click_char)
*r_click_char = 0;

ENSURE_WIDTH(img->size.width);

bool visible = visible_characters < 0 || (p_char_count < visible_characters && YRANGE_VISIBLE(y + lh - font->get_descent() - img->size.height, img->size.height));
bool visible = visible_characters < 0 || (p_char_count < visible_characters && YRANGE_VISIBLE(y + lh - Math::round(font->get_descent() * font_scale) - img->size.height, img->size.height));

if (visible)
line_is_blank = false;

if (p_mode == PROCESS_DRAW && visible) {
img->image->draw_rect(ci, Rect2(p_ofs + Point2(align_ofs + wofs, y + lh - font->get_descent() - img->size.height), img->size));
img->image->draw_rect(ci, Rect2(p_ofs + Point2(align_ofs + wofs, y + lh - Math::round(font->get_descent() * font_scale) - img->size.height), img->size));
}
p_char_count++;

ADVANCE(img->size.width);
CHECK_HEIGHT((img->size.height + font->get_descent()));
CHECK_HEIGHT((img->size.height + Math::round(font->get_descent() * font_scale)));

} break;
case ITEM_NEWLINE: {
Expand Down Expand Up @@ -1316,6 +1327,24 @@ Ref<Font> RichTextLabel::_find_font(Item *p_item) {
return Ref<Font>();
}

real_t RichTextLabel::_find_font_scale(Item *p_item) {

Item *sizeitem = p_item;

while (sizeitem) {

if (sizeitem->type == ITEM_FONT_SCALE) {

ItemScaleFont *fi = static_cast<ItemScaleFont *>(sizeitem);
return fi->scale;
}

sizeitem = sizeitem->parent;
}

return 0;
}

int RichTextLabel::_find_margin(Item *p_item, const Ref<Font> &p_base_font) {

Item *item = p_item;
Expand All @@ -1330,9 +1359,11 @@ int RichTextLabel::_find_margin(Item *p_item, const Ref<Font> &p_base_font) {
if (font.is_null())
font = p_base_font;

real_t font_scale = _find_font_scale(item);

ItemIndent *indent = static_cast<ItemIndent *>(item);

margin += indent->level * tab_size * font->get_char_size(' ').width;
margin += indent->level * tab_size * Math::round(font->get_char_size(' ').width * font_scale);

} else if (item->type == ITEM_LIST) {

Expand Down Expand Up @@ -1467,7 +1498,7 @@ bool RichTextLabel::_find_meta(Item *p_item, Variant *r_meta, ItemMeta **r_item)
bool RichTextLabel::_find_layout_subitem(Item *from, Item *to) {

if (from && from != to) {
if (from->type != ITEM_FONT && from->type != ITEM_COLOR && from->type != ITEM_UNDERLINE && from->type != ITEM_STRIKETHROUGH)
if (from->type != ITEM_FONT && from->type != ITEM_FONT_SCALE && from->type != ITEM_COLOR && from->type != ITEM_UNDERLINE && from->type != ITEM_STRIKETHROUGH)
return true;

for (List<Item *>::Element *E = from->subitems.front(); E; E = E->next()) {
Expand Down Expand Up @@ -1724,6 +1755,16 @@ void RichTextLabel::push_font(const Ref<Font> &p_font) {
_add_item(item, true);
}

void RichTextLabel::push_font_scale(real_t scale) {

ERR_FAIL_COND(current->type == ITEM_TABLE);
ERR_FAIL_COND(scale <= 0);
ItemScaleFont *item = memnew(ItemScaleFont);

item->scale = scale;
_add_item(item, true);
}

void RichTextLabel::push_normal() {
Ref<Font> normal_font = get_font("normal_font");
ERR_FAIL_COND(normal_font.is_null());
Expand Down Expand Up @@ -2281,6 +2322,16 @@ Error RichTextLabel::append_bbcode(const String &p_bbcode) {
pos = brk_end + 1;
tag_stack.push_front("font");

} else if (tag.begins_with("font_scale=")) {

float size = tag.substr(11, tag.length()).to_float();

if (size > 0)
push_font_scale(size);

pos = brk_end + 1;
tag_stack.push_front("font_scale");

} else if (tag.begins_with("fade")) {
Vector<String> tags = tag.split(" ", false);
int startIndex = 0;
Expand Down Expand Up @@ -2485,7 +2536,13 @@ bool RichTextLabel::search(const String &p_string, bool p_from_selection, bool p

_validate_line_caches(main);

int fh = _find_font(t).is_valid() ? _find_font(t)->get_height() : get_font("normal_font")->get_height();
Ref<Font> font = _find_font(t);
if (!font.is_valid())
font = get_font("normal_font");

real_t font_scale = _find_font_scale(it);

int fh = Math::round(font->get_height() * font_scale);

float offset = 0;

Expand Down Expand Up @@ -2780,6 +2837,7 @@ void RichTextLabel::_bind_methods() {
BIND_ENUM_CONSTANT(ITEM_IMAGE);
BIND_ENUM_CONSTANT(ITEM_NEWLINE);
BIND_ENUM_CONSTANT(ITEM_FONT);
BIND_ENUM_CONSTANT(ITEM_FONT_SCALE);
BIND_ENUM_CONSTANT(ITEM_COLOR);
BIND_ENUM_CONSTANT(ITEM_UNDERLINE);
BIND_ENUM_CONSTANT(ITEM_STRIKETHROUGH);
Expand Down
9 changes: 9 additions & 0 deletions scene/gui/rich_text_label.h
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,7 @@ class RichTextLabel : public Control {
ITEM_IMAGE,
ITEM_NEWLINE,
ITEM_FONT,
ITEM_FONT_SCALE,
ITEM_COLOR,
ITEM_UNDERLINE,
ITEM_STRIKETHROUGH,
Expand Down Expand Up @@ -157,6 +158,12 @@ class RichTextLabel : public Control {
ItemFont() { type = ITEM_FONT; }
};

struct ItemScaleFont : public Item {

real_t scale;
ItemScaleFont() { type = ITEM_FONT_SCALE; }
};

struct ItemColor : public Item {
Color color;
ItemColor() { type = ITEM_COLOR; }
Expand Down Expand Up @@ -372,6 +379,7 @@ class RichTextLabel : public Control {
void _find_click(ItemFrame *p_frame, const Point2i &p_click, Item **r_click_item = NULL, int *r_click_char = NULL, bool *r_outside = NULL);

Ref<Font> _find_font(Item *p_item);
real_t _find_font_scale(Item *p_item);
int _find_margin(Item *p_item, const Ref<Font> &p_base_font);
Align _find_align(Item *p_item);
Color _find_color(Item *p_item, const Color &p_default_color);
Expand Down Expand Up @@ -416,6 +424,7 @@ class RichTextLabel : public Control {
void push_bold_italics();
void push_italics();
void push_mono();
void push_font_scale(real_t scale);
void push_color(const Color &p_color);
void push_underline();
void push_strikethrough();
Expand Down
16 changes: 8 additions & 8 deletions scene/resources/dynamic_font.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -299,7 +299,7 @@ void DynamicFontAtSize::set_texture_flags(uint32_t p_flags) {
}
}

float DynamicFontAtSize::draw_char(RID p_canvas_item, const Point2 &p_pos, CharType p_char, CharType p_next, const Color &p_modulate, const Vector<Ref<DynamicFontAtSize> > &p_fallbacks, bool p_advance_only) const {
float DynamicFontAtSize::draw_char_scaled(RID p_canvas_item, const Point2 &p_pos, float p_scale, CharType p_char, CharType p_next, const Color &p_modulate, const Vector<Ref<DynamicFontAtSize> > &p_fallbacks, bool p_advance_only) const {

if (!valid)
return 0;
Expand All @@ -319,18 +319,18 @@ float DynamicFontAtSize::draw_char(RID p_canvas_item, const Point2 &p_pos, CharT

if (!p_advance_only && ch->texture_idx != -1) {
Point2 cpos = p_pos;
cpos.x += ch->h_align;
cpos.y -= font->get_ascent();
cpos.y += ch->v_align;
cpos.x += ch->h_align * p_scale;
cpos.y -= font->get_ascent() * p_scale;
cpos.y += ch->v_align * p_scale;
Color modulate = p_modulate;
if (FT_HAS_COLOR(face)) {
modulate.r = modulate.g = modulate.b = 1.0;
}
RID texture = font->textures[ch->texture_idx].texture->get_rid();
VisualServer::get_singleton()->canvas_item_add_texture_rect_region(p_canvas_item, Rect2(cpos, ch->rect.size), texture, ch->rect_uv, modulate, false, RID(), false);
VisualServer::get_singleton()->canvas_item_add_texture_rect_region(p_canvas_item, Rect2(cpos, ch->rect.size * p_scale), texture, ch->rect_uv, modulate, false, RID(), false);
}

advance = ch->advance;
advance = ch->advance * p_scale;
}

return advance;
Expand Down Expand Up @@ -864,7 +864,7 @@ bool DynamicFont::has_outline() const {
return outline_cache_id.outline_size > 0;
}

float DynamicFont::draw_char(RID p_canvas_item, const Point2 &p_pos, CharType p_char, CharType p_next, const Color &p_modulate, bool p_outline) const {
float DynamicFont::draw_char_scaled(RID p_canvas_item, const Point2 &p_pos, float p_scale, CharType p_char, CharType p_next, const Color &p_modulate, bool p_outline) const {
const Ref<DynamicFontAtSize> &font_at_size = p_outline && outline_cache_id.outline_size > 0 ? outline_data_at_size : data_at_size;

if (!font_at_size.is_valid())
Expand All @@ -875,7 +875,7 @@ float DynamicFont::draw_char(RID p_canvas_item, const Point2 &p_pos, CharType p_

// If requested outline draw, but no outline is present, simply return advance without drawing anything
bool advance_only = p_outline && outline_cache_id.outline_size == 0;
return font_at_size->draw_char(p_canvas_item, p_pos, p_char, p_next, color, fallbacks, advance_only) + spacing_char;
return font_at_size->draw_char_scaled(p_canvas_item, p_pos, p_scale, p_char, p_next, color, fallbacks, advance_only) + spacing_char;
}

void DynamicFont::set_fallback(int p_idx, const Ref<DynamicFontData> &p_data) {
Expand Down
Loading

0 comments on commit 60cf7dc

Please sign in to comment.