Changeset - r21353:433db3a92931
[Not reviewed]
master
0 11 0
peter1138 - 10 years ago 2014-04-08 21:09:06
peter1138@openttd.org
(svn r26450) -Feature: Hierarchical vehicle subgroups.
11 files changed with 218 insertions and 51 deletions:
0 comments (0 inline, 0 general)
src/autoreplace.cpp
Show inline comments
 
@@ -25,13 +25,13 @@ INSTANTIATE_POOL_METHODS(EngineRenew)
 
 */
 
static EngineRenew *GetEngineReplacement(EngineRenewList erl, EngineID engine, GroupID group)
 
{
 
	EngineRenew *er = (EngineRenew *)erl;
 

	
 
	while (er != NULL) {
 
		if (er->from == engine && er->group_id == group) return er;
 
		if (er->from == engine && GroupIsInGroup(group, er->group_id)) return er;
 
		er = er->next;
 
	}
 
	return NULL;
 
}
 

	
 
/**
src/command.cpp
Show inline comments
 
@@ -177,13 +177,13 @@ CommandProc CmdStartStopVehicle;
 
CommandProc CmdMassStartStopVehicle;
 
CommandProc CmdAutoreplaceVehicle;
 
CommandProc CmdDepotSellAllVehicles;
 
CommandProc CmdDepotMassAutoReplace;
 

	
 
CommandProc CmdCreateGroup;
 
CommandProc CmdRenameGroup;
 
CommandProc CmdAlterGroup;
 
CommandProc CmdDeleteGroup;
 
CommandProc CmdAddVehicleGroup;
 
CommandProc CmdAddSharedVehicleGroup;
 
CommandProc CmdRemoveAllVehiclesGroup;
 
CommandProc CmdSetGroupReplaceProtection;
 

	
 
@@ -335,13 +335,13 @@ static const Command _command_proc_table
 
	DEF_CMD(CmdMassStartStopVehicle,                           0, CMDT_VEHICLE_MANAGEMENT    ), // CMD_MASS_START_STOP
 
	DEF_CMD(CmdAutoreplaceVehicle,                             0, CMDT_VEHICLE_MANAGEMENT    ), // CMD_AUTOREPLACE_VEHICLE
 
	DEF_CMD(CmdDepotSellAllVehicles,                           0, CMDT_VEHICLE_CONSTRUCTION  ), // CMD_DEPOT_SELL_ALL_VEHICLES
 
	DEF_CMD(CmdDepotMassAutoReplace,                           0, CMDT_VEHICLE_CONSTRUCTION  ), // CMD_DEPOT_MASS_AUTOREPLACE
 
	DEF_CMD(CmdCreateGroup,                                    0, CMDT_ROUTE_MANAGEMENT      ), // CMD_CREATE_GROUP
 
	DEF_CMD(CmdDeleteGroup,                                    0, CMDT_ROUTE_MANAGEMENT      ), // CMD_DELETE_GROUP
 
	DEF_CMD(CmdRenameGroup,                                    0, CMDT_OTHER_MANAGEMENT      ), // CMD_RENAME_GROUP
 
	DEF_CMD(CmdAlterGroup,                                     0, CMDT_OTHER_MANAGEMENT      ), // CMD_ALTER_GROUP
 
	DEF_CMD(CmdAddVehicleGroup,                                0, CMDT_ROUTE_MANAGEMENT      ), // CMD_ADD_VEHICLE_GROUP
 
	DEF_CMD(CmdAddSharedVehicleGroup,                          0, CMDT_ROUTE_MANAGEMENT      ), // CMD_ADD_SHARE_VEHICLE_GROUP
 
	DEF_CMD(CmdRemoveAllVehiclesGroup,                         0, CMDT_ROUTE_MANAGEMENT      ), // CMD_REMOVE_ALL_VEHICLES_GROUP
 
	DEF_CMD(CmdSetGroupReplaceProtection,                      0, CMDT_ROUTE_MANAGEMENT      ), // CMD_SET_GROUP_REPLACE_PROTECTION
 
	DEF_CMD(CmdMoveOrder,                                      0, CMDT_ROUTE_MANAGEMENT      ), // CMD_MOVE_ORDER
 
	DEF_CMD(CmdChangeTimetable,                                0, CMDT_ROUTE_MANAGEMENT      ), // CMD_CHANGE_TIMETABLE
src/command_type.h
Show inline comments
 
@@ -311,13 +311,13 @@ enum Commands {
 
	CMD_AUTOREPLACE_VEHICLE,          ///< replace/renew a vehicle while it is in a depot
 
	CMD_DEPOT_SELL_ALL_VEHICLES,      ///< sell all vehicles which are in a given depot
 
	CMD_DEPOT_MASS_AUTOREPLACE,       ///< force the autoreplace to take action in a given depot
 

	
 
	CMD_CREATE_GROUP,                 ///< create a new group
 
	CMD_DELETE_GROUP,                 ///< delete a group
 
	CMD_RENAME_GROUP,                 ///< rename a group
 
	CMD_ALTER_GROUP,                  ///< alter a group
 
	CMD_ADD_VEHICLE_GROUP,            ///< add a vehicle to a group
 
	CMD_ADD_SHARED_VEHICLE_GROUP,     ///< add all other shared vehicles to a group which are missing
 
	CMD_REMOVE_ALL_VEHICLES_GROUP,    ///< remove all vehicles from a group
 
	CMD_SET_GROUP_REPLACE_PROTECTION, ///< set the autoreplace-protection for a group
 

	
 
	CMD_MOVE_ORDER,                   ///< move an order
src/group.h
Show inline comments
 
@@ -68,12 +68,14 @@ struct Group : GroupPool::PoolItem<&_gro
 
	OwnerByte owner;                        ///< Group Owner
 
	VehicleTypeByte vehicle_type;           ///< Vehicle type of the group
 

	
 
	bool replace_protection;                ///< If set to true, the global autoreplace have no effect on the group
 
	GroupStatistics statistics;             ///< NOSAVE: Statistics and caches on the vehicles in the group.
 

	
 
	GroupID parent;                         ///< Parent group
 

	
 
	Group(CompanyID owner = INVALID_COMPANY);
 
	~Group();
 
};
 

	
 

	
 
static inline bool IsDefaultGroupID(GroupID index)
 
@@ -98,10 +100,11 @@ static inline bool IsAllGroupID(GroupID 
 
uint GetGroupNumEngines(CompanyID company, GroupID id_g, EngineID id_e);
 

	
 
void SetTrainGroupID(Train *v, GroupID grp);
 
void UpdateTrainGroupID(Train *v);
 
void RemoveVehicleFromGroup(const Vehicle *v);
 
void RemoveAllGroupsForCompany(const CompanyID company);
 
bool GroupIsInGroup(GroupID search, GroupID group);
 

	
 
extern GroupID _new_group_id;
 

	
 
#endif /* GROUP_H */
src/group_cmd.cpp
Show inline comments
 
@@ -282,12 +282,13 @@ CommandCost CmdCreateGroup(TileIndex til
 
	if (!Group::CanAllocateItem()) return CMD_ERROR;
 

	
 
	if (flags & DC_EXEC) {
 
		Group *g = new Group(_current_company);
 
		g->replace_protection = false;
 
		g->vehicle_type = vt;
 
		g->parent = INVALID_GROUP;
 

	
 
		_new_group_id = g->index;
 

	
 
		InvalidateWindowData(GetWindowClassForVehicleType(vt), VehicleListIdentifier(VL_GROUP_LIST, vt, _current_company).Pack());
 
	}
 

	
 
@@ -310,12 +311,20 @@ CommandCost CmdDeleteGroup(TileIndex til
 
	Group *g = Group::GetIfValid(p1);
 
	if (g == NULL || g->owner != _current_company) return CMD_ERROR;
 

	
 
	/* Remove all vehicles from the group */
 
	DoCommand(0, p1, 0, flags, CMD_REMOVE_ALL_VEHICLES_GROUP);
 

	
 
	/* Delete sub-groups */
 
	Group *gp;
 
	FOR_ALL_GROUPS(gp) {
 
		if (gp->parent == g->index) {
 
			DoCommand(0, gp->index, 0, flags, CMD_DELETE_GROUP);
 
		}
 
	}
 

	
 
	if (flags & DC_EXEC) {
 
		/* Update backupped orders if needed */
 
		OrderBackup::ClearGroup(g->index);
 

	
 
		/* If we set an autoreplace for the group we delete, remove it. */
 
		if (_current_company < MAX_COMPANIES) {
 
@@ -349,39 +358,66 @@ static bool IsUniqueGroupNameForVehicleT
 
	}
 

	
 
	return true;
 
}
 

	
 
/**
 
 * Rename a group
 
 * Alter a group
 
 * @param tile unused
 
 * @param flags type of operation
 
 * @param p1   index of array group
 
 *   - p1 bit 0-15 : GroupID
 
 * @param p2   unused
 
 *   - p1 bit 16: 0 - Rename grouop
 
 *                1 - Set group parent
 
 * @param p2   parent group index
 
 * @param text the new name or an empty string when resetting to the default
 
 * @return the cost of this operation or an error
 
 */
 
CommandCost CmdRenameGroup(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
 
CommandCost CmdAlterGroup(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
 
{
 
	Group *g = Group::GetIfValid(p1);
 
	Group *g = Group::GetIfValid(GB(p1, 0, 16));
 
	if (g == NULL || g->owner != _current_company) return CMD_ERROR;
 

	
 
	bool reset = StrEmpty(text);
 
	if (!HasBit(p1, 16)) {
 
		/* Rename group */
 
		bool reset = StrEmpty(text);
 

	
 
		if (!reset) {
 
			if (Utf8StringLength(text) >= MAX_LENGTH_GROUP_NAME_CHARS) return CMD_ERROR;
 
			if (!IsUniqueGroupNameForVehicleType(text, g->vehicle_type)) return_cmd_error(STR_ERROR_NAME_MUST_BE_UNIQUE);
 
		}
 

	
 
	if (!reset) {
 
		if (Utf8StringLength(text) >= MAX_LENGTH_GROUP_NAME_CHARS) return CMD_ERROR;
 
		if (!IsUniqueGroupNameForVehicleType(text, g->vehicle_type)) return_cmd_error(STR_ERROR_NAME_MUST_BE_UNIQUE);
 
		if (flags & DC_EXEC) {
 
			/* Delete the old name */
 
			free(g->name);
 
			/* Assign the new one */
 
			g->name = reset ? NULL : strdup(text);
 
		}
 
	} else {
 
		/* Set group parent */
 
		const Group *pg = Group::GetIfValid(GB(p2, 0, 16));
 

	
 
		if (pg != NULL) {
 
			if (pg->owner != _current_company) return CMD_ERROR;
 
			if (pg->vehicle_type != g->vehicle_type) return CMD_ERROR;
 

	
 
			/* Ensure request parent isn't child of group.
 
			 * This is the only place that infinite loops are prevented. */
 
			const Group *looptest = pg;
 
			while (looptest->parent != INVALID_GROUP) {
 
				if (looptest->parent == g->index) return CMD_ERROR;
 
				looptest = Group::Get(looptest->parent);
 
			}
 
		}
 

	
 
		if (flags & DC_EXEC) {
 
			g->parent = (pg == NULL) ? INVALID_GROUP : pg->index;
 
		}
 
	}
 

	
 
	if (flags & DC_EXEC) {
 
		/* Delete the old name */
 
		free(g->name);
 
		/* Assign the new one */
 
		g->name = reset ? NULL : strdup(text);
 

	
 
		SetWindowDirty(WC_REPLACE_VEHICLE, g->vehicle_type);
 
		InvalidateWindowData(GetWindowClassForVehicleType(g->vehicle_type), VehicleListIdentifier(VL_GROUP_LIST, g->vehicle_type, _current_company).Pack());
 
	}
 

	
 
	return CommandCost();
 
}
 
@@ -539,31 +575,50 @@ CommandCost CmdRemoveAllVehiclesGroup(Ti
 
		InvalidateWindowData(GetWindowClassForVehicleType(g->vehicle_type), VehicleListIdentifier(VL_GROUP_LIST, g->vehicle_type, _current_company).Pack());
 
	}
 

	
 
	return CommandCost();
 
}
 

	
 
/**
 
 * Set replace protection for a group and its sub-groups.
 
 * @param g initial group.
 
 * @param protect 1 to set or 0 to clear protection.
 
 */
 
static void SetGroupReplaceProtection(Group *g, bool protect)
 
{
 
	g->replace_protection = protect;
 

	
 
	Group *pg;
 
	FOR_ALL_GROUPS(pg) {
 
		if (pg->parent == g->index) SetGroupReplaceProtection(pg, protect);
 
	}
 
}
 

	
 
/**
 
 * (Un)set global replace protection from a group
 
 * @param tile unused
 
 * @param flags type of operation
 
 * @param p1   index of group array
 
 * - p1 bit 0-15 : GroupID
 
 * @param p2
 
 * - p2 bit 0    : 1 to set or 0 to clear protection.
 
 * - p2 bit 1    : 1 to apply to sub-groups.
 
 * @param text unused
 
 * @return the cost of this operation or an error
 
 */
 
CommandCost CmdSetGroupReplaceProtection(TileIndex tile, DoCommandFlag flags, uint32 p1, uint32 p2, const char *text)
 
{
 
	Group *g = Group::GetIfValid(p1);
 
	if (g == NULL || g->owner != _current_company) return CMD_ERROR;
 

	
 
	if (flags & DC_EXEC) {
 
		g->replace_protection = HasBit(p2, 0);
 
		if (HasBit(p2, 1)) {
 
			SetGroupReplaceProtection(g, HasBit(p2, 0));
 
		} else {
 
			g->replace_protection = HasBit(p2, 0);
 
		}
 

	
 
		SetWindowDirty(GetWindowClassForVehicleType(g->vehicle_type), VehicleListIdentifier(VL_GROUP_LIST, g->vehicle_type, _current_company).Pack());
 
		InvalidateWindowData(WC_REPLACE_VEHICLE, g->vehicle_type);
 
	}
 

	
 
	return CommandCost();
 
@@ -636,18 +691,39 @@ void UpdateTrainGroupID(Train *v)
 
 * @param id_g The GroupID of the group used
 
 * @param id_e The EngineID of the engine to count
 
 * @return The number of engines with EngineID id_e in the group
 
 */
 
uint GetGroupNumEngines(CompanyID company, GroupID id_g, EngineID id_e)
 
{
 
	uint count = 0;
 
	const Engine *e = Engine::Get(id_e);
 
	return GroupStatistics::Get(company, id_g, e->type).num_engines[id_e];
 
	const Group *g;
 
	FOR_ALL_GROUPS(g) {
 
		if (g->parent == id_g) count += GetGroupNumEngines(company, g->index, id_e);
 
	}
 
	return count + GroupStatistics::Get(company, id_g, e->type).num_engines[id_e];
 
}
 

	
 
void RemoveAllGroupsForCompany(const CompanyID company)
 
{
 
	Group *g;
 

	
 
	FOR_ALL_GROUPS(g) {
 
		if (company == g->owner) delete g;
 
	}
 
}
 

	
 

	
 
bool GroupIsInGroup(GroupID search, GroupID group)
 
{
 
	if (search == NEW_GROUP ||
 
	    search == ALL_GROUP ||
 
	    search == DEFAULT_GROUP ||
 
	    search == INVALID_GROUP) return search == group;
 

	
 
	do {
 
		if (search == group) return true;
 
		search = Group::Get(search)->parent;
 
	} while (search != INVALID_GROUP);
 

	
 
	return false;
 
}
src/group_gui.cpp
Show inline comments
 
@@ -27,12 +27,14 @@
 
#include "company_base.h"
 

	
 
#include "widgets/group_widget.h"
 

	
 
#include "table/sprites.h"
 

	
 
static const int LEVEL_WIDTH = 10; ///< Indenting width of a sub-group in pixels
 

	
 
typedef GUIList<const Group*> GUIGroupList;
 

	
 
static const NWidgetPart _nested_group_widgets[] = {
 
	NWidget(NWID_HORIZONTAL), // Window header
 
		NWidget(WWT_CLOSEBOX, COLOUR_GREY),
 
		NWidget(WWT_CAPTION, COLOUR_GREY, WID_GL_CAPTION),
 
@@ -102,40 +104,32 @@ private:
 
		VGC_NUMBER,        ///< Number of vehicles in the group.
 

	
 
		VGC_END
 
	};
 

	
 
	VehicleID vehicle_sel; ///< Selected vehicle
 
	GroupID group_sel;     ///< Selected group (for drag/drop)
 
	GroupID group_rename;  ///< Group being renamed, INVALID_GROUP if none
 
	GroupID group_over;    ///< Group over which a vehicle is dragged, INVALID_GROUP if none
 
	GUIGroupList groups;   ///< List of groups
 
	uint tiny_step_height; ///< Step height for the group list
 
	Scrollbar *group_sb;
 

	
 
	SmallVector<int, 16> indents; ///< Indentation levels
 

	
 
	Dimension column_size[VGC_END]; ///< Size of the columns in the group list.
 

	
 
	/**
 
	 * (Re)Build the group list.
 
	 *
 
	 * @param owner The owner of the window
 
	 */
 
	void BuildGroupList(Owner owner)
 
	void AddParents(GUIGroupList *source, GroupID parent, int indent)
 
	{
 
		if (!this->groups.NeedRebuild()) return;
 

	
 
		this->groups.Clear();
 

	
 
		const Group *g;
 
		FOR_ALL_GROUPS(g) {
 
			if (g->owner == owner && g->vehicle_type == this->vli.vtype) {
 
				*this->groups.Append() = g;
 
		for (const Group **g = source->Begin(); g != source->End(); g++) {
 
			if ((*g)->parent == parent) {
 
				*this->groups.Append() = *g;
 
				*this->indents.Append() = indent;
 
				AddParents(source, (*g)->index, indent + 1);
 
			}
 
		}
 

	
 
		this->groups.Compact();
 
		this->groups.RebuildDone();
 
	}
 

	
 
	/** Sort the groups by their name */
 
	static int CDECL GroupNameSorter(const Group * const *a, const Group * const *b)
 
	{
 
		static const Group *last_group[2] = { NULL, NULL };
 
@@ -156,12 +150,42 @@ private:
 
		int r = strnatcmp(last_name[0], last_name[1]); // Sort by name (natural sorting).
 
		if (r == 0) return (*a)->index - (*b)->index;
 
		return r;
 
	}
 

	
 
	/**
 
	 * (Re)Build the group list.
 
	 *
 
	 * @param owner The owner of the window
 
	 */
 
	void BuildGroupList(Owner owner)
 
	{
 
		if (!this->groups.NeedRebuild()) return;
 

	
 
		this->groups.Clear();
 
		this->indents.Clear();
 

	
 
		GUIGroupList list;
 

	
 
		const Group *g;
 
		FOR_ALL_GROUPS(g) {
 
			if (g->owner == owner && g->vehicle_type == this->vli.vtype) {
 
				*list.Append() = g;
 
			}
 
		}
 

	
 
		list.ForceResort();
 
		list.Sort(&GroupNameSorter);
 

	
 
		AddParents(&list, INVALID_GROUP, 0);
 

	
 
		this->groups.Compact();
 
		this->groups.RebuildDone();
 
	}
 

	
 
	/**
 
	 * Compute tiny_step_height and column_size
 
	 * @return Total width required for the group list.
 
	 */
 
	uint ComputeGroupInfoSize()
 
	{
 
		this->column_size[VGC_NAME] = maxdim(GetStringBoundingBox(STR_GROUP_DEFAULT_TRAINS + this->vli.vtype), GetStringBoundingBox(STR_GROUP_ALL_TRAINS + this->vli.vtype));
 
@@ -201,15 +225,16 @@ private:
 
	/**
 
	 * Draw a row in the group list.
 
	 * @param y Top of the row.
 
	 * @param left Left of the row.
 
	 * @param right Right of the row.
 
	 * @param g_id Group to list.
 
	 * @param indent Indentation level.
 
	 * @param protection Whether autoreplace protection is set.
 
	 */
 
	void DrawGroupInfo(int y, int left, int right, GroupID g_id, bool protection = false) const
 
	void DrawGroupInfo(int y, int left, int right, GroupID g_id, int indent = 0, bool protection = false) const
 
	{
 
		/* Highlight the group if a vehicle is dragged over it */
 
		if (g_id == this->group_over) {
 
			GfxFillRect(left + WD_FRAMERECT_LEFT, y + WD_FRAMERECT_TOP, right - WD_FRAMERECT_RIGHT, y + this->tiny_step_height - WD_FRAMERECT_BOTTOM - WD_MATRIX_TOP, _colour_gradient[COLOUR_GREY][7]);
 
		}
 

	
 
@@ -228,13 +253,13 @@ private:
 
			str = STR_GROUP_DEFAULT_TRAINS + this->vli.vtype;
 
		} else {
 
			SetDParam(0, g_id);
 
			str = STR_GROUP_NAME;
 
		}
 
		int x = rtl ? right - WD_FRAMERECT_RIGHT - 8 - this->column_size[VGC_NAME].width + 1 : left + WD_FRAMERECT_LEFT + 8;
 
		DrawString(x, x + this->column_size[VGC_NAME].width - 1, y + (this->tiny_step_height - this->column_size[VGC_NAME].height) / 2, str, colour);
 
		DrawString(x + indent * LEVEL_WIDTH, x + this->column_size[VGC_NAME].width - 1, y + (this->tiny_step_height - this->column_size[VGC_NAME].height) / 2, str, colour);
 

	
 
		/* draw autoreplace protection */
 
		x = rtl ? x - 8 - this->column_size[VGC_PROTECT].width : x + 8 + this->column_size[VGC_NAME].width;
 
		if (protection) DrawSprite(SPR_GROUP_REPLACE_PROTECT, PAL_NONE, x, y + (this->tiny_step_height - this->column_size[VGC_PROTECT].height) / 2);
 

	
 
		/* draw autoreplace status */
 
@@ -292,12 +317,13 @@ public:
 
			case VEH_SHIP:     this->sorting = &_sorting.ship;     break;
 
			case VEH_AIRCRAFT: this->sorting = &_sorting.aircraft; break;
 
		}
 

	
 
		this->vli.index = ALL_GROUP;
 
		this->vehicle_sel = INVALID_VEHICLE;
 
		this->group_sel = INVALID_GROUP;
 
		this->group_rename = INVALID_GROUP;
 
		this->group_over = INVALID_GROUP;
 

	
 
		this->vehicles.SetListing(*this->sorting);
 
		this->vehicles.ForceRebuild();
 
		this->vehicles.NeedResort();
 
@@ -305,13 +331,12 @@ public:
 
		this->BuildVehicleList();
 
		this->SortVehicleList();
 

	
 
		this->groups.ForceRebuild();
 
		this->groups.NeedResort();
 
		this->BuildGroupList(vli.company);
 
		this->groups.Sort(&GroupNameSorter);
 

	
 
		this->GetWidget<NWidgetCore>(WID_GL_CAPTION)->widget_data = STR_VEHICLE_LIST_TRAIN_CAPTION + this->vli.vtype;
 
		this->GetWidget<NWidgetCore>(WID_GL_LIST_VEHICLE)->tool_tip = STR_VEHICLE_LIST_TRAIN_LIST_TOOLTIP + this->vli.vtype;
 

	
 
		this->GetWidget<NWidgetCore>(WID_GL_CREATE_GROUP)->widget_data += this->vli.vtype;
 
		this->GetWidget<NWidgetCore>(WID_GL_RENAME_GROUP)->widget_data += this->vli.vtype;
 
@@ -439,13 +464,12 @@ public:
 
		/* If we select the all vehicles, this->list will contain all vehicles of the owner
 
		 * else this->list will contain all vehicles which belong to the selected group */
 
		this->BuildVehicleList();
 
		this->SortVehicleList();
 

	
 
		this->BuildGroupList(this->owner);
 
		this->groups.Sort(&GroupNameSorter);
 

	
 
		this->group_sb->SetCount(this->groups.Length());
 
		this->vscroll->SetCount(this->vehicles.Length());
 

	
 
		/* The drop down menu is out, *but* it may not be used, retract it. */
 
		if (this->vehicles.Length() == 0 && this->IsWidgetLowered(WID_GL_MANAGE_VEHICLES_DROPDOWN)) {
 
@@ -505,13 +529,13 @@ public:
 
				int max = min(this->group_sb->GetPosition() + this->group_sb->GetCapacity(), this->groups.Length());
 
				for (int i = this->group_sb->GetPosition(); i < max; ++i) {
 
					const Group *g = this->groups[i];
 

	
 
					assert(g->owner == this->owner);
 

	
 
					DrawGroupInfo(y1, r.left, r.right, g->index, g->replace_protection);
 
					DrawGroupInfo(y1, r.left, r.right, g->index, this->indents[i], g->replace_protection);
 

	
 
					y1 += this->tiny_step_height;
 
				}
 
				if ((uint)this->group_sb->GetPosition() + this->group_sb->GetCapacity() > this->groups.Length()) {
 
					DrawGroupInfo(y1, r.left, r.right, NEW_GROUP);
 
				}
 
@@ -520,12 +544,25 @@ public:
 

	
 
			case WID_GL_SORT_BY_ORDER:
 
				this->DrawSortButtonState(WID_GL_SORT_BY_ORDER, this->vehicles.IsDescSortOrder() ? SBS_DOWN : SBS_UP);
 
				break;
 

	
 
			case WID_GL_LIST_VEHICLE:
 
				if (this->vli.index != ALL_GROUP) {
 
					/* Mark vehicles which are in sub-groups */
 
					int y = r.top;
 
					uint max = min(this->vscroll->GetPosition() + this->vscroll->GetCapacity(), this->vehicles.Length());
 
					for (uint i = this->vscroll->GetPosition(); i < max; ++i) {
 
						const Vehicle *v = this->vehicles[i];
 
						if (v->group_id != this->vli.index) {
 
							GfxFillRect(r.left + 1, y + 1, r.right - 1, y + this->resize.step_height - 2, _colour_gradient[COLOUR_GREY][3], FILLRECT_CHECKER);
 
						}
 
						y += this->resize.step_height;
 
					}
 
				}
 

	
 
				this->DrawVehicleListItems(this->vehicle_sel, this->resize.step_height, r);
 
				break;
 
		}
 
	}
 

	
 
	virtual void OnClick(Point pt, int widget, int click_count)
 
@@ -557,13 +594,15 @@ public:
 
				break;
 

	
 
			case WID_GL_LIST_GROUP: { // Matrix Group
 
				uint id_g = this->group_sb->GetScrolledRowFromWidget(pt.y, this, WID_GL_LIST_GROUP, 0, this->tiny_step_height);
 
				if (id_g >= this->groups.Length()) return;
 

	
 
				this->vli.index = this->groups[id_g]->index;
 
				this->group_sel = this->vli.index = this->groups[id_g]->index;
 

	
 
				SetObjectToPlaceWnd(SPR_CURSOR_MOUSE, PAL_NONE, HT_DRAG, this);
 

	
 
				this->vehicles.ForceRebuild();
 
				this->SetDirty();
 
				break;
 
			}
 

	
 
@@ -617,20 +656,52 @@ public:
 
				break;
 
			}
 

	
 
			case WID_GL_REPLACE_PROTECTION: {
 
				const Group *g = Group::GetIfValid(this->vli.index);
 
				if (g != NULL) {
 
					DoCommandP(0, this->vli.index, !g->replace_protection, CMD_SET_GROUP_REPLACE_PROTECTION);
 
					DoCommandP(0, this->vli.index, !g->replace_protection | (_ctrl_pressed << 1), CMD_SET_GROUP_REPLACE_PROTECTION);
 
				}
 
				break;
 
			}
 
		}
 
	}
 

	
 
	virtual void OnDragDrop(Point pt, int widget)
 
	void OnDragDrop_Group(Point pt, int widget)
 
	{
 
		const Group *g = Group::Get(this->group_sel);
 

	
 
		switch (widget) {
 
			case WID_GL_ALL_VEHICLES: // All vehicles
 
			case WID_GL_DEFAULT_VEHICLES: // Ungroupd vehicles
 
				if (g->parent != INVALID_GROUP) {
 
					DoCommandP(0, this->group_sel | (1 << 16), INVALID_GROUP, CMD_ALTER_GROUP | CMD_MSG(STR_ERROR_GROUP_CAN_T_SET_PARENT));
 
				}
 

	
 
				this->group_sel = INVALID_GROUP;
 
				this->group_over = INVALID_GROUP;
 
				this->SetDirty();
 
				break;
 

	
 
			case WID_GL_LIST_GROUP: { // Matrix group
 
				uint id_g = this->group_sb->GetScrolledRowFromWidget(pt.y, this, WID_GL_LIST_GROUP, 0, this->tiny_step_height);
 
				GroupID new_g = id_g >= this->groups.Length() ? INVALID_GROUP : this->groups[id_g]->index;
 

	
 
				if (this->group_sel != new_g && g->parent != new_g) {
 
					DoCommandP(0, this->group_sel | (1 << 16), new_g, CMD_ALTER_GROUP | CMD_MSG(STR_ERROR_GROUP_CAN_T_SET_PARENT));
 
				}
 

	
 
				this->group_sel = INVALID_GROUP;
 
				this->group_over = INVALID_GROUP;
 
				this->SetDirty();
 
				break;
 
			}
 
		}
 
	}
 

	
 
	void OnDragDrop_Vehicle(Point pt, int widget)
 
	{
 
		switch (widget) {
 
			case WID_GL_DEFAULT_VEHICLES: // Ungrouped vehicles
 
				DoCommandP(0, DEFAULT_GROUP, this->vehicle_sel | (_ctrl_pressed ? 1 << 31 : 0), CMD_ADD_VEHICLE_GROUP | CMD_MSG(STR_ERROR_GROUP_CAN_T_ADD_VEHICLE));
 

	
 
				this->vehicle_sel = INVALID_VEHICLE;
 
@@ -665,18 +736,25 @@ public:
 
				if (!VehicleClicked(v) && vindex == v->index) {
 
					ShowVehicleViewWindow(v);
 
				}
 
				break;
 
			}
 
		}
 
	}
 

	
 
	virtual void OnDragDrop(Point pt, int widget)
 
	{
 
		if (this->vehicle_sel != INVALID_VEHICLE) OnDragDrop_Vehicle(pt, widget);
 
		if (this->group_sel != INVALID_GROUP) OnDragDrop_Group(pt, widget);
 

	
 
		_cursor.vehchain = false;
 
	}
 

	
 
	virtual void OnQueryTextFinished(char *str)
 
	{
 
		if (str != NULL) DoCommandP(0, this->group_rename, 0, CMD_RENAME_GROUP | CMD_MSG(STR_ERROR_GROUP_CAN_T_RENAME), NULL, str);
 
		if (str != NULL) DoCommandP(0, this->group_rename, 0, CMD_ALTER_GROUP | CMD_MSG(STR_ERROR_GROUP_CAN_T_RENAME), NULL, str);
 
		this->group_rename = INVALID_GROUP;
 
	}
 

	
 
	virtual void OnResize()
 
	{
 
		this->group_sb->SetCapacityFromWidget(this, WID_GL_LIST_GROUP);
 
@@ -739,13 +817,13 @@ public:
 
		this->group_over = INVALID_GROUP;
 
		this->SetWidgetDirty(WID_GL_LIST_VEHICLE);
 
	}
 

	
 
	virtual void OnMouseDrag(Point pt, int widget)
 
	{
 
		if (this->vehicle_sel == INVALID_VEHICLE) return;
 
		if (this->vehicle_sel == INVALID_VEHICLE && this->group_sel == INVALID_GROUP) return;
 

	
 
		/* A vehicle is dragged over... */
 
		GroupID new_group_over = INVALID_GROUP;
 
		switch (widget) {
 
			case WID_GL_DEFAULT_VEHICLES: // ... the 'default' group.
 
				new_group_over = DEFAULT_GROUP;
 
@@ -756,13 +834,17 @@ public:
 
				new_group_over = id_g >= this->groups.Length() ? NEW_GROUP : this->groups[id_g]->index;
 
				break;
 
			}
 
		}
 

	
 
		/* Do not highlight when dragging over the current group */
 
		if (Vehicle::Get(vehicle_sel)->group_id == new_group_over) new_group_over = INVALID_GROUP;
 
		if (this->vehicle_sel != INVALID_VEHICLE) {
 
			if (Vehicle::Get(vehicle_sel)->group_id == new_group_over) new_group_over = INVALID_GROUP;
 
		} else if (this->group_sel != INVALID_GROUP) {
 
			if (this->group_sel == new_group_over || Group::Get(this->group_sel)->parent == new_group_over) new_group_over = INVALID_GROUP;
 
		}
 

	
 
		/* Mark widgets as dirty if the group changed. */
 
		if (new_group_over != this->group_over) {
 
			this->DirtyHighlightedGroupWidget();
 
			this->group_over = new_group_over;
 
			this->DirtyHighlightedGroupWidget();
src/lang/english.txt
Show inline comments
 
@@ -3294,13 +3294,13 @@ STR_GROUP_ALL_AIRCRAFTS                 
 

	
 
STR_GROUP_DEFAULT_TRAINS                                        :Ungrouped trains
 
STR_GROUP_DEFAULT_ROAD_VEHICLES                                 :Ungrouped road vehicles
 
STR_GROUP_DEFAULT_SHIPS                                         :Ungrouped ships
 
STR_GROUP_DEFAULT_AIRCRAFTS                                     :Ungrouped aircraft
 

	
 
STR_GROUPS_CLICK_ON_GROUP_FOR_TOOLTIP                           :{BLACK}Groups - click on a group to list all vehicles of this group
 
STR_GROUPS_CLICK_ON_GROUP_FOR_TOOLTIP                           :{BLACK}Groups - click on a group to list all vehicles of this group. Drag and drop groups to arrange hierarchy.
 
STR_GROUP_CREATE_TOOLTIP                                        :{BLACK}Click to create a group
 
STR_GROUP_DELETE_TOOLTIP                                        :{BLACK}Delete the selected group
 
STR_GROUP_RENAME_TOOLTIP                                        :{BLACK}Rename the selected group
 
STR_GROUP_REPLACE_PROTECTION_TOOLTIP                            :{BLACK}Click to protect this group from global autoreplace
 

	
 
STR_GROUP_ADD_SHARED_VEHICLE                                    :Add shared vehicles
 
@@ -4273,12 +4273,13 @@ STR_ERROR_CAN_T_PURCHASE_THIS_LAND      
 
STR_ERROR_YOU_ALREADY_OWN_IT                                    :{WHITE}... you already own it!
 

	
 
# Group related errors
 
STR_ERROR_GROUP_CAN_T_CREATE                                    :{WHITE}Can't create group...
 
STR_ERROR_GROUP_CAN_T_DELETE                                    :{WHITE}Can't delete this group...
 
STR_ERROR_GROUP_CAN_T_RENAME                                    :{WHITE}Can't rename group...
 
STR_ERROR_GROUP_CAN_T_SET_PARENT                                :{WHITE}Can't set parent group...
 
STR_ERROR_GROUP_CAN_T_REMOVE_ALL_VEHICLES                       :{WHITE}Can't remove all vehicles from this group...
 
STR_ERROR_GROUP_CAN_T_ADD_VEHICLE                               :{WHITE}Can't add the vehicle to this group...
 
STR_ERROR_GROUP_CAN_T_ADD_SHARED_VEHICLE                        :{WHITE}Can't add shared vehicles to group...
 

	
 
# Generic vehicle errors
 
STR_ERROR_TRAIN_IN_THE_WAY                                      :{WHITE}Train in the way
src/saveload/group_sl.cpp
Show inline comments
 
@@ -18,12 +18,13 @@ static const SaveLoad _group_desc[] = {
 
	 SLE_CONDVAR(Group, name,               SLE_NAME,                       0,  83),
 
	 SLE_CONDSTR(Group, name,               SLE_STR | SLF_ALLOW_CONTROL, 0, 84, SL_MAX_VERSION),
 
	SLE_CONDNULL(2,                                                         0,  163), // num_vehicle
 
	     SLE_VAR(Group, owner,              SLE_UINT8),
 
	     SLE_VAR(Group, vehicle_type,       SLE_UINT8),
 
	     SLE_VAR(Group, replace_protection, SLE_BOOL),
 
	 SLE_CONDVAR(Group, parent,             SLE_UINT16,                    189, SL_MAX_VERSION),
 
	     SLE_END()
 
};
 

	
 
static void Save_GRPS()
 
{
 
	Group *g;
 
@@ -39,12 +40,14 @@ static void Load_GRPS()
 
{
 
	int index;
 

	
 
	while ((index = SlIterateArray()) != -1) {
 
		Group *g = new (index) Group();
 
		SlObject(g, _group_desc);
 

	
 
		if (IsSavegameVersionBefore(189)) g->parent = INVALID_GROUP;
 
	}
 
}
 

	
 
extern const ChunkHandler _group_chunk_handlers[] = {
 
	{ 'GRPS', Save_GRPS, Load_GRPS, NULL, NULL, CH_ARRAY | CH_LAST},
 
};
src/saveload/saveload.cpp
Show inline comments
 
@@ -251,14 +251,15 @@
 
 *  183   25363
 
 *  184   25508
 
 *  185   25620
 
 *  186   25833
 
 *  187   25899
 
 *  188   26169   1.4.x
 
 *  189   26450
 
 */
 
extern const uint16 SAVEGAME_VERSION = 188; ///< Current savegame version of OpenTTD.
 
extern const uint16 SAVEGAME_VERSION = 189; ///< Current savegame version of OpenTTD.
 

	
 
SavegameType _savegame_type; ///< type of savegame we are loading
 

	
 
uint32 _ttdp_version;     ///< version of TTDP savegame (if applicable)
 
uint16 _sl_version;       ///< the major savegame version identifier
 
byte   _sl_minor_version; ///< the minor savegame version, DO NOT USE!
src/script/api/script_group.cpp
Show inline comments
 
@@ -54,13 +54,13 @@
 
	EnforcePrecondition(false, IsValidGroup(group_id));
 
	EnforcePrecondition(false, name != NULL);
 
	const char *text = name->GetDecodedText();
 
	EnforcePreconditionEncodedText(false, text);
 
	EnforcePreconditionCustomError(false, ::Utf8StringLength(text) < MAX_LENGTH_GROUP_NAME_CHARS, ScriptError::ERR_PRECONDITION_STRING_TOO_LONG);
 

	
 
	return ScriptObject::DoCommand(0, group_id, 0, CMD_RENAME_GROUP, text);
 
	return ScriptObject::DoCommand(0, group_id, 0, CMD_ALTER_GROUP, text);
 
}
 

	
 
/* static */ char *ScriptGroup::GetName(GroupID group_id)
 
{
 
	if (!IsValidGroup(group_id)) return NULL;
 

	
src/vehiclelist.cpp
Show inline comments
 
@@ -9,12 +9,13 @@
 

	
 
/** @file vehiclelist.cpp Lists of vehicles. */
 

	
 
#include "stdafx.h"
 
#include "train.h"
 
#include "vehiclelist.h"
 
#include "group.h"
 

	
 
/**
 
 * Pack a VehicleListIdentifier in a single uint32.
 
 * @return The packed identifier.
 
 */
 
uint32 VehicleListIdentifier::Pack()
 
@@ -142,13 +143,13 @@ bool GenerateVehicleSortList(VehicleList
 
			break;
 

	
 
		case VL_GROUP_LIST:
 
			if (vli.index != ALL_GROUP) {
 
				FOR_ALL_VEHICLES(v) {
 
					if (v->type == vli.vtype && v->IsPrimaryVehicle() &&
 
							v->owner == vli.company && v->group_id == vli.index) {
 
							v->owner == vli.company && GroupIsInGroup(v->group_id, vli.index)) {
 
						*list->Append() = v;
 
					}
 
				}
 
				break;
 
			}
 
			/* FALL THROUGH */
0 comments (0 inline, 0 general)