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 "command_func.h"
00012 #include "viewport_func.h"
00013 #include "gfx_func.h"
00014 #include "industry.h"
00015 #include "town.h"
00016 #include "variables.h"
00017 #include "cheat_func.h"
00018 #include "cargotype.h"
00019 #include "newgrf.h"
00020 #include "newgrf_callbacks.h"
00021 #include "newgrf_industries.h"
00022 #include "newgrf_text.h"
00023 #include "strings_func.h"
00024 #include "map_func.h"
00025 #include "company_func.h"
00026 #include "settings_type.h"
00027 #include "tilehighlight_func.h"
00028 #include "string_func.h"
00029 #include "sortlist_type.h"
00030 #include "widgets/dropdown_func.h"
00031 #include "company_base.h"
00032
00033 #include "table/strings.h"
00034 #include "table/sprites.h"
00035
00036 bool _ignore_restrictions;
00037
00038 enum CargoSuffixType {
00039 CST_FUND,
00040 CST_VIEW,
00041 CST_DIR,
00042 };
00043
00058 static StringID GetCargoSuffix(uint cargo, CargoSuffixType cst, Industry *ind, IndustryType ind_type, const IndustrySpec *indspec)
00059 {
00060 if (HasBit(indspec->callback_flags, CBM_IND_CARGO_SUFFIX)) {
00061 uint16 callback = GetIndustryCallback(CBID_INDUSTRY_CARGO_SUFFIX, 0, (cst << 8) | cargo, ind, ind_type, (cst != CST_FUND) ? ind->xy : INVALID_TILE);
00062 if (GB(callback, 0, 8) != 0xFF) return GetGRFStringID(indspec->grf_prop.grffile->grfid, 0xD000 + callback);
00063 }
00064 return STR_EMPTY;
00065 }
00066
00068 enum DynamicPlaceIndustriesWidgets {
00069 DPIW_CLOSEBOX = 0,
00070 DPIW_CAPTION,
00071 DPIW_MATRIX_WIDGET,
00072 DPIW_SCROLLBAR,
00073 DPIW_INFOPANEL,
00074 DPIW_FUND_WIDGET,
00075 DPIW_RESIZE_WIDGET,
00076 };
00077
00079 static const Widget _build_industry_widgets[] = {
00080 { WWT_CLOSEBOX, RESIZE_NONE, COLOUR_DARK_GREEN, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW},
00081 { WWT_CAPTION, RESIZE_RIGHT, COLOUR_DARK_GREEN, 11, 169, 0, 13, STR_0314_FUND_NEW_INDUSTRY, STR_018C_WINDOW_TITLE_DRAG_THIS},
00082 { WWT_MATRIX, RESIZE_RB, COLOUR_DARK_GREEN, 0, 157, 14, 118, 0x801, STR_INDUSTRY_SELECTION_HINT},
00083 { WWT_SCROLLBAR, RESIZE_LRB, COLOUR_DARK_GREEN, 158, 169, 14, 118, 0x0, STR_0190_SCROLL_BAR_SCROLLS_LIST},
00084 { WWT_PANEL, RESIZE_RTB, COLOUR_DARK_GREEN, 0, 169, 119, 199, 0x0, STR_NULL},
00085 { WWT_TEXTBTN, RESIZE_RTB, COLOUR_DARK_GREEN, 0, 157, 200, 211, STR_FUND_NEW_INDUSTRY, STR_NULL},
00086 { WWT_RESIZEBOX, RESIZE_LRTB, COLOUR_DARK_GREEN, 158, 169, 200, 211, 0x0, STR_RESIZE_BUTTON},
00087 { WIDGETS_END},
00088 };
00089
00091 static const WindowDesc _build_industry_desc = {
00092 WDP_AUTO, WDP_AUTO, 170, 212, 170, 212,
00093 WC_BUILD_INDUSTRY, WC_NONE,
00094 WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_RESIZABLE,
00095 _build_industry_widgets,
00096 };
00097
00098 class BuildIndustryWindow : public Window {
00099 int selected_index;
00100 IndustryType selected_type;
00101 uint16 callback_timer;
00102 bool timer_enabled;
00103 uint16 count;
00104 IndustryType index[NUM_INDUSTRYTYPES + 1];
00105 StringID text[NUM_INDUSTRYTYPES + 1];
00106 bool enabled[NUM_INDUSTRYTYPES + 1];
00107
00108 void SetupArrays()
00109 {
00110 IndustryType ind;
00111 const IndustrySpec *indsp;
00112
00113 this->count = 0;
00114
00115 for (uint i = 0; i < lengthof(this->index); i++) {
00116 this->index[i] = INVALID_INDUSTRYTYPE;
00117 this->text[i] = STR_NULL;
00118 this->enabled[i] = false;
00119 }
00120
00121 if (_game_mode == GM_EDITOR) {
00122 this->index[this->count] = INVALID_INDUSTRYTYPE;
00123 this->count++;
00124 this->timer_enabled = false;
00125 }
00126
00127
00128
00129
00130 for (ind = 0; ind < NUM_INDUSTRYTYPES; ind++) {
00131 indsp = GetIndustrySpec(ind);
00132 if (indsp->enabled){
00133
00134
00135
00136 if (_game_mode != GM_EDITOR && indsp->IsRawIndustry() && _settings_game.construction.raw_industry_construction == 0) {
00137
00138 if (this->selected_type == ind) this->selected_index = -1;
00139 continue;
00140 }
00141 this->index[this->count] = ind;
00142 this->enabled[this->count] = (_game_mode == GM_EDITOR) || CheckIfCallBackAllowsAvailability(ind, IACT_USERCREATION);
00143
00144 if (this->selected_type == ind) this->selected_index = this->count;
00145 this->count++;
00146 }
00147 }
00148
00149
00150
00151 if (this->selected_index == -1) {
00152 this->selected_index = 0;
00153 this->selected_type = this->index[0];
00154 }
00155 }
00156
00157 public:
00158 BuildIndustryWindow() : Window(&_build_industry_desc)
00159 {
00160
00161
00162
00163 if (!_loaded_newgrf_features.has_newindustries) {
00164 this->widget[DPIW_INFOPANEL].bottom -= 44;
00165 this->widget[DPIW_FUND_WIDGET].bottom -= 44;
00166 this->widget[DPIW_FUND_WIDGET].top -= 44;
00167 this->widget[DPIW_RESIZE_WIDGET].bottom -= 44;
00168 this->widget[DPIW_RESIZE_WIDGET].top -= 44;
00169 this->resize.height = this->height -= 44;
00170 }
00171
00172 this->timer_enabled = _loaded_newgrf_features.has_newindustries;
00173
00174 this->vscroll.cap = 8;
00175 this->resize.step_height = 13;
00176
00177 this->selected_index = -1;
00178 this->selected_type = INVALID_INDUSTRYTYPE;
00179
00180
00181 this->SetupArrays();
00182
00183 this->callback_timer = DAY_TICKS;
00184
00185 this->FindWindowPlacementAndResize(&_build_industry_desc);
00186 }
00187
00188 virtual void OnPaint()
00189 {
00190 const IndustrySpec *indsp = (this->selected_type == INVALID_INDUSTRYTYPE) ? NULL : GetIndustrySpec(this->selected_type);
00191 int x_str = this->widget[DPIW_INFOPANEL].left + 3;
00192 int y_str = this->widget[DPIW_INFOPANEL].top + 3;
00193 const Widget *wi = &this->widget[DPIW_INFOPANEL];
00194 int max_width = wi->right - wi->left - 4;
00195
00196
00197
00198 if (_game_mode == GM_EDITOR) {
00199
00200 if (indsp == NULL) this->enabled[this->selected_index] = _settings_game.difficulty.number_industries != 0;
00201 this->widget[DPIW_FUND_WIDGET].data = STR_BUILD_NEW_INDUSTRY;
00202 } else {
00203 this->widget[DPIW_FUND_WIDGET].data = (_settings_game.construction.raw_industry_construction == 2 && indsp->IsRawIndustry()) ? STR_PROSPECT_NEW_INDUSTRY : STR_FUND_NEW_INDUSTRY;
00204 }
00205 this->SetWidgetDisabledState(DPIW_FUND_WIDGET, !this->enabled[this->selected_index]);
00206
00207 SetVScrollCount(this, this->count);
00208
00209 this->DrawWidgets();
00210
00211
00212 for (byte i = 0; i < this->vscroll.cap && ((i + this->vscroll.pos) < this->count); i++) {
00213 int offset = i * 13;
00214 int x = 3;
00215 int y = 16;
00216 bool selected = this->selected_index == i + this->vscroll.pos;
00217
00218 if (this->index[i + this->vscroll.pos] == INVALID_INDUSTRYTYPE) {
00219 DrawStringTruncated(20, y + offset, STR_MANY_RANDOM_INDUSTRIES, selected ? TC_WHITE : TC_ORANGE, max_width - 25);
00220 continue;
00221 }
00222 const IndustrySpec *indsp = GetIndustrySpec(this->index[i + this->vscroll.pos]);
00223
00224
00225 DrawStringTruncated(20, y + offset, indsp->name, selected ? TC_WHITE : TC_ORANGE, max_width - 25);
00226 GfxFillRect(x, y + 1 + offset, x + 10, y + 7 + offset, selected ? 15 : 0);
00227 GfxFillRect(x + 1, y + 2 + offset, x + 9, y + 6 + offset, indsp->map_colour);
00228 }
00229
00230 if (this->selected_type == INVALID_INDUSTRYTYPE) {
00231 DrawStringMultiLine(x_str, y_str, STR_RANDOM_INDUSTRIES_TIP, max_width, wi->bottom - wi->top - 40);
00232 return;
00233 }
00234
00235 if (_game_mode != GM_EDITOR) {
00236 SetDParam(0, indsp->GetConstructionCost());
00237 DrawStringTruncated(x_str, y_str, STR_482F_COST, TC_FROMSTRING, max_width);
00238 y_str += 11;
00239 }
00240
00241
00242 StringID str = STR_4827_REQUIRES;
00243 byte p = 0;
00244 SetDParam(0, STR_00D0_NOTHING);
00245 SetDParam(1, STR_EMPTY);
00246 for (byte j = 0; j < lengthof(indsp->accepts_cargo); j++) {
00247 if (indsp->accepts_cargo[j] == CT_INVALID) continue;
00248 if (p > 0) str++;
00249 SetDParam(p++, GetCargo(indsp->accepts_cargo[j])->name);
00250 SetDParam(p++, GetCargoSuffix(j, CST_FUND, NULL, this->selected_type, indsp));
00251 }
00252 DrawStringTruncated(x_str, y_str, str, TC_FROMSTRING, max_width);
00253 y_str += 11;
00254
00255
00256 str = STR_4827_PRODUCES;
00257 p = 0;
00258 SetDParam(0, STR_00D0_NOTHING);
00259 SetDParam(1, STR_EMPTY);
00260 for (byte j = 0; j < lengthof(indsp->produced_cargo); j++) {
00261 if (indsp->produced_cargo[j] == CT_INVALID) continue;
00262 if (p > 0) str++;
00263 SetDParam(p++, GetCargo(indsp->produced_cargo[j])->name);
00264 SetDParam(p++, GetCargoSuffix(j + 3, CST_FUND, NULL, this->selected_type, indsp));
00265 }
00266 DrawStringTruncated(x_str, y_str, str, TC_FROMSTRING, max_width);
00267 y_str += 11;
00268
00269
00270 if (this->text[this->selected_index] == STR_NULL) {
00271 if (HasBit(indsp->callback_flags, CBM_IND_FUND_MORE_TEXT)) {
00272 uint16 callback_res = GetIndustryCallback(CBID_INDUSTRY_FUND_MORE_TEXT, 0, 0, NULL, this->selected_type, INVALID_TILE);
00273 if (callback_res != CALLBACK_FAILED) {
00274 StringID newtxt = GetGRFStringID(indsp->grf_prop.grffile->grfid, 0xD000 + callback_res);
00275 this->text[this->selected_index] = newtxt;
00276 }
00277 }
00278 }
00279
00280
00281
00282 str = this->text[this->selected_index];
00283 if (str != STR_NULL && str != STR_UNDEFINED) {
00284 SetDParam(0, str);
00285 DrawStringMultiLine(x_str, y_str, STR_JUST_STRING, max_width, wi->bottom - wi->top - 40);
00286 }
00287 }
00288
00289 virtual void OnDoubleClick(Point pt, int widget)
00290 {
00291 if (widget != DPIW_MATRIX_WIDGET) return;
00292 this->OnClick(pt, DPIW_FUND_WIDGET);
00293 }
00294
00295 virtual void OnClick(Point pt, int widget)
00296 {
00297 switch (widget) {
00298 case DPIW_MATRIX_WIDGET: {
00299 const IndustrySpec *indsp;
00300 int y = (pt.y - this->widget[DPIW_MATRIX_WIDGET].top) / 13 + this->vscroll.pos ;
00301
00302 if (y >= 0 && y < count) {
00303 this->selected_index = y;
00304 this->selected_type = this->index[y];
00305 indsp = (this->selected_type == INVALID_INDUSTRYTYPE) ? NULL : GetIndustrySpec(this->selected_type);
00306
00307 this->SetDirty();
00308
00309 if ((_game_mode != GM_EDITOR && _settings_game.construction.raw_industry_construction == 2 && indsp != NULL && indsp->IsRawIndustry()) ||
00310 this->selected_type == INVALID_INDUSTRYTYPE) {
00311
00312 this->RaiseButtons();
00313 ResetObjectToPlace();
00314 }
00315 }
00316 } break;
00317
00318 case DPIW_FUND_WIDGET: {
00319 if (this->selected_type == INVALID_INDUSTRYTYPE) {
00320 this->HandleButtonClick(DPIW_FUND_WIDGET);
00321
00322 if (GetNumTowns() == 0) {
00323 ShowErrorMessage(STR_0286_MUST_BUILD_TOWN_FIRST, STR_CAN_T_GENERATE_INDUSTRIES, 0, 0);
00324 } else {
00325 extern void GenerateIndustries();
00326 _generating_world = true;
00327 GenerateIndustries();
00328 _generating_world = false;
00329 }
00330 } else if (_game_mode != GM_EDITOR && _settings_game.construction.raw_industry_construction == 2 && GetIndustrySpec(this->selected_type)->IsRawIndustry()) {
00331 DoCommandP(0, this->selected_type, InteractiveRandom(), NULL, CMD_BUILD_INDUSTRY | CMD_MSG(STR_4830_CAN_T_CONSTRUCT_THIS_INDUSTRY));
00332 this->HandleButtonClick(DPIW_FUND_WIDGET);
00333 } else {
00334 HandlePlacePushButton(this, DPIW_FUND_WIDGET, SPR_CURSOR_INDUSTRY, VHM_RECT, NULL);
00335 }
00336 } break;
00337 }
00338 }
00339
00340 virtual void OnResize(Point new_size, Point delta)
00341 {
00342
00343 this->vscroll.cap += delta.y / (int)this->resize.step_height;
00344 this->widget[DPIW_MATRIX_WIDGET].data = (this->vscroll.cap << 8) + 1;
00345 }
00346
00347 virtual void OnPlaceObject(Point pt, TileIndex tile)
00348 {
00349 bool success = true;
00350
00351 const IndustrySpec *indsp = GetIndustrySpec(this->selected_type);
00352 uint32 seed = InteractiveRandom();
00353
00354 if (_game_mode == GM_EDITOR) {
00355
00356 if (GetNumTowns() == 0) {
00357 SetDParam(0, indsp->name);
00358 ShowErrorMessage(STR_0286_MUST_BUILD_TOWN_FIRST, STR_0285_CAN_T_BUILD_HERE, pt.x, pt.y);
00359 return;
00360 }
00361
00362 _current_company = OWNER_NONE;
00363 _generating_world = true;
00364 _ignore_restrictions = true;
00365 success = DoCommandP(tile, (InteractiveRandomRange(indsp->num_table) << 16) | this->selected_type, seed, NULL, CMD_BUILD_INDUSTRY | CMD_MSG(STR_4830_CAN_T_CONSTRUCT_THIS_INDUSTRY));
00366 if (!success) {
00367 SetDParam(0, indsp->name);
00368 ShowErrorMessage(_error_message, STR_0285_CAN_T_BUILD_HERE, pt.x, pt.y);
00369 }
00370
00371 _ignore_restrictions = false;
00372 _generating_world = false;
00373 } else {
00374 success = DoCommandP(tile, (InteractiveRandomRange(indsp->num_table) << 16) | this->selected_type, seed, NULL, CMD_BUILD_INDUSTRY | CMD_MSG(STR_4830_CAN_T_CONSTRUCT_THIS_INDUSTRY));
00375 }
00376
00377
00378 if (success) ResetObjectToPlace();
00379 }
00380
00381 virtual void OnTick()
00382 {
00383 if (_pause_game != 0) return;
00384 if (!this->timer_enabled) return;
00385 if (--this->callback_timer == 0) {
00386
00387
00388 this->callback_timer = DAY_TICKS;
00389
00390 const IndustrySpec *indsp = GetIndustrySpec(this->selected_type);
00391
00392 if (indsp->enabled) {
00393 bool call_back_result = CheckIfCallBackAllowsAvailability(this->selected_type, IACT_USERCREATION);
00394
00395
00396 if (call_back_result != this->enabled[this->selected_index]) {
00397 this->enabled[this->selected_index] = call_back_result;
00398 this->SetDirty();
00399 }
00400 }
00401 }
00402 }
00403
00404 virtual void OnTimeout()
00405 {
00406 this->RaiseButtons();
00407 }
00408
00409 virtual void OnPlaceObjectAbort()
00410 {
00411 this->RaiseButtons();
00412 }
00413
00414 virtual void OnInvalidateData(int data = 0)
00415 {
00416 this->SetupArrays();
00417 this->SetDirty();
00418 }
00419 };
00420
00421 void ShowBuildIndustryWindow()
00422 {
00423 if (_game_mode != GM_EDITOR && !IsValidCompanyID(_current_company)) return;
00424 if (BringWindowToFrontById(WC_BUILD_INDUSTRY, 0)) return;
00425 new BuildIndustryWindow();
00426 }
00427
00428 static void UpdateIndustryProduction(Industry *i);
00429
00430 static inline bool IsProductionMinimum(const Industry *i, int pt)
00431 {
00432 return i->production_rate[pt] == 0;
00433 }
00434
00435 static inline bool IsProductionMaximum(const Industry *i, int pt)
00436 {
00437 return i->production_rate[pt] >= 255;
00438 }
00439
00440 static inline bool IsProductionAlterable(const Industry *i)
00441 {
00442 return ((_game_mode == GM_EDITOR || _cheats.setup_prod.value) &&
00443 (i->accepts_cargo[0] == CT_INVALID || i->accepts_cargo[0] == CT_VALUABLES));
00444 }
00445
00447 enum IndustryViewWidgets {
00448 IVW_CLOSEBOX = 0,
00449 IVW_CAPTION,
00450 IVW_STICKY,
00451 IVW_BACKGROUND,
00452 IVW_VIEWPORT,
00453 IVW_INFO,
00454 IVW_GOTO,
00455 IVW_SPACER,
00456 IVW_RESIZE,
00457 };
00458
00459 class IndustryViewWindow : public Window
00460 {
00461 byte editbox_line;
00462 byte clicked_line;
00463 byte clicked_button;
00464 byte production_offset_y;
00465
00466 public:
00467 IndustryViewWindow(const WindowDesc *desc, WindowNumber window_number) : Window(desc, window_number)
00468 {
00469 this->flags4 |= WF_DISABLE_VP_SCROLL;
00470 this->editbox_line = 0;
00471 this->clicked_line = 0;
00472 this->clicked_button = 0;
00473 InitializeWindowViewport(this, 3, 17, 254, 86, GetIndustry(window_number)->xy + TileDiffXY(1, 1), ZOOM_LVL_INDUSTRY);
00474 this->FindWindowPlacementAndResize(desc);
00475 }
00476
00477 virtual void OnPaint()
00478 {
00479 Industry *i = GetIndustry(this->window_number);
00480 const IndustrySpec *ind = GetIndustrySpec(i->type);
00481 int y = this->widget[IVW_INFO].top + 1;
00482 bool first = true;
00483 bool has_accept = false;
00484
00485 SetDParam(0, this->window_number);
00486 this->DrawWidgets();
00487
00488 if (HasBit(ind->callback_flags, CBM_IND_PRODUCTION_CARGO_ARRIVAL) || HasBit(ind->callback_flags, CBM_IND_PRODUCTION_256_TICKS)) {
00489 for (byte j = 0; j < lengthof(i->accepts_cargo); j++) {
00490 if (i->accepts_cargo[j] == CT_INVALID) continue;
00491 has_accept = true;
00492 if (first) {
00493 DrawStringTruncated(2, y, STR_INDUSTRY_WINDOW_WAITING_FOR_PROCESSING, TC_FROMSTRING, this->widget[IVW_INFO].right - 2);
00494 y += 10;
00495 first = false;
00496 }
00497 SetDParam(0, i->accepts_cargo[j]);
00498 SetDParam(1, i->incoming_cargo_waiting[j]);
00499 SetDParam(2, GetCargoSuffix(j, CST_VIEW, i, i->type, ind));
00500 DrawStringTruncated(4, y, STR_INDUSTRY_WINDOW_WAITING_STOCKPILE_CARGO, TC_FROMSTRING, this->widget[IVW_INFO].right - 4);
00501 y += 10;
00502 }
00503 } else {
00504 StringID str = STR_4827_REQUIRES;
00505 byte p = 0;
00506 for (byte j = 0; j < lengthof(i->accepts_cargo); j++) {
00507 if (i->accepts_cargo[j] == CT_INVALID) continue;
00508 has_accept = true;
00509 if (p > 0) str++;
00510 SetDParam(p++, GetCargo(i->accepts_cargo[j])->name);
00511 SetDParam(p++, GetCargoSuffix(j, CST_VIEW, i, i->type, ind));
00512 }
00513 if (has_accept) {
00514 DrawStringTruncated(2, y, str, TC_FROMSTRING, this->widget[IVW_INFO].right - 2);
00515 y += 10;
00516 }
00517 }
00518
00519 first = true;
00520 for (byte j = 0; j < lengthof(i->produced_cargo); j++) {
00521 if (i->produced_cargo[j] == CT_INVALID) continue;
00522 if (first) {
00523 if (has_accept) y += 10;
00524 DrawStringTruncated(2, y, STR_482A_PRODUCTION_LAST_MONTH, TC_FROMSTRING, this->widget[IVW_INFO].right - 2);
00525 y += 10;
00526 this->production_offset_y = y;
00527 first = false;
00528 }
00529
00530 SetDParam(0, i->produced_cargo[j]);
00531 SetDParam(1, i->last_month_production[j]);
00532 SetDParam(2, GetCargoSuffix(j + 3, CST_VIEW, i, i->type, ind));
00533
00534 SetDParam(3, i->last_month_pct_transported[j] * 100 >> 8);
00535 uint x = 4 + (IsProductionAlterable(i) ? 30 : 0);
00536 DrawStringTruncated(x, y, STR_482B_TRANSPORTED, TC_FROMSTRING, this->widget[IVW_INFO].right - x);
00537
00538 if (IsProductionAlterable(i)) {
00539 DrawArrowButtons(5, y, COLOUR_YELLOW, (this->clicked_line == j + 1) ? this->clicked_button : 0,
00540 !IsProductionMinimum(i, j), !IsProductionMaximum(i, j));
00541 }
00542 y += 10;
00543 }
00544
00545
00546 if (HasBit(ind->callback_flags, CBM_IND_WINDOW_MORE_TEXT)) {
00547 uint16 callback_res = GetIndustryCallback(CBID_INDUSTRY_WINDOW_MORE_TEXT, 0, 0, i, i->type, i->xy);
00548 if (callback_res != CALLBACK_FAILED) {
00549 StringID message = GetGRFStringID(ind->grf_prop.grffile->grfid, 0xD000 + callback_res);
00550 if (message != STR_NULL && message != STR_UNDEFINED) {
00551 const Widget *wi = &this->widget[IVW_INFO];
00552 y += 10;
00553
00554 PrepareTextRefStackUsage(6);
00555
00556 y += DrawStringMultiLine(2, y, message, wi->right - wi->left - 4, -1);
00557 StopTextRefStackUsage();
00558 }
00559 }
00560 }
00561
00562 if (y > this->widget[IVW_INFO].bottom) {
00563 this->SetDirty();
00564 ResizeWindowForWidget(this, IVW_INFO, 0, y - this->widget[IVW_INFO].top);
00565 this->SetDirty();
00566 return;
00567 }
00568
00569 this->DrawViewport();
00570 }
00571
00572 virtual void OnClick(Point pt, int widget)
00573 {
00574 Industry *i;
00575
00576 switch (widget) {
00577 case IVW_INFO: {
00578 int line, x;
00579
00580 i = GetIndustry(this->window_number);
00581
00582
00583 if (!IsProductionAlterable(i)) return;
00584 x = pt.x;
00585 line = (pt.y - this->production_offset_y) / 10;
00586 if (pt.y >= this->production_offset_y && IsInsideMM(line, 0, 2) && i->produced_cargo[line] != CT_INVALID) {
00587 if (IsInsideMM(x, 5, 25) ) {
00588
00589 if (x < 15) {
00590 if (IsProductionMinimum(i, line)) return;
00591 i->production_rate[line] = max(i->production_rate[line] / 2, 0);
00592 } else {
00593
00594 int new_prod = i->production_rate[line] == 0 ? 1 : i->production_rate[line] * 2;
00595 if (IsProductionMaximum(i, line)) return;
00596 i->production_rate[line] = minu(new_prod, 255);
00597 }
00598
00599 UpdateIndustryProduction(i);
00600 this->SetDirty();
00601 this->flags4 |= WF_TIMEOUT_BEGIN;
00602 this->clicked_line = line + 1;
00603 this->clicked_button = (x < 15 ? 1 : 2);
00604 } else if (IsInsideMM(x, 34, 160)) {
00605
00606 this->editbox_line = line;
00607 SetDParam(0, i->production_rate[line] * 8);
00608 ShowQueryString(STR_CONFIG_PATCHES_INT32, STR_CONFIG_GAME_PRODUCTION, 10, 100, this, CS_ALPHANUMERAL, QSF_NONE);
00609 }
00610 }
00611 } break;
00612
00613 case IVW_GOTO:
00614 i = GetIndustry(this->window_number);
00615 if (_ctrl_pressed) {
00616 ShowExtraViewPortWindow(i->xy + TileDiffXY(1, 1));
00617 } else {
00618 ScrollMainWindowToTile(i->xy + TileDiffXY(1, 1));
00619 }
00620 break;
00621 }
00622 }
00623
00624 virtual void OnTimeout()
00625 {
00626 this->clicked_line = 0;
00627 this->clicked_button = 0;
00628 this->SetDirty();
00629 }
00630
00631 virtual void OnResize(Point new_size, Point delta)
00632 {
00633 this->viewport->width += delta.x;
00634 this->viewport->height += delta.y;
00635 this->viewport->virtual_width += delta.x;
00636 this->viewport->virtual_height += delta.y;
00637 this->viewport->dest_scrollpos_x -= delta.x;
00638 this->viewport->dest_scrollpos_y -= delta.y;
00639 UpdateViewportPosition(this);
00640 }
00641
00642 virtual void OnQueryTextFinished(char *str)
00643 {
00644 if (StrEmpty(str)) return;
00645
00646 Industry* i = GetIndustry(this->window_number);
00647 int line = this->editbox_line;
00648
00649 i->production_rate[line] = ClampU(atoi(str), 0, 255);
00650 UpdateIndustryProduction(i);
00651 this->SetDirty();
00652 }
00653 };
00654
00655 static void UpdateIndustryProduction(Industry *i)
00656 {
00657 for (byte j = 0; j < lengthof(i->produced_cargo); j++) {
00658 if (i->produced_cargo[j] != CT_INVALID) {
00659 i->last_month_production[j] = 8 * i->production_rate[j];
00660 }
00661 }
00662 }
00663
00665 static const Widget _industry_view_widgets[] = {
00666 { WWT_CLOSEBOX, RESIZE_NONE, COLOUR_CREAM, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW},
00667 { WWT_CAPTION, RESIZE_RIGHT, COLOUR_CREAM, 11, 247, 0, 13, STR_4801, STR_018C_WINDOW_TITLE_DRAG_THIS},
00668 { WWT_STICKYBOX, RESIZE_LR, COLOUR_CREAM, 248, 259, 0, 13, 0x0, STR_STICKY_BUTTON},
00669 { WWT_PANEL, RESIZE_RB, COLOUR_CREAM, 0, 259, 14, 105, 0x0, STR_NULL},
00670 { WWT_INSET, RESIZE_RB, COLOUR_CREAM, 2, 257, 16, 103, 0x0, STR_NULL},
00671 { WWT_PANEL, RESIZE_RTB, COLOUR_CREAM, 0, 259, 106, 107, 0x0, STR_NULL},
00672 { WWT_PUSHTXTBTN, RESIZE_TB, COLOUR_CREAM, 0, 129, 108, 119, STR_00E4_LOCATION, STR_482C_CENTER_THE_MAIN_VIEW_ON},
00673 { WWT_PANEL, RESIZE_RTB, COLOUR_CREAM, 130, 247, 108, 119, 0x0, STR_NULL},
00674 { WWT_RESIZEBOX, RESIZE_LRTB, COLOUR_CREAM, 248, 259, 108, 119, 0x0, STR_RESIZE_BUTTON},
00675 { WIDGETS_END},
00676 };
00677
00679 static const WindowDesc _industry_view_desc = {
00680 WDP_AUTO, WDP_AUTO, 260, 120, 260, 120,
00681 WC_INDUSTRY_VIEW, WC_NONE,
00682 WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS | WDF_STICKY_BUTTON | WDF_RESIZABLE,
00683 _industry_view_widgets,
00684 };
00685
00686 void ShowIndustryViewWindow(int industry)
00687 {
00688 AllocateWindowDescFront<IndustryViewWindow>(&_industry_view_desc, industry);
00689 }
00690
00692 enum IndustryDirectoryWidgets {
00693 IDW_CLOSEBOX = 0,
00694 IDW_CAPTION,
00695 IDW_STICKY,
00696 IDW_DROPDOWN_ORDER,
00697 IDW_DROPDOWN_CRITERIA,
00698 IDW_SPACER,
00699 IDW_INDUSTRY_LIST,
00700 IDW_SCROLLBAR,
00701 IDW_RESIZE,
00702 };
00703
00705 static const Widget _industry_directory_widgets[] = {
00706 { WWT_CLOSEBOX, RESIZE_NONE, COLOUR_BROWN, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW},
00707 { WWT_CAPTION, RESIZE_RIGHT, COLOUR_BROWN, 11, 415, 0, 13, STR_INDUSTRYDIR_CAPTION, STR_018C_WINDOW_TITLE_DRAG_THIS},
00708 { WWT_STICKYBOX, RESIZE_LR, COLOUR_BROWN, 416, 427, 0, 13, 0x0, STR_STICKY_BUTTON},
00709
00710 { WWT_TEXTBTN, RESIZE_NONE, COLOUR_BROWN, 0, 80, 14, 25, STR_SORT_BY, STR_SORT_ORDER_TIP},
00711 { WWT_DROPDOWN, RESIZE_NONE, COLOUR_BROWN, 81, 243, 14, 25, 0x0, STR_SORT_CRITERIA_TIP},
00712 { WWT_PANEL, RESIZE_RIGHT, COLOUR_BROWN, 244, 415, 14, 25, 0x0, STR_NULL},
00713
00714 { WWT_PANEL, RESIZE_RB, COLOUR_BROWN, 0, 415, 26, 189, 0x0, STR_INDUSTRYDIR_LIST_CAPTION},
00715 { WWT_SCROLLBAR, RESIZE_LRB, COLOUR_BROWN, 416, 427, 14, 177, 0x0, STR_0190_SCROLL_BAR_SCROLLS_LIST},
00716 { WWT_RESIZEBOX, RESIZE_LRTB, COLOUR_BROWN, 416, 427, 178, 189, 0x0, STR_RESIZE_BUTTON},
00717 { WIDGETS_END},
00718 };
00719
00720 typedef GUIList<const Industry*> GUIIndustryList;
00721
00722
00726 class IndustryDirectoryWindow : public Window {
00727 protected:
00728
00729 static Listing last_sorting;
00730 static const Industry *last_industry;
00731
00732
00733 static const StringID sorter_names[];
00734 static GUIIndustryList::SortFunction *const sorter_funcs[];
00735
00736 GUIIndustryList industries;
00737
00739 void BuildIndustriesList()
00740 {
00741 if (!this->industries.NeedRebuild()) return;
00742
00743 this->industries.Clear();
00744
00745 DEBUG(misc, 3, "Building industry list");
00746
00747 const Industry *i;
00748 FOR_ALL_INDUSTRIES(i) {
00749 *this->industries.Append() = i;
00750 }
00751
00752 this->industries.Compact();
00753 this->industries.RebuildDone();
00754 }
00755
00763 static inline int GetCargoTransportedPercentsIfValid(const Industry *i, uint id)
00764 {
00765 assert(id < lengthof(i->produced_cargo));
00766
00767 if (i->produced_cargo[id] == CT_INVALID) return 101;
00768 return i->last_month_pct_transported[id] * 100 >> 8;
00769 }
00770
00778 static int GetCargoTransportedSortValue(const Industry *i)
00779 {
00780 int p1 = GetCargoTransportedPercentsIfValid(i, 0);
00781 int p2 = GetCargoTransportedPercentsIfValid(i, 1);
00782
00783 if (p1 > p2) Swap(p1, p2);
00784
00785 return (p1 << 8) + p2;
00786 }
00787
00789 static int CDECL IndustryNameSorter(const Industry* const *a, const Industry* const *b)
00790 {
00791 static char buf_cache[96];
00792 static char buf[96];
00793
00794 SetDParam(0, (*a)->town->index);
00795 GetString(buf, STR_TOWN, lastof(buf));
00796
00797 if (*b != last_industry) {
00798 last_industry = *b;
00799 SetDParam(0, (*b)->town->index);
00800 GetString(buf_cache, STR_TOWN, lastof(buf_cache));
00801 }
00802
00803 return strcmp(buf, buf_cache);
00804 }
00805
00807 static int CDECL IndustryTypeSorter(const Industry* const *a, const Industry* const *b)
00808 {
00809 int r = (*a)->type - (*b)->type;
00810 return (r == 0) ? IndustryNameSorter(a, b) : r;
00811 }
00812
00814 static int CDECL IndustryProductionSorter(const Industry* const *a, const Industry* const *b)
00815 {
00816 int r = 0;
00817
00818 if ((*a)->produced_cargo[0] == CT_INVALID) {
00819 if ((*b)->produced_cargo[0] != CT_INVALID) return -1;
00820 } else {
00821 if ((*b)->produced_cargo[0] == CT_INVALID) return 1;
00822
00823 r = ((*a)->last_month_production[0] + (*a)->last_month_production[1]) -
00824 ((*b)->last_month_production[0] + (*b)->last_month_production[1]);
00825 }
00826
00827 return (r == 0) ? IndustryNameSorter(a, b) : r;
00828 }
00829
00831 static int CDECL IndustryTransportedCargoSorter(const Industry* const *a, const Industry* const *b)
00832 {
00833 int r = GetCargoTransportedSortValue(*a) -