(svn r6651) -Coding feature: added the windowevent WE_INVALIDATE_DATA

This gives the ability to invalidate some window data and recalculate as needed instead of doing it for each WE_PAINT

   This event is called right away when using InvalidateWindowData(), so it may be a good idea to set a bool or similar in the window
     or similar and then act on that bool in WE_PAINT instead of doing a lot of stuff in WE_INVALIDATE_DATA as it might be called more than once before WE_PAINT is called

   InvalidateWindowData() will not automatically repaint the window, so if you want to repaint it as well, you need to mark it dirty as well.

   Made the depot windows use WE_INVALIDATE_DATA to set when to generate the engine and wagon lists instead of at each redraw
   It makes no sense to regenerate the list when say using the scrollbar if we know that no vehicle have entered or left the list

   NOTE: currently there is a piece of code to generate the list when it's not needed and compare it to the stored list and assert if they mismatch
    This check is somewhat slow and kills the whole idea of WE_INVALIDATE_DATA, so it's a short lived one to verify that InvalidateWindowData() is used everywhere where it's needed
This commit is contained in:
bjarni 2006-10-05 12:59:28 +00:00
parent a9478f810c
commit ea075f78e0
9 changed files with 80 additions and 14 deletions

View File

@ -399,6 +399,7 @@ int32 CmdBuildAircraft(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
}
GetPlayer(_current_player)->num_engines[p1]++;
InvalidateWindowData(WC_VEHICLE_DEPOT, v->tile);
InvalidateWindow(WC_VEHICLE_DEPOT, v->tile);
RebuildVehicleLists();
InvalidateWindow(WC_COMPANY, v->owner);
@ -1432,6 +1433,7 @@ static void AircraftLeaveHangar(Vehicle *v)
VehicleServiceInDepot(v);
SetAircraftPosition(v, v->x_pos, v->y_pos, v->z_pos);
InvalidateWindowData(WC_VEHICLE_DEPOT, v->tile);
InvalidateWindow(WC_VEHICLE_DEPOT, v->tile);
InvalidateWindowClasses(WC_AIRCRAFT_LIST);
}

View File

@ -618,18 +618,43 @@ static void DepotWndProc(Window *w, WindowEvent *e)
{
switch (e->event) {
case WE_CREATE:
WP(w, depot_d).vehicle_list = NULL;
WP(w, depot_d).wagon_list = NULL;
WP(w, depot_d).engine_count = 0;
WP(w, depot_d).wagon_count = 0;
WP(w, depot_d).vehicle_list = NULL;
WP(w, depot_d).wagon_list = NULL;
WP(w, depot_d).engine_count = 0;
WP(w, depot_d).wagon_count = 0;
WP(w, depot_d).generate_list = true;
break;
case WE_INVALIDATE_DATA:
WP(w, depot_d).generate_list = true;
break;
case WE_PAINT:
/* Generate the vehicle list
* It's ok to use the wagon pointers for non-trains as they will be ignored */
BuildDepotVehicleList(WP(w, depot_d).type, w->window_number,
&WP(w, depot_d).vehicle_list, &WP(w, depot_d).engine_list_length, &WP(w, depot_d).engine_count,
&WP(w, depot_d).wagon_list, &WP(w, depot_d).wagon_list_length, &WP(w, depot_d).wagon_count);
if (WP(w, depot_d).generate_list) {
/* Generate the vehicle list
* It's ok to use the wagon pointers for non-trains as they will be ignored */
BuildDepotVehicleList(WP(w, depot_d).type, w->window_number,
&WP(w, depot_d).vehicle_list, &WP(w, depot_d).engine_list_length, &WP(w, depot_d).engine_count,
&WP(w, depot_d).wagon_list, &WP(w, depot_d).wagon_list_length, &WP(w, depot_d).wagon_count);
WP(w, depot_d).generate_list = false;
#ifndef NDEBUG
} else {
/* Here we got a piece of code, that only checks if we got a different number of vehicles in the depot list and the number of vehicles actually being in the depot.
* IF they aren't the same, then WE_INVALIDATE_DATA should have been called somewhere, but it wasn't and we got a bug
* Since this is a time consuming check and not nice to memory fragmentation, it may not stay for long, but it's a good way to check this
* We can turn it on/off by switching between #ifndef NDEBUG and #if 0 */
Vehicle **engines = NULL, **wagons = NULL;
uint16 engine_count = 0, engine_length = 0;
uint16 wagon_count = 0, wagon_length = 0;
BuildDepotVehicleList(WP(w, depot_d).type, w->window_number, &engines, &engine_length, &engine_count,
&wagons, &wagon_length, &wagon_count);
assert(engine_count == WP(w, depot_d).engine_count);
assert(wagon_count == WP(w, depot_d).wagon_count);
free((void*)engines);
free((void*)wagons);
#endif
}
DrawDepotWindow(w);
break;

View File

@ -2005,6 +2005,7 @@ static uint32 VehicleEnter_Track(Vehicle *v, TileIndex tile, int x, int y)
v->u.rail.track = 0x80,
v->vehstatus |= VS_HIDDEN; /* hide it */
v->direction = ReverseDir(v->direction);
InvalidateWindowData(WC_VEHICLE_DEPOT, v->tile);
if (v->next == NULL)
VehicleEnterDepot(v);
v->tile = tile;

View File

@ -194,6 +194,7 @@ int32 CmdBuildRoadVeh(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
VehiclePositionChanged(v);
GetPlayer(_current_player)->num_engines[p1]++;
InvalidateWindowData(WC_VEHICLE_DEPOT, v->tile);
InvalidateWindow(WC_VEHICLE_DEPOT, v->tile);
RebuildVehicleLists();
InvalidateWindow(WC_COMPANY, v->owner);
@ -1305,6 +1306,7 @@ static void RoadVehController(Vehicle *v)
UpdateRoadVehDeltaXY(v);
SetRoadVehPosition(v,x,y);
InvalidateWindowData(WC_VEHICLE_DEPOT, v->tile);
InvalidateWindow(WC_VEHICLE_DEPOT, v->tile);
return;
}

View File

@ -358,6 +358,7 @@ static void CheckShipLeaveDepot(Vehicle *v)
PlayShipSound(v);
VehicleServiceInDepot(v);
InvalidateWindowData(WC_VEHICLE_DEPOT, v->tile);
InvalidateWindowClasses(WC_SHIPS_LIST);
}
@ -882,6 +883,7 @@ int32 CmdBuildShip(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
VehiclePositionChanged(v);
GetPlayer(_current_player)->num_engines[p1]++;
InvalidateWindowData(WC_VEHICLE_DEPOT, v->tile);
InvalidateWindow(WC_VEHICLE_DEPOT, v->tile);
RebuildVehicleLists();
InvalidateWindow(WC_COMPANY, v->owner);

View File

@ -615,6 +615,7 @@ static int32 CmdBuildRailWagon(EngineID engine, TileIndex tile, uint32 flags)
u->next = v;
} else {
SetFreeWagon(v);
InvalidateWindowData(WC_VEHICLE_DEPOT, v->tile);
}
v->cargo_type = rvi->cargo_type;
@ -818,6 +819,7 @@ int32 CmdBuildRailVehicle(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
}
GetPlayer(_current_player)->num_engines[p1]++;
InvalidateWindowData(WC_VEHICLE_DEPOT, v->tile);
InvalidateWindow(WC_VEHICLE_DEPOT, tile);
RebuildVehicleLists();
InvalidateWindow(WC_COMPANY, v->owner);
@ -1122,6 +1124,7 @@ int32 CmdMoveRailVehicle(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
while (GetNextVehicle(v) != src) v = GetNextVehicle(v);
GetLastEnginePart(v)->next = NULL;
} else {
InvalidateWindowData(WC_VEHICLE_DEPOT, src_head->tile); // We removed a line
src_head = NULL;
}
} else {
@ -1133,6 +1136,9 @@ int32 CmdMoveRailVehicle(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
}
if (dst == NULL) {
/* We make a new line in the depot, so we know already that we invalidate the window data */
InvalidateWindowData(WC_VEHICLE_DEPOT, src_head->tile);
// move the train to an empty line. for locomotives, we set the type to TS_Front. for wagons, 4.
if (IsTrainEngine(src)) {
if (!IsFrontEngine(src)) {
@ -1152,9 +1158,12 @@ int32 CmdMoveRailVehicle(TileIndex tile, uint32 flags, uint32 p1, uint32 p2)
DeleteVehicleOrders(src);
}
ClearFrontEngine(src);
ClearFreeWagon(src);
src->unitnumber = 0; // doesn't occupy a unitnumber anymore.
if (IsFrontEngine(src) || IsFreeWagon(src)) {
InvalidateWindowData(WC_VEHICLE_DEPOT, src->tile);
ClearFrontEngine(src);
ClearFreeWagon(src);
src->unitnumber = 0; // doesn't occupy a unitnumber anymore.
}
// link in the wagon(s) in the chain.
{
@ -1640,8 +1649,10 @@ static void ReverseTrainDirection(Vehicle *v)
int l = 0, r = -1;
Vehicle *u;
if (IsTileDepotType(v->tile, TRANSPORT_RAIL))
if (IsTileDepotType(v->tile, TRANSPORT_RAIL)) {
InvalidateWindowData(WC_VEHICLE_DEPOT, v->tile);
InvalidateWindow(WC_VEHICLE_DEPOT, v->tile);
}
/* Check if we were approaching a rail/road-crossing */
{
@ -1672,8 +1683,10 @@ static void ReverseTrainDirection(Vehicle *v)
AdvanceWagons(v, false);
if (IsTileDepotType(v->tile, TRANSPORT_RAIL))
if (IsTileDepotType(v->tile, TRANSPORT_RAIL)) {
InvalidateWindowData(WC_VEHICLE_DEPOT, v->tile);
InvalidateWindow(WC_VEHICLE_DEPOT, v->tile);
}
CLRBIT(v->u.rail.flags, VRF_REVERSING);
}
@ -2166,6 +2179,7 @@ static bool CheckTrainStayInDepot(Vehicle *v)
VehiclePositionChanged(v);
UpdateSignalsOnSegment(v->tile, DirToDiagDir(v->direction));
UpdateTrainAcceleration(v);
InvalidateWindowData(WC_VEHICLE_DEPOT, v->tile);
InvalidateWindow(WC_VEHICLE_DEPOT, v->tile);
return false;

View File

@ -566,6 +566,10 @@ void DestroyVehicle(Vehicle *v)
DeleteName(v->string_id);
if (v->type == VEH_Road) ClearSlot(v);
if (v->type != VEH_Train || (v->type == VEH_Train && (IsFrontEngine(v) || IsFreeWagon(v)))) {
InvalidateWindowData(WC_VEHICLE_DEPOT, v->tile);
}
UpdateVehiclePosHash(v, INVALID_COORD, 0);
v->next_hash = INVALID_VEHICLE;
if (v->orders != NULL) DeleteVehicleOrders(v);
@ -2476,6 +2480,11 @@ void VehicleEnterDepot(Vehicle *v)
default: NOT_REACHED();
}
if (v->type != VEH_Train) {
/* Trains update the vehicle list when the first unit enters the depot and calls VehicleEnterDepot() when the last unit enters.
* We only increase the number of vehicles when the first one enters, so we will not need to search for more vehicles in the depot */
InvalidateWindowData(WC_VEHICLE_DEPOT, v->tile);
}
InvalidateWindow(WC_VEHICLE_DEPOT, v->tile);
v->vehstatus |= VS_HIDDEN;

View File

@ -1563,6 +1563,14 @@ void InvalidateWindowClasses(WindowClass cls)
}
}
void InvalidateWindowData(WindowClass cls, WindowNumber number)
{
Window *w;
for (w = _windows; w != _last_window; w++) {
if (w->window_class == cls && w->window_number == number) CallWindowEventNP(w, WE_INVALIDATE_DATA);
}
}
void CallWindowTickEvent(void)
{

View File

@ -99,6 +99,7 @@ enum WindowEventCodes {
WE_MESSAGE = 23,
WE_SCROLL = 24,
WE_MOUSEWHEEL = 25,
WE_INVALIDATE_DATA = 26,
};
struct WindowEvent {
@ -397,6 +398,7 @@ assert_compile(WINDOW_CUSTOM_SIZE >= sizeof(replaceveh_d));
typedef struct {
VehicleID sel;
byte type;
bool generate_list;
uint16 engine_list_length;
uint16 wagon_list_length;
uint16 engine_count;
@ -748,6 +750,7 @@ int GetMenuItemIndex(const Window *w, int x, int y);
void InputLoop(void);
void UpdateWindows(void);
void InvalidateWidget(const Window *w, byte widget_index);
void InvalidateWindowData(WindowClass cls, WindowNumber number);
void RaiseWindowButtons(Window *w);
void RelocateAllWindows(int neww, int newh);
int PositionMainToolbar(Window *w);