Description
Related:
Here's the problem
View.GetNormalColor ()
etc... are virtual
, allowing View
subclasses the ability to override colors used during draw.
However, if a SuperView
wants to influence the colors used by a SubView when they draw all it can do is:
- Set the SubView's
ColorScheme
property - This is problematic because now it's next to impossible to keep the SubView's colors in sync with the superview, esp if the superview is ALSO a subview of another view that's trying to do cool color stuff. - Try to depend on the fact that
ColorScheme
is a value type, held byView
as by-ref.
One of the motivations for having #457 is the instincts that none of this works very well.
In practice, this "architecture" (saying it was architected is generous) leads to things like:
Shortcut
having logic that looks like this in order to control how it's subviews appear in various situations (particularly HasFocus
):
if (HasFocus || highlight || ForceFocusColors)
{
if (_nonFocusColorScheme is null)
{
_nonFocusColorScheme = base.ColorScheme;
}
base.ColorScheme ??= new (Attribute.Default);
// When we have focus, we invert the colors
base.ColorScheme = new (base.ColorScheme)
{
Normal = GetFocusColor (),
HotNormal = GetHotFocusColor (),
HotFocus = GetHotNormalColor (),
Focus = GetNormalColor (),
};
}
else
{
if (_nonFocusColorScheme is { })
{
base.ColorScheme = _nonFocusColorScheme;
//_nonFocusColorScheme = null;
}
else
{
base.ColorScheme = SuperView?.ColorScheme ?? base.ColorScheme;
}
}
if (CommandView.Margin is { })
{
CommandView.Margin.ColorScheme = base.ColorScheme;
}
if (HelpView.Margin is { })
{
HelpView.Margin.ColorScheme = base.ColorScheme;
}
if (KeyView.Margin is { })
{
KeyView.Margin.ColorScheme = base.ColorScheme;
}
HighlightStyle.Hover
needing logic in View.Mouse
like this:
if (args.NewValue.HasFlag (HighlightStyle.Pressed) || args.NewValue.HasFlag (HighlightStyle.PressedOutside))
{
if (_savedHighlightColorScheme is null && ColorScheme is { })
{
_savedHighlightColorScheme ??= ColorScheme;
if (CanFocus)
{
var cs = new ColorScheme (ColorScheme)
{
// Highlight the foreground focus color
Focus = new (ColorScheme.Focus.Foreground.GetHighlightColor (), ColorScheme.Focus.Background.GetHighlightColo
};
ColorScheme = cs;
}
else
{
var cs = new ColorScheme (ColorScheme)
{
// Invert Focus color foreground/background. We can do this because we know the view is not going to be focus
Normal = new (ColorScheme.Focus.Background, ColorScheme.Normal.Foreground)
};
ColorScheme = cs;
}
}
// Return false since we don't want to eat the event
return false;
}
if (args.NewValue == HighlightStyle.None)
{
// Unhighlight
if (_savedHighlightColorScheme is { })
{
ColorScheme = _savedHighlightColorScheme;
_savedHighlightColorScheme = null;
}
}
Margin
needing to do crap like this:
public override ColorScheme? ColorScheme
{
get
{
if (base.ColorScheme is { })
{
return base.ColorScheme;
}
return (Parent?.SuperView?.ColorScheme ?? Colors.ColorSchemes ["TopLevel"])!;
}
set
{
base.ColorScheme = value;
Parent?.SetNeedsDraw ();
}
}
Solution
After fighting to get focused, highlight, etc... colors working will w/in Shortcut
, Bar
, etc... as part of Menuv2
I've come up with this concept as a partial fix for #457, focusing on the problem above:
Add cancellable events for each of Normal
, HotNormal
, Focus
, HotFocus
public virtual Attribute GetNormalColor ()
{
Attribute currAttribute = ColorScheme?.Normal ?? Attribute.Default;
Attribute newAttribute = new Attribute ();
CancelEventArgs<Attribute> args = new CancelEventArgs<Attribute> (in currAttribute, ref newAttribute);
GettingNormalColor?.Invoke (this, args);
if (args.Cancel)
{
return args.NewValue;
}
ColorScheme? cs = ColorScheme ?? new ();
Attribute disabled = new (cs.Disabled.Foreground, cs.Disabled.Background);
if (Diagnostics.HasFlag (ViewDiagnosticFlags.Hover) && _hovering)
{
disabled = new (disabled.Foreground.GetDarkerColor (), disabled.Background.GetDarkerColor ());
}
return Enabled ? GetColor (cs.Normal) : disabled;
}
public event EventHandler<CancelEventArgs<Attribute>>? GettingNormalColor;
This allows Shortcut
, for example to get rid of all the SetColor
stuff shown above and just do:
...
HelpView.GettingNormalColor += HelpView_GettingNormalColor;
}
private void HelpView_GettingNormalColor (object? sender, CancelEventArgs<Attribute>? e)
{
if (HasFocus)
{
e.Cancel = true;
e.NewValue = GetFocusColor ();
}
}
// Same for CommandView
// Since KeyView needs to invert HotNormal and Normal, we create a new class, `KeyView` that overrides `GetNormal/GetHotNormal` instead.
public override Attribute GetNormalColor ()
{
if (HasFocus)
{
return base.GetFocusColor ();
}
return base.GetNormalColor ();
}
I will be attempting to implement this as part of
This may also fix:
Metadata
Metadata
Assignees
Type
Projects
Status