Files @ r9583:b6e25a00b908
Branch filter:

Location: cpp/openttd-patchpack/source/src/signs_gui.cpp - annotation

rubidium
(svn r13621) -Fix: building roadbits in the wrong direction on bridges or building roadbits from underneath the bridge to the bridgehead is impossible, so don't silently ignore that error when building over houses and industries is not ignored.
r5751:9b4f4afbf71b
r5751:9b4f4afbf71b
r9111:983de9c5a848
r6420:01087f989fd1
r5751:9b4f4afbf71b
r5751:9b4f4afbf71b
r5751:9b4f4afbf71b
r8107:82461791b7a2
r8107:82461791b7a2
r8254:b96be9ebfc6e
r9510:6d2f1c62ff65
r8790:550c9960067a
r8790:550c9960067a
r5751:9b4f4afbf71b
r5751:9b4f4afbf71b
r8116:df67d3c5e4fd
r8114:866ed489ed98
r8130:bece2e5c7460
r8131:7a50db7be0ff
r8139:4fc34c1bc2fb
r8224:194097dc7288
r8224:194097dc7288
r9179:660680ae613d
r5751:9b4f4afbf71b
r8264:d493cb51fe8a
r8264:d493cb51fe8a
r8264:d493cb51fe8a
r5751:9b4f4afbf71b
r5751:9b4f4afbf71b
r5751:9b4f4afbf71b
r5751:9b4f4afbf71b
r5751:9b4f4afbf71b
r5751:9b4f4afbf71b
r5751:9b4f4afbf71b
r5751:9b4f4afbf71b
r5751:9b4f4afbf71b
r5751:9b4f4afbf71b
r5751:9b4f4afbf71b
r5751:9b4f4afbf71b
r8258:08100da56269
r8258:08100da56269
r5751:9b4f4afbf71b
r5751:9b4f4afbf71b
r5751:9b4f4afbf71b
r8258:08100da56269
r8258:08100da56269
r5751:9b4f4afbf71b
r5751:9b4f4afbf71b
r5751:9b4f4afbf71b
r5751:9b4f4afbf71b
r5751:9b4f4afbf71b
r6247:96e840dbefcc
r5751:9b4f4afbf71b
r5751:9b4f4afbf71b
r5751:9b4f4afbf71b
r5751:9b4f4afbf71b
r5751:9b4f4afbf71b
r5751:9b4f4afbf71b
r5751:9b4f4afbf71b
r5751:9b4f4afbf71b
r5751:9b4f4afbf71b
r5751:9b4f4afbf71b
r5751:9b4f4afbf71b
r5751:9b4f4afbf71b
r5751:9b4f4afbf71b
r5751:9b4f4afbf71b
r5751:9b4f4afbf71b
r5751:9b4f4afbf71b
r5751:9b4f4afbf71b
r9316:61233b01525f
r9316:61233b01525f
r9316:61233b01525f
r9316:61233b01525f
r9316:61233b01525f
r9316:61233b01525f
r5751:9b4f4afbf71b
r9316:61233b01525f
r9316:61233b01525f
r5751:9b4f4afbf71b
r9316:61233b01525f
r9316:61233b01525f
r9316:61233b01525f
r9316:61233b01525f
r9316:61233b01525f
r5751:9b4f4afbf71b
r9316:61233b01525f
r9316:61233b01525f
r5751:9b4f4afbf71b
r9316:61233b01525f
r9316:61233b01525f
r9316:61233b01525f
r9316:61233b01525f
r9316:61233b01525f
r9316:61233b01525f
r5751:9b4f4afbf71b
r9316:61233b01525f
r9316:61233b01525f
r9316:61233b01525f
r9316:61233b01525f
r9316:61233b01525f
r5751:9b4f4afbf71b
r9316:61233b01525f
r9316:61233b01525f
r9316:61233b01525f
r9316:61233b01525f
r9316:61233b01525f
r5751:9b4f4afbf71b
r9316:61233b01525f
r9316:61233b01525f
r9316:61233b01525f
r9316:61233b01525f
r9316:61233b01525f
r9316:61233b01525f
r9316:61233b01525f
r9316:61233b01525f
r5751:9b4f4afbf71b
r9316:61233b01525f
r9316:61233b01525f
r9316:61233b01525f
r9316:61233b01525f
r5751:9b4f4afbf71b
r9316:61233b01525f
r9316:61233b01525f
r9316:61233b01525f
r5751:9b4f4afbf71b
r9316:61233b01525f
r5751:9b4f4afbf71b
r5751:9b4f4afbf71b
r5751:9b4f4afbf71b
r5751:9b4f4afbf71b
r5751:9b4f4afbf71b
r5751:9b4f4afbf71b
r5751:9b4f4afbf71b
r5751:9b4f4afbf71b
r5751:9b4f4afbf71b
r5751:9b4f4afbf71b
r5751:9b4f4afbf71b
r5751:9b4f4afbf71b
r7341:72820788b006
r5893:6c4fd9987e0f
r5751:9b4f4afbf71b
r5751:9b4f4afbf71b
r5751:9b4f4afbf71b
r5751:9b4f4afbf71b
r5751:9b4f4afbf71b
r6247:96e840dbefcc
r5751:9b4f4afbf71b
r9316:61233b01525f
r5751:9b4f4afbf71b
r7127:9394e882dc36
r9179:660680ae613d
r9179:660680ae613d
r9179:660680ae613d
r9179:660680ae613d
r9179:660680ae613d
r7127:9394e882dc36
r7127:9394e882dc36
r7127:9394e882dc36
r7127:9394e882dc36
r7127:9394e882dc36
r7127:9394e882dc36
r7127:9394e882dc36
r7127:9394e882dc36
r7127:9394e882dc36
r7127:9394e882dc36
r9179:660680ae613d
r9179:660680ae613d
r7127:9394e882dc36
r9179:660680ae613d
r9179:660680ae613d
r9179:660680ae613d
r9179:660680ae613d
r9179:660680ae613d
r9179:660680ae613d
r7127:9394e882dc36
r9179:660680ae613d
r9305:8a6ac0fa8c78
r9179:660680ae613d
r9179:660680ae613d
r9179:660680ae613d
r9179:660680ae613d
r9179:660680ae613d
r9179:660680ae613d
r7127:9394e882dc36
r9179:660680ae613d
r9179:660680ae613d
r9179:660680ae613d
r9179:660680ae613d
r9179:660680ae613d
r9179:660680ae613d
r9179:660680ae613d
r9179:660680ae613d
r9179:660680ae613d
r9179:660680ae613d
r7127:9394e882dc36
r9179:660680ae613d
r9179:660680ae613d
r9179:660680ae613d
r9179:660680ae613d
r9179:660680ae613d
r7127:9394e882dc36
r9179:660680ae613d
r9179:660680ae613d
r9179:660680ae613d
r9273:0df9c11598cc
r9179:660680ae613d
r9179:660680ae613d
r7127:9394e882dc36
r9179:660680ae613d
r9179:660680ae613d
r9179:660680ae613d
r9179:660680ae613d
r9179:660680ae613d
r9179:660680ae613d
r9179:660680ae613d
r9179:660680ae613d
r9179:660680ae613d
r9179:660680ae613d
r7127:9394e882dc36
r9179:660680ae613d
r9179:660680ae613d
r7127:9394e882dc36
r9179:660680ae613d
r9179:660680ae613d
r9179:660680ae613d
r9179:660680ae613d
r7127:9394e882dc36
r9179:660680ae613d
r9179:660680ae613d
r9179:660680ae613d
r9179:660680ae613d
r9179:660680ae613d
r9179:660680ae613d
r9179:660680ae613d
r7127:9394e882dc36
r9179:660680ae613d
r9179:660680ae613d
r7127:9394e882dc36
r9179:660680ae613d
r9179:660680ae613d
r9179:660680ae613d
r9179:660680ae613d
r7127:9394e882dc36
r9179:660680ae613d
r9179:660680ae613d
r9179:660680ae613d
r8737:36bd0e7321ea
r9179:660680ae613d
r9179:660680ae613d
r9179:660680ae613d
r9179:660680ae613d
r7127:9394e882dc36
r9179:660680ae613d
r9179:660680ae613d
r9179:660680ae613d
r7127:9394e882dc36
r9179:660680ae613d
r9179:660680ae613d
r9179:660680ae613d
r9179:660680ae613d
r9179:660680ae613d
r7127:9394e882dc36
r9285:acbf930223e4
r9179:660680ae613d
r9285:acbf930223e4
r9285:acbf930223e4
r9179:660680ae613d
r9179:660680ae613d
r9179:660680ae613d
r7127:9394e882dc36
r9179:660680ae613d
r9179:660680ae613d
r9179:660680ae613d
r9179:660680ae613d
r9285:acbf930223e4
r9179:660680ae613d
r7127:9394e882dc36
r9179:660680ae613d
r9179:660680ae613d
r9179:660680ae613d
r7127:9394e882dc36
r9179:660680ae613d
r7127:9394e882dc36
r7127:9394e882dc36
r8737:36bd0e7321ea
r8737:36bd0e7321ea
r8737:36bd0e7321ea
r8737:36bd0e7321ea
r8737:36bd0e7321ea
r8737:36bd0e7321ea
r8737:36bd0e7321ea
r8737:36bd0e7321ea
r8737:36bd0e7321ea
r8737:36bd0e7321ea
r7127:9394e882dc36
r7127:9394e882dc36
r7127:9394e882dc36
r7127:9394e882dc36
r7341:72820788b006
r7127:9394e882dc36
r8019:cc25a5b61a28
r7127:9394e882dc36
r7127:9394e882dc36
r7127:9394e882dc36
r9510:6d2f1c62ff65
r9510:6d2f1c62ff65
r9510:6d2f1c62ff65
r9510:6d2f1c62ff65
r9510:6d2f1c62ff65
r9510:6d2f1c62ff65
r9510:6d2f1c62ff65
r9510:6d2f1c62ff65
r9510:6d2f1c62ff65
r7127:9394e882dc36
r7127:9394e882dc36
r7127:9394e882dc36
r7127:9394e882dc36
r7127:9394e882dc36
r7127:9394e882dc36
r9179:660680ae613d
r7127:9394e882dc36
/* $Id$ */

/** @file signs_gui.cpp The GUI for signs. */

#include "stdafx.h"
#include "openttd.h"
#include "gui.h"
#include "textbuf_gui.h"
#include "window_gui.h"
#include "player_gui.h"
#include "player_func.h"
#include "signs_base.h"
#include "signs_func.h"
#include "debug.h"
#include "variables.h"
#include "command_func.h"
#include "strings_func.h"
#include "core/alloc_func.hpp"
#include "window_func.h"
#include "map_func.h"
#include "gfx_func.h"
#include "viewport_func.h"
#include "querystring_gui.h"

#include "table/strings.h"
#include "table/sprites.h"

static const Sign **_sign_sort;
static uint _num_sign_sort;

static char _bufcache[64];
static const Sign *_last_sign;

static int CDECL SignNameSorter(const void *a, const void *b)
{
	const Sign *sign0 = *(const Sign**)a;
	const Sign *sign1 = *(const Sign**)b;
	char buf1[64];

	SetDParam(0, sign0->index);
	GetString(buf1, STR_SIGN_NAME, lastof(buf1));

	if (sign1 != _last_sign) {
		_last_sign = sign1;
		SetDParam(0, sign1->index);
		GetString(_bufcache, STR_SIGN_NAME, lastof(_bufcache));
	}

	return strcmp(buf1, _bufcache); // sort by name
}

static void GlobalSortSignList()
{
	const Sign *si;
	uint n = 0;

	/* Create array for sorting */
	_sign_sort = ReallocT(_sign_sort, GetMaxSignIndex() + 1);

	FOR_ALL_SIGNS(si) _sign_sort[n++] = si;
	_num_sign_sort = n;

	qsort((void*)_sign_sort, n, sizeof(_sign_sort[0]), SignNameSorter);

	_sign_sort_dirty = false;

	DEBUG(misc, 3, "Resorting global signs list");
}

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

		this->FindWindowPlacementAndResize(desc);
	}

	virtual void OnPaint()
	{
		if (_sign_sort_dirty) GlobalSortSignList();

		SetVScrollCount(this, _num_sign_sort);

		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},
{    WWT_CAPTION,  RESIZE_RIGHT,    14,    11,   345,     0,    13, STR_SIGN_LIST_CAPTION, STR_018C_WINDOW_TITLE_DRAG_THIS},
{  WWT_STICKYBOX,     RESIZE_LR,    14,   346,   357,     0,    13, 0x0,                   STR_STICKY_BUTTON},
{      WWT_PANEL,     RESIZE_RB,    14,     0,   345,    14,   137, 0x0,                   STR_NULL},
{  WWT_SCROLLBAR,    RESIZE_LRB,    14,   346,   357,    14,   125, 0x0,                   STR_0190_SCROLL_BAR_SCROLLS_LIST},
{  WWT_RESIZEBOX,   RESIZE_LRTB,    14,   346,   357,   126,   137, 0x0,                   STR_RESIZE_BUTTON},
{   WIDGETS_END},
};

static const WindowDesc _sign_list_desc = {
	WDP_AUTO, WDP_AUTO, 358, 138, 358, 138,
	WC_SIGN_LIST, WC_NONE,
	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_STICKY_BUTTON | WDF_RESIZABLE,
	_sign_list_widget,
};


void ShowSignList()
{
	AllocateWindowDescFront<SignListWindow>(&_sign_list_desc, 0);
}

static void RenameSign(SignID index, const char *text)
{
	_cmd_text = text;
	DoCommandP(0, index, 0, NULL, CMD_RENAME_SIGN | CMD_MSG(STR_280C_CAN_T_CHANGE_SIGN_NAME));
}

enum QueryEditSignWidgets {
	QUERY_EDIT_SIGN_WIDGET_TEXT = 3,
	QUERY_EDIT_SIGN_WIDGET_OK,
	QUERY_EDIT_SIGN_WIDGET_CANCEL,
	QUERY_EDIT_SIGN_WIDGET_DELETE,
	QUERY_EDIT_SIGN_WIDGET_PREVIOUS = QUERY_EDIT_SIGN_WIDGET_DELETE + 2,
	QUERY_EDIT_SIGN_WIDGET_NEXT,
};

struct SignWindow : QueryStringBaseWindow {
	SignID cur_sign;

	SignWindow(const WindowDesc *desc, const Sign *si) : QueryStringBaseWindow(desc)
	{
		SetBit(_no_scroll, SCROLL_EDIT);
		this->caption = STR_280B_EDIT_SIGN_TEXT;
		this->afilter = CS_ALPHANUMERAL;
		this->LowerWidget(QUERY_EDIT_SIGN_WIDGET_TEXT);

		UpdateSignEditWindow(si);
		this->FindWindowPlacementAndResize(desc);
	}

	~SignWindow()
	{
		ClrBit(_no_scroll, SCROLL_EDIT);
	}

	void UpdateSignEditWindow(const Sign *si)
	{
		/* Display an empty string when the sign hasnt been edited yet */
		if (si->name != NULL) {
			SetDParam(0, si->index);
			GetString(this->edit_str_buf, STR_SIGN_NAME, lastof(this->edit_str_buf));
		} else {
			GetString(this->edit_str_buf, STR_EMPTY, lastof(this->edit_str_buf));
		}
		this->edit_str_buf[lengthof(this->edit_str_buf) - 1] = '\0';

		this->cur_sign = si->index;
		InitializeTextBuffer(&this->text, this->edit_str_buf, 31, 255); // Allow 31 characters (including \0)

		this->InvalidateWidget(QUERY_EDIT_SIGN_WIDGET_TEXT);
	}

	virtual void OnPaint()
	{
		SetDParam(0, this->caption);
		this->DrawWidgets();
		this->DrawEditBox(QUERY_EDIT_SIGN_WIDGET_TEXT);
	}

	virtual void OnClick(Point pt, int widget)
	{
		switch (widget) {
			case QUERY_EDIT_SIGN_WIDGET_PREVIOUS: {
				if (_sign_sort_dirty) GlobalSortSignList();
				SignID sign_index = _sign_sort[_num_sign_sort - 1]->index;
				for (uint i = 1; i < _num_sign_sort; i++) {
					if (this->cur_sign == _sign_sort[i]->index) {
						sign_index = _sign_sort[i - 1]->index;
						break;
					}
				}
				const Sign *si = GetSign(sign_index);

				/* Scroll to sign and reopen window */
				ScrollMainWindowToTile(TileVirtXY(si->x, si->y));
				UpdateSignEditWindow(si);
			} break;

			case QUERY_EDIT_SIGN_WIDGET_NEXT: {
				if (_sign_sort_dirty) GlobalSortSignList();
				SignID sign_index = _sign_sort[0]->index;
				for (uint i = 0; i < _num_sign_sort - 1; i++) {
					if (this->cur_sign == _sign_sort[i]->index) {
						sign_index = _sign_sort[i + 1]->index;
						break;
					}
				}
				const Sign *si = GetSign(sign_index);

				/* Scroll to sign and reopen window */
				ScrollMainWindowToTile(TileVirtXY(si->x, si->y));
				UpdateSignEditWindow(si);
			} break;

			case QUERY_EDIT_SIGN_WIDGET_TEXT:
				ShowOnScreenKeyboard(this, widget, QUERY_EDIT_SIGN_WIDGET_CANCEL, QUERY_EDIT_SIGN_WIDGET_OK);
				break;

			case QUERY_EDIT_SIGN_WIDGET_DELETE:
				/* Only need to set the buffer to null, the rest is handled as the OK button */
				DeleteTextBufferAll(&this->text);
				/* FALL THROUGH */

			case QUERY_EDIT_SIGN_WIDGET_OK:
				RenameSign(this->cur_sign, this->text.buf);
				/* FALL THROUGH */

			case QUERY_EDIT_SIGN_WIDGET_CANCEL:
				delete this;
				break;
		}
	}

	virtual EventState OnKeyPress(uint16 key, uint16 keycode)
	{
		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 */

			case 2: // ESC pressed, closes window, abandons changes
				delete this;
				break;
		}
		return state;
	}

	virtual void OnMouseLoop()
	{
		this->HandleEditBox(QUERY_EDIT_SIGN_WIDGET_TEXT);
	}
};

static const Widget _query_sign_edit_widgets[] = {
{ WWT_CLOSEBOX, RESIZE_NONE,  14,   0,  10,   0,  13, STR_00C5,          STR_018B_CLOSE_WINDOW},
{  WWT_CAPTION, RESIZE_NONE,  14,  11, 259,   0,  13, STR_012D,          STR_NULL },
{    WWT_PANEL, RESIZE_NONE,  14,   0, 259,  14,  29, STR_NULL,          STR_NULL },
{  WWT_EDITBOX, RESIZE_NONE,  14,   2, 257,  16,  27, STR_SIGN_OSKTITLE, STR_NULL },  // Text field
{  WWT_TEXTBTN, RESIZE_NONE,  14,   0,  60,  30,  41, STR_012F_OK,       STR_NULL },
{  WWT_TEXTBTN, RESIZE_NONE,  14,  61, 120,  30,  41, STR_012E_CANCEL,   STR_NULL },
{  WWT_TEXTBTN, RESIZE_NONE,  14, 121, 180,  30,  41, STR_0290_DELETE,   STR_NULL },
{    WWT_PANEL, RESIZE_NONE,  14, 181, 237,  30,  41, STR_NULL,          STR_NULL },
{  WWT_TEXTBTN, RESIZE_NONE,  14, 238, 248,  30,  41, STR_6819,          STR_PREVIOUS_SIGN_TOOLTIP },
{  WWT_TEXTBTN, RESIZE_NONE,  14, 249, 259,  30,  41, STR_681A,          STR_NEXT_SIGN_TOOLTIP },
{ WIDGETS_END },
};

static const WindowDesc _query_sign_edit_desc = {
	190, 170, 260, 42, 260, 42,
	WC_QUERY_STRING, WC_NONE,
	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET,
	_query_sign_edit_widgets,
};

void HandleClickOnSign(const Sign *si)
{
	if (_ctrl_pressed && si->owner == _local_player) {
		RenameSign(si->index, "");
		return;
	}
	ShowRenameSignWindow(si);
}

void ShowRenameSignWindow(const Sign *si)
{
	/* Delete all other edit windows and the save window */
	DeleteWindowById(WC_QUERY_STRING, 0);
	DeleteWindowById(WC_SAVELOAD, 0);

	new SignWindow(&_query_sign_edit_desc, si);
}