tron@2186: /* $Id$ */ tron@2186: rubidium@9111: /** @file industry_gui.cpp GUIs related to industries. */ belugas@6201: truelight@0: #include "stdafx.h" Darkvater@1891: #include "openttd.h" tron@1299: #include "debug.h" tron@1386: #include "gui.h" rubidium@8107: #include "window_gui.h" rubidium@8107: #include "textbuf_gui.h" rubidium@8116: #include "command_func.h" rubidium@8224: #include "viewport_func.h" rubidium@8224: #include "gfx_func.h" truelight@0: #include "industry.h" truelight@0: #include "town.h" tron@2159: #include "variables.h" rubidium@8965: #include "cheat_func.h" peter1138@6091: #include "cargotype.h" rubidium@7195: #include "newgrf.h" rubidium@7195: #include "newgrf_callbacks.h" rubidium@7195: #include "newgrf_industries.h" rubidium@7195: #include "newgrf_text.h" rubidium@8114: #include "strings_func.h" rubidium@8139: #include "map_func.h" rubidium@8254: #include "player_func.h" rubidium@8270: #include "settings_type.h" rubidium@9127: #include "tilehighlight_func.h" rubidium@9164: #include "string_func.h" glx@9306: #include "sortlist_type.h" skidd13@9400: #include "widgets/dropdown_func.h" rubidium@9659: #include "player_base.h" truelight@0: rubidium@8264: #include "table/strings.h" rubidium@8264: #include "table/sprites.h" rubidium@8264: belugas@7218: bool _ignore_restrictions; belugas@7218: glx@9104: enum CargoSuffixType { glx@9104: CST_FUND, glx@9104: CST_VIEW, glx@9105: CST_DIR, glx@9104: }; glx@9104: glx@8759: /** glx@8759: * Gets the string to display after the cargo name (using callback 37) glx@8759: * @param cargo the cargo for which the suffix is requested glx@8759: * - 00 - first accepted cargo type glx@8759: * - 01 - second accepted cargo type glx@8759: * - 02 - third accepted cargo type glx@8759: * - 03 - first produced cargo type glx@8759: * - 04 - second produced cargo type glx@9104: * @param cst the cargo suffix type (for which window is it requested) glx@8759: * @param ind the industry (NULL if in fund window) glx@8759: * @param ind_type the industry type glx@8759: * @param indspec the industry spec glx@8759: * @return the string to display glx@8759: */ glx@9104: static StringID GetCargoSuffix(uint cargo, CargoSuffixType cst, Industry *ind, IndustryType ind_type, const IndustrySpec *indspec) glx@8759: { glx@8759: if (HasBit(indspec->callback_flags, CBM_IND_CARGO_SUFFIX)) { glx@9104: uint16 callback = GetIndustryCallback(CBID_INDUSTRY_CARGO_SUFFIX, 0, (cst << 8) | cargo, ind, ind_type, (cst != CST_FUND) ? ind->xy : INVALID_TILE); rubidium@9019: if (GB(callback, 0, 8) != 0xFF) return GetGRFStringID(indspec->grf_prop.grffile->grfid, 0xD000 + callback); glx@8759: } glx@8759: return STR_EMPTY; glx@8759: } glx@8759: glx@9173: /** Names of the widgets of the dynamic place industries gui */ glx@9173: enum DynamicPlaceIndustriesWidgets { glx@9173: DPIW_CLOSEBOX = 0, glx@9173: DPIW_CAPTION, glx@9173: DPIW_MATRIX_WIDGET, glx@9173: DPIW_SCROLLBAR, glx@9173: DPIW_INFOPANEL, glx@9173: DPIW_FUND_WIDGET, glx@9173: DPIW_RESIZE_WIDGET, glx@9173: }; truelight@0: skidd13@8047: /** Widget definition of the dynamic place industries gui */ glx@9173: static const Widget _build_industry_widgets[] = { belugas@9744: { WWT_CLOSEBOX, RESIZE_NONE, COLOUR_DARK_GREEN, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW}, // DPIW_CLOSEBOX belugas@9744: { WWT_CAPTION, RESIZE_RIGHT, COLOUR_DARK_GREEN, 11, 169, 0, 13, STR_0314_FUND_NEW_INDUSTRY, STR_018C_WINDOW_TITLE_DRAG_THIS}, // DPIW_CAPTION belugas@9744: { WWT_MATRIX, RESIZE_RB, COLOUR_DARK_GREEN, 0, 157, 14, 118, 0x801, STR_INDUSTRY_SELECTION_HINT}, // DPIW_MATRIX_WIDGET belugas@9744: { WWT_SCROLLBAR, RESIZE_LRB, COLOUR_DARK_GREEN, 158, 169, 14, 118, 0x0, STR_0190_SCROLL_BAR_SCROLLS_LIST}, // DPIW_SCROLLBAR belugas@9744: { WWT_PANEL, RESIZE_RTB, COLOUR_DARK_GREEN, 0, 169, 119, 199, 0x0, STR_NULL}, // DPIW_INFOPANEL belugas@9744: { WWT_TEXTBTN, RESIZE_RTB, COLOUR_DARK_GREEN, 0, 157, 200, 211, STR_FUND_NEW_INDUSTRY, STR_NULL}, // DPIW_FUND_WIDGET belugas@9744: { WWT_RESIZEBOX, RESIZE_LRTB, COLOUR_DARK_GREEN, 158, 169, 200, 211, 0x0, STR_RESIZE_BUTTON}, // DPIW_RESIZE_WIDGET darkvater@176: { WIDGETS_END}, truelight@0: }; truelight@0: skidd13@8047: /** Window definition of the dynamic place industries gui */ glx@9173: static const WindowDesc _build_industry_desc = { rubidium@7341: WDP_AUTO, WDP_AUTO, 170, 212, 170, 212, rubidium@5893: WC_BUILD_INDUSTRY, WC_NONE, belugas@7218: WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_RESIZABLE, glx@9173: _build_industry_widgets, glx@9173: }; glx@9173: glx@9173: class BuildIndustryWindow : public Window { glx@9173: int selected_index; ///< index of the element in the matrix glx@9173: IndustryType selected_type; ///< industry corresponding to the above index glx@9173: uint16 callback_timer; ///< timer counter for callback eventual verification glx@9173: bool timer_enabled; ///< timer can be used glx@9173: uint16 count; ///< How many industries are loaded glx@9173: IndustryType index[NUM_INDUSTRYTYPES + 1]; ///< Type of industry, in the order it was loaded glx@9173: StringID text[NUM_INDUSTRYTYPES + 1]; ///< Text coming from CBM_IND_FUND_MORE_TEXT (if ever) glx@9173: bool enabled[NUM_INDUSTRYTYPES + 1]; ///< availability state, coming from CBID_INDUSTRY_AVAILABLE (if ever) glx@9173: glx@9194: void SetupArrays() glx@9173: { glx@9173: IndustryType ind; glx@9173: const IndustrySpec *indsp; glx@9173: glx@9194: this->count = 0; glx@9194: glx@9194: for (uint i = 0; i < lengthof(this->index); i++) { glx@9194: this->index[i] = INVALID_INDUSTRYTYPE; glx@9194: this->text[i] = STR_NULL; glx@9194: this->enabled[i] = false; glx@9194: } glx@9194: glx@9194: if (_game_mode == GM_EDITOR) { // give room for the Many Random "button" glx@9194: this->index[this->count] = INVALID_INDUSTRYTYPE; glx@9194: this->count++; glx@9194: this->timer_enabled = false; glx@9194: } glx@9194: /* Fill the arrays with industries. glx@9194: * The tests performed after the enabled allow to load the industries glx@9194: * In the same way they are inserted by grf (if any) glx@9194: */ glx@9194: for (ind = 0; ind < NUM_INDUSTRYTYPES; ind++) { glx@9194: indsp = GetIndustrySpec(ind); glx@9194: if (indsp->enabled){ glx@9194: /* Rule is that editor mode loads all industries. glx@9194: * In game mode, all non raw industries are loaded too glx@9194: * and raw ones are loaded only when setting allows it */ rubidium@9413: if (_game_mode != GM_EDITOR && indsp->IsRawIndustry() && _settings_game.construction.raw_industry_construction == 0) { glx@9194: /* Unselect if the industry is no longer in the list */ glx@9194: if (this->selected_type == ind) this->selected_index = -1; glx@9194: continue; glx@9194: } glx@9194: this->index[this->count] = ind; glx@9194: this->enabled[this->count] = (_game_mode == GM_EDITOR) || CheckIfCallBackAllowsAvailability(ind, IACT_USERCREATION); glx@9194: /* Keep the selection to the correct line */ glx@9194: if (this->selected_type == ind) this->selected_index = this->count; glx@9194: this->count++; glx@9194: } glx@9194: } glx@9194: glx@9194: /* first indutry type is selected if the current selection is invalid. glx@9194: * I'll be damned if there are none available ;) */ glx@9194: if (this->selected_index == -1) { glx@9194: this->selected_index = 0; glx@9194: this->selected_type = this->index[0]; glx@9194: } glx@9194: } glx@9194: glx@9194: public: glx@9194: BuildIndustryWindow() : Window(&_build_industry_desc) glx@9194: { glx@9173: /* Shorten the window to the equivalant of the additionnal purchase glx@9194: * info coming from the callback. SO it will only be available to its full glx@9173: * height when newindistries are loaded */ glx@9173: if (!_loaded_newgrf_features.has_newindustries) { glx@9173: this->widget[DPIW_INFOPANEL].bottom -= 44; glx@9173: this->widget[DPIW_FUND_WIDGET].bottom -= 44; glx@9173: this->widget[DPIW_FUND_WIDGET].top -= 44; glx@9173: this->widget[DPIW_RESIZE_WIDGET].bottom -= 44; glx@9173: this->widget[DPIW_RESIZE_WIDGET].top -= 44; glx@9173: this->resize.height = this->height -= 44; glx@9173: } glx@9173: glx@9173: this->timer_enabled = _loaded_newgrf_features.has_newindustries; glx@9173: glx@9173: this->vscroll.cap = 8; // rows in grid, same in scroller glx@9173: this->resize.step_height = 13; glx@9173: glx@9194: this->selected_index = -1; glx@9194: this->selected_type = INVALID_INDUSTRYTYPE; glx@9173: glx@9194: /* Initialize arrays */ glx@9194: this->SetupArrays(); glx@9173: glx@9173: this->callback_timer = DAY_TICKS; rubidium@9178: rubidium@9178: this->FindWindowPlacementAndResize(&_build_industry_desc); glx@9173: } glx@9173: glx@9173: virtual void OnPaint() glx@9173: { glx@9173: const IndustrySpec *indsp = (this->selected_type == INVALID_INDUSTRYTYPE) ? NULL : GetIndustrySpec(this->selected_type); glx@9173: int x_str = this->widget[DPIW_INFOPANEL].left + 3; glx@9173: int y_str = this->widget[DPIW_INFOPANEL].top + 3; glx@9173: const Widget *wi = &this->widget[DPIW_INFOPANEL]; glx@9173: int max_width = wi->right - wi->left - 4; glx@9173: glx@9173: /* Raw industries might be prospected. Show this fact by changing the string glx@9173: * In Editor, you just build, while ingame, or you fund or you prospect */ glx@9173: if (_game_mode == GM_EDITOR) { glx@9173: /* We've chosen many random industries but no industries have been specified */ rubidium@9413: if (indsp == NULL) this->enabled[this->selected_index] = _settings_game.difficulty.number_industries != 0; glx@9173: this->widget[DPIW_FUND_WIDGET].data = STR_BUILD_NEW_INDUSTRY; glx@9173: } else { rubidium@9413: this->widget[DPIW_FUND_WIDGET].data = (_settings_game.construction.raw_industry_construction == 2 && indsp->IsRawIndustry()) ? STR_PROSPECT_NEW_INDUSTRY : STR_FUND_NEW_INDUSTRY; glx@9173: } glx@9173: this->SetWidgetDisabledState(DPIW_FUND_WIDGET, !this->enabled[this->selected_index]); glx@9173: glx@9173: SetVScrollCount(this, this->count); glx@9173: rubidium@9273: this->DrawWidgets(); glx@9173: glx@9173: /* and now with the matrix painting */ glx@9173: for (byte i = 0; i < this->vscroll.cap && ((i + this->vscroll.pos) < this->count); i++) { glx@9173: int offset = i * 13; glx@9173: int x = 3; glx@9173: int y = 16; glx@9173: bool selected = this->selected_index == i + this->vscroll.pos; glx@9173: glx@9173: if (this->index[i + this->vscroll.pos] == INVALID_INDUSTRYTYPE) { glx@9173: DrawStringTruncated(20, y + offset, STR_MANY_RANDOM_INDUSTRIES, selected ? TC_WHITE : TC_ORANGE, max_width - 25); glx@9173: continue; glx@9173: } glx@9173: const IndustrySpec *indsp = GetIndustrySpec(this->index[i + this->vscroll.pos]); glx@9173: glx@9173: /* Draw the name of the industry in white is selected, otherwise, in orange */ glx@9173: DrawStringTruncated(20, y + offset, indsp->name, selected ? TC_WHITE : TC_ORANGE, max_width - 25); glx@9173: GfxFillRect(x, y + 1 + offset, x + 10, y + 7 + offset, selected ? 15 : 0); glx@9173: GfxFillRect(x + 1, y + 2 + offset, x + 9, y + 6 + offset, indsp->map_colour); glx@9173: } glx@9173: glx@9173: if (this->selected_type == INVALID_INDUSTRYTYPE) { glx@9173: DrawStringMultiLine(x_str, y_str, STR_RANDOM_INDUSTRIES_TIP, max_width, wi->bottom - wi->top - 40); glx@9173: return; glx@9173: } glx@9173: glx@9173: if (_game_mode != GM_EDITOR) { glx@9173: SetDParam(0, indsp->GetConstructionCost()); glx@9173: DrawStringTruncated(x_str, y_str, STR_482F_COST, TC_FROMSTRING, max_width); glx@9173: y_str += 11; glx@9173: } glx@9173: glx@9173: /* Draw the accepted cargos, if any. Otherwhise, will print "Nothing" */ glx@9173: StringID str = STR_4827_REQUIRES; glx@9173: byte p = 0; glx@9173: SetDParam(0, STR_00D0_NOTHING); glx@9173: SetDParam(1, STR_EMPTY); glx@9173: for (byte j = 0; j < lengthof(indsp->accepts_cargo); j++) { glx@9173: if (indsp->accepts_cargo[j] == CT_INVALID) continue; glx@9173: if (p > 0) str++; glx@9173: SetDParam(p++, GetCargo(indsp->accepts_cargo[j])->name); glx@9173: SetDParam(p++, GetCargoSuffix(j, CST_FUND, NULL, this->selected_type, indsp)); glx@9173: } glx@9173: DrawStringTruncated(x_str, y_str, str, TC_FROMSTRING, max_width); glx@9173: y_str += 11; glx@9173: glx@9173: /* Draw the produced cargos, if any. Otherwhise, will print "Nothing" */ glx@9173: str = STR_4827_PRODUCES; glx@9173: p = 0; glx@9173: SetDParam(0, STR_00D0_NOTHING); glx@9173: SetDParam(1, STR_EMPTY); glx@9173: for (byte j = 0; j < lengthof(indsp->produced_cargo); j++) { glx@9173: if (indsp->produced_cargo[j] == CT_INVALID) continue; glx@9173: if (p > 0) str++; glx@9173: SetDParam(p++, GetCargo(indsp->produced_cargo[j])->name); glx@9173: SetDParam(p++, GetCargoSuffix(j + 3, CST_FUND, NULL, this->selected_type, indsp)); glx@9173: } glx@9173: DrawStringTruncated(x_str, y_str, str, TC_FROMSTRING, max_width); glx@9173: y_str += 11; glx@9173: glx@9173: /* Get the additional purchase info text, if it has not already been */ glx@9173: if (this->text[this->selected_index] == STR_NULL) { // Have i been called already? glx@9173: if (HasBit(indsp->callback_flags, CBM_IND_FUND_MORE_TEXT)) { // No. Can it be called? glx@9173: uint16 callback_res = GetIndustryCallback(CBID_INDUSTRY_FUND_MORE_TEXT, 0, 0, NULL, this->selected_type, INVALID_TILE); glx@9173: if (callback_res != CALLBACK_FAILED) { // Did it failed? glx@9173: StringID newtxt = GetGRFStringID(indsp->grf_prop.grffile->grfid, 0xD000 + callback_res); // No. here's the new string glx@9173: this->text[this->selected_index] = newtxt; // Store it for further usage glx@9173: } glx@9173: } glx@9173: } glx@9173: glx@9173: /* Draw the Additional purchase text, provided by newgrf callback, if any. glx@9173: * Otherwhise, will print Nothing */ glx@9173: str = this->text[this->selected_index]; glx@9173: if (str != STR_NULL && str != STR_UNDEFINED) { glx@9173: SetDParam(0, str); glx@9173: DrawStringMultiLine(x_str, y_str, STR_JUST_STRING, max_width, wi->bottom - wi->top - 40); glx@9173: } glx@9173: } glx@9173: glx@9173: virtual void OnDoubleClick(Point pt, int widget) glx@9173: { glx@9173: if (widget != DPIW_MATRIX_WIDGET) return; glx@9173: this->OnClick(pt, DPIW_FUND_WIDGET); glx@9173: } glx@9173: glx@9173: virtual void OnClick(Point pt, int widget) glx@9173: { glx@9173: switch (widget) { glx@9173: case DPIW_MATRIX_WIDGET: { glx@9173: const IndustrySpec *indsp; glx@9173: int y = (pt.y - this->widget[DPIW_MATRIX_WIDGET].top) / 13 + this->vscroll.pos ; glx@9173: glx@9173: if (y >= 0 && y < count) { // Is it within the boundaries of available data? glx@9173: this->selected_index = y; glx@9173: this->selected_type = this->index[y]; glx@9173: indsp = (this->selected_type == INVALID_INDUSTRYTYPE) ? NULL : GetIndustrySpec(this->selected_type); glx@9173: glx@9173: this->SetDirty(); glx@9173: rubidium@9413: if ((_game_mode != GM_EDITOR && _settings_game.construction.raw_industry_construction == 2 && indsp != NULL && indsp->IsRawIndustry()) || glx@9173: this->selected_type == INVALID_INDUSTRYTYPE) { glx@9173: /* Reset the button state if going to prospecting or "build many industries" */ glx@9173: this->RaiseButtons(); glx@9173: ResetObjectToPlace(); glx@9173: } glx@9173: } glx@9173: } break; glx@9173: glx@9173: case DPIW_FUND_WIDGET: { glx@9173: if (this->selected_type == INVALID_INDUSTRYTYPE) { glx@9173: this->HandleButtonClick(DPIW_FUND_WIDGET); glx@9173: glx@9173: if (GetNumTowns() == 0) { glx@9173: ShowErrorMessage(STR_0286_MUST_BUILD_TOWN_FIRST, STR_CAN_T_GENERATE_INDUSTRIES, 0, 0); glx@9173: } else { glx@9173: extern void GenerateIndustries(); glx@9173: _generating_world = true; glx@9173: GenerateIndustries(); glx@9173: _generating_world = false; glx@9173: } rubidium@9413: } else if (_game_mode != GM_EDITOR && _settings_game.construction.raw_industry_construction == 2 && GetIndustrySpec(this->selected_type)->IsRawIndustry()) { glx@9173: DoCommandP(0, this->selected_type, InteractiveRandom(), NULL, CMD_BUILD_INDUSTRY | CMD_MSG(STR_4830_CAN_T_CONSTRUCT_THIS_INDUSTRY)); glx@9173: this->HandleButtonClick(DPIW_FUND_WIDGET); glx@9173: } else { glx@9173: HandlePlacePushButton(this, DPIW_FUND_WIDGET, SPR_CURSOR_INDUSTRY, VHM_RECT, NULL); glx@9173: } glx@9173: } break; glx@9173: } glx@9173: } glx@9173: glx@9173: virtual void OnResize(Point new_size, Point delta) glx@9173: { glx@9173: /* Adjust the number of items in the matrix depending of the rezise */ glx@9173: this->vscroll.cap += delta.y / (int)this->resize.step_height; glx@9173: this->widget[DPIW_MATRIX_WIDGET].data = (this->vscroll.cap << 8) + 1; glx@9173: } glx@9173: glx@9173: virtual void OnPlaceObject(Point pt, TileIndex tile) glx@9173: { glx@9173: bool success = true; glx@9173: /* We do not need to protect ourselves against "Random Many Industries" in this mode */ glx@9173: const IndustrySpec *indsp = GetIndustrySpec(this->selected_type); glx@9173: uint32 seed = InteractiveRandom(); glx@9173: glx@9173: if (_game_mode == GM_EDITOR) { glx@9173: /* Show error if no town exists at all */ glx@9173: if (GetNumTowns() == 0) { glx@9173: SetDParam(0, indsp->name); glx@9173: ShowErrorMessage(STR_0286_MUST_BUILD_TOWN_FIRST, STR_0285_CAN_T_BUILD_HERE, pt.x, pt.y); glx@9173: return; glx@9173: } glx@9173: glx@9173: _current_player = OWNER_NONE; glx@9173: _generating_world = true; glx@9173: _ignore_restrictions = true; glx@9173: 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)); glx@9173: if (!success) { glx@9173: SetDParam(0, indsp->name); glx@9173: ShowErrorMessage(_error_message, STR_0285_CAN_T_BUILD_HERE, pt.x, pt.y); glx@9173: } glx@9173: glx@9173: _ignore_restrictions = false; glx@9173: _generating_world = false; glx@9173: } else { glx@9173: 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)); glx@9173: } glx@9173: glx@9173: /* If an industry has been built, just reset the cursor and the system */ glx@9173: if (success) ResetObjectToPlace(); glx@9173: } glx@9173: glx@9173: virtual void OnTick() glx@9173: { glx@9173: if (_pause_game != 0) return; glx@9173: if (!this->timer_enabled) return; glx@9173: if (--this->callback_timer == 0) { glx@9173: /* We have just passed another day. glx@9173: * See if we need to update availability of currently selected industry */ glx@9173: this->callback_timer = DAY_TICKS; //restart counter glx@9173: glx@9173: const IndustrySpec *indsp = GetIndustrySpec(this->selected_type); glx@9173: glx@9173: if (indsp->enabled) { glx@9173: bool call_back_result = CheckIfCallBackAllowsAvailability(this->selected_type, IACT_USERCREATION); glx@9173: glx@9173: /* Only if result does match the previous state would it require a redraw. */ glx@9173: if (call_back_result != this->enabled[this->selected_index]) { glx@9173: this->enabled[this->selected_index] = call_back_result; glx@9173: this->SetDirty(); glx@9173: } glx@9173: } glx@9173: } glx@9173: } glx@9173: glx@9173: virtual void OnTimeout() glx@9173: { glx@9173: this->RaiseButtons(); glx@9173: } glx@9173: glx@9173: virtual void OnPlaceObjectAbort() glx@9173: { glx@9173: this->RaiseButtons(); glx@9173: } glx@9194: glx@9194: virtual void OnInvalidateData(int data = 0) glx@9194: { glx@9194: this->SetupArrays(); glx@9194: this->SetDirty(); glx@9194: } truelight@0: }; truelight@0: rubidium@6247: void ShowBuildIndustryWindow() truelight@193: { rubidium@9652: if (_game_mode != GM_EDITOR && !IsValidPlayerID(_current_player)) return; glx@9173: if (BringWindowToFrontById(WC_BUILD_INDUSTRY, 0)) return; glx@9173: new BuildIndustryWindow(); truelight@0: } truelight@0: belugas@7218: static void UpdateIndustryProduction(Industry *i); belugas@7218: glx@9110: static inline bool IsProductionMinimum(const Industry *i, int pt) rubidium@7284: { belugas@7790: return i->production_rate[pt] == 0; miham@4211: } miham@4211: glx@9110: static inline bool IsProductionMaximum(const Industry *i, int pt) rubidium@7284: { belugas@7790: return i->production_rate[pt] >= 255; miham@4211: } miham@4211: Darkvater@4194: static inline bool IsProductionAlterable(const Industry *i) Darkvater@4194: { Darkvater@4194: return ((_game_mode == GM_EDITOR || _cheats.setup_prod.value) && glx@7645: (i->accepts_cargo[0] == CT_INVALID || i->accepts_cargo[0] == CT_VALUABLES)); Darkvater@4194: } Darkvater@4194: skidd13@8047: /** Names of the widgets of the view industry gui */ skidd13@8047: enum IndustryViewWidgets { skidd13@8047: IVW_CLOSEBOX = 0, skidd13@8047: IVW_CAPTION, skidd13@8047: IVW_STICKY, skidd13@8047: IVW_BACKGROUND, skidd13@8047: IVW_VIEWPORT, skidd13@8047: IVW_INFO, skidd13@8047: IVW_GOTO, skidd13@8047: IVW_SPACER, glx@9169: IVW_RESIZE, skidd13@8047: }; skidd13@8047: glx@9187: class IndustryViewWindow : public Window glx@9187: { rubidium@7284: byte editbox_line; ///< The line clicked to open the edit box rubidium@7284: byte clicked_line; ///< The line of the button that has been clicked rubidium@7284: byte clicked_button; ///< The button that has been clicked (to raise) rubidium@7284: byte production_offset_y; ///< The offset of the production texts/buttons truelight@0: glx@9187: public: rubidium@9203: IndustryViewWindow(const WindowDesc *desc, WindowNumber window_number) : Window(desc, window_number) glx@9187: { glx@9187: this->flags4 |= WF_DISABLE_VP_SCROLL; glx@9187: this->editbox_line = 0; glx@9187: this->clicked_line = 0; glx@9187: this->clicked_button = 0; glx@9187: InitializeWindowViewport(this, 3, 17, 254, 86, GetIndustry(window_number)->xy + TileDiffXY(1, 1), ZOOM_LVL_INDUSTRY); glx@9187: this->FindWindowPlacementAndResize(desc); glx@9187: } glx@9187: glx@9187: virtual void OnPaint() glx@9187: { glx@9187: Industry *i = GetIndustry(this->window_number); glx@9187: const IndustrySpec *ind = GetIndustrySpec(i->type); glx@9187: int y = this->widget[IVW_INFO].top + 1; glx@9187: bool first = true; glx@9187: bool has_accept = false; glx@9187: glx@9187: SetDParam(0, this->window_number); rubidium@9273: this->DrawWidgets(); glx@9187: glx@9187: if (HasBit(ind->callback_flags, CBM_IND_PRODUCTION_CARGO_ARRIVAL) || HasBit(ind->callback_flags, CBM_IND_PRODUCTION_256_TICKS)) { glx@9187: for (byte j = 0; j < lengthof(i->accepts_cargo); j++) { glx@9187: if (i->accepts_cargo[j] == CT_INVALID) continue; glx@9187: has_accept = true; glx@9187: if (first) { glx@9187: DrawStringTruncated(2, y, STR_INDUSTRY_WINDOW_WAITING_FOR_PROCESSING, TC_FROMSTRING, this->widget[IVW_INFO].right - 2); rubidium@7195: y += 10; glx@9187: first = false; rubidium@7195: } glx@9187: SetDParam(0, i->accepts_cargo[j]); glx@9187: SetDParam(1, i->incoming_cargo_waiting[j]); glx@9187: SetDParam(2, GetCargoSuffix(j, CST_VIEW, i, i->type, ind)); glx@9187: DrawStringTruncated(4, y, STR_INDUSTRY_WINDOW_WAITING_STOCKPILE_CARGO, TC_FROMSTRING, this->widget[IVW_INFO].right - 4); glx@9187: y += 10; glx@9187: } glx@9187: } else { glx@9187: StringID str = STR_4827_REQUIRES; glx@9187: byte p = 0; glx@9187: for (byte j = 0; j < lengthof(i->accepts_cargo); j++) { glx@9187: if (i->accepts_cargo[j] == CT_INVALID) continue; glx@9187: has_accept = true; glx@9187: if (p > 0) str++; glx@9187: SetDParam(p++, GetCargo(i->accepts_cargo[j])->name); glx@9187: SetDParam(p++, GetCargoSuffix(j, CST_VIEW, i, i->type, ind)); glx@9187: } glx@9187: if (has_accept) { glx@9187: DrawStringTruncated(2, y, str, TC_FROMSTRING, this->widget[IVW_INFO].right - 2); glx@9187: y += 10; glx@9187: } glx@9187: } glx@9187: glx@9187: first = true; glx@9187: for (byte j = 0; j < lengthof(i->produced_cargo); j++) { glx@9187: if (i->produced_cargo[j] == CT_INVALID) continue; glx@9187: if (first) { glx@9187: if (has_accept) y += 10; glx@9187: DrawStringTruncated(2, y, STR_482A_PRODUCTION_LAST_MONTH, TC_FROMSTRING, this->widget[IVW_INFO].right - 2); glx@9187: y += 10; glx@9187: this->production_offset_y = y; glx@9187: first = false; glx@9187: } glx@9187: glx@9187: SetDParam(0, i->produced_cargo[j]); glx@9187: SetDParam(1, i->last_month_production[j]); glx@9187: SetDParam(2, GetCargoSuffix(j + 3, CST_VIEW, i, i->type, ind)); glx@9187: glx@9187: SetDParam(3, i->last_month_pct_transported[j] * 100 >> 8); glx@9187: uint x = 4 + (IsProductionAlterable(i) ? 30 : 0); glx@9187: DrawStringTruncated(x, y, STR_482B_TRANSPORTED, TC_FROMSTRING, this->widget[IVW_INFO].right - x); glx@9187: /* Let's put out those buttons.. */ glx@9187: if (IsProductionAlterable(i)) { belugas@9858: DrawArrowButtons(5, y, COLOUR_YELLOW, (this->clicked_line == j + 1) ? this->clicked_button : 0, glx@9187: !IsProductionMinimum(i, j), !IsProductionMaximum(i, j)); glx@9187: } glx@9187: y += 10; glx@9187: } glx@9187: glx@9187: /* Get the extra message for the GUI */ glx@9187: if (HasBit(ind->callback_flags, CBM_IND_WINDOW_MORE_TEXT)) { glx@9187: uint16 callback_res = GetIndustryCallback(CBID_INDUSTRY_WINDOW_MORE_TEXT, 0, 0, i, i->type, i->xy); glx@9187: if (callback_res != CALLBACK_FAILED) { glx@9187: StringID message = GetGRFStringID(ind->grf_prop.grffile->grfid, 0xD000 + callback_res); glx@9187: if (message != STR_NULL && message != STR_UNDEFINED) { glx@9187: const Widget *wi = &this->widget[IVW_INFO]; belugas@9096: y += 10; glx@9187: glx@9187: PrepareTextRefStackUsage(6); glx@9187: /* Use all the available space left from where we stand up to the end of the window */ glx@9187: y += DrawStringMultiLine(2, y, message, wi->right - wi->left - 4, -1); glx@9187: StopTextRefStackUsage(); belugas@9096: } rubidium@7195: } glx@9187: } belugas@9096: glx@9187: if (y > this->widget[IVW_INFO].bottom) { glx@9187: this->SetDirty(); glx@9187: ResizeWindowForWidget(this, IVW_INFO, 0, y - this->widget[IVW_INFO].top); glx@9187: this->SetDirty(); glx@9187: return; glx@9187: } truelight@0: rubidium@9273: this->DrawViewport(); glx@9187: } rubidium@7616: glx@9187: virtual void OnClick(Point pt, int widget) glx@9187: { glx@9187: Industry *i; glx@9187: glx@9187: switch (widget) { glx@9187: case IVW_INFO: { glx@9187: int line, x; glx@9187: glx@9187: i = GetIndustry(this->window_number); glx@9187: glx@9187: /* We should work if needed.. */ glx@9187: if (!IsProductionAlterable(i)) return; glx@9187: x = pt.x; glx@9187: line = (pt.y - this->production_offset_y) / 10; glx@9187: if (pt.y >= this->production_offset_y && IsInsideMM(line, 0, 2) && i->produced_cargo[line] != CT_INVALID) { glx@9187: if (IsInsideMM(x, 5, 25) ) { glx@9187: /* Clicked buttons, decrease or increase production */ glx@9187: if (x < 15) { glx@9187: if (IsProductionMinimum(i, line)) return; glx@9187: i->production_rate[line] = max(i->production_rate[line] / 2, 0); glx@9187: } else { glx@9187: /* a zero production industry is unlikely to give anything but zero, so push it a little bit */ glx@9187: int new_prod = i->production_rate[line] == 0 ? 1 : i->production_rate[line] * 2; glx@9187: if (IsProductionMaximum(i, line)) return; glx@9187: i->production_rate[line] = minu(new_prod, 255); glx@9187: } glx@9187: glx@9187: UpdateIndustryProduction(i); glx@9187: this->SetDirty(); glx@9187: this->flags4 |= 5 << WF_TIMEOUT_SHL; glx@9187: this->clicked_line = line + 1; glx@9187: this->clicked_button = (x < 15 ? 1 : 2); glx@9187: } else if (IsInsideMM(x, 34, 160)) { glx@9187: /* clicked the text */ glx@9187: this->editbox_line = line; glx@9187: SetDParam(0, i->production_rate[line] * 8); glx@9187: ShowQueryString(STR_CONFIG_PATCHES_INT32, STR_CONFIG_GAME_PRODUCTION, 10, 100, this, CS_ALPHANUMERAL); belugas@9096: } miham@4211: } glx@9187: } break; belugas@9096: glx@9187: case IVW_GOTO: glx@9187: i = GetIndustry(this->window_number); glx@9187: if (_ctrl_pressed) { glx@9187: ShowExtraViewPortWindow(i->xy + TileDiffXY(1, 1)); glx@9187: } else { glx@9187: ScrollMainWindowToTile(i->xy + TileDiffXY(1, 1)); glx@9187: } glx@9187: break; glx@9187: } glx@9187: } Darkvater@4193: glx@9187: virtual void OnTimeout() glx@9187: { glx@9187: this->clicked_line = 0; glx@9187: this->clicked_button = 0; glx@9187: this->SetDirty(); glx@9187: } miham@1004: glx@9187: virtual void OnResize(Point new_size, Point delta) glx@9187: { glx@9187: this->viewport->width += delta.x; glx@9187: this->viewport->height += delta.y; glx@9187: this->viewport->virtual_width += delta.x; glx@9187: this->viewport->virtual_height += delta.y; glx@9187: this->viewport->dest_scrollpos_x -= delta.x; glx@9187: this->viewport->dest_scrollpos_y -= delta.y; glx@9187: UpdateViewportPosition(this); glx@9187: } glx@9169: glx@9187: virtual void OnQueryTextFinished(char *str) glx@9187: { glx@9187: if (StrEmpty(str)) return; miham@1004: glx@9187: Industry* i = GetIndustry(this->window_number); glx@9187: int line = this->editbox_line; glx@9187: glx@9187: i->production_rate[line] = ClampU(atoi(str), 0, 255); glx@9187: UpdateIndustryProduction(i); glx@9187: this->SetDirty(); truelight@0: } glx@9187: }; truelight@0: miham@1004: static void UpdateIndustryProduction(Industry *i) miham@1004: { glx@7645: for (byte j = 0; j < lengthof(i->produced_cargo); j++) { glx@7645: if (i->produced_cargo[j] != CT_INVALID) { rubidium@6819: i->last_month_production[j] = 8 * i->production_rate[j]; belugas@6636: } belugas@6636: } miham@1004: } miham@1004: skidd13@8047: /** Widget definition of the view industy gui */ truelight@0: static const Widget _industry_view_widgets[] = { belugas@9744: { WWT_CLOSEBOX, RESIZE_NONE, COLOUR_CREAM, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW}, // IVW_CLOSEBOX belugas@9744: { WWT_CAPTION, RESIZE_RIGHT, COLOUR_CREAM, 11, 247, 0, 13, STR_4801, STR_018C_WINDOW_TITLE_DRAG_THIS}, // IVW_CAPTION belugas@9744: { WWT_STICKYBOX, RESIZE_LR, COLOUR_CREAM, 248, 259, 0, 13, 0x0, STR_STICKY_BUTTON}, // IVW_STICKY belugas@9744: { WWT_PANEL, RESIZE_RB, COLOUR_CREAM, 0, 259, 14, 105, 0x0, STR_NULL}, // IVW_BACKGROUND belugas@9744: { WWT_INSET, RESIZE_RB, COLOUR_CREAM, 2, 257, 16, 103, 0x0, STR_NULL}, // IVW_VIEWPORT belugas@9744: { WWT_PANEL, RESIZE_RTB, COLOUR_CREAM, 0, 259, 106, 107, 0x0, STR_NULL}, // IVW_INFO belugas@9744: { WWT_PUSHTXTBTN, RESIZE_TB, COLOUR_CREAM, 0, 129, 108, 119, STR_00E4_LOCATION, STR_482C_CENTER_THE_MAIN_VIEW_ON}, // IVW_GOTO belugas@9744: { WWT_PANEL, RESIZE_RTB, COLOUR_CREAM, 130, 247, 108, 119, 0x0, STR_NULL}, // IVW_SPACER belugas@9744: { WWT_RESIZEBOX, RESIZE_LRTB, COLOUR_CREAM, 248, 259, 108, 119, 0x0, STR_RESIZE_BUTTON}, // IVW_RESIZE darkvater@176: { WIDGETS_END}, truelight@0: }; truelight@0: skidd13@8047: /** Window definition of the view industy gui */ truelight@0: static const WindowDesc _industry_view_desc = { peter1138@8779: WDP_AUTO, WDP_AUTO, 260, 120, 260, 120, rubidium@5893: WC_INDUSTRY_VIEW, WC_NONE, glx@9169: WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS | WDF_STICKY_BUTTON | WDF_RESIZABLE, truelight@0: _industry_view_widgets, truelight@0: }; truelight@0: truelight@0: void ShowIndustryViewWindow(int industry) truelight@0: { glx@9187: AllocateWindowDescFront(&_industry_view_desc, industry); truelight@0: } truelight@0: skidd13@8047: /** Names of the widgets of the industry directory gui */ skidd13@8047: enum IndustryDirectoryWidgets { skidd13@8047: IDW_CLOSEBOX = 0, skidd13@8047: IDW_CAPTION, skidd13@8047: IDW_STICKY, skidd13@9400: IDW_DROPDOWN_ORDER, skidd13@9400: IDW_DROPDOWN_CRITERIA, skidd13@8047: IDW_SPACER, glx@9306: IDW_INDUSTRY_LIST, skidd13@8047: IDW_SCROLLBAR, skidd13@8047: IDW_RESIZE, belugas@7278: }; belugas@7278: skidd13@8047: /** Widget definition of the industy directory gui */ truelight@0: static const Widget _industry_directory_widgets[] = { belugas@9744: { WWT_CLOSEBOX, RESIZE_NONE, COLOUR_BROWN, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW}, // IDW_CLOSEBOX belugas@9744: { WWT_CAPTION, RESIZE_RIGHT, COLOUR_BROWN, 11, 415, 0, 13, STR_INDUSTRYDIR_CAPTION, STR_018C_WINDOW_TITLE_DRAG_THIS}, // IDW_CAPTION belugas@9744: { WWT_STICKYBOX, RESIZE_LR, COLOUR_BROWN, 416, 427, 0, 13, 0x0, STR_STICKY_BUTTON}, // IDW_STICKY skidd13@9400: belugas@9744: { WWT_TEXTBTN, RESIZE_NONE, COLOUR_BROWN, 0, 80, 14, 25, STR_SORT_BY, STR_SORT_ORDER_TIP}, // IDW_DROPDOWN_ORDER belugas@9744: { WWT_DROPDOWN, RESIZE_NONE, COLOUR_BROWN, 81, 243, 14, 25, 0x0, STR_SORT_CRITERIA_TIP}, // IDW_DROPDOWN_CRITERIA belugas@9744: { WWT_PANEL, RESIZE_RIGHT, COLOUR_BROWN, 244, 415, 14, 25, 0x0, STR_NULL}, // IDW_SPACER skidd13@9400: rubidium@9777: { WWT_PANEL, RESIZE_RB, COLOUR_BROWN, 0, 415, 26, 189, 0x0, STR_INDUSTRYDIR_LIST_CAPTION}, // IDW_INDUSRTY_LIST belugas@9744: { WWT_SCROLLBAR, RESIZE_LRB, COLOUR_BROWN, 416, 427, 14, 177, 0x0, STR_0190_SCROLL_BAR_SCROLLS_LIST}, // IDW_SCROLLBAR belugas@9744: { WWT_RESIZEBOX, RESIZE_LRTB, COLOUR_BROWN, 416, 427, 178, 189, 0x0, STR_RESIZE_BUTTON}, // IDW_RESIZE darkvater@176: { WIDGETS_END}, truelight@0: }; truelight@0: glx@9306: typedef GUIList GUIIndustryList; glx@9306: glx@9306: glx@9306: /** glx@9306: * The list of industries. glx@9306: */ skidd13@9400: class IndustryDirectoryWindow : public Window { skidd13@9400: protected: skidd13@9400: /* Runtime saved values */ skidd13@9400: static Listing last_sorting; skidd13@9400: static const Industry *last_industry; skidd13@9400: skidd13@9400: /* Constants for sorting stations */ skidd13@9400: static const StringID sorter_names[]; skidd13@9400: static GUIIndustryList::SortFunction *const sorter_funcs[]; glx@9306: skidd13@9384: GUIIndustryList industries; skidd13@9384: skidd13@9400: /** (Re)Build industries list */ skidd13@9400: void BuildIndustriesList() skidd13@9400: { skidd13@9400: if (!this->industries.NeedRebuild()) return; skidd13@9400: skidd13@9400: this->industries.Clear(); skidd13@9400: skidd13@9400: DEBUG(misc, 3, "Building industry list"); skidd13@9400: skidd13@9400: const Industry *i; skidd13@9400: FOR_ALL_INDUSTRIES(i) { skidd13@9400: *this->industries.Append() = i; skidd13@9400: } skidd13@9400: skidd13@9400: this->industries.Compact(); skidd13@9400: this->industries.RebuildDone(); skidd13@9400: } skidd13@9400: skidd13@9400: /** skidd13@9400: * Returns percents of cargo transported if industry produces this cargo, else -1 skidd13@9400: * skidd13@9400: * @param i industry to check skidd13@9400: * @param id cargo slot skidd13@9400: * @return percents of cargo transported, or -1 if industry doesn't use this cargo slot skidd13@9400: */ skidd13@9400: static inline int GetCargoTransportedPercentsIfValid(const Industry *i, uint id) skidd13@9400: { skidd13@9400: assert(id < lengthof(i->produced_cargo)); skidd13@9400: skidd13@9400: if (i->produced_cargo[id] == CT_INVALID) return 101; skidd13@9400: return i->last_month_pct_transported[id] * 100 >> 8; skidd13@9400: } skidd13@9400: skidd13@9400: /** skidd13@9400: * Returns value representing industry's transported cargo skidd13@9400: * percentage for industry sorting skidd13@9400: * skidd13@9400: * @param i industry to check skidd13@9400: * @return value used for sorting skidd13@9400: */ skidd13@9400: static int GetCargoTransportedSortValue(const Industry *i) skidd13@9400: { skidd13@9400: int p1 = GetCargoTransportedPercentsIfValid(i, 0); skidd13@9400: int p2 = GetCargoTransportedPercentsIfValid(i, 1); skidd13@9400: skidd13@9400: if (p1 > p2) Swap(p1, p2); // lower value has higher priority skidd13@9400: skidd13@9400: return (p1 << 8) + p2; skidd13@9400: } skidd13@9400: skidd13@9400: /** Sort industries by name */ skidd13@9400: static int CDECL IndustryNameSorter(const Industry* const *a, const Industry* const *b) skidd13@9400: { skidd13@9400: static char buf_cache[96]; skidd13@9400: static char buf[96]; skidd13@9400: skidd13@9400: SetDParam(0, (*a)->town->index); skidd13@9400: GetString(buf, STR_TOWN, lastof(buf)); skidd13@9400: skidd13@9400: if (*b != last_industry) { skidd13@9400: last_industry = *b; skidd13@9400: SetDParam(0, (*b)->town->index); skidd13@9400: GetString(buf_cache, STR_TOWN, lastof(buf_cache)); skidd13@9400: } skidd13@9400: skidd13@9400: return strcmp(buf, buf_cache); skidd13@9400: } skidd13@9400: skidd13@9400: /** Sort industries by type and name */ skidd13@9400: static int CDECL IndustryTypeSorter(const Industry* const *a, const Industry* const *b) skidd13@9400: { skidd13@9400: int r = (*a)->type - (*b)->type; rubidium@9467: return (r == 0) ? IndustryNameSorter(a, b) : r; skidd13@9400: } skidd13@9400: skidd13@9400: /** Sort industries by production and name */ skidd13@9400: static int CDECL IndustryProductionSorter(const Industry* const *a, const Industry* const *b) skidd13@9400: { rubidium@9467: int r = 0; skidd13@9400: skidd13@9400: if ((*a)->produced_cargo[0] == CT_INVALID) { skidd13@9400: if ((*b)->produced_cargo[0] != CT_INVALID) return -1; skidd13@9400: } else { skidd13@9400: if ((*b)->produced_cargo[0] == CT_INVALID) return 1; skidd13@9400: skidd13@9400: r = ((*a)->last_month_production[0] + (*a)->last_month_production[1]) - skidd13@9400: ((*b)->last_month_production[0] + (*b)->last_month_production[1]); skidd13@9400: } skidd13@9400: rubidium@9467: return (r == 0) ? IndustryNameSorter(a, b) : r; skidd13@9400: } skidd13@9400: skidd13@9400: /** Sort industries by transported cargo and name */ skidd13@9400: static int CDECL IndustryTransportedCargoSorter(const Industry* const *a, const Industry* const *b) skidd13@9400: { skidd13@9400: int r = GetCargoTransportedSortValue(*a) - GetCargoTransportedSortValue(*b); rubidium@9467: return (r == 0) ? IndustryNameSorter(a, b) : r; skidd13@9400: } skidd13@9400: skidd13@9400: /** Sort the industries list */ skidd13@9400: void SortIndustriesList() skidd13@9400: { skidd13@9400: if (!this->industries.Sort()) return; skidd13@9400: skidd13@9400: /* Reset name sorter sort cache */ skidd13@9400: this->last_industry = NULL; skidd13@9400: skidd13@9400: /* Set the modified widget dirty */ skidd13@9400: this->InvalidateWidget(IDW_INDUSTRY_LIST); skidd13@9400: } skidd13@9400: skidd13@9400: public: glx@9306: IndustryDirectoryWindow(const WindowDesc *desc, WindowNumber number) : Window(desc, number) glx@9306: { glx@9306: this->vscroll.cap = 16; glx@9306: this->resize.height = this->height - 6 * 10; // minimum 10 items glx@9306: this->resize.step_height = 10; glx@9306: this->FindWindowPlacementAndResize(desc); glx@9306: skidd13@9400: this->industries.SetListing(this->last_sorting); skidd13@9400: this->industries.SetSortFuncs(this->sorter_funcs); skidd13@9400: this->industries.ForceRebuild(); skidd13@9400: this->industries.NeedResort(); skidd13@9400: this->SortIndustriesList(); skidd13@9400: skidd13@9400: this->widget[IDW_DROPDOWN_CRITERIA].data = this->sorter_names[this->industries.SortType()]; skidd13@9400: } skidd13@9400: skidd13@9400: ~IndustryDirectoryWindow() skidd13@9400: { skidd13@9400: this->last_sorting = this->industries.GetListing(); glx@9306: } glx@9306: glx@9306: virtual void OnPaint() glx@9306: { skidd13@9400: BuildIndustriesList(); skidd13@9400: SortIndustriesList(); glx@9306: skidd13@9384: SetVScrollCount(this, this->industries.Length()); glx@9306: glx@9306: this->DrawWidgets(); skidd13@9400: this->DrawSortButtonState(IDW_DROPDOWN_ORDER, this->industries.IsDescSortOrder() ? SBS_DOWN : SBS_UP); glx@9306: skidd13@9384: int max = min(this->vscroll.pos + this->vscroll.cap, this->industries.Length()); glx@9306: int y = 28; // start of the list-widget glx@9306: glx@9306: for (int n = this->vscroll.pos; n < max; ++n) { skidd13@9384: const Industry* i = this->industries[n]; glx@9306: const IndustrySpec *indsp = GetIndustrySpec(i->type); glx@9306: byte p = 0; glx@9306: glx@9306: /* Industry name */ glx@9306: SetDParam(p++, i->index); glx@9306: glx@9306: /* Industry productions */ glx@9306: for (byte j = 0; j < lengthof(i->produced_cargo); j++) { glx@9306: if (i->produced_cargo[j] == CT_INVALID) continue; glx@9306: SetDParam(p++, i->produced_cargo[j]); glx@9306: SetDParam(p++, i->last_month_production[j]); glx@9306: SetDParam(p++, GetCargoSuffix(j + 3, CST_DIR, (Industry*)i, i->type, indsp)); truelight@0: } truelight@0: glx@9306: /* Transported productions */ glx@9306: for (byte j = 0; j < lengthof(i->produced_cargo); j++) { glx@9306: if (i->produced_cargo[j] == CT_INVALID) continue; glx@9306: SetDParam(p++, i->last_month_pct_transported[j] * 100 >> 8); belugas@9096: } truelight@0: glx@9306: /* Drawing the right string */ glx@9306: StringID str = STR_INDUSTRYDIR_ITEM_NOPROD; glx@9306: if (p != 1) str = (p == 5) ? STR_INDUSTRYDIR_ITEM : STR_INDUSTRYDIR_ITEM_TWO; glx@9306: DrawStringTruncated(4, y, str, TC_FROMSTRING, this->widget[IDW_INDUSTRY_LIST].right - 4); belugas@9096: glx@9306: y += 10; glx@9306: } glx@9306: } belugas@9096: glx@9306: virtual void OnClick(Point pt, int widget) glx@9306: { glx@9306: switch (widget) { skidd13@9400: case IDW_DROPDOWN_ORDER: skidd13@9400: this->industries.ToggleSortOrder(); glx@9306: this->SetDirty(); glx@9306: break; glx@9306: skidd13@9400: case IDW_DROPDOWN_CRITERIA: skidd13@9400: ShowDropDownMenu(this, this->sorter_names, this->industries.SortType(), IDW_DROPDOWN_CRITERIA, 0, 0); skidd13@9400: break; skidd13@9400: glx@9306: case IDW_INDUSTRY_LIST: { glx@9306: int y = (pt.y - 28) / 10; glx@9306: uint16 p; glx@9306: glx@9306: if (!IsInsideMM(y, 0, this->vscroll.cap)) return; glx@9306: p = y + this->vscroll.pos; skidd13@9384: if (p < this->industries.Length()) { glx@9306: if (_ctrl_pressed) { skidd13@9384: ShowExtraViewPortWindow(this->industries[p]->xy); glx@9306: } else { skidd13@9384: ScrollMainWindowToTile(this->industries[p]->xy); belugas@9096: } glx@9306: } glx@9306: } break; glx@9306: } glx@9306: } belugas@9096: skidd13@9400: virtual void OnDropdownSelect(int widget, int index) skidd13@9400: { skidd13@9400: if (this->industries.SortType() != index) { skidd13@9400: this->industries.SetSortType(index); skidd13@9400: this->widget[IDW_DROPDOWN_CRITERIA].data = this->sorter_names[this->industries.SortType()]; skidd13@9400: this->SetDirty(); skidd13@9400: } skidd13@9400: } skidd13@9400: glx@9306: virtual void OnResize(Point new_size, Point delta) glx@9306: { glx@9306: this->vscroll.cap += delta.y / 10; glx@9306: } belugas@9096: glx@9306: virtual void OnInvalidateData(int data) glx@9306: { skidd13@9400: if (data == 0) { skidd13@9400: this->industries.ForceRebuild(); skidd13@9400: } else { skidd13@9400: this->industries.ForceResort(); skidd13@9400: } glx@9306: this->InvalidateWidget(IDW_INDUSTRY_LIST); truelight@193: } glx@9306: }; glx@9306: skidd13@9400: Listing IndustryDirectoryWindow::last_sorting = {false, 0}; skidd13@9400: const Industry *IndustryDirectoryWindow::last_industry = NULL; skidd13@9400: skidd13@9400: /* Availible station sorting functions */ skidd13@9400: GUIIndustryList::SortFunction* const IndustryDirectoryWindow::sorter_funcs[] = { skidd13@9400: &IndustryNameSorter, skidd13@9400: &IndustryTypeSorter, skidd13@9400: &IndustryProductionSorter, skidd13@9400: &IndustryTransportedCargoSorter skidd13@9400: }; skidd13@9400: skidd13@9400: /* Names of the sorting functions */ skidd13@9400: const StringID IndustryDirectoryWindow::sorter_names[] = { skidd13@9400: STR_SORT_BY_DROPDOWN_NAME, skidd13@9400: STR_SORT_BY_TYPE, skidd13@9400: STR_SORT_BY_PRODUCTION, skidd13@9400: STR_SORT_BY_TRANSPORTED, skidd13@9400: INVALID_STRING_ID skidd13@9400: }; skidd13@9400: truelight@0: skidd13@8047: /** Window definition of the industy directory gui */ truelight@0: static const WindowDesc _industry_directory_desc = { skidd13@9400: WDP_AUTO, WDP_AUTO, 428, 190, 428, 190, rubidium@5893: WC_INDUSTRY_DIRECTORY, WC_NONE, truelight@867: WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS | WDF_STICKY_BUTTON | WDF_RESIZABLE, truelight@0: _industry_directory_widgets, truelight@0: }; truelight@0: rubidium@6247: void ShowIndustryDirectory() truelight@0: { glx@9306: AllocateWindowDescFront(&_industry_directory_desc, 0); truelight@0: }