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 |
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 } |
|