PseudoListbox
This code emulates a multi-column listbox where each row is composed of different widgets. Please post comments or questions on the message board thread for the Pseudo-Listbox
Introduction
The .layout arranges three widgets in a row; a StaticText, an Editbox, and a Combobox. This "row" is then copied to result in 5 "rows". These are not real Listbox rows but they will appear to be. Next to these rows is a scrollbar, to navigate through the rows.
Just like a real Listbox the pseudo-listbox displays a subset of the data; there could be 10 data items to display but only 5 rows on the screen. This means that the scrollbar will be used to navigate through the data.
The Scrollbar is configured within two functions. The first is initRowCount() where the .layout is analyzed to figure out the number of rows contained within the pseudo-listbox. The page size is specified as the number of rows such that if rows 0 to 4 are displayed scrolling to the next page would display rows 5 to 9, 10 to 14, etc.
The line size is is specified as 1, to ensure that when the scrollbar is moved it does so by a whole unit, a whole row.
The number of rows could have been defined (hard-coded) in code. However the benefits of the current approach is that a GUI designer could change the appearance of the pseudo-listbox (size and position of the widgets) or change the number of rows and the program would still function (as long as the contents of each row remains the same).
The second Scrollbar configuration is within the initData() function, when the number of data item changes. The document size is specified as the number (count) of data items. This will let the Scrollbar properly move the contents by a line or by a page.
Files
PseudoListbox.h
<cpp/>
- ifndef _PseudoListbox_h_
- define _PseudoListbox_h_
- include "CEGuiSample.h"
- include "CEGUI.h"
- include "CEGUIXMLAttributes.h"
- include "CEGUIDefaultResourceProvider.h"
class DemoSample : public CEGuiSample { public:
bool initialiseSample()
{ using namespace CEGUI; try { // Retrieve the window manager WindowManager& winMgr = WindowManager::getSingleton();
// Load the TaharezLook scheme and set up the default mouse cursor and font SchemeManager::getSingleton().loadScheme("TaharezLook.scheme"); System::getSingleton().setDefaultMouseCursor("TaharezLook", "MouseArrow"); if(!FontManager::getSingleton().isFontPresent("Commonwealth-10")) FontManager::getSingleton().createFont("Commonwealth-10.font");
// Load a layout and set the GUI Sheet Window* guiLayout = winMgr.loadWindowLayout("PseudoListbox.layout"); Window* sheet = winMgr.getWindow("Root"); System::getSingleton().setGUISheet(sheet); sheet->addChildWindow(guiLayout);
// Initialize the scrollbar events Scrollbar* scrollbar = static_cast<Scrollbar*>(winMgr.getWindow("Root/PseudoList/Scrollbar")); scrollbar->subscribeEvent(Scrollbar::EventScrollPositionChanged, Event::Subscriber(&DemoSample::Event_ScrollChange, this));
// Initialize the apply event PushButton* apply = static_cast<PushButton*>(winMgr.getWindow("Root/Config/Apply")); apply->subscribeEvent(PushButton::EventClicked, Event::Subscriber(&DemoSample::Event_DataCountChange, this));
// Figure out how many rows have been defined within the .layout // based on the specified prefix. initRowCount("Root/PseudoList/LabelRow");
// Initialize the data based on the value provided by the .layout // This code simulates a click on the apply button, which will then query // the value specified of the Editbox within the .layout CEGUI::EventArgs args; apply->fireEvent(PushButton::EventClicked, args); } catch(Exception &e) { #if defined( __WIN32__ ) || defined( _WIN32 ) MessageBox(NULL, e.getMessage().c_str(), "Error initializing the demo", MB_OK | MB_ICONERROR | MB_TASKMODAL); #else std::cerr << "Error initializing the demo:" << e.getMessage().c_str() << "\n"; #endif }
return true; }
void cleanupSample(void) { }
void initRowCount(const CEGUI::String& pPrefix) { // This function should only be called once, to initialize the // rows that compose our pseudo-list. using namespace CEGUI; WindowManager& winMgr = WindowManager::getSingleton();
mRowCount = 0; while(winMgr.isWindowPresent(pPrefix + CEGUI::PropertyHelper::intToString(mRowCount))) { mRowCount++; }
// Configure the scrollbar Scrollbar* scrollbar = static_cast<Scrollbar*>(winMgr.getWindow("Root/PseudoList/Scrollbar")); scrollbar->setPageSize(static_cast<float>(mRowCount)); // Scroll the entire set of rows scrollbar->setStepSize(1.0f); // Scroll one row at a time }
void initData(const int& pDataCount) { // This function should be called everytime the number of data changes using namespace CEGUI; WindowManager& winMgr = WindowManager::getSingleton(); DataRow row; CEGUI::String rowId; mListData.clear(); for(int data = 0; data < pDataCount; data++) { rowId = CEGUI::PropertyHelper::intToString(data); row.label = "Label #" + rowId; row.text = "Text #" + rowId; row.choice = "Choice #" + rowId; mListData.push_back(row); }
// Configure the scrollbar Scrollbar* scrollbar = static_cast<Scrollbar*>(winMgr.getWindow("Root/PseudoList/Scrollbar")); scrollbar->setDocumentSize(static_cast<float>(mListData.size())); // Specify the total number of rows }
void showData(const int& pOffset) { // This function updates the contents of the displayed rows. // The "trick" is that the scrollbar offset determines the // first data being displayed. using namespace CEGUI; DefaultWindow* label; Editbox* text; Combobox* choice; String rowId; WindowManager& winMgr = WindowManager::getSingleton();
DataRow row; for(int rowIndex = 0; rowIndex < mRowCount; rowIndex++) { if(rowIndex < static_cast<int>(mListData.size())) { // Display the offsetted data row = mListData[rowIndex + pOffset]; } else { // There is less data than can be displayed // Could disable or hide some of the row widgets and hide the scrollbar. row.label = ""; row.text = ""; row.choice = ""; } rowId = CEGUI::PropertyHelper::intToString(rowIndex); label = static_cast<DefaultWindow*>(winMgr.getWindow("Root/PseudoList/LabelRow" + rowId)); label->setText(row.label);
text = static_cast<Editbox*>(winMgr.getWindow("Root/PseudoList/TextRow" + rowId)); text->setText(row.text);
choice = static_cast<Combobox*>(winMgr.getWindow("Root/PseudoList/ChoiceRow" + rowId)); choice->setText(row.text); } }
bool Event_ScrollChange(const CEGUI::EventArgs& args) { using namespace CEGUI;
WindowManager& winMgr = WindowManager::getSingleton(); Scrollbar* scrollbar = static_cast<Scrollbar*>(winMgr.getWindow("Root/PseudoList/Scrollbar")); int scrollOffset = static_cast<int>(scrollbar->getScrollPosition()); showData(scrollOffset); return true; }
bool Event_DataCountChange(const CEGUI::EventArgs& args) { using namespace CEGUI;
WindowManager& winMgr = WindowManager::getSingleton(); Editbox* dataRows = static_cast<Editbox*>(winMgr.getWindow("Root/Config/DataRows")); int dataCount = PropertyHelper::stringToInt(dataRows->getText()); initData(dataCount);
Scrollbar* scrollbar = static_cast<Scrollbar*>(winMgr.getWindow("Root/PseudoList/Scrollbar")); EventArgs scrollArgs; scrollbar->fireEvent(Scrollbar::EventScrollPositionChanged, scrollArgs);
return true; }
private: // The number of rows defined within the .layout int mRowCount;
struct DataRow { CEGUI::String label; CEGUI::String text; CEGUI::String choice; };
typedef std::vector<DataRow> DataList; DataList mListData; };
- endif // _PseudoListbox_h_
PseudoListbox.layout
<?xml version="1.0" encoding="UTF-8"?> <GUILayout > <Window Type="DefaultWindow" Name="Root" > <Property Name="InheritsAlpha" Value="False" /> <Property Name="UnifiedMaxSize" Value="{{1,0},{1,0}}" /> <Property Name="UnifiedAreaRect" Value="{{0,0},{0,0},{1,0},{1,0}}" /> <Window Type="DefaultWindow" Name="Root/PseudoList" > <Property Name="UnifiedMaxSize" Value="{{1,0},{1,0}}" /> <Property Name="UnifiedAreaRect" Value="{{0.01,0},{0.01,0},{0.5,0},{0.391667,0}}" /> <Window Type="TaharezLook/VerticalScrollbar" Name="Root/PseudoList/Scrollbar" > <Property Name="PageSize" Value="0" /> <Property Name="StepSize" Value="1" /> <Property Name="OverlapSize" Value="0" /> <Property Name="DocumentSize" Value="1" /> <Property Name="ScrollPosition" Value="0" /> <Property Name="UnifiedMaxSize" Value="{{1,0},{1,0}}" /> <Property Name="UnifiedAreaRect" Value="{{0.95,0},{0.01,0},{0.99,0},{0.99,0}}" /> </Window> <Window Type="TaharezLook/StaticText" Name="Root/PseudoList/LabelRow0" > <Property Name="UnifiedMaxSize" Value="{{1,0},{1,0}}" /> <Property Name="UnifiedAreaRect" Value="{{0.01,0},{0.01,0},{0.25,0},{0.2,0}}" /> </Window> <Window Type="TaharezLook/Editbox" Name="Root/PseudoList/TextRow0" > <Property Name="MaxTextLength" Value="1073741823" /> <Property Name="UnifiedMaxSize" Value="{{1,0},{1,0}}" /> <Property Name="UnifiedAreaRect" Value="{{0.26,0},{0.01,0},{0.5,0},{0.2,0}}" /> </Window> <Window Type="TaharezLook/Combobox" Name="Root/PseudoList/ChoiceRow0" > <Property Name="UnifiedMaxSize" Value="{{1,0},{1,0}}" /> <Property Name="UnifiedAreaRect" Value="{{0.51,0},{0.01,0},{0.9,0},{0.2,0}}" /> <Property Name="MaxEditTextLength" Value="1073741823" /> </Window> <Window Type="TaharezLook/StaticText" Name="Root/PseudoList/LabelRow1" > <Property Name="Font" Value="Commonwealth-10" /> <Property Name="UnifiedMaxSize" Value="{{1,0},{1,0}}" /> <Property Name="UnifiedAreaRect" Value="{{0.01,0},{0.21,0},{0.25,0},{0.4,0}}" /> </Window> <Window Type="TaharezLook/Editbox" Name="Root/PseudoList/TextRow1" > <Property Name="Font" Value="Commonwealth-10" /> <Property Name="MaxTextLength" Value="1073741823" /> <Property Name="UnifiedMaxSize" Value="{{1,0},{1,0}}" /> <Property Name="UnifiedAreaRect" Value="{{0.26,0},{0.21,0},{0.5,0},{0.4,0}}" /> </Window> <Window Type="TaharezLook/Combobox" Name="Root/PseudoList/ChoiceRow1" > <Property Name="Font" Value="Commonwealth-10" /> <Property Name="UnifiedMaxSize" Value="{{1,0},{1,0}}" /> <Property Name="UnifiedAreaRect" Value="{{0.51,0},{0.21,0},{0.9,0},{0.4,0}}" /> <Property Name="MaxEditTextLength" Value="1073741823" /> </Window> <Window Type="TaharezLook/StaticText" Name="Root/PseudoList/LabelRow2" > <Property Name="Font" Value="Commonwealth-10" /> <Property Name="UnifiedMaxSize" Value="{{1,0},{1,0}}" /> <Property Name="UnifiedAreaRect" Value="{{0.01,0},{0.41,0},{0.25,0},{0.6,0}}" /> </Window> <Window Type="TaharezLook/Editbox" Name="Root/PseudoList/TextRow2" > <Property Name="Font" Value="Commonwealth-10" /> <Property Name="MaxTextLength" Value="1073741823" /> <Property Name="UnifiedMaxSize" Value="{{1,0},{1,0}}" /> <Property Name="UnifiedAreaRect" Value="{{0.26,0},{0.41,0},{0.5,0},{0.6,0}}" /> </Window> <Window Type="TaharezLook/Combobox" Name="Root/PseudoList/ChoiceRow2" > <Property Name="Font" Value="Commonwealth-10" /> <Property Name="UnifiedMaxSize" Value="{{1,0},{1,0}}" /> <Property Name="UnifiedAreaRect" Value="{{0.51,0},{0.41,0},{0.9,0},{0.6,0}}" /> <Property Name="MaxEditTextLength" Value="1073741823" /> </Window> <Window Type="TaharezLook/StaticText" Name="Root/PseudoList/LabelRow3" > <Property Name="Font" Value="Commonwealth-10" /> <Property Name="UnifiedMaxSize" Value="{{1,0},{1,0}}" /> <Property Name="UnifiedAreaRect" Value="{{0.01,0},{0.61,0},{0.25,0},{0.8,0}}" /> </Window> <Window Type="TaharezLook/Editbox" Name="Root/PseudoList/TextRow3" > <Property Name="Font" Value="Commonwealth-10" /> <Property Name="MaxTextLength" Value="1073741823" /> <Property Name="UnifiedMaxSize" Value="{{1,0},{1,0}}" /> <Property Name="UnifiedAreaRect" Value="{{0.26,0},{0.61,0},{0.5,0},{0.8,0}}" /> </Window> <Window Type="TaharezLook/Combobox" Name="Root/PseudoList/ChoiceRow3" > <Property Name="Font" Value="Commonwealth-10" /> <Property Name="UnifiedMaxSize" Value="{{1,0},{1,0}}" /> <Property Name="UnifiedAreaRect" Value="{{0.51,0},{0.61,0},{0.9,0},{0.8,0}}" /> <Property Name="MaxEditTextLength" Value="1073741823" /> </Window> <Window Type="TaharezLook/StaticText" Name="Root/PseudoList/LabelRow4" > <Property Name="Font" Value="Commonwealth-10" /> <Property Name="UnifiedMaxSize" Value="{{1,0},{1,0}}" /> <Property Name="UnifiedAreaRect" Value="{{0.01,0},{0.81,0},{0.25,0},{0.99,0}}" /> </Window> <Window Type="TaharezLook/Editbox" Name="Root/PseudoList/TextRow4" > <Property Name="Font" Value="Commonwealth-10" /> <Property Name="MaxTextLength" Value="1073741823" /> <Property Name="UnifiedMaxSize" Value="{{1,0},{1,0}}" /> <Property Name="UnifiedAreaRect" Value="{{0.26,0},{0.81,0},{0.5,0},{1,0}}" /> </Window> <Window Type="TaharezLook/Combobox" Name="Root/PseudoList/ChoiceRow4" > <Property Name="Font" Value="Commonwealth-10" /> <Property Name="UnifiedMaxSize" Value="{{1,0},{1,0}}" /> <Property Name="UnifiedAreaRect" Value="{{0.51,0},{0.81,0},{0.9,0},{1,0}}" /> <Property Name="MaxEditTextLength" Value="1073741823" /> </Window> </Window> <Window Type="TaharezLook/FrameWindow" Name="Root/Config" > <Property Name="Text" Value="Configuration" /> <Property Name="TitlebarFont" Value="Commonwealth-10" /> <Property Name="UnifiedMaxSize" Value="{{1,0},{1,0}}" /> <Property Name="TitlebarEnabled" Value="True" /> <Property Name="UnifiedAreaRect" Value="{{0.6,0},{0.01,0},{0.9,0},{0.3,0}}" /> <Window Type="TaharezLook/StaticText" Name="Root/Config/Label" > <Property Name="Text" Value="Data rows:" /> <Property Name="HorzFormatting" Value="RightAligned" /> <Property Name="UnifiedMaxSize" Value="{{1,0},{1,0}}" /> <Property Name="UnifiedAreaRect" Value="{{0.03,0},{0.3,0},{0.4,0},{0.5,0}}" /> </Window> <Window Type="TaharezLook/Editbox" Name="Root/Config/DataRows" > <Property Name="Text" Value="10" /> <Property Name="MaxTextLength" Value="1073741823" /> <Property Name="UnifiedMaxSize" Value="{{1,0},{1,0}}" /> <Property Name="UnifiedAreaRect" Value="{{0.4,0},{0.3,0},{0.95,0},{0.5,0}}" /> </Window> <Window Type="TaharezLook/Button" Name="Root/Config/Apply" > <Property Name="Text" Value="Apply" /> <Property Name="UnifiedMaxSize" Value="{{1,0},{1,0}}" /> <Property Name="UnifiedAreaRect" Value="{{0.6,0},{0.7,0},{0.95,0},{0.9,0}}" /> </Window> </Window> </Window> </GUILayout>
main.cpp
<cpp/>
- if defined( __WIN32__ ) || defined( _WIN32 )
#define WIN32_LEAN_AND_MEAN #define NOMINMAX #include "windows.h"
- endif
- include "PseudoListbox.h"
- if defined( __WIN32__ ) || defined( _WIN32 )
int APIENTRY WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine,int nCmdShow)
- else
int main(int argc, char *argv[])
- endif
{
DemoSample app; return app.run();
}