1 /*
2 Copyright (C) 2001-2006, William Joseph.
3 All Rights Reserved.
4
5 This file is part of GtkRadiant.
6
7 GtkRadiant is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
11
12 GtkRadiant is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
16
17 You should have received a copy of the GNU General Public License
18 along with GtkRadiant; if not, write to the Free Software
19 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
20 */
21
22 #if !defined (INCLUDED_SELECTIONLIB_H)
23 #define INCLUDED_SELECTIONLIB_H
24
25 #include "iselection.h"
26 #include "selectable.h"
27 #include "generic/callback.h"
28 #include "scenelib.h"
29 #include <stdlib.h>
30
31 /** greebo: A structure containing information about the current
32 * Selection. An instance of this is maintained by the
33 * RadiantSelectionSystem, and a const reference can be
34 * retrieved via the according getSelectionInfo() method.
35 */
36 class SelectionInfo {
37
38 public:
39 int totalCount; // number of selected items
40 int brushCount; // -- " -- brushes
41 int entityCount; // -- " -- entities
42
SelectionInfo()43 SelectionInfo () :
44 totalCount(0),
45 brushCount(0),
46 entityCount(0)
47 {
48 }
49
50 // Zeroes all the counters
clear()51 void clear ()
52 {
53 totalCount = 0;
54 brushCount = 0;
55 entityCount = 0;
56 }
57 };
58
59
60 namespace selection
61 {
62
63 /**
64 * The selection "WorkZone" defines the bounds of the most
65 * recent selection. On each selection, the workzone is
66 * recalculated, nothing happens on deselection.
67 */
68 struct WorkZone
69 {
70 // The corner points defining the selection workzone
71 Vector3 min;
72 Vector3 max;
73
74 // The bounds of the selection workzone (equivalent to min/max)
75 AABB bounds;
76
WorkZoneWorkZone77 WorkZone() :
78 min(-64,-64,-64),
79 max(64,64,64),
80 bounds(AABB::createFromMinMax(min, max))
81 {}
82 };
83
84 } // namespace selection
85
86 class SelectableBool: public Selectable
87 {
88 bool m_selected;
89 public:
SelectableBool()90 SelectableBool () :
91 m_selected(false)
92 {
93 }
94
95 void setSelected (bool select = true)
96 {
97 m_selected = select;
98 }
isSelected()99 bool isSelected () const
100 {
101 return m_selected;
102 }
103
invertSelected()104 void invertSelected() {
105 m_selected = !m_selected;
106 }
107 };
108
109 // greebo: A selectable with an attached callback function that is called upon selection (change)
110 class ObservedSelectable: public Selectable
111 {
112 SelectionChangeCallback m_onchanged;
113 bool m_selected;
114 public:
ObservedSelectable(const SelectionChangeCallback & onchanged)115 ObservedSelectable (const SelectionChangeCallback& onchanged) :
116 m_onchanged(onchanged), m_selected(false)
117 {
118 }
ObservedSelectable(const ObservedSelectable & other)119 ObservedSelectable (const ObservedSelectable& other) :
120 Selectable(other), m_onchanged(other.m_onchanged), m_selected(false)
121 {
122 setSelected(other.isSelected());
123 }
124 ObservedSelectable& operator= (const ObservedSelectable& other)
125 {
126 setSelected(other.isSelected());
127 return *this;
128 }
~ObservedSelectable()129 ~ObservedSelectable ()
130 {
131 setSelected(false);
132 }
133
setSelected(bool select)134 void setSelected (bool select)
135 {
136 if (select ^ m_selected) {
137 m_selected = select;
138
139 m_onchanged(*this);
140 }
141 }
isSelected()142 bool isSelected () const
143 {
144 return m_selected;
145 }
146
invertSelected()147 void invertSelected() {
148 setSelected(!isSelected());
149 }
150 };
151
152 class SelectableInstance: public scene::Instance, public Selectable
153 {
154 ObservedSelectable m_selectable;
155 public:
156
SelectableInstance(const scene::Path & path,scene::Instance * parent)157 SelectableInstance (const scene::Path& path, scene::Instance* parent) :
158 Instance(path, parent), m_selectable(SelectedChangedCaller(*this))
159 {
160 }
161
getSelectable()162 Selectable& getSelectable ()
163 {
164 return m_selectable;
165 }
getSelectable()166 const Selectable& getSelectable () const
167 {
168 return m_selectable;
169 }
170
selectedChanged(const Selectable & selectable)171 void selectedChanged (const Selectable& selectable)
172 {
173 GlobalSelectionSystem().onSelectedChanged(*this, selectable);
174
175 Instance::selectedChanged();
176 }
177 typedef MemberCaller1<SelectableInstance, const Selectable&, &SelectableInstance::selectedChanged>
178 SelectedChangedCaller;
179
180 /** greebo: Selectable implementation
181 */
setSelected(bool select)182 virtual void setSelected(bool select) {
183 m_selectable.setSelected(select);
184 }
185
isSelected()186 virtual bool isSelected() const {
187 return m_selectable.isSelected();
188 }
189
invertSelected()190 virtual void invertSelected() {
191 m_selectable.invertSelected();
192 }
193 };
194
195 template<typename Iterator>
range_check(Iterator start,Iterator finish,Iterator iter)196 inline bool range_check (Iterator start, Iterator finish, Iterator iter)
197 {
198 for (; start != finish; ++start) {
199 if (start == iter) {
200 return true;
201 }
202 }
203 return false;
204 }
205
206 #include <list>
207
208 template<typename Selected>
209 class SelectionList
210 {
211 typedef std::list<Selected*> List;
212 List m_selection;
213 public:
214 typedef typename List::iterator iterator;
215 typedef typename List::const_iterator const_iterator;
216
begin()217 iterator begin ()
218 {
219 return m_selection.begin();
220 }
begin()221 const_iterator begin () const
222 {
223 return m_selection.begin();
224 }
end()225 iterator end ()
226 {
227 return m_selection.end();
228 }
end()229 const_iterator end () const
230 {
231 return m_selection.end();
232 }
empty()233 bool empty () const
234 {
235 return m_selection.empty();
236 }
size()237 std::size_t size () const
238 {
239 return m_selection.size();
240 }
back()241 Selected& back ()
242 {
243 return *m_selection.back();
244 }
back()245 Selected& back () const
246 {
247 return *m_selection.back();
248 }
append(Selected & selected)249 void append (Selected& selected)
250 {
251 m_selection.push_back(&selected);
252 }
erase(Selected & selected)253 void erase (Selected& selected)
254 {
255 typename List::reverse_iterator i = std::find(m_selection.rbegin(), m_selection.rend(), &selected);
256 ASSERT_MESSAGE(i != m_selection.rend(), "selection-tracking error");
257 ASSERT_MESSAGE(range_check(m_selection.begin(), m_selection.end(), --i.base()), "selection-tracking error");
258 m_selection.erase(--i.base());
259 }
260 };
261
262 class OccludeSelector : public Selector
263 {
264 SelectionIntersection& _bestIntersection;
265 bool& _occluded;
266 public:
OccludeSelector(SelectionIntersection & bestIntersection,bool & occluded)267 OccludeSelector(SelectionIntersection& bestIntersection, bool& occluded) :
268 _bestIntersection(bestIntersection),
269 _occluded(occluded)
270 {
271 _occluded = false;
272 }
273
pushSelectable(Selectable & selectable)274 void pushSelectable(Selectable& selectable) {}
popSelectable()275 void popSelectable() {}
276
addIntersection(const SelectionIntersection & intersection)277 void addIntersection(const SelectionIntersection& intersection) {
278 if (SelectionIntersection_closer(intersection, _bestIntersection)) {
279 _bestIntersection = intersection;
280 _occluded = true;
281 }
282 }
283 }; // class OccludeSelector
284
285 #endif
286