00001
00002
00003
00004
00005
00006
00007
00008
00009
00012 #include "stdafx.h"
00013 #include "openttd.h"
00014 #include "gui.h"
00015 #include "window_gui.h"
00016 #include "viewport_func.h"
00017 #include "news_type.h"
00018 #include "gfx_func.h"
00019 #include "strings_func.h"
00020 #include "window_func.h"
00021 #include "date_func.h"
00022 #include "vehicle_base.h"
00023 #include "vehicle_func.h"
00024 #include "station_base.h"
00025 #include "industry.h"
00026 #include "town.h"
00027 #include "sound_func.h"
00028 #include "string_func.h"
00029 #include "widgets/dropdown_func.h"
00030 #include "statusbar_gui.h"
00031 #include "company_manager_face.h"
00032 #include "company_func.h"
00033 #include "engine_gui.h"
00034
00035 #include "table/strings.h"
00036
00037 const NewsItem *_statusbar_news_item = NULL;
00038 bool _news_ticker_sound;
00039
00040 static uint MIN_NEWS_AMOUNT = 30;
00041 static uint _total_news = 0;
00042 static NewsItem *_oldest_news = NULL;
00043 static NewsItem *_latest_news = NULL;
00044
00049 static const NewsItem *_forced_news = NULL;
00050
00052 static const NewsItem *_current_news = NULL;
00053
00054
00061 static TileIndex GetReferenceTile(NewsReferenceType reftype, uint32 ref)
00062 {
00063 switch (reftype) {
00064 case NR_TILE: return (TileIndex)ref;
00065 case NR_STATION: return Station::Get((StationID)ref)->xy;
00066 case NR_INDUSTRY: return Industry::Get((IndustryID)ref)->location.tile + TileDiffXY(1, 1);
00067 case NR_TOWN: return Town::Get((TownID)ref)->xy;
00068 default: return INVALID_TILE;
00069 }
00070 }
00071
00073 enum NewsTypeWidgets {
00074 NTW_PANEL,
00075 NTW_TITLE,
00076 NTW_HEADLINE,
00077 NTW_CLOSEBOX,
00078 NTW_DATE,
00079 NTW_CAPTION,
00080 NTW_INSET,
00081 NTW_VIEWPORT,
00082 NTW_COMPANY_MSG,
00083 NTW_MESSAGE,
00084 NTW_MGR_FACE,
00085 NTW_MGR_NAME,
00086 NTW_VEH_TITLE,
00087 NTW_VEH_BKGND,
00088 NTW_VEH_NAME,
00089 NTW_VEH_SPR,
00090 NTW_VEH_INFO,
00091 };
00092
00093
00094 static const NWidgetPart _nested_normal_news_widgets[] = {
00095 NWidget(WWT_PANEL, COLOUR_WHITE, NTW_PANEL),
00096 NWidget(NWID_HORIZONTAL), SetPadding(1, 1, 0, 1),
00097 NWidget(WWT_TEXT, COLOUR_WHITE, NTW_CLOSEBOX), SetDataTip(STR_SILVER_CROSS, STR_NULL), SetPadding(0, 0, 0, 1),
00098 NWidget(NWID_SPACER), SetFill(1, 0),
00099 NWidget(NWID_VERTICAL),
00100 NWidget(WWT_LABEL, COLOUR_WHITE, NTW_DATE), SetDataTip(STR_DATE_LONG_SMALL, STR_NULL),
00101 NWidget(NWID_SPACER), SetFill(0, 1),
00102 EndContainer(),
00103 EndContainer(),
00104 NWidget(WWT_EMPTY, COLOUR_WHITE, NTW_MESSAGE), SetMinimalSize(428, 154), SetPadding(0, 1, 1, 1),
00105 EndContainer(),
00106 };
00107
00108 static const WindowDesc _normal_news_desc(
00109 WDP_MANUAL, 0, 0,
00110 WC_NEWS_WINDOW, WC_NONE,
00111 0,
00112 _nested_normal_news_widgets, lengthof(_nested_normal_news_widgets)
00113 );
00114
00115
00116 static const NWidgetPart _nested_vehicle_news_widgets[] = {
00117 NWidget(WWT_PANEL, COLOUR_WHITE, NTW_PANEL),
00118 NWidget(NWID_HORIZONTAL), SetPadding(1, 1, 0, 1),
00119 NWidget(NWID_VERTICAL),
00120 NWidget(WWT_TEXT, COLOUR_WHITE, NTW_CLOSEBOX), SetDataTip(STR_SILVER_CROSS, STR_NULL), SetPadding(0, 0, 0, 1),
00121 NWidget(NWID_SPACER), SetFill(0, 1),
00122 EndContainer(),
00123 NWidget(WWT_LABEL, COLOUR_WHITE, NTW_VEH_TITLE), SetFill(1, 1), SetMinimalSize(419, 55), SetDataTip(STR_EMPTY, STR_NULL),
00124 EndContainer(),
00125 NWidget(WWT_PANEL, COLOUR_WHITE, NTW_VEH_BKGND), SetPadding(0, 25, 1, 25),
00126 NWidget(NWID_VERTICAL),
00127 NWidget(WWT_EMPTY, INVALID_COLOUR, NTW_VEH_NAME), SetMinimalSize(369, 33), SetFill(1, 0),
00128 NWidget(WWT_EMPTY, INVALID_COLOUR, NTW_VEH_SPR), SetMinimalSize(369, 32), SetFill(1, 0),
00129 NWidget(WWT_EMPTY, INVALID_COLOUR, NTW_VEH_INFO), SetMinimalSize(369, 46), SetFill(1, 0),
00130 EndContainer(),
00131 EndContainer(),
00132 EndContainer(),
00133 };
00134
00135 static const WindowDesc _vehicle_news_desc(
00136 WDP_MANUAL, 0, 0,
00137 WC_NEWS_WINDOW, WC_NONE,
00138 0,
00139 _nested_vehicle_news_widgets, lengthof(_nested_vehicle_news_widgets)
00140 );
00141
00142
00143 static const NWidgetPart _nested_company_news_widgets[] = {
00144 NWidget(WWT_PANEL, COLOUR_WHITE, NTW_PANEL),
00145 NWidget(NWID_HORIZONTAL), SetPadding(1, 1, 0, 1),
00146 NWidget(NWID_VERTICAL),
00147 NWidget(WWT_TEXT, COLOUR_WHITE, NTW_CLOSEBOX), SetDataTip(STR_SILVER_CROSS, STR_NULL), SetPadding(0, 0, 0, 1),
00148 NWidget(NWID_SPACER), SetFill(0, 1),
00149 EndContainer(),
00150 NWidget(WWT_LABEL, COLOUR_WHITE, NTW_TITLE), SetFill(1, 1), SetMinimalSize(410, 20), SetDataTip(STR_EMPTY, STR_NULL),
00151 EndContainer(),
00152 NWidget(NWID_HORIZONTAL), SetPadding(0, 1, 1, 1),
00153 NWidget(NWID_VERTICAL),
00154 NWidget(WWT_EMPTY, COLOUR_WHITE, NTW_MGR_FACE), SetMinimalSize(93, 119), SetPadding(2, 6, 2, 1),
00155 NWidget(NWID_HORIZONTAL),
00156 NWidget(WWT_EMPTY, COLOUR_WHITE, NTW_MGR_NAME), SetMinimalSize(93, 24), SetPadding(0, 0, 0, 1),
00157 NWidget(NWID_SPACER), SetFill(1, 0),
00158 EndContainer(),
00159 NWidget(NWID_SPACER), SetFill(0, 1),
00160 EndContainer(),
00161 NWidget(WWT_EMPTY, COLOUR_WHITE, NTW_COMPANY_MSG), SetFill(1, 1), SetMinimalSize(328, 150),
00162 EndContainer(),
00163 EndContainer(),
00164 };
00165
00166 static const WindowDesc _company_news_desc(
00167 WDP_MANUAL, 0, 0,
00168 WC_NEWS_WINDOW, WC_NONE,
00169 0,
00170 _nested_company_news_widgets, lengthof(_nested_company_news_widgets)
00171 );
00172
00173
00174 static const NWidgetPart _nested_thin_news_widgets[] = {
00175 NWidget(WWT_PANEL, COLOUR_WHITE, NTW_PANEL),
00176 NWidget(NWID_HORIZONTAL), SetPadding(1, 1, 0, 1),
00177 NWidget(WWT_TEXT, COLOUR_WHITE, NTW_CLOSEBOX), SetDataTip(STR_SILVER_CROSS, STR_NULL), SetPadding(0, 0, 0, 1),
00178 NWidget(NWID_SPACER), SetFill(1, 0),
00179 NWidget(NWID_VERTICAL),
00180 NWidget(WWT_LABEL, COLOUR_WHITE, NTW_DATE), SetDataTip(STR_DATE_LONG_SMALL, STR_NULL),
00181 NWidget(NWID_SPACER), SetFill(0, 1),
00182 EndContainer(),
00183 EndContainer(),
00184 NWidget(WWT_EMPTY, COLOUR_WHITE, NTW_MESSAGE), SetMinimalSize(428, 48), SetFill(1, 0), SetPadding(0, 1, 0, 1),
00185 NWidget(NWID_VIEWPORT, INVALID_COLOUR, NTW_VIEWPORT), SetMinimalSize(426, 70), SetPadding(1, 2, 2, 2),
00186 EndContainer(),
00187 };
00188
00189 static const WindowDesc _thin_news_desc(
00190 WDP_MANUAL, 0, 0,
00191 WC_NEWS_WINDOW, WC_NONE,
00192 0,
00193 _nested_thin_news_widgets, lengthof(_nested_thin_news_widgets)
00194 );
00195
00196
00197 static const NWidgetPart _nested_small_news_widgets[] = {
00198
00199 NWidget(NWID_HORIZONTAL),
00200 NWidget(WWT_CLOSEBOX, COLOUR_LIGHT_BLUE, NTW_CLOSEBOX),
00201 NWidget(WWT_CAPTION, COLOUR_LIGHT_BLUE, NTW_CAPTION), SetDataTip(STR_NEWS_MESSAGE_CAPTION, STR_NULL),
00202 EndContainer(),
00203
00204
00205 NWidget(WWT_PANEL, COLOUR_LIGHT_BLUE, NTW_HEADLINE),
00206 NWidget(WWT_INSET, COLOUR_LIGHT_BLUE, NTW_INSET), SetPadding(2, 2, 2, 2),
00207 NWidget(NWID_VIEWPORT, INVALID_COLOUR, NTW_VIEWPORT), SetPadding(1, 1, 1, 1), SetMinimalSize(274, 47), SetFill(1, 0),
00208 EndContainer(),
00209 NWidget(WWT_EMPTY, COLOUR_WHITE, NTW_MESSAGE), SetMinimalSize(275, 20), SetFill(1, 0),
00210 EndContainer(),
00211 };
00212
00213 static const WindowDesc _small_news_desc(
00214 WDP_MANUAL, 0, 0,
00215 WC_NEWS_WINDOW, WC_NONE,
00216 0,
00217 _nested_small_news_widgets, lengthof(_nested_small_news_widgets)
00218 );
00219
00223 struct NewsSubtypeData {
00224 NewsType type;
00225 NewsFlag flags;
00226 const WindowDesc *desc;
00227 };
00228
00232 static const NewsSubtypeData _news_subtype_data[] = {
00233
00234 { NT_ARRIVAL_COMPANY, (NF_NO_TRANSPARENT | NF_SHADE), &_thin_news_desc },
00235 { NT_ARRIVAL_OTHER, (NF_NO_TRANSPARENT | NF_SHADE), &_thin_news_desc },
00236 { NT_ACCIDENT, (NF_NO_TRANSPARENT | NF_SHADE), &_thin_news_desc },
00237 { NT_COMPANY_INFO, NF_NONE, &_company_news_desc },
00238 { NT_COMPANY_INFO, NF_NONE, &_company_news_desc },
00239 { NT_COMPANY_INFO, NF_NONE, &_company_news_desc },
00240 { NT_COMPANY_INFO, NF_NONE, &_company_news_desc },
00241 { NT_INDUSTRY_OPEN, (NF_NO_TRANSPARENT | NF_SHADE), &_thin_news_desc },
00242 { NT_INDUSTRY_CLOSE, (NF_NO_TRANSPARENT | NF_SHADE), &_thin_news_desc },
00243 { NT_ECONOMY, NF_NONE, &_normal_news_desc },
00244 { NT_INDUSTRY_COMPANY, (NF_NO_TRANSPARENT | NF_SHADE), &_thin_news_desc },
00245 { NT_INDUSTRY_OTHER, (NF_NO_TRANSPARENT | NF_SHADE), &_thin_news_desc },
00246 { NT_INDUSTRY_NOBODY, (NF_NO_TRANSPARENT | NF_SHADE), &_thin_news_desc },
00247 { NT_ADVICE, NF_INCOLOUR, &_small_news_desc },
00248 { NT_NEW_VEHICLES, NF_NONE, &_vehicle_news_desc },
00249 { NT_ACCEPTANCE, NF_INCOLOUR, &_small_news_desc },
00250 { NT_SUBSIDIES, NF_NONE, &_normal_news_desc },
00251 { NT_GENERAL, NF_NONE, &_normal_news_desc },
00252 };
00253
00254 assert_compile(lengthof(_news_subtype_data) == NS_END);
00255
00259 NewsTypeData _news_type_data[] = {
00260
00261 NewsTypeData("arrival_player", 60, SND_1D_APPLAUSE, STR_NEWS_MESSAGE_TYPE_ARRIVAL_OF_FIRST_VEHICLE_OWN ),
00262 NewsTypeData("arrival_other", 60, SND_1D_APPLAUSE, STR_NEWS_MESSAGE_TYPE_ARRIVAL_OF_FIRST_VEHICLE_OTHER ),
00263 NewsTypeData("accident", 90, SND_BEGIN, STR_NEWS_MESSAGE_TYPE_ACCIDENTS_DISASTERS ),
00264 NewsTypeData("company_info", 60, SND_BEGIN, STR_NEWS_MESSAGE_TYPE_COMPANY_INFORMATION ),
00265 NewsTypeData("open", 90, SND_BEGIN, STR_NEWS_MESSAGE_TYPE_INDUSTRY_OPEN ),
00266 NewsTypeData("close", 90, SND_BEGIN, STR_NEWS_MESSAGE_TYPE_INDUSTRY_CLOSE ),
00267 NewsTypeData("economy", 30, SND_BEGIN, STR_NEWS_MESSAGE_TYPE_ECONOMY_CHANGES ),
00268 NewsTypeData("production_player", 30, SND_BEGIN, STR_NEWS_MESSAGE_TYPE_INDUSTRY_CHANGES_SERVED_BY_COMPANY ),
00269 NewsTypeData("production_other", 30, SND_BEGIN, STR_NEWS_MESSAGE_TYPE_INDUSTRY_CHANGES_SERVED_BY_OTHER ),
00270 NewsTypeData("production_nobody", 30, SND_BEGIN, STR_NEWS_MESSAGE_TYPE_INDUSTRY_CHANGES_UNSERVED ),
00271 NewsTypeData("advice", 150, SND_BEGIN, STR_NEWS_MESSAGE_TYPE_ADVICE_INFORMATION_ON_COMPANY ),
00272 NewsTypeData("new_vehicles", 30, SND_1E_OOOOH, STR_NEWS_MESSAGE_TYPE_NEW_VEHICLES ),
00273 NewsTypeData("acceptance", 90, SND_BEGIN, STR_NEWS_MESSAGE_TYPE_CHANGES_OF_CARGO_ACCEPTANCE ),
00274 NewsTypeData("subsidies", 180, SND_BEGIN, STR_NEWS_MESSAGE_TYPE_SUBSIDIES ),
00275 NewsTypeData("general", 60, SND_BEGIN, STR_NEWS_MESSAGE_TYPE_GENERAL_INFORMATION ),
00276 };
00277
00278 assert_compile(lengthof(_news_type_data) == NT_END);
00279
00281 struct NewsWindow : Window {
00282 uint16 chat_height;
00283 uint16 status_height;
00284 const NewsItem *ni;
00285 static uint duration;
00286
00287 NewsWindow(const WindowDesc *desc, const NewsItem *ni) : Window(), ni(ni)
00288 {
00289 NewsWindow::duration = 555;
00290 const Window *w = FindWindowByClass(WC_SEND_NETWORK_MSG);
00291 this->chat_height = (w != NULL) ? w->height : 0;
00292 this->status_height = FindWindowById(WC_STATUS_BAR, 0)->height;
00293
00294 this->flags4 |= WF_DISABLE_VP_SCROLL;
00295
00296 this->CreateNestedTree(desc);
00297 switch (this->ni->subtype) {
00298 case NS_COMPANY_TROUBLE:
00299 this->GetWidget<NWidgetCore>(NTW_TITLE)->widget_data = STR_NEWS_COMPANY_IN_TROUBLE_TITLE;
00300 break;
00301
00302 case NS_COMPANY_MERGER:
00303 this->GetWidget<NWidgetCore>(NTW_TITLE)->widget_data = STR_NEWS_COMPANY_MERGER_TITLE;
00304 break;
00305
00306 case NS_COMPANY_BANKRUPT:
00307 this->GetWidget<NWidgetCore>(NTW_TITLE)->widget_data = STR_NEWS_COMPANY_BANKRUPT_TITLE;
00308 break;
00309
00310 case NS_COMPANY_NEW:
00311 this->GetWidget<NWidgetCore>(NTW_TITLE)->widget_data = STR_NEWS_COMPANY_LAUNCH_TITLE;
00312 break;
00313
00314 default:
00315 break;
00316 }
00317 this->FinishInitNested(desc, 0);
00318
00319
00320 NWidgetViewport *nvp = this->GetWidget<NWidgetViewport>(NTW_VIEWPORT);
00321 if (nvp != NULL) {
00322 nvp->InitializeViewport(this, ni->reftype1 == NR_VEHICLE ? 0x80000000 | ni->ref1 : GetReferenceTile(ni->reftype1, ni->ref1), ZOOM_LVL_NEWS);
00323 if (this->ni->flags & NF_NO_TRANSPARENT) nvp->disp_flags |= ND_NO_TRANSPARENCY;
00324 if ((this->ni->flags & NF_INCOLOUR) == 0) {
00325 nvp->disp_flags |= ND_SHADE_GREY;
00326 } else if (this->ni->flags & NF_SHADE) {
00327 nvp->disp_flags |= ND_SHADE_DIMMED;
00328 }
00329 }
00330 }
00331
00332 void DrawNewsBorder(const Rect &r) const
00333 {
00334 GfxFillRect(r.left, r.top, r.right, r.bottom, 0xF);
00335
00336 GfxFillRect(r.left, r.top, r.left, r.bottom, 0xD7);
00337 GfxFillRect(r.right, r.top, r.right, r.bottom, 0xD7);
00338 GfxFillRect(r.left, r.top, r.right, r.top, 0xD7);
00339 GfxFillRect(r.left, r.bottom, r.right, r.bottom, 0xD7);
00340 }
00341
00342 virtual Point OnInitialPosition(const WindowDesc *desc, int16 sm_width, int16 sm_height, int window_number)
00343 {
00344 Point pt = { (_screen.width - max(sm_width, desc->default_width)) / 2, _screen.height };
00345 return pt;
00346 }
00347
00348 virtual void OnPaint()
00349 {
00350 this->DrawWidgets();
00351 }
00352
00353 virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize)
00354 {
00355 StringID str = STR_NULL;
00356 switch (widget) {
00357 case NTW_MESSAGE:
00358 CopyInDParam(0, this->ni->params, lengthof(this->ni->params));
00359 str = this->ni->string_id;
00360 break;
00361
00362 case NTW_COMPANY_MSG:
00363 str = this->GetCompanyMessageString();
00364 break;
00365
00366 case NTW_VEH_NAME:
00367 case NTW_VEH_TITLE:
00368 str = this->GetNewVehicleMessageString(widget);
00369 break;
00370
00371 case NTW_VEH_INFO: {
00372 assert(this->ni->reftype1 == NR_ENGINE);
00373 EngineID engine = this->ni->ref1;
00374 str = GetEngineInfoString(engine);
00375 break;
00376 }
00377 default:
00378 return;
00379 }
00380
00381
00382 Dimension d = *size;
00383 d.width = (d.width >= padding.width) ? d.width - padding.width : 0;
00384 d.height = (d.height >= padding.height) ? d.height - padding.height : 0;
00385 d = GetStringMultiLineBoundingBox(str, d);
00386 d.width += padding.width;
00387 d.height += padding.height;
00388 *size = maxdim(*size, d);
00389 }
00390
00391 virtual void SetStringParameters(int widget) const
00392 {
00393 if (widget == NTW_DATE) SetDParam(0, this->ni->date);
00394 }
00395
00396 virtual void DrawWidget(const Rect &r, int widget) const
00397 {
00398 switch (widget) {
00399 case NTW_PANEL:
00400 this->DrawNewsBorder(r);
00401 return;
00402
00403 case NTW_MESSAGE:
00404 CopyInDParam(0, this->ni->params, lengthof(this->ni->params));
00405 DrawStringMultiLine(r.left + 2, r.right - 2, r.top, r.bottom, this->ni->string_id, TC_FROMSTRING, SA_CENTER);
00406 break;
00407
00408 case NTW_MGR_FACE: {
00409 const CompanyNewsInformation *cni = (const CompanyNewsInformation*)this->ni->free_data;
00410 DrawCompanyManagerFace(cni->face, cni->colour, r.left, r.top);
00411 GfxFillRect(r.left + 1, r.top, r.left + 1 + 91, r.top + 118, PALETTE_TO_STRUCT_GREY, FILLRECT_RECOLOUR);
00412 break;
00413 }
00414 case NTW_MGR_NAME: {
00415 const CompanyNewsInformation *cni = (const CompanyNewsInformation*)this->ni->free_data;
00416 SetDParamStr(0, cni->president_name);
00417 DrawStringMultiLine(r.left, r.right, r.top, r.bottom, STR_JUST_RAW_STRING, TC_FROMSTRING, SA_CENTER);
00418 break;
00419 }
00420 case NTW_COMPANY_MSG:
00421 DrawStringMultiLine(r.left, r.right, r.top, r.bottom, this->GetCompanyMessageString(), TC_FROMSTRING, SA_CENTER);
00422 break;
00423
00424 case NTW_VEH_BKGND:
00425 GfxFillRect(r.left, r.top, r.right, r.bottom, 10);
00426 break;
00427
00428 case NTW_VEH_NAME:
00429 case NTW_VEH_TITLE:
00430 DrawStringMultiLine(r.left, r.right, r.top, r.bottom, this->GetNewVehicleMessageString(widget), TC_FROMSTRING, SA_CENTER);
00431 break;
00432
00433 case NTW_VEH_SPR: {
00434 assert(this->ni->reftype1 == NR_ENGINE);
00435 EngineID engine = this->ni->ref1;
00436 DrawVehicleEngine(r.left, r.right, (r.left + r.right) / 2, (r.top + r.bottom) / 2, engine, GetEnginePalette(engine, _local_company));
00437 GfxFillRect(r.left, r.top, r.right, r.bottom, PALETTE_TO_STRUCT_GREY, FILLRECT_RECOLOUR);
00438 break;
00439 }
00440 case NTW_VEH_INFO: {
00441 assert(this->ni->reftype1 == NR_ENGINE);
00442 EngineID engine = this->ni->ref1;
00443 DrawStringMultiLine(r.left, r.right, r.top, r.bottom, GetEngineInfoString(engine), TC_FROMSTRING, SA_CENTER);
00444 break;
00445 }
00446 }
00447 }
00448
00449 virtual void OnClick(Point pt, int widget)
00450 {
00451 switch (widget) {
00452 case NTW_CLOSEBOX:
00453 NewsWindow::duration = 0;
00454 delete this;
00455 _forced_news = NULL;
00456 break;
00457
00458 case NTW_CAPTION:
00459 case NTW_VIEWPORT:
00460 break;
00461
00462 default:
00463 if (this->ni->reftype1 == NR_VEHICLE) {
00464 const Vehicle *v = Vehicle::Get(this->ni->ref1);
00465 ScrollMainWindowTo(v->x_pos, v->y_pos, v->z_pos);
00466 } else {
00467 TileIndex tile1 = GetReferenceTile(this->ni->reftype1, this->ni->ref1);
00468 TileIndex tile2 = GetReferenceTile(this->ni->reftype2, this->ni->ref2);
00469 if (_ctrl_pressed) {
00470 if (tile1 != INVALID_TILE) ShowExtraViewPortWindow(tile1);
00471 if (tile2 != INVALID_TILE) ShowExtraViewPortWindow(tile2);
00472 } else {
00473 if ((tile1 == INVALID_TILE || !ScrollMainWindowToTile(tile1)) && tile2 != INVALID_TILE) {
00474 ScrollMainWindowToTile(tile2);
00475 }
00476 }
00477 }
00478 break;
00479 }
00480 }
00481
00482 virtual EventState OnKeyPress(uint16 key, uint16 keycode)
00483 {
00484 if (keycode == WKC_SPACE) {
00485
00486 delete this;
00487 return ES_HANDLED;
00488 }
00489 return ES_NOT_HANDLED;
00490 }
00491
00492 virtual void OnInvalidateData(int data)
00493 {
00494
00495 this->chat_height = data;
00496 }
00497
00498 virtual void OnTick()
00499 {
00500
00501 int y = max(this->top - 4, _screen.height - this->height - this->status_height - this->chat_height);
00502 if (y == this->top) return;
00503
00504 if (this->viewport != NULL) this->viewport->top += y - this->top;
00505
00506 int diff = Delta(this->top, y);
00507 this->top = y;
00508
00509 SetDirtyBlocks(this->left, this->top, this->left + this->width, this->top + this->height + diff);
00510 }
00511
00512 private:
00513 StringID GetCompanyMessageString() const
00514 {
00515 switch (this->ni->subtype) {
00516 case NS_COMPANY_TROUBLE:
00517 SetDParam(0, this->ni->params[2]);
00518 return STR_NEWS_COMPANY_IN_TROUBLE_DESCRIPTION;
00519
00520 case NS_COMPANY_MERGER:
00521 SetDParam(0, this->ni->params[2]);
00522 SetDParam(1, this->ni->params[3]);
00523 SetDParam(2, this->ni->params[4]);
00524 return this->ni->params[4] == 0 ? STR_NEWS_MERGER_TAKEOVER_TITLE : STR_NEWS_COMPANY_MERGER_DESCRIPTION;
00525
00526 case NS_COMPANY_BANKRUPT:
00527 SetDParam(0, this->ni->params[2]);
00528 return STR_NEWS_COMPANY_BANKRUPT_DESCRIPTION;
00529
00530 case NS_COMPANY_NEW:
00531 SetDParam(0, this->ni->params[2]);
00532 SetDParam(1, this->ni->params[3]);
00533 return STR_NEWS_COMPANY_LAUNCH_DESCRIPTION;
00534
00535 default:
00536 NOT_REACHED();
00537 }
00538 }
00539
00540 StringID GetNewVehicleMessageString(int widget) const
00541 {
00542 assert(this->ni->reftype1 == NR_ENGINE);
00543 EngineID engine = this->ni->ref1;
00544
00545 switch (widget) {
00546 case NTW_VEH_TITLE:
00547 SetDParam(0, GetEngineCategoryName(engine));
00548 return STR_NEWS_NEW_VEHICLE_NOW_AVAILABLE;
00549
00550 case NTW_VEH_NAME:
00551 SetDParam(0, engine);
00552 return STR_NEWS_NEW_VEHICLE_TYPE;
00553
00554 default:
00555 NOT_REACHED();
00556 }
00557 }
00558 };
00559
00560 uint NewsWindow::duration = 0;
00561
00562
00564 static void ShowNewspaper(const NewsItem *ni)
00565 {
00566 SoundFx sound = _news_type_data[_news_subtype_data[ni->subtype].type].sound;
00567 if (sound != 0) SndPlayFx(sound);
00568
00569 new NewsWindow(_news_subtype_data[ni->subtype].desc, ni);
00570 }
00571
00573 static void ShowTicker(const NewsItem *ni)
00574 {
00575 if (_news_ticker_sound) SndPlayFx(SND_16_MORSE);
00576
00577 _statusbar_news_item = ni;
00578 InvalidateWindowData(WC_STATUS_BAR, 0, SBI_SHOW_TICKER);
00579 }
00580
00582 void InitNewsItemStructs()
00583 {
00584 for (NewsItem *ni = _oldest_news; ni != NULL; ) {
00585 NewsItem *next = ni->next;
00586 delete ni;
00587 ni = next;
00588 }
00589
00590 _total_news = 0;
00591 _oldest_news = NULL;
00592 _latest_news = NULL;
00593 _forced_news = NULL;
00594 _current_news = NULL;
00595 _statusbar_news_item = NULL;
00596 NewsWindow::duration = 0;
00597 }
00598
00603 static bool ReadyForNextItem()
00604 {
00605 const NewsItem *ni = _forced_news == NULL ? _current_news : _forced_news;
00606 if (ni == NULL) return true;
00607
00608
00609
00610 if (IsNewsTickerShown()) return false;
00611
00612
00613 if (NewsWindow::duration != 0) NewsWindow::duration--;
00614
00615
00616 return (NewsWindow::duration == 0 || FindWindowById(WC_NEWS_WINDOW, 0) == NULL);
00617 }
00618
00620 static void MoveToNextItem()
00621 {
00622 InvalidateWindowData(WC_STATUS_BAR, 0, SBI_NEWS_DELETED);
00623 DeleteWindowById(WC_NEWS_WINDOW, 0);
00624 _forced_news = NULL;
00625 _statusbar_news_item = NULL;
00626
00627
00628 if (_current_news != _latest_news) {
00629 _current_news = (_current_news == NULL) ? _oldest_news : _current_news->next;
00630 const NewsItem *ni = _current_news;
00631 const NewsType type = _news_subtype_data[ni->subtype].type;
00632
00633
00634 if (_date - _news_type_data[type].age > ni->date) return;
00635
00636 switch (_news_type_data[type].display) {
00637 default: NOT_REACHED();
00638 case ND_OFF:
00639 InvalidateWindowData(WC_STATUS_BAR, 0, SBI_SHOW_REMINDER);
00640 break;
00641
00642 case ND_SUMMARY:
00643 ShowTicker(ni);
00644 break;
00645
00646 case ND_FULL:
00647 ShowNewspaper(ni);
00648 break;
00649 }
00650 }
00651 }
00652
00665 void AddNewsItem(StringID string, NewsSubtype subtype, NewsReferenceType reftype1, uint32 ref1, NewsReferenceType reftype2, uint32 ref2, void *free_data)
00666 {
00667 if (_game_mode == GM_MENU) return;
00668
00669
00670 NewsItem *ni = new NewsItem;
00671
00672 ni->string_id = string;
00673 ni->subtype = subtype;
00674 ni->flags = _news_subtype_data[subtype].flags;
00675
00676
00677 if (_cur_year >= _settings_client.gui.coloured_news_year) ni->flags |= NF_INCOLOUR;
00678
00679 ni->reftype1 = reftype1;
00680 ni->reftype2 = reftype2;
00681 ni->ref1 = ref1;
00682 ni->ref2 = ref2;
00683 ni->free_data = free_data;
00684 ni->date = _date;
00685 CopyOutDParam(ni->params, 0, lengthof(ni->params));
00686
00687 if (_total_news++ == 0) {
00688 assert(_oldest_news == NULL);
00689 _oldest_news = ni;
00690 ni->prev = NULL;
00691 } else {
00692 assert(_latest_news->next == NULL);
00693 _latest_news->next = ni;
00694 ni->prev = _latest_news;
00695 }
00696
00697 ni->next = NULL;
00698 _latest_news = ni;
00699
00700 SetWindowDirty(WC_MESSAGE_HISTORY, 0);
00701 }
00702
00704 static void DeleteNewsItem(NewsItem *ni)
00705 {
00706 if (_forced_news == ni || _current_news == ni) {
00707
00708
00709 MoveToNextItem();
00710 }
00711
00712
00713
00714 if (ni->prev != NULL) {
00715 ni->prev->next = ni->next;
00716 } else {
00717 assert(_oldest_news == ni);
00718 _oldest_news = ni->next;
00719 }
00720
00721 if (ni->next != NULL) {
00722 ni->next->prev = ni->prev;
00723 } else {
00724 assert(_latest_news == ni);
00725 _latest_news = ni->prev;
00726 }
00727
00728 free(ni->free_data);
00729
00730 if (_current_news == ni) _current_news = ni->prev;
00731 _total_news--;
00732 delete ni;
00733
00734 SetWindowDirty(WC_MESSAGE_HISTORY, 0);
00735 }
00736
00737 void DeleteVehicleNews(VehicleID vid, StringID news)
00738 {
00739 NewsItem *ni = _oldest_news;
00740
00741 while (ni != NULL) {
00742 NewsItem *next = ni->next;
00743 if (((ni->reftype1 == NR_VEHICLE && ni->ref1 == vid) || (ni->reftype2 == NR_VEHICLE && ni->ref2 == vid)) &&
00744 (news == INVALID_STRING_ID || ni->string_id == news)) {
00745 DeleteNewsItem(ni);
00746 }
00747 ni = next;
00748 }
00749 }
00750
00755 void DeleteStationNews(StationID sid)
00756 {
00757 NewsItem *ni = _oldest_news;
00758
00759 while (ni != NULL) {
00760 NewsItem *next = ni->next;
00761 if ((ni->reftype1 == NR_STATION && ni->ref1 == sid) || (ni->reftype2 == NR_STATION && ni->ref2 == sid)) {
00762 DeleteNewsItem(ni);
00763 }
00764 ni = next;
00765 }
00766 }
00767
00771 void DeleteIndustryNews(IndustryID iid)
00772 {
00773 NewsItem *ni = _oldest_news;
00774
00775 while (ni != NULL) {
00776 NewsItem *next = ni->next;
00777 if ((ni->reftype1 == NR_INDUSTRY && ni->ref1 == iid) || (ni->reftype2 == NR_INDUSTRY && ni->ref2 == iid)) {
00778 DeleteNewsItem(ni);
00779 }
00780 ni = next;
00781 }
00782 }
00783
00784 static void RemoveOldNewsItems()
00785 {
00786 NewsItem *next;
00787 for (NewsItem *cur = _oldest_news; _total_news > MIN_NEWS_AMOUNT && cur != NULL; cur = next) {
00788 next = cur->next;
00789 if (_date - _news_type_data[_news_subtype_data[cur->subtype].type].age * _settings_client.gui.news_message_timeout > cur->date) DeleteNewsItem(cur);
00790 }
00791 }
00792
00799 void ChangeVehicleNews(VehicleID from_index, VehicleID to_index)
00800 {
00801 for (NewsItem *ni = _oldest_news; ni != NULL; ni = ni->next) {
00802 if (ni->reftype1 == NR_VEHICLE && ni->ref1 == from_index) ni->ref1 = to_index;
00803 if (ni->reftype2 == NR_VEHICLE && ni->ref2 == from_index) ni->ref2 = to_index;
00804
00805
00806
00807
00808
00809
00810
00811
00812 if (ni->subtype == NS_ADVICE && ni->params[0] == from_index) ni->params[0] = to_index;
00813 }
00814 }
00815
00816 void NewsLoop()
00817 {
00818
00819 if (_total_news == 0) return;
00820
00821
00822
00823
00824 if (FindWindowById(WC_STATUS_BAR, 0) == NULL) return;
00825
00826 static byte _last_clean_month = 0;
00827
00828 if (_last_clean_month != _cur_month) {
00829 RemoveOldNewsItems();
00830 _last_clean_month = _cur_month;
00831 }
00832
00833 if (ReadyForNextItem()) MoveToNextItem();
00834 }
00835
00837 static void ShowNewsMessage(const NewsItem *ni)
00838 {
00839 assert(_total_news != 0);
00840
00841
00842 DeleteWindowById(WC_NEWS_WINDOW, 0);
00843
00844
00845 _forced_news = ni;
00846
00847 if (_forced_news != NULL) {
00848 DeleteWindowById(WC_NEWS_WINDOW, 0);
00849 ShowNewspaper(ni);
00850 }
00851 }
00852
00854 void ShowLastNewsMessage()
00855 {
00856 if (_total_news == 0) {
00857 return;
00858 } else if (_forced_news == NULL) {
00859
00860
00861 const Window *w = FindWindowById(WC_NEWS_WINDOW, 0);
00862 ShowNewsMessage((w == NULL || (_current_news == _oldest_news)) ? _current_news : _current_news->prev);
00863 } else if (_forced_news == _oldest_news) {
00864
00865 ShowNewsMessage(_latest_news);
00866 } else {
00867
00868 ShowNewsMessage(_forced_news->prev);
00869 }
00870 }
00871
00872
00883 static void DrawNewsString(uint left, uint right, int y, TextColour colour, const NewsItem *ni)
00884 {
00885 char buffer[512], buffer2[512];
00886 StringID str;
00887
00888 CopyInDParam(0, ni->params, lengthof(ni->params));
00889 str = ni->string_id;
00890
00891 GetString(buffer, str, lastof(buffer));
00892
00893
00894 const char *ptr = buffer;
00895 char *dest = buffer2;
00896 WChar c_last = '\0';
00897 for (;;) {
00898 WChar c = Utf8Consume(&ptr);
00899 if (c == 0) break;
00900
00901 if (c == '\n' && c_last != '\n') {
00902 dest[0] = ' ';
00903 dest++;
00904 } else if (c == '\r') {
00905 dest[0] = dest[1] = dest[2] = dest[3] = ' ';
00906 dest += 4;
00907 } else if (IsPrintable(c)) {
00908 dest += Utf8Encode(dest, c);
00909 }
00910 c_last = c;
00911 }
00912
00913 *dest = '\0';
00914
00915 DrawString(left, right, y, buffer2, colour);
00916 }
00917
00919 enum MessageHistoryWidgets {
00920 MHW_STICKYBOX,
00921 MHW_BACKGROUND,
00922 MHW_SCROLLBAR,
00923 };
00924
00925 struct MessageHistoryWindow : Window {
00926 static const int top_spacing;
00927 static const int bottom_spacing;
00928
00929 int line_height;
00930 int date_width;
00931
00932 MessageHistoryWindow(const WindowDesc *desc) : Window()
00933 {
00934 this->InitNested(desc);
00935 this->OnInvalidateData(0);
00936 }
00937
00938 virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize)
00939 {
00940 if (widget == MHW_BACKGROUND) {
00941 this->line_height = FONT_HEIGHT_NORMAL + 2;
00942 resize->height = this->line_height;
00943
00944 SetDParam(0, ConvertYMDToDate(ORIGINAL_MAX_YEAR, 12, 30));
00945 this->date_width = GetStringBoundingBox(STR_SHORT_DATE).width;
00946
00947 size->height = 4 * resize->height + this->top_spacing + this->bottom_spacing;
00948 size->width = max(200u, size->width);
00949 }
00950 }
00951
00952 virtual void OnPaint()
00953 {
00954 this->OnInvalidateData(0);
00955 this->DrawWidgets();
00956 }
00957
00958 virtual void DrawWidget(const Rect &r, int widget) const
00959 {
00960 if (widget != MHW_BACKGROUND || _total_news == 0) return;
00961
00962
00963 NewsItem *ni = _latest_news;
00964 for (int n = this->vscroll.GetPosition(); n > 0; n--) {
00965 ni = ni->prev;
00966 if (ni == NULL) return;
00967 }
00968
00969
00970 int y = r.top + this->top_spacing;
00971 bool rtl = _dynlang.text_dir == TD_RTL;
00972 uint date_left = rtl ? r.right - WD_FRAMERECT_RIGHT - this->date_width : r.left + WD_FRAMERECT_LEFT;
00973 uint date_right = rtl ? r.right - WD_FRAMERECT_RIGHT : r.left + WD_FRAMERECT_LEFT + this->date_width;
00974 uint news_left = rtl ? r.left + WD_FRAMERECT_LEFT : r.left + WD_FRAMERECT_LEFT + this->date_width + WD_FRAMERECT_RIGHT;
00975 uint news_right = rtl ? r.right - WD_FRAMERECT_RIGHT - this->date_width - WD_FRAMERECT_RIGHT : r.right - WD_FRAMERECT_RIGHT;
00976 for (int n = this->vscroll.GetCapacity(); n > 0; n--) {
00977 SetDParam(0, ni->date);
00978 DrawString(date_left, date_right, y, STR_SHORT_DATE);
00979
00980 DrawNewsString(news_left, news_right, y, TC_WHITE, ni);
00981 y += this->line_height;
00982
00983 ni = ni->prev;
00984 if (ni == NULL) return;
00985 }
00986 }
00987
00988 virtual void OnInvalidateData(int data)
00989 {
00990 this->vscroll.SetCount(_total_news);
00991 }
00992
00993 virtual void OnClick(Point pt, int widget)
00994 {
00995 if (widget == MHW_BACKGROUND) {
00996 NewsItem *ni = _latest_news;
00997 if (ni == NULL) return;
00998
00999 for (int n = (pt.y - this->GetWidget<NWidgetBase>(MHW_BACKGROUND)->pos_y - WD_FRAMERECT_TOP) / this->line_height + this->vscroll.GetPosition(); n > 0; n--) {
01000 ni = ni->prev;
01001 if (ni == NULL) return;
01002 }
01003
01004 ShowNewsMessage(ni);
01005 }
01006 }
01007
01008 virtual void OnResize()
01009 {
01010 this->vscroll.SetCapacity(this->GetWidget<NWidgetBase>(MHW_BACKGROUND)->current_y / this->line_height);
01011 }
01012 };
01013
01014 const int MessageHistoryWindow::top_spacing = WD_FRAMERECT_TOP + 4;
01015 const int MessageHistoryWindow::bottom_spacing = WD_FRAMERECT_BOTTOM;
01016
01017 static const NWidgetPart _nested_message_history[] = {
01018 NWidget(NWID_HORIZONTAL),
01019 NWidget(WWT_CLOSEBOX, COLOUR_BROWN),
01020 NWidget(WWT_CAPTION, COLOUR_BROWN), SetDataTip(STR_MESSAGE_HISTORY, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
01021 NWidget(WWT_SHADEBOX, COLOUR_BROWN),
01022 NWidget(WWT_STICKYBOX, COLOUR_BROWN),
01023 EndContainer(),
01024
01025 NWidget(NWID_HORIZONTAL),
01026 NWidget(WWT_PANEL, COLOUR_BROWN, MHW_BACKGROUND), SetMinimalSize(200, 125), SetDataTip(0x0, STR_MESSAGE_HISTORY_TOOLTIP), SetResize(1, 12),
01027 EndContainer(),
01028 NWidget(NWID_VERTICAL),
01029 NWidget(WWT_SCROLLBAR, COLOUR_BROWN, MHW_SCROLLBAR),
01030 NWidget(WWT_RESIZEBOX, COLOUR_BROWN),
01031 EndContainer(),
01032 EndContainer(),
01033 };
01034
01035 static const WindowDesc _message_history_desc(
01036 WDP_AUTO, 400, 140,
01037 WC_MESSAGE_HISTORY, WC_NONE,
01038 WDF_UNCLICK_BUTTONS,
01039 _nested_message_history, lengthof(_nested_message_history)
01040 );
01041
01043 void ShowMessageHistory()
01044 {
01045 DeleteWindowById(WC_MESSAGE_HISTORY, 0);
01046 new MessageHistoryWindow(&_message_history_desc);
01047 }
01048
01050 enum MessageOptionsSpace {
01051 MOS_WIDG_PER_SETTING = 4,
01052
01053 MOS_LEFT_EDGE = 6,
01054 MOS_COLUMN_SPACING = 4,
01055 MOS_RIGHT_EDGE = 6,
01056 MOS_BUTTON_SPACE = 10,
01057
01058 MOS_ABOVE_GLOBAL_SETTINGS = 6,
01059 MOS_BOTTOM_EDGE = 6,
01060 };
01061
01063 enum MessageOptionWidgets {
01064 WIDGET_NEWSOPT_BACKGROUND,
01065 WIDGET_NEWSOPT_LABEL,
01066 WIDGET_NEWSOPT_DROP_SUMMARY,
01067 WIDGET_NEWSOPT_LABEL_SUMMARY,
01068 WIDGET_NEWSOPT_SOUNDTICKER,
01069 WIDGET_NEWSOPT_SOUNDTICKER_LABEL,
01070
01071 WIDGET_NEWSOPT_START_OPTION,
01072 WIDGET_NEWSOPT_END_OPTION = WIDGET_NEWSOPT_START_OPTION + NT_END * MOS_WIDG_PER_SETTING,
01073 };
01074
01075 struct MessageOptionsWindow : Window {
01076 static const StringID message_opt[];
01077 int state;
01078 Dimension dim_message_opt;
01079
01080 MessageOptionsWindow(const WindowDesc *desc) : Window()
01081 {
01082 this->InitNested(desc);
01083
01084 NewsDisplay all_val = _news_type_data[0].display;
01085 for (int i = 0; i < NT_END; i++) {
01086 this->SetMessageButtonStates(_news_type_data[i].display, i);
01087
01088 if (_news_type_data[i].display != all_val) all_val = ND_OFF;
01089 }
01090
01091 this->state = all_val;
01092 this->OnInvalidateData(0);
01093 }
01094
01103 void SetMessageButtonStates(byte value, int element)
01104 {
01105 element *= MOS_WIDG_PER_SETTING;
01106
01107 this->SetWidgetDisabledState(element + WIDGET_NEWSOPT_START_OPTION, value == 0);
01108 this->SetWidgetDisabledState(element + WIDGET_NEWSOPT_START_OPTION + 2, value == 2);
01109 }
01110
01111 virtual void OnPaint()
01112 {
01113 this->DrawWidgets();
01114 }
01115
01116 virtual void DrawWidget(const Rect &r, int widget) const
01117 {
01118 if (widget >= WIDGET_NEWSOPT_START_OPTION && widget < WIDGET_NEWSOPT_END_OPTION && (widget - WIDGET_NEWSOPT_START_OPTION) % MOS_WIDG_PER_SETTING == 1) {
01119
01120 int i = (widget - WIDGET_NEWSOPT_START_OPTION) / MOS_WIDG_PER_SETTING;
01121 DrawString(r.left, r.right, r.top + 2, this->message_opt[_news_type_data[i].display], TC_BLACK, SA_CENTER);
01122 }
01123 }
01124
01125 virtual void OnInit()
01126 {
01127 this->dim_message_opt.width = 0;
01128 this->dim_message_opt.height = 0;
01129 for (const StringID *str = message_opt; *str != INVALID_STRING_ID; str++) this->dim_message_opt = maxdim(this->dim_message_opt, GetStringBoundingBox(*str));
01130 }
01131
01132 virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize)
01133 {
01134 if (widget >= WIDGET_NEWSOPT_START_OPTION && widget < WIDGET_NEWSOPT_END_OPTION) {
01135
01136 size->height = FONT_HEIGHT_NORMAL + max(WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM, WD_IMGBTN_TOP + WD_IMGBTN_BOTTOM);
01137
01138
01139 if ((widget - WIDGET_NEWSOPT_START_OPTION) % MOS_WIDG_PER_SETTING == 1) {
01140 size->width = this->dim_message_opt.width + padding.width + MOS_BUTTON_SPACE;
01141 }
01142 return;
01143 }
01144
01145
01146 if (widget == WIDGET_NEWSOPT_DROP_SUMMARY || widget == WIDGET_NEWSOPT_LABEL_SUMMARY || widget == WIDGET_NEWSOPT_SOUNDTICKER || widget == WIDGET_NEWSOPT_SOUNDTICKER_LABEL) {
01147
01148 size->height = FONT_HEIGHT_NORMAL + max(WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM, WD_DROPDOWNTEXT_TOP + WD_DROPDOWNTEXT_BOTTOM);
01149
01150 if (widget == WIDGET_NEWSOPT_DROP_SUMMARY) {
01151 size->width = this->dim_message_opt.width + padding.width + MOS_BUTTON_SPACE;
01152 } else if (widget == WIDGET_NEWSOPT_SOUNDTICKER) {
01153 size->width += MOS_BUTTON_SPACE;
01154 }
01155 return;
01156 }
01157 }
01158
01159 virtual void OnInvalidateData(int data)
01160 {
01161
01162 this->GetWidget<NWidgetCore>(WIDGET_NEWSOPT_DROP_SUMMARY)->widget_data = this->message_opt[this->state];
01163
01164
01165 this->SetWidgetLoweredState(WIDGET_NEWSOPT_SOUNDTICKER, _news_ticker_sound);
01166 }
01167
01168 virtual void OnClick(Point pt, int widget)
01169 {
01170 switch (widget) {
01171 case WIDGET_NEWSOPT_DROP_SUMMARY:
01172 ShowDropDownMenu(this, this->message_opt, this->state, WIDGET_NEWSOPT_DROP_SUMMARY, 0, 0);
01173 break;
01174
01175 case WIDGET_NEWSOPT_SOUNDTICKER:
01176 _news_ticker_sound ^= 1;
01177 this->InvalidateData();
01178 break;
01179
01180 default: {
01181 if (widget >= WIDGET_NEWSOPT_START_OPTION && widget < WIDGET_NEWSOPT_END_OPTION) {
01182 int wid = widget - WIDGET_NEWSOPT_START_OPTION;
01183 int element = wid / MOS_WIDG_PER_SETTING;
01184 byte val = (_news_type_data[element].display + ((wid % MOS_WIDG_PER_SETTING) ? 1 : -1)) % 3;
01185
01186 this->SetMessageButtonStates(val, element);
01187 _news_type_data[element].display = (NewsDisplay)val;
01188 this->SetDirty();
01189 }
01190 break;
01191 }
01192 }
01193 }
01194
01195 virtual void OnDropdownSelect(int widget, int index)
01196 {
01197 this->state = index;
01198
01199 for (int i = 0; i < NT_END; i++) {
01200 this->SetMessageButtonStates(index, i);
01201 _news_type_data[i].display = (NewsDisplay)index;
01202 }
01203 this->InvalidateData();
01204 }
01205 };
01206
01207 const StringID MessageOptionsWindow::message_opt[] = {STR_NEWS_MESSAGES_OFF, STR_NEWS_MESSAGES_SUMMARY, STR_NEWS_MESSAGES_FULL, INVALID_STRING_ID};
01208
01210 static NWidgetBase *MakeButtonsColumn(int *biggest_index)
01211 {
01212 NWidgetVertical *vert_buttons = new NWidgetVertical;
01213
01214
01215 int widnum = WIDGET_NEWSOPT_START_OPTION;
01216 for (int i = 0; i < NT_END; i++) {
01217 NWidgetHorizontal *hor = new NWidgetHorizontal;
01218
01219 NWidgetLeaf *leaf = new NWidgetLeaf(NWID_BUTTON_ARROW, COLOUR_YELLOW, widnum, AWV_DECREASE, STR_TOOLTIP_HSCROLL_BAR_SCROLLS_LIST);
01220 leaf->SetFill(1, 1);
01221 hor->Add(leaf);
01222
01223 leaf = new NWidgetLeaf(WWT_PUSHTXTBTN, COLOUR_YELLOW, widnum + 1, STR_EMPTY, STR_NULL);
01224 leaf->SetFill(1, 1);
01225 hor->Add(leaf);
01226
01227 leaf = new NWidgetLeaf(NWID_BUTTON_ARROW, COLOUR_YELLOW, widnum + 2, AWV_INCREASE, STR_TOOLTIP_HSCROLL_BAR_SCROLLS_LIST);
01228 leaf->SetFill(1, 1);
01229 hor->Add(leaf);
01230 vert_buttons->Add(hor);
01231
01232 widnum += MOS_WIDG_PER_SETTING;
01233 }
01234 *biggest_index = widnum - MOS_WIDG_PER_SETTING + 2;
01235
01236
01237 NWidgetSpacer *spacer = new NWidgetSpacer(0, MOS_ABOVE_GLOBAL_SETTINGS);
01238 vert_buttons->Add(spacer);
01239
01240
01241 NWidgetLeaf *leaf = new NWidgetLeaf(WWT_DROPDOWN, COLOUR_YELLOW, WIDGET_NEWSOPT_DROP_SUMMARY, STR_EMPTY, STR_NULL);
01242 leaf->SetFill(1, 1);
01243 vert_buttons->Add(leaf);
01244
01245 leaf = new NWidgetLeaf(WWT_TEXTBTN_2, COLOUR_YELLOW, WIDGET_NEWSOPT_SOUNDTICKER, STR_STATION_BUILD_COVERAGE_OFF, STR_NULL);
01246 leaf->SetFill(1, 1);
01247 vert_buttons->Add(leaf);
01248
01249 *biggest_index = max(*biggest_index, max<int>(WIDGET_NEWSOPT_DROP_SUMMARY, WIDGET_NEWSOPT_SOUNDTICKER));
01250 return vert_buttons;
01251 }
01252
01254 static NWidgetBase *MakeDescriptionColumn(int *biggest_index)
01255 {
01256 NWidgetVertical *vert_desc = new NWidgetVertical;
01257
01258
01259 int widnum = WIDGET_NEWSOPT_START_OPTION;
01260 for (int i = 0; i < NT_END; i++) {
01261 NWidgetHorizontal *hor = new NWidgetHorizontal;
01262
01263
01264 NWidgetLeaf *leaf = new NWidgetLeaf(WWT_TEXT, COLOUR_YELLOW, widnum + 3, _news_type_data[i].description, STR_NULL);
01265 hor->Add(leaf);
01266
01267 NWidgetSpacer *spacer = new NWidgetSpacer(0, 0);
01268 spacer->SetFill(1, 0);
01269 hor->Add(spacer);
01270 vert_desc->Add(hor);
01271
01272 widnum += MOS_WIDG_PER_SETTING;
01273 }
01274 *biggest_index = widnum - MOS_WIDG_PER_SETTING + 3;
01275
01276
01277 NWidgetSpacer *spacer = new NWidgetSpacer(0, MOS_ABOVE_GLOBAL_SETTINGS);
01278 vert_desc->Add(spacer);
01279
01280
01281 NWidgetHorizontal *hor = new NWidgetHorizontal;
01282 NWidgetLeaf *leaf = new NWidgetLeaf(WWT_TEXT, COLOUR_YELLOW, WIDGET_NEWSOPT_LABEL_SUMMARY, STR_NEWS_MESSAGES_ALL, STR_NULL);
01283 hor->Add(leaf);
01284
01285 spacer = new NWidgetSpacer(0, 0);
01286 spacer->SetFill(1, 0);
01287 hor->Add(spacer);
01288 vert_desc->Add(hor);
01289
01290 hor = new NWidgetHorizontal;
01291 leaf = new NWidgetLeaf(WWT_TEXT, COLOUR_YELLOW, WIDGET_NEWSOPT_SOUNDTICKER_LABEL, STR_NEWS_MESSAGES_SOUND, STR_NULL);
01292 hor->Add(leaf);
01293
01294 spacer = new NWidgetSpacer(0, 0);
01295 leaf->SetFill(1, 0);
01296 hor->Add(spacer);
01297 vert_desc->Add(hor);
01298
01299 *biggest_index = max(*biggest_index, max<int>(WIDGET_NEWSOPT_LABEL_SUMMARY, WIDGET_NEWSOPT_SOUNDTICKER_LABEL));
01300 return vert_desc;
01301 }
01302
01303 static const NWidgetPart _nested_message_options_widgets[] = {
01304 NWidget(NWID_HORIZONTAL),
01305 NWidget(WWT_CLOSEBOX, COLOUR_BROWN),
01306 NWidget(WWT_CAPTION, COLOUR_BROWN), SetDataTip(STR_NEWS_MESSAGE_OPTIONS_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
01307 EndContainer(),
01308 NWidget(WWT_PANEL, COLOUR_BROWN, WIDGET_NEWSOPT_BACKGROUND),
01309 NWidget(NWID_HORIZONTAL),
01310 NWidget(NWID_SPACER), SetFill(1, 0),
01311 NWidget(WWT_LABEL, COLOUR_BROWN, WIDGET_NEWSOPT_LABEL), SetMinimalSize(0, 14), SetDataTip(STR_NEWS_MESSAGE_TYPES, STR_NULL),
01312 NWidget(NWID_SPACER), SetFill(1, 0),
01313 EndContainer(),
01314 NWidget(NWID_HORIZONTAL),
01315 NWidget(NWID_SPACER), SetMinimalSize(MOS_LEFT_EDGE, 0),
01316 NWidgetFunction(MakeButtonsColumn),
01317 NWidget(NWID_SPACER), SetMinimalSize(MOS_COLUMN_SPACING, 0),
01318 NWidgetFunction(MakeDescriptionColumn),
01319 NWidget(NWID_SPACER), SetMinimalSize(MOS_RIGHT_EDGE, 0),
01320 EndContainer(),
01321 NWidget(NWID_SPACER), SetMinimalSize(0, MOS_BOTTOM_EDGE),
01322 EndContainer(),
01323 };
01324
01325 static const WindowDesc _message_options_desc(
01326 WDP_AUTO, 0, 0,
01327 WC_GAME_OPTIONS, WC_NONE,
01328 WDF_UNCLICK_BUTTONS,
01329 _nested_message_options_widgets, lengthof(_nested_message_options_widgets)
01330 );
01331
01332 void ShowMessageOptions()
01333 {
01334 DeleteWindowById(WC_GAME_OPTIONS, 0);
01335 new MessageOptionsWindow(&_message_options_desc);
01336 }