# HG changeset patch # Parent 3fb0e89ad828d3eadb859cb2bd37469f6b37e8ba diff --git a/projects/openttd_vs100.vcxproj b/projects/openttd_vs100.vcxproj --- a/projects/openttd_vs100.vcxproj +++ b/projects/openttd_vs100.vcxproj @@ -573,6 +573,8 @@ + + diff --git a/projects/openttd_vs100.vcxproj.filters b/projects/openttd_vs100.vcxproj.filters --- a/projects/openttd_vs100.vcxproj.filters +++ b/projects/openttd_vs100.vcxproj.filters @@ -948,6 +948,12 @@ Header Files + + Header Files + + + Header Files + Header Files diff --git a/projects/openttd_vs80.vcproj b/projects/openttd_vs80.vcproj --- a/projects/openttd_vs80.vcproj +++ b/projects/openttd_vs80.vcproj @@ -1567,6 +1567,14 @@ > + + + + diff --git a/projects/openttd_vs90.vcproj b/projects/openttd_vs90.vcproj --- a/projects/openttd_vs90.vcproj +++ b/projects/openttd_vs90.vcproj @@ -1564,6 +1564,14 @@ > + + + + diff --git a/source.list b/source.list --- a/source.list +++ b/source.list @@ -306,6 +306,8 @@ terraform_gui.h textbuf_gui.h texteff.hpp +textfile_gui.h +textfile_type.h tgp.h tile_cmd.h tile_type.h diff --git a/src/newgrf_config.h b/src/newgrf_config.h --- a/src/newgrf_config.h +++ b/src/newgrf_config.h @@ -17,6 +17,7 @@ #include "core/smallmap_type.hpp" #include "misc/countedptr.hpp" #include "fileio_type.h" +#include "textfile_type.h" /** GRF config bit flags */ enum GCF_Flags { @@ -145,18 +146,6 @@ ~GRFTextWrapper(); }; -/** Additional text files accompanying NewGRFs */ -enum TextfileType { - TFT_BEGIN, - - TFT_README = TFT_BEGIN, ///< NewGRF readme - TFT_CHANGELOG, ///< NewGRF changelog - TFT_LICENSE, ///< NewGRF license - - TFT_END, -}; -DECLARE_POSTFIX_INCREMENT(TextfileType) - /** Information about GRF, used in the game and (part of it) in savegames */ struct GRFConfig : ZeroedMemoryAllocator { GRFConfig(const char *filename = NULL); diff --git a/src/newgrf_gui.cpp b/src/newgrf_gui.cpp --- a/src/newgrf_gui.cpp +++ b/src/newgrf_gui.cpp @@ -25,8 +25,7 @@ #include "querystring_gui.h" #include "core/geometry_func.hpp" #include "newgrf_text.h" -#include "fileio_func.h" -#include "fontcache.h" +#include "textfile_gui.h" #include "widgets/newgrf_widget.h" @@ -465,207 +464,27 @@ } /** Window for displaying the textfile of a NewGRF. */ -struct NewGRFTextfileWindow : public Window, MissingGlyphSearcher { - const GRFConfig *grf_config; ///< View the textfile of this GRFConfig. - TextfileType file_type; ///< Type of textfile to view. - int line_height; ///< Height of a line in the display widget. - Scrollbar *vscroll; ///< Vertical scrollbar. - Scrollbar *hscroll; ///< Horizontal scrollbar. - char *text; ///< Lines of text from the NewGRF's textfile. - SmallVector lines; ///< #text, split into lines in a table with lines. - uint max_length; ///< The longest line in the textfile (in pixels). +struct NewGRFTextfileWindow : public TextfileWindow { + const GRFConfig *grf_config; ///< View the textfile of this GRFConfig. - static const int TOP_SPACING = WD_FRAMETEXT_TOP; ///< Additional spacing at the top of the #WID_NT_BACKGROUND widget. - static const int BOTTOM_SPACING = WD_FRAMETEXT_BOTTOM; ///< Additional spacing at the bottom of the #WID_NT_BACKGROUND widget. + NewGRFTextfileWindow(const WindowDesc *desc, TextfileType file_type, const GRFConfig *c) : TextfileWindow(desc, file_type), grf_config(c) + { + this->GetWidget(WID_TF_CAPTION)->SetDataTip(STR_NEWGRF_README_CAPTION + file_type, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS); - NewGRFTextfileWindow(const WindowDesc *desc, const GRFConfig *c, TextfileType file_type) : Window(), grf_config(c), file_type(file_type) - { - this->CreateNestedTree(desc); - this->GetWidget(WID_NT_CAPTION)->SetDataTip(STR_NEWGRF_README_CAPTION + file_type, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS); - this->vscroll = this->GetScrollbar(WID_NT_VSCROLLBAR); - this->hscroll = this->GetScrollbar(WID_NT_HSCROLLBAR); - this->FinishInitNested(desc); - - this->LoadTextfile(); + const char *textfile = this->grf_config->GetTextfile(file_type); + this->LoadTextfile(textfile, NEWGRF_DIR); } - ~NewGRFTextfileWindow() + /* virtual */ void SetStringParameters(int widget) const { - free(this->text); - } - - virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) - { - switch (widget) { - case WID_NT_BACKGROUND: - this->line_height = FONT_HEIGHT_MONO + 2; - resize->height = this->line_height; - - size->height = 4 * resize->height + TOP_SPACING + BOTTOM_SPACING; // At least 4 lines are visible. - size->width = max(200u, size->width); // At least 200 pixels wide. - break; - } - } - - virtual void SetStringParameters(int widget) const - { - if (widget == WID_NT_CAPTION) SetDParamStr(0, this->grf_config->GetName()); - } - - virtual void DrawWidget(const Rect &r, int widget) const - { - if (widget != WID_NT_BACKGROUND) return; - - int width = r.right - r.left + 1 - WD_BEVEL_LEFT - WD_BEVEL_RIGHT; - int height = r.bottom - r.top + 1 - WD_BEVEL_LEFT - WD_BEVEL_RIGHT; - - DrawPixelInfo new_dpi; - if (!FillDrawPixelInfo(&new_dpi, r.left + WD_BEVEL_LEFT, r.top, width, height)) return; - DrawPixelInfo *old_dpi = _cur_dpi; - _cur_dpi = &new_dpi; - - int left, right; - if (_current_text_dir == TD_RTL) { - left = width + WD_BEVEL_RIGHT - WD_FRAMETEXT_RIGHT - this->hscroll->GetCount(); - right = width + WD_BEVEL_RIGHT - WD_FRAMETEXT_RIGHT - 1 + this->hscroll->GetPosition(); - } else { - left = WD_FRAMETEXT_LEFT - WD_BEVEL_LEFT - this->hscroll->GetPosition(); - right = WD_FRAMETEXT_LEFT - WD_BEVEL_LEFT + this->hscroll->GetCount() - 1; - } - int top = TOP_SPACING; - for (uint i = 0; i < this->vscroll->GetCapacity() && i + this->vscroll->GetPosition() < this->lines.Length(); i++) { - DrawString(left, right, top + i * this->line_height, this->lines[i + this->vscroll->GetPosition()], TC_WHITE, SA_LEFT, false, FS_MONO); - } - - _cur_dpi = old_dpi; - } - - virtual void OnResize() - { - this->vscroll->SetCapacityFromWidget(this, WID_NT_BACKGROUND, TOP_SPACING + BOTTOM_SPACING); - this->hscroll->SetCapacityFromWidget(this, WID_NT_BACKGROUND); - } - -private: - uint search_iterator; ///< Iterator for the font check search. - - /* virtual */ void Reset() - { - this->search_iterator = 0; - } - - FontSize DefaultSize() - { - return FS_MONO; - } - - const char *NextString() - { - if (this->search_iterator >= this->lines.Length()) return NULL; - - return this->lines[this->search_iterator++]; - } - - /* virtual */ bool Monospace() - { - return true; - } - - /* virtual */ void SetFontNames(FreeTypeSettings *settings, const char *font_name) - { -#ifdef WITH_FREETYPE - strecpy(settings->mono_font, font_name, lastof(settings->mono_font)); -#endif /* WITH_FREETYPE */ - } - - /** - * Load the NewGRF's textfile text from file, and setup #lines, #max_length, and both scrollbars. - */ - void LoadTextfile() - { - this->lines.Clear(); - - /* Does GRF have a file of the demanded type? */ - const char *textfile = this->grf_config->GetTextfile(file_type); - if (textfile == NULL) return; - - /* Get text from file */ - size_t filesize; - FILE *handle = FioFOpenFile(textfile, "rb", NEWGRF_DIR, &filesize); - if (handle == NULL) return; - - this->text = ReallocT(this->text, filesize + 1); - size_t read = fread(this->text, 1, filesize, handle); - fclose(handle); - - if (read != filesize) return; - - this->text[filesize] = '\0'; - - /* Replace tabs and line feeds with a space since str_validate removes those. */ - for (char *p = this->text; *p != '\0'; p++) { - if (*p == '\t' || *p == '\r') *p = ' '; - } - - /* Check for the byte-order-mark, and skip it if needed. */ - char *p = this->text + (strncmp("\xEF\xBB\xBF", this->text, 3) == 0 ? 3 : 0); - - /* Make sure the string is a valid UTF-8 sequence. */ - str_validate(p, this->text + filesize, SVS_REPLACE_WITH_QUESTION_MARK | SVS_ALLOW_NEWLINE); - - /* Split the string on newlines. */ - *this->lines.Append() = p; - for (; *p != '\0'; p++) { - if (*p == '\n') { - *p = '\0'; - *this->lines.Append() = p + 1; - } - } - - CheckForMissingGlyphs(true, this); - - /* Initialize scrollbars */ - this->vscroll->SetCount(this->lines.Length()); - - this->max_length = 0; - for (uint i = 0; i < this->lines.Length(); i++) { - this->max_length = max(this->max_length, GetStringBoundingBox(this->lines[i], FS_MONO).width); - } - this->hscroll->SetCount(this->max_length + WD_FRAMETEXT_LEFT + WD_FRAMETEXT_RIGHT); - this->hscroll->SetStepSize(10); // Speed up horizontal scrollbar + if (widget == WID_TF_CAPTION) SetDParamStr(0, this->grf_config->GetName()); } }; -static const NWidgetPart _nested_newgrf_textfile_widgets[] = { - NWidget(NWID_HORIZONTAL), - NWidget(WWT_CLOSEBOX, COLOUR_MAUVE), - NWidget(WWT_CAPTION, COLOUR_MAUVE, WID_NT_CAPTION), SetDataTip(STR_NULL, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS), - EndContainer(), - NWidget(NWID_HORIZONTAL), - NWidget(WWT_PANEL, COLOUR_MAUVE, WID_NT_BACKGROUND), SetMinimalSize(200, 125), SetResize(1, 12), SetScrollbar(WID_NT_VSCROLLBAR), - EndContainer(), - NWidget(NWID_VERTICAL), - NWidget(NWID_VSCROLLBAR, COLOUR_MAUVE, WID_NT_VSCROLLBAR), - EndContainer(), - EndContainer(), - NWidget(NWID_HORIZONTAL), - NWidget(NWID_HSCROLLBAR, COLOUR_MAUVE, WID_NT_HSCROLLBAR), - NWidget(WWT_RESIZEBOX, COLOUR_MAUVE), - EndContainer(), -}; - -/** Window definition for the grf textfile window */ -static const WindowDesc _newgrf_textfile_desc( - WDP_CENTER, 630, 460, - WC_NEWGRF_TEXTFILE, WC_NONE, - WDF_UNCLICK_BUTTONS, - _nested_newgrf_textfile_widgets, lengthof(_nested_newgrf_textfile_widgets) -); - -void ShowNewGRFTextfileWindow(const GRFConfig *c, TextfileType file_type) +void ShowNewGRFTextfileWindow(TextfileType file_type, const GRFConfig *c) { - DeleteWindowByClass(WC_NEWGRF_TEXTFILE); - new NewGRFTextfileWindow(&_newgrf_textfile_desc, c, file_type); + DeleteWindowByClass(WC_TEXTFILE); + new NewGRFTextfileWindow(&_textfile_desc, file_type, c); } static GRFPresetList _grf_preset_list; @@ -756,7 +575,7 @@ ~NewGRFWindow() { DeleteWindowByClass(WC_GRF_PARAMETERS); - DeleteWindowByClass(WC_NEWGRF_TEXTFILE); + DeleteWindowByClass(WC_TEXTFILE); if (this->editable && !this->execute) { CopyGRFConfigList(this->orig_list, this->actives, true); @@ -962,7 +781,7 @@ if (widget >= WID_NS_NEWGRF_TEXTFILE && widget < WID_NS_NEWGRF_TEXTFILE + TFT_END) { if (this->active_sel == NULL && this->avail_sel == NULL) return; - ShowNewGRFTextfileWindow(this->active_sel != NULL ? this->active_sel : this->avail_sel, (TextfileType)(widget - WID_NS_NEWGRF_TEXTFILE)); + ShowNewGRFTextfileWindow((TextfileType)(widget - WID_NS_NEWGRF_TEXTFILE), this->active_sel != NULL ? this->active_sel : this->avail_sel); return; } @@ -1185,8 +1004,8 @@ this->avail_sel = NULL; this->avail_pos = -1; this->avails.ForceRebuild(); - this->DeleteChildWindows(WC_QUERY_STRING); // Remove the parameter query window - this->DeleteChildWindows(WC_NEWGRF_TEXTFILE); // Remove the view textfile window + this->DeleteChildWindows(WC_QUERY_STRING); // Remove the parameter query window + this->DeleteChildWindows(WC_TEXTFILE); // Remove the view textfile window } virtual void OnDropdownSelect(int widget, int index) diff --git a/src/script/api/game/game_window.hpp.sq b/src/script/api/game/game_window.hpp.sq --- a/src/script/api/game/game_window.hpp.sq +++ b/src/script/api/game/game_window.hpp.sq @@ -59,7 +59,7 @@ SQGSWindow.DefSQConst(engine, ScriptWindow::WC_SET_DATE, "WC_SET_DATE"); SQGSWindow.DefSQConst(engine, ScriptWindow::WC_AI_SETTINGS, "WC_AI_SETTINGS"); SQGSWindow.DefSQConst(engine, ScriptWindow::WC_GRF_PARAMETERS, "WC_GRF_PARAMETERS"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WC_NEWGRF_TEXTFILE, "WC_NEWGRF_TEXTFILE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WC_TEXTFILE, "WC_TEXTFILE"); SQGSWindow.DefSQConst(engine, ScriptWindow::WC_TOWN_AUTHORITY, "WC_TOWN_AUTHORITY"); SQGSWindow.DefSQConst(engine, ScriptWindow::WC_VEHICLE_DETAILS, "WC_VEHICLE_DETAILS"); SQGSWindow.DefSQConst(engine, ScriptWindow::WC_VEHICLE_REFIT, "WC_VEHICLE_REFIT"); @@ -750,10 +750,6 @@ SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NP_RESET, "WID_NP_RESET"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NP_SHOW_DESCRIPTION, "WID_NP_SHOW_DESCRIPTION"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NP_DESCRIPTION, "WID_NP_DESCRIPTION"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NT_CAPTION, "WID_NT_CAPTION"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NT_BACKGROUND, "WID_NT_BACKGROUND"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NT_VSCROLLBAR, "WID_NT_VSCROLLBAR"); - SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NT_HSCROLLBAR, "WID_NT_HSCROLLBAR"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NS_PRESET_LIST, "WID_NS_PRESET_LIST"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NS_PRESET_SAVE, "WID_NS_PRESET_SAVE"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NS_PRESET_DELETE, "WID_NS_PRESET_DELETE"); @@ -782,6 +778,10 @@ SQGSWindow.DefSQConst(engine, ScriptWindow::WID_NS_SHOW_APPLY, "WID_NS_SHOW_APPLY"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SP_PROGRESS_BAR, "WID_SP_PROGRESS_BAR"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SP_PROGRESS_TEXT, "WID_SP_PROGRESS_TEXT"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TF_CAPTION, "WID_TF_CAPTION"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TF_BACKGROUND, "WID_TF_BACKGROUND"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TF_VSCROLLBAR, "WID_TF_VSCROLLBAR"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TF_HSCROLLBAR, "WID_TF_HSCROLLBAR"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_N_PANEL, "WID_N_PANEL"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_N_TITLE, "WID_N_TITLE"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_N_HEADLINE, "WID_N_HEADLINE"); diff --git a/src/script/api/script_window.hpp b/src/script/api/script_window.hpp --- a/src/script/api/script_window.hpp +++ b/src/script/api/script_window.hpp @@ -250,7 +250,7 @@ * textfile; Window numbers: * - 0 = #NewGRFTextfileWidgets */ - WC_NEWGRF_TEXTFILE = ::WC_NEWGRF_TEXTFILE, + WC_TEXTFILE = ::WC_TEXTFILE, /** @@ -1671,14 +1671,6 @@ WID_NP_DESCRIPTION = ::WID_NP_DESCRIPTION, ///< Multi-line description of a parameter. }; - /** Widgets of the #NewGRFTextfileWindow class. */ - enum NewGRFTextfileWidgets { - WID_NT_CAPTION = ::WID_NT_CAPTION, ///< The caption of the window. - WID_NT_BACKGROUND = ::WID_NT_BACKGROUND, ///< Panel to draw the textfile on. - WID_NT_VSCROLLBAR = ::WID_NT_VSCROLLBAR, ///< Vertical scrollbar to scroll through the textfile up-and-down. - WID_NT_HSCROLLBAR = ::WID_NT_HSCROLLBAR, ///< Horizontal scrollbar to scroll through the textfile left-to-right. - }; - /** Widgets of the #NewGRFWindow class. */ enum NewGRFStateWidgets { WID_NS_PRESET_LIST = ::WID_NS_PRESET_LIST, ///< Active NewGRF preset. @@ -1715,6 +1707,14 @@ WID_SP_PROGRESS_TEXT = ::WID_SP_PROGRESS_TEXT, ///< Text explaining what is happening. }; + /** Widgets of the #TextfileWindow class. */ + enum TextfileWidgets { + WID_TF_CAPTION = ::WID_TF_CAPTION, ///< The caption of the window. + WID_TF_BACKGROUND = ::WID_TF_BACKGROUND, ///< Panel to draw the textfile on. + WID_TF_VSCROLLBAR = ::WID_TF_VSCROLLBAR, ///< Vertical scrollbar to scroll through the textfile up-and-down. + WID_TF_HSCROLLBAR = ::WID_TF_HSCROLLBAR, ///< Horizontal scrollbar to scroll through the textfile left-to-right. + }; + /** Widgets of the #NewsWindow class. */ enum NewsWidgets { WID_N_PANEL = ::WID_N_PANEL, ///< Panel of the window. diff --git a/src/script/api/template/template_window.hpp.sq b/src/script/api/template/template_window.hpp.sq --- a/src/script/api/template/template_window.hpp.sq +++ b/src/script/api/template/template_window.hpp.sq @@ -155,12 +155,12 @@ template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::SpriteAlignerWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } template <> inline ScriptWindow::NewGRFParametersWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::NewGRFParametersWidgets)tmp; } template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::NewGRFParametersWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } - template <> inline ScriptWindow::NewGRFTextfileWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::NewGRFTextfileWidgets)tmp; } - template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::NewGRFTextfileWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } template <> inline ScriptWindow::NewGRFStateWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::NewGRFStateWidgets)tmp; } template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::NewGRFStateWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } template <> inline ScriptWindow::ScanProgressWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::ScanProgressWidgets)tmp; } template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::ScanProgressWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } + template <> inline ScriptWindow::TextfileWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::TextfileWidgets)tmp; } + template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::TextfileWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } template <> inline ScriptWindow::NewsWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::NewsWidgets)tmp; } template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::NewsWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } template <> inline ScriptWindow::MessageHistoryWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::MessageHistoryWidgets)tmp; } diff --git a/src/textfile_gui.h b/src/textfile_gui.h new file mode 100644 --- /dev/null +++ b/src/textfile_gui.h @@ -0,0 +1,219 @@ +/* $Id$ */ + +/* + * This file is part of OpenTTD. + * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2. + * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see . + */ + +/** @file textfile_gui.h GUI functions related to textfiles. */ + +#ifndef TEXTFILE_GUI_H +#define TEXTFILE_GUI_H + +#include "fileio_func.h" +#include "fontcache.h" +#include "gfx_type.h" +#include "gfx_func.h" +#include "string_func.h" +#include "strings_func.h" +#include "textfile_type.h" +#include "window_gui.h" + +#include "widgets/misc_widget.h" + +#include "table/strings.h" + +/** Window for displaying a textfile */ +struct TextfileWindow : public Window, MissingGlyphSearcher { + TextfileType file_type; ///< Type of textfile to view. + int line_height; ///< Height of a line in the display widget. + Scrollbar *vscroll; ///< Vertical scrollbar. + Scrollbar *hscroll; ///< Horizontal scrollbar. + char *text; ///< Lines of text from the NewGRF's textfile. + SmallVector lines; ///< #text, split into lines in a table with lines. + uint max_length; ///< The longest line in the textfile (in pixels). + + static const int TOP_SPACING = WD_FRAMETEXT_TOP; ///< Additional spacing at the top of the #WID_TF_BACKGROUND widget. + static const int BOTTOM_SPACING = WD_FRAMETEXT_BOTTOM; ///< Additional spacing at the bottom of the #WID_TF_BACKGROUND widget. + + TextfileWindow(const WindowDesc *desc, TextfileType file_type) : Window(), file_type(file_type) + { + this->CreateNestedTree(desc); + this->vscroll = this->GetScrollbar(WID_TF_VSCROLLBAR); + this->hscroll = this->GetScrollbar(WID_TF_HSCROLLBAR); + this->FinishInitNested(desc); + } + + virtual ~TextfileWindow() + { + free(this->text); + } + + virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) + { + switch (widget) { + case WID_TF_BACKGROUND: + this->line_height = FONT_HEIGHT_MONO + 2; + resize->height = this->line_height; + + size->height = 4 * resize->height + TOP_SPACING + BOTTOM_SPACING; // At least 4 lines are visible. + size->width = max(200u, size->width); // At least 200 pixels wide. + break; + } + } + + virtual void SetStringParameters(int widget) const {}; + + virtual void DrawWidget(const Rect &r, int widget) const + { + if (widget != WID_TF_BACKGROUND) return; + + int width = r.right - r.left + 1 - WD_BEVEL_LEFT - WD_BEVEL_RIGHT; + int height = r.bottom - r.top + 1 - WD_BEVEL_LEFT - WD_BEVEL_RIGHT; + + DrawPixelInfo new_dpi; + if (!FillDrawPixelInfo(&new_dpi, r.left + WD_BEVEL_LEFT, r.top, width, height)) return; + DrawPixelInfo *old_dpi = _cur_dpi; + _cur_dpi = &new_dpi; + + int left, right; + if (_current_text_dir == TD_RTL) { + left = width + WD_BEVEL_RIGHT - WD_FRAMETEXT_RIGHT - this->hscroll->GetCount(); + right = width + WD_BEVEL_RIGHT - WD_FRAMETEXT_RIGHT - 1 + this->hscroll->GetPosition(); + } else { + left = WD_FRAMETEXT_LEFT - WD_BEVEL_LEFT - this->hscroll->GetPosition(); + right = WD_FRAMETEXT_LEFT - WD_BEVEL_LEFT + this->hscroll->GetCount() - 1; + } + int top = TOP_SPACING; + for (uint i = 0; i < this->vscroll->GetCapacity() && i + this->vscroll->GetPosition() < this->lines.Length(); i++) { + DrawString(left, right, top + i * this->line_height, this->lines[i + this->vscroll->GetPosition()], TC_WHITE, SA_LEFT, false, FS_MONO); + } + + _cur_dpi = old_dpi; + } + + virtual void OnResize() + { + this->vscroll->SetCapacityFromWidget(this, WID_TF_BACKGROUND, TOP_SPACING + BOTTOM_SPACING); + this->hscroll->SetCapacityFromWidget(this, WID_TF_BACKGROUND); + } + + uint search_iterator; ///< Iterator for the font check search. + + /* virtual */ void Reset() + { + this->search_iterator = 0; + } + + virtual FontSize DefaultSize() + { + return FS_MONO; + } + + virtual const char *NextString() + { + if (this->search_iterator >= this->lines.Length()) return NULL; + + return this->lines[this->search_iterator++]; + } + + /* virtual */ bool Monospace() + { + return true; + } + + /* virtual */ void SetFontNames(FreeTypeSettings *settings, const char *font_name) + { +#ifdef WITH_FREETYPE + strecpy(settings->mono_font, font_name, lastof(settings->mono_font)); +#endif /* WITH_FREETYPE */ + } + + /** + * Loads the textfile text from file, and setup #lines, #max_length, and both scrollbars. + */ + virtual void LoadTextfile(const char *textfile, Subdirectory dir) + { + if (textfile == NULL) return; + + this->lines.Clear(); + + /* Get text from file */ + size_t filesize; + FILE *handle = FioFOpenFile(textfile, "rb", dir, &filesize); + if (handle == NULL) return; + + this->text = ReallocT(this->text, filesize + 1); + size_t read = fread(this->text, 1, filesize, handle); + fclose(handle); + + if (read != filesize) return; + + this->text[filesize] = '\0'; + + /* Replace tabs and line feeds with a space since str_validate removes those. */ + for (char *p = this->text; *p != '\0'; p++) { + if (*p == '\t' || *p == '\r') *p = ' '; + } + + /* Check for the byte-order-mark, and skip it if needed. */ + char *p = this->text + (strncmp("\xEF\xBB\xBF", this->text, 3) == 0 ? 3 : 0); + + /* Make sure the string is a valid UTF-8 sequence. */ + str_validate(p, this->text + filesize, SVS_REPLACE_WITH_QUESTION_MARK | SVS_ALLOW_NEWLINE); + + /* Split the string on newlines. */ + *this->lines.Append() = p; + for (; *p != '\0'; p++) { + if (*p == '\n') { + *p = '\0'; + *this->lines.Append() = p + 1; + } + } + + CheckForMissingGlyphs(true, this); + + /* Initialize scrollbars */ + this->vscroll->SetCount(this->lines.Length()); + + this->max_length = 0; + for (uint i = 0; i < this->lines.Length(); i++) { + this->max_length = max(this->max_length, GetStringBoundingBox(this->lines[i], FS_MONO).width); + } + this->hscroll->SetCount(this->max_length + WD_FRAMETEXT_LEFT + WD_FRAMETEXT_RIGHT); + this->hscroll->SetStepSize(10); // Speed up horizontal scrollbar + } +}; + +/** Widgets for the textfile window. */ +static const NWidgetPart _nested_textfile_widgets[] = { + NWidget(NWID_HORIZONTAL), + NWidget(WWT_CLOSEBOX, COLOUR_MAUVE), + NWidget(WWT_CAPTION, COLOUR_MAUVE, WID_TF_CAPTION), SetDataTip(STR_NULL, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS), + EndContainer(), + NWidget(NWID_HORIZONTAL), + NWidget(WWT_PANEL, COLOUR_MAUVE, WID_TF_BACKGROUND), SetMinimalSize(200, 125), SetResize(1, 12), SetScrollbar(WID_TF_VSCROLLBAR), + EndContainer(), + NWidget(NWID_VERTICAL), + NWidget(NWID_VSCROLLBAR, COLOUR_MAUVE, WID_TF_VSCROLLBAR), + EndContainer(), + EndContainer(), + NWidget(NWID_HORIZONTAL), + NWidget(NWID_HSCROLLBAR, COLOUR_MAUVE, WID_TF_HSCROLLBAR), + NWidget(WWT_RESIZEBOX, COLOUR_MAUVE), + EndContainer(), +}; + +/** Window definition for the textfile window */ +static const WindowDesc _textfile_desc( + WDP_CENTER, 630, 460, + WC_TEXTFILE, WC_NONE, + WDF_UNCLICK_BUTTONS, + _nested_textfile_widgets, lengthof(_nested_textfile_widgets) +); + + + +#endif /* TEXTFILE_GUI_H */ diff --git a/src/textfile_type.h b/src/textfile_type.h new file mode 100644 --- /dev/null +++ b/src/textfile_type.h @@ -0,0 +1,27 @@ +/* $Id$ */ + +/* + * This file is part of OpenTTD. + * OpenTTD is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, version 2. + * OpenTTD is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with OpenTTD. If not, see . + */ + +/** @file textfile_type.h Types related to textfiles. */ + +#ifndef TEXTFILE_TYPE_H +#define TEXTFILE_TYPE_H + +/** Additional text files accompanying Tar archives */ +enum TextfileType { + TFT_BEGIN, + + TFT_README = TFT_BEGIN, ///< NewGRF readme + TFT_CHANGELOG, ///< NewGRF changelog + TFT_LICENSE, ///< NewGRF license + + TFT_END, +}; +DECLARE_POSTFIX_INCREMENT(TextfileType) + +#endif /* TEXTFILE_TYPE_H */ diff --git a/src/widgets/misc_widget.h b/src/widgets/misc_widget.h --- a/src/widgets/misc_widget.h +++ b/src/widgets/misc_widget.h @@ -45,4 +45,12 @@ WID_Q_YES, ///< No button. }; +/** Widgets of the #TextfileWindow class. */ +enum TextfileWidgets { + WID_TF_CAPTION, ///< The caption of the window. + WID_TF_BACKGROUND, ///< Panel to draw the textfile on. + WID_TF_VSCROLLBAR, ///< Vertical scrollbar to scroll through the textfile up-and-down. + WID_TF_HSCROLLBAR, ///< Horizontal scrollbar to scroll through the textfile left-to-right. +}; + #endif /* WIDGETS_MISC_WIDGET_H */ diff --git a/src/widgets/newgrf_widget.h b/src/widgets/newgrf_widget.h --- a/src/widgets/newgrf_widget.h +++ b/src/widgets/newgrf_widget.h @@ -13,6 +13,7 @@ #define WIDGETS_NEWGRF_WIDGET_H #include "../newgrf_config.h" +#include "../textfile_type.h" /** Widgets of the #NewGRFParametersWindow class. */ enum NewGRFParametersWidgets { @@ -29,14 +30,6 @@ WID_NP_DESCRIPTION, ///< Multi-line description of a parameter. }; -/** Widgets of the #NewGRFTextfileWindow class. */ -enum NewGRFTextfileWidgets { - WID_NT_CAPTION, ///< The caption of the window. - WID_NT_BACKGROUND, ///< Panel to draw the textfile on. - WID_NT_VSCROLLBAR, ///< Vertical scrollbar to scroll through the textfile up-and-down. - WID_NT_HSCROLLBAR, ///< Horizontal scrollbar to scroll through the textfile left-to-right. -}; - /** Widgets of the #NewGRFWindow class. */ enum NewGRFStateWidgets { WID_NS_PRESET_LIST, ///< Active NewGRF preset. diff --git a/src/window.cpp b/src/window.cpp --- a/src/window.cpp +++ b/src/window.cpp @@ -999,9 +999,9 @@ case WC_CUSTOM_CURRENCY: case WC_NETWORK_WINDOW: case WC_GRF_PARAMETERS: - case WC_NEWGRF_TEXTFILE: case WC_AI_LIST: case WC_AI_SETTINGS: + case WC_TEXTFILE: ++z_priority; case WC_CONSOLE: diff --git a/src/window_type.h b/src/window_type.h --- a/src/window_type.h +++ b/src/window_type.h @@ -181,7 +181,7 @@ * textfile; %Window numbers: * - 0 = #NewGRFTextfileWidgets */ - WC_NEWGRF_TEXTFILE, + WC_TEXTFILE, /**