File: GroupCycle.cpp

package info (click to toggle)
darkradiant 3.9.0-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 41,080 kB
  • sloc: cpp: 264,743; ansic: 10,659; python: 1,852; xml: 1,650; sh: 92; makefile: 21
file content (126 lines) | stat: -rw-r--r-- 2,754 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
#include "GroupCycle.h"

#include "iselectable.h"
#include "selectionlib.h"
#include "iscenegraph.h"

namespace selection {

namespace algorithm {

	/** greebo: This helper visitor populates the given targetList with
	 *          all found child selectables under the given node.
	 */
	class ChildNodeFinder :
		public scene::NodeVisitor
	{
		NodeVector& _targetList;
	public:
		ChildNodeFinder(NodeVector& targetList) :
			_targetList(targetList)
		{}

		bool pre(const scene::INodePtr& node) {
			ISelectablePtr selectable = scene::node_cast<ISelectable>(node);

			// If a visible selectable was found and the path depth is appropriate, add it
			if (selectable != NULL && node->visible()) {
				_targetList.push_back(node);
			}

			return true;
		}
	};

} // namespace algorithm

GroupCycle::GroupCycle() :
	_index(0),
	_updateActive(false)
{
	GlobalSelectionSystem().addObserver(this);
	rescanSelection();
}

void GroupCycle::selectionChanged(const scene::INodePtr& node, bool isComponent) {
	// greebo: Only rescan the selection for non-component changes, otherwise the list
	// will get cleared as soon as the face dragresize manipulator gets active
	if (!isComponent) {
		rescanSelection();
	}
}

void GroupCycle::rescanSelection() {
	if (_updateActive) {
		return;
	}

	const SelectionInfo& info = GlobalSelectionSystem().getSelectionInfo();

	_list.clear();
	_index = 0;

	if (info.totalCount == 1 && info.entityCount == 1) {
		const scene::INodePtr& node = GlobalSelectionSystem().ultimateSelected();

		algorithm::ChildNodeFinder finder(_list);
		node->traverse(finder);
	}
}

void GroupCycle::updateSelection() {
	_updateActive = true;

	// Do some sanity checking before we run into crashes
	if (_index >= 0 && _index < static_cast<int>(_list.size())) {
		for (std::size_t i = 0; i < _list.size(); i++) {
			Node_setSelected(_list[i], false);
		}

		Node_setSelected(_list[_index], true);
	}

	SceneChangeNotify();

	_updateActive = false;
}

void GroupCycle::doCycleForward() {
	if (_list.size() > 1) {
		// Increase the index and wrap around at the list end
		_index = (_index+1) % static_cast<int>(_list.size());

		// Select the new candidate
		updateSelection();
	}
}

void GroupCycle::doCycleBackward() {
	if (_list.size() > 1) {
		// Decrease the index and wrap around, if necessary
		_index--;

		if (_index < 0) {
			_index += static_cast<int>(_list.size());
		}

		// Select the new candidate
		updateSelection();
	}
}

void GroupCycle::cycleBackward(const cmd::ArgumentList& args) {
	Instance().doCycleBackward();
}

void GroupCycle::cycleForward(const cmd::ArgumentList& args) {
	Instance().doCycleForward();
}

GroupCycle& GroupCycle::Instance() {
	static GroupCycle _instance;

	return _instance;
}

} // namespace selection