00001
00002
00005 #include "stdafx.h"
00006 #include "openttd.h"
00007 #include "heightmap.h"
00008 #include "debug.h"
00009 #include "landscape.h"
00010 #include "newgrf.h"
00011 #include "newgrf_text.h"
00012 #include "saveload.h"
00013 #include "tile_map.h"
00014 #include "gui.h"
00015 #include "window_gui.h"
00016 #include "station_gui.h"
00017 #include "textbuf_gui.h"
00018 #include "viewport_func.h"
00019 #include "gfx_func.h"
00020 #include "station_func.h"
00021 #include "command_func.h"
00022 #include "company_func.h"
00023 #include "company_base.h"
00024 #include "town.h"
00025 #include "network/network.h"
00026 #include "variables.h"
00027 #include "cheat_func.h"
00028 #include "train.h"
00029 #include "tgp.h"
00030 #include "cargotype.h"
00031 #include "company_manager_face.h"
00032 #include "strings_func.h"
00033 #include "fileio_func.h"
00034 #include "fios.h"
00035 #include "tile_cmd.h"
00036 #include "zoom_func.h"
00037 #include "functions.h"
00038 #include "window_func.h"
00039 #include "date_func.h"
00040 #include "sound_func.h"
00041 #include "string_func.h"
00042 #include "company_gui.h"
00043 #include "settings_type.h"
00044 #include "newgrf_cargo.h"
00045 #include "rail_gui.h"
00046 #include "tilehighlight_func.h"
00047 #include "querystring_gui.h"
00048 #include "company_base.h"
00049
00050 #include "table/sprites.h"
00051 #include "table/strings.h"
00052
00053
00054 SaveLoadDialogMode _saveload_mode;
00055
00056
00057 static bool _fios_path_changed;
00058 static bool _savegame_sort_dirty;
00059
00060 static const Widget _land_info_widgets[] = {
00061 { WWT_CLOSEBOX, RESIZE_NONE, COLOUR_GREY, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW},
00062 { WWT_CAPTION, RESIZE_NONE, COLOUR_GREY, 11, 299, 0, 13, STR_01A3_LAND_AREA_INFORMATION, STR_018C_WINDOW_TITLE_DRAG_THIS},
00063 { WWT_PANEL, RESIZE_BOTTOM, COLOUR_GREY, 0, 299, 14, 99, 0x0, STR_NULL},
00064 { WIDGETS_END},
00065 };
00066
00067 static const WindowDesc _land_info_desc = {
00068 WDP_AUTO, WDP_AUTO, 300, 100, 300, 100,
00069 WC_LAND_INFO, WC_NONE,
00070 WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET,
00071 _land_info_widgets,
00072 };
00073
00074 class LandInfoWindow : public Window {
00075 enum {
00076 LAND_INFO_CENTERED_LINES = 12,
00077 LAND_INFO_MULTICENTER_LINE = LAND_INFO_CENTERED_LINES,
00078 LAND_INFO_LINE_END,
00079
00080 LAND_INFO_LINE_BUFF_SIZE = 512,
00081 };
00082
00083 public:
00084 char landinfo_data[LAND_INFO_LINE_END][LAND_INFO_LINE_BUFF_SIZE];
00085
00086 virtual void OnPaint()
00087 {
00088 this->DrawWidgets();
00089
00090 uint y = 21;
00091 for (uint i = 0; i < LAND_INFO_CENTERED_LINES; i++) {
00092 if (StrEmpty(this->landinfo_data[i])) break;
00093
00094 DoDrawStringCentered(150, y, this->landinfo_data[i], i == 0 ? TC_LIGHT_BLUE : TC_FROMSTRING);
00095 y += i == 0 ? 16 : 12;
00096 }
00097
00098 y += 6;
00099
00100 if (!StrEmpty(this->landinfo_data[LAND_INFO_MULTICENTER_LINE])) {
00101 SetDParamStr(0, this->landinfo_data[LAND_INFO_MULTICENTER_LINE]);
00102 DrawStringMultiCenter(150, y, STR_JUST_RAW_STRING, this->width - 4);
00103 }
00104 }
00105
00106 LandInfoWindow(TileIndex tile) : Window(&_land_info_desc) {
00107 Company *c = GetCompany(IsValidCompanyID(_local_company) ? _local_company : COMPANY_FIRST);
00108 Town *t = ClosestTownFromTile(tile, _settings_game.economy.dist_local_authority);
00109
00110 Money old_money = c->money;
00111 c->money = INT64_MAX;
00112 CommandCost costclear = DoCommand(tile, 0, 0, 0, CMD_LANDSCAPE_CLEAR);
00113 c->money = old_money;
00114
00115
00116 TileDesc td;
00117 AcceptedCargo ac;
00118
00119 td.build_date = INVALID_DATE;
00120
00121
00122
00123
00124
00125 td.owner_type[0] = STR_01A7_OWNER;
00126 td.owner_type[1] = STR_NULL;
00127 td.owner_type[2] = STR_NULL;
00128 td.owner_type[3] = STR_NULL;
00129 td.owner[0] = OWNER_NONE;
00130 td.owner[1] = OWNER_NONE;
00131 td.owner[2] = OWNER_NONE;
00132 td.owner[3] = OWNER_NONE;
00133
00134 td.station_class = STR_NULL;
00135 td.station_name = STR_NULL;
00136
00137 td.grf = NULL;
00138
00139 GetAcceptedCargo(tile, ac);
00140 GetTileDesc(tile, &td);
00141
00142 uint line_nr = 0;
00143
00144
00145 SetDParam(0, td.dparam[0]);
00146 GetString(this->landinfo_data[line_nr], td.str, lastof(this->landinfo_data[line_nr]));
00147 line_nr++;
00148
00149
00150 for (uint i = 0; i < 4; i++) {
00151 if (td.owner_type[i] == STR_NULL) continue;
00152
00153 SetDParam(0, STR_01A6_N_A);
00154 if (td.owner[i] != OWNER_NONE && td.owner[i] != OWNER_WATER) GetNameOfOwner(td.owner[i], tile);
00155 GetString(this->landinfo_data[line_nr], td.owner_type[i], lastof(this->landinfo_data[line_nr]));
00156 line_nr++;
00157 }
00158
00159
00160 StringID str = STR_01A4_COST_TO_CLEAR_N_A;
00161 if (CmdSucceeded(costclear)) {
00162 SetDParam(0, costclear.GetCost());
00163 str = STR_01A5_COST_TO_CLEAR;
00164 }
00165 GetString(this->landinfo_data[line_nr], str, lastof(this->landinfo_data[line_nr]));
00166 line_nr++;
00167
00168
00169 char tmp[16];
00170 snprintf(tmp, lengthof(tmp), "0x%.4X", tile);
00171 SetDParam(0, TileX(tile));
00172 SetDParam(1, TileY(tile));
00173 SetDParam(2, TileHeight(tile));
00174 SetDParamStr(3, tmp);
00175 GetString(this->landinfo_data[line_nr], STR_LANDINFO_COORDS, lastof(this->landinfo_data[line_nr]));
00176 line_nr++;
00177
00178
00179 SetDParam(0, STR_01A9_NONE);
00180 if (t != NULL && t->IsValid()) {
00181 SetDParam(0, STR_TOWN);
00182 SetDParam(1, t->index);
00183 }
00184 GetString(this->landinfo_data[line_nr], STR_01A8_LOCAL_AUTHORITY, lastof(this->landinfo_data[line_nr]));
00185 line_nr++;
00186
00187
00188 if (td.build_date != INVALID_DATE) {
00189 SetDParam(0, td.build_date);
00190 GetString(this->landinfo_data[line_nr], STR_BUILD_DATE, lastof(this->landinfo_data[line_nr]));
00191 line_nr++;
00192 }
00193
00194
00195 if (td.station_class != STR_NULL) {
00196 SetDParam(0, td.station_class);
00197 GetString(this->landinfo_data[line_nr], STR_TILEDESC_STATION_CLASS, lastof(this->landinfo_data[line_nr]));
00198 line_nr++;
00199 }
00200
00201
00202 if (td.station_name != STR_NULL) {
00203 SetDParam(0, td.station_name);
00204 GetString(this->landinfo_data[line_nr], STR_TILEDESC_STATION_TYPE, lastof(this->landinfo_data[line_nr]));
00205 line_nr++;
00206 }
00207
00208
00209 if (td.grf != NULL) {
00210 SetDParamStr(0, td.grf);
00211 GetString(this->landinfo_data[line_nr], STR_TILEDESC_NEWGRF_NAME, lastof(this->landinfo_data[line_nr]));
00212 line_nr++;
00213 }
00214
00215 assert(line_nr < LAND_INFO_CENTERED_LINES);
00216
00217
00218 this->landinfo_data[line_nr][0] = '\0';
00219
00220
00221 char *strp = GetString(this->landinfo_data[LAND_INFO_MULTICENTER_LINE], STR_01CE_CARGO_ACCEPTED, lastof(this->landinfo_data[LAND_INFO_MULTICENTER_LINE]));
00222 bool found = false;
00223
00224 for (CargoID i = 0; i < NUM_CARGO; ++i) {
00225 if (ac[i] > 0) {
00226
00227 if (found) {
00228 *strp++ = ',';
00229 *strp++ = ' ';
00230 }
00231 found = true;
00232
00233
00234 if (ac[i] < 8) {
00235 SetDParam(0, ac[i]);
00236 SetDParam(1, GetCargo(i)->name);
00237 strp = GetString(strp, STR_01D1_8, lastof(this->landinfo_data[LAND_INFO_MULTICENTER_LINE]));
00238 } else {
00239 strp = GetString(strp, GetCargo(i)->name, lastof(this->landinfo_data[LAND_INFO_MULTICENTER_LINE]));
00240 }
00241 }
00242 }
00243 if (!found) this->landinfo_data[LAND_INFO_MULTICENTER_LINE][0] = '\0';
00244
00245 if (found) line_nr += 2;
00246
00247 if (line_nr > 6) ResizeWindow(this, 0, 12 * (line_nr - 6));
00248
00249 this->FindWindowPlacementAndResize(&_land_info_desc);
00250
00251 #if defined(_DEBUG)
00252 # define LANDINFOD_LEVEL 0
00253 #else
00254 # define LANDINFOD_LEVEL 1
00255 #endif
00256 DEBUG(misc, LANDINFOD_LEVEL, "TILE: %#x (%i,%i)", tile, TileX(tile), TileY(tile));
00257 DEBUG(misc, LANDINFOD_LEVEL, "type_height = %#x", _m[tile].type_height);
00258 DEBUG(misc, LANDINFOD_LEVEL, "m1 = %#x", _m[tile].m1);
00259 DEBUG(misc, LANDINFOD_LEVEL, "m2 = %#x", _m[tile].m2);
00260 DEBUG(misc, LANDINFOD_LEVEL, "m3 = %#x", _m[tile].m3);
00261 DEBUG(misc, LANDINFOD_LEVEL, "m4 = %#x", _m[tile].m4);
00262 DEBUG(misc, LANDINFOD_LEVEL, "m5 = %#x", _m[tile].m5);
00263 DEBUG(misc, LANDINFOD_LEVEL, "m6 = %#x", _m[tile].m6);
00264 DEBUG(misc, LANDINFOD_LEVEL, "m7 = %#x", _me[tile].m7);
00265 #undef LANDINFOD_LEVEL
00266 }
00267 };
00268
00269 static void Place_LandInfo(TileIndex tile)
00270 {
00271 DeleteWindowById(WC_LAND_INFO, 0);
00272 new LandInfoWindow(tile);
00273 }
00274
00275 void PlaceLandBlockInfo()
00276 {
00277 if (_cursor.sprite == SPR_CURSOR_QUERY) {
00278 ResetObjectToPlace();
00279 } else {
00280 _place_proc = Place_LandInfo;
00281 SetObjectToPlace(SPR_CURSOR_QUERY, PAL_NONE, VHM_RECT, WC_MAIN_TOOLBAR, 0);
00282 }
00283 }
00284
00285 static const Widget _about_widgets[] = {
00286 { WWT_CLOSEBOX, RESIZE_NONE, COLOUR_GREY, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW},
00287 { WWT_CAPTION, RESIZE_NONE, COLOUR_GREY, 11, 419, 0, 13, STR_015B_OPENTTD, STR_NULL},
00288 { WWT_PANEL, RESIZE_NONE, COLOUR_GREY, 0, 419, 14, 271, 0x0, STR_NULL},
00289 { WWT_FRAME, RESIZE_NONE, COLOUR_GREY, 5, 414, 40, 245, STR_NULL, STR_NULL},
00290 { WIDGETS_END},
00291 };
00292
00293 static const WindowDesc _about_desc = {
00294 WDP_CENTER, WDP_CENTER, 420, 272, 420, 272,
00295 WC_GAME_OPTIONS, WC_NONE,
00296 WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET,
00297 _about_widgets,
00298 };
00299
00300 struct AboutWindow : public Window {
00301 int scroll_height;
00302 uint16 counter;
00303
00304 AboutWindow() : Window(&_about_desc)
00305 {
00306 this->counter = 5;
00307 this->scroll_height = this->height - 40;
00308 this->FindWindowPlacementAndResize(&_about_desc);
00309 }
00310
00311 virtual void OnPaint()
00312 {
00313 static const char *credits[] = {
00314
00315
00316 "Original design by Chris Sawyer",
00317 "Original graphics by Simon Foster",
00318 "",
00319 "The OpenTTD team (in alphabetical order):",
00320 " Jean-Francois Claeys (Belugas) - GUI, newindustries and more",
00321 " Bjarni Corfitzen (Bjarni) - MacOSX port, coder and vehicles",
00322 " Matthijs Kooijman (blathijs) - Pathfinder-guru, pool rework",
00323 " Victor Fischer (Celestar) - Programming everywhere you need him to",
00324 " Christoph Elsenhans (frosch) - General coding",
00325 " Loïc Guilloux (glx) - General coding",
00326 " Jaroslav Mazanec (KUDr) - YAPG (Yet Another Pathfinder God) ;)",
00327 " Jonathan Coome (Maedhros) - High priest of the newGRF Temple",
00328 " Attila Bán (MiHaMiX) - WebTranslator, Nightlies, Wiki and bugtracker host",
00329 " Owen Rudge (orudge) - Forum host, OS/2 port",
00330 " Peter Nelson (peter1138) - Spiritual descendant from newGRF gods",
00331 " Remko Bijker (Rubidium) - Lead coder and way more",
00332 " Benedikt Brüggemeier (skidd13) - Bug fixer and code reworker",
00333 " Zdenek Sojka (SmatZ) - Bug finder and fixer",
00334 "",
00335 "Inactive Developers:",
00336 " Tamás Faragó (Darkvater) - Ex-Lead coder",
00337 " Christoph Mallon (Tron) - Programmer, code correctness police",
00338 "",
00339 "Retired Developers:",
00340 " Ludvig Strigeus (ludde) - OpenTTD author, main coder (0.1 - 0.3.3)",
00341 " Serge Paquet (vurlix) - Assistant project manager, coder (0.1 - 0.3.3)",
00342 " Dominik Scherer (dominik81) - Lead programmer, GUI expert (0.3.0 - 0.3.6)",
00343 " Patric Stout (TrueLight) - Programmer, webhoster (0.3 - pre0.6)",
00344 "",
00345 "Special thanks go out to:",
00346 " Josef Drexler - For his great work on TTDPatch",
00347 " Marcin Grzegorczyk - For his documentation of TTD internals",
00348 " Petr Baudis (pasky) - Many patches, newGRF support",
00349 " Stefan Meißner (sign_de) - For his work on the console",
00350 " Simon Sasburg (HackyKid) - Many bugfixes he has blessed us with",
00351 " Cian Duffy (MYOB) - BeOS port / manual writing",
00352 " Christian Rosentreter (tokai) - MorphOS / AmigaOS port",
00353 " Richard Kempton (richK) - additional airports, initial TGP implementation",
00354 "",
00355 " Michael Blunck - Pre-Signals and Semaphores © 2003",
00356 " George - Canal/Lock graphics © 2003-2004",
00357 " David Dallaston - Tram tracks",
00358 " Marcin Grzegorczyk - Foundations for Tracks on Slopes",
00359 " All Translators - Who made OpenTTD a truly international game",
00360 " Bug Reporters - Without whom OpenTTD would still be full of bugs!",
00361 "",
00362 "",
00363 "And last but not least:",
00364 " Chris Sawyer - For an amazing game!"
00365 };
00366
00367 this->DrawWidgets();
00368
00369
00370 DrawStringCentered(210, 17, STR_00B6_ORIGINAL_COPYRIGHT, TC_FROMSTRING);
00371 DrawStringCentered(210, 17 + 10, STR_00B7_VERSION, TC_FROMSTRING);
00372
00373 int y = this->scroll_height;
00374
00375
00376 for (uint i = 0; i < lengthof(credits); i++) {
00377 if (y >= 50 && y < (this->height - 40)) {
00378 DoDrawString(credits[i], 10, y, TC_BLACK);
00379 }
00380 y += 10;
00381 }
00382
00383
00384 if (y < 50) this->scroll_height = this->height - 40;
00385
00386 DoDrawStringCentered(210, this->height - 25, "Website: http://www.openttd.org", TC_BLACK);
00387 DrawStringCentered(210, this->height - 15, STR_00BA_COPYRIGHT_OPENTTD, TC_FROMSTRING);
00388 }
00389
00390 virtual void OnTick()
00391 {
00392 if (--this->counter == 0) {
00393 this->counter = 5;
00394 this->scroll_height--;
00395 this->SetDirty();
00396 }
00397 }
00398 };
00399
00400 void ShowAboutWindow()
00401 {
00402 DeleteWindowById(WC_GAME_OPTIONS, 0);
00403 new AboutWindow();
00404 }
00405
00406 static const Widget _errmsg_widgets[] = {
00407 { WWT_CLOSEBOX, RESIZE_NONE, COLOUR_RED, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW},
00408 { WWT_CAPTION, RESIZE_NONE, COLOUR_RED, 11, 239, 0, 13, STR_00B2_MESSAGE, STR_NULL},
00409 { WWT_PANEL, RESIZE_BOTTOM, COLOUR_RED, 0, 239, 14, 45, 0x0, STR_NULL},
00410 { WIDGETS_END},
00411 };
00412
00413 static const Widget _errmsg_face_widgets[] = {
00414 { WWT_CLOSEBOX, RESIZE_NONE, COLOUR_RED, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW},
00415 { WWT_CAPTION, RESIZE_NONE, COLOUR_RED, 11, 333, 0, 13, STR_00B3_MESSAGE_FROM, STR_NULL},
00416 { WWT_PANEL, RESIZE_BOTTOM, COLOUR_RED, 0, 333, 14, 136, 0x0, STR_NULL},
00417 { WIDGETS_END},
00418 };
00419
00420 struct ErrmsgWindow : public Window {
00421 private:
00422 uint duration;
00423 uint64 decode_params[20];
00424 StringID message_1;
00425 StringID message_2;
00426 bool show_company_manager_face;
00427
00428 int y[2];
00429
00430 public:
00431 ErrmsgWindow(Point pt, int width, int height, StringID msg1, StringID msg2, const Widget *widget, bool show_company_manager_face) :
00432 Window(pt.x, pt.y, width, height, WC_ERRMSG, widget),
00433 show_company_manager_face(show_company_manager_face)
00434 {
00435 this->duration = _settings_client.gui.errmsg_duration;
00436 CopyOutDParam(this->decode_params, 0, lengthof(this->decode_params));
00437 this->message_1 = msg1;
00438 this->message_2 = msg2;
00439 this->desc_flags = WDF_STD_BTN | WDF_DEF_WIDGET;
00440
00441 SwitchToErrorRefStack();
00442 RewindTextRefStack();
00443
00444 assert(msg2 != INVALID_STRING_ID);
00445
00446 int h2 = 3 + GetStringHeight(msg2, width - 2);
00447 int h1 = (msg1 == INVALID_STRING_ID) ? 0 : 3 + GetStringHeight(msg1, width - 2);
00448
00449 SwitchToNormalRefStack();
00450
00451 int h = 15 + h1 + h2;
00452 height = max<int>(height, h);
00453
00454 if (msg1 == INVALID_STRING_ID) {
00455
00456 y[1] = (height - 15) / 2 + 15 - 5;
00457 } else {
00458 int over = (height - h) / 4;
00459
00460 y[1] = 15 + h2 / 2 + 1 - 5 + over;
00461 y[0] = height - 3 - h1 / 2 - 5 - over;
00462 }
00463
00464 this->FindWindowPlacementAndResize(width, height);
00465 }
00466
00467 virtual void OnPaint()
00468 {
00469 CopyInDParam(0, this->decode_params, lengthof(this->decode_params));
00470 this->DrawWidgets();
00471 CopyInDParam(0, this->decode_params, lengthof(this->decode_params));
00472
00473
00474
00475
00476 SwitchToErrorRefStack();
00477 RewindTextRefStack();
00478
00479 if (this->show_company_manager_face) {
00480 const Company *c = GetCompany((CompanyID)GetDParamX(this->decode_params, 2));
00481 DrawCompanyManagerFace(c->face, c->colour, 2, 16);
00482 }
00483
00484 DrawStringMultiCenter(this->width - 120, y[1], this->message_2, this->width - 2);
00485 if (this->message_1 != INVALID_STRING_ID) DrawStringMultiCenter(this->width - 120, y[0], this->message_1, this->width - 2);
00486
00487
00488 SwitchToNormalRefStack();
00489 }
00490
00491 virtual void OnMouseLoop()
00492 {
00493 if (_right_button_down) delete this;
00494 }
00495
00496 virtual void OnHundredthTick()
00497 {
00498 if (--this->duration == 0) delete this;
00499 }
00500
00501 ~ErrmsgWindow()
00502 {
00503 SetRedErrorSquare(0);
00504 extern StringID _switch_mode_errorstr;
00505 _switch_mode_errorstr = INVALID_STRING_ID;
00506 }
00507
00508 virtual EventState OnKeyPress(uint16 key, uint16 keycode)
00509 {
00510 if (keycode != WKC_SPACE) return ES_NOT_HANDLED;
00511 delete this;
00512 return ES_HANDLED;
00513 }
00514 };
00515
00516 void ShowErrorMessage(StringID msg_1, StringID msg_2, int x, int y)
00517 {
00518 DeleteWindowById(WC_ERRMSG, 0);
00519
00520 if (!_settings_client.gui.errmsg_duration) return;
00521
00522 if (msg_2 == STR_NULL) msg_2 = STR_EMPTY;
00523
00524 Point pt;
00525 const ViewPort *vp;
00526
00527 if (msg_1 != STR_013B_OWNED_BY || GetDParam(2) >= 8) {
00528 if ((x | y) != 0) {
00529 pt = RemapCoords2(x, y);
00530 vp = FindWindowById(WC_MAIN_WINDOW, 0)->viewport;
00531
00532
00533 pt.x = UnScaleByZoom(pt.x - vp->virtual_left, vp->zoom) + vp->left;
00534 pt.x = (pt.x < (_screen.width >> 1)) ? _screen.width - 260 : 20;
00535
00536
00537 pt.y = UnScaleByZoom(pt.y - vp->virtual_top, vp->zoom) + vp->top;
00538 pt.y = (pt.y < (_screen.height >> 1)) ? _screen.height - 80 : 100;
00539
00540 } else {
00541 pt.x = (_screen.width - 240) >> 1;
00542 pt.y = (_screen.height - 46) >> 1;
00543 }
00544 new ErrmsgWindow(pt, 240, 46, msg_1, msg_2, _errmsg_widgets, false);
00545 } else {
00546 if ((x | y) != 0) {
00547 pt = RemapCoords2(x, y);
00548 vp = FindWindowById(WC_MAIN_WINDOW, 0)->viewport;
00549 pt.x = Clamp(UnScaleByZoom(pt.x - vp->virtual_left, vp->zoom) + vp->left - (334 / 2), 0, _screen.width - 334);
00550 pt.y = Clamp(UnScaleByZoom(pt.y - vp->virtual_top, vp->zoom) + vp->top - (137 / 2), 22, _screen.height - 137);
00551 } else {
00552 pt.x = (_screen.width - 334) >> 1;
00553 pt.y = (_screen.height - 137) >> 1;
00554 }
00555 new ErrmsgWindow(pt, 334, 137, msg_1, msg_2, _errmsg_face_widgets, true);
00556 }
00557 }
00558
00559 void ShowEstimatedCostOrIncome(Money cost, int x, int y)
00560 {
00561 StringID msg = STR_0805_ESTIMATED_COST;
00562
00563 if (cost < 0) {
00564 cost = -cost;
00565 msg = STR_0807_ESTIMATED_INCOME;
00566 }
00567 SetDParam(0, cost);
00568 ShowErrorMessage(INVALID_STRING_ID, msg, x, y);
00569 }
00570
00571 void ShowCostOrIncomeAnimation(int x, int y, int z, Money cost)
00572 {
00573 Point pt = RemapCoords(x,y,z);
00574 StringID msg = STR_0801_COST;
00575
00576 if (cost < 0) {
00577 cost = -cost;
00578 msg = STR_0803_INCOME;
00579 }
00580 SetDParam(0, cost);
00581 AddTextEffect(msg, pt.x, pt.y, 0x250, TE_RISING);
00582 }
00583
00584 void ShowFeederIncomeAnimation(int x, int y, int z, Money cost)
00585 {
00586 Point pt = RemapCoords(x,y,z);
00587
00588 SetDParam(0, cost);
00589 AddTextEffect(STR_FEEDER, pt.x, pt.y, 0x250, TE_RISING);
00590 }
00591
00592 TextEffectID ShowFillingPercent(int x, int y, int z, uint8 percent, StringID string)
00593 {
00594 Point pt = RemapCoords(x, y, z);
00595
00596 assert(string != STR_NULL);
00597
00598 SetDParam(0, percent);
00599 return AddTextEffect(string, pt.x, pt.y, 0xFFFF, TE_STATIC);
00600 }
00601
00602 void UpdateFillingPercent(TextEffectID te_id, uint8 percent, StringID string)
00603 {
00604 assert(string != STR_NULL);
00605
00606 SetDParam(0, percent);
00607 UpdateTextEffect(te_id, string);
00608 }
00609
00610 void HideFillingPercent(TextEffectID *te_id)
00611 {
00612 if (*te_id == INVALID_TE_ID) return;
00613
00614 RemoveTextEffect(*te_id);
00615 *te_id = INVALID_TE_ID;
00616 }
00617
00618 static const Widget _tooltips_widgets[] = {
00619 { WWT_PANEL, RESIZE_NONE, COLOUR_GREY, 0, 199, 0, 31, 0x0, STR_NULL},
00620 { WIDGETS_END},
00621 };
00622
00623 struct TooltipsWindow : public Window
00624 {
00625 StringID string_id;
00626 byte paramcount;
00627 uint64 params[5];
00628 bool use_left_mouse_button;
00629
00630 TooltipsWindow(int x, int y, int width, int height, const Widget *widget,
00631 StringID str, uint paramcount, const uint64 params[], bool use_left_mouse_button) :
00632 Window(x, y, width, height, WC_TOOLTIPS, widget)
00633 {
00634 this->string_id = str;
00635 assert(sizeof(this->params[0]) == sizeof(params[0]));
00636 assert(paramcount <= lengthof(this->params));
00637 memcpy(this->params, params, sizeof(this->params[0]) * paramcount);
00638 this->paramcount = paramcount;
00639 this->use_left_mouse_button = use_left_mouse_button;
00640
00641 this->flags4 &= ~WF_WHITE_BORDER_MASK;
00642 this->widget[0].right = width;
00643 this->widget[0].bottom = height;
00644
00645 FindWindowPlacementAndResize(width, height);
00646 }
00647
00648 virtual void OnPaint()
00649 {
00650 GfxFillRect(0, 0, this->width - 1, this->height - 1, 0);
00651 GfxFillRect(1, 1, this->width - 2, this->height - 2, 0x44);
00652
00653 for (uint arg = 0; arg < this->paramcount; arg++) {
00654 SetDParam(arg, this->params[arg]);
00655 }
00656 DrawStringMultiCenter((this->width >> 1), (this->height >> 1) - 5, this->string_id, this->width - 2);
00657 }
00658
00659 virtual void OnMouseLoop()
00660 {
00661
00662
00663 if (this->use_left_mouse_button ? !_left_button_down : !_right_button_down) delete this;
00664 }
00665 };
00666
00673 void GuiShowTooltips(StringID str, uint paramcount, const uint64 params[], bool use_left_mouse_button)
00674 {
00675 DeleteWindowById(WC_TOOLTIPS, 0);
00676
00677 if (str == STR_NULL) return;
00678
00679 for (uint i = 0; i != paramcount; i++) SetDParam(i, params[i]);
00680 char buffer[512];
00681 GetString(buffer, str, lastof(buffer));
00682
00683 Dimension br = GetStringBoundingBox(buffer);
00684 br.width += 6; br.height += 4;
00685
00686
00687 if (br.width > 200) {
00688 br.height += ((br.width - 4) / 176) * 10;
00689 br.width = 200;
00690 }
00691
00692
00693
00694
00695 int y = Clamp(_cursor.pos.y + _cursor.size.y + _cursor.offs.y + 5, 22, _screen.height - 12);
00696 if (y + br.height > _screen.height - 12) y = _cursor.pos.y + _cursor.offs.y - br.height - 5;
00697 int x = Clamp(_cursor.pos.x - (br.width >> 1), 0, _screen.width - br.width);
00698
00699 new TooltipsWindow(x, y, br.width, br.height, _tooltips_widgets, str, paramcount, params, use_left_mouse_button);
00700 }
00701
00702
00703 static int DrawStationCoverageText(const AcceptedCargo cargo,
00704 int str_x, int str_y, StationCoverageType sct, bool supplies)
00705 {
00706 bool first = true;
00707
00708 char string[512];
00709 char *b = InlineString(string, supplies ? STR_SUPPLIES : STR_000D_ACCEPTS);
00710
00711 for (CargoID i = 0; i < NUM_CARGO; i++) {
00712 if (b >= lastof(string) - (1 + 2 * 4)) break;
00713 switch (sct) {
00714 case SCT_PASSENGERS_ONLY: if (!IsCargoInClass(i, CC_PASSENGERS)) continue; break;
00715 case SCT_NON_PASSENGERS_ONLY: if (IsCargoInClass(i, CC_PASSENGERS)) continue; break;
00716 case SCT_ALL: break;
00717 default: NOT_REACHED();
00718 }
00719 if (cargo[i] >= (supplies ? 1U : 8U)) {
00720 if (first) {
00721 first = false;
00722 } else {
00723
00724 *b++ = ',';
00725 *b++ = ' ';
00726 }
00727 b = InlineString(b, GetCargo(i)->name);
00728 }
00729 }
00730
00731
00732 if (first) b = InlineString(b, STR_00D0_NOTHING);
00733
00734 *b = '\0';
00735
00736
00737 assert(b < endof(string));
00738
00739 SetDParamStr(0, string);
00740 return DrawStringMultiLine(str_x, str_y, STR_JUST_RAW_STRING, 144);
00741 }
00742
00752 int DrawStationCoverageAreaText(int sx, int sy, StationCoverageType sct, int rad, bool supplies)
00753 {
00754 TileIndex tile = TileVirtXY(_thd.pos.x, _thd.pos.y);
00755 AcceptedCargo cargo;
00756 if (tile < MapSize()) {
00757 if (supplies) {
00758 GetProductionAroundTiles(cargo, tile, _thd.size.x / TILE_SIZE, _thd.size.y / TILE_SIZE , rad);
00759 } else {
00760 GetAcceptanceAroundTiles(cargo, tile, _thd.size.x / TILE_SIZE, _thd.size.y / TILE_SIZE , rad);
00761 }
00762 return sy + DrawStationCoverageText(cargo, sx, sy, sct, supplies);
00763 }
00764
00765 return sy;
00766 }
00767
00768 void CheckRedrawStationCoverage(const Window *w)
00769 {
00770 if (_thd.dirty & 1) {
00771 _thd.dirty &= ~1;
00772 SetWindowDirty(w);
00773 }
00774 }
00775
00776
00777
00778
00779 static void DelChar(Textbuf *tb, bool backspace)
00780 {
00781 WChar c;
00782 char *s = tb->buf + tb->caretpos;
00783
00784 if (backspace) s = Utf8PrevChar(s);
00785
00786 uint16 len = (uint16)Utf8Decode(&c, s);
00787 uint width = GetCharacterWidth(FS_NORMAL, c);
00788
00789 tb->width -= width;
00790 if (backspace) {
00791 tb->caretpos -= len;
00792 tb->caretxoffs -= width;
00793 }
00794
00795
00796 memmove(s, s + len, tb->size - (s - tb->buf) - len);
00797 tb->size -= len;
00798 }
00799
00807 bool DeleteTextBufferChar(Textbuf *tb, int delmode)
00808 {
00809 if (delmode == WKC_BACKSPACE && tb->caretpos != 0) {
00810 DelChar(tb, true);
00811 return true;
00812 } else if (delmode == WKC_DELETE && tb->caretpos < tb->size - 1) {
00813 DelChar(tb, false);
00814 return true;
00815 }
00816
00817 return false;
00818 }
00819
00824 void DeleteTextBufferAll(Textbuf *tb)
00825 {
00826 memset(tb->buf, 0, tb->maxsize);
00827 tb->size = 1;
00828 tb->width = tb->caretpos = tb->caretxoffs = 0;
00829 }
00830
00839 bool InsertTextBufferChar(Textbuf *tb, WChar key)
00840 {
00841 const byte charwidth = GetCharacterWidth(FS_NORMAL, key);
00842 uint16 len = (uint16)Utf8CharLen(key);
00843 if (tb->size + len <= tb->maxsize && (tb->maxwidth == 0 || tb->width + charwidth <= tb->maxwidth)) {
00844 memmove(tb->buf + tb->caretpos + len, tb->buf + tb->caretpos, tb->size - tb->caretpos);
00845 Utf8Encode(tb->buf + tb->caretpos, key);
00846 tb->size += len;
00847 tb->width += charwidth;
00848
00849 tb->caretpos += len;
00850 tb->caretxoffs += charwidth;
00851 return true;
00852 }
00853 return false;
00854 }
00855
00863 bool MoveTextBufferPos(Textbuf *tb, int navmode)
00864 {
00865 switch (navmode) {
00866 case WKC_LEFT:
00867 if (tb->caretpos != 0) {
00868 WChar c;
00869 const char *s = Utf8PrevChar(tb->buf + tb->caretpos);
00870 Utf8Decode(&c, s);
00871 tb->caretpos = s - tb->buf;
00872 tb->caretxoffs -= GetCharacterWidth(FS_NORMAL, c);
00873
00874 return true;
00875 }
00876 break;
00877
00878 case WKC_RIGHT:
00879 if (tb->caretpos < tb->size - 1) {
00880 WChar c;
00881
00882 tb->caretpos += (uint16)Utf8Decode(&c, tb->buf + tb->caretpos);
00883 tb->caretxoffs += GetCharacterWidth(FS_NORMAL, c);
00884
00885 return true;
00886 }
00887 break;
00888
00889 case WKC_HOME:
00890 tb->caretpos = 0;
00891 tb->caretxoffs = 0;
00892 return true;
00893
00894 case WKC_END:
00895 tb->caretpos = tb->size - 1;
00896 tb->caretxoffs = tb->width;
00897 return true;
00898
00899 default:
00900 break;
00901 }
00902
00903 return false;
00904 }
00905
00915 void InitializeTextBuffer(Textbuf *tb, char *buf, uint16 maxsize, uint16 maxwidth)
00916 {
00917 assert(maxsize != 0);
00918
00919 tb->buf = buf;
00920 tb->maxsize = maxsize;
00921 tb->maxwidth = maxwidth;
00922 tb->caret = true;
00923 UpdateTextBufferSize(tb);
00924 }
00925
00932 void UpdateTextBufferSize(Textbuf *tb)
00933 {
00934 const char *buf = tb->buf;
00935
00936 tb->width = 0;
00937 tb->size = 1;
00938
00939 WChar c;
00940 while ((c = Utf8Consume(&buf)) != '\0') {
00941 tb->width += GetCharacterWidth(FS_NORMAL, c);
00942 tb->size += Utf8CharLen(c);
00943 }
00944
00945 assert(tb->size <= tb->maxsize);
00946
00947 tb->caretpos = tb->size - 1;
00948 tb->caretxoffs = tb->width;
00949 }
00950
00951 bool HandleCaret(Textbuf *tb)
00952 {
00953
00954 bool b = !!(_caret_timer & 0x20);
00955
00956 if (b != tb->caret) {
00957 tb->caret = b;
00958 return true;
00959 }
00960 return false;
00961 }
00962
00963 HandleEditBoxResult QueryString::HandleEditBoxKey(Window *w, int wid, uint16 key, uint16 keycode, Window::EventState &state)
00964 {
00965 state = Window::ES_HANDLED;
00966
00967 switch (keycode) {
00968 case WKC_ESC: return HEBR_CANCEL;
00969
00970 case WKC_RETURN: case WKC_NUM_ENTER: return HEBR_CONFIRM;
00971
00972 case (WKC_CTRL | 'V'):
00973 if (InsertTextBufferClipboard(&this->text)) w->InvalidateWidget(wid);
00974 break;
00975
00976 case (WKC_CTRL | 'U'):
00977 DeleteTextBufferAll(&this->text);
00978 w->InvalidateWidget(wid);
00979 break;
00980
00981 case WKC_BACKSPACE: case WKC_DELETE:
00982 if (DeleteTextBufferChar(&this->text, keycode)) w->InvalidateWidget(wid);
00983 break;
00984
00985 case WKC_LEFT: case WKC_RIGHT: case WKC_END: case WKC_HOME:
00986 if (MoveTextBufferPos(&this->text, keycode)) w->InvalidateWidget(wid);
00987 break;
00988
00989 default:
00990 if (IsValidChar(key, this->afilter)) {
00991 if (InsertTextBufferChar(&this->text, key)) w->InvalidateWidget(wid);
00992 } else {
00993 state = (this->afilter == CS_ALPHANUMERAL) ? Window::ES_HANDLED : Window::ES_NOT_HANDLED;
00994 }
00995 }
00996
00997 return HEBR_EDITING;
00998 }
00999
01000 void QueryString::HandleEditBox(Window *w, int wid)
01001 {
01002 if (HandleCaret(&this->text)) w->InvalidateWidget(wid);
01003 }
01004
01005 void QueryString::DrawEditBox(Window *w, int wid)
01006 {
01007 const Widget *wi = &w->widget[wid];
01008
01009 assert((wi->type & WWT_MASK) == WWT_EDITBOX);
01010
01011 GfxFillRect(wi->left + 1, wi->top + 1, wi->right - 1, wi->bottom - 1, 215);
01012
01013 DrawPixelInfo dpi;
01014 int delta;
01015
01016
01017 if (!FillDrawPixelInfo(&dpi,
01018 wi->left + 4,
01019 wi->top + 1,
01020 wi->right - wi->left - 4,
01021 wi->bottom - wi->top - 1)) {
01022 return;
01023 }
01024
01025 DrawPixelInfo *old_dpi = _cur_dpi;
01026 _cur_dpi = &dpi;
01027
01028
01029
01030 const Textbuf *tb = &this->text;
01031
01032 delta = (wi->right - wi->left) - tb->width - 10;
01033 if (delta > 0) delta = 0;
01034
01035 if (tb->caretxoffs + delta < 0) delta = -tb->caretxoffs;
01036
01037 DoDrawString(tb->buf, delta, 0, TC_YELLOW);
01038 if (tb->caret) DoDrawString("_", tb->caretxoffs + delta, 0, TC_WHITE);
01039
01040 _cur_dpi = old_dpi;
01041 }
01042
01043 int QueryStringBaseWindow::HandleEditBoxKey(int wid, uint16 key, uint16 keycode, EventState &state)
01044 {
01045 return this->QueryString::HandleEditBoxKey(this, wid, key, keycode, state);
01046 }
01047
01048 void QueryStringBaseWindow::HandleEditBox(int wid)
01049 {
01050 this->QueryString::HandleEditBox(this, wid);
01051 }
01052
01053 <