Merge remote-tracking branch 'upstream/master'

This commit is contained in:
dP
2024-02-04 22:50:08 +05:30
1358 changed files with 138991 additions and 72904 deletions
+56 -60
View File
@@ -10,7 +10,6 @@
#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"
@@ -32,8 +31,6 @@
#include "table/strings.h"
#include "table/sprites.h"
#include <numeric>
#include "citymania/cm_hotkeys.hpp"
#include "safeguards.h"
@@ -63,7 +60,7 @@ protected:
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.
std::string selected_generic_title; ///< If the selected page doesn't have a custom title, this buffer is used to store a generic page title.
StoryPageElementID active_button_id; ///< Which button element the player is currently using
@@ -191,9 +188,9 @@ protected:
{
/* Generate generic title if selected page have no custom title. */
StoryPage *page = this->GetSelPage();
if (page != nullptr && page->title == nullptr) {
if (page != nullptr && page->title.empty()) {
SetDParam(0, GetSelPageNum() + 1);
GetString(selected_generic_title, STR_STORY_BOOK_GENERIC_PAGE_ITEM, lastof(selected_generic_title));
selected_generic_title = GetString(STR_STORY_BOOK_GENERIC_PAGE_ITEM);
}
this->story_page_elements.ForceRebuild();
@@ -254,21 +251,16 @@ protected:
DropDownList BuildDropDownList() const
{
DropDownList list;
uint16 page_num = 1;
uint16_t page_num = 1;
for (const StoryPage *p : this->story_pages) {
bool current_page = p->index == this->selected_page_id;
DropDownListStringItem *item = nullptr;
if (p->title != nullptr) {
item = new DropDownListCharStringItem(p->title, p->index, current_page);
if (!p->title.empty()) {
list.push_back(std::make_unique<DropDownListStringItem>(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;
SetDParam(0, page_num);
list.push_back(std::make_unique<DropDownListStringItem>(STR_STORY_BOOK_GENERIC_PAGE_ITEM, p->index, current_page));
}
list.emplace_back(item);
page_num++;
}
@@ -297,8 +289,8 @@ protected:
int height = 0;
/* Title lines */
height += FONT_HEIGHT_NORMAL; // Date always use exactly one line.
SetDParamStr(0, page->title != nullptr ? page->title : this->selected_generic_title);
height += GetCharacterHeight(FS_NORMAL); // Date always use exactly one line.
SetDParamStr(0, !page->title.empty() ? page->title : this->selected_generic_title);
height += GetStringHeight(STR_STORY_BOOK_TITLE, max_width);
return height;
@@ -336,7 +328,7 @@ protected:
switch (pe.type) {
case SPET_TEXT:
SetDParamStr(0, pe.text);
return GetStringHeight(STR_BLACK_RAW_STRING, max_width);
return GetStringHeight(STR_JUST_RAW_STRING, max_width);
case SPET_GOAL:
case SPET_LOCATION: {
@@ -414,7 +406,7 @@ protected:
StoryPage *page = this->GetSelPage();
if (page == nullptr) return;
int max_width = GetAvailablePageContentWidth();
int element_dist = FONT_HEIGHT_NORMAL;
int element_dist = GetCharacterHeight(FS_NORMAL);
/* Make space for the header */
int main_y = GetHeadHeight(max_width) + element_dist;
@@ -435,7 +427,7 @@ protected:
if (fl == ElementFloat::None) {
/* Verify available width */
const int min_required_width = 10 * FONT_HEIGHT_NORMAL;
const int min_required_width = 10 * GetCharacterHeight(FS_NORMAL);
int left_offset = (left_width == 0) ? 0 : (left_width + element_dist);
int right_offset = (right_width == 0) ? 0 : (right_width + element_dist);
if (left_offset + right_offset + min_required_width >= max_width) {
@@ -544,7 +536,7 @@ protected:
* Internal event handler for when a page element is clicked.
* @param pe The clicked page element.
*/
void OnPageElementClick(const StoryPageElement& pe)
void OnPageElementClick(const StoryPageElement &pe)
{
switch (pe.type) {
case SPET_TEXT:
@@ -606,7 +598,7 @@ public:
{
this->CreateNestedTree();
this->vscroll = this->GetScrollbar(WID_SB_SCROLLBAR);
this->vscroll->SetStepSize(FONT_HEIGHT_NORMAL);
this->vscroll->SetStepSize(GetCharacterHeight(FS_NORMAL));
/* Initialize page sort. */
this->story_pages.SetSortFuncs(StoryBookWindow::page_sorter_funcs);
@@ -619,7 +611,7 @@ public:
this->owner = (Owner)this->window_number;
/* Initialize selected vars. */
this->selected_generic_title[0] = '\0';
this->selected_generic_title.clear();
this->selected_page_id = INVALID_STORY_PAGE;
this->active_button_id = INVALID_STORY_PAGE_ELEMENT;
@@ -632,8 +624,8 @@ public:
*/
void UpdatePrevNextDisabledState()
{
this->SetWidgetDisabledState(WID_SB_PREV_PAGE, story_pages.size() == 0 || this->IsFirstPageSelected());
this->SetWidgetDisabledState(WID_SB_NEXT_PAGE, story_pages.size() == 0 || this->IsLastPageSelected());
this->SetWidgetDisabledState(WID_SB_PREV_PAGE, story_pages.empty() || this->IsFirstPageSelected());
this->SetWidgetDisabledState(WID_SB_NEXT_PAGE, story_pages.empty() || this->IsLastPageSelected());
this->SetWidgetDirty(WID_SB_PREV_PAGE);
this->SetWidgetDirty(WID_SB_NEXT_PAGE);
}
@@ -642,7 +634,7 @@ public:
* Sets the selected page.
* @param page_index pool index of the page to select.
*/
void SetSelectedPage(uint16 page_index)
void SetSelectedPage(uint16_t page_index)
{
if (this->selected_page_id != page_index) {
if (this->active_button_id) ResetObjectToPlace();
@@ -653,12 +645,12 @@ public:
}
}
void SetStringParameters(int widget) const override
void SetStringParameters(WidgetID widget) const override
{
switch (widget) {
case WID_SB_SEL_PAGE: {
StoryPage *page = this->GetSelPage();
SetDParamStr(0, page != nullptr && page->title != nullptr ? page->title : this->selected_generic_title);
SetDParamStr(0, page != nullptr && !page->title.empty() ? page->title : this->selected_generic_title);
break;
}
case WID_SB_CAPTION:
@@ -687,7 +679,7 @@ public:
this->DrawWidgets();
}
void DrawWidget(const Rect &r, int widget) const override
void DrawWidget(const Rect &r, WidgetID widget) const override
{
if (widget != WID_SB_PAGE_PANEL) return;
@@ -698,26 +690,25 @@ public:
/* Set up a clipping region for the panel. */
DrawPixelInfo tmp_dpi;
if (!FillDrawPixelInfo(&tmp_dpi, fr.left, fr.top, fr.Width(), fr.Height())) return;
if (!FillDrawPixelInfo(&tmp_dpi, fr)) return;
DrawPixelInfo *old_dpi = _cur_dpi;
_cur_dpi = &tmp_dpi;
AutoRestoreBackup dpi_backup(_cur_dpi, &tmp_dpi);
/* Draw content (now coordinates given to Draw** are local to the new clipping region). */
fr = fr.Translate(-fr.left, -fr.top);
int line_height = FONT_HEIGHT_NORMAL;
int line_height = GetCharacterHeight(FS_NORMAL);
const int scrollpos = this->vscroll->GetPosition();
int y_offset = -scrollpos;
/* Date */
if (page->date != INVALID_DATE) {
if (page->date != CalendarTime::INVALID_DATE) {
SetDParam(0, page->date);
DrawString(0, fr.right, y_offset, STR_JUST_DATE_LONG, TC_BLACK);
}
y_offset += line_height;
/* Title */
SetDParamStr(0, page->title != nullptr ? page->title : this->selected_generic_title);
SetDParamStr(0, !page->title.empty() ? page->title : this->selected_generic_title);
y_offset = DrawStringMultiLine(0, fr.right, y_offset, fr.bottom, STR_STORY_BOOK_TITLE, TC_BLACK, SA_TOP | SA_HOR_CENTER);
/* Page elements */
@@ -760,17 +751,14 @@ public:
default: NOT_REACHED();
}
}
/* Restore clipping region. */
_cur_dpi = old_dpi;
}
void UpdateWidgetSize(int widget, Dimension *size, const Dimension &padding, Dimension *fill, Dimension *resize) override
void UpdateWidgetSize(WidgetID widget, Dimension *size, [[maybe_unused]] const Dimension &padding, [[maybe_unused]] Dimension *fill, [[maybe_unused]] Dimension *resize) override
{
if (widget != WID_SB_SEL_PAGE && widget != WID_SB_PAGE_PANEL) return;
Dimension d;
d.height = FONT_HEIGHT_NORMAL;
d.height = GetCharacterHeight(FS_NORMAL);
d.width = 0;
switch (widget) {
@@ -780,12 +768,12 @@ public:
for (size_t i = 0; i < this->story_pages.size(); i++) {
const StoryPage *s = this->story_pages[i];
if (s->title != nullptr) {
if (!s->title.empty()) {
SetDParamStr(0, s->title);
} else {
SetDParamStr(0, this->selected_generic_title);
}
Dimension title_d = GetStringBoundingBox(STR_BLACK_RAW_STRING);
Dimension title_d = GetStringBoundingBox(STR_JUST_RAW_STRING);
if (title_d.width > d.width) {
d.width = title_d.width;
@@ -815,7 +803,7 @@ public:
this->vscroll->SetCount(this->GetContentHeight());
}
void OnClick(Point pt, int widget, int click_count) override
void OnClick([[maybe_unused]] Point pt, WidgetID widget, [[maybe_unused]] int click_count) override
{
switch (widget) {
case WID_SB_SEL_PAGE: {
@@ -856,7 +844,7 @@ public:
}
}
void OnDropdownSelect(int widget, int index) override
void OnDropdownSelect(WidgetID widget, int index) override
{
if (widget != WID_SB_SEL_PAGE) return;
@@ -871,7 +859,7 @@ public:
* >= 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.
*/
void OnInvalidateData(int data = 0, bool gui_scope = true) override
void OnInvalidateData([[maybe_unused]] int data = 0, [[maybe_unused]] bool gui_scope = true) override
{
if (!gui_scope) return;
@@ -883,22 +871,22 @@ public:
this->BuildStoryPageList();
/* Was the last page removed? */
if (this->story_pages.size() == 0) {
this->selected_generic_title[0] = '\0';
if (this->story_pages.empty()) {
this->selected_generic_title.clear();
}
/* 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.size() > 0) {
if (this->selected_page_id == INVALID_STORY_PAGE && !this->story_pages.empty()) {
/* 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.size() == 0);
this->SetWidgetDisabledState(WID_SB_SEL_PAGE, this->story_pages.empty());
this->SetWidgetDirty(WID_SB_SEL_PAGE);
this->UpdatePrevNextDisabledState();
} else if (data >= 0 && this->selected_page_id == data) {
@@ -912,7 +900,7 @@ public:
this->SetWidgetDirty(WID_SB_PAGE_PANEL);
}
void OnPlaceObject(Point pt, TileIndex tile) override
void OnPlaceObject([[maybe_unused]] Point pt, TileIndex tile) override
{
const StoryPageElement *const pe = StoryPageElement::GetIfValid(this->active_button_id);
if (pe == nullptr || pe->type != SPET_BUTTON_TILE) {
@@ -961,32 +949,39 @@ GUIStoryPageElementList::SortFunction * const StoryBookWindow::page_element_sort
&PageElementOrderSorter,
};
static const NWidgetPart _nested_story_book_widgets[] = {
static constexpr NWidgetPart _nested_story_book_widgets[] = {
NWidget(NWID_HORIZONTAL),
NWidget(WWT_CLOSEBOX, COLOUR_BROWN),
NWidget(WWT_CAPTION, COLOUR_BROWN, WID_SB_CAPTION), SetDataTip(STR_JUST_STRING, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
NWidget(WWT_CAPTION, COLOUR_BROWN, WID_SB_CAPTION), SetDataTip(STR_JUST_STRING1, 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_HORIZONTAL),
NWidget(WWT_PANEL, COLOUR_BROWN, WID_SB_PAGE_PANEL), SetResize(1, 1), SetScrollbar(WID_SB_SCROLLBAR), EndContainer(),
NWidget(NWID_VSCROLLBAR, COLOUR_BROWN, 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),
SetDataTip(STR_JUST_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),
NWidget(WWT_RESIZEBOX, COLOUR_BROWN),
EndContainer(),
};
static WindowDesc _story_book_desc(
WDP_CENTER, "view_story", 400, 300,
static WindowDesc _story_book_desc(__FILE__, __LINE__,
WDP_AUTO, "view_story", 400, 300,
WC_STORY_BOOK, WC_NONE,
0,
_nested_story_book_widgets, lengthof(_nested_story_book_widgets)
std::begin(_nested_story_book_widgets), std::end(_nested_story_book_widgets)
);
static WindowDesc _story_book_gs_desc(__FILE__, __LINE__,
WDP_CENTER, "view_story_gs", 400, 300,
WC_STORY_BOOK, WC_NONE,
0,
std::begin(_nested_story_book_widgets), std::end(_nested_story_book_widgets)
);
static CursorID TranslateStoryPageButtonCursor(StoryPageButtonCursor cursor)
@@ -1055,11 +1050,12 @@ static CursorID TranslateStoryPageButtonCursor(StoryPageButtonCursor cursor)
* Raise or create the story book window for \a company, at page \a page_id.
* @param company 'Owner' of the story book, may be #INVALID_COMPANY.
* @param page_id Page to open, may be #INVALID_STORY_PAGE.
* @param centered Whether to open the window centered.
*/
void ShowStoryBook(CompanyID company, uint16 page_id)
void ShowStoryBook(CompanyID company, uint16_t page_id, bool centered)
{
if (!Company::IsValidID(company)) company = (CompanyID)INVALID_COMPANY;
StoryBookWindow *w = AllocateWindowDescFront<StoryBookWindow>(&_story_book_desc, company, true);
StoryBookWindow *w = AllocateWindowDescFront<StoryBookWindow>(centered ? &_story_book_gs_desc : &_story_book_desc, company, true);
if (page_id != INVALID_STORY_PAGE) w->SetSelectedPage(page_id);
}