Index: gui/road_line_builder_frame.cc =================================================================== --- gui/road_line_builder_frame.cc (nonexistent) +++ gui/road_line_builder_frame.cc (working copy) @@ -0,0 +1,457 @@ +#include "road_line_builder_frame.h" +#include "../dataobj/translator.h" +#include "../dataobj/crossing_logic.h" +#include "components/gui_textinput.h" +#include "../utils/simstring.h" +#include "schedule_gui.h" +#include "../dataobj/schedule.h" +#include "../simtool.h" +#include "../simline.h" +#include +#include +#include +#include +#include "../descriptor/building_desc.h" +#include "station_building_select.h" +#include "../bauer/hausbauer.h" +#include "halt_info.h" +#include "../display/viewport.h" + +road_line_builder_frame_t::road_line_builder_frame_t(player_t* player_): +gui_frame_t(translator::translate("Road Line Builder")), +player(player_), +stats(player), +scrolly(&stats), +schedule(new truck_schedule_t()), +mode(undefined_mode) + + +{ + + set_windowsize(scr_size(bt_add.get_size().w * 3, 256)); + scr_coord_val ypos = D_H_SPACE; + tstrncpy(ibuf, "", lengthof(ibuf)); + input.set_pos(scr_coord(BUTTON1_X, ypos)); + input.set_size(scr_size(D_BUTTON_WIDTH, D_EDIT_HEIGHT)); + input.set_text(ibuf, 128); + + + lb_counter.set_text("#"); + lb_counter.set_pos(scr_coord(input.get_pos().x + input.get_size().w + D_V_SPACE, ypos)); + add_component(&lb_counter); + counter.set_pos(scr_coord(lb_counter.get_pos().x+lb_counter.get_size().w+D_V_SPACE, ypos)); + counter.set_width_by_len(4); + counter.align_to(&input, ALIGN_CENTER_V); + counter.set_value(1); + counter.set_limits(0, 9999); + counter.add_listener(this); + add_component(&counter); + lb_counter.align_to(&counter, ALIGN_CENTER_V); + + + lb_digits.set_text("Digits:"); + lb_digits.set_pos(scr_coord(counter.get_pos().x+counter.get_size().w+D_V_SPACE, ypos)); + add_component(&lb_digits); + ninput.set_pos(scr_coord(lb_digits.get_pos().x+lb_digits.get_size().w+D_V_SPACE,ypos)); + ninput.set_width_by_len(2); + ninput.align_to(&input, ALIGN_CENTER_V); + ninput.set_value(2); + ninput.set_limits(0, max_digits); + ninput.add_listener(this); + lb_digits.align_to(&ninput, ALIGN_CENTER_V); + add_component(&ninput); + + ypos += D_H_SPACE+input.get_size().h; + bt_add.init(button_t::roundbox_state, "Add Stop", scr_coord(BUTTON1_X, ypos)); + bt_add.set_tooltip("Appends stops at the end of the schedule"); + bt_add.add_listener(this); + bt_add.pressed = false; + add_component(&bt_add); + + bt_remove.init(button_t::roundbox_state, "Del Stop", scr_coord(BUTTON2_X, ypos)); + bt_remove.set_tooltip("Delete the current stop"); + bt_remove.add_listener(this); + bt_remove.pressed = false; + add_component(&bt_remove); + + ypos += D_H_SPACE + bt_add.get_size().h; + + + scrolly.set_pos(scr_coord(BUTTON1_X, ypos)); + scrolly.set_show_scroll_x(true); + scrolly.set_scroll_amount_y(LINESPACE + 1); + add_component(&scrolly); + + bt_finish.init(button_t::box, "Create Line"); + bt_finish.set_tooltip("Crete Line for selection"); + bt_finish.add_listener(this); + add_component(&bt_finish); + + //bt_refresh.init(button_t::box, "Dispaly Path"); + //bt_refresh.set_tooltip("Display and update path"); + //bt_refresh.add_listener(this); + //add_component(&bt_refresh); + + add_component(&input); + add_component(&bt_add); + add_component(&bt_remove); + add_component(&bt_finish); + //cursor.y += D_EDIT_HEIGHT; + //cursor.y += D_V_SPACE; + set_min_windowsize(scr_size(BUTTON4_X, 200)); + set_resizemode(diagonal_resize); + set_windowsize(scr_size(BUTTON4_X, 200)); + +} + +road_line_builder_frame_t::~road_line_builder_frame_t() +{ + if (player) { + update_tool(false); + } + delete schedule; + +} + +bool road_line_builder_frame_t::action_triggered(gui_action_creator_t * comp, value_t extra) +{ + //from schedule + if (comp == &bt_add) { + stats.set_schedule(schedule); + stats.highlight_schedule(schedule, true); + mode = adding; + bt_add.pressed = true; + bt_remove.pressed = false; + update_tool(true); + } + else if (comp == &bt_remove) { + mode = removing; + bt_add.pressed = false; + bt_remove.pressed = true; + update_tool(false); + } + else if (comp == &bt_refresh) + { + schedule->cleanup(); + if (schedule->entries.get_count() >= 2) + { + std::vector> paths = get_paths(); + for (auto const& path : paths) + { + mark_path(path, true); + } + } + } + + else if(comp == &bt_finish) + { + stats.highlight_schedule(schedule, false); + mode = undefined_mode; + update_tool(false); + bt_add.pressed = false; + bt_remove.pressed = false; + create_line(); + } + return false; +} + +void road_line_builder_frame_t::create_line() +{ + + schedule_t *line_schedule = new truck_schedule_t(); + std::vectorstations = get_station_coords(get_paths()); + for(auto const& field : stations) + { + build_station(field); + line_schedule->append(welt->lookup_kartenboden(field.get_2d())); + } + line_schedule->add_return_way(); + linehandle_t line = player->simlinemgmt.create_line(simline_t::truckline, player, line_schedule); + line->set_name(get_next_line_name().c_str()); + + + schedule = new truck_schedule_t(); + stats.set_schedule(schedule); + +} +std::string road_line_builder_frame_t::get_next_line_name() +{ + std::string name = ibuf; + + if(ninput.get_value()>0) + { + std::stringstream ss; + ss << std::setw(ninput.get_value()) << std::setfill('0') << counter.get_value(); + counter.set_value(counter.get_value() + 1); + name.append(" "); + name.append(ss.str()); + } + + return name; +} + +void road_line_builder_frame_t::update_tool(bool set) +{ + //from schedule + if (!set || mode == removing || mode == undefined_mode) { + // reset tools, if still selected ... + if (welt->get_tool(player->get_player_nr()) == tool_t::general_tool[TOOL_SCHEDULE_ADD]) { + if (tool_t::general_tool[TOOL_SCHEDULE_ADD]->get_default_param() == (const char *)schedule) { + welt->set_tool(tool_t::general_tool[TOOL_QUERY], player); + } + } + } + else { + // .. or set them again + if (mode == adding) { + tool_t::general_tool[TOOL_SCHEDULE_ADD]->set_default_param((const char *)schedule); + welt->set_tool(tool_t::general_tool[TOOL_SCHEDULE_ADD], player); + } + } +} + +void road_line_builder_frame_t::set_windowsize(scr_size size) +{ + gui_frame_t::set_windowsize(size); + bt_finish.set_pos(scr_coord(BUTTON1_X, size.h - D_H_SPACE - D_BUTTON_HEIGHT-25));//??? + bt_refresh.set_pos(scr_coord(BUTTON2_X, size.h - D_H_SPACE - D_BUTTON_HEIGHT - 25));//??? + scrolly.set_size(scr_size(size.w - D_V_SPACE * 2, size.h - 75)); + +} + +bool road_line_builder_frame_t::infowin_event(const event_t *ev) +{ + //from schedule + if ((ev)->ev_class == EVENT_CLICK && !((ev)->ev_code == MOUSE_WHEELUP || (ev)->ev_code == MOUSE_WHEELDOWN) ) { + + if (ev->my >= scrolly.get_pos().y + D_TITLEBAR_HEIGHT) { + // we are now in the multiline region ... + const int line = (ev->my - scrolly.get_pos().y + scrolly.get_scroll_y() - D_TITLEBAR_HEIGHT) / schedule_gui_t::entry_height; + + if (line >= 0 && line < schedule->get_count()) { + if (IS_RIGHTCLICK(ev) || ev->mx < 16) { + // just center on it + welt->get_viewport()->change_world_position(schedule->entries[line].pos); + } + else if (ev->mx < scrolly.get_size().w - 11) { + schedule->set_current_stop(line); + if (mode == removing) { + stats.highlight_schedule(schedule, false); + schedule->remove(); + action_triggered(&bt_add, value_t()); + } + } + } + } + } + else if (ev->ev_class == INFOWIN && ev->ev_code == WIN_CLOSE) { + stats.highlight_schedule(schedule, false); + } + return gui_frame_t::infowin_event(ev); +} +void road_line_builder_frame_t::mark_paths(std::vector < std::vector> paths, bool marking) +{ + for (auto const& path : paths) + { + mark_path(path, marking); + } +} + + +void road_line_builder_frame_t::mark_path(std::vector path, bool marking) +{ + for (auto const& field : path) + { + grund_t* const grund = welt->lookup_kartenboden(field.get_2d()); + for (uint idx = 0; idx < grund->get_top(); idx++) { + obj_t *obj = grund->obj_bei(idx); + if (marking) { + if (!obj->is_moving()) { + obj->set_flag(obj_t::highlight); + } + } + else { + obj->clear_flag(obj_t::highlight); + } + } + grund->set_flag(grund_t::dirty); + } +} + +std::vector road_line_builder_frame_t::get_station_coords(std::vector> paths) +{ + //todo maybe better multiple options? + uint32 const cov2 = 2 * welt->get_settings().get_station_coverage() +1; + std::vector stations; + koord3d currentBest; + bool is_better = false; + bool last_ns = false; + for(auto const& path : paths) + { + for(auto const& field: path) + { + grund_t *grund = welt->lookup_kartenboden(field.get_2d()); + weg_t *weg = grund->get_weg(waytype_t::road_wt); + + if(grund->get_grund_hang()==0 && can_station(weg)&&weg!=NULL) + { + if(stations.empty()) + { + stations.push_back(field); + ribi_t::ribi ribi = weg->get_ribi(); + last_ns = ribi_t::is_straight_ns(ribi); + }else + { + koord3d last = stations.back(); + uint32 distance = get_distance_1D(last, field); + + if(distance1) + { + ribi_t::ribi ribi = weg->get_ribi(); + bool new_ns = ribi_t::is_straight_ns(ribi); + if(new_ns==last_ns) + { + currentBest = field; + is_better = true; + }else + { + stations.push_back(field); + is_better = false; + last_ns = new_ns; + } + + }else if(distance==cov2) + { + stations.push_back(field); + is_better = false; + ribi_t::ribi ribi = weg->get_ribi(); + last_ns = ribi_t::is_straight_ns(ribi); + }else if(distance>cov2){ + if(currentBest!=koord3d()){ + stations.push_back(currentBest); + ribi_t::ribi ribi = welt->lookup_kartenboden(currentBest.get_2d())->get_weg(waytype_t::road_wt)->get_ribi(); + last_ns = ribi_t::is_straight_ns(ribi); + currentBest = field; + is_better = true; + }else{ + stations.push_back(field); + is_better = false; + ribi_t::ribi ribi = weg->get_ribi(); + last_ns = ribi_t::is_straight_ns(ribi); + } + + } + } + } + } + } + + + if(is_better&&stations.back()!=paths.back().back()) + { + stations.push_back(currentBest); + } + return stations; +} + +uint32 road_line_builder_frame_t::get_distance_1D(koord3d a, koord3d b) +{ + if(a.x==b.x) + { + return abs(a.y - b.y); + } + else if(a.y==b.y) + { + return abs(a.x - b.x); + }else + { + return koord_distance(a, b)-1; + } +} + +bool road_line_builder_frame_t::can_station(weg_t *weg) +{ + ribi_t::ribi ribi = weg->get_ribi(); + return ribi_t::is_straight(ribi) && !weg->is_diagonal() && !weg->is_crossing(); + +} + +void road_line_builder_frame_t::build_station(koord3d koord3) +{ + //from ai + //todo let player chose? + const building_desc_t* desc = hausbauer_t::get_random_station(building_desc_t::generic_stop, road_wt, welt->get_timeline_year_month(), haltestelle_t::PAX); + //const building_desc_t* desc = hausbauer_t::get_desc("big_early_bus_stop"); + + grund_t *gr = welt->lookup_kartenboden(koord3.get_2d()); + koord3d pos = gr ? gr->get_pos() : koord3d::invalid; + const char *old_param = tool_t::general_tool[TOOL_BUILD_STATION]->get_default_param(); + tool_t::general_tool[TOOL_BUILD_STATION]->set_default_param(desc->get_name()); + const char * err = tool_t::general_tool[TOOL_BUILD_STATION]->work(player, pos); + if (err) { + if (*err) { + dbg->message("road_line_builder_frame_t::build_station", "failed for tool %i at (%s) because of \"%s\"", TOOL_BUILD_STATION, pos.get_str(), err); + } + else { + dbg->message("road_line_builder_frame_t::build_station", "not successful for tool %i at (%s)", TOOL_BUILD_STATION, pos.get_str()); + } + } + tool_t::general_tool[TOOL_BUILD_STATION]->set_default_param(old_param); + } + +std::vector> road_line_builder_frame_t::get_paths() +{ + //todo use path search? + std::vector> paths; + for (int i = 0; i < schedule->entries.get_count() - 1; i++) + { + //either x or y need to be the same + schedule_entry_t e1 = schedule->entries[i]; + schedule_entry_t e2 = schedule->entries[i + 1]; + + paths.push_back(get_path(e1, e2)); + + + } + return paths; +} + +std::vector road_line_builder_frame_t::get_path(schedule_entry_t e1, schedule_entry_t e2) +{ + std::vector path; + if (e1.pos.y == e2.pos.y) + { + int op = 0; + if (e1.pos.x < e2.pos.x) + { + op = 1; + } + else + { + op = -1; + } + for (int x = e1.pos.x; x != e2.pos.x; x += op) + { + path.push_back(koord3d(x, e1.pos.y, e1.pos.z)); + } + } + else if (e1.pos.x == e2.pos.x) + { + int op = 0; + if (e1.pos.y < e2.pos.y) + { + op = 1; + } + else + { + op = -1; + } + for (int y = e1.pos.y; y != e2.pos.y; y += op) + { + path.push_back(koord3d(e1.pos.x, y, e1.pos.z)); + } + } + path.push_back(e2.pos); + return path; +} + Index: gui/road_line_builder_frame.h =================================================================== --- gui/road_line_builder_frame.h (nonexistent) +++ gui/road_line_builder_frame.h (working copy) @@ -0,0 +1,84 @@ +#ifndef road_line_builder_frame_t_h +#define road_line_builder_frame_t_h +#include "gui_frame.h" +#include "components/gui_textinput.h" +#include "components/gui_scrollpane.h" +#include "components/gui_divider.h" +#include "schedule_gui.h" +#include "../bauer/wegbauer.h" +#include +#include "../boden/wege/weg.h" + +class zeiger_t; +class schedule_t; +struct schedule_entry_t; +class player_t; + + + +class road_line_builder_frame_t : public gui_frame_t, public action_listener_t +{ +private: + enum mode_t { adding, inserting, removing, undefined_mode }; + mode_t mode; + static const int max_digits = 4; + static const int ibuffer_size = 1024 - max_digits -1; + char ibuf[ibuffer_size]; + + + void update_tool(bool set); + + //create line with given points in schedule + void create_line(); + //mark or unmarks path of coords in given vector + void mark_path(std::vector path, bool marking); + void mark_paths(std::vector> paths, bool marking); + //search for fitting coords to place stations + std::vector get_station_coords(std::vector> paths); + //distance function for 1D + uint32 get_distance_1D(koord3d a, koord3d b); + // station buildable on tile + bool can_station(weg_t* weg); + //build station add coord + void build_station(koord3d koord3); + //get next line name + std::string get_next_line_name(); + //get all paths between given coords + std::vector> get_paths(); + //get path between given points + std::vector get_path(schedule_entry_t e1, schedule_entry_t e2); + +protected: + gui_numberinput_t ninput; // input for desired digits + gui_numberinput_t counter; // counter for line number + gui_textinput_t input; // input for line name + + //buttons + button_t bt_add; + button_t bt_remove; + button_t bt_finish; + button_t bt_refresh; + + //labels for numberinputs + gui_label_t lb_counter; + gui_label_t lb_digits; + + gui_scrollpane_t scrolly; //scroll panel for schedule stats + schedule_gui_stats_t stats; + + + player_t *player; + schedule_t *schedule; + + + public: + road_line_builder_frame_t(player_t* player); + ~road_line_builder_frame_t(); + virtual bool action_triggered(gui_action_creator_t *comp, value_t extra); + + virtual void set_windowsize(scr_size size); + bool infowin_event(const event_t* ev); + +}; + +#endif Index: gui/simwin.h =================================================================== --- gui/simwin.h (revision 8648) +++ gui/simwin.h (working copy) @@ -101,6 +101,7 @@ magic_convoi_info, magic_factory_info, magic_font, + magic_road_line_builder, magic_convoi_detail=magic_convoi_info+65536, magic_halt_info=magic_convoi_detail+65536, magic_halt_detail=magic_halt_info+65536, Index: Makefile =================================================================== --- Makefile (revision 8648) +++ Makefile (working copy) @@ -379,6 +379,7 @@ SOURCES += gui/password_frame.cc SOURCES += gui/player_frame_t.cc SOURCES += gui/privatesign_info.cc +SOURCES += gui/road_line_builder_frame.cc SOURCES += gui/savegame_frame.cc SOURCES += gui/scenario_frame.cc SOURCES += gui/scenario_info.cc Index: simmenu.cc =================================================================== --- simmenu.cc (revision 8648) +++ simmenu.cc (working copy) @@ -213,6 +213,7 @@ case DIALOG_THEMES: tool = new dialog_themes_t(); break; case DIALOG_SCENARIO: tool = new dialog_scenario_t(); break; case DIALOG_SCENARIO_INFO: tool = new dialog_scenario_info_t(); break; + case DIALOG_CREATE_ROAD_LINE: tool = new dialog_road_line_builder_t(); break; default: dbg->error("create_dialog_tool()","cannot satisfy request for dialog_tool[%i]!",toolnr); return NULL; } Index: simmenu.h =================================================================== --- simmenu.h (revision 8648) +++ simmenu.h (working copy) @@ -153,6 +153,7 @@ DIALOG_THEMES, DIALOG_SCENARIO, DIALOG_SCENARIO_INFO, + DIALOG_CREATE_ROAD_LINE, DIALOGE_TOOL_COUNT, DIALOGE_TOOL = 0x4000 }; Index: simtool-dialogs.h =================================================================== --- simtool-dialogs.h (revision 8648) +++ simtool-dialogs.h (working copy) @@ -49,6 +49,7 @@ #include "gui/themeselector.h" #include "gui/scenario_frame.h" #include "gui/scenario_info.h" +#include "gui/road_line_builder_frame.h" class player_t; @@ -564,4 +565,18 @@ bool is_init_network_save() const OVERRIDE{ return true; } bool is_work_network_save() const OVERRIDE{ return true; } }; + +class dialog_road_line_builder_t : public tool_t { +public: + dialog_road_line_builder_t() : tool_t(DIALOG_CREATE_ROAD_LINE | DIALOGE_TOOL) {} + char const* get_tooltip(player_t const*) const OVERRIDE { return translator::translate("Select a theme for display"); } + bool is_selected() const OVERRIDE { return win_get_magic(magic_road_line_builder); } + bool init(player_t* player_) OVERRIDE { + create_win(new road_line_builder_frame_t(player_), w_info, magic_road_line_builder); + return false; + } + bool exit(player_t*) OVERRIDE { destroy_win(magic_road_line_builder); return false; } + bool is_init_network_save() const OVERRIDE { return true; } + bool is_work_network_save() const OVERRIDE { return true; } +}; #endif