src/town_gui.cpp
changeset 9387 ede823d445f5
parent 9354 845e07db4549
child 9390 88d36f907e96
equal deleted inserted replaced
9386:f3fd0650f9d5 9387:ede823d445f5
    22 #include "economy_func.h"
    22 #include "economy_func.h"
    23 #include "core/alloc_func.hpp"
    23 #include "core/alloc_func.hpp"
    24 #include "settings_type.h"
    24 #include "settings_type.h"
    25 #include "tilehighlight_func.h"
    25 #include "tilehighlight_func.h"
    26 #include "string_func.h"
    26 #include "string_func.h"
       
    27 #include "sortlist_type.h"
    27 
    28 
    28 #include "table/sprites.h"
    29 #include "table/sprites.h"
    29 #include "table/strings.h"
    30 #include "table/strings.h"
       
    31 
       
    32 typedef GUIList<const Town*> GUITownList;
    30 
    33 
    31 extern bool GenerateTowns();
    34 extern bool GenerateTowns();
    32 static int _scengen_town_size = 1; // depress medium-sized towns per default
    35 static int _scengen_town_size = 1; // depress medium-sized towns per default
    33 
    36 
    34 static const Widget _town_authority_widgets[] = {
    37 static const Widget _town_authority_widgets[] = {
   446 {  WWT_RESIZEBOX,     RESIZE_TB,    13,   196,   207,   190,   201, 0x0,                    STR_RESIZE_BUTTON},
   449 {  WWT_RESIZEBOX,     RESIZE_TB,    13,   196,   207,   190,   201, 0x0,                    STR_RESIZE_BUTTON},
   447 {   WIDGETS_END},
   450 {   WIDGETS_END},
   448 };
   451 };
   449 
   452 
   450 
   453 
   451 /* used to get a sorted list of the towns */
       
   452 static uint _num_town_sort;
       
   453 
       
   454 static char _bufcache[64];
       
   455 static const Town* _last_town;
       
   456 
       
   457 static int CDECL TownNameSorter(const void *a, const void *b)
       
   458 {
       
   459 	const Town* ta = *(const Town**)a;
       
   460 	const Town* tb = *(const Town**)b;
       
   461 	char buf1[64];
       
   462 	int r;
       
   463 
       
   464 	SetDParam(0, ta->index);
       
   465 	GetString(buf1, STR_TOWN, lastof(buf1));
       
   466 
       
   467 	/* If 'b' is the same town as in the last round, use the cached value
       
   468 	 *  We do this to speed stuff up ('b' is called with the same value a lot of
       
   469 	 *  times after eachother) */
       
   470 	if (tb != _last_town) {
       
   471 		_last_town = tb;
       
   472 		SetDParam(0, tb->index);
       
   473 		GetString(_bufcache, STR_TOWN, lastof(_bufcache));
       
   474 	}
       
   475 
       
   476 	r = strcmp(buf1, _bufcache);
       
   477 	if (_town_sort_order & 1) r = -r;
       
   478 	return r;
       
   479 }
       
   480 
       
   481 static int CDECL TownPopSorter(const void *a, const void *b)
       
   482 {
       
   483 	const Town* ta = *(const Town**)a;
       
   484 	const Town* tb = *(const Town**)b;
       
   485 	int r = ta->population - tb->population;
       
   486 	if (_town_sort_order & 1) r = -r;
       
   487 	return r;
       
   488 }
       
   489 
       
   490 static void MakeSortedTownList()
       
   491 {
       
   492 	const Town* t;
       
   493 	uint n = 0;
       
   494 
       
   495 	/* Create array for sorting */
       
   496 	_town_sort = ReallocT(_town_sort, GetMaxTownIndex() + 1);
       
   497 
       
   498 	FOR_ALL_TOWNS(t) _town_sort[n++] = t;
       
   499 
       
   500 	_num_town_sort = n;
       
   501 
       
   502 	_last_town = NULL; // used for "cache"
       
   503 	qsort((void*)_town_sort, n, sizeof(_town_sort[0]), _town_sort_order & 2 ? TownPopSorter : TownNameSorter);
       
   504 
       
   505 	DEBUG(misc, 3, "Resorting towns list");
       
   506 }
       
   507 
       
   508 
       
   509 struct TownDirectoryWindow : public Window {
   454 struct TownDirectoryWindow : public Window {
   510 private:
   455 private:
   511 	enum TownDirectoryWidget {
   456 	enum TownDirectoryWidget {
   512 		TDW_SORTNAME = 3,
   457 		TDW_SORTNAME = 3,
   513 		TDW_SORTPOPULATION,
   458 		TDW_SORTPOPULATION,
   514 		TDW_CENTERTOWN,
   459 		TDW_CENTERTOWN,
   515 	};
   460 	};
   516 
   461 
       
   462 	/* Runtime saved values */
       
   463 	static Listing last_sorting;
       
   464 	static const Town *last_town;
       
   465 
       
   466 	/* Constants for sorting towns */
       
   467 	static const GUITownList::SortFunction * const sorter_funcs[];
       
   468 
       
   469 	GUITownList towns;
       
   470 
       
   471 	void BuildTownList()
       
   472 	{
       
   473 		if (!this->towns.NeedRebuild()) return;
       
   474 
       
   475 		this->towns.Clear();
       
   476 
       
   477 		const Town *t;
       
   478 		FOR_ALL_TOWNS(t) {
       
   479 			*this->towns.Append() = t;
       
   480 		}
       
   481 
       
   482 		this->towns.Compact();
       
   483 		this->towns.RebuildDone();
       
   484 	}
       
   485 
       
   486 	void SortTownList()
       
   487 	{
       
   488 		last_town = NULL;
       
   489 		this->towns.Sort();
       
   490 	}
       
   491 
       
   492 	/** Sort by town name */
       
   493 	static int CDECL TownNameSorter(const Town * const *a, const Town * const *b)
       
   494 	{
       
   495 		static char buf_cache[64];
       
   496 		const Town *ta = *a;
       
   497 		const Town *tb = *b;
       
   498 		char buf[64];
       
   499 
       
   500 		SetDParam(0, ta->index);
       
   501 		GetString(buf, STR_TOWN, lastof(buf));
       
   502 
       
   503 		/* If 'b' is the same town as in the last round, use the cached value
       
   504 		 * We do this to speed stuff up ('b' is called with the same value a lot of
       
   505 		 * times after eachother) */
       
   506 		if (tb != last_town) {
       
   507 			last_town = tb;
       
   508 			SetDParam(0, tb->index);
       
   509 			GetString(buf_cache, STR_TOWN, lastof(buf_cache));
       
   510 		}
       
   511 
       
   512 		return strcmp(buf, buf_cache);
       
   513 	}
       
   514 
       
   515 	/** Sort by population */
       
   516 	static int CDECL TownPopulationSorter(const Town * const *a, const Town * const *b)
       
   517 	{
       
   518 		return (*a)->population - (*b)->population;
       
   519 	}
       
   520 
   517 public:
   521 public:
   518 	TownDirectoryWindow(const WindowDesc *desc) : Window(desc, 0)
   522 	TownDirectoryWindow(const WindowDesc *desc) : Window(desc, 0)
   519 	{
   523 	{
   520 		this->vscroll.cap = 16;
   524 		this->vscroll.cap = 16;
   521 		this->resize.step_height = 10;
   525 		this->resize.step_height = 10;
   522 		this->resize.height = this->height - 10 * 6; // minimum of 10 items in the list, each item 10 high
   526 		this->resize.height = this->height - 10 * 6; // minimum of 10 items in the list, each item 10 high
   523 
   527 
       
   528 		this->towns.SetListing(this->last_sorting);
       
   529 		this->towns.SetSortFuncs(this->sorter_funcs);
       
   530 		this->towns.ForceRebuild();
       
   531 
   524 		this->FindWindowPlacementAndResize(desc);
   532 		this->FindWindowPlacementAndResize(desc);
   525 	}
   533 	}
   526 
   534 
       
   535 	~TownDirectoryWindow()
       
   536 	{
       
   537 		this->last_sorting = this->towns.GetListing();
       
   538 	}
       
   539 
   527 	virtual void OnPaint()
   540 	virtual void OnPaint()
   528 	{
   541 	{
   529 		if (_town_sort_dirty) {
   542 		this->BuildTownList();
   530 			_town_sort_dirty = false;
   543 		this->SortTownList();
   531 			MakeSortedTownList();
   544 
   532 		}
   545 		SetVScrollCount(this, this->towns.Length());
   533 
       
   534 		SetVScrollCount(this, _num_town_sort);
       
   535 
   546 
   536 		this->DrawWidgets();
   547 		this->DrawWidgets();
   537 		this->DrawSortButtonState((_town_sort_order <= 1) ? TDW_SORTNAME : TDW_SORTPOPULATION, _town_sort_order & 1 ? SBS_DOWN : SBS_UP);
   548 		this->DrawSortButtonState(this->towns.sort_type == 0 ? TDW_SORTNAME : TDW_SORTPOPULATION, this->towns.IsDescSortOrder() ? SBS_DOWN : SBS_UP);
   538 
   549 
   539 		{
   550 		{
   540 			int n = 0;
   551 			int n = 0;
   541 			uint16 i = this->vscroll.pos;
   552 			uint16 i = this->vscroll.pos;
   542 			int y = 28;
   553 			int y = 28;
   543 
   554 
   544 			while (i < _num_town_sort) {
   555 			while (i < this->towns.Length()) {
   545 				const Town* t = _town_sort[i];
   556 				const Town *t = this->towns[i];
   546 
   557 
   547 				assert(t->xy);
   558 				assert(t->xy);
   548 
   559 
   549 				SetDParam(0, t->index);
   560 				SetDParam(0, t->index);
   550 				SetDParam(1, t->population);
   561 				SetDParam(1, t->population);
   562 
   573 
   563 	virtual void OnClick(Point pt, int widget)
   574 	virtual void OnClick(Point pt, int widget)
   564 	{
   575 	{
   565 		switch (widget) {
   576 		switch (widget) {
   566 			case TDW_SORTNAME: /* Sort by Name ascending/descending */
   577 			case TDW_SORTNAME: /* Sort by Name ascending/descending */
   567 				_town_sort_order = (_town_sort_order == 0) ? 1 : 0;
   578 				if (this->towns.SortType() == 0) {
   568 				_town_sort_dirty = true;
   579 					this->towns.ToggleSortOrder();
       
   580 				} else {
       
   581 					this->towns.SetSortType(0);
       
   582 				}
   569 				this->SetDirty();
   583 				this->SetDirty();
   570 				break;
   584 				break;
   571 
   585 
   572 			case TDW_SORTPOPULATION: /* Sort by Population ascending/descending */
   586 			case TDW_SORTPOPULATION: /* Sort by Population ascending/descending */
   573 				_town_sort_order = (_town_sort_order == 2) ? 3 : 2;
   587 				if (this->towns.SortType() == 1) {
   574 				_town_sort_dirty = true;
   588 					this->towns.ToggleSortOrder();
       
   589 				} else {
       
   590 					this->towns.SetSortType(1);
       
   591 				}
   575 				this->SetDirty();
   592 				this->SetDirty();
   576 				break;
   593 				break;
   577 
   594 
   578 			case TDW_CENTERTOWN: { /* Click on Town Matrix */
   595 			case TDW_CENTERTOWN: { /* Click on Town Matrix */
   579 				const Town* t;
       
   580 
       
   581 				uint16 id_v = (pt.y - 28) / 10;
   596 				uint16 id_v = (pt.y - 28) / 10;
   582 
   597 
   583 				if (id_v >= this->vscroll.cap) return; // click out of bounds
   598 				if (id_v >= this->vscroll.cap) return; // click out of bounds
   584 
   599 
   585 				id_v += this->vscroll.pos;
   600 				id_v += this->vscroll.pos;
   586 
   601 
   587 				if (id_v >= _num_town_sort) return; // click out of town bounds
   602 				if (id_v >= this->towns.Length()) return; // click out of town bounds
   588 
   603 
   589 				t = _town_sort[id_v];
   604 				const Town *t = this->towns[id_v];
   590 				assert(t->xy);
   605 				assert(t->xy);
   591 				if (_ctrl_pressed) {
   606 				if (_ctrl_pressed) {
   592 					ShowExtraViewPortWindow(t->xy);
   607 					ShowExtraViewPortWindow(t->xy);
   593 				} else {
   608 				} else {
   594 					ScrollMainWindowToTile(t->xy);
   609 					ScrollMainWindowToTile(t->xy);
   605 
   620 
   606 	virtual void OnResize(Point new_size, Point delta)
   621 	virtual void OnResize(Point new_size, Point delta)
   607 	{
   622 	{
   608 		this->vscroll.cap += delta.y / 10;
   623 		this->vscroll.cap += delta.y / 10;
   609 	}
   624 	}
       
   625 
       
   626 	virtual void OnInvalidateData(int data)
       
   627 	{
       
   628 		if (data == 0) {
       
   629 			this->towns.ForceRebuild();
       
   630 		} else {
       
   631 			this->towns.ForceResort();
       
   632 		}
       
   633 	}
       
   634 };
       
   635 
       
   636 Listing TownDirectoryWindow::last_sorting = {false, 0};
       
   637 const Town *TownDirectoryWindow::last_town = NULL;
       
   638 
       
   639 /* Available town directory sorting functions */
       
   640 const GUITownList::SortFunction * const TownDirectoryWindow::sorter_funcs[] = {
       
   641 	&TownNameSorter,
       
   642 	&TownPopulationSorter,
   610 };
   643 };
   611 
   644 
   612 static const WindowDesc _town_directory_desc = {
   645 static const WindowDesc _town_directory_desc = {
   613 	WDP_AUTO, WDP_AUTO, 208, 202, 208, 202,
   646 	WDP_AUTO, WDP_AUTO, 208, 202, 208, 202,
   614 	WC_TOWN_DIRECTORY, WC_NONE,
   647 	WC_TOWN_DIRECTORY, WC_NONE,