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