(svn r12356) [NewGRF_ports] -Codechange: Use enummed widgets since its got them.
/* $Id$ */
/** @file airport_gui.cpp */
#include "stdafx.h"
#include "openttd.h"
#include "window_gui.h"
#include "gui.h"
#include "station_gui.h"
#include "terraform_gui.h"
#include "command_func.h"
#include "station.h"
#include "airport.h"
#include "depot.h"
#include "newgrf_callbacks.h"
#include "sound_func.h"
#include "window_func.h"
#include "settings_type.h"
#include "viewport_func.h"
#include "gfx_func.h"
#include "player_func.h"
#include "widgets/dropdown_type.h"
#include "widgets/dropdown_func.h"
#include "strings_func.h"
//TODO: remove station.h once converted to newgrf airports. stations just used as temporary loader
#include "station.h"
#include "table/sprites.h"
#include "table/strings.h"
static struct {
byte layout_set;
byte numtracks;
byte platlength;
bool dragdrop;
FSMportsClassIDByte fsmports_class;
byte station_type;
byte station_count;
DirectionByte direction;
} _airport;
static void ShowBuildAirportPicker();
void CcBuildAirport(bool success, TileIndex tile, uint32 p1, uint32 p2)
{
if (success) {
SndPlayTileFx(SND_1F_SPLAT, tile);
ResetObjectToPlace();
}
}
static void PlaceAirport(TileIndex tile)
{
if (_airport.station_type != 0xFF) /*0xFF represents No Airports Available to build */
DoCommandP(tile,
_airport.layout_set | (_airport.numtracks << 8) | (_airport.platlength << 16) | (_ctrl_pressed << 24),
0x80 | (_airport.fsmports_class << 8) | (_airport.station_type << 16), CcBuildAirport,
CMD_BUILD_AIRPORT | CMD_MSG(STR_A001_CAN_T_BUILD_AIRPORT_HERE));
}
static void PlaceAir_DemolishArea(TileIndex tile)
{
VpStartPlaceSizing(tile, VPM_X_AND_Y, DDSP_DEMOLISH_AREA);
}
enum {
ATW_AIRPORT = 3,
ATW_DEMOLISH = 4
};
static void BuildAirClick_Airport(Window *w)
{
if (HandlePlacePushButton(w, ATW_AIRPORT, SPR_CURSOR_AIRPORT, VHM_RECT, PlaceAirport)) ShowBuildAirportPicker();
}
static void BuildAirClick_Demolish(Window *w)
{
HandlePlacePushButton(w, ATW_DEMOLISH, ANIMCURSOR_DEMOLISH, VHM_RECT, PlaceAir_DemolishArea);
}
typedef void OnButtonClick(Window *w);
static OnButtonClick * const _build_air_button_proc[] = {
BuildAirClick_Airport,
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;
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 && e->we.place.select_proc == DDSP_DEMOLISH_AREA) {
DoCommandP(e->we.place.tile, e->we.place.starttile, 0, CcPlaySound10, CMD_CLEAR_AREA | CMD_MSG(STR_00B5_CAN_T_CLEAR_THIS_AREA));
}
break;
case WE_ABORT_PLACE_OBJ:
w->RaiseButtons();
w = FindWindowById(WC_BUILD_STATION, 0);
if (w != 0)
WP(w, def_d).close = true;
break;
case WE_DESTROY:
if (_patches.link_terraform_toolbar) DeleteWindowById(WC_SCEN_LAND_GEN, 0);
break;
}
}
static const Widget _air_toolbar_widgets[] = {
{ WWT_CLOSEBOX, RESIZE_NONE, 7, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW },
{ WWT_CAPTION, RESIZE_NONE, 7, 11, 51, 0, 13, STR_A000_AIRPORTS, STR_018C_WINDOW_TITLE_DRAG_THIS },
{ WWT_STICKYBOX, RESIZE_NONE, 7, 52, 63, 0, 13, 0x0, STR_STICKY_BUTTON },
{ WWT_IMGBTN, RESIZE_NONE, 7, 0, 41, 14, 35, SPR_IMG_AIRPORT, STR_A01E_BUILD_AIRPORT },
{ WWT_IMGBTN, RESIZE_NONE, 7, 42, 63, 14, 35, SPR_IMG_DYNAMITE, STR_018D_DEMOLISH_BUILDINGS_ETC },
{ WIDGETS_END},
};
static const WindowDesc _air_toolbar_desc = {
WDP_ALIGN_TBR, 22, 64, 36, 64, 36,
WC_BUILD_TOOLBAR, WC_NONE,
WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_STICKY_BUTTON,
_air_toolbar_widgets,
BuildAirToolbWndProc
};
void ShowBuildAirToolbar()
{
if (!IsValidPlayer(_current_player)) return;
DeleteWindowById(WC_BUILD_TOOLBAR, 0);
Window *w = AllocateWindowDescFront(&_air_toolbar_desc, 0);
if (_patches.link_terraform_toolbar) ShowTerraformToolbar(w);
}
/** Enum referring to the widgets of the airport build window */
enum BuildAirportWidgets {
BAPW_CLOSEBOX = 0,
BAPW_CAPTION,
BAPW_BACKGROUND,
BAPW_NEWAP_DROPDOWN,
BAPW_NEWAP_LIST,
BAPW_NEWAP_SCROLL,
BAPW_MINIPIC_PANEL,
BAPW_ORIENT_NE,
BAPW_ORIENT_SE,
BAPW_ORIENT_SW,
BAPW_ORIENT_NW,
BAPW_HIGHLIGHT_OFF,
BAPW_HIGHLIGHT_ON,
};
static void BuildAirportPickerWndProc(Window *w, WindowEvent *e)
{
switch (e->event) {
case WE_CREATE:
w->SetWidgetLoweredState(BAPW_HIGHLIGHT_OFF, !_station_show_coverage);
w->SetWidgetLoweredState(BAPW_HIGHLIGHT_ON, _station_show_coverage);
break;
case WE_PAINT: {
byte preview_sprite = 0xFF;
FSMportsSpec *fsmportspec = GetCustomFSMportsSpec(_airport.fsmports_class, _airport.station_type);
/* if the port is no longer available, find one that is */
if ((fsmportspec == NULL) || (HasBit(fsmportspec->callbackmask, CBM_STATION_AVAIL) && GetFSMportsCallback(CBID_STATION_AVAILABILITY, 0, 0, fsmportspec, NULL, INVALID_TILE) == 0)) {
/* port not available, find new one*/
_airport.station_type = 0xFF; //set to the invalid condition to prevent any selection if nothing is available
for (uint i = 0; i < _airport.station_count; i++) {
fsmportspec = GetCustomFSMportsSpec(_airport.fsmports_class, i);
if (!HasBit(fsmportspec->callbackmask, CBM_STATION_AVAIL) || GetFSMportsCallback(CBID_STATION_AVAILABILITY, 0, 0, fsmportspec, NULL, INVALID_TILE) != 0) {
_airport.station_type = i;
break;
}
}
}
if (WP(w, def_d).close) return;
for (byte j = 0; j < 4; j++) {
w->SetWidgetDisabledState(BAPW_ORIENT_NE + j, true);
w->RaiseWidget(BAPW_ORIENT_NE + j);
w->widget[BAPW_ORIENT_NE + j].data = SPR_IMG_ARROW_NE_WHITE + j; //reset arrows to white
}
if (_airport.station_type != 0xFF) {
int x = fsmportspec->size_x[_airport.layout_set];
int y = fsmportspec->size_y[_airport.layout_set];
SetTileSelectSize(x, y);
/* an airport is available, so read it and update screen accordingly */
for (byte j = 0; j < fsmportspec->numlayouts; j++) {
if (fsmportspec->layouts[j] == NULL) break;
/* enable the permitted orientations */
byte *layout_ptr = (byte*)alloca(x*y + 2);
memcpy(layout_ptr, fsmportspec->layouts[j], (x * y) + 2);
w->SetWidgetDisabledState(BAPW_ORIENT_NE + GB((byte)*layout_ptr, 1, 2), false);
if (j == _airport.layout_set) {
layout_ptr++;
preview_sprite = *layout_ptr;
}
}
w->LowerWidget(BAPW_ORIENT_NE + DirToDiagDir(_airport.direction));
w->widget[BAPW_ORIENT_NE + DirToDiagDir(_airport.direction)].data = SPR_IMG_ARROW_NE_YELLOW + DirToDiagDir(_airport.direction); //show in yellow
}
SetDParam(0, GetFSMportsClassName(_airport.fsmports_class));
DrawWindowWidgets(w);
// strings such as 'Size' and 'Coverage Area'
// 'Coverage Area'
if (_airport.station_type != 0xFF) {
/* draw the preview image if the station is available */
if (!HasBit(fsmportspec->callbackmask, CBM_STATION_AVAIL) || GetFSMportsCallback(CBID_STATION_AVAILABILITY, 0, 0, fsmportspec, NULL, INVALID_TILE) != 0) {
DrawFSMportsTile(9, 106, preview_sprite, _airport.fsmports_class, _airport.station_type);
}
_thd.FSMportLayout = &fsmportspec->layouts[_airport.layout_set]; // irregular airport support
_thd.FSMportMask = NULL;
if (fsmportspec->layout_mask != NULL) _thd.FSMportMask = &fsmportspec->layout_mask[_airport.layout_set]; // irregular airport support
int rad = _patches.modified_catchment ? fsmportspec->portFSM->catchment : 4;
if (_station_show_coverage) SetTileSelectBigSize(-rad, -rad, 2 * rad, 2 * rad);
int text_end = DrawStationCoverageAreaText(2, 206, SCT_ALL, rad) + 4;
if (text_end > w->widget[BAPW_BACKGROUND].bottom) {
SetWindowDirty(w);
ResizeWindowForWidget(w, BAPW_BACKGROUND, 0, text_end - w->widget[BAPW_BACKGROUND].bottom);
SetWindowDirty(w);
}
} else {
/* if nothing is selectable, draw the image of the first in the non-selectable list, but grey out the preview */
fsmportspec = GetCustomFSMportsSpec(_airport.fsmports_class, 0);
byte *layout_ptr = (byte*)alloca(fsmportspec->size_x[0] * fsmportspec->size_y[0] + 2);
memcpy(layout_ptr, fsmportspec->layouts[0], (fsmportspec->size_x[0] * fsmportspec->size_y[0]) + 2);
layout_ptr++;
preview_sprite = *layout_ptr;
DrawFSMportsTile(9, 106, preview_sprite, _airport.fsmports_class, 0);
GfxFillRect(8, 106, 105, 172, (1 << PALETTE_MODIFIER_GREYOUT));
_thd.FSMportLayout = NULL; // ensure irregular airport support disabled
_thd.FSMportMask = NULL;
SetTileSelectSize(1,1);
}
for (uint16 i = w->vscroll.pos, y = 35; i < _airport.station_count && i < (uint)(w->vscroll.pos + w->vscroll.cap); i++, y += 14) {
const FSMportsSpec *fsmportspec = GetCustomFSMportsSpec(_airport.fsmports_class, i);
if (fsmportspec != NULL && fsmportspec->name != 0) {
if (HasBit(fsmportspec->callbackmask, CBM_STATION_AVAIL) && GetFSMportsCallback(CBID_STATION_AVAILABILITY, 0, 0, fsmportspec, NULL, INVALID_TILE) == 0) {
GfxFillRect(8, y - 2, 127, y + 10, (1 << PALETTE_MODIFIER_GREYOUT));
}
DrawStringTruncated(9, y, fsmportspec->name, i == _airport.station_type ? 12 : 16, 118);
} else {
DrawStringTruncated(9, y, STR_STAT_CLASS_DFLT, i == _airport.station_type ? 12 : 16, 118);
}
}
break;
}
case WE_CLICK: {
switch (e->we.click.widget) {
case BAPW_HIGHLIGHT_OFF: case BAPW_HIGHLIGHT_ON:
_station_show_coverage = (e->we.click.widget != BAPW_HIGHLIGHT_OFF);
w->SetWidgetLoweredState(BAPW_HIGHLIGHT_OFF, !_station_show_coverage);
w->SetWidgetLoweredState(BAPW_HIGHLIGHT_ON, _station_show_coverage);
SndPlayFx(SND_15_BEEP);
SetWindowDirty(w);
break;
case BAPW_NEWAP_DROPDOWN:
ShowDropDownList(w, BuildFSMportsClassDropdown(), _airport.fsmports_class, BAPW_NEWAP_DROPDOWN);
break;
case BAPW_NEWAP_LIST: {
const FSMportsSpec *fsmportspec;
int y = (e->we.click.pt.y - 32) / 14;
if (y >= w->vscroll.cap) return;
y += w->vscroll.pos;
if (y >= _airport.station_count) return;
/* Check station availability callback */
fsmportspec = GetCustomFSMportsSpec(_airport.fsmports_class, y);
if (fsmportspec != NULL &&
HasBit(fsmportspec->callbackmask, CBM_STATION_AVAIL) &&
GetFSMportsCallback(CBID_STATION_AVAILABILITY, 0, 0, fsmportspec, NULL, INVALID_TILE) == 0) return;
_airport.station_type = y;
_airport.layout_set = 0;
_airport.platlength= fsmportspec->size_y[_airport.layout_set];
_airport.numtracks = fsmportspec->size_x[_airport.layout_set];
SndPlayFx(SND_15_BEEP);
SetWindowDirty(w);
break;
}
case BAPW_ORIENT_NE:
case BAPW_ORIENT_SE:
case BAPW_ORIENT_SW:
case BAPW_ORIENT_NW:
w->widget[BAPW_ORIENT_NE + DirToDiagDir(_airport.direction)].data = SPR_IMG_ARROW_NE_WHITE + DirToDiagDir(_airport.direction); //reset arrow to white
/* find the layout_set that corresponds to the selected orientation */
FSMportsSpec *fsmportspec = GetCustomFSMportsSpec(_airport.fsmports_class, _airport.station_type);
_airport.layout_set = 0;
_airport.direction = DiagDirToDir((DiagDirection)(e->we.click.widget - BAPW_ORIENT_NE));
for (byte j = 0; j < fsmportspec->numlayouts; j++) {
int x = fsmportspec->size_x[j];
int y = fsmportspec->size_y[j];
if (fsmportspec->layouts[j] == NULL) break;
/* enable the permitted orientations */
byte *layout_ptr = (byte*)alloca(x * y + 2);
memcpy(layout_ptr, fsmportspec->layouts[j], (x * y) + 2);
if (*layout_ptr == _airport.direction) {
_airport.layout_set = j;
break;
}
}
w->SetWidgetLoweredState( BAPW_ORIENT_NE, (_airport.direction == DIR_NE));
w->SetWidgetLoweredState( BAPW_ORIENT_SE, (_airport.direction == DIR_SE));
w->SetWidgetLoweredState( BAPW_ORIENT_SW, (_airport.direction == DIR_SW));
w->SetWidgetLoweredState( BAPW_ORIENT_NW, (_airport.direction == DIR_NW));
SndPlayFx(SND_15_BEEP);
SetWindowDirty(w);
break;
}
} break;
case WE_DROPDOWN_SELECT: {
if (_airport.fsmports_class != e->we.dropdown.index) {
_airport.fsmports_class = (FSMportsClassID)e->we.dropdown.index;
_airport.station_type = 0;
_airport.layout_set = 0;
_airport.direction = DIR_NE;
_airport.station_count = GetNumCustomFSMports(_airport.fsmports_class);
w->vscroll.count = _airport.station_count;
w->vscroll.pos = _airport.station_type;
}
SndPlayFx(SND_15_BEEP);
SetWindowDirty(w);
} break;
case WE_MOUSELOOP: {
if (WP(w, def_d).close) {
DeleteWindow(w);
return;
}
CheckRedrawStationCoverage(w);
} break;
case WE_DESTROY:
if (!WP(w, def_d).close) ResetObjectToPlace();
_thd.FSMportLayout = NULL; // ensure irregular airport support disabled
_thd.FSMportMask = NULL;
break;
}
}
static const Widget _build_airport_picker_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_3001_AIRPORT_SELECTION, STR_018C_WINDOW_TITLE_DRAG_THIS},
{ WWT_PANEL, RESIZE_NONE, 7, 0, 147, 14, 239, 0x0, STR_NULL},
{ WWT_DROPDOWNIN, RESIZE_NONE, 14, 7, 140, 17, 28, STR_02BD, STR_SELECT_STATION_CLASS_TIP}, // BAPW_NEWAP_DROPDOWN
{ WWT_MATRIX, RESIZE_NONE, 14, 7, 128, 32, 102, 0x501, STR_SELECT_STATION_TYPE_TIP},
{ WWT_SCROLLBAR, RESIZE_NONE, 14, 129, 140, 32, 102, 0x0, STR_0190_SCROLL_BAR_SCROLLS_LIST},
{ WWT_INSET, RESIZE_NONE, 7, 7, 107, 104, 173, 0x0, STR_NULL},
{ WWT_IMGBTN, RESIZE_NONE, 14, 109, 140, 104, 119, SPR_IMG_ARROW_NE_WHITE, STR_NULL},
{ WWT_IMGBTN, RESIZE_NONE, 14, 109, 140, 122, 137, SPR_IMG_ARROW_SE_WHITE, STR_NULL},
{ WWT_IMGBTN, RESIZE_NONE, 14, 109, 140, 140, 155, SPR_IMG_ARROW_SW_WHITE, STR_NULL},
{ WWT_IMGBTN, RESIZE_NONE, 14, 109, 140, 158, 173, SPR_IMG_ARROW_NW_WHITE, STR_NULL},
{ WWT_TEXTBTN, RESIZE_NONE, 14, 14, 73, 191, 202, STR_02DB_OFF, STR_3065_DON_T_HIGHLIGHT_COVERAGE},
{ WWT_TEXTBTN, RESIZE_NONE, 14, 74, 133, 191, 202, STR_02DA_ON, STR_3064_HIGHLIGHT_COVERAGE_AREA},
{ WWT_LABEL, RESIZE_NONE, 7, 0, 147, 178, 191, STR_3066_COVERAGE_AREA_HIGHLIGHT, STR_NULL},
{ WIDGETS_END},
};
static const WindowDesc _build_airport_desc = {
WDP_AUTO, WDP_AUTO, 148, 240, 148, 240,
WC_BUILD_STATION, WC_BUILD_TOOLBAR,
WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET,
_build_airport_picker_widgets,
BuildAirportPickerWndProc
};
static void ShowBuildAirportPicker()
{
Window *w = AllocateWindowDesc(&_build_airport_desc);
if (w == NULL) return;
_airport.station_type = 0;
_airport.layout_set = 0;
_airport.direction = DIR_NE;
_airport.station_count = GetNumCustomFSMports(_airport.fsmports_class);
//if (HasBit(fsmportspec->callbackmask, CBM_STATION_AVAIL) && GetFSMportsCallback(CBID_STATION_AVAILABILITY, 0, 0, fsmportspec, NULL, INVALID_TILE) == 0) {
// _airport.station_type = 0;
//}
w->vscroll.count = _airport.station_count;
w->vscroll.cap = 5;
w->vscroll.pos = Clamp(_airport.station_type - 2, 0, w->vscroll.count - w->vscroll.cap);
}
void InitializeAirportGui()
{
}