00001
00002
00003
00004
00005
00006
00007
00008
00009
00012 #include "stdafx.h"
00013 #include "error.h"
00014 #include "gui.h"
00015 #include "newgrf.h"
00016 #include "strings_func.h"
00017 #include "window_func.h"
00018 #include "gamelog.h"
00019 #include "settings_type.h"
00020 #include "settings_func.h"
00021 #include "widgets/dropdown_type.h"
00022 #include "network/network.h"
00023 #include "network/network_content.h"
00024 #include "sortlist_type.h"
00025 #include "querystring_gui.h"
00026 #include "core/geometry_func.hpp"
00027 #include "newgrf_text.h"
00028 #include "fileio_func.h"
00029 #include "fontcache.h"
00030
00031 #include "widgets/newgrf_widget.h"
00032
00033 #include "table/sprites.h"
00034
00038 void ShowNewGRFError()
00039 {
00040
00041 if (_game_mode == GM_MENU) return;
00042
00043 for (const GRFConfig *c = _grfconfig; c != NULL; c = c->next) {
00044
00045 if (c->error == NULL || c->error->severity != STR_NEWGRF_ERROR_MSG_FATAL) continue;
00046
00047 SetDParam (0, c->error->custom_message == NULL ? c->error->message : STR_JUST_RAW_STRING);
00048 SetDParamStr(1, c->error->custom_message);
00049 SetDParam (2, STR_JUST_RAW_STRING);
00050 SetDParamStr(3, c->filename);
00051 SetDParam (4, STR_JUST_RAW_STRING);
00052 SetDParamStr(5, c->error->data);
00053 for (uint i = 0; i < c->error->num_params; i++) {
00054 SetDParam(6 + i, c->error->param_value[i]);
00055 }
00056 ShowErrorMessage(STR_NEWGRF_ERROR_FATAL_POPUP, INVALID_STRING_ID, WL_CRITICAL);
00057 break;
00058 }
00059 }
00060
00061 static void ShowNewGRFInfo(const GRFConfig *c, uint x, uint y, uint right, uint bottom, bool show_params)
00062 {
00063 if (c->error != NULL) {
00064 char message[512];
00065 SetDParamStr(0, c->error->custom_message);
00066 SetDParam (1, STR_JUST_RAW_STRING);
00067 SetDParamStr(2, c->filename);
00068 SetDParam (3, STR_JUST_RAW_STRING);
00069 SetDParamStr(4, c->error->data);
00070 for (uint i = 0; i < c->error->num_params; i++) {
00071 SetDParam(5 + i, c->error->param_value[i]);
00072 }
00073 GetString(message, c->error->custom_message == NULL ? c->error->message : STR_JUST_RAW_STRING, lastof(message));
00074
00075 SetDParamStr(0, message);
00076 y = DrawStringMultiLine(x, right, y, bottom, c->error->severity);
00077 }
00078
00079
00080 if (c->filename != NULL) {
00081 SetDParamStr(0, c->filename);
00082 y = DrawStringMultiLine(x, right, y, bottom, STR_NEWGRF_SETTINGS_FILENAME);
00083 }
00084
00085
00086 char buff[256];
00087 snprintf(buff, lengthof(buff), "%08X", BSWAP32(c->ident.grfid));
00088 SetDParamStr(0, buff);
00089 y = DrawStringMultiLine(x, right, y, bottom, STR_NEWGRF_SETTINGS_GRF_ID);
00090
00091 if ((_settings_client.gui.newgrf_developer_tools || _settings_client.gui.newgrf_show_old_versions) && c->version != 0) {
00092 SetDParam(0, c->version);
00093 y = DrawStringMultiLine(x, right, y, bottom, STR_NEWGRF_SETTINGS_VERSION);
00094 }
00095 if ((_settings_client.gui.newgrf_developer_tools || _settings_client.gui.newgrf_show_old_versions) && c->min_loadable_version != 0) {
00096 SetDParam(0, c->min_loadable_version);
00097 y = DrawStringMultiLine(x, right, y, bottom, STR_NEWGRF_SETTINGS_MIN_VERSION);
00098 }
00099
00100
00101 md5sumToString(buff, lastof(buff), c->ident.md5sum);
00102 SetDParamStr(0, buff);
00103 y = DrawStringMultiLine(x, right, y, bottom, STR_NEWGRF_SETTINGS_MD5SUM);
00104
00105
00106 if (show_params) {
00107 if (c->num_params > 0) {
00108 GRFBuildParamList(buff, c, lastof(buff));
00109 SetDParam(0, STR_JUST_RAW_STRING);
00110 SetDParamStr(1, buff);
00111 } else {
00112 SetDParam(0, STR_LAND_AREA_INFORMATION_LOCAL_AUTHORITY_NONE);
00113 }
00114 y = DrawStringMultiLine(x, right, y, bottom, STR_NEWGRF_SETTINGS_PARAMETER);
00115
00116
00117 if (c->palette & GRFP_BLT_32BPP) {
00118 SetDParamStr(0, (c->palette & GRFP_USE_WINDOWS) ? "Windows / 32 bpp" : "DOS / 32 bpp");
00119 } else {
00120 SetDParamStr(0, (c->palette & GRFP_USE_WINDOWS) ? "Windows" : "DOS");
00121 }
00122 y = DrawStringMultiLine(x, right, y, bottom, STR_NEWGRF_SETTINGS_PALETTE);
00123 }
00124
00125
00126 if (c->status == GCS_NOT_FOUND) y = DrawStringMultiLine(x, right, y, bottom, STR_NEWGRF_SETTINGS_NOT_FOUND);
00127 if (c->status == GCS_DISABLED) y = DrawStringMultiLine(x, right, y, bottom, STR_NEWGRF_SETTINGS_DISABLED);
00128 if (HasBit(c->flags, GCF_INVALID)) y = DrawStringMultiLine(x, right, y, bottom, STR_NEWGRF_SETTINGS_INCOMPATIBLE);
00129 if (HasBit(c->flags, GCF_COMPATIBLE)) y = DrawStringMultiLine(x, right, y, bottom, STR_NEWGRF_COMPATIBLE_LOADED);
00130
00131
00132 if (!StrEmpty(c->GetDescription())) {
00133 SetDParam(0, STR_JUST_RAW_STRING);
00134 SetDParamStr(1, c->GetDescription());
00135 y = DrawStringMultiLine(x, right, y, bottom, STR_BLACK_STRING);
00136 } else {
00137 y = DrawStringMultiLine(x, right, y, bottom, STR_NEWGRF_SETTINGS_NO_INFO);
00138 }
00139 }
00140
00144 struct NewGRFParametersWindow : public Window {
00145 static GRFParameterInfo dummy_parameter_info;
00146 GRFConfig *grf_config;
00147 uint clicked_button;
00148 bool clicked_increase;
00149 int timeout;
00150 uint clicked_row;
00151 int line_height;
00152 Scrollbar *vscroll;
00153 bool action14present;
00154 bool editable;
00155
00156 NewGRFParametersWindow(const WindowDesc *desc, GRFConfig *c, bool editable) : Window(),
00157 grf_config(c),
00158 clicked_button(UINT_MAX),
00159 timeout(0),
00160 clicked_row(UINT_MAX),
00161 editable(editable)
00162 {
00163 this->action14present = (c->num_valid_params != lengthof(c->param) || c->param_info.Length() != 0);
00164
00165 this->CreateNestedTree(desc);
00166 this->vscroll = this->GetScrollbar(WID_NP_SCROLLBAR);
00167 this->GetWidget<NWidgetStacked>(WID_NP_SHOW_NUMPAR)->SetDisplayedPlane(this->action14present ? SZSP_HORIZONTAL : 0);
00168 this->GetWidget<NWidgetStacked>(WID_NP_SHOW_DESCRIPTION)->SetDisplayedPlane(this->action14present ? 0 : SZSP_HORIZONTAL);
00169 this->FinishInitNested(desc);
00170
00171 this->SetWidgetDisabledState(WID_NP_RESET, !this->editable);
00172
00173 this->InvalidateData();
00174 }
00175
00181 static GRFParameterInfo *GetDummyParameterInfo(uint nr)
00182 {
00183 dummy_parameter_info.param_nr = nr;
00184 return &dummy_parameter_info;
00185 }
00186
00187 virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize)
00188 {
00189 switch (widget) {
00190 case WID_NP_NUMPAR_DEC:
00191 case WID_NP_NUMPAR_INC: {
00192 size->width = size->height = FONT_HEIGHT_NORMAL;
00193 break;
00194 }
00195
00196 case WID_NP_NUMPAR: {
00197 SetDParam(0, 999);
00198 Dimension d = GetStringBoundingBox(this->GetWidget<NWidgetCore>(widget)->widget_data);
00199 d.width += padding.width;
00200 d.height += padding.height;
00201 *size = maxdim(*size, d);
00202 break;
00203 }
00204
00205 case WID_NP_BACKGROUND:
00206 this->line_height = FONT_HEIGHT_NORMAL + WD_MATRIX_TOP + WD_MATRIX_BOTTOM;
00207
00208 resize->width = 1;
00209 resize->height = this->line_height;
00210 size->height = GB(this->GetWidget<NWidgetCore>(widget)->widget_data, MAT_ROW_START, MAT_ROW_BITS) * this->line_height;
00211 break;
00212
00213 case WID_NP_DESCRIPTION:
00214 size->height = max<uint>(size->height, FONT_HEIGHT_NORMAL * 4 + WD_TEXTPANEL_TOP + WD_TEXTPANEL_BOTTOM);
00215 break;
00216 }
00217 }
00218
00219 virtual void SetStringParameters(int widget) const
00220 {
00221 switch (widget) {
00222 case WID_NP_NUMPAR:
00223 SetDParam(0, this->vscroll->GetCount());
00224 break;
00225 }
00226 }
00227
00228 virtual void DrawWidget(const Rect &r, int widget) const
00229 {
00230 if (widget == WID_NP_DESCRIPTION) {
00231 const GRFParameterInfo *par_info = (this->clicked_row < this->grf_config->param_info.Length()) ? this->grf_config->param_info[this->clicked_row] : NULL;
00232 if (par_info == NULL) return;
00233 const char *desc = GetGRFStringFromGRFText(par_info->desc);
00234 if (desc == NULL) return;
00235 DrawStringMultiLine(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, r.top + WD_TEXTPANEL_TOP, r.bottom - WD_TEXTPANEL_BOTTOM, desc, TC_BLACK);
00236 return;
00237 } else if (widget != WID_NP_BACKGROUND) {
00238 return;
00239 }
00240
00241 bool rtl = _current_text_dir == TD_RTL;
00242 uint buttons_left = rtl ? r.right - 23 : r.left + 4;
00243 uint text_left = r.left + (rtl ? WD_FRAMERECT_LEFT : 28);
00244 uint text_right = r.right - (rtl ? 28 : WD_FRAMERECT_RIGHT);
00245
00246 int y = r.top;
00247 for (uint i = this->vscroll->GetPosition(); this->vscroll->IsVisible(i) && i < this->vscroll->GetCount(); i++) {
00248 GRFParameterInfo *par_info = (i < this->grf_config->param_info.Length()) ? this->grf_config->param_info[i] : NULL;
00249 if (par_info == NULL) par_info = GetDummyParameterInfo(i);
00250 uint32 current_value = par_info->GetValue(this->grf_config);
00251 bool selected = (i == this->clicked_row);
00252
00253 if (par_info->type == PTYPE_BOOL) {
00254 DrawBoolButton(buttons_left, y + 2, current_value != 0, this->editable);
00255 SetDParam(2, par_info->GetValue(this->grf_config) == 0 ? STR_CONFIG_SETTING_OFF : STR_CONFIG_SETTING_ON);
00256 } else if (par_info->type == PTYPE_UINT_ENUM) {
00257 DrawArrowButtons(buttons_left, y + 2, 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);
00258 SetDParam(2, STR_JUST_INT);
00259 SetDParam(3, current_value);
00260 if (par_info->value_names.Contains(current_value)) {
00261 const char *label = GetGRFStringFromGRFText(par_info->value_names.Find(current_value)->second);
00262 if (label != NULL) {
00263 SetDParam(2, STR_JUST_RAW_STRING);
00264 SetDParamStr(3, label);
00265 }
00266 }
00267 }
00268
00269 const char *name = GetGRFStringFromGRFText(par_info->name);
00270 if (name != NULL) {
00271 SetDParam(0, STR_JUST_RAW_STRING);
00272 SetDParamStr(1, name);
00273 } else {
00274 SetDParam(0, STR_NEWGRF_PARAMETERS_DEFAULT_NAME);
00275 SetDParam(1, i + 1);
00276 }
00277
00278 DrawString(text_left, text_right, y + WD_MATRIX_TOP, STR_NEWGRF_PARAMETERS_SETTING, selected ? TC_WHITE : TC_LIGHT_BLUE);
00279 y += this->line_height;
00280 }
00281 }
00282
00283 virtual void OnClick(Point pt, int widget, int click_count)
00284 {
00285 switch (widget) {
00286 case WID_NP_NUMPAR_DEC:
00287 if (this->editable && !this->action14present && this->grf_config->num_params > 0) {
00288 this->grf_config->num_params--;
00289 this->InvalidateData();
00290 SetWindowDirty(WC_GAME_OPTIONS, WN_GAME_OPTIONS_NEWGRF_STATE);
00291 }
00292 break;
00293
00294 case WID_NP_NUMPAR_INC: {
00295 GRFConfig *c = this->grf_config;
00296 if (this->editable && !this->action14present && c->num_params < c->num_valid_params) {
00297 c->param[c->num_params++] = 0;
00298 this->InvalidateData();
00299 SetWindowDirty(WC_GAME_OPTIONS, WN_GAME_OPTIONS_NEWGRF_STATE);
00300 }
00301 break;
00302 }
00303
00304 case WID_NP_BACKGROUND: {
00305 if (!this->editable) break;
00306 uint num = this->vscroll->GetScrolledRowFromWidget(pt.y, this, WID_NP_BACKGROUND);
00307 if (num >= this->vscroll->GetCount()) break;
00308 if (this->clicked_row != num) {
00309 DeleteChildWindows(WC_QUERY_STRING);
00310 this->clicked_row = num;
00311 }
00312
00313 const NWidgetBase *wid = this->GetWidget<NWidgetBase>(WID_NP_BACKGROUND);
00314 int x = pt.x - wid->pos_x;
00315 if (_current_text_dir == TD_RTL) x = wid->current_x - x;
00316 x -= 4;
00317
00318 GRFParameterInfo *par_info = (num < this->grf_config->param_info.Length()) ? this->grf_config->param_info[num] : NULL;
00319 if (par_info == NULL) par_info = GetDummyParameterInfo(num);
00320
00321
00322 if (IsInsideMM(x, 0, 21)) {
00323 uint32 val = par_info->GetValue(this->grf_config);
00324 uint32 old_val = val;
00325 if (par_info->type == PTYPE_BOOL) {
00326 val = !val;
00327 } else {
00328 if (x >= 10) {
00329
00330 if (val < par_info->max_value) val++;
00331 this->clicked_increase = true;
00332 } else {
00333
00334 if (val > par_info->min_value) val--;
00335 this->clicked_increase = false;
00336 }
00337 }
00338 if (val != old_val) {
00339 par_info->SetValue(this->grf_config, val);
00340
00341 this->clicked_button = num;
00342 this->timeout = 5;
00343 }
00344 } else if (par_info->type == PTYPE_UINT_ENUM && click_count >= 2) {
00345
00346 SetDParam(0, this->grf_config->param[num]);
00347 ShowQueryString(STR_JUST_INT, STR_CONFIG_SETTING_QUERY_CAPTION, 10, this, CS_NUMERAL, QSF_NONE);
00348 }
00349 this->SetDirty();
00350 break;
00351 }
00352
00353 case WID_NP_RESET:
00354 if (!this->editable) break;
00355 this->grf_config->SetParameterDefaults();
00356 this->InvalidateData();
00357 SetWindowDirty(WC_GAME_OPTIONS, WN_GAME_OPTIONS_NEWGRF_STATE);
00358 break;
00359
00360 case WID_NP_ACCEPT:
00361 delete this;
00362 break;
00363 }
00364 }
00365
00366 virtual void OnQueryTextFinished(char *str)
00367 {
00368 if (StrEmpty(str)) return;
00369 int32 value = atoi(str);
00370 GRFParameterInfo *par_info = ((uint)this->clicked_row < this->grf_config->param_info.Length()) ? this->grf_config->param_info[this->clicked_row] : NULL;
00371 if (par_info == NULL) par_info = GetDummyParameterInfo(this->clicked_row);
00372 uint32 val = Clamp<uint32>(value, par_info->min_value, par_info->max_value);
00373 par_info->SetValue(this->grf_config, val);
00374 this->SetDirty();
00375 }
00376
00377 virtual void OnResize()
00378 {
00379 NWidgetCore *nwi = this->GetWidget<NWidgetCore>(WID_NP_BACKGROUND);
00380 this->vscroll->SetCapacity(nwi->current_y / this->line_height);
00381 nwi->widget_data = (this->vscroll->GetCapacity() << MAT_ROW_START) + (1 << MAT_COL_START);
00382 }
00383
00389 virtual void OnInvalidateData(int data = 0, bool gui_scope = true)
00390 {
00391 if (!gui_scope) return;
00392 if (!this->action14present) {
00393 this->SetWidgetDisabledState(WID_NP_NUMPAR_DEC, !this->editable || this->grf_config->num_params == 0);
00394 this->SetWidgetDisabledState(WID_NP_NUMPAR_INC, !this->editable || this->grf_config->num_params >= this->grf_config->num_valid_params);
00395 }
00396
00397 this->vscroll->SetCount(this->action14present ? this->grf_config->num_valid_params : this->grf_config->num_params);
00398 if (this->clicked_row != UINT_MAX && this->clicked_row >= this->vscroll->GetCount()) {
00399 this->clicked_row = UINT_MAX;
00400 DeleteChildWindows(WC_QUERY_STRING);
00401 }
00402 }
00403
00404 virtual void OnTick()
00405 {
00406 if (--this->timeout == 0) {
00407 this->clicked_button = UINT_MAX;
00408 this->SetDirty();
00409 }
00410 }
00411 };
00412 GRFParameterInfo NewGRFParametersWindow::dummy_parameter_info(0);
00413
00414
00415 static const NWidgetPart _nested_newgrf_parameter_widgets[] = {
00416 NWidget(NWID_HORIZONTAL),
00417 NWidget(WWT_CLOSEBOX, COLOUR_MAUVE),
00418 NWidget(WWT_CAPTION, COLOUR_MAUVE), SetDataTip(STR_NEWGRF_PARAMETERS_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
00419 EndContainer(),
00420 NWidget(NWID_SELECTION, INVALID_COLOUR, WID_NP_SHOW_NUMPAR),
00421 NWidget(WWT_PANEL, COLOUR_MAUVE), SetResize(1, 0), SetFill(1, 0), SetPIP(4, 0, 4),
00422 NWidget(NWID_HORIZONTAL), SetPIP(4, 0, 4),
00423 NWidget(WWT_PUSHARROWBTN, COLOUR_YELLOW, WID_NP_NUMPAR_DEC), SetMinimalSize(12, 12), SetDataTip(AWV_DECREASE, STR_NULL),
00424 NWidget(WWT_PUSHARROWBTN, COLOUR_YELLOW, WID_NP_NUMPAR_INC), SetMinimalSize(12, 12), SetDataTip(AWV_INCREASE, STR_NULL),
00425 NWidget(WWT_TEXT, COLOUR_MAUVE, WID_NP_NUMPAR), SetResize(1, 0), SetFill(1, 0), SetPadding(0, 0, 0, 4), SetDataTip(STR_NEWGRF_PARAMETERS_NUM_PARAM, STR_NULL),
00426 EndContainer(),
00427 EndContainer(),
00428 EndContainer(),
00429 NWidget(NWID_HORIZONTAL),
00430 NWidget(WWT_MATRIX, COLOUR_MAUVE, WID_NP_BACKGROUND), SetMinimalSize(188, 182), SetResize(1, 1), SetFill(1, 0), SetDataTip(0x501, STR_NULL), SetScrollbar(WID_NP_SCROLLBAR),
00431 NWidget(NWID_VSCROLLBAR, COLOUR_MAUVE, WID_NP_SCROLLBAR),
00432 EndContainer(),
00433 NWidget(NWID_SELECTION, INVALID_COLOUR, WID_NP_SHOW_DESCRIPTION),
00434 NWidget(WWT_PANEL, COLOUR_MAUVE, WID_NP_DESCRIPTION), SetResize(1, 0), SetFill(1, 0),
00435 EndContainer(),
00436 EndContainer(),
00437 NWidget(NWID_HORIZONTAL),
00438 NWidget(NWID_HORIZONTAL, NC_EQUALSIZE),
00439 NWidget(WWT_PUSHTXTBTN, COLOUR_MAUVE, WID_NP_ACCEPT), SetResize(1, 0), SetFill(1, 0), SetDataTip(STR_NEWGRF_PARAMETERS_CLOSE, STR_NULL),
00440 NWidget(WWT_PUSHTXTBTN, COLOUR_MAUVE, WID_NP_RESET), SetResize(1, 0), SetFill(1, 0), SetDataTip(STR_NEWGRF_PARAMETERS_RESET, STR_NEWGRF_PARAMETERS_RESET_TOOLTIP),
00441 EndContainer(),
00442 NWidget(WWT_RESIZEBOX, COLOUR_MAUVE),
00443 EndContainer(),
00444 };
00445
00447 static const WindowDesc _newgrf_parameters_desc(
00448 WDP_CENTER, 500, 208,
00449 WC_GRF_PARAMETERS, WC_NONE,
00450 WDF_UNCLICK_BUTTONS,
00451 _nested_newgrf_parameter_widgets, lengthof(_nested_newgrf_parameter_widgets)
00452 );
00453
00454 static void OpenGRFParameterWindow(GRFConfig *c, bool editable)
00455 {
00456 DeleteWindowByClass(WC_GRF_PARAMETERS);
00457 new NewGRFParametersWindow(&_newgrf_parameters_desc, c, editable);
00458 }
00459
00461 struct NewGRFTextfileWindow : public Window, MissingGlyphSearcher {
00462 const GRFConfig *grf_config;
00463 TextfileType file_type;
00464 int line_height;
00465 Scrollbar *vscroll;
00466 Scrollbar *hscroll;
00467 char *text;
00468 SmallVector<const char *, 64> lines;
00469 uint max_length;
00470
00471 static const int TOP_SPACING = WD_FRAMETEXT_TOP;
00472 static const int BOTTOM_SPACING = WD_FRAMETEXT_BOTTOM;
00473
00474 NewGRFTextfileWindow(const WindowDesc *desc, const GRFConfig *c, TextfileType file_type) : Window(), grf_config(c), file_type(file_type)
00475 {
00476 this->CreateNestedTree(desc);
00477 this->GetWidget<NWidgetCore>(WID_NT_CAPTION)->SetDataTip(STR_NEWGRF_README_CAPTION + file_type, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS);
00478 this->vscroll = this->GetScrollbar(WID_NT_VSCROLLBAR);
00479 this->hscroll = this->GetScrollbar(WID_NT_HSCROLLBAR);
00480 this->FinishInitNested(desc);
00481
00482 this->LoadTextfile();
00483 }
00484
00485 ~NewGRFTextfileWindow()
00486 {
00487 free(this->text);
00488 }
00489
00490 virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize)
00491 {
00492 switch (widget) {
00493 case WID_NT_BACKGROUND:
00494 this->line_height = FONT_HEIGHT_MONO + 2;
00495 resize->height = this->line_height;
00496
00497 size->height = 4 * resize->height + TOP_SPACING + BOTTOM_SPACING;
00498 size->width = max(200u, size->width);
00499 break;
00500 }
00501 }
00502
00503 virtual void SetStringParameters(int widget) const
00504 {
00505 if (widget == WID_NT_CAPTION) SetDParamStr(0, this->grf_config->GetName());
00506 }
00507
00508 virtual void DrawWidget(const Rect &r, int widget) const
00509 {
00510 if (widget != WID_NT_BACKGROUND) return;
00511
00512 int width = r.right - r.left + 1 - WD_BEVEL_LEFT - WD_BEVEL_RIGHT;
00513 int height = r.bottom - r.top + 1 - WD_BEVEL_LEFT - WD_BEVEL_RIGHT;
00514
00515 DrawPixelInfo new_dpi;
00516 if (!FillDrawPixelInfo(&new_dpi, r.left + WD_BEVEL_LEFT, r.top, width, height)) return;
00517 DrawPixelInfo *old_dpi = _cur_dpi;
00518 _cur_dpi = &new_dpi;
00519
00520 int left, right;
00521 if (_current_text_dir == TD_RTL) {
00522 left = width + WD_BEVEL_RIGHT - WD_FRAMETEXT_RIGHT - this->hscroll->GetCount();
00523 right = width + WD_BEVEL_RIGHT - WD_FRAMETEXT_RIGHT - 1 + this->hscroll->GetPosition();
00524 } else {
00525 left = WD_FRAMETEXT_LEFT - WD_BEVEL_LEFT - this->hscroll->GetPosition();
00526 right = WD_FRAMETEXT_LEFT - WD_BEVEL_LEFT + this->hscroll->GetCount() - 1;
00527 }
00528 int top = TOP_SPACING;
00529 for (uint i = 0; i < this->vscroll->GetCapacity() && i + this->vscroll->GetPosition() < this->lines.Length(); i++) {
00530 DrawString(left, right, top + i * this->line_height, this->lines[i + this->vscroll->GetPosition()], TC_WHITE, SA_LEFT, false, FS_MONO);
00531 }
00532
00533 _cur_dpi = old_dpi;
00534 }
00535
00536 virtual void OnResize()
00537 {
00538 this->vscroll->SetCapacityFromWidget(this, WID_NT_BACKGROUND, TOP_SPACING + BOTTOM_SPACING);
00539 this->hscroll->SetCapacityFromWidget(this, WID_NT_BACKGROUND);
00540 }
00541
00542 private:
00543 uint search_iterator;
00544
00545 void Reset()
00546 {
00547 this->search_iterator = 0;
00548 }
00549
00550 FontSize DefaultSize()
00551 {
00552 return FS_MONO;
00553 }
00554
00555 const char *NextString()
00556 {
00557 if (this->search_iterator >= this->lines.Length()) return NULL;
00558
00559 return this->lines[this->search_iterator++];
00560 }
00561
00562 bool Monospace()
00563 {
00564 return true;
00565 }
00566
00567 void SetFontNames(FreeTypeSettings *settings, const char *font_name)
00568 {
00569 #ifdef WITH_FREETYPE
00570 strecpy(settings->mono_font, font_name, lastof(settings->mono_font));
00571 #endif
00572 }
00573
00577 void LoadTextfile()
00578 {
00579 this->lines.Clear();
00580
00581
00582 const char *textfile = this->grf_config->GetTextfile(file_type);
00583 if (textfile == NULL) return;
00584
00585
00586 size_t filesize;
00587 FILE *handle = FioFOpenFile(textfile, "rb", NEWGRF_DIR, &filesize);
00588 if (handle == NULL) return;
00589
00590 this->text = ReallocT(this->text, filesize + 1);
00591 size_t read = fread(this->text, 1, filesize, handle);
00592 fclose(handle);
00593
00594 if (read != filesize) return;
00595
00596 this->text[filesize] = '\0';
00597
00598
00599 for (char *p = this->text; *p != '\0'; p++) {
00600 if (*p == '\t' || *p == '\r') *p = ' ';
00601 }
00602
00603
00604 char *p = this->text + (strncmp("\xEF\xBB\xBF", this->text, 3) == 0 ? 3 : 0);
00605
00606
00607 str_validate(p, this->text + filesize, SVS_REPLACE_WITH_QUESTION_MARK | SVS_ALLOW_NEWLINE);
00608
00609
00610 *this->lines.Append() = p;
00611 for (; *p != '\0'; p++) {
00612 if (*p == '\n') {
00613 *p = '\0';
00614 *this->lines.Append() = p + 1;
00615 }
00616 }
00617
00618 CheckForMissingGlyphs(true, this);
00619
00620
00621 this->vscroll->SetCount(this->lines.Length());
00622
00623 this->max_length = 0;
00624 for (uint i = 0; i < this->lines.Length(); i++) {
00625 this->max_length = max(this->max_length, GetStringBoundingBox(this->lines[i], FS_MONO).width);
00626 }
00627 this->hscroll->SetCount(this->max_length + WD_FRAMETEXT_LEFT + WD_FRAMETEXT_RIGHT);
00628 this->hscroll->SetStepSize(10);
00629 }
00630 };
00631
00632 static const NWidgetPart _nested_newgrf_textfile_widgets[] = {
00633 NWidget(NWID_HORIZONTAL),
00634 NWidget(WWT_CLOSEBOX, COLOUR_MAUVE),
00635 NWidget(WWT_CAPTION, COLOUR_MAUVE, WID_NT_CAPTION), SetDataTip(STR_NULL, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
00636 EndContainer(),
00637 NWidget(NWID_HORIZONTAL),
00638 NWidget(WWT_PANEL, COLOUR_MAUVE, WID_NT_BACKGROUND), SetMinimalSize(200, 125), SetResize(1, 12), SetScrollbar(WID_NT_VSCROLLBAR),
00639 EndContainer(),
00640 NWidget(NWID_VERTICAL),
00641 NWidget(NWID_VSCROLLBAR, COLOUR_MAUVE, WID_NT_VSCROLLBAR),
00642 EndContainer(),
00643 EndContainer(),
00644 NWidget(NWID_HORIZONTAL),
00645 NWidget(NWID_HSCROLLBAR, COLOUR_MAUVE, WID_NT_HSCROLLBAR),
00646 NWidget(WWT_RESIZEBOX, COLOUR_MAUVE),
00647 EndContainer(),
00648 };
00649
00651 static const WindowDesc _newgrf_textfile_desc(
00652 WDP_CENTER, 630, 460,
00653 WC_NEWGRF_TEXTFILE, WC_NONE,
00654 WDF_UNCLICK_BUTTONS,
00655 _nested_newgrf_textfile_widgets, lengthof(_nested_newgrf_textfile_widgets)
00656 );
00657
00658 void ShowNewGRFTextfileWindow(const GRFConfig *c, TextfileType file_type)
00659 {
00660 DeleteWindowByClass(WC_NEWGRF_TEXTFILE);
00661 new NewGRFTextfileWindow(&_newgrf_textfile_desc, c, file_type);
00662 }
00663
00664 static GRFPresetList _grf_preset_list;
00665
00666 class DropDownListPresetItem : public DropDownListItem {
00667 public:
00668 DropDownListPresetItem(int result) : DropDownListItem(result, false) {}
00669
00670 virtual ~DropDownListPresetItem() {}
00671
00672 bool Selectable() const
00673 {
00674 return true;
00675 }
00676
00677 void Draw(int left, int right, int top, int bottom, bool sel, int bg_colour) const
00678 {
00679 DrawString(left + 2, right + 2, top, _grf_preset_list[this->result], sel ? TC_WHITE : TC_BLACK);
00680 }
00681 };
00682
00683 static void NewGRFConfirmationCallback(Window *w, bool confirmed);
00684
00688 struct NewGRFWindow : public QueryStringBaseWindow, NewGRFScanCallback {
00689 typedef GUIList<const GRFConfig *> GUIGRFConfigList;
00690
00691 static const uint EDITBOX_MAX_SIZE = 50;
00692
00693 static Listing last_sorting;
00694 static Filtering last_filtering;
00695 static GUIGRFConfigList::SortFunction * const sorter_funcs[];
00696 static GUIGRFConfigList::FilterFunction * const filter_funcs[];
00697
00698 GUIGRFConfigList avails;
00699 const GRFConfig *avail_sel;
00700 int avail_pos;
00701
00702 GRFConfig *actives;
00703 GRFConfig *active_sel;
00704
00705 GRFConfig **orig_list;
00706 bool editable;
00707 bool show_params;
00708 bool execute;
00709 int preset;
00710
00711 Scrollbar *vscroll;
00712 Scrollbar *vscroll2;
00713
00714 NewGRFWindow(const WindowDesc *desc, bool editable, bool show_params, bool execute, GRFConfig **orig_list) : QueryStringBaseWindow(EDITBOX_MAX_SIZE)
00715 {
00716 this->avail_sel = NULL;
00717 this->avail_pos = -1;
00718 this->active_sel = NULL;
00719 this->actives = NULL;
00720 this->orig_list = orig_list;
00721 this->editable = editable;
00722 this->execute = execute;
00723 this->show_params = show_params;
00724 this->preset = -1;
00725
00726 CopyGRFConfigList(&this->actives, *orig_list, false);
00727 GetGRFPresetList(&_grf_preset_list);
00728
00729 this->CreateNestedTree(desc);
00730 this->vscroll = this->GetScrollbar(WID_NS_SCROLLBAR);
00731 this->vscroll2 = this->GetScrollbar(WID_NS_SCROLL2BAR);
00732
00733 this->GetWidget<NWidgetStacked>(WID_NS_SHOW_REMOVE)->SetDisplayedPlane(this->editable ? 0 : 1);
00734 this->GetWidget<NWidgetStacked>(WID_NS_SHOW_APPLY)->SetDisplayedPlane(this->editable ? 0 : this->show_params ? 1 : SZSP_HORIZONTAL);
00735 this->FinishInitNested(desc, WN_GAME_OPTIONS_NEWGRF_STATE);
00736
00737 InitializeTextBuffer(&this->text, this->edit_str_buf, this->edit_str_size);
00738 this->SetFocusedWidget(WID_NS_FILTER);
00739
00740 this->avails.SetListing(this->last_sorting);
00741 this->avails.SetFiltering(this->last_filtering);
00742 this->avails.SetSortFuncs(this->sorter_funcs);
00743 this->avails.SetFilterFuncs(this->filter_funcs);
00744 this->avails.ForceRebuild();
00745
00746 this->OnInvalidateData(GOID_NEWGRF_LIST_EDITED);
00747 }
00748
00749 ~NewGRFWindow()
00750 {
00751 DeleteWindowByClass(WC_GRF_PARAMETERS);
00752 DeleteWindowByClass(WC_NEWGRF_TEXTFILE);
00753
00754 if (this->editable && !this->execute) {
00755 CopyGRFConfigList(this->orig_list, this->actives, true);
00756 ResetGRFConfig(false);
00757 ReloadNewGRFData();
00758 }
00759
00760
00761 ClearGRFConfigList(&this->actives);
00762 _grf_preset_list.Clear();
00763 }
00764
00765 virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize)
00766 {
00767 switch (widget) {
00768 case WID_NS_FILE_LIST:
00769 {
00770 Dimension d = maxdim(GetSpriteSize(SPR_SQUARE), GetSpriteSize(SPR_WARNING_SIGN));
00771 resize->height = max(d.height + 2U, FONT_HEIGHT_NORMAL + 2U);
00772 size->height = max(size->height, WD_FRAMERECT_TOP + 6 * resize->height + WD_FRAMERECT_BOTTOM);
00773 break;
00774 }
00775
00776 case WID_NS_AVAIL_LIST:
00777 resize->height = max(12, FONT_HEIGHT_NORMAL + 2);
00778 size->height = max(size->height, WD_FRAMERECT_TOP + 8 * resize->height + WD_FRAMERECT_BOTTOM);
00779 break;
00780
00781 case WID_NS_NEWGRF_INFO_TITLE: {
00782 Dimension dim = GetStringBoundingBox(STR_NEWGRF_SETTINGS_INFO_TITLE);
00783 size->height = max(size->height, dim.height + WD_FRAMETEXT_TOP + WD_FRAMETEXT_BOTTOM);
00784 size->width = max(size->width, dim.width + WD_FRAMETEXT_LEFT + WD_FRAMETEXT_RIGHT);
00785 break;
00786 }
00787
00788 case WID_NS_NEWGRF_INFO:
00789 size->height = max(size->height, WD_FRAMERECT_TOP + 10 * FONT_HEIGHT_NORMAL + WD_FRAMERECT_BOTTOM + padding.height + 2);
00790 break;
00791
00792 case WID_NS_PRESET_LIST: {
00793 Dimension d = GetStringBoundingBox(STR_NUM_CUSTOM);
00794 for (uint i = 0; i < _grf_preset_list.Length(); i++) {
00795 if (_grf_preset_list[i] != NULL) {
00796 SetDParamStr(0, _grf_preset_list[i]);
00797 d = maxdim(d, GetStringBoundingBox(STR_JUST_RAW_STRING));
00798 }
00799 }
00800 d.width += padding.width;
00801 *size = maxdim(d, *size);
00802 break;
00803 }
00804
00805 case WID_NS_CONTENT_DOWNLOAD:
00806 case WID_NS_CONTENT_DOWNLOAD2: {
00807 Dimension d = GetStringBoundingBox(STR_NEWGRF_SETTINGS_FIND_MISSING_CONTENT_BUTTON);
00808 *size = maxdim(d, GetStringBoundingBox(STR_INTRO_ONLINE_CONTENT));
00809 size->width += padding.width;
00810 size->height += padding.height;
00811 break;
00812 }
00813 }
00814 }
00815
00816 virtual void OnResize()
00817 {
00818 this->vscroll->SetCapacityFromWidget(this, WID_NS_FILE_LIST);
00819 this->vscroll2->SetCapacityFromWidget(this, WID_NS_AVAIL_LIST);
00820 }
00821
00822 virtual void SetStringParameters(int widget) const
00823 {
00824 switch (widget) {
00825 case WID_NS_PRESET_LIST:
00826 if (this->preset == -1) {
00827 SetDParam(0, STR_NUM_CUSTOM);
00828 } else {
00829 SetDParam(0, STR_JUST_RAW_STRING);
00830 SetDParamStr(1, _grf_preset_list[this->preset]);
00831 }
00832 break;
00833 }
00834 }
00835
00836 virtual void OnPaint()
00837 {
00838 this->DrawWidgets();
00839 if (this->editable) this->DrawEditBox(WID_NS_FILTER);
00840 }
00841
00847 inline PaletteID GetPalette(const GRFConfig *c) const
00848 {
00849 PaletteID pal;
00850
00851
00852 switch (c->status) {
00853 case GCS_NOT_FOUND:
00854 case GCS_DISABLED:
00855 pal = PALETTE_TO_RED;
00856 break;
00857 case GCS_ACTIVATED:
00858 pal = PALETTE_TO_GREEN;
00859 break;
00860 default:
00861 pal = PALETTE_TO_BLUE;
00862 break;
00863 }
00864
00865
00866 if (pal != PALETTE_TO_RED) {
00867 if (HasBit(c->flags, GCF_STATIC)) {
00868 pal = PALETTE_TO_GREY;
00869 } else if (HasBit(c->flags, GCF_COMPATIBLE)) {
00870 pal = PALETTE_TO_ORANGE;
00871 }
00872 }
00873
00874 return pal;
00875 }
00876
00877 virtual void DrawWidget(const Rect &r, int widget) const
00878 {
00879 switch (widget) {
00880 case WID_NS_FILE_LIST: {
00881 GfxFillRect(r.left + 1, r.top + 1, r.right - 1, r.bottom - 1, PC_BLACK);
00882
00883 uint step_height = this->GetWidget<NWidgetBase>(WID_NS_FILE_LIST)->resize_y;
00884 uint y = r.top + WD_FRAMERECT_TOP;
00885 Dimension square = GetSpriteSize(SPR_SQUARE);
00886 Dimension warning = GetSpriteSize(SPR_WARNING_SIGN);
00887 int square_offset_y = (step_height - square.height) / 2;
00888 int warning_offset_y = (step_height - warning.height) / 2;
00889 int offset_y = (step_height - FONT_HEIGHT_NORMAL) / 2;
00890
00891 bool rtl = _current_text_dir == TD_RTL;
00892 uint text_left = rtl ? r.left + WD_FRAMERECT_LEFT : r.left + square.width + 15;
00893 uint text_right = rtl ? r.right - square.width - 15 : r.right - WD_FRAMERECT_RIGHT;
00894 uint square_left = rtl ? r.right - square.width - 5 : r.left + 5;
00895 uint warning_left = rtl ? r.right - square.width - warning.width - 10 : r.left + square.width + 10;
00896
00897 int i = 0;
00898 for (const GRFConfig *c = this->actives; c != NULL; c = c->next, i++) {
00899 if (this->vscroll->IsVisible(i)) {
00900 const char *text = c->GetName();
00901 bool h = (this->active_sel == c);
00902 PaletteID pal = this->GetPalette(c);
00903
00904 if (h) GfxFillRect(r.left + 1, y, r.right - 1, y + step_height - 1, PC_DARK_BLUE);
00905 DrawSprite(SPR_SQUARE, pal, square_left, y + square_offset_y);
00906 if (c->error != NULL) DrawSprite(SPR_WARNING_SIGN, 0, warning_left, y + warning_offset_y);
00907 uint txtoffset = c->error == NULL ? 0 : warning.width;
00908 DrawString(text_left + (rtl ? 0 : txtoffset), text_right - (rtl ? txtoffset : 0), y + offset_y, text, h ? TC_WHITE : TC_ORANGE);
00909 y += step_height;
00910 }
00911 }
00912 break;
00913 }
00914
00915 case WID_NS_AVAIL_LIST: {
00916 GfxFillRect(r.left + 1, r.top + 1, r.right - 1, r.bottom - 1, PC_BLACK);
00917
00918 uint step_height = this->GetWidget<NWidgetBase>(WID_NS_AVAIL_LIST)->resize_y;
00919 int offset_y = (step_height - FONT_HEIGHT_NORMAL) / 2;
00920 uint y = r.top + WD_FRAMERECT_TOP;
00921 uint min_index = this->vscroll2->GetPosition();
00922 uint max_index = min(min_index + this->vscroll2->GetCapacity(), this->avails.Length());
00923
00924 for (uint i = min_index; i < max_index; i++) {
00925 const GRFConfig *c = this->avails[i];
00926 bool h = (c == this->avail_sel);
00927 const char *text = c->GetName();
00928
00929 if (h) GfxFillRect(r.left + 1, y, r.right - 1, y + step_height - 1, PC_DARK_BLUE);
00930 DrawString(r.left + WD_FRAMERECT_LEFT, r.right - WD_FRAMERECT_RIGHT, y + offset_y, text, h ? TC_WHITE : TC_SILVER);
00931 y += step_height;
00932 }
00933 break;
00934 }
00935
00936 case WID_NS_NEWGRF_INFO_TITLE:
00937
00938 GfxFillRect(r.left + 1, r.top + 1, r.right - 1, r.bottom - 1, PC_DARK_BLUE);
00939 DrawString(r.left, r.right, (r.top + r.bottom - FONT_HEIGHT_NORMAL) / 2, STR_NEWGRF_SETTINGS_INFO_TITLE, TC_FROMSTRING, SA_HOR_CENTER);
00940 break;
00941
00942 case WID_NS_NEWGRF_INFO: {
00943 const GRFConfig *selected = this->active_sel;
00944 if (selected == NULL) selected = this->avail_sel;
00945 if (selected != NULL) {
00946 ShowNewGRFInfo(selected, r.left + WD_FRAMERECT_LEFT, r.top + WD_FRAMERECT_TOP, r.right - WD_FRAMERECT_RIGHT, r.bottom - WD_FRAMERECT_BOTTOM, this->show_params);
00947 }
00948 break;
00949 }
00950 }
00951 }
00952
00953 virtual void OnClick(Point pt, int widget, int click_count)
00954 {
00955 if (widget >= WID_NS_NEWGRF_TEXTFILE && widget < WID_NS_NEWGRF_TEXTFILE + TFT_END) {
00956 if (this->active_sel == NULL && this->avail_sel == NULL) return;
00957
00958 ShowNewGRFTextfileWindow(this->active_sel != NULL ? this->active_sel : this->avail_sel, (TextfileType)(widget - WID_NS_NEWGRF_TEXTFILE));
00959 return;
00960 }
00961
00962 switch (widget) {
00963 case WID_NS_PRESET_LIST: {
00964 DropDownList *list = new DropDownList();
00965
00966
00967 list->push_back(new DropDownListStringItem(STR_NONE, -1, false));
00968
00969 for (uint i = 0; i < _grf_preset_list.Length(); i++) {
00970 if (_grf_preset_list[i] != NULL) {
00971 list->push_back(new DropDownListPresetItem(i));
00972 }
00973 }
00974
00975 this->DeleteChildWindows(WC_QUERY_STRING);
00976 ShowDropDownList(this, list, this->preset, WID_NS_PRESET_LIST);
00977 break;
00978 }
00979
00980 case WID_NS_OPEN_URL: {
00981 const GRFConfig *c = (this->avail_sel == NULL) ? this->active_sel : this->avail_sel;
00982
00983 extern void OpenBrowser(const char *url);
00984 OpenBrowser(c->GetURL());
00985 break;
00986 }
00987
00988 case WID_NS_PRESET_SAVE:
00989 ShowQueryString(STR_EMPTY, STR_NEWGRF_SETTINGS_PRESET_SAVE_QUERY, 32, this, CS_ALPHANUMERAL, QSF_NONE);
00990 break;
00991
00992 case WID_NS_PRESET_DELETE:
00993 if (this->preset == -1) return;
00994
00995 DeleteGRFPresetFromConfig(_grf_preset_list[this->preset]);
00996 GetGRFPresetList(&_grf_preset_list);
00997 this->preset = -1;
00998 this->InvalidateData();
00999 this->DeleteChildWindows(WC_QUERY_STRING);
01000 break;
01001
01002 case WID_NS_MOVE_UP: {
01003 if (this->active_sel == NULL || !this->editable) break;
01004
01005 int pos = 0;
01006 for (GRFConfig **pc = &this->actives; *pc != NULL; pc = &(*pc)->next, pos++) {
01007 GRFConfig *c = *pc;
01008 if (c->next == this->active_sel) {
01009 c->next = this->active_sel->next;
01010 this->active_sel->next = c;
01011 *pc = this->active_sel;
01012 break;
01013 }
01014 }
01015 this->vscroll->ScrollTowards(pos);
01016 this->preset = -1;
01017 this->InvalidateData();
01018 break;
01019 }
01020
01021 case WID_NS_MOVE_DOWN: {
01022 if (this->active_sel == NULL || !this->editable) break;
01023
01024 int pos = 1;
01025 for (GRFConfig **pc = &this->actives; *pc != NULL; pc = &(*pc)->next, pos++) {
01026 GRFConfig *c = *pc;
01027 if (c == this->active_sel) {
01028 *pc = c->next;
01029 c->next = c->next->next;
01030 (*pc)->next = c;
01031 break;
01032 }
01033 }
01034 this->vscroll->ScrollTowards(pos);
01035 this->preset = -1;
01036 this->InvalidateData();
01037 break;
01038 }
01039
01040 case WID_NS_FILE_LIST: {
01041 uint i = this->vscroll->GetScrolledRowFromWidget(pt.y, this, WID_NS_FILE_LIST);
01042
01043 GRFConfig *c;
01044 for (c = this->actives; c != NULL && i > 0; c = c->next, i--) {}
01045
01046 if (this->active_sel != c) DeleteWindowByClass(WC_GRF_PARAMETERS);
01047 this->active_sel = c;
01048 this->avail_sel = NULL;
01049 this->avail_pos = -1;
01050
01051 this->InvalidateData();
01052 if (click_count == 1) break;
01053
01054 }
01055
01056 case WID_NS_REMOVE: {
01057 if (this->active_sel == NULL || !this->editable) break;
01058 DeleteWindowByClass(WC_GRF_PARAMETERS);
01059
01060
01061 GRFConfig *newsel = this->active_sel->next;
01062 for (GRFConfig **pc = &this->actives; *pc != NULL; pc = &(*pc)->next) {
01063 GRFConfig *c = *pc;
01064
01065
01066 if (newsel == NULL && c->next == this->active_sel) newsel = c;
01067
01068 if (c == this->active_sel) {
01069 *pc = c->next;
01070 delete c;
01071 break;
01072 }
01073 }
01074
01075 this->active_sel = newsel;
01076 this->preset = -1;
01077 this->avail_pos = -1;
01078 this->avail_sel = NULL;
01079 this->avails.ForceRebuild();
01080 this->InvalidateData(GOID_NEWGRF_LIST_EDITED);
01081 break;
01082 }
01083
01084 case WID_NS_AVAIL_LIST: {
01085 uint i = this->vscroll2->GetScrolledRowFromWidget(pt.y, this, WID_NS_AVAIL_LIST);
01086 this->active_sel = NULL;
01087 DeleteWindowByClass(WC_GRF_PARAMETERS);
01088 if (i < this->avails.Length()) {
01089 this->avail_sel = this->avails[i];
01090 this->avail_pos = i;
01091 }
01092 this->InvalidateData();
01093 if (click_count == 1) break;
01094
01095 }
01096
01097 case WID_NS_ADD: {
01098 if (this->avail_sel == NULL || !this->editable || HasBit(this->avail_sel->flags, GCF_INVALID)) break;
01099
01100 GRFConfig **list;
01101
01102 for (list = &this->actives; *list != NULL; list = &(*list)->next) {
01103 if ((*list)->ident.grfid == this->avail_sel->ident.grfid) {
01104 ShowErrorMessage(STR_NEWGRF_DUPLICATE_GRFID, INVALID_STRING_ID, WL_INFO);
01105 return;
01106 }
01107 }
01108
01109 GRFConfig *c = new GRFConfig(*this->avail_sel);
01110 c->SetParameterDefaults();
01111 *list = c;
01112
01113
01114 int new_pos = this->avail_pos + 1;
01115 if (new_pos >= (int)this->avails.Length()) new_pos = this->avail_pos - 1;
01116 this->avail_pos = new_pos;
01117 if (new_pos >= 0) this->avail_sel = this->avails[new_pos];
01118
01119 this->avails.ForceRebuild();
01120 this->InvalidateData(GOID_NEWGRF_LIST_EDITED);
01121 break;
01122 }
01123
01124 case WID_NS_APPLY_CHANGES:
01125 if (!this->editable) break;
01126 if (this->execute) {
01127 ShowQuery(
01128 STR_NEWGRF_POPUP_CAUTION_CAPTION,
01129 STR_NEWGRF_CONFIRMATION_TEXT,
01130 this,
01131 NewGRFConfirmationCallback
01132 );
01133 } else {
01134 CopyGRFConfigList(this->orig_list, this->actives, true);
01135 ResetGRFConfig(false);
01136 ReloadNewGRFData();
01137 }
01138 this->DeleteChildWindows(WC_QUERY_STRING);
01139 break;
01140
01141 case WID_NS_VIEW_PARAMETERS:
01142 case WID_NS_SET_PARAMETERS: {
01143 if (this->active_sel == NULL || !this->show_params || this->active_sel->num_valid_params == 0) break;
01144
01145 OpenGRFParameterWindow(this->active_sel, this->editable);
01146 break;
01147 }
01148
01149 case WID_NS_TOGGLE_PALETTE:
01150 if (this->active_sel != NULL || !this->editable) {
01151 this->active_sel->palette ^= GRFP_USE_MASK;
01152 this->SetDirty();
01153 }
01154 break;
01155
01156 case WID_NS_CONTENT_DOWNLOAD:
01157 case WID_NS_CONTENT_DOWNLOAD2:
01158 if (!_network_available) {
01159 ShowErrorMessage(STR_NETWORK_ERROR_NOTAVAILABLE, INVALID_STRING_ID, WL_ERROR);
01160 } else {
01161 #if defined(ENABLE_NETWORK)
01162 this->DeleteChildWindows(WC_QUERY_STRING);
01163
01164 ShowMissingContentWindow(this->actives);
01165 #endif
01166 }
01167 break;
01168
01169 case WID_NS_RESCAN_FILES:
01170 case WID_NS_RESCAN_FILES2:
01171 ScanNewGRFFiles(this);
01172 break;
01173 }
01174 }
01175
01176 virtual void OnNewGRFsScanned()
01177 {
01178 this->avail_sel = NULL;
01179 this->avail_pos = -1;
01180 this->avails.ForceRebuild();
01181 this->DeleteChildWindows(WC_QUERY_STRING);
01182 this->DeleteChildWindows(WC_NEWGRF_TEXTFILE);
01183 }
01184
01185 virtual void OnDropdownSelect(int widget, int index)
01186 {
01187 if (!this->editable) return;
01188
01189 ClearGRFConfigList(&this->actives);
01190 this->preset = index;
01191
01192 if (index != -1) {
01193 this->actives = LoadGRFPresetFromConfig(_grf_preset_list[index]);
01194 }
01195 this->avails.ForceRebuild();
01196
01197 DeleteWindowByClass(WC_GRF_PARAMETERS);
01198 this->active_sel = NULL;
01199 this->InvalidateData(GOID_NEWGRF_PRESET_LOADED);
01200 }
01201
01202 virtual void OnQueryTextFinished(char *str)
01203 {
01204 if (str == NULL) return;
01205
01206 SaveGRFPresetToConfig(str, this->actives);
01207 GetGRFPresetList(&_grf_preset_list);
01208
01209
01210 for (uint i = 0; i < _grf_preset_list.Length(); i++) {
01211 if (_grf_preset_list[i] != NULL && strcmp(_grf_preset_list[i], str) == 0) {
01212 this->preset = i;
01213 break;
01214 }
01215 }
01216
01217 this->InvalidateData();
01218 }
01219
01225 virtual void OnInvalidateData(int data = 0, bool gui_scope = true)
01226 {
01227 if (!gui_scope) return;
01228 switch (data) {
01229 default:
01230
01231 break;
01232
01233 case GOID_NEWGRF_RESCANNED:
01234
01235 for (GRFConfig **l = &this->actives; *l != NULL; l = &(*l)->next) {
01236 GRFConfig *c = *l;
01237 bool compatible = HasBit(c->flags, GCF_COMPATIBLE);
01238 if (c->status != GCS_NOT_FOUND && !compatible) continue;
01239
01240 const GRFConfig *f = FindGRFConfig(c->ident.grfid, FGCM_EXACT, compatible ? c->original_md5sum : c->ident.md5sum);
01241 if (f == NULL || HasBit(f->flags, GCF_INVALID)) continue;
01242
01243 *l = new GRFConfig(*f);
01244 (*l)->next = c->next;
01245
01246 if (active_sel == c) active_sel = *l;
01247
01248 delete c;
01249 }
01250
01251 this->avails.ForceRebuild();
01252
01253 case GOID_NEWGRF_LIST_EDITED:
01254 this->preset = -1;
01255
01256 case GOID_NEWGRF_PRESET_LOADED: {
01257
01258 int i = 0;
01259 for (const GRFConfig *c = this->actives; c != NULL; c = c->next, i++) {}
01260
01261 this->vscroll->SetCapacityFromWidget(this, WID_NS_FILE_LIST);
01262 this->vscroll->SetCount(i);
01263
01264 this->vscroll2->SetCapacityFromWidget(this, WID_NS_AVAIL_LIST);
01265 if (this->avail_pos >= 0) this->vscroll2->ScrollTowards(this->avail_pos);
01266 break;
01267 }
01268 }
01269
01270 this->BuildAvailables();
01271
01272 this->SetWidgetsDisabledState(!this->editable,
01273 WID_NS_PRESET_LIST,
01274 WID_NS_APPLY_CHANGES,
01275 WID_NS_TOGGLE_PALETTE,
01276 WIDGET_LIST_END
01277 );
01278 this->SetWidgetDisabledState(WID_NS_ADD, !this->editable || this->avail_sel == NULL || HasBit(this->avail_sel->flags, GCF_INVALID));
01279
01280 bool disable_all = this->active_sel == NULL || !this->editable;
01281 this->SetWidgetsDisabledState(disable_all,
01282 WID_NS_REMOVE,
01283 WID_NS_MOVE_UP,
01284 WID_NS_MOVE_DOWN,
01285 WIDGET_LIST_END
01286 );
01287
01288 const GRFConfig *c = (this->avail_sel == NULL) ? this->active_sel : this->avail_sel;
01289 for (TextfileType tft = TFT_BEGIN; tft < TFT_END; tft++) {
01290 this->SetWidgetDisabledState(WID_NS_NEWGRF_TEXTFILE + tft, c == NULL || c->GetTextfile(tft) == NULL);
01291 }
01292 this->SetWidgetDisabledState(WID_NS_OPEN_URL, c == NULL || StrEmpty(c->GetURL()));
01293
01294 this->SetWidgetDisabledState(WID_NS_SET_PARAMETERS, !this->show_params || this->active_sel == NULL || this->active_sel->num_valid_params == 0);
01295 this->SetWidgetDisabledState(WID_NS_VIEW_PARAMETERS, !this->show_params || this->active_sel == NULL || this->active_sel->num_valid_params == 0);
01296 this->SetWidgetDisabledState(WID_NS_TOGGLE_PALETTE, disable_all);
01297
01298 if (!disable_all) {
01299
01300 if (this->active_sel == this->actives) this->DisableWidget(WID_NS_MOVE_UP);
01301 if (this->active_sel->next == NULL) this->DisableWidget(WID_NS_MOVE_DOWN);
01302 if (this->active_sel->IsOpenTTDBaseGRF()) this->DisableWidget(WID_NS_REMOVE);
01303 }
01304
01305 this->SetWidgetDisabledState(WID_NS_PRESET_DELETE, this->preset == -1);
01306
01307 bool has_missing = false;
01308 bool has_compatible = false;
01309 for (const GRFConfig *c = this->actives; !has_missing && c != NULL; c = c->next) {
01310 has_missing |= c->status == GCS_NOT_FOUND;
01311 has_compatible |= HasBit(c->flags, GCF_COMPATIBLE);
01312 }
01313 uint16 widget_data;
01314 StringID tool_tip;
01315 if (has_missing || has_compatible) {
01316 widget_data = STR_NEWGRF_SETTINGS_FIND_MISSING_CONTENT_BUTTON;
01317 tool_tip = STR_NEWGRF_SETTINGS_FIND_MISSING_CONTENT_TOOLTIP;
01318 } else {
01319 widget_data = STR_INTRO_ONLINE_CONTENT;
01320 tool_tip = STR_INTRO_TOOLTIP_ONLINE_CONTENT;
01321 }
01322 this->GetWidget<NWidgetCore>(WID_NS_CONTENT_DOWNLOAD)->widget_data = widget_data;
01323 this->GetWidget<NWidgetCore>(WID_NS_CONTENT_DOWNLOAD)->tool_tip = tool_tip;
01324 this->GetWidget<NWidgetCore>(WID_NS_CONTENT_DOWNLOAD2)->widget_data = widget_data;
01325 this->GetWidget<NWidgetCore>(WID_NS_CONTENT_DOWNLOAD2)->tool_tip = tool_tip;
01326
01327 this->SetWidgetDisabledState(WID_NS_PRESET_SAVE, has_missing);
01328 }
01329
01330 virtual void OnMouseLoop()
01331 {
01332 if (this->editable) this->HandleEditBox(WID_NS_FILTER);
01333 }
01334
01335 virtual EventState OnKeyPress(uint16 key, uint16 keycode)
01336 {
01337 if (!this->editable) return ES_NOT_HANDLED;
01338
01339 switch (keycode) {
01340 case WKC_UP:
01341
01342 if (this->avail_pos > 0) this->avail_pos--;
01343 break;
01344
01345 case WKC_DOWN:
01346
01347 if (this->avail_pos < (int)this->avails.Length() - 1) this->avail_pos++;
01348 break;
01349
01350 case WKC_PAGEUP:
01351
01352 this->avail_pos = (this->avail_pos < this->vscroll2->GetCapacity()) ? 0 : this->avail_pos - this->vscroll2->GetCapacity();
01353 break;
01354
01355 case WKC_PAGEDOWN:
01356
01357 this->avail_pos = min(this->avail_pos + this->vscroll2->GetCapacity(), (int)this->avails.Length() - 1);
01358 break;
01359
01360 case WKC_HOME:
01361
01362 this->avail_pos = 0;
01363 break;
01364
01365 case WKC_END:
01366
01367 this->avail_pos = this->avails.Length() - 1;
01368 break;
01369
01370 default: {
01371
01372 EventState state = ES_NOT_HANDLED;
01373 if (this->HandleEditBoxKey(WID_NS_FILTER, key, keycode, state) == HEBR_EDITING) {
01374 this->OnOSKInput(WID_NS_FILTER);
01375 }
01376 return state;
01377 }
01378 }
01379
01380 if (this->avails.Length() == 0) this->avail_pos = -1;
01381 if (this->avail_pos >= 0) {
01382 this->avail_sel = this->avails[this->avail_pos];
01383 this->vscroll2->ScrollTowards(this->avail_pos);
01384 this->InvalidateData(0);
01385 }
01386
01387 return ES_HANDLED;
01388 }
01389
01390 virtual void OnOSKInput(int wid)
01391 {
01392 if (!this->editable) return;
01393
01394 this->avails.SetFilterState(!StrEmpty(this->edit_str_buf));
01395 this->avails.ForceRebuild();
01396 this->InvalidateData(0);
01397 }
01398
01399 private:
01401 static int CDECL NameSorter(const GRFConfig * const *a, const GRFConfig * const *b)
01402 {
01403 int i = strnatcmp((*a)->GetName(), (*b)->GetName());
01404 if (i != 0) return i;
01405
01406 i = (*a)->version - (*b)->version;
01407 if (i != 0) return i;
01408
01409 return memcmp((*a)->ident.md5sum, (*b)->ident.md5sum, lengthof((*b)->ident.md5sum));
01410 }
01411
01413 static bool CDECL TagNameFilter(const GRFConfig * const *a, const char *filter_string)
01414 {
01415 if (strcasestr((*a)->GetName(), filter_string) != NULL) return true;
01416 if ((*a)->filename != NULL && strcasestr((*a)->filename, filter_string) != NULL) return true;
01417 if ((*a)->GetDescription() != NULL && strcasestr((*a)->GetDescription(), filter_string) != NULL) return true;
01418 return false;
01419 }
01420
01421 void BuildAvailables()
01422 {
01423 if (!this->avails.NeedRebuild()) return;
01424
01425 this->avails.Clear();
01426
01427 for (const GRFConfig *c = _all_grfs; c != NULL; c = c->next) {
01428 bool found = false;
01429 for (const GRFConfig *grf = this->actives; grf != NULL && !found; grf = grf->next) found = grf->ident.HasGrfIdentifier(c->ident.grfid, c->ident.md5sum);
01430 if (found) continue;
01431
01432 if (_settings_client.gui.newgrf_show_old_versions) {
01433 *this->avails.Append() = c;
01434 } else {
01435 const GRFConfig *best = FindGRFConfig(c->ident.grfid, HasBit(c->flags, GCF_INVALID) ? FGCM_NEWEST : FGCM_NEWEST_VALID);
01436
01437
01438
01439
01440
01441
01442
01443 if (best->version == 0 || best->ident.HasGrfIdentifier(c->ident.grfid, c->ident.md5sum)) {
01444 *this->avails.Append() = c;
01445 }
01446 }
01447 }
01448
01449 this->avails.Filter(this->edit_str_buf);
01450 this->avails.Compact();
01451 this->avails.RebuildDone();
01452 this->avails.Sort();
01453
01454 if (this->avail_sel != NULL) {
01455 this->avail_pos = this->avails.FindIndex(this->avail_sel);
01456 if (this->avail_pos < 0) this->avail_sel = NULL;
01457 }
01458
01459 this->vscroll2->SetCount(this->avails.Length());
01460 }
01461 };
01462
01463 #if defined(ENABLE_NETWORK)
01464
01468 void ShowMissingContentWindow(const GRFConfig *list)
01469 {
01470
01471 ContentVector cv;
01472 for (const GRFConfig *c = list; c != NULL; c = c->next) {
01473 if (c->status != GCS_NOT_FOUND && !HasBit(c->flags, GCF_COMPATIBLE)) continue;
01474
01475 ContentInfo *ci = new ContentInfo();
01476 ci->type = CONTENT_TYPE_NEWGRF;
01477 ci->state = ContentInfo::DOES_NOT_EXIST;
01478 ttd_strlcpy(ci->name, c->GetName(), lengthof(ci->name));
01479 ci->unique_id = BSWAP32(c->ident.grfid);
01480 memcpy(ci->md5sum, HasBit(c->flags, GCF_COMPATIBLE) ? c->original_md5sum : c->ident.md5sum, sizeof(ci->md5sum));
01481 *cv.Append() = ci;
01482 }
01483 ShowNetworkContentListWindow(cv.Length() == 0 ? NULL : &cv, CONTENT_TYPE_NEWGRF);
01484 }
01485 #endif
01486
01487 Listing NewGRFWindow::last_sorting = {false, 0};
01488 Filtering NewGRFWindow::last_filtering = {false, 0};
01489
01490 NewGRFWindow::GUIGRFConfigList::SortFunction * const NewGRFWindow::sorter_funcs[] = {
01491 &NameSorter,
01492 };
01493
01494 NewGRFWindow::GUIGRFConfigList::FilterFunction * const NewGRFWindow::filter_funcs[] = {
01495 &TagNameFilter,
01496 };
01497
01504 class NWidgetNewGRFDisplay : public NWidgetContainer {
01505 public:
01506 static const uint INTER_LIST_SPACING;
01507 static const uint INTER_COLUMN_SPACING;
01508 static const uint MAX_EXTRA_INFO_WIDTH;
01509 static const uint MIN_EXTRA_FOR_3_COLUMNS;
01510
01511 NWidgetBase *avs;
01512 NWidgetBase *acs;
01513 NWidgetBase *inf;
01514 bool editable;
01515
01516 NWidgetNewGRFDisplay(NWidgetBase *avs, NWidgetBase *acs, NWidgetBase *inf) : NWidgetContainer(NWID_HORIZONTAL)
01517 {
01518 this->avs = avs;
01519 this->acs = acs;
01520 this->inf = inf;
01521
01522 this->Add(this->avs);
01523 this->Add(this->acs);
01524 this->Add(this->inf);
01525
01526 this->editable = true;
01527 }
01528
01529 virtual void SetupSmallestSize(Window *w, bool init_array)
01530 {
01531
01532 assert(dynamic_cast<NewGRFWindow *>(w) != NULL);
01533 NewGRFWindow *ngw = (NewGRFWindow *)w;
01534 this->editable = ngw->editable;
01535
01536 this->avs->SetupSmallestSize(w, init_array);
01537 this->acs->SetupSmallestSize(w, init_array);
01538 this->inf->SetupSmallestSize(w, init_array);
01539
01540 uint min_avs_width = this->avs->smallest_x + this->avs->padding_left + this->avs->padding_right;
01541 uint min_acs_width = this->acs->smallest_x + this->acs->padding_left + this->acs->padding_right;
01542 uint min_inf_width = this->inf->smallest_x + this->inf->padding_left + this->inf->padding_right;
01543
01544 uint min_avs_height = this->avs->smallest_y + this->avs->padding_top + this->avs->padding_bottom;
01545 uint min_acs_height = this->acs->smallest_y + this->acs->padding_top + this->acs->padding_bottom;
01546 uint min_inf_height = this->inf->smallest_y + this->inf->padding_top + this->inf->padding_bottom;
01547
01548
01549 this->smallest_x = max(min_avs_width, min_acs_width) + INTER_COLUMN_SPACING + min_inf_width;
01550 this->smallest_y = max(min_inf_height, min_acs_height + INTER_LIST_SPACING + min_avs_height);
01551
01552
01553 this->fill_x = LeastCommonMultiple(this->avs->fill_x, this->acs->fill_x);
01554 if (this->inf->fill_x > 0 && (this->fill_x == 0 || this->fill_x > this->inf->fill_x)) this->fill_x = this->inf->fill_x;
01555
01556 this->fill_y = this->avs->fill_y;
01557 if (this->acs->fill_y > 0 && (this->fill_y == 0 || this->fill_y > this->acs->fill_y)) this->fill_y = this->acs->fill_y;
01558 this->fill_y = LeastCommonMultiple(this->fill_y, this->inf->fill_y);
01559
01560
01561 this->resize_x = LeastCommonMultiple(this->avs->resize_x, this->acs->resize_x);
01562 if (this->inf->resize_x > 0 && (this->resize_x == 0 || this->resize_x > this->inf->resize_x)) this->resize_x = this->inf->resize_x;
01563
01564 this->resize_y = this->avs->resize_y;
01565 if (this->acs->resize_y > 0 && (this->resize_y == 0 || this->resize_y > this->acs->resize_y)) this->resize_y = this->acs->resize_y;
01566 this->resize_y = LeastCommonMultiple(this->resize_y, this->inf->resize_y);
01567
01568
01569 this->smallest_y = ComputeMaxSize(min_acs_height, this->smallest_y + this->resize_y - 1, this->resize_y);
01570 }
01571
01572 virtual void AssignSizePosition(SizingType sizing, uint x, uint y, uint given_width, uint given_height, bool rtl)
01573 {
01574 this->StoreSizePosition(sizing, x, y, given_width, given_height);
01575
01576 uint min_avs_width = this->avs->smallest_x + this->avs->padding_left + this->avs->padding_right;
01577 uint min_acs_width = this->acs->smallest_x + this->acs->padding_left + this->acs->padding_right;
01578 uint min_inf_width = this->inf->smallest_x + this->inf->padding_left + this->inf->padding_right;
01579
01580 uint min_list_width = max(min_avs_width, min_acs_width);
01581 uint avs_extra_width = min_list_width - min_avs_width;
01582 uint acs_extra_width = min_list_width - min_acs_width;
01583
01584
01585 uint min_three_columns = min_avs_width + min_acs_width + min_inf_width + 2 * INTER_COLUMN_SPACING;
01586 uint min_two_columns = min_list_width + min_inf_width + INTER_COLUMN_SPACING;
01587 bool use_three_columns = this->editable && (min_three_columns + MIN_EXTRA_FOR_3_COLUMNS <= given_width);
01588
01589
01590 uint extra_width, inf_width;
01591 if (use_three_columns) {
01592 extra_width = given_width - min_three_columns;
01593 inf_width = min(MAX_EXTRA_INFO_WIDTH, extra_width / 2);
01594 } else {
01595 extra_width = given_width - min_two_columns;
01596 inf_width = min(MAX_EXTRA_INFO_WIDTH, extra_width / 2);
01597 }
01598 inf_width = ComputeMaxSize(this->inf->smallest_x, this->inf->smallest_x + inf_width, this->inf->GetHorizontalStepSize(sizing));
01599 extra_width -= inf_width - this->inf->smallest_x;
01600
01601 uint inf_height = ComputeMaxSize(this->inf->smallest_y, given_height, this->inf->GetVerticalStepSize(sizing));
01602
01603 if (use_three_columns) {
01604
01605
01606 uint avs_width = min(avs_extra_width, extra_width);
01607 extra_width -= avs_width;
01608 extra_width -= min(acs_extra_width, extra_width);
01609 avs_width += extra_width / 2;
01610
01611 avs_width = ComputeMaxSize(this->avs->smallest_x, this->avs->smallest_x + avs_width, this->avs->GetHorizontalStepSize(sizing));
01612
01613 uint acs_width = given_width -
01614 inf_width - this->inf->padding_left - this->inf->padding_right -
01615 avs_width - this->avs->padding_left - this->avs->padding_right - 2 * INTER_COLUMN_SPACING;
01616 acs_width = ComputeMaxSize(min_acs_width, acs_width, this->acs->GetHorizontalStepSize(sizing)) -
01617 this->acs->padding_left - this->acs->padding_right;
01618
01619
01620 uint avs_height = ComputeMaxSize(this->avs->smallest_y, given_height, this->avs->resize_y);
01621 uint acs_height = ComputeMaxSize(this->acs->smallest_y, given_height, this->acs->resize_y);
01622
01623
01624 if (rtl) {
01625 x += this->inf->padding_left;
01626 this->inf->AssignSizePosition(sizing, x, y + this->inf->padding_top, inf_width, inf_height, rtl);
01627 x += inf_width + this->inf->padding_right + INTER_COLUMN_SPACING;
01628 } else {
01629 x += this->avs->padding_left;
01630 this->avs->AssignSizePosition(sizing, x, y + this->avs->padding_top, avs_width, avs_height, rtl);
01631 x += avs_width + this->avs->padding_right + INTER_COLUMN_SPACING;
01632 }
01633
01634 x += this->acs->padding_left;
01635 this->acs->AssignSizePosition(sizing, x, y + this->acs->padding_top, acs_width, acs_height, rtl);
01636 x += acs_width + this->acs->padding_right + INTER_COLUMN_SPACING;
01637
01638 if (rtl) {
01639 x += this->avs->padding_left;
01640 this->avs->AssignSizePosition(sizing, x, y + this->avs->padding_top, avs_width, avs_height, rtl);
01641 } else {
01642 x += this->inf->padding_left;
01643 this->inf->AssignSizePosition(sizing, x, y + this->inf->padding_top, inf_width, inf_height, rtl);
01644 }
01645 } else {
01646
01647
01648 uint avs_width = ComputeMaxSize(this->avs->smallest_x, this->avs->smallest_x + avs_extra_width + extra_width,
01649 this->avs->GetHorizontalStepSize(sizing));
01650 uint acs_width = ComputeMaxSize(this->acs->smallest_x, this->acs->smallest_x + acs_extra_width + extra_width,
01651 this->acs->GetHorizontalStepSize(sizing));
01652
01653 uint min_avs_height = (!this->editable) ? 0 : this->avs->smallest_y + this->avs->padding_top + this->avs->padding_bottom + INTER_LIST_SPACING;
01654 uint min_acs_height = this->acs->smallest_y + this->acs->padding_top + this->acs->padding_bottom;
01655 uint extra_height = given_height - min_acs_height - min_avs_height;
01656
01657
01658 uint avs_height = ComputeMaxSize(this->avs->smallest_y, this->avs->smallest_y + extra_height / 2, this->avs->resize_y);
01659 if (this->editable) extra_height -= avs_height - this->avs->smallest_y;
01660 uint acs_height = ComputeMaxSize(this->acs->smallest_y, this->acs->smallest_y + extra_height, this->acs->resize_y);
01661
01662
01663 if (rtl) {
01664 x += this->inf->padding_left;
01665 this->inf->AssignSizePosition(sizing, x, y + this->inf->padding_top, inf_width, inf_height, rtl);
01666 x += inf_width + this->inf->padding_right + INTER_COLUMN_SPACING;
01667
01668 this->acs->AssignSizePosition(sizing, x + this->acs->padding_left, y + this->acs->padding_top, acs_width, acs_height, rtl);
01669 if (this->editable) {
01670 this->avs->AssignSizePosition(sizing, x + this->avs->padding_left, y + given_height - avs_height - this->avs->padding_bottom, avs_width, avs_height, rtl);
01671 } else {
01672 this->avs->AssignSizePosition(sizing, 0, 0, this->avs->smallest_x, this->avs->smallest_y, rtl);
01673 }
01674 } else {
01675 this->acs->AssignSizePosition(sizing, x + this->acs->padding_left, y + this->acs->padding_top, acs_width, acs_height, rtl);
01676 if (this->editable) {
01677 this->avs->AssignSizePosition(sizing, x + this->avs->padding_left, y + given_height - avs_height - this->avs->padding_bottom, avs_width, avs_height, rtl);
01678 } else {
01679 this->avs->AssignSizePosition(sizing, 0, 0, this->avs->smallest_x, this->avs->smallest_y, rtl);
01680 }
01681 uint dx = this->acs->current_x + this->acs->padding_left + this->acs->padding_right;
01682 if (this->editable) {
01683 dx = max(dx, this->avs->current_x + this->avs->padding_left + this->avs->padding_right);
01684 }
01685 x += dx + INTER_COLUMN_SPACING + this->inf->padding_left;
01686 this->inf->AssignSizePosition(sizing, x, y + this->inf->padding_top, inf_width, inf_height, rtl);
01687 }
01688 }
01689 }
01690
01691 virtual NWidgetCore *GetWidgetFromPos(int x, int y)
01692 {
01693 if (!IsInsideBS(x, this->pos_x, this->current_x) || !IsInsideBS(y, this->pos_y, this->current_y)) return NULL;
01694
01695 NWidgetCore *nw = (this->editable) ? this->avs->GetWidgetFromPos(x, y) : NULL;
01696 if (nw == NULL) nw = this->acs->GetWidgetFromPos(x, y);
01697 if (nw == NULL) nw = this->inf->GetWidgetFromPos(x, y);
01698 return nw;
01699 }
01700
01701 virtual void Draw(const Window *w)
01702 {
01703 if (this->editable) this->avs->Draw(w);
01704 this->acs->Draw(w);
01705 this->inf->Draw(w);
01706 }
01707 };
01708
01709 const uint NWidgetNewGRFDisplay::INTER_LIST_SPACING = WD_RESIZEBOX_WIDTH + 1;
01710 const uint NWidgetNewGRFDisplay::INTER_COLUMN_SPACING = WD_RESIZEBOX_WIDTH;
01711 const uint NWidgetNewGRFDisplay::MAX_EXTRA_INFO_WIDTH = 150;
01712 const uint NWidgetNewGRFDisplay::MIN_EXTRA_FOR_3_COLUMNS = 50;
01713
01714 static const NWidgetPart _nested_newgrf_actives_widgets[] = {
01715
01716 NWidget(NWID_HORIZONTAL),
01717 NWidget(WWT_TEXT, COLOUR_MAUVE), SetDataTip(STR_NEWGRF_SETTINGS_SELECT_PRESET, STR_NULL),
01718 SetPadding(0, WD_FRAMETEXT_RIGHT, 0, 0),
01719 NWidget(WWT_DROPDOWN, COLOUR_YELLOW, WID_NS_PRESET_LIST), SetFill(1, 0), SetResize(1, 0),
01720 SetDataTip(STR_JUST_STRING, STR_NEWGRF_SETTINGS_PRESET_LIST_TOOLTIP),
01721 EndContainer(),
01722 NWidget(NWID_HORIZONTAL, NC_EQUALSIZE),
01723 NWidget(WWT_PUSHTXTBTN, COLOUR_YELLOW, WID_NS_PRESET_SAVE), SetFill(1, 0), SetResize(1, 0),
01724 SetDataTip(STR_NEWGRF_SETTINGS_PRESET_SAVE, STR_NEWGRF_SETTINGS_PRESET_SAVE_TOOLTIP),
01725 NWidget(WWT_PUSHTXTBTN, COLOUR_YELLOW, WID_NS_PRESET_DELETE), SetFill(1, 0), SetResize(1, 0),
01726 SetDataTip(STR_NEWGRF_SETTINGS_PRESET_DELETE, STR_NEWGRF_SETTINGS_PRESET_DELETE_TOOLTIP),
01727 EndContainer(),
01728
01729 NWidget(NWID_SPACER), SetMinimalSize(0, WD_RESIZEBOX_WIDTH), SetResize(1, 0), SetFill(1, 0),
01730 NWidget(WWT_PANEL, COLOUR_MAUVE),
01731 NWidget(WWT_LABEL, COLOUR_MAUVE), SetDataTip(STR_NEWGRF_SETTINGS_ACTIVE_LIST, STR_NULL),
01732 SetFill(1, 0), SetResize(1, 0), SetPadding(3, WD_FRAMETEXT_RIGHT, 0, WD_FRAMETEXT_LEFT),
01733
01734 NWidget(NWID_HORIZONTAL), SetPadding(0, 2, 0, 2),
01735 NWidget(WWT_PANEL, COLOUR_MAUVE),
01736 NWidget(WWT_INSET, COLOUR_MAUVE, WID_NS_FILE_LIST), SetMinimalSize(100, 1), SetPadding(2, 2, 2, 2),
01737 SetFill(1, 1), SetResize(1, 1), SetScrollbar(WID_NS_SCROLLBAR), SetDataTip(STR_NULL, STR_NEWGRF_SETTINGS_FILE_TOOLTIP),
01738 EndContainer(),
01739 EndContainer(),
01740 NWidget(NWID_VSCROLLBAR, COLOUR_MAUVE, WID_NS_SCROLLBAR),
01741 EndContainer(),
01742
01743 NWidget(NWID_SELECTION, INVALID_COLOUR, WID_NS_SHOW_REMOVE),
01744 NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), SetPadding(2, 2, 2, 2), SetPIP(0, WD_RESIZEBOX_WIDTH, 0),
01745 NWidget(WWT_PUSHTXTBTN, COLOUR_YELLOW, WID_NS_REMOVE), SetFill(1, 0), SetResize(1, 0),
01746 SetDataTip(STR_NEWGRF_SETTINGS_REMOVE, STR_NEWGRF_SETTINGS_REMOVE_TOOLTIP),
01747 NWidget(NWID_VERTICAL),
01748 NWidget(WWT_PUSHTXTBTN, COLOUR_YELLOW, WID_NS_MOVE_UP), SetFill(1, 0), SetResize(1, 0),
01749 SetDataTip(STR_NEWGRF_SETTINGS_MOVEUP, STR_NEWGRF_SETTINGS_MOVEUP_TOOLTIP),
01750 NWidget(WWT_PUSHTXTBTN, COLOUR_YELLOW, WID_NS_MOVE_DOWN), SetFill(1, 0), SetResize(1, 0),
01751 SetDataTip(STR_NEWGRF_SETTINGS_MOVEDOWN, STR_NEWGRF_SETTINGS_MOVEDOWN_TOOLTIP),
01752 EndContainer(),
01753 EndContainer(),
01754
01755 NWidget(NWID_VERTICAL, NC_EQUALSIZE), SetPadding(2, 2, 2, 2),
01756 NWidget(WWT_PUSHTXTBTN, COLOUR_YELLOW, WID_NS_RESCAN_FILES2), SetFill(1, 0), SetResize(1, 0),
01757 SetDataTip(STR_NEWGRF_SETTINGS_RESCAN_FILES, STR_NEWGRF_SETTINGS_RESCAN_FILES_TOOLTIP),
01758 NWidget(WWT_PUSHTXTBTN, COLOUR_YELLOW, WID_NS_CONTENT_DOWNLOAD2), SetFill(1, 0), SetResize(1, 0),
01759 SetDataTip(STR_INTRO_ONLINE_CONTENT, STR_INTRO_TOOLTIP_ONLINE_CONTENT),
01760 EndContainer(),
01761 EndContainer(),
01762 EndContainer(),
01763 };
01764
01765 static const NWidgetPart _nested_newgrf_availables_widgets[] = {
01766 NWidget(WWT_PANEL, COLOUR_MAUVE),
01767 NWidget(WWT_LABEL, COLOUR_MAUVE), SetDataTip(STR_NEWGRF_SETTINGS_INACTIVE_LIST, STR_NULL),
01768 SetFill(1, 0), SetResize(1, 0), SetPadding(3, WD_FRAMETEXT_RIGHT, 0, WD_FRAMETEXT_LEFT),
01769
01770 NWidget(NWID_HORIZONTAL), SetPadding(WD_TEXTPANEL_TOP, 0, WD_TEXTPANEL_BOTTOM, 0),
01771 SetPIP(WD_FRAMETEXT_LEFT, WD_FRAMETEXT_RIGHT, WD_FRAMETEXT_RIGHT),
01772 NWidget(WWT_TEXT, COLOUR_MAUVE), SetFill(0, 1), SetDataTip(STR_NEWGRF_FILTER_TITLE, STR_NULL),
01773 NWidget(WWT_EDITBOX, COLOUR_MAUVE, WID_NS_FILTER), SetFill(1, 0), SetMinimalSize(50, 12), SetResize(1, 0),
01774 SetDataTip(STR_LIST_FILTER_OSKTITLE, STR_LIST_FILTER_TOOLTIP),
01775 EndContainer(),
01776
01777 NWidget(NWID_HORIZONTAL), SetPadding(0, 2, 0, 2),
01778 NWidget(WWT_PANEL, COLOUR_MAUVE),
01779 NWidget(WWT_INSET, COLOUR_MAUVE, WID_NS_AVAIL_LIST), SetMinimalSize(100, 1), SetPadding(2, 2, 2, 2),
01780 SetFill(1, 1), SetResize(1, 1), SetScrollbar(WID_NS_SCROLL2BAR),
01781 EndContainer(),
01782 EndContainer(),
01783 NWidget(NWID_VSCROLLBAR, COLOUR_MAUVE, WID_NS_SCROLL2BAR),
01784 EndContainer(),
01785
01786 NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), SetPadding(2, 2, 2, 2), SetPIP(0, WD_RESIZEBOX_WIDTH, 0),
01787 NWidget(WWT_PUSHTXTBTN, COLOUR_YELLOW, WID_NS_ADD), SetFill(1, 0), SetResize(1, 0),
01788 SetDataTip(STR_NEWGRF_SETTINGS_ADD, STR_NEWGRF_SETTINGS_ADD_FILE_TOOLTIP),
01789 NWidget(NWID_VERTICAL),
01790 NWidget(WWT_PUSHTXTBTN, COLOUR_YELLOW, WID_NS_RESCAN_FILES), SetFill(1, 0), SetResize(1, 0),
01791 SetDataTip(STR_NEWGRF_SETTINGS_RESCAN_FILES, STR_NEWGRF_SETTINGS_RESCAN_FILES_TOOLTIP),
01792 NWidget(WWT_PUSHTXTBTN, COLOUR_YELLOW, WID_NS_CONTENT_DOWNLOAD), SetFill(1, 0), SetResize(1, 0),
01793 SetDataTip(STR_INTRO_ONLINE_CONTENT, STR_INTRO_TOOLTIP_ONLINE_CONTENT),
01794 EndContainer(),
01795 EndContainer(),
01796 EndContainer(),
01797 };
01798
01799 static const NWidgetPart _nested_newgrf_infopanel_widgets[] = {
01800
01801 NWidget(NWID_VERTICAL), SetPadding(0, 0, 2, 0),
01802 NWidget(WWT_PANEL, COLOUR_MAUVE), SetPadding(0, 0, 2, 0),
01803 NWidget(WWT_EMPTY, COLOUR_MAUVE, WID_NS_NEWGRF_INFO_TITLE), SetFill(1, 0), SetResize(1, 0),
01804 NWidget(WWT_EMPTY, COLOUR_MAUVE, WID_NS_NEWGRF_INFO), SetFill(1, 1), SetResize(1, 1), SetMinimalSize(150, 100),
01805 EndContainer(),
01806 NWidget(WWT_PUSHTXTBTN, COLOUR_YELLOW, WID_NS_OPEN_URL), SetFill(1, 0), SetResize(1, 0),
01807 SetDataTip(STR_CONTENT_OPEN_URL, STR_CONTENT_OPEN_URL_TOOLTIP),
01808 NWidget(WWT_PUSHTXTBTN, COLOUR_YELLOW, WID_NS_NEWGRF_TEXTFILE + TFT_README), SetFill(1, 0), SetResize(1, 0),
01809 SetDataTip(STR_NEWGRF_SETTINGS_VIEW_README, STR_NULL),
01810 NWidget(NWID_HORIZONTAL, NC_EQUALSIZE),
01811 NWidget(WWT_PUSHTXTBTN, COLOUR_YELLOW, WID_NS_NEWGRF_TEXTFILE + TFT_CHANGELOG), SetFill(1, 0), SetResize(1, 0),
01812 SetDataTip(STR_NEWGRF_SETTINGS_VIEW_CHANGELOG, STR_NULL),
01813 NWidget(WWT_PUSHTXTBTN, COLOUR_YELLOW, WID_NS_NEWGRF_TEXTFILE + TFT_LICENSE), SetFill(1, 0), SetResize(1, 0),
01814 SetDataTip(STR_NEWGRF_SETTINGS_VIEW_LICENSE, STR_NULL),
01815 EndContainer(),
01816 EndContainer(),
01817 NWidget(NWID_SELECTION, INVALID_COLOUR, WID_NS_SHOW_APPLY),
01818
01819 NWidget(NWID_HORIZONTAL, NC_EQUALSIZE), SetPIP(0, WD_RESIZEBOX_WIDTH, 0),
01820 NWidget(NWID_VERTICAL),
01821 NWidget(WWT_PUSHTXTBTN, COLOUR_YELLOW, WID_NS_SET_PARAMETERS), SetFill(1, 0), SetResize(1, 0),
01822 SetDataTip(STR_NEWGRF_SETTINGS_SET_PARAMETERS, STR_NULL),
01823 NWidget(WWT_PUSHTXTBTN, COLOUR_YELLOW, WID_NS_TOGGLE_PALETTE), SetFill(1, 0), SetResize(1, 0),
01824 SetDataTip(STR_NEWGRF_SETTINGS_TOGGLE_PALETTE, STR_NEWGRF_SETTINGS_TOGGLE_PALETTE_TOOLTIP),
01825 EndContainer(),
01826 NWidget(WWT_PUSHTXTBTN, COLOUR_YELLOW, WID_NS_APPLY_CHANGES), SetFill(1, 0), SetResize(1, 0),
01827 SetDataTip(STR_NEWGRF_SETTINGS_APPLY_CHANGES, STR_NULL),
01828 EndContainer(),
01829 NWidget(WWT_PUSHTXTBTN, COLOUR_YELLOW, WID_NS_VIEW_PARAMETERS), SetFill(1, 0), SetResize(1, 0),
01830 SetDataTip(STR_NEWGRF_SETTINGS_SHOW_PARAMETERS, STR_NULL),
01831 EndContainer(),
01832 };
01833
01835 NWidgetBase* NewGRFDisplay(int *biggest_index)
01836 {
01837 NWidgetBase *avs = MakeNWidgets(_nested_newgrf_availables_widgets, lengthof(_nested_newgrf_availables_widgets), biggest_index, NULL);
01838
01839 int biggest2;
01840 NWidgetBase *acs = MakeNWidgets(_nested_newgrf_actives_widgets, lengthof(_nested_newgrf_actives_widgets), &biggest2, NULL);
01841 *biggest_index = max(*biggest_index, biggest2);
01842
01843 NWidgetBase *inf = MakeNWidgets(_nested_newgrf_infopanel_widgets, lengthof(_nested_newgrf_infopanel_widgets), &biggest2, NULL);
01844 *biggest_index = max(*biggest_index, biggest2);
01845
01846 return new NWidgetNewGRFDisplay(avs, acs, inf);
01847 }
01848
01849
01850 static const NWidgetPart _nested_newgrf_widgets[] = {
01851 NWidget(NWID_HORIZONTAL),
01852 NWidget(WWT_CLOSEBOX, COLOUR_MAUVE),
01853 NWidget(WWT_CAPTION, COLOUR_MAUVE), SetDataTip(STR_NEWGRF_SETTINGS_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
01854 EndContainer(),
01855 NWidget(WWT_PANEL, COLOUR_MAUVE),
01856 NWidgetFunction(NewGRFDisplay), SetPadding(WD_RESIZEBOX_WIDTH, WD_RESIZEBOX_WIDTH, 2, WD_RESIZEBOX_WIDTH),
01857
01858 NWidget(NWID_HORIZONTAL),
01859 NWidget(NWID_SPACER), SetFill(1, 0), SetResize(1, 0),
01860 NWidget(WWT_RESIZEBOX, COLOUR_MAUVE),
01861 EndContainer(),
01862 EndContainer(),
01863 };
01864
01865
01866 static const WindowDesc _newgrf_desc(
01867 WDP_CENTER, 300, 263,
01868 WC_GAME_OPTIONS, WC_NONE,
01869 WDF_UNCLICK_BUTTONS,
01870 _nested_newgrf_widgets, lengthof(_nested_newgrf_widgets)
01871 );
01872
01878 static void NewGRFConfirmationCallback(Window *w, bool confirmed)
01879 {
01880 if (confirmed) {
01881 DeleteWindowByClass(WC_GRF_PARAMETERS);
01882 NewGRFWindow *nw = dynamic_cast<NewGRFWindow*>(w);
01883
01884 GamelogStartAction(GLAT_GRF);
01885 GamelogGRFUpdate(_grfconfig, nw->actives);
01886 CopyGRFConfigList(nw->orig_list, nw->actives, false);
01887 ReloadNewGRFData();
01888 GamelogStopAction();
01889
01890
01891 GRFConfig *c;
01892 int i = 0;
01893 for (c = nw->actives; c != NULL && c != nw->active_sel; c = c->next, i++) {}
01894 CopyGRFConfigList(&nw->actives, *nw->orig_list, false);
01895 for (c = nw->actives; c != NULL && i > 0; c = c->next, i--) {}
01896 nw->active_sel = c;
01897 nw->avails.ForceRebuild();
01898
01899 w->InvalidateData();
01900
01901 ReInitAllWindows();
01902 DeleteWindowByClass(WC_BUILD_OBJECT);
01903 }
01904 }
01905
01906
01907
01916 void ShowNewGRFSettings(bool editable, bool show_params, bool exec_changes, GRFConfig **config)
01917 {
01918 DeleteWindowByClass(WC_GAME_OPTIONS);
01919 new NewGRFWindow(&_newgrf_desc, editable, show_params, exec_changes, config);
01920 }
01921
01923 static const NWidgetPart _nested_scan_progress_widgets[] = {
01924 NWidget(WWT_CAPTION, COLOUR_GREY), SetDataTip(STR_NEWGRF_SCAN_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
01925 NWidget(WWT_PANEL, COLOUR_GREY),
01926 NWidget(NWID_HORIZONTAL), SetPIP(20, 0, 20),
01927 NWidget(NWID_VERTICAL), SetPIP(11, 8, 11),
01928 NWidget(WWT_LABEL, INVALID_COLOUR), SetDataTip(STR_NEWGRF_SCAN_MESSAGE, STR_NULL), SetFill(1, 0),
01929 NWidget(WWT_EMPTY, INVALID_COLOUR, WID_SP_PROGRESS_BAR), SetFill(1, 0),
01930 NWidget(WWT_EMPTY, INVALID_COLOUR, WID_SP_PROGRESS_TEXT), SetFill(1, 0),
01931 EndContainer(),
01932 EndContainer(),
01933 EndContainer(),
01934 };
01935
01937 static const WindowDesc _scan_progress_desc(
01938 WDP_CENTER, 0, 0,
01939 WC_MODAL_PROGRESS, WC_NONE,
01940 WDF_UNCLICK_BUTTONS,
01941 _nested_scan_progress_widgets, lengthof(_nested_scan_progress_widgets)
01942 );
01943
01945 struct ScanProgressWindow : public Window {
01946 char *last_name;
01947 int scanned;
01948
01950 ScanProgressWindow() : Window(), last_name(NULL), scanned(0)
01951 {
01952 this->InitNested(&_scan_progress_desc, 1);
01953 }
01954
01956 ~ScanProgressWindow()
01957 {
01958 free(last_name);
01959 }
01960
01961 virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize)
01962 {
01963 switch (widget) {
01964 case WID_SP_PROGRESS_BAR: {
01965 SetDParam(0, 100);
01966 *size = GetStringBoundingBox(STR_GENERATION_PROGRESS);
01967
01968 size->height += 8;
01969 size->width += 8;
01970 break;
01971 }
01972
01973 case WID_SP_PROGRESS_TEXT:
01974 SetDParam(0, 9999);
01975 SetDParam(1, 9999);
01976
01977
01978 size->width = max(400U, GetStringBoundingBox(STR_NEWGRF_SCAN_STATUS).width);
01979 size->height = FONT_HEIGHT_NORMAL * 2 + WD_PAR_VSEP_NORMAL;
01980 break;
01981 }
01982 }
01983
01984 virtual void DrawWidget(const Rect &r, int widget) const
01985 {
01986 switch (widget) {
01987 case WID_SP_PROGRESS_BAR: {
01988
01989 DrawFrameRect(r.left, r.top, r.right, r.bottom, COLOUR_GREY, FR_BORDERONLY);
01990 uint percent = scanned * 100 / max(1U, _settings_client.gui.last_newgrf_count);
01991 DrawFrameRect(r.left + 1, r.top + 1, (int)((r.right - r.left - 2) * percent / 100) + r.left + 1, r.bottom - 1, COLOUR_MAUVE, FR_NONE);
01992 SetDParam(0, percent);
01993 DrawString(r.left, r.right, r.top + 5, STR_GENERATION_PROGRESS, TC_FROMSTRING, SA_HOR_CENTER);
01994 break;
01995 }
01996
01997 case WID_SP_PROGRESS_TEXT:
01998 SetDParam(0, this->scanned);
01999 SetDParam(1, _settings_client.gui.last_newgrf_count);
02000 DrawString(r.left, r.right, r.top, STR_NEWGRF_SCAN_STATUS, TC_FROMSTRING, SA_HOR_CENTER);
02001
02002 DrawString(r.left, r.right, r.top + FONT_HEIGHT_NORMAL + WD_PAR_VSEP_NORMAL, this->last_name == NULL ? "" : this->last_name, TC_BLACK, SA_HOR_CENTER);
02003 break;
02004 }
02005 }
02006
02012 void UpdateNewGRFScanStatus(uint num, const char *name)
02013 {
02014 free(this->last_name);
02015 if (name == NULL) {
02016 char buf[256];
02017 GetString(buf, STR_NEWGRF_SCAN_ARCHIVES, lastof(buf));
02018 this->last_name = strdup(buf);
02019 } else {
02020 this->last_name = strdup(name);
02021 }
02022 this->scanned = num;
02023 if (num > _settings_client.gui.last_newgrf_count) _settings_client.gui.last_newgrf_count = num;
02024
02025 this->SetDirty();
02026 }
02027 };
02028
02034 void UpdateNewGRFScanStatus(uint num, const char *name)
02035 {
02036 ScanProgressWindow *w = dynamic_cast<ScanProgressWindow *>(FindWindowByClass(WC_MODAL_PROGRESS));
02037 if (w == NULL) w = new ScanProgressWindow();
02038 w->UpdateNewGRFScanStatus(num, name);
02039 }