diff --git a/graph_gui.c b/graph_gui.c index fdd6a1ee5c..d27c140b95 100644 --- a/graph_gui.c +++ b/graph_gui.c @@ -6,6 +6,9 @@ #include "gfx.h" #include "player.h" #include "economy.h" +#include "signs.h" +#include "strings.h" +#include "debug.h" static uint _legend_excludebits; static uint _legend_cargobits; @@ -1098,3 +1101,149 @@ void ShowPerformanceRatingDetail(void) { AllocateWindowDescFront(&_performance_rating_detail_desc, 0); } + + +static uint16 _num_sign_sort; + +static char _bufcache[64]; +static uint16 _last_sign_idx; + +static int CDECL SignNameSorter(const void *a, const void *b) +{ + char buf1[64]; + SignStruct *ss; + const uint16 cmp1 = *(const uint16 *)a; + const uint16 cmp2 = *(const uint16 *)b; + + ss = GetSign(cmp1); + GetString(buf1, ss->str); + + if (cmp2 != _last_sign_idx) { + _last_sign_idx = cmp2; + ss = GetSign(cmp2); + GetString(_bufcache, ss->str); + } + + return strcmp(buf1, _bufcache); // sort by name +} + +static void GlobalSortSignList(void) +{ + const SignStruct *ss; + uint32 n = 0; + + _num_sign_sort = 0; + + /* Create array for sorting */ + _sign_sort = realloc(_sign_sort, GetSignPoolSize() * sizeof(_sign_sort[0])); + if (_sign_sort == NULL) + error("Could not allocate memory for the sign-sorting-list"); + + FOR_ALL_SIGNS(ss) { + if(ss->str != STR_NULL) { + _sign_sort[n++] = ss->index; + _num_sign_sort++; + } + } + + qsort(_sign_sort, n, sizeof(_sign_sort[0]), SignNameSorter); + + _sign_sort_dirty = false; + + DEBUG(misc, 1) ("Resorting global sign list..."); +} + +static void SignListWndProc(Window *w, WindowEvent *e) +{ + switch (e->event) { + case WE_PAINT: { + uint32 i; + int y = 16; // offset from top of widget + + if (_sign_sort_dirty) + GlobalSortSignList(); + + SetVScrollCount(w, _num_sign_sort); + + SetDParam(0, w->vscroll.count); + DrawWindowWidgets(w); + + /* No signs? */ + if (w->vscroll.count == 0) { + DrawString(2, y, STR_304A_NONE, 0); + return; + } + + { + SignStruct *ss; + + /* Start drawing the signs */ + i = 0; + for (i = w->vscroll.pos; i < (uint)w->vscroll.cap + w->vscroll.pos && i < w->vscroll.count; i++) { + ss = GetSign(_sign_sort[i]); + + if (ss->owner != OWNER_NONE) + DrawPlayerIcon(ss->owner, 4, y + 1); + + DrawString(22, y, ss->str, 8); + y += 10; + } + } + } break; + + case WE_CLICK: { + switch (e->click.widget) { + case 3: { + uint32 id_v = (e->click.pt.y - 15) / 10; + SignStruct *ss; + + if (id_v >= w->vscroll.cap) + return; + + id_v += w->vscroll.pos; + + if (id_v >= w->vscroll.count) + return; + + ss = GetSign(_sign_sort[id_v]); + ScrollMainWindowToTile(TILE_FROM_XY(ss->x, ss->y)); + } break; + } + } break; + + case WE_RESIZE: + w->vscroll.cap += e->sizing.diff.y / 10; + break; + } +} + +static const Widget _sign_list_widget[] = { +{ WWT_CLOSEBOX, RESIZE_NONE, 14, 0, 10, 0, 13, STR_00C5, STR_018B_CLOSE_WINDOW}, +{ WWT_CAPTION, RESIZE_RIGHT, 14, 11, 345, 0, 13, STR_SIGN_LIST_CAPTION, STR_018C_WINDOW_TITLE_DRAG_THIS}, +{ WWT_STICKYBOX, RESIZE_LR, 14, 346, 357, 0, 13, 0x0, STR_STICKY_BUTTON}, +{ WWT_PANEL, RESIZE_RB, 14, 0, 345, 14, 137, 0x0, STR_NULL}, +{ WWT_SCROLLBAR, RESIZE_LRB, 14, 346, 357, 14, 125, 0x0, STR_0190_SCROLL_BAR_SCROLLS_LIST}, +{ WWT_RESIZEBOX, RESIZE_LRTB, 14, 346, 357, 126, 137, 0x0, STR_RESIZE_BUTTON}, +{ WIDGETS_END}, +}; + +static const WindowDesc _sign_list_desc = { + -1, -1, 358, 138, + WC_SIGN_LIST,0, + WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_STICKY_BUTTON | WDF_RESIZABLE, + _sign_list_widget, + SignListWndProc +}; + + +void ShowSignList(void) +{ + Window *w; + + w = AllocateWindowDescFront(&_sign_list_desc, 0); + if (w != NULL) { + w->vscroll.cap = 12; + w->resize.step_height = 10; + w->resize.height = w->height - 10 * 7; // minimum if 5 in the list + } +} diff --git a/gui.h b/gui.h index eb2a2b3af4..8686621447 100644 --- a/gui.h +++ b/gui.h @@ -75,6 +75,7 @@ void ShowSubsidiesList(void); void ShowPlayerStations(int player); void ShowPlayerFinances(int player); void ShowPlayerCompany(int player); +void ShowSignList(void); void ShowEstimatedCostOrIncome(int32 cost, int x, int y); void ShowErrorMessage(StringID msg_1, StringID msg_2, int x, int y); diff --git a/lang/english.txt b/lang/english.txt index 4f5011547d..729c81a139 100644 --- a/lang/english.txt +++ b/lang/english.txt @@ -772,6 +772,7 @@ STR_02DC_DISPLAY_SUBSIDIES :{BLACK}Display subsidies STR_02DD_SUBSIDIES :Subsidies STR_02DE_MAP_OF_WORLD :Map of world STR_EXTRA_VIEW_PORT :Extra viewport +STR_SIGN_LIST :Sign list STR_02DF_TOWN_DIRECTORY :Town directory STR_TOWN_POPULATION :{BLACK}World population: {COMMA32} STR_EXTRA_VIEW_PORT_TITLE :{WHITE}Viewport {COMMA16} @@ -2796,6 +2797,7 @@ STR_REPLACE_HELP_REPLACE_INFO_TAB :{BLACK}Displays which engine the left sele STR_REPLACE_HELP :{BLACK}This allows you to replace one engine type with another type, when trains of the original type enter a depot STR_SHORT_DATE :{WHITE}{DATE_TINY} +STR_SIGN_LIST_CAPTION :{WHITE}Sign List - {COMMA16} Signs ############ Lists rail types diff --git a/main_gui.c b/main_gui.c index bac3509f7a..633b970b7d 100644 --- a/main_gui.c +++ b/main_gui.c @@ -233,6 +233,7 @@ static void MenuClickMap(int index) switch(index) { case 0: ShowSmallMap(); break; case 1: ShowExtraViewPortWindow(); break; + case 2: ShowSignList(); break; } } @@ -778,7 +779,7 @@ static void ToolbarSaveClick(Window *w) static void ToolbarMapClick(Window *w) { - PopupMainToolbMenu(w, 96, 4, STR_02DE_MAP_OF_WORLD, 2); + PopupMainToolbMenu(w, 96, 4, STR_02DE_MAP_OF_WORLD, 3); } static void ToolbarTownClick(Window *w) diff --git a/signs.c b/signs.c index c686dc1eb1..74856cc2bc 100644 --- a/signs.c +++ b/signs.c @@ -4,6 +4,7 @@ #include "signs.h" #include "saveload.h" #include "command.h" +#include "strings.h" enum { /* Max signs: 64000 (4 * 16000) */ @@ -75,10 +76,17 @@ static void MarkSignDirty(SignStruct *ss) */ static SignStruct *AllocateSign(void) { - SignStruct *s; - FOR_ALL_SIGNS(s) - if (s->str == 0) - return s; + SignStruct *ss; + FOR_ALL_SIGNS(ss) { + if (ss->str == 0) { + uint index = ss->index; + + memset(ss, 0, sizeof(SignStruct)); + ss->index = index; + + return ss; + } + } /* Check if we can add a block to the pool */ if (AddBlockToPool(&_sign_pool)) @@ -112,6 +120,8 @@ int32 CmdPlaceSign(int x, int y, uint32 flags, uint32 p1, uint32 p2) ss->z = GetSlopeZ(x,y); UpdateSignVirtCoords(ss); MarkSignDirty(ss); + InvalidateWindow(WC_SIGN_LIST, 0); + _sign_sort_dirty = true; _new_sign_struct = ss; } @@ -151,6 +161,8 @@ int32 CmdRenameSign(int x, int y, uint32 flags, uint32 sign_id, uint32 owner) /* Update */ UpdateSignVirtCoords(ss); MarkSignDirty(ss); + InvalidateWindow(WC_SIGN_LIST, 0); + _sign_sort_dirty = true; } else { /* Free the name, because we did not assign it yet */ DeleteName(str); @@ -165,6 +177,8 @@ int32 CmdRenameSign(int x, int y, uint32 flags, uint32 sign_id, uint32 owner) ss->str = 0; MarkSignDirty(ss); + InvalidateWindow(WC_SIGN_LIST, 0); + _sign_sort_dirty = true; } } @@ -252,6 +266,8 @@ static void Load_SIGN(void) ss = GetSign(index); SlObject(ss, _sign_desc); } + + _sign_sort_dirty = true; } const ChunkHandler _sign_chunk_handlers[] = { diff --git a/signs.h b/signs.h index dc8c657857..2cc417ca03 100644 --- a/signs.h +++ b/signs.h @@ -46,6 +46,9 @@ static inline uint16 GetSignPoolSize(void) VARDEF SignStruct *_new_sign_struct; +VARDEF bool _sign_sort_dirty; +VARDEF uint16 *_sign_sort; + void UpdateAllSignVirtCoords(void); void PlaceProc_Sign(uint tile); diff --git a/ttd.h b/ttd.h index 24b193b0c4..33cc3c13d3 100644 --- a/ttd.h +++ b/ttd.h @@ -425,6 +425,7 @@ enum { WC_CUSTOM_CURRENCY = 0x4B, WC_REPLACE_VEHICLE = 0x4C, WC_HIGHSCORE_ENDSCREEN = 0x4D, + WC_SIGN_LIST = 0x4E, };