Merge commit 'a8b575671894ffe1329ef37dca4989c0e60d70f5'
These merges are becoming more awful every time Conflicts: src/ai/ai_gui.cpp src/build_vehicle_gui.cpp src/cheat_gui.cpp src/company_gui.cpp src/depot_gui.cpp src/dock_gui.cpp src/error_gui.cpp src/genworld_gui.cpp src/misc_gui.cpp src/network/network_content_gui.cpp src/network/network_gui.cpp src/newgrf_gui.cpp src/news_gui.cpp src/rail_gui.cpp src/rev.cpp.in src/road_gui.cpp src/settings_gui.cpp src/settings_gui.h src/signs_gui.cpp src/station_gui.cpp src/table/settings.ini src/terraform_gui.cpp src/toolbar_gui.cpp src/toolbar_gui.h src/vehicle_gui.cpp src/video/sdl_v.cpp src/viewport.cpp src/widget.cpp src/widgets/settings_widget.h
This commit is contained in:
@@ -30,6 +30,8 @@
|
||||
#include "table/strings.h"
|
||||
#include "../table/sprites.h"
|
||||
|
||||
#include <bitset>
|
||||
|
||||
#include "../safeguards.h"
|
||||
|
||||
|
||||
@@ -283,10 +285,22 @@ public:
|
||||
}
|
||||
};
|
||||
|
||||
/** Filter data for NetworkContentListWindow. */
|
||||
struct ContentListFilterData {
|
||||
StringFilter string_filter; ///< Text filter of content list
|
||||
std::bitset<CONTENT_TYPE_END> types; ///< Content types displayed
|
||||
};
|
||||
|
||||
/** Filter criterias for NetworkContentListWindow. */
|
||||
enum ContentListFilterCriteria {
|
||||
CONTENT_FILTER_TEXT = 0, ///< Filter by query sting
|
||||
CONTENT_FILTER_TYPE_OR_SELECTED,///< Filter by being of displayed type or selected for download
|
||||
};
|
||||
|
||||
/** Window that lists the content that's at the content server */
|
||||
class NetworkContentListWindow : public Window, ContentCallback {
|
||||
/** List with content infos. */
|
||||
typedef GUIList<const ContentInfo *, StringFilter &> GUIContentList;
|
||||
typedef GUIList<const ContentInfo *, ContentListFilterData &> GUIContentList;
|
||||
|
||||
static const uint EDITBOX_MAX_SIZE = 50; ///< Maximum size of the editbox in characters.
|
||||
|
||||
@@ -296,14 +310,17 @@ class NetworkContentListWindow : public Window, ContentCallback {
|
||||
static GUIContentList::FilterFunction * const filter_funcs[]; ///< Filter functions.
|
||||
GUIContentList content; ///< List with content
|
||||
bool auto_select; ///< Automatically select all content when the meta-data becomes available
|
||||
StringFilter string_filter; ///< Filter for content list
|
||||
ContentListFilterData filter_data; ///< Filter for content list
|
||||
QueryString filter_editbox; ///< Filter editbox;
|
||||
Dimension checkbox_size; ///< Size of checkbox/"blot" sprite
|
||||
|
||||
const ContentInfo *selected; ///< The selected content info
|
||||
int list_pos; ///< Our position in the list
|
||||
uint filesize_sum; ///< The sum of all selected file sizes
|
||||
Scrollbar *vscroll; ///< Cache of the vertical scrollbar
|
||||
|
||||
static char content_type_strs[CONTENT_TYPE_END][64]; ///< Cached strings for all content types.
|
||||
|
||||
/** Search external websites for content */
|
||||
void OpenExternalSearch()
|
||||
{
|
||||
@@ -401,11 +418,7 @@ class NetworkContentListWindow : public Window, ContentCallback {
|
||||
{
|
||||
int r = 0;
|
||||
if ((*a)->type != (*b)->type) {
|
||||
char a_str[64];
|
||||
char b_str[64];
|
||||
GetString(a_str, STR_CONTENT_TYPE_BASE_GRAPHICS + (*a)->type - CONTENT_TYPE_BASE_GRAPHICS, lastof(a_str));
|
||||
GetString(b_str, STR_CONTENT_TYPE_BASE_GRAPHICS + (*b)->type - CONTENT_TYPE_BASE_GRAPHICS, lastof(b_str));
|
||||
r = strnatcmp(a_str, b_str);
|
||||
r = strnatcmp(content_type_strs[(*a)->type], content_type_strs[(*b)->type]);
|
||||
}
|
||||
if (r == 0) r = NameSorter(a, b);
|
||||
return r;
|
||||
@@ -433,20 +446,38 @@ class NetworkContentListWindow : public Window, ContentCallback {
|
||||
}
|
||||
|
||||
/** Filter content by tags/name */
|
||||
static bool CDECL TagNameFilter(const ContentInfo * const *a, StringFilter &filter)
|
||||
static bool CDECL TagNameFilter(const ContentInfo * const *a, ContentListFilterData &filter)
|
||||
{
|
||||
filter.ResetState();
|
||||
filter.string_filter.ResetState();
|
||||
for (int i = 0; i < (*a)->tag_count; i++) {
|
||||
filter.AddLine((*a)->tags[i]);
|
||||
filter.string_filter.AddLine((*a)->tags[i]);
|
||||
}
|
||||
filter.AddLine((*a)->name);
|
||||
return filter.GetState();
|
||||
filter.string_filter.AddLine((*a)->name);
|
||||
return filter.string_filter.GetState();
|
||||
}
|
||||
|
||||
/** Filter content by type, but still show content selected for download. */
|
||||
static bool CDECL TypeOrSelectedFilter(const ContentInfo * const *a, ContentListFilterData &filter)
|
||||
{
|
||||
if (filter.types.none()) return true;
|
||||
if (filter.types[(*a)->type]) return true;
|
||||
return ((*a)->state == ContentInfo::SELECTED || (*a)->state == ContentInfo::AUTOSELECTED);
|
||||
}
|
||||
|
||||
/** Filter the content list */
|
||||
void FilterContentList()
|
||||
{
|
||||
if (!this->content.Filter(this->string_filter)) return;
|
||||
/* Apply filters. */
|
||||
bool changed = false;
|
||||
if (!this->filter_data.string_filter.IsEmpty()) {
|
||||
this->content.SetFilterType(CONTENT_FILTER_TEXT);
|
||||
changed |= this->content.Filter(this->filter_data);
|
||||
}
|
||||
if (this->filter_data.types.any()) {
|
||||
this->content.SetFilterType(CONTENT_FILTER_TYPE_OR_SELECTED);
|
||||
changed |= this->content.Filter(this->filter_data);
|
||||
}
|
||||
if (!changed) return;
|
||||
|
||||
/* update list position */
|
||||
for (ConstContentIterator iter = this->content.Begin(); iter != this->content.End(); iter++) {
|
||||
@@ -461,6 +492,20 @@ class NetworkContentListWindow : public Window, ContentCallback {
|
||||
this->list_pos = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update filter state based on current window state.
|
||||
* @return true if filter state was changed, otherwise false.
|
||||
*/
|
||||
bool UpdateFilterState()
|
||||
{
|
||||
Filtering old_params = this->content.GetFiltering();
|
||||
bool new_state = !this->filter_data.string_filter.IsEmpty() || this->filter_data.types.any();
|
||||
if (new_state != old_params.state) {
|
||||
this->content.SetFilterState(new_state);
|
||||
}
|
||||
return new_state != old_params.state;
|
||||
}
|
||||
|
||||
/** Make sure that the currently selected content info is within the visible part of the matrix */
|
||||
void ScrollToSelected()
|
||||
{
|
||||
@@ -469,19 +514,26 @@ class NetworkContentListWindow : public Window, ContentCallback {
|
||||
this->vscroll->ScrollTowards(this->list_pos);
|
||||
}
|
||||
|
||||
friend void BuildContentTypeStringList();
|
||||
public:
|
||||
/**
|
||||
* Create the content list window.
|
||||
* @param desc the window description to pass to Window's constructor.
|
||||
* @param select_all Whether the select all button is allowed or not.
|
||||
* @param type the main type of content to display or #CONTENT_TYPE_END.
|
||||
* When a type other than #CONTENT_TYPE_END is given, dependencies of
|
||||
* other types are only shown when content that depend on them are
|
||||
* selected.
|
||||
*/
|
||||
NetworkContentListWindow(WindowDesc *desc, bool select_all) :
|
||||
NetworkContentListWindow(WindowDesc *desc, bool select_all, const std::bitset<CONTENT_TYPE_END> &types) :
|
||||
Window(desc),
|
||||
auto_select(select_all),
|
||||
filter_editbox(EDITBOX_MAX_SIZE),
|
||||
selected(NULL),
|
||||
list_pos(0)
|
||||
{
|
||||
this->checkbox_size = maxdim(maxdim(GetSpriteSize(SPR_BOX_EMPTY), GetSpriteSize(SPR_BOX_CHECKED)), GetSpriteSize(SPR_BLOT));
|
||||
|
||||
this->CreateNestedTree();
|
||||
this->vscroll = this->GetScrollbar(WID_NCL_SCROLLBAR);
|
||||
this->FinishInitNested(WN_NETWORK_WINDOW_CONTENT_LIST);
|
||||
@@ -492,12 +544,14 @@ public:
|
||||
this->filter_editbox.cancel_button = QueryString::ACTION_CLEAR;
|
||||
this->SetFocusedWidget(WID_NCL_FILTER);
|
||||
this->SetWidgetDisabledState(WID_NCL_SEARCH_EXTERNAL, this->auto_select);
|
||||
this->filter_data.types = types;
|
||||
|
||||
_network_content_client.AddCallback(this);
|
||||
this->content.SetListing(this->last_sorting);
|
||||
this->content.SetFiltering(this->last_filtering);
|
||||
this->content.SetSortFuncs(this->sorter_funcs);
|
||||
this->content.SetFilterFuncs(this->filter_funcs);
|
||||
this->UpdateFilterState();
|
||||
this->content.ForceRebuild();
|
||||
this->FilterContentList();
|
||||
this->SortContentList();
|
||||
@@ -517,6 +571,10 @@ public:
|
||||
*size = maxdim(*size, GetStringBoundingBox(STR_CONTENT_FILTER_TITLE));
|
||||
break;
|
||||
|
||||
case WID_NCL_CHECKBOX:
|
||||
size->width = this->checkbox_size.width + WD_MATRIX_RIGHT + WD_MATRIX_LEFT;
|
||||
break;
|
||||
|
||||
case WID_NCL_TYPE: {
|
||||
Dimension d = *size;
|
||||
for (int i = CONTENT_TYPE_BEGIN; i < CONTENT_TYPE_END; i++) {
|
||||
@@ -527,7 +585,7 @@ public:
|
||||
}
|
||||
|
||||
case WID_NCL_MATRIX:
|
||||
resize->height = GetMinSizing(NWST_STEP, FONT_HEIGHT_NORMAL + WD_MATRIX_TOP + WD_MATRIX_BOTTOM);
|
||||
resize->height = GetMinSizing(NWST_STEP, max(this->checkbox_size.height, (uint)FONT_HEIGHT_NORMAL) + WD_MATRIX_TOP + WD_MATRIX_BOTTOM);
|
||||
size->height = 6 * resize->height;
|
||||
break;
|
||||
}
|
||||
@@ -578,9 +636,11 @@ public:
|
||||
const NWidgetBase *nwi_name = this->GetWidget<NWidgetBase>(WID_NCL_NAME);
|
||||
const NWidgetBase *nwi_type = this->GetWidget<NWidgetBase>(WID_NCL_TYPE);
|
||||
|
||||
int line_height = max(this->checkbox_size.height, (uint)FONT_HEIGHT_NORMAL);
|
||||
|
||||
/* Fill the matrix with the information */
|
||||
Dimension sprite_dim = GetSpriteSize(SPR_BOX_EMPTY);
|
||||
int sprite_y_offset = WD_MATRIX_TOP + (line_height - this->checkbox_size.height) / 2 - 1;
|
||||
int text_y_offset = WD_MATRIX_TOP + (line_height - FONT_HEIGHT_NORMAL) / 2;
|
||||
uint y = r.top;
|
||||
int cnt = 0;
|
||||
for (ConstContentIterator iter = this->content.Get(this->vscroll->GetPosition()); iter != this->content.End() && cnt < this->vscroll->GetCapacity(); iter++, cnt++) {
|
||||
@@ -602,9 +662,9 @@ public:
|
||||
DrawSprite(sprite, pal, Center(nwi_checkbox->pos_x + (pal == PAL_NONE ? 2 : 3), nwi_checkbox->current_x, sprite_dim.width), Center(y, this->resize.step_height, sprite_dim.height + (pal == PAL_NONE ? 0 : -2)));
|
||||
|
||||
StringID str = STR_CONTENT_TYPE_BASE_GRAPHICS + ci->type - CONTENT_TYPE_BASE_GRAPHICS;
|
||||
DrawString(nwi_type->pos_x, nwi_type->pos_x + nwi_type->current_x - 1, Center(y, this->resize.step_height), str, TC_BLACK, SA_HOR_CENTER);
|
||||
DrawString(nwi_type->pos_x, nwi_type->pos_x + nwi_type->current_x - 1, y + text_y_offset, str, TC_BLACK, SA_HOR_CENTER);
|
||||
|
||||
DrawString(nwi_name->pos_x + WD_FRAMERECT_LEFT, nwi_name->pos_x + nwi_name->current_x - WD_FRAMERECT_RIGHT, Center(y,this->resize.step_height), ci->name, TC_BLACK);
|
||||
DrawString(nwi_name->pos_x + WD_FRAMERECT_LEFT, nwi_name->pos_x + nwi_name->current_x - WD_FRAMERECT_RIGHT, y + text_y_offset, ci->name, TC_BLACK);
|
||||
y += this->resize.step_height;
|
||||
}
|
||||
}
|
||||
@@ -745,6 +805,10 @@ public:
|
||||
this->content.ForceResort();
|
||||
}
|
||||
|
||||
if (this->filter_data.types.any()) {
|
||||
this->content.ForceRebuild();
|
||||
}
|
||||
|
||||
this->InvalidateData();
|
||||
break;
|
||||
}
|
||||
@@ -840,9 +904,13 @@ public:
|
||||
this->content.ForceResort();
|
||||
this->InvalidateData();
|
||||
}
|
||||
if (this->filter_data.types.any()) {
|
||||
this->content.ForceRebuild();
|
||||
this->InvalidateData();
|
||||
}
|
||||
return ES_HANDLED;
|
||||
}
|
||||
/* FALL THROUGH, space is pressed and filter isn't focused. */
|
||||
/* FALL THROUGH, space is pressed and filter is focused. */
|
||||
|
||||
default:
|
||||
return ES_NOT_HANDLED;
|
||||
@@ -850,13 +918,21 @@ public:
|
||||
|
||||
if (this->content.Length() == 0) {
|
||||
this->list_pos = 0; // above stuff may result in "-1".
|
||||
if (this->UpdateFilterState()) {
|
||||
this->content.ForceRebuild();
|
||||
this->InvalidateData();
|
||||
}
|
||||
return ES_HANDLED;
|
||||
}
|
||||
|
||||
this->selected = *this->content.Get(this->list_pos);
|
||||
|
||||
/* scroll to the new server if it is outside the current range */
|
||||
this->ScrollToSelected();
|
||||
if (this->UpdateFilterState()) {
|
||||
this->content.ForceRebuild();
|
||||
} else {
|
||||
/* Scroll to the new content if it is outside the current range. */
|
||||
this->ScrollToSelected();
|
||||
}
|
||||
|
||||
/* redraw window */
|
||||
this->InvalidateData();
|
||||
@@ -866,8 +942,8 @@ public:
|
||||
virtual void OnEditboxChanged(int wid)
|
||||
{
|
||||
if (wid == WID_NCL_FILTER) {
|
||||
this->string_filter.SetFilterTerm(this->filter_editbox.text.buf);
|
||||
this->content.SetFilterState(!this->string_filter.IsEmpty());
|
||||
this->filter_data.string_filter.SetFilterTerm(this->filter_editbox.text.buf);
|
||||
this->UpdateFilterState();
|
||||
this->content.ForceRebuild();
|
||||
this->InvalidateData();
|
||||
}
|
||||
@@ -959,8 +1035,21 @@ NetworkContentListWindow::GUIContentList::SortFunction * const NetworkContentLis
|
||||
|
||||
NetworkContentListWindow::GUIContentList::FilterFunction * const NetworkContentListWindow::filter_funcs[] = {
|
||||
&TagNameFilter,
|
||||
&TypeOrSelectedFilter,
|
||||
};
|
||||
|
||||
char NetworkContentListWindow::content_type_strs[CONTENT_TYPE_END][64];
|
||||
|
||||
/**
|
||||
* Build array of all strings corresponding to the content types.
|
||||
*/
|
||||
void BuildContentTypeStringList()
|
||||
{
|
||||
for (int i = CONTENT_TYPE_BEGIN; i < CONTENT_TYPE_END; i++) {
|
||||
GetString(NetworkContentListWindow::content_type_strs[i], STR_CONTENT_TYPE_BASE_GRAPHICS + i - CONTENT_TYPE_BASE_GRAPHICS, lastof(NetworkContentListWindow::content_type_strs[i]));
|
||||
}
|
||||
}
|
||||
|
||||
/** The widgets for the content list. */
|
||||
static const NWidgetPart _nested_network_content_list_widgets[] = {
|
||||
NWidget(NWID_HORIZONTAL),
|
||||
@@ -1049,20 +1138,29 @@ static WindowDesc _network_content_list_desc(
|
||||
/**
|
||||
* Show the content list window with a given set of content
|
||||
* @param cv the content to show, or NULL when it has to search for itself
|
||||
* @param type the type to (only) show
|
||||
* @param type1 the first type to (only) show or #CONTENT_TYPE_END to show all.
|
||||
* @param type2 the second type to (only) show in addition to type1. If type2 is != #CONTENT_TYPE_END, then also type1 should be != #CONTENT_TYPE_END.
|
||||
* If type2 != #CONTENT_TYPE_END, then type1 != type2 must be true.
|
||||
*/
|
||||
void ShowNetworkContentListWindow(ContentVector *cv, ContentType type)
|
||||
void ShowNetworkContentListWindow(ContentVector *cv, ContentType type1, ContentType type2)
|
||||
{
|
||||
#if defined(WITH_ZLIB)
|
||||
std::bitset<CONTENT_TYPE_END> types;
|
||||
_network_content_client.Clear();
|
||||
if (cv == NULL) {
|
||||
_network_content_client.RequestContentList(type);
|
||||
assert(type1 != CONTENT_TYPE_END || type2 == CONTENT_TYPE_END);
|
||||
assert(type1 == CONTENT_TYPE_END || type1 != type2);
|
||||
_network_content_client.RequestContentList(type1);
|
||||
if (type2 != CONTENT_TYPE_END) _network_content_client.RequestContentList(type2);
|
||||
|
||||
if (type1 != CONTENT_TYPE_END) types[type1] = true;
|
||||
if (type2 != CONTENT_TYPE_END) types[type2] = true;
|
||||
} else {
|
||||
_network_content_client.RequestContentList(cv, true);
|
||||
}
|
||||
|
||||
DeleteWindowById(WC_NETWORK_WINDOW, WN_NETWORK_WINDOW_CONTENT_LIST);
|
||||
new NetworkContentListWindow(&_network_content_list_desc, cv != NULL);
|
||||
new NetworkContentListWindow(&_network_content_list_desc, cv != NULL, types);
|
||||
#else
|
||||
ShowErrorMessage(STR_CONTENT_NO_ZLIB, STR_CONTENT_NO_ZLIB_SUB, WL_ERROR);
|
||||
/* Connection failed... clean up the mess */
|
||||
|
||||
Reference in New Issue
Block a user