cTextMsg pre-calculate layout
This commit is contained in:
@@ -95,6 +95,29 @@ void cTextMsg::setFixed(bool w, bool 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() {
|
||||
if(fixedWidth && fixedHeight) return;
|
||||
TextStyle style;
|
||||
@@ -151,6 +174,7 @@ void cTextMsg::recalcRect() {
|
||||
calc_rect.width() = combo.width() + 16;
|
||||
}
|
||||
frame = calc_rect;
|
||||
calculate_layout();
|
||||
}
|
||||
|
||||
cTextMsg::cTextMsg(cDialog& parent) :
|
||||
@@ -189,10 +213,6 @@ void cTextMsg::draw(){
|
||||
inWindow->setActive();
|
||||
|
||||
if(visible){
|
||||
TextStyle style;
|
||||
style.font = textFont;
|
||||
style.pointSize = textSize;
|
||||
style.underline = underlined;
|
||||
drawFrame(2, frameStyle);
|
||||
sf::Color draw_color = color;
|
||||
if(depressed){
|
||||
@@ -200,24 +220,9 @@ void cTextMsg::draw(){
|
||||
draw_color.g = 256 - draw_color.g;
|
||||
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;
|
||||
if(to_rect.bottom - to_rect.top < 20) { // essentially, it's a single line
|
||||
style.lineHeight = 12;
|
||||
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);
|
||||
}
|
||||
if (!calculated) calculate_layout();
|
||||
win_draw_string(*inWindow,to_rect,msg,text_mode,style,break_info);
|
||||
}
|
||||
}
|
||||
|
||||
|
@@ -55,5 +55,12 @@ private:
|
||||
std::vector<boost::optional<std::string>> keyRefs;
|
||||
std::string fromList;
|
||||
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
|
||||
|
@@ -46,11 +46,10 @@ struct text_params_t {
|
||||
enum {RECTS, SNIPPETS} returnType;
|
||||
std::vector<rectangle> returnRects;
|
||||
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) {
|
||||
std::vector<hilite_t>& hilites = options.hilite_ranges;
|
||||
std::vector<snippet_t>& snippets = options.snippets;
|
||||
@@ -90,14 +89,57 @@ static void push_snippets(size_t start, size_t end, text_params_t& options, size
|
||||
} while(start < upper_bound);
|
||||
}
|
||||
|
||||
break_info_t calculate_line_wrapping(rectangle dest_rect, std::string str, TextStyle style) {
|
||||
break_info_t break_info;
|
||||
if(str.empty()) return break_info; // Nothing to do!
|
||||
|
||||
short line_height = style.lineHeight;
|
||||
sf::Text str_to_draw;
|
||||
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);
|
||||
short total_width = str_to_draw.getLocalBounds().width;
|
||||
|
||||
if(total_width < dest_rect.width()){
|
||||
// The text fits on one line, so break_info won't end up being used by win_draw_string anyway
|
||||
return break_info;
|
||||
}
|
||||
|
||||
auto text_len = [&str_to_draw](size_t i) -> int {
|
||||
return str_to_draw.findCharacterPos(i).x;
|
||||
};
|
||||
|
||||
short 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))
|
||||
&& (last_word_break >= last_line_break)) || (str[i] == '|')) {
|
||||
if(str[i] == '|') {
|
||||
last_word_break = i + 1;
|
||||
} else if(last_line_break == last_word_break)
|
||||
last_word_break = i;
|
||||
break_info.push_back(std::make_pair(last_line_break, last_word_break));
|
||||
last_line_break = last_word_break;
|
||||
}
|
||||
if(str[i] == ' ')
|
||||
last_word_break = i + 1;
|
||||
}
|
||||
|
||||
if(i - last_line_break > 0) {
|
||||
std::string snippet = str.substr(last_line_break);
|
||||
if(!snippet.empty())
|
||||
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 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
|
||||
@@ -105,53 +147,36 @@ static void win_draw_string(sf::RenderTarget& dest_window,rectangle dest_rect,st
|
||||
adjust_y -= str_to_draw.getLocalBounds().height;
|
||||
|
||||
str_to_draw.setString(str);
|
||||
str_len = str.length();
|
||||
if(str_len == 0) {
|
||||
return;
|
||||
}
|
||||
short total_width = str_to_draw.getLocalBounds().width;
|
||||
|
||||
eTextMode mode = options.mode;
|
||||
total_width = str_to_draw.getLocalBounds().width;
|
||||
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;
|
||||
|
||||
auto text_len = [&str_to_draw](size_t i) -> int {
|
||||
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(!options.showBreaks){
|
||||
for(int i=0; i < str.length(); ++i){
|
||||
if(str[i] == '|') str[i] = ' ';
|
||||
}
|
||||
}
|
||||
|
||||
if(mode == eTextMode::WRAP) {
|
||||
moveTo = location(dest_rect.left + adjust_x, dest_rect.top + adjust_y);
|
||||
short 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))
|
||||
&& (last_word_break >= last_line_break)) || (str[i] == '|')) {
|
||||
if(str[i] == '|') {
|
||||
if(!options.showBreaks) str[i] = ' ';
|
||||
last_word_break = i + 1;
|
||||
} else if(last_line_break == last_word_break)
|
||||
last_word_break = i;
|
||||
break_info.push_back(std::make_pair(last_line_break, last_word_break));
|
||||
last_line_break = last_word_break;
|
||||
}
|
||||
if(str[i] == ' ')
|
||||
last_word_break = i + 1;
|
||||
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);
|
||||
}
|
||||
|
||||
if(i - last_line_break > 0) {
|
||||
std::string snippet = str.substr(last_line_break);
|
||||
if(!snippet.empty())
|
||||
break_info.push_back(std::make_pair(last_line_break, str.length() + 1));
|
||||
}
|
||||
moveTo = location(dest_rect.left + adjust_x, dest_rect.top + adjust_y);
|
||||
|
||||
for(auto break_info_pair : break_info){
|
||||
push_snippets(break_info_pair.first, break_info_pair.second, options, iHilite, str, moveTo);
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
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) {
|
||||
text_params_t params;
|
||||
params.mode = eTextMode::WRAP;
|
||||
|
@@ -37,6 +37,9 @@ struct TextStyle {
|
||||
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 {
|
||||
std::string text;
|
||||
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<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, 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);
|
||||
|
||||
#endif
|
||||
|
Reference in New Issue
Block a user