I know, I know....
The idea is to make a derived ListboxTextItem Class that does the wrapping, and add that to the Listbox. My question is: how do you accomplish wrapping even within the derived class?
What I've been thinking about, is maybe getlistrenderarea of the listbox, and if so, split the string with a \n at the closes word location to that rect... but how are you supposed to figure that out? Also, I tried a simple attempt of making a string in a listboxtextitem contain a couple \n's, which don't show up in the listbox.... I've read all over the forums about how to make a subclassed version (your own listitem widget), but no ideas about how to make it wrap. if I were to divide the text into 2 listboxitem entries, how would I make that functional in the derived class?
Any ideas are greatly appreciated...
Erebus
Word-Wrap ListboxItem
Moderators: CEGUI MVP, CEGUI Team
Alright, this very likely is the worst possible method and implementation of word-wrapping I have ever made or seen, but since I can't seem to find any other method (using code, Pompei2's idea was a great one, but does quite a bit on the outside of code, in the xml files). Anyway, I made a class to handle word-wrapping with a CEGUI::Listbox, the concept is extremely inefficient, but it works. If someone finds a way to tweak it, or use the idea to make a better version, please let me know. At present, the code gets the list render area of the listbox, and basically makes an instance of ListboxTextItem, appending each character of the message and checking if it is still in range. Nasty hack, but it seems to work.
It handles wrapping by word, (if spaces exist) and if not, splits by the text at the character position. It also takes into account the vertical scroll bar, but be warned, that if there is no vertical scrollbar, CEGUI will throw an UnknownObjectException, so, it's a good idea to keep the scrollbar always visible, or remove that portion of the following code.
The main method strToItemList, returns a vector of CEGUI::ListboxTextItem pointers, basically the code sees if there needs to be a split of the message (if not, it returns a vector with 1 item in it... the entire message). If so, it splits the message into the needed number of listboxtextitems... so a line that just needs one split (that is, just a little too long) will return 2 items in the vector (2 listboxtextitems). One thing I plan to do with this in my own code, is to create an init method, that will get the size of all the keyboard characters, so that it can just compare the already known values, saving a lot of processing time. Hopefully someone has some idea's to make it better, but for now:
lbwraptext.h
lbwraptext.cpp
use case:
It handles wrapping by word, (if spaces exist) and if not, splits by the text at the character position. It also takes into account the vertical scroll bar, but be warned, that if there is no vertical scrollbar, CEGUI will throw an UnknownObjectException, so, it's a good idea to keep the scrollbar always visible, or remove that portion of the following code.
The main method strToItemList, returns a vector of CEGUI::ListboxTextItem pointers, basically the code sees if there needs to be a split of the message (if not, it returns a vector with 1 item in it... the entire message). If so, it splits the message into the needed number of listboxtextitems... so a line that just needs one split (that is, just a little too long) will return 2 items in the vector (2 listboxtextitems). One thing I plan to do with this in my own code, is to create an init method, that will get the size of all the keyboard characters, so that it can just compare the already known values, saving a lot of processing time. Hopefully someone has some idea's to make it better, but for now:
lbwraptext.h
Code: Select all
/* Taken From Anepsosis */
#ifndef LBWrapText_H
#define LBWrapText_H
#include <vector>
#include <CEGUI/CEGUI.h>
using namespace std;
class LBWrapText
{
public:
LBWrapText();
~LBWrapText();
bool isInRange(CEGUI::Listbox *lb, std::string message);
std::vector<CEGUI::ListboxTextItem*> strToItemList(CEGUI::Listbox *lb, std::string message);
private:
};
#endif
lbwraptext.cpp
Code: Select all
/* Taken From Anepsosis */
#include <CEGUI/CEGUI.h>
#include <iostream>
#include <vector>
#include "lbwraptext.h"
using namespace std;
LBWrapText::LBWrapText()
{
}
LBWrapText::~LBWrapText()
{
}
// Method Used Just To Check If The String Is Too Long Or Not
bool LBWrapText::isInRange(CEGUI::Listbox *lb, std::string message)
{
// Get The Size Of The Message In Pixels
CEGUI::ListboxTextItem *chatItem = new CEGUI::ListboxTextItem(message);
CEGUI::Size lbti = chatItem->getPixelSize();
// Get The Widths Of The Listbox And Item In Floats
float lblength = lb->getListRenderArea().getWidth();
float itemlen = lbti.d_width;
// Clean Up Our Mess, And Check If The
// ListboxItem is Too Long
delete chatItem;
if (itemlen < lblength) {
return true;
} else {
return false;
}
}
std::vector<CEGUI::ListboxTextItem*> LBWrapText::strToItemList(CEGUI::Listbox *lb, std::string message)
{
// Clear The Vector, And Get The Number Of Needed Splits
std::vector<CEGUI::ListboxTextItem*> lstItems;
std::vector<std::string> msgparts;
CEGUI::ListboxTextItem *chatItem;
// CAUTION!!! This Line Might Cause An UnknownObjectException
// You Need To Ensure That You Have Vertical ScrollBar Always
// Visible With: setShowVertScrollbar (bool setting)
CEGUI::Window *lbscrollbar = static_cast<CEGUI::Window*>(lb->getVertScrollbar());
CEGUI::UDim sbwidth = lbscrollbar->getWidth();
CEGUI::Size lbti;
// Empty Our Vectors
lstItems.clear();
msgparts.clear();
// Get Some Float Values For The Listbox / Item
float lblength = lb->getListRenderArea().getWidth();
float lbsbwidth = sbwidth.d_offset;
float itemlen = 0;
int charlen = 0;
int ccount = 0;
// Create Listbox Item Or Items
if (this->isInRange(lb, message) == false) {
// Get The Max Length Of Characters Of The Listbox
std::string tmpbuf = "";
for (size_t i=0; i < message.length(); i++) {
tmpbuf += message[i];
chatItem = new CEGUI::ListboxTextItem(tmpbuf);
lbti = chatItem->getPixelSize();
itemlen = lbti.d_width;
// If We've Reached The End Of The Listbox
// (Taking Into Account For The Scrollbar
if (itemlen >= (lblength - lbsbwidth)) {
size_t pos;
pos = i;
// If We Landed On A Space
if (message[pos] == ' ') {
msgparts.push_back(message.substr(0, i));
message.erase(0, i + 1);
} else {
// If Not, Loop Until We Find One,
// Or Our String Runs Out
if (message.find(" ") != std::string::npos) {
while (message[pos] != ' ') {
if (pos >= 0) {
// Finally Found A Previous Space
if (message[pos] == ' ') {
msgparts.push_back(message.substr(0, pos));
message.erase(0, pos + 1);
break;
} else {
pos--;
}
} else {
// No Space Found Behind Us... Cut It Here
msgparts.push_back(message.substr(0, i));
message.erase(0, i + 1);
pos--;
break;
}
}
} else {
// No Space In The String... Cut It By Letter
msgparts.push_back(message.substr(0, i));
message.erase(0, i);
}
}
// Clean Up Used Heap
delete chatItem;
}
}
// Gather The Remaining Chunks Of Message
msgparts.push_back(message);
// Generate The ListboxTextItems
for (size_t i=0; i < msgparts.size(); i++) {
lstItems.push_back(new CEGUI::ListboxTextItem(msgparts[i]));
}
} else {
lstItems.push_back(new CEGUI::ListboxTextItem(message));
}
// Return The Vector
return lstItems;
}
use case:
Code: Select all
std::vector<CEGUI::ListboxTextItem *> chatitemlist;
LBWrapText wraptext;
chatitemlist = wraptext.strToItemList(listBoxptr, "Some Very Looooooooooooong Text String, That Should Ideally Be Too Long To Fit In One Or Two Lines. This Line Just Isn't Long Enough For Testing....");
for (size_t i=0; i < chatitemlist.size(); i++) {
listBoxptr->addItem(chatitemlist[i]);
}
Who is online
Users browsing this forum: No registered users and 11 guests