aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/src/others/irrlicht-1.8.1/source/Irrlicht/CGUITable.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/others/irrlicht-1.8.1/source/Irrlicht/CGUITable.cpp')
-rw-r--r--src/others/irrlicht-1.8.1/source/Irrlicht/CGUITable.cpp1256
1 files changed, 1256 insertions, 0 deletions
diff --git a/src/others/irrlicht-1.8.1/source/Irrlicht/CGUITable.cpp b/src/others/irrlicht-1.8.1/source/Irrlicht/CGUITable.cpp
new file mode 100644
index 0000000..a045aac
--- /dev/null
+++ b/src/others/irrlicht-1.8.1/source/Irrlicht/CGUITable.cpp
@@ -0,0 +1,1256 @@
1// Copyright (C) 2002-2012 Nikolaus Gebhardt
2// This file is part of the "Irrlicht Engine".
3// For conditions of distribution and use, see copyright notice in irrlicht.h
4
5// 07.10.2005 - Multicolor-Listbox added by A. Buschhueter (Acki)
6// A_Buschhueter@gmx.de
7
8#include "CGUITable.h"
9#ifdef _IRR_COMPILE_WITH_GUI_
10
11#include "IGUISkin.h"
12#include "IGUIEnvironment.h"
13#include "IVideoDriver.h"
14#include "IGUIFont.h"
15#include "CGUIScrollBar.h"
16#include "os.h"
17
18#define ARROW_PAD 15
19
20namespace irr
21{
22namespace gui
23{
24
25//! constructor
26CGUITable::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 )
36{
37 #ifdef _DEBUG
38 setDebugName("CGUITable");
39 #endif
40
41 VerticalScrollBar = Environment->addScrollBar(false, core::rect<s32>(0, 0, 100, 100), this, -1);
42 if (VerticalScrollBar)
43 {
44 VerticalScrollBar->grab();
45 VerticalScrollBar->setNotClipped(false);
46 VerticalScrollBar->setSubElement(true);
47 }
48
49 HorizontalScrollBar = Environment->addScrollBar(true, core::rect<s32>(0, 0, 100, 100), this, -1);
50 if ( HorizontalScrollBar )
51 {
52 HorizontalScrollBar->grab();
53 HorizontalScrollBar->setNotClipped(false);
54 HorizontalScrollBar->setSubElement(true);
55 }
56
57 refreshControls();
58}
59
60
61//! destructor
62CGUITable::~CGUITable()
63{
64 if (VerticalScrollBar)
65 VerticalScrollBar->drop();
66 if ( HorizontalScrollBar )
67 HorizontalScrollBar->drop();
68
69 if (Font)
70 Font->drop();
71}
72
73
74void CGUITable::addColumn(const wchar_t* caption, s32 columnIndex)
75{
76 Column tabHeader;
77 tabHeader.Name = caption;
78 tabHeader.Width = Font->getDimension(caption).Width + (CellWidthPadding * 2) + ARROW_PAD;
79 tabHeader.OrderingMode = EGCO_NONE;
80
81 if ( columnIndex < 0 || columnIndex >= (s32)Columns.size() )
82 {
83 Columns.push_back(tabHeader);
84 for ( u32 i=0; i < Rows.size(); ++i )
85 {
86 Cell cell;
87 Rows[i].Items.push_back(cell);
88 }
89 }
90 else
91 {
92 Columns.insert(tabHeader, columnIndex);
93 for ( u32 i=0; i < Rows.size(); ++i )
94 {
95 Cell cell;
96 Rows[i].Items.insert(cell, columnIndex);
97 }
98 }
99
100 if (ActiveTab == -1)
101 ActiveTab = 0;
102
103 recalculateWidths();
104}
105
106
107//! remove a column from the table
108void CGUITable::removeColumn(u32 columnIndex)
109{
110 if ( columnIndex < Columns.size() )
111 {
112 Columns.erase(columnIndex);
113 for ( u32 i=0; i < Rows.size(); ++i )
114 {
115 Rows[i].Items.erase(columnIndex);
116 }
117 }
118 if ( (s32)columnIndex <= ActiveTab )
119 ActiveTab = Columns.size() ? 0 : -1;
120
121 recalculateWidths();
122}
123
124
125s32 CGUITable::getColumnCount() const
126{
127 return Columns.size();
128}
129
130
131s32 CGUITable::getRowCount() const
132{
133 return Rows.size();
134}
135
136
137bool CGUITable::setActiveColumn(s32 idx, bool doOrder )
138{
139 if (idx < 0 || idx >= (s32)Columns.size())
140 return false;
141
142 bool changed = (ActiveTab != idx);
143
144 ActiveTab = idx;
145 if ( ActiveTab < 0 )
146 return false;
147
148 if ( doOrder )
149 {
150 switch ( Columns[idx].OrderingMode )
151 {
152 case EGCO_NONE:
153 CurrentOrdering = EGOM_NONE;
154 break;
155
156 case EGCO_CUSTOM:
157 CurrentOrdering = EGOM_NONE;
158 if (Parent)
159 {
160 SEvent event;
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);
166 }
167
168 break;
169
170 case EGCO_ASCENDING:
171 CurrentOrdering = EGOM_ASCENDING;
172 break;
173
174 case EGCO_DESCENDING:
175 CurrentOrdering = EGOM_DESCENDING;
176 break;
177
178 case EGCO_FLIP_ASCENDING_DESCENDING:
179 CurrentOrdering = EGOM_ASCENDING == CurrentOrdering ? EGOM_DESCENDING : EGOM_ASCENDING;
180 break;
181 default:
182 CurrentOrdering = EGOM_NONE;
183 }
184
185 orderRows(getActiveColumn(), CurrentOrdering);
186 }
187
188 if (changed)
189 {
190 SEvent event;
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);
196 }
197
198 return true;
199}
200
201
202s32 CGUITable::getActiveColumn() const
203{
204 return ActiveTab;
205}
206
207
208EGUI_ORDERING_MODE CGUITable::getActiveColumnOrdering() const
209{
210 return CurrentOrdering;
211}
212
213
214void CGUITable::setColumnWidth(u32 columnIndex, u32 width)
215{
216 if ( columnIndex < Columns.size() )
217 {
218 const u32 MIN_WIDTH = Font->getDimension(Columns[columnIndex].Name.c_str() ).Width + (CellWidthPadding * 2);
219 if ( width < MIN_WIDTH )
220 width = MIN_WIDTH;
221
222 Columns[columnIndex].Width = width;
223
224 for ( u32 i=0; i < Rows.size(); ++i )
225 {
226 breakText( Rows[i].Items[columnIndex].Text, Rows[i].Items[columnIndex].BrokenText, Columns[columnIndex].Width );
227 }
228 }
229 recalculateWidths();
230}
231
232//! Get the width of a column
233u32 CGUITable::getColumnWidth(u32 columnIndex) const
234{
235 if ( columnIndex >= Columns.size() )
236 return 0;
237
238 return Columns[columnIndex].Width;
239}
240
241void CGUITable::setResizableColumns(bool resizable)
242{
243 ResizableColumns = resizable;
244}
245
246
247bool CGUITable::hasResizableColumns() const
248{
249 return ResizableColumns;
250}
251
252
253u32 CGUITable::addRow(u32 rowIndex)
254{
255 if ( rowIndex > Rows.size() )
256 {
257 rowIndex = Rows.size();
258 }
259
260 Row row;
261
262 if ( rowIndex == Rows.size() )
263 Rows.push_back(row);
264 else
265 Rows.insert(row, rowIndex);
266
267 Rows[rowIndex].Items.reallocate(Columns.size());
268 for ( u32 i = 0 ; i < Columns.size() ; ++i )
269 {
270 Rows[rowIndex].Items.push_back(Cell());
271 }
272
273 recalculateHeights();
274 return rowIndex;
275}
276
277
278void CGUITable::removeRow(u32 rowIndex)
279{
280 if ( rowIndex > Rows.size() )
281 return;
282
283 Rows.erase( rowIndex );
284
285 if ( !(Selected < s32(Rows.size())) )
286 Selected = Rows.size() - 1;
287
288 recalculateHeights();
289}
290
291
292//! adds an list item, returns id of item
293void CGUITable::setCellText(u32 rowIndex, u32 columnIndex, const core::stringw& text)
294{
295 if ( rowIndex < Rows.size() && columnIndex < Columns.size() )
296 {
297 Rows[rowIndex].Items[columnIndex].Text = text;
298 breakText( Rows[rowIndex].Items[columnIndex].Text, Rows[rowIndex].Items[columnIndex].BrokenText, Columns[columnIndex].Width );
299
300 IGUISkin* skin = Environment->getSkin();
301 if ( skin )
302 Rows[rowIndex].Items[columnIndex].Color = skin->getColor(EGDC_BUTTON_TEXT);
303 }
304}
305
306void CGUITable::setCellText(u32 rowIndex, u32 columnIndex, const core::stringw& text, video::SColor color)
307{
308 if ( rowIndex < Rows.size() && columnIndex < Columns.size() )
309 {
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;
314 }
315}
316
317
318void CGUITable::setCellColor(u32 rowIndex, u32 columnIndex, video::SColor color)
319{
320 if ( rowIndex < Rows.size() && columnIndex < Columns.size() )
321 {
322 Rows[rowIndex].Items[columnIndex].Color = color;
323 Rows[rowIndex].Items[columnIndex].IsOverrideColor = true;
324 }
325}
326
327
328void CGUITable::setCellData(u32 rowIndex, u32 columnIndex, void *data)
329{
330 if ( rowIndex < Rows.size() && columnIndex < Columns.size() )
331 {
332 Rows[rowIndex].Items[columnIndex].Data = data;
333 }
334}
335
336
337const wchar_t* CGUITable::getCellText(u32 rowIndex, u32 columnIndex ) const
338{
339 if ( rowIndex < Rows.size() && columnIndex < Columns.size() )
340 {
341 return Rows[rowIndex].Items[columnIndex].Text.c_str();
342 }
343
344 return 0;
345}
346
347
348void* CGUITable::getCellData(u32 rowIndex, u32 columnIndex ) const
349{
350 if ( rowIndex < Rows.size() && columnIndex < Columns.size() )
351 {
352 return Rows[rowIndex].Items[columnIndex].Data;
353 }
354
355 return 0;
356}
357
358
359//! clears the list
360void CGUITable::clear()
361{
362 Selected = -1;
363 Rows.clear();
364 Columns.clear();
365
366 if (VerticalScrollBar)
367 VerticalScrollBar->setPos(0);
368 if ( HorizontalScrollBar )
369 HorizontalScrollBar->setPos(0);
370
371 recalculateHeights();
372 recalculateWidths();
373}
374
375
376void CGUITable::clearRows()
377{
378 Selected = -1;
379 Rows.clear();
380
381 if (VerticalScrollBar)
382 VerticalScrollBar->setPos(0);
383
384 recalculateHeights();
385}
386
387
388/*!
389*/
390s32 CGUITable::getSelected() const
391{
392 return Selected;
393}
394
395//! set wich row is currently selected
396void CGUITable::setSelected( s32 index )
397{
398 Selected = -1;
399 if ( index >= 0 && index < (s32) Rows.size() )
400 Selected = index;
401}
402
403
404void CGUITable::recalculateWidths()
405{
406 TotalItemWidth=0;
407 for ( u32 i=0; i < Columns.size(); ++i )
408 {
409 TotalItemWidth += Columns[i].Width;
410 }
411 checkScrollbars();
412}
413
414
415void CGUITable::recalculateHeights()
416{
417 TotalItemHeight = 0;
418 IGUISkin* skin = Environment->getSkin();
419 if (Font != skin->getFont())
420 {
421 if (Font)
422 Font->drop();
423
424 Font = skin->getFont();
425
426 ItemHeight = 0;
427
428 if(Font)
429 {
430 ItemHeight = Font->getDimension(L"A").Height + (CellHeightPadding * 2);
431 Font->grab();
432 }
433 }
434 TotalItemHeight = ItemHeight * Rows.size(); // header is not counted, because we only want items
435 checkScrollbars();
436}
437
438
439// automatic enabled/disabling and resizing of scrollbars
440void CGUITable::checkScrollbars()
441{
442 IGUISkin* skin = Environment->getSkin();
443 if ( !HorizontalScrollBar || !VerticalScrollBar || !skin)
444 return;
445
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);
451
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;
458
459 // area of for the items (without header and without scrollbars)
460 core::rect<s32> clientClip(tableRect);
461 clientClip.UpperLeftCorner.Y = headerBottom + 1;
462
463 // needs horizontal scroll be visible?
464 if( TotalItemWidth > clientClip.getWidth() )
465 {
466 clientClip.LowerRightCorner.Y -= scrollBarSize;
467 HorizontalScrollBar->setVisible(true);
468 HorizontalScrollBar->setMax(core::max_(0,TotalItemWidth - clientClip.getWidth()));
469 }
470
471 // needs vertical scroll be visible?
472 if( TotalItemHeight > clientClip.getHeight() )
473 {
474 clientClip.LowerRightCorner.X -= scrollBarSize;
475 VerticalScrollBar->setVisible(true);
476 VerticalScrollBar->setMax(core::max_(0,TotalItemHeight - clientClip.getHeight()));
477
478 // check horizontal again because we have now smaller clientClip
479 if ( !HorizontalScrollBar->isVisible() )
480 {
481 if( TotalItemWidth > clientClip.getWidth() )
482 {
483 clientClip.LowerRightCorner.Y -= scrollBarSize;
484 HorizontalScrollBar->setVisible(true);
485 HorizontalScrollBar->setMax(core::max_(0,TotalItemWidth - clientClip.getWidth()));
486 }
487 }
488 }
489
490 // find the correct size for the vertical scrollbar
491 if ( VerticalScrollBar->isVisible() )
492 {
493 if (!wasVerticalScrollBarVisible )
494 VerticalScrollBar->setPos(0);
495
496 if ( HorizontalScrollBar->isVisible() )
497 {
498 VerticalScrollBar->setRelativePosition(
499 core::rect<s32>(RelativeRect.getWidth() - scrollBarSize, 1,
500 RelativeRect.getWidth()-1, RelativeRect.getHeight()-(1+scrollBarSize) ) );
501 }
502 else
503 {
504 VerticalScrollBar->setRelativePosition(
505 core::rect<s32>(RelativeRect.getWidth() - scrollBarSize, 1,
506 RelativeRect.getWidth()-1, RelativeRect.getHeight()-1) );
507 }
508 }
509
510 // find the correct size for the horizontal scrollbar
511 if ( HorizontalScrollBar->isVisible() )
512 {
513 if ( !wasHorizontalScrollBarVisible )
514 HorizontalScrollBar->setPos(0);
515
516 if ( VerticalScrollBar->isVisible() )
517 {
518 HorizontalScrollBar->setRelativePosition( core::rect<s32>(1, RelativeRect.getHeight() - scrollBarSize, RelativeRect.getWidth()-(1+scrollBarSize), RelativeRect.getHeight()-1) );
519 }
520 else
521 {
522 HorizontalScrollBar->setRelativePosition( core::rect<s32>(1, RelativeRect.getHeight() - scrollBarSize, RelativeRect.getWidth()-1, RelativeRect.getHeight()-1) );
523 }
524 }
525}
526
527
528void CGUITable::refreshControls()
529{
530 updateAbsolutePosition();
531
532 if ( VerticalScrollBar )
533 VerticalScrollBar->setVisible(false);
534
535 if ( HorizontalScrollBar )
536 HorizontalScrollBar->setVisible(false);
537
538 recalculateHeights();
539 recalculateWidths();
540}
541
542
543//! called if an event happened.
544bool CGUITable::OnEvent(const SEvent &event)
545{
546 if (isEnabled())
547 {
548
549 switch(event.EventType)
550 {
551 case EET_GUI_EVENT:
552 switch(event.GUIEvent.EventType)
553 {
554 case gui::EGET_SCROLL_BAR_CHANGED:
555 if (event.GUIEvent.Caller == VerticalScrollBar)
556 {
557 // current position will get read out in draw
558 return true;
559 }
560 if (event.GUIEvent.Caller == HorizontalScrollBar)
561 {
562 // current position will get read out in draw
563 return true;
564 }
565 break;
566 case gui::EGET_ELEMENT_FOCUS_LOST:
567 {
568 CurrentResizedColumn = -1;
569 Selecting = false;
570 }
571 break;
572 default:
573 break;
574 }
575 break;
576 case EET_MOUSE_INPUT_EVENT:
577 {
578 if ( !isEnabled() )
579 return false;
580
581 core::position2d<s32> p(event.MouseInput.X, event.MouseInput.Y);
582
583 switch(event.MouseInput.Event)
584 {
585 case EMIE_MOUSE_WHEEL:
586 VerticalScrollBar->setPos(VerticalScrollBar->getPos() + (event.MouseInput.Wheel < 0 ? -1 : 1)*-10);
587 return true;
588
589 case EMIE_LMOUSE_PRESSED_DOWN:
590
591 if (Environment->hasFocus(this) &&
592 VerticalScrollBar->isVisible() &&
593 VerticalScrollBar->getAbsolutePosition().isPointInside(p) &&
594 VerticalScrollBar->OnEvent(event))
595 return true;
596
597 if (Environment->hasFocus(this) &&
598 HorizontalScrollBar->isVisible() &&
599 HorizontalScrollBar->getAbsolutePosition().isPointInside(p) &&
600 HorizontalScrollBar->OnEvent(event))
601 return true;
602
603 if ( dragColumnStart( event.MouseInput.X, event.MouseInput.Y ) )
604 {
605 Environment->setFocus(this);
606 return true;
607 }
608
609 if ( selectColumnHeader( event.MouseInput.X, event.MouseInput.Y ) )
610 return true;
611
612 Selecting = true;
613 Environment->setFocus(this);
614 return true;
615
616 case EMIE_LMOUSE_LEFT_UP:
617
618 CurrentResizedColumn = -1;
619 Selecting = false;
620 if (!getAbsolutePosition().isPointInside(p))
621 {
622 Environment->removeFocus(this);
623 }
624
625 if (Environment->hasFocus(this) &&
626 VerticalScrollBar->isVisible() &&
627 VerticalScrollBar->getAbsolutePosition().isPointInside(p) &&
628 VerticalScrollBar->OnEvent(event))
629 {
630 return true;
631 }
632
633 if (Environment->hasFocus(this) &&
634 HorizontalScrollBar->isVisible() &&
635 HorizontalScrollBar->getAbsolutePosition().isPointInside(p) &&
636 HorizontalScrollBar->OnEvent(event))
637 {
638 return true;
639 }
640
641 selectNew(event.MouseInput.Y);
642 return true;
643
644 case EMIE_MOUSE_MOVED:
645 if ( CurrentResizedColumn >= 0 )
646 {
647 if ( dragColumnUpdate(event.MouseInput.X) )
648 {
649 return true;
650 }
651 }
652 if (Selecting || MoveOverSelect)
653 {
654 if (getAbsolutePosition().isPointInside(p))
655 {
656 selectNew(event.MouseInput.Y);
657 return true;
658 }
659 }
660 break;
661 default:
662 break;
663 }
664 }
665 break;
666 default:
667 break;
668 }
669 }
670
671 return IGUIElement::OnEvent(event);
672}
673
674
675void CGUITable::setColumnOrdering(u32 columnIndex, EGUI_COLUMN_ORDERING mode)
676{
677 if ( columnIndex < Columns.size() )
678 Columns[columnIndex].OrderingMode = mode;
679}
680
681
682void CGUITable::swapRows(u32 rowIndexA, u32 rowIndexB)
683{
684 if ( rowIndexA >= Rows.size() )
685 return;
686
687 if ( rowIndexB >= Rows.size() )
688 return;
689
690 Row swap = Rows[rowIndexA];
691 Rows[rowIndexA] = Rows[rowIndexB];
692 Rows[rowIndexB] = swap;
693
694 if ( Selected == s32(rowIndexA) )
695 Selected = rowIndexB;
696 else if( Selected == s32(rowIndexB) )
697 Selected = rowIndexA;
698
699}
700
701
702bool CGUITable::dragColumnStart(s32 xpos, s32 ypos)
703{
704 if ( !ResizableColumns )
705 return false;
706
707 if ( ypos > ( AbsoluteRect.UpperLeftCorner.Y + ItemHeight ) )
708 return false;
709
710 const s32 CLICK_AREA = 12; // to left and right of line which can be dragged
711 s32 pos = AbsoluteRect.UpperLeftCorner.X+1;
712
713 if ( HorizontalScrollBar && HorizontalScrollBar->isVisible() )
714 pos -= HorizontalScrollBar->getPos();
715
716 pos += TotalItemWidth;
717
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 )
720 {
721 u32 colWidth = Columns[i].Width;
722
723 if ( xpos >= (pos - CLICK_AREA) && xpos < ( pos + CLICK_AREA ) )
724 {
725 CurrentResizedColumn = i;
726 ResizeStart = xpos;
727 return true;
728 }
729
730 pos -= colWidth;
731 }
732
733 return false;
734}
735
736
737bool CGUITable::dragColumnUpdate(s32 xpos)
738{
739 if ( !ResizableColumns || CurrentResizedColumn < 0 || CurrentResizedColumn >= s32(Columns.size()) )
740 {
741 CurrentResizedColumn = -1;
742 return false;
743 }
744
745 s32 width = s32(Columns[CurrentResizedColumn].Width) + (xpos-ResizeStart);
746 if ( width < 0 )
747 width = 0;
748 setColumnWidth(CurrentResizedColumn, u32(width));
749 ResizeStart = xpos;
750
751 return false;
752}
753
754
755bool CGUITable::selectColumnHeader(s32 xpos, s32 ypos)
756{
757 if ( ypos > ( AbsoluteRect.UpperLeftCorner.Y + ItemHeight ) )
758 return false;
759
760 s32 pos = AbsoluteRect.UpperLeftCorner.X+1;
761
762 if ( HorizontalScrollBar && HorizontalScrollBar->isVisible() )
763 pos -= HorizontalScrollBar->getPos();
764
765 for ( u32 i = 0 ; i < Columns.size() ; ++i )
766 {
767 u32 colWidth = Columns[i].Width;
768
769 if ( xpos >= pos && xpos < ( pos + s32(colWidth) ) )
770 {
771 setActiveColumn( i, true );
772
773 return true;
774 }
775
776 pos += colWidth;
777 }
778
779 return false;
780}
781
782
783void CGUITable::orderRows(s32 columnIndex, EGUI_ORDERING_MODE mode)
784{
785 Row swap;
786
787 if ( columnIndex == -1 )
788 columnIndex = getActiveColumn();
789 if ( columnIndex < 0 )
790 return;
791
792 if ( mode == EGOM_ASCENDING )
793 {
794 for ( s32 i = 0 ; i < s32(Rows.size()) - 1 ; ++i )
795 {
796 for ( s32 j = 0 ; j < s32(Rows.size()) - i - 1 ; ++j )
797 {
798 if ( Rows[j+1].Items[columnIndex].Text < Rows[j].Items[columnIndex].Text )
799 {
800 swap = Rows[j];
801 Rows[j] = Rows[j+1];
802 Rows[j+1] = swap;
803
804 if ( Selected == j )
805 Selected = j+1;
806 else if( Selected == j+1 )
807 Selected = j;
808 }
809 }
810 }
811 }
812 else if ( mode == EGOM_DESCENDING )
813 {
814 for ( s32 i = 0 ; i < s32(Rows.size()) - 1 ; ++i )
815 {
816 for ( s32 j = 0 ; j < s32(Rows.size()) - i - 1 ; ++j )
817 {
818 if ( Rows[j].Items[columnIndex].Text < Rows[j+1].Items[columnIndex].Text)
819 {
820 swap = Rows[j];
821 Rows[j] = Rows[j+1];
822 Rows[j+1] = swap;
823
824 if ( Selected == j )
825 Selected = j+1;
826 else if( Selected == j+1 )
827 Selected = j;
828 }
829 }
830 }
831 }
832}
833
834
835void CGUITable::selectNew(s32 ypos, bool onlyHover)
836{
837 IGUISkin* skin = Environment->getSkin();
838 if (!skin)
839 return;
840
841 s32 oldSelected = Selected;
842
843 if ( ypos < ( AbsoluteRect.UpperLeftCorner.Y + ItemHeight ) )
844 return;
845
846 // find new selected item.
847 if (ItemHeight!=0)
848 Selected = ((ypos - AbsoluteRect.UpperLeftCorner.Y - ItemHeight - 1) + VerticalScrollBar->getPos()) / ItemHeight;
849
850 if (Selected >= (s32)Rows.size())
851 Selected = Rows.size() - 1;
852 else if (Selected<0)
853 Selected = 0;
854
855 // post the news
856 if (Parent && !onlyHover)
857 {
858 SEvent event;
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);
864 }
865}
866
867
868//! draws the element and its children
869void CGUITable::draw()
870{
871 if (!IsVisible)
872 return;
873
874 irr::video::IVideoDriver* driver = Environment->getVideoDriver();
875
876 IGUISkin* skin = Environment->getSkin();
877 if (!skin)
878 return;
879
880 IGUIFont* font = skin->getFont();
881 if (!font)
882 return;
883
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);
893
894 s32 headerBottom = tableRect.UpperLeftCorner.Y + ItemHeight;
895
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);
900
901 // draw background for whole element
902 skin->draw3DSunkenPane(this, skin->getColor(EGDC_3D_HIGH_LIGHT), true, DrawBack, AbsoluteRect, &AbsoluteClippingRect);
903
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() )
910 {
911 scrolledTableClient.UpperLeftCorner.Y -= VerticalScrollBar->getPos();
912 scrolledTableClient.LowerRightCorner.Y -= VerticalScrollBar->getPos();
913 }
914 if ( HorizontalScrollBar && HorizontalScrollBar->isVisible() )
915 {
916 scrolledTableClient.UpperLeftCorner.X -= HorizontalScrollBar->getPos();
917 scrolledTableClient.LowerRightCorner.X -= HorizontalScrollBar->getPos();
918 }
919
920 // rowRect is around the scrolled row
921 core::rect<s32> rowRect(scrolledTableClient);
922 rowRect.LowerRightCorner.Y = rowRect.UpperLeftCorner.Y + ItemHeight;
923
924 u32 pos;
925 for ( u32 i = 0 ; i < Rows.size() ; ++i )
926 {
927 if (rowRect.LowerRightCorner.Y >= AbsoluteRect.UpperLeftCorner.Y &&
928 rowRect.UpperLeftCorner.Y <= AbsoluteRect.LowerRightCorner.Y)
929 {
930 // draw row seperator
931 if ( DrawFlags & EGTDF_ROWS )
932 {
933 core::rect<s32> lineRect(rowRect);
934 lineRect.UpperLeftCorner.Y = lineRect.LowerRightCorner.Y - 1;
935 driver->draw2DRectangle(skin->getColor(EGDC_3D_SHADOW), lineRect, &clientClip);
936 }
937
938 core::rect<s32> textRect(rowRect);
939 pos = rowRect.UpperLeftCorner.X;
940
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);
944
945 for ( u32 j = 0 ; j < Columns.size() ; ++j )
946 {
947 textRect.UpperLeftCorner.X = pos + CellWidthPadding;
948 textRect.LowerRightCorner.X = pos + Columns[j].Width - CellWidthPadding;
949
950 // draw item text
951 if ((s32)i == Selected)
952 {
953 font->draw(Rows[i].Items[j].BrokenText.c_str(), textRect, skin->getColor(isEnabled() ? EGDC_HIGH_LIGHT_TEXT : EGDC_GRAY_TEXT), false, true, &clientClip);
954 }
955 else
956 {
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);
960 }
961
962 pos += Columns[j].Width;
963 }
964 }
965
966 rowRect.UpperLeftCorner.Y += ItemHeight;
967 rowRect.LowerRightCorner.Y += ItemHeight;
968 }
969
970 core::rect<s32> columnSeparator(clientClip);
971 pos = scrolledTableClient.UpperLeftCorner.X;
972
973 core::rect<s32> tableClip(tableRect);
974 tableClip.clipAgainst(AbsoluteClippingRect);
975
976 for (u32 i = 0 ; i < Columns.size() ; ++i )
977 {
978 const wchar_t* text = Columns[i].Name.c_str();
979 u32 colWidth = Columns[i].Width;
980
981 //core::dimension2d<s32 > dim = font->getDimension(text);
982
983 core::rect<s32> columnrect(pos, tableRect.UpperLeftCorner.Y, pos + colWidth, headerBottom);
984
985 // draw column background
986 skin->draw3DButtonPaneStandard(this, columnrect, &tableClip);
987
988 // draw column seperator
989 if ( DrawFlags & EGTDF_COLUMNS )
990 {
991 columnSeparator.UpperLeftCorner.X = pos;
992 columnSeparator.LowerRightCorner.X = pos + 1;
993 driver->draw2DRectangle(skin->getColor(EGDC_3D_SHADOW), columnSeparator, &tableClip);
994 }
995
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);
999
1000 // draw icon for active column tab
1001 if ( (s32)i == ActiveTab )
1002 {
1003 if ( CurrentOrdering == EGOM_ASCENDING )
1004 {
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);
1008 }
1009 else
1010 {
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);
1014 }
1015 }
1016
1017 pos += colWidth;
1018 }
1019
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);
1023
1024 IGUIElement::draw();
1025}
1026
1027
1028void CGUITable::breakText(const core::stringw& text, core::stringw& brokenText, u32 cellWidth)
1029{
1030 IGUISkin* skin = Environment->getSkin();
1031
1032 if (!skin)
1033 return;
1034
1035 if (!Font)
1036 return;
1037
1038 IGUIFont* font = skin->getFont();
1039 if (!font)
1040 return;
1041
1042 core::stringw line, lineDots;
1043 wchar_t c[2];
1044 c[1] = L'\0';
1045
1046 const u32 maxLength = cellWidth - (CellWidthPadding * 2);
1047 const u32 maxLengthDots = cellWidth - (CellWidthPadding * 2) - font->getDimension(L"...").Width;
1048 const u32 size = text.size();
1049 u32 pos = 0;
1050
1051 u32 i;
1052
1053 for (i=0; i<size; ++i)
1054 {
1055 c[0] = text[i];
1056
1057 if (c[0] == L'\n')
1058 break;
1059
1060 pos += font->getDimension(c).Width;
1061 if ( pos > maxLength )
1062 break;
1063
1064 if ( font->getDimension( (line + c).c_str() ).Width > maxLengthDots )
1065 lineDots = line;
1066
1067 line += c[0];
1068 }
1069
1070 if ( i < size )
1071 brokenText = lineDots + L"...";
1072 else
1073 brokenText = line;
1074}
1075
1076
1077//! Set some flags influencing the layout of the table
1078void CGUITable::setDrawFlags(s32 flags)
1079{
1080 DrawFlags = flags;
1081}
1082
1083
1084//! Get the flags which influence the layout of the table
1085s32 CGUITable::getDrawFlags() const
1086{
1087 return DrawFlags;
1088}
1089
1090
1091//! Writes attributes of the element.
1092void CGUITable::serializeAttributes(io::IAttributes* out, io::SAttributeReadWriteOptions* options) const
1093{
1094 IGUITable::serializeAttributes(out, options);
1095
1096 out->addInt("ColumnCount", Columns.size());
1097 u32 i;
1098 for (i=0;i<Columns.size(); ++i)
1099 {
1100 core::stringc label;
1101
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);
1108 }
1109
1110 out->addInt("RowCount", Rows.size());
1111 for (i=0;i<Rows.size(); ++i)
1112 {
1113 core::stringc label;
1114
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 );
1118
1119 //label = "Row"; label += i; label += "ItemCount";
1120 //out->addInt(label.c_str(), Rows[i].Items.size());
1121 u32 c;
1122 for ( c=0; c < Rows[i].Items.size(); ++c )
1123 {
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
1132 }
1133 }
1134
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
1141
1142 out->addBool ("Clip", Clip);
1143 out->addBool ("DrawBack", DrawBack);
1144 out->addBool ("MoveOverSelect", MoveOverSelect);
1145
1146 // s32 CurrentResizedColumn; // runtime info - depends on user action
1147 out->addBool ("ResizableColumns", ResizableColumns);
1148
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);
1156}
1157
1158
1159//! Reads attributes of the element
1160void CGUITable::deserializeAttributes(io::IAttributes* in, io::SAttributeReadWriteOptions* options)
1161{
1162 IGUITable::deserializeAttributes(in, options);
1163
1164 Columns.clear();
1165 u32 columnCount = in->getAttributeAsInt("ColumnCount");
1166 u32 i;
1167 for (i=0;i<columnCount; ++i)
1168 {
1169 core::stringc label;
1170 Column column;
1171
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";
1177
1178 column.OrderingMode = EGCO_NONE;
1179 s32 co = in->getAttributeAsEnumeration(label.c_str(), GUIColumnOrderingNames);
1180 if (co > 0)
1181 column.OrderingMode = EGUI_COLUMN_ORDERING(co);
1182
1183 Columns.push_back(column);
1184 }
1185
1186 Rows.clear();
1187 u32 rowCount = in->getAttributeAsInt("RowCount");
1188 for (i=0; i<rowCount; ++i)
1189 {
1190 core::stringc label;
1191
1192 Row row;
1193
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() );
1197
1198 Rows.push_back(row);
1199
1200 //label = "Row"; label += i; label += "ItemCount";
1201 //u32 itemCount = in->getAttributeAsInt(label.c_str());
1202 u32 c;
1203 for ( c=0; c < columnCount; ++c )
1204 {
1205 Cell cell;
1206
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());
1214
1215 cell.Data = NULL;
1216
1217 Rows[Rows.size()-1].Items.push_back(cell);
1218 }
1219 }
1220
1221 ItemHeight = 0; // calculated
1222 TotalItemHeight = 0; // calculated
1223 TotalItemWidth = 0; // calculated
1224
1225 // force font recalculation
1226 if ( Font )
1227 {
1228 Font->drop();
1229 Font = 0;
1230 }
1231
1232 Clip = in->getAttributeAsBool("Clip");
1233 DrawBack = in->getAttributeAsBool("DrawBack");
1234 MoveOverSelect = in->getAttributeAsBool("MoveOverSelect");
1235
1236 CurrentResizedColumn = -1;
1237 ResizeStart = 0;
1238 ResizableColumns = in->getAttributeAsBool("ResizableColumns");
1239
1240 Selected = -1;
1241 CellWidthPadding = in->getAttributeAsInt("CellWidthPadding");
1242 CellHeightPadding = in->getAttributeAsInt("CellHeightPadding");
1243 ActiveTab = -1;
1244 Selecting = false;
1245
1246 CurrentOrdering = (EGUI_ORDERING_MODE) in->getAttributeAsEnumeration("CurrentOrdering", GUIOrderingModeNames);
1247 DrawFlags = in->getAttributeAsInt("DrawFlags");
1248
1249 refreshControls();
1250}
1251
1252} // end namespace gui
1253} // end namespace irr
1254
1255#endif
1256