diff --git a/Makefile b/Makefile
index aab8f0e47b5..a83c9c4c616 100644
--- a/Makefile
+++ b/Makefile
@@ -408,6 +408,9 @@ SOURCES += gui/components/gui_vehicle_cargoinfo.cc
SOURCES += gui/components/gui_waytype_image_box.cc
SOURCES += gui/components/gui_waytype_tab_panel.cc
SOURCES += gui/components/gui_world_view_t.cc
+SOURCES += gui/components/sortable_table.cc
+SOURCES += gui/components/sortable_table_header.cc
+SOURCES += gui/components/sortable_table_vehicle.cc
SOURCES += gui/convoi_detail_t.cc
SOURCES += gui/convoi_filter_frame.cc
SOURCES += gui/convoi_frame.cc
@@ -493,6 +496,7 @@ SOURCES += gui/obj_info.cc
SOURCES += gui/slim_obj_info.cc
SOURCES += gui/vehicle_class_manager.cc
SOURCES += gui/vehicle_detail.cc
+SOURCES += gui/vehicle_manager.cc
SOURCES += gui/water_info.cc
SOURCES += gui/way_info.cc
SOURCES += gui/welt.cc
diff --git a/Simutrans-Extended.vcxproj b/Simutrans-Extended.vcxproj
index 1349e3595f3..99d6563fdb0 100644
--- a/Simutrans-Extended.vcxproj
+++ b/Simutrans-Extended.vcxproj
@@ -1941,6 +1941,7 @@
+
true
@@ -2347,6 +2348,9 @@
+
+
+
@@ -2630,6 +2634,7 @@
+
@@ -2836,6 +2841,9 @@
+
+
+
diff --git a/cmake/SimutransSourceList.cmake b/cmake/SimutransSourceList.cmake
index 465aed632c4..12d7350ad06 100644
--- a/cmake/SimutransSourceList.cmake
+++ b/cmake/SimutransSourceList.cmake
@@ -142,6 +142,9 @@ target_sources(simutrans-extended PRIVATE
gui/components/gui_waytype_image_box.cc
gui/components/gui_waytype_tab_panel.cc
gui/components/gui_world_view_t.cc
+ gui/components/sortable_table.cc
+ gui/components/sortable_table_header.cc
+ gui/components/sortable_table_vehicle.cc
gui/convoi_detail_t.cc
gui/convoi_filter_frame.cc
gui/convoi_frame.cc
@@ -229,6 +232,7 @@ target_sources(simutrans-extended PRIVATE
gui/vehiclelist_frame.cc
gui/vehicle_class_manager.cc
gui/vehicle_detail.cc
+ gui/vehicle_manager.cc
gui/water_info.cc
gui/way_info.cc
gui/welt.cc
diff --git a/gui/components/gui_button.cc b/gui/components/gui_button.cc
index 144d1d585cb..7abce0f8fbb 100644
--- a/gui/components/gui_button.cc
+++ b/gui/components/gui_button.cc
@@ -121,6 +121,7 @@ void button_t::set_typ(enum type t)
break;
case imagebox:
+ set_size( scr_size(max(get_size().w,LINESPACE), max(get_size().w,LINESPACE)) );
img = IMG_EMPTY;
break;
@@ -218,10 +219,7 @@ scr_size button_t::get_min_size() const
case imagebox: {
scr_coord_val x = 0, y = 0, w = 0, h = 0;
display_get_image_offset(img, &x, &y, &w, &h);
- scr_size size(gui_theme_t::gui_pos_button_size);
- size.w = max(size.w, w+4);
- size.h = max(size.h, h+4);
- return size;
+ return scr_size(max(get_size().w, w + 4), max(get_size().h, h + 4));
}
case sortarrow:
diff --git a/gui/components/gui_chart.h b/gui/components/gui_chart.h
index 79faa69c8fa..2ae1565237e 100644
--- a/gui/components/gui_chart.h
+++ b/gui/components/gui_chart.h
@@ -21,7 +21,7 @@ class gui_chart_t : public gui_component_t
enum chart_marker_t { square = 0, cross, diamond, round_box, none };
// NOTE: KMPH and FORCE hacks drawing accuracy and should not be mixed with other types
// CURVE TYPES
- enum chart_suffix_t { STANDARD = 0, MONEY, PERCENT, DISTANCE, KMPH, FORCE, PAX_KM, KG_KM, TON_KM, TON_KM_MAIL, KW,/* WATT,*/ TONNEN, TIME };
+ enum chart_suffix_t { STANDARD = 0, MONEY, PERCENT, DISTANCE, KMPH, FORCE, PAX_KM, KG_KM, TON_KM, TON_KM_MAIL, KW,/* WATT,*/ TONNEN, TIME, DATE };
/**
* Set background color. -1 means no background
diff --git a/gui/components/gui_combobox.cc b/gui/components/gui_combobox.cc
index 6474bcf200c..6cb6e357201 100644
--- a/gui/components/gui_combobox.cc
+++ b/gui/components/gui_combobox.cc
@@ -411,7 +411,7 @@ scr_size gui_combobox_t::get_min_size() const
return scr_size(bl.w + ti.w + br.w + D_H_SPACE, max(max(bl.h, ti.h), br.h));
}
else {
- return scr_size(bl.w + br.w + sl.w - D_H_SPACE, max(max(bl.h, ti.h), br.h));
+ return scr_size(bl.w + br.w + sl.w + D_H_SPACE*2 + D_SCROLLBAR_WIDTH, max(max(bl.h, ti.h), br.h));
}
}
diff --git a/gui/components/gui_container.cc b/gui/components/gui_container.cc
index e69603f3e77..602ee43d8bd 100644
--- a/gui/components/gui_container.cc
+++ b/gui/components/gui_container.cc
@@ -272,9 +272,9 @@ void gui_container_t::draw(scr_coord offset)
continue;
}
- if (checkered && (checker_count&1)==0) {
+ if (checkered) {
scr_coord c_pos = screen_pos + c->get_pos();
- display_blend_wh_rgb( c_pos.x, c_pos.y, c->get_size().w, c->get_size().h, color_idx_to_rgb(COL_WHITE), 50 );
+ display_fillbox_wh_clip_rgb( c_pos.x, c_pos.y, c->get_size().w, c->get_size().h, (checker_count&1) ? SYSCOL_LIST_BACKGROUND_EVEN : SYSCOL_LIST_BACKGROUND_ODD, false);
}
if( c == comp_focus ) {
diff --git a/gui/components/gui_convoy_assembler.cc b/gui/components/gui_convoy_assembler.cc
index 29911f5e70c..4c5a72c7275 100644
--- a/gui/components/gui_convoy_assembler.cc
+++ b/gui/components/gui_convoy_assembler.cc
@@ -577,6 +577,7 @@ gui_convoy_assembler_t::gui_convoy_assembler_t(depot_frame_t *frame) :
scrolly_waggons(&waggons)
{
depot_frame = frame;
+ old_stored_vehicles = depot_frame->get_depot()->get_vehicle_list().get_count();
replace_frame = NULL;
}
@@ -617,16 +618,21 @@ void gui_convoy_assembler_t::init(waytype_t wt, signed char player_nr, bool elec
// top left
add_table(1,3)->set_margin(scr_size(D_MARGIN_LEFT,0), scr_size(0,0));
{
- cont_convoi.set_table_layout(2,2);
- cont_convoi.set_margin(scr_size(0,0), scr_size(get_grid(wt).x/2,0));
- cont_convoi.set_spacing(scr_size(0,0));
- cont_convoi.add_component(&convoi);
- lb_makeup.init("Select vehicles to make up a convoy", scr_coord(0,0), SYSCOL_TEXT_INACTIVE, gui_label_t::centered);
- cont_convoi.add_component(&lb_makeup);
- cont_convoi.new_component(0,D_SCROLLBAR_HEIGHT);
- convoi.set_max_rows(1);
- scrollx_convoi.set_maximize(true);
- add_component(&scrollx_convoi);
+ add_table(2,1);
+ {
+ cont_convoi.set_table_layout(2,1);
+ cont_convoi.set_margin(scr_size(0,0), scr_size(get_grid(wt).x/2,0));
+ cont_convoi.set_spacing(scr_size(0,0));
+ cont_convoi.add_component(&convoi);
+ lb_makeup.init("Select vehicles to make up a convoy", scr_coord(0,0), SYSCOL_TEXT_INACTIVE, gui_label_t::centered);
+ cont_convoi.add_component(&lb_makeup);
+ convoi.set_max_rows(1);
+ scrollx_convoi.set_maximize(true);
+ add_component(&scrollx_convoi);
+
+ new_component(0, get_grid(wt).y+8);
+ }
+ end_table();
// convoy length
add_table(5,1);
@@ -702,6 +708,7 @@ void gui_convoy_assembler_t::init(waytype_t wt, signed char player_nr, bool elec
bt_class_management.set_image(skinverwaltung_t::open_window->get_image_id(0));
bt_class_management.set_image_position_right(true);
}
+ bt_class_management.set_rigid(true);
bt_class_management.add_listener(this);
add_component(&bt_class_management);
}
@@ -857,7 +864,6 @@ void gui_convoy_assembler_t::init(waytype_t wt, signed char player_nr, bool elec
scrolly_electrics.set_min_height(scr_min_h);
scrolly_locos.set_min_height(scr_min_h);
scrolly_waggons.set_min_height(scr_min_h);
- scrollx_convoi.set_min_height(scr_min_h+D_SCROLLBAR_WIDTH);
set_size(get_min_size());
gui_image_list_t* ilists[] = { &convoi, &pas, &pas2, &electrics, &locos, &waggons };
for (uint32 i = 0; i < lengthof(ilists); i++) {
@@ -2265,6 +2271,15 @@ void gui_convoy_assembler_t::draw(scr_coord offset)
{
if (depot_frame==NULL && replace_frame==NULL) return;
+ if (depot_frame){
+ bt_class_management.set_visible(vehicles.get_count());
+
+ if( old_stored_vehicles != depot_frame->get_depot()->get_vehicle_list().get_count()) {
+ old_stored_vehicles=depot_frame->get_depot()->get_vehicle_list().get_count();
+ build_vehicle_lists();
+ }
+ }
+
update_vehicle_info_text(pos+offset);
const uint8 player_nr = depot_frame ? depot_frame->get_depot()->get_owner_nr() : replace_frame->get_player_nr();
diff --git a/gui/components/gui_convoy_assembler.h b/gui/components/gui_convoy_assembler.h
index be49b59c035..f19b9f32b38 100644
--- a/gui/components/gui_convoy_assembler.h
+++ b/gui/components/gui_convoy_assembler.h
@@ -121,6 +121,8 @@ class gui_convoy_assembler_t : public gui_aligned_container_t, public gui_action
uint16 livery_scheme_index=UINT16_MAX;
+ uint32 old_stored_vehicles = 0; // update vehicle list triggar
+
// The selected convoy so far...
vector_tpl vehicles;
diff --git a/gui/components/gui_scrolled_list.cc b/gui/components/gui_scrolled_list.cc
index cd52c54c2d9..2b93599b070 100644
--- a/gui/components/gui_scrolled_list.cc
+++ b/gui/components/gui_scrolled_list.cc
@@ -89,6 +89,7 @@ gui_scrolled_list_t::gui_scrolled_list_t(enum type type, item_compare_func cmp)
{
container.set_table_layout(1,0);
container.set_spacing(NO_SPACING); // Spaces between components create spaces that do not accept clicks
+ container.set_margin(scr_size(D_H_SPACE, 0), scr_size(D_SCROLLBAR_HEIGHT, D_SCROLLBAR_WIDTH));
set_component(&container);
@@ -96,7 +97,7 @@ gui_scrolled_list_t::gui_scrolled_list_t(enum type type, item_compare_func cmp)
compare = cmp;
size = scr_size(0,0);
pos = scr_coord(0,0);
- multiple_selection = false;
+ multiple_selection_mode = 0;
maximize = false;
}
@@ -202,8 +203,8 @@ void gui_scrolled_list_t::set_size(scr_size size)
void gui_scrolled_list_t::reset_container_size()
{
// reset element positioning
- container.set_margin( scr_size( D_H_SPACE, 0 ), scr_size( D_H_SPACE, 0 ) );
- container.set_spacing( scr_size( D_H_SPACE, 0 ) );
+ container.set_margin( scr_size( D_H_SPACE, 0 ), scr_size( D_SCROLLBAR_HEIGHT, D_SCROLLBAR_WIDTH ) );
+ container.set_spacing( NO_SPACING ); // Spaces between components create spaces that do not accept clicks
scr_size csize = container.get_min_size();
@@ -232,8 +233,10 @@ bool gui_scrolled_list_t::infowin_event(const event_t *ev)
// if different element is focused, calculate selection and call listeners
if ( focus != new_focus || (new_focus && IS_LEFTRELEASE(&ev2) && new_focus->getroffen(ev2.mouse_pos)) ) {
calc_selection(focus, new_focus, *ev);
- const int new_selection = get_selection();
- call_listeners((long)new_selection);
+ if (new_focus->selected) {
+ const int new_selection = get_selection();
+ call_listeners((long)new_selection);
+ }
swallowed = true;
}
@@ -247,7 +250,7 @@ void gui_scrolled_list_t::calc_selection(scrollitem_t* old_focus, scrollitem_t*
// do nothing.
return;
}
- else if( !multiple_selection || ev.ev_key_mod==0 ) {
+ else if( multiple_selection_mode==0 || (ev.ev_key_mod==0 && multiple_selection_mode!=2) ) {
// simply select new_focus
for(gui_component_t* v : item_list) {
scrollitem_t* item = dynamic_cast(v);
@@ -256,9 +259,13 @@ void gui_scrolled_list_t::calc_selection(scrollitem_t* old_focus, scrollitem_t*
}
}
}
- else if( multiple_selection && IS_CONTROL_PRESSED(&ev) ) {
+ else if( multiple_selection_mode==2 || (multiple_selection_mode==1 && IS_CONTROL_PRESSED(&ev)) ) {
// control key is pressed. select or deselect the focused one.
new_focus->selected = !new_focus->selected;
+ new_focus->focused = new_focus->selected;
+ if (!get_selections().get_count()) {
+ container.set_focus(NULL);
+ }
}
else if( IS_SHIFT_PRESSED(&ev) ) {
// shift key is pressed.
diff --git a/gui/components/gui_scrolled_list.h b/gui/components/gui_scrolled_list.h
index e888bc250b4..3350dc2030d 100644
--- a/gui/components/gui_scrolled_list.h
+++ b/gui/components/gui_scrolled_list.h
@@ -115,7 +115,7 @@ class gui_scrolled_list_t :
item_compare_func compare;
- bool multiple_selection; // true when multiple selection is enabled.
+ uint8 multiple_selection_mode=0;
void calc_selection(scrollitem_t*, scrollitem_t*, event_t);
protected:
@@ -149,7 +149,9 @@ class gui_scrolled_list_t :
scrollitem_t* get_selected_item() const;
sint32 get_count() const { return item_list.get_count(); }
- void enable_multiple_selection() { multiple_selection = true; }
+ // 0: disable(single), 1: work with ctrl pressed, 2: work as default
+ void enable_multiple_selection() { multiple_selection_mode = 1; } // Retained for compatibility
+ void set_multiple_selection(uint8 mode) { multiple_selection_mode = mode; }
/* when rebuilding a list, be sure to call recalculate the slider
* with recalculate_slider() to update the scrollbar properly. */
diff --git a/gui/components/gui_table.cc b/gui/components/gui_table.cc
index e4c8f70799d..3c9ae0256c2 100644
--- a/gui/components/gui_table.cc
+++ b/gui/components/gui_table.cc
@@ -69,48 +69,3 @@ void gui_table_header_buf_t::draw(scr_coord offset)
gui_table_cell_buf_t::draw(offset);
}
-
-
-
-void table_sort_button_t::set_text(const char * text)
-{
- this->text = text;
- translated_text = translator::translate(text);
- scr_coord_val w = translated_text ? proportional_string_width(translated_text) : 0;
- w += 2 * D_H_SPACE + D_BUTTON_PADDINGS_X + 5; // padding + arrow size
- set_size(scr_size(w, size.h));
-}
-
-void table_sort_button_t::draw(scr_coord offset)
-{
- // draw table header cell
- PIXVAL bgcolor = pressed ? SYSCOL_TH_BACKGROUND_SELECTED : SYSCOL_TH_BACKGROUND_TOP;
- text_color = pressed ? SYSCOL_TH_TEXT_SELECTED : SYSCOL_TH_TEXT_TOP;
- display_ddd_box_clip_rgb(pos.x + offset.x, pos.y + offset.y, get_size().w, get_size().h, SYSCOL_TH_BORDER, SYSCOL_TH_BORDER);
- display_fillbox_wh_clip_rgb(pos.x + offset.x+1, pos.y + offset.y+1, get_size().w-2, get_size().h-2, bgcolor, true);
-
- // draw text
- const scr_rect area(offset + pos, size);
- scr_rect area_text = area - gui_theme_t::gui_button_text_offset_right;
- area_text.set_pos(gui_theme_t::gui_button_text_offset + area.get_pos()-scr_coord(2,0));
- if( text ) {
- display_proportional_ellipsis_rgb( area_text, translated_text, ALIGN_CENTER_H | ALIGN_CENTER_V | DT_CLIP, text_color, true );
- }
- if (pressed) {
- // draw an arrow
-
- scr_coord_val xoff_arrow_center = pos.x + offset.x + size.w - D_H_SPACE - 3;
- display_fillbox_wh_clip_rgb(xoff_arrow_center, pos.y+offset.y + D_V_SPACE-1, 1, size.h - D_V_SPACE*2+2, SYSCOL_TH_TEXT_SELECTED, false);
- if (reversed) {
- // asc
- display_fillbox_wh_clip_rgb(xoff_arrow_center-1, pos.y+offset.y + D_V_SPACE, 3, 1, SYSCOL_TH_TEXT_SELECTED, false);
- display_fillbox_wh_clip_rgb(xoff_arrow_center-2, pos.y+offset.y + D_V_SPACE+1, 5, 1, SYSCOL_TH_TEXT_SELECTED, false);
- }
- else {
- // desc
- display_fillbox_wh_clip_rgb(xoff_arrow_center-1, pos.y+offset.y + size.h - D_V_SPACE - 1, 3, 1, SYSCOL_TH_TEXT_SELECTED, false);
- display_fillbox_wh_clip_rgb(xoff_arrow_center-2, pos.y+offset.y + size.h - D_V_SPACE - 2, 5, 1, SYSCOL_TH_TEXT_SELECTED, false);
- }
-
- }
-}
diff --git a/gui/components/gui_table.h b/gui/components/gui_table.h
index 08bb7e8af37..2b45a48aedc 100644
--- a/gui/components/gui_table.h
+++ b/gui/components/gui_table.h
@@ -108,24 +108,4 @@ class gui_table_header_buf_t: public gui_table_cell_buf_t
};
-class table_sort_button_t : public button_t {
- bool reversed = false;
-
-public:
- table_sort_button_t() {
- init(button_t::roundbox_middle_state, "");
- }
-
- void set_reverse(bool yesno = false) { reversed=yesno; }
-
- // set text and set size (including sort arrow space)
- void set_text(const char * text) OVERRIDE;
-
- void draw(scr_coord offset) OVERRIDE;
-
- scr_size get_min_size() const OVERRIDE { return size; }
- scr_size get_max_size() const OVERRIDE { return get_min_size(); }
-};
-
-
#endif
diff --git a/gui/components/gui_vehicle_cargoinfo.cc b/gui/components/gui_vehicle_cargoinfo.cc
index 32289559192..4a7009f8c62 100644
--- a/gui/components/gui_vehicle_cargoinfo.cc
+++ b/gui/components/gui_vehicle_cargoinfo.cc
@@ -268,7 +268,7 @@ void gui_vehicle_cargo_info_t::update()
if (!total_cargo) {
// no cargo => empty
new_component("leer", SYSCOL_TEXT_WEAK, gui_label_t::left);
- new_component();
+ new_component();
}
else {
add_table(2,0)->set_spacing(scr_size(0,1));
@@ -788,6 +788,7 @@ void gui_cargo_info_t::init(uint8 info_depth_from, uint8 info_depth_to, bool div
else {
new_component(LINEASCENT);
new_component("leer", SYSCOL_TEXT_WEAK);
+ new_component();
}
set_size(get_min_size());
}
diff --git a/gui/components/sortable_table.cc b/gui/components/sortable_table.cc
new file mode 100644
index 00000000000..010a0e91454
--- /dev/null
+++ b/gui/components/sortable_table.cc
@@ -0,0 +1,434 @@
+/*
+ * This file is part of the Simutrans-Extended project under the Artistic License.
+ * (see LICENSE.txt)
+ */
+
+/*
+ * Vehicle info including availability
+ */
+
+#include "sortable_table.h"
+
+#include "../../simworld.h"
+#include "../../simcolor.h"
+#include "../../display/simgraph.h"
+#include "../../display/viewport.h"
+
+#include "../../dataobj/translator.h"
+
+#include "../../utils/simstring.h"
+
+#include "../../descriptor/intro_dates.h"
+
+scr_coord_val table_cell_item_t::check_height(scr_coord_val new_height)
+{
+ size.h = max(new_height, size.h);
+ draw_offset.y = (size.h - min_size.h) / 2;
+ return size.h;
+}
+
+void table_cell_item_t::set_size(scr_size new_size)
+{
+ set_width(new_size.w);
+ check_height(new_size.h);
+}
+
+void table_cell_item_t::set_width(scr_coord_val new_width)
+{
+ size.w = new_width + L_CELL_PADDING*2;
+ switch (align) {
+ case centered:
+ draw_offset.x=(size.w-min_size.w)/2;
+ break;
+ case right:
+ draw_offset.x = size.w - min_size.w - L_CELL_PADDING;
+ break;
+ case left:
+ default:
+ draw_offset.x = L_CELL_PADDING;
+ break;
+ }
+}
+
+void table_cell_item_t::draw(scr_coord offset)
+{
+ offset+=pos;
+ if (highlight) { // for filter
+ display_fillbox_wh_clip_rgb(offset.x+1, offset.y, size.w, size.h, SYSCOL_TD_BACKGROUND_HIGHLIGHT, false);
+ }
+ // draw border
+ display_ddd_box_clip_rgb(offset.x, offset.y-1, size.w+1, size.h+1, SYSCOL_TD_BORDER, SYSCOL_TD_BORDER);
+}
+
+
+
+text_cell_t::text_cell_t(const char* text_, PIXVAL col, align_t align_, bool underlined_)
+{
+ text= text_;
+ color= col;
+ align=align_;
+ underlined = underlined_;
+ min_size = scr_size(proportional_string_width(translator::translate(text)), LINESPACE);
+ set_size(min_size);
+}
+
+void text_cell_t::draw(scr_coord offset)
+{
+ table_cell_item_t::draw(offset);
+
+ offset+=pos;
+ display_proportional_clip_rgb(offset.x+ draw_offset.x, offset.y+ draw_offset.y, translator::translate(text), ALIGN_LEFT, color, false);
+ if (underlined) {
+ display_fillbox_wh_clip_rgb(offset.x + draw_offset.x, offset.y + draw_offset.y + LINESPACE-1, min_size.w, 1, color, false);
+ }
+}
+
+
+coord_cell_t::coord_cell_t(const char* alt_text, koord coord_, align_t align_)
+{
+ coord = coord_;
+ align = align_;
+ if (alt_text != NULL) {
+ buf.printf("%s", alt_text);
+ }
+ else {
+ buf.append("-");
+ }
+ min_size = scr_size(proportional_string_width(buf), LINESPACE);
+ set_size(min_size);
+}
+
+coord_cell_t::coord_cell_t(koord coord_, align_t align_)
+{
+ coord = coord_;
+ align = align_;
+ if (coord != koord::invalid) {
+ buf.printf("%s", coord.get_str());
+ show_posicon = true;
+ }
+ else {
+ buf.append("-");
+ }
+ min_size = scr_size(proportional_string_width(buf) + (D_POS_BUTTON_WIDTH + 2) * show_posicon, show_posicon ? max(LINESPACE, D_POS_BUTTON_HEIGHT) : LINESPACE);
+ set_size(min_size);
+}
+
+void coord_cell_t::draw(scr_coord offset)
+{
+ table_cell_item_t::draw(offset);
+
+ offset += pos;
+ PIXVAL text_col= SYSCOL_TEXT;
+ if (world()->get_viewport()->get_world_position() == coord) {
+ text_col=SYSCOL_TEXT_HIGHLIGHT;
+ if (show_posicon){
+ display_color_img(skinverwaltung_t::posbutton->get_image_id(SKIN_BUTTON_POS_PRESSED), offset.x + draw_offset.x, offset.y + (size.h-D_POS_BUTTON_HEIGHT)/2, 0, false, false);
+ }
+ }
+ display_proportional_clip_rgb(offset.x + draw_offset.x + (D_POS_BUTTON_WIDTH+2) * show_posicon, offset.y + draw_offset.y, buf, ALIGN_LEFT, text_col, false);
+ if (coord != koord::invalid) {
+ display_fillbox_wh_clip_rgb(offset.x + draw_offset.x + (D_POS_BUTTON_WIDTH + 2) * show_posicon, offset.y + draw_offset.y + LINESPACE - 1, min_size.w - (D_POS_BUTTON_WIDTH + 2) * show_posicon, 1, text_col, false);
+ }
+}
+
+
+value_cell_t::value_cell_t(sint64 value_, gui_chart_t::chart_suffix_t suffix_, align_t align_, PIXVAL col)
+{
+ color = col;
+ align = align_;
+ suffix= suffix_;
+
+ set_value(value_);
+ set_size(min_size);
+}
+
+void value_cell_t::set_value(sint64 value_)
+{
+ value = value_;
+ buf.clear();
+
+ switch(suffix)
+ {
+ case gui_chart_t::MONEY:
+ buf.append_money(value/100.0);
+ break;
+ case gui_chart_t::PERCENT:
+ buf.append(value / 100.0, 2);
+ buf.append("%");
+ //color = value >= 0 ? (value > 0 ? MONEY_PLUS : SYSCOL_TEXT_UNUSED) : MONEY_MINUS;
+ break;
+ case gui_chart_t::KMPH:
+ buf.append(value);
+ buf.append(" km/h");
+ break;
+ case gui_chart_t::KW:
+ if (value==0) {
+ buf.append("-");
+ align = centered;
+ color = COL_INACTIVE;
+ }
+ else {
+ buf.append(value);
+ buf.append(" kW");
+ }
+ break;
+ case gui_chart_t::TONNEN:
+ if (value == 0) {
+ buf.append("-");
+ align = centered;
+ color = COL_INACTIVE;
+ }
+ else {
+ buf.printf("%.1ft", (float)value/1000.0);
+ }
+ break;
+ case gui_chart_t::DATE:
+ if (value == DEFAULT_RETIRE_DATE*12) {
+ // empty cell
+ ////buf.append("-");
+ ////color = COL_INACTIVE;
+ }
+ else {
+ buf.append(translator::get_short_date((uint16)value / 12, (uint16)value % 12));
+ }
+ break;
+ case gui_chart_t::TIME:
+ {
+ if (value==0) {
+ buf.append("--:--:--");
+ color = COL_INACTIVE;
+ }
+ else {
+ char as_clock[32];
+ world()->sprintf_ticks(as_clock, sizeof(as_clock), value);
+ buf.printf("%s", as_clock);
+ }
+ break;
+ }
+ case gui_chart_t::FORCE:
+ if (value == 0) {
+ buf.append("-");
+ align = centered;
+ color = COL_INACTIVE;
+ }
+ else {
+ buf.append(value);
+ buf.append(" kN");
+ }
+ break;
+ case gui_chart_t::DISTANCE:
+ {
+ buf.printf("%.1fkm", (float)(value*world()->get_settings().get_meters_per_tile()/1000.0));
+ break;
+ }
+ case gui_chart_t::STANDARD:
+ default:
+ buf.append(value);
+ break;
+ }
+ min_size = scr_size(proportional_string_width(buf), LINESPACE);
+ if (min_size.w> (size.w - L_CELL_PADDING*2) ) {
+ dbg->warning("value_cell_t::set_value", "Cell's text width has been changed to %i, exceeding the column width of %i.", min_size.w, size.w);
+ }
+ set_width(size.w - L_CELL_PADDING*2); // recalc draw_offset.x
+}
+
+void value_cell_t::draw(scr_coord offset)
+{
+ table_cell_item_t::draw(offset);
+
+ offset += pos;
+ display_proportional_clip_rgb(offset.x + draw_offset.x, offset.y + draw_offset.y, translator::translate(buf), ALIGN_LEFT, color, false);
+}
+
+
+values_cell_t::values_cell_t(sint64 value_, sint64 sub_value_, PIXVAL col, bool single_line_)
+{
+ color = col;
+ min_size.h = LINESPACE;
+ align = centered;
+ single_line = single_line_;
+
+ set_values(value_, sub_value_);
+
+ set_size(min_size);
+}
+
+void values_cell_t::set_values(sint64 value_, sint64 sub_value_)
+{
+ value = value_;
+ sub_value = sub_value_;
+
+ buf.clear();
+ sub_buf.clear();
+
+ if (value == 0 && sub_value == 0) {
+ buf.append("-");
+ color = SYSCOL_TEXT_WEAK;
+ }
+ if (value != 0) {
+ buf.printf("%i", value);
+ }
+ if (sub_value != 0) {
+ if (value != 0) {
+ if (single_line) {
+ buf.printf(" (%i)", sub_value);
+ }
+ else {
+ // display two lines
+ sub_buf.printf("(%i)", sub_value);
+ min_size.h += LINESPACE;
+ sub_draw_offset_x = proportional_string_width(sub_buf) / 2;
+ min_size.w = max(proportional_string_width(buf), sub_draw_offset_x * 2 + 1);
+ }
+ }
+ else {
+ buf.printf("(%i)", sub_value);
+ }
+ }
+ if (single_line) {
+ min_size.w = proportional_string_width(buf);
+ }
+ if (min_size.w > (size.w - L_CELL_PADDING * 2)) {
+ dbg->warning("values_cell_t::set_value", "Cell's text width has been changed to %i, exceeding the column width of %i.", min_size.w, size.w);
+ }
+ set_width(size.w - L_CELL_PADDING * 2); // recalc draw_offset.x
+}
+
+void values_cell_t::set_width(scr_coord_val new_width)
+{
+ size.w = new_width + L_CELL_PADDING * 2;
+ if (single_line) {
+ draw_offset.x = (size.w - min_size.w) / 2;
+ }
+ else {
+ draw_offset.x = (size.w - proportional_string_width(buf)) / 2;
+ }
+
+}
+
+void values_cell_t::draw(scr_coord offset)
+{
+ table_cell_item_t::draw(offset);
+
+ offset += pos;
+ display_proportional_clip_rgb(offset.x + draw_offset.x, offset.y + draw_offset.y, buf, ALIGN_LEFT, color, false);
+ display_proportional_clip_rgb(offset.x + size.w / 2 - sub_draw_offset_x, offset.y + draw_offset.y + LINESPACE, sub_buf, ALIGN_LEFT, color, false);
+}
+
+
+gui_sort_table_row_t::gui_sort_table_row_t()
+{
+ row_height=LINESPACE+D_V_SPACE+1; // default is minimum height of row
+}
+
+gui_sort_table_row_t::~gui_sort_table_row_t()
+{
+ clear_ptr_vector(owned_cells);
+}
+
+void gui_sort_table_row_t::add_component(gui_component_t* comp)
+{
+ gui_container_t::add_component(comp);
+ row_height = max(row_height, dynamic_cast(comp)->check_height(row_height));
+ min_widths.append(comp->get_size().w);
+}
+
+void gui_sort_table_row_t::set_highlight(sint32 i, bool highlight)
+{
+ if (owned_cells.get_count()<=i) return;
+ owned_cells[i]->set_highlight(highlight);
+}
+
+void gui_sort_table_row_t::set_col(uint col, scr_coord_val width)
+{
+ assert(col < owned_cells.get_count());
+ table_cell_item_t* item = owned_cells.get_element(col);
+ item->set_width(width);
+ item->set_pos(scr_coord(size.w, 0));
+ size.w+= item->get_size().w; // added padding
+}
+
+scr_coord_val gui_sort_table_row_t::get_min_width(uint col) {
+ assert(col < owned_cells.get_count());
+ return owned_cells.get_element(col)->get_min_width();
+}
+
+void gui_sort_table_row_t::draw(scr_coord offset)
+{
+ // draw selected background
+ if (selected) {
+ display_fillbox_wh_clip_rgb(pos.x + offset.x, pos.y + offset.y, get_size().w, get_size().h, (focused ? SYSCOL_TH_BACKGROUND_SELECTED : SYSCOL_TR_BACKGROUND_SELECTED), true);
+ }
+ gui_container_t::draw(offset);
+}
+
+sint64 gui_sort_table_row_t::compare_value(const table_cell_item_t* a, const table_cell_item_t* b)
+{
+ sint64 cmp = 0;
+ const value_cell_t* cell_a = dynamic_cast(a);
+ const value_cell_t* cell_b = dynamic_cast(b);
+ return cell_a->get_value() - cell_b->get_value();
+}
+
+sint64 gui_sort_table_row_t::compare_values(const table_cell_item_t* a, const table_cell_item_t* b)
+{
+ sint64 cmp=0;
+ const values_cell_t* cell_a = dynamic_cast(a);
+ const values_cell_t* cell_b = dynamic_cast(b);
+ cmp = cell_a->get_value() - cell_b->get_value();
+ if (cmp == 0) {
+ cmp = cell_a->get_sub_value() - cell_b->get_sub_value();
+ }
+ return cmp;
+}
+
+int gui_sort_table_row_t::compare_text(const table_cell_item_t* a, const table_cell_item_t* b)
+{
+ const text_cell_t* cell_a = dynamic_cast(a);
+ const text_cell_t* cell_b = dynamic_cast(b);
+ const char* a_text = translator::translate(cell_a->get_text());
+ const char* b_text = translator::translate(cell_b->get_text());
+ return STRICMP(a_text, b_text);
+}
+
+int gui_sort_table_row_t::compare_coord(const table_cell_item_t* a, const table_cell_item_t* b)
+{
+ int cmp = 0;
+ const coord_cell_t* cell_a = dynamic_cast(a);
+ const coord_cell_t* cell_b = dynamic_cast(b);
+ cmp = cell_a->get_coord().x - cell_b->get_coord().x;
+ if (cmp == 0) {
+ cmp = cell_a->get_coord().y - cell_b->get_coord().y;
+ }
+ return cmp;
+}
+
+
+int gui_sort_table_row_t::compare(const table_cell_item_t* a, const table_cell_item_t* b)
+{
+ sint64 cmp = 0;
+ const uint8 data_type = a->get_type();
+ if (data_type != b->get_type()) return 0;
+
+ switch (data_type) {
+ case table_cell_item_t::cell_value:
+ cmp = gui_sort_table_row_t::compare_value(a, b);
+ break;
+ case table_cell_item_t::cell_values:
+ cmp = gui_sort_table_row_t::compare_values(a, b);
+ break;
+ case table_cell_item_t::cell_text:
+ cmp = gui_sort_table_row_t::compare_text(a, b);
+ break;
+ case table_cell_item_t::cell_coord:
+ cmp = gui_sort_table_row_t::compare_coord(a, b);
+ break;
+ case table_cell_item_t::cell_no_sorting:
+ default:
+ // nothing to do
+ break;
+ }
+
+ return cmp;
+}
diff --git a/gui/components/sortable_table.h b/gui/components/sortable_table.h
new file mode 100644
index 00000000000..92da9d66ee0
--- /dev/null
+++ b/gui/components/sortable_table.h
@@ -0,0 +1,219 @@
+/*
+ * This file is part of the Simutrans-Extended project under the Artistic License.
+ * (see LICENSE.txt)
+ */
+
+#ifndef GUI_COMPONENTS_SORTABLE_TABLE_H
+#define GUI_COMPONENTS_SORTABLE_TABLE_H
+
+
+#include "gui_container.h"
+#include "gui_scrolled_list.h"
+#include "gui_chart.h"
+
+#include "../../tpl/vector_tpl.h"
+
+#include "../../utils/cbuffer_t.h"
+
+
+
+#define L_CELL_PADDING (LINESPACE>>2)
+
+class table_cell_item_t : virtual public gui_component_t
+{
+public:
+ enum {
+ cell_no_sorting = 0,
+ cell_value = 1,
+ cell_values = 2,
+ cell_text = 3,
+ cell_coord = 4
+ };
+
+ enum align_t {
+ left,
+ centered,
+ right
+ };
+
+protected:
+ scr_size min_size;
+ align_t align;
+ scr_coord draw_offset;
+ bool highlight=false;
+
+public:
+ table_cell_item_t(align_t align_=left) { align = align_; }
+
+ scr_coord_val get_min_width() { return min_size.w; }
+ virtual void set_width(scr_coord_val new_width) OVERRIDE;
+ void set_size(scr_size size) OVERRIDE;
+
+ // for filter
+ void set_highlight(bool yesno){ highlight=yesno; }
+
+ scr_coord_val check_height(scr_coord_val new_height);
+
+ virtual const uint8 get_type() const { return cell_no_sorting; }
+
+ bool is_focusable() OVERRIDE { return false; }
+
+ void draw(scr_coord offset) OVERRIDE;
+};
+
+
+class text_cell_t : public table_cell_item_t
+{
+ const char* text; // only for direct access of non-translatable things. Do not use!
+ PIXVAL color;
+ bool underlined;
+ // bool is_bold;
+
+public:
+ text_cell_t(const char* text = NULL, PIXVAL color = SYSCOL_TEXT, align_t align = left, bool underlined = false);
+
+ const uint8 get_type() const OVERRIDE { return cell_text; }
+
+ char const* get_text() const { return text; }
+
+ void draw(scr_coord offset) OVERRIDE;
+};
+
+
+// Hold the coordinates and click a cell to jump to the coordinates.
+class coord_cell_t : public table_cell_item_t
+{
+ koord coord;
+ cbuffer_t buf;
+ bool show_posicon=false;
+
+public:
+ coord_cell_t(const char* alt_text = NULL, koord coord=koord::invalid, align_t align = left);
+ coord_cell_t(koord coord = koord::invalid, align_t align = left);
+
+ koord get_coord() const { return coord; }
+
+ const uint8 get_type() const OVERRIDE { return cell_coord; }
+
+ void draw(scr_coord offset) OVERRIDE;
+};
+
+
+// The cell holds a single value for sorting
+// Can specify a suffix.
+class value_cell_t : public table_cell_item_t
+{
+ gui_chart_t::chart_suffix_t suffix;
+protected:
+ cbuffer_t buf;
+ PIXVAL color;
+ // bool is_bold;
+ sint64 value;
+
+public:
+ value_cell_t(sint64 value, gui_chart_t::chart_suffix_t suffix= gui_chart_t::STANDARD, align_t align = left, PIXVAL color = SYSCOL_TEXT);
+
+ // When resetting the value, care must be taken not to increase the column width.
+ virtual void set_value(sint64 value);
+
+ sint64 get_value() const { return value; }
+
+ void set_color(PIXVAL color_) { color = color_; }
+
+ const uint8 get_type() const OVERRIDE { return cell_value; }
+
+ void draw(scr_coord offset) OVERRIDE;
+};
+
+// The cell holds two values for sorting
+// There is no suffix
+class values_cell_t : public table_cell_item_t
+{
+protected:
+ cbuffer_t buf, sub_buf;
+ PIXVAL color;
+ sint64 value, sub_value;
+ scr_coord_val sub_draw_offset_x = 0;
+ bool single_line;
+
+public:
+ // single_line: Displaying two values on the same line
+ values_cell_t(sint64 value, sint64 sub_value, PIXVAL color = SYSCOL_TEXT, bool single_line=false);
+
+ void set_width(scr_coord_val new_width) OVERRIDE;
+
+ // When resetting the value, care must be taken not to increase the column width.
+ void set_values(sint64 value, sint64 sub_value=0);
+
+ sint64 get_value() const { return value; }
+ sint64 get_sub_value() const { return sub_value; }
+
+ const uint8 get_type() const OVERRIDE { return cell_values; }
+
+ void draw(scr_coord offset) OVERRIDE;
+};
+
+
+class gui_sort_table_row_t : public gui_container_t, public gui_scrolled_list_t::scrollitem_t
+{
+public:
+ static sint64 compare_value(const table_cell_item_t* a, const table_cell_item_t* b);
+ static sint64 compare_values(const table_cell_item_t* a, const table_cell_item_t* b);
+ static int compare_text(const table_cell_item_t* a, const table_cell_item_t* b);
+ static int compare_coord(const table_cell_item_t* a, const table_cell_item_t* b);
+
+
+protected:
+ vector_tpl owned_cells; ///< we take ownership of these pointers
+
+ scr_coord_val row_height;
+
+ slist_tpl min_widths;
+
+public:
+ gui_sort_table_row_t();
+
+ ~gui_sort_table_row_t();
+
+ void add_component(gui_component_t* comp) OVERRIDE;
+
+ template
+ C* new_component() { C* comp = new C(); add_component(comp); owned_cells.append(comp); return comp; }
+ template
+ C* new_component(const A1& a1) { C* comp = new C(a1); add_component(comp); owned_cells.append(comp); return comp; }
+ template
+ C* new_component(const A1& a1, const A2& a2) { C* comp = new C(a1, a2); add_component(comp); owned_cells.append(comp); return comp; }
+ template
+ C* new_component(const A1& a1, const A2& a2, const A3& a3) { C* comp = new C(a1, a2, a3); add_component(comp); owned_cells.append(comp); return comp; }
+ template
+ C* new_component(const A1& a1, const A2& a2, const A3& a3, const A4& a4) { C* comp = new C(a1, a2, a3, a4); add_component(comp); owned_cells.append(comp); return comp; }
+
+ const char* get_text() const OVERRIDE { return "Ding"; }
+
+ table_cell_item_t* get_element(sint32 i) const { return (i >= 0 && (uint32)i < owned_cells.get_count()) ? dynamic_cast(owned_cells[i]) : NULL; }
+
+ // highlight column
+ void set_highlight(sint32 i, bool highlight=true);
+
+ void set_col(uint col, scr_coord_val width);
+
+ scr_coord_val get_min_width(uint col);
+
+ static int compare(const table_cell_item_t* a, const table_cell_item_t* b);
+
+ virtual bool infowin_event(event_t const* ev) OVERRIDE { return false; }
+
+ bool is_focusable() OVERRIDE { return selected; }
+ gui_component_t* get_focus() OVERRIDE { return this; }
+ scr_coord get_focus_pos() OVERRIDE { return pos; }
+
+ void draw(scr_coord offset) OVERRIDE;
+
+ scr_size get_size() const OVERRIDE { return scr_size(size.w, row_height); }
+
+ scr_size get_min_size() const OVERRIDE { return get_size(); }
+ scr_size get_max_size() const OVERRIDE { return get_min_size(); }
+};
+
+
+#endif
diff --git a/gui/components/sortable_table_header.cc b/gui/components/sortable_table_header.cc
new file mode 100644
index 00000000000..5df5db4064c
--- /dev/null
+++ b/gui/components/sortable_table_header.cc
@@ -0,0 +1,152 @@
+/*
+ * This file is part of the Simutrans-Extended project under the Artistic License.
+ * (see LICENSE.txt)
+ */
+
+/*
+ * Vehicle info including availability
+ */
+
+#include "sortable_table_header.h"
+#include "sortable_table.h"
+
+#include "../../simworld.h"
+#include "../../simcolor.h"
+#include "../../display/simgraph.h"
+#include "../../player/simplay.h"
+
+#include "../../dataobj/translator.h"
+
+#include "../../utils/simstring.h"
+
+
+
+sortable_header_cell_t::sortable_header_cell_t(char const* const text_, bool yesno)
+{
+ enabled=yesno;
+ text = text_;
+ min_width = proportional_string_width(translator::translate(text)) + 10 /* arrow width */;
+ size.h=D_BUTTON_HEIGHT;
+}
+
+void sortable_header_cell_t::draw(scr_coord offset)
+{
+ if (selected) {
+ display_fillbox_wh_clip_rgb(pos.x + offset.x + 1, pos.y + offset.y + 1, get_size().w - 1, get_size().h - 2, SYSCOL_TH_BACKGROUND_SELECTED, false);
+ }
+ PIXVAL text_color = selected ? SYSCOL_TH_TEXT_SELECTED : SYSCOL_TH_TEXT_TOP;
+ display_ddd_box_clip_rgb(pos.x + offset.x, pos.y + offset.y, get_size().w+1, get_size().h, SYSCOL_TH_BORDER, SYSCOL_TH_BORDER);
+
+ // draw text
+ const scr_rect area(offset + pos, size-scr_size(5,0));
+ if (text) {
+ display_proportional_ellipsis_rgb(area, translator::translate(text), ALIGN_CENTER_H | ALIGN_CENTER_V | DT_CLIP, text_color, false);
+ }
+ if (enabled && selected) {
+ // draw an arrow
+ scr_coord_val xoff_arrow_center = pos.x + offset.x + size.w - D_H_SPACE - 3;
+ display_fillbox_wh_clip_rgb(xoff_arrow_center, pos.y+offset.y + D_V_SPACE-1, 1, size.h - D_V_SPACE*2+2, SYSCOL_TH_TEXT_SELECTED, false);
+ if (reversed) {
+ // asc
+ display_fillbox_wh_clip_rgb(xoff_arrow_center-1, pos.y+offset.y + D_V_SPACE, 3, 1, SYSCOL_TH_TEXT_SELECTED, false);
+ display_fillbox_wh_clip_rgb(xoff_arrow_center-2, pos.y+offset.y + D_V_SPACE+1, 5, 1, SYSCOL_TH_TEXT_SELECTED, false);
+ }
+ else {
+ // desc
+ display_fillbox_wh_clip_rgb(xoff_arrow_center-1, pos.y+offset.y + size.h - D_V_SPACE - 1, 3, 1, SYSCOL_TH_TEXT_SELECTED, false);
+ display_fillbox_wh_clip_rgb(xoff_arrow_center-2, pos.y+offset.y + size.h - D_V_SPACE - 2, 5, 1, SYSCOL_TH_TEXT_SELECTED, false);
+ }
+ }
+}
+
+void sortable_header_cell_t::set_width(scr_coord_val new_width)
+{
+ size.w = new_width + L_CELL_PADDING * 2;
+}
+
+
+gui_sort_table_header_t::gui_sort_table_header_t()
+{
+ set_size(scr_size(D_H_SPACE, D_BUTTON_HEIGHT));
+
+}
+
+gui_sort_table_header_t::~gui_sort_table_header_t()
+{
+ clear_ptr_vector(owned_cells);
+}
+
+void gui_sort_table_header_t::add_component(gui_component_t* comp)
+{
+ comp->set_focusable(true);
+ gui_container_t::add_component(comp);
+}
+
+void gui_sort_table_header_t::set_col(uint col, scr_coord_val width)
+{
+ assert(col < components.get_count());
+ sortable_header_cell_t*item = dynamic_cast(components.get_element(col));
+ item->set_width(width);
+ item->set_pos(scr_coord(size.w, 0));
+ size.w += item->get_size().w; // added padding
+}
+
+scr_coord_val gui_sort_table_header_t::get_min_width(uint col)
+{
+ if(col>=owned_cells.get_count()) return 0;
+ return owned_cells.get_element(col)->get_min_width();
+}
+
+void gui_sort_table_header_t::set_selection(uint32 col)
+{
+ if (selected_col == col) {
+ }
+
+ selected_col=col;
+ uint idx=0;
+ for (auto& cell : owned_cells) {
+ if (idx == col) {
+ reversed ^= 1;
+ cell->selected = true;
+ set_focus(cell);
+ }
+ else {
+ cell->selected = false;
+ cell->reversed = false;
+ }
+ idx++;
+ }
+}
+
+void gui_sort_table_header_t::draw(scr_coord offset)
+{
+ // draw background
+ display_fillbox_wh_clip_rgb(pos.x + offset.x + D_H_SPACE, pos.y + offset.y, get_size().w-D_SCROLLBAR_WIDTH-D_H_SPACE, get_size().h, SYSCOL_TH_BACKGROUND_TOP, true);
+ gui_container_t::draw(offset);
+}
+
+bool gui_sort_table_header_t::infowin_event(const event_t* ev)
+{
+ bool swallowed = gui_container_t::infowin_event(ev);
+
+ if (!swallowed && IS_LEFTRELEASE(ev) && getroffen(ev->mouse_pos)) {
+ uint idx=0;
+ for (auto& cell : owned_cells) {
+ if (cell->getroffen(ev->mouse_pos)) {
+ set_focus(cell);
+ if (selected_col == idx) {
+ // already selected => inverse reversed state
+ cell->reversed^=1;
+ }
+ selected_col=idx;
+ reversed=cell->reversed;
+ call_listeners((long)selected_col);
+ break;
+ }
+ idx++;
+ }
+ }
+
+ return swallowed;
+}
+
diff --git a/gui/components/sortable_table_header.h b/gui/components/sortable_table_header.h
new file mode 100644
index 00000000000..5882b32b40e
--- /dev/null
+++ b/gui/components/sortable_table_header.h
@@ -0,0 +1,74 @@
+/*
+ * This file is part of the Simutrans-Extended project under the Artistic License.
+ * (see LICENSE.txt)
+ */
+
+#ifndef GUI_COMPONENTS_SORTABLE_TABLE_HEADER_H
+#define GUI_COMPONENTS_SORTABLE_TABLE_HEADER_H
+
+
+#include "gui_container.h"
+#include "gui_action_creator.h"
+
+class sortable_header_cell_t : /*public gui_action_creator_t,*/ public gui_component_t
+{
+ const char* text;
+ bool enabled=true;
+ scr_coord_val min_width; // element width = without padding
+
+public:
+ sortable_header_cell_t(char const* const text_, bool enable=true);
+
+ scr_coord_val get_min_width() { return min_width; }
+
+ void set_width(scr_coord_val new_width) OVERRIDE;
+
+ bool reversed = false;
+ bool selected = false;
+ void enable(bool yesno = true) { enabled = yesno; }
+ void draw(scr_coord offset) OVERRIDE;
+
+ //bool infowin_event(event_t const* ev) OVERRIDE;
+
+ scr_size get_min_size() const OVERRIDE { return size; }
+ scr_size get_max_size() const OVERRIDE { return get_min_size(); }
+
+};
+
+class gui_sort_table_header_t : public gui_container_t, public gui_action_creator_t
+{
+ vector_tpl owned_cells; ///< we take ownership of these pointers
+ uint8 selected_col=0;
+
+ bool reversed=false;
+
+public:
+ gui_sort_table_header_t();
+ ~gui_sort_table_header_t();
+
+ void add_component(gui_component_t* comp) OVERRIDE;
+
+ template
+ C* new_component() { C* comp = new C(); add_component(comp); owned_cells.append(comp); return comp; }
+ template
+ C* new_component(const A1& a1) { C* comp = new C(a1); add_component(comp); owned_cells.append(comp); return comp; }
+
+ void set_col(uint col, scr_coord_val width);
+
+ scr_coord_val get_min_width(uint col);
+
+ void set_selection(uint32 col);
+
+ uint8 get_selected_column() { return selected_col; }
+ bool is_reversed() { return reversed; }
+
+ bool infowin_event(event_t const* ev) OVERRIDE;
+
+ void draw(scr_coord offset) OVERRIDE;
+
+ scr_size get_min_size() const OVERRIDE { return get_size(); }
+ scr_size get_max_size() const OVERRIDE { return get_min_size(); }
+};
+
+
+#endif
diff --git a/gui/components/sortable_table_vehicle.cc b/gui/components/sortable_table_vehicle.cc
new file mode 100644
index 00000000000..a95d3baf6b7
--- /dev/null
+++ b/gui/components/sortable_table_vehicle.cc
@@ -0,0 +1,385 @@
+/*
+ * This file is part of the Simutrans-Extended project under the Artistic License.
+ * (see LICENSE.txt)
+ */
+
+/*
+ * Vehicle info including availability
+ */
+
+#include "sortable_table_vehicle.h"
+#include "gui_colorbox.h"
+
+#include "../../simworld.h"
+#include "../../simcolor.h"
+
+#include "../../bauer/goods_manager.h"
+#include "../../bauer/vehikelbauer.h"
+#include "../../descriptor/vehicle_desc.h"
+
+#include "../../dataobj/translator.h"
+#include "../../display/simgraph.h"
+#include "../../player/simplay.h"
+
+#include "../../utils/simstring.h"
+
+#include "../gui_theme.h"
+#include "../vehicle_detail.h"
+#include "../../descriptor/intro_dates.h"
+
+int vehicle_row_t::sort_mode = vehicle_row_t::VH_PURCHASE_DATE;
+bool vehicle_row_t::sortreverse = false;
+
+int vehicle_desc_row_t::sort_mode = vehicle_desc_row_t::VD_SPEED;
+bool vehicle_desc_row_t::sortreverse = false;
+bool vehicle_desc_row_t::side_view_mode = true;
+uint8 vehicle_desc_row_t::filter_flag = 0;
+
+void display_insignia_dot(scr_coord_val xp, scr_coord_val yp, PIXVAL color= SYSCOL_CLASS_INSIGNIA, bool dirty=false)
+{
+ if (LINESPACE<18) {
+ display_fillbox_wh_clip_rgb(xp, yp, 2, 2, color, dirty);
+ }
+ else if (LINESPACE<24) {
+ display_fillbox_wh_clip_rgb(xp+1, yp, 1, 3, color, dirty);
+ display_fillbox_wh_clip_rgb(xp, yp+1, 3, 1, color, dirty);
+ }
+ else {
+ display_fillbox_wh_clip_rgb(xp + 1, yp, 2, 4, color, dirty);
+ display_fillbox_wh_clip_rgb(xp, yp + 1, 4, 2, color, dirty);
+ }
+}
+
+
+vehicle_side_image_cell_t::vehicle_side_image_cell_t(image_id img, const char* text_)
+ : text_cell_t(text_)
+{
+ side_image = img;
+ scr_coord_val x, y, w, h;
+ display_get_base_image_offset(side_image, &x, &y, &w, &h);
+ min_size = scr_size(w, h);
+ set_size(min_size);
+ remove_offset = scr_coord(x, y);
+}
+
+void vehicle_side_image_cell_t::draw(scr_coord offset)
+{
+ table_cell_item_t::draw(offset);
+
+ display_base_img(side_image, offset.x - remove_offset.x+ draw_offset.x, offset.y - remove_offset.y + draw_offset.y, world()->get_active_player_nr(), false, true);
+}
+
+
+vehicle_class_cell_t::vehicle_class_cell_t(const vehicle_desc_t* desc) : values_cell_t((sint64)desc->get_freight_type()->get_catg_index(), 0)
+{
+ align=centered;
+ min_size = scr_size(D_FIXED_SYMBOL_WIDTH+D_H_SPACE, D_FIXED_SYMBOL_WIDTH);
+ if (!desc->get_total_capacity() && !desc->get_overcrowded_capacity()) {
+ // no capacity => nothing to draw
+ veh_type=NULL;
+ value=0; sub_value=0;
+ }
+ else {
+ veh_type=desc;
+ if (veh_type->get_freight_type()->get_number_of_classes() > 1) {
+ // need to draw insignia dots => calculate size
+ const scr_coord_val insignia_dot_size = (LINESPACE<18) ? 2: (LINESPACE<24) ? 3 : 4;
+ uint accommodations=0;
+ for (uint8 ac=0; ac < veh_type->get_freight_type()->get_number_of_classes(); ac++) {
+ if (veh_type->get_capacity(ac)) {
+ accommodations++;
+ }
+ }
+ sub_value = veh_type->get_max_accommodation_class();
+
+ min_size.h = D_FIXED_SYMBOL_WIDTH + accommodations * insignia_dot_size *1.5;
+ min_size.w = max(D_FIXED_SYMBOL_WIDTH, veh_type->get_max_accommodation_class() * (int)(insignia_dot_size * 1.5));
+ }
+ }
+ set_size(min_size);
+}
+
+void vehicle_class_cell_t::set_width(scr_coord_val new_width)
+{
+ size.w = new_width + L_CELL_PADDING * 2;
+ draw_offset.x = (size.w - D_FIXED_SYMBOL_WIDTH) / 2;
+}
+
+void vehicle_class_cell_t::draw(scr_coord offset)
+{
+ table_cell_item_t::draw(offset);
+ if (veh_type) {
+ offset += pos;
+ display_color_img(veh_type->get_freight_type()->get_catg_symbol(), offset.x + draw_offset.x, offset.y + draw_offset.y, 0, false, false);
+ const uint8 number_of_classes = veh_type->get_freight_type()->get_number_of_classes();
+ if (number_of_classes > 1) {
+ // draw dots
+ const scr_coord_val insignia_dot_size = (LINESPACE<18) ? 2: (LINESPACE<24) ? 3 : 4;
+ scr_coord_val yoff = D_FIXED_SYMBOL_WIDTH + insignia_dot_size;
+ for (uint8 a_class = 0; a_class < number_of_classes; ++a_class) {
+ if (veh_type->get_capacity(a_class)) {
+ int xoff = -((insignia_dot_size *(a_class+1) + insignia_dot_size /2*a_class))/2;
+ for (uint8 n = 0; n < a_class + 1; ++n) {
+ display_insignia_dot(offset.x + size.w / 2 + xoff, offset.y + draw_offset.y + yoff);
+ xoff += (int)(insignia_dot_size *1.5);
+ }
+ yoff += (int)(insignia_dot_size * 1.5);
+ }
+ }
+ }
+ }
+}
+
+
+engine_type_cell_t::engine_type_cell_t(vehicle_desc_t::engine_t et) :
+ value_cell_t((sint64)et, gui_chart_t::STANDARD)
+{
+ uint8 engine_type = (uint8)et + 1;
+ value= engine_type;
+ buf.clear();
+ if (engine_type) {
+ buf.append(vehicle_builder_t::engine_type_names[engine_type]);
+ }
+ else {
+ buf.append("-");
+ align = centered;
+ color = COL_INACTIVE;
+ }
+ min_size = scr_size(proportional_string_width(buf), LINESPACE);
+ set_size(min_size);
+}
+
+
+vehicle_status_bar_t::vehicle_status_bar_t(const vehicle_desc_t* desc)
+ : values_cell_t((sint64)desc->get_basic_constraint_prev(), 0)
+{
+ veh_type=desc;
+ align = centered;
+ min_size = scr_size(VEHICLE_BAR_HEIGHT*4, VEHICLE_BAR_HEIGHT);
+ sub_value= (sint64)veh_type->get_basic_constraint_next(); // Substitute here to avoid making the size two lines.
+ set_size(min_size);
+
+ l_color = veh_type->get_basic_constraint_prev() & vehicle_desc_t::intermediate_unique ? COL_CAUTION : veh_type->get_vehicle_status_color();
+ r_color = veh_type->get_basic_constraint_next() & vehicle_desc_t::intermediate_unique ? COL_CAUTION : veh_type->get_vehicle_status_color();
+}
+
+void vehicle_status_bar_t::set_width(scr_coord_val new_width)
+{
+ size.w = new_width + L_CELL_PADDING * 2;
+ draw_offset.x = size.w/2- min_size.w/2;
+}
+
+void vehicle_status_bar_t::draw(scr_coord offset)
+{
+ table_cell_item_t::draw(offset);
+
+ offset += pos;
+ display_veh_form_wh_clip_rgb(offset.x + draw_offset.x, offset.y +draw_offset.y, VEHICLE_BAR_HEIGHT * 2, VEHICLE_BAR_HEIGHT, l_color, false, false, veh_type->get_basic_constraint_prev(), veh_type->get_interactivity());
+ display_veh_form_wh_clip_rgb(offset.x + draw_offset.x+min_size.w/2, offset.y +draw_offset.y, VEHICLE_BAR_HEIGHT * 2, VEHICLE_BAR_HEIGHT, r_color, false, true, veh_type->get_basic_constraint_next(), veh_type->get_interactivity());
+}
+
+
+vehicle_desc_row_t::vehicle_desc_row_t(const vehicle_desc_t* desc)
+{
+ veh_type = desc;
+ tooltip_buf.printf(veh_type->get_name());
+
+ // 1. image/name
+ if (side_view_mode) {
+ new_component(veh_type->get_image_id(ribi_t::dir_southwest, goods_manager_t::none), veh_type->get_name());
+ }
+ else {
+ new_component(veh_type->get_name());
+ }
+ // 2. color bar
+ new_component(veh_type);
+ // 3. value
+ new_component(veh_type->get_value(), gui_chart_t::MONEY, table_cell_item_t::right);
+ // 4. enigine type
+ new_component(veh_type->get_engine_type());
+ // 5. power
+ new_component((sint64)veh_type->get_power(), gui_chart_t::KW, table_cell_item_t::right);
+ // 6. force
+ new_component((sint64)veh_type->get_tractive_effort(), gui_chart_t::FORCE, table_cell_item_t::right);
+ // 7. speed
+ new_component((sint64)veh_type->get_topspeed(), gui_chart_t::KMPH, table_cell_item_t::right);
+ // 8. catg
+ new_component(veh_type);
+ // 9. capacity
+ new_component((sint64)veh_type->get_total_capacity(), veh_type->get_overcrowded_capacity());
+ // 10. weight
+ new_component((sint64)veh_type->get_weight(), gui_chart_t::TONNEN, table_cell_item_t::right);
+ // 11. axle load
+ new_component(veh_type->get_waytype() == water_wt ? 0 : (sint64)veh_type->get_axle_load() * 1000, gui_chart_t::TONNEN, table_cell_item_t::right);
+ // 12. intro date
+ PIXVAL status_color = veh_type->get_vehicle_status_color();
+ new_component((sint64)veh_type->get_intro_year_month(), gui_chart_t::DATE, table_cell_item_t::right, status_color == COL_SAFETY ? SYSCOL_TEXT : status_color);
+ // 13. retire date
+ sint64 retire_date= DEFAULT_RETIRE_DATE * 12;
+ if (veh_type->get_retire_year_month() != DEFAULT_RETIRE_DATE * 12 &&
+ (((!world()->get_settings().get_show_future_vehicle_info() && veh_type->will_end_prodection_soon(world()->get_timeline_year_month()))
+ || world()->get_settings().get_show_future_vehicle_info()
+ || veh_type->is_retired(world()->get_timeline_year_month()))))
+ {
+ retire_date = (sint64)veh_type->get_retire_year_month();
+
+ }
+ new_component(retire_date, gui_chart_t::DATE, table_cell_item_t::right);
+
+ //init cell height
+ for (auto& cell : owned_cells) {
+ cell->set_height(row_height);
+ }
+}
+
+void vehicle_desc_row_t::update_highlight()
+{
+ old_filter_flag=filter_flag;
+ if (!side_view_mode) {
+ set_highlight(VD_NAME, filter_flag & VL_FILTER_NAME);
+ }
+ set_highlight(VD_ENGINE_TYPE, filter_flag&VL_FILTER_FUEL);
+ set_highlight(VD_FREIGHT_TYPE, filter_flag&VL_FILTER_FREIGHT);
+ set_highlight(VD_STATUSBAR, filter_flag&VL_FILTER_UPGRADABLE);
+}
+
+bool vehicle_desc_row_t::infowin_event(const event_t* ev)
+{
+ bool swallowed = gui_scrolled_list_t::scrollitem_t::infowin_event(ev);
+ if (!swallowed && veh_type && IS_RIGHTRELEASE(ev)) {
+ vehicle_detail_t* win = dynamic_cast(win_get_magic(magic_vehicle_detail));
+ if (!win) {
+ create_win(new vehicle_detail_t(veh_type), w_info, magic_vehicle_detail);
+ }
+ else {
+ win->set_vehicle(veh_type);
+ top_win(win, false);
+ }
+ return false;
+ }
+ return swallowed;
+}
+
+void vehicle_desc_row_t::draw(scr_coord offset)
+{
+ if (filter_flag != old_filter_flag) {
+ update_highlight();
+ }
+ gui_sort_table_row_t::draw(offset);
+ // show tooltip
+ if (getroffen(get_mouse_pos() - offset)) {
+ win_set_tooltip(get_mouse_pos() + TOOLTIP_MOUSE_OFFSET, tooltip_buf, this);
+ }
+}
+
+
+vehicle_row_t::vehicle_row_t(vehicle_t* v)
+{
+ veh = v;
+ const vehicle_desc_t* veh_type = veh->get_desc();
+
+ tooltip_buf.printf(veh_type->get_name());
+
+ // 1. image
+ new_component(veh_type->get_image_id(ribi_t::dir_southwest, goods_manager_t::none, veh->get_current_livery()), veh_type->get_name());
+ // 2. color bar
+ new_component(veh_type);
+ // 3. value
+ new_component((sint64)veh->calc_sale_value(), gui_chart_t::MONEY, table_cell_item_t::right);
+ // 4. enigine type
+ new_component(veh_type->get_engine_type());
+ // 5. power
+ new_component((sint64)veh_type->get_power(), gui_chart_t::KW, table_cell_item_t::right);
+ // 6. force
+ new_component((sint64)veh_type->get_tractive_effort(), gui_chart_t::FORCE, table_cell_item_t::right);
+ // 7. speed
+ new_component((sint64)veh_type->get_topspeed(), gui_chart_t::KMPH, table_cell_item_t::right);
+ // 8. catg
+ new_component(veh_type);
+ // 9. capacity
+ new_component((sint64)veh_type->get_total_capacity(), veh_type->get_overcrowded_capacity());
+ // 10. weight
+ new_component((sint64)veh_type->get_weight(), gui_chart_t::TONNEN, table_cell_item_t::right);
+ // 11. axle load
+ new_component(veh_type->get_waytype()==water_wt ? 0: (sint64)veh_type->get_axle_load()*1000, gui_chart_t::TONNEN, table_cell_item_t::right);
+ // 12. purchase date
+ new_component((sint64)veh->get_purchase_time(), gui_chart_t::DATE, table_cell_item_t::right);
+ // 13. intro date
+ PIXVAL status_color = veh_type->get_vehicle_status_color();
+ new_component((sint64)veh_type->get_intro_year_month(), gui_chart_t::DATE, table_cell_item_t::right, status_color==COL_SAFETY ? SYSCOL_TEXT : status_color);
+ // owner
+ //new_component(veh->get_owner()->get_name());
+
+ //init cell height
+ for (auto& cell : owned_cells) {
+ cell->set_height(row_height);
+ }
+}
+
+
+bool vehicle_row_t::infowin_event(const event_t* ev)
+{
+ bool swallowed = gui_scrolled_list_t::scrollitem_t::infowin_event(ev);
+ if( !swallowed && veh && IS_RIGHTRELEASE(ev) ) {
+ vehicle_detail_t* win = dynamic_cast(win_get_magic(magic_vehicle_detail));
+ if (!win) {
+ create_win(new vehicle_detail_t(veh->get_desc()), w_info, magic_vehicle_detail);
+ }
+ else {
+ win->set_vehicle(veh->get_desc());
+ top_win(win, false);
+ }
+ return false;
+ }
+ return swallowed;
+}
+
+void vehicle_row_t::draw(scr_coord offset)
+{
+ gui_sort_table_row_t::draw(offset);
+ // show tooltip
+ if (getroffen(get_mouse_pos() - offset)) {
+ win_set_tooltip(get_mouse_pos() + TOOLTIP_MOUSE_OFFSET, tooltip_buf, this);
+ }
+}
+
+
+bool vehicle_desc_row_t::compare(const gui_component_t* aa, const gui_component_t* bb)
+{
+ const vehicle_desc_row_t* row_a = dynamic_cast(aa);
+ const vehicle_desc_row_t* row_b = dynamic_cast(bb);
+ if (row_a == NULL || row_b == NULL) {
+ dbg->warning("vehicle_desc_row_t::compare()", "row data error");
+ return false;
+ }
+
+ const table_cell_item_t* a = row_a->get_element(sort_mode);
+ const table_cell_item_t* b = row_b->get_element(sort_mode);
+ if (a == NULL || b == NULL) {
+ dbg->warning("vehicle_desc_row_t::compare()", "Could not get table_cell_item_t successfully");
+ return false;
+ }
+
+ int cmp = gui_sort_table_row_t::compare(a, b);
+ return sortreverse ? cmp < 0 : cmp > 0; // Do not include 0
+}
+
+bool vehicle_row_t::compare(const gui_component_t* aa, const gui_component_t* bb)
+{
+ const vehicle_row_t* row_a = dynamic_cast(aa);
+ const vehicle_row_t* row_b = dynamic_cast(bb);
+ if (row_a == NULL || row_b == NULL) {
+ dbg->warning("vehicle_row_t::compare()", "row data error");
+ return false;
+ }
+
+ const table_cell_item_t* a = row_a->get_element(sort_mode);
+ const table_cell_item_t* b = row_b->get_element(sort_mode);
+ if (a == NULL || b == NULL) {
+ dbg->warning("vehicle_row_t::compare()", "Could not get table_cell_item_t successfully");
+ return false;
+ }
+
+ int cmp = gui_sort_table_row_t::compare(a, b);
+ return sortreverse ? cmp < 0 : cmp > 0; // Do not include 0
+}
diff --git a/gui/components/sortable_table_vehicle.h b/gui/components/sortable_table_vehicle.h
new file mode 100644
index 00000000000..4ef3c8712d5
--- /dev/null
+++ b/gui/components/sortable_table_vehicle.h
@@ -0,0 +1,172 @@
+/*
+ * This file is part of the Simutrans-Extended project under the Artistic License.
+ * (see LICENSE.txt)
+ */
+
+#ifndef GUI_COMPONENTS_SORTABLE_TABLE_VEHICLE_H
+#define GUI_COMPONENTS_SORTABLE_TABLE_VEHICLE_H
+
+
+#include "sortable_table.h"
+#include "gui_aligned_container.h"
+#include "gui_label.h"
+#include "gui_scrolled_list.h"
+#include "gui_image.h"
+#include "gui_table.h"
+#include "../../display/scr_coord.h"
+#include "../../vehicle/vehicle.h"
+#include "../../utils/cbuffer_t.h"
+
+#include "gui_scrolled_list.h"
+
+#include "gui_chart.h"
+#include "gui_container.h"
+
+
+class vehicle_side_image_cell_t : public text_cell_t
+{
+ image_id side_image;
+ scr_coord remove_offset;
+
+public:
+ vehicle_side_image_cell_t(image_id img, const char* text = NULL);
+
+ void draw(scr_coord offset) OVERRIDE;
+};
+
+
+class vehicle_class_cell_t : public values_cell_t
+{
+ const vehicle_desc_t* veh_type;
+
+public:
+ vehicle_class_cell_t(const vehicle_desc_t* desc);
+
+ void set_width(scr_coord_val new_width) OVERRIDE;
+
+ const uint8 get_type() const OVERRIDE { return cell_values; }
+
+ void draw(scr_coord offset) OVERRIDE;
+};
+
+class engine_type_cell_t : public value_cell_t
+{
+public:
+ engine_type_cell_t(vehicle_desc_t::engine_t et);
+};
+
+
+class vehicle_status_bar_t : public values_cell_t
+{
+ const vehicle_desc_t* veh_type;
+ PIXVAL l_color, r_color;
+
+public:
+ vehicle_status_bar_t(const vehicle_desc_t* desc);
+
+ void set_width(scr_coord_val new_width) OVERRIDE;
+
+ void draw(scr_coord offset) OVERRIDE;
+};
+
+
+class vehicle_desc_row_t : public gui_sort_table_row_t
+{
+public:
+ enum sort_mode_t {
+ VD_NAME,
+ VD_STATUSBAR,
+ VD_COST,
+ VD_ENGINE_TYPE,
+ VD_POWER,
+ VD_TRACTIVE_FORCE,
+ VD_SPEED,
+ VD_FREIGHT_TYPE,
+ VD_CAPACITY,
+ VD_WEIGHT,
+ VD_AXLE_LOAD,
+ VD_INTRO_DATE,
+ VL_RETIRE_DATE,
+ MAX_COLS
+ };
+
+ static int sort_mode;
+ static bool sortreverse;
+ // false=show name, true=show side view
+ static bool side_view_mode;
+
+ // 1=fuel filer on, 2=freight type fiter on
+ enum {
+ VL_NO_FILTER = 0,
+ VL_FILTER_NAME = 1 << 0,
+ VL_FILTER_FUEL = 1 << 1,
+ VL_FILTER_FREIGHT = 1 << 2,
+ VL_FILTER_UPGRADABLE = 1 << 3
+ };
+ static uint8 filter_flag;
+ uint8 old_filter_flag=0;
+
+private:
+ const vehicle_desc_t* veh_type=NULL;
+ cbuffer_t tooltip_buf;
+
+ void update_highlight();
+
+public:
+ vehicle_desc_row_t(const vehicle_desc_t* desc);
+
+ char const* get_text() const OVERRIDE { return veh_type->get_name(); }
+
+ bool infowin_event(event_t const* ev) OVERRIDE;
+
+ void draw(scr_coord offset) OVERRIDE;
+
+ static bool compare(const gui_component_t* aa, const gui_component_t* bb);
+};
+
+// Generate list based on vehicle_t instead of vehicle_desc
+class vehicle_row_t : public gui_sort_table_row_t
+{
+public:
+ //VD_xxx : Fields that reference vehicle_desc
+ //VH_xxx : Fields that reference vehicle_t
+ enum sort_mode_t {
+ VD_LENGTH, // image with livery
+ VD_STATUSBAR,
+ VH_COST,
+ VD_ENGINE_TYPE,
+ VD_POWER,
+ VD_TRACTIVE_FORCE,
+ VD_SPEED,
+ VD_FREIGHT_TYPE,
+ VD_CAPACITY,
+ VD_WEIGHT,
+ VD_AXLE_LOAD,
+ VH_PURCHASE_DATE,
+ VD_INTRO_DATE,
+ MAX_COLS
+ };
+
+ static int sort_mode;
+ static bool sortreverse;
+
+private:
+ vehicle_t* veh;
+ cbuffer_t tooltip_buf;
+
+public:
+ vehicle_row_t(vehicle_t* v);
+
+ vehicle_t* get_vehicle() const { return veh; }
+
+ char const* get_text() const OVERRIDE { return veh->get_desc()->get_name(); }
+
+ bool infowin_event(event_t const* ev) OVERRIDE;
+
+ void draw(scr_coord offset) OVERRIDE;
+
+ static bool compare(const gui_component_t* aa, const gui_component_t* bb);
+};
+
+
+#endif
diff --git a/gui/convoi_info_t.cc b/gui/convoi_info_t.cc
index dffbf72ccc9..e348c169ba9 100644
--- a/gui/convoi_info_t.cc
+++ b/gui/convoi_info_t.cc
@@ -341,12 +341,16 @@ void convoi_info_t::init_cargo_info_controller()
cont_tab_cargo_info.add_table(2, 2)->set_spacing(scr_size(0, 0));
{
cont_tab_cargo_info.new_component_span("Sort by",2);
+ scr_coord_val min_width=D_LABEL_WIDTH;
for( uint8 i=0; i(translator::translate(sort_text[i]), SYSCOL_TEXT);
}
freight_sort_selector.set_selection( env_t::default_sortmode(translator::translate("Origin stop"), SYSCOL_TEXT);
selector_ci_depth_from.set_selection(cargo_info_depth_from);
selector_ci_depth_from.add_listener(this);
+ selector_ci_depth_from.set_width_fixed(true);
+ selector_ci_depth_from.set_width(LINESPACE<<3);
cont_tab_cargo_info.add_component(&selector_ci_depth_from);
cont_tab_cargo_info.new_component("info_depth_to:");
@@ -377,6 +383,8 @@ void convoi_info_t::init_cargo_info_controller()
selector_ci_depth_to.new_component(translator::translate("Destination"), SYSCOL_TEXT);
selector_ci_depth_to.set_selection(cargo_info_depth_to);
selector_ci_depth_to.add_listener(this);
+ selector_ci_depth_to.set_width_fixed(true);
+ selector_ci_depth_to.set_width(LINESPACE<<3);
cont_tab_cargo_info.add_component(&selector_ci_depth_to);
}
cont_tab_cargo_info.end_table();
diff --git a/gui/depot_frame.cc b/gui/depot_frame.cc
index 8c9208706c1..b42049f531c 100644
--- a/gui/depot_frame.cc
+++ b/gui/depot_frame.cc
@@ -51,6 +51,7 @@
#include "depot_frame.h"
#include "convoi_detail_t.h"
+#include "vehicle_manager.h"
bool depot_frame_t::compare_line(linehandle_t const& a, linehandle_t const& b)
@@ -111,7 +112,7 @@ depot_frame_t::depot_frame_t(depot_t* depot) :
void depot_frame_t::init(depot_t *dep)
{
depot = dep;
- reset_depot_name();
+ set_name(translator::translate(depot->get_name()));
set_owner(depot->get_owner());
icnv = depot->convoi_count()-1;
@@ -184,21 +185,31 @@ void depot_frame_t::init_table()
set_margin(scr_size(0,0), scr_size(0,0));
add_table(1,0)->set_margin(scr_size(D_MARGIN_LEFT, D_MARGIN_TOP), scr_size(D_MARGIN_RIGHT, 0));
- add_table(3,1);
+ add_table(5,1);
{
- name_input.set_text(name, sizeof(name));
- name_input.add_listener(this);
- add_component(&name_input);
-
// Bolt image for electrified depots:
img_bolt.set_image(skinverwaltung_t::electricity->get_image_id(0), true);
img_bolt.set_rigid(true);
add_component(&img_bolt);
lb_traction_types.set_color(SYSCOL_TRACTION_TYPE);
add_component(&lb_traction_types);
+
+ new_component();
+
+ lb_vehicle_count.init(SYSCOL_TEXT, gui_label_t::right);
+ add_component(&lb_vehicle_count);
+
+ bt_manage.init(button_t::roundbox_state | button_t::flexible, "veh_mgr");
+ if (skinverwaltung_t::open_window) {
+ bt_manage.set_image(skinverwaltung_t::open_window->get_image_id(0));
+ bt_manage.set_image_position_right(true);
+ }
+ bt_manage.add_listener(this);
+ bt_manage.set_tooltip("Open the vehicle management window");
+ add_component(&bt_manage);
}
end_table();
- add_table(3,2);
+ add_table(2,2);
{
// text will be translated by ourselves (after update data)!
add_component(&lb_convois);
@@ -206,8 +217,6 @@ void depot_frame_t::init_table()
convoy_selector.set_highlight_color(color_idx_to_rgb(depot->get_owner()->get_player_color1() + 1));
convoy_selector.add_listener(this);
add_component(&convoy_selector);
- lb_vehicle_count.init(SYSCOL_TEXT,gui_label_t::right);
- add_component(&lb_vehicle_count);
/*
* [SELECT ROUTE]:
@@ -228,32 +237,38 @@ void depot_frame_t::init_table()
}
end_table();
- line_selector.add_listener(this);
- line_selector.set_highlight_color( color_idx_to_rgb(depot->get_owner()->get_player_color1() + 1));
- line_selector.set_wrapping(false);
- line_selector.set_focusable(true);
- add_component(&line_selector);
-
- add_table(3,1)->set_spacing(scr_size(0,0));
+ add_table(2, 1);
{
- // [freight type filter buttons]
- filter_btn_all_pas.init(button_t::roundbox_state, NULL, scr_coord(0,0), scr_size(D_BUTTON_HEIGHT, D_BUTTON_HEIGHT));
- filter_btn_all_pas.set_image(skinverwaltung_t::passengers->get_image_id(0));
- filter_btn_all_pas.set_tooltip("filter_pas_line");
- filter_btn_all_pas.add_listener(this);
- add_component(&filter_btn_all_pas);
-
- filter_btn_all_mails.init(button_t::roundbox_state, NULL, scr_coord(0,0), scr_size(D_BUTTON_HEIGHT, D_BUTTON_HEIGHT));
- filter_btn_all_mails.set_image(skinverwaltung_t::mail->get_image_id(0));
- filter_btn_all_mails.set_tooltip("filter_mail_line");
- filter_btn_all_mails.add_listener(this);
- add_component(&filter_btn_all_mails);
-
- filter_btn_all_freights.init(button_t::roundbox_state, NULL, scr_coord(0,0), scr_size(D_BUTTON_HEIGHT, D_BUTTON_HEIGHT));
- filter_btn_all_freights.set_image(skinverwaltung_t::goods->get_image_id(0));
- filter_btn_all_freights.set_tooltip("filter_freight_line");
- filter_btn_all_freights.add_listener(this);
- add_component(&filter_btn_all_freights);
+ line_selector.add_listener(this);
+ line_selector.set_highlight_color( color_idx_to_rgb(depot->get_owner()->get_player_color1() + 1));
+ line_selector.set_wrapping(false);
+ line_selector.set_focusable(true);
+ add_component(&line_selector);
+
+ add_table(3,1)->set_spacing(scr_size(0,0));
+ {
+ // [freight type filter buttons]
+ filter_btn_all_pas.init(button_t::imagebox_state, NULL, scr_coord(0,0), scr_size(D_BUTTON_HEIGHT, D_BUTTON_HEIGHT));
+ filter_btn_all_pas.set_image(skinverwaltung_t::passengers->get_image_id(0));
+ filter_btn_all_pas.set_tooltip(translator::translate("filter_pas_line"));
+ filter_btn_all_pas.set_no_translate(false);
+ filter_btn_all_pas.add_listener(this);
+ add_component(&filter_btn_all_pas);
+
+ filter_btn_all_mails.init(button_t::imagebox_state, NULL, scr_coord(0,0), scr_size(D_BUTTON_HEIGHT, D_BUTTON_HEIGHT));
+ filter_btn_all_mails.set_image(skinverwaltung_t::mail->get_image_id(0));
+ filter_btn_all_mails.set_tooltip("filter_mail_line");
+ filter_btn_all_mails.set_no_translate(false);
+ filter_btn_all_mails.add_listener(this);
+ add_component(&filter_btn_all_mails);
+
+ filter_btn_all_freights.init(button_t::imagebox_state, NULL, scr_coord(0,0), scr_size(D_BUTTON_HEIGHT, D_BUTTON_HEIGHT));
+ filter_btn_all_freights.set_image(skinverwaltung_t::goods->get_image_id(0));
+ filter_btn_all_freights.set_tooltip("filter_freight_line");
+ filter_btn_all_freights.add_listener(this);
+ add_component(&filter_btn_all_freights);
+ }
+ end_table();
}
end_table();
}
@@ -476,34 +491,12 @@ void depot_frame_t::build_line_list()
}
-void depot_frame_t::rename_depot()
-{
- const char *t = name_input.get_text();
- // only change if old name and current name are the same
- // otherwise some unintended undo if renaming would occur
- if( t && t[0] && strcmp(t, depot->get_name()) && strcmp(old_name, depot->get_name())==0) {
- // text changed => call tool
- cbuffer_t buf;
- buf.printf("d%s,%s", depot->get_pos().get_str(), t);
- tool_t *tool = create_tool(TOOL_RENAME | SIMPLE_TOOL);
- tool->set_default_param(buf);
- welt->set_tool(tool, depot->get_owner());
- // since init always returns false, it is safe to delete immediately
- delete tool;
- // do not trigger this command again
- tstrncpy(old_name, depot->get_name(), sizeof(old_name));
- }
-}
-
void depot_frame_t::reset_depot_name()
{
- tstrncpy(old_name, depot->get_name(), sizeof(old_name));
- tstrncpy(name, depot->get_name(), sizeof(name));
set_name(translator::translate(depot->get_name()));
}
-
sint64 depot_frame_t::calc_sale_value(const vehicle_desc_t *veh_type)
{
sint64 wert = 0;
@@ -593,6 +586,10 @@ bool depot_frame_t::action_triggered( gui_action_creator_t *comp, value_t p)
create_win({ 20, 20 }, new convoi_detail_t(cnv), w_info, magic_convoi_detail + cnv.get_id());
return true;
}
+ else if (comp == &bt_manage) {
+ create_win({ 20, 20 }, new vehicle_manager_t(depot), w_info, magic_vehicle_manager + depot->get_owner_nr());
+ return true;
+ }
else if( comp == &bt_copy_convoi )
{
if( cnv.is_bound() && cnv->all_vehicles_are_buildable())
@@ -689,10 +686,6 @@ bool depot_frame_t::action_triggered( gui_action_creator_t *comp, value_t p)
build_line_list();
return true;
}
- else if (comp == &name_input) {
- // send rename command if necessary
- rename_depot();
- }
else {
return false;
}
@@ -787,6 +780,7 @@ void depot_frame_t::draw(scr_coord pos, scr_size size)
bt_start.enable( action_allowed );
bt_schedule.enable( action_allowed );
bt_sell.enable( action_allowed );
+ bt_manage.enable(action_allowed);
convoihandle_t cnv = depot->get_convoi(icnv);
line_button.enable( action_allowed && cnv.is_bound() && cnv->get_line().is_bound() );
diff --git a/gui/depot_frame.h b/gui/depot_frame.h
index 6110450281f..10c81d0dc2f 100644
--- a/gui/depot_frame.h
+++ b/gui/depot_frame.h
@@ -51,9 +51,6 @@ class depot_frame_t : public gui_frame_t, public action_listener_t
*/
gui_label_buf_t lb_convois, lb_vehicle_count, lb_traction_types;
- char name[256], old_name[256];
- gui_textinput_t name_input;
-
/// contains the current translation of "new convoi"
const char* new_convoy_text;
gui_combobox_t convoy_selector;
@@ -63,6 +60,7 @@ class depot_frame_t : public gui_frame_t, public action_listener_t
button_t bt_schedule;
button_t bt_sell;
button_t bt_details;
+ button_t bt_manage;
cbuffer_t txt_convoi_cost;
@@ -111,9 +109,6 @@ class depot_frame_t : public gui_frame_t, public action_listener_t
static bool compare_line(linehandle_t const& l1, linehandle_t const& l2);
- /// Renames the depot to the name given in the text input field
- void rename_depot();
-
public:
// the next two are only needed for depot_t update notifications
void activate_convoi( convoihandle_t cnv );
diff --git a/gui/depotlist_frame.cc b/gui/depotlist_frame.cc
index 4aef052e57c..3e28d37230c 100644
--- a/gui/depotlist_frame.cc
+++ b/gui/depotlist_frame.cc
@@ -10,7 +10,6 @@
#include "../player/simplay.h"
#include "../simcity.h"
-#include "../simdepot.h"
#include "../simskin.h"
#include "../simworld.h"
@@ -25,244 +24,193 @@
#include "../boden/wege/strasse.h"
#include "../bauer/vehikelbauer.h"
-enum sort_mode_t { by_name, by_waytype, by_convoys, by_vehicle, by_coord, by_region, SORT_MODES };
+#include "../descriptor/building_desc.h"
+#include "../display/viewport.h"
+
+static const char* const dl_header_text[depotlist_row_t::MAX_COLS] =
+{
+ "", "Name", "convoys stored", "vehicles stored", "koord", "by_region", "City", "Fixed Costs", "Built in"
+};
+
+int depotlist_row_t::sort_mode = 0;
+bool depotlist_row_t::sortreverse = false;
+
-uint8 depotlist_stats_t::sort_mode = by_name;
-bool depotlist_stats_t::reverse = false;
-uint16 depotlist_stats_t::name_width = D_LABEL_WIDTH;
uint8 depotlist_frame_t::selected_tab = 0;
static karte_ptr_t welt;
-bool depotlist_frame_t::is_available_wt(waytype_t wt)
+
+depot_type_cell_t::depot_type_cell_t(obj_t::typ typ, bool is_electrified) : values_cell_t((sint64)typ, (sint64)is_electrified, SYSCOL_TEXT, true)
{
- switch (wt) {
- case maglev_wt:
- return maglev_t::default_maglev ? true : false;
- case monorail_wt:
- return monorail_t::default_monorail ? true : false;
- case track_wt:
- return schiene_t::default_schiene ? true : false;
- case tram_wt:
- return vehicle_builder_t::get_info(tram_wt).empty() ? false : true;
- case narrowgauge_wt:
- return narrowgauge_t::default_narrowgauge ? true : false;
- case road_wt:
- return strasse_t::default_strasse ? true : false;
- case water_wt:
- return vehicle_builder_t::get_info(water_wt).empty() ? false : true;
- case air_wt:
- return runway_t::default_runway ? true : false;
- default:
- return false;
- }
- return false;
+ align = centered;
+ min_size = scr_size(D_FIXED_SYMBOL_WIDTH + LINESPACE, ((LINESPACE-2)*2/3-1));
+ color = minimap_t::get_depot_color(typ);
+
+ set_size(min_size);
}
-depotlist_stats_t::depotlist_stats_t(depot_t *d)
+void depot_type_cell_t::draw(scr_coord offset)
{
- this->depot = d;
- set_table_layout(7,1);
- new_component(0);
- const waytype_t wt = d->get_wegtyp();
+ table_cell_item_t::draw(offset);
- const weg_t *w = welt->lookup(depot->get_pos())->get_weg(wt != tram_wt ? wt : track_wt);
- const bool way_electrified = w ? w->is_electrified() : false;
- if (way_electrified) {
- new_component()->set_image(skinverwaltung_t::electricity->get_image_id(0), true);
- }
- else {
- new_component(skinverwaltung_t::electricity->get_image(0)->w);
- }
+ offset += pos;
- lb_name.buf().append( translator::translate(depot->get_name()) );
- const scr_coord_val temp_w = proportional_string_width( translator::translate(depot->get_name()) );
- if (temp_w > name_width) {
- name_width = temp_w;
+ display_depot_symbol_rgb(offset.x + draw_offset.x, offset.y + draw_offset.y-1, LINESPACE-2, color, false);
+
+ if (sub_value) {
+ display_color_img(skinverwaltung_t::electricity->get_image_id(0), offset.x + draw_offset.x + LINESPACE+2, offset.y + draw_offset.y + (LINESPACE * 2 / 3 - 1)/2 - D_FIXED_SYMBOL_WIDTH/2, 0, false, false);
}
- lb_name.set_fixed_width(name_width);
- add_component(&lb_name);
+}
- lb_cnv_count.init(SYSCOL_TEXT, gui_label_t::right);
- lb_cnv_count.set_fixed_width(proportional_string_width(translator::translate("%d convois")));
- add_component(&lb_cnv_count);
- lb_vh_count.init(SYSCOL_TEXT, gui_label_t::right);
- lb_vh_count.set_fixed_width(proportional_string_width(translator::translate("%d vehicles")));
- add_component(&lb_vh_count);
+depotlist_row_t::depotlist_row_t(depot_t *dep)
+{
+ assert(depot!=NULL);
+ depot = dep;
- add_table(2,1)->set_spacing(scr_size(0,0));
+ // 1. type
+ const waytype_t wt = depot->get_wegtyp();
+ const weg_t* w = welt->lookup(depot->get_pos())->get_weg(wt != tram_wt ? wt : track_wt);
+ const bool way_electrified = w ? w->is_electrified() : false;
+ new_component(depot->get_typ(), way_electrified);
+ // 2. name
+ new_component(depot->get_name());
+ // 3. convoys
+ old_convoys = depot->get_convoy_list().get_count();
+ new_component((sint64)old_convoys, gui_chart_t::STANDARD, table_cell_item_t::right, old_convoys ? SYSCOL_TEXT : SYSCOL_TEXT_INACTIVE);
+ // 4. vehicle count and listed count
+ const sint64 listed_vehicles = (sint64)depot->get_vehicles_for_sale().get_count();
+ old_vehicles = depot->get_vehicle_list().get_count();
+ new_component((sint64)old_vehicles+listed_vehicles, listed_vehicles, SYSCOL_TEXT, true);
+ // 5. pos
+ const koord depot_pos = depot->get_pos().get_2d();
+ new_component(depot_pos, table_cell_item_t::centered);
+ // 6. region
+ new_component(welt->get_settings().regions.empty() ? "" : translator::translate(welt->get_region_name(depot_pos).c_str()));
+ // 7. city
+ stadt_t* c = welt->get_city(depot_pos);
+ new_component(c ? c->get_name() : "-", c ? c->get_center(): koord::invalid);
+ // 8. Fixed Costs
+ sint64 maintenance = depot->get_tile()->get_desc()->get_maintenance();
+ if (maintenance == PRICE_MAGIC)
{
- // pos button (depot type)
- //// Change the symbol size in the button depending on the depot level
- ////const uint8 symbol_width = LINEASCENT-2 + min(2,d->get_tile()->get_desc()->get_level()/3)*2;
- //gotopos.set_typ(button_t::posbutton_automatic);
- gotopos.set_typ(button_t::depot_automatic);
- gotopos.set_targetpos3d(depot->get_pos());
- gotopos.text_color = minimap_t::get_depot_color(depot->get_typ());
- add_component(&gotopos);
-
- lb_region.buf().printf( " %s ", depot->get_pos().get_2d().get_fullstr() );
- stadt_t* c = welt->get_city(depot->get_pos().get_2d());
- if (c) {
- lb_region.buf().append("- ");
- lb_region.buf().append( c->get_name() );
- }
- if (!welt->get_settings().regions.empty()) {
- if (!c) {
- lb_region.buf().append("-");
- }
- lb_region.buf().printf(" (%s)", translator::translate(welt->get_region_name(depot->get_pos().get_2d()).c_str()));
- }
- lb_region.update();
- add_component(&lb_region);
+ maintenance = depot->get_tile()->get_desc()->get_level() * welt->get_settings().maint_building;
}
- end_table();
- update_label();
-
- new_component();
-}
+ new_component((double)welt->calc_adjusted_monthly_figure(maintenance), gui_chart_t::MONEY, table_cell_item_t::right);
+ // 9. Built date
+ new_component((sint64)depot->get_purchase_time(), gui_chart_t::DATE, table_cell_item_t::right);
+ // Possibility of adding items:
+ // supported traction types
-void depotlist_stats_t::update_label()
-{
- lb_cnv_count.buf().clear();
- int cnvs = depot->convoi_count();
- if( cnvs == 0 ) {
-// buf.append( translator::translate( "no convois" ) );
+ // init cells height
+ for (auto& cell : owned_cells) {
+ cell->set_height(row_height);
}
- else if( cnvs == 1 ) {
- lb_cnv_count.buf().append( translator::translate( "1 convoi" ) );
- }
- else {
- lb_cnv_count.buf().printf( translator::translate( "%d convois" ), cnvs );
- }
- lb_cnv_count.update();
- int vhls = depot->get_vehicle_list().get_count();
- lb_vh_count.buf().clear();
- if( vhls == 0 ) {
- //buf.append( translator::translate( "Keine Einzelfahrzeuge im Depot" ) );
- }
- else if( vhls == 1 ) {
- lb_vh_count.buf().append( translator::translate( "1 vehicle" ) );
- }
- else {
- lb_vh_count.buf().printf( translator::translate( "%d vehicles" ), vhls );
- }
- lb_vh_count.update();
}
-
-void depotlist_stats_t::set_size(scr_size size)
+void depotlist_row_t::draw(scr_coord offset)
{
- gui_aligned_container_t::set_size(size);
+ if (old_convoys != depot->get_convoy_list().get_count()) {
+ value_cell_t *cell = dynamic_cast(owned_cells[DEPOT_CONVOYS]);
+ old_convoys = depot->get_convoy_list().get_count();
+ cell->set_value((sint64)old_convoys);
+ cell->set_color(old_convoys ? SYSCOL_TEXT : SYSCOL_TEXT_INACTIVE);
+ }
+ if (old_vehicles != depot->get_vehicle_list().get_count()) {
+ values_cell_t* cell = dynamic_cast(owned_cells[DEPOT_VEHICLES]);
+ old_vehicles = depot->get_vehicle_list().get_count();
+ cell->set_values((sint64)old_vehicles, (sint64)depot->get_vehicles_for_sale().get_count());
+ }
+ gui_sort_table_row_t::draw(offset);
}
-
-bool depotlist_stats_t::is_valid() const
+void depotlist_row_t::show_depot()
{
- return depot_t::get_depot_list().is_contained(depot);
+ if (depot->get_owner() == world()->get_active_player() ) {
+ depot->show_info();
+ }
}
-bool depotlist_stats_t::infowin_event(const event_t * ev)
+bool depotlist_row_t::infowin_event(const event_t* ev)
{
- bool swallowed = gui_aligned_container_t::infowin_event(ev);
-
- if( !swallowed && IS_LEFTRELEASE(ev) ) {
- depot->show_info();
- swallowed = true;
+ bool swallowed = gui_scrolled_list_t::scrollitem_t::infowin_event(ev);
+
+ if (!swallowed && depot) {
+ if (IS_RIGHTRELEASE(ev)) {
+ for (auto& cell : owned_cells) {
+ if (cell->get_type() == table_cell_item_t::cell_coord && cell->getroffen(ev->mouse_pos)) {
+ const coord_cell_t* coord_cell = dynamic_cast(cell);
+ const koord k = coord_cell->get_coord();
+ if (k != koord::invalid) {
+ world()->get_viewport()->change_world_position(k);
+ return true;
+ }
+ return false;
+ }
+ }
+ }
}
return swallowed;
}
-void depotlist_stats_t::draw(scr_coord pos)
-{
- update_label();
-
- gui_aligned_container_t::draw(pos);
-}
-
-bool depotlist_stats_t::compare(const gui_component_t *aa, const gui_component_t *bb)
+bool depotlist_row_t::compare(const gui_component_t* aa, const gui_component_t* bb)
{
- const depotlist_stats_t* fa = dynamic_cast(aa);
- const depotlist_stats_t* fb = dynamic_cast(bb);
- // good luck with mixed lists
- assert(fa != NULL && fb != NULL);
- depot_t *a=fa->depot, *b=fb->depot;
-
- int cmp;
- switch( sort_mode ) {
- default:
- case by_coord:
- cmp = 0;
- break;
-
- case by_region:
- cmp = welt->get_region(a->get_pos().get_2d()) - welt->get_region(b->get_pos().get_2d());
- if (cmp == 0) {
- const koord a_city_koord = welt->get_city(a->get_pos().get_2d()) ? welt->get_city(a->get_pos().get_2d())->get_pos() : koord(0, 0);
- const koord b_city_koord = welt->get_city(b->get_pos().get_2d()) ? welt->get_city(b->get_pos().get_2d())->get_pos() : koord(0, 0);
- cmp = a_city_koord.x - b_city_koord.x;
- if (cmp == 0) {
- cmp = a_city_koord.y - b_city_koord.y;
- }
- }
- break;
-
- case by_name:
- cmp = strcmp(a->get_name(), b->get_name());
- break;
+ const depotlist_row_t* row_a = dynamic_cast(aa);
+ const depotlist_row_t* row_b = dynamic_cast(bb);
+ if (row_a == NULL || row_b == NULL) {
+ dbg->warning("depotlist_row_t::compare()", "row data error");
+ return false;
+ }
- case by_waytype:
- cmp = a->get_waytype() - b->get_waytype();
- if (cmp == 0) {
- cmp = strcmp(a->get_name(), b->get_name());
- }
- break;
+ const table_cell_item_t* a = row_a->get_element(sort_mode);
+ const table_cell_item_t* b = row_b->get_element(sort_mode);
+ if (a == NULL || b == NULL) {
+ dbg->warning("depotlist_row_t::compare()", "Could not get table_cell_item_t successfully");
+ return false;
+ }
- case by_convoys:
- cmp = a->convoi_count() - b->convoi_count();
- if( cmp == 0 ) {
- cmp = a->get_vehicle_list().get_count() - b->get_vehicle_list().get_count();
- }
- break;
+ int cmp = gui_sort_table_row_t::compare(a, b);
+ return sortreverse ? cmp < 0 : cmp > 0; // Do not include 0
+}
- case by_vehicle:
- cmp = a->get_vehicle_list().get_count() - b->get_vehicle_list().get_count();
- if( cmp == 0 ) {
- cmp = a->convoi_count() - b->convoi_count();
- }
- break;
+bool depotlist_frame_t::is_available_wt(waytype_t wt)
+{
+ switch (wt) {
+ case maglev_wt:
+ return maglev_t::default_maglev ? true : false;
+ case monorail_wt:
+ return monorail_t::default_monorail ? true : false;
+ case track_wt:
+ return schiene_t::default_schiene ? true : false;
+ case tram_wt:
+ return vehicle_builder_t::get_info(tram_wt).empty() ? false : true;
+ case narrowgauge_wt:
+ return narrowgauge_t::default_narrowgauge ? true : false;
+ case road_wt:
+ return strasse_t::default_strasse ? true : false;
+ case water_wt:
+ return vehicle_builder_t::get_info(water_wt).empty() ? false : true;
+ case air_wt:
+ return runway_t::default_runway ? true : false;
+ default:
+ return false;
}
- if (cmp == 0) {
- cmp = koord_distance( a->get_pos(), koord( 0, 0 ) ) - koord_distance( b->get_pos(), koord( 0, 0 ) );
- if( cmp == 0 ) {
- cmp = a->get_pos().x - b->get_pos().x;
- }
- }
- return reverse ? cmp > 0 : cmp < 0;
+ return false;
}
-
-static const char *sort_text[SORT_MODES] = {
- "hl_btn_sort_name",
- "waytype",
- "convoys stored",
- "vehicles stored",
- "koord",
- "by_region"
-};
-
depotlist_frame_t::depotlist_frame_t(player_t *player) :
gui_frame_t( translator::translate("dp_title"), player ),
- scrolly(gui_scrolled_list_t::windowskin, depotlist_stats_t::compare)
+ scrolly(gui_scrolled_list_t::windowskin, depotlist_row_t::compare),
+ scroll_tab(&cont_sortable, true, false)
{
this->player = player;
@@ -272,7 +220,8 @@ depotlist_frame_t::depotlist_frame_t(player_t *player) :
depotlist_frame_t::depotlist_frame_t() :
gui_frame_t(translator::translate("dp_title"), NULL),
- scrolly(gui_scrolled_list_t::windowskin, depotlist_stats_t::compare)
+ scrolly(gui_scrolled_list_t::windowskin, depotlist_row_t::compare),
+ scroll_tab(&cont_sortable, true, false)
{
player = NULL;
@@ -284,48 +233,38 @@ void depotlist_frame_t::init_table()
{
last_depot_count = 0;
- set_table_layout(1,0);
+ scrolly.add_listener(this);
+ scrolly.set_show_scroll_x(false);
+ scrolly.set_checkered(true);
+ scrolly.set_scroll_amount_y(LINESPACE + D_H_SPACE + 2); // default cell height
- add_table(3,1);
- {
- new_component("hl_txt_sort");
- add_table(3,1);
- {
- sortedby.clear_elements();
- for (int i = 0; i < SORT_MODES; i++) {
- sortedby.new_component(translator::translate(sort_text[i]), SYSCOL_TEXT);
- }
- sortedby.set_selection(depotlist_stats_t::sort_mode);
- sortedby.add_listener(this);
- sortedby.set_width_fixed(true);
- sortedby.set_width(LINESPACE*12);
- add_component(&sortedby);
-
- // sort asc/desc switching button
- sort_order.init(button_t::sortarrow_state, "");
- sort_order.set_tooltip(translator::translate("hl_btn_sort_order"));
- sort_order.add_listener(this);
- sort_order.pressed = depotlist_stats_t::reverse;
- add_component(&sort_order);
-
- new_component(D_H_SPACE*2);
- }
- end_table();
+ scroll_tab.set_maximize(true);
- lb_depot_counter.set_fixed_width(proportional_string_width("8888/8888"));
- add_component(&lb_depot_counter);
+ // init table sort buttons
+ table_header.add_listener(this);
+ for (uint8 col = 0; col < depotlist_row_t::MAX_COLS; col++) {
+ table_header.new_component(dl_header_text[col]);
}
- end_table();
- tabs.init_tabs(&scrolly);
+ cont_sortable.set_margin(NO_SPACING, NO_SPACING);
+ cont_sortable.set_spacing(NO_SPACING);
+ cont_sortable.set_table_layout(1, 2);
+ cont_sortable.set_alignment(ALIGN_TOP); // Without this, the layout will be broken if the height is small.
+ cont_sortable.add_component(&table_header);
+ cont_sortable.add_component(&scrolly);
+
+ set_table_layout(1,0);
+
+ lb_depot_counter.set_fixed_width(proportional_string_width("8888/8888"));
+ add_component(&lb_depot_counter);
+
+ tabs.init_tabs(&scroll_tab);
tabs.add_listener(this);
add_component(&tabs);
+ set_min_windowsize(scr_size(LINESPACE*24, LINESPACE*12));
fill_list();
set_resizemode(diagonal_resize);
- scrolly.set_maximize(true);
- scrolly.set_checkered(true);
- reset_min_windowsize();
}
/**
@@ -336,15 +275,18 @@ bool depotlist_frame_t::action_triggered( gui_action_creator_t *comp,value_t v)
if (comp == &tabs) {
fill_list();
}
- else if(comp == &sortedby) {
- depotlist_stats_t::sort_mode = max(0, v.i);
+ else if (comp == &table_header) {
+ depotlist_row_t::sort_mode = v.i;
+ table_header.set_selection(depotlist_row_t::sort_mode);
+ depotlist_row_t::sortreverse = table_header.is_reversed();
scrolly.sort(0);
}
- else if (comp == &sort_order) {
- depotlist_stats_t::reverse = !depotlist_stats_t::reverse;
- scrolly.sort(0);
- sort_order.pressed = depotlist_stats_t::reverse;
+ else if ( comp == &scrolly ) {
+ scrolly.get_selection();
+ depotlist_row_t* row = (depotlist_row_t*)scrolly.get_element(v.i);
+ row->show_depot();
}
+
return true;
}
@@ -356,7 +298,7 @@ void depotlist_frame_t::fill_list()
for(depot_t* const depot : depot_t::get_depot_list()) {
if( depot->get_owner() == player ) {
if( tabs.get_active_tab_index() == 0 || depot->get_waytype() == tabs.get_active_tab_waytype() ) {
- scrolly.new_component(depot);
+ scrolly.new_component(depot);
}
p_total++;
}
@@ -366,6 +308,39 @@ void depotlist_frame_t::fill_list()
scrolly.sort(0);
scrolly.set_size(scr_size(get_windowsize().w, scrolly.get_size().h));
+ // recalc stats table width
+ scr_coord_val max_widths[depotlist_row_t::MAX_COLS] = {};
+
+ // check column widths
+ table_header.set_selection(depotlist_row_t::sort_mode);
+ table_header.set_width(D_H_SPACE); // init width
+ for (uint c = 0; c < depotlist_row_t::MAX_COLS; c++) {
+ // get header widths
+ max_widths[c] = table_header.get_min_width(c);
+ }
+ for (int r = 0; r < scrolly.get_count(); r++) {
+ depotlist_row_t* row = (depotlist_row_t*)scrolly.get_element(r);
+ for (uint c = 0; c < depotlist_row_t::MAX_COLS; c++) {
+ max_widths[c] = max(max_widths[c], row->get_min_width(c));
+ }
+ }
+
+ // set column widths
+ for (uint c = 0; c < depotlist_row_t::MAX_COLS; c++) {
+ table_header.set_col(c, max_widths[c]);
+ }
+ table_header.set_width(table_header.get_size().w + D_SCROLLBAR_WIDTH);
+
+ for (int r = 0; r < scrolly.get_count(); r++) {
+ depotlist_row_t* row = (depotlist_row_t*)scrolly.get_element(r);
+ row->set_size(scr_size(0, row->get_size().h));
+ for (uint c = 0; c < depotlist_row_t::MAX_COLS; c++) {
+ row->set_col(c, max_widths[c]);
+ }
+ }
+
+ cont_sortable.set_size(cont_sortable.get_min_size());
+
last_depot_count = depot_t::get_depot_list().get_count();
resize(scr_coord(0, 0));
}
@@ -388,8 +363,8 @@ void depotlist_frame_t::rdwr(loadsave_t *file)
selected_tab = tabs.get_active_tab_index();
file->rdwr_byte(selected_tab);
- file->rdwr_bool(sort_order.pressed);
- uint8 s = depotlist_stats_t::sort_mode;
+ file->rdwr_bool(depotlist_row_t::sortreverse);
+ uint8 s = (uint8)depotlist_row_t::sort_mode;
file->rdwr_byte(s);
file->rdwr_byte(player_nr);
size.rdwr(file);
@@ -398,9 +373,7 @@ void depotlist_frame_t::rdwr(loadsave_t *file)
player = welt->get_player(player_nr);
gui_frame_t::set_owner(player);
win_set_magic(this, magic_depotlist + player_nr);
- sortedby.set_selection(s);
- depotlist_stats_t::sort_mode = s;
- depotlist_stats_t::reverse = sort_order.pressed;
+ depotlist_row_t::sort_mode = (int)s;
tabs.set_active_tab_index(selected_tabget_name(); }
+
+ void show_depot();
+
+ bool infowin_event(event_t const* ev) OVERRIDE;
+
+ void draw(scr_coord offset) OVERRIDE;
+
+ static bool compare(const gui_component_t* aa, const gui_component_t* bb);
+};
+
class depotlist_frame_t : public gui_frame_t, private action_listener_t
{
private:
- gui_combobox_t sortedby;
- button_t sort_order;
+ gui_sort_table_header_t table_header;
+ gui_aligned_container_t cont_sortable;
gui_scrolled_list_t scrolly;
+ gui_scrollpane_t scroll_tab;
+
gui_label_buf_t lb_depot_counter;
gui_waytype_tab_panel_t tabs;
@@ -33,8 +90,6 @@ class depotlist_frame_t : public gui_frame_t, private action_listener_t
uint32 last_depot_count;
static uint8 selected_tab;
- void fill_list();
-
void init_table();
player_t *player;
@@ -46,6 +101,8 @@ class depotlist_frame_t : public gui_frame_t, private action_listener_t
const char *get_help_filename() const OVERRIDE {return "depotlist.txt"; }
+ void fill_list();
+
bool action_triggered(gui_action_creator_t*, value_t) OVERRIDE;
void draw(scr_coord pos, scr_size size) OVERRIDE;
@@ -62,31 +119,4 @@ class depotlist_frame_t : public gui_frame_t, private action_listener_t
};
-class depotlist_stats_t : public gui_aligned_container_t, public gui_scrolled_list_t::scrollitem_t
-{
-private:
- depot_t *depot;
- gui_label_buf_t lb_name, lb_cnv_count, lb_vh_count, lb_region;
- gui_image_t waytype_symbol;
- button_t gotopos;
-
- void update_label();
-
-public:
- static uint8 sort_mode;
- static bool reverse;
- static uint16 name_width;
-
- depotlist_stats_t(depot_t *);
-
- void draw( scr_coord pos) OVERRIDE;
-
- char const* get_text() const OVERRIDE { return ""; /* label.buf().get_str(); */ }
- bool infowin_event(const event_t *) OVERRIDE;
- bool is_valid() const OVERRIDE;
- void set_size(scr_size size) OVERRIDE;
-
- static bool compare(const gui_component_t *a, const gui_component_t *b );
-};
-
#endif
diff --git a/gui/gui_theme.cc b/gui/gui_theme.cc
index 868423cc011..442dfd6d824 100644
--- a/gui/gui_theme.cc
+++ b/gui/gui_theme.cc
@@ -43,6 +43,8 @@ PIXVAL gui_theme_t::gui_color_chart_lines_odd;
PIXVAL gui_theme_t::gui_color_chart_lines_even;
PIXVAL gui_theme_t::gui_color_list_text_selected_focus;
PIXVAL gui_theme_t::gui_color_list_text_selected_nofocus;
+PIXVAL gui_theme_t::gui_color_list_background_even;
+PIXVAL gui_theme_t::gui_color_list_background_odd;
PIXVAL gui_theme_t::gui_color_list_background_selected_f;
PIXVAL gui_theme_t::gui_color_list_background_selected_nf;
PIXVAL gui_theme_t::gui_color_button_text;
@@ -195,6 +197,8 @@ void gui_theme_t::init_gui_defaults()
gui_color_list_text_selected_focus = color_idx_to_rgb(COL_WHITE);
gui_color_list_text_selected_nofocus = color_idx_to_rgb(MN_GREY3);
+ gui_color_list_background_even = color_idx_to_rgb(MN_GREY2);
+ gui_color_list_background_odd = color_idx_to_rgb(MN_GREY3);
gui_color_list_background_selected_f = color_idx_to_rgb(COL_BLUE);
gui_color_list_background_selected_nf = color_idx_to_rgb(COL_LIGHT_BLUE);
@@ -620,6 +624,8 @@ bool gui_theme_t::themes_init(const char *file_name, bool init_fonts, bool init_
gui_theme_t::gui_color_chart_lines_even = (PIXVAL)contents.get_color("gui_color_chart_lines_even", SYSCOL_CHART_LINES_EVEN);
gui_theme_t::gui_color_list_text_selected_focus = (PIXVAL)contents.get_color("gui_color_list_text_selected_focus", SYSCOL_LIST_TEXT_SELECTED_FOCUS);
gui_theme_t::gui_color_list_text_selected_nofocus = (PIXVAL)contents.get_color("gui_color_list_text_selected_nofocus", SYSCOL_LIST_TEXT_SELECTED_NOFOCUS);
+ gui_theme_t::gui_color_list_background_even = (PIXVAL)contents.get_color("gui_color_list_background_even", SYSCOL_LIST_BACKGROUND_EVEN);
+ gui_theme_t::gui_color_list_background_odd = (PIXVAL)contents.get_color("gui_color_list_background_odd", SYSCOL_LIST_BACKGROUND_ODD);
gui_theme_t::gui_color_list_background_selected_f = (PIXVAL)contents.get_color("gui_color_list_background_selected_focus", SYSCOL_LIST_BACKGROUND_SELECTED_F);
gui_theme_t::gui_color_list_background_selected_nf = (PIXVAL)contents.get_color("gui_color_list_background_selected_nofocus", SYSCOL_LIST_BACKGROUND_SELECTED_NF);
gui_theme_t::gui_color_button_text = (PIXVAL)contents.get_color("gui_color_button_text", SYSCOL_BUTTON_TEXT);
diff --git a/gui/gui_theme.h b/gui/gui_theme.h
index 3ae0049c6f6..251a7b9beee 100644
--- a/gui/gui_theme.h
+++ b/gui/gui_theme.h
@@ -240,6 +240,8 @@ class gui_theme_t {
static PIXVAL gui_color_chart_lines_even; //@< Color to draw in-chart vertical even lines and text
static PIXVAL gui_color_list_text_selected_focus; //@< Colour to draw the selected element text in list when window has focus
static PIXVAL gui_color_list_text_selected_nofocus; //@< Colour to draw the selected element text in list when window is not in focus
+ static PIXVAL gui_color_list_background_even;
+ static PIXVAL gui_color_list_background_odd;
static PIXVAL gui_color_list_background_selected_f; //@< Colour to draw the selected element background in list when window has focus
static PIXVAL gui_color_list_background_selected_nf; //@< Colour to draw the selected element background in list when window is not in focus
static PIXVAL gui_color_button_text; //@< Color to draw text in normal buttons
diff --git a/gui/halt_info.cc b/gui/halt_info.cc
index a6476a9c33a..f12c1b450eb 100644
--- a/gui/halt_info.cc
+++ b/gui/halt_info.cc
@@ -901,12 +901,16 @@ void halt_info_t::init_cargo_info_controller()
cont_tab_cargo_info.add_table(2, 2)->set_spacing(NO_SPACING);
{
cont_tab_cargo_info.new_component_span("Sort by", 2);
+ scr_coord_val min_width = D_LABEL_WIDTH;
freight_sort_selector.clear_elements();
for (uint8 i = 0; i < gui_halt_cargoinfo_t::SORT_MODES; ++i) {
+ min_width = max(min_width, proportional_string_width(translator::translate(sort_text[i])));
freight_sort_selector.new_component(translator::translate(sort_text[i]), SYSCOL_TEXT);
}
freight_sort_selector.set_selection(env_t::default_sortmode < gui_halt_cargoinfo_t::SORT_MODES ? env_t::default_sortmode : 0);
freight_sort_selector.add_listener(this);
+ freight_sort_selector.set_width_fixed(true);
+ freight_sort_selector.set_width(min_width + D_SCROLLBAR_WIDTH + D_H_SPACE);
cont_tab_cargo_info.add_component(&freight_sort_selector);
sort_order.init(button_t::sortarrow_state, "");
@@ -927,6 +931,8 @@ void halt_info_t::init_cargo_info_controller()
selector_ci_depth_from.new_component(translator::translate("Origin stop"), SYSCOL_TEXT);
selector_ci_depth_from.set_selection(cargo_info_depth_from);
selector_ci_depth_from.add_listener(this);
+ selector_ci_depth_from.set_width_fixed(true);
+ selector_ci_depth_from.set_width(LINESPACE << 3);
cont_tab_cargo_info.add_component(&selector_ci_depth_from);
cont_tab_cargo_info.new_component("info_depth_to:");
@@ -936,6 +942,8 @@ void halt_info_t::init_cargo_info_controller()
selector_ci_depth_to.new_component(translator::translate("Destination"), SYSCOL_TEXT);
selector_ci_depth_to.set_selection(cargo_info_depth_to);
selector_ci_depth_to.add_listener(this);
+ selector_ci_depth_to.set_width_fixed(true);
+ selector_ci_depth_to.set_width(LINESPACE << 3);
cont_tab_cargo_info.add_component(&selector_ci_depth_to);
}
cont_tab_cargo_info.end_table();
diff --git a/gui/schedule_gui.cc b/gui/schedule_gui.cc
index 26457c32cf2..885ec916061 100644
--- a/gui/schedule_gui.cc
+++ b/gui/schedule_gui.cc
@@ -611,17 +611,17 @@ void schedule_gui_t::init_components()
line_selector.set_highlight_color(color_idx_to_rgb(player->get_player_color1() + 1));
- filter_btn_all_pas.init(button_t::roundbox_state, NULL, scr_coord(0, 0), scr_size(D_BUTTON_HEIGHT, D_BUTTON_HEIGHT));
+ filter_btn_all_pas.init(button_t::imagebox_state, NULL, scr_coord(0, 0), scr_size(D_BUTTON_HEIGHT, D_BUTTON_HEIGHT));
filter_btn_all_pas.set_image(skinverwaltung_t::passengers->get_image_id(0));
filter_btn_all_pas.set_tooltip("filter_pas_line");
filter_btn_all_pas.add_listener(this);
- filter_btn_all_mails.init(button_t::roundbox_state, NULL, scr_coord(0,0), scr_size(D_BUTTON_HEIGHT, D_BUTTON_HEIGHT));
+ filter_btn_all_mails.init(button_t::imagebox_state, NULL, scr_coord(0,0), scr_size(D_BUTTON_HEIGHT, D_BUTTON_HEIGHT));
filter_btn_all_mails.set_image(skinverwaltung_t::mail->get_image_id(0));
filter_btn_all_mails.set_tooltip("filter_mail_line");
filter_btn_all_mails.add_listener(this);
- filter_btn_all_freights.init(button_t::roundbox_state, NULL, scr_coord(0, 0), scr_size(D_BUTTON_HEIGHT, D_BUTTON_HEIGHT));
+ filter_btn_all_freights.init(button_t::imagebox_state, NULL, scr_coord(0, 0), scr_size(D_BUTTON_HEIGHT, D_BUTTON_HEIGHT));
filter_btn_all_freights.set_image(skinverwaltung_t::goods->get_image_id(0));
filter_btn_all_freights.set_tooltip("filter_freight_line");
filter_btn_all_freights.add_listener(this);
diff --git a/gui/simwin.cc b/gui/simwin.cc
index 1c7c90efb61..8e413172bd9 100644
--- a/gui/simwin.cc
+++ b/gui/simwin.cc
@@ -78,6 +78,7 @@
#include "optionen.h"
#include "vehicle_class_manager.h"
#include "player_ranking_frame.h"
+#include "vehicle_manager.h"
#include "../simversion.h"
@@ -674,6 +675,9 @@ void rdwr_all_win(loadsave_t *file)
else if (id >= magic_depotlist && id < magic_depotlist + MAX_PLAYER_COUNT) {
w = new depotlist_frame_t(wl->get_player(id - magic_depotlist));
}
+ //else if (id >= magic_vehicle_manager && id < magic_vehicle_manager + MAX_PLAYER_COUNT) {
+ // w = new vehicle_manager_t(); // TODO: support_rdwr
+ //}
else if( id>=magic_replace && id < magic_replace +0x10000 ) {
w = new replace_frame_t();
}
diff --git a/gui/simwin.h b/gui/simwin.h
index 7fcc017ea1f..356c3e228df 100644
--- a/gui/simwin.h
+++ b/gui/simwin.h
@@ -134,6 +134,7 @@ enum magic_numbers {
magic_pier_rotation_select,
magic_depot, // only used to load/save
magic_replace_line,
+ magic_vehicle_manager = magic_replace_line + MAX_PLAYER_COUNT,
magic_consist_order,
magic_script_error,
magic_max
diff --git a/gui/vehicle_manager.cc b/gui/vehicle_manager.cc
new file mode 100644
index 00000000000..46730a547d0
--- /dev/null
+++ b/gui/vehicle_manager.cc
@@ -0,0 +1,545 @@
+/*
+ * This file is part of the Simutrans-Extended project under the Artistic License.
+ * (see LICENSE.txt)
+ */
+
+#include "vehicle_manager.h"
+#include "vehicle_detail.h"
+
+#include "../simworld.h"
+#include "../simmenu.h"
+#include "../convoy.h"
+
+#include "../bauer/goods_manager.h"
+#include "../bauer/vehikelbauer.h"
+#include "../display/viewport.h"
+#include "../descriptor/vehicle_desc.h"
+#include "../descriptor/intro_dates.h"
+#include "../utils/simstring.h"
+#include "components/gui_colorbox.h"
+#include "components/gui_divider.h"
+#include "components/gui_waytype_image_box.h"
+
+#include "vehiclelist_frame.h"
+
+
+static const char* const vl_header_text[vehicle_row_t::MAX_COLS] =
+{
+ "Name", "", "Wert", "engine_type",
+ "Leistung", "TF_", "Max. speed", "", "Capacity",
+ "curb_weight", "Axle load:", "Built date", "Intro. date"
+};
+
+
+vehicle_manager_t::vehicle_manager_t(depot_t* dep) :
+ gui_frame_t(""),
+ scrolly(gui_scrolled_list_t::windowskin, vehicle_row_t::compare),
+ scroll_sortable(&cont_sortable, true, true)
+{
+ old_selections = 0;
+ old_vhicles = 0;
+
+ if (dep) {
+ depot=dep;
+ gui_frame_t::set_name(translator::translate("vehicle_management"));
+ gui_frame_t::set_owner(depot->get_owner());
+ set_table_layout(1, 0);
+ init_table();
+ }
+}
+
+void vehicle_manager_t::reset_depot_name()
+{
+ tstrncpy(old_name, depot->get_name(), sizeof(old_name));
+ tstrncpy(name, depot->get_name(), sizeof(name));
+ set_name(translator::translate(depot->get_name()));
+}
+
+void vehicle_manager_t::update_list()
+{
+ old_month = world()->get_current_month();
+ scrolly.clear_elements();
+
+ old_listed_vehicles=world()->get_listed_vehicle_number(depot->get_waytype());
+ if (dep_action==da_buy) {
+ if (old_listed_vehicles-depot->get_vehicles_for_sale().get_count()) {
+ player_t *player=depot->get_owner();
+ for (depot_t* const other_depot : depot_t::get_depot_list()) {
+ // filter
+ if (player == other_depot->get_owner()) continue;
+ if (depot->get_waytype() != other_depot->get_waytype()) continue;
+
+ for (auto vehicle : other_depot->get_vehicles_for_sale()) {
+ // Check if this depot can accept the vehicle
+ if( !depot->is_suitable_for( vehicle, vehicle->get_desc()->get_traction_type(), true ) ) continue;
+ scrolly.new_component(vehicle);
+ }
+ }
+ }
+ }
+ else {
+ for (auto vehicle : dep_action==da_cancel_listing ? depot->get_vehicles_for_sale() : depot->get_vehicle_list()){
+ scrolly.new_component(vehicle);
+ }
+ }
+ scrolly.set_selection(-1);
+ scrolly.sort(0);
+ // recalc stats table width
+ scr_coord_val max_widths[vehicle_row_t::MAX_COLS]={};
+
+ // check column widths
+ table_header.set_selection(vehicle_row_t::sort_mode);
+ table_header.set_width(D_H_SPACE); // init width
+ for (uint c = 0; c < vehicle_row_t::MAX_COLS; c++) {
+ // get header widths
+ max_widths[c] = table_header.get_min_width(c);
+ }
+ for (int r = 0; r < scrolly.get_count(); r++) {
+ vehicle_row_t* row = (vehicle_row_t*)scrolly.get_element(r);
+ for (uint c=0; cget_min_width(c));
+ }
+ }
+
+ // set column widths
+ for (uint c = 0; c < vehicle_row_t::MAX_COLS; c++) {
+ table_header.set_col(c, max_widths[c]);
+ }
+ table_header.set_width(table_header.get_size().w+D_SCROLLBAR_WIDTH);
+
+ for (int r = 0; r < scrolly.get_count(); r++) {
+ vehicle_row_t* row = (vehicle_row_t*)scrolly.get_element(r);
+ row->set_size(scr_size(0, row->get_size().h));
+ for (uint c = 0; c < vehicle_row_t::MAX_COLS; c++) {
+ row->set_col(c, max_widths[c]);
+ }
+ }
+
+ old_vhicles = depot->get_vehicle_list().get_count();
+ lb_vehicle_count.buf().clear();
+ if (old_vhicles == 0) {
+ lb_vehicle_count.buf().append( translator::translate( "Keine Einzelfahrzeuge im Depot" ) );
+ }
+ else {
+ lb_vehicle_count.buf().append(translator::translate("Stored"));
+ lb_vehicle_count.buf().append(": ");
+ if (old_vhicles == 1) {
+ lb_vehicle_count.buf().append(translator::translate("1 vehicle"));
+ }
+ else {
+ lb_vehicle_count.buf().printf(translator::translate("%d vehicles"), old_vhicles);
+ }
+ }
+ uint32 for_sale_cnt = depot->get_vehicles_for_sale().get_count();
+ if (for_sale_cnt) {
+ if (old_vhicles) {
+ lb_vehicle_count.buf().append(", ");
+ }
+ lb_vehicle_count.buf().append(translator::translate("Listed"));
+ lb_vehicle_count.buf().append(": ");
+ if (for_sale_cnt == 1) {
+ lb_vehicle_count.buf().append(translator::translate("1 vehicle"));
+ }
+ else {
+ lb_vehicle_count.buf().printf(translator::translate("%d vehicles"), for_sale_cnt);
+ }
+ }
+ lb_vehicle_count.update();
+ resize(scr_size(0, 0));
+
+ bt_mode_scrap.enable(old_vhicles);
+ bt_mode_sell.enable(old_vhicles);
+ bt_mode_cancel_listing.enable(for_sale_cnt);
+ bt_mode_buy.enable( old_listed_vehicles - for_sale_cnt );
+
+ scroll_sortable.set_visible(scrolly.get_count());
+
+ calc_total_cost();
+}
+
+void vehicle_manager_t::init_table()
+{
+ if (depot == NULL) {
+ destroy_win(this);
+ }
+
+ reset_depot_name();
+
+ scrolly.add_listener(this);
+ scrolly.set_show_scroll_x(false);
+ scrolly.set_multiple_selection(2);
+ scrolly.set_checkered(true);
+ scrolly.set_scroll_amount_y(LINESPACE + D_H_SPACE +2); // default cell height
+
+ scroll_sortable.set_rigid(true);
+ scroll_sortable.set_maximize(true);
+
+ table_header.add_listener(this);
+ for (uint8 col=0; col(vl_header_text[col]);
+ }
+
+ cont_sortable.set_margin(NO_SPACING, NO_SPACING);
+ cont_sortable.set_spacing(NO_SPACING);
+ cont_sortable.set_table_layout(1,2);
+ cont_sortable.set_alignment(ALIGN_TOP); // Without this, the layout will be broken if the height is small.
+ cont_sortable.add_component(&table_header);
+ cont_sortable.add_component(&scrolly);
+
+ add_table(3,1);
+ {
+ new_component(depot->get_waytype());
+ name_input.set_text(name, sizeof(name));
+ name_input.add_listener(this);
+ add_component(&name_input);
+
+ gui_label_buf_t *lb = new_component();
+ if (depot->get_traction_types() == 0)
+ {
+ lb->buf().printf("%s", translator::translate("Unpowered vehicles only"));
+ }
+ else if (depot->get_traction_types() == 65535)
+ {
+ lb->buf().printf("%s", translator::translate("All traction types"));
+ }
+ else
+ {
+ uint16 shifter;
+ bool first = true;
+ for (uint16 i = 0; i < (vehicle_desc_t::MAX_TRACTION_TYPE); i++)
+ {
+ shifter = 1 << i;
+ if ((shifter & depot->get_traction_types()))
+ {
+ if (first)
+ {
+ first = false;
+ lb->buf().clear();
+ }
+ else
+ {
+ lb->buf().printf(", ");
+ }
+ lb->buf().printf("%s", translator::translate(vehicle_builder_t::engine_type_names[(vehicle_desc_t::engine_t)(i + 1)]));
+ }
+ }
+ }
+ }
+ end_table();
+
+ add_table(2, 1);
+ {
+ add_component(&lb_vehicle_count);
+ new_component();
+ }
+ end_table();
+
+ add_table(8,1)->set_spacing(NO_SPACING);
+ {
+ bt_mode_scrap.init(button_t::roundbox_left_state, translator::translate("Scrap"));
+ bt_mode_scrap.pressed=true;
+ bt_mode_scrap.add_listener(this);
+ add_component(&bt_mode_scrap);
+ bt_mode_sell.init(button_t::roundbox_middle_state, translator::translate("Sell"));
+ bt_mode_sell.add_listener(this);
+ add_component(&bt_mode_sell);
+ bt_mode_cancel_listing.init(button_t::roundbox_middle_state, translator::translate("Listed"));
+ bt_mode_cancel_listing.add_listener(this);
+ add_component(&bt_mode_cancel_listing);
+ bt_mode_buy.init(button_t::roundbox_right_state, translator::translate("Buy"));
+ bt_mode_buy.add_listener(this);
+ add_component(&bt_mode_buy);
+
+ new_component(LINESPACE);
+ bt_sel_all.init(button_t::roundbox, translator::translate("clf_btn_alle"));
+ bt_sel_all.add_listener(this);
+ add_component(&bt_sel_all);
+ bt_reset.init(button_t::roundbox, translator::translate("clf_btn_keine"));
+ bt_reset.add_listener(this);
+ add_component(&bt_reset);
+ new_component();
+ }
+ end_table();
+
+ add_component(&scroll_sortable);
+ update_list();
+ add_component(&lb_total_cost);
+ bt_execute.init(button_t::roundbox, "execute_scrap");
+ bt_execute.add_listener(this);
+ add_component(&bt_execute);
+
+ set_resizemode(diagonal_resize);
+ reset_min_windowsize();
+ resize(scr_size(0,0));
+}
+
+void vehicle_manager_t::calc_total_cost()
+{
+ last_selected = scrolly.get_selection(); // current focused one
+ old_selections = scrolly.get_selections().get_count(); // selected vehicle count
+ if ( bt_mode_cancel_listing.pressed ){
+ lb_total_cost.buf().append(translator::translate("Cancel the listing request for the selected vehicles"));
+ }
+ else {
+ sint64 total=0;
+ for (auto i : scrolly.get_selections()) {
+ vehicle_row_t* vr = (vehicle_row_t*)scrolly.get_element(i);
+ vehicle_t* veh = vr->get_vehicle();
+ total += (sint64)veh->calc_sale_value();
+ }
+
+ char number[64];
+ money_to_string(number, total / 100.0);
+ if (bt_mode_buy.pressed) {
+ lb_total_cost.buf().printf("%s: ", translator::translate("Price"));
+ }
+ else {
+ lb_total_cost.buf().printf("%s ", translator::translate("Restwert:"));
+ }
+ lb_total_cost.buf().append(number);
+ }
+ lb_total_cost.update();
+ lb_total_cost.set_size(lb_total_cost.get_min_size()); // When the width is increased, the text may be cut off.
+
+ bt_execute.enable(old_selections);
+}
+
+void vehicle_manager_t::scrap_vehicles()
+{
+ // standard's code only allows players to sell the newest vehicle,
+ // but this UI requires players to sell the specific vehicle selected precisely.
+ uint16 stored_idx= (uint16)depot->get_vehicle_list().get_count();
+ // The process is done backwards so that the vehicle index does not change.
+ for (uint16 stored_idx = depot->get_vehicle_list().get_count(); stored_idx>0; stored_idx--) {
+ vehicle_t *veh = depot->get_vehicle_list().at(stored_idx-1);
+ for (auto i : scrolly.get_selections()) {
+ vehicle_row_t* vi = (vehicle_row_t*)scrolly.get_element(i);
+ if (vi->get_vehicle() && vi->get_vehicle() == veh) {
+ depot->call_depot_tool('S', convoihandle_t(), vi->get_text(), stored_idx-1);
+ break; // check next
+ }
+ }
+ }
+}
+
+void vehicle_manager_t::offer_vehicles_for_sale()
+{
+ uint16 stored_idx = (uint16)depot->get_vehicle_list().get_count();
+ // The process is done backwards so that the vehicle index does not change.
+ for (uint16 stored_idx = depot->get_vehicle_list().get_count(); stored_idx>0; stored_idx--) {
+ vehicle_t *veh = depot->get_vehicle_list().at(stored_idx-1);
+ for (auto i : scrolly.get_selections()) {
+ vehicle_row_t* vi = (vehicle_row_t*)scrolly.get_element(i);
+ if (vi->get_vehicle() && vi->get_vehicle() == veh) {
+ depot->call_depot_tool('f', convoihandle_t(), vi->get_text(), stored_idx-1);
+ break; // check next
+ }
+ }
+ }
+}
+
+void vehicle_manager_t::cancel_vehicles_for_sale()
+{
+ // The process is done backwards so that the vehicle index does not change.
+ for (uint16 listed_idx = depot->get_vehicles_for_sale().get_count(); listed_idx >0; listed_idx--) {
+ vehicle_t *veh = depot->get_vehicles_for_sale().at(listed_idx-1);
+ for (auto i : scrolly.get_selections()) {
+ vehicle_row_t* vi = (vehicle_row_t*)scrolly.get_element(i);
+ if (vi->get_vehicle() && vi->get_vehicle() == veh) {
+ depot->call_depot_tool('F', convoihandle_t(), vi->get_text(), listed_idx -1);
+ break; // check next
+ }
+ }
+ }
+}
+
+void vehicle_manager_t::takeover_vehicles()
+{
+ for (uint32 i=scrolly.get_selections().get_count(); i>0; i--) {
+ vehicle_row_t* vinfo = (vehicle_row_t*)scrolly.get_element(scrolly.get_selections().get_element(i-1));
+ vehicle_t *veh = vinfo->get_vehicle();
+
+ if (grund_t* gr = welt->lookup(veh->get_pos())) {
+ if (depot_t* seller_dep = gr->get_depot()) {
+ uint32 j=0;
+ for (auto vj : seller_dep->get_vehicles_for_sale()) {
+ if (veh==vj) {
+ tool_t* tmp_tool = create_tool(TOOL_TRANSFER_VEHICLE | SIMPLE_TOOL);
+ cbuffer_t buf;
+ buf.append(seller_dep->get_pos().get_str());
+ buf.append(",");
+ buf.append(depot->get_pos().get_str());
+ buf.printf(",%u",j);
+ tmp_tool->set_default_param(buf);
+ welt->set_tool(tmp_tool, depot->get_owner());
+ // since init always returns false, it is safe to delete immediately
+ delete tmp_tool;
+ break;
+ }
+ j++;
+ }
+ }
+ else {
+ dbg->warning("vehicle_manager_t::takeover_vehicles", "Depot not found at %s", veh->get_pos().get_fullstr());
+ }
+ }
+ else {
+ dbg->warning("vehicle_manager_t::takeover_vehicles", "Invalid coord - %s", veh->get_pos().get_fullstr());
+ }
+ }
+}
+
+
+void vehicle_manager_t::rename_depot()
+{
+ const char* t = name_input.get_text();
+ // only change if old name and current name are the same
+ // otherwise some unintended undo if renaming would occur
+ if (t && t[0] && strcmp(t, depot->get_name()) && strcmp(old_name, depot->get_name()) == 0) {
+ // text changed => call tool
+ cbuffer_t buf;
+ buf.printf("d%s,%s", depot->get_pos().get_str(), t);
+ tool_t* tool = create_tool(TOOL_RENAME | SIMPLE_TOOL);
+ tool->set_default_param(buf);
+ welt->set_tool(tool, depot->get_owner());
+ // since init always returns false, it is safe to delete immediately
+ delete tool;
+ // do not trigger this command again
+ tstrncpy(old_name, depot->get_name(), sizeof(old_name));
+
+ reset_depot_name();
+ }
+}
+
+
+void vehicle_manager_t::draw(scr_coord pos, scr_size size)
+{
+ if (depot == NULL || depot->get_owner_nr() != world()->get_active_player_nr()) {
+ destroy_win(this);
+ }
+
+ // update
+ if( depot->get_vehicle_list().get_count()!=old_vhicles
+ || old_month != world()->get_current_month()
+ || old_listed_vehicles != world()->get_listed_vehicle_number(depot->get_waytype()) ) {
+ update_list();
+ }
+
+ if( last_selected != scrolly.get_selection() || old_selections != scrolly.get_selections().get_count() ) {
+ calc_total_cost();
+ }
+
+ gui_frame_t::draw(pos, size);
+}
+
+void vehicle_manager_t::init_mode_buttons()
+{
+ bt_mode_scrap.pressed = dep_action == da_scrap;
+ bt_mode_sell.pressed = dep_action == da_listing;
+ bt_mode_buy.pressed = dep_action == da_buy;
+ bt_mode_cancel_listing.pressed = dep_action == da_cancel_listing;
+ switch (dep_action)
+ {
+ default:
+ bt_execute.set_text("execute");
+ break;
+ case da_scrap:
+ bt_execute.set_text("execute_scrap");
+ break;
+ case da_listing:
+ bt_execute.set_text("execute_listing");
+ break;
+ case da_cancel_listing:
+ bt_execute.set_text("cancel_the_listing");
+ cancel_vehicles_for_sale();
+ break;
+ case da_buy:
+ bt_execute.set_text("execute_purchase");
+ takeover_vehicles();
+ break;
+ }
+}
+
+
+bool vehicle_manager_t::action_triggered(gui_action_creator_t *comp, value_t v)
+{
+ if (depot->get_owner_nr() != world()->get_active_player_nr()) return false;
+
+ if( comp==&bt_sel_all || comp == &bt_reset) {
+ const bool select = comp==&bt_sel_all;
+ for (int i=0; iselected = select;
+ }
+ scrolly.set_selection(-1);
+ }
+ bool need_update=false;
+ if( comp == &bt_mode_scrap ) {
+ need_update = (dep_action!=da_scrap && dep_action!=da_listing);
+ dep_action=da_scrap;
+ init_mode_buttons();
+ }
+ if( comp == &bt_mode_sell ) {
+ need_update = (dep_action!=da_scrap && dep_action!=da_listing);
+ dep_action=da_listing;
+ init_mode_buttons();
+ }
+ if( comp == &bt_mode_cancel_listing ) {
+ need_update= dep_action != da_cancel_listing;
+ dep_action=da_cancel_listing;
+ init_mode_buttons();
+ }
+ if( comp==&bt_mode_buy) {
+ need_update = dep_action != da_buy;
+ dep_action= da_buy;
+ init_mode_buttons();
+ }
+ if (need_update) {
+ update_list();
+ return true;
+ }
+ if (comp == &table_header) {
+ vehicle_row_t::sort_mode = v.i;
+ table_header.set_selection(vehicle_row_t::sort_mode);
+ vehicle_row_t::sortreverse = table_header.is_reversed();
+ scrolly.sort(0);
+ }
+ if (comp == &bt_execute) {
+ switch (dep_action)
+ {
+ default:
+ break;
+ case da_scrap:
+ scrap_vehicles();
+ break;
+ case da_listing:
+ offer_vehicles_for_sale();
+ break;
+ case da_cancel_listing:
+ cancel_vehicles_for_sale();
+ break;
+ case da_buy:
+ takeover_vehicles();
+ break;
+ }
+ }
+ else if (comp == &name_input) {
+ // send rename command if necessary
+ rename_depot();
+ }
+
+ return false;
+}
+
+
+// returns position of depot on the map
+koord3d vehicle_manager_t::get_weltpos(bool)
+{
+ return depot->get_pos();
+}
+
+
+bool vehicle_manager_t::is_weltpos()
+{
+ return (world()->get_viewport()->is_on_center(get_weltpos(false)));
+}
diff --git a/gui/vehicle_manager.h b/gui/vehicle_manager.h
new file mode 100644
index 00000000000..b878e0923eb
--- /dev/null
+++ b/gui/vehicle_manager.h
@@ -0,0 +1,108 @@
+/*
+ * This file is part of the Simutrans-Extended project under the Artistic License.
+ * (see LICENSE.txt)
+ */
+
+#ifndef GUI_VEHICLE_MANAGER_H
+#define GUI_VEHICLE_MANAGER_H
+
+
+#include "simwin.h"
+#include "gui_frame.h"
+#include "../simdepot.h"
+#include "components/gui_button.h"
+#include "components/gui_scrolled_list.h"
+#include "components/gui_label.h"
+#include "components/gui_image.h"
+#include "components/gui_textinput.h"
+#include "components/gui_table.h"
+#include "components/sortable_table_vehicle.h"
+#include "components/sortable_table_header.h"
+
+class vehicle_desc_t;
+
+class vehicle_manager_t : public gui_frame_t, action_listener_t
+{
+ depot_t *depot;
+
+ // update triggars
+ uint32 old_vhicles; // stored vehicles
+ uint32 old_listed_vehicles; // waytype total in the world
+ uint32 old_selections; // selected vehicles
+ sint32 last_selected=-1; // last selected vehicle
+ uint32 old_month; // Update flag when the month changes
+
+public:
+
+ enum {
+ da_scrap,
+ da_listing,
+ da_cancel_listing,
+ da_buy
+ };
+ uint8 dep_action=da_scrap;
+
+private:
+ //static sort_mode_t sortby;
+ //static const char* sort_text[vehicle_row_t::MAX_COLS]; // ?
+
+ button_t
+ bt_mode_scrap,
+ bt_mode_sell,
+ bt_mode_cancel_listing,
+ bt_mode_buy,
+ bt_sel_all,
+ bt_reset,
+ bt_execute;
+ gui_label_buf_t
+ lb_vehicle_count,
+ lb_total_cost;
+
+ char name[256], old_name[256];
+ gui_textinput_t name_input;
+
+ gui_sort_table_header_t table_header;
+ gui_aligned_container_t cont_sortable;
+
+ gui_scrolled_list_t scrolly;
+ gui_scrollpane_t scroll_sortable;
+
+ /// refill the list of vehicle info elements
+ void update_list();
+
+ void init_table();
+ void init_mode_buttons();
+
+ // calculate total selected vehicles cost and update the label
+ void calc_total_cost();
+
+ // execute vechile trade command
+ void scrap_vehicles();
+ void offer_vehicles_for_sale();
+ void cancel_vehicles_for_sale();
+
+ // buy vehicles from other players
+ void takeover_vehicles();
+
+ /// Renames the depot to the name given in the text input field
+ void rename_depot();
+
+public:
+ vehicle_manager_t(depot_t* depot);
+
+ void reset_depot_name();
+
+ const char *get_help_filename() const OVERRIDE {return "vehicle_manager.txt"; }
+
+ bool action_triggered(gui_action_creator_t *comp, value_t v) OVERRIDE;
+
+ void draw(scr_coord pos, scr_size size) OVERRIDE;
+
+ koord3d get_weltpos(bool) OVERRIDE;
+ bool is_weltpos() OVERRIDE;
+
+ uint32 get_rdwr_id() OVERRIDE { return magic_vehicle_manager + depot->get_owner_nr(); }
+};
+
+
+#endif
diff --git a/gui/vehiclelist_frame.cc b/gui/vehiclelist_frame.cc
index a2aac4ce38f..08082a48122 100644
--- a/gui/vehiclelist_frame.cc
+++ b/gui/vehiclelist_frame.cc
@@ -12,6 +12,7 @@
#include "../simskin.h"
#include "../simworld.h"
+#include "../vehicle/vehicle.h"
#include "../display/simgraph.h"
@@ -26,39 +27,15 @@
#include "../unicode.h"
-int vehiclelist_stats_t::sort_mode = vehicle_builder_t::sb_intro_date;
-bool vehiclelist_stats_t::reverse = false;
-
-uint8 vehiclelist_frame_t::filter_flag=0;
-bool vehiclelist_frame_t::side_view_mode = true;
char vehiclelist_frame_t::name_filter[256] = "";
char vehiclelist_frame_t::status_counts_text[10][VL_MAX_STATUS_FILTER] = {};
-int vehiclelist_frame_t::cell_width[vehiclelist_frame_t::VL_MAX_SPECS] = {};
-#define MAX_IMG_WIDTH vehiclelist_frame_t::cell_width[vehiclelist_frame_t::VL_IMAGE]
-int vehiclelist_frame_t::stats_width = 0;
-
-static int col_to_sort_mode[vehiclelist_frame_t::VL_MAX_SPECS] = {
- vehicle_builder_t::sb_name,
- vehicle_builder_t::sb_role,
- vehicle_builder_t::sb_value,
- vehicle_builder_t::sb_enigine_type,
- vehicle_builder_t::sb_power,
- vehicle_builder_t::sb_tractive_force,
- vehicle_builder_t::sb_freight,
- vehicle_builder_t::sb_capacity,
- vehicle_builder_t::sb_speed,
- vehicle_builder_t::sb_weight,
- vehicle_builder_t::sb_axle_load,
- vehicle_builder_t::sb_intro_date,
- vehicle_builder_t::sb_retire_date
-};
-static const char *const vl_header_text[vehiclelist_frame_t::VL_MAX_SPECS] =
+static const char *const vl_header_text[vehicle_desc_row_t::MAX_COLS] =
{
"Name", "", "Wert", "engine_type",
- "Leistung", "TF_", "", "Capacity",
- "Max. speed", "curb_weight", "Axle load:", "Intro. date","Retire date"
+ "Leistung", "TF_", "Max. speed", "",
+ "Capacity", "curb_weight", "Axle load:", "Intro. date","Retire date"
};
static const char *const timeline_filter_button_text[vehiclelist_frame_t::VL_MAX_STATUS_FILTER] =
@@ -66,344 +43,30 @@ static const char *const timeline_filter_button_text[vehiclelist_frame_t::VL_MAX
"Show future", "Show available", "Show outdated", "Show obsolete", "upgrade_only"
};
-vehiclelist_stats_t::vehiclelist_stats_t(const vehicle_desc_t *v)
-{
- veh = v;
-
- // name for tooltip
- tooltip_buf.clear();
- tooltip_buf.append( translator::translate( veh->get_name(), world()->get_settings().get_name_language_id() ) );
-
- // calculate first column width
- if( vehiclelist_frame_t::side_view_mode ) {
- // width of image
- scr_coord_val x, y, w, h;
- const image_id image = veh->get_image_id( ribi_t::dir_southwest, veh->get_freight_type() );
- display_get_base_image_offset(image, &x, &y, &w, &h );
- if( w > MAX_IMG_WIDTH ) {
- MAX_IMG_WIDTH = min(w + D_H_SPACE, int(get_base_tile_raster_width()*0.67)); // 1 tile = length 16
- }
- height = h;
- }
- else {
- MAX_IMG_WIDTH = max(proportional_string_width(tooltip_buf), MAX_IMG_WIDTH);
- }
-
- height = max( height, LINEASCENT*2 + D_V_SPACE*3 );
-}
-
-
-void vehiclelist_stats_t::draw( scr_coord offset )
-{
- // show tooltip
- if (getroffen(get_mouse_pos() - offset)) {
- win_set_tooltip(get_mouse_pos() + TOOLTIP_MOUSE_OFFSET, tooltip_buf, this);
- }
-
- const uint32 month = world()->get_current_month();
- offset += pos;
- offset.x += D_H_SPACE;
- const int text_offset_y = (height-1-LINEASCENT)>>1;
-
- vehicle_detail_t *win = dynamic_cast(win_get_magic(magic_vehicle_detail));
- const bool selected = win ? (win->get_vehicle()==veh) : false;
-
- if (vehiclelist_frame_t::side_view_mode) {
- if( selected ) {
- display_fillbox_wh_clip_rgb(offset.x, offset.y, MAX_IMG_WIDTH - 1, height - 1, SYSCOL_TR_BACKGROUND_SELECTED, false);
- }
- // show side view image
- scr_coord_val x, y, w, h;
- const image_id image = veh->get_image_id( ribi_t::dir_southwest, veh->get_freight_type() );
- display_get_base_image_offset(image, &x, &y, &w, &h );
- display_base_img(image, offset.x - x, offset.y - y + D_GET_CENTER_ALIGN_OFFSET(h, height-1), world()->get_active_player_nr(), false, true);
- }
- else {
- // show name
- PIXVAL name_colval = veh->get_vehicle_status_color();
- if (veh->is_available_only_as_upgrade()) {
- if (name_colval == SYSCOL_OBSOLETE) {
- name_colval = color_idx_to_rgb(COL_DARK_PURPLE);
- }
- else {
- name_colval = SYSCOL_UPGRADEABLE;
- }
- }
- if (name_colval==COL_SAFETY) {
- name_colval = selected ? SYSCOL_TD_TEXT_SELECTED : SYSCOL_TEXT;
- }
- display_fillbox_wh_clip_rgb(offset.x, offset.y, MAX_IMG_WIDTH - 1, height - 1, selected ? SYSCOL_TR_BACKGROUND_SELECTED:SYSCOL_TH_BACKGROUND_LEFT, false);
- display_proportional_rgb(
- offset.x, offset.y + text_offset_y,
- translator::translate( veh->get_name(), world()->get_settings().get_name_language_id() ),
- ALIGN_LEFT|DT_CLIP,
- name_colval,
- false
- );
- }
-
- offset.x += MAX_IMG_WIDTH;
- for (uint8 col = 1; colget_vehicle_status_color();
- if (veh->is_available_only_as_upgrade()) {
- if (status_color == SYSCOL_OBSOLETE) {
- status_color = color_idx_to_rgb(COL_DARK_PURPLE);
- }
- else {
- status_color = SYSCOL_UPGRADEABLE;
- }
- }
-
- scr_coord_val xoff= offset.x + D_H_SPACE;
- display_veh_form_wh_clip_rgb(xoff, offset.y + D_GET_CENTER_ALIGN_OFFSET(VEHICLE_BAR_HEIGHT, height-1), VEHICLE_BAR_HEIGHT*2, VEHICLE_BAR_HEIGHT, status_color, true, false, veh->get_basic_constraint_prev(), veh->get_interactivity());
- xoff += VEHICLE_BAR_HEIGHT * 2;
- display_veh_form_wh_clip_rgb(xoff, offset.y + D_GET_CENTER_ALIGN_OFFSET(VEHICLE_BAR_HEIGHT, height-1), VEHICLE_BAR_HEIGHT*2, VEHICLE_BAR_HEIGHT, status_color, true, true, veh->get_basic_constraint_next(), veh->get_interactivity());
-
- const uint8 upgradable_state = veh->has_available_upgrade(month);
- if( vehiclelist_frame_t::filter_flag&vehiclelist_frame_t::VL_FILTER_UPGRADABLE && upgradable_state && skinverwaltung_t::upgradable ) {
- if (world()->get_settings().get_show_future_vehicle_info() || (!world()->get_settings().get_show_future_vehicle_info() && veh->is_future(month) != 2)) {
- xoff = xoff + VEHICLE_BAR_HEIGHT * 2 - D_FIXED_SYMBOL_WIDTH;
- display_color_img(skinverwaltung_t::upgradable->get_image_id(upgradable_state - 1), xoff, offset.y + height - D_FIXED_SYMBOL_WIDTH, 0, false, false);
- }
- }
- break;
- }
- case vehiclelist_frame_t::VL_COST:
- {
- char tmp[ 128 ];
- money_to_string( tmp, veh->get_value() / 100.0, false );
- buf.printf("%8s", tmp);
- display_proportional_rgb( offset.x+ vehiclelist_frame_t::cell_width[col]-D_H_SPACE, offset.y+text_offset_y, buf, ALIGN_RIGHT | DT_CLIP, text_color, false);
- break;
- }
- case vehiclelist_frame_t::VL_ENGINE_TYPE:
- {
- char str[ 256 ];
- const uint8 et = (uint8)veh->get_engine_type() + 1;
- if( et ) {
- sprintf( str, "%s", translator::translate( vehicle_builder_t::engine_type_names[et] ) );
- display_proportional_rgb( offset.x+D_H_SPACE, offset.y+text_offset_y, str, ALIGN_LEFT|DT_CLIP, text_color, false );
- }
- break;
- }
- case vehiclelist_frame_t::VL_POWER:
- if (veh->get_power() > 0) {
- buf.printf("%4d kW", veh->get_power());
- display_proportional_rgb(offset.x + vehiclelist_frame_t::cell_width[col] - D_H_SPACE, offset.y + text_offset_y, buf, ALIGN_RIGHT | DT_CLIP, text_color, false);
- }
- break;
-
- case vehiclelist_frame_t::VL_TRACTIVE_FORCE:
- if (veh->get_power() > 0) {
- buf.printf("%3d kN", veh->get_tractive_effort());
- display_proportional_rgb(offset.x + vehiclelist_frame_t::cell_width[col] - D_H_SPACE, offset.y + text_offset_y, buf, ALIGN_RIGHT | DT_CLIP, text_color, false);
- }
- break;
-
- case vehiclelist_frame_t::VL_FREIGHT_TYPE:
- if( veh->get_total_capacity() || veh->get_overcrowded_capacity() ){
- const uint8 number_of_classes = goods_manager_t::get_classes_catg_index( veh->get_freight_type()->get_catg_index() );
- // owned class indicator
- if( number_of_classes>1 ) {
- int yoff = D_GET_CENTER_ALIGN_OFFSET((D_FIXED_SYMBOL_WIDTH+veh->get_accommodations()*3), height-1);
- display_color_img(veh->get_freight_type()->get_catg_symbol(), offset.x + D_H_SPACE, offset.y + yoff, 0, false, false);
- yoff += D_FIXED_SYMBOL_WIDTH+1;
- for (uint8 a_class=0; a_classget_capacity(a_class) ) {
- int xoff = (vehiclelist_frame_t::cell_width[col]>>1)-(int)(a_class*3/2)-1;
- for( uint8 n=0; nheight) {
- break;
- }
- }
- }
- }
- else {
- display_color_img(veh->get_freight_type()->get_catg_symbol(),offset.x + D_H_SPACE, offset.y+ D_GET_CENTER_ALIGN_OFFSET(D_FIXED_SYMBOL_WIDTH, height-1),0, false, false);
- }
- }
- break;
-
- case vehiclelist_frame_t::VL_CAPACITY:
- {
- int yoff = text_offset_y;
- if (!veh->get_total_capacity() && !veh->get_overcrowded_capacity() ) {
- buf.append("-");
- text_color = SYSCOL_TEXT_WEAK;
- }
- else if(veh->get_total_capacity() && veh->get_overcrowded_capacity()) {
- // display two lines
- buf.printf("%4d", veh->get_total_capacity());
- display_proportional_rgb(offset.x + (vehiclelist_frame_t::cell_width[col]>>1), offset.y + D_V_SPACE, buf, ALIGN_CENTER_H | DT_CLIP, text_color, false);
- buf.clear();
- yoff = LINEASCENT+D_V_SPACE*2;
- buf.printf("(%d)", veh->get_overcrowded_capacity());
- }
- else {
- if (veh->get_total_capacity()) {
- buf.printf("%4d", veh->get_total_capacity());
- }
- if (veh->get_overcrowded_capacity()) {
- buf.printf("(%d)", veh->get_overcrowded_capacity());
- }
- }
- display_proportional_rgb(offset.x + (vehiclelist_frame_t::cell_width[col]>>1), offset.y + yoff, buf, ALIGN_CENTER_H | DT_CLIP, text_color, false);
- break;
- }
- case vehiclelist_frame_t::VL_SPEED:
- buf.printf("%3d km/h", veh->get_topspeed());
- display_proportional_rgb(offset.x + vehiclelist_frame_t::cell_width[col] - D_H_SPACE, offset.y + text_offset_y, buf, ALIGN_RIGHT | DT_CLIP, text_color, false);
- break;
- case vehiclelist_frame_t::VL_WEIGHT:
- if (veh->get_weight()) {
- buf.printf("%4.1ft", veh->get_weight() / 1000.0);
- }
- else {
- buf.append("-");
- text_color = SYSCOL_TEXT_WEAK;
- }
- display_proportional_rgb(offset.x + vehiclelist_frame_t::cell_width[col] - D_H_SPACE, offset.y + text_offset_y, buf, ALIGN_RIGHT | DT_CLIP, text_color, false);
- break;
- case vehiclelist_frame_t::VL_AXLE_LOAD:
- if (veh->get_waytype() != water_wt) {
- buf.printf("%2it", veh->get_axle_load());
- display_proportional_rgb(offset.x + vehiclelist_frame_t::cell_width[col] - D_H_SPACE, offset.y + text_offset_y, buf, ALIGN_RIGHT | DT_CLIP, text_color, false);
- }
- break;
- case vehiclelist_frame_t::VL_INTRO_DATE:
- buf.append( translator::get_short_date(veh->get_intro_year_month()/12, veh->get_intro_year_month()%12) );
- display_proportional_rgb(offset.x + D_H_SPACE, offset.y + text_offset_y, buf, ALIGN_LEFT | DT_CLIP, text_color, false);
- break;
- case vehiclelist_frame_t::VL_RETIRE_DATE:
- if (veh->get_retire_year_month() != DEFAULT_RETIRE_DATE * 12 &&
- (((!world()->get_settings().get_show_future_vehicle_info() && veh->will_end_prodection_soon(world()->get_timeline_year_month()))
- || world()->get_settings().get_show_future_vehicle_info()
- || veh->is_retired(world()->get_timeline_year_month()))))
- {
- buf.append( translator::get_short_date(veh->get_retire_year_month()/12, veh->get_retire_year_month()%12) );
- }
- display_proportional_rgb(offset.x + D_H_SPACE, offset.y + text_offset_y, buf, ALIGN_LEFT | DT_CLIP, text_color, false);
- break;
-
- default:
- break;
- }
- offset.x += vehiclelist_frame_t::cell_width[col];
- }
-}
-
-
-bool vehiclelist_stats_t::infowin_event(const event_t *ev)
-{
- if( IS_LEFTRELEASE(ev) && getroffen( ev->mouse_pos+pos ) ) {
- vehicle_detail_t *win = dynamic_cast(win_get_magic(magic_vehicle_detail));
- if (!win) {
- create_win(new vehicle_detail_t(veh), w_info, magic_vehicle_detail);
- }
- else {
- win->set_vehicle(veh);
- top_win(win, false);
- }
- }
- return false;
-}
-
-
-const char *vehiclelist_stats_t::get_text() const
-{
- return translator::translate( veh->get_name() );
-}
-
-scr_size vehiclelist_stats_t::get_size() const
-{
- return scr_size(D_MARGINS_X + vehiclelist_frame_t::stats_width, height);
-}
-
-bool vehiclelist_stats_t::compare(const gui_component_t *aa, const gui_component_t *bb)
-{
- if (reverse) {
- return vehicle_builder_t::compare_vehicles(dynamic_cast(bb)->veh, dynamic_cast(aa)->veh, (vehicle_builder_t::sort_mode_t)vehiclelist_stats_t::sort_mode);
- }
- return vehicle_builder_t::compare_vehicles( dynamic_cast(aa)->veh, dynamic_cast(bb)->veh, (vehicle_builder_t::sort_mode_t)vehiclelist_stats_t::sort_mode );
-}
-
vehiclelist_frame_t::vehiclelist_frame_t() :
gui_frame_t( translator::translate("vh_title") ),
- scrolly(gui_scrolled_list_t::windowskin, vehiclelist_stats_t::compare),
- scrollx_tab(&cont_list_table,true,false)
+ scrolly(gui_scrolled_list_t::windowskin, vehicle_desc_row_t::compare),
+ scrollx_tab(&cont_sortable,true,true)
{
last_name_filter[0] = 0;
- scrolly.set_cmp( vehiclelist_stats_t::compare );
// Scrolling in x direction should not be possible due to fixed header
scrolly.set_show_scroll_x(false);
+ scrolly.set_checkered(true);
+ scrolly.set_scroll_amount_y(LINESPACE + D_H_SPACE + 2); // default cell height
// init table sort buttons
- for (uint8 i=0; iset_spacing(scr_size(0,0));
- {
- cont_list_table.new_component(D_H_SPACE<<1);
- for( uint8 i=0; i(vl_header_text[col]);
}
- cont_list_table.end_table();
- cont_list_table.add_component(&scrolly);
+
+ cont_sortable.set_margin(NO_SPACING, NO_SPACING);
+ cont_sortable.set_spacing(NO_SPACING);
+ cont_sortable.set_table_layout(1,2);
+ cont_sortable.set_alignment(ALIGN_TOP); // Without this, the layout will be broken if the height is small.
+ cont_sortable.add_component(&table_header);
+ cont_sortable.add_component(&scrolly);
set_table_layout(1,0);
@@ -428,7 +91,7 @@ vehiclelist_frame_t::vehiclelist_frame_t() :
engine_filter.new_component(translator::translate(vehicle_builder_t::engine_type_names[(vehicle_desc_t::engine_t)i]), SYSCOL_TEXT);
}
engine_filter.new_component(translator::translate("Trailers"), SYSCOL_TEXT);
- filter_flag = 0;
+ vehicle_desc_row_t::filter_flag = 0;
engine_filter.set_selection( 0 );
engine_filter.add_listener( this );
add_component( &engine_filter );
@@ -500,8 +163,8 @@ vehiclelist_frame_t::vehiclelist_frame_t() :
bt_show_name.add_listener(this);
bt_show_side_view.init(button_t::roundbox_right_state, "show_side_view");
bt_show_side_view.add_listener(this);
- bt_show_name.pressed = !side_view_mode;
- bt_show_side_view.pressed = side_view_mode;
+ bt_show_name.pressed = !vehicle_desc_row_t::side_view_mode;
+ bt_show_side_view.pressed = vehicle_desc_row_t::side_view_mode;
add_component( &bt_show_name );
add_component( &bt_show_side_view);
}
@@ -515,7 +178,7 @@ vehiclelist_frame_t::vehiclelist_frame_t() :
fill_list();
set_resizemode(diagonal_resize);
- scrolly.set_maximize(true);
+ scrollx_tab.set_maximize(false);
}
@@ -549,15 +212,21 @@ bool vehiclelist_frame_t::action_triggered( gui_action_creator_t *comp,value_t v
else if( comp == &bt_show_name ) {
bt_show_name.pressed = true;
bt_show_side_view.pressed = false;
- side_view_mode = false;
+ vehicle_desc_row_t::side_view_mode = false;
fill_list();
}
else if( comp == &bt_show_side_view) {
bt_show_name.pressed = false;
bt_show_side_view.pressed = true;
- side_view_mode = true;
+ vehicle_desc_row_t::side_view_mode = true;
fill_list();
}
+ else if (comp == &table_header) {
+ vehicle_desc_row_t::sort_mode = v.i;
+ table_header.set_selection(vehicle_desc_row_t::sort_mode);
+ vehicle_desc_row_t::sortreverse = table_header.is_reversed();
+ scrolly.sort(0);
+ }
else {
for( uint8 i=0; iget_current_month();
const goods_desc_t *ware = idx_to_ware[ max( 0, ware_filter.get_selection() ) ];
const bool show_all_upgrade_only_vehicle = bt_timeline_filters[VL_FILTER_UPGRADE_ONLY].pressed
@@ -689,7 +345,8 @@ void vehiclelist_frame_t::fill_list()
continue;
}
}
- scrolly.new_component( veh );
+ scrolly.new_component(veh);
+ //scrolly.new_component( veh, side_view_mode );
if( veh->is_available_only_as_upgrade() ){
status_counts[VL_FILTER_UPGRADE_ONLY]++;
}
@@ -774,7 +431,8 @@ void vehiclelist_frame_t::fill_list()
continue;
}
}
- scrolly.new_component( veh );
+ //scrolly.new_component( veh, side_view_mode );
+ scrolly.new_component(veh);
if( veh->is_available_only_as_upgrade() ){
status_counts[VL_FILTER_UPGRADE_ONLY]++;
}
@@ -795,12 +453,8 @@ void vehiclelist_frame_t::fill_list()
count++;
}
}
- if( vehiclelist_stats_t::sort_mode != 0 ) {
- scrolly.sort(0);
- }
- else {
- scrolly.set_size( scrolly.get_size() );
- }
+ scrolly.sort(0);
+ scrolly.set_size( scrolly.get_size() );
switch (count) {
case 0:
lb_count.buf().printf(translator::translate("Vehicle not found"), count);
@@ -817,6 +471,37 @@ void vehiclelist_frame_t::fill_list()
}
lb_count.update();
+ // recalc stats table width
+ scr_coord_val max_widths[vehicle_desc_row_t::MAX_COLS] = {};
+
+ // check column widths
+ table_header.set_selection(vehicle_desc_row_t::sort_mode);
+ table_header.set_width(D_H_SPACE); // init width
+ for (uint c = 0; c < vehicle_desc_row_t::MAX_COLS; c++) {
+ // get header widths
+ max_widths[c] = table_header.get_min_width(c);
+ }
+ for (int r = 0; r < scrolly.get_count(); r++) {
+ vehicle_desc_row_t* row = (vehicle_desc_row_t*)scrolly.get_element(r);
+ for (uint c = 0; c < vehicle_desc_row_t::MAX_COLS; c++) {
+ max_widths[c] = max(max_widths[c], row->get_min_width(c));
+ }
+ }
+
+ // set column widths
+ for (uint c = 0; c < vehicle_desc_row_t::MAX_COLS; c++) {
+ table_header.set_col(c, max_widths[c]);
+ }
+ table_header.set_width(table_header.get_size().w + D_SCROLLBAR_WIDTH);
+
+ for (int r = 0; r < scrolly.get_count(); r++) {
+ vehicle_desc_row_t* row = (vehicle_desc_row_t*)scrolly.get_element(r);
+ row->set_size(scr_size(0, row->get_size().h));
+ for (uint c = 0; c < vehicle_desc_row_t::MAX_COLS; c++) {
+ row->set_col(c, max_widths[c]);
+ }
+ }
+
for( uint8 i=0; irdwr_bool(vehiclelist_stats_t::reverse);
+ file->rdwr_bool(vehicle_desc_row_t::sortreverse);
file->rdwr_bool(bt_timeline_filters[VL_SHOW_OUT_OBSOLETE].pressed);
file->rdwr_bool(bt_timeline_filters[VL_SHOW_FUTURE].pressed);
file->rdwr_bool(bt_timeline_filters[VL_SHOW_OUT_OF_PROD].pressed);
diff --git a/gui/vehiclelist_frame.h b/gui/vehiclelist_frame.h
index b0af6717583..c1bd7c166fe 100644
--- a/gui/vehiclelist_frame.h
+++ b/gui/vehiclelist_frame.h
@@ -15,7 +15,8 @@
#include "components/gui_label.h"
#include "components/gui_image.h"
#include "components/gui_waytype_tab_panel.h"
-#include "components/gui_table.h"
+#include "components/sortable_table_vehicle.h"
+#include "components/sortable_table_header.h"
class vehicle_desc_t;
class goods_desc_t;
@@ -24,25 +25,6 @@ class goods_desc_t;
class vehiclelist_frame_t : public gui_frame_t, private action_listener_t
{
public:
- enum veh_spec_col_t {
- VL_IMAGE,
- VL_STATUSBAR,
- VL_COST,
- VL_ENGINE_TYPE,
- VL_POWER,
- VL_TRACTIVE_FORCE,
- VL_FREIGHT_TYPE,
- VL_CAPACITY,
- VL_SPEED,
- VL_WEIGHT,
- VL_AXLE_LOAD,
- VL_INTRO_DATE,
- VL_RETIRE_DATE,
- VL_MAX_SPECS
- };
- static int cell_width[vehiclelist_frame_t::VL_MAX_SPECS];
- static int stats_width;
-
// vehicle status(mainly timeline) filter index
enum status_filter_t {
VL_SHOW_FUTURE =0, // gray
@@ -53,22 +35,11 @@ class vehiclelist_frame_t : public gui_frame_t, private action_listener_t
VL_MAX_STATUS_FILTER,
};
- // 1=fuel filer on, 2=freight type fiter on
- enum {
- VL_NO_FILTER = 0,
- VL_FILTER_FUEL = 1<<0,
- VL_FILTER_FREIGHT = 1<<1,
- VL_FILTER_UPGRADABLE = 1<<2
- };
- static uint8 filter_flag;
-
- // false=show name, true=show side view
- static bool side_view_mode;
-
private:
button_t bt_timeline_filters[VL_MAX_STATUS_FILTER];
button_t bt_upgradable;
- gui_aligned_container_t cont_list_table;
+ gui_sort_table_header_t table_header;
+ gui_aligned_container_t cont_sortable;
gui_scrolled_list_t scrolly;
gui_scrollpane_t scrollx_tab;
gui_waytype_tab_panel_t tabs;
@@ -84,7 +55,6 @@ class vehiclelist_frame_t : public gui_frame_t, private action_listener_t
static char status_counts_text[10][VL_MAX_STATUS_FILTER];
button_t bt_show_name, bt_show_side_view;
- table_sort_button_t bt_table_sort[VL_MAX_SPECS];
static char name_filter[256];
char last_name_filter[256];
@@ -104,31 +74,4 @@ class vehiclelist_frame_t : public gui_frame_t, private action_listener_t
uint32 get_rdwr_id() OVERRIDE { return magic_vehiclelist; }
};
-
-class vehiclelist_stats_t : public gui_scrolled_list_t::scrollitem_t
-{
-private:
- const vehicle_desc_t *veh;
- cbuffer_t tooltip_buf;
- cbuffer_t buf;
- int height;
-
-public:
- static int sort_mode;
- static bool reverse;
-
- vehiclelist_stats_t(const vehicle_desc_t *);
-
- char const* get_text() const OVERRIDE;
- scr_size get_size() const OVERRIDE;
- scr_size get_min_size() const OVERRIDE { return get_size(); };
- scr_size get_max_size() const OVERRIDE { return get_min_size(); }
-
- static bool compare(const gui_component_t *a, const gui_component_t *b );
-
- bool infowin_event(event_t const *ev) OVERRIDE;
-
- void draw( scr_coord offset ) OVERRIDE;
-};
-
#endif
diff --git a/simcolor.h b/simcolor.h
index 3a4545c1af1..e8f858ee9a6 100644
--- a/simcolor.h
+++ b/simcolor.h
@@ -175,6 +175,8 @@ typedef unsigned int FLAGGED_PIXVAL;
#define SYSCOL_CHART_LINES_EVEN gui_theme_t::gui_color_chart_lines_even
#define SYSCOL_LIST_TEXT_SELECTED_FOCUS gui_theme_t::gui_color_list_text_selected_focus
#define SYSCOL_LIST_TEXT_SELECTED_NOFOCUS gui_theme_t::gui_color_list_text_selected_nofocus
+#define SYSCOL_LIST_BACKGROUND_EVEN gui_theme_t::gui_color_list_background_even
+#define SYSCOL_LIST_BACKGROUND_ODD gui_theme_t::gui_color_list_background_odd
#define SYSCOL_LIST_BACKGROUND_SELECTED_F gui_theme_t::gui_color_list_background_selected_f
#define SYSCOL_LIST_BACKGROUND_SELECTED_NF gui_theme_t::gui_color_list_background_selected_nf
#define SYSCOL_BUTTON_TEXT gui_theme_t::gui_color_button_text
diff --git a/simdepot.cc b/simdepot.cc
index 0257af0016b..fff10d96b5f 100644
--- a/simdepot.cc
+++ b/simdepot.cc
@@ -22,6 +22,7 @@
#include "gui/depot_frame.h"
#include "gui/messagebox.h"
+#include "gui/depotlist_frame.h"
#include "dataobj/schedule.h"
#include "dataobj/loadsave.h"
@@ -201,7 +202,7 @@ void depot_t::convoi_arrived(convoihandle_t acnv, bool fpl_adjust)
vehicle_t *v = acnv->get_vehicle(i);
// Hajo: reset vehicle data
v->discard_cargo();
- v->set_pos( koord3d::invalid );
+ v->set_pos( get_pos() );
v->set_leading( i==0 );
v->set_last( i+1==acnv->get_vehicle_count() );
}
@@ -332,6 +333,43 @@ void depot_t::sell_vehicle(vehicle_t* veh)
delete veh;
}
+void depot_t::set_vehicle_for_sale(vehicle_t* veh)
+{
+ vehicles.remove(veh);
+ vehicles_for_sale.insert(veh);
+ veh->set_pos(get_pos()); // to identify this depot;
+}
+
+void depot_t::cancel_vehicle_for_sale(vehicle_t* veh)
+{
+ vehicles_for_sale.remove(veh);
+ vehicles.append(veh);
+}
+
+void depot_t::takeover_vehicle(vehicle_t* veh)
+{
+ if (grund_t* gr = welt->lookup(veh->get_pos())) {
+ if (depot_t* seller_dep = gr->get_depot()) {
+ veh->set_owner(get_owner());
+ veh->set_pos(get_pos());
+ vehicles.append(veh);
+ player_t *seller= seller_dep->get_owner();
+ const sint64 cost = (sint64)veh->calc_sale_value();
+ get_owner()->book_vehicle_number(1, get_waytype());
+ seller->book_vehicle_number(-1, get_waytype());
+ get_owner()->book_new_vehicle(-cost, get_pos().get_2d(), get_waytype());
+ seller->book_new_vehicle(cost, get_pos().get_2d(), get_waytype());
+
+ seller_dep->remove_vehicle_from_listed(veh);
+ }
+ }
+}
+
+void depot_t::remove_vehicle_from_listed(vehicle_t* veh)
+{
+ vehicles_for_sale.remove(veh);
+}
+
// returns the indest of the old/newest vehicle in a list
//@author: isidoro
@@ -707,12 +745,22 @@ void depot_t::rdwr(loadsave_t *file)
if (file->is_version_less(81, 33)) {
// wagons are stored extra, just add them to vehicles
assert(file->is_loading());
- rdwr_vehicle(vehicles, file);
+ rdwr_vehicle(vehicles, file, true);
+ }
+ if (file->is_version_ex_atleast(14, 67)){
+ DBG_MESSAGE("depot_t::rdwr_vehicles_for_sale", "loading %d vehicles", vehicles_for_sale.get_count());
+ rdwr_vehicle(vehicles_for_sale, file, true);
+ if (file->is_loading()) {
+ welt->add_listed_vehicle_count(vehicles_for_sale.get_count(), get_wegtyp());
+ }
+ }
+ else {
+ vehicles_for_sale.clear();
}
}
-void depot_t::rdwr_vehicle(slist_tpl &list, loadsave_t *file)
+void depot_t::rdwr_vehicle(slist_tpl &list, loadsave_t *file, bool skip_depot_name)
{
// read/write vehicles in the depot, which are not part of a convoi.
@@ -741,20 +789,20 @@ void depot_t::rdwr_vehicle(slist_tpl &list, loadsave_t *file)
const bool last = false;
switch (typ) {
- case old_road_vehicle:
- case road_vehicle: v = new road_vehicle_t(file, first, last); break;
- case old_waggon:
- case rail_vehicle: v = new rail_vehicle_t(file, first, last); break;
- case old_schiff:
- case water_vehicle: v = new water_vehicle_t(file, first, last); break;
- case old_aircraft:
- case air_vehicle: v = new air_vehicle_t(file, first, last); break;
- case old_monorail_vehicle:
- case monorail_vehicle: v = new monorail_rail_vehicle_t(file, first, last); break;
- case maglev_vehicle: v = new maglev_rail_vehicle_t(file, first, last); break;
- case narrowgauge_vehicle: v = new narrowgauge_rail_vehicle_t(file, first, last); break;
- default:
- dbg->fatal("depot_t::vehicle_laden()", "invalid vehicle type $%X", typ);
+ case old_road_vehicle:
+ case road_vehicle: v = new road_vehicle_t(file, first, last); break;
+ case old_waggon:
+ case rail_vehicle: v = new rail_vehicle_t(file, first, last); break;
+ case old_schiff:
+ case water_vehicle: v = new water_vehicle_t(file, first, last); break;
+ case old_aircraft:
+ case air_vehicle: v = new air_vehicle_t(file, first, last); break;
+ case old_monorail_vehicle:
+ case monorail_vehicle: v = new monorail_rail_vehicle_t(file, first, last); break;
+ case maglev_vehicle: v = new maglev_rail_vehicle_t(file, first, last); break;
+ case narrowgauge_vehicle: v = new narrowgauge_rail_vehicle_t(file, first, last); break;
+ default:
+ dbg->fatal("depot_t::vehicle_laden()", "invalid vehicle type $%X", typ);
}
const vehicle_desc_t* desc = v->get_desc();
if (desc) {
@@ -779,6 +827,8 @@ void depot_t::rdwr_vehicle(slist_tpl &list, loadsave_t *file)
}
}
+ // depot name
+ if(skip_depot_name) return;
if (file->is_version_ex_atleast(14, 56))
{
file->rdwr_str(name, lengthof(name));
@@ -801,6 +851,10 @@ void depot_t::set_name(const char* value)
if (win) {
win->reset_depot_name();
}
+ depotlist_frame_t *win2 = dynamic_cast(win_get_magic(magic_depotlist+get_owner_nr()));
+ if (win2) {
+ win2->fill_list();
+ }
}
const char* depot_t::get_name() const
@@ -823,7 +877,7 @@ const char * depot_t:: is_deletable(const player_t *player)
if(player!=get_owner() && player!=welt->get_public_player()) {
return NOTICE_OWNED_BY_OTHER_PLAYER;
}
- if (!vehicles.empty()) {
+ if (!vehicles.empty() || !vehicles_for_sale.empty()) {
return "There are still vehicles\nstored in this depot!\n";
}
@@ -926,12 +980,12 @@ uint16 depot_t::get_traction_types() const
* - 0 if we don't want to filter by traction type
* - a bitmask of possible traction types; we need only match one
*/
-bool depot_t::is_suitable_for( const vehicle_t * test_vehicle, const uint16 traction_types /* = 0 */ ) const
+bool depot_t::is_suitable_for( const vehicle_t * test_vehicle, const uint16 traction_types /* = 0 */, bool ignore_owner ) const
{
assert(test_vehicle != NULL);
- // Owner must be the same
- if ( this->get_owner() != test_vehicle->get_owner() ) {
+ // When transferring vehicles between players, the owner must be ignored.
+ if ( !ignore_owner && this->get_owner() != test_vehicle->get_owner() ) {
return false;
}
diff --git a/simdepot.h b/simdepot.h
index 869c72d0d88..ededd63e415 100644
--- a/simdepot.h
+++ b/simdepot.h
@@ -36,9 +36,12 @@ class depot_t : public gebaeude_t
* Vehicles are accessed by type.
*/
slist_tpl vehicles;
+ slist_tpl vehicles_for_sale;
slist_tpl convois;
- void rdwr_vehicle(slist_tpl &list, loadsave_t *file);
+ // Railway depots do not go through rdwr, so read the depot name with rdwr_vehicle
+ // skip_depot_name: Option to not load depot name again when loading vehicles_for_sale
+ void rdwr_vehicle(slist_tpl &list, loadsave_t *file, bool skip_depot_name=false);
static slist_tpl all_depots;
@@ -52,9 +55,10 @@ class depot_t : public gebaeude_t
* @param traction_types
* - 0 if we don't want to filter by traction type
* - a bitmask of possible traction types; we need only match one
+ * @param ignore_owner -- In the case of vehicle transfer, the owner must be ignored.
*/
uint16 get_traction_types() const;
- bool is_suitable_for( const vehicle_t * test_vehicle, const uint16 traction_types = 0) const;
+ bool is_suitable_for( const vehicle_t * test_vehicle, const uint16 traction_types = 0, bool ignore_owner=false) const;
// finds the next/previous depot relative to the current position
static depot_t *find_depot( koord3d start, const obj_t::typ depot_type, const player_t *player, bool next);
@@ -144,6 +148,7 @@ class depot_t : public gebaeude_t
*/
unsigned vehicle_count() const { return vehicles.get_count(); }
slist_tpl & get_vehicle_list() { return vehicles; }
+ slist_tpl& get_vehicles_for_sale() { return vehicles_for_sale; }
/**
* A new vehicle is bought and added to the vehicle list.
@@ -160,6 +165,15 @@ class depot_t : public gebaeude_t
*/
void sell_vehicle(vehicle_t* veh);
+ // Put the vehicle up for sale
+ void set_vehicle_for_sale(vehicle_t* veh);
+ void cancel_vehicle_for_sale(vehicle_t* veh);
+
+ // Receiving a vehicle from another player
+ void takeover_vehicle(vehicle_t* veh);
+ // for takeover
+ void remove_vehicle_from_listed(vehicle_t* veh);
+
/**
* Returns the waytype for a certain vehicle; only way to distinguish differnt depots ...
*/
@@ -263,7 +277,13 @@ class bahndepot_t : public depot_t
simline_t::linetype get_line_type() const OVERRIDE { return simline_t::trainline; }
- void rdwr_vehicles(loadsave_t *file) { depot_t::rdwr_vehicle(vehicles,file); }
+ void rdwr_vehicles(loadsave_t *file)
+ {
+ depot_t::rdwr_vehicle(vehicles,file);
+ if (file->is_version_ex_atleast(14, 67)) {
+ depot_t::rdwr_vehicle(vehicles_for_sale, file, true);
+ }
+ }
waytype_t get_wegtyp() const OVERRIDE {return track_wt;}
#ifdef INLINE_OBJ_TYPE
diff --git a/simmenu.cc b/simmenu.cc
index 8f079ec1166..b0468e92a9b 100644
--- a/simmenu.cc
+++ b/simmenu.cc
@@ -177,6 +177,7 @@ const char *tool_t::id_to_string(uint16 id)
CASE_TO_STRING(TOOL_CONVOY_LOADINGBAR);
CASE_TO_STRING(TOOL_SHOW_FACTORY_STORAGE);
CASE_TO_STRING(TOOL_REASSIGN_SIGNAL_INTERNAL);
+ CASE_TO_STRING(TOOL_TRANSFER_VEHICLE);
}
}
else if (id & DIALOG_TOOL) {
@@ -359,6 +360,7 @@ tool_t *create_simple_tool(int toolnr)
case TOOL_RECOLOUR_TOOL: tool = new tool_recolour_t(); break;
case TOOL_ACCESS_TOOL: tool = new tool_access_t(); break;
case TOOL_REASSIGN_SIGNAL_INTERNAL: tool = new tool_reassign_signal_internal_t(); break;
+ case TOOL_TRANSFER_VEHICLE: tool = new tool_transfer_vehicle_t(); break;
case UNUSED_WKZ_PWDHASH_TOOL:
dbg->warning("create_simple_tool()","deprecated tool [%i] requested", toolnr);
return NULL;
diff --git a/simmenu.h b/simmenu.h
index ced66e23f95..be3419ad671 100644
--- a/simmenu.h
+++ b/simmenu.h
@@ -145,6 +145,7 @@ enum {
TOOL_SHOW_FACTORY_STORAGE,
TOOL_TOGGLE_CONTROL,
TOOL_REASSIGN_SIGNAL_INTERNAL,
+ TOOL_TRANSFER_VEHICLE,
SIMPLE_TOOL_COUNT,
SIMPLE_TOOL = 0x2000
};
diff --git a/simtool.cc b/simtool.cc
index a9acd3984a8..435e6f2e47e 100644
--- a/simtool.cc
+++ b/simtool.cc
@@ -10298,8 +10298,11 @@ bool tool_change_line_t::init( player_t *player )
* 'a' : appends a vehicle (+vehicle_name) uses the oldest
* 'i' : inserts a vehicle in front (+vehicle_name) uses the oldest
* 's' : sells a vehicle (+vehicle_name) uses the newest
+ * 'S' : Sell a specific vehicle specified by its index number
* 'r' : removes a vehicle (+number in convoi)
* 'R' : removes all vehicles including (+number in convoi) to end
+ * 'f' : change "for_sale" state of the vehicle (vehicle name is not used)
+ * 'F' : cancel "for_sale" state of the vehicle (vehicle name is not used)
*/
bool tool_change_depot_t::init( player_t *player )
{
@@ -10404,6 +10407,52 @@ bool tool_change_depot_t::init( player_t *player )
}
break;
}
+ case 'S':
+ {
+ // Sell a specific vehicle. Not the newest one.
+ // Use liveryscheme_index as vehicle index.
+ vehicle_t* veh = depot->get_vehicle_list().at(livery_scheme_index);
+ if (veh != NULL) {
+ depot->sell_vehicle(veh);
+ }
+ break;
+ }
+ case 'f':
+ {
+ // Use liveryscheme_index as vehicle index.
+ vehicle_t* veh = depot->get_vehicle_list().at(livery_scheme_index);
+ if (veh != NULL) {
+ depot->set_vehicle_for_sale(veh);
+ cbuffer_t buf;
+ if (welt->get_active_player_nr()==depot->get_owner_nr()) {
+ buf.printf(translator::translate("You put %s up for sale."), translator::translate(veh->get_desc()->get_name()));
+ }
+ else{
+ buf.printf(translator::translate("%s offer %s for sale."), depot->get_owner()->get_name(), translator::translate(veh->get_desc()->get_name()));
+ }
+ welt->get_message()->add_message(buf, koord::invalid, message_t::new_vehicle, color_idx_to_rgb(depot->get_owner()->get_player_color1() + env_t::gui_player_color_dark), veh->get_base_image());
+ welt->add_listed_vehicle_count(1, veh->get_waytype());
+ }
+ break;
+ }
+ case 'F':
+ {
+ // Use liveryscheme_index as vehicle index.
+ vehicle_t* veh = depot->get_vehicles_for_sale().at(livery_scheme_index);
+ if (veh != NULL) {
+ depot->cancel_vehicle_for_sale(veh);
+ cbuffer_t buf;
+ if (welt->get_active_player_nr()==depot->get_owner_nr()) {
+ buf.printf(translator::translate("You have cancelled the listing for %s."), translator::translate(veh->get_desc()->get_name()));
+ }
+ else{
+ buf.printf(translator::translate("%s cancelled the listing for %s."), depot->get_owner()->get_name(), translator::translate(veh->get_desc()->get_name()));
+ }
+ welt->get_message()->add_message(buf, koord::invalid, message_t::new_vehicle, color_idx_to_rgb(depot->get_owner()->get_player_color1() + env_t::gui_player_color_dark), veh->get_base_image());
+ welt->add_listed_vehicle_count(-1, veh->get_waytype());
+ }
+ break;
+ }
case 'a': // append a vehicle
case 'i': // insert a vehicle in front
case 's': // sells a vehicle
@@ -11215,3 +11264,42 @@ bool tool_reassign_signal_internal_t::init(player_t *player)
}
return false;
}
+
+
+bool tool_transfer_vehicle_t::init(player_t* player)
+{
+ koord3d pos_from;
+ koord3d pos_to;
+ uint32 veh_index;
+
+ if (7 != sscanf(default_param, "%hi,%hi,%hhi,%hi,%hi,%hhi,%u", &pos_from.x, &pos_from.y, &pos_from.z, &pos_to.x, &pos_to.y, &pos_to.z, &veh_index))
+ {
+ dbg->error("tool_transfer_vehicle_t::init", "could not perform (%s)", default_param);
+ return false;
+ }
+
+ if (grund_t* gr = welt->lookup(pos_from)) {
+ if (depot_t* from = gr->get_depot()) {
+ if (grund_t* gr2 = welt->lookup(pos_to)) {
+ if (depot_t* to = gr2->get_depot()) {
+ vehicle_t* veh = from->get_vehicles_for_sale().at(veh_index);
+ if (veh != NULL) {
+ to->takeover_vehicle(veh);
+ player_t *buyer=to->get_owner();
+ player_t *seller=from->get_owner();
+ cbuffer_t buf;
+ if (welt->get_active_player() == buyer) {
+ buf.printf(translator::translate("You purchased %s from %s."), translator::translate(veh->get_desc()->get_name()), seller->get_name());
+ }
+ else {
+ buf.printf(translator::translate("%s purchased %s that you had listed."), buyer->get_name(), translator::translate(veh->get_desc()->get_name()));
+ }
+ welt->get_message()->add_message(buf, koord::invalid, message_t::new_vehicle, color_idx_to_rgb(buyer->get_player_color1() + env_t::gui_player_color_dark), veh->get_base_image());
+ welt->add_listed_vehicle_count(-1, veh->get_waytype());
+ }
+ }
+ }
+ }
+ }
+ return false;
+}
diff --git a/simtool.h b/simtool.h
index 2ab159b6920..a1d2dcdedb9 100644
--- a/simtool.h
+++ b/simtool.h
@@ -1450,4 +1450,12 @@ class tool_reassign_signal_internal_t : public tool_t {
bool is_init_keeps_game_state() const OVERRIDE { return false; }
};
+// internal tool: Transfer a vehicle from one depot to another in order to give it away
+class tool_transfer_vehicle_t : public tool_t {
+public:
+ tool_transfer_vehicle_t() : tool_t(TOOL_TRANSFER_VEHICLE | SIMPLE_TOOL) {}
+ bool init(player_t* player) OVERRIDE;
+ bool is_init_keeps_game_state() const OVERRIDE { return false; }
+};
+
#endif
diff --git a/simutrans/text/ja.tab b/simutrans/text/ja.tab
index b05bc157be4..f709ae8ed9f 100644
--- a/simutrans/text/ja.tab
+++ b/simutrans/text/ja.tab
@@ -845,8 +845,6 @@ convoi passed last month:
前月交通量:
Convois
編成数
-Convois: %d\nProfit: %s
-就役編成: %d\n利益: %s
Convoys
編成
Copy Convoi
@@ -2267,6 +2265,38 @@ Zu nah am Kartenrand
%s大通り%s
#___________________________Simutrans Extended Texts____________________________
#___________________________Simutrans Extended Texts____________________________
+You put %s up for sale.
+「%s」を出品しました。
+You have cancelled the listing for %s.
+「%s」の出品を中止しました。
+You purchased %s from %s.
+%2$sから「%1$s」を購入しました。
+%s offer %s for sale.
+%sは「%s」の買い手を探しています。
+%s cancelled the listing for %s."
+%sは「%s」の出品を中止しました。
+%s purchased %s that you had listed.
+%sがあなたが出品中の「%s」を購入しました。
+Stored
+入庫中
+1 vehicle
+1台(両)
+Listed
+出品中
+veh_mgr
+車庫名変更/車両売買
+Open the vehicle management window
+ここから車庫名の変更と車両の売買が行えます
+execute_scrap
+廃車解体する
+execute_listing
+出品する
+cancel_the_listing
+出品を中止する
+execute_purchase
+中古車両を購入
+Cancel the listing request for the selected vehicles
+選択した車両の出品を取り下げます
hd_sv_mode_frequency
運行頻度、編成数
hd_sv_mode_catg
@@ -2427,8 +2457,10 @@ building
建築物
Built
建設年月
-Buy/sell
-購入/売却
+Built date
+製造年月
+Buy
+中古車の購入
cab_signalling
車内信号閉塞式
call_on
@@ -3794,7 +3826,7 @@ map_btn_building_level
sort_pas_arrived
旅客輸送実績
Scrap
-車両を解体
+廃車解体
Scrap all vehicles in the convoy.
編成中の車両を全て解体します。車両購入費用は一切戻ってきません。
Return the vehicle(s) for a full refund.
@@ -4519,6 +4551,10 @@ line_network
接続路線
#_______________________________unnecessary_text________________________________
#_______________________________unnecessary_text________________________________
+Buy/sell
+購入/売却
+Convois: %d\nProfit: %s
+就役編成: %d\n利益: %s
Free Capacity
空席
100 km/h = %i tiles/month
diff --git a/simutrans/themes/modern.tab b/simutrans/themes/modern.tab
index 7826162176f..2668339d013 100644
--- a/simutrans/themes/modern.tab
+++ b/simutrans/themes/modern.tab
@@ -78,9 +78,11 @@ gui_color_chart_lines_zero = #005C9E
gui_color_chart_lines_odd = #338FCC
gui_color_chart_lines_even = #005C9E
-gui_color_list_text_selected_focus = #FAFAFA
-gui_color_list_text_selected_nofocus = #FAFAFA
-gui_color_list_background_selected_focus = #72B2DD
+gui_color_list_text_selected_focus = #FAFAFA
+gui_color_list_text_selected_nofocus = #FAFAFA
+gui_color_list_background_even = #B5DBEF
+gui_color_list_background_odd = #DEF3FF
+gui_color_list_background_selected_focus = #72B2DD
gui_color_list_background_selected_nofocus = #72B2DD
gui_color_button_text = #FAFAFA
@@ -129,6 +131,26 @@ gui_chat_window_network_transparency = 0
# if defined, use plain color for chat window in network games
gui_color_chat_window_network_transparency = #D6ECF7
+# Color for table
+gui_color_table_frame = #6392BD
+gui_color_table_background_head_row = #6392BD
+gui_color_table_background_head_selected = #31596B
+gui_color_table_header_border = #52799C
+gui_color_table_cell_border = #8CC3E7
+gui_color_table_background_left_col = #8CC3E7
+gui_color_table_background_data_sum = #ABD3EF
+gui_color_table_background_data = #C6E3F7
+gui_color_table_background = #E7F3FF
+gui_color_table_background_highlight = #DEE5AD
+gui_color_table_background_selected = #73b2de
+gui_color_text_head_row = #FFFFFF
+gui_color_text_left_col = #000000
+gui_color_text_head_selected = #ffffff
+gui_color_text_table_cell_selected = #ffffff
+
+# Chart button
+gui_color_chart_button_background = #99ddff
+
##################################size stuff##################################
# force main menu icon size
diff --git a/simutrans/themes/newstandard-large.tab b/simutrans/themes/newstandard-large.tab
index 39fbff46c94..b9ea7c99732 100644
--- a/simutrans/themes/newstandard-large.tab
+++ b/simutrans/themes/newstandard-large.tab
@@ -82,6 +82,8 @@ gui_color_obsolete = #0000F8
#gui_color_list_text_selected_focus = #000000
#gui_color_list_text_selected_nofocus = #000000
+gui_color_list_background_even = #BDCBD6
+gui_color_list_background_odd = #D6E3EF
#gui_color_list_background_selected_focus = #000000
#gui_color_list_background_selected_nofocus = #000000
@@ -142,23 +144,28 @@ gui_color_table_cell_border = #8c9aad
gui_color_table_background_left_col = #cedbe7
gui_color_table_background_data_sum = #c6d3de
gui_color_table_background_data = #bdcbd6
-gui_color_table_background = #adbac6
+gui_color_table_background = #BDCBD6
+gui_color_table_background_highlight= #DEE5AD
gui_color_text_head_row = #ffffff
gui_color_text_left_col = #000000
#gui_color_table_frame = #5a829c
#gui_color_table_background_head_row = #7392a5
+gui_color_table_background_head_selected = #73b2de
#gui_color_table_header_border = #5a829c
#gui_color_table_cell_border = #8c9aad
#gui_color_table_background_left_col = #9cb2c6
#gui_color_table_background_data_sum = #a5bace
#gui_color_table_background_data = #b1bfce
#gui_color_table_background = #c6d3de
+#gui_color_table_background_highlight= #DEE5AD
+gui_color_table_background_selected = #73b2de
#gui_color_text_head_row = #ffffff
#gui_color_text_left_col = #000000
+gui_color_text_head_selected = #ffffff
+gui_color_text_table_cell_selected = #ffffff
-##################################size stuff##################################
-
+################################## Size settings ##################################
# size of tools
icon_width = 48
diff --git a/simutrans/themes/purple_night-large.tab b/simutrans/themes/purple_night-large.tab
new file mode 100644
index 00000000000..62b907cf9e3
--- /dev/null
+++ b/simutrans/themes/purple_night-large.tab
@@ -0,0 +1,217 @@
+#
+# Simutrans purple night large theme
+#
+# Read the wiki article for better explanation and full parameters list
+# https://wiki.simutrans.com/en_themeDef
+#
+
+# name of the theme (will be shown with file selector)
+name=Purple Night (large size)
+
+# show tooltips (default 1=show)
+show_tooltips = 1
+
+# tooltip background color (+-1 around this index is used), taken from player-color table
+tooltip_background_color = 4
+
+# tooltip text color (240=black, 215=white)
+tooltip_text_color = 240
+
+# delay before showing tooltip in ms (default 500ms)
+tooltip_delay = 500
+
+# duration in ms during tooltip is visible (default 5000ms=5s)
+tooltip_duration = 5000
+
+# windows drop a little shadow (default off)
+# gui_drop_shadows = 1
+
+#################################window stuff#################################
+
+# when moving, you can use windows to snap onto each other seamlessly
+# if you do not like it, set the catch radius to zero
+window_snap_distance = 8
+
+# show the windows close etc. buttons on the right (like Windows)
+# window_buttons_right = 0
+
+# closes windows/toolbar when button clicked a second time (default off=0)
+second_open_closes_win = 0
+
+# restores window position when window is reopening
+# This will be saved, but will be discarded when screen is resized
+remember_window_positions = 1
+
+# there are three different ways to indicate an active window
+
+# first: draw a frame with titlebar color around active window
+# window_frame_active = 0
+
+# second: draw the title with a different brightness (0: dark ... 6: bright)
+front_window_bar_color = 1
+bottom_window_bar_color = 3
+
+# third (best together with 2nd):use different text color for bar
+# some colors are 215-white, 240-black 208-214- all shades of gray
+front_window_text_color = #DDDDDD
+bottom_window_text_color = #C0C0C0
+
+#################################colour stuff#################################
+
+default_window_title_color = #705726
+
+gui_color_text = #C0C0C0
+gui_color_text_highlight = #908010
+gui_color_text_shadow = #00FF00
+gui_color_text_title = #338FCC
+gui_color_text_strong = #E46A0B
+
+########Test########
+gui_color_empty = #868c86
+gui_color_obsolete = #2878ff
+
+gui_color_edit_text = #908010
+gui_color_edit_text_selected = #FAFAFA
+gui_color_edit_text_disabled = #666666
+gui_color_edit_background_selected = #72B2DD
+gui_color_edit_beam = #a89823
+
+gui_color_chart_background = #2e2e40
+gui_color_chart_lines_zero = #005C9E
+gui_color_chart_lines_odd = #68688e
+gui_color_chart_lines_even = #68688e
+
+gui_color_list_text_selected_focus = #C0C0C0
+gui_color_list_text_selected_nofocus = #908010
+gui_color_list_background_selected_focus = #72B2DD
+gui_color_list_background_selected_nofocus = #72B2DD
+
+gui_color_button_text = #C0C0C0
+gui_color_button_text_disabled = #8A8A8A
+gui_color_button_text_selected = #FAFAFA
+
+gui_color_colored_button_text = #201000
+gui_color_colored_button_text_selected = #CCCCCC
+
+gui_color_checkbox_text = #C0C0C0
+gui_color_checkbox_text_disabled = #666666
+
+gui_color_ticker_background = #3c3c52
+gui_color_ticker_divider = #4d4d69
+
+gui_color_statusbar_text = #C0C0C0
+gui_color_statusbar_background = #3c3c52
+gui_color_statusbar_divider = #4d4d69
+
+gui_highlight_color = #68688e
+gui_shadow_color = #000000
+
+gui_color_text_minus = #C07010
+gui_color_text_plus = #70C010
+gui_color_text_unused = #E46A0B
+
+# Color of cursor overlay, which is blended over marked ground tiles
+cursor_overlay_color = #1060F0
+
+# Color loadbar, save game, load game, server...
+gui_color_loadingbar_progress = #6080A0
+gui_color_loadingbar_inner = #303246
+
+# Color player bright
+gui_player_color_dark = 3
+gui_player_color_bright = 7
+gui_titlebar_player_color_background_brightness = 2
+
+# make the chat window transparent in network games
+gui_chat_window_network_transparency = 25
+
+# if defined, use plain color for chat window in network games
+gui_color_chat_window_network_transparency = #D6ECF7
+
+# Transparency color of boost icons (mail, energy, passangers) in factories
+gui_color_image_transparency = #ffffff
+
+# Extended unique color settings
+gui_color_up_pointing_triangle = #00ebff
+#gui_color_down_pointing_triangle = #
+gui_color_out_of_production = #0092a5
+gui_color_text_overcrowding = #d659a5
+# Recommended brightness: gui_color_text < gui_color_text_weak < gui_color_text_inactive (reversed on dark themes)
+gui_color_text_inactive = #63618c
+gui_color_text_weak = #848a8c
+
+#---- Color for table
+gui_color_table_header_border = #5a5973
+#gui_color_table_background_head_row =
+gui_color_table_background_head_selected = #AD9239
+gui_color_table_frame = #63618c
+gui_color_table_background_head_row = #63618c
+gui_color_table_cell_border = #5a5973
+gui_color_table_background_left_col = #5a5973
+gui_color_table_background_data_sum = #52516b
+gui_color_table_background_data = #4a4961
+gui_color_table_background = #424459
+gui_color_table_background_highlight = #737152
+gui_color_table_background_selected = #5A92A5
+gui_color_text_head_row = #FFFFFF
+gui_color_text_left_col = #c6cbce
+#gui_color_text_head_selected = #737152
+gui_color_text_table_cell_selected = #eff3f7
+gui_color_list_background_even = #424459
+gui_color_list_background_odd = #55576c
+
+##################################size stuff##################################
+
+# force main menu icon size
+icon_width = 48
+
+# titlebar height
+gui_titlebar_height = 22
+
+# width of the window elements
+gui_gadget_width = 22
+
+# safe margin around windows
+# gui_frame_left = 10
+# gui_frame_top = 10
+# gui_frame_right = 10
+# gui_frame_bottom = 10
+
+# horizontal and vertical margins between objects
+# gui_hspace = 4
+# gui_vspace = 4
+
+# tab minimum sizes
+gui_tab_header_vsize = 22
+
+# input boxes height
+# minimum height is the height of the position button graphic
+# gui_edit_height = 22
+
+# checkbox height, default sizes come from the checkbox graphic
+# gui_checkbox_width = 10
+# gui_checkbox_height = 10
+
+# sum of the top and bottom margins for divider lines
+# default is twice the size of gui_vspace
+# gui_divider_vsize = 8
+
+# buttons sizes
+gui_button_height = 22
+# for buttons with fixed widths
+gui_button_width = 100
+
+# text margins inside the buttons (left, top, right)
+gui_button_text_offset = 5,2,5
+gui_color_button_text_offset = 5,2,5
+
+# maximum size of tool bars in tools (0 = no limit)
+# if more tools than allowed by height,
+# next and prev arrows for scrolling appears
+toolbar_max_width = 0
+toolbar_max_height = 0
+
+###################################pakstuff###################################
+
+# pak with the images for this theme
+themeimages=purple_night-large.pak
diff --git a/simutrans/themes/purple_night.tab b/simutrans/themes/purple_night.tab
new file mode 100644
index 00000000000..728f29105ac
--- /dev/null
+++ b/simutrans/themes/purple_night.tab
@@ -0,0 +1,217 @@
+#
+# Simutrans purple night theme
+#
+# Read the wiki article for better explanation and full parameters list
+# https://wiki.simutrans.com/en_themeDef
+#
+
+# name of the theme (will be shown with file selector)
+name=Purple Night
+
+# show tooltips (default 1=show)
+show_tooltips = 1
+
+# tooltip background color (+-1 around this index is used), taken from player-color table
+tooltip_background_color = 4
+
+# tooltip text color (240=black, 215=white)
+tooltip_text_color = 240
+
+# delay before showing tooltip in ms (default 500ms)
+tooltip_delay = 500
+
+# duration in ms during tooltip is visible (default 5000ms=5s)
+tooltip_duration = 5000
+
+# windows drop a little shadow (default off)
+# gui_drop_shadows = 1
+
+#################################window stuff#################################
+
+# when moving, you can use windows to snap onto each other seamlessly
+# if you do not like it, set the catch radius to zero
+window_snap_distance = 8
+
+# show the windows close etc. buttons on the right (like Windows)
+# window_buttons_right = 0
+
+# closes windows/toolbar when button clicked a second time (default off=0)
+second_open_closes_win = 0
+
+# restores window position when window is reopening
+# This will be saved, but will be discarded when screen is resized
+remember_window_positions = 1
+
+# there are three different ways to indicate an active window
+
+# first: draw a frame with titlebar color around active window
+# window_frame_active = 0
+
+# second: draw the title with a different brightness (0: dark ... 6: bright)
+front_window_bar_color = 1
+bottom_window_bar_color = 3
+
+# third (best together with 2nd):use different text color for bar
+# some colors are 215-white, 240-black 208-214- all shades of gray
+front_window_text_color = #DDDDDD
+bottom_window_text_color = #B7B7B7
+
+#################################colour stuff#################################
+
+default_window_title_color = #705726
+
+gui_color_text = #D0D0D0
+gui_color_text_highlight = #908010
+gui_color_text_shadow = #00FF00
+gui_color_text_title = #338FCC
+gui_color_text_strong = #E46A0B
+
+########Test########
+gui_color_empty = #868c86
+gui_color_obsolete = #2878ff
+
+gui_color_edit_text = #908010
+gui_color_edit_text_selected = #FAFAFA
+gui_color_edit_text_disabled = #666666
+gui_color_edit_background_selected = #72B2DD
+gui_color_edit_beam = #a89823
+
+gui_color_chart_background = #2e2e40
+gui_color_chart_lines_zero = #005C9E
+gui_color_chart_lines_odd = #68688e
+gui_color_chart_lines_even = #68688e
+
+gui_color_list_text_selected_focus = #B7B7B7
+gui_color_list_text_selected_nofocus = #908010
+gui_color_list_background_selected_focus = #72B2DD
+gui_color_list_background_selected_nofocus = #72B2DD
+
+gui_color_button_text = #C0C0C0
+gui_color_button_text_disabled = #8A8A8A
+gui_color_button_text_selected = #FAFAFA
+
+gui_color_colored_button_text = #201000
+gui_color_colored_button_text_selected = #CCCCCC
+
+gui_color_checkbox_text = #C0C0C0
+gui_color_checkbox_text_disabled = #666666
+
+gui_color_ticker_background = #3c3c52
+gui_color_ticker_divider = #4d4d69
+
+gui_color_statusbar_text = #C0C0C0
+gui_color_statusbar_background = #3c3c52
+gui_color_statusbar_divider = #4d4d69
+
+gui_highlight_color = #68688e
+gui_shadow_color = #000000
+
+gui_color_text_minus = #C07010
+gui_color_text_plus = #70C010
+gui_color_text_unused = #E46A0B
+
+# Color of cursor overlay, which is blended over marked ground tiles
+cursor_overlay_color = #1060F0
+
+# Color loadbar, save game, load game, server...
+gui_color_loadingbar_progress = #6080A0
+gui_color_loadingbar_inner = #303246
+
+# Color player bright
+gui_player_color_dark = 3
+gui_player_color_bright = 7
+gui_titlebar_player_color_background_brightness = 2
+
+# make the chat window transparent in network games
+gui_chat_window_network_transparency = 25
+
+# if defined, use plain color for chat window in network games
+gui_color_chat_window_network_transparency = #D6ECF7
+
+# Transparency color of boost icons (mail, energy, passangers) in factories
+gui_color_image_transparency = #ffffff
+
+# Extended unique color settings
+gui_color_up_pointing_triangle = #00ebff
+#gui_color_down_pointing_triangle = #
+gui_color_out_of_production = #0092a5
+gui_color_text_overcrowding = #d659a5
+# Recommended brightness: gui_color_text < gui_color_text_weak < gui_color_text_inactive (reversed on dark themes)
+gui_color_text_inactive = #63618c
+gui_color_text_weak = #848a8c
+
+#---- Color for table
+gui_color_table_header_border = #5a5973
+#gui_color_table_background_head_row =
+gui_color_table_background_head_selected = #AD9239
+gui_color_table_frame = #63618c
+gui_color_table_background_head_row = #63618c
+gui_color_table_cell_border = #5a5973
+gui_color_table_background_left_col = #5a5973
+gui_color_table_background_data_sum = #52516b
+gui_color_table_background_data = #4a4961
+gui_color_table_background = #424459
+gui_color_table_background_highlight = #737152
+gui_color_table_background_selected = #5A92A5
+gui_color_text_head_row = #FFFFFF
+gui_color_text_left_col = #c6cbce
+#gui_color_text_head_selected = #737152
+gui_color_text_table_cell_selected = #eff3f7
+gui_color_list_background_even = #424459
+gui_color_list_background_odd = #55576c
+
+##################################size stuff##################################
+
+# force main menu icon size
+icon_width = 32
+
+# titlebar height
+gui_titlebar_height = 22
+
+# width of the window elements
+gui_gadget_width = 20
+
+# safe margin around windows
+# gui_frame_left = 10
+# gui_frame_top = 10
+# gui_frame_right = 10
+# gui_frame_bottom = 10
+
+# horizontal and vertical margins between objects
+# gui_hspace = 4
+# gui_vspace = 4
+
+# tab minimum sizes
+gui_tab_header_vsize = 18
+
+# input boxes height
+# minimum height is the height of the position button graphic
+# gui_edit_height = 22
+
+# checkbox height, default sizes come from the checkbox graphic
+# gui_checkbox_width = 10
+# gui_checkbox_height = 10
+
+# sum of the top and bottom margins for divider lines
+# default is twice the size of gui_vspace
+# gui_divider_vsize = 8
+
+# buttons sizes
+gui_button_height = 17
+# for buttons with fixed widths
+gui_button_width = 100
+
+# text margins inside the buttons (left, top, right)
+gui_button_text_offset = 5,1,5
+gui_color_button_text_offset = 5,1,5
+
+# maximum size of tool bars in tools (0 = no limit)
+# if more tools than allowed by height,
+# next and prev arrows for scrolling appears
+toolbar_max_width = 0
+toolbar_max_height = 0
+
+###################################pakstuff###################################
+
+# pak with the images for this theme
+themeimages=purple_night.pak
diff --git a/simutrans/themes/silver-large.tab b/simutrans/themes/silver-large.tab
new file mode 100644
index 00000000000..27513b7d5d6
--- /dev/null
+++ b/simutrans/themes/silver-large.tab
@@ -0,0 +1,182 @@
+# Simutrans default touch theme
+#
+# Read the wiki article for better explanation and full parameters list
+# https://wiki.simutrans.com/en_themeDef
+#
+# name of the theme (will be shown with file selector)
+name=Silver (large size)
+
+# show tooltips (default 1=show)
+show_tooltips = 1
+
+# tooltip background color (+-1 around this index is used), taken from player-color table
+tooltip_background_color = 4
+
+# tooltip text color (240=black, 215=white)
+tooltip_text_color = 240
+
+# delay before showing tooltip in ms (default 500ms)
+tooltip_delay = 500
+
+# duration in ms during tooltip is visible (default 5000ms=5s)
+tooltip_duration = 5000
+
+# windows drop a little shadow (default off)
+# gui_drop_shadows = 1
+
+#################################window stuff#################################
+
+# when moving, you can use windows to snap onto each other seamlessly
+# if you do not like it, set the catch radius to zero
+window_snap_distance = 8
+
+# show the windows close etc. buttons on the right (like Windows)
+# window_buttons_right = 0
+
+# closes windows/toolbar when button clicked a second time (default off=0)
+second_open_closes_win = 0
+
+# restores window position when window is reopening
+# This will be saved, but will be discarded when screen is resized
+remember_window_positions = 1
+
+# there are three different ways to indicate an active window
+
+# first: draw a frame with titlebar color around active window
+# window_frame_active = 0
+
+# second: draw the title with a different brightness (0: dark ... 6: bright)
+front_window_bar_color = 1
+bottom_window_bar_color = 3
+
+# third (best together with 2nd):use different text color for bar
+# some colors are 215-white, 240-black 208-214- all shades of gray
+front_window_text_color = #FFFFFF
+bottom_window_text_color = #C0C0C0
+
+#################################colour stuff#################################
+
+default_window_title_color = #84939e
+
+# gui_color_text = #000000
+gui_color_text_highlight = #706000
+gui_color_text_shadow = #BDD3DF
+gui_color_text_title = #338FCC
+gui_color_text_strong = #E46A0B
+
+########Test########
+gui_color_empty = #868c86
+gui_color_obsolete = #2878ff
+
+gui_color_edit_text = #000000
+gui_color_edit_text_selected = #FAFAFA
+gui_color_edit_text_disabled = #666666
+gui_color_edit_background_selected = #72B2DD
+gui_color_edit_beam = #000000
+
+gui_color_chart_background = #6f6d60
+gui_color_chart_lines_zero = #005C9E
+gui_color_chart_lines_odd = #373630
+gui_color_chart_lines_even = #373630
+
+gui_color_list_text_selected_focus = #FAFAFA
+gui_color_list_text_selected_nofocus = #FAFAFA
+gui_color_list_background_selected_focus = #72B2DD
+gui_color_list_background_selected_nofocus = #72B2DD
+
+gui_color_button_text = #001020
+gui_color_button_text_disabled = #666666
+gui_color_button_text_selected = #FAFAFA
+
+gui_color_colored_button_text = #FAFAFA
+gui_color_colored_button_text_selected = #FAFAFA
+
+# gui_color_checkbox_text = #000000
+gui_color_checkbox_text_disabled = #666666
+
+gui_color_ticker_background = #D6ECF7
+gui_color_ticker_divider = #6095B8
+
+# gui_color_statusbar_text = #000000
+gui_color_statusbar_background = #b8b8a8
+gui_color_statusbar_divider = #f8fcf0
+
+gui_highlight_color = #FFFFF7
+gui_shadow_color = #72726E
+
+# gui_color_text_minus = #C00000
+# gui_color_text_plus = #000000
+gui_color_text_unused = #555f66
+
+# Color of cursor overlay, which is blended over marked ground tiles
+cursor_overlay_color = #ff0000
+
+# Color loadbar, save game, load game, server...
+gui_color_loadingbar_progress = #76b9e6
+gui_color_loadingbar_inner = #D6ECF7
+
+# Color player brigth
+gui_player_color_dark = 1
+gui_player_color_bright = 3
+
+# make the chat window transparent in network games
+gui_chat_window_network_transparency = 25
+
+# if defined, use plain color for chat window in network games
+gui_color_chat_window_network_transparency = #D6ECF7
+
+##################################size stuff##################################
+
+# force main menu icon size
+icon_width = 48
+
+# titlebar height
+gui_titlebar_height = 22
+
+# width of the window elements
+gui_gadget_width = 22
+
+# safe margin around windows
+# gui_frame_left = 10
+# gui_frame_top = 10
+# gui_frame_right = 10
+# gui_frame_bottom = 10
+
+# horizontal and vertical margins between objects
+# gui_hspace = 4
+# gui_vspace = 4
+
+# tab minimum sizes
+gui_tab_header_vsize = 22
+
+# input boxes height
+# minimum height is the height of the position button graphic
+# gui_edit_height = 22
+
+# checkbox height, default sizes come from the checkbox graphic
+# gui_checkbox_width = 10
+# gui_checkbox_height = 10
+
+# sum of the top and bottom margins for divider lines
+# default is twice the size of gui_vspace
+# gui_divider_vsize = 8
+
+# buttons sizes
+gui_button_height = 22
+# for buttons with fixed widths
+gui_button_width = 100
+
+# text margins inside the buttons (left, top, right)
+gui_button_text_offset = 5,1,5
+gui_color_button_text_offset = 5,1,5
+
+# maximum size of tool bars in tools (0 = no limit)
+# if more tools than allowed by height,
+# next and prev arrows for scrolling appears
+toolbar_max_width = 0
+toolbar_max_height = 0
+
+###################################pakstuff###################################
+
+# pak with the images for this theme
+themeimages=silver-large.pak
diff --git a/simutrans/themes/silver.tab b/simutrans/themes/silver.tab
new file mode 100644
index 00000000000..6d847031976
--- /dev/null
+++ b/simutrans/themes/silver.tab
@@ -0,0 +1,182 @@
+# Simutrans default touch theme
+#
+# Read the wiki article for better explanation and full parameters list
+# https://wiki.simutrans.com/en_themeDef
+#
+# name of the theme (will be shown with file selector)
+name=Silver
+
+# show tooltips (default 1=show)
+show_tooltips = 1
+
+# tooltip background color (+-1 around this index is used), taken from player-color table
+tooltip_background_color = 4
+
+# tooltip text color (240=black, 215=white)
+tooltip_text_color = 240
+
+# delay before showing tooltip in ms (default 500ms)
+tooltip_delay = 500
+
+# duration in ms during tooltip is visible (default 5000ms=5s)
+tooltip_duration = 5000
+
+# windows drop a little shadow (default off)
+# gui_drop_shadows = 1
+
+#################################window stuff#################################
+
+# when moving, you can use windows to snap onto each other seamlessly
+# if you do not like it, set the catch radius to zero
+window_snap_distance = 8
+
+# show the windows close etc. buttons on the right (like Windows)
+# window_buttons_right = 0
+
+# closes windows/toolbar when button clicked a second time (default off=0)
+second_open_closes_win = 0
+
+# restores window position when window is reopening
+# This will be saved, but will be discarded when screen is resized
+remember_window_positions = 1
+
+# there are three different ways to indicate an active window
+
+# first: draw a frame with titlebar color around active window
+# window_frame_active = 0
+
+# second: draw the title with a different brightness (0: dark ... 6: bright)
+front_window_bar_color = 1
+bottom_window_bar_color = 3
+
+# third (best together with 2nd):use different text color for bar
+# some colors are 215-white, 240-black 208-214- all shades of gray
+front_window_text_color = #FFFFFF
+bottom_window_text_color = #C0C0C0
+
+#################################colour stuff#################################
+
+default_window_title_color = #84939e
+
+# gui_color_text = #000000
+gui_color_text_highlight = #706000
+gui_color_text_shadow = #BDD3DF
+gui_color_text_title = #338FCC
+gui_color_text_strong = #E46A0B
+
+########Test########
+gui_color_empty = #868c86
+gui_color_obsolete = #2878ff
+
+gui_color_edit_text = #000000
+gui_color_edit_text_selected = #FAFAFA
+gui_color_edit_text_disabled = #666666
+gui_color_edit_background_selected = #72B2DD
+gui_color_edit_beam = #000000
+
+gui_color_chart_background = #6f6d60
+gui_color_chart_lines_zero = #005C9E
+gui_color_chart_lines_odd = #373630
+gui_color_chart_lines_even = #373630
+
+gui_color_list_text_selected_focus = #FAFAFA
+gui_color_list_text_selected_nofocus = #FAFAFA
+gui_color_list_background_selected_focus = #72B2DD
+gui_color_list_background_selected_nofocus = #72B2DD
+
+gui_color_button_text = #001020
+gui_color_button_text_disabled = #666666
+gui_color_button_text_selected = #FAFAFA
+
+gui_color_colored_button_text = #FAFAFA
+gui_color_colored_button_text_selected = #FAFAFA
+
+# gui_color_checkbox_text = #000000
+gui_color_checkbox_text_disabled = #666666
+
+gui_color_ticker_background = #D6ECF7
+gui_color_ticker_divider = #6095B8
+
+# gui_color_statusbar_text = #000000
+gui_color_statusbar_background = #b8b8a8
+gui_color_statusbar_divider = #f8fcf0
+
+gui_highlight_color = #FFFFF7
+gui_shadow_color = #72726E
+
+# gui_color_text_minus = #C00000
+# gui_color_text_plus = #000000
+gui_color_text_unused = #555f66
+
+# Color of cursor overlay, which is blended over marked ground tiles
+cursor_overlay_color = #ff0000
+
+# Color loadbar, save game, load game, server...
+gui_color_loadingbar_progress = #76b9e6
+gui_color_loadingbar_inner = #D6ECF7
+
+# Color player brigth
+gui_player_color_dark = 1
+gui_player_color_bright = 3
+
+# make the chat window transparent in network games
+gui_chat_window_network_transparency = 25
+
+# if defined, use plain color for chat window in network games
+gui_color_chat_window_network_transparency = #D6ECF7
+
+##################################size stuff##################################
+
+# force main menu icon size
+icon_width = 32
+
+# titlebar height
+gui_titlebar_height = 22
+
+# width of the window elements
+gui_gadget_width = 20
+
+# safe margin around windows
+# gui_frame_left = 10
+# gui_frame_top = 10
+# gui_frame_right = 10
+# gui_frame_bottom = 10
+
+# horizontal and vertical margins between objects
+# gui_hspace = 4
+# gui_vspace = 4
+
+# tab minimum sizes
+gui_tab_header_vsize = 18
+
+# input boxes height
+# minimum height is the height of the position button graphic
+# gui_edit_height = 22
+
+# checkbox height, default sizes come from the checkbox graphic
+# gui_checkbox_width = 10
+# gui_checkbox_height = 10
+
+# sum of the top and bottom margins for divider lines
+# default is twice the size of gui_vspace
+# gui_divider_vsize = 8
+
+# buttons sizes
+gui_button_height = 16
+# for buttons with fixed widths
+gui_button_width = 100
+
+# text margins inside the buttons (left, top, right)
+gui_button_text_offset = 5,1,5
+gui_color_button_text_offset = 5,1,5
+
+# maximum size of tool bars in tools (0 = no limit)
+# if more tools than allowed by height,
+# next and prev arrows for scrolling appears
+toolbar_max_width = 0
+toolbar_max_height = 0
+
+###################################pakstuff###################################
+
+# pak with the images for this theme
+themeimages=silver.pak
diff --git a/simutrans/themes/theme-large.tab b/simutrans/themes/theme-large.tab
index a5df9cbf8ba..7ca8327ca17 100644
--- a/simutrans/themes/theme-large.tab
+++ b/simutrans/themes/theme-large.tab
@@ -80,9 +80,11 @@ gui_color_chart_lines_zero = #005C9E
gui_color_chart_lines_odd = #338FCC
gui_color_chart_lines_even = #005C9E
-gui_color_list_text_selected_focus = #FAFAFA
-gui_color_list_text_selected_nofocus = #FAFAFA
-gui_color_list_background_selected_focus = #72B2DD
+gui_color_list_text_selected_focus = #FAFAFA
+gui_color_list_text_selected_nofocus = #FAFAFA
+gui_color_list_background_even = #B5DBEF
+gui_color_list_background_odd = #DEF3FF
+gui_color_list_background_selected_focus = #72B2DD
gui_color_list_background_selected_nofocus = #72B2DD
gui_color_button_text = #FAFAFA
@@ -129,6 +131,23 @@ gui_chat_window_network_transparency = 25
# if defined, use plain color for chat window in network games
gui_color_chat_window_network_transparency = #D6ECF7
+# Color for table
+gui_color_table_frame = #6392BD
+gui_color_table_background_head_row = #6392BD
+gui_color_table_background_head_selected = #31596B
+gui_color_table_header_border = #52799C
+gui_color_table_cell_border = #8CC3E7
+gui_color_table_background_left_col = #8CC3E7
+gui_color_table_background_data_sum = #ABD3EF
+gui_color_table_background_data = #C6E3F7
+gui_color_table_background = #E7F3FF
+gui_color_table_background_highlight = #DEE5AD
+gui_color_table_background_selected = #73b2de
+gui_color_text_head_row = #FFFFFF
+gui_color_text_left_col = #000000
+gui_color_text_head_selected = #ffffff
+gui_color_text_table_cell_selected = #ffffff
+
##################################size stuff##################################
# force main menu icon size
diff --git a/simutrans/themes/themes.tab b/simutrans/themes/themes.tab
index 3bbd4209f84..c7a12ba19c5 100644
--- a/simutrans/themes/themes.tab
+++ b/simutrans/themes/themes.tab
@@ -52,6 +52,7 @@ remember_window_positions = 1
pressed_button_sinks = 1
################################# Colour settings #################################
+## theme window background color=#adbabd #RGB=(173,186,189)
# color used for the default titlebars
default_window_title_color = #D74700
@@ -83,6 +84,8 @@ gui_color_text_placeholder = #CCCCCC
#gui_color_list_text_selected_focus = #000000
#gui_color_list_text_selected_nofocus = #000000
+gui_color_list_background_even = #BDCBD6
+gui_color_list_background_odd = #D6E3EF
#gui_color_list_background_selected_focus = #000000
#gui_color_list_background_selected_nofocus = #000000
@@ -128,7 +131,7 @@ gui_chat_window_network_transparency = 0
gui_color_chat_window_network_transparency = #D6ECF7
# Extended unique color settings
-gui_color_up_pointing_triangle = #008000
+#gui_color_up_pointing_triangle = #008000
#gui_color_down_pointing_triangle = #FF0000
#gui_color_out_of_production = #
# Recommended brightness: gui_color_text < gui_color_text_weak < gui_color_text_inactive (reversed on dark themes)
@@ -143,7 +146,7 @@ gui_color_table_cell_border = #8c9aad
gui_color_table_background_left_col = #cedbe7
gui_color_table_background_data_sum = #c6d3de
gui_color_table_background_data = #bdcbd6
-gui_color_table_background = #adbac6
+gui_color_table_background = #BDCBD6
gui_color_table_background_highlight= #DEE5AD
gui_color_text_head_row = #ffffff
gui_color_text_left_col = #000000
diff --git a/simversion.h b/simversion.h
index 3bc2ee5cb4b..b837c3cee31 100644
--- a/simversion.h
+++ b/simversion.h
@@ -35,7 +35,7 @@ extern "C" FILE * __cdecl __iob_func(void) { return _iob; }
#define EX_VERSION_MAJOR 14
#define EX_VERSION_MINOR 23
-#define EX_SAVE_MINOR 66
+#define EX_SAVE_MINOR 67
// Do not forget to increment the save game versions in settings_stats.cc when changing this
diff --git a/simworld.cc b/simworld.cc
index 17bac9a66da..3f99f2c4644 100644
--- a/simworld.cc
+++ b/simworld.cc
@@ -645,6 +645,11 @@ void karte_t::destroy()
DBG_MESSAGE("karte_t::destroy()", "world destroyed");
destroying = false;
+
+ for(uint8 i=0; i< simline_t::MAX_LINE_TYPE-1; i++){
+ world_listed_vehicles[i] = 0;
+ }
+
#ifdef MULTI_THREAD
cities_to_process = 0;
terminating_threads = false;
@@ -664,6 +669,19 @@ void karte_t::rem_convoi(convoihandle_t const &cnv)
convoi_array.remove(cnv);
}
+void karte_t::add_listed_vehicle_count(int amount, waytype_t wt)
+{
+ if (wt == invalid_wt) { dbg->warning("karte_t::add_listed_vehicle_count", "Invalid waytype!"); return; }
+
+ world_listed_vehicles[simline_t::waytype_to_linetype(wt)-1]+=amount;
+}
+
+uint32 karte_t::get_listed_vehicle_number(waytype_t wt) const
+{
+ if( wt==invalid_wt ){ dbg->warning("karte_t::get_listed_vehicle_number", "Invalid waytype!"); return 0; }
+
+ return world_listed_vehicles[simline_t::waytype_to_linetype(wt)-1];
+}
void karte_t::add_city(stadt_t *s)
{
@@ -1543,6 +1561,10 @@ DBG_DEBUG("karte_t::init()","built timeline");
pedestrian_t::check_timeline_pedestrians();
+ for (uint8 i = 0; i < simline_t::MAX_LINE_TYPE-1; i++) {
+ world_listed_vehicles[i] = 0;
+ }
+
#ifdef MULTI_THREAD
init_threads();
#else
@@ -3517,7 +3539,7 @@ bool karte_t::change_player_tool(uint8 cmd, uint8 player_nr, uint16 param, bool
return false;
}
if(exec) {
- init_new_player( player_nr, (uint8) param );
+ init_new_player( player_nr, (uint8) param, false );
// activate/deactivate AI immediately
player_t *player = get_player(player_nr);
if (param != player_t::HUMAN && player) {
@@ -8159,7 +8181,7 @@ DBG_MESSAGE("karte_t::save(loadsave_t *file)", "motd filename %s", env_t::server
}
}
- if (file->get_extended_version() >= 15 || (file->get_extended_version() == 14 && file->get_extended_revision() >= 19))
+ if (file->is_version_ex_atleast(14,19))
{
if (file->get_extended_version() == 14 && file->get_extended_revision() < 20)
{
@@ -8169,7 +8191,7 @@ DBG_MESSAGE("karte_t::save(loadsave_t *file)", "motd filename %s", env_t::server
}
}
- if (file->get_extended_version() >= 15 || (file->get_extended_version() == 14 && file->get_extended_revision() >= 20))
+ if (file->is_version_ex_atleast(14,20))
{
file->rdwr_long(weg_t::private_car_routes_currently_reading_element);
}
@@ -8179,7 +8201,7 @@ DBG_MESSAGE("karte_t::save(loadsave_t *file)", "motd filename %s", env_t::server
path_explorer_t::rdwr(file);
}
- if (file->get_extended_version() >= 15 || (file->get_extended_version() == 14 && file->get_extended_revision() >= 35))
+ if (file->is_version_ex_atleast(14,35))
{
uint32 count = cities_awaiting_private_car_route_check.get_count();
file->rdwr_long(count);
@@ -9563,7 +9585,7 @@ DBG_MESSAGE("karte_t::load()", "%d factories loaded", fab_list.get_count());
}
}
- if (file->get_extended_version() >= 15 || (file->get_extended_version() == 14 && file->get_extended_revision() >= 19))
+ if (file->is_version_ex_atleast(14, 19))
{
if (file->get_extended_version() == 14 && file->get_extended_revision() < 20)
{
@@ -9573,7 +9595,7 @@ DBG_MESSAGE("karte_t::load()", "%d factories loaded", fab_list.get_count());
}
}
- if (file->get_extended_version() >= 15 || (file->get_extended_version() == 14 && file->get_extended_revision() >= 20))
+ if (file->is_version_ex_atleast(14, 20))
{
file->rdwr_long(weg_t::private_car_routes_currently_reading_element);
}
@@ -9594,7 +9616,7 @@ DBG_MESSAGE("karte_t::load()", "%d factories loaded", fab_list.get_count());
path_explorer_t::reset_must_refresh_on_loading();
cities_awaiting_private_car_route_check.clear();
- if (file->get_extended_version() >= 15 || (file->get_extended_version() == 14 && file->get_extended_revision() >= 35))
+ if (file->is_version_ex_atleast(14, 35))
{
uint32 count = 0;
file->rdwr_long(count);
@@ -10250,7 +10272,7 @@ koord karte_t::get_closest_coordinate(koord outside_pos)
/* creates a new player with this type */
-const char *karte_t::init_new_player(uint8 new_player_in, uint8 type)
+const char *karte_t::init_new_player(uint8 new_player_in, uint8 type, bool new_world)
{
if( new_player_in>=PLAYER_UNOWNED || get_player(new_player_in)!=NULL ) {
return "Id invalid/already in use!";
@@ -10260,23 +10282,24 @@ const char *karte_t::init_new_player(uint8 new_player_in, uint8 type)
case player_t::EMPTY: break;
case player_t::HUMAN:
players[new_player_in] = new player_t(new_player_in);
- if( env_t::networkmode ){
- buf.printf(translator::translate("%s founded new company %s."), env_t::nickname.c_str(), players[new_player_in]->get_name());
- }
- else{
+ if (!new_world) {
buf.printf(translator::translate("Now %s was founded."), players[new_player_in]->get_name());
+ msg->add_message(buf, koord::invalid, message_t::ai, PLAYER_FLAG | new_player_in, IMG_EMPTY);
}
- msg->add_message(buf, koord::invalid, message_t::ai, PLAYER_FLAG | new_player_in, IMG_EMPTY);
break;
case player_t::AI_GOODS:
players[new_player_in] = new ai_goods_t(new_player_in);
- buf.printf(translator::translate("Now %s was founded. (Operating by Goods-AI)"), players[new_player_in]->get_name());
- msg->add_message(buf, koord::invalid, message_t::ai, PLAYER_FLAG | new_player_in, IMG_EMPTY);
+ if (!new_world) {
+ buf.printf(translator::translate("Now %s was founded. (Operating by Goods-AI)"), players[new_player_in]->get_name());
+ msg->add_message(buf, koord::invalid, message_t::ai, PLAYER_FLAG | new_player_in, IMG_EMPTY);
+ }
break;
case player_t::AI_PASSENGER:
players[new_player_in] = new ai_passenger_t(new_player_in);
- buf.printf(translator::translate("Now %s was founded. (Operating by Passenger-AI)"), players[new_player_in]->get_name());
- msg->add_message(buf, koord::invalid, message_t::ai, PLAYER_FLAG | new_player_in, IMG_EMPTY);
+ if (!new_world) {
+ buf.printf(translator::translate("Now %s was founded. (Operating by Passenger-AI)"), players[new_player_in]->get_name());
+ msg->add_message(buf, koord::invalid, message_t::ai, PLAYER_FLAG | new_player_in, IMG_EMPTY);
+ }
break;
default: return "Unknown AI type!";
}
diff --git a/simworld.h b/simworld.h
index 47ec556b7f9..3b3d2a7d3cd 100644
--- a/simworld.h
+++ b/simworld.h
@@ -361,6 +361,9 @@ class karte_t
*/
vector_tpl convoi_array;
+ // Total number of vehicles currently listed by players
+ uint32 world_listed_vehicles[8/*simline_t::MAX_LINE_TYPE-1*/];
+
/**
* Array containing the factories.
*/
@@ -1158,7 +1161,7 @@ class karte_t
player_t* get_active_player() const { return active_player; }
uint8 get_active_player_nr() const { return active_player_nr; }
void switch_active_player(uint8 nr, bool silent);
- const char *init_new_player( uint8 nr, uint8 type );
+ const char *init_new_player( uint8 nr, uint8 type, bool new_world=true );
void store_player_password_hash( uint8 player_nr, const pwd_hash_t& hash );
const pwd_hash_t& get_player_password_hash( uint8 player_nr ) const { return player_password_hash[player_nr]; }
void clear_player_password_hashes();
@@ -2102,6 +2105,10 @@ class karte_t
void rem_convoi(convoihandle_t const &cnv);
vector_tpl const& convoys() const { return convoi_array; }
+ // To access the world listed vehicle number
+ void add_listed_vehicle_count(int amount, waytype_t wt);
+ uint32 get_listed_vehicle_number(waytype_t wt) const;
+
/**
* To access the cities array.
*/
diff --git a/themes.src/build_themes.sh b/themes.src/build_themes.sh
index 22a5417809e..e9c946fec0e 100755
--- a/themes.src/build_themes.sh
+++ b/themes.src/build_themes.sh
@@ -51,3 +51,16 @@ rm -rf *.pak
mv *.pak ../../simutrans/themes
cp *.tab ../../simutrans/themes
+cd ../silver
+rm -rf *.pak
+../../build/default/makeobj-extended/makeobj-extended pak silver.pak standard.dat
+../../build/default/makeobj-extended/makeobj-extended pak silver-large.pak standard-large.dat
+mv *.pak ../../simutrans/themes
+cp *.tab ../../simutrans/themes
+
+cd ../purple_night
+rm -rf *.pak
+../../build/default/makeobj-extended/makeobj-extended pak purple_night.pak standard.dat
+../../build/default/makeobj-extended/makeobj-extended pak purple_night-large.pak standard-large.dat
+mv *.pak ../../simutrans/themes
+cp *.tab ../../simutrans/themes
diff --git a/themes.src/modern/theme-large.tab b/themes.src/modern/theme-large.tab
index 31068f4439f..7ca8327ca17 100644
--- a/themes.src/modern/theme-large.tab
+++ b/themes.src/modern/theme-large.tab
@@ -80,9 +80,11 @@ gui_color_chart_lines_zero = #005C9E
gui_color_chart_lines_odd = #338FCC
gui_color_chart_lines_even = #005C9E
-gui_color_list_text_selected_focus = #FAFAFA
-gui_color_list_text_selected_nofocus = #FAFAFA
-gui_color_list_background_selected_focus = #72B2DD
+gui_color_list_text_selected_focus = #FAFAFA
+gui_color_list_text_selected_nofocus = #FAFAFA
+gui_color_list_background_even = #B5DBEF
+gui_color_list_background_odd = #DEF3FF
+gui_color_list_background_selected_focus = #72B2DD
gui_color_list_background_selected_nofocus = #72B2DD
gui_color_button_text = #FAFAFA
@@ -130,17 +132,6 @@ gui_chat_window_network_transparency = 25
gui_color_chat_window_network_transparency = #D6ECF7
# Color for table
-gui_color_table_header_border = #52799C
-gui_color_table_frame = #6392BD
-gui_color_table_background_head_row = #6392BD
-gui_color_table_cell_border = #8CC3E7
-gui_color_table_background_left_col = #8CC3E7
-gui_color_table_background_data_sum = #ABD3EF
-gui_color_table_background_data = #C6E3F7
-gui_color_table_background = #E7F3FF
-gui_color_text_head_row = #FFFFFF
-gui_color_text_left_col = #000000
-
gui_color_table_frame = #6392BD
gui_color_table_background_head_row = #6392BD
gui_color_table_background_head_selected = #31596B
diff --git a/themes.src/newstandard/newstandard-large.tab b/themes.src/newstandard/newstandard-large.tab
index 953cc6bdf36..7ca688ebbe9 100644
--- a/themes.src/newstandard/newstandard-large.tab
+++ b/themes.src/newstandard/newstandard-large.tab
@@ -82,6 +82,8 @@ gui_color_obsolete = #0000F8
#gui_color_list_text_selected_focus = #000000
#gui_color_list_text_selected_nofocus = #000000
+gui_color_list_background_even = #BDCBD6
+gui_color_list_background_odd = #D6E3EF
#gui_color_list_background_selected_focus = #000000
#gui_color_list_background_selected_nofocus = #000000
@@ -142,7 +144,7 @@ gui_color_table_cell_border = #8c9aad
gui_color_table_background_left_col = #cedbe7
gui_color_table_background_data_sum = #c6d3de
gui_color_table_background_data = #bdcbd6
-gui_color_table_background = #adbac6
+gui_color_table_background = #BDCBD6
gui_color_table_background_highlight= #DEE5AD
gui_color_text_head_row = #ffffff
gui_color_text_left_col = #000000
diff --git a/themes.src/newstandard/themes.tab b/themes.src/newstandard/themes.tab
index 692c08470c0..c7a12ba19c5 100644
--- a/themes.src/newstandard/themes.tab
+++ b/themes.src/newstandard/themes.tab
@@ -52,6 +52,7 @@ remember_window_positions = 1
pressed_button_sinks = 1
################################# Colour settings #################################
+## theme window background color=#adbabd #RGB=(173,186,189)
# color used for the default titlebars
default_window_title_color = #D74700
@@ -83,6 +84,8 @@ gui_color_text_placeholder = #CCCCCC
#gui_color_list_text_selected_focus = #000000
#gui_color_list_text_selected_nofocus = #000000
+gui_color_list_background_even = #BDCBD6
+gui_color_list_background_odd = #D6E3EF
#gui_color_list_background_selected_focus = #000000
#gui_color_list_background_selected_nofocus = #000000
@@ -143,7 +146,7 @@ gui_color_table_cell_border = #8c9aad
gui_color_table_background_left_col = #cedbe7
gui_color_table_background_data_sum = #c6d3de
gui_color_table_background_data = #bdcbd6
-gui_color_table_background = #adbac6
+gui_color_table_background = #BDCBD6
gui_color_table_background_highlight= #DEE5AD
gui_color_text_head_row = #ffffff
gui_color_text_left_col = #000000
diff --git a/themes.src/purple_night/back.png b/themes.src/purple_night/back.png
new file mode 100644
index 00000000000..ba5f9121b03
Binary files /dev/null and b/themes.src/purple_night/back.png differ
diff --git a/themes.src/purple_night/build.sh b/themes.src/purple_night/build.sh
new file mode 100644
index 00000000000..66205e9b242
--- /dev/null
+++ b/themes.src/purple_night/build.sh
@@ -0,0 +1,6 @@
+rm -rf *.pak
+../../makeobj/makeobj pak purple_night.pak standard.dat
+../../makeobj/makeobj pak purple_night-large.pak standard-large.dat
+mv *.pak ../../../../simutrans/themes
+cp *.tab ../../../../simutrans/themes
+
diff --git a/themes.src/purple_night/button-symbols.png b/themes.src/purple_night/button-symbols.png
new file mode 100644
index 00000000000..ff876e2be91
Binary files /dev/null and b/themes.src/purple_night/button-symbols.png differ
diff --git a/themes.src/purple_night/button.png b/themes.src/purple_night/button.png
new file mode 100644
index 00000000000..5906c55d8a6
Binary files /dev/null and b/themes.src/purple_night/button.png differ
diff --git a/themes.src/purple_night/checkbutton-small.png b/themes.src/purple_night/checkbutton-small.png
new file mode 100644
index 00000000000..3a38208235d
Binary files /dev/null and b/themes.src/purple_night/checkbutton-small.png differ
diff --git a/themes.src/purple_night/checkbutton.png b/themes.src/purple_night/checkbutton.png
new file mode 100644
index 00000000000..c5cf48ef859
Binary files /dev/null and b/themes.src/purple_night/checkbutton.png differ
diff --git a/themes.src/purple_night/divider.png b/themes.src/purple_night/divider.png
new file mode 100644
index 00000000000..7289f05aadd
Binary files /dev/null and b/themes.src/purple_night/divider.png differ
diff --git a/themes.src/purple_night/editfield.png b/themes.src/purple_night/editfield.png
new file mode 100644
index 00000000000..b504a5683f9
Binary files /dev/null and b/themes.src/purple_night/editfield.png differ
diff --git a/themes.src/purple_night/gadget.png b/themes.src/purple_night/gadget.png
new file mode 100644
index 00000000000..fb91cd29ceb
Binary files /dev/null and b/themes.src/purple_night/gadget.png differ
diff --git a/themes.src/purple_night/listbox.png b/themes.src/purple_night/listbox.png
new file mode 100644
index 00000000000..16834cf4bd3
Binary files /dev/null and b/themes.src/purple_night/listbox.png differ
diff --git a/themes.src/purple_night/posbutton-small.png b/themes.src/purple_night/posbutton-small.png
new file mode 100644
index 00000000000..f8ce1c85bcf
Binary files /dev/null and b/themes.src/purple_night/posbutton-small.png differ
diff --git a/themes.src/purple_night/posbutton.png b/themes.src/purple_night/posbutton.png
new file mode 100644
index 00000000000..b3c45f8a629
Binary files /dev/null and b/themes.src/purple_night/posbutton.png differ
diff --git a/themes.src/purple_night/purple_night-large.tab b/themes.src/purple_night/purple_night-large.tab
new file mode 100644
index 00000000000..62b907cf9e3
--- /dev/null
+++ b/themes.src/purple_night/purple_night-large.tab
@@ -0,0 +1,217 @@
+#
+# Simutrans purple night large theme
+#
+# Read the wiki article for better explanation and full parameters list
+# https://wiki.simutrans.com/en_themeDef
+#
+
+# name of the theme (will be shown with file selector)
+name=Purple Night (large size)
+
+# show tooltips (default 1=show)
+show_tooltips = 1
+
+# tooltip background color (+-1 around this index is used), taken from player-color table
+tooltip_background_color = 4
+
+# tooltip text color (240=black, 215=white)
+tooltip_text_color = 240
+
+# delay before showing tooltip in ms (default 500ms)
+tooltip_delay = 500
+
+# duration in ms during tooltip is visible (default 5000ms=5s)
+tooltip_duration = 5000
+
+# windows drop a little shadow (default off)
+# gui_drop_shadows = 1
+
+#################################window stuff#################################
+
+# when moving, you can use windows to snap onto each other seamlessly
+# if you do not like it, set the catch radius to zero
+window_snap_distance = 8
+
+# show the windows close etc. buttons on the right (like Windows)
+# window_buttons_right = 0
+
+# closes windows/toolbar when button clicked a second time (default off=0)
+second_open_closes_win = 0
+
+# restores window position when window is reopening
+# This will be saved, but will be discarded when screen is resized
+remember_window_positions = 1
+
+# there are three different ways to indicate an active window
+
+# first: draw a frame with titlebar color around active window
+# window_frame_active = 0
+
+# second: draw the title with a different brightness (0: dark ... 6: bright)
+front_window_bar_color = 1
+bottom_window_bar_color = 3
+
+# third (best together with 2nd):use different text color for bar
+# some colors are 215-white, 240-black 208-214- all shades of gray
+front_window_text_color = #DDDDDD
+bottom_window_text_color = #C0C0C0
+
+#################################colour stuff#################################
+
+default_window_title_color = #705726
+
+gui_color_text = #C0C0C0
+gui_color_text_highlight = #908010
+gui_color_text_shadow = #00FF00
+gui_color_text_title = #338FCC
+gui_color_text_strong = #E46A0B
+
+########Test########
+gui_color_empty = #868c86
+gui_color_obsolete = #2878ff
+
+gui_color_edit_text = #908010
+gui_color_edit_text_selected = #FAFAFA
+gui_color_edit_text_disabled = #666666
+gui_color_edit_background_selected = #72B2DD
+gui_color_edit_beam = #a89823
+
+gui_color_chart_background = #2e2e40
+gui_color_chart_lines_zero = #005C9E
+gui_color_chart_lines_odd = #68688e
+gui_color_chart_lines_even = #68688e
+
+gui_color_list_text_selected_focus = #C0C0C0
+gui_color_list_text_selected_nofocus = #908010
+gui_color_list_background_selected_focus = #72B2DD
+gui_color_list_background_selected_nofocus = #72B2DD
+
+gui_color_button_text = #C0C0C0
+gui_color_button_text_disabled = #8A8A8A
+gui_color_button_text_selected = #FAFAFA
+
+gui_color_colored_button_text = #201000
+gui_color_colored_button_text_selected = #CCCCCC
+
+gui_color_checkbox_text = #C0C0C0
+gui_color_checkbox_text_disabled = #666666
+
+gui_color_ticker_background = #3c3c52
+gui_color_ticker_divider = #4d4d69
+
+gui_color_statusbar_text = #C0C0C0
+gui_color_statusbar_background = #3c3c52
+gui_color_statusbar_divider = #4d4d69
+
+gui_highlight_color = #68688e
+gui_shadow_color = #000000
+
+gui_color_text_minus = #C07010
+gui_color_text_plus = #70C010
+gui_color_text_unused = #E46A0B
+
+# Color of cursor overlay, which is blended over marked ground tiles
+cursor_overlay_color = #1060F0
+
+# Color loadbar, save game, load game, server...
+gui_color_loadingbar_progress = #6080A0
+gui_color_loadingbar_inner = #303246
+
+# Color player bright
+gui_player_color_dark = 3
+gui_player_color_bright = 7
+gui_titlebar_player_color_background_brightness = 2
+
+# make the chat window transparent in network games
+gui_chat_window_network_transparency = 25
+
+# if defined, use plain color for chat window in network games
+gui_color_chat_window_network_transparency = #D6ECF7
+
+# Transparency color of boost icons (mail, energy, passangers) in factories
+gui_color_image_transparency = #ffffff
+
+# Extended unique color settings
+gui_color_up_pointing_triangle = #00ebff
+#gui_color_down_pointing_triangle = #
+gui_color_out_of_production = #0092a5
+gui_color_text_overcrowding = #d659a5
+# Recommended brightness: gui_color_text < gui_color_text_weak < gui_color_text_inactive (reversed on dark themes)
+gui_color_text_inactive = #63618c
+gui_color_text_weak = #848a8c
+
+#---- Color for table
+gui_color_table_header_border = #5a5973
+#gui_color_table_background_head_row =
+gui_color_table_background_head_selected = #AD9239
+gui_color_table_frame = #63618c
+gui_color_table_background_head_row = #63618c
+gui_color_table_cell_border = #5a5973
+gui_color_table_background_left_col = #5a5973
+gui_color_table_background_data_sum = #52516b
+gui_color_table_background_data = #4a4961
+gui_color_table_background = #424459
+gui_color_table_background_highlight = #737152
+gui_color_table_background_selected = #5A92A5
+gui_color_text_head_row = #FFFFFF
+gui_color_text_left_col = #c6cbce
+#gui_color_text_head_selected = #737152
+gui_color_text_table_cell_selected = #eff3f7
+gui_color_list_background_even = #424459
+gui_color_list_background_odd = #55576c
+
+##################################size stuff##################################
+
+# force main menu icon size
+icon_width = 48
+
+# titlebar height
+gui_titlebar_height = 22
+
+# width of the window elements
+gui_gadget_width = 22
+
+# safe margin around windows
+# gui_frame_left = 10
+# gui_frame_top = 10
+# gui_frame_right = 10
+# gui_frame_bottom = 10
+
+# horizontal and vertical margins between objects
+# gui_hspace = 4
+# gui_vspace = 4
+
+# tab minimum sizes
+gui_tab_header_vsize = 22
+
+# input boxes height
+# minimum height is the height of the position button graphic
+# gui_edit_height = 22
+
+# checkbox height, default sizes come from the checkbox graphic
+# gui_checkbox_width = 10
+# gui_checkbox_height = 10
+
+# sum of the top and bottom margins for divider lines
+# default is twice the size of gui_vspace
+# gui_divider_vsize = 8
+
+# buttons sizes
+gui_button_height = 22
+# for buttons with fixed widths
+gui_button_width = 100
+
+# text margins inside the buttons (left, top, right)
+gui_button_text_offset = 5,2,5
+gui_color_button_text_offset = 5,2,5
+
+# maximum size of tool bars in tools (0 = no limit)
+# if more tools than allowed by height,
+# next and prev arrows for scrolling appears
+toolbar_max_width = 0
+toolbar_max_height = 0
+
+###################################pakstuff###################################
+
+# pak with the images for this theme
+themeimages=purple_night-large.pak
diff --git a/themes.src/purple_night/purple_night.tab b/themes.src/purple_night/purple_night.tab
new file mode 100644
index 00000000000..728f29105ac
--- /dev/null
+++ b/themes.src/purple_night/purple_night.tab
@@ -0,0 +1,217 @@
+#
+# Simutrans purple night theme
+#
+# Read the wiki article for better explanation and full parameters list
+# https://wiki.simutrans.com/en_themeDef
+#
+
+# name of the theme (will be shown with file selector)
+name=Purple Night
+
+# show tooltips (default 1=show)
+show_tooltips = 1
+
+# tooltip background color (+-1 around this index is used), taken from player-color table
+tooltip_background_color = 4
+
+# tooltip text color (240=black, 215=white)
+tooltip_text_color = 240
+
+# delay before showing tooltip in ms (default 500ms)
+tooltip_delay = 500
+
+# duration in ms during tooltip is visible (default 5000ms=5s)
+tooltip_duration = 5000
+
+# windows drop a little shadow (default off)
+# gui_drop_shadows = 1
+
+#################################window stuff#################################
+
+# when moving, you can use windows to snap onto each other seamlessly
+# if you do not like it, set the catch radius to zero
+window_snap_distance = 8
+
+# show the windows close etc. buttons on the right (like Windows)
+# window_buttons_right = 0
+
+# closes windows/toolbar when button clicked a second time (default off=0)
+second_open_closes_win = 0
+
+# restores window position when window is reopening
+# This will be saved, but will be discarded when screen is resized
+remember_window_positions = 1
+
+# there are three different ways to indicate an active window
+
+# first: draw a frame with titlebar color around active window
+# window_frame_active = 0
+
+# second: draw the title with a different brightness (0: dark ... 6: bright)
+front_window_bar_color = 1
+bottom_window_bar_color = 3
+
+# third (best together with 2nd):use different text color for bar
+# some colors are 215-white, 240-black 208-214- all shades of gray
+front_window_text_color = #DDDDDD
+bottom_window_text_color = #B7B7B7
+
+#################################colour stuff#################################
+
+default_window_title_color = #705726
+
+gui_color_text = #D0D0D0
+gui_color_text_highlight = #908010
+gui_color_text_shadow = #00FF00
+gui_color_text_title = #338FCC
+gui_color_text_strong = #E46A0B
+
+########Test########
+gui_color_empty = #868c86
+gui_color_obsolete = #2878ff
+
+gui_color_edit_text = #908010
+gui_color_edit_text_selected = #FAFAFA
+gui_color_edit_text_disabled = #666666
+gui_color_edit_background_selected = #72B2DD
+gui_color_edit_beam = #a89823
+
+gui_color_chart_background = #2e2e40
+gui_color_chart_lines_zero = #005C9E
+gui_color_chart_lines_odd = #68688e
+gui_color_chart_lines_even = #68688e
+
+gui_color_list_text_selected_focus = #B7B7B7
+gui_color_list_text_selected_nofocus = #908010
+gui_color_list_background_selected_focus = #72B2DD
+gui_color_list_background_selected_nofocus = #72B2DD
+
+gui_color_button_text = #C0C0C0
+gui_color_button_text_disabled = #8A8A8A
+gui_color_button_text_selected = #FAFAFA
+
+gui_color_colored_button_text = #201000
+gui_color_colored_button_text_selected = #CCCCCC
+
+gui_color_checkbox_text = #C0C0C0
+gui_color_checkbox_text_disabled = #666666
+
+gui_color_ticker_background = #3c3c52
+gui_color_ticker_divider = #4d4d69
+
+gui_color_statusbar_text = #C0C0C0
+gui_color_statusbar_background = #3c3c52
+gui_color_statusbar_divider = #4d4d69
+
+gui_highlight_color = #68688e
+gui_shadow_color = #000000
+
+gui_color_text_minus = #C07010
+gui_color_text_plus = #70C010
+gui_color_text_unused = #E46A0B
+
+# Color of cursor overlay, which is blended over marked ground tiles
+cursor_overlay_color = #1060F0
+
+# Color loadbar, save game, load game, server...
+gui_color_loadingbar_progress = #6080A0
+gui_color_loadingbar_inner = #303246
+
+# Color player bright
+gui_player_color_dark = 3
+gui_player_color_bright = 7
+gui_titlebar_player_color_background_brightness = 2
+
+# make the chat window transparent in network games
+gui_chat_window_network_transparency = 25
+
+# if defined, use plain color for chat window in network games
+gui_color_chat_window_network_transparency = #D6ECF7
+
+# Transparency color of boost icons (mail, energy, passangers) in factories
+gui_color_image_transparency = #ffffff
+
+# Extended unique color settings
+gui_color_up_pointing_triangle = #00ebff
+#gui_color_down_pointing_triangle = #
+gui_color_out_of_production = #0092a5
+gui_color_text_overcrowding = #d659a5
+# Recommended brightness: gui_color_text < gui_color_text_weak < gui_color_text_inactive (reversed on dark themes)
+gui_color_text_inactive = #63618c
+gui_color_text_weak = #848a8c
+
+#---- Color for table
+gui_color_table_header_border = #5a5973
+#gui_color_table_background_head_row =
+gui_color_table_background_head_selected = #AD9239
+gui_color_table_frame = #63618c
+gui_color_table_background_head_row = #63618c
+gui_color_table_cell_border = #5a5973
+gui_color_table_background_left_col = #5a5973
+gui_color_table_background_data_sum = #52516b
+gui_color_table_background_data = #4a4961
+gui_color_table_background = #424459
+gui_color_table_background_highlight = #737152
+gui_color_table_background_selected = #5A92A5
+gui_color_text_head_row = #FFFFFF
+gui_color_text_left_col = #c6cbce
+#gui_color_text_head_selected = #737152
+gui_color_text_table_cell_selected = #eff3f7
+gui_color_list_background_even = #424459
+gui_color_list_background_odd = #55576c
+
+##################################size stuff##################################
+
+# force main menu icon size
+icon_width = 32
+
+# titlebar height
+gui_titlebar_height = 22
+
+# width of the window elements
+gui_gadget_width = 20
+
+# safe margin around windows
+# gui_frame_left = 10
+# gui_frame_top = 10
+# gui_frame_right = 10
+# gui_frame_bottom = 10
+
+# horizontal and vertical margins between objects
+# gui_hspace = 4
+# gui_vspace = 4
+
+# tab minimum sizes
+gui_tab_header_vsize = 18
+
+# input boxes height
+# minimum height is the height of the position button graphic
+# gui_edit_height = 22
+
+# checkbox height, default sizes come from the checkbox graphic
+# gui_checkbox_width = 10
+# gui_checkbox_height = 10
+
+# sum of the top and bottom margins for divider lines
+# default is twice the size of gui_vspace
+# gui_divider_vsize = 8
+
+# buttons sizes
+gui_button_height = 17
+# for buttons with fixed widths
+gui_button_width = 100
+
+# text margins inside the buttons (left, top, right)
+gui_button_text_offset = 5,1,5
+gui_color_button_text_offset = 5,1,5
+
+# maximum size of tool bars in tools (0 = no limit)
+# if more tools than allowed by height,
+# next and prev arrows for scrolling appears
+toolbar_max_width = 0
+toolbar_max_height = 0
+
+###################################pakstuff###################################
+
+# pak with the images for this theme
+themeimages=purple_night.pak
diff --git a/themes.src/purple_night/scrollbar-small.png b/themes.src/purple_night/scrollbar-small.png
new file mode 100644
index 00000000000..45826725ef7
Binary files /dev/null and b/themes.src/purple_night/scrollbar-small.png differ
diff --git a/themes.src/purple_night/scrollbar.png b/themes.src/purple_night/scrollbar.png
new file mode 100644
index 00000000000..b4e61e99753
Binary files /dev/null and b/themes.src/purple_night/scrollbar.png differ
diff --git a/themes.src/purple_night/standard-large.dat b/themes.src/purple_night/standard-large.dat
new file mode 100644
index 00000000000..bb13645d51d
--- /dev/null
+++ b/themes.src/purple_night/standard-large.dat
@@ -0,0 +1,218 @@
+#
+# Simutrans window skin definitions for themes
+#
+# All image names must start with "> " to have them non zoomable
+#
+# This theme has the scalable standard look
+#
+################################################
+#
+# Button have 3 rows with left middle right images for one state
+#
+# If only top row is there, button will be centered vertically in area if the size does not match.
+# If all nine are there, you can set any size in themes.tab
+#
+--
+Obj=menu
+name=Button
+# normal
+Image[0]=> button.0.0
+Image[1]=> button.0.2
+Image[2]=> button.0.1
+Image[3]=> button.0.3
+Image[4]=> button.0.5
+Image[5]=> button.0.4
+Image[6]=> button.0.6
+Image[7]=> button.0.8
+Image[8]=> button.0.7
+# pressed
+Image[9]=> button.1.0
+Image[10]=> button.1.2
+Image[11]=> button.1.1
+Image[12]=> button.1.3
+Image[13]=> button.1.5
+Image[14]=> button.1.4
+Image[15]=> button.1.6
+Image[16]=> button.1.8
+Image[17]=> button.1.7
+# disabled (will use the unpressed color mask)
+Image[18]=> button.2.0
+Image[19]=> button.2.2
+Image[20]=> button.2.1
+Image[21]=> button.2.3
+Image[22]=> button.2.5
+Image[23]=> button.2.4
+Image[24]=> button.2.6
+Image[25]=> button.2.8
+Image[26]=> button.2.7
+# color mask (will be blended, so it is a good idea to have a bright color for the foreground in this area)
+Image[27]=> button.3.0
+Image[28]=> button.3.2
+Image[29]=> button.3.1
+Image[30]=> button.3.3
+Image[31]=> button.3.5
+Image[32]=> button.3.4
+Image[33]=> button.3.6
+Image[34]=> button.3.8
+Image[35]=> button.3.7
+# If the position of the colored area is different for a pressed button (i.e. protruding knobs)
+# then here can come another nine mask images
+--
+Obj=menu
+name=Roundbutton
+# normal
+Image[0]=> button.0.0
+Image[1]=> button.0.2
+Image[2]=> button.0.1
+Image[3]=> button.0.3
+Image[4]=> button.0.5
+Image[5]=> button.0.4
+Image[6]=> button.0.6
+Image[7]=> button.0.8
+Image[8]=> button.0.7
+# pressed
+Image[9]=> button.1.0
+Image[10]=> button.1.2
+Image[11]=> button.1.1
+Image[12]=> button.1.3
+Image[13]=> button.1.5
+Image[14]=> button.1.4
+Image[15]=> button.1.6
+Image[16]=> button.1.8
+Image[17]=> button.1.7
+# disabled
+Image[18]=> button.2.0
+Image[19]=> button.2.2
+Image[20]=> button.2.1
+Image[21]=> button.2.3
+Image[22]=> button.2.5
+Image[23]=> button.2.4
+Image[24]=> button.2.6
+Image[25]=> button.2.8
+Image[26]=> button.2.7
+--
+Obj=menu
+name=Editfield
+#should be either scalable or at least LINESPACE+2px high
+Image[0]=> editfield.0.0
+Image[1]=> editfield.0.1
+Image[2]=> editfield.0.2
+Image[3]=> editfield.1.0
+Image[4]=> editfield.1.1
+Image[5]=> editfield.1.2
+Image[6]=> editfield.2.0
+Image[7]=> editfield.2.1
+Image[8]=> editfield.2.2
+--
+Obj=menu
+name=Listbox
+#Must be scalable!
+Image[0]=> listbox.0.0
+Image[1]=> listbox.0.1
+Image[2]=> listbox.0.2
+Image[3]=> listbox.1.0
+Image[4]=> listbox.1.1
+Image[5]=> listbox.1.2
+Image[6]=> listbox.2.0
+Image[7]=> listbox.2.1
+Image[8]=> listbox.2.2
+--
+# window background
+Obj=menu
+name=Back
+Image[0]=> back.0.0
+Image[1]=> back.0.1
+Image[2]=> back.0.2
+Image[3]=> back.1.0
+Image[4]=> back.1.1
+Image[5]=> back.1.2
+Image[6]=> back.2.0
+Image[7]=> back.2.1
+Image[8]=> back.2.2
+--
+#################################################################
+#
+# The following control only have one (or three) images, and are not stretchable
+#
+Obj=menu
+name=Checkbutton
+# normal
+Image[0]=> checkbutton.0.0
+# pressed
+Image[1]=> checkbutton.0.1
+# disabled
+Image[2]=> checkbutton.0.2
+--
+Obj=menu
+name=Posbutton
+# normal
+Image[0]=> posbutton.0.0
+# pressed
+Image[1]=> posbutton.0.1
+# disabled
+Image[2]=> posbutton.0.2
+--
+Obj=menu
+name=Scrollbar
+# normal/pressed/disabled left button
+Image[0]=> scrollbar.0.0
+Image[1]=> scrollbar.0.1
+Image[2]=> scrollbar.0.2
+# normal/pressed/disabled right button
+Image[3]=> scrollbar.0.3
+Image[4]=> scrollbar.0.4
+Image[5]=> scrollbar.0.5
+# left/center/right scrollbar background
+Image[6]=-
+Image[7]=> scrollbar.1.6
+Image[8]=-
+# left/center/right scrollbar knob
+Image[9]=> scrollbar.1.0
+Image[10]=> scrollbar.1.2
+Image[11]=> scrollbar.1.1
+# normal/pressed/disabled up button
+Image[12]=> scrollbar.2.0
+Image[13]=> scrollbar.2.1
+Image[14]=> scrollbar.2.2
+# normal/pressed/disabled down button
+Image[15]=> scrollbar.2.3
+Image[16]=> scrollbar.2.4
+Image[17]=> scrollbar.2.5
+# up/center/down scrollbar background
+Image[18]=-
+Image[19]=> scrollbar.3.6
+Image[20]=-
+# up/center/down scrollbar knob
+Image[21]=> scrollbar.3.0
+Image[22]=> scrollbar.3.2
+Image[23]=> scrollbar.3.1
+--
+# window symbols
+Obj=menu
+name=Gadget
+# close
+Image[0]=> gadget.0.0
+# help
+Image[1]=> gadget.0.1
+# minimize
+Image[2]=> gadget.0.2
+# previous
+Image[3]=> gadget.0.3
+# next
+Image[4]=> gadget.0.4
+# unsticky
+Image[5]=> gadget.0.5
+# sticky
+Image[6]=> gadget.0.6
+# resize corner
+Image[7]=> gadget.0.7
+# goto pos
+Image[8]=> gadget.0.8
+--
+# divider line
+Obj=menu
+name=Divider
+Image[0]=-
+Image[1]=> divider.0.0
+Image[2]=-
+--
diff --git a/themes.src/purple_night/standard.dat b/themes.src/purple_night/standard.dat
new file mode 100644
index 00000000000..8f34e4dabba
--- /dev/null
+++ b/themes.src/purple_night/standard.dat
@@ -0,0 +1,310 @@
+#
+# Simutrans window skin definitions for themes
+#
+# All image names must start with "> " to have them non zoomable
+#
+# This theme has the scalable standard look
+#
+################################################
+#
+# Button have 3 rows with left middle right images for one state
+#
+# If only top row is there, button will be centered vertically in area if the size does not match.
+# If all nine are there, you can set any size in themes.tab
+#
+--
+Obj=menu
+name=Button
+# normal
+Image[0]=> button.0.0
+Image[1]=> button.0.2
+Image[2]=> button.0.1
+Image[3]=> button.0.3
+Image[4]=> button.0.5
+Image[5]=> button.0.4
+Image[6]=> button.0.6
+Image[7]=> button.0.8
+Image[8]=> button.0.7
+# pressed
+Image[9]=> button.1.0
+Image[10]=> button.1.2
+Image[11]=> button.1.1
+Image[12]=> button.1.3
+Image[13]=> button.1.5
+Image[14]=> button.1.4
+Image[15]=> button.1.6
+Image[16]=> button.1.8
+Image[17]=> button.1.7
+# disabled (will use the unpressed color mask)
+Image[18]=> button.2.0
+Image[19]=> button.2.2
+Image[20]=> button.2.1
+Image[21]=> button.2.3
+Image[22]=> button.2.5
+Image[23]=> button.2.4
+Image[24]=> button.2.6
+Image[25]=> button.2.8
+Image[26]=> button.2.7
+# color mask (will be blended, so it is a good idea to have a bright color for the foreground in this area)
+Image[27]=> button.3.0
+Image[28]=> button.3.2
+Image[29]=> button.3.1
+Image[30]=> button.3.3
+Image[31]=> button.3.5
+Image[32]=> button.3.4
+Image[33]=> button.3.6
+Image[34]=> button.3.8
+Image[35]=> button.3.7
+# If the position of the colored area is different for a pressed button (i.e. protruding knobs)
+# then here can come another nine mask images
+--
+Obj=menu
+name=Roundbutton
+# normal
+Image[0]=> button.0.0
+Image[1]=> button.0.2
+Image[2]=> button.0.1
+Image[3]=> button.0.3
+Image[4]=> button.0.5
+Image[5]=> button.0.4
+Image[6]=> button.0.6
+Image[7]=> button.0.8
+Image[8]=> button.0.7
+# pressed
+Image[9]=> button.1.0
+Image[10]=> button.1.2
+Image[11]=> button.1.1
+Image[12]=> button.1.3
+Image[13]=> button.1.5
+Image[14]=> button.1.4
+Image[15]=> button.1.6
+Image[16]=> button.1.8
+Image[17]=> button.1.7
+# disabled
+Image[18]=> button.2.0
+Image[19]=> button.2.2
+Image[20]=> button.2.1
+Image[21]=> button.2.3
+Image[22]=> button.2.5
+Image[23]=> button.2.4
+Image[24]=> button.2.6
+Image[25]=> button.2.8
+Image[26]=> button.2.7
+--
+Obj=menu
+name=Editfield
+#should be either scalable or at least LINESPACE+2px high
+Image[0]=> editfield.0.0
+Image[1]=> editfield.0.1
+Image[2]=> editfield.0.2
+Image[3]=> editfield.1.0
+Image[4]=> editfield.1.1
+Image[5]=> editfield.1.2
+Image[6]=> editfield.2.0
+Image[7]=> editfield.2.1
+Image[8]=> editfield.2.2
+--
+Obj=menu
+name=Listbox
+#Must be scalable!
+Image[0]=> listbox.0.0
+Image[1]=> listbox.0.1
+Image[2]=> listbox.0.2
+Image[3]=> listbox.1.0
+Image[4]=> listbox.1.1
+Image[5]=> listbox.1.2
+Image[6]=> listbox.2.0
+Image[7]=> listbox.2.1
+Image[8]=> listbox.2.2
+--
+# window background
+Obj=menu
+name=Back
+Image[0]=> back.0.0
+Image[1]=> back.0.1
+Image[2]=> back.0.2
+Image[3]=> back.1.0
+Image[4]=> back.1.1
+Image[5]=> back.1.2
+Image[6]=> back.2.0
+Image[7]=> back.2.1
+Image[8]=> back.2.2
+--
+#################################################################
+#
+# The following control only have one (or three) images, and are not stretchable
+#
+Obj=menu
+name=Checkbutton
+# normal
+Image[0]=> checkbutton-small.0.0
+# pressed
+Image[1]=> checkbutton-small.0.1
+# disabled
+Image[2]=> checkbutton-small.0.2
+--
+Obj=menu
+name=Posbutton
+# normal
+Image[0]=> posbutton-small.0.0
+# pressed
+Image[1]=> posbutton-small.0.1
+# disabled
+Image[2]=> posbutton-small.0.2
+--
+Obj=menu
+name=Scrollbar
+# normal/pressed/disabled left button
+Image[0]=> scrollbar-small.0.0
+Image[1]=> scrollbar-small.0.1
+Image[2]=> scrollbar-small.0.2
+# normal/pressed/disabled right button
+Image[3]=> scrollbar-small.0.3
+Image[4]=> scrollbar-small.0.4
+Image[5]=> scrollbar-small.0.5
+# left/center/right scrollbar background
+Image[6]=-
+Image[7]=> scrollbar-small.1.6
+Image[8]=-
+# left/center/right scrollbar knob
+Image[9]=> scrollbar-small.1.0
+Image[10]=> scrollbar-small.1.2
+Image[11]=> scrollbar-small.1.1
+# normal/pressed/disabled up button
+Image[12]=> scrollbar-small.2.0
+Image[13]=> scrollbar-small.2.1
+Image[14]=> scrollbar-small.2.2
+# normal/pressed/disabled down button
+Image[15]=> scrollbar-small.2.3
+Image[16]=> scrollbar-small.2.4
+Image[17]=> scrollbar-small.2.5
+# up/center/down scrollbar background
+Image[18]=-
+Image[19]=> scrollbar-small.3.6
+Image[20]=-
+# up/center/down scrollbar knob
+Image[21]=> scrollbar-small.3.0
+Image[22]=> scrollbar-small.3.2
+Image[23]=> scrollbar-small.3.1
+--
+# window symbols
+Obj=menu
+name=Gadget
+# close
+Image[0]=> gadget.0.0
+# help
+Image[1]=> gadget.0.1
+# minimize
+Image[2]=> gadget.0.2
+# previous
+Image[3]=> gadget.0.3
+# next
+Image[4]=> gadget.0.4
+# unsticky
+Image[5]=> gadget.0.5
+# sticky
+Image[6]=> gadget.0.6
+# resize corner
+Image[7]=> gadget.0.7
+# goto pos
+Image[8]=> gadget.0.8
+# unlocked
+Image[9]=> gadget.0.9
+# locked
+Image[10]=> gadget.0.10
+--
+# divider line
+Obj=menu
+name=Divider
+Image[0]=-
+Image[1]=> divider.0.0
+Image[2]=-
+--
+#################################################################
+Obj=menu
+name=Alerts
+copyright=Ranran
+Image[0]=> ../symbols.0.0
+Image[1]=> ../symbols.0.1
+Image[2]=> ../symbols.0.2
+Image[3]=> ../symbols.0.3
+Image[4]=> ../symbols.0.4
+--
+Obj=menu
+name=WaitingTime
+copyright=Ranran
+# for average waiting time at the stop
+Image[0]=> ../symbols.2.0
+-------
+Obj=menu
+name=TravelTime
+copyright=Ranran
+# for display the average travering time to the distination
+Image[0]=> ../symbols.2.1
+-------
+Obj=menu
+name=ServiceFrequency
+copyright=Ranran
+# for display the line service frequency
+Image[0]=> ../symbols.2.2
+-------
+Obj=menu
+name=MissingScheduledSlot
+copyright=Ranran
+# for line missing scheduled slot
+Image[0]=> ../symbols.2.3
+-------
+Obj=menu
+name=OnFoot
+copyright=Ranran
+Image[0]=> ../symbols.2.4
+-------
+Obj=menu
+name=Comfort
+copyright=Ranran
+Image[0]=> ../symbols.6.0
+-------
+Obj=menu
+name=Comfort
+copyright=Ranran
+Image[0]=> ../symbols.6.0
+-------
+Obj=menu
+name=Upgradable
+copyright=Ranran
+# for vehicle which has upgrade target
+Image[0]=> ../symbols.0.5
+Image[1]=> ../symbols.0.6
+-------
+Obj=menu
+name=ReverseArrows
+copyright=Ranran
+# arrows representing the reverse order of the schedule
+Image[0]=> ../symbols.2.5
+Image[1]=> ../symbols.2.6
+-------
+Obj=menu
+name=InputOutput
+copyright=Ranran
+# for industry input/output
+Image[0]=> ../symbols.4.0
+Image[1]=> ../symbols.4.1
+-------
+Obj=menu
+name=InTransit
+copyright=Ranran
+# for goods in transit for industry information
+Image[0]=> ../symbols.4.2
+-------
+#################################################################
+-------
+Obj=menu
+name=Search
+copyright=Ranran
+Image[0]=> ../symbols.6.1
+-------
+Obj=menu
+name=OpenWindow
+copyright=Ranran
+Image[0]=> ../button-../symbols.0.0
+-------
diff --git a/themes.src/purple_night/symbols.png b/themes.src/purple_night/symbols.png
new file mode 100644
index 00000000000..60c84b8066c
Binary files /dev/null and b/themes.src/purple_night/symbols.png differ
diff --git a/themes.src/silver/back.png b/themes.src/silver/back.png
new file mode 100644
index 00000000000..f94a4ab6684
Binary files /dev/null and b/themes.src/silver/back.png differ
diff --git a/themes.src/silver/build.sh b/themes.src/silver/build.sh
new file mode 100644
index 00000000000..9c3d7442e38
--- /dev/null
+++ b/themes.src/silver/build.sh
@@ -0,0 +1,6 @@
+rm -rf *.pak
+../../makeobj/makeobj pak silver.pak standard.dat
+../../makeobj/makeobj pak silver-large.pak standard-large.dat
+mv *.pak ../../../../simutrans/themes
+cp *.tab ../../../../simutrans/themes
+
diff --git a/themes.src/silver/button-symbols.png b/themes.src/silver/button-symbols.png
new file mode 100644
index 00000000000..ff876e2be91
Binary files /dev/null and b/themes.src/silver/button-symbols.png differ
diff --git a/themes.src/silver/button.png b/themes.src/silver/button.png
new file mode 100644
index 00000000000..0b20925c16a
Binary files /dev/null and b/themes.src/silver/button.png differ
diff --git a/themes.src/silver/checkbutton-small.png b/themes.src/silver/checkbutton-small.png
new file mode 100644
index 00000000000..9e1fad1d235
Binary files /dev/null and b/themes.src/silver/checkbutton-small.png differ
diff --git a/themes.src/silver/checkbutton.png b/themes.src/silver/checkbutton.png
new file mode 100644
index 00000000000..a9a19e17fc0
Binary files /dev/null and b/themes.src/silver/checkbutton.png differ
diff --git a/themes.src/silver/divider.png b/themes.src/silver/divider.png
new file mode 100644
index 00000000000..66043622261
Binary files /dev/null and b/themes.src/silver/divider.png differ
diff --git a/themes.src/silver/editfield.png b/themes.src/silver/editfield.png
new file mode 100644
index 00000000000..559346c408c
Binary files /dev/null and b/themes.src/silver/editfield.png differ
diff --git a/themes.src/silver/gadget.png b/themes.src/silver/gadget.png
new file mode 100644
index 00000000000..fb91cd29ceb
Binary files /dev/null and b/themes.src/silver/gadget.png differ
diff --git a/themes.src/silver/listbox.png b/themes.src/silver/listbox.png
new file mode 100644
index 00000000000..bac308abd1b
Binary files /dev/null and b/themes.src/silver/listbox.png differ
diff --git a/themes.src/silver/posbutton-small.png b/themes.src/silver/posbutton-small.png
new file mode 100644
index 00000000000..e25a3424f4f
Binary files /dev/null and b/themes.src/silver/posbutton-small.png differ
diff --git a/themes.src/silver/posbutton.png b/themes.src/silver/posbutton.png
new file mode 100644
index 00000000000..0e4fcfd49ed
Binary files /dev/null and b/themes.src/silver/posbutton.png differ
diff --git a/themes.src/silver/scrollbar-small.png b/themes.src/silver/scrollbar-small.png
new file mode 100644
index 00000000000..1a131d7db79
Binary files /dev/null and b/themes.src/silver/scrollbar-small.png differ
diff --git a/themes.src/silver/scrollbar.png b/themes.src/silver/scrollbar.png
new file mode 100644
index 00000000000..2ae482eedef
Binary files /dev/null and b/themes.src/silver/scrollbar.png differ
diff --git a/themes.src/silver/silver-large.tab b/themes.src/silver/silver-large.tab
new file mode 100644
index 00000000000..27513b7d5d6
--- /dev/null
+++ b/themes.src/silver/silver-large.tab
@@ -0,0 +1,182 @@
+# Simutrans default touch theme
+#
+# Read the wiki article for better explanation and full parameters list
+# https://wiki.simutrans.com/en_themeDef
+#
+# name of the theme (will be shown with file selector)
+name=Silver (large size)
+
+# show tooltips (default 1=show)
+show_tooltips = 1
+
+# tooltip background color (+-1 around this index is used), taken from player-color table
+tooltip_background_color = 4
+
+# tooltip text color (240=black, 215=white)
+tooltip_text_color = 240
+
+# delay before showing tooltip in ms (default 500ms)
+tooltip_delay = 500
+
+# duration in ms during tooltip is visible (default 5000ms=5s)
+tooltip_duration = 5000
+
+# windows drop a little shadow (default off)
+# gui_drop_shadows = 1
+
+#################################window stuff#################################
+
+# when moving, you can use windows to snap onto each other seamlessly
+# if you do not like it, set the catch radius to zero
+window_snap_distance = 8
+
+# show the windows close etc. buttons on the right (like Windows)
+# window_buttons_right = 0
+
+# closes windows/toolbar when button clicked a second time (default off=0)
+second_open_closes_win = 0
+
+# restores window position when window is reopening
+# This will be saved, but will be discarded when screen is resized
+remember_window_positions = 1
+
+# there are three different ways to indicate an active window
+
+# first: draw a frame with titlebar color around active window
+# window_frame_active = 0
+
+# second: draw the title with a different brightness (0: dark ... 6: bright)
+front_window_bar_color = 1
+bottom_window_bar_color = 3
+
+# third (best together with 2nd):use different text color for bar
+# some colors are 215-white, 240-black 208-214- all shades of gray
+front_window_text_color = #FFFFFF
+bottom_window_text_color = #C0C0C0
+
+#################################colour stuff#################################
+
+default_window_title_color = #84939e
+
+# gui_color_text = #000000
+gui_color_text_highlight = #706000
+gui_color_text_shadow = #BDD3DF
+gui_color_text_title = #338FCC
+gui_color_text_strong = #E46A0B
+
+########Test########
+gui_color_empty = #868c86
+gui_color_obsolete = #2878ff
+
+gui_color_edit_text = #000000
+gui_color_edit_text_selected = #FAFAFA
+gui_color_edit_text_disabled = #666666
+gui_color_edit_background_selected = #72B2DD
+gui_color_edit_beam = #000000
+
+gui_color_chart_background = #6f6d60
+gui_color_chart_lines_zero = #005C9E
+gui_color_chart_lines_odd = #373630
+gui_color_chart_lines_even = #373630
+
+gui_color_list_text_selected_focus = #FAFAFA
+gui_color_list_text_selected_nofocus = #FAFAFA
+gui_color_list_background_selected_focus = #72B2DD
+gui_color_list_background_selected_nofocus = #72B2DD
+
+gui_color_button_text = #001020
+gui_color_button_text_disabled = #666666
+gui_color_button_text_selected = #FAFAFA
+
+gui_color_colored_button_text = #FAFAFA
+gui_color_colored_button_text_selected = #FAFAFA
+
+# gui_color_checkbox_text = #000000
+gui_color_checkbox_text_disabled = #666666
+
+gui_color_ticker_background = #D6ECF7
+gui_color_ticker_divider = #6095B8
+
+# gui_color_statusbar_text = #000000
+gui_color_statusbar_background = #b8b8a8
+gui_color_statusbar_divider = #f8fcf0
+
+gui_highlight_color = #FFFFF7
+gui_shadow_color = #72726E
+
+# gui_color_text_minus = #C00000
+# gui_color_text_plus = #000000
+gui_color_text_unused = #555f66
+
+# Color of cursor overlay, which is blended over marked ground tiles
+cursor_overlay_color = #ff0000
+
+# Color loadbar, save game, load game, server...
+gui_color_loadingbar_progress = #76b9e6
+gui_color_loadingbar_inner = #D6ECF7
+
+# Color player brigth
+gui_player_color_dark = 1
+gui_player_color_bright = 3
+
+# make the chat window transparent in network games
+gui_chat_window_network_transparency = 25
+
+# if defined, use plain color for chat window in network games
+gui_color_chat_window_network_transparency = #D6ECF7
+
+##################################size stuff##################################
+
+# force main menu icon size
+icon_width = 48
+
+# titlebar height
+gui_titlebar_height = 22
+
+# width of the window elements
+gui_gadget_width = 22
+
+# safe margin around windows
+# gui_frame_left = 10
+# gui_frame_top = 10
+# gui_frame_right = 10
+# gui_frame_bottom = 10
+
+# horizontal and vertical margins between objects
+# gui_hspace = 4
+# gui_vspace = 4
+
+# tab minimum sizes
+gui_tab_header_vsize = 22
+
+# input boxes height
+# minimum height is the height of the position button graphic
+# gui_edit_height = 22
+
+# checkbox height, default sizes come from the checkbox graphic
+# gui_checkbox_width = 10
+# gui_checkbox_height = 10
+
+# sum of the top and bottom margins for divider lines
+# default is twice the size of gui_vspace
+# gui_divider_vsize = 8
+
+# buttons sizes
+gui_button_height = 22
+# for buttons with fixed widths
+gui_button_width = 100
+
+# text margins inside the buttons (left, top, right)
+gui_button_text_offset = 5,1,5
+gui_color_button_text_offset = 5,1,5
+
+# maximum size of tool bars in tools (0 = no limit)
+# if more tools than allowed by height,
+# next and prev arrows for scrolling appears
+toolbar_max_width = 0
+toolbar_max_height = 0
+
+###################################pakstuff###################################
+
+# pak with the images for this theme
+themeimages=silver-large.pak
diff --git a/themes.src/silver/silver.tab b/themes.src/silver/silver.tab
new file mode 100644
index 00000000000..6d847031976
--- /dev/null
+++ b/themes.src/silver/silver.tab
@@ -0,0 +1,182 @@
+# Simutrans default touch theme
+#
+# Read the wiki article for better explanation and full parameters list
+# https://wiki.simutrans.com/en_themeDef
+#
+# name of the theme (will be shown with file selector)
+name=Silver
+
+# show tooltips (default 1=show)
+show_tooltips = 1
+
+# tooltip background color (+-1 around this index is used), taken from player-color table
+tooltip_background_color = 4
+
+# tooltip text color (240=black, 215=white)
+tooltip_text_color = 240
+
+# delay before showing tooltip in ms (default 500ms)
+tooltip_delay = 500
+
+# duration in ms during tooltip is visible (default 5000ms=5s)
+tooltip_duration = 5000
+
+# windows drop a little shadow (default off)
+# gui_drop_shadows = 1
+
+#################################window stuff#################################
+
+# when moving, you can use windows to snap onto each other seamlessly
+# if you do not like it, set the catch radius to zero
+window_snap_distance = 8
+
+# show the windows close etc. buttons on the right (like Windows)
+# window_buttons_right = 0
+
+# closes windows/toolbar when button clicked a second time (default off=0)
+second_open_closes_win = 0
+
+# restores window position when window is reopening
+# This will be saved, but will be discarded when screen is resized
+remember_window_positions = 1
+
+# there are three different ways to indicate an active window
+
+# first: draw a frame with titlebar color around active window
+# window_frame_active = 0
+
+# second: draw the title with a different brightness (0: dark ... 6: bright)
+front_window_bar_color = 1
+bottom_window_bar_color = 3
+
+# third (best together with 2nd):use different text color for bar
+# some colors are 215-white, 240-black 208-214- all shades of gray
+front_window_text_color = #FFFFFF
+bottom_window_text_color = #C0C0C0
+
+#################################colour stuff#################################
+
+default_window_title_color = #84939e
+
+# gui_color_text = #000000
+gui_color_text_highlight = #706000
+gui_color_text_shadow = #BDD3DF
+gui_color_text_title = #338FCC
+gui_color_text_strong = #E46A0B
+
+########Test########
+gui_color_empty = #868c86
+gui_color_obsolete = #2878ff
+
+gui_color_edit_text = #000000
+gui_color_edit_text_selected = #FAFAFA
+gui_color_edit_text_disabled = #666666
+gui_color_edit_background_selected = #72B2DD
+gui_color_edit_beam = #000000
+
+gui_color_chart_background = #6f6d60
+gui_color_chart_lines_zero = #005C9E
+gui_color_chart_lines_odd = #373630
+gui_color_chart_lines_even = #373630
+
+gui_color_list_text_selected_focus = #FAFAFA
+gui_color_list_text_selected_nofocus = #FAFAFA
+gui_color_list_background_selected_focus = #72B2DD
+gui_color_list_background_selected_nofocus = #72B2DD
+
+gui_color_button_text = #001020
+gui_color_button_text_disabled = #666666
+gui_color_button_text_selected = #FAFAFA
+
+gui_color_colored_button_text = #FAFAFA
+gui_color_colored_button_text_selected = #FAFAFA
+
+# gui_color_checkbox_text = #000000
+gui_color_checkbox_text_disabled = #666666
+
+gui_color_ticker_background = #D6ECF7
+gui_color_ticker_divider = #6095B8
+
+# gui_color_statusbar_text = #000000
+gui_color_statusbar_background = #b8b8a8
+gui_color_statusbar_divider = #f8fcf0
+
+gui_highlight_color = #FFFFF7
+gui_shadow_color = #72726E
+
+# gui_color_text_minus = #C00000
+# gui_color_text_plus = #000000
+gui_color_text_unused = #555f66
+
+# Color of cursor overlay, which is blended over marked ground tiles
+cursor_overlay_color = #ff0000
+
+# Color loadbar, save game, load game, server...
+gui_color_loadingbar_progress = #76b9e6
+gui_color_loadingbar_inner = #D6ECF7
+
+# Color player brigth
+gui_player_color_dark = 1
+gui_player_color_bright = 3
+
+# make the chat window transparent in network games
+gui_chat_window_network_transparency = 25
+
+# if defined, use plain color for chat window in network games
+gui_color_chat_window_network_transparency = #D6ECF7
+
+##################################size stuff##################################
+
+# force main menu icon size
+icon_width = 32
+
+# titlebar height
+gui_titlebar_height = 22
+
+# width of the window elements
+gui_gadget_width = 20
+
+# safe margin around windows
+# gui_frame_left = 10
+# gui_frame_top = 10
+# gui_frame_right = 10
+# gui_frame_bottom = 10
+
+# horizontal and vertical margins between objects
+# gui_hspace = 4
+# gui_vspace = 4
+
+# tab minimum sizes
+gui_tab_header_vsize = 18
+
+# input boxes height
+# minimum height is the height of the position button graphic
+# gui_edit_height = 22
+
+# checkbox height, default sizes come from the checkbox graphic
+# gui_checkbox_width = 10
+# gui_checkbox_height = 10
+
+# sum of the top and bottom margins for divider lines
+# default is twice the size of gui_vspace
+# gui_divider_vsize = 8
+
+# buttons sizes
+gui_button_height = 16
+# for buttons with fixed widths
+gui_button_width = 100
+
+# text margins inside the buttons (left, top, right)
+gui_button_text_offset = 5,1,5
+gui_color_button_text_offset = 5,1,5
+
+# maximum size of tool bars in tools (0 = no limit)
+# if more tools than allowed by height,
+# next and prev arrows for scrolling appears
+toolbar_max_width = 0
+toolbar_max_height = 0
+
+###################################pakstuff###################################
+
+# pak with the images for this theme
+themeimages=silver.pak
diff --git a/themes.src/silver/standard-large.dat b/themes.src/silver/standard-large.dat
new file mode 100644
index 00000000000..bb13645d51d
--- /dev/null
+++ b/themes.src/silver/standard-large.dat
@@ -0,0 +1,218 @@
+#
+# Simutrans window skin definitions for themes
+#
+# All image names must start with "> " to have them non zoomable
+#
+# This theme has the scalable standard look
+#
+################################################
+#
+# Button have 3 rows with left middle right images for one state
+#
+# If only top row is there, button will be centered vertically in area if the size does not match.
+# If all nine are there, you can set any size in themes.tab
+#
+--
+Obj=menu
+name=Button
+# normal
+Image[0]=> button.0.0
+Image[1]=> button.0.2
+Image[2]=> button.0.1
+Image[3]=> button.0.3
+Image[4]=> button.0.5
+Image[5]=> button.0.4
+Image[6]=> button.0.6
+Image[7]=> button.0.8
+Image[8]=> button.0.7
+# pressed
+Image[9]=> button.1.0
+Image[10]=> button.1.2
+Image[11]=> button.1.1
+Image[12]=> button.1.3
+Image[13]=> button.1.5
+Image[14]=> button.1.4
+Image[15]=> button.1.6
+Image[16]=> button.1.8
+Image[17]=> button.1.7
+# disabled (will use the unpressed color mask)
+Image[18]=> button.2.0
+Image[19]=> button.2.2
+Image[20]=> button.2.1
+Image[21]=> button.2.3
+Image[22]=> button.2.5
+Image[23]=> button.2.4
+Image[24]=> button.2.6
+Image[25]=> button.2.8
+Image[26]=> button.2.7
+# color mask (will be blended, so it is a good idea to have a bright color for the foreground in this area)
+Image[27]=> button.3.0
+Image[28]=> button.3.2
+Image[29]=> button.3.1
+Image[30]=> button.3.3
+Image[31]=> button.3.5
+Image[32]=> button.3.4
+Image[33]=> button.3.6
+Image[34]=> button.3.8
+Image[35]=> button.3.7
+# If the position of the colored area is different for a pressed button (i.e. protruding knobs)
+# then here can come another nine mask images
+--
+Obj=menu
+name=Roundbutton
+# normal
+Image[0]=> button.0.0
+Image[1]=> button.0.2
+Image[2]=> button.0.1
+Image[3]=> button.0.3
+Image[4]=> button.0.5
+Image[5]=> button.0.4
+Image[6]=> button.0.6
+Image[7]=> button.0.8
+Image[8]=> button.0.7
+# pressed
+Image[9]=> button.1.0
+Image[10]=> button.1.2
+Image[11]=> button.1.1
+Image[12]=> button.1.3
+Image[13]=> button.1.5
+Image[14]=> button.1.4
+Image[15]=> button.1.6
+Image[16]=> button.1.8
+Image[17]=> button.1.7
+# disabled
+Image[18]=> button.2.0
+Image[19]=> button.2.2
+Image[20]=> button.2.1
+Image[21]=> button.2.3
+Image[22]=> button.2.5
+Image[23]=> button.2.4
+Image[24]=> button.2.6
+Image[25]=> button.2.8
+Image[26]=> button.2.7
+--
+Obj=menu
+name=Editfield
+#should be either scalable or at least LINESPACE+2px high
+Image[0]=> editfield.0.0
+Image[1]=> editfield.0.1
+Image[2]=> editfield.0.2
+Image[3]=> editfield.1.0
+Image[4]=> editfield.1.1
+Image[5]=> editfield.1.2
+Image[6]=> editfield.2.0
+Image[7]=> editfield.2.1
+Image[8]=> editfield.2.2
+--
+Obj=menu
+name=Listbox
+#Must be scalable!
+Image[0]=> listbox.0.0
+Image[1]=> listbox.0.1
+Image[2]=> listbox.0.2
+Image[3]=> listbox.1.0
+Image[4]=> listbox.1.1
+Image[5]=> listbox.1.2
+Image[6]=> listbox.2.0
+Image[7]=> listbox.2.1
+Image[8]=> listbox.2.2
+--
+# window background
+Obj=menu
+name=Back
+Image[0]=> back.0.0
+Image[1]=> back.0.1
+Image[2]=> back.0.2
+Image[3]=> back.1.0
+Image[4]=> back.1.1
+Image[5]=> back.1.2
+Image[6]=> back.2.0
+Image[7]=> back.2.1
+Image[8]=> back.2.2
+--
+#################################################################
+#
+# The following control only have one (or three) images, and are not stretchable
+#
+Obj=menu
+name=Checkbutton
+# normal
+Image[0]=> checkbutton.0.0
+# pressed
+Image[1]=> checkbutton.0.1
+# disabled
+Image[2]=> checkbutton.0.2
+--
+Obj=menu
+name=Posbutton
+# normal
+Image[0]=> posbutton.0.0
+# pressed
+Image[1]=> posbutton.0.1
+# disabled
+Image[2]=> posbutton.0.2
+--
+Obj=menu
+name=Scrollbar
+# normal/pressed/disabled left button
+Image[0]=> scrollbar.0.0
+Image[1]=> scrollbar.0.1
+Image[2]=> scrollbar.0.2
+# normal/pressed/disabled right button
+Image[3]=> scrollbar.0.3
+Image[4]=> scrollbar.0.4
+Image[5]=> scrollbar.0.5
+# left/center/right scrollbar background
+Image[6]=-
+Image[7]=> scrollbar.1.6
+Image[8]=-
+# left/center/right scrollbar knob
+Image[9]=> scrollbar.1.0
+Image[10]=> scrollbar.1.2
+Image[11]=> scrollbar.1.1
+# normal/pressed/disabled up button
+Image[12]=> scrollbar.2.0
+Image[13]=> scrollbar.2.1
+Image[14]=> scrollbar.2.2
+# normal/pressed/disabled down button
+Image[15]=> scrollbar.2.3
+Image[16]=> scrollbar.2.4
+Image[17]=> scrollbar.2.5
+# up/center/down scrollbar background
+Image[18]=-
+Image[19]=> scrollbar.3.6
+Image[20]=-
+# up/center/down scrollbar knob
+Image[21]=> scrollbar.3.0
+Image[22]=> scrollbar.3.2
+Image[23]=> scrollbar.3.1
+--
+# window symbols
+Obj=menu
+name=Gadget
+# close
+Image[0]=> gadget.0.0
+# help
+Image[1]=> gadget.0.1
+# minimize
+Image[2]=> gadget.0.2
+# previous
+Image[3]=> gadget.0.3
+# next
+Image[4]=> gadget.0.4
+# unsticky
+Image[5]=> gadget.0.5
+# sticky
+Image[6]=> gadget.0.6
+# resize corner
+Image[7]=> gadget.0.7
+# goto pos
+Image[8]=> gadget.0.8
+--
+# divider line
+Obj=menu
+name=Divider
+Image[0]=-
+Image[1]=> divider.0.0
+Image[2]=-
+--
diff --git a/themes.src/silver/standard.dat b/themes.src/silver/standard.dat
new file mode 100644
index 00000000000..8f34e4dabba
--- /dev/null
+++ b/themes.src/silver/standard.dat
@@ -0,0 +1,310 @@
+#
+# Simutrans window skin definitions for themes
+#
+# All image names must start with "> " to have them non zoomable
+#
+# This theme has the scalable standard look
+#
+################################################
+#
+# Button have 3 rows with left middle right images for one state
+#
+# If only top row is there, button will be centered vertically in area if the size does not match.
+# If all nine are there, you can set any size in themes.tab
+#
+--
+Obj=menu
+name=Button
+# normal
+Image[0]=> button.0.0
+Image[1]=> button.0.2
+Image[2]=> button.0.1
+Image[3]=> button.0.3
+Image[4]=> button.0.5
+Image[5]=> button.0.4
+Image[6]=> button.0.6
+Image[7]=> button.0.8
+Image[8]=> button.0.7
+# pressed
+Image[9]=> button.1.0
+Image[10]=> button.1.2
+Image[11]=> button.1.1
+Image[12]=> button.1.3
+Image[13]=> button.1.5
+Image[14]=> button.1.4
+Image[15]=> button.1.6
+Image[16]=> button.1.8
+Image[17]=> button.1.7
+# disabled (will use the unpressed color mask)
+Image[18]=> button.2.0
+Image[19]=> button.2.2
+Image[20]=> button.2.1
+Image[21]=> button.2.3
+Image[22]=> button.2.5
+Image[23]=> button.2.4
+Image[24]=> button.2.6
+Image[25]=> button.2.8
+Image[26]=> button.2.7
+# color mask (will be blended, so it is a good idea to have a bright color for the foreground in this area)
+Image[27]=> button.3.0
+Image[28]=> button.3.2
+Image[29]=> button.3.1
+Image[30]=> button.3.3
+Image[31]=> button.3.5
+Image[32]=> button.3.4
+Image[33]=> button.3.6
+Image[34]=> button.3.8
+Image[35]=> button.3.7
+# If the position of the colored area is different for a pressed button (i.e. protruding knobs)
+# then here can come another nine mask images
+--
+Obj=menu
+name=Roundbutton
+# normal
+Image[0]=> button.0.0
+Image[1]=> button.0.2
+Image[2]=> button.0.1
+Image[3]=> button.0.3
+Image[4]=> button.0.5
+Image[5]=> button.0.4
+Image[6]=> button.0.6
+Image[7]=> button.0.8
+Image[8]=> button.0.7
+# pressed
+Image[9]=> button.1.0
+Image[10]=> button.1.2
+Image[11]=> button.1.1
+Image[12]=> button.1.3
+Image[13]=> button.1.5
+Image[14]=> button.1.4
+Image[15]=> button.1.6
+Image[16]=> button.1.8
+Image[17]=> button.1.7
+# disabled
+Image[18]=> button.2.0
+Image[19]=> button.2.2
+Image[20]=> button.2.1
+Image[21]=> button.2.3
+Image[22]=> button.2.5
+Image[23]=> button.2.4
+Image[24]=> button.2.6
+Image[25]=> button.2.8
+Image[26]=> button.2.7
+--
+Obj=menu
+name=Editfield
+#should be either scalable or at least LINESPACE+2px high
+Image[0]=> editfield.0.0
+Image[1]=> editfield.0.1
+Image[2]=> editfield.0.2
+Image[3]=> editfield.1.0
+Image[4]=> editfield.1.1
+Image[5]=> editfield.1.2
+Image[6]=> editfield.2.0
+Image[7]=> editfield.2.1
+Image[8]=> editfield.2.2
+--
+Obj=menu
+name=Listbox
+#Must be scalable!
+Image[0]=> listbox.0.0
+Image[1]=> listbox.0.1
+Image[2]=> listbox.0.2
+Image[3]=> listbox.1.0
+Image[4]=> listbox.1.1
+Image[5]=> listbox.1.2
+Image[6]=> listbox.2.0
+Image[7]=> listbox.2.1
+Image[8]=> listbox.2.2
+--
+# window background
+Obj=menu
+name=Back
+Image[0]=> back.0.0
+Image[1]=> back.0.1
+Image[2]=> back.0.2
+Image[3]=> back.1.0
+Image[4]=> back.1.1
+Image[5]=> back.1.2
+Image[6]=> back.2.0
+Image[7]=> back.2.1
+Image[8]=> back.2.2
+--
+#################################################################
+#
+# The following control only have one (or three) images, and are not stretchable
+#
+Obj=menu
+name=Checkbutton
+# normal
+Image[0]=> checkbutton-small.0.0
+# pressed
+Image[1]=> checkbutton-small.0.1
+# disabled
+Image[2]=> checkbutton-small.0.2
+--
+Obj=menu
+name=Posbutton
+# normal
+Image[0]=> posbutton-small.0.0
+# pressed
+Image[1]=> posbutton-small.0.1
+# disabled
+Image[2]=> posbutton-small.0.2
+--
+Obj=menu
+name=Scrollbar
+# normal/pressed/disabled left button
+Image[0]=> scrollbar-small.0.0
+Image[1]=> scrollbar-small.0.1
+Image[2]=> scrollbar-small.0.2
+# normal/pressed/disabled right button
+Image[3]=> scrollbar-small.0.3
+Image[4]=> scrollbar-small.0.4
+Image[5]=> scrollbar-small.0.5
+# left/center/right scrollbar background
+Image[6]=-
+Image[7]=> scrollbar-small.1.6
+Image[8]=-
+# left/center/right scrollbar knob
+Image[9]=> scrollbar-small.1.0
+Image[10]=> scrollbar-small.1.2
+Image[11]=> scrollbar-small.1.1
+# normal/pressed/disabled up button
+Image[12]=> scrollbar-small.2.0
+Image[13]=> scrollbar-small.2.1
+Image[14]=> scrollbar-small.2.2
+# normal/pressed/disabled down button
+Image[15]=> scrollbar-small.2.3
+Image[16]=> scrollbar-small.2.4
+Image[17]=> scrollbar-small.2.5
+# up/center/down scrollbar background
+Image[18]=-
+Image[19]=> scrollbar-small.3.6
+Image[20]=-
+# up/center/down scrollbar knob
+Image[21]=> scrollbar-small.3.0
+Image[22]=> scrollbar-small.3.2
+Image[23]=> scrollbar-small.3.1
+--
+# window symbols
+Obj=menu
+name=Gadget
+# close
+Image[0]=> gadget.0.0
+# help
+Image[1]=> gadget.0.1
+# minimize
+Image[2]=> gadget.0.2
+# previous
+Image[3]=> gadget.0.3
+# next
+Image[4]=> gadget.0.4
+# unsticky
+Image[5]=> gadget.0.5
+# sticky
+Image[6]=> gadget.0.6
+# resize corner
+Image[7]=> gadget.0.7
+# goto pos
+Image[8]=> gadget.0.8
+# unlocked
+Image[9]=> gadget.0.9
+# locked
+Image[10]=> gadget.0.10
+--
+# divider line
+Obj=menu
+name=Divider
+Image[0]=-
+Image[1]=> divider.0.0
+Image[2]=-
+--
+#################################################################
+Obj=menu
+name=Alerts
+copyright=Ranran
+Image[0]=> ../symbols.0.0
+Image[1]=> ../symbols.0.1
+Image[2]=> ../symbols.0.2
+Image[3]=> ../symbols.0.3
+Image[4]=> ../symbols.0.4
+--
+Obj=menu
+name=WaitingTime
+copyright=Ranran
+# for average waiting time at the stop
+Image[0]=> ../symbols.2.0
+-------
+Obj=menu
+name=TravelTime
+copyright=Ranran
+# for display the average travering time to the distination
+Image[0]=> ../symbols.2.1
+-------
+Obj=menu
+name=ServiceFrequency
+copyright=Ranran
+# for display the line service frequency
+Image[0]=> ../symbols.2.2
+-------
+Obj=menu
+name=MissingScheduledSlot
+copyright=Ranran
+# for line missing scheduled slot
+Image[0]=> ../symbols.2.3
+-------
+Obj=menu
+name=OnFoot
+copyright=Ranran
+Image[0]=> ../symbols.2.4
+-------
+Obj=menu
+name=Comfort
+copyright=Ranran
+Image[0]=> ../symbols.6.0
+-------
+Obj=menu
+name=Comfort
+copyright=Ranran
+Image[0]=> ../symbols.6.0
+-------
+Obj=menu
+name=Upgradable
+copyright=Ranran
+# for vehicle which has upgrade target
+Image[0]=> ../symbols.0.5
+Image[1]=> ../symbols.0.6
+-------
+Obj=menu
+name=ReverseArrows
+copyright=Ranran
+# arrows representing the reverse order of the schedule
+Image[0]=> ../symbols.2.5
+Image[1]=> ../symbols.2.6
+-------
+Obj=menu
+name=InputOutput
+copyright=Ranran
+# for industry input/output
+Image[0]=> ../symbols.4.0
+Image[1]=> ../symbols.4.1
+-------
+Obj=menu
+name=InTransit
+copyright=Ranran
+# for goods in transit for industry information
+Image[0]=> ../symbols.4.2
+-------
+#################################################################
+-------
+Obj=menu
+name=Search
+copyright=Ranran
+Image[0]=> ../symbols.6.1
+-------
+Obj=menu
+name=OpenWindow
+copyright=Ranran
+Image[0]=> ../button-../symbols.0.0
+-------
diff --git a/themes.src/silver/symbols.png b/themes.src/silver/symbols.png
new file mode 100644
index 00000000000..60c84b8066c
Binary files /dev/null and b/themes.src/silver/symbols.png differ