Add client list overlay (toggleable)

This commit is contained in:
dP
2021-09-29 22:55:14 +03:00
parent c8ac56fda6
commit 2c5f48943c
13 changed files with 255 additions and 1 deletions

View File

@@ -24,6 +24,8 @@ add_files(
cm_blueprint.cpp cm_blueprint.cpp
cm_cargo_table_gui.hpp cm_cargo_table_gui.hpp
cm_cargo_table_gui.cpp cm_cargo_table_gui.cpp
cm_client_list_gui.hpp
cm_client_list_gui.cpp
cm_commands_gui.hpp cm_commands_gui.hpp
cm_commands_gui.cpp cm_commands_gui.cpp
cm_highlight.hpp cm_highlight.hpp

View File

@@ -0,0 +1,205 @@
#include "../stdafx.h"
#include "cm_client_list_gui.hpp"
#include "../blitter/factory.hpp"
#include "../company_base.h"
#include "../company_gui.h"
#include "../console_func.h"
#include "../debug.h"
#include "../core/geometry_type.hpp"
#include "../gfx_func.h"
#include "../network/network.h"
#include "../network/network_base.h"
#include "../network/network_func.h"
#include "../strings_func.h"
#include "../table/sprites.h"
#include "../video/video_driver.hpp"
#include "../window_func.h"
#include "../window_gui.h"
#include "../zoom_func.h"
#include "../safeguards.h"
namespace citymania {
bool Intersects(PointDimension rect, Point pos, Point size) {
return (
pos.x + size.x >= rect.x &&
pos.x <= rect.x + rect.width &&
pos.y + size.y >= rect.y &&
pos.y <= rect.y + rect.height
);
}
bool Intersects(PointDimension rect, int left, int top, int right, int bottom) {
return (
right >= rect.x &&
left <= rect.x + rect.width &&
bottom >= rect.y &&
top <= rect.y + rect.height
);
}
class ClientListOverlay {
protected:
PointDimension box;
bool drawn = false;
bool dirty = true;
PointDimension backup_box;
uint8 *backup = nullptr;
int backup_size = -1;
int padding;
int line_height;
int text_offset_y;
int icon_offset_y;
public:
void SetDirty() {
this->dirty = true;
}
void UpdateSize() {
this->padding = ScaleGUITrad(3);
auto icon_size = GetSpriteSize(SPR_COMPANY_ICON);
auto common_height = std::max<int>(icon_size.height, FONT_HEIGHT_NORMAL);
this->line_height = common_height + this->padding;
this->text_offset_y = (common_height - FONT_HEIGHT_NORMAL) / 2;
this->icon_offset_y = (common_height - icon_size.height) / 2;
this->box.height = this->padding;
this->box.width = 0;
for (const NetworkClientInfo *ci : NetworkClientInfo::Iterate()) {
SetDParamStr(0, ci->client_name);
this->box.width = std::max<int>(this->box.width, GetStringBoundingBox(STR_JUST_RAW_STRING).width);
this->box.height += this->line_height;
}
this->box.width += this->padding * 3 + icon_size.width;
this->box.x = this->padding;
this->box.y = this->padding;
Window *toolbar = FindWindowById(WC_MAIN_TOOLBAR, 0);
if (toolbar != nullptr && toolbar->left < this->box.x + this->box.width + this->padding) {
this->box.y = toolbar->top + toolbar->height + this->padding;
}
if (this->box.x + this->box.width > _screen.width)
this->box.width = _screen.width - this->box.x;
if (this->box.y + this->box.height > _screen.height)
this->box.height = _screen.height - this->box.y;
}
void Undraw(int left, int top, int right, int bottom) {
auto &box = this->backup_box;
if (!this->drawn) return;
if (!Intersects(box, left, top, right, bottom)) return;
if (box.x + box.width > _screen.width) return;
if (box.y + box.height > _screen.height) return;
Blitter *blitter = BlitterFactory::GetCurrentBlitter();
/* Put our 'shot' back to the screen */
blitter->CopyFromBuffer(blitter->MoveTo(_screen.dst_ptr, box.x, box.y), this->backup, box.width, box.height);
/* And make sure it is updated next time */
VideoDriver::GetInstance()->MakeDirty(box.x, box.y, box.width, box.height);
this->drawn = false;
this->dirty = true;
}
void Draw() {
if (!this->dirty) return;
this->dirty = false;
this->UpdateSize();
Blitter *blitter = BlitterFactory::GetCurrentBlitter();
bool make_backup = true;
if (this->drawn) {
/* Put our 'shot' back to the screen */
blitter->CopyFromBuffer(blitter->MoveTo(_screen.dst_ptr, this->backup_box.x, this->backup_box.y), this->backup, this->backup_box.width, this->backup_box.height);
/* And make sure it is updated next time */
VideoDriver::GetInstance()->MakeDirty(this->backup_box.x, this->backup_box.y, this->backup_box.width, this->backup_box.height);
this->drawn = false;
make_backup = (
this->box.x != this->backup_box.x ||
this->box.y != this->backup_box.y ||
this->box.width != this->backup_box.width ||
this->box.height != this->backup_box.height
);
}
if (_game_mode != GM_NORMAL) return;
if (_iconsole_mode != ICONSOLE_CLOSED) return;
if (!_networking) return;
if (!_settings_client.gui.cm_show_client_overlay) return;
if (this->box.width <= 0 || this->box.height <= 0) return;
if (make_backup) {
auto size = this->box.width * this->box.height * BlitterFactory::GetCurrentBlitter()->GetBytesPerPixel();
if (size > this->backup_size) {
this->backup = ReallocT(this->backup, size);
this->backup_size = size;
}
blitter->CopyToBuffer(blitter->MoveTo(_screen.dst_ptr, this->box.x, this->box.y), this->backup, this->box.width, this->box.height);
this->backup_box = this->box;
}
_cur_dpi = &_screen; // switch to _screen painting
/* Paint a half-transparent box behind the client list */
GfxFillRect(this->box.x, this->box.y, this->box.x + this->box.width - 1, this->box.y + this->box.height - 1,
PALETTE_TO_TRANSPARENT, FILLRECT_RECOLOUR // black, but with some alpha for background
);
int y = this->box.y + this->padding;
int x = this->box.x + this->padding;
auto text_left = x + GetSpriteSize(SPR_COMPANY_ICON).width + this->padding;
auto text_right = this->box.x + this->box.width - 1 - this->padding;
std::vector<std::tuple<CompanyID, std::string, TextColour>> clients;
for (const NetworkClientInfo *ci : NetworkClientInfo::Iterate()) {
auto colour = TC_SILVER;
if (ci->client_id == _network_own_client_id) colour = TC_WHITE;
if (ci->client_id == CLIENT_ID_SERVER) colour = TC_ORANGE;
clients.emplace_back(ci->client_playas, ci->client_name, colour);
}
std::sort(clients.begin(), clients.end());
for (const auto &[playas, name, colour] : clients) {
SetDParamStr(0, name);
// auto colour = TC_SILVER;
// if (ci->client_id == _network_own_client_id) colour = TC_WHITE;
// if (ci->client_id == CLIENT_ID_SERVER) colour = TC_ORANGE;
DrawString(text_left, text_right, y + this->text_offset_y, STR_JUST_RAW_STRING, colour);
if (Company::IsValidID(playas))
DrawCompanyIcon(playas, x, y + this->icon_offset_y);
y += this->line_height;
}
/* Make sure the data is updated next flush */
VideoDriver::GetInstance()->MakeDirty(this->box.x, this->box.y, this->box.width, this->box.height);
this->drawn = true;
}
};
ClientListOverlay _client_list_overlay;
void SetClientListDirty() {
_client_list_overlay.SetDirty();
}
void UndrawClientList(int left, int top, int right, int bottom) {
_client_list_overlay.Undraw(left, top, right, bottom);
}
void DrawClientList() {
_client_list_overlay.Draw();
}
} // namespace citymania

View File

@@ -0,0 +1,12 @@
#ifndef CM_CLIENT_LIST_GUI_HPP
#define CM_CLIENT_LIST_GUI_HPP
namespace citymania {
void SetClientListDirty();
void UndrawClientList(int left, int top, int right, int bottom);
void DrawClientList();
} // namespace citymania
#endif

View File

@@ -26,6 +26,8 @@
#include "table/sprites.h" #include "table/sprites.h"
#include "table/control_codes.h" #include "table/control_codes.h"
#include "citymania/cm_client_list_gui.hpp"
#include "safeguards.h" #include "safeguards.h"
byte _dirkeys; ///< 1 = left, 2 = up, 4 = right, 8 = down byte _dirkeys; ///< 1 = left, 2 = up, 4 = right, 8 = down
@@ -94,6 +96,7 @@ void GfxScroll(int left, int top, int width, int height, int xo, int yo)
if (_cursor.visible) UndrawMouseCursor(); if (_cursor.visible) UndrawMouseCursor();
if (_networking) NetworkUndrawChatMessage(); if (_networking) NetworkUndrawChatMessage();
if (_networking) citymania::UndrawClientList(left, top, left + width, top + height);
blitter->ScrollBuffer(_screen.dst_ptr, left, top, width, height, xo, yo); blitter->ScrollBuffer(_screen.dst_ptr, left, top, width, height, xo, yo);
/* This part of the screen is now dirty. */ /* This part of the screen is now dirty. */
@@ -1585,6 +1588,7 @@ void RedrawScreenRect(int left, int top, int right, int bottom)
} }
if (_networking) NetworkUndrawChatMessage(); if (_networking) NetworkUndrawChatMessage();
if (_networking) citymania::UndrawClientList(left, top, right, bottom);
DrawOverlappedWindowForAll(left, top, right, bottom); DrawOverlappedWindowForAll(left, top, right, bottom);

View File

@@ -5966,3 +5966,4 @@ STR_CONFIG_SETTING_PERSISTENT_DEPOTTOOLS_HELPTEXT :Keep the buildi
STR_CM_CONFIG_SETTING_IMPROVED_STATION_JOIN :Use improved station joining controls: {STRING2} STR_CM_CONFIG_SETTING_IMPROVED_STATION_JOIN :Use improved station joining controls: {STRING2}
STR_CM_CONFIG_SETTING_IMPROVED_STATION_JOIN_HELPTEXT :Use Ctrl-click on station tile to select or deselect station to join. If station has no tiles Ctrl-click its sign. Ctrl-click empty tile for a new station. Also recently built station is automatically selected as a station to join. {RED}Doesn't work if joining stations not directly adjacent(distant join) is not allowed in settings. STR_CM_CONFIG_SETTING_IMPROVED_STATION_JOIN_HELPTEXT :Use Ctrl-click on station tile to select or deselect station to join. If station has no tiles Ctrl-click its sign. Ctrl-click empty tile for a new station. Also recently built station is automatically selected as a station to join. {RED}Doesn't work if joining stations not directly adjacent(distant join) is not allowed in settings.
CM_STR_TOGGLE_CLIENTS_OVERLAY :Toggle client list overlay.

View File

@@ -39,7 +39,8 @@
#include <sstream> #include <sstream>
#include <iomanip> #include <iomanip>
#include "citymania/cm_console_cmds.hpp" #include "../citymania/cm_client_list_gui.hpp"
#include "../citymania/cm_console_cmds.hpp"
#include "../safeguards.h" #include "../safeguards.h"
@@ -562,6 +563,7 @@ NetworkAddress ParseConnectionString(const std::string &connection_string, uint1
ServerNetworkGameSocketHandler *cs = new ServerNetworkGameSocketHandler(s); ServerNetworkGameSocketHandler *cs = new ServerNetworkGameSocketHandler(s);
cs->client_address = address; // Save the IP of the client cs->client_address = address; // Save the IP of the client
citymania::SetClientListDirty();
InvalidateWindowData(WC_CLIENT_LIST, 0); InvalidateWindowData(WC_CLIENT_LIST, 0);
} }

View File

@@ -35,6 +35,7 @@
#include "../town.h" #include "../town.h"
#include "network_func.h" #include "network_func.h"
#include "../citymania/cm_newgrf_revisions.hpp" #include "../citymania/cm_newgrf_revisions.hpp"
#include "../citymania/cm_client_list_gui.hpp"
#include "../safeguards.h" #include "../safeguards.h"
@@ -590,6 +591,7 @@ NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_CLIENT_INFO(Pac
ci->client_playas = playas; ci->client_playas = playas;
ci->client_name = name; ci->client_name = name;
citymania::SetClientListDirty();
InvalidateWindowData(WC_CLIENT_LIST, 0); InvalidateWindowData(WC_CLIENT_LIST, 0);
InvalidateWindowClassesData(WC_WATCH_COMPANY, 0); InvalidateWindowClassesData(WC_WATCH_COMPANY, 0);
SetWindowClassesDirty(WC_WATCH_COMPANY); SetWindowClassesDirty(WC_WATCH_COMPANY);
@@ -613,6 +615,7 @@ NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_CLIENT_INFO(Pac
ci->client_name = name; ci->client_name = name;
citymania::SetClientListDirty();
InvalidateWindowData(WC_CLIENT_LIST, 0); InvalidateWindowData(WC_CLIENT_LIST, 0);
InvalidateWindowClassesData(WC_WATCH_COMPANY, 0); InvalidateWindowClassesData(WC_WATCH_COMPANY, 0);
SetWindowClassesDirty(WC_WATCH_COMPANY); SetWindowClassesDirty(WC_WATCH_COMPANY);
@@ -1009,6 +1012,7 @@ NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_ERROR_QUIT(Pack
delete ci; delete ci;
} }
citymania::SetClientListDirty();
InvalidateWindowData(WC_CLIENT_LIST, 0); InvalidateWindowData(WC_CLIENT_LIST, 0);
return NETWORK_RECV_STATUS_OKAY; return NETWORK_RECV_STATUS_OKAY;
@@ -1028,6 +1032,7 @@ NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_QUIT(Packet *p)
Debug(net, 1, "Unknown client ({}) is leaving the game", client_id); Debug(net, 1, "Unknown client ({}) is leaving the game", client_id);
} }
citymania::SetClientListDirty();
InvalidateWindowData(WC_CLIENT_LIST, 0); InvalidateWindowData(WC_CLIENT_LIST, 0);
InvalidateWindowClassesData( WC_WATCH_COMPANYA, 0 ); InvalidateWindowClassesData( WC_WATCH_COMPANYA, 0 );
SetWindowClassesDirty( WC_WATCH_COMPANYA ); SetWindowClassesDirty( WC_WATCH_COMPANYA );
@@ -1047,6 +1052,7 @@ NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_JOIN(Packet *p)
NetworkTextMessage(NETWORK_ACTION_JOIN, CC_DEFAULT, false, ci->client_name); NetworkTextMessage(NETWORK_ACTION_JOIN, CC_DEFAULT, false, ci->client_name);
} }
citymania::SetClientListDirty();
InvalidateWindowData(WC_CLIENT_LIST, 0); InvalidateWindowData(WC_CLIENT_LIST, 0);
return NETWORK_RECV_STATUS_OKAY; return NETWORK_RECV_STATUS_OKAY;

View File

@@ -53,6 +53,7 @@
#include "../error.h" #include "../error.h"
#include "../zoom_func.h" #include "../zoom_func.h"
#include "../citymania/cm_client_list_gui.hpp"
#include "../citymania/cm_hotkeys.hpp" #include "../citymania/cm_hotkeys.hpp"
#include "../citymania/cm_watch_gui.hpp" #include "../citymania/cm_watch_gui.hpp"
@@ -1328,6 +1329,7 @@ static const NWidgetPart _nested_client_list_widgets[] = {
NWidget(NWID_HORIZONTAL), NWidget(NWID_HORIZONTAL),
NWidget(WWT_CLOSEBOX, COLOUR_GREY), NWidget(WWT_CLOSEBOX, COLOUR_GREY),
NWidget(WWT_CAPTION, COLOUR_GREY), SetDataTip(STR_NETWORK_CLIENT_LIST_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS), NWidget(WWT_CAPTION, COLOUR_GREY), SetDataTip(STR_NETWORK_CLIENT_LIST_CAPTION, STR_TOOLTIP_WINDOW_TITLE_DRAG_THIS),
NWidget(WWT_IMGBTN, COLOUR_GREY, CM_WID_CL_TOGGLE_OVERLAY), SetDataTip(SPR_LARGE_SMALL_WINDOW, CM_STR_TOGGLE_CLIENTS_OVERLAY),
NWidget(WWT_DEFSIZEBOX, COLOUR_GREY), NWidget(WWT_DEFSIZEBOX, COLOUR_GREY),
NWidget(WWT_STICKYBOX, COLOUR_GREY), NWidget(WWT_STICKYBOX, COLOUR_GREY),
EndContainer(), EndContainer(),
@@ -1743,6 +1745,7 @@ public:
this->vscroll = this->GetScrollbar(WID_CL_SCROLLBAR); this->vscroll = this->GetScrollbar(WID_CL_SCROLLBAR);
this->OnInvalidateData(); this->OnInvalidateData();
this->FinishInitNested(window_number); this->FinishInitNested(window_number);
this->GetWidget<NWidgetCore>(CM_WID_CL_TOGGLE_OVERLAY)->SetLowered(_settings_client.gui.cm_show_client_overlay);
} }
void OnInvalidateData(int data = 0, bool gui_scope = true) override void OnInvalidateData(int data = 0, bool gui_scope = true) override
@@ -1844,6 +1847,12 @@ public:
button->OnClick(this, pt); button->OnClick(this, pt);
break; break;
} }
case CM_WID_CL_TOGGLE_OVERLAY: {
_settings_client.gui.cm_show_client_overlay = !_settings_client.gui.cm_show_client_overlay;
this->GetWidget<NWidgetCore>(widget)->SetLowered(_settings_client.gui.cm_show_client_overlay);
citymania::SetClientListDirty();
break;
}
} }
} }

View File

@@ -32,6 +32,8 @@
#include <mutex> #include <mutex>
#include <condition_variable> #include <condition_variable>
#include "../citymania/cm_client_list_gui.hpp"
#include "../safeguards.h" #include "../safeguards.h"
@@ -293,6 +295,7 @@ NetworkRecvStatus ServerNetworkGameSocketHandler::CloseConnection(NetworkRecvSta
delete this->GetInfo(); delete this->GetInfo();
delete this; delete this;
citymania::SetClientListDirty();
InvalidateWindowData(WC_CLIENT_LIST, 0); InvalidateWindowData(WC_CLIENT_LIST, 0);
return status; return status;
@@ -977,6 +980,7 @@ NetworkRecvStatus ServerNetworkGameSocketHandler::Receive_CLIENT_MAP_OK(Packet *
std::string client_name = this->GetClientName(); std::string client_name = this->GetClientName();
NetworkTextMessage(NETWORK_ACTION_JOIN, CC_DEFAULT, false, client_name, "", this->client_id); NetworkTextMessage(NETWORK_ACTION_JOIN, CC_DEFAULT, false, client_name, "", this->client_id);
citymania::SetClientListDirty();
InvalidateWindowData(WC_CLIENT_LIST, 0); InvalidateWindowData(WC_CLIENT_LIST, 0);
Debug(net, 3, "[{}] Client #{} ({}) joined as {}", ServerNetworkGameSocketHandler::GetName(), this->client_id, this->GetClientIP(), client_name); Debug(net, 3, "[{}] Client #{} ({}) joined as {}", ServerNetworkGameSocketHandler::GetName(), this->client_id, this->GetClientIP(), client_name);
@@ -1945,6 +1949,7 @@ void NetworkServerDoMove(ClientID client_id, CompanyID company_id)
NetworkAction action = (company_id == COMPANY_SPECTATOR) ? NETWORK_ACTION_COMPANY_SPECTATOR : NETWORK_ACTION_COMPANY_JOIN; NetworkAction action = (company_id == COMPANY_SPECTATOR) ? NETWORK_ACTION_COMPANY_SPECTATOR : NETWORK_ACTION_COMPANY_JOIN;
NetworkServerSendChat(action, DESTTYPE_BROADCAST, 0, "", client_id, company_id + 1); NetworkServerSendChat(action, DESTTYPE_BROADCAST, 0, "", client_id, company_id + 1);
citymania::SetClientListDirty();
InvalidateWindowData(WC_CLIENT_LIST, 0); InvalidateWindowData(WC_CLIENT_LIST, 0);
} }

View File

@@ -223,6 +223,7 @@ struct GUISettings {
uint8 cm_shaded_trees; uint8 cm_shaded_trees;
bool cm_show_apm; bool cm_show_apm;
uint8 cm_graph_background; uint8 cm_graph_background;
bool cm_show_client_overlay;
/** /**
* Returns true when the user has sufficient privileges to edit newgrfs on a running game * Returns true when the user has sufficient privileges to edit newgrfs on a running game

View File

@@ -268,3 +268,7 @@ str = STR_CM_CONFIG_SETTING_IMPROVED_STATION_JOIN
strhelp = STR_CM_CONFIG_SETTING_IMPROVED_STATION_JOIN_HELPTEXT strhelp = STR_CM_CONFIG_SETTING_IMPROVED_STATION_JOIN_HELPTEXT
cat = SC_BASIC cat = SC_BASIC
[SDTC_BOOL]
var = gui.cm_show_client_overlay
def = false
cat = SC_BASIC

View File

@@ -95,6 +95,7 @@ enum ClientListWidgets {
WID_CL_SCROLLBAR, ///< Scrollbar for company/client list. WID_CL_SCROLLBAR, ///< Scrollbar for company/client list.
WID_CL_COMPANY_JOIN, ///< Used for QueryWindow when a company has a password. WID_CL_COMPANY_JOIN, ///< Used for QueryWindow when a company has a password.
WID_CL_CLIENT_COMPANY_COUNT, ///< Count of clients and companies. WID_CL_CLIENT_COMPANY_COUNT, ///< Count of clients and companies.
CM_WID_CL_TOGGLE_OVERLAY, ///< (CityMania) toggle client list overlay visibility.
}; };
/** Widgets of the #NetworkJoinStatusWindow class. */ /** Widgets of the #NetworkJoinStatusWindow class. */

View File

@@ -41,6 +41,7 @@
#include "guitimer_func.h" #include "guitimer_func.h"
#include "news_func.h" #include "news_func.h"
#include "citymania/cm_client_list_gui.hpp"
#include "citymania/cm_hotkeys.hpp" #include "citymania/cm_hotkeys.hpp"
#include "safeguards.h" #include "safeguards.h"
@@ -3132,6 +3133,7 @@ void UpdateWindows()
/* Update viewport only if window is not shaded. */ /* Update viewport only if window is not shaded. */
if (w->viewport != nullptr && !w->IsShaded()) UpdateViewportPosition(w); if (w->viewport != nullptr && !w->IsShaded()) UpdateViewportPosition(w);
} }
citymania::DrawClientList();
NetworkDrawChatMessage(); NetworkDrawChatMessage();
/* Redraw mouse cursor in case it was hidden */ /* Redraw mouse cursor in case it was hidden */
DrawMouseCursor(); DrawMouseCursor();