// objlibwin.cpp -- the object library window // // Written by Frederic Bouvier, started April 2002. // // Copyright (C) 2001 Frederic Bouvier - fredb@users.sourceforge.net // // This program 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. // // This program 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 this program; if not, write to the Free Software // Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. // // $Id: objlibwin.cpp,v 1.24 2005/06/11 08:31:01 fredb2 Exp $ #ifdef _MSC_VER #pragma warning( disable : 4786 4355 4800 ) #endif #ifdef HAVE_CONFIG_H #include "config.h" #endif #include "objlibwin.hpp" #include #include #include #include #include #include #include #include #include #include #include "Fl_Plib/Fl_Plib.h" #include #define OBJ_LIB_FILE_NAME ".fgsdobjlib" #include "folder1.xpm" #include "folder2.xpm" #include "file.xpm" static void addNodeToTree( Flu_Tree_Browser *tree, SGPropertyNode *root, const std::string &rName ) { std::deque nodes; std::deque names; nodes.push_back( root ); names.push_back( rName ); while ( nodes.size() > 0 ) { SGPropertyNode *node = nodes.front(); nodes.pop_front(); std::string name = names.front(); names.pop_front(); std::vector cFolder = node->getChildren( "folder" ); size_t i; size_t nb = cFolder.size(); for ( i = 0; i < nb; i++ ) { SGPropertyNode_ptr n = cFolder[ i ]; std::string nm = n->getStringValue( "name" ); std::string path = name + "/" + nm; nodes.push_back( n ); names.push_back( path ); path += "/"; Flu_Tree_Browser::Node *item = tree->add( path.c_str() ); item->user_data( n ); } std::vector cModel = node->getChildren( "model" ); nb = cModel.size(); for ( i = 0; i < nb; i++ ) { SGPropertyNode_ptr n = cModel[ i ]; std::string nm = n->getStringValue( "name" ); std::string path = name + "/" + nm; Flu_Tree_Browser::Node *item = tree->add( path.c_str() ); item->user_data( n ); } } } FGSD_ObjectLibraryWindow::FGSD_ObjectLibraryWindow( int w, int h ) : _modified( false ) { std::string fileName; char *home = getenv( "HOME" ); if ( home != 0 ) { fileName = home; if ( fileName[ fileName.size() - 1 ] != '/' ) fileName += '/'; } fileName += OBJ_LIB_FILE_NAME; struct stat buffer; if ( stat( fileName.c_str(), &buffer ) == 0 ) { readProperties( fileName, &_library ); } else { SGPropertyNode *nm = _library.getChild( "name", 0, true ); nm->setStringValue( "root" ); nm->setAttributes( SGPropertyNode::READ | SGPropertyNode::WRITE | SGPropertyNode::ARCHIVE ); } _window = new FGSD_Window( w, h, "Object Library" ); _window->begin(); _tools = new Fl_Group( 0, 0, w, 40 ); _tools->begin(); _input = new Fl_Input( 5, 5, 200, 30 ); _addFolder = new Fl_Button( 210, 5, 30, 30, "Af" ); _addFolder->tooltip( "Add a new folder" ); _addFolder->callback( FGSD_ObjectLibraryWindow::add_folder_cb, this ); _renFolder = new Fl_Button( 240, 5, 30, 30, "Rf" ); _renFolder->tooltip( "Rename a folder" ); _renFolder->callback( FGSD_ObjectLibraryWindow::ren_folder_cb, this ); _cut = new Fl_Button( 280, 5, 30, 30, "Cut" ); _cut->tooltip( "Cut" ); _cut->callback( FGSD_ObjectLibraryWindow::cut_cb, this ); _paste = new Fl_Button( 310, 5, 30, 30, "Pst" ); _paste->tooltip( "Paste" ); _paste->callback( FGSD_ObjectLibraryWindow::paste_cb, this ); _addModel = new Fl_Button( 350, 5, 30, 30, "Am" ); _addModel->tooltip( "Add a new model" ); _addModel->callback( FGSD_ObjectLibraryWindow::add_model_cb, this ); _renModel = new Fl_Button( 380, 5, 30, 30, "Rm" ); _renModel->tooltip( "Rename a model" ); _renModel->callback( FGSD_ObjectLibraryWindow::ren_model_cb, this ); _addTexture = new Fl_Button( 410, 5, 30, 30, "At" ); _addTexture->tooltip( "Add a texture to a model" ); _addTexture->callback( FGSD_ObjectLibraryWindow::add_texture_cb, this ); Fl_Box *b = new Fl_Box( 475, 0, w - 580, 40 ); _select = new Fl_Button( w - 100, 5, 50, 30, "Select" ); _select->callback( FGSD_ObjectLibraryWindow::select_cb, this ); _quit = new Fl_Button( w - 45, 5, 40, 30, "Quit" ); _quit->callback( &FGSD_ObjectLibraryWindow::close_cb, this ); _tools->resizable( *b ); _tools->end(); _tile = new Fl_Tile( 0, 40, w, h - 40 ); _tile->begin(); int x = w > 300 ? 200 : w / 2; _tree = new Flu_Tree_Browser( 0, 40, x, h - 40, "Root" ); _tree->always_open( true ); _tree->callback( &FGSD_ObjectLibraryWindow::tree_cb, this ); _viewGroup = new Fl_Group( x, 40, w - x, h - 40 ); _viewGroup->begin(); _viewer = new Fl_Plib( x, 40, w - x, h - 40 ); _viewGroup->resizable( _viewer ); _viewGroup->end(); _tile->end(); _window->resizable( _tile ); _window->callback( close_cb, (void *)this ); _window->end(); _tree->get_root()->user_data( &_library ); addNodeToTree( _tree, &_library, "" ); } FGSD_ObjectLibraryWindow::~FGSD_ObjectLibraryWindow() { delete _window; } bool FGSD_ObjectLibraryWindow::checkModified() { if ( _modified ) { std::string fileName; char *home = getenv( "HOME" ); if ( home != 0 ) { fileName = home; if ( fileName[ fileName.size() - 1 ] != '/' ) fileName += '/'; } fileName += OBJ_LIB_FILE_NAME; setArchiveBit( &_library ); writeProperties( fileName, &_library ); _modified = false; } return true; } void FGSD_ObjectLibraryWindow::close_cb(Fl_Widget *o, void *v) { static_cast( v )->close_cb( o, false ); } void FGSD_ObjectLibraryWindow::select_cb(Fl_Widget *o, void *v) { static_cast( v )->close_cb( o, true ); } void FGSD_ObjectLibraryWindow::close_cb(Fl_Widget *, bool __ok ) { bool close = checkModified(); if ( close ) { SGPropertyNode *cNode = _currentNode; if ( !__ok || _mode != Select || ( cNode && std::string( cNode->getName() ) == "model" ) ) _window->hide(); if ( __ok ) _window->set_value(); else _window->clear_value(); } } void FGSD_ObjectLibraryWindow::add_folder_cb( Fl_Widget *, void *v ) { static_cast( v )->addFolder(); } void FGSD_ObjectLibraryWindow::ren_folder_cb( Fl_Widget *, void *v ) { static_cast( v )->renFolder(); } void FGSD_ObjectLibraryWindow::cut_cb( Fl_Widget *, void *v ) { static_cast( v )->cut(); } void FGSD_ObjectLibraryWindow::paste_cb( Fl_Widget *, void *v ) { static_cast( v )->paste(); } void FGSD_ObjectLibraryWindow::add_model_cb( Fl_Widget *, void *v ) { static_cast( v )->addModel(); } void FGSD_ObjectLibraryWindow::ren_model_cb( Fl_Widget *, void *v ) { static_cast( v )->renModel(); } void FGSD_ObjectLibraryWindow::add_texture_cb( Fl_Widget *, void *v ) { static_cast( v )->addTexture(); } void FGSD_ObjectLibraryWindow::tree_cb( Fl_Widget *, void *v ) { static_cast( v )->tree(); } static std::string getFullPath( SGPropertyNode *n ) { if ( n == 0 || n->getParent() == 0 ) return ""; else return getFullPath( n->getParent() ) + "/" + n->getStringValue( "name" ); } void FGSD_ObjectLibraryWindow::addFolder() { SGPropertyNode *cNode = _currentNode; if ( cNode && ( std::string( cNode->getName() ) == "folder" || std::string( cNode->getName() ) == "" ) ) { const char *val = _input->value(); if ( val && val[0] ) { size_t next = 0; std::string name( val ); std::vector children = cNode->getChildren( "folder" ); size_t nb = children.size(); size_t i; for ( i = 0; i < nb; i++ ) { SGPropertyNode *node = children[ i ]; SGPropertyNode *nm = node->getChild( "name" ); if ( nm && name == nm->getStringValue() ) return; size_t ind = node->getIndex(); if ( next <= ind ) next = ind + 1; } children = cNode->getChildren( "model" ); nb = children.size(); for ( i = 0; i < nb; i++ ) { SGPropertyNode *node = children[ i ]; SGPropertyNode *nm = node->getChild( "name" ); if ( nm && name == nm->getStringValue() ) return; } SGPropertyNode *node = cNode->getChild( "folder", next, true ); if ( node ) { node->setAttributes( SGPropertyNode::READ | SGPropertyNode::WRITE | SGPropertyNode::ARCHIVE ); SGPropertyNode *nm = node->getChild( "name", 0, true ); nm->setAttributes( SGPropertyNode::READ | SGPropertyNode::WRITE | SGPropertyNode::ARCHIVE ); nm->setStringValue( val ); std::string path = getFullPath( node ) + "/"; Flu_Tree_Browser::Node *n = _tree->add( path.c_str() ); n->user_data( node ); _tree->redraw(); _modified = true; } } } } void FGSD_ObjectLibraryWindow::renFolder() { SGPropertyNode *cNode = _currentNode; if ( cNode && std::string( cNode->getName() ) == "folder" ) { int index = cNode->getIndex(); SGPropertyNode *parent = cNode->getParent(); const char *val = _input->value(); if ( val && val[0] ) { int next = 0; std::string name( val ); std::vector children = parent->getChildren( "folder" ); size_t nb = children.size(); size_t i; for ( i = 0; i < nb; i++ ) { SGPropertyNode *node = children[ i ]; SGPropertyNode *nm = node->getChild( "name" ); if ( nm && name == nm->getStringValue() && node->getIndex() != index ) return; int ind = node->getIndex(); if ( next <= ind ) next = ind + 1; } children = parent->getChildren( "model" ); nb = children.size(); for ( i = 0; i < nb; i++ ) { SGPropertyNode *node = children[ i ]; SGPropertyNode *nm = node->getChild( "name" ); if ( nm && name == nm->getStringValue() ) return; } std::string path = getFullPath( cNode ) + "/"; Flu_Tree_Browser::Node *n = _tree->find( path.c_str() ); n->label( val ); SGPropertyNode *nm = cNode->getChild( "name" ); std::string oldName = nm->getStringValue(); nm->setStringValue( val ); _input->value( oldName.c_str() ); _tree->redraw(); _modified = true; } } } void FGSD_ObjectLibraryWindow::cut() { SGPropertyNode *&cNode = _currentNode; if ( cNode ) { std::string path = getFullPath( cNode ) + "/"; SGPropertyNode *node = cNode; cNode = node->getParent(); if ( cNode ) { Flu_Tree_Browser::Node *n = _tree->find( path.c_str() ); if ( n ) { _cutNode = cNode->removeChild( node->getName(), node->getIndex(), false ); _tree->remove( n ); _tree->redraw(); _modified = true; } else cNode = node; } else cNode = node; } } void FGSD_ObjectLibraryWindow::copyNode( SGPropertyNode *__dst, SGPropertyNode *__src ) { __dst->setAttributes( __src->getAttributes() ); SGPropertyNode::Type type = __src->getType(); switch ( type ) { case SGPropertyNode::NONE: break; case SGPropertyNode::ALIAS: // Problem here break; case SGPropertyNode::BOOL: __dst->setBoolValue( __src->getBoolValue() ); break; case SGPropertyNode::INT: __dst->setIntValue( __src->getIntValue() ); break; case SGPropertyNode::LONG: __dst->setLongValue( __src->getLongValue() ); break; case SGPropertyNode::FLOAT: __dst->setFloatValue( __src->getFloatValue() ); break; case SGPropertyNode::DOUBLE: __dst->setDoubleValue( __src->getDoubleValue() ); break; case SGPropertyNode::STRING: __dst->setStringValue( __src->getStringValue() ); break; case SGPropertyNode::UNSPECIFIED: __dst->setUnspecifiedValue( __src->getStringValue() ); break; } size_t nb = __src->nChildren(); for ( size_t i = 0; i < nb; i++ ) { SGPropertyNode *s = __src->getChild( i ); SGPropertyNode *d = __dst->getChild( s->getName(), s->getIndex(), true ); copyNode( d, s ); } } void FGSD_ObjectLibraryWindow::setArchiveBit( SGPropertyNode *__dst ) { __dst->setAttribute( SGPropertyNode::ARCHIVE, true ); size_t nb = __dst->nChildren(); for ( size_t i = 0; i < nb; i++ ) { SGPropertyNode *d = __dst->getChild( i ); setArchiveBit( d ); } } void FGSD_ObjectLibraryWindow::paste() { SGPropertyNode *cNode = _currentNode; if ( cNode && ( std::string( cNode->getName() ) == "folder" || std::string( cNode->getName() ) == "" ) ) { std::string type = _cutNode->getName(); int index = _cutNode->getIndex(); SGPropertyNode *node = cNode->getChild( type.c_str(), index, true ); copyNode( node, _cutNode ); std::string path = getFullPath( node ); addNodeToTree( _tree, node, path ); path += "/"; _tree->add( path.c_str() )->user_data( node ); _tree->redraw(); _modified = true; } } void FGSD_ObjectLibraryWindow::addModel() { SGPropertyNode *cNode = _currentNode; if ( cNode && ( std::string( cNode->getName() ) == "folder" || std::string( cNode->getName() ) == "" ) ) { const char *val = _input->value(); if ( val && val[0] ) { const char *fileName = flu_file_chooser( "Select a 3D model ...", "*", 0 ); if ( fileName ) { size_t next = 0; std::string name( val ); std::vector children = cNode->getChildren( "folder" ); size_t nb = children.size(); size_t i; for ( i = 0; i < nb; i++ ) { SGPropertyNode *node = children[ i ]; SGPropertyNode *nm = node->getChild( "name" ); if ( nm && name == nm->getStringValue() ) return; } children = cNode->getChildren( "model" ); nb = children.size(); for ( i = 0; i < nb; i++ ) { SGPropertyNode *node = children[ i ]; SGPropertyNode *nm = node->getChild( "name" ); if ( nm && name == nm->getStringValue() ) return; size_t ind = node->getIndex(); if ( next <= ind ) next = ind + 1; } SGPropertyNode *node = cNode->getChild( "model", next, true ); if ( node ) { node->setAttributes( SGPropertyNode::READ | SGPropertyNode::WRITE | SGPropertyNode::ARCHIVE ); SGPropertyNode *nm = node->getChild( "name", 0, true ); nm->setAttributes( SGPropertyNode::READ | SGPropertyNode::WRITE | SGPropertyNode::ARCHIVE ); nm->setStringValue( val ); nm = node->getChild( "path", 0, true ); nm->setAttributes( SGPropertyNode::READ | SGPropertyNode::WRITE | SGPropertyNode::ARCHIVE ); nm->setStringValue( fileName ); std::string path = getFullPath( node ); Flu_Tree_Browser::Node *n = _tree->add( path.c_str() ); n->user_data( node ); _tree->redraw(); _modified = true; } } } } } void FGSD_ObjectLibraryWindow::renModel() { SGPropertyNode *cNode = _currentNode; if ( cNode && std::string( cNode->getName() ) == "model" ) { int index = cNode->getIndex(); SGPropertyNode *parent = cNode->getParent(); const char *val = _input->value(); if ( val && val[0] ) { int next = 0; std::string name( val ); std::vector children = parent->getChildren( "folder" ); size_t nb = children.size(); size_t i; for ( i = 0; i < nb; i++ ) { SGPropertyNode *node = children[ i ]; SGPropertyNode *nm = node->getChild( "name" ); if ( nm && name == nm->getStringValue() ) return; } children = parent->getChildren( "model" ); nb = children.size(); for ( i = 0; i < nb; i++ ) { SGPropertyNode *node = children[ i ]; SGPropertyNode *nm = node->getChild( "name" ); if ( nm && name == nm->getStringValue() && node->getIndex() != index ) return; int ind = node->getIndex(); if ( next <= ind ) next = ind + 1; } std::string path = getFullPath( cNode ); Flu_Tree_Browser::Node *n = _tree->find( path.c_str() ); n->label( val ); SGPropertyNode *nm = cNode->getChild( "name" ); std::string oldName = nm->getStringValue(); nm->setStringValue( val ); _input->value( oldName.c_str() ); _tree->redraw(); _modified = true; } } } void FGSD_ObjectLibraryWindow::addTexture() { SGPropertyNode *cNode = _currentNode; if ( cNode && std::string( cNode->getName() ) == "model" ) { const char *fileName = flu_file_chooser( "Select texture ...", "*", 0 ); if ( fileName ) { int next = 0; std::vector children = cNode->getChildren( "texture" ); size_t nb = children.size(); for ( size_t i = 0; i < nb; i++ ) { SGPropertyNode *node = children[ i ]; int ind = node->getIndex(); if ( next <= ind ) next = ind + 1; } SGPropertyNode *nm = cNode->getChild( "texture", next, true ); nm->setAttributes( SGPropertyNode::READ | SGPropertyNode::WRITE | SGPropertyNode::ARCHIVE ); nm->setStringValue( fileName ); _tree->redraw(); _modified = true; } } } void FGSD_ObjectLibraryWindow::tree() { int reason = _tree->callback_reason(); if ( reason == FLU_SELECTED ) { Flu_Tree_Browser::Node *n = _tree->callback_node(); _currentNode = static_cast( n->user_data() ); _viewer->clear(); SGPropertyNode *p = _currentNode->getChild( "path" ); if ( p ) { _window->cursor( FL_CURSOR_WAIT ); const char *path = p->getStringValue(); _viewer->init(); _viewer->load( path ); _window->cursor( FL_CURSOR_DEFAULT ); } _viewer->redraw(); } } std::string FGSD_ObjectLibraryWindow::getCurrentModel() const { std::string res; SGPropertyNode *cNode = _currentNode; if ( cNode && std::string( cNode->getName() ) == "model" ) { SGPropertyNode *pnode = cNode->getChild( "path" ); res = pnode->getStringValue(); } return res; } std::vector FGSD_ObjectLibraryWindow::getTexturesForCurrentModel() const { std::vector res; SGPropertyNode *cNode = _currentNode; if ( cNode && std::string( cNode->getName() ) == "model" ) { std::vector children = cNode->getChildren( "texture" ); size_t nb = children.size(); for ( size_t i = 0; i < nb; i++ ) res.push_back( children[ i ]->getStringValue() ); } return res; } void FGSD_ObjectLibraryWindow::show( /* int argc, char **argv */ ) { if ( _mode == Edit ) _select->deactivate(); else _select->activate(); if ( _window ) _window->show( /* argc, argv */ ); } bool FGSD_ObjectLibraryWindow::visible() { bool ret = false; if ( _window ) ret = _window->visible(); return ret; } bool FGSD_ObjectLibraryWindow::exec(const Fl_Window* w, bool grab) { if ( _mode == Edit ) _select->deactivate(); else _select->activate(); bool ret = false; if ( _window ) ret = _window->exec( /*w , grab*/ ); return ret; }