GTK+ Css ignoring margin [duplicate] - gtk

How can i make layout like this using CSS stylesheet for GTK app?
Here is example code:
#!/usr/bin/python
import gi
gi.require_version("Gtk", "3.0")
gi.require_version("Gdk", "3.0")
from gi.repository import Gtk, Gdk
# Main application window
# =======================
class MainWindow(Gtk.Window):
def __init__(self):
Gtk.Window.__init__(self)
self.connect("delete-event", Gtk.main_quit)
self.set_name("main-window")
# load style from file
cssProvider = Gtk.CssProvider()
cssProvider.load_from_path('style.css')
# get the default screen for the default display
screen = Gdk.Screen.get_default()
# new object which will store styling information affecting widget
styleContext = Gtk.StyleContext()
styleContext.add_provider_for_screen(screen, cssProvider, Gtk.STYLE_PROVIDER_PRIORITY_APPLICATION)
self.resize(200, 200)
# create box for another boxes
self.box = Gtk.Box()
self.box.set_name("box")
self.add(self.box)
self.box2 = Gtk.Box()
self.box2.set_name("box2")
self.box.pack_start(self.box2, False, False, 0)
self.text = Gtk.Label.new()
self.text.set_text('text')
self.box2.pack_start(self.text, False, False, 0)
self.box3 = Gtk.Box()
self.box3.set_name("box3")
self.box.pack_start(self.box3, False, False, 0)
self.text2 = Gtk.Label.new()
self.text2.set_text('text2')
self.box3.pack_start(self.text2, False, False, 0)
# Create and show window
win = MainWindow()
win.show_all()
Gtk.main()
Here is CSS stylesheet for this which will work in HTML
#box {
background: blue;
padding: 5px;
}
#box2 {
background: red;
margin: 5px;
}
#box3 {
background: green;
margin: 5px;
}
But result is:
Of course I can add padding/spacing values in python code, but only for horizontal gaps without nesting boxes. Can it be done without hardcoding, with css-only solution?

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.

Related

how to get rid of padding around Gtk.Image in Gtk.Box / Gtk.Grid in gtk4?

I'm trying to write a simple GUI using Gtk4 (in Python), but I'm having trouble with getting rid of padding (and I don't understand why the padding is there).
The goal is pretty simple - I need a Gtk.Grid showing a bunch of images with some basic metadata. AFAICS a good way to do that is Window -> ScrollWindow -> Grid -> Box -> (Image + Label). And in general this works, except that the images have a lot of top/bottom padding, so the labels have a lot of empty space around, which I don't like but can't get rid of it :-(
See this screenshot
Here's a simple example demonstrating this:
import gi
import sys
gi.require_version('Gtk', '4.0')
from gi.repository import Gtk, GdkPixbuf
def create_image(file_name, img_width, cssProvider = None):
info = 'file:' + file_name
box = Gtk.Box(orientation=Gtk.Orientation.VERTICAL)
# box.get_style_context().add_provider(cssProvider, Gtk.STYLE_PROVIDER_PRIORITY_USER)
# box.add_css_class('thumbnail')
box.set_hexpand(True)
# add image to top
pixbuf = GdkPixbuf.Pixbuf.new_from_file(file_name)
# calculate height to keep width and aspect ratio
img_height = pixbuf.get_height() * img_width / pixbuf.get_width()
image = Gtk.Image.new_from_pixbuf(pixbuf)
image.set_size_request(img_height, img_width)
# image.get_style_context().add_provider(cssProvider, Gtk.STYLE_PROVIDER_PRIORITY_USER)
# image.add_css_class('thumbnail-image')
box.append(image)
# add label to bottom
label = Gtk.Label(label=info)
# label.get_style_context().add_provider(cssProvider, Gtk.STYLE_PROVIDER_PRIORITY_USER)
# label.add_css_class('thumbnail-label')
box.append(label)
return box
class MainWindow(Gtk.ApplicationWindow):
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.cssProvider = None
# self.cssProvider = Gtk.CssProvider()
# self.cssProvider.load_from_data(b"""
#.thumbnail {background-color: white; color: black; border: 1px solid #ddd; margin: 5px; padding: 0; }
#.thumbnail-label { font-size: 12pt; margin: 0; padding: 0; }
#.thumbnail-image { margin: 0; padding: 0; }
#.green { background-color: #bfb; }""")
self.set_default_size(900, 600)
self.set_title("MyApp")
self.grid = Gtk.Grid()
self.window = Gtk.ScrolledWindow()
self.window.set_child(self.grid)
self.set_child(self.window)
idx = 0
prev = None
for idx in range(0,20):
# 4 columns
i = int(idx / 4)
j = int(idx % 4)
image = create_image('frog.jpg', 1920/4 - 10, self.cssProvider)
self.grid.attach(image, j, i, 1, 1)
class MyApp(Gtk.Application):
def __init__(self, **kwargs):
super().__init__(**kwargs)
self.connect('activate', self.on_activate)
def on_activate(self, app):
self.win = MainWindow(application=app)
self.win.present()
app = MyApp(application_id="com.example.GtkApplication")
app.run(sys.argv)
This needs an image called 'frog.jpg', e.g. this one.
The sizes are meant to work on 1920x1080, with 4 columns. I'm sure it could be done more dynamic (i.e. to work better with resized windows etc.), but I believe that's a separate issue.
I've tried a bunch of things, including styling using CSS, etc. (which is commented-out in the sample).
I also experimented with setting hexpand/vexpand on different widgets, not adding the label, and various similar things.
Apparently using Gtk.Picture instead of Gtk.Image solves the issue - with Picture there's no unwanted empty space/padding. Seems a bit confusing, considering Picture/Image are often used as synonyms. Maybe it's in the gtk docs somewhere, but I don't see it - certainly not without reading between the lines. I see some discussion of "natural size" but I don't see how'd that imply this behavior. Anyway, if others face the same issue, try using Gtk.Picture.

How to get rid of horizontal scrollbar in Material-UI TreeView?

When trying out the Material-UI basic example for Tree View (#mui/lab/TreeView), I do not know how to remove the horizontal scrollbar when using the overflowY: "auto" (The same effect even if I use overflow: "auto") option in the sx prop of the TreeView component. The horizontal scrollbar appears no matter how much space is available to the right. I want to keep the overflowY option in case of vertical overflow.
For example please see the basic tree view example from the official Material-UI page in StackBlitz or CodeSandbox.
How to remove the horizontal scrollbar when it's not needed?
This happens because the CSS classes .MuiTreeItem-content and its child .MuiTreeItem-label are set to 100% width by default, therefore, the .MuiTreeItem-content's 8px padding on x axis (also default) get in the way, adding 16px too many. You can easily override this by setting .MuiTreeItem-content's class padding to 0.
// ...
import MuiTreeItem from "#mui/lab/TreeItem";
import { styled } from "#mui/material/styles";
const TreeItem = styled(MuiTreeItem)(({ theme }) => ({
"& .MuiTreeItem-content": {
padding: 0,
},
}));
// ...
To remove the horizontal scrollbar completely you can hide the overflow over the X axis.
in css
.TreeView {
overflow-x: hidden;
}
or in jsx
<TreeView
sx={{ overflowX: "hidden" }}
...
>

Make GTK Entry box smaller

I am trying to make a GUI program in Julia using Gtk. My program includes a large number of GtkEntry boxes. However, I am running into space issues because the Entry boxes have a lot of internal padding around the actual characters. I would like to reduce, at least, the top and bottom whitespace. I have tried to use the setproperty!() function to change the height-request value, but that seems to be only able to make the box bigger, not smaller. Additionally, the margin, margin-top, etc. fields are all set to 0 by default. Again, I can make them bigger but not smaller.
Is this possible to fix? I have included below a minimal working example, a screenshot, and a Julia REPL output displaying the available properties.
Edit:
I have also tried using a css file (test.css) with the contents
entry {
margin-top: 0;
margin-bottom: 0;
padding-top: 0;
padding-bottom: 0;
}
Julia 0.6.0 code:
using Gtk
win = GtkWindow("Example")
sb = GtkGrid()
function sb_entry(label)
frame = GtkFrame(label)
entry = GtkEntry()
setproperty!(entry, :input_purpose, 2)
push!(frame, entry)
return frame
end
sb_rows = sb_entry("rows")
sb_cols = sb_entry("cols")
sb_row_off = sb_entry("row off")
sb_col_off = sb_entry("col off")
sb[1,1] = sb_rows
sb[2,1] = sb_cols
sb[1,2] = sb_row_off
sb[2,2] = sb_col_off
setproperty!(sb, :column_homogeneous, true)
setproperty!(sb, :column_spacing, 5)
setproperty!(sb, :row_spacing, 5)
push!(win, sb)
### begin edit (css)
screen = Gtk.GAccessor.screen(win)
provider = GtkCssProviderLeaf(filename="/path/to/test.css")
ccall((:gtk_style_context_add_provider_for_screen, Gtk.libgtk), Void,
(Ptr{Void}, Ptr{GObject}, Cuint),
screen, provider, 1)
### end edit (css)
showall(win)
if !isinteractive()
c = Condition()
signal_connect(win, :destroy) do widget
notify(c)
end
wait(c)
end
julia> sb_row_off[1]
Gtk.GtkEntryLeaf(editing-canceled=FALSE, name="", parent, width-request=-1,
height-request=-1, visible=TRUE, sensitive=TRUE, app-paintable=FALSE,
can-focus=TRUE, has-focus=FALSE, is-focus=TRUE, focus-on-click=TRUE,
can-default=FALSE, has-default=FALSE, receives-default=FALSE, composite-child=FALSE,
style, events=0, no-show-all=FALSE, has-tooltip=FALSE, tooltip-markup=NULL,
tooltip-text=NULL, window, opacity=1.000000, double-buffered, halign=GTK_ALIGN_FILL,
valign=GTK_ALIGN_FILL, margin-left, margin-right, margin-start=0, margin-end=0,
margin-top=0, margin-bottom=0, margin=0, hexpand=FALSE, vexpand=FALSE,
hexpand-set=FALSE, vexpand-set=FALSE, expand=FALSE, scale-factor=2, buffer,
cursor-position=0, selection-bound=0, editable=TRUE, max-length=0, visibility=TRUE,
has-frame=TRUE, inner-border, invisible-char=9679, activates-default=FALSE,
width-chars=-1, max-width-chars=-1, scroll-offset=0, text="", xalign=0.000000,
truncate-multiline=FALSE, shadow-type, overwrite-mode=FALSE, text-length=0,
invisible-char-set=FALSE, caps-lock-warning=TRUE, progress-fraction=0.000000,
progress-pulse-step=0.100000, primary-icon-pixbuf, secondary-icon-pixbuf,
primary-icon-stock, secondary-icon-stock, primary-icon-name=NULL,
secondary-icon-name=NULL, primary-icon-gicon, secondary-icon-gicon,
primary-icon-storage-type=GTK_IMAGE_EMPTY,
secondary-icon-storage-type=GTK_IMAGE_EMPTY, primary-icon-activatable=TRUE,
secondary-icon-activatable=TRUE, primary-icon-sensitive=TRUE,
secondary-icon-sensitive=TRUE, primary-icon-tooltip-text=NULL,
secondary-icon-tooltip-text=NULL, primary-icon-tooltip-markup=NULL,
secondary-icon-tooltip-markup=NULL, im-module=NULL, placeholder-text=NULL,
completion, input-purpose=GTK_INPUT_PURPOSE_DIGITS, input-hints=GTK_INPUT_HINT_NONE,
attributes, populate-all=FALSE, tabs)
entry { min-height: 0px; } allows it to be as small as possible. Adjust size as required.

Can't set CSS to specified widget in GTK+

I'm using Vala with GTK+ and now I'm trying to add custom CSS to specified widget.
I can add fe. backgroudn to GtkWidget but not for #sidebar
#sidebar { //It doesn't work
color: white;
}
GtkWindow { // It works
background-color: red;
}
I'm adding class to widget like that:
sidebar = new Gtk.Label("Hello");
sidebar.set_name("sidebar");
And it's changes color to GtkWindow, but not for this label.
Any ideas?
I haven't programmed in Vala, but you should add class to StyleContext.
This is in C
sidebar = gtk_label_new ("Hello');
gtk_style_context_add_class ( gtk_widget_get_style_context ("mysidebar"), sidebar);
Also, style "sidebar", is already defined in GtkStyle. You should change the "sidebar" in CSS into something else (sidebar is used by views, toolbar etc)
But if you persist, the syntax should be:
.mysidebar {
#anything
}

Remove space from Ui widgets that are not visible

function doGet() {
var app = UiApp.createApplication();
var flex = app.createFlexTable();
for (var i = 1; i<=30; i++)
flex.setWidget(i, 0, app.createButton('Button '+i).setId('Button'+i).setVisible(false));
app.getElementById('Button1').setVisible(true);
var submit = app.createButton('Submit');
app.add(flex).add(submit);
return app;
}
Produces this Ui.
How can we eliminate the empty space between the first visible button and the 'Submit' button?
The space is coming from the browser specific styling of the various HTML elements, which applies, for example, a 2px border-spacing to each hidden row. (I'm testing in Chrome; it may be different for other browsers.)
I'd suggest using a CSS reset to clear out all browser-specific styling. A simple one like this fixes your spacing issue (again, in Chrome):
div, table, tbody, tr, td {
margin: 0;
padding: 0;
border-spacing: 0;
border-collapse: collapse;
}