aircraft_gui.c
changeset 164 0cbdf3c9bde1
parent 156 8fef5e5752d6
child 168 79f9ed5b23e6
--- a/aircraft_gui.c	Mon Sep 06 16:57:40 2004 +0000
+++ b/aircraft_gui.c	Mon Sep 06 18:15:13 2004 +0000
@@ -864,102 +864,175 @@
 	}
 }
 
+// used to get a sorted list of the vehicles
+static SortStruct _aircraft_sort[NUM_NORMAL_VEHICLES];
+static uint16 _num_aircraft_sort[MAX_PLAYERS];
+
+static void MakeSortedAircraftList(byte owner)
+{
+	SortStruct *firstelement;
+	Vehicle *v;
+	uint32 n = 0;
+	uint16 *i;
+
+	if (_vehicle_sort_dirty[VEHAIRCRAFT]) { // only resort the whole array if vehicles have been added/removed
+		// reset to 0 just to be sure
+		for (i = _num_aircraft_sort; i != endof(_num_aircraft_sort); i++) {*i = 0;}
+
+		FOR_ALL_VEHICLES(v) {
+			if(v->type == VEH_Aircraft && v->subtype <= 2) {
+				_aircraft_sort[n].index = v->index;
+				_aircraft_sort[n++].owner = v->owner;
+				_num_aircraft_sort[v->owner]++; // add number of aircraft of player
+			}
+		}
+
+		// create cumulative aircraft-ownage
+		// aircraft are stored as a cummulative index, eg 25, 41, 43. This means
+		// Player0: 25; Player1: (41-25) 16; Player2: (43-41) 2
+		for (i = &_num_aircraft_sort[1]; i != endof(_num_aircraft_sort); i++) {*i += *(i-1);}
+	
+
+		// sort by owner, then only subsort the requested owner-vehicles
+		qsort(_aircraft_sort, n, sizeof(_aircraft_sort[0]), GeneralOwnerSorter);
+
+		_last_vehicle_idx = 0; // used for "cache" in namesorting
+		_vehicle_sort_dirty[VEHAIRCRAFT] = false;
+	}
+
+	if (owner == 0) { // first element starts at 0th element and has n elements as described above
+		firstelement =	&_aircraft_sort[0];
+		n =							_num_aircraft_sort[0];
+	}	else { // nth element starts at the end of the previous one, and has n elements as described above
+		firstelement =	&_aircraft_sort[_num_aircraft_sort[owner-1]];
+		n =							_num_aircraft_sort[owner] - _num_aircraft_sort[owner-1];
+	}
+
+	_internal_sort_type				= _aircraft_sort_type[owner];
+	_internal_sort_order			= _aircraft_sort_order[owner];
+	_internal_name_sorter_id	= STR_SV_AIRCRAFT_NAME;
+	// only name sorting needs a different procedure, all others are handled by the general sorter
+	qsort(firstelement, n, sizeof(_aircraft_sort[0]), (_internal_sort_type == SORT_BY_NAME) ? VehicleNameSorter : GeneralVehicleSorter);
+
+	DEBUG(misc, 1) ("Resorting Aircraft list player %d...", owner+1);
+}
+
 static void PlayerAircraftWndProc(Window *w, WindowEvent *e)
 {
 	switch(e->event) {
-	case WE_PAINT:
-		/* determine amount of items for scroller */
-		{
-			Vehicle *v;
-			int num = 0;
-			byte owner = (byte)w->window_number;
+	case WE_PAINT: {
+		uint32 i;
+		const byte window_number = (byte)w->window_number;
 
-			FOR_ALL_VEHICLES(v) {
-				if (v->type == VEH_Aircraft && v->subtype <= 2 && v->owner == owner)
-					num++;
-			}
+		if (_aircraft_sort_type[window_number] == SORT_BY_UNSORTED) // disable 'Sort By' tooltip on Unsorted sorting criteria
+			w->disabled_state |= (1 << 3);
 
-			SetVScrollCount(w, num);
+		if (_aircraft_sort_dirty[window_number] || _vehicle_sort_dirty[VEHAIRCRAFT]) {
+			_aircraft_sort_dirty[window_number] = false;
+			MakeSortedAircraftList(window_number);
+			/* reset sorting timeout */
+			w->custom[0] = DAY_TICKS;
+			w->custom[1] = PERIODIC_RESORT_DAYS;
 		}
 
+		// aircraft are stored as a cummulative index, eg 25, 41, 43. This means
+		// Player0: 25; Player1: (41-25) 16; Player2: (43-41) 2 aircraft
+		i = (window_number == 0) ? 0 : _num_aircraft_sort[window_number-1];
+		SetVScrollCount(w, _num_aircraft_sort[window_number] - i);
+		
 		/* draw the widgets */
 		{
-			Player *p = DEREF_PLAYER(w->window_number);
+			Player *p = DEREF_PLAYER(window_number);
+			/* Company Name -- (###) Aircraft */
 			SET_DPARAM16(0, p->name_1);
 			SET_DPARAM32(1, p->name_2);
+			SET_DPARAM16(2, w->vscroll.count);
+			SET_DPARAM16(3, _vehicle_sort_listing[_aircraft_sort_type[window_number]]);
 			DrawWindowWidgets(w);
 		}
+		/* draw arrow pointing up/down for ascending/descending soring */
+		DoDrawString(_aircraft_sort_order[window_number] & 1 ? "\xAA" : "\xA0", 85, 15, 0x10);
 
 		/* draw the aircraft */
 		{
 			Vehicle *v;
-			int pos = w->vscroll.pos;
-			byte owner = (byte)w->window_number;
-			int x = 2;
-			int y = 15;
-
-			FOR_ALL_VEHICLES(v) {
-				if (v->type == VEH_Aircraft && v->subtype <= 2 && v->owner == owner &&
-						--pos < 0 && pos >= -4) {
-					StringID str;
-
-					DrawAircraftImage(v, x + 19, y + 6, INVALID_VEHICLE);
-					DrawVehicleProfitButton(v, x, y+13);
+			int n = 0;
+			const int x = 2;			// offset from left side of widget
+			int y = PLY_WND_PRC__OFFSET_TOP_WIDGET;	// offset from top of widget
+			i += w->vscroll.pos;	// offset from sorted aircraft list of current player
 
-					SET_DPARAM16(0, v->unitnumber);
-					if (IsAircraftHangarTile(v->tile)) {
-						str = STR_021F;
-					} else {
-						str = v->age > v->max_age - 366 ? STR_00E3 : STR_00E2;
-					}
-					DrawString(x, y+2, str, 0);
+			while (i < _num_aircraft_sort[window_number]) {
+				StringID str;
+				v = DEREF_VEHICLE(_aircraft_sort[i].index);
 
-					SET_DPARAM32(0, v->profit_this_year);
-					SET_DPARAM32(1, v->profit_last_year);
-					DrawString(x+19, y + 28, STR_0198_PROFIT_THIS_YEAR_LAST_YEAR, 0);
+				DrawAircraftImage(v, x + 19, y + 6, INVALID_VEHICLE);
+				DrawVehicleProfitButton(v, x, y+13);
 
-					if (v->string_id != STR_SV_AIRCRAFT_NAME) {
-						SET_DPARAM16(0, v->string_id);
-						DrawString(x+19, y, STR_01AB, 0);
-					}
+				SET_DPARAM16(0, v->unitnumber);
+				if (IsAircraftHangarTile(v->tile)) {
+					str = STR_021F;
+				} else {
+					str = v->age > v->max_age - 366 ? STR_00E3 : STR_00E2;
+				}
+				DrawString(x, y+2, str, 0);
 
-					DrawSmallSchedule(v, x+136, y);
 
-					y += 36;
+				SET_DPARAM32(0, v->profit_this_year);
+				SET_DPARAM32(1, v->profit_last_year);
+				DrawString(x+19, y + 28, STR_0198_PROFIT_THIS_YEAR_LAST_YEAR, 0);
+				
+				if (v->string_id != STR_SV_AIRCRAFT_NAME) {
+					SET_DPARAM16(0, v->string_id);
+					DrawString(x+19, y, STR_01AB, 0);
 				}
+
+				DrawSmallSchedule(v, x+136, y);
+
+				y += PLY_WND_PRC__SIZE_OF_ROW_BIG;
+				i++; // next aircraft
+				if (++n == w->vscroll.cap) { break;} // max number of aircraft in the window
 			}
 		}
-		break;
-
-	case WE_CLICK:
-		switch(e->click.widget) {
-		case 2: { /* click on aircraft */
-			int sel;
-			Vehicle *v;
-			byte owner;
-
-			sel = (e->click.pt.y - 14) / 36;
+		}	break;
 
-			if ((uint)sel >= 4)
-				break;
-			sel += w->vscroll.pos;
-			owner = (byte)w->window_number;
-			FOR_ALL_VEHICLES(v) {
-				if (v->type == VEH_Aircraft && v->subtype <= 2 && v->owner == owner &&
-						--sel < 0) {
-					ShowAircraftViewWindow(v);
-					break;
-				}
+	case WE_CLICK: {
+		switch(e->click.widget) {
+		case 3: /* Flip sorting method ascending/descending */
+			_aircraft_sort_order[(byte)w->window_number] ^= 1;
+			_aircraft_sort_dirty[(byte)w->window_number] = true;
+			SetWindowDirty(w);
+			break;
+		case 4: case 5:/* Select sorting criteria dropdown menu */
+			ShowDropDownMenu(w, _vehicle_sort_listing, _aircraft_sort_type[(byte)w->window_number], 5, 0); // do it for widget 5
+			return;
+		case 6: { /* Matrix to show vehicles */
+			int id_v = (e->click.pt.y - PLY_WND_PRC__OFFSET_TOP_WIDGET) / PLY_WND_PRC__SIZE_OF_ROW_BIG;
+			
+			if ((uint)id_v >= w->vscroll.cap) { return;} // click out of bounds
+
+			id_v += w->vscroll.pos;
+
+			{
+				byte owner		= (byte)w->window_number;
+				uint16 adder	= (owner == 0) ? 0 : _num_aircraft_sort[owner - 1]; // first element in list
+				Vehicle *v;
+
+				if (id_v + adder >= _num_aircraft_sort[owner]) { return;} // click out of vehicle bound
+
+				v	= DEREF_VEHICLE(_aircraft_sort[adder+id_v].index); // add the offset id_x to that
+
+				assert(v->type == VEH_Aircraft && v->subtype <= 2 && v->owner == owner && v->owner == _aircraft_sort[adder+id_v].owner);
+
+				ShowAircraftViewWindow(v);
 			}
-			break;
-		}
-		case 4: { /* build new */
+		} break;
+
+		case 8: { /* Build new Vehicle */
 			uint tile;
 
 			tile = _last_built_aircraft_depot_tile;
 			do {
-				if (_map_owner[tile] == _local_player &&
-						IsAircraftHangarTile(tile)) {
+				if (_map_owner[tile] == _local_player && IsAircraftHangarTile(tile)) {
 					ShowAircraftDepotWindow(tile);
 					ShowBuildAircraftWindow(tile);
 					return;
@@ -967,43 +1040,79 @@
 
 				tile = TILE_MASK(tile + 1);
 			} while(tile != _last_built_aircraft_depot_tile);
+
 			ShowBuildAircraftWindow(0);
 		} break;
 		}
+	}	break;
+
+	case WE_DROPDOWN_SELECT: /* we have selected a dropdown item in the list */
+		if (_aircraft_sort_type[(byte)w->window_number] != e->dropdown.index) // if value hasn't changed, dont resort list
+			_aircraft_sort_dirty[(byte)w->window_number] = true;
+
+		_aircraft_sort_type[(byte)w->window_number] = e->dropdown.index;
+
+		if (_aircraft_sort_type[(byte)w->window_number] != SORT_BY_UNSORTED) // enable 'Sort By' if a sorter criteria is chosen
+			w->disabled_state &= ~(1 << 3);
+
+		SetWindowDirty(w);
+		break;
+	case WE_CREATE: /* set up resort timer */
+		w->custom[0] = DAY_TICKS;
+		w->custom[1] = PERIODIC_RESORT_DAYS;
+		break;
+	case WE_TICK: /* resort the list every 20 seconds orso (10 days) */
+		if (--w->custom[0] == 0) {
+			w->custom[0] = DAY_TICKS;
+			if (--w->custom[1] == 0) {
+				w->custom[1] = PERIODIC_RESORT_DAYS;
+				_aircraft_sort_dirty[(byte)w->window_number] = true;
+				DEBUG(misc, 1) ("Periodic resort Aircraft list player %d...", w->window_number+1);
+				SetWindowDirty(w);
+			}
+		}
 		break;
 	}
 }
 
 static const Widget _player_aircraft_widgets[] = {
-{    WWT_TEXTBTN,    14,     0,    10,     0,    13, STR_00C5, STR_018B_CLOSE_WINDOW},
-{    WWT_CAPTION,    14,    11,   259,     0,    13, STR_A009_AIRCRAFT, STR_018C_WINDOW_TITLE_DRAG_THIS},
-{     WWT_MATRIX,    14,     0,   248,    14,   157, 0x401, STR_A01F_AIRCRAFT_CLICK_ON_AIRCRAFT},
-{  WWT_SCROLLBAR,    14,   249,   259,    14,   157, 0x0, STR_0190_SCROLL_BAR_SCROLLS_LIST},
-{ WWT_PUSHTXTBTN,    14,     0,   129,   158,   169, STR_A003_NEW_AIRCRAFT, STR_A020_BUILD_NEW_AIRCRAFT_REQUIRES},
-{     WWT_IMGBTN,    14,   130,   259,   158,   169, 0x0, 0},
+{   WWT_CLOSEBOX,    14,     0,    10,     0,    13, STR_00C5,							STR_018B_CLOSE_WINDOW},
+{    WWT_CAPTION,    14,    11,   259,     0,    13, STR_A009_AIRCRAFT,			STR_018C_WINDOW_TITLE_DRAG_THIS},
+{      WWT_PANEL,    14,     0,    15,    14,    25, 0x0,										0},
+{ WWT_PUSHTXTBTN,    14,    16,    96,    14,    25, SRT_SORT_BY,						STR_SORT_TIP},
+{    WWT_TEXTBTN,    14,    97,   248,    14,    25, STR_02E7,							0},
+{   WWT_CLOSEBOX,    14,   249,   259,    14,    25, STR_0225,							STR_SORT_TIP},
+{     WWT_MATRIX,    14,     0,   248,    26,   169, 0x401,									STR_A01F_AIRCRAFT_CLICK_ON_AIRCRAFT},
+{  WWT_SCROLLBAR,    14,   249,   259,    26,   169, 0x0,										STR_0190_SCROLL_BAR_SCROLLS_LIST},
+{ WWT_PUSHTXTBTN,    14,     0,   129,   170,   181, STR_A003_NEW_AIRCRAFT,	STR_A020_BUILD_NEW_AIRCRAFT_REQUIRES},
+{      WWT_PANEL,    14,   130,   259,   170,   181, 0x0,										0},
 {      WWT_LAST},
 };
 
 static const WindowDesc _player_aircraft_desc = {
-	-1, -1, 260, 170,
+	-1, -1, 260, 182,
 	WC_AIRCRAFT_LIST,0,
-	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS,
+	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS | WDF_RESTORE_DPARAM,
 	_player_aircraft_widgets,
 	PlayerAircraftWndProc
 };
 
 static const Widget _other_player_aircraft_widgets[] = {
-{    WWT_TEXTBTN,    14,     0,    10,     0,    13, STR_00C5, STR_018B_CLOSE_WINDOW},
-{    WWT_CAPTION,    14,    11,   259,     0,    13, STR_A009_AIRCRAFT, STR_018C_WINDOW_TITLE_DRAG_THIS},
-{     WWT_MATRIX,    14,     0,   248,    14,   157, 0x401, STR_A01F_AIRCRAFT_CLICK_ON_AIRCRAFT},
-{  WWT_SCROLLBAR,    14,   249,   259,    14,   157, 0x0, STR_0190_SCROLL_BAR_SCROLLS_LIST},
+{   WWT_CLOSEBOX,    14,     0,    10,     0,    13, STR_00C5,							STR_018B_CLOSE_WINDOW},
+{    WWT_CAPTION,    14,    11,   259,     0,    13, STR_A009_AIRCRAFT,			STR_018C_WINDOW_TITLE_DRAG_THIS},
+{      WWT_PANEL,    14,     0,    15,    14,    25, 0x0,										0},
+{ WWT_PUSHTXTBTN,    14,    16,    96,    14,    25, SRT_SORT_BY,						STR_SORT_TIP},
+{    WWT_TEXTBTN,    14,    97,   248,    14,    25, STR_02E7,							0},
+{   WWT_CLOSEBOX,    14,   249,   259,    14,    25, STR_0225,							STR_SORT_TIP},
+{     WWT_MATRIX,    14,     0,   248,    26,   169, 0x401,									STR_A01F_AIRCRAFT_CLICK_ON_AIRCRAFT},
+{  WWT_SCROLLBAR,    14,   249,   259,    26,   169, 0x0,										STR_0190_SCROLL_BAR_SCROLLS_LIST},
 {      WWT_LAST},
 };
 
 static const WindowDesc _other_player_aircraft_desc = {
-	-1, -1, 260, 158,
+	-1, -1, 260, 170,
 	WC_AIRCRAFT_LIST,0,
-	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET,
+	WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS | WDF_RESTORE_DPARAM,
 	_other_player_aircraft_widgets,
 	PlayerAircraftWndProc
 };
@@ -1012,7 +1121,7 @@
 {
 	Window *w;
 
-	if ( player == _local_player) {
+	if (player == _local_player) {
 		w = AllocateWindowDescFront(&_player_aircraft_desc, player);
 	} else  {
 		w = AllocateWindowDescFront(&_other_player_aircraft_desc, player);
@@ -1020,6 +1129,6 @@
 
 	if (w) {
 		w->caption_color = w->window_number;
-		w->vscroll.cap = 4;
+		w->vscroll.cap = 4; // maximum number of vehicles shown
 	}
 }