diff -r c42a62268eee src/fileio.cpp --- a/src/fileio.cpp Fri Apr 29 18:35:36 2011 +0100 +++ b/src/fileio.cpp Tue May 10 20:02:29 2011 +0100 @@ -469,6 +469,53 @@ return true; } +/** + * Check a grf for a readme.txt file. + * @param cfg The GRFConfig to check. + * @return true is the GRF is packaged with a readme.txt file. + * @note a GRF can only have a readme if it is inside a tar archive. + */ +bool GrfHasReadme(const GRFConfig *cfg) +{ + if (!FindReadme(cfg)) return false; + return true; +} + +/** + * Find a readme.txt file. + * @param cfg The GRFConfig to check. + * @return The path to the readme, false if no readme found. + */ +char *FindReadme(const GRFConfig *cfg) +{ + if (cfg == NULL || cfg->filename == NULL) return false; + + const char *slash = strrchr(cfg->filename, PATHSEPCHAR); + if (slash == NULL) return false; + int prefix_length = slash - cfg->filename + 1; // Including the path separator. + if (prefix_length + 10 + 1 > MAX_PATH) return false; // "foo/" + "readme.txt" + '\0' must fit. + + char readme_path[MAX_PATH]; + memcpy(readme_path, cfg->filename, prefix_length); + strecpy(readme_path + prefix_length, "readme.txt", lastof(readme_path)); + + TarFileList::iterator tar_entry = _tar_filelist.find(readme_path); + if (tar_entry == _tar_filelist.end()) return false; + return readme_path; +} + +/** + * Load a readme. + * @param cfg The GRFConfig to load the readme from. + * @return the readme in char form. + */ +char *LoadReadme(const GRFConfig *cfg) +{ + char readme[MAX_README_LENGTH]; + char readme_path = FindReadme(cfg); + return readme; +} + /** * Allocates and files a variable with the full path * based on the given directory. diff -r c42a62268eee src/fileio_func.h --- a/src/fileio_func.h Fri Apr 29 18:35:36 2011 +0100 +++ b/src/fileio_func.h Tue May 10 20:02:29 2011 +0100 @@ -13,6 +13,7 @@ #define FILEIO_FUNC_H #include "fileio_type.h" +#include "newgrf_config.h" void FioSeekTo(size_t pos, int mode); void FioSeekToFile(uint8 slot, size_t pos); @@ -57,6 +58,9 @@ void SanitizeFilename(char *filename); bool AppendPathSeparator(char *buf, size_t buflen); +bool GrfHasReadme(const GRFConfig *cfg); +char *FindReadme(const GRFConfig *cfg); +char *LoadReadme(const GRFConfig *cfg); void DeterminePaths(const char *exe); void *ReadFileToMem(const char *filename, size_t *lenp, size_t maxsize); bool FileExists(const char *filename); @@ -66,6 +70,8 @@ extern char *_personal_dir; ///< custom directory for personal settings, saves, newgrf, etc. +static const uint16 MAX_README_LENGTH = 8191; + /** Helper for scanning for files with a given name */ class FileScanner { diff -r c42a62268eee src/lang/english.txt --- a/src/lang/english.txt Fri Apr 29 18:35:36 2011 +0100 +++ b/src/lang/english.txt Tue May 10 20:02:29 2011 +0100 @@ -2384,6 +2384,7 @@ STR_NEWGRF_SETTINGS_MOVEDOWN :{BLACK}Move Down STR_NEWGRF_SETTINGS_MOVEDOWN_TOOLTIP :{BLACK}Move the selected NewGRF file down the list STR_NEWGRF_SETTINGS_FILE_TOOLTIP :{BLACK}A list of the NewGRF files that are installed. Click a file to change its parameters +STR_NEWGRF_SETTINGS_VIEW_README :{BLACK}View Readme STR_NEWGRF_SETTINGS_SET_PARAMETERS :{BLACK}Set parameters STR_NEWGRF_SETTINGS_TOGGLE_PALETTE :{BLACK}Toggle palette @@ -2417,6 +2418,9 @@ STR_NEWGRF_PARAMETERS_SETTING :{STRING1}: {ORANGE}{STRING1} STR_NEWGRF_PARAMETERS_NUM_PARAM :{LTBLUE}Number of parameters: {ORANGE}{NUM} +# NewGRF readme window +STR_NEWGRF_README_CAPTION :{WHITE}View NewGRF Readme + # NewGRF inspect window STR_NEWGRF_INSPECT_CAPTION :{WHITE}Inspect - {STRING5} STR_NEWGRF_INSPECT_PARENT_BUTTON :{BLACK}Parent diff -r c42a62268eee src/newgrf_gui.cpp --- a/src/newgrf_gui.cpp Fri Apr 29 18:35:36 2011 +0100 +++ b/src/newgrf_gui.cpp Tue May 10 20:02:29 2011 +0100 @@ -25,6 +25,7 @@ #include "core/geometry_func.hpp" #include "newgrf_text.h" #include "fileio_func.h" +#include "tar_type.h" #include "table/strings.h" #include "table/sprites.h" @@ -455,6 +456,110 @@ new NewGRFParametersWindow(&_newgrf_parameters_desc, c); } +enum ShowNewGRFReadmeWidgets { + GRW_WIDGET_BACKGROUND, ///< Panel to draw the readme on + GRW_WIDGET_SCROLLBAR, ///< Scrollbar to scroll through the readme +}; + +struct NewGRFReadmeWindow : public Window { + GRFConfig *grf_config; ///< View the readme of this GRFConfig. + uint clicked_button; ///< The row in which a button was clicked or UINT_MAX. + bool clicked_increase; ///< True if the increase button was clicked, false for the decrease button. + int timeout; ///< How long before we unpress the last-pressed button? + int line_height; ///< Height of a row in the matrix widget. + Scrollbar *vscroll; + + + static const int top_spacing; ///< Additional spacing at the top of the #MHW_BACKGROUND widget. + static const int bottom_spacing; ///< Additional spacing at the bottom of the #MHW_BACKGROUND widget. + + int date_width; /// < Width needed for the date part. + + NewGRFReadmeWindow(const WindowDesc *desc, GRFConfig *c) : Window(), + grf_config(c), + clicked_button(UINT_MAX), + timeout(0) + { + this->CreateNestedTree(desc); + this->vscroll = this->GetScrollbar(GRFPAR_WIDGET_SCROLLBAR); + this->FinishInitNested(desc); // Initializes 'this->line_height' as side effect. + this->OnInvalidateData(); + } + + virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) + { + switch (widget) { + case GRW_WIDGET_BACKGROUND: + this->line_height = FONT_HEIGHT_NORMAL + 2; + resize->height = this->line_height; + + size->height = 4 * resize->height + this->top_spacing + this->bottom_spacing; // At least 4 lines are visible. + size->width = max(200u, size->width); // At least 200 pixels wide. + break; + } + } + + virtual void OnPaint() + { + this->OnInvalidateData(0); + this->DrawWidgets(); + } + + virtual void DrawWidget(const Rect &r, int widget) const + { + if (widget != GRW_WIDGET_BACKGROUND) return; + } + + virtual void OnResize() + { + } + + /** + * 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) + { + if (!gui_scope) return; + DeleteChildWindows(WC_NEWGRF_README); + } +}; + +const int NewGRFReadmeWindow::top_spacing = WD_FRAMERECT_TOP + 4; +const int NewGRFReadmeWindow::bottom_spacing = WD_FRAMERECT_BOTTOM; + +static const NWidgetPart _nested_newgrf_readme_widgets[] = { + NWidget(NWID_HORIZONTAL), + NWidget(WWT_CLOSEBOX, COLOUR_MAUVE), + NWidget(WWT_CAPTION, COLOUR_MAUVE), SetDataTip(STR_NEWGRF_README_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS), + NWidget(WWT_SHADEBOX, COLOUR_MAUVE), + NWidget(WWT_STICKYBOX, COLOUR_MAUVE), + EndContainer(), + NWidget(NWID_HORIZONTAL), + NWidget(WWT_PANEL, COLOUR_MAUVE, GRW_WIDGET_BACKGROUND), SetMinimalSize(200, 125), SetResize(1, 12), SetScrollbar(GRW_WIDGET_SCROLLBAR), + EndContainer(), + NWidget(NWID_VERTICAL), + NWidget(NWID_VSCROLLBAR, COLOUR_MAUVE, GRW_WIDGET_SCROLLBAR), + NWidget(WWT_RESIZEBOX, COLOUR_MAUVE), + EndContainer(), + EndContainer(), +}; + +/* Window definition for the grf readme window */ +static const WindowDesc _newgrf_readme_desc( + WDP_CENTER, 630, 460, + WC_NEWGRF_README, WC_NONE, + WDF_UNCLICK_BUTTONS, + _nested_newgrf_readme_widgets, lengthof(_nested_newgrf_readme_widgets) +); + +void OpenNewGRFReadmeWindow(GRFConfig *c) +{ + DeleteWindowByClass(WC_NEWGRF_README); + new NewGRFReadmeWindow(&_newgrf_readme_desc, c); +} + static GRFPresetList _grf_preset_list; class DropDownListPresetItem : public DropDownListItem { @@ -492,6 +597,7 @@ SNGRFS_SCROLL2BAR, SNGRFS_NEWGRF_INFO_TITLE, SNGRFS_NEWGRF_INFO, + SNGRFS_NEWGRF_README, SNGRFS_SET_PARAMETERS, SNGRFS_TOGGLE_PALETTE, SNGRFS_APPLY_CHANGES, @@ -570,6 +676,7 @@ ~NewGRFWindow() { DeleteWindowByClass(WC_NEWGRF_PARAMETERS); + DeleteWindowByClass(WC_NEWGRF_README); if (this->editable && !this->execute) { CopyGRFConfigList(this->orig_list, this->actives, true); @@ -936,6 +1043,18 @@ } this->DeleteChildWindows(WC_QUERY_STRING); // Remove the parameter query window break; + + case SNGRFS_NEWGRF_README: { // View GRF readme + if (this->active_sel == NULL && this->avail_sel == NULL) break; + + if (this->active_sel) { + OpenNewGRFReadmeWindow(this->active_sel); + break; + } + GRFConfig *c = new GRFConfig(*this->avail_sel); + OpenNewGRFReadmeWindow(c); + break; + } case SNGRFS_SET_PARAMETERS: { // Edit parameters if (this->active_sel == NULL || !this->editable || !this->show_params) break; @@ -986,6 +1105,7 @@ this->avails.ForceRebuild(); this->InvalidateData(1); this->DeleteChildWindows(WC_QUERY_STRING); // Remove the parameter query window + this->DeleteChildWindows(WC_NEWGRF_README); // Remove the view readme window InvalidateWindowClassesData(WC_SAVELOAD); break; } @@ -1102,6 +1222,13 @@ SNGRFS_MOVE_DOWN, WIDGET_LIST_END ); + + bool disable_readme = false; + if (this->avail_sel == NULL && this->active_sel == NULL) disable_readme = true; + const GRFConfig *c = (this->avail_sel == NULL ? this->active_sel : this->avail_sel); + if (!GrfHasReadme(c)) disable_readme = true; + this->SetWidgetDisabledState(SNGRFS_NEWGRF_README, disable_readme); + this->SetWidgetDisabledState(SNGRFS_SET_PARAMETERS, !this->show_params || disable_all); this->SetWidgetDisabledState(SNGRFS_TOGGLE_PALETTE, disable_all); @@ -1586,6 +1713,8 @@ NWidget(WWT_PANEL, COLOUR_MAUVE), SetPadding(0, 0, 2, 0), NWidget(WWT_EMPTY, COLOUR_MAUVE, SNGRFS_NEWGRF_INFO_TITLE), SetFill(1, 0), SetResize(1, 0), NWidget(WWT_EMPTY, COLOUR_MAUVE, SNGRFS_NEWGRF_INFO), SetFill(1, 1), SetResize(1, 1), SetMinimalSize(150, 100), + NWidget(WWT_PUSHTXTBTN, COLOUR_YELLOW, SNGRFS_NEWGRF_README), SetFill(1, 0), SetResize(1, 0), + SetDataTip(STR_NEWGRF_SETTINGS_VIEW_README, STR_NULL), SetPadding(2, 2, 2, 2), EndContainer(), NWidget(NWID_SELECTION, INVALID_COLOUR, SNGRFS_SHOW_APPLY), /* Right side, buttons. */ diff -r c42a62268eee src/window_type.h --- a/src/window_type.h Fri Apr 29 18:35:36 2011 +0100 +++ b/src/window_type.h Tue May 10 20:02:29 2011 +0100 @@ -111,6 +111,7 @@ WC_INDUSTRY_CARGOES, WC_NEWGRF_PARAMETERS, WC_BUILD_OBJECT, + WC_NEWGRF_README, WC_INVALID = 0xFFFF };