// mainwin.cpp -- main window // // Written by Frederic Bouvier, started October 2001. // // 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: mainwin.cpp,v 1.137 2005/06/09 22:33:58 fredb2 Exp $ #ifdef _MSC_VER #pragma warning( disable : 4786 4800 4503 ) #define _USE_MATH_DEFINES #endif #include #include #include #include #include #include #include #include #include #include #include #ifdef HAVE_CONFIG_H #include "config.h" #endif #include #include #include #include "bobject.hpp" #include "mainwin.hpp" #include "messwin.hpp" #include "optwin.hpp" #include "tilewin.hpp" #include "curvtypwin.hpp" #include "objlibwin.hpp" #include "sdutil.hpp" #include "runways.hpp" #include "objectstatic.hpp" #include "triobject.hpp" #include "action.hpp" #include "statobjact.hpp" #include "fragmentact.hpp" #include "tileact.hpp" #include "baseobjact.hpp" #include "actionwin.hpp" #include "jpgimage.hpp" #include "curveact.hpp" #include "curvetools.hpp" #include "scenerytools.hpp" #include "tilefilewin.hpp" #include "tile.hpp" #include "exportwin.hpp" #include "topbana.c" // 200 = nombre de points // 120 = 1 / 0:00'30'' // ==> 200 points d'ecran pour 30 sec d'arc ( 1km sur un meridien ) #define SCALE_FACTOR ( 200 * 120 ) static const double FGSD_EPSILON = 0.000005; #include "new.xpm" #include "open.xpm" #include "save.xpm" #include "undo.xpm" #include "undo-gray.xpm" #include "redo.xpm" #include "redo-gray.xpm" #include "fragments.xpm" #include "fragments-gray.xpm" #include "curves.xpm" #include "curves-gray.xpm" #include "scenery.xpm" #include "scenery-gray.xpm" #include "measure.xpm" #include "measure-gray.xpm" Fl_Image *FGSD_MainWindow::_images[ NbImages ][ 2 ] = { { new Fl_Pixmap( new_xpm ), new Fl_Pixmap( new_xpm ) }, { new Fl_Pixmap( open_xpm ), new Fl_Pixmap( open_xpm ) }, { new Fl_Pixmap( save_xpm ), new Fl_Pixmap( save_xpm ) }, { new Fl_Pixmap( undo_xpm ), new Fl_Pixmap( undo_gray_xpm ) }, { new Fl_Pixmap( redo_xpm ), new Fl_Pixmap( redo_gray_xpm ) }, { new Fl_Pixmap( fragments_xpm ), new Fl_Pixmap( fragments_gray_xpm ) }, { new Fl_Pixmap( curves_xpm ), new Fl_Pixmap( curves_gray_xpm ) }, { new Fl_Pixmap( scenery_xpm ), new Fl_Pixmap( scenery_gray_xpm ) }, { new Fl_Pixmap( measure_xpm ), new Fl_Pixmap( measure_gray_xpm ) } }; FGSD_Preferences generalPreferences; Fl_Menu_Item mainMenu[] = { { "&File", 0, 0, 0, FL_SUBMENU }, { "&New", FL_ALT+'N', &FGSD_MainWindow::new_cb }, { "&Open...", FL_ALT+'O', &FGSD_MainWindow::open_cb }, { "&Recent Files", 0, 0, 0, FL_SUBMENU }, { "None", 0, 0, 0, FL_MENU_INACTIVE }, { 0 }, { "&Map Fragments...", FL_ALT+'M', &FGSD_MainWindow::import_cb, 0, FL_MENU_DIVIDER }, { "&Save", FL_ALT+'S', &FGSD_MainWindow::save_cb }, { "Save &As...", FL_ALT+'A', &FGSD_MainWindow::saveAs_cb }, { "&Export...", FL_ALT+'E', &FGSD_MainWindow::export_cb, 0, FL_MENU_DIVIDER }, { "&Quit", FL_ALT+'Q', &FGSD_MainWindow::quit_cb }, { 0 }, { "&Edit", 0, 0, 0, FL_SUBMENU }, { "&Undo", FL_CTRL+'z', &FGSD_MainWindow::undo_cb, 0, FL_MENU_INACTIVE }, { "&Redo", FL_CTRL+'y', &FGSD_MainWindow::redo_cb, 0, FL_MENU_INACTIVE }, { 0 }, { "&Tools", 0, 0, 0, FL_SUBMENU }, { "&Object Library...", 0, &FGSD_MainWindow::objlib_cb }, { "&Import Scenery", 0, 0, 0, FL_SUBMENU }, { "By extents...", 0, &FGSD_MainWindow::impscen_cb }, { "By file...", 0, &FGSD_MainWindow::impscenfile_cb }, { 0 }, { "&Goto airport", 0, 0, 0, FL_SUBMENU | FL_MENU_DIVIDER }, { "None", 0, 0, 0, FL_MENU_INACTIVE }, { 0 }, { "&Options...", 0, &FGSD_MainWindow::options_cb }, { 0 }, { "&?", 0, 0, 0, FL_SUBMENU }, { "&About FGSD...", 0, &FGSD_MainWindow::about_cb }, { 0 }, { 0 } }; FGSD_MainWindow::FGSD_MainWindow( int w, int h ) : _input( 0 ) , _valid( false ) , _outlinedFragment( 0 ) , _lockMouse( false ) , _popupShown( false ) , _dragging( false ) , _currentShape( 0 ) , _curObject( 0 ) , _adjObject( 0 ) , _curCurve( 0 ) , _dragMove( false ) , _visw( 0 ) , _vish( 0 ) , _zLevel( 1.0 ) , _minx( 1000 ) , _miny( 1000 ) , _maxx( -1000 ) , _maxy( -1000 ) , _drawType( FGSD_BaseObject::Normal ) , _drawCurves( true ) , _minBucket( false ) , _maxBucket( false ) , _doPostLoad( false ) { // FGSD_AirportObject aptobj; FGSD_Action::_mainWindow = this; FGSD_Action::_step = &FGSD_MainWindow::step_cb; _jpg = new FGSD_JPEGImage; _jpg->loadFromBuffer( banner.pixel_data, banner.length ); _banner = new Fl_RGB_Image( _jpg->buffer(), _jpg->width(), _jpg->height(), _jpg->depth() ); generalPreferences.load(); _taxiways = new FGSD_Taxiways; _runways = new FGSD_Runways; _airports = new FGSD_Airports; _input = new FGSD_InputWindow( 640, 480 ); _objlib = new FGSD_ObjectLibraryWindow( 640, 480 ); //_aptedt = new FGSD_AirportEditorWindow( 640, 480, _airports, _runways, _taxiways ); _exportWindow = new FGSD_ExportWindow( generalPreferences ); _actionWindow = 0; _window = new Fl_Window( w, h ); // _window->begin(); _popup = new Fl_Menu_Button( 0, 70, 0, 0 ); _popup->type( Fl_Menu_Button::POPUP3 ); _menubar = new Fl_Menu_Bar( 0, 0, w, 30 ); _menubar->box( FL_UP_BOX ); size_t nb = sizeof mainMenu / sizeof( Fl_Menu_Item ); int recent = -1, airport = -1, undo = -1, redo = -1; for ( size_t i = 0; i < nb; i++ ) { if ( mainMenu[ i ].text && strcmp( mainMenu[ i ].text, "&Recent Files" ) == 0 ) recent = i; if ( mainMenu[ i ].text && strcmp( mainMenu[ i ].text, "&Goto airport" ) == 0 ) airport = i; if ( mainMenu[ i ].text && strcmp( mainMenu[ i ].text, "&Undo" ) == 0 ) undo = i; if ( mainMenu[ i ].text && strcmp( mainMenu[ i ].text, "&Redo" ) == 0 ) redo = i; if ( mainMenu[ i ].callback_ != 0 ) mainMenu[ i ].user_data_ = this; } _menubar->menu( mainMenu ); _recentSubMenu.init( _menubar, "&File/&Recent Files/", recent, &_undoItem ); _undoItem.init( _menubar, "&Edit/", undo, &_redoItem ); _redoItem.init( _menubar, "&Edit/", redo, &_airportSubMenu ); _airportSubMenu.init( _menubar, "&Tools/&Goto airport/", airport, 0 ); refreshRecentFiles(); _tools = new Fl_Group( 0, 30, w, 40 ); int posx = 5; _nbutton = new Fl_Button( posx, 35, 30, 30 ); setButtonImage( _nbutton, New_i, true ); _nbutton->tooltip( "New project" ); _nbutton->callback( &FGSD_MainWindow::new_cb, this ); posx += 30; _obutton = new Fl_Button( posx, 35, 30, 30 ); setButtonImage( _obutton, Open_i, true ); _obutton->tooltip( "Open project" ); _obutton->callback( &FGSD_MainWindow::open_cb, this ); posx += 30; _vbutton = new Fl_Button( posx, 35, 30, 30 ); setButtonImage( _vbutton, Save_i, true ); _vbutton->tooltip( "Save project" ); _vbutton->callback( &FGSD_MainWindow::save_cb, this ); posx += 40; _ubutton = new Fl_Button( posx, 35, 30, 30 ); setButtonImage( _ubutton, Undo_i, true ); _ubutton->tooltip( "Undo" ); _ubutton->callback( &FGSD_MainWindow::undo_cb, this ); _ubutton->deactivate(); posx += 30; _ulbutton = new Fl_Button( posx, 35, 15, 30, "@2>" ); _ulbutton->labeltype( FL_SYMBOL_LABEL ); _ulbutton->tooltip( "Undo" ); _ulbutton->callback( &FGSD_MainWindow::undoButton_cb, this ); _ulbutton->deactivate(); posx += 15; _rbutton = new Fl_Button( posx, 35, 30, 30 ); setButtonImage( _rbutton, Redo_i, true ); _rbutton->tooltip( "Redo" ); _rbutton->callback( &FGSD_MainWindow::redo_cb, this ); _rbutton->deactivate(); posx += 30; _rlbutton = new Fl_Button( posx, 35, 15, 30, "@2>" ); _rlbutton->labeltype( FL_SYMBOL_LABEL ); _rlbutton->tooltip( "Redo" ); _rlbutton->callback( &FGSD_MainWindow::redoButton_cb, this ); _rlbutton->deactivate(); posx += 25; _fbutton = new Fl_Button( posx, 35, 30, 30 ); setButtonImage( _fbutton, Fragments_i, false ); _fbutton->type( FL_TOGGLE_BUTTON ); _fbutton->tooltip( "Map fragments toolbar" ); _fbutton->callback( &FGSD_MainWindow::fragmentButton_cb, this ); _fbutton->value( generalPreferences.showOutline() ); posx += 30; _cbutton = new Fl_Button( posx, 35, 30, 30 ); setButtonImage( _cbutton, Curves_i, false ); _cbutton->type( FL_TOGGLE_BUTTON ); _cbutton->tooltip( "Curves toolbar" ); _cbutton->callback( &FGSD_MainWindow::levelButton_cb, this ); _cbutton->value( generalPreferences.showLevelCurve() ); posx += 30; _sbutton = new Fl_Button( posx, 35, 30, 30 ); _sbutton->type( FL_TOGGLE_BUTTON ); _sbutton->tooltip( "FGFS sceneries toolbar" ); _sbutton->callback( &FGSD_MainWindow::sceneryButton_cb, this ); _sbutton->value( 0 ); _sbutton->deactivate(); setButtonImage( _sbutton, Scenery_i, true ); posx += 30; _mbutton = new Fl_Button( posx, 35, 30, 30 ); setButtonImage( _mbutton, Measure_i, false ); _mbutton->type( FL_TOGGLE_BUTTON ); _mbutton->tooltip( "Measure mode" ); _mbutton->callback( &FGSD_MainWindow::measureMode_cb, this ); posx += 40; _zoom = new Fl_Value_Slider( posx, 35, 100, 30 ); _zoom->type( FL_HORIZONTAL ); _zoom->range( -7, 7 ); _zoom->step( 1 ); _zoom->tooltip( "Zoom level" ); _zoom->callback( &FGSD_MainWindow::zoom_cb, (void *)this ); _zoom->value( generalPreferences.zoomLevel() ); posx += 105; bool neg_ = false; int v = (int)_zoom->value(); generalPreferences.zoomLevel( v ); if ( v < 0 ) { neg_ = true; v = -v; } _zLevel = 1 << v; if ( neg_ ) _zLevel = 1 / _zLevel; _tools->end(); _tools->resizable( 0 ); _tools->box( FL_THIN_UP_BOX ); _status = new Fl_Group( 0, h - 40, w, 40 ); _status->box( FL_THIN_UP_BOX ); _status->begin(); _xentry = new Fl_Output( 5, h - 35, 110, 30 ); _xentry->tooltip( "Current longitude of the mouse pointer" ); _xentry->color( _window->color() ); _yentry = new Fl_Output( 120, h - 35, 110, 30 ); _yentry->tooltip( "Current latitude of the mouse pointer" ); _yentry->color( _window->color() ); _zentry = new Fl_Output( 235, h - 35, 70, 30 ); _zentry->tooltip( "Current altitude of the mouse pointer" ); _zentry->color( _window->color() ); _matentry = new Fl_Output( 310, h - 35, 200, 30 ); _matentry->tooltip( "Current material of the mouse pointer" ); _matentry->color( _window->color() ); _aidentry = new Fl_Output( 515, h - 35, 50, 30 ); _aidentry->tooltip( "Current airport ID of the mouse pointer" ); _aidentry->color( _window->color() ); _progress = new Flu_Progress( 570, h - 35, 100, 30 ); _progress->box( FL_DOWN_BOX ); _progress->align( FL_ALIGN_BOTTOM ); _progress->selection_color(FL_BLUE); _progress->color(FL_WHITE); _progress->labelcolor(FL_WHITE); _status->end(); _status->resizable( 0 ); _curveTools = new FGSD_CurveToolbar( 0, 70, w, 40, this ); int th = 40; if ( !_cbutton->value() ) _curveTools->show( false ); _sceneryTools = new FGSD_SceneryToolbar( 0, 70, w, 40, this ); if ( !_sbutton->value() ) _sceneryTools->show( false ); _sceneryTools->drawTiles( generalPreferences.showTiles() ); _sceneryTools->drawStatic( generalPreferences.showStatic() ); _sceneryTools->drawTileFrames( generalPreferences.showTileFrames() ); _view = new Fl_Group( 0, 70+th, w, h - 110 - th ); _view->begin(); _vscroll = new Fl_Scrollbar( w - 20, 70+th+0, 20, h - 130 - th ); _vscroll->linesize( 10 ); _vscroll->callback( &FGSD_MainWindow::vscroll_cb, (void *)this ); _vscroll->deactivate(); _hscroll = new Fl_Scrollbar( 0, 70+th+h - 130 - th, w - 20, 20 ); _hscroll->type( FL_HORIZONTAL ); _hscroll->linesize( 10 ); _hscroll->callback( &FGSD_MainWindow::hscroll_cb, (void *)this ); _hscroll->deactivate(); _area = new FGSD_MainGLWindow( 0, 70+th+0, w - 20, h - 130 - th, this ); _view->resizable( _area ); _view->end(); _window->resizable( _view ); _window->callback( &FGSD_MainWindow::quit_cb, (void *)this ); _window->end(); setTitle(); Fl::add_timeout( 0.2, &FGSD_MainWindow::showBanner_cb, this ); } FGSD_MainWindow::~FGSD_MainWindow() { delete _input; delete _objlib; delete _exportWindow; cleanProject(); delete _window; delete _runways; delete _taxiways; delete _airports; delete _banner; _banner = 0; delete _jpg; _jpg = 0; for ( size_t i = 0; i < NbImages; i++ ) { delete _images[ i ][ 0 ]; delete _images[ i ][ 1 ]; } generalPreferences.save(); delete _currentShape; } void FGSD_MainWindow::layout_() { if ( _valid ) { double xcent = _posx + _visw / 2; if ( xcent < _minx ) xcent = _minx; if ( xcent > _maxx ) xcent = _maxx; double ycent = _posy + _vish / 2; if ( ycent < _miny ) ycent = _miny; if ( ycent > _maxy ) ycent = _maxy; double fy = SCALE_FACTOR * _zLevel; double fx = fy * cos( _miny * M_PI / 180 ); _visw = (double)_area->w() / fx; _vish = (double)_area->h() / fy; centerPosition( xcent, ycent ); } } void FGSD_MainWindow::mouseMove( int x, int y, int e, int s ) { //std::cout << "move " << x << " " << y << " " << e << " " << std::hex << s << std::dec << std::endl; if ( _lockMouse || _popupShown ) return; if ( _valid ) { if ( !_dragging ) { if ( _mbutton->value() ) { setCursor( FL_CURSOR_CROSS ); } else { FGSD_BaseObject *mouseObj = objectUnderMouse(); if ( _sceneryTools->vertexEdit() && mouseObj && mouseObj->isA( FGSD_BaseObject::TriangleObject ) ) { FGSD_TriangleObject *obj = (FGSD_TriangleObject *)mouseObj->convertTo( FGSD_BaseObject::TriangleObject ); bool xmin, ymin; bool xlock = obj->xlock( xmin ); bool ylock = obj->ylock( ymin ); if ( xlock && ylock ) setCursor( FL_CURSOR_DEFAULT ); else if ( !( xlock || ylock ) ) setCursor( FL_CURSOR_MOVE ); else if ( xlock ) setCursor( FL_CURSOR_NS ); else setCursor( FL_CURSOR_WE ); } else if ( _sceneryTools->drawStatic() && mouseObj && mouseObj->isA( FGSD_BaseObject::ObjectStatic ) ) setCursor( FL_CURSOR_MOVE ); else if ( _cbutton->value() && !Fl::event_state( FL_CTRL) && mouseObj && mouseObj->isA( FGSD_BaseObject::Curve ) ) { FGSD_Curve *curve = (FGSD_Curve *)mouseObj->convertTo( FGSD_BaseObject::Curve ); if ( curve->mouseOnPoint() ) setCursor( FL_CURSOR_MOVE ); else if ( curve->mouseOnEdge() ) setCursor( FL_CURSOR_HAND ); else setCursor( FL_CURSOR_DEFAULT ); } else setCursor( FL_CURSOR_DEFAULT ); } } double fy = SCALE_FACTOR * _zLevel; double fx = fy * cos( _miny * M_PI / 180 ); _curx = _posx + x / fx; _cury = _posy + ( _area->h() - y ) / fy; std::string airportID; bool ok = propertiesUnderMouse( _curx, _cury, _curz, _curMaterial, airportID ); _xentry->value( FGSD_Util::positionToString( _curx, true ).c_str() ); _yentry->value( FGSD_Util::positionToString( _cury, false ).c_str() ); /* std::ostringstream str1; str1 << _curx << std::ends; _xentry->value( str1.str().c_str() ); str1.str(""); str1 << _cury << std::ends; _yentry->value( str1.str().c_str() ); */ if ( ok ) { std::ostringstream str; str << (int)(_curz * 10.0 + .5) / 10.0 << std::ends; _zentry->value( str.str().c_str() ); if ( _dragging && !_dragMove && _mbutton->value() ) { double az1, az2, s; geo_inverse_wgs_84( _dragOriginZ, _dragOriginY, _dragOriginX, _cury, _curx, &az1, &az2, &s ); std::ostringstream str; #ifdef HAVE_STD_FIXED str << std::setprecision( 2 ) << std::fixed << s << " m, " << std::setprecision( 1 ) << std::fixed << az1 << "°" << std::ends; #else str << std::setprecision( 2 ) << s << " m, " << std::setprecision( 1 ) << az1 << "°" << std::ends; #endif _matentry->value( str.str().c_str() ); } else _matentry->value( _curMaterial.c_str() ); _aidentry->value( airportID.c_str() ); } else { _zentry->value( "-----" ); _matentry->value( "-----" ); } if ( _fbutton->value() ) { FGSD_MapFragment *outlined = 0; for ( FragmentList::reverse_iterator i = _fragmentList.rbegin(); i != _fragmentList.rend(); i++ ) { if ( mouseIsOverFragment( *i, _curx, _cury ) ) { outlined = *i; break; } } if ( outlined != _outlinedFragment ) { _outlinedFragment = outlined; _area->redraw(); } } else if ( _outlinedFragment ) { _outlinedFragment = 0; _area->redraw(); } if ( ( s & FL_BUTTON1 ) && e == FL_DRAG && _mbutton->value() ) { if ( !_dragging ) { setCursor( FL_CURSOR_CROSS ); _dragOriginX = _curx; _dragOriginY = _cury; _dragOriginZ = _curz; } _area->redraw(); } else if ( ( s & FL_BUTTON1 ) && e == FL_DRAG && _sceneryTools->drawStatic() && _curObject && _curObject->isA( FGSD_BaseObject::ObjectStatic ) ) { FGSD_ObjectStatic *obj = (FGSD_ObjectStatic *)_curObject->convertTo( FGSD_BaseObject::ObjectStatic ); FGSD_Tile *tile = obj->tile(); if ( !tile->positionInTile( _curx, _cury ) ) { if ( tile->removeObject( obj ) ) { FGSD_Tile *newTile = findTile( _curx, _cury ); if ( newTile ) newTile->addObject( obj ); else tile->addObject( obj ); } } newAction( new FGSD_MoveStaticObjectAction( obj->getName().c_str(), obj->getLon(), obj->getLat(), obj->getElev(), obj->getHeading(), _curx - obj->getLon(), _cury - obj->getLat() ) ); obj->changePosition( _curx, _cury ); _area->redraw(); } else if ( ( s & FL_BUTTON1 ) && e == FL_DRAG && _sceneryTools->vertexEdit() && _curObject && _curObject->isA( FGSD_BaseObject::TriangleObject ) ) { FGSD_TriangleObject *obj = (FGSD_TriangleObject *)_curObject->convertTo( FGSD_BaseObject::TriangleObject ); bool xmin, ymin; bool xlock = obj->xlock( xmin ); bool ylock = obj->ylock( ymin ); if ( !xlock && !ylock ) { Point3D p0 = obj->current(); newAction( new FGSD_MoveVertexBaseObjectAction( obj->getName().c_str(), p0.x(), p0.y(), _curx - p0.x(), _cury - p0.y() ) ); obj->changeCurrentPointPosition( _curx, _cury ); } else if ( ( xlock && !ylock ) || ( !xlock && ylock ) ) { Point3D p0 = obj->current(); obj->changeCurrentPointPosition( _curx, _cury ); if ( _adjObject ) { Point3D p = obj->current(); _adjObject->changeCurrentPointPosition( p.x(), p.y() ); } newAction( new FGSD_MoveVertexBaseObjectAction( obj->getName().c_str(), p0.x(), p0.y(), _curx - p0.x(), _cury - p0.y() ) ); } _area->redraw(); } else if ( ( s & FL_BUTTON1 ) && e == FL_DRAG && _cbutton->value() && _curObject && _curObject->convertTo( FGSD_BaseObject::Curve ) != 0 ) { FGSD_Curve *curve = (FGSD_Curve *)_curObject->convertTo( FGSD_BaseObject::Curve ); Point3D p0 = _curCurve->firstPoint(); Point3D p = _curCurve->mousePoint(); if ( curve->moveCurrentPoint( _curx, _cury ) ) newAction( new FGSD_MoveCurvePointAction( p0.x(), p0.y(), _curCurve->mouseIndex(), _curx - p.x(), _cury - p.y() ) ); _area->redraw(); } else if ( ( s & FL_BUTTON2 ) && e == FL_DRAG ) { if ( !_dragging ) { setCursor( ShapeHand ); _dragMove = true; _dragOriginX = _curx; _dragOriginY = _cury; _dragOriginZ = _curz; } if ( _visw > _maxx - _minx ) _dragOriginX = _curx; if ( _vish > _maxy - _miny ) _dragOriginY = _cury; gotoPosition( _dragOriginX, _dragOriginY, 2 * x, 2 * y ); } if ( e == FL_DRAG ) { _dragging = true; } else if ( _dragging ) { if ( _sceneryTools->vertexEdit() && _curObject && _curObject->isA( FGSD_BaseObject::TriangleObject ) ) { FGSD_TriangleObject *obj = (FGSD_TriangleObject *)_curObject->convertTo( FGSD_BaseObject::TriangleObject ); obj->tile()->recalcStaticObjectHeight(); if ( _adjObject ) _adjObject->tile()->recalcStaticObjectHeight(); } else if ( _cbutton->value() && _curObject && _curObject->convertTo( FGSD_BaseObject::Curve ) != 0 ) { FGSD_Curve *curve = (FGSD_Curve *)_curObject->convertTo( FGSD_BaseObject::Curve ); curve->tryToClose( _zLevel ); } else if ( _dragMove ) { setCursor( FL_CURSOR_DEFAULT ); _dragMove = false; } else if ( _mbutton->value() ) { _area->redraw(); } _dragging = false; } } } void FGSD_MainWindow::mouseClick( int x, int y, int s ) { //std::cout << "click " << x << " " << y << " " << std::hex << s << std::dec << std::endl; if ( !_valid ) return; _curObject = objectUnderMouse(); FGSD_TriangleObject *obj = 0; if ( _curObject ) obj = (FGSD_TriangleObject *)_curObject->convertTo( FGSD_BaseObject::TriangleObject ); if ( _sceneryTools->vertexEdit() && obj ) { bool xmin, ymin; bool xlock = obj->xlock( xmin ); bool ylock = obj->ylock( ymin ); if ( xlock && !ylock ) _adjObject = getAdjacentTerrainObject( obj->tile(), true, xmin ); else if ( !xlock && ylock ) _adjObject = getAdjacentTerrainObject( obj->tile(), false, ymin ); if ( _adjObject && ( xlock || ylock ) ) _adjObject->setCurrent( obj->current() ); else _adjObject = 0; } else _adjObject = 0; if ( s & FL_BUTTON2 ) { setCursor( ShapeHand ); } else if ( s & FL_BUTTON3 ) { int last = 0; _popup->clear(); last = _popup->add( "&Center", FL_ALT + 'c', &FGSD_MainWindow::center_cb, this ); last = _popup->add( "C&opy current height", FL_ALT + 'o', &FGSD_MainWindow::copyCurrentHeight_cb, this ); last = _popup->add( "&Start FlightGear here", FL_ALT + 's', &FGSD_MainWindow::startFlightGear_cb, this ); last = _popup->add( "&Fetch terraserver-usa.com from here...", FL_ALT + 'f', &FGSD_MainWindow::importAndFetch_cb, this, FL_MENU_DIVIDER ); if ( _sceneryTools->drawStatic() && _curObject && _curObject->isA( FGSD_BaseObject::ObjectStatic ) ) { last = _popup->add( "Change &heading...", FL_ALT + 'h', &FGSD_MainWindow::changeObjectHeading_cb, this ); last = _popup->add( "Remove object...", FL_ALT + 'r', &FGSD_MainWindow::removeStaticObject_cb, this ); } else { if ( _sceneryTools->drawStatic() ) { last = _popup->add( "&Add new object...", FL_ALT + 'a', &FGSD_MainWindow::addNewStaticObject_cb, this ); } if ( obj && !obj->interior() && _sceneryTools->vertexEdit() ) { last = _popup->add( "Change &vertex height", FL_ALT + 'v', &FGSD_MainWindow::changeVertexHeight_cb, this ); } last = _popup->add( "Change face &material", FL_ALT + 'm', &FGSD_MainWindow::changeMaterial_cb, this ); last = _popup->add( "&Repeat face material", FL_ALT + 'r', &FGSD_MainWindow::repeatChangeMaterial_cb, this ); } FGSD_Curve *curve = 0; if ( _cbutton->value() && _curObject && ( curve = (FGSD_Curve *)_curObject->convertTo( FGSD_BaseObject::Curve ) ) ) { _popup->mode( last, FL_MENU_DIVIDER ); if ( curve->mouseOnPoint() ) last = _popup->add( "Remove point", 0, &FGSD_MainWindow::remCurvePoint_cb, this ); last = _popup->add( "Remove curve", 0, &FGSD_MainWindow::remCurve_cb, this ); last = _popup->add( "Embed curve", 0, &FGSD_MainWindow::embedCurve_cb, this ); last = _popup->add( "Curve properties...", 0, &FGSD_MainWindow::curveType_cb, this ); } if ( _fbutton->value() && _outlinedFragment ) { _popup->mode( last, FL_MENU_DIVIDER ); last = _popup->add( "To &top", FL_ALT + 't', &FGSD_MainWindow::toTop_cb, this ); last = _popup->add( "To &bottom", FL_ALT + 'b', &FGSD_MainWindow::toBottom_cb, this ); last = _popup->add( "One &up", FL_ALT + 'u', &FGSD_MainWindow::oneUp_cb, this ); last = _popup->add( "One &down", FL_ALT + 'd', &FGSD_MainWindow::oneDown_cb, this, FL_MENU_DIVIDER ); last = _popup->add( "Remove map fragment", 0, &FGSD_MainWindow::remMapFragment_cb, this ); } if ( !findTile( _curx, _cury ) ) { _popup->mode( last, FL_MENU_DIVIDER ); last = _popup->add( "Create tile", 0, &FGSD_MainWindow::addTile_cb, this ); } setCursor( FL_CURSOR_DEFAULT ); _popupShown = true; _popup->value(-1); // Should be : _popup->popup(); // but there is a problem with menu positionning so : const Fl_Menu_Item* m = _popup->menu()->popup(Fl::event_x(), Fl::event_y() + 110, _popup->label(), _popup->mvalue(), _popup ); _popup->picked(m); // _popupShown = false; } else if ( _cbutton->value() && ( s & FL_BUTTON1 ) ) { if ( Fl::event_state(FL_CTRL) || _curveTools->addPoint() ) { FGSD_Action *act = 0; if ( _curCurve == 0 ) { _curCurve = new FGSD_Curve; _curveList.push_back( _curCurve ); _curCurve->selected( true ); act = new FGSD_AddCurveAction( _curx, _cury ); } else { Point3D p = _curCurve->firstPoint(); act = new FGSD_AddCurvePointAction( p.x(), p.y(), _curCurve->current(), _curx, _cury ); } if ( _curCurve->insertPoint( _curx, _cury ) ) { _curCurve->tryToClose( _zLevel ); newAction( act ); } else { delete act; } _area->redraw(); } else { FGSD_Curve *curve = _curObject ? (FGSD_Curve *)_curObject->convertTo( FGSD_BaseObject::Curve ) : 0; if ( _curCurve ) _curCurve->selected( false ); _curCurve = curve; if ( _curCurve ) _curCurve->selected( true ); if ( _curCurve ) _curCurve->changeCurrentPoint(); _area->redraw(); } } } void FGSD_MainWindow::mouseRelease( int x, int y, int s ) { if ( _dragging ) { if ( _mbutton->value() ) setCursor( FL_CURSOR_CROSS ); else setCursor( FL_CURSOR_DEFAULT ); } } void FGSD_MainWindow::mouseLeave() { //std::cout << "leave " << std::endl; if ( !_popupShown ) { _xentry->value( "-----" ); _yentry->value( "-----" ); _zentry->value( "-----" ); _matentry->value( "" ); _aidentry->value( "" ); } if ( _currentCursor != FL_CURSOR_WAIT ) setCursor( FL_CURSOR_DEFAULT ); } void FGSD_MainWindow::undoButton_cb( Fl_Widget *w, void *v ) { static_cast( v )->toolButton_cb( w, Undo ); } void FGSD_MainWindow::redoButton_cb( Fl_Widget *w, void *v ) { static_cast( v )->toolButton_cb( w, Redo ); } void FGSD_MainWindow::fragmentButton_cb( Fl_Widget *w, void *v ) { static_cast( v )->toolButton_cb( w, Fragment ); } void FGSD_MainWindow::levelButton_cb( Fl_Widget *w, void *v ) { static_cast( v )->toolButton_cb( w, Curve ); } void FGSD_MainWindow::sceneryButton_cb( Fl_Widget *w, void *v ) { static_cast( v )->toolButton_cb( w, Scenery ); } void FGSD_MainWindow::tileButton_cb( Fl_Widget *w, void *v ) { static_cast( v )->toolButton_cb( w, Tile ); } void FGSD_MainWindow::staticButton_cb( Fl_Widget *w, void *v ) { static_cast( v )->toolButton_cb( w, StaticObj ); } void FGSD_MainWindow::tileFrameButton_cb( Fl_Widget *w, void *v ) { static_cast( v )->toolButton_cb( w, TileFrame ); } void FGSD_MainWindow::vertexMode_cb( Fl_Widget *w, void *v ) { static_cast( v )->toolButton_cb( w, Vertex ); } void FGSD_MainWindow::measureMode_cb( Fl_Widget *w, void *v ) { static_cast( v )->toolButton_cb( w, Measure ); } void FGSD_MainWindow::toolButton_cb( Fl_Widget *w, ToolButton b ) { switch ( b ) { case Undo: _actionWindow = new FGSD_ActionWindow( this, 110, 70, 200, 150, true ); _actionWindow->show(); break; case Redo: _actionWindow = new FGSD_ActionWindow( this, 140, 70, 200, 150, false ); _actionWindow->show(); break; case Fragment: generalPreferences.showOutline( _fbutton->value() ); _cbutton->value( 0 ); _curveTools->show( false ); if ( !_fbutton->value() ) { _outlinedFragment = 0; _area->redraw(); } break; case Curve: generalPreferences.showLevelCurve( _cbutton->value() ); _fbutton->value( 0 ); _sceneryTools->vertexEdit( 0 ); _sbutton->value( 0 ); _sceneryTools->show( false ); _curveTools->show( _cbutton->value() ); if ( _curCurve ) _curCurve->selected( _cbutton->value() ); _area->redraw(); break; case Scenery: _sceneryTools->show( _sbutton->value() ); _cbutton->value( 0 ); _curveTools->show( false ); break; case Tile: _sceneryTools->drawTiles( _sceneryTools->drawTiles() ); generalPreferences.showTiles( _sceneryTools->drawTiles() ); _area->redraw(); break; case StaticObj: generalPreferences.showStatic( _sceneryTools->drawStatic() ); _area->redraw(); break; case TileFrame: generalPreferences.showTileFrames( _sceneryTools->drawTileFrames() ); _area->redraw(); break; case Vertex: if ( _curCurve ) _curCurve->selected( false ); _area->redraw(); break; case Measure: if ( _mbutton->value() ) setCursor( FL_CURSOR_CROSS ); else setCursor( FL_CURSOR_DEFAULT ); break; } } void FGSD_MainWindow::quit_cb(Fl_Widget *o, void *v) { static_cast( v )->quit_cb( o ); } void FGSD_MainWindow::quit_cb(Fl_Widget *) { bool close = checkModified(); if ( close ) _window->hide(); } void FGSD_MainWindow::recentFile_cb(Fl_Widget *o, void *v) { static_cast( v )->recentFile_cb( o ); } void FGSD_MainWindow::recentFile_cb( Fl_Widget *o ) { if ( checkModified() ) { int n = _menubar->value() - _recentSubMenu.first(); std::string fileName = generalPreferences.getFileFromHistory( n ); if ( fileName.size() ) { setCursor( FL_CURSOR_WAIT ); cleanProject(); load( fileName.c_str() ); _posx = _minx; _posy = _miny; layout_(); if ( _fragmentList.empty() ) { _fbutton->deactivate(); setButtonImage( _fbutton, Fragments_i, true ); } else { _fbutton->activate(); setButtonImage( _fbutton, Fragments_i, false ); } if ( _tileList.empty() ) { _sbutton->value( 0 ); _sbutton->deactivate(); setButtonImage( _sbutton, Scenery_i, true ); _sceneryTools->drawTiles( false ); } else { _sbutton->activate(); setButtonImage( _sbutton, Scenery_i, false ); if ( _fragmentList.empty() ) { _sceneryTools->drawTiles( true ); _sceneryTools->noFragmentPresent(); } else { _sceneryTools->fragmentPresent(); } } if ( _fragmentList.empty() ) { _sceneryTools->drawTiles( true ); _sceneryTools->noFragmentPresent(); } _vscroll->activate(); _hscroll->activate(); _area->valid( 0 ); _area->redraw(); _fileName = fileName; setTitle(); generalPreferences.addFileToHistory( _fileName ); generalPreferences.save(); refreshRecentFiles(); setCursor( FL_CURSOR_DEFAULT ); } } } void FGSD_MainWindow::new_cb(Fl_Widget *o, void *v) { static_cast( v )->new_cb( o ); } void FGSD_MainWindow::new_cb(Fl_Widget*) { if ( checkModified() ) { setCursor( FL_CURSOR_WAIT ); cleanProject(); _xentry->value( "" ); _yentry->value( "" ); _zentry->value( "" ); _matentry->value( "" ); _aidentry->value( "" ); _fbutton->activate(); setButtonImage( _fbutton, Fragments_i, false ); _cbutton->activate(); setButtonImage( _cbutton, Curves_i, false ); _sbutton->value( 0 ); _sbutton->deactivate(); setButtonImage( _sbutton, Scenery_i, true ); _vscroll->deactivate(); _hscroll->deactivate(); _area->valid( 0 ); _area->redraw(); _fileName = ""; setTitle(); setCursor( FL_CURSOR_DEFAULT ); } } void FGSD_MainWindow::open_cb(Fl_Widget *o, void *v) { static_cast( v )->open_cb( o ); } void FGSD_MainWindow::save_cb(Fl_Widget *o, void *v) { static_cast( v )->saveProject( false ); } void FGSD_MainWindow::saveAs_cb(Fl_Widget *o, void *v) { static_cast( v )->saveProject( true ); } void FGSD_MainWindow::export_cb(Fl_Widget *o, void *v) { static_cast( v )->export_cb( o ); } void FGSD_MainWindow::export_cb(Fl_Widget*) { if ( _exportWindow->exec() ) { std::string outPath = _exportWindow->outputPath(); if ( outPath.size() ) { std::string format = _exportWindow->format(); bool objectBase = _exportWindow->objectBase(); bool object = _exportWindow->object(); bool objectStatic = _exportWindow->objectStatic(); bool objectShared = _exportWindow->objectShared(); bool force = _exportWindow->force(); setCursor( FL_CURSOR_WAIT ); TileList::iterator i; for ( i = _tileList.begin(); i != _tileList.end(); ++i ) { FGSD_Tile *tile = i->second; if ( force || tile->modified() ) { tile->saveTo( outPath, format, objectBase, object, objectStatic, objectShared, force ); } Fl::check(); } setCursor( FL_CURSOR_DEFAULT ); } else { FGSD_MessageWindow mess( "FlightGear Scenery Designer", "The output path must be set before exporting", FGSD_MessageWindow::Error, FGSD_MessageWindow::Ok ); mess.exec(); } } } void FGSD_MainWindow::objlib_cb(Fl_Widget *o, void *v) { static_cast( v )->objlib_cb( o ); } void FGSD_MainWindow::objlib_cb( Fl_Widget *o ) { _objlib->setMode( FGSD_ObjectLibraryWindow::Edit ); _objlib->exec( _window, false ); } void FGSD_MainWindow::impscen_cb(Fl_Widget *o, void *v) { static_cast( v )->impscen_cb( o ); } void FGSD_MainWindow::impscen_cb( Fl_Widget *o ) { FGSD_TileWindow tile( _minx, _miny, _maxx, _maxy ); if ( tile.exec() ) { setCursor( FL_CURSOR_WAIT ); SGBucket min_ = tile.minBucket(); SGBucket max_ = tile.maxBucket(); _minx = min_.get_chunk_lon() + min_.get_x() * min_.get_width(); _miny = min_.get_chunk_lat() + min_.get_y() * min_.get_height(); _maxx = max_.get_chunk_lon() + ( max_.get_x() + 1 ) * max_.get_width(); _maxy = max_.get_chunk_lat() + ( max_.get_y() + 1 ) * max_.get_height(); TileList newTiles = importTiles( generalPreferences.fgRootPath().c_str(), generalPreferences.fgSceneryPath().c_str() ); postTileLoad( newTiles ); for ( TileList::iterator it = newTiles.begin(); it != newTiles.end(); ++it ) { _tileList[ it->first ] = it->second; } _progress->labelcolor(FL_WHITE); _progress->value( 0 ); _posx = _minx; _posy = _miny; _valid = true; if ( _tileList.empty() ) { _sbutton->value( 0 ); _sbutton->deactivate(); setButtonImage( _sbutton, Scenery_i, true ); _sceneryTools->drawTiles( false ); } else { _sbutton->activate(); setButtonImage( _sbutton, Scenery_i, false ); _sceneryTools->drawTiles( true ); if ( _fragmentList.empty() ) { _sceneryTools->noFragmentPresent(); } else { _sceneryTools->fragmentPresent(); } _vscroll->activate(); _hscroll->activate(); } layout_(); _area->valid( 0 ); _area->redraw(); refreshAirportList(); setCursor( FL_CURSOR_DEFAULT ); } } void FGSD_MainWindow::impscenfile_cb(Fl_Widget *o, void *v) { static_cast( v )->impscenfile_cb( o ); } void FGSD_MainWindow::impscenfile_cb( Fl_Widget *o ) { static std::string current; std::list pathList; FGSD_Util::splitPath( generalPreferences.fgSceneryPath(), pathList, ';' ); TileList newTiles; FGSD_TileFileWindow tfw( pathList, current.c_str() ); int ok = tfw.exec(); if ( ok ) { setCursor( FL_CURSOR_WAIT ); current = tfw.currentPath(); _progress->labelcolor(FL_RED); _progress->value( 0 ); Fl::check(); std::vector tilenames = tfw.selected(); if ( tfw.level() == 0 || tfw.level() == 1 ) // 10x10 or 1x1 chunks { size_t i, nb = 0; std::vector > buckets; for ( i = 0; i < tilenames.size(); i++ ) { std::string chunkname = tilenames[ i ]; size_t pos = chunkname.rfind( '/' ); chunkname.erase( 0, pos + 1 ); std::istringstream str( chunkname ); char xsign, ysign; int lon, lat; str >> xsign >> lon >> ysign >> lat; if ( xsign == 'w' || xsign == 'W' ) lon = -lon; if ( ysign == 's' || ysign == 'S' ) lat = -lat; size_t n = 10; if ( tfw.level() == 1 ) n = 1; for ( size_t j = 0; j < n; j++ ) { for ( size_t k = 0; k < n; k++ ) { SGBucket bmin( lon + j, lat + k ); size_t dx = (size_t)( 1 / bmin.get_width() ); size_t dy = (size_t)( 1 / bmin.get_height() ); buckets.push_back( std::pair( lon + j, lat + k ) ); nb += ( dx * dy ); } } } _progress->maximum( nb ); for ( i = 0; i < buckets.size(); i++ ) { std::pair v = buckets[ i ]; int lon = v.first; int lat = v.second; SGBucket bmin( lon, lat ); size_t dx = (size_t)( 1 / bmin.get_width() ); size_t dy = (size_t)( 1 / bmin.get_height() ); for ( size_t j = 0; j < dx; j++ ) { for ( size_t k = 0; k < dy; k++ ) { SGBucket b = sgBucketOffset( lon, lat, j, k ); if ( !findTile( b.get_chunk_lon() + b.get_x() * b.get_width(), b.get_chunk_lat() + b.get_y() * b.get_height() ) ) { FGSD_Tile *tile = new FGSD_Tile( b ); bool ok = tile->load( generalPreferences.fgRootPath().c_str(), generalPreferences.fgSceneryPath().c_str() ); if ( ok ) { newAction( new FGSD_AddRemoveTileAction( true, b.gen_index_str().c_str() ) ); newTiles[ tile->getName() ] = tile; } else delete tile; } _progress->value( _progress->value() + 1 ); Fl::check(); } } } } else // 2 - individual tile { _progress->maximum( tilenames.size() ); for ( size_t i = 0; i < tilenames.size(); i++ ) { std::string tilename = tilenames[ i ]; size_t pos = tilename.rfind( '/' ); tilename.erase( 0, pos + 1 ); pos = tilename.find( '.' ); tilename.erase( pos ); long index; std::istringstream str( tilename ); str >> index; SGBucket b( index ); if ( !findTile( b.get_chunk_lon() + b.get_x() * b.get_width(), b.get_chunk_lat() + b.get_y() * b.get_height() ) ) { FGSD_Tile *tile = new FGSD_Tile( b ); bool ok = tile->load( generalPreferences.fgRootPath().c_str(), generalPreferences.fgSceneryPath().c_str() ); if ( ok ) { newAction( new FGSD_AddRemoveTileAction( true, b.gen_index_str().c_str() ) ); newTiles[ tile->getName() ] = tile; } else delete tile; } _progress->value( _progress->value() + 1 ); Fl::check(); } } postTileLoad( newTiles ); for ( TileList::iterator it = newTiles.begin(); it != newTiles.end(); ++it ) _tileList[ it->first ] = it->second; overallBoundingBox( _minx, _miny, _maxx, _maxy ); _progress->labelcolor(FL_WHITE); _progress->value( 0 ); if ( !_valid ) { _posx = _minx; _posy = _miny; _valid = true; } if ( _tileList.empty() ) { _sbutton->value( 0 ); _sbutton->deactivate(); setButtonImage( _sbutton, Scenery_i, true ); _sceneryTools->drawTiles( false ); } else { _sbutton->activate(); setButtonImage( _sbutton, Scenery_i, false ); _sceneryTools->drawTiles( true ); if ( _fragmentList.empty() ) { _sceneryTools->noFragmentPresent(); } else { _sceneryTools->fragmentPresent(); } _vscroll->activate(); _hscroll->activate(); } layout_(); _area->valid( 0 ); _area->redraw(); refreshAirportList(); setCursor( FL_CURSOR_DEFAULT ); } } void FGSD_MainWindow::options_cb(Fl_Widget *o, void *v) { static_cast( v )->options_cb( o ); } void FGSD_MainWindow::options_cb( Fl_Widget *o ) { FGSD_OptionWindow opt( generalPreferences ); opt.exec(); _area->redraw(); } void FGSD_MainWindow::hscroll_cb(Fl_Widget *o, void *v) { static_cast( v )->hscroll_cb( o ); } void FGSD_MainWindow::hscroll_cb(Fl_Widget *) { double fx = SCALE_FACTOR * _zLevel * cos( _miny * M_PI / 180 ); _posx = _minx + _hscroll->value() / fx; _area->valid(0); _area->redraw(); } void FGSD_MainWindow::vscroll_cb(Fl_Widget *o, void *v) { static_cast( v )->vscroll_cb( o ); } void FGSD_MainWindow::vscroll_cb(Fl_Widget *) { double fy = SCALE_FACTOR * _zLevel; double lv = ( _maxy - _miny ) * fy; _posy = _miny + ( lv - _area->h() - _vscroll->value() ) / fy; _area->valid(0); _area->redraw(); } void FGSD_MainWindow::zoom_cb(Fl_Widget *o, void *v) { static_cast( v )->zoom_cb(); } void FGSD_MainWindow::zoom_cb() { double visw = _visw * _zLevel; double vish = _vish * _zLevel; double xcent = _posx + _visw / 2; double ycent = _posy + _vish / 2; bool neg_ = false; int v = (int)_zoom->value(); generalPreferences.zoomLevel( v ); if ( v < 0 ) { neg_ = true; v = -v; } _zLevel = 1 << v; if ( neg_ ) _zLevel = 1 / _zLevel; _visw = visw / _zLevel; if ( _visw > _maxx - _minx ) xcent = ( _maxx + _minx ) / 2; _vish = vish / _zLevel; if ( _vish > _maxy - _miny ) ycent = ( _maxy + _miny ) / 2; centerPosition( xcent, ycent ); } void FGSD_MainWindow::alpha_cb(Fl_Widget *o, void *v) { static_cast( v )->alpha_cb( o ); } void FGSD_MainWindow::alpha_cb(Fl_Widget *) { generalPreferences.alphaValue( _sceneryTools->alphaValue() ); _area->redraw(); } void FGSD_MainWindow::about_cb(Fl_Widget *, void *v) { static_cast( v )->showBanner( false ); } void FGSD_MainWindow::closeAbout_cb(Fl_Widget *, void *v) { static_cast( v )->closeAbout_cb(); } void FGSD_MainWindow::closeAbout_cb() { _banWindow->hide(); } void FGSD_MainWindow::drawGL() { layout_(); glViewport( 0, 0, _area->w(), _area->h() ); glMatrixMode( GL_PROJECTION ); glLoadIdentity(); if ( _valid ) gluOrtho2D( _posx, _posx + _visw, _posy, _posy + _vish ); else gluOrtho2D( 0, _area->w(), 0, _area->h() ); glClearColor( (GLfloat)0.3, (GLfloat)0.3, 0.0, 0.0 ); glClear( GL_COLOR_BUFFER_BIT ); glEnable( GL_TEXTURE_2D ); glDisable( GL_LIGHTING ); glDisable( GL_COLOR_MATERIAL ); double alpha = _sceneryTools->alphaValue(); if ( !_sceneryTools->drawTiles() || alpha < 1 ) { for ( FragmentList::iterator i = _fragmentList.begin(); i != _fragmentList.end(); i++ ) { FGSD_MapFragment *fragment = *i; double x1, y1, x2, y2; getFragmentBoundingBox( fragment, x1, y1, x2, y2 ); if ( x2 >= _posx && y2 >= _posy && x1 < _posx + _visw && y1 < _posy + _vish ) drawTransformedFragment( fragment, _posx, _posy, _posx + _visw, _posy + _vish ); } } glDisable( GL_TEXTURE_2D ); if ( _sceneryTools->drawTiles() ) { glEnable( GL_BLEND ); glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA ); TileList::iterator i; for ( i = _tileList.begin(); i != _tileList.end(); ++i ) { FGSD_Tile *tile = i->second; tile->drawGL( FGSD_BaseObject::TriangleObject, alpha, _sceneryTools->drawTileFrames(), _drawType, _posx, _posx + _visw, _posy, _posy + _vish, _zLevel ); } if ( _sceneryTools->drawStatic() ) { for ( i = _tileList.begin(); i != _tileList.end(); ++i ) { FGSD_Tile *tile = i->second; tile->drawGL( FGSD_BaseObject::ObjectStatic, alpha, _sceneryTools->drawTileFrames(), _drawType, _posx, _posx + _visw, _posy, _posy + _vish, _zLevel ); } } glPolygonMode( GL_FRONT_AND_BACK, GL_FILL ); glDisable( GL_BLEND ); } if ( _outlinedFragment ) { glColor3f( 1.0, 0.0, 1.0 ); glLineWidth( 3.0 ); drawFragmentOutline( _outlinedFragment ); } if ( _drawCurves ) for ( CurveList::iterator ci = _curveList.begin(); ci != _curveList.end(); ++ci ) (*ci)->draw( alpha, true, FGSD_BaseObject::Normal, _posx, _posx + _visw, _posy, _posy + _vish, _zLevel ); if ( _dragging && !_dragMove && _mbutton->value() ) { // Save previous state glPushAttrib( GL_CURRENT_BIT | GL_POINT_BIT | GL_LINE_BIT | GL_POLYGON_BIT ); // Set new state glPolygonMode( GL_FRONT_AND_BACK, GL_LINE ); double xscale = 0.0006 / _zLevel; double yscale = xscale * cos( _dragOriginY * M_PI / 180 ); glColor4f( 0.0, 0.0, 1.0, 1.0 ); glLineWidth( 1.0 ); glBegin( GL_LINES ); glVertex2d( _dragOriginX - xscale, _dragOriginY ); glVertex2d( _dragOriginX + xscale, _dragOriginY ); glVertex2d( _dragOriginX, _dragOriginY - yscale ); glVertex2d( _dragOriginX, _dragOriginY + yscale ); glVertex2d( _dragOriginX, _dragOriginY ); glVertex2d( _curx, _cury ); glEnd(); // Restore previous state glPopAttrib(); } } void FGSD_MainWindow::gotoApt_cb(Fl_Widget *o, void *v) { static_cast( v )->gotoApt_cb( o ); } void FGSD_MainWindow::gotoApt_cb( Fl_Widget *o ) { size_t n = _menubar->value() - _airportSubMenu.first(); FGSD_Airport apt; _airports->search( _aptList[ n ].c_str(), apt ); centerPosition( apt.lon, apt.lat ); } bool FGSD_MainWindow::loadTiles( const std::vector &__nameList, void (*__step)( size_t, void * ) ) { bool ret = false; if ( !__step && __nameList.size() > 10 ) { _progress->labelcolor(FL_RED); _progress->maximum( __nameList.size() ); _progress->value( 0 ); Fl::check(); } TileList newTiles; for ( std::vector::const_iterator ni = __nameList.begin(); ni != __nameList.end(); ++ni ) { long index; std::istringstream str( *ni ); str >> index; SGBucket b( index ); FGSD_Tile *tile = new FGSD_Tile( b ); bool ok = tile->load( generalPreferences.fgRootPath().c_str(), generalPreferences.fgSceneryPath().c_str() ); if ( ok ) { newTiles[ tile->getName() ] = tile; ret = true; } else delete tile; if ( __step ) __step( 1, this ); else if ( __nameList.size() > 10 ) { _progress->value( _progress->value() + 1 ); Fl::check(); } } if ( ret ) { for ( TileList::iterator it = newTiles.begin(); it != newTiles.end(); ++it ) _tileList[ it->first ] = it->second; refreshAirportList(); overallBoundingBox( _minx, _miny, _maxx, _maxy ); layout_(); _doPostLoad = true; } if ( !__step && __nameList.size() > 10 ) { _progress->labelcolor( FL_WHITE ); _progress->value( 0 ); } return ret; } bool FGSD_MainWindow::removeTiles( const std::vector &__nameList ) { bool ret = false; if ( __nameList.size() > 10 ) { _progress->labelcolor(FL_RED); _progress->maximum( __nameList.size() ); _progress->value( 0 ); Fl::check(); } for ( std::vector::const_iterator ni = __nameList.begin(); ni != __nameList.end(); ++ni ) { TileList::iterator ti = _tileList.find( *ni ); FGSD_Tile *t = ti->second; _tileList.erase( ti ); delete t; if ( __nameList.size() > 10 ) { _progress->value( _progress->value() + 1 ); Fl::check(); } ret = true; } if ( ret ) { refreshAirportList(); overallBoundingBox( _minx, _miny, _maxx, _maxy ); layout_(); } if ( __nameList.size() > 10 ) { _progress->labelcolor( FL_WHITE ); _progress->value( 0 ); } return ret; } bool FGSD_MainWindow::moveBaseObjectVertex( const char *__name, double __lon, double __lat, double __xdepl, double __ydepl ) { bool ret = false; long index; std::istringstream str( __name ); str >> index; SGBucket b( index ); double lon = b.get_chunk_lon() + b.get_x() * b.get_width(); double lat = b.get_chunk_lat() + b.get_y() * b.get_height(); FGSD_Tile *tile = findTile( lon, lat ); if ( tile ) { FGSD_TriangleObject *obj = tile->getTerrain(); if ( obj ) { obj->setCurrent( Point3D( __lon, __lat, 0 ) ); bool xmin, ymin; bool xlock = obj->xlock( xmin ); bool ylock = obj->ylock( ymin ); FGSD_TriangleObject *adjObject = 0; if ( xlock && !ylock ) adjObject = getAdjacentTerrainObject( obj->tile(), true, xmin ); else if ( !xlock && ylock ) adjObject = getAdjacentTerrainObject( obj->tile(), false, ymin ); if ( adjObject && ( xlock || ylock ) ) adjObject->setCurrent( obj->current() ); if ( !xlock && !ylock ) { Point3D p0 = obj->current(); obj->changeCurrentPointPosition( p0.x() + __xdepl, p0.y() + __ydepl ); } else if ( ( xlock && !ylock ) || ( !xlock && ylock ) ) { Point3D p0 = obj->current(); obj->changeCurrentPointPosition( p0.x() + __xdepl, p0.y() + __ydepl ); if ( adjObject ) { Point3D p = obj->current(); adjObject->changeCurrentPointPosition( p.x(), p.y() ); } } obj->tile()->recalcStaticObjectHeight(); if ( adjObject ) adjObject->tile()->recalcStaticObjectHeight(); ret = true; } } return ret; } bool FGSD_MainWindow::changeBaseObjectHeight( const char *__name, double __lon, double __lat, double __zdepl ) { bool ret = false; long index; std::istringstream str( __name ); str >> index; SGBucket b( index ); double lon = b.get_chunk_lon() + b.get_x() * b.get_width(); double lat = b.get_chunk_lat() + b.get_y() * b.get_height(); FGSD_Tile *tile = findTile( lon, lat ); if ( tile ) { FGSD_TriangleObject *obj = tile->getTerrain(); if ( obj ) { obj->setCurrent( Point3D( __lon, __lat, 0 ) ); Point3D p0 = obj->current(); if ( !obj->interior() ) { bool xmin, ymin; bool xlock = obj->xlock( xmin ); bool ylock = obj->ylock( ymin ); if ( !( xlock || ylock ) ) { obj->changeCurrentPointHeight( p0.z() + __zdepl ); obj->tile()->recalcStaticObjectHeight(); } else if ( !( xlock && ylock ) ) { FGSD_TriangleObject *adjObject = 0; if ( xlock ) adjObject = getAdjacentTerrainObject( obj->tile(), true, xmin ); else adjObject = getAdjacentTerrainObject( obj->tile(), false, ymin ); adjObject->setCurrent( p0 ); obj->changeCurrentPointHeight( p0.z() + __zdepl ); Point3D p = obj->current(); adjObject->changeCurrentPointHeight( p0.z() ); obj->tile()->recalcStaticObjectHeight(); adjObject->tile()->recalcStaticObjectHeight(); } else { FGSD_TriangleObject *adjxObject = getAdjacentTerrainObject( obj->tile(), true, xmin ); FGSD_TriangleObject *adjyObject = getAdjacentTerrainObject( obj->tile(), false, ymin ); FGSD_TriangleObject *adjxyObject = getAdjacentTerrainObject( adjxObject->tile(), false, ymin ); adjxObject->setCurrent( p0 ); adjyObject->setCurrent( p0 ); adjxyObject->setCurrent( p0 ); obj->changeCurrentPointHeight( p0.z() + __zdepl ); Point3D p = obj->current(); adjxObject->changeCurrentPointHeight( p.z() ); adjyObject->changeCurrentPointHeight( p.z() ); adjxyObject->changeCurrentPointHeight( p.z() ); obj->tile()->recalcStaticObjectHeight(); adjxObject->tile()->recalcStaticObjectHeight(); adjyObject->tile()->recalcStaticObjectHeight(); adjxyObject->tile()->recalcStaticObjectHeight(); } ret = true; } } } return ret; } bool FGSD_MainWindow::changeBaseObjectMaterial( const char *__name, double __lon, double __lat, const std::string &__material ) { bool ret = false; long index; std::istringstream str( __name ); str >> index; SGBucket b( index ); double lon = b.get_chunk_lon() + b.get_x() * b.get_width(); double lat = b.get_chunk_lat() + b.get_y() * b.get_height(); FGSD_Tile *tile = findTile( lon, lat ); if ( tile ) { ret = tile->changeMaterial( __material, __lon, __lat ); } return ret; } bool FGSD_MainWindow::getBaseObjectPointPosition( const char *__name, size_t __index, double &__lon, double &__lat ) const { bool ret = false; long index; std::istringstream str( __name ); str >> index; SGBucket b( index ); double lon = b.get_chunk_lon() + b.get_x() * b.get_width(); double lat = b.get_chunk_lat() + b.get_y() * b.get_height(); FGSD_Tile *tile = findTile( lon, lat ); if ( tile ) { FGSD_TriangleObject *obj = tile->getTerrain(); if ( obj ) { ret = obj->getPointPosition( __index, __lon, __lat ); } } return ret; } bool FGSD_MainWindow::getCurvePointPosition( double __lon, double __lat, size_t __index, double &__pLon, double &__pLat ) const { bool ret = false; for ( CurveList::const_iterator ci = _curveList.begin(); ci != _curveList.end(); ++ci ) { FGSD_Curve *curve = *ci; Point3D point = curve->firstPoint(); if ( fabs( point.x() - __lon ) < FGSD_EPSILON && fabs( point.y() - __lat ) < FGSD_EPSILON ) { Point3D p = curve->pointAt( __index ); __pLon = p.x(); __pLat = p.y(); ret = true; } } return ret; } bool FGSD_MainWindow::newCurve( const FGSD_Curve::PointList *__pointList, bool __opened, size_t __current ) { FGSD_Curve *curve = new FGSD_Curve; _curveList.push_back( curve ); if ( __pointList ) { size_t nb = __pointList->size(); for ( size_t i = 0; i < nb; i++ ) { Point3D p = (*__pointList)[ i ].p; curve->insertPoint( p.x(), p.y() ); } curve->setOpened( __opened ); curve->changeCurrentPoint( __current ); selectCurve( (*__pointList)[ 0 ].x(), (*__pointList)[ 0 ].y() ); } return true; } bool FGSD_MainWindow::newCurve( double __lon, double __lat ) { FGSD_Curve *curve = new FGSD_Curve; _curveList.push_back( curve ); curve->insertPoint( __lon, __lat ); selectCurve( __lon, __lat ); return true; } bool FGSD_MainWindow::removeCurve( double __lon, double __lat ) { bool ret = false; for ( CurveList::iterator ci = _curveList.begin(); ci != _curveList.end(); ++ci ) { FGSD_Curve *curve = *ci; Point3D point = curve->firstPoint(); if ( fabs( point.x() - __lon ) < FGSD_EPSILON && fabs( point.y() - __lat ) < FGSD_EPSILON ) { if ( _curCurve == curve ) _curCurve = 0; _curveList.erase( ci ); delete curve; ret = true; break; } } return ret; } bool FGSD_MainWindow::addCurvePoint( double __lon, double __lat, size_t __index, double __pLon, double __pLat ) { bool ret = false; for ( CurveList::iterator ci = _curveList.begin(); ci != _curveList.end(); ++ci ) { FGSD_Curve *curve = *ci; Point3D point = curve->firstPoint(); if ( fabs( point.x() - __lon ) < FGSD_EPSILON && fabs( point.y() - __lat ) < FGSD_EPSILON ) { curve->changeCurrentPoint( __index ); curve->insertPoint( __pLon, __pLat ); curve->tryToClose( _zLevel ); if ( __index ) selectCurve( __lon, __lat ); else selectCurve( __pLon, __pLat ); ret = true; break; } } return ret; } bool FGSD_MainWindow::removeCurvePoint( double __lon, double __lat, size_t __index ) { bool ret = false; for ( CurveList::iterator ci = _curveList.begin(); ci != _curveList.end(); ++ci ) { FGSD_Curve *curve = *ci; Point3D point = __index ? curve->firstPoint() : curve->secondPoint(); if ( fabs( point.x() - __lon ) < FGSD_EPSILON && fabs( point.y() - __lat ) < FGSD_EPSILON ) { curve->removePoint( __index ); selectCurve( __lon, __lat ); ret = true; break; } } return ret; } bool FGSD_MainWindow::selectCurve( double __lon, double __lat ) { bool ret = false; for ( CurveList::iterator ci = _curveList.begin(); ci != _curveList.end(); ++ci ) { FGSD_Curve *curve = *ci; Point3D point = curve->firstPoint(); if ( fabs( point.x() - __lon ) < FGSD_EPSILON && fabs( point.y() - __lat ) < FGSD_EPSILON ) { curve->selected( true ); _curCurve = curve; ret = true; } else curve->selected( false ); } return ret; } bool FGSD_MainWindow::moveCurvePoint( double __lon, double __lat, size_t __index, double __xdepl, double __ydepl, bool __undo ) { bool ret = false; for ( CurveList::iterator ci = _curveList.begin(); ci != _curveList.end(); ++ci ) { FGSD_Curve *curve = *ci; Point3D point = curve->firstPoint(); if ( __index == 0 && __undo ) point += Point3D( __xdepl, __ydepl, 0 ); double px = point.x(); double py = point.y(); if ( fabs( px - __lon ) < FGSD_EPSILON && fabs( py - __lat ) < FGSD_EPSILON ) { curve->changeMousePoint( __index ); Point3D p = curve->mousePoint(); curve->moveCurrentPoint( p.x() + __xdepl, p.y() + __ydepl ); if ( __index != 0 || __undo ) selectCurve( __lon, __lat ); else selectCurve( __lon + __xdepl, __lat + __ydepl ); ret = true; } } return ret; } bool FGSD_MainWindow::closeCurve( double __lon, double __lat ) { bool ret = false; for ( CurveList::iterator ci = _curveList.begin(); ci != _curveList.end(); ++ci ) { FGSD_Curve *curve = *ci; Point3D point = curve->firstPoint(); if ( fabs( point.x() - __lon ) < FGSD_EPSILON && fabs( point.y() - __lat ) < FGSD_EPSILON ) { curve->tryToClose( _zLevel ); selectCurve( __lon, __lat ); ret = true; } } return ret; } bool FGSD_MainWindow::openCurve( double __lon, double __lat ) { bool ret = false; for ( CurveList::iterator ci = _curveList.begin(); ci != _curveList.end(); ++ci ) { FGSD_Curve *curve = *ci; Point3D point = curve->firstPoint(); if ( fabs( point.x() - __lon ) < FGSD_EPSILON && fabs( point.y() - __lat ) < FGSD_EPSILON ) { curve->open(); selectCurve( __lon, __lat ); ret = true; } } return ret; } bool FGSD_MainWindow::setCurveProperties( double __lon, double __lat, FGSD_Curve::CurveType __type, double __height, const char *__material, bool __water ) { bool ret = false; for ( CurveList::iterator ci = _curveList.begin(); ci != _curveList.end(); ++ci ) { FGSD_Curve *curve = *ci; Point3D point = curve->firstPoint(); if ( fabs( point.x() - __lon ) < FGSD_EPSILON && fabs( point.y() - __lat ) < FGSD_EPSILON ) { curve->curveType( __type ); curve->height( __height ); curve->material( __material ); curve->water( __water ); selectCurve( __lon, __lat ); ret = true; } } return ret; } bool FGSD_MainWindow::embedCurve( double __lon, double __lat ) { bool ret = false; for ( CurveList::iterator ci = _curveList.begin(); ci != _curveList.end(); ++ci ) { FGSD_Curve *curve = *ci; Point3D point = curve->firstPoint(); if ( fabs( point.x() - __lon ) < FGSD_EPSILON && fabs( point.y() - __lat ) < FGSD_EPSILON ) { curve->embedInTiles( this ); ret = true; } } return ret; } bool FGSD_MainWindow::moveStaticObject( const char *__name, double __lon, double __lat, double __elev, double __hdg, double __xdepl, double __ydepl ) { bool ret = false; FGSD_Tile *tile = findTile( __lon, __lat ); if ( tile ) { FGSD_ObjectStatic *obj = tile->findStaticObject( __name, __lon, __lat, __elev, __hdg ); if ( obj ) { if ( !tile->positionInTile( __lon + __xdepl, __lat + __ydepl ) ) { if ( tile->removeObject( obj ) ) { FGSD_Tile *newTile = findTile( __lon + __xdepl, __lat + __ydepl ); if ( newTile ) newTile->addObject( obj ); else tile->addObject( obj ); } } obj->changePosition( __lon + __xdepl, __lat + __ydepl ); ret = true; } } return ret; } bool FGSD_MainWindow::rotateStaticObject( const char *__name, double __lon, double __lat, double __elev, double __hdg, double __rot ) { bool ret = false; FGSD_Tile *tile = findTile( __lon, __lat ); if ( tile ) { FGSD_ObjectStatic *obj = tile->findStaticObject( __name, __lon, __lat, __elev, __hdg ); if ( obj ) { obj->changeHeading( __hdg + __rot ); ret = true; } } return ret; } bool FGSD_MainWindow::addStaticObject( const char *__name, const std::vector &__textures, double __lon, double __lat, double __elev, double __hdg ) { bool ret = false; FGSD_Tile *tile = findTile( __lon, __lat ); if ( tile ) { // Don't add already created object. True if we reload a tile exported from fgsd FGSD_ObjectStatic *obj = tile->findStaticObject( __name, __lon, __lat, __elev, __hdg ); if ( !obj ) { obj = new FGSD_ObjectStatic( __name, __textures ); tile->addObject( obj ); obj->changePosition( __lon, __lat ); obj->changeHeading( __hdg ); ret = true; } } return ret; } bool FGSD_MainWindow::removeStaticObject( const char *__name, double __lon, double __lat, double __elev, double __hdg ) { bool ret = false; FGSD_Tile *tile = findTile( __lon, __lat ); if ( tile ) { FGSD_ObjectStatic *obj = tile->findStaticObject( __name, __lon, __lat, __elev, __hdg ); if ( obj && tile->removeObject( obj ) ) { delete obj; ret = true; } } return ret; } void FGSD_MainWindow::undo_cb(Fl_Widget *o, void *v) { static_cast( v )->undo_cb( o ); } void FGSD_MainWindow::undo_cb(Fl_Widget *o) { setCursor( FL_CURSOR_WAIT ); if ( _actionMgr.undo() ) { updateUndoMenu(); double lon, lat; bool change = _actionMgr.getPosition( true, lon, lat ); if ( change ) { double xcent = _posx + _visw / 2; if ( xcent < _minx ) xcent = _minx; if ( xcent > _maxx ) xcent = _maxx; double ycent = _posy + _vish / 2; if ( ycent < _miny ) ycent = _miny; if ( ycent > _maxy ) ycent = _maxy; if ( lon < xcent - _visw / 2 || lon > xcent + _visw / 2 || lat < ycent - _vish / 2 || lat > ycent + _vish / 2 ) centerPosition( lon, lat ); } if ( _doPostLoad ) postTileLoad( _tileList ); _area->redraw(); } setCursor( FL_CURSOR_DEFAULT ); } void FGSD_MainWindow::redo_cb(Fl_Widget *o, void *v) { static_cast( v )->redo_cb( o ); } void FGSD_MainWindow::redo_cb(Fl_Widget *o) { setCursor( FL_CURSOR_WAIT ); if ( _actionMgr.redo() ) { updateUndoMenu(); double lon, lat; bool change = _actionMgr.getPosition( false, lon, lat ); if ( change ) { double xcent = _posx + _visw / 2; if ( xcent < _minx ) xcent = _minx; if ( xcent > _maxx ) xcent = _maxx; double ycent = _posy + _vish / 2; if ( ycent < _miny ) ycent = _miny; if ( ycent > _maxy ) ycent = _maxy; if ( lon < xcent - _visw / 2 || lon > xcent + _visw / 2 || lat < ycent - _vish / 2 || lat > ycent + _vish / 2 ) centerPosition( lon, lat ); } if ( _doPostLoad ) postTileLoad( _tileList ); _area->redraw(); } setCursor( FL_CURSOR_DEFAULT ); } void FGSD_MainWindow::newAction( FGSD_Action *__action ) { _actionMgr.newAction( __action ); updateUndoMenu(); } void FGSD_MainWindow::step_cb( size_t o, void *v ) { static_cast( v )->step_cb( o ); } void FGSD_MainWindow::step_cb( size_t n ) { _progress->value( _progress->value() + n ); Fl::check(); } int FGSD_FloatInput::handle(int e) { switch ( e ) { case FL_KEYDOWN: if ( Fl::event_key() == 'z' && Fl::event_state(FL_CTRL) ) return Fl_Widget::handle( e ); else if ( Fl::event_key() == 0xffab && Fl::event_state(FL_CTRL) ) { // CTRL NUM+ _mw->incZoomValue( 1 ); return 1; } else if ( Fl::event_key() == 0xffad && Fl::event_state(FL_CTRL) ) { // CTRL NUM- _mw->incZoomValue( -1 ); return 1; } default: return Fl_Float_Input::handle( e ); } }