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