|
|
|
|
@@ -1425,6 +1425,159 @@ public:
|
|
|
|
|
using CompanyButton = Button<CompanyID>;
|
|
|
|
|
using ClientButton = Button<ClientID>;
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Base interface for a network client list line.
|
|
|
|
|
*/
|
|
|
|
|
class ButtonLine {
|
|
|
|
|
public:
|
|
|
|
|
std::vector<std::unique_ptr<ButtonCommon>> buttons{}; ///< Buttons for this line.
|
|
|
|
|
|
|
|
|
|
virtual ~ButtonLine() = default;
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Draw the button line.
|
|
|
|
|
* @param r Rect to draw within.
|
|
|
|
|
*/
|
|
|
|
|
virtual void Draw(Rect r) const = 0;
|
|
|
|
|
|
|
|
|
|
template <typename T, typename...TArgs>
|
|
|
|
|
T &AddButton(TArgs &&... args)
|
|
|
|
|
{
|
|
|
|
|
auto &button = this->buttons.emplace_back(std::make_unique<T>(std::forward<TArgs &&>(args)...));
|
|
|
|
|
return static_cast<T &>(*button);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Get the button at a given point on the line.
|
|
|
|
|
* @param r Rect of line.
|
|
|
|
|
* @param pt Point of interest.
|
|
|
|
|
* @return Button at point, or \c nullptr if button isn't pressed.
|
|
|
|
|
*/
|
|
|
|
|
ButtonCommon *GetButton(Rect r, const Point &pt) const
|
|
|
|
|
{
|
|
|
|
|
bool rtl = _current_text_dir == TD_RTL;
|
|
|
|
|
for (auto &button : this->buttons) {
|
|
|
|
|
if (r.WithWidth(button->width, !rtl).Contains(pt)) return button.get();
|
|
|
|
|
r = r.Indent(button->width + WidgetDimensions::scaled.hsep_normal, !rtl);
|
|
|
|
|
}
|
|
|
|
|
return nullptr;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Get tooptip for a given point on the line.
|
|
|
|
|
* @param r Rect of line.
|
|
|
|
|
* @param pt Point of interest.
|
|
|
|
|
* @return EncodedString of tooltip, or \c std::nullopt if none.
|
|
|
|
|
*/
|
|
|
|
|
virtual std::optional<EncodedString> GetTooltip(Rect r, const Point &pt) const
|
|
|
|
|
{
|
|
|
|
|
ButtonCommon *button = this->GetButton(r, pt);
|
|
|
|
|
if (button == nullptr) return {};
|
|
|
|
|
return GetEncodedString(button->tooltip);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
protected:
|
|
|
|
|
/**
|
|
|
|
|
* Draw the buttons for this line.
|
|
|
|
|
* @param r Rect to draw within.
|
|
|
|
|
* @return Rect of remaining space.
|
|
|
|
|
*/
|
|
|
|
|
Rect DrawButtons(Rect r) const
|
|
|
|
|
{
|
|
|
|
|
bool rtl = _current_text_dir == TD_RTL;
|
|
|
|
|
for (auto &button : buttons) {
|
|
|
|
|
Rect br = r.CentreTo(r.Width(), button->height).WithWidth(button->width, !rtl);
|
|
|
|
|
DrawFrameRect(br, button->colour, {});
|
|
|
|
|
DrawSpriteIgnorePadding(button->sprite, PAL_NONE, br, SA_CENTER);
|
|
|
|
|
if (button->disabled) {
|
|
|
|
|
GfxFillRect(br.Shrink(WidgetDimensions::scaled.bevel), GetColourGradient(button->colour, SHADE_DARKER), FILLRECT_CHECKER);
|
|
|
|
|
}
|
|
|
|
|
r = r.Indent(button->width + WidgetDimensions::scaled.hsep_normal, !rtl);
|
|
|
|
|
}
|
|
|
|
|
return r;
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
class CompanyButtonLine : public ButtonLine {
|
|
|
|
|
public:
|
|
|
|
|
CompanyButtonLine(CompanyID company_id) : company_id(company_id) {}
|
|
|
|
|
|
|
|
|
|
void Draw(Rect r) const override
|
|
|
|
|
{
|
|
|
|
|
bool rtl = _current_text_dir == TD_RTL;
|
|
|
|
|
r = this->DrawButtons(r);
|
|
|
|
|
|
|
|
|
|
Dimension d = GetSpriteSize(CM_SPR_COMPANY_ICON);
|
|
|
|
|
PaletteID pal = Company::IsValidID(this->company_id) ? GetCompanyPalette(this->company_id) : PALETTE_TO_GREY;
|
|
|
|
|
DrawSpriteIgnorePadding(CM_SPR_COMPANY_ICON, pal, r.WithWidth(d.width, rtl), SA_CENTER);
|
|
|
|
|
|
|
|
|
|
Rect tr = r.CentreTo(r.Width(), GetCharacterHeight(FS_NORMAL)).Indent(d.width + WidgetDimensions::scaled.hsep_normal, rtl);
|
|
|
|
|
if (this->company_id == COMPANY_SPECTATOR) {
|
|
|
|
|
DrawString(tr, STR_NETWORK_CLIENT_LIST_SPECTATORS, TC_SILVER);
|
|
|
|
|
} else if (this->company_id == COMPANY_NEW_COMPANY) {
|
|
|
|
|
DrawString(tr, STR_NETWORK_CLIENT_LIST_NEW_COMPANY, TC_WHITE);
|
|
|
|
|
} else {
|
|
|
|
|
DrawString(tr, GetString(STR_COMPANY_NAME, this->company_id, this->company_id), TC_SILVER);
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
CompanyID company_id;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
class ClientButtonLine : public ButtonLine {
|
|
|
|
|
public:
|
|
|
|
|
ClientButtonLine(ClientPoolID client_pool_id) : client_pool_id(client_pool_id) {}
|
|
|
|
|
|
|
|
|
|
void Draw(Rect r) const override
|
|
|
|
|
{
|
|
|
|
|
const NetworkClientInfo *ci = NetworkClientInfo::GetIfValid(this->client_pool_id);
|
|
|
|
|
if (ci == nullptr) return;
|
|
|
|
|
|
|
|
|
|
bool rtl = _current_text_dir == TD_RTL;
|
|
|
|
|
r = this->DrawButtons(r);
|
|
|
|
|
|
|
|
|
|
Rect tr = r.CentreTo(r.Width(), GetCharacterHeight(FS_NORMAL));
|
|
|
|
|
|
|
|
|
|
SpriteID player_icon = 0;
|
|
|
|
|
if (ci->client_id == _network_own_client_id) {
|
|
|
|
|
player_icon = CM_SPR_PLAYER; /* SPR_PLAYER_SELF */
|
|
|
|
|
} else if (ci->client_id == CLIENT_ID_SERVER) {
|
|
|
|
|
player_icon = CM_SPR_HOST; /* SPR_PLAYER_HOST */
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (player_icon != 0) {
|
|
|
|
|
Dimension d = GetSpriteSize(player_icon);
|
|
|
|
|
DrawSpriteIgnorePadding(player_icon, PALETTE_TO_GREY, r.WithWidth(d.width, rtl), SA_CENTER);
|
|
|
|
|
tr = tr.Indent(d.width + WidgetDimensions::scaled.hsep_normal, rtl);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
DrawString(tr, GetString(STR_JUST_RAW_STRING, ci->client_name), TC_BLACK);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
std::optional<EncodedString> GetTooltip(Rect r, const Point &pt) const override
|
|
|
|
|
{
|
|
|
|
|
bool rtl = _current_text_dir == TD_RTL;
|
|
|
|
|
Dimension d = GetSpriteSize(SPR_PLAYER_SELF);
|
|
|
|
|
|
|
|
|
|
if (r.WithWidth(d.width, rtl).Contains(pt)) {
|
|
|
|
|
const NetworkClientInfo *ci = NetworkClientInfo::GetIfValid(this->client_pool_id);
|
|
|
|
|
if (ci != nullptr) {
|
|
|
|
|
if (ci->client_id == _network_own_client_id) {
|
|
|
|
|
return GetEncodedString(STR_NETWORK_CLIENT_LIST_PLAYER_ICON_SELF_TOOLTIP);
|
|
|
|
|
} else if (ci->client_id == CLIENT_ID_SERVER) {
|
|
|
|
|
return GetEncodedString(STR_NETWORK_CLIENT_LIST_PLAYER_ICON_HOST_TOOLTIP);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return this->ButtonLine::GetTooltip(r, pt);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
ClientPoolID client_pool_id;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Main handle for clientlist
|
|
|
|
|
*/
|
|
|
|
|
@@ -1437,12 +1590,9 @@ private:
|
|
|
|
|
|
|
|
|
|
Scrollbar *vscroll = nullptr; ///< Vertical scrollbar of this window.
|
|
|
|
|
uint line_height = 0; ///< Current lineheight of each entry in the matrix.
|
|
|
|
|
uint line_count = 0; ///< Amount of lines in the matrix.
|
|
|
|
|
int hover_index = -1; ///< Index of the current line we are hovering over, or -1 if none.
|
|
|
|
|
int player_self_index = -1; ///< The line the current player is on.
|
|
|
|
|
int player_host_index = -1; ///< The line the host is on.
|
|
|
|
|
|
|
|
|
|
std::map<uint, std::vector<std::unique_ptr<ButtonCommon>>> buttons{}; ///< Per line which buttons are available.
|
|
|
|
|
std::vector<std::unique_ptr<ButtonLine>> buttons{}; ///< Per line which buttons are available.
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Chat button on a Company is clicked.
|
|
|
|
|
@@ -1561,44 +1711,34 @@ private:
|
|
|
|
|
*/
|
|
|
|
|
void RebuildListCompany(CompanyID company_id, CompanyID client_playas, bool can_join_company)
|
|
|
|
|
{
|
|
|
|
|
ButtonCommon *chat_button = new CompanyButton(SPR_CHAT, company_id == COMPANY_SPECTATOR ? STR_NETWORK_CLIENT_LIST_CHAT_SPECTATOR_TOOLTIP : STR_NETWORK_CLIENT_LIST_CHAT_COMPANY_TOOLTIP, COLOUR_ORANGE, company_id, &NetworkClientListWindow::OnClickCompanyChat);
|
|
|
|
|
ButtonLine &company_line = *this->buttons.emplace_back(std::make_unique<CompanyButtonLine>(company_id));
|
|
|
|
|
if (_network_server) company_line.AddButton<CompanyButton>(SPR_ADMIN, STR_NETWORK_CLIENT_LIST_ADMIN_COMPANY_TOOLTIP, COLOUR_RED, company_id, &NetworkClientListWindow::OnClickCompanyAdmin, company_id == COMPANY_SPECTATOR);
|
|
|
|
|
|
|
|
|
|
if (_network_server) this->buttons[line_count].push_back(std::make_unique<CompanyButton>(SPR_ADMIN, STR_NETWORK_CLIENT_LIST_ADMIN_COMPANY_TOOLTIP, COLOUR_RED, company_id, &NetworkClientListWindow::OnClickCompanyAdmin, company_id == COMPANY_SPECTATOR));
|
|
|
|
|
/* CityMania code start */
|
|
|
|
|
auto company = Company::GetIfValid(company_id);
|
|
|
|
|
if (company != nullptr) {
|
|
|
|
|
ButtonCommon *hq_button = new CompanyButton(CM_SPR_HQ, CM_STR_NETWORK_CLIENT_LIST_HQ_TOOLTIP, COLOUR_ORANGE, company_id, &NetworkClientListWindow::CMOnClickCompanyHQ);
|
|
|
|
|
if (company->location_of_HQ == INVALID_TILE) hq_button->disabled = true;
|
|
|
|
|
this->buttons[line_count].emplace_back(hq_button);
|
|
|
|
|
// TODO push_back(make_unique?
|
|
|
|
|
this->buttons[line_count].emplace_back(new CompanyButton(CM_SPR_WATCH, CM_STR_NETWORK_CLIENT_LIST_WATCH_TOOLTIP, COLOUR_ORANGE, company_id, &NetworkClientListWindow::CMOnClickCompanyWatch));
|
|
|
|
|
ButtonCommon &hq_button = company_line.AddButton<CompanyButton>(CM_SPR_HQ, CM_STR_NETWORK_CLIENT_LIST_HQ_TOOLTIP, COLOUR_ORANGE, company_id, &NetworkClientListWindow::CMOnClickCompanyHQ);
|
|
|
|
|
if (company->location_of_HQ == INVALID_TILE) hq_button.disabled = true;
|
|
|
|
|
company_line.AddButton<CompanyButton>(CM_SPR_WATCH, CM_STR_NETWORK_CLIENT_LIST_WATCH_TOOLTIP, COLOUR_ORANGE, company_id, &NetworkClientListWindow::CMOnClickCompanyWatch);
|
|
|
|
|
}
|
|
|
|
|
/* CityMania code end */
|
|
|
|
|
this->buttons[line_count].emplace_back(chat_button);
|
|
|
|
|
if (can_join_company) this->buttons[line_count].push_back(std::make_unique<CompanyButton>(SPR_JOIN, STR_NETWORK_CLIENT_LIST_JOIN_TOOLTIP, COLOUR_ORANGE, company_id, &NetworkClientListWindow::OnClickCompanyJoin, company_id != COMPANY_SPECTATOR && Company::Get(company_id)->is_ai));
|
|
|
|
|
|
|
|
|
|
this->line_count += 1;
|
|
|
|
|
ButtonCommon &chat_button = company_line.AddButton<CompanyButton>(SPR_CHAT, company_id == COMPANY_SPECTATOR ? STR_NETWORK_CLIENT_LIST_CHAT_SPECTATOR_TOOLTIP : STR_NETWORK_CLIENT_LIST_CHAT_COMPANY_TOOLTIP, COLOUR_ORANGE, company_id, &NetworkClientListWindow::OnClickCompanyChat);
|
|
|
|
|
if (can_join_company) company_line.AddButton<CompanyButton>(SPR_JOIN, STR_NETWORK_CLIENT_LIST_JOIN_TOOLTIP, COLOUR_ORANGE, company_id, &NetworkClientListWindow::OnClickCompanyJoin, company_id != COMPANY_SPECTATOR && Company::Get(company_id)->is_ai);
|
|
|
|
|
|
|
|
|
|
bool has_players = false;
|
|
|
|
|
for (const NetworkClientInfo *ci : NetworkClientInfo::Iterate()) {
|
|
|
|
|
if (ci->client_playas != company_id) continue;
|
|
|
|
|
has_players = true;
|
|
|
|
|
|
|
|
|
|
if (_network_server) this->buttons[line_count].push_back(std::make_unique<ClientButton>(SPR_ADMIN, STR_NETWORK_CLIENT_LIST_ADMIN_CLIENT_TOOLTIP, COLOUR_RED, ci->client_id, &NetworkClientListWindow::OnClickClientAdmin, _network_own_client_id == ci->client_id));
|
|
|
|
|
if (_network_own_client_id != ci->client_id) this->buttons[line_count].push_back(std::make_unique<ClientButton>(SPR_CHAT, STR_NETWORK_CLIENT_LIST_CHAT_CLIENT_TOOLTIP, COLOUR_ORANGE, ci->client_id, &NetworkClientListWindow::OnClickClientChat));
|
|
|
|
|
if (_network_own_client_id != ci->client_id && client_playas != COMPANY_SPECTATOR && !ci->CanJoinCompany(client_playas)) this->buttons[line_count].push_back(std::make_unique<ClientButton>(SPR_JOIN, STR_NETWORK_CLIENT_LIST_COMPANY_AUTHORIZE_TOOLTIP, COLOUR_GREEN, ci->client_id, &NetworkClientListWindow::OnClickClientAuthorize));
|
|
|
|
|
|
|
|
|
|
if (ci->client_id == _network_own_client_id) {
|
|
|
|
|
this->player_self_index = this->line_count;
|
|
|
|
|
} else if (ci->client_id == CLIENT_ID_SERVER) {
|
|
|
|
|
this->player_host_index = this->line_count;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
this->line_count += 1;
|
|
|
|
|
ButtonLine &line = *this->buttons.emplace_back(std::make_unique<ClientButtonLine>(ci->index));
|
|
|
|
|
if (_network_server) line.AddButton<ClientButton>(SPR_ADMIN, STR_NETWORK_CLIENT_LIST_ADMIN_CLIENT_TOOLTIP, COLOUR_RED, ci->client_id, &NetworkClientListWindow::OnClickClientAdmin, _network_own_client_id == ci->client_id);
|
|
|
|
|
if (_network_own_client_id != ci->client_id) line.AddButton<ClientButton>(SPR_CHAT, STR_NETWORK_CLIENT_LIST_CHAT_CLIENT_TOOLTIP, COLOUR_ORANGE, ci->client_id, &NetworkClientListWindow::OnClickClientChat);
|
|
|
|
|
if (_network_own_client_id != ci->client_id && client_playas != COMPANY_SPECTATOR && !ci->CanJoinCompany(client_playas)) line.AddButton<ClientButton>(SPR_JOIN, STR_NETWORK_CLIENT_LIST_COMPANY_AUTHORIZE_TOOLTIP, COLOUR_GREEN, ci->client_id, &NetworkClientListWindow::OnClickClientAuthorize);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Disable the chat button when there are players in this company. */
|
|
|
|
|
chat_button->disabled = !has_players;
|
|
|
|
|
chat_button.disabled = !has_players;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
@@ -1610,14 +1750,11 @@ private:
|
|
|
|
|
CompanyID client_playas = own_ci == nullptr ? COMPANY_SPECTATOR : own_ci->client_playas;
|
|
|
|
|
|
|
|
|
|
this->buttons.clear();
|
|
|
|
|
this->line_count = 0;
|
|
|
|
|
this->player_host_index = -1;
|
|
|
|
|
this->player_self_index = -1;
|
|
|
|
|
|
|
|
|
|
/* As spectator, show a line to create a new company. */
|
|
|
|
|
if (client_playas == COMPANY_SPECTATOR && !NetworkMaxCompaniesReached()) {
|
|
|
|
|
this->buttons[line_count].push_back(std::make_unique<CompanyButton>(SPR_JOIN, STR_NETWORK_CLIENT_LIST_NEW_COMPANY_TOOLTIP, COLOUR_ORANGE, COMPANY_SPECTATOR, &NetworkClientListWindow::OnClickCompanyNew));
|
|
|
|
|
this->line_count += 1;
|
|
|
|
|
ButtonLine &line = *this->buttons.emplace_back(std::make_unique<CompanyButtonLine>(COMPANY_NEW_COMPANY));
|
|
|
|
|
line.AddButton<CompanyButton>(SPR_JOIN, STR_NETWORK_CLIENT_LIST_NEW_COMPANY_TOOLTIP, COLOUR_ORANGE, COMPANY_SPECTATOR, &NetworkClientListWindow::OnClickCompanyNew);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (client_playas != COMPANY_SPECTATOR) {
|
|
|
|
|
@@ -1634,40 +1771,7 @@ private:
|
|
|
|
|
/* Spectators */
|
|
|
|
|
this->RebuildListCompany(COMPANY_SPECTATOR, client_playas, client_playas != COMPANY_SPECTATOR);
|
|
|
|
|
|
|
|
|
|
this->vscroll->SetCount(this->line_count);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Get the button at a specific point on the WID_CL_MATRIX.
|
|
|
|
|
* @param pt The point to look for a button.
|
|
|
|
|
* @return The button or a nullptr if there was none.
|
|
|
|
|
*/
|
|
|
|
|
ButtonCommon *GetButtonAtPoint(Point pt)
|
|
|
|
|
{
|
|
|
|
|
uint index = this->vscroll->GetScrolledRowFromWidget(pt.y, this, WID_CL_MATRIX);
|
|
|
|
|
Rect matrix = this->GetWidget<NWidgetBase>(WID_CL_MATRIX)->GetCurrentRect().Shrink(WidgetDimensions::scaled.framerect);
|
|
|
|
|
|
|
|
|
|
bool rtl = _current_text_dir == TD_RTL;
|
|
|
|
|
uint x = rtl ? matrix.left : matrix.right;
|
|
|
|
|
|
|
|
|
|
/* Find the buttons for this row. */
|
|
|
|
|
auto button_find = this->buttons.find(index);
|
|
|
|
|
if (button_find == this->buttons.end()) return nullptr;
|
|
|
|
|
|
|
|
|
|
/* Check if we want to display a tooltip for any of the buttons. */
|
|
|
|
|
for (auto &button : button_find->second) {
|
|
|
|
|
uint left = rtl ? x : x - button->width;
|
|
|
|
|
uint right = rtl ? x + button->width : x;
|
|
|
|
|
|
|
|
|
|
if (IsInsideMM(pt.x, left, right)) {
|
|
|
|
|
return button.get();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int width = button->width + WidgetDimensions::scaled.framerect.Horizontal();
|
|
|
|
|
x += rtl ? width : -width;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return nullptr;
|
|
|
|
|
this->vscroll->SetCount(this->buttons.size());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
public:
|
|
|
|
|
@@ -1682,7 +1786,7 @@ public:
|
|
|
|
|
|
|
|
|
|
void OnInit() override
|
|
|
|
|
{
|
|
|
|
|
RebuildList();
|
|
|
|
|
this->RebuildList();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void OnInvalidateData([[maybe_unused]] int data = 0, [[maybe_unused]] bool gui_scope = true) override
|
|
|
|
|
@@ -1786,7 +1890,12 @@ public:
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case WID_CL_MATRIX: {
|
|
|
|
|
ButtonCommon *button = this->GetButtonAtPoint(pt);
|
|
|
|
|
auto it = this->vscroll->GetScrolledItemFromWidget(this->buttons, pt.y, this, WID_CL_MATRIX);
|
|
|
|
|
if (it == std::end(this->buttons)) break;
|
|
|
|
|
|
|
|
|
|
Rect r = this->GetWidget<NWidgetBase>(WID_CL_MATRIX)->GetCurrentRect().Shrink(WidgetDimensions::scaled.framerect);
|
|
|
|
|
ButtonCommon *button = (*it)->GetButton(r, pt);
|
|
|
|
|
|
|
|
|
|
/* CityMania code start */
|
|
|
|
|
// NOTE: needs to match company order in DrawWidget
|
|
|
|
|
if (button == nullptr) {
|
|
|
|
|
@@ -1835,34 +1944,14 @@ public:
|
|
|
|
|
{
|
|
|
|
|
switch (widget) {
|
|
|
|
|
case WID_CL_MATRIX: {
|
|
|
|
|
int index = this->vscroll->GetScrolledRowFromWidget(pt.y, this, WID_CL_MATRIX);
|
|
|
|
|
auto it = this->vscroll->GetScrolledItemFromWidget(this->buttons, pt.y, this, WID_CL_MATRIX);
|
|
|
|
|
if (it == std::end(this->buttons)) break;
|
|
|
|
|
|
|
|
|
|
bool rtl = _current_text_dir == TD_RTL;
|
|
|
|
|
Rect matrix = this->GetWidget<NWidgetBase>(WID_CL_MATRIX)->GetCurrentRect().Shrink(WidgetDimensions::scaled.framerect);
|
|
|
|
|
Rect r = this->GetWidget<NWidgetBase>(WID_CL_MATRIX)->GetCurrentRect().Shrink(WidgetDimensions::scaled.framerect);
|
|
|
|
|
auto tooltip = (*it)->GetTooltip(r, pt);
|
|
|
|
|
if (!tooltip.has_value()) break;
|
|
|
|
|
|
|
|
|
|
Dimension d = GetSpriteSize(SPR_COMPANY_ICON);
|
|
|
|
|
uint text_left = matrix.left + (rtl ? 0 : d.width + WidgetDimensions::scaled.hsep_wide);
|
|
|
|
|
uint text_right = matrix.right - (rtl ? d.width + WidgetDimensions::scaled.hsep_wide : 0);
|
|
|
|
|
|
|
|
|
|
Dimension d2 = GetSpriteSize(SPR_PLAYER_SELF);
|
|
|
|
|
uint offset_x = WidgetDimensions::scaled.hsep_indent - d2.width - ScaleGUITrad(3);
|
|
|
|
|
|
|
|
|
|
uint player_icon_x = rtl ? text_right - offset_x - d2.width : text_left + offset_x;
|
|
|
|
|
|
|
|
|
|
if (IsInsideMM(pt.x, player_icon_x, player_icon_x + d2.width)) {
|
|
|
|
|
if (index == this->player_self_index) {
|
|
|
|
|
GuiShowTooltips(this, GetEncodedString(STR_NETWORK_CLIENT_LIST_PLAYER_ICON_SELF_TOOLTIP), close_cond);
|
|
|
|
|
return true;
|
|
|
|
|
} else if (index == this->player_host_index) {
|
|
|
|
|
GuiShowTooltips(this, GetEncodedString(STR_NETWORK_CLIENT_LIST_PLAYER_ICON_HOST_TOOLTIP), close_cond);
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
ButtonCommon *button = this->GetButtonAtPoint(pt);
|
|
|
|
|
if (button == nullptr) return false;
|
|
|
|
|
|
|
|
|
|
GuiShowTooltips(this, GetEncodedString(button->tooltip), close_cond);
|
|
|
|
|
GuiShowTooltips(this, std::move(*tooltip), close_cond);
|
|
|
|
|
return true;
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
@@ -1956,153 +2045,23 @@ public:
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Draw the buttons for a single line in the matrix.
|
|
|
|
|
*
|
|
|
|
|
* The x-position in RTL is the most left or otherwise the most right pixel
|
|
|
|
|
* we can draw the buttons from.
|
|
|
|
|
*
|
|
|
|
|
* @param x The x-position to start with the buttons. Updated during this function.
|
|
|
|
|
* @param y The y-position to start with the buttons.
|
|
|
|
|
* @param buttons The buttons to draw.
|
|
|
|
|
*/
|
|
|
|
|
void DrawButtons(int &x, uint y, const std::vector<std::unique_ptr<ButtonCommon>> &buttons) const
|
|
|
|
|
{
|
|
|
|
|
Rect r;
|
|
|
|
|
|
|
|
|
|
for (auto &button : buttons) {
|
|
|
|
|
bool rtl = _current_text_dir == TD_RTL;
|
|
|
|
|
|
|
|
|
|
int offset = (this->line_height - button->height) / 2;
|
|
|
|
|
r.left = rtl ? x : x - button->width + 1;
|
|
|
|
|
r.right = rtl ? x + button->width - 1 : x;
|
|
|
|
|
r.top = y + offset;
|
|
|
|
|
r.bottom = r.top + button->height - 1;
|
|
|
|
|
|
|
|
|
|
DrawFrameRect(r, button->colour, {});
|
|
|
|
|
DrawSprite(button->sprite, PAL_NONE, r.left + WidgetDimensions::scaled.framerect.left, r.top + WidgetDimensions::scaled.framerect.top);
|
|
|
|
|
if (button->disabled) {
|
|
|
|
|
GfxFillRect(r.Shrink(WidgetDimensions::scaled.bevel), GetColourGradient(button->colour, SHADE_DARKER), FILLRECT_CHECKER);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int width = button->width + WidgetDimensions::scaled.hsep_normal;
|
|
|
|
|
x += rtl ? width : -width;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* Draw a company and its clients on the matrix.
|
|
|
|
|
* @param company_id The company to draw.
|
|
|
|
|
* @param r The rect to draw within.
|
|
|
|
|
* @param line The Nth line we are drawing. Updated during this function.
|
|
|
|
|
*/
|
|
|
|
|
void DrawCompany(CompanyID company_id, const Rect &r, uint &line) const
|
|
|
|
|
{
|
|
|
|
|
bool rtl = _current_text_dir == TD_RTL;
|
|
|
|
|
int text_y_offset = CentreBounds(0, this->line_height, GetCharacterHeight(FS_NORMAL));
|
|
|
|
|
|
|
|
|
|
Dimension d = GetSpriteSize(CM_SPR_COMPANY_ICON);
|
|
|
|
|
int offset = CentreBounds(0, this->line_height, d.height);
|
|
|
|
|
|
|
|
|
|
uint line_start = this->vscroll->GetPosition();
|
|
|
|
|
uint line_end = line_start + this->vscroll->GetCapacity();
|
|
|
|
|
|
|
|
|
|
uint y = r.top + (this->line_height * (line - line_start));
|
|
|
|
|
|
|
|
|
|
/* Draw the company line (if in range of scrollbar). */
|
|
|
|
|
if (IsInsideMM(line, line_start, line_end)) {
|
|
|
|
|
int icon_left = r.WithWidth(d.width, rtl).left;
|
|
|
|
|
Rect tr = r.Indent(d.width + WidgetDimensions::scaled.hsep_normal, rtl);
|
|
|
|
|
int &x = rtl ? tr.left : tr.right;
|
|
|
|
|
|
|
|
|
|
/* If there are buttons for this company, draw them. */
|
|
|
|
|
auto button_find = this->buttons.find(line);
|
|
|
|
|
if (button_find != this->buttons.end()) {
|
|
|
|
|
this->DrawButtons(x, y, button_find->second);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (company_id == COMPANY_SPECTATOR) {
|
|
|
|
|
DrawSprite(CM_SPR_COMPANY_ICON, PALETTE_TO_GREY, icon_left, y + offset);
|
|
|
|
|
DrawString(tr.left, tr.right, y + text_y_offset, STR_NETWORK_CLIENT_LIST_SPECTATORS, TC_SILVER);
|
|
|
|
|
} else if (company_id == COMPANY_NEW_COMPANY) {
|
|
|
|
|
DrawSprite(CM_SPR_COMPANY_ICON, PALETTE_TO_GREY, icon_left, y + offset);
|
|
|
|
|
DrawString(tr.left, tr.right, y + text_y_offset, STR_NETWORK_CLIENT_LIST_NEW_COMPANY, TC_WHITE);
|
|
|
|
|
} else {
|
|
|
|
|
DrawSprite(CM_SPR_COMPANY_ICON, GetCompanyPalette(company_id), icon_left, y + offset);
|
|
|
|
|
DrawString(tr.left, tr.right, y + text_y_offset, GetString(STR_COMPANY_NAME, company_id, company_id), TC_SILVER);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
y += this->line_height;
|
|
|
|
|
line++;
|
|
|
|
|
|
|
|
|
|
for (const NetworkClientInfo *ci : NetworkClientInfo::Iterate()) {
|
|
|
|
|
if (ci->client_playas != company_id) continue;
|
|
|
|
|
|
|
|
|
|
/* Draw the player line (if in range of scrollbar). */
|
|
|
|
|
if (IsInsideMM(line, line_start, line_end)) {
|
|
|
|
|
Rect tr = r.Indent(WidgetDimensions::scaled.hsep_indent, rtl);
|
|
|
|
|
|
|
|
|
|
/* If there are buttons for this client, draw them. */
|
|
|
|
|
auto button_find = this->buttons.find(line);
|
|
|
|
|
if (button_find != this->buttons.end()) {
|
|
|
|
|
int &x = rtl ? tr.left : tr.right;
|
|
|
|
|
this->DrawButtons(x, y, button_find->second);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
SpriteID player_icon = 0;
|
|
|
|
|
if (ci->client_id == _network_own_client_id) {
|
|
|
|
|
player_icon = CM_SPR_PLAYER /* SPR_PLAYER_SELF */;
|
|
|
|
|
} else if (ci->client_id == CLIENT_ID_SERVER) {
|
|
|
|
|
player_icon = CM_SPR_HOST /* SPR_PLAYER_HOST */;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (player_icon != 0) {
|
|
|
|
|
Dimension d2 = GetSpriteSize(player_icon);
|
|
|
|
|
int offset_y = CentreBounds(0, this->line_height, d2.height);
|
|
|
|
|
DrawSprite(player_icon, PALETTE_TO_GREY, rtl ? tr.right - d2.width : tr.left, y + offset_y);
|
|
|
|
|
tr = tr.Indent(d2.width + WidgetDimensions::scaled.hsep_normal, rtl);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
DrawString(tr.left, tr.right, y + text_y_offset, GetString(STR_JUST_RAW_STRING, ci->client_name), TC_BLACK);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
y += this->line_height;
|
|
|
|
|
line++;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void DrawWidget(const Rect &r, WidgetID widget) const override
|
|
|
|
|
{
|
|
|
|
|
switch (widget) {
|
|
|
|
|
case WID_CL_MATRIX: {
|
|
|
|
|
Rect ir = r.Shrink(WidgetDimensions::scaled.framerect, RectPadding::zero);
|
|
|
|
|
uint line = 0;
|
|
|
|
|
Rect ir = r.WithHeight(this->line_height).Shrink(WidgetDimensions::scaled.framerect, RectPadding::zero);
|
|
|
|
|
|
|
|
|
|
if (this->hover_index >= 0) {
|
|
|
|
|
Rect br = r.WithHeight(this->line_height).Translate(0, this->hover_index * this->line_height);
|
|
|
|
|
GfxFillRect(br.Shrink(WidgetDimensions::scaled.bevel), GREY_SCALE(9));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
NetworkClientInfo *own_ci = NetworkClientInfo::GetByClientID(_network_own_client_id);
|
|
|
|
|
CompanyID client_playas = own_ci == nullptr ? COMPANY_SPECTATOR : own_ci->client_playas;
|
|
|
|
|
|
|
|
|
|
if (client_playas == COMPANY_SPECTATOR && !NetworkMaxCompaniesReached()) {
|
|
|
|
|
this->DrawCompany(COMPANY_NEW_COMPANY, ir, line);
|
|
|
|
|
auto [first, last] = this->vscroll->GetVisibleRangeIterators(this->buttons);
|
|
|
|
|
for (auto it = first; it != last; ++it) {
|
|
|
|
|
(*it)->Draw(ir);
|
|
|
|
|
ir = ir.Translate(0, this->line_height);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (client_playas != COMPANY_SPECTATOR) {
|
|
|
|
|
this->DrawCompany(client_playas, ir, line);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for (const Company *c : Company::Iterate()) {
|
|
|
|
|
if (client_playas == c->index) continue;
|
|
|
|
|
this->DrawCompany(c->index, ir, line);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Spectators */
|
|
|
|
|
this->DrawCompany(COMPANY_SPECTATOR, ir, line);
|
|
|
|
|
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|