Changeset - r164:32c72e637930
[Not reviewed]
master
0 26 2
darkvater - 20 years ago 2004-09-06 18:15:13
darkvater@openttd.org
(svn r165) -Feature: Option to sort vehicles in vehicle-list window by different criteria. Total independent sort for all types and players. Periodic resort of list every 10 TTD days. Thank you for your graphical inspiration follow and buxo (since none of you provided any code).
-Fix: Sorter icon pointing down 'v' sorts in every window lowest value first, '^' highest value first
-CodeChange: move Dropdownlist from settings_gui.c to widget.c. More in place there.
28 files changed with 1284 insertions and 614 deletions:
0 comments (0 inline, 0 general)
Makefile
Show inline comments
 
@@ -446,7 +446,7 @@ ttd_SOURCES = \
 
	smallmap_gui.c sound.c spritecache.c station_cmd.c station_gui.c \
 
	strings.c subsidy_gui.c terraform_gui.c texteff.c town_cmd.c \
 
	town_gui.c train_cmd.c train_gui.c tree_cmd.c ttd.c tunnelbridge_cmd.c \
 
	unmovable_cmd.c vehicle.c viewport.c water_cmd.c widget.c window.c \
 
	unmovable_cmd.c vehicle.c vehicle_gui.c viewport.c water_cmd.c widget.c window.c \
 

	
 
ifdef WITH_SDL
 
ttd_SOURCES += sdl.c
aircraft_cmd.c
Show inline comments
 
@@ -336,6 +336,7 @@ int32 CmdBuildAircraft(int x, int y, uin
 
		}
 

	
 
		InvalidateWindow(WC_VEHICLE_DEPOT, v->tile);
 
		_vehicle_sort_dirty[VEHAIRCRAFT] = true; // build aircraft
 
		InvalidateWindow(WC_AIRCRAFT_LIST, v->owner);
 
		InvalidateWindow(WC_COMPANY, v->owner);
 
	}
 
@@ -367,6 +368,7 @@ static bool CheckStoppedInHangar(Vehicle
 
void DoDeleteAircraft(Vehicle *v)
 
{
 
	DeleteWindowById(WC_VEHICLE_VIEW, v->index);
 
	_vehicle_sort_dirty[VEHAIRCRAFT] = true; // delete aircraft
 
	InvalidateWindow(WC_AIRCRAFT_LIST, v->owner);
 
	InvalidateWindow(WC_COMPANY, v->owner);
 
	DeleteVehicleChain(v);
aircraft_gui.c
Show inline comments
 
@@ -864,102 +864,175 @@ static void DrawSmallSchedule(Vehicle *v
 
	}
 
}
 

	
 
// 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;
 

	
 
		if (_aircraft_sort_type[window_number] == SORT_BY_UNSORTED) // disable 'Sort By' tooltip on Unsorted sorting criteria
 
			w->disabled_state |= (1 << 3);
 

	
 
			FOR_ALL_VEHICLES(v) {
 
				if (v->type == VEH_Aircraft && v->subtype <= 2 && v->owner == owner)
 
					num++;
 
			}
 

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

	
 
			FOR_ALL_VEHICLES(v) {
 
				if (v->type == VEH_Aircraft && v->subtype <= 2 && v->owner == owner &&
 
						--pos < 0 && pos >= -4) {
 
					StringID str;
 
			while (i < _num_aircraft_sort[window_number]) {
 
				StringID str;
 
				v = DEREF_VEHICLE(_aircraft_sort[i].index);
 

	
 
					DrawAircraftImage(v, x + 19, y + 6, INVALID_VEHICLE);
 
					DrawVehicleProfitButton(v, x, y+13);
 
				DrawAircraftImage(v, x + 19, y + 6, INVALID_VEHICLE);
 
				DrawVehicleProfitButton(v, x, y+13);
 

	
 
					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);
 
				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);
 

	
 

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

	
 
					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);
 

	
 
					DrawSmallSchedule(v, x+136, y);
 

	
 
					y += 36;
 
				}
 
				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;
 
		}	break;
 

	
 
	case WE_CLICK:
 
	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;
 
		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
 

	
 
			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;
 
				}
 
			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 @@ static void PlayerAircraftWndProc(Window
 

	
 
				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 @@ void ShowPlayerAircraft(int player)
 
{
 
	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 @@ void ShowPlayerAircraft(int player)
 

	
 
	if (w) {
 
		w->caption_color = w->window_number;
 
		w->vscroll.cap = 4;
 
		w->vscroll.cap = 4; // maximum number of vehicles shown
 
	}
 
}
gui.h
Show inline comments
 
@@ -108,8 +108,6 @@ void ShowBuildIndustryWindow();
 
void ShowQueryString(StringID str, StringID caption, int maxlen, int maxwidth, byte window_class, uint16 window_number);
 
void ShowMusicWindow();
 

	
 
void DrawVehicleProfitButton(Vehicle *v, int x, int y);
 

	
 
/* main_gui.c */
 
VARDEF byte _newspaper_flag;
 
VARDEF byte _construct_mode;
industry_gui.c
Show inline comments
 
@@ -388,45 +388,44 @@ static byte _last_industry_idx;
 

	
 
static byte _industry_sort_order;
 

	
 
static int CDECL IndustrySorter(const void *a, const void *b)
 
static int CDECL GeneralIndustrySorter(const void *a, const void *b)
 
{
 
	char buf1[96];
 
	Industry *i, *j;
 
	byte val;
 
	Industry *i = DEREF_INDUSTRY(*(byte*)a);
 
	Industry *j = DEREF_INDUSTRY(*(byte*)b);
 
	int r = 0;
 

	
 
	i = DEREF_INDUSTRY(*(byte*)a);
 
	j = DEREF_INDUSTRY(*(byte*)b);
 

	
 
	switch (_industry_sort_order >> 1) {
 
	case 0: 
 
		r = 0; 
 
		break;
 
	case 1: /* Case 1, sort by type */
 
	/* case 0: Sort by Name (handled later) */
 
	case 1: /* Sort by Type */
 
		r = i->type - j->type; 
 
		break;
 
	case 2: /* Case 2, sort by production */
 
		if (i->produced_cargo[0] != 0xFF && j->produced_cargo[0] != 0xFF) { //producing any cargo?
 
				if (i->produced_cargo[1] == 0xFF) //producing one or two things?
 
	// FIXME - Production & Transported sort need to be inversed...but, WTF it does not wanna!
 
	// FIXME - And no simple --> "if (!(_industry_sort_order & 1)) r = -r;" hack at the bottom!!
 
	case 2: { /* Sort by Production */
 
		if (i->produced_cargo[0] != 0xFF && j->produced_cargo[0] != 0xFF) { // both industries produce cargo?
 
				if (i->produced_cargo[1] == 0xFF) // producing one or two things?
 
					r = j->total_production[0] - i->total_production[0];
 
				else	
 
					r = (j->total_production[0] + j->total_production[1]) / 2 - (i->total_production[0] + i->total_production[1]) / 2;
 
		} else if (i->produced_cargo[0] == 0xFF && j->produced_cargo[0] == 0xFF) //None of them producing anything, let them go to the name-sorting
 
		} else if (i->produced_cargo[0] == 0xFF && j->produced_cargo[0] == 0xFF) // none of them producing anything, let them go to the name-sorting
 
			r = 0;
 
		else if (i->produced_cargo[0] == 0xFF) //Non-producers, end up last/first in list
 
		else if (i->produced_cargo[0] == 0xFF) // end up the non-producer industry first/last in list
 
			r = 1;
 
		else
 
			r = -1;
 
		break;
 
	case 3: /* Case 3, sort by transportation */
 
		if (i->produced_cargo[0] != 0xFF && j->produced_cargo[0] != 0xFF) { //producing any cargo?
 
				if (i->produced_cargo[1] == 0xFF) //producing one or two things?
 
	}
 
	case 3: /* Sort by Transported amount */
 
		if (i->produced_cargo[0] != 0xFF && j->produced_cargo[0] != 0xFF) { // both industries produce cargo?
 
				if (i->produced_cargo[1] == 0xFF) // producing one or two things?
 
					r = (j->pct_transported[0] * 100 >> 8) - (i->pct_transported[0] * 100 >> 8);
 
				else 
 
					r = ((j->pct_transported[0] * 100 >> 8) + (j->pct_transported[1] * 100 >> 8)) / 2 - ((i->pct_transported[0] * 100 >> 8) + (i->pct_transported[1] * 100 >> 8)) / 2;
 
		} else if (i->produced_cargo[0] == 0xFF && j->produced_cargo[0] == 0xFF) //None of them producing anything, let them go to the name-sorting
 
		} else if (i->produced_cargo[0] == 0xFF && j->produced_cargo[0] == 0xFF) // none of them producing anything, let them go to the name-sorting
 
			r = 0;
 
		else if (i->produced_cargo[0] == 0xFF) //Non-producers, end up last/first in list
 
		else if (i->produced_cargo[0] == 0xFF) // end up the non-producer industry first/last in list
 
			r = 1;
 
		else
 
			r = -1;
 
@@ -446,9 +445,7 @@ static int CDECL IndustrySorter(const vo
 
		r = strcmp(buf1, _bufcache);
 
	}
 
	
 
	if (_industry_sort_order & 1)
 
		r = -r;
 
	
 
	if (_industry_sort_order & 1) r = -r;	
 
	return r;
 
}
 

	
 
@@ -464,7 +461,7 @@ static void MakeSortedIndustryList()
 
	_num_industry_sort = n;
 
	_last_industry_idx = 255; // used for "cache"
 

	
 
	qsort(_industry_sort, n, 1, IndustrySorter);
 
	qsort(_industry_sort, n, 1, GeneralIndustrySorter);
 

	
 
	DEBUG(misc, 1) ("Resorting Industries list...");
 
}
lang/english.txt
Show inline comments
 
@@ -352,9 +352,24 @@ STR_015E_QUIT_GAME								:Abandon game
 
STR_015F_QUIT											:Exit
 
STR_0160_ARE_YOU_SURE_YOU_WANT_TO	:{YELLOW}Are you sure you want to abandon this game?
 
STR_0161_QUIT_GAME								:{WHITE}Abandon Game
 
STR_SORT_TIP											:{BLACK}Select sorting order
 
STR_SORT_BY_NAME									:{BLACK}Name
 
STR_SORT_BY_DATE									:{BLACK}Date
 
STR_SORT_TIP											:{BLACK}Select sorting order descending/ascending
 
SRT_SORT_BY												:{BLACK}Sort by
 

	
 
STR_SORT_BY_POPULATION										:{BLACK}Population
 
STR_SORT_BY_PRODUCTION										:{BLACK}Production
 
STR_SORT_BY_TYPE													:{BLACK}Type
 
STR_SORT_BY_TRANSPORTED										:{BLACK}Transported
 
STR_SORT_BY_NAME													:{BLACK}Name
 
STR_SORT_BY_DROPDOWN_NAME									:Name
 
STR_SORT_BY_DATE													:{BLACK}Date
 
STR_SORT_BY_UNSORTED											:Unsorted
 
STR_SORT_BY_NUMBER												:Number
 
STR_SORT_BY_PROFIT_LAST_YEAR							:Profit last year
 
STR_SORT_BY_PROFIT_THIS_YEAR							:Profit this year
 
STR_SORT_BY_AGE														:Age
 
STR_SORT_BY_RELIABILITY										:Reliability
 
STR_SORT_BY_TOTAL_CAPACITY_PER_CARGOTYPE	:Total capacity per cargo type
 
STR_SORT_BY_MAX_SPEED											:Maximum speed
 

	
 
############ range for months starts
 
STR_0162_JAN							:Jan
 
@@ -843,8 +858,8 @@ STR_TOWNNAME_HUNGARIAN					:Hungarian
 
STR_TOWNNAME_AUSTRIAN					:Austrian
 
############ end of	townname region
 

	
 
STR_CURR_POUNDS							:Pounds ({POUNDSIGN})
 
STR_CURR_DOLLARS						:Dollars ($)
 
STR_CURR_POUNDS						:Pounds ({POUNDSIGN})
 
STR_CURR_DOLLARS					:Dollars ($)
 
STR_CURR_FF								:Franc (FF)
 
STR_CURR_DM								:Deutschmark (DM)
 
STR_CURR_YEN							:Yen ({YENSIGN})
 
@@ -1052,8 +1067,6 @@ STR_CHEAT_NO_JETCRASH					:{LTBLUE}Jetpl
 
STR_CHEAT_SWITCH_CLIMATE			:{LTBLUE}Switch climate: {ORANGE} {STRING}
 
STR_CHEAT_CHANGE_DATE					:{LTBLUE}Change date: {ORANGE} {DATE_SHORT}
 

	
 
STR_SORT_BY_POPULATION					:{BLACK}Population
 

	
 
STR_HEADING_FOR_CHECKPOINT				:{LTBLUE}Heading for {CHECKPOINT}
 
STR_HEADING_FOR_CHECKPOINT_VEL			:{LTBLUE}Heading for {CHECKPOINT}, {VELOCITY}
 

	
 
@@ -1136,9 +1149,6 @@ STR_CONSTRUCT_BUBBLE_GENERATOR_TIP		:{BL
 
STR_CONSTRUCT_TOFFEE_QUARRY_TIP			:{BLACK}Fund Toffee Quarry
 
STR_CONSTRUCT_SUGAR_MINE_TIP			:{BLACK}Construct Sugar Mine
 

	
 
STR_SORT_BY_PRODUCTION				:{BLACK}Production
 
STR_SORT_BY_TYPE					:{BLACK}Type
 
STR_SORT_BY_TRANSPORTED				:{BLACK}Transported
 
STR_INDUSTRYDIR_CAPTION					:{WHITE}Industries
 
STR_INDUSTRYDIR_ITEM					:{ORANGE}{TOWN} {STRING}{BLACK} ({STRING}){YELLOW} ({COMMA16}% transported)
 
STR_INDUSTRYDIR_ITEM_TWO				:{ORANGE}{TOWN} {STRING}{BLACK} ({STRING}/{STRING}){YELLOW} ({COMMA16}%/{COMMA16}% transported)
 
@@ -2228,7 +2238,7 @@ STR_8817_COST_WEIGHT_T_SPEED_POWER		:{BL
 
STR_8818_INFORMATION					:{BLACK}Information
 
STR_8819_TRAIN_TOO_LONG					:{WHITE}Train too long
 
STR_881A_TRAINS_CAN_ONLY_BE_ALTERED		:{WHITE}Trains can only be altered when stopped inside a depot
 
STR_881B_TRAINS							:{WHITE}{STRING} - Trains
 
STR_881B_TRAINS							:{WHITE}{STRING} - {COMMA16} Trains
 
STR_881C_NEW_RAIL_VEHICLES				:{WHITE}New Rail Vehicles
 
STR_881D_NEW_MONORAIL_VEHICLES			:{WHITE}New Monorail Vehicles
 
STR_881E_NEW_MAGLEV_VEHICLES			:{WHITE}New Maglev Vehicles
 
@@ -2319,7 +2329,7 @@ STR_TRAIN_STOPPING_VEL					:{RED}Stoppin
 

	
 
##id 0x9000
 
STR_9000_ROAD_VEHICLE_IN_THE_WAY		:{WHITE}Road vehicle in the way
 
STR_9001_ROAD_VEHICLES					:{WHITE}{STRING} - Road Vehicles
 
STR_9001_ROAD_VEHICLES					:{WHITE}{STRING} - {COMMA16} Road Vehicles
 
STR_9002								:{WHITE}{STRING}
 
STR_9003_ROAD_VEHICLE_DEPOT				:{WHITE}{TOWN} Road Vehicle Depot
 
STR_9004_NEW_VEHICLES					:{BLACK}New Vehicles
 
@@ -2384,7 +2394,7 @@ STR_9801_DOCK_CONSTRUCTION				:{WHITE}Do
 
STR_9802_CAN_T_BUILD_DOCK_HERE			:{WHITE}Can't build dock here...
 
STR_9803_SHIP_DEPOT						:{WHITE}{TOWN} Ship Depot
 
STR_9804_NEW_SHIPS						:{BLACK}New Ships
 
STR_9805_SHIPS							:{WHITE}{STRING} - Ships
 
STR_9805_SHIPS							:{WHITE}{STRING} - {COMMA16} Ships
 
STR_9806_CAN_T_BUILD_SHIPS				:{WHITE}Can't build ships...
 
STR_9807_MUST_BUILD_SHIP_DEPOT_FIRST	:{WHITE}Must build ship depot first
 
STR_9808_NEW_SHIPS						:{WHITE}New Ships
 
@@ -2460,7 +2470,7 @@ STR_A005_NEW_AIRCRAFT					:{WHITE}New Ai
 
STR_A006_BUILD_AIRCRAFT					:{BLACK}Build Aircraft
 
STR_A007_COST_SPEED_CAPACITY_PASSENGERS	:{BLACK}Cost: {GOLD}{CURRENCY}{BLACK} Speed: {GOLD}{VELOCITY}{}{BLACK}Capacity: {GOLD}{COMMA16} passengers, {COMMA16} bags of mail{}{BLACK}Running Cost: {GOLD}{CURRENCY}/yr{}{BLACK}Designed: {GOLD}{NUMU16}{BLACK}  Life: {GOLD}{COMMA16} years{}{BLACK}Max. Reliability: {GOLD}{COMMA8}%
 
STR_A008_CAN_T_BUILD_AIRCRAFT			:{WHITE}Can't build aircraft...
 
STR_A009_AIRCRAFT						:{WHITE}{STRING} - Aircraft
 
STR_A009_AIRCRAFT						:{WHITE}{STRING} - {COMMA16} Aircraft
 
STR_A00A								:{WHITE}{STRING}
 
STR_A00B_ORDERS							:{WHITE}{STRING} (Orders)
 
STR_A00C_DETAILS						:{WHITE}{STRING} (Details)
misc.c
Show inline comments
 
@@ -121,6 +121,7 @@ void InitializeGame()
 
	InitializeIndustries();
 
	
 
	InitializeNameMgr();
 
	InitializeVehiclesGuiList();
 
	InitializeTrains();
 

	
 
	InitializePlayers();
roadveh_cmd.c
Show inline comments
 
@@ -271,6 +271,7 @@ int32 CmdBuildRoadVeh(int x, int y, uint
 
		VehiclePositionChanged(v);
 

	
 
		InvalidateWindow(WC_VEHICLE_DEPOT, v->tile);
 
		_vehicle_sort_dirty[VEHROAD] = true; // build a new bus/truck
 
		InvalidateWindow(WC_ROADVEH_LIST, v->owner);
 
		InvalidateWindow(WC_COMPANY, v->owner);
 
	}
 
@@ -314,6 +315,7 @@ int32 CmdSellRoadVeh(int x, int y, uint3
 
	if (flags & DC_EXEC) {
 
		// Invalidate depot
 
		InvalidateWindow(WC_VEHICLE_DEPOT, v->tile);
 
		_vehicle_sort_dirty[VEHROAD] = true; // sell a bus/truck
 
		InvalidateWindow(WC_ROADVEH_LIST, v->owner);
 
		InvalidateWindow(WC_COMPANY, v->owner);
 
		DeleteWindowById(WC_VEHICLE_VIEW, v->index);
 
@@ -505,6 +507,7 @@ static void RoadVehDelete(Vehicle *v)
 
	DeleteWindowById(WC_VEHICLE_VIEW, v->index);
 
	InvalidateWindow(WC_VEHICLE_DETAILS, v->index);
 
		
 
	_vehicle_sort_dirty[VEHROAD] = true; // delete bus/truck (eg. crash for example)
 
	InvalidateWindow(WC_ROADVEH_LIST, v->owner);
 
	InvalidateWindow(WC_COMPANY, v->owner);
 

	
roadveh_gui.c
Show inline comments
 
@@ -9,7 +9,6 @@
 
#include "station.h"
 
#include "command.h"
 
#include "player.h"
 
//#include "town.h"
 
#include "engine.h"
 

	
 
extern const byte _roadveh_price[88];
 
@@ -704,100 +703,172 @@ void ShowRoadDepotWindow(uint tile)
 
	}
 
}
 

	
 
// used to get a sorted list of the vehicles
 
static SortStruct _road_sort[NUM_NORMAL_VEHICLES];
 
static uint16 _num_road_sort[MAX_PLAYERS];
 

	
 
static void MakeSortedRoadList(byte owner)
 
{
 
	SortStruct *firstelement;
 
	Vehicle *v;
 
	uint32 n = 0;
 
	uint16 *i;
 

	
 
	if (_vehicle_sort_dirty[VEHROAD]) { // only resort the whole array if vehicles have been added/removed
 
		// reset to 0 just to be sure
 
		for (i = _num_road_sort; i != endof(_num_road_sort); i++) {*i = 0;}
 

	
 
		FOR_ALL_VEHICLES(v) {
 
			if(v->type == VEH_Road) {
 
				_road_sort[n].index = v->index;
 
				_road_sort[n++].owner = v->owner;
 
				_num_road_sort[v->owner]++; // add number of roads of player
 
			}
 
		}
 

	
 
		// create cumulative road-ownage
 
		// roads 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_road_sort[1]; i != endof(_num_road_sort); i++) {*i += *(i-1);}
 
	
 

	
 
		// sort by owner, then only subsort the requested owner-vehicles
 
		qsort(_road_sort, n, sizeof(_road_sort[0]), GeneralOwnerSorter);
 

	
 
		_last_vehicle_idx = 0; // used for "cache" in namesorting
 
		_vehicle_sort_dirty[VEHROAD] = false;
 
	}
 

	
 
	if (owner == 0) { // first element starts at 0th element and has n elements as described above
 
		firstelement =	&_road_sort[0];
 
		n =							_num_road_sort[0];
 
	}	else { // nth element starts at the end of the previous one, and has n elements as described above
 
		firstelement =	&_road_sort[_num_road_sort[owner-1]];
 
		n =							_num_road_sort[owner] - _num_road_sort[owner-1];
 
	}
 

	
 
	_internal_sort_type				= _road_sort_type[owner];
 
	_internal_sort_order			= _road_sort_order[owner];
 
	_internal_name_sorter_id	= STR_SV_ROADVEH_NAME;
 
	// only name sorting needs a different procedure, all others are handled by the general sorter
 
	qsort(firstelement, n, sizeof(_road_sort[0]), (_internal_sort_type == SORT_BY_NAME) ? VehicleNameSorter : GeneralVehicleSorter);
 

	
 
	DEBUG(misc, 1) ("Resorting Roadvehicles list player %d...", owner+1);
 
}
 

	
 
static void PlayerRoadVehWndProc(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;
 

	
 
		if (_road_sort_type[window_number] == SORT_BY_UNSORTED) // disable 'Sort By' tooltip on Unsorted sorting criteria
 
			w->disabled_state |= (1 << 3);
 

	
 
			FOR_ALL_VEHICLES(v) {
 
				if (v->type == VEH_Road && v->owner == owner)
 
					num++;
 
			}
 
			SetVScrollCount(w, num);
 
		if (_road_sort_dirty[window_number] || _vehicle_sort_dirty[VEHROAD]) {
 
			_road_sort_dirty[window_number] = false;
 
			MakeSortedRoadList(window_number);
 
			/* reset sorting timeout */
 
			w->custom[0] = DAY_TICKS;
 
			w->custom[1] = PERIODIC_RESORT_DAYS;
 
		}
 

	
 
		// roads are stored as a cummulative index, eg 25, 41, 43. This means
 
		// Player0: 25; Player1: (41-25) 16; Player2: (43-41) 2 roads
 
		i = (window_number == 0) ? 0 : _num_road_sort[window_number-1];
 
		SetVScrollCount(w, _num_road_sort[window_number] - i);
 
		
 
		/* draw the widgets */
 
		{
 
			Player *p = DEREF_PLAYER(w->window_number);
 
			Player *p = DEREF_PLAYER(window_number);
 
			/* Company Name -- (###) Roadvehicles */
 
			SET_DPARAM16(0, p->name_1);
 
			SET_DPARAM32(1, p->name_2);
 
			SET_DPARAM16(2, w->vscroll.count);
 
			SET_DPARAM16(3, _vehicle_sort_listing[_road_sort_type[window_number]]);
 
			DrawWindowWidgets(w);
 
		}
 
		/* draw arrow pointing up/down for ascending/descending soring */
 
		DoDrawString(_road_sort_order[window_number] & 1 ? "\xAA" : "\xA0", 85, 15, 0x10);
 

	
 
		/* draw the road vehicles */
 
		/* draw the roadvehicles */
 
		{
 
			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_Road && v->owner == owner &&
 
						--pos < 0 && pos >= -7) {
 
					StringID str;
 
					
 
					DrawRoadVehImage(v, x + 22, y + 6, INVALID_VEHICLE);
 
					DrawVehicleProfitButton(v, x, y+13);
 
					
 
					SET_DPARAM16(0, v->unitnumber);
 
					if (IsRoadDepotTile(v->tile)) {
 
						str = STR_021F;
 
					} else {
 
						str = v->age > v->max_age - 366 ? STR_00E3 : STR_00E2;
 
					}
 
					DrawString(x, y+2, str, 0);
 
			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 roads list of current player
 

	
 
			while (i < _num_road_sort[window_number]) {
 
				StringID str;
 
				v = DEREF_VEHICLE(_road_sort[i].index);
 

	
 
				DrawRoadVehImage(v, x + 22, y + 6, INVALID_VEHICLE);
 
				DrawVehicleProfitButton(v, x, y+13);
 

	
 
					SET_DPARAM32(0, v->profit_this_year);
 
					SET_DPARAM32(1, v->profit_last_year);
 
					DrawString(x + 24, y + 18, STR_0198_PROFIT_THIS_YEAR_LAST_YEAR, 0);
 
					
 
					if (v->string_id != STR_SV_ROADVEH_NAME) {
 
						SET_DPARAM16(0, v->string_id);
 
						DrawString(x+24, y, STR_01AB, 0);
 
					}
 
					y += 26;
 
				}				
 
				SET_DPARAM16(0, v->unitnumber);
 
				if (IsRoadDepotTile(v->tile)) {
 
					str = STR_021F;
 
				} else {
 
					str = v->age > v->max_age - 366 ? STR_00E3 : STR_00E2;
 
				}
 
				DrawString(x, y+2, str, 0);
 

	
 
				SET_DPARAM32(0, v->profit_this_year);
 
				SET_DPARAM32(1, v->profit_last_year);
 
				DrawString(x + 24, y + 18, STR_0198_PROFIT_THIS_YEAR_LAST_YEAR, 0);
 
				
 
				if (v->string_id != STR_SV_ROADVEH_NAME) {
 
					SET_DPARAM16(0, v->string_id);
 
					DrawString(x+24, y, STR_01AB, 0);
 
				}
 

	
 
				y += PLY_WND_PRC__SIZE_OF_ROW_SMALL;
 
				i++; // next road
 
				if (++n == w->vscroll.cap) { break;} // max number of roads in the window
 
			}
 
		}
 
		break;
 

	
 
	case WE_CLICK:
 
		switch(e->click.widget) {
 
		case 2: {
 
			int idx = (e->click.pt.y - 14) / 26;
 
			Vehicle *v;
 
			byte owner;
 
		}	break;
 

	
 
			if ((uint)idx >= 7)
 
				break;
 

	
 
			idx += w->vscroll.pos;
 

	
 
			owner = (byte)w->window_number;
 
	case WE_CLICK: {
 
		switch(e->click.widget) {
 
		case 3: /* Flip sorting method ascending/descending */
 
			_road_sort_order[(byte)w->window_number] ^= 1;
 
			_road_sort_dirty[(byte)w->window_number] = true;
 
			SetWindowDirty(w);
 
			break;
 
		case 4: case 5:/* Select sorting criteria dropdown menu */
 
			ShowDropDownMenu(w, _vehicle_sort_listing, _road_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_SMALL;
 
			
 
			if ((uint)id_v >= w->vscroll.cap) { return;} // click out of bounds
 

	
 
			FOR_ALL_VEHICLES(v) {
 
				if (v->type == VEH_Road && v->owner == owner &&
 
						--idx < 0) {	
 
					ShowRoadVehViewWindow(v);
 
					break;
 
				}
 
			id_v += w->vscroll.pos;
 

	
 
			{
 
				byte owner		= (byte)w->window_number;
 
				uint16 adder	= (owner == 0) ? 0 : _num_road_sort[owner - 1]; // first element in list
 
				Vehicle *v;
 

	
 
				if (id_v + adder >= _num_road_sort[owner]) { return;} // click out of vehicle bound
 

	
 
				v	= DEREF_VEHICLE(_road_sort[adder+id_v].index); // add the offset id_x to that
 

	
 
				assert(v->type == VEH_Road && v->owner == owner && v->owner == _road_sort[adder+id_v].owner);
 

	
 
				ShowRoadVehViewWindow(v);
 
			}
 
		} break;
 

	
 
		case 4: {
 
		case 8: { /* Build new Vehicle */
 
			uint tile;
 

	
 
			tile = _last_built_road_depot_tile;
 
			do {
 
				if (_map_owner[tile] == _local_player &&
 
						IsRoadDepotTile(tile)) {
 
					
 
				if (_map_owner[tile] == _local_player && IsRoadDepotTile(tile)) {					
 
					ShowRoadDepotWindow(tile);
 
					ShowBuildRoadVehWindow(tile);
 
					return;
 
@@ -808,40 +879,76 @@ static void PlayerRoadVehWndProc(Window 
 
			
 
			ShowBuildRoadVehWindow(0);
 
		} break;
 
	} break;
 
		}
 
	}	break;
 

	
 
	case WE_DROPDOWN_SELECT: /* we have selected a dropdown item in the list */
 
		if (_road_sort_type[(byte)w->window_number] != e->dropdown.index) // if value hasn't changed, dont resort list
 
			_road_sort_dirty[(byte)w->window_number] = true;
 

	
 
		_road_sort_type[(byte)w->window_number] = e->dropdown.index;
 

	
 
		if (_road_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;
 
				_road_sort_dirty[(byte)w->window_number] = true;
 
				DEBUG(misc, 1) ("Periodic resort Roadvehicles list player %d...", w->window_number+1);
 
				SetWindowDirty(w);
 
			}
 
		}
 
		break;
 
	}
 
}
 

	
 
static const Widget _player_roadveh_widgets[] = {
 
{    WWT_TEXTBTN,    14,     0,    10,     0,    13, STR_00C5, STR_018B_CLOSE_WINDOW},
 
{    WWT_CAPTION,    14,    11,   259,     0,    13, STR_9001_ROAD_VEHICLES, STR_018C_WINDOW_TITLE_DRAG_THIS},
 
{     WWT_MATRIX,    14,     0,   248,    14,   195, 0x701, STR_901A_ROAD_VEHICLES_CLICK_ON},
 
{  WWT_SCROLLBAR,    14,   249,   259,    14,   195, 0x0, STR_0190_SCROLL_BAR_SCROLLS_LIST},
 
{ WWT_PUSHTXTBTN,    14,     0,   129,   196,   207, STR_9004_NEW_VEHICLES, STR_901B_BUILD_NEW_ROAD_VEHICLES},
 
{     WWT_IMGBTN,    14,   130,   259,   196,   207, 0x0, 0},
 
{   WWT_CLOSEBOX,    14,     0,    10,     0,    13, STR_00C5,								STR_018B_CLOSE_WINDOW},
 
{    WWT_CAPTION,    14,    11,   259,     0,    13, STR_9001_ROAD_VEHICLES,	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,   207, 0x701,										STR_901A_ROAD_VEHICLES_CLICK_ON},
 
{  WWT_SCROLLBAR,    14,   249,   259,    26,   207, 0x0,											STR_0190_SCROLL_BAR_SCROLLS_LIST},
 
{ WWT_PUSHTXTBTN,    14,     0,   129,   208,   219, STR_9004_NEW_VEHICLES, STR_901B_BUILD_NEW_ROAD_VEHICLES},
 
{     WWT_IMGBTN,    14,   130,   259,   208,   219, 0x0, 0},
 
{      WWT_LAST},
 
};
 

	
 
static const WindowDesc _player_roadveh_desc = {
 
	-1, -1, 260, 208,
 
	-1, -1, 260, 220,
 
	WC_ROADVEH_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_roadveh_widgets,
 
	PlayerRoadVehWndProc
 
};
 

	
 
static const Widget _other_player_roadveh_widgets[] = {
 
{    WWT_TEXTBTN,    14,     0,    10,     0,    13, STR_00C5, STR_018B_CLOSE_WINDOW},
 
{    WWT_CAPTION,    14,    11,   259,     0,    13, STR_9001_ROAD_VEHICLES, STR_018C_WINDOW_TITLE_DRAG_THIS},
 
{     WWT_MATRIX,    14,     0,   248,    14,   195, 0x701, STR_901A_ROAD_VEHICLES_CLICK_ON},
 
{  WWT_SCROLLBAR,    14,   249,   259,    14,   195, 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_9001_ROAD_VEHICLES,	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,   207, 0x701,										STR_901A_ROAD_VEHICLES_CLICK_ON},
 
{  WWT_SCROLLBAR,    14,   249,   259,    26,   207, 0x0,											STR_0190_SCROLL_BAR_SCROLLS_LIST},
 
{      WWT_LAST},
 
};
 

	
 
static const WindowDesc _other_player_roadveh_desc = {
 
	-1, -1, 260, 196,
 
	-1, -1, 260, 208,
 
	WC_ROADVEH_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_roadveh_widgets,
 
	PlayerRoadVehWndProc
 
};
settings_gui.c
Show inline comments
 
@@ -3,198 +3,14 @@
 

	
 
#include "window.h"
 
#include "gui.h"
 
#include "viewport.h"
 
#include "gfx.h"
 
#include "command.h"
 
#include "engine.h"
 

	
 
static uint32 _dropdown_disabled;
 
static const StringID *_dropdown_items;
 
static int _dropdown_selindex;
 
static uint _dropdown_item_count;
 
static byte _dropdown_button;
 
static WindowClass _dropdown_windowclass;
 
static WindowNumber _dropdown_windownum;
 
static byte _dropdown_var1;
 
static byte _dropdown_var2;
 

	
 
static uint32 _difficulty_click_a;
 
static uint32 _difficulty_click_b;
 
static byte _difficulty_timeout;
 

	
 
static Widget _dropdown_menu_widgets[] = {
 
{     WWT_IMGBTN,     0,     0, 0,     0, 0, 0x0},
 
{      WWT_LAST},
 
};
 

	
 
static int GetDropdownItem(Window *w)
 
{
 
	uint item;
 
	int y;
 

	
 
	if (GetWidgetFromPos(w, _cursor.pos.x - w->left, _cursor.pos.y - w->top) < 0)
 
		return -1;
 
	
 
	y = _cursor.pos.y - w->top - 2;
 

	
 
	if (y < 0)
 
		return - 1;
 

	
 
	item = y / 10;
 
	if (item >= _dropdown_item_count || HASBIT(_dropdown_disabled,item) || _dropdown_items[item] == 0)
 
		return - 1;
 

	
 
	return item;
 
}
 

	
 
void DropdownMenuWndProc(Window *w, WindowEvent *e)
 
{
 
	int item;
 

	
 
	switch(e->event) {
 
	case WE_PAINT: {
 
		int x,y,i,sel;
 
		uint32 dis;
 

	
 
		DrawWindowWidgets(w);
 

	
 
		x = 1;
 
		y = 2;
 
		sel = _dropdown_selindex;
 
		dis = _dropdown_disabled;
 

	
 
		for(i=0; _dropdown_items[i] != INVALID_STRING_ID; i++) {
 
			if (_dropdown_items[i] != 0) {
 
				if (sel == 0) {
 
					GfxFillRect(x+1, y, x+w->width-4, y + 9, 0);
 
				}
 
				DrawString(x+2, y, _dropdown_items[i], sel==0 ? 12 : 16);
 

	
 
				if (dis & 1) {
 
					GfxFillRect(x, y, x+w->width-3, y + 9, 0x8000 + 
 
						_color_list[_dropdown_menu_widgets[0].color].window_color_bga);
 
				}
 
			} else {
 
				int color_1 = _color_list[_dropdown_menu_widgets[0].color].window_color_1a;
 
				int color_2 = _color_list[_dropdown_menu_widgets[0].color].window_color_2;
 
				GfxFillRect(x+1, y+3, x+w->width-5, y+3, color_1);
 
				GfxFillRect(x+1, y+4, x+w->width-5, y+4, color_2);
 
			}
 
			y += 10;
 
			sel--;
 
			dis>>=1;
 
		}
 
	} break;
 

	
 
	case WE_CLICK: {
 
		item = GetDropdownItem(w);
 
		if (item >= 0) {
 
			_dropdown_var1 = 4;
 
			_dropdown_selindex = item;
 
			SetWindowDirty(w);
 
		}
 
	} break;
 

	
 
	case WE_MOUSELOOP: {
 
		Window *w2 = FindWindowById(_dropdown_windowclass, _dropdown_windownum);
 
		if (w2 == NULL) {
 
			DeleteWindow(w);
 
			return;
 
		}
 

	
 
		if (_dropdown_var1 != 0 && --_dropdown_var1 == 0) {
 
			WindowEvent e;
 
			e.event = WE_DROPDOWN_SELECT;
 
			e.dropdown.button = _dropdown_button;
 
			e.dropdown.index = _dropdown_selindex;
 
			w2->wndproc(w2, &e);
 
			DeleteWindow(w);
 
			return;
 
		}
 

	
 
		if (_dropdown_var2 != 0) {
 
			item = GetDropdownItem(w);
 

	
 
			if (!_left_button_clicked) {
 
				_dropdown_var2 = 0;
 
				if (item < 0)
 
					return;
 
				_dropdown_var1 = 2;
 
			} else {
 
				if (item < 0)
 
					return;
 
			}
 

	
 
			_dropdown_selindex = item;
 
			SetWindowDirty(w);
 
		}
 
	} break;
 
		
 
	case WE_DESTROY: {
 
		Window *w2 = FindWindowById(_dropdown_windowclass, _dropdown_windownum);
 
		if (w2 != NULL) {
 
			CLRBIT(w2->click_state, _dropdown_button);
 
			InvalidateWidget(w2, _dropdown_button);
 
		}
 
	} break;
 
	}
 
}
 

	
 
void ShowDropDownMenu(Window *w, const StringID *strings, int selected, int button, uint32 disabled_mask)
 
{
 
	WindowNumber num;
 
	WindowClass cls;
 
	int i,t1,t2;
 
	const Widget *wi;
 
	Window *w2;
 
	uint32 old_click_state = w->click_state;
 
	
 
	_dropdown_disabled = disabled_mask;
 

	
 
	cls = w->window_class;
 
	num = w->window_number;
 
	DeleteWindowById(WC_DROPDOWN_MENU, 0);
 
	w = FindWindowById(cls, num);
 

	
 
	if (HASBIT(old_click_state, button))
 
		return;
 

	
 
	SETBIT(w->click_state, button);
 

	
 
	InvalidateWidget(w, button);
 
	
 
	for(i=0;strings[i] != INVALID_STRING_ID;i++);
 
	if (i == 0)
 
		return;
 

	
 
	_dropdown_items = strings;
 
	_dropdown_item_count = i;
 
	_dropdown_selindex = selected;
 
	
 
	_dropdown_windowclass = w->window_class;
 
	_dropdown_windownum = w->window_number;
 
	_dropdown_button = button;
 
	
 
	_dropdown_var1 = 0;
 
	_dropdown_var2 = 1;
 

	
 
	wi = &w->widget[button];
 

	
 
	_dropdown_menu_widgets[0].color = wi->color;
 

	
 
	w2 = AllocateWindow(
 
		w->left + wi[-1].left + 1,
 
		w->top + wi->bottom + 2,
 
		(_dropdown_menu_widgets[0].right=t1=wi->right - wi[-1].left, t1 + 1), 
 
		(_dropdown_menu_widgets[0].bottom=t2=i*10+3, t2+1), 
 
		DropdownMenuWndProc,
 
		0x3F,
 
		_dropdown_menu_widgets);
 

	
 

	
 
	w2->flags4 &= ~WF_WHITE_BORDER_MASK;
 
}
 

	
 
extern const StringID _currency_string_list[];
 
extern uint GetMaskOfAllowedCurrencies();
 

	
ship_cmd.c
Show inline comments
 
@@ -852,6 +852,7 @@ int32 CmdBuildShip(int x, int y, uint32 
 
		VehiclePositionChanged(v);
 

	
 
		InvalidateWindow(WC_VEHICLE_DEPOT, v->tile);
 
		_vehicle_sort_dirty[VEHSHIP] = true; // build a ship
 
		InvalidateWindow(WC_SHIPS_LIST, v->owner);
 
		InvalidateWindow(WC_COMPANY, v->owner);
 
	}
 
@@ -875,6 +876,7 @@ int32 CmdSellShip(int x, int y, uint32 f
 
	
 
	if (flags & DC_EXEC) {
 
		InvalidateWindow(WC_VEHICLE_DEPOT, v->tile);
 
		_vehicle_sort_dirty[VEHSHIP] = true; // sell a ship
 
		InvalidateWindow(WC_SHIPS_LIST, v->owner);
 
		InvalidateWindow(WC_COMPANY, v->owner);
 
		DeleteWindowById(WC_VEHICLE_VIEW, v->index);
ship_gui.c
Show inline comments
 
@@ -9,7 +9,6 @@
 
#include "station.h"
 
#include "command.h"
 
#include "player.h"
 
//#include "town.h"
 
#include "engine.h"
 

	
 

	
 
@@ -868,100 +867,175 @@ static void DrawSmallShipSchedule(Vehicl
 
	}
 
}
 

	
 
// used to get a sorted list of the vehicles
 
static SortStruct _ship_sort[NUM_NORMAL_VEHICLES];
 
static uint16 _num_ship_sort[MAX_PLAYERS];
 

	
 
static void MakeSortedShiptList(byte owner)
 
{
 
	SortStruct *firstelement;
 
	Vehicle *v;
 
	uint32 n = 0;
 
	uint16 *i;
 

	
 
	if (_vehicle_sort_dirty[VEHSHIP]) { // only resort the whole array if vehicles have been added/removed
 
		// reset to 0 just to be sure
 
		for (i = _num_ship_sort; i != endof(_num_ship_sort); i++) {*i = 0;}
 

	
 
		FOR_ALL_VEHICLES(v) {
 
			if(v->type == VEH_Ship) {
 
				_ship_sort[n].index = v->index;
 
				_ship_sort[n++].owner = v->owner;
 
				_num_ship_sort[v->owner]++; // add number of trains of player
 
			}
 
		}
 

	
 
		// create cumulative ship-ownage
 
		// ships 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_ship_sort[1]; i != endof(_num_ship_sort); i++) {*i += *(i-1);}
 
	
 

	
 
		// sort by owner, then only subsort the requested owner-vehicles
 
		qsort(_ship_sort, n, sizeof(_ship_sort[0]), GeneralOwnerSorter);
 

	
 
		_last_vehicle_idx = 0; // used for "cache" in namesorting
 
		_vehicle_sort_dirty[VEHSHIP] = false;
 
	}
 

	
 
	if (owner == 0) { // first element starts at 0th element and has n elements as described above
 
		firstelement =	&_ship_sort[0];
 
		n =							_num_ship_sort[0];
 
	}	else { // nth element starts at the end of the previous one, and has n elements as described above
 
		firstelement =	&_ship_sort[_num_ship_sort[owner-1]];
 
		n =							_num_ship_sort[owner] - _num_ship_sort[owner-1];
 
	}
 

	
 
	_internal_sort_type				= _ship_sort_type[owner];
 
	_internal_sort_order			= _ship_sort_order[owner];
 
	_internal_name_sorter_id	= STR_SV_SHIP_NAME;
 
	// only name sorting needs a different procedure, all others are handled by the general sorter
 
	qsort(firstelement, n, sizeof(_ship_sort[0]), (_internal_sort_type == SORT_BY_NAME) ? VehicleNameSorter : GeneralVehicleSorter);
 

	
 
	DEBUG(misc, 1) ("Resorting Ships list player %d...", owner+1);
 
}
 

	
 
static void PlayerShipsWndProc(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;
 

	
 
		if (_ship_sort_type[window_number] == SORT_BY_UNSORTED) // disable 'Sort By' tooltip on Unsorted sorting criteria
 
			w->disabled_state |= (1 << 3);
 

	
 
			FOR_ALL_VEHICLES(v) {
 
				if (v->type == VEH_Ship && v->owner == owner)
 
					num++;
 
			}
 
			SetVScrollCount(w, num);
 
		if (_ship_sort_dirty[window_number] || _vehicle_sort_dirty[VEHSHIP]) {
 
			_ship_sort_dirty[window_number] = false;
 
			MakeSortedShiptList(window_number);
 
			/* reset sorting timeout */
 
			w->custom[0] = DAY_TICKS;
 
			w->custom[1] = PERIODIC_RESORT_DAYS;
 
		}
 

	
 
		// ships are stored as a cummulative index, eg 25, 41, 43. This means
 
		// Player0: 25; Player1: (41-25) 16; Player2: (43-41) 2 ships
 
		i = (window_number == 0) ? 0 : _num_ship_sort[window_number-1];
 
		SetVScrollCount(w, _num_ship_sort[window_number] - i);
 
		
 
		/* draw the widgets */
 
		{
 
			Player *p = DEREF_PLAYER(w->window_number);
 
			Player *p = DEREF_PLAYER(window_number);
 
			/* Company Name -- (###) Ships */
 
			SET_DPARAM16(0, p->name_1);
 
			SET_DPARAM32(1, p->name_2);
 
			SET_DPARAM16(2, w->vscroll.count);
 
			SET_DPARAM16(3, _vehicle_sort_listing[_ship_sort_type[window_number]]);
 
			DrawWindowWidgets(w);
 
		}
 
		/* draw arrow pointing up/down for ascending/descending soring */
 
		DoDrawString(_ship_sort_order[window_number] & 1 ? "\xAA" : "\xA0", 85, 15, 0x10);
 

	
 
		/* draw the ships vehicles */
 
		/* draw the ship vehicles */
 
		{
 
			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_Ship && v->owner == owner &&
 
						--pos < 0 && pos >= -4) {
 
					StringID str;
 
					
 
					DrawShipImage(v, x + 19, y + 6, INVALID_VEHICLE);
 
					DrawVehicleProfitButton(v, x, y+13);
 
					
 
					SET_DPARAM16(0, v->unitnumber);
 
					if (IsShipDepotTile(v->tile)) {
 
						str = STR_021F;
 
					} else {
 
						str = v->age > v->max_age - 366 ? STR_00E3 : STR_00E2;
 
					}
 
					DrawString(x, y+2, str, 0);
 
			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 ship list of current player
 

	
 
			while (i < _num_ship_sort[window_number]) {
 
				StringID str;
 
				v = DEREF_VEHICLE(_ship_sort[i].index);
 

	
 
				DrawShipImage(v, x + 19, y + 6, INVALID_VEHICLE);
 
				DrawVehicleProfitButton(v, x, y+13);
 

	
 
					SET_DPARAM32(0, v->profit_this_year);
 
					SET_DPARAM32(1, v->profit_last_year);
 
					DrawString(x + 12, y + 28, STR_0198_PROFIT_THIS_YEAR_LAST_YEAR, 0);
 
					
 
					if (v->string_id != STR_SV_SHIP_NAME) {
 
						SET_DPARAM16(0, v->string_id);
 
						DrawString(x+12, y, STR_01AB, 0);
 
					}
 
				SET_DPARAM16(0, v->unitnumber);
 
				if (IsShipDepotTile(v->tile)) {
 
					str = STR_021F;
 
				} else {
 
					str = v->age > v->max_age - 366 ? STR_00E3 : STR_00E2;
 
				}
 
				DrawString(x, y+2, str, 0);
 

	
 
					DrawSmallShipSchedule(v, x+138, y);
 
				SET_DPARAM32(0, v->profit_this_year);
 
				SET_DPARAM32(1, v->profit_last_year);
 
				DrawString(x + 12, y + 28, STR_0198_PROFIT_THIS_YEAR_LAST_YEAR, 0);
 
				
 
				if (v->string_id != STR_SV_SHIP_NAME) {
 
					SET_DPARAM16(0, v->string_id);
 
					DrawString(x+12, y, STR_01AB, 0);
 
				}
 

	
 
					y += 36;
 
				}				
 
				DrawSmallShipSchedule(v, x+138, y);
 

	
 

	
 
				y += PLY_WND_PRC__SIZE_OF_ROW_BIG;
 
				i++; // next ship
 
				if (++n == w->vscroll.cap) { break;} // max number of ships in the window
 
			}
 
		}
 
		break;
 
	case WE_CLICK:
 
		}	break;
 

	
 
	case WE_CLICK: {
 
		switch(e->click.widget) {
 
		case 2: { /* click ship */
 
			int sel;
 
			Vehicle *v;
 
			byte owner;
 
	
 
			sel = (e->click.pt.y - 14) / 36;
 
		case 3: /* Flip sorting method ascending/descending */
 
			_ship_sort_order[(byte)w->window_number] ^= 1;
 
			_ship_sort_dirty[(byte)w->window_number] = true;
 
			SetWindowDirty(w);
 
			break;
 
		case 4: case 5:/* Select sorting criteria dropdown menu */
 
			ShowDropDownMenu(w, _vehicle_sort_listing, _ship_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
 

	
 
			if ((uint)sel >= 4)
 
				break;
 
			sel += w->vscroll.pos;
 
			owner = (byte)w->window_number;
 
			FOR_ALL_VEHICLES(v) {
 
				if (v->type == VEH_Ship && v->owner == owner &&	--sel < 0) {	
 
					ShowShipViewWindow(v);
 
					break;
 
				}
 
			id_v += w->vscroll.pos;
 

	
 
			{
 
				byte owner		= (byte)w->window_number;
 
				uint16 adder	= (owner == 0) ? 0 : _num_ship_sort[owner - 1]; // first element in list
 
				Vehicle *v;
 

	
 
				if (id_v + adder >= _num_ship_sort[owner]) { return;} // click out of vehicle bound
 

	
 
				v	= DEREF_VEHICLE(_ship_sort[adder+id_v].index); // add the offset id_x to that
 

	
 
				assert(v->type == VEH_Ship && v->owner == owner && v->owner == _ship_sort[adder+id_v].owner);
 

	
 
				ShowShipViewWindow(v);
 
			}
 
			break;
 
		}
 
		case 4: {/* click buy */
 
		} break;
 

	
 
		case 8: { /* Build new Vehicle */
 
			uint tile;
 

	
 
			tile = _last_built_ship_depot_tile;
 
			do {
 
				if (_map_owner[tile] == _local_player &&
 
						IsShipDepotTile(tile)) {
 
					
 
				if (_map_owner[tile] == _local_player && IsShipDepotTile(tile)) {					
 
					ShowShipDepotWindow(tile);
 
					ShowBuildShipWindow(tile);
 
					return;
 
@@ -973,38 +1047,74 @@ static void PlayerShipsWndProc(Window *w
 
			ShowBuildShipWindow(0);
 
		} break;
 
		}
 
	}	break;
 

	
 
	case WE_DROPDOWN_SELECT: /* we have selected a dropdown item in the list */
 
		if (_ship_sort_type[(byte)w->window_number] != e->dropdown.index) // if value hasn't changed, dont resort list
 
			_ship_sort_dirty[(byte)w->window_number] = true;
 

	
 
		_ship_sort_type[(byte)w->window_number] = e->dropdown.index;
 

	
 
		if (_ship_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;
 
				_ship_sort_dirty[(byte)w->window_number] = true;
 
				DEBUG(misc, 1) ("Periodic resort Ships list player %d...", w->window_number+1);
 
				SetWindowDirty(w);
 
			}
 
		}
 
		break;
 
	}
 
}
 

	
 
static const Widget _player_ships_widgets[] = {
 
{    WWT_TEXTBTN,    14,     0,    10,     0,    13, STR_00C5, STR_018B_CLOSE_WINDOW},
 
{    WWT_CAPTION,    14,    11,   259,     0,    13, STR_9805_SHIPS, STR_018C_WINDOW_TITLE_DRAG_THIS},
 
{     WWT_MATRIX,    14,     0,   248,    14,   157, 0x401, STR_9823_SHIPS_CLICK_ON_SHIP_FOR},
 
{  WWT_SCROLLBAR,    14,   249,   259,    14,   157, 0x0, STR_0190_SCROLL_BAR_SCROLLS_LIST},
 
{ WWT_PUSHTXTBTN,    14,     0,   129,   158,   169, STR_9804_NEW_SHIPS, STR_9824_BUILD_NEW_SHIPS_REQUIRES},
 
{     WWT_IMGBTN,    14,   130,   259,   158,   169, 0x0},
 
{   WWT_CLOSEBOX,    14,     0,    10,     0,    13, STR_00C5,							STR_018B_CLOSE_WINDOW},
 
{    WWT_CAPTION,    14,    11,   259,     0,    13, STR_9805_SHIPS,				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_9823_SHIPS_CLICK_ON_SHIP_FOR},
 
{  WWT_SCROLLBAR,    14,   249,   259,    26,   169, 0x0,										STR_0190_SCROLL_BAR_SCROLLS_LIST},
 
{ WWT_PUSHTXTBTN,    14,     0,   129,   170,   181, STR_9804_NEW_SHIPS,		STR_9824_BUILD_NEW_SHIPS_REQUIRES},
 
{      WWT_PANEL,    14,   130,   259,   170,   181, 0x0,										0},
 
{      WWT_LAST},
 
};
 

	
 
static const WindowDesc _player_ships_desc = {
 
	-1, -1, 260, 170,
 
	-1, -1, 260, 182,
 
	WC_SHIPS_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_ships_widgets,
 
	PlayerShipsWndProc
 
};
 

	
 
static const Widget _other_player_ships_widgets[] = {
 
{    WWT_TEXTBTN,    14,     0,    10,     0,    13, STR_00C5, STR_018B_CLOSE_WINDOW},
 
{    WWT_CAPTION,    14,    11,   259,     0,    13, STR_9805_SHIPS, STR_018C_WINDOW_TITLE_DRAG_THIS},
 
{     WWT_MATRIX,    14,     0,   248,    14,   157, 0x401, STR_9823_SHIPS_CLICK_ON_SHIP_FOR},
 
{  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_9805_SHIPS,				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_9823_SHIPS_CLICK_ON_SHIP_FOR},
 
{  WWT_SCROLLBAR,    14,   249,   259,    26,   169, 0x0,										STR_0190_SCROLL_BAR_SCROLLS_LIST},
 
{      WWT_LAST},
 
};
 

	
 
static const WindowDesc _other_player_ships_desc = {
 
	-1, -1, 260, 158,
 
	-1, -1, 260, 170,
 
	WC_SHIPS_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,
 
	_other_player_ships_widgets,
 
	PlayerShipsWndProc
 
};
station_gui.c
Show inline comments
 
@@ -44,47 +44,37 @@ static void StationsWndShowStationRating
 
	}
 
}
 

	
 
// used to get a sorted list of the stations
 
typedef struct StationSort {
 
	uint16	index;
 
	byte		owner;
 
} StationSort;
 

	
 
static StationSort _station_sort[lengthof(_stations)];
 
static SortStruct _station_sort[lengthof(_stations)];
 
static uint16 _num_station_sort[MAX_PLAYERS];
 

	
 
static char _bufcache[64];
 
static uint16 _last_station_idx;
 

	
 
static int CDECL StationSorterByName(const void *a, const void *b)
 
static int CDECL StationNameSorter(const void *a, const void *b)
 
{
 
	char buf1[64];
 
	Station *st;
 
	StationSort *cmp1, *cmp2;
 
	cmp1 = (StationSort*)a;
 
	cmp2 = (StationSort*)b;
 
	SortStruct *cmp1, *cmp2;
 
	cmp1 = (SortStruct*)a;
 
	cmp2 = (SortStruct*)b;
 

	
 
	// sort stations by owner, and inside owner by name
 
	if (cmp1->owner == cmp2->owner) {	// if same owner, sort by name
 
		st = DEREF_STATION(cmp1->index);
 
	st = DEREF_STATION(cmp1->index);
 
	SET_DPARAM16(0, st->town->townnametype);
 
	SET_DPARAM32(1, st->town->townnameparts);
 
	GetString(buf1, st->string_id);
 

	
 
	if ( cmp2->index != _last_station_idx) {
 
		_last_station_idx = cmp2->index;
 
		st = DEREF_STATION(cmp2->index);
 
		SET_DPARAM16(0, st->town->townnametype);
 
		SET_DPARAM32(1, st->town->townnameparts);
 
		GetString(buf1, st->string_id);
 
		GetString(_bufcache, st->string_id);
 
	}
 

	
 
		if ( cmp2->index != _last_station_idx) {
 
			_last_station_idx = cmp2->index;
 
			st = DEREF_STATION(cmp2->index);
 
			SET_DPARAM16(0, st->town->townnametype);
 
			SET_DPARAM32(1, st->town->townnameparts);
 
			GetString(_bufcache, st->string_id);
 
		}
 

	
 
		return strcmp(buf1, _bufcache);	// sort by name
 
	}
 
	return cmp1->owner - cmp2->owner;	// sort by owner
 
	return strcmp(buf1, _bufcache);	// sort by name
 
}
 

	
 
static void MakeSortedStationList(Window *w)
 
static void MakeSortedStationList()
 
{
 
	Station *st;
 
	uint16 n = 0;
 
@@ -106,7 +96,11 @@ static void MakeSortedStationList(Window
 
	for (i = &_num_station_sort[1]; i != endof(_num_station_sort); i++) {*i += *(i-1);}
 

	
 
	_last_station_idx = 255; // used for "cache"
 
	qsort(_station_sort, n, sizeof(_station_sort[0]), StationSorterByName);
 

	
 
	// sort by owner, then only subsort the requested owner-vehicles
 
	qsort(_station_sort, n, sizeof(_station_sort[0]), GeneralOwnerSorter);
 

	
 
	qsort(_station_sort, n, sizeof(_station_sort[0]), StationNameSorter);
 
	
 
	DEBUG(misc, 1) ("Resorting Stations list...");
 
}
 
@@ -118,12 +112,12 @@ static void PlayerStationsWndProc(Window
 
		byte i;
 
		if (_station_sort_dirty) {
 
			_station_sort_dirty = false;
 
			MakeSortedStationList(w);
 
			MakeSortedStationList();
 
		}
 

	
 
		// stations are stored as a cummulative index, eg 25, 41, 43. This means
 
		// Player0: 25; Player1: (41-25) 16; Player2: (43-41) 2 stations
 
		i = (byte)(w->window_number == 0) ? 0 : _num_station_sort[w->window_number-1];;
 
		i = (byte)(w->window_number == 0) ? 0 : _num_station_sort[w->window_number-1];
 
		SetVScrollCount(w, _num_station_sort[w->window_number] - i);
 

	
 
		/* draw widgets, with player's name in the caption */
 
@@ -167,7 +161,7 @@ static void PlayerStationsWndProc(Window
 
				}
 
				y += 10;
 
				i++;	// next station
 
				if (++p == 12) { break;} // max number of stations in 1 window
 
				if (++p == w->vscroll.cap) { break;} // max number of stations in 1 window
 
			}
 
		}
 
	} break;
town_gui.c
Show inline comments
 
@@ -351,7 +351,7 @@ static uint _num_town_sort;
 
static char _bufcache[64];
 
static byte _last_town_idx;
 

	
 
static int CDECL TownSorterByName(const void *a, const void *b)
 
static int CDECL TownNameSorter(const void *a, const void *b)
 
{
 
	char buf1[64];
 
	Town *t;
 
@@ -374,11 +374,11 @@ static int CDECL TownSorterByName(const 
 
	return r;
 
}
 

	
 
static int CDECL TownSorterByPop(const void *a, const void *b)
 
static int CDECL TownPopSorter(const void *a, const void *b)
 
{
 
	Town *ta = DEREF_TOWN(*(byte*)a);
 
	Town *tb = DEREF_TOWN(*(byte*)b);
 
	int r = tb->population - ta->population;
 
	int r = ta->population - tb->population;
 
	if (_town_sort_order & 1) r = -r;
 
	return r;
 
}
 
@@ -391,7 +391,7 @@ static void MakeSortedTownList()
 
	_num_town_sort = n;
 

	
 
	_last_town_idx = 255; // used for "cache"
 
	qsort(_town_sort, n, 1, _town_sort_order & 2 ? TownSorterByPop : TownSorterByName);
 
	qsort(_town_sort, n, sizeof(_town_sort[0]), _town_sort_order & 2 ? TownPopSorter : TownNameSorter);
 

	
 
	DEBUG(misc, 1) ("Resorting Towns list...");
 
}
train_cmd.c
Show inline comments
 
@@ -496,6 +496,7 @@ int32 CmdBuildRailVehicle(int x, int y, 
 
			NormalizeTrainVehInDepot(v);
 

	
 
			InvalidateWindow(WC_VEHICLE_DEPOT, tile);
 
			_vehicle_sort_dirty[VEHTRAIN] = true; // build a trainengine
 
			InvalidateWindow(WC_TRAINS_LIST, v->owner);
 
			InvalidateWindow(WC_COMPANY, v->owner);
 
		}
 
@@ -793,7 +794,10 @@ int32 CmdSellRailWagon(int x, int y, uin
 
	if (flags & DC_EXEC) {
 
		// always redraw the depot. maybe redraw train list
 
		InvalidateWindow(WC_VEHICLE_DEPOT, first->tile);
 
		if (first->subtype == 0) InvalidateWindow(WC_TRAINS_LIST, first->owner);
 
		if (first->subtype == 0) {
 
			_vehicle_sort_dirty[VEHTRAIN] = true; // sell a wagon / locomotive
 
			InvalidateWindow(WC_TRAINS_LIST, first->owner);
 
		}
 
		// when selling an attached locomotive. we need to delete its window.
 
		if (v->subtype == 0) {
 
			DeleteWindowById(WC_VEHICLE_VIEW, v->index);
 
@@ -2198,6 +2202,7 @@ static void DeleteLastWagon(Vehicle *v)
 

	
 
	InvalidateWindow(WC_VEHICLE_DETAILS, v->index);
 
	DeleteWindowById(WC_VEHICLE_VIEW, v->index);
 
	_vehicle_sort_dirty[VEHTRAIN] = true; // remove crashed train
 
	InvalidateWindow(WC_TRAINS_LIST, v->owner);
 
	InvalidateWindow(WC_COMPANY, v->owner);
 

	
train_gui.c
Show inline comments
 
@@ -9,7 +9,6 @@
 
#include "station.h"
 
#include "command.h"
 
#include "player.h"
 
//#include "town.h"
 
#include "engine.h"
 

	
 
static Engine * const _rail_engines[3] = {
 
@@ -54,6 +53,7 @@ static void CcBuildWagon(bool success, u
 
		found = GetLastVehicleInChain(found);
 
		// put the new wagon at the end of the loco.
 
		DoCommandP(0, _new_wagon_id | (found->index<<16), 0, NULL, CMD_MOVE_RAIL_VEHICLE);
 
		_vehicle_sort_dirty[VEHTRAIN] = true;
 
	}
 
}
 

	
 
@@ -562,7 +562,6 @@ static const Widget _train_depot_widgets
 
{   WWT_CLOSEBOX,    14,     0,    10,     0,    13, STR_00C5,							STR_018B_CLOSE_WINDOW},
 
{    WWT_CAPTION,    14,    11,   348,     0,    13, STR_8800_TRAIN_DEPOT,	STR_018C_WINDOW_TITLE_DRAG_THIS},
 
{     WWT_MATRIX,    14,     0,   313,    14,    97, 0x601,									STR_883F_TRAINS_CLICK_ON_TRAIN_FOR},
 
//{      WWT_PANEL,    14,   314,   337,    14,   108, 0x2A9,									STR_8841_DRAG_TRAIN_VEHICLE_TO_HERE},
 
{      WWT_PANEL,    14,   314,   337,    14,    54, 0x2A9,									STR_8841_DRAG_TRAIN_VEHICLE_TO_HERE},
 
{      WWT_PANEL,    14,   314,   337,    55,   108, 0x2BF,									STR_DRAG_WHOLE_TRAIN_TO_SELL_TIP},
 

	
 
@@ -700,9 +699,6 @@ static void ShowRailVehicleRefitWindow(V
 
	WP(w,refit_d).sel = -1;
 
}
 

	
 

	
 

	
 

	
 
static Widget _train_view_widgets[] = {
 
{   WWT_CLOSEBOX,    14,     0,    10,     0,    13, STR_00C5, STR_018B_CLOSE_WINDOW},
 
{    WWT_CAPTION,    14,    11,   249,     0,    13, STR_882E, STR_018C_WINDOW_TITLE_DRAG_THIS},
 
@@ -1140,129 +1136,172 @@ void ShowTrainDetailsWindow(Vehicle *v)
 
	WP(w,traindetails_d).tab = 0;
 
}
 

	
 
// draw the vehicle profit button in the vehicle list window.
 
void DrawVehicleProfitButton(Vehicle *v, int x, int y)
 
// used to get a sorted list of the vehicles
 
static SortStruct _train_sort[NUM_NORMAL_VEHICLES];
 
static uint16 _num_train_sort[MAX_PLAYERS];
 

	
 
static void MakeSortedTrainList(byte owner)
 
{
 
	uint32 ormod;
 
	SortStruct *firstelement;
 
	Vehicle *v;
 
	uint32 n = 0;
 
	uint16 *i;
 

	
 
	if (_vehicle_sort_dirty[VEHTRAIN]) { // only resort the whole array if vehicles have been added/removed
 
		// reset to 0 just to be sure
 
		for (i = _num_train_sort; i != endof(_num_train_sort); i++) {*i = 0;}
 

	
 
		FOR_ALL_VEHICLES(v) {
 
			if(v->type == VEH_Train && v->subtype == 0) {
 
				_train_sort[n].index = v->index;
 
				_train_sort[n++].owner = v->owner;
 
				_num_train_sort[v->owner]++; // add number of trains of player
 
			}
 
		}
 

	
 
	// draw profit-based colored icons
 
	if(v->age <= 365 * 2)
 
		ormod = 0x3158000; // grey
 
	else if(v->profit_last_year < 0)
 
		ormod = 0x30b8000; //red
 
	else if(v->profit_last_year < 10000)
 
		ormod = 0x30a8000; // yellow
 
	else
 
		ormod = 0x30d8000; // green
 
	DrawSprite((SPR_OPENTTD_BASE + 10) | ormod, x, y);
 
		// create cumulative train-ownage
 
		// trains 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_train_sort[1]; i != endof(_num_train_sort); i++) {*i += *(i-1);}
 
	
 

	
 
		// sort by owner, then only subsort the requested owner-vehicles
 
		qsort(_train_sort, n, sizeof(_train_sort[0]), GeneralOwnerSorter);
 

	
 
		_last_vehicle_idx = 0; // used for "cache" in namesorting
 
		_vehicle_sort_dirty[VEHTRAIN] = false;
 
	}
 

	
 
	if (owner == 0) { // first element starts at 0th element and has n elements as described above
 
		firstelement =	&_train_sort[0];
 
		n =							_num_train_sort[0];
 
	}	else { // nth element starts at the end of the previous one, and has n elements as described above
 
		firstelement =	&_train_sort[_num_train_sort[owner-1]];
 
		n =							_num_train_sort[owner] - _num_train_sort[owner-1];
 
	}
 

	
 
	_internal_sort_type				= _train_sort_type[owner];
 
	_internal_sort_order			= _train_sort_order[owner];
 
	_internal_name_sorter_id	= STR_SV_TRAIN_NAME;
 
	// only name sorting needs a different procedure, all others are handled by the general sorter
 
	qsort(firstelement, n, sizeof(_train_sort[0]), (_internal_sort_type == SORT_BY_NAME) ? VehicleNameSorter : GeneralVehicleSorter);
 

	
 
	DEBUG(misc, 1) ("Resorting Trains list player %d...", owner+1);
 
}
 

	
 

	
 
static const StringID _player_trains_tooltips[] = {
 
	STR_018B_CLOSE_WINDOW,
 
	STR_018C_WINDOW_TITLE_DRAG_THIS,
 
	STR_883D_TRAINS_CLICK_ON_TRAIN_FOR,
 
	STR_0190_SCROLL_BAR_SCROLLS_LIST,
 
	STR_883E_BUILD_NEW_TRAINS_REQUIRES,
 
	0,
 
};
 

	
 
static void PlayerTrainsWndProc(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;
 

	
 
		if (_train_sort_type[window_number] == SORT_BY_UNSORTED) // disable 'Sort By' tooltip on Unsorted sorting criteria
 
			w->disabled_state |= (1 << 3);
 

	
 
			FOR_ALL_VEHICLES(v) {
 
				if (v->type == VEH_Train && v->subtype == 0 && v->owner == owner)
 
					num++;
 
			}
 
		if (_train_sort_dirty[window_number] || _vehicle_sort_dirty[VEHTRAIN]) {
 
			_train_sort_dirty[window_number] = false;
 
			MakeSortedTrainList(window_number);
 
			/* reset sorting timeout */
 
			w->custom[0] = DAY_TICKS;
 
			w->custom[1] = PERIODIC_RESORT_DAYS;
 
		}
 

	
 
			SetVScrollCount(w, num);
 
		}
 
		// Trains are stored as a cummulative index, eg 25, 41, 43. This means
 
		// Player0: 25; Player1: (41-25) 16; Player2: (43-41) 2 trains
 
		i = (window_number == 0) ? 0 : _num_train_sort[window_number-1];
 
		SetVScrollCount(w, _num_train_sort[window_number] - i);
 
		
 
		/* draw the widgets */
 
		{
 
			Player *p = DEREF_PLAYER(w->window_number);
 
			Player *p = DEREF_PLAYER(window_number);
 
			/* Company Name -- (###) Trains */
 
			SET_DPARAM16(0, p->name_1);
 
			SET_DPARAM32(1, p->name_2);
 
			SET_DPARAM16(2, w->vscroll.count);
 
			SET_DPARAM16(3, _vehicle_sort_listing[_train_sort_type[window_number]]);
 
			DrawWindowWidgets(w);
 
		}
 
		/* draw arrow pointing up/down for ascending/descending soring */
 
		DoDrawString(_train_sort_order[window_number] & 1 ? "\xAA" : "\xA0", 150, 15, 0x10);
 

	
 
		/* draw the trains */
 
		{
 
			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_Train && v->subtype == 0 && v->owner == owner &&
 
						--pos < 0 && pos >= -7) {
 
					StringID str;
 
					
 
					DrawTrainImage(v, x + 21, y + 6, 10, 0, INVALID_VEHICLE);
 
					DrawVehicleProfitButton(v, x, y+13);
 
					
 
					SET_DPARAM16(0, v->unitnumber);
 
					if (IsTrainDepotTile(v->tile)) {
 
						str = STR_021F;
 
					} else {
 
						str = v->age > v->max_age - 366 ? STR_00E3 : STR_00E2;
 
					}
 
					DrawString(x, y+2, str, 0);
 
			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 trains list of current player
 

	
 
			while (i < _num_train_sort[window_number]) {
 
				StringID str;
 
				v = DEREF_VEHICLE(_train_sort[i].index);
 

	
 
				DrawTrainImage(v, x + 21, y + 6, 10, 0, INVALID_VEHICLE);
 
				DrawVehicleProfitButton(v, x, y+13);
 

	
 
					SET_DPARAM32(0, v->profit_this_year);
 
					SET_DPARAM32(1, v->profit_last_year);
 
					DrawString(x + 21, y + 18, STR_0198_PROFIT_THIS_YEAR_LAST_YEAR, 0);
 
					
 
					if (v->string_id != STR_SV_TRAIN_NAME) {
 
						SET_DPARAM16(0, v->string_id);
 
						DrawString(x+21, y, STR_01AB, 0);
 
					}
 
				SET_DPARAM16(0, v->unitnumber);
 
				if (IsTrainDepotTile(v->tile)) {
 
					str = STR_021F;
 
				} else {
 
					str = v->age > v->max_age - 366 ? STR_00E3 : STR_00E2;
 
				}
 
				DrawString(x, y+2, str, 0);
 

	
 
					y += 26;
 
				}				
 
				SET_DPARAM32(0, v->profit_this_year);
 
				SET_DPARAM32(1, v->profit_last_year);
 
				DrawString(x + 21, y + 18, STR_0198_PROFIT_THIS_YEAR_LAST_YEAR, 0);
 
				
 
				if (v->string_id != STR_SV_TRAIN_NAME) {
 
					SET_DPARAM16(0, v->string_id);
 
					DrawString(x+21, y, STR_01AB, 0);
 
				}
 

	
 
				y += PLY_WND_PRC__SIZE_OF_ROW_SMALL;
 
				i++; // next train
 
				if (++n == w->vscroll.cap) { break;} // max number of trains in the window
 
			}
 
		}
 
		break;
 
		}	break;
 

	
 
	case WE_CLICK: {
 
		switch(e->click.widget) {
 
		case 2: {
 
			int idx = (e->click.pt.y - 0xE) / 26;
 
			Vehicle *v;
 
			byte owner;
 

	
 
			if ((uint)idx >= 7)
 
				break;
 
		case 3: /* Flip sorting method ascending/descending */
 
			_train_sort_order[(byte)w->window_number] ^= 1;
 
			_train_sort_dirty[(byte)w->window_number] = true;
 
			SetWindowDirty(w);
 
			break;
 
		case 4: case 5:/* Select sorting criteria dropdown menu */
 
			ShowDropDownMenu(w, _vehicle_sort_listing, _train_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_SMALL;
 
			
 
			if ((uint)id_v >= w->vscroll.cap) { return;} // click out of bounds
 

	
 
			idx += w->vscroll.pos;
 
			id_v += w->vscroll.pos;
 

	
 
			owner = (byte)w->window_number;
 
			{
 
				byte owner		= (byte)w->window_number;
 
				uint16 adder	= (owner == 0) ? 0 : _num_train_sort[owner - 1]; // first element in list
 
				Vehicle *v;
 

	
 
			FOR_ALL_VEHICLES(v) {
 
				if (v->type == VEH_Train && v->subtype == 0 && v->owner == owner &&
 
						--idx < 0) {	
 
					ShowTrainViewWindow(v);
 
					break;
 
				}
 
				if (id_v + adder >= _num_train_sort[owner]) { return;} // click out of vehicle bound
 

	
 
				v	= DEREF_VEHICLE(_train_sort[adder+id_v].index); // add the offset id_x to that
 

	
 
				assert(v->type == VEH_Train && v->subtype == 0 && v->owner == owner && v->owner == _train_sort[adder+id_v].owner);
 

	
 
				ShowTrainViewWindow(v);
 
			}
 
		} break;
 

	
 
		case 4: {
 
		case 8: { /* Build new Vehicle */
 
			uint tile;
 

	
 
			tile = _last_built_train_depot_tile;
 
			do {
 
				if (_map_owner[tile] == _local_player &&
 
						IsTrainDepotTile(tile)) {
 
					
 
				if (_map_owner[tile] == _local_player && IsTrainDepotTile(tile)) {			
 
					ShowTrainDepotWindow(tile);
 
					ShowBuildTrainWindow(tile);
 
					return;
 
@@ -1276,39 +1315,73 @@ static void PlayerTrainsWndProc(Window *
 
		}
 
	}	break;
 

	
 
	case WE_DROPDOWN_SELECT: /* we have selected a dropdown item in the list */
 
		if (_train_sort_type[(byte)w->window_number] != e->dropdown.index) // if value hasn't changed, dont resort list
 
			_train_sort_dirty[(byte)w->window_number] = true;
 

	
 
		_train_sort_type[(byte)w->window_number] = e->dropdown.index;
 

	
 
		if (_train_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;
 
				_train_sort_dirty[(byte)w->window_number] = true;
 
				DEBUG(misc, 1) ("Periodic resort Trains list player %d...", w->window_number+1);
 
				SetWindowDirty(w);
 
			}
 
		}
 
		break;
 
	}
 
}
 

	
 
static const Widget _player_trains_widgets[] = {
 
{   WWT_CLOSEBOX,    14,     0,    10,     0,    13, STR_00C5,							STR_018B_CLOSE_WINDOW},
 
{    WWT_CAPTION,    14,    11,   324,     0,    13, STR_881B_TRAINS,				STR_018C_WINDOW_TITLE_DRAG_THIS},
 
{     WWT_MATRIX,    14,     0,   313,    14,   195, 0x701,									STR_883D_TRAINS_CLICK_ON_TRAIN_FOR},
 
{  WWT_SCROLLBAR,    14,   314,   324,    14,   195, 0x0,										STR_0190_SCROLL_BAR_SCROLLS_LIST},
 
{ WWT_PUSHTXTBTN,    14,     0,   161,   196,   207, STR_8815_NEW_VEHICLES,	STR_883E_BUILD_NEW_TRAINS_REQUIRES},
 
{      WWT_PANEL,    14,   162,   324,   196,   207, 0x0,										0},
 
{      WWT_PANEL,    14,     0,    80,    14,    25, 0x0,										0},
 
{ WWT_PUSHTXTBTN,    14,    81,   161,    14,    25, SRT_SORT_BY,           STR_SORT_TIP},
 
{    WWT_TEXTBTN,    14,   162,   313,    14,    25, STR_02E7,              0},
 
{   WWT_CLOSEBOX,    14,   314,   324,    14,    25, STR_0225,              STR_SORT_TIP},
 
{     WWT_MATRIX,    14,     0,   313,    26,   207, 0x701,									STR_883D_TRAINS_CLICK_ON_TRAIN_FOR},
 
{  WWT_SCROLLBAR,    14,   314,   324,    26,   207, 0x0,										STR_0190_SCROLL_BAR_SCROLLS_LIST},
 
{ WWT_PUSHTXTBTN,    14,     0,   161,   208,   219, STR_8815_NEW_VEHICLES,	STR_883E_BUILD_NEW_TRAINS_REQUIRES},
 
{      WWT_PANEL,    14,   162,   324,   208,   219, 0x0,										0},
 
{      WWT_LAST},
 
};
 

	
 
static const WindowDesc _player_trains_desc = {
 
	-1, -1, 325, 208,
 
	-1, -1, 325, 220,
 
	WC_TRAINS_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_trains_widgets,
 
	PlayerTrainsWndProc
 
};
 

	
 
static const Widget _other_player_trains_widgets[] = {
 
{   WWT_CLOSEBOX,    14,     0,    10,     0,    13, STR_00C5,				STR_018B_CLOSE_WINDOW},
 
{    WWT_CAPTION,    14,    11,   324,     0,    13, STR_881B_TRAINS,	STR_018C_WINDOW_TITLE_DRAG_THIS},
 
{     WWT_MATRIX,    14,     0,   313,    14,   195, 0x701,						STR_883D_TRAINS_CLICK_ON_TRAIN_FOR},
 
{  WWT_SCROLLBAR,    14,   314,   324,    14,   195, 0x0,							STR_0190_SCROLL_BAR_SCROLLS_LIST},
 
{   WWT_CLOSEBOX,    14,     0,    10,     0,    13, STR_00C5,							STR_018B_CLOSE_WINDOW},
 
{    WWT_CAPTION,    14,    11,   324,     0,    13, STR_881B_TRAINS,				STR_018C_WINDOW_TITLE_DRAG_THIS},
 
{      WWT_PANEL,    14,     0,    80,    14,    25, 0x0,										0},
 
{ WWT_PUSHTXTBTN,    14,    81,   161,    14,    25, SRT_SORT_BY,           STR_SORT_TIP},
 
{    WWT_TEXTBTN,    14,   162,   313,    14,    25, STR_02E7,              0},
 
{   WWT_CLOSEBOX,    14,   314,   324,    14,    25, STR_0225,              STR_SORT_TIP},
 
{     WWT_MATRIX,    14,     0,   313,    26,   207, 0x701,									STR_883D_TRAINS_CLICK_ON_TRAIN_FOR},
 
{  WWT_SCROLLBAR,    14,   314,   324,    26,   207, 0x0,										STR_0190_SCROLL_BAR_SCROLLS_LIST},
 
{      WWT_LAST},
 
};
 

	
 
static const WindowDesc _other_player_trains_desc = {
 
	-1, -1, 325, 196,
 
	-1, -1, 325, 208,
 
	WC_TRAINS_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_trains_widgets,
 
	PlayerTrainsWndProc
 
};
 
@@ -1317,13 +1390,13 @@ void ShowPlayerTrains(int player)
 
{
 
	Window *w;
 

	
 
	if ( player == _local_player) {
 
	if (player == _local_player) {
 
		w = AllocateWindowDescFront(&_player_trains_desc, player);
 
	} else  {
 
	} else {
 
		w = AllocateWindowDescFront(&_other_player_trains_desc, player);
 
	}
 
	if (w) {
 
		w->caption_color = w->window_number;
 
		w->vscroll.cap = 7;
 
		w->vscroll.cap = 7; // maximum number of vehicles shown
 
	}
 
}
ttd.dsp
Show inline comments
 
@@ -358,6 +358,10 @@ SOURCE=.\vehicle.c
 
# End Source File
 
# Begin Source File
 
 
SOURCE=.\vehicle_gui.c
 
# End Source File
 
# Begin Source File
 
 
SOURCE=.\viewport.c
 
# End Source File
 
# Begin Source File
 
@@ -502,6 +506,10 @@ SOURCE=.\vehicle.h
 
# End Source File
 
# Begin Source File
 
 
SOURCE=.\vehicle_gui.h
 
# End Source File
 
# Begin Source File
 
 
SOURCE=.\viewport.h
 
# End Source File
 
# Begin Source File
ttd.h
Show inline comments
 
@@ -32,6 +32,16 @@ typedef struct YearMonthDay {
 
	int year, month, day;
 
} YearMonthDay;
 

	
 
/* --- 1 Day is 74 ticks ---
 
* The game's internal structure is dictated by ticks. The date counter (date_fract) is an integer of
 
* uint16 type, so it can have a max value of 65536. Every tick this variable (date_fract) is 
 
* increased by 885. When it overflows, the new day loop is called. 
 
* * this that means 1 day is : 65536 / 885 = 74 ticks
 
* * 1 tick is approximately 27ms. 
 
* * 1 day is thus about 2 seconds (74*27 = 1998) on a machine that can run OpenTTD normally
 
*/
 
#define DAY_TICKS 74
 

	
 
#include "macros.h"
 

	
 
// Forward declarations of structs.
ttd.vcproj
Show inline comments
 
@@ -1168,6 +1168,9 @@
 
				RelativePath="vehicle.h">
 
			</File>
 
			<File
 
				RelativePath=".\vehicle_gui.h">
 
			</File>
 
			<File
 
				RelativePath="viewport.h">
 
			</File>
 
			<File
 
@@ -2015,6 +2018,9 @@
 
						BasicRuntimeChecks="3"/>
 
				</FileConfiguration>
 
			</File>
 
			<File
 
				RelativePath=".\vehicle_gui.c">
 
			</File>
 
		</Filter>
 
		<Filter
 
			Name="Landscape"
unix.c
Show inline comments
 
@@ -43,7 +43,7 @@ int compare_FiosItems (const void *a, co
 
	int r;
 

	
 
	if (_savegame_sort_order < 2) // sort by date
 
    r = da->mtime < db->mtime ? 1 : -1;
 
    r = da->mtime < db->mtime ? -1 : 1;
 
	else	
 
		r = strcmp(da->title[0] ? da->title : da->name, db->title[0] ? db->title : db->name);
 

	
vehicle.c
Show inline comments
 
@@ -1399,6 +1399,10 @@ int32 CmdNameVehicle(int x, int y, uint3
 
		StringID old_str = v->string_id;
 
		v->string_id = str;
 
		DeleteName(old_str);
 
		_train_sort_dirty[v->owner]			= true;
 
		_aircraft_sort_dirty[v->owner]	= true;
 
		_ship_sort_dirty[v->owner]			= true;
 
		_road_sort_dirty[v->owner]			= true;
 
		MarkWholeScreenDirty();
 
	} else {
 
		DeleteName(str);
vehicle.h
Show inline comments
 
#ifndef VEHICLE_H
 
#define VEHICLE_H
 

	
 
#include "vehicle_gui.h"
 

	
 
typedef struct VehicleRail {
 
	uint16 last_speed;		// NOSAVE: only used in UI
 
	uint16 crash_anim_pos;
 
@@ -369,6 +371,7 @@ byte GetDirectionTowards(Vehicle *v, int
 
#define BEGIN_ENUM_WAGONS(v) do {
 
#define END_ENUM_WAGONS(v) } while ( (v=v->next) != NULL);
 

	
 
#define DEREF_VEHICLE(i) (&_vehicles[i])
 
#define FOR_ALL_VEHICLES(v) for(v=_vehicles; v != endof(_vehicles); v++)
 

	
 
/* vehicle.c */
vehicle_gui.c
Show inline comments
 
new file 100644
 
#include "stdafx.h"
 
#include "ttd.h"
 

	
 
#include "vehicle.h"
 

	
 
/* General Vehicle GUI based procedures that are independent of vehicle types */
 
void InitializeVehiclesGuiList()
 
{
 
	bool *i;
 
	for (i = _train_sort_dirty; i != endof(_train_sort_dirty); i++)
 
		*i = true;
 

	
 
	for (i = _aircraft_sort_dirty; i != endof(_aircraft_sort_dirty); i++)
 
		*i = true;
 

	
 
	for (i = _ship_sort_dirty; i != endof(_ship_sort_dirty); i++)
 
		*i = true;
 

	
 
	for (i = _road_sort_dirty; i != endof(_road_sort_dirty); i++)
 
		*i = true;
 

	
 
	for (i = _vehicle_sort_dirty; i != endof(_vehicle_sort_dirty); i++)
 
		*i = true;
 

	
 
	//memset(_train_sort_dirty, true, sizeof(_train_sort_dirty));
 
}
 

	
 
// draw the vehicle profit button in the vehicle list window.
 
void DrawVehicleProfitButton(Vehicle *v, int x, int y)
 
{
 
	uint32 ormod;
 

	
 
	// draw profit-based colored icons
 
	if(v->age <= 365 * 2)
 
		ormod = 0x3158000; // grey
 
	else if(v->profit_last_year < 0)
 
		ormod = 0x30b8000; //red
 
	else if(v->profit_last_year < 10000)
 
		ormod = 0x30a8000; // yellow
 
	else
 
		ormod = 0x30d8000; // green
 
	DrawSprite((SPR_OPENTTD_BASE + 10) | ormod, x, y);
 
}
 

	
 
/************ Sorter functions *****************/
 
int CDECL GeneralOwnerSorter(const void *a, const void *b)
 
{
 
	return (*(SortStruct*)a).owner - (*(SortStruct*)b).owner;
 
}
 

	
 
static char _bufcache[64];	// used together with _last_vehicle_idx to hopefully speed up stringsorting
 

	
 
/* Variables you need to set before calling this function!
 
* 1. (uint32)_internal_name_sorter_id:	default StringID of the vehicle when no name is set. eg
 
*    STR_SV_TRAIN_NAME for trains or STR_SV_AIRCRAFT_NAME for aircraft
 
* 2. (bool)_internal_sort_order:				sorting order, descending/ascending
 
*/
 
int CDECL VehicleNameSorter(const void *a, const void *b)
 
{
 
	SortStruct *cmp1 = (SortStruct*)a;
 
	SortStruct *cmp2 = (SortStruct*)b;
 
	Vehicle *v;
 
	char buf1[64] = "\0";
 
	int r;
 

	
 
	v = DEREF_VEHICLE(cmp1->index);
 
	if (v->string_id != _internal_name_sorter_id) {
 
		SET_DPARAM16(0, v->string_id);
 
		GetString(buf1, STR_0315);
 
	}
 

	
 
	if ( cmp2->index != _last_vehicle_idx) {
 
		_last_vehicle_idx = cmp2->index;
 
		v = DEREF_VEHICLE(cmp2->index);
 
		_bufcache[0] = '\0';
 
		if (v->string_id != _internal_name_sorter_id) {
 
			SET_DPARAM16(0, v->string_id);
 
			GetString(_bufcache, STR_0315);
 
		}
 
	}
 

	
 
	r =  strcmp(buf1, _bufcache);	// sort by name
 
	if (_internal_sort_order & 1) r = -r;
 
	return r;
 
}
 

	
 
/* Variables you need to set before calling this function!
 
* 1. (byte)_internal_sort_type:		the criteria by which to sort these vehicles (number, age, etc)
 
* 2. (bool)_internal_sort_order:	sorting order, descending/ascending
 
*/
 
int CDECL GeneralVehicleSorter(const void *a, const void *b)
 
{
 
	SortStruct *cmp1 = (SortStruct*)a;
 
	SortStruct *cmp2 = (SortStruct*)b;
 
	Vehicle *va = DEREF_VEHICLE(cmp1->index);
 
	Vehicle *vb = DEREF_VEHICLE(cmp2->index);
 
	int r;
 

	
 
	switch (_internal_sort_type) {
 
		case SORT_BY_UNSORTED: /* Sort unsorted */
 
			return va->index - vb->index;
 
		case SORT_BY_NUMBER: /* Sort by Number */
 
			r = va->unitnumber - vb->unitnumber;
 
			break;
 
		/* case SORT_BY_NAME: Sort by Name (VehicleNameSorter)*/
 
		case SORT_BY_AGE: /* Sort by Age */
 
			r = va->age - vb->age;
 
			break;
 
		case SORT_BY_PROFIT_THIS_YEAR: /* Sort by Profit this year */
 
			r = va->profit_this_year - vb->profit_this_year;
 
			break;
 
		case SORT_BY_PROFIT_LAST_YEAR: /* Sort by Profit last year */
 
			r = va->profit_last_year - vb->profit_last_year;
 
			break;
 
		case SORT_BY_TOTAL_CAPACITY_PER_CARGOTYPE: { /* Sort by Total capacity per cargotype */
 
			// FIXME - someone write a normal cargo sorter that also works by cargo_cap,
 
			// FIXME - since I seem to be unable to do so :S
 
			Vehicle *ua = va;
 
			Vehicle *ub = vb;
 
			int i;
 
			byte _cargo_counta[NUM_CARGO];
 
			byte _cargo_countb[NUM_CARGO];
 
			do {
 
				_cargo_counta[ua->cargo_type]++;
 
			} while ( (ua = ua->next) != NULL);
 
			do {
 
				_cargo_countb[ub->cargo_type]++;
 
			} while ( (ub = ub->next) != NULL);
 

	
 
			for (i = 0; i < NUM_CARGO; i++) {
 
				r = _cargo_counta[i] - _cargo_countb[i];
 
				if (r != 0)
 
					break;
 
			}
 
		} break;
 
		case SORT_BY_RELIABILITY: /* Sort by Reliability */
 
			r = va->reliability - vb->reliability;
 
			break;
 
		case SORT_BY_MAX_SPEED: /* Sort by Max speed */
 
			r = va->max_speed - vb->max_speed;
 
			break;
 
		default: NOT_REACHED();
 
	}
 
	
 
	if (_internal_sort_order & 1) r = -r;
 
	return r;
 
}
vehicle_gui.h
Show inline comments
 
new file 100644
 
#ifndef VEHICLE_GUI_H
 
#define VEHICLE_GUI_H
 

	
 
void DrawVehicleProfitButton(Vehicle *v, int x, int y);
 
void InitializeVehiclesGuiList();
 

	
 
/* sorter stuff */
 
int CDECL GeneralOwnerSorter  (const void *a, const void *b);
 
int CDECL VehicleNameSorter   (const void *a, const void *b);
 
int CDECL GeneralVehicleSorter(const void *a, const void *b);
 
VARDEF uint32	_internal_name_sorter_id;	// internal StringID for default vehicle-names
 
VARDEF uint32	_last_vehicle_idx;				// cached index to hopefully speed up name-sorting
 
VARDEF bool		_internal_sort_order;			// descending/ascending
 
VARDEF byte		_internal_sort_type;			// Miscalleneous sorting criteria
 

	
 
typedef struct SortStruct { // store owner through sorting process
 
	uint32	index;
 
	byte		owner;
 
} SortStruct;
 

	
 
#define PERIODIC_RESORT_DAYS 10
 

	
 
enum VehicleSortListingTypes {
 
 SORT_BY_UNSORTED											= 0,
 
 SORT_BY_NUMBER												= 1,
 
 SORT_BY_NAME													= 2,
 
 SORT_BY_AGE													= 3,
 
 SORT_BY_PROFIT_THIS_YEAR							= 4,
 
 SORT_BY_PROFIT_LAST_YEAR							= 5,
 
 SORT_BY_TOTAL_CAPACITY_PER_CARGOTYPE	= 6,
 
 SORT_BY_RELIABILITY									= 7,
 
 SORT_BY_MAX_SPEED										= 8
 
};
 

	
 
static const uint16 _vehicle_sort_listing[] = {
 
	STR_SORT_BY_UNSORTED,
 
	STR_SORT_BY_NUMBER,
 
	STR_SORT_BY_DROPDOWN_NAME,
 
	STR_SORT_BY_AGE,
 
	STR_SORT_BY_PROFIT_THIS_YEAR,
 
	STR_SORT_BY_PROFIT_LAST_YEAR,
 
	STR_SORT_BY_TOTAL_CAPACITY_PER_CARGOTYPE,
 
	STR_SORT_BY_RELIABILITY,
 
	STR_SORT_BY_MAX_SPEED,
 
	INVALID_STRING_ID
 
};
 

	
 
enum VehicleSortTypes {
 
	VEHTRAIN		= 0,
 
	VEHROAD			= 1,
 
	VEHSHIP			= 2,
 
	VEHAIRCRAFT	= 3
 
};
 

	
 
VARDEF bool _vehicle_sort_dirty[4];	// global sort, vehicles added/removed (4 types of vehicles)
 

	
 
VARDEF bool _train_sort_dirty[MAX_PLAYERS];			// vehicles for a given player needs to be resorted (new criteria)
 
VARDEF byte _train_sort_type[MAX_PLAYERS];			// different criteria for sorting
 
VARDEF bool _train_sort_order[MAX_PLAYERS];			// sort descending/ascending
 

	
 
VARDEF bool _aircraft_sort_dirty[MAX_PLAYERS];	// vehicles for a given player needs to be resorted (new criteria)
 
VARDEF byte _aircraft_sort_type[MAX_PLAYERS];		// different criteria for sorting
 
VARDEF bool _aircraft_sort_order[MAX_PLAYERS];	// sort descending/ascending
 

	
 
VARDEF bool _ship_sort_dirty[MAX_PLAYERS];			// vehicles for a given player needs to be resorted (new criteria)
 
VARDEF byte _ship_sort_type[MAX_PLAYERS];				// different criteria for sorting
 
VARDEF bool _ship_sort_order[MAX_PLAYERS];			// sort descending/ascending
 

	
 
VARDEF bool _road_sort_dirty[MAX_PLAYERS];			// vehicles for a given player needs to be resorted (new criteria)
 
VARDEF byte _road_sort_type[MAX_PLAYERS];				// different criteria for sorting
 
VARDEF bool _road_sort_order[MAX_PLAYERS];			// sort descending/ascending
 

	
 
enum {
 
  PLY_WND_PRC__OFFSET_TOP_WIDGET	= 26,
 
	PLY_WND_PRC__SIZE_OF_ROW_SMALL	= 26,
 
  PLY_WND_PRC__SIZE_OF_ROW_BIG		= 36,
 
};
 

	
 
#endif /* VEHICLE_GUI_H */
water_cmd.c
Show inline comments
 
@@ -531,6 +531,7 @@ static void FloodVehicle(Vehicle *v)
 

	
 
			v->vehstatus |= VS_CRASHED;
 
			v->u.road.crashed_ctr = 2000;	// max 2220, disappear pretty fast
 
			_vehicle_sort_dirty[VEHROAD] = true;
 
			InvalidateWindow(WC_ROADVEH_LIST, v->owner);
 
		}
 
		
 
@@ -547,6 +548,7 @@ static void FloodVehicle(Vehicle *v)
 

	
 
			v = u;
 
			v->u.rail.crash_anim_pos = 4000; // max 4440, disappear pretty fast
 
			_vehicle_sort_dirty[VEHTRAIN] = true;
 
			InvalidateWindow(WC_TRAINS_LIST, v->owner);						
 
		}
 

	
widget.c
Show inline comments
 
@@ -373,3 +373,186 @@ draw_default:;
 
	}
 

	
 
}
 

	
 
static uint _dropdown_item_count;
 
static uint32 _dropdown_disabled;
 
static const StringID *_dropdown_items;
 
static int _dropdown_selindex;
 
static byte _dropdown_button;
 
static WindowClass _dropdown_windowclass;
 
static WindowNumber _dropdown_windownum;
 
static byte _dropdown_var1;
 
static byte _dropdown_var2;
 

	
 
static Widget _dropdown_menu_widgets[] = {
 
{     WWT_IMGBTN,     0,     0, 0,     0, 0, 0x0},
 
{      WWT_LAST},
 
};
 

	
 
static int GetDropdownItem(Window *w)
 
{
 
	uint item;
 
	int y;
 

	
 
	if (GetWidgetFromPos(w, _cursor.pos.x - w->left, _cursor.pos.y - w->top) < 0)
 
		return -1;
 
	
 
	y = _cursor.pos.y - w->top - 2;
 

	
 
	if (y < 0)
 
		return - 1;
 

	
 
	item = y / 10;
 
	if (item >= _dropdown_item_count || HASBIT(_dropdown_disabled,item) || _dropdown_items[item] == 0)
 
		return - 1;
 

	
 
	return item;
 
}
 

	
 
void DropdownMenuWndProc(Window *w, WindowEvent *e)
 
{
 
	int item;
 

	
 
	switch(e->event) {
 
	case WE_PAINT: {
 
		int x,y,i,sel;
 
		uint32 dis;
 

	
 
		DrawWindowWidgets(w);
 

	
 
		x = 1;
 
		y = 2;
 
		sel = _dropdown_selindex;
 
		dis = _dropdown_disabled;
 

	
 
		for(i=0; _dropdown_items[i] != INVALID_STRING_ID; i++) {
 
			if (_dropdown_items[i] != 0) {
 
				if (sel == 0) {
 
					GfxFillRect(x+1, y, x+w->width-4, y + 9, 0);
 
				}
 
				DrawString(x+2, y, _dropdown_items[i], sel==0 ? 12 : 16);
 

	
 
				if (dis & 1) {
 
					GfxFillRect(x, y, x+w->width-3, y + 9, 0x8000 + 
 
						_color_list[_dropdown_menu_widgets[0].color].window_color_bga);
 
				}
 
			} else {
 
				int color_1 = _color_list[_dropdown_menu_widgets[0].color].window_color_1a;
 
				int color_2 = _color_list[_dropdown_menu_widgets[0].color].window_color_2;
 
				GfxFillRect(x+1, y+3, x+w->width-5, y+3, color_1);
 
				GfxFillRect(x+1, y+4, x+w->width-5, y+4, color_2);
 
			}
 
			y += 10;
 
			sel--;
 
			dis>>=1;
 
		}
 
	} break;
 

	
 
	case WE_CLICK: {
 
		item = GetDropdownItem(w);
 
		if (item >= 0) {
 
			_dropdown_var1 = 4;
 
			_dropdown_selindex = item;
 
			SetWindowDirty(w);
 
		}
 
	} break;
 

	
 
	case WE_MOUSELOOP: {
 
		Window *w2 = FindWindowById(_dropdown_windowclass, _dropdown_windownum);
 
		if (w2 == NULL) {
 
			DeleteWindow(w);
 
			return;
 
		}
 

	
 
		if (_dropdown_var1 != 0 && --_dropdown_var1 == 0) {
 
			WindowEvent e;
 
			e.event = WE_DROPDOWN_SELECT;
 
			e.dropdown.button = _dropdown_button;
 
			e.dropdown.index = _dropdown_selindex;
 
			w2->wndproc(w2, &e);
 
			DeleteWindow(w);
 
			return;
 
		}
 

	
 
		if (_dropdown_var2 != 0) {
 
			item = GetDropdownItem(w);
 

	
 
			if (!_left_button_clicked) {
 
				_dropdown_var2 = 0;
 
				if (item < 0)
 
					return;
 
				_dropdown_var1 = 2;
 
			} else {
 
				if (item < 0)
 
					return;
 
			}
 

	
 
			_dropdown_selindex = item;
 
			SetWindowDirty(w);
 
		}
 
	} break;
 
		
 
	case WE_DESTROY: {
 
		Window *w2 = FindWindowById(_dropdown_windowclass, _dropdown_windownum);
 
		if (w2 != NULL) {
 
			CLRBIT(w2->click_state, _dropdown_button);
 
			InvalidateWidget(w2, _dropdown_button);
 
		}
 
	} break;
 
	}
 
}
 

	
 
void ShowDropDownMenu(Window *w, const StringID *strings, int selected, int button, uint32 disabled_mask)
 
{
 
	WindowNumber num;
 
	WindowClass cls;
 
	int i,t1,t2;
 
	const Widget *wi;
 
	Window *w2;
 
	uint32 old_click_state = w->click_state;
 
	
 
	_dropdown_disabled = disabled_mask;
 

	
 
	cls = w->window_class;
 
	num = w->window_number;
 
	DeleteWindowById(WC_DROPDOWN_MENU, 0);
 
	w = FindWindowById(cls, num);
 

	
 
	if (HASBIT(old_click_state, button))
 
		return;
 

	
 
	SETBIT(w->click_state, button);
 

	
 
	InvalidateWidget(w, button);
 
	
 
	for(i=0;strings[i] != INVALID_STRING_ID;i++);
 
	if (i == 0)
 
		return;
 

	
 
	_dropdown_items = strings;
 
	_dropdown_item_count = i;
 
	_dropdown_selindex = selected;
 
	
 
	_dropdown_windowclass = w->window_class;
 
	_dropdown_windownum = w->window_number;
 
	_dropdown_button = button;
 
	
 
	_dropdown_var1 = 0;
 
	_dropdown_var2 = 1;
 

	
 
	wi = &w->widget[button];
 

	
 
	_dropdown_menu_widgets[0].color = wi->color;
 

	
 
	w2 = AllocateWindow(
 
		w->left + wi[-1].left + 1,
 
		w->top + wi->bottom + 2,
 
		(_dropdown_menu_widgets[0].right=t1=wi->right - wi[-1].left, t1 + 1), 
 
		(_dropdown_menu_widgets[0].bottom=t2=i*10+3, t2+1), 
 
		DropdownMenuWndProc,
 
		0x3F,
 
		_dropdown_menu_widgets);
 

	
 

	
 
	w2->flags4 &= ~WF_WHITE_BORDER_MASK;
 
}
win32.c
Show inline comments
 
@@ -1470,7 +1470,7 @@ int CDECL compare_FiosItems (const void 
 
	int r;
 

	
 
	if (_savegame_sort_order < 2) // sort by date
 
    r = da->mtime < db->mtime ? 1 : -1;
 
    r = da->mtime < db->mtime ? -1 : 1;
 
	else	
 
		r = stricmp(da->title[0] ? da->title : da->name, db->title[0] ? db->title : db->name);
 

	
window.h
Show inline comments
 
@@ -422,6 +422,7 @@ int32 PositionMainToolbar(Window *w);
 
/* widget.c */
 
int GetWidgetFromPos(Window *w, int x, int y);
 
void DrawWindowWidgets(Window *w);
 
void ShowDropDownMenu(Window *w, const StringID *strings, int selected, int button, uint32 disabled_mask);
 

	
 
void HandleButtonClick(Window *w, byte widget);
 

	
0 comments (0 inline, 0 general)