src/industry_gui.cpp
branchnoai
changeset 10645 8cbdb511a674
parent 10513 33cb70ff2f5d
child 10715 6bdf79ffb022
equal deleted inserted replaced
10644:6c4314786d68 10645:8cbdb511a674
    24 #include "map_func.h"
    24 #include "map_func.h"
    25 #include "player_func.h"
    25 #include "player_func.h"
    26 #include "settings_type.h"
    26 #include "settings_type.h"
    27 #include "tilehighlight_func.h"
    27 #include "tilehighlight_func.h"
    28 #include "string_func.h"
    28 #include "string_func.h"
       
    29 #include "sortlist_type.h"
    29 
    30 
    30 #include "table/strings.h"
    31 #include "table/strings.h"
    31 #include "table/sprites.h"
    32 #include "table/sprites.h"
    32 
    33 
    33 bool _ignore_restrictions;
    34 bool _ignore_restrictions;
    88 static const WindowDesc _build_industry_desc = {
    89 static const WindowDesc _build_industry_desc = {
    89 	WDP_AUTO, WDP_AUTO, 170, 212, 170, 212,
    90 	WDP_AUTO, WDP_AUTO, 170, 212, 170, 212,
    90 	WC_BUILD_INDUSTRY, WC_NONE,
    91 	WC_BUILD_INDUSTRY, WC_NONE,
    91 	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_RESIZABLE,
    92 	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_RESIZABLE,
    92 	_build_industry_widgets,
    93 	_build_industry_widgets,
    93 	NULL,
       
    94 };
    94 };
    95 
    95 
    96 class BuildIndustryWindow : public Window {
    96 class BuildIndustryWindow : public Window {
    97 	int selected_index;                         ///< index of the element in the matrix
    97 	int selected_index;                         ///< index of the element in the matrix
    98 	IndustryType selected_type;                 ///< industry corresponding to the above index
    98 	IndustryType selected_type;                 ///< industry corresponding to the above index
   101 	uint16 count;                               ///< How many industries are loaded
   101 	uint16 count;                               ///< How many industries are loaded
   102 	IndustryType index[NUM_INDUSTRYTYPES + 1];  ///< Type of industry, in the order it was loaded
   102 	IndustryType index[NUM_INDUSTRYTYPES + 1];  ///< Type of industry, in the order it was loaded
   103 	StringID text[NUM_INDUSTRYTYPES + 1];       ///< Text coming from CBM_IND_FUND_MORE_TEXT (if ever)
   103 	StringID text[NUM_INDUSTRYTYPES + 1];       ///< Text coming from CBM_IND_FUND_MORE_TEXT (if ever)
   104 	bool enabled[NUM_INDUSTRYTYPES + 1];        ///< availability state, coming from CBID_INDUSTRY_AVAILABLE (if ever)
   104 	bool enabled[NUM_INDUSTRYTYPES + 1];        ///< availability state, coming from CBID_INDUSTRY_AVAILABLE (if ever)
   105 
   105 
   106 public:
   106 	void SetupArrays()
   107 	BuildIndustryWindow() : Window(&_build_industry_desc)
       
   108 	{
   107 	{
   109 		IndustryType ind;
   108 		IndustryType ind;
   110 		const IndustrySpec *indsp;
   109 		const IndustrySpec *indsp;
   111 
   110 
   112 		/* Shorten the window to the equivalant of the additionnal purchase
       
   113 		 * info coming from the callback.  SO it will only be available to tis full
       
   114 		 * height when newindistries are loaded */
       
   115 		if (!_loaded_newgrf_features.has_newindustries) {
       
   116 			this->widget[DPIW_INFOPANEL].bottom -= 44;
       
   117 			this->widget[DPIW_FUND_WIDGET].bottom -= 44;
       
   118 			this->widget[DPIW_FUND_WIDGET].top -= 44;
       
   119 			this->widget[DPIW_RESIZE_WIDGET].bottom -= 44;
       
   120 			this->widget[DPIW_RESIZE_WIDGET].top -= 44;
       
   121 			this->resize.height = this->height -= 44;
       
   122 		}
       
   123 
       
   124 		this->timer_enabled = _loaded_newgrf_features.has_newindustries;
       
   125 
       
   126 		/* Initialize structures */
       
   127 		this->count = 0;
   111 		this->count = 0;
   128 
   112 
   129 		for (uint i = 0; i < lengthof(this->index); i++) {
   113 		for (uint i = 0; i < lengthof(this->index); i++) {
   130 			this->index[i]   = 0xFF;
   114 			this->index[i]   = INVALID_INDUSTRYTYPE;
   131 			this->text[i]    = STR_NULL;
   115 			this->text[i]    = STR_NULL;
   132 			this->enabled[i] = false;
   116 			this->enabled[i] = false;
   133 		}
   117 		}
   134 
       
   135 		this->vscroll.cap = 8; // rows in grid, same in scroller
       
   136 		this->resize.step_height = 13;
       
   137 
   118 
   138 		if (_game_mode == GM_EDITOR) { // give room for the Many Random "button"
   119 		if (_game_mode == GM_EDITOR) { // give room for the Many Random "button"
   139 			this->index[this->count] = INVALID_INDUSTRYTYPE;
   120 			this->index[this->count] = INVALID_INDUSTRYTYPE;
   140 			this->count++;
   121 			this->count++;
   141 			this->timer_enabled = false;
   122 			this->timer_enabled = false;
   142 		}
   123 		}
   143 
   124 		/* Fill the arrays with industries.
   144 		/* Fill the _fund_gui structure with industries.
       
   145 		 * The tests performed after the enabled allow to load the industries
   125 		 * The tests performed after the enabled allow to load the industries
   146 		 * In the same way they are inserted by grf (if any)
   126 		 * In the same way they are inserted by grf (if any)
   147 		 */
   127 		 */
   148 		for (ind = 0; ind < NUM_INDUSTRYTYPES; ind++) {
   128 		for (ind = 0; ind < NUM_INDUSTRYTYPES; ind++) {
   149 			indsp = GetIndustrySpec(ind);
   129 			indsp = GetIndustrySpec(ind);
   150 			if (indsp->enabled){
   130 			if (indsp->enabled){
   151 				/* Rule is that editor mode loads all industries.
   131 				/* Rule is that editor mode loads all industries.
   152 				 * In game mode, all non raw industries are loaded too
   132 				 * In game mode, all non raw industries are loaded too
   153 				 * and raw ones are loaded only when setting allows it */
   133 				 * and raw ones are loaded only when setting allows it */
   154 				if (_game_mode != GM_EDITOR && indsp->IsRawIndustry() && _patches.raw_industry_construction == 0) continue;
   134 				if (_game_mode != GM_EDITOR && indsp->IsRawIndustry() && _patches.raw_industry_construction == 0) {
       
   135 					/* Unselect if the industry is no longer in the list */
       
   136 					if (this->selected_type == ind) this->selected_index = -1;
       
   137 					continue;
       
   138 				}
   155 				this->index[this->count] = ind;
   139 				this->index[this->count] = ind;
   156 				this->enabled[this->count] = (_game_mode == GM_EDITOR) || CheckIfCallBackAllowsAvailability(ind, IACT_USERCREATION);
   140 				this->enabled[this->count] = (_game_mode == GM_EDITOR) || CheckIfCallBackAllowsAvailability(ind, IACT_USERCREATION);
       
   141 				/* Keep the selection to the correct line */
       
   142 				if (this->selected_type == ind) this->selected_index = this->count;
   157 				this->count++;
   143 				this->count++;
   158 			}
   144 			}
   159 		}
   145 		}
   160 
   146 
   161 		/* first indutry type is selected.
   147 		/* first indutry type is selected if the current selection is invalid.
   162 		 * I'll be damned if there are none available ;) */
   148 		 * I'll be damned if there are none available ;) */
   163 		this->selected_index = 0;
   149 		if (this->selected_index == -1) {
   164 		this->selected_type = this->index[0];
   150 			this->selected_index = 0;
       
   151 			this->selected_type = this->index[0];
       
   152 		}
       
   153 	}
       
   154 
       
   155 public:
       
   156 	BuildIndustryWindow() : Window(&_build_industry_desc)
       
   157 	{
       
   158 		/* Shorten the window to the equivalant of the additionnal purchase
       
   159 		 * info coming from the callback.  SO it will only be available to its full
       
   160 		 * height when newindistries are loaded */
       
   161 		if (!_loaded_newgrf_features.has_newindustries) {
       
   162 			this->widget[DPIW_INFOPANEL].bottom -= 44;
       
   163 			this->widget[DPIW_FUND_WIDGET].bottom -= 44;
       
   164 			this->widget[DPIW_FUND_WIDGET].top -= 44;
       
   165 			this->widget[DPIW_RESIZE_WIDGET].bottom -= 44;
       
   166 			this->widget[DPIW_RESIZE_WIDGET].top -= 44;
       
   167 			this->resize.height = this->height -= 44;
       
   168 		}
       
   169 
       
   170 		this->timer_enabled = _loaded_newgrf_features.has_newindustries;
       
   171 
       
   172 		this->vscroll.cap = 8; // rows in grid, same in scroller
       
   173 		this->resize.step_height = 13;
       
   174 
       
   175 		this->selected_index = -1;
       
   176 		this->selected_type = INVALID_INDUSTRYTYPE;
       
   177 
       
   178 		/* Initialize arrays */
       
   179 		this->SetupArrays();
       
   180 
   165 		this->callback_timer = DAY_TICKS;
   181 		this->callback_timer = DAY_TICKS;
   166 
   182 
   167 		this->FindWindowPlacementAndResize(&_build_industry_desc);
   183 		this->FindWindowPlacementAndResize(&_build_industry_desc);
   168 	}
   184 	}
   169 
   185 
   186 		}
   202 		}
   187 		this->SetWidgetDisabledState(DPIW_FUND_WIDGET, !this->enabled[this->selected_index]);
   203 		this->SetWidgetDisabledState(DPIW_FUND_WIDGET, !this->enabled[this->selected_index]);
   188 
   204 
   189 		SetVScrollCount(this, this->count);
   205 		SetVScrollCount(this, this->count);
   190 
   206 
   191 		DrawWindowWidgets(this);
   207 		this->DrawWidgets();
   192 
   208 
   193 		/* and now with the matrix painting */
   209 		/* and now with the matrix painting */
   194 		for (byte i = 0; i < this->vscroll.cap && ((i + this->vscroll.pos) < this->count); i++) {
   210 		for (byte i = 0; i < this->vscroll.cap && ((i + this->vscroll.pos) < this->count); i++) {
   195 			int offset = i * 13;
   211 			int offset = i * 13;
   196 			int x = 3;
   212 			int x = 3;
   390 
   406 
   391 	virtual void OnPlaceObjectAbort()
   407 	virtual void OnPlaceObjectAbort()
   392 	{
   408 	{
   393 		this->RaiseButtons();
   409 		this->RaiseButtons();
   394 	}
   410 	}
       
   411 
       
   412 	virtual void OnInvalidateData(int data = 0)
       
   413 	{
       
   414 		this->SetupArrays();
       
   415 		this->SetDirty();
       
   416 	}
   395 };
   417 };
   396 
   418 
   397 void ShowBuildIndustryWindow()
   419 void ShowBuildIndustryWindow()
   398 {
   420 {
   399 	if (_game_mode != GM_EDITOR && !IsValidPlayer(_current_player)) return;
   421 	if (_game_mode != GM_EDITOR && !IsValidPlayer(_current_player)) return;
   438 	byte clicked_line;        ///< The line of the button that has been clicked
   460 	byte clicked_line;        ///< The line of the button that has been clicked
   439 	byte clicked_button;      ///< The button that has been clicked (to raise)
   461 	byte clicked_button;      ///< The button that has been clicked (to raise)
   440 	byte production_offset_y; ///< The offset of the production texts/buttons
   462 	byte production_offset_y; ///< The offset of the production texts/buttons
   441 
   463 
   442 public:
   464 public:
   443 	IndustryViewWindow(const WindowDesc *desc, void *data, WindowNumber window_number) : Window(desc, data, window_number)
   465 	IndustryViewWindow(const WindowDesc *desc, WindowNumber window_number) : Window(desc, window_number)
   444 	{
   466 	{
   445 		this->flags4 |= WF_DISABLE_VP_SCROLL;
   467 		this->flags4 |= WF_DISABLE_VP_SCROLL;
   446 		this->editbox_line = 0;
   468 		this->editbox_line = 0;
   447 		this->clicked_line = 0;
   469 		this->clicked_line = 0;
   448 		this->clicked_button = 0;
   470 		this->clicked_button = 0;
   457 		int y = this->widget[IVW_INFO].top + 1;
   479 		int y = this->widget[IVW_INFO].top + 1;
   458 		bool first = true;
   480 		bool first = true;
   459 		bool has_accept = false;
   481 		bool has_accept = false;
   460 
   482 
   461 		SetDParam(0, this->window_number);
   483 		SetDParam(0, this->window_number);
   462 		DrawWindowWidgets(this);
   484 		this->DrawWidgets();
   463 
   485 
   464 		if (HasBit(ind->callback_flags, CBM_IND_PRODUCTION_CARGO_ARRIVAL) || HasBit(ind->callback_flags, CBM_IND_PRODUCTION_256_TICKS)) {
   486 		if (HasBit(ind->callback_flags, CBM_IND_PRODUCTION_CARGO_ARRIVAL) || HasBit(ind->callback_flags, CBM_IND_PRODUCTION_256_TICKS)) {
   465 			for (byte j = 0; j < lengthof(i->accepts_cargo); j++) {
   487 			for (byte j = 0; j < lengthof(i->accepts_cargo); j++) {
   466 				if (i->accepts_cargo[j] == CT_INVALID) continue;
   488 				if (i->accepts_cargo[j] == CT_INVALID) continue;
   467 				has_accept = true;
   489 				has_accept = true;
   540 			ResizeWindowForWidget(this, IVW_INFO, 0, y - this->widget[IVW_INFO].top);
   562 			ResizeWindowForWidget(this, IVW_INFO, 0, y - this->widget[IVW_INFO].top);
   541 			this->SetDirty();
   563 			this->SetDirty();
   542 			return;
   564 			return;
   543 		}
   565 		}
   544 
   566 
   545 		DrawWindowViewport(this);
   567 		this->DrawViewport();
   546 	}
   568 	}
   547 
   569 
   548 	virtual void OnClick(Point pt, int widget)
   570 	virtual void OnClick(Point pt, int widget)
   549 	{
   571 	{
   550 		Industry *i;
   572 		Industry *i;
   655 static const WindowDesc _industry_view_desc = {
   677 static const WindowDesc _industry_view_desc = {
   656 	WDP_AUTO, WDP_AUTO, 260, 120, 260, 120,
   678 	WDP_AUTO, WDP_AUTO, 260, 120, 260, 120,
   657 	WC_INDUSTRY_VIEW, WC_NONE,
   679 	WC_INDUSTRY_VIEW, WC_NONE,
   658 	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS | WDF_STICKY_BUTTON | WDF_RESIZABLE,
   680 	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS | WDF_STICKY_BUTTON | WDF_RESIZABLE,
   659 	_industry_view_widgets,
   681 	_industry_view_widgets,
   660 	NULL
       
   661 };
   682 };
   662 
   683 
   663 void ShowIndustryViewWindow(int industry)
   684 void ShowIndustryViewWindow(int industry)
   664 {
   685 {
   665 	AllocateWindowDescFront<IndustryViewWindow>(&_industry_view_desc, industry);
   686 	AllocateWindowDescFront<IndustryViewWindow>(&_industry_view_desc, industry);
   673 	IDW_SORTBYNAME,
   694 	IDW_SORTBYNAME,
   674 	IDW_SORTBYTYPE,
   695 	IDW_SORTBYTYPE,
   675 	IDW_SORTBYPROD,
   696 	IDW_SORTBYPROD,
   676 	IDW_SORTBYTRANSPORT,
   697 	IDW_SORTBYTRANSPORT,
   677 	IDW_SPACER,
   698 	IDW_SPACER,
   678 	IDW_INDUSRTY_LIST,
   699 	IDW_INDUSTRY_LIST,
   679 	IDW_SCROLLBAR,
   700 	IDW_SCROLLBAR,
   680 	IDW_RESIZE,
   701 	IDW_RESIZE,
   681 };
   702 };
   682 
   703 
   683 /** Widget definition of the industy directory gui */
   704 /** Widget definition of the industy directory gui */
   694 {  WWT_SCROLLBAR,    RESIZE_LRB,    13,   496,   507,    14,   177, 0x0,                     STR_0190_SCROLL_BAR_SCROLLS_LIST},  // IDW_SCROLLBAR
   715 {  WWT_SCROLLBAR,    RESIZE_LRB,    13,   496,   507,    14,   177, 0x0,                     STR_0190_SCROLL_BAR_SCROLLS_LIST},  // IDW_SCROLLBAR
   695 {  WWT_RESIZEBOX,   RESIZE_LRTB,    13,   496,   507,   178,   189, 0x0,                     STR_RESIZE_BUTTON},                 // IDW_RESIZE
   716 {  WWT_RESIZEBOX,   RESIZE_LRTB,    13,   496,   507,   178,   189, 0x0,                     STR_RESIZE_BUTTON},                 // IDW_RESIZE
   696 {   WIDGETS_END},
   717 {   WIDGETS_END},
   697 };
   718 };
   698 
   719 
   699 static uint _num_industry_sort;
       
   700 
       
   701 static char _bufcache[96];
   720 static char _bufcache[96];
   702 static const Industry* _last_industry;
   721 static const Industry* _last_industry;
   703 
   722 static int _internal_sort_order;
   704 static byte _industry_sort_order;
       
   705 
   723 
   706 static int CDECL GeneralIndustrySorter(const void *a, const void *b)
   724 static int CDECL GeneralIndustrySorter(const void *a, const void *b)
   707 {
   725 {
   708 	const Industry* i = *(const Industry**)a;
   726 	const Industry* i = *(const Industry**)a;
   709 	const Industry* j = *(const Industry**)b;
   727 	const Industry* j = *(const Industry**)b;
   710 	int r;
   728 	int r;
   711 
   729 
   712 	switch (_industry_sort_order >> 1) {
   730 	switch (_internal_sort_order >> 1) {
   713 		default: NOT_REACHED();
   731 		default: NOT_REACHED();
   714 		case 0: /* Sort by Name (handled later) */
   732 		case 0: /* Sort by Name (handled later) */
   715 			r = 0;
   733 			r = 0;
   716 			break;
   734 			break;
   717 
   735 
   774 			GetString(_bufcache, STR_TOWN, lastof(_bufcache));
   792 			GetString(_bufcache, STR_TOWN, lastof(_bufcache));
   775 		}
   793 		}
   776 		r = strcmp(buf1, _bufcache);
   794 		r = strcmp(buf1, _bufcache);
   777 	}
   795 	}
   778 
   796 
   779 	if (_industry_sort_order & 1) r = -r;
   797 	if (_internal_sort_order & 1) r = -r;
   780 	return r;
   798 	return r;
   781 }
   799 }
   782 
   800 
       
   801 typedef GUIList<const Industry*> GUIIndustryList;
       
   802 
   783 /**
   803 /**
   784  * Makes a sorted industry list.
   804  * Rebuild industries list if the VL_REBUILD flag is set
   785  * When there are no industries, the list has to be made. This so when one
   805  *
   786  * starts a new game without industries after playing a game with industries
   806  * @param sl pointer to industry list
   787  * the list is not populated with invalid industries from the previous game.
       
   788  */
   807  */
   789 static void MakeSortedIndustryList()
   808 static void BuildIndustriesList(GUIIndustryList *sl)
   790 {
   809 {
   791 	const Industry* i;
   810 	uint n = 0;
   792 	int n = 0;
   811 	const Industry *i;
       
   812 
       
   813 	if (!(sl->flags & VL_REBUILD)) return;
   793 
   814 
   794 	/* Create array for sorting */
   815 	/* Create array for sorting */
   795 	_industry_sort = ReallocT(_industry_sort, GetMaxIndustryIndex() + 1);
   816 	const Industry **industry_sort = MallocT<const Industry*>(GetMaxIndustryIndex() + 1);
   796 
   817 
   797 	/* Don't attempt a sort if there are no industries */
   818 	DEBUG(misc, 3, "Building industry list");
   798 	if (GetNumIndustries() != 0) {
   819 
   799 		FOR_ALL_INDUSTRIES(i) _industry_sort[n++] = i;
   820 	FOR_ALL_INDUSTRIES(i) industry_sort[n++] = i;
   800 		qsort((void*)_industry_sort, n, sizeof(_industry_sort[0]), GeneralIndustrySorter);
   821 
   801 	}
   822 	free((void*)sl->sort_list);
   802 
   823 	sl->sort_list = MallocT<const Industry*>(n);
   803 	_num_industry_sort = n;
   824 	sl->list_length = n;
   804 	_last_industry = NULL; // used for "cache"
   825 
   805 
   826 	for (uint i = 0; i < n; ++i) sl->sort_list[i] = industry_sort[i];
   806 	DEBUG(misc, 3, "Resorting industries list");
   827 
   807 }
   828 	sl->flags &= ~VL_REBUILD;
   808 
   829 	sl->flags |= VL_RESORT;
   809 
   830 	free((void*)industry_sort);
   810 static void IndustryDirectoryWndProc(Window *w, WindowEvent *e)
   831 }
   811 {
   832 
   812 	switch (e->event) {
   833 
   813 		case WE_PAINT: {
   834 /**
   814 			if (_industry_sort_dirty) {
   835  * Sort industry list if the VL_RESORT flag is set
   815 				_industry_sort_dirty = false;
   836  *
   816 				MakeSortedIndustryList();
   837  * @param sl pointer to industry list
   817 			}
   838  */
   818 
   839 static void SortIndustriesList(GUIIndustryList *sl)
   819 			SetVScrollCount(w, _num_industry_sort);
   840 {
   820 
   841 	if (!(sl->flags & VL_RESORT)) return;
   821 			DrawWindowWidgets(w);
   842 
   822 			DrawSortButtonState(w, IDW_SORTBYNAME + (_industry_sort_order >> 1), _industry_sort_order & 1 ? SBS_DOWN : SBS_UP);
   843 	_internal_sort_order = (sl->sort_type << 1) | (sl->flags & VL_DESC);
   823 
   844 	_last_industry = NULL; // used for "cache" in namesorting
   824 			uint pos = w->vscroll.pos;
   845 	qsort((void*)sl->sort_list, sl->list_length, sizeof(sl->sort_list[0]), &GeneralIndustrySorter);
   825 			int n = 0;
   846 
   826 
   847 	sl->flags &= ~VL_RESORT;
   827 			while (pos < _num_industry_sort) {
   848 }
   828 				const Industry* i = _industry_sort[pos];
   849 
   829 				const IndustrySpec *indsp = GetIndustrySpec(i->type);
   850 /**
   830 				byte p = 0;
   851  * The list of industries.
   831 
   852  */
   832 				/* Industry name */
   853 struct IndustryDirectoryWindow : public Window, public GUIIndustryList {
   833 				SetDParam(p++, i->index);
   854 	static Listing industry_sort;
   834 
   855 
   835 				/* Industry productions */
   856 	IndustryDirectoryWindow(const WindowDesc *desc, WindowNumber number) : Window(desc, number)
   836 				for (byte j = 0; j < lengthof(i->produced_cargo); j++) {
   857 	{
   837 					if (i->produced_cargo[j] == CT_INVALID) continue;
   858 		this->vscroll.cap = 16;
   838 					SetDParam(p++, i->produced_cargo[j]);
   859 		this->resize.height = this->height - 6 * 10; // minimum 10 items
   839 					SetDParam(p++, i->last_month_production[j]);
   860 		this->resize.step_height = 10;
   840 					SetDParam(p++, GetCargoSuffix(j + 3, CST_DIR, (Industry*)i, i->type, indsp));
   861 		this->FindWindowPlacementAndResize(desc);
   841 				}
   862 
   842 
   863 		this->sort_list = NULL;
   843 				/* Transported productions */
   864 		this->flags = VL_REBUILD;
   844 				for (byte j = 0; j < lengthof(i->produced_cargo); j++) {
   865 		this->sort_type = industry_sort.criteria;
   845 					if (i->produced_cargo[j] == CT_INVALID) continue;
   866 		if (industry_sort.order) this->flags |= VL_DESC;
   846 					SetDParam(p++, i->last_month_pct_transported[j] * 100 >> 8);
   867 	}
   847 				}
   868 
   848 
   869 	virtual void OnPaint()
   849 				/* Drawing the right string */
   870 	{
   850 				StringID str = STR_INDUSTRYDIR_ITEM_NOPROD;
   871 		BuildIndustriesList(this);
   851 				if (p != 1) str = (p == 5) ? STR_INDUSTRYDIR_ITEM : STR_INDUSTRYDIR_ITEM_TWO;
   872 		SortIndustriesList(this);
   852 				DrawStringTruncated(4, 28 + n * 10, str, TC_FROMSTRING, w->widget[IDW_INDUSRTY_LIST].right - 4);
   873 
   853 
   874 		SetVScrollCount(this, this->list_length);
   854 				pos++;
   875 
   855 				if (++n == w->vscroll.cap) break;
   876 		this->DrawWidgets();
   856 			}
   877 		this->DrawSortButtonState(IDW_SORTBYNAME + this->sort_type, this->flags & VL_DESC ? SBS_DOWN : SBS_UP);
   857 		} break;
   878 
   858 
   879 		int max = min(this->vscroll.pos + this->vscroll.cap, this->list_length);
   859 		case WE_CLICK:
   880 		int y = 28; // start of the list-widget
   860 			switch (e->we.click.widget) {
   881 
   861 				case IDW_SORTBYNAME: {
   882 		for (int n = this->vscroll.pos; n < max; ++n) {
   862 					_industry_sort_order = _industry_sort_order == 0 ? 1 : 0;
   883 			const Industry* i = this->sort_list[n];
   863 					_industry_sort_dirty = true;
   884 			const IndustrySpec *indsp = GetIndustrySpec(i->type);
   864 					w->SetDirty();
   885 			byte p = 0;
   865 				} break;
   886 
   866 
   887 			/* Industry name */
   867 				case IDW_SORTBYTYPE: {
   888 			SetDParam(p++, i->index);
   868 					_industry_sort_order = _industry_sort_order == 2 ? 3 : 2;
   889 
   869 					_industry_sort_dirty = true;
   890 			/* Industry productions */
   870 					w->SetDirty();
   891 			for (byte j = 0; j < lengthof(i->produced_cargo); j++) {
   871 				} break;
   892 				if (i->produced_cargo[j] == CT_INVALID) continue;
   872 
   893 				SetDParam(p++, i->produced_cargo[j]);
   873 				case IDW_SORTBYPROD: {
   894 				SetDParam(p++, i->last_month_production[j]);
   874 					_industry_sort_order = _industry_sort_order == 4 ? 5 : 4;
   895 				SetDParam(p++, GetCargoSuffix(j + 3, CST_DIR, (Industry*)i, i->type, indsp));
   875 					_industry_sort_dirty = true;
   896 			}
   876 					w->SetDirty();
   897 
   877 				} break;
   898 			/* Transported productions */
   878 
   899 			for (byte j = 0; j < lengthof(i->produced_cargo); j++) {
   879 				case IDW_SORTBYTRANSPORT: {
   900 				if (i->produced_cargo[j] == CT_INVALID) continue;
   880 					_industry_sort_order = _industry_sort_order == 6 ? 7 : 6;
   901 				SetDParam(p++, i->last_month_pct_transported[j] * 100 >> 8);
   881 					_industry_sort_dirty = true;
   902 			}
   882 					w->SetDirty();
   903 
   883 				} break;
   904 			/* Drawing the right string */
   884 
   905 			StringID str = STR_INDUSTRYDIR_ITEM_NOPROD;
   885 				case IDW_INDUSRTY_LIST: {
   906 			if (p != 1) str = (p == 5) ? STR_INDUSTRYDIR_ITEM : STR_INDUSTRYDIR_ITEM_TWO;
   886 					int y = (e->we.click.pt.y - 28) / 10;
   907 			DrawStringTruncated(4, y, str, TC_FROMSTRING, this->widget[IDW_INDUSTRY_LIST].right - 4);
   887 					uint16 p;
   908 
   888 
   909 			y += 10;
   889 					if (!IsInsideMM(y, 0, w->vscroll.cap)) return;
   910 		}
   890 					p = y + w->vscroll.pos;
   911 	}
   891 					if (p < _num_industry_sort) {
   912 
   892 						if (_ctrl_pressed) {
   913 	virtual void OnClick(Point pt, int widget)
   893 							ShowExtraViewPortWindow(_industry_sort[p]->xy);
   914 	{
   894 						} else {
   915 		switch (widget) {
   895 							ScrollMainWindowToTile(_industry_sort[p]->xy);
   916 			case IDW_SORTBYNAME:
   896 						}
   917 			case IDW_SORTBYTYPE:
       
   918 			case IDW_SORTBYPROD:
       
   919 			case IDW_SORTBYTRANSPORT:
       
   920 				if (this->sort_type == (widget - IDW_SORTBYNAME)) {
       
   921 					this->flags ^= VL_DESC;
       
   922 				} else {
       
   923 					this->sort_type = widget - IDW_SORTBYNAME;
       
   924 					this->flags &= ~VL_DESC;
       
   925 				}
       
   926 				industry_sort.criteria = this->sort_type;
       
   927 				industry_sort.order = HasBit(this->flags, 0);
       
   928 				this->flags |= VL_RESORT;
       
   929 				this->SetDirty();
       
   930 				break;
       
   931 
       
   932 			case IDW_INDUSTRY_LIST: {
       
   933 				int y = (pt.y - 28) / 10;
       
   934 				uint16 p;
       
   935 
       
   936 				if (!IsInsideMM(y, 0, this->vscroll.cap)) return;
       
   937 				p = y + this->vscroll.pos;
       
   938 				if (p < this->list_length) {
       
   939 					if (_ctrl_pressed) {
       
   940 						ShowExtraViewPortWindow(this->sort_list[p]->xy);
       
   941 					} else {
       
   942 						ScrollMainWindowToTile(this->sort_list[p]->xy);
   897 					}
   943 					}
   898 				} break;
   944 				}
   899 			}
   945 			} break;
   900 			break;
   946 		}
   901 
   947 	}
   902 		case WE_100_TICKS:
   948 
   903 			w->SetDirty();
   949 	virtual void OnResize(Point new_size, Point delta)
   904 			break;
   950 	{
   905 
   951 		this->vscroll.cap += delta.y / 10;
   906 		case WE_RESIZE:
   952 	}
   907 			w->vscroll.cap += e->we.sizing.diff.y / 10;
   953 
   908 			break;
   954 	virtual void OnInvalidateData(int data)
   909 	}
   955 	{
   910 }
   956 		this->flags |= (data == 0 ? VL_REBUILD : VL_RESORT);
       
   957 		this->InvalidateWidget(IDW_INDUSTRY_LIST);
       
   958 	}
       
   959 };
       
   960 
       
   961 Listing IndustryDirectoryWindow::industry_sort = {0, 0};
   911 
   962 
   912 /** Window definition of the industy directory gui */
   963 /** Window definition of the industy directory gui */
   913 static const WindowDesc _industry_directory_desc = {
   964 static const WindowDesc _industry_directory_desc = {
   914 	WDP_AUTO, WDP_AUTO, 508, 190, 508, 190,
   965 	WDP_AUTO, WDP_AUTO, 508, 190, 508, 190,
   915 	WC_INDUSTRY_DIRECTORY, WC_NONE,
   966 	WC_INDUSTRY_DIRECTORY, WC_NONE,
   916 	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS | WDF_STICKY_BUTTON | WDF_RESIZABLE,
   967 	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS | WDF_STICKY_BUTTON | WDF_RESIZABLE,
   917 	_industry_directory_widgets,
   968 	_industry_directory_widgets,
   918 	IndustryDirectoryWndProc
       
   919 };
   969 };
   920 
   970 
   921 void ShowIndustryDirectory()
   971 void ShowIndustryDirectory()
   922 {
   972 {
   923 	Window *w = AllocateWindowDescFront<Window>(&_industry_directory_desc, 0);
   973 	AllocateWindowDescFront<IndustryDirectoryWindow>(&_industry_directory_desc, 0);
   924 
   974 }
   925 	if (w != NULL) {
       
   926 		w->vscroll.cap = 16;
       
   927 		w->resize.height = w->height - 6 * 10; // minimum 10 items
       
   928 		w->resize.step_height = 10;
       
   929 		w->SetDirty();
       
   930 	}
       
   931 }