mirror of
https://github.com/mRemoteNG/mRemoteNG.git
synced 2026-02-17 14:07:46 +08:00
Merge branch 'v1.78.2-dev' into copilot/add-color-support-for-connection-folders
This commit is contained in:
@@ -17,6 +17,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
||||
- #2734: fix native build for Windows-x64
|
||||
|
||||
### Added
|
||||
- Add configurable connection tab colors to distinguish between different environments (e.g., Dev, Test, Live)
|
||||
- #2728 Add support for building mRemoteNG on Windows ARM64
|
||||
- #2723: Read keyboardhook, gatewayaccesstoken and gatewaycredentialssource from RDP File
|
||||
- #2690: தமிழ் (ta) Translation update
|
||||
|
||||
@@ -42,6 +42,7 @@ namespace mRemoteNG.Config.Serializers.ConnectionSerializers.Xml
|
||||
element.Add(new XAttribute("Descr", connectionInfo.Description));
|
||||
element.Add(new XAttribute("Icon", connectionInfo.Icon));
|
||||
element.Add(new XAttribute("Panel", connectionInfo.Panel));
|
||||
element.Add(new XAttribute("TabColor", connectionInfo.TabColor));
|
||||
element.Add(new XAttribute("Id", connectionInfo.ConstantID));
|
||||
|
||||
if (!Runtime.UseCredentialManager)
|
||||
@@ -187,6 +188,8 @@ namespace mRemoteNG.Config.Serializers.ConnectionSerializers.Xml
|
||||
element.Add(new XAttribute("InheritIcon", inheritance.Icon.ToString().ToLowerInvariant()));
|
||||
if (inheritance.Panel)
|
||||
element.Add(new XAttribute("InheritPanel", inheritance.Panel.ToString().ToLowerInvariant()));
|
||||
if (inheritance.TabColor)
|
||||
element.Add(new XAttribute("InheritTabColor", inheritance.TabColor.ToString().ToLowerInvariant()));
|
||||
if (inheritance.Password)
|
||||
element.Add(new XAttribute("InheritPassword", inheritance.Password.ToString().ToLowerInvariant()));
|
||||
if (inheritance.Port)
|
||||
|
||||
@@ -328,6 +328,7 @@ namespace mRemoteNG.Config.Serializers.ConnectionSerializers.Xml
|
||||
connectionInfo.Inheritance.DisplayWallpaper = xmlnode.GetAttributeAsBool("InheritDisplayWallpaper");
|
||||
connectionInfo.Inheritance.Icon = xmlnode.GetAttributeAsBool("InheritIcon");
|
||||
connectionInfo.Inheritance.Panel = xmlnode.GetAttributeAsBool("InheritPanel");
|
||||
connectionInfo.Inheritance.TabColor = xmlnode.GetAttributeAsBool("InheritTabColor");
|
||||
connectionInfo.Inheritance.Port = xmlnode.GetAttributeAsBool("InheritPort");
|
||||
connectionInfo.Inheritance.Protocol = xmlnode.GetAttributeAsBool("InheritProtocol");
|
||||
connectionInfo.Inheritance.PuttySession = xmlnode.GetAttributeAsBool("InheritPuttySession");
|
||||
@@ -350,6 +351,7 @@ namespace mRemoteNG.Config.Serializers.ConnectionSerializers.Xml
|
||||
|
||||
connectionInfo.Icon = xmlnode.GetAttributeAsString("Icon");
|
||||
connectionInfo.Panel = xmlnode.GetAttributeAsString("Panel");
|
||||
connectionInfo.TabColor = xmlnode.GetAttributeAsString("TabColor");
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
@@ -61,6 +61,10 @@ namespace mRemoteNG.Config.Serializers.MiscSerializers
|
||||
if (host.Vnc)
|
||||
finalProtocol = ProtocolType.VNC;
|
||||
break;
|
||||
case ProtocolType.ARD:
|
||||
if (host.Vnc)
|
||||
finalProtocol = ProtocolType.ARD;
|
||||
break;
|
||||
default:
|
||||
protocolValid = false;
|
||||
break;
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Drawing;
|
||||
using mRemoteNG.Connection.Protocol;
|
||||
using mRemoteNG.Connection.Protocol.Http;
|
||||
using mRemoteNG.Connection.Protocol.RDP;
|
||||
@@ -23,6 +24,7 @@ namespace mRemoteNG.Connection
|
||||
private string _icon;
|
||||
private string _panel;
|
||||
private string _color;
|
||||
private string _tabColor;
|
||||
|
||||
private string _hostname;
|
||||
private ExternalAddressProvider _externalAddressProvider;
|
||||
@@ -163,6 +165,13 @@ namespace mRemoteNG.Connection
|
||||
{
|
||||
get => GetPropertyValue("Color", _color);
|
||||
set => SetField(ref _color, value, "Color");
|
||||
LocalizedAttributes.LocalizedDisplayName(nameof(Language.TabColor)),
|
||||
LocalizedAttributes.LocalizedDescription(nameof(Language.PropertyDescriptionTabColor)),
|
||||
TypeConverter(typeof(MiscTools.TabColorConverter))]
|
||||
public virtual string TabColor
|
||||
{
|
||||
get => GetPropertyValue("TabColor", _tabColor);
|
||||
set => SetField(ref _tabColor, value, "TabColor");
|
||||
}
|
||||
|
||||
#endregion
|
||||
@@ -920,7 +929,7 @@ namespace mRemoteNG.Connection
|
||||
LocalizedAttributes.LocalizedDisplayName(nameof(Language.Compression)),
|
||||
LocalizedAttributes.LocalizedDescription(nameof(Language.PropertyDescriptionCompression)),
|
||||
TypeConverter(typeof(MiscTools.EnumTypeConverter)),
|
||||
AttributeUsedInProtocol(ProtocolType.VNC),
|
||||
AttributeUsedInProtocol(ProtocolType.VNC, ProtocolType.ARD),
|
||||
Browsable(false)]
|
||||
public ProtocolVNC.Compression VNCCompression
|
||||
{
|
||||
@@ -932,7 +941,7 @@ namespace mRemoteNG.Connection
|
||||
LocalizedAttributes.LocalizedDisplayName(nameof(Language.Encoding)),
|
||||
LocalizedAttributes.LocalizedDescription(nameof(Language.PropertyDescriptionEncoding)),
|
||||
TypeConverter(typeof(MiscTools.EnumTypeConverter)),
|
||||
AttributeUsedInProtocol(ProtocolType.VNC),
|
||||
AttributeUsedInProtocol(ProtocolType.VNC, ProtocolType.ARD),
|
||||
Browsable(false)]
|
||||
public ProtocolVNC.Encoding VNCEncoding
|
||||
{
|
||||
@@ -944,7 +953,7 @@ namespace mRemoteNG.Connection
|
||||
LocalizedAttributes.LocalizedDisplayName(nameof(Language.AuthenticationMode)),
|
||||
LocalizedAttributes.LocalizedDescription(nameof(Language.PropertyDescriptionAuthenticationMode)),
|
||||
TypeConverter(typeof(MiscTools.EnumTypeConverter)),
|
||||
AttributeUsedInProtocol(ProtocolType.VNC),
|
||||
AttributeUsedInProtocol(ProtocolType.VNC, ProtocolType.ARD),
|
||||
Browsable(false)]
|
||||
public ProtocolVNC.AuthMode VNCAuthMode
|
||||
{
|
||||
@@ -956,7 +965,7 @@ namespace mRemoteNG.Connection
|
||||
LocalizedAttributes.LocalizedDisplayName(nameof(Language.ProxyType)),
|
||||
LocalizedAttributes.LocalizedDescription(nameof(Language.PropertyDescriptionVNCProxyType)),
|
||||
TypeConverter(typeof(MiscTools.EnumTypeConverter)),
|
||||
AttributeUsedInProtocol(ProtocolType.VNC),
|
||||
AttributeUsedInProtocol(ProtocolType.VNC, ProtocolType.ARD),
|
||||
Browsable(false)]
|
||||
public ProtocolVNC.ProxyType VNCProxyType
|
||||
{
|
||||
@@ -967,7 +976,7 @@ namespace mRemoteNG.Connection
|
||||
[LocalizedAttributes.LocalizedCategory(nameof(Language.Proxy), 7),
|
||||
LocalizedAttributes.LocalizedDisplayName(nameof(Language.ProxyAddress)),
|
||||
LocalizedAttributes.LocalizedDescription(nameof(Language.PropertyDescriptionVNCProxyAddress)),
|
||||
AttributeUsedInProtocol(ProtocolType.VNC),
|
||||
AttributeUsedInProtocol(ProtocolType.VNC, ProtocolType.ARD),
|
||||
Browsable(false)]
|
||||
public string VNCProxyIP
|
||||
{
|
||||
@@ -978,7 +987,7 @@ namespace mRemoteNG.Connection
|
||||
[LocalizedAttributes.LocalizedCategory(nameof(Language.Proxy), 7),
|
||||
LocalizedAttributes.LocalizedDisplayName(nameof(Language.ProxyPort)),
|
||||
LocalizedAttributes.LocalizedDescription(nameof(Language.PropertyDescriptionVNCProxyPort)),
|
||||
AttributeUsedInProtocol(ProtocolType.VNC),
|
||||
AttributeUsedInProtocol(ProtocolType.VNC, ProtocolType.ARD),
|
||||
Browsable(false)]
|
||||
public int VNCProxyPort
|
||||
{
|
||||
@@ -989,7 +998,7 @@ namespace mRemoteNG.Connection
|
||||
[LocalizedAttributes.LocalizedCategory(nameof(Language.Proxy), 7),
|
||||
LocalizedAttributes.LocalizedDisplayName(nameof(Language.ProxyUsername)),
|
||||
LocalizedAttributes.LocalizedDescription(nameof(Language.PropertyDescriptionVNCProxyUsername)),
|
||||
AttributeUsedInProtocol(ProtocolType.VNC),
|
||||
AttributeUsedInProtocol(ProtocolType.VNC, ProtocolType.ARD),
|
||||
Browsable(false)]
|
||||
public string VNCProxyUsername
|
||||
{
|
||||
@@ -1001,7 +1010,7 @@ namespace mRemoteNG.Connection
|
||||
LocalizedAttributes.LocalizedDisplayName(nameof(Language.ProxyPassword)),
|
||||
LocalizedAttributes.LocalizedDescription(nameof(Language.PropertyDescriptionVNCProxyPassword)),
|
||||
PasswordPropertyText(true),
|
||||
AttributeUsedInProtocol(ProtocolType.VNC),
|
||||
AttributeUsedInProtocol(ProtocolType.VNC, ProtocolType.ARD),
|
||||
Browsable(false)]
|
||||
public string VNCProxyPassword
|
||||
{
|
||||
@@ -1013,7 +1022,7 @@ namespace mRemoteNG.Connection
|
||||
LocalizedAttributes.LocalizedDisplayName(nameof(Language.Colors)),
|
||||
LocalizedAttributes.LocalizedDescription(nameof(Language.PropertyDescriptionColors)),
|
||||
TypeConverter(typeof(MiscTools.EnumTypeConverter)),
|
||||
AttributeUsedInProtocol(ProtocolType.VNC),
|
||||
AttributeUsedInProtocol(ProtocolType.VNC, ProtocolType.ARD),
|
||||
Browsable(false)]
|
||||
public ProtocolVNC.Colors VNCColors
|
||||
{
|
||||
@@ -1025,7 +1034,7 @@ namespace mRemoteNG.Connection
|
||||
LocalizedAttributes.LocalizedDisplayName(nameof(Language.SmartSizeMode)),
|
||||
LocalizedAttributes.LocalizedDescription(nameof(Language.PropertyDescriptionSmartSizeMode)),
|
||||
TypeConverter(typeof(MiscTools.EnumTypeConverter)),
|
||||
AttributeUsedInProtocol(ProtocolType.VNC)]
|
||||
AttributeUsedInProtocol(ProtocolType.VNC, ProtocolType.ARD)]
|
||||
public ProtocolVNC.SmartSizeMode VNCSmartSizeMode
|
||||
{
|
||||
get => GetPropertyValue("VNCSmartSizeMode", _vncSmartSizeMode);
|
||||
@@ -1036,7 +1045,7 @@ namespace mRemoteNG.Connection
|
||||
LocalizedAttributes.LocalizedDisplayName(nameof(Language.ViewOnly)),
|
||||
LocalizedAttributes.LocalizedDescription(nameof(Language.PropertyDescriptionViewOnly)),
|
||||
TypeConverter(typeof(MiscTools.YesNoTypeConverter)),
|
||||
AttributeUsedInProtocol(ProtocolType.VNC)]
|
||||
AttributeUsedInProtocol(ProtocolType.VNC, ProtocolType.ARD)]
|
||||
public bool VNCViewOnly
|
||||
{
|
||||
get => GetPropertyValue("VNCViewOnly", _vncViewOnly);
|
||||
|
||||
@@ -5,6 +5,7 @@ using System.Linq;
|
||||
using System.Reflection;
|
||||
using mRemoteNG.App;
|
||||
using mRemoteNG.Connection.Protocol;
|
||||
using mRemoteNG.Connection.Protocol.ARD;
|
||||
using mRemoteNG.Connection.Protocol.Http;
|
||||
using mRemoteNG.Connection.Protocol.PowerShell;
|
||||
using mRemoteNG.Connection.Protocol.RAW;
|
||||
@@ -254,6 +255,8 @@ namespace mRemoteNG.Connection
|
||||
return (int)RdpProtocol.Defaults.Port;
|
||||
case ProtocolType.VNC:
|
||||
return (int)ProtocolVNC.Defaults.Port;
|
||||
case ProtocolType.ARD:
|
||||
return (int)ProtocolARD.Defaults.Port;
|
||||
case ProtocolType.SSH1:
|
||||
return (int)ProtocolSSH1.Defaults.Port;
|
||||
case ProtocolType.SSH2:
|
||||
@@ -290,6 +293,7 @@ namespace mRemoteNG.Connection
|
||||
Icon = Settings.Default.ConDefaultIcon;
|
||||
Panel = Language.General;
|
||||
Color = string.Empty;
|
||||
TabColor = string.Empty;
|
||||
}
|
||||
|
||||
private void SetConnectionDefaults()
|
||||
|
||||
@@ -55,6 +55,10 @@ namespace mRemoteNG.Connection
|
||||
LocalizedAttributes.LocalizedDescriptionInherit(nameof(Language.PropertyDescriptionColor)),
|
||||
TypeConverter(typeof(MiscTools.YesNoTypeConverter))]
|
||||
public bool Color { get; set; }
|
||||
LocalizedAttributes.LocalizedDisplayNameInherit(nameof(Language.TabColor)),
|
||||
LocalizedAttributes.LocalizedDescriptionInherit(nameof(Language.PropertyDescriptionTabColor)),
|
||||
TypeConverter(typeof(MiscTools.YesNoTypeConverter))]
|
||||
public bool TabColor { get; set; }
|
||||
|
||||
#endregion
|
||||
|
||||
|
||||
19
mRemoteNG/Connection/Protocol/ARD/ProtocolARD.cs
Normal file
19
mRemoteNG/Connection/Protocol/ARD/ProtocolARD.cs
Normal file
@@ -0,0 +1,19 @@
|
||||
using System;
|
||||
using System.Runtime.Versioning;
|
||||
using mRemoteNG.Connection.Protocol.VNC;
|
||||
|
||||
namespace mRemoteNG.Connection.Protocol.ARD
|
||||
{
|
||||
[SupportedOSPlatform("windows")]
|
||||
public class ProtocolARD : ProtocolVNC
|
||||
{
|
||||
public ProtocolARD()
|
||||
{
|
||||
}
|
||||
|
||||
public new enum Defaults
|
||||
{
|
||||
Port = 5900
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -5,6 +5,7 @@ using mRemoteNG.Connection.Protocol.Rlogin;
|
||||
using mRemoteNG.Connection.Protocol.SSH;
|
||||
using mRemoteNG.Connection.Protocol.Telnet;
|
||||
using mRemoteNG.Connection.Protocol.VNC;
|
||||
using mRemoteNG.Connection.Protocol.ARD;
|
||||
using System;
|
||||
using mRemoteNG.Connection.Protocol.PowerShell;
|
||||
using mRemoteNG.Resources.Language;
|
||||
@@ -28,6 +29,8 @@ namespace mRemoteNG.Connection.Protocol
|
||||
return rdp;
|
||||
case ProtocolType.VNC:
|
||||
return new ProtocolVNC();
|
||||
case ProtocolType.ARD:
|
||||
return new ProtocolARD();
|
||||
case ProtocolType.SSH1:
|
||||
return new ProtocolSSH1();
|
||||
case ProtocolType.SSH2:
|
||||
|
||||
@@ -35,6 +35,9 @@ namespace mRemoteNG.Connection.Protocol
|
||||
[LocalizedAttributes.LocalizedDescription(nameof(Language.PowerShell))]
|
||||
PowerShell = 10,
|
||||
|
||||
[LocalizedAttributes.LocalizedDescription(nameof(Language.Ard))]
|
||||
ARD = 11,
|
||||
|
||||
[LocalizedAttributes.LocalizedDescription(nameof(Language.ExternalTool))]
|
||||
IntApp = 20
|
||||
}
|
||||
|
||||
@@ -159,6 +159,9 @@
|
||||
<data name="AskUpdatesMainInstruction" xml:space="preserve">
|
||||
<value>Automatic update settings</value>
|
||||
</data>
|
||||
<data name="Ard" xml:space="preserve">
|
||||
<value>ARD (Apple Remote Desktop)</value>
|
||||
</data>
|
||||
<data name="Aspect" xml:space="preserve">
|
||||
<value>Aspect</value>
|
||||
</data>
|
||||
@@ -1022,6 +1025,8 @@ If you run into such an error, please create a new connection file!</value>
|
||||
</data>
|
||||
<data name="PropertyDescriptionColor" xml:space="preserve">
|
||||
<value>Sets the color for the connection or folder in the connections tree. Connections inherit this color from their parent folder.</value>
|
||||
<data name="PropertyDescriptionTabColor" xml:space="preserve">
|
||||
<value>Sets the color of the connection tab. Leave empty for default theme color.</value>
|
||||
</data>
|
||||
<data name="PropertyDescriptionPassword" xml:space="preserve">
|
||||
<value>Enter your password.</value>
|
||||
@@ -1188,6 +1193,9 @@ If you run into such an error, please create a new connection file!</value>
|
||||
<data name="Panel" xml:space="preserve">
|
||||
<value>Panel</value>
|
||||
</data>
|
||||
<data name="TabColor" xml:space="preserve">
|
||||
<value>Tab Color</value>
|
||||
</data>
|
||||
<data name="Password" xml:space="preserve">
|
||||
<value>Password</value>
|
||||
</data>
|
||||
|
||||
@@ -268,5 +268,131 @@ namespace mRemoteNG.Tools
|
||||
return svc;
|
||||
}
|
||||
}
|
||||
|
||||
public class TabColorConverter : TypeConverter
|
||||
{
|
||||
public override bool CanConvertFrom(ITypeDescriptorContext? context, Type sourceType)
|
||||
{
|
||||
return sourceType == typeof(string) || sourceType == typeof(Color) || base.CanConvertFrom(context, sourceType);
|
||||
}
|
||||
|
||||
public override bool CanConvertTo(ITypeDescriptorContext? context, Type? destinationType)
|
||||
{
|
||||
return destinationType == typeof(string) || destinationType == typeof(Color) || base.CanConvertTo(context, destinationType);
|
||||
}
|
||||
|
||||
public override object? ConvertFrom(ITypeDescriptorContext? context, CultureInfo? culture, object? value)
|
||||
{
|
||||
if (value == null || (value is string str && string.IsNullOrWhiteSpace(str)))
|
||||
{
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
if (value is string stringValue)
|
||||
{
|
||||
return stringValue;
|
||||
}
|
||||
|
||||
if (value is Color colorValue)
|
||||
{
|
||||
// Convert Color to string representation
|
||||
// Use named color if it's a known color, otherwise use hex format
|
||||
if (colorValue.IsNamedColor)
|
||||
{
|
||||
return colorValue.Name;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Return hex format without alpha if fully opaque, otherwise include alpha
|
||||
if (colorValue.A == 255)
|
||||
{
|
||||
return $"#{colorValue.R:X2}{colorValue.G:X2}{colorValue.B:X2}";
|
||||
}
|
||||
else
|
||||
{
|
||||
return $"#{colorValue.A:X2}{colorValue.R:X2}{colorValue.G:X2}{colorValue.B:X2}";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return base.ConvertFrom(context, culture, value);
|
||||
}
|
||||
|
||||
public override object ConvertTo(ITypeDescriptorContext? context, CultureInfo? culture, object? value, Type destinationType)
|
||||
{
|
||||
if (destinationType == typeof(string))
|
||||
{
|
||||
if (value == null || (value is string str && string.IsNullOrWhiteSpace(str)))
|
||||
{
|
||||
return string.Empty;
|
||||
}
|
||||
return value.ToString() ?? string.Empty;
|
||||
}
|
||||
|
||||
if (destinationType == typeof(Color))
|
||||
{
|
||||
if (value == null || (value is string str && string.IsNullOrWhiteSpace(str)))
|
||||
{
|
||||
return Color.Empty;
|
||||
}
|
||||
|
||||
if (value is string stringValue)
|
||||
{
|
||||
try
|
||||
{
|
||||
ColorConverter converter = new ColorConverter();
|
||||
return converter.ConvertFromString(stringValue) ?? Color.Empty;
|
||||
}
|
||||
catch
|
||||
{
|
||||
return Color.Empty;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return base.ConvertTo(context, culture, value, destinationType) ?? throw new InvalidOperationException("Base conversion returned null.");
|
||||
}
|
||||
|
||||
public override bool GetStandardValuesSupported(ITypeDescriptorContext? context)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public override StandardValuesCollection GetStandardValues(ITypeDescriptorContext? context)
|
||||
{
|
||||
// Provide a list of common colors for the dropdown
|
||||
Color[] colors =
|
||||
[
|
||||
Color.Red,
|
||||
Color.Orange,
|
||||
Color.Yellow,
|
||||
Color.Green,
|
||||
Color.Blue,
|
||||
Color.Purple,
|
||||
Color.Pink,
|
||||
Color.Brown,
|
||||
Color.Black,
|
||||
Color.White,
|
||||
Color.Gray,
|
||||
Color.LightGray,
|
||||
Color.DarkGray,
|
||||
Color.Cyan,
|
||||
Color.Magenta,
|
||||
Color.Lime,
|
||||
Color.Navy,
|
||||
Color.Teal,
|
||||
Color.Maroon,
|
||||
Color.Olive
|
||||
];
|
||||
|
||||
return new StandardValuesCollection(colors);
|
||||
}
|
||||
|
||||
public override bool GetStandardValuesExclusive(ITypeDescriptorContext? context)
|
||||
{
|
||||
// Return false to allow custom values (hex codes or other color names)
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -168,6 +168,7 @@ namespace mRemoteNG.UI.Controls.ConnectionInfoPropertyGrid
|
||||
strHide.AddRange(SpecialRdpExclusions());
|
||||
break;
|
||||
case ProtocolType.VNC:
|
||||
case ProtocolType.ARD:
|
||||
strHide.AddRange(SpecialVncExclusions());
|
||||
break;
|
||||
}
|
||||
|
||||
@@ -991,8 +991,11 @@ namespace mRemoteNG.UI.Tabs
|
||||
rectText = DrawHelper.RtlTransform(this, rectText);
|
||||
rectIcon = DrawHelper.RtlTransform(this, rectIcon);
|
||||
|
||||
Color activeColor = DockPane.DockPanel.Theme.ColorPalette.TabSelectedActive.Background;
|
||||
Color lostFocusColor = DockPane.DockPanel.Theme.ColorPalette.TabSelectedInactive.Background;
|
||||
// Get custom tab color if available
|
||||
Color? customTabColor = GetCustomTabColor(tab.Content);
|
||||
|
||||
Color activeColor = customTabColor ?? DockPane.DockPanel.Theme.ColorPalette.TabSelectedActive.Background;
|
||||
Color lostFocusColor = customTabColor ?? DockPane.DockPanel.Theme.ColorPalette.TabSelectedInactive.Background;
|
||||
Color inactiveColor = DockPane.DockPanel.Theme.ColorPalette.MainWindowActive.Background;
|
||||
Color mouseHoverColor = DockPane.DockPanel.Theme.ColorPalette.TabUnselectedHovered.Background;
|
||||
|
||||
@@ -1056,6 +1059,31 @@ namespace mRemoteNG.UI.Tabs
|
||||
g.DrawIcon(tab.Content.DockHandler.Icon, rectIcon);
|
||||
}
|
||||
|
||||
private Color? GetCustomTabColor(IDockContent content)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (content is ConnectionTab connectionTab)
|
||||
{
|
||||
InterfaceControl interfaceControl = InterfaceControl.FindInterfaceControl(connectionTab);
|
||||
if (interfaceControl?.Info != null)
|
||||
{
|
||||
string tabColorStr = interfaceControl.Info.TabColor;
|
||||
if (!string.IsNullOrEmpty(tabColorStr))
|
||||
{
|
||||
ColorConverter converter = new ColorConverter();
|
||||
return (Color)converter.ConvertFromString(tabColorStr);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
// If there's any error parsing the color, just return null to use default
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private bool m_isMouseDown;
|
||||
|
||||
protected bool IsMouseDown
|
||||
|
||||
@@ -776,6 +776,7 @@ namespace mRemoteNG.UI.Window
|
||||
ProtocolBase protocolBase = sender as ProtocolBase;
|
||||
if (!(protocolBase?.InterfaceControl.Parent is ConnectionTab tabPage)) return;
|
||||
if (tabPage.Disposing || tabPage.IsDisposed) return;
|
||||
if (IsDisposed || Disposing) return;
|
||||
tabPage.protocolClose = true;
|
||||
Invoke(new Action(() => tabPage.Close()));
|
||||
}
|
||||
|
||||
@@ -87,6 +87,26 @@ Icon
|
||||
The icon indicates the visual identifier for the connection.
|
||||
Clicking the icon will let you set a different icon for the connection.
|
||||
|
||||
Tab Color
|
||||
---------
|
||||
|
||||
.. note::
|
||||
|
||||
The Tab Color property is available in the Display category of the connection properties.
|
||||
|
||||
You can set a custom color for connection tabs to help distinguish between different environments (e.g., Development, Testing, Production).
|
||||
This can be especially useful when working with critical systems like Live servers, where you want a clear visual reminder.
|
||||
|
||||
To set a tab color:
|
||||
|
||||
1. Select your connection in the Connections panel
|
||||
2. In the Config panel, expand the **Display** category
|
||||
3. Find the **Tab Color** property
|
||||
4. Enter a color name (e.g., "Red", "Green", "Blue") or a hex color code (e.g., "#FF0000", "#00FF00")
|
||||
5. Leave empty to use the default theme color
|
||||
|
||||
The tab color will be applied when you open the connection. You can use inheritance to set the same color for multiple connections in a folder.
|
||||
|
||||
Status
|
||||
------
|
||||
|
||||
|
||||
@@ -115,6 +115,7 @@ namespace mRemoteNGTests.Connection
|
||||
[TestCase(ProtocolType.SSH2, ExpectedResult = 22)]
|
||||
[TestCase(ProtocolType.Telnet, ExpectedResult = 23)]
|
||||
[TestCase(ProtocolType.VNC, ExpectedResult = 5900)]
|
||||
[TestCase(ProtocolType.ARD, ExpectedResult = 5900)]
|
||||
public int GetDefaultPortReturnsCorrectPortForProtocol(ProtocolType protocolType)
|
||||
{
|
||||
_connectionInfo.Protocol = protocolType;
|
||||
|
||||
148
mRemoteNGTests/Tools/TabColorConverterTests.cs
Normal file
148
mRemoteNGTests/Tools/TabColorConverterTests.cs
Normal file
@@ -0,0 +1,148 @@
|
||||
using System.Drawing;
|
||||
using mRemoteNG.Tools;
|
||||
using NUnit.Framework;
|
||||
|
||||
namespace mRemoteNGTests.Tools
|
||||
{
|
||||
public class TabColorConverterTests
|
||||
{
|
||||
private MiscTools.TabColorConverter _converter;
|
||||
|
||||
[SetUp]
|
||||
public void Setup()
|
||||
{
|
||||
_converter = new MiscTools.TabColorConverter();
|
||||
}
|
||||
|
||||
[TestCase(typeof(string), true)]
|
||||
[TestCase(typeof(Color), true)]
|
||||
public void CanConvertFrom(Type typeToConvertFrom, bool expectedOutcome)
|
||||
{
|
||||
var actualOutcome = _converter.CanConvertFrom(typeToConvertFrom);
|
||||
Assert.That(actualOutcome, Is.EqualTo(expectedOutcome));
|
||||
}
|
||||
|
||||
[TestCase(typeof(string), true)]
|
||||
[TestCase(typeof(Color), true)]
|
||||
public void CanConvertTo(Type typeToConvertTo, bool expectedOutcome)
|
||||
{
|
||||
var actualOutcome = _converter.CanConvertTo(typeToConvertTo);
|
||||
Assert.That(actualOutcome, Is.EqualTo(expectedOutcome));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ConvertFromColorToStringNamedColor()
|
||||
{
|
||||
var color = Color.Red;
|
||||
var result = _converter.ConvertFrom(color);
|
||||
Assert.That(result, Is.EqualTo("Red"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ConvertFromColorToStringCustomColor()
|
||||
{
|
||||
var color = Color.FromArgb(255, 128, 64, 32);
|
||||
var result = _converter.ConvertFrom(color);
|
||||
Assert.That(result, Is.EqualTo("#80401F"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ConvertFromColorToStringCustomColorWithAlpha()
|
||||
{
|
||||
var color = Color.FromArgb(128, 255, 0, 0);
|
||||
var result = _converter.ConvertFrom(color);
|
||||
Assert.That(result, Is.EqualTo("#80FF0000"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ConvertFromStringReturnsString()
|
||||
{
|
||||
var colorString = "Blue";
|
||||
var result = _converter.ConvertFrom(colorString);
|
||||
Assert.That(result, Is.EqualTo("Blue"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ConvertFromHexStringReturnsString()
|
||||
{
|
||||
var colorString = "#FF0000";
|
||||
var result = _converter.ConvertFrom(colorString);
|
||||
Assert.That(result, Is.EqualTo("#FF0000"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ConvertFromNullReturnsEmptyString()
|
||||
{
|
||||
var result = _converter.ConvertFrom(null);
|
||||
Assert.That(result, Is.EqualTo(string.Empty));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ConvertFromEmptyStringReturnsEmptyString()
|
||||
{
|
||||
var result = _converter.ConvertFrom("");
|
||||
Assert.That(result, Is.EqualTo(string.Empty));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ConvertToStringFromString()
|
||||
{
|
||||
var colorString = "Green";
|
||||
var result = _converter.ConvertTo(colorString, typeof(string));
|
||||
Assert.That(result, Is.EqualTo("Green"));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ConvertToColorFromNamedString()
|
||||
{
|
||||
var colorString = "Red";
|
||||
var result = _converter.ConvertTo(colorString, typeof(Color));
|
||||
Assert.That(result, Is.EqualTo(Color.Red));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ConvertToColorFromHexString()
|
||||
{
|
||||
var colorString = "#FF0000";
|
||||
var result = _converter.ConvertTo(colorString, typeof(Color));
|
||||
var expectedColor = Color.FromArgb(255, 255, 0, 0);
|
||||
Assert.That(result, Is.EqualTo(expectedColor));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ConvertToColorFromEmptyStringReturnsEmpty()
|
||||
{
|
||||
var result = _converter.ConvertTo("", typeof(Color));
|
||||
Assert.That(result, Is.EqualTo(Color.Empty));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ConvertToColorFromNullReturnsEmpty()
|
||||
{
|
||||
var result = _converter.ConvertTo(null, typeof(Color));
|
||||
Assert.That(result, Is.EqualTo(Color.Empty));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GetStandardValuesSupportedReturnsTrue()
|
||||
{
|
||||
var result = _converter.GetStandardValuesSupported(null);
|
||||
Assert.That(result, Is.True);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GetStandardValuesReturnsColorList()
|
||||
{
|
||||
var result = _converter.GetStandardValues(null);
|
||||
Assert.That(result, Is.Not.Null);
|
||||
Assert.That(result.Count, Is.GreaterThan(0));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void GetStandardValuesExclusiveReturnsFalse()
|
||||
{
|
||||
var result = _converter.GetStandardValuesExclusive(null);
|
||||
Assert.That(result, Is.False);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user