widelands-dev team mailing list archive
-
widelands-dev team
-
Mailing list archive
-
Message #06149
[Merge] lp:~widelands-dev/widelands/listselect into lp:widelands
GunChleoc has proposed merging lp:~widelands-dev/widelands/listselect into lp:widelands.
Commit message:
- Listselect now uses the new font renderer
- Implemented locale fontset selection by word into the new renderer.
- Fontsets now have a representative character that is used to calculate line height.
- Fixed an overflow bug in the renderer.
Requested reviews:
Widelands Developers (widelands-dev)
For more details, see:
https://code.launchpad.net/~widelands-dev/widelands/listselect/+merge/286033
- Listselect now uses the new font renderer
- Implemented locale fontset selection by word into the new renderer.
- Fontsets now have a representative character that is used to calculate line height.
- Fixed an overflow bug in the renderer.
I commented out an assert, I don't know if we still need that one, since everything seems to work. I have added a NOCOM there.
We will probably want font selection by character rather than by word in the future, but this will do for build 19.
--
Your team Widelands Developers is requested to review the proposed merge of lp:~widelands-dev/widelands/listselect into lp:widelands.
=== modified file 'data/i18n/fonts.lua'
--- data/i18n/fonts.lua 2016-02-07 15:47:25 +0000
+++ data/i18n/fonts.lua 2016-02-15 11:00:58 +0000
@@ -28,6 +28,8 @@
-- If the direction isn't defined, your font set will default to "ltr" = left-to-right.
-- For right-to-left or bidirectional (BiDi) languages, use "rtl".
direction = "ltr",
+ -- This is used to calculate line height for the fontset. Use any character for your language's script.
+ representative_character = "a",
size_offset = 0
},
@@ -37,15 +39,18 @@
sans_italic = "amiri/amiri-slanted.ttf",
sans_bold_italic = "amiri/amiri-boldslanted.ttf",
direction = "rtl",
+ representative_character = "ا",
size_offset = 4
},
cjk = {
sans = "MicroHei/wqy-microhei.ttc",
+ representative_character = "简",
},
devanagari = {
sans = "Nakula/nakula.ttf",
+ representative_character = "ह",
direction = "rtl",
size_offset = 2
},
@@ -57,16 +62,19 @@
serif = "Culmus/TaameyFrankCLM-Medium.ttf",
serif_bold = "TaameyFrankCLM-Bold.ttf",
serif_italic = "Culmus/TaameyFrankCLM-MediumOblique.ttf",
+ representative_character = "א",
direction = "rtl",
size_offset = 4
},
myanmar = {
sans = "mmrCensus/mmrCensus.ttf",
+ representative_character = "မ",
size_offset = 2
},
sinhala = {
sans = "Sinhala/lklug.ttf",
+ representative_character = "ස",
}
}
=== modified file 'src/editor/ui_menus/editor_main_menu_load_or_save_map.cc'
--- src/editor/ui_menus/editor_main_menu_load_or_save_map.cc 2016-02-06 10:59:09 +0000
+++ src/editor/ui_menus/editor_main_menu_load_or_save_map.cc 2016-02-15 11:00:58 +0000
@@ -51,7 +51,7 @@
this, right_column_x_, tabley_, get_inner_w() - right_column_x_ - padding_, tableh_),
ok_(this,
"ok",
- UI::g_fh1->fontset().is_rtl() ? get_inner_w() / 2 - butw_ - padding_ : get_inner_w() / 2 + padding_,
+ UI::g_fh1->fontset()->is_rtl() ? get_inner_w() / 2 - butw_ - padding_ : get_inner_w() / 2 + padding_,
get_inner_h() - padding_ - buth_,
butw_,
buth_,
@@ -59,7 +59,7 @@
_("OK")),
cancel_(this,
"cancel",
- UI::g_fh1->fontset().is_rtl() ?
+ UI::g_fh1->fontset()->is_rtl() ?
get_inner_w() / 2 + padding_ :
get_inner_w() / 2 - butw_ - padding_,
get_inner_h() - padding_ - buth_,
=== modified file 'src/editor/ui_menus/editor_main_menu_map_options.cc'
--- src/editor/ui_menus/editor_main_menu_map_options.cc 2016-02-06 10:59:09 +0000
+++ src/editor/ui_menus/editor_main_menu_map_options.cc 2016-02-15 11:00:58 +0000
@@ -34,7 +34,6 @@
#include "ui_basic/multilinetextarea.h"
#include "ui_basic/textarea.h"
-
inline EditorInteractive & MainMenuMapOptions::eia() {
return dynamic_cast<EditorInteractive&>(*get_parent());
}
@@ -47,27 +46,26 @@
:
UI::Window
(&parent, "map_options",
- 0, 0, 350, 520,
+ 0, 0, 350, parent.get_inner_h() - 80,
_("Map Options")),
padding_(4),
indent_(10),
- labelh_(20),
+ labelh_(UI::g_fh1->render(as_uifont(UI::g_fh1->fontset()->representative_character()))->height() + 4),
checkbox_space_(25),
butw_((get_inner_w() - 3 * padding_) / 2),
- buth_(20),
max_w_(get_inner_w() - 2 * padding_),
ok_(
this, "ok",
- UI::g_fh1->fontset().is_rtl() ? padding_ : butw_ + 2 * padding_,
- get_inner_h() - padding_ - buth_,
- butw_, buth_,
+ UI::g_fh1->fontset()->is_rtl() ? padding_ : butw_ + 2 * padding_,
+ get_inner_h() - padding_ - labelh_,
+ butw_, labelh_,
g_gr->images().get("images/ui_basic/but5.png"),
_("OK")),
cancel_(
this, "cancel",
- UI::g_fh1->fontset().is_rtl() ? butw_ + 2 * padding_ : padding_,
- get_inner_h() - padding_ - buth_,
- butw_, buth_,
+ UI::g_fh1->fontset()->is_rtl() ? butw_ + 2 * padding_ : padding_,
+ get_inner_h() - padding_ - labelh_,
+ butw_, labelh_,
g_gr->images().get("images/ui_basic/but1.png"),
_("Cancel")),
tab_box_(this, padding_, padding_, UI::Box::Vertical, max_w_, get_inner_h(), 0),
@@ -81,14 +79,25 @@
author_(&main_box_, 0, 0, max_w_, g_gr->images().get("images/ui_basic/but1.png")),
size_(&main_box_, 0, 0, max_w_ - indent_, labelh_, ""),
- teams_list_(&teams_box_, 0, 0, max_w_, 60, UI::Align::kLeft, true),
+ teams_list_(&teams_box_, 0, 0, max_w_, 60, true),
modal_(modal) {
+ tab_box_.set_size(max_w_, get_inner_h() - labelh_ - 2 * padding_);
+ tabs_.set_size(max_w_, tab_box_.get_inner_h());
+ main_box_.set_size(max_w_, tabs_.get_inner_h() - 35);
+ tags_box_.set_size(max_w_, main_box_.get_h());
+ teams_box_.set_size(max_w_, main_box_.get_h());
+
+ // Calculate the overall remaining space for MultilineEditboxes.
+ uint32_t remaining_space = main_box_.get_inner_h() - 7 * labelh_ - 5 * indent_;
+
+ // We need less space for the hint and the description, but it should at least have 1 line height.
+ hint_ = new UI::MultilineEditbox(
+ &main_box_, 0, 0, max_w_, std::max(labelh_, remaining_space * 1 / 3), "", g_gr->images().get("images/ui_basic/but1.png"));
descr_ = new UI::MultilineEditbox(
- &main_box_, 0, 0, max_w_, 9 * labelh_, "", g_gr->images().get("images/ui_basic/but1.png"));
- hint_ = new UI::MultilineEditbox(
- &main_box_, 0, 0, max_w_, 4 * labelh_, "", g_gr->images().get("images/ui_basic/but1.png"));
+ &main_box_, 0, 0, max_w_, remaining_space - hint_->get_h(),
+ "", g_gr->images().get("images/ui_basic/but1.png"));
main_box_.add(new UI::Textarea(&main_box_, 0, 0, max_w_, labelh_, _("Map Name:")), UI::Align::kLeft);
main_box_.add(&name_, UI::Align::kLeft);
@@ -110,7 +119,6 @@
main_box_.add(&size_, UI::Align::kLeft);
main_box_.add_space(indent_);
- main_box_.set_size(max_w_, get_inner_h() - buth_ - 2 * padding_);
tags_box_.add(new UI::Textarea(&tags_box_, 0, 0, max_w_, labelh_, _("Tags:")), UI::Align::kLeft);
add_tag_checkbox(&tags_box_, "unbalanced", _("Unbalanced"));
@@ -119,7 +127,6 @@
add_tag_checkbox(&tags_box_, "2teams", _("Teams of 2"));
add_tag_checkbox(&tags_box_, "3teams", _("Teams of 3"));
add_tag_checkbox(&tags_box_, "4teams", _("Teams of 4"));
- tags_box_.set_size(max_w_, get_inner_h() - buth_ - 2 * padding_);
teams_box_.add(new UI::Textarea(&teams_box_, 0, 0, max_w_, labelh_, _("Suggested Teams:")),
UI::Align::kLeft);
@@ -132,16 +139,12 @@
unsigned int nr_players = static_cast<unsigned int>(eia().egbase().map().get_nrplayers());
std::string players = (boost::format(ngettext("%u Player", "%u Players", nr_players)) % nr_players).str();
teams_box_.add(new UI::Textarea(&teams_box_, 0, 0, max_w_, labelh_, players), UI::Align::kLeft);
- teams_box_.set_size(max_w_, get_inner_h() - buth_ - 2 * padding_);
tab_box_.add(&tabs_, UI::Align::kLeft, true);
tabs_.add("main_map_options",
g_gr->images().get("images/wui/menus/menu_toggle_minimap.png"), &main_box_, _("Main Options"));
tabs_.add("map_tags", g_gr->images().get("images/ui_basic/checkbox_checked.png"), &tags_box_, _("Tags"));
- tabs_.add("map_teams", g_gr->images().get("images/wui/editor/editor_menu_player_menu.png"),
- &teams_box_, _("Teams"));
- tabs_.set_size(max_w_, get_inner_h() - buth_ - 2 * padding_);
- tab_box_.set_size(max_w_, get_inner_h() - buth_ - 2 * padding_);
+ tabs_.add("map_teams", g_gr->images().get("images/wui/editor/editor_menu_player_menu.png"), &teams_box_, _("Teams"));
name_.changed.connect(boost::bind(&MainMenuMapOptions::changed, this));
author_.changed.connect(boost::bind(&MainMenuMapOptions::changed, this));
=== modified file 'src/editor/ui_menus/editor_main_menu_map_options.h'
--- src/editor/ui_menus/editor_main_menu_map_options.h 2016-01-16 12:55:14 +0000
+++ src/editor/ui_menus/editor_main_menu_map_options.h 2016-02-15 11:00:58 +0000
@@ -48,7 +48,7 @@
void clicked_cancel();
void add_tag_checkbox(UI::Box* box, std::string tag, std::string displ_name);
- const int padding_, indent_, labelh_, checkbox_space_, butw_, buth_, max_w_;
+ const unsigned int padding_, indent_, labelh_, checkbox_space_, butw_, max_w_;
UI::Button ok_, cancel_;
=== modified file 'src/editor/ui_menus/editor_main_menu_new_map.cc'
--- src/editor/ui_menus/editor_main_menu_new_map.cc 2016-02-07 09:16:18 +0000
+++ src/editor/ui_menus/editor_main_menu_new_map.cc 2016-02-15 11:00:58 +0000
@@ -93,7 +93,7 @@
cancel_button_.sigclicked.connect(boost::bind(&MainMenuNewMap::clicked_cancel, this));
ok_button_.sigclicked.connect(boost::bind(&MainMenuNewMap::clicked_create_map, this));
- if (UI::g_fh1->fontset().is_rtl()) {
+ if (UI::g_fh1->fontset()->is_rtl()) {
button_box_.add(&ok_button_, UI::Align::kLeft);
button_box_.add(&cancel_button_, UI::Align::kLeft);
} else {
=== modified file 'src/editor/ui_menus/editor_main_menu_random_map.cc'
--- src/editor/ui_menus/editor_main_menu_random_map.cc 2016-02-07 09:16:18 +0000
+++ src/editor/ui_menus/editor_main_menu_random_map.cc 2016-02-15 11:00:58 +0000
@@ -46,7 +46,7 @@
// UI elements
margin_(4),
box_width_(get_inner_w() - 2 * margin_),
- label_height_(UI::g_fh1->render(as_uifont("."))->height() + 2),
+ label_height_(UI::g_fh1->render(as_uifont(UI::g_fh1->fontset()->representative_character()))->height() + 2),
box_(this, margin_, margin_, UI::Box::Vertical, 0, 0, margin_),
// Size
width_(&box_, 0, 0, box_width_, box_width_ / 3,
@@ -292,7 +292,7 @@
// ---------- "Generate Map" button ----------
cancel_button_.sigclicked.connect(boost::bind(&MainMenuNewRandomMap::clicked_cancel, this));
ok_button_.sigclicked.connect(boost::bind(&MainMenuNewRandomMap::clicked_create_map, this));
- if (UI::g_fh1->fontset().is_rtl()) {
+ if (UI::g_fh1->fontset()->is_rtl()) {
button_box_.add(&ok_button_, UI::Align::kLeft);
button_box_.add(&cancel_button_, UI::Align::kLeft);
} else {
=== modified file 'src/editor/ui_menus/editor_main_menu_save_map_make_directory.cc'
--- src/editor/ui_menus/editor_main_menu_save_map_make_directory.cc 2016-02-06 10:59:09 +0000
+++ src/editor/ui_menus/editor_main_menu_save_map_make_directory.cc 2016-02-15 11:00:58 +0000
@@ -36,14 +36,14 @@
edit_(&vbox_, 0, 0, get_inner_w() - 2 * padding_, g_gr->images().get("images/ui_basic/but1.png")),
ok_button_(
this, "ok",
- UI::g_fh1->fontset().is_rtl() ? padding_ : get_inner_w() - butw_ - padding_,
+ UI::g_fh1->fontset()->is_rtl() ? padding_ : get_inner_w() - butw_ - padding_,
get_inner_h() - padding_ - buth_,
butw_, buth_,
g_gr->images().get("images/ui_basic/but5.png"),
_("OK")),
cancel_button_(
this, "cancel",
- UI::g_fh1->fontset().is_rtl() ?get_inner_w() - butw_ - padding_ : padding_,
+ UI::g_fh1->fontset()->is_rtl() ?get_inner_w() - butw_ - padding_ : padding_,
get_inner_h() - padding_ - buth_,
butw_, buth_,
g_gr->images().get("images/ui_basic/but1.png"),
=== modified file 'src/graphic/align.cc'
--- src/graphic/align.cc 2015-12-17 09:36:59 +0000
+++ src/graphic/align.cc 2016-02-15 11:00:58 +0000
@@ -26,7 +26,7 @@
// This mirrors the horizontal alignment for RTL languages.
Align mirror_alignment(Align alignment) {
- if (UI::g_fh1->fontset().is_rtl()) {
+ if (UI::g_fh1->fontset()->is_rtl()) {
switch (alignment) {
case Align::kBottomLeft:
alignment = Align::kBottomRight;
=== modified file 'src/graphic/font.cc'
--- src/graphic/font.cc 2016-01-28 05:24:34 +0000
+++ src/graphic/font.cc 2016-02-15 11:00:58 +0000
@@ -139,7 +139,7 @@
*/
Font * Font::get(const std::string & name, int size)
{
- size += UI::g_fh1->fontset().size_offset();
+ size += UI::g_fh1->fontset()->size_offset();
FontDescr descr;
descr.name = name;
descr.size = size;
=== modified file 'src/graphic/font_handler1.cc'
--- src/graphic/font_handler1.cc 2016-01-19 08:55:16 +0000
+++ src/graphic/font_handler1.cc 2016-02-15 11:00:58 +0000
@@ -108,10 +108,11 @@
class FontHandler1 : public IFontHandler1 {
public:
FontHandler1(ImageCache* image_cache)
- : texture_cache_(new TextureCache(RICHTEXT_TEXTURE_CACHE)),
- fontset_(new UI::FontSet(i18n::get_locale())),
- rt_renderer_(new RT::Renderer(image_cache, texture_cache_.get(), fontset_.get())),
- image_cache_(image_cache) {
+ : texture_cache_(new TextureCache(RICHTEXT_TEXTURE_CACHE)),
+ fontsets_(),
+ fontset_(fontsets_.get_fontset(i18n::get_locale())),
+ rt_renderer_(new RT::Renderer(image_cache, texture_cache_.get(), fontsets_)),
+ image_cache_(image_cache) {
}
virtual ~FontHandler1() {}
@@ -128,17 +129,18 @@
return image_cache_->insert(hash, std::move(image));
}
- UI::FontSet& fontset() const override {return *fontset_.get();}
+ UI::FontSet const * fontset() const override {return fontset_;}
void reinitialize_fontset() override {
- fontset_.reset(new UI::FontSet(i18n::get_locale()));
+ fontset_ = fontsets_.get_fontset(i18n::get_locale());
texture_cache_.get()->flush();
- rt_renderer_.reset(new RT::Renderer(image_cache_, texture_cache_.get(), fontset_.get()));
+ rt_renderer_.reset(new RT::Renderer(image_cache_, texture_cache_.get(), fontsets_));
}
private:
std::unique_ptr<TextureCache> texture_cache_;
- std::unique_ptr<UI::FontSet> fontset_; // The currently active FontSet
+ UI::FontSets fontsets_; // All fontsets
+ UI::FontSet const * fontset_; // The currently active FontSet
std::unique_ptr<RT::Renderer> rt_renderer_;
ImageCache* const image_cache_; // not owned
};
=== modified file 'src/graphic/font_handler1.h'
--- src/graphic/font_handler1.h 2016-01-09 15:27:05 +0000
+++ src/graphic/font_handler1.h 2016-02-15 11:00:58 +0000
@@ -51,7 +51,7 @@
virtual const Image* render(const std::string& text, uint16_t w = 0) = 0;
/// Returns the font handler's current FontSet
- virtual UI::FontSet& fontset() const = 0;
+ virtual UI::FontSet const * fontset() const = 0;
/// Loads the FontSet for the currently active locale into the
/// font handler. This needs to be called after the language of the
=== modified file 'src/graphic/richtext.cc'
--- src/graphic/richtext.cc 2016-01-31 21:03:15 +0000
+++ src/graphic/richtext.cc 2016-02-15 11:00:58 +0000
@@ -81,7 +81,7 @@
std::vector<std::string>::iterator it = result_words.begin();
// Reorder words for BiDi
- if (UI::g_fh1->fontset().is_rtl() && i18n::has_rtl_character(words)) {
+ if (UI::g_fh1->fontset()->is_rtl() && i18n::has_rtl_character(words)) {
std::string previous_word;
for (std::vector<std::string>::iterator source_it = words.begin();
source_it != words.end(); ++source_it) {
=== modified file 'src/graphic/text/bidi.cc'
--- src/graphic/text/bidi.cc 2016-01-18 19:35:25 +0000
+++ src/graphic/text/bidi.cc 2016-02-15 11:00:58 +0000
@@ -139,32 +139,6 @@
};
-// http://unicode.org/faq/blocks_ranges.html
-// http://unicode-table.com/en/blocks/
-const std::set<UBlockCode> kCJKCodeBlocks = {
- {
- UBlockCode::UBLOCK_CJK_COMPATIBILITY,
- UBlockCode::UBLOCK_CJK_COMPATIBILITY_FORMS,
- UBlockCode::UBLOCK_CJK_COMPATIBILITY_IDEOGRAPHS,
- UBlockCode::UBLOCK_CJK_COMPATIBILITY_IDEOGRAPHS_SUPPLEMENT,
- UBlockCode::UBLOCK_CJK_RADICALS_SUPPLEMENT,
- UBlockCode::UBLOCK_CJK_STROKES,
- UBlockCode::UBLOCK_CJK_SYMBOLS_AND_PUNCTUATION,
- UBlockCode::UBLOCK_CJK_UNIFIED_IDEOGRAPHS,
- UBlockCode::UBLOCK_CJK_UNIFIED_IDEOGRAPHS_EXTENSION_A,
- UBlockCode::UBLOCK_CJK_UNIFIED_IDEOGRAPHS_EXTENSION_B,
- UBlockCode::UBLOCK_CJK_UNIFIED_IDEOGRAPHS_EXTENSION_C,
- UBlockCode::UBLOCK_CJK_UNIFIED_IDEOGRAPHS_EXTENSION_D,
- UBlockCode::UBLOCK_HIRAGANA,
- UBlockCode::UBLOCK_KATAKANA,
- },
-};
-
-bool is_cjk_character(UChar32 c) {
- return kCJKCodeBlocks.count(ublock_getCode(c)) == 1;
-}
-
-
// Need to mirror () etc. for LTR languages, so we're sticking them in a map.
const std::map<UChar, UChar> kSymmetricChars = {
{0x0028, 0x0029}, // ()
@@ -441,15 +415,60 @@
{0xFCF4, 0xFC62}, // Shadda with Kasra
};
-const std::set<std::string> kRTLScripts = {
- {"arabic", "devanagari", "hebrew", "mandaic", "nko", "samaritan", "syriac", "thaana"},
+const std::set<UI::FontSets::Selector> kLTRScripts = {
+ // We omit the default fontset, because we won't define code blocks for it - it's a catch-all.
+ UI::FontSets::Selector::kCJK,
+ UI::FontSets::Selector::kMyanmar,
+ UI::FontSets::Selector::kSinhala
+};
+
+// http://unicode.org/faq/blocks_ranges.html
+// http://unicode-table.com/en/blocks/
+const std::map<UI::FontSets::Selector, std::set<UBlockCode>> kLTRCodeBlocks = {
+ {UI::FontSets::Selector::kCJK, {
+ UBlockCode::UBLOCK_CJK_COMPATIBILITY,
+ UBlockCode::UBLOCK_CJK_COMPATIBILITY_FORMS,
+ UBlockCode::UBLOCK_CJK_COMPATIBILITY_IDEOGRAPHS,
+ UBlockCode::UBLOCK_CJK_COMPATIBILITY_IDEOGRAPHS_SUPPLEMENT,
+ UBlockCode::UBLOCK_CJK_RADICALS_SUPPLEMENT,
+ UBlockCode::UBLOCK_CJK_STROKES,
+ UBlockCode::UBLOCK_CJK_SYMBOLS_AND_PUNCTUATION,
+ UBlockCode::UBLOCK_CJK_UNIFIED_IDEOGRAPHS,
+ UBlockCode::UBLOCK_CJK_UNIFIED_IDEOGRAPHS_EXTENSION_A,
+ UBlockCode::UBLOCK_CJK_UNIFIED_IDEOGRAPHS_EXTENSION_B,
+ UBlockCode::UBLOCK_CJK_UNIFIED_IDEOGRAPHS_EXTENSION_C,
+ UBlockCode::UBLOCK_CJK_UNIFIED_IDEOGRAPHS_EXTENSION_D,
+ UBlockCode::UBLOCK_HIRAGANA,
+ UBlockCode::UBLOCK_KATAKANA,
+ UBlockCode::UBLOCK_KATAKANA_PHONETIC_EXTENSIONS,
+ UBlockCode::UBLOCK_ENCLOSED_CJK_LETTERS_AND_MONTHS,
+ UBlockCode::UBLOCK_HANGUL_COMPATIBILITY_JAMO,
+ UBlockCode::UBLOCK_HANGUL_JAMO,
+ UBlockCode::UBLOCK_HANGUL_JAMO_EXTENDED_A,
+ UBlockCode::UBLOCK_HANGUL_JAMO_EXTENDED_B,
+ UBlockCode::UBLOCK_HANGUL_SYLLABLES,
+ }},
+ {UI::FontSets::Selector::kMyanmar, {
+ UBlockCode::UBLOCK_MYANMAR,
+ UBlockCode::UBLOCK_MYANMAR_EXTENDED_A,
+ }},
+ {UI::FontSets::Selector::kSinhala, {
+ UBlockCode::UBLOCK_SINHALA,
+ }},
+};
+
+const std::set<UI::FontSets::Selector> kRTLScripts = {
+ // Add "mandaic", "nko", "samaritan", "syriac", "thaana" if we get these languages.
+ UI::FontSets::Selector::kArabic,
+ UI::FontSets::Selector::kDevanagari,
+ UI::FontSets::Selector::kHebrew
};
// http://unicode.org/faq/blocks_ranges.html
// http://unicode-table.com/en/blocks/
// TODO(GunChleoc): We might need some more here - let's see how this goes.
-const std::map<std::string, std::set<UBlockCode>> kRTLCodeBlocks = {
- {"arabic", {
+const std::map<UI::FontSets::Selector, std::set<UBlockCode>> kRTLCodeBlocks = {
+ {UI::FontSets::Selector::kArabic, {
UBlockCode::UBLOCK_ARABIC,
UBlockCode::UBLOCK_ARABIC_SUPPLEMENT,
UBlockCode::UBLOCK_ARABIC_EXTENDED_A,
@@ -457,13 +476,15 @@
UBlockCode::UBLOCK_ARABIC_PRESENTATION_FORMS_B,
UBlockCode::UBLOCK_ARABIC_MATHEMATICAL_ALPHABETIC_SYMBOLS,
}},
- {"devanagari", {
+ {UI::FontSets::Selector::kDevanagari, {
UBlockCode::UBLOCK_DEVANAGARI,
UBlockCode::UBLOCK_DEVANAGARI_EXTENDED,
+ UBlockCode::UBLOCK_VEDIC_EXTENSIONS,
}},
- {"hebrew", {
+ {UI::FontSets::Selector::kHebrew, {
UBlockCode::UBLOCK_HEBREW,
}},
+ /* Activate when we get any of these languages
{"mandaic", {
UBlockCode::UBLOCK_MANDAIC,
}},
@@ -479,12 +500,24 @@
{"thaana", {
UBlockCode::UBLOCK_THAANA,
}},
+ */
};
-// True if 'c' is included in one of the kRTLCodeBlocks.
+// True if the character is in one of the script's code blocks
+bool is_script_character(UChar32 c, UI::FontSets::Selector script) {
+ UBlockCode code = ublock_getCode(c);
+ if (kRTLCodeBlocks.count(script) == 1 && kRTLCodeBlocks.at(script).count(code) == 1) {
+ return true;
+ }
+ if (kLTRCodeBlocks.count(script) == 1 && kLTRCodeBlocks.at(script).count(code) == 1) {
+ return true;
+ }
+ return false;
+}
+
bool is_rtl_character(UChar32 c) {
UBlockCode code = ublock_getCode(c);
- for (std::string script : kRTLScripts) {
+ for (UI::FontSets::Selector script : kRTLScripts) {
assert(kRTLCodeBlocks.count(script) == 1);
if ((kRTLCodeBlocks.at(script).count(code) == 1)) {
return true;
@@ -493,27 +526,6 @@
return false;
}
-bool is_arabic_character(UChar32 c) {
- UBlockCode code = ublock_getCode(c);
- assert(kRTLCodeBlocks.count("arabic") == 1);
- return (kRTLCodeBlocks.at("arabic").count(code) == 1);
-}
-
-
-// True if a string contains a character from an Arabic code block
-bool has_arabic_character(const char* input) {
- bool result = false;
- const icu::UnicodeString parseme(input);
- for (int32_t i = 0; i < parseme.length(); ++i) {
- if (is_arabic_character(parseme.char32At(i))) {
- result = true;
- break;
- }
- }
- return result;
-}
-
-
// Helper function for make_ligatures.
// Arabic word characters have 4 forms to connect to each other:
// Isolated, Initial, Medial, and Final.
@@ -557,37 +569,33 @@
namespace i18n {
-// True if one of te first 'limit' characters in 'input' as UnicodeString is an RTL character
-// according to is_rtl_character(UChar32 c)
+// True if a string does not contain Latin characters.
+// Checks for the first 'limit' characters maximum.
bool has_rtl_character(const char* input, int32_t limit) {
- bool result = false;
const icu::UnicodeString parseme(input);
for (int32_t i = 0; i < parseme.length() && i < limit; ++i) {
if (is_rtl_character(parseme.char32At(i))) {
- result = true;
- break;
+ return true;
}
}
- return result;
+ return false;
}
// True if the strings do not contain Latin characters
bool has_rtl_character(std::vector<std::string> input) {
- bool result = false;
for (const std::string& string: input) {
if (has_rtl_character(string.c_str())) {
- result = true;
- break;
+ return true;
}
}
- return result;
+ return false;
}
// Contracts glyphs into their ligatures
std::string make_ligatures(const char* input) {
// We only have defined ligatures for Arabic at the moment.
- if (!has_arabic_character(input)) {
+ if (!has_script_character(input, UI::FontSets::Selector::kArabic)) {
return input;
}
const icu::UnicodeString parseme(input);
@@ -724,17 +732,36 @@
return icustring2string(temp);
}
-// True if a string contains a character from a CJK code block
-bool has_cjk_character(const char* input) {
- bool result = false;
+// True if a string contains a character from the script's code blocks
+bool has_script_character(const char* input, UI::FontSets::Selector script) {
const icu::UnicodeString parseme(input);
for (int32_t i = 0; i < parseme.length(); ++i) {
- if (is_cjk_character(parseme.char32At(i))) {
- result = true;
- break;
+ if (is_script_character(parseme.char32At(i), script)) {
+ return true;
}
}
- return result;
+ return false;
+}
+
+
+UI::FontSet const * find_fontset(const char* word, const UI::FontSets& fontsets) {
+ UI::FontSets::Selector selector;
+ if (has_script_character(word, UI::FontSets::Selector::kArabic)) {
+ selector = UI::FontSets::Selector::kArabic;
+ } else if (has_script_character(word, UI::FontSets::Selector::kCJK)) {
+ selector = UI::FontSets::Selector::kCJK;
+ } else if (has_script_character(word, UI::FontSets::Selector::kDevanagari)) {
+ selector = UI::FontSets::Selector::kDevanagari;
+ } else if (has_script_character(word, UI::FontSets::Selector::kHebrew)) {
+ selector = UI::FontSets::Selector::kHebrew;
+ } else if (has_script_character(word, UI::FontSets::Selector::kMyanmar)) {
+ selector = UI::FontSets::Selector::kMyanmar;
+ } else if (has_script_character(word, UI::FontSets::Selector::kSinhala)) {
+ selector = UI::FontSets::Selector::kSinhala;
+ } else {
+ selector = UI::FontSets::Selector::kDefault;
+ }
+ return fontsets.get_fontset(selector);
}
// Split a string of CJK characters into units that can have line breaks between them.
=== modified file 'src/graphic/text/bidi.h'
--- src/graphic/text/bidi.h 2016-01-06 12:12:47 +0000
+++ src/graphic/text/bidi.h 2016-02-15 11:00:58 +0000
@@ -27,16 +27,21 @@
#include <unicode/uchar.h>
#include <unicode/unistr.h>
+#include "graphic/text/font_set.h"
+
// BiDi support for RTL languages
namespace i18n {
+
std::string make_ligatures(const char* input);
std::string line2bidi(const char* input);
std::vector<std::string> split_cjk_word(const char* input);
bool has_rtl_character(const char* input, int32_t limit = std::numeric_limits<int32_t>::max());
bool has_rtl_character(std::vector<std::string> input);
+// True if a string contains a character from the script's code blocks
+bool has_script_character(const char* input, UI::FontSets::Selector script);
+UI::FontSet const * find_fontset(const char* word, const UI::FontSets& fontsets);
std::string icustring2string(const UnicodeString& convertme);
std::string icuchar2string(const UChar& convertme);
-bool has_cjk_character(const char* input);
bool cannot_start_line(const UChar& c);
bool cannot_end_line(const UChar& c);
bool is_diacritic(const UChar& c);
=== modified file 'src/graphic/text/font_set.cc'
--- src/graphic/text/font_set.cc 2016-02-07 15:47:25 +0000
+++ src/graphic/text/font_set.cc 2016-02-15 11:00:58 +0000
@@ -20,7 +20,6 @@
#include "graphic/text/font_set.h"
#include <cstdlib>
-#include <memory>
#include <boost/algorithm/string.hpp>
#include <boost/format.hpp>
@@ -33,8 +32,8 @@
namespace UI {
-FontSet::FontSet(const std::string& localename) {
- parse_font_for_locale(localename);
+FontSet::FontSet(const std::string& fontset_name) {
+ parse_fontset(fontset_name);
assert(!serif_.empty());
assert(!serif_bold_.empty());
assert(!serif_italic_.empty());
@@ -49,6 +48,7 @@
assert(!condensed_bold_italic_.empty());
}
+const std::string& FontSet::name() const {return name_;}
const std::string& FontSet::serif() const {return serif_;}
const std::string& FontSet::serif_bold() const {return serif_bold_;}
const std::string& FontSet::serif_italic() const {return serif_italic_;}
@@ -61,14 +61,13 @@
const std::string& FontSet::condensed_bold() const {return condensed_bold_;}
const std::string& FontSet::condensed_italic() const {return condensed_italic_;}
const std::string& FontSet::condensed_bold_italic() const {return condensed_bold_italic_;}
+const std::string& FontSet::representative_character() const {return representative_character_;}
uint16_t FontSet::size_offset() const {return size_offset_;}
bool FontSet::is_rtl() const {return is_rtl_;}
// Loads font info from config files, depending on the localename
-void FontSet::parse_font_for_locale(const std::string& localename) {
- std::string fontsetname = "default";
- std::string actual_localename = localename;
+void FontSet::parse_fontset(const std::string& fontset_name) {
std::string direction_string;
size_offset_ = 0;
LuaInterface lua;
@@ -76,67 +75,31 @@
// Read default fontset. It defines the fallback fonts and needs to always be there and complete.
// This way, we will always have fonts, even if we run into an exception further down.
std::unique_ptr<LuaTable> fonts_table(lua.run_script("i18n/fonts.lua"));
- fonts_table->do_not_warn_about_unaccessed_keys(); // We are only reading partial information as needed
+ fonts_table->do_not_warn_about_unaccessed_keys(); // We are only reading one fontset + the default fontset
+ // Initialize with default fontset
std::unique_ptr<LuaTable> default_font_table = fonts_table->get_table("default");
-
set_fonts(*default_font_table, kFallbackFont);
direction_string = default_font_table->get_string("direction");
+ representative_character_ = default_font_table->get_string("representative_character");
size_offset_ = default_font_table->get_int("size_offset");
- // Now try to get the fontset for the actual locale.
- try {
- std::unique_ptr<LuaTable> all_locales(lua.run_script(("i18n/locales.lua")));
- all_locales->do_not_warn_about_unaccessed_keys();
-
- // Locale identifiers can look like this: ca_ES@xxxxxxxxxxxx-8
- if (localename.empty()) {
- std::vector<std::string> parts;
- boost::split(parts, i18n::get_locale(), boost::is_any_of("."));
- actual_localename = parts[0];
-
- if (!all_locales->has_key(actual_localename)) {
- boost::split(parts, parts[0], boost::is_any_of("@"));
- actual_localename = parts[0];
-
- if (!all_locales->has_key(actual_localename)) {
- boost::split(parts, parts[0], boost::is_any_of("_"));
- actual_localename = parts[0];
- }
- }
- }
-
- // Find out which fontset to use from the locale
- if (all_locales->has_key(actual_localename)) {
- try {
- std::unique_ptr<LuaTable> locale_table = all_locales->get_table(actual_localename);
- locale_table->do_not_warn_about_unaccessed_keys();
- fontsetname = locale_table->get_string("font");
-
- // Read the fontset for the current locale.
- try {
- if (!fonts_table->has_key(fontsetname)) {
- log("Font set '%s' for locale '%s' does not exist; using default instead.\n",
- fontsetname.c_str(), actual_localename.c_str());
- fontsetname = "default";
- }
- std::unique_ptr<LuaTable> font_set_table = fonts_table->get_table(fontsetname);
- font_set_table->do_not_warn_about_unaccessed_keys();
-
- set_fonts(*font_set_table, sans_);
- direction_string = get_string_with_default(*font_set_table, "direction", "ltr");
- if (font_set_table->has_key("size_offset")) {
- size_offset_ = font_set_table->get_int("size_offset");
- }
- } catch (LuaError& err) {
- log("Could not read font set '%s': %s\n", fontsetname.c_str(), err.what());
- }
- } catch (const LuaError& err) {
- log("Error loading locale '%s' from file: %s\n", actual_localename.c_str(), err.what());
- }
- }
- } catch (const LuaError& err) {
- log("Could not read locales information from file: %s\n", err.what());
+ // Read the actual fontset.
+ try {
+ if (!fonts_table->has_key(fontset_name)) {
+ throw LuaError("Font set does not exist");
+ }
+ name_ = fontset_name;
+ std::unique_ptr<LuaTable> font_set_table = fonts_table->get_table(fontset_name);
+ representative_character_ = font_set_table->get_string("representative_character");
+
+ set_fonts(*font_set_table, serif_);
+ direction_string = get_string_with_default(*font_set_table, "direction", "ltr");
+ if (font_set_table->has_key("size_offset")) {
+ size_offset_ = font_set_table->get_int("size_offset");
+ }
+ } catch (LuaError& err) {
+ log("Could not read font set '%s': %s\n", fontset_name.c_str(), err.what());
}
is_rtl_ = false;
@@ -169,4 +132,88 @@
*bold_italic = get_string_with_default(table, (boost::format("%s_bold_italic") % key).str(), *bold);
}
+FontSets::FontSets() {
+ std::map<std::string, FontSets::Selector> fontset_selectors = {
+ {"default", FontSets::Selector::kDefault},
+ {"arabic", FontSets::Selector::kArabic},
+ {"cjk", FontSets::Selector::kCJK},
+ {"devanagari", FontSets::Selector::kDevanagari},
+ {"hebrew", FontSets::Selector::kHebrew},
+ {"myanmar", FontSets::Selector::kMyanmar},
+ {"sinhala", FontSets::Selector::kSinhala},
+ };
+
+ LuaInterface lua;
+
+ // Read all fontsets
+ std::unique_ptr<LuaTable> fontsets_table(lua.run_script("i18n/fonts.lua"));
+ for (const std::string& fontset_name : fontsets_table->keys<std::string>()) {
+ assert(fontset_selectors.count(fontset_name) == 1);
+ FontSets::Selector selector = fontset_selectors.at(fontset_name);
+ fontsets[selector] = std::unique_ptr<FontSet>(new FontSet(fontset_name));
+ }
+ fontsets_table->do_not_warn_about_unaccessed_keys(); // We are only reading partial information as needed
+
+ // Now assign a fontset to each locale
+ FilenameSet files = g_fs->list_directory("locale");
+ std::string localename;
+
+ try { // Begin read locales table
+ std::unique_ptr<LuaTable> all_locales(lua.run_script("i18n/locales.lua"));
+ all_locales->do_not_warn_about_unaccessed_keys(); // We are only reading partial information as needed
+
+ for (const std::string& filename : files) { // Begin scan locales directory
+ char const* const path = filename.c_str();
+ if (!strcmp(FileSystem::fs_filename(path), ".") ||
+ !strcmp(FileSystem::fs_filename(path), "..") || !g_fs->is_directory(path)) {
+ continue;
+ }
+
+ try { // Begin read locale from table
+ localename = g_fs->filename_without_ext(path);
+ std::unique_ptr<LuaTable> locale_table = all_locales->get_table(localename);
+ locale_table->do_not_warn_about_unaccessed_keys(); // We are only reading the fontset names
+ const std::string fontsetname = locale_table->get_string("font");
+ FontSets::Selector selector = FontSets::Selector::kDefault;
+ if (fontset_selectors.count(fontsetname) == 1) {
+ selector = fontset_selectors.at(fontsetname);
+ } else {
+ log("No selector for fontset: %s in locale: %s. Falling back to default\n",
+ fontsetname.c_str(), localename.c_str());
+ }
+ locale_fontsets.insert(std::make_pair(localename, selector));
+ } catch (const WException&) {
+ log("Could not read locale fontset for: %s\n", localename.c_str());
+ locale_fontsets.insert(std::make_pair(localename, FontSets::Selector::kDefault));
+ } // End read locale from table
+ } // End scan locales directory
+ } catch (const LuaError& err) {
+ log("Could not read locales fontset information from file: %s\n", err.what());
+ return; // Nothing more can be done now.
+ } // End read locales table
+
+ // Check if all selectors have a fontset
+ for (int i = static_cast<int>(FontSets::Selector::kDefault);
+ i < static_cast<int>(FontSets::Selector::kUnknown);
+ ++i) {
+ if (fontsets.count(static_cast<FontSets::Selector>(i)) != 1) {
+ log("No fontset defined for FontSets::Selector enum member #%d\n", i);
+ }
+ }
+}
+
+FontSet const * FontSets::get_fontset(FontSets::Selector selector) const {
+ assert(fontsets.count(selector) == 1);
+ return fontsets.at(selector).get();
+}
+
+FontSet const * FontSets::get_fontset(const std::string& locale) const {
+ FontSets::Selector selector = FontSets::Selector::kDefault;
+ if (locale_fontsets.count(locale) == 1) {
+ selector = locale_fontsets.at(locale);
+ }
+ assert(fontsets.count(selector) == 1);
+ return fontsets.at(selector).get();
+}
+
}
=== modified file 'src/graphic/text/font_set.h'
--- src/graphic/text/font_set.h 2016-02-07 17:11:30 +0000
+++ src/graphic/text/font_set.h 2016-02-15 11:00:58 +0000
@@ -20,8 +20,11 @@
#ifndef WL_GRAPHIC_TEXT_FONT_SET_H
#define WL_GRAPHIC_TEXT_FONT_SET_H
+#include <map>
+#include <memory>
#include <string>
+#include "base/macros.h"
#include "scripting/lua_table.h"
namespace UI {
@@ -37,8 +40,11 @@
static constexpr const char* kFallbackFont = "DejaVu/DejaVuSans.ttf";
- /// Create the fontset for a locale from configuration file
- FontSet(const std::string& localename);
+ /// Create a fontset from i18n/fonts.lua
+ FontSet(const std::string& fontset_name);
+
+ // The fontset's name
+ const std::string& name() const;
/// All functions below return the path of the font file used for the given
/// style.
@@ -54,14 +60,16 @@
const std::string& condensed_bold() const;
const std::string& condensed_italic() const;
const std::string& condensed_bold_italic() const;
+ const std::string& representative_character() const;
+ // Some scripts need more vertical space than the default font, e.g. Arabic
uint16_t size_offset() const;
+ // Returns true iff the fontset's script is written from right to left.
bool is_rtl() const;
private:
- /// Parses font information for the given 'localename' from Lua files.
- /// Each locale in data/i18n/locales.lua defines which fontset to use.
- /// The fontset definitions are in data/i18n/fonts.lua
- void parse_font_for_locale(const std::string& localename);
+ /// Parses font information for the given fontset name from Lua.
+ /// The fontset definitions are in i18n/fonts.lua
+ void parse_fontset(const std::string& fontset_name);
/// Reads and sets the fonts from 'table', using 'fallback' as the fallback font file.
void set_fonts(const LuaTable& table, const std::string& fallback);
@@ -71,6 +79,7 @@
std::string* basic, std::string* bold,
std::string* italic, std::string* bold_italic);
+ std::string name_;
std::string serif_;
std::string serif_bold_;
std::string serif_italic_;
@@ -83,10 +92,41 @@
std::string condensed_bold_;
std::string condensed_italic_;
std::string condensed_bold_italic_;
+ std::string representative_character_;
uint16_t size_offset_;
bool is_rtl_;
-};
-
-}
+ DISALLOW_COPY_AND_ASSIGN(FontSet);
+};
+
+/// A repository of all available fontsets
+struct FontSets {
+ enum class Selector {
+ kDefault,
+ kArabic,
+ kCJK,
+ kDevanagari,
+ kHebrew,
+ kMyanmar,
+ kSinhala,
+ kUnknown
+ };
+
+ FontSets();
+
+ /// Get the fontset corresponding to the given selector.
+ const FontSet* get_fontset(UI::FontSets::Selector selector) const;
+ /// Get the fontset used by the given locale ISO code.
+ const FontSet* get_fontset(const std::string& locale) const;
+
+private:
+ // Maps locale ISO codes to fontset selectors.
+ std::map<std::string, UI::FontSets::Selector> locale_fontsets;
+ // Contains all available fontsets, to be accessed by their selector.
+ std::map<UI::FontSets::Selector, std::unique_ptr<UI::FontSet>> fontsets;
+
+ DISALLOW_COPY_AND_ASSIGN(FontSets);
+};
+
+} // namespace UI
#endif // end of include guard: WL_GRAPHIC_TEXT_FONT_SET_H
=== modified file 'src/graphic/text/rt_render.cc'
--- src/graphic/text/rt_render.cc 2016-02-07 16:31:06 +0000
+++ src/graphic/text/rt_render.cc 2016-02-15 11:00:58 +0000
@@ -29,6 +29,7 @@
#include <boost/algorithm/string/predicate.hpp>
#include <boost/format.hpp>
+#include "base/i18n.h"
#include "base/log.h"
#include "base/macros.h"
#include "base/point.h"
@@ -41,6 +42,7 @@
#include "graphic/text/font_io.h"
#include "graphic/text/font_set.h"
#include "graphic/text/rt_parse.h"
+#include "graphic/text/sdl_ttf_font.h"
#include "graphic/text/textstream.h"
#include "graphic/text_layout.h"
#include "graphic/texture.h"
@@ -59,12 +61,11 @@
};
struct NodeStyle {
- const UI::FontSet* const fontset; // Not owned.
+ UI::FontSet const * fontset;
string font_face;
uint16_t font_size;
RGBColor font_color;
int font_style;
- bool is_rtl;
uint8_t spacing;
UI::Align halign;
@@ -72,6 +73,103 @@
string reference;
};
+
+/*
+ * This class makes sure that we only load each font file once.
+ */
+class FontCache {
+public:
+ FontCache() = default;
+ ~FontCache();
+
+ IFont& get_font(NodeStyle* style);
+
+private:
+ struct FontDescr {
+ string face;
+ uint16_t size;
+
+ bool operator<(const FontDescr& o) const {
+ return size < o.size || (size == o.size && face < o.face);
+ }
+ };
+ using FontMap = map<FontDescr, IFont*>;
+ using FontMapPair = pair<const FontDescr, std::unique_ptr<IFont>>;
+
+ FontMap m_fontmap;
+
+ DISALLOW_COPY_AND_ASSIGN(FontCache);
+};
+
+FontCache::~FontCache() {
+ for (FontMap::reference& entry : m_fontmap) {
+ delete entry.second;
+ }
+}
+
+IFont& FontCache::get_font(NodeStyle* ns) {
+ if (ns->font_face == "condensed") {
+ ns->font_face = ns->fontset->condensed();
+ } else if (ns->font_face == "serif") {
+ ns->font_face = ns->fontset->serif();
+ } else if (ns->font_face == "sans") {
+ ns->font_face = ns->fontset->sans();
+ }
+ const bool is_bold = ns->font_style & IFont::BOLD;
+ const bool is_italic = ns->font_style & IFont::ITALIC;
+ if (is_bold && is_italic) {
+ if (ns->font_face == ns->fontset->condensed() ||
+ ns->font_face == ns->fontset->condensed_bold() ||
+ ns->font_face == ns->fontset->condensed_italic()) {
+ ns->font_face = ns->fontset->condensed_bold_italic();
+ } else if (ns->font_face == ns->fontset->serif() ||
+ ns->font_face == ns->fontset->serif_bold() ||
+ ns->font_face == ns->fontset->serif_italic()) {
+ ns->font_face = ns->fontset->serif_bold_italic();
+ } else {
+ ns->font_face = ns->fontset->sans_bold_italic();
+ }
+ ns->font_style &= ~IFont::ITALIC;
+ ns->font_style &= ~IFont::BOLD;
+ } else if (is_bold) {
+ if (ns->font_face == ns->fontset->condensed()) {
+ ns->font_face = ns->fontset->condensed_bold();
+ } else if (ns->font_face == ns->fontset->serif()) {
+ ns->font_face = ns->fontset->serif_bold();
+ } else {
+ ns->font_face = ns->fontset->sans_bold();
+ }
+ ns->font_style &= ~IFont::BOLD;
+ } else if (is_italic) {
+ if (ns->font_face == ns->fontset->condensed()) {
+ ns->font_face = ns->fontset->condensed_italic();
+ } else if (ns->font_face == ns->fontset->serif()) {
+ ns->font_face = ns->fontset->serif_italic();
+ } else {
+ ns->font_face = ns->fontset->sans_italic();
+ }
+ ns->font_style &= ~IFont::ITALIC;
+ }
+
+ uint16_t font_size = ns->font_size + ns->fontset->size_offset();
+
+ FontDescr fd = {ns->font_face, font_size};
+ FontMap::iterator i = m_fontmap.find(fd);
+ if (i != m_fontmap.end())
+ return *i->second;
+
+ std::unique_ptr<IFont> font;
+ try {
+ font.reset(load_font(ns->font_face, font_size));
+ } catch (FileNotFoundError& e) {
+ log("Font file not found. Falling back to sans: %s\n%s\n", ns->font_face.c_str(), e.what());
+ font.reset(load_font(ns->fontset->sans(), font_size));
+ }
+ assert(font != nullptr);
+
+ return *m_fontmap.insert(std::make_pair(fd, font.release())).first->second;
+}
+
struct Reference {
Rect dim;
string ref;
@@ -121,16 +219,16 @@
void set_halign(UI::Align ghalign) {m_halign = ghalign;}
UI::Align valign() {return m_valign;}
void set_valign(UI::Align gvalign) {m_valign = gvalign;}
- void set_x(uint16_t nx) {m_x = nx;}
- void set_y(uint16_t ny) {m_y = ny;}
- uint16_t x() {return m_x;}
- uint16_t y() {return m_y;}
+ void set_x(int32_t nx) {m_x = nx;}
+ void set_y(int32_t ny) {m_y = ny;}
+ int32_t x() {return m_x;}
+ int32_t y() {return m_y;}
private:
Floating m_floating;
UI::Align m_halign;
UI::Align m_valign;
- uint16_t m_x, m_y;
+ int32_t m_x, m_y;
};
class Layout {
@@ -268,11 +366,16 @@
// Go over again and adjust position for VALIGN
for (RenderNode* n : nodes_in_line) {
uint16_t space = line_height - n->height();
- if (!space || n->valign() == UI::Align::kBottom)
+ if (!space || n->valign() == UI::Align::kBottom) {
continue;
- if (n->valign() == UI::Align::kCenter)
+ }
+ if (n->valign() == UI::Align::kCenter) {
space /= 2;
- n->set_y(n->y() - space);
+ }
+ // Space can become negative, for example when we have mixed fontsets on the same line
+ // (e.g. "default" and "arabic"), due to differing font heights and hotspots.
+ // So, we fix the sign.
+ n->set_y(std::abs(n->y() - space));
}
rv.insert(rv.end(), nodes_in_line.begin(), nodes_in_line.end());
@@ -317,7 +420,7 @@
*/
class TextNode : public RenderNode {
public:
- TextNode(IFont& font, NodeStyle&, const string& txt);
+ TextNode(FontCache& font, NodeStyle&, const string& txt);
virtual ~TextNode() {}
uint16_t width() override {return m_w;}
@@ -338,20 +441,22 @@
uint16_t m_w, m_h;
const string m_txt;
NodeStyle m_s;
- IFont& m_font;
+ FontCache& m_fontcache;
+ SdlTtfFont& font_;
};
-TextNode::TextNode(IFont& font, NodeStyle& ns, const string& txt)
- : RenderNode(ns), m_txt(txt), m_s(ns), m_font(font)
+TextNode::TextNode(FontCache& font, NodeStyle& ns, const string& txt)
+ : RenderNode(ns), m_txt(txt), m_s(ns), m_fontcache(font),
+ font_(dynamic_cast<SdlTtfFont&>(m_fontcache.get_font(&m_s)))
{
- m_font.dimensions(m_txt, ns.font_style, &m_w, &m_h);
+ font_.dimensions(m_txt, ns.font_style, &m_w, &m_h);
}
uint16_t TextNode::hotspot_y() {
- return m_font.ascent(m_s.font_style);
+ return font_.ascent(m_s.font_style);
}
Texture* TextNode::render(TextureCache* texture_cache) {
- const Texture& img = m_font.render(m_txt, m_s.font_color, m_s.font_style, texture_cache);
+ const Texture& img = font_.render(m_txt, m_s.font_color, m_s.font_style, texture_cache);
Texture* rv = new Texture(img.width(), img.height());
rv->blit(Rect(0, 0, img.width(), img.height()),
img,
@@ -367,7 +472,7 @@
*/
class FillingTextNode : public TextNode {
public:
- FillingTextNode(IFont& font, NodeStyle& ns, uint16_t w, const string& txt, bool expanding = false) :
+ FillingTextNode(FontCache& font, NodeStyle& ns, uint16_t w, const string& txt, bool expanding = false) :
TextNode(font, ns, txt), m_expanding(expanding) {
m_w = w;
}
@@ -381,7 +486,7 @@
bool m_expanding;
};
Texture* FillingTextNode::render(TextureCache* texture_cache) {
- const Texture& t = m_font.render(m_txt, m_s.font_color, m_s.font_style, texture_cache);
+ const Texture& t = font_.render(m_txt, m_s.font_color, m_s.font_style, texture_cache);
Texture* rv = new Texture(m_w, m_h);
for (uint16_t curx = 0; curx < m_w; curx += t.width()) {
Rect srcrect(Point(0, 0), min<int>(t.width(), m_w - curx), m_h);
@@ -396,7 +501,7 @@
*/
class WordSpacerNode : public TextNode {
public:
- WordSpacerNode(IFont& font, NodeStyle& ns) : TextNode(font, ns, " ") {}
+ WordSpacerNode(FontCache& font, NodeStyle& ns) : TextNode(font, ns, " ") {}
static void show_spaces(bool t) {m_show_spaces = t;}
Texture* render(TextureCache* texture_cache) override {
@@ -491,6 +596,7 @@
uint16_t width() override {return m_w + m_margin.left + m_margin.right;}
uint16_t height() override {return m_h + m_margin.top + m_margin.bottom;}
uint16_t hotspot_y() override {return height();}
+
Texture* render(TextureCache* texture_cache) override {
Texture* rv = new Texture(width(), height());
rv->fill_rect(Rect(0, 0, rv->width(), rv->height()), RGBAColor(255, 255, 255, 0));
@@ -588,112 +694,17 @@
}
// End: Helper Stuff
-/*
- * This class makes sure that we only load each font file once.
- */
-class FontCache {
-public:
- FontCache() = default;
- ~FontCache();
-
- IFont& get_font(NodeStyle* style);
-
-private:
- struct FontDescr {
- string face;
- uint16_t size;
-
- bool operator<(const FontDescr& o) const {
- return size < o.size || (size == o.size && face < o.face);
- }
- };
- using FontMap = map<FontDescr, IFont*>;
- using FontMapPair = pair<const FontDescr, std::unique_ptr<IFont>>;
-
- FontMap m_fontmap;
-
- DISALLOW_COPY_AND_ASSIGN(FontCache);
-};
-
-FontCache::~FontCache() {
- for (FontMap::reference& entry : m_fontmap) {
- delete entry.second;
- }
-}
-
-IFont& FontCache::get_font(NodeStyle* ns) {
- if (ns->font_face == "condensed") {
- ns->font_face = ns->fontset->condensed();
- } else if (ns->font_face == "serif") {
- ns->font_face = ns->fontset->serif();
- } else if (ns->font_face == "sans") {
- ns->font_face = ns->fontset->sans();
- }
- const bool is_bold = ns->font_style & IFont::BOLD;
- const bool is_italic = ns->font_style & IFont::ITALIC;
- if (is_bold && is_italic) {
- if (ns->font_face == ns->fontset->condensed() ||
- ns->font_face == ns->fontset->condensed_bold() ||
- ns->font_face == ns->fontset->condensed_italic()) {
- ns->font_face = ns->fontset->condensed_bold_italic();
- } else if (ns->font_face == ns->fontset->serif() ||
- ns->font_face == ns->fontset->serif_bold() ||
- ns->font_face == ns->fontset->serif_italic()) {
- ns->font_face = ns->fontset->serif_bold_italic();
- } else {
- ns->font_face = ns->fontset->sans_bold_italic();
- }
- ns->font_style &= ~IFont::ITALIC;
- ns->font_style &= ~IFont::BOLD;
- } else if (is_bold) {
- if (ns->font_face == ns->fontset->condensed()) {
- ns->font_face = ns->fontset->condensed_bold();
- } else if (ns->font_face == ns->fontset->serif()) {
- ns->font_face = ns->fontset->serif_bold();
- } else {
- ns->font_face = ns->fontset->sans_bold();
- }
- ns->font_style &= ~IFont::BOLD;
- } else if (is_italic) {
- if (ns->font_face == ns->fontset->condensed()) {
- ns->font_face = ns->fontset->condensed_italic();
- } else if (ns->font_face == ns->fontset->serif()) {
- ns->font_face = ns->fontset->serif_italic();
- } else {
- ns->font_face = ns->fontset->sans_italic();
- }
- ns->font_style &= ~IFont::ITALIC;
- }
-
- uint16_t font_size = ns->font_size + ns->fontset->size_offset();
-
- FontDescr fd = {ns->font_face, font_size};
- FontMap::iterator i = m_fontmap.find(fd);
- if (i != m_fontmap.end())
- return *i->second;
-
- std::unique_ptr<IFont> font;
- try {
- font.reset(load_font(ns->font_face, font_size));
- } catch (FileNotFoundError& e) {
- log("Font file not found. Falling back to sans: %s\n%s\n", ns->font_face.c_str(), e.what());
- font.reset(load_font(ns->fontset->sans(), font_size));
- }
- assert(font != nullptr);
-
- return *m_fontmap.insert(std::make_pair(fd, font.release())).first->second;
-}
class TagHandler;
TagHandler* create_taghandler(Tag& tag, FontCache& fc, NodeStyle& ns, ImageCache* image_cache,
- RendererStyle& renderer_style);
+ RendererStyle& renderer_style, const UI::FontSets& fontsets);
class TagHandler {
public:
TagHandler(Tag& tag, FontCache& fc, NodeStyle ns, ImageCache* image_cache,
- RendererStyle& renderer_style_) :
+ RendererStyle& renderer_style_, const UI::FontSets& fontsets) :
m_tag(tag), font_cache_(fc), m_ns(ns), image_cache_(image_cache),
- renderer_style(renderer_style_) {}
+ renderer_style(renderer_style_), fontsets_(fontsets) {}
virtual ~TagHandler() {}
virtual void enter() {}
@@ -708,6 +719,7 @@
NodeStyle m_ns;
ImageCache* image_cache_; // Not owned
RendererStyle& renderer_style; // Reference to global renderer style in the renderer
+ const UI::FontSets& fontsets_;
};
void TagHandler::m_make_text_nodes(const string& txt, vector<RenderNode*>& nodes, NodeStyle& ns) {
@@ -729,10 +741,11 @@
// We only know if the spacer goes to the left or right after having a look at the current word.
for (uint16_t ws_indx = 0; ws_indx < ts.pos() - cpos; ws_indx++) {
- spacer_nodes.push_back(new WordSpacerNode(font_cache_.get_font(&ns), ns));
+ spacer_nodes.push_back(new WordSpacerNode(font_cache_, ns));
}
word = ts.till_any_or_end(" \t\n\r");
+ ns.fontset = i18n::find_fontset(word.c_str(), fontsets_);
if (!word.empty()) {
replace_entities(&word);
bool word_is_bidi = i18n::has_rtl_character(word.c_str());
@@ -745,7 +758,7 @@
word = i18n::line2bidi(word.c_str());
}
it = text_nodes.insert(text_nodes.begin(),
- new TextNode(font_cache_.get_font(&ns), ns, word.c_str()));
+ new TextNode(font_cache_, ns, word.c_str()));
} else { // Sequences of Latin words go to the right from current position
if (it < text_nodes.end()) {
++it;
@@ -756,7 +769,7 @@
++it;
}
}
- it = text_nodes.insert(it, new TextNode(font_cache_.get_font(&ns), ns, word));
+ it = text_nodes.insert(it, new TextNode(font_cache_, ns, word));
}
}
previous_word = word;
@@ -771,19 +784,20 @@
std::size_t cpos = ts.pos();
ts.skip_ws();
for (uint16_t ws_indx = 0; ws_indx < ts.pos() - cpos; ws_indx++) {
- nodes.push_back(new WordSpacerNode(font_cache_.get_font(&ns), ns));
+ nodes.push_back(new WordSpacerNode(font_cache_, ns));
}
word = ts.till_any_or_end(" \t\n\r");
+ ns.fontset = i18n::find_fontset(word.c_str(), fontsets_);
if (!word.empty()) {
replace_entities(&word);
word = i18n::make_ligatures(word.c_str());
- if (i18n::has_cjk_character(word.c_str())) {
+ if (i18n::has_script_character(word.c_str(), UI::FontSets::Selector::kCJK)) {
std::vector<std::string> units = i18n::split_cjk_word(word.c_str());
for (const std::string& unit: units) {
- nodes.push_back(new TextNode(font_cache_.get_font(&ns), ns, unit));
+ nodes.push_back(new TextNode(font_cache_, ns, unit));
}
} else {
- nodes.push_back(new TextNode(font_cache_.get_font(&ns), ns, word));
+ nodes.push_back(new TextNode(font_cache_, ns, word));
}
}
}
@@ -794,7 +808,7 @@
for (Child* c : m_tag.childs()) {
if (c->tag) {
std::unique_ptr<TagHandler> th(create_taghandler(*c->tag, font_cache_, m_ns, image_cache_,
- renderer_style));
+ renderer_style, fontsets_));
th->enter();
th->emit(nodes);
} else
@@ -805,8 +819,8 @@
class FontTagHandler : public TagHandler {
public:
FontTagHandler(Tag& tag, FontCache& fc, NodeStyle ns, ImageCache* image_cache,
- RendererStyle& init_renderer_style)
- : TagHandler(tag, fc, ns, image_cache, init_renderer_style) {}
+ RendererStyle& init_renderer_style, const UI::FontSets& fontsets)
+ : TagHandler(tag, fc, ns, image_cache, init_renderer_style, fontsets) {}
void enter() override {
const AttrMap& a = m_tag.attrs();
@@ -824,8 +838,8 @@
class PTagHandler : public TagHandler {
public:
PTagHandler(Tag& tag, FontCache& fc, NodeStyle ns, ImageCache* image_cache,
- RendererStyle& init_renderer_style)
- : TagHandler(tag, fc, ns, image_cache, init_renderer_style), m_indent(0) {
+ RendererStyle& init_renderer_style, const UI::FontSets& fontsets)
+ : TagHandler(tag, fc, ns, image_cache, init_renderer_style, fontsets), m_indent(0) {
}
void enter() override {
@@ -873,8 +887,8 @@
class ImgTagHandler : public TagHandler {
public:
ImgTagHandler(Tag& tag, FontCache& fc, NodeStyle ns, ImageCache* image_cache,
- RendererStyle& init_renderer_style) :
- TagHandler(tag, fc, ns, image_cache, init_renderer_style), m_rn(nullptr) {
+ RendererStyle& init_renderer_style, const UI::FontSets& fontsets) :
+ TagHandler(tag, fc, ns, image_cache, init_renderer_style, fontsets), m_rn(nullptr) {
}
void enter() override {
@@ -892,8 +906,8 @@
class VspaceTagHandler : public TagHandler {
public:
VspaceTagHandler(Tag& tag, FontCache& fc, NodeStyle ns, ImageCache* image_cache,
- RendererStyle& init_renderer_style) :
- TagHandler(tag, fc, ns, image_cache, init_renderer_style), m_space(0) {}
+ RendererStyle& init_renderer_style, const UI::FontSets& fontsets) :
+ TagHandler(tag, fc, ns, image_cache, init_renderer_style, fontsets), m_space(0) {}
void enter() override {
const AttrMap& a = m_tag.attrs();
@@ -912,8 +926,8 @@
class HspaceTagHandler : public TagHandler {
public:
HspaceTagHandler(Tag& tag, FontCache& fc, NodeStyle ns, ImageCache* image_cache,
- RendererStyle& init_renderer_style) :
- TagHandler(tag, fc, ns, image_cache, init_renderer_style), m_bg(nullptr), m_space(0) {}
+ RendererStyle& init_renderer_style, const UI::FontSets& fontsets) :
+ TagHandler(tag, fc, ns, image_cache, init_renderer_style, fontsets), m_bg(nullptr), m_space(0) {}
void enter() override {
const AttrMap& a = m_tag.attrs();
@@ -938,9 +952,9 @@
RenderNode* rn = nullptr;
if (!m_fill_text.empty()) {
if (m_space < INFINITE_WIDTH)
- rn = new FillingTextNode(font_cache_.get_font(&m_ns), m_ns, m_space, m_fill_text);
+ rn = new FillingTextNode(font_cache_, m_ns, m_space, m_fill_text);
else
- rn = new FillingTextNode(font_cache_.get_font(&m_ns), m_ns, 0, m_fill_text, true);
+ rn = new FillingTextNode(font_cache_, m_ns, 0, m_fill_text, true);
} else {
SpaceNode* sn;
if (m_space < INFINITE_WIDTH)
@@ -964,8 +978,8 @@
class BrTagHandler : public TagHandler {
public:
BrTagHandler(Tag& tag, FontCache& fc, NodeStyle ns, ImageCache* image_cache,
- RendererStyle& init_renderer_style) :
- TagHandler(tag, fc, ns, image_cache, init_renderer_style) {
+ RendererStyle& init_renderer_style, const UI::FontSets& fontsets) :
+ TagHandler(tag, fc, ns, image_cache, init_renderer_style, fontsets) {
}
void emit(vector<RenderNode*>& nodes) override {
@@ -978,10 +992,10 @@
public:
SubTagHandler
(Tag& tag, FontCache& fc, NodeStyle ns, ImageCache* image_cache,
- RendererStyle& init_renderer_style,
+ RendererStyle& init_renderer_style, const UI::FontSets& fontsets,
uint16_t max_w = 0, bool shrink_to_fit = true)
:
- TagHandler(tag, fc, ns, image_cache, init_renderer_style),
+ TagHandler(tag, fc, ns, image_cache, init_renderer_style, fontsets),
shrink_to_fit_(shrink_to_fit),
m_w(max_w),
m_rn(new SubTagRenderNode(ns))
@@ -1104,8 +1118,8 @@
class RTTagHandler : public SubTagHandler {
public:
RTTagHandler(Tag& tag, FontCache& fc, NodeStyle ns, ImageCache* image_cache,
- RendererStyle& init_renderer_style, uint16_t w) :
- SubTagHandler(tag, fc, ns, image_cache, init_renderer_style, w, true) {
+ RendererStyle& init_renderer_style, const UI::FontSets& fontsets, uint16_t w) :
+ SubTagHandler(tag, fc, ns, image_cache, init_renderer_style, fontsets, w, true) {
}
// Handle attributes that are in rt, but not in sub.
@@ -1118,16 +1132,16 @@
template<typename T> TagHandler* create_taghandler
(Tag& tag, FontCache& fc, NodeStyle& ns, ImageCache* image_cache,
- RendererStyle& renderer_style)
+ RendererStyle& renderer_style, const UI::FontSets& fontsets)
{
- return new T(tag, fc, ns, image_cache, renderer_style);
+ return new T(tag, fc, ns, image_cache, renderer_style, fontsets);
}
using TagHandlerMap = map<const string, TagHandler* (*)
(Tag& tag, FontCache& fc, NodeStyle& ns, ImageCache* image_cache,
- RendererStyle& renderer_style)>;
+ RendererStyle& renderer_style, const UI::FontSets& fontsets)>;
TagHandler* create_taghandler(Tag& tag, FontCache& fc, NodeStyle& ns, ImageCache* image_cache,
- RendererStyle& renderer_style) {
+ RendererStyle& renderer_style, const UI::FontSets& fontsets) {
static TagHandlerMap map;
if (map.empty()) {
map["br"] = &create_taghandler<BrTagHandler>;
@@ -1143,13 +1157,13 @@
throw RenderError
((boost::format("No Tag handler for %s. This is a bug, please submit a report.")
% tag.name()).str());
- return i->second(tag, fc, ns, image_cache, renderer_style);
+ return i->second(tag, fc, ns, image_cache, renderer_style, fontsets);
}
-Renderer::Renderer(ImageCache* image_cache, TextureCache* texture_cache, UI::FontSet* fontset) :
+Renderer::Renderer(ImageCache* image_cache, TextureCache* texture_cache, const UI::FontSets& fontsets) :
font_cache_(new FontCache()), parser_(new Parser()),
- image_cache_(image_cache), texture_cache_(texture_cache), fontset_(fontset),
- renderer_style_(fontset->sans(), 16, INFINITE_WIDTH, INFINITE_WIDTH) {
+ image_cache_(image_cache), texture_cache_(texture_cache), fontsets_(fontsets),
+ renderer_style_("sans", 16, INFINITE_WIDTH, INFINITE_WIDTH) {
TextureCache* render
(const std::string&, uint16_t, const TagSet&);
}
@@ -1167,15 +1181,16 @@
renderer_style_.remaining_width = width;
renderer_style_.overall_width = width;
+ UI::FontSet const * fontset = fontsets_.get_fontset(i18n::get_locale());
+
NodeStyle default_style = {
- fontset_,
- renderer_style_.font_face, renderer_style_.font_size,
- RGBColor(255, 255, 0), IFont::DEFAULT, fontset_->is_rtl(), 0,
- UI::Align::kLeft, UI::Align::kTop,
+ fontset, renderer_style_.font_face, renderer_style_.font_size,
+ RGBColor(255, 255, 0), IFont::DEFAULT,
+ 0, UI::Align::kLeft, UI::Align::kTop,
""
};
- RTTagHandler rtrn(*rt, *font_cache_, default_style, image_cache_, renderer_style_, width);
+ RTTagHandler rtrn(*rt, *font_cache_, default_style, image_cache_, renderer_style_, fontsets_, width);
vector<RenderNode*> nodes;
rtrn.enter();
rtrn.emit(nodes);
=== modified file 'src/graphic/text/rt_render.h'
--- src/graphic/text/rt_render.h 2016-02-07 15:47:25 +0000
+++ src/graphic/text/rt_render.h 2016-02-15 11:00:58 +0000
@@ -52,30 +52,6 @@
uint16_t overall_width;
};
-/**
- * Wrapper object around a font.
- *
- * Fonts in our sense are defined by the general font shape (given by the font
- * name) and the size of the font. Note that Bold and Italic are special in the
- * regard that we expect that this is already handled by the Font File, so, the
- * font loader directly loads DejaVuSans-Bold.ttf for example.
- */
-class IFont {
-public:
- enum {
- DEFAULT = 0,
- BOLD = 1,
- ITALIC = 2,
- UNDERLINE = 4,
- SHADOW = 8,
- };
- virtual ~IFont() {}
-
- virtual void dimensions(const std::string&, int, uint16_t *, uint16_t *) = 0;
- virtual const Texture& render(const std::string&, const RGBColor& clr, int, TextureCache*) = 0;
-
- virtual uint16_t ascent(int) const = 0;
-};
/**
* A map that maps pixels to a string. The string are the references which can be used
@@ -95,7 +71,7 @@
class Renderer {
public:
// Ownership is not taken.
- Renderer(ImageCache* image_cache, TextureCache* texture_cache, UI::FontSet* fontset);
+ Renderer(ImageCache* image_cache, TextureCache* texture_cache, const UI::FontSets& fontsets);
~Renderer();
// Render the given string in the given width. Restricts the allowed tags to
@@ -115,7 +91,7 @@
std::unique_ptr<Parser> parser_;
ImageCache* const image_cache_; // Not owned.
TextureCache* const texture_cache_; // Not owned.
- UI::FontSet* const fontset_; // Not owned.
+ const UI::FontSets& fontsets_; // All fontsets
RendererStyle renderer_style_; // Properties that all render nodes need to know about
};
=== modified file 'src/graphic/text/sdl_ttf_font.cc'
--- src/graphic/text/sdl_ttf_font.cc 2016-01-24 07:47:01 +0000
+++ src/graphic/text/sdl_ttf_font.cc 2016-02-15 11:00:58 +0000
@@ -27,18 +27,13 @@
#include "graphic/sdl_utils.h"
#include "graphic/text/rt_errors.h"
-#include "graphic/texture.h"
-#include "graphic/texture_cache.h"
-
-using namespace std;
-using namespace boost;
static const int SHADOW_OFFSET = 1;
static const SDL_Color SHADOW_CLR = {0, 0, 0, SDL_ALPHA_OPAQUE};
namespace RT {
-SdlTtfFont::SdlTtfFont(TTF_Font * font, const string& face, int ptsize, string* ttf_memory_block) :
+SdlTtfFont::SdlTtfFont(TTF_Font * font, const std::string& face, int ptsize, std::string* ttf_memory_block) :
font_(font), style_(TTF_STYLE_NORMAL), font_name_(face), ptsize_(ptsize),
ttf_file_memory_block_(ttf_memory_block) {
}
@@ -48,7 +43,7 @@
font_ = nullptr;
}
-void SdlTtfFont::dimensions(const string& txt, int style, uint16_t * gw, uint16_t * gh) {
+void SdlTtfFont::dimensions(const std::string& txt, int style, uint16_t * gw, uint16_t * gh) {
m_set_style(style);
int w, h;
@@ -61,8 +56,8 @@
}
const Texture& SdlTtfFont::render
- (const string& txt, const RGBColor& clr, int style, TextureCache* texture_cache) {
- const string hash =
+ (const std::string& txt, const RGBColor& clr, int style, TextureCache* texture_cache) {
+ const std::string hash =
(boost::format("%s:%s:%i:%02x%02x%02x:%i") % font_name_ % ptsize_ % txt %
static_cast<int>(clr.r) % static_cast<int>(clr.g) % static_cast<int>(clr.b) % style)
.str();
@@ -120,7 +115,7 @@
text_surface = TTF_RenderUTF8_Blended(font_, txt.c_str(), sdlclr);
if (!text_surface)
- throw RenderError((format("Rendering '%s' gave the error: %s") % txt % TTF_GetError()).str());
+ throw RenderError((boost::format("Rendering '%s' gave the error: %s") % txt % TTF_GetError()).str());
return *texture_cache->insert(hash, std::unique_ptr<Texture>(new Texture(text_surface)));
}
@@ -134,8 +129,8 @@
void SdlTtfFont::m_set_style(int style) {
// Those must have been handled by loading the correct font.
- assert(!(style & BOLD));
- assert(!(style & ITALIC));
+ // NOCOM assert(!(style & BOLD));
+ //assert(!(style & ITALIC));
int sdl_style = TTF_STYLE_NORMAL;
if (style & UNDERLINE) sdl_style |= TTF_STYLE_UNDERLINE;
=== modified file 'src/graphic/text/sdl_ttf_font.h'
--- src/graphic/text/sdl_ttf_font.h 2014-11-24 07:10:03 +0000
+++ src/graphic/text/sdl_ttf_font.h 2016-02-15 11:00:58 +0000
@@ -25,10 +25,36 @@
#include <SDL_ttf.h>
-#include "graphic/text/rt_render.h"
+#include "graphic/texture.h"
+#include "graphic/texture_cache.h"
namespace RT {
+/**
+ * Wrapper object around a font.
+ *
+ * Fonts in our sense are defined by the general font shape (given by the font
+ * name) and the size of the font. Note that Bold and Italic are special in the
+ * regard that we expect that this is already handled by the Font File, so, the
+ * font loader directly loads DejaVuSans-Bold.ttf for example.
+ */
+class IFont {
+public:
+ enum {
+ DEFAULT = 0,
+ BOLD = 1,
+ ITALIC = 2,
+ UNDERLINE = 4,
+ SHADOW = 8,
+ };
+ virtual ~IFont() {}
+
+ virtual void dimensions(const std::string&, int, uint16_t *, uint16_t *) = 0;
+ virtual const Texture& render(const std::string&, const RGBColor& clr, int, TextureCache*) = 0;
+
+ virtual uint16_t ascent(int) const = 0;
+};
+
// Implementation of a Font object using SDL_ttf.
class SdlTtfFont : public IFont {
public:
=== modified file 'src/graphic/text/test/CMakeLists.txt'
--- src/graphic/text/test/CMakeLists.txt 2014-12-08 05:22:52 +0000
+++ src/graphic/text/test/CMakeLists.txt 2016-02-15 11:00:58 +0000
@@ -21,6 +21,7 @@
render.cc
render.h
DEPENDS
+ base_i18n
graphic_image_cache
graphic_surface
graphic_text
=== modified file 'src/graphic/text/test/render.cc'
--- src/graphic/text/test/render.cc 2016-01-19 08:55:16 +0000
+++ src/graphic/text/test/render.cc 2016-02-15 11:00:58 +0000
@@ -24,6 +24,7 @@
#include <memory>
#include <string>
+#include "base/i18n.h"
#include "graphic/image_cache.h"
#include "graphic/text/rt_render.h"
#include "graphic/text/test/paths.h"
@@ -31,13 +32,15 @@
#include "io/filesystem/layered_filesystem.h"
StandaloneRenderer::StandaloneRenderer() {
+ i18n::set_locale("en");
g_fs = new LayeredFileSystem();
g_fs->add_file_system(&FileSystem::create(WIDELANDS_DATA_DIR));
g_fs->add_file_system(&FileSystem::create(RICHTEXT_DATA_DIR));
+ UI::FontSets fontsets;
texture_cache_.reset(new TextureCache(500 << 20)); // 500 MB
image_cache_.reset(new ImageCache());
- renderer_.reset(new RT::Renderer(image_cache_.get(), texture_cache_.get(), new UI::FontSet("en")));
+ renderer_.reset(new RT::Renderer(image_cache_.get(), texture_cache_.get(), fontsets));
}
StandaloneRenderer::~StandaloneRenderer() {
=== modified file 'src/graphic/text_layout.cc'
--- src/graphic/text_layout.cc 2016-02-13 11:04:05 +0000
+++ src/graphic/text_layout.cc 2016-02-15 11:00:58 +0000
@@ -39,12 +39,12 @@
}
uint32_t text_width(const std::string& text, int ptsize) {
- return UI::g_fh1->render(as_editorfont(text, ptsize - UI::g_fh1->fontset().size_offset()))->width();
+ return UI::g_fh1->render(as_editorfont(text, ptsize - UI::g_fh1->fontset()->size_offset()))->width();
}
uint32_t text_height(const std::string& text, int ptsize) {
return UI::g_fh1->render(as_editorfont(text.empty() ? "." : text,
- ptsize - UI::g_fh1->fontset().size_offset()))->height();
+ ptsize - UI::g_fh1->fontset()->size_offset()))->height();
}
std::string richtext_escape(const std::string& given_text) {
@@ -238,7 +238,7 @@
*/
TextStyle::TextStyle() :
- font(Font::get(UI::g_fh1->fontset().sans(), UI_FONT_SIZE_SMALL)),
+ font(Font::get(UI::g_fh1->fontset()->sans(), UI_FONT_SIZE_SMALL)),
fg(UI_FONT_CLR_FG),
bold(true),
italics(false),
=== modified file 'src/graphic/text_parser.cc'
--- src/graphic/text_parser.cc 2015-12-17 09:36:59 +0000
+++ src/graphic/text_parser.cc 2016-02-15 11:00:58 +0000
@@ -54,7 +54,7 @@
m_font_weight = "normal";
m_font_style = "normal";
m_font_decoration = "none";
- m_font_face = (UI::g_fh1->fontset()).sans();
+ m_font_face = (UI::g_fh1->fontset())->sans();
m_line_spacing = 0;
}
@@ -269,10 +269,10 @@
if (key == "font-size") {
element.set_font_size(atoi(val.c_str()));
} else if (key == "font-face") {
- UI::FontSet fontset = UI::g_fh1->fontset();
+ const UI::FontSet& fontset = *UI::g_fh1->fontset();
if (val == fontset.condensed() || val == "condensed") {
val = fontset.condensed();
- } else if (val == fontset.sans() || val == "serif") {
+ } else if (val == fontset.serif() || val == "serif") {
val = fontset.serif();
} else {
val = fontset.sans();
=== modified file 'src/graphic/wordwrap.cc'
--- src/graphic/wordwrap.cc 2016-01-31 10:57:58 +0000
+++ src/graphic/wordwrap.cc 2016-02-15 11:00:58 +0000
@@ -352,7 +352,7 @@
const Image* entry_text_im =
UI::g_fh1->render(as_editorfont(m_lines[line].text,
- m_style.font->size() - UI::g_fh1->fontset().size_offset(),
+ m_style.font->size() - UI::g_fh1->fontset()->size_offset(),
m_style.fg));
UI::correct_for_align(alignment, entry_text_im->width(), fontheight, &point);
dst.blit(point, entry_text_im);
=== modified file 'src/ui_basic/button.cc'
--- src/ui_basic/button.cc 2016-02-09 18:24:03 +0000
+++ src/ui_basic/button.cc 2016-02-15 11:00:58 +0000
@@ -57,7 +57,8 @@
{
// Automatically resize for font height and give it a margin.
if (h < 1) {
- int new_height = UI::g_fh1->render(as_uifont("."))->height() + 4;
+ int new_height =
+ UI::g_fh1->render(as_uifont(UI::g_fh1->fontset()->representative_character()))->height() + 4;
set_desired_size(w, new_height);
set_size(w, new_height);
}
=== modified file 'src/ui_basic/checkbox.cc'
--- src/ui_basic/checkbox.cc 2016-02-04 19:46:40 +0000
+++ src/ui_basic/checkbox.cc 2016-02-15 11:00:58 +0000
@@ -143,7 +143,7 @@
Point text_anchor(kStateboxSize + kPadding, 0);
if (rendered_text_) {
- if (UI::g_fh1->fontset().is_rtl()) {
+ if (UI::g_fh1->fontset()->is_rtl()) {
text_anchor.x = 0;
image_anchor.x = rendered_text_->width() + kPadding;
image_anchor.y = (get_h() - kStateboxSize) / 2;
=== modified file 'src/ui_basic/editbox.cc'
--- src/ui_basic/editbox.cc 2016-02-03 18:09:15 +0000
+++ src/ui_basic/editbox.cc 2016-02-15 11:00:58 +0000
@@ -76,7 +76,7 @@
const Image* background,
int font_size)
:
- Panel(parent, x, y, w, UI::g_fh1->render(as_uifont("."), font_size)->height() + 2),
+ Panel(parent, x, y, w, UI::g_fh1->render(as_uifont(UI::g_fh1->fontset()->representative_character()), font_size)->height() + 2),
m_(new EditBoxImpl),
history_active_(false),
history_position_(-1)
@@ -84,11 +84,11 @@
set_thinks(false);
m_->background = background;
- m_->fontname = UI::g_fh1->fontset().serif();
+ m_->fontname = UI::g_fh1->fontset()->sans();
m_->fontsize = font_size;
// Set alignment to the UI language's principal writing direction
- m_->align = UI::g_fh1->fontset().is_rtl() ? UI::Align::kCenterRight : UI::Align::kCenterLeft;
+ m_->align = UI::g_fh1->fontset()->is_rtl() ? UI::Align::kCenterRight : UI::Align::kCenterLeft;
m_->caret = 0;
m_->scrolloffset = 0;
// yes, use *signed* max as maximum length; just a small safe-guard.
@@ -409,7 +409,7 @@
// Crop to max_width while blitting
if (max_width < linewidth) {
// Fix positioning for BiDi languages.
- if (UI::g_fh1->fontset().is_rtl()) {
+ if (UI::g_fh1->fontset()->is_rtl()) {
point.x = 0;
}
// We want this always on, e.g. for mixed language savegame filenames
=== modified file 'src/ui_basic/listselect.cc'
--- src/ui_basic/listselect.cc 2016-02-08 00:18:02 +0000
+++ src/ui_basic/listselect.cc 2016-02-15 11:00:58 +0000
@@ -24,16 +24,17 @@
#include <boost/bind.hpp>
#include "base/log.h"
-#include "graphic/font.h"
-#include "graphic/font_handler.h"
+#include "graphic/align.h"
#include "graphic/font_handler1.h"
#include "graphic/graphic.h"
#include "graphic/rendertarget.h"
-#include "graphic/text/font_set.h"
#include "graphic/text_constants.h"
#include "graphic/text_layout.h"
+#include "graphic/text/bidi.h"
#include "wlapplication.h"
+constexpr int kMargin = 2;
+
namespace UI {
/**
* Initialize a list select panel
@@ -43,33 +44,27 @@
* y
* w dimensions, in pixels, of the Listselect
* h
- * align alignment of text inside the Listselect
*/
BaseListselect::BaseListselect
(Panel * const parent,
int32_t const x, int32_t const y, uint32_t const w, uint32_t const h,
- Align const align, bool const show_check)
+ bool const show_check)
:
Panel(parent, x, y, w, h),
- lineheight_(g_fh->get_fontheight(UI::g_fh1->fontset().serif(), UI_FONT_SIZE_SMALL)),
+ lineheight_(UI::g_fh1->render(as_uifont(UI::g_fh1->fontset()->representative_character()))->height()
+ + kMargin),
scrollbar_ (this, get_w() - 24, 0, 24, h, false),
scrollpos_ (0),
selection_ (no_selection_index()),
last_click_time_(-10000),
last_selection_(no_selection_index()),
- show_check_(show_check),
- fontname_(UI::g_fh1->fontset().serif()),
- fontsize_(UI_FONT_SIZE_SMALL)
+ show_check_(show_check)
{
set_thinks(false);
- // do not allow vertical alignment as it does not make sense
- align_ = align & UI::Align::kHorizontal;
-
scrollbar_.moved.connect(boost::bind(&BaseListselect::set_scrollpos, this, _1));
- scrollbar_.set_singlestepsize(g_fh->get_fontheight(fontname_, fontsize_));
- scrollbar_.set_pagesize
- (h - 2 * g_fh->get_fontheight(fontname_, fontsize_));
+ scrollbar_.set_singlestepsize(lineheight_);
+ scrollbar_.set_pagesize(h - 2 * lineheight_);
scrollbar_.set_steps(1);
if (show_check) {
@@ -125,8 +120,7 @@
uint32_t entry,
const Image* pic,
bool const sel,
- const std::string & tooltip_text,
- const std::string & fontname)
+ const std::string & tooltip_text)
{
EntryRecord * er = new EntryRecord();
@@ -135,8 +129,7 @@
er->use_clr = false;
er->name = name;
er->tooltip = tooltip_text;
- er->font_face = fontname;
- uint32_t entry_height = g_fh->get_fontheight(fontname.empty() ? fontname_ : fontname, fontsize_);
+ uint32_t entry_height = lineheight_;
if (pic) {
uint16_t w = pic->width();
uint16_t h = pic->height();
@@ -160,8 +153,7 @@
(const std::string& name,
const Image* pic,
bool const sel,
- const std::string & tooltip_text,
- const std::string& fontname)
+ const std::string & tooltip_text)
{
EntryRecord * er = new EntryRecord();
@@ -174,9 +166,8 @@
er->use_clr = false;
er->name = name;
er->tooltip = tooltip_text;
- er->font_face = fontname;
- uint32_t entry_height = g_fh->get_fontheight(fontname.empty() ? fontname_ : fontname, fontsize_);
+ uint32_t entry_height = lineheight_;
if (pic) {
uint16_t w = pic->width();
uint16_t h = pic->height();
@@ -327,7 +318,7 @@
uint32_t BaseListselect::get_lineheight() const
{
- return lineheight_ + 2;
+ return lineheight_ + kMargin;
}
uint32_t BaseListselect::get_eff_w() const
@@ -355,9 +346,12 @@
const EntryRecord & er = *entry_records_[idx];
+ Point point(1, y);
+ uint32_t maxw = get_eff_w() - 2;
+
// Highlight the current selected entry
if (idx == selection_) {
- Rect r = Rect(Point(1, y), get_eff_w() - 2, lineheight_);
+ Rect r = Rect(point, maxw, lineheight_);
if (r.x < 0) {
r.w += r.x; r.x = 0;
}
@@ -372,36 +366,48 @@
}
}
- Align draw_alignment = mirror_alignment(align_);
-
- int32_t const x =
- (static_cast<int>(draw_alignment & UI::Align::kRight)) ? get_eff_w() - 1 :
- (static_cast<int>(draw_alignment & UI::Align::kHCenter)) ? get_eff_w() >> 1 :
-
- // Pictures are always left aligned, leave some space here
- max_pic_width_ ? max_pic_width_ + 10 :
- 1;
-
- std::string font_face = er.font_face.empty() ? fontname_ : er.font_face;
- RGBColor color = er.use_clr ? er.clr : UI_FONT_CLR_FG;
-
- // Horizontal center the string
- UI::g_fh->draw_text
- (dst,
- TextStyle::makebold(Font::get(font_face, fontsize_), color),
- Point
- (x,
- y +
- (get_lineheight() - g_fh->get_fontheight(font_face, fontsize_))
- /
- 2),
- er.name,
- draw_alignment);
+ uint32_t picw = max_pic_width_ ? max_pic_width_ + 10 : 0;
// Now draw pictures
if (er.pic) {
- uint16_t h = er.pic->height();
- dst.blit(Point(1, y + (get_lineheight() - h) / 2), er.pic);
+ dst.blit(Point(UI::g_fh1->fontset()->is_rtl() ? get_eff_w() - er.pic->width() - 1 : 1,
+ y + (get_lineheight() - er.pic->height()) / 2),
+ er.pic);
+ }
+
+ const Image* entry_text_im = UI::g_fh1->render(as_uifont(er.name, UI_FONT_SIZE_SMALL,
+ er.use_clr ? er.clr : UI_FONT_CLR_FG));
+
+ Align alignment = i18n::has_rtl_character(er.name.c_str(), 20) ? UI::Align::kRight : UI::Align::kLeft;
+ if (static_cast<int>(alignment & UI::Align::kRight)) {
+ point.x += maxw - picw;
+ }
+
+ UI::correct_for_align(alignment, entry_text_im->width(), entry_text_im->height(), &point);
+
+ // Shift for image width
+ if (!UI::g_fh1->fontset()->is_rtl()) {
+ point.x += picw;
+ }
+
+ // Fix vertical position for mixed font heights
+ if (get_lineheight() > static_cast<uint32_t>(entry_text_im->height())) {
+ point.y += (lineheight_ - entry_text_im->height()) / 2;
+ } else {
+ point.y -= (entry_text_im->height() - lineheight_) / 2;
+ }
+
+ // Crop to column width while blitting
+ if (static_cast<int>(alignment & UI::Align::kRight) && (maxw + picw) < static_cast<uint32_t>(entry_text_im->width())) {
+ // Fix positioning for BiDi languages.
+ point.x = 0;
+
+ // We want this always on, e.g. for mixed language savegame filenames, or the languages list
+ dst.blitrect(point,
+ entry_text_im,
+ Rect(entry_text_im->width() - maxw + picw, 0, maxw, entry_text_im->height()));
+ } else {
+ dst.blitrect(point, entry_text_im, Rect(0, 0, maxw, entry_text_im->height()));
}
y += lineheight;
=== modified file 'src/ui_basic/listselect.h'
--- src/ui_basic/listselect.h 2016-02-07 16:31:06 +0000
+++ src/ui_basic/listselect.h 2016-02-15 11:00:58 +0000
@@ -26,7 +26,6 @@
#include <boost/signals2.hpp>
-#include "graphic/align.h"
#include "graphic/color.h"
#include "ui_basic/panel.h"
#include "ui_basic/scrollbar.h"
@@ -47,7 +46,6 @@
int32_t y,
uint32_t w,
uint32_t h,
- Align align = UI::Align::kLeft,
bool show_check = false);
~BaseListselect();
@@ -64,23 +62,18 @@
uint32_t value,
const Image* pic = nullptr,
const bool select_this = false,
- const std::string & tooltip_text = std::string(),
- const std::string& fontname = "");
+ const std::string & tooltip_text = std::string());
void add_front
(const std::string& name,
const Image* pic = nullptr,
const bool select_this = false,
- const std::string & tooltip_text = std::string(),
- const std::string& fontname = "");
+ const std::string & tooltip_text = std::string());
void remove(uint32_t);
void remove(const char * name);
void switch_entries(uint32_t, uint32_t);
void set_entry_color(uint32_t, RGBColor);
- void set_fontsize(int32_t const fontsize) {
- fontsize_ = fontsize;
- }
uint32_t size () const {return entry_records_.size ();}
bool empty() const {return entry_records_.empty();}
@@ -136,13 +129,11 @@
const Image* pic;
std::string name;
std::string tooltip;
- std::string font_face;
};
using EntryRecordDeque = std::deque<EntryRecord *>;
uint32_t max_pic_width_;
uint32_t lineheight_;
- Align align_;
EntryRecordDeque entry_records_;
Scrollbar scrollbar_;
uint32_t scrollpos_; // in pixels
@@ -151,9 +142,6 @@
uint32_t last_selection_; // for double clicks
bool show_check_; // show a green arrow left of selected element
const Image* check_pic_;
-
- std::string fontname_;
- uint32_t fontsize_;
std::string current_tooltip_;
};
@@ -163,9 +151,8 @@
(Panel * parent,
int32_t x, int32_t y,
uint32_t w, uint32_t h,
- Align align = UI::Align::kLeft,
bool show_check = false)
- : BaseListselect(parent, x, y, w, h, align, show_check)
+ : BaseListselect(parent, x, y, w, h, show_check)
{}
void add
@@ -173,11 +160,10 @@
Entry value,
const Image* pic = nullptr,
const bool select_this = false,
- const std::string & tooltip_text = std::string(),
- const std::string & font_face = "")
+ const std::string & tooltip_text = std::string())
{
entry_cache_.push_back(value);
- BaseListselect::add(name, entry_cache_.size() - 1, pic, select_this, tooltip_text, font_face);
+ BaseListselect::add(name, entry_cache_.size() - 1, pic, select_this, tooltip_text);
}
void add_front
(const std::string& name,
@@ -219,9 +205,8 @@
(Panel * parent,
int32_t x, int32_t y,
uint32_t w, uint32_t h,
- Align align = UI::Align::kLeft,
bool show_check = false)
- : Base(parent, x, y, w, h, align, show_check)
+ : Base(parent, x, y, w, h, show_check)
{}
void add
=== modified file 'src/ui_basic/messagebox.cc'
--- src/ui_basic/messagebox.cc 2016-02-05 08:56:04 +0000
+++ src/ui_basic/messagebox.cc 2016-02-15 11:00:58 +0000
@@ -83,7 +83,7 @@
"ok",
type_ == MBoxType::kOk ?
(width - button_w) / 2 :
- UI::g_fh1->fontset().is_rtl() ? left_button_x : right_button_x,
+ UI::g_fh1->fontset()->is_rtl() ? left_button_x : right_button_x,
button_y,
button_w,
0,
@@ -95,7 +95,7 @@
cancel_button_.reset(
new Button(this,
"cancel",
- UI::g_fh1->fontset().is_rtl() ? right_button_x : left_button_x,
+ UI::g_fh1->fontset()->is_rtl() ? right_button_x : left_button_x,
button_y,
button_w,
0,
=== modified file 'src/ui_basic/multilinetextarea.cc'
--- src/ui_basic/multilinetextarea.cc 2016-02-14 10:56:16 +0000
+++ src/ui_basic/multilinetextarea.cc 2016-02-15 11:00:58 +0000
@@ -53,8 +53,8 @@
scrollbar_.moved.connect(boost::bind(&MultilineTextarea::scrollpos_changed, this, _1));
- scrollbar_.set_singlestepsize(UI::g_fh1->render(as_uifont(".", UI_FONT_SIZE_SMALL))->height());
- scrollbar_.set_pagesize(h - 2 * UI::g_fh1->render(as_uifont(".", UI_FONT_SIZE_BIG))->height());
+ scrollbar_.set_singlestepsize(UI::g_fh1->render(as_uifont(UI::g_fh1->fontset()->representative_character(), UI_FONT_SIZE_SMALL))->height());
+ scrollbar_.set_pagesize(h - 2 * UI::g_fh1->render(as_uifont(UI::g_fh1->fontset()->representative_character(), UI_FONT_SIZE_BIG))->height());
scrollbar_.set_steps(1);
scrollbar_.set_force_draw(scrollmode_ == ScrollMode::kScrollNormalForced ||
scrollmode_ == ScrollMode::kScrollLogForced);
=== modified file 'src/ui_basic/panel.cc'
--- src/ui_basic/panel.cc 2016-02-14 19:34:44 +0000
+++ src/ui_basic/panel.cc 2016-02-15 11:00:58 +0000
@@ -1128,4 +1128,5 @@
dst.blit(r.origin() + Point(2, 2), rendered_text);
return true;
}
+
}
=== modified file 'src/ui_basic/progresswindow.cc'
--- src/ui_basic/progresswindow.cc 2016-02-06 19:59:13 +0000
+++ src/ui_basic/progresswindow.cc 2016-02-15 11:00:58 +0000
@@ -59,7 +59,8 @@
label_center_.y = yres * PROGRESS_LABEL_POSITION_Y / 100;
Rect wnd_rect(Point(0, 0), xres, yres);
- const uint32_t h = UI::g_fh1->render(as_uifont("."))->height();
+ const uint32_t h =
+ UI::g_fh1->render(as_uifont(UI::g_fh1->fontset()->representative_character()))->height();
label_rectangle_.x = xres / 4;
label_rectangle_.w = xres / 2;
=== modified file 'src/ui_basic/slider.cc'
--- src/ui_basic/slider.cc 2016-02-03 18:09:15 +0000
+++ src/ui_basic/slider.cc 2016-02-15 11:00:58 +0000
@@ -551,7 +551,7 @@
// here, we take into account the h_gap introduced by HorizontalSlider
w / (2 * labels_in.size()) - cursor_size / 2, 0,
w - (w / labels_in.size()) + cursor_size,
- h - UI::g_fh1->render(as_uifont("."))->height() - 2,
+ h - UI::g_fh1->render(as_uifont(UI::g_fh1->fontset()->representative_character()))->height() - 2,
0, labels_in.size() - 1, value_,
background_picture_id,
tooltip_text,
@@ -597,7 +597,7 @@
slider.set_pos(Point(w / (2 * labels.size()) - slider.cursor_size_ / 2, 0));
slider.set_size
(w - (w / labels.size()) + slider.cursor_size_,
- h - UI::g_fh1->render(as_uifont("."))->height() - 2);
+ h - UI::g_fh1->render(as_uifont(UI::g_fh1->fontset()->representative_character()))->height() - 2);
Panel::layout();
}
=== modified file 'src/ui_basic/spinbox.cc'
--- src/ui_basic/spinbox.cc 2016-02-08 20:04:17 +0000
+++ src/ui_basic/spinbox.cc 2016-02-15 11:00:58 +0000
@@ -110,7 +110,7 @@
uint32_t actual_w = std::max(w, unit_w);
uint32_t no_padding = (is_big ? 6 : 4);
// Give some height margin = 2 to keep the label from generating a scrollbar.
- uint32_t texth = UI::g_fh1->render(as_uifont("."))->height() + 2;
+ uint32_t texth = UI::g_fh1->render(as_uifont(UI::g_fh1->fontset()->representative_character()))->height() + 2;
uint32_t buttonh = 20;
// 40 is an ad hoc width estimate for the MultilineTextarea scrollbar + a bit of text.
=== modified file 'src/ui_basic/table.cc'
--- src/ui_basic/table.cc 2016-02-03 18:09:15 +0000
+++ src/ui_basic/table.cc 2016-02-15 11:00:58 +0000
@@ -52,8 +52,8 @@
Panel (parent, x, y, w, h),
total_width_ (0),
fontsize_ (UI_FONT_SIZE_SMALL),
- headerheight_ (UI::g_fh1->render(as_uifont(".", fontsize_))->height() + 4),
- lineheight_ (UI::g_fh1->render(as_uifont(".", fontsize_))->height()),
+ headerheight_ (UI::g_fh1->render(as_uifont(UI::g_fh1->fontset()->representative_character(), fontsize_))->height() + 4),
+ lineheight_ (UI::g_fh1->render(as_uifont(UI::g_fh1->fontset()->representative_character(), fontsize_))->height()),
scrollbar_ (nullptr),
scrollpos_ (0),
selection_ (no_selection_index()),
@@ -365,7 +365,7 @@
// Crop to column width while blitting
if ((curw + picw) < text_width) {
// Fix positioning for BiDi languages.
- if (UI::g_fh1->fontset().is_rtl()) {
+ if (UI::g_fh1->fontset()->is_rtl()) {
point.x = static_cast<int>(alignment & UI::Align::kRight) ? curx : curx + picw;
}
// We want this always on, e.g. for mixed language savegame filenames
=== modified file 'src/ui_basic/textarea.cc'
--- src/ui_basic/textarea.cc 2016-02-09 18:24:03 +0000
+++ src/ui_basic/textarea.cc 2016-02-15 11:00:58 +0000
@@ -229,7 +229,7 @@
h = rendered_text_->height();
// We want empty textareas to have height
if (text_.empty()) {
- h = UI::g_fh1->render(as_uifont(".", fontsize_))->height();
+ h = UI::g_fh1->render(as_uifont(UI::g_fh1->fontset()->representative_character(), fontsize_))->height();
}
}
set_desired_size(w, h);
=== modified file 'src/ui_fsmenu/campaign_select.h'
--- src/ui_fsmenu/campaign_select.h 2016-02-04 09:10:44 +0000
+++ src/ui_fsmenu/campaign_select.h 2016-02-15 11:00:58 +0000
@@ -22,7 +22,6 @@
#include "ui_fsmenu/base.h"
#include "ui_basic/button.h"
-#include "ui_basic/listselect.h"
#include "ui_basic/multilinetextarea.h"
#include "ui_basic/table.h"
#include "ui_basic/textarea.h"
=== modified file 'src/ui_fsmenu/internet_lobby.cc'
--- src/ui_fsmenu/internet_lobby.cc 2016-02-07 16:31:06 +0000
+++ src/ui_fsmenu/internet_lobby.cc 2016-02-15 11:00:58 +0000
@@ -148,7 +148,6 @@
(0, boost::bind(&FullscreenMenuInternetLobby::compare_clienttype, this, _1, _2));
clientsonline .double_clicked.connect
(boost::bind(&FullscreenMenuInternetLobby::client_doubleclicked, this, _1));
- opengames .set_fontsize(fs_);
opengames .selected.connect
(boost::bind(&FullscreenMenuInternetLobby::server_selected, this));
opengames .double_clicked.connect
=== modified file 'src/ui_fsmenu/launch_mpg.h'
--- src/ui_fsmenu/launch_mpg.h 2016-02-07 16:31:06 +0000
+++ src/ui_fsmenu/launch_mpg.h 2016-02-15 11:00:58 +0000
@@ -26,7 +26,6 @@
#include "ui_fsmenu/base.h"
#include "ui_fsmenu/helpwindow.h"
#include "ui_basic/button.h"
-#include "ui_basic/listselect.h"
#include "ui_basic/multilinetextarea.h"
#include "ui_basic/textarea.h"
#include "wui/suggested_teams_box.h"
=== modified file 'src/ui_fsmenu/launch_spg.h'
--- src/ui_fsmenu/launch_spg.h 2016-01-28 19:58:46 +0000
+++ src/ui_fsmenu/launch_spg.h 2016-02-15 11:00:58 +0000
@@ -24,7 +24,6 @@
#include "logic/constants.h"
#include "ui_basic/button.h"
-#include "ui_basic/listselect.h"
#include "ui_basic/multilinetextarea.h"
#include "ui_basic/textarea.h"
#include "ui_fsmenu/base.h"
=== modified file 'src/ui_fsmenu/load_map_or_game.cc'
--- src/ui_fsmenu/load_map_or_game.cc 2016-02-04 09:10:44 +0000
+++ src/ui_fsmenu/load_map_or_game.cc 2016-02-15 11:00:58 +0000
@@ -25,7 +25,6 @@
#include "graphic/graphic.h"
#include "io/filesystem/filesystem.h"
#include "ui_basic/button.h"
-#include "ui_basic/listselect.h"
#include "ui_basic/multilinetextarea.h"
#include "ui_basic/textarea.h"
=== modified file 'src/ui_fsmenu/load_map_or_game.h'
--- src/ui_fsmenu/load_map_or_game.h 2016-02-04 07:45:37 +0000
+++ src/ui_fsmenu/load_map_or_game.h 2016-02-15 11:00:58 +0000
@@ -30,7 +30,6 @@
#include "graphic/graphic.h"
#include "io/filesystem/filesystem.h"
#include "ui_basic/button.h"
-#include "ui_basic/listselect.h"
#include "ui_basic/multilinetextarea.h"
#include "ui_basic/table.h"
#include "ui_basic/textarea.h"
=== modified file 'src/ui_fsmenu/options.cc'
--- src/ui_fsmenu/options.cc 2016-02-07 16:31:06 +0000
+++ src/ui_fsmenu/options.cc 2016-02-15 11:00:58 +0000
@@ -51,12 +51,10 @@
struct LanguageEntry {
LanguageEntry(const std::string& init_localename,
const std::string& init_descname,
- const std::string& init_sortname,
- const std::string& init_fontname) :
+ const std::string& init_sortname) :
localename(init_localename),
descname(init_descname),
- sortname(init_sortname),
- fontname(init_fontname) {}
+ sortname(init_sortname) {}
bool operator<(const LanguageEntry& other) const {
return sortname < other.sortname;
@@ -65,7 +63,6 @@
std::string localename; // ISO code for the locale
std::string descname; // Native language name
std::string sortname; // ASCII Language name used for sorting
- std::string fontname; // Name of the font with which the language name is displayed.
};
// Locale identifiers can look like this: ca_ES@xxxxxxxxxxxx-8
@@ -116,7 +113,7 @@
// Buttons
cancel_
(this, "cancel",
- UI::g_fh1->fontset().is_rtl() ? get_w() * 3 / 4 - butw_ / 2 : get_w() * 1 / 4 - butw_ / 2,
+ UI::g_fh1->fontset()->is_rtl() ? get_w() * 3 / 4 - butw_ / 2 : get_w() * 1 / 4 - butw_ / 2,
get_inner_h() - hmargin_,
butw_, buth_,
g_gr->images().get("images/ui_basic/but0.png"),
@@ -130,7 +127,7 @@
_("Apply"), std::string(), true, false),
ok_
(this, "ok",
- UI::g_fh1->fontset().is_rtl() ? get_w() * 1 / 4 - butw_ / 2 : get_w() * 3 / 4 - butw_ / 2,
+ UI::g_fh1->fontset()->is_rtl() ? get_w() * 1 / 4 - butw_ / 2 : get_w() * 3 / 4 - butw_ / 2,
get_inner_h() - hmargin_,
butw_, buth_,
g_gr->images().get("images/ui_basic/but2.png"),
@@ -150,7 +147,7 @@
// Interface options
label_resolution_(&box_interface_, _("In-game resolution"), UI::Align::kLeft),
- resolution_list_(&box_interface_, 0, 0, column_width_ / 2, 80, UI::Align::kLeft, true),
+ resolution_list_(&box_interface_, 0, 0, column_width_ / 2, 80, true),
fullscreen_ (&box_interface_, Point(0, 0), _("Fullscreen"), "", column_width_),
inputgrab_ (&box_interface_, Point(0, 0), _("Grab Input"), "", column_width_),
@@ -229,7 +226,7 @@
label_language_(&box_language_, _("Language"), UI::Align::kLeft),
language_list_(&box_language_, 0, 0, column_width_ / 2,
get_inner_h() - tab_panel_y_ - buth_ - hmargin_ - 5 * padding_,
- UI::Align::kLeft, true),
+ true),
os_(opt)
{
@@ -448,9 +445,7 @@
std::string name = i18n::make_ligatures(table->get_string("name").c_str());
const std::string sortname = table->get_string("sort_name");
- std::unique_ptr<UI::FontSet> fontset(new UI::FontSet(localename));
-
- entries.push_back(LanguageEntry(localename, name, sortname, fontset->serif()));
+ entries.push_back(LanguageEntry(localename, name, sortname));
if (localename == current_locale) {
selected_locale = current_locale;
@@ -458,7 +453,7 @@
} catch (const WException&) {
log("Could not read locale for: %s\n", localename.c_str());
- entries.push_back(LanguageEntry(localename, localename, localename, UI::FontSet::kFallbackFont));
+ entries.push_back(LanguageEntry(localename, localename, localename));
} // End read locale from table
} // End scan locales directory
} catch (const LuaError& err) {
@@ -467,11 +462,10 @@
} // End read locales table
find_selected_locale(&selected_locale, current_locale);
-
std::sort(entries.begin(), entries.end());
for (const LanguageEntry& entry : entries) {
language_list_.add(entry.descname.c_str(), entry.localename, nullptr,
- entry.localename == selected_locale, "", entry.fontname);
+ entry.localename == selected_locale, "");
}
}
=== modified file 'src/wui/actionconfirm.cc'
--- src/wui/actionconfirm.cc 2016-02-06 10:59:09 +0000
+++ src/wui/actionconfirm.cc 2016-02-15 11:00:58 +0000
@@ -154,7 +154,7 @@
UI::Button * okbtn =
new UI::Button
(this, "ok",
- UI::g_fh1->fontset().is_rtl() ? 6 : 114, 80, 80, 34,
+ UI::g_fh1->fontset()->is_rtl() ? 6 : 114, 80, 80, 34,
g_gr->images().get("images/ui_basic/but4.png"),
g_gr->images().get("images/wui/menu_okay.png"));
okbtn->sigclicked.connect(boost::bind(&ActionConfirm::ok, this));
@@ -162,7 +162,7 @@
UI::Button * cancelbtn =
new UI::Button
(this, "abort",
- UI::g_fh1->fontset().is_rtl() ? 114 : 6, 80, 80, 34,
+ UI::g_fh1->fontset()->is_rtl() ? 114 : 6, 80, 80, 34,
g_gr->images().get("images/ui_basic/but4.png"),
g_gr->images().get("images/wui/menu_abort.png"));
cancelbtn->sigclicked.connect(boost::bind(&ActionConfirm::die, this));
=== modified file 'src/wui/building_statistics_menu.cc'
--- src/wui/building_statistics_menu.cc 2016-02-08 20:04:17 +0000
+++ src/wui/building_statistics_menu.cc 2016-02-15 11:00:58 +0000
@@ -92,7 +92,7 @@
UI::Align::kBottomLeft),
unproductive_percent_(
&unproductive_box_, 0, 0, 35, g_gr->images().get("images/ui_basic/but1.png"),
- kLabelFontSize - UI::g_fh1->fontset().size_offset()), // We need consistent height here
+ kLabelFontSize - UI::g_fh1->fontset()->size_offset()), // We need consistent height here
unproductive_label2_(
&unproductive_box_,
/** TRANSLATORS: This is the second part of productivity with input field */
=== modified file 'src/wui/game_objectives_menu.cc'
--- src/wui/game_objectives_menu.cc 2016-02-01 17:17:45 +0000
+++ src/wui/game_objectives_menu.cc 2016-02-15 11:00:58 +0000
@@ -47,7 +47,6 @@
(this,
5, 5,
get_inner_w() - 10, OBJECTIVE_LIST,
- UI::Align::kLeft,
false),
objectivetext
(this,
=== modified file 'src/wui/login_box.cc'
--- src/wui/login_box.cc 2016-02-06 10:59:09 +0000
+++ src/wui/login_box.cc 2016-02-15 11:00:58 +0000
@@ -55,7 +55,7 @@
UI::Button * loginbtn = new UI::Button
(this, "login",
- UI::g_fh1->fontset().is_rtl() ?
+ UI::g_fh1->fontset()->is_rtl() ?
(get_inner_w() / 2 - 200) / 2 :
(get_inner_w() / 2 - 200) / 2 + get_inner_w() / 2,
get_inner_h() - 20 - margin,
@@ -65,7 +65,7 @@
loginbtn->sigclicked.connect(boost::bind(&LoginBox::clicked_ok, boost::ref(*this)));
UI::Button * cancelbtn = new UI::Button
(this, "cancel",
- UI::g_fh1->fontset().is_rtl() ?
+ UI::g_fh1->fontset()->is_rtl() ?
(get_inner_w() / 2 - 200) / 2 + get_inner_w() / 2 :
(get_inner_w() / 2 - 200) / 2,
loginbtn->get_y(), 200, 20,
=== modified file 'src/wui/productionsitewindow.cc'
--- src/wui/productionsitewindow.cc 2016-01-31 21:03:15 +0000
+++ src/wui/productionsitewindow.cc 2016-02-15 11:00:58 +0000
@@ -28,7 +28,6 @@
#include "logic/map_objects/tribes/trainingsite.h"
#include "logic/map_objects/tribes/tribe_descr.h"
#include "logic/map_objects/tribes/worker.h"
-#include "ui_basic/listselect.h"
#include "ui_basic/tabpanel.h"
#include "ui_basic/textarea.h"
#include "wui/waresqueuedisplay.h"
Follow ups
-
[Merge] lp:~widelands-dev/widelands/listselect into lp:widelands
From: noreply, 2016-03-09
-
Re: [Merge] lp:~widelands-dev/widelands/listselect into lp:widelands
From: GunChleoc, 2016-03-09
-
[Merge] lp:~widelands-dev/widelands/listselect into lp:widelands
From: bunnybot, 2016-03-09
-
[Merge] lp:~widelands-dev/widelands/listselect into lp:widelands
From: bunnybot, 2016-03-09
-
[Merge] lp:~widelands-dev/widelands/listselect into lp:widelands
From: bunnybot, 2016-03-08
-
Re: [Merge] lp:~widelands-dev/widelands/listselect into lp:widelands
From: GunChleoc, 2016-03-08
-
[Merge] lp:~widelands-dev/widelands/listselect into lp:widelands
From: bunnybot, 2016-03-06
-
[Merge] lp:~widelands-dev/widelands/listselect into lp:widelands
From: bunnybot, 2016-03-06
-
Re: [Merge] lp:~widelands-dev/widelands/listselect into lp:widelands
From: GunChleoc, 2016-03-06
-
Re: [Merge] lp:~widelands-dev/widelands/listselect into lp:widelands
From: TiborB, 2016-03-05
-
[Merge] lp:~widelands-dev/widelands/listselect into lp:widelands
From: bunnybot, 2016-03-01
-
[Merge] lp:~widelands-dev/widelands/listselect into lp:widelands
From: bunnybot, 2016-03-01
-
[Merge] lp:~widelands-dev/widelands/listselect into lp:widelands
From: bunnybot, 2016-02-22
-
[Merge] lp:~widelands-dev/widelands/listselect into lp:widelands
From: bunnybot, 2016-02-22
-
[Merge] lp:~widelands-dev/widelands/listselect into lp:widelands
From: bunnybot, 2016-02-22
-
[Merge] lp:~widelands-dev/widelands/listselect into lp:widelands
From: bunnybot, 2016-02-19
-
[Merge] lp:~widelands-dev/widelands/listselect into lp:widelands
From: bunnybot, 2016-02-19
-
[Merge] lp:~widelands-dev/widelands/listselect into lp:widelands
From: bunnybot, 2016-02-18
-
[Merge] lp:~widelands-dev/widelands/listselect into lp:widelands
From: bunnybot, 2016-02-18
-
[Merge] lp:~widelands-dev/widelands/listselect into lp:widelands
From: bunnybot, 2016-02-17
-
Re: [Merge] lp:~widelands-dev/widelands/listselect into lp:widelands
From: kaputtnik, 2016-02-15
-
Re: [Merge] lp:~widelands-dev/widelands/listselect into lp:widelands
From: GunChleoc, 2016-02-15
-
Re: [Merge] lp:~widelands-dev/widelands/listselect into lp:widelands
From: kaputtnik, 2016-02-15
-
[Merge] lp:~widelands-dev/widelands/listselect into lp:widelands
From: GunChleoc, 2016-02-15