|
@@ -541,144 +541,146 @@ struct RefitOption {
|
|
|
|
|
|
/**
|
|
|
* Equality operator for #RefitOption.
|
|
|
* @param other Compare to this #RefitOption.
|
|
|
* @return True if both #RefitOption are equal.
|
|
|
*/
|
|
|
inline bool operator == (const RefitOption &other) const
|
|
|
{
|
|
|
return other.cargo == this->cargo && other.string == this->string;
|
|
|
}
|
|
|
};
|
|
|
|
|
|
typedef std::vector<RefitOption> SubtypeList; ///< List of refit subtypes associated to a cargo.
|
|
|
using RefitOptions = std::map<CargoID, std::vector<RefitOption>, CargoIDComparator>; ///< Available refit options (subtype and string) associated with each cargo type.
|
|
|
|
|
|
/**
|
|
|
* Draw the list of available refit options for a consist and highlight the selected refit option (if any).
|
|
|
* @param list List of subtype options for each (sorted) cargo.
|
|
|
* @param sel Selected refit cargo-type in the window
|
|
|
* @param refits Available refit options for each (sorted) cargo.
|
|
|
* @param sel Selected refit option in the window
|
|
|
* @param pos Position of the selected item in caller widow
|
|
|
* @param rows Number of rows(capacity) in caller window
|
|
|
* @param delta Step height in caller window
|
|
|
* @param r Rectangle of the matrix widget.
|
|
|
*/
|
|
|
static void DrawVehicleRefitWindow(const SubtypeList list[NUM_CARGO], const int sel[2], uint pos, uint rows, uint delta, const Rect &r)
|
|
|
static void DrawVehicleRefitWindow(const RefitOptions &refits, const RefitOption *sel, uint pos, uint rows, uint delta, const Rect &r)
|
|
|
{
|
|
|
Rect ir = r.Shrink(WidgetDimensions::scaled.matrix);
|
|
|
uint current = 0;
|
|
|
|
|
|
bool rtl = _current_text_dir == TD_RTL;
|
|
|
uint iconwidth = std::max(GetSpriteSize(SPR_CIRCLE_FOLDED).width, GetSpriteSize(SPR_CIRCLE_UNFOLDED).width);
|
|
|
uint iconheight = GetSpriteSize(SPR_CIRCLE_FOLDED).height;
|
|
|
int linecolour = _colour_gradient[COLOUR_ORANGE][4];
|
|
|
|
|
|
int iconleft = rtl ? ir.right - iconwidth : ir.left;
|
|
|
int iconcenter = rtl ? ir.right - iconwidth / 2 : ir.left + iconwidth / 2;
|
|
|
int iconinner = rtl ? ir.right - iconwidth : ir.left + iconwidth;
|
|
|
|
|
|
Rect tr = ir.Indent(iconwidth + WidgetDimensions::scaled.hsep_wide, rtl);
|
|
|
|
|
|
/* Draw the list of subtypes for each cargo, and find the selected refit option (by its position). */
|
|
|
for (uint i = 0; current < pos + rows && i < NUM_CARGO; i++) {
|
|
|
for (uint j = 0; current < pos + rows && j < list[i].size(); j++) {
|
|
|
const RefitOption &refit = list[i][j];
|
|
|
|
|
|
/* Hide subtypes if sel[0] does not match */
|
|
|
if (sel[0] != (int)i && refit.subtype != 0xFF) continue;
|
|
|
for (const auto &pair : refits) {
|
|
|
bool has_subtypes = pair.second.size() > 1;
|
|
|
for (const RefitOption &refit : pair.second) {
|
|
|
if (current >= pos + rows) break;
|
|
|
|
|
|
/* Hide subtypes if selected cargo type does not match */
|
|
|
if ((sel == nullptr || sel->cargo != refit.cargo) && refit.subtype != UINT8_MAX) continue;
|
|
|
|
|
|
/* Refit options with a position smaller than pos don't have to be drawn. */
|
|
|
if (current < pos) {
|
|
|
current++;
|
|
|
continue;
|
|
|
}
|
|
|
|
|
|
if (list[i].size() > 1) {
|
|
|
if (refit.subtype != 0xFF) {
|
|
|
if (has_subtypes) {
|
|
|
if (refit.subtype != UINT8_MAX) {
|
|
|
/* Draw tree lines */
|
|
|
int ycenter = tr.top + FONT_HEIGHT_NORMAL / 2;
|
|
|
GfxDrawLine(iconcenter, tr.top - WidgetDimensions::scaled.matrix.top, iconcenter, j == list[i].size() - 1 ? ycenter : tr.top - WidgetDimensions::scaled.matrix.top + delta - 1, linecolour);
|
|
|
GfxDrawLine(iconcenter, tr.top - WidgetDimensions::scaled.matrix.top, iconcenter, (&refit == &pair.second.back()) ? ycenter : tr.top - WidgetDimensions::scaled.matrix.top + delta - 1, linecolour);
|
|
|
GfxDrawLine(iconcenter, ycenter, iconinner, ycenter, linecolour);
|
|
|
} else {
|
|
|
/* Draw expand/collapse icon */
|
|
|
DrawSprite(sel[0] == (int)i ? SPR_CIRCLE_UNFOLDED : SPR_CIRCLE_FOLDED, PAL_NONE, iconleft, tr.top + (FONT_HEIGHT_NORMAL - iconheight) / 2);
|
|
|
DrawSprite((sel != nullptr && sel->cargo == refit.cargo) ? SPR_CIRCLE_UNFOLDED : SPR_CIRCLE_FOLDED, PAL_NONE, iconleft, tr.top + (FONT_HEIGHT_NORMAL - iconheight) / 2);
|
|
|
}
|
|
|
}
|
|
|
|
|
|
TextColour colour = (sel[0] == (int)i && (uint)sel[1] == j) ? TC_WHITE : TC_BLACK;
|
|
|
TextColour colour = (sel != nullptr && sel->cargo == refit.cargo && sel->subtype == refit.subtype) ? TC_WHITE : TC_BLACK;
|
|
|
/* Get the cargo name. */
|
|
|
SetDParam(0, CargoSpec::Get(refit.cargo)->name);
|
|
|
SetDParam(1, refit.string);
|
|
|
DrawString(tr, STR_JUST_STRING_STRING, colour);
|
|
|
|
|
|
tr.top += delta;
|
|
|
current++;
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
/** Refit cargo window. */
|
|
|
struct RefitWindow : public Window {
|
|
|
int sel[2]; ///< Index in refit options, sel[0] == -1 if nothing is selected.
|
|
|
RefitOption *cargo; ///< Refit option selected by #sel.
|
|
|
SubtypeList list[NUM_CARGO]; ///< List of refit subtypes available for each sorted cargo.
|
|
|
const RefitOption *selected_refit; ///< Selected refit option.
|
|
|
RefitOptions refit_list; ///< List of refit subtypes available for each sorted cargo.
|
|
|
VehicleOrderID order; ///< If not #INVALID_VEH_ORDER_ID, selection is part of a refit order (rather than execute directly).
|
|
|
uint information_width; ///< Width required for correctly displaying all cargoes in the information panel.
|
|
|
Scrollbar *vscroll; ///< The main scrollbar.
|
|
|
Scrollbar *hscroll; ///< Only used for long vehicles.
|
|
|
int vehicle_width; ///< Width of the vehicle being drawn.
|
|
|
int sprite_left; ///< Left position of the vehicle sprite.
|
|
|
int sprite_right; ///< Right position of the vehicle sprite.
|
|
|
uint vehicle_margin; ///< Margin to use while selecting vehicles when the vehicle image is centered.
|
|
|
int click_x; ///< Position of the first click while dragging.
|
|
|
VehicleID selected_vehicle; ///< First vehicle in the current selection.
|
|
|
uint8_t num_vehicles; ///< Number of selected vehicles.
|
|
|
bool auto_refit; ///< Select cargo for auto-refitting.
|
|
|
|
|
|
/**
|
|
|
* Collects all (cargo, subcargo) refit options of a vehicle chain.
|
|
|
*/
|
|
|
void BuildRefitList()
|
|
|
{
|
|
|
for (uint i = 0; i < NUM_CARGO; i++) this->list[i].clear();
|
|
|
/* Store the currently selected RefitOption. */
|
|
|
std::optional<RefitOption> current_refit_option;
|
|
|
if (this->selected_refit != nullptr) current_refit_option = *(this->selected_refit);
|
|
|
this->selected_refit = nullptr;
|
|
|
|
|
|
this->refit_list.clear();
|
|
|
Vehicle *v = Vehicle::Get(this->window_number);
|
|
|
|
|
|
/* Check only the selected vehicles. */
|
|
|
VehicleSet vehicles_to_refit;
|
|
|
GetVehicleSet(vehicles_to_refit, Vehicle::Get(this->selected_vehicle), this->num_vehicles);
|
|
|
|
|
|
do {
|
|
|
if (v->type == VEH_TRAIN && std::find(vehicles_to_refit.begin(), vehicles_to_refit.end(), v->index) == vehicles_to_refit.end()) continue;
|
|
|
const Engine *e = v->GetEngine();
|
|
|
CargoTypes cmask = e->info.refit_mask;
|
|
|
byte callback_mask = e->info.callback_mask;
|
|
|
|
|
|
/* Skip this engine if it does not carry anything */
|
|
|
if (!e->CanCarryCargo()) continue;
|
|
|
/* Skip this engine if we build the list for auto-refitting and engine doesn't allow it. */
|
|
|
if (this->auto_refit && !HasBit(e->info.misc_flags, EF_AUTO_REFIT)) continue;
|
|
|
|
|
|
/* Loop through all cargoes in the refit mask */
|
|
|
int current_index = 0;
|
|
|
for (const auto &cs : _sorted_cargo_specs) {
|
|
|
CargoID cid = cs->Index();
|
|
|
/* Skip cargo type if it's not listed */
|
|
|
if (!HasBit(cmask, cid)) {
|
|
|
current_index++;
|
|
|
continue;
|
|
|
}
|
|
|
|
|
|
bool first_vehicle = this->list[current_index].size() == 0;
|
|
|
if (!HasBit(cmask, cid)) continue;
|
|
|
|
|
|
auto &list = this->refit_list[cid];
|
|
|
bool first_vehicle = list.size() == 0;
|
|
|
if (first_vehicle) {
|
|
|
/* Keeping the current subtype is always an option. It also serves as the option in case of no subtypes */
|
|
|
this->list[current_index].push_back({cid, 0xFF, STR_EMPTY});
|
|
|
list.push_back({cid, UINT8_MAX, STR_EMPTY});
|
|
|
}
|
|
|
|
|
|
/* Check the vehicle's callback mask for cargo suffixes.
|
|
|
* This is not supported for ordered refits, since subtypes only have a meaning
|
|
|
* for a specific vehicle at a specific point in time, which conflicts with shared orders,
|
|
|
* autoreplace, autorenew, clone, order restoration, ... */
|
|
|
if (this->order == INVALID_VEH_ORDER_ID && HasBit(callback_mask, CBM_VEHICLE_CARGO_SUFFIX)) {
|
|
|
/* Make a note of the original cargo type. It has to be
|
|
|
* changed to test the cargo & subtype... */
|
|
|
CargoID temp_cargo = v->cargo_type;
|
|
|
byte temp_subtype = v->cargo_subtype;
|
|
|
|
|
@@ -692,184 +694,149 @@ struct RefitWindow : public Window {
|
|
|
v->InvalidateNewGRFCache();
|
|
|
|
|
|
StringID subtype = GetCargoSubtypeText(v);
|
|
|
|
|
|
if (first_vehicle) {
|
|
|
/* Append new subtype (don't add duplicates though) */
|
|
|
if (subtype == STR_EMPTY) break;
|
|
|
|
|
|
RefitOption option;
|
|
|
option.cargo = cid;
|
|
|
option.subtype = refit_cyc;
|
|
|
option.string = subtype;
|
|
|
include(this->list[current_index], option);
|
|
|
include(list, option);
|
|
|
} else {
|
|
|
/* Intersect the subtypes of earlier vehicles with the subtypes of this vehicle */
|
|
|
if (subtype == STR_EMPTY) {
|
|
|
/* No more subtypes for this vehicle, delete all subtypes >= refit_cyc */
|
|
|
SubtypeList &l = this->list[current_index];
|
|
|
/* 0xFF item is in front, other subtypes are sorted. So just truncate the list in the right spot */
|
|
|
for (uint i = 1; i < l.size(); i++) {
|
|
|
if (l[i].subtype >= refit_cyc) {
|
|
|
l.resize(i);
|
|
|
/* UINT8_MAX item is in front, other subtypes are sorted. So just truncate the list in the right spot */
|
|
|
for (uint i = 1; i < list.size(); i++) {
|
|
|
if (list[i].subtype >= refit_cyc) {
|
|
|
list.resize(i);
|
|
|
break;
|
|
|
}
|
|
|
}
|
|
|
break;
|
|
|
} else {
|
|
|
/* Check whether the subtype matches with the subtype of earlier vehicles. */
|
|
|
uint pos = 1;
|
|
|
SubtypeList &l = this->list[current_index];
|
|
|
while (pos < l.size() && l[pos].subtype != refit_cyc) pos++;
|
|
|
if (pos < l.size() && l[pos].string != subtype) {
|
|
|
while (pos < list.size() && list[pos].subtype != refit_cyc) pos++;
|
|
|
if (pos < list.size() && list[pos].string != subtype) {
|
|
|
/* String mismatch, remove item keeping the order */
|
|
|
l.erase(l.begin() + pos);
|
|
|
list.erase(list.begin() + pos);
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
/* Reset the vehicle's cargo type */
|
|
|
v->cargo_type = temp_cargo;
|
|
|
v->cargo_subtype = temp_subtype;
|
|
|
|
|
|
/* And make sure we haven't tainted the cache */
|
|
|
v->First()->InvalidateNewGRFCache();
|
|
|
v->InvalidateNewGRFCache();
|
|
|
}
|
|
|
current_index++;
|
|
|
}
|
|
|
} while (v->IsGroundVehicle() && (v = v->Next()) != nullptr);
|
|
|
|
|
|
/* Restore the previously selected RefitOption. */
|
|
|
if (current_refit_option.has_value()) {
|
|
|
for (const auto &pair : this->refit_list) {
|
|
|
for (const auto &refit : pair.second) {
|
|
|
if (refit.cargo == current_refit_option->cargo && refit.subtype == current_refit_option->subtype) {
|
|
|
this->selected_refit = &refit;
|
|
|
break;
|
|
|
}
|
|
|
}
|
|
|
if (this->selected_refit != nullptr) break;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
this->SetWidgetDisabledState(WID_VR_REFIT, this->selected_refit == nullptr);
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* Refresh scrollbar after selection changed
|
|
|
*/
|
|
|
void RefreshScrollbar()
|
|
|
{
|
|
|
uint scroll_row = 0;
|
|
|
uint row = 0;
|
|
|
|
|
|
for (uint i = 0; i < NUM_CARGO; i++) {
|
|
|
for (uint j = 0; j < this->list[i].size(); j++) {
|
|
|
const RefitOption &refit = this->list[i][j];
|
|
|
|
|
|
/* Hide subtypes if sel[0] does not match */
|
|
|
if (this->sel[0] != (int)i && refit.subtype != 0xFF) continue;
|
|
|
|
|
|
if (this->sel[0] == (int)i && (uint)this->sel[1] == j) scroll_row = row;
|
|
|
|
|
|
row++;
|
|
|
size_t scroll_row = 0;
|
|
|
size_t rows = 0;
|
|
|
CargoID cargo = this->selected_refit == nullptr ? (CargoID)CT_INVALID : this->selected_refit->cargo;
|
|
|
|
|
|
for (const auto &pair : this->refit_list) {
|
|
|
if (pair.first == cargo) {
|
|
|
/* selected_refit points to an element in the vector so no need to search for it. */
|
|
|
scroll_row = rows + (this->selected_refit - pair.second.data());
|
|
|
rows += pair.second.size();
|
|
|
} else {
|
|
|
rows++; /* Unselected cargo type is collapsed into one row. */
|
|
|
}
|
|
|
}
|
|
|
|
|
|
this->vscroll->SetCount(row);
|
|
|
if (scroll_row < row) this->vscroll->ScrollTowards(scroll_row);
|
|
|
this->vscroll->SetCount(rows);
|
|
|
this->vscroll->ScrollTowards(static_cast<int>(scroll_row));
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* Select a row.
|
|
|
* @param click_row Clicked row
|
|
|
*/
|
|
|
void SetSelection(uint click_row)
|
|
|
{
|
|
|
uint row = 0;
|
|
|
|
|
|
for (uint i = 0; i < NUM_CARGO; i++) {
|
|
|
for (uint j = 0; j < this->list[i].size(); j++) {
|
|
|
const RefitOption &refit = this->list[i][j];
|
|
|
|
|
|
/* Hide subtypes if sel[0] does not match */
|
|
|
if (this->sel[0] != (int)i && refit.subtype != 0xFF) continue;
|
|
|
|
|
|
for (const auto &pair : refit_list) {
|
|
|
for (const RefitOption &refit : pair.second) {
|
|
|
if (row == click_row) {
|
|
|
this->sel[0] = i;
|
|
|
this->sel[1] = j;
|
|
|
this->selected_refit = &refit;
|
|
|
return;
|
|
|
}
|
|
|
|
|
|
row++;
|
|
|
/* If this cargo type is not already selected then its subtypes are not visible, so skip the rest. */
|
|
|
if (this->selected_refit == nullptr || this->selected_refit->cargo != refit.cargo) break;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
this->sel[0] = -1;
|
|
|
this->sel[1] = 0;
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* Gets the #RefitOption placed in the selected index.
|
|
|
* @return Pointer to the #RefitOption currently in use.
|
|
|
*/
|
|
|
RefitOption *GetRefitOption()
|
|
|
{
|
|
|
if (this->sel[0] < 0) return nullptr;
|
|
|
|
|
|
SubtypeList &l = this->list[this->sel[0]];
|
|
|
if ((uint)this->sel[1] >= l.size()) return nullptr;
|
|
|
|
|
|
return &l[this->sel[1]];
|
|
|
/* No selection made */
|
|
|
this->selected_refit = nullptr;
|
|
|
}
|
|
|
|
|
|
RefitWindow(WindowDesc *desc, const Vehicle *v, VehicleOrderID order, bool auto_refit) : Window(desc)
|
|
|
{
|
|
|
this->sel[0] = -1;
|
|
|
this->sel[1] = 0;
|
|
|
this->auto_refit = auto_refit;
|
|
|
this->order = order;
|
|
|
this->CreateNestedTree();
|
|
|
|
|
|
this->vscroll = this->GetScrollbar(WID_VR_SCROLLBAR);
|
|
|
this->hscroll = (v->IsGroundVehicle() ? this->GetScrollbar(WID_VR_HSCROLLBAR) : nullptr);
|
|
|
this->GetWidget<NWidgetCore>(WID_VR_SELECT_HEADER)->tool_tip = STR_REFIT_TRAIN_LIST_TOOLTIP + v->type;
|
|
|
this->GetWidget<NWidgetCore>(WID_VR_MATRIX)->tool_tip = STR_REFIT_TRAIN_LIST_TOOLTIP + v->type;
|
|
|
NWidgetCore *nwi = this->GetWidget<NWidgetCore>(WID_VR_REFIT);
|
|
|
nwi->widget_data = STR_REFIT_TRAIN_REFIT_BUTTON + v->type;
|
|
|
nwi->tool_tip = STR_REFIT_TRAIN_REFIT_TOOLTIP + v->type;
|
|
|
this->GetWidget<NWidgetStacked>(WID_VR_SHOW_HSCROLLBAR)->SetDisplayedPlane(v->IsGroundVehicle() ? 0 : SZSP_HORIZONTAL);
|
|
|
this->GetWidget<NWidgetCore>(WID_VR_VEHICLE_PANEL_DISPLAY)->tool_tip = (v->type == VEH_TRAIN) ? STR_REFIT_SELECT_VEHICLES_TOOLTIP : STR_NULL;
|
|
|
|
|
|
this->FinishInitNested(v->index);
|
|
|
this->owner = v->owner;
|
|
|
|
|
|
this->SetWidgetDisabledState(WID_VR_REFIT, this->sel[0] < 0);
|
|
|
this->SetWidgetDisabledState(WID_VR_REFIT, this->selected_refit == nullptr);
|
|
|
}
|
|
|
|
|
|
void OnInit() override
|
|
|
{
|
|
|
if (this->cargo != nullptr) {
|
|
|
/* Store the RefitOption currently in use. */
|
|
|
RefitOption current_refit_option = *(this->cargo);
|
|
|
|
|
|
/* Rebuild the refit list */
|
|
|
this->BuildRefitList();
|
|
|
this->sel[0] = -1;
|
|
|
this->sel[1] = 0;
|
|
|
this->cargo = nullptr;
|
|
|
for (uint i = 0; this->cargo == nullptr && i < NUM_CARGO; i++) {
|
|
|
for (uint j = 0; j < list[i].size(); j++) {
|
|
|
if (list[i][j] == current_refit_option) {
|
|
|
this->sel[0] = i;
|
|
|
this->sel[1] = j;
|
|
|
this->cargo = &list[i][j];
|
|
|
break;
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
this->SetWidgetDisabledState(WID_VR_REFIT, this->sel[0] < 0);
|
|
|
this->RefreshScrollbar();
|
|
|
} else {
|
|
|
/* Rebuild the refit list */
|
|
|
this->OnInvalidateData(VIWD_CONSIST_CHANGED);
|
|
|
}
|
|
|
/* (Re)build the refit list */
|
|
|
this->OnInvalidateData(VIWD_CONSIST_CHANGED);
|
|
|
}
|
|
|
|
|
|
void OnPaint() override
|
|
|
{
|
|
|
/* Determine amount of items for scroller. */
|
|
|
if (this->hscroll != nullptr) this->hscroll->SetCount(this->vehicle_width);
|
|
|
|
|
|
/* Calculate sprite position. */
|
|
|
NWidgetCore *vehicle_panel_display = this->GetWidget<NWidgetCore>(WID_VR_VEHICLE_PANEL_DISPLAY);
|
|
|
int sprite_width = std::max(0, ((int)vehicle_panel_display->current_x - this->vehicle_width) / 2);
|
|
|
this->sprite_left = vehicle_panel_display->pos_x;
|
|
|
this->sprite_right = vehicle_panel_display->pos_x + vehicle_panel_display->current_x - 1;
|
|
@@ -904,32 +871,32 @@ struct RefitWindow : public Window {
|
|
|
|
|
|
void SetStringParameters(int widget) const override
|
|
|
{
|
|
|
if (widget == WID_VR_CAPTION) SetDParam(0, Vehicle::Get(this->window_number)->index);
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* Gets the #StringID to use for displaying capacity.
|
|
|
* @param option Cargo and cargo subtype to check for capacity.
|
|
|
* @return INVALID_STRING_ID if there is no capacity. StringID to use in any other case.
|
|
|
* @post String parameters have been set.
|
|
|
*/
|
|
|
StringID GetCapacityString(RefitOption *option) const
|
|
|
StringID GetCapacityString(const RefitOption &option) const
|
|
|
{
|
|
|
assert(_current_company == _local_company);
|
|
|
auto [cost, refit_capacity, mail_capacity, cargo_capacities] = Command<CMD_REFIT_VEHICLE>::Do(DC_QUERY_COST, this->selected_vehicle, option->cargo, option->subtype, this->auto_refit, false, this->num_vehicles);
|
|
|
auto [cost, refit_capacity, mail_capacity, cargo_capacities] = Command<CMD_REFIT_VEHICLE>::Do(DC_QUERY_COST, this->selected_vehicle, option.cargo, option.subtype, this->auto_refit, false, this->num_vehicles);
|
|
|
|
|
|
if (cost.Failed()) return INVALID_STRING_ID;
|
|
|
|
|
|
SetDParam(0, option->cargo);
|
|
|
SetDParam(0, option.cargo);
|
|
|
SetDParam(1, refit_capacity);
|
|
|
|
|
|
Money money = cost.GetCost();
|
|
|
if (mail_capacity > 0) {
|
|
|
SetDParam(2, CT_MAIL);
|
|
|
SetDParam(3, mail_capacity);
|
|
|
if (this->order != INVALID_VEH_ORDER_ID) {
|
|
|
/* No predictable cost */
|
|
|
return STR_PURCHASE_INFO_AIRCRAFT_CAPACITY;
|
|
|
} else if (money <= 0) {
|
|
|
SetDParam(4, -money);
|
|
|
return STR_REFIT_NEW_CAPACITY_INCOME_FROM_AIRCRAFT_REFIT;
|
|
@@ -1012,30 +979,30 @@ struct RefitWindow : public Window {
|
|
|
width += current_width;
|
|
|
x += current_width;
|
|
|
}
|
|
|
break;
|
|
|
}
|
|
|
|
|
|
default: break;
|
|
|
}
|
|
|
break;
|
|
|
}
|
|
|
|
|
|
case WID_VR_MATRIX:
|
|
|
DrawVehicleRefitWindow(this->list, this->sel, this->vscroll->GetPosition(), this->vscroll->GetCapacity(), this->resize.step_height, r);
|
|
|
DrawVehicleRefitWindow(this->refit_list, this->selected_refit, this->vscroll->GetPosition(), this->vscroll->GetCapacity(), this->resize.step_height, r);
|
|
|
break;
|
|
|
|
|
|
case WID_VR_INFO:
|
|
|
if (this->cargo != nullptr) {
|
|
|
StringID string = this->GetCapacityString(this->cargo);
|
|
|
if (this->selected_refit != nullptr) {
|
|
|
StringID string = this->GetCapacityString(*this->selected_refit);
|
|
|
if (string != INVALID_STRING_ID) {
|
|
|
DrawStringMultiLine(r.Shrink(WidgetDimensions::scaled.framerect), string);
|
|
|
}
|
|
|
}
|
|
|
break;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
* 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.
|
|
@@ -1052,44 +1019,43 @@ struct RefitWindow : public Window {
|
|
|
FALLTHROUGH;
|
|
|
}
|
|
|
|
|
|
case 2: { // The vehicle selection has changed; rebuild the entire list.
|
|
|
if (!gui_scope) break;
|
|
|
this->BuildRefitList();
|
|
|
|
|
|
/* The vehicle width has changed too. */
|
|
|
this->vehicle_width = GetVehicleWidth(Vehicle::Get(this->window_number), EIT_IN_DETAILS);
|
|
|
uint max_width = 0;
|
|
|
|
|
|
/* Check the width of all cargo information strings. */
|
|
|
for (uint i = 0; i < NUM_CARGO; i++) {
|
|
|
for (uint j = 0; j < this->list[i].size(); j++) {
|
|
|
StringID string = this->GetCapacityString(&list[i][j]);
|
|
|
for (const auto &list : this->refit_list) {
|
|
|
for (const RefitOption &refit : list.second) {
|
|
|
StringID string = this->GetCapacityString(refit);
|
|
|
if (string != INVALID_STRING_ID) {
|
|
|
Dimension dim = GetStringBoundingBox(string);
|
|
|
max_width = std::max(dim.width, max_width);
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
if (this->information_width < max_width) {
|
|
|
this->information_width = max_width;
|
|
|
this->ReInit();
|
|
|
}
|
|
|
FALLTHROUGH;
|
|
|
}
|
|
|
|
|
|
case 1: // A new cargo has been selected.
|
|
|
if (!gui_scope) break;
|
|
|
this->cargo = GetRefitOption();
|
|
|
this->RefreshScrollbar();
|
|
|
break;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
int GetClickPosition(int click_x)
|
|
|
{
|
|
|
const NWidgetCore *matrix_widget = this->GetWidget<NWidgetCore>(WID_VR_VEHICLE_PANEL_DISPLAY);
|
|
|
if (_current_text_dir == TD_RTL) click_x = matrix_widget->current_x - click_x;
|
|
|
click_x -= this->vehicle_margin;
|
|
|
if (this->hscroll != nullptr) click_x += this->hscroll->GetPosition();
|
|
|
|
|
@@ -1159,40 +1125,40 @@ struct RefitWindow : public Window {
|
|
|
this->SetWidgetDirty(WID_VR_VEHICLE_PANEL_DISPLAY);
|
|
|
if (!_ctrl_pressed) {
|
|
|
SetObjectToPlaceWnd(SPR_CURSOR_MOUSE, PAL_NONE, HT_DRAG, this);
|
|
|
} else {
|
|
|
/* The vehicle selection has changed. */
|
|
|
this->InvalidateData(2);
|
|
|
}
|
|
|
break;
|
|
|
}
|
|
|
|
|
|
case WID_VR_MATRIX: { // listbox
|
|
|
this->SetSelection(this->vscroll->GetScrolledRowFromWidget(pt.y, this, WID_VR_MATRIX));
|
|
|
this->SetWidgetDisabledState(WID_VR_REFIT, this->sel[0] < 0);
|
|
|
this->SetWidgetDisabledState(WID_VR_REFIT, this->selected_refit == nullptr);
|
|
|
this->InvalidateData(1);
|
|
|
|
|
|
if (click_count == 1) break;
|
|
|
FALLTHROUGH;
|
|
|
}
|
|
|
|
|
|
case WID_VR_REFIT: // refit button
|
|
|
if (this->cargo != nullptr) {
|
|
|
if (this->selected_refit != nullptr) {
|
|
|
const Vehicle *v = Vehicle::Get(this->window_number);
|
|
|
|
|
|
if (this->order == INVALID_VEH_ORDER_ID) {
|
|
|
bool delete_window = this->selected_vehicle == v->index && this->num_vehicles == UINT8_MAX;
|
|
|
if (Command<CMD_REFIT_VEHICLE>::Post(GetCmdRefitVehMsg(v), v->tile, this->selected_vehicle, this->cargo->cargo, this->cargo->subtype, false, false, this->num_vehicles) && delete_window) this->Close();
|
|
|
if (Command<CMD_REFIT_VEHICLE>::Post(GetCmdRefitVehMsg(v), v->tile, this->selected_vehicle, this->selected_refit->cargo, this->selected_refit->subtype, false, false, this->num_vehicles) && delete_window) this->Close();
|
|
|
} else {
|
|
|
if (Command<CMD_ORDER_REFIT>::Post(v->tile, v->index, this->order, this->cargo->cargo)) this->Close();
|
|
|
if (Command<CMD_ORDER_REFIT>::Post(v->tile, v->index, this->order, this->selected_refit->cargo)) this->Close();
|
|
|
}
|
|
|
}
|
|
|
break;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
void OnMouseDrag(Point pt, int widget) override
|
|
|
{
|
|
|
switch (widget) {
|
|
|
case WID_VR_VEHICLE_PANEL_DISPLAY: { // Vehicle image.
|
|
|
if (this->order != INVALID_VEH_ORDER_ID) break;
|
|
|
NWidgetBase *nwi = this->GetWidget<NWidgetBase>(WID_VR_VEHICLE_PANEL_DISPLAY);
|