# textfile_gui.cpp

Go to the documentation of this file.

    00001 /* $Id: textfile_gui.cpp 25925 2013-10-28 12:15:44Z frosch $ */
    00002
    00003 /*
    00004  * This file is part of OpenTTD.
    00005  * 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.
    00006  * 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.
    00007  * 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 <http://www.gnu.org/licenses/>.
    00008  */
    00009
    00012 #include "stdafx.h"
    00013 #include "fileio_func.h"
    00014 #include "fontcache.h"
    00015 #include "gfx_type.h"
    00016 #include "gfx_func.h"
    00017 #include "string_func.h"
    00018 #include "textfile_gui.h"
    00019
    00020 #include "widgets/misc_widget.h"
    00021
    00022 #include "table/strings.h"
    00023
    00025 static const NWidgetPart _nested_textfile_widgets[] = {
    00026   NWidget(NWID_HORIZONTAL),
    00027     NWidget(WWT_CLOSEBOX, COLOUR_MAUVE),
    00028     NWidget(WWT_CAPTION, COLOUR_MAUVE, WID_TF_CAPTION), SetDataTip(STR_NULL, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
    00029     NWidget(WWT_TEXTBTN, COLOUR_MAUVE, WID_TF_WRAPTEXT), SetDataTip(STR_TEXTFILE_WRAP_TEXT, STR_TEXTFILE_WRAP_TEXT_TOOLTIP),
    00030     NWidget(WWT_DEFSIZEBOX, COLOUR_MAUVE),
    00031   EndContainer(),
    00032   NWidget(NWID_HORIZONTAL),
    00033     NWidget(WWT_PANEL, COLOUR_MAUVE, WID_TF_BACKGROUND), SetMinimalSize(200, 125), SetResize(1, 12), SetScrollbar(WID_TF_VSCROLLBAR),
    00034     EndContainer(),
    00035     NWidget(NWID_VERTICAL),
    00036       NWidget(NWID_VSCROLLBAR, COLOUR_MAUVE, WID_TF_VSCROLLBAR),
    00037     EndContainer(),
    00038   EndContainer(),
    00039   NWidget(NWID_HORIZONTAL),
    00040     NWidget(NWID_HSCROLLBAR, COLOUR_MAUVE, WID_TF_HSCROLLBAR),
    00041     NWidget(WWT_RESIZEBOX, COLOUR_MAUVE),
    00042   EndContainer(),
    00043 };
    00044
    00046 static WindowDesc _textfile_desc(
    00047   WDP_CENTER, "textfile", 630, 460,
    00048   WC_TEXTFILE, WC_NONE,
    00049   0,
    00050   _nested_textfile_widgets, lengthof(_nested_textfile_widgets)
    00051 );
    00052
    00053 TextfileWindow::TextfileWindow(TextfileType file_type) : Window(&_textfile_desc), file_type(file_type)
    00054 {
    00055   this->CreateNestedTree();
    00056   this->vscroll = this->GetScrollbar(WID_TF_VSCROLLBAR);
    00057   this->hscroll = this->GetScrollbar(WID_TF_HSCROLLBAR);
    00058   this->FinishInitNested();
    00059   this->GetWidget<NWidgetCore>(WID_TF_CAPTION)->SetDataTip(STR_TEXTFILE_README_CAPTION + file_type, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS);
    00060
    00061   this->hscroll->SetStepSize(10); // Speed up horizontal scrollbar
    00062   this->vscroll->SetStepSize(FONT_HEIGHT_MONO);
    00063 }
    00064
    00065 /* virtual */ TextfileWindow::~TextfileWindow()
    00066 {
    00067   free(this->text);
    00068 }
    00069
    00074 uint TextfileWindow::GetContentHeight()
    00075 {
    00076   int max_width = this->GetWidget<NWidgetCore>(WID_TF_BACKGROUND)->current_x - WD_FRAMETEXT_LEFT - WD_FRAMERECT_RIGHT;
    00077
    00078   uint height = 0;
    00079   for (uint i = 0; i < this->lines.Length(); i++) {
    00080     height += GetStringHeight(this->lines[i], max_width, FS_MONO);
    00081   }
    00082
    00083   return height;
    00084 }
    00085
    00086 /* virtual */ void TextfileWindow::UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize)
    00087 {
    00088   switch (widget) {
    00089     case WID_TF_BACKGROUND:
    00090       resize->height = 1;
    00091
    00092       size->height = 4 * resize->height + TOP_SPACING + BOTTOM_SPACING; // At least 4 lines are visible.
    00093       size->width = max(200u, size->width); // At least 200 pixels wide.
    00094       break;
    00095   }
    00096 }
    00097
    00099 void TextfileWindow::SetupScrollbars()
    00100 {
    00101   if (IsWidgetLowered(WID_TF_WRAPTEXT)) {
    00102     this->vscroll->SetCount(this->GetContentHeight());
    00103     this->hscroll->SetCount(0);
    00104   } else {
    00105     uint max_length = 0;
    00106     for (uint i = 0; i < this->lines.Length(); i++) {
    00107       max_length = max(max_length, GetStringBoundingBox(this->lines[i], FS_MONO).width);
    00108     }
    00109     this->vscroll->SetCount(this->lines.Length() * FONT_HEIGHT_MONO);
    00110     this->hscroll->SetCount(max_length + WD_FRAMETEXT_LEFT + WD_FRAMETEXT_RIGHT);
    00111   }
    00112
    00113   this->SetWidgetDisabledState(WID_TF_HSCROLLBAR, IsWidgetLowered(WID_TF_WRAPTEXT));
    00114 }
    00115
    00116 /* virtual */ void TextfileWindow::OnClick(Point pt, int widget, int click_count)
    00117 {
    00118   switch (widget) {
    00119     case WID_TF_WRAPTEXT:
    00120       this->ToggleWidgetLoweredState(WID_TF_WRAPTEXT);
    00121       this->SetupScrollbars();
    00122       this->InvalidateData();
    00123       break;
    00124   }
    00125 }
    00126
    00127 /* virtual */ void TextfileWindow::DrawWidget(const Rect &r, int widget) const
    00128 {
    00129   if (widget != WID_TF_BACKGROUND) return;
    00130
    00131   const int x = r.left + WD_FRAMETEXT_LEFT;
    00132   const int y = r.top + WD_FRAMETEXT_TOP;
    00133   const int right = r.right - WD_FRAMETEXT_RIGHT;
    00134   const int bottom = r.bottom - WD_FRAMETEXT_BOTTOM;
    00135
    00136   DrawPixelInfo new_dpi;
    00137   if (!FillDrawPixelInfo(&new_dpi, x, y, right - x + 1, bottom - y + 1)) return;
    00138   DrawPixelInfo *old_dpi = _cur_dpi;
    00139   _cur_dpi = &new_dpi;
    00140
    00141   /* Draw content (now coordinates given to DrawString* are local to the new clipping region). */
    00142   int line_height = FONT_HEIGHT_MONO;
    00143   int y_offset = -this->vscroll->GetPosition();
    00144
    00145   for (uint i = 0; i < this->lines.Length(); i++) {
    00146     if (IsWidgetLowered(WID_TF_WRAPTEXT)) {
    00147       y_offset = DrawStringMultiLine(0, right - x, y_offset, bottom - y, this->lines[i], TC_WHITE, SA_TOP | SA_LEFT, false, FS_MONO);
    00148     } else {
    00149       DrawString(-this->hscroll->GetPosition(), right - x, y_offset, this->lines[i], TC_WHITE, SA_TOP | SA_LEFT, false, FS_MONO);
    00150       y_offset += line_height; // margin to previous element
    00151     }
    00152   }
    00153
    00154   _cur_dpi = old_dpi;
    00155 }
    00156
    00157 /* virtual */ void TextfileWindow::OnResize()
    00158 {
    00159   this->vscroll->SetCapacityFromWidget(this, WID_TF_BACKGROUND, TOP_SPACING + BOTTOM_SPACING);
    00160   this->hscroll->SetCapacityFromWidget(this, WID_TF_BACKGROUND);
    00161
    00162   this->SetupScrollbars();
    00163 }
    00164
    00165 /* virtual */ void TextfileWindow::Reset()
    00166 {
    00167   this->search_iterator = 0;
    00168 }
    00169
    00170 /* virtual */ FontSize TextfileWindow::DefaultSize()
    00171 {
    00172   return FS_MONO;
    00173 }
    00174
    00175 /* virtual */ const char *TextfileWindow::NextString()
    00176 {
    00177   if (this->search_iterator >= this->lines.Length()) return NULL;
    00178
    00179   return this->lines[this->search_iterator++];
    00180 }
    00181
    00182 /* virtual */ bool TextfileWindow::Monospace()
    00183 {
    00184   return true;
    00185 }
    00186
    00187 /* virtual */ void TextfileWindow::SetFontNames(FreeTypeSettings *settings, const char *font_name)
    00188 {
    00189 #ifdef WITH_FREETYPE
    00190   strecpy(settings->mono.font, font_name, lastof(settings->mono.font));
    00191 #endif /* WITH_FREETYPE */
    00192 }
    00193
    00197 /* virtual */ void TextfileWindow::LoadTextfile(const char *textfile, Subdirectory dir)
    00198 {
    00199   if (textfile == NULL) return;
    00200
    00201   this->lines.Clear();
    00202
    00203   /* Get text from file */
    00204   size_t filesize;
    00205   FILE *handle = FioFOpenFile(textfile, "rb", dir, &filesize);
    00206   if (handle == NULL) return;
    00207
    00208   this->text = ReallocT(this->text, filesize + 1);
    00209   size_t read = fread(this->text, 1, filesize, handle);
    00210   fclose(handle);
    00211
    00212   if (read != filesize) return;
    00213
    00214   this->text[filesize] = '\0';
    00215
    00216   /* Replace tabs and line feeds with a space since str_validate removes those. */
    00217   for (char *p = this->text; *p != '\0'; p++) {
    00218     if (*p == '\t' || *p == '\r') *p = ' ';
    00219   }
    00220
    00221   /* Check for the byte-order-mark, and skip it if needed. */
    00222   char *p = this->text + (strncmp("\xEF\xBB\xBF", this->text, 3) == 0 ? 3 : 0);
    00223
    00224   /* Make sure the string is a valid UTF-8 sequence. */
    00225   str_validate(p, this->text + filesize, SVS_REPLACE_WITH_QUESTION_MARK | SVS_ALLOW_NEWLINE);
    00226
    00227   /* Split the string on newlines. */
    00228   *this->lines.Append() = p;
    00229   for (; *p != '\0'; p++) {
    00230     if (*p == '\n') {
    00231       *p = '\0';
    00232       *this->lines.Append() = p + 1;
    00233     }
    00234   }
    00235
    00236   CheckForMissingGlyphs(true, this);
    00237 }
    00238
    00246 const char *GetTextfile(TextfileType type, Subdirectory dir, const char *filename)
    00247 {
    00248   static const char * const prefixes[] = {
    00249     "readme",
    00250     "changelog",
    00251     "license",
    00252   };
    00253   assert_compile(lengthof(prefixes) == TFT_END);
    00254
    00255   const char *prefix = prefixes[type];
    00256
    00257   if (filename == NULL) return NULL;
    00258
    00259   static char file_path[MAX_PATH];
    00260   strecpy(file_path, filename, lastof(file_path));
    00261
    00262   char *slash = strrchr(file_path, PATHSEPCHAR);
    00263   if (slash == NULL) return NULL;
    00264
    00265   seprintf(slash + 1, lastof(file_path), "%s_%s.txt", prefix, GetCurrentLanguageIsoCode());
    00266   if (FioCheckFileExists(file_path, dir)) return file_path;
    00267
    00268   seprintf(slash + 1, lastof(file_path), "%s_%.2s.txt", prefix, GetCurrentLanguageIsoCode());
    00269   if (FioCheckFileExists(file_path, dir)) return file_path;
    00270
    00271   seprintf(slash + 1, lastof(file_path), "%s.txt", prefix);
    00272   return FioCheckFileExists(file_path, dir) ? file_path : NULL;
    00273 }