bootstrap_gui.cpp

Go to the documentation of this file.
00001 /* $Id: bootstrap_gui.cpp 26209 2014-01-02 22:41:58Z rubidium $ */
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 "base_media_base.h"
00014 #include "blitter/factory.hpp"
00015 
00016 #if defined(ENABLE_NETWORK) && defined(WITH_FREETYPE)
00017 
00018 #include "core/geometry_func.hpp"
00019 #include "fontcache.h"
00020 #include "gfx_func.h"
00021 #include "network/network.h"
00022 #include "network/network_content_gui.h"
00023 #include "openttd.h"
00024 #include "strings_func.h"
00025 #include "video/video_driver.hpp"
00026 #include "window_func.h"
00027 
00028 #include "widgets/bootstrap_widget.h"
00029 
00030 #include "table/strings.h"
00031 
00033 static const struct NWidgetPart _background_widgets[] = {
00034   NWidget(WWT_PANEL, COLOUR_DARK_BLUE, WID_BB_BACKGROUND), SetResize(1, 1),
00035 };
00036 
00040 static WindowDesc _background_desc(
00041   WDP_MANUAL, NULL, 0, 0,
00042   WC_BOOTSTRAP, WC_NONE,
00043   0,
00044   _background_widgets, lengthof(_background_widgets)
00045 );
00046 
00048 class BootstrapBackground : public Window {
00049 public:
00050   BootstrapBackground() : Window(&_background_desc)
00051   {
00052     this->InitNested(0);
00053     CLRBITS(this->flags, WF_WHITE_BORDER);
00054     ResizeWindow(this, _screen.width, _screen.height);
00055   }
00056 
00057   virtual void DrawWidget(const Rect &r, int widget) const
00058   {
00059     GfxFillRect(r.left, r.top, r.right, r.bottom, 4, FILLRECT_OPAQUE);
00060     GfxFillRect(r.left, r.top, r.right, r.bottom, 0, FILLRECT_CHECKER);
00061   }
00062 };
00063 
00065 static const NWidgetPart _nested_boostrap_download_status_window_widgets[] = {
00066   NWidget(WWT_CAPTION, COLOUR_GREY), SetDataTip(STR_CONTENT_DOWNLOAD_TITLE, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
00067   NWidget(WWT_PANEL, COLOUR_GREY, WID_NCDS_BACKGROUND),
00068     NWidget(NWID_SPACER), SetMinimalSize(350, 0), SetMinimalTextLines(3, WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM + 30),
00069   EndContainer(),
00070 };
00071 
00073 static WindowDesc _bootstrap_download_status_window_desc(
00074   WDP_CENTER, NULL, 0, 0,
00075   WC_NETWORK_STATUS_WINDOW, WC_NONE,
00076   WDF_MODAL,
00077   _nested_boostrap_download_status_window_widgets, lengthof(_nested_boostrap_download_status_window_widgets)
00078 );
00079 
00080 
00082 struct BootstrapContentDownloadStatusWindow : public BaseNetworkContentDownloadStatusWindow {
00083 public:
00085   BootstrapContentDownloadStatusWindow() : BaseNetworkContentDownloadStatusWindow(&_bootstrap_download_status_window_desc)
00086   {
00087   }
00088 
00089   virtual void OnDownloadComplete(ContentID cid)
00090   {
00091     /* We have completed downloading. We can trigger finding the right set now. */
00092     BaseGraphics::FindSets();
00093 
00094     /* And continue going into the menu. */
00095     _game_mode = GM_MENU;
00096 
00097     /* _exit_game is used to break out of the outer video driver's MainLoop. */
00098     _exit_game = true;
00099     delete this;
00100   }
00101 };
00102 
00104 static const NWidgetPart _bootstrap_query_widgets[] = {
00105   NWidget(NWID_HORIZONTAL),
00106     NWidget(WWT_CAPTION, COLOUR_GREY), SetDataTip(STR_MISSING_GRAPHICS_SET_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
00107   EndContainer(),
00108   NWidget(WWT_PANEL, COLOUR_GREY),
00109     NWidget(WWT_PANEL, COLOUR_GREY, WID_BAFD_QUESTION), EndContainer(),
00110     NWidget(NWID_HORIZONTAL),
00111       NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_BAFD_YES), SetDataTip(STR_MISSING_GRAPHICS_YES_DOWNLOAD, STR_NULL),
00112       NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, WID_BAFD_NO), SetDataTip(STR_MISSING_GRAPHICS_NO_QUIT, STR_NULL),
00113     EndContainer(),
00114   EndContainer(),
00115 };
00116 
00118 static WindowDesc _bootstrap_query_desc(
00119   WDP_CENTER, NULL, 0, 0,
00120   WC_CONFIRM_POPUP_QUERY, WC_NONE,
00121   0,
00122   _bootstrap_query_widgets, lengthof(_bootstrap_query_widgets)
00123 );
00124 
00126 class BootstrapAskForDownloadWindow : public Window, ContentCallback {
00127   Dimension button_size; 
00128 
00129 public:
00131   BootstrapAskForDownloadWindow() : Window(&_bootstrap_query_desc)
00132   {
00133     this->InitNested(WN_CONFIRM_POPUP_QUERY_BOOTSTRAP);
00134     _network_content_client.AddCallback(this);
00135   }
00136 
00138   ~BootstrapAskForDownloadWindow()
00139   {
00140     _network_content_client.RemoveCallback(this);
00141   }
00142 
00143   virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize)
00144   {
00145     /* We cache the button size. This is safe as no reinit can happen here. */
00146     if (this->button_size.width == 0) {
00147       this->button_size = maxdim(GetStringBoundingBox(STR_MISSING_GRAPHICS_YES_DOWNLOAD), GetStringBoundingBox(STR_MISSING_GRAPHICS_NO_QUIT));
00148       this->button_size.width += WD_FRAMETEXT_LEFT + WD_FRAMETEXT_RIGHT;
00149       this->button_size.height += WD_FRAMETEXT_TOP + WD_FRAMETEXT_BOTTOM;
00150     }
00151 
00152     switch (widget) {
00153       case WID_BAFD_QUESTION:
00154         /* The question is twice as wide as the buttons, and determine the height based on the width. */
00155         size->width = this->button_size.width * 2;
00156         size->height = GetStringHeight(STR_MISSING_GRAPHICS_SET_MESSAGE, size->width - WD_FRAMETEXT_LEFT - WD_FRAMETEXT_RIGHT) + WD_FRAMETEXT_BOTTOM + WD_FRAMETEXT_TOP;
00157         break;
00158 
00159       case WID_BAFD_YES:
00160       case WID_BAFD_NO:
00161         *size = this->button_size;
00162         break;
00163     }
00164   }
00165 
00166   virtual void DrawWidget(const Rect &r, int widget) const
00167   {
00168     if (widget != 0) return;
00169 
00170     DrawStringMultiLine(r.left + WD_FRAMETEXT_LEFT, r.right - WD_FRAMETEXT_RIGHT, r.top + WD_FRAMETEXT_TOP, r.bottom - WD_FRAMETEXT_BOTTOM, STR_MISSING_GRAPHICS_SET_MESSAGE, TC_FROMSTRING, SA_CENTER);
00171   }
00172 
00173   virtual void OnClick(Point pt, int widget, int click_count)
00174   {
00175     switch (widget) {
00176       case WID_BAFD_YES:
00177         /* We got permission to connect! Yay! */
00178         _network_content_client.Connect();
00179         break;
00180 
00181       case WID_BAFD_NO:
00182         _exit_game = true;
00183         break;
00184 
00185       default:
00186         break;
00187     }
00188   }
00189 
00190   virtual void OnConnect(bool success)
00191   {
00192     /* Once connected, request the metadata. */
00193     _network_content_client.RequestContentList(CONTENT_TYPE_BASE_GRAPHICS);
00194   }
00195 
00196   virtual void OnReceiveContentInfo(const ContentInfo *ci)
00197   {
00198     /* And once the meta data is received, start downloading it. */
00199     _network_content_client.Select(ci->id);
00200     new BootstrapContentDownloadStatusWindow();
00201     delete this;
00202   }
00203 };
00204 
00205 #endif /* defined(ENABLE_NETWORK) && defined(WITH_FREETYPE) */
00206 
00213 bool HandleBootstrap()
00214 {
00215   if (BaseGraphics::GetUsedSet() != NULL) return true;
00216 
00217   /* No user interface, bail out with an error. */
00218   if (BlitterFactory::GetCurrentBlitter()->GetScreenDepth() == 0) goto failure;
00219 
00220   /* If there is no network or no freetype, then there is nothing we can do. Go straight to failure. */
00221 #if defined(ENABLE_NETWORK) && defined(WITH_FREETYPE) && (defined(WITH_FONTCONFIG) || defined(WIN32) || defined(__APPLE__))
00222   if (!_network_available) goto failure;
00223 
00224   /* First tell the game we're bootstrapping. */
00225   _game_mode = GM_BOOTSTRAP;
00226 
00227   /* Initialise the freetype font code. */
00228   InitializeUnicodeGlyphMap();
00229   /* Next "force" finding a suitable freetype font as the local font is missing. */
00230   CheckForMissingGlyphs(false);
00231 
00232   /* Initialise the palette. The biggest step is 'faking' some recolour sprites.
00233    * This way the mauve and gray colours work and we can show the user interface. */
00234   GfxInitPalettes();
00235   static const int offsets[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x80, 0, 0, 0, 0x04, 0x08 };
00236   for (uint i = 0; i != 16; i++) {
00237     for (int j = 0; j < 8; j++) {
00238       _colour_gradient[i][j] = offsets[i] + j;
00239     }
00240   }
00241 
00242   /* Finally ask the question. */
00243   new BootstrapBackground();
00244   new BootstrapAskForDownloadWindow();
00245 
00246   /* Process the user events. */
00247   _video_driver->MainLoop();
00248 
00249   /* _exit_game is used to get out of the video driver's main loop.
00250    * In case GM_BOOTSTRAP is still set we did not exit it via the
00251    * "download complete" event, so it was a manual exit. Obey it. */
00252   _exit_game = _game_mode == GM_BOOTSTRAP;
00253   if (_exit_game) return false;
00254 
00255   /* Try to probe the graphics. Should work this time. */
00256   if (!BaseGraphics::SetSet(NULL)) goto failure;
00257 
00258   /* Finally we can continue heading for the menu. */
00259   _game_mode = GM_MENU;
00260   return true;
00261 #endif
00262 
00263   /* Failure to get enough working to get a graphics set. */
00264 failure:
00265   usererror("Failed to find a graphics set. Please acquire a graphics set for OpenTTD. See section 4.1 of readme.txt.");
00266   return false;
00267 }