diff --git a/src/order_gui.cpp b/src/order_gui.cpp --- a/src/order_gui.cpp +++ b/src/order_gui.cpp @@ -58,60 +58,6 @@ enum OrderWindowWidgets { ORDER_WIDGET_RESIZE, }; -/** Under what reason are we using the PlaceObject functionality? */ -enum OrderPlaceObjectState { - OPOS_GOTO, - OPOS_CONDITIONAL, -}; - -struct order_d { - int sel; - OrderPlaceObjectState goto_type; -}; -assert_compile(WINDOW_CUSTOM_SIZE >= sizeof(order_d)); - -/** - * Return the memorised selected order. - * - * @param w current window - * @return the memorised order if it is a vaild one - * else return the number of orders - */ -static int OrderGetSel(const Window *w) -{ - const Vehicle *v = GetVehicle(w->window_number); - int num = WP(w, order_d).sel; - - return (num >= 0 && num < v->num_orders) ? num : v->num_orders; -} - -/** - * Calculate the selected order. - * The calculation is based on the relative (to the window) y click position and - * the position of the scrollbar. - * - * @param w current window - * @param y Y-value of the click relative to the window origin - * @param v current vehicle - * @return the new selected order if the order is valid else return that - * an invalid one has been selected. - */ -static int GetOrderFromOrderWndPt(Window *w, int y, const Vehicle *v) -{ - /* - * Calculation description: - * 15 = 14 (w->widget[ORDER_WIDGET_ORDER_LIST].top) + 1 (frame-line) - * 10 = order text hight - */ - int sel = (y - w->widget[ORDER_WIDGET_ORDER_LIST].top - 1) / 10; - - if ((uint)sel >= w->vscroll.cap) return INVALID_ORDER; - - sel += w->vscroll.pos; - - return (sel <= v->num_orders && sel >= 0) ? sel : INVALID_ORDER; -} - /** Order load types that could be given to station orders. */ static const StringID _station_load_types[][5] = { { @@ -312,121 +258,6 @@ void DrawOrderString(const Vehicle *v, c } -static void DrawOrdersWindow(Window *w) -{ - const Vehicle *v = GetVehicle(w->window_number); - bool shared_orders = v->IsOrderListShared(); - - SetVScrollCount(w, v->num_orders + 1); - - int sel = OrderGetSel(w); - const Order *order = GetVehicleOrder(v, sel); - - if (v->owner == _local_player) { - /* Set the strings for the dropdown boxes. */ - w->widget[ORDER_WIDGET_NON_STOP].data = _order_non_stop_drowdown[order == NULL ? 0 : order->GetNonStopType()]; - w->widget[ORDER_WIDGET_FULL_LOAD].data = _order_full_load_drowdown[order == NULL ? 0 : order->GetLoadType()]; - w->widget[ORDER_WIDGET_UNLOAD].data = _order_unload_drowdown[order == NULL ? 0 : order->GetUnloadType()]; - w->widget[ORDER_WIDGET_COND_VARIABLE].data = _order_conditional_variable[order == NULL ? 0 : order->GetConditionVariable()]; - w->widget[ORDER_WIDGET_COND_COMPARATOR].data = _order_conditional_condition[order == NULL ? 0 : order->GetConditionComparator()]; - - /* skip */ - w->SetWidgetDisabledState(ORDER_WIDGET_SKIP, v->num_orders <= 1); - - /* delete */ - w->SetWidgetDisabledState(ORDER_WIDGET_DELETE, - (uint)v->num_orders + ((shared_orders || v->num_orders != 0) ? 1 : 0) <= (uint)WP(w, order_d).sel); - - /* non-stop only for trains */ - w->SetWidgetDisabledState(ORDER_WIDGET_NON_STOP, (v->type != VEH_TRAIN && v->type != VEH_ROAD) || order == NULL); - w->SetWidgetDisabledState(ORDER_WIDGET_FULL_LOAD, order == NULL || (order->GetNonStopType() & ONSF_NO_STOP_AT_DESTINATION_STATION) != 0); // full load - w->SetWidgetDisabledState(ORDER_WIDGET_UNLOAD, order == NULL || (order->GetNonStopType() & ONSF_NO_STOP_AT_DESTINATION_STATION) != 0); // unload - /* Disable list of vehicles with the same shared orders if there is no list */ - w->SetWidgetDisabledState(ORDER_WIDGET_SHARED_ORDER_LIST, !shared_orders || v->orders == NULL); - w->SetWidgetDisabledState(ORDER_WIDGET_REFIT, order == NULL); // Refit - w->SetWidgetDisabledState(ORDER_WIDGET_SERVICE, order == NULL); // Refit - w->HideWidget(ORDER_WIDGET_REFIT); // Refit - w->HideWidget(ORDER_WIDGET_SERVICE); // Service - - w->HideWidget(ORDER_WIDGET_COND_VARIABLE); - w->HideWidget(ORDER_WIDGET_COND_COMPARATOR); - w->HideWidget(ORDER_WIDGET_COND_VALUE); - } - - w->ShowWidget(ORDER_WIDGET_NON_STOP); - w->ShowWidget(ORDER_WIDGET_UNLOAD); - w->ShowWidget(ORDER_WIDGET_FULL_LOAD); - - if (order != NULL) { - switch (order->GetType()) { - case OT_GOTO_STATION: - if (!GetStation(order->GetDestination())->IsBuoy()) break; - /* Fall-through */ - - case OT_GOTO_WAYPOINT: - w->DisableWidget(ORDER_WIDGET_FULL_LOAD); - w->DisableWidget(ORDER_WIDGET_UNLOAD); - break; - - case OT_GOTO_DEPOT: - w->DisableWidget(ORDER_WIDGET_FULL_LOAD); - - /* Remove unload and replace it with refit */ - w->HideWidget(ORDER_WIDGET_UNLOAD); - w->ShowWidget(ORDER_WIDGET_REFIT); - w->HideWidget(ORDER_WIDGET_FULL_LOAD); - w->ShowWidget(ORDER_WIDGET_SERVICE); - break; - - case OT_CONDITIONAL: { - w->HideWidget(ORDER_WIDGET_NON_STOP); - w->HideWidget(ORDER_WIDGET_UNLOAD); - w->HideWidget(ORDER_WIDGET_FULL_LOAD); - w->ShowWidget(ORDER_WIDGET_COND_VARIABLE); - w->ShowWidget(ORDER_WIDGET_COND_COMPARATOR); - w->ShowWidget(ORDER_WIDGET_COND_VALUE); - - OrderConditionVariable ocv = order->GetConditionVariable(); - w->SetWidgetDisabledState(ORDER_WIDGET_COND_COMPARATOR, ocv == OCV_UNCONDITIONALLY); - w->SetWidgetDisabledState(ORDER_WIDGET_COND_VALUE, ocv == OCV_REQUIRES_SERVICE || ocv == OCV_UNCONDITIONALLY); - - uint value = order->GetConditionValue(); - if (order->GetConditionVariable() == OCV_MAX_SPEED) value = ConvertSpeedToDisplaySpeed(value); - SetDParam(1, value); - } break; - - default: // every other orders - w->DisableWidget(ORDER_WIDGET_NON_STOP); - w->DisableWidget(ORDER_WIDGET_FULL_LOAD); - w->DisableWidget(ORDER_WIDGET_UNLOAD); - } - } - - SetDParam(0, v->index); - DrawWindowWidgets(w); - - int y = 15; - - int i = w->vscroll.pos; - order = GetVehicleOrder(v, i); - StringID str; - while (order != NULL) { - /* Don't draw anything if it extends past the end of the window. */ - if (i - w->vscroll.pos >= w->vscroll.cap) break; - - DrawOrderString(v, order, i, y, i == WP(w, order_d).sel, false); - y += 10; - - i++; - order = order->next; - } - - if (i - w->vscroll.pos < w->vscroll.cap) { - str = shared_orders ? STR_END_OF_SHARED_ORDERS : STR_882A_END_OF_ORDERS; - DrawString(2, y, str, (i == WP(w, order_d).sel) ? TC_WHITE : TC_BLACK); - } -} - static Order GetOrderCmdFromTile(const Vehicle *v, TileIndex tile) { Order order; @@ -510,548 +341,689 @@ static Order GetOrderCmdFromTile(const V return order; } -static bool HandleOrderVehClick(const Vehicle *v, const Vehicle *u, Window *w) -{ - if (u->type != v->type) return false; - - if (!u->IsPrimaryVehicle()) { - u = u->First(); - if (!u->IsPrimaryVehicle()) return false; - } +struct OrdersWindow : public Window { +private: + /** Under what reason are we using the PlaceObject functionality? */ + enum OrderPlaceObjectState { + OPOS_GOTO, + OPOS_CONDITIONAL, + }; - /* v is vehicle getting orders. Only copy/clone orders if vehicle doesn't have any orders yet - * obviously if you press CTRL on a non-empty orders vehicle you know what you are doing */ - if (v->num_orders != 0 && _ctrl_pressed == 0) return false; + int selected_order; + OrderPlaceObjectState goto_type; + const Vehicle *vehicle; - if (DoCommandP(v->tile, v->index | (u->index << 16), _ctrl_pressed ? CO_SHARE : CO_COPY, NULL, - _ctrl_pressed ? CMD_CLONE_ORDER | CMD_MSG(STR_CANT_SHARE_ORDER_LIST) : CMD_CLONE_ORDER | CMD_MSG(STR_CANT_COPY_ORDER_LIST))) { - WP(w, order_d).sel = -1; - ResetObjectToPlace(); + /** + * Return the memorised selected order. + * @return the memorised order if it is a vaild one + * else return the number of orders + */ + int OrderGetSel() + { + int num = this->selected_order; + return (num >= 0 && num < vehicle->num_orders) ? num : vehicle->num_orders; } - return true; -} - -static void OrdersPlaceObj(const Vehicle *v, TileIndex tile, Window *w) -{ - /* check if we're clicking on a vehicle first.. clone orders in that case. */ - const Vehicle *u = CheckMouseOverVehicle(); - if (u != NULL && HandleOrderVehClick(v, u, w)) return; - - const Order cmd = GetOrderCmdFromTile(v, tile); - if (!cmd.IsValid()) return; - - if (DoCommandP(v->tile, v->index + (OrderGetSel(w) << 16), cmd.Pack(), NULL, CMD_INSERT_ORDER | CMD_MSG(STR_8833_CAN_T_INSERT_NEW_ORDER))) { - if (WP(w, order_d).sel != -1) WP(w, order_d).sel++; - ResetObjectToPlace(); - } -} + /** + * Calculate the selected order. + * The calculation is based on the relative (to the window) y click position and + * the position of the scrollbar. + * + * @param y Y-value of the click relative to the window origin + * @param v current vehicle + * @return the new selected order if the order is valid else return that + * an invalid one has been selected. + */ + int GetOrderFromPt(int y) + { + /* + * Calculation description: + * 15 = 14 (w->widget[ORDER_WIDGET_ORDER_LIST].top) + 1 (frame-line) + * 10 = order text hight + */ + int sel = (y - this->widget[ORDER_WIDGET_ORDER_LIST].top - 1) / 10; -/** - * Handle the click on the goto button. - * - * @param w current window - * @param v current vehicle - */ -static void OrderClick_Goto(Window *w, const Vehicle *v, int i) -{ - w->InvalidateWidget(ORDER_WIDGET_GOTO); - w->ToggleWidgetLoweredState(ORDER_WIDGET_GOTO); - if (w->IsWidgetLowered(ORDER_WIDGET_GOTO)) { - _place_clicked_vehicle = NULL; - SetObjectToPlaceWnd(ANIMCURSOR_PICKSTATION, PAL_NONE, VHM_RECT, w); - WP(w, order_d).goto_type = OPOS_GOTO; - } else { - ResetObjectToPlace(); - } -} + if ((uint)sel >= this->vscroll.cap) return INVALID_ORDER; + + sel += this->vscroll.pos; -/** - * Handle the click on the full load button. - * - * @param w current window - * @param v current vehicle - * @param load_type the way to load. - */ -static void OrderClick_FullLoad(Window *w, const Vehicle *v, int load_type) -{ - VehicleOrderID sel_ord = OrderGetSel(w); - const Order *order = GetVehicleOrder(v, sel_ord); + return (sel <= vehicle->num_orders && sel >= 0) ? sel : INVALID_ORDER; + } - if (order->GetLoadType() == load_type) return; - - if (load_type < 0) { - switch (order->GetLoadType()) { - case OLF_LOAD_IF_POSSIBLE: load_type = OLFB_FULL_LOAD; break; - case OLFB_FULL_LOAD: load_type = OLF_FULL_LOAD_ANY; break; - case OLF_FULL_LOAD_ANY: load_type = OLFB_NO_LOAD; break; - case OLFB_NO_LOAD: load_type = OLF_LOAD_IF_POSSIBLE; break; - default: NOT_REACHED(); - } - } - DoCommandP(v->tile, v->index + (sel_ord << 16), MOF_LOAD | (load_type << 4), NULL, CMD_MODIFY_ORDER | CMD_MSG(STR_8835_CAN_T_MODIFY_THIS_ORDER)); -} + bool HandleOrderVehClick(const Vehicle *u) + { + if (u->type != this->vehicle->type) return false; -/** - * Handle the click on the service. - * - * @param w current window - * @param v current vehicle - */ -static void OrderClick_Service(Window *w, const Vehicle *v, int i) -{ - DoCommandP(v->tile, v->index + (OrderGetSel(w) << 16), MOF_DEPOT_ACTION, NULL, CMD_MODIFY_ORDER | CMD_MSG(STR_8835_CAN_T_MODIFY_THIS_ORDER)); -} + if (!u->IsPrimaryVehicle()) { + u = u->First(); + if (!u->IsPrimaryVehicle()) return false; + } -/** - * Handle the click on the service in nearest depot button. - * - * @param w current window - * @param v current vehicle - */ -static void OrderClick_NearestDepot(Window *w, const Vehicle *v, int i) -{ - Order order; - order.next = NULL; - order.index = 0; - order.MakeGoToDepot(0, ODTFB_PART_OF_ORDERS); - order.SetDepotActionType(ODATFB_NEAREST_DEPOT); + /* v is vehicle getting orders. Only copy/clone orders if vehicle doesn't have any orders yet + * obviously if you press CTRL on a non-empty orders vehicle you know what you are doing */ + if (this->vehicle->num_orders != 0 && _ctrl_pressed == 0) return false; - DoCommandP(v->tile, v->index + (OrderGetSel(w) << 16), order.Pack(), NULL, CMD_INSERT_ORDER | CMD_MSG(STR_8833_CAN_T_INSERT_NEW_ORDER)); -} + if (DoCommandP(this->vehicle->tile, this->vehicle->index | (u->index << 16), _ctrl_pressed ? CO_SHARE : CO_COPY, NULL, + _ctrl_pressed ? CMD_CLONE_ORDER | CMD_MSG(STR_CANT_SHARE_ORDER_LIST) : CMD_CLONE_ORDER | CMD_MSG(STR_CANT_COPY_ORDER_LIST))) { + this->selected_order = -1; + ResetObjectToPlace(); + } -/** - * Handle the click on the conditional order button. - * - * @param w current window - * @param v current vehicle - */ -static void OrderClick_Conditional(Window *w, const Vehicle *v, int i) -{ - w->InvalidateWidget(ORDER_WIDGET_GOTO); - w->LowerWidget(ORDER_WIDGET_GOTO); - SetObjectToPlaceWnd(ANIMCURSOR_PICKSTATION, PAL_NONE, VHM_RECT, w); - WP(w, order_d).goto_type = OPOS_CONDITIONAL; -} + return true; + } -/** - * Handle the click on the unload button. - * - * @param w current window - * @param v current vehicle - */ -static void OrderClick_Unload(Window *w, const Vehicle *v, int unload_type) -{ - VehicleOrderID sel_ord = OrderGetSel(w); - const Order *order = GetVehicleOrder(v, sel_ord); - - if (order->GetUnloadType() == unload_type) return; - - if (unload_type < 0) { - switch (order->GetUnloadType()) { - case OUF_UNLOAD_IF_POSSIBLE: unload_type = OUFB_UNLOAD; break; - case OUFB_UNLOAD: unload_type = OUFB_TRANSFER; break; - case OUFB_TRANSFER: unload_type = OUFB_NO_UNLOAD; break; - case OUFB_NO_UNLOAD: unload_type = OUF_UNLOAD_IF_POSSIBLE; break; - default: NOT_REACHED(); + /** + * Handle the click on the goto button. + * + * @param w current window + */ + static void OrderClick_Goto(OrdersWindow *w, int i) + { + w->InvalidateWidget(ORDER_WIDGET_GOTO); + w->ToggleWidgetLoweredState(ORDER_WIDGET_GOTO); + if (w->IsWidgetLowered(ORDER_WIDGET_GOTO)) { + _place_clicked_vehicle = NULL; + SetObjectToPlaceWnd(ANIMCURSOR_PICKSTATION, PAL_NONE, VHM_RECT, w); + w->goto_type = OPOS_GOTO; + } else { + ResetObjectToPlace(); } } - DoCommandP(v->tile, v->index + (sel_ord << 16), MOF_UNLOAD | (unload_type << 4), NULL, CMD_MODIFY_ORDER | CMD_MSG(STR_8835_CAN_T_MODIFY_THIS_ORDER)); -} + /** + * Handle the click on the full load button. + * + * @param w current window + * @param load_type the way to load. + */ + static void OrderClick_FullLoad(OrdersWindow *w, int load_type) + { + VehicleOrderID sel_ord = w->OrderGetSel(); + const Order *order = GetVehicleOrder(w->vehicle, sel_ord); + + if (order == NULL || order->GetLoadType() == load_type) return; + + if (load_type < 0) { + switch (order->GetLoadType()) { + case OLF_LOAD_IF_POSSIBLE: load_type = OLFB_FULL_LOAD; break; + case OLFB_FULL_LOAD: load_type = OLF_FULL_LOAD_ANY; break; + case OLF_FULL_LOAD_ANY: load_type = OLFB_NO_LOAD; break; + case OLFB_NO_LOAD: load_type = OLF_LOAD_IF_POSSIBLE; break; + default: NOT_REACHED(); + } + } + DoCommandP(w->vehicle->tile, w->vehicle->index + (sel_ord << 16), MOF_LOAD | (load_type << 4), NULL, CMD_MODIFY_ORDER | CMD_MSG(STR_8835_CAN_T_MODIFY_THIS_ORDER)); + } + + /** + * Handle the click on the service. + * + * @param w current window + */ + static void OrderClick_Service(OrdersWindow *w, int i) + { + DoCommandP(w->vehicle->tile, w->vehicle->index + (w->OrderGetSel() << 16), MOF_DEPOT_ACTION, NULL, CMD_MODIFY_ORDER | CMD_MSG(STR_8835_CAN_T_MODIFY_THIS_ORDER)); + } + + /** + * Handle the click on the service in nearest depot button. + * + * @param w current window + */ + static void OrderClick_NearestDepot(OrdersWindow *w, int i) + { + Order order; + order.next = NULL; + order.index = 0; + order.MakeGoToDepot(0, ODTFB_PART_OF_ORDERS); + order.SetDepotActionType(ODATFB_NEAREST_DEPOT); + + DoCommandP(w->vehicle->tile, w->vehicle->index + (w->OrderGetSel() << 16), order.Pack(), NULL, CMD_INSERT_ORDER | CMD_MSG(STR_8833_CAN_T_INSERT_NEW_ORDER)); + } -/** - * Handle the click on the nonstop button. - * - * @param w current window - * @param v current vehicle - * @param non_stop what non-stop type to use; -1 to use the 'next' one. - */ -static void OrderClick_Nonstop(Window *w, const Vehicle *v, int non_stop) -{ - VehicleOrderID sel_ord = OrderGetSel(w); - const Order *order = GetVehicleOrder(v, sel_ord); + /** + * Handle the click on the conditional order button. + * + * @param w current window + */ + static void OrderClick_Conditional(OrdersWindow *w, int i) + { + w->InvalidateWidget(ORDER_WIDGET_GOTO); + w->LowerWidget(ORDER_WIDGET_GOTO); + SetObjectToPlaceWnd(ANIMCURSOR_PICKSTATION, PAL_NONE, VHM_RECT, w); + w->goto_type = OPOS_CONDITIONAL; + } + + /** + * Handle the click on the unload button. + * + * @param w current window + */ + static void OrderClick_Unload(OrdersWindow *w, int unload_type) + { + VehicleOrderID sel_ord = w->OrderGetSel(); + const Order *order = GetVehicleOrder(w->vehicle, sel_ord); + + if (order == NULL || order->GetUnloadType() == unload_type) return; + + if (unload_type < 0) { + switch (order->GetUnloadType()) { + case OUF_UNLOAD_IF_POSSIBLE: unload_type = OUFB_UNLOAD; break; + case OUFB_UNLOAD: unload_type = OUFB_TRANSFER; break; + case OUFB_TRANSFER: unload_type = OUFB_NO_UNLOAD; break; + case OUFB_NO_UNLOAD: unload_type = OUF_UNLOAD_IF_POSSIBLE; break; + default: NOT_REACHED(); + } + } - if (order->GetNonStopType() == non_stop) return; + DoCommandP(w->vehicle->tile, w->vehicle->index + (sel_ord << 16), MOF_UNLOAD | (unload_type << 4), NULL, CMD_MODIFY_ORDER | CMD_MSG(STR_8835_CAN_T_MODIFY_THIS_ORDER)); + } + + /** + * Handle the click on the nonstop button. + * + * @param w current window + * @param non_stop what non-stop type to use; -1 to use the 'next' one. + */ + static void OrderClick_Nonstop(OrdersWindow *w, int non_stop) + { + VehicleOrderID sel_ord = w->OrderGetSel(); + const Order *order = GetVehicleOrder(w->vehicle, sel_ord); + + if (order == NULL || order->GetNonStopType() == non_stop) return; - /* Keypress if negative, so 'toggle' to the next */ - if (non_stop < 0) { - non_stop = (order->GetNonStopType() + 1) % ONSF_END; + /* Keypress if negative, so 'toggle' to the next */ + if (non_stop < 0) { + non_stop = (order->GetNonStopType() + 1) % ONSF_END; + } + + DoCommandP(w->vehicle->tile, w->vehicle->index + (sel_ord << 16), MOF_NON_STOP | non_stop << 4, NULL, CMD_MODIFY_ORDER | CMD_MSG(STR_8835_CAN_T_MODIFY_THIS_ORDER)); + } + + /** + * Handle the click on the transfer button. + * + * @param w current window + */ + static void OrderClick_Transfer(OrdersWindow *w, int i) + { + VehicleOrderID sel_ord = w->OrderGetSel(); + const Order *order = GetVehicleOrder(w->vehicle, sel_ord); + + if (order == NULL) return; + + DoCommandP(w->vehicle->tile, w->vehicle->index + (sel_ord << 16), MOF_UNLOAD | ((order->GetUnloadType() & ~OUFB_NO_UNLOAD) ^ OUFB_TRANSFER) << 4, NULL, CMD_MODIFY_ORDER | CMD_MSG(STR_8835_CAN_T_MODIFY_THIS_ORDER)); } - DoCommandP(v->tile, v->index + (sel_ord << 16), MOF_NON_STOP | non_stop << 4, NULL, CMD_MODIFY_ORDER | CMD_MSG(STR_8835_CAN_T_MODIFY_THIS_ORDER)); -} - -/** - * Handle the click on the transfer button. - * - * @param w current window - * @param v current vehicle - */ -static void OrderClick_Transfer(Window *w, const Vehicle *v, int i) -{ - VehicleOrderID sel_ord = OrderGetSel(w); - const Order *order = GetVehicleOrder(v, sel_ord); + /** + * Handle the click on the skip button. + * If ctrl is pressed skip to selected order. + * Else skip to current order + 1 + * + * @param w current window + */ + static void OrderClick_Skip(OrdersWindow *w, int i) + { + /* Don't skip when there's nothing to skip */ + if (_ctrl_pressed && w->vehicle->cur_order_index == w->OrderGetSel()) return; - DoCommandP(v->tile, v->index + (sel_ord << 16), MOF_UNLOAD | ((order->GetUnloadType() & ~OUFB_NO_UNLOAD) ^ OUFB_TRANSFER) << 4, NULL, CMD_MODIFY_ORDER | CMD_MSG(STR_8835_CAN_T_MODIFY_THIS_ORDER)); -} - -/** - * Handle the click on the skip button. - * If ctrl is pressed skip to selected order. - * Else skip to current order + 1 - * - * @param w current window - * @param v current vehicle - */ -static void OrderClick_Skip(Window *w, const Vehicle *v, int i) -{ - /* Don't skip when there's nothing to skip */ - if (_ctrl_pressed && v->cur_order_index == OrderGetSel(w)) return; + DoCommandP(w->vehicle->tile, w->vehicle->index, _ctrl_pressed ? w->OrderGetSel() : ((w->vehicle->cur_order_index + 1) % w->vehicle->num_orders), + NULL, CMD_SKIP_TO_ORDER | CMD_MSG(_ctrl_pressed ? STR_CAN_T_SKIP_TO_ORDER : STR_CAN_T_SKIP_ORDER)); + } - DoCommandP(v->tile, v->index, _ctrl_pressed ? OrderGetSel(w) : ((v->cur_order_index + 1) % v->num_orders), - NULL, CMD_SKIP_TO_ORDER | CMD_MSG(_ctrl_pressed ? STR_CAN_T_SKIP_TO_ORDER : STR_CAN_T_SKIP_ORDER)); -} - -/** - * Handle the click on the unload button. - * - * @param w current window - * @param v current vehicle - */ -static void OrderClick_Delete(Window *w, const Vehicle *v, int i) -{ - DoCommandP(v->tile, v->index, OrderGetSel(w), NULL, CMD_DELETE_ORDER | CMD_MSG(STR_8834_CAN_T_DELETE_THIS_ORDER)); -} + /** + * Handle the click on the unload button. + * + * @param w current window + */ + static void OrderClick_Delete(OrdersWindow *w, int i) + { + DoCommandP(w->vehicle->tile, w->vehicle->index, w->OrderGetSel(), NULL, CMD_DELETE_ORDER | CMD_MSG(STR_8834_CAN_T_DELETE_THIS_ORDER)); + } -/** - * Handle the click on the refit button. - * If ctrl is pressed cancel refitting. - * Else show the refit window. - * - * @param w current window - * @param v current vehicle - */ -static void OrderClick_Refit(Window *w, const Vehicle *v, int i) -{ - if (_ctrl_pressed) { - /* Cancel refitting */ - DoCommandP(v->tile, v->index, (WP(w, order_d).sel << 16) | (CT_NO_REFIT << 8) | CT_NO_REFIT, NULL, CMD_ORDER_REFIT); - } else { - ShowVehicleRefitWindow(v, WP(w, order_d).sel); + /** + * Handle the click on the refit button. + * If ctrl is pressed cancel refitting. + * Else show the refit window. + * + * @param w current window + */ + static void OrderClick_Refit(OrdersWindow *w, int i) + { + if (_ctrl_pressed) { + /* Cancel refitting */ + DoCommandP(w->vehicle->tile, w->vehicle->index, (w->OrderGetSel() << 16) | (CT_NO_REFIT << 8) | CT_NO_REFIT, NULL, CMD_ORDER_REFIT); + } else { + ShowVehicleRefitWindow(w->vehicle, w->OrderGetSel()); + } } -} - -typedef void OnButtonVehClick(Window *w, const Vehicle *v, int i); + typedef void Handler(OrdersWindow*, int); + struct KeyToEvent { + uint16 keycode; + Handler *proc; + }; -/** - * Keycode function mapping. - * - * @see _order_keycodes[] - * @note Keep them allways in sync with _order_keycodes[]! - */ -static OnButtonVehClick* const _order_button_proc[] = { - OrderClick_Skip, - OrderClick_Delete, - OrderClick_Nonstop, - OrderClick_Goto, - OrderClick_FullLoad, - OrderClick_Unload, - OrderClick_Transfer, - OrderClick_Service, -}; +public: + OrdersWindow(const WindowDesc *desc, const Vehicle *v) : Window(desc, v->index) + { + this->caption_color = v->owner; + this->vscroll.cap = 6; + this->resize.step_height = 10; + this->selected_order = -1; + this->vehicle = v; + if (_patches.timetabling) { + this->widget[ORDER_WIDGET_CAPTION].right -= 61; + } else { + this->HideWidget(ORDER_WIDGET_TIMETABLE_VIEW); + } + this->FindWindowPlacementAndResize(desc); + } -static const uint16 _order_keycodes[] = { - 'D', //skip order - 'F', //delete order - 'G', //non-stop - 'H', //goto order - 'J', //full load - 'K' //unload -}; + virtual void OnPaint() + { + bool shared_orders = this->vehicle->IsOrderListShared(); -static void OrdersWndProc(Window *w, WindowEvent *e) -{ - const Vehicle *v = GetVehicle(w->window_number); + SetVScrollCount(this, this->vehicle->num_orders + 1); - switch (e->event) { - case WE_CREATE: - if (_patches.timetabling) { - w->widget[ORDER_WIDGET_CAPTION].right -= 61; - } else { - w->HideWidget(ORDER_WIDGET_TIMETABLE_VIEW); - } + int sel = OrderGetSel(); + const Order *order = GetVehicleOrder(this->vehicle, sel); - break; - - case WE_PAINT: - DrawOrdersWindow(w); - break; + if (this->vehicle->owner == _local_player) { + /* Set the strings for the dropdown boxes. */ + this->widget[ORDER_WIDGET_NON_STOP].data = _order_non_stop_drowdown[order == NULL ? 0 : order->GetNonStopType()]; + this->widget[ORDER_WIDGET_FULL_LOAD].data = _order_full_load_drowdown[order == NULL ? 0 : order->GetLoadType()]; + this->widget[ORDER_WIDGET_UNLOAD].data = _order_unload_drowdown[order == NULL ? 0 : order->GetUnloadType()]; + this->widget[ORDER_WIDGET_COND_VARIABLE].data = _order_conditional_variable[order == NULL ? 0 : order->GetConditionVariable()]; + this->widget[ORDER_WIDGET_COND_COMPARATOR].data = _order_conditional_condition[order == NULL ? 0 : order->GetConditionComparator()]; - case WE_CLICK: - if (w->widget[e->we.click.widget].type != WWT_DROPDOWN) HideDropDownMenu(w); - switch (e->we.click.widget) { - case ORDER_WIDGET_ORDER_LIST: { - ResetObjectToPlace(); + /* skip */ + this->SetWidgetDisabledState(ORDER_WIDGET_SKIP, this->vehicle->num_orders <= 1); - int sel = GetOrderFromOrderWndPt(w, e->we.click.pt.y, v); + /* delete */ + this->SetWidgetDisabledState(ORDER_WIDGET_DELETE, + (uint)this->vehicle->num_orders + ((shared_orders || this->vehicle->num_orders != 0) ? 1 : 0) <= (uint)this->selected_order); - if (sel == INVALID_ORDER) { - /* This was a click on an empty part of the orders window, so - * deselect the currently selected order. */ - WP(w, order_d).sel = -1; - w->SetDirty(); - return; - } - - if (_ctrl_pressed && sel < v->num_orders) { - const Order *ord = GetVehicleOrder(v, sel); - TileIndex xy; + /* non-stop only for trains */ + this->SetWidgetDisabledState(ORDER_WIDGET_NON_STOP, (this->vehicle->type != VEH_TRAIN && this->vehicle->type != VEH_ROAD) || order == NULL); + this->SetWidgetDisabledState(ORDER_WIDGET_FULL_LOAD, order == NULL || (order->GetNonStopType() & ONSF_NO_STOP_AT_DESTINATION_STATION) != 0); // full load + this->SetWidgetDisabledState(ORDER_WIDGET_UNLOAD, order == NULL || (order->GetNonStopType() & ONSF_NO_STOP_AT_DESTINATION_STATION) != 0); // unload + /* Disable list of vehicles with the same shared orders if there is no list */ + this->SetWidgetDisabledState(ORDER_WIDGET_SHARED_ORDER_LIST, !shared_orders || this->vehicle->orders == NULL); + this->SetWidgetDisabledState(ORDER_WIDGET_REFIT, order == NULL); // Refit + this->SetWidgetDisabledState(ORDER_WIDGET_SERVICE, order == NULL); // Refit + this->HideWidget(ORDER_WIDGET_REFIT); // Refit + this->HideWidget(ORDER_WIDGET_SERVICE); // Service - switch (ord->GetType()) { - case OT_GOTO_STATION: xy = GetStation(ord->GetDestination())->xy ; break; - case OT_GOTO_DEPOT: xy = (v->type == VEH_AIRCRAFT) ? GetStation(ord->GetDestination())->xy : GetDepot(ord->GetDestination())->xy; break; - case OT_GOTO_WAYPOINT: xy = GetWaypoint(ord->GetDestination())->xy; break; - default: xy = 0; break; - } + this->HideWidget(ORDER_WIDGET_COND_VARIABLE); + this->HideWidget(ORDER_WIDGET_COND_COMPARATOR); + this->HideWidget(ORDER_WIDGET_COND_VALUE); + } + + this->ShowWidget(ORDER_WIDGET_NON_STOP); + this->ShowWidget(ORDER_WIDGET_UNLOAD); + this->ShowWidget(ORDER_WIDGET_FULL_LOAD); - if (xy != 0) ScrollMainWindowToTile(xy); - return; - } else { - if (sel == WP(w, order_d).sel) { - /* Deselect clicked order */ - WP(w, order_d).sel = -1; - } else { - /* Select clicked order */ - WP(w, order_d).sel = sel; + if (order != NULL) { + switch (order->GetType()) { + case OT_GOTO_STATION: + if (!GetStation(order->GetDestination())->IsBuoy()) break; + /* Fall-through */ - if (v->owner == _local_player) { - /* Activate drag and drop */ - SetObjectToPlaceWnd(SPR_CURSOR_MOUSE, PAL_NONE, VHM_DRAG, w); - } - } - } - - w->SetDirty(); - } break; - - case ORDER_WIDGET_SKIP: - OrderClick_Skip(w, v, 0); + case OT_GOTO_WAYPOINT: + this->DisableWidget(ORDER_WIDGET_FULL_LOAD); + this->DisableWidget(ORDER_WIDGET_UNLOAD); break; - case ORDER_WIDGET_DELETE: - OrderClick_Delete(w, v, 0); - break; + case OT_GOTO_DEPOT: + this->DisableWidget(ORDER_WIDGET_FULL_LOAD); - case ORDER_WIDGET_NON_STOP: { - const Order *o = GetVehicleOrder(v, OrderGetSel(w)); - ShowDropDownMenu(w, _order_non_stop_drowdown, o->GetNonStopType(), ORDER_WIDGET_NON_STOP, 0, o->IsType(OT_GOTO_STATION) ? 0 : (o->IsType(OT_GOTO_WAYPOINT) ? 3 : 12)); - } break; - - case ORDER_WIDGET_GOTO: - OrderClick_Goto(w, v, 0); + /* Remove unload and replace it with refit */ + this->HideWidget(ORDER_WIDGET_UNLOAD); + this->ShowWidget(ORDER_WIDGET_REFIT); + this->HideWidget(ORDER_WIDGET_FULL_LOAD); + this->ShowWidget(ORDER_WIDGET_SERVICE); break; - case ORDER_WIDGET_GOTO_DROPDOWN: - ShowDropDownMenu(w, v->type == VEH_AIRCRAFT ? _order_goto_dropdown_aircraft : _order_goto_dropdown, 0, ORDER_WIDGET_GOTO, 0, 0, w->widget[ORDER_WIDGET_GOTO_DROPDOWN].right - w->widget[ORDER_WIDGET_GOTO].left); - break; - - case ORDER_WIDGET_FULL_LOAD: - ShowDropDownMenu(w, _order_full_load_drowdown, GetVehicleOrder(v, OrderGetSel(w))->GetLoadType(), ORDER_WIDGET_FULL_LOAD, 0, 2); - break; - - case ORDER_WIDGET_UNLOAD: - ShowDropDownMenu(w, _order_unload_drowdown, GetVehicleOrder(v, OrderGetSel(w))->GetUnloadType(), ORDER_WIDGET_UNLOAD, 0, 8); - break; - - case ORDER_WIDGET_REFIT: - OrderClick_Refit(w, v, 0); - break; + case OT_CONDITIONAL: { + this->HideWidget(ORDER_WIDGET_NON_STOP); + this->HideWidget(ORDER_WIDGET_UNLOAD); + this->HideWidget(ORDER_WIDGET_FULL_LOAD); + this->ShowWidget(ORDER_WIDGET_COND_VARIABLE); + this->ShowWidget(ORDER_WIDGET_COND_COMPARATOR); + this->ShowWidget(ORDER_WIDGET_COND_VALUE); - case ORDER_WIDGET_SERVICE: - OrderClick_Service(w, v, 0); - break; - - case ORDER_WIDGET_TIMETABLE_VIEW: - ShowTimetableWindow(v); - break; + OrderConditionVariable ocv = order->GetConditionVariable(); + this->SetWidgetDisabledState(ORDER_WIDGET_COND_COMPARATOR, ocv == OCV_UNCONDITIONALLY); + this->SetWidgetDisabledState(ORDER_WIDGET_COND_VALUE, ocv == OCV_REQUIRES_SERVICE || ocv == OCV_UNCONDITIONALLY); - case ORDER_WIDGET_COND_VARIABLE: - ShowDropDownMenu(w, _order_conditional_variable, GetVehicleOrder(v, OrderGetSel(w))->GetConditionVariable(), ORDER_WIDGET_COND_VARIABLE, 0, 0); - break; - - case ORDER_WIDGET_COND_COMPARATOR: { - const Order *o = GetVehicleOrder(v, OrderGetSel(w)); - ShowDropDownMenu(w, _order_conditional_condition, o->GetConditionComparator(), ORDER_WIDGET_COND_COMPARATOR, 0, (o->GetConditionVariable() == OCV_REQUIRES_SERVICE) ? 0x3F : 0xC0); - } break; - - case ORDER_WIDGET_COND_VALUE: { - const Order *order = GetVehicleOrder(v, OrderGetSel(w)); uint value = order->GetConditionValue(); if (order->GetConditionVariable() == OCV_MAX_SPEED) value = ConvertSpeedToDisplaySpeed(value); - SetDParam(0, value); - ShowQueryString(STR_CONFIG_PATCHES_INT32, STR_ORDER_CONDITIONAL_VALUE_CAPT, 5, 100, w, CS_NUMERAL); + SetDParam(1, value); } break; - case ORDER_WIDGET_SHARED_ORDER_LIST: - ShowVehicleListWindow(v); - break; + default: // every other orders + this->DisableWidget(ORDER_WIDGET_NON_STOP); + this->DisableWidget(ORDER_WIDGET_FULL_LOAD); + this->DisableWidget(ORDER_WIDGET_UNLOAD); } - break; + } + + SetDParam(0, this->vehicle->index); + DrawWindowWidgets(this); + + int y = 15; - case WE_ON_EDIT_TEXT: - if (!StrEmpty(e->we.edittext.str)) { - VehicleOrderID sel = OrderGetSel(w); - uint value = atoi(e->we.edittext.str); + int i = this->vscroll.pos; + order = GetVehicleOrder(this->vehicle, i); + StringID str; + while (order != NULL) { + /* Don't draw anything if it extends past the end of the window. */ + if (i - this->vscroll.pos >= this->vscroll.cap) break; + + DrawOrderString(this->vehicle, order, i, y, i == this->selected_order, false); + y += 10; + + i++; + order = order->next; + } + + if (i - this->vscroll.pos < this->vscroll.cap) { + str = shared_orders ? STR_END_OF_SHARED_ORDERS : STR_882A_END_OF_ORDERS; + DrawString(2, y, str, (i == this->selected_order) ? TC_WHITE : TC_BLACK); + } + } - switch (GetVehicleOrder(v, sel)->GetConditionVariable()) { - case OCV_MAX_SPEED: - value = ConvertDisplaySpeedToSpeed(value); - break; + virtual void OnClick(Point pt, int widget) + { + if (this->widget[widget].type != WWT_DROPDOWN) HideDropDownMenu(this); + switch (widget) { + case ORDER_WIDGET_ORDER_LIST: { + ResetObjectToPlace(); + + int sel = this->GetOrderFromPt(pt.y); + + if (sel == INVALID_ORDER) { + /* This was a click on an empty part of the orders window, so + * deselect the currently selected order. */ + this->selected_order = -1; + this->SetDirty(); + return; + } + + if (_ctrl_pressed && sel < this->vehicle->num_orders) { + const Order *ord = GetVehicleOrder(this->vehicle, sel); + TileIndex xy; - case OCV_RELIABILITY: - case OCV_LOAD_PERCENTAGE: - value = Clamp(value, 0, 100); + switch (ord->GetType()) { + case OT_GOTO_STATION: xy = GetStation(ord->GetDestination())->xy ; break; + case OT_GOTO_DEPOT: xy = (this->vehicle->type == VEH_AIRCRAFT) ? GetStation(ord->GetDestination())->xy : GetDepot(ord->GetDestination())->xy; break; + case OT_GOTO_WAYPOINT: xy = GetWaypoint(ord->GetDestination())->xy; break; + default: xy = 0; break; + } - default: - break; + if (xy != 0) ScrollMainWindowToTile(xy); + return; + } else { + if (sel == this->selected_order) { + /* Deselect clicked order */ + this->selected_order = -1; + } else { + /* Select clicked order */ + this->selected_order = sel; + + if (this->vehicle->owner == _local_player) { + /* Activate drag and drop */ + SetObjectToPlaceWnd(SPR_CURSOR_MOUSE, PAL_NONE, VHM_DRAG, this); + } + } } - DoCommandP(v->tile, v->index + (sel << 16), MOF_COND_VALUE | Clamp(value, 0, 2047) << 4, NULL, CMD_MODIFY_ORDER | CMD_MSG(STR_8835_CAN_T_MODIFY_THIS_ORDER)); - } - break; - case WE_DROPDOWN_SELECT: // we have selected a dropdown item in the list - switch (e->we.dropdown.button) { - case ORDER_WIDGET_NON_STOP: - OrderClick_Nonstop(w, v, e->we.dropdown.index); - break; + this->SetDirty(); + } break; + + case ORDER_WIDGET_SKIP: + OrderClick_Skip(this, 0); + break; + + case ORDER_WIDGET_DELETE: + OrderClick_Delete(this, 0); + break; + + case ORDER_WIDGET_NON_STOP: { + const Order *o = GetVehicleOrder(this->vehicle, this->OrderGetSel()); + ShowDropDownMenu(this, _order_non_stop_drowdown, o->GetNonStopType(), ORDER_WIDGET_NON_STOP, 0, o->IsType(OT_GOTO_STATION) ? 0 : (o->IsType(OT_GOTO_WAYPOINT) ? 3 : 12)); + } break; - case ORDER_WIDGET_FULL_LOAD: - OrderClick_FullLoad(w, v, e->we.dropdown.index); - break; + case ORDER_WIDGET_GOTO: + OrderClick_Goto(this, 0); + break; + + case ORDER_WIDGET_GOTO_DROPDOWN: + ShowDropDownMenu(this, this->vehicle->type == VEH_AIRCRAFT ? _order_goto_dropdown_aircraft : _order_goto_dropdown, 0, ORDER_WIDGET_GOTO, 0, 0, this->widget[ORDER_WIDGET_GOTO_DROPDOWN].right - this->widget[ORDER_WIDGET_GOTO].left); + break; - case ORDER_WIDGET_UNLOAD: - OrderClick_Unload(w, v, e->we.dropdown.index); - break; + case ORDER_WIDGET_FULL_LOAD: + ShowDropDownMenu(this, _order_full_load_drowdown, GetVehicleOrder(this->vehicle, this->OrderGetSel())->GetLoadType(), ORDER_WIDGET_FULL_LOAD, 0, 2); + break; + + case ORDER_WIDGET_UNLOAD: + ShowDropDownMenu(this, _order_unload_drowdown, GetVehicleOrder(this->vehicle, this->OrderGetSel())->GetUnloadType(), ORDER_WIDGET_UNLOAD, 0, 8); + break; + + case ORDER_WIDGET_REFIT: + OrderClick_Refit(this, 0); + break; - case ORDER_WIDGET_GOTO: - switch (e->we.dropdown.index) { - case 0: - w->ToggleWidgetLoweredState(ORDER_WIDGET_GOTO); - OrderClick_Goto(w, v, 0); - break; + case ORDER_WIDGET_SERVICE: + OrderClick_Service(this, 0); + break; + + case ORDER_WIDGET_TIMETABLE_VIEW: + ShowTimetableWindow(this->vehicle); + break; + + case ORDER_WIDGET_COND_VARIABLE: + ShowDropDownMenu(this, _order_conditional_variable, GetVehicleOrder(this->vehicle, this->OrderGetSel())->GetConditionVariable(), ORDER_WIDGET_COND_VARIABLE, 0, 0); + break; + + case ORDER_WIDGET_COND_COMPARATOR: { + const Order *o = GetVehicleOrder(this->vehicle, this->OrderGetSel()); + ShowDropDownMenu(this, _order_conditional_condition, o->GetConditionComparator(), ORDER_WIDGET_COND_COMPARATOR, 0, (o->GetConditionVariable() == OCV_REQUIRES_SERVICE) ? 0x3F : 0xC0); + } break; - case 1: OrderClick_NearestDepot(w, v, 0); break; - case 2: OrderClick_Conditional(w, v, 0); break; - default: NOT_REACHED(); - } - break; + case ORDER_WIDGET_COND_VALUE: { + const Order *order = GetVehicleOrder(this->vehicle, this->OrderGetSel()); + uint value = order->GetConditionValue(); + if (order->GetConditionVariable() == OCV_MAX_SPEED) value = ConvertSpeedToDisplaySpeed(value); + SetDParam(0, value); + ShowQueryString(STR_CONFIG_PATCHES_INT32, STR_ORDER_CONDITIONAL_VALUE_CAPT, 5, 100, this, CS_NUMERAL); + } break; - case ORDER_WIDGET_COND_VARIABLE: - DoCommandP(v->tile, v->index + (OrderGetSel(w) << 16), MOF_COND_VARIABLE | e->we.dropdown.index << 4, NULL, CMD_MODIFY_ORDER | CMD_MSG(STR_8835_CAN_T_MODIFY_THIS_ORDER)); + case ORDER_WIDGET_SHARED_ORDER_LIST: + ShowVehicleListWindow(this->vehicle); + break; + } + } + + virtual void OnQueryTextFinished(char *str) + { + if (!StrEmpty(str)) { + VehicleOrderID sel = this->OrderGetSel(); + uint value = atoi(str); + + switch (GetVehicleOrder(this->vehicle, sel)->GetConditionVariable()) { + case OCV_MAX_SPEED: + value = ConvertDisplaySpeedToSpeed(value); break; - case ORDER_WIDGET_COND_COMPARATOR: - DoCommandP(v->tile, v->index + (OrderGetSel(w) << 16), MOF_COND_COMPARATOR | e->we.dropdown.index << 4, NULL, CMD_MODIFY_ORDER | CMD_MSG(STR_8835_CAN_T_MODIFY_THIS_ORDER)); + case OCV_RELIABILITY: + case OCV_LOAD_PERCENTAGE: + value = Clamp(value, 0, 100); + + default: break; } - break; + DoCommandP(this->vehicle->tile, this->vehicle->index + (sel << 16), MOF_COND_VALUE | Clamp(value, 0, 2047) << 4, NULL, CMD_MODIFY_ORDER | CMD_MSG(STR_8835_CAN_T_MODIFY_THIS_ORDER)); + } + } + + virtual void OnDropdownSelect(int widget, int index) + { + switch (widget) { + case ORDER_WIDGET_NON_STOP: + OrderClick_Nonstop(this, index); + break; + + case ORDER_WIDGET_FULL_LOAD: + OrderClick_FullLoad(this, index); + break; + + case ORDER_WIDGET_UNLOAD: + OrderClick_Unload(this, index); + break; + + case ORDER_WIDGET_GOTO: + switch (index) { + case 0: + this->ToggleWidgetLoweredState(ORDER_WIDGET_GOTO); + OrderClick_Goto(this, 0); + break; - case WE_DRAGDROP: - switch (e->we.click.widget) { - case ORDER_WIDGET_ORDER_LIST: { - int from_order = OrderGetSel(w); - int to_order = GetOrderFromOrderWndPt(w, e->we.dragdrop.pt.y, v); + case 1: OrderClick_NearestDepot(this, 0); break; + case 2: OrderClick_Conditional(this, 0); break; + default: NOT_REACHED(); + } + break; + + case ORDER_WIDGET_COND_VARIABLE: + DoCommandP(this->vehicle->tile, this->vehicle->index + (this->OrderGetSel() << 16), MOF_COND_VARIABLE | index << 4, NULL, CMD_MODIFY_ORDER | CMD_MSG(STR_8835_CAN_T_MODIFY_THIS_ORDER)); + break; + + case ORDER_WIDGET_COND_COMPARATOR: + DoCommandP(this->vehicle->tile, this->vehicle->index + (this->OrderGetSel() << 16), MOF_COND_COMPARATOR | index << 4, NULL, CMD_MODIFY_ORDER | CMD_MSG(STR_8835_CAN_T_MODIFY_THIS_ORDER)); + break; + } + } - if (!(from_order == to_order || from_order == INVALID_ORDER || from_order > v->num_orders || to_order == INVALID_ORDER || to_order > v->num_orders) && - DoCommandP(v->tile, v->index, from_order | (to_order << 16), NULL, CMD_MOVE_ORDER | CMD_MSG(STR_CAN_T_MOVE_THIS_ORDER))) { - WP(w, order_d).sel = -1; - } + virtual void OnDragDrop(Point pt, int widget) + { + switch (widget) { + case ORDER_WIDGET_ORDER_LIST: { + int from_order = this->OrderGetSel(); + int to_order = this->GetOrderFromPt(pt.y); - } break; + if (!(from_order == to_order || from_order == INVALID_ORDER || from_order > this->vehicle->num_orders || to_order == INVALID_ORDER || to_order > this->vehicle->num_orders) && + DoCommandP(this->vehicle->tile, this->vehicle->index, from_order | (to_order << 16), NULL, CMD_MOVE_ORDER | CMD_MSG(STR_CAN_T_MOVE_THIS_ORDER))) { + this->selected_order = -1; + } + } break; + + case ORDER_WIDGET_DELETE: + OrderClick_Delete(this, 0); + break; + } - case ORDER_WIDGET_DELETE: - OrderClick_Delete(w, v, 0); - break; + ResetObjectToPlace(); + } + + virtual bool OnKeyPress(uint16 key, uint16 keycode) + { + static const KeyToEvent keytoevent[] = { + {'D', OrderClick_Skip}, + {'F', OrderClick_Delete}, + {'G', OrderClick_Goto}, + {'H', OrderClick_Nonstop}, + {'J', OrderClick_FullLoad}, + {'K', OrderClick_Unload}, + //{'?', OrderClick_Transfer}, + //('?', OrderClick_Service}, + }; + + if (this->vehicle->owner != _local_player) return true; + + for (uint i = 0; i < lengthof(keytoevent); i++) { + if (keycode == keytoevent[i].keycode) { + keytoevent[i].proc(this, -1); + return false; } - - ResetObjectToPlace(); - break; + } + return true; + } - case WE_KEYPRESS: - if (v->owner != _local_player) break; + virtual void OnPlaceObject(Point pt, TileIndex tile) + { + if (this->goto_type == OPOS_GOTO) { + /* check if we're clicking on a vehicle first.. clone orders in that case. */ + const Vehicle *v = CheckMouseOverVehicle(); + if (v != NULL && this->HandleOrderVehClick(v)) return; + + const Order cmd = GetOrderCmdFromTile(this->vehicle, tile); + if (!cmd.IsValid()) return; + + if (DoCommandP(this->vehicle->tile, this->vehicle->index + (this->OrderGetSel() << 16), cmd.Pack(), NULL, CMD_INSERT_ORDER | CMD_MSG(STR_8833_CAN_T_INSERT_NEW_ORDER))) { + if (this->selected_order != -1) this->selected_order++; + ResetObjectToPlace(); + } + } + } - for (uint i = 0; i < lengthof(_order_keycodes); i++) { - if (e->we.keypress.keycode == _order_keycodes[i]) { - e->we.keypress.cont = false; - /* see if the button is disabled */ - if (!w->IsWidgetDisabled(i + ORDER_WIDGET_SKIP)) _order_button_proc[i](w, v, -1); - break; + virtual void OnPlaceObjectAbort() + { + if (this->goto_type == OPOS_CONDITIONAL) { + this->goto_type = OPOS_GOTO; + if (_cursor.pos.x >= (this->left + this->widget[ORDER_WIDGET_ORDER_LIST].left) && + _cursor.pos.y >= (this->top + this->widget[ORDER_WIDGET_ORDER_LIST].top) && + _cursor.pos.x <= (this->left + this->widget[ORDER_WIDGET_ORDER_LIST].right) && + _cursor.pos.y <= (this->top + this->widget[ORDER_WIDGET_ORDER_LIST].bottom)) { + int order_id = this->GetOrderFromPt(_cursor.pos.y - this->top); + if (order_id != INVALID_ORDER) { + Order order; + order.next = NULL; + order.index = 0; + order.MakeConditional(order_id); + + DoCommandP(this->vehicle->tile, this->vehicle->index + (this->OrderGetSel() << 16), order.Pack(), NULL, CMD_INSERT_ORDER | CMD_MSG(STR_8833_CAN_T_INSERT_NEW_ORDER)); } } - break; - - case WE_PLACE_OBJ: - if (WP(w, order_d).goto_type == OPOS_GOTO) { - OrdersPlaceObj(GetVehicle(w->window_number), e->we.place.tile, w); - } - break; - - case WE_ABORT_PLACE_OBJ: - if (WP(w, order_d).goto_type == OPOS_CONDITIONAL) { - WP(w, order_d).goto_type = OPOS_GOTO; - if (_cursor.pos.x >= (w->left + w->widget[ORDER_WIDGET_ORDER_LIST].left) && - _cursor.pos.y >= (w->top + w->widget[ORDER_WIDGET_ORDER_LIST].top) && - _cursor.pos.x <= (w->left + w->widget[ORDER_WIDGET_ORDER_LIST].right) && - _cursor.pos.y <= (w->top + w->widget[ORDER_WIDGET_ORDER_LIST].bottom)) { - int order_id = GetOrderFromOrderWndPt(w, _cursor.pos.y - w->top, v); - if (order_id != INVALID_ORDER) { - Order order; - order.next = NULL; - order.index = 0; - order.MakeConditional(order_id); - - DoCommandP(v->tile, v->index + (OrderGetSel(w) << 16), order.Pack(), NULL, CMD_INSERT_ORDER | CMD_MSG(STR_8833_CAN_T_INSERT_NEW_ORDER)); - } - } - } - w->RaiseWidget(ORDER_WIDGET_GOTO); - w->InvalidateWidget(ORDER_WIDGET_GOTO); - break; + } + this->RaiseWidget(ORDER_WIDGET_GOTO); + this->InvalidateWidget(ORDER_WIDGET_GOTO); + } - /* check if a vehicle in a depot was clicked.. */ - case WE_MOUSELOOP: - v = _place_clicked_vehicle; - /* - * Check if we clicked on a vehicle - * and if the GOTO button of this window is pressed - * This is because of all open order windows WE_MOUSELOOP is called - * and if you have 3 windows open, and this check is not done - * the order is copied to the last open window instead of the - * one where GOTO is enabled - */ - if (v != NULL && w->IsWidgetLowered(ORDER_WIDGET_GOTO)) { - _place_clicked_vehicle = NULL; - HandleOrderVehClick(GetVehicle(w->window_number), v, w); - } - break; + virtual void OnMouseLoop() + { + const Vehicle *v = _place_clicked_vehicle; + /* + * Check if we clicked on a vehicle + * and if the GOTO button of this window is pressed + * This is because of all open order windows WE_MOUSELOOP is called + * and if you have 3 windows open, and this check is not done + * the order is copied to the last open window instead of the + * one where GOTO is enabled + */ + if (v != NULL && this->IsWidgetLowered(ORDER_WIDGET_GOTO)) { + _place_clicked_vehicle = NULL; + this->HandleOrderVehClick(v); + } + } - case WE_RESIZE: - /* Update the scroll + matrix */ - w->vscroll.cap = (w->widget[ORDER_WIDGET_ORDER_LIST].bottom - w->widget[ORDER_WIDGET_ORDER_LIST].top) / 10; - break; + virtual void OnResize(Point new_size, Point delta) + { + /* Update the scroll + matrix */ + this->vscroll.cap = (this->widget[ORDER_WIDGET_ORDER_LIST].bottom - this->widget[ORDER_WIDGET_ORDER_LIST].top) / 10; + } - case WE_TIMEOUT: // handle button unclick ourselves... - /* unclick all buttons except for the 'goto' button (ORDER_WIDGET_GOTO), which is 'persistent' */ - for (uint i = 0; i < w->widget_count; i++) { - if (w->IsWidgetLowered(i) && i != ORDER_WIDGET_GOTO) { - w->RaiseWidget(i); - w->InvalidateWidget(i); - } + virtual void OnTimeout() + { + /* unclick all buttons except for the 'goto' button (ORDER_WIDGET_GOTO), which is 'persistent' */ + for (uint i = 0; i < this->widget_count; i++) { + if (this->IsWidgetLowered(i) && i != ORDER_WIDGET_GOTO) { + this->RaiseWidget(i); + this->InvalidateWidget(i); } - break; + } } -} +}; /** * Widget definition for player train orders @@ -1091,7 +1063,7 @@ static const WindowDesc _orders_train_de WC_VEHICLE_ORDERS, WC_VEHICLE_VIEW, WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_RESIZABLE, _orders_train_widgets, - OrdersWndProc + NULL }; /** @@ -1132,7 +1104,7 @@ static const WindowDesc _orders_desc = { WC_VEHICLE_ORDERS, WC_VEHICLE_VIEW, WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_RESIZABLE, _orders_widgets, - OrdersWndProc + NULL }; /** @@ -1173,27 +1145,19 @@ static const WindowDesc _other_orders_de WC_VEHICLE_ORDERS, WC_VEHICLE_VIEW, WDF_STD_TOOLTIPS | WDF_STD_BTN | WDF_DEF_WIDGET | WDF_UNCLICK_BUTTONS | WDF_RESIZABLE, _other_orders_widgets, - OrdersWndProc + NULL }; void ShowOrdersWindow(const Vehicle *v) { - Window *w; VehicleID veh = v->index; DeleteWindowById(WC_VEHICLE_ORDERS, veh); DeleteWindowById(WC_VEHICLE_DETAILS, veh); if (v->owner != _local_player) { - w = AllocateWindowDescFront(&_other_orders_desc, veh); + new OrdersWindow(&_other_orders_desc, v); } else { - w = AllocateWindowDescFront((v->type == VEH_TRAIN || v->type == VEH_ROAD) ? &_orders_train_desc : &_orders_desc, veh); - } - - if (w != NULL) { - w->caption_color = v->owner; - w->vscroll.cap = 6; - w->resize.step_height = 10; - WP(w, order_d).sel = -1; + new OrdersWindow((v->type == VEH_TRAIN || v->type == VEH_ROAD) ? &_orders_train_desc : &_orders_desc, v); } }