picoe / Eto

Cross platform GUI framework for desktop and mobile applications in .NET
Other
3.67k stars 335 forks source link

GTK2 ignores Button backgroundcolor #382

Open oliverdarvall opened 9 years ago

oliverdarvall commented 9 years ago

Build 0357 Pre-release:

Button S1 = new Button() { BackgroundColor = new Color(0, 0, 0), Text = "1", ToolTip = "Shot 1" }; S1 always has a grayish background color, if set as above or in a style

kivarsen commented 9 years ago

I recently struggled with this as well. (Had trouble setting the background color of a button when working directly in Gtk#. Looked through the Eto code to see how it was done there, and discovered that it didn't seem to work reliably in Eto either.)

Just a few notes for Curtis based on my recent experience with this issue, in case they help with the Eto implementation:

As I'm sure you know, it is surprisingly hard to reliably set widget background colors in Gtk. For example, text input controls, labels, and buttons all require different techniques. This is further complicated by theme engines in Gtk, which can ignore requested colors and draw widgets in their own way. (One example is the "wimp" engine used to draw native-looking controls in MS Windows. It seems to always use the colors from the current Windows theme to draw the button. Another example that's easy to imagine is the "pixmap" engine, which I believe would just draw a widget based on a specified image rather than painting with a specified color.)

One option to work around this is to create a custom style for a "colored" button, which disables any engines that would be used to draw that button. For example, somewhere in Eto's startup you can call Gtk.Rc.ParseString() with something like this:

style "no-engine" { engine "" {} }

Apply this style to the widget with Name=CustomStyle

widget "*.CustomStyle" style "no-engine"

Then, when you have a button with a custom background color, you set Button.Name to "CustomStyle". Now it will be drawn with Gtk's default drawing engine, which should pay attention to things like ModifyBg().

The main problem is that the default button style will look very out of place compared to other themed buttons in the application. So, I took another approach in Gtk, which is to pack a Label inside an EventBox inside a Button, set the text color of the Label, set the background color of the EventBox, and try to make the EventBox extend all the way out to the boundaries of the button. Here's some sample code -- feel free to adapt this in Eto if you want. One issue at the moment is that the dotted box to indicate the button has focus doesn't have any space around it, at least in Windows.

// This Label contains the button text. Label buttonLabel = new Label("Button with colored EventBox");

// Need to set the Normal, Prelight, and Active colors or else // the button text will revert back to its default color when // the mouse hovers over or clicks the button. buttonLabel.ModifyFg(StateType.Normal, new Gdk.Color(240, 0, 0)); // Normal appearance buttonLabel.ModifyFg(StateType.Prelight, new Gdk.Color(255, 0, 0)); // Make this a bit lighter when the mouse hovers over buttonLabel.ModifyFg(StateType.Active, new Gdk.Color(220, 0, 0)); // Make this a bit darker to indicate a click

// Later on when we remove the button's X/Ythickness the button will // shrink down to the size of the label. Add some padding around the // label to get it back to a more sensible default size. // TODO: Figure out how big the button originally would have been // and set the padding to compensate. buttonLabel.SetPadding(2, 2);

// We can't set the background color of a Label directly since it is // windowless, so we pack it in an EventBox and set its background // color instead EventBox labelContainer = new EventBox(); labelContainer.Child = buttonLabel;

// Again, need to modify (at least) these three color states labelContainer.ModifyBg(StateType.Normal, new Gdk.Color(248, 248, 0)); // Normal appearance labelContainer.ModifyBg(StateType.Prelight, new Gdk.Color(255, 255, 0)); // A bit lighter labelContainer.ModifyBg(StateType.Active, new Gdk.Color(230, 230, 0)); // A bit darker

// Create the actual button and pack our EventBox-with-Label inside Button buttonWithEventBoxLabel = new Button(labelContainer);

// Set the thickness to 0 so that the EventBox color extends (almost) all // the way out to the edges of the button. buttonWithEventBoxLabel.ModifierStyle.Xthickness = 0; buttonWithEventBoxLabel.ModifierStyle.Ythickness = 0;

cwensley commented 9 years ago

@kivarsen thanks for the info!! I've never applied styles like that before so it's interesting how that works. I don't know at this point which is better: Having a control with incorrect style but correct background color, or ignoring the background color. We could certainly add a setting to allow you to choose, but neither seem like a good choice to me.

It is unfortunate that Gtk has these problems with setting colors of widgets, and it doesn't seem like Gtk3 is much better as I've had similar difficulty setting background colors for some controls there as well.

cwensley commented 9 years ago

One thing to also keep in mind, is some themes use the color specified in a gradient, so it would actually use the color but not necessarily appear to. Both OS X and on Ubuntu will show only minor differences when using a grayscale background color using Gtk2.

If you run the Eto.Test.Gtk2 application on ubuntu and run the Control Fonts & Colors sample, I am having no problems setting the background colors for a button.

@oliverdarvall what OS are you running this on? I have heard in windows it completely ignores the colors you set, so other than doing what @kivarsen suggested by using Eto's styles there may be no other options.

kivarsen commented 9 years ago

@cwensley Just ran a couple quick tests with Eto.Test.Gtk2 on a few distributions. The background color does indeed seem to work fine on Ubuntu 14.04, but it does not work in Linux Mint 17 (both the Xfce and Cinnamon editions). Screenshots attached. I've also included a couple screenshots showing Gtk buttons using the techniques I described earlier.

Eto.Test.Gtk2, Ubuntu 14.04: ubuntu1404

Eto.Test.Gtk2, Linux Mint 17 Xfce: mint17

Label in EventBox in Button, Ubuntu 14.04 (ignore the "Button with ColorLabel", which was another experiment): ubuntu1404_eventbox

Label in EventBox in Button, Mint 17: mint17_eventbox

Button with theme engine disabled, Ubuntu 14.04: ubuntu1404_customstyle

Button with theme engine disabled, Mint 17: mint17_customstyle

cwensley commented 9 years ago

@kivarsen thanks for the screenshots! EventBox method seems to be the best of those options, though it overrides the theme so if that method were to be used we'd only want to add the EventBox when the BackgroundColor is set.

It won't help any of the other controls though, I'm not sure what hacks we'd have to make for all those to work. I'll have to install Mint to see how the other controls react when changing the background color when I get some time..