Add most of the logic to word wrap list items
This commit is contained in:
parent
f33a9c1a18
commit
bf7354a7d8
@ -11,6 +11,7 @@
|
||||
#include "IGUIFont.h"
|
||||
#include "IGUISpriteBank.h"
|
||||
#include "IGUIScrollBar.h"
|
||||
#include "utils/string_utils.hpp"
|
||||
#include "utils/time.hpp"
|
||||
|
||||
|
||||
@ -555,11 +556,30 @@ void CGUISTKListBox::draw()
|
||||
if ( i==Selected && hl )
|
||||
font_color = EGUI_LBC_TEXT_HIGHLIGHT;
|
||||
|
||||
Font->draw(
|
||||
Items[i].m_contents[x].m_text.c_str(),
|
||||
textRect,
|
||||
hasItemOverrideColor(i, font_color) ? getItemOverrideColor(i, font_color) : getItemDefaultColor(font_color),
|
||||
Items[i].m_contents[x].m_center, true, &clientClip);
|
||||
std::wstring cell_text = Items[i].m_contents[x].m_text.c_str();
|
||||
std::vector<std::wstring> cell_text_lines;
|
||||
if (Items[i].m_word_wrap)
|
||||
{
|
||||
StringUtils::breakText(cell_text, cell_text_lines, 300, Font);
|
||||
}
|
||||
else
|
||||
{
|
||||
cell_text_lines.push_back(cell_text);
|
||||
}
|
||||
|
||||
core::rect<s32> lineRect = textRect;
|
||||
for (unsigned int i=0; i<cell_text_lines.size(); i++)
|
||||
{
|
||||
irr::core::stringw text_line = cell_text_lines[i].c_str();
|
||||
Font->draw(
|
||||
text_line,
|
||||
lineRect,
|
||||
hasItemOverrideColor(i, font_color) ? getItemOverrideColor(i, font_color) : getItemDefaultColor(font_color),
|
||||
Items[i].m_contents[x].m_center, true, &clientClip);
|
||||
|
||||
lineRect.UpperLeftCorner.Y += 30;
|
||||
lineRect.LowerRightCorner.Y += 30;
|
||||
}
|
||||
|
||||
//Position back to inital pos
|
||||
if (IconBank && (Items[i].m_contents[x].m_icon > -1))
|
||||
|
@ -49,6 +49,8 @@ namespace irr
|
||||
std::string m_internal_name;
|
||||
int m_current_id;
|
||||
|
||||
bool m_word_wrap = false;
|
||||
|
||||
// A multicolor extension
|
||||
struct ListItemOverrideColor
|
||||
{
|
||||
|
@ -239,6 +239,7 @@ void ListWidget::addItem( const std::string& internal_name,
|
||||
ListItem newItem;
|
||||
newItem.m_internal_name = internal_name;
|
||||
newItem.m_contents.push_back(cell);
|
||||
newItem.m_word_wrap = (m_properties[PROP_WORD_WRAP] == "true");
|
||||
|
||||
CGUISTKListBox* list = getIrrlichtElement<CGUISTKListBox>();
|
||||
assert(list != NULL);
|
||||
@ -266,6 +267,7 @@ void ListWidget::addItem(const std::string& internal_name,
|
||||
{
|
||||
newItem.m_contents.push_back(contents[i]);
|
||||
}
|
||||
newItem.m_word_wrap = (m_properties[PROP_WORD_WRAP] == "true");
|
||||
|
||||
CGUISTKListBox* list = getIrrlichtElement<CGUISTKListBox>();
|
||||
assert(list != NULL);
|
||||
|
@ -908,6 +908,136 @@ namespace StringUtils
|
||||
return out;
|
||||
}
|
||||
|
||||
// ------------------------------------------------------------------------
|
||||
/** Breaks the text so that each line is smaller than max_width with the current settings.
|
||||
* The result is put into output, a vector of strings, with each line having its own string */
|
||||
// TODO : try to get rid of the complications induced by wchar
|
||||
void breakText(std::wstring& input, std::vector<std::wstring> &output, unsigned int max_width, irr::gui::IGUIFont* font)
|
||||
{
|
||||
output.clear();
|
||||
|
||||
// We need to use a wstring to get wchar_t later
|
||||
std::wstring work_copy = input;
|
||||
|
||||
wchar_t c;
|
||||
unsigned int index = 0;
|
||||
// The index of the last character to include before the linebreak
|
||||
unsigned int break_index = 0;
|
||||
irr::core::dimension2du area;
|
||||
// Algorithm :
|
||||
// 1)If the index exceed the work_copy string size, go to step 7a)
|
||||
// 2)We look at the character at the index
|
||||
// 3)We check if the current character is a linebreak. If yes, go to step 7a)
|
||||
// 4)We check if it is part of a multi-wchar unicode character.
|
||||
// If we are in a multi-wchar unicode character, go to step 6.
|
||||
// We don't check if it's the first or second one, because those characters
|
||||
// are not a suitable break-point anyway. In theory, this doesn't work well
|
||||
// if only such characters are used, but this is a silly theoretical case.
|
||||
// 5a)We check if the length of the string including the new character is < max_width
|
||||
// 5b)If it is smaller, and a suitable character to break, we update the break_index
|
||||
// 5c)If it is bigger, we go to step 7
|
||||
// 6)If no linebreak has been requested, increment the index, and return to step 1)
|
||||
// 7a)If a linebreak has been requested, we push back the substring from 0 to break_index,
|
||||
// and truncate that substring from work_copy. The index is reset to 0.
|
||||
// If break_index is 0, we cut the string at the current index.
|
||||
// 7b)If we have broken the whole input text into lines, we quit the loop.
|
||||
while(true)
|
||||
{
|
||||
// We have reached the end of the string, we just need to push back the current content
|
||||
// Step 1
|
||||
if (index >= work_copy.size());
|
||||
{
|
||||
break_index = index-1;
|
||||
goto push_text; // Avoid complicating things with stupid checks
|
||||
}
|
||||
|
||||
// Step 2
|
||||
c = work_copy[index];
|
||||
|
||||
// Step 3
|
||||
if (c == L'\r' || c == L'\n')
|
||||
{
|
||||
break_index = index;
|
||||
if (c == L'\r' && index+1 < work_copy.size() && work_copy[index+1] == L'\n') // Windows breaks
|
||||
work_copy.erase(index+1);
|
||||
goto push_text;
|
||||
}
|
||||
|
||||
// Step 4
|
||||
if (partOfLongUnicodeChar(c))
|
||||
goto next_loop_no_push;
|
||||
|
||||
// Step 5
|
||||
|
||||
// index+1 because index starts at 0 and substr takes initial pos and length as arguments
|
||||
area = font->getDimension(work_copy.substr(0,index+1).c_str());
|
||||
if (area.Width < max_width)
|
||||
{
|
||||
if (breakable(c))
|
||||
break_index = index;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Not enough room to draw even 1 character, abort
|
||||
if (index==0)
|
||||
{
|
||||
Log::error("StringUtils",
|
||||
"Not enough width to fit a character. Width is %i.", max_width);
|
||||
break;
|
||||
}
|
||||
|
||||
goto push_text;
|
||||
}
|
||||
|
||||
// Step 6
|
||||
next_loop_no_push:
|
||||
index++;
|
||||
continue;
|
||||
|
||||
// Step 7
|
||||
push_text:
|
||||
std::wstring text_line = work_copy.substr(0,break_index);
|
||||
output.push_back(text_line);
|
||||
|
||||
// If the line break was the last char of the input string
|
||||
if (work_copy.size() == break_index+1)
|
||||
{
|
||||
// The text is entirely treated
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
work_copy = work_copy.substr(break_index+1); // All the string except the pushed back part
|
||||
index = 0;
|
||||
}
|
||||
} // While(true) - active until the whole string has been broken and copied
|
||||
} // breakText
|
||||
|
||||
/* This function checks if a char is suitable to break lines.
|
||||
* Currently a copy of the function found at irrlicht/include/utfwrapping.h */
|
||||
bool breakable (wchar_t c)
|
||||
{
|
||||
if ((c > 12287 && c < 40960) || //Common CJK words
|
||||
(c > 44031 && c < 55204) || //Hangul
|
||||
(c > 63743 && c < 64256) || //More Chinese
|
||||
c == 173 || c == L' ' || //Soft hyphen and white space
|
||||
c == 47 || c == 92) //Slash and blackslash
|
||||
return true;
|
||||
return false;
|
||||
} // breakable
|
||||
|
||||
/* This function checks if a char is part of a two wchars unicode symbol */
|
||||
bool partOfLongUnicodeChar (wchar_t c)
|
||||
{
|
||||
#ifdef WIN32
|
||||
if (c >= 0x10000)
|
||||
return true;
|
||||
return false;
|
||||
#else
|
||||
return false; //A wchar_t in linux or max uses 32 bits
|
||||
#endif
|
||||
} // partOfLongUnicodeChar
|
||||
|
||||
} // namespace StringUtils
|
||||
|
||||
|
||||
|
@ -26,6 +26,7 @@
|
||||
#include <vector>
|
||||
#include <sstream>
|
||||
#include <irrString.h>
|
||||
#include <IGUIFont.h>
|
||||
#include "utils/constants.hpp"
|
||||
#include "utils/types.hpp"
|
||||
#include "utils/log.hpp"
|
||||
@ -246,6 +247,11 @@ namespace StringUtils
|
||||
std::string wideToUtf8(const irr::core::stringw& input);
|
||||
std::string findAndReplace(const std::string& source, const std::string& find, const std::string& replace);
|
||||
std::string removeWhitespaces(const std::string& input);
|
||||
void breakText(const std::wstring& input, std::vector<std::wstring> &output,
|
||||
unsigned int max_width, irr::gui::IGUIFont* font);
|
||||
bool breakable (wchar_t c);
|
||||
bool partOfLongUnicodeChar (wchar_t c);
|
||||
|
||||
inline std::string getUserAgentString()
|
||||
{
|
||||
std::string uagent(std::string("SuperTuxKart/") + STK_VERSION);
|
||||
|
Loading…
x
Reference in New Issue
Block a user