From bbf5571c172437c1b4c7de5eccfb1a3b925efaf1 Mon Sep 17 00:00:00 2001 From: Park Joon-Kyu Date: Mon, 25 Dec 2017 20:17:37 +0900 Subject: [PATCH] Allow filtering guests by name (#6633) --- contributors.md | 1 + data/language/en-GB.txt | 3 + resources/g2/icons/search.png | Bin 0 -> 1906 bytes resources/g2/sprites.json | 3 + src/openrct2-ui/windows/GuestList.cpp | 80 ++++++++++++++++++++++--- src/openrct2/localisation/string_ids.h | 4 ++ src/openrct2/sprites.h | 2 + src/openrct2/util/Util.cpp | 38 ++++++++++++ src/openrct2/util/Util.h | 3 + 9 files changed, 126 insertions(+), 8 deletions(-) create mode 100644 resources/g2/icons/search.png diff --git a/contributors.md b/contributors.md index 7d65c44e1d..d0f675bf8b 100644 --- a/contributors.md +++ b/contributors.md @@ -68,6 +68,7 @@ The following people are not part of the project team, but have been contributin * Thomas Delebo (delebota) - Misc. * Brian Callahan (ibara) - OpenBSD port. * Jens Heuseveldt (jensj12) - Mountain tool improvements, misc. +* Park Joon-Kyu (segfault87) - Misc. ## Bug fixes * (halfbro) diff --git a/data/language/en-GB.txt b/data/language/en-GB.txt index 205268fe4f..301a0bb681 100644 --- a/data/language/en-GB.txt +++ b/data/language/en-GB.txt @@ -4477,6 +4477,9 @@ STR_6167 :{SMALLFONT}{BLACK}Advanced STR_6168 :Title Sequence STR_6169 :Scenario selection STR_6170 :Tweaks +STR_6171 :Search +STR_6172 :{SMALLFONT}{BLACK}Search +STR_6173 :Please provide the name to search: ############# # Scenarios # diff --git a/resources/g2/icons/search.png b/resources/g2/icons/search.png new file mode 100644 index 0000000000000000000000000000000000000000..b9df419b0ebaed91b3f4840398069f8738a81162 GIT binary patch literal 1906 zcmbVMTWs4@7Hn!WQ zeFBP@5Dy&>Y!aXiB*x%nL8E97(=?`5XkwyhokU?}ePXI$urieiiBW~)+z6<<2ut=k zKIc2%|NWQqzY!hi-M;OCZ3IDV4~K$7cx<)bE%o@j^vTy>;bE&Ddfp_6=6U2Fhh{LH-=$EOEC&)cH5ffyQ1;|`BqnctaKoxmKJhzt_iY!8`(E!zD8zhG# zQBu+jL<&w14LLVUdi_q$!@33Tagt{_FT)B9>!DdrWPKvfk>!WN)(kl*4h5eq+robV zDs5T1$S@NV6V3^jQ!`Qw=lA;=mS=dL#t7P+R4tIBRnt*n2qF_2if$>IO4^Jdp^aGq z3M(zSkkzZSs#y*b4j7XII>R|x+od88+WK*;mpVSdEgiLMBfT(92%XHY@=%QpGU};8N z(=wGrMJtj?Ng{Ve08~`lg|?alCEWMUmAoijtPm3~U&ybJebg zB`IoXNhO0f%%R?HGTbA1IKRh3^G>cPHxd!Us%ZfgqHr)k;ovwGMHaojq#JrL&Xa_Y zc0(^u`#?gbIUnb9C83-IvafPJsKGJ21nl#r+aPNYbNnMuP9|g)`Z(Gvvo0C{x0ePi z!sH$SB8c2D;RY49rws*PNRX*zwN=TO5xF4p$%2mtE&5@qDo5E zO)Y6n00VWUaO`edh0M*wn_&Fb((f#lB~7)`H?7+LBfT6Jm~i%Lmh z{+qAjUQOSsz;QFQr`0Zuf2w^PshHZpU3$lvg*M#bL(%?t4;~Na^Myj;K8M5Maxs$B z5sN(q;fQH!)6>%j56;9IG2p1ycw%nu^qVagmY0`~-m|v8zJ6|JVU;PY?=9SzDHP`3 zd3|;obJbfz12H`QIX=IFhxu@@E57TSvGXH$Pm@gz(Tkl;?!@4kjkVdjb948fI{Zg} z>z1E4c3gipMfQFkCqivse)m(0{$S_;dsVO7f05hWJACBj-xu;%mOeZF4FBG#S^vG> z^!|^p_YKyE&Mq$9*xeL;#o77LFT~3CN4g)qTE8;b_#^lNG(6@wwD)q~;)NgbCs*HE z%xA9EZ(OEU9ew$IFZ>!>z4GC{aLe+g6UQ&111ra-{+gj*`; #include #include +#include enum { PAGE_INDIVIDUAL, @@ -42,7 +43,8 @@ enum WINDOW_GUEST_LIST_WIDGET_IDX { WIDX_TRACKING, WIDX_TAB_1, WIDX_TAB_2, - WIDX_GUEST_LIST + WIDX_GUEST_LIST, + WIDX_FILTER_BY_NAME }; enum { @@ -77,13 +79,14 @@ static rct_widget window_guest_list_widgets[] = { { WWT_RESIZE, 1, 0, 349, 43, 329, 0xFFFFFFFF, STR_NONE }, // tab content panel { WWT_DROPDOWN, 1, 5, 84, 59, 70, STR_PAGE_1, STR_NONE }, // page dropdown { WWT_DROPDOWN_BUTTON, 1, 73, 83, 60, 69, STR_DROPDOWN_GLYPH, STR_NONE }, // page dropdown button - { WWT_DROPDOWN, 1, 120, 295, 59, 70, 0xFFFFFFFF, STR_INFORMATION_TYPE_TIP }, // information type dropdown - { WWT_DROPDOWN_BUTTON, 1, 284, 294, 60, 69, STR_DROPDOWN_GLYPH, STR_INFORMATION_TYPE_TIP }, // information type dropdown button + { WWT_DROPDOWN, 1, 120, 285, 59, 70, 0xFFFFFFFF, STR_INFORMATION_TYPE_TIP }, // information type dropdown + { WWT_DROPDOWN_BUTTON, 1, 274, 284, 60, 69, STR_DROPDOWN_GLYPH, STR_INFORMATION_TYPE_TIP }, // information type dropdown button { WWT_FLATBTN, 1, 297, 320, 46, 69, SPR_MAP, STR_SHOW_GUESTS_ON_MAP_TIP }, // map { WWT_FLATBTN, 1, 321, 344, 46, 69, SPR_TRACK_PEEP, STR_TRACKED_GUESTS_ONLY_TIP }, // tracking { WWT_TAB, 1, 3, 33, 17, 43, IMAGE_TYPE_REMAP | SPR_TAB, STR_INDIVIDUAL_GUESTS_TIP }, // tab 1 { WWT_TAB, 1, 34, 64, 17, 43, IMAGE_TYPE_REMAP | SPR_TAB, STR_SUMMARISED_GUESTS_TIP }, // tab 2 { WWT_SCROLL, 1, 3, 346, 72, 326, SCROLL_BOTH, STR_NONE }, // guest list + { WWT_FLATBTN, 1, 293, 316, 46, 69, SPR_G2_SEARCH, STR_GUESTS_FILTER_BY_NAME_TIP }, // filter by name { WIDGETS_END }, }; @@ -101,6 +104,7 @@ static void window_guest_list_tooltip(rct_window* w, rct_widgetindex widgetIndex static void window_guest_list_invalidate(rct_window *w); static void window_guest_list_paint(rct_window *w, rct_drawpixelinfo *dpi); static void window_guest_list_scrollpaint(rct_window *w, rct_drawpixelinfo *dpi, sint32 scrollIndex); +static void window_guest_list_textinput(rct_window *w, rct_widgetindex widgetIndex, char *text); static rct_window_event_list window_guest_list_events = { nullptr, @@ -122,7 +126,7 @@ static rct_window_event_list window_guest_list_events = { window_guest_list_scrollmousedown, nullptr, window_guest_list_scrollmouseover, - nullptr, + window_guest_list_textinput, nullptr, nullptr, window_guest_list_tooltip, @@ -153,11 +157,15 @@ static uint32 _window_guest_list_groups_argument_2[240]; static uint8 _window_guest_list_groups_guest_faces[240 * 58]; static uint8 _window_guest_list_group_index[240]; +static char _window_guest_list_filter_name[32]; + static sint32 window_guest_list_is_peep_in_filter(rct_peep* peep); static void window_guest_list_find_groups(); static void get_arguments_from_peep(rct_peep *peep, uint32 *argument_1, uint32* argument_2); +static bool guest_should_be_visible(rct_peep *peep); + void window_guest_list_init_vars() { _window_guest_list_selected_tab = 0; @@ -191,7 +199,8 @@ rct_window * window_guest_list_open() (1 << WIDX_MAP) | (1 << WIDX_TRACKING) | (1 << WIDX_TAB_1) | - (1 << WIDX_TAB_2); + (1 << WIDX_TAB_2) | + (1 << WIDX_FILTER_BY_NAME); window_init_scroll_widgets(window); _window_guest_list_highlighted_index = -1; @@ -201,7 +210,9 @@ rct_window * window_guest_list_open() _window_guest_list_selected_page = 0; _window_guest_list_num_pages = 1; _window_guest_list_tracking_only = false; + _window_guest_list_filter_name[0] = '\0'; window_guest_list_widgets[WIDX_TRACKING].type = WWT_FLATBTN; + window_guest_list_widgets[WIDX_FILTER_BY_NAME].type = WWT_FLATBTN; window_guest_list_widgets[WIDX_PAGE_DROPDOWN].type = WWT_EMPTY; window_guest_list_widgets[WIDX_PAGE_DROPDOWN_BUTTON].type = WWT_EMPTY; window->var_492 = 0; @@ -320,6 +331,25 @@ static void window_guest_list_mouseup(rct_window *w, rct_widgetindex widgetIndex window_invalidate(w); w->scrolls[0].v_top = 0; break; + case WIDX_FILTER_BY_NAME: + if (strnlen(_window_guest_list_filter_name, sizeof(_window_guest_list_filter_name)) > 0) + { + // Unset the search filter. + _window_guest_list_filter_name[0] = '\0'; + w->pressed_widgets &= ~(1 << WIDX_FILTER_BY_NAME); + } + else + { + window_text_input_open( + w, + WIDX_FILTER_BY_NAME, + STR_GUESTS_FILTER_BY_NAME, + STR_GUESTS_ENTER_NAME_TO_SEARCH, + STR_STRING, + (uintptr_t) &_window_guest_list_filter_name, + sizeof(_window_guest_list_filter_name)); + } + break; } } @@ -358,8 +388,12 @@ static void window_guest_list_mousedown(rct_window *w, rct_widgetindex widgetInd _window_guest_list_selected_page = 0; _window_guest_list_num_pages = 1; window_guest_list_widgets[WIDX_TRACKING].type = WWT_EMPTY; + window_guest_list_widgets[WIDX_FILTER_BY_NAME].type = WWT_EMPTY; if (_window_guest_list_selected_tab == PAGE_INDIVIDUAL) + { window_guest_list_widgets[WIDX_TRACKING].type = WWT_FLATBTN; + window_guest_list_widgets[WIDX_FILTER_BY_NAME].type = WWT_FLATBTN; + } window_guest_list_widgets[WIDX_PAGE_DROPDOWN].type = WWT_EMPTY; window_guest_list_widgets[WIDX_PAGE_DROPDOWN_BUTTON].type = WWT_EMPTY; w->list_information_type = 0; @@ -468,7 +502,7 @@ static void window_guest_list_scrollgetsize(rct_window *w, sint32 scrollIndex, s if (_window_guest_list_selected_filter != -1) if (window_guest_list_is_peep_in_filter(peep)) continue; - if (_window_guest_list_tracking_only && !(peep->peep_flags & PEEP_FLAGS_TRACKING)) + if (!guest_should_be_visible(peep)) continue; numGuests++; } @@ -534,7 +568,7 @@ static void window_guest_list_scrollmousedown(rct_window *w, sint32 scrollIndex, if (_window_guest_list_selected_filter != -1) if (window_guest_list_is_peep_in_filter(peep)) continue; - if (_window_guest_list_tracking_only && !(peep->peep_flags & PEEP_FLAGS_TRACKING)) + if (!guest_should_be_visible(peep)) continue; if (i == 0) { @@ -614,6 +648,8 @@ static void window_guest_list_invalidate(rct_window *w) window_guest_list_widgets[WIDX_PAGE_DROPDOWN].text = pageNames[_window_guest_list_selected_page]; window_guest_list_widgets[WIDX_TRACKING].left = 321 - 350 + w->width; window_guest_list_widgets[WIDX_TRACKING].right = 344 - 350 + w->width; + window_guest_list_widgets[WIDX_FILTER_BY_NAME].left = 293 - 350 + w->width; + window_guest_list_widgets[WIDX_FILTER_BY_NAME].right = 316 - 350 + w->width; if (_window_guest_list_num_pages > 1) { window_guest_list_widgets[WIDX_PAGE_DROPDOWN].type = WWT_DROPDOWN; @@ -713,7 +749,7 @@ static void window_guest_list_scrollpaint(rct_window *w, rct_drawpixelinfo *dpi, gWindowMapFlashingFlags |= (1 << 0); sprite_set_flashing((rct_sprite*)peep, true); } - if (_window_guest_list_tracking_only && !(peep->peep_flags & PEEP_FLAGS_TRACKING)) + if (!guest_should_be_visible(peep)) continue; // Check if y is beyond the scroll control @@ -814,6 +850,14 @@ static void window_guest_list_scrollpaint(rct_window *w, rct_drawpixelinfo *dpi, } } +static void window_guest_list_textinput(rct_window *w, rct_widgetindex widgetIndex, char *text) +{ + if (text != nullptr && text[0] != '\0') + { + strncpy(_window_guest_list_filter_name, text, sizeof(_window_guest_list_filter_name)); + w->pressed_widgets |= (1 << WIDX_FILTER_BY_NAME); + } +} /** * returns 0 for in filter and 1 for not in filter @@ -998,3 +1042,23 @@ static void window_guest_list_find_groups() } while (++swap_position <= groupIndex); } } + +static bool guest_should_be_visible(rct_peep *peep) +{ + if (_window_guest_list_tracking_only && !(peep->peep_flags & PEEP_FLAGS_TRACKING)) + return false; + + if (_window_guest_list_filter_name[0] != '\0') + { + char formatted[256]; + + set_format_arg(0, rct_string_id, peep->name_string_idx); + set_format_arg(2, uint32, peep->id); + format_string(formatted, sizeof(formatted), peep->name_string_idx, gCommonFormatArgs); + + if (strcasestr(formatted, _window_guest_list_filter_name) == nullptr) + return false; + } + + return true; +} diff --git a/src/openrct2/localisation/string_ids.h b/src/openrct2/localisation/string_ids.h index a36976293d..b0dde5bf82 100644 --- a/src/openrct2/localisation/string_ids.h +++ b/src/openrct2/localisation/string_ids.h @@ -3818,6 +3818,10 @@ enum { STR_OPTIONS_SCENARIO_SELECTION = 6169, STR_OPTIONS_TWEAKS = 6170, + STR_GUESTS_FILTER_BY_NAME = 6171, + STR_GUESTS_FILTER_BY_NAME_TIP = 6172, + STR_GUESTS_ENTER_NAME_TO_SEARCH = 6173, + // Have to include resource strings (from scenarios and objects) for the time being now that language is partially working STR_COUNT = 32768 }; diff --git a/src/openrct2/sprites.h b/src/openrct2/sprites.h index e96761dbc8..b4f8ba827c 100644 --- a/src/openrct2/sprites.h +++ b/src/openrct2/sprites.h @@ -822,6 +822,8 @@ enum { SPR_G2_MINIATURE_RAILWAY_INSET_END_NW_SE = SPR_G2_MINIATURE_RAILWAY_BEGIN + 11, SPR_G2_MINIATURE_RAILWAY_LAST = SPR_G2_BEGIN + 105, + SPR_G2_SEARCH = SPR_G2_BEGIN + 106, + // 0x60000, chosen because it's a round hex number // of the last possible range of image ID values that is large enough to fit all csg1 sprites. SPR_CSG_BEGIN = 393216, diff --git a/src/openrct2/util/Util.cpp b/src/openrct2/util/Util.cpp index 799735ec59..cb346e1f3f 100644 --- a/src/openrct2/util/Util.cpp +++ b/src/openrct2/util/Util.cpp @@ -415,6 +415,44 @@ char *safe_strtrimleft(char *destination, const char *source, size_t size) return safe_strcpy(destination, source, size); } +#if !defined(_GNU_SOURCE) +char * strcasestr(const char * haystack, const char * needle) +{ + const char * p1 = haystack; + const char * p2 = needle; + const char * r = *p2 == 0 ? haystack : 0; + + while (*p1 != 0 && *p2 != 0) { + if (tolower((unsigned char) *p1) == tolower((unsigned char) *p2)) + { + if (r == 0) + r = p1; + p2++; + } + else + { + p2 = needle; + if (r != 0) + p1 = r + 1; + + if (tolower((unsigned char) *p1) == tolower((unsigned char) *p2)) + { + r = p1; + p2++; + } + else + { + r = 0; + } + } + + p1++; + } + + return *p2 == 0 ? (char *) r : 0; +} +#endif + bool utf8_is_bom(const char *str) { return str[0] == (char)(uint8)0xEF && str[1] == (char)(uint8)0xBB && str[2] == (char)(uint8)0xBF; diff --git a/src/openrct2/util/Util.h b/src/openrct2/util/Util.h index 2f2e13e330..2a9fc6df02 100644 --- a/src/openrct2/util/Util.h +++ b/src/openrct2/util/Util.h @@ -52,6 +52,9 @@ char *safe_strcpy(char * destination, const char * source, size_t num); char *safe_strcat(char *destination, const char *source, size_t size); char *safe_strcat_path(char *destination, const char *source, size_t size); char *safe_strtrimleft(char *destination, const char *source, size_t size); +#if !defined(_GNU_SOURCE) +char * strcasestr(const char * haystack, const char * needle); +#endif bool utf8_is_bom(const char *str); bool str_is_null_or_empty(const char *str);