aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/Body.cpp41
-rw-r--r--src/QuickMedia.cpp95
-rw-r--r--src/Text.cpp200
-rw-r--r--src/plugins/Fourchan.cpp2
-rw-r--r--src/plugins/Matrix.cpp2
5 files changed, 218 insertions, 122 deletions
diff --git a/src/Body.cpp b/src/Body.cpp
index 3ebd11e..fd6ad07 100644
--- a/src/Body.cpp
+++ b/src/Body.cpp
@@ -15,7 +15,14 @@ const sf::Color front_color(32, 36, 42);
const sf::Color back_color(33, 35, 37);
namespace QuickMedia {
- BodyItem::BodyItem(std::string _title): visible(true), dirty(false), dirty_description(false), thumbnail_is_local(false), title_color(sf::Color::White) {
+ BodyItem::BodyItem(std::string _title) :
+ visible(true),
+ dirty(false),
+ dirty_description(false),
+ dirty_author(false),
+ thumbnail_is_local(false),
+ title_color(sf::Color::White)
+ {
set_title(std::move(_title));
}
@@ -29,6 +36,7 @@ namespace QuickMedia {
visible = other.visible;
dirty = other.dirty;
dirty_description = other.dirty_description;
+ dirty_author = other.dirty_author;
thumbnail_is_local = other.thumbnail_is_local;
if(other.title_text)
title_text = std::make_unique<Text>(*other.title_text);
@@ -43,9 +51,10 @@ namespace QuickMedia {
title_color = other.title_color;
}
- Body::Body(Program *program, sf::Font *font, sf::Font *bold_font) :
+ Body::Body(Program *program, sf::Font *font, sf::Font *bold_font, sf::Font *cjk_font) :
font(font),
bold_font(bold_font),
+ cjk_font(cjk_font),
progress_text("", *font, 14),
author_text("", *bold_font, 16),
replies_text("", *font, 14),
@@ -355,26 +364,34 @@ namespace QuickMedia {
thumbnail_it.second.referenced = false;
}
- // TODO: Change font size. Currently it doesn't work because it glitches out. Why does that happen??
for(auto &body_item : items) {
if(body_item->dirty) {
body_item->dirty = false;
+ // TODO: Find a way to optimize fromUtf8
+ sf::String str = sf::String::fromUtf8(body_item->get_title().data(), body_item->get_title().data() + body_item->get_title().size());
if(body_item->title_text)
- body_item->title_text->setString(body_item->get_title());
+ body_item->title_text->setString(std::move(str));
else
- body_item->title_text = std::make_unique<Text>(body_item->get_title(), font, 16, size.x - 50 - image_padding_x * 2.0f);
+ body_item->title_text = std::make_unique<Text>(std::move(str), font, cjk_font, 16, size.x - 50 - image_padding_x * 2.0f);
body_item->title_text->setFillColor(body_item->title_color);
body_item->title_text->updateGeometry();
}
if(body_item->dirty_description) {
- body_item->dirty_description = true;
+ body_item->dirty_description = false;
+ sf::String str = sf::String::fromUtf8(body_item->get_description().data(), body_item->get_description().data() + body_item->get_description().size());
if(body_item->description_text)
- body_item->description_text->setString(body_item->get_description());
+ body_item->description_text->setString(std::move(str));
else
- body_item->description_text = std::make_unique<Text>(body_item->get_description(), font, 14, size.x - 50 - image_padding_x * 2.0f);
+ body_item->description_text = std::make_unique<Text>(std::move(str), font, cjk_font, 14, size.x - 50 - image_padding_x * 2.0f);
body_item->description_text->updateGeometry();
}
+
+ if(body_item->dirty_author) {
+ body_item->dirty_author = false;
+ sf::String str = sf::String::fromUtf8(body_item->get_author().data(), body_item->get_author().data() + body_item->get_author().size());
+ author_text.setString(std::move(str));
+ }
}
// Find the starting row that can be drawn to make selected row visible as well
@@ -388,7 +405,7 @@ namespace QuickMedia {
if(!item->get_title().empty()) {
item_height += item->title_text->getHeight();
}
- if(!item->author.empty()) {
+ if(!item->get_author().empty()) {
item_height += author_text.getCharacterSize() + 2.0f;
}
if(item->description_text) {
@@ -437,7 +454,7 @@ namespace QuickMedia {
if(!item->get_title().empty()) {
item_height += item->title_text->getHeight();
}
- if(!item->author.empty()) {
+ if(!item->get_author().empty()) {
item_height += author_text.getCharacterSize() + 2.0f;
}
if(item->description_text) {
@@ -496,9 +513,7 @@ namespace QuickMedia {
}
}
- if(!item->author.empty()) {
- // TODO: Remove this call, should not be called every frame
- author_text.setString(item->author);
+ if(!item->get_author().empty()) {
author_text.setPosition(std::floor(item_pos.x + text_offset_x), std::floor(item_pos.y + padding_y));
window.draw(author_text);
diff --git a/src/QuickMedia.cpp b/src/QuickMedia.cpp
index f6b9d61..295749f 100644
--- a/src/QuickMedia.cpp
+++ b/src/QuickMedia.cpp
@@ -168,16 +168,47 @@ namespace QuickMedia {
resources_root = "../../../";
}
- if(!font.loadFromFile(resources_root + "fonts/NotoSans-Regular.ttf")) {
- fprintf(stderr, "Failed to load font: NotoSans-Regular.ttf\n");
+ const std::string noto_sans_directories[] = {
+ "/usr/share/fonts/noto", "/usr/share/fonts/truetype/noto",
+ "/usr/share/fonts/noto-cjk", "/usr/share/fonts/truetype/noto-cjk"
+ };
+ for(const std::string &noto_sans_dir : noto_sans_directories) {
+ if(!font) {
+ auto new_font = std::make_unique<sf::Font>();
+ if(new_font->loadFromFile(noto_sans_dir + "/NotoSans-Regular.ttf"))
+ font = std::move(new_font);
+ }
+
+ if(!bold_font) {
+ auto new_font = std::make_unique<sf::Font>();
+ if(new_font->loadFromFile(noto_sans_dir + "/NotoSans-Bold.ttf"))
+ bold_font = std::move(new_font);
+ }
+
+ if(!cjk_font) {
+ auto new_font = std::make_unique<sf::Font>();
+ if(new_font->loadFromFile(noto_sans_dir + "/NotoSansCJK-Regular.ttc"))
+ cjk_font = std::move(new_font);
+ }
+ }
+
+ if(!font) {
+ fprintf(stderr, "Failed to find NotoSans-Regular.ttf in /usr/share/fonts/noto and /usr/share/fonts/truetype/noto\n");
+ abort();
+ }
+
+ if(!bold_font) {
+ fprintf(stderr, "Failed to find NotoSans-Bold.ttf in /usr/share/fonts/noto and /usr/share/fonts/truetype/noto\n");
abort();
}
- if(!bold_font.loadFromFile(resources_root + "fonts/NotoSans-Bold.ttf")) {
- fprintf(stderr, "Failed to load font: NotoSans-Bold.ttf\n");
+
+ if(!cjk_font) {
+ fprintf(stderr, "Failed to find NotoSansCJK-Regular.ttc in /usr/share/fonts/noto and /usr/share/fonts/truetype/noto\n");
abort();
}
- body = new Body(this, &font, &bold_font);
- related_media_body = new Body(this, &font, &bold_font);
+
+ body = new Body(this, font.get(), bold_font.get(), cjk_font.get());
+ related_media_body = new Body(this, font.get(), bold_font.get(), cjk_font.get());
related_media_body->draw_thumbnails = true;
struct sigaction action;
@@ -454,7 +485,7 @@ namespace QuickMedia {
if(search_placeholder.empty())
search_placeholder = "Search...";
- search_bar = std::make_unique<SearchBar>(font, &plugin_logo, search_placeholder);
+ search_bar = std::make_unique<SearchBar>(*font, &plugin_logo, search_placeholder);
search_bar->text_autosearch_delay = current_plugin->get_search_delay();
while(window.isOpen()) {
@@ -926,16 +957,16 @@ namespace QuickMedia {
std::string autocomplete_text;
bool autocomplete_running = false;
- Body history_body(this, &font, &bold_font);
+ Body history_body(this, font.get(), bold_font.get(), cjk_font.get());
std::unique_ptr<Body> recommended_body;
- sf::Text all_tab_text("All", font, tab_text_size);
- sf::Text history_tab_text("History", font, tab_text_size);
- sf::Text recommended_tab_text("Recommended", font, tab_text_size);
- sf::Text login_tab_text("Login", font, tab_text_size);
+ sf::Text all_tab_text("All", *font, tab_text_size);
+ sf::Text history_tab_text("History", *font, tab_text_size);
+ sf::Text recommended_tab_text("Recommended", *font, tab_text_size);
+ sf::Text login_tab_text("Login", *font, tab_text_size);
SearchBar *focused_login_input = nullptr;
if(current_plugin->name == "youtube") {
- recommended_body = std::make_unique<Body>(this, &font, &bold_font);
+ recommended_body = std::make_unique<Body>(this, font.get(), bold_font.get(), cjk_font.get());
recommended_body->draw_thumbnails = true;
fill_recommended_items_from_json(load_recommended_json(current_plugin), recommended_body->items);
}
@@ -973,7 +1004,7 @@ namespace QuickMedia {
if(recommended_body)
tabs.push_back(Tab{recommended_body.get(), nullptr, SearchSuggestionTab::RECOMMENDED, &recommended_tab_text});
if(is_fourchan) {
- tabs.push_back(Tab{nullptr, std::make_unique<LoginTab>(font), SearchSuggestionTab::LOGIN, &login_tab_text});
+ tabs.push_back(Tab{nullptr, std::make_unique<LoginTab>(*font), SearchSuggestionTab::LOGIN, &login_tab_text});
focused_login_input = tabs.back().login_tab->username.get();
tabs.back().login_tab->username->caret_visible = true;
@@ -1403,7 +1434,7 @@ namespace QuickMedia {
sf::Vector2f related_media_window_size;
bool related_media_window_visible = false;
- sf::Text related_videos_text("Related videos", bold_font, 20);
+ sf::Text related_videos_text("Related videos", *bold_font, 20);
const float related_videos_text_height = related_videos_text.getCharacterSize();
sf::WindowHandle video_player_window = None;
@@ -1794,18 +1825,18 @@ namespace QuickMedia {
chapters_tab.type = EpisodeListTabType::CHAPTERS;
chapters_tab.body = body;
chapters_tab.creator = nullptr;
- chapters_tab.text = sf::Text("Chapters", font, tab_text_size);
+ chapters_tab.text = sf::Text("Chapters", *font, tab_text_size);
tabs.push_back(std::move(chapters_tab));
const std::vector<Creator>& creators = manga->get_creators();
for(const Creator &creator : creators) {
EpisodeListTab tab;
tab.type = EpisodeListTabType::CREATOR;
- tab.body = new Body(this, &font, &bold_font);
+ tab.body = new Body(this, font.get(), bold_font.get(), cjk_font.get());
tab.body->draw_thumbnails = true;
tab.creator = &creator;
tab.creator_page_download_future = std::async(std::launch::async, download_creator_page, creator.url);
- tab.text = sf::Text(creator.name, font, tab_text_size);
+ tab.text = sf::Text(creator.name, *font, tab_text_size);
tabs.push_back(std::move(tab));
}
@@ -2069,7 +2100,7 @@ namespace QuickMedia {
sf::Texture image_texture;
sf::Sprite image;
- sf::Text error_message("", font, 30);
+ sf::Text error_message("", *font, 30);
error_message.setFillColor(sf::Color::White);
assert(current_plugin->is_manga());
@@ -2132,7 +2163,7 @@ namespace QuickMedia {
bool redraw = true;
sf::Event event;
- sf::Text chapter_text(content_title + " | " + chapter_title + " | Page " + std::to_string(image_index + 1) + "/" + std::to_string(num_images), font, 14);
+ sf::Text chapter_text(content_title + " | " + chapter_title + " | Page " + std::to_string(image_index + 1) + "/" + std::to_string(num_images), *font, 14);
if(image_index == num_images)
chapter_text.setString(content_title + " | " + chapter_title + " | End");
chapter_text.setFillColor(sf::Color::White);
@@ -2296,7 +2327,7 @@ namespace QuickMedia {
json_chapter = Json::Value(Json::objectValue);
}
- ImageViewer image_viewer(image_plugin, images_url, content_title, chapter_title, image_index, content_cache_dir, &font);
+ ImageViewer image_viewer(image_plugin, images_url, content_title, chapter_title, image_index, content_cache_dir, font.get());
json_chapter["current"] = std::min(latest_read, image_viewer.get_num_pages());
json_chapter["total"] = image_viewer.get_num_pages();
@@ -2490,7 +2521,7 @@ namespace QuickMedia {
search_bar->text_autosearch_delay = file_manager->get_search_delay();
Page previous_page = pop_page_stack();
- sf::Text current_dir_text(file_manager->get_current_dir().string(), bold_font, 18);
+ sf::Text current_dir_text(file_manager->get_current_dir().string(), *bold_font, 18);
// TODO: Make asynchronous.
// TODO: Automatically go to the parent if this fails (recursively).
@@ -2664,7 +2695,7 @@ namespace QuickMedia {
std::mutex attachment_load_mutex;
GoogleCaptchaChallengeInfo challenge_info;
- sf::Text challenge_description_text("", font, 24);
+ sf::Text challenge_description_text("", *font, 24);
challenge_description_text.setFillColor(sf::Color::White);
const size_t captcha_num_columns = 3;
const size_t captcha_num_rows = 3;
@@ -3050,11 +3081,11 @@ namespace QuickMedia {
void Program::chat_login_page() {
assert(current_plugin->name == "matrix");
- SearchBar login_input(font, nullptr, "Username");
- SearchBar password_input(font, nullptr, "Password", true);
- SearchBar homeserver_input(font, nullptr, "Homeserver");
+ SearchBar login_input(*font, nullptr, "Username");
+ SearchBar password_input(*font, nullptr, "Password", true);
+ SearchBar homeserver_input(*font, nullptr, "Homeserver");
- sf::Text status_text("", font, 18);
+ sf::Text status_text("", *font, 18);
const int num_inputs = 3;
SearchBar *inputs[num_inputs] = { &login_input, &password_input, &homeserver_input };
@@ -3150,18 +3181,18 @@ namespace QuickMedia {
ChatTab messages_tab;
messages_tab.type = ChatTabType::MESSAGES;
- messages_tab.body = std::make_unique<Body>(this, &font, &bold_font);
+ messages_tab.body = std::make_unique<Body>(this, font.get(), bold_font.get(), cjk_font.get());
messages_tab.body->draw_thumbnails = true;
//messages_tab.body->line_seperator_color = sf::Color::Transparent;
- messages_tab.text = sf::Text("Messages", font, tab_text_size);
+ messages_tab.text = sf::Text("Messages", *font, tab_text_size);
tabs.push_back(std::move(messages_tab));
ChatTab rooms_tab;
rooms_tab.type = ChatTabType::ROOMS;
- rooms_tab.body = std::make_unique<Body>(this, &font, &bold_font);
+ rooms_tab.body = std::make_unique<Body>(this, font.get(), bold_font.get(), cjk_font.get());
rooms_tab.body->draw_thumbnails = true;
//rooms_tab.body->line_seperator_color = sf::Color::Transparent;
- rooms_tab.text = sf::Text("Rooms", font, tab_text_size);
+ rooms_tab.text = sf::Text("Rooms", *font, tab_text_size);
tabs.push_back(std::move(rooms_tab));
const int MESSAGES_TAB_INDEX = 0;
@@ -3206,7 +3237,7 @@ namespace QuickMedia {
plugin_logo.setSmooth(true);
}
- SearchBar chat_input(font, &plugin_logo, "Send a message...");
+ SearchBar chat_input(*font, &plugin_logo, "Send a message...");
chat_input.set_background_color(sf::Color::Transparent);
// TODO: Filer for rooms and settings
diff --git a/src/Text.cpp b/src/Text.cpp
index 0517c15..bdd41c3 100644
--- a/src/Text.cpp
+++ b/src/Text.cpp
@@ -21,31 +21,12 @@ namespace QuickMedia
return -1;
}
- Text::Text(const sf::Font *_font) :
- font(_font),
- characterSize(0),
- vertices(sf::PrimitiveType::Quads),
- maxWidth(0.0f),
- color(sf::Color::White),
- urlColor(URL_COLOR),
- dirty(false),
- dirtyText(false),
- dirtyCaret(false),
- plainText(false),
- editable(false),
- visible(true),
- caretMoveDirection(CaretMoveDirection::NONE),
- lineSpacing(0.0f),
- characterSpacing(0.0f),
- caretIndex(0)
- {
-
- }
+ Text::Text(const sf::Font *_font, const sf::Font *_cjk_font) : Text("", _font, _cjk_font, 0, 0.0f, false) {}
- Text::Text(const sf::String &_str, const sf::Font *_font, unsigned int _characterSize, float _maxWidth, bool _plainText) :
+ Text::Text(sf::String _str, const sf::Font *_font, const sf::Font *_cjk_font, unsigned int _characterSize, float _maxWidth, bool _plainText) :
font(_font),
+ cjk_font(_cjk_font),
characterSize(_characterSize),
- vertices(sf::PrimitiveType::Quads),
maxWidth(_maxWidth),
color(sf::Color::White),
urlColor(URL_COLOR),
@@ -60,19 +41,21 @@ namespace QuickMedia
characterSpacing(0.0f),
caretIndex(0)
{
- setString(_str);
+ vertices[0].setPrimitiveType(sf::PrimitiveType::Quads);
+ vertices[1].setPrimitiveType(sf::PrimitiveType::Quads);
+ setString(std::move(_str));
}
- void Text::setString(const sf::String &str)
+ void Text::setString(sf::String str)
{
if(str != this->str)
{
- this->str = str;
+ this->str = std::move(str);
dirty = true;
dirtyText = true;
- if((int)str.getSize() < caretIndex)
+ if((int)this->str.getSize() < caretIndex)
{
- caretIndex = str.getSize();
+ caretIndex = this->str.getSize();
dirtyCaret = true;
}
}
@@ -177,22 +160,68 @@ namespace QuickMedia
{
return boundingBox.height;
}
+
+ // TODO: Is there a more efficient way to do this? maybe japanese characters have a specific bit-pattern?
+ static bool is_japanese_codepoint(sf::Uint32 codepoint) {
+ return (codepoint >= 0x2E80 && codepoint <= 0x2FD5) // Kanji radicals
+ || (codepoint >= 0x3000 && codepoint <= 0x303F) // Punctuation
+ || (codepoint >= 0x3041 && codepoint <= 0x3096) // Hiragana
+ || (codepoint >= 0x30A0 && codepoint <= 0x30FF) // Katakana
+ || (codepoint >= 0x31F0 && codepoint <= 0x31FF) // Miscellaneous symbols and characters 1
+ || (codepoint >= 0x3220 && codepoint <= 0x3243) // Miscellaneous symbols and characters 2
+ || (codepoint >= 0x3280 && codepoint <= 0x337F) // Miscellaneous symbols and characters 3
+ || (codepoint >= 0x3400 && codepoint <= 0x4DB5) // Kanji 1
+ || (codepoint >= 0x4E00 && codepoint <= 0x9FCB) // Kanji 2
+ || (codepoint >= 0xF900 && codepoint <= 0xFA6A) // Kanji 3
+ || (codepoint >= 0xFF01 && codepoint <= 0xFF5E) // Alphanumeric and punctuation (full width)
+ || (codepoint >= 0xFF5F && codepoint <= 0xFF9F); // Katakana and punctuation (half width)
+ }
+
+ static size_t find_end_of_japanese(const sf::Uint32 *str, size_t size) {
+ for(size_t i = 0; i < size; ++i) {
+ if(!is_japanese_codepoint(str[i]))
+ return i;
+ }
+ return size;
+ }
+
+ static size_t find_end_of_non_japanese(const sf::Uint32 *str, size_t size) {
+ for(size_t i = 0; i < size; ++i) {
+ if(is_japanese_codepoint(str[i]))
+ return i;
+ }
+ return size;
+ }
+
+ void Text::splitTextByFont() {
+ textElements.clear();
+ size_t index = 0;
+ size_t size = str.getSize();
+ while(index < size) {
+ size_t offset;
+ bool is_japanese = is_japanese_codepoint(str[index]);
+ if(is_japanese)
+ offset = find_end_of_japanese(str.getData() + index + 1, size - index - 1);
+ else
+ offset = find_end_of_non_japanese(str.getData() + index + 1, size - index - 1);
+ textElements.push_back({ StringViewUtf32(str.getData() + index, offset + 1), TextElement::Type::TEXT });
+ textElements.back().is_japanese = is_japanese;
+ index += 1 + offset;
+ }
+ }
// Logic loosely based on https://github.com/SFML/SFML/wiki/Source:-CurvedText
- void Text::updateGeometry(bool update_even_if_not_dirty)
- {
- if(dirtyText)
- {
- textElements.clear();
- StringViewUtf32 wholeStr(this->str.getData(), this->str.getSize());
- textElements.push_back({ wholeStr, TextElement::Type::TEXT });
+ void Text::updateGeometry(bool update_even_if_not_dirty) {
+ if(dirtyText) {
dirtyText = false;
+ splitTextByFont();
}
if(!update_even_if_not_dirty && !dirty)
return;
- vertices.clear();
+ vertices[0].clear();
+ vertices[1].clear();
float hspace = font->getGlyph(' ', characterSize, false).advance + characterSpacing;
float vspace = font->getLineSpacing(characterSize);
@@ -205,14 +234,20 @@ namespace QuickMedia
for(usize textElementIndex = 0; textElementIndex < textElements.size(); ++textElementIndex)
{
TextElement &textElement = textElements[textElementIndex];
+ const sf::Font *ff = font;
+ size_t vertices_index = 0;
+ if(textElement.is_japanese) {
+ ff = cjk_font;
+ vertices_index = 1;
+ }
- usize vertexOffset = vertices.getVertexCount();
- vertices.resize(vertices.getVertexCount() + 4 * (textElement.text.size + 1));
+ usize vertexOffset = vertices[vertices_index].getVertexCount();
+ vertices[vertices_index].resize(vertices[vertices_index].getVertexCount() + 4 * (textElement.text.size + 1));
textElement.position = glyphPos;
for(size_t i = 0; i < textElement.text.size; ++i)
{
sf::Uint32 codePoint = textElement.text[i];
- float kerning = font->getKerning(prevCodePoint, codePoint, characterSize);
+ float kerning = ff->getKerning(prevCodePoint, codePoint, characterSize);
prevCodePoint = codePoint;
glyphPos.x += kerning;
@@ -222,10 +257,10 @@ namespace QuickMedia
{
case ' ':
{
- vertices[vertexStart + 0] = { sf::Vector2f(glyphPos.x, glyphPos.y - vspace), sf::Color::Transparent, sf::Vector2f() };
- vertices[vertexStart + 1] = { sf::Vector2f(glyphPos.x + hspace, glyphPos.y - vspace), sf::Color::Transparent, sf::Vector2f() };
- vertices[vertexStart + 2] = { sf::Vector2f(glyphPos.x + hspace, glyphPos.y), sf::Color::Transparent, sf::Vector2f() };
- vertices[vertexStart + 3] = { sf::Vector2f(glyphPos.x, glyphPos.y), sf::Color::Transparent, sf::Vector2f() };
+ vertices[vertices_index][vertexStart + 0] = { sf::Vector2f(glyphPos.x, glyphPos.y - vspace), sf::Color::Transparent, sf::Vector2f() };
+ vertices[vertices_index][vertexStart + 1] = { sf::Vector2f(glyphPos.x + hspace, glyphPos.y - vspace), sf::Color::Transparent, sf::Vector2f() };
+ vertices[vertices_index][vertexStart + 2] = { sf::Vector2f(glyphPos.x + hspace, glyphPos.y), sf::Color::Transparent, sf::Vector2f() };
+ vertices[vertices_index][vertexStart + 3] = { sf::Vector2f(glyphPos.x, glyphPos.y), sf::Color::Transparent, sf::Vector2f() };
glyphPos.x += hspace;
if(glyphPos.x > maxWidth * 0.5f)
{
@@ -236,10 +271,10 @@ namespace QuickMedia
}
case '\t':
{
- vertices[vertexStart + 0] = { sf::Vector2f(glyphPos.x, glyphPos.y - vspace), sf::Color::Transparent, sf::Vector2f() };
- vertices[vertexStart + 1] = { sf::Vector2f(glyphPos.x + hspace * TAB_WIDTH, glyphPos.y - vspace), sf::Color::Transparent, sf::Vector2f() };
- vertices[vertexStart + 2] = { sf::Vector2f(glyphPos.x + hspace * TAB_WIDTH, glyphPos.y), sf::Color::Transparent, sf::Vector2f() };
- vertices[vertexStart + 3] = { sf::Vector2f(glyphPos.x, glyphPos.y), sf::Color::Transparent, sf::Vector2f() };
+ vertices[vertices_index][vertexStart + 0] = { sf::Vector2f(glyphPos.x, glyphPos.y - vspace), sf::Color::Transparent, sf::Vector2f() };
+ vertices[vertices_index][vertexStart + 1] = { sf::Vector2f(glyphPos.x + hspace * TAB_WIDTH, glyphPos.y - vspace), sf::Color::Transparent, sf::Vector2f() };
+ vertices[vertices_index][vertexStart + 2] = { sf::Vector2f(glyphPos.x + hspace * TAB_WIDTH, glyphPos.y), sf::Color::Transparent, sf::Vector2f() };
+ vertices[vertices_index][vertexStart + 3] = { sf::Vector2f(glyphPos.x, glyphPos.y), sf::Color::Transparent, sf::Vector2f() };
glyphPos.x += (hspace * TAB_WIDTH);
if(glyphPos.x > maxWidth * 0.5f)
{
@@ -250,17 +285,17 @@ namespace QuickMedia
}
case '\n':
{
- vertices[vertexStart + 0] = { sf::Vector2f(glyphPos.x, glyphPos.y - vspace), sf::Color::Transparent, sf::Vector2f() };
- vertices[vertexStart + 1] = { sf::Vector2f(0.0f, glyphPos.y), sf::Color::Transparent, sf::Vector2f() };
- vertices[vertexStart + 2] = { sf::Vector2f(0.0f, glyphPos.y), sf::Color::Transparent, sf::Vector2f() };
- vertices[vertexStart + 3] = { sf::Vector2f(0.0f, glyphPos.y), sf::Color::Transparent, sf::Vector2f() };
+ vertices[vertices_index][vertexStart + 0] = { sf::Vector2f(glyphPos.x, glyphPos.y - vspace), sf::Color::Transparent, sf::Vector2f() };
+ vertices[vertices_index][vertexStart + 1] = { sf::Vector2f(0.0f, glyphPos.y), sf::Color::Transparent, sf::Vector2f() };
+ vertices[vertices_index][vertexStart + 2] = { sf::Vector2f(0.0f, glyphPos.y), sf::Color::Transparent, sf::Vector2f() };
+ vertices[vertices_index][vertexStart + 3] = { sf::Vector2f(0.0f, glyphPos.y), sf::Color::Transparent, sf::Vector2f() };
glyphPos.x = 0.0f;
glyphPos.y += floor(vspace + lineSpacing);
continue;
}
}
- const sf::Glyph &glyph = font->getGlyph(codePoint, characterSize, false);
+ const sf::Glyph &glyph = ff->getGlyph(codePoint, characterSize, false);
if(glyphPos.x + glyph.advance > maxWidth)
{
// If there was a space in the text and text width is too long, then we need to word wrap at space index instead,
@@ -271,7 +306,7 @@ namespace QuickMedia
{
for(size_t k = 0; k < 4; ++k)
{
- sf::Vector2f &vertexPos = vertices[vertexOffset + j * 4 + k].position;
+ sf::Vector2f &vertexPos = vertices[vertices_index][vertexOffset + j * 4 + k].position;
vertexPos.x -= lastSpacingAccumulatedOffset;
vertexPos.y += floor(vspace + lineSpacing);
}
@@ -299,18 +334,18 @@ namespace QuickMedia
sf::Color fontColor = (textElement.type == TextElement::Type::TEXT ? color : urlColor);
- vertices[vertexStart + 0] = { vertexTopLeft, fontColor, textureTopLeft };
- vertices[vertexStart + 1] = { vertexTopRight, fontColor, textureTopRight };
- vertices[vertexStart + 2] = { vertexBottomRight, fontColor, textureBottomRight };
- vertices[vertexStart + 3] = { vertexBottomLeft, fontColor, textureBottomLeft };
+ vertices[vertices_index][vertexStart + 0] = { vertexTopLeft, fontColor, textureTopLeft };
+ vertices[vertices_index][vertexStart + 1] = { vertexTopRight, fontColor, textureTopRight };
+ vertices[vertices_index][vertexStart + 2] = { vertexBottomRight, fontColor, textureBottomRight };
+ vertices[vertices_index][vertexStart + 3] = { vertexBottomLeft, fontColor, textureBottomLeft };
glyphPos.x += glyph.advance + characterSpacing;
}
- vertices[vertices.getVertexCount() - 4] = { sf::Vector2f(glyphPos.x, glyphPos.y - vspace), sf::Color::Transparent, sf::Vector2f() };
- vertices[vertices.getVertexCount() - 3] = { sf::Vector2f(glyphPos.x, glyphPos.y - vspace), sf::Color::Transparent, sf::Vector2f() };
- vertices[vertices.getVertexCount() - 2] = { sf::Vector2f(glyphPos.x, glyphPos.y - vspace), sf::Color::Transparent, sf::Vector2f() };
- vertices[vertices.getVertexCount() - 1] = { sf::Vector2f(glyphPos.x, glyphPos.y - vspace), sf::Color::Transparent, sf::Vector2f() };
+ vertices[vertices_index][vertices[vertices_index].getVertexCount() - 4] = { sf::Vector2f(glyphPos.x, glyphPos.y - vspace), sf::Color::Transparent, sf::Vector2f() };
+ vertices[vertices_index][vertices[vertices_index].getVertexCount() - 3] = { sf::Vector2f(glyphPos.x, glyphPos.y - vspace), sf::Color::Transparent, sf::Vector2f() };
+ vertices[vertices_index][vertices[vertices_index].getVertexCount() - 2] = { sf::Vector2f(glyphPos.x, glyphPos.y - vspace), sf::Color::Transparent, sf::Vector2f() };
+ vertices[vertices_index][vertices[vertices_index].getVertexCount() - 1] = { sf::Vector2f(glyphPos.x, glyphPos.y - vspace), sf::Color::Transparent, sf::Vector2f() };
prevCodePoint = 0;
}
@@ -318,16 +353,19 @@ namespace QuickMedia
boundingBox.height = glyphPos.y + lineSpacing;
boundingBox.height += vspace;
- usize numVertices = vertices.getVertexCount();
- for(usize i = 0; i < numVertices; i += 4)
- {
- const sf::Vertex &bottomRight = vertices[i + 2];
- boundingBox.width = std::max(boundingBox.width, bottomRight.position.x);
+ for(size_t vertices_index = 0; vertices_index < 2; ++vertices_index) {
+ usize numVertices = vertices[vertices_index].getVertexCount();
+ for(usize i = 0; i < numVertices; i += 4)
+ {
+ const sf::Vertex &bottomRight = vertices[vertices_index][i + 2];
+ boundingBox.width = std::max(boundingBox.width, bottomRight.position.x);
+ }
}
dirty = false;
}
+#if 0
void Text::updateCaret()
{
assert(!dirty && !dirtyText);
@@ -339,6 +377,7 @@ namespace QuickMedia
return;
}
+
switch(caretMoveDirection)
{
case CaretMoveDirection::UP:
@@ -380,13 +419,13 @@ namespace QuickMedia
caretPosition = topLeftVertex.position;
}
}
-
+
bool Text::isCaretAtEnd() const
{
assert(!dirty && !dirtyText);
return textElements[0].text.size == 0 || caretIndex == (int)textElements[0].text.size;
}
-
+
// TODO: This can be optimized by using binary search
int Text::getStartOfLine(int startIndex) const
{
@@ -604,21 +643,22 @@ namespace QuickMedia
dirtyCaret = true;
}
}
-
+#endif
bool Text::draw(sf::RenderTarget &target)
{
updateGeometry();
+#if 0
if(dirtyCaret || caretMoveDirection != CaretMoveDirection::NONE)
{
updateCaret();
dirtyCaret = false;
caretMoveDirection = CaretMoveDirection::NONE;
}
+#endif
float vspace = font->getLineSpacing(characterSize);
- sf::RenderStates states;
sf::Vector2f pos = position;
pos.y += floor(vspace); // Origin is at bottom left, we want it to be at top left
@@ -633,22 +673,29 @@ namespace QuickMedia
if(!editable && visible && lastSeenTimer.getElapsedTime().asMilliseconds() > 3000)
{
visible = false;
- vertices.resize(0);
+ vertices[0].resize(0);
+ vertices[1].resize(0);
}
return false;
}
- if(!visible)
+ if(!visible) {
+ visible = true;
updateGeometry(true);
+ }
- states.transform.translate(pos);
- states.texture = &font->getTexture(characterSize);
- target.draw(vertices, states);
+ const sf::Font *fonts[] = { font, cjk_font };
+ for(size_t i = 0; i < 2; ++i) {
+ sf::RenderStates states;
+ states.transform.translate(pos);
+ states.texture = &fonts[i]->getTexture(characterSize);
+ target.draw(vertices[i], states);
+ }
lastSeenTimer.restart();
- visible = true;
pos.y -= floor(vspace);
+#if 0
if(!editable) return true;
//float rows = floor(totalHeight / (vspace + lineSpacing));
@@ -659,5 +706,8 @@ namespace QuickMedia
caretRect.setPosition(sf::Vector2f(floor(pos.x + caretPosition.x), floor(pos.y + caretRow * (vspace + lineSpacing))));
target.draw(caretRect);
return true;
+#else
+ return true;
+#endif
}
}
diff --git a/src/plugins/Fourchan.cpp b/src/plugins/Fourchan.cpp
index 4490f39..a70070e 100644
--- a/src/plugins/Fourchan.cpp
+++ b/src/plugins/Fourchan.cpp
@@ -519,7 +519,7 @@ namespace QuickMedia {
html_unescape_sequences(comment_text);
BodyItem *body_item = result_items[body_item_index].get();
body_item->set_title(std::move(comment_text));
- body_item->author = std::move(author_str);
+ body_item->set_author(std::move(author_str));
const Json::Value &ext = post["ext"];
const Json::Value &tim = post["tim"];
diff --git a/src/plugins/Matrix.cpp b/src/plugins/Matrix.cpp
index e806f39..1e8b927 100644
--- a/src/plugins/Matrix.cpp
+++ b/src/plugins/Matrix.cpp
@@ -190,7 +190,7 @@ namespace QuickMedia {
result_items.back()->append_description(it->body);
} else {
auto body_item = std::make_unique<BodyItem>("");
- body_item->author = user_info.display_name;
+ body_item->set_author(user_info.display_name);
body_item->set_description(it->body);
if(!it->thumbnail_url.empty())
body_item->thumbnail_url = it->thumbnail_url;