From c346f249cd30329dde69a84e3de5915a91921eca Mon Sep 17 00:00:00 2001 From: rubidium Date: Fri, 6 Feb 2009 12:00:14 +0000 Subject: [PATCH] (svn r15372) -Feature: filter the 'content' based on the tag/name. Based on a patch by Roujin. --- src/lang/english.txt | 3 + src/network/network_content_gui.cpp | 117 +++++++++++++++++++++++----- 2 files changed, 99 insertions(+), 21 deletions(-) diff --git a/src/lang/english.txt b/src/lang/english.txt index a506474d89..30eca93cd2 100644 --- a/src/lang/english.txt +++ b/src/lang/english.txt @@ -3763,6 +3763,9 @@ STR_CONTENT_SELECT_UPDATES_CAPTION :{BLACK}Select u STR_CONTENT_SELECT_UPDATES_CAPTION_TIP :{BLACK}Mark all content that is an upgrade for existing content to be downloaded STR_CONTENT_UNSELECT_ALL_CAPTION :{BLACK}Unselect all STR_CONTENT_UNSELECT_ALL_CAPTION_TIP :{BLACK}Mark all content to be not downloaded +STR_CONTENT_FILTER_OSKTITLE :{BLACK}Enter filter string +STR_CONTENT_FILTER_TIP :{BLACK}Enter a keyword to filter the list for +STR_CONTENT_FILTER_TITLE :{BLACK}Tag/name filter: STR_CONTENT_DOWNLOAD_CAPTION :{BLACK}Download STR_CONTENT_DOWNLOAD_CAPTION_TIP :{BLACK}Start downloading the selected content STR_CONTENT_TOTAL_DOWNLOAD_SIZE :{SILVER}Total download size: {WHITE}{BYTES} diff --git a/src/network/network_content_gui.cpp b/src/network/network_content_gui.cpp index 633db8687c..5ae37eca1c 100644 --- a/src/network/network_content_gui.cpp +++ b/src/network/network_content_gui.cpp @@ -13,6 +13,7 @@ #include "../ai/ai.hpp" #include "../gfxinit.h" #include "../sortlist_type.h" +#include "../querystring_gui.h" #include "network_content.h" #include "table/strings.h" @@ -157,7 +158,7 @@ public: }; /** Window that lists the content that's at the content server */ -class NetworkContentListWindow : public Window, ContentCallback { +class NetworkContentListWindow : public QueryStringBaseWindow, ContentCallback { typedef GUIList GUIContentList; /** All widgets used */ @@ -166,6 +167,8 @@ class NetworkContentListWindow : public Window, ContentCallback { NCLWW_CAPTION, ///< Caption of the window NCLWW_BACKGROUND, ///< Resize button + NCLWW_FILTER, ///< Filter editbox + NCLWW_CHECKBOX, ///< Button above checkboxes NCLWW_TYPE, ///< 'Type' button NCLWW_NAME, ///< 'Name' button @@ -184,10 +187,17 @@ class NetworkContentListWindow : public Window, ContentCallback { NCLWW_RESIZE, ///< Resize button }; + enum { + EDITBOX_MAX_SIZE = 50, + EDITBOX_MAX_LENGTH = 300, + }; + /** Runtime saved values */ static Listing last_sorting; + static Filtering last_filtering; /** The sorter functions */ static GUIContentList::SortFunction * const sorter_funcs[]; + static GUIContentList::FilterFunction * const filter_funcs[]; GUIContentList content; ///< List with content const ContentInfo *selected; ///< The selected content info @@ -208,6 +218,7 @@ class NetworkContentListWindow : public Window, ContentCallback { *this->content.Append() = *iter; } + this->FilterContentList(); this->content.Compact(); this->content.RebuildDone(); } @@ -254,6 +265,31 @@ class NetworkContentListWindow : public Window, ContentCallback { } } + /** Filter content by tags/name */ + static bool CDECL TagNameFilter(const ContentInfo * const *a, const char *filter_string) + { + for (int i = 0; i < (*a)->tag_count; i++) { + if (strcasestr((*a)->tags[i], filter_string) != NULL) return true; + } + return strcasestr((*a)->name, filter_string) != NULL; + } + + /** Filter the content list */ + void FilterContentList() + { + if (!this->content.Filter(this->edit_str_buf)) return; + + this->selected = NULL; + this->list_pos = 0; + + for (ConstContentIterator iter = this->content.Begin(); iter != this->content.End(); iter++) { + if (*iter == this->selected) { + this->list_pos = iter - this->content.Begin(); + break; + } + } + } + /** Make sure that the currently selected content info is within the visible part of the matrix */ void ScrollToSelected() { @@ -273,8 +309,12 @@ public: * Create the content list window. * @param desc the window description to pass to Window's constructor. */ - NetworkContentListWindow(const WindowDesc *desc, bool select_all) : Window(desc, 1), selected(NULL), list_pos(0) + NetworkContentListWindow(const WindowDesc *desc, bool select_all) : QueryStringBaseWindow(EDITBOX_MAX_SIZE, desc), selected(NULL), list_pos(0) { + ttd_strlcpy(this->edit_str_buf, "", this->edit_str_size); + this->afilter = CS_ALPHANUMERAL; + InitializeTextBuffer(&this->text, this->edit_str_buf, this->edit_str_size, EDITBOX_MAX_LENGTH); + this->vscroll.cap = 14; this->resize.step_height = 14; this->resize.step_width = 2; @@ -283,8 +323,11 @@ public: this->HideWidget(select_all ? NCLWW_SELECT_UPDATE : NCLWW_SELECT_ALL); 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->content.ForceRebuild(); + this->FilterContentList(); this->SortContentList(); SetVScrollCount(this, this->content.Length()); @@ -336,6 +379,10 @@ public: this->DrawWidgets(); + /* Edit box to filter for keywords */ + this->DrawEditBox(NCLWW_FILTER); + DrawStringRightAligned(this->widget[NCLWW_FILTER].left - 8, this->widget[NCLWW_FILTER].top + 2, STR_CONTENT_FILTER_TITLE, TC_FROMSTRING); + switch (this->content.SortType()) { case NCLWW_CHECKBOX - NCLWW_CHECKBOX: this->DrawSortButtonState(NCLWW_CHECKBOX, arrow); break; case NCLWW_TYPE - NCLWW_CHECKBOX: this->DrawSortButtonState(NCLWW_TYPE, arrow); break; @@ -488,7 +535,7 @@ public: if (id_v >= this->vscroll.cap) return; // click out of bounds id_v += this->vscroll.pos; - if (id_v >= _network_content_client.Length()) return; // click out of bounds + if (id_v >= this->content.Length()) return; // click out of bounds this->selected = *this->content.Get(id_v); this->list_pos = id_v; @@ -541,10 +588,13 @@ public: } } + virtual void OnMouseLoop() + { + this->HandleEditBox(NCLWW_FILTER); + } + virtual EventState OnKeyPress(uint16 key, uint16 keycode) { - if (_network_content_client.Length() == 0) return ES_HANDLED; - switch (keycode) { case WKC_UP: /* scroll up by one */ @@ -571,7 +621,7 @@ public: this->list_pos = this->content.Length() - 1; break; - case WKC_SPACE: + case WKC_RETURN: if (this->selected != NULL) { _network_content_client.ToggleSelectedState(this->selected); this->content.ForceResort(); @@ -579,9 +629,19 @@ public: } return ES_HANDLED; - default: return ES_NOT_HANDLED; + default: { + /* Handle editbox input */ + EventState state = ES_NOT_HANDLED; + if (this->HandleEditBoxKey(NCLWW_FILTER, key, keycode, state) == HEBR_EDITING) { + this->OnOSKInput(NCLWW_FILTER); + } + + return state; + } } + if (_network_content_client.Length() == 0) return ES_HANDLED; + this->selected = *this->content.Get(this->list_pos); /* scroll to the new server if it is outside the current range */ @@ -592,6 +652,13 @@ public: return ES_HANDLED; } + virtual void OnOSKInput(int wid) + { + this->content.SetFilterState(!StrEmpty(this->edit_str_buf)); + this->content.ForceRebuild(); + this->SetDirty(); + } + virtual void OnResize(Point new_size, Point delta) { this->vscroll.cap += delta.y / (int)this->resize.step_height; @@ -633,45 +700,53 @@ public: }; Listing NetworkContentListWindow::last_sorting = {false, 1}; +Filtering NetworkContentListWindow::last_filtering = {false, 0}; + NetworkContentListWindow::GUIContentList::SortFunction * const NetworkContentListWindow::sorter_funcs[] = { &StateSorter, &TypeSorter, &NameSorter, }; +NetworkContentListWindow::GUIContentList::FilterFunction * const NetworkContentListWindow::filter_funcs[] = { + &TagNameFilter, +}; + /** Widgets used for the content list */ static const Widget _network_content_list_widgets[] = { /* TOP */ { WWT_CLOSEBOX, RESIZE_NONE, COLOUR_LIGHT_BLUE, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW}, // NCLWW_CLOSE { WWT_CAPTION, RESIZE_RIGHT, COLOUR_LIGHT_BLUE, 11, 449, 0, 13, STR_CONTENT_TITLE, STR_NULL}, // NCLWW_CAPTION -{ WWT_PANEL, RESIZE_RB, COLOUR_LIGHT_BLUE, 0, 449, 14, 263, 0x0, STR_NULL}, // NCLWW_BACKGROUND +{ WWT_PANEL, RESIZE_RB, COLOUR_LIGHT_BLUE, 0, 449, 14, 277, 0x0, STR_NULL}, // NCLWW_BACKGROUND + +{ WWT_EDITBOX, RESIZE_LR, COLOUR_LIGHT_BLUE, 210, 440, 20, 31, STR_CONTENT_FILTER_OSKTITLE, STR_CONTENT_FILTER_TIP}, // NCLWW_FILTER /* LEFT SIDE */ -{ WWT_PUSHTXTBTN, RESIZE_NONE, COLOUR_WHITE, 8, 20, 22, 33, STR_EMPTY, STR_NULL}, // NCLWW_CHECKBOX -{ WWT_PUSHTXTBTN, RESIZE_NONE, COLOUR_WHITE, 21, 110, 22, 33, STR_CONTENT_TYPE_CAPTION, STR_CONTENT_TYPE_CAPTION_TIP}, // NCLWW_TYPE -{ WWT_PUSHTXTBTN, RESIZE_RIGHT, COLOUR_WHITE, 111, 191, 22, 33, STR_CONTENT_NAME_CAPTION, STR_CONTENT_NAME_CAPTION_TIP}, // NCLWW_NAME +{ WWT_PUSHTXTBTN, RESIZE_NONE, COLOUR_WHITE, 8, 20, 36, 47, STR_EMPTY, STR_NULL}, // NCLWW_CHECKBOX +{ WWT_PUSHTXTBTN, RESIZE_NONE, COLOUR_WHITE, 21, 110, 36, 47, STR_CONTENT_TYPE_CAPTION, STR_CONTENT_TYPE_CAPTION_TIP}, // NCLWW_TYPE +{ WWT_PUSHTXTBTN, RESIZE_RIGHT, COLOUR_WHITE, 111, 190, 36, 47, STR_CONTENT_NAME_CAPTION, STR_CONTENT_NAME_CAPTION_TIP}, // NCLWW_NAME -{ WWT_MATRIX, RESIZE_RB, COLOUR_LIGHT_BLUE, 8, 190, 34, 230, (14 << 8) | 1, STR_CONTENT_MATRIX_TIP}, // NCLWW_MATRIX -{ WWT_SCROLLBAR, RESIZE_LRB, COLOUR_LIGHT_BLUE, 191, 202, 22, 230, 0x0, STR_0190_SCROLL_BAR_SCROLLS_LIST}, // NCLWW_SCROLLBAR +{ WWT_MATRIX, RESIZE_RB, COLOUR_LIGHT_BLUE, 8, 190, 48, 244, (14 << 8) | 1, STR_CONTENT_MATRIX_TIP}, // NCLWW_MATRIX +{ WWT_SCROLLBAR, RESIZE_LRB, COLOUR_LIGHT_BLUE, 191, 202, 36, 244, 0x0, STR_0190_SCROLL_BAR_SCROLLS_LIST}, // NCLWW_SCROLLBAR /* RIGHT SIDE */ -{ WWT_PANEL, RESIZE_LRB, COLOUR_LIGHT_BLUE, 210, 440, 22, 230, 0x0, STR_NULL}, // NCLWW_DETAILS +{ WWT_PANEL, RESIZE_LRB, COLOUR_LIGHT_BLUE, 210, 440, 36, 244, 0x0, STR_NULL}, // NCLWW_DETAILS /* BOTTOM */ -{ WWT_PUSHTXTBTN, RESIZE_TB, COLOUR_WHITE, 10, 110, 238, 249, STR_CONTENT_SELECT_ALL_CAPTION, STR_CONTENT_SELECT_ALL_CAPTION_TIP}, // NCLWW_SELECT_ALL -{ WWT_PUSHTXTBTN, RESIZE_TB, COLOUR_WHITE, 10, 110, 238, 249, STR_CONTENT_SELECT_UPDATES_CAPTION, STR_CONTENT_SELECT_UPDATES_CAPTION_TIP}, // NCLWW_SELECT_UPDATES -{ WWT_PUSHTXTBTN, RESIZE_TB, COLOUR_WHITE, 118, 218, 238, 249, STR_CONTENT_UNSELECT_ALL_CAPTION, STR_CONTENT_UNSELECT_ALL_CAPTION_TIP}, // NCLWW_UNSELECT -{ WWT_PUSHTXTBTN, RESIZE_LRTB, COLOUR_WHITE, 226, 326, 238, 249, STR_012E_CANCEL, STR_NULL}, // NCLWW_CANCEL -{ WWT_PUSHTXTBTN, RESIZE_LRTB, COLOUR_WHITE, 334, 434, 238, 249, STR_CONTENT_DOWNLOAD_CAPTION, STR_CONTENT_DOWNLOAD_CAPTION_TIP}, // NCLWW_DOWNLOAD +{ WWT_PUSHTXTBTN, RESIZE_TB, COLOUR_WHITE, 10, 110, 252, 263, STR_CONTENT_SELECT_ALL_CAPTION, STR_CONTENT_SELECT_ALL_CAPTION_TIP}, // NCLWW_SELECT_ALL +{ WWT_PUSHTXTBTN, RESIZE_TB, COLOUR_WHITE, 10, 110, 252, 263, STR_CONTENT_SELECT_UPDATES_CAPTION, STR_CONTENT_SELECT_UPDATES_CAPTION_TIP}, // NCLWW_SELECT_UPDATES +{ WWT_PUSHTXTBTN, RESIZE_TB, COLOUR_WHITE, 118, 218, 252, 263, STR_CONTENT_UNSELECT_ALL_CAPTION, STR_CONTENT_UNSELECT_ALL_CAPTION_TIP}, // NCLWW_UNSELECT +{ WWT_PUSHTXTBTN, RESIZE_LRTB, COLOUR_WHITE, 226, 326, 252, 263, STR_012E_CANCEL, STR_NULL}, // NCLWW_CANCEL +{ WWT_PUSHTXTBTN, RESIZE_LRTB, COLOUR_WHITE, 334, 434, 252, 263, STR_CONTENT_DOWNLOAD_CAPTION, STR_CONTENT_DOWNLOAD_CAPTION_TIP}, // NCLWW_DOWNLOAD -{ WWT_RESIZEBOX, RESIZE_LRTB, COLOUR_LIGHT_BLUE, 438, 449, 252, 263, 0x0, STR_RESIZE_BUTTON }, // NCLWW_RESIZE +{ WWT_RESIZEBOX, RESIZE_LRTB, COLOUR_LIGHT_BLUE, 438, 449, 266, 277, 0x0, STR_RESIZE_BUTTON }, // NCLWW_RESIZE { WIDGETS_END}, }; /** Window description of the content list */ static const WindowDesc _network_content_list_desc = { - WDP_CENTER, WDP_CENTER, 450, 264, 630, 460, + WDP_CENTER, WDP_CENTER, 450, 278, 630, 460, WC_NETWORK_WINDOW, WC_NONE, WDF_STD_TOOLTIPS | WDF_DEF_WIDGET | WDF_STD_BTN | WDF_UNCLICK_BUTTONS | WDF_RESIZABLE, _network_content_list_widgets,