Skip to content

Commit

Permalink
Refactor Text Icons #1
Browse files Browse the repository at this point in the history
- Parse icon tags as a special type of token instead of simple decorators.
- Refactor the formatter to render text and icons separately.
- Fix issue where icons were drawn multiple times because batch wasn't cleared.
  • Loading branch information
firas-assaad committed May 12, 2021
1 parent 50b9906 commit de3992e
Show file tree
Hide file tree
Showing 6 changed files with 165 additions and 169 deletions.
12 changes: 5 additions & 7 deletions include/xd/graphics/detail/text_formatter.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,18 +8,21 @@
namespace xd { namespace detail { namespace text_formatter {

// text decorator visitor
class decorate_text;
class token_decorator;
class formatted_element_renderer;

// tokens
struct token_text;
struct token_variable;
struct token_icon;
struct token_open_decorator;
struct token_close_decorator;

// variant token
typedef std::variant<
token_text,
token_variable,
token_icon,
token_open_decorator,
token_close_decorator
> token;
Expand Down Expand Up @@ -49,7 +52,6 @@ namespace xd { namespace detail { namespace text_formatter {
typedef nested_value<glm::vec2> nested_position;
typedef nested_value<float> nested_letter_spacing;
typedef nested_value<bool> nested_force_autohint;
typedef nested_value<int> nested_icon;
typedef nested_value<void> nested_void;

// state changes
Expand All @@ -62,7 +64,6 @@ namespace xd { namespace detail { namespace text_formatter {
struct state_change_push_position : nested_position {};
struct state_change_push_letter_spacing : nested_letter_spacing {};
struct state_change_push_force_autohint : nested_force_autohint {};
struct state_change_push_icon : nested_icon {};
struct state_change_pop_color : nested_void {};
struct state_change_pop_alpha : nested_void {};
struct state_change_pop_size : nested_void {};
Expand All @@ -72,7 +73,6 @@ namespace xd { namespace detail { namespace text_formatter {
struct state_change_pop_position : nested_void {};
struct state_change_pop_letter_spacing : nested_void {};
struct state_change_pop_force_autohint : nested_void {};
struct state_change_pop_icon : nested_void {};

// variant state change
typedef std::variant<
Expand All @@ -85,7 +85,6 @@ namespace xd { namespace detail { namespace text_formatter {
state_change_push_position,
state_change_push_letter_spacing,
state_change_push_force_autohint,
state_change_push_icon,
state_change_pop_color,
state_change_pop_alpha,
state_change_pop_size,
Expand All @@ -94,8 +93,7 @@ namespace xd { namespace detail { namespace text_formatter {
state_change_pop_outline,
state_change_pop_position,
state_change_pop_letter_spacing,
state_change_pop_force_autohint,
state_change_pop_icon
state_change_pop_force_autohint
> state_change;

// token list
Expand Down
72 changes: 26 additions & 46 deletions include/xd/graphics/text_formatter.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -15,22 +15,18 @@
#include <functional>
#include <unordered_map>
#include <memory>
#include <variant>

namespace xd
{
namespace xd {
class text_formatter;

class formatted_char
{
class formatted_char {
public:
formatted_char(utf8::uint32_t chr)
: m_chr(chr)
, m_level(0)
{
}
, m_level(0) {}

utf8::uint32_t get() const noexcept
{
utf8::uint32_t get() const noexcept {
return m_chr;
}

Expand All @@ -41,90 +37,74 @@ namespace xd

friend class text_decorator;
friend class text_formatter;
friend class detail::text_formatter::decorate_text;
friend class detail::text_formatter::token_decorator;
friend class detail::text_formatter::formatted_element_renderer;
};

class formatted_text
{
class formatted_text {
public:
typedef std::vector<formatted_char>::iterator iterator;
typedef std::vector<formatted_char>::const_iterator const_iterator;

formatted_text() noexcept
{
}
formatted_text() noexcept {}

formatted_text(const std::string& text)
{
formatted_text(const std::string& text) {
*this += text;
}

formatted_text& operator+=(const formatted_char& chr)
{
formatted_text& operator+=(const formatted_char& chr) {
m_chars.push_back(chr);
return *this;
}

formatted_text& operator+=(const formatted_text& text)
{
formatted_text& operator+=(const formatted_text& text) {
if (this != &text) {
m_chars.insert(m_chars.end(), text.m_chars.begin(), text.m_chars.end());
}
return *this;
}

formatted_text& operator+=(const std::string& text)
{
formatted_text& operator+=(const std::string& text) {
std::string::const_iterator i = text.begin();
while (i != text.end()) {
m_chars.push_back(utf8::next(i, text.end()));
}
return *this;
}

formatted_char& operator[](size_t index) noexcept
{
formatted_char& operator[](size_t index) noexcept {
return m_chars[index];
}

const formatted_char& operator[](size_t index) const noexcept
{
const formatted_char& operator[](size_t index) const noexcept {
return m_chars[index];
}

iterator begin() noexcept
{
iterator begin() noexcept {
return m_chars.begin();
}

iterator end() noexcept
{
iterator end() noexcept {
return m_chars.end();
}

const_iterator begin() const noexcept
{
const_iterator begin() const noexcept {
return m_chars.begin();
}

const_iterator end() const noexcept
{
const_iterator end() const noexcept {
return m_chars.end();
}

size_t length() const noexcept
{
size_t length() const noexcept {
return m_chars.size();
}

void clear() noexcept
{
void clear() noexcept {
m_chars.clear();
}

std::string get_unformatted() const
{
//return std::string(m_chars.begin(), m_chars.end());
std::string get_unformatted() const {
std::string unformatted;
for (const_iterator i = m_chars.begin(); i != m_chars.end(); ++i) {
utf8::append(i->get(), std::back_inserter(unformatted));
Expand All @@ -137,9 +117,11 @@ namespace xd

friend class text_decorator;
friend class text_formatter;
friend class detail::text_formatter::decorate_text;
friend class detail::text_formatter::token_decorator;
};

typedef std::variant<int, formatted_text> formatted_element;

class text_decorator_args
{
public:
Expand Down Expand Up @@ -192,7 +174,6 @@ namespace xd
void push_position(const glm::vec2& position);
void push_letter_spacing(float letter_spacing);
void push_force_autohint(bool force_autohint);
void push_icon(int index);

void pop_color();
void pop_alpha();
Expand All @@ -203,7 +184,6 @@ namespace xd
void pop_position();
void pop_letter_spacing();
void pop_force_autohint();
void pop_icon();

template <typename T>
void push_text(const T& val)
Expand All @@ -219,7 +199,7 @@ namespace xd
detail::text_formatter::state_change_list m_current_state_changes;

// decorate_text needs to be able to modify current state
friend class detail::text_formatter::decorate_text;
friend class detail::text_formatter::token_decorator;
};

class text_formatter
Expand Down
3 changes: 1 addition & 2 deletions src/text_parser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -85,8 +85,7 @@ std::vector<Token> Text_Parser::parse(const std::string& text, bool permissive)
std::string value;
bool has_value = false;
bool error = false;
while (start != end)
{
while (start != end) {
if (std::find(std::begin(special), std::end(special), *start) == std::end(special)) {
// Read tag name or value
if (tag_token.tag.empty())
Expand Down
7 changes: 3 additions & 4 deletions src/xd/graphics/font.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -249,11 +249,10 @@ void xd::font::render(const std::string& text, const font_style& style,
auto icon_mvp = xd::translate(mvp, xd::vec3(0, -src.h, 0));
m_sprite_batch.add(m_icon_texture, src, pos->x, pos->y);
m_sprite_batch.draw(xd::shader_uniforms{icon_mvp});
m_sprite_batch.clear();
text_pos.x += src.w;
if (text.empty() || text == " ") {
*pos = text_pos;
return;
}
*pos = text_pos;
return;
}

// check if the font size is already loaded
Expand Down
6 changes: 0 additions & 6 deletions src/xd/graphics/stock_text_formatter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,6 @@ xd::stock_text_formatter::stock_text_formatter()
register_decorator("type", std::bind(&stock_text_formatter::type_decorator, this, _1, _2, _3));
register_decorator("bold", std::bind(&stock_text_formatter::bold_decorator, this, _1, _2, _3));
register_decorator("italic", std::bind(&stock_text_formatter::italic_decorator, this, _1, _2, _3));
register_decorator("icon", std::bind(&stock_text_formatter::icon_decorator, this, _1, _2, _3));
register_decorator("color", std::bind(&stock_text_formatter::color_decorator, this, _1, _2, _3));
register_decorator("shadow", std::bind(&stock_text_formatter::shadow_decorator, this, _1, _2, _3));
register_decorator("outline", std::bind(&stock_text_formatter::outline_decorator, this, _1, _2, _3));
Expand Down Expand Up @@ -83,11 +82,6 @@ void xd::stock_text_formatter::italic_decorator(text_decorator& decorator, const
decorator.push_text(text);
}

void xd::stock_text_formatter::icon_decorator(text_decorator& decorator, const formatted_text& text, const text_decorator_args& args) {
decorator.push_icon(args.get<int>(0));
decorator.push_text(text.length() == 0 ? formatted_text{" "} : text);
}

void xd::stock_text_formatter::color_decorator(text_decorator& decorator, const formatted_text& text, const text_decorator_args& args)
{
glm::vec4 color;
Expand Down
Loading

0 comments on commit de3992e

Please sign in to comment.