Can I style GtkBox margin/padding with CSS only?
Not right now. GTK doesn't support margin
properties on its widgets, and it only supports padding
properties on widgets that draw a frame. (Which elements draw a frame can be a bit arbitrary, but Gtk.Box
and Gtk.Label
don't, so that's why your example doesn't work. You can fake it on any widget by putting it inside a Gtk.Frame
though.)
This blog post reveals that margin
and padding
are planned to be supported consistently on all widgets in the upcoming GTK 3.20.
Which GTK+ elements support which CSS properties?
Here is an overview of which CSS properties are supported as of GTK 3.8. The same information is mostly contained in the documentation for GtkCssProvider
, albeit not in table form.
Which widgets support which properties is a bit harder. It boils down to two kinds of widgets: those that are simple and only support basic styling (no borders or backgrounds), such as GtkLabel
; and those that support all properties, such as GtkFrame
. Wrapping a simple widget inside a GtkFrame
or GtkEventBox
, as you have discovered, is the usual way to turn one into the other.
The margin
property is not supported at all, and I'm told that this is a choice by the GTK developers. The thinking goes, as I understand it, that GTK is not HTML, and the layout of your widgets on screen should be governed by your code and not by CSS.
Update in GTK 3.20: The margin
CSS property is now supported across most or all widgets.
Problem styling Gtk::Box with CSS in gtkmm 3.10.1
A comment from @lb90 led me to a solution.
The commit that introduces the missing rendering of Gtk::Box background and border using style context, is here: https://gitlab.gnome.org/GNOME/gtk/commit/698488ddc4
Using the technique from said commit, I was able to work around the issue. I introduce a StyleBox class that derives from Gtk::Box and overrides the on_draw() handler. In on_draw() the background and border is rendered.
In the example code StyleTestWindow.cpp, just change mainbox's type from Gtk::Box to StyleBox.
StyleBox.h
class StyleBox : public Gtk::Box
{
public:
explicit StyleBox(Gtk::Orientation orientation = Gtk::ORIENTATION_HORIZONTAL, int spacing = 0) :
Gtk::Box(orientation, spacing)
{
}
virtual ~StyleBox() = default;
protected:
virtual bool on_draw(const ::Cairo::RefPtr< ::Cairo::Context>& cr) override
{
GtkWidget *widget = GTK_WIDGET(gobj());
GtkStyleContext *context;
GtkAllocation alloc;
cairo_t *ccr = const_cast<cairo_t*>(cr->cobj());
context = gtk_widget_get_style_context (widget);
gtk_widget_get_allocation (widget, &alloc);
gtk_render_background(context, ccr, 0, 0, alloc.width, alloc.height);
gtk_render_frame(context, ccr, 0, 0, alloc.width, alloc.height);
return Box::on_draw(cr);
}
};
Gtk3 Button - Reduce Padding of Internal Label
I reduced margin using style {padding: 0}
But if there is other button with bigger margin/padding then (in my example) Box()
resizes first button to use the same sizes. It may need different layout manager
import gi
gi.require_version("Gtk", "3.0")
from gi.repository import Gtk
from gi.repository import Gdk
class ButtonWindow(Gtk.Window):
def __init__(self):
Gtk.Window.__init__(self)
screen = Gdk.Screen.get_default()
provider = Gtk.CssProvider()
style_context = Gtk.StyleContext()
style_context.add_provider_for_screen(screen, provider, Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION)
#provider.load_from_path('app.css')
#provider.load_from_data("#small {margin: 0; padding: 0;}".encode())
provider.load_from_data("#small {padding: 0;}".encode())
hbox = Gtk.Box()
self.add(hbox)
button1 = Gtk.Button.new_with_label("Padding 0")
button1.set_name('small') # assign CSS with padding 0
hbox.pack_start(button1, False, False, 0)
#button2 = Gtk.Button.new_with_label("Normal padding")
#hbox.pack_start(button2, True, True, 0)
#button2.set_name('small') # assign CSS with padding 0
win = ButtonWindow()
win.connect("destroy", Gtk.main_quit)
win.show_all()
Gtk.main()
{padding: 0}
Second button (with standard padding) is higher and automatically it adds top/bottom padding to first button.
Both buttons with {padding: 0}
Gtk Popover Menu is not using the default padding
Nautilus uses a combination of margin and padding for its Popover.
I hope the screenshot demonstrates it. The first is the Popover as it is with your code. The second one has a margin but as you can see, the selection directly touches the text. Therefore the third Popover has margin and padding.
The margin can be set with widget.set_property('margin', 10)
and the padding with a css file.
How to change size to GtkWidget with CSS?
You can't. Sizing and positioning are layout properties, and not under the remit of the theming machinery, which is exposed via CSS.
If you could change sizing and position via the theming infrastructure, you'd be able to change the way applications are presented; while this works fine for web pages and the CSS Zen Garden, it does not map to desktop applications.
At most, you can specify CSS margins and padding on top of the existing preferred size of a widget.
If you want to set the minimum size of a GtkWidget
, use gtk_widget_set_size_request() from your application code instead.
Related Topics
Inverting a Dictionary with List Values
Scrape Multiple Pages with Beautifulsoup and Python
Plotting 3-Tuple Data Points in a Surface/Contour Plot Using Matplotlib
Interpreting a Benchmark in C, Clojure, Python, Ruby, Scala and Others
Separate a Row of Strings into Separate Rows
How to Link Pycharm with Pyspark
What Is the Perfect Counterpart in Python for "While Not Eof"
Splitting a String into Words and Punctuation
The Difference Between Sys.Stdout.Write and Print
Pyqt: No Error Msg (Traceback) on Exit
Generating HTML Documents in Python
R Markdown: How to Make Rstudio Display Python Plots Inline Instead of in New Window
What Are the Python Equivalents to Ruby's Bundler/Perl's Carton
Why Is Ruby More Suitable for Rails Than Python
How to Convert a Dictionary into a List of Tuples
How to Get Reproducible Results in Keras
Handling Backreferences to Capturing Groups in Re.Sub Replacement Pattern