# main_gui.cpp

Go to the documentation of this file.

    00001 /* $Id: main_gui.cpp 18486 2009-12-13 19:33:07Z 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 "openttd.h"
    00014 #include "currency.h"
    00015 #include "spritecache.h"
    00016 #include "window_gui.h"
    00017 #include "window_func.h"
    00018 #include "textbuf_gui.h"
    00019 #include "viewport_func.h"
    00020 #include "command_func.h"
    00021 #include "console_gui.h"
    00022 #include "genworld.h"
    00023 #include "transparency_gui.h"
    00024 #include "functions.h"
    00025 #include "sound_func.h"
    00026 #include "transparency.h"
    00027 #include "strings_func.h"
    00028 #include "zoom_func.h"
    00029 #include "company_base.h"
    00030 #include "company_func.h"
    00031 #include "toolbar_gui.h"
    00032 #include "statusbar_gui.h"
    00033 #include "tilehighlight_func.h"
    00034
    00035 #include "network/network.h"
    00036 #include "network/network_func.h"
    00037 #include "network/network_gui.h"
    00038 #include "network/network_base.h"
    00039
    00040 #include "table/sprites.h"
    00041 #include "table/strings.h"
    00042
    00043 static int _rename_id = 1;
    00044 static int _rename_what = -1;
    00045
    00046 void CcGiveMoney(bool success, TileIndex tile, uint32 p1, uint32 p2)
    00047 {
    00048 #ifdef ENABLE_NETWORK
    00049   if (!success || !_settings_game.economy.give_money) return;
    00050
    00051   /* Inform the company of the action of one of it's clients (controllers). */
    00052   char msg[64];
    00053   SetDParam(0, p2);
    00054   GetString(msg, STR_COMPANY_NAME, lastof(msg));
    00055
    00056   if (!_network_server) {
    00057     NetworkClientSendChat(NETWORK_ACTION_GIVE_MONEY, DESTTYPE_TEAM, p2, msg, p1);
    00058   } else {
    00059     NetworkServerSendChat(NETWORK_ACTION_GIVE_MONEY, DESTTYPE_TEAM, p2, msg, CLIENT_ID_SERVER, p1);
    00060   }
    00061 #endif /* ENABLE_NETWORK */
    00062 }
    00063
    00064 void HandleOnEditText(const char *str)
    00065 {
    00066   switch (_rename_what) {
    00067 #ifdef ENABLE_NETWORK
    00068   case 3: { // Give money, you can only give money in excess of loan
    00069     const Company *c = Company::GetIfValid(_local_company);
    00070     if (c == NULL) break;
    00071     Money money = min(c->money - c->current_loan, (Money)(atoi(str) / _currency->rate));
    00072
    00073     uint32 money_c = Clamp(ClampToI32(money), 0, 20000000); // Clamp between 20 million and 0
    00074
    00075     /* Give 'id' the money, and substract it from ourself */
    00076     DoCommandP(0, money_c, _rename_id, CMD_GIVE_MONEY | CMD_MSG(STR_ERROR_INSUFFICIENT_FUNDS), CcGiveMoney, str);
    00077   } break;
    00078 #endif /* ENABLE_NETWORK */
    00079     default: NOT_REACHED();
    00080   }
    00081
    00082   _rename_id = _rename_what = -1;
    00083 }
    00084
    00096 bool HandlePlacePushButton(Window *w, int widget, CursorID cursor, HighLightStyle mode, PlaceProc *placeproc)
    00097 {
    00098   if (w->IsWidgetDisabled(widget)) return false;
    00099
    00100   SndPlayFx(SND_15_BEEP);
    00101   w->SetDirty();
    00102
    00103   if (w->IsWidgetLowered(widget)) {
    00104     ResetObjectToPlace();
    00105     return false;
    00106   }
    00107
    00108   SetObjectToPlace(cursor, PAL_NONE, mode, w->window_class, w->window_number);
    00109   w->LowerWidget(widget);
    00110   _place_proc = placeproc;
    00111   return true;
    00112 }
    00113
    00114
    00115 void CcPlaySound10(bool success, TileIndex tile, uint32 p1, uint32 p2)
    00116 {
    00117   if (success) SndPlayTileFx(SND_12_EXPLOSION, tile);
    00118 }
    00119
    00120 #ifdef ENABLE_NETWORK
    00121 void ShowNetworkGiveMoneyWindow(CompanyID company)
    00122 {
    00123   _rename_id = company;
    00124   _rename_what = 3;
    00125   ShowQueryString(STR_EMPTY, STR_NETWORK_GIVE_MONEY_CAPTION, 30, 180, NULL, CS_NUMERAL, QSF_NONE);
    00126 }
    00127 #endif /* ENABLE_NETWORK */
    00128
    00129
    00130 /* Zooms a viewport in a window in or out
    00131  * No button handling or what so ever */
    00132 bool DoZoomInOutWindow(int how, Window *w)
    00133 {
    00134   ViewPort *vp;
    00135
    00136   assert(w != NULL);
    00137   vp = w->viewport;
    00138
    00139   switch (how) {
    00140     case ZOOM_IN:
    00141       if (vp->zoom == ZOOM_LVL_MIN) return false;
    00142       vp->zoom = (ZoomLevel)((int)vp->zoom - 1);
    00143       vp->virtual_width >>= 1;
    00144       vp->virtual_height >>= 1;
    00145
    00146       w->viewport->scrollpos_x += vp->virtual_width >> 1;
    00147       w->viewport->scrollpos_y += vp->virtual_height >> 1;
    00148       w->viewport->dest_scrollpos_x = w->viewport->scrollpos_x;
    00149       w->viewport->dest_scrollpos_y = w->viewport->scrollpos_y;
    00150       break;
    00151     case ZOOM_OUT:
    00152       if (vp->zoom == ZOOM_LVL_MAX) return false;
    00153       vp->zoom = (ZoomLevel)((int)vp->zoom + 1);
    00154
    00155       w->viewport->scrollpos_x -= vp->virtual_width >> 1;
    00156       w->viewport->scrollpos_y -= vp->virtual_height >> 1;
    00157       w->viewport->dest_scrollpos_x = w->viewport->scrollpos_x;
    00158       w->viewport->dest_scrollpos_y = w->viewport->scrollpos_y;
    00159
    00160       vp->virtual_width <<= 1;
    00161       vp->virtual_height <<= 1;
    00162       break;
    00163   }
    00164   if (vp != NULL) { // the vp can be null when how == ZOOM_NONE
    00165     vp->virtual_left = w->viewport->scrollpos_x;
    00166     vp->virtual_top = w->viewport->scrollpos_y;
    00167   }
    00168   /* Update the windows that have zoom-buttons to perhaps disable their buttons */
    00169   w->InvalidateData();
    00170   return true;
    00171 }
    00172
    00173 void ZoomInOrOutToCursorWindow(bool in, Window *w)
    00174 {
    00175   assert(w != NULL);
    00176
    00177   if (_game_mode != GM_MENU) {
    00178     ViewPort *vp = w->viewport;
    00179     if ((in && vp->zoom == ZOOM_LVL_MIN) || (!in && vp->zoom == ZOOM_LVL_MAX))
    00180       return;
    00181
    00182     Point pt = GetTileZoomCenterWindow(in, w);
    00183     if (pt.x != -1) {
    00184       ScrollWindowTo(pt.x, pt.y, -1, w, true);
    00185
    00186       DoZoomInOutWindow(in ? ZOOM_IN : ZOOM_OUT, w);
    00187     }
    00188   }
    00189 }
    00190
    00192 enum MainWindowWidgets {
    00193   MW_VIEWPORT,
    00194 };
    00195
    00196 static const struct NWidgetPart _nested_main_window_widgets[] = {
    00197   NWidget(NWID_VIEWPORT, INVALID_COLOUR, MW_VIEWPORT), SetResize(1, 1),
    00198 };
    00199
    00200 static const WindowDesc _main_window_desc(
    00201   WDP_MANUAL, 0, 0,
    00202   WC_MAIN_WINDOW, WC_NONE,
    00203   0,
    00204   _nested_main_window_widgets, lengthof(_nested_main_window_widgets)
    00205 );
    00206
    00207 struct MainWindow : Window
    00208 {
    00209   MainWindow() : Window()
    00210   {
    00211     this->InitNested(&_main_window_desc, 0);
    00212     ResizeWindow(this, _screen.width, _screen.height);
    00213
    00214     NWidgetViewport *nvp = this->GetWidget<NWidgetViewport>(MW_VIEWPORT);
    00215     nvp->InitializeViewport(this, TileXY(32, 32), ZOOM_LVL_VIEWPORT);
    00216   }
    00217
    00218   virtual void OnPaint()
    00219   {
    00220     this->DrawWidgets();
    00221     if (_game_mode == GM_MENU) {
    00222       int off_x = this->width / 2;
    00223
    00224       DrawSprite(SPR_OTTD_O, PAL_NONE, off_x - 120, 50);
    00225       DrawSprite(SPR_OTTD_P, PAL_NONE, off_x -  86, 50);
    00226       DrawSprite(SPR_OTTD_E, PAL_NONE, off_x -  53, 50);
    00227       DrawSprite(SPR_OTTD_N, PAL_NONE, off_x -  22, 50);
    00228
    00229       DrawSprite(SPR_OTTD_T, PAL_NONE, off_x +  34, 50);
    00230       DrawSprite(SPR_OTTD_T, PAL_NONE, off_x +  65, 50);
    00231       DrawSprite(SPR_OTTD_D, PAL_NONE, off_x +  96, 50);
    00232     }
    00233   }
    00234
    00235   virtual EventState OnKeyPress(uint16 key, uint16 keycode)
    00236   {
    00237     switch (keycode) {
    00238       case 'Q' | WKC_CTRL:
    00239       case 'Q' | WKC_META:
    00240         HandleExitGameRequest();
    00241         return ES_HANDLED;
    00242     }
    00243
    00244     /* Disable all key shortcuts, except quit shortcuts when
    00245      * generating the world, otherwise they create threading
    00246      * problem during the generating, resulting in random
    00247      * assertions that are hard to trigger and debug */
    00248     if (IsGeneratingWorld()) return ES_NOT_HANDLED;
    00249
    00250     if (keycode == WKC_BACKQUOTE) {
    00251       IConsoleSwitch();
    00252       return ES_HANDLED;
    00253     }
    00254
    00255     if (keycode == ('B' | WKC_CTRL)) {
    00256       extern bool _draw_bounding_boxes;
    00257       _draw_bounding_boxes = !_draw_bounding_boxes;
    00258       MarkWholeScreenDirty();
    00259       return ES_HANDLED;
    00260     }
    00261
    00262     if (_game_mode == GM_MENU) return ES_NOT_HANDLED;
    00263
    00264     switch (keycode) {
    00265       case 'C':
    00266       case 'Z': {
    00267         Point pt = GetTileBelowCursor();
    00268         if (pt.x != -1) {
    00269           if (keycode == 'Z') MaxZoomInOut(ZOOM_IN, this);
    00270           ScrollMainWindowTo(pt.x, pt.y);
    00271         }
    00272         break;
    00273       }
    00274
    00275       case WKC_ESC: ResetObjectToPlace(); break;
    00276       case WKC_DELETE: DeleteNonVitalWindows(); break;
    00277       case WKC_DELETE | WKC_SHIFT: DeleteAllNonVitalWindows(); break;
    00278       case 'R' | WKC_CTRL: MarkWholeScreenDirty(); break;
    00279
    00280 #if defined(_DEBUG)
    00281       case '0' | WKC_ALT: // Crash the game
    00282         *(byte*)0 = 0;
    00283         break;
    00284
    00285       case '1' | WKC_ALT: // Gimme money
    00286         /* Server can not cheat in advertise mode either! */
    00287 #ifdef ENABLE_NETWORK
    00288         if (!_networking || !_network_server || !_settings_client.network.server_advertise)
    00289 #endif /* ENABLE_NETWORK */
    00290           DoCommandP(0, 10000000, 0, CMD_MONEY_CHEAT);
    00291         break;
    00292
    00293       case '2' | WKC_ALT: // Update the coordinates of all station signs
    00294         UpdateAllVirtCoords();
    00295         break;
    00296 #endif
    00297
    00298       case '1' | WKC_CTRL:
    00299       case '2' | WKC_CTRL:
    00300       case '3' | WKC_CTRL:
    00301       case '4' | WKC_CTRL:
    00302       case '5' | WKC_CTRL:
    00303       case '6' | WKC_CTRL:
    00304       case '7' | WKC_CTRL:
    00305       case '8' | WKC_CTRL:
    00306       case '9' | WKC_CTRL:
    00307         /* Transparency toggle hot keys */
    00308         ToggleTransparency((TransparencyOption)(keycode - ('1' | WKC_CTRL)));
    00309         MarkWholeScreenDirty();
    00310         break;
    00311
    00312       case '1' | WKC_CTRL | WKC_SHIFT:
    00313       case '2' | WKC_CTRL | WKC_SHIFT:
    00314       case '3' | WKC_CTRL | WKC_SHIFT:
    00315       case '4' | WKC_CTRL | WKC_SHIFT:
    00316       case '5' | WKC_CTRL | WKC_SHIFT:
    00317       case '6' | WKC_CTRL | WKC_SHIFT:
    00318       case '7' | WKC_CTRL | WKC_SHIFT:
    00319       case '8' | WKC_CTRL | WKC_SHIFT:
    00320         /* Invisibility toggle hot keys */
    00321         ToggleInvisibilityWithTransparency((TransparencyOption)(keycode - ('1' | WKC_CTRL | WKC_SHIFT)));
    00322         MarkWholeScreenDirty();
    00323         break;
    00324
    00325       case 'X' | WKC_CTRL:
    00326         ShowTransparencyToolbar();
    00327         break;
    00328
    00329       case 'X':
    00330         ResetRestoreAllTransparency();
    00331         break;
    00332
    00333 #ifdef ENABLE_NETWORK
    00334       case WKC_RETURN: case 'T': // smart chat; send to team if any, otherwise to all
    00335         if (_networking) {
    00336           const NetworkClientInfo *cio = NetworkFindClientInfoFromClientID(_network_own_client_id);
    00337           if (cio == NULL) break;
    00338
    00339           ShowNetworkChatQueryWindow(NetworkClientPreferTeamChat(cio) ? DESTTYPE_TEAM : DESTTYPE_BROADCAST, cio->client_playas);
    00340         }
    00341         break;
    00342
    00343       case WKC_SHIFT | WKC_RETURN: case WKC_SHIFT | 'T': // send text message to all clients
    00344         if (_networking) ShowNetworkChatQueryWindow(DESTTYPE_BROADCAST, 0);
    00345         break;
    00346
    00347       case WKC_CTRL | WKC_RETURN: case WKC_CTRL | 'T': // send text to all team mates
    00348         if (_networking) {
    00349           const NetworkClientInfo *cio = NetworkFindClientInfoFromClientID(_network_own_client_id);
    00350           if (cio == NULL) break;
    00351
    00352           ShowNetworkChatQueryWindow(DESTTYPE_TEAM, cio->client_playas);
    00353         }
    00354         break;
    00355 #endif
    00356
    00357       default: return ES_NOT_HANDLED;
    00358     }
    00359     return ES_HANDLED;
    00360   }
    00361
    00362   virtual void OnScroll(Point delta)
    00363   {
    00364     ViewPort *vp = IsPtInWindowViewport(this, _cursor.pos.x, _cursor.pos.y);
    00365
    00366     if (vp == NULL) {
    00367       _cursor.fix_at = false;
    00368       _scrolling_viewport = false;
    00369     }
    00370
    00371     this->viewport->scrollpos_x += ScaleByZoom(delta.x, vp->zoom);
    00372     this->viewport->scrollpos_y += ScaleByZoom(delta.y, vp->zoom);
    00373     this->viewport->dest_scrollpos_x = this->viewport->scrollpos_x;
    00374     this->viewport->dest_scrollpos_y = this->viewport->scrollpos_y;
    00375   };
    00376
    00377   virtual void OnMouseWheel(int wheel)
    00378   {
    00379     ZoomInOrOutToCursorWindow(wheel < 0, this);
    00380   }
    00381
    00382   virtual void OnResize()
    00383   {
    00384     if (this->viewport != NULL) {
    00385       NWidgetViewport *nvp = this->GetWidget<NWidgetViewport>(MW_VIEWPORT);
    00386       nvp->UpdateViewportCoordinates(this);
    00387     }
    00388   }
    00389
    00390   virtual void OnInvalidateData(int data)
    00391   {
    00392     /* Forward the message to the appropiate toolbar (ingame or scenario editor) */
    00393     InvalidateWindowData(WC_MAIN_TOOLBAR, 0, data);
    00394   }
    00395 };
    00396
    00397
    00398 void ShowSelectGameWindow();
    00399
    00400 void SetupColoursAndInitialWindow()
    00401 {
    00402   for (uint i = 0; i != 16; i++) {
    00403     const byte *b = GetNonSprite(PALETTE_RECOLOUR_START + i, ST_RECOLOUR);
    00404
    00405     assert(b);
    00406     memcpy(_colour_gradient[i], b + 0xC6, sizeof(_colour_gradient[i]));
    00407   }
    00408
    00409   new MainWindow;
    00410
    00411   /* XXX: these are not done */
    00412   switch (_game_mode) {
    00413     default: NOT_REACHED();
    00414     case GM_MENU:
    00415       ShowSelectGameWindow();
    00416       break;
    00417
    00418     case GM_NORMAL:
    00419     case GM_EDITOR:
    00420       ShowVitalWindows();
    00421       break;
    00422   }
    00423 }
    00424
    00425 void ShowVitalWindows()
    00426 {
    00427   AllocateToolbar();
    00428
    00429   /* Status bad only for normal games */
    00430   if (_game_mode == GM_EDITOR) return;
    00431
    00432   ShowStatusBar();
    00433 }
    00434
    00439 void GameSizeChanged()
    00440 {
    00441   _cur_resolution.width  = _screen.width;
    00442   _cur_resolution.height = _screen.height;
    00443   ScreenSizeChanged();
    00444   RelocateAllWindows(_screen.width, _screen.height);
    00445   MarkWholeScreenDirty();
    00446 }