+static void clean_desc_text(char *dest, const char *src);
+
+
+ExhibitSlot::ExhibitSlot(Exhibit *ex)
+{
+ this->ex = 0;
+
+ init(ex);
+}
+
+ExhibitSlot::~ExhibitSlot()
+{
+ detach_exhibit();
+
+ SceneNode *par = node.get_parent();
+ if(par) {
+ par->remove_child(&node);
+
+ while(node.get_num_children()) {
+ par->add_child(node.get_child(0));
+ }
+ }
+}
+
+
+void ExhibitSlot::init(Exhibit *ex)
+{
+ std::string node_name = "ExhibitSlot";
+ if(ex) {
+ if(ex->get_name()) {
+ node_name += std::string(":") + std::string(ex->get_name());
+ }
+
+ if(ex->node) {
+ if(ex->node->get_parent()) {
+ ex->node->get_parent()->add_child(&node);
+ }
+ node.set_position(ex->node->get_node_position());
+ node.set_rotation(ex->node->get_node_rotation());
+ ex->node->set_position(Vec3(0, 0, 0));
+ ex->node->set_rotation(Quat::identity);
+ }
+ attach_exhibit(ex);
+ } else {
+ this->ex = 0;
+ }
+
+ node.set_name(node_name.c_str());
+}
+
+bool ExhibitSlot::empty() const
+{
+ return ex == 0;
+}
+
+Exhibit *ExhibitSlot::get_exhibit() const
+{
+ return ex;
+}
+
+/* In the process of attaching the exhibit, we also steal the exhibit's node
+ * from its previous parent, and reparent it to the slot's node. As the slot's
+ * node itself should have been made a child of the original parent of the
+ * exhibit during init(), the initial state is we're interjecting a null node in
+ * the scene graph between the exhibit and its original parent.
+ *
+ * Attaching to a slot, implicitly detaches from the previous slot.
+ */
+bool ExhibitSlot::attach_exhibit(Exhibit *ex, ExSlotAttachMode mode)
+{
+ if(!ex || this->ex) return false;
+
+ if(ex->prev_slot && ex->prev_slot->ex == ex) {
+ ex->prev_slot->detach_exhibit();
+ }
+
+ if(mode != EXSLOT_ATTACH_TRANSIENT) {
+ ex->prev_slot = this;
+ }
+
+ node.add_child(ex->node);
+ this->ex = ex;
+ return true;
+}
+
+bool ExhibitSlot::detach_exhibit()
+{
+ if(!ex) return false;
+
+ node.remove_child(ex->node);
+ ex = 0;
+ return true;
+}
+
+
+// ---- exhibit manager implementation ----