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 "IGUIFont.h"
|
||||||
#include "IGUISpriteBank.h"
|
#include "IGUISpriteBank.h"
|
||||||
#include "IGUIScrollBar.h"
|
#include "IGUIScrollBar.h"
|
||||||
|
#include "utils/string_utils.hpp"
|
||||||
#include "utils/time.hpp"
|
#include "utils/time.hpp"
|
||||||
|
|
||||||
|
|
||||||
@ -555,11 +556,30 @@ void CGUISTKListBox::draw()
|
|||||||
if ( i==Selected && hl )
|
if ( i==Selected && hl )
|
||||||
font_color = EGUI_LBC_TEXT_HIGHLIGHT;
|
font_color = EGUI_LBC_TEXT_HIGHLIGHT;
|
||||||
|
|
||||||
Font->draw(
|
std::wstring cell_text = Items[i].m_contents[x].m_text.c_str();
|
||||||
Items[i].m_contents[x].m_text.c_str(),
|
std::vector<std::wstring> cell_text_lines;
|
||||||
textRect,
|
if (Items[i].m_word_wrap)
|
||||||
hasItemOverrideColor(i, font_color) ? getItemOverrideColor(i, font_color) : getItemDefaultColor(font_color),
|
{
|
||||||
Items[i].m_contents[x].m_center, true, &clientClip);
|
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
|
//Position back to inital pos
|
||||||
if (IconBank && (Items[i].m_contents[x].m_icon > -1))
|
if (IconBank && (Items[i].m_contents[x].m_icon > -1))
|
||||||
|
@ -49,6 +49,8 @@ namespace irr
|
|||||||
std::string m_internal_name;
|
std::string m_internal_name;
|
||||||
int m_current_id;
|
int m_current_id;
|
||||||
|
|
||||||
|
bool m_word_wrap = false;
|
||||||
|
|
||||||
// A multicolor extension
|
// A multicolor extension
|
||||||
struct ListItemOverrideColor
|
struct ListItemOverrideColor
|
||||||
{
|
{
|
||||||
|
@ -239,6 +239,7 @@ void ListWidget::addItem( const std::string& internal_name,
|
|||||||
ListItem newItem;
|
ListItem newItem;
|
||||||
newItem.m_internal_name = internal_name;
|
newItem.m_internal_name = internal_name;
|
||||||
newItem.m_contents.push_back(cell);
|
newItem.m_contents.push_back(cell);
|
||||||
|
newItem.m_word_wrap = (m_properties[PROP_WORD_WRAP] == "true");
|
||||||
|
|
||||||
CGUISTKListBox* list = getIrrlichtElement<CGUISTKListBox>();
|
CGUISTKListBox* list = getIrrlichtElement<CGUISTKListBox>();
|
||||||
assert(list != NULL);
|
assert(list != NULL);
|
||||||
@ -266,6 +267,7 @@ void ListWidget::addItem(const std::string& internal_name,
|
|||||||
{
|
{
|
||||||
newItem.m_contents.push_back(contents[i]);
|
newItem.m_contents.push_back(contents[i]);
|
||||||
}
|
}
|
||||||
|
newItem.m_word_wrap = (m_properties[PROP_WORD_WRAP] == "true");
|
||||||
|
|
||||||
CGUISTKListBox* list = getIrrlichtElement<CGUISTKListBox>();
|
CGUISTKListBox* list = getIrrlichtElement<CGUISTKListBox>();
|
||||||
assert(list != NULL);
|
assert(list != NULL);
|
||||||
|
@ -908,6 +908,136 @@ namespace StringUtils
|
|||||||
return out;
|
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
|
} // namespace StringUtils
|
||||||
|
|
||||||
|
|
||||||
|
@ -26,6 +26,7 @@
|
|||||||
#include <vector>
|
#include <vector>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include <irrString.h>
|
#include <irrString.h>
|
||||||
|
#include <IGUIFont.h>
|
||||||
#include "utils/constants.hpp"
|
#include "utils/constants.hpp"
|
||||||
#include "utils/types.hpp"
|
#include "utils/types.hpp"
|
||||||
#include "utils/log.hpp"
|
#include "utils/log.hpp"
|
||||||
@ -246,6 +247,11 @@ namespace StringUtils
|
|||||||
std::string wideToUtf8(const irr::core::stringw& input);
|
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 findAndReplace(const std::string& source, const std::string& find, const std::string& replace);
|
||||||
std::string removeWhitespaces(const std::string& input);
|
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()
|
inline std::string getUserAgentString()
|
||||||
{
|
{
|
||||||
std::string uagent(std::string("SuperTuxKart/") + STK_VERSION);
|
std::string uagent(std::string("SuperTuxKart/") + STK_VERSION);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user