Loading

Revision differences

Old revision #paiimwyt5New revision #pmqd87lcm
13    }  13    }  
14  14  
15    return visible_settings;  15    return visible_settings;  
16} 16}
   17
   18
   19////BLA BLA CODE ////
   20
   21/**
   22 * Window for settings the parameters of an AI.
   23 */
   24struct AISettingsWindow : public Window {
   25    CompanyID slot;                       ///< The currently show company's setting.
   26    ScriptConfig *ai_config;              ///< The configuration we're modifying.
   27    int clicked_button;                   ///< The button we clicked.
   28    bool clicked_increase;                ///< Whether we clicked the increase or decrease button.
   29    bool clicked_dropdown;                ///< Whether the dropdown is open.
   30    bool closing_dropdown;                ///< True, if the dropdown list is currently closing.
   31    GUITimer timeout;                     ///< Timeout for unclicking the button.
   32    int clicked_row;                      ///< The clicked row of settings.
   33    int line_height;                      ///< Height of a row in the matrix widget.
   34    Scrollbar *vscroll;                   ///< Cache of the vertical scrollbar.
   35    VisibleSettingsList visible_settings; ///< List of visible AI settings
   36
   37    /**
   38     * Constructor for the window.
   39     * @param desc The description of the window.
   40     * @param slot The company we're changing the settings for.
   41     */
   42    AISettingsWindow(WindowDesc *desc, CompanyID slot) : Window(desc),
   43        slot(slot),
   44        clicked_button(-1),
   45        clicked_dropdown(false),
   46        closing_dropdown(false),
   47        timeout(0)
   48    {
   49        this->ai_config = GetConfig(slot);
   50
   51        this->CreateNestedTree();
   52        this->vscroll = this->GetScrollbar(WID_AIS_SCROLLBAR);
   53        this->FinishInitNested(slot);  // Initializes 'this->line_height' as side effect.
   54
   55        this->SetWidgetDisabledState(WID_AIS_RESET, _game_mode == GM_EDITOR && !IsConsideredDead(this->slot));
   56
   57        this->RebuildVisibleSettings();
   58    }
   59
   60    virtual void SetStringParameters(int widget) const
   61    {
   62        switch (widget) {
   63            case WID_AIS_CAPTION:
   64                SetDParam(0, (this->slot == OWNER_DEITY) ? STR_AI_SETTINGS_CAPTION_GAMESCRIPT : STR_AI_SETTINGS_CAPTION_AI);
   65                break;
   66        }
   67    }
   68
   69    /**
   70     * Rebuilds the list of visible settings. AI settings with the flag
   71     * SCRIPTCONFIG_DEVELOPER set will only be visible if the client setting
   72     * gui.ai_developer_tools is enabled.
   73     */
   74    void RebuildVisibleSettings()
   75    {
   76        this->ai_config = GetConfig(slot);
   77        visible_settings.clear();
   78        visible_settings.swap(BuildVisibleSettingsList(slot));
   79
   80        this->vscroll->SetCount((int)this->visible_settings.size());
   81    }
   82
   83    virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize)
   84    {
   85        if (widget == WID_AIS_BACKGROUND) {
   86            this->line_height = max(SETTING_BUTTON_HEIGHT, FONT_HEIGHT_NORMAL) + WD_MATRIX_TOP + WD_MATRIX_BOTTOM;
   87
   88            resize->width = 1;
   89            resize->height = this->line_height;
   90            size->height = 5 * this->line_height;
   91        }
   92    }
   93
   94    virtual void DrawWidget(const Rect &r, int widget) const
   95    {
   96        if (widget != WID_AIS_BACKGROUND) return;
   97
   98        ScriptConfig *config = this->ai_config;
   99        VisibleSettingsList::const_iterator it = this->visible_settings.begin();
   100        int i = 0;
   101        for (; !this->vscroll->IsVisible(i); i++) it++;
   102
   103        bool rtl = _current_text_dir == TD_RTL;
   104        uint buttons_left = rtl ? r.right - SETTING_BUTTON_WIDTH - 3 : r.left + 4;
   105        uint text_left    = r.left + (rtl ? WD_FRAMERECT_LEFT : SETTING_BUTTON_WIDTH + 8);
   106        uint text_right   = r.right - (rtl ? SETTING_BUTTON_WIDTH + 8 : WD_FRAMERECT_RIGHT);
   107
   108
   109        int y = r.top;
   110        int button_y_offset = (this->line_height - SETTING_BUTTON_HEIGHT) / 2;
   111        int text_y_offset = (this->line_height - FONT_HEIGHT_NORMAL) / 2;
   112        for (; this->vscroll->IsVisible(i) && it != visible_settings.end(); i++, it++) {
   113            const ScriptConfigItem &config_item = **it;
   114            int current_value = config->GetSetting((config_item).name);
   115            bool editable = this->IsEditableItem(config_item);
   116
   117            StringID str;
   118            TextColour colour;
   119            uint idx = 0;
   120            if (StrEmpty(config_item.description)) {
   121                if (!strcmp(config_item.name, "start_date")) {
   122                    /* Build-in translation */
   123                    str = STR_AI_SETTINGS_START_DELAY;
   124                    colour = TC_LIGHT_BLUE;
   125                } else {
   126                    str = STR_JUST_STRING;
   127                    colour = TC_ORANGE;
   128                }
   129            } else {
   130                str = STR_AI_SETTINGS_SETTING;
   131                colour = TC_LIGHT_BLUE;
   132                SetDParamStr(idx++, config_item.description);
   133            }
   134
   135            if ((config_item.flags & SCRIPTCONFIG_BOOLEAN) != 0) {
   136                DrawBoolButton(buttons_left, y + button_y_offset, current_value != 0, editable);
   137                SetDParam(idx++, current_value == 0 ? STR_CONFIG_SETTING_OFF : STR_CONFIG_SETTING_ON);
   138            } else {
   139                if (config_item.complete_labels) {
   140                    DrawDropDownButton(buttons_left, y + button_y_offset, COLOUR_YELLOW, this->clicked_row == i && clicked_dropdown, editable);
   141                } else {
   142                    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);
   143                }
   144                if (config_item.labels != NULL && config_item.labels->Contains(current_value)) {
   145                    SetDParam(idx++, STR_JUST_RAW_STRING);
   146                    SetDParamStr(idx++, config_item.labels->Find(current_value)->second);
   147                } else {
   148                    SetDParam(idx++, STR_JUST_INT);
   149                    SetDParam(idx++, current_value);
   150                }
   151            }
   152
   153            DrawString(text_left, text_right, y + text_y_offset, str, colour);
   154            y += this->line_height;
   155        }
   156    }
   157
   158    virtual void OnPaint()
   159    {
   160        if (this->closing_dropdown) {
   161            this->closing_dropdown = false;
   162            this->clicked_dropdown = false;
   163        }
   164        this->DrawWidgets();
   165    }
   166
   167    virtual void OnClick(Point pt, int widget, int click_count)
   168    {
   169        switch (widget) {
   170            case WID_AIS_BACKGROUND: {
   171                const NWidgetBase *wid = this->GetWidget<NWidgetBase>(WID_AIS_BACKGROUND);
   172                int num = (pt.y - wid->pos_y) / this->line_height + this->vscroll->GetPosition();
   173                if (num >= (int)this->visible_settings.size()) break;
   174
   175                VisibleSettingsList::const_iterator it = this->visible_settings.begin();
   176                for (int i = 0; i < num; i++) it++;
   177                const ScriptConfigItem config_item = **it;
   178                if (!this->IsEditableItem(config_item)) return;
   179
   180                if (this->clicked_row != num) {
   181                    DeleteChildWindows(WC_QUERY_STRING);
   182                    HideDropDownMenu(this);
   183                    this->clicked_row = num;
   184                    this->clicked_dropdown = false;
   185                }
   186
   187                bool bool_item = (config_item.flags & SCRIPTCONFIG_BOOLEAN) != 0;
   188
   189                int x = pt.x - wid->pos_x;
   190                if (_current_text_dir == TD_RTL) x = wid->current_x - 1 - x;
   191                x -= 4;
   192
   193                /* One of the arrows is clicked (or green/red rect in case of bool value) */
   194                int old_val = this->ai_config->GetSetting(config_item.name);
   195                if (!bool_item && IsInsideMM(x, 0, SETTING_BUTTON_WIDTH) && config_item.complete_labels) {
   196                    if (this->clicked_dropdown) {
   197                        /* unclick the dropdown */
   198                        HideDropDownMenu(this);
   199                        this->clicked_dropdown = false;
   200                        this->closing_dropdown = false;
   201                    } else {
   202                        const NWidgetBase *wid = this->GetWidget<NWidgetBase>(WID_AIS_BACKGROUND);
   203                        int rel_y = (pt.y - (int)wid->pos_y) % this->line_height;
   204
   205                        Rect wi_rect;
   206                        wi_rect.left = pt.x - (_current_text_dir == TD_RTL ? SETTING_BUTTON_WIDTH - 1 - x : x);
   207                        wi_rect.right = wi_rect.left + SETTING_BUTTON_WIDTH - 1;
   208                        wi_rect.top = pt.y - rel_y + (this->line_height - SETTING_BUTTON_HEIGHT) / 2;
   209                        wi_rect.bottom = wi_rect.top + SETTING_BUTTON_HEIGHT - 1;
   210
   211                        /* For dropdowns we also have to check the y position thoroughly, the mouse may not above the just opening dropdown */
   212                        if (pt.y >= wi_rect.top && pt.y <= wi_rect.bottom) {
   213                            this->clicked_dropdown = true;
   214                            this->closing_dropdown = false;
   215
   216                            DropDownList *list = new DropDownList();
   217                            for (int i = config_item.min_value; i <= config_item.max_value; i++) {
   218                                *list->Append() = new DropDownListCharStringItem(config_item.labels->Find(i)->second, i, false);
   219                            }
   220
   221                            ShowDropDownListAt(this, list, old_val, -1, wi_rect, COLOUR_ORANGE, true);
   222                        }
   223                    }
   224                } else if (IsInsideMM(x, 0, SETTING_BUTTON_WIDTH)) {
   225                    int new_val = old_val;
   226                    if (bool_item) {
   227                        new_val = !new_val;
   228                    } else if (x >= SETTING_BUTTON_WIDTH / 2) {
   229                        /* Increase button clicked */
   230                        new_val += config_item.step_size;
   231                        if (new_val > config_item.max_value) new_val = config_item.max_value;
   232                        this->clicked_increase = true;
   233                    } else {
   234                        /* Decrease button clicked */
   235                        new_val -= config_item.step_size;
   236                        if (new_val < config_item.min_value) new_val = config_item.min_value;
   237                        this->clicked_increase = false;
   238                    }
   239
   240                    if (new_val != old_val) {
   241                        this->ai_config->SetSetting(config_item.name, new_val);
   242                        this->clicked_button = num;
   243                        this->timeout.SetInterval(150);
   244                    }
   245                } else if (!bool_item && !config_item.complete_labels) {
   246                    /* Display a query box so users can enter a custom value. */
   247                    SetDParam(0, old_val);
   248                    ShowQueryString(STR_JUST_INT, STR_CONFIG_SETTING_QUERY_CAPTION, 10, this, CS_NUMERAL, QSF_NONE);
   249                }
   250                this->SetDirty();
   251                break;
   252            }
   253
   254            case WID_AIS_ACCEPT:
   255                delete this;
   256                break;
   257
   258            case WID_AIS_RESET:
   259                if (_game_mode != GM_EDITOR || IsConsideredDead(this->slot)) {
   260                    this->ai_config->ResetSettingsGUI(IsConsideredDead(this->slot));
   261                    this->SetDirty();
   262                }
   263                break;
   264        }
   265    }
   266
   267    virtual void OnQueryTextFinished(char *str)
   268    {
   269        if (StrEmpty(str)) return;
   270        VisibleSettingsList::const_iterator it = this->visible_settings.begin();
   271        for (int i = 0; i < this->clicked_row; i++) it++;
   272        const ScriptConfigItem config_item = **it;
   273        if (_game_mode != GM_MENU && !IsConsideredDead(this->slot) && (config_item.flags & SCRIPTCONFIG_INGAME) == 0) return;
   274        int32 value = atoi(str);
   275        this->ai_config->SetSetting(config_item.name, value);
   276        this->SetDirty();
   277    }
   278
   279    virtual void OnDropdownSelect(int widget, int index)
   280    {
   281        assert(this->clicked_dropdown);
   282        VisibleSettingsList::const_iterator it = this->visible_settings.begin();
   283        for (int i = 0; i < this->clicked_row; i++) it++;
   284        const ScriptConfigItem config_item = **it;
   285        if (_game_mode != GM_MENU && !IsConsideredDead(this->slot) && (config_item.flags & SCRIPTCONFIG_INGAME) == 0) return;
   286        this->ai_config->SetSetting(config_item.name, index);
   287        this->SetDirty();
   288    }
   289
   290    virtual void OnDropdownClose(Point pt, int widget, int index, bool instant_close)
   291    {
   292        /* We cannot raise the dropdown button just yet. OnClick needs some hint, whether
   293         * the same dropdown button was clicked again, and then not open the dropdown again.
   294         * So, we only remember that it was closed, and process it on the next OnPaint, which is
   295         * after OnClick. */
   296        assert(this->clicked_dropdown);
   297        this->closing_dropdown = true;
   298        this->SetDirty();
   299    }
   300
   301    virtual void OnResize()
   302    {
   303        this->vscroll->SetCapacityFromWidget(this, WID_AIS_BACKGROUND);
   304    }
   305
   306    virtual void OnRealtimeTick(uint delta_ms)
   307    {
   308        if (this->timeout.Elapsed(delta_ms)) {
   309            this->clicked_button = -1;
   310            this->SetDirty();
   311        }
   312    }
   313
   314    /**
   315     * Some data on this window has become invalid.
   316     * @param data Information about the changed data.
   317     * @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.
   318     */
   319    virtual void OnInvalidateData(int data = 0, bool gui_scope = true)
   320    {
   321        this->RebuildVisibleSettings();
   322        HideDropDownMenu(this);
   323        DeleteChildWindows(WC_QUERY_STRING);
   324    }
   325
   326private:
   327    bool IsEditableItem(const ScriptConfigItem config_item) const
   328    {
   329        if (_game_mode == GM_MENU) return true;
   330
   331        if (_game_mode == GM_NORMAL) {
   332            if (IsConsideredDead(slot)) return true;
   333            if (config_item.flags & SCRIPTCONFIG_INGAME) return true;
   334        }
   335
   336        if (IsConsideredDead(slot)) {
   337            if (slot == OWNER_DEITY) {
   338                if (Game::GetInstance() == NULL) return true;
   339            }
   340            if (!Company::IsValidAiID(slot)) return true;
   341            if (Company::Get(slot)->ai_instance == NULL) return true;
   342        }
   343
   344        return false;
   345    }
   346};