00001
00002
00005 #include "stdafx.h"
00006 #include "openttd.h"
00007 #include "debug.h"
00008 #include "gui.h"
00009 #include "window_gui.h"
00010 #include "textbuf_gui.h"
00011 #include "station_base.h"
00012 #include "company_func.h"
00013 #include "economy_func.h"
00014 #include "town.h"
00015 #include "command_func.h"
00016 #include "variables.h"
00017 #include "vehicle_gui.h"
00018 #include "cargotype.h"
00019 #include "station_gui.h"
00020 #include "station_func.h"
00021 #include "strings_func.h"
00022 #include "core/alloc_func.hpp"
00023 #include "window_func.h"
00024 #include "viewport_func.h"
00025 #include "gfx_func.h"
00026 #include "widgets/dropdown_func.h"
00027 #include "newgrf_cargo.h"
00028 #include "map_func.h"
00029 #include "settings_type.h"
00030 #include "tile_map.h"
00031 #include "station_map.h"
00032 #include "tilehighlight_func.h"
00033 #include "core/smallvec_type.hpp"
00034 #include "core/smallmap_type.hpp"
00035 #include "string_func.h"
00036 #include "company_base.h"
00037 #include "sortlist_type.h"
00038
00039 #include "table/strings.h"
00040 #include "table/sprites.h"
00041
00056 static void StationsWndShowStationRating(int x, int y, CargoID type, uint amount, byte rating)
00057 {
00058 static const uint units_full = 576;
00059 static const uint rating_full = 224;
00060
00061 const CargoSpec *cs = GetCargo(type);
00062 if (!cs->IsValid()) return;
00063
00064 int colour = cs->rating_colour;
00065 uint w = (minu(amount, units_full) + 5) / 36;
00066
00067
00068 if (w != 0) GfxFillRect(x, y, x + w - 1, y + 6, colour);
00069
00070
00071
00072 if (w == 0) {
00073 uint rest = amount / 5;
00074 if (rest != 0) {
00075 w += x;
00076 GfxFillRect(w, y + 6 - rest, w, y + 6, colour);
00077 }
00078 }
00079
00080 DrawString(x + 1, y, cs->abbrev, TC_BLACK);
00081
00082
00083 y += 8;
00084 GfxFillRect(x + 1, y, x + 14, y, 0xB8);
00085 rating = minu(rating, rating_full) / 16;
00086 if (rating != 0) GfxFillRect(x + 1, y, x + rating, y, 0xD0);
00087 }
00088
00089 typedef GUIList<const Station*> GUIStationList;
00090
00094 class CompanyStationsWindow : public Window
00095 {
00096 protected:
00097
00098 static Listing last_sorting;
00099 static byte facilities;
00100 static bool include_empty;
00101 static const uint32 cargo_filter_max;
00102 static uint32 cargo_filter;
00103 static const Station *last_station;
00104
00105
00106 static const StringID sorter_names[];
00107 static GUIStationList::SortFunction *const sorter_funcs[];
00108
00109 GUIStationList stations;
00110
00111
00117 void BuildStationsList(const Owner owner)
00118 {
00119 if (!this->stations.NeedRebuild()) return;
00120
00121 DEBUG(misc, 3, "Building station list for company %d", owner);
00122
00123 this->stations.Clear();
00124
00125 const Station *st;
00126 FOR_ALL_STATIONS(st) {
00127 if (st->owner == owner || (st->owner == OWNER_NONE && !st->IsBuoy() && HasStationInUse(st->index, owner))) {
00128 if (this->facilities & st->facilities) {
00129 int num_waiting_cargo = 0;
00130 for (CargoID j = 0; j < NUM_CARGO; j++) {
00131 if (!st->goods[j].cargo.Empty()) {
00132 num_waiting_cargo++;
00133 if (HasBit(this->cargo_filter, j)) {
00134 *this->stations.Append() = st;
00135 break;
00136 }
00137 }
00138 }
00139
00140 if (num_waiting_cargo == 0 && this->include_empty) {
00141 *this->stations.Append() = st;
00142 }
00143 }
00144 }
00145 }
00146
00147 this->stations.Compact();
00148 this->stations.RebuildDone();
00149 }
00150
00152 static int CDECL StationNameSorter(const Station* const *a, const Station* const *b)
00153 {
00154 static char buf_cache[64];
00155 char buf[64];
00156
00157 SetDParam(0, (*a)->index);
00158 GetString(buf, STR_STATION, lastof(buf));
00159
00160 if (*b != last_station) {
00161 last_station = *b;
00162 SetDParam(0, (*b)->index);
00163 GetString(buf_cache, STR_STATION, lastof(buf_cache));
00164 }
00165
00166 return strcmp(buf, buf_cache);
00167 }
00168
00170 static int CDECL StationTypeSorter(const Station* const *a, const Station* const *b)
00171 {
00172 return (*a)->facilities - (*b)->facilities;
00173 }
00174
00176 static int CDECL StationWaitingSorter(const Station* const *a, const Station* const *b)
00177 {
00178 Money diff = 0;
00179
00180 for (CargoID j = 0; j < NUM_CARGO; j++) {
00181 if (!HasBit(cargo_filter, j)) continue;
00182 if (!(*a)->goods[j].cargo.Empty()) diff += GetTransportedGoodsIncome((*a)->goods[j].cargo.Count(), 20, 50, j);
00183 if (!(*b)->goods[j].cargo.Empty()) diff -= GetTransportedGoodsIncome((*b)->goods[j].cargo.Count(), 20, 50, j);
00184 }
00185
00186 return ClampToI32(diff);
00187 }
00188
00190 static int CDECL StationRatingMaxSorter(const Station* const *a, const Station* const *b)
00191 {
00192 byte maxr1 = 0;
00193 byte maxr2 = 0;
00194
00195 for (CargoID j = 0; j < NUM_CARGO; j++) {
00196 if (HasBit((*a)->goods[j].acceptance_pickup, GoodsEntry::PICKUP)) maxr1 = max(maxr1, (*a)->goods[j].rating);
00197 if (HasBit((*b)->goods[j].acceptance_pickup, GoodsEntry::PICKUP)) maxr2 = max(maxr2, (*b)->goods[j].rating);
00198 }
00199
00200 return maxr1 - maxr2;
00201 }
00202
00204 void SortStationsList()
00205 {
00206 if (!this->stations.Sort()) return;
00207
00208
00209 this->last_station = NULL;
00210
00211
00212 this->InvalidateWidget(SLW_LIST);
00213 }
00214
00215 public:
00216 CompanyStationsWindow(const WindowDesc *desc, WindowNumber window_number) : Window(desc, window_number)
00217 {
00218 this->caption_color = (byte)this->window_number;
00219 this->vscroll.cap = 12;
00220 this->resize.step_height = 10;
00221 this->resize.height = this->height - 10 * 7;
00222
00223
00224 uint num_active = 0;
00225 for (CargoID c = 0; c < NUM_CARGO; c++) {
00226 if (GetCargo(c)->IsValid()) num_active++;
00227 }
00228
00229 this->widget_count += num_active;
00230 this->widget = ReallocT(this->widget, this->widget_count + 1);
00231 this->widget[this->widget_count].type = WWT_LAST;
00232
00233 uint i = 0;
00234 for (CargoID c = 0; c < NUM_CARGO; c++) {
00235 if (!GetCargo(c)->IsValid()) continue;
00236
00237 Widget *wi = &this->widget[SLW_CARGOSTART + i];
00238 wi->type = WWT_PANEL;
00239 wi->display_flags = RESIZE_NONE;
00240 wi->color = COLOUR_GREY;
00241 wi->left = 89 + i * 14;
00242 wi->right = wi->left + 13;
00243 wi->top = 14;
00244 wi->bottom = 24;
00245 wi->data = 0;
00246 wi->tooltips = STR_USE_CTRL_TO_SELECT_MORE;
00247
00248 if (HasBit(this->cargo_filter, c)) this->LowerWidget(SLW_CARGOSTART + i);
00249 i++;
00250 }
00251
00252 this->widget[SLW_NOCARGOWAITING].left += num_active * 14;
00253 this->widget[SLW_NOCARGOWAITING].right += num_active * 14;
00254 this->widget[SLW_CARGOALL].left += num_active * 14;
00255 this->widget[SLW_CARGOALL].right += num_active * 14;
00256 this->widget[SLW_PAN_RIGHT].left += num_active * 14;
00257
00258 if (num_active > 15) {
00259
00260 ResizeWindow(this, (num_active - 15) * 14, 0);
00261 this->resize.width = this->width;
00262 }
00263
00264 if (this->cargo_filter == this->cargo_filter_max) this->cargo_filter = _cargo_mask;
00265
00266 for (uint i = 0; i < 5; i++) {
00267 if (HasBit(this->facilities, i)) this->LowerWidget(i + SLW_TRAIN);
00268 }
00269 this->SetWidgetLoweredState(SLW_FACILALL, this->facilities == (FACIL_TRAIN | FACIL_TRUCK_STOP | FACIL_BUS_STOP | FACIL_AIRPORT | FACIL_DOCK));
00270 this->SetWidgetLoweredState(SLW_CARGOALL, this->cargo_filter == _cargo_mask && this->include_empty);
00271 this->SetWidgetLoweredState(SLW_NOCARGOWAITING, this->include_empty);
00272
00273 this->stations.SetListing(this->last_sorting);
00274 this->stations.SetSortFuncs(this->sorter_funcs);
00275 this->stations.ForceRebuild();
00276 this->stations.NeedResort();
00277 this->SortStationsList();
00278
00279 this->widget[SLW_SORTDROPBTN].data = this->sorter_names[this->stations.SortType()];
00280
00281 this->FindWindowPlacementAndResize(desc);
00282 }
00283
00284 ~CompanyStationsWindow()
00285 {
00286 this->last_sorting = this->stations.GetListing();
00287 }
00288
00289 virtual void OnPaint()
00290 {
00291 const Owner owner = (Owner)this->window_number;
00292
00293 this->BuildStationsList(owner);
00294 this->SortStationsList();
00295
00296 SetVScrollCount(this, this->stations.Length());
00297
00298
00299 SetDParam(0, owner);
00300 SetDParam(1, this->vscroll.count);
00301
00302 this->DrawWidgets();
00303
00304
00305 this->DrawSortButtonState(SLW_SORTBY, this->stations.IsDescSortOrder() ? SBS_DOWN : SBS_UP);
00306
00307 int cg_ofst;
00308 int x = 89;
00309 int y = 14;
00310 int xb = 2;
00311
00312 uint i = 0;
00313 for (CargoID c = 0; c < NUM_CARGO; c++) {
00314 const CargoSpec *cs = GetCargo(c);
00315 if (!cs->IsValid()) continue;
00316
00317 cg_ofst = HasBit(this->cargo_filter, c) ? 2 : 1;
00318 GfxFillRect(x + cg_ofst, y + cg_ofst, x + cg_ofst + 10 , y + cg_ofst + 7, cs->rating_colour);
00319 DrawStringCentered(x + 6 + cg_ofst, y + cg_ofst, cs->abbrev, TC_BLACK);
00320 x += 14;
00321 i++;
00322 }
00323
00324 x += 6;
00325 cg_ofst = this->IsWidgetLowered(SLW_NOCARGOWAITING) ? 2 : 1;
00326 DrawStringCentered(x + cg_ofst, y + cg_ofst, STR_ABBREV_NONE, TC_BLACK);
00327 x += 14;
00328 cg_ofst = this->IsWidgetLowered(SLW_CARGOALL) ? 2 : 1;
00329 DrawStringCentered(x + cg_ofst, y + cg_ofst, STR_ABBREV_ALL, TC_BLACK);
00330
00331 cg_ofst = this->IsWidgetLowered(SLW_FACILALL) ? 2 : 1;
00332 DrawString(71 + cg_ofst, y + cg_ofst, STR_ABBREV_ALL, TC_BLACK);
00333
00334 if (this->vscroll.count == 0) {
00335 DrawString(xb, 40, STR_304A_NONE, TC_FROMSTRING);
00336 return;
00337 }
00338
00339 int max = min(this->vscroll.pos + this->vscroll.cap, this->stations.Length());
00340 y = 40;
00341
00342 for (int i = this->vscroll.pos; i < max; ++i) {
00343 const Station *st = this->stations[i];
00344 int x;
00345
00346 assert(st->xy != INVALID_TILE);
00347
00348
00349
00350 assert(st->owner == owner || (st->owner == OWNER_NONE && !st->IsBuoy()));
00351
00352 SetDParam(0, st->index);
00353 SetDParam(1, st->facilities);
00354 x = DrawString(xb, y, STR_3049_0, TC_FROMSTRING) + 5;
00355
00356
00357 for (CargoID j = 0; j < NUM_CARGO; j++) {
00358 if (!st->goods[j].cargo.Empty()) {
00359 StationsWndShowStationRating(x, y, j, st->goods[j].cargo.Count(), st->goods[j].rating);
00360 x += 20;
00361 }
00362 }
00363 y += 10;
00364 }
00365 }
00366
00367 virtual void OnClick(Point pt, int widget)
00368 {
00369 switch (widget) {
00370 case SLW_LIST: {
00371 uint32 id_v = (pt.y - 41) / 10;
00372
00373 if (id_v >= this->vscroll.cap) return;
00374
00375 id_v += this->vscroll.pos;
00376
00377 if (id_v >= this->stations.Length()) return;
00378
00379 const Station *st = this->stations[id_v];
00380
00381 assert(st->owner == (Owner)this->window_number || (st->owner == OWNER_NONE && !st->IsBuoy()));
00382
00383 if (_ctrl_pressed) {
00384 ShowExtraViewPortWindow(st->xy);
00385 } else {
00386 ScrollMainWindowToTile(st->xy);
00387 }
00388 break;
00389 }
00390
00391 case SLW_TRAIN:
00392 case SLW_TRUCK:
00393 case SLW_BUS:
00394 case SLW_AIRPLANE:
00395 case SLW_SHIP:
00396 if (_ctrl_pressed) {
00397 ToggleBit(this->facilities, widget - SLW_TRAIN);
00398 this->ToggleWidgetLoweredState(widget);
00399 } else {
00400 uint i;
00401 FOR_EACH_SET_BIT(i, this->facilities) {
00402 this->RaiseWidget(i + SLW_TRAIN);
00403 }
00404 SetBit(this->facilities, widget - SLW_TRAIN);
00405 this->LowerWidget(widget);
00406 }
00407 this->SetWidgetLoweredState(SLW_FACILALL, this->facilities == (FACIL_TRAIN | FACIL_TRUCK_STOP | FACIL_BUS_STOP | FACIL_AIRPORT | FACIL_DOCK));
00408 this->stations.ForceRebuild();
00409 this->SetDirty();
00410 break;
00411
00412 case SLW_FACILALL:
00413 for (uint i = 0; i < 5; i++) {
00414 this->LowerWidget(i + SLW_TRAIN);
00415 }
00416 this->LowerWidget(SLW_FACILALL);
00417
00418 this->facilities = FACIL_TRAIN | FACIL_TRUCK_STOP | FACIL_BUS_STOP | FACIL_AIRPORT | FACIL_DOCK;
00419 this->stations.ForceRebuild();
00420 this->SetDirty();
00421 break;
00422
00423 case SLW_CARGOALL: {
00424 uint i = 0;
00425 for (CargoID c = 0; c < NUM_CARGO; c++) {
00426 if (!GetCargo(c)->IsValid()) continue;
00427 this->LowerWidget(i + SLW_CARGOSTART);
00428 i++;
00429 }
00430 this->LowerWidget(SLW_NOCARGOWAITING);
00431 this->LowerWidget(SLW_CARGOALL);
00432
00433 this->cargo_filter = _cargo_mask;
00434 this->include_empty = true;
00435 this->stations.ForceRebuild();
00436 this->SetDirty();
00437 break;
00438 }
00439
00440 case SLW_SORTBY:
00441 this->stations.ToggleSortOrder();
00442 this->flags4 |= WF_TIMEOUT_BEGIN;
00443 this->LowerWidget(SLW_SORTBY);
00444 this->SetDirty();
00445 break;
00446
00447 case SLW_SORTDROPBTN:
00448 ShowDropDownMenu(this, this->sorter_names, this->stations.SortType(), SLW_SORTDROPBTN, 0, 0);
00449 break;
00450
00451 case SLW_NOCARGOWAITING:
00452 if (_ctrl_pressed) {
00453 this->include_empty = !this->include_empty;
00454 this->ToggleWidgetLoweredState(SLW_NOCARGOWAITING);
00455 } else {
00456 for (uint i = SLW_CARGOSTART; i < this->widget_count; i++) {
00457 this->RaiseWidget(i);
00458 }
00459
00460 this->cargo_filter = 0;
00461 this->include_empty = true;
00462
00463 this->LowerWidget(SLW_NOCARGOWAITING);
00464 }
00465 this->SetWidgetLoweredState(SLW_CARGOALL, this->cargo_filter == _cargo_mask && this->include_empty);
00466 this->stations.ForceRebuild();
00467 this->SetDirty();
00468 break;
00469
00470 default:
00471 if (widget >= SLW_CARGOSTART) {
00472
00473 CargoID c;
00474 int i = 0;
00475 for (c = 0; c < NUM_CARGO; c++) {
00476 if (!GetCargo(c)->IsValid()) continue;
00477 if (widget - SLW_CARGOSTART == i) break;
00478 i++;
00479 }
00480
00481 if (_ctrl_pressed) {
00482 ToggleBit(this->cargo_filter, c);
00483 this->ToggleWidgetLoweredState(widget);
00484 } else {
00485 for (uint i = SLW_CARGOSTART; i < this->widget_count; i++) {
00486 this->RaiseWidget(i);
00487 }
00488 this->RaiseWidget(SLW_NOCARGOWAITING);
00489
00490 this->cargo_filter = 0;
00491 this->include_empty = false;
00492
00493 SetBit(this->cargo_filter, c);
00494 this->LowerWidget(widget);
00495 }
00496 this->SetWidgetLoweredState(SLW_CARGOALL, this->cargo_filter == _cargo_mask && this->include_empty);
00497 this->stations.ForceRebuild();
00498 this->SetDirty();
00499 }
00500 break;
00501 }
00502 }
00503
00504 virtual void OnDropdownSelect(int widget, int index)
00505 {
00506 if (this->stations.SortType() != index) {
00507 this->stations.SetSortType(index);
00508
00509
00510 this->widget[SLW_SORTDROPBTN].data = this->sorter_names[this->stations.SortType()];
00511
00512 this->SetDirty();
00513 }
00514 }
00515
00516 virtual void OnTick()
00517 {
00518 if (_pause_game != 0) return;
00519 if (this->stations.NeedResort()) {
00520 DEBUG(misc, 3, "Periodic rebuild station list company %d", this->window_number);
00521 this->SetDirty();
00522 }
00523 }
00524
00525 virtual void OnTimeout()
00526 {
00527 this->RaiseWidget(SLW_SORTBY);
00528 this->SetDirty();
00529 }
00530
00531 virtual void OnResize(Point new_size, Point delta)
00532 {
00533 this->vscroll.cap += delta.y / 10;
00534 }
00535
00536 virtual void OnInvalidateData(int data)
00537 {
00538 if (data == 0) {
00539 this->stations.ForceRebuild();
00540 } else {
00541 this->stations.ForceResort();
00542 }
00543 }
00544 };
00545
00546 Listing CompanyStationsWindow::last_sorting = {false, 0};
00547 byte CompanyStationsWindow::facilities = FACIL_TRAIN | FACIL_TRUCK_STOP | FACIL_BUS_STOP | FACIL_AIRPORT | FACIL_DOCK;
00548 bool CompanyStationsWindow::include_empty = true;
00549 const uint32 CompanyStationsWindow::cargo_filter_max = UINT32_MAX;
00550 uint32 CompanyStationsWindow::cargo_filter = UINT32_MAX;
00551 const Station *CompanyStationsWindow::last_station = NULL;
00552
00553
00554 GUIStationList::SortFunction *const CompanyStationsWindow::sorter_funcs[] = {
00555 &StationNameSorter,
00556 &StationTypeSorter,
00557 &StationWaitingSorter,
00558 &StationRatingMaxSorter
00559 };
00560
00561
00562 const StringID CompanyStationsWindow::sorter_names[] = {
00563 STR_SORT_BY_DROPDOWN_NAME,
00564 STR_SORT_BY_FACILITY,
00565 STR_SORT_BY_WAITING,
00566 STR_SORT_BY_RATING_MAX,
00567 INVALID_STRING_ID
00568 };
00569
00570
00571 static const Widget _company_stations_widgets[] = {
00572 { WWT_CLOSEBOX, RESIZE_NONE, COLOUR_GREY, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW},
00573 { WWT_CAPTION, RESIZE_RIGHT, COLOUR_GREY, 11, 345, 0, 13, STR_3048_STATIONS, STR_018C_WINDOW_TITLE_DRAG_THIS},
00574 { WWT_STICKYBOX, RESIZE_LR, COLOUR_GREY, 346, 357, 0, 13, 0x0, STR_STICKY_BUTTON},
00575 { WWT_PANEL, RESIZE_RB, COLOUR_GREY, 0, 345, 37, 161, 0x0, STR_3057_STATION_NAMES_CLICK_ON},
00576 { WWT_SCROLLBAR, RESIZE_LRB, COLOUR_GREY, 346, 357, 37, 149, 0x0, STR_0190_SCROLL_BAR_SCROLLS_LIST},
00577 { WWT_RESIZEBOX, RESIZE_LRTB, COLOUR_GREY, 346, 357, 150, 161, 0x0, STR_RESIZE_BUTTON},
00578
00579 { WWT_TEXTBTN, RESIZE_NONE, COLOUR_GREY, 0, 13, 14, 24, STR_TRAIN, STR_USE_CTRL_TO_SELECT_MORE},
00580 { WWT_TEXTBTN, RESIZE_NONE, COLOUR_GREY, 14, 27, 14, 24, STR_LORRY, STR_USE_CTRL_TO_SELECT_MORE},
00581 { WWT_TEXTBTN, RESIZE_NONE, COLOUR_GREY, 28, 41, 14, 24, STR_BUS, STR_USE_CTRL_TO_SELECT_MORE},
00582 { WWT_TEXTBTN, RESIZE_NONE, COLOUR_GREY, 42, 55, 14, 24, STR_PLANE, STR_USE_CTRL_TO_SELECT_MORE},
00583 { WWT_TEXTBTN, RESIZE_NONE, COLOUR_GREY, 56, 69, 14, 24, STR_SHIP, STR_USE_CTRL_TO_SELECT_MORE},
00584 { WWT_PANEL, RESIZE_NONE, COLOUR_GREY, 70, 83, 14, 24, 0x0, STR_SELECT_ALL_FACILITIES},
00585
00586 { WWT_PANEL, RESIZE_NONE, COLOUR_GREY, 83, 88, 14, 24, 0x0, STR_NULL},
00587 { WWT_PANEL, RESIZE_NONE, COLOUR_GREY, 89, 102, 14, 24, 0x0, STR_NO_WAITING_CARGO},
00588 { WWT_PANEL, RESIZE_NONE, COLOUR_GREY, 103, 116, 14, 24, 0x0, STR_SELECT_ALL_TYPES},
00589 { WWT_PANEL, RESIZE_RIGHT, COLOUR_GREY, 117, 357, 14, 24, 0x0, STR_NULL},
00590
00591 { WWT_TEXTBTN, RESIZE_NONE, COLOUR_GREY, 0, 80, 25, 36, STR_SORT_BY, STR_SORT_ORDER_TIP},
00592 { WWT_DROPDOWN, RESIZE_NONE, COLOUR_GREY, 81, 243, 25, 36, 0x0, STR_SORT_CRITERIA_TIP},
00593 { WWT_PANEL, RESIZE_RIGHT, COLOUR_GREY, 244, 357, 25, 36, 0x0, STR_NULL},
00594 { WIDGETS_END},
00595 };
00596
00597 static const WindowDesc _company_stations_desc = {
00598 WDP_AUTO, WDP_AUTO, 358, 162, 358, 162,
00599 WC_STATION_LIST, WC_NONE,
00600 WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_STICKY_BUTTON | WDF_RESIZABLE,
00601 _company_stations_widgets,
00602 };
00603
00609 void ShowCompanyStations(CompanyID company)
00610 {
00611 if (!IsValidCompanyID(company)) return;
00612
00613 AllocateWindowDescFront<CompanyStationsWindow>(&_company_stations_desc, company);
00614 }
00615
00616 static const Widget _station_view_widgets[] = {
00617 { WWT_CLOSEBOX, RESIZE_NONE, COLOUR_GREY, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW},
00618 { WWT_CAPTION, RESIZE_RIGHT, COLOUR_GREY, 11, 236, 0, 13, STR_300A_0, STR_018C_WINDOW_TITLE_DRAG_THIS},
00619 { WWT_STICKYBOX, RESIZE_LR, COLOUR_GREY, 237, 248, 0, 13, 0x0, STR_STICKY_BUTTON},
00620 { WWT_PANEL, RESIZE_RB, COLOUR_GREY, 0, 236, 14, 65, 0x0, STR_NULL},
00621 { WWT_SCROLLBAR, RESIZE_LRB, COLOUR_GREY, 237, 248, 14, 65, 0x0, STR_0190_SCROLL_BAR_SCROLLS_LIST},
00622 { WWT_PANEL, RESIZE_RTB, COLOUR_GREY, 0, 248, 66, 97, 0x0, STR_NULL},
00623 { WWT_PUSHTXTBTN, RESIZE_TB, COLOUR_GREY, 0, 59, 98, 109, STR_00E4_LOCATION, STR_3053_CENTER_MAIN_VIEW_ON_STATION},
00624 { WWT_PUSHTXTBTN, RESIZE_TB, COLOUR_GREY, 60, 120, 98, 109, STR_3032_RATINGS, STR_3054_SHOW_STATION_RATINGS},
00625 { WWT_PUSHTXTBTN, RESIZE_RTB, COLOUR_GREY, 121, 180, 98, 109, STR_0130_RENAME, STR_3055_CHANGE_NAME_OF_STATION},
00626 { WWT_PUSHTXTBTN, RESIZE_LRTB, COLOUR_GREY, 181, 194, 98, 109, STR_TRAIN, STR_SCHEDULED_TRAINS_TIP },
00627 { WWT_PUSHTXTBTN, RESIZE_LRTB, COLOUR_GREY, 195, 208, 98, 109, STR_LORRY, STR_SCHEDULED_ROAD_VEHICLES_TIP },
00628 { WWT_PUSHTXTBTN, RESIZE_LRTB, COLOUR_GREY, 209, 222, 98, 109, STR_PLANE, STR_SCHEDULED_AIRCRAFT_TIP },
00629 { WWT_PUSHTXTBTN, RESIZE_LRTB, COLOUR_GREY, 223, 236, 98, 109, STR_SHIP, STR_SCHEDULED_SHIPS_TIP },
00630 { WWT_RESIZEBOX, RESIZE_LRTB, COLOUR_GREY, 237, 248, 98, 109, 0x0, STR_RESIZE_BUTTON},
00631 { WIDGETS_END},
00632 };
00633
00634 SpriteID GetCargoSprite(CargoID i)
00635 {
00636 const CargoSpec *cs = GetCargo(i);
00637 SpriteID sprite;
00638
00639 if (cs->sprite == 0xFFFF) {
00640
00641 sprite = GetCustomCargoSprite(cs);
00642 } else {
00643 sprite = cs->sprite;
00644 }
00645
00646 if (sprite == 0) sprite = SPR_CARGO_GOODS;
00647
00648 return sprite;
00649 }
00650
00659 static void DrawCargoIcons(CargoID i, uint waiting, int x, int y, uint width)
00660 {
00661 uint num = min((waiting + 5) / 10, width / 10);
00662 if (num == 0) return;
00663
00664 SpriteID sprite = GetCargoSprite(i);
00665
00666 do {
00667 DrawSprite(sprite, PAL_NONE, x, y);
00668 x += 10;
00669 } while (--num);
00670 }
00671
00672 struct CargoData {
00673 CargoID cargo;
00674 StationID source;
00675 uint count;
00676
00677 CargoData(CargoID cargo, StationID source, uint count) :
00678 cargo(cargo),
00679 source(source),
00680 count(count)
00681 { }
00682 };
00683
00684 typedef std::list<CargoData> CargoDataList;
00685
00689 struct StationViewWindow : public Window {
00690 uint32 cargo;
00691 uint16 cargo_rows[NUM_CARGO];
00692
00693 StationViewWindow(const WindowDesc *desc, WindowNumber window_number) : Window(desc, window_number)
00694 {
00695 Owner owner = GetStation(window_number)->owner;
00696 if (owner != OWNER_NONE) this->caption_color = owner;
00697 this->vscroll.cap = 5;
00698 this->resize.step_height = 10;
00699
00700 this->FindWindowPlacementAndResize(desc);
00701 }
00702
00703 ~StationViewWindow()
00704 {
00705 WindowNumber wno =
00706 (this->window_number << 16) | VLW_STATION_LIST | GetStation(this->window_number)->owner;
00707
00708 DeleteWindowById(WC_TRAINS_LIST, wno | (VEH_TRAIN << 11), false);
00709 DeleteWindowById(WC_ROADVEH_LIST, wno | (VEH_ROAD << 11), false);
00710 DeleteWindowById(WC_SHIPS_LIST, wno | (VEH_SHIP << 11), false);
00711 DeleteWindowById(WC_AIRCRAFT_LIST, wno | (VEH_AIRCRAFT << 11), false);
00712 }
00713
00714 virtual void OnPaint()
00715 {
00716 StationID station_id = this->window_number;
00717 const Station *st = GetStation(station_id);
00718 CargoDataList cargolist;
00719 uint32 transfers = 0;
00720
00721
00722 for (CargoID i = 0; i < NUM_CARGO; i++) {
00723 if (st->goods[i].cargo.Empty()) {
00724 this->cargo_rows[i] = 0;
00725 } else {
00726
00727 cargolist.push_back(CargoData(i, INVALID_STATION, st->goods[i].cargo.Count()));
00728
00729
00730 this->cargo_rows[i] = (uint16)cargolist.size();
00731
00732
00733 const CargoList::List *packets = st->goods[i].cargo.Packets();
00734 for (CargoList::List::const_iterator it = packets->begin(); it != packets->end(); it++) {
00735 const CargoPacket *cp = *it;
00736 if (cp->source != station_id) {
00737 bool added = false;
00738
00739
00740 SetBit(transfers, i);
00741
00742
00743 if (!HasBit(this->cargo, i)) break;
00744
00745
00746 for (CargoDataList::iterator jt = cargolist.begin(); jt != cargolist.end(); jt++) {
00747 CargoData *cd = &(*jt);
00748 if (cd->cargo == i && cd->source == cp->source) {
00749 cd->count += cp->count;
00750 added = true;
00751 break;
00752 }
00753 }
00754
00755 if (!added) cargolist.push_back(CargoData(i, cp->source, cp->count));
00756 }
00757 }
00758 }
00759 }
00760 SetVScrollCount(this, (int)cargolist.size() + 1);
00761
00762
00763 this->SetWidgetDisabledState(SVW_RENAME, st->owner != _local_company);
00764 this->SetWidgetDisabledState(SVW_TRAINS, !(st->facilities & FACIL_TRAIN));
00765 this->SetWidgetDisabledState(SVW_ROADVEHS, !(st->facilities & FACIL_TRUCK_STOP) && !(st->facilities & FACIL_BUS_STOP));
00766 this->SetWidgetDisabledState(SVW_PLANES, !(st->facilities & FACIL_AIRPORT));
00767 this->SetWidgetDisabledState(SVW_SHIPS, !(st->facilities & FACIL_DOCK));
00768
00769 SetDParam(0, st->index);
00770 SetDParam(1, st->facilities);
00771 this->DrawWidgets();
00772
00773 int x = 2;
00774 int y = 15;
00775 int pos = this->vscroll.pos;
00776
00777 uint width = this->widget[SVW_WAITING].right - this->widget[SVW_WAITING].left - 4;
00778 int maxrows = this->vscroll.cap;
00779
00780 StringID str;
00781
00782 if (--pos < 0) {
00783 str = STR_00D0_NOTHING;
00784 for (CargoID i = 0; i < NUM_CARGO; i++) {
00785 if (!st->goods[i].cargo.Empty()) str = STR_EMPTY;
00786 }
00787 SetDParam(0, str);
00788 DrawString(x, y, STR_0008_WAITING, TC_FROMSTRING);
00789 y += 10;
00790 }
00791
00792 for (CargoDataList::const_iterator it = cargolist.begin(); it != cargolist.end() && pos > -maxrows; ++it) {
00793 if (--pos < 0) {
00794 const CargoData *cd = &(*it);
00795 if (cd->source == INVALID_STATION) {
00796
00797 DrawCargoIcons(cd->cargo, cd->count, x, y, width);
00798 SetDParam(0, cd->cargo);
00799 SetDParam(1, cd->count);
00800 if (HasBit(transfers, cd->cargo)) {
00801
00802 const char *sym = HasBit(this->cargo, cd->cargo) ? "-" : "+";
00803 DrawStringRightAligned(x + width - 8, y, STR_0009, TC_FROMSTRING);
00804 DoDrawString(sym, x + width - 6, y, TC_YELLOW);
00805 } else {
00806 DrawStringRightAligned(x + width, y, STR_0009, TC_FROMSTRING);
00807 }
00808 } else {
00809 SetDParam(0, cd->cargo);
00810 SetDParam(1, cd->count);
00811 SetDParam(2, cd->source);
00812 DrawStringRightAlignedTruncated(x + width, y, STR_EN_ROUTE_FROM, TC_FROMSTRING, width);
00813 }
00814
00815 y += 10;
00816 }
00817 }
00818
00819 if (this->widget[SVW_ACCEPTS].data == STR_3032_RATINGS) {
00820 char string[512];
00821 char *b = string;
00822 bool first = true;
00823
00824 b = InlineString(b, STR_000C_ACCEPTS);
00825
00826 for (CargoID i = 0; i < NUM_CARGO; i++) {
00827 if (b >= lastof(string) - (1 + 2 * 4)) break;
00828 if (HasBit(st->goods[i].acceptance_pickup, GoodsEntry::ACCEPTANCE)) {
00829 if (first) {
00830 first = false;
00831 } else {
00832
00833 *b++ = ',';
00834 *b++ = ' ';
00835 }
00836 b = InlineString(b, GetCargo(i)->name);
00837 }
00838 }
00839
00840
00841 if (first) b = InlineString(b, STR_00D0_NOTHING);
00842
00843 *b = '\0';
00844
00845
00846 assert(b < endof(string));
00847
00848 SetDParamStr(0, string);
00849 DrawStringMultiLine(2, this->widget[SVW_ACCEPTLIST].top + 1, STR_JUST_RAW_STRING, this->widget[SVW_ACCEPTLIST].right - this->widget[SVW_ACCEPTLIST].left);
00850 } else {
00851 y = this->widget[SVW_RATINGLIST].top + 1;
00852
00853 DrawString(2, y, STR_3034_LOCAL_RATING_OF_TRANSPORT, TC_FROMSTRING);
00854 y += 10;
00855
00856 for (CargoID i = 0; i < NUM_CARGO; i++) {
00857 const CargoSpec *cs = GetCargo(i);
00858 if (!cs->IsValid())