12#include <unicode/ubrk.h>
13#include <unicode/utypes.h>
14#include <unicode/ubidi.h>
59 result.reserve(sv.length());
61 result += char(tolower(ch));
71 if((byte1 & 0x80) == 0) {
73 }
else if((byte1 & 0xE0) == 0xC0) {
75 }
else if((byte1 & 0xF0) == 0xE0) {
77 }
else if((byte1 & 0xF8) == 0xF0) {
84 return ((b & 0x80) == 0) ? 1 : ((b & 0xE0) == 0xC0) ? 2
85 : ((b & 0xF0) == 0xE0) ? 3 : ((b & 0xF8) == 0xF0) ? 4
89 return (c == 0x3000 || c == 0x205F || c == 0x202F || c == 0x2029 || c == 0x2028 || c == 0x00A0
90 || c == 0x0085 || c <= 0x0020 || (0x2000 <= c && c <= 0x200A));
93 return c == 0x2029 || c == 0x2028 || c ==
uint32_t(
'\n') || c ==
uint32_t(
'\r');
97 auto cpos = file_content;
103 if(
int(file_content[0]) == 0xEF &&
int(file_content[1]) == 0xBB &&
int(file_content[2]) == 0xBF)
106 while(cpos < file_content + file_size) {
107 cpos = parsers::parse_fixed_amount_csv_values<14>(cpos, file_content + file_size,
';', [&](std::string_view
const* values) {
108 auto key =
state.add_key_utf8(values[0]);
109 auto entry =
state.add_locale_data_utf8(values[target_column]);
110 state.locale_key_to_text_sequence.insert_or_assign(key, entry);
114 while(cpos < file_content + file_size) {
115 cpos = parsers::parse_fixed_amount_csv_values<14>(cpos, file_content + file_size,
';', [&](std::string_view
const* values) {
116 auto key =
state.add_key_win1252(values[0]);
117 auto entry =
state.add_locale_data_win1252(values[target_column]);
118 state.locale_key_to_text_sequence.insert_or_assign(key, entry);
126 if(v.length() != (N - 1))
128 for(
unsigned int i = 0; i < N - 1; ++i) {
129 if(tolower(v[i]) != t[i])
135#define CT_STRING_ENUM(X) else if(is_fixed_token_ci(v, #X)) return variable_type::X;
138 if(v.length() == 1) {
145 }
else if(v.length() == 2) {
151 }
else if(v.length() == 3) {
206 }
else if(v.length() == 4) {
256 }
else if(v.length() == 5) {
304 }
else if(v.length() == 6) {
343 }
else if(v.length() == 7) {
388 }
else if(v.length() == 8) {
428 }
else if(v.length() == 9) {
452 }
else if(v.length() == 10) {
476 }
else if(v.length() == 11) {
493 }
else if(v.length() == 12) {
505 }
else if(v.length() == 13) {
525 }
else if(v.length() == 14) {
536 }
else if(v.length() == 15) {
542 }
else if(v.length() == 16) {
548 }
else if(v.length() == 17) {
551 }
else if(v.length() == 18) {
558 }
else if(v.length() == 19) {
563 }
else if(v.length() == 20) {
565 }
else if(v.length() == 21) {
568 }
else if(v.length() == 22) {
573 }
else if(v.length() == 23) {
575 }
else if(v.length() == 24) {
588 constexpr static char16_t converted[256] =
590 { u
' ', u
'\u0001', u
'\u0002', u
'\u0003', u
'\u0004', u
' ', u
' ', u
' ', u
' ', u
'\t', u
'\n', u
' ', u
' ', u
' ', u
' ', u
' ',
591 u
' ', u
' ', u
' ', u
' ', u
' ', u
' ', u
' ', u
' ', u
' ', u
' ', u
' ', u
' ', u
' ', u
' ', u
' ', u
' ',
592 u
' ', u
'!', u
'\"', u
'#', u
'$', u
'%', u
'&', u
'\'', u
'(', u
')', u
'*', u
'+', u
',', u
'-', u
'.', u
'/',
593 u
'0', u
'1', u
'2', u
'3', u
'4', u
'5', u
'6', u
'7', u
'8', u
'9', u
':', u
';', u
'<', u
'=', u
'>', u
'?',
594 u
'@', u
'A', u
'B', u
'C', u
'D', u
'E', u
'F', u
'G', u
'H', u
'I', u
'J', u
'K', u
'L', u
'M', u
'N', u
'O',
595 u
'P', u
'Q', u
'R', u
'S', u
'T', u
'U', u
'V', u
'W', u
'X', u
'Y', u
'Z', u
'[', u
'\\', u
']', u
'^', u
'_',
596 u
'`', u
'a', u
'b', u
'c', u
'd', u
'e', u
'f', u
'g', u
'h', u
'i', u
'j', u
'k', u
'l', u
'm', u
'n', u
'o',
597 u
'p', u
'q', u
'r', u
's', u
't', u
'u', u
'v', u
'w', u
'x', u
'y', u
'z', u
'{', u
'|', u
'}', u
'~', u
' ',
598 u
'\u20AC', u
' ', u
'\u201A', u
' ', u
'\u201E', u
'\u2026', u
'\u2020', u
'\u2021', u
' ', u
'\u2030', u
'\u0160', u
'\u2039', u
'\u015A', u
'\u0164', u
'\u017D', u
'\u0179',
599 u
' ', u
'\u2018', u
'\u2019', u
'\u201C', u
'\u201D', u
'\u2022', u
'\u2013', u
'\u2014', u
' ', u
'\u2122', u
'\u0161',
600 u
'\u203A', u
'\u015B', u
'\u0165', u
'\u017E', u
'\u017A',
601 u
'\u00A0', u
'\u02C7', u
'\u02D8', u
'\u00A2', u
'\u00A3', u
'\u0104', u
'\u00A6', u
'\u00A7', u
'\u00A8', u
'\u00A9',
602 u
'\u015E', u
'\u00AB', u
'\u00AC', u
'-', u
'\u00AE', u
'\u017B',
603 u
'\u00B0', u
'\u00B1', u
'\u02DB', u
'\u0142', u
'\u00B4', u
'\u00B5', u
'\u00B6', u
'\u00B7', u
'\u00B8', u
'\u0105',
604 u
'\u015F', u
'\u00BB', u
'\u013D', u
'\u02DD', u
'\u013E', u
'\u017C',
605 u
'\u0154', u
'\u00C1', u
'\u00C2', u
'\u0102', u
'\u00C4', u
'\u0139', u
'\u0106', u
'\u00C7', u
'\u010C', u
'\u00C9',
606 u
'\u0118', u
'\u00CB', u
'\u011A', u
'\u00CD', u
'\u00CE', u
'\u010E',
607 u
'\u0110', u
'\u0143', u
'\u0147', u
'\u00D3', u
'\u00D4', u
'\u0150', u
'\u00D6', u
'\u00D7', u
'\u0158', u
'\u016E',
608 u
'\u00DA', u
'\u0170', u
'\u00DC', u
'\u00DD', u
'\u0162', u
'\u00DF',
609 u
'\u0115', u
'\u00E1', u
'\u00E2', u
'\u0103', u
'\u00E4', u
'\u013A', u
'\u0107', u
'\u00E7', u
'\u00E8', u
'\u00E9',
610 u
'\u0119', u
'\u00EB', u
'\u011B', u
'\u00ED', u
'\u00EE', u
'\u010F',
611 u
'\u0111', u
'\u0144', u
'\u0148', u
'\u00F3', u
'\u00F4', u
'\u0151', u
'\u00F6', u
'\u00F7', u
'\u0159', u
'\u016F',
612 u
'\u00FA', u
'\u0171', u
'\u00FC', u
'\u00FD', u
'\u0163', u
'\u02D9'};
624 if(
auto it =
state.locale_key_to_text_sequence.find(
id); it !=
state.locale_key_to_text_sequence.end()) {
625 sv =
state.locale_string_view(it->second);
627 sv =
state.to_string_view(
id);
630 char const* section_start = sv.data();
631 for(
char const* pos = sv.data(); pos < sv.data() + sv.length();) {
632 bool colour_esc =
false;
633 if(pos + 1 < sv.data() + sv.length() &&
uint8_t(*pos) == 0xC2 &&
uint8_t(*(pos + 1)) == 0xA7) {
634 if(section_start < pos)
635 result += std::string_view(section_start, pos - section_start);
639 if(pos < sv.data() + sv.length()) {
644 if(section_start < pos)
645 result += std::string_view(section_start, pos - section_start);
647 section_start = pos += 3;
649 if(pos < sv.data() + sv.length()) {
653 }
else if(pos + 1 < sv.data() + sv.length() && *pos ==
'?' &&
is_qmark_color(*(pos + 1))) {
654 if(section_start < pos)
655 result += std::string_view(section_start, pos - section_start);
660 if(pos < sv.data() + sv.length()) {
664 }
else if(*pos ==
'$') {
665 if(section_start < pos)
666 result += std::string_view(section_start, pos - section_start);
668 const char* vend = pos + 1;
669 for(; vend != sv.data() + sv.length() && *vend !=
'$'; ++vend)
674 }
else if(pos + 1 < sv.data() + sv.length() && *pos ==
'\\' && *(pos + 1) ==
'n') {
675 result += std::string_view(section_start, pos - section_start);
676 section_start = pos += 2;
682 if(section_start < sv.data() + sv.length())
683 result += std::string_view(section_start, (sv.data() + sv.length()) - section_start);
688 auto v =
state.lookup_key(txt);
692 return std::string(txt);
697 return state.add_key_utf8(key);
699 return state.add_key_win1252(key);
703 constexpr static double mag[] = {
709 1'000'000'000'000'000.0,
710 1'000'000'000'000'000'000.0
712 constexpr static char const* sufx_two[] = {
721 constexpr static char const* sufx_one[] = {
730 constexpr static char const* sufx_zero[] = {
739 char buffer[200] = { 0 };
740 double dval = double(
num);
741 if(std::abs(dval) <= 1.f) {
742 snprintf(buffer,
sizeof(buffer), sufx_two[0],
float(dval));
743 return std::string(buffer);
745 for(
size_t i = std::extent_v<
decltype(mag)>; i-- > 0;) {
746 if(std::abs(dval) >= mag[i]) {
747 auto reduced = dval / mag[i];
748 if(std::abs(reduced) < 10.0) {
749 snprintf(buffer,
sizeof(buffer), sufx_two[i],
float(reduced));
750 }
else if(std::abs(reduced) < 100.0) {
751 snprintf(buffer,
sizeof(buffer), sufx_one[i],
float(reduced));
753 snprintf(buffer,
sizeof(buffer), sufx_zero[i],
float(reduced));
755 return std::string(buffer);
758 return std::string(
"#inf");
764 return std::string(
"0");
766 constexpr static double mag[] = {
772 1'000'000'000'000'000.0,
773 1'000'000'000'000'000'000.0
775 constexpr static char const* sufx_two[] = {
784 constexpr static char const* sufx_one[] = {
793 constexpr static char const* sufx_zero[] = {
803 char buffer[200] = { 0 };
804 double dval = double(
num);
805 for(
size_t i = std::extent_v<
decltype(mag)>; i-- > 0;) {
806 if(std::abs(dval) >= mag[i]) {
807 auto reduced = dval / mag[i];
808 if(std::abs(reduced) < 10.0) {
809 snprintf(buffer,
sizeof(buffer), sufx_two[i],
float(reduced));
810 }
else if(std::abs(reduced) < 100.0) {
811 snprintf(buffer,
sizeof(buffer), sufx_one[i],
float(reduced));
813 snprintf(buffer,
sizeof(buffer), sufx_zero[i],
float(reduced));
815 return std::string(buffer);
818 return std::string(
"#inf");
823 for(
auto st : fat_id.get_definition().get_abstract_state_membership()) {
824 if(
auto osm = st.get_province().get_state_membership().id; osm && fat_id.id != osm) {
825 if(!
state.key_is_localized(fat_id.get_definition().get_name())) {
832 if(!
state.key_is_localized(fat_id.get_definition().get_name()))
839 for(
auto st : fat_id.get_definition().get_abstract_state_membership()) {
840 if(
auto osm = st.get_province().get_state_membership().id; osm && fat_id.id != osm) {
842 if(!
state.key_is_localized(fat_id.get_definition().get_name())) {
843 if(!
state.key_is_localized(adj_id)) {
850 }
else if(!
state.key_is_localized(adj_id)) {
859 if(!
state.key_is_localized(fat_id.get_definition().get_name()))
866 auto state_instance_id = fat_id.get_state_membership().id;
867 if(state_instance_id) {
870 auto sdef = fat_id.get_abstract_state_membership_as_province().get_state();
871 if(!
state.key_is_localized(sdef.get_name())) {
872 auto lprovs = sdef.get_abstract_state_membership();
873 if(lprovs.begin() != lprovs.end())
881 auto ident =
state.world.nation_get_identity_from_identity_holder(
id);
882 auto gov_id =
state.world.nation_get_government_type(
id);
884 auto gname =
state.world.national_identity_get_government_name(
ident, gov_id);
885 if(
state.key_is_localized(gname))
888 return state.world.national_identity_get_name(
ident);
891 auto ident =
state.world.nation_get_identity_from_identity_holder(
id);
893 if(
auto k =
state.world.national_identity_get_government_adjective(
ident,
state.world.nation_get_government_type(
id));
state.key_is_localized(k)) {
896 return state.world.national_identity_get_adjective(
ident);
900 auto ident =
state.world.nation_get_identity_from_identity_holder(
n);
901 auto gov =
state.world.nation_get_government_type(
n);
903 if(
auto k =
state.world.national_identity_get_government_ruler_name(
ident,
gov);
state.key_is_localized(k)) {
906 return state.world.government_type_get_ruler_name(
gov);
982 char buffer[200] = {0};
988 return std::string(
"0.000");
989 }
else if(
num > 0.f &&
num < 0.001f) {
990 return std::string(
">0.000");
991 }
else if(
num > -0.001f &&
num < 0.f) {
992 return std::string(
"<0.000");
998 return std::string(
"0.00");
999 }
else if(
num > 0.f &&
num < 0.01f) {
1000 return std::string(
">0.00");
1001 }
else if(
num > -0.01f &&
num < 0.f) {
1002 return std::string(
"<0.00");
1008 return std::string(
"0.0");
1009 }
else if(
num > 0.f &&
num < 0.1f) {
1010 return std::string(
">0.0");
1011 }
else if(
num > -0.1f &&
num < 0.f) {
1012 return std::string(
"<0.0");
1018 return std::string(
"0");
1019 }
else if(
num > 0.f &&
num < 1.f) {
1020 return std::string(
">0");
1021 }
else if(
num > -1.f &&
num < 0.f) {
1022 return std::string(
"<0");
1024 return std::to_string(int64_t(
num));
1026 return std::string(buffer);
1044 while(abs_value > 0) {
1048 auto last = abs_value % 10;
1051 result.push_back(
char(
'0' + last));
1065 return std::to_string(
left) +
'/' + std::to_string(
right);
1073 static const std::string_view month_names[12] = {
"january",
"february",
"march",
"april",
"may_month_name",
"june",
"july",
"august",
1074 "september",
"october",
"november",
"december"};
1077 return state.lookup_key(
"january");
1079 return state.lookup_key(month_names[
month - 1]);
1093 if(int32_t(chunk.x) <=
x &&
x <= int32_t(chunk.x) + chunk.width && chunk.y <=
y &&
y <= chunk.y + chunk.height) {
1101 dest.contents.clear();
1102 dest.number_of_lines = 0;
1112 auto gap = (box.
x_position - float(
dest.fixed_parameters.left)) / 2.0f;
1113 for(
size_t i = box.
line_start; i <
dest.base_layout.contents.size(); ++i) {
1114 dest.base_layout.contents[i].x -= gap;
1117 auto gap = (float(
dest.fixed_parameters.right) - box.
x_position) / 2.0f;
1118 for(
size_t i = box.
line_start; i <
dest.base_layout.contents.size(); ++i) {
1119 dest.base_layout.contents[i].x += gap;
1124 for(
size_t i = box.
line_start; i <
dest.base_layout.contents.size(); ++i) {
1125 dest.base_layout.contents[i].x += gap;
1129 for(
size_t i = box.
line_start; i <
dest.base_layout.contents.size(); ++i) {
1130 dest.base_layout.contents[i].x -= gap;
1141 dest.base_layout.number_of_lines += 1;
1148 auto text_height = int32_t(std::ceil(
state.font_collection.line_height(
state,
dest.fixed_parameters.font_id)));
1149 auto line_height = text_height +
dest.fixed_parameters.leading;
1153 auto text_height = int32_t(std::ceil(
state.font_collection.line_height(
state,
dest.fixed_parameters.font_id)));
1154 auto line_height = text_height +
dest.fixed_parameters.leading;
1155 dest.base_layout.number_of_lines += 1;
1156 dest.y_cursor += line_height;
1159 auto text_height = int32_t(std::ceil(
state.font_collection.line_height(
state,
dest.fixed_parameters.font_id)));
1160 auto line_height = text_height +
dest.fixed_parameters.leading;
1161 dest.base_layout.number_of_lines += 1;
1162 dest.y_cursor += line_height;
1234 if(
text.size() == 0)
1238 auto text_height = int32_t(std::ceil(
state.font_collection.line_height(
state,
dest.fixed_parameters.font_id)));
1239 auto line_height = text_height +
dest.fixed_parameters.leading;
1240 auto tmp_color = color;
1241 if(std::holds_alternative<dcon::nation_id>(
source)
1242 || std::holds_alternative<dcon::province_id>(
source)
1243 || std::holds_alternative<dcon::state_instance_id>(
source)
1244 || std::holds_alternative<dcon::state_definition_id>(
source)) {
1245 if(!
dest.fixed_parameters.suppress_hyperlinks) {
1260 bool first_in_line =
true;
1263 std::vector<uint16_t> temp_text;
1265 auto start =
text.data();
1266 auto end = start +
text.length();
1267 int32_t base_index = 0;
1269 while(start + base_index < end) {
1273 temp_text.push_back(
char16_t(c));
1276 temp_text.push_back(
char16_t(p.high));
1277 temp_text.push_back(
char16_t(p.low));
1284 UErrorCode errorCode = U_ZERO_ERROR;
1285 UBreakIterator* lb_it = ubrk_openBinaryRules(
state.font_collection.compiled_ubrk_rules.data(), int32_t(
state.font_collection.compiled_ubrk_rules.size()), (UChar
const*)temp_text.data(), int32_t(temp_text.size()), &errorCode);
1287 if(!lb_it || !U_SUCCESS(errorCode)) {
1296 int32_t glyph_position = 0;
1297 int32_t glyph_start_position = 0;
1298 int32_t cluster_position = 0;
1299 int32_t cluster_start_position = 0;
1301 while(cluster_start_position < int32_t(temp_text.size())) {
1302 if(
dest.fixed_parameters.single_line && box.
x_position <=
dest.fixed_parameters.left)
1305 auto next_cluster_position = ubrk_next(lb_it);
1306 int32_t next_glyph_position = 0;
1308 if(next_cluster_position == UBRK_DONE) {
1309 next_glyph_position = int32_t(all_glyphs.
glyph_info.size());
1310 next_cluster_position = int32_t(temp_text.size());
1312 for(next_glyph_position = glyph_position; next_glyph_position < int32_t(all_glyphs.
glyph_info.size()); ++next_glyph_position) {
1313 if(all_glyphs.
glyph_info[next_glyph_position].cluster >=
uint32_t(next_cluster_position)) {
1319 float extent =
state.font_collection.text_extent(
state, all_glyphs, glyph_start_position, next_glyph_position - glyph_start_position,
dest.fixed_parameters.font_id);
1330 box.
x_position, (!
dest.fixed_parameters.suppress_hyperlinks) ?
source : std::monostate{}, int16_t(box.
y_position), int16_t(extent), int16_t(text_height), tmp_color });
1335 glyph_start_position = next_glyph_position;
1336 glyph_position = next_glyph_position;
1337 cluster_position = next_cluster_position;
1338 cluster_start_position = next_cluster_position;
1339 }
else if(!
dest.fixed_parameters.single_line && box.
x_position - extent <=
dest.fixed_parameters.left) {
1340 extent =
state.font_collection.text_extent(
state, all_glyphs, glyph_start_position, glyph_position - glyph_start_position,
dest.fixed_parameters.font_id);
1345 dest.base_layout.contents.push_back(
1347 box.
x_position, (!
dest.fixed_parameters.suppress_hyperlinks) ?
source : std::monostate{}, int16_t(box.
y_position), int16_t(extent), int16_t(text_height), tmp_color });
1351 glyph_start_position = glyph_position;
1352 cluster_start_position = cluster_position;
1354 ubrk_previous(lb_it);
1355 first_in_line =
true;
1356 }
else if(
dest.fixed_parameters.single_line && box.
x_position - extent <=
dest.fixed_parameters.left) {
1359 bool ellipsis_valid =
true;
1362 if(width_of_ellipsis <= 0 || glyphid == 0) {
1363 ellipsis_valid =
false;
1366 if(
state.user_settings.use_classic_fonts) {
1367 ellipsis_valid =
false;
1368 width_of_ellipsis = 3.0f *
font_size / 6.f;
1371 int32_t
m = glyph_start_position;
1372 while(
m < next_glyph_position) {
1373 if(box.
x_position -
state.font_collection.text_extent(
state, all_glyphs, glyph_start_position,
uint32_t(
m),
dest.fixed_parameters.font_id) - width_of_ellipsis <
dest.fixed_parameters.left)
1377 if(
m >= next_glyph_position)
m = next_glyph_position - 1;
1379 auto cluster_end = all_glyphs.
glyph_info[
m].cluster;
1380 std::vector<uint16_t> tempv{ temp_text.data() + cluster_start_position, temp_text.data() + cluster_end };
1382 if(ellipsis_valid) {
1383 tempv.push_back(0x2026);
1385 tempv.push_back(
'.'); tempv.push_back(
'.'); tempv.push_back(
'.');
1388 dest.base_layout.contents.push_back(
1390 box.
x_position, (!
dest.fixed_parameters.suppress_hyperlinks) ?
source : std::monostate{}, int16_t(box.
y_position), int16_t(extent), int16_t(text_height), tmp_color });
1394 }
else if(next_cluster_position >= int32_t(temp_text.size())) {
1403 box.
x_position, (!
dest.fixed_parameters.suppress_hyperlinks) ?
source : std::monostate{}, int16_t(box.
y_position), int16_t(extent), int16_t(text_height), tmp_color });
1405 if(!
dest.fixed_parameters.single_line && box.
x_position <=
dest.fixed_parameters.left)
1408 glyph_start_position = next_glyph_position;
1409 glyph_position = next_glyph_position;
1410 cluster_position = next_cluster_position;
1411 cluster_start_position = next_cluster_position;
1413 glyph_position = next_glyph_position;
1414 cluster_position = next_cluster_position;
1415 first_in_line =
false;
1420 int32_t glyph_position = 0;
1421 int32_t glyph_start_position = 0;
1422 int32_t cluster_position = 0;
1423 int32_t cluster_start_position = 0;
1425 while(cluster_start_position < int32_t(temp_text.size())) {
1426 if(
dest.fixed_parameters.single_line && box.
x_position >=
dest.fixed_parameters.right)
1429 auto next_cluster_position = ubrk_next(lb_it);
1430 int32_t next_glyph_position = 0;
1432 if(next_cluster_position == UBRK_DONE) {
1433 next_glyph_position = int32_t(all_glyphs.
glyph_info.size());
1434 next_cluster_position = int32_t(temp_text.size());
1436 for(next_glyph_position = glyph_position; next_glyph_position < int32_t(all_glyphs.
glyph_info.size()); ++next_glyph_position) {
1437 if(all_glyphs.
glyph_info[next_glyph_position].cluster >=
uint32_t(next_cluster_position)) {
1443 float extent =
state.font_collection.text_extent(
state, all_glyphs, glyph_start_position, next_glyph_position - glyph_start_position,
dest.fixed_parameters.font_id);
1448 dest.base_layout.contents.push_back(
text_chunk{
text::stored_glyphs(
state,
text::font_index_from_font_id(
state,
dest.fixed_parameters.font_id), std::span<uint16_t>(temp_text.data() + cluster_start_position, next_cluster_position - cluster_start_position)), box.
x_position, (!
dest.fixed_parameters.suppress_hyperlinks) ?
source : std::monostate{}, int16_t(box.
y_position), int16_t(extent), int16_t(text_height), tmp_color });
1457 glyph_start_position = next_glyph_position;
1458 glyph_position = next_glyph_position;
1459 cluster_position = next_cluster_position;
1460 cluster_start_position = next_cluster_position;
1461 }
else if(!
dest.fixed_parameters.single_line && box.
x_position + extent >=
dest.fixed_parameters.right) {
1463 extent =
state.font_collection.text_extent(
state, all_glyphs, glyph_start_position, glyph_position - glyph_start_position,
dest.fixed_parameters.font_id);
1464 dest.base_layout.contents.push_back(
1466 box.
x_position, (!
dest.fixed_parameters.suppress_hyperlinks) ?
source : std::monostate{}, int16_t(box.
y_position), int16_t(extent), int16_t(text_height), tmp_color });
1473 glyph_start_position = glyph_position;
1474 cluster_start_position = cluster_position;
1476 ubrk_previous(lb_it);
1477 first_in_line =
true;
1478 }
else if(
dest.fixed_parameters.single_line && box.
x_position + extent >=
dest.fixed_parameters.right) {
1481 bool ellipsis_valid =
true;
1484 if(width_of_ellipsis <= 0 || glyphid == 0) {
1485 ellipsis_valid =
false;
1488 if(
state.user_settings.use_classic_fonts) {
1489 ellipsis_valid =
false;
1490 width_of_ellipsis = 3.0f *
font_size / 6.f;
1493 int32_t
m = glyph_start_position;
1494 while(
m < next_glyph_position) {
1495 if(box.
x_position +
state.font_collection.text_extent(
state, all_glyphs, glyph_start_position,
uint32_t(
m),
dest.fixed_parameters.font_id) + width_of_ellipsis >
dest.fixed_parameters.right)
1499 if(
m >= next_glyph_position)
m = next_glyph_position - 1;
1501 auto cluster_end = all_glyphs.
glyph_info[
m].cluster;
1502 std::vector<uint16_t> tempv{temp_text.data() + cluster_start_position, temp_text.data() + cluster_end };
1504 if(ellipsis_valid) {
1505 tempv.push_back(0x2026);
1507 tempv.push_back(
'.'); tempv.push_back(
'.'); tempv.push_back(
'.');
1510 dest.base_layout.contents.push_back(
1512 box.
x_position, (!
dest.fixed_parameters.suppress_hyperlinks) ?
source : std::monostate{}, int16_t(box.
y_position), int16_t(extent), int16_t(text_height), tmp_color });
1516 }
else if(next_cluster_position >= int32_t(temp_text.size())) {
1519 dest.base_layout.contents.push_back(
text_chunk{
text::stored_glyphs(
state,
text::font_index_from_font_id(
state,
dest.fixed_parameters.font_id), std::span<uint16_t>(temp_text.data() + cluster_start_position, next_cluster_position - cluster_start_position)), box.
x_position, (!
dest.fixed_parameters.suppress_hyperlinks) ?
source : std::monostate{}, int16_t(box.
y_position), int16_t(extent), int16_t(text_height), tmp_color });
1525 if(!
dest.fixed_parameters.single_line && box.
x_position >=
dest.fixed_parameters.right)
1528 glyph_start_position = next_glyph_position;
1529 glyph_position = next_glyph_position;
1530 cluster_position = next_cluster_position;
1531 cluster_start_position = next_cluster_position;
1533 glyph_position = next_glyph_position;
1534 cluster_position = next_cluster_position;
1535 first_in_line =
false;
1546 if(std::holds_alternative<std::string_view>(
sub)) {
1547 return std::string(std::get<std::string_view>(
sub));
1548 }
else if(std::holds_alternative<dcon::text_key>(
sub)) {
1549 auto tkey = std::get<dcon::text_key>(
sub);
1550 if(
auto it =
state.locale_key_to_text_sequence.find(tkey); it !=
state.locale_key_to_text_sequence.end()) {
1551 return std::string(
state.locale_string_view(it->second));
1553 return std::string(
state.to_string_view(tkey));
1555 }
else if(std::holds_alternative<dcon::nation_id>(
sub)) {
1556 dcon::nation_id nid = std::get<dcon::nation_id>(
sub);
1558 }
else if(std::holds_alternative<dcon::state_instance_id>(
sub)) {
1559 dcon::state_instance_id sid = std::get<dcon::state_instance_id>(
sub);
1561 }
else if(std::holds_alternative<dcon::province_id>(
sub)) {
1562 auto pid = std::get<dcon::province_id>(
sub);
1564 }
else if(std::holds_alternative<dcon::national_identity_id>(
sub)) {
1565 auto t = std::get<dcon::national_identity_id>(
sub);
1566 auto h =
state.world.national_identity_get_nation_from_identity_holder(t);
1568 }
else if(std::holds_alternative<int64_t>(
sub)) {
1569 return std::to_string(std::get<int64_t>(
sub));
1570 }
else if(std::holds_alternative<fp_one_place>(
sub)) {
1572 }
else if(std::holds_alternative<fp_two_places>(
sub)) {
1574 }
else if(std::holds_alternative<fp_three_places>(
sub)) {
1576 }
else if(std::holds_alternative<fp_four_places>(
sub)) {
1578 }
else if(std::holds_alternative<sys::date>(
sub)) {
1580 }
else if(std::holds_alternative<fp_currency>(
sub)) {
1582 }
else if(std::holds_alternative<pretty_integer>(
sub)) {
1584 }
else if(std::holds_alternative<fp_percentage>(
sub)) {
1586 }
else if(std::holds_alternative<fp_percentage_one_place>(
sub)) {
1588 }
else if(std::holds_alternative<int_percentage>(
sub)) {
1589 return std::to_string(std::get<int_percentage>(
sub).
value) +
"%";
1590 }
else if(std::holds_alternative<int_wholenum>(
sub)) {
1592 }
else if(std::holds_alternative<dcon::state_definition_id>(
sub)) {
1595 return std::string(
"?");
1602 if(sv.length() == 0)
1605 auto current_color =
dest.fixed_parameters.color;
1607 auto text_height = int32_t(std::ceil(
state.font_collection.line_height(
state,
dest.fixed_parameters.font_id)));
1608 auto line_height = text_height +
dest.fixed_parameters.leading;
1610 char const* seq_start = sv.data();
1611 char const* seq_end = sv.data() + sv.size();
1612 char const* section_start = seq_start;
1614 auto add_text_range = [&](std::string_view sv) {
1615 if(sv.length() > 0) {
1620 for(
char const* pos = seq_start; pos < seq_end;) {
1621 bool colour_esc =
false;
1622 if(pos + 1 < seq_end &&
uint8_t(*pos) == 0xC2 &&
uint8_t(*(pos + 1)) == 0xA7) {
1623 if(section_start < pos)
1624 add_text_range(std::string_view(section_start, pos - section_start));
1627 section_start = pos;
1631 current_color =
dest.fixed_parameters.color;
1633 current_color = newcolor;
1636 section_start = pos;
1639 if(section_start < pos)
1640 add_text_range(std::string_view(section_start, pos - section_start));
1642 section_start = pos += 3;
1647 current_color =
dest.fixed_parameters.color;
1649 current_color = newcolor;
1652 section_start = pos;
1654 }
else if(*pos ==
'@' && pos + 3 < seq_end) {
1655 if(*(pos + 1) ==
'(' && *(pos + 3) ==
')') {
1656 if(*(pos + 2) ==
'A') {
1657 if(section_start < pos)
1658 add_text_range(std::string_view(section_start, pos - section_start));
1661 section_start = pos;
1662 }
else if(*(pos + 2) ==
'N') {
1663 if(section_start < pos)
1664 add_text_range(std::string_view(section_start, pos - section_start));
1667 section_start = pos;
1668 }
else if(*(pos + 2) ==
'T') {
1669 if(section_start < pos)
1670 add_text_range(std::string_view(section_start, pos - section_start));
1673 section_start = pos;
1674 }
else if(*(pos + 2) ==
'F') {
1675 if(section_start < pos)
1676 add_text_range(std::string_view(section_start, pos - section_start));
1679 section_start = pos;
1683 }
else if(*(pos + 1) ==
'*') {
1684 uint8_t tens = char(*(pos + 2)) -
'0';
1685 uint8_t ones = char(*(pos + 3)) -
'0';
1686 uint8_t unit_index = tens * 10 + ones;
1688 dcon::unit_type_id given_unit_type_id { unit_index };
1689 auto icon =
state.military_definitions.unit_base_definitions[given_unit_type_id].icon;
1691 section_start = pos;
1693 auto tag_int =
nations::tag_to_int(
char(toupper(*(pos + 1))),
char(toupper(*(pos + 2))),
char(toupper(*(pos + 3))));
1694 bool matched =
false;
1695 for(
auto nid :
state.world.in_national_identity) {
1696 if(nid.get_identifying_int() == tag_int) {
1699 if(section_start < pos)
1700 add_text_range(std::string_view(section_start, pos - section_start));
1705 section_start = pos;
1712 }
else if(pos + 1 < seq_end && *pos ==
'?' &&
is_qmark_color(*(pos + 1))) {
1713 if(section_start < pos)
1714 add_text_range(std::string_view(section_start, pos - section_start));
1717 section_start = pos;
1724 current_color =
dest.fixed_parameters.color;
1726 current_color = newcolor;
1729 section_start = pos;
1731 }
else if(*pos ==
'$') {
1732 if(section_start < pos)
1733 add_text_range(std::string_view(section_start, pos - section_start));
1735 const char* vend = pos + 1;
1736 for(; vend != seq_end && *vend !=
'$'; ++vend)
1738 if(vend > pos + 1) {
1741 if(
auto it = mp.find(
uint32_t(var_type)); it != mp.end()) {
1752 section_start = pos;
1753 }
else if(pos + 1 < seq_end && *pos ==
'\\' && *(pos + 1) ==
'n') {
1754 if(section_start < pos)
1755 add_text_range(std::string_view(section_start, pos - section_start));
1758 section_start = pos += 2;
1764 if(section_start < seq_end)
1765 add_text_range(std::string_view(section_start, seq_end - section_start));
1772 std::string_view sv;
1773 if(
auto it =
state.locale_key_to_text_sequence.find(source_text); it !=
state.locale_key_to_text_sequence.end()) {
1774 sv =
state.locale_string_view(it->second);
1776 sv =
state.to_string_view(source_text);
1801 return layout_box{
dest.base_layout.contents.size(),
dest.base_layout.contents.size(), indent, 0, 0,
1802 float(indent +
dest.fixed_parameters.left), 0,
dest.fixed_parameters.color};
1804 return layout_box{
dest.base_layout.contents.size(),
dest.base_layout.contents.size(), indent, 0, 0,
1805 float(
dest.fixed_parameters.right - indent), 0,
dest.fixed_parameters.color };
1811 dest.current_column_x =
dest.used_width +
dest.column_width;
1812 for(
auto i = box.
first_chunk; i <
dest.base_layout.contents.size(); ++i) {
1813 dest.base_layout.contents[i].y +=
dest.fixed_parameters.top;
1814 dest.base_layout.contents[i].x += float(
dest.current_column_x);
1815 dest.used_width = std::max(
dest.used_width, int32_t(
dest.base_layout.contents[i].x +
dest.base_layout.contents[i].width));
1819 for(
auto i = box.
first_chunk; i <
dest.base_layout.contents.size(); ++i) {
1820 dest.base_layout.contents[i].y += int16_t(
dest.y_cursor);
1821 dest.base_layout.contents[i].x += float(
dest.current_column_x);
1822 dest.used_width = std::max(
dest.used_width, int32_t(
dest.base_layout.contents[i].x +
dest.base_layout.contents[i].width));
1826 dest.used_height = std::max(
dest.used_height,
dest.y_cursor);
1829 dest.current_column_x =
dest.used_width -
dest.column_width;
1830 for(
auto i = box.
first_chunk; i <
dest.base_layout.contents.size(); ++i) {
1831 dest.base_layout.contents[i].y +=
dest.fixed_parameters.top;
1832 dest.base_layout.contents[i].x += float(
dest.current_column_x) - float(
dest.fixed_parameters.right -
dest.fixed_parameters.left);
1833 dest.used_width = std::min(
dest.used_width, int32_t(
dest.base_layout.contents[i].x));
1837 for(
auto i = box.
first_chunk; i <
dest.base_layout.contents.size(); ++i) {
1838 dest.base_layout.contents[i].y += int16_t(
dest.y_cursor);
1839 dest.base_layout.contents[i].x += float(
dest.current_column_x) - float(
dest.fixed_parameters.right -
dest.fixed_parameters.left);
1840 dest.used_width = std::min(
dest.used_width, int32_t(
dest.base_layout.contents[i].x));
1844 dest.used_height = std::max(
dest.used_height,
dest.y_cursor);
1849 for(
auto i = box.
first_chunk; i <
dest.base_layout.contents.size(); ++i) {
1850 dest.base_layout.contents[i].y += int16_t(
dest.y_cursor);
1860 dest.internal_close_box(box);
1874 dest.contents.clear();
1875 dest.number_of_lines = 0;
1881 if(
auto k =
state.lookup_key(key); k) {
1892 if(
auto k =
state.lookup_key(key); k) {
1948 if(
auto k =
state.lookup_key(key); k) {
1966 if(
auto k =
state.lookup_key(key); k) {
1984 if(
auto k =
state.lookup_key(key); k) {
2004 if(
auto k =
state.lookup_key(key); k) {
2014void add_line_with_condition(
sys::state&
state,
layout_base&
dest, std::string_view key,
bool condition_met,
variable_type subkey,
substitution value,
variable_type subkeyb,
substitution valueb,
variable_type subkeyc,
substitution valuec, int32_t indent) {
2025 if(
auto k =
state.lookup_key(key); k) {
2040 if(
auto k =
state.lookup_key(key); k) {
2053 if(
auto k =
state.lookup_key(key); k) {
2067 if(
auto k =
state.lookup_key(key); k) {
2083 if(
auto k =
state.lookup_key(key); k) {
2106 auto ident =
state.world.nation_get_identity_from_identity_holder(
n);
2116 std::string_view sv;
2117 if(
auto it =
state.locale_key_to_text_sequence.find(source_text); it !=
state.locale_key_to_text_sequence.end()) {
2118 sv =
state.locale_string_view(it->second);
2120 sv =
state.to_string_view(source_text);
2123 char const* seq_start = sv.data();
2124 char const* seq_end = sv.data() + sv.size();
2125 char const* section_start = seq_start;
2127 auto add_text_range = [&](std::string_view sv) {
2131 for(
char const* pos = seq_start; pos < seq_end;) {
2132 bool colour_esc =
false;
2133 if(pos + 1 < seq_end &&
uint8_t(*pos) == 0xC2 &&
uint8_t(*(pos + 1)) == 0xA7) {
2134 if(section_start < pos)
2135 add_text_range(std::string_view(section_start, pos - section_start));
2138 section_start = pos;
2141 section_start = pos;
2144 if(section_start < pos)
2145 add_text_range(std::string_view(section_start, pos - section_start));
2147 section_start = pos += 3;
2151 section_start = pos;
2153 }
else if(pos + 1 < seq_end && *pos ==
'?' &&
is_qmark_color(*(pos + 1))) {
2154 if(section_start < pos)
2155 add_text_range(std::string_view(section_start, pos - section_start));
2158 section_start = pos;
2162 section_start = pos;
2164 }
else if(*pos ==
'$') {
2165 if(section_start < pos)
2166 add_text_range(std::string_view(section_start, pos - section_start));
2168 const char* vend = pos + 1;
2169 for(; vend != seq_end && *vend !=
'$'; ++vend)
2171 if(vend > pos + 1) {
2174 if(
auto it = mp.find(
uint32_t(var_type)); it != mp.end()) {
2180 result += std::string_view(pos, (vend - pos) + 1);
2184 section_start = pos;
2185 }
else if(pos + 1 < seq_end && *pos ==
'\\' && *(pos + 1) ==
'n') {
2186 add_text_range(std::string_view(section_start, pos - section_start));
2187 section_start = pos += 2;
2193 if(section_start < seq_end)
2194 add_text_range(std::string_view(section_start, seq_end - section_start));
2200 dcon::text_key source_text;
2201 if(
auto k =
state.lookup_key(key); k) {
2206 return std::string{key};
float base_glyph_width(char32_t ch_in)
pop_satisfaction_wrapper_fat fatten(data_container const &c, pop_satisfaction_wrapper_id id) noexcept
constexpr uint8_t level_friendly
constexpr uint8_t level_opposed
constexpr uint8_t level_neutral
constexpr uint8_t level_hostile
constexpr uint8_t level_in_sphere
constexpr uint8_t level_mask
constexpr uint8_t level_cordial
@ immigration_colonization_focus
uint32_t tag_to_int(char first, char second, char third)
std::string lb_resolve_substitution(sys::state &state, substitution sub, substitution_map const &mp)
void lb_finish_line(layout_base &dest, layout_box &box, int32_t line_height)
@ crisisdefender_continent
@ error_no_matching_value
@ crisisattacker_continent
void add_line_break_to_layout_box(sys::state &state, layout_base &dest, layout_box &box)
void add_to_layout_box(sys::state &state, layout_base &dest, layout_box &box, embedded_flag ico)
std::string resolve_string_substitution(sys::state &state, dcon::text_key source_text, substitution_map const &mp)
std::string format_money(float num)
std::string get_focus_category_name(sys::state const &state, nations::focus_type category)
int32_t size_from_font_id(uint16_t id)
std::string get_name_as_string(sys::state &state, T t)
std::string format_ratio(int32_t left, int32_t right)
layout_box open_layout_box(layout_base &dest, int32_t indent)
bool codepoint_is_space(uint32_t c) noexcept
void add_unparsed_text_to_layout_box(sys::state &state, layout_base &dest, layout_box &box, std::string_view sv, substitution_map const &mp)
bool codepoint_is_line_break(uint32_t c) noexcept
columnar_layout create_columnar_layout(sys::state &state, layout &dest, layout_parameters const ¶ms, int32_t column_width)
std::string date_to_string(sys::state &state, sys::date date)
void localised_single_sub_box(sys::state &state, layout_base &dest, layout_box &box, std::string_view key, variable_type subkey, substitution value)
void localised_format_box(sys::state &state, layout_base &dest, layout_box &box, std::string_view key, text::substitution_map const &sub)
std::string prettify(int64_t num)
endless_layout create_endless_layout(sys::state &state, layout &dest, layout_parameters const ¶ms)
std::string format_float(float num, size_t digits)
dcon::text_key get_ruler_title(sys::state &state, dcon::nation_id n)
void add_line(sys::state &state, layout_base &dest, dcon::text_key txt, int32_t indent)
std::string get_short_state_name(sys::state &state, dcon::state_instance_id state_id)
uint32_t codepoint_from_utf8(char const *start, char const *end)
void add_line_with_condition(sys::state &state, layout_base &dest, std::string_view key, bool condition_met, int32_t indent)
void add_line_break_to_layout(sys::state &state, columnar_layout &dest)
text::alignment to_text_alignment(ui::alignment in)
text_color char_to_color(char in)
std::string lowercase_str(std::string_view sv)
bool is_fixed_token_ci(std::string_view v, char const (&t)[N])
char16_t win1250toUTF16(char in)
void add_to_substitution_map(substitution_map &mp, variable_type key, substitution value)
surrogate_pair make_surrogate_pair(uint32_t val) noexcept
void add_divider_to_layout_box(sys::state &state, layout_base &dest, layout_box &box)
dcon::text_key get_adjective(sys::state &state, dcon::nation_id id)
std::string get_dynamic_state_name(sys::state &state, dcon::state_instance_id state_id)
std::string format_wholenum(int32_t num)
size_t size_from_utf8(char const *start, char const *)
ankerl::unordered_dense::map< uint32_t, substitution > substitution_map
bool requires_surrogate_pair(uint32_t codepoint)
std::string produce_simple_string(sys::state const &state, dcon::text_key id)
dcon::text_key get_name(sys::state &state, dcon::nation_id id)
font_selection font_index_from_font_id(sys::state &state, uint16_t id)
std::string format_percentage(float num, size_t digits)
void consume_csv_file(sys::state &state, char const *file_content, uint32_t file_size, int32_t target_column, bool as_unicode)
text::alignment localized_alignment(sys::state &state, text::alignment in)
std::string get_influence_level_name(sys::state const &state, uint8_t v)
variable_type variable_type_from_name(std::string_view v)
dcon::text_key localize_month(sys::state const &state, uint16_t month)
void add_space_to_layout_box(sys::state &state, layout_base &dest, layout_box &box)
void nation_name_and_flag(sys::state &state, dcon::nation_id n, layout_base &dest, int32_t indent)
std::string get_province_state_name(sys::state &state, dcon::province_id prov_id)
dcon::text_key find_or_add_key(sys::state &state, std::string_view key, bool as_unicode)
uint32_t font_size(std::string_view txt)
std::string prettify_currency(float num)
void close_layout_box(columnar_layout &dest, layout_box &box)
bool is_qmark_color(char in)
std::variant< std::string_view, dcon::text_key, dcon::province_id, dcon::state_instance_id, dcon::nation_id, dcon::national_identity_id, int64_t, fp_one_place, sys::date, std::monostate, fp_two_places, fp_three_places, fp_four_places, fp_currency, pretty_integer, fp_percentage, fp_percentage_one_place, int_percentage, int_wholenum, dcon::state_definition_id, embedded_icon, embedded_flag, embedded_unit_icon > substitution
void internal_close_box(layout_box &box) final
void internal_close_box(layout_box &box) final
text_chunk const * get_chunk_from_position(int32_t x, int32_t y) const
std::vector< text_chunk > contents
void internal_close_box(layout_box &box) final
void add_text(sys::state &state, std::string_view v)
std::vector< stored_glyph > glyph_info
#define CT_STRING_ENUM(X)