summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/openttd.cpp3
-rw-r--r--src/town.h4
-rw-r--r--src/town_cmd.cpp15
-rw-r--r--src/town_gui.cpp173
4 files changed, 107 insertions, 88 deletions
diff --git a/src/openttd.cpp b/src/openttd.cpp
index 06a818d41..1ece64737 100644
--- a/src/openttd.cpp
+++ b/src/openttd.cpp
@@ -282,7 +282,6 @@ static void ParseResolution(int res[2], const char *s)
static void InitializeDynamicVariables()
{
/* Dynamic stuff needs to be initialized somewhere... */
- _town_sort = NULL;
_industry_mngr.ResetMapping();
_industile_mngr.ResetMapping();
}
@@ -318,8 +317,6 @@ static void ShutdownGame()
_CargoPacket_pool.CleanPool();
_Engine_pool.CleanPool();
- free((void*)_town_sort);
-
free(_config_file);
/* Close all and any open filehandles */
diff --git a/src/town.h b/src/town.h
index d19a6b387..155a392ca 100644
--- a/src/town.h
+++ b/src/town.h
@@ -345,10 +345,6 @@ Town *CalcClosestTownFromTile(TileIndex tile, uint threshold);
#define FOR_ALL_TOWNS_FROM(t, start) for (t = GetTown(start); t != NULL; t = (t->index + 1U < GetTownPoolSize()) ? GetTown(t->index + 1U) : NULL) if (t->IsValid())
#define FOR_ALL_TOWNS(t) FOR_ALL_TOWNS_FROM(t, 0)
-extern bool _town_sort_dirty;
-extern byte _town_sort_order;
-extern const Town **_town_sort;
-
extern Town *_cleared_town;
extern int _cleared_town_rating;
diff --git a/src/town_cmd.cpp b/src/town_cmd.cpp
index 7359ef952..98891028c 100644
--- a/src/town_cmd.cpp
+++ b/src/town_cmd.cpp
@@ -55,10 +55,6 @@
uint _total_towns;
HouseSpec _house_specs[HOUSE_MAX];
-bool _town_sort_dirty;
-byte _town_sort_order;
-const Town **_town_sort;
-
Town *_cleared_town;
int _cleared_town_rating;
@@ -82,7 +78,7 @@ Town::~Town()
/* Delete town authority window
* and remove from list of sorted towns */
DeleteWindowById(WC_TOWN_VIEW, this->index);
- _town_sort_dirty = true;
+ InvalidateWindowData(WC_TOWN_DIRECTORY, 0, 0);
_total_towns--;
/* Delete all industries belonging to the town */
@@ -348,7 +344,7 @@ static void ChangePopulation(Town *t, int mod)
InvalidateWindow(WC_TOWN_VIEW, t->index);
UpdateTownVirtCoord(t);
- if (_town_sort_order & 2) _town_sort_dirty = true;
+ InvalidateWindowData(WC_TOWN_DIRECTORY, 0, 1);
}
/**
@@ -1465,7 +1461,7 @@ static void DoCreateTown(Town *t, TileIndex tile, uint32 townnameparts, TownSize
t->townnameparts = townnameparts;
UpdateTownVirtCoord(t);
- _town_sort_dirty = true;
+ InvalidateWindowData(WC_TOWN_DIRECTORY, 0, 0);
t->InitializeLayout();
@@ -2099,7 +2095,7 @@ CommandCost CmdRenameTown(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
t->name = strdup(_cmd_text);
UpdateTownVirtCoord(t);
- _town_sort_dirty = true;
+ InvalidateWindowData(WC_TOWN_DIRECTORY, 0, 1);
UpdateAllStationVirtCoord();
UpdateAllWaypointSigns();
MarkWholeScreenDirty();
@@ -2565,7 +2561,6 @@ void InitializeTowns()
_cur_town_ctr = 0;
_cur_town_iter = 0;
_total_towns = 0;
- _town_sort_dirty = true;
}
static CommandCost TerraformTile_Town(TileIndex tile, uint32 flags, uint z_new, Slope tileh_new)
@@ -2736,8 +2731,6 @@ static void Load_TOWN()
void AfterLoadTown()
{
- _town_sort_dirty = true;
-
Town *t;
FOR_ALL_TOWNS(t) t->InitializeLayout();
}
diff --git a/src/town_gui.cpp b/src/town_gui.cpp
index 5d7715e95..aed740d8f 100644
--- a/src/town_gui.cpp
+++ b/src/town_gui.cpp
@@ -24,10 +24,13 @@
#include "settings_type.h"
#include "tilehighlight_func.h"
#include "string_func.h"
+#include "sortlist_type.h"
#include "table/sprites.h"
#include "table/strings.h"
+typedef GUIList<const Town*> GUITownList;
+
extern bool GenerateTowns();
static int _scengen_town_size = 1; // depress medium-sized towns per default
@@ -448,71 +451,72 @@ static const Widget _town_directory_widgets[] = {
};
-/* used to get a sorted list of the towns */
-static uint _num_town_sort;
-
-static char _bufcache[64];
-static const Town* _last_town;
+struct TownDirectoryWindow : public Window {
+private:
+ enum TownDirectoryWidget {
+ TDW_SORTNAME = 3,
+ TDW_SORTPOPULATION,
+ TDW_CENTERTOWN,
+ };
-static int CDECL TownNameSorter(const void *a, const void *b)
-{
- const Town* ta = *(const Town**)a;
- const Town* tb = *(const Town**)b;
- char buf1[64];
- int r;
-
- SetDParam(0, ta->index);
- GetString(buf1, STR_TOWN, lastof(buf1));
-
- /* If 'b' is the same town as in the last round, use the cached value
- * We do this to speed stuff up ('b' is called with the same value a lot of
- * times after eachother) */
- if (tb != _last_town) {
- _last_town = tb;
- SetDParam(0, tb->index);
- GetString(_bufcache, STR_TOWN, lastof(_bufcache));
- }
+ /* Runtime saved values */
+ static Listing last_sorting;
+ static const Town *last_town;
- r = strcmp(buf1, _bufcache);
- if (_town_sort_order & 1) r = -r;
- return r;
-}
+ /* Constants for sorting towns */
+ static const GUITownList::SortFunction * const sorter_funcs[];
-static int CDECL TownPopSorter(const void *a, const void *b)
-{
- const Town* ta = *(const Town**)a;
- const Town* tb = *(const Town**)b;
- int r = ta->population - tb->population;
- if (_town_sort_order & 1) r = -r;
- return r;
-}
+ GUITownList towns;
-static void MakeSortedTownList()
-{
- const Town* t;
- uint n = 0;
+ void BuildTownList()
+ {
+ if (!this->towns.NeedRebuild()) return;
- /* Create array for sorting */
- _town_sort = ReallocT(_town_sort, GetMaxTownIndex() + 1);
+ this->towns.Clear();
- FOR_ALL_TOWNS(t) _town_sort[n++] = t;
+ const Town *t;
+ FOR_ALL_TOWNS(t) {
+ *this->towns.Append() = t;
+ }
- _num_town_sort = n;
+ this->towns.Compact();
+ this->towns.RebuildDone();
+ }
- _last_town = NULL; // used for "cache"
- qsort((void*)_town_sort, n, sizeof(_town_sort[0]), _town_sort_order & 2 ? TownPopSorter : TownNameSorter);
+ void SortTownList()
+ {
+ last_town = NULL;
+ this->towns.Sort();
+ }
- DEBUG(misc, 3, "Resorting towns list");
-}
+ /** Sort by town name */
+ static int CDECL TownNameSorter(const Town * const *a, const Town * const *b)
+ {
+ static char buf_cache[64];
+ const Town *ta = *a;
+ const Town *tb = *b;
+ char buf[64];
+
+ SetDParam(0, ta->index);
+ GetString(buf, STR_TOWN, lastof(buf));
+
+ /* If 'b' is the same town as in the last round, use the cached value
+ * We do this to speed stuff up ('b' is called with the same value a lot of
+ * times after eachother) */
+ if (tb != last_town) {
+ last_town = tb;
+ SetDParam(0, tb->index);
+ GetString(buf_cache, STR_TOWN, lastof(buf_cache));
+ }
+ return strcmp(buf, buf_cache);
+ }
-struct TownDirectoryWindow : public Window {
-private:
- enum TownDirectoryWidget {
- TDW_SORTNAME = 3,
- TDW_SORTPOPULATION,
- TDW_CENTERTOWN,
- };
+ /** Sort by population */
+ static int CDECL TownPopulationSorter(const Town * const *a, const Town * const *b)
+ {
+ return (*a)->population - (*b)->population;
+ }
public:
TownDirectoryWindow(const WindowDesc *desc) : Window(desc, 0)
@@ -521,28 +525,35 @@ public:
this->resize.step_height = 10;
this->resize.height = this->height - 10 * 6; // minimum of 10 items in the list, each item 10 high
+ this->towns.SetListing(this->last_sorting);
+ this->towns.SetSortFuncs(this->sorter_funcs);
+ this->towns.ForceRebuild();
+
this->FindWindowPlacementAndResize(desc);
}
+ ~TownDirectoryWindow()
+ {
+ this->last_sorting = this->towns.GetListing();
+ }
+
virtual void OnPaint()
{
- if (_town_sort_dirty) {
- _town_sort_dirty = false;
- MakeSortedTownList();
- }
+ this->BuildTownList();
+ this->SortTownList();
- SetVScrollCount(this, _num_town_sort);
+ SetVScrollCount(this, this->towns.Length());
this->DrawWidgets();
- this->DrawSortButtonState((_town_sort_order <= 1) ? TDW_SORTNAME : TDW_SORTPOPULATION, _town_sort_order & 1 ? SBS_DOWN : SBS_UP);
+ this->DrawSortButtonState(this->towns.sort_type == 0 ? TDW_SORTNAME : TDW_SORTPOPULATION, this->towns.IsDescSortOrder() ? SBS_DOWN : SBS_UP);
{
int n = 0;
uint16 i = this->vscroll.pos;
int y = 28;
- while (i < _num_town_sort) {
- const Town* t = _town_sort[i];
+ while (i < this->towns.Length()) {
+ const Town *t = this->towns[i];
assert(t->xy);
@@ -564,29 +575,33 @@ public:
{
switch (widget) {
case TDW_SORTNAME: /* Sort by Name ascending/descending */
- _town_sort_order = (_town_sort_order == 0) ? 1 : 0;
- _town_sort_dirty = true;
+ if (this->towns.SortType() == 0) {
+ this->towns.ToggleSortOrder();
+ } else {
+ this->towns.SetSortType(0);
+ }
this->SetDirty();
break;
case TDW_SORTPOPULATION: /* Sort by Population ascending/descending */
- _town_sort_order = (_town_sort_order == 2) ? 3 : 2;
- _town_sort_dirty = true;
+ if (this->towns.SortType() == 1) {
+ this->towns.ToggleSortOrder();
+ } else {
+ this->towns.SetSortType(1);
+ }
this->SetDirty();
break;
case TDW_CENTERTOWN: { /* Click on Town Matrix */
- const Town* t;
-
uint16 id_v = (pt.y - 28) / 10;
if (id_v >= this->vscroll.cap) return; // click out of bounds
id_v += this->vscroll.pos;
- if (id_v >= _num_town_sort) return; // click out of town bounds
+ if (id_v >= this->towns.Length()) return; // click out of town bounds
- t = _town_sort[id_v];
+ const Town *t = this->towns[id_v];
assert(t->xy);
if (_ctrl_pressed) {
ShowExtraViewPortWindow(t->xy);
@@ -607,6 +622,24 @@ public:
{
this->vscroll.cap += delta.y / 10;
}
+
+ virtual void OnInvalidateData(int data)
+ {
+ if (data == 0) {
+ this->towns.ForceRebuild();
+ } else {
+ this->towns.ForceResort();
+ }
+ }
+};
+
+Listing TownDirectoryWindow::last_sorting = {false, 0};
+const Town *TownDirectoryWindow::last_town = NULL;
+
+/* Available town directory sorting functions */
+const GUITownList::SortFunction * const TownDirectoryWindow::sorter_funcs[] = {
+ &TownNameSorter,
+ &TownPopulationSorter,
};
static const WindowDesc _town_directory_desc = {