From 7a5cedf078cf39d56cf6031d26619b2c41f2e934 Mon Sep 17 00:00:00 2001 From: zuu Date: Sun, 9 Jun 2013 12:48:27 +0000 Subject: [PATCH] (svn r25344) -Feature: GUI for viewing story pages --- bin/baseset/openttd.grf | Bin 824193 -> 825364 bytes bin/baseset/orig_dos.obg | 2 +- bin/baseset/orig_dos_de.obg | 2 +- bin/baseset/orig_win.obg | 2 +- media/extra_grf/openttdgui.nfo | 7 +- media/extra_grf/openttdgui.png | Bin 25163 -> 26280 bytes projects/openttd_vs100.vcxproj | 2 + projects/openttd_vs100.vcxproj.filters | 6 + projects/openttd_vs80.vcproj | 8 + projects/openttd_vs90.vcproj | 8 + source.list | 2 + src/gui.h | 1 + src/lang/english.txt | 11 + src/script/api/game/game_window.hpp.sq | 7 + src/script/api/script_window.hpp | 17 + .../api/template/template_window.hpp.sq | 2 + src/story.cpp | 10 + src/story_gui.cpp | 731 ++++++++++++++++++ src/table/sprites.h | 9 +- src/toolbar_gui.cpp | 9 +- src/widgets/story_widget.h | 26 + src/window_type.h | 5 + 22 files changed, 858 insertions(+), 9 deletions(-) create mode 100644 src/story_gui.cpp create mode 100644 src/widgets/story_widget.h diff --git a/bin/baseset/openttd.grf b/bin/baseset/openttd.grf index afee09e4fd0fc08557b94ed58ef086fa37d9bf54..86b70789f0052ec79fb95e536a901bee069b1e3a 100644 GIT binary patch delta 1234 zcmZo%ZZu_s5eo~$|7ndZtt^bKEKIE|%&jaeTUl6r|1z%I9`u)0zGwPDJvNd02NJAV zAh1A@Jtrq8CyOQP0s96)Ha0dkc5bd0Y!}3D2y$?7b8~aEb929t;bdb|WXR#>;pTb4 z!pzOi@j~>43?tVA5oT^4o)^NLJe(XH9IWi@><>guygLv;N{^30Tv!M z4mK{<7seMfSa?}jS#D^s)N`@2u-p)NVadeH`$F`F#tD%V8jL&(G%f_N^RTmVaB^`S zuz8U3B9N7ZosElYLkbHk3op-$3T94r_6-#`Y;I^Uv9fLuc~HT~xsMM@Qd;6uQc_=1QsQ0gK7cWg)D_iMK5&3l{^aySv-}LSZfQ5iaePMS&NiwYgubw z7>E?rDAg9T7O~b878cbP*D4h$6)Ca4&}6A$EvkKCF3eI>q*S9+Q{e8d#Zu&1SXir6 z`yz?4=tVL&lLrfvvXUuNjS}++M=3TFVB~pjI}Q&v((ns*1qU|F#Cn!i<3759!NY`z*SUQ zTU=Z0U0bXCg5!nd3mc}Q+Lwu3wY7P5CAE3AdBrbSA4t9|eVBGJ`(eY&Y()68v9Pf) zFfhDezQA^)o`;Qv!-0i`WrxHKE;bepCr1az6B5iUEDkr!UWl?8IT<-QIKI$-AbY`< z(eZ)k3*8$W3p8FhUNGnoz2Vwn+o7>Rl+p1(+JmYW)ep1|^szWNI5|8JUJ&@;)Qh<* zDqlRfaQ(u?178ljUGejTNT+P4L5F6CZD&+R(9JwXwuOx|80%q)f*Ix_9%dFcmIrJP zST6{$vaqnQaNH1KWPKp^K!B0;1vew>1(655EG#UX91mnK2*0p-p}@k$$-((Tosso~ z^#dM8mKP$7TrZ@UxVbL)zuj-9qJv{ z9sV6j2ODmdz3jyvoS@L;goY+N3kMe`7bn*RP;hdBf|G@ti<|3){sY+)whu&^IXO6Q zaMbV6VAfv3^+M!^0ShO~(j_;77?-RNWnQ{u+XdSfqAzTB2wzA&Ao@b>K-vw_7iljn z5A?k#X5@Te|H6ln`#|4=Q_L(&v~LJs*!JSVjc1HYURb`kc;L%J_7|;8+DkV4e4xRy zbcr^@3(=LbH-s4(7Kk#ja9j{xAo}9T1>qH18-zF5GjlA_X4}}vv`xFcu#>I5u#>&L Zu#=;`u#>aBu#>C3u#2Cl delta 68 zcmbQT!KiV$5eo~$|A~z(tt^bKEKIE|%&jaeTUl6r|1z%J9`u)0zNej~kFA}hkG-9x YkE5NXkF%YnkE@-fk9#{yACCYR0PuMfyZ`_I diff --git a/bin/baseset/orig_dos.obg b/bin/baseset/orig_dos.obg index 593257fb64..16cf83a7ff 100644 --- a/bin/baseset/orig_dos.obg +++ b/bin/baseset/orig_dos.obg @@ -64,7 +64,7 @@ TRGI.GRF = da6a6c9dcc451eec88d79211437b76a8 TRGC.GRF = ed446637e034104c5559b32c18afe78d TRGH.GRF = ee6616fb0e6ef6b24892c58c93d86fc9 TRGT.GRF = e30e8a398ae86c03dc534a8ac7dfb3b6 -OPENTTD.GRF = 9285f720c9c6805b4adcfcbf869a7deb +OPENTTD.GRF = 63d40d4bc6cfb3546cab72d94614e6cd [origin] default = You can find it on your Transport Tycoon Deluxe CD-ROM. diff --git a/bin/baseset/orig_dos_de.obg b/bin/baseset/orig_dos_de.obg index aa8112d5fb..a2132dde9e 100644 --- a/bin/baseset/orig_dos_de.obg +++ b/bin/baseset/orig_dos_de.obg @@ -64,7 +64,7 @@ TRGI.GRF = da6a6c9dcc451eec88d79211437b76a8 TRGC.GRF = ed446637e034104c5559b32c18afe78d TRGH.GRF = ee6616fb0e6ef6b24892c58c93d86fc9 TRGT.GRF = fcde1d7e8a74197d72a62695884b909e -OPENTTD.GRF = 9285f720c9c6805b4adcfcbf869a7deb +OPENTTD.GRF = 63d40d4bc6cfb3546cab72d94614e6cd [origin] default = You can find it on your Transport Tycoon Deluxe CD-ROM. diff --git a/bin/baseset/orig_win.obg b/bin/baseset/orig_win.obg index 8d50bbca4c..bc3411ba83 100644 --- a/bin/baseset/orig_win.obg +++ b/bin/baseset/orig_win.obg @@ -64,7 +64,7 @@ TRGIR.GRF = 0c2484ff6be49fc63a83be6ab5c38f32 TRGCR.GRF = 3668f410c761a050b5e7095a2b14879b TRGHR.GRF = 06bf2b7a31766f048baac2ebe43457b1 TRGTR.GRF = de53650517fe661ceaa3138c6edb0eb8 -OPENTTD.GRF = 9285f720c9c6805b4adcfcbf869a7deb +OPENTTD.GRF = 63d40d4bc6cfb3546cab72d94614e6cd [origin] default = You can find it on your Transport Tycoon Deluxe CD-ROM. diff --git a/media/extra_grf/openttdgui.nfo b/media/extra_grf/openttdgui.nfo index 33ad4cb8b4..1d96de8558 100644 --- a/media/extra_grf/openttdgui.nfo +++ b/media/extra_grf/openttdgui.nfo @@ -7,7 +7,7 @@ // 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 . // -1 * 0 0C "OpenTTD GUI graphics" - -1 * 3 05 15 \b 169 // OPENTTD_SPRITE_COUNT + -1 * 3 05 15 \b 174 // OPENTTD_SPRITE_COUNT -1 sprites/openttdgui.png 8bpp 66 8 64 31 -31 7 normal -1 sprites/openttdgui.png 8bpp 146 8 64 31 -31 7 normal -1 sprites/openttdgui.png 8bpp 226 8 64 31 -31 7 normal @@ -177,3 +177,8 @@ -1 sprites/openttdgui.png 8bpp 312 440 14 10 0 0 normal -1 sprites/openttdgui.png 8bpp 328 440 14 10 0 0 normal -1 sprites/openttdgui.png 8bpp 348 440 8 8 0 0 normal + -1 sprites/openttdgui.png 8bpp 362 440 20 20 0 0 normal + -1 sprites/openttdgui.png 8bpp 388 440 20 20 0 0 normal + -1 sprites/openttdgui.png 8bpp 414 440 20 20 0 0 normal + -1 sprites/openttdgui.png 8bpp 440 440 20 20 0 0 normal + -1 sprites/openttdgui.png 8bpp 466 440 20 20 0 0 normal diff --git a/media/extra_grf/openttdgui.png b/media/extra_grf/openttdgui.png index f03033d2968c39663f2d0dd124c379f6d48f4fff..6f011b654dadfa41a8902be5284f647ec0391866 100644 GIT binary patch delta 25636 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 + @@ -763,6 +764,7 @@ + diff --git a/projects/openttd_vs100.vcxproj.filters b/projects/openttd_vs100.vcxproj.filters index c521cc6d82..f2900c846f 100644 --- a/projects/openttd_vs100.vcxproj.filters +++ b/projects/openttd_vs100.vcxproj.filters @@ -1344,6 +1344,9 @@ GUI Source Code + + GUI Source Code + GUI Source Code @@ -1518,6 +1521,9 @@ Widgets + + Widgets + Widgets diff --git a/projects/openttd_vs80.vcproj b/projects/openttd_vs80.vcproj index d6d806212d..5c866b99dd 100644 --- a/projects/openttd_vs80.vcproj +++ b/projects/openttd_vs80.vcproj @@ -2102,6 +2102,10 @@ RelativePath=".\..\src\statusbar_gui.cpp" > + + @@ -2338,6 +2342,10 @@ RelativePath=".\..\src\widgets\statusbar_widget.h" > + + diff --git a/projects/openttd_vs90.vcproj b/projects/openttd_vs90.vcproj index 8219894e7a..96120ed473 100644 --- a/projects/openttd_vs90.vcproj +++ b/projects/openttd_vs90.vcproj @@ -2099,6 +2099,10 @@ RelativePath=".\..\src\statusbar_gui.cpp" > + + @@ -2335,6 +2339,10 @@ RelativePath=".\..\src\widgets\statusbar_widget.h" > + + diff --git a/source.list b/source.list index 1a72fbd8ba..be324f335f 100644 --- a/source.list +++ b/source.list @@ -457,6 +457,7 @@ signs_gui.cpp smallmap_gui.cpp station_gui.cpp statusbar_gui.cpp +story_gui.cpp subsidy_gui.cpp terraform_gui.cpp textfile_gui.cpp @@ -517,6 +518,7 @@ widgets/sign_widget.h widgets/smallmap_widget.h widgets/station_widget.h widgets/statusbar_widget.h +widgets/story_widget.h widgets/subsidy_widget.h widgets/terraform_widget.h widgets/timetable_widget.h diff --git a/src/gui.h b/src/gui.h index 8b31c6c984..79c33e0b37 100644 --- a/src/gui.h +++ b/src/gui.h @@ -51,6 +51,7 @@ void ShowIndustryCargoesWindow(); void ShowSubsidiesList(); void ShowGoalsList(); void ShowGoalQuestion(uint16 id, byte type, uint32 button_mask, const char *question); +void ShowStoryBook(); void ShowEstimatedCostOrIncome(Money cost, int x, int y); diff --git a/src/lang/english.txt b/src/lang/english.txt index 6e5b8eeb14..9fef3802d0 100644 --- a/src/lang/english.txt +++ b/src/lang/english.txt @@ -399,6 +399,7 @@ STR_GRAPH_MENU_CARGO_PAYMENT_RATES :Cargo payment r ############ range for company league menu starts STR_GRAPH_MENU_GOAL :Current goals +STR_GRAPH_MENU_STORY_BOOK :Story book STR_GRAPH_MENU_COMPANY_LEAGUE_TABLE :Company league table STR_GRAPH_MENU_DETAILED_PERFORMANCE_RATING :Detailed performance rating STR_GRAPH_MENU_HIGHSCORE :Highscore table @@ -2947,6 +2948,16 @@ STR_SUBSIDIES_SUBSIDISED_TITLE :{BLACK}Services STR_SUBSIDIES_SUBSIDISED_FROM_TO :{ORANGE}{STRING} from {STRING2} to {STRING2}{YELLOW} ({COMPANY}{YELLOW}, until {DATE_SHORT}) STR_SUBSIDIES_TOOLTIP_CLICK_ON_SERVICE_TO_CENTER :{BLACK}Click on service to centre main view on industry/town. Ctrl+Click opens a new viewport on industry/town location +# Story book window +STR_STORY_BOOK_CAPTION :{WHITE}Story Book +STR_STORY_BOOK_TITLE :{YELLOW}{RAW_STRING} +STR_STORY_BOOK_GENERIC_PAGE_ITEM :Page {NUM} +STR_STORY_BOOK_SEL_PAGE_TOOLTIP :{BLACK}Jump to a specific page by selecting it in this drop down list. +STR_STORY_BOOK_PREV_PAGE :{BLACK}Previous +STR_STORY_BOOK_PREV_PAGE_TOOLTIP :{BLACK}Go to previous page +STR_STORY_BOOK_NEXT_PAGE :{BLACK}Next +STR_STORY_BOOK_NEXT_PAGE_TOOLTIP :{BLACK}Go to next page + # Station list window STR_STATION_LIST_TOOLTIP :{BLACK}Station names - click on name to centre main view on station. Ctrl+Click opens a new viewport on station location STR_STATION_LIST_USE_CTRL_TO_SELECT_MORE :{BLACK}Hold Ctrl to select more than one item diff --git a/src/script/api/game/game_window.hpp.sq b/src/script/api/game/game_window.hpp.sq index 01811a2125..73b4d4bac9 100644 --- a/src/script/api/game/game_window.hpp.sq +++ b/src/script/api/game/game_window.hpp.sq @@ -76,6 +76,7 @@ void SQGSWindow_Register(Squirrel *engine) SQGSWindow.DefSQConst(engine, ScriptWindow::WC_SIGN_LIST, "WC_SIGN_LIST"); SQGSWindow.DefSQConst(engine, ScriptWindow::WC_AI_LIST, "WC_AI_LIST"); SQGSWindow.DefSQConst(engine, ScriptWindow::WC_GOALS_LIST, "WC_GOALS_LIST"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WC_STORY_BOOK, "WC_STORY_BOOK"); SQGSWindow.DefSQConst(engine, ScriptWindow::WC_STATION_LIST, "WC_STATION_LIST"); SQGSWindow.DefSQConst(engine, ScriptWindow::WC_TRAINS_LIST, "WC_TRAINS_LIST"); SQGSWindow.DefSQConst(engine, ScriptWindow::WC_ROADVEH_LIST, "WC_ROADVEH_LIST"); @@ -1084,6 +1085,12 @@ void SQGSWindow_Register(Squirrel *engine) SQGSWindow.DefSQConst(engine, ScriptWindow::WID_S_LEFT, "WID_S_LEFT"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_S_MIDDLE, "WID_S_MIDDLE"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_S_RIGHT, "WID_S_RIGHT"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SB_CAPTION, "WID_SB_CAPTION"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SB_SEL_PAGE, "WID_SB_SEL_PAGE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SB_PAGE_PANEL, "WID_SB_PAGE_PANEL"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SB_SCROLLBAR, "WID_SB_SCROLLBAR"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SB_PREV_PAGE, "WID_SB_PREV_PAGE"); + SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SB_NEXT_PAGE, "WID_SB_NEXT_PAGE"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SUL_PANEL, "WID_SUL_PANEL"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_SUL_SCROLLBAR, "WID_SUL_SCROLLBAR"); SQGSWindow.DefSQConst(engine, ScriptWindow::WID_TT_SHOW_PLACE_OBJECT, "WID_TT_SHOW_PLACE_OBJECT"); diff --git a/src/script/api/script_window.hpp b/src/script/api/script_window.hpp index 1fae2bfae8..e9e10e3ed5 100644 --- a/src/script/api/script_window.hpp +++ b/src/script/api/script_window.hpp @@ -69,6 +69,7 @@ #include "../../widgets/viewport_widget.h" #include "../../widgets/waypoint_widget.h" #include "../../widgets/link_graph_legend_widget.h" +#include "../../widgets/story_widget.h" /** * Class that handles window interaction. A Window in OpenTTD has two imporant @@ -366,6 +367,11 @@ public: */ WC_GOALS_LIST = ::WC_GOALS_LIST, + /** + * Story book; %Window numbers: + * - CompanyID = #StoryBookWidgets + */ + WC_STORY_BOOK = ::WC_STORY_BOOK, /** * Station list; %Window numbers: @@ -2241,6 +2247,17 @@ public: WID_S_RIGHT = ::WID_S_RIGHT, ///< Right part; bank balance. }; + /* automatically generated from ../../widgets/story_widget.h */ + /** Widgets of the #GoalListWindow class. */ + enum StoryBookWidgets { + WID_SB_CAPTION = ::WID_SB_CAPTION, ///< Caption of the window. + WID_SB_SEL_PAGE = ::WID_SB_SEL_PAGE, ///< Page selector. + WID_SB_PAGE_PANEL = ::WID_SB_PAGE_PANEL, ///< Page body. + WID_SB_SCROLLBAR = ::WID_SB_SCROLLBAR, ///< Scrollbar of the goal list. + WID_SB_PREV_PAGE = ::WID_SB_PREV_PAGE, ///< Prev button. + WID_SB_NEXT_PAGE = ::WID_SB_NEXT_PAGE, ///< Next button. + }; + /* automatically generated from ../../widgets/subsidy_widget.h */ /** Widgets of the #SubsidyListWindow class. */ enum SubsidyListWidgets { diff --git a/src/script/api/template/template_window.hpp.sq b/src/script/api/template/template_window.hpp.sq index 238c403c2e..9f01e42d5a 100644 --- a/src/script/api/template/template_window.hpp.sq +++ b/src/script/api/template/template_window.hpp.sq @@ -209,6 +209,8 @@ namespace SQConvert { template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::JoinStationWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } template <> inline ScriptWindow::StatusbarWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::StatusbarWidgets)tmp; } template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::StatusbarWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } + template <> inline ScriptWindow::StoryBookWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::StoryBookWidgets)tmp; } + template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::StoryBookWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } template <> inline ScriptWindow::SubsidyListWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::SubsidyListWidgets)tmp; } template <> inline int Return(HSQUIRRELVM vm, ScriptWindow::SubsidyListWidgets res) { sq_pushinteger(vm, (int32)res); return 1; } template <> inline ScriptWindow::TerraformToolbarWidgets GetParam(ForceType, HSQUIRRELVM vm, int index, SQAutoFreePointers *ptr) { SQInteger tmp; sq_getinteger(vm, index, &tmp); return (ScriptWindow::TerraformToolbarWidgets)tmp; } diff --git a/src/story.cpp b/src/story.cpp index 3574cf5252..e492ded4da 100644 --- a/src/story.cpp +++ b/src/story.cpp @@ -20,6 +20,7 @@ #include "tile_map.h" #include "goal_type.h" #include "goal_base.h" +#include "window_func.h" StoryPageElementID _new_story_page_element_id; @@ -123,6 +124,8 @@ CommandCost CmdCreateStoryPage(TileIndex tile, DoCommandFlag flags, uint32 p1, u s->title = strdup(text); } + InvalidateWindowData(WC_STORY_BOOK, -1); + _new_story_page_id = s->index; _story_page_next_sort_value++; } @@ -172,6 +175,8 @@ CommandCost CmdCreateStoryPageElement(TileIndex tile, DoCommandFlag flags, uint3 pe->page = page_id; UpdateElement(*pe, tile, p2, text); + InvalidateWindowData(WC_STORY_BOOK, page_id); + _new_story_page_element_id = pe->index; _story_page_element_next_sort_value++; } @@ -205,6 +210,7 @@ CommandCost CmdUpdateStoryPageElement(TileIndex tile, DoCommandFlag flags, uint3 if (flags & DC_EXEC) { UpdateElement(*pe, tile, p2, text); + InvalidateWindowData(WC_STORY_BOOK, pe->page); } return CommandCost(); @@ -233,6 +239,8 @@ CommandCost CmdSetStoryPageTitle(TileIndex tile, DoCommandFlag flags, uint32 p1, } else { p->title = strdup(text); } + + InvalidateWindowData(WC_STORY_BOOK, page_id); } return CommandCost(); @@ -264,6 +272,8 @@ CommandCost CmdRemoveStoryPage(TileIndex tile, DoCommandFlag flags, uint32 p1, u } delete p; + + InvalidateWindowData(WC_STORY_BOOK, -1); } return CommandCost(); diff --git a/src/story_gui.cpp b/src/story_gui.cpp new file mode 100644 index 0000000000..62ec3606a8 --- /dev/null +++ b/src/story_gui.cpp @@ -0,0 +1,731 @@ +/* $Id$ */ + +/* + * This file is part of OpenTTD. + * 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. + * 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. + * 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 . + */ + +/** @file goal_gui.cpp GUI for goals. */ + +#include "stdafx.h" +#include "window_gui.h" +#include "strings_func.h" +#include "date_func.h" +#include "gui.h" +#include "story_base.h" +#include "core/geometry_func.hpp" +#include "company_func.h" +#include "command_func.h" +#include "widgets/dropdown_type.h" +#include "widgets/dropdown_func.h" +#include "sortlist_type.h" +#include "goal_base.h" +#include "viewport_func.h" + +#include "widgets/story_widget.h" + +#include "table/strings.h" +#include "table/sprites.h" + +typedef GUIList GUIStoryPageList; +typedef GUIList GUIStoryPageElementList; + +struct StoryBookWindow : Window { +protected: + Scrollbar *vscroll; ///< Scrollbar of the page text. + + GUIStoryPageList story_pages; ///< Sorted list of pages. + GUIStoryPageElementList story_page_elements; ///< Sorted list of page elements that belong to the current page. + StoryPageID selected_page_id; ///< Pool index of selected page. + char selected_generic_title[255]; ///< If the selected page doesn't have a custom title, this buffer is used to store a generic page title. + + static GUIStoryPageList::SortFunction * const page_sorter_funcs[]; + static GUIStoryPageElementList::SortFunction * const page_element_sorter_funcs[]; + + /** (Re)Build story page list. */ + void BuildStoryPageList() + { + if (this->story_pages.NeedRebuild()) { + this->story_pages.Clear(); + + const StoryPage *p; + FOR_ALL_STORY_PAGES(p) { + if (this->IsPageAvailable(p)) { + *this->story_pages.Append() = p; + } + } + + this->story_pages.Compact(); + this->story_pages.RebuildDone(); + } + + this->story_pages.Sort(); + } + + /** Sort story pages by order value. */ + static int CDECL PageOrderSorter(const StoryPage * const *a, const StoryPage * const *b) + { + return (*a)->sort_value - (*b)->sort_value; + } + + /** (Re)Build story page element list. */ + void BuildStoryPageElementList() + { + if (this->story_page_elements.NeedRebuild()) { + this->story_page_elements.Clear(); + + const StoryPage *p = GetSelPage(); + if (p != NULL) { + const StoryPageElement *pe; + FOR_ALL_STORY_PAGE_ELEMENTS(pe) { + if (pe->page == p->index) { + *this->story_page_elements.Append() = pe; + } + } + } + + this->story_page_elements.Compact(); + this->story_page_elements.RebuildDone(); + } + + this->story_page_elements.Sort(); + } + + /** Sort story page elements by order value. */ + static int CDECL PageElementOrderSorter(const StoryPageElement * const *a, const StoryPageElement * const *b) + { + return (*a)->sort_value - (*b)->sort_value; + } + + /* + * Checks if a given page should be visible in the story book. + * @param page The page to check. + * @return True if the page should be visible, otherwise false. + */ + bool IsPageAvailable(const StoryPage *page) const + { + return page->company == INVALID_COMPANY || page->company == _local_company; + } + + /** + * Get instance of selected page. + * @return Instance of selected page or NULL if no page is selected. + */ + StoryPage *GetSelPage() const + { + if (!_story_page_pool.IsValidID(selected_page_id)) return NULL; + return _story_page_pool.Get(selected_page_id); + } + + /** + * Get the page number of selected page. + * @return Number of available pages before to the selected one, or -1 if no page is selected. + */ + int GetSelPageNum() const + { + int page_number = 0; + for (const StoryPage *const*iter = this->story_pages.Begin(); iter != this->story_pages.End(); iter++) { + const StoryPage *p = *iter; + if (p->index == this->selected_page_id) { + return page_number; + } + page_number++; + } + return -1; + } + + /** + * Check if the selected page is also the first available page. + */ + bool IsFirstPageSelected() + { + /* Verify that the selected page exist. */ + if (!_story_page_pool.IsValidID(this->selected_page_id)) return false; + + return (*this->story_pages.Begin())->index == this->selected_page_id; + } + + /** + * Check if the selected page is also the last available page. + */ + bool IsLastPageSelected() + { + /* Verify that the selected page exist. */ + if (!_story_page_pool.IsValidID(this->selected_page_id)) return false; + + if (this->story_pages.Length() <= 1) return true; + const StoryPage *last = *(this->story_pages.End() - 1); + return last->index == this->selected_page_id; + } + + /** + * Updates the content of selected page. + */ + void RefreshSelectedPage() + { + /* Generate generic title if selected page have no custom title. */ + StoryPage *page = this->GetSelPage(); + if (page != NULL && page->title == NULL) { + SetDParam(0, GetSelPageNum() + 1); + GetString(selected_generic_title, STR_STORY_BOOK_GENERIC_PAGE_ITEM, lastof(selected_generic_title)); + } + + this->story_page_elements.ForceRebuild(); + this->BuildStoryPageElementList(); + + this->vscroll->SetCount(this->CountLines()); + this->SetWidgetDirty(WID_SB_SCROLLBAR); + this->SetWidgetDirty(WID_SB_SEL_PAGE); + this->SetWidgetDirty(WID_SB_PAGE_PANEL); + } + + /** + * Selects the previous available page before the currently selected page. + */ + void SelectPrevPage() + { + if (!_story_page_pool.IsValidID(this->selected_page_id)) return; + + /* Find the last available page which is previous to the current selected page. */ + const StoryPage *last_available; + last_available = NULL; + for (const StoryPage *const*iter = this->story_pages.Begin(); iter != this->story_pages.End(); iter++) { + const StoryPage *p = *iter; + if (p->index == this->selected_page_id) { + if (last_available == NULL) return; // No previous page available. + this->SetSelectedPage(last_available->index); + return; + } + last_available = p; + } + } + + /** + * Selects the next available page after the currently selected page. + */ + void SelectNextPage() + { + if (!_story_page_pool.IsValidID(this->selected_page_id)) return; + + /* Find selected page. */ + for (const StoryPage *const*iter = this->story_pages.Begin(); iter != this->story_pages.End(); iter++) { + const StoryPage *p = *iter; + if (p->index == this->selected_page_id) { + /* Select the page after selected page. */ + iter++; + if (iter != this->story_pages.End()) { + this->SetSelectedPage((*iter)->index); + } + return; + } + } + } + + /** + * Builds the page selector drop down list. + */ + DropDownList *BuildDropDownList() const + { + DropDownList *list = new DropDownList(); + uint16 page_num = 1; + for (const StoryPage *const*iter = this->story_pages.Begin(); iter != this->story_pages.End(); iter++) { + const StoryPage *p = *iter; + char *title = p->title; + bool current_page = p->index == this->selected_page_id; + DropDownListStringItem *item = NULL; + if (p->title != NULL) { + item = new DropDownListCharStringItem(p->title, p->index, current_page); + } else { + /* No custom title => use a generic page title with page number. */ + DropDownListParamStringItem *str_item = + new DropDownListParamStringItem(STR_STORY_BOOK_GENERIC_PAGE_ITEM, p->index, current_page); + str_item->SetParam(0, page_num); + item = str_item; + } + + list->push_back(item); + page_num++; + } + + /* Check if list is empty. */ + if (list->size() == 0) { + free(list); + list = NULL; + } + + return list; + } + + /** + * Get the width available for displaying content on the page panel. + */ + uint GetAvailablePageContentWidth() + { + return this->GetWidget(WID_SB_PAGE_PANEL)->current_x - WD_FRAMETEXT_LEFT - WD_FRAMERECT_RIGHT; + } + + /** + * Counts how many lines that are used by Date and Title + * (excluding marginal after Title, as each body element has + * an empty row before the elment). + * @param max_width Available width to display content. + * @return the number of lines. + */ + uint CountHeadLines(int max_width) + { + StoryPage *page = this->GetSelPage(); + if (page == NULL) return 0; + int num_lines = 0; + + /* Title lines */ + num_lines += 1; // Date always use exactly one line. + SetDParamStr(0, page->title != NULL ? page->title : this->selected_generic_title); + num_lines += GetStringLineCount(STR_STORY_BOOK_TITLE, max_width); + + return num_lines; + } + + /** + * Decides which sprite to display for a given page element. + * @param pe The page element. + * @return The SpriteID of the sprite to display. + * @pre pe.type must be SPET_GOAL or SPET_LOCATION. + */ + SpriteID GetPageElementSprite(const StoryPageElement &pe) const + { + switch (pe.type) { + case SPET_GOAL: { + Goal *g = Goal::Get((GoalID) pe.referenced_id); + if (g == NULL) return SPR_IMG_GOAL_BROKEN_REF; + return g->completed ? SPR_IMG_GOAL_COMPLETED : SPR_IMG_GOAL; + } + case SPET_LOCATION: + return SPR_IMG_VIEW_LOCATION; + default: + NOT_REACHED(); + } + } + + /** + * Count the number of lines used by a given page element. + * @param pe The story page element. + * @param max_width Available width to display content. + * @return the number of lines. + */ + uint CountPageElementLines(const StoryPageElement &pe, int max_width) + { + switch (pe.type) { + case SPET_TEXT: + SetDParamStr(0, pe.text); + return GetStringLineCount(STR_BLACK_RAW_STRING, max_width); + break; + + case SPET_GOAL: + case SPET_LOCATION: { + Dimension sprite_dim = GetSpriteSize(GetPageElementSprite(pe)); + int line_height = GetStringHeight(STR_JUST_NOTHING, INT_MAX); + if (line_height == 0) return 1; + return max((uint)1, sprite_dim.height / (uint)line_height); + break; + } + default: + NOT_REACHED(); + } + } + + /** + * Count the number of lines in this window. + * @return the number of lines. + */ + uint CountLines() + { + StoryPage *page = this->GetSelPage(); + if (page == NULL) return 0; + int max_width = GetAvailablePageContentWidth(); + + /* Head lines */ + int num_lines = CountHeadLines(max_width); + + /* Body lines */ + for (const StoryPageElement **iter = this->story_page_elements.Begin(); iter != this->story_page_elements.End(); iter++) { + const StoryPageElement *pe = *iter; + num_lines += 1; // For the space between previous element and current element. + + num_lines += CountPageElementLines(*pe, max_width); + } + + return num_lines; + } + + /** + * Draws a page element that is composed of a sprite to the left and a single line of + * text after that. These page elements are generally clickable and are thus called + * action elements. + * @param y_offset Current y_offset which will get updated when this method has completed its drawing. + * @param width Width of the region available for drawing. + * @param line_height Height of one line of text. + * @param action_sprite The sprite to draw. + * @return the number of lines. + */ + void DrawActionElement(int &y_offset, int width, int line_height, SpriteID action_sprite) const + { + Dimension sprite_dim = GetSpriteSize(action_sprite); + uint element_height = max((uint)1, sprite_dim.height / (uint)line_height) * line_height; + + uint sprite_top = y_offset + (element_height - sprite_dim.height) / 2; + uint text_top = y_offset + (element_height - line_height) / 2; + + DrawSprite(action_sprite, PAL_NONE, 0, y_offset); + DrawString(sprite_dim.width + WD_FRAMETEXT_LEFT, width, text_top, STR_JUST_RAW_STRING, TC_BLACK); + + y_offset += element_height; + } + + /** + * Internal event handler for when a page element is clicked. + * @param pe The clicked page element. + */ + void OnPageElementClick(const StoryPageElement& pe) + { + switch (pe.type) { + case SPET_TEXT: + /* Do nothing. */ + break; + + case SPET_LOCATION: + if (_ctrl_pressed) { + ShowExtraViewPortWindow((TileIndex)pe.referenced_id); + } else { + ScrollMainWindowToTile((TileIndex)pe.referenced_id); + } + break; + + case SPET_GOAL: + ShowGoalsList(); + break; + + default: + NOT_REACHED(); + } + } + +public: + StoryBookWindow(WindowDesc *desc, WindowNumber window_number) : Window(desc) + { + this->CreateNestedTree(); + this->vscroll = this->GetScrollbar(WID_SB_SCROLLBAR); + + /* Initalize page sort. */ + this->story_pages.SetSortFuncs(StoryBookWindow::page_sorter_funcs); + this->story_pages.ForceRebuild(); + this->BuildStoryPageList(); + this->story_page_elements.SetSortFuncs(StoryBookWindow::page_element_sorter_funcs); + /* story_page_elements will get built by SetSelectedPage */ + + this->FinishInitNested(window_number); + + /* Initialize selected vars. */ + this->selected_generic_title[0] = '\0'; + this->selected_page_id = INVALID_STORY_PAGE; + + this->OnInvalidateData(-1); + } + + /** + * Updates the disabled state of the prev/next buttons. + */ + void UpdatePrevNextDisabledState() + { + this->SetWidgetDisabledState(WID_SB_PREV_PAGE, story_pages.Length() == 0 || this->IsFirstPageSelected()); + this->SetWidgetDisabledState(WID_SB_NEXT_PAGE, story_pages.Length() == 0 || this->IsLastPageSelected()); + this->SetWidgetDirty(WID_SB_PREV_PAGE); + this->SetWidgetDirty(WID_SB_NEXT_PAGE); + } + + /** + * Sets the selected page. + * @param page_index pool index of the page to select. + */ + void SetSelectedPage(uint16 page_index) + { + if (this->selected_page_id != page_index) { + this->selected_page_id = page_index; + this->RefreshSelectedPage(); + this->UpdatePrevNextDisabledState(); + } + } + + virtual void SetStringParameters(int widget) const + { + if (widget != WID_SB_SEL_PAGE) return; + + StoryPage *page = this->GetSelPage(); + SetDParamStr(0, page != NULL && page->title != NULL ? page->title : this->selected_generic_title); + } + + virtual void DrawWidget(const Rect &r, int widget) const + { + if (widget != WID_SB_PAGE_PANEL) return; + + StoryPage *page = this->GetSelPage(); + if (page == NULL) return; + + const int x = r.left + WD_FRAMETEXT_LEFT; + const int y = r.top + WD_FRAMETEXT_TOP; + const int right = r.right - WD_FRAMETEXT_RIGHT; + const int bottom = r.bottom - WD_FRAMETEXT_BOTTOM; + + /* Set up a clipping region for the panel. */ + DrawPixelInfo tmp_dpi; + if (!FillDrawPixelInfo(&tmp_dpi, x, y, right - x + 1, r.bottom - y + 1)) return; + + DrawPixelInfo *old_dpi = _cur_dpi; + _cur_dpi = &tmp_dpi; + + /* Draw content (now coordinates given to Draw** are local to the new clipping region). */ + int line_height = GetStringHeight(STR_JUST_NOTHING, INT_MAX); + int y_offset = - this->vscroll->GetPosition() * line_height; + + /* Date */ + SetDParam(0, page->date); + DrawString(0, right - x, y_offset, STR_JUST_DATE_LONG, TC_BLACK); + y_offset += line_height; + + /* Title */ + SetDParamStr(0, page->title != NULL ? page->title : this->selected_generic_title); + y_offset = DrawStringMultiLine(0, right - x, y_offset, bottom - y, STR_STORY_BOOK_TITLE, TC_BLACK, SA_TOP | SA_HOR_CENTER); + + /* Page elements */ + for (const StoryPageElement *const*iter = this->story_page_elements.Begin(); iter != this->story_page_elements.End(); iter++) { + const StoryPageElement *const pe = *iter; + y_offset += line_height; // margin to previous element + + switch (pe->type) { + case SPET_TEXT: + SetDParamStr(0, pe->text); + y_offset = DrawStringMultiLine(0, right - x, y_offset, bottom - y, STR_JUST_RAW_STRING, TC_BLACK, SA_TOP | SA_LEFT); + break; + + case SPET_GOAL: { + Goal *g = Goal::Get((GoalID) pe->referenced_id); + if (g != NULL) { + SetDParamStr(0, g->text); + DrawActionElement(y_offset, right - x, line_height, GetPageElementSprite(*pe)); + } else { + y_offset += line_height; + } + break; + } + + case SPET_LOCATION: + SetDParamStr(0, pe->text); + DrawActionElement(y_offset, right - x, line_height, GetPageElementSprite(*pe)); + break; + } + } + + /* Restore clipping region. */ + _cur_dpi = old_dpi; + } + + virtual void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) + { + if (widget != WID_SB_SEL_PAGE && widget != WID_SB_PAGE_PANEL) return; + + Dimension d = GetStringBoundingBox(STR_JUST_NOTHING); + d.width = 0; + + switch(widget) { + case WID_SB_SEL_PAGE: { + + /* Get max title width. */ + for (uint16 i = 0; i < this->story_pages.Length(); i++) { + const StoryPage *s = this->story_pages[i]; + + if (s->title != NULL) { + SetDParamStr(0, s->title); + } else { + SetDParamStr(0, this->selected_generic_title); + } + Dimension title_d = GetStringBoundingBox(STR_BLACK_RAW_STRING); + + if (title_d.width > d.width) { + d.width = title_d.width; + } + } + + d.width += padding.width + WD_DROPDOWNTEXT_LEFT + WD_DROPDOWNTEXT_RIGHT; + d.height += padding.height + WD_DROPDOWNTEXT_TOP + WD_DROPDOWNTEXT_BOTTOM; + *size = maxdim(*size, d); + break; + } + + case WID_SB_PAGE_PANEL: { + resize->height = d.height; + + d.height *= 5; + d.height += padding.height + WD_FRAMETEXT_TOP + WD_FRAMETEXT_BOTTOM; + *size = maxdim(*size, d); + break; + } + } + + } + + virtual void OnResize() + { + this->vscroll->SetCapacityFromWidget(this, WID_SB_PAGE_PANEL, WD_FRAMETEXT_TOP + WD_FRAMETEXT_BOTTOM); + this->vscroll->SetCount(this->CountLines()); + } + + virtual void OnClick(Point pt, int widget, int click_count) + { + switch (widget) { + case WID_SB_SEL_PAGE: { + DropDownList *list = this->BuildDropDownList(); + if (list != NULL) { + /* Get the index of selected page. */ + int selected = 0; + for (uint16 i = 0; i < this->story_pages.Length(); i++) { + const StoryPage *p = this->story_pages[i]; + if (p->index == this->selected_page_id) break; + selected++; + } + + ShowDropDownList(this, list, selected, widget); + } + break; + } + + case WID_SB_PREV_PAGE: + this->SelectPrevPage(); + break; + + case WID_SB_NEXT_PAGE: + this->SelectNextPage(); + break; + + case WID_SB_PAGE_PANEL: { + uint clicked_row = this->vscroll->GetScrolledRowFromWidget(pt.y, this, WID_SB_PAGE_PANEL, WD_FRAMETEXT_TOP); + uint max_width = GetAvailablePageContentWidth(); + + /* Skip head rows. */ + uint n_head_rows = this->CountHeadLines(max_width); + if (clicked_row < n_head_rows) return; + + /* Detect if a page element was clicked. */ + uint row = n_head_rows; + for (const StoryPageElement *const*iter = this->story_page_elements.Begin(); iter != this->story_page_elements.End(); iter++) { + const StoryPageElement *const pe = *iter; + + row += 1; // margin row + + uint content_rows = CountPageElementLines(*pe, max_width); + if (clicked_row >= row && clicked_row < row + content_rows) { + this->OnPageElementClick(*pe); + return; + } + + row += content_rows; + } + } + } + } + + virtual void OnDropdownSelect(int widget, int index) + { + if (widget != WID_SB_SEL_PAGE) return; + + /* index (which is set in BuildDropDownList) is the page id. */ + this->SetSelectedPage(index); + } + + /** + * Some data on this window has become invalid. + * @param data Information about the changed data. + * -1 Rebuild page list and refresh current page; + * >= 0 Id of the page that needs to be refreshed. If it is not the current page, nothing happens. + * @param gui_scope Whether the call is done from GUI scope. You may not do everything when not in GUI scope. See #InvalidateWindowData() for details. + */ + virtual void OnInvalidateData(int data = 0, bool gui_scope = true) + { + if (!gui_scope) return; + + /* If added/removed page, force rebuild. Sort order never change so just a + * re-sort is never needed. + */ + if (data == -1) { + this->story_pages.ForceRebuild(); + this->BuildStoryPageList(); + + /* Was the last page removed? */ + if (this->story_pages.Length() == 0) { + this->selected_generic_title[0] = '\0'; + } + + /* Verify page selection. */ + if (!_story_page_pool.IsValidID(this->selected_page_id)) { + this->selected_page_id = INVALID_STORY_PAGE; + } + if (this->selected_page_id == INVALID_STORY_PAGE && this->story_pages.Length() > 0) { + /* No page is selected, but there exist at least one available. + * => Select first page. + */ + this->SetSelectedPage(this->story_pages[0]->index); + } + + this->SetWidgetDisabledState(WID_SB_SEL_PAGE, this->story_pages.Length() == 0); + this->SetWidgetDirty(WID_SB_SEL_PAGE); + this->UpdatePrevNextDisabledState(); + } else if (data >= 0 && this->selected_page_id == data) { + this->RefreshSelectedPage(); + } + } +}; + +GUIStoryPageList::SortFunction * const StoryBookWindow::page_sorter_funcs[] = { + &PageOrderSorter, +}; + +GUIStoryPageElementList::SortFunction * const StoryBookWindow::page_element_sorter_funcs[] = { + &PageElementOrderSorter, +}; + +static const NWidgetPart _nested_story_book_widgets[] = { + NWidget(NWID_HORIZONTAL), + NWidget(WWT_CLOSEBOX, COLOUR_BROWN), + NWidget(WWT_CAPTION, COLOUR_BROWN, WID_SB_CAPTION), SetDataTip(STR_STORY_BOOK_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS), + NWidget(WWT_SHADEBOX, COLOUR_BROWN), + NWidget(WWT_DEFSIZEBOX, COLOUR_BROWN), + NWidget(WWT_STICKYBOX, COLOUR_BROWN), + EndContainer(), + NWidget(NWID_HORIZONTAL), SetFill(1, 1), + NWidget(NWID_VERTICAL), SetFill(1, 1), + NWidget(WWT_PANEL, COLOUR_BROWN, WID_SB_PAGE_PANEL), SetResize(1, 1), SetScrollbar(WID_SB_SCROLLBAR), EndContainer(), + NWidget(NWID_HORIZONTAL), + NWidget(WWT_TEXTBTN, COLOUR_BROWN, WID_SB_PREV_PAGE), SetMinimalSize(100, 0), SetFill(0, 0), SetDataTip(STR_STORY_BOOK_PREV_PAGE, STR_STORY_BOOK_PREV_PAGE_TOOLTIP), + NWidget(NWID_BUTTON_DROPDOWN, COLOUR_BROWN, WID_SB_SEL_PAGE), SetMinimalSize(93, 12), SetFill(1, 0), + SetDataTip(STR_BLACK_RAW_STRING, STR_STORY_BOOK_SEL_PAGE_TOOLTIP), SetResize(1, 0), + NWidget(WWT_TEXTBTN, COLOUR_BROWN, WID_SB_NEXT_PAGE), SetMinimalSize(100, 0), SetFill(0, 0), SetDataTip(STR_STORY_BOOK_NEXT_PAGE, STR_STORY_BOOK_NEXT_PAGE_TOOLTIP), + EndContainer(), + EndContainer(), + NWidget(NWID_VERTICAL), SetFill(0, 1), + NWidget(NWID_VSCROLLBAR, COLOUR_BROWN, WID_SB_SCROLLBAR), + NWidget(WWT_RESIZEBOX, COLOUR_BROWN), + EndContainer(), + EndContainer(), +}; + +static WindowDesc _story_book_desc( + WDP_CENTER, "view_story", 400, 300, + WC_STORY_BOOK, WC_NONE, + 0, + _nested_story_book_widgets, lengthof(_nested_story_book_widgets) +); + +void ShowStoryBook() +{ + AllocateWindowDescFront(&_story_book_desc, 0); +} diff --git a/src/table/sprites.h b/src/table/sprites.h index cc24868314..576ffb88c5 100644 --- a/src/table/sprites.h +++ b/src/table/sprites.h @@ -56,7 +56,7 @@ static const SpriteID SPR_LARGE_SMALL_WINDOW = 682; /** Extra graphic spritenumbers */ static const SpriteID SPR_OPENTTD_BASE = 4896; -static const uint16 OPENTTD_SPRITE_COUNT = 169; +static const uint16 OPENTTD_SPRITE_COUNT = 174; /* Halftile-selection sprites */ static const SpriteID SPR_HALFTILE_SELECTION_FLAT = SPR_OPENTTD_BASE; @@ -1088,6 +1088,7 @@ static const SpriteID SPR_IMG_MESSAGES = 680; static const SpriteID SPR_IMG_QUERY = 723; static const SpriteID SPR_IMG_SIGN = 4082; static const SpriteID SPR_IMG_BUY_LAND = 4791; +static const SpriteID SPR_IMG_STORY_BOOK = SPR_OPENTTD_BASE + 169; /* OpenTTD in gamescreen */ static const SpriteID SPR_OTTD_O = 4842; @@ -1317,6 +1318,12 @@ static const SpriteID SPR_IMG_CONVERT_ELRAIL = SPR_OPENTTD_BASE + 59; static const SpriteID SPR_IMG_CONVERT_MONO = SPR_OPENTTD_BASE + 65; static const SpriteID SPR_IMG_CONVERT_MAGLEV = SPR_OPENTTD_BASE + 71; +/* story_gui.cpp */ +static const SpriteID SPR_IMG_VIEW_LOCATION = SPR_OPENTTD_BASE + 170; +static const SpriteID SPR_IMG_GOAL = SPR_OPENTTD_BASE + 171; +static const SpriteID SPR_IMG_GOAL_COMPLETED = SPR_OPENTTD_BASE + 172; +static const SpriteID SPR_IMG_GOAL_BROKEN_REF= SPR_OPENTTD_BASE + 173; + /* intro_gui.cpp, genworld_gui.cpp */ static const SpriteID SPR_SELECT_TEMPERATE = 4882; static const SpriteID SPR_SELECT_TEMPERATE_PUSHED = 4883; diff --git a/src/toolbar_gui.cpp b/src/toolbar_gui.cpp index 7d743d2768..cab5593eb5 100644 --- a/src/toolbar_gui.cpp +++ b/src/toolbar_gui.cpp @@ -642,7 +642,7 @@ static CallBackFunction MenuClickGraphs(int index) static CallBackFunction ToolbarLeagueClick(Window *w) { - PopupMainToolbMenu(w, WID_TN_LEAGUE, STR_GRAPH_MENU_GOAL, _networking ? 3 : 4, Game::GetInstance() != NULL ? 0 : 1); + PopupMainToolbMenu(w, WID_TN_LEAGUE, STR_GRAPH_MENU_GOAL, _networking ? 4 : 5, Game::GetInstance() != NULL ? 0 : 2); return CBF_NONE; } @@ -656,9 +656,10 @@ static CallBackFunction MenuClickLeague(int index) { switch (index) { case 0: ShowGoalsList(); break; - case 1: ShowCompanyLeagueTable(); break; - case 2: ShowPerformanceRatingDetail(); break; - case 3: ShowHighscoreTable(); break; + case 1: ShowStoryBook(); break; + case 2: ShowCompanyLeagueTable(); break; + case 3: ShowPerformanceRatingDetail(); break; + case 4: ShowHighscoreTable(); break; } return CBF_NONE; } diff --git a/src/widgets/story_widget.h b/src/widgets/story_widget.h new file mode 100644 index 0000000000..2c1e749146 --- /dev/null +++ b/src/widgets/story_widget.h @@ -0,0 +1,26 @@ + +/* $Id$ */ + +/* + * This file is part of OpenTTD. + * 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. + * 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. + * 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 . + */ + +/** @file goal_widget.h Types related to the goal widgets. */ + +#ifndef WIDGETS_STORY_WIDGET_H +#define WIDGETS_STORY_WIDGET_H + +/** Widgets of the #GoalListWindow class. */ +enum StoryBookWidgets { + WID_SB_CAPTION, ///< Caption of the window. + WID_SB_SEL_PAGE, ///< Page selector. + WID_SB_PAGE_PANEL,///< Page body. + WID_SB_SCROLLBAR, ///< Scrollbar of the goal list. + WID_SB_PREV_PAGE, ///< Prev button. + WID_SB_NEXT_PAGE, ///< Next button. +}; + +#endif /* WIDGETS_STORY_WIDGET_H */ \ No newline at end of file diff --git a/src/window_type.h b/src/window_type.h index d8365c9025..29fe15dc0e 100644 --- a/src/window_type.h +++ b/src/window_type.h @@ -284,6 +284,11 @@ enum WindowClass { */ WC_GOALS_LIST, + /** + * Story book; %Window numbers: + * - CompanyID = #StoryBookWidgets + */ + WC_STORY_BOOK, /** * Station list; %Window numbers: