X-Git-Url: http://git.tdb.fi/?a=blobdiff_plain;f=source%2Fdesigner%2Fdesigner.cpp;h=744f975799f32c0834457df1104dd4b012e52b24;hb=759fee443361cdcafe6fb259df3ba1b05bea0b21;hp=c1bbc3ff17dfb4f56b7bd1fa15200ab9be6d4fb4;hpb=449fb5de95ddb2ac9da4bd72a1c12150505d5549;p=r2c2.git diff --git a/source/designer/designer.cpp b/source/designer/designer.cpp index c1bbc3f..744f975 100644 --- a/source/designer/designer.cpp +++ b/source/designer/designer.cpp @@ -1,356 +1,408 @@ -/* $Id$ - -This file is part of the MSP Märklin suite -Copyright © 2006-2009 Mikkosoft Productions, Mikko Rasa -Distributed under the GPL -*/ - #include +#include #include -#include -#include -#include -#include +#include +#include +#include +#include +#include +#include #include #include -#include +#include +#include +#include #include -#include #include #include #include -#include "libmarklin/tracktype.h" +#include "libr2c2/route.h" +#include "libr2c2/terrain.h" +#include "libr2c2/tracktype.h" +#include "libr2c2/zone.h" +#include "3d/path.h" #include "designer.h" +#include "elevatetool.h" +#include "extendtool.h" #include "input.h" +#include "layoutbar.h" #include "manipulator.h" #include "measure.h" +#include "movetool.h" +#include "objectproperties.h" +#include "objectselecttool.h" +#include "rotatetool.h" +#include "routebar.h" #include "selection.h" +#include "slopetool.h" +#include "svgexporter.h" +#include "terraintool.h" +#include "trackbar.h" +#include "zonebar.h" +#include "zoneproperties.h" using namespace std; -using namespace Marklin; +using namespace R2C2; using namespace Msp; -Application::RegApp Designer::reg; - Designer::Designer(int argc, char **argv): - screen_w(1280), - screen_h(960), - base_mesh(0), - mode(SELECT), - input(0), - cam_yaw(M_PI/2), - cam_pitch(-M_PI/4), - cam_pos(0, -0.5, 0.5), - shift(false), - move_x(0), - move_y(0), - zoom(0), - rotate(0), - pitch(0) + window(1280, 960), + keyboard(window), + mouse(window), + ui_res("r2c2.res"), + root(ui_res, &window, &keyboard, &mouse), + base_object(0), + cur_route(0), + cur_zone(0), + mode(TOOL), + sel_wrap(selection), + cur_tool(0), + keep_status(0) { - DataFile::load(catalogue, "tracks.dat"); + window.set_title("Railway Designer"); + window.signal_close.connect(sigc::bind(sigc::mem_fun(this, &Designer::exit), 0)); - cat_layout=new Layout(catalogue); - cat_layout_3d=new Layout3D(*cat_layout); - - const map &ctracks=catalogue.get_tracks(); - unsigned n=0; - for(map::const_iterator i=ctracks.begin(); i!=ctracks.end(); ++i, ++n) - { - Track *track=new Track(*i->second); - track->set_position(Point((n%11)*0.1-0.5, 0.2-n/11*0.3, 0)); - track->set_rotation(M_PI/2); - cat_layout->add_track(*track); - } + // Setup catalogue and layout + DataFile::load(catalogue, "tracks.dat"); + DataFile::load(catalogue, "terrain.dat"); - manipulator=new Manipulator(*this); - manipulator->signal_status.connect(sigc::mem_fun(this, &Designer::manipulation_status)); - manipulator->signal_done.connect(sigc::mem_fun(this, &Designer::manipulation_done)); + cat_layout_3d = new Layout3D(catalogue.get_layout()); - layout=new Layout(catalogue); - layout_3d=new Layout3D(*layout); + layout = new Layout(catalogue); + layout_3d = new Layout3D(*layout); if(argc>1) { + filename = argv[1]; DataFile::load(*layout, argv[1]); - const list <racks=layout_3d->get_tracks(); - for(list::const_iterator i=ltracks.begin(); i!=ltracks.end(); ++i) + + if(!layout->get_base().empty()) { - if((*i)->get_track().get_sensor_id()) - (*i)->set_color(GL::Color(1, 1, 0.5)); - else if((*i)->get_track().get_turnout_id()) - (*i)->set_color(GL::Color(0.5, 1, 1)); - else if((*i)->get_track().get_flex()) - (*i)->set_color(GL::Color(1, 0.5, 1)); + base_object = new GL::Object; + DataFile::load(*base_object, layout->get_base()); } + } - if(!layout->get_base().empty()) + // Setup OpenGL + cat_view = new View3D(*cat_layout_3d, window.get_width(), window.get_height()); + + main_view = new View3D(*layout_3d, window.get_width(), window.get_height()); + GL::Pipeline *pipeline = &main_view->get_pipeline(); + + GL::Pipeline::Pass *pass = &pipeline->add_pass("unlit"); + pass->set_depth_test(&GL::DepthTest::lequal()); + pass->set_blend(&GL::Blend::alpha()); + + pass = &pipeline->add_pass("blended"); + pass->set_lighting(&layout_3d->get_lighting()); + pass->set_depth_test(&GL::DepthTest::lequal()); + pass->set_blend(&GL::Blend::alpha()); + + pass = &pipeline->add_pass("overlay"); + pass->set_blend(&GL::Blend::alpha()); + + if(base_object) + pipeline->add_renderable(*base_object); + pipeline->add_renderable_for_pass(layout_3d->get_path_scene(), "unlit"); + pipeline->add_renderable_for_pass(layout_3d->get_endpoint_scene(), "unlit"); + + // Setup UI + keyboard.signal_button_press.connect(sigc::bind_return(sigc::mem_fun(this, &Designer::key_press), false)); + mouse.signal_button_press.connect(sigc::bind_return(sigc::mem_fun(this, &Designer::button_press), false)); + root.signal_tooltip.connect(sigc::mem_fun(this, &Designer::tooltip)); + root_layout = new GLtk::Layout; + root_layout->set_margin(0); + root.set_layout(root_layout); + + toolbars.push_back(new Layoutbar(*this)); + toolbars.push_back(new Trackbar(*this)); + toolbars.push_back(new Routebar(*this)); + toolbars.push_back(new Zonebar(*this)); + Toolbar *prev = 0; + for(vector::iterator i=toolbars.begin(); i!=toolbars.end(); ++i) + { + root.add(**i); + if(i!=toolbars.begin()) + (*i)->expand(false); + (*i)->signal_expanded.connect(sigc::hide(sigc::mem_fun(root_layout, &GLtk::Layout::update))); + if(prev) { - base_mesh=new GL::Mesh; - DataFile::load(*base_mesh, layout->get_base()); + root_layout->add_constraint(**i, GLtk::Layout::RIGHT_OF, *prev, 0); + root_layout->add_constraint(**i, GLtk::Layout::COPY_HEIGHT, *prev); } + prev = *i; } - selection=new Selection; - manipulator->set_selection(selection); + GLtk::Panel *statusbar = new GLtk::Panel; + root.add(*statusbar); + statusbar->set_focusable(false); + root_layout->set_gravity(*statusbar, -1, -1); + root_layout->set_expand(*statusbar, true, false); - measure=new Measure(*this); - measure->signal_changed.connect(sigc::mem_fun(this, &Designer::measure_changed)); - measure->signal_done.connect(sigc::mem_fun(this, &Designer::measure_done)); + lbl_status = new GLtk::Label; + statusbar->add(*lbl_status); + lbl_status->set_geometry(GLtk::Geometry(20, 2, 300, 16)); + + pipeline->add_renderable_for_pass(sel_wrap, "unlit"); + overlay = new Overlay3D(ui_res.get_default_font()); + pipeline->add_renderable_for_pass(*overlay, "overlay"); + + camera_ctl = new CameraController(*main_view, keyboard, mouse); + cat_view->get_camera().set_look_direction(GL::Vector3(0, 0.13053, -0.99144)); + cat_view->view_all(true); + main_view->view_all(); + + const set &objects = layout->get_all(); + for(set::const_iterator i=objects.begin(); i!=objects.end(); ++i) + update_object_icon(**i); } Designer::~Designer() { - delete manipulator; - delete selection; - delete layout; + for(vector::iterator i=toolbars.begin(); i!=toolbars.end(); ++i) + delete *i; + delete camera_ctl; + delete overlay; + delete main_view; + delete base_object; delete layout_3d; - delete cat_layout; + delete layout; + delete cat_view; delete cat_layout_3d; - delete measure; } int Designer::main() { - dpy=new Graphics::Display; - wnd=new Graphics::Window(*dpy, screen_w, screen_h); - glc=new Graphics::GLContext(*wnd); - - wnd->signal_close.connect(sigc::bind(sigc::mem_fun(this, &Designer::exit), 0)); - wnd->signal_key_press.connect(sigc::mem_fun(this, &Designer::key_press)); - wnd->signal_key_release.connect(sigc::mem_fun(this, &Designer::key_release)); - wnd->signal_button_press.connect(sigc::mem_fun(this, &Designer::button_press)); - wnd->signal_pointer_motion.connect(sigc::mem_fun(this, &Designer::pointer_motion)); + window.show(); - wnd->show(); + use_select_tool(); - glEnableClientState(GL_VERTEX_ARRAY); - glEnable(GL_DEPTH_TEST); - glEnable(GL_BLEND); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - glEnable(GL_CULL_FACE); + return Application::main(); +} - GL::Texture2D *font_tex=new GL::Texture2D; - font_tex->set_min_filter(GL::LINEAR); - font_tex->load_image("dejavu-20.png"); - font=new GL::Font(); - font->set_texture(*font_tex); - DataFile::load(*font, "dejavu-20.font"); +void Designer::save() +{ + InputDialog *input = new InputDialog(*this, "Save layout", filename); + input->signal_accept.connect(sigc::mem_fun(layout, &Layout::save)); + root.add(*input); + root_layout->set_gravity(*input, 0, 0); +} - mode=SELECT; +void Designer::quit() +{ + exit(0); +} - Application::main(); +void Designer::new_object() +{ + use_select_tool(); - delete font; - delete font_tex; - delete input; + mode = CATALOGUE; + lbl_status->set_text("Select new object or press Esc to cancel"); +} - delete glc; - delete wnd; - delete dpy; +void Designer::erase_objects() +{ + use_select_tool(); - return exit_code; + set objects = selection.get_objects(); + selection.clear(); + for(set::iterator i=objects.begin(); i!=objects.end(); ++i) + { + overlay->clear(layout_3d->get_3d(**i)); + delete *i; + } } -void Designer::map_pointer_coords(int x, int y, float &gx, float &gy) +void Designer::object_properties() { - float cos_pitch=cos(cam_pitch); - float sin_pitch=sin(cam_pitch); - float cos_yaw=cos(cam_yaw); - float sin_yaw=sin(cam_yaw); + use_select_tool(); + if(selection.empty()) + return; - float rx=sin_yaw*0.55228; - float ry=-cos_yaw*0.55228; + ObjectProperties *dlg = new ObjectProperties(selection); + root.add(*dlg); + root_layout->set_gravity(*dlg, 0, 0); - float ux=cos_yaw*-sin_pitch*0.41421; - float uy=sin_yaw*-sin_pitch*0.41421; - float uz=cos_pitch*0.41421; + dlg->signal_response.connect(sigc::mem_fun(this, &Designer::object_properties_response)); +} - float xf=static_cast(x)*2/screen_w-1; - float yf=static_cast(y)*2/screen_h-1; +void Designer::extend_track() +{ + use_tool_with_selected_objects(); +} - float vx=cos_yaw*cos_pitch + xf*rx + yf*ux; - float vy=sin_yaw*cos_pitch + xf*ry + yf*uy; - float vz=sin_pitch + yf*uz; +void Designer::connect_tracks() +{ + use_tool_with_selected_objects()->connect(); +} - gx=cam_pos.x-vx*cam_pos.z/vz; - gy=cam_pos.y-vy*cam_pos.z/vz; +void Designer::flatten_tracks() +{ + use_tool_with_selected_objects()->flatten(); } -void Designer::tick() +void Designer::svg_export() { - const Msp::Time::TimeStamp t=Msp::Time::now(); - float dt=(t-last_tick)/Msp::Time::sec; - last_tick=t; + InputDialog *input = new InputDialog(*this, "SVG export", FS::basepart(filename)+".svg"); + input->signal_accept.connect(sigc::mem_fun(this, &Designer::svg_export_accept)); + root.add(*input); + root_layout->set_gravity(*input, 0, 0); +} - dpy->tick(); +void Designer::edit_route(Route *r) +{ + cur_route = r; + cur_zone = 0; + if(cur_route) + show_route(*cur_route); + else + clear_paths(); +} - if(move_y) - { - cam_pos.x+=cos(cam_yaw)*dt*move_y; - cam_pos.y+=sin(cam_yaw)*dt*move_y; - } - if(move_x) +void Designer::rename_route() +{ + use_select_tool(); + if(!cur_route) + return; + + InputDialog *input = new InputDialog(*this, "Route name", cur_route->get_name()); + input->signal_accept.connect(sigc::mem_fun(this, &Designer::route_name_accept)); + root.add(*input); + root_layout->set_gravity(*input, 0, 0); +} + +void Designer::add_selection_to_route() +{ + if(!cur_route) + return; + + try { - cam_pos.x+=sin(cam_yaw)*dt*move_x; - cam_pos.y+=-cos(cam_yaw)*dt*move_x; + cur_route->add_tracks(selection.get_objects()); } - if(zoom) + catch(const exception &e) { - cam_pos.x+=cos(cam_yaw)*cos(cam_pitch)*dt*zoom; - cam_pos.y+=sin(cam_yaw)*cos(cam_pitch)*dt*zoom; - cam_pos.z+=sin(cam_pitch)*dt*zoom; + lbl_status->set_text(e.what()); } - if(rotate) + + show_route(*cur_route); +} + +void Designer::edit_zone(Zone *z) +{ + cur_zone = z; + cur_route = 0; + if(cur_zone) + show_zone(*cur_zone); + else + clear_paths(); +} + +void Designer::zone_properties() +{ + if(!cur_zone) + return; + + ZoneProperties *zone_prop = new ZoneProperties(*cur_zone); + root.add(*zone_prop); + const GLtk::Geometry &root_geom = root.get_geometry(); + const GLtk::Geometry &dlg_geom = zone_prop->get_geometry(); + zone_prop->set_position((root_geom.w-dlg_geom.w)/2, (root_geom.h-dlg_geom.h)/2); +} + +void Designer::add_selection_to_zone() +{ + if(!cur_zone) + return; + + try { - float vx=cos(cam_yaw)*cos(cam_pitch); - float vy=sin(cam_yaw)*cos(cam_pitch); - float vz=sin(cam_pitch); - - float gx=cam_pos.x-vx*cam_pos.z/vz; - float gy=cam_pos.y-vy*cam_pos.z/vz; - float d=sqrt(vx*vx+vy*vy)*cam_pos.z/vz; - - cam_yaw+=M_PI*dt*rotate; - if(cam_yaw>M_PI*2) - cam_yaw-=M_PI*2; - else if(cam_yaw<0) - cam_yaw+=M_PI*2; - - cam_pos.x=gx+cos(cam_yaw)*d; - cam_pos.y=gy+sin(cam_yaw)*d; + cur_zone->add_tracks(selection.get_objects()); } - if(pitch) + catch(const exception &e) { - cam_pitch+=M_PI/2*dt*pitch; - if(cam_pitch>M_PI/12) - cam_pitch=M_PI/12; - else if(cam_pitch<-M_PI/2) - cam_pitch=-M_PI/2; + lbl_status->set_text(e.what()); } - if(tooltip_timeout && t>tooltip_timeout) - { - Track3D *t3d=0; + show_zone(*cur_zone); +} - if(mode==CATALOGUE) - t3d=pick_track(pointer_x, pointer_y); - else - t3d=pick_track(pointer_x, pointer_y); +Vector Designer::map_pointer_to_ground(const Vector &p) +{ + GL::Vector4 vec = main_view->get_camera().unproject(GL::Vector4(p.x, p.y, 0, 0)); + const GL::Vector3 &pos = main_view->get_camera().get_position(); - if(t3d) - { - const Track &track=t3d->get_track(); - const TrackType &ttype=track.get_type(); - ostringstream ss; - ss.precision(2); - ss<is_done()) + { + cur_tool->update_selection(selection); + use_select_tool(); } + keep_status = 0; + + window.tick(); + root.tick(); + camera_ctl->tick(dt); render(); - glc->swap_buffers(); + window.swap_buffers(); } -/*** private ***/ - -void Designer::key_press(unsigned code, unsigned mod, wchar_t ch) +void Designer::key_press(unsigned key) { - unsigned key=Msp::Input::key_from_sys(code); + bool shift = keyboard.get_button_state(Input::KEY_SHIFT_L) || keyboard.get_button_state(Input::KEY_SHIFT_R); - if(mode==INPUT) - { - input->key_press(key, mod, ch); - return; - } - - if(key==Msp::Input::KEY_SHIFT_L || key==Msp::Input::KEY_SHIFT_R) - shift=true; - - if(key==Msp::Input::KEY_N) - mode=CATALOGUE; + if(key==Msp::Input::KEY_N && shift) + use_tool_with_selected_objects(); + else if(key==Msp::Input::KEY_N) + new_object(); else if(key==Msp::Input::KEY_G) - { - manipulator->start_move(); - mode=MANIPULATE; - } + use_tool_with_selected_objects(); else if(key==Msp::Input::KEY_R) - { - manipulator->start_rotate(); - mode=MANIPULATE; - } + use_tool_with_selected_objects(); else if(key==Msp::Input::KEY_D) { - manipulator->duplicate(); - manipulator->start_move(); - mode=MANIPULATE; + const set &sel_objs = selection.get_objects(); + list new_objs; + for(set::iterator i=sel_objs.begin(); i!=sel_objs.end(); ++i) + { + Object *obj = (*i)->clone(layout); + for(list::iterator j=new_objs.begin(); j!=new_objs.end(); ++j) + obj->link_to(**j); + new_objs.push_back(obj); + } + + selection.replace(new_objs.begin(), new_objs.end()); + + use_tool_with_selected_objects(); } else if(key==Msp::Input::KEY_W) - { - input=new ::Input(*this, "Filename"); - input->signal_cancel.connect(sigc::mem_fun(this, &Designer::input_dismiss)); - input->signal_accept.connect(sigc::mem_fun(this, &Designer::save_accept)); - mode=INPUT; - } - else if(key==Msp::Input::KEY_PLUS) - selection->select_more(); - else if(key==Msp::Input::KEY_L && (mod&1)) - { - const set &tracks=layout->get_tracks(); - float len=0; - for(set::const_iterator i=tracks.begin(); i!=tracks.end(); ++i) - len+=(*i)->get_type().get_total_length(); - cout<<"Total length: "<select_linked(); + save(); else if(key==Msp::Input::KEY_M) - { - measure->start(); - mode=MEASURE; - } + use_tool(); else if(key==Msp::Input::KEY_Z) - { - manipulator->start_elevate(); - mode=MANIPULATE; - } + use_tool_with_selected_objects(); else if(key==Msp::Input::KEY_ESC) { - if(mode==MANIPULATE) - manipulator->cancel(); - else if(mode==CATALOGUE) - mode=SELECT; - else - selection->clear(); + if(mode==CATALOGUE) + use_select_tool(); } else if(key==Msp::Input::KEY_X) + erase_objects(); + else if(key==Msp::Input::KEY_F && shift) { - set tracks=selection->get_tracks(); - selection->clear(); - for(set::iterator i=tracks.begin(); i!=tracks.end(); ++i) - { - layout->remove_track(**i); - delete *i; - } - } - else if(key==Msp::Input::KEY_F && (mod&1)) - { - const set &tracks=selection->get_tracks(); - const set <racks=layout->get_tracks(); + const set &tracks = selection.get_objects(); + const set <racks = layout->get_all(); for(set::const_iterator i=tracks.begin(); i!=tracks.end(); ++i) { (*i)->set_flex(!(*i)->get_flex()); @@ -359,337 +411,244 @@ void Designer::key_press(unsigned code, unsigned mod, wchar_t ch) if(*j!=*i) (*i)->snap_to(**j, true); - Track3D &t3d=layout_3d->get_track(**i); - if((*i)->get_flex()) - t3d.set_color(GL::Color(1, 0.5, 1)); - else - t3d.set_color(GL::Color(1, 1, 1)); + update_object_icon(**i); } } else if(key==Msp::Input::KEY_F) - manipulator->flatten(); - else if(key==Msp::Input::KEY_E && (mod&1)) - manipulator->even_slope(true); + use_tool_with_selected_objects()->flatten(); + else if(key==Msp::Input::KEY_E && shift) + use_tool_with_selected_objects()->even_slope(true); else if(key==Msp::Input::KEY_E) - manipulator->even_slope(); - else if(key==Msp::Input::KEY_T) + use_tool_with_selected_objects()->even_slope(); + else if(key==Msp::Input::KEY_A) { - Track *track=selection->get_track(); - if(selection->size()==1 && track->get_type().get_n_routes()>1) - { - ostringstream ss; - ss<get_turnout_id(); - input=new ::Input(*this, "Turnout ID", ss.str()); - input->signal_cancel.connect(sigc::mem_fun(this, &Designer::input_dismiss)); - input->signal_accept.connect(sigc::mem_fun(this, &Designer::turnout_id_accept)); - mode=INPUT; - } + if(cur_route) + add_selection_to_route(); + else if(cur_zone) + add_selection_to_zone(); } - else if(key==Msp::Input::KEY_S) + else if(key==Msp::Input::KEY_C) + use_tool_with_selected_objects()->connect(); + else if(key==Msp::Input::KEY_V) + svg_export(); + else if(key==Msp::Input::KEY_P) + object_properties(); + else if(key==Msp::Input::KEY_TAB) { - const set &tracks=selection->get_tracks(); - bool ok=false; - int id=-1; - for(set::const_iterator i=tracks.begin(); i!=tracks.end(); ++i) - { - if((*i)->get_type().get_n_routes()==1) - ok=true; - if(static_cast((*i)->get_sensor_id())!=id) - { - if(id==-1) - id=(*i)->get_sensor_id(); - else - id=-2; - } - } - if(ok) - { - ostringstream ss; - if(id>=0) - ss<signal_cancel.connect(sigc::mem_fun(this, &Designer::input_dismiss)); - input->signal_accept.connect(sigc::mem_fun(this, &Designer::sensor_id_accept)); - mode=INPUT; - } + Object *obj = selection.get_object(); + if(Terrain *terrain = dynamic_cast(obj)) + use_tool(new TerrainTool(*this, keyboard, mouse, *terrain)); } - else if(key==Msp::Input::KEY_RIGHT) - rotate=-1; - else if(key==Msp::Input::KEY_LEFT) - rotate=1; - else if(key==Msp::Input::KEY_UP) - move_y=1; - else if(key==Msp::Input::KEY_DOWN) - move_y=-1; - else if(key==Msp::Input::KEY_INSERT) - zoom=-1; - else if(key==Msp::Input::KEY_PGUP) - zoom=1; - else if(key==Msp::Input::KEY_HOME) - pitch=1; - else if(key==Msp::Input::KEY_END) - pitch=-1; - else if(key==Msp::Input::KEY_DELETE) - move_x=-1; - else if(key==Msp::Input::KEY_PGDN) - move_x=1; -} - -void Designer::key_release(unsigned code, unsigned) -{ - unsigned key=Msp::Input::key_from_sys(code); - - if(mode==INPUT) - return; - - if(key==Msp::Input::KEY_SHIFT_L || key==Msp::Input::KEY_SHIFT_R) - shift=false; - else if(key==Msp::Input::KEY_RIGHT || key==Msp::Input::KEY_LEFT) - rotate=0; - else if(key==Msp::Input::KEY_UP || key==Msp::Input::KEY_DOWN) - move_y=0; - else if(key==Msp::Input::KEY_INSERT || key==Msp::Input::KEY_PGUP) - zoom=0; - else if(key==Msp::Input::KEY_HOME || key==Msp::Input::KEY_END) - pitch=0; - else if(key==Msp::Input::KEY_DELETE || key==Msp::Input::KEY_PGDN) - move_x=0; } -void Designer::button_press(int x, int y, unsigned btn, unsigned) +template +T *Designer::use_tool_with_selected_objects() { - y=screen_h-y-1; + T *tool = new T(*this, keyboard, mouse, selection.get_objects()); + use_tool(tool); + return tool; +} - float gx, gy; - map_pointer_coords(x, y, gx, gy); +template +T *Designer::use_tool() +{ + T *tool = new T(*this, keyboard, mouse); + use_tool(tool); + return tool; +} - if(mode==CATALOGUE) +void Designer::use_tool(Tool *tool) +{ + if(cur_tool) { - if(btn==1) - { - Track3D *ctrack=pick_track(x, y); - if(ctrack) - { - Track *track=ctrack->get_track().copy(); - track->set_position(Point(gx, gy, 0)); - layout->add_track(*track); + delete cur_tool; + cur_tool = 0; + } - selection->clear(); - selection->add_track(track); + cur_tool = tool; + cur_tool->signal_status.connect(sigc::mem_fun(this, &Designer::tool_status)); + if(keep_status<2) + tool_status(tool->get_status()); + mode = TOOL; + keep_status = 1; +} - mode=SELECT; - } - } - else - mode=SELECT; - } - else if(mode==SELECT) +void Designer::use_select_tool() +{ + use_tool(new ObjectSelectTool(*this, keyboard, mouse, selection)); +} + +void Designer::button_press(unsigned btn) +{ + Vector pointer(mouse.get_axis_value(0), mouse.get_axis_value(1), 0); + Vector ground = map_pointer_to_ground(pointer); + + if(mode==CATALOGUE) { + Object *obj = 0; if(btn==1) + obj = pick_object(pointer); + + if(obj) { - Track3D *track=pick_track(x, y); - if(track) - { - if(!shift) - selection->clear(); - selection->toggle_track(&track->get_track()); - } + obj = obj->clone(layout); + obj->set_position(ground); + + selection.clear(); + selection.add_object(obj); } + + if(obj || btn==3) + use_select_tool(); } - else if(mode==MANIPULATE) - manipulator->button_press(x, y, gx, gy, btn); - else if(mode==MEASURE) - measure->button_press(x, y, gx, gy, btn); } -void Designer::pointer_motion(int x, int y) +void Designer::render() { - y=screen_h-y-1; - - float gx, gy; - map_pointer_coords(x, y, gx, gy); + GL::Framebuffer::system().clear(GL::COLOR_BUFFER_BIT|GL::DEPTH_BUFFER_BIT); - if(mode==SELECT || mode==CATALOGUE) - { - pointer_x=x; - pointer_y=y; - tooltip_timeout=Msp::Time::now()+100*Msp::Time::msec; - } + View3D *view = (mode==CATALOGUE ? cat_view : main_view); + view->render(); - if(mode!=INPUT) - { - manipulator->pointer_motion(x, y, gx, gy); - measure->pointer_motion(x, y, gx, gy); - } - - if(mode==MEASURE || mode==MANIPULATE) - move_tooltip(x, y); + root.render(); } -void Designer::project_3d() +Object *Designer::pick_object(const Vector &pointer) { - glMatrixMode(GL_PROJECTION); - glLoadIdentity(); - glFrustum(-0.055228, 0.055228, -0.041421, 0.041421, 0.1, 10); - glMatrixMode(GL_MODELVIEW); -} + View3D &view = *(mode==CATALOGUE ? cat_view : main_view); + const GL::Vector3 &cpos = view.get_camera().get_position(); + GL::Vector4 cray = view.get_camera().unproject(GL::Vector4(pointer.x, pointer.y, 0, 0)); -void Designer::apply_camera() -{ - glLoadIdentity(); - if(mode==CATALOGUE) - glTranslatef(0, 0, -1); - else - { - glRotatef(-cam_pitch*180/M_PI-90, 1, 0, 0); - glRotatef(90-cam_yaw*180/M_PI, 0, 0, 1); - glTranslatef(-cam_pos.x, -cam_pos.y, -cam_pos.z); - } + return view.get_layout().get_layout().pick(Ray(cpos, Vector(cray))); } -void Designer::render() +void Designer::update_object_icon(Object &obj) { - glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT); - glEnable(GL_DEPTH_TEST); + Object3D &obj3d = layout_3d->get_3d(obj); + overlay->clear(obj3d); - project_3d(); - apply_camera(); - if(mode==CATALOGUE) - cat_layout_3d->render(); - else + if(Track *track = dynamic_cast(&obj)) { - if(base_mesh) + if(track->get_flex()) + overlay->add_graphic(obj3d, "flex"); + + if(unsigned saddr = track->get_sensor_address()) { - GL::Texture::unbind(); - base_mesh->draw(); + overlay->add_graphic(obj3d, "trackcircuit"); + overlay->set_label(obj3d, lexical_cast(saddr)); + } + else if(track->get_type().is_turnout()) + { + unsigned taddr = track->get_turnout_address(); + if(taddr<0x800) + { + overlay->add_graphic(obj3d, "turnout"); + overlay->set_label(obj3d, lexical_cast(taddr)); + } } - layout_3d->render(true); - manipulator->render(); - if(mode==MEASURE) - measure->render(); } - - glMatrixMode(GL_PROJECTION); - glLoadIdentity(); - glOrtho(0, screen_w, 0, screen_h, 0, 1); - glMatrixMode(GL_MODELVIEW); - glLoadIdentity(); - - glDisable(GL_DEPTH_TEST); - - if(!tooltip.empty()) + else if(Signal *signal = dynamic_cast(&obj)) { - glTranslatef(tooltip_x, tooltip_y, 0); - glScalef(20, 20, 20); - float width=font->get_string_width(tooltip); - glColor4f(0, 0, 0, 0.5); - glBegin(GL_QUADS); - glVertex2f(0, 0); - glVertex2f(width, 0); - glVertex2f(width, 1); - glVertex2f(0, 1); - glEnd(); - glColor4f(1, 1, 1, 1); - font->draw_string(tooltip); + overlay->add_graphic(obj3d, "signal"); + overlay->set_label(obj3d, lexical_cast(signal->get_address())); + } + else if(BeamGate *gate = dynamic_cast(&obj)) + { + overlay->add_graphic(obj3d, "beamgate"); + overlay->set_label(obj3d, lexical_cast(gate->get_address())); } - - if(mode==INPUT) - input->render(); } -Track3D *Designer::pick_track(int x, int y) +void Designer::tool_status(const string &status) { - Layout3D *l=layout_3d; - if(mode==CATALOGUE) - l=cat_layout_3d; - - float xx=(static_cast(x-static_cast(screen_w)/2)/screen_h)*0.82843; - float yy=(static_cast(y)/screen_h-0.5)*0.82843; - float size=4.0/screen_h*0.82843; - - project_3d(); - apply_camera(); - - return l->pick_track(xx, yy, size); + lbl_status->set_text(status); + if(keep_status==1) + keep_status = 2; } -void Designer::manipulation_status(const string &status) +void Designer::object_properties_response(int) { - tooltip=status; + const set &objects = selection.get_objects(); + for(set::const_iterator i=objects.begin(); i!=objects.end(); ++i) + update_object_icon(**i); } -void Designer::manipulation_done(bool) +void Designer::route_name_accept(const string &text) { - mode=SELECT; + if(cur_route) + cur_route->set_name(text); } -void Designer::measure_changed() +void Designer::svg_export_accept(const string &text) { - float pard=measure->get_parallel_distance()*1000; - float perpd=measure->get_perpendicular_distance()*1000; - float d=sqrt(pard*pard+perpd*perpd); - float adiff=measure->get_angle_difference()*180/M_PI; - ostringstream ss; - ss.precision(3); - ss<<"Par "<get_type(); + string info = format("%d %s", otype.get_article_number(), otype.get_name()); + if(Track *track = dynamic_cast(obj)) + { + if(mode!=CATALOGUE && abs(track->get_tilt()).radians()>1e-4) + info += format(" (slope %.1f%%)", abs(tan(track->get_tilt())*100)); + if(track->get_type().is_turnout()) + info += format(" (turnout %d)", track->get_turnout_address()); + else if(track->get_sensor_address()) + info += format(" (sensor %d)", track->get_sensor_address()); + } + if(mode==CATALOGUE) + { + const string &descr = otype.get_description(); + if(!descr.empty()) + { + info += '\n'; + info += otype.get_description(); + } + } + return info; + } -void Designer::move_tooltip(int x, int y) -{ - int w=static_cast(font->get_string_width(tooltip)*20); - tooltip_x=max(min(static_cast(screen_w)-w, x), 0); - tooltip_y=max(min(static_cast(screen_h)-20, y), 0); + return string(); } -void Designer::save_accept() +void Designer::clear_paths() { - layout->save(input->get_text()); - - input_dismiss(); + for(list::iterator i=highlight_paths.begin(); i!=highlight_paths.end(); ++i) + delete *i; + highlight_paths.clear(); } -void Designer::turnout_id_accept() +void Designer::show_route(const Route &route) { - Track *track=selection->get_track(); - unsigned id=lexical_cast(input->get_text()); - track->set_turnout_id(id); - - Track3D &t3d=layout_3d->get_track(*track); - if(id) - t3d.set_color(GL::Color(0.5, 1, 1)); - else - t3d.set_color(GL::Color(1, 1, 1)); - - input_dismiss(); -} + clear_paths(); -void Designer::sensor_id_accept() -{ - const set &tracks=selection->get_tracks(); - unsigned id=lexical_cast(input->get_text()); - for(set::const_iterator i=tracks.begin(); i!=tracks.end(); ++i) + const set &rtracks = route.get_tracks(); + for(set::iterator i=rtracks.begin(); i!=rtracks.end(); ++i) { - (*i)->set_sensor_id(id); - - Track3D &t3d=layout_3d->get_track(**i); - if(id) - t3d.set_color(GL::Color(1, 1, 0.5)); - else - t3d.set_color(GL::Color(1, 1, 1)); + Track3D &t3d = layout_3d->get_3d(**i); + Path3D *path = new Path3D(t3d); + path->set_color(GL::Color(0.5, 0.8, 1.0)); + if((*i)->get_type().is_turnout()) + path->set_path(route.get_turnout((*i)->get_turnout_address())); + highlight_paths.push_back(path); } - - input_dismiss(); } -void Designer::input_dismiss() +void Designer::show_zone(const Zone &zone) { - delete input; - input=0; - mode=SELECT; + clear_paths(); + + const Zone::TrackSet &ztracks = zone.get_tracks(); + for(Zone::TrackSet::const_iterator i=ztracks.begin(); i!=ztracks.end(); ++i) + { + Track3D &t3d = layout_3d->get_3d(**i); + Path3D *path = new Path3D(t3d); + path->set_color(GL::Color(0.8, 1.0, 0.5)); + highlight_paths.push_back(path); + } }