From c60bc7be1a671c2f783f423775c5392e9f1f0528 Mon Sep 17 00:00:00 2001 From: Jonathan G Rennison Date: Mon, 23 Jan 2017 21:47:09 +0000 Subject: [PATCH] Fix refresh/validity issues for cargo type orders GUI. Handle case where the order disappears/moves, fixes crash if order list is now too short. Refresh drop-down when running as a multiplayer client, or when another player updates the cargo options. --- src/order_gui.cpp | 46 +++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 45 insertions(+), 1 deletion(-) diff --git a/src/order_gui.cpp b/src/order_gui.cpp index 9b320ce324..8774cf4add 100644 --- a/src/order_gui.cpp +++ b/src/order_gui.cpp @@ -68,6 +68,9 @@ private: const Vehicle *vehicle; ///< Vehicle owning the orders being displayed and manipulated. VehicleOrderID order_id; ///< Index of the order concerned by this window. + VehicleOrderID order_count; ///< Count of the orders of the vehicle owning this window + const Order *order; ///< Order pointer at construction time; + static const uint8 CARGO_ICON_WIDTH = 12; static const uint8 CARGO_ICON_HEIGHT = 8; @@ -124,6 +127,13 @@ private: return (this->variant == CTOWV_LOAD) ? (uint8) order->GetCargoLoadTypeRaw(cargo_id) : (uint8) order->GetCargoUnloadTypeRaw(cargo_id); } + bool CheckOrderStillValid() const + { + if (this->vehicle->GetNumOrders() != this->order_count) return false; + if (this->vehicle->GetOrder(this->order_id) != this->order) return false; + return true; + } + public: /** * Instantiate a new CargoTypeOrdersWindow. @@ -142,6 +152,8 @@ public: this->vehicle = v; this->order_id = order_id; + this->order_count = v->GetNumOrders(); + this->order = v->GetOrder(order_id); this->CreateNestedTree(desc); this->GetWidget(WID_CTO_CAPTION)->SetDataTip(STR_CARGO_TYPE_ORDERS_LOAD_CAPTION + this->variant, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS); @@ -193,6 +205,10 @@ public: virtual void OnClick(Point pt, int widget, int click_count) { + if (!this->CheckOrderStillValid()) { + delete this; + return; + } if (widget == WID_CTO_CLOSEBTN) { delete this; } else if (WID_CTO_CARGO_DROPDOWN_FIRST <= widget && widget <= WID_CTO_CARGO_DROPDOWN_LAST) { @@ -207,6 +223,10 @@ public: virtual void OnDropdownSelect(int widget, int action_type) { + if (!this->CheckOrderStillValid()) { + delete this; + return; + } if (WID_CTO_CARGO_DROPDOWN_FIRST <= widget && widget <= WID_CTO_CARGO_DROPDOWN_LAST) { const CargoSpec *cs = _sorted_cargo_specs[widget - WID_CTO_CARGO_DROPDOWN_FIRST]; CargoID cargo_id = GetCargoIDByBitnum(cs->bitnum); @@ -234,12 +254,32 @@ public: virtual void SetStringParameters(int widget) const { + if (!this->CheckOrderStillValid()) { + return; + } if (widget == WID_CTO_CAPTION) { SetDParam(0, this->vehicle->index); SetDParam(1, this->order_id + 1); SetDParam(2, this->vehicle->GetOrder(this->order_id)->GetDestination()); } } + + /** + * Some data on this window has become invalid. + * @param data Information about the changed data. + * @param gui_scope Whether the call is done from GUI scope. You may not do everything when not in GUI scope. See #InvalidateWindowData() for details. + */ + virtual void OnInvalidateData(int data = 0, bool gui_scope = true) + { + if (!this->CheckOrderStillValid()) { + delete this; + return; + } + if (gui_scope) { + this->InitDropdownSelectedTypes(); + this->SetDirty(); + } + } }; /** @@ -1282,7 +1322,11 @@ public: } this->vscroll->SetCount(this->vehicle->GetNumOrders() + 1); - if (gui_scope) this->UpdateButtonState(); + if (gui_scope) { + this->UpdateButtonState(); + InvalidateWindowClassesData(WC_VEHICLE_CARGO_TYPE_LOAD_ORDERS, 0); + InvalidateWindowClassesData(WC_VEHICLE_CARGO_TYPE_UNLOAD_ORDERS, 0); + } /* Scroll to the new order. */ if (from == INVALID_VEH_ORDER_ID && to != INVALID_VEH_ORDER_ID && !this->vscroll->IsVisible(to)) {