src/airport_gui.cpp
author richk
Mon, 10 Mar 2008 16:29:40 +0000
branchNewGRF_ports
changeset 6882 f508b3bab2c5
parent 6881 c3ade087d011
child 10184 fcf5fb2548eb
permissions -rw-r--r--
(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()
{
}