diff --git a/src/newgrf_config.cpp b/src/newgrf_config.cpp index 352740a591..d327da550f 100644 --- a/src/newgrf_config.cpp +++ b/src/newgrf_config.cpp @@ -164,6 +164,17 @@ void GRFConfig::SetSuitablePalette() SB(this->palette, GRFP_USE_BIT, 1, pal == PAL_WINDOWS ? GRFP_USE_WINDOWS : GRFP_USE_DOS); } +/** + * Finalize Action 14 info after file scan is finished. + */ +void GRFConfig::FinalizeParameterInfo() +{ + for (GRFParameterInfo **info = this->param_info.Begin(); info != this->param_info.End(); ++info) { + if (*info == NULL) continue; + (*info)->Finalize(); + } +} + GRFConfig *_all_grfs; GRFConfig *_grfconfig; GRFConfig *_grfconfig_newgame; @@ -232,7 +243,8 @@ GRFParameterInfo::GRFParameterInfo(GRFParameterInfo &info) : def_value(info.def_value), param_nr(info.param_nr), first_bit(info.first_bit), - num_bit(info.num_bit) + num_bit(info.num_bit), + complete_labels(info.complete_labels) { for (uint i = 0; i < info.value_names.Length(); i++) { SmallPair *data = info.value_names.Get(i); @@ -280,6 +292,20 @@ void GRFParameterInfo::SetValue(struct GRFConfig *config, uint32 value) SetWindowDirty(WC_GAME_OPTIONS, WN_GAME_OPTIONS_NEWGRF_STATE); } +/** + * Finalize Action 14 info after file scan is finished. + */ +void GRFParameterInfo::Finalize() +{ + this->complete_labels = true; + for (uint32 value = this->min_value; value <= this->max_value; value++) { + if (!this->value_names.Contains(value)) { + this->complete_labels = false; + break; + } + } +} + /** * Update the palettes of the graphics from the config file. * Called when changing the default palette in advanced settings. @@ -367,6 +393,7 @@ bool FillGRFDetails(GRFConfig *config, bool is_static, Subdirectory subdir) /* Find and load the Action 8 information */ LoadNewGRFFile(config, CONFIG_SLOT, GLS_FILESCAN, subdir); config->SetSuitablePalette(); + config->FinalizeParameterInfo(); /* Skip if the grfid is 0 (not read) or 0xFFFFFFFF (ttdp system grf) */ if (config->ident.grfid == 0 || config->ident.grfid == 0xFFFFFFFF || config->IsOpenTTDBaseGRF()) return false; diff --git a/src/newgrf_config.h b/src/newgrf_config.h index c950e698a3..52818c8f05 100644 --- a/src/newgrf_config.h +++ b/src/newgrf_config.h @@ -133,9 +133,11 @@ struct GRFParameterInfo { byte first_bit; ///< First bit to use in the GRF parameter byte num_bit; ///< Number of bits to use for this parameter SmallMap value_names; ///< Names for each value. + bool complete_labels; ///< True if all values have a label. uint32 GetValue(struct GRFConfig *config) const; void SetValue(struct GRFConfig *config, uint32 value); + void Finalize(); }; /** Reference counted wrapper around a GRFText pointer. */ @@ -183,6 +185,7 @@ struct GRFConfig : ZeroedMemoryAllocator { void SetParameterDefaults(); void SetSuitablePalette(); + void FinalizeParameterInfo(); }; /** Method to find GRFs using FindGRFConfig */ diff --git a/src/newgrf_gui.cpp b/src/newgrf_gui.cpp index 56b8c74dc8..6df352324f 100644 --- a/src/newgrf_gui.cpp +++ b/src/newgrf_gui.cpp @@ -19,6 +19,7 @@ #include "settings_type.h" #include "settings_func.h" #include "widgets/dropdown_type.h" +#include "widgets/dropdown_func.h" #include "network/network.h" #include "network/network_content.h" #include "sortlist_type.h" @@ -143,6 +144,8 @@ struct NewGRFParametersWindow : public Window { GRFConfig *grf_config; ///< Set the parameters of this GRFConfig. uint clicked_button; ///< The row in which a button was clicked or UINT_MAX. bool clicked_increase; ///< True if the increase button was clicked, false for the decrease button. + bool clicked_dropdown; ///< Whether the dropdown is open. + bool closing_dropdown; ///< True, if the dropdown list is currently closing. int timeout; ///< How long before we unpress the last-pressed button? uint clicked_row; ///< The selected parameter int line_height; ///< Height of a row in the matrix widget. @@ -153,6 +156,8 @@ struct NewGRFParametersWindow : public Window { NewGRFParametersWindow(const WindowDesc *desc, GRFConfig *c, bool editable) : Window(), grf_config(c), clicked_button(UINT_MAX), + clicked_dropdown(false), + closing_dropdown(false), timeout(0), clicked_row(UINT_MAX), editable(editable) @@ -263,7 +268,11 @@ struct NewGRFParametersWindow : public Window { DrawBoolButton(buttons_left, y + button_y_offset, current_value != 0, this->editable); SetDParam(2, par_info->GetValue(this->grf_config) == 0 ? STR_CONFIG_SETTING_OFF : STR_CONFIG_SETTING_ON); } else if (par_info->type == PTYPE_UINT_ENUM) { - DrawArrowButtons(buttons_left, y + button_y_offset, COLOUR_YELLOW, (this->clicked_button == i) ? 1 + (this->clicked_increase != rtl) : 0, this->editable && current_value > par_info->min_value, this->editable && current_value < par_info->max_value); + if (par_info->complete_labels) { + DrawDropDownButton(buttons_left, y + button_y_offset, COLOUR_YELLOW, this->clicked_row == i && this->clicked_dropdown, this->editable); + } else { + DrawArrowButtons(buttons_left, y + button_y_offset, COLOUR_YELLOW, (this->clicked_button == i) ? 1 + (this->clicked_increase != rtl) : 0, this->editable && current_value > par_info->min_value, this->editable && current_value < par_info->max_value); + } SetDParam(2, STR_JUST_INT); SetDParam(3, current_value); if (par_info->value_names.Contains(current_value)) { @@ -289,6 +298,15 @@ struct NewGRFParametersWindow : public Window { } } + virtual void OnPaint() + { + if (this->closing_dropdown) { + this->closing_dropdown = false; + this->clicked_dropdown = false; + } + this->DrawWidgets(); + } + virtual void OnClick(Point pt, int widget, int click_count) { switch (widget) { @@ -316,7 +334,9 @@ struct NewGRFParametersWindow : public Window { if (num >= this->vscroll->GetCount()) break; if (this->clicked_row != num) { DeleteChildWindows(WC_QUERY_STRING); + HideDropDownMenu(this); this->clicked_row = num; + this->clicked_dropdown = false; } const NWidgetBase *wid = this->GetWidget(WID_NP_BACKGROUND); @@ -329,7 +349,36 @@ struct NewGRFParametersWindow : public Window { /* One of the arrows is clicked */ uint32 old_val = par_info->GetValue(this->grf_config); - if (IsInsideMM(x, 0, SETTING_BUTTON_WIDTH)) { + if (par_info->type != PTYPE_BOOL && IsInsideMM(x, 0, SETTING_BUTTON_WIDTH) && par_info->complete_labels) { + if (this->clicked_dropdown) { + /* unclick the dropdown */ + HideDropDownMenu(this); + this->clicked_dropdown = false; + this->closing_dropdown = false; + } else { + const NWidgetBase *wid = this->GetWidget(WID_NP_BACKGROUND); + int rel_y = (pt.y - (int)wid->pos_y) % this->line_height; + + Rect wi_rect; + wi_rect.left = pt.x - (_current_text_dir == TD_RTL ? SETTING_BUTTON_WIDTH - 1 - x : x);; + wi_rect.right = wi_rect.left + SETTING_BUTTON_WIDTH - 1; + wi_rect.top = pt.y - rel_y + (this->line_height - SETTING_BUTTON_HEIGHT) / 2; + wi_rect.bottom = wi_rect.top + SETTING_BUTTON_HEIGHT - 1; + + /* For dropdowns we also have to check the y position thoroughly, the mouse may not above the just opening dropdown */ + if (pt.y >= wi_rect.top && pt.y <= wi_rect.bottom) { + this->clicked_dropdown = true; + this->closing_dropdown = false; + + DropDownList *list = new DropDownList(); + for (uint32 i = par_info->min_value; i <= par_info->max_value; i++) { + list->push_back(new DropDownListCharStringItem(GetGRFStringFromGRFText(par_info->value_names.Find(i)->second), i, false)); + } + + ShowDropDownListAt(this, list, old_val, -1, wi_rect, COLOUR_ORANGE, true); + } + } + } else if (IsInsideMM(x, 0, SETTING_BUTTON_WIDTH)) { uint32 val = old_val; if (par_info->type == PTYPE_BOOL) { val = !val; @@ -350,7 +399,7 @@ struct NewGRFParametersWindow : public Window { this->clicked_button = num; this->timeout = 5; } - } else if (par_info->type == PTYPE_UINT_ENUM && click_count >= 2) { + } else if (par_info->type == PTYPE_UINT_ENUM && !par_info->complete_labels && click_count >= 2) { /* Display a query box so users can enter a custom value. */ SetDParam(0, old_val); ShowQueryString(STR_JUST_INT, STR_CONFIG_SETTING_QUERY_CAPTION, 10, this, CS_NUMERAL, QSF_NONE); @@ -383,6 +432,26 @@ struct NewGRFParametersWindow : public Window { this->SetDirty(); } + virtual void OnDropdownSelect(int widget, int index) + { + assert(this->clicked_dropdown); + GRFParameterInfo *par_info = ((uint)this->clicked_row < this->grf_config->param_info.Length()) ? this->grf_config->param_info[this->clicked_row] : NULL; + if (par_info == NULL) par_info = GetDummyParameterInfo(this->clicked_row); + par_info->SetValue(this->grf_config, index); + this->SetDirty(); + } + + virtual void OnDropdownClose(Point pt, int widget, int index, bool instant_close) + { + /* We cannot raise the dropdown button just yet. OnClick needs some hint, whether + * the same dropdown button was clicked again, and then not open the dropdown again. + * So, we only remember that it was closed, and process it on the next OnPaint, which is + * after OnClick. */ + assert(this->clicked_dropdown); + this->closing_dropdown = true; + this->SetDirty(); + } + virtual void OnResize() { NWidgetCore *nwi = this->GetWidget(WID_NP_BACKGROUND);