/* Copyright (C) 2001-2006, William Joseph. All Rights Reserved. This file is part of GtkRadiant. GtkRadiant is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. GtkRadiant is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with GtkRadiant; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ #if !defined (INCLUDED_SELECTIONLIB_H) #define INCLUDED_SELECTIONLIB_H #include "iselection.h" #include "generic/callback.h" #include "scenelib.h" #include class SelectableBool : public Selectable { bool m_selected; public: SelectableBool() : m_selected(false) {} void setSelected(bool select = true) { m_selected = select; } bool isSelected() const { return m_selected; } }; class ObservedSelectable : public Selectable { SelectionChangeCallback m_onchanged; bool m_selected; public: ObservedSelectable(const SelectionChangeCallback& onchanged) : m_onchanged(onchanged), m_selected(false) { } ObservedSelectable(const ObservedSelectable& other) : Selectable(other), m_onchanged(other.m_onchanged), m_selected(false) { setSelected(other.isSelected()); } ObservedSelectable& operator=(const ObservedSelectable& other) { setSelected(other.isSelected()); return *this; } ~ObservedSelectable() { setSelected(false); } void setSelected(bool select) { if(select ^ m_selected) { m_selected = select; m_onchanged(*this); } } bool isSelected() const { return m_selected; } }; class SelectableInstance : public scene::Instance { class TypeCasts { InstanceTypeCastTable m_casts; public: TypeCasts() { InstanceContainedCast::install(m_casts); } InstanceTypeCastTable& get() { return m_casts; } }; ObservedSelectable m_selectable; public: typedef LazyStatic StaticTypeCasts; SelectableInstance(const scene::Path& path, scene::Instance* parent, void* instance = 0, InstanceTypeCastTable& casts = StaticTypeCasts::instance().get()) : Instance(path, parent, instance != 0 ? instance : this, casts), m_selectable(SelectedChangedCaller(*this)) { } Selectable& get(NullType) { return m_selectable; } Selectable& getSelectable() { return m_selectable; } const Selectable& getSelectable() const { return m_selectable; } void selectedChanged(const Selectable& selectable) { GlobalSelectionSystem().getObserver(SelectionSystem::ePrimitive)(selectable); GlobalSelectionSystem().onSelectedChanged(*this, selectable); Instance::selectedChanged(); } typedef MemberCaller1 SelectedChangedCaller; }; template inline bool range_check(Iterator start, Iterator finish, Iterator iter) { for(;start != finish; ++start) { if(start == iter) { return true; } } return false; } #include template class SelectionList { typedef std::list List; List m_selection; public: typedef typename List::iterator iterator; typedef typename List::const_iterator const_iterator; iterator begin() { return m_selection.begin(); } const_iterator begin() const { return m_selection.begin(); } iterator end() { return m_selection.end(); } const_iterator end() const { return m_selection.end(); } bool empty() const { return m_selection.empty(); } std::size_t size() const { return m_selection.size(); } Selected& back() { return *m_selection.back(); } Selected& back() const { return *m_selection.back(); } void append(Selected& selected) { m_selection.push_back(&selected); } void erase(Selected& selected) { typename List::reverse_iterator i = std::find(m_selection.rbegin(), m_selection.rend(), &selected); ASSERT_MESSAGE(i != m_selection.rend(), "selection-tracking error"); ASSERT_MESSAGE(range_check(m_selection.begin(), m_selection.end(), --i.base()), "selection-tracking error"); m_selection.erase(--i.base()); } }; #endif