diff --git a/src/industry.h b/src/industry.h --- a/src/industry.h +++ b/src/industry.h @@ -354,9 +354,6 @@ static inline Industry *GetRandomIndustr #define FOR_ALL_INDUSTRIES_FROM(i, start) for (i = GetIndustry(start); i != NULL; i = (i->index + 1U < GetIndustryPoolSize()) ? GetIndustry(i->index + 1U) : NULL) if (i->IsValid()) #define FOR_ALL_INDUSTRIES(i) FOR_ALL_INDUSTRIES_FROM(i, 0) -extern const Industry **_industry_sort; -extern bool _industry_sort_dirty; - static const uint8 IT_INVALID = 255; #endif /* INDUSTRY_H */ diff --git a/src/industry_cmd.cpp b/src/industry_cmd.cpp --- a/src/industry_cmd.cpp +++ b/src/industry_cmd.cpp @@ -55,9 +55,6 @@ static TileIndex _industry_sound_tile; int _total_industries; //general counter uint16 _industry_counts[NUM_INDUSTRYTYPES]; // Number of industries per type ingame -const Industry **_industry_sort; -bool _industry_sort_dirty; - IndustrySpec _industry_specs[NUM_INDUSTRYTYPES]; IndustryTileSpec _industry_tile_specs[NUM_INDUSTRYTILES]; @@ -168,12 +165,11 @@ Industry::~Industry() } END_TILE_LOOP(tile_cur, 42, 42, this->xy - TileDiff(21, 21)) } - _industry_sort_dirty = true; DecIndustryTypeCount(this->type); DeleteSubsidyWithIndustry(this->index); DeleteWindowById(WC_INDUSTRY_VIEW, this->index); - InvalidateWindow(WC_INDUSTRY_DIRECTORY, 0); + InvalidateWindowData(WC_INDUSTRY_DIRECTORY, 0, 0); this->xy = 0; } @@ -1556,8 +1552,7 @@ static void DoCreateNewIndustry(Industry if (GetIndustrySpec(i->type)->behaviour & INDUSTRYBEH_PLANT_ON_BUILT) { for (j = 0; j != 50; j++) PlantRandomFarmField(i); } - _industry_sort_dirty = true; - InvalidateWindow(WC_INDUSTRY_DIRECTORY, 0); + InvalidateWindowData(WC_INDUSTRY_DIRECTORY, 0, 0); } /** Helper function for Build/Fund an industry @@ -2240,8 +2235,7 @@ void IndustryMonthlyLoop() _current_player = old_player; /* production-change */ - _industry_sort_dirty = true; - InvalidateWindow(WC_INDUSTRY_DIRECTORY, 0); + InvalidateWindowData(WC_INDUSTRY_DIRECTORY, 0, 1); } @@ -2251,7 +2245,6 @@ void InitializeIndustries() _Industry_pool.AddBlockToPool(); ResetIndustryCounts(); - _industry_sort_dirty = true; _industry_sound_tile = 0; } diff --git a/src/industry_gui.cpp b/src/industry_gui.cpp --- a/src/industry_gui.cpp +++ b/src/industry_gui.cpp @@ -26,6 +26,7 @@ #include "settings_type.h" #include "tilehighlight_func.h" #include "string_func.h" +#include "sortlist_type.h" #include "table/strings.h" #include "table/sprites.h" @@ -697,7 +698,7 @@ enum IndustryDirectoryWidgets { IDW_SORTBYPROD, IDW_SORTBYTRANSPORT, IDW_SPACER, - IDW_INDUSRTY_LIST, + IDW_INDUSTRY_LIST, IDW_SCROLLBAR, IDW_RESIZE, }; @@ -718,12 +719,9 @@ static const Widget _industry_directory_ { WIDGETS_END}, }; -static uint _num_industry_sort; - static char _bufcache[96]; static const Industry* _last_industry; - -static byte _industry_sort_order; +static int _internal_sort_order; static int CDECL GeneralIndustrySorter(const void *a, const void *b) { @@ -731,7 +729,7 @@ static int CDECL GeneralIndustrySorter(c const Industry* j = *(const Industry**)b; int r; - switch (_industry_sort_order >> 1) { + switch (_internal_sort_order >> 1) { default: NOT_REACHED(); case 0: /* Sort by Name (handled later) */ r = 0; @@ -798,138 +796,169 @@ static int CDECL GeneralIndustrySorter(c r = strcmp(buf1, _bufcache); } - if (_industry_sort_order & 1) r = -r; + if (_internal_sort_order & 1) r = -r; return r; } +typedef GUIList GUIIndustryList; + /** - * Makes a sorted industry list. - * When there are no industries, the list has to be made. This so when one - * starts a new game without industries after playing a game with industries - * the list is not populated with invalid industries from the previous game. + * Rebuild industries list if the VL_REBUILD flag is set + * + * @param sl pointer to industry list */ -static void MakeSortedIndustryList() +static void BuildIndustriesList(GUIIndustryList *sl) { - const Industry* i; - int n = 0; + uint n = 0; + const Industry *i; + + if (!(sl->flags & VL_REBUILD)) return; /* Create array for sorting */ - _industry_sort = ReallocT(_industry_sort, GetMaxIndustryIndex() + 1); + const Industry **industry_sort = MallocT(GetMaxIndustryIndex() + 1); + + DEBUG(misc, 3, "Building industry list"); + + FOR_ALL_INDUSTRIES(i) industry_sort[n++] = i; - /* Don't attempt a sort if there are no industries */ - if (GetNumIndustries() != 0) { - FOR_ALL_INDUSTRIES(i) _industry_sort[n++] = i; - qsort((void*)_industry_sort, n, sizeof(_industry_sort[0]), GeneralIndustrySorter); - } + free((void*)sl->sort_list); + sl->sort_list = MallocT(n); + sl->list_length = n; - _num_industry_sort = n; - _last_industry = NULL; // used for "cache" + for (uint i = 0; i < n; ++i) sl->sort_list[i] = industry_sort[i]; - DEBUG(misc, 3, "Resorting industries list"); + sl->flags &= ~VL_REBUILD; + sl->flags |= VL_RESORT; + free((void*)industry_sort); } -static void IndustryDirectoryWndProc(Window *w, WindowEvent *e) +/** + * Sort industry list if the VL_RESORT flag is set + * + * @param sl pointer to industry list + */ +static void SortIndustriesList(GUIIndustryList *sl) { - switch (e->event) { - case WE_PAINT: { - if (_industry_sort_dirty) { - _industry_sort_dirty = false; - MakeSortedIndustryList(); + if (!(sl->flags & VL_RESORT)) return; + + _internal_sort_order = (sl->sort_type << 1) | (sl->flags & VL_DESC); + _last_industry = NULL; // used for "cache" in namesorting + qsort((void*)sl->sort_list, sl->list_length, sizeof(sl->sort_list[0]), &GeneralIndustrySorter); + + sl->flags &= ~VL_RESORT; +} + +/** + * The list of industries. + */ +struct IndustryDirectoryWindow : public Window, public GUIIndustryList { + static Listing industry_sort; + + IndustryDirectoryWindow(const WindowDesc *desc, WindowNumber number) : Window(desc, number) + { + this->vscroll.cap = 16; + this->resize.height = this->height - 6 * 10; // minimum 10 items + this->resize.step_height = 10; + this->FindWindowPlacementAndResize(desc); + + this->sort_list = NULL; + this->flags = VL_REBUILD; + this->sort_type = industry_sort.criteria; + if (industry_sort.order) this->flags |= VL_DESC; + } + + virtual void OnPaint() + { + BuildIndustriesList(this); + SortIndustriesList(this); + + SetVScrollCount(this, this->list_length); + + this->DrawWidgets(); + this->DrawSortButtonState(IDW_SORTBYNAME + this->sort_type, this->flags & VL_DESC ? SBS_DOWN : SBS_UP); + + int max = min(this->vscroll.pos + this->vscroll.cap, this->list_length); + int y = 28; // start of the list-widget + + for (int n = this->vscroll.pos; n < max; ++n) { + const Industry* i = this->sort_list[n]; + const IndustrySpec *indsp = GetIndustrySpec(i->type); + byte p = 0; + + /* Industry name */ + SetDParam(p++, i->index); + + /* Industry productions */ + for (byte j = 0; j < lengthof(i->produced_cargo); j++) { + if (i->produced_cargo[j] == CT_INVALID) continue; + SetDParam(p++, i->produced_cargo[j]); + SetDParam(p++, i->last_month_production[j]); + SetDParam(p++, GetCargoSuffix(j + 3, CST_DIR, (Industry*)i, i->type, indsp)); } - SetVScrollCount(w, _num_industry_sort); - - w->DrawWidgets(); - w->DrawSortButtonState(IDW_SORTBYNAME + (_industry_sort_order >> 1), _industry_sort_order & 1 ? SBS_DOWN : SBS_UP); - - uint pos = w->vscroll.pos; - int n = 0; - - while (pos < _num_industry_sort) { - const Industry* i = _industry_sort[pos]; - const IndustrySpec *indsp = GetIndustrySpec(i->type); - byte p = 0; - - /* Industry name */ - SetDParam(p++, i->index); + /* Transported productions */ + for (byte j = 0; j < lengthof(i->produced_cargo); j++) { + if (i->produced_cargo[j] == CT_INVALID) continue; + SetDParam(p++, i->last_month_pct_transported[j] * 100 >> 8); + } - /* Industry productions */ - for (byte j = 0; j < lengthof(i->produced_cargo); j++) { - if (i->produced_cargo[j] == CT_INVALID) continue; - SetDParam(p++, i->produced_cargo[j]); - SetDParam(p++, i->last_month_production[j]); - SetDParam(p++, GetCargoSuffix(j + 3, CST_DIR, (Industry*)i, i->type, indsp)); - } + /* Drawing the right string */ + StringID str = STR_INDUSTRYDIR_ITEM_NOPROD; + if (p != 1) str = (p == 5) ? STR_INDUSTRYDIR_ITEM : STR_INDUSTRYDIR_ITEM_TWO; + DrawStringTruncated(4, y, str, TC_FROMSTRING, this->widget[IDW_INDUSTRY_LIST].right - 4); - /* Transported productions */ - for (byte j = 0; j < lengthof(i->produced_cargo); j++) { - if (i->produced_cargo[j] == CT_INVALID) continue; - SetDParam(p++, i->last_month_pct_transported[j] * 100 >> 8); - } - - /* Drawing the right string */ - StringID str = STR_INDUSTRYDIR_ITEM_NOPROD; - if (p != 1) str = (p == 5) ? STR_INDUSTRYDIR_ITEM : STR_INDUSTRYDIR_ITEM_TWO; - DrawStringTruncated(4, 28 + n * 10, str, TC_FROMSTRING, w->widget[IDW_INDUSRTY_LIST].right - 4); - - pos++; - if (++n == w->vscroll.cap) break; - } - } break; + y += 10; + } + } - case WE_CLICK: - switch (e->we.click.widget) { - case IDW_SORTBYNAME: { - _industry_sort_order = _industry_sort_order == 0 ? 1 : 0; - _industry_sort_dirty = true; - w->SetDirty(); - } break; + virtual void OnClick(Point pt, int widget) + { + switch (widget) { + case IDW_SORTBYNAME: + case IDW_SORTBYTYPE: + case IDW_SORTBYPROD: + case IDW_SORTBYTRANSPORT: + if (this->sort_type == (widget - IDW_SORTBYNAME)) { + this->flags ^= VL_DESC; + } else { + this->sort_type = widget - IDW_SORTBYNAME; + this->flags &= ~VL_DESC; + } + this->flags |= VL_RESORT; + this->SetDirty(); + break; - case IDW_SORTBYTYPE: { - _industry_sort_order = _industry_sort_order == 2 ? 3 : 2; - _industry_sort_dirty = true; - w->SetDirty(); - } break; - - case IDW_SORTBYPROD: { - _industry_sort_order = _industry_sort_order == 4 ? 5 : 4; - _industry_sort_dirty = true; - w->SetDirty(); - } break; - - case IDW_SORTBYTRANSPORT: { - _industry_sort_order = _industry_sort_order == 6 ? 7 : 6; - _industry_sort_dirty = true; - w->SetDirty(); - } break; + case IDW_INDUSTRY_LIST: { + int y = (pt.y - 28) / 10; + uint16 p; - case IDW_INDUSRTY_LIST: { - int y = (e->we.click.pt.y - 28) / 10; - uint16 p; - - if (!IsInsideMM(y, 0, w->vscroll.cap)) return; - p = y + w->vscroll.pos; - if (p < _num_industry_sort) { - if (_ctrl_pressed) { - ShowExtraViewPortWindow(_industry_sort[p]->xy); - } else { - ScrollMainWindowToTile(_industry_sort[p]->xy); - } + if (!IsInsideMM(y, 0, this->vscroll.cap)) return; + p = y + this->vscroll.pos; + if (p < this->list_length) { + if (_ctrl_pressed) { + ShowExtraViewPortWindow(this->sort_list[p]->xy); + } else { + ScrollMainWindowToTile(this->sort_list[p]->xy); } - } break; - } - break; + } + } break; + } + } - case WE_100_TICKS: - w->SetDirty(); - break; + virtual void OnResize(Point new_size, Point delta) + { + this->vscroll.cap += delta.y / 10; + } - case WE_RESIZE: - w->vscroll.cap += e->we.sizing.diff.y / 10; - break; + virtual void OnInvalidateData(int data) + { + this->flags |= (data == 0 ? VL_REBUILD : VL_RESORT); + this->InvalidateWidget(IDW_INDUSTRY_LIST); } -} +}; + +Listing IndustryDirectoryWindow::industry_sort = {0, 0}; /** Window definition of the industy directory gui */ static const WindowDesc _industry_directory_desc = { @@ -937,17 +966,10 @@ static const WindowDesc _industry_direct WC_INDUSTRY_DIRECTORY, WC_NONE, WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS | WDF_STICKY_BUTTON | WDF_RESIZABLE, _industry_directory_widgets, - IndustryDirectoryWndProc + NULL }; void ShowIndustryDirectory() { - Window *w = AllocateWindowDescFront(&_industry_directory_desc, 0); - - if (w != NULL) { - w->vscroll.cap = 16; - w->resize.height = w->height - 6 * 10; // minimum 10 items - w->resize.step_height = 10; - w->SetDirty(); - } + AllocateWindowDescFront(&_industry_directory_desc, 0); } diff --git a/src/openttd.cpp b/src/openttd.cpp --- a/src/openttd.cpp +++ b/src/openttd.cpp @@ -283,7 +283,6 @@ static void InitializeDynamicVariables() { /* Dynamic stuff needs to be initialized somewhere... */ _town_sort = NULL; - _industry_sort = NULL; _industry_mngr.ResetMapping(); _industile_mngr.ResetMapping(); } @@ -320,7 +319,6 @@ static void ShutdownGame() _Engine_pool.CleanPool(); free((void*)_town_sort); - free((void*)_industry_sort); free(_config_file);