Linux: Integrate some of Mesen's code to fix usability issues with menu/tool bars and improve the look of some controls

This commit is contained in:
Sour 2019-10-26 11:45:32 -04:00
parent 97571c94bc
commit 95199f5f62
5 changed files with 373 additions and 2 deletions

View file

@ -41,8 +41,6 @@ namespace Mesen.GUI.Debugger
protected override void OnLoad(EventArgs e)
{
base.OnLoad(e);
_notifListener = new NotificationListener();
_notifListener.OnNotification += OnNotificationReceived;
@ -89,6 +87,8 @@ namespace Mesen.GUI.Debugger
BreakpointManager.AddCpuType(_cpuType);
DebugApi.Step(_cpuType, 10000, StepType.Step);
base.OnLoad(e);
}
protected override void OnClosing(CancelEventArgs e)

View file

@ -25,6 +25,7 @@ namespace Mesen.GUI.Forms
public BaseForm()
{
InitializeComponent();
MonoThemeHelper.InitTheme(Color.White);
}
public virtual bool IsConfigForm { get { return false; } }
@ -88,6 +89,8 @@ namespace Mesen.GUI.Forms
}
}
MonoThemeHelper.FixMonoColors(this);
int tabIndex = 0;
InitializeTabIndexes(this, ref tabIndex);
ResourceHelper.ApplyResources(this);

290
UI/Forms/MonoThemeHelper.cs Normal file
View file

@ -0,0 +1,290 @@
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace Mesen.GUI
{
public static class MonoThemeHelper
{
public static MonoTheme Theme { get; private set; } = new MonoTheme();
private static Dictionary<string, List<WeakReference<object>>> _excludedControls = new Dictionary<string, List<WeakReference<object>>>();
public static void InitTheme(Color backColor)
{
if(backColor.R < 128 && backColor.G < 128 && backColor.B < 128) {
Theme = new DarkMonoTheme();
} else {
Theme = new MonoTheme();
}
}
public static bool IsDark { get { return Theme is DarkMonoTheme; } }
public static void ExcludeFromTheme(Control ctrl)
{
if(Program.IsMono) {
List<WeakReference<object>> refList;
if(!_excludedControls.TryGetValue(ctrl.Name, out refList)) {
refList = new List<WeakReference<object>>();
_excludedControls[ctrl.Name] = refList;
}
refList.Add(new WeakReference<object>(ctrl));
}
}
public static bool IsExcludedFromTheme(Control ctrl)
{
if(Program.IsMono) {
List<WeakReference<object>> refList;
if(_excludedControls.TryGetValue(ctrl.Name, out refList)) {
foreach(WeakReference<object> weakRef in refList) {
object target;
if(weakRef.TryGetTarget(out target)) {
return target == ctrl;
}
}
}
}
return false;
}
public static void FixMonoColors(Form form)
{
if(Program.IsMono) {
form.BackColor = Theme.FormBgColor;
FixMonoColors(form, Theme);
}
}
public static void FixMonoColors(ContextMenuStrip menu)
{
if(Program.IsMono) {
if(menu.Tag == null || (bool)menu.Tag != true) {
//Only process this context menu a single time (uses its Tag to know if we've processed it or not)
FixMonoColors(menu, Theme);
menu.Tag = true;
}
}
}
private static void FixMonoColors(ToolStripItem item, MonoTheme theme)
{
item.ForeColor = item.Enabled ? theme.ToolStripItemForeColor : theme.ToolStripItemDisabledForeColor;
item.BackColor = theme.ToolStripItemBgColor;
item.Font = new Font("Microsoft Sans Serif", 8.25f);
item.EnabledChanged += (object sender, EventArgs e) => {
((ToolStripItem)sender).ForeColor = ((ToolStripItem)sender).Enabled ? theme.ToolStripItemForeColor : theme.ToolStripItemDisabledForeColor;
};
if(item is ToolStripDropDownItem) {
ToolStripDropDownItem ddItem = item as ToolStripDropDownItem;
ddItem.DropDownOpening += MonoToolStripHelper.DropdownOpening;
ddItem.DropDownClosed += MonoToolStripHelper.DropdownClosed;
ddItem.DropDownOpening += (s, e) => {
ddItem.DropDown.BackColor = theme.ToolStripItemBgColor;
foreach(ToolStripItem subItem in ddItem.DropDownItems) {
FixMonoColors(subItem, theme);
}
};
foreach(ToolStripItem subItem in ddItem.DropDownItems) {
FixMonoColors(subItem, theme);
}
}
}
private static void FixMonoColors(Control container, MonoTheme theme)
{
if(MonoThemeHelper.IsExcludedFromTheme(container)) {
return;
}
if(container is TextBox) {
TextBox txt = (TextBox)container;
txt.BorderStyle = BorderStyle.FixedSingle;
txt.BackColor = txt.ReadOnly ? theme.TextBoxDisabledBgColor : theme.TextBoxEnabledBgColor;
txt.ForeColor = theme.TextBoxForeColor;
txt.ReadOnlyChanged += (object sender, EventArgs e) => {
((TextBox)sender).BackColor = ((TextBox)sender).ReadOnly ? theme.TextBoxDisabledBgColor : theme.TextBoxEnabledBgColor;
};
} else if(container is Label) {
Label lbl = (Label)container;
if(lbl.BackColor == Color.White) {
//Trackbar labels
lbl.BackColor = theme.TextBoxEnabledBgColor;
lbl.ForeColor = theme.TextBoxForeColor;
} else {
if(lbl.ForeColor == SystemColors.GrayText) {
//Headers
lbl.ForeColor = theme.GrayTextColor;
} else if(lbl.ForeColor == SystemColors.ControlDark) {
//ctrlRiskyOption
lbl.ForeColor = theme.DarkTextColor;
} else {
//Regular label
lbl.ForeColor = lbl.Enabled ? theme.LabelForeColor : theme.LabelDisabledForeColor;
lbl.EnabledChanged += (object sender, EventArgs e) => {
((Label)sender).ForeColor = ((Label)sender).Enabled ? theme.LabelForeColor : theme.LabelDisabledForeColor;
};
}
}
} else if(container is CheckBox) {
CheckBox chk = (CheckBox)container;
chk.FlatStyle = FlatStyle.Flat;
chk.ForeColor = chk.Enabled ? theme.LabelForeColor : theme.LabelDisabledForeColor;
if(chk.BackColor == SystemColors.ControlLightLight) {
//Enable equalizer checkbox
chk.BackColor = theme.TabBgColor;
}
chk.EnabledChanged += (object sender, EventArgs e) => {
((CheckBox)sender).ForeColor = ((CheckBox)sender).Enabled ? theme.LabelForeColor : theme.LabelDisabledForeColor;
};
} else if(container is RadioButton) {
((RadioButton)container).ForeColor = ((RadioButton)container).Enabled ? theme.LabelForeColor : theme.LabelDisabledForeColor;
((RadioButton)container).EnabledChanged += (object sender, EventArgs e) => {
((RadioButton)sender).ForeColor = ((RadioButton)sender).Enabled ? theme.LabelForeColor : theme.LabelDisabledForeColor;
};
} else if(container is TrackBar) {
((TrackBar)container).BackColor = theme.TabBgColor;
} else if(container is Button) {
Button btn = (Button)container;
btn.FlatStyle = FlatStyle.Flat;
btn.BackColor = btn.Enabled ? theme.ButtonEnabledBgColor : theme.ButtonDisabledBgColor;
btn.ForeColor = theme.ButtonForeColor;
btn.EnabledChanged += (object sender, EventArgs e) => {
((Button)sender).BackColor = ((Button)sender).Enabled ? theme.ButtonEnabledBgColor : theme.ButtonDisabledBgColor;
};
} else if(container is ComboBox) {
ComboBox cbo = (ComboBox)container;
cbo.FlatStyle = FlatStyle.Flat;
cbo.BackColor = cbo.Enabled ? theme.ComboEnabledBgColor : theme.ComboDisabledBgColor;
cbo.ForeColor = theme.TextBoxForeColor;
cbo.EnabledChanged += (object sender, EventArgs e) => {
((ComboBox)sender).BackColor = ((ComboBox)sender).Enabled ? theme.ComboEnabledBgColor : theme.ComboDisabledBgColor;
};
} else if(container is GroupBox) {
((GroupBox)container).ForeColor = theme.LabelForeColor;
} else if(container is TabControl) {
((TabControl)container).BackColor = theme.TabBgColor;
} else if(container is TabPage) {
((TabPage)container).BackColor = theme.TabBgColor;
} else if(container is Panel && !(container is TableLayoutPanel) && !(container is FlowLayoutPanel)) {
((Panel)container).BackColor = theme.PanelBgColor;
} else if(container is DataGridView) {
DataGridView dgv = (DataGridView)container;
dgv.BackgroundColor = theme.ListBgColor;
dgv.ForeColor = theme.LabelForeColor;
dgv.GridColor = theme.LabelForeColor;
dgv.DefaultCellStyle.ForeColor = theme.LabelForeColor;
dgv.DefaultCellStyle.BackColor = theme.ListBgColor;
dgv.ColumnHeadersDefaultCellStyle.ForeColor = theme.LabelForeColor;
dgv.ColumnHeadersDefaultCellStyle.BackColor = theme.TabBgColor;
} else if(container is DataGridTextBox) {
((DataGridTextBox)container).BackColor = theme.TextBoxEnabledBgColor;
((DataGridTextBox)container).ForeColor = theme.TextBoxForeColor;
} else if(container is ListView) {
((ListView)container).BackColor = theme.ListBgColor;
((ListView)container).ForeColor = theme.LabelForeColor;
} else if(container is ToolStrip) {
((ToolStrip)container).BackColor = theme.FormBgColor;
if(container is ContextMenuStrip) {
((ContextMenuStrip)container).Opening += MonoToolStripHelper.ContextMenuOpening;
((ContextMenuStrip)container).Closed += MonoToolStripHelper.ContextMenuClosed;
} else {
((ToolStrip)container).RenderMode = ToolStripRenderMode.System;
}
foreach(ToolStripItem item in ((ToolStrip)container).Items) {
FixMonoColors(item, theme);
}
}
if(container.ContextMenuStrip != null) {
container.ContextMenuStrip.Opening += MonoToolStripHelper.ContextMenuOpening;
container.ContextMenuStrip.Closed += MonoToolStripHelper.ContextMenuClosed;
foreach(ToolStripItem item in container.ContextMenuStrip.Items) {
FixMonoColors(item, theme);
}
}
foreach(Control ctrl in container.Controls) {
FixMonoColors(ctrl, theme);
}
}
public class MonoTheme
{
public virtual Color TextBoxDisabledBgColor { get; } = Color.FromArgb(240, 240, 240);
public virtual Color TextBoxEnabledBgColor { get; } = Color.FromArgb(255, 255, 255);
public virtual Color TextBoxForeColor { get; } = Color.FromArgb(0, 0, 0);
public virtual Color ButtonDisabledBgColor { get; } = Color.FromArgb(180, 180, 180);
public virtual Color ButtonEnabledBgColor { get; } = Color.FromArgb(230, 230, 230);
public virtual Color ButtonForeColor { get; } = Color.FromArgb(0, 0, 0);
public virtual Color LabelForeColor { get; } = Program.IsMono ? Color.Black : SystemColors.ControlText;
public virtual Color LabelDisabledForeColor { get; } = Color.Gray;
public virtual Color ErrorTextColor { get; } = Color.Red;
public virtual Color GrayTextColor { get; } = Program.IsMono ? Color.Gray : SystemColors.GrayText;
public virtual Color DarkTextColor { get; } = Program.IsMono ? Color.LightGray : SystemColors.ControlDark;
public virtual Color LinkTextColor { get; } = Color.FromArgb(61, 125, 255);
public virtual Color ComboEnabledBgColor { get; } = Color.FromArgb(230, 230, 230);
public virtual Color ComboDisabledBgColor { get; } = Color.FromArgb(180, 180, 180);
public virtual Color FormBgColor { get; } = Program.IsMono ? Color.FromArgb(239, 240, 241) : SystemColors.Control;
public virtual Color TabBgColor { get; } = Program.IsMono ? Color.White : Color.Transparent;
public virtual Color PanelBgColor { get; } = Program.IsMono ? Color.FromArgb(239, 240, 241) : SystemColors.Control;
public virtual Color ListBgColor { get; } = Program.IsMono ? Color.White : SystemColors.ControlLightLight;
public virtual Color ToolStripItemBgColor { get; } = Program.IsMono ? Color.FromArgb(239, 240, 241) : SystemColors.Control;
public virtual Color ToolStripItemForeColor { get; } = Color.Black;
public virtual Color ToolStripItemDisabledForeColor { get; } = Color.Gray;
}
class DarkMonoTheme : MonoTheme
{
private static readonly Color TextColor = Color.FromArgb(255, 255, 255);
private static readonly Color MainBgColor = Color.FromArgb(49, 54, 69);
private static readonly Color HighlightBgColor = Color.FromArgb(69, 73, 70);
private static readonly Color HighlightDisabledBgColor = Color.FromArgb(47, 52, 57);
public override Color TextBoxDisabledBgColor { get; } = DarkMonoTheme.HighlightDisabledBgColor;
public override Color TextBoxEnabledBgColor { get; } = Color.FromArgb(69, 73, 78);
public override Color TextBoxForeColor { get; } = DarkMonoTheme.TextColor;
public override Color ButtonDisabledBgColor { get; } = DarkMonoTheme.HighlightDisabledBgColor;
public override Color ButtonEnabledBgColor { get; } = DarkMonoTheme.HighlightBgColor;
public override Color ButtonForeColor { get; } = DarkMonoTheme.TextColor;
public override Color LabelForeColor { get; } = DarkMonoTheme.TextColor;
public override Color LabelDisabledForeColor { get; } = Color.Gray;
public override Color ErrorTextColor { get; } = Color.IndianRed;
public override Color GrayTextColor { get; } = Color.LightGray;
public override Color DarkTextColor { get; } = Color.LightGray;
public override Color LinkTextColor { get; } = Color.FromArgb(61, 125, 255);
public override Color ComboEnabledBgColor { get; } = Color.FromArgb(69, 73, 78);
public override Color ComboDisabledBgColor { get; } = Color.FromArgb(47, 52, 47);
public override Color FormBgColor { get; } = DarkMonoTheme.MainBgColor;
public override Color TabBgColor { get; } = Color.FromArgb(45, 49, 54);
public override Color PanelBgColor { get; } = DarkMonoTheme.MainBgColor;
public override Color ListBgColor { get; } = Color.FromArgb(45, 49, 54);
public override Color ToolStripItemBgColor { get; } = DarkMonoTheme.MainBgColor;
public override Color ToolStripItemForeColor { get; } = DarkMonoTheme.TextColor;
public override Color ToolStripItemDisabledForeColor { get; } = Color.Gray;
}
}
}

View file

@ -0,0 +1,76 @@
using System;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Windows.Forms;
namespace Mesen.GUI
{
//Everything in here is a workaround for issues with dropdown menus in the latest version of Mono (5.18)
//Bug report:
//https://github.com/mono/mono/issues/12644
static class MonoToolStripHelper
{
private static HashSet<ToolStripDropDown> _openedDropdowns = new HashSet<ToolStripDropDown>();
public static void DropdownOpening(object sender, EventArgs e)
{
ToolStripDropDownItem ddItem = (ToolStripDropDownItem)sender;
if(!ddItem.GetCurrentParent().Visible) {
ddItem.DropDown.Close();
return;
}
HashSet<object> parents = new HashSet<object>();
parents.Add(ddItem.GetCurrentParent());
ToolStripItem parent = ddItem.OwnerItem;
if(parent != null) {
parents.Add(parent);
parents.Add(parent.GetCurrentParent());
while((parent = parent.OwnerItem) != null) {
parents.Add(parent);
parents.Add(parent.GetCurrentParent());
}
}
foreach(ToolStripDropDown openedDropdown in _openedDropdowns.ToList()) {
//Close all non-parent dropdowns when opening a new dropdown
if(!parents.Contains(openedDropdown.OwnerItem) && !parents.Contains(openedDropdown)) {
openedDropdown.Close();
}
}
_openedDropdowns.Add(ddItem.DropDown);
}
public static void DropdownClosed(object sender, EventArgs e)
{
ToolStripDropDownItem ddItem = (ToolStripDropDownItem)sender;
ToolStripDropDown parent = ddItem.GetCurrentParent() as ToolStripDropDown;
if(parent != null) {
Point pos = parent.PointToClient(Cursor.Position);
if(pos.X < 0 || pos.Y < 0 || pos.X > parent.Width || pos.Y > parent.Height) {
//When closing a dropdown, if the mouse isn't inside its parent, close all the parent, too.
parent.Close();
}
}
_openedDropdowns.Remove(ddItem.DropDown);
}
public static void ContextMenuOpening(object sender, EventArgs e)
{
//Close all existing dropdowns with no exception when a context menu opens
foreach(ToolStripDropDown openedDropdown in _openedDropdowns.ToList()) {
openedDropdown.Close();
}
_openedDropdowns = new HashSet<ToolStripDropDown>();
_openedDropdowns.Add((ContextMenuStrip)sender);
}
public static void ContextMenuClosed(object sender, EventArgs e)
{
_openedDropdowns.Remove((ContextMenuStrip)sender);
}
}
}

View file

@ -800,6 +800,8 @@
<Compile Include="Forms\Config\frmRecordMovie.Designer.cs">
<DependentUpon>frmRecordMovie.cs</DependentUpon>
</Compile>
<Compile Include="Forms\MonoThemeHelper.cs" />
<Compile Include="Forms\MonoToolStripHelper.cs" />
<Compile Include="Forms\NetPlay\frmClientConfig.cs">
<SubType>Form</SubType>
</Compile>