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