1
// Copyright (C) 2002-2011 Nikolaus Gebhardt
2
// This file is part of the "Irrlicht Engine".
3
// For conditions of distribution and use, see copyright notice in irrlicht.h
5
// 07.10.2005 - Multicolor-Listbox added by A. Buschhueter (Acki)
6
// A_Buschhueter@gmx.de
9
#ifdef _IRR_COMPILE_WITH_GUI_
12
#include "IGUIEnvironment.h"
13
#include "IVideoDriver.h"
15
#include "CGUIScrollBar.h"
26
CGUITable::CGUITable(IGUIEnvironment* environment, IGUIElement* parent,
27
s32 id, const core::rect<s32>& rectangle, bool clip,
28
bool drawBack, bool moveOverSelect)
29
: IGUITable(environment, parent, id, rectangle), Font(0),
30
VerticalScrollBar(0), HorizontalScrollBar(0),
31
Clip(clip), DrawBack(drawBack), MoveOverSelect(moveOverSelect),
32
Selecting(false), CurrentResizedColumn(-1), ResizeStart(0), ResizableColumns(true),
33
ItemHeight(0), TotalItemHeight(0), TotalItemWidth(0), Selected(-1),
34
CellHeightPadding(2), CellWidthPadding(5), ActiveTab(-1),
35
CurrentOrdering(EGOM_NONE), DrawFlags(EGTDF_ROWS | EGTDF_COLUMNS | EGTDF_ACTIVE_ROW )
38
setDebugName("CGUITable");
41
VerticalScrollBar = Environment->addScrollBar(false, core::rect<s32>(0, 0, 100, 100), this, -1);
42
if (VerticalScrollBar)
44
VerticalScrollBar->grab();
45
VerticalScrollBar->setNotClipped(false);
46
VerticalScrollBar->setSubElement(true);
49
HorizontalScrollBar = Environment->addScrollBar(true, core::rect<s32>(0, 0, 100, 100), this, -1);
50
if ( HorizontalScrollBar )
52
HorizontalScrollBar->grab();
53
HorizontalScrollBar->setNotClipped(false);
54
HorizontalScrollBar->setSubElement(true);
62
CGUITable::~CGUITable()
64
if (VerticalScrollBar)
65
VerticalScrollBar->drop();
66
if ( HorizontalScrollBar )
67
HorizontalScrollBar->drop();
74
void CGUITable::addColumn(const wchar_t* caption, s32 columnIndex)
77
tabHeader.Name = caption;
78
tabHeader.Width = Font->getDimension(caption).Width + (CellWidthPadding * 2) + ARROW_PAD;
79
tabHeader.OrderingMode = EGCO_NONE;
81
if ( columnIndex < 0 || columnIndex >= (s32)Columns.size() )
83
Columns.push_back(tabHeader);
84
for ( u32 i=0; i < Rows.size(); ++i )
87
Rows[i].Items.push_back(cell);
92
Columns.insert(tabHeader, columnIndex);
93
for ( u32 i=0; i < Rows.size(); ++i )
96
Rows[i].Items.insert(cell, columnIndex);
107
//! remove a column from the table
108
void CGUITable::removeColumn(u32 columnIndex)
110
if ( columnIndex < Columns.size() )
112
Columns.erase(columnIndex);
113
for ( u32 i=0; i < Rows.size(); ++i )
115
Rows[i].Items.erase(columnIndex);
118
if ( (s32)columnIndex <= ActiveTab )
119
ActiveTab = Columns.size() ? 0 : -1;
125
s32 CGUITable::getColumnCount() const
127
return Columns.size();
131
s32 CGUITable::getRowCount() const
137
bool CGUITable::setActiveColumn(s32 idx, bool doOrder )
139
if (idx < 0 || idx >= (s32)Columns.size())
142
bool changed = (ActiveTab != idx);
150
switch ( Columns[idx].OrderingMode )
153
CurrentOrdering = EGOM_NONE;
157
CurrentOrdering = EGOM_NONE;
161
event.EventType = EET_GUI_EVENT;
162
event.GUIEvent.Caller = this;
163
event.GUIEvent.Element = 0;
164
event.GUIEvent.EventType = EGET_TABLE_HEADER_CHANGED;
165
Parent->OnEvent(event);
171
CurrentOrdering = EGOM_ASCENDING;
174
case EGCO_DESCENDING:
175
CurrentOrdering = EGOM_DESCENDING;
178
case EGCO_FLIP_ASCENDING_DESCENDING:
179
CurrentOrdering = EGOM_ASCENDING == CurrentOrdering ? EGOM_DESCENDING : EGOM_ASCENDING;
182
CurrentOrdering = EGOM_NONE;
185
orderRows(getActiveColumn(), CurrentOrdering);
191
event.EventType = EET_GUI_EVENT;
192
event.GUIEvent.Caller = this;
193
event.GUIEvent.Element = 0;
194
event.GUIEvent.EventType = EGET_TABLE_HEADER_CHANGED;
195
Parent->OnEvent(event);
202
s32 CGUITable::getActiveColumn() const
208
EGUI_ORDERING_MODE CGUITable::getActiveColumnOrdering() const
210
return CurrentOrdering;
214
void CGUITable::setColumnWidth(u32 columnIndex, u32 width)
216
if ( columnIndex < Columns.size() )
218
const u32 MIN_WIDTH = Font->getDimension(Columns[columnIndex].Name.c_str() ).Width + (CellWidthPadding * 2);
219
if ( width < MIN_WIDTH )
222
Columns[columnIndex].Width = width;
224
for ( u32 i=0; i < Rows.size(); ++i )
226
breakText( Rows[i].Items[columnIndex].Text, Rows[i].Items[columnIndex].BrokenText, Columns[columnIndex].Width );
232
//! Get the width of a column
233
u32 CGUITable::getColumnWidth(u32 columnIndex) const
235
if ( columnIndex >= Columns.size() )
238
return Columns[columnIndex].Width;
241
void CGUITable::setResizableColumns(bool resizable)
243
ResizableColumns = resizable;
247
bool CGUITable::hasResizableColumns() const
249
return ResizableColumns;
253
u32 CGUITable::addRow(u32 rowIndex)
255
if ( rowIndex > Rows.size() )
257
rowIndex = Rows.size();
262
if ( rowIndex == Rows.size() )
265
Rows.insert(row, rowIndex);
267
Rows[rowIndex].Items.reallocate(Columns.size());
268
for ( u32 i = 0 ; i < Columns.size() ; ++i )
270
Rows[rowIndex].Items.push_back(Cell());
273
recalculateHeights();
278
void CGUITable::removeRow(u32 rowIndex)
280
if ( rowIndex > Rows.size() )
283
Rows.erase( rowIndex );
285
if ( !(Selected < s32(Rows.size())) )
286
Selected = Rows.size() - 1;
288
recalculateHeights();
292
//! adds an list item, returns id of item
293
void CGUITable::setCellText(u32 rowIndex, u32 columnIndex, const core::stringw& text)
295
if ( rowIndex < Rows.size() && columnIndex < Columns.size() )
297
Rows[rowIndex].Items[columnIndex].Text = text;
298
breakText( Rows[rowIndex].Items[columnIndex].Text, Rows[rowIndex].Items[columnIndex].BrokenText, Columns[columnIndex].Width );
300
IGUISkin* skin = Environment->getSkin();
302
Rows[rowIndex].Items[columnIndex].Color = skin->getColor(EGDC_BUTTON_TEXT);
306
void CGUITable::setCellText(u32 rowIndex, u32 columnIndex, const core::stringw& text, video::SColor color)
308
if ( rowIndex < Rows.size() && columnIndex < Columns.size() )
310
Rows[rowIndex].Items[columnIndex].Text = text;
311
breakText( Rows[rowIndex].Items[columnIndex].Text, Rows[rowIndex].Items[columnIndex].BrokenText, Columns[columnIndex].Width );
312
Rows[rowIndex].Items[columnIndex].Color = color;
313
Rows[rowIndex].Items[columnIndex].IsOverrideColor = true;
318
void CGUITable::setCellColor(u32 rowIndex, u32 columnIndex, video::SColor color)
320
if ( rowIndex < Rows.size() && columnIndex < Columns.size() )
322
Rows[rowIndex].Items[columnIndex].Color = color;
323
Rows[rowIndex].Items[columnIndex].IsOverrideColor = true;
328
void CGUITable::setCellData(u32 rowIndex, u32 columnIndex, void *data)
330
if ( rowIndex < Rows.size() && columnIndex < Columns.size() )
332
Rows[rowIndex].Items[columnIndex].Data = data;
337
const wchar_t* CGUITable::getCellText(u32 rowIndex, u32 columnIndex ) const
339
if ( rowIndex < Rows.size() && columnIndex < Columns.size() )
341
return Rows[rowIndex].Items[columnIndex].Text.c_str();
348
void* CGUITable::getCellData(u32 rowIndex, u32 columnIndex ) const
350
if ( rowIndex < Rows.size() && columnIndex < Columns.size() )
352
return Rows[rowIndex].Items[columnIndex].Data;
360
void CGUITable::clear()
366
if (VerticalScrollBar)
367
VerticalScrollBar->setPos(0);
368
if ( HorizontalScrollBar )
369
HorizontalScrollBar->setPos(0);
371
recalculateHeights();
376
void CGUITable::clearRows()
381
if (VerticalScrollBar)
382
VerticalScrollBar->setPos(0);
384
recalculateHeights();
390
s32 CGUITable::getSelected() const
395
//! set wich row is currently selected
396
void CGUITable::setSelected( s32 index )
399
if ( index >= 0 && index < (s32) Rows.size() )
404
void CGUITable::recalculateWidths()
407
for ( u32 i=0; i < Columns.size(); ++i )
409
TotalItemWidth += Columns[i].Width;
415
void CGUITable::recalculateHeights()
418
IGUISkin* skin = Environment->getSkin();
419
if (Font != skin->getFont())
424
Font = skin->getFont();
430
ItemHeight = Font->getDimension(L"A").Height + (CellHeightPadding * 2);
434
TotalItemHeight = ItemHeight * Rows.size(); // header is not counted, because we only want items
439
// automatic enabled/disabling and resizing of scrollbars
440
void CGUITable::checkScrollbars()
442
IGUISkin* skin = Environment->getSkin();
443
if ( !HorizontalScrollBar || !VerticalScrollBar || !skin)
446
s32 scrollBarSize = skin->getSize(EGDS_SCROLLBAR_SIZE);
447
bool wasHorizontalScrollBarVisible = HorizontalScrollBar->isVisible();
448
bool wasVerticalScrollBarVisible = VerticalScrollBar->isVisible();
449
HorizontalScrollBar->setVisible(false);
450
VerticalScrollBar->setVisible(false);
452
// CAREFUL: near identical calculations for tableRect and clientClip are also done in draw
453
// area of table used for drawing without scrollbars
454
core::rect<s32> tableRect(AbsoluteRect);
455
tableRect.UpperLeftCorner.X += 1;
456
tableRect.UpperLeftCorner.Y += 1;
457
s32 headerBottom = tableRect.UpperLeftCorner.Y + ItemHeight;
459
// area of for the items (without header and without scrollbars)
460
core::rect<s32> clientClip(tableRect);
461
clientClip.UpperLeftCorner.Y = headerBottom + 1;
463
// needs horizontal scroll be visible?
464
if( TotalItemWidth > clientClip.getWidth() )
466
clientClip.LowerRightCorner.Y -= scrollBarSize;
467
HorizontalScrollBar->setVisible(true);
468
HorizontalScrollBar->setMax(core::max_(0,TotalItemWidth - clientClip.getWidth()));
471
// needs vertical scroll be visible?
472
if( TotalItemHeight > clientClip.getHeight() )
474
clientClip.LowerRightCorner.X -= scrollBarSize;
475
VerticalScrollBar->setVisible(true);
476
VerticalScrollBar->setMax(core::max_(0,TotalItemHeight - clientClip.getHeight()));
478
// check horizontal again because we have now smaller clientClip
479
if ( !HorizontalScrollBar->isVisible() )
481
if( TotalItemWidth > clientClip.getWidth() )
483
clientClip.LowerRightCorner.Y -= scrollBarSize;
484
HorizontalScrollBar->setVisible(true);
485
HorizontalScrollBar->setMax(core::max_(0,TotalItemWidth - clientClip.getWidth()));
490
// find the correct size for the vertical scrollbar
491
if ( VerticalScrollBar->isVisible() )
493
if (!wasVerticalScrollBarVisible )
494
VerticalScrollBar->setPos(0);
496
if ( HorizontalScrollBar->isVisible() )
498
VerticalScrollBar->setRelativePosition(
499
core::rect<s32>(RelativeRect.getWidth() - scrollBarSize, 1,
500
RelativeRect.getWidth()-1, RelativeRect.getHeight()-(1+scrollBarSize) ) );
504
VerticalScrollBar->setRelativePosition(
505
core::rect<s32>(RelativeRect.getWidth() - scrollBarSize, 1,
506
RelativeRect.getWidth()-1, RelativeRect.getHeight()-1) );
510
// find the correct size for the horizontal scrollbar
511
if ( HorizontalScrollBar->isVisible() )
513
if ( !wasHorizontalScrollBarVisible )
514
HorizontalScrollBar->setPos(0);
516
if ( VerticalScrollBar->isVisible() )
518
HorizontalScrollBar->setRelativePosition( core::rect<s32>(1, RelativeRect.getHeight() - scrollBarSize, RelativeRect.getWidth()-(1+scrollBarSize), RelativeRect.getHeight()-1) );
522
HorizontalScrollBar->setRelativePosition( core::rect<s32>(1, RelativeRect.getHeight() - scrollBarSize, RelativeRect.getWidth()-1, RelativeRect.getHeight()-1) );
528
void CGUITable::refreshControls()
530
updateAbsolutePosition();
532
if ( VerticalScrollBar )
533
VerticalScrollBar->setVisible(false);
535
if ( HorizontalScrollBar )
536
HorizontalScrollBar->setVisible(false);
538
recalculateHeights();
543
//! called if an event happened.
544
bool CGUITable::OnEvent(const SEvent &event)
549
switch(event.EventType)
552
switch(event.GUIEvent.EventType)
554
case gui::EGET_SCROLL_BAR_CHANGED:
555
if (event.GUIEvent.Caller == VerticalScrollBar)
557
// current position will get read out in draw
560
if (event.GUIEvent.Caller == HorizontalScrollBar)
562
// current position will get read out in draw
566
case gui::EGET_ELEMENT_FOCUS_LOST:
568
CurrentResizedColumn = -1;
576
case EET_MOUSE_INPUT_EVENT:
581
core::position2d<s32> p(event.MouseInput.X, event.MouseInput.Y);
583
switch(event.MouseInput.Event)
585
case EMIE_MOUSE_WHEEL:
586
VerticalScrollBar->setPos(VerticalScrollBar->getPos() + (event.MouseInput.Wheel < 0 ? -1 : 1)*-10);
589
case EMIE_LMOUSE_PRESSED_DOWN:
591
if (Environment->hasFocus(this) &&
592
VerticalScrollBar->isVisible() &&
593
VerticalScrollBar->getAbsolutePosition().isPointInside(p) &&
594
VerticalScrollBar->OnEvent(event))
597
if (Environment->hasFocus(this) &&
598
HorizontalScrollBar->isVisible() &&
599
HorizontalScrollBar->getAbsolutePosition().isPointInside(p) &&
600
HorizontalScrollBar->OnEvent(event))
603
if ( dragColumnStart( event.MouseInput.X, event.MouseInput.Y ) )
605
Environment->setFocus(this);
609
if ( selectColumnHeader( event.MouseInput.X, event.MouseInput.Y ) )
613
Environment->setFocus(this);
616
case EMIE_LMOUSE_LEFT_UP:
618
CurrentResizedColumn = -1;
620
if (!getAbsolutePosition().isPointInside(p))
622
Environment->removeFocus(this);
625
if (Environment->hasFocus(this) &&
626
VerticalScrollBar->isVisible() &&
627
VerticalScrollBar->getAbsolutePosition().isPointInside(p) &&
628
VerticalScrollBar->OnEvent(event))
633
if (Environment->hasFocus(this) &&
634
HorizontalScrollBar->isVisible() &&
635
HorizontalScrollBar->getAbsolutePosition().isPointInside(p) &&
636
HorizontalScrollBar->OnEvent(event))
641
selectNew(event.MouseInput.Y);
644
case EMIE_MOUSE_MOVED:
645
if ( CurrentResizedColumn >= 0 )
647
if ( dragColumnUpdate(event.MouseInput.X) )
652
if (Selecting || MoveOverSelect)
654
if (getAbsolutePosition().isPointInside(p))
656
selectNew(event.MouseInput.Y);
671
return IGUIElement::OnEvent(event);
675
void CGUITable::setColumnOrdering(u32 columnIndex, EGUI_COLUMN_ORDERING mode)
677
if ( columnIndex < Columns.size() )
678
Columns[columnIndex].OrderingMode = mode;
682
void CGUITable::swapRows(u32 rowIndexA, u32 rowIndexB)
684
if ( rowIndexA >= Rows.size() )
687
if ( rowIndexB >= Rows.size() )
690
Row swap = Rows[rowIndexA];
691
Rows[rowIndexA] = Rows[rowIndexB];
692
Rows[rowIndexB] = swap;
694
if ( Selected == s32(rowIndexA) )
695
Selected = rowIndexB;
696
else if( Selected == s32(rowIndexB) )
697
Selected = rowIndexA;
702
bool CGUITable::dragColumnStart(s32 xpos, s32 ypos)
704
if ( !ResizableColumns )
707
if ( ypos > ( AbsoluteRect.UpperLeftCorner.Y + ItemHeight ) )
710
const s32 CLICK_AREA = 12; // to left and right of line which can be dragged
711
s32 pos = AbsoluteRect.UpperLeftCorner.X+1;
713
if ( HorizontalScrollBar && HorizontalScrollBar->isVisible() )
714
pos -= HorizontalScrollBar->getPos();
716
pos += TotalItemWidth;
718
// have to search from the right as otherwise lines could no longer be resized when a column width is 0
719
for ( s32 i = (s32)Columns.size()-1; i >= 0 ; --i )
721
u32 colWidth = Columns[i].Width;
723
if ( xpos >= (pos - CLICK_AREA) && xpos < ( pos + CLICK_AREA ) )
725
CurrentResizedColumn = i;
737
bool CGUITable::dragColumnUpdate(s32 xpos)
739
if ( !ResizableColumns || CurrentResizedColumn < 0 || CurrentResizedColumn >= s32(Columns.size()) )
741
CurrentResizedColumn = -1;
745
s32 width = s32(Columns[CurrentResizedColumn].Width) + (xpos-ResizeStart);
748
setColumnWidth(CurrentResizedColumn, u32(width));
755
bool CGUITable::selectColumnHeader(s32 xpos, s32 ypos)
757
if ( ypos > ( AbsoluteRect.UpperLeftCorner.Y + ItemHeight ) )
760
s32 pos = AbsoluteRect.UpperLeftCorner.X+1;
762
if ( HorizontalScrollBar && HorizontalScrollBar->isVisible() )
763
pos -= HorizontalScrollBar->getPos();
765
for ( u32 i = 0 ; i < Columns.size() ; ++i )
767
u32 colWidth = Columns[i].Width;
769
if ( xpos >= pos && xpos < ( pos + s32(colWidth) ) )
771
setActiveColumn( i, true );
783
void CGUITable::orderRows(s32 columnIndex, EGUI_ORDERING_MODE mode)
787
if ( columnIndex == -1 )
788
columnIndex = getActiveColumn();
789
if ( columnIndex < 0 )
792
if ( mode == EGOM_ASCENDING )
794
for ( s32 i = 0 ; i < s32(Rows.size()) - 1 ; ++i )
796
for ( s32 j = 0 ; j < s32(Rows.size()) - i - 1 ; ++j )
798
if ( Rows[j+1].Items[columnIndex].Text < Rows[j].Items[columnIndex].Text )
806
else if( Selected == j+1 )
812
else if ( mode == EGOM_DESCENDING )
814
for ( s32 i = 0 ; i < s32(Rows.size()) - 1 ; ++i )
816
for ( s32 j = 0 ; j < s32(Rows.size()) - i - 1 ; ++j )
818
if ( Rows[j].Items[columnIndex].Text < Rows[j+1].Items[columnIndex].Text)
826
else if( Selected == j+1 )
835
void CGUITable::selectNew(s32 ypos, bool onlyHover)
837
IGUISkin* skin = Environment->getSkin();
841
s32 oldSelected = Selected;
843
if ( ypos < ( AbsoluteRect.UpperLeftCorner.Y + ItemHeight ) )
846
// find new selected item.
848
Selected = ((ypos - AbsoluteRect.UpperLeftCorner.Y - ItemHeight - 1) + VerticalScrollBar->getPos()) / ItemHeight;
850
if (Selected >= (s32)Rows.size())
851
Selected = Rows.size() - 1;
856
if (Parent && !onlyHover)
859
event.EventType = EET_GUI_EVENT;
860
event.GUIEvent.Caller = this;
861
event.GUIEvent.Element = 0;
862
event.GUIEvent.EventType = (Selected != oldSelected) ? EGET_TABLE_CHANGED : EGET_TABLE_SELECTED_AGAIN;
863
Parent->OnEvent(event);
868
//! draws the element and its children
869
void CGUITable::draw()
874
irr::video::IVideoDriver* driver = Environment->getVideoDriver();
876
IGUISkin* skin = Environment->getSkin();
880
IGUIFont* font = skin->getFont();
884
// CAREFUL: near identical calculations for tableRect and clientClip are also done in checkScrollbars and selectColumnHeader
885
// Area of table used for drawing without scrollbars
886
core::rect<s32> tableRect(AbsoluteRect);
887
tableRect.UpperLeftCorner.X += 1;
888
tableRect.UpperLeftCorner.Y += 1;
889
if ( VerticalScrollBar && VerticalScrollBar->isVisible() )
890
tableRect.LowerRightCorner.X -= skin->getSize(EGDS_SCROLLBAR_SIZE);
891
if ( HorizontalScrollBar && HorizontalScrollBar->isVisible() )
892
tableRect.LowerRightCorner.Y -= skin->getSize(EGDS_SCROLLBAR_SIZE);
894
s32 headerBottom = tableRect.UpperLeftCorner.Y + ItemHeight;
896
// area of for the items (without header and without scrollbars)
897
core::rect<s32> clientClip(tableRect);
898
clientClip.UpperLeftCorner.Y = headerBottom + 1;
899
clientClip.clipAgainst(AbsoluteClippingRect);
901
// draw background for whole element
902
skin->draw3DSunkenPane(this, skin->getColor(EGDC_3D_HIGH_LIGHT), true, DrawBack, AbsoluteRect, &AbsoluteClippingRect);
904
// scrolledTableClient is the area where the table items would be if it could be drawn completely
905
core::rect<s32> scrolledTableClient(tableRect);
906
scrolledTableClient.UpperLeftCorner.Y = headerBottom + 1;
907
scrolledTableClient.LowerRightCorner.Y = scrolledTableClient.UpperLeftCorner.Y + TotalItemHeight;
908
scrolledTableClient.LowerRightCorner.X = scrolledTableClient.UpperLeftCorner.X + TotalItemWidth;
909
if ( VerticalScrollBar && VerticalScrollBar->isVisible() )
911
scrolledTableClient.UpperLeftCorner.Y -= VerticalScrollBar->getPos();
912
scrolledTableClient.LowerRightCorner.Y -= VerticalScrollBar->getPos();
914
if ( HorizontalScrollBar && HorizontalScrollBar->isVisible() )
916
scrolledTableClient.UpperLeftCorner.X -= HorizontalScrollBar->getPos();
917
scrolledTableClient.LowerRightCorner.X -= HorizontalScrollBar->getPos();
920
// rowRect is around the scrolled row
921
core::rect<s32> rowRect(scrolledTableClient);
922
rowRect.LowerRightCorner.Y = rowRect.UpperLeftCorner.Y + ItemHeight;
925
for ( u32 i = 0 ; i < Rows.size() ; ++i )
927
if (rowRect.LowerRightCorner.Y >= AbsoluteRect.UpperLeftCorner.Y &&
928
rowRect.UpperLeftCorner.Y <= AbsoluteRect.LowerRightCorner.Y)
930
// draw row seperator
931
if ( DrawFlags & EGTDF_ROWS )
933
core::rect<s32> lineRect(rowRect);
934
lineRect.UpperLeftCorner.Y = lineRect.LowerRightCorner.Y - 1;
935
driver->draw2DRectangle(skin->getColor(EGDC_3D_SHADOW), lineRect, &clientClip);
938
core::rect<s32> textRect(rowRect);
939
pos = rowRect.UpperLeftCorner.X;
941
// draw selected row background highlighted
942
if ((s32)i == Selected && DrawFlags & EGTDF_ACTIVE_ROW )
943
driver->draw2DRectangle(skin->getColor(EGDC_HIGH_LIGHT), rowRect, &clientClip);
945
for ( u32 j = 0 ; j < Columns.size() ; ++j )
947
textRect.UpperLeftCorner.X = pos + CellWidthPadding;
948
textRect.LowerRightCorner.X = pos + Columns[j].Width - CellWidthPadding;
951
if ((s32)i == Selected)
953
font->draw(Rows[i].Items[j].BrokenText.c_str(), textRect, skin->getColor(isEnabled() ? EGDC_HIGH_LIGHT_TEXT : EGDC_GRAY_TEXT), false, true, &clientClip);
957
if ( !Rows[i].Items[j].IsOverrideColor ) // skin-colors can change
958
Rows[i].Items[j].Color = skin->getColor(EGDC_BUTTON_TEXT);
959
font->draw(Rows[i].Items[j].BrokenText.c_str(), textRect, isEnabled() ? Rows[i].Items[j].Color : skin->getColor(EGDC_GRAY_TEXT), false, true, &clientClip);
962
pos += Columns[j].Width;
966
rowRect.UpperLeftCorner.Y += ItemHeight;
967
rowRect.LowerRightCorner.Y += ItemHeight;
970
core::rect<s32> columnSeparator(clientClip);
971
pos = scrolledTableClient.UpperLeftCorner.X;
973
core::rect<s32> tableClip(tableRect);
974
tableClip.clipAgainst(AbsoluteClippingRect);
976
for (u32 i = 0 ; i < Columns.size() ; ++i )
978
const wchar_t* text = Columns[i].Name.c_str();
979
u32 colWidth = Columns[i].Width;
981
//core::dimension2d<s32 > dim = font->getDimension(text);
983
core::rect<s32> columnrect(pos, tableRect.UpperLeftCorner.Y, pos + colWidth, headerBottom);
985
// draw column background
986
skin->draw3DButtonPaneStandard(this, columnrect, &tableClip);
988
// draw column seperator
989
if ( DrawFlags & EGTDF_COLUMNS )
991
columnSeparator.UpperLeftCorner.X = pos;
992
columnSeparator.LowerRightCorner.X = pos + 1;
993
driver->draw2DRectangle(skin->getColor(EGDC_3D_SHADOW), columnSeparator, &tableClip);
996
// draw header column text
997
columnrect.UpperLeftCorner.X += CellWidthPadding;
998
font->draw(text, columnrect, skin->getColor( isEnabled() ? EGDC_BUTTON_TEXT : EGDC_GRAY_TEXT), false, true, &tableClip);
1000
// draw icon for active column tab
1001
if ( (s32)i == ActiveTab )
1003
if ( CurrentOrdering == EGOM_ASCENDING )
1005
columnrect.UpperLeftCorner.X = columnrect.LowerRightCorner.X - CellWidthPadding - ARROW_PAD / 2 + 2;
1006
columnrect.UpperLeftCorner.Y += 7;
1007
skin->drawIcon(this,EGDI_CURSOR_UP,columnrect.UpperLeftCorner,0,0,false,&tableClip);
1011
columnrect.UpperLeftCorner.X = columnrect.LowerRightCorner.X - CellWidthPadding - ARROW_PAD / 2 + 2;
1012
columnrect.UpperLeftCorner.Y += 7;
1013
skin->drawIcon(this,EGDI_CURSOR_DOWN,columnrect.UpperLeftCorner,0,0,false,&tableClip);
1020
// fill up header background up to the right side
1021
core::rect<s32> columnrect(pos, tableRect.UpperLeftCorner.Y, tableRect.LowerRightCorner.X , headerBottom);
1022
skin->draw3DButtonPaneStandard(this, columnrect, &tableClip);
1024
IGUIElement::draw();
1028
void CGUITable::breakText(const core::stringw& text, core::stringw& brokenText, u32 cellWidth)
1030
IGUISkin* skin = Environment->getSkin();
1038
IGUIFont* font = skin->getFont();
1042
core::stringw line, lineDots;
1046
const u32 maxLength = cellWidth - (CellWidthPadding * 2);
1047
const u32 maxLengthDots = cellWidth - (CellWidthPadding * 2) - font->getDimension(L"...").Width;
1048
const u32 size = text.size();
1053
for (i=0; i<size; ++i)
1060
pos += font->getDimension(c).Width;
1061
if ( pos > maxLength )
1064
if ( font->getDimension( (line + c).c_str() ).Width > maxLengthDots )
1071
brokenText = lineDots + L"...";
1077
//! Set some flags influencing the layout of the table
1078
void CGUITable::setDrawFlags(s32 flags)
1084
//! Get the flags which influence the layout of the table
1085
s32 CGUITable::getDrawFlags() const
1091
//! Writes attributes of the element.
1092
void CGUITable::serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options) const
1094
IGUITable::serializeAttributes(out, options);
1096
out->addInt("ColumnCount", Columns.size());
1098
for (i=0;i<Columns.size(); ++i)
1100
core::stringc label;
1102
label = "Column"; label += i; label += "name";
1103
out->addString(label.c_str(), Columns[i].Name.c_str() );
1104
label = "Column"; label += i; label += "width";
1105
out->addInt(label.c_str(), Columns[i].Width );
1106
label = "Column"; label += i; label += "OrderingMode";
1107
out->addEnum(label.c_str(), Columns[i].OrderingMode, GUIColumnOrderingNames);
1110
out->addInt("RowCount", Rows.size());
1111
for (i=0;i<Rows.size(); ++i)
1113
core::stringc label;
1115
// Height currently not used and could be recalculated anyway
1116
//label = "Row"; label += i; label += "height";
1117
//out->addInt(label.c_str(), Rows[i].Height );
1119
//label = "Row"; label += i; label += "ItemCount";
1120
//out->addInt(label.c_str(), Rows[i].Items.size());
1122
for ( c=0; c < Rows[i].Items.size(); ++c )
1124
label = "Row"; label += i; label += "cell"; label += c; label += "text";
1125
out->addString(label.c_str(), Rows[i].Items[c].Text.c_str() );
1126
// core::stringw BrokenText; // can be recalculated
1127
label = "Row"; label += i; label += "cell"; label += c; label += "color";
1128
out->addColor(label.c_str(), Rows[i].Items[c].Color );
1129
label = "Row"; label += i; label += "cell"; label += c; label += "IsOverrideColor";
1130
out->addColor(label.c_str(), Rows[i].Items[c].IsOverrideColor );
1131
// void *data; // can't be serialized
1135
// s32 ItemHeight; // can be calculated
1136
// TotalItemHeight // calculated
1137
// TotalItemWidth // calculated
1138
// gui::IGUIFont* Font; // font is just the current font from environment
1139
// gui::IGUIScrollBar* VerticalScrollBar; // not serialized
1140
// gui::IGUIScrollBar* HorizontalScrollBar; // not serialized
1142
out->addBool ("Clip", Clip);
1143
out->addBool ("DrawBack", DrawBack);
1144
out->addBool ("MoveOverSelect", MoveOverSelect);
1146
// s32 CurrentResizedColumn; // runtime info - depends on user action
1147
out->addBool ("ResizableColumns", ResizableColumns);
1149
// s32 Selected; // runtime info - depends on user action
1150
out->addInt("CellWidthPadding", CellWidthPadding );
1151
out->addInt("CellHeightPadding", CellHeightPadding );
1152
// s32 ActiveTab; // runtime info - depends on user action
1153
// bool Selecting; // runtime info - depends on user action
1154
out->addEnum("CurrentOrdering", CurrentOrdering, GUIOrderingModeNames);
1155
out->addInt("DrawFlags", DrawFlags);
1159
//! Reads attributes of the element
1160
void CGUITable::deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options)
1162
IGUITable::deserializeAttributes(in, options);
1165
u32 columnCount = in->getAttributeAsInt("ColumnCount");
1167
for (i=0;i<columnCount; ++i)
1169
core::stringc label;
1172
label = "Column"; label += i; label += "name";
1173
column.Name = core::stringw(in->getAttributeAsString(label.c_str()).c_str());
1174
label = "Column"; label += i; label += "width";
1175
column.Width = in->getAttributeAsInt(label.c_str());
1176
label = "Column"; label += i; label += "OrderingMode";
1178
column.OrderingMode = EGCO_NONE;
1179
s32 co = in->getAttributeAsEnumeration(label.c_str(), GUIColumnOrderingNames);
1181
column.OrderingMode = EGUI_COLUMN_ORDERING(co);
1183
Columns.push_back(column);
1187
u32 rowCount = in->getAttributeAsInt("RowCount");
1188
for (i=0; i<rowCount; ++i)
1190
core::stringc label;
1194
// Height currently not used and could be recalculated anyway
1195
//label = "Row"; label += i; label += "height";
1196
//row.Height = in->getAttributeAsInt(label.c_str() );
1198
Rows.push_back(row);
1200
//label = "Row"; label += i; label += "ItemCount";
1201
//u32 itemCount = in->getAttributeAsInt(label.c_str());
1203
for ( c=0; c < columnCount; ++c )
1207
label = "Row"; label += i; label += "cell"; label += c; label += "text";
1208
cell.Text = core::stringw(in->getAttributeAsString(label.c_str()).c_str());
1209
breakText( cell.Text, cell.BrokenText, Columns[c].Width );
1210
label = "Row"; label += i; label += "cell"; label += c; label += "color";
1211
cell.Color = in->getAttributeAsColor(label.c_str());
1212
label = "Row"; label += i; label += "cell"; label += c; label += "IsOverrideColor";
1213
cell.IsOverrideColor = in->getAttributeAsBool(label.c_str());
1217
Rows[Rows.size()-1].Items.push_back(cell);
1221
ItemHeight = 0; // calculated
1222
TotalItemHeight = 0; // calculated
1223
TotalItemWidth = 0; // calculated
1225
// force font recalculation
1232
Clip = in->getAttributeAsBool("Clip");
1233
DrawBack = in->getAttributeAsBool("DrawBack");
1234
MoveOverSelect = in->getAttributeAsBool("MoveOverSelect");
1236
CurrentResizedColumn = -1;
1238
ResizableColumns = in->getAttributeAsBool("ResizableColumns");
1241
CellWidthPadding = in->getAttributeAsInt("CellWidthPadding");
1242
CellHeightPadding = in->getAttributeAsInt("CellHeightPadding");
1246
CurrentOrdering = (EGUI_ORDERING_MODE) in->getAttributeAsEnumeration("CurrentOrdering", GUIOrderingModeNames);
1247
DrawFlags = in->getAttributeAsInt("DrawFlags");
1252
} // end namespace gui
1253
} // end namespace irr