1 /***********************************************************************
2 created: 13/4/2004
3 author: Paul D Turner
4
5 purpose: Implementation of ListHeader widget base class
6 *************************************************************************/
7 /***************************************************************************
8 * Copyright (C) 2004 - 2006 Paul D Turner & The CEGUI Development Team
9 *
10 * Permission is hereby granted, free of charge, to any person obtaining
11 * a copy of this software and associated documentation files (the
12 * "Software"), to deal in the Software without restriction, including
13 * without limitation the rights to use, copy, modify, merge, publish,
14 * distribute, sublicense, and/or sell copies of the Software, and to
15 * permit persons to whom the Software is furnished to do so, subject to
16 * the following conditions:
17 *
18 * The above copyright notice and this permission notice shall be
19 * included in all copies or substantial portions of the Software.
20 *
21 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
22 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
23 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
24 * IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
25 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
26 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
27 * OTHER DEALINGS IN THE SOFTWARE.
28 ***************************************************************************/
29 #include "CEGUI/widgets/ListHeader.h"
30 #include "CEGUI/Exceptions.h"
31 #include "CEGUI/CoordConverter.h"
32 #include <sstream>
33
34
35 // Start of CEGUI namespace section
36 namespace CEGUI
37 {
38 const String ListHeader::EventNamespace("ListHeader");
39 const String ListHeader::WidgetTypeName("CEGUI/ListHeader");
40
41 /*************************************************************************
42 ListHeaderWindowRenderer constructor
43 *************************************************************************/
ListHeaderWindowRenderer(const String & name)44 ListHeaderWindowRenderer::ListHeaderWindowRenderer(const String& name) :
45 WindowRenderer(name, "ListHeader")
46 {
47 }
48 /*************************************************************************
49 Constants
50 *************************************************************************/
51 // Event names
52 const String ListHeader::EventSortColumnChanged( "SortColumnChanged" );
53 const String ListHeader::EventSortDirectionChanged( "SortDirectionChanged" );
54 const String ListHeader::EventSegmentSized( "SegmentSized" );
55 const String ListHeader::EventSegmentClicked( "SegmentClicked" );
56 const String ListHeader::EventSplitterDoubleClicked( "SplitterDoubleClicked" );
57 const String ListHeader::EventSegmentSequenceChanged( "SegmentSequenceChanged" );
58 const String ListHeader::EventSegmentAdded( "SegmentAdded" );
59 const String ListHeader::EventSegmentRemoved( "SegmentRemoved" );
60 const String ListHeader::EventSortSettingChanged( "SortSettingChanged" );
61 const String ListHeader::EventDragMoveSettingChanged( "DragMoveSettingChanged" );
62 const String ListHeader::EventDragSizeSettingChanged( "DragSizeSettingChanged" );
63 const String ListHeader::EventSegmentRenderOffsetChanged( "SegmentRenderOffsetChanged" );
64
65 // values
66 const float ListHeader::ScrollSpeed = 8.0f;
67 const float ListHeader::MinimumSegmentPixelWidth = 20.0f;
68
69 /*************************************************************************
70 Child Widget name suffix constants
71 *************************************************************************/
72 const String ListHeader::SegmentNameSuffix("__auto_seg_");
73
74
75
76 /*************************************************************************
77 Constructor for the list header base class.
78 *************************************************************************/
ListHeader(const String & type,const String & name)79 ListHeader::ListHeader(const String& type, const String& name) :
80 Window(type, name),
81 d_sortSegment(0),
82 d_sizingEnabled(true),
83 d_sortingEnabled(true),
84 d_movingEnabled(true),
85 d_uniqueIDNumber(0),
86 d_segmentOffset(0.0f),
87 d_sortDir(ListHeaderSegment::None)
88 {
89 addHeaderProperties();
90 }
91
92
93 /*************************************************************************
94 Destructor for the list header base class.
95 *************************************************************************/
~ListHeader(void)96 ListHeader::~ListHeader(void)
97 {
98 }
99
100
101 /*************************************************************************
102 Return the current number of segments in the header.
103 *************************************************************************/
getColumnCount(void) const104 uint ListHeader::getColumnCount(void) const
105 {
106 return (uint)d_segments.size();
107 }
108
109
110 /*************************************************************************
111 Given a zero based column index, return the ListHeaderSegment.
112 *************************************************************************/
getSegmentFromColumn(uint column) const113 ListHeaderSegment& ListHeader::getSegmentFromColumn(uint column) const
114 {
115 if (column >= getColumnCount())
116 {
117 CEGUI_THROW(InvalidRequestException(
118 "requested column index is out of range for this ListHeader."));
119 }
120 else
121 {
122 return *d_segments[column];
123 }
124 }
125
126 /*************************************************************************
127 Return the ListHeaderSegment with the requested ID.
128 *************************************************************************/
getSegmentFromID(uint id) const129 ListHeaderSegment& ListHeader::getSegmentFromID(uint id) const
130 {
131 for (uint i = 0; i < getColumnCount(); ++i)
132 {
133 if (d_segments[i]->getID() == id)
134 {
135 return *d_segments[i];
136 }
137
138 }
139
140 // No such segment found, throw exception
141 CEGUI_THROW(InvalidRequestException(
142 "no segment with the requested ID is attached to this ListHeader."));
143 }
144
145
146 /*************************************************************************
147 Return the sort-key segment.
148 *************************************************************************/
getSortSegment(void) const149 ListHeaderSegment& ListHeader::getSortSegment(void) const
150 {
151 if (!d_sortSegment)
152 {
153 CEGUI_THROW(InvalidRequestException(
154 "Sort segment was invalid! (No segments are attached to the ListHeader?)"));
155 }
156 else
157 {
158 return *d_sortSegment;
159 }
160
161 }
162 /*************************************************************************
163 Return the sort-key segment.
164 *************************************************************************/
getSortSegmentID(void) const165 uint ListHeader::getSortSegmentID(void) const
166 {
167 return getSortSegment().getID();
168 }
169
170 /*************************************************************************
171 Given a segment, return it's zero based column index.
172 *************************************************************************/
getColumnFromSegment(const ListHeaderSegment & segment) const173 uint ListHeader::getColumnFromSegment(const ListHeaderSegment& segment) const
174 {
175 for (uint i = 0; i < getColumnCount(); ++i)
176 {
177 if (d_segments[i] == &segment)
178 {
179 return i;
180 }
181
182 }
183
184 // No such segment found, throw exception
185 CEGUI_THROW(InvalidRequestException(
186 "the given ListHeaderSegment is not attached to this ListHeader."));
187 }
188
189
190 /*************************************************************************
191 Return the column index that has a segment with the requested ID.
192 *************************************************************************/
getColumnFromID(uint id) const193 uint ListHeader::getColumnFromID(uint id) const
194 {
195 for (uint i = 0; i < getColumnCount(); ++i)
196 {
197 if (d_segments[i]->getID() == id)
198 {
199 return i;
200 }
201
202 }
203
204 // No such segment found, throw exception
205 CEGUI_THROW(InvalidRequestException(
206 "no column with the requested ID is available on this ListHeader."));
207 }
208
209
210 /*************************************************************************
211 Return the current sort-key column
212 *************************************************************************/
getSortColumn(void) const213 uint ListHeader::getSortColumn(void) const
214 {
215 return getColumnFromSegment(getSortSegment());
216 }
217
218
219 /*************************************************************************
220 return the zero based column index of the segment with the requested
221 text.
222 *************************************************************************/
getColumnWithText(const String & text) const223 uint ListHeader::getColumnWithText(const String& text) const
224 {
225 for (uint i = 0; i < getColumnCount(); ++i)
226 {
227 if (d_segments[i]->getText() == text)
228 {
229 return i;
230 }
231
232 }
233
234 // No such segment found, throw exception
235 CEGUI_THROW(InvalidRequestException(
236 "no column with the text '" + text + "' is attached to this ListHeader."));
237 }
238
239
240 /*************************************************************************
241 return the pixel offset to the given segment
242 *************************************************************************/
getPixelOffsetToSegment(const ListHeaderSegment & segment) const243 float ListHeader::getPixelOffsetToSegment(const ListHeaderSegment& segment) const
244 {
245 float offset = 0.0f;
246
247 for (uint i = 0; i < getColumnCount(); ++i)
248 {
249 if (d_segments[i] == &segment)
250 {
251 return offset;
252 }
253
254 offset += d_segments[i]->getPixelSize().d_width;
255 }
256
257 // No such segment found, throw exception
258 CEGUI_THROW(InvalidRequestException(
259 "the given ListHeaderSegment is not attached to this ListHeader."));
260 }
261
262
263 /*************************************************************************
264 return the pixel offset to the segment with the given column index
265 *************************************************************************/
getPixelOffsetToColumn(uint column) const266 float ListHeader::getPixelOffsetToColumn(uint column) const
267 {
268 if (column >= getColumnCount())
269 {
270 CEGUI_THROW(InvalidRequestException(
271 "requested column index is out of range for this ListHeader."));
272 }
273 else
274 {
275 float offset = 0.0f;
276
277 for (uint i = 0; i < column; ++i)
278 {
279 offset += d_segments[i]->getPixelSize().d_width;
280 }
281
282 return offset;
283 }
284
285 }
286
287
288 /*************************************************************************
289 Return the total pixel width of all segments
290 *************************************************************************/
getTotalSegmentsPixelExtent(void) const291 float ListHeader::getTotalSegmentsPixelExtent(void) const
292 {
293 float extent = 0.0f;
294
295 for (uint i = 0; i < getColumnCount(); ++i)
296 {
297 extent += d_segments[i]->getPixelSize().d_width;
298 }
299
300 return extent;
301 }
302
303
304 /*************************************************************************
305 Return the width of the segment at the specified column index.
306 *************************************************************************/
getColumnWidth(uint column) const307 UDim ListHeader::getColumnWidth(uint column) const
308 {
309 if (column >= getColumnCount())
310 {
311 CEGUI_THROW(InvalidRequestException(
312 "requested column index is out of range for this ListHeader."));
313 }
314 else
315 {
316 return d_segments[column]->getWidth();
317 }
318
319 }
320
321
322 /*************************************************************************
323 return the current sort direction
324 *************************************************************************/
getSortDirection(void) const325 ListHeaderSegment::SortDirection ListHeader::getSortDirection(void) const
326 {
327 return d_sortDir;
328 }
329
330
331 /*************************************************************************
332 Return whether sorting is enabled for this header.
333 *************************************************************************/
isSortingEnabled(void) const334 bool ListHeader::isSortingEnabled(void) const
335 {
336 return d_sortingEnabled;
337 }
338
339
340 /*************************************************************************
341 Return whether segment sizing is enabled for this header
342 *************************************************************************/
isColumnSizingEnabled(void) const343 bool ListHeader::isColumnSizingEnabled(void) const
344 {
345 return d_sizingEnabled;
346 }
347
348
349 /*************************************************************************
350 Return whether segment dragging is enabled for this header.
351 *************************************************************************/
isColumnDraggingEnabled(void) const352 bool ListHeader::isColumnDraggingEnabled(void) const
353 {
354 return d_movingEnabled;
355 }
356
357
358 /*************************************************************************
359 Set whether the ability to change sort segment / direction is enabled
360 *************************************************************************/
setSortingEnabled(bool setting)361 void ListHeader::setSortingEnabled(bool setting)
362 {
363 if (d_sortingEnabled != setting)
364 {
365 d_sortingEnabled = setting;
366
367 // make the setting change for all component segments.
368 for (uint i = 0; i <getColumnCount(); ++i)
369 {
370 d_segments[i]->setClickable(d_sortingEnabled);
371 }
372
373 // Fire setting changed event.
374 WindowEventArgs args(this);
375 onSortSettingChanged(args);
376 }
377
378 }
379
380
381 /*************************************************************************
382 Set the sort direction on the current sort segment / column.
383 *************************************************************************/
setSortDirection(ListHeaderSegment::SortDirection direction)384 void ListHeader::setSortDirection(ListHeaderSegment::SortDirection direction)
385 {
386 if (d_sortDir != direction)
387 {
388 d_sortDir = direction;
389
390 // set direction of current sort segment
391 if (d_sortSegment)
392 {
393 d_sortSegment->setSortDirection(direction);
394 }
395
396 // Fire sort direction changed event.
397 WindowEventArgs args(this);
398 onSortDirectionChanged(args);
399 }
400
401 }
402
403
404 /*************************************************************************
405 Set the current sort segment.
406 *************************************************************************/
setSortSegment(const ListHeaderSegment & segment)407 void ListHeader::setSortSegment(const ListHeaderSegment& segment)
408 {
409 setSortColumn(getColumnFromSegment(segment));
410 }
411
412
413 /*************************************************************************
414 Set the current sort segment via column index.
415 *************************************************************************/
setSortColumn(uint column)416 void ListHeader::setSortColumn(uint column)
417 {
418 if (column >= getColumnCount())
419 {
420 CEGUI_THROW(InvalidRequestException(
421 "specified column index is out of range for this ListHeader."));
422 }
423 else
424 {
425 // if column is different to current sort segment
426 if (d_sortSegment != d_segments[column])
427 {
428 // set sort direction on 'old' sort segment to none.
429 if (d_sortSegment)
430 {
431 d_sortSegment->setSortDirection(ListHeaderSegment::None);
432 }
433
434 // set-up new sort segment
435 d_sortSegment = d_segments[column];
436 d_sortSegment->setSortDirection(d_sortDir);
437
438 // Fire sort column changed event
439 WindowEventArgs args(this);
440 onSortColumnChanged(args);
441 }
442
443 }
444
445 }
446
447
448 /*************************************************************************
449 Set the current sort segment via ID code.
450 *************************************************************************/
setSortColumnFromID(uint id)451 void ListHeader::setSortColumnFromID(uint id)
452 {
453 setSortSegment(getSegmentFromID(id));
454 }
455
456
457 /*************************************************************************
458 Set whether or not segments may be sized.
459 *************************************************************************/
setColumnSizingEnabled(bool setting)460 void ListHeader::setColumnSizingEnabled(bool setting)
461 {
462 if (d_sizingEnabled != setting)
463 {
464 d_sizingEnabled = setting;
465
466 // make the setting change for all component segments.
467 for (uint i = 0; i <getColumnCount(); ++i)
468 {
469 d_segments[i]->setSizingEnabled(d_sizingEnabled);
470 }
471
472 // Fire setting changed event.
473 WindowEventArgs args(this);
474 onDragSizeSettingChanged(args);
475 }
476
477 }
478
479
480 /*************************************************************************
481 Set whether columns may be dragged into new orders.
482 *************************************************************************/
setColumnDraggingEnabled(bool setting)483 void ListHeader::setColumnDraggingEnabled(bool setting)
484 {
485 if (d_movingEnabled != setting)
486 {
487 d_movingEnabled = setting;
488
489 // make the setting change for all component segments.
490 for (uint i = 0; i <getColumnCount(); ++i)
491 {
492 d_segments[i]->setDragMovingEnabled(d_movingEnabled);
493 }
494
495 // Fire setting changed event.
496 WindowEventArgs args(this);
497 onDragMoveSettingChanged(args);
498 }
499
500 }
501
502
503 /*************************************************************************
504 Add a new column segment to the header.
505 *************************************************************************/
addColumn(const String & text,uint id,const UDim & width)506 void ListHeader::addColumn(const String& text, uint id, const UDim& width)
507 {
508 // add just inserts at end.
509 insertColumn(text, id, width, getColumnCount());
510 }
511
512
513 /*************************************************************************
514 Insert a new column segment into the header
515 *************************************************************************/
insertColumn(const String & text,uint id,const UDim & width,uint position)516 void ListHeader::insertColumn(const String& text, uint id, const UDim& width, uint position)
517 {
518 // if position is too big, insert at end.
519 if (position > getColumnCount())
520 {
521 position = getColumnCount();
522 }
523
524 ListHeaderSegment* seg = createInitialisedSegment(text, id, width);
525 d_segments.insert((d_segments.begin() + position), seg);
526
527 // add window as a child of this
528 addChild(seg);
529
530 layoutSegments();
531
532 // Fire segment added event.
533 WindowEventArgs args(this);
534 onSegmentAdded(args);
535
536 // if sort segment is invalid, make it valid now we have a segment attached
537 if (!d_sortSegment)
538 {
539 setSortColumn(position);
540 }
541 }
542
543
544 /*************************************************************************
545 Remove a column from the header
546 *************************************************************************/
removeColumn(uint column)547 void ListHeader::removeColumn(uint column)
548 {
549 if (column >= getColumnCount())
550 {
551 CEGUI_THROW(InvalidRequestException(
552 "specified column index is out of range for this ListHeader."));
553 }
554 else
555 {
556 ListHeaderSegment* seg = d_segments[column];
557
558 // remove from the list of segments
559 d_segments.erase(d_segments.begin() + column);
560
561 // have we removed the sort column?
562 if (d_sortSegment == seg)
563 {
564 // any other columns?
565 if (getColumnCount() > 0)
566 {
567 // put first column in as sort column
568 d_sortDir = ListHeaderSegment::None;
569 setSortColumn(0);
570 }
571 // no columns, set sort segment to NULL
572 else
573 {
574 d_sortSegment = 0;
575 }
576
577 }
578
579 // detach segment window from the header (this)
580 removeChild(seg);
581
582 // destroy the segment (done in derived class, since that's where it was created).
583 destroyListSegment(seg);
584
585 layoutSegments();
586
587 // Fire segment removed event.
588 WindowEventArgs args(this);
589 onSegmentRemoved(args);
590 }
591
592 }
593
594
595 /*************************************************************************
596 Move a column segment to a new position
597 *************************************************************************/
moveColumn(uint column,uint position)598 void ListHeader::moveColumn(uint column, uint position)
599 {
600 if (column >= getColumnCount())
601 {
602 CEGUI_THROW(InvalidRequestException(
603 "specified column index is out of range for this ListHeader."));
604 }
605 else
606 {
607 // if position is too big, move to end.
608 if (position >= getColumnCount())
609 {
610 position = getColumnCount() - 1;
611 }
612
613 ListHeaderSegment* seg = d_segments[column];
614
615 // remove original copy of segment
616 d_segments.erase(d_segments.begin() + column);
617
618 // insert the segment at it's new position
619 d_segments.insert(d_segments.begin() + position, seg);
620
621 // Fire sequence changed event
622 HeaderSequenceEventArgs args(this, column, position);
623 onSegmentSequenceChanged(args);
624
625 layoutSegments();
626 }
627
628 }
629
630
631 /*************************************************************************
632 Insert a new column segment into the header
633 *************************************************************************/
insertColumn(const String & text,uint id,const UDim & width,const ListHeaderSegment & position)634 void ListHeader::insertColumn(const String& text, uint id, const UDim& width, const ListHeaderSegment& position)
635 {
636 insertColumn(text, id, width, getColumnFromSegment(position));
637 }
638
639
640 /*************************************************************************
641 Remove a segment from the header
642 *************************************************************************/
removeSegment(const ListHeaderSegment & segment)643 void ListHeader::removeSegment(const ListHeaderSegment& segment)
644 {
645 removeColumn(getColumnFromSegment(segment));
646 }
647
648
649 /*************************************************************************
650 Move a column segment to a new position.
651 *************************************************************************/
moveColumn(uint column,const ListHeaderSegment & position)652 void ListHeader::moveColumn(uint column, const ListHeaderSegment& position)
653 {
654 moveColumn(column, getColumnFromSegment(position));
655 }
656
657
658 /*************************************************************************
659 Move a segment to a new position
660 *************************************************************************/
moveSegment(const ListHeaderSegment & segment,uint position)661 void ListHeader::moveSegment(const ListHeaderSegment& segment, uint position)
662 {
663 moveColumn(getColumnFromSegment(segment), position);
664 }
665
666
667 /*************************************************************************
668 Move a segment to a new position
669 *************************************************************************/
moveSegment(const ListHeaderSegment & segment,const ListHeaderSegment & position)670 void ListHeader::moveSegment(const ListHeaderSegment& segment, const ListHeaderSegment& position)
671 {
672 moveColumn(getColumnFromSegment(segment), getColumnFromSegment(position));
673 }
674
675
676 /*************************************************************************
677 Set the current segment offset value (metrics dependant)
678 *************************************************************************/
setSegmentOffset(float offset)679 void ListHeader::setSegmentOffset(float offset)
680 {
681 if (d_segmentOffset != offset)
682 {
683 d_segmentOffset = offset;
684 layoutSegments();
685 invalidate();
686
687 // Fire event.
688 WindowEventArgs args(this);
689 onSegmentOffsetChanged(args);
690 }
691
692 }
693
694
695 /*************************************************************************
696 Set the width of the specified column.
697 *************************************************************************/
setColumnWidth(uint column,const UDim & width)698 void ListHeader::setColumnWidth(uint column, const UDim& width)
699 {
700 if (column >= getColumnCount())
701 {
702 CEGUI_THROW(InvalidRequestException(
703 "specified column index is out of range for this ListHeader."));
704 }
705 else
706 {
707 d_segments[column]->setSize(USize(width, d_segments[column]->getSize().d_height));
708
709 layoutSegments();
710
711 // Fire segment sized event.
712 WindowEventArgs args(d_segments[column]);
713 onSegmentSized(args);
714 }
715
716 }
717
718
719 /*************************************************************************
720 Create initialise and return a ListHeaderSegment object, with all
721 events subscribed and ready to use.
722 *************************************************************************/
createInitialisedSegment(const String & text,uint id,const UDim & width)723 ListHeaderSegment* ListHeader::createInitialisedSegment(const String& text, uint id, const UDim& width)
724 {
725 // Build unique name
726 std::stringstream name;
727 name << SegmentNameSuffix << d_uniqueIDNumber;
728
729 // create segment.
730 ListHeaderSegment* newseg = createNewSegment(name.str().c_str());
731 d_uniqueIDNumber++;
732
733 // setup segment;
734 newseg->setSize(USize(width, cegui_reldim(1.0f)));
735 newseg->setMinSize(USize(cegui_absdim(MinimumSegmentPixelWidth), cegui_absdim(0)));
736 newseg->setText(text);
737 newseg->setID(id);
738 newseg->setSizingEnabled(d_sizingEnabled);
739 newseg->setDragMovingEnabled(d_movingEnabled);
740 newseg->setClickable(d_sortingEnabled);
741
742 // subscribe events we listen to
743 newseg->subscribeEvent(ListHeaderSegment::EventSegmentSized, Event::Subscriber(&CEGUI::ListHeader::segmentSizedHandler, this));
744 newseg->subscribeEvent(ListHeaderSegment::EventSegmentDragStop, Event::Subscriber(&CEGUI::ListHeader::segmentMovedHandler, this));
745 newseg->subscribeEvent(ListHeaderSegment::EventSegmentClicked, Event::Subscriber(&CEGUI::ListHeader::segmentClickedHandler, this));
746 newseg->subscribeEvent(ListHeaderSegment::EventSplitterDoubleClicked, Event::Subscriber(&CEGUI::ListHeader::segmentDoubleClickHandler, this));
747 newseg->subscribeEvent(ListHeaderSegment::EventSegmentDragPositionChanged, Event::Subscriber(&CEGUI::ListHeader::segmentDragHandler, this));
748
749 return newseg;
750 }
751
752
753 /*************************************************************************
754 Layout the segments
755 *************************************************************************/
layoutSegments(void)756 void ListHeader::layoutSegments(void)
757 {
758 UVector2 pos(cegui_absdim(-d_segmentOffset), cegui_absdim(0.0f));
759
760 for (uint i = 0; i < getColumnCount(); ++i)
761 {
762 d_segments[i]->setPosition(pos);
763 pos.d_x += d_segments[i]->getWidth();
764 }
765
766 }
767
validateWindowRenderer(const WindowRenderer * renderer) const768 bool ListHeader::validateWindowRenderer(const WindowRenderer* renderer) const
769 {
770 return dynamic_cast<const ListHeaderWindowRenderer*>(renderer) != 0;
771 }
772
773 /*************************************************************************
774 Handler called when the sort column is changed.
775 *************************************************************************/
onSortColumnChanged(WindowEventArgs & e)776 void ListHeader::onSortColumnChanged(WindowEventArgs& e)
777 {
778 fireEvent(EventSortColumnChanged, e, EventNamespace);
779 }
780
781
782 /*************************************************************************
783 Handler called when the sort direction is changed.
784 *************************************************************************/
onSortDirectionChanged(WindowEventArgs & e)785 void ListHeader::onSortDirectionChanged(WindowEventArgs& e)
786 {
787 fireEvent(EventSortDirectionChanged, e, EventNamespace);
788 }
789
790
791 /*************************************************************************
792 Handler called when a segment is sized by the user.
793 e.window points to the segment.
794 *************************************************************************/
onSegmentSized(WindowEventArgs & e)795 void ListHeader::onSegmentSized(WindowEventArgs& e)
796 {
797 fireEvent(EventSegmentSized, e, EventNamespace);
798 }
799
800
801 /*************************************************************************
802 Handler called when a segment is clicked by the user.
803 e.window points to the segment.
804 *************************************************************************/
onSegmentClicked(WindowEventArgs & e)805 void ListHeader::onSegmentClicked(WindowEventArgs& e)
806 {
807 fireEvent(EventSegmentClicked, e, EventNamespace);
808 }
809
810
811 /*************************************************************************
812 Handler called when a segment splitter / sizer is double-clicked.
813 e.window points to the segment.
814 *************************************************************************/
onSplitterDoubleClicked(WindowEventArgs & e)815 void ListHeader::onSplitterDoubleClicked(WindowEventArgs& e)
816 {
817 fireEvent(EventSplitterDoubleClicked, e, EventNamespace);
818 }
819
820
821 /*************************************************************************
822 Handler called when the segment / column order changes.
823 *************************************************************************/
onSegmentSequenceChanged(WindowEventArgs & e)824 void ListHeader::onSegmentSequenceChanged(WindowEventArgs& e)
825 {
826 fireEvent(EventSegmentSequenceChanged, e, EventNamespace);
827 }
828
829
830 /*************************************************************************
831 Handler called when a new segment is added to the header.
832 *************************************************************************/
onSegmentAdded(WindowEventArgs & e)833 void ListHeader::onSegmentAdded(WindowEventArgs& e)
834 {
835 fireEvent(EventSegmentAdded, e, EventNamespace);
836 }
837
838
839 /*************************************************************************
840 Handler called when a segment is removed from the header.
841 *************************************************************************/
onSegmentRemoved(WindowEventArgs & e)842 void ListHeader::onSegmentRemoved(WindowEventArgs& e)
843 {
844 fireEvent(EventSegmentRemoved, e, EventNamespace);
845 }
846
847
848 /*************************************************************************
849 Handler called then setting that controls the users ability to
850 modify the search column & direction changes.
851 *************************************************************************/
onSortSettingChanged(WindowEventArgs & e)852 void ListHeader::onSortSettingChanged(WindowEventArgs& e)
853 {
854 fireEvent(EventSortSettingChanged, e, EventNamespace);
855 }
856
857
858 /*************************************************************************
859 Handler called when the setting that controls the users ability to
860 drag and drop segments changes.
861 *************************************************************************/
onDragMoveSettingChanged(WindowEventArgs & e)862 void ListHeader::onDragMoveSettingChanged(WindowEventArgs& e)
863 {
864 fireEvent(EventDragMoveSettingChanged, e, EventNamespace);
865 }
866
867
868 /*************************************************************************
869 Handler called when the setting that controls the users ability t
870 size segments changes.
871 *************************************************************************/
onDragSizeSettingChanged(WindowEventArgs & e)872 void ListHeader::onDragSizeSettingChanged(WindowEventArgs& e)
873 {
874 fireEvent(EventDragSizeSettingChanged, e, EventNamespace);
875 }
876
877
878 /*************************************************************************
879 Handler called when the base rendering offset for the segments
880 (scroll position) changes.
881 *************************************************************************/
onSegmentOffsetChanged(WindowEventArgs & e)882 void ListHeader::onSegmentOffsetChanged(WindowEventArgs& e)
883 {
884 fireEvent(EventSegmentRenderOffsetChanged, e, EventNamespace);
885 }
886
887
888 /*************************************************************************
889 Handler method for when a segment is sized.
890 *************************************************************************/
segmentSizedHandler(const EventArgs & e)891 bool ListHeader::segmentSizedHandler(const EventArgs& e)
892 {
893 layoutSegments();
894
895 // Fire segment sized event.
896 WindowEventArgs args(((WindowEventArgs&)e).window);
897 onSegmentSized(args);
898
899 return true;
900 }
901
902
903 /*************************************************************************
904 Handler method for when a segment is dragged & dropped.
905 *************************************************************************/
segmentMovedHandler(const EventArgs & e)906 bool ListHeader::segmentMovedHandler(const EventArgs& e)
907 {
908 const Vector2f mousePos(getUnprojectedPosition(
909 getGUIContext().getMouseCursor().getPosition()));
910
911 // segment must be dropped within the window
912 if (isHit(mousePos))
913 {
914 // get mouse position as something local
915 Vector2f localMousePos(CoordConverter::screenToWindow(*this, mousePos));
916
917 // set up to allow for current offsets
918 float currwidth = -d_segmentOffset;
919
920 // calculate column where dragged segment was dropped
921 uint col;
922 for (col = 0; col < getColumnCount(); ++col)
923 {
924 currwidth += d_segments[col]->getPixelSize().d_width;
925
926 if (localMousePos.d_x < currwidth)
927 {
928 // this is the column, exit loop early
929 break;
930 }
931
932 }
933
934 // find original column for dragged segment.
935 ListHeaderSegment* seg = ((ListHeaderSegment*)((WindowEventArgs&)e).window);
936 uint curcol = getColumnFromSegment(*seg);
937
938 // move column
939 moveColumn(curcol, col);
940 }
941
942 return true;
943 }
944
945
946 /*************************************************************************
947 Hanlder for when a segment is clicked (to change sort segment / direction)
948 *************************************************************************/
segmentClickedHandler(const EventArgs & e)949 bool ListHeader::segmentClickedHandler(const EventArgs& e)
950 {
951 // double-check we allow this action
952 if (d_sortingEnabled)
953 {
954 ListHeaderSegment* seg = ((ListHeaderSegment*)((WindowEventArgs&)e).window);
955
956 // is this a new sort column?
957 if (d_sortSegment != seg)
958 {
959 d_sortDir = ListHeaderSegment::Descending;
960 setSortSegment(*seg);
961 }
962 // not a new segment, toggle current direction
963 else if (d_sortSegment)
964 {
965 ListHeaderSegment::SortDirection currDir = d_sortSegment->getSortDirection();
966
967 // set new direction based on the current value.
968 switch (currDir)
969 {
970 case ListHeaderSegment::None:
971 setSortDirection(ListHeaderSegment::Descending);
972 break;
973
974 case ListHeaderSegment::Ascending:
975 setSortDirection(ListHeaderSegment::Descending);
976 break;
977
978 case ListHeaderSegment::Descending:
979 setSortDirection(ListHeaderSegment::Ascending);
980 break;
981 }
982
983 }
984
985 // Notify that a segment has been clicked
986 WindowEventArgs args(((WindowEventArgs&)e).window);
987 onSegmentClicked(args);
988 }
989
990 return true;
991 }
992
993
994 /*************************************************************************
995 Handler called when a segment splitter is double-clicked.
996 *************************************************************************/
segmentDoubleClickHandler(const EventArgs & e)997 bool ListHeader::segmentDoubleClickHandler(const EventArgs& e)
998 {
999 WindowEventArgs args(((WindowEventArgs&)e).window);
1000 onSplitterDoubleClicked(args);
1001
1002 return true;
1003 }
1004
1005
1006 /*************************************************************************
1007 Handler called whenever the mouse moves while dragging a segment
1008 *************************************************************************/
segmentDragHandler(const EventArgs &)1009 bool ListHeader::segmentDragHandler(const EventArgs&)
1010 {
1011 // what we do here is monitor the position and scroll if we can when mouse is outside area.
1012
1013 // get mouse position as something local
1014 const Vector2f localMousePos(CoordConverter::screenToWindow(*this,
1015 getUnprojectedPosition(getGUIContext().
1016 getMouseCursor().getPosition())));
1017
1018 // scroll left?
1019 if (localMousePos.d_x < 0.0f)
1020 {
1021 if (d_segmentOffset > 0.0f)
1022 {
1023 setSegmentOffset(ceguimax(0.0f, d_segmentOffset - ScrollSpeed));
1024 }
1025 }
1026 // scroll right?
1027 else if (localMousePos.d_x >= d_pixelSize.d_width)
1028 {
1029 float maxOffset = ceguimax(0.0f, getTotalSegmentsPixelExtent() - d_pixelSize.d_width);
1030
1031 // if we have not scrolled to the limit
1032 if (d_segmentOffset < maxOffset)
1033 {
1034 // scroll, but never beyond the limit
1035 setSegmentOffset(ceguimin(maxOffset, d_segmentOffset + ScrollSpeed));
1036 }
1037
1038 }
1039
1040 return true;
1041 }
1042
1043
1044 /*************************************************************************
1045 Add ListHeader specific properties
1046 *************************************************************************/
addHeaderProperties(void)1047 void ListHeader::addHeaderProperties(void)
1048 {
1049 const String& propertyOrigin = WidgetTypeName;
1050
1051 CEGUI_DEFINE_PROPERTY(ListHeader, bool,
1052 "SortSettingEnabled", "Property to get/set the setting for for user modification of the sort column & direction. Value is either \"true\" or \"false\".",
1053 &ListHeader::setSortingEnabled, &ListHeader::isSortingEnabled, true /* TODO: Inconsistency */
1054 );
1055
1056 CEGUI_DEFINE_PROPERTY(ListHeader, bool,
1057 "ColumnsSizable", "Property to get/set the setting for user sizing of the column headers. Value is either \"true\" or \"false\".",
1058 &ListHeader::setColumnSizingEnabled, &ListHeader::isColumnSizingEnabled, true /* TODO: Inconsistency */
1059 );
1060
1061 CEGUI_DEFINE_PROPERTY(ListHeader, bool,
1062 "ColumnsMovable", "Property to get/set the setting for user moving of the column headers. Value is either \"true\" or \"false\".",
1063 &ListHeader::setColumnDraggingEnabled, &ListHeader::isColumnDraggingEnabled, true /* TODO: Inconsistency */
1064 );
1065
1066 CEGUI_DEFINE_PROPERTY(ListHeader, uint,
1067 "SortColumnID", "Property to get/set the current sort column (via ID code). Value is an unsigned integer number.",
1068 &ListHeader::setSortColumnFromID, &ListHeader::getSortSegmentID, 0 /* TODO: Inconsistency */
1069 );
1070
1071 CEGUI_DEFINE_PROPERTY(ListHeader, ListHeaderSegment::SortDirection,
1072 "SortDirection", "Property to get/set the sort direction setting of the header. Value is the text of one of the SortDirection enumerated value names.",
1073 &ListHeader::setSortDirection, &ListHeader::getSortDirection, ListHeaderSegment::None
1074 );
1075 }
1076
1077 /*************************************************************************
1078 Create new segment
1079 *************************************************************************/
createNewSegment(const String & name) const1080 ListHeaderSegment* ListHeader::createNewSegment(const String& name) const
1081 {
1082 if (d_windowRenderer != 0)
1083 {
1084 ListHeaderWindowRenderer* wr = (ListHeaderWindowRenderer*)d_windowRenderer;
1085 return wr->createNewSegment(name);
1086 }
1087 else
1088 {
1089 //return createNewSegment_impl(name);
1090 CEGUI_THROW(InvalidRequestException(
1091 "This function must be implemented by the window renderer module"));
1092 }
1093 }
1094
1095 /*************************************************************************
1096 Destroy segment
1097 *************************************************************************/
destroyListSegment(ListHeaderSegment * segment) const1098 void ListHeader::destroyListSegment(ListHeaderSegment* segment) const
1099 {
1100 if (d_windowRenderer != 0)
1101 {
1102 ListHeaderWindowRenderer* wr = (ListHeaderWindowRenderer*)d_windowRenderer;
1103 wr->destroyListSegment(segment);
1104 }
1105 else
1106 {
1107 //return destroyListSegment_impl(segment);
1108 CEGUI_THROW(InvalidRequestException(
1109 "This function must be implemented by the window renderer module"));
1110 }
1111 }
1112
1113 } // End of CEGUI namespace section
1114