Text fields now support multiline editing!

This commit is contained in:
2014-12-01 01:18:53 -05:00
parent 45caa9d7ff
commit 70696dc42f
3 changed files with 60 additions and 40 deletions

View File

@@ -88,42 +88,42 @@ void cTextField::draw(){
frame_rect(*inWindow, outline, sf::Color::Black);
std::string contents = getText();
RECT rect = frame;
rect.inset(2,6);
rect.inset(2,2);
TextStyle style;
style.font = FONT_PLAIN;
style.pointSize = 12;
style.colour = sf::Color::Black;
style.lineHeight = 14;
// TODO: Proper support for multiline fields
int ip_offset, sel_offset;
style.lineHeight = 16;
size_t ip_offset = 0;
if(haveFocus) {
std::string pre_ip = contents.substr(0, insertionPoint);
// TODO: Update string_length to take a std::string
hilite_t hilite = {insertionPoint, selectionPoint};
if(selectionPoint < insertionPoint) std::swap(hilite.first,hilite.second);
std::vector<snippet_t> snippets = draw_string_sel(*inWindow, rect, contents, style, {hilite}, hiliteClr);
int iSnippet = -1, sum = 0;
ip_offset = insertionPoint;
for(size_t i = 0; i < snippets.size(); i++) {
size_t snippet_len = snippets[i].text.length();
sum += snippet_len;
if(sum >= insertionPoint) {
iSnippet = i;
break;
}
ip_offset -= snippet_len;
}
std::string pre_ip = iSnippet >= 0 ? snippets[iSnippet].text.substr(0, ip_offset) : "";
ip_offset = string_length(pre_ip, style);
if(insertionPoint != selectionPoint) {
std::string pre_sel = contents.substr(0, selectionPoint);
sel_offset = string_length(pre_sel, style);
int sel_start = std::min(ip_offset, sel_offset) + 1;
int sel_width = abs(ip_offset - sel_offset) + 3;
RECT selectRect = frame;
selectRect.left += sel_start;
selectRect.right = selectRect.left + sel_width;
fill_rect(*inWindow, selectRect, ipClr);
// TODO: I forget whether this was supposed to be = or -=
selectRect.right - 1;
fill_rect(*inWindow, selectRect, hiliteClr);
} else if(ip_timer.getElapsedTime().asMilliseconds() < 500) {
if(ip_timer.getElapsedTime().asMilliseconds() < 500) {
// printf("Blink on (%d); ", ip_timer.getElapsedTime().asMilliseconds());
RECT ipRect = frame;
ipRect.left += ip_offset + 2;
ipRect.right = ipRect.left + 1;
RECT ipRect = {0, 0, 15, 1};
if(iSnippet >= 0)
ipRect.offset(snippets[iSnippet].at.x + ip_offset, snippets[iSnippet].at.y + 1);
else ipRect.offset(frame.topLeft()), ipRect.offset(3,2);
fill_rect(*inWindow, ipRect, ipClr);
} else if(ip_timer.getElapsedTime().asMilliseconds() > 1000) {
// printf("Blink off (%d); ", ip_timer.getElapsedTime().asMilliseconds());
ip_timer.restart();
}
}
win_draw_string(*inWindow, rect, contents, eTextMode::WRAP, style);
} else win_draw_string(*inWindow, rect, contents, eTextMode::WRAP, style);
}
void cTextField::handleInput(cKey key) {

View File

@@ -196,18 +196,14 @@ void TextStyle::applyTo(sf::Text& text) {
struct text_params_t {
TextStyle style;
eTextMode mode;
bool showBreaks = false;
location offset = {0,0};
// Hilite ranges are, like the STL, of the form [first, last).
std::vector<hilite_t> hilite_ranges;
sf::Color hilite_fg, hilite_bg = sf::Color::Transparent;
enum {RECTS} returnType;
enum {RECTS, SNIPPETS} returnType;
std::vector<RECT> returnRects;
};
struct snippet_t {
std::string text;
location at;
bool hilited;
std::vector<snippet_t> snippets;
};
void win_draw_string(sf::RenderTarget& dest_window,RECT dest_rect,std::string str,text_params_t& options);
@@ -231,14 +227,30 @@ std::vector<RECT> draw_string_hilite(sf::RenderTarget& dest_window,RECT dest_rec
return params.returnRects;
}
void push_snippets(size_t start, size_t end, text_params_t& options, std::vector<snippet_t>& snippets, size_t& iHilite, const std::string& str, location loc) {
std::vector<snippet_t> draw_string_sel(sf::RenderTarget& dest_window,RECT dest_rect,std::string str,TextStyle style,std::vector<hilite_t> hilites,sf::Color hiliteClr) {
text_params_t params;
params.mode = eTextMode::WRAP;
params.hilite_ranges = hilites;
params.style = style;
params.hilite_fg = style.colour;
params.hilite_bg = hiliteClr;
params.returnType = text_params_t::RECTS;
win_draw_string(dest_window, dest_rect, str, params);
return params.snippets;
}
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;
// Check if we have any hilites on this line.
// We assume the list of hilites is sorted, so we just need to
// check the current entry.
size_t upper_bound = end;
do {
bool hilited = false;
// Skip any hilite rules that have start = end
while(iHilite < hilites.size() && hilites[iHilite].first == hilites[iHilite].second)
iHilite++;
if(iHilite < hilites.size()) {
// Possibilities: (vertical bars indicate line boundaries, parentheses for hilite boundaries, dots are data)
// 1. |...|...(...) --> no hilite on this line
@@ -266,6 +278,7 @@ void push_snippets(size_t start, size_t end, text_params_t& options, std::vector
}
void win_draw_string(sf::RenderTarget& dest_window,RECT 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);
@@ -300,7 +313,6 @@ void win_draw_string(sf::RenderTarget& dest_window,RECT dest_rect,std::string st
size_t iHilite = 0;
location moveTo;
std::vector<snippet_t> snippets;
line_height -= 2; // TODO: ...why are we arbitrarily reducing the line height from the requested value?
if(mode == eTextMode::WRAP) {
@@ -309,10 +321,10 @@ void win_draw_string(sf::RenderTarget& dest_window,RECT dest_rect,std::string st
if(((text_len(i) - text_len(last_line_break) > (dest_rect.width() - 6))
&& (last_word_break > last_line_break)) || (str[i] == '|')) {
if(str[i] == '|') {
str[i] = ' ';
if(!options.showBreaks) str[i] = ' ';
last_word_break = i + 1;
}
push_snippets(last_line_break, last_word_break, options, snippets, iHilite, str, moveTo);
push_snippets(last_line_break, last_word_break, options, iHilite, str, moveTo);
moveTo.y += line_height;
last_line_break = last_word_break;
}
@@ -320,10 +332,10 @@ void win_draw_string(sf::RenderTarget& dest_window,RECT dest_rect,std::string st
last_word_break = i + 1;
}
if(i - last_line_break > 1) {
if(i - last_line_break > 0) {
std::string snippet = str.substr(last_line_break);
if(snippet.size() > 2)
push_snippets(last_line_break, str.length() + 1, options, snippets, iHilite, str, moveTo);
if(!snippet.empty())
push_snippets(last_line_break, str.length() + 1, options, iHilite, str, moveTo);
}
} else {
switch(mode) {
@@ -340,10 +352,10 @@ void win_draw_string(sf::RenderTarget& dest_window,RECT dest_rect,std::string st
case eTextMode::WRAP:
break; // Never happens, but put this here to silence warning
}
push_snippets(0, str.length() + 1, options, snippets, iHilite, str, moveTo);
push_snippets(0, str.length() + 1, options, iHilite, str, moveTo);
}
for(auto& snippet : snippets) {
for(auto& snippet : options.snippets) {
str_to_draw.setString(snippet.text);
str_to_draw.setPosition(snippet.at);
if(snippet.hilited) {
@@ -355,6 +367,7 @@ void win_draw_string(sf::RenderTarget& dest_window,RECT dest_rect,std::string st
if(options.returnType == text_params_t::RECTS)
options.returnRects.push_back(bounds);
str_to_draw.setColor(options.hilite_fg);
bounds.inset(0,-4);
fill_rect(dest_window, bounds, options.hilite_bg);
} else str_to_draw.setColor(options.style.colour);
dest_window.draw(str_to_draw);

View File

@@ -78,6 +78,12 @@ struct cCustomGraphics {
size_t count();
};
struct snippet_t {
std::string text;
location at;
bool hilited;
};
enum class eTextMode {
WRAP,
CENTRE,
@@ -92,6 +98,7 @@ void rect_draw_some_item(const sf::Texture& src_gworld,RECT src_rect,RECT targ_r
void rect_draw_some_item(const sf::Texture& src_gworld,RECT src_rect,const sf::Texture& mask_gworld,RECT mask_rect,sf::RenderTarget& targ_gworld,RECT targ_rect);
std::vector<RECT> draw_string_hilite(sf::RenderTarget& dest_window,RECT 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,RECT dest_rect,std::string str,TextStyle style,std::vector<hilite_t> hilites,sf::Color hiliteClr);
void win_draw_string(sf::RenderTarget& dest_window,RECT dest_rect,std::string str,eTextMode mode,TextStyle style, location offset = {0,0});
short string_length(std::string str, TextStyle style);
//OSStatus flip_pict(OSType domain, OSType type, short id, void *ptr, UInt32 size, bool isNative, void *refcon);