typedef std::vector<const ScriptConfigItem *> VisibleSettingsList;
static VisibleSettingsList BuildVisibleSettingsList(CompanyID slot)
{
VisibleSettingsList visible_settings; ///< List of visible AI settings
ScriptConfig *config_list = GetConfig(slot);
ScriptConfigItemList::const_iterator it = config_list->GetConfigList()->begin();
for (; it != config_list->GetConfigList()->end(); it++) {
bool no_hide = (it->flags & SCRIPTCONFIG_DEVELOPER) == 0;
if (no_hide || _settings_client.gui.ai_developer_tools) {
visible_settings.push_back(&(*it));
}
}
return visible_settings;
}
////BLA BLA CODE ////
/**
* Window for settings the parameters of an AI.
*/
struct AISettingsWindow : public Window {
CompanyID slot; ///< The currently show company's setting.
ScriptConfig *ai_config; ///< The configuration we're modifying.
int clicked_button; ///< The button we clicked.
bool clicked_increase; ///< Whether we clicked the increase or decrease button.
bool clicked_dropdown; ///< Whether the dropdown is open.
bool closing_dropdown; ///< True, if the dropdown list is currently closing.
GUITimer timeout; ///< Timeout for unclicking the button.
int clicked_row; ///< The clicked row of settings.
int line_height; ///< Height of a row in the matrix widget.
Scrollbar *vscroll; ///< Cache of the vertical scrollbar.
VisibleSettingsList visible_settings; ///< List of visible AI settings
/**
* Constructor for the window.
* @param desc The description of the window.
* @param slot The company we're changing the settings for.
*/
AISettingsWindow(WindowDesc *desc, CompanyID slot) : Window(desc),
slot(slot),
clicked_button(-1),
clicked_dropdown(false),
closing_dropdown(false),
timeout(0)
{
this->ai_config = GetConfig(slot);
this->CreateNestedTree();
this->vscroll = this->GetScrollbar(WID_AIS_SCROLLBAR);
this->FinishInitNested(slot); // Initializes 'this->line_height' as side effect.
this->SetWidgetDisabledState(WID_AIS_RESET, _game_mode == GM_EDITOR && !IsConsideredDead(this->slot));
this->RebuildVisibleSettings();
}
virtual void SetStringParameters(int widget) const
{
switch (widget) {
case WID_AIS_CAPTION:
SetDParam(0, (this->slot == OWNER_DEITY) ? STR_AI_SETTINGS_CAPTION_GAMESCRIPT : STR_AI_SETTINGS_CAPTION_AI);
break;
}
}
/**
* Rebuilds the list of visible settings. AI settings with the flag
* SCRIPTCONFIG_DEVELOPER set will only be visible if the client setting
* gui.ai_developer_tools is enabled.
*/
void RebuildVisibleSettings()
{
this->ai_config = GetConfig(slot);
visible_settings.clear();
visible_settings.swap(BuildVisibleSettingsList(slot));
this->vscroll->SetCount((int)this->visible_settings.size());
}
virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize)
{
if (widget == WID_AIS_BACKGROUND) {
this->line_height = max(SETTING_BUTTON_HEIGHT, FONT_HEIGHT_NORMAL) + WD_MATRIX_TOP + WD_MATRIX_BOTTOM;
resize->width = 1;
resize->height = this->line_height;
size->height = 5 * this->line_height;
}
}
virtual void DrawWidget(const Rect &r, int widget) const
{
if (widget != WID_AIS_BACKGROUND) return;
ScriptConfig *config = this->ai_config;
VisibleSettingsList::const_iterator it = this->visible_settings.begin();
int i = 0;
for (; !this->vscroll->IsVisible(i); i++) it++;
bool rtl = _current_text_dir == TD_RTL;
uint buttons_left = rtl ? r.right - SETTING_BUTTON_WIDTH - 3 : r.left + 4;
uint text_left = r.left + (rtl ? WD_FRAMERECT_LEFT : SETTING_BUTTON_WIDTH + 8);
uint text_right = r.right - (rtl ? SETTING_BUTTON_WIDTH + 8 : WD_FRAMERECT_RIGHT);
int y = r.top;
int button_y_offset = (this->line_height - SETTING_BUTTON_HEIGHT) / 2;
int text_y_offset = (this->line_height - FONT_HEIGHT_NORMAL) / 2;
for (; this->vscroll->IsVisible(i) && it != visible_settings.end(); i++, it++) {
const ScriptConfigItem &config_item = **it;
int current_value = config->GetSetting((config_item).name);
bool editable = this->IsEditableItem(config_item);
StringID str;
TextColour colour;
uint idx = 0;
if (StrEmpty(config_item.description)) {
if (!strcmp(config_item.name, "start_date")) {
/* Build-in translation */
str = STR_AI_SETTINGS_START_DELAY;
colour = TC_LIGHT_BLUE;
} else {
str = STR_JUST_STRING;
colour = TC_ORANGE;
}
} else {
str = STR_AI_SETTINGS_SETTING;
colour = TC_LIGHT_BLUE;
SetDParamStr(idx++, config_item.description);
}
if ((config_item.flags & SCRIPTCONFIG_BOOLEAN) != 0) {
DrawBoolButton(buttons_left, y + button_y_offset, current_value != 0, editable);
SetDParam(idx++, current_value == 0 ? STR_CONFIG_SETTING_OFF : STR_CONFIG_SETTING_ON);
} else {
if (config_item.complete_labels) {
DrawDropDownButton(buttons_left, y + button_y_offset, COLOUR_YELLOW, this->clicked_row == i && clicked_dropdown, editable);
} else {
DrawArrowButtons(buttons_left, y + button_y_offset, COLOUR_YELLOW, (this->clicked_button == i) ? 1 + (this->clicked_increase != rtl) : 0, editable && current_value > config_item.min_value, editable && current_value < config_item.max_value);
}
if (config_item.labels != NULL && config_item.labels->Contains(current_value)) {
SetDParam(idx++, STR_JUST_RAW_STRING);
SetDParamStr(idx++, config_item.labels->Find(current_value)->second);
} else {
SetDParam(idx++, STR_JUST_INT);
SetDParam(idx++, current_value);
}
}
DrawString(text_left, text_right, y + text_y_offset, str, colour);
y += this->line_height;
}
}
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) {
case WID_AIS_BACKGROUND: {
const NWidgetBase *wid = this->GetWidget<NWidgetBase>(WID_AIS_BACKGROUND);
int num = (pt.y - wid->pos_y) / this->line_height + this->vscroll->GetPosition();
if (num >= (int)this->visible_settings.size()) break;
VisibleSettingsList::const_iterator it = this->visible_settings.begin();
for (int i = 0; i < num; i++) it++;
const ScriptConfigItem config_item = **it;
if (!this->IsEditableItem(config_item)) return;
if (this->clicked_row != num) {
DeleteChildWindows(WC_QUERY_STRING);
HideDropDownMenu(this);
this->clicked_row = num;
this->clicked_dropdown = false;
}
bool bool_item = (config_item.flags & SCRIPTCONFIG_BOOLEAN) != 0;
int x = pt.x - wid->pos_x;
if (_current_text_dir == TD_RTL) x = wid->current_x - 1 - x;
x -= 4;
/* One of the arrows is clicked (or green/red rect in case of bool value) */
int old_val = this->ai_config->GetSetting(config_item.name);
if (!bool_item && IsInsideMM(x, 0, SETTING_BUTTON_WIDTH) && config_item.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<NWidgetBase>(WID_AIS_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 (int i = config_item.min_value; i <= config_item.max_value; i++) {
*list->Append() = new DropDownListCharStringItem(config_item.labels->Find(i)->second, i, false);
}
ShowDropDownListAt(this, list, old_val, -1, wi_rect, COLOUR_ORANGE, true);
}
}
} else if (IsInsideMM(x, 0, SETTING_BUTTON_WIDTH)) {
int new_val = old_val;
if (bool_item) {
new_val = !new_val;
} else if (x >= SETTING_BUTTON_WIDTH / 2) {
/* Increase button clicked */
new_val += config_item.step_size;
if (new_val > config_item.max_value) new_val = config_item.max_value;
this->clicked_increase = true;
} else {
/* Decrease button clicked */
new_val -= config_item.step_size;
if (new_val < config_item.min_value) new_val = config_item.min_value;
this->clicked_increase = false;
}
if (new_val != old_val) {
this->ai_config->SetSetting(config_item.name, new_val);
this->clicked_button = num;
this->timeout.SetInterval(150);
}
} else if (!bool_item && !config_item.complete_labels) {
/* 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);
}
this->SetDirty();
break;
}
case WID_AIS_ACCEPT:
delete this;
break;
case WID_AIS_RESET:
if (_game_mode != GM_EDITOR || IsConsideredDead(this->slot)) {
this->ai_config->ResetSettingsGUI(IsConsideredDead(this->slot));
this->SetDirty();
}
break;
}
}
virtual void OnQueryTextFinished(char *str)
{
if (StrEmpty(str)) return;
VisibleSettingsList::const_iterator it = this->visible_settings.begin();
for (int i = 0; i < this->clicked_row; i++) it++;
const ScriptConfigItem config_item = **it;
if (_game_mode != GM_MENU && !IsConsideredDead(this->slot) && (config_item.flags & SCRIPTCONFIG_INGAME) == 0) return;
int32 value = atoi(str);
this->ai_config->SetSetting(config_item.name, value);
this->SetDirty();
}
virtual void OnDropdownSelect(int widget, int index)
{
assert(this->clicked_dropdown);
VisibleSettingsList::const_iterator it = this->visible_settings.begin();
for (int i = 0; i < this->clicked_row; i++) it++;
const ScriptConfigItem config_item = **it;
if (_game_mode != GM_MENU && !IsConsideredDead(this->slot) && (config_item.flags & SCRIPTCONFIG_INGAME) == 0) return;
this->ai_config->SetSetting(config_item.name, 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()
{
this->vscroll->SetCapacityFromWidget(this, WID_AIS_BACKGROUND);
}
virtual void OnRealtimeTick(uint delta_ms)
{
if (this->timeout.Elapsed(delta_ms)) {
this->clicked_button = -1;
this->SetDirty();
}
}
/**
* Some data on this window has become invalid.
* @param data Information about the changed data.
* @param gui_scope Whether the call is done from GUI scope. You may not do everything when not in GUI scope. See #InvalidateWindowData() for details.
*/
virtual void OnInvalidateData(int data = 0, bool gui_scope = true)
{
this->RebuildVisibleSettings();
HideDropDownMenu(this);
DeleteChildWindows(WC_QUERY_STRING);
}
private:
bool IsEditableItem(const ScriptConfigItem config_item) const
{
if (_game_mode == GM_MENU) return true;
if (_game_mode == GM_NORMAL) {
if (IsConsideredDead(slot)) return true;
if (config_item.flags & SCRIPTCONFIG_INGAME) return true;
}
if (IsConsideredDead(slot)) {
if (slot == OWNER_DEITY) {
if (Game::GetInstance() == NULL) return true;
}
if (!Company::IsValidAiID(slot)) return true;
if (Company::Get(slot)->ai_instance == NULL) return true;
}
return false;
}
};