(svn r13189) [NoAI] -Sync: with trunk r13055:13185.
--- a/projects/openttd_vs80.vcproj Mon May 19 14:14:33 2008 +0000
+++ b/projects/openttd_vs80.vcproj Mon May 19 15:13:58 2008 +0000
@@ -1292,6 +1292,10 @@
>
</File>
<File
+ RelativePath=".\..\src\querystring_gui.h"
+ >
+ </File>
+ <File
RelativePath=".\..\src\queue.h"
>
</File>
@@ -1420,6 +1424,10 @@
>
</File>
<File
+ RelativePath=".\..\src\sortlist_type.h"
+ >
+ </File>
+ <File
RelativePath=".\..\src\sound_func.h"
>
</File>
@@ -1452,6 +1460,10 @@
>
</File>
<File
+ RelativePath=".\..\src\statusbar_gui.h"
+ >
+ </File>
+ <File
RelativePath=".\..\src\stdafx.h"
>
</File>
@@ -2212,10 +2224,6 @@
>
</File>
<File
- RelativePath=".\..\src\ai\ai_factory.hpp"
- >
- </File>
- <File
RelativePath=".\..\src\ai\ai_gui.cpp"
>
</File>
@@ -2224,6 +2232,14 @@
>
</File>
<File
+ RelativePath=".\..\src\ai\ai_info.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\..\src\ai\ai_info.hpp"
+ >
+ </File>
+ <File
RelativePath=".\..\src\ai\ai_squirrel.cpp"
>
</File>
--- a/projects/openttd_vs90.vcproj Mon May 19 14:14:33 2008 +0000
+++ b/projects/openttd_vs90.vcproj Mon May 19 15:13:58 2008 +0000
@@ -1289,6 +1289,10 @@
>
</File>
<File
+ RelativePath=".\..\src\querystring_gui.h"
+ >
+ </File>
+ <File
RelativePath=".\..\src\queue.h"
>
</File>
@@ -1417,6 +1421,10 @@
>
</File>
<File
+ RelativePath=".\..\src\sortlist_type.h"
+ >
+ </File>
+ <File
RelativePath=".\..\src\sound_func.h"
>
</File>
@@ -1449,6 +1457,10 @@
>
</File>
<File
+ RelativePath=".\..\src\statusbar_gui.h"
+ >
+ </File>
+ <File
RelativePath=".\..\src\stdafx.h"
>
</File>
@@ -2209,10 +2221,6 @@
>
</File>
<File
- RelativePath=".\..\src\ai\ai_factory.hpp"
- >
- </File>
- <File
RelativePath=".\..\src\ai\ai_gui.cpp"
>
</File>
@@ -2221,6 +2229,14 @@
>
</File>
<File
+ RelativePath=".\..\src\ai\ai_info.cpp"
+ >
+ </File>
+ <File
+ RelativePath=".\..\src\ai\ai_info.hpp"
+ >
+ </File>
+ <File
RelativePath=".\..\src\ai\ai_squirrel.cpp"
>
</File>
--- a/source.list Mon May 19 14:14:33 2008 +0000
+++ b/source.list Mon May 19 15:13:58 2008 +0000
@@ -92,7 +92,7 @@
thread_morphos.cpp
#else
thread_pthread.cpp
- #endif
+ #end
#end
fiber_thread.cpp
#end
@@ -248,6 +248,7 @@
player_func.h
player_gui.h
player_type.h
+querystring_gui.h
queue.h
rail.h
rail_gui.h
@@ -280,6 +281,7 @@
signs_type.h
slope_func.h
slope_type.h
+sortlist_type.h
sound_func.h
sound_type.h
sprite.h
@@ -288,6 +290,7 @@
station_func.h
station_gui.h
station_type.h
+statusbar_gui.h
stdafx.h
string_func.h
string_type.h
--- a/src/ai/ai_gui.cpp Mon May 19 14:14:33 2008 +0000
+++ b/src/ai/ai_gui.cpp Mon May 19 15:13:58 2008 +0000
@@ -55,7 +55,7 @@
static PlayerID ai_debug_player;
int redraw_timer;
- AIDebugWindow(const WindowDesc *desc, void *data, WindowNumber number) : Window(desc, data, number)
+ AIDebugWindow(const WindowDesc *desc, WindowNumber number) : Window(desc, number)
{
/* Disable the players who are not active or not an AI */
for (PlayerID i = PLAYER_FIRST; i < MAX_PLAYERS; i++) {
@@ -74,7 +74,7 @@
virtual void OnPaint()
{
/* Draw standard stuff */
- DrawWindowWidgets(this);
+ this->DrawWidgets();
/* Check if the currently selected player is still active. */
if (ai_debug_player == INVALID_PLAYER || !GetPlayer(ai_debug_player)->is_active) {
@@ -246,8 +246,7 @@
WDP_AUTO, WDP_AUTO, 299, 228, 299, 228,
WC_PERFORMANCE_DETAIL, WC_NONE,
WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET,
- _ai_debug_widgets,
- NULL
+ _ai_debug_widgets
};
void ShowAIDebugWindow()
--- a/src/aircraft_cmd.cpp Mon May 19 14:14:33 2008 +0000
+++ b/src/aircraft_cmd.cpp Mon May 19 15:13:58 2008 +0000
@@ -447,7 +447,7 @@
}
InvalidateWindowData(WC_VEHICLE_DEPOT, v->tile);
- RebuildVehicleLists();
+ InvalidateWindowClassesData(WC_AIRCRAFT_LIST, 0);
InvalidateWindow(WC_COMPANY, v->owner);
if (IsLocalPlayer())
InvalidateAutoreplaceWindow(v->engine_type, v->group_id); //updates the replace Aircraft window
@@ -462,11 +462,10 @@
static void DoDeleteAircraft(Vehicle *v)
{
DeleteWindowById(WC_VEHICLE_VIEW, v->index);
- RebuildVehicleLists();
InvalidateWindow(WC_COMPANY, v->owner);
DeleteDepotHighlightOfVehicle(v);
DeleteVehicleChain(v);
- InvalidateWindowClasses(WC_AIRCRAFT_LIST);
+ InvalidateWindowClassesData(WC_AIRCRAFT_LIST, 0);
}
/** Sell an aircraft.
@@ -657,7 +656,7 @@
v->cargo_subtype = new_subtype;
InvalidateWindow(WC_VEHICLE_DETAILS, v->index);
InvalidateWindow(WC_VEHICLE_DEPOT, v->tile);
- RebuildVehicleLists();
+ InvalidateWindowClassesData(WC_AIRCRAFT_LIST, 0);
}
return cost;
@@ -1404,7 +1403,7 @@
SetDParam(1, st->index);
AddNewsItem(newsitem,
- NM_THIN, NF_VIEWPORT | NF_VEHICLE, NT_ACCIDENT, DNC_NONE,
+ NS_ACCIDENT_VEHICLE,
v->index,
0);
@@ -1449,7 +1448,7 @@
/* show newsitem of celebrating citizens */
AddNewsItem(
STR_A033_CITIZENS_CELEBRATE_FIRST,
- NM_THIN, NF_VIEWPORT | NF_VEHICLE, (v->owner == _local_player) ? NT_ARRIVAL_PLAYER : NT_ARRIVAL_OTHER, DNC_NONE,
+ (v->owner == _local_player) ? NS_ARRIVAL_PLAYER : NS_ARRIVAL_OTHER,
v->index,
0);
}
--- a/src/aircraft_gui.cpp Mon May 19 14:14:33 2008 +0000
+++ b/src/aircraft_gui.cpp Mon May 19 15:13:58 2008 +0000
@@ -13,6 +13,7 @@
#include "vehicle_func.h"
#include "gfx_func.h"
#include "order_func.h"
+#include "window_gui.h"
#include "table/sprites.h"
#include "table/strings.h"
--- a/src/airport_gui.cpp Mon May 19 14:14:33 2008 +0000
+++ b/src/airport_gui.cpp Mon May 19 15:13:58 2008 +0000
@@ -65,53 +65,65 @@
BuildAirClick_Demolish,
};
-static void BuildAirToolbWndProc(Window *w, WindowEvent *e)
-{
- switch (e->event) {
- case WE_PAINT:
- DrawWindowWidgets(w);
- break;
-
- case WE_CLICK:
- if (e->we.click.widget - 3 >= 0)
- _build_air_button_proc[e->we.click.widget - 3](w);
- break;
-
- case WE_KEYPRESS: {
- switch (e->we.keypress.keycode) {
- case '1': BuildAirClick_Airport(w); break;
- case '2': BuildAirClick_Demolish(w); break;
- default: return;
- }
- } break;
+struct BuildAirToolbarWindow : Window {
+ BuildAirToolbarWindow(const WindowDesc *desc, WindowNumber window_number) : Window(desc, window_number)
+ {
+ this->FindWindowPlacementAndResize(desc);
+ if (_patches.link_terraform_toolbar) ShowTerraformToolbar(this);
+ }
- case WE_PLACE_OBJ:
- _place_proc(e->we.place.tile);
- break;
-
- case WE_PLACE_DRAG:
- VpSelectTilesWithMethod(e->we.place.pt.x, e->we.place.pt.y, e->we.place.select_method);
- break;
+ ~BuildAirToolbarWindow()
+ {
+ if (_patches.link_terraform_toolbar) DeleteWindowById(WC_SCEN_LAND_GEN, 0);
+ }
- case WE_PLACE_MOUSEUP:
- if (e->we.place.pt.x != -1 && e->we.place.select_proc == DDSP_DEMOLISH_AREA) {
- GUIPlaceProcDragXY(e);
- }
- break;
-
- case WE_ABORT_PLACE_OBJ:
- w->RaiseButtons();
+ virtual void OnPaint()
+ {
+ this->DrawWidgets();
+ }
- w = FindWindowById(WC_BUILD_STATION, 0);
- if (w != 0)
- WP(w, def_d).close = true;
- break;
+ virtual void OnClick(Point pt, int widget)
+ {
+ if (widget - 3 >= 0) {
+ _build_air_button_proc[widget - 3](this);
+ }
+ }
- case WE_DESTROY:
- if (_patches.link_terraform_toolbar) DeleteWindowById(WC_SCEN_LAND_GEN, 0);
- break;
+
+ virtual EventState OnKeyPress(uint16 key, uint16 keycode)
+ {
+ switch (keycode) {
+ case '1': BuildAirClick_Airport(this); break;
+ case '2': BuildAirClick_Demolish(this); break;
+ default: return ES_NOT_HANDLED;
+ }
+ return ES_HANDLED;
}
-}
+
+ virtual void OnPlaceObject(Point pt, TileIndex tile)
+ {
+ _place_proc(tile);
+ }
+
+ virtual void OnPlaceDrag(ViewportPlaceMethod select_method, ViewportDragDropSelectionProcess select_proc, Point pt)
+ {
+ VpSelectTilesWithMethod(pt.x, pt.y, select_method);
+ }
+
+ virtual void OnPlaceMouseUp(ViewportPlaceMethod select_method, ViewportDragDropSelectionProcess select_proc, Point pt, TileIndex start_tile, TileIndex end_tile)
+ {
+ if (pt.x != -1 && select_proc == DDSP_DEMOLISH_AREA) {
+ GUIPlaceProcDragXY(select_proc, start_tile, end_tile);
+ }
+ }
+
+ virtual void OnPlaceObjectAbort()
+ {
+ this->RaiseButtons();
+
+ delete FindWindowById(WC_BUILD_STATION, 0);
+ }
+};
static const Widget _air_toolbar_widgets[] = {
{ WWT_CLOSEBOX, RESIZE_NONE, 7, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW },
@@ -128,7 +140,6 @@
WC_BUILD_TOOLBAR, WC_NONE,
WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_STICKY_BUTTON,
_air_toolbar_widgets,
- BuildAirToolbWndProc
};
void ShowBuildAirToolbar()
@@ -136,114 +147,107 @@
if (!IsValidPlayer(_current_player)) return;
DeleteWindowByClass(WC_BUILD_TOOLBAR);
- Window *w = AllocateWindowDescFront<Window>(&_air_toolbar_desc, TRANSPORT_AIR);
- if (_patches.link_terraform_toolbar) ShowTerraformToolbar(w);
+ AllocateWindowDescFront<BuildAirToolbarWindow>(&_air_toolbar_desc, TRANSPORT_AIR);
}
-enum {
- BAW_BOTTOMPANEL = 10,
- BAW_SMALL_AIRPORT,
- BAW_CITY_AIRPORT,
- BAW_HELIPORT,
- BAW_METRO_AIRPORT,
- BAW_STR_INTERNATIONAL_AIRPORT,
- BAW_COMMUTER_AIRPORT,
- BAW_HELIDEPOT,
- BAW_STR_INTERCONTINENTAL_AIRPORT,
- BAW_HELISTATION,
- BAW_LAST_AIRPORT = BAW_HELISTATION,
- BAW_AIRPORT_COUNT = BAW_LAST_AIRPORT - BAW_SMALL_AIRPORT + 1,
- BAW_BTN_DONTHILIGHT = BAW_LAST_AIRPORT + 1,
- BAW_BTN_DOHILIGHT,
-};
-
-static void BuildAirportPickerWndProc(Window *w, WindowEvent *e)
-{
- switch (e->event) {
- case WE_CREATE:
- w->SetWidgetLoweredState(BAW_BTN_DONTHILIGHT, !_station_show_coverage);
- w->SetWidgetLoweredState(BAW_BTN_DOHILIGHT, _station_show_coverage);
- w->LowerWidget(_selected_airport_type + BAW_SMALL_AIRPORT);
- break;
-
- case WE_PAINT: {
- int i; // airport enabling loop
- uint32 avail_airports;
- const AirportFTAClass *airport;
-
- if (WP(w, def_d).close) return;
-
- avail_airports = GetValidAirports();
-
- w->RaiseWidget(_selected_airport_type + BAW_SMALL_AIRPORT);
- if (!HasBit(avail_airports, 0) && _selected_airport_type == AT_SMALL) _selected_airport_type = AT_LARGE;
- if (!HasBit(avail_airports, 1) && _selected_airport_type == AT_LARGE) _selected_airport_type = AT_SMALL;
- w->LowerWidget(_selected_airport_type + BAW_SMALL_AIRPORT);
-
- /* 'Country Airport' starts at widget BAW_SMALL_AIRPORT, and if its bit is set, it is
- * available, so take its opposite value to set the disabled state.
- * There are 9 buildable airports
- * XXX TODO : all airports should be held in arrays, with all relevant data.
- * This should be part of newgrf-airports, i suppose
- */
- for (i = 0; i < BAW_AIRPORT_COUNT; i++) w->SetWidgetDisabledState(i + BAW_SMALL_AIRPORT, !HasBit(avail_airports, i));
-
- /* select default the coverage area to 'Off' (16) */
- airport = GetAirport(_selected_airport_type);
- SetTileSelectSize(airport->size_x, airport->size_y);
+class AirportPickerWindow : public PickerWindowBase {
- int rad = _patches.modified_catchment ? airport->catchment : (uint)CA_UNMODIFIED;
-
- if (_station_show_coverage) SetTileSelectBigSize(-rad, -rad, 2 * rad, 2 * rad);
-
- DrawWindowWidgets(w);
- /* strings such as 'Size' and 'Coverage Area' */
- int text_end = DrawStationCoverageAreaText(2, 206, SCT_ALL, rad, false);
- text_end = DrawStationCoverageAreaText(2, text_end + 4, SCT_ALL, rad, true) + 4;
- if (text_end != w->widget[BAW_BOTTOMPANEL].bottom) {
- w->SetDirty();
- ResizeWindowForWidget(w, BAW_BOTTOMPANEL, 0, text_end - w->widget[BAW_BOTTOMPANEL].bottom);
- w->SetDirty();
- }
- break;
- }
+ enum {
+ BAW_BOTTOMPANEL = 10,
+ BAW_SMALL_AIRPORT,
+ BAW_CITY_AIRPORT,
+ BAW_HELIPORT,
+ BAW_METRO_AIRPORT,
+ BAW_STR_INTERNATIONAL_AIRPORT,
+ BAW_COMMUTER_AIRPORT,
+ BAW_HELIDEPOT,
+ BAW_STR_INTERCONTINENTAL_AIRPORT,
+ BAW_HELISTATION,
+ BAW_LAST_AIRPORT = BAW_HELISTATION,
+ BAW_AIRPORT_COUNT = BAW_LAST_AIRPORT - BAW_SMALL_AIRPORT + 1,
+ BAW_BTN_DONTHILIGHT = BAW_LAST_AIRPORT + 1,
+ BAW_BTN_DOHILIGHT,
+ };
- case WE_CLICK: {
- switch (e->we.click.widget) {
- case BAW_SMALL_AIRPORT: case BAW_CITY_AIRPORT: case BAW_HELIPORT: case BAW_METRO_AIRPORT:
- case BAW_STR_INTERNATIONAL_AIRPORT: case BAW_COMMUTER_AIRPORT: case BAW_HELIDEPOT:
- case BAW_STR_INTERCONTINENTAL_AIRPORT: case BAW_HELISTATION:
- w->RaiseWidget(_selected_airport_type + BAW_SMALL_AIRPORT);
- _selected_airport_type = e->we.click.widget - BAW_SMALL_AIRPORT;
- w->LowerWidget(_selected_airport_type + BAW_SMALL_AIRPORT);
- SndPlayFx(SND_15_BEEP);
- w->SetDirty();
- break;
+public:
- case BAW_BTN_DONTHILIGHT: case BAW_BTN_DOHILIGHT:
- _station_show_coverage = (e->we.click.widget != BAW_BTN_DONTHILIGHT);
- w->SetWidgetLoweredState(BAW_BTN_DONTHILIGHT, !_station_show_coverage);
- w->SetWidgetLoweredState(BAW_BTN_DOHILIGHT, _station_show_coverage);
- SndPlayFx(SND_15_BEEP);
- w->SetDirty();
- break;
- }
- } break;
+ AirportPickerWindow(const WindowDesc *desc) : PickerWindowBase(desc)
+ {
+ this->SetWidgetLoweredState(BAW_BTN_DONTHILIGHT, !_station_show_coverage);
+ this->SetWidgetLoweredState(BAW_BTN_DOHILIGHT, _station_show_coverage);
+ this->LowerWidget(_selected_airport_type + BAW_SMALL_AIRPORT);
- case WE_TICK: {
- if (WP(w, def_d).close) {
- delete w;
- return;
- }
+ this->FindWindowPlacementAndResize(desc);
+ }
- CheckRedrawStationCoverage(w);
- } break;
+ virtual void OnPaint()
+ {
+ int i; // airport enabling loop
+ uint32 avail_airports;
+ const AirportFTAClass *airport;
- case WE_DESTROY:
- if (!WP(w, def_d).close) ResetObjectToPlace();
- break;
+ avail_airports = GetValidAirports();
+
+ this->RaiseWidget(_selected_airport_type + BAW_SMALL_AIRPORT);
+ if (!HasBit(avail_airports, 0) && _selected_airport_type == AT_SMALL) _selected_airport_type = AT_LARGE;
+ if (!HasBit(avail_airports, 1) && _selected_airport_type == AT_LARGE) _selected_airport_type = AT_SMALL;
+ this->LowerWidget(_selected_airport_type + BAW_SMALL_AIRPORT);
+
+ /* 'Country Airport' starts at widget BAW_SMALL_AIRPORT, and if its bit is set, it is
+ * available, so take its opposite value to set the disabled state.
+ * There are 9 buildable airports
+ * XXX TODO : all airports should be held in arrays, with all relevant data.
+ * This should be part of newgrf-airports, i suppose
+ */
+ for (i = 0; i < BAW_AIRPORT_COUNT; i++) this->SetWidgetDisabledState(i + BAW_SMALL_AIRPORT, !HasBit(avail_airports, i));
+
+ /* select default the coverage area to 'Off' (16) */
+ airport = GetAirport(_selected_airport_type);
+ SetTileSelectSize(airport->size_x, airport->size_y);
+
+ int rad = _patches.modified_catchment ? airport->catchment : (uint)CA_UNMODIFIED;
+
+ if (_station_show_coverage) SetTileSelectBigSize(-rad, -rad, 2 * rad, 2 * rad);
+
+ this->DrawWidgets();
+ /* strings such as 'Size' and 'Coverage Area' */
+ int text_end = DrawStationCoverageAreaText(2, 206, SCT_ALL, rad, false);
+ text_end = DrawStationCoverageAreaText(2, text_end + 4, SCT_ALL, rad, true) + 4;
+ if (text_end != this->widget[BAW_BOTTOMPANEL].bottom) {
+ this->SetDirty();
+ ResizeWindowForWidget(this, BAW_BOTTOMPANEL, 0, text_end - this->widget[BAW_BOTTOMPANEL].bottom);
+ this->SetDirty();
+ }
}
-}
+
+ virtual void OnClick(Point pt, int widget)
+ {
+ switch (widget) {
+ case BAW_SMALL_AIRPORT: case BAW_CITY_AIRPORT: case BAW_HELIPORT: case BAW_METRO_AIRPORT:
+ case BAW_STR_INTERNATIONAL_AIRPORT: case BAW_COMMUTER_AIRPORT: case BAW_HELIDEPOT:
+ case BAW_STR_INTERCONTINENTAL_AIRPORT: case BAW_HELISTATION:
+ this->RaiseWidget(_selected_airport_type + BAW_SMALL_AIRPORT);
+ _selected_airport_type = widget - BAW_SMALL_AIRPORT;
+ this->LowerWidget(_selected_airport_type + BAW_SMALL_AIRPORT);
+ SndPlayFx(SND_15_BEEP);
+ this->SetDirty();
+ break;
+
+ case BAW_BTN_DONTHILIGHT: case BAW_BTN_DOHILIGHT:
+ _station_show_coverage = (widget != BAW_BTN_DONTHILIGHT);
+ this->SetWidgetLoweredState(BAW_BTN_DONTHILIGHT, !_station_show_coverage);
+ this->SetWidgetLoweredState(BAW_BTN_DOHILIGHT, _station_show_coverage);
+ SndPlayFx(SND_15_BEEP);
+ this->SetDirty();
+ break;
+ }
+ }
+
+ virtual void OnTick()
+ {
+ CheckRedrawStationCoverage(this);
+ }
+};
static const Widget _build_airport_picker_widgets[] = {
{ WWT_CLOSEBOX, RESIZE_NONE, 7, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW},
@@ -277,12 +281,11 @@
WC_BUILD_STATION, WC_BUILD_TOOLBAR,
WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET,
_build_airport_picker_widgets,
- BuildAirportPickerWndProc
};
static void ShowBuildAirportPicker()
{
- new Window(&_build_airport_desc);
+ new AirportPickerWindow(&_build_airport_desc);
}
void InitializeAirportGui()
--- a/src/autoreplace_cmd.cpp Mon May 19 14:14:33 2008 +0000
+++ b/src/autoreplace_cmd.cpp Mon May 19 15:13:58 2008 +0000
@@ -216,7 +216,7 @@
// copy/clone the orders
DoCommand(0, (old_v->index << 16) | new_v->index, old_v->IsOrderListShared() ? CO_SHARE : CO_COPY, DC_EXEC, CMD_CLONE_ORDER);
new_v->cur_order_index = old_v->cur_order_index;
- ChangeVehicleViewWindow(old_v, new_v);
+ ChangeVehicleViewWindow(old_v->index, new_v->index);
new_v->profit_this_year = old_v->profit_this_year;
new_v->profit_last_year = old_v->profit_last_year;
new_v->service_interval = old_v->service_interval;
@@ -323,7 +323,7 @@
if (v == NULL) {
/* We sold all the wagons and the train is still not short enough */
SetDParam(0, front->unitnumber);
- AddNewsItem(STR_TRAIN_TOO_LONG_AFTER_REPLACEMENT, NM_SMALL, NF_VIEWPORT | NF_VEHICLE, NT_ADVICE, DNC_NONE, front->index, 0);
+ AddNewsItem(STR_TRAIN_TOO_LONG_AFTER_REPLACEMENT, NS_ADVICE, front->index, 0);
return cost;
}
@@ -480,7 +480,7 @@
default: NOT_REACHED(); message = 0; break;
}
- AddNewsItem(message, NM_SMALL, NF_VIEWPORT|NF_VEHICLE, NT_ADVICE, DNC_NONE, v->index, 0);
+ AddNewsItem(message, NS_ADVICE, v->index, 0);
}
}
}
--- a/src/autoreplace_gui.cpp Mon May 19 14:14:33 2008 +0000
+++ b/src/autoreplace_gui.cpp Mon May 19 15:13:58 2008 +0000
@@ -21,6 +21,7 @@
#include "widgets/dropdown_func.h"
#include "engine_func.h"
#include "engine_base.h"
+#include "window_gui.h"
#include "table/sprites.h"
#include "table/strings.h"
@@ -249,7 +250,7 @@
}
public:
- ReplaceVehicleWindow(const WindowDesc *desc, VehicleType vehicletype, GroupID id_g) : Window(desc, NULL, window_number)
+ ReplaceVehicleWindow(const WindowDesc *desc, VehicleType vehicletype, GroupID id_g) : Window(desc, vehicletype)
{
this->wagon_btnstate = true; // start with locomotives (all other vehicles will not read this bool)
new (&this->list[0]) EngineList();
@@ -360,7 +361,7 @@
this->widget[RVW_WIDGET_TRAIN_RAILTYPE_DROPDOWN].data = _rail_types_list[sel_railtype];
}
- DrawWindowWidgets(this);
+ this->DrawWidgets();
/* sets up the string for the vehicle that is being replaced to */
if (selected_id[0] != INVALID_ENGINE) {
@@ -532,7 +533,6 @@
WC_REPLACE_VEHICLE, WC_NONE,
WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS | WDF_STICKY_BUTTON | WDF_RESIZABLE,
_replace_vehicle_widgets,
- NULL
};
static const WindowDesc _replace_vehicle_desc = {
@@ -540,7 +540,6 @@
WC_REPLACE_VEHICLE, WC_NONE,
WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS | WDF_STICKY_BUTTON | WDF_RESIZABLE,
_replace_vehicle_widgets,
- NULL
};
RailType ReplaceVehicleWindow::sel_railtype = RAILTYPE_RAIL;
--- a/src/blitter/factory.hpp Mon May 19 14:14:33 2008 +0000
+++ b/src/blitter/factory.hpp Mon May 19 15:13:58 2008 +0000
@@ -56,7 +56,13 @@
name(NULL)
{}
- virtual ~BlitterFactoryBase() { if (this->name != NULL) GetBlitters().erase(this->name); free(this->name); }
+ virtual ~BlitterFactoryBase()
+ {
+ if (this->name == NULL) return;
+ GetBlitters().erase(this->name);
+ if (GetBlitters().empty()) delete &GetBlitters();
+ free(this->name);
+ }
/**
* Find the requested blitter and return his class.
--- a/src/bridge_gui.cpp Mon May 19 14:14:33 2008 +0000
+++ b/src/bridge_gui.cpp Mon May 19 15:13:58 2008 +0000
@@ -17,146 +17,329 @@
#include "viewport_func.h"
#include "gfx_func.h"
#include "tunnelbridge.h"
+#include "sortlist_type.h"
+#include "widgets/dropdown_func.h"
#include "table/strings.h"
-static struct BridgeData {
- uint8 last_size;
- uint count;
- TileIndex start_tile;
- TileIndex end_tile;
- uint32 type; ///< Data type for the bridge. Bit 16,15 = transport type, 14..8 = road/rail pieces, 7..0 = type of bridge
- BridgeType indexes[MAX_BRIDGES];
- Money costs[MAX_BRIDGES];
+/* Save the sorting during runtime */
+static Listing _bridge_sorting = {false, 0};
- BridgeData()
- : last_size(4)
- , count(0)
- {};
-} _bridgedata;
+/**
+ * Carriage for the data we need if we want to build a bridge
+ */
+struct BuildBridgeData {
+ BridgeType index;
+ const BridgeSpec *spec;
+ Money cost;
+};
+typedef GUIList<BuildBridgeData> GUIBridgeList;
+
+/** Sort the bridges by their index */
+static int CDECL BridgeIndexSorter(const void *a, const void *b)
+{
+ const BuildBridgeData* ba = (BuildBridgeData*)a;
+ const BuildBridgeData* bb = (BuildBridgeData*)b;
+ int r = ba->index - bb->index;
+
+ return (_bridge_sorting.order) ? -r : r;
+}
+
+/** Sort the bridges by their price */
+static int CDECL BridgePriceSorter(const void *a, const void *b)
+{
+ const BuildBridgeData* ba = (BuildBridgeData*)a;
+ const BuildBridgeData* bb = (BuildBridgeData*)b;
+ int r = ba->cost - bb->cost;
+
+ return (_bridge_sorting.order) ? -r : r;
+}
+
+/** Sort the bridges by their maximum speed */
+static int CDECL BridgeSpeedSorter(const void *a, const void *b)
+{
+ const BuildBridgeData* ba = (BuildBridgeData*)a;
+ const BuildBridgeData* bb = (BuildBridgeData*)b;
+ int r = ba->spec->speed - bb->spec->speed;
+
+ return (_bridge_sorting.order) ? -r : r;
+}
+
+typedef int CDECL BridgeSortListingTypeFunction(const void*, const void*);
+
+/* Availible bridge sorting functions */
+static BridgeSortListingTypeFunction* const _bridge_sorter[] = {
+ &BridgeIndexSorter,
+ &BridgePriceSorter,
+ &BridgeSpeedSorter
+};
+
+/* Names of the sorting functions */
+static const StringID _bridge_sort_listing[] = {
+ STR_SORT_BY_NUMBER,
+ STR_ENGINE_SORT_COST,
+ STR_SORT_BY_MAX_SPEED,
+ INVALID_STRING_ID
+};
+
+/**
+ * Callback executed after a build Bridge CMD has been called
+ *
+ * @param scucess True if the build succeded
+ * @param tile The tile where the command has been executed
+ * @param p1 not used
+ * @param p2 not used
+ */
void CcBuildBridge(bool success, TileIndex tile, uint32 p1, uint32 p2)
{
if (success) SndPlayTileFx(SND_27_BLACKSMITH_ANVIL, tile);
}
-static void BuildBridge(Window *w, int i)
-{
- delete w;
- DoCommandP(_bridgedata.end_tile, _bridgedata.start_tile,
- _bridgedata.type | _bridgedata.indexes[i], CcBuildBridge,
- CMD_BUILD_BRIDGE | CMD_MSG(STR_5015_CAN_T_BUILD_BRIDGE_HERE));
-}
-
/* Names of the build bridge selection window */
enum BuildBridgeSelectionWidgets {
BBSW_CLOSEBOX = 0,
BBSW_CAPTION,
+ BBSW_DROPDOWN_ORDER,
+ BBSW_DROPDOWN_CRITERIA,
BBSW_BRIDGE_LIST,
BBSW_SCROLLBAR,
BBSW_RESIZEBOX
};
-static void BuildBridgeWndProc(Window *w, WindowEvent *e)
-{
- switch (e->event) {
- case WE_CREATE:
- w->resize.step_height = 22;
- w->vscroll.count = _bridgedata.count;
+class BuildBridgeWindow : public Window {
+private:
+ /* The last size of the build bridge window
+ * is saved during runtime */
+ static uint last_size;
- if (_bridgedata.last_size <= 4) {
- w->vscroll.cap = 4;
- } else {
- /* Resize the bridge selection window if we used a bigger one the last time */
- w->vscroll.cap = (w->vscroll.count > _bridgedata.last_size) ? _bridgedata.last_size : w->vscroll.count;
- ResizeWindow(w, 0, (w->vscroll.cap - 4) * w->resize.step_height);
- w->widget[BBSW_BRIDGE_LIST].data = (w->vscroll.cap << 8) + 1;
- }
- break;
-
- case WE_PAINT: {
- DrawWindowWidgets(w);
+ TileIndex start_tile;
+ TileIndex end_tile;
+ uint32 type;
+ GUIBridgeList *bridges;
- uint y = 15;
- for (uint i = 0; (i < w->vscroll.cap) && ((i + w->vscroll.pos) < _bridgedata.count); i++) {
- const BridgeSpec *b = GetBridgeSpec(_bridgedata.indexes[i + w->vscroll.pos]);
+ void BuildBridge(uint8 i)
+ {
+ DoCommandP(this->end_tile, this->start_tile, this->type | this->bridges->sort_list[i].index,
+ CcBuildBridge, CMD_BUILD_BRIDGE | CMD_MSG(STR_5015_CAN_T_BUILD_BRIDGE_HERE));
+ }
- SetDParam(2, _bridgedata.costs[i + w->vscroll.pos]);
- SetDParam(1, b->speed * 10 / 16);
- SetDParam(0, b->material);
+ /** Sort the builable bridges */
+ void SortBridgeList()
+ {
+ /* Skip sorting if resort bit is not set */
+ if (!(bridges->flags & VL_RESORT)) return;
- DrawSprite(b->sprite, b->pal, 3, y);
- DrawString(44, y, STR_500D, TC_FROMSTRING);
- y += w->resize.step_height;
- }
- break;
+ qsort(this->bridges->sort_list, this->bridges->list_length, sizeof(this->bridges->sort_list[0]), _bridge_sorter[_bridge_sorting.criteria]);
+
+ /* Display the current sort variant */
+ this->widget[BBSW_DROPDOWN_CRITERIA].data = _bridge_sort_listing[this->bridges->sort_type];
+
+ bridges->flags &= ~VL_RESORT;
+
+ /* Set the modified widgets dirty */
+ this->InvalidateWidget(BBSW_DROPDOWN_CRITERIA);
+ this->InvalidateWidget(BBSW_BRIDGE_LIST);
+ }
+
+public:
+ BuildBridgeWindow(const WindowDesc *desc, TileIndex start, TileIndex end, uint32 br_type, GUIBridgeList *bl) : Window(desc),
+ start_tile(start),
+ end_tile(end),
+ type(br_type),
+ bridges(bl)
+ {
+ this->SortBridgeList();
+
+ /* Change the data, or the caption of the gui. Set it to road or rail, accordingly */
+ this->widget[BBSW_CAPTION].data = (GB(this->type, 15, 2) == TRANSPORT_ROAD) ? STR_1803_SELECT_ROAD_BRIDGE : STR_100D_SELECT_RAIL_BRIDGE;
+
+ this->resize.step_height = 22;
+ this->vscroll.count = bl->list_length;
+
+ if (this->last_size <= 4) {
+ this->vscroll.cap = 4;
+ } else {
+ /* Resize the bridge selection window if we used a bigger one the last time */
+ this->vscroll.cap = (this->vscroll.count > this->last_size) ? this->last_size : this->vscroll.count;
+ ResizeWindow(this, 0, (this->vscroll.cap - 4) * this->resize.step_height);
+ this->widget[BBSW_BRIDGE_LIST].data = (this->vscroll.cap << 8) + 1;
}
- case WE_KEYPRESS: {
- const uint8 i = e->we.keypress.keycode - '1';
- if (i < 9 && i < _bridgedata.count) {
- e->we.keypress.cont = false;
- BuildBridge(w, i);
- }
+ this->FindWindowPlacementAndResize(desc);
+ }
- break;
- }
+ ~BuildBridgeWindow()
+ {
+ free(this->bridges->sort_list);
+ delete bridges;
+ }
- case WE_CLICK:
- if (e->we.click.widget == BBSW_BRIDGE_LIST) {
- uint ind = ((int)e->we.click.pt.y - 14) / w->resize.step_height;
- if (ind < w->vscroll.cap) {
- ind += w->vscroll.pos;
- if (ind < _bridgedata.count) {
- BuildBridge(w, ind);
+ virtual void OnPaint()
+ {
+ this->DrawWidgets();
+
+ this->DrawSortButtonState(BBSW_DROPDOWN_ORDER, (this->bridges->flags & VL_DESC) ? SBS_DOWN : SBS_UP);
+
+ uint y = this->widget[BBSW_BRIDGE_LIST].top + 2;
+
+ for (uint i = this->vscroll.pos; (i < (this->vscroll.cap + this->vscroll.pos)) && (i < this->bridges->list_length); i++) {
+ const BridgeSpec *b = this->bridges->sort_list[i].spec;
+
+ SetDParam(2, this->bridges->sort_list[i].cost);
+ SetDParam(1, b->speed * 10 / 16);
+ SetDParam(0, b->material);
+
+ DrawSprite(b->sprite, b->pal, 3, y);
+ DrawString(44, y, STR_500D, TC_FROMSTRING);
+ y += this->resize.step_height;
+
+ }
+ }
+
+ virtual EventState OnKeyPress(uint16 key, uint16 keycode)
+ {
+ const uint8 i = keycode - '1';
+ if (i < 9 && i < this->bridges->list_length) {
+ /* Build the requested bridge */
+ this->BuildBridge(i);
+ delete this;
+ return ES_HANDLED;
+ }
+ return ES_NOT_HANDLED;
+ }
+
+ virtual void OnClick(Point pt, int widget)
+ {
+ switch (widget) {
+ default: break;
+ case BBSW_BRIDGE_LIST: {
+ uint i = ((int)pt.y - this->widget[BBSW_BRIDGE_LIST].top) / this->resize.step_height;
+ if (i < this->vscroll.cap) {
+ i += this->vscroll.pos;
+ if (i < this->bridges->list_length) {
+ this->BuildBridge(i);
+ delete this;
}
}
- }
- break;
+ } break;
- case WE_RESIZE:
- w->vscroll.cap += e->we.sizing.diff.y / (int)w->resize.step_height;
- w->widget[BBSW_BRIDGE_LIST].data = (w->vscroll.cap << 8) + 1;
- SetVScrollCount(w, _bridgedata.count);
+ case BBSW_DROPDOWN_ORDER:
+ /* Revers the sort order */
+ this->bridges->flags ^= VL_DESC;
+ _bridge_sorting.order = !_bridge_sorting.order;
- _bridgedata.last_size = w->vscroll.cap;
- break;
+ this->bridges->flags |= VL_RESORT;
+ this->SortBridgeList();
+ break;
+
+ case BBSW_DROPDOWN_CRITERIA:
+ ShowDropDownMenu(this, _bridge_sort_listing, bridges->sort_type, BBSW_DROPDOWN_CRITERIA, 0, 0);
+ break;
+ }
}
-}
+
+ virtual void OnDropdownSelect(int widget, int index)
+ {
+ if (widget == BBSW_DROPDOWN_CRITERIA && this->bridges->sort_type != index) {
+ this->bridges->sort_type = index;
+ _bridge_sorting.criteria = index;
+
+ this->bridges->flags |= VL_RESORT;
+ this->SortBridgeList();
+ }
+ }
+
+ virtual void OnResize(Point new_size, Point delta)
+ {
+ this->vscroll.cap += delta.y / (int)this->resize.step_height;
+ this->widget[BBSW_BRIDGE_LIST].data = (this->vscroll.cap << 8) + 1;
+ SetVScrollCount(this, this->bridges->list_length);
+
+ this->last_size = this->vscroll.cap;
+ }
+};
+
+/* Set the default size of the Build Bridge Window */
+uint BuildBridgeWindow::last_size = 4;
/* Widget definition for the rail bridge selection window */
static const Widget _build_bridge_widgets[] = {
{ WWT_CLOSEBOX, RESIZE_NONE, 7, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW}, // BBSW_CLOSEBOX
{ WWT_CAPTION, RESIZE_NONE, 7, 11, 199, 0, 13, STR_100D_SELECT_RAIL_BRIDGE, STR_018C_WINDOW_TITLE_DRAG_THIS}, // BBSW_CAPTION
-{ WWT_MATRIX, RESIZE_BOTTOM, 7, 0, 187, 14, 101, 0x401, STR_101F_BRIDGE_SELECTION_CLICK}, // BBSW_BRIDGE_LIST
-{ WWT_SCROLLBAR, RESIZE_BOTTOM, 7, 188, 199, 14, 89, 0x0, STR_0190_SCROLL_BAR_SCROLLS_LIST}, // BBSW_SCROLLBAR
-{ WWT_RESIZEBOX, RESIZE_TB, 7, 188, 199, 90, 101, 0x0, STR_RESIZE_BUTTON}, // BBSW_RESIZEBOX
+
+{ WWT_TEXTBTN, RESIZE_NONE, 7, 0, 80, 14, 25, STR_SORT_BY, STR_SORT_ORDER_TIP}, // BBSW_DROPDOWN_ORDER
+{ WWT_DROPDOWN, RESIZE_NONE, 7, 81, 199, 14, 25, 0x0, STR_SORT_CRITERIA_TIP}, // BBSW_DROPDOWN_CRITERIA
+
+{ WWT_MATRIX, RESIZE_BOTTOM, 7, 0, 187, 26, 113, 0x401, STR_101F_BRIDGE_SELECTION_CLICK}, // BBSW_BRIDGE_LIST
+{ WWT_SCROLLBAR, RESIZE_BOTTOM, 7, 188, 199, 26, 101, 0x0, STR_0190_SCROLL_BAR_SCROLLS_LIST}, // BBSW_SCROLLBAR
+{ WWT_RESIZEBOX, RESIZE_TB, 7, 188, 199, 102, 113, 0x0, STR_RESIZE_BUTTON}, // BBSW_RESIZEBOX
{ WIDGETS_END},
};
/* Window definition for the rail bridge selection window */
static const WindowDesc _build_bridge_desc = {
- WDP_AUTO, WDP_AUTO, 200, 102, 200, 102,
+ WDP_AUTO, WDP_AUTO, 200, 114, 200, 114,
WC_BUILD_BRIDGE, WC_BUILD_TOOLBAR,
WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_RESIZABLE,
_build_bridge_widgets,
- BuildBridgeWndProc
};
+/**
+ * Add a buildable bridge to the list.
+ * If the list is empty a new one is created.
+ *
+ * @param bl The list which we want to manage
+ * @param item The item to add
+ * @return The pointer to the list
+ */
+static GUIBridgeList *PushBridgeList(GUIBridgeList *bl, BuildBridgeData item)
+{
+ if (bl == NULL) {
+ /* Create the list if needed */
+ bl = new GUIBridgeList();
+ bl->flags |= VL_RESORT;
+ if (_bridge_sorting.order) bl->flags |= VL_DESC;
+ bl->list_length = 1;
+ bl->sort_type = _bridge_sorting.criteria;
+ } else {
+ /* Resize the list */
+ bl->list_length++;
+ }
+
+ bl->sort_list = ReallocT(bl->sort_list, bl->list_length);
+
+ bl->sort_list[bl->list_length - 1] = item;
+
+ return bl;
+}
+
+/**
+ * Prepare the data for the build a bridge window.
+ * If we can't build a bridge under the given conditions
+ * show an error message.
+ *
+ * @parma start The start tile of the bridge
+ * @param end The end tile of the bridge
+ * @param transport_type The transport type
+ * @param bridge_type The bridge type
+ */
void ShowBuildBridgeWindow(TileIndex start, TileIndex end, TransportType transport_type, byte bridge_type)
{
DeleteWindowById(WC_BUILD_BRIDGE, 0);
- _bridgedata.type = (transport_type << 15) | (bridge_type << 8); //prepare the parameter for use only once
- _bridgedata.start_tile = start;
- _bridgedata.end_tile = end;
+ /* Data type for the bridge.
+ * Bit 16,15 = transport type,
+ * 14..8 = road/rail pieces,
+ * 7..0 = type of bridge */
+ uint32 type = (transport_type << 15) | (bridge_type << 8);
/* only query bridge building possibility once, result is the same for all bridges!
* returns CMD_ERROR on failure, and price on success */
StringID errmsg = INVALID_STRING_ID;
- CommandCost ret = DoCommand(end, start, _bridgedata.type, DC_AUTO | DC_QUERY_COST, CMD_BUILD_BRIDGE);
+ CommandCost ret = DoCommand(end, start, type, DC_AUTO | DC_QUERY_COST, CMD_BUILD_BRIDGE);
- uint8 j = 0;
+ GUIBridgeList *bl = NULL;
if (CmdFailed(ret)) {
errmsg = _error_message;
} else {
@@ -171,22 +354,19 @@
for (BridgeType brd_type = 0; brd_type != MAX_BRIDGES; brd_type++) {
if (CheckBridge_Stuff(brd_type, bridge_len)) {
/* bridge is accepted, add to list */
- const BridgeSpec *b = GetBridgeSpec(brd_type);
+ BuildBridgeData item;
+ item.index = brd_type;
+ item.spec = GetBridgeSpec(brd_type);
/* Add to terraforming & bulldozing costs the cost of the
* bridge itself (not computed with DC_QUERY_COST) */
- _bridgedata.costs[j] = ret.GetCost() + (((int64)tot_bridgedata_len * _price.build_bridge * b->price) >> 8);
- _bridgedata.indexes[j] = brd_type;
- j++;
+ item.cost = ret.GetCost() + (((int64)tot_bridgedata_len * _price.build_bridge * item.spec->price) >> 8);
+ bl = PushBridgeList(bl, item);
}
}
-
- _bridgedata.count = j;
}
- if (j != 0) {
- Window *w = new Window(&_build_bridge_desc);
- /* Change the data, or the caption of the gui. Set it to road or rail, accordingly */
- w->widget[BBSW_CAPTION].data = (transport_type == TRANSPORT_ROAD) ? STR_1803_SELECT_ROAD_BRIDGE : STR_100D_SELECT_RAIL_BRIDGE;
+ if (bl != NULL) {
+ new BuildBridgeWindow(&_build_bridge_desc, start, end, type, bl);
} else {
ShowErrorMessage(errmsg, STR_5015_CAN_T_BUILD_BRIDGE_HERE, TileX(end) * TILE_SIZE, TileY(end) * TILE_SIZE);
}
--- a/src/build_vehicle_gui.cpp Mon May 19 14:14:33 2008 +0000
+++ b/src/build_vehicle_gui.cpp Mon May 19 15:13:58 2008 +0000
@@ -28,27 +28,11 @@
#include "gfx_func.h"
#include "widgets/dropdown_func.h"
#include "string_func.h"
+#include "window_gui.h"
#include "table/sprites.h"
#include "table/strings.h"
-struct buildvehicle_d {
- VehicleType vehicle_type;
- union {
- RailTypeByte railtype;
- AirportFTAClass::Flags flags;
- RoadTypes roadtypes;
- } filter;
- byte sel_index; ///< deprecated value, used for 'unified' ship and road
- bool descending_sort_order;
- byte sort_criteria;
- bool regenerate_list;
- EngineID sel_engine;
- EngineID rename_engine;
- EngineList eng_list;
-};
-assert_compile(WINDOW_CUSTOM_SIZE >= sizeof(buildvehicle_d));
-
enum BuildVehicleWidgets {
BUILD_VEHICLE_WIDGET_CLOSEBOX = 0,
BUILD_VEHICLE_WIDGET_CAPTION,
@@ -78,52 +62,7 @@
{ WIDGETS_END},
};
-/* Setup widget strings to fit the different types of vehicles */
-static void SetupWindowStrings(Window *w, VehicleType type)
-{
- switch (type) {
- default: NOT_REACHED();
-
- case VEH_TRAIN:
- w->widget[BUILD_VEHICLE_WIDGET_CAPTION].data = STR_JUST_STRING;
- w->widget[BUILD_VEHICLE_WIDGET_LIST].tooltips = STR_8843_TRAIN_VEHICLE_SELECTION;
- w->widget[BUILD_VEHICLE_WIDGET_BUILD].data = STR_881F_BUILD_VEHICLE;
- w->widget[BUILD_VEHICLE_WIDGET_BUILD].tooltips = STR_8844_BUILD_THE_HIGHLIGHTED_TRAIN;
- w->widget[BUILD_VEHICLE_WIDGET_RENAME].data = STR_8820_RENAME;
- w->widget[BUILD_VEHICLE_WIDGET_RENAME].tooltips = STR_8845_RENAME_TRAIN_VEHICLE_TYPE;
- break;
-
- case VEH_ROAD:
- w->widget[BUILD_VEHICLE_WIDGET_CAPTION].data = STR_9006_NEW_ROAD_VEHICLES;
- w->widget[BUILD_VEHICLE_WIDGET_LIST].tooltips = STR_9026_ROAD_VEHICLE_SELECTION;
- w->widget[BUILD_VEHICLE_WIDGET_BUILD].data = STR_9007_BUILD_VEHICLE;
- w->widget[BUILD_VEHICLE_WIDGET_BUILD].tooltips = STR_9027_BUILD_THE_HIGHLIGHTED_ROAD;
- w->widget[BUILD_VEHICLE_WIDGET_RENAME].data = STR_9034_RENAME;
- w->widget[BUILD_VEHICLE_WIDGET_RENAME].tooltips = STR_9035_RENAME_ROAD_VEHICLE_TYPE;
- break;
-
- case VEH_SHIP:
- w->widget[BUILD_VEHICLE_WIDGET_CAPTION].data = STR_9808_NEW_SHIPS;
- w->widget[BUILD_VEHICLE_WIDGET_LIST].tooltips = STR_9825_SHIP_SELECTION_LIST_CLICK;
- w->widget[BUILD_VEHICLE_WIDGET_BUILD].data = STR_9809_BUILD_SHIP;
- w->widget[BUILD_VEHICLE_WIDGET_BUILD].tooltips = STR_9826_BUILD_THE_HIGHLIGHTED_SHIP;
- w->widget[BUILD_VEHICLE_WIDGET_RENAME].data = STR_9836_RENAME;
- w->widget[BUILD_VEHICLE_WIDGET_RENAME].tooltips = STR_9837_RENAME_SHIP_TYPE;
- break;
-
- case VEH_AIRCRAFT:
- w->widget[BUILD_VEHICLE_WIDGET_CAPTION].data = STR_A005_NEW_AIRCRAFT;
- w->widget[BUILD_VEHICLE_WIDGET_LIST].tooltips = STR_A025_AIRCRAFT_SELECTION_LIST;
- w->widget[BUILD_VEHICLE_WIDGET_BUILD].data = STR_A006_BUILD_AIRCRAFT;
- w->widget[BUILD_VEHICLE_WIDGET_BUILD].tooltips = STR_A026_BUILD_THE_HIGHLIGHTED_AIRCRAFT;
- w->widget[BUILD_VEHICLE_WIDGET_RENAME].data = STR_A037_RENAME;
- w->widget[BUILD_VEHICLE_WIDGET_RENAME].tooltips = STR_A038_RENAME_AIRCRAFT_TYPE;
- break;
- }
-}
-
static bool _internal_sort_order; // descending/ascending
-
static byte _last_sort_criteria[] = {0, 0, 0, 0};
static bool _last_sort_order[] = {false, false, false, false};
@@ -216,8 +155,8 @@
const RailVehicleInfo *rvi_a = RailVehInfo(*(const EngineID*)a);
const RailVehicleInfo *rvi_b = RailVehInfo(*(const EngineID*)b);
- int va = rvi_a->power << (rvi_a->railveh_type == RAILVEH_MULTIHEAD ? 1 : 0);
- int vb = rvi_b->power << (rvi_b->railveh_type == RAILVEH_MULTIHEAD ? 1 : 0);
+ int va = rvi_a->power;
+ int vb = rvi_b->power;
int r = va - vb;
return _internal_sort_order ? -r : r;
@@ -600,7 +539,7 @@
/* Max speed - Engine power */
SetDParam(0, GetEngineProperty(engine_number, 0x09, rvi->max_speed) * 10 / 16);
- SetDParam(1, GetEngineProperty(engine_number, 0x0B, rvi->power) << multihead);
+ SetDParam(1, GetEngineProperty(engine_number, 0x0B, rvi->power));
DrawString(x, y, STR_PURCHASE_INFO_SPEED_POWER, TC_FROMSTRING);
y += 10;
@@ -613,7 +552,7 @@
/* Running cost */
if (rvi->running_cost_class != 0xFF) {
- SetDParam(0, (GetEngineProperty(engine_number, 0x0D, rvi->running_cost) * GetPriceByIndex(rvi->running_cost_class) >> 8) << multihead);
+ SetDParam(0, GetEngineProperty(engine_number, 0x0D, rvi->running_cost) * GetPriceByIndex(rvi->running_cost_class) >> 8);
DrawString(x, y, STR_PURCHASE_INFO_RUNNINGCOST, TC_FROMSTRING);
y += 10;
}
@@ -785,143 +724,6 @@
return y;
}
-/* Figure out what train EngineIDs to put in the list */
-static void GenerateBuildTrainList(Window *w)
-{
- EngineID sel_id = INVALID_ENGINE;
- int num_engines = 0;
- int num_wagons = 0;
- buildvehicle_d *bv = &WP(w, buildvehicle_d);
-
- bv->filter.railtype = (w->window_number <= VEH_END) ? RAILTYPE_END : GetRailType(w->window_number);
-
- bv->eng_list.clear();
-
- /* Make list of all available train engines and wagons.
- * Also check to see if the previously selected engine is still available,
- * and if not, reset selection to INVALID_ENGINE. This could be the case
- * when engines become obsolete and are removed */
- const Engine *e;
- FOR_ALL_ENGINES_OF_TYPE(e, VEH_TRAIN) {
- EngineID eid = e->index;
- const RailVehicleInfo *rvi = &e->u.rail;
-
- if (bv->filter.railtype != RAILTYPE_END && !HasPowerOnRail(rvi->railtype, bv->filter.railtype)) continue;
- if (!IsEngineBuildable(eid, VEH_TRAIN, _local_player)) continue;
-
- bv->eng_list.push_back(eid);
- if (rvi->railveh_type != RAILVEH_WAGON) {
- num_engines++;
- } else {
- num_wagons++;
- }
-
- if (eid == bv->sel_engine) sel_id = eid;
- }
-
- bv->sel_engine = sel_id;
-
- /* make engines first, and then wagons, sorted by ListPositionOfEngine() */
- _internal_sort_order = false;
- EngList_Sort(&bv->eng_list, TrainEnginesThenWagonsSorter);
-
- /* and then sort engines */
- _internal_sort_order = bv->descending_sort_order;
- EngList_SortPartial(&bv->eng_list, _sorter[0][bv->sort_criteria], 0, num_engines);
-
- /* and finally sort wagons */
- EngList_SortPartial(&bv->eng_list, _sorter[0][bv->sort_criteria], num_engines, num_wagons);
-}
-
-/* Figure out what road vehicle EngineIDs to put in the list */
-static void GenerateBuildRoadVehList(Window *w)
-{
- EngineID sel_id = INVALID_ENGINE;
- buildvehicle_d *bv = &WP(w, buildvehicle_d);
-
- bv->eng_list.clear();
-
- const Engine *e;
- FOR_ALL_ENGINES_OF_TYPE(e, VEH_ROAD) {
- EngineID eid = e->index;
- if (!IsEngineBuildable(eid, VEH_ROAD, _local_player)) continue;
- if (!HasBit(bv->filter.roadtypes, HasBit(EngInfo(eid)->misc_flags, EF_ROAD_TRAM) ? ROADTYPE_TRAM : ROADTYPE_ROAD)) continue;
- bv->eng_list.push_back(eid);
-
- if (eid == bv->sel_engine) sel_id = eid;
- }
- bv->sel_engine = sel_id;
-}
-
-/* Figure out what ship EngineIDs to put in the list */
-static void GenerateBuildShipList(Window *w)
-{
- EngineID sel_id = INVALID_ENGINE;
- buildvehicle_d *bv = &WP(w, buildvehicle_d);
-
- bv->eng_list.clear();
-
- const Engine *e;
- FOR_ALL_ENGINES_OF_TYPE(e, VEH_SHIP) {
- EngineID eid = e->index;
- if (!IsEngineBuildable(eid, VEH_SHIP, _local_player)) continue;
- bv->eng_list.push_back(eid);
-
- if (eid == bv->sel_engine) sel_id = eid;
- }
- bv->sel_engine = sel_id;
-}
-
-/* Figure out what aircraft EngineIDs to put in the list */
-static void GenerateBuildAircraftList(Window *w)
-{
- EngineID sel_id = INVALID_ENGINE;
- buildvehicle_d *bv = &WP(w, buildvehicle_d);
-
- bv->eng_list.clear();
-
- /* Make list of all available planes.
- * Also check to see if the previously selected plane is still available,
- * and if not, reset selection to INVALID_ENGINE. This could be the case
- * when planes become obsolete and are removed */
- const Engine *e;
- FOR_ALL_ENGINES_OF_TYPE(e, VEH_AIRCRAFT) {
- EngineID eid = e->index;
- if (!IsEngineBuildable(eid, VEH_AIRCRAFT, _local_player)) continue;
- /* First VEH_END window_numbers are fake to allow a window open for all different types at once */
- if (w->window_number > VEH_END && !CanAircraftUseStation(eid, w->window_number)) continue;
-
- bv->eng_list.push_back(eid);
- if (eid == bv->sel_engine) sel_id = eid;
- }
-
- bv->sel_engine = sel_id;
-}
-
-/* Generate the list of vehicles */
-static void GenerateBuildList(Window *w)
-{
- buildvehicle_d *bv = &WP(w, buildvehicle_d);
-
- switch (bv->vehicle_type) {
- default: NOT_REACHED();
- case VEH_TRAIN:
- GenerateBuildTrainList(w);
- return; // trains should not reach the last sorting
- case VEH_ROAD:
- GenerateBuildRoadVehList(w);
- break;
- case VEH_SHIP:
- GenerateBuildShipList(w);
- break;
- case VEH_AIRCRAFT:
- GenerateBuildAircraftList(w);
- break;
- }
- _internal_sort_order = bv->descending_sort_order;
- EngList_Sort(&bv->eng_list, _sorter[bv->vehicle_type][bv->sort_criteria]);
-}
-
static void DrawVehicleEngine(VehicleType type, int x, int y, EngineID engine, SpriteID pal)
{
switch (type) {
@@ -990,199 +792,400 @@
}
}
-static void DrawBuildVehicleWindow(Window *w)
-{
- const buildvehicle_d *bv = &WP(w, buildvehicle_d);
- uint max = min(w->vscroll.pos + w->vscroll.cap, bv->eng_list.size());
-
- w->SetWidgetDisabledState(BUILD_VEHICLE_WIDGET_BUILD, w->window_number <= VEH_END);
-
- SetVScrollCount(w, bv->eng_list.size());
- SetDParam(0, bv->filter.railtype + STR_881C_NEW_RAIL_VEHICLES); // This should only affect rail vehicles
- /* Set text of sort by dropdown */
- w->widget[BUILD_VEHICLE_WIDGET_SORT_DROPDOWN].data = _sort_listing[bv->vehicle_type][bv->sort_criteria];
-
- DrawWindowWidgets(w);
-
- DrawEngineList(bv->vehicle_type, w->widget[BUILD_VEHICLE_WIDGET_LIST].left + 2, w->widget[BUILD_VEHICLE_WIDGET_LIST].top + 1, bv->eng_list, w->vscroll.pos, max, bv->sel_engine, 0, DEFAULT_GROUP);
+struct BuildVehicleWindow : Window {
+ VehicleType vehicle_type;
+ union {
+ RailTypeByte railtype;
+ AirportFTAClass::Flags flags;
+ RoadTypes roadtypes;
+ } filter;
+ byte sel_index; ///< deprecated value, used for 'unified' ship and road
+ bool descending_sort_order;
+ byte sort_criteria;
+ bool regenerate_list;
+ EngineID sel_engine;
+ EngineID rename_engine;
+ EngineList eng_list;
- if (bv->sel_engine != INVALID_ENGINE) {
- const Widget *wi = &w->widget[BUILD_VEHICLE_WIDGET_PANEL];
- int text_end = DrawVehiclePurchaseInfo(2, wi->top + 1, wi->right - wi->left - 2, bv->sel_engine);
+ BuildVehicleWindow(const WindowDesc *desc, TileIndex tile, VehicleType type) : Window(desc, tile == 0 ? (int)type : tile)
+ {
+ this->vehicle_type = type;
+ int vlh = GetVehicleListHeight(this->vehicle_type);
- if (text_end > wi->bottom) {
- w->SetDirty();
- ResizeWindowForWidget(w, BUILD_VEHICLE_WIDGET_PANEL, 0, text_end - wi->bottom);
- w->SetDirty();
+ ResizeWindow(this, 0, vlh - 14);
+ this->resize.step_height = vlh;
+ this->vscroll.cap = 1;
+ this->widget[BUILD_VEHICLE_WIDGET_LIST].data = 0x101;
+
+ this->resize.width = this->width;
+ this->resize.height = this->height;
+
+ this->caption_color = (tile != 0) ? GetTileOwner(tile) : _local_player;
+
+ this->sel_engine = INVALID_ENGINE;
+ this->regenerate_list = false;
+
+ this->sort_criteria = _last_sort_criteria[type];
+ this->descending_sort_order = _last_sort_order[type];
+
+ switch (type) {
+ default: NOT_REACHED();
+ case VEH_TRAIN:
+ this->filter.railtype = (tile == 0) ? RAILTYPE_END : GetRailType(tile);
+ break;
+ case VEH_ROAD:
+ this->filter.roadtypes = (tile == 0) ? ROADTYPES_ALL : GetRoadTypes(tile);
+ case VEH_SHIP:
+ break;
+ case VEH_AIRCRAFT:
+ this->filter.flags =
+ tile == 0 ? AirportFTAClass::ALL : GetStationByTile(tile)->Airport()->flags;
+ break;
+ }
+ this->SetupWindowStrings(type);
+ ResizeButtons(this, BUILD_VEHICLE_WIDGET_BUILD, BUILD_VEHICLE_WIDGET_RENAME);
+
+ this->GenerateBuildList(); // generate the list, since we need it in the next line
+ /* Select the first engine in the list as default when opening the window */
+ if (this->eng_list.size() > 0) this->sel_engine = this->eng_list[0];
+
+ this->FindWindowPlacementAndResize(desc);
+ }
+
+ /* Setup widget strings to fit the different types of vehicles */
+ void SetupWindowStrings(VehicleType type)
+ {
+ switch (type) {
+ default: NOT_REACHED();
+
+ case VEH_TRAIN:
+ this->widget[BUILD_VEHICLE_WIDGET_CAPTION].data = STR_JUST_STRING;
+ this->widget[BUILD_VEHICLE_WIDGET_LIST].tooltips = STR_8843_TRAIN_VEHICLE_SELECTION;
+ this->widget[BUILD_VEHICLE_WIDGET_BUILD].data = STR_881F_BUILD_VEHICLE;
+ this->widget[BUILD_VEHICLE_WIDGET_BUILD].tooltips = STR_8844_BUILD_THE_HIGHLIGHTED_TRAIN;
+ this->widget[BUILD_VEHICLE_WIDGET_RENAME].data = STR_8820_RENAME;
+ this->widget[BUILD_VEHICLE_WIDGET_RENAME].tooltips = STR_8845_RENAME_TRAIN_VEHICLE_TYPE;
+ break;
+
+ case VEH_ROAD:
+ this->widget[BUILD_VEHICLE_WIDGET_CAPTION].data = STR_9006_NEW_ROAD_VEHICLES;
+ this->widget[BUILD_VEHICLE_WIDGET_LIST].tooltips = STR_9026_ROAD_VEHICLE_SELECTION;
+ this->widget[BUILD_VEHICLE_WIDGET_BUILD].data = STR_9007_BUILD_VEHICLE;
+ this->widget[BUILD_VEHICLE_WIDGET_BUILD].tooltips = STR_9027_BUILD_THE_HIGHLIGHTED_ROAD;
+ this->widget[BUILD_VEHICLE_WIDGET_RENAME].data = STR_9034_RENAME;
+ this->widget[BUILD_VEHICLE_WIDGET_RENAME].tooltips = STR_9035_RENAME_ROAD_VEHICLE_TYPE;
+ break;
+
+ case VEH_SHIP:
+ this->widget[BUILD_VEHICLE_WIDGET_CAPTION].data = STR_9808_NEW_SHIPS;
+ this->widget[BUILD_VEHICLE_WIDGET_LIST].tooltips = STR_9825_SHIP_SELECTION_LIST_CLICK;
+ this->widget[BUILD_VEHICLE_WIDGET_BUILD].data = STR_9809_BUILD_SHIP;
+ this->widget[BUILD_VEHICLE_WIDGET_BUILD].tooltips = STR_9826_BUILD_THE_HIGHLIGHTED_SHIP;
+ this->widget[BUILD_VEHICLE_WIDGET_RENAME].data = STR_9836_RENAME;
+ this->widget[BUILD_VEHICLE_WIDGET_RENAME].tooltips = STR_9837_RENAME_SHIP_TYPE;
+ break;
+
+ case VEH_AIRCRAFT:
+ this->widget[BUILD_VEHICLE_WIDGET_CAPTION].data = STR_A005_NEW_AIRCRAFT;
+ this->widget[BUILD_VEHICLE_WIDGET_LIST].tooltips = STR_A025_AIRCRAFT_SELECTION_LIST;
+ this->widget[BUILD_VEHICLE_WIDGET_BUILD].data = STR_A006_BUILD_AIRCRAFT;
+ this->widget[BUILD_VEHICLE_WIDGET_BUILD].tooltips = STR_A026_BUILD_THE_HIGHLIGHTED_AIRCRAFT;
+ this->widget[BUILD_VEHICLE_WIDGET_RENAME].data = STR_A037_RENAME;
+ this->widget[BUILD_VEHICLE_WIDGET_RENAME].tooltips = STR_A038_RENAME_AIRCRAFT_TYPE;
+ break;
}
}
- DrawSortButtonState(w, BUILD_VEHICLE_WIDGET_SORT_ASSENDING_DESCENDING, bv->descending_sort_order ? SBS_DOWN : SBS_UP);
-}
-
-static void BuildVehicleClickEvent(Window *w, WindowEvent *e)
-{
- buildvehicle_d *bv = &WP(w, buildvehicle_d);
+ /* Figure out what train EngineIDs to put in the list */
+ void GenerateBuildTrainList()
+ {
+ EngineID sel_id = INVALID_ENGINE;
+ int num_engines = 0;
+ int num_wagons = 0;
- switch (e->we.click.widget) {
- case BUILD_VEHICLE_WIDGET_SORT_ASSENDING_DESCENDING:
- bv->descending_sort_order ^= true;
- _last_sort_order[bv->vehicle_type] = bv->descending_sort_order;
- bv->regenerate_list = true;
- w->SetDirty();
- break;
+ this->filter.railtype = (this->window_number <= VEH_END) ? RAILTYPE_END : GetRailType(this->window_number);
- case BUILD_VEHICLE_WIDGET_LIST: {
- uint i = (e->we.click.pt.y - w->widget[BUILD_VEHICLE_WIDGET_LIST].top) / GetVehicleListHeight(bv->vehicle_type) + w->vscroll.pos;
- size_t num_items = bv->eng_list.size();
- bv->sel_engine = (i < num_items) ? bv->eng_list[i] : INVALID_ENGINE;
- w->SetDirty();
- break;
+ this->eng_list.clear();
+
+ /* Make list of all available train engines and wagons.
+ * Also check to see if the previously selected engine is still available,
+ * and if not, reset selection to INVALID_ENGINE. This could be the case
+ * when engines become obsolete and are removed */
+ const Engine *e;
+ FOR_ALL_ENGINES_OF_TYPE(e, VEH_TRAIN) {
+ EngineID eid = e->index;
+ const RailVehicleInfo *rvi = &e->u.rail;
+
+ if (this->filter.railtype != RAILTYPE_END && !HasPowerOnRail(rvi->railtype, this->filter.railtype)) continue;
+ if (!IsEngineBuildable(eid, VEH_TRAIN, _local_player)) continue;
+
+ this->eng_list.push_back(eid);
+ if (rvi->railveh_type != RAILVEH_WAGON) {
+ num_engines++;
+ } else {
+ num_wagons++;
+ }
+
+ if (eid == this->sel_engine) sel_id = eid;
}
- case BUILD_VEHICLE_WIDGET_SORT_DROPDOWN: // Select sorting criteria dropdown menu
- ShowDropDownMenu(w, _sort_listing[bv->vehicle_type], bv->sort_criteria, BUILD_VEHICLE_WIDGET_SORT_DROPDOWN, 0, 0);
- break;
+ this->sel_engine = sel_id;
- case BUILD_VEHICLE_WIDGET_BUILD: {
- EngineID sel_eng = bv->sel_engine;
- if (sel_eng != INVALID_ENGINE) {
- switch (bv->vehicle_type) {
- default: NOT_REACHED();
- case VEH_TRAIN:
- DoCommandP(w->window_number, sel_eng, 0, (RailVehInfo(sel_eng)->railveh_type == RAILVEH_WAGON) ? CcBuildWagon : CcBuildLoco,
- CMD_BUILD_RAIL_VEHICLE | CMD_MSG(STR_882B_CAN_T_BUILD_RAILROAD_VEHICLE));
- break;
- case VEH_ROAD:
- DoCommandP(w->window_number, sel_eng, 0, CcBuildRoadVeh, CMD_BUILD_ROAD_VEH | CMD_MSG(STR_9009_CAN_T_BUILD_ROAD_VEHICLE));
- break;
- case VEH_SHIP:
- DoCommandP(w->window_number, sel_eng, 0, CcBuildShip, CMD_BUILD_SHIP | CMD_MSG(STR_980D_CAN_T_BUILD_SHIP));
- break;
- case VEH_AIRCRAFT:
- DoCommandP(w->window_number, sel_eng, 0, CcBuildAircraft, CMD_BUILD_AIRCRAFT | CMD_MSG(STR_A008_CAN_T_BUILD_AIRCRAFT));
- break;
- }
- }
- break;
+ /* make engines first, and then wagons, sorted by ListPositionOfEngine() */
+ _internal_sort_order = false;
+ EngList_Sort(&this->eng_list, TrainEnginesThenWagonsSorter);
+
+ /* and then sort engines */
+ _internal_sort_order = this->descending_sort_order;
+ EngList_SortPartial(&this->eng_list, _sorter[0][this->sort_criteria], 0, num_engines);
+
+ /* and finally sort wagons */
+ EngList_SortPartial(&this->eng_list, _sorter[0][this->sort_criteria], num_engines, num_wagons);
+ }
+
+ /* Figure out what road vehicle EngineIDs to put in the list */
+ void GenerateBuildRoadVehList()
+ {
+ EngineID sel_id = INVALID_ENGINE;
+
+ this->eng_list.clear();
+
+ const Engine *e;
+ FOR_ALL_ENGINES_OF_TYPE(e, VEH_ROAD) {
+ EngineID eid = e->index;
+ if (!IsEngineBuildable(eid, VEH_ROAD, _local_player)) continue;
+ if (!HasBit(this->filter.roadtypes, HasBit(EngInfo(eid)->misc_flags, EF_ROAD_TRAM) ? ROADTYPE_TRAM : ROADTYPE_ROAD)) continue;
+ this->eng_list.push_back(eid);
+
+ if (eid == this->sel_engine) sel_id = eid;
+ }
+ this->sel_engine = sel_id;
+ }
+
+ /* Figure out what ship EngineIDs to put in the list */
+ void GenerateBuildShipList()
+ {
+ EngineID sel_id = INVALID_ENGINE;
+ this->eng_list.clear();
+
+ const Engine *e;
+ FOR_ALL_ENGINES_OF_TYPE(e, VEH_SHIP) {
+ EngineID eid = e->index;
+ if (!IsEngineBuildable(eid, VEH_SHIP, _local_player)) continue;
+ this->eng_list.push_back(eid);
+
+ if (eid == this->sel_engine) sel_id = eid;
+ }
+ this->sel_engine = sel_id;
+ }
+
+ /* Figure out what aircraft EngineIDs to put in the list */
+ void GenerateBuildAircraftList()
+ {
+ EngineID sel_id = INVALID_ENGINE;
+
+ this->eng_list.clear();
+
+ /* Make list of all available planes.
+ * Also check to see if the previously selected plane is still available,
+ * and if not, reset selection to INVALID_ENGINE. This could be the case
+ * when planes become obsolete and are removed */
+ const Engine *e;
+ FOR_ALL_ENGINES_OF_TYPE(e, VEH_AIRCRAFT) {
+ EngineID eid = e->index;
+ if (!IsEngineBuildable(eid, VEH_AIRCRAFT, _local_player)) continue;
+ /* First VEH_END window_numbers are fake to allow a window open for all different types at once */
+ if (this->window_number > VEH_END && !CanAircraftUseStation(eid, this->window_number)) continue;
+
+ this->eng_list.push_back(eid);
+ if (eid == this->sel_engine) sel_id = eid;
}
- case BUILD_VEHICLE_WIDGET_RENAME: {
- EngineID sel_eng = bv->sel_engine;
- if (sel_eng != INVALID_ENGINE) {
- StringID str = STR_NULL;
+ this->sel_engine = sel_id;
+ }
- bv->rename_engine = sel_eng;
- switch (bv->vehicle_type) {
- default: NOT_REACHED();
- case VEH_TRAIN: str = STR_886A_RENAME_TRAIN_VEHICLE_TYPE; break;
- case VEH_ROAD: str = STR_9036_RENAME_ROAD_VEHICLE_TYPE; break;
- case VEH_SHIP: str = STR_9838_RENAME_SHIP_TYPE; break;
- case VEH_AIRCRAFT: str = STR_A039_RENAME_AIRCRAFT_TYPE; break;
+ /* Generate the list of vehicles */
+ void GenerateBuildList()
+ {
+ switch (this->vehicle_type) {
+ default: NOT_REACHED();
+ case VEH_TRAIN:
+ this->GenerateBuildTrainList();
+ return; // trains should not reach the last sorting
+ case VEH_ROAD:
+ this->GenerateBuildRoadVehList();
+ break;
+ case VEH_SHIP:
+ this->GenerateBuildShipList();
+ break;
+ case VEH_AIRCRAFT:
+ this->GenerateBuildAircraftList();
+ break;
+ }
+ _internal_sort_order = this->descending_sort_order;
+ EngList_Sort(&this->eng_list, _sorter[this->vehicle_type][this->sort_criteria]);
+ }
+
+ void OnClick(Point pt, int widget)
+ {
+ switch (widget) {
+ case BUILD_VEHICLE_WIDGET_SORT_ASSENDING_DESCENDING:
+ this->descending_sort_order ^= true;
+ _last_sort_order[this->vehicle_type] = this->descending_sort_order;
+ this->regenerate_list = true;
+ this->SetDirty();
+ break;
+
+ case BUILD_VEHICLE_WIDGET_LIST: {
+ uint i = (pt.y - this->widget[BUILD_VEHICLE_WIDGET_LIST].top) / GetVehicleListHeight(this->vehicle_type) + this->vscroll.pos;
+ size_t num_items = this->eng_list.size();
+ this->sel_engine = (i < num_items) ? this->eng_list[i] : INVALID_ENGINE;
+ this->SetDirty();
+ break;
+ }
+
+ case BUILD_VEHICLE_WIDGET_SORT_DROPDOWN: // Select sorting criteria dropdown menu
+ ShowDropDownMenu(this, _sort_listing[this->vehicle_type], this->sort_criteria, BUILD_VEHICLE_WIDGET_SORT_DROPDOWN, 0, 0);
+ break;
+
+ case BUILD_VEHICLE_WIDGET_BUILD: {
+ EngineID sel_eng = this->sel_engine;
+ if (sel_eng != INVALID_ENGINE) {
+ switch (this->vehicle_type) {
+ default: NOT_REACHED();
+ case VEH_TRAIN:
+ DoCommandP(this->window_number, sel_eng, 0, (RailVehInfo(sel_eng)->railveh_type == RAILVEH_WAGON) ? CcBuildWagon : CcBuildLoco,
+ CMD_BUILD_RAIL_VEHICLE | CMD_MSG(STR_882B_CAN_T_BUILD_RAILROAD_VEHICLE));
+ break;
+ case VEH_ROAD:
+ DoCommandP(this->window_number, sel_eng, 0, CcBuildRoadVeh, CMD_BUILD_ROAD_VEH | CMD_MSG(STR_9009_CAN_T_BUILD_ROAD_VEHICLE));
+ break;
+ case VEH_SHIP:
+ DoCommandP(this->window_number, sel_eng, 0, CcBuildShip, CMD_BUILD_SHIP | CMD_MSG(STR_980D_CAN_T_BUILD_SHIP));
+ break;
+ case VEH_AIRCRAFT:
+ DoCommandP(this->window_number, sel_eng, 0, CcBuildAircraft, CMD_BUILD_AIRCRAFT | CMD_MSG(STR_A008_CAN_T_BUILD_AIRCRAFT));
+ break;
+ }
}
- SetDParam(0, sel_eng);
- ShowQueryString(STR_ENGINE_NAME, str, 31, 160, w, CS_ALPHANUMERAL);
+ break;
}
- break;
+
+ case BUILD_VEHICLE_WIDGET_RENAME: {
+ EngineID sel_eng = this->sel_engine;
+ if (sel_eng != INVALID_ENGINE) {
+ StringID str = STR_NULL;
+
+ this->rename_engine = sel_eng;
+ switch (this->vehicle_type) {
+ default: NOT_REACHED();
+ case VEH_TRAIN: str = STR_886A_RENAME_TRAIN_VEHICLE_TYPE; break;
+ case VEH_ROAD: str = STR_9036_RENAME_ROAD_VEHICLE_TYPE; break;
+ case VEH_SHIP: str = STR_9838_RENAME_SHIP_TYPE; break;
+ case VEH_AIRCRAFT: str = STR_A039_RENAME_AIRCRAFT_TYPE; break;
+ }
+ SetDParam(0, sel_eng);
+ ShowQueryString(STR_ENGINE_NAME, str, 31, 160, this, CS_ALPHANUMERAL);
+ }
+ break;
+ }
}
}
-}
-
-static void NewVehicleWndProc(Window *w, WindowEvent *e)
-{
- buildvehicle_d *bv = &WP(w, buildvehicle_d);
-
- switch (e->event) {
- case WE_CREATE: {
- bv->vehicle_type = *(VehicleType*)e->we.create.data;
- int vlh = GetVehicleListHeight(bv->vehicle_type);
-
- ResizeWindow(w, 0, vlh - 14);
- w->resize.step_height = vlh;
- w->vscroll.cap = 1;
- w->widget[BUILD_VEHICLE_WIDGET_LIST].data = 0x101;
-
- w->resize.width = w->width;
- w->resize.height = w->height;
- } break;
-
- case WE_INVALIDATE_DATA:
- bv->regenerate_list = true;
- w->SetDirty();
- break;
-
- case WE_DESTROY:
- bv->eng_list.~EngineList(); // call destructor explicitly
- break;
- case WE_PAINT:
- if (bv->regenerate_list) {
- bv->regenerate_list = false;
- GenerateBuildList(w);
- }
- DrawBuildVehicleWindow(w);
- break;
-
- case WE_CLICK:
- BuildVehicleClickEvent(w, e);
- break;
+ virtual void OnInvalidateData(int data)
+ {
+ this->regenerate_list = true;
+ }
- case WE_DOUBLE_CLICK:
- if (e->we.click.widget == BUILD_VEHICLE_WIDGET_LIST) {
- /* When double clicking, we want to buy a vehicle */
- e->we.click.widget = BUILD_VEHICLE_WIDGET_BUILD;
- BuildVehicleClickEvent(w, e);
- }
- break;
-
- case WE_ON_EDIT_TEXT: {
- if (!StrEmpty(e->we.edittext.str)) {
- StringID str = STR_NULL;
- _cmd_text = e->we.edittext.str;
- switch (bv->vehicle_type) {
- default: NOT_REACHED();
- case VEH_TRAIN: str = STR_886B_CAN_T_RENAME_TRAIN_VEHICLE; break;
- case VEH_ROAD: str = STR_9037_CAN_T_RENAME_ROAD_VEHICLE; break;
- case VEH_SHIP: str = STR_9839_CAN_T_RENAME_SHIP_TYPE; break;
- case VEH_AIRCRAFT: str = STR_A03A_CAN_T_RENAME_AIRCRAFT_TYPE; break;
- }
- DoCommandP(0, bv->rename_engine, 0, NULL, CMD_RENAME_ENGINE | CMD_MSG(str));
- }
- break;
+ virtual void OnPaint()
+ {
+ if (this->regenerate_list) {
+ this->regenerate_list = false;
+ this->GenerateBuildList();
}
- case WE_DROPDOWN_SELECT: // we have selected a dropdown item in the list
- if (bv->sort_criteria != e->we.dropdown.index) {
- bv->sort_criteria = e->we.dropdown.index;
- _last_sort_criteria[bv->vehicle_type] = bv->sort_criteria;
- bv->regenerate_list = true;
- }
- w->SetDirty();
- break;
+ uint max = min(this->vscroll.pos + this->vscroll.cap, this->eng_list.size());
- case WE_RESIZE:
- if (e->we.sizing.diff.x != 0) ResizeButtons(w, BUILD_VEHICLE_WIDGET_BUILD, BUILD_VEHICLE_WIDGET_RENAME);
- if (e->we.sizing.diff.y == 0) break;
+ this->SetWidgetDisabledState(BUILD_VEHICLE_WIDGET_BUILD, this->window_number <= VEH_END);
- w->vscroll.cap += e->we.sizing.diff.y / (int)GetVehicleListHeight(bv->vehicle_type);
- w->widget[BUILD_VEHICLE_WIDGET_LIST].data = (w->vscroll.cap << 8) + 1;
- break;
+ SetVScrollCount(this, this->eng_list.size());
+ SetDParam(0, this->filter.railtype + STR_881C_NEW_RAIL_VEHICLES); // This should only affect rail vehicles
+
+ /* Set text of sort by dropdown */
+ this->widget[BUILD_VEHICLE_WIDGET_SORT_DROPDOWN].data = _sort_listing[this->vehicle_type][this->sort_criteria];
+
+ this->DrawWidgets();
+
+ DrawEngineList(this->vehicle_type, this->widget[BUILD_VEHICLE_WIDGET_LIST].left + 2, this->widget[BUILD_VEHICLE_WIDGET_LIST].top + 1, this->eng_list, this->vscroll.pos, max, this->sel_engine, 0, DEFAULT_GROUP);
+
+ if (this->sel_engine != INVALID_ENGINE) {
+ const Widget *wi = &this->widget[BUILD_VEHICLE_WIDGET_PANEL];
+ int text_end = DrawVehiclePurchaseInfo(2, wi->top + 1, wi->right - wi->left - 2, this->sel_engine);
+
+ if (text_end > wi->bottom) {
+ this->SetDirty();
+ ResizeWindowForWidget(this, BUILD_VEHICLE_WIDGET_PANEL, 0, text_end - wi->bottom);
+ this->SetDirty();
+ }
+ }
+
+ this->DrawSortButtonState(BUILD_VEHICLE_WIDGET_SORT_ASSENDING_DESCENDING, this->descending_sort_order ? SBS_DOWN : SBS_UP);
}
-}
+
+ virtual void OnDoubleClick(Point pt, int widget)
+ {
+ if (widget == BUILD_VEHICLE_WIDGET_LIST) {
+ /* When double clicking, we want to buy a vehicle */
+ this->OnClick(pt, BUILD_VEHICLE_WIDGET_BUILD);
+ }
+ }
+
+ virtual void OnQueryTextFinished(char *str)
+ {
+ if (!StrEmpty(str)) {
+ StringID err_str = STR_NULL;
+ _cmd_text = str;
+ switch (this->vehicle_type) {
+ default: NOT_REACHED();
+ case VEH_TRAIN: err_str = STR_886B_CAN_T_RENAME_TRAIN_VEHICLE; break;
+ case VEH_ROAD: err_str = STR_9037_CAN_T_RENAME_ROAD_VEHICLE; break;
+ case VEH_SHIP: err_str = STR_9839_CAN_T_RENAME_SHIP_TYPE; break;
+ case VEH_AIRCRAFT: err_str = STR_A03A_CAN_T_RENAME_AIRCRAFT_TYPE; break;
+ }
+ DoCommandP(0, this->rename_engine, 0, NULL, CMD_RENAME_ENGINE | CMD_MSG(err_str));
+ }
+ }
+
+ virtual void OnDropdownSelect(int widget, int index)
+ {
+ if (this->sort_criteria != index) {
+ this->sort_criteria = index;
+ _last_sort_criteria[this->vehicle_type] = this->sort_criteria;
+ this->regenerate_list = true;
+ }
+ this->SetDirty();
+ }
+
+ virtual void OnResize(Point new_size, Point delta)
+ {
+ if (delta.x != 0) ResizeButtons(this, BUILD_VEHICLE_WIDGET_BUILD, BUILD_VEHICLE_WIDGET_RENAME);
+ if (delta.y == 0) return;
+
+ this->vscroll.cap += delta.y / (int)GetVehicleListHeight(this->vehicle_type);
+ this->widget[BUILD_VEHICLE_WIDGET_LIST].data = (this->vscroll.cap << 8) + 1;
+ }
+};
static const WindowDesc _build_vehicle_desc = {
WDP_AUTO, WDP_AUTO, 240, 174, 240, 256,
WC_BUILD_VEHICLE, WC_NONE,
WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS | WDF_RESIZABLE,
_build_vehicle_widgets,
- NewVehicleWndProc
};
void ShowBuildVehicleWindow(TileIndex tile, VehicleType type)
{
- buildvehicle_d *bv;
- Window *w;
/* We want to be able to open both Available Train as Available Ships,
* so if tile == 0 (Available XXX Window), use 'type' as unique number.
* As it always is a low value, it won't collide with any real tile
@@ -1193,39 +1196,5 @@
DeleteWindowById(WC_BUILD_VEHICLE, num);
- w = AllocateWindowDescFront<Window>(&_build_vehicle_desc, num, &type);
-
- if (w == NULL) return;
-
- w->caption_color = (tile != 0) ? GetTileOwner(tile) : _local_player;
-
- bv = &WP(w, buildvehicle_d);
- new (&bv->eng_list) EngineList();
- bv->sel_engine = INVALID_ENGINE;
-
- bv->regenerate_list = false;
-
- bv->sort_criteria = _last_sort_criteria[type];
- bv->descending_sort_order = _last_sort_order[type];
-
- switch (type) {
- default: NOT_REACHED();
- case VEH_TRAIN:
- WP(w, buildvehicle_d).filter.railtype = (tile == 0) ? RAILTYPE_END : GetRailType(tile);
- break;
- case VEH_ROAD:
- WP(w, buildvehicle_d).filter.roadtypes = (tile == 0) ? ROADTYPES_ALL : GetRoadTypes(tile);
- case VEH_SHIP:
- break;
- case VEH_AIRCRAFT:
- bv->filter.flags =
- tile == 0 ? AirportFTAClass::ALL : GetStationByTile(tile)->Airport()->flags;
- break;
- }
- SetupWindowStrings(w, type);
- ResizeButtons(w, BUILD_VEHICLE_WIDGET_BUILD, BUILD_VEHICLE_WIDGET_RENAME);
-
- GenerateBuildList(w); // generate the list, since we need it in the next line
- /* Select the first engine in the list as default when opening the window */
- if (bv->eng_list.size() > 0) bv->sel_engine = bv->eng_list[0];
+ new BuildVehicleWindow(&_build_vehicle_desc, tile, type);
}
--- a/src/cheat_gui.cpp Mon May 19 14:14:33 2008 +0000
+++ b/src/cheat_gui.cpp Mon May 19 15:13:58 2008 +0000
@@ -120,114 +120,117 @@
{ WIDGETS_END},
};
-static void CheatsWndProc(Window *w, WindowEvent *e)
-{
- switch (e->event) {
- case WE_PAINT: {
- int clk = WP(w, def_d).data_1;
-
- DrawWindowWidgets(w);
- DrawStringMultiCenter(200, 25, STR_CHEATS_WARNING, w->width - 50);
-
- for (int i = 0, x = 0, y = 45; i != lengthof(_cheats_ui); i++) {
- const CheatEntry *ce = &_cheats_ui[i];
-
- DrawSprite((*ce->been_used) ? SPR_BOX_CHECKED : SPR_BOX_EMPTY, PAL_NONE, x + 5, y + 2);
-
- switch (ce->type) {
- case SLE_BOOL: {
- bool on = (*(bool*)ce->variable);
-
- DrawFrameRect(x + 20, y + 1, x + 30 + 9, y + 9, on ? 6 : 4, on ? FR_LOWERED : FR_NONE);
- SetDParam(0, on ? STR_CONFIG_PATCHES_ON : STR_CONFIG_PATCHES_OFF);
- } break;
-
- default: {
- int32 val = (int32)ReadValue(ce->variable, ce->type);
- char buf[512];
+struct CheatWindow : Window {
+ int clicked;
- /* Draw [<][>] boxes for settings of an integer-type */
- DrawArrowButtons(x + 20, y, 3, clk - (i * 2), true, true);
-
- switch (ce->str) {
- /* Display date for change date cheat */
- case STR_CHEAT_CHANGE_DATE: SetDParam(0, _date); break;
-
- /* Draw colored flag for change player cheat */
- case STR_CHEAT_CHANGE_PLAYER:
- SetDParam(0, val);
- GetString(buf, STR_CHEAT_CHANGE_PLAYER, lastof(buf));
- DrawPlayerIcon(_current_player, 60 + GetStringBoundingBox(buf).width, y + 2);
- break;
+ CheatWindow(const WindowDesc *desc) : Window(desc)
+ {
+ }
- /* Set correct string for switch climate cheat */
- case STR_CHEAT_SWITCH_CLIMATE: val += STR_TEMPERATE_LANDSCAPE;
+ virtual void OnPaint()
+ {
+ this->DrawWidgets();
+ DrawStringMultiCenter(200, 25, STR_CHEATS_WARNING, width - 50);
- /* Fallthrough */
- default: SetDParam(0, val);
- }
- } break;
- }
+ for (int i = 0, x = 0, y = 45; i != lengthof(_cheats_ui); i++) {
+ const CheatEntry *ce = &_cheats_ui[i];
- DrawString(50, y + 1, ce->str, TC_FROMSTRING);
+ DrawSprite((*ce->been_used) ? SPR_BOX_CHECKED : SPR_BOX_EMPTY, PAL_NONE, x + 5, y + 2);
- y += 12;
+ switch (ce->type) {
+ case SLE_BOOL: {
+ bool on = (*(bool*)ce->variable);
+
+ DrawFrameRect(x + 20, y + 1, x + 30 + 9, y + 9, on ? 6 : 4, on ? FR_LOWERED : FR_NONE);
+ SetDParam(0, on ? STR_CONFIG_PATCHES_ON : STR_CONFIG_PATCHES_OFF);
+ } break;
+
+ default: {
+ int32 val = (int32)ReadValue(ce->variable, ce->type);
+ char buf[512];
+
+ /* Draw [<][>] boxes for settings of an integer-type */
+ DrawArrowButtons(x + 20, y, 3, clicked - (i * 2), true, true);
+
+ switch (ce->str) {
+ /* Display date for change date cheat */
+ case STR_CHEAT_CHANGE_DATE: SetDParam(0, _date); break;
+
+ /* Draw colored flag for change player cheat */
+ case STR_CHEAT_CHANGE_PLAYER:
+ SetDParam(0, val);
+ GetString(buf, STR_CHEAT_CHANGE_PLAYER, lastof(buf));
+ DrawPlayerIcon(_current_player, 60 + GetStringBoundingBox(buf).width, y + 2);
+ break;
+
+ /* Set correct string for switch climate cheat */
+ case STR_CHEAT_SWITCH_CLIMATE: val += STR_TEMPERATE_LANDSCAPE;
+
+ /* Fallthrough */
+ default: SetDParam(0, val);
+ }
+ } break;
}
- break;
+
+ DrawString(50, y + 1, ce->str, TC_FROMSTRING);
+
+ y += 12;
+ }
+ }
+
+ virtual void OnClick(Point pt, int widget)
+ {
+ uint btn = (pt.y - 46) / 12;
+ uint x = pt.x;
+
+ /* Not clicking a button? */
+ if (!IsInsideMM(x, 20, 40) || btn >= lengthof(_cheats_ui)) return;
+
+ const CheatEntry *ce = &_cheats_ui[btn];
+ int value = (int32)ReadValue(ce->variable, ce->type);
+ int oldvalue = value;
+
+ *ce->been_used = true;
+
+ switch (ce->type) {
+ case SLE_BOOL:
+ value ^= 1;
+ if (ce->proc != NULL) ce->proc(value, 0);
+ break;
+
+ default:
+ /* Take whatever the function returns */
+ value = ce->proc(value + ((x >= 30) ? 1 : -1), (x >= 30) ? 1 : -1);
+
+ /* The first cheat (money), doesn't return a different value. */
+ if (value != oldvalue || btn == 0) this->clicked = btn * 2 + 1 + ((x >= 30) ? 1 : 0);
+ break;
}
- case WE_CLICK: {
- uint btn = (e->we.click.pt.y - 46) / 12;
- uint x = e->we.click.pt.x;
-
- /* Not clicking a button? */
- if (!IsInsideMM(x, 20, 40) || btn >= lengthof(_cheats_ui)) break;
-
- const CheatEntry *ce = &_cheats_ui[btn];
- int value = (int32)ReadValue(ce->variable, ce->type);
- int oldvalue = value;
-
- *ce->been_used = true;
-
- switch (ce->type) {
- case SLE_BOOL:
- value ^= 1;
- if (ce->proc != NULL) ce->proc(value, 0);
- break;
+ if (value != oldvalue) WriteValue(ce->variable, ce->type, (int64)value);
- default:
- /* Take whatever the function returns */
- value = ce->proc(value + ((x >= 30) ? 1 : -1), (x >= 30) ? 1 : -1);
-
- if (value != oldvalue) WP(w, def_d).data_1 = btn * 2 + 1 + ((x >= 30) ? 1 : 0);
- break;
- }
-
- if (value != oldvalue) WriteValue(ce->variable, ce->type, (int64)value);
+ flags4 |= 5 << WF_TIMEOUT_SHL;
- w->flags4 |= 5 << WF_TIMEOUT_SHL;
-
- w->SetDirty();
- } break;
+ SetDirty();
+ }
- case WE_TIMEOUT:
- WP(w, def_d).data_1 = 0;
- w->SetDirty();
- break;
+ virtual void OnTimeout()
+ {
+ this->clicked = 0;
+ this->SetDirty();
}
-}
+};
static const WindowDesc _cheats_desc = {
240, 22, 400, 170, 400, 170,
WC_CHEATS, WC_NONE,
WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS,
_cheat_widgets,
- CheatsWndProc
};
void ShowCheatWindow()
{
DeleteWindowById(WC_CHEATS, 0);
- new Window(&_cheats_desc);
+ new CheatWindow(&_cheats_desc);
}
--- a/src/console.cpp Mon May 19 14:14:33 2008 +0000
+++ b/src/console.cpp Mon May 19 15:13:58 2008 +0000
@@ -77,137 +77,167 @@
static void IConsoleHistoryAdd(const char *cmd);
static void IConsoleHistoryNavigate(int direction);
-/* ** console window ** */
-static void IConsoleWndProc(Window *w, WindowEvent *e)
+struct IConsoleWindow : Window
{
- static byte iconsole_scroll = ICON_BUFFER;
+ static byte scroll;
- switch (e->event) {
- case WE_PAINT: {
- int i = iconsole_scroll;
- int max = (w->height / ICON_LINE_HEIGHT) - 1;
- int delta = 0;
- GfxFillRect(w->left, w->top, w->width, w->height - 1, 0);
- while ((i > 0) && (i > iconsole_scroll - max) && (_iconsole_buffer[i] != NULL)) {
- DoDrawString(_iconsole_buffer[i], 5,
- w->height - (iconsole_scroll + 2 - i) * ICON_LINE_HEIGHT, _iconsole_cbuffer[i]);
- i--;
- }
- /* If the text is longer than the window, don't show the starting ']' */
- delta = w->width - 10 - _iconsole_cmdline.width - ICON_RIGHT_BORDERWIDTH;
- if (delta > 0) {
- DoDrawString("]", 5, w->height - ICON_LINE_HEIGHT, _icolour_cmd);
- delta = 0;
- }
+ IConsoleWindow(const WindowDesc *desc) : Window(desc)
+ {
+ _iconsole_mode = ICONSOLE_OPENED;
+ SetBit(_no_scroll, SCROLL_CON); // override cursor arrows; the gamefield will not scroll
- DoDrawString(_iconsole_cmdline.buf, 10 + delta, w->height - ICON_LINE_HEIGHT, _icolour_cmd);
+ this->height = _screen.height / 3;
+ this->width = _screen.width;
+ }
- if (_iconsole_cmdline.caret)
- DoDrawString("_", 10 + delta + _iconsole_cmdline.caretxoffs, w->height - ICON_LINE_HEIGHT, TC_WHITE);
- break;
+ ~IConsoleWindow()
+ {
+ _iconsole_mode = ICONSOLE_CLOSED;
+ ClrBit(_no_scroll, SCROLL_CON);
+ }
+
+ virtual void OnPaint()
+ {
+ int i = IConsoleWindow::scroll;
+ int max = (this->height / ICON_LINE_HEIGHT) - 1;
+ int delta = 0;
+ GfxFillRect(this->left, this->top, this->width, this->height - 1, 0);
+ while ((i > 0) && (i > IConsoleWindow::scroll - max) && (_iconsole_buffer[i] != NULL)) {
+ DoDrawString(_iconsole_buffer[i], 5,
+ this->height - (IConsoleWindow::scroll + 2 - i) * ICON_LINE_HEIGHT, _iconsole_cbuffer[i]);
+ i--;
}
- case WE_MOUSELOOP:
- if (HandleCaret(&_iconsole_cmdline)) w->SetDirty();
- break;
- case WE_DESTROY:
- _iconsole_mode = ICONSOLE_CLOSED;
- break;
- case WE_KEYPRESS:
- e->we.keypress.cont = false;
- switch (e->we.keypress.keycode) {
- case WKC_UP:
- IConsoleHistoryNavigate(+1);
- w->SetDirty();
- break;
- case WKC_DOWN:
- IConsoleHistoryNavigate(-1);
- w->SetDirty();
- break;
- case WKC_SHIFT | WKC_PAGEUP:
- if (iconsole_scroll - (w->height / ICON_LINE_HEIGHT) - 1 < 0) {
- iconsole_scroll = 0;
- } else {
- iconsole_scroll -= (w->height / ICON_LINE_HEIGHT) - 1;
- }
- w->SetDirty();
- break;
- case WKC_SHIFT | WKC_PAGEDOWN:
- if (iconsole_scroll + (w->height / ICON_LINE_HEIGHT) - 1 > ICON_BUFFER) {
- iconsole_scroll = ICON_BUFFER;
- } else {
- iconsole_scroll += (w->height / ICON_LINE_HEIGHT) - 1;
- }
- w->SetDirty();
- break;
- case WKC_SHIFT | WKC_UP:
- if (iconsole_scroll <= 0) {
- iconsole_scroll = 0;
- } else {
- --iconsole_scroll;
- }
- w->SetDirty();
- break;
- case WKC_SHIFT | WKC_DOWN:
- if (iconsole_scroll >= ICON_BUFFER) {
- iconsole_scroll = ICON_BUFFER;
- } else {
- ++iconsole_scroll;
- }
- w->SetDirty();
- break;
- case WKC_BACKQUOTE:
- IConsoleSwitch();
- break;
- case WKC_RETURN: case WKC_NUM_ENTER:
- IConsolePrintF(_icolour_cmd, "] %s", _iconsole_cmdline.buf);
- IConsoleHistoryAdd(_iconsole_cmdline.buf);
+ /* If the text is longer than the window, don't show the starting ']' */
+ delta = this->width - 10 - _iconsole_cmdline.width - ICON_RIGHT_BORDERWIDTH;
+ if (delta > 0) {
+ DoDrawString("]", 5, this->height - ICON_LINE_HEIGHT, _icolour_cmd);
+ delta = 0;
+ }
- IConsoleCmdExec(_iconsole_cmdline.buf);
- IConsoleClearCommand();
- break;
- case WKC_CTRL | WKC_RETURN:
- _iconsole_mode = (_iconsole_mode == ICONSOLE_FULL) ? ICONSOLE_OPENED : ICONSOLE_FULL;
- IConsoleResize(w);
- MarkWholeScreenDirty();
- break;
- case (WKC_CTRL | 'V'):
- if (InsertTextBufferClipboard(&_iconsole_cmdline)) {
- IConsoleResetHistoryPos();
- w->SetDirty();
- }
- break;
- case (WKC_CTRL | 'L'):
- IConsoleCmdExec("clear");
- break;
- case (WKC_CTRL | 'U'):
- DeleteTextBufferAll(&_iconsole_cmdline);
- w->SetDirty();
- break;
- case WKC_BACKSPACE: case WKC_DELETE:
- if (DeleteTextBufferChar(&_iconsole_cmdline, e->we.keypress.keycode)) {
- IConsoleResetHistoryPos();
- w->SetDirty();
- }
- break;
- case WKC_LEFT: case WKC_RIGHT: case WKC_END: case WKC_HOME:
- if (MoveTextBufferPos(&_iconsole_cmdline, e->we.keypress.keycode)) {
- IConsoleResetHistoryPos();
- w->SetDirty();
- }
- break;
- default:
- if (IsValidChar(e->we.keypress.key, CS_ALPHANUMERAL)) {
- iconsole_scroll = ICON_BUFFER;
- InsertTextBufferChar(&_iconsole_cmdline, e->we.keypress.key);
- IConsoleResetHistoryPos();
- w->SetDirty();
- } else {
- e->we.keypress.cont = true;
- }
- break;
+ DoDrawString(_iconsole_cmdline.buf, 10 + delta, this->height - ICON_LINE_HEIGHT, _icolour_cmd);
+
+ if (_iconsole_cmdline.caret) {
+ DoDrawString("_", 10 + delta + _iconsole_cmdline.caretxoffs, this->height - ICON_LINE_HEIGHT, TC_WHITE);
}
}
-}
+
+ virtual void OnMouseLoop()
+ {
+ if (HandleCaret(&_iconsole_cmdline)) this->SetDirty();
+ }
+
+ virtual EventState OnKeyPress(uint16 key, uint16 keycode)
+ {
+ switch (keycode) {
+ case WKC_UP:
+ IConsoleHistoryNavigate(+1);
+ this->SetDirty();
+ break;
+
+ case WKC_DOWN:
+ IConsoleHistoryNavigate(-1);
+ this->SetDirty();
+ break;
+
+ case WKC_SHIFT | WKC_PAGEUP:
+ if (IConsoleWindow::scroll - (this->height / ICON_LINE_HEIGHT) - 1 < 0) {
+ IConsoleWindow::scroll = 0;
+ } else {
+ IConsoleWindow::scroll -= (this->height / ICON_LINE_HEIGHT) - 1;
+ }
+ this->SetDirty();
+ break;
+
+ case WKC_SHIFT | WKC_PAGEDOWN:
+ if (IConsoleWindow::scroll + (this->height / ICON_LINE_HEIGHT) - 1 > ICON_BUFFER) {
+ IConsoleWindow::scroll = ICON_BUFFER;
+ } else {
+ IConsoleWindow::scroll += (this->height / ICON_LINE_HEIGHT) - 1;
+ }
+ this->SetDirty();
+ break;
+
+ case WKC_SHIFT | WKC_UP:
+ if (IConsoleWindow::scroll <= 0) {
+ IConsoleWindow::scroll = 0;
+ } else {
+ --IConsoleWindow::scroll;
+ }
+ this->SetDirty();
+ break;
+
+ case WKC_SHIFT | WKC_DOWN:
+ if (IConsoleWindow::scroll >= ICON_BUFFER) {
+ IConsoleWindow::scroll = ICON_BUFFER;
+ } else {
+ ++IConsoleWindow::scroll;
+ }
+ this->SetDirty();
+ break;
+
+ case WKC_BACKQUOTE:
+ IConsoleSwitch();
+ break;
+
+ case WKC_RETURN: case WKC_NUM_ENTER:
+ IConsolePrintF(_icolour_cmd, "] %s", _iconsole_cmdline.buf);
+ IConsoleHistoryAdd(_iconsole_cmdline.buf);
+
+ IConsoleCmdExec(_iconsole_cmdline.buf);
+ IConsoleClearCommand();
+ break;
+
+ case WKC_CTRL | WKC_RETURN:
+ _iconsole_mode = (_iconsole_mode == ICONSOLE_FULL) ? ICONSOLE_OPENED : ICONSOLE_FULL;
+ IConsoleResize(this);
+ MarkWholeScreenDirty();
+ break;
+
+ case (WKC_CTRL | 'V'):
+ if (InsertTextBufferClipboard(&_iconsole_cmdline)) {
+ IConsoleResetHistoryPos();
+ this->SetDirty();
+ }
+ break;
+
+ case (WKC_CTRL | 'L'):
+ IConsoleCmdExec("clear");
+ break;
+
+ case (WKC_CTRL | 'U'):
+ DeleteTextBufferAll(&_iconsole_cmdline);
+ this->SetDirty();
+ break;
+
+ case WKC_BACKSPACE: case WKC_DELETE:
+ if (DeleteTextBufferChar(&_iconsole_cmdline, keycode)) {
+ IConsoleResetHistoryPos();
+ this->SetDirty();
+ }
+ break;
+
+ case WKC_LEFT: case WKC_RIGHT: case WKC_END: case WKC_HOME:
+ if (MoveTextBufferPos(&_iconsole_cmdline, keycode)) {
+ IConsoleResetHistoryPos();
+ this->SetDirty();
+ }
+ break;
+
+ default:
+ if (IsValidChar(key, CS_ALPHANUMERAL)) {
+ IConsoleWindow::scroll = ICON_BUFFER;
+ InsertTextBufferChar(&_iconsole_cmdline, key);
+ IConsoleResetHistoryPos();
+ this->SetDirty();
+ } else {
+ return ES_NOT_HANDLED;
+ }
+ }
+ return ES_HANDLED;
+ }
+};
+
+byte IConsoleWindow::scroll = ICON_BUFFER;
static const Widget _iconsole_window_widgets[] = {
{WIDGETS_END}
@@ -218,7 +248,6 @@
WC_CONSOLE, WC_NONE,
WDF_STD_TOOLTIPS | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS,
_iconsole_window_widgets,
- IConsoleWndProc,
};
void IConsoleInit()
@@ -317,17 +346,12 @@
void IConsoleSwitch()
{
switch (_iconsole_mode) {
- case ICONSOLE_CLOSED: {
- Window *w = new Window(&_iconsole_window_desc);
- w->height = _screen.height / 3;
- w->width = _screen.width;
- _iconsole_mode = ICONSOLE_OPENED;
- SetBit(_no_scroll, SCROLL_CON); // override cursor arrows; the gamefield will not scroll
- } break;
+ case ICONSOLE_CLOSED:
+ new IConsoleWindow(&_iconsole_window_desc);
+ break;
+
case ICONSOLE_OPENED: case ICONSOLE_FULL:
DeleteWindowById(WC_CONSOLE, 0);
- _iconsole_mode = ICONSOLE_CLOSED;
- ClrBit(_no_scroll, SCROLL_CON);
break;
}
--- a/src/console_cmds.cpp Mon May 19 14:14:33 2008 +0000
+++ b/src/console_cmds.cpp Mon May 19 15:13:58 2008 +0000
@@ -537,7 +537,11 @@
if (argc < 3) return false;
- SEND_COMMAND(PACKET_CLIENT_RCON)(argv[1], argv[2]);
+ if (_network_server) {
+ IConsoleCmdExec(argv[2]);
+ } else {
+ SEND_COMMAND(PACKET_CLIENT_RCON)(argv[1], argv[2]);
+ }
return true;
}
--- a/src/currency.cpp Mon May 19 14:14:33 2008 +0000
+++ b/src/currency.cpp Mon May 19 15:13:58 2008 +0000
@@ -154,7 +154,7 @@
_currency_specs[_opt.currency].to_euro != CF_ISEURO &&
_cur_year >= _currency_specs[_opt.currency].to_euro) {
_opt.currency = 2; // this is the index of euro above.
- AddNewsItem(STR_EURO_INTRODUCE, NM_NORMAL, NF_NONE, NT_ECONOMY, DNC_NONE, 0, 0);
+ AddNewsItem(STR_EURO_INTRODUCE, NS_ECONOMY, 0, 0);
}
}
--- a/src/depot_gui.cpp Mon May 19 14:14:33 2008 +0000
+++ b/src/depot_gui.cpp Mon May 19 15:13:58 2008 +0000
@@ -25,6 +25,7 @@
#include "order_func.h"
#include "depot_base.h"
#include "tilehighlight_func.h"
+#include "window_gui.h"
#include "table/strings.h"
#include "table/sprites.h"
@@ -101,27 +102,11 @@
};
-struct depot_d {
- VehicleID sel;
- VehicleType type;
- bool generate_list;
- uint16 engine_list_length;
- uint16 wagon_list_length;
- uint16 engine_count;
- uint16 wagon_count;
- Vehicle **vehicle_list;
- Vehicle **wagon_list;
-};
-assert_compile(WINDOW_CUSTOM_SIZE >= sizeof(depot_d));
-
-static void DepotWndProc(Window *w, WindowEvent *e);
-
static const WindowDesc _train_depot_desc = {
WDP_AUTO, WDP_AUTO, 36, 27, 36, 27,
WC_VEHICLE_DEPOT, WC_NONE,
WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS | WDF_STICKY_BUTTON | WDF_RESIZABLE,
_depot_widgets,
- DepotWndProc
};
static const WindowDesc _road_depot_desc = {
@@ -129,7 +114,6 @@
WC_VEHICLE_DEPOT, WC_NONE,
WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS | WDF_STICKY_BUTTON | WDF_RESIZABLE,
_depot_widgets,
- DepotWndProc
};
static const WindowDesc _ship_depot_desc = {
@@ -137,7 +121,6 @@
WC_VEHICLE_DEPOT, WC_NONE,
WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS | WDF_STICKY_BUTTON | WDF_RESIZABLE,
_depot_widgets,
- DepotWndProc
};
static const WindowDesc _aircraft_depot_desc = {
@@ -145,10 +128,10 @@
WC_VEHICLE_DEPOT, WC_NONE,
WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS | WDF_STICKY_BUTTON | WDF_RESIZABLE,
_depot_widgets,
- DepotWndProc
};
extern int WagonLengthToPixels(int len);
+extern void DepotSortList(Vehicle **v, uint16 length);
/**
* This is the Callback method after the cloning attempt of a vehicle
@@ -166,247 +149,6 @@
ShowVehicleViewWindow(v);
}
-static void DepotSellAllConfirmationCallback(Window *w, bool confirmed)
-{
- if (confirmed) {
- TileIndex tile = w->window_number;
- byte vehtype = WP(w, depot_d).type;
- DoCommandP(tile, vehtype, 0, NULL, CMD_DEPOT_SELL_ALL_VEHICLES);
- }
-}
-
-const Sprite *GetAircraftSprite(EngineID engine);
-
-/** Draw a vehicle in the depot window in the box with the top left corner at x,y
- * @param *w Window to draw in
- * @param *v Vehicle to draw
- * @param x Left side of the box to draw in
- * @param y Top of the box to draw in
- */
-static void DrawVehicleInDepot(Window *w, const Vehicle *v, int x, int y)
-{
- byte diff_x = 0, diff_y = 0;
-
- int sprite_y = y + w->resize.step_height - GetVehicleListHeight(v->type);
-
- switch (v->type) {
- case VEH_TRAIN:
- DrawTrainImage(v, x + 21, sprite_y, WP(w, depot_d).sel, w->hscroll.cap + 4, w->hscroll.pos);
-
- /* Number of wagons relative to a standard length wagon (rounded up) */
- SetDParam(0, (v->u.rail.cached_total_length + 7) / 8);
- DrawStringRightAligned(w->widget[DEPOT_WIDGET_MATRIX].right - 1, y + 4, STR_TINY_BLACK, TC_FROMSTRING); // Draw the counter
- break;
-
- case VEH_ROAD: DrawRoadVehImage( v, x + 24, sprite_y, WP(w, depot_d).sel, 1); break;
- case VEH_SHIP: DrawShipImage( v, x + 19, sprite_y - 1, WP(w, depot_d).sel); break;
- case VEH_AIRCRAFT: {
- const Sprite *spr = GetSprite(v->GetImage(DIR_W));
- DrawAircraftImage(v, x + 12,
- y + max(spr->height + spr->y_offs - 14, 0), // tall sprites needs an y offset
- WP(w, depot_d).sel);
- } break;
- default: NOT_REACHED();
- }
-
- if (w->resize.step_height == 14) {
- /* VEH_TRAIN and VEH_ROAD, which are low */
- diff_x = 15;
- } else {
- /* VEH_SHIP and VEH_AIRCRAFT, which are tall */
- diff_y = 12;
- }
-
- DrawSprite((v->vehstatus & VS_STOPPED) ? SPR_FLAG_VEH_STOPPED : SPR_FLAG_VEH_RUNNING, PAL_NONE, x + diff_x, y + diff_y);
-
- SetDParam(0, v->unitnumber);
- DrawString(x, y + 2, (uint16)(v->max_age - 366) >= v->age ? STR_00E2 : STR_00E3, TC_FROMSTRING);
-}
-
-static void DrawDepotWindow(Window *w)
-{
- Vehicle **vl = WP(w, depot_d).vehicle_list;
- TileIndex tile = w->window_number;
- int x, y, i, maxval;
- uint16 hnum;
- uint16 num = WP(w, depot_d).engine_count;
-
- /* Set the row and number of boxes in each row based on the number of boxes drawn in the matrix */
- uint16 rows_in_display = w->widget[DEPOT_WIDGET_MATRIX].data >> 8;
- uint16 boxes_in_each_row = w->widget[DEPOT_WIDGET_MATRIX].data & 0xFF;
-
- /* setup disabled buttons */
- w->SetWidgetsDisabledState(!IsTileOwner(tile, _local_player),
- DEPOT_WIDGET_STOP_ALL,
- DEPOT_WIDGET_START_ALL,
- DEPOT_WIDGET_SELL,
- DEPOT_WIDGET_SELL_CHAIN,
- DEPOT_WIDGET_SELL_ALL,
- DEPOT_WIDGET_BUILD,
- DEPOT_WIDGET_CLONE,
- DEPOT_WIDGET_AUTOREPLACE,
- WIDGET_LIST_END);
-
- /* determine amount of items for scroller */
- if (WP(w, depot_d).type == VEH_TRAIN) {
- hnum = 8;
- for (num = 0; num < WP(w, depot_d).engine_count; num++) {
- const Vehicle *v = vl[num];
- hnum = max(hnum, v->u.rail.cached_total_length);
- }
- /* Always have 1 empty row, so people can change the setting of the train */
- SetVScrollCount(w, WP(w, depot_d).engine_count + WP(w, depot_d).wagon_count + 1);
- SetHScrollCount(w, WagonLengthToPixels(hnum));
- } else {
- SetVScrollCount(w, (num + w->hscroll.cap - 1) / w->hscroll.cap);
- }
-
- /* locate the depot struct */
- if (WP(w, depot_d).type == VEH_AIRCRAFT) {
- SetDParam(0, GetStationIndex(tile)); // Airport name
- } else {
- Depot *depot = GetDepotByTile(tile);
- assert(depot != NULL);
-
- SetDParam(0, depot->town_index);
- }
-
- DrawWindowWidgets(w);
-
- num = w->vscroll.pos * boxes_in_each_row;
- maxval = min(WP(w, depot_d).engine_count, num + (rows_in_display * boxes_in_each_row));
-
- for (x = 2, y = 15; num < maxval; y += w->resize.step_height, x = 2) { // Draw the rows
- byte i;
-
- for (i = 0; i < boxes_in_each_row && num < maxval; i++, num++, x += w->resize.step_width) {
- /* Draw all vehicles in the current row */
- const Vehicle *v = vl[num];
- DrawVehicleInDepot(w, v, x, y);
- }
- }
-
- maxval = min(WP(w, depot_d).engine_count + WP(w, depot_d).wagon_count, (w->vscroll.pos * boxes_in_each_row) + (rows_in_display * boxes_in_each_row));
-
- /* draw the train wagons, that do not have an engine in front */
- for (; num < maxval; num++, y += 14) {
- const Vehicle *v = WP(w, depot_d).wagon_list[num - WP(w, depot_d).engine_count];
- const Vehicle *u;
-
- DrawTrainImage(v, x + 50, y, WP(w, depot_d).sel, w->hscroll.cap - 29, 0);
- DrawString(x, y + 2, STR_8816, TC_FROMSTRING);
-
- /*Draw the train counter */
- i = 0;
- u = v;
- do i++; while ((u = u->Next()) != NULL); // Determine length of train
- SetDParam(0, i); // Set the counter
- DrawStringRightAligned(w->widget[DEPOT_WIDGET_MATRIX].right - 1, y + 4, STR_TINY_BLACK, TC_FROMSTRING); // Draw the counter
- }
-}
-
-struct GetDepotVehiclePtData {
- Vehicle *head;
- Vehicle *wagon;
-};
-
-enum DepotGUIAction {
- MODE_ERROR,
- MODE_DRAG_VEHICLE,
- MODE_SHOW_VEHICLE,
- MODE_START_STOP,
-};
-
-static DepotGUIAction GetVehicleFromDepotWndPt(const Window *w, int x, int y, Vehicle **veh, GetDepotVehiclePtData *d)
-{
- Vehicle **vl = WP(w, depot_d).vehicle_list;
- uint xt, row, xm = 0, ym = 0;
- int pos, skip = 0;
- uint16 boxes_in_each_row = w->widget[DEPOT_WIDGET_MATRIX].data & 0xFF;
-
- if (WP(w, depot_d).type == VEH_TRAIN) {
- xt = 0;
- x -= 23;
- } else {
- xt = x / w->resize.step_width;
- xm = x % w->resize.step_width;
- if (xt >= w->hscroll.cap) return MODE_ERROR;
-
- ym = (y - 14) % w->resize.step_height;
- }
-
- row = (y - 14) / w->resize.step_height;
- if (row >= w->vscroll.cap) return MODE_ERROR;
-
- pos = ((row + w->vscroll.pos) * boxes_in_each_row) + xt;
-
- if (WP(w, depot_d).engine_count + WP(w, depot_d).wagon_count <= pos) {
- if (WP(w, depot_d).type == VEH_TRAIN) {
- d->head = NULL;
- d->wagon = NULL;
- return MODE_DRAG_VEHICLE;
- } else {
- return MODE_ERROR; // empty block, so no vehicle is selected
- }
- }
-
- if (WP(w, depot_d).engine_count > pos) {
- *veh = vl[pos];
- skip = w->hscroll.pos;
- } else {
- vl = WP(w, depot_d).wagon_list;
- pos -= WP(w, depot_d).engine_count;
- *veh = vl[pos];
- /* free wagons don't have an initial loco. */
- x -= _traininfo_vehicle_width;
- }
-
- switch (WP(w, depot_d).type) {
- case VEH_TRAIN: {
- Vehicle *v = *veh;
- d->head = d->wagon = v;
-
- /* either pressed the flag or the number, but only when it's a loco */
- if (x < 0 && IsFrontEngine(v)) return (x >= -10) ? MODE_START_STOP : MODE_SHOW_VEHICLE;
-
- skip = (skip * 8) / _traininfo_vehicle_width;
- x = (x * 8) / _traininfo_vehicle_width;
-
- /* Skip vehicles that are scrolled off the list */
- x += skip;
-
- /* find the vehicle in this row that was clicked */
- while (v != NULL && (x -= v->u.rail.cached_veh_length) >= 0) v = v->Next();
-
- /* if an articulated part was selected, find its parent */
- while (v != NULL && IsArticulatedPart(v)) v = v->Previous();
-
- d->wagon = v;
-
- return MODE_DRAG_VEHICLE;
- }
- break;
-
- case VEH_ROAD:
- if (xm >= 24) return MODE_DRAG_VEHICLE;
- if (xm <= 16) return MODE_SHOW_VEHICLE;
- break;
-
- case VEH_SHIP:
- if (xm >= 19) return MODE_DRAG_VEHICLE;
- if (ym <= 10) return MODE_SHOW_VEHICLE;
- break;
-
- case VEH_AIRCRAFT:
- if (xm >= 12) return MODE_DRAG_VEHICLE;
- if (ym <= 12) return MODE_SHOW_VEHICLE;
- break;
-
- default: NOT_REACHED();
- }
- return MODE_START_STOP;
-}
-
static void TrainDepotMoveVehicle(Vehicle *wagon, VehicleID sel, Vehicle *head)
{
Vehicle *v;
@@ -427,220 +169,6 @@
DoCommandP(v->tile, v->index + ((wagon == NULL ? INVALID_VEHICLE : wagon->index) << 16), _ctrl_pressed ? 1 : 0, NULL, CMD_MOVE_RAIL_VEHICLE | CMD_MSG(STR_8837_CAN_T_MOVE_VEHICLE));
}
-static void DepotClick(Window *w, int x, int y)
-{
- GetDepotVehiclePtData gdvp;
- Vehicle *v = NULL;
- DepotGUIAction mode = GetVehicleFromDepotWndPt(w, x, y, &v, &gdvp);
-
- /* share / copy orders */
- if (_thd.place_mode != VHM_NONE && mode != MODE_ERROR) {
- _place_clicked_vehicle = (WP(w, depot_d).type == VEH_TRAIN ? gdvp.head : v);
- return;
- }
-
- if (WP(w, depot_d).type == VEH_TRAIN) v = gdvp.wagon;
-
- switch (mode) {
- case MODE_ERROR: // invalid
- return;
-
- case MODE_DRAG_VEHICLE: { // start dragging of vehicle
- VehicleID sel = WP(w, depot_d).sel;
-
- if (WP(w, depot_d).type == VEH_TRAIN && sel != INVALID_VEHICLE) {
- WP(w, depot_d).sel = INVALID_VEHICLE;
- TrainDepotMoveVehicle(v, sel, gdvp.head);
- } else if (v != NULL) {
- int image = v->GetImage(DIR_W);
-
- WP(w, depot_d).sel = v->index;
- w->SetDirty();
- SetObjectToPlaceWnd(image, GetVehiclePalette(v), VHM_DRAG, w);
- _cursor.vehchain = _ctrl_pressed;
- }
- }
- break;
-
- case MODE_SHOW_VEHICLE: // show info window
- ShowVehicleViewWindow(v);
- break;
-
- case MODE_START_STOP: { // click start/stop flag
- uint command;
-
- switch (WP(w, depot_d).type) {
- case VEH_TRAIN: command = CMD_START_STOP_TRAIN | CMD_MSG(STR_883B_CAN_T_STOP_START_TRAIN); break;
- case VEH_ROAD: command = CMD_START_STOP_ROADVEH | CMD_MSG(STR_9015_CAN_T_STOP_START_ROAD_VEHICLE); break;
- case VEH_SHIP: command = CMD_START_STOP_SHIP | CMD_MSG(STR_9818_CAN_T_STOP_START_SHIP); break;
- case VEH_AIRCRAFT: command = CMD_START_STOP_AIRCRAFT | CMD_MSG(STR_A016_CAN_T_STOP_START_AIRCRAFT); break;
- default: NOT_REACHED(); command = 0;
- }
- DoCommandP(v->tile, v->index, 0, NULL, command);
- }
- break;
-
- default: NOT_REACHED();
- }
-}
-
-/**
- * Clones a vehicle
- * @param *v is the original vehicle to clone
- * @param *w is the window of the depot where the clone is build
- */
-static void HandleCloneVehClick(const Vehicle *v, const Window *w)
-{
- uint error_str;
-
- if (v == NULL) return;
-
- if (!v->IsPrimaryVehicle()) {
- v = v->First();
- /* Do nothing when clicking on a train in depot with no loc attached */
- if (v->type == VEH_TRAIN && !IsFrontEngine(v)) return;
- }
-
- switch (v->type) {
- case VEH_TRAIN: error_str = CMD_MSG(STR_882B_CAN_T_BUILD_RAILROAD_VEHICLE); break;
- case VEH_ROAD: error_str = CMD_MSG(STR_9009_CAN_T_BUILD_ROAD_VEHICLE); break;
- case VEH_SHIP: error_str = CMD_MSG(STR_980D_CAN_T_BUILD_SHIP); break;
- case VEH_AIRCRAFT: error_str = CMD_MSG(STR_A008_CAN_T_BUILD_AIRCRAFT); break;
- default: return;
- }
-
- DoCommandP(w->window_number, v->index, _ctrl_pressed ? 1 : 0, CcCloneVehicle, CMD_CLONE_VEHICLE | error_str);
-
- ResetObjectToPlace();
-}
-
-static void ClonePlaceObj(const Window *w)
-{
- const Vehicle *v = CheckMouseOverVehicle();
-
- if (v != NULL) HandleCloneVehClick(v, w);
-}
-
-static void ResizeDepotButtons(Window *w)
-{
- ResizeButtons(w, DEPOT_WIDGET_BUILD, DEPOT_WIDGET_LOCATION);
-
- if (WP(w, depot_d).type == VEH_TRAIN) {
- /* Divide the size of DEPOT_WIDGET_SELL into two equally big buttons so DEPOT_WIDGET_SELL and DEPOT_WIDGET_SELL_CHAIN will get the same size.
- * This way it will stay the same even if DEPOT_WIDGET_SELL_CHAIN is resized for some reason */
- w->widget[DEPOT_WIDGET_SELL_CHAIN].top = ((w->widget[DEPOT_WIDGET_SELL_CHAIN].bottom - w->widget[DEPOT_WIDGET_SELL].top) / 2) + w->widget[DEPOT_WIDGET_SELL].top;
- w->widget[DEPOT_WIDGET_SELL].bottom = w->widget[DEPOT_WIDGET_SELL_CHAIN].top - 1;
- }
-}
-
-/* Function to set up vehicle specific sprites and strings
- * Only use this if it's the same widget, that's used for more than one vehicle type and it needs different text/sprites
- * Vehicle specific text/sprites, that's in a widget, that's only shown for one vehicle type (like sell whole train) is set in the widget array
- */
-static void SetupStringsForDepotWindow(Window *w, VehicleType type)
-{
- switch (type) {
- default: NOT_REACHED();
-
- case VEH_TRAIN:
- w->widget[DEPOT_WIDGET_CAPTION].data = STR_8800_TRAIN_DEPOT;
- w->widget[DEPOT_WIDGET_STOP_ALL].tooltips = STR_MASS_STOP_DEPOT_TRAIN_TIP;
- w->widget[DEPOT_WIDGET_START_ALL].tooltips= STR_MASS_START_DEPOT_TRAIN_TIP;
- w->widget[DEPOT_WIDGET_SELL].tooltips = STR_8841_DRAG_TRAIN_VEHICLE_TO_HERE;
- w->widget[DEPOT_WIDGET_SELL_ALL].tooltips = STR_DEPOT_SELL_ALL_BUTTON_TRAIN_TIP;
- w->widget[DEPOT_WIDGET_MATRIX].tooltips = STR_883F_TRAINS_CLICK_ON_TRAIN_FOR;
-
- w->widget[DEPOT_WIDGET_BUILD].data = STR_8815_NEW_VEHICLES;
- w->widget[DEPOT_WIDGET_BUILD].tooltips = STR_8840_BUILD_NEW_TRAIN_VEHICLE;
- w->widget[DEPOT_WIDGET_CLONE].data = STR_CLONE_TRAIN;
- w->widget[DEPOT_WIDGET_CLONE].tooltips = STR_CLONE_TRAIN_DEPOT_INFO;
-
- w->widget[DEPOT_WIDGET_LOCATION].tooltips = STR_8842_CENTER_MAIN_VIEW_ON_TRAIN;
- w->widget[DEPOT_WIDGET_VEHICLE_LIST].data = STR_TRAIN;
- w->widget[DEPOT_WIDGET_VEHICLE_LIST].tooltips = STR_DEPOT_VEHICLE_ORDER_LIST_TRAIN_TIP;
- w->widget[DEPOT_WIDGET_AUTOREPLACE].tooltips = STR_DEPOT_AUTOREPLACE_TRAIN_TIP;
-
- /* Sprites */
- w->widget[DEPOT_WIDGET_SELL].data = SPR_SELL_TRAIN;
- w->widget[DEPOT_WIDGET_SELL_ALL].data = SPR_SELL_ALL_TRAIN;
- w->widget[DEPOT_WIDGET_AUTOREPLACE].data = SPR_REPLACE_TRAIN;
- break;
-
- case VEH_ROAD:
- w->widget[DEPOT_WIDGET_CAPTION].data = STR_9003_ROAD_VEHICLE_DEPOT;
- w->widget[DEPOT_WIDGET_STOP_ALL].tooltips = STR_MASS_STOP_DEPOT_ROADVEH_TIP;
- w->widget[DEPOT_WIDGET_START_ALL].tooltips= STR_MASS_START_DEPOT_ROADVEH_TIP;
- w->widget[DEPOT_WIDGET_SELL].tooltips = STR_9024_DRAG_ROAD_VEHICLE_TO_HERE;
- w->widget[DEPOT_WIDGET_SELL_ALL].tooltips = STR_DEPOT_SELL_ALL_BUTTON_ROADVEH_TIP;
- w->widget[DEPOT_WIDGET_MATRIX].tooltips = STR_9022_VEHICLES_CLICK_ON_VEHICLE;
-
- w->widget[DEPOT_WIDGET_BUILD].data = STR_9004_NEW_VEHICLES;
- w->widget[DEPOT_WIDGET_BUILD].tooltips = STR_9023_BUILD_NEW_ROAD_VEHICLE;
- w->widget[DEPOT_WIDGET_CLONE].data = STR_CLONE_ROAD_VEHICLE;
- w->widget[DEPOT_WIDGET_CLONE].tooltips = STR_CLONE_ROAD_VEHICLE_DEPOT_INFO;
-
- w->widget[DEPOT_WIDGET_LOCATION].tooltips = STR_9025_CENTER_MAIN_VIEW_ON_ROAD;
- w->widget[DEPOT_WIDGET_VEHICLE_LIST].data = STR_LORRY;
- w->widget[DEPOT_WIDGET_VEHICLE_LIST].tooltips = STR_DEPOT_VEHICLE_ORDER_LIST_ROADVEH_TIP;
- w->widget[DEPOT_WIDGET_AUTOREPLACE].tooltips = STR_DEPOT_AUTOREPLACE_ROADVEH_TIP;
-
- /* Sprites */
- w->widget[DEPOT_WIDGET_SELL].data = SPR_SELL_ROADVEH;
- w->widget[DEPOT_WIDGET_SELL_ALL].data = SPR_SELL_ALL_ROADVEH;
- w->widget[DEPOT_WIDGET_AUTOREPLACE].data = SPR_REPLACE_ROADVEH;
- break;
-
- case VEH_SHIP:
- w->widget[DEPOT_WIDGET_CAPTION].data = STR_9803_SHIP_DEPOT;
- w->widget[DEPOT_WIDGET_STOP_ALL].tooltips = STR_MASS_STOP_DEPOT_SHIP_TIP;
- w->widget[DEPOT_WIDGET_START_ALL].tooltips= STR_MASS_START_DEPOT_SHIP_TIP;
- w->widget[DEPOT_WIDGET_SELL].tooltips = STR_9821_DRAG_SHIP_TO_HERE_TO_SELL;
- w->widget[DEPOT_WIDGET_SELL_ALL].tooltips = STR_DEPOT_SELL_ALL_BUTTON_SHIP_TIP;
- w->widget[DEPOT_WIDGET_MATRIX].tooltips = STR_981F_SHIPS_CLICK_ON_SHIP_FOR;
-
- w->widget[DEPOT_WIDGET_BUILD].data = STR_9804_NEW_SHIPS;
- w->widget[DEPOT_WIDGET_BUILD].tooltips = STR_9820_BUILD_NEW_SHIP;
- w->widget[DEPOT_WIDGET_CLONE].data = STR_CLONE_SHIP;
- w->widget[DEPOT_WIDGET_CLONE].tooltips = STR_CLONE_SHIP_DEPOT_INFO;
-
- w->widget[DEPOT_WIDGET_LOCATION].tooltips = STR_9822_CENTER_MAIN_VIEW_ON_SHIP;
- w->widget[DEPOT_WIDGET_VEHICLE_LIST].data = STR_SHIP;
- w->widget[DEPOT_WIDGET_VEHICLE_LIST].tooltips = STR_DEPOT_VEHICLE_ORDER_LIST_SHIP_TIP;
- w->widget[DEPOT_WIDGET_AUTOREPLACE].tooltips = STR_DEPOT_AUTOREPLACE_SHIP_TIP;
-
- /* Sprites */
- w->widget[DEPOT_WIDGET_SELL].data = SPR_SELL_SHIP;
- w->widget[DEPOT_WIDGET_SELL_ALL].data = SPR_SELL_ALL_SHIP;
- w->widget[DEPOT_WIDGET_AUTOREPLACE].data = SPR_REPLACE_SHIP;
- break;
-
- case VEH_AIRCRAFT:
- w->widget[DEPOT_WIDGET_CAPTION].data = STR_A002_AIRCRAFT_HANGAR;
- w->widget[DEPOT_WIDGET_STOP_ALL].tooltips = STR_MASS_STOP_HANGAR_TIP;
- w->widget[DEPOT_WIDGET_START_ALL].tooltips= STR_MASS_START_HANGAR_TIP;
- w->widget[DEPOT_WIDGET_SELL].tooltips = STR_A023_DRAG_AIRCRAFT_TO_HERE_TO;
- w->widget[DEPOT_WIDGET_SELL_ALL].tooltips = STR_DEPOT_SELL_ALL_BUTTON_AIRCRAFT_TIP;
- w->widget[DEPOT_WIDGET_MATRIX].tooltips = STR_A021_AIRCRAFT_CLICK_ON_AIRCRAFT;
-
- w->widget[DEPOT_WIDGET_BUILD].data = STR_A003_NEW_AIRCRAFT;
- w->widget[DEPOT_WIDGET_BUILD].tooltips = STR_A022_BUILD_NEW_AIRCRAFT;
- w->widget[DEPOT_WIDGET_CLONE].data = STR_CLONE_AIRCRAFT;
- w->widget[DEPOT_WIDGET_CLONE].tooltips = STR_CLONE_AIRCRAFT_INFO_HANGAR_WINDOW;
-
- w->widget[DEPOT_WIDGET_LOCATION].tooltips = STR_A024_CENTER_MAIN_VIEW_ON_HANGAR;
- w->widget[DEPOT_WIDGET_VEHICLE_LIST].data = STR_PLANE;
- w->widget[DEPOT_WIDGET_VEHICLE_LIST].tooltips = STR_DEPOT_VEHICLE_ORDER_LIST_AIRCRAFT_TIP;
- w->widget[DEPOT_WIDGET_AUTOREPLACE].tooltips = STR_DEPOT_AUTOREPLACE_AIRCRAFT_TIP;
-
- /* Sprites */
- w->widget[DEPOT_WIDGET_SELL].data = SPR_SELL_AIRCRAFT;
- w->widget[DEPOT_WIDGET_SELL_ALL].data = SPR_SELL_ALL_AIRCRAFT;
- w->widget[DEPOT_WIDGET_AUTOREPLACE].data = SPR_REPLACE_AIRCRAFT;
- break;
- }
-}
-
-
/* Array to hold the block sizes
* First part is the vehicle type, while the last is 0 = x, 1 = y */
uint _block_sizes[4][2];
@@ -707,296 +235,746 @@
ResizeDefaultWindowSize(VEH_AIRCRAFT);
}
-static void CreateDepotListWindow(Window *w, VehicleType type)
-{
- WP(w, depot_d).type = type;
- _backup_orders_tile = 0;
-
- assert(IsPlayerBuildableVehicleType(type)); // ensure that we make the call with a valid type
-
- /* Resize the window according to the vehicle type */
-
- /* Set the number of blocks in each direction */
- w->vscroll.cap = _resize_cap[type][0];
- w->hscroll.cap = _resize_cap[type][1];
+static void DepotSellAllConfirmationCallback(Window *w, bool confirmed);
+const Sprite *GetAircraftSprite(EngineID engine);
- /* Set the block size */
- w->resize.step_width = _block_sizes[type][0];
- w->resize.step_height = _block_sizes[type][1];
+struct DepotWindow : Window {
+ VehicleID sel;
+ VehicleType type;
+ bool generate_list;
+ uint16 engine_list_length;
+ uint16 wagon_list_length;
+ uint16 engine_count;
+ uint16 wagon_count;
+ Vehicle **vehicle_list;
+ Vehicle **wagon_list;
- /* Enlarge the window to fit with the selected number of blocks of the selected size */
- ResizeWindow(w,
- _block_sizes[type][0] * w->hscroll.cap,
- _block_sizes[type][1] * w->vscroll.cap);
+ DepotWindow(const WindowDesc *desc, WindowNumber window_number) : Window(desc, window_number)
+ {
+ this->sel = INVALID_VEHICLE;
+ this->vehicle_list = NULL;
+ this->wagon_list = NULL;
+ this->engine_count = 0;
+ this->wagon_count = 0;
+ this->generate_list = true;
- if (type == VEH_TRAIN) {
- /* Make space for the horizontal scrollbar vertically, and the unit
- * number, flag, and length counter horizontally. */
- ResizeWindow(w, 36, 12);
- /* substract the newly added space from the matrix since it was meant for the scrollbar */
- w->widget[DEPOT_WIDGET_MATRIX].bottom -= 12;
+ this->FindWindowPlacementAndResize(desc);
}
- /* Set the minimum window size to the current window size */
- w->resize.width = w->width;
- w->resize.height = w->height;
+ ~DepotWindow()
+ {
+ DeleteWindowById(WC_BUILD_VEHICLE, this->window_number);
+ free((void*)this->vehicle_list);
+ free((void*)this->wagon_list);
+ }
- SetupStringsForDepotWindow(w, type);
+ /** Draw a vehicle in the depot window in the box with the top left corner at x,y
+ * @param *w Window to draw in
+ * @param *v Vehicle to draw
+ * @param x Left side of the box to draw in
+ * @param y Top of the box to draw in
+ */
+ void DrawVehicleInDepot(Window *w, const Vehicle *v, int x, int y)
+ {
+ byte diff_x = 0, diff_y = 0;
- w->widget[DEPOT_WIDGET_MATRIX].data =
- (w->vscroll.cap * 0x100) // number of rows to draw on the background
- + (type == VEH_TRAIN ? 1 : w->hscroll.cap); // number of boxes in each row. Trains always have just one
+ int sprite_y = y + this->resize.step_height - GetVehicleListHeight(v->type);
+
+ switch (v->type) {
+ case VEH_TRAIN:
+ DrawTrainImage(v, x + 21, sprite_y, this->sel, this->hscroll.cap + 4, this->hscroll.pos);
+
+ /* Number of wagons relative to a standard length wagon (rounded up) */
+ SetDParam(0, (v->u.rail.cached_total_length + 7) / 8);
+ DrawStringRightAligned(this->widget[DEPOT_WIDGET_MATRIX].right - 1, y + 4, STR_TINY_BLACK, TC_FROMSTRING); // Draw the counter
+ break;
+
+ case VEH_ROAD: DrawRoadVehImage( v, x + 24, sprite_y, this->sel, 1); break;
+ case VEH_SHIP: DrawShipImage( v, x + 19, sprite_y - 1, this->sel); break;
+ case VEH_AIRCRAFT: {
+ const Sprite *spr = GetSprite(v->GetImage(DIR_W));
+ DrawAircraftImage(v, x + 12,
+ y + max(spr->height + spr->y_offs - 14, 0), // tall sprites needs an y offset
+ this->sel);
+ } break;
+ default: NOT_REACHED();
+ }
+
+ if (this->resize.step_height == 14) {
+ /* VEH_TRAIN and VEH_ROAD, which are low */
+ diff_x = 15;
+ } else {
+ /* VEH_SHIP and VEH_AIRCRAFT, which are tall */
+ diff_y = 12;
+ }
+
+ DrawSprite((v->vehstatus & VS_STOPPED) ? SPR_FLAG_VEH_STOPPED : SPR_FLAG_VEH_RUNNING, PAL_NONE, x + diff_x, y + diff_y);
+
+ SetDParam(0, v->unitnumber);
+ DrawString(x, y + 2, (uint16)(v->max_age - 366) >= v->age ? STR_00E2 : STR_00E3, TC_FROMSTRING);
+ }
+
+ void DrawDepotWindow(Window *w)
+ {
+ Vehicle **vl = this->vehicle_list;
+ TileIndex tile = this->window_number;
+ int x, y, i, maxval;
+ uint16 hnum;
+ uint16 num = this->engine_count;
+
+ /* Set the row and number of boxes in each row based on the number of boxes drawn in the matrix */
+ uint16 rows_in_display = this->widget[DEPOT_WIDGET_MATRIX].data >> 8;
+ uint16 boxes_in_each_row = this->widget[DEPOT_WIDGET_MATRIX].data & 0xFF;
+
+ /* setup disabled buttons */
+ this->SetWidgetsDisabledState(!IsTileOwner(tile, _local_player),
+ DEPOT_WIDGET_STOP_ALL,
+ DEPOT_WIDGET_START_ALL,
+ DEPOT_WIDGET_SELL,
+ DEPOT_WIDGET_SELL_CHAIN,
+ DEPOT_WIDGET_SELL_ALL,
+ DEPOT_WIDGET_BUILD,
+ DEPOT_WIDGET_CLONE,
+ DEPOT_WIDGET_AUTOREPLACE,
+ WIDGET_LIST_END);
+
+ /* determine amount of items for scroller */
+ if (this->type == VEH_TRAIN) {
+ hnum = 8;
+ for (num = 0; num < this->engine_count; num++) {
+ const Vehicle *v = vl[num];
+ hnum = max(hnum, v->u.rail.cached_total_length);
+ }
+ /* Always have 1 empty row, so people can change the setting of the train */
+ SetVScrollCount(w, this->engine_count + this->wagon_count + 1);
+ SetHScrollCount(w, WagonLengthToPixels(hnum));
+ } else {
+ SetVScrollCount(w, (num + this->hscroll.cap - 1) / this->hscroll.cap);
+ }
+
+ /* locate the depot struct */
+ if (this->type == VEH_AIRCRAFT) {
+ SetDParam(0, GetStationIndex(tile)); // Airport name
+ } else {
+ Depot *depot = GetDepotByTile(tile);
+ assert(depot != NULL);
+
+ SetDParam(0, depot->town_index);
+ }
+
+ w->DrawWidgets();
+
+ num = this->vscroll.pos * boxes_in_each_row;
+ maxval = min(this->engine_count, num + (rows_in_display * boxes_in_each_row));
+
+ for (x = 2, y = 15; num < maxval; y += this->resize.step_height, x = 2) { // Draw the rows
+ byte i;
+
+ for (i = 0; i < boxes_in_each_row && num < maxval; i++, num++, x += this->resize.step_width) {
+ /* Draw all vehicles in the current row */
+ const Vehicle *v = vl[num];
+ DrawVehicleInDepot(w, v, x, y);
+ }
+ }
+
+ maxval = min(this->engine_count + this->wagon_count, (this->vscroll.pos * boxes_in_each_row) + (rows_in_display * boxes_in_each_row));
+
+ /* draw the train wagons, that do not have an engine in front */
+ for (; num < maxval; num++, y += 14) {
+ const Vehicle *v = this->wagon_list[num - this->engine_count];
+ const Vehicle *u;
+
+ DrawTrainImage(v, x + 50, y, this->sel, this->hscroll.cap - 29, 0);
+ DrawString(x, y + 2, STR_8816, TC_FROMSTRING);
+
+ /*Draw the train counter */
+ i = 0;
+ u = v;
+ do i++; while ((u = u->Next()) != NULL); // Determine length of train
+ SetDParam(0, i); // Set the counter
+ DrawStringRightAligned(this->widget[DEPOT_WIDGET_MATRIX].right - 1, y + 4, STR_TINY_BLACK, TC_FROMSTRING); // Draw the counter
+ }
+ }
+
+ struct GetDepotVehiclePtData {
+ Vehicle *head;
+ Vehicle *wagon;
+ };
+
+ enum DepotGUIAction {
+ MODE_ERROR,
+ MODE_DRAG_VEHICLE,
+ MODE_SHOW_VEHICLE,
+ MODE_START_STOP,
+ };
+
+ DepotGUIAction GetVehicleFromDepotWndPt(int x, int y, Vehicle **veh, GetDepotVehiclePtData *d) const
+ {
+ Vehicle **vl = this->vehicle_list;
+ uint xt, row, xm = 0, ym = 0;
+ int pos, skip = 0;
+ uint16 boxes_in_each_row = this->widget[DEPOT_WIDGET_MATRIX].data & 0xFF;
+
+ if (this->type == VEH_TRAIN) {
+ xt = 0;
+ x -= 23;
+ } else {
+ xt = x / this->resize.step_width;
+ xm = x % this->resize.step_width;
+ if (xt >= this->hscroll.cap) return MODE_ERROR;
+
+ ym = (y - 14) % this->resize.step_height;
+ }
+
+ row = (y - 14) / this->resize.step_height;
+ if (row >= this->vscroll.cap) return MODE_ERROR;
+
+ pos = ((row + this->vscroll.pos) * boxes_in_each_row) + xt;
+
+ if (this->engine_count + this->wagon_count <= pos) {
+ if (this->type == VEH_TRAIN) {
+ d->head = NULL;
+ d->wagon = NULL;
+ return MODE_DRAG_VEHICLE;
+ } else {
+ return MODE_ERROR; // empty block, so no vehicle is selected
+ }
+ }
+
+ if (this->engine_count > pos) {
+ *veh = vl[pos];
+ skip = this->hscroll.pos;
+ } else {
+ vl = this->wagon_list;
+ pos -= this->engine_count;
+ *veh = vl[pos];
+ /* free wagons don't have an initial loco. */
+ x -= _traininfo_vehicle_width;
+ }
+
+ switch (this->type) {
+ case VEH_TRAIN: {
+ Vehicle *v = *veh;
+ d->head = d->wagon = v;
+
+ /* either pressed the flag or the number, but only when it's a loco */
+ if (x < 0 && IsFrontEngine(v)) return (x >= -10) ? MODE_START_STOP : MODE_SHOW_VEHICLE;
+
+ skip = (skip * 8) / _traininfo_vehicle_width;
+ x = (x * 8) / _traininfo_vehicle_width;
+
+ /* Skip vehicles that are scrolled off the list */
+ x += skip;
+
+ /* find the vehicle in this row that was clicked */
+ while (v != NULL && (x -= v->u.rail.cached_veh_length) >= 0) v = v->Next();
+
+ /* if an articulated part was selected, find its parent */
+ while (v != NULL && IsArticulatedPart(v)) v = v->Previous();
+
+ d->wagon = v;
+
+ return MODE_DRAG_VEHICLE;
+ }
+ break;
+
+ case VEH_ROAD:
+ if (xm >= 24) return MODE_DRAG_VEHICLE;
+ if (xm <= 16) return MODE_SHOW_VEHICLE;
+ break;
+
+ case VEH_SHIP:
+ if (xm >= 19) return MODE_DRAG_VEHICLE;
+ if (ym <= 10) return MODE_SHOW_VEHICLE;
+ break;
+
+ case VEH_AIRCRAFT:
+ if (xm >= 12) return MODE_DRAG_VEHICLE;
+ if (ym <= 12) return MODE_SHOW_VEHICLE;
+ break;
+
+ default: NOT_REACHED();
+ }
+ return MODE_START_STOP;
+ }
+
+ void DepotClick(int x, int y)
+ {
+ GetDepotVehiclePtData gdvp = { NULL, NULL };
+ Vehicle *v = NULL;
+ DepotGUIAction mode = this->GetVehicleFromDepotWndPt(x, y, &v, &gdvp);
+
+ /* share / copy orders */
+ if (_thd.place_mode != VHM_NONE && mode != MODE_ERROR) {
+ _place_clicked_vehicle = (this->type == VEH_TRAIN ? gdvp.head : v);
+ return;
+ }
+
+ if (this->type == VEH_TRAIN) v = gdvp.wagon;
+
+ switch (mode) {
+ case MODE_ERROR: // invalid
+ return;
+
+ case MODE_DRAG_VEHICLE: { // start dragging of vehicle
+ VehicleID sel = this->sel;
+
+ if (this->type == VEH_TRAIN && sel != INVALID_VEHICLE) {
+ this->sel = INVALID_VEHICLE;
+ TrainDepotMoveVehicle(v, sel, gdvp.head);
+ } else if (v != NULL) {
+ int image = v->GetImage(DIR_W);
+
+ this->sel = v->index;
+ this->SetDirty();
+ SetObjectToPlaceWnd(image, GetVehiclePalette(v), VHM_DRAG, this);
+ _cursor.vehchain = _ctrl_pressed;
+ }
+ } break;
+
+ case MODE_SHOW_VEHICLE: // show info window
+ ShowVehicleViewWindow(v);
+ break;
+
+ case MODE_START_STOP: { // click start/stop flag
+ uint command;
+
+ switch (this->type) {
+ case VEH_TRAIN: command = CMD_START_STOP_TRAIN | CMD_MSG(STR_883B_CAN_T_STOP_START_TRAIN); break;
+ case VEH_ROAD: command = CMD_START_STOP_ROADVEH | CMD_MSG(STR_9015_CAN_T_STOP_START_ROAD_VEHICLE); break;
+ case VEH_SHIP: command = CMD_START_STOP_SHIP | CMD_MSG(STR_9818_CAN_T_STOP_START_SHIP); break;
+ case VEH_AIRCRAFT: command = CMD_START_STOP_AIRCRAFT | CMD_MSG(STR_A016_CAN_T_STOP_START_AIRCRAFT); break;
+ default: NOT_REACHED(); command = 0;
+ }
+ DoCommandP(v->tile, v->index, 0, NULL, command);
+ } break;
+
+ default: NOT_REACHED();
+ }
+ }
+
+ /**
+ * Clones a vehicle
+ * @param *v is the original vehicle to clone
+ * @param *w is the window of the depot where the clone is build
+ */
+ void HandleCloneVehClick(const Vehicle *v, const Window *w)
+ {
+ uint error_str;
+
+ if (v == NULL) return;
+
+ if (!v->IsPrimaryVehicle()) {
+ v = v->First();
+ /* Do nothing when clicking on a train in depot with no loc attached */
+ if (v->type == VEH_TRAIN && !IsFrontEngine(v)) return;
+ }
+
+ switch (v->type) {
+ case VEH_TRAIN: error_str = CMD_MSG(STR_882B_CAN_T_BUILD_RAILROAD_VEHICLE); break;
+ case VEH_ROAD: error_str = CMD_MSG(STR_9009_CAN_T_BUILD_ROAD_VEHICLE); break;
+ case VEH_SHIP: error_str = CMD_MSG(STR_980D_CAN_T_BUILD_SHIP); break;
+ case VEH_AIRCRAFT: error_str = CMD_MSG(STR_A008_CAN_T_BUILD_AIRCRAFT); break;
+ default: return;
+ }
+
+ DoCommandP(this->window_number, v->index, _ctrl_pressed ? 1 : 0, CcCloneVehicle, CMD_CLONE_VEHICLE | error_str);
+
+ ResetObjectToPlace();
+ }
+
+ void ResizeDepotButtons(Window *w)
+ {
+ ResizeButtons(w, DEPOT_WIDGET_BUILD, DEPOT_WIDGET_LOCATION);
+
+ if (this->type == VEH_TRAIN) {
+ /* Divide the size of DEPOT_WIDGET_SELL into two equally big buttons so DEPOT_WIDGET_SELL and DEPOT_WIDGET_SELL_CHAIN will get the same size.
+ * This way it will stay the same even if DEPOT_WIDGET_SELL_CHAIN is resized for some reason */
+ this->widget[DEPOT_WIDGET_SELL_CHAIN].top = ((this->widget[DEPOT_WIDGET_SELL_CHAIN].bottom - this->widget[DEPOT_WIDGET_SELL].top) / 2) + this->widget[DEPOT_WIDGET_SELL].top;
+ this->widget[DEPOT_WIDGET_SELL].bottom = this->widget[DEPOT_WIDGET_SELL_CHAIN].top - 1;
+ }
+ }
+
+ /* Function to set up vehicle specific sprites and strings
+ * Only use this if it's the same widget, that's used for more than one vehicle type and it needs different text/sprites
+ * Vehicle specific text/sprites, that's in a widget, that's only shown for one vehicle type (like sell whole train) is set in the widget array
+ */
+ void SetupStringsForDepotWindow(VehicleType type)
+ {
+ switch (type) {
+ default: NOT_REACHED();
+
+ case VEH_TRAIN:
+ this->widget[DEPOT_WIDGET_CAPTION].data = STR_8800_TRAIN_DEPOT;
+ this->widget[DEPOT_WIDGET_STOP_ALL].tooltips = STR_MASS_STOP_DEPOT_TRAIN_TIP;
+ this->widget[DEPOT_WIDGET_START_ALL].tooltips= STR_MASS_START_DEPOT_TRAIN_TIP;
+ this->widget[DEPOT_WIDGET_SELL].tooltips = STR_8841_DRAG_TRAIN_VEHICLE_TO_HERE;
+ this->widget[DEPOT_WIDGET_SELL_ALL].tooltips = STR_DEPOT_SELL_ALL_BUTTON_TRAIN_TIP;
+ this->widget[DEPOT_WIDGET_MATRIX].tooltips = STR_883F_TRAINS_CLICK_ON_TRAIN_FOR;
+
+ this->widget[DEPOT_WIDGET_BUILD].data = STR_8815_NEW_VEHICLES;
+ this->widget[DEPOT_WIDGET_BUILD].tooltips = STR_8840_BUILD_NEW_TRAIN_VEHICLE;
+ this->widget[DEPOT_WIDGET_CLONE].data = STR_CLONE_TRAIN;
+ this->widget[DEPOT_WIDGET_CLONE].tooltips = STR_CLONE_TRAIN_DEPOT_INFO;
+
+ this->widget[DEPOT_WIDGET_LOCATION].tooltips = STR_8842_CENTER_MAIN_VIEW_ON_TRAIN;
+ this->widget[DEPOT_WIDGET_VEHICLE_LIST].data = STR_TRAIN;
+ this->widget[DEPOT_WIDGET_VEHICLE_LIST].tooltips = STR_DEPOT_VEHICLE_ORDER_LIST_TRAIN_TIP;
+ this->widget[DEPOT_WIDGET_AUTOREPLACE].tooltips = STR_DEPOT_AUTOREPLACE_TRAIN_TIP;
+
+ /* Sprites */
+ this->widget[DEPOT_WIDGET_SELL].data = SPR_SELL_TRAIN;
+ this->widget[DEPOT_WIDGET_SELL_ALL].data = SPR_SELL_ALL_TRAIN;
+ this->widget[DEPOT_WIDGET_AUTOREPLACE].data = SPR_REPLACE_TRAIN;
+ break;
+
+ case VEH_ROAD:
+ this->widget[DEPOT_WIDGET_CAPTION].data = STR_9003_ROAD_VEHICLE_DEPOT;
+ this->widget[DEPOT_WIDGET_STOP_ALL].tooltips = STR_MASS_STOP_DEPOT_ROADVEH_TIP;
+ this->widget[DEPOT_WIDGET_START_ALL].tooltips= STR_MASS_START_DEPOT_ROADVEH_TIP;
+ this->widget[DEPOT_WIDGET_SELL].tooltips = STR_9024_DRAG_ROAD_VEHICLE_TO_HERE;
+ this->widget[DEPOT_WIDGET_SELL_ALL].tooltips = STR_DEPOT_SELL_ALL_BUTTON_ROADVEH_TIP;
+ this->widget[DEPOT_WIDGET_MATRIX].tooltips = STR_9022_VEHICLES_CLICK_ON_VEHICLE;
+
+ this->widget[DEPOT_WIDGET_BUILD].data = STR_9004_NEW_VEHICLES;
+ this->widget[DEPOT_WIDGET_BUILD].tooltips = STR_9023_BUILD_NEW_ROAD_VEHICLE;
+ this->widget[DEPOT_WIDGET_CLONE].data = STR_CLONE_ROAD_VEHICLE;
+ this->widget[DEPOT_WIDGET_CLONE].tooltips = STR_CLONE_ROAD_VEHICLE_DEPOT_INFO;
+
+ this->widget[DEPOT_WIDGET_LOCATION].tooltips = STR_9025_CENTER_MAIN_VIEW_ON_ROAD;
+ this->widget[DEPOT_WIDGET_VEHICLE_LIST].data = STR_LORRY;
+ this->widget[DEPOT_WIDGET_VEHICLE_LIST].tooltips = STR_DEPOT_VEHICLE_ORDER_LIST_ROADVEH_TIP;
+ this->widget[DEPOT_WIDGET_AUTOREPLACE].tooltips = STR_DEPOT_AUTOREPLACE_ROADVEH_TIP;
+
+ /* Sprites */
+ this->widget[DEPOT_WIDGET_SELL].data = SPR_SELL_ROADVEH;
+ this->widget[DEPOT_WIDGET_SELL_ALL].data = SPR_SELL_ALL_ROADVEH;
+ this->widget[DEPOT_WIDGET_AUTOREPLACE].data = SPR_REPLACE_ROADVEH;
+ break;
+
+ case VEH_SHIP:
+ this->widget[DEPOT_WIDGET_CAPTION].data = STR_9803_SHIP_DEPOT;
+ this->widget[DEPOT_WIDGET_STOP_ALL].tooltips = STR_MASS_STOP_DEPOT_SHIP_TIP;
+ this->widget[DEPOT_WIDGET_START_ALL].tooltips= STR_MASS_START_DEPOT_SHIP_TIP;
+ this->widget[DEPOT_WIDGET_SELL].tooltips = STR_9821_DRAG_SHIP_TO_HERE_TO_SELL;
+ this->widget[DEPOT_WIDGET_SELL_ALL].tooltips = STR_DEPOT_SELL_ALL_BUTTON_SHIP_TIP;
+ this->widget[DEPOT_WIDGET_MATRIX].tooltips = STR_981F_SHIPS_CLICK_ON_SHIP_FOR;
+
+ this->widget[DEPOT_WIDGET_BUILD].data = STR_9804_NEW_SHIPS;
+ this->widget[DEPOT_WIDGET_BUILD].tooltips = STR_9820_BUILD_NEW_SHIP;
+ this->widget[DEPOT_WIDGET_CLONE].data = STR_CLONE_SHIP;
+ this->widget[DEPOT_WIDGET_CLONE].tooltips = STR_CLONE_SHIP_DEPOT_INFO;
+
+ this->widget[DEPOT_WIDGET_LOCATION].tooltips = STR_9822_CENTER_MAIN_VIEW_ON_SHIP;
+ this->widget[DEPOT_WIDGET_VEHICLE_LIST].data = STR_SHIP;
+ this->widget[DEPOT_WIDGET_VEHICLE_LIST].tooltips = STR_DEPOT_VEHICLE_ORDER_LIST_SHIP_TIP;
+ this->widget[DEPOT_WIDGET_AUTOREPLACE].tooltips = STR_DEPOT_AUTOREPLACE_SHIP_TIP;
+
+ /* Sprites */
+ this->widget[DEPOT_WIDGET_SELL].data = SPR_SELL_SHIP;
+ this->widget[DEPOT_WIDGET_SELL_ALL].data = SPR_SELL_ALL_SHIP;
+ this->widget[DEPOT_WIDGET_AUTOREPLACE].data = SPR_REPLACE_SHIP;
+ break;
+
+ case VEH_AIRCRAFT:
+ this->widget[DEPOT_WIDGET_CAPTION].data = STR_A002_AIRCRAFT_HANGAR;
+ this->widget[DEPOT_WIDGET_STOP_ALL].tooltips = STR_MASS_STOP_HANGAR_TIP;
+ this->widget[DEPOT_WIDGET_START_ALL].tooltips= STR_MASS_START_HANGAR_TIP;
+ this->widget[DEPOT_WIDGET_SELL].tooltips = STR_A023_DRAG_AIRCRAFT_TO_HERE_TO;
+ this->widget[DEPOT_WIDGET_SELL_ALL].tooltips = STR_DEPOT_SELL_ALL_BUTTON_AIRCRAFT_TIP;
+ this->widget[DEPOT_WIDGET_MATRIX].tooltips = STR_A021_AIRCRAFT_CLICK_ON_AIRCRAFT;
+
+ this->widget[DEPOT_WIDGET_BUILD].data = STR_A003_NEW_AIRCRAFT;
+ this->widget[DEPOT_WIDGET_BUILD].tooltips = STR_A022_BUILD_NEW_AIRCRAFT;
+ this->widget[DEPOT_WIDGET_CLONE].data = STR_CLONE_AIRCRAFT;
+ this->widget[DEPOT_WIDGET_CLONE].tooltips = STR_CLONE_AIRCRAFT_INFO_HANGAR_WINDOW;
+
+ this->widget[DEPOT_WIDGET_LOCATION].tooltips = STR_A024_CENTER_MAIN_VIEW_ON_HANGAR;
+ this->widget[DEPOT_WIDGET_VEHICLE_LIST].data = STR_PLANE;
+ this->widget[DEPOT_WIDGET_VEHICLE_LIST].tooltips = STR_DEPOT_VEHICLE_ORDER_LIST_AIRCRAFT_TIP;
+ this->widget[DEPOT_WIDGET_AUTOREPLACE].tooltips = STR_DEPOT_AUTOREPLACE_AIRCRAFT_TIP;
+
+ /* Sprites */
+ this->widget[DEPOT_WIDGET_SELL].data = SPR_SELL_AIRCRAFT;
+ this->widget[DEPOT_WIDGET_SELL_ALL].data = SPR_SELL_ALL_AIRCRAFT;
+ this->widget[DEPOT_WIDGET_AUTOREPLACE].data = SPR_REPLACE_AIRCRAFT;
+ break;
+ }
+ }
+
+ void CreateDepotListWindow(VehicleType type)
+ {
+ this->type = type;
+ _backup_orders_tile = 0;
+
+ assert(IsPlayerBuildableVehicleType(type)); // ensure that we make the call with a valid type
+
+ /* Resize the window according to the vehicle type */
+
+ /* Set the number of blocks in each direction */
+ this->vscroll.cap = _resize_cap[type][0];
+ this->hscroll.cap = _resize_cap[type][1];
+
+ /* Set the block size */
+ this->resize.step_width = _block_sizes[type][0];
+ this->resize.step_height = _block_sizes[type][1];
+
+ /* Enlarge the window to fit with the selected number of blocks of the selected size */
+ ResizeWindow(this,
+ _block_sizes[type][0] * this->hscroll.cap,
+ _block_sizes[type][1] * this->vscroll.cap);
+
+ if (type == VEH_TRAIN) {
+ /* Make space for the horizontal scrollbar vertically, and the unit
+ * number, flag, and length counter horizontally. */
+ ResizeWindow(this, 36, 12);
+ /* substract the newly added space from the matrix since it was meant for the scrollbar */
+ this->widget[DEPOT_WIDGET_MATRIX].bottom -= 12;
+ }
+
+ /* Set the minimum window size to the current window size */
+ this->resize.width = this->width;
+ this->resize.height = this->height;
+
+ this->SetupStringsForDepotWindow(type);
+
+ this->widget[DEPOT_WIDGET_MATRIX].data =
+ (this->vscroll.cap * 0x100) // number of rows to draw on the background
+ + (type == VEH_TRAIN ? 1 : this->hscroll.cap); // number of boxes in each row. Trains always have just one
- w->SetWidgetsHiddenState(type != VEH_TRAIN,
- DEPOT_WIDGET_H_SCROLL,
- DEPOT_WIDGET_SELL_CHAIN,
- WIDGET_LIST_END);
-
- ResizeDepotButtons(w);
-}
-
-void DepotSortList(Vehicle **v, uint16 length);
-
-static void DepotWndProc(Window *w, WindowEvent *e)
-{
- switch (e->event) {
- case WE_CREATE:
- WP(w, depot_d).sel = INVALID_VEHICLE;
- WP(w, depot_d).vehicle_list = NULL;
- WP(w, depot_d).wagon_list = NULL;
- WP(w, depot_d).engine_count = 0;
- WP(w, depot_d).wagon_count = 0;
- WP(w, depot_d).generate_list = true;
- break;
-
- case WE_INVALIDATE_DATA:
- WP(w, depot_d).generate_list = true;
- break;
+ this->SetWidgetsHiddenState(type != VEH_TRAIN,
+ DEPOT_WIDGET_H_SCROLL,
+ DEPOT_WIDGET_SELL_CHAIN,
+ WIDGET_LIST_END);
- case WE_PAINT:
- if (WP(w, depot_d).generate_list) {
- /* Generate the vehicle list
- * It's ok to use the wagon pointers for non-trains as they will be ignored */
- BuildDepotVehicleList(WP(w, depot_d).type, w->window_number,
- &WP(w, depot_d).vehicle_list, &WP(w, depot_d).engine_list_length, &WP(w, depot_d).engine_count,
- &WP(w, depot_d).wagon_list, &WP(w, depot_d).wagon_list_length, &WP(w, depot_d).wagon_count);
- WP(w, depot_d).generate_list = false;
- DepotSortList(WP(w, depot_d).vehicle_list, WP(w, depot_d).engine_count);
-//#ifndef NDEBUG
-#if 0
-/* We disabled this check for now, but will keep it to quickly make this test again later (if we change some code) */
- } else {
- /* Here we got a piece of code, that only checks if we got a different number of vehicles in the depot list and the number of vehicles actually being in the depot.
- * IF they aren't the same, then WE_INVALIDATE_DATA should have been called somewhere, but it wasn't and we got a bug
- * Since this is a time consuming check and not nice to memory fragmentation, it may not stay for long, but it's a good way to check this
- * We can turn it on/off by switching between #ifndef NDEBUG and #if 0 */
- Vehicle **engines = NULL, **wagons = NULL;
- uint16 engine_count = 0, engine_length = 0;
- uint16 wagon_count = 0, wagon_length = 0;
- BuildDepotVehicleList(WP(w, depot_d).type, w->window_number, &engines, &engine_length, &engine_count,
- &wagons, &wagon_length, &wagon_count);
-
- assert(engine_count == WP(w, depot_d).engine_count);
- assert(wagon_count == WP(w, depot_d).wagon_count);
- free((void*)engines);
- free((void*)wagons);
-#endif
- }
- DrawDepotWindow(w);
- break;
+ ResizeDepotButtons(this);
+ }
- case WE_CLICK:
- switch (e->we.click.widget) {
- case DEPOT_WIDGET_MATRIX: // List
- DepotClick(w, e->we.click.pt.x, e->we.click.pt.y);
- break;
-
- case DEPOT_WIDGET_BUILD: // Build vehicle
- ResetObjectToPlace();
- ShowBuildVehicleWindow(w->window_number, WP(w, depot_d).type);
- break;
-
- case DEPOT_WIDGET_CLONE: // Clone button
- w->InvalidateWidget(DEPOT_WIDGET_CLONE);
- w->ToggleWidgetLoweredState(DEPOT_WIDGET_CLONE);
+ virtual void OnInvalidateData(int data)
+ {
+ this->generate_list = true;
+ }
- if (w->IsWidgetLowered(DEPOT_WIDGET_CLONE)) {
- static const CursorID clone_icons[] = {
- SPR_CURSOR_CLONE_TRAIN, SPR_CURSOR_CLONE_ROADVEH,
- SPR_CURSOR_CLONE_SHIP, SPR_CURSOR_CLONE_AIRPLANE
- };
+ virtual void OnPaint()
+ {
+ if (this->generate_list) {
+ /* Generate the vehicle list
+ * It's ok to use the wagon pointers for non-trains as they will be ignored */
+ BuildDepotVehicleList(this->type, this->window_number,
+ &this->vehicle_list, &this->engine_list_length, &this->engine_count,
+ &this->wagon_list, &this->wagon_list_length, &this->wagon_count);
+ this->generate_list = false;
+ DepotSortList(this->vehicle_list, this->engine_count);
+ }
+ DrawDepotWindow(this);
+ }
- _place_clicked_vehicle = NULL;
- SetObjectToPlaceWnd(clone_icons[WP(w, depot_d).type], PAL_NONE, VHM_RECT, w);
- } else {
- ResetObjectToPlace();
- }
- break;
+ virtual void OnClick(Point pt, int widget)
+ {
+ switch (widget) {
+ case DEPOT_WIDGET_MATRIX: // List
+ this->DepotClick(pt.x, pt.y);
+ break;
- case DEPOT_WIDGET_LOCATION:
- if (_ctrl_pressed) {
- ShowExtraViewPortWindow(w->window_number);
- } else {
- ScrollMainWindowToTile(w->window_number);
- }
- break;
+ case DEPOT_WIDGET_BUILD: // Build vehicle
+ ResetObjectToPlace();
+ ShowBuildVehicleWindow(this->window_number, this->type);
+ break;
- case DEPOT_WIDGET_STOP_ALL:
- case DEPOT_WIDGET_START_ALL:
- DoCommandP(w->window_number, 0, WP(w, depot_d).type | (e->we.click.widget == DEPOT_WIDGET_START_ALL ? (1 << 5) : 0), NULL, CMD_MASS_START_STOP);
+ case DEPOT_WIDGET_CLONE: // Clone button
+ this->InvalidateWidget(DEPOT_WIDGET_CLONE);
+ this->ToggleWidgetLoweredState(DEPOT_WIDGET_CLONE);
+
+ if (this->IsWidgetLowered(DEPOT_WIDGET_CLONE)) {
+ static const CursorID clone_icons[] = {
+ SPR_CURSOR_CLONE_TRAIN, SPR_CURSOR_CLONE_ROADVEH,
+ SPR_CURSOR_CLONE_SHIP, SPR_CURSOR_CLONE_AIRPLANE
+ };
+
+ _place_clicked_vehicle = NULL;
+ SetObjectToPlaceWnd(clone_icons[this->type], PAL_NONE, VHM_RECT, this);
+ } else {
+ ResetObjectToPlace();
+ }
break;
- case DEPOT_WIDGET_SELL_ALL:
- /* Only open the confimation window if there are anything to sell */
- if (WP(w, depot_d).engine_count != 0 || WP(w, depot_d).wagon_count != 0) {
- static const StringID confirm_captions[] = {
- STR_8800_TRAIN_DEPOT,
- STR_9003_ROAD_VEHICLE_DEPOT,
- STR_9803_SHIP_DEPOT,
- STR_A002_AIRCRAFT_HANGAR
- };
- TileIndex tile = w->window_number;
- byte vehtype = WP(w, depot_d).type;
-
- SetDParam(0, (vehtype == VEH_AIRCRAFT) ? GetStationIndex(tile) : GetDepotByTile(tile)->town_index);
- ShowQuery(
- confirm_captions[vehtype],
- STR_DEPOT_SELL_CONFIRMATION_TEXT,
- w,
- DepotSellAllConfirmationCallback
- );
- }
- break;
-
- case DEPOT_WIDGET_VEHICLE_LIST:
- ShowVehicleListWindow(GetTileOwner(w->window_number), WP(w, depot_d).type, (TileIndex)w->window_number);
- break;
-
- case DEPOT_WIDGET_AUTOREPLACE:
- DoCommandP(w->window_number, WP(w, depot_d).type, 0, NULL, CMD_DEPOT_MASS_AUTOREPLACE);
- break;
-
- }
- break;
-
- case WE_PLACE_OBJ: {
- ClonePlaceObj(w);
- } break;
-
- case WE_ABORT_PLACE_OBJ: {
- /* abort clone */
- w->RaiseWidget(DEPOT_WIDGET_CLONE);
- w->InvalidateWidget(DEPOT_WIDGET_CLONE);
-
- /* abort drag & drop */
- WP(w, depot_d).sel = INVALID_VEHICLE;
- w->InvalidateWidget(DEPOT_WIDGET_MATRIX);
- } break;
-
- /* check if a vehicle in a depot was clicked.. */
- case WE_MOUSELOOP: {
- const Vehicle *v = _place_clicked_vehicle;
-
- /* since OTTD checks all open depot windows, we will make sure that it triggers the one with a clicked clone button */
- if (v != NULL && w->IsWidgetLowered(DEPOT_WIDGET_CLONE)) {
- _place_clicked_vehicle = NULL;
- HandleCloneVehClick(v, w);
- }
- } break;
-
- case WE_DESTROY:
- DeleteWindowById(WC_BUILD_VEHICLE, w->window_number);
- free((void*)WP(w, depot_d).vehicle_list);
- free((void*)WP(w, depot_d).wagon_list);
- break;
-
- case WE_DRAGDROP:
- switch (e->we.click.widget) {
- case DEPOT_WIDGET_MATRIX: {
- Vehicle *v;
- VehicleID sel = WP(w, depot_d).sel;
-
- WP(w, depot_d).sel = INVALID_VEHICLE;
- w->SetDirty();
+ case DEPOT_WIDGET_LOCATION:
+ if (_ctrl_pressed) {
+ ShowExtraViewPortWindow(this->window_number);
+ } else {
+ ScrollMainWindowToTile(this->window_number);
+ }
+ break;
- if (WP(w, depot_d).type == VEH_TRAIN) {
- GetDepotVehiclePtData gdvp;
-
- if (GetVehicleFromDepotWndPt(w, e->we.dragdrop.pt.x, e->we.dragdrop.pt.y, &v, &gdvp) == MODE_DRAG_VEHICLE &&
- sel != INVALID_VEHICLE) {
- if (gdvp.wagon != NULL && gdvp.wagon->index == sel && _ctrl_pressed) {
- DoCommandP(GetVehicle(sel)->tile, GetVehicle(sel)->index, true, NULL, CMD_REVERSE_TRAIN_DIRECTION | CMD_MSG(STR_9033_CAN_T_MAKE_VEHICLE_TURN));
- } else if (gdvp.wagon == NULL || gdvp.wagon->index != sel) {
- TrainDepotMoveVehicle(gdvp.wagon, sel, gdvp.head);
- } else if (gdvp.head != NULL && IsFrontEngine(gdvp.head)) {
- ShowVehicleViewWindow(gdvp.head);
- }
- }
- } else if (GetVehicleFromDepotWndPt(w, e->we.dragdrop.pt.x, e->we.dragdrop.pt.y, &v, NULL) == MODE_DRAG_VEHICLE &&
- v != NULL &&
- sel == v->index) {
- ShowVehicleViewWindow(v);
- }
- } break;
-
- case DEPOT_WIDGET_SELL: case DEPOT_WIDGET_SELL_CHAIN:
- if (!w->IsWidgetDisabled(DEPOT_WIDGET_SELL) &&
- WP(w, depot_d).sel != INVALID_VEHICLE) {
- Vehicle *v;
- uint command;
- int sell_cmd;
- bool is_engine;
-
- if (w->IsWidgetDisabled(e->we.click.widget)) return;
- if (WP(w, depot_d).sel == INVALID_VEHICLE) return;
-
- w->HandleButtonClick(e->we.click.widget);
-
- v = GetVehicle(WP(w, depot_d).sel);
- WP(w, depot_d).sel = INVALID_VEHICLE;
- w->SetDirty();
+ case DEPOT_WIDGET_STOP_ALL:
+ case DEPOT_WIDGET_START_ALL:
+ DoCommandP(this->window_number, 0, this->type | (widget == DEPOT_WIDGET_START_ALL ? (1 << 5) : 0), NULL, CMD_MASS_START_STOP);
+ break;
- sell_cmd = (v->type == VEH_TRAIN && (e->we.click.widget == DEPOT_WIDGET_SELL_CHAIN || _ctrl_pressed)) ? 1 : 0;
-
- is_engine = (!(v->type == VEH_TRAIN && !IsFrontEngine(v)));
-
- if (is_engine) {
- _backup_orders_tile = v->tile;
- BackupVehicleOrders(v);
- }
+ case DEPOT_WIDGET_SELL_ALL:
+ /* Only open the confimation window if there are anything to sell */
+ if (this->engine_count != 0 || this->wagon_count != 0) {
+ static const StringID confirm_captions[] = {
+ STR_8800_TRAIN_DEPOT,
+ STR_9003_ROAD_VEHICLE_DEPOT,
+ STR_9803_SHIP_DEPOT,
+ STR_A002_AIRCRAFT_HANGAR
+ };
+ TileIndex tile = this->window_number;
+ byte vehtype = this->type;
- switch (v->type) {
- case VEH_TRAIN: command = CMD_SELL_RAIL_WAGON | CMD_MSG(STR_8839_CAN_T_SELL_RAILROAD_VEHICLE); break;
- case VEH_ROAD: command = CMD_SELL_ROAD_VEH | CMD_MSG(STR_9014_CAN_T_SELL_ROAD_VEHICLE); break;
- case VEH_SHIP: command = CMD_SELL_SHIP | CMD_MSG(STR_980C_CAN_T_SELL_SHIP); break;
- case VEH_AIRCRAFT: command = CMD_SELL_AIRCRAFT | CMD_MSG(STR_A01C_CAN_T_SELL_AIRCRAFT); break;
- default: NOT_REACHED(); command = 0;
+ SetDParam(0, (vehtype == VEH_AIRCRAFT) ? GetStationIndex(tile) : GetDepotByTile(tile)->town_index);
+ ShowQuery(
+ confirm_captions[vehtype],
+ STR_DEPOT_SELL_CONFIRMATION_TEXT,
+ this,
+ DepotSellAllConfirmationCallback
+ );
+ }
+ break;
+
+ case DEPOT_WIDGET_VEHICLE_LIST:
+ ShowVehicleListWindow(GetTileOwner(this->window_number), this->type, (TileIndex)this->window_number);
+ break;
+
+ case DEPOT_WIDGET_AUTOREPLACE:
+ DoCommandP(this->window_number, this->type, 0, NULL, CMD_DEPOT_MASS_AUTOREPLACE);
+ break;
+
+ }
+ }
+
+ virtual void OnPlaceObject(Point pt, TileIndex tile)
+ {
+ const Vehicle *v = CheckMouseOverVehicle();
+
+ if (v != NULL) HandleCloneVehClick(v, this);
+ }
+
+ virtual void OnPlaceObjectAbort()
+ {
+ /* abort clone */
+ this->RaiseWidget(DEPOT_WIDGET_CLONE);
+ this->InvalidateWidget(DEPOT_WIDGET_CLONE);
+
+ /* abort drag & drop */
+ this->sel = INVALID_VEHICLE;
+ this->InvalidateWidget(DEPOT_WIDGET_MATRIX);
+ };
+
+ /* check if a vehicle in a depot was clicked.. */
+ virtual void OnMouseLoop()
+ {
+ const Vehicle *v = _place_clicked_vehicle;
+
+ /* since OTTD checks all open depot windows, we will make sure that it triggers the one with a clicked clone button */
+ if (v != NULL && this->IsWidgetLowered(DEPOT_WIDGET_CLONE)) {
+ _place_clicked_vehicle = NULL;
+ HandleCloneVehClick(v, this);
+ }
+ }
+
+ virtual void OnDragDrop(Point pt, int widget)
+ {
+ switch (widget) {
+ case DEPOT_WIDGET_MATRIX: {
+ Vehicle *v;
+ VehicleID sel = this->sel;
+
+ this->sel = INVALID_VEHICLE;
+ this->SetDirty();
+
+ if (this->type == VEH_TRAIN) {
+ GetDepotVehiclePtData gdvp = { NULL, NULL };
+
+ if (this->GetVehicleFromDepotWndPt(pt.x, pt.y, &v, &gdvp) == MODE_DRAG_VEHICLE &&
+ sel != INVALID_VEHICLE) {
+ if (gdvp.wagon != NULL && gdvp.wagon->index == sel && _ctrl_pressed) {
+ DoCommandP(GetVehicle(sel)->tile, GetVehicle(sel)->index, true, NULL, CMD_REVERSE_TRAIN_DIRECTION | CMD_MSG(STR_9033_CAN_T_MAKE_VEHICLE_TURN));
+ } else if (gdvp.wagon == NULL || gdvp.wagon->index != sel) {
+ TrainDepotMoveVehicle(gdvp.wagon, sel, gdvp.head);
+ } else if (gdvp.head != NULL && IsFrontEngine(gdvp.head)) {
+ ShowVehicleViewWindow(gdvp.head);
}
-
- if (!DoCommandP(v->tile, v->index, sell_cmd, NULL, command) && is_engine) _backup_orders_tile = 0;
}
- break;
- default:
- WP(w, depot_d).sel = INVALID_VEHICLE;
- w->SetDirty();
- }
- _cursor.vehchain = false;
- break;
+ } else if (this->GetVehicleFromDepotWndPt(pt.x, pt.y, &v, NULL) == MODE_DRAG_VEHICLE &&
+ v != NULL &&
+ sel == v->index) {
+ ShowVehicleViewWindow(v);
+ }
+ } break;
- case WE_RESIZE:
- w->vscroll.cap += e->we.sizing.diff.y / (int)w->resize.step_height;
- w->hscroll.cap += e->we.sizing.diff.x / (int)w->resize.step_width;
- w->widget[DEPOT_WIDGET_MATRIX].data = (w->vscroll.cap << 8) + (WP(w, depot_d).type == VEH_TRAIN ? 1 : w->hscroll.cap);
- ResizeDepotButtons(w);
- break;
+ case DEPOT_WIDGET_SELL: case DEPOT_WIDGET_SELL_CHAIN:
+ if (!this->IsWidgetDisabled(DEPOT_WIDGET_SELL) &&
+ this->sel != INVALID_VEHICLE) {
+ Vehicle *v;
+ uint command;
+ int sell_cmd;
+ bool is_engine;
- case WE_CTRL_CHANGED:
- if (WP(w, depot_d).sel != INVALID_VEHICLE) {
- _cursor.vehchain = _ctrl_pressed;
- w->InvalidateWidget(DEPOT_WIDGET_MATRIX);
- }
- break;
+ if (this->IsWidgetDisabled(widget)) return;
+ if (this->sel == INVALID_VEHICLE) return;
+
+ this->HandleButtonClick(widget);
+
+ v = GetVehicle(this->sel);
+ this->sel = INVALID_VEHICLE;
+ this->SetDirty();
+
+ sell_cmd = (v->type == VEH_TRAIN && (widget == DEPOT_WIDGET_SELL_CHAIN || _ctrl_pressed)) ? 1 : 0;
+
+ is_engine = (!(v->type == VEH_TRAIN && !IsFrontEngine(v)));
+
+ if (is_engine) {
+ _backup_orders_tile = v->tile;
+ BackupVehicleOrders(v);
+ }
+
+ switch (v->type) {
+ case VEH_TRAIN: command = CMD_SELL_RAIL_WAGON | CMD_MSG(STR_8839_CAN_T_SELL_RAILROAD_VEHICLE); break;
+ case VEH_ROAD: command = CMD_SELL_ROAD_VEH | CMD_MSG(STR_9014_CAN_T_SELL_ROAD_VEHICLE); break;
+ case VEH_SHIP: command = CMD_SELL_SHIP | CMD_MSG(STR_980C_CAN_T_SELL_SHIP); break;
+ case VEH_AIRCRAFT: command = CMD_SELL_AIRCRAFT | CMD_MSG(STR_A01C_CAN_T_SELL_AIRCRAFT); break;
+ default: NOT_REACHED(); command = 0;
+ }
+
+ if (!DoCommandP(v->tile, v->index, sell_cmd, NULL, command) && is_engine) _backup_orders_tile = 0;
+ }
+ break;
+ default:
+ this->sel = INVALID_VEHICLE;
+ this->SetDirty();
+ }
+ _cursor.vehchain = false;
+ }
+
+ virtual void OnResize(Point new_size, Point delta)
+ {
+ this->vscroll.cap += delta.y / (int)this->resize.step_height;
+ this->hscroll.cap += delta.x / (int)this->resize.step_width;
+ this->widget[DEPOT_WIDGET_MATRIX].data = (this->vscroll.cap << 8) + (this->type == VEH_TRAIN ? 1 : this->hscroll.cap);
+ ResizeDepotButtons(this);
+ }
+
+ virtual EventState OnCTRLStateChange()
+ {
+ if (this->sel != INVALID_VEHICLE) {
+ _cursor.vehchain = _ctrl_pressed;
+ this->InvalidateWidget(DEPOT_WIDGET_MATRIX);
+ }
+
+ return ES_HANDLED;
+ }
+};
+
+static void DepotSellAllConfirmationCallback(Window *win, bool confirmed)
+{
+ if (confirmed) {
+ DepotWindow *w = (DepotWindow*)win;
+ TileIndex tile = w->window_number;
+ byte vehtype = w->type;
+ DoCommandP(tile, vehtype, 0, NULL, CMD_DEPOT_SELL_ALL_VEHICLES);
}
}
@@ -1006,24 +984,24 @@
*/
void ShowDepotWindow(TileIndex tile, VehicleType type)
{
- Window *w;
+ DepotWindow *w;
switch (type) {
default: NOT_REACHED();
case VEH_TRAIN:
- w = AllocateWindowDescFront<Window>(&_train_depot_desc, tile); break;
+ w = AllocateWindowDescFront<DepotWindow>(&_train_depot_desc, tile); break;
case VEH_ROAD:
- w = AllocateWindowDescFront<Window>(&_road_depot_desc, tile); break;
+ w = AllocateWindowDescFront<DepotWindow>(&_road_depot_desc, tile); break;
case VEH_SHIP:
- w = AllocateWindowDescFront<Window>(&_ship_depot_desc, tile); break;
+ w = AllocateWindowDescFront<DepotWindow>(&_ship_depot_desc, tile); break;
case VEH_AIRCRAFT:
- w = AllocateWindowDescFront<Window>(&_aircraft_depot_desc, tile); break;
+ w = AllocateWindowDescFront<DepotWindow>(&_aircraft_depot_desc, tile); break;
}
- if (w != NULL) {
- w->caption_color = GetTileOwner(tile);
- CreateDepotListWindow(w, type);
- }
+ if (w == NULL) return;
+
+ w->caption_color = GetTileOwner(tile);
+ w->CreateDepotListWindow(type);
}
/** Removes the highlight of a vehicle in a depot window
@@ -1031,15 +1009,16 @@
*/
void DeleteDepotHighlightOfVehicle(const Vehicle *v)
{
- Window *w;
+ DepotWindow *w;
/* If we haven't got any vehicles on the mouse pointer, we haven't got any highlighted in any depots either
- * If that is the case, we can skip looping though the windows and save time */
+ * If that is the case, we can skip looping though the windows and save time
+ */
if (_special_mouse_mode != WSM_DRAGDROP) return;
- w = FindWindowById(WC_VEHICLE_DEPOT, v->tile);
+ w = dynamic_cast<DepotWindow*>(FindWindowById(WC_VEHICLE_DEPOT, v->tile));
if (w != NULL) {
- WP(w, depot_d).sel = INVALID_VEHICLE;
+ w->sel = INVALID_VEHICLE;
ResetObjectToPlace();
}
}
--- a/src/disaster_cmd.cpp Mon May 19 14:14:33 2008 +0000
+++ b/src/disaster_cmd.cpp Mon May 19 15:13:58 2008 +0000
@@ -234,7 +234,7 @@
SetDParam(0, GetStationIndex(tile));
AddNewsItem(STR_B000_ZEPPELIN_DISASTER_AT,
- NM_THIN, NF_VIEWPORT | NF_VEHICLE, NT_ACCIDENT, DNC_NONE,
+ NS_ACCIDENT_VEHICLE,
v->index,
0);
}
@@ -367,7 +367,7 @@
u->vehstatus |= VS_CRASHED;
AddNewsItem(STR_B001_ROAD_VEHICLE_DESTROYED,
- NM_THIN, NF_VIEWPORT | NF_VEHICLE, NT_ACCIDENT, DNC_NONE,
+ NS_ACCIDENT_VEHICLE,
u->index,
0);
}
@@ -442,7 +442,7 @@
DestructIndustry(i);
SetDParam(0, i->town->index);
- AddNewsItem(STR_B002_OIL_REFINERY_EXPLOSION, NM_THIN, NF_VIEWPORT | NF_TILE, NT_ACCIDENT, DNC_NONE, i->xy, 0);
+ AddNewsItem(STR_B002_OIL_REFINERY_EXPLOSION, NS_ACCIDENT_TILE, i->xy, 0);
SndPlayTileFx(SND_12_EXPLOSION, i->xy);
}
} else if (v->current_order.GetDestination() == 0) {
@@ -515,7 +515,7 @@
DestructIndustry(i);
SetDParam(0, i->town->index);
- AddNewsItem(STR_B003_FACTORY_DESTROYED_IN_SUSPICIOUS, NM_THIN, NF_VIEWPORT | NF_TILE, NT_ACCIDENT, DNC_NONE, i->xy, 0);
+ AddNewsItem(STR_B003_FACTORY_DESTROYED_IN_SUSPICIOUS, NS_ACCIDENT_TILE, i->xy, 0);
SndPlayTileFx(SND_12_EXPLOSION, i->xy);
}
} else if (v->current_order.GetDestination() == 0) {
@@ -600,7 +600,7 @@
t = ClosestTownFromTile(v->dest_tile, (uint)-1);
SetDParam(0, t->index);
AddNewsItem(STR_B004_UFO_LANDS_NEAR,
- NM_THIN, NF_VIEWPORT | NF_TILE, NT_ACCIDENT, DNC_NONE,
+ NS_ACCIDENT_TILE,
v->tile,
0);
@@ -978,7 +978,7 @@
if ((GetIndustrySpec(i->type)->behaviour & INDUSTRYBEH_CAN_SUBSIDENCE) && --index < 0) {
SetDParam(0, i->town->index);
AddNewsItem(STR_B005_COAL_MINE_SUBSIDENCE_LEAVES,
- NM_THIN, NF_VIEWPORT | NF_TILE, NT_ACCIDENT, DNC_NONE, i->xy + TileDiffXY(1, 1), 0);
+ NS_ACCIDENT_TILE, i->xy + TileDiffXY(1, 1), 0);
{
TileIndex tile = i->xy;
--- a/src/dock_gui.cpp Mon May 19 14:14:33 2008 +0000
+++ b/src/dock_gui.cpp Mon May 19 15:13:58 2008 +0000
@@ -125,80 +125,85 @@
BuildDocksClick_Buoy
};
-static void BuildDocksToolbWndProc(Window *w, WindowEvent *e)
-{
- switch (e->event) {
- case WE_PAINT:
- DrawWindowWidgets(w);
- w->SetWidgetsDisabledState(!CanBuildVehicleInfrastructure(VEH_SHIP), 7, 8, 9, WIDGET_LIST_END);
- break;
-
- case WE_CLICK:
- if (e->we.click.widget - 3 >= 0 && e->we.click.widget != 5) _build_docks_button_proc[e->we.click.widget - 3](w);
- break;
-
- case WE_KEYPRESS:
- switch (e->we.keypress.keycode) {
- case '1': BuildDocksClick_Canal(w); break;
- case '2': BuildDocksClick_Lock(w); break;
- case '3': BuildDocksClick_Demolish(w); break;
- case '4': BuildDocksClick_Depot(w); break;
- case '5': BuildDocksClick_Dock(w); break;
- case '6': BuildDocksClick_Buoy(w); break;
- default: return;
- }
- break;
-
- case WE_PLACE_OBJ:
- _place_proc(e->we.place.tile);
- break;
-
- case WE_PLACE_DRAG: {
- VpSelectTilesWithMethod(e->we.place.pt.x, e->we.place.pt.y, e->we.place.select_method);
- return;
+struct BuildDocksToolbarWindow : Window {
+ BuildDocksToolbarWindow(const WindowDesc *desc, WindowNumber window_number) : Window(desc, window_number)
+ {
+ this->FindWindowPlacementAndResize(desc);
+ if (_patches.link_terraform_toolbar) ShowTerraformToolbar(this);
}
- case WE_PLACE_MOUSEUP:
- if (e->we.place.pt.x != -1) {
- switch (e->we.place.select_proc) {
+ ~BuildDocksToolbarWindow()
+ {
+ if (_patches.link_terraform_toolbar) DeleteWindowById(WC_SCEN_LAND_GEN, 0);
+ }
+
+ virtual void OnPaint()
+ {
+ this->SetWidgetsDisabledState(!CanBuildVehicleInfrastructure(VEH_SHIP), 7, 8, 9, WIDGET_LIST_END);
+ this->DrawWidgets();
+ }
+
+ virtual void OnClick(Point pt, int widget)
+ {
+ if (widget - 3 >= 0 && widget != 5) _build_docks_button_proc[widget - 3](this);
+ }
+
+ virtual EventState OnKeyPress(uint16 key, uint16 keycode)
+ {
+ switch (keycode) {
+ case '1': BuildDocksClick_Canal(this); break;
+ case '2': BuildDocksClick_Lock(this); break;
+ case '3': BuildDocksClick_Demolish(this); break;
+ case '4': BuildDocksClick_Depot(this); break;
+ case '5': BuildDocksClick_Dock(this); break;
+ case '6': BuildDocksClick_Buoy(this); break;
+ default: return ES_NOT_HANDLED;
+ }
+ return ES_HANDLED;
+ }
+
+ virtual void OnPlaceObject(Point pt, TileIndex tile)
+ {
+ _place_proc(tile);
+ }
+
+ virtual void OnPlaceDrag(ViewportPlaceMethod select_method, ViewportDragDropSelectionProcess select_proc, Point pt)
+ {
+ VpSelectTilesWithMethod(pt.x, pt.y, select_method);
+ }
+
+ virtual void OnPlaceMouseUp(ViewportPlaceMethod select_method, ViewportDragDropSelectionProcess select_proc, Point pt, TileIndex start_tile, TileIndex end_tile)
+ {
+ if (pt.x != -1) {
+ switch (select_proc) {
case DDSP_DEMOLISH_AREA:
- GUIPlaceProcDragXY(e);
+ GUIPlaceProcDragXY(select_proc, start_tile, end_tile);
break;
case DDSP_CREATE_WATER:
- DoCommandP(e->we.place.tile, e->we.place.starttile, 0, CcBuildCanal, CMD_BUILD_CANAL | CMD_MSG(STR_CANT_BUILD_CANALS));
+ DoCommandP(end_tile, start_tile, 0, CcBuildCanal, CMD_BUILD_CANAL | CMD_MSG(STR_CANT_BUILD_CANALS));
break;
+
default: break;
}
}
- break;
-
- case WE_ABORT_PLACE_OBJ:
- w->RaiseButtons();
-
- w = FindWindowById(WC_BUILD_STATION, 0);
- if (w != NULL) WP(w, def_d).close = true;
+ }
- w = FindWindowById(WC_BUILD_DEPOT, 0);
- if (w != NULL) WP(w, def_d).close = true;
- break;
+ virtual void OnPlaceObjectAbort()
+ {
+ this->RaiseButtons();
- case WE_PLACE_PRESIZE: {
- TileIndex tile_from;
- TileIndex tile_to;
+ delete FindWindowById(WC_BUILD_STATION, 0);
+ delete FindWindowById(WC_BUILD_DEPOT, 0);
+ }
- tile_from = e->we.place.tile;
-
+ virtual void OnPlacePresize(Point pt, TileIndex tile_from)
+ {
DiagDirection dir = GetInclinedSlopeDirection(GetTileSlope(tile_from, NULL));
- tile_to = (dir != INVALID_DIAGDIR ? TileAddByDiagDir(tile_from, ReverseDiagDir(dir)) : tile_from);
+ TileIndex tile_to = (dir != INVALID_DIAGDIR ? TileAddByDiagDir(tile_from, ReverseDiagDir(dir)) : tile_from);
VpSetPresizeRange(tile_from, tile_to);
- } break;
-
- case WE_DESTROY:
- if (_patches.link_terraform_toolbar) DeleteWindowById(WC_SCEN_LAND_GEN, 0);
- break;
}
-}
+};
static const Widget _build_docks_toolb_widgets[] = {
{ WWT_CLOSEBOX, RESIZE_NONE, 7, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW},
@@ -221,7 +226,6 @@
WC_BUILD_TOOLBAR, WC_NONE,
WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_STICKY_BUTTON,
_build_docks_toolb_widgets,
- BuildDocksToolbWndProc
};
void ShowBuildDocksToolbar()
@@ -229,20 +233,32 @@
if (!IsValidPlayer(_current_player)) return;
DeleteWindowByClass(WC_BUILD_TOOLBAR);
- Window *w = AllocateWindowDescFront<Window>(&_build_docks_toolbar_desc, TRANSPORT_WATER);
- if (_patches.link_terraform_toolbar) ShowTerraformToolbar(w);
+ AllocateWindowDescFront<BuildDocksToolbarWindow>(&_build_docks_toolbar_desc, TRANSPORT_WATER);
}
-static void BuildDockStationWndProc(Window *w, WindowEvent *e)
-{
- switch (e->event) {
- case WE_CREATE: w->LowerWidget(_station_show_coverage + 3); break;
+struct BuildDocksStationWindow : public PickerWindowBase {
+private:
+ enum BuildDockStationWidgets {
+ BDSW_CLOSE,
+ BDSW_CAPTION,
+ BDSW_BACKGROUND,
+ BDSW_LT_OFF,
+ BDSW_LT_ON,
+ BDSW_INFO,
+ };
- case WE_PAINT: {
+public:
+ BuildDocksStationWindow(const WindowDesc *desc) : PickerWindowBase(desc)
+ {
+ this->LowerWidget(_station_show_coverage + BDSW_LT_OFF);
+ this->FindWindowPlacementAndResize(desc);
+ }
+
+ virtual void OnPaint()
+ {
int rad = (_patches.modified_catchment) ? CA_DOCK : CA_UNMODIFIED;
- if (WP(w, def_d).close) return;
- DrawWindowWidgets(w);
+ this->DrawWidgets();
if (_station_show_coverage) {
SetTileSelectBigSize(-rad, -rad, 2 * rad, 2 * rad);
@@ -252,50 +268,40 @@
int text_end = DrawStationCoverageAreaText(4, 50, SCT_ALL, rad, false);
text_end = DrawStationCoverageAreaText(4, text_end + 4, SCT_ALL, rad, true) + 4;
- if (text_end != w->widget[2].bottom) {
- w->SetDirty();
- ResizeWindowForWidget(w, 2, 0, text_end - w->widget[2].bottom);
- w->SetDirty();
+ if (text_end != this->widget[BDSW_BACKGROUND].bottom) {
+ this->SetDirty();
+ ResizeWindowForWidget(this, 2, 0, text_end - this->widget[BDSW_BACKGROUND].bottom);
+ this->SetDirty();
}
-
- break;
}
- case WE_CLICK:
- switch (e->we.click.widget) {
- case 3:
- case 4:
- w->RaiseWidget(_station_show_coverage + 3);
- _station_show_coverage = (e->we.click.widget != 3);
- w->LowerWidget(_station_show_coverage + 3);
+ virtual void OnClick(Point pt, int widget)
+ {
+ switch (widget) {
+ case BDSW_LT_OFF:
+ case BDSW_LT_ON:
+ this->RaiseWidget(_station_show_coverage + BDSW_LT_OFF);
+ _station_show_coverage = (widget != BDSW_LT_OFF);
+ this->LowerWidget(_station_show_coverage + BDSW_LT_OFF);
SndPlayFx(SND_15_BEEP);
- w->SetDirty();
+ this->SetDirty();
break;
}
- break;
-
- case WE_TICK:
- if (WP(w, def_d).close) {
- delete w;
- return;
- }
+ }
- CheckRedrawStationCoverage(w);
- break;
-
- case WE_DESTROY:
- if (!WP(w, def_d).close) ResetObjectToPlace();
- break;
+ virtual void OnTick()
+ {
+ CheckRedrawStationCoverage(this);
}
-}
+};
static const Widget _build_dock_station_widgets[] = {
-{ WWT_CLOSEBOX, RESIZE_NONE, 7, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW},
-{ WWT_CAPTION, RESIZE_NONE, 7, 11, 147, 0, 13, STR_3068_DOCK, STR_018C_WINDOW_TITLE_DRAG_THIS},
-{ WWT_PANEL, RESIZE_NONE, 7, 0, 147, 14, 74, 0x0, STR_NULL},
-{ WWT_TEXTBTN, RESIZE_NONE, 14, 14, 73, 30, 40, STR_02DB_OFF, STR_3065_DON_T_HIGHLIGHT_COVERAGE},
-{ WWT_TEXTBTN, RESIZE_NONE, 14, 74, 133, 30, 40, STR_02DA_ON, STR_3064_HIGHLIGHT_COVERAGE_AREA},
-{ WWT_LABEL, RESIZE_NONE, 7, 0, 147, 17, 30, STR_3066_COVERAGE_AREA_HIGHLIGHT, STR_NULL},
+{ WWT_CLOSEBOX, RESIZE_NONE, 7, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW}, // BDSW_CLOSE
+{ WWT_CAPTION, RESIZE_NONE, 7, 11, 147, 0, 13, STR_3068_DOCK, STR_018C_WINDOW_TITLE_DRAG_THIS}, // BDSW_CAPTION
+{ WWT_PANEL, RESIZE_NONE, 7, 0, 147, 14, 74, 0x0, STR_NULL}, // BDSW_BACKGROUND
+{ WWT_TEXTBTN, RESIZE_NONE, 14, 14, 73, 30, 40, STR_02DB_OFF, STR_3065_DON_T_HIGHLIGHT_COVERAGE}, // BDSW_LT_OFF
+{ WWT_TEXTBTN, RESIZE_NONE, 14, 74, 133, 30, 40, STR_02DA_ON, STR_3064_HIGHLIGHT_COVERAGE_AREA}, // BDSW_LT_ON
+{ WWT_LABEL, RESIZE_NONE, 7, 0, 147, 17, 30, STR_3066_COVERAGE_AREA_HIGHLIGHT, STR_NULL}, // BDSW_INFO
{ WIDGETS_END},
};
@@ -304,67 +310,72 @@
WC_BUILD_STATION, WC_BUILD_TOOLBAR,
WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET,
_build_dock_station_widgets,
- BuildDockStationWndProc
};
static void ShowBuildDockStationPicker()
{
- new Window(&_build_dock_station_desc);
+ new BuildDocksStationWindow(&_build_dock_station_desc);
}
-static void UpdateDocksDirection()
-{
- if (_ship_depot_direction != AXIS_X) {
- SetTileSelectSize(1, 2);
- } else {
- SetTileSelectSize(2, 1);
+struct BuildDocksDepotWindow : public PickerWindowBase {
+private:
+ enum BuildDockDepotWidgets {
+ BDDW_CLOSE,
+ BDDW_CAPTION,
+ BDDW_BACKGROUND,
+ BDDW_X,
+ BDDW_Y,
+ };
+
+ static void UpdateDocksDirection()
+ {
+ if (_ship_depot_direction != AXIS_X) {
+ SetTileSelectSize(1, 2);
+ } else {
+ SetTileSelectSize(2, 1);
+ }
}
-}
-static void BuildDocksDepotWndProc(Window *w, WindowEvent *e)
-{
- switch (e->event) {
- case WE_CREATE: w->LowerWidget(_ship_depot_direction + 3); break;
+public:
+ BuildDocksDepotWindow(const WindowDesc *desc) : PickerWindowBase(desc)
+ {
+ this->LowerWidget(_ship_depot_direction + BDDW_X);
+ UpdateDocksDirection();
+ this->FindWindowPlacementAndResize(desc);
+ }
- case WE_PAINT:
- DrawWindowWidgets(w);
+ virtual void OnPaint()
+ {
+ this->DrawWidgets();
DrawShipDepotSprite(67, 35, 0);
DrawShipDepotSprite(35, 51, 1);
DrawShipDepotSprite(135, 35, 2);
DrawShipDepotSprite(167, 51, 3);
- return;
+ }
- case WE_CLICK: {
- switch (e->we.click.widget) {
- case 3:
- case 4:
- w->RaiseWidget(_ship_depot_direction + 3);
- _ship_depot_direction = (e->we.click.widget == 3 ? AXIS_X : AXIS_Y);
- w->LowerWidget(_ship_depot_direction + 3);
- SndPlayFx(SND_15_BEEP);
- UpdateDocksDirection();
- w->SetDirty();
- break;
+ virtual void OnClick(Point pt, int widget)
+ {
+ switch (widget) {
+ case BDDW_X:
+ case BDDW_Y:
+ this->RaiseWidget(_ship_depot_direction + BDDW_X);
+ _ship_depot_direction = (widget == BDDW_X ? AXIS_X : AXIS_Y);
+ this->LowerWidget(_ship_depot_direction + BDDW_X);
+ SndPlayFx(SND_15_BEEP);
+ UpdateDocksDirection();
+ this->SetDirty();
+ break;
}
- } break;
-
- case WE_TICK:
- if (WP(w, def_d).close) delete w;
- break;
-
- case WE_DESTROY:
- if (!WP(w, def_d).close) ResetObjectToPlace();
- break;
}
-}
+};
static const Widget _build_docks_depot_widgets[] = {
-{ WWT_CLOSEBOX, RESIZE_NONE, 7, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW},
-{ WWT_CAPTION, RESIZE_NONE, 7, 11, 203, 0, 13, STR_3800_SHIP_DEPOT_ORIENTATION, STR_018C_WINDOW_TITLE_DRAG_THIS},
-{ WWT_PANEL, RESIZE_NONE, 7, 0, 203, 14, 85, 0x0, STR_NULL},
-{ WWT_PANEL, RESIZE_NONE, 14, 3, 100, 17, 82, 0x0, STR_3803_SELECT_SHIP_DEPOT_ORIENTATION},
-{ WWT_PANEL, RESIZE_NONE, 14, 103, 200, 17, 82, 0x0, STR_3803_SELECT_SHIP_DEPOT_ORIENTATION},
+{ WWT_CLOSEBOX, RESIZE_NONE, 7, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW}, // BDDW_CLOSE
+{ WWT_CAPTION, RESIZE_NONE, 7, 11, 203, 0, 13, STR_3800_SHIP_DEPOT_ORIENTATION, STR_018C_WINDOW_TITLE_DRAG_THIS}, // BDDW_CAPTION
+{ WWT_PANEL, RESIZE_NONE, 7, 0, 203, 14, 85, 0x0, STR_NULL}, // BDDW_BACKGROUND
+{ WWT_PANEL, RESIZE_NONE, 14, 3, 100, 17, 82, 0x0, STR_3803_SELECT_SHIP_DEPOT_ORIENTATION}, // BDDW_X
+{ WWT_PANEL, RESIZE_NONE, 14, 103, 200, 17, 82, 0x0, STR_3803_SELECT_SHIP_DEPOT_ORIENTATION}, // BDDW_Y
{ WIDGETS_END},
};
@@ -373,14 +384,12 @@
WC_BUILD_DEPOT, WC_BUILD_TOOLBAR,
WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET,
_build_docks_depot_widgets,
- BuildDocksDepotWndProc
};
static void ShowBuildDocksDepotPicker()
{
- new Window(&_build_docks_depot_desc);
- UpdateDocksDirection();
+ new BuildDocksDepotWindow(&_build_docks_depot_desc);
}
--- a/src/driver.h Mon May 19 14:14:33 2008 +0000
+++ b/src/driver.h Mon May 19 15:13:58 2008 +0000
@@ -43,7 +43,7 @@
static Drivers &GetDrivers()
{
- static Drivers s_drivers;
+ static Drivers &s_drivers = *new Drivers();
return s_drivers;
}
@@ -71,7 +71,14 @@
*/
virtual ~DriverFactoryBase() {
if (this->name == NULL) return;
- GetDrivers().erase(this->name);
+
+ /* Prefix the name with driver type to make it unique */
+ char buf[32];
+ strecpy(buf, GetDriverTypeName(type), lastof(buf));
+ strecpy(buf + 5, this->name, lastof(buf));
+
+ GetDrivers().erase(buf);
+ if (GetDrivers().empty()) delete &GetDrivers();
free(this->name);
}
--- a/src/economy.cpp Mon May 19 14:14:33 2008 +0000
+++ b/src/economy.cpp Mon May 19 15:13:58 2008 +0000
@@ -29,7 +29,6 @@
#include "newgrf_station.h"
#include "unmovable.h"
#include "cargotype.h"
-#include "player_face.h"
#include "group.h"
#include "strings_func.h"
#include "tile_cmd.h"
@@ -528,8 +527,10 @@
switch (p->quarters_of_bankrupcy) {
case 2:
- AddNewsItem((StringID)(owner | NB_BTROUBLE),
- NM_CALLBACK, NF_NONE, NT_COMPANY_INFO, DNC_BANKRUPCY, 0, 0);
+ SetDParam(0, STR_7056_TRANSPORT_COMPANY_IN_TROUBLE);
+ SetDParam(1, STR_7057_WILL_BE_SOLD_OFF_OR_DECLARED);
+ SetDParam(2, owner);
+ AddNewsItem(STR_02B6, NS_COMPANY_TROUBLE, 0, owner);
for (PlayerID i = PLAYER_FIRST; i < MAX_PLAYERS; i++) {
AI_Event(i, new AIEventCompanyInTrouble(owner));
}
@@ -538,8 +539,10 @@
/* XXX - In multiplayer, should we ask other players if it wants to take
over when it is a human company? -- TrueLight */
if (IsHumanPlayer(owner)) {
- AddNewsItem((StringID)(owner | NB_BTROUBLE),
- NM_CALLBACK, NF_NONE, NT_COMPANY_INFO, DNC_BANKRUPCY, 0, 0);
+ SetDParam(0, STR_7056_TRANSPORT_COMPANY_IN_TROUBLE);
+ SetDParam(1, STR_7057_WILL_BE_SOLD_OFF_OR_DECLARED);
+ SetDParam(2, owner);
+ AddNewsItem(STR_02B6, NS_COMPANY_TROUBLE, 0, owner);
break;
}
@@ -559,8 +562,10 @@
DeletePlayerWindows(owner);
/* Show bankrupt news */
- SetDParam(0, p->index);
- AddNewsItem((StringID)(owner | NB_BBANKRUPT), NM_CALLBACK, NF_NONE, NT_COMPANY_INFO, DNC_BANKRUPCY, 0, 0);
+ SetDParam(0, STR_705C_BANKRUPT);
+ SetDParam(1, STR_705D_HAS_BEEN_CLOSED_DOWN_BY);
+ SetDParam(2, p->index);
+ AddNewsItem(STR_02B6, NS_COMPANY_BANKRUPT, 0, owner);
if (IsHumanPlayer(owner)) {
/* XXX - If we are in offline mode, leave the player playing. Eg. there
@@ -591,102 +596,6 @@
}
}
-void DrawNewsBankrupcy(Window *w, const NewsItem *ni)
-{
- DrawNewsBorder(w);
-
- Player *p = GetPlayer((PlayerID)GB(ni->string_id, 0, 4));
- DrawPlayerFace(p->face, p->player_color, 2, 23);
- GfxFillRect(3, 23, 3 + 91, 23 + 118, PALETTE_TO_STRUCT_GREY | (1 << USE_COLORTABLE));
-
- SetDParam(0, p->index);
-
- DrawStringMultiCenter(49, 148, STR_7058_PRESIDENT, 94);
-
- switch (ni->string_id & 0xF0) {
- case NB_BTROUBLE:
- DrawStringCentered(w->width >> 1, 1, STR_7056_TRANSPORT_COMPANY_IN_TROUBLE, TC_FROMSTRING);
-
- SetDParam(0, p->index);
-
- DrawStringMultiCenter(
- ((w->width - 101) >> 1) + 98,
- 90,
- STR_7057_WILL_BE_SOLD_OFF_OR_DECLARED,
- w->width - 101);
- break;
-
- case NB_BMERGER:
- DrawStringCentered(w->width >> 1, 1, STR_7059_TRANSPORT_COMPANY_MERGER, TC_FROMSTRING);
- SetDParam(0, ni->params[0]);
- SetDParam(1, p->index);
- SetDParam(2, ni->params[1]);
- DrawStringMultiCenter(
- ((w->width - 101) >> 1) + 98,
- 90,
- ni->params[1] == 0 ? STR_707F_HAS_BEEN_TAKEN_OVER_BY : STR_705A_HAS_BEEN_SOLD_TO_FOR,
- w->width - 101);
- break;
-
- case NB_BBANKRUPT:
- DrawStringCentered(w->width >> 1, 1, STR_705C_BANKRUPT, TC_FROMSTRING);
- SetDParam(0, ni->params[0]);
- DrawStringMultiCenter(
- ((w->width - 101) >> 1) + 98,
- 90,
- STR_705D_HAS_BEEN_CLOSED_DOWN_BY,
- w->width - 101);
- break;
-
- case NB_BNEWCOMPANY:
- DrawStringCentered(w->width >> 1, 1, STR_705E_NEW_TRANSPORT_COMPANY_LAUNCHED, TC_FROMSTRING);
- SetDParam(0, p->index);
- SetDParam(1, ni->params[0]);
- DrawStringMultiCenter(
- ((w->width - 101) >> 1) + 98,
- 90,
- STR_705F_STARTS_CONSTRUCTION_NEAR,
- w->width - 101);
- break;
-
- default:
- NOT_REACHED();
- }
-}
-
-StringID GetNewsStringBankrupcy(const NewsItem *ni)
-{
- const Player *p = GetPlayer((PlayerID)GB(ni->string_id, 0, 4));
-
- switch (ni->string_id & 0xF0) {
- case NB_BTROUBLE:
- SetDParam(0, STR_7056_TRANSPORT_COMPANY_IN_TROUBLE);
- SetDParam(1, STR_7057_WILL_BE_SOLD_OFF_OR_DECLARED);
- SetDParam(2, p->index);
- return STR_02B6;
- case NB_BMERGER:
- SetDParam(0, STR_7059_TRANSPORT_COMPANY_MERGER);
- SetDParam(1, ni->params[1] == 0 ? STR_707F_HAS_BEEN_TAKEN_OVER_BY : STR_705A_HAS_BEEN_SOLD_TO_FOR);
- SetDParam(2, ni->params[0]);
- SetDParam(3, p->index);
- SetDParam(4, ni->params[1]);
- return STR_02B6;
- case NB_BBANKRUPT:
- SetDParam(0, STR_705C_BANKRUPT);
- SetDParam(1, STR_705D_HAS_BEEN_CLOSED_DOWN_BY);
- SetDParam(2, ni->params[0]);
- return STR_02B6;
- case NB_BNEWCOMPANY:
- SetDParam(0, STR_705E_NEW_TRANSPORT_COMPANY_LAUNCHED);
- SetDParam(1, STR_705F_STARTS_CONSTRUCTION_NEAR);
- SetDParam(2, p->index);
- SetDParam(3, ni->params[0]);
- return STR_02B6;
- default:
- NOT_REACHED();
- }
-}
-
static void PlayersGenStatistics()
{
Station *st;
@@ -808,10 +717,10 @@
if (--_economy.fluct == 0) {
_economy.fluct = -(int)GB(Random(), 0, 2);
- AddNewsItem(STR_7073_WORLD_RECESSION_FINANCIAL, NM_NORMAL, NF_NONE, NT_ECONOMY, DNC_NONE, 0, 0);
+ AddNewsItem(STR_7073_WORLD_RECESSION_FINANCIAL, NS_ECONOMY, 0, 0);
} else if (_economy.fluct == -12) {
_economy.fluct = GB(Random(), 0, 8) + 312;
- AddNewsItem(STR_7074_RECESSION_OVER_UPTURN_IN, NM_NORMAL, NF_NONE, NT_ECONOMY, DNC_NONE, 0, 0);
+ AddNewsItem(STR_7074_RECESSION_OVER_UPTURN_IN, NS_ECONOMY, 0, 0);
}
}
@@ -1151,7 +1060,7 @@
if (s->age == 12-1) {
pair = SetupSubsidyDecodeParam(s, 1);
- AddNewsItem(STR_202E_OFFER_OF_SUBSIDY_EXPIRED, NM_NORMAL, NF_TILE | NF_TILE2, NT_SUBSIDIES, DNC_NONE, pair.a, pair.b);
+ AddNewsItem(STR_202E_OFFER_OF_SUBSIDY_EXPIRED, NS_SUBSIDIES, pair.a, pair.b);
s->cargo_type = CT_INVALID;
modified = true;
for (PlayerID i = PLAYER_FIRST; i != MAX_PLAYERS; i++) {
@@ -1161,7 +1070,7 @@
st = GetStation(s->to);
if (st->owner == _local_player) {
pair = SetupSubsidyDecodeParam(s, 1);
- AddNewsItem(STR_202F_SUBSIDY_WITHDRAWN_SERVICE, NM_NORMAL, NF_TILE | NF_TILE2, NT_SUBSIDIES, DNC_NONE, pair.a, pair.b);
+ AddNewsItem(STR_202F_SUBSIDY_WITHDRAWN_SERVICE, NS_SUBSIDIES, pair.a, pair.b);
}
s->cargo_type = CT_INVALID;
modified = true;
@@ -1203,7 +1112,7 @@
if (!CheckSubsidyDuplicate(s)) {
s->age = 0;
pair = SetupSubsidyDecodeParam(s, 0);
- AddNewsItem(STR_2030_SERVICE_SUBSIDY_OFFERED, NM_NORMAL, NF_TILE | NF_TILE2, NT_SUBSIDIES, DNC_NONE, pair.a, pair.b);
+ AddNewsItem(STR_2030_SERVICE_SUBSIDY_OFFERED, NS_SUBSIDIES, pair.a, pair.b);
for (PlayerID i = PLAYER_FIRST; i != MAX_PLAYERS; i++) {
AI_Event(i, new AIEventSubsidyOffer(s - _subsidies));
}
@@ -1423,7 +1332,7 @@
SetDParam(0, _current_player);
AddNewsItem(
STR_2031_SERVICE_SUBSIDY_AWARDED + _opt.diff.subsidy_multiplier,
- NM_NORMAL, NF_TILE | NF_TILE2, NT_SUBSIDIES, DNC_NONE,
+ NS_SUBSIDIES,
pair.a, pair.b
);
for (PlayerID i = PLAYER_FIRST; i != MAX_PLAYERS; i++) {
@@ -1864,9 +1773,12 @@
Money value;
PlayerID pi = p->index;
- SetDParam(0, p->index);
- SetDParam(1, p->bankrupt_value);
- AddNewsItem((StringID)(_current_player | NB_BMERGER), NM_CALLBACK, NF_NONE, NT_COMPANY_INFO, DNC_BANKRUPCY, 0, 0);
+ SetDParam(0, STR_7059_TRANSPORT_COMPANY_MERGER);
+ SetDParam(1, p->bankrupt_value == 0 ? STR_707F_HAS_BEEN_TAKEN_OVER_BY : STR_705A_HAS_BEEN_SOLD_TO_FOR);
+ SetDParam(2, p->index);
+ SetDParam(3, _current_player);
+ SetDParam(4, p->bankrupt_value);
+ AddNewsItem(STR_02B6, NS_COMPANY_MERGER, 0, _current_player);
for (PlayerID i = PLAYER_FIRST; i < MAX_PLAYERS; i++) {
AI_Event(i, new AIEventCompanyMerger(pi, _current_player));
}
@@ -1894,7 +1806,10 @@
if (!IsHumanPlayer(p->index)) AI_PlayerDied(p->index);
DeletePlayerWindows(pi);
- RebuildVehicleLists(); //Updates the open windows to add the newly acquired vehicles to the lists
+ InvalidateWindowClassesData(WC_TRAINS_LIST, 0);
+ InvalidateWindowClassesData(WC_SHIPS_LIST, 0);
+ InvalidateWindowClassesData(WC_ROADVEH_LIST, 0);
+ InvalidateWindowClassesData(WC_AIRCRAFT_LIST, 0);
}
extern int GetAmountOwnedBy(const Player *p, PlayerID owner);
--- a/src/elrail.cpp Mon May 19 14:14:33 2008 +0000
+++ b/src/elrail.cpp Mon May 19 15:13:58 2008 +0000
@@ -104,7 +104,7 @@
if (override != NULL && (IsTunnel(t) || GetTunnelBridgeLength(t, GetOtherBridgeEnd(t)) > 0)) {
*override = 1 << GetTunnelBridgeDirection(t);
}
- return AxisToTrackBits(DiagDirToAxis(GetTunnelBridgeDirection(t)));
+ return DiagDirToDiagTrackBits(GetTunnelBridgeDirection(t));
case MP_ROAD:
if (!IsLevelCrossing(t)) return TRACK_BIT_NONE;
--- a/src/engine.cpp Mon May 19 14:14:33 2008 +0000
+++ b/src/engine.cpp Mon May 19 15:13:58 2008 +0000
@@ -28,6 +28,7 @@
#include "oldpool_func.h"
#include "ai/ai.h"
#include "core/alloc_func.hpp"
+#include "vehicle_func.h"
#include "map"
#include "table/strings.h"
@@ -121,7 +122,11 @@
*/
void EngList_Sort(EngineList *el, EngList_SortTypeFunction compare)
{
- qsort(&((*el)[0]), el->size(), sizeof(EngineID), compare);
+ size_t size = el->size();
+ /* out-of-bounds access at the next line for size == 0 (even with operator[] at some systems)
+ * generally, do not sort if there are less than 2 items */
+ if (size < 2) return;
+ qsort(&((*el)[0]), size, sizeof(EngineID), compare); // MorphOS doesn't know vector::at(int) ...
}
/** Sort selected range of items (on indices @ <begin, begin+num_items-1>)
@@ -134,9 +139,49 @@
{
assert(begin <= (uint)el->size());
assert(begin + num_items <= (uint)el->size());
+ if (num_items < 2) return;
qsort(&((*el)[begin]), num_items, sizeof(EngineID), compare);
}
+
+/** Sets cached values in Player::num_vehicles and Group::num_vehicles
+ */
+void SetCachedEngineCounts()
+{
+ uint engines = GetEnginePoolSize();
+
+ /* Set up the engine count for all players */
+ Player *p;
+ FOR_ALL_PLAYERS(p) {
+ free(p->num_engines);
+ p->num_engines = CallocT<EngineID>(engines);
+ }
+
+ /* Recalculate */
+ Group *g;
+ FOR_ALL_GROUPS(g) {
+ free(g->num_engines);
+ g->num_engines = CallocT<EngineID>(engines);
+ }
+
+ const Vehicle *v;
+ FOR_ALL_VEHICLES(v) {
+ if (!IsEngineCountable(v)) continue;
+
+ assert(v->engine_type < engines);
+
+ GetPlayer(v->owner)->num_engines[v->engine_type]++;
+
+ if (v->group_id == DEFAULT_GROUP) continue;
+
+ g = GetGroup(v->group_id);
+ assert(v->type == g->vehicle_type);
+ assert(v->owner == g->owner);
+
+ g->num_engines[v->engine_type]++;
+ }
+}
+
void SetupEngines()
{
_Engine_pool.CleanPool();
@@ -364,6 +409,8 @@
return e->type == VEH_TRAIN && e->u.rail.railveh_type == RAILVEH_WAGON;
}
+StringID GetEngineCategoryName(EngineID engine);
+
static void NewVehicleAvailable(Engine *e)
{
Vehicle *v;
@@ -416,7 +463,10 @@
if (p->is_active) SetBit(p->avail_roadtypes, HasBit(e->info.misc_flags, EF_ROAD_TRAM) ? ROADTYPE_TRAM : ROADTYPE_ROAD);
}
}
- AddNewsItem(index, NM_CALLBACK, NF_NONE, NT_NEW_VEHICLES, DNC_VEHICLEAVAIL, 0, 0);
+
+ SetDParam(0, GetEngineCategoryName(index));
+ SetDParam(1, index);
+ AddNewsItem(STR_NEW_VEHICLE_NOW_AVAILABLE_WITH_TYPE, NS_NEW_VEHICLES, index, 0);
}
void EnginesMonthlyLoop()
--- a/src/engine_func.h Mon May 19 14:14:33 2008 +0000
+++ b/src/engine_func.h Mon May 19 15:13:58 2008 +0000
@@ -27,6 +27,7 @@
bool IsEngineBuildable(EngineID engine, VehicleType type, PlayerID player);
CargoID GetEngineCargoType(EngineID engine);
+void SetCachedEngineCounts();
typedef int CDECL EngList_SortTypeFunction(const void*, const void*); ///< argument type for EngList_Sort()
void EngList_Sort(EngineList *el, EngList_SortTypeFunction compare); ///< qsort of the engine list
--- a/src/engine_gui.cpp Mon May 19 14:14:33 2008 +0000
+++ b/src/engine_gui.cpp Mon May 19 15:13:58 2008 +0000
@@ -19,7 +19,7 @@
#include "table/strings.h"
#include "table/sprites.h"
-static StringID GetEngineCategoryName(EngineID engine)
+StringID GetEngineCategoryName(EngineID engine)
{
switch (GetEngine(engine)->type) {
default: NOT_REACHED();
@@ -66,55 +66,53 @@
{ DrawAircraftEngine, DrawAircraftEngineInfo },
};
-static void EnginePreviewWndProc(Window *w, WindowEvent *e)
-{
- switch (e->event) {
- case WE_PAINT: {
- EngineID engine = w->window_number;
- const DrawEngineInfo* dei;
- int width;
+struct EnginePreviewWindow : Window {
+ EnginePreviewWindow(const WindowDesc *desc, WindowNumber window_number) : Window(desc, window_number)
+ {
+ }
- DrawWindowWidgets(w);
+ virtual void OnPaint()
+ {
+ this->DrawWidgets();
+ EngineID engine = this->window_number;
SetDParam(0, GetEngineCategoryName(engine));
DrawStringMultiCenter(150, 44, STR_8101_WE_HAVE_JUST_DESIGNED_A, 296);
SetDParam(0, engine);
- DrawStringCentered(w->width >> 1, 80, STR_ENGINE_NAME, TC_BLACK);
+ DrawStringCentered(this->width >> 1, 80, STR_ENGINE_NAME, TC_BLACK);
- dei = &_draw_engine_list[GetEngine(engine)->type];
+ const DrawEngineInfo *dei = &_draw_engine_list[GetEngine(engine)->type];
- width = w->width;
+ int width = this->width;
dei->engine_proc(width >> 1, 100, engine, 0);
dei->info_proc(engine, width >> 1, 130, width - 52);
- break;
}
- case WE_CLICK:
- switch (e->we.click.widget) {
+ virtual void OnClick(Point pt, int widget)
+ {
+ switch (widget) {
case 4:
- DoCommandP(0, w->window_number, 0, NULL, CMD_WANT_ENGINE_PREVIEW);
+ DoCommandP(0, this->window_number, 0, NULL, CMD_WANT_ENGINE_PREVIEW);
/* Fallthrough */
case 3:
- delete w;
+ delete this;
break;
}
- break;
}
-}
+};
static const WindowDesc _engine_preview_desc = {
WDP_CENTER, WDP_CENTER, 300, 192, 300, 192,
WC_ENGINE_PREVIEW, WC_NONE,
WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET,
_engine_preview_widgets,
- EnginePreviewWndProc
};
void ShowEnginePreviewWindow(EngineID engine)
{
- AllocateWindowDescFront<Window>(&_engine_preview_desc, engine);
+ AllocateWindowDescFront<EnginePreviewWindow>(&_engine_preview_desc, engine);
}
static void DrawTrainEngineInfo(EngineID engine, int x, int y, int maxw)
@@ -174,20 +172,9 @@
DrawStringMultiCenter(x, y, STR_982E_COST_MAX_SPEED_CAPACITY, maxw);
}
-
-StringID GetNewsStringNewVehicleAvail(const NewsItem *ni)
-{
- EngineID engine = ni->string_id;
- SetDParam(0, GetEngineCategoryName(engine));
- SetDParam(1, engine);
- return STR_NEW_VEHICLE_NOW_AVAILABLE_WITH_TYPE;
-}
-
void DrawNewsNewVehicleAvail(Window *w, const NewsItem *ni)
{
- DrawNewsBorder(w);
-
- EngineID engine = ni->string_id;
+ EngineID engine = ni->data_a;
const DrawEngineInfo *dei = &_draw_engine_list[GetEngine(engine)->type];
SetDParam(0, GetEngineCategoryName(engine));
--- a/src/genworld_gui.cpp Mon May 19 14:14:33 2008 +0000
+++ b/src/genworld_gui.cpp Mon May 19 15:13:58 2008 +0000
@@ -253,7 +253,7 @@
char name[64];
glwp_modes mode;
- GenerateLandscapeWindow(const WindowDesc *desc, void *data = NULL, WindowNumber number = 0) : QueryStringBaseWindow(desc, NULL, number)
+ GenerateLandscapeWindow(const WindowDesc *desc, WindowNumber number = 0) : QueryStringBaseWindow(desc, number)
{
this->LowerWidget(_opt_newgame.landscape + GLAND_TEMPERATE);
@@ -315,7 +315,7 @@
SetDParam(2, 1 << _patches_newgame.map_y); // GLAND_MAPSIZE_Y_PULLDOWN
SetDParam(3, _patches_newgame.snow_line_height); // GLAND_SNOW_LEVEL_TEXT
- DrawWindowWidgets(this);
+ this->DrawWidgets();
this->DrawEditBox(GLAND_RANDOM_EDITBOX);
@@ -470,17 +470,17 @@
this->HandleEditBox(GLAND_RANDOM_EDITBOX);
}
- virtual bool OnKeyPress(uint16 key, uint16 keycode)
+ virtual EventState OnKeyPress(uint16 key, uint16 keycode)
{
- bool cont;
- this->HandleEditBoxKey(GLAND_RANDOM_EDITBOX, key, keycode, cont);
+ EventState state;
+ this->HandleEditBoxKey(GLAND_RANDOM_EDITBOX, key, keycode, state);
/* the seed is unsigned, therefore atoi cannot be used.
* As 2^32 - 1 (MAX_UVALUE(uint32)) is a 'magic' value
* (use random seed) it should not be possible to be
* entered into the input field; the generate seed
* button can be used instead. */
_patches_newgame.generation_seed = minu(strtoul(this->edit_str_buf, NULL, sizeof(this->edit_str_buf) - 1), MAX_UVALUE(uint32) - 1);
- return cont;
+ return state;
}
virtual void OnDropdownSelect(int widget, int index)
@@ -554,7 +554,6 @@
WC_GENERATE_LANDSCAPE, WC_NONE,
WDF_STD_TOOLTIPS | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS,
_generate_landscape_widgets,
- NULL,
};
static const WindowDesc _heightmap_load_desc = {
@@ -562,7 +561,6 @@
WC_GENERATE_LANDSCAPE, WC_NONE,
WDF_STD_TOOLTIPS | WDF_DEF_WIDGET | WDF_STD_BTN | WDF_UNCLICK_BUTTONS,
_heightmap_load_widgets,
- NULL,
};
static void _ShowGenerateLandscape(glwp_modes mode)
@@ -644,7 +642,7 @@
{
uint widget_id;
- CreateScenarioWindow(const WindowDesc *desc, WindowNumber window_number) : Window(desc, NULL, window_number)
+ CreateScenarioWindow(const WindowDesc *desc, WindowNumber window_number) : Window(desc, window_number)
{
this->LowerWidget(_opt_newgame.landscape + CSCEN_TEMPERATE);
}
@@ -667,7 +665,7 @@
SetDParam(2, 1 << _patches_newgame.map_y); // CSCEN_MAPSIZE_Y_PULLDOWN
SetDParam(3, _patches_newgame.se_flat_world_height); // CSCEN_FLAT_LAND_HEIGHT_TEXT
- DrawWindowWidgets(this);
+ this->DrawWidgets();
}
virtual void OnClick(Point pt, int widget)
@@ -801,7 +799,6 @@
WC_GENERATE_LANDSCAPE, WC_NONE,
WDF_STD_TOOLTIPS | WDF_DEF_WIDGET | WDF_STD_BTN | WDF_UNCLICK_BUTTONS,
_create_scenario_widgets,
- NULL,
};
void ShowCreateScenario()
@@ -811,13 +808,20 @@
}
-static const Widget _show_terrain_progress_widgets[] = {
-{ WWT_CAPTION, RESIZE_NONE, 14, 0, 180, 0, 13, STR_GENERATION_WORLD, STR_018C_WINDOW_TITLE_DRAG_THIS},
-{ WWT_PANEL, RESIZE_NONE, 14, 0, 180, 14, 96, 0x0, STR_NULL},
-{ WWT_TEXTBTN, RESIZE_NONE, 15, 20, 161, 74, 85, STR_GENERATION_ABORT, STR_NULL}, // Abort button
+static const Widget _generate_progress_widgets[] = {
+{ WWT_CAPTION, RESIZE_NONE, 14, 0, 180, 0, 13, STR_GENERATION_WORLD, STR_018C_WINDOW_TITLE_DRAG_THIS}, // GPWW_CAPTION
+{ WWT_PANEL, RESIZE_NONE, 14, 0, 180, 14, 96, 0x0, STR_NULL}, // GPWW_BACKGROUND
+{ WWT_TEXTBTN, RESIZE_NONE, 15, 20, 161, 74, 85, STR_GENERATION_ABORT, STR_NULL}, // GPWW_ABORT
{ WIDGETS_END},
};
+static const WindowDesc _generate_progress_desc = {
+ WDP_CENTER, WDP_CENTER, 181, 97, 181, 97,
+ WC_GENERATE_PROGRESS_WINDOW, WC_NONE,
+ WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS,
+ _generate_progress_widgets,
+};
+
struct tp_info {
uint percent;
StringID cls;
@@ -837,51 +841,52 @@
}
}
-static void ShowTerrainProgressProc(Window* w, WindowEvent* e)
-{
- switch (e->event) {
- case WE_CLICK:
- switch (e->we.click.widget) {
- case 2:
- if (_cursor.sprite == SPR_CURSOR_ZZZ) SetMouseCursor(SPR_CURSOR_MOUSE, PAL_NONE);
- ShowQuery(
- STR_GENERATION_ABORT_CAPTION,
- STR_GENERATION_ABORT_MESSAGE,
- w,
- AbortGeneratingWorldCallback
- );
- break;
- }
- break;
-
- case WE_PAINT:
- DrawWindowWidgets(w);
+struct GenerateProgressWindow : public Window {
+private:
+ enum GenerationProgressWindowWidgets {
+ GPWW_CAPTION,
+ GPWW_BACKGROUND,
+ GPWW_ABORT,
+ };
- /* Draw the % complete with a bar and a text */
- DrawFrameRect(19, 20, (w->width - 18), 37, 14, FR_BORDERONLY);
- DrawFrameRect(20, 21, (int)((w->width - 40) * _tp.percent / 100) + 20, 36, 10, FR_NONE);
- SetDParam(0, _tp.percent);
- DrawStringCentered(90, 25, STR_PROGRESS, TC_FROMSTRING);
-
- /* Tell which class we are generating */
- DrawStringCentered(90, 46, _tp.cls, TC_FROMSTRING);
+public:
+ GenerateProgressWindow() : Window(&_generate_progress_desc) {};
- /* And say where we are in that class */
- SetDParam(0, _tp.current);
- SetDParam(1, _tp.total);
- DrawStringCentered(90, 58, STR_GENERATION_PROGRESS, TC_FROMSTRING);
-
- w->SetDirty();
- break;
+ virtual void OnClick(Point pt, int widget)
+ {
+ switch (widget) {
+ case GPWW_ABORT:
+ if (_cursor.sprite == SPR_CURSOR_ZZZ) SetMouseCursor(SPR_CURSOR_MOUSE, PAL_NONE);
+ ShowQuery(
+ STR_GENERATION_ABORT_CAPTION,
+ STR_GENERATION_ABORT_MESSAGE,
+ this,
+ AbortGeneratingWorldCallback
+ );
+ break;
+ }
}
-}
-static const WindowDesc _show_terrain_progress_desc = {
- WDP_CENTER, WDP_CENTER, 181, 97, 181, 97,
- WC_GENERATE_PROGRESS_WINDOW, WC_NONE,
- WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS,
- _show_terrain_progress_widgets,
- ShowTerrainProgressProc
+ virtual void OnPaint()
+ {
+ this->DrawWidgets();
+
+ /* Draw the % complete with a bar and a text */
+ DrawFrameRect(19, 20, (this->width - 18), 37, 14, FR_BORDERONLY);
+ DrawFrameRect(20, 21, (int)((this->width - 40) * _tp.percent / 100) + 20, 36, 10, FR_NONE);
+ SetDParam(0, _tp.percent);
+ DrawStringCentered(90, 25, STR_PROGRESS, TC_FROMSTRING);
+
+ /* Tell which class we are generating */
+ DrawStringCentered(90, 46, _tp.cls, TC_FROMSTRING);
+
+ /* And say where we are in that class */
+ SetDParam(0, _tp.current);
+ SetDParam(1, _tp.total);
+ DrawStringCentered(90, 58, STR_GENERATION_PROGRESS, TC_FROMSTRING);
+
+ this->SetDirty();
+ }
};
/**
@@ -901,7 +906,8 @@
*/
void ShowGenerateWorldProgress()
{
- AllocateWindowDescFront<Window>(&_show_terrain_progress_desc, 0);
+ if (BringWindowToFrontById(WC_GENERATE_PROGRESS_WINDOW, 0)) return;
+ new GenerateProgressWindow();
}
static void _SetGeneratingWorldProgress(gwp_class cls, uint progress, uint total)
--- a/src/graph_gui.cpp Mon May 19 14:14:33 2008 +0000
+++ b/src/graph_gui.cpp Mon May 19 15:13:58 2008 +0000
@@ -24,295 +24,62 @@
static uint _legend_excluded_players;
static uint _legend_excluded_cargo;
-/************************/
-/* GENERIC GRAPH DRAWER */
-/************************/
-
-enum {
- GRAPH_MAX_DATASETS = 32,
- GRAPH_AXIS_LABEL_COLOUR = TC_BLACK,
- GRAPH_AXIS_LINE_COLOUR = 215,
-
- GRAPH_X_POSITION_BEGINNING = 44, ///< Start the graph 44 pixels from gw->left
- GRAPH_X_POSITION_SEPARATION = 22, ///< There are 22 pixels between each X value
-
- GRAPH_NUM_LINES_Y = 9, ///< How many horizontal lines to draw.
- /* 9 is convenient as that means the distance between them is the height of the graph / 8,
- * which is the same
- * as height >> 3. */
-};
-
/* Apparently these don't play well with enums. */
static const OverflowSafeInt64 INVALID_DATAPOINT(INT64_MAX); // Value used for a datapoint that shouldn't be drawn.
static const uint INVALID_DATAPOINT_POS = UINT_MAX; // Used to determine if the previous point was drawn.
-struct GraphDrawer {
- uint excluded_data; ///< bitmask of the datasets that shouldn't be displayed.
- byte num_dataset;
- byte num_on_x_axis;
- bool has_negative_values;
- byte num_vert_lines;
-
- /* The starting month and year that values are plotted against. If month is
- * 0xFF, use x_values_start and x_values_increment below instead. */
- byte month;
- Year year;
-
- /* These values are used if the graph is being plotted against values
- * rather than the dates specified by month and year. */
- uint16 x_values_start;
- uint16 x_values_increment;
-
- int left, top; ///< Where to start drawing the graph, in pixels.
- uint height; ///< The height of the graph in pixels.
- StringID format_str_y_axis;
- byte colors[GRAPH_MAX_DATASETS];
- OverflowSafeInt64 cost[GRAPH_MAX_DATASETS][24]; ///< last 2 years
-};
-
-static void DrawGraph(const GraphDrawer *gw)
-{
- uint x, y; ///< Reused whenever x and y coordinates are needed.
- OverflowSafeInt64 highest_value; ///< Highest value to be drawn.
- int x_axis_offset; ///< Distance from the top of the graph to the x axis.
-
- /* the colors and cost array of GraphDrawer must accomodate
- * both values for cargo and players. So if any are higher, quit */
- assert(GRAPH_MAX_DATASETS >= (int)NUM_CARGO && GRAPH_MAX_DATASETS >= (int)MAX_PLAYERS);
- assert(gw->num_vert_lines > 0);
-
- byte grid_colour = _colour_gradient[14][4];
-
- /* The coordinates of the opposite edges of the graph. */
- int bottom = gw->top + gw->height - 1;
- int right = gw->left + GRAPH_X_POSITION_BEGINNING + gw->num_vert_lines * GRAPH_X_POSITION_SEPARATION - 1;
-
- /* Draw the vertical grid lines. */
-
- /* Don't draw the first line, as that's where the axis will be. */
- x = gw->left + GRAPH_X_POSITION_BEGINNING + GRAPH_X_POSITION_SEPARATION;
-
- for (int i = 0; i < gw->num_vert_lines; i++) {
- GfxFillRect(x, gw->top, x, bottom, grid_colour);
- x += GRAPH_X_POSITION_SEPARATION;
- }
-
- /* Draw the horizontal grid lines. */
- x = gw->left + GRAPH_X_POSITION_BEGINNING;
- y = gw->height + gw->top;
-
- for (int i = 0; i < GRAPH_NUM_LINES_Y; i++) {
- GfxFillRect(x, y, right, y, grid_colour);
- y -= (gw->height / (GRAPH_NUM_LINES_Y - 1));
- }
-
- /* Draw the y axis. */
- GfxFillRect(x, gw->top, x, bottom, GRAPH_AXIS_LINE_COLOUR);
-
- /* Find the distance from the top of the graph to the x axis. */
- x_axis_offset = gw->height;
-
- /* The graph is currently symmetrical about the x axis. */
- if (gw->has_negative_values) x_axis_offset /= 2;
-
- /* Draw the x axis. */
- y = x_axis_offset + gw->top;
- GfxFillRect(x, y, right, y, GRAPH_AXIS_LINE_COLOUR);
-
- /* Find the largest value that will be drawn. */
- if (gw->num_on_x_axis == 0)
- return;
-
- assert(gw->num_on_x_axis > 0);
- assert(gw->num_dataset > 0);
-
- /* Start of with a value of twice the height of the graph in pixels. It's a
- * bit arbitrary, but it makes the cargo payment graph look a little nicer,
- * and prevents division by zero when calculating where the datapoint
- * should be drawn. */
- highest_value = x_axis_offset * 2;
-
- for (int i = 0; i < gw->num_dataset; i++) {
- if (!HasBit(gw->excluded_data, i)) {
- for (int j = 0; j < gw->num_on_x_axis; j++) {
- OverflowSafeInt64 datapoint = gw->cost[i][j];
-
- if (datapoint != INVALID_DATAPOINT) {
- /* For now, if the graph has negative values the scaling is
- * symmetrical about the x axis, so take the absolute value
- * of each data point. */
- highest_value = max(highest_value, abs(datapoint));
- }
- }
- }
- }
-
- /* Round up highest_value so that it will divide cleanly into the number of
- * axis labels used. */
- int round_val = highest_value % (GRAPH_NUM_LINES_Y - 1);
- if (round_val != 0) highest_value += (GRAPH_NUM_LINES_Y - 1 - round_val);
-
- /* draw text strings on the y axis */
- int64 y_label = highest_value;
- int64 y_label_separation = highest_value / (GRAPH_NUM_LINES_Y - 1);
-
- /* If there are negative values, the graph goes from highest_value to
- * -highest_value, not highest_value to 0. */
- if (gw->has_negative_values) y_label_separation *= 2;
-
- x = gw->left + GRAPH_X_POSITION_BEGINNING + 1;
- y = gw->top - 3;
-
- for (int i = 0; i < GRAPH_NUM_LINES_Y; i++) {
- SetDParam(0, gw->format_str_y_axis);
- SetDParam(1, y_label);
- DrawStringRightAligned(x, y, STR_0170, GRAPH_AXIS_LABEL_COLOUR);
-
- y_label -= y_label_separation;
- y += (gw->height / (GRAPH_NUM_LINES_Y - 1));
- }
-
- /* draw strings on the x axis */
- if (gw->month != 0xFF) {
- x = gw->left + GRAPH_X_POSITION_BEGINNING;
- y = gw->top + gw->height + 1;
- byte month = gw->month;
- Year year = gw->year;
- for (int i = 0; i < gw->num_on_x_axis; i++) {
- SetDParam(0, month + STR_0162_JAN);
- SetDParam(1, month + STR_0162_JAN + 2);
- SetDParam(2, year);
- DrawString(x, y, month == 0 ? STR_016F : STR_016E, GRAPH_AXIS_LABEL_COLOUR);
-
- month += 3;
- if (month >= 12) {
- month = 0;
- year++;
- }
- x += GRAPH_X_POSITION_SEPARATION;
- }
- } else {
- /* Draw the label under the data point rather than on the grid line. */
- x = gw->left + GRAPH_X_POSITION_BEGINNING + (GRAPH_X_POSITION_SEPARATION / 2) + 1;
- y = gw->top + gw->height + 1;
- uint16 label = gw->x_values_start;
-
- for (int i = 0; i < gw->num_on_x_axis; i++) {
- SetDParam(0, label);
- DrawStringCentered(x, y, STR_01CB, GRAPH_AXIS_LABEL_COLOUR);
-
- label += gw->x_values_increment;
- x += GRAPH_X_POSITION_SEPARATION;
- }
- }
-
- /* draw lines and dots */
- for (int i = 0; i < gw->num_dataset; i++) {
- if (!HasBit(gw->excluded_data, i)) {
- /* Centre the dot between the grid lines. */
- x = gw->left + GRAPH_X_POSITION_BEGINNING + (GRAPH_X_POSITION_SEPARATION / 2);
-
- byte color = gw->colors[i];
- uint prev_x = INVALID_DATAPOINT_POS;
- uint prev_y = INVALID_DATAPOINT_POS;
-
- for (int j = 0; j < gw->num_on_x_axis; j++) {
- OverflowSafeInt64 datapoint = gw->cost[i][j];
-
- if (datapoint != INVALID_DATAPOINT) {
- /*
- * Check whether we need to reduce the 'accuracy' of the
- * datapoint value and the highest value to splut overflows.
- * And when 'drawing' 'one million' or 'one million and one'
- * there is no significant difference, so the least
- * significant bits can just be removed.
- *
- * If there are more bits needed than would fit in a 32 bits
- * integer, so at about 31 bits because of the sign bit, the
- * least significant bits are removed.
- */
- int mult_range = FindLastBit(x_axis_offset) + FindLastBit(abs(datapoint));
- int reduce_range = max(mult_range - 31, 0);
-
- /* Handle negative values differently (don't shift sign) */
- if (datapoint < 0) {
- datapoint = -(abs(datapoint) >> reduce_range);
- } else {
- datapoint >>= reduce_range;
- }
-
- y = gw->top + x_axis_offset - (x_axis_offset * datapoint) / (highest_value >> reduce_range);
-
- /* Draw the point. */
- GfxFillRect(x - 1, y - 1, x + 1, y + 1, color);
-
- /* Draw the line connected to the previous point. */
- if (prev_x != INVALID_DATAPOINT_POS) GfxDrawLine(prev_x, prev_y, x, y, color);
-
- prev_x = x;
- prev_y = y;
- } else {
- prev_x = INVALID_DATAPOINT_POS;
- prev_y = INVALID_DATAPOINT_POS;
- }
-
- x += GRAPH_X_POSITION_SEPARATION;
- }
- }
- }
-}
-
/****************/
/* GRAPH LEGEND */
/****************/
-static void GraphLegendWndProc(Window *w, WindowEvent *e)
-{
- switch (e->event) {
- case WE_CREATE:
- for (uint i = 3; i < w->widget_count; i++) {
- if (!HasBit(_legend_excluded_players, i - 3)) w->LowerWidget(i);
- }
- break;
-
- case WE_PAINT: {
- const Player *p;
-
- FOR_ALL_PLAYERS(p) {
- if (p->is_active) continue;
-
- SetBit(_legend_excluded_players, p->index);
- w->RaiseWidget(p->index + 3);
- }
-
- DrawWindowWidgets(w);
-
- FOR_ALL_PLAYERS(p) {
- if (!p->is_active) continue;
-
- DrawPlayerIcon(p->index, 4, 18 + p->index * 12);
-
- SetDParam(0, p->index);
- SetDParam(1, p->index);
- DrawString(21, 17 + p->index * 12, STR_7021, HasBit(_legend_excluded_players, p->index) ? TC_BLACK : TC_WHITE);
- }
- break;
+struct GraphLegendWindow : Window {
+ GraphLegendWindow(const WindowDesc *desc, WindowNumber window_number) : Window(desc, window_number)
+ {
+ for (uint i = 3; i < this->widget_count; i++) {
+ if (!HasBit(_legend_excluded_players, i - 3)) this->LowerWidget(i);
}
- case WE_CLICK:
- if (!IsInsideMM(e->we.click.widget, 3, 11)) return;
+ this->FindWindowPlacementAndResize(desc);
+ }
- ToggleBit(_legend_excluded_players, e->we.click.widget - 3);
- w->ToggleWidgetLoweredState(e->we.click.widget);
- w->SetDirty();
- InvalidateWindow(WC_INCOME_GRAPH, 0);
- InvalidateWindow(WC_OPERATING_PROFIT, 0);
- InvalidateWindow(WC_DELIVERED_CARGO, 0);
- InvalidateWindow(WC_PERFORMANCE_HISTORY, 0);
- InvalidateWindow(WC_COMPANY_VALUE, 0);
- break;
+ virtual void OnPaint()
+ {
+ const Player *p;
+
+ FOR_ALL_PLAYERS(p) {
+ if (p->is_active) continue;
+
+ SetBit(_legend_excluded_players, p->index);
+ this->RaiseWidget(p->index + 3);
+ }
+
+ this->DrawWidgets();
+
+ FOR_ALL_PLAYERS(p) {
+ if (!p->is_active) continue;
+
+ DrawPlayerIcon(p->index, 4, 18 + p->index * 12);
+
+ SetDParam(0, p->index);
+ SetDParam(1, p->index);
+ DrawString(21, 17 + p->index * 12, STR_7021, HasBit(_legend_excluded_players, p->index) ? TC_BLACK : TC_WHITE);
+ }
}
-}
+
+ virtual void OnClick(Point pt, int widget)
+ {
+ if (!IsInsideMM(widget, 3, 11)) return;
+
+ ToggleBit(_legend_excluded_players, widget - 3);
+ this->ToggleWidgetLoweredState(widget);
+ this->SetDirty();
+ InvalidateWindow(WC_INCOME_GRAPH, 0);
+ InvalidateWindow(WC_OPERATING_PROFIT, 0);
+ InvalidateWindow(WC_DELIVERED_CARGO, 0);
+ InvalidateWindow(WC_PERFORMANCE_HISTORY, 0);
+ InvalidateWindow(WC_COMPANY_VALUE, 0);
+ }
+};
static const Widget _graph_legend_widgets[] = {
{ WWT_CLOSEBOX, RESIZE_NONE, 14, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW},
@@ -334,90 +101,332 @@
WC_GRAPH_LEGEND, WC_NONE,
WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET,
_graph_legend_widgets,
- GraphLegendWndProc
};
static void ShowGraphLegend()
{
- AllocateWindowDescFront<Window>(&_graph_legend_desc, 0);
+ AllocateWindowDescFront<GraphLegendWindow>(&_graph_legend_desc, 0);
}
+/******************/
+/* BASE OF GRAPHS */
+/*****************/
+
+struct BaseGraphWindow : Window {
+protected:
+ enum {
+ GRAPH_MAX_DATASETS = 32,
+ GRAPH_AXIS_LABEL_COLOUR = TC_BLACK,
+ GRAPH_AXIS_LINE_COLOUR = 215,
+
+ GRAPH_X_POSITION_BEGINNING = 44, ///< Start the graph 44 pixels from gd_left
+ GRAPH_X_POSITION_SEPARATION = 22, ///< There are 22 pixels between each X value
+
+ GRAPH_NUM_LINES_Y = 9, ///< How many horizontal lines to draw.
+ /* 9 is convenient as that means the distance between them is the gd_height of the graph / 8,
+ * which is the same
+ * as height >> 3. */
+ };
+
+ uint excluded_data; ///< bitmask of the datasets that shouldn't be displayed.
+ byte num_dataset;
+ byte num_on_x_axis;
+ bool has_negative_values;
+ byte num_vert_lines;
+
+ /* The starting month and year that values are plotted against. If month is
+ * 0xFF, use x_values_start and x_values_increment below instead. */
+ byte month;
+ Year year;
+
+ /* These values are used if the graph is being plotted against values
+ * rather than the dates specified by month and year. */
+ uint16 x_values_start;
+ uint16 x_values_increment;
+
+ int gd_left, gd_top; ///< Where to start drawing the graph, in pixels.
+ uint gd_height; ///< The height of the graph in pixels.
+ StringID format_str_y_axis;
+ byte colors[GRAPH_MAX_DATASETS];
+ OverflowSafeInt64 cost[GRAPH_MAX_DATASETS][24]; ///< last 2 years
+
+ void DrawGraph() const
+ {
+ uint x, y; ///< Reused whenever x and y coordinates are needed.
+ OverflowSafeInt64 highest_value; ///< Highest value to be drawn.
+ int x_axis_offset; ///< Distance from the top of the graph to the x axis.
+
+ /* the colors and cost array of GraphDrawer must accomodate
+ * both values for cargo and players. So if any are higher, quit */
+ assert(GRAPH_MAX_DATASETS >= (int)NUM_CARGO && GRAPH_MAX_DATASETS >= (int)MAX_PLAYERS);
+ assert(this->num_vert_lines > 0);
+
+ byte grid_colour = _colour_gradient[14][4];
+
+ /* The coordinates of the opposite edges of the graph. */
+ int bottom = this->gd_top + this->gd_height - 1;
+ int right = this->gd_left + GRAPH_X_POSITION_BEGINNING + this->num_vert_lines * GRAPH_X_POSITION_SEPARATION - 1;
+
+ /* Draw the vertical grid lines. */
+
+ /* Don't draw the first line, as that's where the axis will be. */
+ x = this->gd_left + GRAPH_X_POSITION_BEGINNING + GRAPH_X_POSITION_SEPARATION;
+
+ for (int i = 0; i < this->num_vert_lines; i++) {
+ GfxFillRect(x, this->gd_top, x, bottom, grid_colour);
+ x += GRAPH_X_POSITION_SEPARATION;
+ }
+
+ /* Draw the horizontal grid lines. */
+ x = this->gd_left + GRAPH_X_POSITION_BEGINNING;
+ y = this->gd_height + this->gd_top;
+
+ for (int i = 0; i < GRAPH_NUM_LINES_Y; i++) {
+ GfxFillRect(x, y, right, y, grid_colour);
+ y -= (this->gd_height / (GRAPH_NUM_LINES_Y - 1));
+ }
+
+ /* Draw the y axis. */
+ GfxFillRect(x, this->gd_top, x, bottom, GRAPH_AXIS_LINE_COLOUR);
+
+ /* Find the distance from the gd_top of the graph to the x axis. */
+ x_axis_offset = this->gd_height;
+
+ /* The graph is currently symmetrical about the x axis. */
+ if (this->has_negative_values) x_axis_offset /= 2;
+
+ /* Draw the x axis. */
+ y = x_axis_offset + this->gd_top;
+ GfxFillRect(x, y, right, y, GRAPH_AXIS_LINE_COLOUR);
+
+ /* Find the largest value that will be drawn. */
+ if (this->num_on_x_axis == 0)
+ return;
+
+ assert(this->num_on_x_axis > 0);
+ assert(this->num_dataset > 0);
+
+ /* Start of with a value of twice the gd_height of the graph in pixels. It's a
+ * bit arbitrary, but it makes the cargo payment graph look a little nicer,
+ * and prevents division by zero when calculating where the datapoint
+ * should be drawn. */
+ highest_value = x_axis_offset * 2;
+
+ for (int i = 0; i < this->num_dataset; i++) {
+ if (!HasBit(this->excluded_data, i)) {
+ for (int j = 0; j < this->num_on_x_axis; j++) {
+ OverflowSafeInt64 datapoint = this->cost[i][j];
+
+ if (datapoint != INVALID_DATAPOINT) {
+ /* For now, if the graph has negative values the scaling is
+ * symmetrical about the x axis, so take the absolute value
+ * of each data point. */
+ highest_value = max(highest_value, abs(datapoint));
+ }
+ }
+ }
+ }
+
+ /* Round up highest_value so that it will divide cleanly into the number of
+ * axis labels used. */
+ int round_val = highest_value % (GRAPH_NUM_LINES_Y - 1);
+ if (round_val != 0) highest_value += (GRAPH_NUM_LINES_Y - 1 - round_val);
+
+ /* draw text strings on the y axis */
+ int64 y_label = highest_value;
+ int64 y_label_separation = highest_value / (GRAPH_NUM_LINES_Y - 1);
+
+ /* If there are negative values, the graph goes from highest_value to
+ * -highest_value, not highest_value to 0. */
+ if (this->has_negative_values) y_label_separation *= 2;
+
+ x = this->gd_left + GRAPH_X_POSITION_BEGINNING + 1;
+ y = this->gd_top - 3;
+
+ for (int i = 0; i < GRAPH_NUM_LINES_Y; i++) {
+ SetDParam(0, this->format_str_y_axis);
+ SetDParam(1, y_label);
+ DrawStringRightAligned(x, y, STR_0170, GRAPH_AXIS_LABEL_COLOUR);
+
+ y_label -= y_label_separation;
+ y += (this->gd_height / (GRAPH_NUM_LINES_Y - 1));
+ }
+
+ /* draw strings on the x axis */
+ if (this->month != 0xFF) {
+ x = this->gd_left + GRAPH_X_POSITION_BEGINNING;
+ y = this->gd_top + this->gd_height + 1;
+ byte month = this->month;
+ Year year = this->year;
+ for (int i = 0; i < this->num_on_x_axis; i++) {
+ SetDParam(0, month + STR_0162_JAN);
+ SetDParam(1, month + STR_0162_JAN + 2);
+ SetDParam(2, year);
+ DrawString(x, y, month == 0 ? STR_016F : STR_016E, GRAPH_AXIS_LABEL_COLOUR);
+
+ month += 3;
+ if (month >= 12) {
+ month = 0;
+ year++;
+ }
+ x += GRAPH_X_POSITION_SEPARATION;
+ }
+ } else {
+ /* Draw the label under the data point rather than on the grid line. */
+ x = this->gd_left + GRAPH_X_POSITION_BEGINNING + (GRAPH_X_POSITION_SEPARATION / 2) + 1;
+ y = this->gd_top + this->gd_height + 1;
+ uint16 label = this->x_values_start;
+
+ for (int i = 0; i < this->num_on_x_axis; i++) {
+ SetDParam(0, label);
+ DrawStringCentered(x, y, STR_01CB, GRAPH_AXIS_LABEL_COLOUR);
+
+ label += this->x_values_increment;
+ x += GRAPH_X_POSITION_SEPARATION;
+ }
+ }
+
+ /* draw lines and dots */
+ for (int i = 0; i < this->num_dataset; i++) {
+ if (!HasBit(this->excluded_data, i)) {
+ /* Centre the dot between the grid lines. */
+ x = this->gd_left + GRAPH_X_POSITION_BEGINNING + (GRAPH_X_POSITION_SEPARATION / 2);
+
+ byte color = this->colors[i];
+ uint prev_x = INVALID_DATAPOINT_POS;
+ uint prev_y = INVALID_DATAPOINT_POS;
+
+ for (int j = 0; j < this->num_on_x_axis; j++) {
+ OverflowSafeInt64 datapoint = this->cost[i][j];
+
+ if (datapoint != INVALID_DATAPOINT) {
+ /*
+ * Check whether we need to reduce the 'accuracy' of the
+ * datapoint value and the highest value to splut overflows.
+ * And when 'drawing' 'one million' or 'one million and one'
+ * there is no significant difference, so the least
+ * significant bits can just be removed.
+ *
+ * If there are more bits needed than would fit in a 32 bits
+ * integer, so at about 31 bits because of the sign bit, the
+ * least significant bits are removed.
+ */
+ int mult_range = FindLastBit(x_axis_offset) + FindLastBit(abs(datapoint));
+ int reduce_range = max(mult_range - 31, 0);
+
+ /* Handle negative values differently (don't shift sign) */
+ if (datapoint < 0) {
+ datapoint = -(abs(datapoint) >> reduce_range);
+ } else {
+ datapoint >>= reduce_range;
+ }
+
+ y = this->gd_top + x_axis_offset - (x_axis_offset * datapoint) / (highest_value >> reduce_range);
+
+ /* Draw the point. */
+ GfxFillRect(x - 1, y - 1, x + 1, y + 1, color);
+
+ /* Draw the line connected to the previous point. */
+ if (prev_x != INVALID_DATAPOINT_POS) GfxDrawLine(prev_x, prev_y, x, y, color);
+
+ prev_x = x;
+ prev_y = y;
+ } else {
+ prev_x = INVALID_DATAPOINT_POS;
+ prev_y = INVALID_DATAPOINT_POS;
+ }
+
+ x += GRAPH_X_POSITION_SEPARATION;
+ }
+ }
+ }
+ }
+
+
+ BaseGraphWindow(const WindowDesc *desc, WindowNumber window_number, int left,
+ int top, int height, bool has_negative_values, StringID format_str_y_axis) :
+ Window(desc, window_number), has_negative_values(has_negative_values),
+ gd_left(left), gd_top(top), gd_height(height), format_str_y_axis(format_str_y_axis)
+ {
+ InvalidateWindow(WC_GRAPH_LEGEND, 0);
+ }
+
+public:
+ virtual void OnPaint()
+ {
+ this->DrawWidgets();
+
+ uint excluded_players = _legend_excluded_players;
+
+ /* Exclude the players which aren't valid */
+ const Player* p;
+ FOR_ALL_PLAYERS(p) {
+ if (!p->is_active) SetBit(excluded_players, p->index);
+ }
+ this->excluded_data = excluded_players;
+ this->num_vert_lines = 24;
+
+ byte nums = 0;
+ FOR_ALL_PLAYERS(p) {
+ if (p->is_active) nums = max(nums, p->num_valid_stat_ent);
+ }
+ this->num_on_x_axis = min(nums, 24);
+
+ int mo = (_cur_month / 3 - nums) * 3;
+ int yr = _cur_year;
+ while (mo < 0) {
+ yr--;
+ mo += 12;
+ }
+
+ this->year = yr;
+ this->month = mo;
+
+ int numd = 0;
+ FOR_ALL_PLAYERS(p) {
+ if (p->is_active) {
+ this->colors[numd] = _colour_gradient[p->player_color][6];
+ for (int j = this->num_on_x_axis, i = 0; --j >= 0;) {
+ this->cost[numd][i] = (j >= p->num_valid_stat_ent) ? INVALID_DATAPOINT : GetGraphData(p, j);
+ i++;
+ }
+ }
+ numd++;
+ }
+
+ this->num_dataset = numd;
+
+ this->DrawGraph();
+ }
+
+ virtual OverflowSafeInt64 GetGraphData(const Player *p, int j)
+ {
+ return INVALID_DATAPOINT;
+ }
+
+ virtual void OnClick(Point pt, int widget)
+ {
+ /* Clicked on legend? */
+ if (widget == 2) ShowGraphLegend();
+ }
+};
+
/********************/
/* OPERATING PROFIT */
/********************/
-static void SetupGraphDrawerForPlayers(GraphDrawer *gd)
-{
- const Player* p;
- uint excluded_players = _legend_excluded_players;
- byte nums;
- int mo, yr;
-
- /* Exclude the players which aren't valid */
- FOR_ALL_PLAYERS(p) {
- if (!p->is_active) SetBit(excluded_players, p->index);
- }
- gd->excluded_data = excluded_players;
- gd->num_vert_lines = 24;
-
- nums = 0;
- FOR_ALL_PLAYERS(p) {
- if (p->is_active) nums = max(nums, p->num_valid_stat_ent);
- }
- gd->num_on_x_axis = min(nums, 24);
-
- mo = (_cur_month / 3 - nums) * 3;
- yr = _cur_year;
- while (mo < 0) {
- yr--;
- mo += 12;
+struct OperatingProfitGraphWindow : BaseGraphWindow {
+ OperatingProfitGraphWindow(const WindowDesc *desc, WindowNumber window_number) :
+ BaseGraphWindow(desc, window_number, 2, 18, 136, true, STR_CURRCOMPACT)
+ {
+ this->FindWindowPlacementAndResize(desc);
}
- gd->year = yr;
- gd->month = mo;
-}
-
-static void OperatingProfitWndProc(Window *w, WindowEvent *e)
-{
- switch (e->event) {
- case WE_PAINT: {
- GraphDrawer gd;
- const Player* p;
-
- DrawWindowWidgets(w);
-
- gd.left = 2;
- gd.top = 18;
- gd.height = 136;
- gd.has_negative_values = true;
- gd.format_str_y_axis = STR_CURRCOMPACT;
-
- SetupGraphDrawerForPlayers(&gd);
-
- int numd = 0;
- FOR_ALL_PLAYERS(p) {
- if (p->is_active) {
- gd.colors[numd] = _colour_gradient[p->player_color][6];
- for (int j = gd.num_on_x_axis, i = 0; --j >= 0;) {
- gd.cost[numd][i] = (j >= p->num_valid_stat_ent) ? INVALID_DATAPOINT : (p->old_economy[j].income + p->old_economy[j].expenses);
- i++;
- }
- }
- numd++;
- }
-
- gd.num_dataset = numd;
-
- DrawGraph(&gd);
- break;
- }
-
- case WE_CLICK:
- /* Clicked on legend? */
- if (e->we.click.widget == 2) ShowGraphLegend();
- break;
+ virtual OverflowSafeInt64 GetGraphData(const Player *p, int j)
+ {
+ return p->old_economy[j].income + p->old_economy[j].expenses;
}
-}
+};
static const Widget _operating_profit_widgets[] = {
{ WWT_CLOSEBOX, RESIZE_NONE, 14, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW},
@@ -432,15 +441,12 @@
WC_OPERATING_PROFIT, WC_NONE,
WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS,
_operating_profit_widgets,
- OperatingProfitWndProc
};
void ShowOperatingProfitGraph()
{
- if (AllocateWindowDescFront<Window>(&_operating_profit_desc, 0)) {
- InvalidateWindow(WC_GRAPH_LEGEND, 0);
- }
+ AllocateWindowDescFront<OperatingProfitGraphWindow>(&_operating_profit_desc, 0);
}
@@ -448,45 +454,18 @@
/* INCOME GRAPH */
/****************/
-static void IncomeGraphWndProc(Window *w, WindowEvent *e)
-{
- switch (e->event) {
- case WE_PAINT: {
- GraphDrawer gd;
- const Player* p;
-
- DrawWindowWidgets(w);
-
- gd.left = 2;
- gd.top = 18;
- gd.height = 104;
- gd.has_negative_values = false;
- gd.format_str_y_axis = STR_CURRCOMPACT;
- SetupGraphDrawerForPlayers(&gd);
+struct IncomeGraphWindow : BaseGraphWindow {
+ IncomeGraphWindow(const WindowDesc *desc, WindowNumber window_number) :
+ BaseGraphWindow(desc, window_number, 2, 18, 104, false, STR_CURRCOMPACT)
+ {
+ this->FindWindowPlacementAndResize(desc);
+ }
- int numd = 0;
- FOR_ALL_PLAYERS(p) {
- if (p->is_active) {
- gd.colors[numd] = _colour_gradient[p->player_color][6];
- for (int j = gd.num_on_x_axis, i = 0; --j >= 0;) {
- gd.cost[numd][i] = (j >= p->num_valid_stat_ent) ? INVALID_DATAPOINT : p->old_economy[j].income;
- i++;
- }
- }
- numd++;
- }
-
- gd.num_dataset = numd;
-
- DrawGraph(&gd);
- break;
- }
-
- case WE_CLICK:
- if (e->we.click.widget == 2) ShowGraphLegend();
- break;
+ virtual OverflowSafeInt64 GetGraphData(const Player *p, int j)
+ {
+ return p->old_economy[j].income;
}
-}
+};
static const Widget _income_graph_widgets[] = {
{ WWT_CLOSEBOX, RESIZE_NONE, 14, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW},
@@ -501,59 +480,29 @@
WC_INCOME_GRAPH, WC_NONE,
WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS,
_income_graph_widgets,
- IncomeGraphWndProc
};
void ShowIncomeGraph()
{
- if (AllocateWindowDescFront<Window>(&_income_graph_desc, 0)) {
- InvalidateWindow(WC_GRAPH_LEGEND, 0);
- }
+ AllocateWindowDescFront<IncomeGraphWindow>(&_income_graph_desc, 0);
}
/*******************/
/* DELIVERED CARGO */
/*******************/
-static void DeliveredCargoGraphWndProc(Window *w, WindowEvent *e)
-{
- switch (e->event) {
- case WE_PAINT: {
- GraphDrawer gd;
- const Player* p;
-
- DrawWindowWidgets(w);
-
- gd.left = 2;
- gd.top = 18;
- gd.height = 104;
- gd.has_negative_values = false;
- gd.format_str_y_axis = STR_7024;
- SetupGraphDrawerForPlayers(&gd);
+struct DeliveredCargoGraphWindow : BaseGraphWindow {
+ DeliveredCargoGraphWindow(const WindowDesc *desc, WindowNumber window_number) :
+ BaseGraphWindow(desc, window_number, 2, 18, 104, false, STR_7024)
+ {
+ this->FindWindowPlacementAndResize(desc);
+ }
- int numd = 0;
- FOR_ALL_PLAYERS(p) {
- if (p->is_active) {
- gd.colors[numd] = _colour_gradient[p->player_color][6];
- for (int j = gd.num_on_x_axis, i = 0; --j >= 0;) {
- gd.cost[numd][i] = (j >= p->num_valid_stat_ent) ? INVALID_DATAPOINT : (OverflowSafeInt64)p->old_economy[j].delivered_cargo;
- i++;
- }
- }
- numd++;
- }
-
- gd.num_dataset = numd;
-
- DrawGraph(&gd);
- break;
- }
-
- case WE_CLICK:
- if (e->we.click.widget == 2) ShowGraphLegend();
- break;
+ virtual OverflowSafeInt64 GetGraphData(const Player *p, int j)
+ {
+ return p->old_economy[j].delivered_cargo;
}
-}
+};
static const Widget _delivered_cargo_graph_widgets[] = {
{ WWT_CLOSEBOX, RESIZE_NONE, 14, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW},
@@ -568,60 +517,35 @@
WC_DELIVERED_CARGO, WC_NONE,
WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS,
_delivered_cargo_graph_widgets,
- DeliveredCargoGraphWndProc
};
void ShowDeliveredCargoGraph()
{
- if (AllocateWindowDescFront<Window>(&_delivered_cargo_graph_desc, 0)) {
- InvalidateWindow(WC_GRAPH_LEGEND, 0);
- }
+ AllocateWindowDescFront<DeliveredCargoGraphWindow>(&_delivered_cargo_graph_desc, 0);
}
/***********************/
/* PERFORMANCE HISTORY */
/***********************/
-static void PerformanceHistoryWndProc(Window *w, WindowEvent *e)
-{
- switch (e->event) {
- case WE_PAINT: {
- GraphDrawer gd;
- const Player* p;
-
- DrawWindowWidgets(w);
-
- gd.left = 2;
- gd.top = 18;
- gd.height = 200;
- gd.has_negative_values = false;
- gd.format_str_y_axis = STR_7024;
- SetupGraphDrawerForPlayers(&gd);
+struct PerformanceHistoryGraphWindow : BaseGraphWindow {
+ PerformanceHistoryGraphWindow(const WindowDesc *desc, WindowNumber window_number) :
+ BaseGraphWindow(desc, window_number, 2, 18, 200, false, STR_7024)
+ {
+ this->FindWindowPlacementAndResize(desc);
+ }
- int numd = 0;
- FOR_ALL_PLAYERS(p) {
- if (p->is_active) {
- gd.colors[numd] = _colour_gradient[p->player_color][6];
- for (int j = gd.num_on_x_axis, i = 0; --j >= 0;) {
- gd.cost[numd][i] = (j >= p->num_valid_stat_ent) ? INVALID_DATAPOINT : (OverflowSafeInt64)p->old_economy[j].performance_history;
- i++;
- }
- }
- numd++;
- }
+ virtual OverflowSafeInt64 GetGraphData(const Player *p, int j)
+ {
+ return p->old_economy[j].performance_history;
+ }
- gd.num_dataset = numd;
-
- DrawGraph(&gd);
- break;
- }
-
- case WE_CLICK:
- if (e->we.click.widget == 2) ShowGraphLegend();
- if (e->we.click.widget == 3) ShowPerformanceRatingDetail();
- break;
+ virtual void OnClick(Point pt, int widget)
+ {
+ if (widget == 3) ShowPerformanceRatingDetail();
+ this->BaseGraphWindow::OnClick(pt, widget);
}
-}
+};
static const Widget _performance_history_widgets[] = {
{ WWT_CLOSEBOX, RESIZE_NONE, 14, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW},
@@ -637,59 +561,29 @@
WC_PERFORMANCE_HISTORY, WC_NONE,
WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS,
_performance_history_widgets,
- PerformanceHistoryWndProc
};
void ShowPerformanceHistoryGraph()
{
- if (AllocateWindowDescFront<Window>(&_performance_history_desc, 0)) {
- InvalidateWindow(WC_GRAPH_LEGEND, 0);
- }
+ AllocateWindowDescFront<PerformanceHistoryGraphWindow>(&_performance_history_desc, 0);
}
/*****************/
/* COMPANY VALUE */
/*****************/
-static void CompanyValueGraphWndProc(Window *w, WindowEvent *e)
-{
- switch (e->event) {
- case WE_PAINT: {
- GraphDrawer gd;
- const Player* p;
-
- DrawWindowWidgets(w);
-
- gd.left = 2;
- gd.top = 18;
- gd.height = 200;
- gd.has_negative_values = false;
- gd.format_str_y_axis = STR_CURRCOMPACT;
- SetupGraphDrawerForPlayers(&gd);
+struct CompanyValueGraphWindow : BaseGraphWindow {
+ CompanyValueGraphWindow(const WindowDesc *desc, WindowNumber window_number) :
+ BaseGraphWindow(desc, window_number, 2, 18, 200, false, STR_CURRCOMPACT)
+ {
+ this->FindWindowPlacementAndResize(desc);
+ }
- int numd = 0;
- FOR_ALL_PLAYERS(p) {
- if (p->is_active) {
- gd.colors[numd] = _colour_gradient[p->player_color][6];
- for (int j = gd.num_on_x_axis, i = 0; --j >= 0;) {
- gd.cost[numd][i] = (j >= p->num_valid_stat_ent) ? INVALID_DATAPOINT : p->old_economy[j].company_value;
- i++;
- }
- }
- numd++;
- }
-
- gd.num_dataset = numd;
-
- DrawGraph(&gd);
- break;
- }
-
- case WE_CLICK:
- if (e->we.click.widget == 2) ShowGraphLegend();
- break;
+ virtual OverflowSafeInt64 GetGraphData(const Player *p, int j)
+ {
+ return p->old_economy[j].company_value;
}
-}
+};
static const Widget _company_value_graph_widgets[] = {
{ WWT_CLOSEBOX, RESIZE_NONE, 14, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW},
@@ -704,90 +598,117 @@
WC_COMPANY_VALUE, WC_NONE,
WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS,
_company_value_graph_widgets,
- CompanyValueGraphWndProc
};
void ShowCompanyValueGraph()
{
- if (AllocateWindowDescFront<Window>(&_company_value_graph_desc, 0)) {
- InvalidateWindow(WC_GRAPH_LEGEND, 0);
- }
+ AllocateWindowDescFront<CompanyValueGraphWindow>(&_company_value_graph_desc, 0);
}
/*****************/
/* PAYMENT RATES */
/*****************/
-static void CargoPaymentRatesWndProc(Window *w, WindowEvent *e)
-{
- switch (e->event) {
- case WE_PAINT: {
- GraphDrawer gd;
-
- DrawWindowWidgets(w);
-
- int x = 495;
- int y = 24;
-
- gd.excluded_data = _legend_excluded_cargo;
- gd.left = 2;
- gd.top = 24;
- gd.height = w->height - 38;
- gd.has_negative_values = false;
- gd.format_str_y_axis = STR_CURRCOMPACT;
- gd.num_on_x_axis = 20;
- gd.num_vert_lines = 20;
- gd.month = 0xFF;
- gd.x_values_start = 10;
- gd.x_values_increment = 10;
-
- uint i = 0;
- for (CargoID c = 0; c < NUM_CARGO; c++) {
- const CargoSpec *cs = GetCargo(c);
- if (!cs->IsValid()) continue;
-
- /* Only draw labels for widgets that exist. If the widget doesn't
- * exist then the local player has used the climate cheat or
- * changed the NewGRF configuration with this window open. */
- if (i + 3 < w->widget_count) {
- /* Since the buttons have no text, no images,
- * both the text and the colored box have to be manually painted.
- * clk_dif will move one pixel down and one pixel to the right
- * when the button is clicked */
- byte clk_dif = w->IsWidgetLowered(i + 3) ? 1 : 0;
-
- GfxFillRect(x + clk_dif, y + clk_dif, x + 8 + clk_dif, y + 5 + clk_dif, 0);
- GfxFillRect(x + 1 + clk_dif, y + 1 + clk_dif, x + 7 + clk_dif, y + 4 + clk_dif, cs->legend_colour);
- SetDParam(0, cs->name);
- DrawString(x + 14 + clk_dif, y + clk_dif, STR_7065, TC_FROMSTRING);
- y += 8;
- }
-
- gd.colors[i] = cs->legend_colour;
- for (uint j = 0; j != 20; j++) {
- gd.cost[i][j] = GetTransportedGoodsIncome(10, 20, j * 6 + 6, c);
- }
-
- i++;
- }
- gd.num_dataset = i;
-
- DrawGraph(&gd);
-
- DrawString(2 + 46, 24 + gd.height + 7, STR_7062_DAYS_IN_TRANSIT, TC_FROMSTRING);
- DrawString(2 + 84, 24 - 9, STR_7063_PAYMENT_FOR_DELIVERING, TC_FROMSTRING);
- break;
+struct PaymentRatesGraphWindow : BaseGraphWindow {
+ PaymentRatesGraphWindow(const WindowDesc *desc, WindowNumber window_number) :
+ BaseGraphWindow(desc, window_number, 2, 24, 200, false, STR_CURRCOMPACT)
+ {
+ uint num_active = 0;
+ for (CargoID c = 0; c < NUM_CARGO; c++) {
+ if (GetCargo(c)->IsValid()) num_active++;
}
- case WE_CLICK:
- if (e->we.click.widget >= 3) {
- ToggleBit(_legend_excluded_cargo, e->we.click.widget - 3);
- w->ToggleWidgetLoweredState(e->we.click.widget);
- w->SetDirty();
+ /* Resize the window to fit the cargo types */
+ ResizeWindow(this, 0, max(num_active, 12U) * 8);
+
+ /* Add widgets for each cargo type */
+ this->widget_count += num_active;
+ this->widget = ReallocT(this->widget, this->widget_count + 1);
+ this->widget[this->widget_count].type = WWT_LAST;
+
+ /* Set the properties of each widget */
+ for (uint i = 0; i != num_active; i++) {
+ Widget *wi = &this->widget[3 + i];
+ wi->type = WWT_PANEL;
+ wi->display_flags = RESIZE_NONE;
+ wi->color = 12;
+ wi->left = 493;
+ wi->right = 562;
+ wi->top = 24 + i * 8;
+ wi->bottom = wi->top + 7;
+ wi->data = 0;
+ wi->tooltips = STR_7064_TOGGLE_GRAPH_FOR_CARGO;
+
+ if (!HasBit(_legend_excluded_cargo, i)) this->LowerWidget(i + 3);
+ }
+
+ this->SetDirty();
+
+ this->gd_height = this->height - 38;
+ this->num_on_x_axis = 20;
+ this->num_vert_lines = 20;
+ this->month = 0xFF;
+ this->x_values_start = 10;
+ this->x_values_increment = 10;
+
+ this->FindWindowPlacementAndResize(desc);
+ }
+
+ virtual void OnPaint()
+ {
+ this->DrawWidgets();
+
+ this->excluded_data = _legend_excluded_cargo;
+
+ int x = 495;
+ int y = 24;
+
+ uint i = 0;
+ for (CargoID c = 0; c < NUM_CARGO; c++) {
+ const CargoSpec *cs = GetCargo(c);
+ if (!cs->IsValid()) continue;
+
+ /* Only draw labels for widgets that exist. If the widget doesn't
+ * exist then the local player has used the climate cheat or
+ * changed the NewGRF configuration with this window open. */
+ if (i + 3 < this->widget_count) {
+ /* Since the buttons have no text, no images,
+ * both the text and the colored box have to be manually painted.
+ * clk_dif will move one pixel down and one pixel to the right
+ * when the button is clicked */
+ byte clk_dif = this->IsWidgetLowered(i + 3) ? 1 : 0;
+
+ GfxFillRect(x + clk_dif, y + clk_dif, x + 8 + clk_dif, y + 5 + clk_dif, 0);
+ GfxFillRect(x + 1 + clk_dif, y + 1 + clk_dif, x + 7 + clk_dif, y + 4 + clk_dif, cs->legend_colour);
+ SetDParam(0, cs->name);
+ DrawString(x + 14 + clk_dif, y + clk_dif, STR_7065, TC_FROMSTRING);
+ y += 8;
}
- break;
+
+ this->colors[i] = cs->legend_colour;
+ for (uint j = 0; j != 20; j++) {
+ this->cost[i][j] = GetTransportedGoodsIncome(10, 20, j * 6 + 6, c);
+ }
+
+ i++;
+ }
+ this->num_dataset = i;
+
+ this->DrawGraph();
+
+ DrawString(2 + 46, 24 + this->gd_height + 7, STR_7062_DAYS_IN_TRANSIT, TC_FROMSTRING);
+ DrawString(2 + 84, 24 - 9, STR_7063_PAYMENT_FOR_DELIVERING, TC_FROMSTRING);
}
-}
+
+ virtual void OnClick(Point pt, int widget)
+ {
+ if (widget >= 3) {
+ ToggleBit(_legend_excluded_cargo, widget - 3);
+ this->ToggleWidgetLoweredState(widget);
+ this->SetDirty();
+ }
+ }
+};
static const Widget _cargo_payment_rates_widgets[] = {
{ WWT_CLOSEBOX, RESIZE_NONE, 14, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW},
@@ -801,46 +722,12 @@
WC_PAYMENT_RATES, WC_NONE,
WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET,
_cargo_payment_rates_widgets,
- CargoPaymentRatesWndProc
};
void ShowCargoPaymentRates()
{
- Window *w = AllocateWindowDescFront<Window>(&_cargo_payment_rates_desc, 0);
- if (w == NULL) return;
-
- /* Count the number of active cargo types */
- uint num_active = 0;
- for (CargoID c = 0; c < NUM_CARGO; c++) {
- if (GetCargo(c)->IsValid()) num_active++;
- }
-
- /* Resize the window to fit the cargo types */
- ResizeWindow(w, 0, max(num_active, 12U) * 8);
-
- /* Add widgets for each cargo type */
- w->widget_count += num_active;
- w->widget = ReallocT(w->widget, w->widget_count + 1);
- w->widget[w->widget_count].type = WWT_LAST;
-
- /* Set the properties of each widget */
- for (uint i = 0; i != num_active; i++) {
- Widget *wi = &w->widget[3 + i];
- wi->type = WWT_PANEL;
- wi->display_flags = RESIZE_NONE;
- wi->color = 12;
- wi->left = 493;
- wi->right = 562;
- wi->top = 24 + i * 8;
- wi->bottom = wi->top + 7;
- wi->data = 0;
- wi->tooltips = STR_7064_TOGGLE_GRAPH_FOR_CARGO;
-
- if (!HasBit(_legend_excluded_cargo, i)) w->LowerWidget(i + 3);
- }
-
- w->SetDirty();
+ AllocateWindowDescFront<PaymentRatesGraphWindow>(&_cargo_payment_rates_desc, 0);
}
/************************/
@@ -879,35 +766,35 @@
return p2->old_economy[1].performance_history - p1->old_economy[1].performance_history;
}
-static void CompanyLeagueWndProc(Window *w, WindowEvent *e)
-{
- switch (e->event) {
- case WE_PAINT: {
- const Player* plist[MAX_PLAYERS];
- const Player* p;
-
- DrawWindowWidgets(w);
-
- uint pl_num = 0;
- FOR_ALL_PLAYERS(p) if (p->is_active) plist[pl_num++] = p;
+struct CompanyLeagueWindow : Window {
+ CompanyLeagueWindow(const WindowDesc *desc, WindowNumber window_number) : Window(desc, window_number)
+ {
+ }
- qsort((void*)plist, pl_num, sizeof(*plist), PerfHistComp);
+ virtual void OnPaint()
+ {
+ const Player *plist[MAX_PLAYERS];
+ const Player *p;
- for (uint i = 0; i != pl_num; i++) {
- p = plist[i];
- SetDParam(0, i + STR_01AC_1ST);
- SetDParam(1, p->index);
- SetDParam(2, p->index);
- SetDParam(3, GetPerformanceTitleFromValue(p->old_economy[1].performance_history));
+ this->DrawWidgets();
- DrawString(2, 15 + i * 10, i == 0 ? STR_7054 : STR_7055, TC_FROMSTRING);
- DrawPlayerIcon(p->index, 27, 16 + i * 10);
- }
+ uint pl_num = 0;
+ FOR_ALL_PLAYERS(p) if (p->is_active) plist[pl_num++] = p;
- break;
+ qsort((void*)plist, pl_num, sizeof(*plist), PerfHistComp);
+
+ for (uint i = 0; i != pl_num; i++) {
+ p = plist[i];
+ SetDParam(0, i + STR_01AC_1ST);
+ SetDParam(1, p->index);
+ SetDParam(2, p->index);
+ SetDParam(3, GetPerformanceTitleFromValue(p->old_economy[1].performance_history));
+
+ DrawString(2, 15 + i * 10, i == 0 ? STR_7054 : STR_7055, TC_FROMSTRING);
+ DrawPlayerIcon(p->index, 27, 16 + i * 10);
}
}
-}
+};
static const Widget _company_league_widgets[] = {
@@ -923,208 +810,204 @@
WC_COMPANY_LEAGUE, WC_NONE,
WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_STICKY_BUTTON,
_company_league_widgets,
- CompanyLeagueWndProc
};
void ShowCompanyLeagueTable()
{
- AllocateWindowDescFront<Window>(&_company_league_desc, 0);
+ AllocateWindowDescFront<CompanyLeagueWindow>(&_company_league_desc, 0);
}
/*****************************/
/* PERFORMANCE RATING DETAIL */
/*****************************/
-static void PerformanceRatingDetailWndProc(Window *w, WindowEvent *e)
-{
- static PlayerID _performance_rating_detail_player = INVALID_PLAYER;
-
- switch (e->event) {
- case WE_PAINT: {
- byte x;
- uint16 y = 14;
- int total_score = 0;
- int color_done, color_notdone;
-
- /* Draw standard stuff */
- DrawWindowWidgets(w);
-
- /* Check if the currently selected player is still active. */
- if (_performance_rating_detail_player == INVALID_PLAYER || !GetPlayer(_performance_rating_detail_player)->is_active) {
- if (_performance_rating_detail_player != INVALID_PLAYER) {
- /* Raise and disable the widget for the previous selection. */
- w->RaiseWidget(_performance_rating_detail_player + 13);
- w->DisableWidget(_performance_rating_detail_player + 13);
- w->SetDirty();
-
- _performance_rating_detail_player = INVALID_PLAYER;
- }
-
- for (PlayerID i = PLAYER_FIRST; i < MAX_PLAYERS; i++) {
- if (GetPlayer(i)->is_active) {
- /* Lower the widget corresponding to this player. */
- w->LowerWidget(i + 13);
- w->SetDirty();
+struct PerformanceRatingDetailWindow : Window {
+ static PlayerID player;
+ int timeout;
- _performance_rating_detail_player = i;
- break;
- }
- }
- }
-
- /* If there are no active players, don't display anything else. */
- if (_performance_rating_detail_player == INVALID_PLAYER) break;
+ PerformanceRatingDetailWindow(const WindowDesc *desc, WindowNumber window_number) : Window(desc, window_number)
+ {
+ /* Disable the players who are not active */
+ for (PlayerID i = PLAYER_FIRST; i < MAX_PLAYERS; i++) {
+ this->SetWidgetDisabledState(i + 13, !GetPlayer(i)->is_active);
+ }
- /* Paint the player icons */
- for (PlayerID i = PLAYER_FIRST; i < MAX_PLAYERS; i++) {
- if (!GetPlayer(i)->is_active) {
- /* Check if we have the player as an active player */
- if (!w->IsWidgetDisabled(i + 13)) {
- /* Bah, player gone :( */
- w->DisableWidget(i + 13);
+ this->UpdatePlayerStats();
- /* We need a repaint */
- w->SetDirty();
- }
- continue;
- }
+ if (player != INVALID_PLAYER) this->LowerWidget(player + 13);
- /* Check if we have the player marked as inactive */
- if (w->IsWidgetDisabled(i + 13)) {
- /* New player! Yippie :p */
- w->EnableWidget(i + 13);
- /* We need a repaint */
- w->SetDirty();
- }
+ this->FindWindowPlacementAndResize(desc);
+ }
- x = (i == _performance_rating_detail_player) ? 1 : 0;
- DrawPlayerIcon(i, i * 37 + 13 + x, 16 + x);
+ void UpdatePlayerStats()
+ {
+ /* Update all player stats with the current data
+ * (this is because _score_info is not saved to a savegame) */
+ Player *p;
+ FOR_ALL_PLAYERS(p) {
+ if (p->is_active) UpdateCompanyRatingAndValue(p, false);
+ }
+
+ this->timeout = DAY_TICKS * 5;
+
+ }
+
+ virtual void OnPaint()
+ {
+ byte x;
+ uint16 y = 14;
+ int total_score = 0;
+ int color_done, color_notdone;
+
+ /* Draw standard stuff */
+ this->DrawWidgets();
+
+ /* Check if the currently selected player is still active. */
+ if (player == INVALID_PLAYER || !GetPlayer(player)->is_active) {
+ if (player != INVALID_PLAYER) {
+ /* Raise and disable the widget for the previous selection. */
+ this->RaiseWidget(player + 13);
+ this->DisableWidget(player + 13);
+ this->SetDirty();
+
+ player = INVALID_PLAYER;
}
- /* The colors used to show how the progress is going */
- color_done = _colour_gradient[COLOUR_GREEN][4];
- color_notdone = _colour_gradient[COLOUR_RED][4];
-
- /* Draw all the score parts */
- for (ScoreID i = SCORE_BEGIN; i < SCORE_END; i++) {
- int val = _score_part[_performance_rating_detail_player][i];
- int needed = _score_info[i].needed;
- int score = _score_info[i].score;
-
- y += 20;
- /* SCORE_TOTAL has his own rulez ;) */
- if (i == SCORE_TOTAL) {
- needed = total_score;
- score = SCORE_MAX;
- } else {
- total_score += score;
- }
-
- DrawString(7, y, STR_PERFORMANCE_DETAIL_VEHICLES + i, TC_FROMSTRING);
-
- /* Draw the score */
- SetDParam(0, score);
- DrawStringRightAligned(107, y, SET_PERFORMANCE_DETAIL_INT, TC_FROMSTRING);
-
- /* Calculate the %-bar */
- x = Clamp(val, 0, needed) * 50 / needed;
-
- /* SCORE_LOAN is inversed */
- if (val < 0 && i == SCORE_LOAN) x = 0;
+ for (PlayerID i = PLAYER_FIRST; i < MAX_PLAYERS; i++) {
+ if (GetPlayer(i)->is_active) {
+ /* Lower the widget corresponding to this player. */
+ this->LowerWidget(i + 13);
+ this->SetDirty();
- /* Draw the bar */
- if (x != 0) GfxFillRect(112, y - 2, 112 + x, y + 10, color_done);
- if (x != 50) GfxFillRect(112 + x, y - 2, 112 + 50, y + 10, color_notdone);
-
- /* Calculate the % */
- x = Clamp(val, 0, needed) * 100 / needed;
-
- /* SCORE_LOAN is inversed */
- if (val < 0 && i == SCORE_LOAN) x = 0;
-
- /* Draw it */
- SetDParam(0, x);
- DrawStringCentered(137, y, STR_PERFORMANCE_DETAIL_PERCENT, TC_FROMSTRING);
-
- /* SCORE_LOAN is inversed */
- if (i == SCORE_LOAN) val = needed - val;
-
- /* Draw the amount we have against what is needed
- * For some of them it is in currency format */
- SetDParam(0, val);
- SetDParam(1, needed);
- switch (i) {
- case SCORE_MIN_PROFIT:
- case SCORE_MIN_INCOME:
- case SCORE_MAX_INCOME:
- case SCORE_MONEY:
- case SCORE_LOAN:
- DrawString(167, y, STR_PERFORMANCE_DETAIL_AMOUNT_CURRENCY, TC_FROMSTRING);
- break;
- default:
- DrawString(167, y, STR_PERFORMANCE_DETAIL_AMOUNT_INT, TC_FROMSTRING);
+ player = i;
+ break;
}
}
-
- break;
}
- case WE_CLICK:
- /* Check which button is clicked */
- if (IsInsideMM(e->we.click.widget, 13, 21)) {
- /* Is it no on disable? */
- if (!w->IsWidgetDisabled(e->we.click.widget)) {
- w->RaiseWidget(_performance_rating_detail_player + 13);
- _performance_rating_detail_player = (PlayerID)(e->we.click.widget - 13);
- w->LowerWidget(_performance_rating_detail_player + 13);
- w->SetDirty();
+ /* If there are no active players, don't display anything else. */
+ if (player == INVALID_PLAYER) return;
+
+ /* Paint the player icons */
+ for (PlayerID i = PLAYER_FIRST; i < MAX_PLAYERS; i++) {
+ if (!GetPlayer(i)->is_active) {
+ /* Check if we have the player as an active player */
+ if (!this->IsWidgetDisabled(i + 13)) {
+ /* Bah, player gone :( */
+ this->DisableWidget(i + 13);
+
+ /* We need a repaint */
+ this->SetDirty();
}
- }
- break;
-
- case WE_CREATE: {
- Player *p2;
-
- /* Disable the players who are not active */
- for (PlayerID i = PLAYER_FIRST; i < MAX_PLAYERS; i++) {
- w->SetWidgetDisabledState(i + 13, !GetPlayer(i)->is_active);
- }
- /* Update all player stats with the current data
- * (this is because _score_info is not saved to a savegame) */
- FOR_ALL_PLAYERS(p2) {
- if (p2->is_active) UpdateCompanyRatingAndValue(p2, false);
+ continue;
}
- w->custom[0] = DAY_TICKS;
- w->custom[1] = 5;
+ /* Check if we have the player marked as inactive */
+ if (this->IsWidgetDisabled(i + 13)) {
+ /* New player! Yippie :p */
+ this->EnableWidget(i + 13);
+ /* We need a repaint */
+ this->SetDirty();
+ }
- if (_performance_rating_detail_player != INVALID_PLAYER) w->LowerWidget(_performance_rating_detail_player + 13);
- w->SetDirty();
-
- break;
+ x = (i == player) ? 1 : 0;
+ DrawPlayerIcon(i, i * 37 + 13 + x, 16 + x);
}
- case WE_TICK:
- if (_pause_game != 0) break;
+ /* The colors used to show how the progress is going */
+ color_done = _colour_gradient[COLOUR_GREEN][4];
+ color_notdone = _colour_gradient[COLOUR_RED][4];
- /* Update the player score every 5 days */
- if (--w->custom[0] == 0) {
- w->custom[0] = DAY_TICKS;
- if (--w->custom[1] == 0) {
- Player *p2;
+ /* Draw all the score parts */
+ for (ScoreID i = SCORE_BEGIN; i < SCORE_END; i++) {
+ int val = _score_part[player][i];
+ int needed = _score_info[i].needed;
+ int score = _score_info[i].score;
- w->custom[1] = 5;
- FOR_ALL_PLAYERS(p2) {
- /* Skip if player is not active */
- if (p2->is_active) UpdateCompanyRatingAndValue(p2, false);
- }
- w->SetDirty();
- }
+ y += 20;
+ /* SCORE_TOTAL has his own rulez ;) */
+ if (i == SCORE_TOTAL) {
+ needed = total_score;
+ score = SCORE_MAX;
+ } else {
+ total_score += score;
}
- break;
+ DrawString(7, y, STR_PERFORMANCE_DETAIL_VEHICLES + i, TC_FROMSTRING);
+
+ /* Draw the score */
+ SetDParam(0, score);
+ DrawStringRightAligned(107, y, SET_PERFORMANCE_DETAIL_INT, TC_FROMSTRING);
+
+ /* Calculate the %-bar */
+ x = Clamp(val, 0, needed) * 50 / needed;
+
+ /* SCORE_LOAN is inversed */
+ if (val < 0 && i == SCORE_LOAN) x = 0;
+
+ /* Draw the bar */
+ if (x != 0) GfxFillRect(112, y - 2, 112 + x, y + 10, color_done);
+ if (x != 50) GfxFillRect(112 + x, y - 2, 112 + 50, y + 10, color_notdone);
+
+ /* Calculate the % */
+ x = Clamp(val, 0, needed) * 100 / needed;
+
+ /* SCORE_LOAN is inversed */
+ if (val < 0 && i == SCORE_LOAN) x = 0;
+
+ /* Draw it */
+ SetDParam(0, x);
+ DrawStringCentered(137, y, STR_PERFORMANCE_DETAIL_PERCENT, TC_FROMSTRING);
+
+ /* SCORE_LOAN is inversed */
+ if (i == SCORE_LOAN) val = needed - val;
+
+ /* Draw the amount we have against what is needed
+ * For some of them it is in currency format */
+ SetDParam(0, val);
+ SetDParam(1, needed);
+ switch (i) {
+ case SCORE_MIN_PROFIT:
+ case SCORE_MIN_INCOME:
+ case SCORE_MAX_INCOME:
+ case SCORE_MONEY:
+ case SCORE_LOAN:
+ DrawString(167, y, STR_PERFORMANCE_DETAIL_AMOUNT_CURRENCY, TC_FROMSTRING);
+ break;
+ default:
+ DrawString(167, y, STR_PERFORMANCE_DETAIL_AMOUNT_INT, TC_FROMSTRING);
+ }
+ }
}
-}
+
+ virtual void OnClick(Point pt, int widget)
+ {
+ /* Check which button is clicked */
+ if (IsInsideMM(widget, 13, 21)) {
+ /* Is it no on disable? */
+ if (!this->IsWidgetDisabled(widget)) {
+ this->RaiseWidget(player + 13);
+ player = (PlayerID)(widget - 13);
+ this->LowerWidget(player + 13);
+ this->SetDirty();
+ }
+ }
+ }
+
+ virtual void OnTick()
+ {
+ if (_pause_game != 0) return;
+
+ /* Update the player score every 5 days */
+ if (--this->timeout == 0) {
+ this->UpdatePlayerStats();
+ this->SetDirty();
+ }
+ }
+};
+
+PlayerID PerformanceRatingDetailWindow::player = INVALID_PLAYER;
+
static const Widget _performance_rating_detail_widgets[] = {
{ WWT_CLOSEBOX, RESIZE_NONE, 14, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW},
@@ -1158,10 +1041,9 @@
WC_PERFORMANCE_DETAIL, WC_NONE,
WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET,
_performance_rating_detail_widgets,
- PerformanceRatingDetailWndProc
};
void ShowPerformanceRatingDetail()
{
- AllocateWindowDescFront<Window>(&_performance_rating_detail_desc, 0);
+ AllocateWindowDescFront<PerformanceRatingDetailWindow>(&_performance_rating_detail_desc, 0);
}
--- a/src/group_gui.cpp Mon May 19 14:14:33 2008 +0000
+++ b/src/group_gui.cpp Mon May 19 15:13:58 2008 +0000
@@ -187,9 +187,10 @@
VehicleID vehicle_sel;
GUIGroupList groups;
- VehicleGroupWindow(const WindowDesc *desc, WindowNumber window_number) : Window(desc, NULL, window_number)
+ VehicleGroupWindow(const WindowDesc *desc, WindowNumber window_number) : Window(desc, window_number)
{
const PlayerID owner = (PlayerID)GB(this->window_number, 0, 8);
+ this->vehicle_type = (VehicleType)GB(this->window_number, 11, 5);
this->caption_color = owner;
this->hscroll.cap = 224;
@@ -222,8 +223,6 @@
case VEH_AIRCRAFT: this->sorting = &_sorting.aircraft; break;
}
- this->vehicle_type = (VehicleType)GB(this->window_number, 11, 5);
-
this->vehicles.sort_list = NULL;
this->vehicles.sort_type = this->sorting->criteria;
this->vehicles.flags = VL_REBUILD | (this->sorting->order ? VL_DESC : VL_NONE);
@@ -287,8 +286,8 @@
virtual void OnInvalidateData(int data)
{
- this->vehicles.flags |= VL_REBUILD;
- this->groups.flags |= VL_REBUILD;
+ this->vehicles.flags |= (data == 0 ? VL_REBUILD : VL_RESORT);
+ this->groups.flags |= (data == 0 ? VL_REBUILD : VL_RESORT);
if (!(IsAllGroupID(this->group_sel) || IsDefaultGroupID(this->group_sel) || IsValidGroupID(this->group_sel))) {
this->group_sel = ALL_GROUP;
HideDropDownMenu(this);
@@ -404,7 +403,7 @@
/* Set text of sort by dropdown */
this->widget[GRP_WIDGET_SORT_BY_DROPDOWN].data = _vehicle_sort_listing[this->vehicles.sort_type];
- DrawWindowWidgets(this);
+ this->DrawWidgets();
/* Draw Matrix Group
* The selected group is drawn in white */
@@ -452,7 +451,7 @@
DrawStringRightAligned(187, y1 + 1, STR_GROUP_TINY_NUM, (this->group_sel == g->index) ? TC_WHITE : TC_BLACK);
}
- DrawSortButtonState(this, GRP_WIDGET_SORT_BY_ORDER, this->vehicles.flags & VL_DESC ? SBS_DOWN : SBS_UP);
+ this->DrawSortButtonState(GRP_WIDGET_SORT_BY_ORDER, this->vehicles.flags & VL_DESC ? SBS_DOWN : SBS_UP);
/* Draw Matrix Vehicle according to the vehicle list built before */
max = min(this->vscroll2.pos + this->vscroll2.cap, this->vehicles.list_length);
@@ -758,7 +757,6 @@
WC_TRAINS_LIST, WC_NONE,
WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS | WDF_STICKY_BUTTON | WDF_RESIZABLE,
_group_widgets,
- NULL
};
void ShowPlayerGroup(PlayerID player, VehicleType vehicle_type)
--- a/src/gui.h Mon May 19 14:14:33 2008 +0000
+++ b/src/gui.h Mon May 19 15:13:58 2008 +0000
@@ -52,7 +52,6 @@
void PlaceLandBlockInfo();
void ShowAboutWindow();
void ShowBuildTreesToolbar();
-void ShowBuildTreesScenToolbar();
void ShowTownDirectory();
void ShowIndustryDirectory();
void ShowSubsidiesList();
--- a/src/industry.h Mon May 19 14:14:33 2008 +0000
+++ b/src/industry.h Mon May 19 15:13:58 2008 +0000
@@ -354,9 +354,6 @@
#define FOR_ALL_INDUSTRIES_FROM(i, start) for (i = GetIndustry(start); i != NULL; i = (i->index + 1U < GetIndustryPoolSize()) ? GetIndustry(i->index + 1U) : NULL) if (i->IsValid())
#define FOR_ALL_INDUSTRIES(i) FOR_ALL_INDUSTRIES_FROM(i, 0)
-extern const Industry **_industry_sort;
-extern bool _industry_sort_dirty;
-
static const uint8 IT_INVALID = 255;
#endif /* INDUSTRY_H */
--- a/src/industry_cmd.cpp Mon May 19 14:14:33 2008 +0000
+++ b/src/industry_cmd.cpp Mon May 19 15:13:58 2008 +0000
@@ -55,9 +55,6 @@
int _total_industries; //general counter
uint16 _industry_counts[NUM_INDUSTRYTYPES]; // Number of industries per type ingame
-const Industry **_industry_sort;
-bool _industry_sort_dirty;
-
IndustrySpec _industry_specs[NUM_INDUSTRYTYPES];
IndustryTileSpec _industry_tile_specs[NUM_INDUSTRYTILES];
@@ -168,12 +165,11 @@
} END_TILE_LOOP(tile_cur, 42, 42, this->xy - TileDiff(21, 21))
}
- _industry_sort_dirty = true;
DecIndustryTypeCount(this->type);
DeleteSubsidyWithIndustry(this->index);
DeleteWindowById(WC_INDUSTRY_VIEW, this->index);
- InvalidateWindow(WC_INDUSTRY_DIRECTORY, 0);
+ InvalidateWindowData(WC_INDUSTRY_DIRECTORY, 0, 0);
this->xy = 0;
}
@@ -1556,8 +1552,7 @@
if (GetIndustrySpec(i->type)->behaviour & INDUSTRYBEH_PLANT_ON_BUILT) {
for (j = 0; j != 50; j++) PlantRandomFarmField(i);
}
- _industry_sort_dirty = true;
- InvalidateWindow(WC_INDUSTRY_DIRECTORY, 0);
+ InvalidateWindowData(WC_INDUSTRY_DIRECTORY, 0, 0);
}
/** Helper function for Build/Fund an industry
@@ -1651,7 +1646,7 @@
SetDParam(1, ind->town->index);
}
AddNewsItem(indspec->new_industry_text,
- NM_THIN, NF_VIEWPORT | NF_TILE, NT_OPENCLOSE, DNC_NONE, ind->xy, 0);
+ NS_OPENCLOSE, ind->xy, 0);
break;
}
}
@@ -1870,7 +1865,7 @@
SetDParam(1, ind->town->index);
}
AddNewsItem(ind_spc->new_industry_text,
- NM_THIN, NF_VIEWPORT | NF_TILE, NT_OPENCLOSE, DNC_NONE, ind->xy, 0);
+ NS_OPENCLOSE, ind->xy, 0);
}
/**
@@ -2002,12 +1997,12 @@
*/
static void ReportNewsProductionChangeIndustry(Industry *ind, CargoID type, int percent)
{
- NewsType nt;
+ NewsSubtype ns;
switch (WhoCanServiceIndustry(ind)) {
- case 0: nt = NT_INDUSTRY_NOBODY; break;
- case 1: nt = NT_INDUSTRY_OTHER; break;
- case 2: nt = NT_INDUSTRY_PLAYER; break;
+ case 0: ns = NS_INDUSTRY_NOBODY; break;
+ case 1: ns = NS_INDUSTRY_OTHER; break;
+ case 2: ns = NS_INDUSTRY_PLAYER; break;
default: NOT_REACHED(); break;
}
SetDParam(2, abs(percent));
@@ -2015,7 +2010,7 @@
SetDParam(1, ind->index);
AddNewsItem(
percent >= 0 ? STR_INDUSTRY_PROD_GOUP : STR_INDUSTRY_PROD_GODOWN,
- NM_THIN, NF_VIEWPORT | NF_TILE, nt, DNC_NONE,
+ ns,
ind->xy + TileDiffXY(1, 1), 0
);
}
@@ -2183,15 +2178,15 @@
}
if (!suppress_message && str != STR_NULL) {
- NewsType nt;
+ NewsSubtype ns;
/* Compute news category */
if (closeit) {
- nt = NT_OPENCLOSE;
+ ns = NS_OPENCLOSE;
} else {
switch (WhoCanServiceIndustry(i)) {
- case 0: nt = NT_INDUSTRY_NOBODY; break;
- case 1: nt = NT_INDUSTRY_OTHER; break;
- case 2: nt = NT_INDUSTRY_PLAYER; break;
+ case 0: ns = NS_INDUSTRY_NOBODY; break;
+ case 1: ns = NS_INDUSTRY_OTHER; break;
+ case 2: ns = NS_INDUSTRY_PLAYER; break;
default: NOT_REACHED(); break;
}
}
@@ -2209,7 +2204,7 @@
}
/* and report the news to the user */
AddNewsItem(str,
- NM_THIN, NF_VIEWPORT | NF_TILE, nt, DNC_NONE,
+ ns,
i->xy + TileDiffXY(1, 1), 0);
}
}
@@ -2240,8 +2235,7 @@
_current_player = old_player;
/* production-change */
- _industry_sort_dirty = true;
- InvalidateWindow(WC_INDUSTRY_DIRECTORY, 0);
+ InvalidateWindowData(WC_INDUSTRY_DIRECTORY, 0, 1);
}
@@ -2251,7 +2245,6 @@
_Industry_pool.AddBlockToPool();
ResetIndustryCounts();
- _industry_sort_dirty = true;
_industry_sound_tile = 0;
}
--- a/src/industry_gui.cpp Mon May 19 14:14:33 2008 +0000
+++ b/src/industry_gui.cpp Mon May 19 15:13:58 2008 +0000
@@ -26,6 +26,7 @@
#include "settings_type.h"
#include "tilehighlight_func.h"
#include "string_func.h"
+#include "sortlist_type.h"
#include "table/strings.h"
#include "table/sprites.h"
@@ -90,7 +91,6 @@
WC_BUILD_INDUSTRY, WC_NONE,
WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_RESIZABLE,
_build_industry_widgets,
- NULL,
};
class BuildIndustryWindow : public Window {
@@ -103,14 +103,60 @@
StringID text[NUM_INDUSTRYTYPES + 1]; ///< Text coming from CBM_IND_FUND_MORE_TEXT (if ever)
bool enabled[NUM_INDUSTRYTYPES + 1]; ///< availability state, coming from CBID_INDUSTRY_AVAILABLE (if ever)
-public:
- BuildIndustryWindow() : Window(&_build_industry_desc)
+ void SetupArrays()
{
IndustryType ind;
const IndustrySpec *indsp;
+ this->count = 0;
+
+ for (uint i = 0; i < lengthof(this->index); i++) {
+ this->index[i] = INVALID_INDUSTRYTYPE;
+ this->text[i] = STR_NULL;
+ this->enabled[i] = false;
+ }
+
+ if (_game_mode == GM_EDITOR) { // give room for the Many Random "button"
+ this->index[this->count] = INVALID_INDUSTRYTYPE;
+ this->count++;
+ this->timer_enabled = false;
+ }
+ /* Fill the arrays with industries.
+ * The tests performed after the enabled allow to load the industries
+ * In the same way they are inserted by grf (if any)
+ */
+ for (ind = 0; ind < NUM_INDUSTRYTYPES; ind++) {
+ indsp = GetIndustrySpec(ind);
+ if (indsp->enabled){
+ /* Rule is that editor mode loads all industries.
+ * In game mode, all non raw industries are loaded too
+ * and raw ones are loaded only when setting allows it */
+ if (_game_mode != GM_EDITOR && indsp->IsRawIndustry() && _patches.raw_industry_construction == 0) {
+ /* Unselect if the industry is no longer in the list */
+ if (this->selected_type == ind) this->selected_index = -1;
+ continue;
+ }
+ this->index[this->count] = ind;
+ this->enabled[this->count] = (_game_mode == GM_EDITOR) || CheckIfCallBackAllowsAvailability(ind, IACT_USERCREATION);
+ /* Keep the selection to the correct line */
+ if (this->selected_type == ind) this->selected_index = this->count;
+ this->count++;
+ }
+ }
+
+ /* first indutry type is selected if the current selection is invalid.
+ * I'll be damned if there are none available ;) */
+ if (this->selected_index == -1) {
+ this->selected_index = 0;
+ this->selected_type = this->index[0];
+ }
+ }
+
+public:
+ BuildIndustryWindow() : Window(&_build_industry_desc)
+ {
/* Shorten the window to the equivalant of the additionnal purchase
- * info coming from the callback. SO it will only be available to tis full
+ * info coming from the callback. SO it will only be available to its full
* height when newindistries are loaded */
if (!_loaded_newgrf_features.has_newindustries) {
this->widget[DPIW_INFOPANEL].bottom -= 44;
@@ -123,45 +169,15 @@
this->timer_enabled = _loaded_newgrf_features.has_newindustries;
- /* Initialize structures */
- this->count = 0;
-
- for (uint i = 0; i < lengthof(this->index); i++) {
- this->index[i] = 0xFF;
- this->text[i] = STR_NULL;
- this->enabled[i] = false;
- }
-
this->vscroll.cap = 8; // rows in grid, same in scroller
this->resize.step_height = 13;
- if (_game_mode == GM_EDITOR) { // give room for the Many Random "button"
- this->index[this->count] = INVALID_INDUSTRYTYPE;
- this->count++;
- this->timer_enabled = false;
- }
+ this->selected_index = -1;
+ this->selected_type = INVALID_INDUSTRYTYPE;
- /* Fill the _fund_gui structure with industries.
- * The tests performed after the enabled allow to load the industries
- * In the same way they are inserted by grf (if any)
- */
- for (ind = 0; ind < NUM_INDUSTRYTYPES; ind++) {
- indsp = GetIndustrySpec(ind);
- if (indsp->enabled){
- /* Rule is that editor mode loads all industries.
- * In game mode, all non raw industries are loaded too
- * and raw ones are loaded only when setting allows it */
- if (_game_mode != GM_EDITOR && indsp->IsRawIndustry() && _patches.raw_industry_construction == 0) continue;
- this->index[this->count] = ind;
- this->enabled[this->count] = (_game_mode == GM_EDITOR) || CheckIfCallBackAllowsAvailability(ind, IACT_USERCREATION);
- this->count++;
- }
- }
+ /* Initialize arrays */
+ this->SetupArrays();
- /* first indutry type is selected.
- * I'll be damned if there are none available ;) */
- this->selected_index = 0;
- this->selected_type = this->index[0];
this->callback_timer = DAY_TICKS;
this->FindWindowPlacementAndResize(&_build_industry_desc);
@@ -188,7 +204,7 @@
SetVScrollCount(this, this->count);
- DrawWindowWidgets(this);
+ this->DrawWidgets();
/* and now with the matrix painting */
for (byte i = 0; i < this->vscroll.cap && ((i + this->vscroll.pos) < this->count); i++) {
@@ -392,6 +408,12 @@
{
this->RaiseButtons();
}
+
+ virtual void OnInvalidateData(int data = 0)
+ {
+ this->SetupArrays();
+ this->SetDirty();
+ }
};
void ShowBuildIndustryWindow()
@@ -440,7 +462,7 @@
byte production_offset_y; ///< The offset of the production texts/buttons
public:
- IndustryViewWindow(const WindowDesc *desc, void *data, WindowNumber window_number) : Window(desc, data, window_number)
+ IndustryViewWindow(const WindowDesc *desc, WindowNumber window_number) : Window(desc, window_number)
{
this->flags4 |= WF_DISABLE_VP_SCROLL;
this->editbox_line = 0;
@@ -459,7 +481,7 @@
bool has_accept = false;
SetDParam(0, this->window_number);
- DrawWindowWidgets(this);
+ this->DrawWidgets();
if (HasBit(ind->callback_flags, CBM_IND_PRODUCTION_CARGO_ARRIVAL) || HasBit(ind->callback_flags, CBM_IND_PRODUCTION_256_TICKS)) {
for (byte j = 0; j < lengthof(i->accepts_cargo); j++) {
@@ -542,7 +564,7 @@
return;
}
- DrawWindowViewport(this);
+ this->DrawViewport();
}
virtual void OnClick(Point pt, int widget)
@@ -657,7 +679,6 @@
WC_INDUSTRY_VIEW, WC_NONE,
WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS | WDF_STICKY_BUTTON | WDF_RESIZABLE,
_industry_view_widgets,
- NULL
};
void ShowIndustryViewWindow(int industry)
@@ -675,7 +696,7 @@
IDW_SORTBYPROD,
IDW_SORTBYTRANSPORT,
IDW_SPACER,
- IDW_INDUSRTY_LIST,
+ IDW_INDUSTRY_LIST,
IDW_SCROLLBAR,
IDW_RESIZE,
};
@@ -696,12 +717,9 @@
{ WIDGETS_END},
};
-static uint _num_industry_sort;
-
static char _bufcache[96];
static const Industry* _last_industry;
-
-static byte _industry_sort_order;
+static int _internal_sort_order;
static int CDECL GeneralIndustrySorter(const void *a, const void *b)
{
@@ -709,7 +727,7 @@
const Industry* j = *(const Industry**)b;
int r;
- switch (_industry_sort_order >> 1) {
+ switch (_internal_sort_order >> 1) {
default: NOT_REACHED();
case 0: /* Sort by Name (handled later) */
r = 0;
@@ -776,138 +794,171 @@
r = strcmp(buf1, _bufcache);
}
- if (_industry_sort_order & 1) r = -r;
+ if (_internal_sort_order & 1) r = -r;
return r;
}
+typedef GUIList<const Industry*> GUIIndustryList;
+
/**
- * Makes a sorted industry list.
- * When there are no industries, the list has to be made. This so when one
- * starts a new game without industries after playing a game with industries
- * the list is not populated with invalid industries from the previous game.
+ * Rebuild industries list if the VL_REBUILD flag is set
+ *
+ * @param sl pointer to industry list
*/
-static void MakeSortedIndustryList()
+static void BuildIndustriesList(GUIIndustryList *sl)
{
- const Industry* i;
- int n = 0;
+ uint n = 0;
+ const Industry *i;
+
+ if (!(sl->flags & VL_REBUILD)) return;
/* Create array for sorting */
- _industry_sort = ReallocT(_industry_sort, GetMaxIndustryIndex() + 1);
+ const Industry **industry_sort = MallocT<const Industry*>(GetMaxIndustryIndex() + 1);
- /* Don't attempt a sort if there are no industries */
- if (GetNumIndustries() != 0) {
- FOR_ALL_INDUSTRIES(i) _industry_sort[n++] = i;
- qsort((void*)_industry_sort, n, sizeof(_industry_sort[0]), GeneralIndustrySorter);
- }
+ DEBUG(misc, 3, "Building industry list");
- _num_industry_sort = n;
- _last_industry = NULL; // used for "cache"
+ FOR_ALL_INDUSTRIES(i) industry_sort[n++] = i;
- DEBUG(misc, 3, "Resorting industries list");
+ free((void*)sl->sort_list);
+ sl->sort_list = MallocT<const Industry*>(n);
+ sl->list_length = n;
+
+ for (uint i = 0; i < n; ++i) sl->sort_list[i] = industry_sort[i];
+
+ sl->flags &= ~VL_REBUILD;
+ sl->flags |= VL_RESORT;
+ free((void*)industry_sort);
}
-static void IndustryDirectoryWndProc(Window *w, WindowEvent *e)
+/**
+ * Sort industry list if the VL_RESORT flag is set
+ *
+ * @param sl pointer to industry list
+ */
+static void SortIndustriesList(GUIIndustryList *sl)
{
- switch (e->event) {
- case WE_PAINT: {
- if (_industry_sort_dirty) {
- _industry_sort_dirty = false;
- MakeSortedIndustryList();
+ if (!(sl->flags & VL_RESORT)) return;
+
+ _internal_sort_order = (sl->sort_type << 1) | (sl->flags & VL_DESC);
+ _last_industry = NULL; // used for "cache" in namesorting
+ qsort((void*)sl->sort_list, sl->list_length, sizeof(sl->sort_list[0]), &GeneralIndustrySorter);
+
+ sl->flags &= ~VL_RESORT;
+}
+
+/**
+ * The list of industries.
+ */
+struct IndustryDirectoryWindow : public Window, public GUIIndustryList {
+ static Listing industry_sort;
+
+ IndustryDirectoryWindow(const WindowDesc *desc, WindowNumber number) : Window(desc, number)
+ {
+ this->vscroll.cap = 16;
+ this->resize.height = this->height - 6 * 10; // minimum 10 items
+ this->resize.step_height = 10;
+ this->FindWindowPlacementAndResize(desc);
+
+ this->sort_list = NULL;
+ this->flags = VL_REBUILD;
+ this->sort_type = industry_sort.criteria;
+ if (industry_sort.order) this->flags |= VL_DESC;
+ }
+
+ virtual void OnPaint()
+ {
+ BuildIndustriesList(this);
+ SortIndustriesList(this);
+
+ SetVScrollCount(this, this->list_length);
+
+ this->DrawWidgets();
+ this->DrawSortButtonState(IDW_SORTBYNAME + this->sort_type, this->flags & VL_DESC ? SBS_DOWN : SBS_UP);
+
+ int max = min(this->vscroll.pos + this->vscroll.cap, this->list_length);
+ int y = 28; // start of the list-widget
+
+ for (int n = this->vscroll.pos; n < max; ++n) {
+ const Industry* i = this->sort_list[n];
+ const IndustrySpec *indsp = GetIndustrySpec(i->type);
+ byte p = 0;
+
+ /* Industry name */
+ SetDParam(p++, i->index);
+
+ /* Industry productions */
+ for (byte j = 0; j < lengthof(i->produced_cargo); j++) {
+ if (i->produced_cargo[j] == CT_INVALID) continue;
+ SetDParam(p++, i->produced_cargo[j]);
+ SetDParam(p++, i->last_month_production[j]);
+ SetDParam(p++, GetCargoSuffix(j + 3, CST_DIR, (Industry*)i, i->type, indsp));
}
- SetVScrollCount(w, _num_industry_sort);
-
- DrawWindowWidgets(w);
- DrawSortButtonState(w, IDW_SORTBYNAME + (_industry_sort_order >> 1), _industry_sort_order & 1 ? SBS_DOWN : SBS_UP);
-
- uint pos = w->vscroll.pos;
- int n = 0;
-
- while (pos < _num_industry_sort) {
- const Industry* i = _industry_sort[pos];
- const IndustrySpec *indsp = GetIndustrySpec(i->type);
- byte p = 0;
-
- /* Industry name */
- SetDParam(p++, i->index);
-
- /* Industry productions */
- for (byte j = 0; j < lengthof(i->produced_cargo); j++) {
- if (i->produced_cargo[j] == CT_INVALID) continue;
- SetDParam(p++, i->produced_cargo[j]);
- SetDParam(p++, i->last_month_production[j]);
- SetDParam(p++, GetCargoSuffix(j + 3, CST_DIR, (Industry*)i, i->type, indsp));
- }
-
- /* Transported productions */
- for (byte j = 0; j < lengthof(i->produced_cargo); j++) {
- if (i->produced_cargo[j] == CT_INVALID) continue;
- SetDParam(p++, i->last_month_pct_transported[j] * 100 >> 8);
- }
-
- /* Drawing the right string */
- StringID str = STR_INDUSTRYDIR_ITEM_NOPROD;
- if (p != 1) str = (p == 5) ? STR_INDUSTRYDIR_ITEM : STR_INDUSTRYDIR_ITEM_TWO;
- DrawStringTruncated(4, 28 + n * 10, str, TC_FROMSTRING, w->widget[IDW_INDUSRTY_LIST].right - 4);
-
- pos++;
- if (++n == w->vscroll.cap) break;
+ /* Transported productions */
+ for (byte j = 0; j < lengthof(i->produced_cargo); j++) {
+ if (i->produced_cargo[j] == CT_INVALID) continue;
+ SetDParam(p++, i->last_month_pct_transported[j] * 100 >> 8);
}
- } break;
- case WE_CLICK:
- switch (e->we.click.widget) {
- case IDW_SORTBYNAME: {
- _industry_sort_order = _industry_sort_order == 0 ? 1 : 0;
- _industry_sort_dirty = true;
- w->SetDirty();
- } break;
-
- case IDW_SORTBYTYPE: {
- _industry_sort_order = _industry_sort_order == 2 ? 3 : 2;
- _industry_sort_dirty = true;
- w->SetDirty();
- } break;
-
- case IDW_SORTBYPROD: {
- _industry_sort_order = _industry_sort_order == 4 ? 5 : 4;
- _industry_sort_dirty = true;
- w->SetDirty();
- } break;
-
- case IDW_SORTBYTRANSPORT: {
- _industry_sort_order = _industry_sort_order == 6 ? 7 : 6;
- _industry_sort_dirty = true;
- w->SetDirty();
- } break;
+ /* Drawing the right string */
+ StringID str = STR_INDUSTRYDIR_ITEM_NOPROD;
+ if (p != 1) str = (p == 5) ? STR_INDUSTRYDIR_ITEM : STR_INDUSTRYDIR_ITEM_TWO;
+ DrawStringTruncated(4, y, str, TC_FROMSTRING, this->widget[IDW_INDUSTRY_LIST].right - 4);
- case IDW_INDUSRTY_LIST: {
- int y = (e->we.click.pt.y - 28) / 10;
- uint16 p;
+ y += 10;
+ }
+ }
- if (!IsInsideMM(y, 0, w->vscroll.cap)) return;
- p = y + w->vscroll.pos;
- if (p < _num_industry_sort) {
- if (_ctrl_pressed) {
- ShowExtraViewPortWindow(_industry_sort[p]->xy);
- } else {
- ScrollMainWindowToTile(_industry_sort[p]->xy);
- }
+ virtual void OnClick(Point pt, int widget)
+ {
+ switch (widget) {
+ case IDW_SORTBYNAME:
+ case IDW_SORTBYTYPE:
+ case IDW_SORTBYPROD:
+ case IDW_SORTBYTRANSPORT:
+ if (this->sort_type == (widget - IDW_SORTBYNAME)) {
+ this->flags ^= VL_DESC;
+ } else {
+ this->sort_type = widget - IDW_SORTBYNAME;
+ this->flags &= ~VL_DESC;
+ }
+ industry_sort.criteria = this->sort_type;
+ industry_sort.order = HasBit(this->flags, 0);
+ this->flags |= VL_RESORT;
+ this->SetDirty();
+ break;
+
+ case IDW_INDUSTRY_LIST: {
+ int y = (pt.y - 28) / 10;
+ uint16 p;
+
+ if (!IsInsideMM(y, 0, this->vscroll.cap)) return;
+ p = y + this->vscroll.pos;
+ if (p < this->list_length) {
+ if (_ctrl_pressed) {
+ ShowExtraViewPortWindow(this->sort_list[p]->xy);
+ } else {
+ ScrollMainWindowToTile(this->sort_list[p]->xy);
}
- } break;
- }
- break;
+ }
+ } break;
+ }
+ }
- case WE_100_TICKS:
- w->SetDirty();
- break;
+ virtual void OnResize(Point new_size, Point delta)
+ {
+ this->vscroll.cap += delta.y / 10;
+ }
- case WE_RESIZE:
- w->vscroll.cap += e->we.sizing.diff.y / 10;
- break;
+ virtual void OnInvalidateData(int data)
+ {
+ this->flags |= (data == 0 ? VL_REBUILD : VL_RESORT);
+ this->InvalidateWidget(IDW_INDUSTRY_LIST);
}
-}
+};
+
+Listing IndustryDirectoryWindow::industry_sort = {0, 0};
/** Window definition of the industy directory gui */
static const WindowDesc _industry_directory_desc = {
@@ -915,17 +966,9 @@
WC_INDUSTRY_DIRECTORY, WC_NONE,
WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS | WDF_STICKY_BUTTON | WDF_RESIZABLE,
_industry_directory_widgets,
- IndustryDirectoryWndProc
};
void ShowIndustryDirectory()
{
- Window *w = AllocateWindowDescFront<Window>(&_industry_directory_desc, 0);
-
- if (w != NULL) {
- w->vscroll.cap = 16;
- w->resize.height = w->height - 6 * 10; // minimum 10 items
- w->resize.step_height = 10;
- w->SetDirty();
- }
+ AllocateWindowDescFront<IndustryDirectoryWindow>(&_industry_directory_desc, 0);
}
--- a/src/intro_gui.cpp Mon May 19 14:14:33 2008 +0000
+++ b/src/intro_gui.cpp Mon May 19 15:13:58 2008 +0000
@@ -53,87 +53,91 @@
InvalidateWindowClasses(WC_SELECT_GAME);
}
-enum SelectGameIntroWidgets {
- SGI_GENERATE_GAME = 2,
- SGI_LOAD_GAME,
- SGI_PLAY_SCENARIO,
- SGI_PLAY_HEIGHTMAP,
- SGI_EDIT_SCENARIO,
- SGI_PLAY_NETWORK,
- SGI_TEMPERATE_LANDSCAPE,
- SGI_ARCTIC_LANDSCAPE,
- SGI_TROPIC_LANDSCAPE,
- SGI_TOYLAND_LANDSCAPE,
- SGI_OPTIONS,
- SGI_DIFFICULTIES,
- SGI_PATCHES_OPTIONS,
- SGI_GRF_SETTINGS,
- SGI_EXIT,
-};
+struct SelectGameWindow : public Window {
+private:
+ enum SelectGameIntroWidgets {
+ SGI_GENERATE_GAME = 2,
+ SGI_LOAD_GAME,
+ SGI_PLAY_SCENARIO,
+ SGI_PLAY_HEIGHTMAP,
+ SGI_EDIT_SCENARIO,
+ SGI_PLAY_NETWORK,
+ SGI_TEMPERATE_LANDSCAPE,
+ SGI_ARCTIC_LANDSCAPE,
+ SGI_TROPIC_LANDSCAPE,
+ SGI_TOYLAND_LANDSCAPE,
+ SGI_OPTIONS,
+ SGI_DIFFICULTIES,
+ SGI_PATCHES_OPTIONS,
+ SGI_GRF_SETTINGS,
+ SGI_EXIT,
+ };
-static void SelectGameWndProc(Window *w, WindowEvent *e)
-{
- switch (e->event) {
- case WE_CREATE: w->LowerWidget(_opt_newgame.landscape + 8); break;
+public:
+ SelectGameWindow(const WindowDesc *desc) : Window(desc)
+ {
+ this->LowerWidget(_opt_newgame.landscape + SGI_TEMPERATE_LANDSCAPE);
+ this->FindWindowPlacementAndResize(desc);
+ }
- case WE_PAINT:
- w->SetWidgetLoweredState(SGI_TEMPERATE_LANDSCAPE, _opt_newgame.landscape == LT_TEMPERATE);
- w->SetWidgetLoweredState(SGI_ARCTIC_LANDSCAPE, _opt_newgame.landscape == LT_ARCTIC);
- w->SetWidgetLoweredState(SGI_TROPIC_LANDSCAPE, _opt_newgame.landscape == LT_TROPIC);
- w->SetWidgetLoweredState(SGI_TOYLAND_LANDSCAPE, _opt_newgame.landscape == LT_TOYLAND);
- SetDParam(0, STR_6801_EASY + _opt_newgame.diff_level);
- DrawWindowWidgets(w);
- break;
+ virtual void OnPaint()
+ {
+ this->SetWidgetLoweredState(SGI_TEMPERATE_LANDSCAPE, _opt_newgame.landscape == LT_TEMPERATE);
+ this->SetWidgetLoweredState(SGI_ARCTIC_LANDSCAPE, _opt_newgame.landscape == LT_ARCTIC);
+ this->SetWidgetLoweredState(SGI_TROPIC_LANDSCAPE, _opt_newgame.landscape == LT_TROPIC);
+ this->SetWidgetLoweredState(SGI_TOYLAND_LANDSCAPE, _opt_newgame.landscape == LT_TOYLAND);
+ SetDParam(0, STR_6801_EASY + _opt_newgame.diff_level);
+ this->DrawWidgets();
+ }
- case WE_CLICK:
+ virtual void OnClick(Point pt, int widget)
+ {
#ifdef ENABLE_NETWORK
- /* Do not create a network server when you (just) have closed one of the game
- * creation/load windows for the network server. */
- if (SGI_GENERATE_GAME <= e->we.click.widget && e->we.click.widget <= SGI_EDIT_SCENARIO) _is_network_server = false;
+ /* Do not create a network server when you (just) have closed one of the game
+ * creation/load windows for the network server. */
+ if (IsInsideMM(widget, SGI_GENERATE_GAME, SGI_EDIT_SCENARIO + 1)) _is_network_server = false;
#endif /* ENABLE_NETWORK */
- switch (e->we.click.widget) {
- case SGI_GENERATE_GAME: ShowGenerateLandscape(); break;
- case SGI_LOAD_GAME: ShowSaveLoadDialog(SLD_LOAD_GAME); break;
- case SGI_PLAY_SCENARIO: ShowSaveLoadDialog(SLD_LOAD_SCENARIO); break;
- case SGI_PLAY_HEIGHTMAP: ShowSaveLoadDialog(SLD_LOAD_HEIGHTMAP); break;
- case SGI_EDIT_SCENARIO: StartScenarioEditor(); break;
-
- case SGI_PLAY_NETWORK:
- if (!_network_available) {
- ShowErrorMessage(INVALID_STRING_ID, STR_NETWORK_ERR_NOTAVAILABLE, 0, 0);
- } else {
- ShowNetworkGameWindow();
- }
- break;
+ switch (widget) {
+ case SGI_GENERATE_GAME: ShowGenerateLandscape(); break;
+ case SGI_LOAD_GAME: ShowSaveLoadDialog(SLD_LOAD_GAME); break;
+ case SGI_PLAY_SCENARIO: ShowSaveLoadDialog(SLD_LOAD_SCENARIO); break;
+ case SGI_PLAY_HEIGHTMAP: ShowSaveLoadDialog(SLD_LOAD_HEIGHTMAP); break;
+ case SGI_EDIT_SCENARIO: StartScenarioEditor(); break;
- case SGI_TEMPERATE_LANDSCAPE: case SGI_ARCTIC_LANDSCAPE:
- case SGI_TROPIC_LANDSCAPE: case SGI_TOYLAND_LANDSCAPE:
- w->RaiseWidget(_opt_newgame.landscape + SGI_TEMPERATE_LANDSCAPE);
- SetNewLandscapeType(e->we.click.widget - SGI_TEMPERATE_LANDSCAPE);
- break;
+ case SGI_PLAY_NETWORK:
+ if (!_network_available) {
+ ShowErrorMessage(INVALID_STRING_ID, STR_NETWORK_ERR_NOTAVAILABLE, 0, 0);
+ } else {
+ ShowNetworkGameWindow();
+ }
+ break;
- case SGI_OPTIONS: ShowGameOptions(); break;
- case SGI_DIFFICULTIES: ShowGameDifficulty(); break;
- case SGI_PATCHES_OPTIONS: ShowPatchesSelection(); break;
- case SGI_GRF_SETTINGS: ShowNewGRFSettings(true, true, false, &_grfconfig_newgame); break;
- case SGI_EXIT: HandleExitGameRequest(); break;
- }
- break;
+ case SGI_TEMPERATE_LANDSCAPE: case SGI_ARCTIC_LANDSCAPE:
+ case SGI_TROPIC_LANDSCAPE: case SGI_TOYLAND_LANDSCAPE:
+ this->RaiseWidget(_opt_newgame.landscape + SGI_TEMPERATE_LANDSCAPE);
+ SetNewLandscapeType(widget - SGI_TEMPERATE_LANDSCAPE);
+ break;
+
+ case SGI_OPTIONS: ShowGameOptions(); break;
+ case SGI_DIFFICULTIES: ShowGameDifficulty(); break;
+ case SGI_PATCHES_OPTIONS: ShowPatchesSelection(); break;
+ case SGI_GRF_SETTINGS: ShowNewGRFSettings(true, true, false, &_grfconfig_newgame); break;
+ case SGI_EXIT: HandleExitGameRequest(); break;
+ }
}
-}
+};
static const WindowDesc _select_game_desc = {
WDP_CENTER, WDP_CENTER, 336, 195, 336, 195,
WC_SELECT_GAME, WC_NONE,
WDF_STD_TOOLTIPS | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS,
_select_game_widgets,
- SelectGameWndProc
};
void ShowSelectGameWindow()
{
- new Window(&_select_game_desc);
+ new SelectGameWindow(&_select_game_desc);
}
static void AskExitGameCallback(Window *w, bool confirmed)
--- a/src/main_gui.cpp Mon May 19 14:14:33 2008 +0000
+++ b/src/main_gui.cpp Mon May 19 15:13:58 2008 +0000
@@ -29,6 +29,7 @@
#include "player_gui.h"
#include "settings_type.h"
#include "toolbar_gui.h"
+#include "statusbar_gui.h"
#include "ai/ai_gui.hpp"
#include "variables.h"
#include "tilehighlight_func.h"
@@ -215,188 +216,194 @@
extern void UpdateAllStationVirtCoord();
-static void MainWindowWndProc(Window *w, WindowEvent *e)
+struct MainWindow : Window
{
- switch (e->event) {
- case WE_PAINT:
- DrawWindowViewport(w);
- if (_game_mode == GM_MENU) {
- int off_x = _screen.width / 2;
-
- DrawSprite(SPR_OTTD_O, PAL_NONE, off_x - 120, 50);
- DrawSprite(SPR_OTTD_P, PAL_NONE, off_x - 86, 50);
- DrawSprite(SPR_OTTD_E, PAL_NONE, off_x - 53, 50);
- DrawSprite(SPR_OTTD_N, PAL_NONE, off_x - 22, 50);
-
- DrawSprite(SPR_OTTD_T, PAL_NONE, off_x + 34, 50);
- DrawSprite(SPR_OTTD_T, PAL_NONE, off_x + 65, 50);
- DrawSprite(SPR_OTTD_D, PAL_NONE, off_x + 96, 50);
- }
- break;
+ MainWindow(int width, int height) : Window(0, 0, width, height, WC_MAIN_WINDOW, NULL)
+ {
+ InitializeWindowViewport(this, 0, 0, width, height, TileXY(32, 32), ZOOM_LVL_VIEWPORT);
+ }
- case WE_KEYPRESS:
- switch (e->we.keypress.keycode) {
- case 'Q' | WKC_CTRL:
- case 'Q' | WKC_META:
- HandleExitGameRequest();
- break;
- }
+ virtual void OnPaint()
+ {
+ this->DrawViewport();
+ if (_game_mode == GM_MENU) {
+ int off_x = _screen.width / 2;
- /* Disable all key shortcuts, except quit shortcuts when
- * generating the world, otherwise they create threading
- * problem during the generating, resulting in random
- * assertions that are hard to trigger and debug */
- if (IsGeneratingWorld()) break;
+ DrawSprite(SPR_OTTD_O, PAL_NONE, off_x - 120, 50);
+ DrawSprite(SPR_OTTD_P, PAL_NONE, off_x - 86, 50);
+ DrawSprite(SPR_OTTD_E, PAL_NONE, off_x - 53, 50);
+ DrawSprite(SPR_OTTD_N, PAL_NONE, off_x - 22, 50);
- if (e->we.keypress.keycode == WKC_BACKQUOTE) {
- IConsoleSwitch();
- e->we.keypress.cont = false;
- break;
- }
+ DrawSprite(SPR_OTTD_T, PAL_NONE, off_x + 34, 50);
+ DrawSprite(SPR_OTTD_T, PAL_NONE, off_x + 65, 50);
+ DrawSprite(SPR_OTTD_D, PAL_NONE, off_x + 96, 50);
+ }
+ }
- if (e->we.keypress.keycode == ('B' | WKC_CTRL)) {
- e->we.keypress.cont = false;
- extern bool _draw_bounding_boxes;
- _draw_bounding_boxes = !_draw_bounding_boxes;
- MarkWholeScreenDirty();
+ virtual EventState OnKeyPress(uint16 key, uint16 keycode)
+ {
+ switch (keycode) {
+ case 'Q' | WKC_CTRL:
+ case 'Q' | WKC_META:
+ HandleExitGameRequest();
+ return ES_HANDLED;
+ }
+
+ /* Disable all key shortcuts, except quit shortcuts when
+ * generating the world, otherwise they create threading
+ * problem during the generating, resulting in random
+ * assertions that are hard to trigger and debug */
+ if (IsGeneratingWorld()) return ES_NOT_HANDLED;
+
+ if (keycode == WKC_BACKQUOTE) {
+ IConsoleSwitch();
+ return ES_HANDLED;
+ }
+
+ if (keycode == ('B' | WKC_CTRL)) {
+ extern bool _draw_bounding_boxes;
+ _draw_bounding_boxes = !_draw_bounding_boxes;
+ MarkWholeScreenDirty();
+ return ES_HANDLED;
+ }
+
+ if (_game_mode == GM_MENU) return ES_NOT_HANDLED;
+
+ switch (keycode) {
+ case 'C':
+ case 'Z': {
+ Point pt = GetTileBelowCursor();
+ if (pt.x != -1) {
+ if (keycode == 'Z') MaxZoomInOut(ZOOM_IN, this);
+ ScrollMainWindowTo(pt.x, pt.y);
+ }
break;
}
- if (_game_mode == GM_MENU) break;
-
- switch (e->we.keypress.keycode) {
- case 'C':
- case 'Z': {
- Point pt = GetTileBelowCursor();
- if (pt.x != -1) {
- if (e->we.keypress.keycode == 'Z') MaxZoomInOut(ZOOM_IN, w);
- ScrollMainWindowTo(pt.x, pt.y);
- }
- break;
- }
-
- case WKC_ESC: ResetObjectToPlace(); break;
- case WKC_DELETE: DeleteNonVitalWindows(); break;
- case WKC_DELETE | WKC_SHIFT: DeleteAllNonVitalWindows(); break;
- case 'R' | WKC_CTRL: MarkWholeScreenDirty(); break;
+ case WKC_ESC: ResetObjectToPlace(); break;
+ case WKC_DELETE: DeleteNonVitalWindows(); break;
+ case WKC_DELETE | WKC_SHIFT: DeleteAllNonVitalWindows(); break;
+ case 'R' | WKC_CTRL: MarkWholeScreenDirty(); break;
#if defined(_DEBUG)
- case '0' | WKC_ALT: // Crash the game
- *(byte*)0 = 0;
- break;
+ case '0' | WKC_ALT: // Crash the game
+ *(byte*)0 = 0;
+ break;
- case '1' | WKC_ALT: // Gimme money
- /* Server can not cheat in advertise mode either! */
- if (!_networking || !_network_server || !_network_advertise)
- DoCommandP(0, 10000000, 0, NULL, CMD_MONEY_CHEAT);
- break;
+ case '1' | WKC_ALT: // Gimme money
+ /* Server can not cheat in advertise mode either! */
+ if (!_networking || !_network_server || !_network_advertise)
+ DoCommandP(0, 10000000, 0, NULL, CMD_MONEY_CHEAT);
+ break;
- case '2' | WKC_ALT: // Update the coordinates of all station signs
- UpdateAllStationVirtCoord();
- break;
+ case '2' | WKC_ALT: // Update the coordinates of all station signs
+ UpdateAllStationVirtCoord();
+ break;
#endif
- case '1' | WKC_CTRL:
- case '2' | WKC_CTRL:
- case '3' | WKC_CTRL:
- case '4' | WKC_CTRL:
- case '5' | WKC_CTRL:
- case '6' | WKC_CTRL:
- case '7' | WKC_CTRL:
- case '8' | WKC_CTRL:
- case '9' | WKC_CTRL:
- /* Transparency toggle hot keys */
- ToggleTransparency((TransparencyOption)(e->we.keypress.keycode - ('1' | WKC_CTRL)));
- MarkWholeScreenDirty();
- break;
+ case '1' | WKC_CTRL:
+ case '2' | WKC_CTRL:
+ case '3' | WKC_CTRL:
+ case '4' | WKC_CTRL:
+ case '5' | WKC_CTRL:
+ case '6' | WKC_CTRL:
+ case '7' | WKC_CTRL:
+ case '8' | WKC_CTRL:
+ case '9' | WKC_CTRL:
+ /* Transparency toggle hot keys */
+ ToggleTransparency((TransparencyOption)(keycode - ('1' | WKC_CTRL)));
+ MarkWholeScreenDirty();
+ break;
- case '1' | WKC_CTRL | WKC_SHIFT:
- case '2' | WKC_CTRL | WKC_SHIFT:
- case '3' | WKC_CTRL | WKC_SHIFT:
- case '4' | WKC_CTRL | WKC_SHIFT:
- case '5' | WKC_CTRL | WKC_SHIFT:
- case '6' | WKC_CTRL | WKC_SHIFT:
- case '7' | WKC_CTRL | WKC_SHIFT:
- case '8' | WKC_CTRL | WKC_SHIFT:
- /* Invisibility toggle hot keys */
- ToggleInvisibilityWithTransparency((TransparencyOption)(e->we.keypress.keycode - ('1' | WKC_CTRL | WKC_SHIFT)));
- MarkWholeScreenDirty();
- break;
+ case '1' | WKC_CTRL | WKC_SHIFT:
+ case '2' | WKC_CTRL | WKC_SHIFT:
+ case '3' | WKC_CTRL | WKC_SHIFT:
+ case '4' | WKC_CTRL | WKC_SHIFT:
+ case '5' | WKC_CTRL | WKC_SHIFT:
+ case '6' | WKC_CTRL | WKC_SHIFT:
+ case '7' | WKC_CTRL | WKC_SHIFT:
+ case '8' | WKC_CTRL | WKC_SHIFT:
+ /* Invisibility toggle hot keys */
+ ToggleInvisibilityWithTransparency((TransparencyOption)(keycode - ('1' | WKC_CTRL | WKC_SHIFT)));
+ MarkWholeScreenDirty();
+ break;
- case 'X' | WKC_CTRL:
- ShowTransparencyToolbar();
- break;
+ case 'X' | WKC_CTRL:
+ ShowTransparencyToolbar();
+ break;
- case 'X':
- ResetRestoreAllTransparency();
- break;
+ case 'X':
+ ResetRestoreAllTransparency();
+ break;
#ifdef ENABLE_NETWORK
- case WKC_RETURN: case 'T': // smart chat; send to team if any, otherwise to all
- if (_networking) {
- const NetworkClientInfo *cio = NetworkFindClientInfoFromIndex(_network_own_client_index);
- bool teamchat = false;
-
- if (cio == NULL) break;
+ case WKC_RETURN: case 'T': // smart chat; send to team if any, otherwise to all
+ if (_networking) {
+ const NetworkClientInfo *cio = NetworkFindClientInfoFromIndex(_network_own_client_index);
+ bool teamchat = false;
- /* Only players actually playing can speak to team. Eg spectators cannot */
- if (_patches.prefer_teamchat && IsValidPlayer(cio->client_playas)) {
- const NetworkClientInfo *ci;
- FOR_ALL_ACTIVE_CLIENT_INFOS(ci) {
- if (ci->client_playas == cio->client_playas && ci != cio) {
- teamchat = true;
- break;
- }
+ if (cio == NULL) break;
+
+ /* Only players actually playing can speak to team. Eg spectators cannot */
+ if (_patches.prefer_teamchat && IsValidPlayer(cio->client_playas)) {
+ const NetworkClientInfo *ci;
+ FOR_ALL_ACTIVE_CLIENT_INFOS(ci) {
+ if (ci->client_playas == cio->client_playas && ci != cio) {
+ teamchat = true;
+ break;
}
}
-
- ShowNetworkChatQueryWindow(teamchat ? DESTTYPE_TEAM : DESTTYPE_BROADCAST, cio->client_playas);
}
- break;
- case WKC_SHIFT | WKC_RETURN: case WKC_SHIFT | 'T': // send text message to all players
- if (_networking) ShowNetworkChatQueryWindow(DESTTYPE_BROADCAST, 0);
- break;
+ ShowNetworkChatQueryWindow(teamchat ? DESTTYPE_TEAM : DESTTYPE_BROADCAST, cio->client_playas);
+ }
+ break;
- case WKC_CTRL | WKC_RETURN: case WKC_CTRL | 'T': // send text to all team mates
- if (_networking) {
- const NetworkClientInfo *cio = NetworkFindClientInfoFromIndex(_network_own_client_index);
- if (cio == NULL) break;
+ case WKC_SHIFT | WKC_RETURN: case WKC_SHIFT | 'T': // send text message to all players
+ if (_networking) ShowNetworkChatQueryWindow(DESTTYPE_BROADCAST, 0);
+ break;
- ShowNetworkChatQueryWindow(DESTTYPE_TEAM, cio->client_playas);
- }
- break;
+ case WKC_CTRL | WKC_RETURN: case WKC_CTRL | 'T': // send text to all team mates
+ if (_networking) {
+ const NetworkClientInfo *cio = NetworkFindClientInfoFromIndex(_network_own_client_index);
+ if (cio == NULL) break;
+
+ ShowNetworkChatQueryWindow(DESTTYPE_TEAM, cio->client_playas);
+ }
+ break;
#endif
- default: return;
- }
- e->we.keypress.cont = false;
- break;
-
- case WE_SCROLL: {
- ViewPort *vp = IsPtInWindowViewport(w, _cursor.pos.x, _cursor.pos.y);
-
- if (vp == NULL) {
- _cursor.fix_at = false;
- _scrolling_viewport = false;
- }
+ default: return ES_NOT_HANDLED;
+ }
+ return ES_HANDLED;
+ }
- w->viewport->scrollpos_x += ScaleByZoom(e->we.scroll.delta.x, vp->zoom);
- w->viewport->scrollpos_y += ScaleByZoom(e->we.scroll.delta.y, vp->zoom);
- w->viewport->dest_scrollpos_x = w->viewport->scrollpos_x;
- w->viewport->dest_scrollpos_y = w->viewport->scrollpos_y;
- } break;
+ virtual void OnScroll(Point delta)
+ {
+ ViewPort *vp = IsPtInWindowViewport(this, _cursor.pos.x, _cursor.pos.y);
- case WE_MOUSEWHEEL:
- ZoomInOrOutToCursorWindow(e->we.wheel.wheel < 0, w);
- break;
+ if (vp == NULL) {
+ _cursor.fix_at = false;
+ _scrolling_viewport = false;
+ }
- case WE_INVALIDATE_DATA:
- /* Forward the message to the appropiate toolbar (ingame or scenario editor) */
- InvalidateWindowData(WC_MAIN_TOOLBAR, 0, e->we.invalidate.data);
- break;
+ this->viewport->scrollpos_x += ScaleByZoom(delta.x, vp->zoom);
+ this->viewport->scrollpos_y += ScaleByZoom(delta.y, vp->zoom);
+ this->viewport->dest_scrollpos_x = this->viewport->scrollpos_x;
+ this->viewport->dest_scrollpos_y = this->viewport->scrollpos_y;
+ };
+
+ virtual void OnMouseWheel(int wheel)
+ {
+ ZoomInOrOutToCursorWindow(wheel < 0, this);
}
-}
+
+ virtual void OnInvalidateData(int data)
+ {
+ /* Forward the message to the appropiate toolbar (ingame or scenario editor) */
+ InvalidateWindowData(WC_MAIN_TOOLBAR, 0, data);
+ }
+};
void ShowSelectGameWindow();
@@ -410,11 +417,7 @@
memcpy(_colour_gradient[i], b + 0xC6, sizeof(_colour_gradient[i]));
}
- int width = _screen.width;
- int height = _screen.height;
-
- Window *w = new Window(0, 0, width, height, MainWindowWndProc, WC_MAIN_WINDOW, NULL);
- InitializeWindowViewport(w, 0, 0, width, height, TileXY(32, 32), ZOOM_LVL_VIEWPORT);
+ new MainWindow(_screen.width, _screen.height);
/* XXX: these are not done */
switch (_game_mode) {
@@ -430,12 +433,9 @@
}
}
-extern void ShowStatusBar();
-
void ShowVitalWindows()
{
- Window *w = AllocateToolbar();
- DoZoomInOutWindow(ZOOM_NONE, w);
+ AllocateToolbar();
/* Status bad only for normal games */
if (_game_mode == GM_EDITOR) return;
--- a/src/misc.cpp Mon May 19 14:14:33 2008 +0000
+++ b/src/misc.cpp Mon May 19 15:13:58 2008 +0000
@@ -28,6 +28,7 @@
#include "animated_tile_func.h"
#include "settings_type.h"
#include "tilehighlight_func.h"
+#include "core/bitmath_func.hpp"
#include "table/strings.h"
#include "table/sprites.h"
--- a/src/misc_gui.cpp Mon May 19 14:14:33 2008 +0000
+++ b/src/misc_gui.cpp Mon May 19 15:13:58 2008 +0000
@@ -69,7 +69,6 @@
WC_LAND_INFO, WC_NONE,
WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET,
_land_info_widgets,
- NULL
};
class LandInfoWindow : public Window {
@@ -83,7 +82,7 @@
virtual void OnPaint()
{
- DrawWindowWidgets(this);
+ this->DrawWidgets();
DoDrawStringCentered(140, 16, this->landinfo_data[0], TC_LIGHT_BLUE);
DoDrawStringCentered(140, 27, this->landinfo_data[1], TC_FROMSTRING);
@@ -206,107 +205,6 @@
}
}
-struct scroller_d {
- int height;
- uint16 counter;
-};
-assert_compile(WINDOW_CUSTOM_SIZE >= sizeof(scroller_d));
-
-static const char *credits[] = {
- /*************************************************************************
- * maximum length of string which fits in window -^*/
- "Original design by Chris Sawyer",
- "Original graphics by Simon Foster",
- "",
- "The OpenTTD team (in alphabetical order):",
- " Jean-Francois Claeys (Belugas) - GUI, newindustries and more",
- " Bjarni Corfitzen (Bjarni) - MacOSX port, coder and vehicles",
- " Matthijs Kooijman (blathijs) - Pathfinder-guru, pool rework",
- " Loïc Guilloux (glx) - General coding",
- " Christoph Elsenhans (frosch) - General coding",
- " Jaroslav Mazanec (KUDr) - YAPG (Yet Another Pathfinder God) ;)",
- " Jonathan Coome (Maedhros) - High priest of the newGRF Temple",
- " Attila Bán (MiHaMiX) - WebTranslator, Nightlies, Wiki and bugtracker host",
- " Owen Rudge (orudge) - Forum host, OS/2 port",
- " Peter Nelson (peter1138) - Spiritual descendant from newGRF gods",
- " Remko Bijker (Rubidium) - Lead coder and way more",
- " Benedikt Brüggemeier (skidd13) - Bug fixer and code reworker",
- " Zdenek Sojka (SmatZ) - Bug finder and fixer",
- "",
- "Inactive Developers:",
- " Victor Fischer (Celestar) - Programming everywhere you need him to",
- " Tamás Faragó (Darkvater) - Ex-Lead coder",
- " Christoph Mallon (Tron) - Programmer, code correctness police",
- "",
- "Retired Developers:",
- " Ludvig Strigeus (ludde) - OpenTTD author, main coder (0.1 - 0.3.3)",
- " Serge Paquet (vurlix) - Assistant project manager, coder (0.1 - 0.3.3)",
- " Dominik Scherer (dominik81) - Lead programmer, GUI expert (0.3.0 - 0.3.6)",
- " Patric Stout (TrueLight) - Programmer, webhoster (0.3 - pre0.6)",
- "",
- "Special thanks go out to:",
- " Josef Drexler - For his great work on TTDPatch",
- " Marcin Grzegorczyk - For his documentation of TTD internals",
- " Petr Baudis (pasky) - Many patches, newGRF support",
- " Stefan Meißner (sign_de) - For his work on the console",
- " Simon Sasburg (HackyKid) - Many bugfixes he has blessed us with",
- " Cian Duffy (MYOB) - BeOS port / manual writing",
- " Christian Rosentreter (tokai) - MorphOS / AmigaOS port",
- " Richard Kempton (richK) - additional airports, initial TGP implementation",
- "",
- " Michael Blunck - Pre-Signals and Semaphores © 2003",
- " George - Canal/Lock graphics © 2003-2004",
- " David Dallaston - Tram tracks",
- " Marcin Grzegorczyk - Foundations for Tracks on Slopes",
- " All Translators - Who made OpenTTD a truly international game",
- " Bug Reporters - Without whom OpenTTD would still be full of bugs!",
- "",
- "",
- "And last but not least:",
- " Chris Sawyer - For an amazing game!"
-};
-
-static void AboutWindowProc(Window *w, WindowEvent *e)
-{
- switch (e->event) {
- case WE_CREATE: // Set up window counter and start position of scroller
- WP(w, scroller_d).counter = 5;
- WP(w, scroller_d).height = w->height - 40;
- break;
-
- case WE_PAINT: {
- int y = WP(w, scroller_d).height;
- DrawWindowWidgets(w);
-
- /* Show original copyright and revision version */
- DrawStringCentered(210, 17, STR_00B6_ORIGINAL_COPYRIGHT, TC_FROMSTRING);
- DrawStringCentered(210, 17 + 10, STR_00B7_VERSION, TC_FROMSTRING);
-
- /* Show all scrolling credits */
- for (uint i = 0; i < lengthof(credits); i++) {
- if (y >= 50 && y < (w->height - 40)) {
- DoDrawString(credits[i], 10, y, TC_BLACK);
- }
- y += 10;
- }
-
- /* If the last text has scrolled start anew from the start */
- if (y < 50) WP(w, scroller_d).height = w->height - 40;
-
- DoDrawStringCentered(210, w->height - 25, "Website: http://www.openttd.org", TC_BLACK);
- DrawStringCentered(210, w->height - 15, STR_00BA_COPYRIGHT_OPENTTD, TC_FROMSTRING);
- } break;
-
- case WE_TICK: // Timer to scroll the text and adjust the new top
- if (--WP(w, scroller_d).counter == 0) {
- WP(w, scroller_d).counter = 5;
- WP(w, scroller_d).height--;
- w->SetDirty();
- }
- break;
- }
-}
-
static const Widget _about_widgets[] = {
{ WWT_CLOSEBOX, RESIZE_NONE, 14, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW},
{ WWT_CAPTION, RESIZE_NONE, 14, 11, 419, 0, 13, STR_015B_OPENTTD, STR_NULL},
@@ -320,21 +218,114 @@
WC_GAME_OPTIONS, WC_NONE,
WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET,
_about_widgets,
- AboutWindowProc
};
+struct AboutWindow : public Window {
+ int scroll_height;
+ uint16 counter;
+
+ AboutWindow() : Window(&_about_desc)
+ {
+ this->counter = 5;
+ this->scroll_height = this->height - 40;
+ this->FindWindowPlacementAndResize(&_about_desc);
+ }
+
+ virtual void OnPaint()
+ {
+ static const char *credits[] = {
+ /*************************************************************************
+ * maximum length of string which fits in window -^*/
+ "Original design by Chris Sawyer",
+ "Original graphics by Simon Foster",
+ "",
+ "The OpenTTD team (in alphabetical order):",
+ " Jean-Francois Claeys (Belugas) - GUI, newindustries and more",
+ " Bjarni Corfitzen (Bjarni) - MacOSX port, coder and vehicles",
+ " Matthijs Kooijman (blathijs) - Pathfinder-guru, pool rework",
+ " Loïc Guilloux (glx) - General coding",
+ " Christoph Elsenhans (frosch) - General coding",
+ " Jaroslav Mazanec (KUDr) - YAPG (Yet Another Pathfinder God) ;)",
+ " Jonathan Coome (Maedhros) - High priest of the newGRF Temple",
+ " Attila Bán (MiHaMiX) - WebTranslator, Nightlies, Wiki and bugtracker host",
+ " Owen Rudge (orudge) - Forum host, OS/2 port",
+ " Peter Nelson (peter1138) - Spiritual descendant from newGRF gods",
+ " Remko Bijker (Rubidium) - Lead coder and way more",
+ " Benedikt Brüggemeier (skidd13) - Bug fixer and code reworker",
+ " Zdenek Sojka (SmatZ) - Bug finder and fixer",
+ "",
+ "Inactive Developers:",
+ " Victor Fischer (Celestar) - Programming everywhere you need him to",
+ " Tamás Faragó (Darkvater) - Ex-Lead coder",
+ " Christoph Mallon (Tron) - Programmer, code correctness police",
+ "",
+ "Retired Developers:",
+ " Ludvig Strigeus (ludde) - OpenTTD author, main coder (0.1 - 0.3.3)",
+ " Serge Paquet (vurlix) - Assistant project manager, coder (0.1 - 0.3.3)",
+ " Dominik Scherer (dominik81) - Lead programmer, GUI expert (0.3.0 - 0.3.6)",
+ " Patric Stout (TrueLight) - Programmer, webhoster (0.3 - pre0.6)",
+ "",
+ "Special thanks go out to:",
+ " Josef Drexler - For his great work on TTDPatch",
+ " Marcin Grzegorczyk - For his documentation of TTD internals",
+ " Petr Baudis (pasky) - Many patches, newGRF support",
+ " Stefan Meißner (sign_de) - For his work on the console",
+ " Simon Sasburg (HackyKid) - Many bugfixes he has blessed us with",
+ " Cian Duffy (MYOB) - BeOS port / manual writing",
+ " Christian Rosentreter (tokai) - MorphOS / AmigaOS port",
+ " Richard Kempton (richK) - additional airports, initial TGP implementation",
+ "",
+ " Michael Blunck - Pre-Signals and Semaphores © 2003",
+ " George - Canal/Lock graphics © 2003-2004",
+ " David Dallaston - Tram tracks",
+ " Marcin Grzegorczyk - Foundations for Tracks on Slopes",
+ " All Translators - Who made OpenTTD a truly international game",
+ " Bug Reporters - Without whom OpenTTD would still be full of bugs!",
+ "",
+ "",
+ "And last but not least:",
+ " Chris Sawyer - For an amazing game!"
+ };
+
+ this->DrawWidgets();
+
+ /* Show original copyright and revision version */
+ DrawStringCentered(210, 17, STR_00B6_ORIGINAL_COPYRIGHT, TC_FROMSTRING);
+ DrawStringCentered(210, 17 + 10, STR_00B7_VERSION, TC_FROMSTRING);
+
+ int y = this->scroll_height;
+
+ /* Show all scrolling credits */
+ for (uint i = 0; i < lengthof(credits); i++) {
+ if (y >= 50 && y < (this->height - 40)) {
+ DoDrawString(credits[i], 10, y, TC_BLACK);
+ }
+ y += 10;
+ }
+
+ /* If the last text has scrolled start a new from the start */
+ if (y < 50) this->scroll_height = this->height - 40;
+
+ DoDrawStringCentered(210, this->height - 25, "Website: http://www.openttd.org", TC_BLACK);
+ DrawStringCentered(210, this->height - 15, STR_00BA_COPYRIGHT_OPENTTD, TC_FROMSTRING);
+ }
+
+ virtual void OnTick()
+ {
+ if (--this->counter == 0) {
+ this->counter = 5;
+ this->scroll_height--;
+ this->SetDirty();
+ }
+ }
+};
void ShowAboutWindow()
{
DeleteWindowById(WC_GAME_OPTIONS, 0);
- new Window(&_about_desc);
+ new AboutWindow();
}
-static uint64 _errmsg_decode_params[20];
-static StringID _errmsg_message_1, _errmsg_message_2;
-static uint _errmsg_duration;
-
-
static const Widget _errmsg_widgets[] = {
{ WWT_CLOSEBOX, RESIZE_NONE, 4, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW},
{ WWT_CAPTION, RESIZE_NONE, 4, 11, 239, 0, 13, STR_00B2_MESSAGE, STR_NULL},
@@ -349,96 +340,96 @@
{ WIDGETS_END},
};
-static void ErrmsgWndProc(Window *w, WindowEvent *e)
-{
- switch (e->event) {
- case WE_PAINT:
- CopyInDParam(0, _errmsg_decode_params, lengthof(_errmsg_decode_params));
- DrawWindowWidgets(w);
- CopyInDParam(0, _errmsg_decode_params, lengthof(_errmsg_decode_params));
-
- /* If the error message comes from a NewGRF, we must use the text ref. stack reserved for error messages.
- * If the message doesn't come from a NewGRF, it won't use the TTDP-style text ref. stack, so we won't hurt anything
- */
- SwitchToErrorRefStack();
- RewindTextRefStack();
-
- if (!IsWindowOfPrototype(w, _errmsg_face_widgets)) {
- DrawStringMultiCenter(
- 120,
- (_errmsg_message_1 == INVALID_STRING_ID ? 25 : 15),
- _errmsg_message_2,
- w->width - 2);
- if (_errmsg_message_1 != INVALID_STRING_ID) {
- DrawStringMultiCenter(
- 120,
- 30,
- _errmsg_message_1,
- w->width - 2);
- }
- } else {
- const Player *p = GetPlayer((PlayerID)GetDParamX(_errmsg_decode_params,2));
- DrawPlayerFace(p->face, p->player_color, 2, 16);
+struct ErrmsgWindow : public Window {
+private:
+ uint duration;
+ uint64 decode_params[20];
+ StringID message_1;
+ StringID message_2;
+ bool show_player_face;
- DrawStringMultiCenter(
- 214,
- (_errmsg_message_1 == INVALID_STRING_ID ? 65 : 45),
- _errmsg_message_2,
- w->width - 2);
- if (_errmsg_message_1 != INVALID_STRING_ID) {
- DrawStringMultiCenter(
- 214,
- 90,
- _errmsg_message_1,
- w->width - 2);
- }
- }
-
- /* Switch back to the normal text ref. stack for NewGRF texts */
- SwitchToNormalRefStack();
- break;
+public:
+ ErrmsgWindow(Point pt, int width, int height, StringID msg1, StringID msg2, const Widget *widget, bool show_player_face) :
+ Window(pt.x, pt.y, width, height, WC_ERRMSG, widget),
+ show_player_face(show_player_face)
+ {
+ this->duration = _patches.errmsg_duration;
+ CopyOutDParam(this->decode_params, 0, lengthof(this->decode_params));
+ this->message_1 = msg1;
+ this->message_2 = msg2;
+ this->desc_flags = WDF_STD_BTN | WDF_DEF_WIDGET;
+ this->FindWindowPlacementAndResize(width, height);
+ }
- case WE_MOUSELOOP:
- if (_right_button_down) delete w;
- break;
-
- case WE_100_TICKS:
- if (--_errmsg_duration == 0) delete w;
- break;
+ virtual void OnPaint()
+ {
+ static int y[][3] = {
+ {15, 25, 30}, // _errmsg_widgets
+ {45, 65, 90}, // _errmsg_face_widgets
+ };
- case WE_DESTROY:
- SetRedErrorSquare(0);
- extern StringID _switch_mode_errorstr;
- _switch_mode_errorstr = INVALID_STRING_ID;
- break;
+ CopyInDParam(0, this->decode_params, lengthof(this->decode_params));
+ this->DrawWidgets();
+ CopyInDParam(0, this->decode_params, lengthof(this->decode_params));
- case WE_KEYPRESS:
- if (e->we.keypress.keycode == WKC_SPACE) {
- /* Don't continue. */
- e->we.keypress.cont = false;
- delete w;
- }
- break;
+ /* If the error message comes from a NewGRF, we must use the text ref. stack reserved for error messages.
+ * If the message doesn't come from a NewGRF, it won't use the TTDP-style text ref. stack, so we won't hurt anything
+ */
+ SwitchToErrorRefStack();
+ RewindTextRefStack();
+
+ if (this->show_player_face) {
+ const Player *p = GetPlayer((PlayerID)GetDParamX(this->decode_params, 2));
+ DrawPlayerFace(p->face, p->player_color, 2, 16);
+ }
+
+ byte j = (this->message_1 == INVALID_STRING_ID) ? 1 : 0;
+ DrawStringMultiCenter(this->width - 120, y[this->show_player_face][j], this->message_2, this->width - 2);
+ if (j == 0) {
+ DrawStringMultiCenter(this->width - 120, y[this->show_player_face][2], this->message_1, this->width - 2);
+ }
+
+ /* Switch back to the normal text ref. stack for NewGRF texts */
+ SwitchToNormalRefStack();
}
-}
+
+ virtual void OnMouseLoop()
+ {
+ if (_right_button_down) delete this;
+ }
+
+ virtual void OnHundredthTick()
+ {
+ if (--this->duration == 0) delete this;
+ }
+
+ ~ErrmsgWindow()
+ {
+ SetRedErrorSquare(0);
+ extern StringID _switch_mode_errorstr;
+ _switch_mode_errorstr = INVALID_STRING_ID;
+ }
+
+ virtual EventState OnKeyPress(uint16 key, uint16 keycode)
+ {
+ if (keycode != WKC_SPACE) return ES_NOT_HANDLED;
+ delete this;
+ return ES_HANDLED;
+ }
+};
void ShowErrorMessage(StringID msg_1, StringID msg_2, int x, int y)
{
DeleteWindowById(WC_ERRMSG, 0);
- if (msg_2 == STR_NULL) msg_2 = STR_EMPTY;
+ if (!_patches.errmsg_duration) return;
- _errmsg_message_1 = msg_1;
- _errmsg_message_2 = msg_2;
- CopyOutDParam(_errmsg_decode_params, 0, lengthof(_errmsg_decode_params));
- _errmsg_duration = _patches.errmsg_duration;
- if (!_errmsg_duration) return;
+ if (msg_2 == STR_NULL) msg_2 = STR_EMPTY;
Point pt;
const ViewPort *vp;
- Window *w;
- if (_errmsg_message_1 != STR_013B_OWNED_BY || GetDParamX(_errmsg_decode_params,2) >= 8) {
+ if (msg_1 != STR_013B_OWNED_BY || GetDParam(2) >= 8) {
if ((x | y) != 0) {
pt = RemapCoords2(x, y);
vp = FindWindowById(WC_MAIN_WINDOW, 0)->viewport;
@@ -455,7 +446,7 @@
pt.x = (_screen.width - 240) >> 1;
pt.y = (_screen.height - 46) >> 1;
}
- w = new Window(pt.x, pt.y, 240, 46, ErrmsgWndProc, WC_ERRMSG, _errmsg_widgets);
+ new ErrmsgWindow(pt, 240, 46, msg_1, msg_2, _errmsg_widgets, false);
} else {
if ((x | y) != 0) {
pt = RemapCoords2(x, y);
@@ -466,13 +457,10 @@
pt.x = (_screen.width - 334) >> 1;
pt.y = (_screen.height - 137) >> 1;
}
- w = new Window(pt.x, pt.y, 334, 137, ErrmsgWndProc, WC_ERRMSG, _errmsg_face_widgets);
+ new ErrmsgWindow(pt, 334, 137, msg_1, msg_2, _errmsg_face_widgets, true);
}
-
- w->desc_flags = WDF_STD_BTN | WDF_DEF_WIDGET;
}
-
void ShowEstimatedCostOrIncome(Money cost, int x, int y)
{
StringID msg = STR_0805_ESTIMATED_COST;
@@ -542,7 +530,7 @@
TooltipsWindow(int x, int y, int width, int height, const Widget *widget,
StringID str, uint paramcount, const uint64 params[]) :
- Window(x, y, width, height, NULL, WC_TOOLTIPS, widget)
+ Window(x, y, width, height, WC_TOOLTIPS, widget)
{
this->string_id = str;
assert(sizeof(this->params[0]) == sizeof(params[0]));
@@ -893,9 +881,9 @@
return false;
}
-int QueryString::HandleEditBoxKey(Window *w, int wid, uint16 key, uint16 keycode, bool &cont)
+int QueryString::HandleEditBoxKey(Window *w, int wid, uint16 key, uint16 keycode, Window::EventState &state)
{
- cont = false;
+ state = Window::ES_HANDLED;
switch (keycode) {
case WKC_ESC: return 2;
@@ -923,7 +911,7 @@
if (IsValidChar(key, this->afilter)) {
if (InsertTextBufferChar(&this->text, key)) w->InvalidateWidget(wid);
} else { // key wasn't caught. Continue only if standard entry specified
- cont = (this->afilter == CS_ALPHANUMERAL);
+ state = (this->afilter == CS_ALPHANUMERAL) ? Window::ES_HANDLED : Window::ES_NOT_HANDLED;
}
}
@@ -973,9 +961,9 @@
_cur_dpi = old_dpi;
}
-int QueryStringBaseWindow::HandleEditBoxKey(int wid, uint16 key, uint16 keycode, bool &cont)
+int QueryStringBaseWindow::HandleEditBoxKey(int wid, uint16 key, uint16 keycode, EventState &state)
{
- return this->QueryString::HandleEditBoxKey(this, wid, key, keycode, cont);
+ return this->QueryString::HandleEditBoxKey(this, wid, key, keycode, state);
}
void QueryStringBaseWindow::HandleEditBox(int wid)
@@ -997,10 +985,9 @@
struct QueryStringWindow : public QueryStringBaseWindow
{
- Window *parent;
-
- QueryStringWindow(const WindowDesc *desc, Window *parent) : QueryStringBaseWindow(desc), parent(parent)
+ QueryStringWindow(const WindowDesc *desc, Window *parent) : QueryStringBaseWindow(desc)
{
+ this->parent = parent;
SetBit(_no_scroll, SCROLL_EDIT);
this->FindWindowPlacementAndResize(desc);
@@ -1009,7 +996,7 @@
virtual void OnPaint()
{
SetDParam(0, this->caption);
- DrawWindowWidgets(this);
+ this->DrawWidgets();
this->DrawEditBox(QUERY_STR_WIDGET_TEXT);
}
@@ -1024,6 +1011,7 @@
} else {
HandleOnEditText(this->text.buf);
}
+ this->handled = true;
}
}
@@ -1048,15 +1036,15 @@
this->HandleEditBox(QUERY_STR_WIDGET_TEXT);
}
- virtual bool OnKeyPress(uint16 key, uint16 keycode)
+ virtual EventState OnKeyPress(uint16 key, uint16 keycode)
{
- bool cont;
- switch (this->HandleEditBoxKey(QUERY_STR_WIDGET_TEXT, key, keycode, cont)) {
+ EventState state;
+ switch (this->HandleEditBoxKey(QUERY_STR_WIDGET_TEXT, key, keycode, state)) {
case 1: this->OnOk(); // Enter pressed, confirms change
/* FALL THROUGH */
case 2: delete this; break; // ESC pressed, closes window, abandons changes
}
- return cont;
+ return state;
}
~QueryStringWindow()
@@ -1084,17 +1072,16 @@
WC_QUERY_STRING, WC_NONE,
WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET,
_query_string_widgets,
- NULL
};
/** Show a query popup window with a textbox in it.
* @param str StringID for the text shown in the textbox
* @param caption StringID of text shown in caption of querywindow
* @param maxlen maximum length in characters allowed. If bit 12 is set we
- * will not check the resulting string against to original string to return success
+ * will not check the resulting string against to original string to return success
* @param maxwidth maximum width in pixels allowed
* @param parent pointer to a Window that will handle the events (ok/cancel) of this
- * window. If NULL, results are handled by global function HandleOnEditText
+ * window. If NULL, results are handled by global function HandleOnEditText
* @param afilter filters out unwanted character input */
void ShowQueryString(StringID str, StringID caption, uint maxlen, uint maxwidth, Window *parent, CharSetFilter afilter)
{
@@ -1163,7 +1150,7 @@
virtual void OnPaint()
{
CopyInDParam(0, this->params, lengthof(this->params));
- DrawWindowWidgets(this);
+ this->DrawWidgets();
CopyInDParam(0, this->params, lengthof(this->params));
DrawStringMultiCenter(this->width / 2, (this->height / 2) - 10, this->message, this->width - 2);
@@ -1184,7 +1171,7 @@
}
}
- virtual bool OnKeyPress(uint16 key, uint16 keycode)
+ virtual EventState OnKeyPress(uint16 key, uint16 keycode)
{
/* ESC closes the window, Enter confirms the action */
switch (keycode) {
@@ -1197,9 +1184,9 @@
/* Fallthrough */
case WKC_ESC:
delete this;
- return false;
+ return ES_HANDLED;
}
- return true;
+ return ES_NOT_HANDLED;
}
};
@@ -1218,7 +1205,6 @@
WC_CONFIRM_POPUP_QUERY, WC_NONE,
WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_UNCLICK_BUTTONS | WDF_DEF_WIDGET | WDF_MODAL,
_query_widgets,
- NULL
};
/** Show a modal confirmation window with standard 'yes' and 'no' buttons
@@ -1429,7 +1415,7 @@
int y;
SetVScrollCount(this, _fios_num);
- DrawWindowWidgets(this);
+ this->DrawWidgets();
DrawFiosTexts(this->width);
if (_savegame_sort_dirty) {
@@ -1438,7 +1424,7 @@
}
GfxFillRect(this->widget[7].left + 1, this->widget[7].top + 1, this->widget[7].right, this->widget[7].bottom, 0xD7);
- DrawSortButtonState(this, _savegame_sort_order & SORT_BY_NAME ? 2 : 3, _savegame_sort_order & SORT_DESCENDING ? SBS_DOWN : SBS_UP);
+ this->DrawSortButtonState(_savegame_sort_order & SORT_BY_NAME ? 2 : 3, _savegame_sort_order & SORT_DESCENDING ? SBS_DOWN : SBS_UP);
y = this->widget[7].top + 1;
for (pos = this->vscroll.pos; pos < _fios_num; pos++) {
@@ -1533,20 +1519,20 @@
}
}
- virtual bool OnKeyPress(uint16 key, uint16 keycode)
+ virtual EventState OnKeyPress(uint16 key, uint16 keycode)
{
if (keycode == WKC_ESC) {
delete this;
- return false;
+ return ES_HANDLED;
}
- bool cont = true;
+ EventState state = ES_NOT_HANDLED;
if ((_saveload_mode == SLD_SAVE_GAME || _saveload_mode == SLD_SAVE_SCENARIO) &&
- this->HandleEditBoxKey(10, key, keycode, cont) == 1) { // Press Enter
+ this->HandleEditBoxKey(10, key, keycode, state) == 1) { // Press Enter
this->HandleButtonClick(12);
}
- return cont;
+ return state;
}
virtual void OnTimeout()
@@ -1599,7 +1585,6 @@
WC_SAVELOAD, WC_NONE,
WDF_STD_TOOLTIPS | WDF_DEF_WIDGET | WDF_STD_BTN | WDF_UNCLICK_BUTTONS | WDF_RESIZABLE,
_load_dialog_widgets,
- NULL,
};
static const WindowDesc _save_dialog_desc = {
@@ -1607,7 +1592,6 @@
WC_SAVELOAD, WC_NONE,
WDF_STD_TOOLTIPS | WDF_DEF_WIDGET | WDF_STD_BTN | WDF_UNCLICK_BUTTONS | WDF_RESIZABLE,
_save_dialog_widgets,
- NULL,
};
/** These values are used to convert the file/operations mode into a corresponding file type.
--- a/src/music/dmusic.cpp Mon May 19 14:14:33 2008 +0000
+++ b/src/music/dmusic.cpp Mon May 19 15:13:58 2008 +0000
@@ -5,6 +5,9 @@
#ifdef WIN32_ENABLE_DIRECTMUSIC_SUPPORT
#include "../stdafx.h"
+#ifdef WIN32_LEAN_AND_MEAN
+ #undef WIN32_LEAN_AND_MEAN // Don't exclude rarely-used stuff from Windows headers
+#endif
#include "../debug.h"
#include "../win32.h"
#include "dmusic.h"
--- a/src/music_gui.cpp Mon May 19 14:14:33 2008 +0000
+++ b/src/music_gui.cpp Mon May 19 15:13:58 2008 +0000
@@ -193,18 +193,40 @@
}
}
-static void MusicTrackSelectionWndProc(Window *w, WindowEvent *e)
-{
- switch (e->event) {
- case WE_PAINT: {
+struct MusicTrackSelectionWindow : public Window {
+private:
+ enum MusicTrackSelectionWidgets {
+ MTSW_CLOSE,
+ MTSW_CAPTION,
+ MTSW_BACKGROUND,
+ MTSW_LIST_LEFT,
+ MTSW_LIST_RIGHT,
+ MTSW_ALL,
+ MTSW_OLD,
+ MTSW_NEW,
+ MTSW_EZY,
+ MTSW_CUSTOM1,
+ MTSW_CUSTOM2,
+ MTSW_CLEAR,
+ MTSW_SAVE,
+ };
+
+public:
+ MusicTrackSelectionWindow(const WindowDesc *desc, WindowNumber number) : Window(desc, number)
+ {
+ this->FindWindowPlacementAndResize(desc);
+ }
+
+ virtual void OnPaint()
+ {
const byte* p;
uint i;
int y;
- w->SetWidgetDisabledState(11, msf.playlist <= 3);
- w->LowerWidget(3);
- w->LowerWidget(4);
- DrawWindowWidgets(w);
+ this->SetWidgetDisabledState(MTSW_CLEAR, msf.playlist <= 3);
+ this->LowerWidget(MTSW_LIST_LEFT);
+ this->LowerWidget(MTSW_LIST_RIGHT);
+ this->DrawWidgets();
GfxFillRect(3, 23, 3 + 177, 23 + 191, 0);
GfxFillRect(251, 23, 251 + 177, 23 + 191, 0);
@@ -238,88 +260,88 @@
DrawString(252, y, (i < 10) ? STR_01EC_0 : STR_01ED, TC_FROMSTRING);
y += 6;
}
- break;
}
- case WE_CLICK:
- switch (e->we.click.widget) {
- case 3: { // add to playlist
- int y = (e->we.click.pt.y - 23) / 6;
- uint i;
- byte *p;
-
- if (msf.playlist < 4) return;
- if (!IsInsideMM(y, 0, NUM_SONGS_AVAILABLE)) return;
+ virtual void OnClick(Point pt, int widget)
+ {
+ switch (widget) {
+ case MTSW_LIST_LEFT: { // add to playlist
+ int y = (pt.y - 23) / 6;
+ uint i;
+ byte *p;
- p = _playlists[msf.playlist];
- for (i = 0; i != NUM_SONGS_PLAYLIST - 1; i++) {
- if (p[i] == 0) {
- p[i] = y + 1;
- p[i + 1] = 0;
- w->SetDirty();
- SelectSongToPlay();
- break;
+ if (msf.playlist < 4) return;
+ if (!IsInsideMM(y, 0, NUM_SONGS_AVAILABLE)) return;
+
+ p = _playlists[msf.playlist];
+ for (i = 0; i != NUM_SONGS_PLAYLIST - 1; i++) {
+ if (p[i] == 0) {
+ p[i] = y + 1;
+ p[i + 1] = 0;
+ this->SetDirty();
+ SelectSongToPlay();
+ break;
+ }
}
- }
- } break;
+ } break;
- case 4: { // remove from playlist
- int y = (e->we.click.pt.y - 23) / 6;
- uint i;
- byte *p;
+ case MTSW_LIST_RIGHT: { // remove from playlist
+ int y = (pt.y - 23) / 6;
+ uint i;
+ byte *p;
- if (msf.playlist < 4) return;
- if (!IsInsideMM(y, 0, NUM_SONGS_AVAILABLE)) return;
+ if (msf.playlist < 4) return;
+ if (!IsInsideMM(y, 0, NUM_SONGS_AVAILABLE)) return;
- p = _playlists[msf.playlist];
- for (i = y; i != NUM_SONGS_PLAYLIST - 1; i++) {
- p[i] = p[i + 1];
+ p = _playlists[msf.playlist];
+ for (i = y; i != NUM_SONGS_PLAYLIST - 1; i++) {
+ p[i] = p[i + 1];
}
- w->SetDirty();
- SelectSongToPlay();
- } break;
+ this->SetDirty();
+ SelectSongToPlay();
+ } break;
- case 11: // clear
- _playlists[msf.playlist][0] = 0;
- w->SetDirty();
- StopMusic();
- SelectSongToPlay();
- break;
+ case MTSW_CLEAR: // clear
+ _playlists[msf.playlist][0] = 0;
+ this->SetDirty();
+ StopMusic();
+ SelectSongToPlay();
+ break;
#if 0
- case 12: // save
- ShowInfo("MusicTrackSelectionWndProc:save not implemented");
- break;
+ case MTSW_SAVE: // save
+ ShowInfo("MusicTrackSelectionWndProc:save not implemented");
+ break;
#endif
- case 5: case 6: case 7: case 8: case 9: case 10: /* set playlist */
- msf.playlist = e->we.click.widget - 5;
- w->SetDirty();
- InvalidateWindow(WC_MUSIC_WINDOW, 0);
- StopMusic();
- SelectSongToPlay();
- break;
+ case MTSW_ALL: case MTSW_OLD: case MTSW_NEW:
+ case MTSW_EZY: case MTSW_CUSTOM1: case MTSW_CUSTOM2: // set playlist
+ msf.playlist = widget - MTSW_ALL;
+ this->SetDirty();
+ InvalidateWindow(WC_MUSIC_WINDOW, 0);
+ StopMusic();
+ SelectSongToPlay();
+ break;
}
- break;
}
-}
+};
static const Widget _music_track_selection_widgets[] = {
-{ WWT_CLOSEBOX, RESIZE_NONE, 14, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW},
-{ WWT_CAPTION, RESIZE_NONE, 14, 11, 431, 0, 13, STR_01EB_MUSIC_PROGRAM_SELECTION, STR_018C_WINDOW_TITLE_DRAG_THIS},
-{ WWT_PANEL, RESIZE_NONE, 14, 0, 431, 14, 217, 0x0, STR_NULL},
-{ WWT_PANEL, RESIZE_NONE, 14, 2, 181, 22, 215, 0x0, STR_01FA_CLICK_ON_MUSIC_TRACK_TO},
-{ WWT_PANEL, RESIZE_NONE, 14, 250, 429, 22, 215, 0x0, STR_CLICK_ON_TRACK_TO_REMOVE},
-{ WWT_PUSHBTN, RESIZE_NONE, 14, 186, 245, 44, 51, 0x0, STR_01F3_SELECT_ALL_TRACKS_PROGRAM},
-{ WWT_PUSHBTN, RESIZE_NONE, 14, 186, 245, 52, 59, 0x0, STR_01F4_SELECT_OLD_STYLE_MUSIC},
-{ WWT_PUSHBTN, RESIZE_NONE, 14, 186, 245, 60, 67, 0x0, STR_01F5_SELECT_NEW_STYLE_MUSIC},
-{ WWT_PUSHBTN, RESIZE_NONE, 14, 186, 245, 68, 75, 0x0, STR_0330_SELECT_EZY_STREET_STYLE},
-{ WWT_PUSHBTN, RESIZE_NONE, 14, 186, 245, 76, 83, 0x0, STR_01F6_SELECT_CUSTOM_1_USER_DEFINED},
-{ WWT_PUSHBTN, RESIZE_NONE, 14, 186, 245, 84, 91, 0x0, STR_01F7_SELECT_CUSTOM_2_USER_DEFINED},
-{ WWT_PUSHBTN, RESIZE_NONE, 14, 186, 245, 108, 115, 0x0, STR_01F8_CLEAR_CURRENT_PROGRAM_CUSTOM1},
+{ WWT_CLOSEBOX, RESIZE_NONE, 14, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW}, // MTSW_CLOSE
+{ WWT_CAPTION, RESIZE_NONE, 14, 11, 431, 0, 13, STR_01EB_MUSIC_PROGRAM_SELECTION, STR_018C_WINDOW_TITLE_DRAG_THIS}, // MTSW_CAPTION
+{ WWT_PANEL, RESIZE_NONE, 14, 0, 431, 14, 217, 0x0, STR_NULL}, // MTSW_BACKGROUND
+{ WWT_PANEL, RESIZE_NONE, 14, 2, 181, 22, 215, 0x0, STR_01FA_CLICK_ON_MUSIC_TRACK_TO}, // MTSW_LIST_LEFT
+{ WWT_PANEL, RESIZE_NONE, 14, 250, 429, 22, 215, 0x0, STR_CLICK_ON_TRACK_TO_REMOVE}, // MTSW_LIST_RIGHT
+{ WWT_PUSHBTN, RESIZE_NONE, 14, 186, 245, 44, 51, 0x0, STR_01F3_SELECT_ALL_TRACKS_PROGRAM}, // MTSW_ALL
+{ WWT_PUSHBTN, RESIZE_NONE, 14, 186, 245, 52, 59, 0x0, STR_01F4_SELECT_OLD_STYLE_MUSIC}, // MTSW_OLD
+{ WWT_PUSHBTN, RESIZE_NONE, 14, 186, 245, 60, 67, 0x0, STR_01F5_SELECT_NEW_STYLE_MUSIC}, // MTSW_NEW
+{ WWT_PUSHBTN, RESIZE_NONE, 14, 186, 245, 68, 75, 0x0, STR_0330_SELECT_EZY_STREET_STYLE}, // MTSW_EZY
+{ WWT_PUSHBTN, RESIZE_NONE, 14, 186, 245, 76, 83, 0x0, STR_01F6_SELECT_CUSTOM_1_USER_DEFINED}, // MTSW_CUSTOM1
+{ WWT_PUSHBTN, RESIZE_NONE, 14, 186, 245, 84, 91, 0x0, STR_01F7_SELECT_CUSTOM_2_USER_DEFINED}, // MTSW_CUSTOM2
+{ WWT_PUSHBTN, RESIZE_NONE, 14, 186, 245, 108, 115, 0x0, STR_01F8_CLEAR_CURRENT_PROGRAM_CUSTOM1}, // MTSW_CLEAR
#if 0
-{ WWT_PUSHBTN, RESIZE_NONE, 14, 186, 245, 124, 131, 0x0, STR_01F9_SAVE_MUSIC_SETTINGS},
+{ WWT_PUSHBTN, RESIZE_NONE, 14, 186, 245, 124, 131, 0x0, STR_01F9_SAVE_MUSIC_SETTINGS}, // MTSW_SAVE
#endif
{ WIDGETS_END},
};
@@ -329,24 +351,50 @@
WC_MUSIC_TRACK_SELECTION, WC_NONE,
WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS,
_music_track_selection_widgets,
- MusicTrackSelectionWndProc
};
static void ShowMusicTrackSelection()
{
- AllocateWindowDescFront<Window>(&_music_track_selection_desc, 0);
+ AllocateWindowDescFront<MusicTrackSelectionWindow>(&_music_track_selection_desc, 0);
}
-static void MusicWindowWndProc(Window *w, WindowEvent *e)
-{
- switch (e->event) {
- case WE_PAINT: {
+struct MusicWindow : public Window {
+private:
+ enum MusicWidgets {
+ MW_CLOSE,
+ MW_CAPTION,
+ MW_PREV,
+ MW_NEXT,
+ MW_STOP,
+ MW_PLAY,
+ MW_SLIDERS,
+ MW_GAUGE,
+ MW_BACKGROUND,
+ MW_INFO,
+ MW_SHUFFLE,
+ MW_PROGRAMME,
+ MW_ALL,
+ MW_OLD,
+ MW_NEW,
+ MW_EZY,
+ MW_CUSTOM1,
+ MW_CUSTOM2,
+ };
+
+public:
+ MusicWindow(const WindowDesc *desc, WindowNumber number) : Window(desc, number)
+ {
+ this->FindWindowPlacementAndResize(desc);
+ }
+
+ virtual void OnPaint()
+ {
uint i;
StringID str;
- w->RaiseWidget(7);
- w->RaiseWidget(9);
- DrawWindowWidgets(w);
+ this->RaiseWidget(MW_GAUGE);
+ this->RaiseWidget(MW_INFO);
+ this->DrawWidgets();
GfxFillRect(187, 16, 200, 33, 0);
@@ -403,92 +451,99 @@
DrawFrameRect(
214 + msf.effect_vol / 2, 22, 217 + msf.effect_vol / 2, 28, 14, FR_NONE
);
- } break;
-
- case WE_CLICK:
- switch (e->we.click.widget) {
- case 2: // skip to prev
- if (!_song_is_active)
- return;
- SkipToPrevSong();
- break;
- case 3: // skip to next
- if (!_song_is_active)
- return;
- SkipToNextSong();
- break;
- case 4: // stop playing
- msf.playing = false;
- break;
- case 5: // start playing
- msf.playing = true;
- break;
- case 6: { // volume sliders
- byte *vol, new_vol;
- int x = e->we.click.pt.x - 88;
-
- if (x < 0) return;
-
- vol = &msf.music_vol;
- if (x >= 106) {
- vol = &msf.effect_vol;
- x -= 106;
- }
-
- new_vol = min(max(x - 21, 0) * 2, 127);
- if (new_vol != *vol) {
- *vol = new_vol;
- if (vol == &msf.music_vol)
- MusicVolumeChanged(new_vol);
- w->SetDirty();
- }
-
- _left_button_clicked = false;
- } break;
- case 10: //toggle shuffle
- msf.shuffle ^= 1;
- StopMusic();
- SelectSongToPlay();
- break;
- case 11: //show track selection
- ShowMusicTrackSelection();
- break;
- case 12: case 13: case 14: case 15: case 16: case 17: // playlist
- msf.playlist = e->we.click.widget - 12;
- w->SetDirty();
- InvalidateWindow(WC_MUSIC_TRACK_SELECTION, 0);
- StopMusic();
- SelectSongToPlay();
- break;
- }
- break;
-
- case WE_TICK:
- InvalidateWindowWidget(WC_MUSIC_WINDOW, 0, 7);
- break;
}
-}
+ virtual void OnClick(Point pt, int widget)
+ {
+ switch (widget) {
+ case MW_PREV: // skip to prev
+ if (!_song_is_active) return;
+ SkipToPrevSong();
+ break;
+
+ case MW_NEXT: // skip to next
+ if (!_song_is_active) return;
+ SkipToNextSong();
+ break;
+
+ case MW_STOP: // stop playing
+ msf.playing = false;
+ break;
+
+ case MW_PLAY: // start playing
+ msf.playing = true;
+ break;
+
+ case MW_SLIDERS: { // volume sliders
+ byte *vol, new_vol;
+ int x = pt.x - 88;
+
+ if (x < 0) return;
+
+ vol = &msf.music_vol;
+ if (x >= 106) {
+ vol = &msf.effect_vol;
+ x -= 106;
+ }
+
+ new_vol = min(max(x - 21, 0) * 2, 127);
+ if (new_vol != *vol) {
+ *vol = new_vol;
+ if (vol == &msf.music_vol) MusicVolumeChanged(new_vol);
+ this->SetDirty();
+ }
+
+ _left_button_clicked = false;
+ } break;
+
+ case MW_SHUFFLE: //toggle shuffle
+ msf.shuffle ^= 1;
+ StopMusic();
+ SelectSongToPlay();
+ break;
+
+ case MW_PROGRAMME: //show track selection
+ ShowMusicTrackSelection();
+ break;
+
+ case MW_ALL: case MW_OLD: case MW_NEW:
+ case MW_EZY: case MW_CUSTOM1: case MW_CUSTOM2: // playlist
+ msf.playlist = widget - MW_ALL;
+ this->SetDirty();
+ InvalidateWindow(WC_MUSIC_TRACK_SELECTION, 0);
+ StopMusic();
+ SelectSongToPlay();
+ break;
+ }
+ }
+
+#if 0
+ virtual void OnTick()
+ {
+ this->InvalidateWidget(MW_GAUGE);
+ }
+#endif
+};
static const Widget _music_window_widgets[] = {
-{ WWT_CLOSEBOX, RESIZE_NONE, 14, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW},
-{ WWT_CAPTION, RESIZE_NONE, 14, 11, 299, 0, 13, STR_01D2_JAZZ_JUKEBOX, STR_018C_WINDOW_TITLE_DRAG_THIS},
-{ WWT_PUSHIMGBTN, RESIZE_NONE, 14, 0, 21, 14, 35, SPR_IMG_SKIP_TO_PREV, STR_01DE_SKIP_TO_PREVIOUS_TRACK},
-{ WWT_PUSHIMGBTN, RESIZE_NONE, 14, 22, 43, 14, 35, SPR_IMG_SKIP_TO_NEXT, STR_01DF_SKIP_TO_NEXT_TRACK_IN_SELECTION},
-{ WWT_PUSHIMGBTN, RESIZE_NONE, 14, 44, 65, 14, 35, SPR_IMG_STOP_MUSIC, STR_01E0_STOP_PLAYING_MUSIC},
-{ WWT_PUSHIMGBTN, RESIZE_NONE, 14, 66, 87, 14, 35, SPR_IMG_PLAY_MUSIC, STR_01E1_START_PLAYING_MUSIC},
-{ WWT_PANEL, RESIZE_NONE, 14, 88, 299, 14, 35, 0x0, STR_01E2_DRAG_SLIDERS_TO_SET_MUSIC},
-{ WWT_PANEL, RESIZE_NONE, 14, 186, 201, 15, 34, 0x0, STR_NULL},
-{ WWT_PANEL, RESIZE_NONE, 14, 0, 299, 36, 57, 0x0, STR_NULL},
-{ WWT_PANEL, RESIZE_NONE, 14, 59, 240, 45, 53, 0x0, STR_NULL},
-{ WWT_PUSHBTN, RESIZE_NONE, 14, 6, 55, 42, 49, 0x0, STR_01FB_TOGGLE_PROGRAM_SHUFFLE},
-{ WWT_PUSHBTN, RESIZE_NONE, 14, 244, 293, 42, 49, 0x0, STR_01FC_SHOW_MUSIC_TRACK_SELECTION},
-{ WWT_PUSHBTN, RESIZE_NONE, 14, 0, 49, 58, 65, 0x0, STR_01F3_SELECT_ALL_TRACKS_PROGRAM},
-{ WWT_PUSHBTN, RESIZE_NONE, 14, 50, 99, 58, 65, 0x0, STR_01F4_SELECT_OLD_STYLE_MUSIC},
-{ WWT_PUSHBTN, RESIZE_NONE, 14, 100, 149, 58, 65, 0x0, STR_01F5_SELECT_NEW_STYLE_MUSIC},
-{ WWT_PUSHBTN, RESIZE_NONE, 14, 150, 199, 58, 65, 0x0, STR_0330_SELECT_EZY_STREET_STYLE},
-{ WWT_PUSHBTN, RESIZE_NONE, 14, 200, 249, 58, 65, 0x0, STR_01F6_SELECT_CUSTOM_1_USER_DEFINED},
-{ WWT_PUSHBTN, RESIZE_NONE, 14, 250, 299, 58, 65, 0x0, STR_01F7_SELECT_CUSTOM_2_USER_DEFINED},
+{ WWT_CLOSEBOX, RESIZE_NONE, 14, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW}, // MW_CLOSE
+{ WWT_CAPTION, RESIZE_NONE, 14, 11, 299, 0, 13, STR_01D2_JAZZ_JUKEBOX, STR_018C_WINDOW_TITLE_DRAG_THIS}, // MW_CAPTION
+{ WWT_PUSHIMGBTN, RESIZE_NONE, 14, 0, 21, 14, 35, SPR_IMG_SKIP_TO_PREV, STR_01DE_SKIP_TO_PREVIOUS_TRACK}, // MW_PREV
+{ WWT_PUSHIMGBTN, RESIZE_NONE, 14, 22, 43, 14, 35, SPR_IMG_SKIP_TO_NEXT, STR_01DF_SKIP_TO_NEXT_TRACK_IN_SELECTION}, // MW_NEXT
+{ WWT_PUSHIMGBTN, RESIZE_NONE, 14, 44, 65, 14, 35, SPR_IMG_STOP_MUSIC, STR_01E0_STOP_PLAYING_MUSIC}, // MW_STOP
+{ WWT_PUSHIMGBTN, RESIZE_NONE, 14, 66, 87, 14, 35, SPR_IMG_PLAY_MUSIC, STR_01E1_START_PLAYING_MUSIC}, // MW_PLAY
+{ WWT_PANEL, RESIZE_NONE, 14, 88, 299, 14, 35, 0x0, STR_01E2_DRAG_SLIDERS_TO_SET_MUSIC}, // MW_SLIDERS
+{ WWT_PANEL, RESIZE_NONE, 14, 186, 201, 15, 34, 0x0, STR_NULL}, // MW_GAUGE
+{ WWT_PANEL, RESIZE_NONE, 14, 0, 299, 36, 57, 0x0, STR_NULL}, // MW_BACKGROUND
+{ WWT_PANEL, RESIZE_NONE, 14, 59, 240, 45, 53, 0x0, STR_NULL}, // MW_INFO
+{ WWT_PUSHBTN, RESIZE_NONE, 14, 6, 55, 42, 49, 0x0, STR_01FB_TOGGLE_PROGRAM_SHUFFLE}, // MW_SHUFFLE
+{ WWT_PUSHBTN, RESIZE_NONE, 14, 244, 293, 42, 49, 0x0, STR_01FC_SHOW_MUSIC_TRACK_SELECTION}, // MW_PROGRAMME
+{ WWT_PUSHBTN, RESIZE_NONE, 14, 0, 49, 58, 65, 0x0, STR_01F3_SELECT_ALL_TRACKS_PROGRAM}, // MW_ALL
+{ WWT_PUSHBTN, RESIZE_NONE, 14, 50, 99, 58, 65, 0x0, STR_01F4_SELECT_OLD_STYLE_MUSIC}, // MW_OLD
+{ WWT_PUSHBTN, RESIZE_NONE, 14, 100, 149, 58, 65, 0x0, STR_01F5_SELECT_NEW_STYLE_MUSIC}, // MW_NEW
+{ WWT_PUSHBTN, RESIZE_NONE, 14, 150, 199, 58, 65, 0x0, STR_0330_SELECT_EZY_STREET_STYLE}, // MW_EZY
+{ WWT_PUSHBTN, RESIZE_NONE, 14, 200, 249, 58, 65, 0x0, STR_01F6_SELECT_CUSTOM_1_USER_DEFINED}, // MW_CUSTOM1
+{ WWT_PUSHBTN, RESIZE_NONE, 14, 250, 299, 58, 65, 0x0, STR_01F7_SELECT_CUSTOM_2_USER_DEFINED}, // MW_CUSTOM2
{ WIDGETS_END},
};
@@ -497,10 +552,9 @@
WC_MUSIC_WINDOW, WC_NONE,
WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS,
_music_window_widgets,
- MusicWindowWndProc
};
void ShowMusicWindow()
{
- AllocateWindowDescFront<Window>(&_music_window_desc, 0);
+ AllocateWindowDescFront<MusicWindow>(&_music_window_desc, 0);
}
--- a/src/network/network_gui.cpp Mon May 19 14:14:33 2008 +0000
+++ b/src/network/network_gui.cpp Mon May 19 15:13:58 2008 +0000
@@ -30,6 +30,7 @@
#include "../settings_type.h"
#include "../widgets/dropdown_func.h"
#include "../querystring_gui.h"
+#include "../sortlist_type.h"
#include "table/strings.h"
#include "../table/sprites.h"
@@ -318,7 +319,7 @@
SetDParam(0, 0x00);
SetDParam(1, _lan_internet_types_dropdown[_network_lan_internet]);
- DrawWindowWidgets(this);
+ this->DrawWidgets();
/* Edit box to set player name */
this->DrawEditBox(NGWW_PLAYER);
@@ -327,9 +328,9 @@
/* Sort based on widgets: name, clients, compatibility */
switch (this->servers.sort_type) {
- case NGWW_NAME - NGWW_NAME: DrawSortButtonState(this, NGWW_NAME, arrow); break;
- case NGWW_CLIENTS - NGWW_NAME: DrawSortButtonState(this, NGWW_CLIENTS, arrow); break;
- case NGWW_INFO - NGWW_NAME: DrawSortButtonState(this, NGWW_INFO, arrow); break;
+ case NGWW_NAME - NGWW_NAME: this->DrawSortButtonState(NGWW_NAME, arrow); break;
+ case NGWW_CLIENTS - NGWW_NAME: this->DrawSortButtonState(NGWW_CLIENTS, arrow); break;
+ case NGWW_INFO - NGWW_NAME: this->DrawSortButtonState(NGWW_INFO, arrow); break;
}
uint16 y = NET_PRC__OFFSET_TOP_WIDGET + 3;
@@ -542,9 +543,9 @@
this->SetDirty();
}
- virtual bool OnKeyPress(uint16 key, uint16 keycode)
+ virtual EventState OnKeyPress(uint16 key, uint16 keycode)
{
- bool cont = true;
+ EventState state = ES_NOT_HANDLED;
if (this->field != NGWW_PLAYER) {
if (this->server != NULL) {
if (keycode == WKC_DELETE) { // Press 'delete' to remove servers
@@ -553,10 +554,10 @@
this->server = NULL;
}
}
- return cont;
+ return state;
}
- if (this->HandleEditBoxKey(NGWW_PLAYER, keycode, key, cont) == 1) return cont; // enter pressed
+ if (this->HandleEditBoxKey(NGWW_PLAYER, keycode, key, state) == 1) return state; // enter pressed
/* The name is only allowed when it starts with a letter! */
if (StrEmpty(this->edit_str_buf) && this->edit_str_buf[0] != ' ') {
@@ -564,7 +565,7 @@
} else {
ttd_strlcpy(_network_player_name, "Player", lengthof(_network_player_name));
}
- return cont;
+ return state;
}
virtual void OnQueryTextFinished(char *str)
@@ -641,7 +642,6 @@
WC_NETWORK_WINDOW, WC_NONE,
WDF_STD_TOOLTIPS | WDF_DEF_WIDGET | WDF_STD_BTN | WDF_UNCLICK_BUTTONS | WDF_RESIZABLE,
_network_game_window_widgets,
- NULL,
};
void ShowNetworkGameWindow()
@@ -727,7 +727,7 @@
SetDParam(3, _network_game_info.companies_max);
SetDParam(4, _network_game_info.spectators_max);
SetDParam(5, STR_NETWORK_LANG_ANY + _network_game_info.server_lang);
- DrawWindowWidgets(this);
+ this->DrawWidgets();
/* editbox to set game name */
this->DrawEditBox(NSSW_GAMENAME);
@@ -891,16 +891,16 @@
if (this->field == NSSW_GAMENAME) this->HandleEditBox(NSSW_GAMENAME);
}
- virtual bool OnKeyPress(uint16 key, uint16 keycode)
+ virtual EventState OnKeyPress(uint16 key, uint16 keycode)
{
- bool cont = true;
+ EventState state = ES_NOT_HANDLED;
if (this->field == NSSW_GAMENAME) {
- if (this->HandleEditBoxKey(NSSW_GAMENAME, key, keycode, cont) == 1) return cont; // enter pressed
+ if (this->HandleEditBoxKey(NSSW_GAMENAME, key, keycode, state) == 1) return state; // enter pressed
ttd_strlcpy(_network_server_name, this->text.buf, sizeof(_network_server_name));
}
- return cont;
+ return state;
}
virtual void OnQueryTextFinished(char *str)
@@ -976,7 +976,6 @@
WC_NETWORK_WINDOW, WC_NONE,
WDF_STD_TOOLTIPS | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS,
_network_start_server_window_widgets,
- NULL,
};
static void ShowNetworkStartServerWindow()
@@ -1036,7 +1035,7 @@
/* Draw window widgets */
SetDParamStr(0, gi->server_name);
- DrawWindowWidgets(this);
+ this->DrawWidgets();
/* Draw company list */
pos = this->vscroll.pos;
@@ -1190,7 +1189,6 @@
WC_NETWORK_WINDOW, WC_NONE,
WDF_STD_TOOLTIPS | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS,
_network_lobby_window_widgets,
- NULL,
};
/* Show the networklobbywindow with the selected server
@@ -1217,14 +1215,6 @@
// Max 10 actions per client
#define MAX_CLIENTLIST_ACTION 10
-// Some standard bullshit.. defines variables ;)
-static void ClientListWndProc(Window *w, WindowEvent *e);
-static void ClientListPopupWndProc(Window *w, WindowEvent *e);
-static byte _selected_clientlist_item = 255;
-static byte _selected_clientlist_y = 0;
-static char _clientlist_action[MAX_CLIENTLIST_ACTION][50];
-static ClientList_Action_Proc *_clientlist_proc[MAX_CLIENTLIST_ACTION];
-
enum {
CLNWND_OFFSET = 16,
CLNWND_ROWSIZE = 10
@@ -1244,12 +1234,11 @@
{ WIDGETS_END},
};
-static WindowDesc _client_list_desc = {
+static const WindowDesc _client_list_desc = {
WDP_AUTO, WDP_AUTO, 250, 1, 250, 1,
WC_CLIENT_LIST, WC_NONE,
WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_STICKY_BUTTON,
_client_list_widgets,
- ClientListWndProc
};
// Finds the Xth client-info that is active
@@ -1321,267 +1310,271 @@
-/**
- * An action is clicked! What do we do?
- */
-static void HandleClientListPopupClick(byte index, byte clientno)
-{
- /* A click on the Popup of the ClientList.. handle the command */
- if (index < MAX_CLIENTLIST_ACTION && _clientlist_proc[index] != NULL) {
- _clientlist_proc[index](clientno);
- }
-}
+struct NetworkClientListPopupWindow : Window {
+ int sel_index;
+ int client_no;
+ char action[MAX_CLIENTLIST_ACTION][50];
+ ClientList_Action_Proc *proc[MAX_CLIENTLIST_ACTION];
-/**
- * Finds the amount of clients and set the height correct
- */
-static bool CheckClientListHeight(Window *w)
-{
- int num = 0;
- const NetworkClientInfo *ci;
+ NetworkClientListPopupWindow(int x, int y, const Widget *widgets, int client_no) :
+ Window(x, y, 150, 100, WC_TOOLBAR_MENU, widgets),
+ sel_index(0), client_no(client_no)
+ {
+ /*
+ * Fill the actions this client has.
+ * Watch is, max 50 chars long!
+ */
- /* Should be replaced with a loop through all clients */
- FOR_ALL_ACTIVE_CLIENT_INFOS(ci) {
- num++;
+ const NetworkClientInfo *ci = NetworkFindClientInfo(client_no);
+
+ int i = 0;
+ if (_network_own_client_index != ci->client_index) {
+ GetString(this->action[i], STR_NETWORK_CLIENTLIST_SPEAK_TO_CLIENT, lastof(this->action[i]));
+ this->proc[i++] = &ClientList_SpeakToClient;
+ }
+
+ if (IsValidPlayer(ci->client_playas) || ci->client_playas == PLAYER_SPECTATOR) {
+ GetString(this->action[i], STR_NETWORK_CLIENTLIST_SPEAK_TO_COMPANY, lastof(this->action[i]));
+ this->proc[i++] = &ClientList_SpeakToCompany;
+ }
+ GetString(this->action[i], STR_NETWORK_CLIENTLIST_SPEAK_TO_ALL, lastof(this->action[i]));
+ this->proc[i++] = &ClientList_SpeakToAll;
+
+ if (_network_own_client_index != ci->client_index) {
+ /* We are no spectator and the player we want to give money to is no spectator and money gifts are allowed */
+ if (IsValidPlayer(_network_playas) && IsValidPlayer(ci->client_playas) && _patches.give_money) {
+ GetString(this->action[i], STR_NETWORK_CLIENTLIST_GIVE_MONEY, lastof(this->action[i]));
+ this->proc[i++] = &ClientList_GiveMoney;
+ }
+ }
+
+ /* A server can kick clients (but not himself) */
+ if (_network_server && _network_own_client_index != ci->client_index) {
+ GetString(this->action[i], STR_NETWORK_CLIENTLIST_KICK, lastof(this->action[i]));
+ this->proc[i++] = &ClientList_Kick;
+
+ sprintf(this->action[i],"Ban"); // XXX GetString?
+ this->proc[i++] = &ClientList_Ban;
+ }
+
+ if (i == 0) {
+ GetString(this->action[i], STR_NETWORK_CLIENTLIST_NONE, lastof(this->action[i]));
+ this->proc[i++] = &ClientList_None;
+ }
+
+ /* Calculate the height */
+ int h = ClientListPopupHeight();
+
+ /* Allocate the popup */
+ this->widget[0].bottom = this->widget[0].top + h;
+ this->widget[0].right = this->widget[0].left + 150;
+
+ this->flags4 &= ~WF_WHITE_BORDER_MASK;
+
+ this->FindWindowPlacementAndResize(150, h + 1);
}
- num *= CLNWND_ROWSIZE;
-
- /* If height is changed */
- if (w->height != CLNWND_OFFSET + num + 1) {
- // XXX - magic unfortunately; (num + 2) has to be one bigger than heigh (num + 1)
- w->SetDirty();
- w->widget[3].bottom = w->widget[3].top + num + 2;
- w->height = CLNWND_OFFSET + num + 1;
- w->SetDirty();
- return false;
- }
- return true;
-}
-
-/**
- * Finds the amount of actions in the popup and set the height correct
- */
-static uint ClientListPopupHeight()
-{
- int num = 0;
-
- // Find the amount of actions
- for (int i = 0; i < MAX_CLIENTLIST_ACTION; i++) {
- if (_clientlist_action[i][0] == '\0') continue;
- if (_clientlist_proc[i] == NULL) continue;
- num++;
+ /**
+ * An action is clicked! What do we do?
+ */
+ void HandleClientListPopupClick(byte index)
+ {
+ /* A click on the Popup of the ClientList.. handle the command */
+ if (index < MAX_CLIENTLIST_ACTION && this->proc[index] != NULL) {
+ this->proc[index](this->client_no);
+ }
}
- num *= CLNWND_ROWSIZE;
+ /**
+ * Finds the amount of actions in the popup and set the height correct
+ */
+ uint ClientListPopupHeight()
+ {
+ int num = 0;
- return num + 1;
-}
+ // Find the amount of actions
+ for (int i = 0; i < MAX_CLIENTLIST_ACTION; i++) {
+ if (this->action[i][0] == '\0') continue;
+ if (this->proc[i] == NULL) continue;
+ num++;
+ }
+
+ num *= CLNWND_ROWSIZE;
+
+ return num + 1;
+ }
+
+
+ virtual void OnPaint()
+ {
+ this->DrawWidgets();
+
+ /* Draw the actions */
+ int sel = this->sel_index;
+ int y = 1;
+ for (int i = 0; i < MAX_CLIENTLIST_ACTION; i++, y += CLNWND_ROWSIZE) {
+ if (this->action[i][0] == '\0') continue;
+ if (this->proc[i] == NULL) continue;
+
+ TextColour colour;
+ if (sel-- == 0) { // Selected item, highlight it
+ GfxFillRect(1, y, 150 - 2, y + CLNWND_ROWSIZE - 1, 0);
+ colour = TC_WHITE;
+ } else {
+ colour = TC_BLACK;
+ }
+
+ DoDrawString(this->action[i], 4, y, colour);
+ }
+ }
+
+ virtual void OnMouseLoop()
+ {
+ /* We selected an action */
+ int index = (_cursor.pos.y - this->top) / CLNWND_ROWSIZE;
+
+ if (_left_button_down) {
+ if (index == -1 || index == this->sel_index) return;
+
+ this->sel_index = index;
+ this->SetDirty();
+ } else {
+ if (index >= 0 && _cursor.pos.y >= this->top) {
+ HandleClientListPopupClick(index);
+ }
+
+ DeleteWindowById(WC_TOOLBAR_MENU, 0);
+ }
+ }
+};
/**
* Show the popup (action list)
*/
-static Window *PopupClientList(Window *w, int client_no, int x, int y)
+static void PopupClientList(int client_no, int x, int y)
{
- int i;
- const NetworkClientInfo *ci;
DeleteWindowById(WC_TOOLBAR_MENU, 0);
- /* Clean the current actions */
- for (i = 0; i < MAX_CLIENTLIST_ACTION; i++) {
- _clientlist_action[i][0] = '\0';
- _clientlist_proc[i] = NULL;
- }
-
- /*
- * Fill the actions this client has.
- * Watch is, max 50 chars long!
- */
-
- ci = NetworkFindClientInfo(client_no);
- if (ci == NULL) return NULL;
-
- i = 0;
- if (_network_own_client_index != ci->client_index) {
- GetString(_clientlist_action[i], STR_NETWORK_CLIENTLIST_SPEAK_TO_CLIENT, lastof(_clientlist_action[i]));
- _clientlist_proc[i++] = &ClientList_SpeakToClient;
- }
-
- if (IsValidPlayer(ci->client_playas) || ci->client_playas == PLAYER_SPECTATOR) {
- GetString(_clientlist_action[i], STR_NETWORK_CLIENTLIST_SPEAK_TO_COMPANY, lastof(_clientlist_action[i]));
- _clientlist_proc[i++] = &ClientList_SpeakToCompany;
- }
- GetString(_clientlist_action[i], STR_NETWORK_CLIENTLIST_SPEAK_TO_ALL, lastof(_clientlist_action[i]));
- _clientlist_proc[i++] = &ClientList_SpeakToAll;
-
- if (_network_own_client_index != ci->client_index) {
- /* We are no spectator and the player we want to give money to is no spectator and money gifts are allowed */
- if (IsValidPlayer(_network_playas) && IsValidPlayer(ci->client_playas) && _patches.give_money) {
- GetString(_clientlist_action[i], STR_NETWORK_CLIENTLIST_GIVE_MONEY, lastof(_clientlist_action[i]));
- _clientlist_proc[i++] = &ClientList_GiveMoney;
- }
- }
-
- /* A server can kick clients (but not himself) */
- if (_network_server && _network_own_client_index != ci->client_index) {
- GetString(_clientlist_action[i], STR_NETWORK_CLIENTLIST_KICK, lastof(_clientlist_action[i]));
- _clientlist_proc[i++] = &ClientList_Kick;
-
- sprintf(_clientlist_action[i],"Ban"); // XXX GetString?
- _clientlist_proc[i++] = &ClientList_Ban;
- }
-
- if (i == 0) {
- GetString(_clientlist_action[i], STR_NETWORK_CLIENTLIST_NONE, lastof(_clientlist_action[i]));
- _clientlist_proc[i++] = &ClientList_None;
- }
-
- /* Calculate the height */
- int h = ClientListPopupHeight();
+ if (NetworkFindClientInfo(client_no) == NULL) return;
- /* Allocate the popup */
- w = new Window(x, y, 150, h + 1, ClientListPopupWndProc, WC_TOOLBAR_MENU, _client_list_popup_widgets);
- w->widget[0].bottom = w->widget[0].top + h;
- w->widget[0].right = w->widget[0].left + 150;
-
- w->flags4 &= ~WF_WHITE_BORDER_MASK;
- WP(w, menu_d).item_count = 0;
- // Save our client
- WP(w, menu_d).main_button = client_no;
- WP(w, menu_d).sel_index = 0;
-
- return w;
-}
-
-/** Main handle for the client popup list
- * uses menu_d WP macro */
-static void ClientListPopupWndProc(Window *w, WindowEvent *e)
-{
- switch (e->event) {
- case WE_PAINT: {
- DrawWindowWidgets(w);
-
- /* Draw the actions */
- int sel = WP(w, menu_d).sel_index;
- int y = 1;
- for (int i = 0; i < MAX_CLIENTLIST_ACTION; i++, y += CLNWND_ROWSIZE) {
- if (_clientlist_action[i][0] == '\0') continue;
- if (_clientlist_proc[i] == NULL) continue;
-
- TextColour colour;
- if (sel-- == 0) { // Selected item, highlight it
- GfxFillRect(1, y, 150 - 2, y + CLNWND_ROWSIZE - 1, 0);
- colour = TC_WHITE;
- } else {
- colour = TC_BLACK;
- }
-
- DoDrawString(_clientlist_action[i], 4, y, colour);
- }
- } break;
-
- case WE_MOUSELOOP: {
- /* We selected an action */
- int index = (_cursor.pos.y - w->top) / CLNWND_ROWSIZE;
-
- if (_left_button_down) {
- if (index == -1 || index == WP(w, menu_d).sel_index) return;
-
- WP(w, menu_d).sel_index = index;
- w->SetDirty();
- } else {
- if (index >= 0 && _cursor.pos.y >= w->top) {
- HandleClientListPopupClick(index, WP(w, menu_d).main_button);
- }
-
- DeleteWindowById(WC_TOOLBAR_MENU, 0);
- }
- } break;
- }
+ new NetworkClientListPopupWindow(x, y, _client_list_popup_widgets, client_no);
}
/**
* Main handle for clientlist
*/
-static void ClientListWndProc(Window *w, WindowEvent *e)
+struct NetworkClientListWindow : Window
{
- switch (e->event) {
- case WE_PAINT: {
- NetworkClientInfo *ci;
- int i = 0;
-
- /* Check if we need to reset the height */
- if (!CheckClientListHeight(w)) break;
-
- DrawWindowWidgets(w);
-
- int y = CLNWND_OFFSET;
-
- FOR_ALL_ACTIVE_CLIENT_INFOS(ci) {
- TextColour colour;
- if (_selected_clientlist_item == i++) { // Selected item, highlight it
- GfxFillRect(1, y, 248, y + CLNWND_ROWSIZE - 1, 0);
- colour = TC_WHITE;
- } else {
- colour = TC_BLACK;
- }
-
- if (ci->client_index == NETWORK_SERVER_INDEX) {
- DrawString(4, y, STR_NETWORK_SERVER, colour);
- } else {
- DrawString(4, y, STR_NETWORK_CLIENT, colour);
- }
+ byte selected_item;
+ byte selected_y;
- /* Filter out spectators */
- if (IsValidPlayer(ci->client_playas)) DrawPlayerIcon(ci->client_playas, 64, y + 1);
-
- DoDrawString(ci->client_name, 81, y, colour);
-
- y += CLNWND_ROWSIZE;
- }
- } break;
-
- case WE_CLICK:
- /* Show the popup with option */
- if (_selected_clientlist_item != 255) {
- PopupClientList(w, _selected_clientlist_item, e->we.click.pt.x + w->left, e->we.click.pt.y + w->top);
- }
- break;
+ NetworkClientListWindow(const WindowDesc *desc, WindowNumber window_number) :
+ Window(desc, window_number),
+ selected_item(0),
+ selected_y(255)
+ {
+ this->FindWindowPlacementAndResize(desc);
+ }
- case WE_MOUSEOVER:
- /* -1 means we left the current window */
- if (e->we.mouseover.pt.y == -1) {
- _selected_clientlist_y = 0;
- _selected_clientlist_item = 255;
- w->SetDirty();
- break;
- }
- /* It did not change.. no update! */
- if (e->we.mouseover.pt.y == _selected_clientlist_y) break;
+ /**
+ * Finds the amount of clients and set the height correct
+ */
+ bool CheckClientListHeight()
+ {
+ int num = 0;
+ const NetworkClientInfo *ci;
- /* Find the new selected item (if any) */
- _selected_clientlist_y = e->we.mouseover.pt.y;
- if (e->we.mouseover.pt.y > CLNWND_OFFSET) {
- _selected_clientlist_item = (e->we.mouseover.pt.y - CLNWND_OFFSET) / CLNWND_ROWSIZE;
+ /* Should be replaced with a loop through all clients */
+ FOR_ALL_ACTIVE_CLIENT_INFOS(ci) {
+ num++;
+ }
+
+ num *= CLNWND_ROWSIZE;
+
+ /* If height is changed */
+ if (this->height != CLNWND_OFFSET + num + 1) {
+ // XXX - magic unfortunately; (num + 2) has to be one bigger than heigh (num + 1)
+ this->SetDirty();
+ this->widget[3].bottom = this->widget[3].top + num + 2;
+ this->height = CLNWND_OFFSET + num + 1;
+ this->SetDirty();
+ return false;
+ }
+ return true;
+ }
+
+ virtual void OnPaint()
+ {
+ NetworkClientInfo *ci;
+ int i = 0;
+
+ /* Check if we need to reset the height */
+ if (!this->CheckClientListHeight()) return;
+
+ this->DrawWidgets();
+
+ int y = CLNWND_OFFSET;
+
+ FOR_ALL_ACTIVE_CLIENT_INFOS(ci) {
+ TextColour colour;
+ if (this->selected_item == i++) { // Selected item, highlight it
+ GfxFillRect(1, y, 248, y + CLNWND_ROWSIZE - 1, 0);
+ colour = TC_WHITE;
} else {
- _selected_clientlist_item = 255;
+ colour = TC_BLACK;
}
- /* Repaint */
- w->SetDirty();
- break;
+ if (ci->client_index == NETWORK_SERVER_INDEX) {
+ DrawString(4, y, STR_NETWORK_SERVER, colour);
+ } else {
+ DrawString(4, y, STR_NETWORK_CLIENT, colour);
+ }
- case WE_DESTROY: case WE_CREATE:
- /* When created or destroyed, data is reset */
- _selected_clientlist_item = 255;
- _selected_clientlist_y = 0;
- break;
+ /* Filter out spectators */
+ if (IsValidPlayer(ci->client_playas)) DrawPlayerIcon(ci->client_playas, 64, y + 1);
+
+ DoDrawString(ci->client_name, 81, y, colour);
+
+ y += CLNWND_ROWSIZE;
+ }
}
-}
+
+ virtual void OnClick(Point pt, int widget)
+ {
+ /* Show the popup with option */
+ if (this->selected_item != 255) {
+ PopupClientList(this->selected_item, pt.x + this->left, pt.y + this->top);
+ }
+ }
+
+ virtual void OnMouseOver(Point pt, int widget)
+ {
+ /* -1 means we left the current window */
+ if (pt.y == -1) {
+ this->selected_y = 0;
+ this->selected_item = 255;
+ this->SetDirty();
+ return;
+ }
+ /* It did not change.. no update! */
+ if (pt.y == this->selected_y) return;
+
+ /* Find the new selected item (if any) */
+ this->selected_y = pt.y;
+ if (pt.y > CLNWND_OFFSET) {
+ this->selected_item = (pt.y - CLNWND_OFFSET) / CLNWND_ROWSIZE;
+ } else {
+ this->selected_item = 255;
+ }
+
+ /* Repaint */
+ this->SetDirty();
+ }
+};
void ShowClientList()
{
- AllocateWindowDescFront<Window>(&_client_list_desc, 0);
+ AllocateWindowDescFront<NetworkClientListWindow>(&_client_list_desc, 0);
}
@@ -1601,56 +1594,60 @@
ShowQueryString(STR_EMPTY, caption, 20, 180, FindWindowById(WC_NETWORK_STATUS_WINDOW, 0), CS_ALPHANUMERAL);
}
-
-static void NetworkJoinStatusWindowWndProc(Window *w, WindowEvent *e)
-{
- switch (e->event) {
- case WE_PAINT: {
- uint8 progress; // used for progress bar
- DrawWindowWidgets(w);
+struct NetworkJoinStatusWindow : Window {
+ NetworkJoinStatusWindow(const WindowDesc *desc) : Window(desc)
+ {
+ this->parent = FindWindowById(WC_NETWORK_WINDOW, 0);
+ }
- DrawStringCentered(125, 35, STR_NETWORK_CONNECTING_1 + _network_join_status, TC_GREY);
- switch (_network_join_status) {
- case NETWORK_JOIN_STATUS_CONNECTING: case NETWORK_JOIN_STATUS_AUTHORIZING:
- case NETWORK_JOIN_STATUS_GETTING_COMPANY_INFO:
- progress = 10; // first two stages 10%
- break;
- case NETWORK_JOIN_STATUS_WAITING:
- SetDParam(0, _network_join_waiting);
- DrawStringCentered(125, 46, STR_NETWORK_CONNECTING_WAITING, TC_GREY);
- progress = 15; // third stage is 15%
- break;
- case NETWORK_JOIN_STATUS_DOWNLOADING:
- SetDParam(0, _network_join_kbytes);
- SetDParam(1, _network_join_kbytes_total);
- DrawStringCentered(125, 46, STR_NETWORK_CONNECTING_DOWNLOADING, TC_GREY);
- /* Fallthrough */
- default: /* Waiting is 15%, so the resting receivement of map is maximum 70% */
- progress = 15 + _network_join_kbytes * (100 - 15) / _network_join_kbytes_total;
- }
+ virtual void OnPaint()
+ {
+ uint8 progress; // used for progress bar
+ this->DrawWidgets();
- /* Draw nice progress bar :) */
- DrawFrameRect(20, 18, (int)((w->width - 20) * progress / 100), 28, 10, FR_NONE);
- } break;
+ DrawStringCentered(125, 35, STR_NETWORK_CONNECTING_1 + _network_join_status, TC_GREY);
+ switch (_network_join_status) {
+ case NETWORK_JOIN_STATUS_CONNECTING: case NETWORK_JOIN_STATUS_AUTHORIZING:
+ case NETWORK_JOIN_STATUS_GETTING_COMPANY_INFO:
+ progress = 10; // first two stages 10%
+ break;
+ case NETWORK_JOIN_STATUS_WAITING:
+ SetDParam(0, _network_join_waiting);
+ DrawStringCentered(125, 46, STR_NETWORK_CONNECTING_WAITING, TC_GREY);
+ progress = 15; // third stage is 15%
+ break;
+ case NETWORK_JOIN_STATUS_DOWNLOADING:
+ SetDParam(0, _network_join_kbytes);
+ SetDParam(1, _network_join_kbytes_total);
+ DrawStringCentered(125, 46, STR_NETWORK_CONNECTING_DOWNLOADING, TC_GREY);
+ /* Fallthrough */
+ default: /* Waiting is 15%, so the resting receivement of map is maximum 70% */
+ progress = 15 + _network_join_kbytes * (100 - 15) / _network_join_kbytes_total;
+ }
- case WE_CLICK:
- if (e->we.click.widget == 2) { //Disconnect button
- NetworkDisconnect();
- SwitchMode(SM_MENU);
- ShowNetworkGameWindow();
- }
- break;
+ /* Draw nice progress bar :) */
+ DrawFrameRect(20, 18, (int)((this->width - 20) * progress / 100), 28, 10, FR_NONE);
+ }
- case WE_ON_EDIT_TEXT:
- if (StrEmpty(e->we.edittext.str)) {
- NetworkDisconnect();
- ShowNetworkGameWindow();
- } else {
- SEND_COMMAND(PACKET_CLIENT_PASSWORD)(pw_type, e->we.edittext.str);
- }
- break;
+ virtual void OnClick(Point pt, int widget)
+ {
+ if (widget == 2) { //Disconnect button
+ NetworkDisconnect();
+ SwitchMode(SM_MENU);
+ ShowNetworkGameWindow();
+ }
}
-}
+
+ virtual void OnQueryTextFinished(char *str)
+ {
+ if (StrEmpty(str)) {
+ NetworkDisconnect();
+ ShowNetworkGameWindow();
+ } else {
+ SEND_COMMAND(PACKET_CLIENT_PASSWORD)(pw_type, str);
+ }
+ }
+};
static const Widget _network_join_status_window_widget[] = {
{ WWT_CAPTION, RESIZE_NONE, 14, 0, 249, 0, 13, STR_NETWORK_CONNECTING, STR_018C_WINDOW_TITLE_DRAG_THIS},
@@ -1664,15 +1661,12 @@
WC_NETWORK_STATUS_WINDOW, WC_NONE,
WDF_STD_TOOLTIPS | WDF_DEF_WIDGET | WDF_MODAL,
_network_join_status_window_widget,
- NetworkJoinStatusWindowWndProc,
};
void ShowJoinStatusWindow()
{
DeleteWindowById(WC_NETWORK_STATUS_WINDOW, 0);
- Window *w = new Window(&_network_join_status_window_desc);
- /* Parent the status window to the lobby */
- if (w != NULL) w->parent = FindWindowById(WC_NETWORK_WINDOW, 0);
+ new NetworkJoinStatusWindow(&_network_join_status_window_desc);
}
static void SendChat(const char *buf, DestType type, int dest)
@@ -1853,7 +1847,7 @@
STR_NETWORK_CHAT_CLIENT_CAPTION
};
- DrawWindowWidgets(this);
+ this->DrawWidgets();
assert((uint)this->dtype < lengthof(chat_captions));
DrawStringRightAligned(this->widget[2].left - 2, this->widget[2].top + 1, chat_captions[this->dtype], TC_BLACK);
@@ -1879,21 +1873,21 @@
this->HandleEditBox(2);
}
- virtual bool OnKeyPress(uint16 key, uint16 keycode)
+ virtual EventState OnKeyPress(uint16 key, uint16 keycode)
{
- bool cont = true;
+ EventState state = ES_NOT_HANDLED;
if (keycode == WKC_TAB) {
ChatTabCompletion();
} else {
_chat_tab_completion_active = false;
- switch (this->HandleEditBoxKey(2, key, keycode, cont)) {
+ switch (this->HandleEditBoxKey(2, key, keycode, state)) {
case 1: /* Return */
SendChat(this->text.buf, this->dtype, this->dest);
/* FALLTHROUGH */
case 2: /* Escape */ delete this; break;
}
}
- return cont;
+ return state;
}
};
@@ -1910,7 +1904,6 @@
WC_SEND_NETWORK_MSG, WC_NONE,
WDF_STD_TOOLTIPS | WDF_DEF_WIDGET,
_chat_window_widgets,
- NULL
};
void ShowNetworkChatQueryWindow(DestType type, int dest)
@@ -1932,8 +1925,9 @@
};
struct NetworkCompanyPasswordWindow : public QueryStringBaseWindow {
- NetworkCompanyPasswordWindow(const WindowDesc *desc) : QueryStringBaseWindow(desc)
+ NetworkCompanyPasswordWindow(const WindowDesc *desc, Window *parent) : QueryStringBaseWindow(desc)
{
+ this->parent = parent;
this->afilter = CS_ALPHANUMERAL;
InitializeTextBuffer(&this->text, this->edit_str_buf, min(lengthof(_network_default_company_pass), lengthof(this->edit_str_buf)), 0);
@@ -1954,7 +1948,7 @@
virtual void OnPaint()
{
- DrawWindowWidgets(this);
+ this->DrawWidgets();
this->DrawEditBox(4);
}
@@ -1985,10 +1979,10 @@
this->HandleEditBox(4);
}
- virtual bool OnKeyPress(uint16 key, uint16 keycode)
+ virtual EventState OnKeyPress(uint16 key, uint16 keycode)
{
- bool cont;
- switch (this->HandleEditBoxKey(4, key, keycode, cont)) {
+ EventState state;
+ switch (this->HandleEditBoxKey(4, key, keycode, state)) {
case 1: // Return
this->OnOk();
/* FALL THROUGH */
@@ -1997,7 +1991,7 @@
delete this;
break;
}
- return cont;
+ return state;
}
};
@@ -2018,14 +2012,13 @@
WC_COMPANY_PASSWORD_WINDOW, WC_NONE,
WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS | WDF_STICKY_BUTTON,
_ncp_window_widgets,
- NULL
};
-void ShowNetworkCompanyPasswordWindow()
+void ShowNetworkCompanyPasswordWindow(Window *parent)
{
DeleteWindowById(WC_COMPANY_PASSWORD_WINDOW, 0);
- new NetworkCompanyPasswordWindow(&_ncp_window_desc);
+ new NetworkCompanyPasswordWindow(&_ncp_window_desc, parent);
}
#endif /* ENABLE_NETWORK */
--- a/src/network/network_gui.h Mon May 19 14:14:33 2008 +0000
+++ b/src/network/network_gui.h Mon May 19 15:13:58 2008 +0000
@@ -5,6 +5,8 @@
#ifndef NETWORK_GUI_H
#define NETWORK_GUI_H
+#include "../window_type.h"
+
#ifdef ENABLE_NETWORK
#include "network_data.h"
@@ -15,7 +17,7 @@
void ShowJoinStatusWindow();
void ShowNetworkGameWindow();
void ShowClientList();
-void ShowNetworkCompanyPasswordWindow();
+void ShowNetworkCompanyPasswordWindow(Window *parent);
#else /* ENABLE_NETWORK */
/* Network function stubs when networking is disabled */
@@ -23,7 +25,7 @@
static inline void ShowNetworkChatQueryWindow(byte desttype, int dest) {}
static inline void ShowClientList() {}
static inline void ShowNetworkGameWindow() {}
-static inline void ShowNetworkCompanyPasswordWindow() {}
+static inline void ShowNetworkCompanyPasswordWindow(Window *parent) {}
#endif /* ENABLE_NETWORK */
--- a/src/newgrf.cpp Mon May 19 14:14:33 2008 +0000
+++ b/src/newgrf.cpp Mon May 19 15:13:58 2008 +0000
@@ -466,22 +466,14 @@
rvi->max_speed = speed;
} break;
- case 0x0B: { // Power
- uint16 power = grf_load_word(&buf);
-
- if (rvi->railveh_type == RAILVEH_MULTIHEAD) power /= 2;
-
- rvi->power = power;
- dewagonize(power, e);
- } break;
-
- case 0x0D: { // Running cost factor
- uint8 runcostfact = grf_load_byte(&buf);
-
- if (rvi->railveh_type == RAILVEH_MULTIHEAD) runcostfact /= 2;
-
- rvi->running_cost = runcostfact;
- } break;
+ case 0x0B: // Power
+ rvi->power = grf_load_word(&buf);
+ dewagonize(rvi->power, e);
+ break;
+
+ case 0x0D: // Running cost factor
+ rvi->running_cost = grf_load_byte(&buf);
+ break;
case 0x0E: { // Running cost base
uint32 base = grf_load_dword(&buf);
@@ -513,18 +505,8 @@
uint8 dual = grf_load_byte(&buf);
if (dual != 0) {
- if (rvi->railveh_type != RAILVEH_MULTIHEAD) {
- // adjust power and running cost if needed
- rvi->power /= 2;
- rvi->running_cost /= 2;
- }
rvi->railveh_type = RAILVEH_MULTIHEAD;
} else {
- if (rvi->railveh_type == RAILVEH_MULTIHEAD) {
- // adjust power and running cost if needed
- rvi->power *= 2;
- rvi->running_cost *= 2;
- }
rvi->railveh_type = rvi->power == 0 ?
RAILVEH_WAGON : RAILVEH_SINGLEHEAD;
}
--- a/src/newgrf_gui.cpp Mon May 19 14:14:33 2008 +0000
+++ b/src/newgrf_gui.cpp Mon May 19 15:13:58 2008 +0000
@@ -109,121 +109,126 @@
}
-/* Dialogue for adding NewGRF files to the selection */
-struct newgrf_add_d {
+/**
+ * Window for adding NewGRF files
+ */
+struct NewGRFAddWindow : public Window {
+ /* Names of the add a newgrf window widgets */
+ enum AddNewGRFWindowWidgets {
+ ANGRFW_CLOSEBOX = 0,
+ ANGRFW_CAPTION,
+ ANGRFW_BACKGROUND,
+ ANGRFW_GRF_LIST,
+ ANGRFW_SCROLLBAR,
+ ANGRFW_GRF_INFO,
+ ANGRFW_ADD,
+ ANGRFW_RESCAN,
+ ANGRFW_RESIZE,
+ };
+
GRFConfig **list;
const GRFConfig *sel;
-};
-assert_compile(WINDOW_CUSTOM_SIZE >= sizeof(newgrf_add_d));
-
-/* Names of the add a newgrf window widgets */
-enum AddNewGRFWindowWidgets {
- ANGRFW_CLOSEBOX = 0,
- ANGRFW_CAPTION,
- ANGRFW_BACKGROUND,
- ANGRFW_GRF_LIST,
- ANGRFW_SCROLLBAR,
- ANGRFW_GRF_INFO,
- ANGRFW_ADD,
- ANGRFW_RESCAN,
- ANGRFW_RESIZE,
-};
-static void NewGRFAddDlgWndProc(Window *w, WindowEvent *e)
-{
- switch (e->event) {
- case WE_PAINT: {
- const GRFConfig *c;
- const Widget *wl = &w->widget[ANGRFW_GRF_LIST];
- int n = 0;
-
- /* Count the number of GRFs */
- for (c = _all_grfs; c != NULL; c = c->next) n++;
-
- w->vscroll.cap = (wl->bottom - wl->top) / 10;
- SetVScrollCount(w, n);
+ NewGRFAddWindow(const WindowDesc *desc, GRFConfig **list) : Window(desc, 0)
+ {
+ this->list = list;
+ this->resize.step_height = 10;
- w->SetWidgetDisabledState(ANGRFW_ADD, WP(w, newgrf_add_d).sel == NULL || WP(w, newgrf_add_d).sel->IsOpenTTDBaseGRF());
- DrawWindowWidgets(w);
-
- GfxFillRect(wl->left + 1, wl->top + 1, wl->right, wl->bottom, 0xD7);
+ this->FindWindowPlacementAndResize(desc);
+ }
- uint y = wl->top + 1;
- for (c = _all_grfs, n = 0; c != NULL && n < (w->vscroll.pos + w->vscroll.cap); c = c->next, n++) {
- if (n >= w->vscroll.pos) {
- bool h = c == WP(w, newgrf_add_d).sel;
- const char *text = (c->name != NULL && !StrEmpty(c->name)) ? c->name : c->filename;
+ virtual void OnPaint()
+ {
+ const GRFConfig *c;
+ const Widget *wl = &this->widget[ANGRFW_GRF_LIST];
+ int n = 0;
- /* Draw selection background */
- if (h) GfxFillRect(3, y, w->width - 15, y + 9, 156);
- DoDrawStringTruncated(text, 4, y, h ? TC_WHITE : TC_ORANGE, w->width - 18);
- y += 10;
- }
+ /* Count the number of GRFs */
+ for (c = _all_grfs; c != NULL; c = c->next) n++;
+
+ this->vscroll.cap = (wl->bottom - wl->top) / 10;
+ SetVScrollCount(this, n);
+
+ this->SetWidgetDisabledState(ANGRFW_ADD, this->sel == NULL || this->sel->IsOpenTTDBaseGRF());
+ this->DrawWidgets();
+
+ GfxFillRect(wl->left + 1, wl->top + 1, wl->right, wl->bottom, 0xD7);
+
+ uint y = wl->top + 1;
+ for (c = _all_grfs, n = 0; c != NULL && n < (this->vscroll.pos + this->vscroll.cap); c = c->next, n++) {
+ if (n >= this->vscroll.pos) {
+ bool h = c == this->sel;
+ const char *text = (c->name != NULL && !StrEmpty(c->name)) ? c->name : c->filename;
+
+ /* Draw selection background */
+ if (h) GfxFillRect(3, y, this->width - 15, y + 9, 156);
+ DoDrawStringTruncated(text, 4, y, h ? TC_WHITE : TC_ORANGE, this->width - 18);
+ y += 10;
+ }
+ }
+
+ if (this->sel != NULL) {
+ const Widget *wi = &this->widget[ANGRFW_GRF_INFO];
+ ShowNewGRFInfo(this->sel, wi->left + 2, wi->top + 2, wi->right - wi->left - 2, wi->bottom, false);
+ }
+ }
+
+ virtual void OnDoubleClick(Point pt, int widget)
+ {
+ if (widget == ANGRFW_GRF_LIST) this->OnClick(pt, ANGRFW_ADD);
+ }
+
+ virtual void OnClick(Point pt, int widget)
+ {
+ switch (widget) {
+ case ANGRFW_GRF_LIST: {
+ /* Get row... */
+ const GRFConfig *c;
+ uint i = (pt.y - this->widget[ANGRFW_GRF_LIST].top) / 10 + this->vscroll.pos;
+
+ for (c = _all_grfs; c != NULL && i > 0; c = c->next, i--) {}
+ this->sel = c;
+ this->SetDirty();
+ break;
}
- if (WP(w, newgrf_add_d).sel != NULL) {
- const Widget *wi = &w->widget[ANGRFW_GRF_INFO];
- ShowNewGRFInfo(WP(w, newgrf_add_d).sel, wi->left + 2, wi->top + 2, wi->right - wi->left - 2, wi->bottom, false);
- }
- break;
- }
-
- case WE_DOUBLE_CLICK:
- if (e->we.click.widget != ANGRFW_GRF_LIST) break;
- e->we.click.widget = ANGRFW_ADD;
- /* Fall through */
-
- case WE_CLICK:
- switch (e->we.click.widget) {
- case ANGRFW_GRF_LIST: {
- /* Get row... */
- const GRFConfig *c;
- uint i = (e->we.click.pt.y - w->widget[ANGRFW_GRF_LIST].top) / 10 + w->vscroll.pos;
-
- for (c = _all_grfs; c != NULL && i > 0; c = c->next, i--) {}
- WP(w, newgrf_add_d).sel = c;
- w->SetDirty();
- break;
- }
-
- case ANGRFW_ADD: // Add selection to list
- if (WP(w, newgrf_add_d).sel != NULL) {
- const GRFConfig *src = WP(w, newgrf_add_d).sel;
- GRFConfig **list;
+ case ANGRFW_ADD: // Add selection to list
+ if (this->sel != NULL) {
+ const GRFConfig *src = this->sel;
+ GRFConfig **list;
- /* Find last entry in the list, checking for duplicate grfid on the way */
- for (list = WP(w, newgrf_add_d).list; *list != NULL; list = &(*list)->next) {
- if ((*list)->grfid == src->grfid) {
- ShowErrorMessage(INVALID_STRING_ID, STR_NEWGRF_DUPLICATE_GRFID, 0, 0);
- return;
- }
+ /* Find last entry in the list, checking for duplicate grfid on the way */
+ for (list = this->list; *list != NULL; list = &(*list)->next) {
+ if ((*list)->grfid == src->grfid) {
+ ShowErrorMessage(INVALID_STRING_ID, STR_NEWGRF_DUPLICATE_GRFID, 0, 0);
+ return;
}
-
- /* Copy GRF details from scanned list */
- GRFConfig *c = CallocT<GRFConfig>(1);
- *c = *src;
- c->filename = strdup(src->filename);
- if (src->name != NULL) c->name = strdup(src->name);
- if (src->info != NULL) c->info = strdup(src->info);
- c->next = NULL;
+ }
- /* Append GRF config to configuration list */
- *list = c;
-
- DeleteWindowByClass(WC_SAVELOAD);
- InvalidateWindowData(WC_GAME_OPTIONS, 0);
- }
- break;
+ /* Copy GRF details from scanned list */
+ GRFConfig *c = CallocT<GRFConfig>(1);
+ *c = *src;
+ c->filename = strdup(src->filename);
+ if (src->name != NULL) c->name = strdup(src->name);
+ if (src->info != NULL) c->info = strdup(src->info);
+ c->next = NULL;
- case ANGRFW_RESCAN: // Rescan list
- WP(w, newgrf_add_d).sel = NULL;
- ScanNewGRFFiles();
- w->SetDirty();
- break;
- }
- break;
+ /* Append GRF config to configuration list */
+ *list = c;
+
+ DeleteWindowByClass(WC_SAVELOAD);
+ InvalidateWindowData(WC_GAME_OPTIONS, 0);
+ }
+ break;
+
+ case ANGRFW_RESCAN: // Rescan list
+ this->sel = NULL;
+ ScanNewGRFFiles();
+ this->SetDirty();
+ break;
+ }
}
-}
+};
/* Widget definition for the add a newgrf window */
static const Widget _newgrf_add_dlg_widgets[] = {
@@ -245,303 +250,282 @@
WC_SAVELOAD, WC_NONE,
WDF_STD_TOOLTIPS | WDF_DEF_WIDGET | WDF_STD_BTN | WDF_UNCLICK_BUTTONS | WDF_RESIZABLE,
_newgrf_add_dlg_widgets,
- NewGRFAddDlgWndProc,
};
-/* 'NewGRF Settings' dialogue */
-struct newgrf_d {
+static void NewGRFConfirmationCallback(Window *w, bool confirmed);
+
+/**
+ * Window for showing NewGRF files
+ */
+struct NewGRFWindow : public Window {
+ /* Names of the manage newgrfs window widgets */
+ enum ShowNewGRFStateWidgets {
+ SNGRFS_CLOSEBOX = 0,
+ SNGRFS_CAPTION,
+ SNGRFS_BACKGROUND,
+ SNGRFS_ADD,
+ SNGRFS_REMOVE,
+ SNGRFS_MOVE_UP,
+ SNGRFS_MOVE_DOWN,
+ SNGRFS_FILE_LIST,
+ SNGRFS_SCROLLBAR,
+ SNGRFS_NEWGRF_INFO,
+ SNGRFS_SET_PARAMETERS,
+ SNGRFS_APPLY_CHANGES,
+ SNGRFS_RESIZE,
+ };
+
GRFConfig **orig_list; ///< grf list the window is shown with
- GRFConfig **list; ///< temporary grf list to which changes are made
+ GRFConfig *list; ///< temporary grf list to which changes are made
GRFConfig *sel; ///< selected grf item
bool editable; ///< is the window editable
bool show_params; ///< are the grf-parameters shown in the info-panel
bool execute; ///< on pressing 'apply changes' are grf changes applied immediately, or only list is updated
-};
-assert_compile(WINDOW_CUSTOM_SIZE >= sizeof(newgrf_d));
-
-
-/* Names of the manage newgrfs window widgets */
-enum ShowNewGRFStateWidgets {
- SNGRFS_CLOSEBOX = 0,
- SNGRFS_CAPTION,
- SNGRFS_BACKGROUND,
- SNGRFS_ADD,
- SNGRFS_REMOVE,
- SNGRFS_MOVE_UP,
- SNGRFS_MOVE_DOWN,
- SNGRFS_FILE_LIST,
- SNGRFS_SCROLLBAR,
- SNGRFS_NEWGRF_INFO,
- SNGRFS_SET_PARAMETERS,
- SNGRFS_APPLY_CHANGES,
- SNGRFS_RESIZE,
-};
-
-static void SetupNewGRFState(Window *w)
-{
- bool disable_all = WP(w, newgrf_d).sel == NULL || !WP(w, newgrf_d).editable;
-
- w->SetWidgetDisabledState(SNGRFS_ADD, !WP(w, newgrf_d).editable);
- w->SetWidgetsDisabledState(disable_all,
- SNGRFS_REMOVE,
- SNGRFS_MOVE_UP,
- SNGRFS_MOVE_DOWN,
- WIDGET_LIST_END
- );
- w->SetWidgetDisabledState(SNGRFS_SET_PARAMETERS, !WP(w, newgrf_d).show_params || disable_all);
-
- if (!disable_all) {
- /* All widgets are now enabled, so disable widgets we can't use */
- if (WP(w, newgrf_d).sel == *WP(w, newgrf_d).list) w->DisableWidget(SNGRFS_MOVE_UP);
- if (WP(w, newgrf_d).sel->next == NULL) w->DisableWidget(SNGRFS_MOVE_DOWN);
- if (WP(w, newgrf_d).sel->IsOpenTTDBaseGRF()) w->DisableWidget(SNGRFS_REMOVE);
- }
-}
-
-
-static void SetupNewGRFWindow(Window *w)
-{
- const GRFConfig *c;
- int i;
-
- for (c = *WP(w, newgrf_d).list, i = 0; c != NULL; c = c->next, i++) {}
-
- w->vscroll.cap = (w->widget[SNGRFS_FILE_LIST].bottom - w->widget[SNGRFS_FILE_LIST].top) / 14 + 1;
- SetVScrollCount(w, i);
- w->SetWidgetDisabledState(SNGRFS_APPLY_CHANGES, !WP(w, newgrf_d).editable);
-}
-
-
-/** Callback function for the newgrf 'apply changes' confirmation window
- * @param w Window which is calling this callback
- * @param confirmed boolean value, true when yes was clicked, false otherwise
- */
-static void NewGRFConfirmationCallback(Window *w, bool confirmed)
-{
- if (confirmed) {
- newgrf_d *nd = &WP(w, newgrf_d);
- GRFConfig *c;
- int i = 0;
- CopyGRFConfigList(nd->orig_list, *nd->list, false);
- ReloadNewGRFData();
-
- /* Show new, updated list */
- for (c = *nd->list; c != NULL && c != nd->sel; c = c->next, i++) {}
- CopyGRFConfigList(nd->list, *nd->orig_list, false);
- for (c = *nd->list; c != NULL && i > 0; c = c->next, i--) {}
- nd->sel = c;
-
- w->SetDirty();
- }
-}
-
-
-static void NewGRFWndProc(Window *w, WindowEvent *e)
-{
- switch (e->event) {
- case WE_PAINT: {
- const GRFConfig *c;
- int i, y;
-
- SetupNewGRFState(w);
-
- DrawWindowWidgets(w);
-
- /* Draw NewGRF list */
- y = w->widget[SNGRFS_FILE_LIST].top;
- for (c = *WP(w, newgrf_d).list, i = 0; c != NULL; c = c->next, i++) {
- if (i >= w->vscroll.pos && i < w->vscroll.pos + w->vscroll.cap) {
- const char *text = (c->name != NULL && !StrEmpty(c->name)) ? c->name : c->filename;
- SpriteID pal;
- byte txtoffset;
+ NewGRFWindow(const WindowDesc *desc, bool editable, bool show_params, bool exec_changes, GRFConfig **config) : Window(desc, 0)
+ {
+ this->resize.step_height = 14;
+ this->sel = NULL;
+ this->list = NULL;
+ this->orig_list = config;
+ this->editable = editable;
+ this->execute = exec_changes;
+ this->show_params = show_params;
- /* Pick a colour */
- switch (c->status) {
- case GCS_NOT_FOUND:
- case GCS_DISABLED:
- pal = PALETTE_TO_RED;
- break;
- case GCS_ACTIVATED:
- pal = PALETTE_TO_GREEN;
- break;
- default:
- pal = PALETTE_TO_BLUE;
- break;
- }
+ CopyGRFConfigList(&this->list, *config, false);
- /* Do not show a "not-failure" colour when it actually failed to load */
- if (pal != PALETTE_TO_RED) {
- if (HasBit(c->flags, GCF_STATIC)) {
- pal = PALETTE_TO_GREY;
- } else if (HasBit(c->flags, GCF_COMPATIBLE)) {
- pal = PALETTE_TO_ORANGE;
- }
- }
+ this->FindWindowPlacementAndResize(desc);
+ this->SetupNewGRFWindow();
+ }
- DrawSprite(SPR_SQUARE, pal, 5, y + 2);
- if (c->error != NULL) DrawSprite(SPR_WARNING_SIGN, 0, 20, y + 2);
- txtoffset = c->error != NULL ? 35 : 25;
- DoDrawStringTruncated(text, txtoffset, y + 3, WP(w, newgrf_d).sel == c ? TC_WHITE : TC_BLACK, w->width - txtoffset - 10);
- y += 14;
- }
- }
-
- if (WP(w, newgrf_d).sel != NULL) {
- /* Draw NewGRF file info */
- const Widget *wi = &w->widget[SNGRFS_NEWGRF_INFO];
- ShowNewGRFInfo(WP(w, newgrf_d).sel, wi->left + 2, wi->top + 2, wi->right - wi->left - 2, wi->bottom, WP(w, newgrf_d).show_params);
- }
-
- break;
+ ~NewGRFWindow()
+ {
+ if (!this->execute) {
+ CopyGRFConfigList(this->orig_list, this->list, true);
+ ResetGRFConfig(false);
+ ReloadNewGRFData();
}
- case WE_INVALIDATE_DATA:
- SetupNewGRFWindow(w);
- break;
-
- case WE_CLICK:
- switch (e->we.click.widget) {
- case SNGRFS_ADD: { // Add GRF
- GRFConfig **list = WP(w, newgrf_d).list;
- Window *w;
-
- DeleteWindowByClass(WC_SAVELOAD);
- w = new Window(&_newgrf_add_dlg_desc);
- w->resize.step_height = 10;
-
- WP(w, newgrf_add_d).list = list;
- break;
- }
-
- case SNGRFS_REMOVE: { // Remove GRF
- GRFConfig **pc, *c, *newsel;
-
- /* Choose the next GRF file to be the selected file */
- newsel = WP(w, newgrf_d).sel->next;
+ /* Remove the temporary copy of grf-list used in window */
+ ClearGRFConfigList(&this->list);
+ }
- for (pc = WP(w, newgrf_d).list; (c = *pc) != NULL; pc = &c->next) {
- /* If the new selection is empty (i.e. we're deleting the last item
- * in the list, pick the file just before the selected file */
- if (newsel == NULL && c->next == WP(w, newgrf_d).sel) newsel = c;
-
- if (c == WP(w, newgrf_d).sel) {
- *pc = c->next;
- free(c);
- break;
- }
- }
+ void SetupNewGRFWindow()
+ {
+ const GRFConfig *c;
+ int i;
- WP(w, newgrf_d).sel = newsel;
- SetupNewGRFWindow(w);
- w->SetDirty();
- break;
- }
-
- case SNGRFS_MOVE_UP: { // Move GRF up
- GRFConfig **pc, *c;
- if (WP(w, newgrf_d).sel == NULL) break;
+ for (c = this->list, i = 0; c != NULL; c = c->next, i++) {}
- for (pc = WP(w, newgrf_d).list; (c = *pc) != NULL; pc = &c->next) {
- if (c->next == WP(w, newgrf_d).sel) {
- c->next = WP(w, newgrf_d).sel->next;
- WP(w, newgrf_d).sel->next = c;
- *pc = WP(w, newgrf_d).sel;
- break;
- }
- }
- w->SetDirty();
- break;
+ this->vscroll.cap = (this->widget[SNGRFS_FILE_LIST].bottom - this->widget[SNGRFS_FILE_LIST].top) / 14 + 1;
+ SetVScrollCount(this, i);
+
+ this->SetWidgetDisabledState(SNGRFS_ADD, !this->editable);
+ this->SetWidgetDisabledState(SNGRFS_APPLY_CHANGES, !this->editable);
+ }
+
+ virtual void OnPaint()
+ {
+ bool disable_all = this->sel == NULL || !this->editable;
+
+ this->SetWidgetsDisabledState(disable_all,
+ SNGRFS_REMOVE,
+ SNGRFS_MOVE_UP,
+ SNGRFS_MOVE_DOWN,
+ WIDGET_LIST_END
+ );
+ this->SetWidgetDisabledState(SNGRFS_SET_PARAMETERS, !this->show_params || disable_all);
+
+ if (!disable_all) {
+ /* All widgets are now enabled, so disable widgets we can't use */
+ if (this->sel == this->list) this->DisableWidget(SNGRFS_MOVE_UP);
+ if (this->sel->next == NULL) this->DisableWidget(SNGRFS_MOVE_DOWN);
+ if (this->sel->IsOpenTTDBaseGRF()) this->DisableWidget(SNGRFS_REMOVE);
+ }
+
+ this->DrawWidgets();
+
+ /* Draw NewGRF list */
+ int y = this->widget[SNGRFS_FILE_LIST].top;
+ int i = 0;
+ for (const GRFConfig *c = this->list; c != NULL; c = c->next, i++) {
+ if (i >= this->vscroll.pos && i < this->vscroll.pos + this->vscroll.cap) {
+ const char *text = (c->name != NULL && !StrEmpty(c->name)) ? c->name : c->filename;
+ SpriteID pal;
+ byte txtoffset;
+
+ /* Pick a colour */
+ switch (c->status) {
+ case GCS_NOT_FOUND:
+ case GCS_DISABLED:
+ pal = PALETTE_TO_RED;
+ break;
+ case GCS_ACTIVATED:
+ pal = PALETTE_TO_GREEN;
+ break;
+ default:
+ pal = PALETTE_TO_BLUE;
+ break;
}
- case SNGRFS_MOVE_DOWN: { // Move GRF down
- GRFConfig **pc, *c;
- if (WP(w, newgrf_d).sel == NULL) break;
-
- for (pc = WP(w, newgrf_d).list; (c = *pc) != NULL; pc = &c->next) {
- if (c == WP(w, newgrf_d).sel) {
- *pc = c->next;
- c->next = c->next->next;
- (*pc)->next = c;
- break;
- }
+ /* Do not show a "not-failure" colour when it actually failed to load */
+ if (pal != PALETTE_TO_RED) {
+ if (HasBit(c->flags, GCF_STATIC)) {
+ pal = PALETTE_TO_GREY;
+ } else if (HasBit(c->flags, GCF_COMPATIBLE)) {
+ pal = PALETTE_TO_ORANGE;
}
- w->SetDirty();
- break;
- }
-
- case SNGRFS_FILE_LIST: { // Select a GRF
- GRFConfig *c;
- uint i = (e->we.click.pt.y - w->widget[SNGRFS_FILE_LIST].top) / 14 + w->vscroll.pos;
-
- for (c = *WP(w, newgrf_d).list; c != NULL && i > 0; c = c->next, i--) {}
- WP(w, newgrf_d).sel = c;
-
- w->SetDirty();
- break;
}
- case SNGRFS_APPLY_CHANGES: // Apply changes made to GRF list
- if (WP(w, newgrf_d).execute) {
- ShowQuery(
- STR_POPUP_CAUTION_CAPTION,
- STR_NEWGRF_CONFIRMATION_TEXT,
- w,
- NewGRFConfirmationCallback
- );
- } else {
- CopyGRFConfigList(WP(w, newgrf_d).orig_list, *WP(w, newgrf_d).list, true);
- ResetGRFConfig(false);
- ReloadNewGRFData();
- }
- break;
-
- case SNGRFS_SET_PARAMETERS: { // Edit parameters
- char buff[512];
- if (WP(w, newgrf_d).sel == NULL) break;
-
- GRFBuildParamList(buff, WP(w, newgrf_d).sel, lastof(buff));
- ShowQueryString(BindCString(buff), STR_NEWGRF_PARAMETER_QUERY, 63, 250, w, CS_ALPHANUMERAL);
- break;
- }
+ DrawSprite(SPR_SQUARE, pal, 5, y + 2);
+ if (c->error != NULL) DrawSprite(SPR_WARNING_SIGN, 0, 20, y + 2);
+ txtoffset = c->error != NULL ? 35 : 25;
+ DoDrawStringTruncated(text, txtoffset, y + 3, this->sel == c ? TC_WHITE : TC_BLACK, this->width - txtoffset - 10);
+ y += 14;
}
- break;
+ }
- case WE_ON_EDIT_TEXT:
- if (e->we.edittext.str != NULL) {
- /* Parse our new "int list" */
- GRFConfig *c = WP(w, newgrf_d).sel;
- c->num_params = parse_intlist(e->we.edittext.str, (int*)c->param, lengthof(c->param));
-
- /* parse_intlist returns -1 on error */
- if (c->num_params == (byte)-1) c->num_params = 0;
-
- w->SetDirty();
- }
- break;
+ if (this->sel != NULL) {
+ /* Draw NewGRF file info */
+ const Widget *wi = &this->widget[SNGRFS_NEWGRF_INFO];
+ ShowNewGRFInfo(this->sel, wi->left + 2, wi->top + 2, wi->right - wi->left - 2, wi->bottom, this->show_params);
+ }
+ }
- case WE_DESTROY:
- if (!WP(w, newgrf_d).execute) {
- CopyGRFConfigList(WP(w, newgrf_d).orig_list, *WP(w, newgrf_d).list, true);
- ResetGRFConfig(false);
- ReloadNewGRFData();
- }
- /* Remove the temporary copy of grf-list used in window */
- ClearGRFConfigList(WP(w, newgrf_d).list);
- break;
+ virtual void OnClick(Point pt, int widget)
+ {
+ switch (widget) {
+ case SNGRFS_ADD: // Add GRF
+ DeleteWindowByClass(WC_SAVELOAD);
+ new NewGRFAddWindow(&_newgrf_add_dlg_desc, &this->list);
+ break;
- case WE_RESIZE:
- if (e->we.sizing.diff.x != 0) {
- ResizeButtons(w, SNGRFS_ADD, SNGRFS_MOVE_DOWN);
- ResizeButtons(w, SNGRFS_SET_PARAMETERS, SNGRFS_APPLY_CHANGES);
+ case SNGRFS_REMOVE: { // Remove GRF
+ GRFConfig **pc, *c, *newsel;
+
+ /* Choose the next GRF file to be the selected file */
+ newsel = this->sel->next;
+
+ for (pc = &this->list; (c = *pc) != NULL; pc = &c->next) {
+ /* If the new selection is empty (i.e. we're deleting the last item
+ * in the list, pick the file just before the selected file */
+ if (newsel == NULL && c->next == this->sel) newsel = c;
+
+ if (c == this->sel) {
+ *pc = c->next;
+ free(c);
+ break;
+ }
+ }
+
+ this->sel = newsel;
+ this->SetupNewGRFWindow();
+ this->SetDirty();
+ break;
}
- w->vscroll.cap += e->we.sizing.diff.y / 14;
- w->widget[SNGRFS_FILE_LIST].data = (w->vscroll.cap << 8) + 1;
- SetupNewGRFWindow(w);
- break;
+
+ case SNGRFS_MOVE_UP: { // Move GRF up
+ GRFConfig **pc, *c;
+ if (this->sel == NULL) break;
+
+ for (pc = &this->list; (c = *pc) != NULL; pc = &c->next) {
+ if (c->next == this->sel) {
+ c->next = this->sel->next;
+ this->sel->next = c;
+ *pc = this->sel;
+ break;
+ }
+ }
+ this->SetDirty();
+ break;
+ }
+
+ case SNGRFS_MOVE_DOWN: { // Move GRF down
+ GRFConfig **pc, *c;
+ if (this->sel == NULL) break;
+
+ for (pc = &this->list; (c = *pc) != NULL; pc = &c->next) {
+ if (c == this->sel) {
+ *pc = c->next;
+ c->next = c->next->next;
+ (*pc)->next = c;
+ break;
+ }
+ }
+ this->SetDirty();
+ break;
+ }
+
+ case SNGRFS_FILE_LIST: { // Select a GRF
+ GRFConfig *c;
+ uint i = (pt.y - this->widget[SNGRFS_FILE_LIST].top) / 14 + this->vscroll.pos;
+
+ for (c = this->list; c != NULL && i > 0; c = c->next, i--) {}
+ this->sel = c;
+
+ this->SetDirty();
+ break;
+ }
+
+ case SNGRFS_APPLY_CHANGES: // Apply changes made to GRF list
+ if (this->execute) {
+ ShowQuery(
+ STR_POPUP_CAUTION_CAPTION,
+ STR_NEWGRF_CONFIRMATION_TEXT,
+ this,
+ NewGRFConfirmationCallback
+ );
+ } else {
+ CopyGRFConfigList(this->orig_list, this->list, true);
+ ResetGRFConfig(false);
+ ReloadNewGRFData();
+ }
+ break;
+
+ case SNGRFS_SET_PARAMETERS: { // Edit parameters
+ if (this->sel == NULL) break;
+
+ char buff[512];
+ GRFBuildParamList(buff, this->sel, lastof(buff));
+ ShowQueryString(BindCString(buff), STR_NEWGRF_PARAMETER_QUERY, 63, 250, this, CS_ALPHANUMERAL);
+ break;
+ }
+ }
}
-}
+
+ virtual void OnQueryTextFinished(char *str)
+ {
+ if (str == NULL) return;
+
+ /* Parse our new "int list" */
+ GRFConfig *c = this->sel;
+ c->num_params = parse_intlist(str, (int*)c->param, lengthof(c->param));
+
+ /* parse_intlist returns -1 on error */
+ if (c->num_params == (byte)-1) c->num_params = 0;
+
+ this->SetDirty();
+ }
+
+ virtual void OnResize(Point new_size, Point delta)
+ {
+ if (delta.x != 0) {
+ ResizeButtons(this, SNGRFS_ADD, SNGRFS_MOVE_DOWN);
+ ResizeButtons(this, SNGRFS_SET_PARAMETERS, SNGRFS_APPLY_CHANGES);
+ }
+
+ this->vscroll.cap += delta.y / 14;
+ this->widget[SNGRFS_FILE_LIST].data = (this->vscroll.cap << 8) + 1;
+
+ this->SetupNewGRFWindow();
+ }
+
+ virtual void OnInvalidateData(int data = 0)
+ {
+ this->SetupNewGRFWindow();
+ }
+};
/* Widget definition of the manage newgrfs window */
static const Widget _newgrf_widgets[] = {
@@ -567,9 +551,33 @@
WC_GAME_OPTIONS, WC_NONE,
WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS | WDF_RESIZABLE,
_newgrf_widgets,
- NewGRFWndProc,
};
+/** Callback function for the newgrf 'apply changes' confirmation window
+ * @param w Window which is calling this callback
+ * @param confirmed boolean value, true when yes was clicked, false otherwise
+ */
+static void NewGRFConfirmationCallback(Window *w, bool confirmed)
+{
+ if (confirmed) {
+ NewGRFWindow *nw = dynamic_cast<NewGRFWindow*>(w);
+ GRFConfig *c;
+ int i = 0;
+
+ CopyGRFConfigList(nw->orig_list, nw->list, false);
+ ReloadNewGRFData();
+
+ /* Show new, updated list */
+ for (c = nw->list; c != NULL && c != nw->sel; c = c->next, i++) {}
+ CopyGRFConfigList(&nw->list, *nw->orig_list, false);
+ for (c = nw->list; c != NULL && i > 0; c = c->next, i--) {}
+ nw->sel = c;
+
+ w->SetDirty();
+ }
+}
+
+
/** Setup the NewGRF gui
* @param editable allow the user to make changes to the grfconfig in the window
@@ -579,23 +587,6 @@
* @param config pointer to a linked-list of grfconfig's that will be shown */
void ShowNewGRFSettings(bool editable, bool show_params, bool exec_changes, GRFConfig **config)
{
- static GRFConfig *local = NULL;
- Window *w;
-
DeleteWindowByClass(WC_GAME_OPTIONS);
- w = new Window(&_newgrf_desc);
- if (w == NULL) return;
-
- w->resize.step_height = 14;
- CopyGRFConfigList(&local, *config, false);
-
- /* Clear selections */
- WP(w, newgrf_d).sel = NULL;
- WP(w, newgrf_d).list = &local;
- WP(w, newgrf_d).orig_list = config;
- WP(w, newgrf_d).editable = editable;
- WP(w, newgrf_d).execute = exec_changes;
- WP(w, newgrf_d).show_params = show_params;
-
- SetupNewGRFWindow(w);
+ new NewGRFWindow(&_newgrf_desc, editable, show_params, exec_changes, config);
}
--- a/src/news_func.h Mon May 19 14:14:33 2008 +0000
+++ b/src/news_func.h Mon May 19 15:13:58 2008 +0000
@@ -8,9 +8,8 @@
#include "news_type.h"
#include "vehicle_type.h"
-void AddNewsItem(StringID string, NewsMode mode, NewsFlag flag, NewsType type, NewsCallback callback, uint data_a, uint data_b);
+void AddNewsItem(StringID string, NewsSubtype subtype, uint data_a, uint data_b);
void NewsLoop();
-void DrawNewsBorder(const Window *w);
void InitNewsItemStructs();
extern NewsItem _statusbar_news_item;
--- a/src/news_gui.cpp Mon May 19 14:14:33 2008 +0000
+++ b/src/news_gui.cpp Mon May 19 15:13:58 2008 +0000
@@ -18,6 +18,8 @@
#include "string_func.h"
#include "widgets/dropdown_func.h"
#include "map_func.h"
+#include "statusbar_gui.h"
+#include "player_face.h"
#include "table/sprites.h"
#include "table/strings.h"
@@ -60,12 +62,6 @@
static NewsID _oldest_news = 0; ///< points to first item in fifo queue
static NewsID _latest_news = INVALID_NEWS; ///< points to last item in fifo queue
-struct news_d {
- uint16 chat_height;
- NewsItem *ni;
-};
-assert_compile(WINDOW_CUSTOM_SIZE >= sizeof(news_d));
-
/** Forced news item.
* Users can force an item by accessing the history or "last message".
* If the message being shown was forced by the user, its index is stored in
@@ -73,23 +69,107 @@
static NewsID _forced_news = INVALID_NEWS;
static uint _total_news = 0; ///< Number of news items in FIFO queue @see _news_items
-
-void DrawNewsNewVehicleAvail(Window *w, const NewsItem *ni);
-void DrawNewsBankrupcy(Window *w, const NewsItem *ni);
static void MoveToNextItem();
-StringID GetNewsStringNewVehicleAvail(const NewsItem *ni);
-StringID GetNewsStringBankrupcy(const NewsItem *ni);
-static DrawNewsCallbackProc * const _draw_news_callback[] = {
- DrawNewsNewVehicleAvail, ///< DNC_VEHICLEAVAIL
- DrawNewsBankrupcy, ///< DNC_BANKRUPCY
+typedef void DrawNewsCallbackProc(struct Window *w, const NewsItem *ni);
+void DrawNewsNewVehicleAvail(Window *w, const NewsItem *ni);
+
+static void DrawNewsBankrupcy(Window *w, const NewsItem *ni)
+{
+ Player *p = GetPlayer((PlayerID)(ni->data_b));
+ DrawPlayerFace(p->face, p->player_color, 2, 23);
+ GfxFillRect(3, 23, 3 + 91, 23 + 118, PALETTE_TO_STRUCT_GREY | (1 << USE_COLORTABLE));
+
+ SetDParam(0, p->index);
+
+ DrawStringMultiCenter(49, 148, STR_7058_PRESIDENT, 94);
+
+ switch (ni->subtype) {
+ case NS_COMPANY_TROUBLE:
+ DrawStringCentered(w->width >> 1, 1, STR_7056_TRANSPORT_COMPANY_IN_TROUBLE, TC_FROMSTRING);
+
+ SetDParam(0, p->index);
+
+ DrawStringMultiCenter(
+ ((w->width - 101) >> 1) + 98,
+ 90,
+ STR_7057_WILL_BE_SOLD_OFF_OR_DECLARED,
+ w->width - 101);
+ break;
+
+ case NS_COMPANY_MERGER:
+ DrawStringCentered(w->width >> 1, 1, STR_7059_TRANSPORT_COMPANY_MERGER, TC_FROMSTRING);
+ SetDParam(0, ni->params[2]);
+ SetDParam(1, p->index);
+ SetDParam(2, ni->params[4]);
+ DrawStringMultiCenter(
+ ((w->width - 101) >> 1) + 98,
+ 90,
+ ni->params[4] == 0 ? STR_707F_HAS_BEEN_TAKEN_OVER_BY : STR_705A_HAS_BEEN_SOLD_TO_FOR,
+ w->width - 101);
+ break;
+
+ case NS_COMPANY_BANKRUPT:
+ DrawStringCentered(w->width >> 1, 1, STR_705C_BANKRUPT, TC_FROMSTRING);
+ SetDParam(0, p->index);
+ DrawStringMultiCenter(
+ ((w->width - 101) >> 1) + 98,
+ 90,
+ STR_705D_HAS_BEEN_CLOSED_DOWN_BY,
+ w->width - 101);
+ break;
+
+ case NS_COMPANY_NEW:
+ DrawStringCentered(w->width >> 1, 1, STR_705E_NEW_TRANSPORT_COMPANY_LAUNCHED, TC_FROMSTRING);
+ SetDParam(0, p->index);
+ SetDParam(1, ni->params[3]);
+ DrawStringMultiCenter(
+ ((w->width - 101) >> 1) + 98,
+ 90,
+ STR_705F_STARTS_CONSTRUCTION_NEAR,
+ w->width - 101);
+ break;
+
+ default:
+ NOT_REACHED();
+ }
+}
+
+
+/**
+ * Data common to all news items of a given subtype (structure)
+ */
+struct NewsSubtypeData {
+ NewsType type; ///< News category @see NewsType
+ NewsMode display_mode; ///< Display mode value @see NewsMode
+ NewsFlag flags; ///< Initial NewsFlags bits @see NewsFlag
+ DrawNewsCallbackProc *callback; ///< Call-back function
};
-extern GetNewsStringCallbackProc * const _get_news_string_callback[];
-GetNewsStringCallbackProc * const _get_news_string_callback[] = {
- GetNewsStringNewVehicleAvail, ///< DNC_VEHICLEAVAIL
- GetNewsStringBankrupcy, ///< DNC_BANKRUPCY
+/**
+ * Data common to all news items of a given subtype (actual data)
+ */
+static const struct NewsSubtypeData _news_subtype_data[NS_END] = {
+ /* type, display_mode, flags, callback */
+ { NT_ARRIVAL_PLAYER, NM_THIN, NF_VIEWPORT|NF_VEHICLE, NULL }, ///< NS_ARRIVAL_PLAYER
+ { NT_ARRIVAL_OTHER, NM_THIN, NF_VIEWPORT|NF_VEHICLE, NULL }, ///< NS_ARRIVAL_OTHER
+ { NT_ACCIDENT, NM_THIN, NF_VIEWPORT|NF_TILE, NULL }, ///< NS_ACCIDENT_TILE
+ { NT_ACCIDENT, NM_THIN, NF_VIEWPORT|NF_VEHICLE, NULL }, ///< NS_ACCIDENT_VEHICLE
+ { NT_COMPANY_INFO, NM_CALLBACK, NF_NONE, DrawNewsBankrupcy }, ///< NS_COMPANY_TROUBLE
+ { NT_COMPANY_INFO, NM_CALLBACK, NF_NONE, DrawNewsBankrupcy }, ///< NS_COMPANY_MERGER
+ { NT_COMPANY_INFO, NM_CALLBACK, NF_NONE, DrawNewsBankrupcy }, ///< NS_COMPANY_BANKRUPT
+ { NT_COMPANY_INFO, NM_CALLBACK, NF_TILE, DrawNewsBankrupcy }, ///< NS_COMPANY_NEW
+ { NT_OPENCLOSE, NM_THIN, NF_VIEWPORT|NF_TILE, NULL }, ///< NS_OPENCLOSE
+ { NT_ECONOMY, NM_NORMAL, NF_NONE, NULL }, ///< NS_ECONOMY
+ { NT_INDUSTRY_PLAYER, NM_THIN, NF_VIEWPORT|NF_TILE, NULL }, ///< NS_INDUSTRY_PLAYER
+ { NT_INDUSTRY_OTHER, NM_THIN, NF_VIEWPORT|NF_TILE, NULL }, ///< NS_INDUSTRY_OTHER
+ { NT_INDUSTRY_NOBODY, NM_THIN, NF_VIEWPORT|NF_TILE, NULL }, ///< NS_INDUSTRY_NOBODY
+ { NT_ADVICE, NM_SMALL, NF_VIEWPORT|NF_VEHICLE, NULL }, ///< NS_ADVICE
+ { NT_NEW_VEHICLES, NM_CALLBACK, NF_NONE, DrawNewsNewVehicleAvail }, ///< NS_NEW_VEHICLES
+ { NT_ACCEPTANCE, NM_SMALL, NF_VIEWPORT|NF_TILE, NULL }, ///< NS_ACCEPTANCE
+ { NT_SUBSIDIES, NM_NORMAL, NF_TILE|NF_TILE2, NULL }, ///< NS_SUBSIDIES
+ { NT_GENERAL, NM_NORMAL, NF_TILE, NULL }, ///< NS_GENERAL
};
/** Initialize the news-items data structures */
@@ -105,148 +185,154 @@
_total_news = 0;
}
-void DrawNewsBorder(const Window *w)
-{
- int left = 0;
- int right = w->width - 1;
- int top = 0;
- int bottom = w->height - 1;
-
- GfxFillRect(left, top, right, bottom, 0xF);
-
- GfxFillRect(left, top, left, bottom, 0xD7);
- GfxFillRect(right, top, right, bottom, 0xD7);
- GfxFillRect(left, top, right, top, 0xD7);
- GfxFillRect(left, bottom, right, bottom, 0xD7);
-
- DrawString(left + 2, top + 1, STR_00C6, TC_FROMSTRING);
-}
-
-static void NewsWindowProc(Window *w, WindowEvent *e)
-{
- switch (e->event) {
- case WE_CREATE: { // If chatbar is open at creation time, we need to go above it
- const Window *w1 = FindWindowById(WC_SEND_NETWORK_MSG, 0);
- WP(w, news_d).chat_height = (w1 != NULL) ? w1->height : 0;
- break;
- }
-
- case WE_PAINT: {
- const NewsItem *ni = WP(w, news_d).ni;
-
- switch (ni->display_mode) {
- case NM_NORMAL:
- case NM_THIN: {
- DrawNewsBorder(w);
-
- DrawString(2, 1, STR_00C6, TC_FROMSTRING);
-
- SetDParam(0, ni->date);
- DrawStringRightAligned(428, 1, STR_01FF, TC_FROMSTRING);
-
- if (!(ni->flags & NF_VIEWPORT)) {
- CopyInDParam(0, ni->params, lengthof(ni->params));
- DrawStringMultiCenter(215, ni->display_mode == NM_NORMAL ? 76 : 56,
- ni->string_id, w->width - 4);
- } else {
- /* Back up transparency options to draw news view */
- TransparencyOptionBits to_backup = _transparency_opt;
- _transparency_opt = 0;
- DrawWindowViewport(w);
- _transparency_opt = to_backup;
+struct NewsWindow : Window {
+ uint16 chat_height;
+ NewsItem *ni;
- /* Shade the viewport into gray, or color*/
- ViewPort *vp = w->viewport;
- GfxFillRect(vp->left - w->left, vp->top - w->top,
- vp->left - w->left + vp->width - 1, vp->top - w->top + vp->height - 1,
- (ni->flags & NF_INCOLOR ? PALETTE_TO_TRANSPARENT : PALETTE_TO_STRUCT_GREY) | (1 << USE_COLORTABLE)
- );
+ NewsWindow(const WindowDesc *desc, NewsItem *ni) : Window(desc), ni(ni)
+ {
+ const Window *w = FindWindowById(WC_SEND_NETWORK_MSG, 0);
+ this->chat_height = (w != NULL) ? w->height : 0;
- CopyInDParam(0, ni->params, lengthof(ni->params));
- DrawStringMultiCenter(w->width / 2, 20, ni->string_id, w->width - 4);
- }
- break;
- }
+ this->ni = &_news_items[_forced_news == INVALID_NEWS ? _current_news : _forced_news];
+ this->flags4 |= WF_DISABLE_VP_SCROLL;
- case NM_CALLBACK:
- _draw_news_callback[ni->callback](w, ni);
- break;
+ this->FindWindowPlacementAndResize(desc);
+ }
- default:
- DrawWindowWidgets(w);
- if (!(ni->flags & NF_VIEWPORT)) {
- CopyInDParam(0, ni->params, lengthof(ni->params));
- DrawStringMultiCenter(140, 38, ni->string_id, 276);
+ void DrawNewsBorder()
+ {
+ int left = 0;
+ int right = this->width - 1;
+ int top = 0;
+ int bottom = this->height - 1;
+
+ GfxFillRect(left, top, right, bottom, 0xF);
+
+ GfxFillRect(left, top, left, bottom, 0xD7);
+ GfxFillRect(right, top, right, bottom, 0xD7);
+ GfxFillRect(left, top, right, top, 0xD7);
+ GfxFillRect(left, bottom, right, bottom, 0xD7);
+
+ DrawString(left + 2, top + 1, STR_00C6, TC_FROMSTRING);
+ }
+
+ virtual void OnPaint()
+ {
+ const NewsMode display_mode = _news_subtype_data[this->ni->subtype].display_mode;
+
+ switch (display_mode) {
+ case NM_NORMAL:
+ case NM_THIN: {
+ this->DrawNewsBorder();
+
+ DrawString(2, 1, STR_00C6, TC_FROMSTRING);
+
+ SetDParam(0, this->ni->date);
+ DrawStringRightAligned(428, 1, STR_01FF, TC_FROMSTRING);
+
+ if (!(this->ni->flags & NF_VIEWPORT)) {
+ CopyInDParam(0, this->ni->params, lengthof(this->ni->params));
+ DrawStringMultiCenter(215, display_mode == NM_NORMAL ? 76 : 56,
+ this->ni->string_id, this->width - 4);
+ } else {
+ /* Back up transparency options to draw news view */
+ TransparencyOptionBits to_backup = _transparency_opt;
+ _transparency_opt = 0;
+ this->DrawViewport();
+ _transparency_opt = to_backup;
+
+ /* Shade the viewport into gray, or color*/
+ ViewPort *vp = this->viewport;
+ GfxFillRect(vp->left - this->left, vp->top - this->top,
+ vp->left - this->left + vp->width - 1, vp->top - this->top + vp->height - 1,
+ (this->ni->flags & NF_INCOLOR ? PALETTE_TO_TRANSPARENT : PALETTE_TO_STRUCT_GREY) | (1 << USE_COLORTABLE)
+ );
+
+ CopyInDParam(0, this->ni->params, lengthof(this->ni->params));
+ DrawStringMultiCenter(this->width / 2, 20, this->ni->string_id, this->width - 4);
+ }
+ break;
+ }
+
+ case NM_CALLBACK:
+ this->DrawNewsBorder();
+ (_news_subtype_data[this->ni->subtype].callback)(this, ni);
+ break;
+
+ default:
+ this->DrawWidgets();
+ if (!(this->ni->flags & NF_VIEWPORT)) {
+ CopyInDParam(0, this->ni->params, lengthof(this->ni->params));
+ DrawStringMultiCenter(140, 38, this->ni->string_id, 276);
+ } else {
+ this->DrawViewport();
+ CopyInDParam(0, this->ni->params, lengthof(this->ni->params));
+ DrawStringMultiCenter(this->width / 2, this->height - 16, this->ni->string_id, this->width - 4);
+ }
+ break;
+ }
+ }
+
+ virtual void OnClick(Point pt, int widget)
+ {
+ switch (widget) {
+ case 1:
+ this->ni->duration = 0;
+ delete this;
+ _forced_news = INVALID_NEWS;
+ break;
+
+ case 0:
+ if (this->ni->flags & NF_VEHICLE) {
+ Vehicle *v = GetVehicle(this->ni->data_a);
+ ScrollMainWindowTo(v->x_pos, v->y_pos);
+ } else if (this->ni->flags & NF_TILE) {
+ if (_ctrl_pressed) {
+ ShowExtraViewPortWindow(this->ni->data_a);
+ if (this->ni->flags & NF_TILE2) {
+ ShowExtraViewPortWindow(this->ni->data_b);
+ }
} else {
- DrawWindowViewport(w);
- CopyInDParam(0, ni->params, lengthof(ni->params));
- DrawStringMultiCenter(w->width / 2, w->height - 16, ni->string_id, w->width - 4);
- }
- break;
- }
- break;
- }
-
- case WE_CLICK:
- switch (e->we.click.widget) {
- case 1: {
- NewsItem *ni = WP(w, news_d).ni;
- delete w;
- ni->duration = 0;
- _forced_news = INVALID_NEWS;
- break;
- }
-
- case 0: {
- NewsItem *ni = WP(w, news_d).ni;
- if (ni->flags & NF_VEHICLE) {
- Vehicle *v = GetVehicle(ni->data_a);
- ScrollMainWindowTo(v->x_pos, v->y_pos);
- } else if (ni->flags & NF_TILE) {
- if (_ctrl_pressed) {
- ShowExtraViewPortWindow(ni->data_a);
- if (ni->flags & NF_TILE2) {
- ShowExtraViewPortWindow(ni->data_b);
- }
- } else {
- if (!ScrollMainWindowToTile(ni->data_a) && ni->flags & NF_TILE2) {
- ScrollMainWindowToTile(ni->data_b);
- }
+ if (!ScrollMainWindowToTile(this->ni->data_a) && this->ni->flags & NF_TILE2) {
+ ScrollMainWindowToTile(this->ni->data_b);
}
}
- break;
}
- }
- break;
-
- case WE_KEYPRESS:
- if (e->we.keypress.keycode == WKC_SPACE) {
- /* Don't continue. */
- e->we.keypress.cont = false;
- delete w;
- }
- break;
-
- case WE_INVALIDATE_DATA: // The chatbar has notified us that is was either created or closed
- WP(w, news_d).chat_height = e->we.invalidate.data;
- break;
-
- case WE_TICK: { // Scroll up newsmessages from the bottom in steps of 4 pixels
- int y = max(w->top - 4, _screen.height - w->height - 12 - WP(w, news_d).chat_height);
- if (y == w->top) return;
-
- if (w->viewport != NULL) {
- w->viewport->top += y - w->top;
- }
-
- int diff = Delta(w->top, y);
- w->top = y;
-
- SetDirtyBlocks(w->left, w->top - diff, w->left + w->width, w->top + w->height);
- break;
+ break;
}
}
-}
+
+ virtual EventState OnKeyPress(uint16 key, uint16 keycode)
+ {
+ if (keycode == WKC_SPACE) {
+ /* Don't continue. */
+ delete this;
+ return ES_HANDLED;
+ }
+ return ES_NOT_HANDLED;
+ }
+
+ virtual void OnInvalidateData(int data)
+ {
+ /* The chatbar has notified us that is was either created or closed */
+ this->chat_height = data;
+ }
+
+ virtual void OnTick()
+ {
+ /* Scroll up newsmessages from the bottom in steps of 4 pixels */
+ int y = max(this->top - 4, _screen.height - this->height - 12 - this->chat_height);
+ if (y == this->top) return;
+
+ if (this->viewport != NULL) this->viewport->top += y - this->top;
+
+ int diff = Delta(this->top, y);
+ this->top = y;
+
+ SetDirtyBlocks(this->left, this->top - diff, this->left + this->width, this->top + this->height);
+ }
+};
/**
* Return the correct index in the pseudo-fifo
@@ -270,29 +356,14 @@
/**
* Add a new newsitem to be shown.
- * @param string String to display, can have special values based on parameter \a display_mode
- * @param display_mode, any of the NewsMode enums (NM_)
- * @param flags any of the NewsFlag enums (NF_)
- * @param type news category, any of the NewsType enums (NT_)
- * @param callback news callback function, any of the NewsCallback enums (DNC_)
+ * @param string String to display
+ * @param subtype news category, any of the NewsSubtype enums (NS_)
* @param data_a news-specific value based on news type
* @param data_b news-specific value based on news type
*
- * @note If the display mode is NM_CALLBACK, special news is shown and parameter
- * \a string has a special meaning.
- * - For DNC_TRAINAVAIL, DNC_ROADAVAIL, DNC_SHIPAVAIL, DNC_AIRCRAFTAVAIL messages: StringID is
- * the index of the engine that is shown
- *
- * - For DNC_BANKRUPCY: bytes 0-3 of StringID contains the player that is in trouble,
- * and 4-7 contains what kind of bankrupcy message is shown.
- * @see NewsBankrupcy
- *
- * @see NewsMode
- * @see NewsFlag
- * @see NewsType
- * @see NewsCallback
+ * @see NewsSubype
*/
-void AddNewsItem(StringID string, NewsMode display_mode, NewsFlag flags, NewsType type, NewsCallback callback, uint data_a, uint data_b)
+void AddNewsItem(StringID string, NewsSubtype subtype, uint data_a, uint data_b)
{
if (_game_mode == GM_MENU) return;
@@ -323,14 +394,12 @@
memset(ni, 0, sizeof(*ni));
ni->string_id = string;
- ni->display_mode = display_mode;
- ni->flags = flags;
+ ni->subtype = subtype;
+ ni->flags = _news_subtype_data[subtype].flags;
/* show this news message in color? */
if (_cur_year >= _patches.colored_news_year) ni->flags |= NF_INCOLOR;
- ni->type = type;
- ni->callback = callback;
ni->data_a = data_a;
ni->data_b = data_b;
ni->date = _date;
@@ -376,7 +445,6 @@
WC_NEWS_WINDOW, WC_NONE,
WDF_DEF_WIDGET,
_news_type13_widgets,
- NewsWindowProc
};
static const Widget _news_type2_widgets[] = {
@@ -390,7 +458,6 @@
WC_NEWS_WINDOW, WC_NONE,
WDF_DEF_WIDGET,
_news_type2_widgets,
- NewsWindowProc
};
static const Widget _news_type0_widgets[] = {
@@ -406,7 +473,6 @@
WC_NEWS_WINDOW, WC_NONE,
WDF_DEF_WIDGET,
_news_type0_widgets,
- NewsWindowProc
};
@@ -416,16 +482,16 @@
ni->flags &= ~NF_FORCE_BIG;
ni->duration = 555;
- SoundFx sound = _news_type_data[ni->type].sound;
+ SoundFx sound = _news_type_data[_news_subtype_data[ni->subtype].type].sound;
if (sound != 0) SndPlayFx(sound);
int top = _screen.height;
Window *w;
- switch (ni->display_mode) {
+ switch (_news_subtype_data[ni->subtype].display_mode) {
case NM_NORMAL:
case NM_CALLBACK:
_news_type13_desc.top = top;
- w = new Window(&_news_type13_desc);
+ w = new NewsWindow(&_news_type13_desc, ni);
if (ni->flags & NF_VIEWPORT) {
InitializeWindowViewport(w, 2, 58, 426, 110,
ni->data_a | (ni->flags & NF_VEHICLE ? 0x80000000 : 0), ZOOM_LVL_NEWS);
@@ -434,7 +500,7 @@
case NM_THIN:
_news_type2_desc.top = top;
- w = new Window(&_news_type2_desc);
+ w = new NewsWindow(&_news_type2_desc, ni);
if (ni->flags & NF_VIEWPORT) {
InitializeWindowViewport(w, 2, 58, 426, 70,
ni->data_a | (ni->flags & NF_VEHICLE ? 0x80000000 : 0), ZOOM_LVL_NEWS);
@@ -443,7 +509,7 @@
default:
_news_type0_desc.top = top;
- w = new Window(&_news_type0_desc);
+ w = new NewsWindow(&_news_type0_desc, ni);
if (ni->flags & NF_VIEWPORT) {
InitializeWindowViewport(w, 3, 17, 274, 47,
ni->data_a | (ni->flags & NF_VEHICLE ? 0x80000000 : 0), ZOOM_LVL_NEWS);
@@ -453,9 +519,6 @@
/*DEBUG(misc, 0, " cur %3d, old %2d, lat %3d, for %3d, tot %2d",
_current_news, _oldest_news, _latest_news, _forced_news, _total_news);*/
-
- WP(w, news_d).ni = &_news_items[_forced_news == INVALID_NEWS ? _current_news : _forced_news];
- w->flags4 |= WF_DISABLE_VP_SCROLL;
}
/** Show news item in the ticker */
@@ -464,8 +527,7 @@
if (_news_ticker_sound) SndPlayFx(SND_16_MORSE);
_statusbar_news_item = *ni;
- Window *w = FindWindowById(WC_STATUS_BAR, 0);
- if (w != NULL) WP(w, def_d).data_1 = 360;
+ InvalidateWindowData(WC_STATUS_BAR, 0, SBI_SHOW_TICKER);
}
@@ -482,8 +544,7 @@
/* Ticker message
* Check if the status bar message is still being displayed? */
- const Window *w = FindWindowById(WC_STATUS_BAR, 0);
- if (w != NULL && WP(w, const def_d).data_1 > -1280) return false;
+ if (IsNewsTickerShown()) return false;
/* Newspaper message, decrement duration counter */
if (ni->duration != 0) ni->duration--;
@@ -502,21 +563,16 @@
if (_current_news != _latest_news) {
_current_news = (_current_news == INVALID_NEWS) ? _oldest_news : IncreaseIndex(_current_news);
NewsItem *ni = &_news_items[_current_news];
+ const NewsType type = _news_subtype_data[ni->subtype].type;
/* check the date, don't show too old items */
- if (_date - _news_type_data[ni->type].age > ni->date) return;
+ if (_date - _news_type_data[type].age > ni->date) return;
- switch (_news_type_data[ni->type].display) {
+ switch (_news_type_data[type].display) {
default: NOT_REACHED();
- case ND_OFF: { // Off - show nothing only a small reminder in the status bar
- Window *w = FindWindowById(WC_STATUS_BAR, 0);
-
- if (w != NULL) {
- WP(w, def_d).data_2 = 91;
- w->SetDirty();
- }
+ case ND_OFF: // Off - show nothing only a small reminder in the status bar
+ InvalidateWindowData(WC_STATUS_BAR, 0, SBI_SHOW_REMINDER);
break;
- }
case ND_SUMMARY: // Summary - show ticker, but if forced big, cascade to full
if (!(ni->flags & NF_FORCE_BIG)) {
@@ -607,12 +663,8 @@
char buffer[512], buffer2[512];
StringID str;
- if (ni->display_mode == NM_CALLBACK) {
- str = _get_news_string_callback[ni->callback](ni);
- } else {
- CopyInDParam(0, ni->params, lengthof(ni->params));
- str = ni->string_id;
- }
+ CopyInDParam(0, ni->params, lengthof(ni->params));
+ str = ni->string_id;
GetString(buffer, str, lastof(buffer));
/* Copy the just gotten string to another buffer to remove any formatting
@@ -642,45 +694,56 @@
}
-static void MessageHistoryWndProc(Window *w, WindowEvent *e)
-{
- switch (e->event) {
- case WE_PAINT: {
- int y = 19;
-
- SetVScrollCount(w, _total_news);
- DrawWindowWidgets(w);
-
- if (_total_news == 0) break;
- NewsID show = min(_total_news, w->vscroll.cap);
-
- for (NewsID p = w->vscroll.pos; p < w->vscroll.pos + show; p++) {
- /* get news in correct order */
- const NewsItem *ni = &_news_items[getNews(p)];
-
- SetDParam(0, ni->date);
- DrawString(4, y, STR_SHORT_DATE, TC_WHITE);
+struct MessageHistoryWindow : Window {
+ MessageHistoryWindow(const WindowDesc *desc) : Window(desc)
+ {
+ this->vscroll.cap = 10;
+ this->vscroll.count = _total_news;
+ this->resize.step_height = 12;
+ this->resize.height = this->height - 12 * 6; // minimum of 4 items in the list, each item 12 high
+ this->resize.step_width = 1;
+ this->resize.width = 200; // can't make window any smaller than 200 pixel
- DrawNewsString(82, y, TC_WHITE, ni, w->width - 95);
- y += 12;
- }
- break;
- }
+ this->FindWindowPlacementAndResize(desc);
+ }
- case WE_CLICK:
- if (e->we.click.widget == 3) {
- int y = (e->we.click.pt.y - 19) / 12;
- NewsID p = getNews(y + w->vscroll.pos);
+ virtual void OnPaint()
+ {
+ int y = 19;
- if (p != INVALID_NEWS) ShowNewsMessage(p);
- }
- break;
+ SetVScrollCount(this, _total_news);
+ this->DrawWidgets();
- case WE_RESIZE:
- w->vscroll.cap += e->we.sizing.diff.y / 12;
- break;
+ if (_total_news == 0) return;
+ NewsID show = min(_total_news, this->vscroll.cap);
+
+ for (NewsID p = this->vscroll.pos; p < this->vscroll.pos + show; p++) {
+ /* get news in correct order */
+ const NewsItem *ni = &_news_items[getNews(p)];
+
+ SetDParam(0, ni->date);
+ DrawString(4, y, STR_SHORT_DATE, TC_WHITE);
+
+ DrawNewsString(82, y, TC_WHITE, ni, this->width - 95);
+ y += 12;
+ }
}
-}
+
+ virtual void OnClick(Point pt, int widget)
+ {
+ if (widget == 3) {
+ int y = (pt.y - 19) / 12;
+ NewsID p = getNews(y + this->vscroll.pos);
+
+ if (p != INVALID_NEWS) ShowNewsMessage(p);
+ }
+ }
+
+ virtual void OnResize(Point new_size, Point delta)
+ {
+ this->vscroll.cap += delta.y / 12;
+ }
+};
static const Widget _message_history_widgets[] = {
{ WWT_CLOSEBOX, RESIZE_NONE, 13, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW},
@@ -697,24 +760,13 @@
WC_MESSAGE_HISTORY, WC_NONE,
WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS | WDF_STICKY_BUTTON | WDF_RESIZABLE,
_message_history_widgets,
- MessageHistoryWndProc
};
/** Display window with news messages history */
void ShowMessageHistory()
{
DeleteWindowById(WC_MESSAGE_HISTORY, 0);
- Window *w = new Window(&_message_history_desc);
-
- if (w == NULL) return;
-
- w->vscroll.cap = 10;
- w->vscroll.count = _total_news;
- w->resize.step_height = 12;
- w->resize.height = w->height - 12 * 6; // minimum of 4 items in the list, each item 12 high
- w->resize.step_width = 1;
- w->resize.width = 200; // can't make window any smaller than 200 pixel
- w->SetDirty();
+ new MessageHistoryWindow(&_message_history_desc);
}
@@ -725,101 +777,96 @@
WIDGET_NEWSOPT_START_OPTION = 8, ///< First widget that is part of a group [<] .. [.]
};
-/**
- * Setup the disabled/enabled buttons in the message window
- * If the value is 'off' disable the [<] widget, and enable the [>] one
- * Same-wise for all the others. Starting value of 4 is the first widget
- * group. These are grouped as [<][>] .. [<][>], etc.
- * @param w Window been used
- * @param value to set in the widget
- * @param element index of the group of widget to set
- */
-static void SetMessageButtonStates(Window *w, byte value, int element)
-{
- element *= NB_WIDG_PER_SETTING;
-
- w->SetWidgetDisabledState(element + WIDGET_NEWSOPT_START_OPTION, value == 0);
- w->SetWidgetDisabledState(element + WIDGET_NEWSOPT_START_OPTION + 2, value == 2);
-}
-
-/**
- * Event handler of the Message Options window
- * @param w window pointer
- * @param e event been triggered
- */
-static void MessageOptionsWndProc(Window *w, WindowEvent *e)
-{
- static const StringID message_opt[] = {STR_OFF, STR_SUMMARY, STR_FULL, INVALID_STRING_ID};
-
- /* WP(w, def_d).data_1 stores state of the ALL on/off/summary button */
- switch (e->event) {
- case WE_CREATE: {
- NewsDisplay all_val;
-
- /* Set up the initial disabled buttons in the case of 'off' or 'full' */
- all_val = _news_type_data[0].display;
- for (int i = 0; i < NT_END; i++) {
- SetMessageButtonStates(w, _news_type_data[i].display, i);
- /* If the value doesn't match the ALL-button value, set the ALL-button value to 'off' */
- if (_news_type_data[i].display != all_val) all_val = ND_OFF;
- }
- /* If all values are the same value, the ALL-button will take over this value */
- WP(w, def_d).data_1 = all_val;
- break;
- }
-
- case WE_PAINT:
- if (_news_ticker_sound) w->LowerWidget(WIDGET_NEWSOPT_SOUNDTICKER);
+static const StringID _message_opt[] = {STR_OFF, STR_SUMMARY, STR_FULL, INVALID_STRING_ID};
- w->widget[WIDGET_NEWSOPT_DROP_SUMMARY].data = message_opt[WP(w, def_d).data_1];
- DrawWindowWidgets(w);
-
- /* Draw the string of each setting on each button. */
- for (int i = 0, y = 26; i < NT_END; i++, y += 12) {
- /* 51 comes from 13 + 89 (left and right of the button)+1, shiefted by one as to get division,
- * which will give centered position */
- DrawStringCentered(51, y + 1, message_opt[_news_type_data[i].display], TC_BLACK);
- }
- break;
-
- case WE_CLICK:
- switch (e->we.click.widget) {
- case WIDGET_NEWSOPT_DROP_SUMMARY: // Dropdown menu for all settings
- ShowDropDownMenu(w, message_opt, WP(w, def_d).data_1, WIDGET_NEWSOPT_DROP_SUMMARY, 0, 0);
- break;
-
- case WIDGET_NEWSOPT_SOUNDTICKER: // Change ticker sound on/off
- _news_ticker_sound ^= 1;
- w->ToggleWidgetLoweredState(e->we.click.widget);
- w->InvalidateWidget(e->we.click.widget);
- break;
+struct MessageOptionsWindow : Window {
+ int state;
- default: { // Clicked on the [<] .. [>] widgets
- int wid = e->we.click.widget - WIDGET_NEWSOPT_START_OPTION;
- if (wid >= 0 && wid < (NB_WIDG_PER_SETTING * NT_END)) {
- int element = wid / NB_WIDG_PER_SETTING;
- byte val = (_news_type_data[element].display + ((wid % NB_WIDG_PER_SETTING) ? 1 : -1)) % 3;
+ MessageOptionsWindow(const WindowDesc *desc) : Window(desc)
+ {
+ NewsDisplay all_val;
- SetMessageButtonStates(w, val, element);
- _news_type_data[element].display = (NewsDisplay)val;
- w->SetDirty();
- }
- break;
+ /* Set up the initial disabled buttons in the case of 'off' or 'full' */
+ all_val = _news_type_data[0].display;
+ for (int i = 0; i < NT_END; i++) {
+ this->SetMessageButtonStates(_news_type_data[i].display, i);
+ /* If the value doesn't match the ALL-button value, set the ALL-button value to 'off' */
+ if (_news_type_data[i].display != all_val) all_val = ND_OFF;
+ }
+ /* If all values are the same value, the ALL-button will take over this value */
+ this->state = all_val;
+ }
+
+ /**
+ * Setup the disabled/enabled buttons in the message window
+ * If the value is 'off' disable the [<] widget, and enable the [>] one
+ * Same-wise for all the others. Starting value of 4 is the first widget
+ * group. These are grouped as [<][>] .. [<][>], etc.
+ * @param value to set in the widget
+ * @param element index of the group of widget to set
+ */
+ void SetMessageButtonStates(byte value, int element)
+ {
+ element *= NB_WIDG_PER_SETTING;
+
+ this->SetWidgetDisabledState(element + WIDGET_NEWSOPT_START_OPTION, value == 0);
+ this->SetWidgetDisabledState(element + WIDGET_NEWSOPT_START_OPTION + 2, value == 2);
+ }
+
+ virtual void OnPaint()
+ {
+ if (_news_ticker_sound) this->LowerWidget(WIDGET_NEWSOPT_SOUNDTICKER);
+
+ this->widget[WIDGET_NEWSOPT_DROP_SUMMARY].data = _message_opt[this->state];
+ this->DrawWidgets();
+
+ /* Draw the string of each setting on each button. */
+ for (int i = 0, y = 26; i < NT_END; i++, y += 12) {
+ /* 51 comes from 13 + 89 (left and right of the button)+1, shiefted by one as to get division,
+ * which will give centered position */
+ DrawStringCentered(51, y + 1, _message_opt[_news_type_data[i].display], TC_BLACK);
+ }
+ }
+
+ virtual void OnClick(Point pt, int widget)
+ {
+ switch (widget) {
+ case WIDGET_NEWSOPT_DROP_SUMMARY: // Dropdown menu for all settings
+ ShowDropDownMenu(this, _message_opt, this->state, WIDGET_NEWSOPT_DROP_SUMMARY, 0, 0);
+ break;
+
+ case WIDGET_NEWSOPT_SOUNDTICKER: // Change ticker sound on/off
+ _news_ticker_sound ^= 1;
+ this->ToggleWidgetLoweredState(widget);
+ this->InvalidateWidget(widget);
+ break;
+
+ default: { // Clicked on the [<] .. [>] widgets
+ int wid = widget - WIDGET_NEWSOPT_START_OPTION;
+ if (wid >= 0 && wid < (NB_WIDG_PER_SETTING * NT_END)) {
+ int element = wid / NB_WIDG_PER_SETTING;
+ byte val = (_news_type_data[element].display + ((wid % NB_WIDG_PER_SETTING) ? 1 : -1)) % 3;
+
+ this->SetMessageButtonStates(val, element);
+ _news_type_data[element].display = (NewsDisplay)val;
+ this->SetDirty();
}
+ break;
}
- break;
-
- case WE_DROPDOWN_SELECT: // Select all settings for newsmessages
- WP(w, def_d).data_1 = e->we.dropdown.index;
+ }
+ }
- for (int i = 0; i < NT_END; i++) {
- SetMessageButtonStates(w, e->we.dropdown.index, i);
- _news_type_data[i].display = (NewsDisplay)e->we.dropdown.index;
- }
- w->SetDirty();
- break;
+ virtual void OnDropdownSelect(int widget, int index)
+ {
+ this->state = index;
+
+ for (int i = 0; i < NT_END; i++) {
+ this->SetMessageButtonStates(index, i);
+ _news_type_data[i].display = (NewsDisplay)index;
+ }
+ this->SetDirty();
}
-}
+};
/*
@@ -920,13 +967,12 @@
WC_GAME_OPTIONS, WC_NONE,
WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS,
_message_options_widgets,
- MessageOptionsWndProc
};
void ShowMessageOptions()
{
DeleteWindowById(WC_GAME_OPTIONS, 0);
- new Window(&_message_options_desc);
+ new MessageOptionsWindow(&_message_options_desc);
}
@@ -961,8 +1007,8 @@
* We also need an update of the current, forced and visible (open window)
* news's as this shifting could change the items they were pointing to */
if (_total_news != 0) {
- Window *w = FindWindowById(WC_NEWS_WINDOW, 0);
- NewsID visible_news = (w != NULL) ? (NewsID)(WP(w, news_d).ni - _news_items) : INVALID_NEWS;
+ NewsWindow *w = dynamic_cast<NewsWindow*>(FindWindowById(WC_NEWS_WINDOW, 0));
+ NewsID visible_news = (w != NULL) ? (NewsID)(w->ni - _news_items) : INVALID_NEWS;
for (NewsID i = n;; i = DecreaseIndex(i)) {
_news_items[i] = _news_items[DecreaseIndex(i)];
@@ -970,7 +1016,7 @@
if (i != _latest_news) {
if (i == _current_news) _current_news = IncreaseIndex(_current_news);
if (i == _forced_news) _forced_news = IncreaseIndex(_forced_news);
- if (i == visible_news) WP(w, news_d).ni = &_news_items[IncreaseIndex(visible_news)];
+ if (i == visible_news) w->ni = &_news_items[IncreaseIndex(visible_news)];
}
if (i == _oldest_news) break;
--- a/src/news_type.h Mon May 19 14:14:33 2008 +0000
+++ b/src/news_type.h Mon May 19 15:13:58 2008 +0000
@@ -5,7 +5,6 @@
#ifndef NEWS_TYPE_H
#define NEWS_TYPE_H
-#include "window_type.h"
#include "date_type.h"
#include "strings_type.h"
#include "sound_type.h"
@@ -32,6 +31,31 @@
};
/**
+ * News subtypes.
+ */
+enum NewsSubtype {
+ NS_ARRIVAL_PLAYER, ///< NT_ARRIVAL_PLAYER
+ NS_ARRIVAL_OTHER, ///< NT_ARRIVAL_OTHER
+ NS_ACCIDENT_TILE, ///< NT_ACCIDENT (tile)
+ NS_ACCIDENT_VEHICLE, ///< NT_ACCIDENT (vehicle)
+ NS_COMPANY_TROUBLE, ///< NT_COMPANY_INFO (trouble)
+ NS_COMPANY_MERGER, ///< NT_COMPANY_INFO (merger)
+ NS_COMPANY_BANKRUPT, ///< NT_COMPANY_INFO (bankrupt)
+ NS_COMPANY_NEW, ///< NT_COMPANY_INFO (new company)
+ NS_OPENCLOSE, ///< NT_OPENCLOSE
+ NS_ECONOMY, ///< NT_ECONOMY
+ NS_INDUSTRY_PLAYER, ///< NT_INDUSTRY_PLAYER
+ NS_INDUSTRY_OTHER, ///< NT_INDUSTRY_OTHER
+ NS_INDUSTRY_NOBODY, ///< NT_INDUSTRY_NOBODY
+ NS_ADVICE, ///< NT_ADVICE
+ NS_NEW_VEHICLES, ///< NT_NEW_VEHICLES
+ NS_ACCEPTANCE, ///< NT_ACCEPTANCE
+ NS_SUBSIDIES, ///< NT_SUBSIDIES
+ NS_GENERAL, ///< NT_GENERAL
+ NS_END, ///< end-of-array marker
+};
+
+/**
* News mode.
*/
enum NewsMode {
@@ -58,26 +82,6 @@
/**
- * Special news items
- */
-enum NewsCallback {
- DNC_VEHICLEAVAIL = 0, ///< Show new vehicle available message. StringID is EngineID
- DNC_BANKRUPCY = 1, ///< Show bankrupcy message. StringID is PlayerID (0-3) and NewsBankrupcy (4-7)
- DNC_NONE = 0xFF, ///< No news callback.
-};
-
-/**
- * Kinds of bankrupcy
- * @note These flags are or'd with player index
- */
-enum NewsBankrupcy {
- NB_BTROUBLE = (1 << 4), ///< Company is in trouble (warning)
- NB_BMERGER = (2 << 4), ///< Company has been bought by another company
- NB_BBANKRUPT = (3 << 4), ///< Company has gone bankrupt
- NB_BNEWCOMPANY = (4 << 4), ///< A new company has been started
-};
-
-/**
* News display options
*/
enum NewsDisplay {
@@ -97,22 +101,16 @@
};
struct NewsItem {
- StringID string_id; ///< Message text (sometimes also used for storing other info)
+ StringID string_id; ///< Message text
uint16 duration; ///< Remaining time for showing this news message
Date date; ///< Date of the news
+ NewsSubtype subtype; ///< News subtype @see NewsSubtype
NewsFlag flags; ///< NewsFlags bits @see NewsFlag
- NewsMode display_mode; ///< Display mode value @see NewsMode
- NewsType type; ///< News category @see NewsType
- NewsCallback callback; ///< Call-back function
- uint data_a; ///< Reference to tile or vehicle
- uint data_b; ///< Reference to second tile or vehicle
+ uint data_a; ///< Custom data 1 (usually tile or vehicle)
+ uint data_b; ///< Custom data 2
uint64 params[10];
};
-typedef bool ValidationProc(uint data_a, uint data_b);
-typedef void DrawNewsCallbackProc(Window *w, const NewsItem *ni);
-typedef StringID GetNewsStringCallbackProc(const NewsItem *ni);
-
#endif /* NEWS_TYPE_H */
--- a/src/oldloader.cpp Mon May 19 14:14:33 2008 +0000
+++ b/src/oldloader.cpp Mon May 19 15:13:58 2008 +0000
@@ -1516,7 +1516,13 @@
* clear it for ourselves and let OTTD's rebuild PBS itself */
_m[i].m4 &= 0xF; /* Only keep the lower four bits; upper four is PBS */
break;
- default: break;
+
+ case MP_WATER:
+ if (GetWaterClass(i) == 3) MakeRiver(i, Random());
+ break;
+
+ default:
+ break;
}
}
--- a/src/openttd.cpp Mon May 19 14:14:33 2008 +0000
+++ b/src/openttd.cpp Mon May 19 15:13:58 2008 +0000
@@ -290,7 +290,6 @@
{
/* Dynamic stuff needs to be initialized somewhere... */
_town_sort = NULL;
- _industry_sort = NULL;
_industry_mngr.ResetMapping();
_industile_mngr.ResetMapping();
}
@@ -327,7 +326,6 @@
_Engine_pool.CleanPool();
free((void*)_town_sort);
- free((void*)_industry_sort);
free(_config_file);
@@ -1344,42 +1342,17 @@
UpdateAllTownVirtCoords();
UpdateAllWaypointSigns();
- /* Recalculate */
- Group *g;
- FOR_ALL_GROUPS(g) {
- g->num_engines = CallocT<uint16>(GetEnginePoolSize());
-
- const Vehicle *v;
- FOR_ALL_VEHICLES(v) {
- if (!IsEngineCountable(v)) continue;
-
- if (v->group_id != g->index || v->type != g->vehicle_type || v->owner != g->owner) continue;
-
- g->num_engines[v->engine_type]++;
+ Player *p;
+ FOR_ALL_PLAYERS(p) {
+ /* For each player, verify (while loading a scenario) that the inauguration date is the current year and set it
+ * accordingly if it is not the case. No need to set it on players that are not been used already,
+ * thus the MIN_YEAR (which is really nothing more than Zero, initialized value) test */
+ if (_file_to_saveload.filetype == FT_SCENARIO && p->inaugurated_year != MIN_YEAR) {
+ p->inaugurated_year = _cur_year;
}
}
- /* Set up the engine count for all players */
- Player *players[MAX_PLAYERS];
- const Vehicle *v;
-
- for (PlayerID i = PLAYER_FIRST; i < MAX_PLAYERS; i++) {
- players[i] = GetPlayer(i);
-
- /* For each player, verify (while loading a scenario) that the inauguration date is the current year and set it
- * accordingly if it is not the case. No need to set it on players that are not been used already,
- * thus the MIN_YEAR (which is really nothing more than Zero, initialized value) test */
- if (_file_to_saveload.filetype == FT_SCENARIO && players[i]->inaugurated_year != MIN_YEAR)
- players[i]->inaugurated_year = _cur_year;
-
- free(players[i]->num_engines);
- players[i]->num_engines = CallocT<uint16>(GetEnginePoolSize());
- }
-
- FOR_ALL_VEHICLES(v) {
- if (!IsEngineCountable(v)) continue;
- players[v->owner]->num_engines[v->engine_type]++;
- }
+ SetCachedEngineCounts();
return true;
}
@@ -2434,9 +2407,7 @@
/* Move river flag and update canals to use water class */
if (IsTileType(t, MP_WATER)) {
- if (_m[t].m5 == 2) {
- MakeRiver(t, Random());
- } else {
+ if (GetWaterClass(t) != WATER_CLASS_RIVER) {
if (IsWater(t)) {
Owner o = GetTileOwner(t);
if (o == OWNER_WATER) {
@@ -2574,11 +2545,14 @@
ResetVehiclePosHash();
AfterLoadVehicles(false);
StartupEngines();
+ SetCachedEngineCounts();
/* update station and waypoint graphics */
AfterLoadWaypoints();
AfterLoadStations();
/* Check and update house and town values */
UpdateHousesAndTowns();
+ /* Update livery selection windows */
+ for (PlayerID i = PLAYER_FIRST; i < MAX_PLAYERS; i++) InvalidateWindowData(WC_PLAYER_COLOR, i, _loaded_newgrf_features.has_2CC);
/* redraw the whole screen */
MarkWholeScreenDirty();
}
--- a/src/order_cmd.cpp Mon May 19 14:14:33 2008 +0000
+++ b/src/order_cmd.cpp Mon May 19 15:13:58 2008 +0000
@@ -546,7 +546,7 @@
}
/* Make sure to rebuild the whole list */
- RebuildVehicleLists();
+ InvalidateWindowClassesData(GetWindowClassForVehicleType(v->type), 0);
}
return CommandCost();
@@ -561,7 +561,7 @@
if (flags & DC_EXEC) {
DeleteVehicleOrders(dst);
InvalidateVehicleOrder(dst);
- RebuildVehicleLists();
+ InvalidateWindowClassesData(GetWindowClassForVehicleType(dst->type), 0);
}
return CommandCost();
}
@@ -673,7 +673,7 @@
cur_order_id++;
}
- RebuildVehicleLists();
+ InvalidateWindowClassesData(GetWindowClassForVehicleType(v->type), 0);
}
return CommandCost();
@@ -811,7 +811,7 @@
}
/* Make sure to rebuild the whole list */
- RebuildVehicleLists();
+ InvalidateWindowClassesData(GetWindowClassForVehicleType(v->type), 0);
}
return CommandCost();
@@ -1075,7 +1075,7 @@
InvalidateVehicleOrder(dst);
InvalidateVehicleOrder(src);
- RebuildVehicleLists();
+ InvalidateWindowClassesData(GetWindowClassForVehicleType(dst->type), 0);
}
} break;
@@ -1134,7 +1134,7 @@
InvalidateVehicleOrder(dst);
- RebuildVehicleLists();
+ InvalidateWindowClassesData(GetWindowClassForVehicleType(dst->type), 0);
}
} break;
@@ -1444,7 +1444,7 @@
SetDParam(0, v->unitnumber);
AddNewsItem(
message,
- NM_SMALL, NF_VIEWPORT | NF_VEHICLE, NT_ADVICE, DNC_NONE,
+ NS_ADVICE,
v->index,
0
);
--- a/src/order_gui.cpp Mon May 19 14:14:33 2008 +0000
+++ b/src/order_gui.cpp Mon May 19 15:13:58 2008 +0000
@@ -58,60 +58,6 @@
ORDER_WIDGET_RESIZE,
};
-/** Under what reason are we using the PlaceObject functionality? */
-enum OrderPlaceObjectState {
- OPOS_GOTO,
- OPOS_CONDITIONAL,
-};
-
-struct order_d {
- int sel;
- OrderPlaceObjectState goto_type;
-};
-assert_compile(WINDOW_CUSTOM_SIZE >= sizeof(order_d));
-
-/**
- * Return the memorised selected order.
- *
- * @param w current window
- * @return the memorised order if it is a vaild one
- * else return the number of orders
- */
-static int OrderGetSel(const Window *w)
-{
- const Vehicle *v = GetVehicle(w->window_number);
- int num = WP(w, order_d).sel;
-
- return (num >= 0 && num < v->num_orders) ? num : v->num_orders;
-}
-
-/**
- * Calculate the selected order.
- * The calculation is based on the relative (to the window) y click position and
- * the position of the scrollbar.
- *
- * @param w current window
- * @param y Y-value of the click relative to the window origin
- * @param v current vehicle
- * @return the new selected order if the order is valid else return that
- * an invalid one has been selected.
- */
-static int GetOrderFromOrderWndPt(Window *w, int y, const Vehicle *v)
-{
- /*
- * Calculation description:
- * 15 = 14 (w->widget[ORDER_WIDGET_ORDER_LIST].top) + 1 (frame-line)
- * 10 = order text hight
- */
- int sel = (y - w->widget[ORDER_WIDGET_ORDER_LIST].top - 1) / 10;
-
- if ((uint)sel >= w->vscroll.cap) return INVALID_ORDER;
-
- sel += w->vscroll.pos;
-
- return (sel <= v->num_orders && sel >= 0) ? sel : INVALID_ORDER;
-}
-
/** Order load types that could be given to station orders. */
static const StringID _station_load_types[][5] = {
{
@@ -312,121 +258,6 @@
}
-static void DrawOrdersWindow(Window *w)
-{
- const Vehicle *v = GetVehicle(w->window_number);
- bool shared_orders = v->IsOrderListShared();
-
- SetVScrollCount(w, v->num_orders + 1);
-
- int sel = OrderGetSel(w);
- const Order *order = GetVehicleOrder(v, sel);
-
- if (v->owner == _local_player) {
- /* Set the strings for the dropdown boxes. */
- w->widget[ORDER_WIDGET_NON_STOP].data = _order_non_stop_drowdown[order == NULL ? 0 : order->GetNonStopType()];
- w->widget[ORDER_WIDGET_FULL_LOAD].data = _order_full_load_drowdown[order == NULL ? 0 : order->GetLoadType()];
- w->widget[ORDER_WIDGET_UNLOAD].data = _order_unload_drowdown[order == NULL ? 0 : order->GetUnloadType()];
- w->widget[ORDER_WIDGET_COND_VARIABLE].data = _order_conditional_variable[order == NULL ? 0 : order->GetConditionVariable()];
- w->widget[ORDER_WIDGET_COND_COMPARATOR].data = _order_conditional_condition[order == NULL ? 0 : order->GetConditionComparator()];
-
- /* skip */
- w->SetWidgetDisabledState(ORDER_WIDGET_SKIP, v->num_orders <= 1);
-
- /* delete */
- w->SetWidgetDisabledState(ORDER_WIDGET_DELETE,
- (uint)v->num_orders + ((shared_orders || v->num_orders != 0) ? 1 : 0) <= (uint)WP(w, order_d).sel);
-
- /* non-stop only for trains */
- w->SetWidgetDisabledState(ORDER_WIDGET_NON_STOP, (v->type != VEH_TRAIN && v->type != VEH_ROAD) || order == NULL);
- w->SetWidgetDisabledState(ORDER_WIDGET_FULL_LOAD, order == NULL || (order->GetNonStopType() & ONSF_NO_STOP_AT_DESTINATION_STATION) != 0); // full load
- w->SetWidgetDisabledState(ORDER_WIDGET_UNLOAD, order == NULL || (order->GetNonStopType() & ONSF_NO_STOP_AT_DESTINATION_STATION) != 0); // unload
- /* Disable list of vehicles with the same shared orders if there is no list */
- w->SetWidgetDisabledState(ORDER_WIDGET_SHARED_ORDER_LIST, !shared_orders || v->orders == NULL);
- w->SetWidgetDisabledState(ORDER_WIDGET_REFIT, order == NULL); // Refit
- w->SetWidgetDisabledState(ORDER_WIDGET_SERVICE, order == NULL); // Refit
- w->HideWidget(ORDER_WIDGET_REFIT); // Refit
- w->HideWidget(ORDER_WIDGET_SERVICE); // Service
-
- w->HideWidget(ORDER_WIDGET_COND_VARIABLE);
- w->HideWidget(ORDER_WIDGET_COND_COMPARATOR);
- w->HideWidget(ORDER_WIDGET_COND_VALUE);
- }
-
- w->ShowWidget(ORDER_WIDGET_NON_STOP);
- w->ShowWidget(ORDER_WIDGET_UNLOAD);
- w->ShowWidget(ORDER_WIDGET_FULL_LOAD);
-
- if (order != NULL) {
- switch (order->GetType()) {
- case OT_GOTO_STATION:
- if (!GetStation(order->GetDestination())->IsBuoy()) break;
- /* Fall-through */
-
- case OT_GOTO_WAYPOINT:
- w->DisableWidget(ORDER_WIDGET_FULL_LOAD);
- w->DisableWidget(ORDER_WIDGET_UNLOAD);
- break;
-
- case OT_GOTO_DEPOT:
- w->DisableWidget(ORDER_WIDGET_FULL_LOAD);
-
- /* Remove unload and replace it with refit */
- w->HideWidget(ORDER_WIDGET_UNLOAD);
- w->ShowWidget(ORDER_WIDGET_REFIT);
- w->HideWidget(ORDER_WIDGET_FULL_LOAD);
- w->ShowWidget(ORDER_WIDGET_SERVICE);
- break;
-
- case OT_CONDITIONAL: {
- w->HideWidget(ORDER_WIDGET_NON_STOP);
- w->HideWidget(ORDER_WIDGET_UNLOAD);
- w->HideWidget(ORDER_WIDGET_FULL_LOAD);
- w->ShowWidget(ORDER_WIDGET_COND_VARIABLE);
- w->ShowWidget(ORDER_WIDGET_COND_COMPARATOR);
- w->ShowWidget(ORDER_WIDGET_COND_VALUE);
-
- OrderConditionVariable ocv = order->GetConditionVariable();
- w->SetWidgetDisabledState(ORDER_WIDGET_COND_COMPARATOR, ocv == OCV_UNCONDITIONALLY);
- w->SetWidgetDisabledState(ORDER_WIDGET_COND_VALUE, ocv == OCV_REQUIRES_SERVICE || ocv == OCV_UNCONDITIONALLY);
-
- uint value = order->GetConditionValue();
- if (order->GetConditionVariable() == OCV_MAX_SPEED) value = ConvertSpeedToDisplaySpeed(value);
- SetDParam(1, value);
- } break;
-
- default: // every other orders
- w->DisableWidget(ORDER_WIDGET_NON_STOP);
- w->DisableWidget(ORDER_WIDGET_FULL_LOAD);
- w->DisableWidget(ORDER_WIDGET_UNLOAD);
- }
- }
-
- SetDParam(0, v->index);
- DrawWindowWidgets(w);
-
- int y = 15;
-
- int i = w->vscroll.pos;
- order = GetVehicleOrder(v, i);
- StringID str;
- while (order != NULL) {
- /* Don't draw anything if it extends past the end of the window. */
- if (i - w->vscroll.pos >= w->vscroll.cap) break;
-
- DrawOrderString(v, order, i, y, i == WP(w, order_d).sel, false);
- y += 10;
-
- i++;
- order = order->next;
- }
-
- if (i - w->vscroll.pos < w->vscroll.cap) {
- str = shared_orders ? STR_END_OF_SHARED_ORDERS : STR_882A_END_OF_ORDERS;
- DrawString(2, y, str, (i == WP(w, order_d).sel) ? TC_WHITE : TC_BLACK);
- }
-}
-
static Order GetOrderCmdFromTile(const Vehicle *v, TileIndex tile)
{
Order order;
@@ -510,548 +341,689 @@
return order;
}
-static bool HandleOrderVehClick(const Vehicle *v, const Vehicle *u, Window *w)
-{
- if (u->type != v->type) return false;
+struct OrdersWindow : public Window {
+private:
+ /** Under what reason are we using the PlaceObject functionality? */
+ enum OrderPlaceObjectState {
+ OPOS_GOTO,
+ OPOS_CONDITIONAL,
+ };
- if (!u->IsPrimaryVehicle()) {
- u = u->First();
- if (!u->IsPrimaryVehicle()) return false;
- }
+ int selected_order;
+ OrderPlaceObjectState goto_type;
+ const Vehicle *vehicle;
- /* v is vehicle getting orders. Only copy/clone orders if vehicle doesn't have any orders yet
- * obviously if you press CTRL on a non-empty orders vehicle you know what you are doing */
- if (v->num_orders != 0 && _ctrl_pressed == 0) return false;
-
- if (DoCommandP(v->tile, v->index | (u->index << 16), _ctrl_pressed ? CO_SHARE : CO_COPY, NULL,
- _ctrl_pressed ? CMD_CLONE_ORDER | CMD_MSG(STR_CANT_SHARE_ORDER_LIST) : CMD_CLONE_ORDER | CMD_MSG(STR_CANT_COPY_ORDER_LIST))) {
- WP(w, order_d).sel = -1;
- ResetObjectToPlace();
+ /**
+ * Return the memorised selected order.
+ * @return the memorised order if it is a vaild one
+ * else return the number of orders
+ */
+ int OrderGetSel()
+ {
+ int num = this->selected_order;
+ return (num >= 0 && num < vehicle->num_orders) ? num : vehicle->num_orders;
}
- return true;
-}
-
-static void OrdersPlaceObj(const Vehicle *v, TileIndex tile, Window *w)
-{
- /* check if we're clicking on a vehicle first.. clone orders in that case. */
- const Vehicle *u = CheckMouseOverVehicle();
- if (u != NULL && HandleOrderVehClick(v, u, w)) return;
-
- const Order cmd = GetOrderCmdFromTile(v, tile);
- if (!cmd.IsValid()) return;
-
- if (DoCommandP(v->tile, v->index + (OrderGetSel(w) << 16), cmd.Pack(), NULL, CMD_INSERT_ORDER | CMD_MSG(STR_8833_CAN_T_INSERT_NEW_ORDER))) {
- if (WP(w, order_d).sel != -1) WP(w, order_d).sel++;
- ResetObjectToPlace();
- }
-}
+ /**
+ * Calculate the selected order.
+ * The calculation is based on the relative (to the window) y click position and
+ * the position of the scrollbar.
+ *
+ * @param y Y-value of the click relative to the window origin
+ * @param v current vehicle
+ * @return the new selected order if the order is valid else return that
+ * an invalid one has been selected.
+ */
+ int GetOrderFromPt(int y)
+ {
+ /*
+ * Calculation description:
+ * 15 = 14 (w->widget[ORDER_WIDGET_ORDER_LIST].top) + 1 (frame-line)
+ * 10 = order text hight
+ */
+ int sel = (y - this->widget[ORDER_WIDGET_ORDER_LIST].top - 1) / 10;
-/**
- * Handle the click on the goto button.
- *
- * @param w current window
- * @param v current vehicle
- */
-static void OrderClick_Goto(Window *w, const Vehicle *v, int i)
-{
- w->InvalidateWidget(ORDER_WIDGET_GOTO);
- w->ToggleWidgetLoweredState(ORDER_WIDGET_GOTO);
- if (w->IsWidgetLowered(ORDER_WIDGET_GOTO)) {
- _place_clicked_vehicle = NULL;
- SetObjectToPlaceWnd(ANIMCURSOR_PICKSTATION, PAL_NONE, VHM_RECT, w);
- WP(w, order_d).goto_type = OPOS_GOTO;
- } else {
- ResetObjectToPlace();
- }
-}
+ if ((uint)sel >= this->vscroll.cap) return INVALID_ORDER;
-/**
- * Handle the click on the full load button.
- *
- * @param w current window
- * @param v current vehicle
- * @param load_type the way to load.
- */
-static void OrderClick_FullLoad(Window *w, const Vehicle *v, int load_type)
-{
- VehicleOrderID sel_ord = OrderGetSel(w);
- const Order *order = GetVehicleOrder(v, sel_ord);
+ sel += this->vscroll.pos;
- if (order->GetLoadType() == load_type) return;
-
- if (load_type < 0) {
- switch (order->GetLoadType()) {
- case OLF_LOAD_IF_POSSIBLE: load_type = OLFB_FULL_LOAD; break;
- case OLFB_FULL_LOAD: load_type = OLF_FULL_LOAD_ANY; break;
- case OLF_FULL_LOAD_ANY: load_type = OLFB_NO_LOAD; break;
- case OLFB_NO_LOAD: load_type = OLF_LOAD_IF_POSSIBLE; break;
- default: NOT_REACHED();
- }
+ return (sel <= vehicle->num_orders && sel >= 0) ? sel : INVALID_ORDER;
}
- DoCommandP(v->tile, v->index + (sel_ord << 16), MOF_LOAD | (load_type << 4), NULL, CMD_MODIFY_ORDER | CMD_MSG(STR_8835_CAN_T_MODIFY_THIS_ORDER));
-}
-
-/**
- * Handle the click on the service.
- *
- * @param w current window
- * @param v current vehicle
- */
-static void OrderClick_Service(Window *w, const Vehicle *v, int i)
-{
- DoCommandP(v->tile, v->index + (OrderGetSel(w) << 16), MOF_DEPOT_ACTION, NULL, CMD_MODIFY_ORDER | CMD_MSG(STR_8835_CAN_T_MODIFY_THIS_ORDER));
-}
-
-/**
- * Handle the click on the service in nearest depot button.
- *
- * @param w current window
- * @param v current vehicle
- */
-static void OrderClick_NearestDepot(Window *w, const Vehicle *v, int i)
-{
- Order order;
- order.next = NULL;
- order.index = 0;
- order.MakeGoToDepot(0, ODTFB_PART_OF_ORDERS);
- order.SetDepotActionType(ODATFB_NEAREST_DEPOT);
-
- DoCommandP(v->tile, v->index + (OrderGetSel(w) << 16), order.Pack(), NULL, CMD_INSERT_ORDER | CMD_MSG(STR_8833_CAN_T_INSERT_NEW_ORDER));
-}
-/**
- * Handle the click on the conditional order button.
- *
- * @param w current window
- * @param v current vehicle
- */
-static void OrderClick_Conditional(Window *w, const Vehicle *v, int i)
-{
- w->InvalidateWidget(ORDER_WIDGET_GOTO);
- w->LowerWidget(ORDER_WIDGET_GOTO);
- SetObjectToPlaceWnd(ANIMCURSOR_PICKSTATION, PAL_NONE, VHM_RECT, w);
- WP(w, order_d).goto_type = OPOS_CONDITIONAL;
-}
+ bool HandleOrderVehClick(const Vehicle *u)
+ {
+ if (u->type != this->vehicle->type) return false;
-/**
- * Handle the click on the unload button.
- *
- * @param w current window
- * @param v current vehicle
- */
-static void OrderClick_Unload(Window *w, const Vehicle *v, int unload_type)
-{
- VehicleOrderID sel_ord = OrderGetSel(w);
- const Order *order = GetVehicleOrder(v, sel_ord);
+ if (!u->IsPrimaryVehicle()) {
+ u = u->First();
+ if (!u->IsPrimaryVehicle()) return false;
+ }
- if (order->GetUnloadType() == unload_type) return;
+ /* v is vehicle getting orders. Only copy/clone orders if vehicle doesn't have any orders yet
+ * obviously if you press CTRL on a non-empty orders vehicle you know what you are doing */
+ if (this->vehicle->num_orders != 0 && _ctrl_pressed == 0) return false;
- if (unload_type < 0) {
- switch (order->GetUnloadType()) {
- case OUF_UNLOAD_IF_POSSIBLE: unload_type = OUFB_UNLOAD; break;
- case OUFB_UNLOAD: unload_type = OUFB_TRANSFER; break;
- case OUFB_TRANSFER: unload_type = OUFB_NO_UNLOAD; break;
- case OUFB_NO_UNLOAD: unload_type = OUF_UNLOAD_IF_POSSIBLE; break;
- default: NOT_REACHED();
+ if (DoCommandP(this->vehicle->tile, this->vehicle->index | (u->index << 16), _ctrl_pressed ? CO_SHARE : CO_COPY, NULL,
+ _ctrl_pressed ? CMD_CLONE_ORDER | CMD_MSG(STR_CANT_SHARE_ORDER_LIST) : CMD_CLONE_ORDER | CMD_MSG(STR_CANT_COPY_ORDER_LIST))) {
+ this->selected_order = -1;
+ ResetObjectToPlace();
+ }
+
+ return true;
+ }
+
+ /**
+ * Handle the click on the goto button.
+ *
+ * @param w current window
+ */
+ static void OrderClick_Goto(OrdersWindow *w, int i)
+ {
+ w->InvalidateWidget(ORDER_WIDGET_GOTO);
+ w->ToggleWidgetLoweredState(ORDER_WIDGET_GOTO);
+ if (w->IsWidgetLowered(ORDER_WIDGET_GOTO)) {
+ _place_clicked_vehicle = NULL;
+ SetObjectToPlaceWnd(ANIMCURSOR_PICKSTATION, PAL_NONE, VHM_RECT, w);
+ w->goto_type = OPOS_GOTO;
+ } else {
+ ResetObjectToPlace();
}
}
- DoCommandP(v->tile, v->index + (sel_ord << 16), MOF_UNLOAD | (unload_type << 4), NULL, CMD_MODIFY_ORDER | CMD_MSG(STR_8835_CAN_T_MODIFY_THIS_ORDER));
-}
+ /**
+ * Handle the click on the full load button.
+ *
+ * @param w current window
+ * @param load_type the way to load.
+ */
+ static void OrderClick_FullLoad(OrdersWindow *w, int load_type)
+ {
+ VehicleOrderID sel_ord = w->OrderGetSel();
+ const Order *order = GetVehicleOrder(w->vehicle, sel_ord);
-/**
- * Handle the click on the nonstop button.
- *
- * @param w current window
- * @param v current vehicle
- * @param non_stop what non-stop type to use; -1 to use the 'next' one.
- */
-static void OrderClick_Nonstop(Window *w, const Vehicle *v, int non_stop)
-{
- VehicleOrderID sel_ord = OrderGetSel(w);
- const Order *order = GetVehicleOrder(v, sel_ord);
+ if (order == NULL || order->GetLoadType() == load_type) return;
- if (order->GetNonStopType() == non_stop) return;
-
- /* Keypress if negative, so 'toggle' to the next */
- if (non_stop < 0) {
- non_stop = (order->GetNonStopType() + 1) % ONSF_END;
+ if (load_type < 0) {
+ switch (order->GetLoadType()) {
+ case OLF_LOAD_IF_POSSIBLE: load_type = OLFB_FULL_LOAD; break;
+ case OLFB_FULL_LOAD: load_type = OLF_FULL_LOAD_ANY; break;
+ case OLF_FULL_LOAD_ANY: load_type = OLFB_NO_LOAD; break;
+ case OLFB_NO_LOAD: load_type = OLF_LOAD_IF_POSSIBLE; break;
+ default: NOT_REACHED();
+ }
+ }
+ DoCommandP(w->vehicle->tile, w->vehicle->index + (sel_ord << 16), MOF_LOAD | (load_type << 4), NULL, CMD_MODIFY_ORDER | CMD_MSG(STR_8835_CAN_T_MODIFY_THIS_ORDER));
}
- DoCommandP(v->tile, v->index + (sel_ord << 16), MOF_NON_STOP | non_stop << 4, NULL, CMD_MODIFY_ORDER | CMD_MSG(STR_8835_CAN_T_MODIFY_THIS_ORDER));
-}
-
-/**
- * Handle the click on the transfer button.
- *
- * @param w current window
- * @param v current vehicle
- */
-static void OrderClick_Transfer(Window *w, const Vehicle *v, int i)
-{
- VehicleOrderID sel_ord = OrderGetSel(w);
- const Order *order = GetVehicleOrder(v, sel_ord);
-
- DoCommandP(v->tile, v->index + (sel_ord << 16), MOF_UNLOAD | ((order->GetUnloadType() & ~OUFB_NO_UNLOAD) ^ OUFB_TRANSFER) << 4, NULL, CMD_MODIFY_ORDER | CMD_MSG(STR_8835_CAN_T_MODIFY_THIS_ORDER));
-}
-
-/**
- * Handle the click on the skip button.
- * If ctrl is pressed skip to selected order.
- * Else skip to current order + 1
- *
- * @param w current window
- * @param v current vehicle
- */
-static void OrderClick_Skip(Window *w, const Vehicle *v, int i)
-{
- /* Don't skip when there's nothing to skip */
- if (_ctrl_pressed && v->cur_order_index == OrderGetSel(w)) return;
-
- DoCommandP(v->tile, v->index, _ctrl_pressed ? OrderGetSel(w) : ((v->cur_order_index + 1) % v->num_orders),
- NULL, CMD_SKIP_TO_ORDER | CMD_MSG(_ctrl_pressed ? STR_CAN_T_SKIP_TO_ORDER : STR_CAN_T_SKIP_ORDER));
-}
-
-/**
- * Handle the click on the unload button.
- *
- * @param w current window
- * @param v current vehicle
- */
-static void OrderClick_Delete(Window *w, const Vehicle *v, int i)
-{
- DoCommandP(v->tile, v->index, OrderGetSel(w), NULL, CMD_DELETE_ORDER | CMD_MSG(STR_8834_CAN_T_DELETE_THIS_ORDER));
-}
-
-/**
- * Handle the click on the refit button.
- * If ctrl is pressed cancel refitting.
- * Else show the refit window.
- *
- * @param w current window
- * @param v current vehicle
- */
-static void OrderClick_Refit(Window *w, const Vehicle *v, int i)
-{
- if (_ctrl_pressed) {
- /* Cancel refitting */
- DoCommandP(v->tile, v->index, (WP(w, order_d).sel << 16) | (CT_NO_REFIT << 8) | CT_NO_REFIT, NULL, CMD_ORDER_REFIT);
- } else {
- ShowVehicleRefitWindow(v, WP(w, order_d).sel);
+ /**
+ * Handle the click on the service.
+ *
+ * @param w current window
+ */
+ static void OrderClick_Service(OrdersWindow *w, int i)
+ {
+ DoCommandP(w->vehicle->tile, w->vehicle->index + (w->OrderGetSel() << 16), MOF_DEPOT_ACTION, NULL, CMD_MODIFY_ORDER | CMD_MSG(STR_8835_CAN_T_MODIFY_THIS_ORDER));
}
-}
-
-typedef void OnButtonVehClick(Window *w, const Vehicle *v, int i);
-
-/**
- * Keycode function mapping.
- *
- * @see _order_keycodes[]
- * @note Keep them allways in sync with _order_keycodes[]!
- */
-static OnButtonVehClick* const _order_button_proc[] = {
- OrderClick_Skip,
- OrderClick_Delete,
- OrderClick_Nonstop,
- OrderClick_Goto,
- OrderClick_FullLoad,
- OrderClick_Unload,
- OrderClick_Transfer,
- OrderClick_Service,
-};
-static const uint16 _order_keycodes[] = {
- 'D', //skip order
- 'F', //delete order
- 'G', //non-stop
- 'H', //goto order
- 'J', //full load
- 'K' //unload
-};
-
-static void OrdersWndProc(Window *w, WindowEvent *e)
-{
- const Vehicle *v = GetVehicle(w->window_number);
-
- switch (e->event) {
- case WE_CREATE:
- if (_patches.timetabling) {
- w->widget[ORDER_WIDGET_CAPTION].right -= 61;
- } else {
- w->HideWidget(ORDER_WIDGET_TIMETABLE_VIEW);
- }
-
- break;
-
- case WE_PAINT:
- DrawOrdersWindow(w);
- break;
-
- case WE_CLICK:
- if (w->widget[e->we.click.widget].type != WWT_DROPDOWN) HideDropDownMenu(w);
- switch (e->we.click.widget) {
- case ORDER_WIDGET_ORDER_LIST: {
- ResetObjectToPlace();
-
- int sel = GetOrderFromOrderWndPt(w, e->we.click.pt.y, v);
-
- if (sel == INVALID_ORDER) {
- /* This was a click on an empty part of the orders window, so
- * deselect the currently selected order. */
- WP(w, order_d).sel = -1;
- w->SetDirty();
- return;
- }
+ /**
+ * Handle the click on the service in nearest depot button.
+ *
+ * @param w current window
+ */
+ static void OrderClick_NearestDepot(OrdersWindow *w, int i)
+ {
+ Order order;
+ order.next = NULL;
+ order.index = 0;
+ order.MakeGoToDepot(0, ODTFB_PART_OF_ORDERS);
+ order.SetDepotActionType(ODATFB_NEAREST_DEPOT);
- if (_ctrl_pressed && sel < v->num_orders) {
- const Order *ord = GetVehicleOrder(v, sel);
- TileIndex xy;
-
- switch (ord->GetType()) {
- case OT_GOTO_STATION: xy = GetStation(ord->GetDestination())->xy ; break;
- case OT_GOTO_DEPOT: xy = (v->type == VEH_AIRCRAFT) ? GetStation(ord->GetDestination())->xy : GetDepot(ord->GetDestination())->xy; break;
- case OT_GOTO_WAYPOINT: xy = GetWaypoint(ord->GetDestination())->xy; break;
- default: xy = 0; break;
- }
-
- if (xy != 0) ScrollMainWindowToTile(xy);
- return;
- } else {
- if (sel == WP(w, order_d).sel) {
- /* Deselect clicked order */
- WP(w, order_d).sel = -1;
- } else {
- /* Select clicked order */
- WP(w, order_d).sel = sel;
+ DoCommandP(w->vehicle->tile, w->vehicle->index + (w->OrderGetSel() << 16), order.Pack(), NULL, CMD_INSERT_ORDER | CMD_MSG(STR_8833_CAN_T_INSERT_NEW_ORDER));
+ }
- if (v->owner == _local_player) {
- /* Activate drag and drop */
- SetObjectToPlaceWnd(SPR_CURSOR_MOUSE, PAL_NONE, VHM_DRAG, w);
- }
- }
- }
-
- w->SetDirty();
- } break;
+ /**
+ * Handle the click on the conditional order button.
+ *
+ * @param w current window
+ */
+ static void OrderClick_Conditional(OrdersWindow *w, int i)
+ {
+ w->InvalidateWidget(ORDER_WIDGET_GOTO);
+ w->LowerWidget(ORDER_WIDGET_GOTO);
+ SetObjectToPlaceWnd(ANIMCURSOR_PICKSTATION, PAL_NONE, VHM_RECT, w);
+ w->goto_type = OPOS_CONDITIONAL;
+ }
- case ORDER_WIDGET_SKIP:
- OrderClick_Skip(w, v, 0);
- break;
+ /**
+ * Handle the click on the unload button.
+ *
+ * @param w current window
+ */
+ static void OrderClick_Unload(OrdersWindow *w, int unload_type)
+ {
+ VehicleOrderID sel_ord = w->OrderGetSel();
+ const Order *order = GetVehicleOrder(w->vehicle, sel_ord);
- case ORDER_WIDGET_DELETE:
- OrderClick_Delete(w, v, 0);
- break;
+ if (order == NULL || order->GetUnloadType() == unload_type) return;
- case ORDER_WIDGET_NON_STOP: {
- const Order *o = GetVehicleOrder(v, OrderGetSel(w));
- ShowDropDownMenu(w, _order_non_stop_drowdown, o->GetNonStopType(), ORDER_WIDGET_NON_STOP, 0, o->IsType(OT_GOTO_STATION) ? 0 : (o->IsType(OT_GOTO_WAYPOINT) ? 3 : 12));
- } break;
+ if (unload_type < 0) {
+ switch (order->GetUnloadType()) {
+ case OUF_UNLOAD_IF_POSSIBLE: unload_type = OUFB_UNLOAD; break;
+ case OUFB_UNLOAD: unload_type = OUFB_TRANSFER; break;
+ case OUFB_TRANSFER: unload_type = OUFB_NO_UNLOAD; break;
+ case OUFB_NO_UNLOAD: unload_type = OUF_UNLOAD_IF_POSSIBLE; break;
+ default: NOT_REACHED();
+ }
+ }
- case ORDER_WIDGET_GOTO:
- OrderClick_Goto(w, v, 0);
+ DoCommandP(w->vehicle->tile, w->vehicle->index + (sel_ord << 16), MOF_UNLOAD | (unload_type << 4), NULL, CMD_MODIFY_ORDER | CMD_MSG(STR_8835_CAN_T_MODIFY_THIS_ORDER));
+ }
+
+ /**
+ * Handle the click on the nonstop button.
+ *
+ * @param w current window
+ * @param non_stop what non-stop type to use; -1 to use the 'next' one.
+ */
+ static void OrderClick_Nonstop(OrdersWindow *w, int non_stop)
+ {
+ VehicleOrderID sel_ord = w->OrderGetSel();
+ const Order *order = GetVehicleOrder(w->vehicle, sel_ord);
+
+ if (order == NULL || order->GetNonStopType() == non_stop) return;
+
+ /* Keypress if negative, so 'toggle' to the next */
+ if (non_stop < 0) {
+ non_stop = (order->GetNonStopType() + 1) % ONSF_END;
+ }
+
+ DoCommandP(w->vehicle->tile, w->vehicle->index + (sel_ord << 16), MOF_NON_STOP | non_stop << 4, NULL, CMD_MODIFY_ORDER | CMD_MSG(STR_8835_CAN_T_MODIFY_THIS_ORDER));
+ }
+
+ /**
+ * Handle the click on the transfer button.
+ *
+ * @param w current window
+ */
+ static void OrderClick_Transfer(OrdersWindow *w, int i)
+ {
+ VehicleOrderID sel_ord = w->OrderGetSel();
+ const Order *order = GetVehicleOrder(w->vehicle, sel_ord);
+
+ if (order == NULL) return;
+
+ DoCommandP(w->vehicle->tile, w->vehicle->index + (sel_ord << 16), MOF_UNLOAD | ((order->GetUnloadType() & ~OUFB_NO_UNLOAD) ^ OUFB_TRANSFER) << 4, NULL, CMD_MODIFY_ORDER | CMD_MSG(STR_8835_CAN_T_MODIFY_THIS_ORDER));
+ }
+
+ /**
+ * Handle the click on the skip button.
+ * If ctrl is pressed skip to selected order.
+ * Else skip to current order + 1
+ *
+ * @param w current window
+ */
+ static void OrderClick_Skip(OrdersWindow *w, int i)
+ {
+ /* Don't skip when there's nothing to skip */
+ if (_ctrl_pressed && w->vehicle->cur_order_index == w->OrderGetSel()) return;
+
+ DoCommandP(w->vehicle->tile, w->vehicle->index, _ctrl_pressed ? w->OrderGetSel() : ((w->vehicle->cur_order_index + 1) % w->vehicle->num_orders),
+ NULL, CMD_SKIP_TO_ORDER | CMD_MSG(_ctrl_pressed ? STR_CAN_T_SKIP_TO_ORDER : STR_CAN_T_SKIP_ORDER));
+ }
+
+ /**
+ * Handle the click on the unload button.
+ *
+ * @param w current window
+ */
+ static void OrderClick_Delete(OrdersWindow *w, int i)
+ {
+ DoCommandP(w->vehicle->tile, w->vehicle->index, w->OrderGetSel(), NULL, CMD_DELETE_ORDER | CMD_MSG(STR_8834_CAN_T_DELETE_THIS_ORDER));
+ }
+
+ /**
+ * Handle the click on the refit button.
+ * If ctrl is pressed cancel refitting.
+ * Else show the refit window.
+ *
+ * @param w current window
+ */
+ static void OrderClick_Refit(OrdersWindow *w, int i)
+ {
+ if (_ctrl_pressed) {
+ /* Cancel refitting */
+ DoCommandP(w->vehicle->tile, w->vehicle->index, (w->OrderGetSel() << 16) | (CT_NO_REFIT << 8) | CT_NO_REFIT, NULL, CMD_ORDER_REFIT);
+ } else {
+ ShowVehicleRefitWindow(w->vehicle, w->OrderGetSel());
+ }
+ }
+ typedef void Handler(OrdersWindow*, int);
+ struct KeyToEvent {
+ uint16 keycode;
+ Handler *proc;
+ };
+
+public:
+ OrdersWindow(const WindowDesc *desc, const Vehicle *v) : Window(desc, v->index)
+ {
+ this->caption_color = v->owner;
+ this->vscroll.cap = 6;
+ this->resize.step_height = 10;
+ this->selected_order = -1;
+ this->vehicle = v;
+ if (_patches.timetabling) {
+ this->widget[ORDER_WIDGET_CAPTION].right -= 61;
+ } else {
+ this->HideWidget(ORDER_WIDGET_TIMETABLE_VIEW);
+ }
+ this->FindWindowPlacementAndResize(desc);
+ }
+
+ virtual void OnPaint()
+ {
+ bool shared_orders = this->vehicle->IsOrderListShared();
+
+ SetVScrollCount(this, this->vehicle->num_orders + 1);
+
+ int sel = OrderGetSel();
+ const Order *order = GetVehicleOrder(this->vehicle, sel);
+
+ if (this->vehicle->owner == _local_player) {
+ /* Set the strings for the dropdown boxes. */
+ this->widget[ORDER_WIDGET_NON_STOP].data = _order_non_stop_drowdown[order == NULL ? 0 : order->GetNonStopType()];
+ this->widget[ORDER_WIDGET_FULL_LOAD].data = _order_full_load_drowdown[order == NULL ? 0 : order->GetLoadType()];
+ this->widget[ORDER_WIDGET_UNLOAD].data = _order_unload_drowdown[order == NULL ? 0 : order->GetUnloadType()];
+ this->widget[ORDER_WIDGET_COND_VARIABLE].data = _order_conditional_variable[order == NULL ? 0 : order->GetConditionVariable()];
+ this->widget[ORDER_WIDGET_COND_COMPARATOR].data = _order_conditional_condition[order == NULL ? 0 : order->GetConditionComparator()];
+
+ /* skip */
+ this->SetWidgetDisabledState(ORDER_WIDGET_SKIP, this->vehicle->num_orders <= 1);
+
+ /* delete */
+ this->SetWidgetDisabledState(ORDER_WIDGET_DELETE,
+ (uint)this->vehicle->num_orders + ((shared_orders || this->vehicle->num_orders != 0) ? 1 : 0) <= (uint)this->selected_order);
+
+ /* non-stop only for trains */
+ this->SetWidgetDisabledState(ORDER_WIDGET_NON_STOP, (this->vehicle->type != VEH_TRAIN && this->vehicle->type != VEH_ROAD) || order == NULL);
+ this->SetWidgetDisabledState(ORDER_WIDGET_FULL_LOAD, order == NULL || (order->GetNonStopType() & ONSF_NO_STOP_AT_DESTINATION_STATION) != 0); // full load
+ this->SetWidgetDisabledState(ORDER_WIDGET_UNLOAD, order == NULL || (order->GetNonStopType() & ONSF_NO_STOP_AT_DESTINATION_STATION) != 0); // unload
+ /* Disable list of vehicles with the same shared orders if there is no list */
+ this->SetWidgetDisabledState(ORDER_WIDGET_SHARED_ORDER_LIST, !shared_orders || this->vehicle->orders == NULL);
+ this->SetWidgetDisabledState(ORDER_WIDGET_REFIT, order == NULL); // Refit
+ this->SetWidgetDisabledState(ORDER_WIDGET_SERVICE, order == NULL); // Refit
+ this->HideWidget(ORDER_WIDGET_REFIT); // Refit
+ this->HideWidget(ORDER_WIDGET_SERVICE); // Service
+
+ this->HideWidget(ORDER_WIDGET_COND_VARIABLE);
+ this->HideWidget(ORDER_WIDGET_COND_COMPARATOR);
+ this->HideWidget(ORDER_WIDGET_COND_VALUE);
+ }
+
+ this->ShowWidget(ORDER_WIDGET_NON_STOP);
+ this->ShowWidget(ORDER_WIDGET_UNLOAD);
+ this->ShowWidget(ORDER_WIDGET_FULL_LOAD);
+
+ if (order != NULL) {
+ switch (order->GetType()) {
+ case OT_GOTO_STATION:
+ if (!GetStation(order->GetDestination())->IsBuoy()) break;
+ /* Fall-through */
+
+ case OT_GOTO_WAYPOINT:
+ this->DisableWidget(ORDER_WIDGET_FULL_LOAD);
+ this->DisableWidget(ORDER_WIDGET_UNLOAD);
break;
- case ORDER_WIDGET_GOTO_DROPDOWN:
- ShowDropDownMenu(w, v->type == VEH_AIRCRAFT ? _order_goto_dropdown_aircraft : _order_goto_dropdown, 0, ORDER_WIDGET_GOTO, 0, 0, w->widget[ORDER_WIDGET_GOTO_DROPDOWN].right - w->widget[ORDER_WIDGET_GOTO].left);
- break;
-
- case ORDER_WIDGET_FULL_LOAD:
- ShowDropDownMenu(w, _order_full_load_drowdown, GetVehicleOrder(v, OrderGetSel(w))->GetLoadType(), ORDER_WIDGET_FULL_LOAD, 0, 2);
- break;
-
- case ORDER_WIDGET_UNLOAD:
- ShowDropDownMenu(w, _order_unload_drowdown, GetVehicleOrder(v, OrderGetSel(w))->GetUnloadType(), ORDER_WIDGET_UNLOAD, 0, 8);
- break;
-
- case ORDER_WIDGET_REFIT:
- OrderClick_Refit(w, v, 0);
- break;
-
- case ORDER_WIDGET_SERVICE:
- OrderClick_Service(w, v, 0);
- break;
-
- case ORDER_WIDGET_TIMETABLE_VIEW:
- ShowTimetableWindow(v);
- break;
-
- case ORDER_WIDGET_COND_VARIABLE:
- ShowDropDownMenu(w, _order_conditional_variable, GetVehicleOrder(v, OrderGetSel(w))->GetConditionVariable(), ORDER_WIDGET_COND_VARIABLE, 0, 0);
- break;
-
- case ORDER_WIDGET_COND_COMPARATOR: {
- const Order *o = GetVehicleOrder(v, OrderGetSel(w));
- ShowDropDownMenu(w, _order_conditional_condition, o->GetConditionComparator(), ORDER_WIDGET_COND_COMPARATOR, 0, (o->GetConditionVariable() == OCV_REQUIRES_SERVICE) ? 0x3F : 0xC0);
- } break;
-
- case ORDER_WIDGET_COND_VALUE: {
- const Order *order = GetVehicleOrder(v, OrderGetSel(w));
- uint value = order->GetConditionValue();
- if (order->GetConditionVariable() == OCV_MAX_SPEED) value = ConvertSpeedToDisplaySpeed(value);
- SetDParam(0, value);
- ShowQueryString(STR_CONFIG_PATCHES_INT32, STR_ORDER_CONDITIONAL_VALUE_CAPT, 5, 100, w, CS_NUMERAL);
- } break;
-
- case ORDER_WIDGET_SHARED_ORDER_LIST:
- ShowVehicleListWindow(v);
- break;
- }
- break;
+ case OT_GOTO_DEPOT:
+ this->DisableWidget(ORDER_WIDGET_FULL_LOAD);
- case WE_ON_EDIT_TEXT:
- if (!StrEmpty(e->we.edittext.str)) {
- VehicleOrderID sel = OrderGetSel(w);
- uint value = atoi(e->we.edittext.str);
-
- switch (GetVehicleOrder(v, sel)->GetConditionVariable()) {
- case OCV_MAX_SPEED:
- value = ConvertDisplaySpeedToSpeed(value);
- break;
-
- case OCV_RELIABILITY:
- case OCV_LOAD_PERCENTAGE:
- value = Clamp(value, 0, 100);
-
- default:
- break;
- }
- DoCommandP(v->tile, v->index + (sel << 16), MOF_COND_VALUE | Clamp(value, 0, 2047) << 4, NULL, CMD_MODIFY_ORDER | CMD_MSG(STR_8835_CAN_T_MODIFY_THIS_ORDER));
- }
- break;
-
- case WE_DROPDOWN_SELECT: // we have selected a dropdown item in the list
- switch (e->we.dropdown.button) {
- case ORDER_WIDGET_NON_STOP:
- OrderClick_Nonstop(w, v, e->we.dropdown.index);
- break;
-
- case ORDER_WIDGET_FULL_LOAD:
- OrderClick_FullLoad(w, v, e->we.dropdown.index);
- break;
-
- case ORDER_WIDGET_UNLOAD:
- OrderClick_Unload(w, v, e->we.dropdown.index);
- break;
-
- case ORDER_WIDGET_GOTO:
- switch (e->we.dropdown.index) {
- case 0:
- w->ToggleWidgetLoweredState(ORDER_WIDGET_GOTO);
- OrderClick_Goto(w, v, 0);
- break;
-
- case 1: OrderClick_NearestDepot(w, v, 0); break;
- case 2: OrderClick_Conditional(w, v, 0); break;
- default: NOT_REACHED();
- }
- break;
-
- case ORDER_WIDGET_COND_VARIABLE:
- DoCommandP(v->tile, v->index + (OrderGetSel(w) << 16), MOF_COND_VARIABLE | e->we.dropdown.index << 4, NULL, CMD_MODIFY_ORDER | CMD_MSG(STR_8835_CAN_T_MODIFY_THIS_ORDER));
+ /* Remove unload and replace it with refit */
+ this->HideWidget(ORDER_WIDGET_UNLOAD);
+ this->ShowWidget(ORDER_WIDGET_REFIT);
+ this->HideWidget(ORDER_WIDGET_FULL_LOAD);
+ this->ShowWidget(ORDER_WIDGET_SERVICE);
break;
- case ORDER_WIDGET_COND_COMPARATOR:
- DoCommandP(v->tile, v->index + (OrderGetSel(w) << 16), MOF_COND_COMPARATOR | e->we.dropdown.index << 4, NULL, CMD_MODIFY_ORDER | CMD_MSG(STR_8835_CAN_T_MODIFY_THIS_ORDER));
- break;
- }
- break;
+ case OT_CONDITIONAL: {
+ this->HideWidget(ORDER_WIDGET_NON_STOP);
+ this->HideWidget(ORDER_WIDGET_UNLOAD);
+ this->HideWidget(ORDER_WIDGET_FULL_LOAD);
+ this->ShowWidget(ORDER_WIDGET_COND_VARIABLE);
+ this->ShowWidget(ORDER_WIDGET_COND_COMPARATOR);
+ this->ShowWidget(ORDER_WIDGET_COND_VALUE);
- case WE_DRAGDROP:
- switch (e->we.click.widget) {
- case ORDER_WIDGET_ORDER_LIST: {
- int from_order = OrderGetSel(w);
- int to_order = GetOrderFromOrderWndPt(w, e->we.dragdrop.pt.y, v);
+ OrderConditionVariable ocv = order->GetConditionVariable();
+ this->SetWidgetDisabledState(ORDER_WIDGET_COND_COMPARATOR, ocv == OCV_UNCONDITIONALLY);
+ this->SetWidgetDisabledState(ORDER_WIDGET_COND_VALUE, ocv == OCV_REQUIRES_SERVICE || ocv == OCV_UNCONDITIONALLY);
- if (!(from_order == to_order || from_order == INVALID_ORDER || from_order > v->num_orders || to_order == INVALID_ORDER || to_order > v->num_orders) &&
- DoCommandP(v->tile, v->index, from_order | (to_order << 16), NULL, CMD_MOVE_ORDER | CMD_MSG(STR_CAN_T_MOVE_THIS_ORDER))) {
- WP(w, order_d).sel = -1;
+ uint value = order->GetConditionValue();
+ if (order->GetConditionVariable() == OCV_MAX_SPEED) value = ConvertSpeedToDisplaySpeed(value);
+ SetDParam(1, value);
+ } break;
+
+ default: // every other orders
+ this->DisableWidget(ORDER_WIDGET_NON_STOP);
+ this->DisableWidget(ORDER_WIDGET_FULL_LOAD);
+ this->DisableWidget(ORDER_WIDGET_UNLOAD);
+ }
+ }
+
+ SetDParam(0, this->vehicle->index);
+ this->DrawWidgets();
+
+ int y = 15;
+
+ int i = this->vscroll.pos;
+ order = GetVehicleOrder(this->vehicle, i);
+ StringID str;
+ while (order != NULL) {
+ /* Don't draw anything if it extends past the end of the window. */
+ if (i - this->vscroll.pos >= this->vscroll.cap) break;
+
+ DrawOrderString(this->vehicle, order, i, y, i == this->selected_order, false);
+ y += 10;
+
+ i++;
+ order = order->next;
+ }
+
+ if (i - this->vscroll.pos < this->vscroll.cap) {
+ str = shared_orders ? STR_END_OF_SHARED_ORDERS : STR_882A_END_OF_ORDERS;
+ DrawString(2, y, str, (i == this->selected_order) ? TC_WHITE : TC_BLACK);
+ }
+ }
+
+ virtual void OnClick(Point pt, int widget)
+ {
+ if (this->widget[widget].type != WWT_DROPDOWN) HideDropDownMenu(this);
+ switch (widget) {
+ case ORDER_WIDGET_ORDER_LIST: {
+ ResetObjectToPlace();
+
+ int sel = this->GetOrderFromPt(pt.y);
+
+ if (sel == INVALID_ORDER) {
+ /* This was a click on an empty part of the orders window, so
+ * deselect the currently selected order. */
+ this->selected_order = -1;
+ this->SetDirty();
+ return;
+ }
+
+ if (_ctrl_pressed && sel < this->vehicle->num_orders) {
+ const Order *ord = GetVehicleOrder(this->vehicle, sel);
+ TileIndex xy;
+
+ switch (ord->GetType()) {
+ case OT_GOTO_STATION: xy = GetStation(ord->GetDestination())->xy ; break;
+ case OT_GOTO_DEPOT: xy = (this->vehicle->type == VEH_AIRCRAFT) ? GetStation(ord->GetDestination())->xy : GetDepot(ord->GetDestination())->xy; break;
+ case OT_GOTO_WAYPOINT: xy = GetWaypoint(ord->GetDestination())->xy; break;
+ default: xy = 0; break;
}
- } break;
+ if (xy != 0) ScrollMainWindowToTile(xy);
+ return;
+ } else {
+ if (sel == this->selected_order) {
+ /* Deselect clicked order */
+ this->selected_order = -1;
+ } else {
+ /* Select clicked order */
+ this->selected_order = sel;
- case ORDER_WIDGET_DELETE:
- OrderClick_Delete(w, v, 0);
+ if (this->vehicle->owner == _local_player) {
+ /* Activate drag and drop */
+ SetObjectToPlaceWnd(SPR_CURSOR_MOUSE, PAL_NONE, VHM_DRAG, this);
+ }
+ }
+ }
+
+ this->SetDirty();
+ } break;
+
+ case ORDER_WIDGET_SKIP:
+ OrderClick_Skip(this, 0);
+ break;
+
+ case ORDER_WIDGET_DELETE:
+ OrderClick_Delete(this, 0);
+ break;
+
+ case ORDER_WIDGET_NON_STOP: {
+ const Order *o = GetVehicleOrder(this->vehicle, this->OrderGetSel());
+ ShowDropDownMenu(this, _order_non_stop_drowdown, o->GetNonStopType(), ORDER_WIDGET_NON_STOP, 0, o->IsType(OT_GOTO_STATION) ? 0 : (o->IsType(OT_GOTO_WAYPOINT) ? 3 : 12));
+ } break;
+
+ case ORDER_WIDGET_GOTO:
+ OrderClick_Goto(this, 0);
+ break;
+
+ case ORDER_WIDGET_GOTO_DROPDOWN:
+ ShowDropDownMenu(this, this->vehicle->type == VEH_AIRCRAFT ? _order_goto_dropdown_aircraft : _order_goto_dropdown, 0, ORDER_WIDGET_GOTO, 0, 0, this->widget[ORDER_WIDGET_GOTO_DROPDOWN].right - this->widget[ORDER_WIDGET_GOTO].left);
+ break;
+
+ case ORDER_WIDGET_FULL_LOAD:
+ ShowDropDownMenu(this, _order_full_load_drowdown, GetVehicleOrder(this->vehicle, this->OrderGetSel())->GetLoadType(), ORDER_WIDGET_FULL_LOAD, 0, 2);
+ break;
+
+ case ORDER_WIDGET_UNLOAD:
+ ShowDropDownMenu(this, _order_unload_drowdown, GetVehicleOrder(this->vehicle, this->OrderGetSel())->GetUnloadType(), ORDER_WIDGET_UNLOAD, 0, 8);
+ break;
+
+ case ORDER_WIDGET_REFIT:
+ OrderClick_Refit(this, 0);
+ break;
+
+ case ORDER_WIDGET_SERVICE:
+ OrderClick_Service(this, 0);
+ break;
+
+ case ORDER_WIDGET_TIMETABLE_VIEW:
+ ShowTimetableWindow(this->vehicle);
+ break;
+
+ case ORDER_WIDGET_COND_VARIABLE:
+ ShowDropDownMenu(this, _order_conditional_variable, GetVehicleOrder(this->vehicle, this->OrderGetSel())->GetConditionVariable(), ORDER_WIDGET_COND_VARIABLE, 0, 0);
+ break;
+
+ case ORDER_WIDGET_COND_COMPARATOR: {
+ const Order *o = GetVehicleOrder(this->vehicle, this->OrderGetSel());
+ ShowDropDownMenu(this, _order_conditional_condition, o->GetConditionComparator(), ORDER_WIDGET_COND_COMPARATOR, 0, (o->GetConditionVariable() == OCV_REQUIRES_SERVICE) ? 0x3F : 0xC0);
+ } break;
+
+ case ORDER_WIDGET_COND_VALUE: {
+ const Order *order = GetVehicleOrder(this->vehicle, this->OrderGetSel());
+ uint value = order->GetConditionValue();
+ if (order->GetConditionVariable() == OCV_MAX_SPEED) value = ConvertSpeedToDisplaySpeed(value);
+ SetDParam(0, value);
+ ShowQueryString(STR_CONFIG_PATCHES_INT32, STR_ORDER_CONDITIONAL_VALUE_CAPT, 5, 100, this, CS_NUMERAL);
+ } break;
+
+ case ORDER_WIDGET_SHARED_ORDER_LIST:
+ ShowVehicleListWindow(this->vehicle);
+ break;
+ }
+ }
+
+ virtual void OnQueryTextFinished(char *str)
+ {
+ if (!StrEmpty(str)) {
+ VehicleOrderID sel = this->OrderGetSel();
+ uint value = atoi(str);
+
+ switch (GetVehicleOrder(this->vehicle, sel)->GetConditionVariable()) {
+ case OCV_MAX_SPEED:
+ value = ConvertDisplaySpeedToSpeed(value);
+ break;
+
+ case OCV_RELIABILITY:
+ case OCV_LOAD_PERCENTAGE:
+ value = Clamp(value, 0, 100);
+
+ default:
break;
}
-
- ResetObjectToPlace();
- break;
+ DoCommandP(this->vehicle->tile, this->vehicle->index + (sel << 16), MOF_COND_VALUE | Clamp(value, 0, 2047) << 4, NULL, CMD_MODIFY_ORDER | CMD_MSG(STR_8835_CAN_T_MODIFY_THIS_ORDER));
+ }
+ }
- case WE_KEYPRESS:
- if (v->owner != _local_player) break;
+ virtual void OnDropdownSelect(int widget, int index)
+ {
+ switch (widget) {
+ case ORDER_WIDGET_NON_STOP:
+ OrderClick_Nonstop(this, index);
+ break;
- for (uint i = 0; i < lengthof(_order_keycodes); i++) {
- if (e->we.keypress.keycode == _order_keycodes[i]) {
- e->we.keypress.cont = false;
- /* see if the button is disabled */
- if (!w->IsWidgetDisabled(i + ORDER_WIDGET_SKIP)) _order_button_proc[i](w, v, -1);
- break;
+ case ORDER_WIDGET_FULL_LOAD:
+ OrderClick_FullLoad(this, index);
+ break;
+
+ case ORDER_WIDGET_UNLOAD:
+ OrderClick_Unload(this, index);
+ break;
+
+ case ORDER_WIDGET_GOTO:
+ switch (index) {
+ case 0:
+ this->ToggleWidgetLoweredState(ORDER_WIDGET_GOTO);
+ OrderClick_Goto(this, 0);
+ break;
+
+ case 1: OrderClick_NearestDepot(this, 0); break;
+ case 2: OrderClick_Conditional(this, 0); break;
+ default: NOT_REACHED();
+ }
+ break;
+
+ case ORDER_WIDGET_COND_VARIABLE:
+ DoCommandP(this->vehicle->tile, this->vehicle->index + (this->OrderGetSel() << 16), MOF_COND_VARIABLE | index << 4, NULL, CMD_MODIFY_ORDER | CMD_MSG(STR_8835_CAN_T_MODIFY_THIS_ORDER));
+ break;
+
+ case ORDER_WIDGET_COND_COMPARATOR:
+ DoCommandP(this->vehicle->tile, this->vehicle->index + (this->OrderGetSel() << 16), MOF_COND_COMPARATOR | index << 4, NULL, CMD_MODIFY_ORDER | CMD_MSG(STR_8835_CAN_T_MODIFY_THIS_ORDER));
+ break;
+ }
+ }
+
+ virtual void OnDragDrop(Point pt, int widget)
+ {
+ switch (widget) {
+ case ORDER_WIDGET_ORDER_LIST: {
+ int from_order = this->OrderGetSel();
+ int to_order = this->GetOrderFromPt(pt.y);
+
+ if (!(from_order == to_order || from_order == INVALID_ORDER || from_order > this->vehicle->num_orders || to_order == INVALID_ORDER || to_order > this->vehicle->num_orders) &&
+ DoCommandP(this->vehicle->tile, this->vehicle->index, from_order | (to_order << 16), NULL, CMD_MOVE_ORDER | CMD_MSG(STR_CAN_T_MOVE_THIS_ORDER))) {
+ this->selected_order = -1;
+ }
+ } break;
+
+ case ORDER_WIDGET_DELETE:
+ OrderClick_Delete(this, 0);
+ break;
+ }
+
+ ResetObjectToPlace();
+ }
+
+ virtual EventState OnKeyPress(uint16 key, uint16 keycode)
+ {
+ static const KeyToEvent keytoevent[] = {
+ {'D', OrderClick_Skip},
+ {'F', OrderClick_Delete},
+ {'G', OrderClick_Goto},
+ {'H', OrderClick_Nonstop},
+ {'J', OrderClick_FullLoad},
+ {'K', OrderClick_Unload},
+ //{'?', OrderClick_Transfer},
+ //('?', OrderClick_Service},
+ };
+
+ if (this->vehicle->owner != _local_player) return ES_NOT_HANDLED;
+
+ for (uint i = 0; i < lengthof(keytoevent); i++) {
+ if (keycode == keytoevent[i].keycode) {
+ keytoevent[i].proc(this, -1);
+ return ES_HANDLED;
+ }
+ }
+ return ES_NOT_HANDLED;
+ }
+
+ virtual void OnPlaceObject(Point pt, TileIndex tile)
+ {
+ if (this->goto_type == OPOS_GOTO) {
+ /* check if we're clicking on a vehicle first.. clone orders in that case. */
+ const Vehicle *v = CheckMouseOverVehicle();
+ if (v != NULL && this->HandleOrderVehClick(v)) return;
+
+ const Order cmd = GetOrderCmdFromTile(this->vehicle, tile);
+ if (!cmd.IsValid()) return;
+
+ if (DoCommandP(this->vehicle->tile, this->vehicle->index + (this->OrderGetSel() << 16), cmd.Pack(), NULL, CMD_INSERT_ORDER | CMD_MSG(STR_8833_CAN_T_INSERT_NEW_ORDER))) {
+ if (this->selected_order != -1) this->selected_order++;
+ ResetObjectToPlace();
+ }
+ }
+ }
+
+ virtual void OnPlaceObjectAbort()
+ {
+ if (this->goto_type == OPOS_CONDITIONAL) {
+ this->goto_type = OPOS_GOTO;
+ if (_cursor.pos.x >= (this->left + this->widget[ORDER_WIDGET_ORDER_LIST].left) &&
+ _cursor.pos.y >= (this->top + this->widget[ORDER_WIDGET_ORDER_LIST].top) &&
+ _cursor.pos.x <= (this->left + this->widget[ORDER_WIDGET_ORDER_LIST].right) &&
+ _cursor.pos.y <= (this->top + this->widget[ORDER_WIDGET_ORDER_LIST].bottom)) {
+ int order_id = this->GetOrderFromPt(_cursor.pos.y - this->top);
+ if (order_id != INVALID_ORDER) {
+ Order order;
+ order.next = NULL;
+ order.index = 0;
+ order.MakeConditional(order_id);
+
+ DoCommandP(this->vehicle->tile, this->vehicle->index + (this->OrderGetSel() << 16), order.Pack(), NULL, CMD_INSERT_ORDER | CMD_MSG(STR_8833_CAN_T_INSERT_NEW_ORDER));
}
}
- break;
-
- case WE_PLACE_OBJ:
- if (WP(w, order_d).goto_type == OPOS_GOTO) {
- OrdersPlaceObj(GetVehicle(w->window_number), e->we.place.tile, w);
- }
- break;
-
- case WE_ABORT_PLACE_OBJ:
- if (WP(w, order_d).goto_type == OPOS_CONDITIONAL) {
- WP(w, order_d).goto_type = OPOS_GOTO;
- if (_cursor.pos.x >= (w->left + w->widget[ORDER_WIDGET_ORDER_LIST].left) &&
- _cursor.pos.y >= (w->top + w->widget[ORDER_WIDGET_ORDER_LIST].top) &&
- _cursor.pos.x <= (w->left + w->widget[ORDER_WIDGET_ORDER_LIST].right) &&
- _cursor.pos.y <= (w->top + w->widget[ORDER_WIDGET_ORDER_LIST].bottom)) {
- int order_id = GetOrderFromOrderWndPt(w, _cursor.pos.y - w->top, v);
- if (order_id != INVALID_ORDER) {
- Order order;
- order.next = NULL;
- order.index = 0;
- order.MakeConditional(order_id);
-
- DoCommandP(v->tile, v->index + (OrderGetSel(w) << 16), order.Pack(), NULL, CMD_INSERT_ORDER | CMD_MSG(STR_8833_CAN_T_INSERT_NEW_ORDER));
- }
- }
- }
- w->RaiseWidget(ORDER_WIDGET_GOTO);
- w->InvalidateWidget(ORDER_WIDGET_GOTO);
- break;
+ }
+ this->RaiseWidget(ORDER_WIDGET_GOTO);
+ this->InvalidateWidget(ORDER_WIDGET_GOTO);
+ }
- /* check if a vehicle in a depot was clicked.. */
- case WE_MOUSELOOP:
- v = _place_clicked_vehicle;
- /*
- * Check if we clicked on a vehicle
- * and if the GOTO button of this window is pressed
- * This is because of all open order windows WE_MOUSELOOP is called
- * and if you have 3 windows open, and this check is not done
- * the order is copied to the last open window instead of the
- * one where GOTO is enabled
- */
- if (v != NULL && w->IsWidgetLowered(ORDER_WIDGET_GOTO)) {
- _place_clicked_vehicle = NULL;
- HandleOrderVehClick(GetVehicle(w->window_number), v, w);
+ virtual void OnMouseLoop()
+ {
+ const Vehicle *v = _place_clicked_vehicle;
+ /*
+ * Check if we clicked on a vehicle
+ * and if the GOTO button of this window is pressed
+ * This is because of all open order windows WE_MOUSELOOP is called
+ * and if you have 3 windows open, and this check is not done
+ * the order is copied to the last open window instead of the
+ * one where GOTO is enabled
+ */
+ if (v != NULL && this->IsWidgetLowered(ORDER_WIDGET_GOTO)) {
+ _place_clicked_vehicle = NULL;
+ this->HandleOrderVehClick(v);
+ }
+ }
+
+ virtual void OnResize(Point new_size, Point delta)
+ {
+ /* Update the scroll + matrix */
+ this->vscroll.cap = (this->widget[ORDER_WIDGET_ORDER_LIST].bottom - this->widget[ORDER_WIDGET_ORDER_LIST].top) / 10;
+ }
+
+ virtual void OnTimeout()
+ {
+ /* unclick all buttons except for the 'goto' button (ORDER_WIDGET_GOTO), which is 'persistent' */
+ for (uint i = 0; i < this->widget_count; i++) {
+ if (this->IsWidgetLowered(i) && i != ORDER_WIDGET_GOTO) {
+ this->RaiseWidget(i);
+ this->InvalidateWidget(i);
}
- break;
-
- case WE_RESIZE:
- /* Update the scroll + matrix */
- w->vscroll.cap = (w->widget[ORDER_WIDGET_ORDER_LIST].bottom - w->widget[ORDER_WIDGET_ORDER_LIST].top) / 10;
- break;
-
- case WE_TIMEOUT: // handle button unclick ourselves...
- /* unclick all buttons except for the 'goto' button (ORDER_WIDGET_GOTO), which is 'persistent' */
- for (uint i = 0; i < w->widget_count; i++) {
- if (w->IsWidgetLowered(i) && i != ORDER_WIDGET_GOTO) {
- w->RaiseWidget(i);
- w->InvalidateWidget(i);
- }
- }
- break;
+ }
}
-}
+};
/**
* Widget definition for player train orders
@@ -1091,7 +1063,6 @@
WC_VEHICLE_ORDERS, WC_VEHICLE_VIEW,
WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_RESIZABLE,
_orders_train_widgets,
- OrdersWndProc
};
/**
@@ -1132,7 +1103,6 @@
WC_VEHICLE_ORDERS, WC_VEHICLE_VIEW,
WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_RESIZABLE,
_orders_widgets,
- OrdersWndProc
};
/**
@@ -1173,27 +1143,18 @@
WC_VEHICLE_ORDERS, WC_VEHICLE_VIEW,
WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS | WDF_RESIZABLE,
_other_orders_widgets,
- OrdersWndProc
};
void ShowOrdersWindow(const Vehicle *v)
{
- Window *w;
VehicleID veh = v->index;
DeleteWindowById(WC_VEHICLE_ORDERS, veh);
DeleteWindowById(WC_VEHICLE_DETAILS, veh);
if (v->owner != _local_player) {
- w = AllocateWindowDescFront<Window>(&_other_orders_desc, veh);
+ new OrdersWindow(&_other_orders_desc, v);
} else {
- w = AllocateWindowDescFront<Window>((v->type == VEH_TRAIN || v->type == VEH_ROAD) ? &_orders_train_desc : &_orders_desc, veh);
- }
-
- if (w != NULL) {
- w->caption_color = v->owner;
- w->vscroll.cap = 6;
- w->resize.step_height = 10;
- WP(w, order_d).sel = -1;
+ new OrdersWindow((v->type == VEH_TRAIN || v->type == VEH_ROAD) ? &_orders_train_desc : &_orders_desc, v);
}
}
--- a/src/osk_gui.cpp Mon May 19 14:14:33 2008 +0000
+++ b/src/osk_gui.cpp Mon May 19 15:13:58 2008 +0000
@@ -42,6 +42,7 @@
static byte _keystate = KEYS_NONE;
struct OskWindow : public Window {
+ StringID caption; ///< the caption for this window.
QueryString *qs; ///< text-input
int text_btn; ///< widget number of parent's text field
int ok_btn; ///< widget number of parent's ok button (=0 when ok shouldn't be passed on)
@@ -54,7 +55,7 @@
this->parent = parent;
assert(parent != NULL);
- if (parent->widget[button].data != 0) parent->caption = parent->widget[button].data;
+ this->caption = (parent->widget[button].data != STR_NULL) ? parent->widget[button].data : parent->caption;
this->qs = parent;
this->text_btn = button;
@@ -96,8 +97,8 @@
this->ChangeOskDiabledState(shift);
- SetDParam(0, this->qs->caption);
- DrawWindowWidgets(this);
+ SetDParam(0, this->caption);
+ this->DrawWidgets();
for (uint i = 0; i < OSK_KEYBOARD_ENTRIES; i++) {
DrawCharCentered(_keyboard[shift][i],
@@ -129,6 +130,8 @@
return;
}
+ bool delete_this = false;
+
switch (widget) {
case OSK_WIDGET_BACKSPACE:
if (DeleteTextBufferChar(&this->qs->text, WKC_BACKSPACE)) this->InvalidateWidget(OSK_WIDGET_TEXT);
@@ -169,25 +172,29 @@
/* pass information by simulating a button press on parent window */
if (this->ok_btn != 0) {
this->parent->OnClick(pt, this->ok_btn);
+ /* Window gets deleted when the parent window removes itself. */
+ return;
}
}
- delete this;
+ delete_this = true;
break;
case OSK_WIDGET_CANCEL:
if (this->cancel_btn != 0) { // pass a cancel event to the parent window
this->parent->OnClick(pt, this->cancel_btn);
/* Window gets deleted when the parent window removes itself. */
+ return;
} else { // or reset to original string
strcpy(qs->text.buf, this->orig_str_buf);
UpdateTextBufferSize(&qs->text);
MoveTextBufferPos(&qs->text, WKC_END);
- delete this;
+ delete_this = true;
}
break;
}
/* make sure that the parent window's textbox also gets updated */
if (this->parent != NULL) this->parent->InvalidateWidget(this->text_btn);
+ if (delete_this) delete this;
}
virtual void OnMouseLoop()
@@ -276,12 +283,11 @@
{ WIDGETS_END},
};
-WindowDesc _osk_desc = {
+static const WindowDesc _osk_desc = {
WDP_CENTER, WDP_CENTER, 256, 140, 256, 140,
WC_OSK, WC_NONE,
WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS,
_osk_widgets,
- NULL
};
/**
@@ -339,7 +345,7 @@
}
/**
- * Show the osk associated with a given textbox
+ * Show the on-screen keyboard (osk) associated with a given textbox
* @param parent pointer to the Window where this keyboard originated from
* @param q querystr_d pointer to the query string of the parent, which is
* shared for both windows
--- a/src/player_face.h Mon May 19 14:14:33 2008 +0000
+++ b/src/player_face.h Mon May 19 15:13:58 2008 +0000
@@ -230,6 +230,5 @@
void DrawPlayerFace(PlayerFace face, int color, int x, int y);
PlayerFace ConvertFromOldPlayerFace(uint32 face);
bool IsValidPlayerFace(PlayerFace pf);
-void DrawFaceStringLabel(const Window *w, byte widget_index, StringID str, uint8 val, bool is_bool_widget);
#endif /* PLAYER_FACE_H */
--- a/src/player_gui.cpp Mon May 19 14:14:33 2008 +0000
+++ b/src/player_gui.cpp Mon May 19 15:13:58 2008 +0000
@@ -35,34 +35,21 @@
#include "table/sprites.h"
#include "table/strings.h"
-/* player face selection window */
-struct facesel_d {
- PlayerFace face; // player face bits
- bool advanced; // advance player face selection window
-};
-assert_compile(WINDOW_CUSTOM_SIZE >= sizeof(facesel_d));
-
-struct highscore_d {
- uint32 background_img;
- int8 rank;
-};
-assert_compile(WINDOW_CUSTOM_SIZE >= sizeof(highscore_d));
-
enum {
FIRST_GUI_CALL = INT_MAX, ///< default value to specify thuis is the first call of the resizable gui
};
static void DoShowPlayerFinances(PlayerID player, bool show_small, bool show_stickied, int top = FIRST_GUI_CALL, int left = FIRST_GUI_CALL);
-static void DoSelectPlayerFace(PlayerID player, bool show_big, int top = FIRST_GUI_CALL, int left = FIRST_GUI_CALL);
+static void DoSelectPlayerFace(Window *parent, bool show_big, int top = FIRST_GUI_CALL, int left = FIRST_GUI_CALL);
-static void DrawPlayerEconomyStats(const Player *p, byte mode)
+static void DrawPlayerEconomyStats(const Player *p, bool small)
{
int x, y, i, j, year;
const Money (*tbl)[EXPENSES_END];
Money sum, cost;
StringID str;
- if (!(mode & 1)) { // normal sized economics window (mode&1) is minimized status
+ if (!small) { // normal sized economics window
/* draw categories */
DrawStringCenterUnderline(61, 15, STR_700F_EXPENDITURE_INCOME, TC_FROMSTRING);
for (i = 0; i != EXPENSES_END; i++)
@@ -161,73 +148,88 @@
{ WIDGETS_END},
};
-
-static void PlayerFinancesWndProc(Window *w, WindowEvent *e)
-{
- switch (e->event) {
- case WE_PAINT: {
- PlayerID player = (PlayerID)w->window_number;
- const Player *p = GetPlayer(player);
-
- /* Recheck the size of the window as it might need to be resized due to the local player changing */
- int new_height = ((player != _local_player) ? 0 : 12) + ((WP(w, def_d).data_1 != 0) ? 48 : 74 + 10 * EXPENSES_END);
- if (w->height != new_height) {
- /* Make window dirty before and after resizing */
- w->SetDirty();
- w->height = new_height;
- w->SetDirty();
-
- w->SetWidgetHiddenState(PFW_WIDGET_INCREASE_LOAN, player != _local_player);
- w->SetWidgetHiddenState(PFW_WIDGET_REPAY_LOAN, player != _local_player);
- }
-
- /* Borrow button only shows when there is any more money to loan */
- w->SetWidgetDisabledState(PFW_WIDGET_INCREASE_LOAN, p->current_loan == _economy.max_loan);
+struct PlayerFinancesWindow : Window {
+ bool small;
- /* Repay button only shows when there is any more money to repay */
- w->SetWidgetDisabledState(PFW_WIDGET_REPAY_LOAN, player != _local_player || p->current_loan == 0);
-
- SetDParam(0, p->index);
- SetDParam(1, p->index);
- SetDParam(2, LOAN_INTERVAL);
- DrawWindowWidgets(w);
-
- DrawPlayerEconomyStats(p, (byte)WP(w, def_d).data_1);
- } break;
+ PlayerFinancesWindow(const WindowDesc *desc, PlayerID player, bool show_small,
+ bool show_stickied, int top, int left) :
+ Window(desc, player),
+ small(show_small)
+ {
+ this->caption_color = this->window_number;
- case WE_CLICK:
- switch (e->we.click.widget) {
- case PFW_WIDGET_TOGGLE_SIZE: {/* toggle size */
- byte mode = (byte)WP(w, def_d).data_1;
- bool stickied = !!(w->flags4 & WF_STICKY);
- int oldtop = w->top; ///< current top position of the window before closing it
- int oldleft = w->left; ///< current left position of the window before closing it
- PlayerID player = (PlayerID)w->window_number;
+ if (show_stickied) this->flags4 |= WF_STICKY;
- delete w;
- /* Open up the (toggled size) Finance window at the same position as the previous */
- DoShowPlayerFinances(player, !HasBit(mode, 0), stickied, oldtop, oldleft);
- }
+ /* Check if repositioning from default is required */
+ if (top != FIRST_GUI_CALL && left != FIRST_GUI_CALL) {
+ this->top = top;
+ this->left = left;
+ }
+ }
+
+ virtual void OnPaint()
+ {
+ PlayerID player = (PlayerID)this->window_number;
+ const Player *p = GetPlayer(player);
+
+ /* Recheck the size of the window as it might need to be resized due to the local player changing */
+ int new_height = ((player != _local_player) ? 0 : 12) + ((this->small != 0) ? 48 : 74 + 10 * EXPENSES_END);
+ if (this->height != new_height) {
+ /* Make window dirty before and after resizing */
+ this->SetDirty();
+ this->height = new_height;
+ this->SetDirty();
+
+ this->SetWidgetHiddenState(PFW_WIDGET_INCREASE_LOAN, player != _local_player);
+ this->SetWidgetHiddenState(PFW_WIDGET_REPAY_LOAN, player != _local_player);
+ }
+
+ /* Borrow button only shows when there is any more money to loan */
+ this->SetWidgetDisabledState(PFW_WIDGET_INCREASE_LOAN, p->current_loan == _economy.max_loan);
+
+ /* Repay button only shows when there is any more money to repay */
+ this->SetWidgetDisabledState(PFW_WIDGET_REPAY_LOAN, player != _local_player || p->current_loan == 0);
+
+ SetDParam(0, p->index);
+ SetDParam(1, p->index);
+ SetDParam(2, LOAN_INTERVAL);
+ this->DrawWidgets();
+
+ DrawPlayerEconomyStats(p, this->small);
+ }
+
+ virtual void OnClick(Point pt, int widget)
+ {
+ switch (widget) {
+ case PFW_WIDGET_TOGGLE_SIZE: {/* toggle size */
+ bool new_mode = !this->small;
+ bool stickied = !!(this->flags4 & WF_STICKY);
+ int oldtop = this->top; ///< current top position of the window before closing it
+ int oldleft = this->left; ///< current left position of the window before closing it
+ PlayerID player = (PlayerID)this->window_number;
+
+ delete this;
+ /* Open up the (toggled size) Finance window at the same position as the previous */
+ DoShowPlayerFinances(player, new_mode, stickied, oldtop, oldleft);
+ }
+ break;
+
+ case PFW_WIDGET_INCREASE_LOAN: /* increase loan */
+ DoCommandP(0, 0, _ctrl_pressed, NULL, CMD_INCREASE_LOAN | CMD_MSG(STR_702C_CAN_T_BORROW_ANY_MORE_MONEY));
break;
- case PFW_WIDGET_INCREASE_LOAN: /* increase loan */
- DoCommandP(0, 0, _ctrl_pressed, NULL, CMD_INCREASE_LOAN | CMD_MSG(STR_702C_CAN_T_BORROW_ANY_MORE_MONEY));
- break;
-
- case PFW_WIDGET_REPAY_LOAN: /* repay loan */
- DoCommandP(0, 0, _ctrl_pressed, NULL, CMD_DECREASE_LOAN | CMD_MSG(STR_702F_CAN_T_REPAY_LOAN));
- break;
- }
- break;
+ case PFW_WIDGET_REPAY_LOAN: /* repay loan */
+ DoCommandP(0, 0, _ctrl_pressed, NULL, CMD_DECREASE_LOAN | CMD_MSG(STR_702F_CAN_T_REPAY_LOAN));
+ break;
+ }
}
-}
+};
static const WindowDesc _player_finances_desc = {
WDP_AUTO, WDP_AUTO, 407, 86 + 10 * EXPENSES_END, 407, 86 + 10 * EXPENSES_END,
WC_FINANCES, WC_NONE,
WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS | WDF_STICKY_BUTTON,
_player_finances_widgets,
- PlayerFinancesWndProc
};
static const WindowDesc _player_finances_small_desc = {
@@ -235,7 +237,6 @@
WC_FINANCES, WC_NONE,
WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS | WDF_STICKY_BUTTON,
_player_finances_small_widgets,
- PlayerFinancesWndProc
};
/**
@@ -253,19 +254,8 @@
{
if (!IsValidPlayer(player)) return;
- Window *w = AllocateWindowDescFront<Window>(show_small ? &_player_finances_small_desc : &_player_finances_desc, player);
- if (w != NULL) {
- w->caption_color = w->window_number;
- WP(w, def_d).data_1 = show_small;
-
- if (show_stickied) w->flags4 |= WF_STICKY;
-
- /* Check if repositioning from default is required */
- if (top != FIRST_GUI_CALL && left != FIRST_GUI_CALL) {
- w->top = top;
- w->left = left;
- }
- }
+ if (BringWindowToFrontById(WC_FINANCES, player)) return;
+ new PlayerFinancesWindow(show_small ? &_player_finances_small_desc : &_player_finances_desc, player, show_small, show_stickied, top, left);
}
void ShowPlayerFinances(PlayerID player)
@@ -294,7 +284,7 @@
};
/* Association of liveries to livery classes */
-static const LiveryClass livery_class[LS_END] = {
+static const LiveryClass _livery_class[LS_END] = {
LC_OTHER,
LC_RAIL, LC_RAIL, LC_RAIL, LC_RAIL, LC_RAIL, LC_RAIL, LC_RAIL, LC_RAIL, LC_RAIL, LC_RAIL, LC_RAIL, LC_RAIL, LC_RAIL,
LC_ROAD, LC_ROAD,
@@ -303,34 +293,6 @@
LC_ROAD, LC_ROAD,
};
-/* Number of liveries in each class, used to determine the height of the livery window */
-static const byte livery_height[] = {
- 1,
- 13,
- 4,
- 2,
- 3,
-};
-
-struct livery_d {
- uint32 sel;
- LiveryClass livery_class;
-};
-assert_compile(WINDOW_CUSTOM_SIZE >= sizeof(livery_d));
-
-
-enum PlayerLiveryWindowWidgets {
- PLW_WIDGET_CLASS_GENERAL = 2,
- PLW_WIDGET_CLASS_RAIL,
- PLW_WIDGET_CLASS_ROAD,
- PLW_WIDGET_CLASS_SHIP,
- PLW_WIDGET_CLASS_AIRCRAFT,
-
- PLW_WIDGET_PRI_COL_DROPDOWN = 9,
- PLW_WIDGET_SEC_COL_DROPDOWN,
- PLW_WIDGET_MATRIX,
-};
-
class DropDownListColourItem : public DropDownListItem {
public:
DropDownListColourItem(int result, bool masked) : DropDownListItem(result, masked) {}
@@ -354,168 +316,211 @@
}
};
-static void ShowColourDropDownMenu(Window *w, uint32 widget)
-{
- uint32 used_colours = 0;
- const Livery *livery;
- LiveryScheme scheme;
+struct SelectPlayerLiveryWindow : public Window {
+private:
+ uint32 sel;
+ LiveryClass livery_class;
- /* Disallow other player colours for the primary colour */
- if (HasBit(WP(w, livery_d).sel, LS_DEFAULT) && widget == PLW_WIDGET_PRI_COL_DROPDOWN) {
- const Player *p;
- FOR_ALL_PLAYERS(p) {
- if (p->is_active && p->index != _local_player) SetBit(used_colours, p->player_color);
+ enum PlayerLiveryWindowWidgets {
+ PLW_WIDGET_CLOSE,
+ PLW_WIDGET_CAPTION,
+ PLW_WIDGET_CLASS_GENERAL,
+ PLW_WIDGET_CLASS_RAIL,
+ PLW_WIDGET_CLASS_ROAD,
+ PLW_WIDGET_CLASS_SHIP,
+ PLW_WIDGET_CLASS_AIRCRAFT,
+ PLW_WIDGET_SPACER_CLASS,
+ PLW_WIDGET_SPACER_DROPDOWN,
+ PLW_WIDGET_PRI_COL_DROPDOWN,
+ PLW_WIDGET_SEC_COL_DROPDOWN,
+ PLW_WIDGET_MATRIX,
+ };
+
+ void ShowColourDropDownMenu(uint32 widget)
+ {
+ uint32 used_colours = 0;
+ const Livery *livery;
+ LiveryScheme scheme;
+
+ /* Disallow other player colours for the primary colour */
+ if (HasBit(this->sel, LS_DEFAULT) && widget == PLW_WIDGET_PRI_COL_DROPDOWN) {
+ const Player *p;
+ FOR_ALL_PLAYERS(p) {
+ if (p->is_active && p->index != _local_player) SetBit(used_colours, p->player_color);
+ }
+ }
+
+ /* Get the first selected livery to use as the default dropdown item */
+ for (scheme = LS_BEGIN; scheme < LS_END; scheme++) {
+ if (HasBit(this->sel, scheme)) break;
+ }
+ if (scheme == LS_END) scheme = LS_DEFAULT;
+ livery = &GetPlayer((PlayerID)this->window_number)->livery[scheme];
+
+ DropDownList *list = new DropDownList();
+ for (uint i = 0; i < lengthof(_colour_dropdown); i++) {
+ list->push_back(new DropDownListColourItem(i, HasBit(used_colours, i)));
+ }
+
+ ShowDropDownList(this, list, widget == PLW_WIDGET_PRI_COL_DROPDOWN ? livery->colour1 : livery->colour2, widget);
+ }
+
+public:
+ SelectPlayerLiveryWindow(const WindowDesc *desc, PlayerID player) : Window(desc, player)
+ {
+ this->caption_color = player;
+ this->livery_class = LC_OTHER;
+ this->sel = 1;
+ this->LowerWidget(PLW_WIDGET_CLASS_GENERAL);
+ this->OnInvalidateData(_loaded_newgrf_features.has_2CC);
+ this->FindWindowPlacementAndResize(desc);
+ }
+
+ virtual void OnPaint()
+ {
+ const Player *p = GetPlayer((PlayerID)this->window_number);
+ LiveryScheme scheme = LS_DEFAULT;
+ int y = 51;
+
+ /* Disable dropdown controls if no scheme is selected */
+ this->SetWidgetDisabledState(PLW_WIDGET_PRI_COL_DROPDOWN, this->sel == 0);
+ this->SetWidgetDisabledState(PLW_WIDGET_SEC_COL_DROPDOWN, this->sel == 0);
+
+ if (this->sel != 0) {
+ for (scheme = LS_BEGIN; scheme < LS_END; scheme++) {
+ if (HasBit(this->sel, scheme)) break;
+ }
+ if (scheme == LS_END) scheme = LS_DEFAULT;
+ }
+
+ SetDParam(0, STR_00D1_DARK_BLUE + p->livery[scheme].colour1);
+ SetDParam(1, STR_00D1_DARK_BLUE + p->livery[scheme].colour2);
+
+ this->DrawWidgets();
+
+ for (scheme = LS_DEFAULT; scheme < LS_END; scheme++) {
+ if (_livery_class[scheme] == this->livery_class) {
+ bool sel = HasBit(this->sel, scheme) != 0;
+
+ if (scheme != LS_DEFAULT) {
+ DrawSprite(p->livery[scheme].in_use ? SPR_BOX_CHECKED : SPR_BOX_EMPTY, PAL_NONE, 2, y);
+ }
+
+ DrawString(15, y, STR_LIVERY_DEFAULT + scheme, sel ? TC_WHITE : TC_BLACK);
+
+ DrawSprite(SPR_SQUARE, GENERAL_SPRITE_COLOR(p->livery[scheme].colour1), 152, y);
+ DrawString(165, y, STR_00D1_DARK_BLUE + p->livery[scheme].colour1, sel ? TC_WHITE : TC_GOLD);
+
+ if (!this->IsWidgetHidden(PLW_WIDGET_SEC_COL_DROPDOWN)) {
+ DrawSprite(SPR_SQUARE, GENERAL_SPRITE_COLOR(p->livery[scheme].colour2), 277, y);
+ DrawString(290, y, STR_00D1_DARK_BLUE + p->livery[scheme].colour2, sel ? TC_WHITE : TC_GOLD);
+ }
+
+ y += 14;
+ }
}
}
- /* Get the first selected livery to use as the default dropdown item */
- for (scheme = LS_BEGIN; scheme < LS_END; scheme++) {
- if (HasBit(WP(w, livery_d).sel, scheme)) break;
- }
- if (scheme == LS_END) scheme = LS_DEFAULT;
- livery = &GetPlayer((PlayerID)w->window_number)->livery[scheme];
-
- DropDownList *list = new DropDownList();
- for (uint i = 0; i < lengthof(_colour_dropdown); i++) {
- list->push_back(new DropDownListColourItem(i, HasBit(used_colours, i)));
- }
-
- ShowDropDownList(w, list, widget == PLW_WIDGET_PRI_COL_DROPDOWN ? livery->colour1 : livery->colour2, widget);
-}
+ virtual void OnClick(Point pt, int widget)
+ {
+ /* Number of liveries in each class, used to determine the height of the livery window */
+ static const byte livery_height[] = {
+ 1,
+ 13,
+ 4,
+ 2,
+ 3,
+ };
-static void SelectPlayerLiveryWndProc(Window *w, WindowEvent *e)
-{
- switch (e->event) {
- case WE_CREATE:
- w->LowerWidget(WP(w, livery_d).livery_class + PLW_WIDGET_CLASS_GENERAL);
- if (!_loaded_newgrf_features.has_2CC) {
- w->HideWidget(PLW_WIDGET_SEC_COL_DROPDOWN);
- }
- break;
+ switch (widget) {
+ /* Livery Class buttons */
+ case PLW_WIDGET_CLASS_GENERAL:
+ case PLW_WIDGET_CLASS_RAIL:
+ case PLW_WIDGET_CLASS_ROAD:
+ case PLW_WIDGET_CLASS_SHIP:
+ case PLW_WIDGET_CLASS_AIRCRAFT: {
+ LiveryScheme scheme;
- case WE_PAINT: {
- const Player *p = GetPlayer((PlayerID)w->window_number);
- LiveryScheme scheme = LS_DEFAULT;
- int y = 51;
+ this->RaiseWidget(this->livery_class + PLW_WIDGET_CLASS_GENERAL);
+ this->livery_class = (LiveryClass)(widget - PLW_WIDGET_CLASS_GENERAL);
+ this->sel = 0;
+ this->LowerWidget(this->livery_class + PLW_WIDGET_CLASS_GENERAL);
- /* Disable dropdown controls if no scheme is selected */
- w->SetWidgetDisabledState(PLW_WIDGET_PRI_COL_DROPDOWN, (WP(w, livery_d).sel == 0));
- w->SetWidgetDisabledState(PLW_WIDGET_SEC_COL_DROPDOWN, (WP(w, livery_d).sel == 0));
-
- if (!(WP(w, livery_d).sel == 0)) {
- for (scheme = LS_BEGIN; scheme < LS_END; scheme++) {
- if (HasBit(WP(w, livery_d).sel, scheme)) break;
+ /* Select the first item in the list */
+ for (scheme = LS_DEFAULT; scheme < LS_END; scheme++) {
+ if (_livery_class[scheme] == this->livery_class) {
+ this->sel = 1 << scheme;
+ break;
+ }
}
- if (scheme == LS_END) scheme = LS_DEFAULT;
+ this->height = 49 + livery_height[this->livery_class] * 14;
+ this->widget[PLW_WIDGET_MATRIX].bottom = this->height - 1;
+ this->widget[PLW_WIDGET_MATRIX].data = livery_height[this->livery_class] << 8 | 1;
+ MarkWholeScreenDirty();
+ break;
}
- SetDParam(0, STR_00D1_DARK_BLUE + p->livery[scheme].colour1);
- SetDParam(1, STR_00D1_DARK_BLUE + p->livery[scheme].colour2);
-
- DrawWindowWidgets(w);
-
- for (scheme = LS_DEFAULT; scheme < LS_END; scheme++) {
- if (livery_class[scheme] == WP(w, livery_d).livery_class) {
- bool sel = HasBit(WP(w, livery_d).sel, scheme) != 0;
+ case PLW_WIDGET_PRI_COL_DROPDOWN: /* First colour dropdown */
+ ShowColourDropDownMenu(PLW_WIDGET_PRI_COL_DROPDOWN);
+ break;
- if (scheme != LS_DEFAULT) {
- DrawSprite(p->livery[scheme].in_use ? SPR_BOX_CHECKED : SPR_BOX_EMPTY, PAL_NONE, 2, y);
- }
-
- DrawString(15, y, STR_LIVERY_DEFAULT + scheme, sel ? TC_WHITE : TC_BLACK);
+ case PLW_WIDGET_SEC_COL_DROPDOWN: /* Second colour dropdown */
+ ShowColourDropDownMenu(PLW_WIDGET_SEC_COL_DROPDOWN);
+ break;
- DrawSprite(SPR_SQUARE, GENERAL_SPRITE_COLOR(p->livery[scheme].colour1), 152, y);
- DrawString(165, y, STR_00D1_DARK_BLUE + p->livery[scheme].colour1, sel ? TC_WHITE : TC_GOLD);
+ case PLW_WIDGET_MATRIX: {
+ LiveryScheme scheme;
+ LiveryScheme j = (LiveryScheme)((pt.y - 48) / 14);
- if (_loaded_newgrf_features.has_2CC) {
- DrawSprite(SPR_SQUARE, GENERAL_SPRITE_COLOR(p->livery[scheme].colour2), 277, y);
- DrawString(290, y, STR_00D1_DARK_BLUE + p->livery[scheme].colour2, sel ? TC_WHITE : TC_GOLD);
- }
-
- y += 14;
+ for (scheme = LS_BEGIN; scheme <= j; scheme++) {
+ if (_livery_class[scheme] != this->livery_class) j++;
+ if (scheme >= LS_END) return;
}
- }
- break;
- }
-
- case WE_CLICK: {
- switch (e->we.click.widget) {
- /* Livery Class buttons */
- case PLW_WIDGET_CLASS_GENERAL:
- case PLW_WIDGET_CLASS_RAIL:
- case PLW_WIDGET_CLASS_ROAD:
- case PLW_WIDGET_CLASS_SHIP:
- case PLW_WIDGET_CLASS_AIRCRAFT: {
- LiveryScheme scheme;
+ if (j >= LS_END) return;
- w->RaiseWidget(WP(w, livery_d).livery_class + PLW_WIDGET_CLASS_GENERAL);
- WP(w, livery_d).livery_class = (LiveryClass)(e->we.click.widget - PLW_WIDGET_CLASS_GENERAL);
- WP(w, livery_d).sel = 0;
- w->LowerWidget(WP(w, livery_d).livery_class + PLW_WIDGET_CLASS_GENERAL);
-
- /* Select the first item in the list */
- for (scheme = LS_DEFAULT; scheme < LS_END; scheme++) {
- if (livery_class[scheme] == WP(w, livery_d).livery_class) {
- WP(w, livery_d).sel = 1 << scheme;
- break;
- }
- }
- w->height = 49 + livery_height[WP(w, livery_d).livery_class] * 14;
- w->widget[PLW_WIDGET_MATRIX].bottom = w->height - 1;
- w->widget[PLW_WIDGET_MATRIX].data = livery_height[WP(w, livery_d).livery_class] << 8 | 1;
- MarkWholeScreenDirty();
- break;
+ /* If clicking on the left edge, toggle using the livery */
+ if (pt.x < 10) {
+ DoCommandP(0, j | (2 << 8), !GetPlayer((PlayerID)this->window_number)->livery[j].in_use, NULL, CMD_SET_PLAYER_COLOR);
}
- case PLW_WIDGET_PRI_COL_DROPDOWN: /* First colour dropdown */
- ShowColourDropDownMenu(w, PLW_WIDGET_PRI_COL_DROPDOWN);
- break;
-
- case PLW_WIDGET_SEC_COL_DROPDOWN: /* Second colour dropdown */
- ShowColourDropDownMenu(w, PLW_WIDGET_SEC_COL_DROPDOWN);
- break;
-
- case PLW_WIDGET_MATRIX: {
- LiveryScheme scheme;
- LiveryScheme j = (LiveryScheme)((e->we.click.pt.y - 48) / 14);
-
- for (scheme = LS_BEGIN; scheme <= j; scheme++) {
- if (livery_class[scheme] != WP(w, livery_d).livery_class) j++;
- if (scheme >= LS_END) return;
- }
- if (j >= LS_END) return;
-
- /* If clicking on the left edge, toggle using the livery */
- if (e->we.click.pt.x < 10) {
- DoCommandP(0, j | (2 << 8), !GetPlayer((PlayerID)w->window_number)->livery[j].in_use, NULL, CMD_SET_PLAYER_COLOR);
- }
-
- if (_ctrl_pressed) {
- ToggleBit(WP(w, livery_d).sel, j);
- } else {
- WP(w, livery_d).sel = 1 << j;
- }
- w->SetDirty();
- break;
+ if (_ctrl_pressed) {
+ ToggleBit(this->sel, j);
+ } else {
+ this->sel = 1 << j;
}
+ this->SetDirty();
+ break;
}
- break;
- }
-
- case WE_DROPDOWN_SELECT: {
- LiveryScheme scheme;
-
- for (scheme = LS_DEFAULT; scheme < LS_END; scheme++) {
- if (HasBit(WP(w, livery_d).sel, scheme)) {
- DoCommandP(0, scheme | (e->we.dropdown.button == PLW_WIDGET_PRI_COL_DROPDOWN ? 0 : 256), e->we.dropdown.index, NULL, CMD_SET_PLAYER_COLOR);
- }
- }
- break;
}
}
-}
-static const Widget _select_player_livery_2cc_widgets[] = {
+ virtual void OnDropdownSelect(int widget, int index)
+ {
+ for (LiveryScheme scheme = LS_DEFAULT; scheme < LS_END; scheme++) {
+ if (HasBit(this->sel, scheme)) {
+ DoCommandP(0, scheme | (widget == PLW_WIDGET_PRI_COL_DROPDOWN ? 0 : 256), index, NULL, CMD_SET_PLAYER_COLOR);
+ }
+ }
+ }
+
+ virtual void OnInvalidateData(int data = 0)
+ {
+ static bool has2cc = true;
+
+ if (has2cc == !!data) return;
+
+ has2cc = !!data;
+
+ int r = this->widget[has2cc ? PLW_WIDGET_SEC_COL_DROPDOWN : PLW_WIDGET_PRI_COL_DROPDOWN].right;
+ this->SetWidgetHiddenState(PLW_WIDGET_SEC_COL_DROPDOWN, !has2cc);
+ this->widget[PLW_WIDGET_CAPTION].right = r;
+ this->widget[PLW_WIDGET_SPACER_CLASS].right = r;
+ this->widget[PLW_WIDGET_MATRIX].right = r;
+ this->width = r + 1;
+ }
+};
+
+static const Widget _select_player_livery_widgets[] = {
{ WWT_CLOSEBOX, RESIZE_NONE, 14, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW },
{ WWT_CAPTION, RESIZE_NONE, 14, 11, 399, 0, 13, STR_7007_NEW_COLOR_SCHEME, STR_018C_WINDOW_TITLE_DRAG_THIS },
{ WWT_IMGBTN, RESIZE_NONE, 14, 0, 21, 14, 35, SPR_IMG_COMPANY_GENERAL, STR_LIVERY_GENERAL_TIP },
@@ -531,37 +536,11 @@
{ WIDGETS_END },
};
-static const WindowDesc _select_player_livery_2cc_desc = {
+static const WindowDesc _select_player_livery_desc = {
WDP_AUTO, WDP_AUTO, 400, 49 + 1 * 14, 400, 49 + 1 * 14,
WC_PLAYER_COLOR, WC_NONE,
WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET,
- _select_player_livery_2cc_widgets,
- SelectPlayerLiveryWndProc
-};
-
-
-static const Widget _select_player_livery_widgets[] = {
-{ WWT_CLOSEBOX, RESIZE_NONE, 14, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW },
-{ WWT_CAPTION, RESIZE_NONE, 14, 11, 274, 0, 13, STR_7007_NEW_COLOR_SCHEME, STR_018C_WINDOW_TITLE_DRAG_THIS },
-{ WWT_IMGBTN, RESIZE_NONE, 14, 0, 21, 14, 35, SPR_IMG_COMPANY_GENERAL, STR_LIVERY_GENERAL_TIP },
-{ WWT_IMGBTN, RESIZE_NONE, 14, 22, 43, 14, 35, SPR_IMG_TRAINLIST, STR_LIVERY_TRAIN_TIP },
-{ WWT_IMGBTN, RESIZE_NONE, 14, 44, 65, 14, 35, SPR_IMG_TRUCKLIST, STR_LIVERY_ROADVEH_TIP },
-{ WWT_IMGBTN, RESIZE_NONE, 14, 66, 87, 14, 35, SPR_IMG_SHIPLIST, STR_LIVERY_SHIP_TIP },
-{ WWT_IMGBTN, RESIZE_NONE, 14, 88, 109, 14, 35, SPR_IMG_AIRPLANESLIST, STR_LIVERY_AIRCRAFT_TIP },
-{ WWT_PANEL, RESIZE_NONE, 14, 110, 274, 14, 35, 0x0, STR_NULL },
-{ WWT_PANEL, RESIZE_NONE, 14, 0, 149, 36, 47, 0x0, STR_NULL },
-{ WWT_DROPDOWN, RESIZE_NONE, 14, 150, 274, 36, 47, STR_02BD, STR_LIVERY_PRIMARY_TIP },
-{ WWT_DROPDOWN, RESIZE_NONE, 14, 275, 275, 36, 47, STR_02E1, STR_LIVERY_SECONDARY_TIP },
-{ WWT_MATRIX, RESIZE_NONE, 14, 0, 274, 48, 48 + 1 * 14, (1 << 8) | 1, STR_LIVERY_PANEL_TIP },
-{ WIDGETS_END },
-};
-
-static const WindowDesc _select_player_livery_desc = {
- WDP_AUTO, WDP_AUTO, 275, 49 + 1 * 14, 275, 49 + 1 * 14,
- WC_PLAYER_COLOR, WC_NONE,
- WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET,
_select_player_livery_widgets,
- SelectPlayerLiveryWndProc
};
/**
@@ -608,62 +587,6 @@
}
}
-/**
- * Names of the widgets. Keep them in the same order as in the widget array.
- * Do not change the order of the widgets from PFW_WIDGET_HAS_MOUSTACHE_EARRING to PFW_WIDGET_GLASSES_R,
- * this order is needed for the WE_CLICK event of DrawFaceStringLabel().
- */
-enum PlayerFaceWindowWidgets {
- PFW_WIDGET_CLOSEBOX = 0,
- PFW_WIDGET_CAPTION,
- PFW_WIDGET_TOGGLE_LARGE_SMALL,
- PFW_WIDGET_SELECT_FACE,
- PFW_WIDGET_CANCEL,
- PFW_WIDGET_ACCEPT,
- PFW_WIDGET_MALE,
- PFW_WIDGET_FEMALE,
- PFW_WIDGET_RANDOM_NEW_FACE,
- PFW_WIDGET_TOGGLE_LARGE_SMALL_BUTTON,
- /* from here is the advanced player face selection window */
- PFW_WIDGET_LOAD,
- PFW_WIDGET_FACECODE,
- PFW_WIDGET_SAVE,
- PFW_WIDGET_ETHNICITY_EUR,
- PFW_WIDGET_ETHNICITY_AFR,
- PFW_WIDGET_HAS_MOUSTACHE_EARRING,
- PFW_WIDGET_HAS_GLASSES,
- PFW_WIDGET_EYECOLOUR_L,
- PFW_WIDGET_EYECOLOUR,
- PFW_WIDGET_EYECOLOUR_R,
- PFW_WIDGET_CHIN_L,
- PFW_WIDGET_CHIN,
- PFW_WIDGET_CHIN_R,
- PFW_WIDGET_EYEBROWS_L,
- PFW_WIDGET_EYEBROWS,
- PFW_WIDGET_EYEBROWS_R,
- PFW_WIDGET_LIPS_MOUSTACHE_L,
- PFW_WIDGET_LIPS_MOUSTACHE,
- PFW_WIDGET_LIPS_MOUSTACHE_R,
- PFW_WIDGET_NOSE_L,
- PFW_WIDGET_NOSE,
- PFW_WIDGET_NOSE_R,
- PFW_WIDGET_HAIR_L,
- PFW_WIDGET_HAIR,
- PFW_WIDGET_HAIR_R,
- PFW_WIDGET_JACKET_L,
- PFW_WIDGET_JACKET,
- PFW_WIDGET_JACKET_R,
- PFW_WIDGET_COLLAR_L,
- PFW_WIDGET_COLLAR,
- PFW_WIDGET_COLLAR_R,
- PFW_WIDGET_TIE_EARRING_L,
- PFW_WIDGET_TIE_EARRING,
- PFW_WIDGET_TIE_EARRING_R,
- PFW_WIDGET_GLASSES_L,
- PFW_WIDGET_GLASSES,
- PFW_WIDGET_GLASSES_R,
-};
-
/** Widget description for the normal/simple player face selection dialog */
static const Widget _select_player_face_widgets[] = {
{ WWT_CLOSEBOX, RESIZE_NONE, 14, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW}, // PFW_WIDGET_CLOSEBOX
@@ -731,267 +654,352 @@
{ WIDGETS_END},
};
-/**
- * Draw dynamic a label to the left of the button and a value in the button
- *
- * @param w Window on which the widget is located
- * @param widget_index index of this widget in the window
- * @param str the label which will be draw
- * @param val the value which will be draw
- * @param is_bool_widget is it a bool button
- */
-void DrawFaceStringLabel(const Window *w, byte widget_index, StringID str, uint8 val, bool is_bool_widget)
+class SelectPlayerFaceWindow : public Window
{
- /* Write the label in gold (0x2) to the left of the button. */
- DrawStringRightAligned(w->widget[widget_index].left - (is_bool_widget ? 5 : 14), w->widget[widget_index].top + 1, str, TC_GOLD);
-
- if (!w->IsWidgetDisabled(widget_index)) {
- if (is_bool_widget) {
- /* if it a bool button write yes or no */
- str = (val != 0) ? STR_FACE_YES : STR_FACE_NO;
- } else {
- /* else write the value + 1 */
- SetDParam(0, val + 1);
- str = STR_JUST_INT;
- }
-
- /* Draw the value/bool in white (0xC). If the button clicked adds 1px to x and y text coordinates (IsWindowWidgetLowered()). */
- DrawStringCentered(w->widget[widget_index].left + (w->widget[widget_index].right - w->widget[widget_index].left) / 2 +
- w->IsWidgetLowered(widget_index), w->widget[widget_index].top + 1 + w->IsWidgetLowered(widget_index), str, TC_WHITE);
- }
-}
-
-/**
- * Player face selection window event definition
- *
- * @param w window pointer
- * @param e event been triggered
- */
-static void SelectPlayerFaceWndProc(Window *w, WindowEvent *e)
-{
- PlayerFace *pf = &WP(w, facesel_d).face; // pointer to the player face bits
- GenderEthnicity ge = (GenderEthnicity)GB(*pf, _pf_info[PFV_GEN_ETHN].offset, _pf_info[PFV_GEN_ETHN].length); // get the gender and ethnicity
- bool is_female = HasBit(ge, GENDER_FEMALE); // get the gender: 0 == male and 1 == female
- bool is_moust_male = !is_female && GetPlayerFaceBits(*pf, PFV_HAS_MOUSTACHE, ge) != 0; // is a male face with moustache
-
- switch (e->event) {
- case WE_PAINT:
- /* lower the non-selected gender button */
- w->SetWidgetLoweredState(PFW_WIDGET_MALE, !is_female);
- w->SetWidgetLoweredState(PFW_WIDGET_FEMALE, is_female);
+ PlayerFace face; // player face bits
+ bool advanced; // advance player face selection window
- /* advanced player face selection window */
- if (WP(w, facesel_d).advanced) {
- /* lower the non-selected ethnicity button */
- w->SetWidgetLoweredState(PFW_WIDGET_ETHNICITY_EUR, !HasBit(ge, ETHNICITY_BLACK));
- w->SetWidgetLoweredState(PFW_WIDGET_ETHNICITY_AFR, HasBit(ge, ETHNICITY_BLACK));
-
-
- /* Disable dynamically the widgets which PlayerFaceVariable has less than 2 options
- * (or in other words you haven't any choice).
- * If the widgets depend on a HAS-variable and this is false the widgets will be disabled, too. */
-
- /* Eye colour buttons */
- w->SetWidgetsDisabledState(_pf_info[PFV_EYE_COLOUR].valid_values[ge] < 2,
- PFW_WIDGET_EYECOLOUR, PFW_WIDGET_EYECOLOUR_L, PFW_WIDGET_EYECOLOUR_R, WIDGET_LIST_END);
-
- /* Chin buttons */
- w->SetWidgetsDisabledState(_pf_info[PFV_CHIN].valid_values[ge] < 2,
- PFW_WIDGET_CHIN, PFW_WIDGET_CHIN_L, PFW_WIDGET_CHIN_R, WIDGET_LIST_END);
-
- /* Eyebrows buttons */
- w->SetWidgetsDisabledState(_pf_info[PFV_EYEBROWS].valid_values[ge] < 2,
- PFW_WIDGET_EYEBROWS, PFW_WIDGET_EYEBROWS_L, PFW_WIDGET_EYEBROWS_R, WIDGET_LIST_END);
+ GenderEthnicity ge;
+ bool is_female;
+ bool is_moust_male;
- /* Lips or (if it a male face with a moustache) moustache buttons */
- w->SetWidgetsDisabledState(_pf_info[is_moust_male ? PFV_MOUSTACHE : PFV_LIPS].valid_values[ge] < 2,
- PFW_WIDGET_LIPS_MOUSTACHE, PFW_WIDGET_LIPS_MOUSTACHE_L, PFW_WIDGET_LIPS_MOUSTACHE_R, WIDGET_LIST_END);
-
- /* Nose buttons | male faces with moustache haven't any nose options */
- w->SetWidgetsDisabledState(_pf_info[PFV_NOSE].valid_values[ge] < 2 || is_moust_male,
- PFW_WIDGET_NOSE, PFW_WIDGET_NOSE_L, PFW_WIDGET_NOSE_R, WIDGET_LIST_END);
-
- /* Hair buttons */
- w->SetWidgetsDisabledState(_pf_info[PFV_HAIR].valid_values[ge] < 2,
- PFW_WIDGET_HAIR, PFW_WIDGET_HAIR_L, PFW_WIDGET_HAIR_R, WIDGET_LIST_END);
+ /**
+ * Names of the widgets. Keep them in the same order as in the widget array.
+ * Do not change the order of the widgets from PFW_WIDGET_HAS_MOUSTACHE_EARRING to PFW_WIDGET_GLASSES_R,
+ * this order is needed for the WE_CLICK event of DrawFaceStringLabel().
+ */
+ enum PlayerFaceWindowWidgets {
+ PFW_WIDGET_CLOSEBOX = 0,
+ PFW_WIDGET_CAPTION,
+ PFW_WIDGET_TOGGLE_LARGE_SMALL,
+ PFW_WIDGET_SELECT_FACE,
+ PFW_WIDGET_CANCEL,
+ PFW_WIDGET_ACCEPT,
+ PFW_WIDGET_MALE,
+ PFW_WIDGET_FEMALE,
+ PFW_WIDGET_RANDOM_NEW_FACE,
+ PFW_WIDGET_TOGGLE_LARGE_SMALL_BUTTON,
+ /* from here is the advanced player face selection window */
+ PFW_WIDGET_LOAD,
+ PFW_WIDGET_FACECODE,
+ PFW_WIDGET_SAVE,
+ PFW_WIDGET_ETHNICITY_EUR,
+ PFW_WIDGET_ETHNICITY_AFR,
+ PFW_WIDGET_HAS_MOUSTACHE_EARRING,
+ PFW_WIDGET_HAS_GLASSES,
+ PFW_WIDGET_EYECOLOUR_L,
+ PFW_WIDGET_EYECOLOUR,
+ PFW_WIDGET_EYECOLOUR_R,
+ PFW_WIDGET_CHIN_L,
+ PFW_WIDGET_CHIN,
+ PFW_WIDGET_CHIN_R,
+ PFW_WIDGET_EYEBROWS_L,
+ PFW_WIDGET_EYEBROWS,
+ PFW_WIDGET_EYEBROWS_R,
+ PFW_WIDGET_LIPS_MOUSTACHE_L,
+ PFW_WIDGET_LIPS_MOUSTACHE,
+ PFW_WIDGET_LIPS_MOUSTACHE_R,
+ PFW_WIDGET_NOSE_L,
+ PFW_WIDGET_NOSE,
+ PFW_WIDGET_NOSE_R,
+ PFW_WIDGET_HAIR_L,
+ PFW_WIDGET_HAIR,
+ PFW_WIDGET_HAIR_R,
+ PFW_WIDGET_JACKET_L,
+ PFW_WIDGET_JACKET,
+ PFW_WIDGET_JACKET_R,
+ PFW_WIDGET_COLLAR_L,
+ PFW_WIDGET_COLLAR,
+ PFW_WIDGET_COLLAR_R,
+ PFW_WIDGET_TIE_EARRING_L,
+ PFW_WIDGET_TIE_EARRING,
+ PFW_WIDGET_TIE_EARRING_R,
+ PFW_WIDGET_GLASSES_L,
+ PFW_WIDGET_GLASSES,
+ PFW_WIDGET_GLASSES_R,
+ };
+ /**
+ * Draw dynamic a label to the left of the button and a value in the button
+ *
+ * @param widget_index index of this widget in the window
+ * @param str the label which will be draw
+ * @param val the value which will be draw
+ * @param is_bool_widget is it a bool button
+ */
+ void DrawFaceStringLabel(byte widget_index, StringID str, uint8 val, bool is_bool_widget)
+ {
+ /* Write the label in gold (0x2) to the left of the button. */
+ DrawStringRightAligned(this->widget[widget_index].left - (is_bool_widget ? 5 : 14), this->widget[widget_index].top + 1, str, TC_GOLD);
- /* Jacket buttons */
- w->SetWidgetsDisabledState(_pf_info[PFV_JACKET].valid_values[ge] < 2,
- PFW_WIDGET_JACKET, PFW_WIDGET_JACKET_L, PFW_WIDGET_JACKET_R, WIDGET_LIST_END);
-
- /* Collar buttons */
- w->SetWidgetsDisabledState(_pf_info[PFV_COLLAR].valid_values[ge] < 2,
- PFW_WIDGET_COLLAR, PFW_WIDGET_COLLAR_L, PFW_WIDGET_COLLAR_R, WIDGET_LIST_END);
-
- /* Tie/earring buttons | female faces without earring haven't any earring options */
- w->SetWidgetsDisabledState(_pf_info[PFV_TIE_EARRING].valid_values[ge] < 2 ||
- (is_female && GetPlayerFaceBits(*pf, PFV_HAS_TIE_EARRING, ge) == 0),
- PFW_WIDGET_TIE_EARRING, PFW_WIDGET_TIE_EARRING_L, PFW_WIDGET_TIE_EARRING_R, WIDGET_LIST_END);
-
- /* Glasses buttons | faces without glasses haven't any glasses options */
- w->SetWidgetsDisabledState(_pf_info[PFV_GLASSES].valid_values[ge] < 2 || GetPlayerFaceBits(*pf, PFV_HAS_GLASSES, ge) == 0,
- PFW_WIDGET_GLASSES, PFW_WIDGET_GLASSES_L, PFW_WIDGET_GLASSES_R, WIDGET_LIST_END);
+ if (!this->IsWidgetDisabled(widget_index)) {
+ if (is_bool_widget) {
+ /* if it a bool button write yes or no */
+ str = (val != 0) ? STR_FACE_YES : STR_FACE_NO;
+ } else {
+ /* else write the value + 1 */
+ SetDParam(0, val + 1);
+ str = STR_JUST_INT;
}
- DrawWindowWidgets(w);
-
- /* Draw dynamic button value and labels for the advanced player face selection window */
- if (WP(w, facesel_d).advanced) {
- if (is_female) {
- /* Only for female faces */
- DrawFaceStringLabel(w, PFW_WIDGET_HAS_MOUSTACHE_EARRING, STR_FACE_EARRING, GetPlayerFaceBits(*pf, PFV_HAS_TIE_EARRING, ge), true );
- DrawFaceStringLabel(w, PFW_WIDGET_TIE_EARRING, STR_FACE_EARRING, GetPlayerFaceBits(*pf, PFV_TIE_EARRING, ge), false);
- } else {
- /* Only for male faces */
- DrawFaceStringLabel(w, PFW_WIDGET_HAS_MOUSTACHE_EARRING, STR_FACE_MOUSTACHE, GetPlayerFaceBits(*pf, PFV_HAS_MOUSTACHE, ge), true );
- DrawFaceStringLabel(w, PFW_WIDGET_TIE_EARRING, STR_FACE_TIE, GetPlayerFaceBits(*pf, PFV_TIE_EARRING, ge), false);
- }
- if (is_moust_male) {
- /* Only for male faces with moustache */
- DrawFaceStringLabel(w, PFW_WIDGET_LIPS_MOUSTACHE, STR_FACE_MOUSTACHE, GetPlayerFaceBits(*pf, PFV_MOUSTACHE, ge), false);
- } else {
- /* Only for female faces or male faces without moustache */
- DrawFaceStringLabel(w, PFW_WIDGET_LIPS_MOUSTACHE, STR_FACE_LIPS, GetPlayerFaceBits(*pf, PFV_LIPS, ge), false);
- }
- /* For all faces */
- DrawFaceStringLabel(w, PFW_WIDGET_HAS_GLASSES, STR_FACE_GLASSES, GetPlayerFaceBits(*pf, PFV_HAS_GLASSES, ge), true );
- DrawFaceStringLabel(w, PFW_WIDGET_HAIR, STR_FACE_HAIR, GetPlayerFaceBits(*pf, PFV_HAIR, ge), false);
- DrawFaceStringLabel(w, PFW_WIDGET_EYEBROWS, STR_FACE_EYEBROWS, GetPlayerFaceBits(*pf, PFV_EYEBROWS, ge), false);
- DrawFaceStringLabel(w, PFW_WIDGET_EYECOLOUR, STR_FACE_EYECOLOUR, GetPlayerFaceBits(*pf, PFV_EYE_COLOUR, ge), false);
- DrawFaceStringLabel(w, PFW_WIDGET_GLASSES, STR_FACE_GLASSES, GetPlayerFaceBits(*pf, PFV_GLASSES, ge), false);
- DrawFaceStringLabel(w, PFW_WIDGET_NOSE, STR_FACE_NOSE, GetPlayerFaceBits(*pf, PFV_NOSE, ge), false);
- DrawFaceStringLabel(w, PFW_WIDGET_CHIN, STR_FACE_CHIN, GetPlayerFaceBits(*pf, PFV_CHIN, ge), false);
- DrawFaceStringLabel(w, PFW_WIDGET_JACKET, STR_FACE_JACKET, GetPlayerFaceBits(*pf, PFV_JACKET, ge), false);
- DrawFaceStringLabel(w, PFW_WIDGET_COLLAR, STR_FACE_COLLAR, GetPlayerFaceBits(*pf, PFV_COLLAR, ge), false);
- }
-
- /* Draw the player face picture */
- DrawPlayerFace(*pf, GetPlayer((PlayerID)w->window_number)->player_color, 2, 16);
- break;
-
- case WE_CLICK:
- switch (e->we.click.widget) {
- /* Toggle size, advanced/simple face selection */
- case PFW_WIDGET_TOGGLE_LARGE_SMALL:
- case PFW_WIDGET_TOGGLE_LARGE_SMALL_BUTTON: {
- int oldtop = w->top; ///< current top position of the window before closing it
- int oldleft = w->left; ///< current top position of the window before closing it
-
- DoCommandP(0, 0, *pf, NULL, CMD_SET_PLAYER_FACE);
- delete w;
- /* Open up the (toggled size) Face selection window at the same position as the previous */
- DoSelectPlayerFace((PlayerID)w->window_number, !WP(w, facesel_d).advanced, oldtop, oldleft);
- } break;
-
- /* Cancel button */
- case PFW_WIDGET_CANCEL:
- delete w;
- break;
-
- /* OK button */
- case PFW_WIDGET_ACCEPT:
- DoCommandP(0, 0, *pf, NULL, CMD_SET_PLAYER_FACE);
- delete w;
- break;
-
- /* Load button */
- case PFW_WIDGET_LOAD:
- *pf = _player_face;
- ScaleAllPlayerFaceBits(*pf);
- ShowErrorMessage(INVALID_STRING_ID, STR_FACE_LOAD_DONE, 0, 0);
- w->SetDirty();
- break;
-
- /* 'Player face number' button, view and/or set player face number */
- case PFW_WIDGET_FACECODE:
- SetDParam(0, *pf);
- ShowQueryString(STR_JUST_INT, STR_FACE_FACECODE_CAPTION, 10 + 1, 0, w, CS_NUMERAL);
- break;
+ /* Draw the value/bool in white (0xC). If the button clicked adds 1px to x and y text coordinates (IsWindowWidgetLowered()). */
+ DrawStringCentered(this->widget[widget_index].left + (this->widget[widget_index].right - this->widget[widget_index].left) / 2 +
+ this->IsWidgetLowered(widget_index), this->widget[widget_index].top + 1 + this->IsWidgetLowered(widget_index), str, TC_WHITE);
+ }
+ }
- /* Save button */
- case PFW_WIDGET_SAVE:
- _player_face = *pf;
- ShowErrorMessage(INVALID_STRING_ID, STR_FACE_SAVE_DONE, 0, 0);
- break;
-
- /* Toggle gender (male/female) button */
- case PFW_WIDGET_MALE:
- case PFW_WIDGET_FEMALE:
- SetPlayerFaceBits(*pf, PFV_GENDER, ge, e->we.click.widget - PFW_WIDGET_MALE);
- ScaleAllPlayerFaceBits(*pf);
- w->SetDirty();
- break;
-
- /* Randomize face button */
- case PFW_WIDGET_RANDOM_NEW_FACE:
- RandomPlayerFaceBits(*pf, ge, WP(w, facesel_d).advanced);
- w->SetDirty();
- break;
-
- /* Toggle ethnicity (european/african) button */
- case PFW_WIDGET_ETHNICITY_EUR:
- case PFW_WIDGET_ETHNICITY_AFR:
- SetPlayerFaceBits(*pf, PFV_ETHNICITY, ge, e->we.click.widget - PFW_WIDGET_ETHNICITY_EUR);
- ScaleAllPlayerFaceBits(*pf);
- w->SetDirty();
- break;
-
- default:
- /* For all buttons from PFW_WIDGET_HAS_MOUSTACHE_EARRING to PFW_WIDGET_GLASSES_R is the same function.
- * Therefor is this combined function.
- * First it checks which PlayerFaceVariable will be change and then
- * a: invert the value for boolean variables
- * or b: it checks inside of IncreasePlayerFaceBits() if a left (_L) butten is pressed and then decrease else increase the variable */
- if (WP(w, facesel_d).advanced && e->we.click.widget >= PFW_WIDGET_HAS_MOUSTACHE_EARRING && e->we.click.widget <= PFW_WIDGET_GLASSES_R) {
- PlayerFaceVariable pfv; // which PlayerFaceVariable shall be edited
+ void UpdateData()
+ {
+ this->ge = (GenderEthnicity)GB(this->face, _pf_info[PFV_GEN_ETHN].offset, _pf_info[PFV_GEN_ETHN].length); // get the gender and ethnicity
+ this->is_female = HasBit(this->ge, GENDER_FEMALE); // get the gender: 0 == male and 1 == female
+ this->is_moust_male = !is_female && GetPlayerFaceBits(this->face, PFV_HAS_MOUSTACHE, this->ge) != 0; // is a male face with moustache
+ }
- if (e->we.click.widget < PFW_WIDGET_EYECOLOUR_L) { // Bool buttons
- switch (e->we.click.widget - PFW_WIDGET_HAS_MOUSTACHE_EARRING) {
- default: NOT_REACHED();
- case 0: pfv = is_female ? PFV_HAS_TIE_EARRING : PFV_HAS_MOUSTACHE; break; // Has earring/moustache button
- case 1: pfv = PFV_HAS_GLASSES; break; // Has glasses button
- }
- SetPlayerFaceBits(*pf, pfv, ge, !GetPlayerFaceBits(*pf, pfv, ge));
- ScaleAllPlayerFaceBits(*pf);
+public:
+ SelectPlayerFaceWindow(const WindowDesc *desc, Window *parent, bool advanced) : Window(desc, parent->window_number)
+ {
+ this->parent = parent;
+ this->FindWindowPlacementAndResize(desc);
+ this->caption_color = this->window_number;
+ this->face = GetPlayer((PlayerID)this->window_number)->face;
+ this->advanced = advanced;
- } else { // Value buttons
- switch ((e->we.click.widget - PFW_WIDGET_EYECOLOUR_L) / 3) {
- default: NOT_REACHED();
- case 0: pfv = PFV_EYE_COLOUR; break; // Eye colour buttons
- case 1: pfv = PFV_CHIN; break; // Chin buttons
- case 2: pfv = PFV_EYEBROWS; break; // Eyebrows buttons
- case 3: pfv = is_moust_male ? PFV_MOUSTACHE : PFV_LIPS; break; // Moustache or lips buttons
- case 4: pfv = PFV_NOSE; break; // Nose buttons
- case 5: pfv = PFV_HAIR; break; // Hair buttons
- case 6: pfv = PFV_JACKET; break; // Jacket buttons
- case 7: pfv = PFV_COLLAR; break; // Collar buttons
- case 8: pfv = PFV_TIE_EARRING; break; // Tie/earring buttons
- case 9: pfv = PFV_GLASSES; break; // Glasses buttons
- }
- /* 0 == left (_L), 1 == middle or 2 == right (_R) - button click */
- IncreasePlayerFaceBits(*pf, pfv, ge, (((e->we.click.widget - PFW_WIDGET_EYECOLOUR_L) % 3) != 0) ? 1 : -1);
- }
+ this->UpdateData();
- w->SetDirty();
- }
- break;
- }
- break;
+ /* Check if repositioning from default is required */
+ if (top != FIRST_GUI_CALL && left != FIRST_GUI_CALL) {
+ this->top = top;
+ this->left = left;
+ }
+ }
- case WE_ON_EDIT_TEXT:
- if (e->we.edittext.str == NULL) break;
- /* Set a new player face number */
- if (!StrEmpty(e->we.edittext.str)) {
- *pf = strtoul(e->we.edittext.str, NULL, 10);
- ScaleAllPlayerFaceBits(*pf);
- ShowErrorMessage(INVALID_STRING_ID, STR_FACE_FACECODE_SET, 0, 0);
- w->SetDirty();
+ virtual void OnPaint()
+ {
+ /* lower the non-selected gender button */
+ this->SetWidgetLoweredState(PFW_WIDGET_MALE, !this->is_female);
+ this->SetWidgetLoweredState(PFW_WIDGET_FEMALE, this->is_female);
+
+ /* advanced player face selection window */
+ if (this->advanced) {
+ /* lower the non-selected ethnicity button */
+ this->SetWidgetLoweredState(PFW_WIDGET_ETHNICITY_EUR, !HasBit(this->ge, ETHNICITY_BLACK));
+ this->SetWidgetLoweredState(PFW_WIDGET_ETHNICITY_AFR, HasBit(this->ge, ETHNICITY_BLACK));
+
+
+ /* Disable dynamically the widgets which PlayerFaceVariable has less than 2 options
+ * (or in other words you haven't any choice).
+ * If the widgets depend on a HAS-variable and this is false the widgets will be disabled, too. */
+
+ /* Eye colour buttons */
+ this->SetWidgetsDisabledState(_pf_info[PFV_EYE_COLOUR].valid_values[this->ge] < 2,
+ PFW_WIDGET_EYECOLOUR, PFW_WIDGET_EYECOLOUR_L, PFW_WIDGET_EYECOLOUR_R, WIDGET_LIST_END);
+
+ /* Chin buttons */
+ this->SetWidgetsDisabledState(_pf_info[PFV_CHIN].valid_values[this->ge] < 2,
+ PFW_WIDGET_CHIN, PFW_WIDGET_CHIN_L, PFW_WIDGET_CHIN_R, WIDGET_LIST_END);
+
+ /* Eyebrows buttons */
+ this->SetWidgetsDisabledState(_pf_info[PFV_EYEBROWS].valid_values[this->ge] < 2,
+ PFW_WIDGET_EYEBROWS, PFW_WIDGET_EYEBROWS_L, PFW_WIDGET_EYEBROWS_R, WIDGET_LIST_END);
+
+ /* Lips or (if it a male face with a moustache) moustache buttons */
+ this->SetWidgetsDisabledState(_pf_info[this->is_moust_male ? PFV_MOUSTACHE : PFV_LIPS].valid_values[this->ge] < 2,
+ PFW_WIDGET_LIPS_MOUSTACHE, PFW_WIDGET_LIPS_MOUSTACHE_L, PFW_WIDGET_LIPS_MOUSTACHE_R, WIDGET_LIST_END);
+
+ /* Nose buttons | male faces with moustache haven't any nose options */
+ this->SetWidgetsDisabledState(_pf_info[PFV_NOSE].valid_values[this->ge] < 2 || this->is_moust_male,
+ PFW_WIDGET_NOSE, PFW_WIDGET_NOSE_L, PFW_WIDGET_NOSE_R, WIDGET_LIST_END);
+
+ /* Hair buttons */
+ this->SetWidgetsDisabledState(_pf_info[PFV_HAIR].valid_values[this->ge] < 2,
+ PFW_WIDGET_HAIR, PFW_WIDGET_HAIR_L, PFW_WIDGET_HAIR_R, WIDGET_LIST_END);
+
+ /* Jacket buttons */
+ this->SetWidgetsDisabledState(_pf_info[PFV_JACKET].valid_values[this->ge] < 2,
+ PFW_WIDGET_JACKET, PFW_WIDGET_JACKET_L, PFW_WIDGET_JACKET_R, WIDGET_LIST_END);
+
+ /* Collar buttons */
+ this->SetWidgetsDisabledState(_pf_info[PFV_COLLAR].valid_values[this->ge] < 2,
+ PFW_WIDGET_COLLAR, PFW_WIDGET_COLLAR_L, PFW_WIDGET_COLLAR_R, WIDGET_LIST_END);
+
+ /* Tie/earring buttons | female faces without earring haven't any earring options */
+ this->SetWidgetsDisabledState(_pf_info[PFV_TIE_EARRING].valid_values[this->ge] < 2 ||
+ (this->is_female && GetPlayerFaceBits(this->face, PFV_HAS_TIE_EARRING, this->ge) == 0),
+ PFW_WIDGET_TIE_EARRING, PFW_WIDGET_TIE_EARRING_L, PFW_WIDGET_TIE_EARRING_R, WIDGET_LIST_END);
+
+ /* Glasses buttons | faces without glasses haven't any glasses options */
+ this->SetWidgetsDisabledState(_pf_info[PFV_GLASSES].valid_values[this->ge] < 2 || GetPlayerFaceBits(this->face, PFV_HAS_GLASSES, this->ge) == 0,
+ PFW_WIDGET_GLASSES, PFW_WIDGET_GLASSES_L, PFW_WIDGET_GLASSES_R, WIDGET_LIST_END);
+ }
+
+ this->DrawWidgets();
+
+ /* Draw dynamic button value and labels for the advanced player face selection window */
+ if (this->advanced) {
+ if (this->is_female) {
+ /* Only for female faces */
+ this->DrawFaceStringLabel(PFW_WIDGET_HAS_MOUSTACHE_EARRING, STR_FACE_EARRING, GetPlayerFaceBits(this->face, PFV_HAS_TIE_EARRING, this->ge), true );
+ this->DrawFaceStringLabel(PFW_WIDGET_TIE_EARRING, STR_FACE_EARRING, GetPlayerFaceBits(this->face, PFV_TIE_EARRING, this->ge), false);
} else {
- ShowErrorMessage(INVALID_STRING_ID, STR_FACE_FACECODE_ERR, 0, 0);
+ /* Only for male faces */
+ this->DrawFaceStringLabel(PFW_WIDGET_HAS_MOUSTACHE_EARRING, STR_FACE_MOUSTACHE, GetPlayerFaceBits(this->face, PFV_HAS_MOUSTACHE, this->ge), true );
+ this->DrawFaceStringLabel(PFW_WIDGET_TIE_EARRING, STR_FACE_TIE, GetPlayerFaceBits(this->face, PFV_TIE_EARRING, this->ge), false);
}
- break;
+ if (this->is_moust_male) {
+ /* Only for male faces with moustache */
+ this->DrawFaceStringLabel(PFW_WIDGET_LIPS_MOUSTACHE, STR_FACE_MOUSTACHE, GetPlayerFaceBits(this->face, PFV_MOUSTACHE, this->ge), false);
+ } else {
+ /* Only for female faces or male faces without moustache */
+ this->DrawFaceStringLabel(PFW_WIDGET_LIPS_MOUSTACHE, STR_FACE_LIPS, GetPlayerFaceBits(this->face, PFV_LIPS, this->ge), false);
+ }
+ /* For all faces */
+ this->DrawFaceStringLabel(PFW_WIDGET_HAS_GLASSES, STR_FACE_GLASSES, GetPlayerFaceBits(this->face, PFV_HAS_GLASSES, this->ge), true );
+ this->DrawFaceStringLabel(PFW_WIDGET_HAIR, STR_FACE_HAIR, GetPlayerFaceBits(this->face, PFV_HAIR, this->ge), false);
+ this->DrawFaceStringLabel(PFW_WIDGET_EYEBROWS, STR_FACE_EYEBROWS, GetPlayerFaceBits(this->face, PFV_EYEBROWS, this->ge), false);
+ this->DrawFaceStringLabel(PFW_WIDGET_EYECOLOUR, STR_FACE_EYECOLOUR, GetPlayerFaceBits(this->face, PFV_EYE_COLOUR, this->ge), false);
+ this->DrawFaceStringLabel(PFW_WIDGET_GLASSES, STR_FACE_GLASSES, GetPlayerFaceBits(this->face, PFV_GLASSES, this->ge), false);
+ this->DrawFaceStringLabel(PFW_WIDGET_NOSE, STR_FACE_NOSE, GetPlayerFaceBits(this->face, PFV_NOSE, this->ge), false);
+ this->DrawFaceStringLabel(PFW_WIDGET_CHIN, STR_FACE_CHIN, GetPlayerFaceBits(this->face, PFV_CHIN, this->ge), false);
+ this->DrawFaceStringLabel(PFW_WIDGET_JACKET, STR_FACE_JACKET, GetPlayerFaceBits(this->face, PFV_JACKET, this->ge), false);
+ this->DrawFaceStringLabel(PFW_WIDGET_COLLAR, STR_FACE_COLLAR, GetPlayerFaceBits(this->face, PFV_COLLAR, this->ge), false);
+ }
+
+ /* Draw the player face picture */
+ DrawPlayerFace(this->face, GetPlayer((PlayerID)this->window_number)->player_color, 2, 16);
}
-}
+
+ virtual void OnClick(Point pt, int widget)
+ {
+ switch (widget) {
+ /* Toggle size, advanced/simple face selection */
+ case PFW_WIDGET_TOGGLE_LARGE_SMALL:
+ case PFW_WIDGET_TOGGLE_LARGE_SMALL_BUTTON: {
+ DoCommandP(0, 0, this->face, NULL, CMD_SET_PLAYER_FACE);
+
+ /* Backup some data before deletion */
+ int oldtop = this->top; ///< current top position of the window before closing it
+ int oldleft = this->left; ///< current top position of the window before closing it
+ bool adv = !this->advanced;
+ Window *parent = this->parent;
+
+ delete this;
+
+ /* Open up the (toggled size) Face selection window at the same position as the previous */
+ DoSelectPlayerFace(parent, adv, oldtop, oldleft);
+ } break;
+
+
+ /* OK button */
+ case PFW_WIDGET_ACCEPT:
+ DoCommandP(0, 0, this->face, NULL, CMD_SET_PLAYER_FACE);
+ /* Fall-Through */
+
+ /* Cancel button */
+ case PFW_WIDGET_CANCEL:
+ delete this;
+ break;
+
+ /* Load button */
+ case PFW_WIDGET_LOAD:
+ this->face = _player_face;
+ ScaleAllPlayerFaceBits(this->face);
+ ShowErrorMessage(INVALID_STRING_ID, STR_FACE_LOAD_DONE, 0, 0);
+ this->UpdateData();
+ this->SetDirty();
+ break;
+
+ /* 'Player face number' button, view and/or set player face number */
+ case PFW_WIDGET_FACECODE:
+ SetDParam(0, this->face);
+ ShowQueryString(STR_JUST_INT, STR_FACE_FACECODE_CAPTION, 10 + 1, 0, this, CS_NUMERAL);
+ break;
+
+ /* Save button */
+ case PFW_WIDGET_SAVE:
+ _player_face = this->face;
+ ShowErrorMessage(INVALID_STRING_ID, STR_FACE_SAVE_DONE, 0, 0);
+ break;
+
+ /* Toggle gender (male/female) button */
+ case PFW_WIDGET_MALE:
+ case PFW_WIDGET_FEMALE:
+ SetPlayerFaceBits(this->face, PFV_GENDER, this->ge, widget - PFW_WIDGET_MALE);
+ ScaleAllPlayerFaceBits(this->face);
+ this->UpdateData();
+ this->SetDirty();
+ break;
+
+ /* Randomize face button */
+ case PFW_WIDGET_RANDOM_NEW_FACE:
+ RandomPlayerFaceBits(this->face, this->ge, this->advanced);
+ this->UpdateData();
+ this->SetDirty();
+ break;
+
+ /* Toggle ethnicity (european/african) button */
+ case PFW_WIDGET_ETHNICITY_EUR:
+ case PFW_WIDGET_ETHNICITY_AFR:
+ SetPlayerFaceBits(this->face, PFV_ETHNICITY, this->ge, widget - PFW_WIDGET_ETHNICITY_EUR);
+ ScaleAllPlayerFaceBits(this->face);
+ this->UpdateData();
+ this->SetDirty();
+ break;
+
+ default:
+ /* For all buttons from PFW_WIDGET_HAS_MOUSTACHE_EARRING to PFW_WIDGET_GLASSES_R is the same function.
+ * Therefor is this combined function.
+ * First it checks which PlayerFaceVariable will be change and then
+ * a: invert the value for boolean variables
+ * or b: it checks inside of IncreasePlayerFaceBits() if a left (_L) butten is pressed and then decrease else increase the variable */
+ if (this->advanced && widget >= PFW_WIDGET_HAS_MOUSTACHE_EARRING && widget <= PFW_WIDGET_GLASSES_R) {
+ PlayerFaceVariable pfv; // which PlayerFaceVariable shall be edited
+
+ if (widget < PFW_WIDGET_EYECOLOUR_L) { // Bool buttons
+ switch (widget - PFW_WIDGET_HAS_MOUSTACHE_EARRING) {
+ default: NOT_REACHED();
+ case 0: pfv = this->is_female ? PFV_HAS_TIE_EARRING : PFV_HAS_MOUSTACHE; break; // Has earring/moustache button
+ case 1: pfv = PFV_HAS_GLASSES; break; // Has glasses button
+ }
+ SetPlayerFaceBits(this->face, pfv, this->ge, !GetPlayerFaceBits(this->face, pfv, this->ge));
+ ScaleAllPlayerFaceBits(this->face);
+ } else { // Value buttons
+ switch ((widget - PFW_WIDGET_EYECOLOUR_L) / 3) {
+ default: NOT_REACHED();
+ case 0: pfv = PFV_EYE_COLOUR; break; // Eye colour buttons
+ case 1: pfv = PFV_CHIN; break; // Chin buttons
+ case 2: pfv = PFV_EYEBROWS; break; // Eyebrows buttons
+ case 3: pfv = this->is_moust_male ? PFV_MOUSTACHE : PFV_LIPS; break; // Moustache or lips buttons
+ case 4: pfv = PFV_NOSE; break; // Nose buttons
+ case 5: pfv = PFV_HAIR; break; // Hair buttons
+ case 6: pfv = PFV_JACKET; break; // Jacket buttons
+ case 7: pfv = PFV_COLLAR; break; // Collar buttons
+ case 8: pfv = PFV_TIE_EARRING; break; // Tie/earring buttons
+ case 9: pfv = PFV_GLASSES; break; // Glasses buttons
+ }
+ /* 0 == left (_L), 1 == middle or 2 == right (_R) - button click */
+ IncreasePlayerFaceBits(this->face, pfv, this->ge, (((widget - PFW_WIDGET_EYECOLOUR_L) % 3) != 0) ? 1 : -1);
+ }
+ this->UpdateData();
+ this->SetDirty();
+ }
+ break;
+ }
+ }
+
+ virtual void OnQueryTextFinished(char *str)
+ {
+ if (str == NULL) return;
+ /* Set a new player face number */
+ if (!StrEmpty(str)) {
+ this->face = strtoul(str, NULL, 10);
+ ScaleAllPlayerFaceBits(this->face);
+ ShowErrorMessage(INVALID_STRING_ID, STR_FACE_FACECODE_SET, 0, 0);
+ this->UpdateData();
+ this->SetDirty();
+ } else {
+ ShowErrorMessage(INVALID_STRING_ID, STR_FACE_FACECODE_ERR, 0, 0);
+ }
+ }
+};
/** normal/simple player face selection window description */
static const WindowDesc _select_player_face_desc = {
@@ -999,7 +1007,6 @@
WC_PLAYER_FACE, WC_NONE,
WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS,
_select_player_face_widgets,
- SelectPlayerFaceWndProc
};
/** advanced player face selection window description */
@@ -1008,7 +1015,6 @@
WC_PLAYER_FACE, WC_NONE,
WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS,
_select_player_face_adv_widgets,
- SelectPlayerFaceWndProc
};
/**
@@ -1021,23 +1027,12 @@
*
* @pre is player a valid player
*/
-static void DoSelectPlayerFace(PlayerID player, bool adv, int top, int left)
+static void DoSelectPlayerFace(Window *parent, bool adv, int top, int left)
{
- if (!IsValidPlayer(player)) return;
-
- Window *w = AllocateWindowDescFront<Window>(adv ? &_select_player_face_adv_desc : &_select_player_face_desc, player); // simple or advanced window
+ if (!IsValidPlayer((PlayerID)parent->window_number)) return;
- if (w != NULL) {
- w->caption_color = w->window_number;
- WP(w, facesel_d).face = GetPlayer((PlayerID)w->window_number)->face;
- WP(w, facesel_d).advanced = adv;
-
- /* Check if repositioning from default is required */
- if (top != FIRST_GUI_CALL && left != FIRST_GUI_CALL) {
- w->top = top;
- w->left = left;
- }
- }
+ if (BringWindowToFrontById(WC_PLAYER_FACE, parent->window_number)) return;
+ new SelectPlayerFaceWindow(adv ? &_select_player_face_adv_desc : &_select_player_face_desc, parent, adv); // simple or advanced window
}
@@ -1165,238 +1160,232 @@
* @param w window pointer
* @param e event been triggered
*/
-static void PlayerCompanyWndProc(Window *w, WindowEvent *e)
+struct PlayerCompanyWindow : Window
{
- switch (e->event) {
- case WE_PAINT: {
- const Player *p = GetPlayer((PlayerID)w->window_number);
- bool local = w->window_number == _local_player;
-
- w->SetWidgetHiddenState(PCW_WIDGET_NEW_FACE, !local);
- w->SetWidgetHiddenState(PCW_WIDGET_COLOR_SCHEME, !local);
- w->SetWidgetHiddenState(PCW_WIDGET_PRESIDENT_NAME, !local);
- w->SetWidgetHiddenState(PCW_WIDGET_COMPANY_NAME, !local);
- w->widget[PCW_WIDGET_BUILD_VIEW_HQ].data = (local && p->location_of_house == 0) ? STR_706F_BUILD_HQ : STR_7072_VIEW_HQ;
- if (local && p->location_of_house != 0) w->widget[PCW_WIDGET_BUILD_VIEW_HQ].type = WWT_PUSHTXTBTN; //HQ is already built.
- w->SetWidgetDisabledState(PCW_WIDGET_BUILD_VIEW_HQ, !local && p->location_of_house == 0);
- w->SetWidgetHiddenState(PCW_WIDGET_RELOCATE_HQ, !local || p->location_of_house == 0);
- w->SetWidgetHiddenState(PCW_WIDGET_BUY_SHARE, local);
- w->SetWidgetHiddenState(PCW_WIDGET_SELL_SHARE, local);
- w->SetWidgetHiddenState(PCW_WIDGET_COMPANY_PASSWORD, !local || !_networking);
-
- if (!local) {
- if (_patches.allow_shares) { // Shares are allowed
- /* If all shares are owned by someone (none by nobody), disable buy button */
- w->SetWidgetDisabledState(PCW_WIDGET_BUY_SHARE, GetAmountOwnedBy(p, PLAYER_SPECTATOR) == 0 ||
- /* Only 25% left to buy. If the player is human, disable buying it up.. TODO issues! */
- (GetAmountOwnedBy(p, PLAYER_SPECTATOR) == 1 && !p->is_ai) ||
- /* Spectators cannot do anything of course */
- _local_player == PLAYER_SPECTATOR);
+ PlayerCompanyWindowWidgets query_widget;
- /* If the player doesn't own any shares, disable sell button */
- w->SetWidgetDisabledState(PCW_WIDGET_SELL_SHARE, (GetAmountOwnedBy(p, _local_player) == 0) ||
- /* Spectators cannot do anything of course */
- _local_player == PLAYER_SPECTATOR);
- } else { // Shares are not allowed, disable buy/sell buttons
- w->DisableWidget(PCW_WIDGET_BUY_SHARE);
- w->DisableWidget(PCW_WIDGET_SELL_SHARE);
- }
- }
-
- SetDParam(0, p->index);
- SetDParam(1, p->index);
-
- DrawWindowWidgets(w);
-
- /* Player face */
- DrawPlayerFace(p->face, p->player_color, 2, 16);
+ PlayerCompanyWindow(const WindowDesc *desc, WindowNumber window_number) : Window(desc, window_number)
+ {
+ this->caption_color = this->window_number;
+ }
- /* "xxx (Manager)" */
- SetDParam(0, p->index);
- DrawStringMultiCenter(48, 141, STR_7037_PRESIDENT, 94);
-
- /* "Inaugurated:" */
- SetDParam(0, p->inaugurated_year);
- DrawString(110, 23, STR_7038_INAUGURATED, TC_FROMSTRING);
+ virtual void OnPaint()
+ {
+ const Player *p = GetPlayer((PlayerID)this->window_number);
+ bool local = this->window_number == _local_player;
- /* "Colour scheme:" */
- DrawString(110, 43, STR_7006_COLOR_SCHEME, TC_FROMSTRING);
- /* Draw company-colour bus */
- DrawSprite(SPR_VEH_BUS_SW_VIEW, PLAYER_SPRITE_COLOR(p->index), 215, 44);
-
- /* "Vehicles:" */
- DrawPlayerVehiclesAmount((PlayerID)w->window_number);
+ this->SetWidgetHiddenState(PCW_WIDGET_NEW_FACE, !local);
+ this->SetWidgetHiddenState(PCW_WIDGET_COLOR_SCHEME, !local);
+ this->SetWidgetHiddenState(PCW_WIDGET_PRESIDENT_NAME, !local);
+ this->SetWidgetHiddenState(PCW_WIDGET_COMPANY_NAME, !local);
+ this->widget[PCW_WIDGET_BUILD_VIEW_HQ].data = (local && p->location_of_house == 0) ? STR_706F_BUILD_HQ : STR_7072_VIEW_HQ;
+ if (local && p->location_of_house != 0) this->widget[PCW_WIDGET_BUILD_VIEW_HQ].type = WWT_PUSHTXTBTN; //HQ is already built.
+ this->SetWidgetDisabledState(PCW_WIDGET_BUILD_VIEW_HQ, !local && p->location_of_house == 0);
+ this->SetWidgetHiddenState(PCW_WIDGET_RELOCATE_HQ, !local || p->location_of_house == 0);
+ this->SetWidgetHiddenState(PCW_WIDGET_BUY_SHARE, local);
+ this->SetWidgetHiddenState(PCW_WIDGET_SELL_SHARE, local);
+ this->SetWidgetHiddenState(PCW_WIDGET_COMPANY_PASSWORD, !local || !_networking);
- /* "Company value:" */
- SetDParam(0, CalculateCompanyValue(p));
- DrawString(110, 106, STR_7076_COMPANY_VALUE, TC_FROMSTRING);
+ if (!local) {
+ if (_patches.allow_shares) { // Shares are allowed
+ /* If all shares are owned by someone (none by nobody), disable buy button */
+ this->SetWidgetDisabledState(PCW_WIDGET_BUY_SHARE, GetAmountOwnedBy(p, PLAYER_SPECTATOR) == 0 ||
+ /* Only 25% left to buy. If the player is human, disable buying it up.. TODO issues! */
+ (GetAmountOwnedBy(p, PLAYER_SPECTATOR) == 1 && !p->is_ai) ||
+ /* Spectators cannot do anything of course */
+ _local_player == PLAYER_SPECTATOR);
- /* Shares list */
- DrawCompanyOwnerText(p);
-
- break;
+ /* If the player doesn't own any shares, disable sell button */
+ this->SetWidgetDisabledState(PCW_WIDGET_SELL_SHARE, (GetAmountOwnedBy(p, _local_player) == 0) ||
+ /* Spectators cannot do anything of course */
+ _local_player == PLAYER_SPECTATOR);
+ } else { // Shares are not allowed, disable buy/sell buttons
+ this->DisableWidget(PCW_WIDGET_BUY_SHARE);
+ this->DisableWidget(PCW_WIDGET_SELL_SHARE);
+ }
}
- case WE_CLICK:
- switch (e->we.click.widget) {
- case PCW_WIDGET_NEW_FACE: DoSelectPlayerFace((PlayerID)w->window_number, false); break;
-
- case PCW_WIDGET_COLOR_SCHEME: {
- Window *wf = AllocateWindowDescFront<Window>(_loaded_newgrf_features.has_2CC ? &_select_player_livery_2cc_desc : &_select_player_livery_desc, w->window_number);
- if (wf != NULL) {
- wf->caption_color = wf->window_number;
- WP(wf, livery_d).livery_class = LC_OTHER;
- WP(wf, livery_d).sel = 1;
- wf->LowerWidget(2);
- }
- break;
- }
-
- case PCW_WIDGET_PRESIDENT_NAME: {
- const Player *p = GetPlayer((PlayerID)w->window_number);
- WP(w, def_d).byte_1 = 0;
- SetDParam(0, p->index);
- ShowQueryString(STR_PLAYER_NAME, STR_700B_PRESIDENT_S_NAME, 31, 94, w, CS_ALPHANUMERAL);
- break;
- }
-
- case PCW_WIDGET_COMPANY_NAME: {
- Player *p = GetPlayer((PlayerID)w->window_number);
- WP(w, def_d).byte_1 = 1;
- SetDParam(0, p->index);
- ShowQueryString(STR_COMPANY_NAME, STR_700A_COMPANY_NAME, 31, 150, w, CS_ALPHANUMERAL);
- break;
- }
+ SetDParam(0, p->index);
+ SetDParam(1, p->index);
- case PCW_WIDGET_BUILD_VIEW_HQ: {
- TileIndex tile = GetPlayer((PlayerID)w->window_number)->location_of_house;
- if (tile == 0) {
- if ((byte)w->window_number != _local_player)
- return;
- SetObjectToPlaceWnd(SPR_CURSOR_HQ, PAL_NONE, VHM_RECT, w);
- SetTileSelectSize(2, 2);
- w->LowerWidget(PCW_WIDGET_BUILD_VIEW_HQ);
- w->InvalidateWidget(PCW_WIDGET_BUILD_VIEW_HQ);
+ this->DrawWidgets();
+
+ /* Player face */
+ DrawPlayerFace(p->face, p->player_color, 2, 16);
+
+ /* "xxx (Manager)" */
+ SetDParam(0, p->index);
+ DrawStringMultiCenter(48, 141, STR_7037_PRESIDENT, 94);
+
+ /* "Inaugurated:" */
+ SetDParam(0, p->inaugurated_year);
+ DrawString(110, 23, STR_7038_INAUGURATED, TC_FROMSTRING);
+
+ /* "Colour scheme:" */
+ DrawString(110, 43, STR_7006_COLOR_SCHEME, TC_FROMSTRING);
+ /* Draw company-colour bus */
+ DrawSprite(SPR_VEH_BUS_SW_VIEW, PLAYER_SPRITE_COLOR(p->index), 215, 44);
+
+ /* "Vehicles:" */
+ DrawPlayerVehiclesAmount((PlayerID)this->window_number);
+
+ /* "Company value:" */
+ SetDParam(0, CalculateCompanyValue(p));
+ DrawString(110, 106, STR_7076_COMPANY_VALUE, TC_FROMSTRING);
+
+ /* Shares list */
+ DrawCompanyOwnerText(p);
+ }
+
+ virtual void OnClick(Point pt, int widget)
+ {
+ switch (widget) {
+ case PCW_WIDGET_NEW_FACE: DoSelectPlayerFace(this, false); break;
+
+ case PCW_WIDGET_COLOR_SCHEME:
+ if (BringWindowToFrontById(WC_PLAYER_COLOR, this->window_number)) break;
+ new SelectPlayerLiveryWindow(&_select_player_livery_desc, (PlayerID)this->window_number);
+ break;
+
+ case PCW_WIDGET_PRESIDENT_NAME:
+ this->query_widget = PCW_WIDGET_PRESIDENT_NAME;
+ SetDParam(0, this->window_number);
+ ShowQueryString(STR_PLAYER_NAME, STR_700B_PRESIDENT_S_NAME, 31, 94, this, CS_ALPHANUMERAL);
+ break;
+
+ case PCW_WIDGET_COMPANY_NAME:
+ this->query_widget = PCW_WIDGET_COMPANY_NAME;
+ SetDParam(0, this->window_number);
+ ShowQueryString(STR_COMPANY_NAME, STR_700A_COMPANY_NAME, 31, 150, this, CS_ALPHANUMERAL);
+ break;
+
+ case PCW_WIDGET_BUILD_VIEW_HQ: {
+ TileIndex tile = GetPlayer((PlayerID)this->window_number)->location_of_house;
+ if (tile == 0) {
+ if ((byte)this->window_number != _local_player) return;
+ SetObjectToPlaceWnd(SPR_CURSOR_HQ, PAL_NONE, VHM_RECT, this);
+ SetTileSelectSize(2, 2);
+ this->LowerWidget(PCW_WIDGET_BUILD_VIEW_HQ);
+ this->InvalidateWidget(PCW_WIDGET_BUILD_VIEW_HQ);
+ } else {
+ if (_ctrl_pressed) {
+ ShowExtraViewPortWindow(tile);
} else {
- if (_ctrl_pressed) {
- ShowExtraViewPortWindow(tile);
- } else {
- ScrollMainWindowToTile(tile);
- }
+ ScrollMainWindowToTile(tile);
}
- break;
}
+ break;
+ }
- case PCW_WIDGET_RELOCATE_HQ:
- SetObjectToPlaceWnd(SPR_CURSOR_HQ, PAL_NONE, VHM_RECT, w);
- SetTileSelectSize(2, 2);
- w->LowerWidget(PCW_WIDGET_RELOCATE_HQ);
- w->InvalidateWidget(PCW_WIDGET_RELOCATE_HQ);
- break;
+ case PCW_WIDGET_RELOCATE_HQ:
+ SetObjectToPlaceWnd(SPR_CURSOR_HQ, PAL_NONE, VHM_RECT, this);
+ SetTileSelectSize(2, 2);
+ this->LowerWidget(PCW_WIDGET_RELOCATE_HQ);
+ this->InvalidateWidget(PCW_WIDGET_RELOCATE_HQ);
+ break;
- case PCW_WIDGET_BUY_SHARE:
- DoCommandP(0, w->window_number, 0, NULL, CMD_BUY_SHARE_IN_COMPANY | CMD_MSG(STR_707B_CAN_T_BUY_25_SHARE_IN_THIS));
- break;
+ case PCW_WIDGET_BUY_SHARE:
+ DoCommandP(0, this->window_number, 0, NULL, CMD_BUY_SHARE_IN_COMPANY | CMD_MSG(STR_707B_CAN_T_BUY_25_SHARE_IN_THIS));
+ break;
- case PCW_WIDGET_SELL_SHARE:
- DoCommandP(0, w->window_number, 0, NULL, CMD_SELL_SHARE_IN_COMPANY | CMD_MSG(STR_707C_CAN_T_SELL_25_SHARE_IN));
- break;
+ case PCW_WIDGET_SELL_SHARE:
+ DoCommandP(0, this->window_number, 0, NULL, CMD_SELL_SHARE_IN_COMPANY | CMD_MSG(STR_707C_CAN_T_SELL_25_SHARE_IN));
+ break;
#ifdef ENABLE_NETWORK
- case PCW_WIDGET_COMPANY_PASSWORD:
- if (w->window_number == _local_player) ShowNetworkCompanyPasswordWindow();
- break;
+ case PCW_WIDGET_COMPANY_PASSWORD:
+ if (this->window_number == _local_player) ShowNetworkCompanyPasswordWindow(this);
+ break;
#endif /* ENABLE_NETWORK */
- }
- break;
-
- case WE_TICK:
- /* redraw the window every now and then */
- if ((++w->vscroll.pos & 0x1F) == 0) w->SetDirty();
- break;
-
- case WE_PLACE_OBJ:
- if (DoCommandP(e->we.place.tile, 0, 0, NULL, CMD_BUILD_COMPANY_HQ | CMD_NO_WATER | CMD_MSG(STR_7071_CAN_T_BUILD_COMPANY_HEADQUARTERS)))
- ResetObjectToPlace();
- w->widget[PCW_WIDGET_BUILD_VIEW_HQ].type = WWT_PUSHTXTBTN; // this button can now behave as a normal push button
- w->RaiseButtons();
- break;
+ }
+ }
- case WE_ABORT_PLACE_OBJ:
- w->RaiseButtons();
- break;
-
- case WE_DESTROY:
- DeleteWindowById(WC_PLAYER_FACE, w->window_number);
- if (w->window_number == _local_player) DeleteWindowById(WC_COMPANY_PASSWORD_WINDOW, 0);
- break;
-
- case WE_ON_EDIT_TEXT:
- if (StrEmpty(e->we.edittext.str)) break;
+ virtual void OnTick()
+ {
+ /* redraw the window every now and then */
+ if ((++this->vscroll.pos & 0x1F) == 0) this->SetDirty();
+ }
- _cmd_text = e->we.edittext.str;
- switch (WP(w, def_d).byte_1) {
- case 0: /* Change president name */
- DoCommandP(0, 0, 0, NULL, CMD_CHANGE_PRESIDENT_NAME | CMD_MSG(STR_700D_CAN_T_CHANGE_PRESIDENT));
- break;
- case 1: /* Change company name */
- DoCommandP(0, 0, 0, NULL, CMD_CHANGE_COMPANY_NAME | CMD_MSG(STR_700C_CAN_T_CHANGE_COMPANY_NAME));
- break;
- }
- break;
+ virtual void OnPlaceObject(Point pt, TileIndex tile)
+ {
+ if (DoCommandP(tile, 0, 0, NULL, CMD_BUILD_COMPANY_HQ | CMD_NO_WATER | CMD_MSG(STR_7071_CAN_T_BUILD_COMPANY_HEADQUARTERS)))
+ ResetObjectToPlace();
+ this->widget[PCW_WIDGET_BUILD_VIEW_HQ].type = WWT_PUSHTXTBTN; // this button can now behave as a normal push button
+ this->RaiseButtons();
}
-}
+ virtual void OnPlaceObjectAbort()
+ {
+ this->RaiseButtons();
+ }
+
+ virtual void OnQueryTextFinished(char *str)
+ {
+ if (StrEmpty(str)) return;
+
+ _cmd_text = str;
+ switch (this->query_widget) {
+ default: NOT_REACHED();
+
+ case PCW_WIDGET_PRESIDENT_NAME:
+ DoCommandP(0, 0, 0, NULL, CMD_CHANGE_PRESIDENT_NAME | CMD_MSG(STR_700D_CAN_T_CHANGE_PRESIDENT));
+ break;
+
+ case PCW_WIDGET_COMPANY_NAME:
+ DoCommandP(0, 0, 0, NULL, CMD_CHANGE_COMPANY_NAME | CMD_MSG(STR_700C_CAN_T_CHANGE_COMPANY_NAME));
+ break;
+ }
+ }
+};
static const WindowDesc _player_company_desc = {
WDP_AUTO, WDP_AUTO, 360, 170, 360, 170,
WC_COMPANY, WC_NONE,
WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS,
_player_company_widgets,
- PlayerCompanyWndProc
};
void ShowPlayerCompany(PlayerID player)
{
- Window *w;
-
if (!IsValidPlayer(player)) return;
- w = AllocateWindowDescFront<Window>(&_player_company_desc, player);
- if (w != NULL) w->caption_color = w->window_number;
+ AllocateWindowDescFront<PlayerCompanyWindow>(&_player_company_desc, player);
}
-static void BuyCompanyWndProc(Window *w, WindowEvent *e)
-{
- switch (e->event) {
- case WE_PAINT: {
- Player *p = GetPlayer((PlayerID)w->window_number);
- SetDParam(0, STR_COMPANY_NAME);
- SetDParam(1, p->index);
- DrawWindowWidgets(w);
-
- DrawPlayerFace(p->face, p->player_color, 2, 16);
+struct BuyCompanyWindow : Window {
+ BuyCompanyWindow(const WindowDesc *desc, WindowNumber window_number) : Window(desc, window_number)
+ {
+ }
- SetDParam(0, p->index);
- SetDParam(1, p->bankrupt_value);
- DrawStringMultiCenter(214, 65, STR_705B_WE_ARE_LOOKING_FOR_A_TRANSPORT, 238);
- } break;
+ virtual void OnPaint()
+ {
+ Player *p = GetPlayer((PlayerID)this->window_number);
+ SetDParam(0, STR_COMPANY_NAME);
+ SetDParam(1, p->index);
+ this->DrawWidgets();
- case WE_CLICK:
- switch (e->we.click.widget) {
- case 3:
- delete w;
- break;
- case 4: {
- DoCommandP(0, w->window_number, 0, NULL, CMD_BUY_COMPANY | CMD_MSG(STR_7060_CAN_T_BUY_COMPANY));
- break;
- }
- }
- break;
+ DrawPlayerFace(p->face, p->player_color, 2, 16);
+
+ SetDParam(0, p->index);
+ SetDParam(1, p->bankrupt_value);
+ DrawStringMultiCenter(214, 65, STR_705B_WE_ARE_LOOKING_FOR_A_TRANSPORT, 238);
}
-}
+
+ virtual void OnClick(Point pt, int widget)
+ {
+ switch (widget) {
+ case 3:
+ delete this;
+ break;
+
+ case 4:
+ DoCommandP(0, this->window_number, 0, NULL, CMD_BUY_COMPANY | CMD_MSG(STR_7060_CAN_T_BUY_COMPANY));
+ break;
+ }
+ }
+};
static const Widget _buy_company_widgets[] = {
{ WWT_CLOSEBOX, RESIZE_NONE, 5, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW},
@@ -1412,117 +1401,165 @@
WC_BUY_COMPANY, WC_NONE,
WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET,
_buy_company_widgets,
- BuyCompanyWndProc
};
void ShowBuyCompanyDialog(uint player)
{
- AllocateWindowDescFront<Window>(&_buy_company_desc, player);
+ AllocateWindowDescFront<BuyCompanyWindow>(&_buy_company_desc, player);
}
/********** HIGHSCORE and ENDGAME windows */
-/* Always draw a maximized window and within there the centered background */
-static void SetupHighScoreEndWindow(Window *w, uint *x, uint *y)
-{
- uint i;
- /* resize window to "full-screen" */
- w->width = _screen.width;
- w->height = _screen.height;
- w->widget[0].right = w->width - 1;
- w->widget[0].bottom = w->height - 1;
+extern StringID EndGameGetPerformanceTitleFromValue(uint value);
- DrawWindowWidgets(w);
- /* Center Highscore/Endscreen background */
- *x = max(0, (_screen.width / 2) - (640 / 2));
- *y = max(0, (_screen.height / 2) - (480 / 2));
- for (i = 0; i < 10; i++) // the image is split into 10 50px high parts
- DrawSprite(WP(w, highscore_d).background_img + i, PAL_NONE, *x, *y + (i * 50));
-}
+struct EndGameHighScoreBaseWindow : Window
+{
+ uint32 background_img;
+ int8 rank;
-extern StringID EndGameGetPerformanceTitleFromValue(uint value);
+ EndGameHighScoreBaseWindow(const WindowDesc *desc) : Window(desc)
+ {
+ }
+
+ /* Always draw a maximized window and within there the centered background */
+ void SetupHighScoreEndWindow(uint *x, uint *y)
+ {
+ /* resize window to "full-screen" */
+ this->width = _screen.width;
+ this->height = _screen.height;
+ this->widget[0].right = this->width - 1;
+ this->widget[0].bottom = this->height - 1;
+
+ this->DrawWidgets();
+
+ /* Center Highscore/Endscreen background */
+ *x = max(0, (_screen.width / 2) - (640 / 2));
+ *y = max(0, (_screen.height / 2) - (480 / 2));
+ for (uint i = 0; i < 10; i++) { // the image is split into 10 50px high parts
+ DrawSprite(this->background_img + i, PAL_NONE, *x, *y + (i * 50));
+ }
+ }
+
+ virtual void OnClick(Point pt, int widget)
+ {
+ delete this;
+ }
+};
/** End game window shown at the end of the game */
-static void EndGameWndProc(Window *w, WindowEvent *e)
-{
- switch (e->event) {
- case WE_PAINT: {
- const Player *p;
- uint x, y;
-
- SetupHighScoreEndWindow(w, &x, &y);
-
- if (!IsValidPlayer(_local_player)) break;
+struct EndGameWindow : EndGameHighScoreBaseWindow {
+ EndGameWindow(const WindowDesc *desc) : EndGameHighScoreBaseWindow(desc)
+ {
+ /* Pause in single-player to have a look at the highscore at your own leisure */
+ if (!_networking) DoCommandP(0, 1, 0, NULL, CMD_PAUSE);
- p = GetPlayer(_local_player);
- /* We need to get performance from last year because the image is shown
- * at the start of the new year when these things have already been copied */
- if (WP(w, highscore_d).background_img == SPR_TYCOON_IMG2_BEGIN) { // Tycoon of the century \o/
- SetDParam(0, p->index);
- SetDParam(1, p->index);
- SetDParam(2, EndGameGetPerformanceTitleFromValue(p->old_economy[0].performance_history));
- DrawStringMultiCenter(x + (640 / 2), y + 107, STR_021C_OF_ACHIEVES_STATUS, 640);
- } else {
- SetDParam(0, p->index);
- SetDParam(1, EndGameGetPerformanceTitleFromValue(p->old_economy[0].performance_history));
- DrawStringMultiCenter(x + (640 / 2), y + 157, STR_021B_ACHIEVES_STATUS, 640);
+ this->background_img = SPR_TYCOON_IMG1_BEGIN;
+
+ if (_local_player != PLAYER_SPECTATOR) {
+ const Player *p = GetPlayer(_local_player);
+ if (p->old_economy[0].performance_history == SCORE_MAX) {
+ this->background_img = SPR_TYCOON_IMG2_BEGIN;
}
- } break;
-
- case WE_CLICK: /* Close the window (and show the highscore window) */
- delete w;
- break;
+ }
- case WE_DESTROY: /* Show the highscore window when this one is closed */
- if (!_networking) DoCommandP(0, 0, 0, NULL, CMD_PAUSE); // unpause
- ShowHighscoreTable(w->window_number, WP(w, highscore_d).rank);
- break;
+ /* In a network game show the endscores of the custom difficulty 'network' which is the last one
+ * as well as generate a TOP5 of that game, and not an all-time top5. */
+ if (_networking) {
+ this->window_number = lengthof(_highscore_table) - 1;
+ this->rank = SaveHighScoreValueNetwork();
+ } else {
+ /* in single player _local player is always valid */
+ const Player *p = GetPlayer(_local_player);
+ this->window_number = _opt.diff_level;
+ this->rank = SaveHighScoreValue(p);
+ }
+
+ MarkWholeScreenDirty();
}
-}
-static void HighScoreWndProc(Window *w, WindowEvent *e)
+ ~EndGameWindow()
+ {
+ if (!_networking) DoCommandP(0, 0, 0, NULL, CMD_PAUSE); // unpause
+ ShowHighscoreTable(this->window_number, this->rank);
+ }
+
+ virtual void OnPaint()
+ {
+ const Player *p;
+ uint x, y;
+
+ this->SetupHighScoreEndWindow(&x, &y);
+
+ if (!IsValidPlayer(_local_player)) return;
+
+ p = GetPlayer(_local_player);
+ /* We need to get performance from last year because the image is shown
+ * at the start of the new year when these things have already been copied */
+ if (this->background_img == SPR_TYCOON_IMG2_BEGIN) { // Tycoon of the century \o/
+ SetDParam(0, p->index);
+ SetDParam(1, p->index);
+ SetDParam(2, EndGameGetPerformanceTitleFromValue(p->old_economy[0].performance_history));
+ DrawStringMultiCenter(x + (640 / 2), y + 107, STR_021C_OF_ACHIEVES_STATUS, 640);
+ } else {
+ SetDParam(0, p->index);
+ SetDParam(1, EndGameGetPerformanceTitleFromValue(p->old_economy[0].performance_history));
+ DrawStringMultiCenter(x + (640 / 2), y + 157, STR_021B_ACHIEVES_STATUS, 640);
+ }
+ }
+};
+
+struct HighScoreWindow : EndGameHighScoreBaseWindow
{
- switch (e->event) {
- case WE_PAINT: {
- const HighScore *hs = _highscore_table[w->window_number];
- uint x, y;
- uint8 i;
-
- SetupHighScoreEndWindow(w, &x, &y);
-
- SetDParam(0, _patches.ending_year);
- SetDParam(1, w->window_number + STR_6801_EASY);
- DrawStringMultiCenter(x + (640 / 2), y + 62, !_networking ? STR_0211_TOP_COMPANIES_WHO_REACHED : STR_TOP_COMPANIES_NETWORK_GAME, 500);
-
- /* Draw Highscore peepz */
- for (i = 0; i < lengthof(_highscore_table[0]); i++) {
- SetDParam(0, i + 1);
- DrawString(x + 40, y + 140 + (i * 55), STR_0212, TC_BLACK);
+ HighScoreWindow(const WindowDesc *desc, int difficulty, int8 ranking) : EndGameHighScoreBaseWindow(desc)
+ {
+ /* pause game to show the chart */
+ if (!_networking) DoCommandP(0, 1, 0, NULL, CMD_PAUSE);
- if (hs[i].company[0] != '\0') {
- TextColour colour = (WP(w, highscore_d).rank == (int8)i) ? TC_RED : TC_BLACK; // draw new highscore in red
-
- DoDrawString(hs[i].company, x + 71, y + 140 + (i * 55), colour);
- SetDParam(0, hs[i].title);
- SetDParam(1, hs[i].score);
- DrawString(x + 71, y + 160 + (i * 55), STR_HIGHSCORE_STATS, colour);
- }
- }
- } break;
+ /* Close all always on-top windows to get a clean screen */
+ if (_game_mode != GM_MENU) HideVitalWindows();
- case WE_CLICK: /* Onclick to close window, and in destroy event handle the rest */
- delete w;
- break;
+ MarkWholeScreenDirty();
+ this->window_number = difficulty; // show highscore chart for difficulty...
+ this->background_img = SPR_HIGHSCORE_CHART_BEGIN; // which background to show
+ this->rank = ranking;
+ }
- case WE_DESTROY: /* Get back all the hidden windows */
- if (_game_mode != GM_MENU) ShowVitalWindows();
+ ~HighScoreWindow()
+ {
+ if (_game_mode != GM_MENU) ShowVitalWindows();
- if (!_networking) DoCommandP(0, 0, 0, NULL, CMD_PAUSE); // unpause
- break;
+ if (!_networking) DoCommandP(0, 0, 0, NULL, CMD_PAUSE); // unpause
+ }
+
+ virtual void OnPaint()
+ {
+ const HighScore *hs = _highscore_table[this->window_number];
+ uint x, y;
+
+ this->SetupHighScoreEndWindow(&x, &y);
+
+ SetDParam(0, _patches.ending_year);
+ SetDParam(1, this->window_number + STR_6801_EASY);
+ DrawStringMultiCenter(x + (640 / 2), y + 62, !_networking ? STR_0211_TOP_COMPANIES_WHO_REACHED : STR_TOP_COMPANIES_NETWORK_GAME, 500);
+
+ /* Draw Highscore peepz */
+ for (uint8 i = 0; i < lengthof(_highscore_table[0]); i++) {
+ SetDParam(0, i + 1);
+ DrawString(x + 40, y + 140 + (i * 55), STR_0212, TC_BLACK);
+
+ if (hs[i].company[0] != '\0') {
+ TextColour colour = (this->rank == i) ? TC_RED : TC_BLACK; // draw new highscore in red
+
+ DoDrawString(hs[i].company, x + 71, y + 140 + (i * 55), colour);
+ SetDParam(0, hs[i].title);
+ SetDParam(1, hs[i].score);
+ DrawString(x + 71, y + 160 + (i * 55), STR_HIGHSCORE_STATS, colour);
+ }
}
-}
+ }
+};
static const Widget _highscore_widgets[] = {
{ WWT_PANEL, RESIZE_NONE, 16, 0, 640, 0, 480, 0x0, STR_NULL},
@@ -1534,7 +1571,6 @@
WC_HIGHSCORE, WC_NONE,
0,
_highscore_widgets,
- HighScoreWndProc
};
static const WindowDesc _endgame_desc = {
@@ -1542,7 +1578,6 @@
WC_ENDSCREEN, WC_NONE,
0,
_highscore_widgets,
- EndGameWndProc
};
/** Show the highscore table for a given difficulty. When called from
@@ -1550,61 +1585,18 @@
* and is thus highlighted */
void ShowHighscoreTable(int difficulty, int8 ranking)
{
- Window *w;
-
- /* pause game to show the chart */
- if (!_networking) DoCommandP(0, 1, 0, NULL, CMD_PAUSE);
-
- /* Close all always on-top windows to get a clean screen */
- if (_game_mode != GM_MENU) HideVitalWindows();
-
DeleteWindowByClass(WC_HIGHSCORE);
- w = new Window(&_highscore_desc);
-
- if (w != NULL) {
- MarkWholeScreenDirty();
- w->window_number = difficulty; // show highscore chart for difficulty...
- WP(w, highscore_d).background_img = SPR_HIGHSCORE_CHART_BEGIN; // which background to show
- WP(w, highscore_d).rank = ranking;
- }
+ new HighScoreWindow(&_highscore_desc, difficulty, ranking);
}
/** Show the endgame victory screen in 2050. Update the new highscore
* if it was high enough */
void ShowEndGameChart()
{
- Window *w;
-
/* Dedicated server doesn't need the highscore window */
if (_network_dedicated) return;
- /* Pause in single-player to have a look at the highscore at your own leisure */
- if (!_networking) DoCommandP(0, 1, 0, NULL, CMD_PAUSE);
HideVitalWindows();
DeleteWindowByClass(WC_ENDSCREEN);
- w = new Window(&_endgame_desc);
-
- if (w != NULL) {
- MarkWholeScreenDirty();
-
- WP(w, highscore_d).background_img = SPR_TYCOON_IMG1_BEGIN;
-
- if (_local_player != PLAYER_SPECTATOR) {
- const Player *p = GetPlayer(_local_player);
- if (p->old_economy[0].performance_history == SCORE_MAX)
- WP(w, highscore_d).background_img = SPR_TYCOON_IMG2_BEGIN;
- }
-
- /* In a network game show the endscores of the custom difficulty 'network' which is the last one
- * as well as generate a TOP5 of that game, and not an all-time top5. */
- if (_networking) {
- w->window_number = lengthof(_highscore_table) - 1;
- WP(w, highscore_d).rank = SaveHighScoreValueNetwork();
- } else {
- /* in single player _local player is always valid */
- const Player *p = GetPlayer(_local_player);
- w->window_number = _opt.diff_level;
- WP(w, highscore_d).rank = SaveHighScoreValue(p);
- }
- }
+ new EndGameWindow(&_endgame_desc);
}
--- a/src/players.cpp Mon May 19 14:14:33 2008 +0000
+++ b/src/players.cpp Mon May 19 15:13:58 2008 +0000
@@ -355,8 +355,11 @@
MarkWholeScreenDirty();
if (!IsHumanPlayer(p->index)) {
- SetDParam(0, t->index);
- AddNewsItem((StringID)(p->index | NB_BNEWCOMPANY), NM_CALLBACK, NF_TILE, NT_COMPANY_INFO, DNC_BANKRUPCY, p->last_build_coordinate, 0);
+ SetDParam(0, STR_705E_NEW_TRANSPORT_COMPANY_LAUNCHED);
+ SetDParam(1, STR_705F_STARTS_CONSTRUCTION_NEAR);
+ SetDParam(2, p->index);
+ SetDParam(3, t->index);
+ AddNewsItem(STR_02B6, NS_COMPANY_NEW, p->last_build_coordinate, p->index);
}
for (PlayerID i = PLAYER_FIRST; i < MAX_PLAYERS; i++) {
if (i != p->index) AI_Event(i, new AIEventCompanyNew(p->index));
@@ -930,8 +933,10 @@
DeletePlayerWindows(p->index);
/* Show the bankrupt news */
- SetDParam(0, p->index);
- AddNewsItem((StringID)(p->index | NB_BBANKRUPT), NM_CALLBACK, NF_NONE, NT_COMPANY_INFO, DNC_BANKRUPCY, 0, 0);
+ SetDParam(0, STR_705C_BANKRUPT);
+ SetDParam(1, STR_705D_HAS_BEEN_CLOSED_DOWN_BY);
+ SetDParam(2, p->index);
+ AddNewsItem(STR_02B6, NS_COMPANY_BANKRUPT, 0, p->index);
/* Remove the company */
ChangeOwnershipOfPlayerItems(p->index, PLAYER_SPECTATOR);
--- a/src/querystring_gui.h Mon May 19 14:14:33 2008 +0000
+++ b/src/querystring_gui.h Mon May 19 15:13:58 2008 +0000
@@ -17,20 +17,20 @@
void DrawEditBox(Window *w, int wid);
void HandleEditBox(Window *w, int wid);
- int HandleEditBoxKey(Window *w, int wid, uint16 key, uint16 keycode, bool &cont);
+ int HandleEditBoxKey(Window *w, int wid, uint16 key, uint16 keycode, Window::EventState &state);
};
struct QueryStringBaseWindow : public Window, public QueryString {
char edit_str_buf[64];
char orig_str_buf[64];
- QueryStringBaseWindow(const WindowDesc *desc, void *data = NULL, WindowNumber window_number = 0) : Window(desc, data, window_number)
+ QueryStringBaseWindow(const WindowDesc *desc, WindowNumber window_number = 0) : Window(desc, window_number)
{
}
void DrawEditBox(int wid);
void HandleEditBox(int wid);
- int HandleEditBoxKey(int wid, uint16 key, uint16 keycode, bool &cont);
+ int HandleEditBoxKey(int wid, uint16 key, uint16 keycode, EventState &state);
};
void ShowOnScreenKeyboard(QueryStringBaseWindow *parent, int button, int cancel, int ok);
--- a/src/rail_cmd.cpp Mon May 19 14:14:33 2008 +0000
+++ b/src/rail_cmd.cpp Mon May 19 15:13:58 2008 +0000
@@ -777,7 +777,7 @@
d->town_index = ClosestTownFromTile(tile, (uint)-1)->index;
AddSideToSignalBuffer(tile, INVALID_DIAGDIR, _current_player);
- YapfNotifyTrackLayoutChange(tile, TrackdirToTrack(DiagdirToDiagTrackdir(dir)));
+ YapfNotifyTrackLayoutChange(tile, DiagDirToDiagTrack(dir));
}
return cost.AddCost(_price.build_train_depot);
@@ -1246,7 +1246,7 @@
case RAIL_TILE_WAYPOINT:
if (flags & DC_EXEC) {
/* notify YAPF about the track layout change */
- YapfNotifyTrackLayoutChange(tile, AxisToTrack(GetWaypointAxis(tile)));
+ YapfNotifyTrackLayoutChange(tile, GetRailWaypointTrack(tile));
}
cost.AddCost(RailConvertCost(type, totype));
break;
@@ -1254,7 +1254,7 @@
case RAIL_TILE_DEPOT:
if (flags & DC_EXEC) {
/* notify YAPF about the track layout change */
- YapfNotifyTrackLayoutChange(tile, AxisToTrack(DiagDirToAxis(GetRailDepotDirection(tile))));
+ YapfNotifyTrackLayoutChange(tile, GetRailDepotTrack(tile));
/* Update build vehicle window related to this depot */
InvalidateWindowData(WC_VEHICLE_DEPOT, tile);
@@ -1295,7 +1295,7 @@
VehicleFromPos(tile, NULL, &UpdateTrainPowerProc);
VehicleFromPos(endtile, NULL, &UpdateTrainPowerProc);
- Track track = AxisToTrack(DiagDirToAxis(GetTunnelBridgeDirection(tile)));
+ Track track = DiagDirToDiagTrack(GetTunnelBridgeDirection(tile));
YapfNotifyTrackLayoutChange(tile, track);
YapfNotifyTrackLayoutChange(endtile, track);
@@ -1344,7 +1344,7 @@
DoClearSquare(tile);
delete GetDepotByTile(tile);
AddSideToSignalBuffer(tile, dir, owner);
- YapfNotifyTrackLayoutChange(tile, TrackdirToTrack(DiagdirToDiagTrackdir(dir)));
+ YapfNotifyTrackLayoutChange(tile, DiagDirToDiagTrack(dir));
}
return CommandCost(EXPENSES_CONSTRUCTION, _price.remove_train_depot);
@@ -2149,7 +2149,7 @@
if (side != INVALID_DIAGDIR && side != dir) break;
- trackbits = AxisToTrackBits(DiagDirToAxis(dir));
+ trackbits = DiagDirToDiagTrackBits(dir);
break;
}
--- a/src/rail_gui.cpp Mon May 19 14:14:33 2008 +0000
+++ b/src/rail_gui.cpp Mon May 19 15:13:58 2008 +0000
@@ -42,25 +42,25 @@
#include "table/sprites.h"
#include "table/strings.h"
-static RailType _cur_railtype;
-static bool _remove_button_clicked;
-static DiagDirection _build_depot_direction;
-static byte _waypoint_count = 1;
-static byte _cur_waypoint_type;
-static bool _convert_signal_button; ///< convert signal button in the signal GUI pressed
-static SignalVariant _cur_signal_variant; ///< set the signal variant (for signal GUI)
-static SignalType _cur_signal_type; ///< set the signal type (for signal GUI)
+static RailType _cur_railtype; ///< Rail type of the current build-rail toolbar.
+static bool _remove_button_clicked; ///< Flag whether 'remove' toggle-button is currently enabled
+static DiagDirection _build_depot_direction; ///< Currently selected depot direction
+static byte _waypoint_count = 1; ///< Number of waypoint types
+static byte _cur_waypoint_type; ///< Currently selected waypoint type
+static bool _convert_signal_button; ///< convert signal button in the signal GUI pressed
+static SignalVariant _cur_signal_variant; ///< set the signal variant (for signal GUI)
+static SignalType _cur_signal_type; ///< set the signal type (for signal GUI)
static struct {
- byte orientation;
- byte numtracks;
- byte platlength;
- bool dragdrop;
+ byte orientation; ///< Currently selected rail station orientation
+ byte numtracks; ///< Currently selected number of tracks in station (if not \c dragdrop )
+ byte platlength; ///< Currently selected platform length of station (if not \c dragdrop )
+ bool dragdrop; ///< Use drag & drop to place a station
- bool newstations;
- StationClassIDByte station_class;
- byte station_type;
- byte station_count;
+ bool newstations; ///< Are custom station definitions available?
+ StationClassIDByte station_class; ///< Currently selected custom station class (if newstations is \c true )
+ byte station_type; ///< Station type within the currently selected custom station class (if newstations is \c true )
+ byte station_count; ///< Number of custom stations (if newstations is \c true )
} _railstation;
@@ -111,6 +111,12 @@
VpStartPlaceSizing(tile, VPM_RAILDIRS, DDSP_PLACE_AUTORAIL);
}
+/**
+ * Try to add an additional rail-track at the entrance of a depot
+ * @param tile Tile to use for adding the rail-track
+ * @param extra Track to add
+ * @see CcRailDepot()
+ */
static void PlaceExtraDepotRail(TileIndex tile, uint16 extra)
{
if (GetRailTileType(tile) != RAIL_TILE_NORMAL) return;
@@ -119,10 +125,11 @@
DoCommandP(tile, _cur_railtype, extra & 0xFF, NULL, CMD_BUILD_SINGLE_RAIL | CMD_NO_WATER);
}
+/** Additional pieces of track to add at the entrance of a depot. */
static const uint16 _place_depot_extra[12] = {
- 0x0604, 0x2102, 0x1202, 0x0505,
- 0x2400, 0x2801, 0x1800, 0x1401,
- 0x2203, 0x0904, 0x0A05, 0x1103,
+ 0x0604, 0x2102, 0x1202, 0x0505, // First additional track for directions 0..3
+ 0x2400, 0x2801, 0x1800, 0x1401, // Second additional track
+ 0x2203, 0x0904, 0x0A05, 0x1103, // Third additional track
};
@@ -235,6 +242,7 @@
VpStartPlaceSizing(tile, VPM_X_OR_Y, DDSP_BUILD_BRIDGE);
}
+/** Command callback for building a tunnel */
void CcBuildRailTunnel(bool success, TileIndex tile, uint32 p1, uint32 p2)
{
if (success) {
@@ -285,7 +293,7 @@
};
-/** Toogles state of the Remove button of Build rail toolbar
+/** Toggles state of the Remove button of Build rail toolbar
* @param w window the button belongs to
*/
static void ToggleRailButton_Remove(Window *w)
@@ -316,36 +324,71 @@
}
+/**
+ * The "rail N"-button click proc of the build-rail toolbar.
+ * @param w Build-rail toolbar window
+ * @see BuildRailToolbWndProc()
+ */
static void BuildRailClick_N(Window *w)
{
HandlePlacePushButton(w, RTW_BUILD_NS, GetRailTypeInfo(_cur_railtype)->cursor.rail_ns, VHM_RECT, PlaceRail_N);
}
+/**
+ * The "rail NE"-button click proc of the build-rail toolbar.
+ * @param w Build-rail toolbar window
+ * @see BuildRailToolbWndProc()
+ */
static void BuildRailClick_NE(Window *w)
{
HandlePlacePushButton(w, RTW_BUILD_X, GetRailTypeInfo(_cur_railtype)->cursor.rail_swne, VHM_RECT, PlaceRail_NE);
}
+/**
+ * The "rail E"-button click proc of the build-rail toolbar.
+ * @param w Build-rail toolbar window
+ * @see BuildRailToolbWndProc()
+ */
static void BuildRailClick_E(Window *w)
{
HandlePlacePushButton(w, RTW_BUILD_EW, GetRailTypeInfo(_cur_railtype)->cursor.rail_ew, VHM_RECT, PlaceRail_E);
}
+/**
+ * The "rail NW"-button click proc of the build-rail toolbar.
+ * @param w Build-rail toolbar window
+ * @see BuildRailToolbWndProc()
+ */
static void BuildRailClick_NW(Window *w)
{
HandlePlacePushButton(w, RTW_BUILD_Y, GetRailTypeInfo(_cur_railtype)->cursor.rail_nwse, VHM_RECT, PlaceRail_NW);
}
+/**
+ * The "auto-rail"-button click proc of the build-rail toolbar.
+ * @param w Build-rail toolbar window
+ * @see BuildRailToolbWndProc()
+ */
static void BuildRailClick_AutoRail(Window *w)
{
HandlePlacePushButton(w, RTW_AUTORAIL, GetRailTypeInfo(_cur_railtype)->cursor.autorail, VHM_RAIL, PlaceRail_AutoRail);
}
+/**
+ * The "demolish"-button click proc of the build-rail toolbar.
+ * @param w Build-rail toolbar window
+ * @see BuildRailToolbWndProc()
+ */
static void BuildRailClick_Demolish(Window *w)
{
HandlePlacePushButton(w, RTW_DEMOLISH, ANIMCURSOR_DEMOLISH, VHM_RECT, PlaceProc_DemolishArea);
}
+/**
+ * The "build depot"-button click proc of the build-rail toolbar.
+ * @param w Build-rail toolbar window
+ * @see BuildRailToolbWndProc()
+ */
static void BuildRailClick_Depot(Window *w)
{
if (HandlePlacePushButton(w, RTW_BUILD_DEPOT, GetRailTypeInfo(_cur_railtype)->cursor.depot, VHM_RECT, PlaceRail_Depot)) {
@@ -353,6 +396,12 @@
}
}
+/**
+ * The "build waypoint"-button click proc of the build-rail toolbar.
+ * If there are newGRF waypoints, also open a window to pick the waypoint type.
+ * @param w Build-rail toolbar window
+ * @see BuildRailToolbWndProc()
+ */
static void BuildRailClick_Waypoint(Window *w)
{
_waypoint_count = GetNumCustomStations(STAT_CLASS_WAYP);
@@ -362,12 +411,22 @@
}
}
+/**
+ * The "build station"-button click proc of the build-rail toolbar.
+ * @param w Build-rail toolbar window
+ * @see BuildRailToolbWndProc()
+ */
static void BuildRailClick_Station(Window *w)
{
if (HandlePlacePushButton(w, RTW_BUILD_STATION, SPR_CURSOR_RAIL_STATION, VHM_RECT, PlaceRail_Station)) ShowStationBuilder();
}
-/** The "build signal"-button proc from BuildRailToolbWndProc() (start ShowSignalBuilder() and/or HandleAutoSignalPlacement()) */
+/**
+ * The "build signal"-button click proc of the build-rail toolbar.
+ * Start ShowSignalBuilder() and/or HandleAutoSignalPlacement().
+ * @param w Build-rail toolbar window
+ * @see BuildRailToolbWndProc()
+ */
static void BuildRailClick_AutoSignals(Window *w)
{
if (_patches.enable_signal_gui != _ctrl_pressed) {
@@ -377,16 +436,31 @@
}
}
+/**
+ * The "build bridge"-button click proc of the build-rail toolbar.
+ * @param w Build-rail toolbar window
+ * @see BuildRailToolbWndProc()
+ */
static void BuildRailClick_Bridge(Window *w)
{
HandlePlacePushButton(w, RTW_BUILD_BRIDGE, SPR_CURSOR_BRIDGE, VHM_RECT, PlaceRail_Bridge);
}
+/**
+ * The "build tunnel"-button click proc of the build-rail toolbar.
+ * @param w Build-rail toolbar window
+ * @see BuildRailToolbWndProc()
+ */
static void BuildRailClick_Tunnel(Window *w)
{
HandlePlacePushButton(w, RTW_BUILD_TUNNEL, GetRailTypeInfo(_cur_railtype)->cursor.tunnel, VHM_SPECIAL, PlaceRail_Tunnel);
}
+/**
+ * The "remove"-button click proc of the build-rail toolbar.
+ * @param w Build-rail toolbar window
+ * @see BuildRailToolbWndProc()
+ */
static void BuildRailClick_Remove(Window *w)
{
if (w->IsWidgetDisabled(RTW_REMOVE)) return;
@@ -416,6 +490,12 @@
}
}
+/**
+ * The "convert-rail"-button click proc of the build-rail toolbar.
+ * Switches to 'convert-rail' mode
+ * @param w Build-rail toolbar window
+ * @see BuildRailToolbWndProc()
+ */
static void BuildRailClick_Convert(Window *w)
{
HandlePlacePushButton(w, RTW_CONVERT_RAIL, GetRailTypeInfo(_cur_railtype)->cursor.convert, VHM_RECT, PlaceRail_ConvertRail);
@@ -526,90 +606,105 @@
};
-static void UpdateRemoveWidgetStatus(Window *w, int clicked_widget)
-{
- switch (clicked_widget) {
- case RTW_REMOVE:
- /* If it is the removal button that has been clicked, do nothing,
- * as it is up to the other buttons to drive removal status */
- return;
- break;
- case RTW_BUILD_NS:
- case RTW_BUILD_X:
- case RTW_BUILD_EW:
- case RTW_BUILD_Y:
- case RTW_AUTORAIL:
- case RTW_BUILD_WAYPOINT:
- case RTW_BUILD_STATION:
- case RTW_BUILD_SIGNALS:
- /* Removal button is enabled only if the rail/signal/waypoint/station
- * button is still lowered. Once raised, it has to be disabled */
- w->SetWidgetDisabledState(RTW_REMOVE, !w->IsWidgetLowered(clicked_widget));
- break;
-
- default:
- /* When any other buttons than rail/signal/waypoint/station, raise and
- * disable the removal button */
- w->DisableWidget(RTW_REMOVE);
- w->RaiseWidget(RTW_REMOVE);
- break;
- }
-}
+/**
+ * Based on the widget clicked, update the status of the 'remove' button.
+ * @param w Rail toolbar window
+ * @param clicked_widget Widget clicked in the toolbar
+ */
+struct BuildRailToolbarWindow : Window {
+ BuildRailToolbarWindow(const WindowDesc *desc, WindowNumber window_number) : Window(desc, window_number)
+ {
+ this->DisableWidget(RTW_REMOVE);
-/**
- * Railway toolbar window event definition
- *
- * @param w window pointer
- * @param e event been triggered
- */
-static void BuildRailToolbWndProc(Window *w, WindowEvent *e)
-{
- switch (e->event) {
- case WE_CREATE: w->DisableWidget(RTW_REMOVE); break;
-
- case WE_PAINT: DrawWindowWidgets(w); break;
+ this->FindWindowPlacementAndResize(desc);
+ if (_patches.link_terraform_toolbar) ShowTerraformToolbar(this);
+ }
- case WE_CLICK:
- if (e->we.click.widget >= RTW_BUILD_NS) {
- _remove_button_clicked = false;
- _build_railroad_button_proc[e->we.click.widget - RTW_BUILD_NS](w);
+ ~BuildRailToolbarWindow()
+ {
+ if (_patches.link_terraform_toolbar) DeleteWindowById(WC_SCEN_LAND_GEN, 0);
+ }
+
+ void UpdateRemoveWidgetStatus(int clicked_widget)
+ {
+ switch (clicked_widget) {
+ case RTW_REMOVE:
+ /* If it is the removal button that has been clicked, do nothing,
+ * as it is up to the other buttons to drive removal status */
+ return;
+ break;
+ case RTW_BUILD_NS:
+ case RTW_BUILD_X:
+ case RTW_BUILD_EW:
+ case RTW_BUILD_Y:
+ case RTW_AUTORAIL:
+ case RTW_BUILD_WAYPOINT:
+ case RTW_BUILD_STATION:
+ case RTW_BUILD_SIGNALS:
+ /* Removal button is enabled only if the rail/signal/waypoint/station
+ * button is still lowered. Once raised, it has to be disabled */
+ this->SetWidgetDisabledState(RTW_REMOVE, !this->IsWidgetLowered(clicked_widget));
+ break;
+
+ default:
+ /* When any other buttons than rail/signal/waypoint/station, raise and
+ * disable the removal button */
+ this->DisableWidget(RTW_REMOVE);
+ this->RaiseWidget(RTW_REMOVE);
+ break;
}
- UpdateRemoveWidgetStatus(w, e->we.click.widget);
- if (_ctrl_pressed) RailToolbar_CtrlChanged(w);
- break;
+ }
- case WE_KEYPRESS:
+ virtual void OnPaint()
+ {
+ this->DrawWidgets();
+ }
+
+ virtual void OnClick(Point pt, int widget)
+ {
+ if (widget >= RTW_BUILD_NS) {
+ _remove_button_clicked = false;
+ _build_railroad_button_proc[widget - RTW_BUILD_NS](this);
+ }
+ this->UpdateRemoveWidgetStatus(widget);
+ if (_ctrl_pressed) RailToolbar_CtrlChanged(this);
+ }
+
+ virtual EventState OnKeyPress(uint16 key, uint16 keycode)
+ {
+ EventState state = ES_NOT_HANDLED;
for (uint8 i = 0; i != lengthof(_rail_keycodes); i++) {
- if (e->we.keypress.keycode == _rail_keycodes[i]) {
- e->we.keypress.cont = false;
+ if (keycode == _rail_keycodes[i]) {
_remove_button_clicked = false;
- _build_railroad_button_proc[i](w);
- UpdateRemoveWidgetStatus(w, i + RTW_BUILD_NS);
- if (_ctrl_pressed) RailToolbar_CtrlChanged(w);
+ _build_railroad_button_proc[i](this);
+ this->UpdateRemoveWidgetStatus(i + RTW_BUILD_NS);
+ if (_ctrl_pressed) RailToolbar_CtrlChanged(this);
+ state = ES_HANDLED;
break;
}
}
MarkTileDirty(_thd.pos.x, _thd.pos.y); // redraw tile selection
- break;
-
- case WE_PLACE_OBJ:
- _place_proc(e->we.place.tile);
- return;
-
- case WE_PLACE_DRAG: {
- /* no dragging if you have pressed the convert button */
- if (FindWindowById(WC_BUILD_SIGNAL, 0) != NULL && _convert_signal_button && w->IsWidgetLowered(RTW_BUILD_SIGNALS)) return;
-
- VpSelectTilesWithMethod(e->we.place.pt.x, e->we.place.pt.y, e->we.place.select_method);
- return;
+ return state;
}
- case WE_PLACE_MOUSEUP:
- if (e->we.place.pt.x != -1) {
- TileIndex start_tile = e->we.place.starttile;
- TileIndex end_tile = e->we.place.tile;
+ virtual void OnPlaceObject(Point pt, TileIndex tile)
+ {
+ _place_proc(tile);
+ }
- switch (e->we.place.select_proc) {
+ virtual void OnPlaceDrag(ViewportPlaceMethod select_method, ViewportDragDropSelectionProcess select_proc, Point pt)
+ {
+ /* no dragging if you have pressed the convert button */
+ if (FindWindowById(WC_BUILD_SIGNAL, 0) != NULL && _convert_signal_button && this->IsWidgetLowered(RTW_BUILD_SIGNALS)) return;
+
+ VpSelectTilesWithMethod(pt.x, pt.y, select_method);
+ }
+
+ virtual void OnPlaceMouseUp(ViewportPlaceMethod select_method, ViewportDragDropSelectionProcess select_proc, Point pt, TileIndex start_tile, TileIndex end_tile)
+ {
+ if (pt.x != -1) {
+ switch (select_proc) {
+ default: NOT_REACHED();
case DDSP_BUILD_BRIDGE:
ResetObjectToPlace();
ShowBuildBridgeWindow(start_tile, end_tile, TRANSPORT_RAIL, _cur_railtype);
@@ -624,7 +719,7 @@
break;
case DDSP_DEMOLISH_AREA:
- GUIPlaceProcDragXY(e);
+ GUIPlaceProcDragXY(select_proc, start_tile, end_tile);
break;
case DDSP_CONVERT_RAIL:
@@ -642,42 +737,36 @@
case DDSP_PLACE_RAIL_NE:
case DDSP_PLACE_RAIL_NW:
- DoRailroadTrack(e->we.place.select_proc == DDSP_PLACE_RAIL_NE ? TRACK_X : TRACK_Y);
+ DoRailroadTrack(select_proc == DDSP_PLACE_RAIL_NE ? TRACK_X : TRACK_Y);
break;
}
}
- break;
-
- case WE_ABORT_PLACE_OBJ:
- w->RaiseButtons();
- w->DisableWidget(RTW_REMOVE);
- w->InvalidateWidget(RTW_REMOVE);
+ }
- w = FindWindowById(WC_BUILD_SIGNAL, 0);
- if (w != NULL) WP(w, def_d).close = true;
- w = FindWindowById(WC_BUILD_STATION, 0);
- if (w != NULL) WP(w, def_d).close = true;
- w = FindWindowById(WC_BUILD_DEPOT, 0);
- if (w != NULL) WP(w, def_d).close = true;
- break;
+ virtual void OnPlaceObjectAbort()
+ {
+ this->RaiseButtons();
+ this->DisableWidget(RTW_REMOVE);
+ this->InvalidateWidget(RTW_REMOVE);
- case WE_PLACE_PRESIZE: {
- TileIndex tile = e->we.place.tile;
+ delete FindWindowById(WC_BUILD_SIGNAL, 0);
+ delete FindWindowById(WC_BUILD_STATION, 0);
+ delete FindWindowById(WC_BUILD_DEPOT, 0);
+ }
+ virtual void OnPlacePresize(Point pt, TileIndex tile)
+ {
DoCommand(tile, 0, 0, DC_AUTO, CMD_BUILD_TUNNEL);
VpSetPresizeRange(tile, _build_tunnel_endtile == 0 ? tile : _build_tunnel_endtile);
- } break;
-
- case WE_DESTROY:
- if (_patches.link_terraform_toolbar) DeleteWindowById(WC_SCEN_LAND_GEN, 0);
- break;
+ }
- case WE_CTRL_CHANGED:
+ virtual EventState OnCTRLStateChange()
+ {
/* do not toggle Remove button by Ctrl when placing station */
- if (!w->IsWidgetLowered(RTW_BUILD_STATION) && RailToolbar_CtrlChanged(w)) e->we.ctrl.cont = false;
- break;
+ if (!this->IsWidgetLowered(RTW_BUILD_STATION) && RailToolbar_CtrlChanged(this)) return ES_HANDLED;
+ return ES_NOT_HANDLED;
}
-}
+};
/** Widget definition for the rail toolbar */
static const Widget _build_rail_widgets[] = {
@@ -712,7 +801,6 @@
WC_BUILD_TOOLBAR, WC_NONE,
WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_STICKY_BUTTON,
_build_rail_widgets,
- BuildRailToolbWndProc
};
@@ -736,66 +824,39 @@
w->widget[RTW_BUILD_TUNNEL].data = rti->gui_sprites.build_tunnel;
}
+/**
+ * Open the build rail toolbar window for a specific rail type.
+ * The window may be opened in the 'normal' way by clicking at the rail icon in
+ * the main toolbar, or by means of selecting one of the functions of the
+ * toolbar. In the latter case, the corresponding widget is also selected.
+ *
+ * If the terraform toolbar is linked to the toolbar, that window is also opened.
+ *
+ * @param railtype Rail type to open the window for
+ * @param button Widget clicked (\c -1 means no button clicked)
+ */
void ShowBuildRailToolbar(RailType railtype, int button)
{
- Window *w;
+ BuildRailToolbarWindow *w;
if (!IsValidPlayer(_current_player)) return;
if (!ValParamRailtype(railtype)) return;
// don't recreate the window if we're clicking on a button and the window exists.
- if (button < 0 || !(w = FindWindowById(WC_BUILD_TOOLBAR, TRANSPORT_RAIL))) {
+ if (button < 0 || !(w = dynamic_cast<BuildRailToolbarWindow*>(FindWindowById(WC_BUILD_TOOLBAR, TRANSPORT_RAIL)))) {
DeleteWindowByClass(WC_BUILD_TOOLBAR);
_cur_railtype = railtype;
- w = AllocateWindowDescFront<Window>(&_build_rail_desc, TRANSPORT_RAIL);
+ w = AllocateWindowDescFront<BuildRailToolbarWindow>(&_build_rail_desc, TRANSPORT_RAIL);
SetupRailToolbar(railtype, w);
}
_remove_button_clicked = false;
if (w != NULL && button >= RTW_CLOSEBOX) {
_build_railroad_button_proc[button](w);
- UpdateRemoveWidgetStatus(w, button + RTW_BUILD_NS);
+ w->UpdateRemoveWidgetStatus(button + RTW_BUILD_NS);
}
- if (_patches.link_terraform_toolbar) ShowTerraformToolbar(w);
}
-/** Enum referring to the widgets of the rail stations window */
-enum BuildRailStationWidgets {
- BRSW_CLOSEBOX = 0,
- BRSW_CAPTION,
- BRSW_BACKGROUND,
-
- BRSW_PLATFORM_DIR_X,
- BRSW_PLATFORM_DIR_Y,
-
- BRSW_PLATFORM_NUM_BEGIN = BRSW_PLATFORM_DIR_Y,
- BRSW_PLATFORM_NUM_1,
- BRSW_PLATFORM_NUM_2,
- BRSW_PLATFORM_NUM_3,
- BRSW_PLATFORM_NUM_4,
- BRSW_PLATFORM_NUM_5,
- BRSW_PLATFORM_NUM_6,
- BRSW_PLATFORM_NUM_7,
-
- BRSW_PLATFORM_LEN_BEGIN = BRSW_PLATFORM_NUM_7,
- BRSW_PLATFORM_LEN_1,
- BRSW_PLATFORM_LEN_2,
- BRSW_PLATFORM_LEN_3,
- BRSW_PLATFORM_LEN_4,
- BRSW_PLATFORM_LEN_5,
- BRSW_PLATFORM_LEN_6,
- BRSW_PLATFORM_LEN_7,
-
- BRSW_PLATFORM_DRAG_N_DROP,
-
- BRSW_HIGHLIGHT_OFF,
- BRSW_HIGHLIGHT_ON,
-
- BRSW_NEWST_DROPDOWN,
- BRSW_NEWST_LIST,
- BRSW_NEWST_SCROLL
-};
-
/* TODO: For custom stations, respect their allowed platforms/lengths bitmasks!
* --pasky */
@@ -819,64 +880,124 @@
CMD_BUILD_RAILROAD_STATION | CMD_NO_WATER | CMD_MSG(STR_100F_CAN_T_BUILD_RAILROAD_STATION));
}
-/* Check if the currently selected station size is allowed */
-static void CheckSelectedSize(Window *w, const StationSpec *statspec)
-{
- if (statspec == NULL || _railstation.dragdrop) return;
+struct BuildRailStationWindow : public PickerWindowBase {
+private:
+ /** Enum referring to the widgets of the rail stations window */
+ enum BuildRailStationWidgets {
+ BRSW_CLOSEBOX = 0,
+ BRSW_CAPTION,
+ BRSW_BACKGROUND,
- if (HasBit(statspec->disallowed_platforms, _railstation.numtracks - 1)) {
- w->RaiseWidget(_railstation.numtracks + BRSW_PLATFORM_NUM_BEGIN);
- _railstation.numtracks = 1;
- while (HasBit(statspec->disallowed_platforms, _railstation.numtracks - 1)) {
- _railstation.numtracks++;
+ BRSW_PLATFORM_DIR_X,
+ BRSW_PLATFORM_DIR_Y,
+
+ BRSW_PLATFORM_NUM_BEGIN = BRSW_PLATFORM_DIR_Y,
+ BRSW_PLATFORM_NUM_1,
+ BRSW_PLATFORM_NUM_2,
+ BRSW_PLATFORM_NUM_3,
+ BRSW_PLATFORM_NUM_4,
+ BRSW_PLATFORM_NUM_5,
+ BRSW_PLATFORM_NUM_6,
+ BRSW_PLATFORM_NUM_7,
+
+ BRSW_PLATFORM_LEN_BEGIN = BRSW_PLATFORM_NUM_7,
+ BRSW_PLATFORM_LEN_1,
+ BRSW_PLATFORM_LEN_2,
+ BRSW_PLATFORM_LEN_3,
+ BRSW_PLATFORM_LEN_4,
+ BRSW_PLATFORM_LEN_5,
+ BRSW_PLATFORM_LEN_6,
+ BRSW_PLATFORM_LEN_7,
+
+ BRSW_PLATFORM_DRAG_N_DROP,
+
+ BRSW_HIGHLIGHT_OFF,
+ BRSW_HIGHLIGHT_ON,
+
+ BRSW_NEWST_DROPDOWN,
+ BRSW_NEWST_LIST,
+ BRSW_NEWST_SCROLL
+ };
+
+ /**
+ * Verify whether the currently selected station size is allowed after selecting a new station class/type.
+ * If not, change the station size variables ( _railstation.numtracks and _railstation.platlength ).
+ * @param statspec Specification of the new station class/type
+ */
+ void CheckSelectedSize(const StationSpec *statspec)
+ {
+ if (statspec == NULL || _railstation.dragdrop) return;
+
+ /* If current number of tracks is not allowed, make it as big as possible (which is always less than currently selected) */
+ if (HasBit(statspec->disallowed_platforms, _railstation.numtracks - 1)) {
+ this->RaiseWidget(_railstation.numtracks + BRSW_PLATFORM_NUM_BEGIN);
+ _railstation.numtracks = 1;
+ while (HasBit(statspec->disallowed_platforms, _railstation.numtracks - 1)) {
+ _railstation.numtracks++;
+ }
+ this->LowerWidget(_railstation.numtracks + BRSW_PLATFORM_NUM_BEGIN);
}
- w->LowerWidget(_railstation.numtracks + BRSW_PLATFORM_NUM_BEGIN);
+
+ if (HasBit(statspec->disallowed_lengths, _railstation.platlength - 1)) {
+ this->RaiseWidget(_railstation.platlength + BRSW_PLATFORM_LEN_BEGIN);
+ _railstation.platlength = 1;
+ while (HasBit(statspec->disallowed_lengths, _railstation.platlength - 1)) {
+ _railstation.platlength++;
+ }
+ this->LowerWidget(_railstation.platlength + BRSW_PLATFORM_LEN_BEGIN);
+ }
}
- if (HasBit(statspec->disallowed_lengths, _railstation.platlength - 1)) {
- w->RaiseWidget(_railstation.platlength + BRSW_PLATFORM_LEN_BEGIN);
- _railstation.platlength = 1;
- while (HasBit(statspec->disallowed_lengths, _railstation.platlength - 1)) {
- _railstation.platlength++;
+ /** Build a dropdown list of available station classes */
+ static DropDownList *BuildStationClassDropDown()
+ {
+ DropDownList *list = new DropDownList();
+
+ for (uint i = 0; i < GetNumStationClasses(); i++) {
+ if (i == STAT_CLASS_WAYP) continue;
+ list->push_back(new DropDownListStringItem(GetStationClassName((StationClassID)i), i, false));
}
- w->LowerWidget(_railstation.platlength + BRSW_PLATFORM_LEN_BEGIN);
+
+ return list;
}
-}
+/**
+ * Window event handler of station build window.
+ * @param w Staion build window
+ * @param e Window event to handle
+ */
-static DropDownList *BuildStationClassDropDown()
-{
- DropDownList *list = new DropDownList();
+public:
+ BuildRailStationWindow(const WindowDesc *desc, bool newstation) : PickerWindowBase(desc)
+ {
+ this->LowerWidget(_railstation.orientation + BRSW_PLATFORM_DIR_X);
+ if (_railstation.dragdrop) {
+ this->LowerWidget(BRSW_PLATFORM_DRAG_N_DROP);
+ } else {
+ this->LowerWidget(_railstation.numtracks + BRSW_PLATFORM_NUM_BEGIN);
+ this->LowerWidget(_railstation.platlength + BRSW_PLATFORM_LEN_BEGIN);
+ }
+ this->SetWidgetLoweredState(BRSW_HIGHLIGHT_OFF, !_station_show_coverage);
+ this->SetWidgetLoweredState(BRSW_HIGHLIGHT_ON, _station_show_coverage);
- for (uint i = 0; i < GetNumStationClasses(); i++) {
- if (i == STAT_CLASS_WAYP) continue;
- list->push_back(new DropDownListStringItem(GetStationClassName((StationClassID)i), i, false));
+ this->FindWindowPlacementAndResize(desc);
+
+ _railstation.newstations = newstation;
+
+ if (newstation) {
+ _railstation.station_count = GetNumCustomStations(_railstation.station_class);
+
+ this->vscroll.count = _railstation.station_count;
+ this->vscroll.cap = 5;
+ this->vscroll.pos = Clamp(_railstation.station_type - 2, 0, this->vscroll.count - this->vscroll.cap);
+ }
}
- return list;
-}
-
-static void StationBuildWndProc(Window *w, WindowEvent *e)
-{
- switch (e->event) {
- case WE_CREATE:
- w->LowerWidget(_railstation.orientation + BRSW_PLATFORM_DIR_X);
- if (_railstation.dragdrop) {
- w->LowerWidget(BRSW_PLATFORM_DRAG_N_DROP);
- } else {
- w->LowerWidget(_railstation.numtracks + BRSW_PLATFORM_NUM_BEGIN);
- w->LowerWidget(_railstation.platlength + BRSW_PLATFORM_LEN_BEGIN);
- }
- w->SetWidgetLoweredState(BRSW_HIGHLIGHT_OFF, !_station_show_coverage);
- w->SetWidgetLoweredState(BRSW_HIGHLIGHT_ON, _station_show_coverage);
- break;
-
- case WE_PAINT: {
+ virtual void OnPaint()
+ {
bool newstations = _railstation.newstations;
DrawPixelInfo tmp_dpi, *old_dpi;
const StationSpec *statspec = newstations ? GetCustomStationSpec(_railstation.station_class, _railstation.station_type) : NULL;
- if (WP(w, def_d).close) return;
-
if (_railstation.dragdrop) {
SetTileSelectSize(1, 1);
} else {
@@ -895,16 +1016,16 @@
for (uint bits = 0; bits < 7; bits++) {
bool disable = bits >= _patches.station_spread;
if (statspec == NULL) {
- w->SetWidgetDisabledState(bits + BRSW_PLATFORM_NUM_1, disable);
- w->SetWidgetDisabledState(bits + BRSW_PLATFORM_LEN_1, disable);
+ this->SetWidgetDisabledState(bits + BRSW_PLATFORM_NUM_1, disable);
+ this->SetWidgetDisabledState(bits + BRSW_PLATFORM_LEN_1, disable);
} else {
- w->SetWidgetDisabledState(bits + BRSW_PLATFORM_NUM_1, HasBit(statspec->disallowed_platforms, bits) || disable);
- w->SetWidgetDisabledState(bits + BRSW_PLATFORM_LEN_1, HasBit(statspec->disallowed_lengths, bits) || disable);
+ this->SetWidgetDisabledState(bits + BRSW_PLATFORM_NUM_1, HasBit(statspec->disallowed_platforms, bits) || disable);
+ this->SetWidgetDisabledState(bits + BRSW_PLATFORM_LEN_1, HasBit(statspec->disallowed_lengths, bits) || disable);
}
}
SetDParam(0, GetStationClassName(_railstation.station_class));
- DrawWindowWidgets(w);
+ this->DrawWidgets();
int y_offset = newstations ? 90 : 0;
@@ -935,16 +1056,16 @@
int text_end = DrawStationCoverageAreaText(2, 166 + y_offset, SCT_ALL, rad, false);
text_end = DrawStationCoverageAreaText(2, text_end + 4, SCT_ALL, rad, true) + 4;
- if (text_end != w->widget[BRSW_BACKGROUND].bottom) {
- w->SetDirty();
- ResizeWindowForWidget(w, BRSW_BACKGROUND, 0, text_end - w->widget[BRSW_BACKGROUND].bottom);
- w->SetDirty();
+ if (text_end != this->widget[BRSW_BACKGROUND].bottom) {
+ this->SetDirty();
+ ResizeWindowForWidget(this, BRSW_BACKGROUND, 0, text_end - this->widget[BRSW_BACKGROUND].bottom);
+ this->SetDirty();
}
if (newstations) {
uint y = 35;
- for (uint16 i = w->vscroll.pos; i < _railstation.station_count && i < (uint)(w->vscroll.pos + w->vscroll.cap); i++) {
+ for (uint16 i = this->vscroll.pos; i < _railstation.station_count && i < (uint)(this->vscroll.pos + this->vscroll.cap); i++) {
const StationSpec *statspec = GetCustomStationSpec(_railstation.station_class, i);
if (statspec != NULL && statspec->name != 0) {
@@ -960,181 +1081,175 @@
y += 14;
}
}
- } break;
-
- case WE_CLICK: {
- switch (e->we.click.widget) {
- case BRSW_PLATFORM_DIR_X:
- case BRSW_PLATFORM_DIR_Y:
- w->RaiseWidget(_railstation.orientation + BRSW_PLATFORM_DIR_X);
- _railstation.orientation = e->we.click.widget - BRSW_PLATFORM_DIR_X;
- w->LowerWidget(_railstation.orientation + BRSW_PLATFORM_DIR_X);
- SndPlayFx(SND_15_BEEP);
- w->SetDirty();
- break;
+ }
- case BRSW_PLATFORM_NUM_1:
- case BRSW_PLATFORM_NUM_2:
- case BRSW_PLATFORM_NUM_3:
- case BRSW_PLATFORM_NUM_4:
- case BRSW_PLATFORM_NUM_5:
- case BRSW_PLATFORM_NUM_6:
- case BRSW_PLATFORM_NUM_7: {
- w->RaiseWidget(_railstation.numtracks + BRSW_PLATFORM_NUM_BEGIN);
- w->RaiseWidget(BRSW_PLATFORM_DRAG_N_DROP);
+ virtual void OnClick(Point pt, int widget)
+ {
+ switch (widget) {
+ case BRSW_PLATFORM_DIR_X:
+ case BRSW_PLATFORM_DIR_Y:
+ this->RaiseWidget(_railstation.orientation + BRSW_PLATFORM_DIR_X);
+ _railstation.orientation = widget - BRSW_PLATFORM_DIR_X;
+ this->LowerWidget(_railstation.orientation + BRSW_PLATFORM_DIR_X);
+ SndPlayFx(SND_15_BEEP);
+ this->SetDirty();
+ break;
- _railstation.numtracks = e->we.click.widget - BRSW_PLATFORM_NUM_BEGIN;
- _railstation.dragdrop = false;
+ case BRSW_PLATFORM_NUM_1:
+ case BRSW_PLATFORM_NUM_2:
+ case BRSW_PLATFORM_NUM_3:
+ case BRSW_PLATFORM_NUM_4:
+ case BRSW_PLATFORM_NUM_5:
+ case BRSW_PLATFORM_NUM_6:
+ case BRSW_PLATFORM_NUM_7: {
+ this->RaiseWidget(_railstation.numtracks + BRSW_PLATFORM_NUM_BEGIN);
+ this->RaiseWidget(BRSW_PLATFORM_DRAG_N_DROP);
- const StationSpec *statspec = _railstation.newstations ? GetCustomStationSpec(_railstation.station_class, _railstation.station_type) : NULL;
- if (statspec != NULL && HasBit(statspec->disallowed_lengths, _railstation.platlength - 1)) {
- /* The previously selected number of platforms in invalid */
- for (uint i = 0; i < 7; i++) {
- if (!HasBit(statspec->disallowed_lengths, i)) {
- w->RaiseWidget(_railstation.platlength + BRSW_PLATFORM_LEN_BEGIN);
- _railstation.platlength = i + 1;
- break;
+ _railstation.numtracks = widget - BRSW_PLATFORM_NUM_BEGIN;
+ _railstation.dragdrop = false;
+
+ const StationSpec *statspec = _railstation.newstations ? GetCustomStationSpec(_railstation.station_class, _railstation.station_type) : NULL;
+ if (statspec != NULL && HasBit(statspec->disallowed_lengths, _railstation.platlength - 1)) {
+ /* The previously selected number of platforms in invalid */
+ for (uint i = 0; i < 7; i++) {
+ if (!HasBit(statspec->disallowed_lengths, i)) {
+ this->RaiseWidget(_railstation.platlength + BRSW_PLATFORM_LEN_BEGIN);
+ _railstation.platlength = i + 1;
+ break;
+ }
}
}
- }
-
- w->LowerWidget(_railstation.numtracks + BRSW_PLATFORM_NUM_BEGIN);
- w->LowerWidget(_railstation.platlength + BRSW_PLATFORM_LEN_BEGIN);
- SndPlayFx(SND_15_BEEP);
- w->SetDirty();
- break;
- }
- case BRSW_PLATFORM_LEN_1:
- case BRSW_PLATFORM_LEN_2:
- case BRSW_PLATFORM_LEN_3:
- case BRSW_PLATFORM_LEN_4:
- case BRSW_PLATFORM_LEN_5:
- case BRSW_PLATFORM_LEN_6:
- case BRSW_PLATFORM_LEN_7: {
- w->RaiseWidget(_railstation.platlength + BRSW_PLATFORM_LEN_BEGIN);
- w->RaiseWidget(BRSW_PLATFORM_DRAG_N_DROP);
-
- _railstation.platlength = e->we.click.widget - BRSW_PLATFORM_LEN_BEGIN;
- _railstation.dragdrop = false;
-
- const StationSpec *statspec = _railstation.newstations ? GetCustomStationSpec(_railstation.station_class, _railstation.station_type) : NULL;
- if (statspec != NULL && HasBit(statspec->disallowed_platforms, _railstation.numtracks - 1)) {
- /* The previously selected number of tracks in invalid */
- for (uint i = 0; i < 7; i++) {
- if (!HasBit(statspec->disallowed_platforms, i)) {
- w->RaiseWidget(_railstation.numtracks + BRSW_PLATFORM_NUM_BEGIN);
- _railstation.numtracks = i + 1;
- break;
- }
- }
+ this->LowerWidget(_railstation.numtracks + BRSW_PLATFORM_NUM_BEGIN);
+ this->LowerWidget(_railstation.platlength + BRSW_PLATFORM_LEN_BEGIN);
+ SndPlayFx(SND_15_BEEP);
+ this->SetDirty();
+ break;
}
- w->LowerWidget(_railstation.numtracks + BRSW_PLATFORM_NUM_BEGIN);
- w->LowerWidget(_railstation.platlength + BRSW_PLATFORM_LEN_BEGIN);
- SndPlayFx(SND_15_BEEP);
- w->SetDirty();
- break;
- }
+ case BRSW_PLATFORM_LEN_1:
+ case BRSW_PLATFORM_LEN_2:
+ case BRSW_PLATFORM_LEN_3:
+ case BRSW_PLATFORM_LEN_4:
+ case BRSW_PLATFORM_LEN_5:
+ case BRSW_PLATFORM_LEN_6:
+ case BRSW_PLATFORM_LEN_7: {
+ this->RaiseWidget(_railstation.platlength + BRSW_PLATFORM_LEN_BEGIN);
+ this->RaiseWidget(BRSW_PLATFORM_DRAG_N_DROP);
- case BRSW_PLATFORM_DRAG_N_DROP: {
- _railstation.dragdrop ^= true;
- w->ToggleWidgetLoweredState(BRSW_PLATFORM_DRAG_N_DROP);
+ _railstation.platlength = widget - BRSW_PLATFORM_LEN_BEGIN;
+ _railstation.dragdrop = false;
- /* get the first allowed length/number of platforms */
- const StationSpec *statspec = _railstation.newstations ? GetCustomStationSpec(_railstation.station_class, _railstation.station_type) : NULL;
- if (statspec != NULL && HasBit(statspec->disallowed_lengths, _railstation.platlength - 1)) {
- for (uint i = 0; i < 7; i++) {
- if (!HasBit(statspec->disallowed_lengths, i)) {
- w->RaiseWidget(_railstation.platlength + BRSW_PLATFORM_LEN_BEGIN);
- _railstation.platlength = i + 1;
- break;
+ const StationSpec *statspec = _railstation.newstations ? GetCustomStationSpec(_railstation.station_class, _railstation.station_type) : NULL;
+ if (statspec != NULL && HasBit(statspec->disallowed_platforms, _railstation.numtracks - 1)) {
+ /* The previously selected number of tracks in invalid */
+ for (uint i = 0; i < 7; i++) {
+ if (!HasBit(statspec->disallowed_platforms, i)) {
+ this->RaiseWidget(_railstation.numtracks + BRSW_PLATFORM_NUM_BEGIN);
+ _railstation.numtracks = i + 1;
+ break;
+ }
}
}
- }
- if (statspec != NULL && HasBit(statspec->disallowed_platforms, _railstation.numtracks - 1)) {
- for (uint i = 0; i < 7; i++) {
- if (!HasBit(statspec->disallowed_platforms, i)) {
- w->RaiseWidget(_railstation.numtracks + BRSW_PLATFORM_NUM_BEGIN);
- _railstation.numtracks = i + 1;
- break;
- }
- }
+
+ this->LowerWidget(_railstation.numtracks + BRSW_PLATFORM_NUM_BEGIN);
+ this->LowerWidget(_railstation.platlength + BRSW_PLATFORM_LEN_BEGIN);
+ SndPlayFx(SND_15_BEEP);
+ this->SetDirty();
+ break;
}
- w->SetWidgetLoweredState(_railstation.numtracks + BRSW_PLATFORM_NUM_BEGIN, !_railstation.dragdrop);
- w->SetWidgetLoweredState(_railstation.platlength + BRSW_PLATFORM_LEN_BEGIN, !_railstation.dragdrop);
- SndPlayFx(SND_15_BEEP);
- w->SetDirty();
- } break;
-
- case BRSW_HIGHLIGHT_OFF:
- case BRSW_HIGHLIGHT_ON:
- _station_show_coverage = (e->we.click.widget != BRSW_HIGHLIGHT_OFF);
- w->SetWidgetLoweredState(BRSW_HIGHLIGHT_OFF, !_station_show_coverage);
- w->SetWidgetLoweredState(BRSW_HIGHLIGHT_ON, _station_show_coverage);
- SndPlayFx(SND_15_BEEP);
- w->SetDirty();
- break;
-
- case BRSW_NEWST_DROPDOWN:
- ShowDropDownList(w, BuildStationClassDropDown(), _railstation.station_class, BRSW_NEWST_DROPDOWN);
- break;
-
- case BRSW_NEWST_LIST: {
- const StationSpec *statspec;
- int y = (e->we.click.pt.y - 32) / 14;
+ case BRSW_PLATFORM_DRAG_N_DROP: {
+ _railstation.dragdrop ^= true;
+ this->ToggleWidgetLoweredState(BRSW_PLATFORM_DRAG_N_DROP);
- if (y >= w->vscroll.cap) return;
- y += w->vscroll.pos;
- if (y >= _railstation.station_count) return;
-
- /* Check station availability callback */
- statspec = GetCustomStationSpec(_railstation.station_class, y);
- if (statspec != NULL &&
- HasBit(statspec->callbackmask, CBM_STATION_AVAIL) &&
- GB(GetStationCallback(CBID_STATION_AVAILABILITY, 0, 0, statspec, NULL, INVALID_TILE), 0, 8) == 0) return;
-
- _railstation.station_type = y;
+ /* get the first allowed length/number of platforms */
+ const StationSpec *statspec = _railstation.newstations ? GetCustomStationSpec(_railstation.station_class, _railstation.station_type) : NULL;
+ if (statspec != NULL && HasBit(statspec->disallowed_lengths, _railstation.platlength - 1)) {
+ for (uint i = 0; i < 7; i++) {
+ if (!HasBit(statspec->disallowed_lengths, i)) {
+ this->RaiseWidget(_railstation.platlength + BRSW_PLATFORM_LEN_BEGIN);
+ _railstation.platlength = i + 1;
+ break;
+ }
+ }
+ }
+ if (statspec != NULL && HasBit(statspec->disallowed_platforms, _railstation.numtracks - 1)) {
+ for (uint i = 0; i < 7; i++) {
+ if (!HasBit(statspec->disallowed_platforms, i)) {
+ this->RaiseWidget(_railstation.numtracks + BRSW_PLATFORM_NUM_BEGIN);
+ _railstation.numtracks = i + 1;
+ break;
+ }
+ }
+ }
- CheckSelectedSize(w, statspec);
+ this->SetWidgetLoweredState(_railstation.numtracks + BRSW_PLATFORM_NUM_BEGIN, !_railstation.dragdrop);
+ this->SetWidgetLoweredState(_railstation.platlength + BRSW_PLATFORM_LEN_BEGIN, !_railstation.dragdrop);
+ SndPlayFx(SND_15_BEEP);
+ this->SetDirty();
+ } break;
- SndPlayFx(SND_15_BEEP);
- w->SetDirty();
- break;
+ case BRSW_HIGHLIGHT_OFF:
+ case BRSW_HIGHLIGHT_ON:
+ _station_show_coverage = (widget != BRSW_HIGHLIGHT_OFF);
+ this->SetWidgetLoweredState(BRSW_HIGHLIGHT_OFF, !_station_show_coverage);
+ this->SetWidgetLoweredState(BRSW_HIGHLIGHT_ON, _station_show_coverage);
+ SndPlayFx(SND_15_BEEP);
+ this->SetDirty();
+ break;
+
+ case BRSW_NEWST_DROPDOWN:
+ ShowDropDownList(this, BuildStationClassDropDown(), _railstation.station_class, BRSW_NEWST_DROPDOWN);
+ break;
+
+ case BRSW_NEWST_LIST: {
+ const StationSpec *statspec;
+ int y = (pt.y - 32) / 14;
+
+ if (y >= this->vscroll.cap) return;
+ y += this->vscroll.pos;
+ if (y >= _railstation.station_count) return;
+
+ /* Check station availability callback */
+ statspec = GetCustomStationSpec(_railstation.station_class, y);
+ if (statspec != NULL &&
+ HasBit(statspec->callbackmask, CBM_STATION_AVAIL) &&
+ GB(GetStationCallback(CBID_STATION_AVAILABILITY, 0, 0, statspec, NULL, INVALID_TILE), 0, 8) == 0) return;
+
+ _railstation.station_type = y;
+
+ this->CheckSelectedSize(statspec);
+
+ SndPlayFx(SND_15_BEEP);
+ this->SetDirty();
+ break;
+ }
}
- }
- } break;
+ }
- case WE_DROPDOWN_SELECT:
- if (_railstation.station_class != e->we.dropdown.index) {
- _railstation.station_class = (StationClassID)e->we.dropdown.index;
+ virtual void OnDropdownSelect(int widget, int index)
+ {
+ if (_railstation.station_class != index) {
+ _railstation.station_class = (StationClassID)index;
_railstation.station_type = 0;
_railstation.station_count = GetNumCustomStations(_railstation.station_class);
- CheckSelectedSize(w, GetCustomStationSpec(_railstation.station_class, _railstation.station_type));
+ this->CheckSelectedSize(GetCustomStationSpec(_railstation.station_class, _railstation.station_type));
- w->vscroll.count = _railstation.station_count;
- w->vscroll.pos = _railstation.station_type;
+ this->vscroll.count = _railstation.station_count;
+ this->vscroll.pos = _railstation.station_type;
}
SndPlayFx(SND_15_BEEP);
- w->SetDirty();
- break;
+ this->SetDirty();
+ }
- case WE_TICK:
- if (WP(w, def_d).close) {
- delete w;
- return;
- }
- CheckRedrawStationCoverage(w);
- break;
-
- case WE_DESTROY:
- if (!WP(w, def_d).close) ResetObjectToPlace();
- break;
+ virtual void OnTick()
+ {
+ CheckRedrawStationCoverage(this);
}
-}
+};
/** Widget definition of the standard build rail station window */
static const Widget _station_builder_widgets[] = {
@@ -1201,36 +1316,29 @@
{ WIDGETS_END},
};
+/** High level window description of the default station-build window */
static const WindowDesc _station_builder_desc = {
WDP_AUTO, WDP_AUTO, 148, 200, 148, 200,
WC_BUILD_STATION, WC_BUILD_TOOLBAR,
WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET,
_station_builder_widgets,
- StationBuildWndProc
};
+/** High level window description of the newGRF station-build window */
static const WindowDesc _newstation_builder_desc = {
WDP_AUTO, WDP_AUTO, 148, 290, 148, 290,
WC_BUILD_STATION, WC_BUILD_TOOLBAR,
WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET,
_newstation_builder_widgets,
- StationBuildWndProc
};
+/** Open station build window */
static void ShowStationBuilder()
{
- Window *w;
if (GetNumStationClasses() <= 2 && GetNumCustomStations(STAT_CLASS_DFLT) == 1) {
- w = new Window(&_station_builder_desc);
- _railstation.newstations = false;
+ new BuildRailStationWindow(&_station_builder_desc, false);
} else {
- w = new Window(&_newstation_builder_desc);
- _railstation.newstations = true;
- _railstation.station_count = GetNumCustomStations(_railstation.station_class);
-
- w->vscroll.count = _railstation.station_count;
- w->vscroll.cap = 5;
- w->vscroll.pos = Clamp(_railstation.station_type - 2, 0, w->vscroll.count - w->vscroll.cap);
+ new BuildRailStationWindow(&_newstation_builder_desc, true);
}
}
@@ -1252,108 +1360,99 @@
BSW_DRAG_SIGNALS_DENSITY_INCREASE,
};
-/**
- * Draw dynamic a signal-sprite in a button in the signal GUI
- * Draw the sprite +1px to the right and down if the button is lowered and change the sprite to sprite + 1 (red to green light)
- *
- * @param w Window on which the widget is located
- * @param widget_index index of this widget in the window
- * @param image the sprite to draw
- * @param xrel the relativ x value of the sprite in the grf
- * @param xsize the width of the sprite
- */
-static void DrawSignalSprite(const Window *w, byte widget_index, SpriteID image, int8 xrel, uint8 xsize)
-{
- DrawSprite(image + w->IsWidgetLowered(widget_index), PAL_NONE,
- w->widget[widget_index].left + (w->widget[widget_index].right - w->widget[widget_index].left) / 2 - xrel - xsize / 2 +
- w->IsWidgetLowered(widget_index), w->widget[widget_index].bottom - 3 + w->IsWidgetLowered(widget_index));
-}
-
-/**
- * Signal selection window event definition
- *
- * @param w window pointer
- * @param e event been triggered
- */
-static void SignalBuildWndProc(Window *w, WindowEvent *e)
-{
- switch (e->event) {
- case WE_PAINT:
- w->LowerWidget((_cur_signal_variant == SIG_ELECTRIC ? BSW_ELECTRIC_NORM : BSW_SEMAPHORE_NORM) + _cur_signal_type);
-
- w->SetWidgetLoweredState(BSW_CONVERT, _convert_signal_button);
-
- w->SetWidgetDisabledState(BSW_DRAG_SIGNALS_DENSITY_DECREASE, _patches.drag_signals_density == 1);
- w->SetWidgetDisabledState(BSW_DRAG_SIGNALS_DENSITY_INCREASE, _patches.drag_signals_density == 20);
-
- DrawWindowWidgets(w);
-
- /* The 'hardcoded' off sets are needed because they are reused sprites. */
- DrawSignalSprite(w, BSW_SEMAPHORE_NORM, SPR_IMG_SIGNAL_SEMAPHORE_NORM, 0, 12); // xsize of sprite + 1 == 9
- DrawSignalSprite(w, BSW_SEMAPHORE_ENTRY, SPR_IMG_SIGNAL_SEMAPHORE_ENTRY, -1, 13); // xsize of sprite + 1 == 10
- DrawSignalSprite(w, BSW_SEMAPHORE_EXIT, SPR_IMG_SIGNAL_SEMAPHORE_EXIT, 0, 12); // xsize of sprite + 1 == 9
- DrawSignalSprite(w, BSW_SEMAPHORE_COMBO, SPR_IMG_SIGNAL_SEMAPHORE_COMBO, 0, 12); // xsize of sprite + 1 == 9
- DrawSignalSprite(w, BSW_ELECTRIC_NORM, SPR_IMG_SIGNAL_ELECTRIC_NORM, -1, 4);
- DrawSignalSprite(w, BSW_ELECTRIC_ENTRY, SPR_IMG_SIGNAL_ELECTRIC_ENTRY, -2, 6);
- DrawSignalSprite(w, BSW_ELECTRIC_EXIT, SPR_IMG_SIGNAL_ELECTRIC_EXIT, -2, 6);
- DrawSignalSprite(w, BSW_ELECTRIC_COMBO, SPR_IMG_SIGNAL_ELECTRIC_COMBO, -2, 6);
+struct BuildSignalWindow : public PickerWindowBase {
+private:
+ /**
+ * Draw dynamic a signal-sprite in a button in the signal GUI
+ * Draw the sprite +1px to the right and down if the button is lowered and change the sprite to sprite + 1 (red to green light)
+ *
+ * @param widget_index index of this widget in the window
+ * @param image the sprite to draw
+ * @param xrel the relativ x value of the sprite in the grf
+ * @param xsize the width of the sprite
+ */
+ void DrawSignalSprite(byte widget_index, SpriteID image, int8 xrel, uint8 xsize)
+ {
+ DrawSprite(image + this->IsWidgetLowered(widget_index), PAL_NONE,
+ this->widget[widget_index].left + (this->widget[widget_index].right - this->widget[widget_index].left) / 2 - xrel - xsize / 2 +
+ this->IsWidgetLowered(widget_index), this->widget[widget_index].bottom - 3 + this->IsWidgetLowered(widget_index));
+ }
- /* Draw dragging signal density value in the BSW_DRAG_SIGNALS_DENSITY widget */
- SetDParam(0, _patches.drag_signals_density);
- DrawStringCentered(w->widget[BSW_DRAG_SIGNALS_DENSITY].left + (w->widget[BSW_DRAG_SIGNALS_DENSITY].right -
- w->widget[BSW_DRAG_SIGNALS_DENSITY].left) / 2 + 1,
- w->widget[BSW_DRAG_SIGNALS_DENSITY].top + 2, STR_JUST_INT, TC_ORANGE);
- break;
-
- case WE_CLICK:
- switch (e->we.click.widget) {
- case BSW_SEMAPHORE_NORM:
- case BSW_SEMAPHORE_ENTRY:
- case BSW_SEMAPHORE_EXIT:
- case BSW_SEMAPHORE_COMBO:
- case BSW_ELECTRIC_NORM:
- case BSW_ELECTRIC_ENTRY:
- case BSW_ELECTRIC_EXIT:
- case BSW_ELECTRIC_COMBO:
- w->RaiseWidget((_cur_signal_variant == SIG_ELECTRIC ? BSW_ELECTRIC_NORM : BSW_SEMAPHORE_NORM) + _cur_signal_type);
-
- _cur_signal_type = (SignalType)((uint)((e->we.click.widget - BSW_SEMAPHORE_NORM) % (SIGTYPE_COMBO + 1)));
- _cur_signal_variant = e->we.click.widget >= BSW_ELECTRIC_NORM ? SIG_ELECTRIC : SIG_SEMAPHORE;
- break;
-
- case BSW_CONVERT:
- _convert_signal_button = !_convert_signal_button;
- break;
+public:
+ BuildSignalWindow(const WindowDesc *desc) : PickerWindowBase(desc)
+ {
+ this->FindWindowPlacementAndResize(desc);
+ };
- case BSW_DRAG_SIGNALS_DENSITY_DECREASE:
- if (_patches.drag_signals_density > 1) {
- _patches.drag_signals_density--;
- SetWindowDirty(FindWindowById(WC_GAME_OPTIONS, 0));
- }
- break;
-
- case BSW_DRAG_SIGNALS_DENSITY_INCREASE:
- if (_patches.drag_signals_density < 20) {
- _patches.drag_signals_density++;
- SetWindowDirty(FindWindowById(WC_GAME_OPTIONS, 0));
- }
- break;
+ virtual void OnPaint()
+ {
+ this->LowerWidget((_cur_signal_variant == SIG_ELECTRIC ? BSW_ELECTRIC_NORM : BSW_SEMAPHORE_NORM) + _cur_signal_type);
- default: break;
- }
-
- w->SetDirty();
- break;
+ this->SetWidgetLoweredState(BSW_CONVERT, _convert_signal_button);
- case WE_TICK:
- if (WP(w, def_d).close) delete w;
- return;
+ this->SetWidgetDisabledState(BSW_DRAG_SIGNALS_DENSITY_DECREASE, _patches.drag_signals_density == 1);
+ this->SetWidgetDisabledState(BSW_DRAG_SIGNALS_DENSITY_INCREASE, _patches.drag_signals_density == 20);
- case WE_DESTROY:
- if (!WP(w, def_d).close) ResetObjectToPlace();
- break;
+ this->DrawWidgets();
+
+ /* The 'hardcoded' off sets are needed because they are reused sprites. */
+ this->DrawSignalSprite(BSW_SEMAPHORE_NORM, SPR_IMG_SIGNAL_SEMAPHORE_NORM, 0, 12); // xsize of sprite + 1 == 9
+ this->DrawSignalSprite(BSW_SEMAPHORE_ENTRY, SPR_IMG_SIGNAL_SEMAPHORE_ENTRY, -1, 13); // xsize of sprite + 1 == 10
+ this->DrawSignalSprite(BSW_SEMAPHORE_EXIT, SPR_IMG_SIGNAL_SEMAPHORE_EXIT, 0, 12); // xsize of sprite + 1 == 9
+ this->DrawSignalSprite(BSW_SEMAPHORE_COMBO, SPR_IMG_SIGNAL_SEMAPHORE_COMBO, 0, 12); // xsize of sprite + 1 == 9
+ this->DrawSignalSprite(BSW_ELECTRIC_NORM, SPR_IMG_SIGNAL_ELECTRIC_NORM, -1, 4);
+ this->DrawSignalSprite(BSW_ELECTRIC_ENTRY, SPR_IMG_SIGNAL_ELECTRIC_ENTRY, -2, 6);
+ this->DrawSignalSprite(BSW_ELECTRIC_EXIT, SPR_IMG_SIGNAL_ELECTRIC_EXIT, -2, 6);
+ this->DrawSignalSprite(BSW_ELECTRIC_COMBO, SPR_IMG_SIGNAL_ELECTRIC_COMBO, -2, 6);
+
+ /* Draw dragging signal density value in the BSW_DRAG_SIGNALS_DENSITY widget */
+ SetDParam(0, _patches.drag_signals_density);
+ DrawStringCentered(this->widget[BSW_DRAG_SIGNALS_DENSITY].left + (this->widget[BSW_DRAG_SIGNALS_DENSITY].right -
+ this->widget[BSW_DRAG_SIGNALS_DENSITY].left) / 2 + 1,
+ this->widget[BSW_DRAG_SIGNALS_DENSITY].top + 2, STR_JUST_INT, TC_ORANGE);
+ }
+
+ virtual void OnClick(Point pt, int widget)
+ {
+ switch (widget) {
+ case BSW_SEMAPHORE_NORM:
+ case BSW_SEMAPHORE_ENTRY:
+ case BSW_SEMAPHORE_EXIT:
+ case BSW_SEMAPHORE_COMBO:
+ case BSW_ELECTRIC_NORM:
+ case BSW_ELECTRIC_ENTRY:
+ case BSW_ELECTRIC_EXIT:
+ case BSW_ELECTRIC_COMBO:
+ this->RaiseWidget((_cur_signal_variant == SIG_ELECTRIC ? BSW_ELECTRIC_NORM : BSW_SEMAPHORE_NORM) + _cur_signal_type);
+
+ _cur_signal_type = (SignalType)((uint)((widget - BSW_SEMAPHORE_NORM) % (SIGTYPE_COMBO + 1)));
+ _cur_signal_variant = widget >= BSW_ELECTRIC_NORM ? SIG_ELECTRIC : SIG_SEMAPHORE;
+ break;
+
+ case BSW_CONVERT:
+ _convert_signal_button = !_convert_signal_button;
+ break;
+
+ case BSW_DRAG_SIGNALS_DENSITY_DECREASE:
+ if (_patches.drag_signals_density > 1) {
+ _patches.drag_signals_density--;
+ SetWindowDirty(FindWindowById(WC_GAME_OPTIONS, 0));
+ }
+ break;
+
+ case BSW_DRAG_SIGNALS_DENSITY_INCREASE:
+ if (_patches.drag_signals_density < 20) {
+ _patches.drag_signals_density++;
+ SetWindowDirty(FindWindowById(WC_GAME_OPTIONS, 0));
+ }
+ break;
+
+ default: break;
}
-}
+
+ this->SetDirty();
+ }
+};
/** Widget definition of the build signal window */
static const Widget _signal_builder_widgets[] = {
@@ -1384,7 +1483,6 @@
WC_BUILD_SIGNAL, WC_BUILD_TOOLBAR,
WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS,
_signal_builder_widgets,
- SignalBuildWndProc
};
/**
@@ -1392,59 +1490,55 @@
*/
static void ShowSignalBuilder()
{
- new Window(&_signal_builder_desc);
+ new BuildSignalWindow(&_signal_builder_desc);
}
-/** Enum referring to the widgets of the build rail depot window */
-enum BuildRailDepotWidgets {
- BRDW_CLOSEBOX = 0,
- BRDW_CAPTION,
- BRDW_BACKGROUND,
- BRDW_DEPOT_NE,
- BRDW_DEPOT_SE,
- BRDW_DEPOT_SW,
- BRDW_DEPOT_NW,
-};
+struct BuildRailDepotWindow : public PickerWindowBase {
+private:
+ /** Enum referring to the widgets of the build rail depot window */
+ enum BuildRailDepotWidgets {
+ BRDW_CLOSEBOX = 0,
+ BRDW_CAPTION,
+ BRDW_BACKGROUND,
+ BRDW_DEPOT_NE,
+ BRDW_DEPOT_SE,
+ BRDW_DEPOT_SW,
+ BRDW_DEPOT_NW,
+ };
-static void BuildTrainDepotWndProc(Window *w, WindowEvent *e)
-{
- switch (e->event) {
- case WE_CREATE: w->LowerWidget(_build_depot_direction + BRDW_DEPOT_NE); break;
+public:
+ BuildRailDepotWindow(const WindowDesc *desc) : PickerWindowBase(desc)
+ {
+ this->LowerWidget(_build_depot_direction + BRDW_DEPOT_NE);
+ this->FindWindowPlacementAndResize(desc);
+ }
- case WE_PAINT: {
- DrawWindowWidgets(w);
+ virtual void OnPaint()
+ {
+ this->DrawWidgets();
DrawTrainDepotSprite(70, 17, DIAGDIR_NE, _cur_railtype);
DrawTrainDepotSprite(70, 69, DIAGDIR_SE, _cur_railtype);
DrawTrainDepotSprite( 2, 69, DIAGDIR_SW, _cur_railtype);
DrawTrainDepotSprite( 2, 17, DIAGDIR_NW, _cur_railtype);
- break;
- }
+ }
- case WE_CLICK:
- switch (e->we.click.widget) {
+ virtual void OnClick(Point pt, int widget)
+ {
+ switch (widget) {
case BRDW_DEPOT_NE:
case BRDW_DEPOT_SE:
case BRDW_DEPOT_SW:
case BRDW_DEPOT_NW:
- w->RaiseWidget(_build_depot_direction + BRDW_DEPOT_NE);
- _build_depot_direction = (DiagDirection)(e->we.click.widget - BRDW_DEPOT_NE);
- w->LowerWidget(_build_depot_direction + BRDW_DEPOT_NE);
+ this->RaiseWidget(_build_depot_direction + BRDW_DEPOT_NE);
+ _build_depot_direction = (DiagDirection)(widget - BRDW_DEPOT_NE);
+ this->LowerWidget(_build_depot_direction + BRDW_DEPOT_NE);
SndPlayFx(SND_15_BEEP);
- w->SetDirty();
+ this->SetDirty();
break;
}
- break;
-
- case WE_TICK:
- if (WP(w, def_d).close) delete w;
- return;
-
- case WE_DESTROY:
- if (!WP(w, def_d).close) ResetObjectToPlace();
- break;
}
-}
+};
/** Widget definition of the build rail depot window */
static const Widget _build_depot_widgets[] = {
@@ -1463,44 +1557,51 @@
WC_BUILD_DEPOT, WC_BUILD_TOOLBAR,
WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET,
_build_depot_widgets,
- BuildTrainDepotWndProc
};
static void ShowBuildTrainDepotPicker()
{
- new Window(&_build_depot_desc);
+ new BuildRailDepotWindow(&_build_depot_desc);
}
-/** Enum referring to the widgets of the build NewGRF rail waypoint window */
-enum BuildRailWaypointWidgets {
- BRWW_CLOSEBOX = 0,
- BRWW_CAPTION,
- BRWW_BACKGROUND,
- BRWW_WAYPOINT_1,
- BRWW_WAYPOINT_2,
- BRWW_WAYPOINT_3,
- BRWW_WAYPOINT_4,
- BRWW_WAYPOINT_5,
- BRWW_SCROLL,
-};
+struct BuildRailWaypointWindow : PickerWindowBase {
+private:
+ /** Enum referring to the widgets of the build NewGRF rail waypoint window */
+ enum BuildRailWaypointWidgets {
+ BRWW_CLOSEBOX = 0,
+ BRWW_CAPTION,
+ BRWW_BACKGROUND,
+ BRWW_WAYPOINT_1,
+ BRWW_WAYPOINT_2,
+ BRWW_WAYPOINT_3,
+ BRWW_WAYPOINT_4,
+ BRWW_WAYPOINT_5,
+ BRWW_SCROLL,
+ };
-static void BuildWaypointWndProc(Window *w, WindowEvent *e)
-{
- switch (e->event) {
- case WE_PAINT: {
+public:
+ BuildRailWaypointWindow(const WindowDesc *desc) : PickerWindowBase(desc)
+ {
+ this->hscroll.cap = 5;
+ this->hscroll.count = _waypoint_count;
+ this->FindWindowPlacementAndResize(desc);
+ };
+
+ virtual void OnPaint()
+ {
uint i;
- for (i = 0; i < w->hscroll.cap; i++) {
- w->SetWidgetLoweredState(i + BRWW_WAYPOINT_1, (w->hscroll.pos + i) == _cur_waypoint_type);
+ for (i = 0; i < this->hscroll.cap; i++) {
+ this->SetWidgetLoweredState(i + BRWW_WAYPOINT_1, (this->hscroll.pos + i) == _cur_waypoint_type);
}
- DrawWindowWidgets(w);
+ this->DrawWidgets();
- for (i = 0; i < w->hscroll.cap; i++) {
- if (w->hscroll.pos + i < w->hscroll.count) {
- const StationSpec *statspec = GetCustomStationSpec(STAT_CLASS_WAYP, w->hscroll.pos + i);
+ for (i = 0; i < this->hscroll.cap; i++) {
+ if (this->hscroll.pos + i < this->hscroll.count) {
+ const StationSpec *statspec = GetCustomStationSpec(STAT_CLASS_WAYP, this->hscroll.pos + i);
- DrawWaypointSprite(2 + i * 68, 25, w->hscroll.pos + i, _cur_railtype);
+ DrawWaypointSprite(2 + i * 68, 25, this->hscroll.pos + i, _cur_railtype);
if (statspec != NULL &&
HasBit(statspec->callbackmask, CBM_STATION_AVAIL) &&
@@ -1509,16 +1610,17 @@
}
}
}
- break;
}
- case WE_CLICK: {
- switch (e->we.click.widget) {
+
+ virtual void OnClick(Point pt, int widget)
+ {
+ switch (widget) {
case BRWW_WAYPOINT_1:
case BRWW_WAYPOINT_2:
case BRWW_WAYPOINT_3:
case BRWW_WAYPOINT_4:
case BRWW_WAYPOINT_5: {
- byte type = e->we.click.widget - BRWW_WAYPOINT_1 + w->hscroll.pos;
+ byte type = widget - BRWW_WAYPOINT_1 + this->hscroll.pos;
/* Check station availability callback */
const StationSpec *statspec = GetCustomStationSpec(STAT_CLASS_WAYP, type);
@@ -1528,22 +1630,12 @@
_cur_waypoint_type = type;
SndPlayFx(SND_15_BEEP);
- w->SetDirty();
+ this->SetDirty();
break;
}
}
- break;
}
-
- case WE_TICK:
- if (WP(w, def_d).close) delete w;
- break;
-
- case WE_DESTROY:
- if (!WP(w, def_d).close) ResetObjectToPlace();
- break;
- }
-}
+};
/** Widget definition for the build NewGRF rail waypoint window */
static const Widget _build_waypoint_widgets[] = {
@@ -1566,17 +1658,16 @@
WC_BUILD_DEPOT, WC_BUILD_TOOLBAR,
WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET,
_build_waypoint_widgets,
- BuildWaypointWndProc
};
static void ShowBuildWaypointPicker()
{
- Window *w = new Window(&_build_waypoint_desc);
- w->hscroll.cap = 5;
- w->hscroll.count = _waypoint_count;
+ new BuildRailWaypointWindow(&_build_waypoint_desc);
}
-
+/**
+ * Initialize rail building GUI settings
+ */
void InitializeRailGui()
{
_build_depot_direction = DIAGDIR_NW;
@@ -1585,6 +1676,10 @@
_railstation.dragdrop = true;
}
+/**
+ * Re-initialize rail-build toolbar after toggling support for electric trains
+ * @param disable Boolean whether electric trains are disabled (removed from the game)
+ */
void ReinitGuiAfterToggleElrail(bool disable)
{
extern RailType _last_built_railtype;
@@ -1600,6 +1695,7 @@
MarkWholeScreenDirty();
}
+/** Set the initial (default) railtype to use */
static void SetDefaultRailGui()
{
if (_local_player == PLAYER_SPECTATOR || !IsValidPlayer(_local_player)) return;
--- a/src/rail_map.h Mon May 19 14:14:33 2008 +0000
+++ b/src/rail_map.h Mon May 19 15:13:58 2008 +0000
@@ -168,6 +168,17 @@
return (DiagDirection)GB(_m[t].m5, 0, 2);
}
+/**
+ * Returns the track of a depot, ignoring direction
+ * @pre IsRailDepotTile(t)
+ * @param t the tile to get the depot track from
+ * @return the track of the depot
+ */
+static inline Track GetRailDepotTrack(TileIndex t)
+{
+ return DiagDirToDiagTrack(GetRailDepotDirection(t));
+}
+
/**
* Returns the axis of the waypoint
--- a/src/road_cmd.cpp Mon May 19 14:14:33 2008 +0000
+++ b/src/road_cmd.cpp Mon May 19 15:13:58 2008 +0000
@@ -43,6 +43,37 @@
#include "table/sprites.h"
#include "table/strings.h"
+
+bool RoadVehiclesAreBuilt()
+{
+ const Vehicle* v;
+
+ FOR_ALL_VEHICLES(v) {
+ if (v->type == VEH_ROAD) return true;
+ }
+ return false;
+}
+
+/**
+ * Change the side of the road vehicles drive on (server only).
+ * @param tile unused
+ * @param flags operation to perform
+ * @param p1 the side of the road; 0 = left side and 1 = right side
+ * @param p2 unused
+ */
+CommandCost CmdSetRoadDriveSide(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
+{
+ /* Check boundaries and you can only change this if NO vehicles have been built yet,
+ * except in the intro-menu where of course it's always possible to do so. */
+ if (p1 > 1 || (_game_mode != GM_MENU && RoadVehiclesAreBuilt())) return CMD_ERROR;
+
+ if (flags & DC_EXEC) {
+ _opt_ptr->road_side = p1;
+ InvalidateWindow(WC_GAME_OPTIONS, 0);
+ }
+ return CommandCost();
+}
+
#define M(x) (1 << (x))
/* Level crossings may only be built on these slopes */
static const uint32 VALID_LEVEL_CROSSING_SLOPES = (M(SLOPE_SEN) | M(SLOPE_ENW) | M(SLOPE_NWS) | M(SLOPE_NS) | M(SLOPE_WSE) | M(SLOPE_EW) | M(SLOPE_FLAT));
@@ -1390,7 +1421,7 @@
if (side != INVALID_DIAGDIR && side != dir) break;
- trackdirbits = TrackBitsToTrackdirBits(AxisToTrackBits(DiagDirToAxis(dir)));
+ trackdirbits = TrackBitsToTrackdirBits(DiagDirToDiagTrackBits(dir));
break;
}
}
--- a/src/road_gui.cpp Mon May 19 14:14:33 2008 +0000
+++ b/src/road_gui.cpp Mon May 19 15:13:58 2008 +0000
@@ -400,220 +400,222 @@
'R',
};
-/**
- * Update the remove button lowered state of the road toolbar
- *
- * @param w The toolbar window
- * @param clicked_widget The widget which the player clicked just now
- */
-static void UpdateOptionWidgetStatus(Window *w, RoadToolbarWidgets clicked_widget)
-{
- /* The remove and the one way button state is driven
- * by the other buttons so they don't act on themselfs.
- * Both are only valid if they are able to apply as options. */
- switch (clicked_widget) {
- case RTW_REMOVE:
- w->RaiseWidget(RTW_ONE_WAY);
- w->InvalidateWidget(RTW_ONE_WAY);
- break;
-
- case RTW_ONE_WAY:
- w->RaiseWidget(RTW_REMOVE);
- w->InvalidateWidget(RTW_REMOVE);
- break;
-
- case RTW_BUS_STATION:
- case RTW_TRUCK_STATION:
- w->DisableWidget(RTW_ONE_WAY);
- w->SetWidgetDisabledState(RTW_REMOVE, !w->IsWidgetLowered(clicked_widget));
- break;
+struct BuildRoadToolbarWindow : Window {
+ BuildRoadToolbarWindow(const WindowDesc *desc, WindowNumber window_number) : Window(desc, window_number)
+ {
+ this->SetWidgetsDisabledState(true,
+ RTW_REMOVE,
+ RTW_ONE_WAY,
+ WIDGET_LIST_END);
- case RTW_ROAD_X:
- case RTW_ROAD_Y:
- case RTW_AUTOROAD:
- w->SetWidgetsDisabledState(!w->IsWidgetLowered(clicked_widget),
- RTW_REMOVE,
- RTW_ONE_WAY,
- WIDGET_LIST_END);
- break;
-
- default:
- /* When any other buttons than road/station, raise and
- * disable the removal button */
- w->SetWidgetsDisabledState(true,
- RTW_REMOVE,
- RTW_ONE_WAY,
- WIDGET_LIST_END);
- w->SetWidgetsLoweredState (false,
- RTW_REMOVE,
- RTW_ONE_WAY,
- WIDGET_LIST_END);
- break;
+ this->FindWindowPlacementAndResize(desc);
+ if (_patches.link_terraform_toolbar) ShowTerraformToolbar(this);
}
-}
-static void BuildRoadToolbWndProc(Window *w, WindowEvent *e)
-{
- switch (e->event) {
- case WE_CREATE:
- w->SetWidgetsDisabledState(true,
- RTW_REMOVE,
- RTW_ONE_WAY,
- WIDGET_LIST_END);
- break;
+ ~BuildRoadToolbarWindow()
+ {
+ if (_patches.link_terraform_toolbar) DeleteWindowById(WC_SCEN_LAND_GEN, 0);
+ }
- case WE_PAINT:
- w->SetWidgetsDisabledState(!CanBuildVehicleInfrastructure(VEH_ROAD),
- RTW_DEPOT,
- RTW_BUS_STATION,
- RTW_TRUCK_STATION,
- WIDGET_LIST_END);
- DrawWindowWidgets(w);
- break;
+ /**
+ * Update the remove button lowered state of the road toolbar
+ *
+ * @param clicked_widget The widget which the player clicked just now
+ */
+ void UpdateOptionWidgetStatus(RoadToolbarWidgets clicked_widget)
+ {
+ /* The remove and the one way button state is driven
+ * by the other buttons so they don't act on themselfs.
+ * Both are only valid if they are able to apply as options. */
+ switch (clicked_widget) {
+ case RTW_REMOVE:
+ this->RaiseWidget(RTW_ONE_WAY);
+ this->InvalidateWidget(RTW_ONE_WAY);
+ break;
- case WE_CLICK:
- if (e->we.click.widget >= RTW_ROAD_X) {
+ case RTW_ONE_WAY:
+ this->RaiseWidget(RTW_REMOVE);
+ this->InvalidateWidget(RTW_REMOVE);
+ break;
+
+ case RTW_BUS_STATION:
+ case RTW_TRUCK_STATION:
+ this->DisableWidget(RTW_ONE_WAY);
+ this->SetWidgetDisabledState(RTW_REMOVE, !this->IsWidgetLowered(clicked_widget));
+ break;
+
+ case RTW_ROAD_X:
+ case RTW_ROAD_Y:
+ case RTW_AUTOROAD:
+ this->SetWidgetsDisabledState(!this->IsWidgetLowered(clicked_widget),
+ RTW_REMOVE,
+ RTW_ONE_WAY,
+ WIDGET_LIST_END);
+ break;
+
+ default:
+ /* When any other buttons than road/station, raise and
+ * disable the removal button */
+ this->SetWidgetsDisabledState(true,
+ RTW_REMOVE,
+ RTW_ONE_WAY,
+ WIDGET_LIST_END);
+ this->SetWidgetsLoweredState (false,
+ RTW_REMOVE,
+ RTW_ONE_WAY,
+ WIDGET_LIST_END);
+ break;
+ }
+ }
+
+ virtual void OnPaint()
+ {
+ this->SetWidgetsDisabledState(!CanBuildVehicleInfrastructure(VEH_ROAD),
+ RTW_DEPOT,
+ RTW_BUS_STATION,
+ RTW_TRUCK_STATION,
+ WIDGET_LIST_END);
+ this->DrawWidgets();
+ }
+
+ virtual void OnClick(Point pt, int widget)
+ {
+ if (widget >= RTW_ROAD_X) {
+ _remove_button_clicked = false;
+ _one_way_button_clicked = false;
+ _build_road_button_proc[widget - RTW_ROAD_X](this);
+ }
+ this->UpdateOptionWidgetStatus((RoadToolbarWidgets)widget);
+ if (_ctrl_pressed) RoadToolbar_CtrlChanged(this);
+ }
+
+ virtual EventState OnKeyPress(uint16 key, uint16 keycode)
+ {
+ EventState state = ES_NOT_HANDLED;
+ for (uint i = 0; i != lengthof(_road_keycodes); i++) {
+ if (keycode == _road_keycodes[i]) {
_remove_button_clicked = false;
_one_way_button_clicked = false;
- _build_road_button_proc[e->we.click.widget - RTW_ROAD_X](w);
+ _build_road_button_proc[i](this);
+ this->UpdateOptionWidgetStatus((RoadToolbarWidgets)(i + RTW_ROAD_X));
+ if (_ctrl_pressed) RoadToolbar_CtrlChanged(this);
+ state = ES_HANDLED;
+ break;
}
- UpdateOptionWidgetStatus(w, (RoadToolbarWidgets)e->we.click.widget);
- if (_ctrl_pressed) RoadToolbar_CtrlChanged(w);
- break;
-
- case WE_KEYPRESS:
- for (uint i = 0; i != lengthof(_road_keycodes); i++) {
- if (e->we.keypress.keycode == _road_keycodes[i]) {
- e->we.keypress.cont = false;
- _remove_button_clicked = false;
- _one_way_button_clicked = false;
- _build_road_button_proc[i](w);
- UpdateOptionWidgetStatus(w, (RoadToolbarWidgets)(i + RTW_ROAD_X));
- if (_ctrl_pressed) RoadToolbar_CtrlChanged(w);
- break;
- }
- }
- MarkTileDirty(_thd.pos.x, _thd.pos.y); // redraw tile selection
- break;
-
- case WE_PLACE_OBJ:
- _remove_button_clicked = w->IsWidgetLowered(RTW_REMOVE);
- _one_way_button_clicked = w->IsWidgetLowered(RTW_ONE_WAY);
- _place_proc(e->we.place.tile);
- break;
+ }
+ MarkTileDirty(_thd.pos.x, _thd.pos.y); // redraw tile selection
+ return state;
+ }
- case WE_ABORT_PLACE_OBJ:
- w->RaiseButtons();
- w->SetWidgetsDisabledState(true,
- RTW_REMOVE,
- RTW_ONE_WAY,
- WIDGET_LIST_END);
- w->InvalidateWidget(RTW_REMOVE);
- w->InvalidateWidget(RTW_ONE_WAY);
+ virtual void OnPlaceObject(Point pt, TileIndex tile)
+ {
+ _remove_button_clicked = this->IsWidgetLowered(RTW_REMOVE);
+ _one_way_button_clicked = this->IsWidgetLowered(RTW_ONE_WAY);
+ _place_proc(tile);
+ }
- w = FindWindowById(WC_BUS_STATION, 0);
- if (w != NULL) WP(w, def_d).close = true;
- w = FindWindowById(WC_TRUCK_STATION, 0);
- if (w != NULL) WP(w, def_d).close = true;
- w = FindWindowById(WC_BUILD_DEPOT, 0);
- if (w != NULL) WP(w, def_d).close = true;
- break;
+ virtual void OnPlaceObjectAbort()
+ {
+ this->RaiseButtons();
+ this->SetWidgetsDisabledState(true,
+ RTW_REMOVE,
+ RTW_ONE_WAY,
+ WIDGET_LIST_END);
+ this->InvalidateWidget(RTW_REMOVE);
+ this->InvalidateWidget(RTW_ONE_WAY);
- case WE_PLACE_DRAG:
- /* Here we update the end tile flags
- * of the road placement actions.
- * At first we reset the end halfroad
- * bits and if needed we set them again. */
- switch (e->we.place.select_proc) {
- case DDSP_PLACE_ROAD_X_DIR:
- _place_road_flag &= ~RF_END_HALFROAD_X;
- if (e->we.place.pt.x & 8) _place_road_flag |= RF_END_HALFROAD_X;
- break;
+ delete FindWindowById(WC_BUS_STATION, 0);
+ delete FindWindowById(WC_TRUCK_STATION, 0);
+ delete FindWindowById(WC_BUILD_DEPOT, 0);
+ }
- case DDSP_PLACE_ROAD_Y_DIR:
- _place_road_flag &= ~RF_END_HALFROAD_Y;
- if (e->we.place.pt.y & 8) _place_road_flag |= RF_END_HALFROAD_Y;
+ virtual void OnPlaceDrag(ViewportPlaceMethod select_method, ViewportDragDropSelectionProcess select_proc, Point pt)
+ {
+ /* Here we update the end tile flags
+ * of the road placement actions.
+ * At first we reset the end halfroad
+ * bits and if needed we set them again. */
+ switch (select_proc) {
+ case DDSP_PLACE_ROAD_X_DIR:
+ _place_road_flag &= ~RF_END_HALFROAD_X;
+ if (pt.x & 8) _place_road_flag |= RF_END_HALFROAD_X;
+ break;
+
+ case DDSP_PLACE_ROAD_Y_DIR:
+ _place_road_flag &= ~RF_END_HALFROAD_Y;
+ if (pt.y & 8) _place_road_flag |= RF_END_HALFROAD_Y;
+ break;
+
+ case DDSP_PLACE_AUTOROAD:
+ _place_road_flag &= ~(RF_END_HALFROAD_Y | RF_END_HALFROAD_X);
+ if (pt.y & 8) _place_road_flag |= RF_END_HALFROAD_Y;
+ if (pt.x & 8) _place_road_flag |= RF_END_HALFROAD_X;
+
+ /* For autoroad we need to update the
+ * direction of the road */
+ if (_thd.size.x > _thd.size.y || (_thd.size.x == _thd.size.y &&
+ ( (_tile_fract_coords.x < _tile_fract_coords.y && (_tile_fract_coords.x + _tile_fract_coords.y) < 16) ||
+ (_tile_fract_coords.x > _tile_fract_coords.y && (_tile_fract_coords.x + _tile_fract_coords.y) > 16) ))) {
+ /* Set dir = X */
+ _place_road_flag &= ~RF_DIR_Y;
+ } else {
+ /* Set dir = Y */
+ _place_road_flag |= RF_DIR_Y;
+ }
+
+ break;
+
+ default:
+ break;
+ }
+
+ VpSelectTilesWithMethod(pt.x, pt.y, select_method);
+ }
+
+ virtual void OnPlaceMouseUp(ViewportPlaceMethod select_method, ViewportDragDropSelectionProcess select_proc, Point pt, TileIndex start_tile, TileIndex end_tile)
+ {
+ if (pt.x != -1) {
+ switch (select_proc) {
+ default: NOT_REACHED();
+ case DDSP_BUILD_BRIDGE:
+ ResetObjectToPlace();
+ ShowBuildBridgeWindow(start_tile, end_tile, TRANSPORT_ROAD, RoadTypeToRoadTypes(_cur_roadtype));
break;
- case DDSP_PLACE_AUTOROAD:
- _place_road_flag &= ~(RF_END_HALFROAD_Y | RF_END_HALFROAD_X);
- if (e->we.place.pt.y & 8) _place_road_flag |= RF_END_HALFROAD_Y;
- if (e->we.place.pt.x & 8) _place_road_flag |= RF_END_HALFROAD_X;
-
- /* For autoroad we need to update the
- * direction of the road */
- if (_thd.size.x > _thd.size.y || (_thd.size.x == _thd.size.y &&
- ( (_tile_fract_coords.x < _tile_fract_coords.y && (_tile_fract_coords.x + _tile_fract_coords.y) < 16) ||
- (_tile_fract_coords.x > _tile_fract_coords.y && (_tile_fract_coords.x + _tile_fract_coords.y) > 16) ))) {
- /* Set dir = X */
- _place_road_flag &= ~RF_DIR_Y;
- } else {
- /* Set dir = Y */
- _place_road_flag |= RF_DIR_Y;
- }
-
+ case DDSP_DEMOLISH_AREA:
+ GUIPlaceProcDragXY(select_proc, start_tile, end_tile);
break;
- default:
+ case DDSP_PLACE_ROAD_X_DIR:
+ case DDSP_PLACE_ROAD_Y_DIR:
+ case DDSP_PLACE_AUTOROAD:
+ /* Flag description:
+ * Use the first three bits (0x07) if dir == Y
+ * else use the last 2 bits (X dir has
+ * not the 3rd bit set) */
+ _place_road_flag = (RoadFlags)((_place_road_flag & RF_DIR_Y) ? (_place_road_flag & 0x07) : (_place_road_flag >> 3));
+
+ DoCommandP(end_tile, start_tile, _place_road_flag | (_cur_roadtype << 3) | (_one_way_button_clicked << 5), CcPlaySound1D,
+ (_ctrl_pressed || _remove_button_clicked) ?
+ CMD_REMOVE_LONG_ROAD | CMD_NO_WATER | CMD_MSG(_road_type_infos[_cur_roadtype].err_remove_road) :
+ CMD_BUILD_LONG_ROAD | CMD_NO_WATER | CMD_MSG(_road_type_infos[_cur_roadtype].err_build_road));
break;
}
-
- VpSelectTilesWithMethod(e->we.place.pt.x, e->we.place.pt.y, e->we.place.select_method);
- return;
-
- case WE_PLACE_MOUSEUP:
- if (e->we.place.pt.x != -1) {
- TileIndex start_tile = e->we.place.starttile;
- TileIndex end_tile = e->we.place.tile;
-
- switch (e->we.place.select_proc) {
- default: NOT_REACHED();
- case DDSP_BUILD_BRIDGE:
- ResetObjectToPlace();
- ShowBuildBridgeWindow(start_tile, end_tile, TRANSPORT_ROAD, RoadTypeToRoadTypes(_cur_roadtype));
- break;
-
- case DDSP_DEMOLISH_AREA:
- GUIPlaceProcDragXY(e);
- break;
+ }
+ }
- case DDSP_PLACE_ROAD_X_DIR:
- case DDSP_PLACE_ROAD_Y_DIR:
- case DDSP_PLACE_AUTOROAD:
- /* Flag description:
- * Use the first three bits (0x07) if dir == Y
- * else use the last 2 bits (X dir has
- * not the 3rd bit set) */
- _place_road_flag = (RoadFlags)((_place_road_flag & RF_DIR_Y) ? (_place_road_flag & 0x07) : (_place_road_flag >> 3));
-
- DoCommandP(end_tile, start_tile, _place_road_flag | (_cur_roadtype << 3) | (_one_way_button_clicked << 5), CcPlaySound1D,
- (_ctrl_pressed || _remove_button_clicked) ?
- CMD_REMOVE_LONG_ROAD | CMD_NO_WATER | CMD_MSG(_road_type_infos[_cur_roadtype].err_remove_road) :
- CMD_BUILD_LONG_ROAD | CMD_NO_WATER | CMD_MSG(_road_type_infos[_cur_roadtype].err_build_road));
- break;
- }
- }
- break;
+ virtual void OnPlacePresize(Point pt, TileIndex tile)
+ {
+ DoCommand(tile, 0x200 | RoadTypeToRoadTypes(_cur_roadtype), 0, DC_AUTO, CMD_BUILD_TUNNEL);
+ VpSetPresizeRange(tile, _build_tunnel_endtile == 0 ? tile : _build_tunnel_endtile);
+ }
- case WE_PLACE_PRESIZE: {
- TileIndex tile = e->we.place.tile;
-
- DoCommand(tile, 0x200 | RoadTypeToRoadTypes(_cur_roadtype), 0, DC_AUTO, CMD_BUILD_TUNNEL);
- VpSetPresizeRange(tile, _build_tunnel_endtile == 0 ? tile : _build_tunnel_endtile);
- } break;
-
- case WE_DESTROY:
- if (_patches.link_terraform_toolbar) DeleteWindowById(WC_SCEN_LAND_GEN, 0);
- break;
-
- case WE_CTRL_CHANGED:
- if (RoadToolbar_CtrlChanged(w)) e->we.ctrl.cont = false;
- break;
-
- default:
- break;
+ virtual EventState OnCTRLStateChange()
+ {
+ if (RoadToolbar_CtrlChanged(this)) return ES_HANDLED;
+ return ES_NOT_HANDLED;
}
-}
+};
/** Widget definition of the build road toolbar */
static const Widget _build_road_widgets[] = {
@@ -641,7 +643,6 @@
WC_BUILD_TOOLBAR, WC_NONE,
WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_STICKY_BUTTON,
_build_road_widgets,
- BuildRoadToolbWndProc
};
/** Widget definition of the build tram toolbar */
@@ -670,7 +671,6 @@
WC_BUILD_TOOLBAR, WC_NONE,
WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_STICKY_BUTTON,
_build_tramway_widgets,
- BuildRoadToolbWndProc
};
void ShowBuildRoadToolbar(RoadType roadtype)
@@ -679,8 +679,7 @@
_cur_roadtype = roadtype;
DeleteWindowByClass(WC_BUILD_TOOLBAR);
- Window *w = AllocateWindowDescFront<Window>(roadtype == ROADTYPE_ROAD ? &_build_road_desc : &_build_tramway_desc, TRANSPORT_ROAD);
- if (_patches.link_terraform_toolbar) ShowTerraformToolbar(w);
+ AllocateWindowDescFront<BuildRoadToolbarWindow>(roadtype == ROADTYPE_ROAD ? &_build_road_desc : &_build_tramway_desc, TRANSPORT_ROAD);
}
/** Widget definition of the build road toolbar in the scenario editor */
@@ -708,72 +707,67 @@
WC_SCEN_BUILD_ROAD, WC_NONE,
WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_STICKY_BUTTON,
_build_road_scen_widgets,
- BuildRoadToolbWndProc
};
void ShowBuildRoadScenToolbar()
{
_cur_roadtype = ROADTYPE_ROAD;
- AllocateWindowDescFront<Window>(&_build_road_scen_desc, 0);
+ AllocateWindowDescFront<BuildRoadToolbarWindow>(&_build_road_scen_desc, 0);
}
-/** Enum referring to the widgets of the build road depot window */
-enum BuildRoadDepotWidgets {
- BRDW_CLOSEBOX = 0,
- BRDW_CAPTION,
- BRDW_BACKGROUND,
- BRDW_DEPOT_NE,
- BRDW_DEPOT_SE,
- BRDW_DEPOT_SW,
- BRDW_DEPOT_NW,
-};
-
-static void BuildRoadDepotWndProc(Window *w, WindowEvent *e)
-{
- switch (e->event) {
- case WE_CREATE:
- w->LowerWidget(_road_depot_orientation + BRDW_DEPOT_NE);
- break;
-
- case WE_PAINT:
- DrawWindowWidgets(w);
-
- DrawRoadDepotSprite(70, 17, DIAGDIR_NE, _cur_roadtype);
- DrawRoadDepotSprite(70, 69, DIAGDIR_SE, _cur_roadtype);
- DrawRoadDepotSprite( 2, 69, DIAGDIR_SW, _cur_roadtype);
- DrawRoadDepotSprite( 2, 17, DIAGDIR_NW, _cur_roadtype);
- break;
+struct BuildRoadDepotWindow : public PickerWindowBase {
+private:
+ /** Enum referring to the widgets of the build road depot window */
+ enum BuildRoadDepotWidgets {
+ BRDW_CLOSEBOX = 0,
+ BRDW_CAPTION,
+ BRDW_BACKGROUND,
+ BRDW_DEPOT_NE,
+ BRDW_DEPOT_SE,
+ BRDW_DEPOT_SW,
+ BRDW_DEPOT_NW,
+ };
- case WE_CLICK:
- switch (e->we.click.widget) {
- case BRDW_DEPOT_NW:
- case BRDW_DEPOT_NE:
- case BRDW_DEPOT_SW:
- case BRDW_DEPOT_SE:
- w->RaiseWidget(_road_depot_orientation + BRDW_DEPOT_NE);
- _road_depot_orientation = (DiagDirection)(e->we.click.widget - BRDW_DEPOT_NE);
- w->LowerWidget(_road_depot_orientation + BRDW_DEPOT_NE);
- SndPlayFx(SND_15_BEEP);
- w->SetDirty();
- break;
+public:
+ BuildRoadDepotWindow(const WindowDesc *desc) : PickerWindowBase(desc)
+ {
+ this->LowerWidget(_road_depot_orientation + BRDW_DEPOT_NE);
+ if ( _cur_roadtype == ROADTYPE_TRAM) {
+ this->widget[BRDW_CAPTION].data = STR_TRAM_DEPOT_ORIENTATION;
+ for (int i = BRDW_DEPOT_NE; i <= BRDW_DEPOT_NW; i++) this->widget[i].tooltips = STR_SELECT_TRAM_VEHICLE_DEPOT;
+ }
+ this->FindWindowPlacementAndResize(desc);
+ }
- default:
- break;
- }
- break;
+ virtual void OnPaint()
+ {
+ this->DrawWidgets();
- case WE_TICK:
- if (WP(w, def_d).close) delete w;
- break;
+ DrawRoadDepotSprite(70, 17, DIAGDIR_NE, _cur_roadtype);
+ DrawRoadDepotSprite(70, 69, DIAGDIR_SE, _cur_roadtype);
+ DrawRoadDepotSprite( 2, 69, DIAGDIR_SW, _cur_roadtype);
+ DrawRoadDepotSprite( 2, 17, DIAGDIR_NW, _cur_roadtype);
+ }
- case WE_DESTROY:
- if (!WP(w, def_d).close) ResetObjectToPlace();
- break;
+ virtual void OnClick(Point pt, int widget)
+ {
+ switch (widget) {
+ case BRDW_DEPOT_NW:
+ case BRDW_DEPOT_NE:
+ case BRDW_DEPOT_SW:
+ case BRDW_DEPOT_SE:
+ this->RaiseWidget(_road_depot_orientation + BRDW_DEPOT_NE);
+ _road_depot_orientation = (DiagDirection)(widget - BRDW_DEPOT_NE);
+ this->LowerWidget(_road_depot_orientation + BRDW_DEPOT_NE);
+ SndPlayFx(SND_15_BEEP);
+ this->SetDirty();
+ break;
- default:
- break;
+ default:
+ break;
+ }
}
-}
+};
/** Widget definition of the build road depot window */
static const Widget _build_road_depot_widgets[] = {
@@ -787,155 +781,128 @@
{ WIDGETS_END},
};
-/** Widget definition of the build tram depot window */
-static const Widget _build_tram_depot_widgets[] = {
-{ WWT_CLOSEBOX, RESIZE_NONE, 7, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW}, // BRDW_CLOSEBOX
-{ WWT_CAPTION, RESIZE_NONE, 7, 11, 139, 0, 13, STR_TRAM_DEPOT_ORIENTATION, STR_018C_WINDOW_TITLE_DRAG_THIS}, // BRDW_CAPTION
-{ WWT_PANEL, RESIZE_NONE, 7, 0, 139, 14, 121, 0x0, STR_NULL}, // BRDW_BACKGROUND
-{ WWT_PANEL, RESIZE_NONE, 14, 71, 136, 17, 66, 0x0, STR_SELECT_TRAM_VEHICLE_DEPOT}, // BRDW_DEPOT_NE
-{ WWT_PANEL, RESIZE_NONE, 14, 71, 136, 69, 118, 0x0, STR_SELECT_TRAM_VEHICLE_DEPOT}, // BRDW_DEPOT_SE
-{ WWT_PANEL, RESIZE_NONE, 14, 3, 68, 69, 118, 0x0, STR_SELECT_TRAM_VEHICLE_DEPOT}, // BRDW_DEPOT_SW
-{ WWT_PANEL, RESIZE_NONE, 14, 3, 68, 17, 66, 0x0, STR_SELECT_TRAM_VEHICLE_DEPOT}, // BRDW_DEPOT_NW
-{ WIDGETS_END},
-};
-
static const WindowDesc _build_road_depot_desc = {
WDP_AUTO, WDP_AUTO, 140, 122, 140, 122,
WC_BUILD_DEPOT, WC_BUILD_TOOLBAR,
WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET,
_build_road_depot_widgets,
- BuildRoadDepotWndProc
-};
-
-static const WindowDesc _build_tram_depot_desc = {
- WDP_AUTO, WDP_AUTO, 140, 122, 140, 122,
- WC_BUILD_DEPOT, WC_BUILD_TOOLBAR,
- WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET,
- _build_tram_depot_widgets,
- BuildRoadDepotWndProc
};
static void ShowRoadDepotPicker()
{
- new Window(_cur_roadtype == ROADTYPE_ROAD ? &_build_road_depot_desc : &_build_tram_depot_desc);
+ new BuildRoadDepotWindow(&_build_road_depot_desc);
}
-/** Enum referring to the widgets of the build road station window */
-enum BuildRoadStationWidgets {
- BRSW_CLOSEBOX = 0,
- BRSW_CAPTION,
- BRSW_BACKGROUND,
- BRSW_STATION_NE,
- BRSW_STATION_SE,
- BRSW_STATION_SW,
- BRSW_STATION_NW,
- BRSW_STATION_X,
- BRSW_STATION_Y,
- BRSW_LT_OFF,
- BRSW_LT_ON,
- BRSW_INFO,
-};
-
-static void RoadStationPickerWndProc(Window *w, WindowEvent *e)
-{
- switch (e->event) {
- case WE_CREATE:
- /* Trams don't have non-drivethrough stations */
- if (_cur_roadtype == ROADTYPE_TRAM && _road_station_picker_orientation < DIAGDIR_END) {
- _road_station_picker_orientation = DIAGDIR_END;
- }
- w->SetWidgetsDisabledState(_cur_roadtype == ROADTYPE_TRAM,
- BRSW_STATION_NE,
- BRSW_STATION_SE,
- BRSW_STATION_SW,
- BRSW_STATION_NW,
- WIDGET_LIST_END);
-
- w->LowerWidget(_road_station_picker_orientation + BRSW_STATION_NE);
- w->LowerWidget(_station_show_coverage + BRSW_LT_OFF);
- break;
-
- case WE_PAINT: {
- if (WP(w, def_d).close) return;
-
- DrawWindowWidgets(w);
-
- if (_station_show_coverage) {
- int rad = _patches.modified_catchment ? CA_TRUCK /* = CA_BUS */ : CA_UNMODIFIED;
- SetTileSelectBigSize(-rad, -rad, 2 * rad, 2 * rad);
- } else {
- SetTileSelectSize(1, 1);
- }
-
- StationType st = (w->window_class == WC_BUS_STATION) ? STATION_BUS : STATION_TRUCK;
-
- StationPickerDrawSprite(103, 35, st, INVALID_RAILTYPE, ROADTYPE_ROAD, 0);
- StationPickerDrawSprite(103, 85, st, INVALID_RAILTYPE, ROADTYPE_ROAD, 1);
- StationPickerDrawSprite( 35, 85, st, INVALID_RAILTYPE, ROADTYPE_ROAD, 2);
- StationPickerDrawSprite( 35, 35, st, INVALID_RAILTYPE, ROADTYPE_ROAD, 3);
-
- StationPickerDrawSprite(171, 35, st, INVALID_RAILTYPE, _cur_roadtype, 4);
- StationPickerDrawSprite(171, 85, st, INVALID_RAILTYPE, _cur_roadtype, 5);
+struct BuildRoadStationWindow : public PickerWindowBase {
+private:
+ /** Enum referring to the widgets of the build road station window */
+ enum BuildRoadStationWidgets {
+ BRSW_CLOSEBOX = 0,
+ BRSW_CAPTION,
+ BRSW_BACKGROUND,
+ BRSW_STATION_NE,
+ BRSW_STATION_SE,
+ BRSW_STATION_SW,
+ BRSW_STATION_NW,
+ BRSW_STATION_X,
+ BRSW_STATION_Y,
+ BRSW_LT_OFF,
+ BRSW_LT_ON,
+ BRSW_INFO,
+ };
- int text_end = DrawStationCoverageAreaText(2, 146,
- (w->window_class == WC_BUS_STATION) ? SCT_PASSENGERS_ONLY : SCT_NON_PASSENGERS_ONLY,
- 3, false);
- text_end = DrawStationCoverageAreaText(2, text_end + 4,
- (w->window_class == WC_BUS_STATION) ? SCT_PASSENGERS_ONLY : SCT_NON_PASSENGERS_ONLY,
- 3, true) + 4;
- if (text_end > w->widget[BRSW_BACKGROUND].bottom) {
- w->SetDirty();
- ResizeWindowForWidget(w, BRSW_BACKGROUND, 0, text_end - w->widget[BRSW_BACKGROUND].bottom);
- w->SetDirty();
- }
- } break;
-
- case WE_CLICK:
- switch (e->we.click.widget) {
- case BRSW_STATION_NE:
- case BRSW_STATION_SE:
- case BRSW_STATION_SW:
- case BRSW_STATION_NW:
- case BRSW_STATION_X:
- case BRSW_STATION_Y:
- w->RaiseWidget(_road_station_picker_orientation + BRSW_STATION_NE);
- _road_station_picker_orientation = (DiagDirection)(e->we.click.widget - BRSW_STATION_NE);
- w->LowerWidget(_road_station_picker_orientation + BRSW_STATION_NE);
- SndPlayFx(SND_15_BEEP);
- w->SetDirty();
- break;
+public:
+ BuildRoadStationWindow(const WindowDesc *desc, RoadStopType rs) : PickerWindowBase(desc)
+ {
+ /* Trams don't have non-drivethrough stations */
+ if (_cur_roadtype == ROADTYPE_TRAM && _road_station_picker_orientation < DIAGDIR_END) {
+ _road_station_picker_orientation = DIAGDIR_END;
+ }
+ this->SetWidgetsDisabledState(_cur_roadtype == ROADTYPE_TRAM,
+ BRSW_STATION_NE,
+ BRSW_STATION_SE,
+ BRSW_STATION_SW,
+ BRSW_STATION_NW,
+ WIDGET_LIST_END);
- case BRSW_LT_OFF:
- case BRSW_LT_ON:
- w->RaiseWidget(_station_show_coverage + BRSW_LT_OFF);
- _station_show_coverage = (e->we.click.widget != BRSW_LT_OFF);
- w->LowerWidget(_station_show_coverage + BRSW_LT_OFF);
- SndPlayFx(SND_15_BEEP);
- w->SetDirty();
- break;
-
- default:
- break;
- }
- break;
+ this->window_class = (rs == ROADSTOP_BUS) ? WC_BUS_STATION : WC_TRUCK_STATION;
+ this->widget[BRSW_CAPTION].data = _road_type_infos[_cur_roadtype].picker_title[rs];
+ for (uint i = BRSW_STATION_NE; i < BRSW_LT_OFF; i++) this->widget[i].tooltips = _road_type_infos[_cur_roadtype].picker_tooltip[rs];
- case WE_TICK:
- if (WP(w, def_d).close) {
- delete w;
- return;
- }
+ this->LowerWidget(_road_station_picker_orientation + BRSW_STATION_NE);
+ this->LowerWidget(_station_show_coverage + BRSW_LT_OFF);
+ this->FindWindowPlacementAndResize(desc);
+ }
- CheckRedrawStationCoverage(w);
- break;
+ virtual void OnPaint()
+ {
+ this->DrawWidgets();
- case WE_DESTROY:
- if (!WP(w, def_d).close) ResetObjectToPlace();
- break;
+ if (_station_show_coverage) {
+ int rad = _patches.modified_catchment ? CA_TRUCK /* = CA_BUS */ : CA_UNMODIFIED;
+ SetTileSelectBigSize(-rad, -rad, 2 * rad, 2 * rad);
+ } else {
+ SetTileSelectSize(1, 1);
+ }
- default:
- break;
+ StationType st = (this->window_class == WC_BUS_STATION) ? STATION_BUS : STATION_TRUCK;
+
+ StationPickerDrawSprite(103, 35, st, INVALID_RAILTYPE, ROADTYPE_ROAD, 0);
+ StationPickerDrawSprite(103, 85, st, INVALID_RAILTYPE, ROADTYPE_ROAD, 1);
+ StationPickerDrawSprite( 35, 85, st, INVALID_RAILTYPE, ROADTYPE_ROAD, 2);
+ StationPickerDrawSprite( 35, 35, st, INVALID_RAILTYPE, ROADTYPE_ROAD, 3);
+
+ StationPickerDrawSprite(171, 35, st, INVALID_RAILTYPE, _cur_roadtype, 4);
+ StationPickerDrawSprite(171, 85, st, INVALID_RAILTYPE, _cur_roadtype, 5);
+
+ int text_end = DrawStationCoverageAreaText(2, 146,
+ (this->window_class == WC_BUS_STATION) ? SCT_PASSENGERS_ONLY : SCT_NON_PASSENGERS_ONLY,
+ 3, false);
+ text_end = DrawStationCoverageAreaText(2, text_end + 4,
+ (this->window_class == WC_BUS_STATION) ? SCT_PASSENGERS_ONLY : SCT_NON_PASSENGERS_ONLY,
+ 3, true) + 4;
+ if (text_end > this->widget[BRSW_BACKGROUND].bottom) {
+ this->SetDirty();
+ ResizeWindowForWidget(this, BRSW_BACKGROUND, 0, text_end - this->widget[BRSW_BACKGROUND].bottom);
+ this->SetDirty();
+ }
}
-}
+
+ virtual void OnClick(Point pt, int widget)
+ {
+ switch (widget) {
+ case BRSW_STATION_NE:
+ case BRSW_STATION_SE:
+ case BRSW_STATION_SW:
+ case BRSW_STATION_NW:
+ case BRSW_STATION_X:
+ case BRSW_STATION_Y:
+ this->RaiseWidget(_road_station_picker_orientation + BRSW_STATION_NE);
+ _road_station_picker_orientation = (DiagDirection)(widget - BRSW_STATION_NE);
+ this->LowerWidget(_road_station_picker_orientation + BRSW_STATION_NE);
+ SndPlayFx(SND_15_BEEP);
+ this->SetDirty();
+ break;
+
+ case BRSW_LT_OFF:
+ case BRSW_LT_ON:
+ this->RaiseWidget(_station_show_coverage + BRSW_LT_OFF);
+ _station_show_coverage = (widget != BRSW_LT_OFF);
+ this->LowerWidget(_station_show_coverage + BRSW_LT_OFF);
+ SndPlayFx(SND_15_BEEP);
+ this->SetDirty();
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ virtual void OnTick()
+ {
+ CheckRedrawStationCoverage(this);
+ }
+};
/** Widget definition of the build raod station window */
static const Widget _rv_station_picker_widgets[] = {
@@ -961,17 +928,11 @@
WC_BUS_STATION, WC_BUILD_TOOLBAR,
WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET,
_rv_station_picker_widgets,
- RoadStationPickerWndProc
};
static void ShowRVStationPicker(RoadStopType rs)
{
- Window *w = new Window(&_rv_station_picker_desc);
- if (w == NULL) return;
-
- w->window_class = (rs == ROADSTOP_BUS) ? WC_BUS_STATION : WC_TRUCK_STATION;
- w->widget[BRSW_CAPTION].data = _road_type_infos[_cur_roadtype].picker_title[rs];
- for (uint i = BRSW_STATION_NE; i < BRSW_LT_OFF; i++) w->widget[i].tooltips = _road_type_infos[_cur_roadtype].picker_tooltip[rs];
+ new BuildRoadStationWindow(&_rv_station_picker_desc, rs);
}
void InitializeRoadGui()
--- a/src/roadveh_cmd.cpp Mon May 19 14:14:33 2008 +0000
+++ b/src/roadveh_cmd.cpp Mon May 19 15:13:58 2008 +0000
@@ -281,7 +281,7 @@
VehiclePositionChanged(v);
InvalidateWindowData(WC_VEHICLE_DEPOT, v->tile);
- RebuildVehicleLists();
+ InvalidateWindowClassesData(WC_ROADVEH_LIST, 0);
InvalidateWindow(WC_COMPANY, v->owner);
if (IsLocalPlayer())
InvalidateAutoreplaceWindow(v->engine_type, v->group_id); // updates the replace Road window
@@ -382,7 +382,7 @@
if (flags & DC_EXEC) {
// Invalidate depot
InvalidateWindow(WC_VEHICLE_DEPOT, v->tile);
- RebuildVehicleLists();
+ InvalidateWindowClassesData(WC_ROADVEH_LIST, 0);
InvalidateWindow(WC_COMPANY, v->owner);
DeleteWindowById(WC_VEHICLE_VIEW, v->index);
DeleteDepotHighlightOfVehicle(v);
@@ -575,7 +575,7 @@
DeleteWindowById(WC_VEHICLE_VIEW, v->index);
- RebuildVehicleLists();
+ InvalidateWindowClassesData(WC_ROADVEH_LIST, 0);
InvalidateWindow(WC_COMPANY, v->owner);
if (IsTileType(v->tile, MP_STATION)) ClearCrashedStation(v);
@@ -667,7 +667,7 @@
AddNewsItem(
(pass == 1) ?
STR_9031_ROAD_VEHICLE_CRASH_DRIVER : STR_9032_ROAD_VEHICLE_CRASH_DIE,
- NM_THIN, NF_VIEWPORT | NF_VEHICLE, NT_ACCIDENT, DNC_NONE,
+ NS_ACCIDENT_VEHICLE,
v->index,
0
);
@@ -833,7 +833,7 @@
SetDParam(0, st->index);
AddNewsItem(
v->u.road.roadtype == ROADTYPE_ROAD ? STR_902F_CITIZENS_CELEBRATE_FIRST : STR_CITIZENS_CELEBRATE_FIRST_PASSENGER_TRAM,
- NM_THIN, NF_VIEWPORT | NF_VEHICLE, (v->owner == _local_player) ? NT_ARRIVAL_PLAYER : NT_ARRIVAL_OTHER, DNC_NONE,
+ (v->owner == _local_player) ? NS_ARRIVAL_PLAYER : NS_ARRIVAL_OTHER,
v->index,
0);
}
@@ -844,7 +844,7 @@
SetDParam(0, st->index);
AddNewsItem(
v->u.road.roadtype == ROADTYPE_ROAD ? STR_9030_CITIZENS_CELEBRATE_FIRST : STR_CITIZENS_CELEBRATE_FIRST_CARGO_TRAM,
- NM_THIN, NF_VIEWPORT | NF_VEHICLE, (v->owner == _local_player) ? NT_ARRIVAL_PLAYER : NT_ARRIVAL_OTHER, DNC_NONE,
+ (v->owner == _local_player) ? NS_ARRIVAL_PLAYER : NS_ARRIVAL_OTHER,
v->index,
0
);
@@ -973,7 +973,7 @@
/* Check if vehicle is in a road stop, depot, tunnel or bridge or not on a straight road */
if (v->u.road.state >= RVSB_IN_ROAD_STOP || !IsStraightRoadTrackdir((Trackdir)(v->u.road.state & RVSB_TRACKDIR_MASK))) return;
- od.trackdir = DiagdirToDiagTrackdir(DirToDiagDir(v->direction));
+ od.trackdir = DiagDirToDiagTrackdir(DirToDiagDir(v->direction));
/* Are the current and the next tile suitable for overtaking?
* - Does the track continue along od.trackdir
@@ -1138,7 +1138,7 @@
NPFFindStationOrTileData fstd;
NPFFillWithOrderData(&fstd, v);
- Trackdir trackdir = DiagdirToDiagTrackdir(enterdir);
+ Trackdir trackdir = DiagDirToDiagTrackdir(enterdir);
//debug("Finding path. Enterdir: %d, Trackdir: %d", enterdir, trackdir);
NPFFoundTargetData ftd = PerfNPFRouteToStationOrTile(tile - TileOffsByDiagDir(enterdir), trackdir, true, &fstd, TRANSPORT_ROAD, v->u.road.compatible_roadtypes, v->owner, INVALID_RAILTYPES);
@@ -1328,7 +1328,7 @@
}
if (diag_dir == INVALID_DIAGDIR) return INVALID_TRACKDIR;
- dir = DiagdirToDiagTrackdir(diag_dir);
+ dir = DiagDirToDiagTrackdir(diag_dir);
} else {
if (already_reversed && prev->tile != tile) {
/*
@@ -2122,7 +2122,7 @@
v->cargo_subtype = new_subtype;
InvalidateWindow(WC_VEHICLE_DETAILS, v->index);
InvalidateWindow(WC_VEHICLE_DEPOT, v->tile);
- RebuildVehicleLists();
+ InvalidateWindowClassesData(WC_ROADVEH_LIST, 0);
}
if (only_this) break;
--- a/src/saveload.cpp Mon May 19 14:14:33 2008 +0000
+++ b/src/saveload.cpp Mon May 19 15:13:58 2008 +0000
@@ -30,6 +30,7 @@
#include "core/endian_func.hpp"
#include "vehicle_base.h"
#include "autoreplace_base.h"
+#include "statusbar_gui.h"
#include <list>
#include "table/strings.h"
@@ -1493,7 +1494,7 @@
_fast_forward = 0;
if (_cursor.sprite == SPR_CURSOR_MOUSE) SetMouseCursor(SPR_CURSOR_ZZZ, PAL_NONE);
- InvalidateWindowData(WC_STATUS_BAR, 0, true);
+ InvalidateWindowData(WC_STATUS_BAR, 0, SBI_SAVELOAD_START);
_ts.saveinprogress = true;
}
@@ -1504,7 +1505,7 @@
_fast_forward = _ts.ff_state;
if (_cursor.sprite == SPR_CURSOR_ZZZ) SetMouseCursor(SPR_CURSOR_MOUSE, PAL_NONE);
- InvalidateWindowData(WC_STATUS_BAR, 0, false);
+ InvalidateWindowData(WC_STATUS_BAR, 0, SBI_SAVELOAD_FINISH);
_ts.saveinprogress = false;
}
@@ -1533,7 +1534,7 @@
SaveFileDone();
}
-static ThreadObject *save_thread;
+static ThreadObject *_save_thread;
/** We have written the whole game into memory, _Savegame_pool, now find
* and appropiate compressor and start writing to file.
@@ -1603,10 +1604,10 @@
void WaitTillSaved()
{
- if (save_thread == NULL) return;
+ if (_save_thread == NULL) return;
- save_thread->Join();
- save_thread = NULL;
+ _save_thread->Join();
+ _save_thread = NULL;
}
/**
@@ -1678,7 +1679,7 @@
SaveFileStart();
if (_network_server ||
- (save_thread = ThreadObject::New(&SaveFileToDiskThread, NULL)) == NULL) {
+ (_save_thread = ThreadObject::New(&SaveFileToDiskThread, NULL)) == NULL) {
if (!_network_server) DEBUG(sl, 1, "Cannot create savegame thread, reverting to single-threaded mode...");
SaveOrLoadResult result = SaveFileToDisk(false);
--- a/src/settings.cpp Mon May 19 14:14:33 2008 +0000
+++ b/src/settings.cpp Mon May 19 15:13:58 2008 +0000
@@ -1141,6 +1141,12 @@
return 0;
}
+static int32 InvalidateBuildIndustryWindow(int32 p1)
+{
+ InvalidateWindowData(WC_BUILD_INDUSTRY, 0);
+ return 0;
+}
+
static int32 CloseSignalGUI(int32 p1)
{
if (p1 == 0) {
@@ -1482,7 +1488,7 @@
/***************************************************************************/
/* Economy section of the GUI-configure patches window */
SDT_BOOL(Patches, inflation, 0, 0, true, STR_CONFIG_PATCHES_INFLATION, NULL),
- SDT_VAR(Patches, raw_industry_construction,SLE_UINT8,0,MS,0,0, 2, 0, STR_CONFIG_PATCHES_RAW_INDUSTRY_CONSTRUCTION_METHOD, NULL),
+ SDT_VAR(Patches, raw_industry_construction,SLE_UINT8,0,MS,0,0, 2, 0, STR_CONFIG_PATCHES_RAW_INDUSTRY_CONSTRUCTION_METHOD, InvalidateBuildIndustryWindow),
SDT_BOOL(Patches, multiple_industry_per_town, 0, 0, false, STR_CONFIG_PATCHES_MULTIPINDTOWN, NULL),
SDT_BOOL(Patches, same_industry_close, 0, 0, false, STR_CONFIG_PATCHES_SAMEINDCLOSE, NULL),
SDT_BOOL(Patches, bribe, 0, 0, true, STR_CONFIG_PATCHES_BRIBE, NULL),
--- a/src/settings_gui.cpp Mon May 19 14:14:33 2008 +0000
+++ b/src/settings_gui.cpp Mon May 19 15:13:58 2008 +0000
@@ -20,7 +20,6 @@
#include "strings_func.h"
#include "functions.h"
#include "window_func.h"
-#include "vehicle_base.h"
#include "core/alloc_func.hpp"
#include "string_func.h"
#include "gfx_func.h"
@@ -102,17 +101,6 @@
return i;
}
-static inline bool RoadVehiclesAreBuilt()
-{
- const Vehicle* v;
-
- FOR_ALL_VEHICLES(v) {
- if (v->type == VEH_ROAD) return true;
- }
- return false;
-}
-
-
enum GameOptionsWidgets {
GAMEOPT_CURRENCY_BTN = 4,
GAMEOPT_DISTANCE_BTN = 6,
@@ -151,199 +139,178 @@
ShowDropDownList(w, list, sel, GAMEOPT_TOWNNAME_BTN);
}
-/**
- * Update/redraw the languages dropdown
- * @param w the window the dropdown belongs to
- */
-static void ShowLangDropdown(Window *w)
-{
- typedef std::map<StringID, int, StringIDCompare> LangList;
-
- /* Sort language names */
- LangList langs;
- for (int i = 0; i < _dynlang.num; i++) langs[SPECSTR_LANGUAGE_START + i] = i;
-
- DropDownList *list = new DropDownList();
- for (LangList::iterator it = langs.begin(); it != langs.end(); it++) {
- list->push_back(new DropDownListStringItem((*it).first, (*it).second, false));
- }
-
- ShowDropDownList(w, list, _dynlang.curr, GAMEOPT_LANG_BTN);
-}
-
static void ShowCustCurrency();
-static void GameOptionsWndProc(Window *w, WindowEvent *e)
-{
- switch (e->event) {
- case WE_PAINT: {
- int i;
- StringID str = STR_02BE_DEFAULT;
-
- w->SetWidgetDisabledState(GAMEOPT_VEHICLENAME_SAVE, !(_vehicle_design_names & 1));
- if (!w->IsWidgetDisabled(GAMEOPT_VEHICLENAME_SAVE)) str = STR_02BF_CUSTOM;
- SetDParam(0, str);
- SetDParam(1, _currency_specs[_opt_ptr->currency].name);
- SetDParam(2, STR_UNITS_IMPERIAL + _opt_ptr->units);
- SetDParam(3, STR_02E9_DRIVE_ON_LEFT + _opt_ptr->road_side);
- SetDParam(4, TownName(_opt_ptr->town_name));
- SetDParam(5, _autosave_dropdown[_opt_ptr->autosave]);
- SetDParam(6, SPECSTR_LANGUAGE_START + _dynlang.curr);
- i = GetCurRes();
- SetDParam(7, i == _num_resolutions ? STR_RES_OTHER : SPECSTR_RESOLUTION_START + i);
- SetDParam(8, SPECSTR_SCREENSHOT_START + _cur_screenshot_format);
- w->SetWidgetLoweredState(GAMEOPT_FULLSCREEN, _fullscreen);
-
- DrawWindowWidgets(w);
- DrawString(20, 175, STR_OPTIONS_FULLSCREEN, TC_FROMSTRING); // fullscreen
- } break;
-
- case WE_CLICK:
- switch (e->we.click.widget) {
- case GAMEOPT_CURRENCY_BTN: /* Setup currencies dropdown */
- ShowDropDownMenu(w, BuildCurrencyDropdown(), _opt_ptr->currency, GAMEOPT_CURRENCY_BTN, _game_mode == GM_MENU ? 0 : ~GetMaskOfAllowedCurrencies(), 0);
- break;
-
- case GAMEOPT_DISTANCE_BTN: /* Setup distance unit dropdown */
- ShowDropDownMenu(w, _units_dropdown, _opt_ptr->units, GAMEOPT_DISTANCE_BTN, 0, 0);
- break;
-
- case GAMEOPT_ROADSIDE_BTN: { /* Setup road-side dropdown */
- int i = 0;
-
- /* You can only change the drive side if you are in the menu or ingame with
- * no vehicles present. In a networking game only the server can change it */
- if ((_game_mode != GM_MENU && RoadVehiclesAreBuilt()) || (_networking && !_network_server))
- i = (-1) ^ (1 << _opt_ptr->road_side); // disable the other value
-
- ShowDropDownMenu(w, _driveside_dropdown, _opt_ptr->road_side, GAMEOPT_ROADSIDE_BTN, i, 0);
- } break;
-
- case GAMEOPT_TOWNNAME_BTN: /* Setup townname dropdown */
- ShowTownnameDropdown(w, _opt_ptr->town_name);
- break;
-
- case GAMEOPT_AUTOSAVE_BTN: /* Setup autosave dropdown */
- ShowDropDownMenu(w, _autosave_dropdown, _opt_ptr->autosave, GAMEOPT_AUTOSAVE_BTN, 0, 0);
- break;
-
- case GAMEOPT_VEHICLENAME_BTN: /* Setup customized vehicle-names dropdown */
- ShowDropDownMenu(w, _designnames_dropdown, (_vehicle_design_names & 1) ? 1 : 0, GAMEOPT_VEHICLENAME_BTN, (_vehicle_design_names & 2) ? 0 : 2, 0);
- break;
-
- case GAMEOPT_VEHICLENAME_SAVE: /* Save customized vehicle-names to disk */
- break; // not implemented
-
- case GAMEOPT_LANG_BTN: /* Setup interface language dropdown */
- ShowLangDropdown(w);
- break;
-
- case GAMEOPT_RESOLUTION_BTN: /* Setup resolution dropdown */
- ShowDropDownMenu(w, BuildDynamicDropdown(SPECSTR_RESOLUTION_START, _num_resolutions), GetCurRes(), GAMEOPT_RESOLUTION_BTN, 0, 0);
- break;
-
- case GAMEOPT_FULLSCREEN: /* Click fullscreen on/off */
- /* try to toggle full-screen on/off */
- if (!ToggleFullScreen(!_fullscreen)) {
- ShowErrorMessage(INVALID_STRING_ID, STR_FULLSCREEN_FAILED, 0, 0);
- }
- w->SetWidgetLoweredState(GAMEOPT_FULLSCREEN, _fullscreen);
- w->SetDirty();
- break;
-
- case GAMEOPT_SCREENSHOT_BTN: /* Setup screenshot format dropdown */
- ShowDropDownMenu(w, BuildDynamicDropdown(SPECSTR_SCREENSHOT_START, _num_screenshot_formats), _cur_screenshot_format, GAMEOPT_SCREENSHOT_BTN, 0, 0);
- break;
- }
- break;
-
- case WE_DROPDOWN_SELECT:
- switch (e->we.dropdown.button) {
- case GAMEOPT_VEHICLENAME_BTN: /* Vehicle design names */
- if (e->we.dropdown.index == 0) {
- DeleteCustomEngineNames();
- MarkWholeScreenDirty();
- } else if (!(_vehicle_design_names & 1)) {
- LoadCustomEngineNames();
- MarkWholeScreenDirty();
- }
- break;
-
- case GAMEOPT_CURRENCY_BTN: /* Currency */
- if (e->we.dropdown.index == CUSTOM_CURRENCY_ID) ShowCustCurrency();
- _opt_ptr->currency = e->we.dropdown.index;
- MarkWholeScreenDirty();
- break;
-
- case GAMEOPT_DISTANCE_BTN: /* Measuring units */
- _opt_ptr->units = e->we.dropdown.index;
- MarkWholeScreenDirty();
- break;
-
- case GAMEOPT_ROADSIDE_BTN: /* Road side */
- if (_opt_ptr->road_side != e->we.dropdown.index) { // only change if setting changed
- DoCommandP(0, e->we.dropdown.index, 0, NULL, CMD_SET_ROAD_DRIVE_SIDE | CMD_MSG(STR_00B4_CAN_T_DO_THIS));
- MarkWholeScreenDirty();
- }
- break;
-
- case GAMEOPT_TOWNNAME_BTN: /* Town names */
- if (_game_mode == GM_MENU) {
- _opt_ptr->town_name = e->we.dropdown.index;
- InvalidateWindow(WC_GAME_OPTIONS, 0);
- }
- break;
-
- case GAMEOPT_AUTOSAVE_BTN: /* Autosave options */
- _opt.autosave = _opt_newgame.autosave = e->we.dropdown.index;
- w->SetDirty();
- break;
-
- case GAMEOPT_LANG_BTN: /* Change interface language */
- ReadLanguagePack(e->we.dropdown.index);
- CheckForMissingGlyphsInLoadedLanguagePack();
- UpdateAllStationVirtCoord();
- UpdateAllWaypointSigns();
- MarkWholeScreenDirty();
- break;
-
- case GAMEOPT_RESOLUTION_BTN: /* Change resolution */
- if (e->we.dropdown.index < _num_resolutions && ChangeResInGame(_resolutions[e->we.dropdown.index][0], _resolutions[e->we.dropdown.index][1]))
- w->SetDirty();
- break;
-
- case GAMEOPT_SCREENSHOT_BTN: /* Change screenshot format */
- SetScreenshotFormat(e->we.dropdown.index);
- w->SetDirty();
- break;
- }
- break;
-
- case WE_DESTROY:
- DeleteWindowById(WC_CUSTOM_CURRENCY, 0);
- break;
+struct GameOptionsWindow : Window {
+ GameOptionsWindow(const WindowDesc *desc) : Window(desc)
+ {
+ this->FindWindowPlacementAndResize(desc);
}
-}
+ ~GameOptionsWindow()
+ {
+ DeleteWindowById(WC_CUSTOM_CURRENCY, 0);
+ }
-/** Change the side of the road vehicles drive on (server only).
- * @param tile unused
- * @param flags operation to perform
- * @param p1 the side of the road; 0 = left side and 1 = right side
- * @param p2 unused
- */
-CommandCost CmdSetRoadDriveSide(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
-{
- /* Check boundaries and you can only change this if NO vehicles have been built yet,
- * except in the intro-menu where of course it's always possible to do so. */
- if (p1 > 1 || (_game_mode != GM_MENU && RoadVehiclesAreBuilt())) return CMD_ERROR;
+ virtual void OnPaint()
+ {
+ StringID str = STR_02BE_DEFAULT;
- if (flags & DC_EXEC) {
- _opt_ptr->road_side = p1;
- InvalidateWindow(WC_GAME_OPTIONS, 0);
+ this->SetWidgetDisabledState(GAMEOPT_VEHICLENAME_SAVE, !(_vehicle_design_names & 1));
+ if (!this->IsWidgetDisabled(GAMEOPT_VEHICLENAME_SAVE)) str = STR_02BF_CUSTOM;
+ SetDParam(0, str);
+ SetDParam(1, _currency_specs[_opt_ptr->currency].name);
+ SetDParam(2, STR_UNITS_IMPERIAL + _opt_ptr->units);
+ SetDParam(3, STR_02E9_DRIVE_ON_LEFT + _opt_ptr->road_side);
+ SetDParam(4, TownName(_opt_ptr->town_name));
+ SetDParam(5, _autosave_dropdown[_opt_ptr->autosave]);
+ SetDParam(6, SPECSTR_LANGUAGE_START + _dynlang.curr);
+ int i = GetCurRes();
+ SetDParam(7, i == _num_resolutions ? STR_RES_OTHER : SPECSTR_RESOLUTION_START + i);
+ SetDParam(8, SPECSTR_SCREENSHOT_START + _cur_screenshot_format);
+ this->SetWidgetLoweredState(GAMEOPT_FULLSCREEN, _fullscreen);
+
+ this->DrawWidgets();
+ DrawString(20, 175, STR_OPTIONS_FULLSCREEN, TC_FROMSTRING); // fullscreen
}
- return CommandCost();
-}
+
+ virtual void OnClick(Point pt, int widget)
+ {
+ switch (widget) {
+ case GAMEOPT_CURRENCY_BTN: // Setup currencies dropdown
+ ShowDropDownMenu(this, BuildCurrencyDropdown(), _opt_ptr->currency, GAMEOPT_CURRENCY_BTN, _game_mode == GM_MENU ? 0 : ~GetMaskOfAllowedCurrencies(), 0);
+ break;
+
+ case GAMEOPT_DISTANCE_BTN: // Setup distance unit dropdown
+ ShowDropDownMenu(this, _units_dropdown, _opt_ptr->units, GAMEOPT_DISTANCE_BTN, 0, 0);
+ break;
+
+ case GAMEOPT_ROADSIDE_BTN: { // Setup road-side dropdown
+ int i = 0;
+ extern bool RoadVehiclesAreBuilt();
+
+ /* You can only change the drive side if you are in the menu or ingame with
+ * no vehicles present. In a networking game only the server can change it */
+ if ((_game_mode != GM_MENU && RoadVehiclesAreBuilt()) || (_networking && !_network_server)) {
+ i = (-1) ^ (1 << _opt_ptr->road_side); // disable the other value
+ }
+
+ ShowDropDownMenu(this, _driveside_dropdown, _opt_ptr->road_side, GAMEOPT_ROADSIDE_BTN, i, 0);
+ } break;
+
+ case GAMEOPT_TOWNNAME_BTN: // Setup townname dropdown
+ ShowTownnameDropdown(this, _opt_ptr->town_name);
+ break;
+
+ case GAMEOPT_AUTOSAVE_BTN: // Setup autosave dropdown
+ ShowDropDownMenu(this, _autosave_dropdown, _opt_ptr->autosave, GAMEOPT_AUTOSAVE_BTN, 0, 0);
+ break;
+
+ case GAMEOPT_VEHICLENAME_BTN: // Setup customized vehicle-names dropdown
+ ShowDropDownMenu(this, _designnames_dropdown, (_vehicle_design_names & 1) ? 1 : 0, GAMEOPT_VEHICLENAME_BTN, (_vehicle_design_names & 2) ? 0 : 2, 0);
+ break;
+
+ case GAMEOPT_VEHICLENAME_SAVE: // Save customized vehicle-names to disk
+ break; // not implemented
+
+ case GAMEOPT_LANG_BTN: { // Setup interface language dropdown
+ typedef std::map<StringID, int, StringIDCompare> LangList;
+
+ /* Sort language names */
+ LangList langs;
+ for (int i = 0; i < _dynlang.num; i++) langs[SPECSTR_LANGUAGE_START + i] = i;
+
+ DropDownList *list = new DropDownList();
+ for (LangList::iterator it = langs.begin(); it != langs.end(); it++) {
+ list->push_back(new DropDownListStringItem((*it).first, (*it).second, false));
+ }
+
+ ShowDropDownList(this, list, _dynlang.curr, GAMEOPT_LANG_BTN);
+ } break;
+
+ case GAMEOPT_RESOLUTION_BTN: // Setup resolution dropdown
+ ShowDropDownMenu(this, BuildDynamicDropdown(SPECSTR_RESOLUTION_START, _num_resolutions), GetCurRes(), GAMEOPT_RESOLUTION_BTN, 0, 0);
+ break;
+
+ case GAMEOPT_FULLSCREEN: // Click fullscreen on/off
+ /* try to toggle full-screen on/off */
+ if (!ToggleFullScreen(!_fullscreen)) {
+ ShowErrorMessage(INVALID_STRING_ID, STR_FULLSCREEN_FAILED, 0, 0);
+ }
+ this->SetWidgetLoweredState(GAMEOPT_FULLSCREEN, _fullscreen);
+ this->SetDirty();
+ break;
+
+ case GAMEOPT_SCREENSHOT_BTN: // Setup screenshot format dropdown
+ ShowDropDownMenu(this, BuildDynamicDropdown(SPECSTR_SCREENSHOT_START, _num_screenshot_formats), _cur_screenshot_format, GAMEOPT_SCREENSHOT_BTN, 0, 0);
+ break;
+ }
+ }
+
+ virtual void OnDropdownSelect(int widget, int index)
+ {
+ switch (widget) {
+ case GAMEOPT_VEHICLENAME_BTN: // Vehicle design names
+ if (index == 0) {
+ DeleteCustomEngineNames();
+ MarkWholeScreenDirty();
+ } else if (!(_vehicle_design_names & 1)) {
+ LoadCustomEngineNames();
+ MarkWholeScreenDirty();
+ }
+ break;
+
+ case GAMEOPT_CURRENCY_BTN: /* Currency */
+ if (index == CUSTOM_CURRENCY_ID) ShowCustCurrency();
+ _opt_ptr->currency = index;
+ MarkWholeScreenDirty();
+ break;
+
+ case GAMEOPT_DISTANCE_BTN: // Measuring units
+ _opt_ptr->units = index;
+ MarkWholeScreenDirty();
+ break;
+
+ case GAMEOPT_ROADSIDE_BTN: // Road side
+ if (_opt_ptr->road_side != index) { // only change if setting changed
+ DoCommandP(0, index, 0, NULL, CMD_SET_ROAD_DRIVE_SIDE | CMD_MSG(STR_00B4_CAN_T_DO_THIS));
+ MarkWholeScreenDirty();
+ }
+ break;
+
+ case GAMEOPT_TOWNNAME_BTN: // Town names
+ if (_game_mode == GM_MENU) {
+ _opt_ptr->town_name = index;
+ InvalidateWindow(WC_GAME_OPTIONS, 0);
+ }
+ break;
+
+ case GAMEOPT_AUTOSAVE_BTN: // Autosave options
+ _opt.autosave = _opt_newgame.autosave = index;
+ this->SetDirty();
+ break;
+
+ case GAMEOPT_LANG_BTN: // Change interface language
+ ReadLanguagePack(index);
+ CheckForMissingGlyphsInLoadedLanguagePack();
+ UpdateAllStationVirtCoord();
+ UpdateAllWaypointSigns();
+ MarkWholeScreenDirty();
+ break;
+
+ case GAMEOPT_RESOLUTION_BTN: // Change resolution
+ if (index < _num_resolutions && ChangeResInGame(_resolutions[index][0], _resolutions[index][1])) {
+ this->SetDirty();
+ }
+ break;
+
+ case GAMEOPT_SCREENSHOT_BTN: // Change screenshot format
+ SetScreenshotFormat(index);
+ this->SetDirty();
+ break;
+ }
+ }
+};
static const Widget _game_options_widgets[] = {
{ WWT_CLOSEBOX, RESIZE_NONE, 14, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW},
@@ -382,14 +349,13 @@
WC_GAME_OPTIONS, WC_NONE,
WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS,
_game_options_widgets,
- GameOptionsWndProc
};
void ShowGameOptions()
{
DeleteWindowById(WC_GAME_OPTIONS, 0);
- new Window(&_game_options_desc);
+ new GameOptionsWindow(&_game_options_desc);
}
struct GameSettingData {
@@ -478,194 +444,6 @@
extern void StartupEconomy();
-enum {
- GAMEDIFF_WND_TOP_OFFSET = 45,
- GAMEDIFF_WND_ROWSIZE = 9
-};
-
-/* Temporary holding place of values in the difficulty window until 'Save' is clicked */
-static GameOptions _opt_mod_temp;
-// 0x383E = (1 << 13) | (1 << 12) | (1 << 11) | (1 << 5) | (1 << 4) | (1 << 3) | (1 << 2) | (1 << 1)
-#define DIFF_INGAME_DISABLED_BUTTONS 0x383E
-
-#define NO_SETTINGS_BUTTON 0xFF
-
-/** Carriage for the game settings window data */
-struct difficulty_d {
- bool clicked_increase;
- uint8 clicked_button;
- uint8 timeout;
-};
-assert_compile(WINDOW_CUSTOM_SIZE >= sizeof(difficulty_d));
-
-/* Names of the game difficulty settings window */
-enum GameDifficultyWidgets {
- GDW_CLOSEBOX = 0,
- GDW_CAPTION,
- GDW_UPPER_BG,
- GDW_LVL_EASY,
- GDW_LVL_MEDIUM,
- GDW_LVL_HARD,
- GDW_LVL_CUSTOM,
- GDW_HIGHSCORE,
- GDW_SETTING_BG,
- GDW_LOWER_BG,
- GDW_ACCEPT,
- GDW_CANCEL,
-};
-
-static void GameDifficultyWndProc(Window *w, WindowEvent *e)
-{
- difficulty_d *diffic_d = &WP(w, difficulty_d);
- switch (e->event) {
- case WE_CREATE:
- diffic_d->clicked_increase = false;
- diffic_d->clicked_button = NO_SETTINGS_BUTTON;
- diffic_d->timeout = 0;
- /* Hide the closebox to make sure that the user aborts or confirms his changes */
- w->HideWidget(GDW_CLOSEBOX);
- w->widget[GDW_CAPTION].left = 0;
- /* Setup disabled buttons when creating window
- * disable all other difficulty buttons during gameplay except for 'custom' */
- w->SetWidgetsDisabledState(_game_mode == GM_NORMAL,
- GDW_LVL_EASY,
- GDW_LVL_MEDIUM,
- GDW_LVL_HARD,
- GDW_LVL_CUSTOM,
- WIDGET_LIST_END);
- w->SetWidgetDisabledState(GDW_HIGHSCORE, _game_mode == GM_EDITOR || _networking); // highscore chart in multiplayer
- w->SetWidgetDisabledState(GDW_ACCEPT, _networking && !_network_server); // Save-button in multiplayer (and if client)
- w->LowerWidget(GDW_LVL_EASY + _opt_mod_temp.diff_level);
- break;
-
- case WE_PAINT: {
- DrawWindowWidgets(w);
-
- /* XXX - Disabled buttons in normal gameplay or during muliplayer as non server.
- * Bitshifted for each button to see if that bit is set. If it is set, the
- * button is disabled */
- uint32 disabled = 0;
- if (_networking && !_network_server) {
- disabled = MAX_UVALUE(uint32); // Disable all
- } else if (_game_mode == GM_NORMAL) {
- disabled = DIFF_INGAME_DISABLED_BUTTONS;
- }
-
- int value;
- int y = GAMEDIFF_WND_TOP_OFFSET;
- for (uint i = 0; i != GAME_DIFFICULTY_NUM; i++) {
- const GameSettingData *gsd = &_game_setting_info[i];
- value = ((GDType*)&_opt_mod_temp.diff)[i];
-
- DrawArrowButtons(5, y, 3,
- (diffic_d->clicked_button == i) ? 1 + !!diffic_d->clicked_increase : 0,
- !(HasBit(disabled, i) || gsd->min == value),
- !(HasBit(disabled, i) || gsd->max == value));
-
- value += _game_setting_info[i].str;
- if (i == 4) value *= 1000; // XXX - handle currency option
- SetDParam(0, value);
- DrawString(30, y, STR_6805_MAXIMUM_NO_COMPETITORS + i, TC_FROMSTRING);
-
- y += GAMEDIFF_WND_ROWSIZE + 2; // space items apart a bit
- }
- } break;
-
- case WE_CLICK:
- switch (e->we.click.widget) {
- case GDW_SETTING_BG: { /* Difficulty settings widget, decode click */
- /* Don't allow clients to make any changes */
- if (_networking && !_network_server) return;
-
- const int x = e->we.click.pt.x - 5;
- if (!IsInsideMM(x, 0, 21)) // Button area
- return;
-
- const int y = e->we.click.pt.y - GAMEDIFF_WND_TOP_OFFSET;
- if (y < 0) return;
-
- /* Get button from Y coord. */
- const uint8 btn = y / (GAMEDIFF_WND_ROWSIZE + 2);
- if (btn >= GAME_DIFFICULTY_NUM || y % (GAMEDIFF_WND_ROWSIZE + 2) >= 9)
- return;
-
- /* Clicked disabled button? */
- if (_game_mode == GM_NORMAL && HasBit(DIFF_INGAME_DISABLED_BUTTONS, btn))
- return;
-
- diffic_d->timeout = 5;
-
- int16 val = ((GDType*)&_opt_mod_temp.diff)[btn];
-
- const GameSettingData *info = &_game_setting_info[btn]; // get information about the difficulty setting
- if (x >= 10) {
- /* Increase button clicked */
- val = min(val + info->step, info->max);
- diffic_d->clicked_increase = true;
- } else {
- /* Decrease button clicked */
- val -= info->step;
- val = max(val, info->min);
- diffic_d->clicked_increase = false;
- }
- diffic_d->clicked_button = btn;
-
- /* save value in temporary variable */
- ((GDType*)&_opt_mod_temp.diff)[btn] = val;
- w->RaiseWidget(GDW_LVL_EASY + _opt_mod_temp.diff_level);
- SetDifficultyLevel(3, &_opt_mod_temp); // set difficulty level to custom
- w->LowerWidget(GDW_LVL_CUSTOM);
- w->SetDirty();
- } break;
-
- case GDW_LVL_EASY:
- case GDW_LVL_MEDIUM:
- case GDW_LVL_HARD:
- case GDW_LVL_CUSTOM:
- /* temporarily change difficulty level */
- w->RaiseWidget(GDW_LVL_EASY + _opt_mod_temp.diff_level);
- SetDifficultyLevel(e->we.click.widget - GDW_LVL_EASY, &_opt_mod_temp);
- w->LowerWidget(GDW_LVL_EASY + _opt_mod_temp.diff_level);
- w->SetDirty();
- break;
-
- case GDW_HIGHSCORE: // Highscore Table
- ShowHighscoreTable(_opt_mod_temp.diff_level, -1);
- break;
-
- case GDW_ACCEPT: { // Save button - save changes
- GDType btn, val;
- for (btn = 0; btn != GAME_DIFFICULTY_NUM; btn++) {
- val = ((GDType*)&_opt_mod_temp.diff)[btn];
- /* if setting has changed, change it */
- if (val != ((GDType*)&_opt_ptr->diff)[btn])
- DoCommandP(0, btn, val, NULL, CMD_CHANGE_DIFFICULTY_LEVEL);
- }
- DoCommandP(0, UINT_MAX, _opt_mod_temp.diff_level, NULL, CMD_CHANGE_DIFFICULTY_LEVEL);
- delete w;
- /* If we are in the editor, we should reload the economy.
- * This way when you load a game, the max loan and interest rate
- * are loaded correctly. */
- if (_game_mode == GM_EDITOR) StartupEconomy();
- break;
- }
-
- case GDW_CANCEL: // Cancel button - close window, abandon changes
- delete w;
- break;
- } break;
-
- case WE_TICK: /* Handle the visual 'clicking' of the buttons */
- if (diffic_d->timeout != 0) {
- diffic_d->timeout--;
- if (diffic_d->timeout == 0) diffic_d->clicked_button = NO_SETTINGS_BUTTON;
- w->SetDirty();
- }
- break;
- }
-}
-#undef DIFF_INGAME_DISABLED_BUTTONS
-
/* Widget definition for the game difficulty settings window */
static const Widget _game_difficulty_widgets[] = {
{ WWT_CLOSEBOX, RESIZE_NONE, 10, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW}, // GDW_CLOSEBOX
@@ -689,16 +467,198 @@
WC_GAME_OPTIONS, WC_NONE,
WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET,
_game_difficulty_widgets,
- GameDifficultyWndProc
+};
+
+struct GameDifficultyWindow : public Window {
+private:
+ bool clicked_increase;
+ uint8 clicked_button;
+ uint8 timeout;
+
+ /* Temporary holding place of values in the difficulty window until 'Save' is clicked */
+ GameOptions opt_mod_temp;
+
+ enum {
+ GAMEDIFF_WND_TOP_OFFSET = 45,
+ GAMEDIFF_WND_ROWSIZE = 9,
+ // 0x383E = (1 << 13) | (1 << 12) | (1 << 11) | (1 << 5) | (1 << 4) | (1 << 3) | (1 << 2) | (1 << 1)
+ DIFF_INGAME_DISABLED_BUTTONS = 0x383E,
+ NO_SETTINGS_BUTTON = 0xFF,
+ };
+
+ /* Names of the game difficulty settings window */
+ enum GameDifficultyWidgets {
+ GDW_CLOSEBOX = 0,
+ GDW_CAPTION,
+ GDW_UPPER_BG,
+ GDW_LVL_EASY,
+ GDW_LVL_MEDIUM,
+ GDW_LVL_HARD,
+ GDW_LVL_CUSTOM,
+ GDW_HIGHSCORE,
+ GDW_SETTING_BG,
+ GDW_LOWER_BG,
+ GDW_ACCEPT,
+ GDW_CANCEL,
+ };
+
+public:
+ GameDifficultyWindow() : Window(&_game_difficulty_desc)
+ {
+ /* Copy current settings (ingame or in intro) to temporary holding place
+ * change that when setting stuff, copy back on clicking 'OK' */
+ this->opt_mod_temp = *_opt_ptr;
+ this->clicked_increase = false;
+ this->clicked_button = NO_SETTINGS_BUTTON;
+ this->timeout = 0;
+ /* Hide the closebox to make sure that the user aborts or confirms his changes */
+ this->HideWidget(GDW_CLOSEBOX);
+ this->widget[GDW_CAPTION].left = 0;
+ /* Setup disabled buttons when creating window
+ * disable all other difficulty buttons during gameplay except for 'custom' */
+ this->SetWidgetsDisabledState(_game_mode == GM_NORMAL,
+ GDW_LVL_EASY,
+ GDW_LVL_MEDIUM,
+ GDW_LVL_HARD,
+ GDW_LVL_CUSTOM,
+ WIDGET_LIST_END);
+ this->SetWidgetDisabledState(GDW_HIGHSCORE, _game_mode == GM_EDITOR || _networking); // highscore chart in multiplayer
+ this->SetWidgetDisabledState(GDW_ACCEPT, _networking && !_network_server); // Save-button in multiplayer (and if client)
+ this->LowerWidget(GDW_LVL_EASY + this->opt_mod_temp.diff_level);
+ this->FindWindowPlacementAndResize(&_game_difficulty_desc);
+ }
+
+ virtual void OnPaint()
+ {
+ this->DrawWidgets();
+
+ /* XXX - Disabled buttons in normal gameplay or during muliplayer as non server.
+ * Bitshifted for each button to see if that bit is set. If it is set, the
+ * button is disabled */
+ uint32 disabled = 0;
+ if (_networking && !_network_server) {
+ disabled = MAX_UVALUE(uint32); // Disable all
+ } else if (_game_mode == GM_NORMAL) {
+ disabled = DIFF_INGAME_DISABLED_BUTTONS;
+ }
+
+ int value;
+ int y = GAMEDIFF_WND_TOP_OFFSET;
+ for (uint i = 0; i != GAME_DIFFICULTY_NUM; i++) {
+ const GameSettingData *gsd = &_game_setting_info[i];
+ value = ((GDType*)&this->opt_mod_temp.diff)[i];
+
+ DrawArrowButtons(5, y, 3,
+ (this->clicked_button == i) ? 1 + !!this->clicked_increase : 0,
+ !(HasBit(disabled, i) || gsd->min == value),
+ !(HasBit(disabled, i) || gsd->max == value));
+
+ value += _game_setting_info[i].str;
+ if (i == 4) value *= 1000; // XXX - handle currency option
+ SetDParam(0, value);
+ DrawString(30, y, STR_6805_MAXIMUM_NO_COMPETITORS + i, TC_FROMSTRING);
+
+ y += GAMEDIFF_WND_ROWSIZE + 2; // space items apart a bit
+ }
+ }
+
+ virtual void OnClick(Point pt, int widget)
+ {
+ switch (widget) {
+ case GDW_SETTING_BG: { /* Difficulty settings widget, decode click */
+ /* Don't allow clients to make any changes */
+ if (_networking && !_network_server) return;
+
+ const int x = pt.x - 5;
+ if (!IsInsideMM(x, 0, 21)) return; // Button area
+
+ const int y = pt.y - GAMEDIFF_WND_TOP_OFFSET;
+ if (y < 0) return;
+
+ /* Get button from Y coord. */
+ const uint8 btn = y / (GAMEDIFF_WND_ROWSIZE + 2);
+ if (btn >= GAME_DIFFICULTY_NUM || y % (GAMEDIFF_WND_ROWSIZE + 2) >= 9) return;
+
+ /* Clicked disabled button? */
+ if (_game_mode == GM_NORMAL && HasBit((int)DIFF_INGAME_DISABLED_BUTTONS, btn)) return;
+
+ this->timeout = 5;
+
+ int16 val = ((GDType*)&this->opt_mod_temp.diff)[btn];
+
+ const GameSettingData *info = &_game_setting_info[btn]; // get information about the difficulty setting
+ if (x >= 10) {
+ /* Increase button clicked */
+ val = min(val + info->step, info->max);
+ this->clicked_increase = true;
+ } else {
+ /* Decrease button clicked */
+ val -= info->step;
+ val = max(val, info->min);
+ this->clicked_increase = false;
+ }
+ this->clicked_button = btn;
+
+ /* save value in temporary variable */
+ ((GDType*)&this->opt_mod_temp.diff)[btn] = val;
+ this->RaiseWidget(GDW_LVL_EASY + this->opt_mod_temp.diff_level);
+ SetDifficultyLevel(3, &this->opt_mod_temp); // set difficulty level to custom
+ this->LowerWidget(GDW_LVL_CUSTOM);
+ this->SetDirty();
+ } break;
+
+ case GDW_LVL_EASY:
+ case GDW_LVL_MEDIUM:
+ case GDW_LVL_HARD:
+ case GDW_LVL_CUSTOM:
+ /* temporarily change difficulty level */
+ this->RaiseWidget(GDW_LVL_EASY + this->opt_mod_temp.diff_level);
+ SetDifficultyLevel(widget - GDW_LVL_EASY, &this->opt_mod_temp);
+ this->LowerWidget(GDW_LVL_EASY + this->opt_mod_temp.diff_level);
+ this->SetDirty();
+ break;
+
+ case GDW_HIGHSCORE: // Highscore Table
+ ShowHighscoreTable(this->opt_mod_temp.diff_level, -1);
+ break;
+
+ case GDW_ACCEPT: { // Save button - save changes
+ GDType btn, val;
+ for (btn = 0; btn != GAME_DIFFICULTY_NUM; btn++) {
+ val = ((GDType*)&this->opt_mod_temp.diff)[btn];
+ /* if setting has changed, change it */
+ if (val != ((GDType*)&_opt_ptr->diff)[btn])
+ DoCommandP(0, btn, val, NULL, CMD_CHANGE_DIFFICULTY_LEVEL);
+ }
+ DoCommandP(0, UINT_MAX, this->opt_mod_temp.diff_level, NULL, CMD_CHANGE_DIFFICULTY_LEVEL);
+ delete this;
+ /* If we are in the editor, we should reload the economy.
+ * This way when you load a game, the max loan and interest rate
+ * are loaded correctly. */
+ if (_game_mode == GM_EDITOR) StartupEconomy();
+ break;
+ }
+
+ case GDW_CANCEL: // Cancel button - close window, abandon changes
+ delete this;
+ break;
+ }
+ }
+
+ virtual void OnTick()
+ {
+ if (this->timeout != 0) {
+ this->timeout--;
+ if (this->timeout == 0) this->clicked_button = NO_SETTINGS_BUTTON;
+ this->SetDirty();
+ }
+ }
};
void ShowGameDifficulty()
{
DeleteWindowById(WC_GAME_OPTIONS, 0);
- /* Copy current settings (ingame or in intro) to temporary holding place
- * change that when setting stuff, copy back on clicking 'OK' */
- _opt_mod_temp = *_opt_ptr;
- new Window(&_game_difficulty_desc);
+ new GameDifficultyWindow();
}
static const char *_patches_ui[] = {
@@ -854,228 +814,232 @@
PATCHSEL_COMPETITORS
};
-/** The main patches window. Shows a number of categories on top and
- * a selection of patches in that category.
- * Uses WP(w, def_d) macro - data_1, data_2, data_3 */
-static void PatchesSelectionWndProc(Window *w, WindowEvent *e)
-{
+struct PatchesSelectionWindow : Window {
static Patches *patches_ptr;
- static int patches_max = 0;
-
- switch (e->event) {
- case WE_CREATE: {
- static bool first_time = true;
-
- patches_ptr = (_game_mode == GM_MENU) ? &_patches_newgame : &_patches;
-
- /* Build up the dynamic settings-array only once per OpenTTD session */
- if (first_time) {
- PatchPage *page;
- for (page = &_patches_page[0]; page != endof(_patches_page); page++) {
- uint i;
-
- if (patches_max < page->num) patches_max = page->num;
-
- page->entries = MallocT<PatchEntry>(page->num);
- for (i = 0; i != page->num; i++) {
- uint index;
- const SettingDesc *sd = GetPatchFromName(page->names[i], &index);
- assert(sd != NULL);
-
- page->entries[i].setting = sd;
- page->entries[i].index = index;
- }
- }
- first_time = false;
- }
-
- /* Resize the window to fit the largest patch tab */
- ResizeWindowForWidget(w, PATCHSEL_OPTIONSPANEL, 0, patches_max * 11);
-
- /* Recentre the window for the new size */
- w->top = w->top - (patches_max * 11) / 2;
-
- w->LowerWidget(4);
- } break;
+ static int patches_max;
- case WE_PAINT: {
- int x, y;
- const PatchPage *page = &_patches_page[WP(w, def_d).data_1];
- uint i;
-
- /* Set up selected category */
- DrawWindowWidgets(w);
-
- x = 5;
- y = 47;
- for (i = 0; i != page->num; i++) {
- const SettingDesc *sd = page->entries[i].setting;
- const SettingDescBase *sdb = &sd->desc;
- const void *var = GetVariableAddress(patches_ptr, &sd->save);
- bool editable = true;
- bool disabled = false;
-
- // We do not allow changes of some items when we are a client in a networkgame
- if (!(sd->save.conv & SLF_NETWORK_NO) && _networking && !_network_server) editable = false;
- if ((sdb->flags & SGF_NETWORK_ONLY) && !_networking) editable = false;
- if ((sdb->flags & SGF_NO_NETWORK) && _networking) editable = false;
+ int page;
+ int entry;
+ int click;
- if (sdb->cmd == SDT_BOOLX) {
- static const int _bool_ctabs[2][2] = {{9, 4}, {7, 6}};
- /* Draw checkbox for boolean-value either on/off */
- bool on = (*(bool*)var);
-
- DrawFrameRect(x, y, x + 19, y + 8, _bool_ctabs[!!on][!!editable], on ? FR_LOWERED : FR_NONE);
- SetDParam(0, on ? STR_CONFIG_PATCHES_ON : STR_CONFIG_PATCHES_OFF);
- } else {
- int32 value;
-
- value = (int32)ReadValue(var, sd->save.conv);
+ PatchesSelectionWindow(const WindowDesc *desc) : Window(desc)
+ {
+ static bool first_time = true;
- /* Draw [<][>] boxes for settings of an integer-type */
- DrawArrowButtons(x, y, 3, WP(w, def_d).data_2 - (i * 2), (editable && value != sdb->min), (editable && value != sdb->max));
+ patches_ptr = (_game_mode == GM_MENU) ? &_patches_newgame : &_patches;
- disabled = (value == 0) && (sdb->flags & SGF_0ISDISABLED);
- if (disabled) {
- SetDParam(0, STR_CONFIG_PATCHES_DISABLED);
+ /* Build up the dynamic settings-array only once per OpenTTD session */
+ if (first_time) {
+ PatchPage *page;
+ for (page = &_patches_page[0]; page != endof(_patches_page); page++) {
+ uint i;
+
+ if (patches_max < page->num) patches_max = page->num;
+
+ page->entries = MallocT<PatchEntry>(page->num);
+ for (i = 0; i != page->num; i++) {
+ uint index;
+ const SettingDesc *sd = GetPatchFromName(page->names[i], &index);
+ assert(sd != NULL);
+
+ page->entries[i].setting = sd;
+ page->entries[i].index = index;
+ }
+ }
+ first_time = false;
+ }
+
+ /* Resize the window to fit the largest patch tab */
+ ResizeWindowForWidget(this, PATCHSEL_OPTIONSPANEL, 0, patches_max * 11);
+
+ /* Recentre the window for the new size */
+ this->top = this->top - (patches_max * 11) / 2;
+
+ this->LowerWidget(4);
+
+ this->FindWindowPlacementAndResize(desc);
+ }
+
+ virtual void OnPaint()
+ {
+ int x, y;
+ const PatchPage *page = &_patches_page[this->page];
+ uint i;
+
+ /* Set up selected category */
+ this->DrawWidgets();
+
+ x = 5;
+ y = 47;
+ for (i = 0; i != page->num; i++) {
+ const SettingDesc *sd = page->entries[i].setting;
+ const SettingDescBase *sdb = &sd->desc;
+ const void *var = GetVariableAddress(patches_ptr, &sd->save);
+ bool editable = true;
+ bool disabled = false;
+
+ // We do not allow changes of some items when we are a client in a networkgame
+ if (!(sd->save.conv & SLF_NETWORK_NO) && _networking && !_network_server) editable = false;
+ if ((sdb->flags & SGF_NETWORK_ONLY) && !_networking) editable = false;
+ if ((sdb->flags & SGF_NO_NETWORK) && _networking) editable = false;
+
+ if (sdb->cmd == SDT_BOOLX) {
+ static const int _bool_ctabs[2][2] = {{9, 4}, {7, 6}};
+ /* Draw checkbox for boolean-value either on/off */
+ bool on = (*(bool*)var);
+
+ DrawFrameRect(x, y, x + 19, y + 8, _bool_ctabs[!!on][!!editable], on ? FR_LOWERED : FR_NONE);
+ SetDParam(0, on ? STR_CONFIG_PATCHES_ON : STR_CONFIG_PATCHES_OFF);
+ } else {
+ int32 value;
+
+ value = (int32)ReadValue(var, sd->save.conv);
+
+ /* Draw [<][>] boxes for settings of an integer-type */
+ DrawArrowButtons(x, y, 3, this->click - (i * 2), (editable && value != sdb->min), (editable && value != sdb->max));
+
+ disabled = (value == 0) && (sdb->flags & SGF_0ISDISABLED);
+ if (disabled) {
+ SetDParam(0, STR_CONFIG_PATCHES_DISABLED);
+ } else {
+ if (sdb->flags & SGF_CURRENCY) {
+ SetDParam(0, STR_CONFIG_PATCHES_CURRENCY);
+ } else if (sdb->flags & SGF_MULTISTRING) {
+ SetDParam(0, sdb->str + value + 1);
} else {
- if (sdb->flags & SGF_CURRENCY) {
- SetDParam(0, STR_CONFIG_PATCHES_CURRENCY);
- } else if (sdb->flags & SGF_MULTISTRING) {
- SetDParam(0, sdb->str + value + 1);
+ SetDParam(0, (sdb->flags & SGF_NOCOMMA) ? STR_CONFIG_PATCHES_INT32 : STR_7024);
+ }
+ SetDParam(1, value);
+ }
+ }
+ DrawString(30, y, (sdb->str) + disabled, TC_FROMSTRING);
+ y += 11;
+ }
+ }
+
+ virtual void OnClick(Point pt, int widget)
+ {
+ switch (widget) {
+ case PATCHSEL_OPTIONSPANEL: {
+ const PatchPage *page = &_patches_page[this->page];
+ const SettingDesc *sd;
+ void *var;
+ int32 value;
+ int x, y;
+ byte btn;
+
+ y = pt.y - 46 - 1;
+ if (y < 0) return;
+
+ x = pt.x - 5;
+ if (x < 0) return;
+
+ btn = y / 11;
+ if (y % 11 > 9) return;
+ if (btn >= page->num) return;
+
+ sd = page->entries[btn].setting;
+
+ /* return if action is only active in network, or only settable by server */
+ if (!(sd->save.conv & SLF_NETWORK_NO) && _networking && !_network_server) return;
+ if ((sd->desc.flags & SGF_NETWORK_ONLY) && !_networking) return;
+ if ((sd->desc.flags & SGF_NO_NETWORK) && _networking) return;
+
+ var = GetVariableAddress(patches_ptr, &sd->save);
+ value = (int32)ReadValue(var, sd->save.conv);
+
+ /* clicked on the icon on the left side. Either scroller or bool on/off */
+ if (x < 21) {
+ const SettingDescBase *sdb = &sd->desc;
+ int32 oldvalue = value;
+
+ switch (sdb->cmd) {
+ case SDT_BOOLX: value ^= 1; break;
+ case SDT_NUMX: {
+ /* Add a dynamic step-size to the scroller. In a maximum of
+ * 50-steps you should be able to get from min to max,
+ * unless specified otherwise in the 'interval' variable
+ * of the current patch. */
+ uint32 step = (sdb->interval == 0) ? ((sdb->max - sdb->min) / 50) : sdb->interval;
+ if (step == 0) step = 1;
+
+ // don't allow too fast scrolling
+ if ((this->flags4 & WF_TIMEOUT_MASK) > 2 << WF_TIMEOUT_SHL) {
+ _left_button_clicked = false;
+ return;
+ }
+
+ /* Increase or decrease the value and clamp it to extremes */
+ if (x >= 10) {
+ value += step;
+ if (value > sdb->max) value = sdb->max;
} else {
- SetDParam(0, (sdb->flags & SGF_NOCOMMA) ? STR_CONFIG_PATCHES_INT32 : STR_7024);
+ value -= step;
+ if (value < sdb->min) value = (sdb->flags & SGF_0ISDISABLED) ? 0 : sdb->min;
}
- SetDParam(1, value);
+
+ /* Set up scroller timeout for numeric values */
+ if (value != oldvalue && !(sd->desc.flags & SGF_MULTISTRING)) {
+ this->click = btn * 2 + 1 + ((x >= 10) ? 1 : 0);
+ this->flags4 |= 5 << WF_TIMEOUT_SHL;
+ _left_button_clicked = false;
+ }
+ } break;
+ default: NOT_REACHED();
+ }
+
+ if (value != oldvalue) {
+ SetPatchValue(page->entries[btn].index, patches_ptr, value);
+ this->SetDirty();
+ }
+ } else {
+ /* only open editbox for types that its sensible for */
+ if (sd->desc.cmd != SDT_BOOLX && !(sd->desc.flags & SGF_MULTISTRING)) {
+ /* Show the correct currency-translated value */
+ if (sd->desc.flags & SGF_CURRENCY) value *= _currency->rate;
+
+ this->entry = btn;
+ SetDParam(0, value);
+ ShowQueryString(STR_CONFIG_PATCHES_INT32, STR_CONFIG_PATCHES_QUERY_CAPT, 10, 100, this, CS_NUMERAL);
}
}
- DrawString(30, y, (sdb->str) + disabled, TC_FROMSTRING);
- y += 11;
- }
- } break;
-
- case WE_CLICK:
- switch (e->we.click.widget) {
- case PATCHSEL_OPTIONSPANEL: {
- const PatchPage *page = &_patches_page[WP(w, def_d).data_1];
- const SettingDesc *sd;
- void *var;
- int32 value;
- int x, y;
- byte btn;
-
- y = e->we.click.pt.y - 46 - 1;
- if (y < 0) return;
-
- x = e->we.click.pt.x - 5;
- if (x < 0) return;
-
- btn = y / 11;
- if (y % 11 > 9) return;
- if (btn >= page->num) return;
-
- sd = page->entries[btn].setting;
-
- /* return if action is only active in network, or only settable by server */
- if (!(sd->save.conv & SLF_NETWORK_NO) && _networking && !_network_server) return;
- if ((sd->desc.flags & SGF_NETWORK_ONLY) && !_networking) return;
- if ((sd->desc.flags & SGF_NO_NETWORK) && _networking) return;
-
- var = GetVariableAddress(patches_ptr, &sd->save);
- value = (int32)ReadValue(var, sd->save.conv);
-
- /* clicked on the icon on the left side. Either scroller or bool on/off */
- if (x < 21) {
- const SettingDescBase *sdb = &sd->desc;
- int32 oldvalue = value;
-
- switch (sdb->cmd) {
- case SDT_BOOLX: value ^= 1; break;
- case SDT_NUMX: {
- /* Add a dynamic step-size to the scroller. In a maximum of
- * 50-steps you should be able to get from min to max,
- * unless specified otherwise in the 'interval' variable
- * of the current patch. */
- uint32 step = (sdb->interval == 0) ? ((sdb->max - sdb->min) / 50) : sdb->interval;
- if (step == 0) step = 1;
-
- // don't allow too fast scrolling
- if ((w->flags4 & WF_TIMEOUT_MASK) > 2 << WF_TIMEOUT_SHL) {
- _left_button_clicked = false;
- return;
- }
+ } break;
- /* Increase or decrease the value and clamp it to extremes */
- if (x >= 10) {
- value += step;
- if (value > sdb->max) value = sdb->max;
- } else {
- value -= step;
- if (value < sdb->min) value = (sdb->flags & SGF_0ISDISABLED) ? 0 : sdb->min;
- }
-
- /* Set up scroller timeout for numeric values */
- if (value != oldvalue && !(sd->desc.flags & SGF_MULTISTRING)) {
- WP(w, def_d).data_2 = btn * 2 + 1 + ((x >= 10) ? 1 : 0);
- w->flags4 |= 5 << WF_TIMEOUT_SHL;
- _left_button_clicked = false;
- }
- } break;
- default: NOT_REACHED();
- }
-
- if (value != oldvalue) {
- SetPatchValue(page->entries[btn].index, patches_ptr, value);
- w->SetDirty();
- }
- } else {
- /* only open editbox for types that its sensible for */
- if (sd->desc.cmd != SDT_BOOLX && !(sd->desc.flags & SGF_MULTISTRING)) {
- /* Show the correct currency-translated value */
- if (sd->desc.flags & SGF_CURRENCY) value *= _currency->rate;
+ case PATCHSEL_INTERFACE: case PATCHSEL_CONSTRUCTION: case PATCHSEL_VEHICLES:
+ case PATCHSEL_STATIONS: case PATCHSEL_ECONOMY: case PATCHSEL_COMPETITORS:
+ this->RaiseWidget(this->page + PATCHSEL_INTERFACE);
+ this->page = widget - PATCHSEL_INTERFACE;
+ this->LowerWidget(this->page + PATCHSEL_INTERFACE);
+ DeleteWindowById(WC_QUERY_STRING, 0);
+ this->SetDirty();
+ break;
+ }
+ }
- WP(w, def_d).data_3 = btn;
- SetDParam(0, value);
- ShowQueryString(STR_CONFIG_PATCHES_INT32, STR_CONFIG_PATCHES_QUERY_CAPT, 10, 100, w, CS_NUMERAL);
- }
- }
- } break;
-
- case PATCHSEL_INTERFACE: case PATCHSEL_CONSTRUCTION: case PATCHSEL_VEHICLES:
- case PATCHSEL_STATIONS: case PATCHSEL_ECONOMY: case PATCHSEL_COMPETITORS:
- w->RaiseWidget(WP(w, def_d).data_1 + PATCHSEL_INTERFACE);
- WP(w, def_d).data_1 = e->we.click.widget - PATCHSEL_INTERFACE;
- w->LowerWidget(WP(w, def_d).data_1 + PATCHSEL_INTERFACE);
- DeleteWindowById(WC_QUERY_STRING, 0);
- w->SetDirty();
- break;
- }
- break;
+ virtual void OnTimeout()
+ {
+ this->click = 0;
+ this->SetDirty();
+ }
- case WE_TIMEOUT:
- WP(w, def_d).data_2 = 0;
- w->SetDirty();
- break;
-
- case WE_ON_EDIT_TEXT:
- if (!StrEmpty(e->we.edittext.str)) {
- const PatchEntry *pe = &_patches_page[WP(w, def_d).data_1].entries[WP(w, def_d).data_3];
- const SettingDesc *sd = pe->setting;
- int32 value = atoi(e->we.edittext.str);
+ virtual void OnQueryTextFinished(char *str)
+ {
+ if (!StrEmpty(str)) {
+ const PatchEntry *pe = &_patches_page[this->page].entries[this->entry];
+ const SettingDesc *sd = pe->setting;
+ int32 value = atoi(str);
- /* Save the correct currency-translated value */
- if (sd->desc.flags & SGF_CURRENCY) value /= _currency->rate;
+ /* Save the correct currency-translated value */
+ if (sd->desc.flags & SGF_CURRENCY) value /= _currency->rate;
- SetPatchValue(pe->index, patches_ptr, value);
- w->SetDirty();
- }
- break;
+ SetPatchValue(pe->index, patches_ptr, value);
+ this->SetDirty();
+ }
+ }
+};
- case WE_DESTROY:
- DeleteWindowById(WC_QUERY_STRING, 0);
- break;
- }
-}
+Patches *PatchesSelectionWindow::patches_ptr = NULL;
+int PatchesSelectionWindow::patches_max = 0;
static const Widget _patches_selection_widgets[] = {
{ WWT_CLOSEBOX, RESIZE_NONE, 10, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW},
@@ -1097,13 +1061,12 @@
WC_GAME_OPTIONS, WC_NONE,
WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET,
_patches_selection_widgets,
- PatchesSelectionWndProc,
};
void ShowPatchesSelection()
{
DeleteWindowById(WC_GAME_OPTIONS, 0);
- new Window(&_patches_selection_desc);
+ new PatchesSelectionWindow(&_patches_selection_desc);
}
@@ -1143,176 +1106,178 @@
CUSTCURR_TO_EURO,
};
-static char _str_separator[2];
-
-static void CustCurrencyWndProc(Window *w, WindowEvent *e)
-{
- switch (e->event) {
- case WE_PAINT: {
- int x;
- int y = 20;
- int clk = WP(w, def_d).data_1;
- DrawWindowWidgets(w);
-
- /* exchange rate */
- DrawArrowButtons(10, y, 3, GB(clk, 0, 2), true, true);
- SetDParam(0, 1);
- SetDParam(1, 1);
- DrawString(35, y + 1, STR_CURRENCY_EXCHANGE_RATE, TC_FROMSTRING);
- y += 12;
-
- /* separator */
- DrawFrameRect(10, y + 1, 29, y + 9, 0, GB(clk, 2, 2) ? FR_LOWERED : FR_NONE);
- x = DrawString(35, y + 1, STR_CURRENCY_SEPARATOR, TC_FROMSTRING);
- DoDrawString(_str_separator, x + 4, y + 1, TC_ORANGE);
- y += 12;
-
- /* prefix */
- DrawFrameRect(10, y + 1, 29, y + 9, 0, GB(clk, 4, 2) ? FR_LOWERED : FR_NONE);
- x = DrawString(35, y + 1, STR_CURRENCY_PREFIX, TC_FROMSTRING);
- DoDrawString(_custom_currency.prefix, x + 4, y + 1, TC_ORANGE);
- y += 12;
-
- /* suffix */
- DrawFrameRect(10, y + 1, 29, y + 9, 0, GB(clk, 6, 2) ? FR_LOWERED : FR_NONE);
- x = DrawString(35, y + 1, STR_CURRENCY_SUFFIX, TC_FROMSTRING);
- DoDrawString(_custom_currency.suffix, x + 4, y + 1, TC_ORANGE);
- y += 12;
-
- /* switch to euro */
- DrawArrowButtons(10, y, 3, GB(clk, 8, 2), true, true);
- SetDParam(0, _custom_currency.to_euro);
- DrawString(35, y + 1, (_custom_currency.to_euro != CF_NOEURO) ? STR_CURRENCY_SWITCH_TO_EURO : STR_CURRENCY_SWITCH_TO_EURO_NEVER, TC_FROMSTRING);
- y += 12;
+struct CustomCurrencyWindow : Window {
+ char separator[2];
+ int click;
+ int query_widget;
- /* Preview */
- y += 12;
- SetDParam(0, 10000);
- DrawString(35, y + 1, STR_CURRENCY_PREVIEW, TC_FROMSTRING);
- } break;
-
- case WE_CLICK: {
- int line = (e->we.click.pt.y - 20) / 12;
- int len = 0;
- int x = e->we.click.pt.x;
- StringID str = 0;
- CharSetFilter afilter = CS_ALPHANUMERAL;
+ CustomCurrencyWindow(const WindowDesc *desc) : Window(desc)
+ {
+ this->separator[0] = _custom_currency.separator;
+ this->separator[1] = '\0';
+ this->FindWindowPlacementAndResize(desc);
+ }
- switch (line) {
- case CUSTCURR_EXCHANGERATE:
- if (IsInsideMM(x, 10, 30)) { // clicked buttons
- if (x < 20) {
- if (_custom_currency.rate > 1) _custom_currency.rate--;
- WP(w, def_d).data_1 = 1 << (line * 2 + 0);
- } else {
- if (_custom_currency.rate < 5000) _custom_currency.rate++;
- WP(w, def_d).data_1 = 1 << (line * 2 + 1);
- }
- } else { // enter text
- SetDParam(0, _custom_currency.rate);
- str = STR_CONFIG_PATCHES_INT32;
- len = 4;
- afilter = CS_NUMERAL;
- }
- break;
+ virtual void OnPaint()
+ {
+ int x;
+ int y = 20;
+ this->DrawWidgets();
- case CUSTCURR_SEPARATOR:
- if (IsInsideMM(x, 10, 30)) { // clicked button
- WP(w, def_d).data_1 = 1 << (line * 2 + 1);
- }
- str = BindCString(_str_separator);
- len = 1;
- break;
+ /* exchange rate */
+ DrawArrowButtons(10, y, 3, GB(this->click, 0, 2), true, true);
+ SetDParam(0, 1);
+ SetDParam(1, 1);
+ DrawString(35, y + 1, STR_CURRENCY_EXCHANGE_RATE, TC_FROMSTRING);
+ y += 12;
- case CUSTCURR_PREFIX:
- if (IsInsideMM(x, 10, 30)) { // clicked button
- WP(w, def_d).data_1 = 1 << (line * 2 + 1);
+ /* separator */
+ DrawFrameRect(10, y + 1, 29, y + 9, 0, GB(this->click, 2, 2) ? FR_LOWERED : FR_NONE);
+ x = DrawString(35, y + 1, STR_CURRENCY_SEPARATOR, TC_FROMSTRING);
+ DoDrawString(this->separator, x + 4, y + 1, TC_ORANGE);
+ y += 12;
+
+ /* prefix */
+ DrawFrameRect(10, y + 1, 29, y + 9, 0, GB(this->click, 4, 2) ? FR_LOWERED : FR_NONE);
+ x = DrawString(35, y + 1, STR_CURRENCY_PREFIX, TC_FROMSTRING);
+ DoDrawString(_custom_currency.prefix, x + 4, y + 1, TC_ORANGE);
+ y += 12;
+
+ /* suffix */
+ DrawFrameRect(10, y + 1, 29, y + 9, 0, GB(this->click, 6, 2) ? FR_LOWERED : FR_NONE);
+ x = DrawString(35, y + 1, STR_CURRENCY_SUFFIX, TC_FROMSTRING);
+ DoDrawString(_custom_currency.suffix, x + 4, y + 1, TC_ORANGE);
+ y += 12;
+
+ /* switch to euro */
+ DrawArrowButtons(10, y, 3, GB(this->click, 8, 2), true, true);
+ SetDParam(0, _custom_currency.to_euro);
+ DrawString(35, y + 1, (_custom_currency.to_euro != CF_NOEURO) ? STR_CURRENCY_SWITCH_TO_EURO : STR_CURRENCY_SWITCH_TO_EURO_NEVER, TC_FROMSTRING);
+ y += 12;
+
+ /* Preview */
+ y += 12;
+ SetDParam(0, 10000);
+ DrawString(35, y + 1, STR_CURRENCY_PREVIEW, TC_FROMSTRING);
+ }
+
+ virtual void OnClick(Point pt, int widget)
+ {
+ int line = (pt.y - 20) / 12;
+ int len = 0;
+ int x = pt.x;
+ StringID str = 0;
+ CharSetFilter afilter = CS_ALPHANUMERAL;
+
+ switch (line) {
+ case CUSTCURR_EXCHANGERATE:
+ if (IsInsideMM(x, 10, 30)) { // clicked buttons
+ if (x < 20) {
+ if (_custom_currency.rate > 1) _custom_currency.rate--;
+ this->click = 1 << (line * 2 + 0);
+ } else {
+ if (_custom_currency.rate < 5000) _custom_currency.rate++;
+ this->click = 1 << (line * 2 + 1);
}
- str = BindCString(_custom_currency.prefix);
- len = 12;
- break;
-
- case CUSTCURR_SUFFIX:
- if (IsInsideMM(x, 10, 30)) { // clicked button
- WP(w, def_d).data_1 = 1 << (line * 2 + 1);
- }
- str = BindCString(_custom_currency.suffix);
- len = 12;
- break;
-
- case CUSTCURR_TO_EURO:
- if (IsInsideMM(x, 10, 30)) { // clicked buttons
- if (x < 20) {
- _custom_currency.to_euro = (_custom_currency.to_euro <= 2000) ?
- CF_NOEURO : _custom_currency.to_euro - 1;
- WP(w, def_d).data_1 = 1 << (line * 2 + 0);
- } else {
- _custom_currency.to_euro =
- Clamp(_custom_currency.to_euro + 1, 2000, MAX_YEAR);
- WP(w, def_d).data_1 = 1 << (line * 2 + 1);
- }
- } else { // enter text
- SetDParam(0, _custom_currency.to_euro);
- str = STR_CONFIG_PATCHES_INT32;
- len = 4;
- afilter = CS_NUMERAL;
- }
- break;
- }
-
- if (len != 0) {
- WP(w, def_d).data_2 = line;
- ShowQueryString(str, STR_CURRENCY_CHANGE_PARAMETER, len + 1, 250, w, afilter);
- }
-
- w->flags4 |= 5 << WF_TIMEOUT_SHL;
- w->SetDirty();
- } break;
+ } else { // enter text
+ SetDParam(0, _custom_currency.rate);
+ str = STR_CONFIG_PATCHES_INT32;
+ len = 4;
+ afilter = CS_NUMERAL;
+ }
+ break;
- case WE_ON_EDIT_TEXT: {
- if (e->we.edittext.str == NULL) break;
-
- const char *b = e->we.edittext.str;
-
- switch (WP(w, def_d).data_2) {
- case CUSTCURR_EXCHANGERATE:
- _custom_currency.rate = Clamp(atoi(b), 1, 5000);
- break;
-
- case CUSTCURR_SEPARATOR: /* Thousands seperator */
- _custom_currency.separator = StrEmpty(b) ? ' ' : b[0];
- ttd_strlcpy(_str_separator, b, lengthof(_str_separator));
- break;
-
- case CUSTCURR_PREFIX:
- ttd_strlcpy(_custom_currency.prefix, b, lengthof(_custom_currency.prefix));
- break;
+ case CUSTCURR_SEPARATOR:
+ if (IsInsideMM(x, 10, 30)) { // clicked button
+ this->click = 1 << (line * 2 + 1);
+ }
+ str = BindCString(this->separator);
+ len = 1;
+ break;
- case CUSTCURR_SUFFIX:
- ttd_strlcpy(_custom_currency.suffix, b, lengthof(_custom_currency.suffix));
- break;
+ case CUSTCURR_PREFIX:
+ if (IsInsideMM(x, 10, 30)) { // clicked button
+ this->click = 1 << (line * 2 + 1);
+ }
+ str = BindCString(_custom_currency.prefix);
+ len = 12;
+ break;
- case CUSTCURR_TO_EURO: { /* Year to switch to euro */
- int val = atoi(b);
+ case CUSTCURR_SUFFIX:
+ if (IsInsideMM(x, 10, 30)) { // clicked button
+ this->click = 1 << (line * 2 + 1);
+ }
+ str = BindCString(_custom_currency.suffix);
+ len = 12;
+ break;
- _custom_currency.to_euro = (val < 2000 ? CF_NOEURO : min(val, MAX_YEAR));
- break;
+ case CUSTCURR_TO_EURO:
+ if (IsInsideMM(x, 10, 30)) { // clicked buttons
+ if (x < 20) {
+ _custom_currency.to_euro = (_custom_currency.to_euro <= 2000) ?
+ CF_NOEURO : _custom_currency.to_euro - 1;
+ this->click = 1 << (line * 2 + 0);
+ } else {
+ _custom_currency.to_euro =
+ Clamp(_custom_currency.to_euro + 1, 2000, MAX_YEAR);
+ this->click = 1 << (line * 2 + 1);
+ }
+ } else { // enter text
+ SetDParam(0, _custom_currency.to_euro);
+ str = STR_CONFIG_PATCHES_INT32;
+ len = 4;
+ afilter = CS_NUMERAL;
}
+ break;
+ }
+
+ if (len != 0) {
+ this->query_widget = line;
+ ShowQueryString(str, STR_CURRENCY_CHANGE_PARAMETER, len + 1, 250, this, afilter);
+ }
+
+ this->flags4 |= 5 << WF_TIMEOUT_SHL;
+ this->SetDirty();
+ }
+
+ virtual void OnQueryTextFinished(char *str)
+ {
+ if (str == NULL) return;
+
+ switch (this->query_widget) {
+ case CUSTCURR_EXCHANGERATE:
+ _custom_currency.rate = Clamp(atoi(str), 1, 5000);
+ break;
+
+ case CUSTCURR_SEPARATOR: /* Thousands seperator */
+ _custom_currency.separator = StrEmpty(str) ? ' ' : str[0];
+ ttd_strlcpy(this->separator, str, lengthof(this->separator));
+ break;
+
+ case CUSTCURR_PREFIX:
+ ttd_strlcpy(_custom_currency.prefix, str, lengthof(_custom_currency.prefix));
+ break;
+
+ case CUSTCURR_SUFFIX:
+ ttd_strlcpy(_custom_currency.suffix, str, lengthof(_custom_currency.suffix));
+ break;
+
+ case CUSTCURR_TO_EURO: { /* Year to switch to euro */
+ int val = atoi(str);
+
+ _custom_currency.to_euro = (val < 2000 ? CF_NOEURO : min(val, MAX_YEAR));
+ break;
}
- MarkWholeScreenDirty();
- } break;
+ }
+ MarkWholeScreenDirty();
+ }
- case WE_TIMEOUT:
- WP(w, def_d).data_1 = 0;
- w->SetDirty();
- break;
-
- case WE_DESTROY:
- DeleteWindowById(WC_QUERY_STRING, 0);
- MarkWholeScreenDirty();
- break;
+ virtual void OnTimeout()
+ {
+ this->click = 0;
+ this->SetDirty();
}
-}
+};
static const Widget _cust_currency_widgets[] = {
{ WWT_CLOSEBOX, RESIZE_NONE, 14, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW},
@@ -1326,14 +1291,10 @@
WC_CUSTOM_CURRENCY, WC_NONE,
WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS,
_cust_currency_widgets,
- CustCurrencyWndProc,
};
static void ShowCustCurrency()
{
- _str_separator[0] = _custom_currency.separator;
- _str_separator[1] = '\0';
-
DeleteWindowById(WC_CUSTOM_CURRENCY, 0);
- new Window(&_cust_currency_desc);
+ new CustomCurrencyWindow(&_cust_currency_desc);
}
--- a/src/ship_cmd.cpp Mon May 19 14:14:33 2008 +0000
+++ b/src/ship_cmd.cpp Mon May 19 15:13:58 2008 +0000
@@ -350,7 +350,7 @@
SetDParam(0, st->index);
AddNewsItem(
STR_9833_CITIZENS_CELEBRATE_FIRST,
- NM_THIN, NF_VIEWPORT | NF_VEHICLE, (v->owner == _local_player) ? NT_ARRIVAL_PLAYER : NT_ARRIVAL_OTHER, DNC_NONE,
+ (v->owner == _local_player) ? NS_ARRIVAL_PLAYER : NS_ARRIVAL_OTHER,
v->index,
0);
}
@@ -818,7 +818,7 @@
VehiclePositionChanged(v);
InvalidateWindowData(WC_VEHICLE_DEPOT, v->tile);
- RebuildVehicleLists();
+ InvalidateWindowClassesData(WC_SHIPS_LIST, 0);
InvalidateWindow(WC_COMPANY, v->owner);
if (IsLocalPlayer())
InvalidateAutoreplaceWindow(v->engine_type, v->group_id); // updates the replace Ship window
@@ -855,7 +855,7 @@
if (flags & DC_EXEC) {
InvalidateWindow(WC_VEHICLE_DEPOT, v->tile);
- RebuildVehicleLists();
+ InvalidateWindowClassesData(WC_SHIPS_LIST, 0);
InvalidateWindow(WC_COMPANY, v->owner);
DeleteWindowById(WC_VEHICLE_VIEW, v->index);
DeleteDepotHighlightOfVehicle(v);
@@ -1001,7 +1001,7 @@
v->cargo_subtype = new_subtype;
InvalidateWindow(WC_VEHICLE_DETAILS, v->index);
InvalidateWindow(WC_VEHICLE_DEPOT, v->tile);
- RebuildVehicleLists();
+ InvalidateWindowClassesData(WC_SHIPS_LIST, 0);
}
return cost;
--- a/src/signal.cpp Mon May 19 14:14:33 2008 +0000
+++ b/src/signal.cpp Mon May 19 15:13:58 2008 +0000
@@ -468,12 +468,12 @@
* @return false iff presignal entry would be green (needed for trains leaving depot)
* @pre IsValidPlayer(owner)
*/
-static bool UpdateSignalsInBuffer(Owner owner)
+static SigSegState UpdateSignalsInBuffer(Owner owner)
{
assert(IsValidPlayer(owner));
bool first = true; // first block?
- bool state = false; // value to return
+ SigSegState state = SIGSEG_FREE; // value to return
TileIndex tile;
DiagDirection dir;
@@ -532,7 +532,10 @@
if (first) {
first = false;
- state = (flags & SF_TRAIN) || (flags & SF_EXIT && !(flags & SF_GREEN)) || (flags & SF_FULL); // true iff train CAN'T leave the depot
+ if ((flags & SF_TRAIN) || (flags & SF_EXIT && !(flags & SF_GREEN)) || (flags & SF_FULL)) {
+ /* SIGSEG_FREE is set by default */
+ state = SIGSEG_FULL;
+ }
}
/* do not do anything when some buffer was full */
@@ -629,7 +632,7 @@
* @param owner owner whose signals we will update
* @return false iff train can leave depot
*/
-bool UpdateSignalsOnSegment(TileIndex tile, DiagDirection side, Owner owner)
+SigSegState UpdateSignalsOnSegment(TileIndex tile, DiagDirection side, Owner owner)
{
assert(_globset.IsEmpty());
_globset.Add(tile, side);
--- a/src/signal_func.h Mon May 19 14:14:33 2008 +0000
+++ b/src/signal_func.h Mon May 19 15:13:58 2008 +0000
@@ -41,7 +41,13 @@
return _signal_on_track[track];
}
-bool UpdateSignalsOnSegment(TileIndex tile, DiagDirection side, Owner owner);
+/** State of the signal segment */
+enum SigSegState {
+ SIGSEG_FREE, ///< Free and has no pre-signal exits or at least one green exit
+ SIGSEG_FULL, ///< Occupied by a train
+};
+
+SigSegState UpdateSignalsOnSegment(TileIndex tile, DiagDirection side, Owner owner);
void SetSignalsOnBothDir(TileIndex tile, Track track, Owner owner);
void AddTrackToSignalBuffer(TileIndex tile, Track track, Owner owner);
void AddSideToSignalBuffer(TileIndex tile, DiagDirection side, Owner owner);
--- a/src/signs_gui.cpp Mon May 19 14:14:33 2008 +0000
+++ b/src/signs_gui.cpp Mon May 19 15:13:58 2008 +0000
@@ -66,54 +66,63 @@
DEBUG(misc, 3, "Resorting global signs list");
}
-static void SignListWndProc(Window *w, WindowEvent *e)
-{
- switch (e->event) {
- case WE_PAINT: {
- if (_sign_sort_dirty) GlobalSortSignList();
-
- SetVScrollCount(w, _num_sign_sort);
-
- SetDParam(0, w->vscroll.count);
- DrawWindowWidgets(w);
-
- /* No signs? */
- int y = 16; // offset from top of widget
- if (w->vscroll.count == 0) {
- DrawString(2, y, STR_304A_NONE, TC_FROMSTRING);
- return;
- }
-
- /* Start drawing the signs */
- for (uint16 i = w->vscroll.pos; i < w->vscroll.cap + w->vscroll.pos && i < w->vscroll.count; i++) {
- const Sign *si = _sign_sort[i];
-
- if (si->owner != OWNER_NONE) DrawPlayerIcon(si->owner, 4, y + 1);
+struct SignListWindow : Window {
+ SignListWindow(const WindowDesc *desc, WindowNumber window_number) : Window(desc, window_number)
+ {
+ this->vscroll.cap = 12;
+ this->resize.step_height = 10;
+ this->resize.height = this->height - 10 * 7; // minimum if 5 in the list
- SetDParam(0, si->index);
- DrawString(22, y, STR_SIGN_NAME, TC_YELLOW);
- y += 10;
- }
- } break;
-
- case WE_CLICK:
- if (e->we.click.widget == 3) {
- uint32 id_v = (e->we.click.pt.y - 15) / 10;
+ this->FindWindowPlacementAndResize(desc);
+ }
- if (id_v >= w->vscroll.cap) return;
- id_v += w->vscroll.pos;
- if (id_v >= w->vscroll.count) return;
+ virtual void OnPaint()
+ {
+ if (_sign_sort_dirty) GlobalSortSignList();
- const Sign *si = _sign_sort[id_v];
- ScrollMainWindowToTile(TileVirtXY(si->x, si->y));
- }
- break;
+ SetVScrollCount(this, _num_sign_sort);
- case WE_RESIZE:
- w->vscroll.cap += e->we.sizing.diff.y / 10;
- break;
+ SetDParam(0, this->vscroll.count);
+ this->DrawWidgets();
+
+ /* No signs? */
+ int y = 16; // offset from top of widget
+ if (this->vscroll.count == 0) {
+ DrawString(2, y, STR_304A_NONE, TC_FROMSTRING);
+ return;
+ }
+
+ /* Start drawing the signs */
+ for (uint16 i = this->vscroll.pos; i < this->vscroll.cap + this->vscroll.pos && i < this->vscroll.count; i++) {
+ const Sign *si = _sign_sort[i];
+
+ if (si->owner != OWNER_NONE) DrawPlayerIcon(si->owner, 4, y + 1);
+
+ SetDParam(0, si->index);
+ DrawString(22, y, STR_SIGN_NAME, TC_YELLOW);
+ y += 10;
+ }
}
-}
+
+ virtual void OnClick(Point pt, int widget)
+ {
+ if (widget == 3) {
+ uint32 id_v = (pt.y - 15) / 10;
+
+ if (id_v >= this->vscroll.cap) return;
+ id_v += this->vscroll.pos;
+ if (id_v >= this->vscroll.count) return;
+
+ const Sign *si = _sign_sort[id_v];
+ ScrollMainWindowToTile(TileVirtXY(si->x, si->y));
+ }
+ }
+
+ virtual void OnResize(Point new_size, Point delta)
+ {
+ this->vscroll.cap += delta.y / 10;
+ }
+};
static const Widget _sign_list_widget[] = {
{ WWT_CLOSEBOX, RESIZE_NONE, 14, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW},
@@ -130,18 +139,12 @@
WC_SIGN_LIST, WC_NONE,
WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_STICKY_BUTTON | WDF_RESIZABLE,
_sign_list_widget,
- SignListWndProc
};
void ShowSignList()
{
- Window *w = AllocateWindowDescFront<Window>(&_sign_list_desc, 0);
- if (w != NULL) {
- w->vscroll.cap = 12;
- w->resize.step_height = 10;
- w->resize.height = w->height - 10 * 7; // minimum if 5 in the list
- }
+ AllocateWindowDescFront<SignListWindow>(&_sign_list_desc, 0);
}
static void RenameSign(SignID index, const char *text)
@@ -170,6 +173,7 @@
this->LowerWidget(QUERY_EDIT_SIGN_WIDGET_TEXT);
UpdateSignEditWindow(si);
+ this->FindWindowPlacementAndResize(desc);
}
~SignWindow()
@@ -197,7 +201,7 @@
virtual void OnPaint()
{
SetDParam(0, this->caption);
- DrawWindowWidgets(this);
+ this->DrawWidgets();
this->DrawEditBox(QUERY_EDIT_SIGN_WIDGET_TEXT);
}
@@ -255,10 +259,10 @@
}
}
- virtual bool OnKeyPress(uint16 key, uint16 keycode)
+ virtual EventState OnKeyPress(uint16 key, uint16 keycode)
{
- bool cont = true;
- switch (this->HandleEditBoxKey(QUERY_EDIT_SIGN_WIDGET_TEXT, key, keycode, cont)) {
+ EventState state = ES_NOT_HANDLED;
+ switch (this->HandleEditBoxKey(QUERY_EDIT_SIGN_WIDGET_TEXT, key, keycode, state)) {
case 1: // Enter pressed, confirms change
RenameSign(this->cur_sign, this->text.buf);
/* FALL THROUGH */
@@ -267,7 +271,7 @@
delete this;
break;
}
- return cont;
+ return state;
}
virtual void OnMouseLoop()
@@ -295,7 +299,6 @@
WC_QUERY_STRING, WC_NONE,
WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET,
_query_sign_edit_widgets,
- NULL
};
void ShowRenameSignWindow(const Sign *si)
--- a/src/smallmap_gui.cpp Mon May 19 14:14:33 2008 +0000
+++ b/src/smallmap_gui.cpp Mon May 19 15:13:58 2008 +0000
@@ -800,7 +800,7 @@
this->SetDirty();
}
- SmallMapWindow(const WindowDesc *desc, void *data, int window_number) : Window(desc, data, window_number)
+ SmallMapWindow(const WindowDesc *desc, int window_number) : Window(desc, window_number)
{
/* Resize the window to fit industries list */
if (_industries_per_column > BASE_NB_PER_COLUMN) {
@@ -847,7 +847,7 @@
/* draw the window */
SetDParam(0, STR_00E5_CONTOURS + _smallmap_type);
- DrawWindowWidgets(this);
+ this->DrawWidgets();
tbl = _legend_table[_smallmap_type];
@@ -1078,7 +1078,6 @@
WC_SMALLMAP, WC_NONE,
WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_STICKY_BUTTON | WDF_RESIZABLE,
_smallmap_widgets,
- NULL
};
void ShowSmallMap()
@@ -1103,88 +1102,127 @@
{ WIDGETS_END},
};
-static void ExtraViewPortWndProc(Window *w, WindowEvent *e)
+class ExtraViewportWindow : public Window
{
- switch (e->event) {
- case WE_CREATE: // Disable zoom in button
- /* New viewport start at (zero,zero) */
- InitializeWindowViewport(w, 3, 17, w->widget[4].right - w->widget[4].left - 1, w->widget[4].bottom - w->widget[4].top - 1, 0, ZOOM_LVL_VIEWPORT);
-
- w->DisableWidget(5);
- break;
-
- case WE_PAINT:
- /* set the number in the title bar */
- SetDParam(0, w->window_number + 1);
-
- DrawWindowWidgets(w);
- DrawWindowViewport(w);
- break;
-
- case WE_CLICK:
- switch (e->we.click.widget) {
- case 5: DoZoomInOutWindow(ZOOM_IN, w); break;
- case 6: DoZoomInOutWindow(ZOOM_OUT, w); break;
-
- case 7: { // location button (move main view to same spot as this view) 'Paste Location'
- Window *w2 = FindWindowById(WC_MAIN_WINDOW, 0);
- int x = w->viewport->scrollpos_x; // Where is the main looking at
- int y = w->viewport->scrollpos_y;
-
- /* set this view to same location. Based on the center, adjusting for zoom */
- w2->viewport->dest_scrollpos_x = x - (w2->viewport->virtual_width - w->viewport->virtual_width) / 2;
- w2->viewport->dest_scrollpos_y = y - (w2->viewport->virtual_height - w->viewport->virtual_height) / 2;
- } break;
+ enum ExtraViewportWindowWidgets {
+ EVW_CLOSE,
+ EVW_CAPTION,
+ EVW_STICKY,
+ EVW_BACKGROUND,
+ EVW_VIEWPORT,
+ EVW_ZOOMIN,
+ EVW_ZOOMOUT,
+ EVW_MAIN_TO_VIEW,
+ EVW_VIEW_TO_MAIN,
+ EVW_SPACER1,
+ EVW_SPACER2,
+ EVW_RESIZE,
+ };
- case 8: { // inverse location button (move this view to same spot as main view) 'Copy Location'
- const Window *w2 = FindWindowById(WC_MAIN_WINDOW, 0);
- int x = w2->viewport->scrollpos_x;
- int y = w2->viewport->scrollpos_y;
-
- w->viewport->dest_scrollpos_x = x + (w2->viewport->virtual_width - w->viewport->virtual_width) / 2;
- w->viewport->dest_scrollpos_y = y + (w2->viewport->virtual_height - w->viewport->virtual_height) / 2;
- } break;
- }
- break;
-
- case WE_RESIZE:
- w->viewport->width += e->we.sizing.diff.x;
- w->viewport->height += e->we.sizing.diff.y;
- w->viewport->virtual_width += e->we.sizing.diff.x;
- w->viewport->virtual_height += e->we.sizing.diff.y;
- break;
-
- case WE_SCROLL: {
- ViewPort *vp = IsPtInWindowViewport(w, _cursor.pos.x, _cursor.pos.y);
+public:
+ ExtraViewportWindow(const WindowDesc *desc, int window_number, TileIndex tile) : Window(desc, window_number)
+ {
+ /* New viewport start at (zero,zero) */
+ InitializeWindowViewport(this, 3, 17, this->widget[EVW_VIEWPORT].right - this->widget[EVW_VIEWPORT].left - 1, this->widget[EVW_VIEWPORT].bottom - this->widget[EVW_VIEWPORT].top - 1, 0, ZOOM_LVL_VIEWPORT);
- if (vp == NULL) {
- _cursor.fix_at = false;
- _scrolling_viewport = false;
- }
+ this->DisableWidget(EVW_ZOOMIN);
+ this->FindWindowPlacementAndResize(desc);
- w->viewport->scrollpos_x += ScaleByZoom(e->we.scroll.delta.x, vp->zoom);
- w->viewport->scrollpos_y += ScaleByZoom(e->we.scroll.delta.y, vp->zoom);
- w->viewport->dest_scrollpos_x = w->viewport->scrollpos_x;
- w->viewport->dest_scrollpos_y = w->viewport->scrollpos_y;
- } break;
+ Point pt;
+ if (tile == INVALID_TILE) {
+ /* the main window with the main view */
+ const Window *w = FindWindowById(WC_MAIN_WINDOW, 0);
- case WE_MOUSEWHEEL:
- ZoomInOrOutToCursorWindow(e->we.wheel.wheel < 0, w);
- break;
+ /* center on same place as main window (zoom is maximum, no adjustment needed) */
+ pt.x = w->viewport->scrollpos_x + w->viewport->virtual_height / 2;
+ pt.y = w->viewport->scrollpos_y + w->viewport->virtual_height / 2;
+ } else {
+ pt = RemapCoords(TileX(tile) * TILE_SIZE + TILE_SIZE / 2, TileY(tile) * TILE_SIZE + TILE_SIZE / 2, TileHeight(tile));
+ }
- case WE_INVALIDATE_DATA:
- /* Only handle zoom message if intended for us (msg ZOOM_IN/ZOOM_OUT) */
- HandleZoomMessage(w, w->viewport, 5, 6);
- break;
+ this->viewport->scrollpos_x = pt.x - ((this->widget[EVW_VIEWPORT].right - this->widget[EVW_VIEWPORT].left) - 1) / 2;
+ this->viewport->scrollpos_y = pt.y - ((this->widget[EVW_VIEWPORT].bottom - this->widget[EVW_VIEWPORT].top) - 1) / 2;
+ this->viewport->dest_scrollpos_x = this->viewport->scrollpos_x;
+ this->viewport->dest_scrollpos_y = this->viewport->scrollpos_y;
+
}
-}
+
+ virtual void OnPaint()
+ {
+ /* set the number in the title bar */
+ SetDParam(0, this->window_number + 1);
+
+ this->DrawWidgets();
+ this->DrawViewport();
+ }
+
+ virtual void OnClick(Point pt, int widget)
+ {
+ switch (widget) {
+ case EVW_ZOOMIN: DoZoomInOutWindow(ZOOM_IN, this); break;
+ case EVW_ZOOMOUT: DoZoomInOutWindow(ZOOM_OUT, this); break;
+
+ case EVW_MAIN_TO_VIEW: { // location button (move main view to same spot as this view) 'Paste Location'
+ Window *w = FindWindowById(WC_MAIN_WINDOW, 0);
+ int x = this->viewport->scrollpos_x; // Where is the main looking at
+ int y = this->viewport->scrollpos_y;
+
+ /* set this view to same location. Based on the center, adjusting for zoom */
+ w->viewport->dest_scrollpos_x = x - (w->viewport->virtual_width - this->viewport->virtual_width) / 2;
+ w->viewport->dest_scrollpos_y = y - (w->viewport->virtual_height - this->viewport->virtual_height) / 2;
+ } break;
+
+ case EVW_VIEW_TO_MAIN: { // inverse location button (move this view to same spot as main view) 'Copy Location'
+ const Window *w = FindWindowById(WC_MAIN_WINDOW, 0);
+ int x = w->viewport->scrollpos_x;
+ int y = w->viewport->scrollpos_y;
+
+ this->viewport->dest_scrollpos_x = x + (w->viewport->virtual_width - this->viewport->virtual_width) / 2;
+ this->viewport->dest_scrollpos_y = y + (w->viewport->virtual_height - this->viewport->virtual_height) / 2;
+ } break;
+ }
+ }
+
+ virtual void OnResize(Point new_size, Point delta)
+ {
+ this->viewport->width += delta.x;
+ this->viewport->height += delta.y;
+ this->viewport->virtual_width += delta.x;
+ this->viewport->virtual_height += delta.y;
+ }
+
+ virtual void OnScroll(Point delta)
+ {
+ ViewPort *vp = IsPtInWindowViewport(this, _cursor.pos.x, _cursor.pos.y);
+
+ if (vp == NULL) {
+ _cursor.fix_at = false;
+ _scrolling_viewport = false;
+ }
+
+ this->viewport->scrollpos_x += ScaleByZoom(delta.x, vp->zoom);
+ this->viewport->scrollpos_y += ScaleByZoom(delta.y, vp->zoom);
+ this->viewport->dest_scrollpos_x = this->viewport->scrollpos_x;
+ this->viewport->dest_scrollpos_y = this->viewport->scrollpos_y;
+ }
+
+ virtual void OnMouseWheel(int wheel)
+ {
+ ZoomInOrOutToCursorWindow(wheel < 0, this);
+ }
+
+ virtual void OnInvalidateData(int data = 0)
+ {
+ /* Only handle zoom message if intended for us (msg ZOOM_IN/ZOOM_OUT) */
+ HandleZoomMessage(this, this->viewport, EVW_ZOOMIN, EVW_ZOOMOUT);
+ }
+};
static const WindowDesc _extra_view_port_desc = {
WDP_AUTO, WDP_AUTO, 300, 68, 300, 268,
WC_EXTRA_VIEW_PORT, WC_NONE,
WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS | WDF_STICKY_BUTTON | WDF_RESIZABLE,
_extra_view_port_widgets,
- ExtraViewPortWndProc
};
void ShowExtraViewPortWindow(TileIndex tile)
@@ -1194,26 +1232,7 @@
/* find next free window number for extra viewport */
while (FindWindowById(WC_EXTRA_VIEW_PORT, i) != NULL) i++;
- Window *w = AllocateWindowDescFront<Window>(&_extra_view_port_desc, i);
- if (w != NULL) {
- Point pt;
-
- if (tile == INVALID_TILE) {
- /* the main window with the main view */
- const Window *v = FindWindowById(WC_MAIN_WINDOW, 0);
-
- /* center on same place as main window (zoom is maximum, no adjustment needed) */
- pt.x = v->viewport->scrollpos_x + v->viewport->virtual_height / 2;
- pt.y = v->viewport->scrollpos_y + v->viewport->virtual_height / 2;
- } else {
- pt = RemapCoords(TileX(tile) * TILE_SIZE + TILE_SIZE / 2, TileY(tile) * TILE_SIZE + TILE_SIZE / 2, TileHeight(tile));
- }
-
- w->viewport->scrollpos_x = pt.x - ((w->widget[4].right - w->widget[4].left) - 1) / 2;
- w->viewport->scrollpos_y = pt.y - ((w->widget[4].bottom - w->widget[4].top) - 1) / 2;
- w->viewport->dest_scrollpos_x = w->viewport->scrollpos_x;
- w->viewport->dest_scrollpos_y = w->viewport->scrollpos_y;
- }
+ new ExtraViewportWindow(&_extra_view_port_desc, i, tile);
}
bool ScrollMainWindowTo(int x, int y, bool instant)
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/sortlist_type.h Mon May 19 15:13:58 2008 +0000
@@ -0,0 +1,31 @@
+/* $Id$ */
+
+/** @file sortlist_type.h Base types for having sorted lists in GUIs. */
+
+#ifndef SORTLIST_TYPE_H
+#define SORTLIST_TYPE_H
+
+enum SortListFlags {
+ VL_NONE = 0, ///< no sort
+ VL_DESC = 1 << 0, ///< sort descending or ascending
+ VL_RESORT = 1 << 1, ///< instruct the code to resort the list in the next loop
+ VL_REBUILD = 1 << 2, ///< create sort-listing to use for qsort and friends
+ VL_END = 1 << 3,
+};
+DECLARE_ENUM_AS_BIT_SET(SortListFlags);
+
+struct Listing {
+ bool order; ///< Ascending/descending
+ byte criteria; ///< Sorting criteria
+};
+
+template <typename T>
+struct GUIList {
+ T* sort_list; ///< The items to sort.
+ SortListFlags flags; ///< used to control sorting/resorting/etc.
+ uint16 list_length; ///< length of the list being sorted
+ uint16 resort_timer; ///< resort list after a given amount of ticks if set
+ byte sort_type; ///< what criteria to sort on
+};
+
+#endif /* SORTLIST_TYPE_H */
--- a/src/station.cpp Mon May 19 14:14:33 2008 +0000
+++ b/src/station.cpp Mon May 19 15:13:58 2008 +0000
@@ -74,8 +74,7 @@
}
MarkDirty();
- RebuildStationLists();
- InvalidateWindowClasses(WC_STATION_LIST);
+ InvalidateWindowData(WC_STATION_LIST, this->owner, 0);
DeleteWindowById(WC_STATION_VIEW, index);
--- a/src/station_cmd.cpp Mon May 19 14:14:33 2008 +0000
+++ b/src/station_cmd.cpp Mon May 19 15:13:58 2008 +0000
@@ -409,7 +409,7 @@
}
SetDParam(0, st->index);
- AddNewsItem(msg, NM_SMALL, NF_VIEWPORT | NF_TILE, NT_ACCEPTANCE, DNC_NONE, st->xy, 0);
+ AddNewsItem(msg, NS_ACCEPTANCE, st->xy, 0);
}
/**
@@ -650,8 +650,7 @@
{
if (st->facilities == 0) {
st->delete_ctr = 0;
- RebuildStationLists();
- InvalidateWindow(WC_STATION_LIST, st->owner);
+ InvalidateWindowData(WC_STATION_LIST, st->owner, 0);
}
/* station remains but it probably lost some parts - station sign should stay in the station boundaries */
UpdateStationSignCoord(st);
@@ -1051,8 +1050,7 @@
st->MarkTilesDirty(false);
UpdateStationVirtCoordDirty(st);
UpdateStationAcceptance(st, false);
- RebuildStationLists();
- InvalidateWindow(WC_STATION_LIST, st->owner);
+ InvalidateWindowData(WC_STATION_LIST, st->owner, 0);
InvalidateWindowWidget(WC_STATION_VIEW, st->index, SVW_TRAINS);
}
@@ -1410,8 +1408,7 @@
UpdateStationVirtCoordDirty(st);
UpdateStationAcceptance(st, false);
- RebuildStationLists();
- InvalidateWindow(WC_STATION_LIST, st->owner);
+ InvalidateWindowData(WC_STATION_LIST, st->owner, 0);
InvalidateWindowWidget(WC_STATION_VIEW, st->index, SVW_ROADVEHS);
}
return cost;
@@ -1723,8 +1720,7 @@
UpdateStationVirtCoordDirty(st);
UpdateStationAcceptance(st, false);
- RebuildStationLists();
- InvalidateWindow(WC_STATION_LIST, st->owner);
+ InvalidateWindowData(WC_STATION_LIST, st->owner, 0);
InvalidateWindowWidget(WC_STATION_VIEW, st->index, SVW_PLANES);
}
@@ -1820,8 +1816,7 @@
UpdateStationVirtCoordDirty(st);
UpdateStationAcceptance(st, false);
- RebuildStationLists();
- InvalidateWindow(WC_STATION_LIST, st->owner);
+ InvalidateWindowData(WC_STATION_LIST, st->owner, 0);
InvalidateWindowWidget(WC_STATION_VIEW, st->index, SVW_SHIPS);
}
@@ -1979,8 +1974,7 @@
UpdateStationVirtCoordDirty(st);
UpdateStationAcceptance(st, false);
- RebuildStationLists();
- InvalidateWindow(WC_STATION_LIST, st->owner);
+ InvalidateWindowData(WC_STATION_LIST, st->owner, 0);
InvalidateWindowWidget(WC_STATION_VIEW, st->index, SVW_SHIPS);
}
@@ -2637,7 +2631,7 @@
st->name = strdup(_cmd_text);
UpdateStationVirtCoord(st);
- ResortStationLists();
+ InvalidateWindowData(WC_STATION_LIST, st->owner, 1);
MarkWholeScreenDirty();
}
@@ -2858,8 +2852,7 @@
SetTileOwner(tile, new_player);
if (!IsBuoy(tile)) st->owner = new_player; // do not set st->owner for buoys
- RebuildStationLists();
- InvalidateWindowClasses(WC_STATION_LIST);
+ InvalidateWindowClassesData(WC_STATION_LIST, 0);
} else {
if (IsDriveThroughStopTile(tile)) {
/* Remove the drive-through road stop */
--- a/src/station_gui.cpp Mon May 19 14:14:33 2008 +0000
+++ b/src/station_gui.cpp Mon May 19 15:13:58 2008 +0000
@@ -168,39 +168,6 @@
typedef GUIList<const Station*> GUIStationList;
/**
- * Set the station sort flag for all station-list windows.
- * @param sl_flag Sort list flag to set for all station-list windows
- */
-static void SetStationListsFlag(SortListFlags sl_flag)
-{
- Window *const *wz;
-
- FOR_ALL_WINDOWS(wz) {
- Window *w = *wz;
- if (w->window_class == WC_STATION_LIST) {
- dynamic_cast<GUIStationList*>(w)->flags |= sl_flag;
- w->SetDirty();
- }
- }
-}
-
-/**
- * Set the 'VL_REBUILD' flag for all station lists
- */
-void RebuildStationLists()
-{
- SetStationListsFlag(VL_REBUILD);
-}
-
-/**
- * Set the 'VL_RESORT' flag for all station lists
- */
-void ResortStationLists()
-{
- SetStationListsFlag(VL_RESORT);
-}
-
-/**
* Rebuild station list if the VL_REBUILD flag is set
*
* @param sl pointer to plstations_d (station list and flags)
@@ -287,7 +254,7 @@
static byte facilities;
static bool include_empty;
- PlayerStationsWindow(const WindowDesc *desc, void *data, WindowNumber window_number) : Window(desc, data, window_number)
+ PlayerStationsWindow(const WindowDesc *desc, WindowNumber window_number) : Window(desc, window_number)
{
this->caption_color = (byte)this->window_number;
this->vscroll.cap = 12;
@@ -369,10 +336,10 @@
/* Set text of sort by dropdown */
this->widget[SLW_SORTDROPBTN].data = _station_sort_listing[this->sort_type];
- DrawWindowWidgets(this);
+ this->DrawWidgets();
/* draw arrow pointing up/down for ascending/descending sorting */
- DrawSortButtonState(this, SLW_SORTBY, this->flags & VL_DESC ? SBS_DOWN : SBS_UP);
+ this->DrawSortButtonState(SLW_SORTBY, this->flags & VL_DESC ? SBS_DOWN : SBS_UP);
int cg_ofst;
int x = 89;
@@ -436,8 +403,6 @@
virtual void OnClick(Point pt, int widget)
{
- PlayerID owner = (PlayerID)this->window_number;
-
switch (widget) {
case SLW_LIST: {
uint32 id_v = (pt.y - 41) / 10;
@@ -450,7 +415,7 @@
const Station *st = this->sort_list[id_v];
/* do not check HasStationInUse - it is slow and may be invalid */
- assert(st->owner == owner || (st->owner == OWNER_NONE && !st->IsBuoy()));
+ assert(st->owner == (PlayerID)this->window_number || (st->owner == OWNER_NONE && !st->IsBuoy()));
if (_ctrl_pressed) {
ShowExtraViewPortWindow(st->xy);
@@ -607,6 +572,11 @@
{
this->vscroll.cap += delta.y / 10;
}
+
+ virtual void OnInvalidateData(int data)
+ {
+ this->flags |= (data == 0 ? VL_REBUILD : VL_RESORT);
+ }
};
Listing PlayerStationsWindow::station_sort = {0, 0};
@@ -645,7 +615,6 @@
WC_STATION_LIST, WC_NONE,
WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_STICKY_BUTTON | WDF_RESIZABLE,
_player_stations_widgets,
- NULL
};
/**
@@ -737,7 +706,7 @@
uint32 cargo; ///< Bitmask of cargo types to expand
uint16 cargo_rows[NUM_CARGO]; ///< Header row for each cargo type
- StationViewWindow(const WindowDesc *desc, void *data, WindowNumber window_number) : Window(desc, data, window_number)
+ StationViewWindow(const WindowDesc *desc, WindowNumber window_number) : Window(desc, window_number)
{
PlayerID owner = GetStation(window_number)->owner;
if (owner != OWNER_NONE) this->caption_color = owner;
@@ -815,7 +784,7 @@
SetDParam(0, st->index);
SetDParam(1, st->facilities);
- DrawWindowWidgets(this);
+ this->DrawWidgets();
int x = 2; ///< coordinates used for printing waiting/accepted/rating of cargo
int y = 15;
@@ -1017,7 +986,6 @@
WC_STATION_VIEW, WC_NONE,
WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS | WDF_STICKY_BUTTON | WDF_RESIZABLE,
_station_view_widgets,
- NULL
};
/**
--- a/src/station_gui.h Mon May 19 14:14:33 2008 +0000
+++ b/src/station_gui.h Mon May 19 15:13:58 2008 +0000
@@ -48,10 +48,6 @@
SVW_RESIZE, ///< Resize button
};
-/* sorter stuff */
-void RebuildStationLists();
-void ResortStationLists();
-
enum StationCoverageType {
SCT_PASSENGERS_ONLY,
SCT_NON_PASSENGERS_ONLY,
--- a/src/statusbar_gui.cpp Mon May 19 14:14:33 2008 +0000
+++ b/src/statusbar_gui.cpp Mon May 19 15:13:58 2008 +0000
@@ -18,21 +18,15 @@
#include "window_gui.h"
#include "variables.h"
#include "window_func.h"
+#include "statusbar_gui.h"
#include "table/strings.h"
#include "table/sprites.h"
-extern GetNewsStringCallbackProc * const _get_news_string_callback[];
-
static bool DrawScrollingStatusText(const NewsItem *ni, int pos, int width)
{
- StringID str;
- if (ni->display_mode == NM_CALLBACK) {
- str = _get_news_string_callback[ni->callback](ni);
- } else {
- CopyInDParam(0, ni->params, lengthof(ni->params));
- str = ni->string_id;
- }
+ CopyInDParam(0, ni->params, lengthof(ni->params));
+ StringID str = ni->string_id;
char buf[512];
GetString(buf, str, lastof(buf));
@@ -69,80 +63,98 @@
return x > 0;
}
-static void StatusBarWndProc(Window *w, WindowEvent *e)
-{
- switch (e->event) {
- case WE_PAINT: {
- const Player *p = (_local_player == PLAYER_SPECTATOR) ? NULL : GetPlayer(_local_player);
-
- DrawWindowWidgets(w);
- SetDParam(0, _date);
- DrawStringCentered(70, 1, (_pause_game || _patches.status_long_date) ? STR_00AF : STR_00AE, TC_FROMSTRING);
-
- if (p != NULL) {
- /* Draw player money */
- SetDParam(0, p->player_money);
- DrawStringCentered(w->widget[2].left + 70, 1, STR_0004, TC_FROMSTRING);
- }
+struct StatusBarWindow : Window {
+ bool saving;
+ int ticker_scroll;
+ int reminder_timeout;
- /* Draw status bar */
- if (WP(w, def_d).data_3) { // true when saving is active
- DrawStringCenteredTruncated(w->widget[1].left + 1, w->widget[1].right - 1, 1, STR_SAVING_GAME, TC_FROMSTRING);
- } else if (_do_autosave) {
- DrawStringCenteredTruncated(w->widget[1].left + 1, w->widget[1].right - 1, 1, STR_032F_AUTOSAVE, TC_FROMSTRING);
- } else if (_pause_game) {
- DrawStringCenteredTruncated(w->widget[1].left + 1, w->widget[1].right - 1, 1, STR_0319_PAUSED, TC_FROMSTRING);
- } else if (WP(w, def_d).data_1 > -1280 && FindWindowById(WC_NEWS_WINDOW,0) == NULL && _statusbar_news_item.string_id != 0) {
- /* Draw the scrolling news text */
- if (!DrawScrollingStatusText(&_statusbar_news_item, WP(w, def_d).data_1, w->widget[1].right - w->widget[1].left - 2)) {
- WP(w, def_d).data_1 = -1280;
- if (p != NULL) {
- /* This is the default text */
- SetDParam(0, p->index);
- DrawStringCenteredTruncated(w->widget[1].left + 1, w->widget[1].right - 1, 1, STR_02BA, TC_FROMSTRING);
- }
- }
- } else {
+ StatusBarWindow(const WindowDesc *desc) : Window(desc)
+ {
+ CLRBITS(this->flags4, WF_WHITE_BORDER_MASK);
+ this->ticker_scroll = -1280;
+
+ this->FindWindowPlacementAndResize(desc);
+ }
+
+ virtual void OnPaint()
+ {
+ const Player *p = (_local_player == PLAYER_SPECTATOR) ? NULL : GetPlayer(_local_player);
+
+ this->DrawWidgets();
+ SetDParam(0, _date);
+ DrawStringCentered(70, 1, (_pause_game || _patches.status_long_date) ? STR_00AF : STR_00AE, TC_FROMSTRING);
+
+ if (p != NULL) {
+ /* Draw player money */
+ SetDParam(0, p->player_money);
+ DrawStringCentered(this->widget[2].left + 70, 1, STR_0004, TC_FROMSTRING);
+ }
+
+ /* Draw status bar */
+ if (this->saving) { // true when saving is active
+ DrawStringCenteredTruncated(this->widget[1].left + 1, this->widget[1].right - 1, 1, STR_SAVING_GAME, TC_FROMSTRING);
+ } else if (_do_autosave) {
+ DrawStringCenteredTruncated(this->widget[1].left + 1, this->widget[1].right - 1, 1, STR_032F_AUTOSAVE, TC_FROMSTRING);
+ } else if (_pause_game) {
+ DrawStringCenteredTruncated(this->widget[1].left + 1, this->widget[1].right - 1, 1, STR_0319_PAUSED, TC_FROMSTRING);
+ } else if (this->ticker_scroll > -1280 && FindWindowById(WC_NEWS_WINDOW, 0) == NULL && _statusbar_news_item.string_id != 0) {
+ /* Draw the scrolling news text */
+ if (!DrawScrollingStatusText(&_statusbar_news_item, this->ticker_scroll, this->widget[1].right - this->widget[1].left - 2)) {
+ this->ticker_scroll = -1280;
if (p != NULL) {
/* This is the default text */
SetDParam(0, p->index);
- DrawStringCenteredTruncated(w->widget[1].left + 1, w->widget[1].right - 1, 1, STR_02BA, TC_FROMSTRING);
+ DrawStringCenteredTruncated(this->widget[1].left + 1, this->widget[1].right - 1, 1, STR_02BA, TC_FROMSTRING);
}
}
-
- if (WP(w, def_d).data_2 > 0) DrawSprite(SPR_BLOT, PALETTE_TO_RED, w->widget[1].right - 11, 2);
- } break;
-
- case WE_INVALIDATE_DATA:
- WP(w, def_d).data_3 = e->we.invalidate.data;
- break;
-
- case WE_CLICK:
- switch (e->we.click.widget) {
- case 1: ShowLastNewsMessage(); break;
- case 2: if (_local_player != PLAYER_SPECTATOR) ShowPlayerFinances(_local_player); break;
- default: ResetObjectToPlace();
+ } else {
+ if (p != NULL) {
+ /* This is the default text */
+ SetDParam(0, p->index);
+ DrawStringCenteredTruncated(this->widget[1].left + 1, this->widget[1].right - 1, 1, STR_02BA, TC_FROMSTRING);
}
- break;
+ }
- case WE_TICK: {
- if (_pause_game) return;
-
- if (WP(w, def_d).data_1 > -1280) { // Scrolling text
- WP(w, def_d).data_1 -= 2;
- w->InvalidateWidget(1);
- }
+ if (this->reminder_timeout > 0) DrawSprite(SPR_BLOT, PALETTE_TO_RED, this->widget[1].right - 11, 2);
+ }
- if (WP(w, def_d).data_2 > 0) { // Red blot to show there are new unread newsmessages
- WP(w, def_d).data_2 -= 2;
- } else if (WP(w, def_d).data_2 < 0) {
- WP(w, def_d).data_2 = 0;
- w->InvalidateWidget(1);
- }
+ virtual void OnInvalidateData(int data)
+ {
+ switch (data) {
+ default: NOT_REACHED();
+ case SBI_SAVELOAD_START: this->saving = true; break;
+ case SBI_SAVELOAD_FINISH: this->saving = false; break;
+ case SBI_SHOW_TICKER: this->ticker_scroll = 360; break;
+ case SBI_SHOW_REMINDER: this->reminder_timeout = 91; break;
+ }
+ }
- } break;
+ virtual void OnClick(Point pt, int widget)
+ {
+ switch (widget) {
+ case 1: ShowLastNewsMessage(); break;
+ case 2: if (_local_player != PLAYER_SPECTATOR) ShowPlayerFinances(_local_player); break;
+ default: ResetObjectToPlace();
+ }
}
-}
+
+ virtual void OnTick()
+ {
+ if (_pause_game) return;
+
+ if (this->ticker_scroll > -1280) { // Scrolling text
+ this->ticker_scroll -= 2;
+ this->InvalidateWidget(1);
+ }
+
+ if (this->reminder_timeout > 0) { // Red blot to show there are new unread newsmessages
+ this->reminder_timeout -= 2;
+ } else if (this->reminder_timeout < 0) {
+ this->reminder_timeout = 0;
+ this->InvalidateWidget(1);
+ }
+ }
+};
static const Widget _main_status_widgets[] = {
{ WWT_PANEL, RESIZE_NONE, 14, 0, 139, 0, 11, 0x0, STR_NULL},
@@ -156,15 +168,19 @@
WC_STATUS_BAR, WC_NONE,
WDF_STD_TOOLTIPS | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS,
_main_status_widgets,
- StatusBarWndProc
};
+/**
+ * Checks whether the news ticker is currently being used.
+ */
+bool IsNewsTickerShown()
+{
+ const StatusBarWindow *w = dynamic_cast<StatusBarWindow*>(FindWindowById(WC_STATUS_BAR, 0));
+ return w != NULL && w->ticker_scroll > -1280;
+}
+
void ShowStatusBar()
{
_main_status_desc.top = _screen.height - 12;
- Window *w = new Window(&_main_status_desc);
- if (w != NULL) {
- CLRBITS(w->flags4, WF_WHITE_BORDER_MASK);
- WP(w, def_d).data_1 = -1280;
- }
+ new StatusBarWindow(&_main_status_desc);
}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/src/statusbar_gui.h Mon May 19 15:13:58 2008 +0000
@@ -0,0 +1,20 @@
+/* $Id$ */
+
+/** @file statusbar_gui.h Functions, definitions and such used only by the GUI. */
+
+#ifndef STATUSBAR_GUI_H
+#define STATUSBAR_GUI_H
+
+enum StatusBarInvalidate
+{
+ SBI_SAVELOAD_START,
+ SBI_SAVELOAD_FINISH,
+ SBI_SHOW_TICKER,
+ SBI_SHOW_REMINDER,
+ SBI_END
+};
+
+bool IsNewsTickerShown();
+void ShowStatusBar();
+
+#endif /* STATUSBAR_GUI_H */
--- a/src/stdafx.h Mon May 19 14:14:33 2008 +0000
+++ b/src/stdafx.h Mon May 19 15:13:58 2008 +0000
@@ -145,6 +145,10 @@
#include <malloc.h> // alloca()
#endif
+#if defined(WIN32)
+ #define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers
+#endif
+
/* Stuff for MSVC */
#if defined(_MSC_VER)
#pragma once
@@ -158,7 +162,6 @@
#endif
#define _WIN32_IE_ 0x0401 // 4.01 (win98 and NT4SP5+)
- #define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers
#pragma warning(disable: 4244) // 'conversion' conversion from 'type1' to 'type2', possible loss of data
#pragma warning(disable: 4761) // integral size mismatch in argument : conversion supplied
#pragma warning(disable: 4200) // nonstandard extension used : zero-sized array in struct/union
--- a/src/subsidy_gui.cpp Mon May 19 14:14:33 2008 +0000
+++ b/src/subsidy_gui.cpp Mon May 19 15:13:58 2008 +0000
@@ -19,161 +19,149 @@
#include "table/strings.h"
-static void HandleSubsidyClick(int y)
-{
- const Subsidy *s;
- uint num;
- int offs;
- TileIndex xy;
+struct SubsidyListWindow : Window {
+ SubsidyListWindow(const WindowDesc *desc, WindowNumber window_number) : Window(desc, window_number)
+ {
+ }
- if (y < 0) return;
+ virtual void OnClick(Point pt, int widget)
+ {
+ if (widget != 3) return;
- num = 0;
- for (s = _subsidies; s != endof(_subsidies); s++) {
- if (s->cargo_type != CT_INVALID && s->age < 12) {
+ int y = pt.y - 25;
+
+ if (y < 0) return;
+
+ uint num = 0;
+ for (const Subsidy *s = _subsidies; s != endof(_subsidies); s++) {
+ if (s->cargo_type != CT_INVALID && s->age < 12) {
+ y -= 10;
+ if (y < 0) this->HandleClick(s);
+ num++;
+ }
+ }
+
+ if (num == 0) {
y -= 10;
- if (y < 0) goto handle_click;
- num++;
+ if (y < 0) return;
+ }
+
+ y -= 11;
+ if (y < 0) return;
+
+ for (const Subsidy *s = _subsidies; s != endof(_subsidies); s++) {
+ if (s->cargo_type != CT_INVALID && s->age >= 12) {
+ y -= 10;
+ if (y < 0) this->HandleClick(s);
+ }
}
}
- if (num == 0) {
- y -= 10;
- if (y < 0) return;
- }
-
- y -= 11;
- if (y < 0) return;
-
- for (s = _subsidies; s != endof(_subsidies); s++) {
- if (s->cargo_type != CT_INVALID && s->age >= 12) {
- y -= 10;
- if (y < 0) goto handle_click;
- }
- }
- return;
+ void HandleClick(const Subsidy *s)
+ {
+ TownEffect te = GetCargo(s->cargo_type)->town_effect;
+ TileIndex xy;
-handle_click:
-
- TownEffect te = GetCargo(s->cargo_type)->town_effect;
-
- /* determine from coordinate for subsidy and try to scroll to it */
- offs = s->from;
- if (s->age >= 12) {
- xy = GetStation(offs)->xy;
- } else if (te == TE_PASSENGERS || te == TE_MAIL) {
- xy = GetTown(offs)->xy;
- } else {
- xy = GetIndustry(offs)->xy;
- }
-
- if (_ctrl_pressed || !ScrollMainWindowToTile(xy)) {
- if (_ctrl_pressed) ShowExtraViewPortWindow(xy);
-
- /* otherwise determine to coordinate for subsidy and scroll to it */
- offs = s->to;
+ /* determine from coordinate for subsidy and try to scroll to it */
+ uint offs = s->from;
if (s->age >= 12) {
xy = GetStation(offs)->xy;
- } else if (te == TE_PASSENGERS || te == TE_MAIL || te == TE_GOODS || te == TE_FOOD) {
+ } else if (te == TE_PASSENGERS || te == TE_MAIL) {
xy = GetTown(offs)->xy;
} else {
xy = GetIndustry(offs)->xy;
}
- if (_ctrl_pressed) {
- ShowExtraViewPortWindow(xy);
- } else {
- ScrollMainWindowToTile(xy);
- }
- }
-}
-
-static void DrawSubsidiesWindow(const Window *w)
-{
- YearMonthDay ymd;
- const Subsidy *s;
- uint num;
- int x;
- int y;
-
- DrawWindowWidgets(w);
-
- ConvertDateToYMD(_date, &ymd);
+ if (_ctrl_pressed || !ScrollMainWindowToTile(xy)) {
+ if (_ctrl_pressed) ShowExtraViewPortWindow(xy);
- int width = w->width - 13; // scroll bar = 11 + pixel each side
- y = 15;
- x = 1;
-
- /* Section for drawing the offered subisidies */
- DrawStringTruncated(x, y, STR_2026_SUBSIDIES_ON_OFFER_FOR, TC_FROMSTRING, width);
- y += 10;
- num = 0;
+ /* otherwise determine to coordinate for subsidy and scroll to it */
+ offs = s->to;
+ if (s->age >= 12) {
+ xy = GetStation(offs)->xy;
+ } else if (te == TE_PASSENGERS || te == TE_MAIL || te == TE_GOODS || te == TE_FOOD) {
+ xy = GetTown(offs)->xy;
+ } else {
+ xy = GetIndustry(offs)->xy;
+ }
- for (s = _subsidies; s != endof(_subsidies); s++) {
- if (s->cargo_type != CT_INVALID && s->age < 12) {
- int x2;
-
- /* Displays the two offered towns */
- SetupSubsidyDecodeParam(s, 1);
- x2 = DrawStringTruncated(x + 2, y, STR_2027_FROM_TO, TC_FROMSTRING, width);
-
- /* Displays the deadline before voiding the proposal */
- SetDParam(0, _date - ymd.day + 384 - s->age * 32);
- DrawStringTruncated(x2, y, STR_2028_BY, TC_FROMSTRING, width - x2);
- y += 10;
- num++;
+ if (_ctrl_pressed) {
+ ShowExtraViewPortWindow(xy);
+ } else {
+ ScrollMainWindowToTile(xy);
+ }
}
}
- if (num == 0) {
- DrawStringTruncated(x + 2, y, STR_202A_NONE, TC_FROMSTRING, width - 2);
- y += 10;
- }
-
- /* Section for drawing the already granted subisidies */
- DrawStringTruncated(x, y + 1, STR_202B_SERVICES_ALREADY_SUBSIDISED, TC_FROMSTRING, width);
- y += 10;
- num = 0;
-
- for (s = _subsidies; s != endof(_subsidies); s++) {
- if (s->cargo_type != CT_INVALID && s->age >= 12) {
- int xt;
-
- SetupSubsidyDecodeParam(s, 1);
-
- PlayerID player = GetStation(s->to)->owner;
- SetDParam(3, player);
-
- /* Displays the two connected stations */
- xt = DrawStringTruncated(x + 2, y, STR_202C_FROM_TO, TC_FROMSTRING, width - 2);
+ virtual void OnPaint()
+ {
+ YearMonthDay ymd;
+ const Subsidy *s;
- /* Displays the date where the granted subsidy will end */
- if ((xt > 3) && (width - xt) > 9 ) { // do not draw if previous drawing failed or if it will overlap on scrollbar
- SetDParam(0, _date - ymd.day + 768 - s->age * 32);
- DrawStringTruncated(xt, y, STR_202D_UNTIL, TC_FROMSTRING, width - xt);
- }
- y += 10;
- num++;
- }
- }
-
- if (num == 0) DrawStringTruncated(x + 2, y, STR_202A_NONE, TC_FROMSTRING, width - 2);
-}
+ this->DrawWidgets();
-static void SubsidiesListWndProc(Window *w, WindowEvent *e)
-{
- switch (e->event) {
- case WE_PAINT: DrawSubsidiesWindow(w); break;
+ ConvertDateToYMD(_date, &ymd);
- case WE_CLICK:
- switch (e->we.click.widget) {
- case 3:
- HandleSubsidyClick(e->we.click.pt.y - 25);
- break;
+ int width = this->width - 13; // scroll bar = 11 + pixel each side
+ int y = 15;
+ int x = 1;
+
+ /* Section for drawing the offered subisidies */
+ DrawStringTruncated(x, y, STR_2026_SUBSIDIES_ON_OFFER_FOR, TC_FROMSTRING, width);
+ y += 10;
+ uint num = 0;
+
+ for (s = _subsidies; s != endof(_subsidies); s++) {
+ if (s->cargo_type != CT_INVALID && s->age < 12) {
+ int x2;
+
+ /* Displays the two offered towns */
+ SetupSubsidyDecodeParam(s, 1);
+ x2 = DrawStringTruncated(x + 2, y, STR_2027_FROM_TO, TC_FROMSTRING, width);
+
+ /* Displays the deadline before voiding the proposal */
+ SetDParam(0, _date - ymd.day + 384 - s->age * 32);
+ DrawStringTruncated(x2, y, STR_2028_BY, TC_FROMSTRING, width - x2);
+ y += 10;
+ num++;
}
- break;
+ }
+
+ if (num == 0) {
+ DrawStringTruncated(x + 2, y, STR_202A_NONE, TC_FROMSTRING, width - 2);
+ y += 10;
+ }
+
+ /* Section for drawing the already granted subisidies */
+ DrawStringTruncated(x, y + 1, STR_202B_SERVICES_ALREADY_SUBSIDISED, TC_FROMSTRING, width);
+ y += 10;
+ num = 0;
+
+ for (s = _subsidies; s != endof(_subsidies); s++) {
+ if (s->cargo_type != CT_INVALID && s->age >= 12) {
+ int xt;
+
+ SetupSubsidyDecodeParam(s, 1);
+
+ PlayerID player = GetStation(s->to)->owner;
+ SetDParam(3, player);
+
+ /* Displays the two connected stations */
+ xt = DrawStringTruncated(x + 2, y, STR_202C_FROM_TO, TC_FROMSTRING, width - 2);
+
+ /* Displays the date where the granted subsidy will end */
+ if ((xt > 3) && (width - xt) > 9 ) { // do not draw if previous drawing failed or if it will overlap on scrollbar
+ SetDParam(0, _date - ymd.day + 768 - s->age * 32);
+ DrawStringTruncated(xt, y, STR_202D_UNTIL, TC_FROMSTRING, width - xt);
+ }
+ y += 10;
+ num++;
+ }
+ }
+
+ if (num == 0) DrawStringTruncated(x + 2, y, STR_202A_NONE, TC_FROMSTRING, width - 2);
}
-}
+};
static const Widget _subsidies_list_widgets[] = {
{ WWT_CLOSEBOX, RESIZE_NONE, 13, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW},
@@ -191,11 +179,10 @@
WC_SUBSIDIES_LIST, WC_NONE,
WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_STICKY_BUTTON | WDF_RESIZABLE,
_subsidies_list_widgets,
- SubsidiesListWndProc
};
void ShowSubsidiesList()
{
- AllocateWindowDescFront<Window>(&_subsidies_list_desc, 0);
+ AllocateWindowDescFront<SubsidyListWindow>(&_subsidies_list_desc, 0);
}
--- a/src/table/engines.h Mon May 19 14:14:33 2008 +0000
+++ b/src/table/engines.h Mon May 19 15:13:58 2008 +0000
@@ -387,8 +387,8 @@
RVI( 0, G, 13, 112, 1000, 131, 120, RC_S, 0, 0 , 20, R, S), // 8
RVI( 1, G, 19, 128, 1200, 162, 140, RC_S, 0, 0 , 21, R, S), // 9
RVI( 0, G, 22, 144, 1600, 170, 130, RC_S, 0, 0 , 22, R, S), // 10
- RVI( 8, M, 11, 112, 600/2, 32, 85/2, RC_D, 38, CT_PASSENGERS , 10, R, D), // 11
- RVI(10, M, 14, 120, 700/2, 38, 70/2, RC_D, 40, CT_PASSENGERS , 11, R, D), // 12
+ RVI( 8, M, 11, 112, 600, 32, 85, RC_D, 38, CT_PASSENGERS , 10, R, D), // 11
+ RVI(10, M, 14, 120, 700, 38, 70, RC_D, 40, CT_PASSENGERS , 11, R, D), // 12
RVI( 4, G, 15, 128, 1250, 72, 95, RC_D, 0, 0 , 30, R, D), // 13
RVI( 5, G, 17, 144, 1750, 101, 120, RC_D, 0, 0 , 31, R, D), // 14
RVI( 4, G, 18, 160, 2580, 112, 140, RC_D, 0, 0 , 32, R, D), // 15
@@ -396,13 +396,13 @@
RVI(12, G, 16, 112, 2400, 120, 105, RC_D, 0, 0 , 34, R, D), // 17
RVI(13, G, 30, 112, 6600, 207, 155, RC_D, 0, 0 , 35, R, D), // 18
RVI(15, G, 18, 104, 1500, 110, 105, RC_D, 0, 0 , 29, R, D), // 19
- RVI(16, M, 35, 160, 3500/2, 95, 205/2, RC_D, 0, 0 , 45, R, D), // 20
+ RVI(16, M, 35, 160, 3500, 95, 205, RC_D, 0, 0 , 45, R, D), // 20
RVI(18, G, 21, 104, 2200, 120, 145, RC_D, 0, 0 , 32, R, D), // 21
- RVI( 6, M, 20, 200, 4500/2, 70, 190/2, RC_D, 4, CT_MAIL , 50, R, D), // 22
+ RVI( 6, M, 20, 200, 4500, 70, 190, RC_D, 4, CT_MAIL , 50, R, D), // 22
RVI(20, G, 26, 160, 3600, 84, 180, RC_E, 0, 0 , 40, C, E), // 23
RVI(20, G, 30, 176, 5000, 82, 205, RC_E, 0, 0 , 41, C, E), // 24
- RVI(21, M, 40, 240, 7000/2, 90, 240/2, RC_E, 0, 0 , 51, C, E), // 25
- RVI(23, M, 43, 264, 8000/2, 95, 250/2, RC_E, 0, 0 , 52, C, E), // 26
+ RVI(21, M, 40, 240, 7000, 90, 240, RC_E, 0, 0 , 51, C, E), // 25
+ RVI(23, M, 43, 264, 8000, 95, 250, RC_E, 0, 0 , 52, C, E), // 26
RVI(33, W, 247, 0, 0, 25, 0, RC_W, 40, CT_PASSENGERS , 0, R, A), // 27
RVI(35, W, 228, 0, 0, 21, 0, RC_W, 30, CT_MAIL , 0, R, A), // 28
RVI(34, W, 176, 0, 0, 18, 0, RC_W, 30, CT_COAL , 0, R, A), // 29
@@ -431,7 +431,7 @@
RVI(58, W, 193, 0, 0, 18, 0, RC_W, 25, CT_FIZZY_DRINKS, 0, R, A), // 52
RVI(59, W, 191, 0, 0, 18, 0, RC_W, 30, CT_PLASTIC , 0, R, A), // 53
RVI(25, G, 52, 304, 9000, 95, 230, RC_E, 0, 0 , 60, O, N), // 54
- RVI(26, M, 60, 336, 10000/2, 85, 240/2, RC_E, 25, CT_PASSENGERS , 62, O, N), // 55
+ RVI(26, M, 60, 336, 10000, 85, 240, RC_E, 25, CT_PASSENGERS , 62, O, N), // 55
RVI(26, G, 53, 320, 5000, 95, 230, RC_E, 0, 0 , 63, O, N), // 56
RVI(60, W, 247, 0, 0, 25, 0, RC_W, 45, CT_PASSENGERS , 0, O, A), // 57
RVI(62, W, 228, 0, 0, 21, 0, RC_W, 35, CT_MAIL , 0, O, A), // 58
@@ -463,7 +463,7 @@
RVI(28, G, 70, 400, 10000, 105, 250, RC_E, 0, 0 , 70, L, V), // 84
RVI(29, G, 74, 448, 12000, 120, 253, RC_E, 0, 0 , 71, L, V), // 85
RVI(30, G, 82, 480, 15000, 130, 254, RC_E, 0, 0 , 72, L, V), // 86
- RVI(31, M, 95, 640, 20000/2, 150, 255/2, RC_E, 0, 0 , 73, L, V), // 87
+ RVI(31, M, 95, 640, 20000, 150, 255, RC_E, 0, 0 , 73, L, V), // 87
RVI(28, G, 70, 480, 10000, 120, 250, RC_E, 0, 0 , 74, L, V), // 88
RVI(60, W, 247, 0, 0, 25, 0, RC_W, 47, CT_PASSENGERS , 0, L, A), // 89
RVI(62, W, 228, 0, 0, 21, 0, RC_W, 37, CT_MAIL , 0, L, A), // 90
--- a/src/terraform_cmd.cpp Mon May 19 14:14:33 2008 +0000
+++ b/src/terraform_cmd.cpp Mon May 19 15:13:58 2008 +0000
@@ -301,7 +301,10 @@
return_cmd_error(STR_1002_EXCAVATION_WOULD_DAMAGE);
}
/* Check tiletype-specific things, and add extra-cost */
+ const bool curr_gen = _generating_world;
+ if (_game_mode == GM_EDITOR) _generating_world = true; // used to create green terraformed land
CommandCost cost = _tile_type_procs[GetTileType(tile)]->terraform_tile_proc(tile, flags | DC_AUTO, z_min * TILE_HEIGHT, tileh);
+ _generating_world = curr_gen;
if (CmdFailed(cost)) {
_terraform_err_tile = tile;
return cost;
--- a/src/terraform_gui.cpp Mon May 19 14:14:33 2008 +0000
+++ b/src/terraform_gui.cpp Mon May 19 15:13:58 2008 +0000
@@ -110,12 +110,9 @@
* allows for additional implements that are more local. For example X_Y drag
* of convertrail which belongs in rail_gui.cpp and not terraform_gui.cpp
**/
-bool GUIPlaceProcDragXY(const WindowEvent *e)
+bool GUIPlaceProcDragXY(ViewportDragDropSelectionProcess proc, TileIndex start_tile, TileIndex end_tile)
{
- TileIndex start_tile = e->we.place.starttile;
- TileIndex end_tile = e->we.place.tile;
-
- switch (e->we.place.select_proc) {
+ switch (proc) {
case DDSP_DEMOLISH_AREA:
DoCommandP(end_tile, start_tile, 0, CcPlaySound10, CMD_CLEAR_AREA | CMD_MSG(STR_00B5_CAN_T_CLEAR_THIS_AREA));
break;
@@ -232,56 +229,67 @@
TerraformClick_PlaceSign,
};
-static void TerraformToolbWndProc(Window *w, WindowEvent *e)
-{
- switch (e->event) {
- case WE_PAINT:
- DrawWindowWidgets(w);
- break;
+struct TerraformToolbarWindow : Window {
+ TerraformToolbarWindow(const WindowDesc *desc, WindowNumber window_number) : Window(desc, window_number)
+ {
+ this->FindWindowPlacementAndResize(desc);
+ }
- case WE_CLICK:
- if (e->we.click.widget >= 4) _terraform_button_proc[e->we.click.widget - 4](w);
- break;
+ ~TerraformToolbarWindow()
+ {
+ }
- case WE_KEYPRESS: {
- uint i;
+ virtual void OnPaint()
+ {
+ this->DrawWidgets();
+ }
- for (i = 0; i != lengthof(_terraform_keycodes); i++) {
- if (e->we.keypress.keycode == _terraform_keycodes[i]) {
- e->we.keypress.cont = false;
- _terraform_button_proc[i](w);
- break;
+ virtual void OnClick(Point pt, int widget)
+ {
+ if (widget >= 4) _terraform_button_proc[widget - 4](this);
+ }
+
+ virtual EventState OnKeyPress(uint16 key, uint16 keycode)
+ {
+ for (uint i = 0; i != lengthof(_terraform_keycodes); i++) {
+ if (keycode == _terraform_keycodes[i]) {
+ _terraform_button_proc[i](this);
+ return ES_HANDLED;
}
}
- break;
+ return ES_NOT_HANDLED;
}
- case WE_PLACE_OBJ:
- _place_proc(e->we.place.tile);
- return;
+ virtual void OnPlaceObject(Point pt, TileIndex tile)
+ {
+ _place_proc(tile);
+ }
- case WE_PLACE_DRAG:
- VpSelectTilesWithMethod(e->we.place.pt.x, e->we.place.pt.y, e->we.place.select_method);
- break;
+ virtual void OnPlaceDrag(ViewportPlaceMethod select_method, ViewportDragDropSelectionProcess select_proc, Point pt)
+ {
+ VpSelectTilesWithMethod(pt.x, pt.y, select_method);
+ }
- case WE_PLACE_MOUSEUP:
- if (e->we.place.pt.x != -1) {
- switch (e->we.place.select_proc) {
+ virtual void OnPlaceMouseUp(ViewportPlaceMethod select_method, ViewportDragDropSelectionProcess select_proc, Point pt, TileIndex start_tile, TileIndex end_tile)
+ {
+ if (pt.x != -1) {
+ switch (select_proc) {
+ default: NOT_REACHED();
case DDSP_DEMOLISH_AREA:
case DDSP_RAISE_AND_LEVEL_AREA:
case DDSP_LOWER_AND_LEVEL_AREA:
case DDSP_LEVEL_AREA:
- GUIPlaceProcDragXY(e);
+ GUIPlaceProcDragXY(select_proc, start_tile, end_tile);
break;
}
}
- break;
+ }
- case WE_ABORT_PLACE_OBJ:
- w->RaiseButtons();
- break;
+ virtual void OnPlaceObjectAbort()
+ {
+ this->RaiseButtons();
}
-}
+};
static const Widget _terraform_widgets[] = {
{ WWT_CLOSEBOX, RESIZE_NONE, 7, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW},
@@ -305,13 +313,12 @@
WC_SCEN_LAND_GEN, WC_NONE,
WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_STICKY_BUTTON,
_terraform_widgets,
- TerraformToolbWndProc
};
void ShowTerraformToolbar(Window *link)
{
if (!IsValidPlayer(_current_player)) return;
- Window *w = AllocateWindowDescFront<Window>(&_terraform_desc, 0);
+ Window *w = AllocateWindowDescFront<TerraformToolbarWindow>(&_terraform_desc, 0);
if (w != NULL && link != NULL) {
/* Align the terraform toolbar under the main toolbar and put the linked
* toolbar to left of it
@@ -339,8 +346,6 @@
int sizex, sizey;
uint h;
- _generating_world = true; // used to create green terraformed land
-
if (_terraform_size == 1) {
StringID msg =
mode ? STR_0808_CAN_T_RAISE_LAND_HERE : STR_0809_CAN_T_LOWER_LAND_HERE;
@@ -376,8 +381,6 @@
}
} END_TILE_LOOP(tile2, sizex, sizey, tile)
}
-
- _generating_world = false;
}
static void PlaceProc_RaiseBigLand(TileIndex tile)
@@ -569,122 +572,128 @@
}
}
-static void ScenEditLandGenWndProc(Window *w, WindowEvent *e)
-{
- switch (e->event) {
- case WE_CREATE:
- /* XXX - lighthouse button is widget 11!! Don't forget when changing */
- w->widget[11].tooltips = (_opt.landscape == LT_TROPIC) ? STR_028F_DEFINE_DESERT_AREA : STR_028D_PLACE_LIGHTHOUSE;
- break;
-
- case WE_PAINT: {
- DrawWindowWidgets(w);
-
- int n = _terraform_size * _terraform_size;
- const int8 *coords = &_multi_terraform_coords[0][0];
-
- assert(n != 0);
- do {
- DrawSprite(SPR_WHITE_POINT, PAL_NONE, 88 + coords[0], 55 + coords[1]);
- coords += 2;
- } while (--n);
-
- if (w->IsWidgetLowered(5) || w->IsWidgetLowered(6)) // change area-size if raise/lower corner is selected
- SetTileSelectSize(_terraform_size, _terraform_size);
-
- } break;
+struct ScenarioEditorLandscapeGenerationWindow : Window {
+ ScenarioEditorLandscapeGenerationWindow(const WindowDesc *desc, WindowNumber window_number) : Window(desc, window_number)
+ {
+ /* XXX - lighthouse button is widget 11!! Don't forget when changing */
+ this->widget[11].tooltips = (_opt.landscape == LT_TROPIC) ? STR_028F_DEFINE_DESERT_AREA : STR_028D_PLACE_LIGHTHOUSE;
+ this->FindWindowPlacementAndResize(desc);
+ }
- case WE_KEYPRESS:
- for (uint i = 0; i != lengthof(_editor_terraform_keycodes); i++) {
- if (e->we.keypress.keycode == _editor_terraform_keycodes[i]) {
- e->we.keypress.cont = false;
- _editor_terraform_button_proc[i](w);
- break;
- }
- }
- break;
+ virtual void OnPaint() {
+ this->DrawWidgets();
- case WE_CLICK:
- switch (e->we.click.widget) {
- case 4: case 5: case 6: case 7: case 8: case 9: case 10: case 11: case 12:
- _editor_terraform_button_proc[e->we.click.widget - 4](w);
- break;
- case 13: case 14: { // Increase/Decrease terraform size
- int size = (e->we.click.widget == 13) ? 1 : -1;
- w->HandleButtonClick(e->we.click.widget);
- size += _terraform_size;
-
- if (!IsInsideMM(size, 1, 8 + 1)) return;
- _terraform_size = size;
+ int n = _terraform_size * _terraform_size;
+ const int8 *coords = &_multi_terraform_coords[0][0];
- SndPlayFx(SND_15_BEEP);
- w->SetDirty();
- } break;
- case 15: // gen random land
- w->HandleButtonClick(15);
- ShowCreateScenario();
- break;
- case 16: // Reset landscape
- ShowQuery(
- STR_022C_RESET_LANDSCAPE,
- STR_RESET_LANDSCAPE_CONFIRMATION_TEXT,
- NULL,
- ResetLandscapeConfirmationCallback);
+ assert(n != 0);
+ do {
+ DrawSprite(SPR_WHITE_POINT, PAL_NONE, 88 + coords[0], 55 + coords[1]);
+ coords += 2;
+ } while (--n);
+
+ if (this->IsWidgetLowered(5) || this->IsWidgetLowered(6)) { // change area-size if raise/lower corner is selected
+ SetTileSelectSize(_terraform_size, _terraform_size);
+ }
+ }
+
+ virtual EventState OnKeyPress(uint16 key, uint16 keycode)
+ {
+ for (uint i = 0; i != lengthof(_editor_terraform_keycodes); i++) {
+ if (keycode == _editor_terraform_keycodes[i]) {
+ _editor_terraform_button_proc[i](this);
+ return ES_HANDLED;
+ }
+ }
+ return ES_NOT_HANDLED;
+ }
+
+ virtual void OnClick(Point pt, int widget)
+ {
+ switch (widget) {
+ case 4: case 5: case 6: case 7: case 8: case 9: case 10: case 11: case 12:
+ _editor_terraform_button_proc[widget - 4](this);
+ break;
+ case 13: case 14: { // Increase/Decrease terraform size
+ int size = (widget == 13) ? 1 : -1;
+ this->HandleButtonClick(widget);
+ size += _terraform_size;
+
+ if (!IsInsideMM(size, 1, 8 + 1)) return;
+ _terraform_size = size;
+
+ SndPlayFx(SND_15_BEEP);
+ this->SetDirty();
+ } break;
+ case 15: // gen random land
+ this->HandleButtonClick(15);
+ ShowCreateScenario();
+ break;
+ case 16: // Reset landscape
+ ShowQuery(
+ STR_022C_RESET_LANDSCAPE,
+ STR_RESET_LANDSCAPE_CONFIRMATION_TEXT,
+ NULL,
+ ResetLandscapeConfirmationCallback);
+ break;
+ }
+ }
+
+ virtual void OnTimeout()
+ {
+ for (uint i = 0; i < this->widget_count; i++) {
+ if (this->IsWidgetLowered(i)) {
+ this->RaiseWidget(i);
+ this->InvalidateWidget(i);
+ }
+ if (i == 3) i = 12;
+ }
+ }
+
+ virtual void OnPlaceObject(Point pt, TileIndex tile)
+ {
+ _place_proc(tile);
+ }
+
+ virtual void OnPlaceDrag(ViewportPlaceMethod select_method, ViewportDragDropSelectionProcess select_proc, Point pt)
+ {
+ VpSelectTilesWithMethod(pt.x, pt.y, select_method);
+ }
+
+ virtual void OnPlaceMouseUp(ViewportPlaceMethod select_method, ViewportDragDropSelectionProcess select_proc, Point pt, TileIndex start_tile, TileIndex end_tile)
+ {
+ if (pt.x != -1) {
+ switch (select_proc) {
+ default: NOT_REACHED();
+ case DDSP_CREATE_ROCKS:
+ case DDSP_CREATE_DESERT:
+ case DDSP_CREATE_WATER:
+ case DDSP_CREATE_RIVER:
+ case DDSP_RAISE_AND_LEVEL_AREA:
+ case DDSP_LOWER_AND_LEVEL_AREA:
+ case DDSP_LEVEL_AREA:
+ case DDSP_DEMOLISH_AREA:
+ GUIPlaceProcDragXY(select_proc, start_tile, end_tile);
break;
}
- break;
-
- case WE_TIMEOUT:
- for (uint i = 0; i < w->widget_count; i++) {
- if (w->IsWidgetLowered(i)) {
- w->RaiseWidget(i);
- w->InvalidateWidget(i);
- }
- if (i == 3) i = 12;
- }
- break;
-
- case WE_PLACE_OBJ:
- _place_proc(e->we.place.tile);
- break;
-
- case WE_PLACE_DRAG:
- VpSelectTilesWithMethod(e->we.place.pt.x, e->we.place.pt.y, e->we.place.select_method);
- break;
+ }
+ }
- case WE_PLACE_MOUSEUP:
- if (e->we.place.pt.x != -1) {
- switch (e->we.place.select_proc) {
- case DDSP_CREATE_ROCKS:
- case DDSP_CREATE_DESERT:
- case DDSP_CREATE_WATER:
- case DDSP_CREATE_RIVER:
- case DDSP_RAISE_AND_LEVEL_AREA:
- case DDSP_LOWER_AND_LEVEL_AREA:
- case DDSP_LEVEL_AREA:
- case DDSP_DEMOLISH_AREA:
- GUIPlaceProcDragXY(e);
- break;
- }
- }
- break;
-
- case WE_ABORT_PLACE_OBJ:
- w->RaiseButtons();
- w->SetDirty();
- break;
+ virtual void OnPlaceObjectAbort()
+ {
+ this->RaiseButtons();
+ this->SetDirty();
}
-}
+};
static const WindowDesc _scen_edit_land_gen_desc = {
WDP_AUTO, WDP_AUTO, 204, 103, 204, 103,
WC_SCEN_LAND_GEN, WC_NONE,
WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_STICKY_BUTTON,
_scen_edit_land_gen_widgets,
- ScenEditLandGenWndProc,
};
void ShowEditorTerraformToolbar()
{
- AllocateWindowDescFront<Window>(&_scen_edit_land_gen_desc, 0);
+ AllocateWindowDescFront<ScenarioEditorLandscapeGenerationWindow>(&_scen_edit_land_gen_desc, 0);
}
--- a/src/tilehighlight_func.h Mon May 19 14:14:33 2008 +0000
+++ b/src/tilehighlight_func.h Mon May 19 15:13:58 2008 +0000
@@ -12,7 +12,7 @@
typedef void PlaceProc(TileIndex tile);
void PlaceProc_DemolishArea(TileIndex tile);
-bool GUIPlaceProcDragXY(const WindowEvent *e);
+bool GUIPlaceProcDragXY(ViewportDragDropSelectionProcess proc, TileIndex start_tile, TileIndex end_tile);
bool HandlePlacePushButton(Window *w, int widget, CursorID cursor, ViewportHighlightMode mode, PlaceProc *placeproc);
void SetObjectToPlaceWnd(CursorID icon, SpriteID pal, ViewportHighlightMode mode, Window *w);
--- a/src/timetable_gui.cpp Mon May 19 14:14:33 2008 +0000
+++ b/src/timetable_gui.cpp Mon May 19 15:13:58 2008 +0000
@@ -36,27 +36,6 @@
TTV_RESIZE,
};
-struct timetable_d {
- int sel;
-};
-assert_compile(WINDOW_CUSTOM_SIZE >= sizeof(timetable_d));
-
-static int GetOrderFromTimetableWndPt(Window *w, int y, const Vehicle *v)
-{
- /*
- * Calculation description:
- * 15 = 14 (w->widget[TTV_ORDER_VIEW].top) + 1 (frame-line)
- * 10 = order text hight
- */
- int sel = (y - 15) / 10;
-
- if ((uint)sel >= w->vscroll.cap) return INVALID_ORDER;
-
- sel += w->vscroll.pos;
-
- return (sel <= v->num_orders * 2 && sel >= 0) ? sel : INVALID_ORDER;
-}
-
void SetTimetableParams(int param1, int param2, uint32 time)
{
if (_patches.timetable_in_ticks) {
@@ -68,208 +47,229 @@
}
}
-static void DrawTimetableWindow(Window *w)
-{
- const Vehicle *v = GetVehicle(w->window_number);
- int selected = WP(w, timetable_d).sel;
-
- SetVScrollCount(w, v->num_orders * 2);
+struct TimetableWindow : Window {
+ int sel_index;
- if (v->owner == _local_player) {
- if (selected == -1) {
- w->DisableWidget(TTV_CHANGE_TIME);
- w->DisableWidget(TTV_CLEAR_TIME);
- } else if (selected % 2 == 1) {
- w->EnableWidget(TTV_CHANGE_TIME);
- w->EnableWidget(TTV_CLEAR_TIME);
- } else {
- const Order *order = GetVehicleOrder(v, (selected + 1) / 2);
- bool disable = order == NULL || !order->IsType(OT_GOTO_STATION) || (order->GetNonStopType() & ONSF_NO_STOP_AT_DESTINATION_STATION);
-
- w->SetWidgetDisabledState(TTV_CHANGE_TIME, disable);
- w->SetWidgetDisabledState(TTV_CLEAR_TIME, disable);
- }
-
- w->EnableWidget(TTV_RESET_LATENESS);
- w->EnableWidget(TTV_AUTOFILL);
- } else {
- w->DisableWidget(TTV_CHANGE_TIME);
- w->DisableWidget(TTV_CLEAR_TIME);
- w->DisableWidget(TTV_RESET_LATENESS);
- w->DisableWidget(TTV_AUTOFILL);
+ TimetableWindow(const WindowDesc *desc, WindowNumber window_number) : Window(desc, window_number)
+ {
+ this->caption_color = GetVehicle(window_number)->owner;
+ this->vscroll.cap = 8;
+ this->resize.step_height = 10;
+ this->sel_index = -1;
}
- w->SetWidgetLoweredState(TTV_AUTOFILL, HasBit(v->vehicle_flags, VF_AUTOFILL_TIMETABLE));
-
- SetDParam(0, v->index);
- DrawWindowWidgets(w);
-
- int y = 15;
- int i = w->vscroll.pos;
- VehicleOrderID order_id = (i + 1) / 2;
- bool final_order = false;
-
- const Order *order = GetVehicleOrder(v, order_id);
-
- while (order != NULL) {
- /* Don't draw anything if it extends past the end of the window. */
- if (i - w->vscroll.pos >= w->vscroll.cap) break;
+ int GetOrderFromTimetableWndPt(int y, const Vehicle *v)
+ {
+ /*
+ * Calculation description:
+ * 15 = 14 (this->widget[TTV_ORDER_VIEW].top) + 1 (frame-line)
+ * 10 = order text hight
+ */
+ int sel = (y - 15) / 10;
- if (i % 2 == 0) {
- DrawOrderString(v, order, order_id, y, i == selected, true);
+ if ((uint)sel >= this->vscroll.cap) return INVALID_ORDER;
- order_id++;
+ sel += this->vscroll.pos;
- if (order_id >= v->num_orders) {
- order = GetVehicleOrder(v, 0);
- final_order = true;
+ return (sel <= v->num_orders * 2 && sel >= 0) ? sel : INVALID_ORDER;
+ }
+
+ void OnPaint()
+ {
+ const Vehicle *v = GetVehicle(this->window_number);
+ int selected = this->sel_index;
+
+ SetVScrollCount(this, v->num_orders * 2);
+
+ if (v->owner == _local_player) {
+ if (selected == -1) {
+ this->DisableWidget(TTV_CHANGE_TIME);
+ this->DisableWidget(TTV_CLEAR_TIME);
+ } else if (selected % 2 == 1) {
+ this->EnableWidget(TTV_CHANGE_TIME);
+ this->EnableWidget(TTV_CLEAR_TIME);
} else {
- order = order->next;
- }
- } else {
- StringID string;
+ const Order *order = GetVehicleOrder(v, (selected + 1) / 2);
+ bool disable = order == NULL || !order->IsType(OT_GOTO_STATION) || (order->GetNonStopType() & ONSF_NO_STOP_AT_DESTINATION_STATION);
- if (order->travel_time == 0) {
- string = STR_TIMETABLE_TRAVEL_NOT_TIMETABLED;
- } else {
- SetTimetableParams(0, 1, order->travel_time);
- string = STR_TIMETABLE_TRAVEL_FOR;
+ this->SetWidgetDisabledState(TTV_CHANGE_TIME, disable);
+ this->SetWidgetDisabledState(TTV_CLEAR_TIME, disable);
}
- DrawString(22, y, string, (i == selected) ? TC_WHITE : TC_BLACK);
-
- if (final_order) break;
+ this->EnableWidget(TTV_RESET_LATENESS);
+ this->EnableWidget(TTV_AUTOFILL);
+ } else {
+ this->DisableWidget(TTV_CHANGE_TIME);
+ this->DisableWidget(TTV_CLEAR_TIME);
+ this->DisableWidget(TTV_RESET_LATENESS);
+ this->DisableWidget(TTV_AUTOFILL);
}
- i++;
- y += 10;
- }
-
- y = w->widget[TTV_SUMMARY_PANEL].top + 1;
+ this->SetWidgetLoweredState(TTV_AUTOFILL, HasBit(v->vehicle_flags, VF_AUTOFILL_TIMETABLE));
- {
- uint total_time = 0;
- bool complete = true;
+ SetDParam(0, v->index);
+ this->DrawWidgets();
- for (const Order *order = GetVehicleOrder(v, 0); order != NULL; order = order->next) {
- total_time += order->travel_time + order->wait_time;
- if (order->travel_time == 0) complete = false;
- if (order->wait_time == 0 && order->IsType(OT_GOTO_STATION) && !(order->GetNonStopType() & ONSF_NO_STOP_AT_DESTINATION_STATION)) complete = false;
+ int y = 15;
+ int i = this->vscroll.pos;
+ VehicleOrderID order_id = (i + 1) / 2;
+ bool final_order = false;
+
+ const Order *order = GetVehicleOrder(v, order_id);
+
+ while (order != NULL) {
+ /* Don't draw anything if it extends past the end of the window. */
+ if (i - this->vscroll.pos >= this->vscroll.cap) break;
+
+ if (i % 2 == 0) {
+ DrawOrderString(v, order, order_id, y, i == selected, true);
+
+ order_id++;
+
+ if (order_id >= v->num_orders) {
+ order = GetVehicleOrder(v, 0);
+ final_order = true;
+ } else {
+ order = order->next;
+ }
+ } else {
+ StringID string;
+
+ if (order->travel_time == 0) {
+ string = STR_TIMETABLE_TRAVEL_NOT_TIMETABLED;
+ } else {
+ SetTimetableParams(0, 1, order->travel_time);
+ string = STR_TIMETABLE_TRAVEL_FOR;
+ }
+
+ DrawString(22, y, string, (i == selected) ? TC_WHITE : TC_BLACK);
+
+ if (final_order) break;
+ }
+
+ i++;
+ y += 10;
}
- if (total_time != 0) {
- SetTimetableParams(0, 1, total_time);
- DrawString(2, y, complete ? STR_TIMETABLE_TOTAL_TIME : STR_TIMETABLE_TOTAL_TIME_INCOMPLETE, TC_BLACK);
+ y = this->widget[TTV_SUMMARY_PANEL].top + 1;
+
+ {
+ uint total_time = 0;
+ bool complete = true;
+
+ for (const Order *order = GetVehicleOrder(v, 0); order != NULL; order = order->next) {
+ total_time += order->travel_time + order->wait_time;
+ if (order->travel_time == 0) complete = false;
+ if (order->wait_time == 0 && order->IsType(OT_GOTO_STATION) && !(order->GetNonStopType() & ONSF_NO_STOP_AT_DESTINATION_STATION)) complete = false;
+ }
+
+ if (total_time != 0) {
+ SetTimetableParams(0, 1, total_time);
+ DrawString(2, y, complete ? STR_TIMETABLE_TOTAL_TIME : STR_TIMETABLE_TOTAL_TIME_INCOMPLETE, TC_BLACK);
+ }
+ }
+ y += 10;
+
+ if (v->lateness_counter == 0 || (!_patches.timetable_in_ticks && v->lateness_counter / DAY_TICKS == 0)) {
+ DrawString(2, y, STR_TIMETABLE_STATUS_ON_TIME, TC_BLACK);
+ } else {
+ SetTimetableParams(0, 1, abs(v->lateness_counter));
+ DrawString(2, y, v->lateness_counter < 0 ? STR_TIMETABLE_STATUS_EARLY : STR_TIMETABLE_STATUS_LATE, TC_BLACK);
}
}
- y += 10;
-
- if (v->lateness_counter == 0 || (!_patches.timetable_in_ticks && v->lateness_counter / DAY_TICKS == 0)) {
- DrawString(2, y, STR_TIMETABLE_STATUS_ON_TIME, TC_BLACK);
- } else {
- SetTimetableParams(0, 1, abs(v->lateness_counter));
- DrawString(2, y, v->lateness_counter < 0 ? STR_TIMETABLE_STATUS_EARLY : STR_TIMETABLE_STATUS_LATE, TC_BLACK);
- }
-}
-
-static inline uint32 PackTimetableArgs(const Vehicle *v, uint selected)
-{
- uint order_number = (selected + 1) / 2;
- uint is_journey = (selected % 2 == 1) ? 1 : 0;
-
- if (order_number >= v->num_orders) order_number = 0;
-
- return v->index | (order_number << 16) | (is_journey << 24);
-}
-
-static void TimetableWndProc(Window *w, WindowEvent *we)
-{
- switch (we->event) {
- case WE_PAINT:
- DrawTimetableWindow(w);
- break;
-
- case WE_CLICK: {
- const Vehicle *v = GetVehicle(w->window_number);
-
- switch (we->we.click.widget) {
- case TTV_ORDER_VIEW: /* Order view button */
- ShowOrdersWindow(v);
- break;
-
- case TTV_TIMETABLE_PANEL: { /* Main panel. */
- int selected = GetOrderFromTimetableWndPt(w, we->we.click.pt.y, v);
-
- if (selected == INVALID_ORDER || selected == WP(w, timetable_d).sel) {
- /* Deselect clicked order */
- WP(w, timetable_d).sel = -1;
- } else {
- /* Select clicked order */
- WP(w, timetable_d).sel = selected;
- }
- } break;
-
- case TTV_CHANGE_TIME: { /* "Wait For" button. */
- int selected = WP(w, timetable_d).sel;
- VehicleOrderID real = (selected + 1) / 2;
-
- if (real >= v->num_orders) real = 0;
- const Order *order = GetVehicleOrder(v, real);
- StringID current = STR_EMPTY;
-
- if (order != NULL) {
- uint time = (selected % 2 == 1) ? order->travel_time : order->wait_time;
- if (!_patches.timetable_in_ticks) time /= DAY_TICKS;
-
- if (time != 0) {
- SetDParam(0, time);
- current = STR_CONFIG_PATCHES_INT32;
- }
- }
-
- ShowQueryString(current, STR_TIMETABLE_CHANGE_TIME, 31, 150, w, CS_NUMERAL);
- } break;
-
- case TTV_CLEAR_TIME: { /* Clear waiting time button. */
- uint32 p1 = PackTimetableArgs(v, WP(w, timetable_d).sel);
- DoCommandP(0, p1, 0, NULL, CMD_CHANGE_TIMETABLE | CMD_MSG(STR_CAN_T_TIMETABLE_VEHICLE));
- } break;
-
- case TTV_RESET_LATENESS: /* Reset the vehicle's late counter. */
- DoCommandP(0, v->index, 0, NULL, CMD_SET_VEHICLE_ON_TIME | CMD_MSG(STR_CAN_T_TIMETABLE_VEHICLE));
- break;
+ static inline uint32 PackTimetableArgs(const Vehicle *v, uint selected)
+ {
+ uint order_number = (selected + 1) / 2;
+ uint is_journey = (selected % 2 == 1) ? 1 : 0;
- case TTV_AUTOFILL: /* Autofill the timetable. */
- DoCommandP(0, v->index, HasBit(v->vehicle_flags, VF_AUTOFILL_TIMETABLE) ? 0 : 1, NULL, CMD_AUTOFILL_TIMETABLE | CMD_MSG(STR_CAN_T_TIMETABLE_VEHICLE));
- break;
- }
-
- w->SetDirty();
- } break;
-
- case WE_ON_EDIT_TEXT: {
- if (we->we.edittext.str == NULL) break;
-
- const Vehicle *v = GetVehicle(w->window_number);
-
- uint32 p1 = PackTimetableArgs(v, WP(w, timetable_d).sel);
+ if (order_number >= v->num_orders) order_number = 0;
- uint64 time = StrEmpty(we->we.edittext.str) ? 0 : strtoul(we->we.edittext.str, NULL, 10);
- if (!_patches.timetable_in_ticks) time *= DAY_TICKS;
-
- uint32 p2 = minu(time, MAX_UVALUE(uint16));
+ return v->index | (order_number << 16) | (is_journey << 24);
+ }
- DoCommandP(0, p1, p2, NULL, CMD_CHANGE_TIMETABLE | CMD_MSG(STR_CAN_T_TIMETABLE_VEHICLE));
- } break;
+ virtual void OnClick(Point pt, int widget)
+ {
+ const Vehicle *v = GetVehicle(this->window_number);
- case WE_RESIZE:
- /* Update the scroll + matrix */
- w->vscroll.cap = (w->widget[TTV_TIMETABLE_PANEL].bottom - w->widget[TTV_TIMETABLE_PANEL].top) / 10;
- break;
+ switch (widget) {
+ case TTV_ORDER_VIEW: /* Order view button */
+ ShowOrdersWindow(v);
+ break;
+ case TTV_TIMETABLE_PANEL: { /* Main panel. */
+ int selected = GetOrderFromTimetableWndPt(pt.y, v);
+
+ if (selected == INVALID_ORDER || selected == this->sel_index) {
+ /* Deselect clicked order */
+ this->sel_index = -1;
+ } else {
+ /* Select clicked order */
+ this->sel_index = selected;
+ }
+ } break;
+
+ case TTV_CHANGE_TIME: { /* "Wait For" button. */
+ int selected = this->sel_index;
+ VehicleOrderID real = (selected + 1) / 2;
+
+ if (real >= v->num_orders) real = 0;
+
+ const Order *order = GetVehicleOrder(v, real);
+ StringID current = STR_EMPTY;
+
+ if (order != NULL) {
+ uint time = (selected % 2 == 1) ? order->travel_time : order->wait_time;
+ if (!_patches.timetable_in_ticks) time /= DAY_TICKS;
+
+ if (time != 0) {
+ SetDParam(0, time);
+ current = STR_CONFIG_PATCHES_INT32;
+ }
+ }
+
+ ShowQueryString(current, STR_TIMETABLE_CHANGE_TIME, 31, 150, this, CS_NUMERAL);
+ } break;
+
+ case TTV_CLEAR_TIME: { /* Clear waiting time button. */
+ uint32 p1 = PackTimetableArgs(v, this->sel_index);
+ DoCommandP(0, p1, 0, NULL, CMD_CHANGE_TIMETABLE | CMD_MSG(STR_CAN_T_TIMETABLE_VEHICLE));
+ } break;
+
+ case TTV_RESET_LATENESS: /* Reset the vehicle's late counter. */
+ DoCommandP(0, v->index, 0, NULL, CMD_SET_VEHICLE_ON_TIME | CMD_MSG(STR_CAN_T_TIMETABLE_VEHICLE));
+ break;
+
+ case TTV_AUTOFILL: /* Autofill the timetable. */
+ DoCommandP(0, v->index, HasBit(v->vehicle_flags, VF_AUTOFILL_TIMETABLE) ? 0 : 1, NULL, CMD_AUTOFILL_TIMETABLE | CMD_MSG(STR_CAN_T_TIMETABLE_VEHICLE));
+ break;
+ }
+
+ this->SetDirty();
}
-}
+
+ virtual void OnQueryTextFinished(char *str)
+ {
+ if (str == NULL) return;
+
+ const Vehicle *v = GetVehicle(this->window_number);
+
+ uint32 p1 = PackTimetableArgs(v, this->sel_index);
+
+ uint64 time = StrEmpty(str) ? 0 : strtoul(str, NULL, 10);
+ if (!_patches.timetable_in_ticks) time *= DAY_TICKS;
+
+ uint32 p2 = minu(time, MAX_UVALUE(uint16));
+
+ DoCommandP(0, p1, p2, NULL, CMD_CHANGE_TIMETABLE | CMD_MSG(STR_CAN_T_TIMETABLE_VEHICLE));
+ }
+
+ virtual void OnResize(Point new_size, Point delta)
+ {
+ /* Update the scroll + matrix */
+ this->vscroll.cap = (this->widget[TTV_TIMETABLE_PANEL].bottom - this->widget[TTV_TIMETABLE_PANEL].top) / 10;
+ }
+};
static const Widget _timetable_widgets[] = {
{ WWT_CLOSEBOX, RESIZE_NONE, 14, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW}, // TTV_WIDGET_CLOSEBOX
@@ -298,17 +298,9 @@
WC_VEHICLE_TIMETABLE, WC_VEHICLE_VIEW,
WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS | WDF_STICKY_BUTTON | WDF_RESIZABLE,
_timetable_widgets,
- TimetableWndProc
};
void ShowTimetableWindow(const Vehicle *v)
{
- Window *w = AllocateWindowDescFront<Window>(&_timetable_desc, v->index);
-
- if (w != NULL) {
- w->caption_color = v->owner;
- w->vscroll.cap = 8;
- w->resize.step_height = 10;
- WP(w, timetable_d).sel = -1;
- }
+ AllocateWindowDescFront<TimetableWindow>(&_timetable_desc, v->index);
}
--- a/src/toolbar_gui.cpp Mon May 19 14:14:33 2008 +0000
+++ b/src/toolbar_gui.cpp Mon May 19 15:13:58 2008 +0000
@@ -46,8 +46,8 @@
#include "table/strings.h"
#include "table/sprites.h"
-static Window *PopupMainToolbMenu(Window *w, uint16 parent_button, StringID base_string, byte item_count, byte disabled_mask);
-static Window *PopupMainPlayerToolbMenu(Window *w, int main_button, int gray);
+static void PopupMainToolbMenu(Window *parent, uint16 parent_button, StringID base_string, byte item_count, byte disabled_mask = 0, int sel_index = 0, int checked_items = 0);
+static void PopupMainPlayerToolbMenu(Window *parent, int main_button, int gray);
RailType _last_built_railtype;
RoadType _last_built_roadtype;
@@ -79,13 +79,13 @@
}
/**
- * In a window with menu_d custom extension, retrieve the menu item number from a position
+ * Retrieve the menu item number from a position
* @param w Window holding the menu items
* @param x X coordinate of the position
* @param y Y coordinate of the position
* @return Index number of the menu item, or \c -1 if no valid selection under position
*/
-static int GetMenuItemIndex(const Window *w)
+static int GetMenuItemIndex(const Window *w, int item_count, int disabled_items)
{
int x = _cursor.pos.x;
int y = _cursor.pos.y;
@@ -93,8 +93,8 @@
if ((x -= w->left) >= 0 && x < w->width && (y -= w->top + 1) >= 0) {
y /= 10;
- if (y < WP(w, const menu_d).item_count &&
- !HasBit(WP(w, const menu_d).disabled_items, y)) {
+ if (y < item_count &&
+ !HasBit(disabled_items, y)) {
return y;
}
}
@@ -123,9 +123,6 @@
static void ToolbarOptionsClick(Window *w)
{
uint16 x = 0;
-
- w = PopupMainToolbMenu(w, 2, STR_02C4_GAME_OPTIONS, 14, 0);
-
if (HasBit(_display_opt, DO_SHOW_TOWN_NAMES)) SetBit(x, 6);
if (HasBit(_display_opt, DO_SHOW_STATION_NAMES)) SetBit(x, 7);
if (HasBit(_display_opt, DO_SHOW_SIGNS)) SetBit(x, 8);
@@ -134,7 +131,8 @@
if (HasBit(_display_opt, DO_FULL_DETAIL)) SetBit(x, 11);
if (IsTransparencySet(TO_HOUSES)) SetBit(x, 12);
if (IsTransparencySet(TO_SIGNS)) SetBit(x, 13);
- WP(w, menu_d).checked_items = x;
+
+ PopupMainToolbMenu(w, 2, STR_02C4_GAME_OPTIONS, 14, 0, 0, x);
}
static void MenuClickSettings(int index)
@@ -162,12 +160,12 @@
static void ToolbarSaveClick(Window *w)
{
- PopupMainToolbMenu(w, 3, STR_015C_SAVE_GAME, 4, 0);
+ PopupMainToolbMenu(w, 3, STR_015C_SAVE_GAME, 4);
}
static void ToolbarScenSaveOrLoad(Window *w)
{
- PopupMainToolbMenu(w, 3, STR_0292_SAVE_SCENARIO, 6, 0);
+ PopupMainToolbMenu(w, 3, STR_0292_SAVE_SCENARIO, 6);
}
static void MenuClickSaveLoad(int index)
@@ -194,7 +192,7 @@
static void ToolbarMapClick(Window *w)
{
- PopupMainToolbMenu(w, 4, STR_02DE_MAP_OF_WORLD, 3, 0);
+ PopupMainToolbMenu(w, 4, STR_02DE_MAP_OF_WORLD, 3);
}
static void MenuClickMap(int index)
@@ -220,7 +218,7 @@
static void ToolbarTownClick(Window *w)
{
- PopupMainToolbMenu(w, 5, STR_02BB_TOWN_DIRECTORY, 1, 0);
+ PopupMainToolbMenu(w, 5, STR_02BB_TOWN_DIRECTORY, 1);
}
static void MenuClickTown(int index)
@@ -232,7 +230,7 @@
static void ToolbarSubsidiesClick(Window *w)
{
- PopupMainToolbMenu(w, 6, STR_02DD_SUBSIDIES, 1, 0);
+ PopupMainToolbMenu(w, 6, STR_02DD_SUBSIDIES, 1);
}
static void MenuClickSubsidies(int index)
@@ -285,7 +283,7 @@
static void ToolbarGraphsClick(Window *w)
{
- PopupMainToolbMenu(w, 10, STR_0154_OPERATING_PROFIT_GRAPH, 6, 0);
+ PopupMainToolbMenu(w, 10, STR_0154_OPERATING_PROFIT_GRAPH, 6);
}
static void MenuClickGraphs(int index)
@@ -304,7 +302,7 @@
static void ToolbarLeagueClick(Window *w)
{
- PopupMainToolbMenu(w, 11, STR_015A_COMPANY_LEAGUE_TABLE, 2, 0);
+ PopupMainToolbMenu(w, 11, STR_015A_COMPANY_LEAGUE_TABLE, 2);
}
static void MenuClickLeague(int index)
@@ -416,8 +414,7 @@
static void ToolbarBuildRailClick(Window *w)
{
const Player *p = GetPlayer(_local_player);
- Window *w2 = PopupMainToolbMenu(w, 19, STR_1015_RAILROAD_CONSTRUCTION, RAILTYPE_END, ~p->avail_railtypes);
- WP(w2, menu_d).sel_index = _last_built_railtype;
+ PopupMainToolbMenu(w, 19, STR_1015_RAILROAD_CONSTRUCTION, RAILTYPE_END, ~p->avail_railtypes, _last_built_railtype);
}
static void MenuClickBuildRail(int index)
@@ -432,8 +429,7 @@
{
const Player *p = GetPlayer(_local_player);
/* The standard road button is *always* available */
- Window *w2 = PopupMainToolbMenu(w, 20, STR_180A_ROAD_CONSTRUCTION, 2, ~(p->avail_roadtypes | ROADTYPES_ROAD));
- WP(w2, menu_d).sel_index = _last_built_roadtype;
+ PopupMainToolbMenu(w, 20, STR_180A_ROAD_CONSTRUCTION, 2, ~(p->avail_roadtypes | ROADTYPES_ROAD), _last_built_roadtype);
}
static void MenuClickBuildRoad(int index)
@@ -446,7 +442,7 @@
static void ToolbarBuildWaterClick(Window *w)
{
- PopupMainToolbMenu(w, 21, STR_9800_DOCK_CONSTRUCTION, 1, 0);
+ PopupMainToolbMenu(w, 21, STR_9800_DOCK_CONSTRUCTION, 1);
}
static void MenuClickBuildWater(int index)
@@ -458,7 +454,7 @@
static void ToolbarBuildAirClick(Window *w)
{
- PopupMainToolbMenu(w, 22, STR_A01D_AIRPORT_CONSTRUCTION, 1, 0);
+ PopupMainToolbMenu(w, 22, STR_A01D_AIRPORT_CONSTRUCTION, 1);
}
static void MenuClickBuildAir(int index)
@@ -470,7 +466,7 @@
static void ToolbarForestClick(Window *w)
{
- PopupMainToolbMenu(w, 23, STR_LANDSCAPING, 3, 0);
+ PopupMainToolbMenu(w, 23, STR_LANDSCAPING, 3);
}
static void MenuClickForest(int index)
@@ -486,7 +482,7 @@
static void ToolbarMusicClick(Window *w)
{
- PopupMainToolbMenu(w, 24, STR_01D3_SOUND_MUSIC, 1, 0);
+ PopupMainToolbMenu(w, 24, STR_01D3_SOUND_MUSIC, 1);
}
static void MenuClickMusicWindow(int index)
@@ -498,7 +494,7 @@
static void ToolbarNewspaperClick(Window *w)
{
- PopupMainToolbMenu(w, 25, STR_0200_LAST_MESSAGE_NEWS_REPORT, 3, 0);
+ PopupMainToolbMenu(w, 25, STR_0200_LAST_MESSAGE_NEWS_REPORT, 3);
}
static void MenuClickNewspaper(int index)
@@ -514,7 +510,7 @@
static void ToolbarHelpClick(Window *w)
{
- PopupMainToolbMenu(w, 26, STR_02D5_LAND_BLOCK_INFO, 7, 0);
+ PopupMainToolbMenu(w, 26, STR_02D5_LAND_BLOCK_INFO, 7);
}
static void MenuClickSmallScreenshot()
@@ -570,7 +566,7 @@
static void ToolbarScenMapTownDir(Window *w)
{
/* Scenario editor button, *hack*hack* use different button to activate */
- PopupMainToolbMenu(w, 8 | (17 << 8), STR_02DE_MAP_OF_WORLD, 4, 0);
+ PopupMainToolbMenu(w, 8 | (17 << 8), STR_02DE_MAP_OF_WORLD, 4);
}
static void ToolbarScenZoomIn(Window *w)
@@ -623,7 +619,7 @@
{
w->HandleButtonClick(15);
SndPlayFx(SND_15_BEEP);
- ShowBuildTreesScenToolbar();
+ ShowBuildTreesToolbar();
}
static void ToolbarScenPlaceSign(Window *w)
@@ -672,137 +668,155 @@
ToolbarHelpClick,
};
-static void MainToolbarWndProc(Window *w, WindowEvent *e)
-{
- switch (e->event) {
- case WE_PAINT:
- /* Draw brown-red toolbar bg. */
- GfxFillRect(0, 0, w->width - 1, w->height - 1, 0xB2);
- GfxFillRect(0, 0, w->width - 1, w->height - 1, 0xB4 | (1 << PALETTE_MODIFIER_GREYOUT));
-
- /* If spectator, disable all construction buttons
- * ie : Build road, rail, ships, airports and landscaping
- * Since enabled state is the default, just disable when needed */
- w->SetWidgetsDisabledState(_current_player == PLAYER_SPECTATOR, 19, 20, 21, 22, 23, WIDGET_LIST_END);
- /* disable company list drop downs, if there are no companies */
- w->SetWidgetsDisabledState(ActivePlayerCount() == 0, 7, 8, 13, 14, 15, 16, WIDGET_LIST_END);
-
- w->SetWidgetDisabledState(19, !CanBuildVehicleInfrastructure(VEH_TRAIN));
- w->SetWidgetDisabledState(22, !CanBuildVehicleInfrastructure(VEH_AIRCRAFT));
-
- DrawWindowWidgets(w);
- break;
-
- case WE_CLICK:
- if (_game_mode != GM_MENU && !w->IsWidgetDisabled(e->we.click.widget)) _toolbar_button_procs[e->we.click.widget](w);
- break;
+struct MainToolbarWindow : Window {
+ MainToolbarWindow(const WindowDesc *desc) : Window(desc)
+ {
+ this->SetWidgetDisabledState(0, _networking && !_network_server); // if not server, disable pause button
+ this->SetWidgetDisabledState(1, _networking); // if networking, disable fast-forward button
- case WE_KEYPRESS:
- switch (e->we.keypress.keycode) {
- case WKC_F1: case WKC_PAUSE: ToolbarPauseClick(w); break;
- case WKC_F2: ShowGameOptions(); break;
- case WKC_F3: MenuClickSaveLoad(0); break;
- case WKC_F4: ShowSmallMap(); break;
- case WKC_F5: ShowTownDirectory(); break;
- case WKC_F6: ShowSubsidiesList(); break;
- case WKC_F7: ShowPlayerStations(_local_player); break;
- case WKC_F8: ShowPlayerFinances(_local_player); break;
- case WKC_F9: ShowPlayerCompany(_local_player); break;
- case WKC_F10: ShowOperatingProfitGraph(); break;
- case WKC_F11: ShowCompanyLeagueTable(); break;
- case WKC_F12: ShowBuildIndustryWindow(); break;
- case WKC_SHIFT | WKC_F1: ShowVehicleListWindow(_local_player, VEH_TRAIN); break;
- case WKC_SHIFT | WKC_F2: ShowVehicleListWindow(_local_player, VEH_ROAD); break;
- case WKC_SHIFT | WKC_F3: ShowVehicleListWindow(_local_player, VEH_SHIP); break;
- case WKC_SHIFT | WKC_F4: ShowVehicleListWindow(_local_player, VEH_AIRCRAFT); break;
- case WKC_NUM_PLUS: // Fall through
- case WKC_EQUALS: // Fall through
- case WKC_SHIFT | WKC_EQUALS: // Fall through
- case WKC_SHIFT | WKC_F5: ToolbarZoomInClick(w); break;
- case WKC_NUM_MINUS: // Fall through
- case WKC_MINUS: // Fall through
- case WKC_SHIFT | WKC_MINUS: // Fall through
- case WKC_SHIFT | WKC_F6: ToolbarZoomOutClick(w); break;
- case WKC_SHIFT | WKC_F7: if (CanBuildVehicleInfrastructure(VEH_TRAIN)) ShowBuildRailToolbar(_last_built_railtype, -1); break;
- case WKC_SHIFT | WKC_F8: ShowBuildRoadToolbar(_last_built_roadtype); break;
- case WKC_SHIFT | WKC_F9: ShowBuildDocksToolbar(); break;
- case WKC_SHIFT | WKC_F10: if (CanBuildVehicleInfrastructure(VEH_AIRCRAFT)) ShowBuildAirToolbar(); break;
- case WKC_SHIFT | WKC_F11: ShowBuildTreesToolbar(); break;
- case WKC_SHIFT | WKC_F12: ShowMusicWindow(); break;
- case WKC_CTRL | 'S': MenuClickSmallScreenshot(); break;
- case WKC_CTRL | 'G': MenuClickWorldScreenshot(); break;
- case WKC_CTRL | WKC_ALT | 'C': if (!_networking) ShowCheatWindow(); break;
- case 'A': if (CanBuildVehicleInfrastructure(VEH_TRAIN)) ShowBuildRailToolbar(_last_built_railtype, 4); break; // Invoke Autorail
- case 'L': ShowTerraformToolbar(); break;
- case 'M': ShowSmallMap(); break;
- case 'V': ShowExtraViewPortWindow(); break;
- default: return;
- }
- e->we.keypress.cont = false;
- break;
+ CLRBITS(this->flags4, WF_WHITE_BORDER_MASK);
- case WE_PLACE_OBJ:
- _place_proc(e->we.place.tile);
- break;
+ this->FindWindowPlacementAndResize(desc);
+ PositionMainToolbar(this);
+ DoZoomInOutWindow(ZOOM_NONE, this);
+ }
- case WE_ABORT_PLACE_OBJ:
- w->RaiseWidget(25);
- w->SetDirty();
- break;
+ virtual void OnPaint()
+ {
+ /* Draw brown-red toolbar bg. */
+ GfxFillRect(0, 0, this->width - 1, this->height - 1, 0xB2);
+ GfxFillRect(0, 0, this->width - 1, this->height - 1, 0xB4 | (1 << PALETTE_MODIFIER_GREYOUT));
- case WE_TICK:
- if (w->IsWidgetLowered(0) != !!_pause_game) {
- w->ToggleWidgetLoweredState(0);
- w->InvalidateWidget(0);
+ /* If spectator, disable all construction buttons
+ * ie : Build road, rail, ships, airports and landscaping
+ * Since enabled state is the default, just disable when needed */
+ this->SetWidgetsDisabledState(_current_player == PLAYER_SPECTATOR, 19, 20, 21, 22, 23, WIDGET_LIST_END);
+ /* disable company list drop downs, if there are no companies */
+ this->SetWidgetsDisabledState(ActivePlayerCount() == 0, 7, 8, 13, 14, 15, 16, WIDGET_LIST_END);
+
+ this->SetWidgetDisabledState(19, !CanBuildVehicleInfrastructure(VEH_TRAIN));
+ this->SetWidgetDisabledState(22, !CanBuildVehicleInfrastructure(VEH_AIRCRAFT));
+
+ this->DrawWidgets();
+ }
+
+ virtual void OnClick(Point pt, int widget)
+ {
+ if (_game_mode != GM_MENU && !this->IsWidgetDisabled(widget)) _toolbar_button_procs[widget](this);
+ }
+
+ virtual EventState OnKeyPress(uint16 key, uint16 keycode)
+ {
+ switch (keycode) {
+ case WKC_F1: case WKC_PAUSE: ToolbarPauseClick(this); break;
+ case WKC_F2: ShowGameOptions(); break;
+ case WKC_F3: MenuClickSaveLoad(0); break;
+ case WKC_F4: ShowSmallMap(); break;
+ case WKC_F5: ShowTownDirectory(); break;
+ case WKC_F6: ShowSubsidiesList(); break;
+ case WKC_F7: ShowPlayerStations(_local_player); break;
+ case WKC_F8: ShowPlayerFinances(_local_player); break;
+ case WKC_F9: ShowPlayerCompany(_local_player); break;
+ case WKC_F10: ShowOperatingProfitGraph(); break;
+ case WKC_F11: ShowCompanyLeagueTable(); break;
+ case WKC_F12: ShowBuildIndustryWindow(); break;
+ case WKC_SHIFT | WKC_F1: ShowVehicleListWindow(_local_player, VEH_TRAIN); break;
+ case WKC_SHIFT | WKC_F2: ShowVehicleListWindow(_local_player, VEH_ROAD); break;
+ case WKC_SHIFT | WKC_F3: ShowVehicleListWindow(_local_player, VEH_SHIP); break;
+ case WKC_SHIFT | WKC_F4: ShowVehicleListWindow(_local_player, VEH_AIRCRAFT); break;
+ case WKC_NUM_PLUS: // Fall through
+ case WKC_EQUALS: // Fall through
+ case WKC_SHIFT | WKC_EQUALS: // Fall through
+ case WKC_SHIFT | WKC_F5: ToolbarZoomInClick(this); break;
+ case WKC_NUM_MINUS: // Fall through
+ case WKC_MINUS: // Fall through
+ case WKC_SHIFT | WKC_MINUS: // Fall through
+ case WKC_SHIFT | WKC_F6: ToolbarZoomOutClick(this); break;
+ case WKC_SHIFT | WKC_F7: if (CanBuildVehicleInfrastructure(VEH_TRAIN)) ShowBuildRailToolbar(_last_built_railtype, -1); break;
+ case WKC_SHIFT | WKC_F8: ShowBuildRoadToolbar(_last_built_roadtype); break;
+ case WKC_SHIFT | WKC_F9: ShowBuildDocksToolbar(); break;
+ case WKC_SHIFT | WKC_F10: if (CanBuildVehicleInfrastructure(VEH_AIRCRAFT)) ShowBuildAirToolbar(); break;
+ case WKC_SHIFT | WKC_F11: ShowBuildTreesToolbar(); break;
+ case WKC_SHIFT | WKC_F12: ShowMusicWindow(); break;
+ case WKC_CTRL | 'S': MenuClickSmallScreenshot(); break;
+ case WKC_CTRL | 'G': MenuClickWorldScreenshot(); break;
+ case WKC_CTRL | WKC_ALT | 'C': if (!_networking) ShowCheatWindow(); break;
+ case 'A': if (CanBuildVehicleInfrastructure(VEH_TRAIN)) ShowBuildRailToolbar(_last_built_railtype, 4); break; // Invoke Autorail
+ case 'L': ShowTerraformToolbar(); break;
+ case 'M': ShowSmallMap(); break;
+ case 'V': ShowExtraViewPortWindow(); break;
+ default: return ES_NOT_HANDLED;
+ }
+ return ES_HANDLED;
+ }
+
+ virtual void OnPlaceObject(Point pt, TileIndex tile)
+ {
+ _place_proc(tile);
+ }
+
+ virtual void OnPlaceObjectAbort()
+ {
+ this->RaiseWidget(25);
+ this->SetDirty();
+ }
+
+ virtual void OnTick()
+ {
+ if (this->IsWidgetLowered(0) != !!_pause_game) {
+ this->ToggleWidgetLoweredState(0);
+ this->InvalidateWidget(0);
+ }
+
+ if (this->IsWidgetLowered(1) != !!_fast_forward) {
+ this->ToggleWidgetLoweredState(1);
+ this->InvalidateWidget(1);
+ }
+ }
+
+ virtual void OnResize(Point new_size, Point delta)
+ {
+ /* There are 27 buttons plus some spacings if the space allows it */
+ uint button_width;
+ uint spacing;
+ if (this->width >= 27 * 22) {
+ button_width = 22;
+ spacing = this->width - (27 * button_width);
+ } else {
+ button_width = this->width / 27;
+ spacing = 0;
+ }
+ uint extra_spacing_at[] = { 4, 8, 13, 17, 19, 24, 0 };
+
+ for (uint i = 0, x = 0, j = 0; i < 27; i++) {
+ if (extra_spacing_at[j] == i) {
+ j++;
+ uint add = spacing / (lengthof(extra_spacing_at) - j);
+ spacing -= add;
+ x += add;
}
- if (w->IsWidgetLowered(1) != !!_fast_forward) {
- w->ToggleWidgetLoweredState(1);
- w->InvalidateWidget(1);
- }
- break;
-
- case WE_RESIZE: {
- /* There are 27 buttons plus some spacings if the space allows it */
- uint button_width;
- uint spacing;
- if (w->width >= 27 * 22) {
- button_width = 22;
- spacing = w->width - (27 * button_width);
- } else {
- button_width = w->width / 27;
- spacing = 0;
- }
- uint extra_spacing_at[] = { 4, 8, 13, 17, 19, 24, 0 };
+ this->widget[i].left = x;
+ x += (spacing != 0) ? button_width : (this->width - x) / (27 - i);
+ this->widget[i].right = x - 1;
+ }
+ }
- for (uint i = 0, x = 0, j = 0; i < 27; i++) {
- if (extra_spacing_at[j] == i) {
- j++;
- uint add = spacing / (lengthof(extra_spacing_at) - j);
- spacing -= add;
- x += add;
- }
-
- w->widget[i].left = x;
- x += (spacing != 0) ? button_width : (w->width - x) / (27 - i);
- w->widget[i].right = x - 1;
+ virtual void OnTimeout()
+ {
+ for (uint i = 2; i < this->widget_count; i++) {
+ if (this->IsWidgetLowered(i)) {
+ this->RaiseWidget(i);
+ this->InvalidateWidget(i);
}
- } break;
+ }
+ }
- case WE_TIMEOUT:
- for (uint i = 2; i < w->widget_count; i++) {
- if (w->IsWidgetLowered(i)) {
- w->RaiseWidget(i);
- w->InvalidateWidget(i);
- }
- }
- break;
-
- case WE_INVALIDATE_DATA:
- if (FindWindowById(WC_MAIN_WINDOW, 0) != NULL) HandleZoomMessage(w, FindWindowById(WC_MAIN_WINDOW, 0)->viewport, 17, 18);
- break;
+ virtual void OnInvalidateData(int data)
+ {
+ if (FindWindowById(WC_MAIN_WINDOW, 0) != NULL) HandleZoomMessage(this, FindWindowById(WC_MAIN_WINDOW, 0)->viewport, 17, 18);
}
-}
+};
static const Widget _toolb_normal_widgets[] = {
{ WWT_IMGBTN, RESIZE_LEFT, 14, 0, 0, 0, 21, SPR_IMG_PAUSE, STR_0171_PAUSE_GAME},
@@ -846,7 +860,6 @@
WC_MAIN_TOOLBAR, WC_NONE,
WDF_STD_TOOLTIPS | WDF_DEF_WIDGET,
_toolb_normal_widgets,
- MainToolbarWndProc
};
@@ -882,163 +895,176 @@
ToolbarHelpClick,
};
-static void ScenEditToolbarWndProc(Window *w, WindowEvent *e)
-{
- switch (e->event) {
- case WE_PAINT:
- w->SetWidgetDisabledState(6, _patches_newgame.starting_year <= MIN_YEAR);
- w->SetWidgetDisabledState(7, _patches_newgame.starting_year >= MAX_YEAR);
+struct ScenarioEditorToolbarWindow : Window {
+ ScenarioEditorToolbarWindow(const WindowDesc *desc) : Window(desc)
+ {
+ CLRBITS(this->flags4, WF_WHITE_BORDER_MASK);
- /* Draw brown-red toolbar bg. */
- GfxFillRect(0, 0, w->width - 1, w->height - 1, 0xB2);
- GfxFillRect(0, 0, w->width - 1, w->height - 1, 0xB4 | (1 << PALETTE_MODIFIER_GREYOUT));
-
- DrawWindowWidgets(w);
+ this->FindWindowPlacementAndResize(desc);
+ PositionMainToolbar(this);
+ DoZoomInOutWindow(ZOOM_NONE, this);
+ }
- SetDParam(0, ConvertYMDToDate(_patches_newgame.starting_year, 0, 1));
- DrawStringCenteredTruncated(w->widget[6].right, w->widget[7].left, 6, STR_00AF, TC_FROMSTRING);
+ virtual void OnPaint()
+ {
+ this->SetWidgetDisabledState(6, _patches_newgame.starting_year <= MIN_YEAR);
+ this->SetWidgetDisabledState(7, _patches_newgame.starting_year >= MAX_YEAR);
- /* We hide this panel when the toolbar space gets too small */
- if (w->widget[4].left != w->widget[4].right) {
- DrawStringCenteredTruncated(w->widget[4].left + 1, w->widget[4].right - 1, 1, STR_0221_OPENTTD, TC_FROMSTRING);
- DrawStringCenteredTruncated(w->widget[4].left + 1, w->widget[4].right - 1, 11, STR_0222_SCENARIO_EDITOR, TC_FROMSTRING);
+ /* Draw brown-red toolbar bg. */
+ GfxFillRect(0, 0, this->width - 1, this->height - 1, 0xB2);
+ GfxFillRect(0, 0, this->width - 1, this->height - 1, 0xB4 | (1 << PALETTE_MODIFIER_GREYOUT));
+
+ this->DrawWidgets();
+
+ SetDParam(0, ConvertYMDToDate(_patches_newgame.starting_year, 0, 1));
+ DrawStringCenteredTruncated(this->widget[6].right, this->widget[7].left, 6, STR_00AF, TC_FROMSTRING);
+
+ /* We hide this panel when the toolbar space gets too small */
+ if (this->widget[4].left != this->widget[4].right) {
+ DrawStringCenteredTruncated(this->widget[4].left + 1, this->widget[4].right - 1, 1, STR_0221_OPENTTD, TC_FROMSTRING);
+ DrawStringCenteredTruncated(this->widget[4].left + 1, this->widget[4].right - 1, 11, STR_0222_SCENARIO_EDITOR, TC_FROMSTRING);
+ }
+ }
+
+ virtual void OnClick(Point pt, int widget)
+ {
+ if (_game_mode == GM_MENU) return;
+ _scen_toolbar_button_procs[widget](this);
+ }
+
+ virtual EventState OnKeyPress(uint16 key, uint16 keycode)
+ {
+ switch (keycode) {
+ case WKC_F1: case WKC_PAUSE: ToolbarPauseClick(this); break;
+ case WKC_F2: ShowGameOptions(); break;
+ case WKC_F3: MenuClickSaveLoad(0); break;
+ case WKC_F4: ToolbarScenGenLand(this); break;
+ case WKC_F5: ToolbarScenGenTown(this); break;
+ case WKC_F6: ToolbarScenGenIndustry(this); break;
+ case WKC_F7: ToolbarScenBuildRoad(this); break;
+ case WKC_F8: ToolbarScenPlantTrees(this); break;
+ case WKC_F9: ToolbarScenPlaceSign(this); break;
+ case WKC_F10: ShowMusicWindow(); break;
+ case WKC_F11: PlaceLandBlockInfo(); break;
+ case WKC_CTRL | 'S': MenuClickSmallScreenshot(); break;
+ case WKC_CTRL | 'G': MenuClickWorldScreenshot(); break;
+
+ /* those following are all fall through */
+ case WKC_NUM_PLUS:
+ case WKC_EQUALS:
+ case WKC_SHIFT | WKC_EQUALS:
+ case WKC_SHIFT | WKC_F5: ToolbarZoomInClick(this); break;
+
+ /* those following are all fall through */
+ case WKC_NUM_MINUS:
+ case WKC_MINUS:
+ case WKC_SHIFT | WKC_MINUS:
+ case WKC_SHIFT | WKC_F6: ToolbarZoomOutClick(this); break;
+
+ case 'L': ShowEditorTerraformToolbar(); break;
+ case 'M': ShowSmallMap(); break;
+ case 'V': ShowExtraViewPortWindow(); break;
+ default: return ES_NOT_HANDLED;
+ }
+ return ES_HANDLED;
+ }
+
+ virtual void OnPlaceObject(Point pt, TileIndex tile)
+ {
+ _place_proc(tile);
+ }
+
+ virtual void OnPlaceObjectAbort()
+ {
+ this->RaiseWidget(25);
+ this->SetDirty();
+ }
+
+ virtual void OnResize(Point new_size, Point delta)
+ {
+ /* There are 15 buttons plus some spacings if the space allows it.
+ * Furthermore there are two panels of which one is non - essential
+ * and that one can be removed is the space is too small. */
+ uint buttons_width;
+ uint spacing;
+
+ static int normal_min_width = (15 * 22) + (2 * 130);
+ static int one_less_panel_min_width = (15 * 22) + 130;
+
+ if (this->width >= one_less_panel_min_width) {
+ buttons_width = 15 * 22;
+ spacing = this->width - ((this->width >= normal_min_width) ? normal_min_width : one_less_panel_min_width);
+ } else {
+ buttons_width = this->width - 130;
+ spacing = 0;
+ }
+ uint extra_spacing_at[] = { 3, 4, 7, 8, 10, 16, 0 };
+
+ /* Yes, it defines about 27 widgets for this toolbar */
+ for (uint i = 0, x = 0, j = 0, b = 0; i < 27; i++) {
+ switch (i) {
+ case 4:
+ this->widget[i].left = x;
+ if (this->width < normal_min_width) {
+ this->widget[i].right = x;
+ j++;
+ continue;
+ }
+
+ x += 130;
+ this->widget[i].right = x - 1;
+ break;
+
+ case 5: {
+ int offset = x - this->widget[i].left;
+ this->widget[i + 1].left += offset;
+ this->widget[i + 1].right += offset;
+ this->widget[i + 2].left += offset;
+ this->widget[i + 2].right += offset;
+ this->widget[i].left = x;
+ x += 130;
+ this->widget[i].right = x - 1;
+ i += 2;
+ } break;
+
+ default:
+ if (this->widget[i].bottom == 0) continue;
+
+ this->widget[i].left = x;
+ x += buttons_width / (15 - b);
+ this->widget[i].right = x - 1;
+ buttons_width -= buttons_width / (15 - b);
+ b++;
+ break;
}
- break;
-
- case WE_CLICK:
- if (_game_mode == GM_MENU) return;
- _scen_toolbar_button_procs[e->we.click.widget](w);
- break;
-
- case WE_KEYPRESS:
- switch (e->we.keypress.keycode) {
- case WKC_F1: case WKC_PAUSE: ToolbarPauseClick(w); break;
- case WKC_F2: ShowGameOptions(); break;
- case WKC_F3: MenuClickSaveLoad(0); break;
- case WKC_F4: ToolbarScenGenLand(w); break;
- case WKC_F5: ToolbarScenGenTown(w); break;
- case WKC_F6: ToolbarScenGenIndustry(w); break;
- case WKC_F7: ToolbarScenBuildRoad(w); break;
- case WKC_F8: ToolbarScenPlantTrees(w); break;
- case WKC_F9: ToolbarScenPlaceSign(w); break;
- case WKC_F10: ShowMusicWindow(); break;
- case WKC_F11: PlaceLandBlockInfo(); break;
- case WKC_CTRL | 'S': MenuClickSmallScreenshot(); break;
- case WKC_CTRL | 'G': MenuClickWorldScreenshot(); break;
-
- /* those following are all fall through */
- case WKC_NUM_PLUS:
- case WKC_EQUALS:
- case WKC_SHIFT | WKC_EQUALS:
- case WKC_SHIFT | WKC_F5: ToolbarZoomInClick(w); break;
-
- /* those following are all fall through */
- case WKC_NUM_MINUS:
- case WKC_MINUS:
- case WKC_SHIFT | WKC_MINUS:
- case WKC_SHIFT | WKC_F6: ToolbarZoomOutClick(w); break;
-
- case 'L': ShowEditorTerraformToolbar(); break;
- case 'M': ShowSmallMap(); break;
- case 'V': ShowExtraViewPortWindow(); break;
- default: return;
+ if (extra_spacing_at[j] == i) {
+ j++;
+ uint add = spacing / (lengthof(extra_spacing_at) - j);
+ spacing -= add;
+ x += add;
}
- e->we.keypress.cont = false;
- break;
-
- case WE_PLACE_OBJ:
- _place_proc(e->we.place.tile);
- break;
-
- case WE_ABORT_PLACE_OBJ:
- w->RaiseWidget(25);
- w->SetDirty();
- break;
-
- case WE_RESIZE: {
- /* There are 15 buttons plus some spacings if the space allows it.
- * Furthermore there are two panels of which one is non - essential
- * and that one can be removed is the space is too small. */
- uint buttons_width;
- uint spacing;
-
- static int normal_min_width = (15 * 22) + (2 * 130);
- static int one_less_panel_min_width = (15 * 22) + 130;
+ }
+ }
- if (w->width >= one_less_panel_min_width) {
- buttons_width = 15 * 22;
- spacing = w->width - ((w->width >= normal_min_width) ? normal_min_width : one_less_panel_min_width);
- } else {
- buttons_width = w->width - 130;
- spacing = 0;
- }
- uint extra_spacing_at[] = { 3, 4, 7, 8, 10, 16, 0 };
-
- /* Yes, it defines about 27 widgets for this toolbar */
- for (uint i = 0, x = 0, j = 0, b = 0; i < 27; i++) {
- switch (i) {
- case 4:
- w->widget[i].left = x;
- if (w->width < normal_min_width) {
- w->widget[i].right = x;
- j++;
- continue;
- }
-
- x += 130;
- w->widget[i].right = x - 1;
- break;
-
- case 5: {
- int offset = x - w->widget[i].left;
- w->widget[i + 1].left += offset;
- w->widget[i + 1].right += offset;
- w->widget[i + 2].left += offset;
- w->widget[i + 2].right += offset;
- w->widget[i].left = x;
- x += 130;
- w->widget[i].right = x - 1;
- i += 2;
- } break;
+ virtual void OnTick()
+ {
+ if (this->IsWidgetLowered(0) != !!_pause_game) {
+ this->ToggleWidgetLoweredState(0);
+ this->SetDirty();
+ }
- default:
- if (w->widget[i].bottom == 0) continue;
-
- w->widget[i].left = x;
- x += buttons_width / (15 - b);
- w->widget[i].right = x - 1;
- buttons_width -= buttons_width / (15 - b);
- b++;
- break;
- }
+ if (this->IsWidgetLowered(1) != !!_fast_forward) {
+ this->ToggleWidgetLoweredState(1);
+ this->SetDirty();
+ }
+ }
- if (extra_spacing_at[j] == i) {
- j++;
- uint add = spacing / (lengthof(extra_spacing_at) - j);
- spacing -= add;
- x += add;
- }
- }
- } break;
-
- case WE_TICK:
- if (w->IsWidgetLowered(0) != !!_pause_game) {
- w->ToggleWidgetLoweredState(0);
- w->SetDirty();
- }
-
- if (w->IsWidgetLowered(1) != !!_fast_forward) {
- w->ToggleWidgetLoweredState(1);
- w->SetDirty();
- }
- break;
-
- case WE_INVALIDATE_DATA:
- HandleZoomMessage(w, FindWindowById(WC_MAIN_WINDOW, 0)->viewport, 9, 10);
- break;
+ virtual void OnInvalidateData(int data)
+ {
+ if (FindWindowById(WC_MAIN_WINDOW, 0) != NULL) HandleZoomMessage(this, FindWindowById(WC_MAIN_WINDOW, 0)->viewport, 17, 18);
}
-}
+};
static const Widget _toolb_scen_widgets[] = {
{ WWT_IMGBTN, RESIZE_LEFT, 14, 0, 0, 0, 21, SPR_IMG_PAUSE, STR_0171_PAUSE_GAME},
@@ -1082,7 +1108,6 @@
WC_MAIN_TOOLBAR, WC_NONE,
WDF_STD_TOOLTIPS | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS,
_toolb_scen_widgets,
- ScenEditToolbarWndProc
};
/* --- Rendering/handling the drop down menus --- */
@@ -1119,71 +1144,77 @@
MenuClickHelp, /* 26 */
};
-static void MenuWndProc(Window *w, WindowEvent *e)
-{
- switch (e->event) {
- case WE_CREATE:
- w->widget[0].right = w->width - 1;
- break;
-
- case WE_PAINT: {
- byte count = WP(w, menu_d).item_count;
- byte sel = WP(w, menu_d).sel_index;
- uint16 chk = WP(w, menu_d).checked_items;
- StringID string = WP(w, menu_d).string_id;
- byte dis = WP(w, menu_d).disabled_items;
-
- DrawWindowWidgets(w);
+struct ToolbarMenuWindow : Window {
+ int item_count;
+ int sel_index;
+ int main_button;
+ int action_id;
+ int checked_items;
+ int disabled_items;
+ StringID base_string;
- int x = 1;
- int y = 1;
-
- for (; count != 0; count--, string++, sel--) {
- TextColour color = HasBit(dis, 0) ? TC_GREY : (sel == 0) ? TC_WHITE : TC_BLACK;
- if (sel == 0) GfxFillRect(x, y, x + w->width - 3, y + 9, 0);
-
- if (HasBit(chk, 0)) DrawString(x + 2, y, STR_CHECKMARK, color);
- DrawString(x + 2, y, string, color);
+ ToolbarMenuWindow(int x, int y, int width, int height, const Widget *widgets, int item_count,
+ int sel_index, int parent_button, StringID base_string, int checked_items,
+ int disabled_mask) :
+ Window(x, y, width, height, WC_TOOLBAR_MENU, widgets),
+ item_count(item_count), sel_index(sel_index), main_button(GB(parent_button, 0, 8)),
+ action_id((GB(parent_button, 8, 8) != 0) ? GB(parent_button, 8, 8) : parent_button),
+ checked_items(checked_items), disabled_items(disabled_items), base_string(base_string)
+ {
+ this->widget[0].bottom = item_count * 10 + 1;
+ this->widget[0].right = this->width - 1;
+ this->flags4 &= ~WF_WHITE_BORDER_MASK;
- y += 10;
- chk >>= 1;
- dis >>= 1;
- }
- } break;
+ this->FindWindowPlacementAndResize(width, height);
+ }
- case WE_DESTROY: {
- Window *v = FindWindowById(WC_MAIN_TOOLBAR, 0);
- v->RaiseWidget(WP(w, menu_d).main_button);
- v->SetDirty();
- return;
+ ~ToolbarMenuWindow()
+ {
+ Window *w = FindWindowById(WC_MAIN_TOOLBAR, 0);
+ w->RaiseWidget(this->main_button);
+ w->SetDirty();
+ }
+
+ virtual void OnPaint()
+ {
+ this->DrawWidgets();
+
+ for (int i = 0, x = 1, y = 1; i != this->item_count; i++, y += 10) {
+ TextColour color = HasBit(this->disabled_items, i) ? TC_GREY : (this->sel_index == i) ? TC_WHITE : TC_BLACK;
+ if (this->sel_index == i) GfxFillRect(x, y, x + this->width - 3, y + 9, 0);
+
+ if (HasBit(this->checked_items, i)) DrawString(x + 2, y, STR_CHECKMARK, color);
+ DrawString(x + 2, y, this->base_string + i, color);
+ }
+ }
+
+ virtual void OnMouseLoop()
+ {
+ int index = GetMenuItemIndex(this, this->item_count, this->disabled_items);
+
+ if (_left_button_down) {
+ if (index == -1 || index == this->sel_index) return;
+
+ this->sel_index = index;
+ this->SetDirty();
+ } else {
+ if (index < 0) {
+ Window *w = FindWindowById(WC_MAIN_TOOLBAR,0);
+ if (GetWidgetFromPos(w, _cursor.pos.x - w->left, _cursor.pos.y - w->top) == this->main_button) {
+ index = this->sel_index;
+ }
}
- case WE_MOUSELOOP: {
- int index = GetMenuItemIndex(w);
-
- if (_left_button_down) {
- if (index == -1 || index == WP(w, menu_d).sel_index) return;
+ int action_id = this->action_id;
+ delete this;
- WP(w, menu_d).sel_index = index;
- w->SetDirty();
- } else {
- if (index < 0) {
- Window *w2 = FindWindowById(WC_MAIN_TOOLBAR,0);
- if (GetWidgetFromPos(w2, _cursor.pos.x - w2->left, _cursor.pos.y - w2->top) == WP(w, menu_d).main_button)
- index = WP(w, menu_d).sel_index;
- }
-
- int action_id = WP(w, menu_d).action_id;
- delete w;
-
- if (index >= 0) {
- assert((uint)index <= lengthof(_menu_clicked_procs));
- _menu_clicked_procs[action_id](index);
- }
+ if (index >= 0) {
+ assert((uint)index <= lengthof(_menu_clicked_procs));
+ _menu_clicked_procs[action_id](index);
}
- } break;
+ }
}
-}
+};
/* Dynamic widget length determined by toolbar-string length.
* See PopupMainToolbMenu en MenuWndProc */
@@ -1222,7 +1253,7 @@
* aligned with the toolbar's right side.
* Since the disable-mask is only 8 bits right now, these dropdowns are
* restricted to 8 items max if any bits of disabled_mask are active.
- * @param w Pointer to a window this dropdown menu belongs to. Has no effect
+ * @param parent Pointer to a window this dropdown menu belongs to. Has no effect
* whatsoever, only graphically for positioning.
* @param parent_button The widget identifier of the button that was clicked for
* this dropdown. The created dropdown then knows what button to raise (button) on
@@ -1236,12 +1267,15 @@
* consecutive indeces from the language file. XXX - fix? Use ingame-string tables?
* @param item_count Number of strings in the list, see previous parameter
* @param disabled_mask Bitmask of disabled strings in the list
- * @return Return a pointer to the newly created dropdown window */
-static Window *PopupMainToolbMenu(Window *w, uint16 parent_button, StringID base_string, byte item_count, byte disabled_mask)
+ * @param sel_index The selected toolbar item
+ * @param check_items The items to have a checked mark in front of them.
+ * @return Return a pointer to the newly created dropdown window
+ */
+static void PopupMainToolbMenu(Window *parent, uint16 parent_button, StringID base_string, byte item_count, byte disabled_mask, int sel_index, int checked_items)
{
assert(disabled_mask == 0 || item_count <= 8);
- w->LowerWidget(parent_button);
- w->InvalidateWidget(parent_button);
+ parent->LowerWidget(parent_button);
+ parent->InvalidateWidget(parent_button);
DeleteWindowById(WC_TOOLBAR_MENU, 0);
@@ -1251,20 +1285,9 @@
Point pos = GetToolbarDropdownPos(parent_button, width, height);
- w = new Window(pos.x, pos.y, width, height, MenuWndProc, WC_TOOLBAR_MENU, _menu_widgets);
- w->widget[0].bottom = item_count * 10 + 1;
- w->flags4 &= ~WF_WHITE_BORDER_MASK;
-
- WP(w, menu_d).item_count = item_count;
- WP(w, menu_d).sel_index = 0;
- WP(w, menu_d).main_button = GB(parent_button, 0, 8);
- WP(w, menu_d).action_id = (GB(parent_button, 8, 8) != 0) ? GB(parent_button, 8, 8) : parent_button;
- WP(w, menu_d).string_id = base_string;
- WP(w, menu_d).checked_items = 0;
- WP(w, menu_d).disabled_items = disabled_mask;
+ new ToolbarMenuWindow(pos.x, pos.y, width, height, _menu_widgets, item_count, sel_index, parent_button, base_string, checked_items, disabled_mask);
SndPlayFx(SND_15_BEEP);
- return w;
}
/* --- Rendering/drawing the player menu --- */
@@ -1280,170 +1303,169 @@
return -1;
}
-static void UpdatePlayerMenuHeight(Window *w)
-{
- byte num = ActivePlayerCount();
-
- /* Increase one to fit in PlayerList in the menu when in network */
- if (_networking && WP(w, menu_d).main_button == 9) num++;
+struct ToolbarPlayerMenuWindow : Window {
+ int item_count;
+ int sel_index;
+ int main_button;
+ int action_id;
+ int gray_items;
- if (WP(w, menu_d).item_count != num) {
- WP(w, menu_d).item_count = num;
- w->SetDirty();
- num = num * 10 + 2;
- w->height = num;
- w->widget[0].bottom = w->widget[0].top + num - 1;
- w->top = GetToolbarDropdownPos(0, w->width, w->height).y;
+ ToolbarPlayerMenuWindow(int x, int y, int width, int height, const Widget *widgets, int main_button, int gray) :
+ Window(x, y, width, height, WC_TOOLBAR_MENU, widgets),
+ item_count(0), main_button(main_button), action_id(main_button), gray_items(gray)
+ {
+ this->flags4 &= ~WF_WHITE_BORDER_MASK;
+ this->sel_index = (_local_player != PLAYER_SPECTATOR) ? _local_player : GetPlayerIndexFromMenu(0);
+ if (_networking && main_button == 9) {
+ if (_local_player != PLAYER_SPECTATOR) {
+ this->sel_index++;
+ } else {
+ /* Select client list by default for spectators */
+ this->sel_index = 0;
+ }
+ }
+ }
+
+ ~ToolbarPlayerMenuWindow()
+ {
+ Window *w = FindWindowById(WC_MAIN_TOOLBAR, 0);
+ w->RaiseWidget(this->main_button);
w->SetDirty();
}
-}
-static void PlayerMenuWndProc(Window *w, WindowEvent *e)
-{
- switch (e->event) {
- case WE_PAINT: {
- UpdatePlayerMenuHeight(w);
- DrawWindowWidgets(w);
+ void UpdatePlayerMenuHeight()
+ {
+ byte num = ActivePlayerCount();
- int x = 1;
- int y = 1;
- int sel = WP(w, menu_d).sel_index;
- int chk = WP(w, menu_d).checked_items; // let this mean gray items.
+ /* Increase one to fit in PlayerList in the menu when in network */
+ if (_networking && this->main_button == 9) num++;
- /* 9 = playerlist */
- if (_networking && WP(w, menu_d).main_button == 9) {
- if (sel == 0) {
+ if (this->item_count != num) {
+ this->item_count = num;
+ this->SetDirty();
+ num = num * 10 + 2;
+ this->height = num;
+ this->widget[0].bottom = this->widget[0].top + num - 1;
+ this->top = GetToolbarDropdownPos(0, this->width, this->height).y;
+ this->SetDirty();
+ }
+ }
+
+ virtual void OnPaint()
+ {
+ this->UpdatePlayerMenuHeight();
+ this->DrawWidgets();
+
+ int x = 1;
+ int y = 1;
+ int sel = this->sel_index;
+ int gray = this->gray_items;
+
+ /* 9 = playerlist */
+ if (_networking && this->main_button == 9) {
+ if (sel == 0) {
+ GfxFillRect(x, y, x + 238, y + 9, 0);
+ }
+ DrawString(x + 19, y, STR_NETWORK_CLIENT_LIST, TC_FROMSTRING);
+ y += 10;
+ sel--;
+ }
+
+ const Player *p;
+ FOR_ALL_PLAYERS(p) {
+ if (p->is_active) {
+ if (p->index == sel) {
GfxFillRect(x, y, x + 238, y + 9, 0);
}
- DrawString(x + 19, y, STR_NETWORK_CLIENT_LIST, TC_FROMSTRING);
+
+ DrawPlayerIcon(p->index, x + 2, y + 1);
+
+ SetDParam(0, p->index);
+ SetDParam(1, p->index);
+
+ TextColour color = (p->index == sel) ? TC_WHITE : TC_BLACK;
+ if (gray & 1) color = TC_GREY;
+ DrawString(x + 19, y, STR_7021, color);
+
y += 10;
- sel--;
+ }
+ gray >>= 1;
+ }
+ }
+
+ virtual void OnMouseLoop()
+ {
+ int index = GetMenuItemIndex(this, this->item_count, 0);
+
+ if (_left_button_down) {
+ this->UpdatePlayerMenuHeight();
+ /* We have a new entry at the top of the list of menu 9 when networking
+ * so keep that in count */
+ if (_networking && this->main_button == 9) {
+ if (index > 0) index = GetPlayerIndexFromMenu(index - 1) + 1;
+ } else {
+ index = GetPlayerIndexFromMenu(index);
}
- const Player *p;
- FOR_ALL_PLAYERS(p) {
- if (p->is_active) {
- if (p->index == sel) {
- GfxFillRect(x, y, x + 238, y + 9, 0);
- }
-
- DrawPlayerIcon(p->index, x + 2, y + 1);
-
- SetDParam(0, p->index);
- SetDParam(1, p->index);
-
- TextColour color = (p->index == sel) ? TC_WHITE : TC_BLACK;
- if (chk & 1) color = TC_GREY;
- DrawString(x + 19, y, STR_7021, color);
-
- y += 10;
- }
- chk >>= 1;
- }
- } break;
-
- case WE_DESTROY: {
- Window *v = FindWindowById(WC_MAIN_TOOLBAR, 0);
- v->RaiseWidget(WP(w, menu_d).main_button);
- v->SetDirty();
- return;
- }
-
- case WE_MOUSELOOP: {
- int index = GetMenuItemIndex(w);
+ if (index == -1 || index == this->sel_index) return;
- if (_left_button_down) {
- UpdatePlayerMenuHeight(w);
- /* We have a new entry at the top of the list of menu 9 when networking
- * so keep that in count */
- if (_networking && WP(w, menu_d).main_button == 9) {
- if (index > 0) index = GetPlayerIndexFromMenu(index - 1) + 1;
- } else {
- index = GetPlayerIndexFromMenu(index);
- }
-
- if (index == -1 || index == WP(w, menu_d).sel_index) return;
-
- WP(w, menu_d).sel_index = index;
- w->SetDirty();
- } else {
- int action_id = WP(w, menu_d).action_id;
+ this->sel_index = index;
+ this->SetDirty();
+ } else {
+ int action_id = this->action_id;
- /* We have a new entry at the top of the list of menu 9 when networking
- * so keep that in count */
- if (_networking && WP(w, menu_d).main_button == 9) {
- if (index > 0) index = GetPlayerIndexFromMenu(index - 1) + 1;
- } else {
- index = GetPlayerIndexFromMenu(index);
- }
+ /* We have a new entry at the top of the list of menu 9 when networking
+ * so keep that in count */
+ if (_networking && this->main_button == 9) {
+ if (index > 0) index = GetPlayerIndexFromMenu(index - 1) + 1;
+ } else {
+ index = GetPlayerIndexFromMenu(index);
+ }
- if (index < 0) {
- Window *w2 = FindWindowById(WC_MAIN_TOOLBAR,0);
- if (GetWidgetFromPos(w2, _cursor.pos.x - w2->left, _cursor.pos.y - w2->top) == WP(w, menu_d).main_button)
- index = WP(w, menu_d).sel_index;
- }
-
- delete w;
-
- if (index >= 0) {
- assert(index >= 0 && index < 30);
- _menu_clicked_procs[action_id](index);
+ if (index < 0) {
+ Window *w = FindWindowById(WC_MAIN_TOOLBAR,0);
+ if (GetWidgetFromPos(w, _cursor.pos.x - w->left, _cursor.pos.y - w->top) == this->main_button) {
+ index = this->sel_index;
}
}
- } break;
+
+ delete this;
+
+ if (index >= 0) {
+ assert(index >= 0 && index < 30);
+ _menu_clicked_procs[action_id](index);
+ }
+ }
}
-}
+};
static const Widget _player_menu_widgets[] = {
{ WWT_PANEL, RESIZE_NONE, 14, 0, 240, 0, 81, 0x0, STR_NULL},
{ WIDGETS_END},
};
-static Window *PopupMainPlayerToolbMenu(Window *w, int main_button, int gray)
+static void PopupMainPlayerToolbMenu(Window *parent, int main_button, int gray)
{
- w->LowerWidget(main_button);
- w->InvalidateWidget(main_button);
+ parent->LowerWidget(main_button);
+ parent->InvalidateWidget(main_button);
DeleteWindowById(WC_TOOLBAR_MENU, 0);
Point pos = GetToolbarDropdownPos(main_button, 241, 82);
- w = new Window(pos.x, pos.y, 241, 82, PlayerMenuWndProc, WC_TOOLBAR_MENU, _player_menu_widgets);
- w->flags4 &= ~WF_WHITE_BORDER_MASK;
- WP(w, menu_d).item_count = 0;
- WP(w, menu_d).sel_index = (_local_player != PLAYER_SPECTATOR) ? _local_player : GetPlayerIndexFromMenu(0);
- if (_networking && main_button == 9) {
- if (_local_player != PLAYER_SPECTATOR) {
- WP(w, menu_d).sel_index++;
- } else {
- /* Select client list by default for spectators */
- WP(w, menu_d).sel_index = 0;
- }
- }
- WP(w, menu_d).action_id = main_button;
- WP(w, menu_d).main_button = main_button;
- WP(w, menu_d).checked_items = gray;
- WP(w, menu_d).disabled_items = 0;
+ new ToolbarPlayerMenuWindow(pos.x, pos.y, 241, 82, _player_menu_widgets, main_button, gray);
SndPlayFx(SND_15_BEEP);
- return w;
}
/* --- Allocating the toolbar --- */
-Window *AllocateToolbar()
+void AllocateToolbar()
{
/* Clean old GUI values; railtype is (re)set by rail_gui.cpp */
_last_built_roadtype = ROADTYPE_ROAD;
- Window *w = new Window((_game_mode != GM_EDITOR) ? &_toolb_normal_desc : &_toolb_scen_desc);
- if (w == NULL) return NULL;
-
- CLRBITS(w->flags4, WF_WHITE_BORDER_MASK);
-
- w->SetWidgetDisabledState(0, _networking && !_network_server); // if not server, disable pause button
- w->SetWidgetDisabledState(1, _networking); // if networking, disable fast-forward button
-
- /* 'w' is for sure a WC_MAIN_TOOLBAR */
- PositionMainToolbar(w);
-
- return w;
+ if (_game_mode == GM_EDITOR) {
+ new ScenarioEditorToolbarWindow(&_toolb_scen_desc);;
+ } else {
+ new MainToolbarWindow(&_toolb_normal_desc);
+ }
}
--- a/src/toolbar_gui.h Mon May 19 14:14:33 2008 +0000
+++ b/src/toolbar_gui.h Mon May 19 15:13:58 2008 +0000
@@ -5,8 +5,6 @@
#ifndef TOOLBAR_GUI_H
#define TOOLBAR_GUI_H
-#include "window_type.h"
-
-Window *AllocateToolbar();
+void AllocateToolbar();
#endif /*TOOLBAR_GUI_H*/
--- a/src/town_cmd.cpp Mon May 19 14:14:33 2008 +0000
+++ b/src/town_cmd.cpp Mon May 19 15:13:58 2008 +0000
@@ -2152,7 +2152,7 @@
SetDParam(1, _current_player);
AddNewsItem(STR_2055_TRAFFIC_CHAOS_IN_ROAD_REBUILDING,
- NM_NORMAL, NF_TILE, NT_GENERAL, DNC_NONE, t->xy, 0);
+ NS_GENERAL, t->xy, 0);
}
static bool DoBuildStatueOfCompany(TileIndex tile, TownID town_id)
--- a/src/town_gui.cpp Mon May 19 14:14:33 2008 +0000
+++ b/src/town_gui.cpp Mon May 19 15:13:58 2008 +0000
@@ -141,140 +141,134 @@
return -1;
}
-static void TownAuthorityWndProc(Window *w, WindowEvent *e)
-{
- switch (e->event) {
- case WE_PAINT: {
- const Town *t = GetTown(w->window_number);
- int numact;
- uint buttons = GetMaskOfTownActions(&numact, _local_player, t);
-
- SetVScrollCount(w, numact + 1);
-
- if (WP(w, def_d).data_1 != -1 && !HasBit(buttons, WP(w, def_d).data_1))
- WP(w, def_d).data_1 = -1;
-
- w->SetWidgetDisabledState(6, WP(w, def_d).data_1 == -1);
-
- {
- int y;
- const Player *p;
- int r;
- StringID str;
-
- SetDParam(0, w->window_number);
- DrawWindowWidgets(w);
-
- DrawString(2, 15, STR_2023_TRANSPORT_COMPANY_RATINGS, TC_FROMSTRING);
+struct TownAuthorityWindow : Window {
+ int sel_index;
- /* Draw list of players */
- y = 25;
- FOR_ALL_PLAYERS(p) {
- if (p->is_active && (HasBit(t->have_ratings, p->index) || t->exclusivity == p->index)) {
- DrawPlayerIcon(p->index, 2, y);
-
- SetDParam(0, p->index);
- SetDParam(1, p->index);
+ TownAuthorityWindow(const WindowDesc *desc, WindowNumber window_number) :
+ Window(desc, window_number), sel_index(-1)
+ {
+ this->vscroll.cap = 5;
- r = t->ratings[p->index];
- (str = STR_3035_APPALLING, r <= RATING_APPALLING) || // Apalling
- (str++, r <= RATING_VERYPOOR) || // Very Poor
- (str++, r <= RATING_POOR) || // Poor
- (str++, r <= RATING_MEDIOCRE) || // Mediocore
- (str++, r <= RATING_GOOD) || // Good
- (str++, r <= RATING_VERYGOOD) || // Very Good
- (str++, r <= RATING_EXCELLENT) || // Excellent
- (str++, true); // Outstanding
+ this->FindWindowPlacementAndResize(desc);
+ }
- SetDParam(2, str);
- if (t->exclusivity == p->index) { // red icon for player with exclusive rights
- DrawSprite(SPR_BLOT, PALETTE_TO_RED, 18, y);
- }
+ virtual void OnPaint()
+ {
+ const Town *t = GetTown(this->window_number);
+ int numact;
+ uint buttons = GetMaskOfTownActions(&numact, _local_player, t);
- DrawString(28, y, STR_2024, TC_FROMSTRING);
- y += 10;
- }
+ SetVScrollCount(this, numact + 1);
+
+ if (this->sel_index != -1 && !HasBit(buttons, this->sel_index)) {
+ this->sel_index = -1;
+ }
+
+ this->SetWidgetDisabledState(6, this->sel_index == -1);
+
+ SetDParam(0, this->window_number);
+ this->DrawWidgets();
+
+ DrawString(2, 15, STR_2023_TRANSPORT_COMPANY_RATINGS, TC_FROMSTRING);
+
+ /* Draw list of players */
+ int y = 25;
+
+ const Player *p;
+ FOR_ALL_PLAYERS(p) {
+ if (p->is_active && (HasBit(t->have_ratings, p->index) || t->exclusivity == p->index)) {
+ DrawPlayerIcon(p->index, 2, y);
+
+ SetDParam(0, p->index);
+ SetDParam(1, p->index);
+
+ int r = t->ratings[p->index];
+ StringID str;
+ (str = STR_3035_APPALLING, r <= RATING_APPALLING) || // Apalling
+ (str++, r <= RATING_VERYPOOR) || // Very Poor
+ (str++, r <= RATING_POOR) || // Poor
+ (str++, r <= RATING_MEDIOCRE) || // Mediocore
+ (str++, r <= RATING_GOOD) || // Good
+ (str++, r <= RATING_VERYGOOD) || // Very Good
+ (str++, r <= RATING_EXCELLENT) || // Excellent
+ (str++, true); // Outstanding
+
+ SetDParam(2, str);
+ if (t->exclusivity == p->index) { // red icon for player with exclusive rights
+ DrawSprite(SPR_BLOT, PALETTE_TO_RED, 18, y);
}
+
+ DrawString(28, y, STR_2024, TC_FROMSTRING);
+ y += 10;
+ }
+ }
+ y = 107;
+ int pos = this->vscroll.pos;
+
+ if (--pos < 0) {
+ DrawString(2, y, STR_2045_ACTIONS_AVAILABLE, TC_FROMSTRING);
+ y += 10;
+ }
+
+ for (int i = 0; buttons; i++, buttons >>= 1) {
+ if (pos <= -5) break; ///< Draw only the 5 fitting lines
+
+ if ((buttons & 1) && --pos < 0) {
+ DrawString(3, y, STR_2046_SMALL_ADVERTISING_CAMPAIGN + i, TC_ORANGE);
+ y += 10;
+ }
+ }
+
+ if (this->sel_index != -1) {
+ SetDParam(1, (_price.build_industry >> 8) * _town_action_costs[this->sel_index]);
+ SetDParam(0, STR_2046_SMALL_ADVERTISING_CAMPAIGN + this->sel_index);
+ DrawStringMultiLine(2, 159, STR_204D_INITIATE_A_SMALL_LOCAL + this->sel_index, 313);
+ }
+ }
+
+ virtual void OnDoubleClick(Point pt, int widget) { HandleClick(pt, widget, true); }
+ virtual void OnClick(Point pt, int widget) { HandleClick(pt, widget, false); }
+
+ void HandleClick(Point pt, int widget, bool double_click)
+ {
+ switch (widget) {
+ case TWA_COMMAND_LIST: {
+ const Town *t = GetTown(this->window_number);
+ int y = (pt.y - 0x6B) / 10;
+
+ if (!IsInsideMM(y, 0, 5)) return;
+
+ y = GetNthSetBit(GetMaskOfTownActions(NULL, _local_player, t), y + this->vscroll.pos - 1);
+ if (y >= 0) {
+ this->sel_index = y;
+ this->SetDirty();
+ }
+ /* Fall through to clicking in case we are double-clicked */
+ if (!double_click || y < 0) break;
}
- /* Draw actions list */
- {
- int y = 107, i;
- int pos = w->vscroll.pos;
-
- if (--pos < 0) {
- DrawString(2, y, STR_2045_ACTIONS_AVAILABLE, TC_FROMSTRING);
- y += 10;
- }
-
- for (i = 0; buttons; i++, buttons >>= 1) {
- if (pos <= -5) break; ///< Draw only the 5 fitting lines
-
- if ((buttons & 1) && --pos < 0) {
- DrawString(3, y, STR_2046_SMALL_ADVERTISING_CAMPAIGN + i, TC_ORANGE);
- y += 10;
- }
- }
- }
-
- {
- int i = WP(w, def_d).data_1;
-
- if (i != -1) {
- SetDParam(1, (_price.build_industry >> 8) * _town_action_costs[i]);
- SetDParam(0, STR_2046_SMALL_ADVERTISING_CAMPAIGN + i);
- DrawStringMultiLine(2, 159, STR_204D_INITIATE_A_SMALL_LOCAL + i, 313);
- }
- }
+ case TWA_EXECUTE:
+ DoCommandP(GetTown(this->window_number)->xy, this->window_number, this->sel_index, NULL, CMD_DO_TOWN_ACTION | CMD_MSG(STR_00B4_CAN_T_DO_THIS));
+ break;
+ }
+ }
- } break;
-
- case WE_DOUBLE_CLICK:
- case WE_CLICK:
- switch (e->we.click.widget) {
- case TWA_COMMAND_LIST: {
- const Town *t = GetTown(w->window_number);
- int y = (e->we.click.pt.y - 0x6B) / 10;
-
- if (!IsInsideMM(y, 0, 5)) return;
-
- y = GetNthSetBit(GetMaskOfTownActions(NULL, _local_player, t), y + w->vscroll.pos - 1);
- if (y >= 0) {
- WP(w, def_d).data_1 = y;
- w->SetDirty();
- }
- /* Fall through to clicking in case we are double-clicked */
- if (e->event != WE_DOUBLE_CLICK || y < 0) break;
- }
-
- case TWA_EXECUTE:
- DoCommandP(GetTown(w->window_number)->xy, w->window_number, WP(w, def_d).data_1, NULL, CMD_DO_TOWN_ACTION | CMD_MSG(STR_00B4_CAN_T_DO_THIS));
- break;
- }
- break;
-
- case WE_100_TICKS:
- w->SetDirty();
- break;
+ virtual void OnHundredthTick()
+ {
+ this->SetDirty();
}
-}
+};
static const WindowDesc _town_authority_desc = {
WDP_AUTO, WDP_AUTO, 317, 222, 317, 222,
WC_TOWN_AUTHORITY, WC_NONE,
WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS,
_town_authority_widgets,
- TownAuthorityWndProc
};
static void ShowTownAuthorityWindow(uint town)
{
- Window *w = AllocateWindowDescFront<Window>(&_town_authority_desc, town);
-
- if (w != NULL) {
- w->vscroll.cap = 5;
- WP(w, def_d).data_1 = -1;
- }
+ AllocateWindowDescFront<TownAuthorityWindow>(&_town_authority_desc, town);
}
@@ -288,87 +282,98 @@
TVW_DELETE,
};
-static void TownViewWndProc(Window *w, WindowEvent *e)
-{
- Town *t = GetTown(w->window_number);
-
- switch (e->event) {
- case WE_CREATE: {
- bool ingame = _game_mode != GM_EDITOR;
- if (t->larger_town) w->widget[TVW_CAPTION].data = STR_CITY;
- w->SetWidgetHiddenState(TVW_DELETE, ingame); // hide delete button on game mode
- w->SetWidgetHiddenState(TVW_EXPAND, ingame); // hide expand button on game mode
- w->SetWidgetHiddenState(TVW_SHOWAUTORITY, !ingame); // hide autority button on editor mode
-
- if (ingame) {
- /* resize caption bar */
- w->widget[TVW_CAPTION].right = w->widget[TVW_STICKY].left -1;
- /* move the rename from top on scenario to bottom in game */
- w->widget[TVW_CHANGENAME].top = w->widget[TVW_EXPAND].top;
- w->widget[TVW_CHANGENAME].bottom = w->widget[TVW_EXPAND].bottom;
- w->widget[TVW_CHANGENAME].right = w->widget[TVW_STICKY].right;
- }
- } break;
-
- case WE_PAINT:
- /* disable renaming town in network games if you are not the server */
- w->SetWidgetDisabledState(TVW_CHANGENAME, _networking && !_network_server);
-
- SetDParam(0, t->index);
- DrawWindowWidgets(w);
-
- SetDParam(0, t->population);
- SetDParam(1, t->num_houses);
- DrawString(2, 107, STR_2006_POPULATION, TC_FROMSTRING);
-
- SetDParam(0, t->act_pass);
- SetDParam(1, t->max_pass);
- DrawString(2, 117, STR_200D_PASSENGERS_LAST_MONTH_MAX, TC_FROMSTRING);
+struct TownViewWindow : Window {
+ TownViewWindow(const WindowDesc *desc, WindowNumber window_number) : Window(desc, window_number)
+ {
+ const Town *t = GetTown(this->window_number);
- SetDParam(0, t->act_mail);
- SetDParam(1, t->max_mail);
- DrawString(2, 127, STR_200E_MAIL_LAST_MONTH_MAX, TC_FROMSTRING);
-
- DrawWindowViewport(w);
- break;
-
- case WE_CLICK:
- switch (e->we.click.widget) {
- case TVW_CENTERVIEW: /* scroll to location */
- if (_ctrl_pressed) {
- ShowExtraViewPortWindow(t->xy);
- } else {
- ScrollMainWindowToTile(t->xy);
- }
- break;
-
- case TVW_SHOWAUTORITY: /* town authority */
- ShowTownAuthorityWindow(w->window_number);
- break;
+ this->flags4 |= WF_DISABLE_VP_SCROLL;
+ InitializeWindowViewport(this, 3, 17, 254, 86, t->xy, ZOOM_LVL_TOWN);
- case TVW_CHANGENAME: /* rename */
- SetDParam(0, w->window_number);
- ShowQueryString(STR_TOWN, STR_2007_RENAME_TOWN, 31, 130, w, CS_ALPHANUMERAL);
- break;
-
- case TVW_EXPAND: /* expand town - only available on Scenario editor */
- ExpandTown(t);
- break;
+ bool ingame = _game_mode != GM_EDITOR;
+ if (t->larger_town) this->widget[TVW_CAPTION].data = STR_CITY;
+ this->SetWidgetHiddenState(TVW_DELETE, ingame); // hide delete button on game mode
+ this->SetWidgetHiddenState(TVW_EXPAND, ingame); // hide expand button on game mode
+ this->SetWidgetHiddenState(TVW_SHOWAUTORITY, !ingame); // hide autority button on editor mode
- case TVW_DELETE: /* delete town - only available on Scenario editor */
- delete t;
- break;
- } break;
+ if (ingame) {
+ /* resize caption bar */
+ this->widget[TVW_CAPTION].right = this->widget[TVW_STICKY].left -1;
+ /* move the rename from top on scenario to bottom in game */
+ this->widget[TVW_CHANGENAME].top = this->widget[TVW_EXPAND].top;
+ this->widget[TVW_CHANGENAME].bottom = this->widget[TVW_EXPAND].bottom;
+ this->widget[TVW_CHANGENAME].right = this->widget[TVW_STICKY].right;
+ }
- case WE_ON_EDIT_TEXT:
- if (!StrEmpty(e->we.edittext.str)) {
- _cmd_text = e->we.edittext.str;
- DoCommandP(0, w->window_number, 0, NULL,
- CMD_RENAME_TOWN | CMD_MSG(STR_2008_CAN_T_RENAME_TOWN));
- }
- break;
+ this->FindWindowPlacementAndResize(desc);
}
-}
+
+ virtual void OnPaint()
+ {
+ const Town *t = GetTown(this->window_number);
+
+ /* disable renaming town in network games if you are not the server */
+ this->SetWidgetDisabledState(TVW_CHANGENAME, _networking && !_network_server);
+
+ SetDParam(0, t->index);
+ this->DrawWidgets();
+
+ SetDParam(0, t->population);
+ SetDParam(1, t->num_houses);
+ DrawString(2, 107, STR_2006_POPULATION, TC_FROMSTRING);
+
+ SetDParam(0, t->act_pass);
+ SetDParam(1, t->max_pass);
+ DrawString(2, 117, STR_200D_PASSENGERS_LAST_MONTH_MAX, TC_FROMSTRING);
+
+ SetDParam(0, t->act_mail);
+ SetDParam(1, t->max_mail);
+ DrawString(2, 127, STR_200E_MAIL_LAST_MONTH_MAX, TC_FROMSTRING);
+
+ this->DrawViewport();
+ }
+
+ virtual void OnClick(Point pt, int widget)
+ {
+ Town *t = GetTown(this->window_number);
+
+ switch (widget) {
+ case TVW_CENTERVIEW: /* scroll to location */
+ if (_ctrl_pressed) {
+ ShowExtraViewPortWindow(t->xy);
+ } else {
+ ScrollMainWindowToTile(t->xy);
+ }
+ break;
+
+ case TVW_SHOWAUTORITY: /* town authority */
+ ShowTownAuthorityWindow(this->window_number);
+ break;
+
+ case TVW_CHANGENAME: /* rename */
+ SetDParam(0, this->window_number);
+ ShowQueryString(STR_TOWN, STR_2007_RENAME_TOWN, 31, 130, this, CS_ALPHANUMERAL);
+ break;
+
+ case TVW_EXPAND: /* expand town - only available on Scenario editor */
+ ExpandTown(t);
+ break;
+
+ case TVW_DELETE: /* delete town - only available on Scenario editor */
+ delete t;
+ break;
+ }
+ }
+
+ virtual void OnQueryTextFinished(char *str)
+ {
+ if (!StrEmpty(str)) {
+ _cmd_text = str;
+ DoCommandP(0, this->window_number, 0, NULL,
+ CMD_RENAME_TOWN | CMD_MSG(STR_2008_CAN_T_RENAME_TOWN));
+ }
+ }
+};
static const Widget _town_view_widgets[] = {
@@ -391,26 +396,13 @@
WC_TOWN_VIEW, WC_NONE,
WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS | WDF_STICKY_BUTTON,
_town_view_widgets,
- TownViewWndProc
};
void ShowTownViewWindow(TownID town)
{
- Window *w;
-
- w = AllocateWindowDescFront<Window>(&_town_view_desc, town);
-
- if (w != NULL) {
- w->flags4 |= WF_DISABLE_VP_SCROLL;
- InitializeWindowViewport(w, 3, 17, 254, 86, GetTown(town)->xy, ZOOM_LVL_TOWN);
- }
+ AllocateWindowDescFront<TownViewWindow>(&_town_view_desc, town);
}
-enum TownDirectoryWidget {
- TDW_SORTNAME = 3,
- TDW_SORTPOPULATION,
- TDW_CENTERTOWN,
-};
static const Widget _town_directory_widgets[] = {
{ WWT_CLOSEBOX, RESIZE_NONE, 13, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW},
{ WWT_CAPTION, RESIZE_NONE, 13, 11, 195, 0, 13, STR_2000_TOWNS, STR_018C_WINDOW_TITLE_DRAG_THIS},
@@ -483,107 +475,117 @@
}
-static void TownDirectoryWndProc(Window *w, WindowEvent *e)
-{
- switch (e->event) {
- case WE_PAINT: {
- if (_town_sort_dirty) {
- _town_sort_dirty = false;
- MakeSortedTownList();
+struct TownDirectoryWindow : public Window {
+ enum TownDirectoryWidget {
+ TDW_SORTNAME = 3,
+ TDW_SORTPOPULATION,
+ TDW_CENTERTOWN,
+ };
+
+ TownDirectoryWindow(const WindowDesc *desc) : Window(desc, 0)
+ {
+ this->vscroll.cap = 16;
+ this->resize.step_height = 10;
+ this->resize.height = this->height - 10 * 6; // minimum of 10 items in the list, each item 10 high
+
+ this->FindWindowPlacementAndResize(desc);
+ }
+
+ virtual void OnPaint()
+ {
+ if (_town_sort_dirty) {
+ _town_sort_dirty = false;
+ MakeSortedTownList();
+ }
+
+ SetVScrollCount(this, _num_town_sort);
+
+ this->DrawWidgets();
+ this->DrawSortButtonState((_town_sort_order <= 1) ? TDW_SORTNAME : TDW_SORTPOPULATION, _town_sort_order & 1 ? SBS_DOWN : SBS_UP);
+
+ {
+ int n = 0;
+ uint16 i = this->vscroll.pos;
+ int y = 28;
+
+ while (i < _num_town_sort) {
+ const Town* t = _town_sort[i];
+
+ assert(t->xy);
+
+ SetDParam(0, t->index);
+ SetDParam(1, t->population);
+ DrawString(2, y, STR_2057, TC_FROMSTRING);
+
+ y += 10;
+ i++;
+ if (++n == this->vscroll.cap) break; // max number of towns in 1 window
}
- SetVScrollCount(w, _num_town_sort);
-
- DrawWindowWidgets(w);
- DrawSortButtonState(w, (_town_sort_order <= 1) ? TDW_SORTNAME : TDW_SORTPOPULATION, _town_sort_order & 1 ? SBS_DOWN : SBS_UP);
-
- {
- int n = 0;
- uint16 i = w->vscroll.pos;
- int y = 28;
-
- while (i < _num_town_sort) {
- const Town* t = _town_sort[i];
-
- assert(t->xy);
-
- SetDParam(0, t->index);
- SetDParam(1, t->population);
- DrawString(2, y, STR_2057, TC_FROMSTRING);
-
- y += 10;
- i++;
- if (++n == w->vscroll.cap) break; // max number of towns in 1 window
- }
- SetDParam(0, GetWorldPopulation());
- DrawString(3, w->height - 12 + 2, STR_TOWN_POPULATION, TC_FROMSTRING);
- }
- } break;
-
- case WE_CLICK:
- switch (e->we.click.widget) {
- case TDW_SORTNAME: /* Sort by Name ascending/descending */
- _town_sort_order = (_town_sort_order == 0) ? 1 : 0;
- _town_sort_dirty = true;
- w->SetDirty();
- break;
+ SetDParam(0, GetWorldPopulation());
+ DrawString(3, this->height - 12 + 2, STR_TOWN_POPULATION, TC_FROMSTRING);
+ }
+ }
- case TDW_SORTPOPULATION: /* Sort by Population ascending/descending */
- _town_sort_order = (_town_sort_order == 2) ? 3 : 2;
- _town_sort_dirty = true;
- w->SetDirty();
- break;
-
- case TDW_CENTERTOWN: { /* Click on Town Matrix */
- const Town* t;
-
- uint16 id_v = (e->we.click.pt.y - 28) / 10;
-
- if (id_v >= w->vscroll.cap) return; // click out of bounds
-
- id_v += w->vscroll.pos;
-
- if (id_v >= _num_town_sort) return; // click out of town bounds
+ virtual void OnClick(Point pt, int widget)
+ {
+ switch (widget) {
+ case TDW_SORTNAME: /* Sort by Name ascending/descending */
+ _town_sort_order = (_town_sort_order == 0) ? 1 : 0;
+ _town_sort_dirty = true;
+ this->SetDirty();
+ break;
- t = _town_sort[id_v];
- assert(t->xy);
- if (_ctrl_pressed) {
- ShowExtraViewPortWindow(t->xy);
- } else {
- ScrollMainWindowToTile(t->xy);
- }
- } break;
+ case TDW_SORTPOPULATION: /* Sort by Population ascending/descending */
+ _town_sort_order = (_town_sort_order == 2) ? 3 : 2;
+ _town_sort_dirty = true;
+ this->SetDirty();
+ break;
+
+ case TDW_CENTERTOWN: { /* Click on Town Matrix */
+ const Town* t;
+
+ uint16 id_v = (pt.y - 28) / 10;
+
+ if (id_v >= this->vscroll.cap) return; // click out of bounds
+
+ id_v += this->vscroll.pos;
+
+ if (id_v >= _num_town_sort) return; // click out of town bounds
+
+ t = _town_sort[id_v];
+ assert(t->xy);
+ if (_ctrl_pressed) {
+ ShowExtraViewPortWindow(t->xy);
+ } else {
+ ScrollMainWindowToTile(t->xy);
+ }
+ break;
}
- break;
+ }
+ }
- case WE_100_TICKS:
- w->SetDirty();
- break;
+ virtual void OnHundredthTick()
+ {
+ this->SetDirty();
+ }
- case WE_RESIZE:
- w->vscroll.cap += e->we.sizing.diff.y / 10;
- break;
+ virtual void OnResize(Point new_size, Point delta)
+ {
+ this->vscroll.cap += delta.y / 10;
}
-}
+};
static const WindowDesc _town_directory_desc = {
WDP_AUTO, WDP_AUTO, 208, 202, 208, 202,
WC_TOWN_DIRECTORY, WC_NONE,
WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS | WDF_STICKY_BUTTON | WDF_RESIZABLE,
_town_directory_widgets,
- TownDirectoryWndProc
};
-
void ShowTownDirectory()
{
- Window *w = AllocateWindowDescFront<Window>(&_town_directory_desc, 0);
-
- if (w != NULL) {
- w->vscroll.cap = 16;
- w->resize.step_height = 10;
- w->resize.height = w->height - 10 * 6; // minimum of 10 items in the list, each item 10 high
- }
+ new TownDirectoryWindow(&_town_directory_desc);
}
void CcBuildTown(bool success, TileIndex tile, uint32 p1, uint32 p2)
@@ -627,85 +629,89 @@
{ WIDGETS_END},
};
-static void ScenEditTownGenWndProc(Window *w, WindowEvent *e)
+struct ScenarioEditorTownGenerationWindow : Window
{
- switch (e->event) {
- case WE_PAINT:
- DrawWindowWidgets(w);
- break;
-
- case WE_CREATE:
- w->LowerWidget(_scengen_town_size + TSEW_SMALLTOWN);
- break;
-
- case WE_CLICK:
- switch (e->we.click.widget) {
- case TSEW_NEWTOWN:
- HandlePlacePushButton(w, TSEW_NEWTOWN, SPR_CURSOR_TOWN, VHM_RECT, PlaceProc_Town);
- break;
-
- case TSEW_RANDOMTOWN: {
- Town *t;
- uint size = min(_scengen_town_size, (int)TSM_CITY);
- TownSizeMode mode = _scengen_town_size > TSM_CITY ? TSM_CITY : TSM_FIXED;
+ ScenarioEditorTownGenerationWindow(const WindowDesc *desc, WindowNumber window_number) : Window(desc, window_number)
+ {
+ this->LowerWidget(_scengen_town_size + TSEW_SMALLTOWN);
+ }
- w->HandleButtonClick(TSEW_RANDOMTOWN);
- _generating_world = true;
- t = CreateRandomTown(20, mode, size);
- _generating_world = false;
-
- if (t == NULL) {
- ShowErrorMessage(STR_NO_SPACE_FOR_TOWN, STR_CANNOT_GENERATE_TOWN, 0, 0);
- } else {
- ScrollMainWindowToTile(t->xy);
- }
- } break;
+ virtual void OnPaint()
+ {
+ this->DrawWidgets();
+ }
- case TSEW_MANYRANDOMTOWNS:
- w->HandleButtonClick(TSEW_MANYRANDOMTOWNS);
+ virtual void OnClick(Point pt, int widget)
+ {
+ switch (widget) {
+ case TSEW_NEWTOWN:
+ HandlePlacePushButton(this, TSEW_NEWTOWN, SPR_CURSOR_TOWN, VHM_RECT, PlaceProc_Town);
+ break;
- _generating_world = true;
- if (!GenerateTowns()) ShowErrorMessage(STR_NO_SPACE_FOR_TOWN, STR_CANNOT_GENERATE_TOWN, 0, 0);
- _generating_world = false;
- break;
+ case TSEW_RANDOMTOWN: {
+ Town *t;
+ uint size = min(_scengen_town_size, (int)TSM_CITY);
+ TownSizeMode mode = _scengen_town_size > TSM_CITY ? TSM_CITY : TSM_FIXED;
- case TSEW_SMALLTOWN: case TSEW_MEDIUMTOWN: case TSEW_LARGETOWN: case TSEW_CITY:
- w->RaiseWidget(_scengen_town_size + TSEW_SMALLTOWN);
- _scengen_town_size = e->we.click.widget - TSEW_SMALLTOWN;
- w->LowerWidget(_scengen_town_size + TSEW_SMALLTOWN);
- w->SetDirty();
- break;
+ this->HandleButtonClick(TSEW_RANDOMTOWN);
+ _generating_world = true;
+ t = CreateRandomTown(20, mode, size);
+ _generating_world = false;
+
+ if (t == NULL) {
+ ShowErrorMessage(STR_NO_SPACE_FOR_TOWN, STR_CANNOT_GENERATE_TOWN, 0, 0);
+ } else {
+ ScrollMainWindowToTile(t->xy);
+ }
} break;
- case WE_TIMEOUT:
- w->RaiseWidget(TSEW_RANDOMTOWN);
- w->RaiseWidget(TSEW_MANYRANDOMTOWNS);
- w->SetDirty();
- break;
+ case TSEW_MANYRANDOMTOWNS:
+ this->HandleButtonClick(TSEW_MANYRANDOMTOWNS);
- case WE_PLACE_OBJ:
- _place_proc(e->we.place.tile);
- break;
+ _generating_world = true;
+ if (!GenerateTowns()) ShowErrorMessage(STR_NO_SPACE_FOR_TOWN, STR_CANNOT_GENERATE_TOWN, 0, 0);
+ _generating_world = false;
+ break;
- case WE_ABORT_PLACE_OBJ:
- w->RaiseButtons();
- w->LowerWidget(_scengen_town_size + TSEW_SMALLTOWN);
- w->SetDirty();
- break;
+ case TSEW_SMALLTOWN: case TSEW_MEDIUMTOWN: case TSEW_LARGETOWN: case TSEW_CITY:
+ this->RaiseWidget(_scengen_town_size + TSEW_SMALLTOWN);
+ _scengen_town_size = widget - TSEW_SMALLTOWN;
+ this->LowerWidget(_scengen_town_size + TSEW_SMALLTOWN);
+ this->SetDirty();
+ break;
+ }
}
-}
+
+ virtual void OnTimeout()
+ {
+ this->RaiseWidget(TSEW_RANDOMTOWN);
+ this->RaiseWidget(TSEW_MANYRANDOMTOWNS);
+ this->SetDirty();
+ }
+
+ virtual void OnPlaceObject(Point pt, TileIndex tile)
+ {
+ _place_proc(tile);
+ }
+
+ virtual void OnPlaceObjectAbort()
+ {
+ this->RaiseButtons();
+ this->LowerWidget(_scengen_town_size + TSEW_SMALLTOWN);
+ this->SetDirty();
+ }
+};
static const WindowDesc _scen_edit_town_gen_desc = {
WDP_AUTO, WDP_AUTO, 160, 95, 160, 95,
WC_SCEN_TOWN_GEN, WC_NONE,
WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_STICKY_BUTTON,
_scen_edit_town_gen_widgets,
- ScenEditTownGenWndProc,
};
void ShowBuildTownWindow()
{
if (_game_mode != GM_EDITOR && !IsValidPlayer(_current_player)) return;
- AllocateWindowDescFront<Window>(&_scen_edit_town_gen_desc, 0);
+ AllocateWindowDescFront<ScenarioEditorTownGenerationWindow>(&_scen_edit_town_gen_desc, 0);
}
--- a/src/track_func.h Mon May 19 14:14:33 2008 +0000
+++ b/src/track_func.h Mon May 19 15:13:58 2008 +0000
@@ -24,8 +24,6 @@
return (Track)a;
}
-
-
/**
* Maps a Track to the corresponding TrackBits value
* @param track the track to convert
@@ -277,7 +275,7 @@
* Converts TrackBits to TrackdirBits while allowing both directions.
*
* @param bits The TrackBits
- * @return The TrackDirBits containing of bits in both directions.
+ * @return The TrackdirBits containing of bits in both directions.
*/
static inline TrackdirBits TrackBitsToTrackdirBits(TrackBits bits)
{
@@ -436,13 +434,35 @@
}
/**
+ * Maps a (4-way) direction to the diagonal track incidating with that diagdir
+ *
+ * @param diagdir The direction
+ * @return The resulting Track
+ */
+static inline Track DiagDirToDiagTrack(DiagDirection diagdir)
+{
+ return (Track)(diagdir & 1);
+}
+
+/**
+ * Maps a (4-way) direction to the diagonal track bits incidating with that diagdir
+ *
+ * @param diagdir The direction
+ * @return The resulting TrackBits
+ */
+static inline TrackBits DiagDirToDiagTrackBits(DiagDirection diagdir)
+{
+ return TrackToTrackBits(DiagDirToDiagTrack(diagdir));
+}
+
+/**
* Maps a (4-way) direction to the diagonal trackdir that runs in that
* direction.
*
* @param diagdir The direction
* @return The resulting Trackdir direction
*/
-static inline Trackdir DiagdirToDiagTrackdir(DiagDirection diagdir)
+static inline Trackdir DiagDirToDiagTrackdir(DiagDirection diagdir)
{
extern const Trackdir _dir_to_diag_trackdir[DIAGDIR_END];
return _dir_to_diag_trackdir[diagdir];
--- a/src/train_cmd.cpp Mon May 19 14:14:33 2008 +0000
+++ b/src/train_cmd.cpp Mon May 19 15:13:58 2008 +0000
@@ -119,6 +119,9 @@
if (engine_has_power) {
uint16 power = GetVehicleProperty(u, 0x0B, rvi_u->power);
if (power != 0) {
+ /* Halve power for multiheaded parts */
+ if (IsMultiheaded(u)) power /= 2;
+
total_power += power;
/* Tractive effort in (tonnes * 1000 * 10 =) N */
max_te += (u->u.rail.cached_veh_weight * 10000 * GetVehicleProperty(u, 0x1F, rvi_u->tractive_effort)) / 256;
@@ -801,7 +804,7 @@
}
InvalidateWindowData(WC_VEHICLE_DEPOT, v->tile);
- RebuildVehicleLists();
+ InvalidateWindowClassesData(WC_TRAINS_LIST, 0);
InvalidateWindow(WC_COMPANY, v->owner);
if (IsLocalPlayer()) {
InvalidateAutoreplaceWindow(v->engine_type, v->group_id); // updates the replace Train window
@@ -1270,7 +1273,7 @@
InvalidateWindow(WC_VEHICLE_DEPOT, dst_head->tile);
}
- RebuildVehicleLists();
+ InvalidateWindowClassesData(WC_TRAINS_LIST, 0);
}
return CommandCost();
@@ -1348,10 +1351,10 @@
if (flags & DC_EXEC) {
if (v == first && IsFrontEngine(first)) {
- delete FindWindowById(WC_VEHICLE_VIEW, first->index);
+ DeleteWindowById(WC_VEHICLE_VIEW, first->index);
}
InvalidateWindow(WC_VEHICLE_DEPOT, first->tile);
- RebuildVehicleLists();
+ InvalidateWindowClassesData(WC_TRAINS_LIST, 0);
}
CommandCost cost(EXPENSES_NEW_VEHICLES);
@@ -1762,7 +1765,7 @@
if (d <= 0) {
leave->vehstatus &= ~VS_HIDDEN; // move it out of the depot
- leave->u.rail.track = AxisToTrackBits(DiagDirToAxis(GetRailDepotDirection(leave->tile)));
+ leave->u.rail.track = TrackToTrackBits(GetRailDepotTrack(leave->tile));
for (int i = 0; i >= d; i--) TrainController(leave, NULL, false); // maybe move it, and maybe let another wagon leave
}
} else {
@@ -1999,7 +2002,7 @@
v->cargo_subtype = new_subtype;
InvalidateWindow(WC_VEHICLE_DETAILS, v->index);
InvalidateWindow(WC_VEHICLE_DEPOT, v->tile);
- RebuildVehicleLists();
+ InvalidateWindowClassesData(WC_TRAINS_LIST, 0);
}
}
}
@@ -2260,7 +2263,7 @@
v->load_unload_time_rem = 0;
- if (UpdateSignalsOnSegment(v->tile, INVALID_DIAGDIR, v->owner)) {
+ if (UpdateSignalsOnSegment(v->tile, INVALID_DIAGDIR, v->owner) == SIGSEG_FULL) {
InvalidateWindowClasses(WC_TRAINS_LIST);
return true;
}
@@ -2448,7 +2451,7 @@
SetDParam(0, v->unitnumber);
AddNewsItem(
STR_TRAIN_IS_LOST,
- NM_SMALL, NF_VIEWPORT | NF_VEHICLE, NT_ADVICE, DNC_NONE,
+ NS_ADVICE,
v->index,
0);
}
@@ -2646,7 +2649,7 @@
SetDParam(0, st->index);
AddNewsItem(
STR_8801_CITIZENS_CELEBRATE_FIRST,
- NM_THIN, NF_VIEWPORT | NF_VEHICLE, v->owner == _local_player ? NT_ARRIVAL_PLAYER : NT_ARRIVAL_OTHER, DNC_NONE,
+ v->owner == _local_player ? NS_ARRIVAL_PLAYER : NS_ARRIVAL_OTHER,
v->index,
0
);
@@ -2804,7 +2807,7 @@
InvalidateWindow(WC_VEHICLE_DEPOT, v->tile);
}
- RebuildVehicleLists();
+ InvalidateWindowClassesData(WC_TRAINS_LIST, 0);
BEGIN_ENUM_WAGONS(v)
v->vehstatus |= VS_CRASHED;
@@ -2893,7 +2896,7 @@
AI_Event(v->owner, new AIEventVehicleCrash(v->index, v->tile));
SetDParam(0, tcc.num);
AddNewsItem(STR_8868_TRAIN_CRASH_DIE_IN_FIREBALL,
- NM_THIN, NF_VIEWPORT | NF_VEHICLE, NT_ACCIDENT, DNC_NONE,
+ NS_ACCIDENT_VEHICLE,
v->index,
0
);
@@ -3152,7 +3155,7 @@
}
}
- RebuildVehicleLists();
+ InvalidateWindowClassesData(WC_TRAINS_LIST, 0);
MarkSingleVehicleDirty(v);
@@ -3502,6 +3505,9 @@
byte cost_factor = GetVehicleProperty(v, 0x0D, rvi->running_cost);
if (cost_factor == 0) continue;
+ /* Halve running cost for multiheaded parts */
+ if (IsMultiheaded(v)) cost_factor /= 2;
+
cost += cost_factor * GetPriceByIndex(rvi->running_cost_class);
} while ((v = GetNextVehicle(v)) != NULL);
@@ -3615,7 +3621,7 @@
SetDParam(0, v->unitnumber);
AddNewsItem(
STR_TRAIN_IS_UNPROFITABLE,
- NM_SMALL, NF_VIEWPORT | NF_VEHICLE, NT_ADVICE, DNC_NONE,
+ NS_ADVICE,
v->index,
0);
}
--- a/src/train_gui.cpp Mon May 19 14:14:33 2008 +0000
+++ b/src/train_gui.cpp Mon May 19 15:13:58 2008 +0000
@@ -18,6 +18,7 @@
#include "order_func.h"
#include "engine_func.h"
#include "engine_base.h"
+#include "window_func.h"
#include "table/sprites.h"
#include "table/strings.h"
@@ -43,7 +44,7 @@
found = GetLastVehicleInChain(found);
/* put the new wagon at the end of the loco. */
DoCommandP(0, _new_vehicle_id | (found->index << 16), 0, NULL, CMD_MOVE_RAIL_VEHICLE);
- RebuildVehicleLists();
+ InvalidateWindowClassesData(WC_TRAINS_LIST, 0);
}
}
--- a/src/transparency_gui.cpp Mon May 19 14:14:33 2008 +0000
+++ b/src/transparency_gui.cpp Mon May 19 15:13:58 2008 +0000
@@ -17,82 +17,86 @@
TransparencyOptionBits _transparency_lock;
TransparencyOptionBits _invisibility_opt;
-enum TransparencyToolbarWidgets{
- TTW_WIDGET_SIGNS = 3, ///< Make signs background transparent
- TTW_WIDGET_TREES, ///< Make trees transparent
- TTW_WIDGET_HOUSES, ///< Make houses transparent
- TTW_WIDGET_INDUSTRIES, ///< Make Industries transparent
- TTW_WIDGET_BUILDINGS, ///< Make player buildings and structures transparent
- TTW_WIDGET_BRIDGES, ///< Make bridges transparent
- TTW_WIDGET_STRUCTURES, ///< Make unmovable structures transparent
- TTW_WIDGET_CATENARY, ///< Make catenary transparent
- TTW_WIDGET_LOADING, ///< Make loading indicators transparent
- TTW_WIDGET_END, ///< End of toggle buttons
-
- /* Panel with buttons for invisibility */
- TTW_BUTTONS = 12, ///< Panel with 'invisibility' buttons
-};
-
-static void TransparencyToolbWndProc(Window *w, WindowEvent *e)
+class TransparenciesWindow : public Window
{
- switch (e->event) {
- case WE_PAINT:
- /* must be sure that the widgets show the transparency variable changes
- * also when we use shortcuts */
- for (uint i = TTW_WIDGET_SIGNS; i < TTW_WIDGET_END; i++) {
- w->SetWidgetLoweredState(i, IsTransparencySet((TransparencyOption)(i - TTW_WIDGET_SIGNS)));
- }
-
- DrawWindowWidgets(w);
- for (uint i = TO_SIGNS; i < TO_END; i++) {
- if (HasBit(_transparency_lock, i)) DrawSprite(SPR_LOCK, PAL_NONE, w->widget[TTW_WIDGET_SIGNS + i].left + 1, w->widget[TTW_WIDGET_SIGNS + i].top + 1);
- }
+ enum TransparencyToolbarWidgets{
+ TTW_WIDGET_SIGNS = 3, ///< Make signs background transparent
+ TTW_WIDGET_TREES, ///< Make trees transparent
+ TTW_WIDGET_HOUSES, ///< Make houses transparent
+ TTW_WIDGET_INDUSTRIES, ///< Make Industries transparent
+ TTW_WIDGET_BUILDINGS, ///< Make player buildings and structures transparent
+ TTW_WIDGET_BRIDGES, ///< Make bridges transparent
+ TTW_WIDGET_STRUCTURES, ///< Make unmovable structures transparent
+ TTW_WIDGET_CATENARY, ///< Make catenary transparent
+ TTW_WIDGET_LOADING, ///< Make loading indicators transparent
+ TTW_WIDGET_END, ///< End of toggle buttons
- /* Do not draw button for invisible loading indicators */
- for (uint i = 0; i < 8; i++) {
- if (i < TTW_WIDGET_BRIDGES - TTW_WIDGET_SIGNS) {
- DrawFrameRect(i * 22, 38, i * 22 + 19, 46, true, HasBit(_invisibility_opt, i) ? FR_LOWERED : FR_NONE);
- } else if (i == TTW_WIDGET_BRIDGES - TTW_WIDGET_SIGNS) {
- DrawFrameRect(i * 22, 38, i * 22 + 41, 46, true, HasBit(_invisibility_opt, i) ? FR_LOWERED : FR_NONE);
- } else { // i > TTW_WIDGET_BRIDGES - TTW_WIDGET_SIGNS
- DrawFrameRect((i + 1) * 22, 38, (i + 1) * 22 + 19, 46, true, HasBit(_invisibility_opt, i) ? FR_LOWERED : FR_NONE);
- }
- }
-
- break;
+ /* Panel with buttons for invisibility */
+ TTW_BUTTONS = 12, ///< Panel with 'invisibility' buttons
+ };
- case WE_CLICK:
- if (e->we.click.widget >= TTW_WIDGET_SIGNS && e->we.click.widget < TTW_WIDGET_END) {
- if (_ctrl_pressed) {
- /* toggle the bit of the transparencies lock variable */
- ToggleTransparencyLock((TransparencyOption)(e->we.click.widget - TTW_WIDGET_SIGNS));
- w->SetDirty();
- } else {
- /* toggle the bit of the transparencies variable and play a sound */
- ToggleTransparency((TransparencyOption)(e->we.click.widget - TTW_WIDGET_SIGNS));
- SndPlayFx(SND_15_BEEP);
- MarkWholeScreenDirty();
- }
- } else if (e->we.click.widget == TTW_BUTTONS) {
- uint x = e->we.click.pt.x / 22;
+public:
+ TransparenciesWindow(const WindowDesc *desc, int window_number) : Window(desc, window_number)
+ {
+ this->FindWindowPlacementAndResize(desc);
+ }
- if (x > TTW_WIDGET_BRIDGES - TTW_WIDGET_SIGNS) x--;
- if (x > TTW_WIDGET_CATENARY - TTW_WIDGET_SIGNS) break;
-
- ToggleInvisibility((TransparencyOption)x);
- SndPlayFx(SND_15_BEEP);
+ virtual void OnPaint()
+ {
+ /* must be sure that the widgets show the transparency variable changes
+ * also when we use shortcuts */
+ for (uint i = TTW_WIDGET_SIGNS; i < TTW_WIDGET_END; i++) {
+ this->SetWidgetLoweredState(i, IsTransparencySet((TransparencyOption)(i - TTW_WIDGET_SIGNS)));
+ }
- /* Redraw whole screen only if transparency is set */
- if (IsTransparencySet((TransparencyOption)x)) {
- MarkWholeScreenDirty();
- } else {
- w->InvalidateWidget(TTW_BUTTONS);
- }
+ this->DrawWidgets();
+ for (uint i = TO_SIGNS; i < TO_END; i++) {
+ if (HasBit(_transparency_lock, i)) DrawSprite(SPR_LOCK, PAL_NONE, this->widget[TTW_WIDGET_SIGNS + i].left + 1, this->widget[TTW_WIDGET_SIGNS + i].top + 1);
+ }
+
+ /* Do not draw button for invisible loading indicators */
+ for (uint i = 0; i < 8; i++) {
+ if (i < TTW_WIDGET_BRIDGES - TTW_WIDGET_SIGNS) {
+ DrawFrameRect(i * 22, 38, i * 22 + 19, 46, true, HasBit(_invisibility_opt, i) ? FR_LOWERED : FR_NONE);
+ } else if (i == TTW_WIDGET_BRIDGES - TTW_WIDGET_SIGNS) {
+ DrawFrameRect(i * 22, 38, i * 22 + 41, 46, true, HasBit(_invisibility_opt, i) ? FR_LOWERED : FR_NONE);
+ } else { // i > TTW_WIDGET_BRIDGES - TTW_WIDGET_SIGNS
+ DrawFrameRect((i + 1) * 22, 38, (i + 1) * 22 + 19, 46, true, HasBit(_invisibility_opt, i) ? FR_LOWERED : FR_NONE);
}
+ }
+ }
- break;
+ virtual void OnClick(Point pt, int widget)
+ {
+ if (widget >= TTW_WIDGET_SIGNS && widget < TTW_WIDGET_END) {
+ if (_ctrl_pressed) {
+ /* toggle the bit of the transparencies lock variable */
+ ToggleTransparencyLock((TransparencyOption)(widget - TTW_WIDGET_SIGNS));
+ this->SetDirty();
+ } else {
+ /* toggle the bit of the transparencies variable and play a sound */
+ ToggleTransparency((TransparencyOption)(widget - TTW_WIDGET_SIGNS));
+ SndPlayFx(SND_15_BEEP);
+ MarkWholeScreenDirty();
+ }
+ } else if (widget == TTW_BUTTONS) {
+ uint x = pt.x / 22;
+
+ if (x > TTW_WIDGET_BRIDGES - TTW_WIDGET_SIGNS) x--;
+ if (x > TTW_WIDGET_CATENARY - TTW_WIDGET_SIGNS) return;
+
+ ToggleInvisibility((TransparencyOption)x);
+ SndPlayFx(SND_15_BEEP);
+
+ /* Redraw whole screen only if transparency is set */
+ if (IsTransparencySet((TransparencyOption)x)) {
+ MarkWholeScreenDirty();
+ } else {
+ this->InvalidateWidget(TTW_BUTTONS);
+ }
+ }
}
-}
+};
static const Widget _transparency_widgets[] = {
{ WWT_CLOSEBOX, RESIZE_NONE, 7, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW},
@@ -121,10 +125,9 @@
WC_TRANSPARENCY_TOOLBAR, WC_NONE,
WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_STICKY_BUTTON,
_transparency_widgets,
- TransparencyToolbWndProc
};
void ShowTransparencyToolbar(void)
{
- AllocateWindowDescFront<Window>(&_transparency_desc, 0);
+ AllocateWindowDescFront<TransparenciesWindow>(&_transparency_desc, 0);
}
--- a/src/tree_gui.cpp Mon May 19 14:14:33 2008 +0000
+++ b/src/tree_gui.cpp Mon May 19 15:13:58 2008 +0000
@@ -16,178 +16,169 @@
#include "table/strings.h"
#include "table/tree_land.h"
-struct tree_d {
- uint16 base;
- uint16 count;
-};
-assert_compile(WINDOW_CUSTOM_SIZE >= sizeof(tree_d));
-
-static int _tree_to_plant;
void PlaceTreesRandomly();
-static const PalSpriteID _tree_sprites[] = {
- { 0x655, PAL_NONE }, { 0x663, PAL_NONE }, { 0x678, PAL_NONE }, { 0x62B, PAL_NONE },
- { 0x647, PAL_NONE }, { 0x639, PAL_NONE }, { 0x64E, PAL_NONE }, { 0x632, PAL_NONE },
- { 0x67F, PAL_NONE }, { 0x68D, PAL_NONE }, { 0x69B, PAL_NONE }, { 0x6A9, PAL_NONE },
- { 0x6AF, PAL_NONE }, { 0x6D2, PAL_NONE }, { 0x6D9, PAL_NONE }, { 0x6C4, PAL_NONE },
- { 0x6CB, PAL_NONE }, { 0x6B6, PAL_NONE }, { 0x6BD, PAL_NONE }, { 0x6E0, PAL_NONE },
- { 0x72E, PAL_NONE }, { 0x734, PAL_NONE }, { 0x74A, PAL_NONE }, { 0x74F, PAL_NONE },
- { 0x76B, PAL_NONE }, { 0x78F, PAL_NONE }, { 0x788, PAL_NONE }, { 0x77B, PAL_NONE },
- { 0x75F, PAL_NONE }, { 0x774, PAL_NONE }, { 0x720, PAL_NONE }, { 0x797, PAL_NONE },
- { 0x79E, PAL_NONE }, { 0x7A5, PALETTE_TO_GREEN }, { 0x7AC, PALETTE_TO_RED }, { 0x7B3, PAL_NONE },
- { 0x7BA, PAL_NONE }, { 0x7C1, PALETTE_TO_RED, }, { 0x7C8, PALETTE_TO_PALE_GREEN }, { 0x7CF, PALETTE_TO_YELLOW }, { 0x7D6, PALETTE_TO_RED }
+class BuildTreesWindow : public Window
+{
+ uint16 base;
+ uint16 count;
+ int tree_to_plant;
+
+ enum BuildTreesWidgets {
+ BTW_CLOSE,
+ BTW_CAPTION,
+ BTW_BACKGROUND,
+ BTW_TYPE_11,
+ BTW_TYPE_12,
+ BTW_TYPE_13,
+ BTW_TYPE_14,
+ BTW_TYPE_21,
+ BTW_TYPE_22,
+ BTW_TYPE_23,
+ BTW_TYPE_24,
+ BTW_TYPE_31,
+ BTW_TYPE_32,
+ BTW_TYPE_33,
+ BTW_TYPE_34,
+ BTW_TYPE_RANDOM,
+ BTW_MANY_RANDOM,
+ };
+
+public:
+ BuildTreesWindow(const WindowDesc *desc, WindowNumber window_number) : Window(desc, window_number)
+ {
+ if (_game_mode != GM_EDITOR) {
+ this->HideWidget(BTW_MANY_RANDOM);
+ int offset = this->widget[BTW_MANY_RANDOM].bottom - this->widget[BTW_MANY_RANDOM].top;
+ this->height -= offset;
+ this->widget[BTW_BACKGROUND].bottom -= offset;
+ }
+ ResetObjectToPlace();
+ this->FindWindowPlacementAndResize(desc);
+ }
+
+ virtual void OnPaint()
+ {
+ static const PalSpriteID tree_sprites[] = {
+ { 0x655, PAL_NONE }, { 0x663, PAL_NONE }, { 0x678, PAL_NONE }, { 0x62B, PAL_NONE },
+ { 0x647, PAL_NONE }, { 0x639, PAL_NONE }, { 0x64E, PAL_NONE }, { 0x632, PAL_NONE },
+ { 0x67F, PAL_NONE }, { 0x68D, PAL_NONE }, { 0x69B, PAL_NONE }, { 0x6A9, PAL_NONE },
+ { 0x6AF, PAL_NONE }, { 0x6D2, PAL_NONE }, { 0x6D9, PAL_NONE }, { 0x6C4, PAL_NONE },
+ { 0x6CB, PAL_NONE }, { 0x6B6, PAL_NONE }, { 0x6BD, PAL_NONE }, { 0x6E0, PAL_NONE },
+ { 0x72E, PAL_NONE }, { 0x734, PAL_NONE }, { 0x74A, PAL_NONE }, { 0x74F, PAL_NONE },
+ { 0x76B, PAL_NONE }, { 0x78F, PAL_NONE }, { 0x788, PAL_NONE }, { 0x77B, PAL_NONE },
+ { 0x75F, PAL_NONE }, { 0x774, PAL_NONE }, { 0x720, PAL_NONE }, { 0x797, PAL_NONE },
+ { 0x79E, PAL_NONE }, { 0x7A5, PALETTE_TO_GREEN }, { 0x7AC, PALETTE_TO_RED }, { 0x7B3, PAL_NONE },
+ { 0x7BA, PAL_NONE }, { 0x7C1, PALETTE_TO_RED, }, { 0x7C8, PALETTE_TO_PALE_GREEN }, { 0x7CF, PALETTE_TO_YELLOW }, { 0x7D6, PALETTE_TO_RED }
+ };
+
+ this->DrawWidgets();
+
+ int i = this->base = _tree_base_by_landscape[_opt.landscape];
+ int count = this->count = _tree_count_by_landscape[_opt.landscape];
+
+ int x = 18;
+ int y = 54;
+ do {
+ DrawSprite(tree_sprites[i].sprite, tree_sprites[i].pal, x, y);
+ x += 35;
+ if (!(++i & 3)) {
+ x -= 35 * 4;
+ y += 47;
+ }
+ } while (--count);
+ }
+
+ virtual void OnClick(Point pt, int widget)
+ {
+ switch (widget) {
+ case BTW_TYPE_11: case BTW_TYPE_12: case BTW_TYPE_13: case BTW_TYPE_14:
+ case BTW_TYPE_21: case BTW_TYPE_22: case BTW_TYPE_23: case BTW_TYPE_24:
+ case BTW_TYPE_31: case BTW_TYPE_32: case BTW_TYPE_33: case BTW_TYPE_34:
+ if (widget - BTW_TYPE_11 >= this->count) break;
+
+ if (HandlePlacePushButton(this, widget, SPR_CURSOR_TREE, VHM_RECT, NULL)) {
+ this->tree_to_plant = this->base + widget - BTW_TYPE_11;
+ }
+ break;
+
+ case BTW_TYPE_RANDOM: // tree of random type.
+ if (HandlePlacePushButton(this, BTW_TYPE_RANDOM, SPR_CURSOR_TREE, VHM_RECT, NULL)) {
+ this->tree_to_plant = -1;
+ }
+ break;
+
+ case BTW_MANY_RANDOM: // place trees randomly over the landscape
+ this->LowerWidget(BTW_MANY_RANDOM);
+ this->flags4 |= 5 << WF_TIMEOUT_SHL;
+ SndPlayFx(SND_15_BEEP);
+ PlaceTreesRandomly();
+ MarkWholeScreenDirty();
+ break;
+ }
+ }
+
+ virtual void OnPlaceObject(Point pt, TileIndex tile)
+ {
+ VpStartPlaceSizing(tile, VPM_X_AND_Y_LIMITED, DDSP_PLANT_TREES);
+ VpSetPlaceSizingLimit(20);
+ }
+
+ virtual void OnPlaceDrag(ViewportPlaceMethod select_method, ViewportDragDropSelectionProcess select_proc, Point pt)
+ {
+ VpSelectTilesWithMethod(pt.x, pt.y, select_method);
+ }
+
+ virtual void OnPlaceMouseUp(ViewportPlaceMethod select_method, ViewportDragDropSelectionProcess select_proc, Point pt, TileIndex start_tile, TileIndex end_tile)
+ {
+ if (pt.x != -1 && select_proc == DDSP_PLANT_TREES) {
+ DoCommandP(end_tile, this->tree_to_plant, start_tile, NULL,
+ CMD_PLANT_TREE | CMD_MSG(STR_2805_CAN_T_PLANT_TREE_HERE));
+ }
+ }
+
+ virtual void OnTimeout()
+ {
+ this->RaiseWidget(BTW_MANY_RANDOM);
+ this->InvalidateWidget(BTW_MANY_RANDOM);
+ }
+
+ virtual void OnPlaceObjectAbort()
+ {
+ this->RaiseButtons();
+ }
};
-static void BuildTreesWndProc(Window *w, WindowEvent *e)
-{
- switch (e->event) {
- case WE_CREATE:
- ResetObjectToPlace();
- break;
-
- case WE_PAINT: {
- DrawWindowWidgets(w);
-
- int i = WP(w, tree_d).base = _tree_base_by_landscape[_opt.landscape];
- int count = WP(w, tree_d).count = _tree_count_by_landscape[_opt.landscape];
-
- int x = 18;
- int y = 54;
- do {
- DrawSprite(_tree_sprites[i].sprite, _tree_sprites[i].pal, x, y);
- x += 35;
- if (!(++i & 3)) {
- x -= 35 * 4;
- y += 47;
- }
- } while (--count);
- } break;
-
- case WE_CLICK: {
- int wid = e->we.click.widget;
-
- switch (wid) {
- case 0:
- ResetObjectToPlace();
- break;
-
- case 3: case 4: case 5: case 6:
- case 7: case 8: case 9: case 10:
- case 11:case 12: case 13: case 14:
- if (wid - 3 >= WP(w, tree_d).count) break;
-
- if (HandlePlacePushButton(w, wid, SPR_CURSOR_TREE, VHM_RECT, NULL)) {
- _tree_to_plant = WP(w, tree_d).base + wid - 3;
- }
- break;
-
- case 15: // tree of random type.
- if (HandlePlacePushButton(w, 15, SPR_CURSOR_TREE, VHM_RECT, NULL)) {
- _tree_to_plant = -1;
- }
- break;
-
- case 16: // place trees randomly over the landscape
- w->LowerWidget(16);
- w->flags4 |= 5 << WF_TIMEOUT_SHL;
- SndPlayFx(SND_15_BEEP);
- PlaceTreesRandomly();
- MarkWholeScreenDirty();
- break;
- }
- } break;
-
- case WE_PLACE_OBJ:
- VpStartPlaceSizing(e->we.place.tile, VPM_X_AND_Y_LIMITED, DDSP_PLANT_TREES);
- VpSetPlaceSizingLimit(20);
- break;
-
- case WE_PLACE_DRAG:
- VpSelectTilesWithMethod(e->we.place.pt.x, e->we.place.pt.y, e->we.place.select_method);
- return;
-
- case WE_PLACE_MOUSEUP:
- if (e->we.place.pt.x != -1 && e->we.place.select_proc == DDSP_PLANT_TREES) {
- DoCommandP(e->we.place.tile, _tree_to_plant, e->we.place.starttile, NULL,
- CMD_PLANT_TREE | CMD_MSG(STR_2805_CAN_T_PLANT_TREE_HERE));
- }
- break;
-
- case WE_TIMEOUT:
- w->RaiseWidget(16);
- break;
-
- case WE_ABORT_PLACE_OBJ:
- w->RaiseButtons();
- break;
- }
-}
-
static const Widget _build_trees_widgets[] = {
-{ WWT_CLOSEBOX, RESIZE_NONE, 7, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW},
-{ WWT_CAPTION, RESIZE_NONE, 7, 11, 142, 0, 13, STR_2802_TREES, STR_018C_WINDOW_TITLE_DRAG_THIS},
-{ WWT_PANEL, RESIZE_NONE, 7, 0, 142, 14, 170, 0x0, STR_NULL},
-{ WWT_PANEL, RESIZE_NONE, 14, 2, 35, 16, 61, 0x0, STR_280D_SELECT_TREE_TYPE_TO_PLANT},
-{ WWT_PANEL, RESIZE_NONE, 14, 37, 70, 16, 61, 0x0, STR_280D_SELECT_TREE_TYPE_TO_PLANT},
-{ WWT_PANEL, RESIZE_NONE, 14, 72, 105, 16, 61, 0x0, STR_280D_SELECT_TREE_TYPE_TO_PLANT},
-{ WWT_PANEL, RESIZE_NONE, 14, 107, 140, 16, 61, 0x0, STR_280D_SELECT_TREE_TYPE_TO_PLANT},
-{ WWT_PANEL, RESIZE_NONE, 14, 2, 35, 63, 108, 0x0, STR_280D_SELECT_TREE_TYPE_TO_PLANT},
-{ WWT_PANEL, RESIZE_NONE, 14, 37, 70, 63, 108, 0x0, STR_280D_SELECT_TREE_TYPE_TO_PLANT},
-{ WWT_PANEL, RESIZE_NONE, 14, 72, 105, 63, 108, 0x0, STR_280D_SELECT_TREE_TYPE_TO_PLANT},
-{ WWT_PANEL, RESIZE_NONE, 14, 107, 140, 63, 108, 0x0, STR_280D_SELECT_TREE_TYPE_TO_PLANT},
-{ WWT_PANEL, RESIZE_NONE, 14, 2, 35, 110, 155, 0x0, STR_280D_SELECT_TREE_TYPE_TO_PLANT},
-{ WWT_PANEL, RESIZE_NONE, 14, 37, 70, 110, 155, 0x0, STR_280D_SELECT_TREE_TYPE_TO_PLANT},
-{ WWT_PANEL, RESIZE_NONE, 14, 72, 105, 110, 155, 0x0, STR_280D_SELECT_TREE_TYPE_TO_PLANT},
-{ WWT_PANEL, RESIZE_NONE, 14, 107, 140, 110, 155, 0x0, STR_280D_SELECT_TREE_TYPE_TO_PLANT},
-{ WWT_TEXTBTN, RESIZE_NONE, 14, 2, 140, 157, 168, STR_TREES_RANDOM_TYPE, STR_TREES_RANDOM_TYPE_TIP},
+{ WWT_CLOSEBOX, RESIZE_NONE, 7, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW}, // BTW_CLOSE
+{ WWT_CAPTION, RESIZE_NONE, 7, 11, 142, 0, 13, STR_2802_TREES, STR_018C_WINDOW_TITLE_DRAG_THIS}, // BTW_CAPTION
+{ WWT_PANEL, RESIZE_NONE, 7, 0, 142, 14, 183, 0x0, STR_NULL}, // BTW_BACKGROUND
+{ WWT_PANEL, RESIZE_NONE, 14, 2, 35, 16, 61, 0x0, STR_280D_SELECT_TREE_TYPE_TO_PLANT}, // BTW_TYPE_11
+{ WWT_PANEL, RESIZE_NONE, 14, 37, 70, 16, 61, 0x0, STR_280D_SELECT_TREE_TYPE_TO_PLANT}, // BTW_TYPE_12
+{ WWT_PANEL, RESIZE_NONE, 14, 72, 105, 16, 61, 0x0, STR_280D_SELECT_TREE_TYPE_TO_PLANT}, // BTW_TYPE_13
+{ WWT_PANEL, RESIZE_NONE, 14, 107, 140, 16, 61, 0x0, STR_280D_SELECT_TREE_TYPE_TO_PLANT}, // BTW_TYPE_14
+{ WWT_PANEL, RESIZE_NONE, 14, 2, 35, 63, 108, 0x0, STR_280D_SELECT_TREE_TYPE_TO_PLANT}, // BTW_TYPE_21
+{ WWT_PANEL, RESIZE_NONE, 14, 37, 70, 63, 108, 0x0, STR_280D_SELECT_TREE_TYPE_TO_PLANT}, // BTW_TYPE_22
+{ WWT_PANEL, RESIZE_NONE, 14, 72, 105, 63, 108, 0x0, STR_280D_SELECT_TREE_TYPE_TO_PLANT}, // BTW_TYPE_23
+{ WWT_PANEL, RESIZE_NONE, 14, 107, 140, 63, 108, 0x0, STR_280D_SELECT_TREE_TYPE_TO_PLANT}, // BTW_TYPE_24
+{ WWT_PANEL, RESIZE_NONE, 14, 2, 35, 110, 155, 0x0, STR_280D_SELECT_TREE_TYPE_TO_PLANT}, // BTW_TYPE_31
+{ WWT_PANEL, RESIZE_NONE, 14, 37, 70, 110, 155, 0x0, STR_280D_SELECT_TREE_TYPE_TO_PLANT}, // BTW_TYPE_32
+{ WWT_PANEL, RESIZE_NONE, 14, 72, 105, 110, 155, 0x0, STR_280D_SELECT_TREE_TYPE_TO_PLANT}, // BTW_TYPE_33
+{ WWT_PANEL, RESIZE_NONE, 14, 107, 140, 110, 155, 0x0, STR_280D_SELECT_TREE_TYPE_TO_PLANT}, // BTW_TYPE_34
+{ WWT_TEXTBTN, RESIZE_NONE, 14, 2, 140, 157, 168, STR_TREES_RANDOM_TYPE, STR_TREES_RANDOM_TYPE_TIP}, // BTW_TYPE_RANDOM
+{ WWT_TEXTBTN, RESIZE_NONE, 14, 2, 140, 170, 181, STR_028A_RANDOM_TREES, STR_028B_PLANT_TREES_RANDOMLY_OVER}, // BTW_MANY_RANDOM
{ WIDGETS_END},
};
static const WindowDesc _build_trees_desc = {
- 497, 22, 143, 171, 143, 171,
- WC_BUILD_TREES, WC_SCEN_LAND_GEN,
- WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET,
- _build_trees_widgets,
- BuildTreesWndProc
-};
-
-static const Widget _build_trees_scen_widgets[] = {
-{ WWT_CLOSEBOX, RESIZE_NONE, 7, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW},
-{ WWT_CAPTION, RESIZE_NONE, 7, 11, 142, 0, 13, STR_2802_TREES, STR_018C_WINDOW_TITLE_DRAG_THIS},
-{ WWT_PANEL, RESIZE_NONE, 7, 0, 142, 14, 183, 0x0, STR_NULL},
-{ WWT_PANEL, RESIZE_NONE, 14, 2, 35, 16, 61, 0x0, STR_280D_SELECT_TREE_TYPE_TO_PLANT},
-{ WWT_PANEL, RESIZE_NONE, 14, 37, 70, 16, 61, 0x0, STR_280D_SELECT_TREE_TYPE_TO_PLANT},
-{ WWT_PANEL, RESIZE_NONE, 14, 72, 105, 16, 61, 0x0, STR_280D_SELECT_TREE_TYPE_TO_PLANT},
-{ WWT_PANEL, RESIZE_NONE, 14, 107, 140, 16, 61, 0x0, STR_280D_SELECT_TREE_TYPE_TO_PLANT},
-{ WWT_PANEL, RESIZE_NONE, 14, 2, 35, 63, 108, 0x0, STR_280D_SELECT_TREE_TYPE_TO_PLANT},
-{ WWT_PANEL, RESIZE_NONE, 14, 37, 70, 63, 108, 0x0, STR_280D_SELECT_TREE_TYPE_TO_PLANT},
-{ WWT_PANEL, RESIZE_NONE, 14, 72, 105, 63, 108, 0x0, STR_280D_SELECT_TREE_TYPE_TO_PLANT},
-{ WWT_PANEL, RESIZE_NONE, 14, 107, 140, 63, 108, 0x0, STR_280D_SELECT_TREE_TYPE_TO_PLANT},
-{ WWT_PANEL, RESIZE_NONE, 14, 2, 35, 110, 155, 0x0, STR_280D_SELECT_TREE_TYPE_TO_PLANT},
-{ WWT_PANEL, RESIZE_NONE, 14, 37, 70, 110, 155, 0x0, STR_280D_SELECT_TREE_TYPE_TO_PLANT},
-{ WWT_PANEL, RESIZE_NONE, 14, 72, 105, 110, 155, 0x0, STR_280D_SELECT_TREE_TYPE_TO_PLANT},
-{ WWT_PANEL, RESIZE_NONE, 14, 107, 140, 110, 155, 0x0, STR_280D_SELECT_TREE_TYPE_TO_PLANT},
-{ WWT_TEXTBTN, RESIZE_NONE, 14, 2, 140, 157, 168, STR_TREES_RANDOM_TYPE, STR_TREES_RANDOM_TYPE_TIP},
-{ WWT_TEXTBTN, RESIZE_NONE, 14, 2, 140, 170, 181, STR_028A_RANDOM_TREES, STR_028B_PLANT_TREES_RANDOMLY_OVER},
-{ WIDGETS_END},
-};
-
-static const WindowDesc _build_trees_scen_desc = {
WDP_AUTO, WDP_AUTO, 143, 184, 143, 184,
WC_BUILD_TREES, WC_NONE,
WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET,
- _build_trees_scen_widgets,
- BuildTreesWndProc
+ _build_trees_widgets,
};
-
void ShowBuildTreesToolbar()
{
- if (!IsValidPlayer(_current_player)) return;
- AllocateWindowDescFront<Window>(&_build_trees_desc, 0);
+ if (_game_mode != GM_EDITOR && !IsValidPlayer(_current_player)) return;
+ AllocateWindowDescFront<BuildTreesWindow>(&_build_trees_desc, 0);
}
-
-void ShowBuildTreesScenToolbar()
-{
- AllocateWindowDescFront<Window>(&_build_trees_scen_desc, 0);
-}
--- a/src/tunnelbridge_cmd.cpp Mon May 19 14:14:33 2008 +0000
+++ b/src/tunnelbridge_cmd.cpp Mon May 19 15:13:58 2008 +0000
@@ -494,7 +494,7 @@
delta = TileOffsByDiagDir(direction);
DiagDirection tunnel_in_way_dir;
- if (OtherAxis(DiagDirToAxis(direction)) == AXIS_X) {
+ if (DiagDirToAxis(direction) == AXIS_Y) {
tunnel_in_way_dir = (TileX(start_tile) < (MapMaxX() / 2)) ? DIAGDIR_SW : DIAGDIR_NE;
} else {
tunnel_in_way_dir = (TileY(start_tile) < (MapMaxX() / 2)) ? DIAGDIR_SE : DIAGDIR_NW;
@@ -558,7 +558,7 @@
MakeRailTunnel(start_tile, _current_player, direction, (RailType)GB(p1, 0, 4));
MakeRailTunnel(end_tile, _current_player, ReverseDiagDir(direction), (RailType)GB(p1, 0, 4));
AddSideToSignalBuffer(start_tile, INVALID_DIAGDIR, _current_player);
- YapfNotifyTrackLayoutChange(start_tile, AxisToTrack(DiagDirToAxis(direction)));
+ YapfNotifyTrackLayoutChange(start_tile, DiagDirToDiagTrack(direction));
} else {
MakeRoadTunnel(start_tile, _current_player, direction, (RoadTypes)GB(p1, 0, 3));
MakeRoadTunnel(end_tile, _current_player, ReverseDiagDir(direction), (RoadTypes)GB(p1, 0, 3));
@@ -623,7 +623,7 @@
AddSideToSignalBuffer(tile, ReverseDiagDir(dir), owner);
AddSideToSignalBuffer(endtile, dir, owner);
- Track track = AxisToTrack(DiagDirToAxis(dir));
+ Track track = DiagDirToDiagTrack(dir);
YapfNotifyTrackLayoutChange(tile, track);
YapfNotifyTrackLayoutChange(endtile, track);
} else {
@@ -691,7 +691,7 @@
AddSideToSignalBuffer(tile, ReverseDiagDir(direction), owner);
AddSideToSignalBuffer(endtile, direction, owner);
- Track track = AxisToTrack(DiagDirToAxis(direction));
+ Track track = DiagDirToDiagTrack(direction);
YapfNotifyTrackLayoutChange(tile, track);
YapfNotifyTrackLayoutChange(endtile, track);
}
@@ -1233,7 +1233,7 @@
DiagDirection dir = GetTunnelBridgeDirection(tile);
if (side != INVALID_DIAGDIR && side != ReverseDiagDir(dir)) return 0;
- return CombineTrackStatus(TrackBitsToTrackdirBits(AxisToTrackBits(DiagDirToAxis(dir))), TRACKDIR_BIT_NONE);
+ return CombineTrackStatus(TrackBitsToTrackdirBits(DiagDirToDiagTrackBits(dir)), TRACKDIR_BIT_NONE);
}
static void ChangeTileOwner_TunnelBridge(TileIndex tile, PlayerID old_player, PlayerID new_player)
--- a/src/vehicle.cpp Mon May 19 14:14:33 2008 +0000
+++ b/src/vehicle.cpp Mon May 19 15:13:58 2008 +0000
@@ -591,11 +591,8 @@
delete this->Next();
}
- Window *w = FindWindowById(WC_MAIN_WINDOW, 0);
- if (w != NULL && w->viewport->follow_vehicle == this->index) {
- ScrollMainWindowTo(this->x_pos, this->y_pos, true); // lock the main view on the vehicle's last position
- w->viewport->follow_vehicle = INVALID_VEHICLE;
- }
+ extern void StopGlobalFollowVehicle(const Vehicle *v);
+ StopGlobalFollowVehicle(this);
}
Vehicle::~Vehicle()
@@ -953,7 +950,7 @@
SetDParam(0, _vehicle_type_names[v->type]);
SetDParam(1, v->unitnumber);
- AddNewsItem(msg, NM_SMALL, NF_VIEWPORT | NF_VEHICLE, NT_ADVICE, DNC_NONE, v->index, 0);
+ AddNewsItem(msg, NS_ADVICE, v->index, 0);
}
void AgeVehicle(Vehicle *v)
@@ -1553,7 +1550,7 @@
* @param color The string to show depending on if we are unloading or loading
* @return A percentage of how full the Vehicle is.
*/
-uint8 CalcPercentVehicleFilled(Vehicle *v, StringID *color)
+uint8 CalcPercentVehicleFilled(const Vehicle *v, StringID *color)
{
int count = 0;
int max = 0;
@@ -1652,7 +1649,7 @@
/* Notify the user that we stopped the vehicle */
SetDParam(0, _vehicle_type_names[v->type]);
SetDParam(1, v->unitnumber);
- AddNewsItem(STR_ORDER_REFIT_FAILED, NM_SMALL, NF_VIEWPORT | NF_VEHICLE, NT_ADVICE, DNC_NONE, v->index, 0);
+ AddNewsItem(STR_ORDER_REFIT_FAILED, NS_ADVICE, v->index, 0);
}
} else if (v->owner == _local_player && cost.GetCost() != 0) {
ShowCostOrIncomeAnimation(v->x_pos, v->y_pos, v->z_pos, cost.GetCost());
@@ -1678,7 +1675,7 @@
}
SetDParam(0, v->unitnumber);
- AddNewsItem(string, NM_SMALL, NF_VIEWPORT | NF_VEHICLE, NT_ADVICE, DNC_NONE, v->index, 0);
+ AddNewsItem(string, NS_ADVICE, v->index, 0);
}
AI_Event(v->owner, new AIEventVehicleWaitingInDepot(v->index));
}
@@ -1738,7 +1735,7 @@
if (flags & DC_EXEC) {
free(v->name);
v->name = strdup(_cmd_text);
- ResortVehicleLists();
+ InvalidateWindowClassesData(WC_TRAINS_LIST, 1);
MarkWholeScreenDirty();
}
@@ -1869,34 +1866,34 @@
switch (v->type) {
case VEH_TRAIN:
if (v->u.rail.track == TRACK_BIT_DEPOT) // We'll assume the train is facing outwards
- return DiagdirToDiagTrackdir(GetRailDepotDirection(v->tile)); // Train in depot
+ return DiagDirToDiagTrackdir(GetRailDepotDirection(v->tile)); // Train in depot
if (v->u.rail.track == TRACK_BIT_WORMHOLE) // train in tunnel, so just use his direction and assume a diagonal track
- return DiagdirToDiagTrackdir(DirToDiagDir(v->direction));
+ return DiagDirToDiagTrackdir(DirToDiagDir(v->direction));
return TrackDirectionToTrackdir(FindFirstTrack(v->u.rail.track), v->direction);
case VEH_SHIP:
if (v->IsInDepot())
// We'll assume the ship is facing outwards
- return DiagdirToDiagTrackdir(GetShipDepotDirection(v->tile));
+ return DiagDirToDiagTrackdir(GetShipDepotDirection(v->tile));
return TrackDirectionToTrackdir(FindFirstTrack(v->u.ship.state), v->direction);
case VEH_ROAD:
if (v->IsInDepot()) // We'll assume the road vehicle is facing outwards
- return DiagdirToDiagTrackdir(GetRoadDepotDirection(v->tile));
+ return DiagDirToDiagTrackdir(GetRoadDepotDirection(v->tile));
if (IsStandardRoadStopTile(v->tile)) // We'll assume the road vehicle is facing outwards
- return DiagdirToDiagTrackdir(GetRoadStopDir(v->tile)); // Road vehicle in a station
-
- if (IsDriveThroughStopTile(v->tile)) return DiagdirToDiagTrackdir(DirToDiagDir(v->direction));
+ return DiagDirToDiagTrackdir(GetRoadStopDir(v->tile)); // Road vehicle in a station
+
+ if (IsDriveThroughStopTile(v->tile)) return DiagDirToDiagTrackdir(DirToDiagDir(v->direction));
/* If vehicle's state is a valid track direction (vehicle is not turning around) return it */
if (!IsReversingRoadTrackdir((Trackdir)v->u.road.state)) return (Trackdir)v->u.road.state;
/* Vehicle is turning around, get the direction from vehicle's direction */
- return DiagdirToDiagTrackdir(DirToDiagDir(v->direction));
+ return DiagDirToDiagTrackdir(DirToDiagDir(v->direction));
/* case VEH_AIRCRAFT: case VEH_EFFECT: case VEH_DISASTER: */
default: return INVALID_TRACKDIR;
@@ -2759,7 +2756,11 @@
memcpy(dest, backup, sizeof(Vehicle));
/* We decreased the engine count when we sold the engines so we will increase it again. */
- if (IsEngineCountable(backup)) p->num_engines[backup->engine_type]++;
+ if (IsEngineCountable(backup)) {
+ p->num_engines[backup->engine_type]++;
+ if (IsValidGroupID(backup->group_id)) GetGroup(backup->group_id)->num_engines[backup->engine_type]++;
+ if (backup->IsPrimaryVehicle()) IncreaseGroupNumVehicle(backup->group_id);
+ }
/* Update hash. */
Vehicle *dummy = dest;
@@ -2806,11 +2807,11 @@
{
if (!ContainsBackup()) return v;
if (v != NULL) {
- ChangeVehicleViewWindow(v, INVALID_VEHICLE);
+ ChangeVehicleViewWindow(v->index, INVALID_VEHICLE);
DoCommand(0, v->index, 1, DC_EXEC, GetCmdSellVeh(v));
}
v = RestoreBackupVehicle(this->vehicles, p);
- ChangeVehicleViewWindow(INVALID_VEHICLE, v);
+ ChangeVehicleViewWindow(INVALID_VEHICLE, v->index);
if (orders != NULL) RestoreVehicleOrdersBruteForce(v, orders);
if (economy != NULL) economy->Restore();
/* If we stored cargo as well then we should restore it. */
--- a/src/vehicle_func.h Mon May 19 14:14:33 2008 +0000
+++ b/src/vehicle_func.h Mon May 19 15:13:58 2008 +0000
@@ -32,7 +32,7 @@
void *VehicleFromPosXY(int x, int y, void *data, VehicleFromPosProc *proc);
void CallVehicleTicks();
Vehicle *FindVehicleOnTileZ(TileIndex tile, byte z);
-uint8 CalcPercentVehicleFilled(Vehicle *v, StringID *color);
+uint8 CalcPercentVehicleFilled(const Vehicle *v, StringID *color);
void InitializeTrains();
byte VehicleRandomBits();
--- a/src/vehicle_gui.cpp Mon May 19 14:14:33 2008 +0000
+++ b/src/vehicle_gui.cpp Mon May 19 15:13:58 2008 +0000
@@ -40,20 +40,6 @@
#include "table/sprites.h"
#include "table/strings.h"
-struct vehicledetails_d {
- byte tab;
-};
-assert_compile(WINDOW_CUSTOM_SIZE >= sizeof(vehicledetails_d));
-
-struct refit_d {
- int sel;
- struct RefitOption *cargo;
- struct RefitList *list;
- uint length;
- VehicleOrderID order;
-};
-assert_compile(WINDOW_CUSTOM_SIZE >= sizeof(refit_d));
-
Sorting _sorting;
static bool _internal_sort_order; // descending/ascending
@@ -100,47 +86,6 @@
INVALID_STRING_ID
};
-/**
- * Set sort list flag for all vehicle list windows
- * @param sl_flag Sort list flag to set
- */
-static void SetVehicleListsFlag(SortListFlags sl_flag)
-{
- Window* const *wz;
-
- FOR_ALL_WINDOWS(wz) {
- Window *w = *wz;
-
- switch (w->window_class) {
- case WC_TRAINS_LIST:
- case WC_ROADVEH_LIST:
- case WC_SHIPS_LIST:
- case WC_AIRCRAFT_LIST:
- dynamic_cast<VehicleListBase*>(w)->vehicles.flags |= sl_flag;
- w->SetDirty();
- break;
-
- default: break;
- }
- }
-}
-
-/**
- * Rebuild all vehicle list windows
- */
-void RebuildVehicleLists()
-{
- SetVehicleListsFlag(VL_REBUILD);
-}
-
-/**
- * Resort all vehicle list windows
- */
-void ResortVehicleLists()
-{
- SetVehicleListsFlag(VL_RESORT);
-}
-
void BuildVehicleList(VehicleListBase *vl, PlayerID owner, uint16 index, uint16 window_type)
{
if (!(vl->vehicles.flags & VL_REBUILD)) return;
@@ -333,89 +278,141 @@
return selected;
}
-static void VehicleRefitWndProc(Window *w, WindowEvent *e)
-{
- switch (e->event) {
- case WE_PAINT: {
- Vehicle *v = GetVehicle(w->window_number);
+struct RefitWindow : public Window {
+ int sel;
+ RefitOption *cargo;
+ RefitList *list;
+ uint length;
+ VehicleOrderID order;
- if (v->type == VEH_TRAIN) {
- uint length = CountVehiclesInChain(v);
+ RefitWindow(const WindowDesc *desc, const Vehicle *v, VehicleOrderID order) : Window(desc, v->index)
+ {
+ this->caption_color = v->owner;
+ this->vscroll.cap = 8;
+ this->resize.step_height = 14;
- if (length != WP(w, refit_d).length) {
- /* Consist length has changed, so rebuild the refit list */
- free(WP(w, refit_d).list->items);
- free(WP(w, refit_d).list);
- WP(w, refit_d).list = BuildRefitList(v);
- WP(w, refit_d).length = length;
+ this->order = order;
+ this->sel = -1;
+ this->list = BuildRefitList(v);
+ if (v->type == VEH_TRAIN) this->length = CountVehiclesInChain(v);
+ SetVScrollCount(this, this->list->num_lines);
+
+ switch (v->type) {
+ case VEH_TRAIN:
+ this->widget[3].tooltips = STR_RAIL_SELECT_TYPE_OF_CARGO_FOR;
+ this->widget[6].data = STR_RAIL_REFIT_VEHICLE;
+ this->widget[6].tooltips = STR_RAIL_REFIT_TO_CARRY_HIGHLIGHTED;
+ break;
+
+ case VEH_ROAD:
+ this->widget[3].tooltips = STR_ROAD_SELECT_TYPE_OF_CARGO_FOR;
+ this->widget[6].data = STR_REFIT_ROAD_VEHICLE;
+ this->widget[6].tooltips = STR_REFIT_ROAD_VEHICLE_TO_CARRY_HIGHLIGHTED;
+ break;
+
+ case VEH_SHIP:
+ this->widget[3].tooltips = STR_983D_SELECT_TYPE_OF_CARGO_FOR;
+ this->widget[6].data = STR_983C_REFIT_SHIP;
+ this->widget[6].tooltips = STR_983E_REFIT_SHIP_TO_CARRY_HIGHLIGHTED;
+ break;
+
+ case VEH_AIRCRAFT:
+ this->widget[3].tooltips = STR_A03E_SELECT_TYPE_OF_CARGO_FOR;
+ this->widget[6].data = STR_A03D_REFIT_AIRCRAFT;
+ this->widget[6].tooltips = STR_A03F_REFIT_AIRCRAFT_TO_CARRY;
+ break;
+
+ default: NOT_REACHED();
+ }
+
+ this->FindWindowPlacementAndResize(desc);
+ }
+
+ ~RefitWindow()
+ {
+ free(this->list->items);
+ free(this->list);
+ }
+
+ virtual void OnPaint()
+ {
+ Vehicle *v = GetVehicle(this->window_number);
+
+ if (v->type == VEH_TRAIN) {
+ uint length = CountVehiclesInChain(v);
+
+ if (length != this->length) {
+ /* Consist length has changed, so rebuild the refit list */
+ free(this->list->items);
+ free(this->list);
+ this->list = BuildRefitList(v);
+ this->length = length;
+ }
+ }
+
+ SetVScrollCount(this, this->list->num_lines);
+
+ SetDParam(0, v->index);
+ this->DrawWidgets();
+
+ this->cargo = DrawVehicleRefitWindow(this->list, this->sel, this->vscroll.pos, this->vscroll.cap, this->resize.step_height);
+
+ if (this->cargo != NULL) {
+ CommandCost cost;
+
+ cost = DoCommand(v->tile, v->index, this->cargo->cargo | this->cargo->subtype << 8,
+ DC_QUERY_COST, GetCmdRefitVeh(v->type));
+
+ if (CmdSucceeded(cost)) {
+ SetDParam(0, this->cargo->cargo);
+ SetDParam(1, _returned_refit_capacity);
+ SetDParam(2, cost.GetCost());
+ DrawString(2, this->widget[5].top + 1, STR_9840_NEW_CAPACITY_COST_OF_REFIT, TC_FROMSTRING);
+ }
+ }
+ }
+
+ virtual void OnClick(Point pt, int widget)
+ {
+ switch (widget) {
+ case 3: { // listbox
+ int y = pt.y - this->widget[3].top;
+ if (y >= 0) {
+ this->sel = (y / (int)this->resize.step_height) + this->vscroll.pos;
+ this->SetDirty();
}
+ break;
}
- SetVScrollCount(w, WP(w, refit_d).list->num_lines);
-
- SetDParam(0, v->index);
- DrawWindowWidgets(w);
-
- WP(w, refit_d).cargo = DrawVehicleRefitWindow(WP(w, refit_d).list, WP(w, refit_d).sel, w->vscroll.pos, w->vscroll.cap, w->resize.step_height);
-
- if (WP(w, refit_d).cargo != NULL) {
- CommandCost cost;
-
- cost = DoCommand(v->tile, v->index, WP(w, refit_d).cargo->cargo | WP(w, refit_d).cargo->subtype << 8,
- DC_QUERY_COST, GetCmdRefitVeh(GetVehicle(w->window_number)->type));
+ case 6: // refit button
+ if (this->cargo != NULL) {
+ const Vehicle *v = GetVehicle(this->window_number);
- if (CmdSucceeded(cost)) {
- SetDParam(0, WP(w, refit_d).cargo->cargo);
- SetDParam(1, _returned_refit_capacity);
- SetDParam(2, cost.GetCost());
- DrawString(2, w->widget[5].top + 1, STR_9840_NEW_CAPACITY_COST_OF_REFIT, TC_FROMSTRING);
- }
- }
- } break;
+ if (this->order == INVALID_VEH_ORDER_ID) {
+ int command = 0;
- case WE_CLICK:
- switch (e->we.click.widget) {
- case 3: { // listbox
- int y = e->we.click.pt.y - w->widget[3].top;
- if (y >= 0) {
- WP(w, refit_d).sel = (y / (int)w->resize.step_height) + w->vscroll.pos;
- w->SetDirty();
+ switch (v->type) {
+ default: NOT_REACHED();
+ case VEH_TRAIN: command = CMD_REFIT_RAIL_VEHICLE | CMD_MSG(STR_RAIL_CAN_T_REFIT_VEHICLE); break;
+ case VEH_ROAD: command = CMD_REFIT_ROAD_VEH | CMD_MSG(STR_REFIT_ROAD_VEHICLE_CAN_T); break;
+ case VEH_SHIP: command = CMD_REFIT_SHIP | CMD_MSG(STR_9841_CAN_T_REFIT_SHIP); break;
+ case VEH_AIRCRAFT: command = CMD_REFIT_AIRCRAFT | CMD_MSG(STR_A042_CAN_T_REFIT_AIRCRAFT); break;
+ }
+ if (DoCommandP(v->tile, v->index, this->cargo->cargo | this->cargo->subtype << 8, NULL, command)) delete this;
+ } else {
+ if (DoCommandP(v->tile, v->index, this->cargo->cargo | this->cargo->subtype << 8 | this->order << 16, NULL, CMD_ORDER_REFIT)) delete this;
}
- } break;
- case 6: // refit button
- if (WP(w, refit_d).cargo != NULL) {
- const Vehicle *v = GetVehicle(w->window_number);
-
- if (WP(w, refit_d).order == INVALID_VEH_ORDER_ID) {
- int command = 0;
+ }
+ break;
+ }
+ }
- switch (v->type) {
- default: NOT_REACHED();
- case VEH_TRAIN: command = CMD_REFIT_RAIL_VEHICLE | CMD_MSG(STR_RAIL_CAN_T_REFIT_VEHICLE); break;
- case VEH_ROAD: command = CMD_REFIT_ROAD_VEH | CMD_MSG(STR_REFIT_ROAD_VEHICLE_CAN_T); break;
- case VEH_SHIP: command = CMD_REFIT_SHIP | CMD_MSG(STR_9841_CAN_T_REFIT_SHIP); break;
- case VEH_AIRCRAFT: command = CMD_REFIT_AIRCRAFT | CMD_MSG(STR_A042_CAN_T_REFIT_AIRCRAFT); break;
- }
- if (DoCommandP(v->tile, v->index, WP(w, refit_d).cargo->cargo | WP(w, refit_d).cargo->subtype << 8, NULL, command)) delete w;
- } else {
- if (DoCommandP(v->tile, v->index, WP(w, refit_d).cargo->cargo | WP(w, refit_d).cargo->subtype << 8 | WP(w, refit_d).order << 16, NULL, CMD_ORDER_REFIT)) delete w;
- }
- }
- break;
- }
- break;
-
- case WE_RESIZE:
- w->vscroll.cap += e->we.sizing.diff.y / (int)w->resize.step_height;
- w->widget[3].data = (w->vscroll.cap << 8) + 1;
- break;
-
- case WE_DESTROY:
- free(WP(w, refit_d).list->items);
- free(WP(w, refit_d).list);
- break;
+ virtual void OnResize(Point new_size, Point delta)
+ {
+ this->vscroll.cap += delta.y / (int)this->resize.step_height;
+ this->widget[3].data = (this->vscroll.cap << 8) + 1;
}
-}
+};
static const Widget _vehicle_refit_widgets[] = {
@@ -435,7 +432,6 @@
WC_VEHICLE_REFIT, WC_VEHICLE_VIEW,
WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS | WDF_RESIZABLE,
_vehicle_refit_widgets,
- VehicleRefitWndProc,
};
/** Show the refit window for a vehicle
@@ -444,46 +440,8 @@
*/
void ShowVehicleRefitWindow(const Vehicle *v, VehicleOrderID order)
{
- Window *w;
-
DeleteWindowById(WC_VEHICLE_REFIT, v->index);
-
- w = AllocateWindowDescFront<Window>(&_vehicle_refit_desc, v->index);
- WP(w, refit_d).order = order;
-
- if (w != NULL) {
- w->caption_color = v->owner;
- w->vscroll.cap = 8;
- w->resize.step_height = 14;
- WP(w, refit_d).sel = -1;
- WP(w, refit_d).list = BuildRefitList(v);
- if (v->type == VEH_TRAIN) WP(w, refit_d).length = CountVehiclesInChain(v);
- SetVScrollCount(w, WP(w, refit_d).list->num_lines);
-
- switch (v->type) {
- case VEH_TRAIN:
- w->widget[3].tooltips = STR_RAIL_SELECT_TYPE_OF_CARGO_FOR;
- w->widget[6].data = STR_RAIL_REFIT_VEHICLE;
- w->widget[6].tooltips = STR_RAIL_REFIT_TO_CARRY_HIGHLIGHTED;
- break;
- case VEH_ROAD:
- w->widget[3].tooltips = STR_ROAD_SELECT_TYPE_OF_CARGO_FOR;
- w->widget[6].data = STR_REFIT_ROAD_VEHICLE;
- w->widget[6].tooltips = STR_REFIT_ROAD_VEHICLE_TO_CARRY_HIGHLIGHTED;
- break;
- case VEH_SHIP:
- w->widget[3].tooltips = STR_983D_SELECT_TYPE_OF_CARGO_FOR;
- w->widget[6].data = STR_983C_REFIT_SHIP;
- w->widget[6].tooltips = STR_983E_REFIT_SHIP_TO_CARRY_HIGHLIGHTED;
- break;
- case VEH_AIRCRAFT:
- w->widget[3].tooltips = STR_A03E_SELECT_TYPE_OF_CARGO_FOR;
- w->widget[6].data = STR_A03D_REFIT_AIRCRAFT;
- w->widget[6].tooltips = STR_A03F_REFIT_AIRCRAFT_TO_CARRY;
- break;
- default: NOT_REACHED();
- }
- }
+ new RefitWindow(&_vehicle_refit_desc, v, order);
}
/** Display additional text from NewGRF in the purchase information window */
@@ -841,7 +799,7 @@
*/
struct VehicleListWindow : public Window, public VehicleListBase {
- VehicleListWindow(const WindowDesc *desc, void *data, WindowNumber window_number) : Window(desc, data, window_number)
+ VehicleListWindow(const WindowDesc *desc, WindowNumber window_number) : Window(desc, window_number)
{
uint16 window_type = this->window_number & VLW_MASK;
PlayerID player = (PlayerID)GB(this->window_number, 0, 8);
@@ -1028,12 +986,12 @@
VLW_WIDGET_START_ALL,
WIDGET_LIST_END);
- DrawWindowWidgets(this);
+ this->DrawWidgets();
/* draw sorting criteria string */
DrawString(85, 15, _vehicle_sort_listing[this->vehicles.sort_type], TC_BLACK);
/* draw arrow pointing up/down for ascending/descending sorting */
- DrawSortButtonState(this, VLW_WIDGET_SORT_ORDER, this->vehicles.flags & VL_DESC ? SBS_DOWN : SBS_UP);
+ this->DrawSortButtonState(VLW_WIDGET_SORT_ORDER, this->vehicles.flags & VL_DESC ? SBS_DOWN : SBS_UP);
max = min(this->vscroll.pos + this->vscroll.cap, this->vehicles.list_length);
for (i = this->vscroll.pos; i < max; ++i) {
@@ -1187,6 +1145,11 @@
this->vscroll.cap += delta.y / (int)this->resize.step_height;
this->widget[VLW_WIDGET_LIST].data = (this->vscroll.cap << 8) + 1;
}
+
+ virtual void OnInvalidateData(int data)
+ {
+ this->vehicles.flags |= (data == 0 ? VL_REBUILD : VL_RESORT);
+ }
};
static const WindowDesc _player_vehicle_list_train_desc = {
@@ -1194,7 +1157,6 @@
WC_TRAINS_LIST, WC_NONE,
WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS | WDF_STICKY_BUTTON | WDF_RESIZABLE,
_vehicle_list_widgets,
- NULL
};
static const WindowDesc _player_vehicle_list_road_veh_desc = {
@@ -1202,7 +1164,6 @@
WC_ROADVEH_LIST, WC_NONE,
WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS | WDF_STICKY_BUTTON | WDF_RESIZABLE,
_vehicle_list_widgets,
- NULL
};
static const WindowDesc _player_vehicle_list_ship_desc = {
@@ -1210,7 +1171,6 @@
WC_SHIPS_LIST, WC_NONE,
WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS | WDF_STICKY_BUTTON | WDF_RESIZABLE,
_vehicle_list_widgets,
- NULL
};
static const WindowDesc _player_vehicle_list_aircraft_desc = {
@@ -1218,7 +1178,6 @@
WC_AIRCRAFT_LIST, WC_NONE,
WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS | WDF_STICKY_BUTTON | WDF_RESIZABLE,
_vehicle_list_widgets,
- NULL
};
static void ShowVehicleListWindowLocal(PlayerID player, uint16 VLW_flag, VehicleType vehicle_type, uint16 unique_number)
@@ -1374,78 +1333,6 @@
},
};
-/** Initialize a newly created vehicle details window */
-void CreateVehicleDetailsWindow(Window *w)
-{
- const Vehicle *v = GetVehicle(w->window_number);
-
- switch (v->type) {
- case VEH_TRAIN:
- ResizeWindow(w, 0, 39);
-
- w->vscroll.cap = 6;
- w->height += 12;
- w->resize.step_height = 14;
- w->resize.height = w->height - 14 * 2; // Minimum of 4 wagons in the display
-
- w->widget[VLD_WIDGET_RENAME_VEHICLE].tooltips = STR_8867_NAME_TRAIN;
- w->widget[VLD_WIDGET_CAPTION].data = STR_8802_DETAILS;
- break;
-
- case VEH_ROAD: {
- w->widget[VLD_WIDGET_CAPTION].data = STR_900C_DETAILS;
- w->widget[VLD_WIDGET_RENAME_VEHICLE].tooltips = STR_902E_NAME_ROAD_VEHICLE;
-
- if (!RoadVehHasArticPart(v)) break;
-
- /* Draw the text under the vehicle instead of next to it, minus the
- * height already allocated for the cargo of the first vehicle. */
- uint height_extension = 15 - 11;
-
- /* Add space for the cargo amount for each part. */
- for (const Vehicle *u = v; u != NULL; u = u->Next()) {
- height_extension += 11;
- }
-
- ResizeWindow(w, 0, height_extension);
- } break;
-
- case VEH_SHIP:
- w->widget[VLD_WIDGET_RENAME_VEHICLE].tooltips = STR_982F_NAME_SHIP;
- w->widget[VLD_WIDGET_CAPTION].data = STR_9811_DETAILS;
- break;
-
- case VEH_AIRCRAFT:
- ResizeWindow(w, 0, 11);
- w->widget[VLD_WIDGET_RENAME_VEHICLE].tooltips = STR_A032_NAME_AIRCRAFT;
- w->widget[VLD_WIDGET_CAPTION].data = STR_A00C_DETAILS;
- break;
- default: NOT_REACHED();
- }
-
- if (v->type != VEH_TRAIN) {
- w->vscroll.cap = 1;
- w->widget[VLD_WIDGET_MIDDLE_DETAILS].right += 12;
- }
-
- w->widget[VLD_WIDGET_MIDDLE_DETAILS].data = (w->vscroll.cap << 8) + 1;
- w->caption_color = v->owner;
-
- WP(w, vehicledetails_d).tab = 0;
-}
-
-/** Checks whether service interval is enabled for the vehicle. */
-static inline bool IsVehicleServiceIntervalEnabled(const VehicleType vehicle_type)
-{
- switch (vehicle_type) {
- default: NOT_REACHED();
- case VEH_TRAIN: return _patches.servint_trains != 0; break;
- case VEH_ROAD: return _patches.servint_roadveh != 0; break;
- case VEH_SHIP: return _patches.servint_ships != 0; break;
- case VEH_AIRCRAFT: return _patches.servint_aircraft != 0; break;
- }
- return false; // kill a compiler warning
-}
extern int GetTrainDetailsWndVScroll(VehicleID veh_id, byte det_tab);
extern void DrawTrainDetails(const Vehicle *v, int x, int y, int vscroll_pos, uint16 vscroll_cap, byte det_tab);
@@ -1453,201 +1340,267 @@
extern void DrawShipDetails(const Vehicle *v, int x, int y);
extern void DrawAircraftDetails(const Vehicle *v, int x, int y);
-/**
-* Draw the details for the given vehicle at the position (x, y) of the Details windows
-*
-* @param v current vehicle
-* @param x The x coordinate
-* @param y The y coordinate
-* @param vscroll_pos (train only)
-* @param vscroll_cap (train only)
-* @param det_tab (train only)
-*/
-static inline void DrawVehicleDetails(const Vehicle *v, int x, int y, int vscroll_pos, uint vscroll_cap, byte det_tab)
-{
- switch (v->type) {
- case VEH_TRAIN: DrawTrainDetails(v, x, y, vscroll_pos, vscroll_cap, det_tab); break;
- case VEH_ROAD: DrawRoadVehDetails(v, x, y); break;
- case VEH_SHIP: DrawShipDetails(v, x, y); break;
- case VEH_AIRCRAFT: DrawAircraftDetails(v, x, y); break;
- default: NOT_REACHED();
- }
-}
-
-/** Repaint vehicle details window. */
-static void DrawVehicleDetailsWindow(Window *w)
-{
- const Vehicle *v = GetVehicle(w->window_number);
- byte det_tab = WP(w, vehicledetails_d).tab;
-
- w->SetWidgetDisabledState(VLD_WIDGET_RENAME_VEHICLE, v->owner != _local_player);
-
- if (v->type == VEH_TRAIN) {
- w->DisableWidget(det_tab + VLD_WIDGET_DETAILS_CARGO_CARRIED);
- SetVScrollCount(w, GetTrainDetailsWndVScroll(v->index, det_tab));
- }
+struct VehicleDetailsWindow : Window {
+ int tab;
- w->SetWidgetsHiddenState(v->type != VEH_TRAIN,
- VLD_WIDGET_SCROLLBAR,
- VLD_WIDGET_DETAILS_CARGO_CARRIED,
- VLD_WIDGET_DETAILS_TRAIN_VEHICLES,
- VLD_WIDGET_DETAILS_CAPACITY_OF_EACH,
- VLD_WIDGET_DETAILS_TOTAL_CARGO,
- VLD_WIDGET_RESIZE,
- WIDGET_LIST_END);
-
- /* Disable service-scroller when interval is set to disabled */
- w->SetWidgetsDisabledState(!IsVehicleServiceIntervalEnabled(v->type),
- VLD_WIDGET_INCREASE_SERVICING_INTERVAL,
- VLD_WIDGET_DECREASE_SERVICING_INTERVAL,
- WIDGET_LIST_END);
-
-
- SetDParam(0, v->index);
- DrawWindowWidgets(w);
+ /** Initialize a newly created vehicle details window */
+ VehicleDetailsWindow(const WindowDesc *desc, WindowNumber window_number) : Window(desc, window_number)
+ {
+ const Vehicle *v = GetVehicle(this->window_number);
- /* Draw running cost */
- SetDParam(1, v->age / 366);
- SetDParam(0, (v->age + 365 < v->max_age) ? STR_AGE : STR_AGE_RED);
- SetDParam(2, v->max_age / 366);
- SetDParam(3, v->GetDisplayRunningCost());
- DrawString(2, 15, _vehicle_translation_table[VST_VEHICLE_AGE_RUNNING_COST_YR][v->type], TC_FROMSTRING);
+ switch (v->type) {
+ case VEH_TRAIN:
+ ResizeWindow(this, 0, 39);
- /* Draw max speed */
- switch (v->type) {
- case VEH_TRAIN:
- SetDParam(2, v->GetDisplayMaxSpeed());
- SetDParam(1, v->u.rail.cached_power);
- SetDParam(0, v->u.rail.cached_weight);
- SetDParam(3, v->u.rail.cached_max_te / 1000);
- DrawString(2, 25, (_patches.realistic_acceleration && v->u.rail.railtype != RAILTYPE_MAGLEV) ?
- STR_VEHICLE_INFO_WEIGHT_POWER_MAX_SPEED_MAX_TE :
- STR_VEHICLE_INFO_WEIGHT_POWER_MAX_SPEED, TC_FROMSTRING);
- break;
+ this->vscroll.cap = 6;
+ this->height += 12;
+ this->resize.step_height = 14;
+ this->resize.height = this->height - 14 * 2; // Minimum of 4 wagons in the display
- case VEH_ROAD:
- case VEH_SHIP:
- case VEH_AIRCRAFT:
- SetDParam(0, v->GetDisplayMaxSpeed());
- DrawString(2, 25, _vehicle_translation_table[VST_VEHICLE_MAX_SPEED][v->type], TC_FROMSTRING);
- break;
+ this->widget[VLD_WIDGET_RENAME_VEHICLE].tooltips = STR_8867_NAME_TRAIN;
+ this->widget[VLD_WIDGET_CAPTION].data = STR_8802_DETAILS;
+ break;
- default: NOT_REACHED();
+ case VEH_ROAD: {
+ this->widget[VLD_WIDGET_CAPTION].data = STR_900C_DETAILS;
+ this->widget[VLD_WIDGET_RENAME_VEHICLE].tooltips = STR_902E_NAME_ROAD_VEHICLE;
+
+ if (!RoadVehHasArticPart(v)) break;
+
+ /* Draw the text under the vehicle instead of next to it, minus the
+ * height already allocated for the cargo of the first vehicle. */
+ uint height_extension = 15 - 11;
+
+ /* Add space for the cargo amount for each part. */
+ for (const Vehicle *u = v; u != NULL; u = u->Next()) {
+ height_extension += 11;
+ }
+
+ ResizeWindow(this, 0, height_extension);
+ } break;
+
+ case VEH_SHIP:
+ this->widget[VLD_WIDGET_RENAME_VEHICLE].tooltips = STR_982F_NAME_SHIP;
+ this->widget[VLD_WIDGET_CAPTION].data = STR_9811_DETAILS;
+ break;
+
+ case VEH_AIRCRAFT:
+ ResizeWindow(this, 0, 11);
+ this->widget[VLD_WIDGET_RENAME_VEHICLE].tooltips = STR_A032_NAME_AIRCRAFT;
+ this->widget[VLD_WIDGET_CAPTION].data = STR_A00C_DETAILS;
+ break;
+ default: NOT_REACHED();
+ }
+
+ if (v->type != VEH_TRAIN) {
+ this->vscroll.cap = 1;
+ this->widget[VLD_WIDGET_MIDDLE_DETAILS].right += 12;
+ }
+
+ this->widget[VLD_WIDGET_MIDDLE_DETAILS].data = (this->vscroll.cap << 8) + 1;
+ this->caption_color = v->owner;
+
+ this->tab = 0;
}
- /* Draw profit */
- SetDParam(0, v->GetDisplayProfitThisYear());
- SetDParam(1, v->GetDisplayProfitLastYear());
- DrawString(2, 35, _vehicle_translation_table[VST_VEHICLE_PROFIT_THIS_YEAR_LAST_YEAR][v->type], TC_FROMSTRING);
-
- /* Draw breakdown & reliability */
- SetDParam(0, v->reliability * 100 >> 16);
- SetDParam(1, v->breakdowns_since_last_service);
- DrawString(2, 45, _vehicle_translation_table[VST_VEHICLE_RELIABILITY_BREAKDOWNS][v->type], TC_FROMSTRING);
-
- /* Draw service interval text */
- SetDParam(0, v->service_interval);
- SetDParam(1, v->date_of_last_service);
- DrawString(13, w->height - (v->type != VEH_TRAIN ? 11 : 23), _patches.servint_ispercent ? STR_SERVICING_INTERVAL_PERCENT : STR_883C_SERVICING_INTERVAL_DAYS, TC_FROMSTRING);
-
- switch (v->type) {
- case VEH_TRAIN:
- DrawVehicleDetails(v, 2, 57, w->vscroll.pos, w->vscroll.cap, det_tab);
- break;
-
- case VEH_ROAD:
- case VEH_SHIP:
- case VEH_AIRCRAFT:
- DrawVehicleImage(v, 3, 57, INVALID_VEHICLE, 0, 0);
- DrawVehicleDetails(v, 75, 57, w->vscroll.pos, w->vscroll.cap, det_tab);
- break;
-
- default: NOT_REACHED();
+ /** Checks whether service interval is enabled for the vehicle. */
+ static bool IsVehicleServiceIntervalEnabled(const VehicleType vehicle_type)
+ {
+ switch (vehicle_type) {
+ default: NOT_REACHED();
+ case VEH_TRAIN: return _patches.servint_trains != 0; break;
+ case VEH_ROAD: return _patches.servint_roadveh != 0; break;
+ case VEH_SHIP: return _patches.servint_ships != 0; break;
+ case VEH_AIRCRAFT: return _patches.servint_aircraft != 0; break;
+ }
+ return false; // kill a compiler warning
}
-}
-
-/** Message strings for renaming vehicles indexed by vehicle type. */
-static const StringID _name_vehicle_title[] = {
- STR_8865_NAME_TRAIN,
- STR_902C_NAME_ROAD_VEHICLE,
- STR_9831_NAME_SHIP,
- STR_A030_NAME_AIRCRAFT
-};
-
-/** Message strings for error while renaming indexed by vehicle type. */
-static const StringID _name_vehicle_error[] = {
- STR_8866_CAN_T_NAME_TRAIN,
- STR_902D_CAN_T_NAME_ROAD_VEHICLE,
- STR_9832_CAN_T_NAME_SHIP,
- STR_A031_CAN_T_NAME_AIRCRAFT
-};
-
-/** Window event hook for vehicle details. */
-static void VehicleDetailsWndProc(Window *w, WindowEvent *e)
-{
- switch (e->event) {
- case WE_CREATE:
- CreateVehicleDetailsWindow(w);
- break;
- case WE_PAINT:
- DrawVehicleDetailsWindow(w);
- break;
-
- case WE_CLICK: {
- switch (e->we.click.widget) {
- case VLD_WIDGET_RENAME_VEHICLE: {// rename
- const Vehicle *v = GetVehicle(w->window_number);
- SetDParam(0, v->index);
- ShowQueryString(STR_VEHICLE_NAME, _name_vehicle_title[v->type], 31, 150, w, CS_ALPHANUMERAL);
- } break;
-
- case VLD_WIDGET_INCREASE_SERVICING_INTERVAL: // increase int
- case VLD_WIDGET_DECREASE_SERVICING_INTERVAL: { // decrease int
- int mod = _ctrl_pressed ? 5 : 10;
- const Vehicle *v = GetVehicle(w->window_number);
-
- mod = (e->we.click.widget == VLD_WIDGET_DECREASE_SERVICING_INTERVAL) ? -mod : mod;
- mod = GetServiceIntervalClamped(mod + v->service_interval);
- if (mod == v->service_interval) return;
-
- DoCommandP(v->tile, v->index, mod, NULL, CMD_CHANGE_SERVICE_INT | CMD_MSG(STR_018A_CAN_T_CHANGE_SERVICING));
- } break;
+ /**
+ * Draw the details for the given vehicle at the position (x, y) of the Details windows
+ *
+ * @param v current vehicle
+ * @param x The x coordinate
+ * @param y The y coordinate
+ * @param vscroll_pos (train only)
+ * @param vscroll_cap (train only)
+ * @param det_tab (train only)
+ */
+ static void DrawVehicleDetails(const Vehicle *v, int x, int y, int vscroll_pos, uint vscroll_cap, byte det_tab)
+ {
+ switch (v->type) {
+ case VEH_TRAIN: DrawTrainDetails(v, x, y, vscroll_pos, vscroll_cap, det_tab); break;
+ case VEH_ROAD: DrawRoadVehDetails(v, x, y); break;
+ case VEH_SHIP: DrawShipDetails(v, x, y); break;
+ case VEH_AIRCRAFT: DrawAircraftDetails(v, x, y); break;
+ default: NOT_REACHED();
+ }
+ }
- case VLD_WIDGET_DETAILS_CARGO_CARRIED:
- case VLD_WIDGET_DETAILS_TRAIN_VEHICLES:
- case VLD_WIDGET_DETAILS_CAPACITY_OF_EACH:
- case VLD_WIDGET_DETAILS_TOTAL_CARGO:
- w->SetWidgetsDisabledState(false,
- VLD_WIDGET_DETAILS_CARGO_CARRIED,
- VLD_WIDGET_DETAILS_TRAIN_VEHICLES,
- VLD_WIDGET_DETAILS_CAPACITY_OF_EACH,
- VLD_WIDGET_DETAILS_TOTAL_CARGO,
- e->we.click.widget,
- WIDGET_LIST_END);
+ /** Repaint vehicle details window. */
+ virtual void OnPaint()
+ {
+ const Vehicle *v = GetVehicle(this->window_number);
+ byte det_tab = this->tab;
- WP(w, vehicledetails_d).tab = e->we.click.widget - VLD_WIDGET_DETAILS_CARGO_CARRIED;
- w->SetDirty();
- break;
- }
- } break;
+ this->SetWidgetDisabledState(VLD_WIDGET_RENAME_VEHICLE, v->owner != _local_player);
- case WE_ON_EDIT_TEXT:
- if (!StrEmpty(e->we.edittext.str)) {
- _cmd_text = e->we.edittext.str;
- DoCommandP(0, w->window_number, 0, NULL, CMD_NAME_VEHICLE | CMD_MSG(_name_vehicle_error[GetVehicle(w->window_number)->type]));
- }
- break;
+ if (v->type == VEH_TRAIN) {
+ this->DisableWidget(det_tab + VLD_WIDGET_DETAILS_CARGO_CARRIED);
+ SetVScrollCount(this, GetTrainDetailsWndVScroll(v->index, det_tab));
+ }
- case WE_RESIZE:
- if (e->we.sizing.diff.x != 0) ResizeButtons(w, VLD_WIDGET_DETAILS_CARGO_CARRIED, VLD_WIDGET_DETAILS_TOTAL_CARGO);
- if (e->we.sizing.diff.y == 0) break;
+ this->SetWidgetsHiddenState(v->type != VEH_TRAIN,
+ VLD_WIDGET_SCROLLBAR,
+ VLD_WIDGET_DETAILS_CARGO_CARRIED,
+ VLD_WIDGET_DETAILS_TRAIN_VEHICLES,
+ VLD_WIDGET_DETAILS_CAPACITY_OF_EACH,
+ VLD_WIDGET_DETAILS_TOTAL_CARGO,
+ VLD_WIDGET_RESIZE,
+ WIDGET_LIST_END);
- w->vscroll.cap += e->we.sizing.diff.y / 14;
- w->widget[VLD_WIDGET_MIDDLE_DETAILS].data = (w->vscroll.cap << 8) + 1;
- break;
+ /* Disable service-scroller when interval is set to disabled */
+ this->SetWidgetsDisabledState(!IsVehicleServiceIntervalEnabled(v->type),
+ VLD_WIDGET_INCREASE_SERVICING_INTERVAL,
+ VLD_WIDGET_DECREASE_SERVICING_INTERVAL,
+ WIDGET_LIST_END);
+
+
+ SetDParam(0, v->index);
+ this->DrawWidgets();
+
+ /* Draw running cost */
+ SetDParam(1, v->age / 366);
+ SetDParam(0, (v->age + 365 < v->max_age) ? STR_AGE : STR_AGE_RED);
+ SetDParam(2, v->max_age / 366);
+ SetDParam(3, v->GetDisplayRunningCost());
+ DrawString(2, 15, _vehicle_translation_table[VST_VEHICLE_AGE_RUNNING_COST_YR][v->type], TC_FROMSTRING);
+
+ /* Draw max speed */
+ switch (v->type) {
+ case VEH_TRAIN:
+ SetDParam(2, v->GetDisplayMaxSpeed());
+ SetDParam(1, v->u.rail.cached_power);
+ SetDParam(0, v->u.rail.cached_weight);
+ SetDParam(3, v->u.rail.cached_max_te / 1000);
+ DrawString(2, 25, (_patches.realistic_acceleration && v->u.rail.railtype != RAILTYPE_MAGLEV) ?
+ STR_VEHICLE_INFO_WEIGHT_POWER_MAX_SPEED_MAX_TE :
+ STR_VEHICLE_INFO_WEIGHT_POWER_MAX_SPEED, TC_FROMSTRING);
+ break;
+
+ case VEH_ROAD:
+ case VEH_SHIP:
+ case VEH_AIRCRAFT:
+ SetDParam(0, v->GetDisplayMaxSpeed());
+ DrawString(2, 25, _vehicle_translation_table[VST_VEHICLE_MAX_SPEED][v->type], TC_FROMSTRING);
+ break;
+
+ default: NOT_REACHED();
+ }
+
+ /* Draw profit */
+ SetDParam(0, v->GetDisplayProfitThisYear());
+ SetDParam(1, v->GetDisplayProfitLastYear());
+ DrawString(2, 35, _vehicle_translation_table[VST_VEHICLE_PROFIT_THIS_YEAR_LAST_YEAR][v->type], TC_FROMSTRING);
+
+ /* Draw breakdown & reliability */
+ SetDParam(0, v->reliability * 100 >> 16);
+ SetDParam(1, v->breakdowns_since_last_service);
+ DrawString(2, 45, _vehicle_translation_table[VST_VEHICLE_RELIABILITY_BREAKDOWNS][v->type], TC_FROMSTRING);
+
+ /* Draw service interval text */
+ SetDParam(0, v->service_interval);
+ SetDParam(1, v->date_of_last_service);
+ DrawString(13, this->height - (v->type != VEH_TRAIN ? 11 : 23), _patches.servint_ispercent ? STR_SERVICING_INTERVAL_PERCENT : STR_883C_SERVICING_INTERVAL_DAYS, TC_FROMSTRING);
+
+ switch (v->type) {
+ case VEH_TRAIN:
+ DrawVehicleDetails(v, 2, 57, this->vscroll.pos, this->vscroll.cap, det_tab);
+ break;
+
+ case VEH_ROAD:
+ case VEH_SHIP:
+ case VEH_AIRCRAFT:
+ DrawVehicleImage(v, 3, 57, INVALID_VEHICLE, 0, 0);
+ DrawVehicleDetails(v, 75, 57, this->vscroll.pos, this->vscroll.cap, det_tab);
+ break;
+
+ default: NOT_REACHED();
+ }
}
-}
+
+ virtual void OnClick(Point pt, int widget)
+ {
+ /** Message strings for renaming vehicles indexed by vehicle type. */
+ static const StringID _name_vehicle_title[] = {
+ STR_8865_NAME_TRAIN,
+ STR_902C_NAME_ROAD_VEHICLE,
+ STR_9831_NAME_SHIP,
+ STR_A030_NAME_AIRCRAFT
+ };
+
+ switch (widget) {
+ case VLD_WIDGET_RENAME_VEHICLE: {// rename
+ const Vehicle *v = GetVehicle(this->window_number);
+ SetDParam(0, v->index);
+ ShowQueryString(STR_VEHICLE_NAME, _name_vehicle_title[v->type], 31, 150, this, CS_ALPHANUMERAL);
+ } break;
+
+ case VLD_WIDGET_INCREASE_SERVICING_INTERVAL: // increase int
+ case VLD_WIDGET_DECREASE_SERVICING_INTERVAL: { // decrease int
+ int mod = _ctrl_pressed ? 5 : 10;
+ const Vehicle *v = GetVehicle(this->window_number);
+
+ mod = (widget == VLD_WIDGET_DECREASE_SERVICING_INTERVAL) ? -mod : mod;
+ mod = GetServiceIntervalClamped(mod + v->service_interval);
+ if (mod == v->service_interval) return;
+
+ DoCommandP(v->tile, v->index, mod, NULL, CMD_CHANGE_SERVICE_INT | CMD_MSG(STR_018A_CAN_T_CHANGE_SERVICING));
+ } break;
+
+ case VLD_WIDGET_DETAILS_CARGO_CARRIED:
+ case VLD_WIDGET_DETAILS_TRAIN_VEHICLES:
+ case VLD_WIDGET_DETAILS_CAPACITY_OF_EACH:
+ case VLD_WIDGET_DETAILS_TOTAL_CARGO:
+ this->SetWidgetsDisabledState(false,
+ VLD_WIDGET_DETAILS_CARGO_CARRIED,
+ VLD_WIDGET_DETAILS_TRAIN_VEHICLES,
+ VLD_WIDGET_DETAILS_CAPACITY_OF_EACH,
+ VLD_WIDGET_DETAILS_TOTAL_CARGO,
+ widget,
+ WIDGET_LIST_END);
+
+ this->tab = widget - VLD_WIDGET_DETAILS_CARGO_CARRIED;
+ this->SetDirty();
+ break;
+ }
+ }
+
+ virtual void OnQueryTextFinished(char *str)
+ {
+ /** Message strings for error while renaming indexed by vehicle type. */
+ static const StringID _name_vehicle_error[] = {
+ STR_8866_CAN_T_NAME_TRAIN,
+ STR_902D_CAN_T_NAME_ROAD_VEHICLE,
+ STR_9832_CAN_T_NAME_SHIP,
+ STR_A031_CAN_T_NAME_AIRCRAFT
+ };
+
+ if (!StrEmpty(str)) {
+ _cmd_text = str;
+ DoCommandP(0, this->window_number, 0, NULL, CMD_NAME_VEHICLE | CMD_MSG(_name_vehicle_error[GetVehicle(this->window_number)->type]));
+ }
+ }
+
+ virtual void OnResize(Point new_size, Point delta)
+ {
+ if (delta.x != 0) ResizeButtons(this, VLD_WIDGET_DETAILS_CARGO_CARRIED, VLD_WIDGET_DETAILS_TOTAL_CARGO);
+ if (delta.y == 0) return;
+
+ this->vscroll.cap += delta.y / 14;
+ this->widget[VLD_WIDGET_MIDDLE_DETAILS].data = (this->vscroll.cap << 8) + 1;
+ }
+};
/** Vehicle details window descriptor. */
static const WindowDesc _vehicle_details_desc = {
@@ -1655,7 +1608,6 @@
WC_VEHICLE_DETAILS, WC_VEHICLE_VIEW,
WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS | WDF_RESIZABLE,
_vehicle_details_widgets,
- VehicleDetailsWndProc
};
/** Shows the vehicle details window of the given vehicle. */
@@ -1663,7 +1615,7 @@
{
DeleteWindowById(WC_VEHICLE_ORDERS, v->index);
DeleteWindowById(WC_VEHICLE_DETAILS, v->index);
- AllocateWindowDescFront<Window>(&_vehicle_details_desc, v->index);
+ AllocateWindowDescFront<VehicleDetailsWindow>(&_vehicle_details_desc, v->index);
}
@@ -1691,15 +1643,12 @@
};
-static void VehicleViewWndProc(Window *w, WindowEvent *e);
-
/** Vehicle view window descriptor for all vehicles but trains. */
static const WindowDesc _vehicle_view_desc = {
WDP_AUTO, WDP_AUTO, 250, 116, 250, 116,
WC_VEHICLE_VIEW, WC_NONE,
WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS | WDF_STICKY_BUTTON | WDF_RESIZABLE,
_vehicle_view_widgets,
- VehicleViewWndProc
};
/** Vehicle view window descriptor for trains. Only minimum_height and
@@ -1710,7 +1659,6 @@
WC_VEHICLE_VIEW, WC_NONE,
WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS | WDF_STICKY_BUTTON | WDF_RESIZABLE,
_vehicle_view_widgets,
- VehicleViewWndProc
};
@@ -1736,300 +1684,6 @@
static const int VV_INITIAL_VIEWPORT_HEIGHT = 84;
static const int VV_INITIAL_VIEWPORT_HEIGHT_TRAIN = 102;
-/** Shows the vehicle view window of the given vehicle. */
-void ShowVehicleViewWindow(const Vehicle *v)
-{
- Window *w = AllocateWindowDescFront<Window>((v->type == VEH_TRAIN) ? &_train_view_desc : &_vehicle_view_desc, v->index);
-
- if (w != NULL) {
- w->caption_color = v->owner;
- InitializeWindowViewport(w, VV_VIEWPORT_X, VV_VIEWPORT_Y, VV_INITIAL_VIEWPORT_WIDTH,
- (v->type == VEH_TRAIN) ? VV_INITIAL_VIEWPORT_HEIGHT_TRAIN : VV_INITIAL_VIEWPORT_HEIGHT,
- w->window_number | (1 << 31), _vehicle_view_zoom_levels[v->type]);
- }
-}
-
-/** Initialize a newly created vehicle view window */
-static void CreateVehicleViewWindow(Window *w)
-{
- const Vehicle *v = GetVehicle(w->window_number);
-
- /*
- * fill in data and tooltip codes for the widgets and
- * move some of the buttons for trains
- */
- switch (v->type) {
- case VEH_TRAIN:
- w->widget[VVW_WIDGET_CAPTION].data = STR_882E;
-
- w->widget[VVW_WIDGET_START_STOP_VEH].tooltips = STR_8846_CURRENT_TRAIN_ACTION_CLICK;
-
- w->widget[VVW_WIDGET_CENTER_MAIN_VIEH].tooltips = STR_8848_CENTER_MAIN_VIEW_ON_TRAIN;
-
- w->widget[VVW_WIDGET_GOTO_DEPOT].data = SPR_SEND_TRAIN_TODEPOT;
- w->widget[VVW_WIDGET_GOTO_DEPOT].tooltips = STR_8849_SEND_TRAIN_TO_DEPOT;
-
- w->widget[VVW_WIDGET_REFIT_VEH].tooltips = STR_RAIL_REFIT_VEHICLE_TO_CARRY;
-
- w->widget[VVW_WIDGET_SHOW_ORDERS].tooltips = STR_8847_SHOW_TRAIN_S_ORDERS;
-
- w->widget[VVW_WIDGET_SHOW_DETAILS].tooltips = STR_884C_SHOW_TRAIN_DETAILS;
-
- w->widget[VVW_WIDGET_CLONE_VEH].data = SPR_CLONE_TRAIN;
- w->widget[VVW_WIDGET_CLONE_VEH].tooltips = STR_CLONE_TRAIN_INFO;
-
- w->widget[VVW_WIDGET_TURN_AROUND].tooltips = STR_884B_REVERSE_DIRECTION_OF_TRAIN;
-
-
- /* due to more buttons we must modify the layout a bit for trains */
- w->widget[VVW_WIDGET_PANEL].bottom = 121;
- w->widget[VVW_WIDGET_VIEWPORT].bottom = 119;
-
- w->widget[VVW_WIDGET_START_STOP_VEH].top = 122;
- w->widget[VVW_WIDGET_START_STOP_VEH].bottom = 133;
-
- w->widget[VVW_WIDGET_REFIT_VEH].top = 68;
- w->widget[VVW_WIDGET_REFIT_VEH].bottom = 85;
-
- w->widget[VVW_WIDGET_SHOW_ORDERS].top = 86;
- w->widget[VVW_WIDGET_SHOW_ORDERS].bottom = 103;
-
- w->widget[VVW_WIDGET_SHOW_DETAILS].top = 104;
- w->widget[VVW_WIDGET_SHOW_DETAILS].bottom = 121;
-
- w->widget[VVW_WIDGET_EMPTY_BOTTOM_RIGHT].top = 122;
- w->widget[VVW_WIDGET_EMPTY_BOTTOM_RIGHT].bottom = 121;
-
- w->widget[VVW_WIDGET_RESIZE].top = 122;
- w->widget[VVW_WIDGET_RESIZE].bottom = 133;
-
- w->widget[VVW_WIDGET_TURN_AROUND].top = 68;
- w->widget[VVW_WIDGET_TURN_AROUND].bottom = 85;
- break;
-
- case VEH_ROAD:
- w->widget[VVW_WIDGET_CAPTION].data = STR_9002;
-
- w->widget[VVW_WIDGET_START_STOP_VEH].tooltips = STR_901C_CURRENT_VEHICLE_ACTION;
-
- w->widget[VVW_WIDGET_CENTER_MAIN_VIEH].tooltips = STR_901E_CENTER_MAIN_VIEW_ON_VEHICLE;
-
- w->widget[VVW_WIDGET_GOTO_DEPOT].data = SPR_SEND_ROADVEH_TODEPOT;
- w->widget[VVW_WIDGET_GOTO_DEPOT].tooltips = STR_901F_SEND_VEHICLE_TO_DEPOT;
-
- w->widget[VVW_WIDGET_REFIT_VEH].tooltips = STR_REFIT_ROAD_VEHICLE_TO_CARRY;
-
- w->widget[VVW_WIDGET_SHOW_ORDERS].tooltips = STR_901D_SHOW_VEHICLE_S_ORDERS;
-
- w->widget[VVW_WIDGET_SHOW_DETAILS].tooltips = STR_9021_SHOW_ROAD_VEHICLE_DETAILS;
-
- w->widget[VVW_WIDGET_CLONE_VEH].data = SPR_CLONE_ROADVEH;
- w->widget[VVW_WIDGET_CLONE_VEH].tooltips = STR_CLONE_ROAD_VEHICLE_INFO;
-
- w->SetWidgetHiddenState(VVW_WIDGET_FORCE_PROCEED, true);
- break;
-
- case VEH_SHIP:
- w->widget[VVW_WIDGET_CAPTION].data = STR_980F;
-
- w->widget[VVW_WIDGET_START_STOP_VEH].tooltips = STR_9827_CURRENT_SHIP_ACTION_CLICK;
-
- w->widget[VVW_WIDGET_CENTER_MAIN_VIEH].tooltips = STR_9829_CENTER_MAIN_VIEW_ON_SHIP;
-
- w->widget[VVW_WIDGET_GOTO_DEPOT].data = SPR_SEND_SHIP_TODEPOT;
- w->widget[VVW_WIDGET_GOTO_DEPOT].tooltips = STR_982A_SEND_SHIP_TO_DEPOT;
-
- w->widget[VVW_WIDGET_REFIT_VEH].tooltips = STR_983A_REFIT_CARGO_SHIP_TO_CARRY;
-
- w->widget[VVW_WIDGET_SHOW_ORDERS].tooltips = STR_9828_SHOW_SHIP_S_ORDERS;
-
- w->widget[VVW_WIDGET_SHOW_DETAILS].tooltips = STR_982B_SHOW_SHIP_DETAILS;
-
- w->widget[VVW_WIDGET_CLONE_VEH].data = SPR_CLONE_SHIP;
- w->widget[VVW_WIDGET_CLONE_VEH].tooltips = STR_CLONE_SHIP_INFO;
-
- w->SetWidgetsHiddenState(true,
- VVW_WIDGET_TURN_AROUND,
- VVW_WIDGET_FORCE_PROCEED,
- WIDGET_LIST_END);
- break;
-
- case VEH_AIRCRAFT:
- w->widget[VVW_WIDGET_CAPTION].data = STR_A00A;
-
- w->widget[VVW_WIDGET_START_STOP_VEH].tooltips = STR_A027_CURRENT_AIRCRAFT_ACTION;
-
- w->widget[VVW_WIDGET_CENTER_MAIN_VIEH].tooltips = STR_A029_CENTER_MAIN_VIEW_ON_AIRCRAFT;
-
- w->widget[VVW_WIDGET_GOTO_DEPOT].data = SPR_SEND_AIRCRAFT_TODEPOT;
- w->widget[VVW_WIDGET_GOTO_DEPOT].tooltips = STR_A02A_SEND_AIRCRAFT_TO_HANGAR;
-
- w->widget[VVW_WIDGET_REFIT_VEH].tooltips = STR_A03B_REFIT_AIRCRAFT_TO_CARRY;
-
- w->widget[VVW_WIDGET_SHOW_ORDERS].tooltips = STR_A028_SHOW_AIRCRAFT_S_ORDERS;
-
- w->widget[VVW_WIDGET_SHOW_DETAILS].tooltips = STR_A02B_SHOW_AIRCRAFT_DETAILS;
-
- w->widget[VVW_WIDGET_CLONE_VEH].data = SPR_CLONE_AIRCRAFT;
- w->widget[VVW_WIDGET_CLONE_VEH].tooltips = STR_CLONE_AIRCRAFT_INFO;
-
- w->SetWidgetsHiddenState(true,
- VVW_WIDGET_TURN_AROUND,
- VVW_WIDGET_FORCE_PROCEED,
- WIDGET_LIST_END);
- break;
-
- default: NOT_REACHED();
- }
-}
-
-/** Checks whether the vehicle may be refitted at the moment.*/
-static bool IsVehicleRefitable(const Vehicle *v)
-{
- /* Why is this so different for different vehicles?
- * Does maybe work one solution for all?
- */
- switch (v->type) {
- case VEH_TRAIN: return false;
- case VEH_ROAD: return EngInfo(v->engine_type)->refit_mask != 0 && v->IsStoppedInDepot();
- case VEH_SHIP: return ShipVehInfo(v->engine_type)->refittable && v->IsStoppedInDepot();
- case VEH_AIRCRAFT: return v->IsStoppedInDepot();
- default: NOT_REACHED();
- }
-}
-
-/** Message strings for heading to depot indexed by vehicle type. */
-static const StringID _heading_for_depot_strings[] = {
- STR_HEADING_FOR_TRAIN_DEPOT,
- STR_HEADING_FOR_ROAD_DEPOT,
- STR_HEADING_FOR_SHIP_DEPOT,
- STR_HEADING_FOR_HANGAR,
-};
-
-/** Message strings for heading to depot and servicing indexed by vehicle type. */
-static const StringID _heading_for_depot_service_strings[] = {
- STR_HEADING_FOR_TRAIN_DEPOT_SERVICE,
- STR_HEADING_FOR_ROAD_DEPOT_SERVICE,
- STR_HEADING_FOR_SHIP_DEPOT_SERVICE,
- STR_HEADING_FOR_HANGAR_SERVICE,
-};
-
-/** Repaint vehicle view window. */
-static void DrawVehicleViewWindow(Window *w)
-{
- const Vehicle *v = GetVehicle(w->window_number);
- StringID str;
- bool is_localplayer = v->owner == _local_player;
- bool refitable_and_stopped_in_depot = IsVehicleRefitable(v);
-
- w->SetWidgetDisabledState(VVW_WIDGET_GOTO_DEPOT, !is_localplayer);
- w->SetWidgetDisabledState(VVW_WIDGET_REFIT_VEH,
- !refitable_and_stopped_in_depot || !is_localplayer);
- w->SetWidgetDisabledState(VVW_WIDGET_CLONE_VEH, !is_localplayer);
-
- if (v->type == VEH_TRAIN) {
- w->SetWidgetDisabledState(VVW_WIDGET_FORCE_PROCEED, !is_localplayer);
- w->SetWidgetDisabledState(VVW_WIDGET_TURN_AROUND, !is_localplayer);
-
- /* Cargo refit button is disabled, until we know we can enable it below. */
-
- if (is_localplayer) {
- /* See if any vehicle can be refitted */
- for (const Vehicle *u = v; u != NULL; u = u->Next()) {
- if (EngInfo(u->engine_type)->refit_mask != 0 ||
- (RailVehInfo(v->engine_type)->railveh_type != RAILVEH_WAGON && v->cargo_cap != 0)) {
- w->EnableWidget(VVW_WIDGET_REFIT_VEH);
- /* We have a refittable carriage, bail out */
- break;
- }
- }
- }
- }
-
- /* draw widgets & caption */
- SetDParam(0, v->index);
- DrawWindowWidgets(w);
-
- if (v->vehstatus & VS_CRASHED) {
- str = STR_8863_CRASHED;
- } else if (v->type != VEH_AIRCRAFT && v->breakdown_ctr == 1) { // check for aircraft necessary?
- str = STR_885C_BROKEN_DOWN;
- } else if (v->vehstatus & VS_STOPPED) {
- if (v->type == VEH_TRAIN) {
- if (v->cur_speed == 0) {
- if (v->u.rail.cached_power == 0) {
- str = STR_TRAIN_NO_POWER;
- } else {
- str = STR_8861_STOPPED;
- }
- } else {
- SetDParam(0, v->GetDisplaySpeed());
- str = STR_TRAIN_STOPPING + _patches.vehicle_speed;
- }
- } else { // no train
- str = STR_8861_STOPPED;
- }
- } else { // vehicle is in a "normal" state, show current order
- switch (v->current_order.GetType()) {
- case OT_GOTO_STATION: {
- SetDParam(0, v->current_order.GetDestination());
- SetDParam(1, v->GetDisplaySpeed());
- str = STR_HEADING_FOR_STATION + _patches.vehicle_speed;
- } break;
-
- case OT_GOTO_DEPOT: {
- if (v->type == VEH_AIRCRAFT) {
- /* Aircrafts always go to a station, even if you say depot */
- SetDParam(0, v->current_order.GetDestination());
- SetDParam(1, v->GetDisplaySpeed());
- } else {
- Depot *depot = GetDepot(v->current_order.GetDestination());
- SetDParam(0, depot->town_index);
- SetDParam(1, v->GetDisplaySpeed());
- }
- if ((v->current_order.GetDepotActionType() & ODATFB_HALT) && !(v->current_order.GetDepotOrderType() & ODTFB_PART_OF_ORDERS)) {
- str = _heading_for_depot_strings[v->type] + _patches.vehicle_speed;
- } else {
- str = _heading_for_depot_service_strings[v->type] + _patches.vehicle_speed;
- }
- } break;
-
- case OT_LOADING:
- str = STR_882F_LOADING_UNLOADING;
- break;
-
- case OT_GOTO_WAYPOINT: {
- assert(v->type == VEH_TRAIN);
- SetDParam(0, v->current_order.GetDestination());
- str = STR_HEADING_FOR_WAYPOINT + _patches.vehicle_speed;
- SetDParam(1, v->GetDisplaySpeed());
- break;
- }
-
- case OT_LEAVESTATION:
- if (v->type != VEH_AIRCRAFT) {
- str = STR_LEAVING;
- break;
- }
- /* fall-through if aircraft. Does this even happen? */
-
- default:
- if (v->num_orders == 0) {
- str = STR_NO_ORDERS + _patches.vehicle_speed;
- SetDParam(0, v->GetDisplaySpeed());
- } else {
- str = STR_EMPTY;
- }
- break;
- }
- }
-
- /* draw the flag plus orders */
- DrawSprite(v->vehstatus & VS_STOPPED ? SPR_FLAG_VEH_STOPPED : SPR_FLAG_VEH_RUNNING, PAL_NONE, 2, w->widget[VVW_WIDGET_START_STOP_VEH].top + 1);
- DrawStringCenteredTruncated(w->widget[VVW_WIDGET_START_STOP_VEH].left + 8, w->widget[VVW_WIDGET_START_STOP_VEH].right, w->widget[VVW_WIDGET_START_STOP_VEH].top + 1, str, TC_FROMSTRING);
- DrawWindowViewport(w);
-}
-
/** Command indices for the _vehicle_command_translation_table. */
enum VehicleCommandTranslation {
VCT_CMD_START_STOP = 0,
@@ -2067,104 +1721,387 @@
},
};
-/** Window event hook for vehicle view. */
-static void VehicleViewWndProc(Window *w, WindowEvent *e)
+/** Checks whether the vehicle may be refitted at the moment.*/
+static bool IsVehicleRefitable(const Vehicle *v)
{
- switch (e->event) {
- case WE_CREATE:
- CreateVehicleViewWindow(w);
- break;
-
- case WE_PAINT:
- DrawVehicleViewWindow(w);
- break;
+ /* Why is this so different for different vehicles?
+ * Does maybe work one solution for all?
+ */
+ switch (v->type) {
+ case VEH_TRAIN: return false;
+ case VEH_ROAD: return EngInfo(v->engine_type)->refit_mask != 0 && v->IsStoppedInDepot();
+ case VEH_SHIP: return ShipVehInfo(v->engine_type)->refittable && v->IsStoppedInDepot();
+ case VEH_AIRCRAFT: return v->IsStoppedInDepot();
+ default: NOT_REACHED();
+ }
+}
- case WE_CLICK: {
- const Vehicle *v = GetVehicle(w->window_number);
+struct VehicleViewWindow : Window {
+ VehicleViewWindow(const WindowDesc *desc, WindowNumber window_number) : Window(desc, window_number)
+ {
+ const Vehicle *v = GetVehicle(this->window_number);
- switch (e->we.click.widget) {
- case VVW_WIDGET_START_STOP_VEH: /* start stop */
- DoCommandP(v->tile, v->index, 0, NULL,
- _vehicle_command_translation_table[VCT_CMD_START_STOP][v->type]);
- break;
- case VVW_WIDGET_CENTER_MAIN_VIEH: {/* center main view */
- const Window *mainwindow = FindWindowById(WC_MAIN_WINDOW, 0);
- /* code to allow the main window to 'follow' the vehicle if the ctrl key is pressed */
- if (_ctrl_pressed && mainwindow->viewport->zoom == ZOOM_LVL_NORMAL) {
- mainwindow->viewport->follow_vehicle = v->index;
+ this->caption_color = v->owner;
+ InitializeWindowViewport(this, VV_VIEWPORT_X, VV_VIEWPORT_Y, VV_INITIAL_VIEWPORT_WIDTH,
+ (v->type == VEH_TRAIN) ? VV_INITIAL_VIEWPORT_HEIGHT_TRAIN : VV_INITIAL_VIEWPORT_HEIGHT,
+ this->window_number | (1 << 31), _vehicle_view_zoom_levels[v->type]);
+
+ /*
+ * fill in data and tooltip codes for the widgets and
+ * move some of the buttons for trains
+ */
+ switch (v->type) {
+ case VEH_TRAIN:
+ this->widget[VVW_WIDGET_CAPTION].data = STR_882E;
+
+ this->widget[VVW_WIDGET_START_STOP_VEH].tooltips = STR_8846_CURRENT_TRAIN_ACTION_CLICK;
+
+ this->widget[VVW_WIDGET_CENTER_MAIN_VIEH].tooltips = STR_8848_CENTER_MAIN_VIEW_ON_TRAIN;
+
+ this->widget[VVW_WIDGET_GOTO_DEPOT].data = SPR_SEND_TRAIN_TODEPOT;
+ this->widget[VVW_WIDGET_GOTO_DEPOT].tooltips = STR_8849_SEND_TRAIN_TO_DEPOT;
+
+ this->widget[VVW_WIDGET_REFIT_VEH].tooltips = STR_RAIL_REFIT_VEHICLE_TO_CARRY;
+
+ this->widget[VVW_WIDGET_SHOW_ORDERS].tooltips = STR_8847_SHOW_TRAIN_S_ORDERS;
+
+ this->widget[VVW_WIDGET_SHOW_DETAILS].tooltips = STR_884C_SHOW_TRAIN_DETAILS;
+
+ this->widget[VVW_WIDGET_CLONE_VEH].data = SPR_CLONE_TRAIN;
+ this->widget[VVW_WIDGET_CLONE_VEH].tooltips = STR_CLONE_TRAIN_INFO;
+
+ this->widget[VVW_WIDGET_TURN_AROUND].tooltips = STR_884B_REVERSE_DIRECTION_OF_TRAIN;
+
+
+ /* due to more buttons we must modify the layout a bit for trains */
+ this->widget[VVW_WIDGET_PANEL].bottom = 121;
+ this->widget[VVW_WIDGET_VIEWPORT].bottom = 119;
+
+ this->widget[VVW_WIDGET_START_STOP_VEH].top = 122;
+ this->widget[VVW_WIDGET_START_STOP_VEH].bottom = 133;
+
+ this->widget[VVW_WIDGET_REFIT_VEH].top = 68;
+ this->widget[VVW_WIDGET_REFIT_VEH].bottom = 85;
+
+ this->widget[VVW_WIDGET_SHOW_ORDERS].top = 86;
+ this->widget[VVW_WIDGET_SHOW_ORDERS].bottom = 103;
+
+ this->widget[VVW_WIDGET_SHOW_DETAILS].top = 104;
+ this->widget[VVW_WIDGET_SHOW_DETAILS].bottom = 121;
+
+ this->widget[VVW_WIDGET_EMPTY_BOTTOM_RIGHT].top = 122;
+ this->widget[VVW_WIDGET_EMPTY_BOTTOM_RIGHT].bottom = 121;
+
+ this->widget[VVW_WIDGET_RESIZE].top = 122;
+ this->widget[VVW_WIDGET_RESIZE].bottom = 133;
+
+ this->widget[VVW_WIDGET_TURN_AROUND].top = 68;
+ this->widget[VVW_WIDGET_TURN_AROUND].bottom = 85;
+ break;
+
+ case VEH_ROAD:
+ this->widget[VVW_WIDGET_CAPTION].data = STR_9002;
+
+ this->widget[VVW_WIDGET_START_STOP_VEH].tooltips = STR_901C_CURRENT_VEHICLE_ACTION;
+
+ this->widget[VVW_WIDGET_CENTER_MAIN_VIEH].tooltips = STR_901E_CENTER_MAIN_VIEW_ON_VEHICLE;
+
+ this->widget[VVW_WIDGET_GOTO_DEPOT].data = SPR_SEND_ROADVEH_TODEPOT;
+ this->widget[VVW_WIDGET_GOTO_DEPOT].tooltips = STR_901F_SEND_VEHICLE_TO_DEPOT;
+
+ this->widget[VVW_WIDGET_REFIT_VEH].tooltips = STR_REFIT_ROAD_VEHICLE_TO_CARRY;
+
+ this->widget[VVW_WIDGET_SHOW_ORDERS].tooltips = STR_901D_SHOW_VEHICLE_S_ORDERS;
+
+ this->widget[VVW_WIDGET_SHOW_DETAILS].tooltips = STR_9021_SHOW_ROAD_VEHICLE_DETAILS;
+
+ this->widget[VVW_WIDGET_CLONE_VEH].data = SPR_CLONE_ROADVEH;
+ this->widget[VVW_WIDGET_CLONE_VEH].tooltips = STR_CLONE_ROAD_VEHICLE_INFO;
+
+ this->SetWidgetHiddenState(VVW_WIDGET_FORCE_PROCEED, true);
+ break;
+
+ case VEH_SHIP:
+ this->widget[VVW_WIDGET_CAPTION].data = STR_980F;
+
+ this->widget[VVW_WIDGET_START_STOP_VEH].tooltips = STR_9827_CURRENT_SHIP_ACTION_CLICK;
+
+ this->widget[VVW_WIDGET_CENTER_MAIN_VIEH].tooltips = STR_9829_CENTER_MAIN_VIEW_ON_SHIP;
+
+ this->widget[VVW_WIDGET_GOTO_DEPOT].data = SPR_SEND_SHIP_TODEPOT;
+ this->widget[VVW_WIDGET_GOTO_DEPOT].tooltips = STR_982A_SEND_SHIP_TO_DEPOT;
+
+ this->widget[VVW_WIDGET_REFIT_VEH].tooltips = STR_983A_REFIT_CARGO_SHIP_TO_CARRY;
+
+ this->widget[VVW_WIDGET_SHOW_ORDERS].tooltips = STR_9828_SHOW_SHIP_S_ORDERS;
+
+ this->widget[VVW_WIDGET_SHOW_DETAILS].tooltips = STR_982B_SHOW_SHIP_DETAILS;
+
+ this->widget[VVW_WIDGET_CLONE_VEH].data = SPR_CLONE_SHIP;
+ this->widget[VVW_WIDGET_CLONE_VEH].tooltips = STR_CLONE_SHIP_INFO;
+
+ this->SetWidgetsHiddenState(true,
+ VVW_WIDGET_TURN_AROUND,
+ VVW_WIDGET_FORCE_PROCEED,
+ WIDGET_LIST_END);
+ break;
+
+ case VEH_AIRCRAFT:
+ this->widget[VVW_WIDGET_CAPTION].data = STR_A00A;
+
+ this->widget[VVW_WIDGET_START_STOP_VEH].tooltips = STR_A027_CURRENT_AIRCRAFT_ACTION;
+
+ this->widget[VVW_WIDGET_CENTER_MAIN_VIEH].tooltips = STR_A029_CENTER_MAIN_VIEW_ON_AIRCRAFT;
+
+ this->widget[VVW_WIDGET_GOTO_DEPOT].data = SPR_SEND_AIRCRAFT_TODEPOT;
+ this->widget[VVW_WIDGET_GOTO_DEPOT].tooltips = STR_A02A_SEND_AIRCRAFT_TO_HANGAR;
+
+ this->widget[VVW_WIDGET_REFIT_VEH].tooltips = STR_A03B_REFIT_AIRCRAFT_TO_CARRY;
+
+ this->widget[VVW_WIDGET_SHOW_ORDERS].tooltips = STR_A028_SHOW_AIRCRAFT_S_ORDERS;
+
+ this->widget[VVW_WIDGET_SHOW_DETAILS].tooltips = STR_A02B_SHOW_AIRCRAFT_DETAILS;
+
+ this->widget[VVW_WIDGET_CLONE_VEH].data = SPR_CLONE_AIRCRAFT;
+ this->widget[VVW_WIDGET_CLONE_VEH].tooltips = STR_CLONE_AIRCRAFT_INFO;
+
+ this->SetWidgetsHiddenState(true,
+ VVW_WIDGET_TURN_AROUND,
+ VVW_WIDGET_FORCE_PROCEED,
+ WIDGET_LIST_END);
+ break;
+
+ default: NOT_REACHED();
+ }
+ }
+
+ ~VehicleViewWindow()
+ {
+ DeleteWindowById(WC_VEHICLE_ORDERS, this->window_number);
+ DeleteWindowById(WC_VEHICLE_REFIT, this->window_number);
+ DeleteWindowById(WC_VEHICLE_DETAILS, this->window_number);
+ DeleteWindowById(WC_VEHICLE_TIMETABLE, this->window_number);
+ }
+
+ virtual void OnPaint()
+ {
+ /** Message strings for heading to depot indexed by vehicle type. */
+ static const StringID _heading_for_depot_strings[] = {
+ STR_HEADING_FOR_TRAIN_DEPOT,
+ STR_HEADING_FOR_ROAD_DEPOT,
+ STR_HEADING_FOR_SHIP_DEPOT,
+ STR_HEADING_FOR_HANGAR,
+ };
+
+ /** Message strings for heading to depot and servicing indexed by vehicle type. */
+ static const StringID _heading_for_depot_service_strings[] = {
+ STR_HEADING_FOR_TRAIN_DEPOT_SERVICE,
+ STR_HEADING_FOR_ROAD_DEPOT_SERVICE,
+ STR_HEADING_FOR_SHIP_DEPOT_SERVICE,
+ STR_HEADING_FOR_HANGAR_SERVICE,
+ };
+
+ const Vehicle *v = GetVehicle(this->window_number);
+ StringID str;
+ bool is_localplayer = v->owner == _local_player;
+ bool refitable_and_stopped_in_depot = IsVehicleRefitable(v);
+
+ this->SetWidgetDisabledState(VVW_WIDGET_GOTO_DEPOT, !is_localplayer);
+ this->SetWidgetDisabledState(VVW_WIDGET_REFIT_VEH,
+ !refitable_and_stopped_in_depot || !is_localplayer);
+ this->SetWidgetDisabledState(VVW_WIDGET_CLONE_VEH, !is_localplayer);
+
+ if (v->type == VEH_TRAIN) {
+ this->SetWidgetDisabledState(VVW_WIDGET_FORCE_PROCEED, !is_localplayer);
+ this->SetWidgetDisabledState(VVW_WIDGET_TURN_AROUND, !is_localplayer);
+
+ /* Cargo refit button is disabled, until we know we can enable it below. */
+
+ if (is_localplayer) {
+ /* See if any vehicle can be refitted */
+ for (const Vehicle *u = v; u != NULL; u = u->Next()) {
+ if (EngInfo(u->engine_type)->refit_mask != 0 ||
+ (RailVehInfo(v->engine_type)->railveh_type != RAILVEH_WAGON && v->cargo_cap != 0)) {
+ this->EnableWidget(VVW_WIDGET_REFIT_VEH);
+ /* We have a refittable carriage, bail out */
+ break;
+ }
+ }
+ }
+ }
+
+ /* draw widgets & caption */
+ SetDParam(0, v->index);
+ this->DrawWidgets();
+
+ if (v->vehstatus & VS_CRASHED) {
+ str = STR_8863_CRASHED;
+ } else if (v->type != VEH_AIRCRAFT && v->breakdown_ctr == 1) { // check for aircraft necessary?
+ str = STR_885C_BROKEN_DOWN;
+ } else if (v->vehstatus & VS_STOPPED) {
+ if (v->type == VEH_TRAIN) {
+ if (v->cur_speed == 0) {
+ if (v->u.rail.cached_power == 0) {
+ str = STR_TRAIN_NO_POWER;
} else {
- ScrollMainWindowTo(v->x_pos, v->y_pos);
+ str = STR_8861_STOPPED;
+ }
+ } else {
+ SetDParam(0, v->GetDisplaySpeed());
+ str = STR_TRAIN_STOPPING + _patches.vehicle_speed;
+ }
+ } else { // no train
+ str = STR_8861_STOPPED;
+ }
+ } else { // vehicle is in a "normal" state, show current order
+ switch (v->current_order.GetType()) {
+ case OT_GOTO_STATION: {
+ SetDParam(0, v->current_order.GetDestination());
+ SetDParam(1, v->GetDisplaySpeed());
+ str = STR_HEADING_FOR_STATION + _patches.vehicle_speed;
+ } break;
+
+ case OT_GOTO_DEPOT: {
+ if (v->type == VEH_AIRCRAFT) {
+ /* Aircrafts always go to a station, even if you say depot */
+ SetDParam(0, v->current_order.GetDestination());
+ SetDParam(1, v->GetDisplaySpeed());
+ } else {
+ Depot *depot = GetDepot(v->current_order.GetDestination());
+ SetDParam(0, depot->town_index);
+ SetDParam(1, v->GetDisplaySpeed());
+ }
+ if ((v->current_order.GetDepotActionType() & ODATFB_HALT) && !(v->current_order.GetDepotOrderType() & ODTFB_PART_OF_ORDERS)) {
+ str = _heading_for_depot_strings[v->type] + _patches.vehicle_speed;
+ } else {
+ str = _heading_for_depot_service_strings[v->type] + _patches.vehicle_speed;
}
} break;
- case VVW_WIDGET_GOTO_DEPOT: /* goto hangar */
- DoCommandP(v->tile, v->index, _ctrl_pressed ? DEPOT_SERVICE : 0, NULL,
- _vehicle_command_translation_table[VCT_CMD_GOTO_DEPOT][v->type]);
- break;
- case VVW_WIDGET_REFIT_VEH: /* refit */
- ShowVehicleRefitWindow(v, INVALID_VEH_ORDER_ID);
- break;
- case VVW_WIDGET_SHOW_ORDERS: /* show orders */
- if (_ctrl_pressed) {
- ShowTimetableWindow(v);
- } else {
- ShowOrdersWindow(v);
- }
+ case OT_LOADING:
+ str = STR_882F_LOADING_UNLOADING;
break;
- case VVW_WIDGET_SHOW_DETAILS: /* show details */
- ShowVehicleDetailsWindow(v);
- break;
- case VVW_WIDGET_CLONE_VEH: /* clone vehicle */
- DoCommandP(v->tile, v->index, _ctrl_pressed ? 1 : 0, CcCloneVehicle,
- _vehicle_command_translation_table[VCT_CMD_CLONE_VEH][v->type]);
+
+ case OT_GOTO_WAYPOINT: {
+ assert(v->type == VEH_TRAIN);
+ SetDParam(0, v->current_order.GetDestination());
+ str = STR_HEADING_FOR_WAYPOINT + _patches.vehicle_speed;
+ SetDParam(1, v->GetDisplaySpeed());
break;
- case VVW_WIDGET_TURN_AROUND: /* turn around */
- assert(v->type == VEH_TRAIN || v->type == VEH_ROAD);
- DoCommandP(v->tile, v->index, 0, NULL,
- _vehicle_command_translation_table[VCT_CMD_TURN_AROUND][v->type]);
- break;
- case VVW_WIDGET_FORCE_PROCEED: /* force proceed */
- assert(v->type == VEH_TRAIN);
- DoCommandP(v->tile, v->index, 0, NULL, CMD_FORCE_TRAIN_PROCEED | CMD_MSG(STR_8862_CAN_T_MAKE_TRAIN_PASS_SIGNAL));
+ }
+
+ case OT_LEAVESTATION:
+ if (v->type != VEH_AIRCRAFT) {
+ str = STR_LEAVING;
+ break;
+ }
+ /* fall-through if aircraft. Does this even happen? */
+
+ default:
+ if (v->num_orders == 0) {
+ str = STR_NO_ORDERS + _patches.vehicle_speed;
+ SetDParam(0, v->GetDisplaySpeed());
+ } else {
+ str = STR_EMPTY;
+ }
break;
}
- } break;
-
- case WE_RESIZE:
- w->viewport->width += e->we.sizing.diff.x;
- w->viewport->height += e->we.sizing.diff.y;
- w->viewport->virtual_width += e->we.sizing.diff.x;
- w->viewport->virtual_height += e->we.sizing.diff.y;
- break;
-
- case WE_DESTROY:
- DeleteWindowById(WC_VEHICLE_ORDERS, w->window_number);
- DeleteWindowById(WC_VEHICLE_REFIT, w->window_number);
- DeleteWindowById(WC_VEHICLE_DETAILS, w->window_number);
- DeleteWindowById(WC_VEHICLE_TIMETABLE, w->window_number);
- break;
+ }
- case WE_TICK: {
- const Vehicle *v = GetVehicle(w->window_number);
- bool veh_stopped = v->IsStoppedInDepot();
+ /* draw the flag plus orders */
+ DrawSprite(v->vehstatus & VS_STOPPED ? SPR_FLAG_VEH_STOPPED : SPR_FLAG_VEH_RUNNING, PAL_NONE, 2, this->widget[VVW_WIDGET_START_STOP_VEH].top + 1);
+ DrawStringCenteredTruncated(this->widget[VVW_WIDGET_START_STOP_VEH].left + 8, this->widget[VVW_WIDGET_START_STOP_VEH].right, this->widget[VVW_WIDGET_START_STOP_VEH].top + 1, str, TC_FROMSTRING);
+ this->DrawViewport();
+ }
- /* Widget VVW_WIDGET_GOTO_DEPOT must be hidden if the vehicle is already
- * stopped in depot.
- * Widget VVW_WIDGET_CLONE_VEH should then be shown, since cloning is
- * allowed only while in depot and stopped.
- * This sytem allows to have two buttons, on top of each other.
- * The same system applies to widget VVW_WIDGET_REFIT_VEH and VVW_WIDGET_TURN_AROUND.*/
- if (veh_stopped != w->IsWidgetHidden(VVW_WIDGET_GOTO_DEPOT) || veh_stopped == w->IsWidgetHidden(VVW_WIDGET_CLONE_VEH)) {
- w->SetWidgetHiddenState( VVW_WIDGET_GOTO_DEPOT, veh_stopped); // send to depot
- w->SetWidgetHiddenState(VVW_WIDGET_CLONE_VEH, !veh_stopped); // clone
- if (v->type == VEH_ROAD || v->type == VEH_TRAIN) {
- w->SetWidgetHiddenState( VVW_WIDGET_REFIT_VEH, !veh_stopped); // refit
- w->SetWidgetHiddenState(VVW_WIDGET_TURN_AROUND, veh_stopped); // force turn around
+ virtual void OnClick(Point pt, int widget)
+ {
+ const Vehicle *v = GetVehicle(this->window_number);
+
+ switch (widget) {
+ case VVW_WIDGET_START_STOP_VEH: // start stop
+ DoCommandP(v->tile, v->index, 0, NULL,
+ _vehicle_command_translation_table[VCT_CMD_START_STOP][v->type]);
+ break;
+ case VVW_WIDGET_CENTER_MAIN_VIEH: {/* center main view */
+ const Window *mainwindow = FindWindowById(WC_MAIN_WINDOW, 0);
+ /* code to allow the main window to 'follow' the vehicle if the ctrl key is pressed */
+ if (_ctrl_pressed && mainwindow->viewport->zoom == ZOOM_LVL_NORMAL) {
+ mainwindow->viewport->follow_vehicle = v->index;
+ } else {
+ ScrollMainWindowTo(v->x_pos, v->y_pos);
}
- w->SetDirty();
+ } break;
+
+ case VVW_WIDGET_GOTO_DEPOT: // goto hangar
+ DoCommandP(v->tile, v->index, _ctrl_pressed ? DEPOT_SERVICE : 0, NULL,
+ _vehicle_command_translation_table[VCT_CMD_GOTO_DEPOT][v->type]);
+ break;
+ case VVW_WIDGET_REFIT_VEH: // refit
+ ShowVehicleRefitWindow(v, INVALID_VEH_ORDER_ID);
+ break;
+ case VVW_WIDGET_SHOW_ORDERS: // show orders
+ if (_ctrl_pressed) {
+ ShowTimetableWindow(v);
+ } else {
+ ShowOrdersWindow(v);
+ }
+ break;
+ case VVW_WIDGET_SHOW_DETAILS: // show details
+ ShowVehicleDetailsWindow(v);
+ break;
+ case VVW_WIDGET_CLONE_VEH: // clone vehicle
+ DoCommandP(v->tile, v->index, _ctrl_pressed ? 1 : 0, CcCloneVehicle,
+ _vehicle_command_translation_table[VCT_CMD_CLONE_VEH][v->type]);
+ break;
+ case VVW_WIDGET_TURN_AROUND: // turn around
+ assert(v->type == VEH_TRAIN || v->type == VEH_ROAD);
+ DoCommandP(v->tile, v->index, 0, NULL,
+ _vehicle_command_translation_table[VCT_CMD_TURN_AROUND][v->type]);
+ break;
+ case VVW_WIDGET_FORCE_PROCEED: // force proceed
+ assert(v->type == VEH_TRAIN);
+ DoCommandP(v->tile, v->index, 0, NULL, CMD_FORCE_TRAIN_PROCEED | CMD_MSG(STR_8862_CAN_T_MAKE_TRAIN_PASS_SIGNAL));
+ break;
+ }
+ }
+
+ virtual void OnResize(Point new_size, Point delta)
+ {
+ this->viewport->width += delta.x;
+ this->viewport->height += delta.y;
+ this->viewport->virtual_width += delta.x;
+ this->viewport->virtual_height += delta.y;
+ }
+
+ virtual void OnTick()
+ {
+ const Vehicle *v = GetVehicle(this->window_number);
+ bool veh_stopped = v->IsStoppedInDepot();
+
+ /* Widget VVW_WIDGET_GOTO_DEPOT must be hidden if the vehicle is already
+ * stopped in depot.
+ * Widget VVW_WIDGET_CLONE_VEH should then be shown, since cloning is
+ * allowed only while in depot and stopped.
+ * This sytem allows to have two buttons, on top of each other.
+ * The same system applies to widget VVW_WIDGET_REFIT_VEH and VVW_WIDGET_TURN_AROUND.*/
+ if (veh_stopped != this->IsWidgetHidden(VVW_WIDGET_GOTO_DEPOT) || veh_stopped == this->IsWidgetHidden(VVW_WIDGET_CLONE_VEH)) {
+ this->SetWidgetHiddenState( VVW_WIDGET_GOTO_DEPOT, veh_stopped); // send to depot
+ this->SetWidgetHiddenState(VVW_WIDGET_CLONE_VEH, !veh_stopped); // clone
+ if (v->type == VEH_ROAD || v->type == VEH_TRAIN) {
+ this->SetWidgetHiddenState( VVW_WIDGET_REFIT_VEH, !veh_stopped); // refit
+ this->SetWidgetHiddenState(VVW_WIDGET_TURN_AROUND, veh_stopped); // force turn around
}
- } break;
+ this->SetDirty();
+ }
}
+};
+
+
+/** Shows the vehicle view window of the given vehicle. */
+void ShowVehicleViewWindow(const Vehicle *v)
+{
+ AllocateWindowDescFront<VehicleViewWindow>((v->type == VEH_TRAIN) ? &_train_view_desc : &_vehicle_view_desc, v->index);
}
void DrawVehicleImage(const Vehicle *v, int x, int y, VehicleID selection, int count, int skip)
@@ -2177,3 +2114,12 @@
default: NOT_REACHED();
}
}
+
+void StopGlobalFollowVehicle(const Vehicle *v)
+{
+ Window *w = FindWindowById(WC_MAIN_WINDOW, 0);
+ if (w != NULL && w->viewport->follow_vehicle == v->index) {
+ ScrollMainWindowTo(v->x_pos, v->y_pos, true); // lock the main view on the vehicle's last position
+ w->viewport->follow_vehicle = INVALID_VEHICLE;
+ }
+}
--- a/src/vehicle_gui.h Mon May 19 14:14:33 2008 +0000
+++ b/src/vehicle_gui.h Mon May 19 15:13:58 2008 +0000
@@ -5,12 +5,12 @@
#ifndef VEHICLE_GUI_H
#define VEHICLE_GUI_H
-#include "window_gui.h"
+#include "sortlist_type.h"
+#include "window_type.h"
#include "vehicle_type.h"
#include "order_type.h"
#include "station_type.h"
#include "engine_type.h"
-#include "vehicle_base.h"
void DrawVehicleProfitButton(const Vehicle *v, int x, int y);
void ShowVehicleRefitWindow(const Vehicle *v, VehicleOrderID order);
@@ -89,21 +89,6 @@
* For ease of use it can be called with both Vehicle pointers and VehicleIDs. */
void ChangeVehicleViewWindow(VehicleID from_index, VehicleID to_index);
-static inline void ChangeVehicleViewWindow(const Vehicle *from_v, VehicleID to_index)
-{
- ChangeVehicleViewWindow(from_v->index, to_index);
-}
-
-static inline void ChangeVehicleViewWindow(VehicleID from_index, const Vehicle *to_v)
-{
- ChangeVehicleViewWindow(from_index, to_v->index);
-}
-
-static inline void ChangeVehicleViewWindow(const Vehicle *from_v, const Vehicle *to_v)
-{
- ChangeVehicleViewWindow(from_v->index, to_v->index);
-}
-
static inline uint GetVehicleListHeight(VehicleType type)
{
return (type == VEH_TRAIN || type == VEH_ROAD) ? 14 : 24;
@@ -148,8 +133,6 @@
extern Sorting _sorting;
/* sorter stuff */
-void RebuildVehicleLists();
-void ResortVehicleLists();
void SortVehicleList(VehicleListBase *vl);
void BuildVehicleList(VehicleListBase *vl, PlayerID owner, uint16 index, uint16 window_type);
--- a/src/viewport.cpp Mon May 19 14:14:33 2008 +0000
+++ b/src/viewport.cpp Mon May 19 15:13:58 2008 +0000
@@ -47,6 +47,7 @@
#include "misc/smallvec.h"
#include "window_func.h"
#include "tilehighlight_func.h"
+#include "window_gui.h"
#include "table/sprites.h"
#include "table/strings.h"
@@ -1536,17 +1537,17 @@
ViewportDrawChk(vp, left, top, right, bottom);
}
-void DrawWindowViewport(const Window *w)
+void Window::DrawViewport() const
{
DrawPixelInfo *dpi = _cur_dpi;
- dpi->left += w->left;
- dpi->top += w->top;
-
- ViewportDraw(w->viewport, dpi->left, dpi->top, dpi->left + dpi->width, dpi->top + dpi->height);
-
- dpi->left -= w->left;
- dpi->top -= w->top;
+ dpi->left += this->left;
+ dpi->top += this->top;
+
+ ViewportDraw(this->viewport, dpi->left, dpi->top, dpi->left + dpi->width, dpi->top + dpi->height);
+
+ dpi->left -= this->left;
+ dpi->top -= this->top;
}
static inline void ClampViewportToMap(const ViewPort *vp, int &x, int &y)
@@ -2660,7 +2661,10 @@
_thd.selend.y = y;
}
-/** while dragging */
+/**
+ * Handle the mouse while dragging for placement/resizing.
+ * @return Boolean whether search for a handler should continue
+ */
bool VpHandlePlaceSizingDrag()
{
if (_special_mouse_mode != WSM_SIZING) return true;
@@ -2708,12 +2712,18 @@
void SetObjectToPlace(CursorID icon, SpriteID pal, ViewportHighlightMode mode, WindowClass window_class, WindowNumber window_num)
{
- Window *w;
-
/* undo clicking on button and drag & drop */
if (_thd.place_mode != VHM_NONE || _special_mouse_mode == WSM_DRAGDROP) {
- w = FindWindowById(_thd.window_class, _thd.window_number);
- if (w != NULL) w->OnPlaceObjectAbort();
+ Window *w = FindWindowById(_thd.window_class, _thd.window_number);
+ if (w != NULL) {
+ /* Call the abort function, but set the window class to something
+ * that will never be used to avoid infinite loops. Setting it to
+ * the 'next' window class must not be done because recursion into
+ * this function might in some cases reset the newly set object to
+ * place or not properly reset the original selection. */
+ _thd.window_class = WC_INVALID;
+ w->OnPlaceObjectAbort();
+ }
}
SetTileSelectSize(1, 1);
@@ -2734,10 +2744,12 @@
if (mode == VHM_SPECIAL) // special tools, like tunnels or docks start with presizing mode
VpStartPreSizing();
- if ( (int)icon < 0)
+ if ((int)icon < 0) {
SetAnimatedMouseCursor(_animcursors[~icon]);
- else
+ } else {
SetMouseCursor(icon, pal);
+ }
+
}
void ResetObjectToPlace()
--- a/src/water_cmd.cpp Mon May 19 14:14:33 2008 +0000
+++ b/src/water_cmd.cpp Mon May 19 15:13:58 2008 +0000
@@ -838,20 +838,21 @@
case VEH_TRAIN:
if (IsFrontEngine(v)) pass += 4; // driver
v->u.rail.crash_anim_pos = 4000; // max 4440, disappear pretty fast
+ InvalidateWindowClassesData(WC_TRAINS_LIST, 0);
break;
case VEH_ROAD:
if (IsRoadVehFront(v)) pass += 1; // driver
v->u.road.crashed_ctr = 2000; // max 2220, disappear pretty fast
+ InvalidateWindowClassesData(WC_ROADVEH_LIST, 0);
break;
case VEH_AIRCRAFT:
pass += 2; // driver
v->u.air.crashed_counter = 9000; // max 10000, disappear pretty fast
+ InvalidateWindowClassesData(WC_AIRCRAFT_LIST, 0);
break;
}
-
- RebuildVehicleLists();
} else {
return;
}
@@ -861,7 +862,7 @@
SetDParam(0, pass);
AddNewsItem(STR_B006_FLOOD_VEHICLE_DESTROYED,
- NM_THIN, NF_VIEWPORT | NF_VEHICLE, NT_ACCIDENT, DNC_NONE,
+ NS_ACCIDENT_VEHICLE,
v->index,
0);
CreateEffectVehicleRel(v, 4, 4, 8, EV_EXPLOSION_LARGE);
@@ -1123,7 +1124,7 @@
switch (GetWaterTileType(tile)) {
case WATER_TILE_CLEAR: ts = (GetTileSlope(tile, NULL) == SLOPE_FLAT) ? TRACK_BIT_ALL : TRACK_BIT_NONE; break;
case WATER_TILE_COAST: ts = (TrackBits)coast_tracks[GetTileSlope(tile, NULL) & 0xF]; break;
- case WATER_TILE_LOCK: ts = AxisToTrackBits(DiagDirToAxis(GetLockDirection(tile))); break;
+ case WATER_TILE_LOCK: ts = DiagDirToDiagTrackBits(GetLockDirection(tile)); break;
case WATER_TILE_DEPOT: ts = AxisToTrackBits(GetShipDepotAxis(tile)); break;
default: return 0;
}
--- a/src/widget.cpp Mon May 19 14:14:33 2008 +0000
+++ b/src/widget.cpp Mon May 19 15:13:58 2008 +0000
@@ -190,20 +190,20 @@
* Paint all widgets of a window.
* @param w Window
*/
-void DrawWindowWidgets(const Window *w)
+void Window::DrawWidgets() const
{
const DrawPixelInfo* dpi = _cur_dpi;
- for (uint i = 0; i < w->widget_count; i++) {
- const Widget *wi = &w->widget[i];
- bool clicked = w->IsWidgetLowered(i);
+ for (uint i = 0; i < this->widget_count; i++) {
+ const Widget *wi = &this->widget[i];
+ bool clicked = this->IsWidgetLowered(i);
Rect r;
if (dpi->left > (r.right = wi->right) ||
dpi->left + dpi->width <= (r.left = wi->left) ||
dpi->top > (r.bottom = wi->bottom) ||
dpi->top + dpi->height <= (r.top = wi->top) ||
- w->IsWidgetHidden(i)) {
+ this->IsWidgetHidden(i)) {
continue;
}
@@ -304,11 +304,11 @@
assert(r.right - r.left == 11); // To ensure the same sizes are used everywhere!
/* draw up/down buttons */
- clicked = ((w->flags4 & (WF_SCROLL_UP | WF_HSCROLL | WF_SCROLL2)) == WF_SCROLL_UP);
+ clicked = ((this->flags4 & (WF_SCROLL_UP | WF_HSCROLL | WF_SCROLL2)) == WF_SCROLL_UP);
DrawFrameRect(r.left, r.top, r.right, r.top + 9, wi->color, (clicked) ? FR_LOWERED : FR_NONE);
DoDrawString(UPARROW, r.left + 2 + clicked, r.top + clicked, TC_BLACK);
- clicked = (((w->flags4 & (WF_SCROLL_DOWN | WF_HSCROLL | WF_SCROLL2)) == WF_SCROLL_DOWN));
+ clicked = (((this->flags4 & (WF_SCROLL_DOWN | WF_HSCROLL | WF_SCROLL2)) == WF_SCROLL_DOWN));
DrawFrameRect(r.left, r.bottom - 9, r.right, r.bottom, wi->color, (clicked) ? FR_LOWERED : FR_NONE);
DoDrawString(DOWNARROW, r.left + 2 + clicked, r.bottom - 9 + clicked, TC_BLACK);
@@ -325,8 +325,8 @@
GfxFillRect(r.left + 7, r.top + 10, r.left + 7, r.bottom - 10, c1);
GfxFillRect(r.left + 8, r.top + 10, r.left + 8, r.bottom - 10, c2);
- Point pt = HandleScrollbarHittest(&w->vscroll, r.top, r.bottom);
- DrawFrameRect(r.left, pt.x, r.right, pt.y, wi->color, (w->flags4 & (WF_SCROLL_MIDDLE | WF_HSCROLL | WF_SCROLL2)) == WF_SCROLL_MIDDLE ? FR_LOWERED : FR_NONE);
+ Point pt = HandleScrollbarHittest(&this->vscroll, r.top, r.bottom);
+ DrawFrameRect(r.left, pt.x, r.right, pt.y, wi->color, (this->flags4 & (WF_SCROLL_MIDDLE | WF_HSCROLL | WF_SCROLL2)) == WF_SCROLL_MIDDLE ? FR_LOWERED : FR_NONE);
break;
}
@@ -335,11 +335,11 @@
assert(r.right - r.left == 11); // To ensure the same sizes are used everywhere!
/* draw up/down buttons */
- clicked = ((w->flags4 & (WF_SCROLL_UP | WF_HSCROLL | WF_SCROLL2)) == (WF_SCROLL_UP | WF_SCROLL2));
+ clicked = ((this->flags4 & (WF_SCROLL_UP | WF_HSCROLL | WF_SCROLL2)) == (WF_SCROLL_UP | WF_SCROLL2));
DrawFrameRect(r.left, r.top, r.right, r.top + 9, wi->color, (clicked) ? FR_LOWERED : FR_NONE);
DoDrawString(UPARROW, r.left + 2 + clicked, r.top + clicked, TC_BLACK);
- clicked = ((w->flags4 & (WF_SCROLL_DOWN | WF_HSCROLL | WF_SCROLL2)) == (WF_SCROLL_DOWN | WF_SCROLL2));
+ clicked = ((this->flags4 & (WF_SCROLL_DOWN | WF_HSCROLL | WF_SCROLL2)) == (WF_SCROLL_DOWN | WF_SCROLL2));
DrawFrameRect(r.left, r.bottom - 9, r.right, r.bottom, wi->color, (clicked) ? FR_LOWERED : FR_NONE);
DoDrawString(DOWNARROW, r.left + 2 + clicked, r.bottom - 9 + clicked, TC_BLACK);
@@ -356,8 +356,8 @@
GfxFillRect(r.left + 7, r.top + 10, r.left + 7, r.bottom - 10, c1);
GfxFillRect(r.left + 8, r.top + 10, r.left + 8, r.bottom - 10, c2);
- Point pt = HandleScrollbarHittest(&w->vscroll2, r.top, r.bottom);
- DrawFrameRect(r.left, pt.x, r.right, pt.y, wi->color, (w->flags4 & (WF_SCROLL_MIDDLE | WF_HSCROLL | WF_SCROLL2)) == (WF_SCROLL_MIDDLE | WF_SCROLL2) ? FR_LOWERED : FR_NONE);
+ Point pt = HandleScrollbarHittest(&this->vscroll2, r.top, r.bottom);
+ DrawFrameRect(r.left, pt.x, r.right, pt.y, wi->color, (this->flags4 & (WF_SCROLL_MIDDLE | WF_HSCROLL | WF_SCROLL2)) == (WF_SCROLL_MIDDLE | WF_SCROLL2) ? FR_LOWERED : FR_NONE);
break;
}
@@ -366,11 +366,11 @@
assert(wi->data == 0);
assert(r.bottom - r.top == 11); // To ensure the same sizes are used everywhere!
- clicked = ((w->flags4 & (WF_SCROLL_UP | WF_HSCROLL)) == (WF_SCROLL_UP | WF_HSCROLL));
+ clicked = ((this->flags4 & (WF_SCROLL_UP | WF_HSCROLL)) == (WF_SCROLL_UP | WF_HSCROLL));
DrawFrameRect(r.left, r.top, r.left + 9, r.bottom, wi->color, (clicked) ? FR_LOWERED : FR_NONE);
DrawSprite(SPR_ARROW_LEFT, PAL_NONE, r.left + 1 + clicked, r.top + 1 + clicked);
- clicked = ((w->flags4 & (WF_SCROLL_DOWN | WF_HSCROLL)) == (WF_SCROLL_DOWN | WF_HSCROLL));
+ clicked = ((this->flags4 & (WF_SCROLL_DOWN | WF_HSCROLL)) == (WF_SCROLL_DOWN | WF_HSCROLL));
DrawFrameRect(r.right - 9, r.top, r.right, r.bottom, wi->color, (clicked) ? FR_LOWERED : FR_NONE);
DrawSprite(SPR_ARROW_RIGHT, PAL_NONE, r.right - 8 + clicked, r.top + 1 + clicked);
@@ -388,8 +388,8 @@
GfxFillRect(r.left + 10, r.top + 8, r.right - 10, r.top + 8, c2);
/* draw actual scrollbar */
- Point pt = HandleScrollbarHittest(&w->hscroll, r.left, r.right);
- DrawFrameRect(pt.x, r.top, pt.y, r.bottom, wi->color, (w->flags4 & (WF_SCROLL_MIDDLE | WF_HSCROLL)) == (WF_SCROLL_MIDDLE | WF_HSCROLL) ? FR_LOWERED : FR_NONE);
+ Point pt = HandleScrollbarHittest(&this->hscroll, r.left, r.right);
+ DrawFrameRect(pt.x, r.top, pt.y, r.bottom, wi->color, (this->flags4 & (WF_SCROLL_MIDDLE | WF_HSCROLL)) == (WF_SCROLL_MIDDLE | WF_HSCROLL) ? FR_LOWERED : FR_NONE);
break;
}
@@ -429,7 +429,7 @@
assert(wi->data == 0);
assert(r.right - r.left == 11); // To ensure the same sizes are used everywhere!
- clicked = !!(w->flags4 & WF_STICKY);
+ clicked = !!(this->flags4 & WF_STICKY);
DrawFrameRect(r.left, r.top, r.right, r.bottom, wi->color, (clicked) ? FR_LOWERED : FR_NONE);
DrawSprite((clicked) ? SPR_PIN_UP : SPR_PIN_DOWN, PAL_NONE, r.left + 2 + clicked, r.top + 3 + clicked);
break;
@@ -438,7 +438,7 @@
assert(wi->data == 0);
assert(r.right - r.left == 11); // To ensure the same sizes are used everywhere!
- clicked = !!(w->flags4 & WF_SIZING);
+ clicked = !!(this->flags4 & WF_SIZING);
DrawFrameRect(r.left, r.top, r.right, r.bottom, wi->color, (clicked) ? FR_LOWERED : FR_NONE);
DrawSprite(SPR_WINDOW_RESIZE, PAL_NONE, r.left + 3 + clicked, r.top + 3 + clicked);
break;
@@ -457,10 +457,10 @@
case WWT_CAPTION:
assert(r.bottom - r.top == 13); // To ensure the same sizes are used everywhere!
DrawFrameRect(r.left, r.top, r.right, r.bottom, wi->color, FR_BORDERONLY);
- DrawFrameRect(r.left + 1, r.top + 1, r.right - 1, r.bottom - 1, wi->color, (w->caption_color == 0xFF) ? FR_LOWERED | FR_DARKENED : FR_LOWERED | FR_DARKENED | FR_BORDERONLY);
+ DrawFrameRect(r.left + 1, r.top + 1, r.right - 1, r.bottom - 1, wi->color, (this->caption_color == 0xFF) ? FR_LOWERED | FR_DARKENED : FR_LOWERED | FR_DARKENED | FR_BORDERONLY);
- if (w->caption_color != 0xFF) {
- GfxFillRect(r.left + 2, r.top + 2, r.right - 2, r.bottom - 2, _colour_gradient[_player_colors[w->caption_color]][4]);
+ if (this->caption_color != 0xFF) {
+ GfxFillRect(r.left + 2, r.top + 2, r.right - 2, r.bottom - 2, _colour_gradient[_player_colors[this->caption_color]][4]);
}
DrawStringCenteredTruncated(r.left + 2, r.right - 2, r.top + 2, wi->data, 0x84);
@@ -489,14 +489,14 @@
}
}
- if (w->IsWidgetDisabled(i)) {
+ if (this->IsWidgetDisabled(i)) {
GfxFillRect(r.left + 1, r.top + 1, r.right - 1, r.bottom - 1, _colour_gradient[wi->color & 0xF][2] | (1 << PALETTE_MODIFIER_GREYOUT));
}
}
- if (w->flags4 & WF_WHITE_BORDER_MASK) {
- DrawFrameRect(0, 0, w->width - 1, w->height - 1, 0xF, FR_BORDERONLY);
+ if (this->flags4 & WF_WHITE_BORDER_MASK) {
+ DrawFrameRect(0, 0, this->width - 1, this->height - 1, 0xF, FR_BORDERONLY);
}
}
@@ -597,10 +597,10 @@
* @param widget Sort button widget
* @param state State of sort button
*/
-void DrawSortButtonState(const Window *w, int widget, SortButtonState state)
+void Window::DrawSortButtonState(int widget, SortButtonState state) const
{
if (state == SBS_OFF) return;
- int offset = w->IsWidgetLowered(widget) ? 1 : 0;
- DoDrawString(state == SBS_DOWN ? DOWNARROW : UPARROW, w->widget[widget].right - 11 + offset, w->widget[widget].top + 1 + offset, TC_BLACK);
+ int offset = this->IsWidgetLowered(widget) ? 1 : 0;
+ DoDrawString(state == SBS_DOWN ? DOWNARROW : UPARROW, this->widget[widget].right - 11 + offset, this->widget[widget].top + 1 + offset, TC_BLACK);
}
--- a/src/widgets/dropdown.cpp Mon May 19 14:14:33 2008 +0000
+++ b/src/widgets/dropdown.cpp Mon May 19 15:13:58 2008 +0000
@@ -72,7 +72,7 @@
bool drag_mode;
int scrolling;
- DropdownWindow(int x, int y, int width, int height, const Widget *widget) : Window(x, y, width, height, NULL, WC_DROPDOWN_MENU, widget)
+ DropdownWindow(int x, int y, int width, int height, const Widget *widget) : Window(x, y, width, height, WC_DROPDOWN_MENU, widget)
{
}
@@ -87,9 +87,9 @@
DeleteDropDownList(this->list);
}
- int GetDropDownItem()
+ bool GetDropDownItem(int &value)
{
- if (GetWidgetFromPos(this, _cursor.pos.x - this->left, _cursor.pos.y - this->top) < 0) return -1;
+ if (GetWidgetFromPos(this, _cursor.pos.x - this->left, _cursor.pos.y - this->top) < 0) return false;
int y = _cursor.pos.y - this->top - 2;
int width = this->widget[0].right - 3;
@@ -105,19 +105,20 @@
int item_height = item->Height(width);
if (y < item_height) {
- if (item->masked || item->String() == STR_NULL) return -1;
- return item->result;
+ if (item->masked || item->String() == STR_NULL) return false;
+ value = item->result;
+ return true;
}
y -= item_height;
}
- return -1;
+ return false;
}
virtual void OnPaint()
{
- DrawWindowWidgets(this);
+ this->DrawWidgets();
int x = 1;
int y = 2;
@@ -162,8 +163,8 @@
virtual void OnClick(Point pt, int widget)
{
if (widget != 0) return;
- int item = GetDropDownItem();
- if (item >= 0) {
+ int item;
+ if (this->GetDropDownItem(item)) {
this->click_delay = 4;
this->selected_index = item;
this->SetDirty();
@@ -197,11 +198,11 @@
}
if (this->drag_mode) {
- int item = GetDropDownItem();
+ int item;
if (!_left_button_clicked) {
this->drag_mode = false;
- if (item < 0) return;
+ if (!this->GetDropDownItem(item)) return;
this->click_delay = 2;
} else {
if (_cursor.pos.y <= this->top + 2) {
@@ -214,7 +215,7 @@
return;
}
- if (item < 0) return;
+ if (!this->GetDropDownItem(item)) return;
}
this->selected_index = item;
--- a/src/win32.cpp Mon May 19 14:14:33 2008 +0000
+++ b/src/win32.cpp Mon May 19 15:13:58 2008 +0000
@@ -61,7 +61,7 @@
for (;;) {
FARPROC p;
- while (*dll++ != '\0');
+ while (*dll++ != '\0') { /* Nothing */ }
if (*dll == '\0') break;
#if defined(WINCE)
p = GetProcAddress(lib, MB_TO_WIDE(dll));
@@ -796,7 +796,7 @@
fios->mtime = 0;
snprintf(fios->name, lengthof(fios->name), "%c:", s[0] & 0xFF);
ttd_strlcpy(fios->title, fios->name, lengthof(fios->title));
- while (*s++ != '\0');
+ while (*s++ != '\0') { /* Nothing */ }
}
#endif
}
--- a/src/window.cpp Mon May 19 14:14:33 2008 +0000
+++ b/src/window.cpp Mon May 19 15:13:58 2008 +0000
@@ -48,221 +48,6 @@
byte _special_mouse_mode;
-/**
- * Call the window event handler for handling event \a e.
- * This is a temporary helper functions that will be removed
- * once all windows that still rely on WindowEvent and
- * WindowEventCodes have been rewritten to use the 'OnXXX'
- * event handlers.
- * @param e Window event to handle
- */
-void Window::HandleWindowEvent(WindowEvent *e)
-{
- if (wndproc != NULL) wndproc(this, e);
-}
-
-void Window::OnPaint()
-{
- WindowEvent e;
- e.event = WE_PAINT;
- this->HandleWindowEvent(&e);
-}
-
-bool Window::OnKeyPress(uint16 key, uint16 keycode)
-{
- WindowEvent e;
- e.event = WE_KEYPRESS;
- e.we.keypress.key = key;
- e.we.keypress.keycode = keycode;
- e.we.keypress.cont = true;
- this->HandleWindowEvent(&e);
-
- return e.we.keypress.cont;
-}
-
-bool Window::OnCTRLStateChange()
-{
- WindowEvent e;
- e.event = WE_CTRL_CHANGED;
- e.we.ctrl.cont = true;
- this->HandleWindowEvent(&e);
-
- return e.we.ctrl.cont;
-}
-
-void Window::OnClick(Point pt, int widget)
-{
- WindowEvent e;
- e.event = WE_CLICK;
- e.we.click.pt = pt;
- e.we.click.widget = widget;
- this->HandleWindowEvent(&e);
-}
-
-void Window::OnDoubleClick(Point pt, int widget)
-{
- WindowEvent e;
- e.event = WE_DOUBLE_CLICK;
- e.we.click.pt = pt;
- e.we.click.widget = widget;
- this->HandleWindowEvent(&e);
-}
-
-void Window::OnRightClick(Point pt, int widget)
-{
- WindowEvent e;
- e.event = WE_RCLICK;
- e.we.click.pt = pt;
- e.we.click.widget = widget;
- this->HandleWindowEvent(&e);
-}
-
-void Window::OnDragDrop(Point pt, int widget)
-{
- WindowEvent e;
- e.event = WE_DRAGDROP;
- e.we.click.pt = pt;
- e.we.click.widget = widget;
- this->HandleWindowEvent(&e);
-}
-
-void Window::OnScroll(Point delta)
-{
- WindowEvent e;
- e.event = WE_SCROLL;
- e.we.scroll.delta = delta;
- this->HandleWindowEvent(&e);
-}
-
-void Window::OnMouseOver(Point pt, int widget)
-{
- WindowEvent e;
- e.event = WE_MOUSEOVER;
- e.we.click.pt = pt;
- e.we.click.widget = widget;
- this->HandleWindowEvent(&e);
-}
-
-void Window::OnMouseWheel(int wheel)
-{
- WindowEvent e;
- e.event = WE_MOUSEWHEEL;
- e.we.wheel.wheel = wheel;
- this->HandleWindowEvent(&e);
-}
-
-void Window::OnMouseLoop()
-{
- WindowEvent e;
- e.event = WE_MOUSELOOP;
- this->HandleWindowEvent(&e);
-}
-
-void Window::OnTick()
-{
- WindowEvent e;
- e.event = WE_TICK;
- this->HandleWindowEvent(&e);
-}
-
-void Window::OnHundredthTick()
-{
- WindowEvent e;
- e.event = WE_100_TICKS;
- this->HandleWindowEvent(&e);
-}
-
-void Window::OnTimeout()
-{
- WindowEvent e;
- e.event = WE_TIMEOUT;
- this->HandleWindowEvent(&e);
-}
-
-void Window::OnResize(Point new_size, Point delta)
-{
- WindowEvent e;
- e.event = WE_RESIZE;
- e.we.sizing.size = new_size;
- e.we.sizing.diff = delta;
- this->HandleWindowEvent(&e);
-}
-
-void Window::OnDropdownSelect(int widget, int index)
-{
- WindowEvent e;
- e.event = WE_DROPDOWN_SELECT;
- e.we.dropdown.button = widget;
- e.we.dropdown.index = index;
- this->HandleWindowEvent(&e);
-}
-
-void Window::OnQueryTextFinished(char *str)
-{
- WindowEvent e;
- e.event = WE_ON_EDIT_TEXT;
- e.we.edittext.str = str;
- this->HandleWindowEvent(&e);
-}
-
-void Window::OnInvalidateData(int data)
-{
- WindowEvent e;
- e.event = WE_INVALIDATE_DATA;
- e.we.invalidate.data = data;
- this->HandleWindowEvent(&e);
-}
-
-void Window::OnPlaceObject(Point pt, TileIndex tile)
-{
- WindowEvent e;
- e.event = WE_PLACE_OBJ;
- e.we.place.pt = pt;
- e.we.place.tile = tile;
- this->HandleWindowEvent(&e);
-}
-
-void Window::OnPlaceObjectAbort()
-{
- WindowEvent e;
- e.event = WE_ABORT_PLACE_OBJ;
- this->HandleWindowEvent(&e);
-}
-
-
-void Window::OnPlaceDrag(ViewportPlaceMethod select_method, byte select_proc, Point pt)
-{
- WindowEvent e;
- e.event = WE_PLACE_DRAG;
- e.we.place.select_method = select_method;
- e.we.place.select_proc = select_proc;
- e.we.place.pt = pt;
- this->HandleWindowEvent(&e);
-}
-
-void Window::OnPlaceMouseUp(ViewportPlaceMethod select_method, byte select_proc, Point pt, TileIndex start_tile, TileIndex end_tile)
-{
- WindowEvent e;
- e.event = WE_PLACE_MOUSEUP;
- e.we.place.select_method = select_method;
- e.we.place.select_proc = select_proc;
- e.we.place.pt = pt;
- e.we.place.tile = end_tile;
- e.we.place.starttile = start_tile;
- this->HandleWindowEvent(&e);
-}
-
-void Window::OnPlacePresize(Point pt, TileIndex tile)
-{
- WindowEvent e;
- e.event = WE_PLACE_PRESIZE;
- e.we.place.pt = pt;
- e.we.place.tile = tile;
- this->HandleWindowEvent(&e);
-}
-
-
-
void CDECL Window::SetWidgetsDisabledState(bool disab_stat, int widgets, ...)
{
va_list wdg_list;
@@ -626,12 +411,13 @@
memmove(wz, wz + 1, (byte*)_last_z_window - (byte*)wz);
_last_z_window--;
- /* Delete any children a window might have in a head-recursive manner */
- delete FindChildWindow(this);
+ /* Delete all children a window might have in a head-recursive manner */
+ Window *child = FindChildWindow(this);
+ while (child != NULL) {
+ delete child;
+ child = FindChildWindow(this);
+ }
- WindowEvent e;
- e.event = WE_DESTROY;
- this->HandleWindowEvent(&e);
if (this->viewport != NULL) DeleteWindowViewport(this);
this->SetDirty();
@@ -844,11 +630,6 @@
NOT_REACHED();
}
-bool IsWindowOfPrototype(const Window *w, const Widget *widget)
-{
- return (w->original_widget == widget);
-}
-
/**
* Assign widgets to a new window by initialising its widget pointers, and by
* copying the widget array \a widget to \c w->widget to allow for resizable
@@ -857,13 +638,10 @@
* @param widget pointer of widget array to fill the window with
*
* @post \c w->widget points to allocated memory and contains the copied widget array except for the terminating widget,
- * \c w->original_widget points to the original widgets,
* \c w->widget_count contains number of widgets in the allocated memory.
*/
static void AssignWidgetToWindow(Window *w, const Widget *widget)
{
- w->original_widget = widget;
-
if (widget != NULL) {
uint index = 1;
@@ -887,14 +665,13 @@
* @param y offset in pixels from the top of the screen
* @param min_width minimum width in pixels of the window
* @param min_height minimum height in pixels of the window
- * @param *proc see WindowProc function to call when any messages/updates happen to the window
* @param cls see WindowClass class of the window, used for identification and grouping
* @param *widget see Widget pointer to the window layout and various elements
* @param window_number number being assigned to the new window
- * @param data the data to be given during the WE_CREATE message
- * @return Window pointer of the newly created window */
+ * @return Window pointer of the newly created window
+ */
void Window::Initialize(int x, int y, int min_width, int min_height,
- WindowProc *proc, WindowClass cls, const Widget *widget, int window_number, void *data)
+ WindowClass cls, const Widget *widget, int window_number)
{
/* We have run out of windows, close one and use that as the place for our new one */
if (_last_z_window == endof(_z_windows)) {
@@ -911,7 +688,6 @@
this->top = y;
this->width = min_width;
this->height = min_height;
- this->wndproc = proc;
AssignWidgetToWindow(this, widget);
this->resize.width = min_width;
this->resize.height = min_height;
@@ -940,11 +716,6 @@
*wz = this;
_last_z_window++;
-
- WindowEvent e;
- e.event = WE_CREATE;
- e.we.create.data = data;
- this->HandleWindowEvent(&e);
}
/**
@@ -1020,16 +791,13 @@
* @param y offset in pixels from the top of the screen
* @param width width in pixels of the window
* @param height height in pixels of the window
- * @param *proc see WindowProc function to call when any messages/updates happen to the window
* @param cls see WindowClass class of the window, used for identification and grouping
* @param *widget see Widget pointer to the window layout and various elements
* @return Window pointer of the newly created window
*/
-Window::Window(int x, int y, int width, int height, WindowProc *proc, WindowClass cls, const Widget *widget, void *data)
+Window::Window(int x, int y, int width, int height, WindowClass cls, const Widget *widget)
{
- this->Initialize(x, y, width, height, proc, cls, widget, 0, data);
-
- if (proc != NULL) this->FindWindowPlacementAndResize(width, height);
+ this->Initialize(x, y, width, height, cls, widget, 0);
}
@@ -1215,17 +983,14 @@
*
* @param *desc The pointer to the WindowDesc to be created
* @param window_number the window number of the new window
- * @param data arbitrary data that is send with the WE_CREATE message
*
* @return Window pointer of the newly created window
*/
-Window::Window(const WindowDesc *desc, void *data, WindowNumber window_number)
+Window::Window(const WindowDesc *desc, WindowNumber window_number)
{
Point pt = LocalGetWindowPlacement(desc, window_number);
- this->Initialize(pt.x, pt.y, desc->minimum_width, desc->minimum_height, desc->proc, desc->cls, desc->widgets, window_number, data);
+ this->Initialize(pt.x, pt.y, desc->minimum_width, desc->minimum_height, desc->cls, desc->widgets, window_number);
this->desc_flags = desc->flags;
-
- if (desc->proc != NULL) this->FindWindowPlacementAndResize(desc->default_width, desc->default_height);
}
/** Do a search for a window at specific coordinates. For this we start
@@ -1860,8 +1625,7 @@
w->window_class != WC_COMPANY_PASSWORD_WINDOW) {
continue;
}
- ;
- if (!w->OnKeyPress(key, keycode)) return;
+ if (w->OnKeyPress(key, keycode) == Window::ES_HANDLED) return;
}
Window *w = FindWindowById(WC_MAIN_TOOLBAR, 0);
@@ -1877,7 +1641,7 @@
/* Call the event, start with the uppermost window. */
for (Window* const *wz = _last_z_window; wz != _z_windows;) {
Window *w = *--wz;
- if (!w->OnCTRLStateChange()) break;
+ if (w->OnCTRLStateChange() == Window::ES_HANDLED) return;
}
}
@@ -1970,7 +1734,7 @@
if (mousewheel != 0) {
if (_patches.scrollwheel_scrolling == 0) {
- /* Send WE_MOUSEWHEEL event to window */
+ /* Send mousewheel event to window */
w->OnMouseWheel(mousewheel);
}
@@ -2400,3 +2164,13 @@
w->top = top;
}
}
+
+/** Destructor of the base class PickerWindowBase
+ * Main utility is to stop the base Window destructor from triggering
+ * a free while the child will already be free, in this case by the ResetObjectToPlace().
+ */
+PickerWindowBase::~PickerWindowBase()
+{
+ this->window_class = WC_INVALID; // stop the ancestor from freeing the already (to be) child
+ ResetObjectToPlace();
+}
--- a/src/window_gui.h Mon May 19 14:14:33 2008 +0000
+++ b/src/window_gui.h Mon May 19 15:13:58 2008 +0000
@@ -20,8 +20,6 @@
*/
static const int MAX_NUMBER_OF_WINDOWS = 25;
-typedef void WindowProc(Window *w, WindowEvent *e);
-
/* How the resize system works:
First, you need to add a WWT_RESIZEBOX to the widgets, and you need
to add the flag WDF_RESIZABLE to the window. Now the window is ready
@@ -106,109 +104,6 @@
void DrawFrameRect(int left, int top, int right, int bottom, int color, FrameFlags flags);
/**
- * Available window events
- */
-enum WindowEventCodes {
- WE_CREATE, ///< Initialize the Window
- WE_DESTROY, ///< Prepare for deletion of the window
- WE_PAINT, ///< Repaint the window contents
- WE_KEYPRESS, ///< Key pressed
- WE_CLICK, ///< Left mouse button click
- WE_DOUBLE_CLICK, ///< Left mouse button double click
- WE_RCLICK, ///< Right mouse button click
- WE_MOUSEOVER,
- WE_MOUSEWHEEL,
- WE_MOUSELOOP, ///< Event for each mouse event in the game (at least once every game tick)
- WE_TICK, ///< Regularly occurring event (every game tick)
- WE_100_TICKS, ///< Regularly occurring event (every 100 game ticks, approximatelly 3 seconds)
- WE_TIMEOUT,
- WE_PLACE_OBJ,
- WE_ABORT_PLACE_OBJ,
- WE_ON_EDIT_TEXT,
- WE_DRAGDROP,
- WE_PLACE_DRAG,
- WE_PLACE_MOUSEUP,
- WE_PLACE_PRESIZE,
- WE_DROPDOWN_SELECT,
- WE_RESIZE, ///< Request to resize the window, @see WindowEvent.we.resize
- WE_SCROLL,
- WE_INVALIDATE_DATA, ///< Notification that data displayed by the window is obsolete
- WE_CTRL_CHANGED, ///< CTRL key has changed state
-};
-
-/**
- * Data structures for additional data associated with a window event
- * @see WindowEventCodes
- */
-struct WindowEvent {
- byte event;
- union {
- struct {
- void *data;
- } create;
-
- struct {
- Point pt;
- int widget;
- } click;
-
- struct {
- Point pt;
- TileIndex tile;
- TileIndex starttile;
- ViewportPlaceMethod select_method;
- byte select_proc;
- } place;
-
- struct {
- Point pt;
- int widget;
- } dragdrop;
-
- struct {
- Point size;
- Point diff;
- } sizing;
-
- struct {
- char *str;
- } edittext;
-
- struct {
- int button;
- int index;
- } dropdown;
-
- struct {
- Point pt;
- int widget;
- } mouseover;
-
- struct {
- bool cont; ///< continue the search? (default true)
- uint16 key; ///< 16-bit Unicode value of the key
- uint16 keycode; ///< untranslated key (including shift-state)
- } keypress;
-
- struct {
- int data;
- } invalidate;
-
- struct {
- Point delta; ///< delta position against position of last call
- } scroll;
-
- struct {
- int wheel; ///< how much was 'wheel'd'
- } wheel;
-
- struct {
- bool cont; ///< continue the search? (default true)
- } ctrl;
- } we;
-};
-
-/**
* High level window description
*/
struct WindowDesc {
@@ -222,7 +117,6 @@
WindowClass parent_cls; ///< Class of the parent window, @see WindowClass
uint32 flags; ///< Flags, @see WindowDefaultFlags
const Widget *widgets; ///< List of widgets with their position and size for the window
- WindowProc *proc; ///< Window event handler function for the window
};
/**
@@ -249,8 +143,6 @@
WDP_ALIGN_TBL = -4, ///< Align the left side of the window with the left side of the main toolbar
};
-#define WP(ptr, str) (*(str*)(ptr)->custom)
-
/**
* Scrollbar data structure
*/
@@ -270,6 +162,12 @@
uint step_height; ///< Step-size of height resize changes
};
+enum SortButtonState {
+ SBS_OFF,
+ SBS_DOWN,
+ SBS_UP,
+};
+
/**
* Data structure for a window viewport
*/
@@ -281,23 +179,24 @@
int32 dest_scrollpos_y;
};
- /**
+/**
* Data structure for an opened window
*/
struct Window : ZeroedMemoryAllocator {
-private:
- WindowProc *wndproc; ///< Event handler function for the window. Do not use directly, call HandleWindowEvent() instead.
- void HandleWindowEvent(WindowEvent *e);
+ enum EventState {
+ ES_HANDLED,
+ ES_NOT_HANDLED,
+ };
protected:
void Initialize(int x, int y, int min_width, int min_height,
- WindowProc *proc, WindowClass cls, const Widget *widget, int window_number, void *data);
+ WindowClass cls, const Widget *widget, int window_number);
void FindWindowPlacementAndResize(int def_width, int def_height);
void FindWindowPlacementAndResize(const WindowDesc *desc);
public:
- Window(int x, int y, int width, int height, WindowProc *proc, WindowClass cls, const Widget *widget, void *data = NULL);
- Window(const WindowDesc *desc, void *data = NULL, WindowNumber number = 0);
+ Window(int x, int y, int width, int height, WindowClass cls, const Widget *widget);
+ Window(const WindowDesc *desc, WindowNumber number = 0);
virtual ~Window();
@@ -318,13 +217,11 @@
byte caption_color; ///< Background color of the window caption, contains PlayerID
ViewportData *viewport; ///< Pointer to viewport data, if present
- const Widget *original_widget; ///< Original widget layout, copied from WindowDesc
Widget *widget; ///< Widgets of the window
uint widget_count; ///< Number of widgets of the window
uint32 desc_flags; ///< Window/widgets default flags setting, @see WindowDefaultFlag
Window *parent; ///< Parent window
- byte custom[WINDOW_CUSTOM_SIZE]; ///< Additional data depending on window type
void HandleButtonClick(byte widget);
@@ -348,6 +245,10 @@
void CDECL SetWidgetsLoweredState(bool lowered_stat, int widgets, ...);
void InvalidateWidget(byte widget_index) const;
+ void DrawWidgets() const;
+ void DrawViewport() const;
+ void DrawSortButtonState(int widget, SortButtonState state) const;
+
void SetDirty() const;
/*** Event handling ***/
@@ -355,24 +256,24 @@
/**
* This window is currently being repainted.
*/
- virtual void OnPaint();
+ virtual void OnPaint() {}
/**
* A key has been pressed.
* @param key the Unicode value of the key.
* @param keycode the untranslated key code including shift state.
- * @return true if the key press has been handled and no other
+ * @return ES_HANDLED if the key press has been handled and no other
* window should receive the event.
*/
- virtual bool OnKeyPress(uint16 key, uint16 keycode);
+ virtual EventState OnKeyPress(uint16 key, uint16 keycode) { return ES_NOT_HANDLED; }
/**
* The state of the control key has changed
- * @return true if the change has been handled and no other
+ * @return ES_HANDLED if the change has been handled and no other
* window should receive the event.
*/
- virtual bool OnCTRLStateChange();
+ virtual EventState OnCTRLStateChange() { return ES_NOT_HANDLED; }
/**
@@ -380,34 +281,34 @@
* @param pt the point inside the window that has been clicked.
* @param widget the clicked widget.
*/
- virtual void OnClick(Point pt, int widget);
+ virtual void OnClick(Point pt, int widget) {}
/**
* A double click with the left mouse button has been made on the window.
* @param pt the point inside the window that has been clicked.
* @param widget the clicked widget.
*/
- virtual void OnDoubleClick(Point pt, int widget);
+ virtual void OnDoubleClick(Point pt, int widget) {}
/**
* A click with the right mouse button has been made on the window.
* @param pt the point inside the window that has been clicked.
* @param widget the clicked widget.
*/
- virtual void OnRightClick(Point pt, int widget);
+ virtual void OnRightClick(Point pt, int widget) {}
/**
* A dragged 'object' has been released.
* @param pt the point inside the window where the release took place.
* @param widget the widget where the release took place.
*/
- virtual void OnDragDrop(Point pt, int widget);
+ virtual void OnDragDrop(Point pt, int widget) {}
/**
* Handle the request for (viewport) scrolling.
* @param delta the amount the viewport must be scrolled.
*/
- virtual void OnScroll(Point delta);
+ virtual void OnScroll(Point delta) {}
/**
* The mouse is currently moving over the window or has just moved outside
@@ -415,34 +316,34 @@
* @param pt the point inside the window that the mouse hovers over.
* @param widget the widget the mouse hovers over.
*/
- virtual void OnMouseOver(Point pt, int widget);
+ virtual void OnMouseOver(Point pt, int widget) {}
/**
* The mouse wheel has been turned.
* @param wheel the amount of movement of the mouse wheel.
*/
- virtual void OnMouseWheel(int wheel);
+ virtual void OnMouseWheel(int wheel) {}
/**
* Called for every mouse loop run, which is at least once per (game) tick.
*/
- virtual void OnMouseLoop();
+ virtual void OnMouseLoop() {}
/**
* Called once per (game) tick.
*/
- virtual void OnTick();
+ virtual void OnTick() {}
/**
* Called once every 100 (game) ticks.
*/
- virtual void OnHundredthTick();
+ virtual void OnHundredthTick() {}
/**
* Called when this window's timeout has been reached.
*/
- virtual void OnTimeout();
+ virtual void OnTimeout() {}
/**
@@ -450,27 +351,27 @@
* @param new_size the new size of the window.
* @param delta the amount of which the window size changed.
*/
- virtual void OnResize(Point new_size, Point delta);
+ virtual void OnResize(Point new_size, Point delta) {}
/**
* A dropdown option associated to this window has been selected.
* @param widget the widget (button) that the dropdown is associated with.
* @param index the element in the dropdown that is selected.
*/
- virtual void OnDropdownSelect(int widget, int index);
+ virtual void OnDropdownSelect(int widget, int index) {}
/**
* The query window opened from this window has closed.
* @param str the new value of the string or NULL if the window
* was cancelled.
*/
- virtual void OnQueryTextFinished(char *str);
+ virtual void OnQueryTextFinished(char *str) {}
/**
* Some data on this window has become invalid.
* @param data information about the changed data.
*/
- virtual void OnInvalidateData(int data = 0);
+ virtual void OnInvalidateData(int data = 0) {}
/**
@@ -479,12 +380,12 @@
* @param pt the exact point on the map that has been clicked.
* @param tile the tile on the map that has been clicked.
*/
- virtual void OnPlaceObject(Point pt, TileIndex tile);
+ virtual void OnPlaceObject(Point pt, TileIndex tile) {}
/**
* The user cancelled a tile highlight mode that has been set.
*/
- virtual void OnPlaceObjectAbort();
+ virtual void OnPlaceObjectAbort() {}
/**
@@ -494,7 +395,7 @@
* @param select_proc what will be created when the drag is over.
* @param pt the exact point on the map where the mouse is.
*/
- virtual void OnPlaceDrag(ViewportPlaceMethod select_method, byte select_proc, Point pt);
+ virtual void OnPlaceDrag(ViewportPlaceMethod select_method, ViewportDragDropSelectionProcess select_proc, Point pt) {}
/**
* The user has dragged over the map when the tile highlight mode
@@ -505,7 +406,7 @@
* @param start_tile the begin tile of the drag.
* @param end_tile the end tile of the drag.
*/
- virtual void OnPlaceMouseUp(ViewportPlaceMethod select_method, byte select_proc, Point pt, TileIndex start_tile, TileIndex end_tile);
+ virtual void OnPlaceMouseUp(ViewportPlaceMethod select_method, ViewportDragDropSelectionProcess select_proc, Point pt, TileIndex start_tile, TileIndex end_tile) {}
/**
* The user moves over the map when a tile highlight mode has been set
@@ -514,51 +415,20 @@
* @param pt the exact point on the map where the mouse is.
* @param tile the tile on the map where the mouse is.
*/
- virtual void OnPlacePresize(Point pt, TileIndex tile);
+ virtual void OnPlacePresize(Point pt, TileIndex tile) {}
/*** End of the event handling ***/
};
-struct menu_d {
- byte item_count; ///< follow_vehicle
- byte sel_index; ///< scrollpos_x
- byte main_button; ///< scrollpos_y
- byte action_id;
- StringID string_id; ///< unk30
- uint16 checked_items; ///< unk32
- byte disabled_items;
-};
-assert_compile(WINDOW_CUSTOM_SIZE >= sizeof(menu_d));
-
-struct def_d {
- int16 data_1, data_2, data_3;
- int16 data_4, data_5;
- bool close;
- byte byte_1;
-};
-assert_compile(WINDOW_CUSTOM_SIZE >= sizeof(def_d));
+/**
+ * Data structure for a window opened from a toolbar
+ */
+class PickerWindowBase : public Window {
-enum SortListFlags {
- VL_NONE = 0, ///< no sort
- VL_DESC = 1 << 0, ///< sort descending or ascending
- VL_RESORT = 1 << 1, ///< instruct the code to resort the list in the next loop
- VL_REBUILD = 1 << 2, ///< create sort-listing to use for qsort and friends
- VL_END = 1 << 3,
-};
-DECLARE_ENUM_AS_BIT_SET(SortListFlags);
+public:
+ PickerWindowBase(const WindowDesc *desc) : Window(desc) {}; // nothing special yet, just propagation
-struct Listing {
- bool order; ///< Ascending/descending
- byte criteria; ///< Sorting criteria
-};
-
-template <typename T>
-struct GUIList {
- T* sort_list; ///< The items to sort.
- SortListFlags flags; ///< used to control sorting/resorting/etc.
- uint16 list_length; ///< length of the list being sorted
- uint16 resort_timer; ///< resort list after a given amount of ticks if set
- byte sort_type; ///< what criteria to sort on
+ virtual ~PickerWindowBase();
};
/****************** THESE ARE NOT WIDGET TYPES!!!!! *******************/
@@ -632,8 +502,6 @@
Window *BringWindowToFrontById(WindowClass cls, WindowNumber number);
Window *FindWindowFromPt(int x, int y);
-bool IsWindowOfPrototype(const Window *w, const Widget *widget);
-
/**
* Open a new window.
* @param *desc The pointer to the WindowDesc to be created
@@ -642,14 +510,12 @@
* @return see Window pointer of the newly created window
*/
template <typename Wcls>
-Wcls *AllocateWindowDescFront(const WindowDesc *desc, int window_number, void *data = NULL)
+Wcls *AllocateWindowDescFront(const WindowDesc *desc, int window_number)
{
if (BringWindowToFrontById(desc->cls, window_number)) return NULL;
- return new Wcls(desc, data, window_number);
+ return new Wcls(desc, window_number);
}
-void DrawWindowViewport(const Window *w);
-
void RelocateAllWindows(int neww, int newh);
/* misc_gui.cpp */
@@ -661,17 +527,6 @@
/* widget.cpp */
int GetWidgetFromPos(const Window *w, int x, int y);
-void DrawWindowWidgets(const Window *w);
-
-enum SortButtonState {
- SBS_OFF,
- SBS_DOWN,
- SBS_UP,
-};
-
-void DrawSortButtonState(const Window *w, int widget, SortButtonState state);
-
-
/* window.cpp */
extern Window *_z_windows[];
--- a/src/window_type.h Mon May 19 14:14:33 2008 +0000
+++ b/src/window_type.h Mon May 19 15:13:58 2008 +0000
@@ -94,17 +94,11 @@
WC_BUILD_SIGNAL,
WC_COMPANY_PASSWORD_WINDOW,
WC_OSK,
+
+ WC_INVALID = 0xFFFF
};
struct Window;
-struct WindowEvent;
typedef int32 WindowNumber;
-/**
- * You cannot 100% reliably calculate the biggest custom struct as
- * the number of pointers in it and alignment will have a huge impact.
- * 96 is the largest window-size for 64-bit machines currently.
- */
-#define WINDOW_CUSTOM_SIZE 96
-
#endif /* WINDOW_TYPE_H */
--- a/src/yapf/yapf_road.cpp Mon May 19 14:14:33 2008 +0000
+++ b/src/yapf/yapf_road.cpp Mon May 19 15:13:58 2008 +0000
@@ -88,7 +88,7 @@
if (v->current_order.IsType(OT_GOTO_STATION) && tile == v->dest_tile) break;
// stop if we have just entered the depot
- if (IsRoadDepotTile(tile) && trackdir == DiagdirToDiagTrackdir(ReverseDiagDir(GetRoadDepotDirection(tile)))) {
+ if (IsRoadDepotTile(tile) && trackdir == DiagDirToDiagTrackdir(ReverseDiagDir(GetRoadDepotDirection(tile)))) {
// next time we will reverse and leave the depot
break;
}
@@ -264,7 +264,7 @@
// handle special case - when next tile is destination tile
if (tile == v->dest_tile) {
// choose diagonal trackdir reachable from enterdir
- return (Trackdir)DiagdirToDiagTrackdir(enterdir);
+ return DiagDirToDiagTrackdir(enterdir);
}
// our source tile will be the next vehicle tile (should be the given one)
TileIndex src_tile = tile;