bootstrap_gui.cpp

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