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 "table/strings.h"
00031 
00033 static const struct NWidgetPart _background_widgets[] = {
00034   NWidget(WWT_PANEL, COLOUR_DARK_BLUE, 0), SetResize(1, 1),
00035 };
00036 
00040 static const WindowDesc _background_desc(
00041   WDP_MANUAL, 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()
00051   {
00052     this->InitNested(&_background_desc, 0);
00053     CLRBITS(this->flags4, WF_WHITE_BORDER_MASK);
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, NCDSWW_BACKGROUND),
00068     NWidget(NWID_SPACER), SetMinimalSize(350, 0), SetMinimalTextLines(3, WD_FRAMERECT_TOP + WD_FRAMERECT_BOTTOM + 30),
00069   EndContainer(),
00070 };
00071 
00073 static const WindowDesc _bootstrap_download_status_window_desc(
00074   WDP_CENTER, 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 enum BootstrapAskForDownloadWidgets {
00105   BAFDW_QUESTION, 
00106   BAFDW_YES,      
00107   BAFDW_NO,       
00108 };
00109 
00111 static const NWidgetPart _bootstrap_query_widgets[] = {
00112   NWidget(NWID_HORIZONTAL),
00113     NWidget(WWT_CAPTION, COLOUR_GREY), SetDataTip(STR_MISSING_GRAPHICS_SET_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
00114   EndContainer(),
00115   NWidget(WWT_PANEL, COLOUR_GREY),
00116     NWidget(WWT_PANEL, COLOUR_GREY, BAFDW_QUESTION), EndContainer(),
00117     NWidget(NWID_HORIZONTAL),
00118       NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, BAFDW_YES), SetDataTip(STR_MISSING_GRAPHICS_YES_DOWNLOAD, STR_NULL),
00119       NWidget(WWT_PUSHTXTBTN, COLOUR_GREY, BAFDW_NO), SetDataTip(STR_MISSING_GRAPHICS_NO_QUIT, STR_NULL),
00120     EndContainer(),
00121   EndContainer(),
00122 };
00123 
00125 static const WindowDesc _bootstrap_query_desc(
00126   WDP_CENTER, 0, 0,
00127   WC_CONFIRM_POPUP_QUERY, WC_NONE,
00128   WDF_UNCLICK_BUTTONS,
00129   _bootstrap_query_widgets, lengthof(_bootstrap_query_widgets)
00130 );
00131 
00133 class BootstrapAskForDownloadWindow : public Window, ContentCallback {
00134   Dimension button_size; 
00135 
00136 public:
00138   BootstrapAskForDownloadWindow() : Window()
00139   {
00140     this->InitNested(&_bootstrap_query_desc);
00141     _network_content_client.AddCallback(this);
00142   }
00143 
00145   ~BootstrapAskForDownloadWindow()
00146   {
00147     _network_content_client.RemoveCallback(this);
00148   }
00149 
00150   virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize)
00151   {
00152     /* We cache the button size. This is safe as no reinit can happen here. */
00153     if (this->button_size.width == 0) {
00154       this->button_size = maxdim(GetStringBoundingBox(STR_MISSING_GRAPHICS_YES_DOWNLOAD), GetStringBoundingBox(STR_MISSING_GRAPHICS_NO_QUIT));
00155       this->button_size.width += WD_FRAMETEXT_LEFT + WD_FRAMETEXT_RIGHT;
00156       this->button_size.height += WD_FRAMETEXT_TOP + WD_FRAMETEXT_BOTTOM;
00157     }
00158 
00159     switch (widget) {
00160       case BAFDW_QUESTION:
00161         /* The question is twice as wide as the buttons, and determine the height based on the width. */
00162         size->width = this->button_size.width * 2;
00163         size->height = GetStringHeight(STR_MISSING_GRAPHICS_SET_MESSAGE, size->width - WD_FRAMETEXT_LEFT - WD_FRAMETEXT_RIGHT) + WD_FRAMETEXT_BOTTOM + WD_FRAMETEXT_TOP;
00164         break;
00165 
00166       case BAFDW_YES:
00167       case BAFDW_NO:
00168         *size = this->button_size;
00169         break;
00170     }
00171   }
00172 
00173   virtual void DrawWidget(const Rect &r, int widget) const
00174   {
00175     if (widget != 0) return;
00176 
00177     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);
00178   }
00179 
00180   virtual void OnClick(Point pt, int widget, int click_count)
00181   {
00182     switch (widget) {
00183       case BAFDW_YES:
00184         /* We got permission to connect! Yay! */
00185         _network_content_client.Connect();
00186         break;
00187 
00188       case BAFDW_NO:
00189         _exit_game = true;
00190         break;
00191 
00192       default:
00193         break;
00194     }
00195   }
00196 
00197   virtual void OnConnect(bool success)
00198   {
00199     /* Once connected, request the metadata. */
00200     _network_content_client.RequestContentList(CONTENT_TYPE_BASE_GRAPHICS);
00201   }
00202 
00203   virtual void OnReceiveContentInfo(const ContentInfo *ci)
00204   {
00205     /* And once the meta data is received, start downloading it. */
00206     _network_content_client.Select(ci->id);
00207     new BootstrapContentDownloadStatusWindow();
00208     delete this;
00209   }
00210 };
00211 
00212 #endif /* defined(ENABLE_NETWORK) && defined(WITH_FREETYPE) */
00213 
00220 bool HandleBootstrap()
00221 {
00222   if (BaseGraphics::GetUsedSet() != NULL) return true;
00223 
00224   /* No user interface, bail out with an error. */
00225   if (BlitterFactoryBase::GetCurrentBlitter()->GetScreenDepth() == 0) goto failure;
00226 
00227   /* If there is no network or no freetype, then there is nothing we can do. Go straight to failure. */
00228 #if defined(ENABLE_NETWORK) && defined(WITH_FREETYPE) && !defined(__APPLE__)
00229   if (!_network_available) goto failure;
00230 
00231   /* First tell the game we're bootstrapping. */
00232   _game_mode = GM_BOOTSTRAP;
00233 
00234   /* Initialise the freetype font code. */
00235   InitializeUnicodeGlyphMap();
00236   /* Next "force" finding a suitable freetype font as the local font is missing. */
00237   CheckForMissingGlyphs(false);
00238 
00239   /* Initialise the palette. The biggest step is 'faking' some recolour sprites.
00240    * This way the mauve and gray colours work and we can show the user interface. */
00241   GfxInitPalettes();
00242   static const int offsets[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0x80, 0, 0, 0, 0x04, 0x08 };
00243   for (uint i = 0; i != 16; i++) {
00244     for (int j = 0; j < 8; j++) {
00245       _colour_gradient[i][j] = offsets[i] + j;
00246     }
00247   }
00248 
00249   /* Finally ask the question. */
00250   new BootstrapBackground();
00251   new BootstrapAskForDownloadWindow();
00252 
00253   /* Process the user events. */
00254   _video_driver->MainLoop();
00255 
00256   /* _exit_game is used to get out of the video driver's main loop.
00257    * In case GM_BOOTSTRAP is still set we did not exit it via the
00258    * "download complete" event, so it was a manual exit. Obey it. */
00259   _exit_game = _game_mode == GM_BOOTSTRAP;
00260   if (_exit_game) return false;
00261 
00262   /* Try to probe the graphics. Should work this time. */
00263   if (!BaseGraphics::SetSet(NULL)) goto failure;
00264 
00265   /* Finally we can continue heading for the menu. */
00266   _game_mode = GM_MENU;
00267   return true;
00268 #endif
00269 
00270   /* Failure to get enough working to get a graphics set. */
00271 failure:
00272   usererror("Failed to find a graphics set. Please acquire a graphics set for OpenTTD. See section 4.1 of readme.txt.");
00273   return false;
00274 }