cTextMsg pre-calculate layout

This commit is contained in:
2024-08-12 15:53:55 -05:00
committed by Celtic Minstrel
parent 5f97d8bfb3
commit c08a10867c
4 changed files with 108 additions and 58 deletions

View File

@@ -95,6 +95,29 @@ void cTextMsg::setFixed(bool w, bool h) {
fixedHeight = h; fixedHeight = h;
} }
void cTextMsg::calculate_layout() {
to_rect = frame;
msg = lbl;
for(const auto& key : keyRefs) {
size_t pos = msg.find_first_of(KEY_PLACEHOLDER);
if(pos == std::string::npos) break;
if(key && !parent->hasControl(*key)) continue;
cControl& ctrl = key ? parent->getControl(*key) : *this;
msg.replace(pos, 1, ctrl.getAttachedKeyDescription());
}
if(to_rect.bottom - to_rect.top < 20) { // essentially, it's a single line
style.lineHeight = 12;
to_rect.left += 3;
text_mode = eTextMode::LEFT_BOTTOM;
}else {
style.lineHeight = textSize + 2;
to_rect.inset(4,4);
text_mode = eTextMode::WRAP;
break_info = calculate_line_wrapping(to_rect, msg, style);
}
calculated = true;
}
void cTextMsg::recalcRect() { void cTextMsg::recalcRect() {
if(fixedWidth && fixedHeight) return; if(fixedWidth && fixedHeight) return;
TextStyle style; TextStyle style;
@@ -151,6 +174,7 @@ void cTextMsg::recalcRect() {
calc_rect.width() = combo.width() + 16; calc_rect.width() = combo.width() + 16;
} }
frame = calc_rect; frame = calc_rect;
calculate_layout();
} }
cTextMsg::cTextMsg(cDialog& parent) : cTextMsg::cTextMsg(cDialog& parent) :
@@ -189,10 +213,6 @@ void cTextMsg::draw(){
inWindow->setActive(); inWindow->setActive();
if(visible){ if(visible){
TextStyle style;
style.font = textFont;
style.pointSize = textSize;
style.underline = underlined;
drawFrame(2, frameStyle); drawFrame(2, frameStyle);
sf::Color draw_color = color; sf::Color draw_color = color;
if(depressed){ if(depressed){
@@ -200,24 +220,9 @@ void cTextMsg::draw(){
draw_color.g = 256 - draw_color.g; draw_color.g = 256 - draw_color.g;
draw_color.b = 256 - draw_color.b; draw_color.b = 256 - draw_color.b;
} }
std::string msg = lbl;
for(const auto& key : keyRefs) {
size_t pos = msg.find_first_of(KEY_PLACEHOLDER);
if(pos == std::string::npos) break;
if(key && !parent->hasControl(*key)) continue;
cControl& ctrl = key ? parent->getControl(*key) : *this;
msg.replace(pos, 1, ctrl.getAttachedKeyDescription());
}
style.colour = draw_color; style.colour = draw_color;
if(to_rect.bottom - to_rect.top < 20) { // essentially, it's a single line if (!calculated) calculate_layout();
style.lineHeight = 12; win_draw_string(*inWindow,to_rect,msg,text_mode,style,break_info);
to_rect.left += 3;
win_draw_string(*inWindow,to_rect,msg,eTextMode::LEFT_BOTTOM,style);
}else {
style.lineHeight = textSize + 2;
to_rect.inset(4,4);
win_draw_string(*inWindow,to_rect,msg,eTextMode::WRAP,style);
}
} }
} }

View File

@@ -55,5 +55,12 @@ private:
std::vector<boost::optional<std::string>> keyRefs; std::vector<boost::optional<std::string>> keyRefs;
std::string fromList; std::string fromList;
bool underlined = false, fixedWidth = false, fixedHeight = false; bool underlined = false, fixedWidth = false, fixedHeight = false;
TextStyle style;
rectangle to_rect;
break_info_t break_info;
eTextMode text_mode;
std::string msg;
void calculate_layout();
bool calculated = false;
}; };
#endif #endif

View File

@@ -46,11 +46,10 @@ struct text_params_t {
enum {RECTS, SNIPPETS} returnType; enum {RECTS, SNIPPETS} returnType;
std::vector<rectangle> returnRects; std::vector<rectangle> returnRects;
std::vector<snippet_t> snippets; std::vector<snippet_t> snippets;
// Pre-calculated line wrapping:
break_info_t break_info;
}; };
// last_line_break, last_word_break
typedef std::vector<std::pair<unsigned short, unsigned short>> break_info_t;
static void push_snippets(size_t start, size_t end, text_params_t& options, size_t& iHilite, const std::string& str, location loc) { static void push_snippets(size_t start, size_t end, text_params_t& options, size_t& iHilite, const std::string& str, location loc) {
std::vector<hilite_t>& hilites = options.hilite_ranges; std::vector<hilite_t>& hilites = options.hilite_ranges;
std::vector<snippet_t>& snippets = options.snippets; std::vector<snippet_t>& snippets = options.snippets;
@@ -90,53 +89,33 @@ static void push_snippets(size_t start, size_t end, text_params_t& options, size
} while(start < upper_bound); } while(start < upper_bound);
} }
static void win_draw_string(sf::RenderTarget& dest_window,rectangle dest_rect,std::string str,text_params_t& options) { break_info_t calculate_line_wrapping(rectangle dest_rect, std::string str, TextStyle style) {
if(str.empty()) return; // Nothing to do! break_info_t break_info;
short line_height = options.style.lineHeight; if(str.empty()) return break_info; // Nothing to do!
sf::Text str_to_draw;
options.style.applyTo(str_to_draw);
short str_len;
unsigned short last_line_break = 0,last_word_break = 0;
short total_width = 0;
short adjust_x = 1, adjust_y = 10;
str_to_draw.setString("fj"); // Something that has both an ascender and a descender short line_height = style.lineHeight;
// TODO: Why the heck are we drawing a whole line higher than requested!? sf::Text str_to_draw;
adjust_y -= str_to_draw.getLocalBounds().height; style.applyTo(str_to_draw);
short str_len = str.length();
unsigned short last_line_break = 0,last_word_break = 0;
str_to_draw.setString(str); str_to_draw.setString(str);
str_len = str.length(); short total_width = str_to_draw.getLocalBounds().width;
if(str_len == 0) {
return;
}
eTextMode mode = options.mode; if(total_width < dest_rect.width()){
total_width = str_to_draw.getLocalBounds().width; // The text fits on one line, so break_info won't end up being used by win_draw_string anyway
if(mode == eTextMode::WRAP && total_width < dest_rect.width()) return break_info;
mode = eTextMode::LEFT_TOP; }
if(mode == eTextMode::LEFT_TOP && str.find('|') != std::string::npos)
mode = eTextMode::WRAP;
auto text_len = [&str_to_draw](size_t i) -> int { auto text_len = [&str_to_draw](size_t i) -> int {
return str_to_draw.findCharacterPos(i).x; return str_to_draw.findCharacterPos(i).x;
}; };
// Special stuff
size_t iHilite = 0;
location moveTo;
line_height -= 2; // TODO: ...why are we arbitrarily reducing the line height from the requested value?
break_info_t break_info;
if(mode == eTextMode::WRAP) {
moveTo = location(dest_rect.left + adjust_x, dest_rect.top + adjust_y);
short i; short i;
for(i = 0; text_len(i) != text_len(i + 1) && i < str_len; i++) { for(i = 0; text_len(i) != text_len(i + 1) && i < str_len; i++) {
if(((text_len(i) - text_len(last_line_break) > (dest_rect.width() - 6)) if(((text_len(i) - text_len(last_line_break) > (dest_rect.width() - 6))
&& (last_word_break >= last_line_break)) || (str[i] == '|')) { && (last_word_break >= last_line_break)) || (str[i] == '|')) {
if(str[i] == '|') { if(str[i] == '|') {
if(!options.showBreaks) str[i] = ' ';
last_word_break = i + 1; last_word_break = i + 1;
} else if(last_line_break == last_word_break) } else if(last_line_break == last_word_break)
last_word_break = i; last_word_break = i;
@@ -153,6 +132,52 @@ static void win_draw_string(sf::RenderTarget& dest_window,rectangle dest_rect,st
break_info.push_back(std::make_pair(last_line_break, str.length() + 1)); break_info.push_back(std::make_pair(last_line_break, str.length() + 1));
} }
return break_info;
}
static void win_draw_string(sf::RenderTarget& dest_window,rectangle dest_rect,std::string str,text_params_t& options) {
if(str.empty()) return; // Nothing to do!
short line_height = options.style.lineHeight;
sf::Text str_to_draw;
options.style.applyTo(str_to_draw);
short adjust_x = 1, adjust_y = 10;
str_to_draw.setString("fj"); // Something that has both an ascender and a descender
// TODO: Why the heck are we drawing a whole line higher than requested!?
adjust_y -= str_to_draw.getLocalBounds().height;
str_to_draw.setString(str);
short total_width = str_to_draw.getLocalBounds().width;
eTextMode mode = options.mode;
if(mode == eTextMode::WRAP && total_width < dest_rect.width())
mode = eTextMode::LEFT_TOP;
if(mode == eTextMode::LEFT_TOP && str.find('|') != std::string::npos)
mode = eTextMode::WRAP;
// Special stuff
size_t iHilite = 0;
location moveTo;
line_height -= 2; // TODO: ...why are we arbitrarily reducing the line height from the requested value?
if(!options.showBreaks){
for(int i=0; i < str.length(); ++i){
if(str[i] == '|') str[i] = ' ';
}
}
if(mode == eTextMode::WRAP) {
break_info_t break_info = options.break_info;
// It is better to pre-calculate line-wrapping and pass it in the options,
// but if you don't, this will handle line-wrapping every frame:
if(break_info.empty()){
break_info = calculate_line_wrapping(dest_rect, str, options.style);
}
moveTo = location(dest_rect.left + adjust_x, dest_rect.top + adjust_y);
for(auto break_info_pair : break_info){ for(auto break_info_pair : break_info){
push_snippets(break_info_pair.first, break_info_pair.second, options, iHilite, str, moveTo); push_snippets(break_info_pair.first, break_info_pair.second, options, iHilite, str, moveTo);
moveTo.y += line_height; moveTo.y += line_height;
@@ -210,6 +235,14 @@ void win_draw_string(sf::RenderTarget& dest_window,rectangle dest_rect,std::stri
win_draw_string(dest_window, dest_rect, str, params); win_draw_string(dest_window, dest_rect, str, params);
} }
void win_draw_string(sf::RenderTarget& dest_window,rectangle dest_rect,std::string str,eTextMode mode,TextStyle style,break_info_t break_info) {
text_params_t params;
params.mode = mode;
params.style = style;
params.break_info = break_info;
win_draw_string(dest_window, dest_rect, str, params);
}
std::vector<rectangle> draw_string_hilite(sf::RenderTarget& dest_window,rectangle dest_rect,std::string str,TextStyle style,std::vector<hilite_t> hilites,sf::Color hiliteClr) { std::vector<rectangle> draw_string_hilite(sf::RenderTarget& dest_window,rectangle dest_rect,std::string str,TextStyle style,std::vector<hilite_t> hilites,sf::Color hiliteClr) {
text_params_t params; text_params_t params;
params.mode = eTextMode::WRAP; params.mode = eTextMode::WRAP;

View File

@@ -37,6 +37,9 @@ struct TextStyle {
void applyTo(sf::Text& text); void applyTo(sf::Text& text);
}; };
// elements: std::make_pair(last_line_break, last_word_break)
typedef std::vector<std::pair<unsigned short, unsigned short>> break_info_t;
struct snippet_t { struct snippet_t {
std::string text; std::string text;
location at; location at;
@@ -53,6 +56,8 @@ enum class eTextMode {
std::vector<rectangle> draw_string_hilite(sf::RenderTarget& dest_window,rectangle dest_rect,std::string str,TextStyle style,std::vector<hilite_t> hilites,sf::Color hiliteClr); std::vector<rectangle> draw_string_hilite(sf::RenderTarget& dest_window,rectangle dest_rect,std::string str,TextStyle style,std::vector<hilite_t> hilites,sf::Color hiliteClr);
std::vector<snippet_t> draw_string_sel(sf::RenderTarget& dest_window,rectangle dest_rect,std::string str,TextStyle style,std::vector<hilite_t> hilites,sf::Color hiliteClr); std::vector<snippet_t> draw_string_sel(sf::RenderTarget& dest_window,rectangle dest_rect,std::string str,TextStyle style,std::vector<hilite_t> hilites,sf::Color hiliteClr);
void win_draw_string(sf::RenderTarget& dest_window,rectangle dest_rect,std::string str,eTextMode mode,TextStyle style); void win_draw_string(sf::RenderTarget& dest_window,rectangle dest_rect,std::string str,eTextMode mode,TextStyle style);
void win_draw_string(sf::RenderTarget& dest_window,rectangle dest_rect,std::string str,eTextMode mode,TextStyle style, break_info_t break_info);
break_info_t calculate_line_wrapping(rectangle dest_rect, std::string str, TextStyle style);
size_t string_length(std::string str, TextStyle style, short* height = nullptr); size_t string_length(std::string str, TextStyle style, short* height = nullptr);
#endif #endif