Add client list overlay (toggleable)
This commit is contained in:
@@ -24,6 +24,8 @@ add_files(
|
||||
cm_blueprint.cpp
|
||||
cm_cargo_table_gui.hpp
|
||||
cm_cargo_table_gui.cpp
|
||||
cm_client_list_gui.hpp
|
||||
cm_client_list_gui.cpp
|
||||
cm_commands_gui.hpp
|
||||
cm_commands_gui.cpp
|
||||
cm_highlight.hpp
|
||||
|
||||
205
src/citymania/cm_client_list_gui.cpp
Normal file
205
src/citymania/cm_client_list_gui.cpp
Normal 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
|
||||
12
src/citymania/cm_client_list_gui.hpp
Normal file
12
src/citymania/cm_client_list_gui.hpp
Normal 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
|
||||
@@ -26,6 +26,8 @@
|
||||
#include "table/sprites.h"
|
||||
#include "table/control_codes.h"
|
||||
|
||||
#include "citymania/cm_client_list_gui.hpp"
|
||||
|
||||
#include "safeguards.h"
|
||||
|
||||
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 (_networking) NetworkUndrawChatMessage();
|
||||
if (_networking) citymania::UndrawClientList(left, top, left + width, top + height);
|
||||
|
||||
blitter->ScrollBuffer(_screen.dst_ptr, left, top, width, height, xo, yo);
|
||||
/* 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) citymania::UndrawClientList(left, top, right, bottom);
|
||||
|
||||
DrawOverlappedWindowForAll(left, top, right, bottom);
|
||||
|
||||
|
||||
@@ -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_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.
|
||||
|
||||
@@ -39,7 +39,8 @@
|
||||
#include <sstream>
|
||||
#include <iomanip>
|
||||
|
||||
#include "citymania/cm_console_cmds.hpp"
|
||||
#include "../citymania/cm_client_list_gui.hpp"
|
||||
#include "../citymania/cm_console_cmds.hpp"
|
||||
|
||||
#include "../safeguards.h"
|
||||
|
||||
@@ -562,6 +563,7 @@ NetworkAddress ParseConnectionString(const std::string &connection_string, uint1
|
||||
ServerNetworkGameSocketHandler *cs = new ServerNetworkGameSocketHandler(s);
|
||||
cs->client_address = address; // Save the IP of the client
|
||||
|
||||
citymania::SetClientListDirty();
|
||||
InvalidateWindowData(WC_CLIENT_LIST, 0);
|
||||
}
|
||||
|
||||
|
||||
@@ -35,6 +35,7 @@
|
||||
#include "../town.h"
|
||||
#include "network_func.h"
|
||||
#include "../citymania/cm_newgrf_revisions.hpp"
|
||||
#include "../citymania/cm_client_list_gui.hpp"
|
||||
|
||||
#include "../safeguards.h"
|
||||
|
||||
@@ -590,6 +591,7 @@ NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_CLIENT_INFO(Pac
|
||||
ci->client_playas = playas;
|
||||
ci->client_name = name;
|
||||
|
||||
citymania::SetClientListDirty();
|
||||
InvalidateWindowData(WC_CLIENT_LIST, 0);
|
||||
InvalidateWindowClassesData(WC_WATCH_COMPANY, 0);
|
||||
SetWindowClassesDirty(WC_WATCH_COMPANY);
|
||||
@@ -613,6 +615,7 @@ NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_CLIENT_INFO(Pac
|
||||
|
||||
ci->client_name = name;
|
||||
|
||||
citymania::SetClientListDirty();
|
||||
InvalidateWindowData(WC_CLIENT_LIST, 0);
|
||||
InvalidateWindowClassesData(WC_WATCH_COMPANY, 0);
|
||||
SetWindowClassesDirty(WC_WATCH_COMPANY);
|
||||
@@ -1009,6 +1012,7 @@ NetworkRecvStatus ClientNetworkGameSocketHandler::Receive_SERVER_ERROR_QUIT(Pack
|
||||
delete ci;
|
||||
}
|
||||
|
||||
citymania::SetClientListDirty();
|
||||
InvalidateWindowData(WC_CLIENT_LIST, 0);
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
citymania::SetClientListDirty();
|
||||
InvalidateWindowData(WC_CLIENT_LIST, 0);
|
||||
InvalidateWindowClassesData( WC_WATCH_COMPANYA, 0 );
|
||||
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);
|
||||
}
|
||||
|
||||
citymania::SetClientListDirty();
|
||||
InvalidateWindowData(WC_CLIENT_LIST, 0);
|
||||
|
||||
return NETWORK_RECV_STATUS_OKAY;
|
||||
|
||||
@@ -53,6 +53,7 @@
|
||||
#include "../error.h"
|
||||
#include "../zoom_func.h"
|
||||
|
||||
#include "../citymania/cm_client_list_gui.hpp"
|
||||
#include "../citymania/cm_hotkeys.hpp"
|
||||
#include "../citymania/cm_watch_gui.hpp"
|
||||
|
||||
@@ -1328,6 +1329,7 @@ static const NWidgetPart _nested_client_list_widgets[] = {
|
||||
NWidget(NWID_HORIZONTAL),
|
||||
NWidget(WWT_CLOSEBOX, COLOUR_GREY),
|
||||
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_STICKYBOX, COLOUR_GREY),
|
||||
EndContainer(),
|
||||
@@ -1743,6 +1745,7 @@ public:
|
||||
this->vscroll = this->GetScrollbar(WID_CL_SCROLLBAR);
|
||||
this->OnInvalidateData();
|
||||
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
|
||||
@@ -1844,6 +1847,12 @@ public:
|
||||
button->OnClick(this, pt);
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -32,6 +32,8 @@
|
||||
#include <mutex>
|
||||
#include <condition_variable>
|
||||
|
||||
#include "../citymania/cm_client_list_gui.hpp"
|
||||
|
||||
#include "../safeguards.h"
|
||||
|
||||
|
||||
@@ -293,6 +295,7 @@ NetworkRecvStatus ServerNetworkGameSocketHandler::CloseConnection(NetworkRecvSta
|
||||
delete this->GetInfo();
|
||||
delete this;
|
||||
|
||||
citymania::SetClientListDirty();
|
||||
InvalidateWindowData(WC_CLIENT_LIST, 0);
|
||||
|
||||
return status;
|
||||
@@ -977,6 +980,7 @@ NetworkRecvStatus ServerNetworkGameSocketHandler::Receive_CLIENT_MAP_OK(Packet *
|
||||
std::string client_name = this->GetClientName();
|
||||
|
||||
NetworkTextMessage(NETWORK_ACTION_JOIN, CC_DEFAULT, false, client_name, "", this->client_id);
|
||||
citymania::SetClientListDirty();
|
||||
InvalidateWindowData(WC_CLIENT_LIST, 0);
|
||||
|
||||
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;
|
||||
NetworkServerSendChat(action, DESTTYPE_BROADCAST, 0, "", client_id, company_id + 1);
|
||||
|
||||
citymania::SetClientListDirty();
|
||||
InvalidateWindowData(WC_CLIENT_LIST, 0);
|
||||
}
|
||||
|
||||
|
||||
@@ -223,6 +223,7 @@ struct GUISettings {
|
||||
uint8 cm_shaded_trees;
|
||||
bool cm_show_apm;
|
||||
uint8 cm_graph_background;
|
||||
bool cm_show_client_overlay;
|
||||
|
||||
/**
|
||||
* Returns true when the user has sufficient privileges to edit newgrfs on a running game
|
||||
|
||||
@@ -268,3 +268,7 @@ str = STR_CM_CONFIG_SETTING_IMPROVED_STATION_JOIN
|
||||
strhelp = STR_CM_CONFIG_SETTING_IMPROVED_STATION_JOIN_HELPTEXT
|
||||
cat = SC_BASIC
|
||||
|
||||
[SDTC_BOOL]
|
||||
var = gui.cm_show_client_overlay
|
||||
def = false
|
||||
cat = SC_BASIC
|
||||
|
||||
@@ -95,6 +95,7 @@ enum ClientListWidgets {
|
||||
WID_CL_SCROLLBAR, ///< Scrollbar for company/client list.
|
||||
WID_CL_COMPANY_JOIN, ///< Used for QueryWindow when a company has a password.
|
||||
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. */
|
||||
|
||||
@@ -41,6 +41,7 @@
|
||||
#include "guitimer_func.h"
|
||||
#include "news_func.h"
|
||||
|
||||
#include "citymania/cm_client_list_gui.hpp"
|
||||
#include "citymania/cm_hotkeys.hpp"
|
||||
|
||||
#include "safeguards.h"
|
||||
@@ -3132,6 +3133,7 @@ void UpdateWindows()
|
||||
/* Update viewport only if window is not shaded. */
|
||||
if (w->viewport != nullptr && !w->IsShaded()) UpdateViewportPosition(w);
|
||||
}
|
||||
citymania::DrawClientList();
|
||||
NetworkDrawChatMessage();
|
||||
/* Redraw mouse cursor in case it was hidden */
|
||||
DrawMouseCursor();
|
||||
|
||||
Reference in New Issue
Block a user