Now that we’ve finally rolled 3.0 out of the door… it’s time to hang up our hats and stop adding features to GTK+.
Err, nah forget about that – instead lets add cool stuff for an awesome 3.2 now !
As discussed in bug 636695, using GdkRGBA colors in GtkTextView is just about the last thing blocking us from completely deprecating GdkColor and moving GTK+ to an RGBA only api for colors.
But wait ! Implementing the RGBA color values on GtkTextTag is not a mere api cleanup, it also lets us…
Do stuff with GtkTextView that was not possible before
As you can see, now the foreground, background and paragraph background colors of text in the text view can be painted with translucency to the background of the GtkTextView, this particular demo connects to the “GtkWidget::draw” signal and simply fills in the background with checkers.
Of course most of the time you use a text view with a default solid white background for readable text, however this new feature does open up some…
New Possibilities
As usual, this installment of “GTK+ feature of the week” was brought to you by Openismus GmbH.
Currently the code is available for your compiling pleasure in the rgba-texttags branch.
What follows here is just my own personal brain storm…
Ideas for GTK+ hackers
While going over the GtkTextView code, which we all know is a fearsome animal not to be taken lightly or hunted in plain sight I came up with a bit of an idea of how we could start taming this beast. Text View code is not horrible really, it just hasn’t received much love over the years and needs a little tidying up.
Currently we have these components:
GtkTextBuffer and friends (GtkTextIter, GtkTextMark, GtkTextChildAnchor, GtkTextTag, GtkTextTagTable): This is all a part of the TextView’s data model, it’s very modular and it all makes sense. Sure, it’s much code but all of that code is well segmented and justified as far as I can see.
GtkTextBTree, GtkTextLine, GtkTextLineSegment: Some caching on the view side of things, all of this is private and caches things about how to render segments of text from the buffer model into the view, still quite modular code and probably very well thought out and well written.
GtkTextLayout: The heart of the beast where all the cached data is traversed and prepared for rendering, this is probably where most hackers are scared off… while most if not all of the code in there is well justified and needed, this code could probably be better organized and have more rich comments to guide the hacker who’s looking at this code for the first time.
Now the fun part:
GtkTextAttributes/GtkTextAppearance: This is something of a customized PangoAttribute the text appearance is a structure holding all the needed attributes for rendering a ‘segment of text’, a segment being a continuous string of glyphs that all share the same attributes… actually the GtkTextAttributes structure holds a GtkTextAppearance member, they could probably be merged into the same structure and the apis which handle this could be better defined (currently we have GtkTextTag modifying the attributes manually with exposed struct members and the like).
GtkTextRenderer (found in gtktextdisplay.c): This is the really fun part, this jem is actually a derived PangoRenderer class and takes over the actual rendering of the glyphs (the fact this jem already existed is why it was relatively easy enough to add RGBA rendering of the pango glyphs into the mix)… The GtkTextRenderer object inspects the custom GtkTextAttributes and uses these extended PangoAttributes to render the glyphs.
Now without digging into the ultra-complex innards of GtkTextLayout, I thought it would be a sweet idea to give GtkTextRenderer and GtkTextAttributes a bit more air time… these are for the most part internals of GTK+ and would not become part of the public api but… we could use the GtkTextRenderer to render text in GtkLabel and GtkEntry (and possibly elsewhere).
By working a little bit towards fine tuning the GtkTextRenderer and attributes to have a sane internal API and reusing it, we would already be able to render text from GtkLabel and GtkEntry using RGBA text attributes… at a relatively low cost. Also, a move in this direction would help demystify the text view code somewhat (at least hackers would be more familiar with GtkTextAttributes and GtkTextRenderer and would not have to consider those entities while looking at the rest of the huge code that is GtkTextView).
Anyway, just some food for thought for anyone who might be interested.
It’s been a few weeks and Glade has learned a few new tricks worthy of showing off.
Today’s release of Glade 3.9.2 was brought to you in a large part by our hero Juan Pablo Ugarte the Magnificent (and the crowd goes wild !)
Project widgets go off screen
Having the project widgets go off screen allows us to draw over the whole project widget hierarchy as a single canvas, resulting in added sexiness for Glade:
It also allowed us to simplify the code base to some extent where it comes to handling events on widgets, not to mention event handling on project widgets is more solid and fail safe now (GtkComboBox can finally be selected in the workspace; something that has been escaping us for years now).
Glade workspace gets a new look
Something I’ve wanted for a long time but never took the time to implement is to have a more coherent workspace and view of the project, recently I went and added notebook tabs to navigate through open projects and now our hero added the final touch by allowing the user to scroll through all the project widgets in the Glade workspace:
With this new touch to Glade’s UI, selecting widgets in the inspector treeview on the right cause the workspace to automatically scroll to the selected widget and ensure it’s visibility. In the future one of our plans is to add some drag’n’drop support to the workspace so that project widgets can be easily moved from one toplevel to another (however the new interface already makes it easier and more obvious for the user to cut/copy widgets and paste them in other toplevels).
GtkComboBoxText
In other, practical news, Glade receives some support for new widgets and objects, one of them being the GtkComboBoxText widget and sports a custom editor to make it easy for the user to create a simple dropdown list using GtkComboBoxText:
This little treeview here lets you easily type in the text for each item, delete items intuitively with the Delete key and reorder the items using the built-in Drag’n’Drop functionality of the treeview. Just type into the < Type Here > row to add new items. Click on the icon on the right to edit the i18n attributes (translator comments and context etc.).
GtkFileFilter and GtkRecentFilter
These filtering auxiliary objects have finally become more useful in Glade as well, now it’s possible to add a list of filename patterns or mime types for the filters (these objects can be set for GtkFileChooser and GtkRecentChooser widgets respectively).
For these editors I was able to just reuse the editor I wrote for editing GtkComboBoxText by simply disabling the translation features, I borrowed the < Type Here > editing paradigm from the signal editor since I thought it was a great way to offer lots of functionality while saving on screen real estate (no need for clumsy “Add” buttons in the UI)… it also makes for good consistency in Glade’s UI.
Glade is now a GtkApplication
This was just a weekend code spike which was surprisingly easy to implement. Using GtkApplication automatically makes Glade a single instance application practically for free. It also opens the door to opening files properly from whichever uris are supported by GIO. Currently Glade still only opens files that are on a local harddisk, but the only thing stopping us from opening remote files handed to us via the GFile is a hand full of logistics in the core (handling read-only mode, displaying a proper project name even if there is no local path to save it to; that kind of internal business logic).
So, Glade 3.9.2 is now available for download at http://download.gnome.org/sources/glade/3.9/, I only just published this tarball so the disks should still be warm: i.e. get them while they’re hot !
This is a general post on the Glade downlow, what’s been going on, and what is to be.
Lets start by discussing what’s the game plan for Glade and GTK+ 3.0, I’ve already detailed this in recent release mails and some bug reports it should also be discussed here.
Glade 3.8
This release of Glade will depend on GTK+ 2.24 and include libglade support, support for legacy catalogs such as libgnomeui and libbonoboui widgets and will still have the project conversion feature to convert your old libglade projects to use the GtkBuilder.
The theory behind releasing 2 Glades simultaneously is that Glade 3.8 will serve as a decent migration path to ease transition of projects transitioning from GTK+ 2 -> GTK+ 3, or from libglade -> GTK+ 2 -> GTK+ 3.
If an older project can be run with Glade 3.8, targeting GTK+ 2.24 and use no deprecated widgets, the glade file should then be ready to load up into Glade 3.10 and already usable with GtkBuilder in GTK+ 3.0.
Glade 3.10
This release will depend on GTK+ 3.0 and will not support libglade, will not support any of the old and deprecated widgets from the GTK+ 2.x line and will evidently, not have any conversion routine. Furthermore the libgladeui-2 core library will guarantee API and ABI stability so that IDE’s like Anjuta will never be broken by an upgrade to the underlying Glade core (not to mention, the code cleanup required to achieve an ABI stable core made the Glade sources considerably more readable, so it will be much easier from now on for you to contribute to Glade… which is what we’re counting on ;-)).
Both of these releases will be made simultaneously, we’re going to try our best to coordinate the release to be at the same date that GTK+ 3.0 is released.
Glade 3.8 and Glade 3.10 will be parallel installable.
$prefix/share/glade/catalogs/ (Catalogs for Glade)
$prefix/share/glade/pixmaps/… (Glade’s graphical resources including widget icons)
http://download.gnome.org/sources/glade/3.10/ (Will be the download location for 3.10 tarballs)
Glade things renamed
In light of the coming renames of ‘glade-3’ exec to be ‘glade’ and the install directory changes, we’ve recently renamed the actual product and repository information to simply be ‘glade’ instead of ‘glade3’.
http://git.gnome.org/browse/glade/ (Glade’s new git repository name)
https://bugzilla.gnome.org/browse.cgi?product=glade (Glade’s new bugzilla product)
Other Glade news
Over the last month or two I’ve been working hard on Glade, the current buglist right now has only 195 bugs on it, where only a month or so ago the list was somewhere between 300 and 400 bugs long. Lots of crashers have been fixed and lots of refactoring done as specially for Glade 3.10.
But besides all that under-the-hood goodness there are a couple things I can show off with screen shots (unfortunately though; I dont have a sexy theme installed for my GTK+ 3.0 sandbox… maybe someone can eventually fix that for me).
Glade loading progress bars
Alot of Glade files only contain a few widgets, or a few hundred widgets… but alot of the time Glade files can contain > 1000 widgets. Loading speed for these files can be slightly optimized but there is a limit to that optimization.
So to avoid freezing the UI completely we’ve added a progress bar so that you can continue your work and have some reliable feedback about when your project will finish loading up:
As you can see, a notebook tab is by far the best place to put a progress bar (I don’t think I’ve seen this done before but I think it looks just perfect).
Ok moving on to something a little more useful…
Glade allows you to edit GtkActionGroup
Using Juan Pablo Ugarte’s original menu editor, which has been reused to edit GtkTreeView and add GtkCellRenderers and has not failed me yet, I simply applied the code towards editing action groups and allowing the user to add actions to groups:
Users who are already familiar with this editor which we use more and more in Glade will find it very easy to setup an action group with this, I suspect.
Glade allows you to add tags to a GtkTextTagTable
This has been a long standing feature request, GtkTextTagTable is not directly useful in a Glade project however for programs that might use a GtkTextView; setting up a text tag table and symbolic text tags can be useful to apply text attributes to a region of a GtkTextView/GtkTextBuffer (i.e., lets say I want to call this paragraph “Important” and next month I want important text to be green and italic instead of purple and bold, I just go and edit the “Important” tag in the Glade file and I’m done).
Glade now supports editing the GtkToolPalette widget
To edit a GtkToolPalette we use the same editor as above, in the same way that we use it to edit GtkToolBar or GtkMenuBar, only in this case we support adding GtkToolItemGroups to a GtkToolPalette and then support adding GtkToolItems to GtkToolItemGroup.
Note here that the GtkToolItemGroup supports use of a custom ‘label-widget’, the above screenshot shows us adding a GtkFrame as the group’s label widget and then adding a label to it, of course it’s not a realistic example of how that might be used, perhaps someone would add a horizontal box with an image and label though.
New GladeSignalEditor
Johannes Schmid has written new code for Glade’s signal editor. Currently the UI looks just about the same as the old signal editor with some minor improvements. However the underlying code has drastically changed so that GladeWidget uses a delegate object to report the signals via a GtkTreeModel interface implementation. This was supposedly the missing link that will allow Anjuta to support Drag’n’Drop of signals from Glade’s signal editor into other active portions of Anjuta’s UI (I suspect probably to automatically create function prototypes in a given language for the signal callback dragged into the GtkSourceView or fancy things like that will happen).
Glade is starting on a Preview feature
The new preview feature by Diego Aurรฉlio Mesquita is in it’s preliminary stages but currently works to the specs that I originally wanted, mainly it runs out of process and uses a ‘glade-previewer’ program that responds to some very basic IPC commands sent to it via stdio to update itself at some appropriate times and to exit when requested. The main reason that I wanted this to be out of process is because there is always the possibility that GtkBuilder can crash while loading the xml, yes it’s highly unlikely but possible.
Some things we want to add to the preview feature:
Override desktop settings, it will be nice to allow the user to configure various desktop settings to see how the app will look and feel on different desktop configurations.
Override theme, this would allow the user to see how their app will look with a specific theme, it should be particularly interesting for example, if the application developed in Glade is targeting a specific handheld device and the user wants to know how the app looks with the hand-held’s theme before compiling it and installing it onto the said device (this can even be interesting for theme authors to see how their theme pans out with various glade files and widget configurations loaded).
Report errors reliably, if for any reason GtkBuilder has some problems with the loaded xml, the previewer program can report back the stdout and it can be displayed to the user in a warning window.
Icons
Dolean Samuel has started working on some new icons for the palette, this work was initiated by a google code-in task and we’re tracking that work in this bug. Hopefully Glade for GTK+ 3.0 will come with all the much needed icons as a result.
Well, I think this covers most of the recent developments on Glade.
As usual, Openismus deserves our thanks for tasking me full time on Glade.
This is one of the final installments on the GtkCellAreaTreeViewrefactoring saga, we’re having a GTK+ team on Tuesday where we’ll discuss this and other various things and finally, land the beast that is GtkCellArea.
Actually as a passing note, the GTK+ team meeting this week is potentially the last one we’re going to have before freezing GTK+ 3.0 apis. If there are glitches, problems, polishing work for GTK+ that you know is important and requires breaking API/ABI, it would be a good idea to present your issues at this meeting.
This is a bit of a surprise post I was not planning on writing but I was surprised by the success of the icon view refactoring work so I thought it would be a good idea to share this here.
Bonus GtkIconView Refactor
I’m pleased to say that the refactored GtkIconView actually works much better than the old icon view, all in ~1700 less lines of code.
A small example of this (without showing off configurable cell alignments and the potential of adding some custom GtkCellArea to your icon view to lay cells out in more custom ways) is already viewable in the tests/testiconview test.
It seems that the former icon view did not handle horizontal layout of cells very well:
As you can see the cells in this icon view are not aligned, the effect is “yuck”. However this was not noticeable when using a typical GtkIconView with only a constant size pixbuf on the left and variable length text on the right, the “yuck” starts to show through when using variably sized cell renderers on the left followed by more, unaligned renderers.
The new Icon View test in the same configuration:
Now all cells are correctly aligned horizontally no matter the size of leading cells.
You’ll have to just trust and forgive me for “Icon 5” and “Icon 6”, it actually does not appear that way. Only when using the screenshot tool and releasing the selected area it causes a rerender of the GtkIconView… it seems the screen capture is performed before the widget has time to finish re-rendering itself.
And that’s not all
The GtkIconView still doesn’t handle progressive calculation of rows like GtkTreeView does (it calculates the sizes of all icons in one go, sorry this refactor did not change that, we still have to take care of that).
However I was curious about the performance difference so I inserted a GTimer into the GtkIconView layouting procedure, which was pretty easy to analyze (since it does everything in one pass, it was pretty easy to compare).
Before refactoring (that is, requesting the size of each GtkCellRenderer individually and doing some complex calculations about where each renderer is placed inside the “icon” or “item”) I got these results:
After adding 10,000 items to the same test (that’s what the “Add Many” button does), the former icon view took 6.225222 seconds to initially layout the newly added items.
With the new icon view (after refactoring), adding the same 10,000 rows took 3.492693 seconds.
Once the sizes are initially requested for newly added rows processing is a bit cheaper, however the whole icon view needs to be relayed out every time it gets a new allocation.
With the old code, in my console after resizing the window pane (with > 10,000 items) I got:
relayout took 3.142941 seconds
relayout took 3.150152 seconds
relayout took 3.149025 seconds
With the new code for the same items I got:
relayout took 1.252735 seconds
relayout took 1.339084 seconds
relayout took 1.313939 seconds
relayout took 1.287726 seconds
So in conclusion, not only does the new icon view render cells with better alignments, not only does it do so in 1700 less lines of code… it also calculates the cell positions and lays out the icons in literally half the time it took with the old icon view code.
The icon view refactor work is now ready after ~2 days of work and available on the icon-view-refactor branch.
This is another installment on the GtkTreeViewrefactoringsaga. We’ve come a really long way with this and have the first phase of GtkTreeView rework almost 100% complete.
I’ve been working around the clock with our treeview master Kristian Rietveld, who worked out the initial integration of GtkCellArea into GtkTreeViewColumn and has been reviewing my patches against the treeview code every chance he gets… I know it’s been hard to keep up between meetings and other obligations but really, thanks a lot for your help on this Kris !
Some of the good news is:
GtkCellArea as an abstract class opens up the road for eventually more implementations, for instance tabular cell areas or areas that embed widgets can be developed and then used directly by GtkIconView, GtkTreeView, GtkComboBox classes without any need to change code in those classes.
GtkCellLayout widgets only need to interface with a single GtkCellArea instead of manage a list of cells, GtkCellLayout only requires that a layouting widget implement the GtkCellLayoutIface->get_area() virtual method and then does everything under the hood on the layouting widget’s behalf (this helps to remove lots of code from lots of classes).
GtkCellArea provides “cell properties” to define the relationship of GtkCellRenderers inside their area. Using this generic interface (just like GtkContainer “child properties”) GtkCellLayout’s GtkBuildable implementation implements a <cell-packing> custom tag and allows cell properties to be defined from the GtkBuilder UI format. (something we’ve been missing for a long time is a way to specify which cells “expand” in a GtkTreeViewColumn from GtkBuilder format).
Since GtkCellArea provides a generic way for handling events, and since recent developments of GtkWidget (i.e. widgets can be “drawn” and can be rendered ofscreen and such), its possible to implement a GtkCellArea subclass that contains and renders widgets (which can even handle events).
Also, GtkCellArea handles the driving of focus from renderer to renderer inside an area (as well as the painting of focus on the renderers), further reducing the workload of cell layouting widgets.
Finally, GtkTreeViewColumn has been reworked to replace it’s management of GtkCellRenderers with a single abstract GtkCellArea (not to mention, GtkTreeViewColumn struct members are now safely in a private data structure and GtkTreeView and Column code have a much cleaner “split”).
Some of the bad news is:
GtkCellArea replicates lots of api. For instance “cell properties” would really be GContainer child properties if we were to have a GContainer interface, “focus navigation” could really be implemented as a GtkFocusable interface that might not be a GtkWidget and finally even event handling could be implemented as a GtkEventable interface of sorts. However, after doing all of this and actually getting it to work, I dont think this api replication is such a bad deal. A GContainer interface providing child packing properties and object hierarchy outside of the GtkWidget hierarchy is something I’ve wanted for a long time however it’s just not exactly what I’ve been working on these days.
Another disappointment is that GtkTreeView has not been fully reworked to harness the power of the new height-for-width apis yet. We preferred a safer and more conservative development procedure for GtkTreeView: dump all the cell renderer man-handling in favor of an abstract GtkCellArea first and then leverage the height-for-width apis afterwards once we know everything is working.
Ideally I wanted GtkTreeView to actually calculate and allocate rows “height-for-width” with wrapping text and the works, all in one go but I also think it’s wise to do this stuff in comprehensible iterations… at least the framework is here and we don’t need to break any more api/abi at this point.
However, that being said, here’s a peek at some of the new things that are already possible with the new and improved GtkTreeView code without adding any fancy GtkCellArea subclasses or actually doing the height for width geometry.
Configurable Cell Alignments:
To show off cell alignments (and test some inner workings) I’ve updated a test that we already have in gtk+, here’s a look at the good old ./tests/testtreeedit in tact and as we are used to seeing it:
Ok nothing new here, moving along, for completeness sake (and just to express what exactly is “configurable” in terms of cell alignments), let’s look at an ugly configuration that no-one is likely to use:
Well, that’s an ugly configuration sure, but sometimes unaligned cells can be useful.
Here’s an example of how an unaligned cell can be more useful:
Ahh this is much better, I’ve always been annoyed at the alignment space between a variable length text renderer and an icon that logically belongs with the text. In this case we can have an icon that is “related” to the variable length text placed nicely to the right of it without any undesired space.
Vertically Oriented GtkCellAreaBox:
That’s right, vertically stacked cells inside a GtkTreeViewColumn was not possible before this. If you’ve used the popular bit torrent client “transmission”, you will find that they’ve achieved a similar look to the above image by way of implementing a custom cell renderer for their needs. With GtkCellAreaBox we should be able to cover most any desirable layout of cells inside an area without any custom code needed (with a GtkCellAreaTable, we can probably cover any conceivable layout that the user might desire without the need for any custom code).
Documentation:
Now that I’m tidying up and trying to close all of this work I’ve been doing over the past 2 months I’m doing the polish work and writing loads of documentation. The bulk of the documentation is not pertinent to users as it tries to discuss how GtkCellLayout widgets actually work (unless GTK+ users are into writing custom treeviews and the like, of course). Nevertheless having the documentation is probably a good step to help us keep track of how things are done inside GTK+.
Documentation for the GtkCellArea itself (the bulk of the documentation).
Documentation for GtkCellAreaContext (a context to store geometrical details for a collection of rows).
Documentation for GtkCellAreaBox (the first cell area implementation, an orientable box area).
Documentation for the GtkTreeMenu (GtkComboBox now delegates it’s menu related work to this new class, which I showed off already in previousposts).
Since the deadline for landing these new apis is getting dangerously close, I hope to land them very soon and then move on to giving GtkTreeView (and GtkIconView) real height-for-width capabilities afterwards, as this part wont need to entail any API breakage.
Coming up up next: Episode “lets land this code” and then the season finale, Episode “Height for width icon views and treeviews”.
This is the next installment on the subject of GtkCellArea hacking (which I introduced last week).
After a raw struggle with GtkComboBox and some final brain-wracking problem solving I was able to finally deliver a new and improved GtkComboBox with much more flexibility in terms of rendering cells.
Of course you’ve all seen what GtkTreeMenu does last week, so there’s not much left to show… except I did have to do a bit of problem solving to make sure it renders properly when cells are oriented vertically as well, even when their height is not fixed over a collection of GtkTreeModel rows (or, menu items).
The end compromise is that cell alignments (i.e. particularly the alignments of cells relative to the same cells in adjacent rows) can only be done when the collection of rows have a fixed size in the said orientation. If that’s not clear enough, take for example a treeview; in a treeview column every row gets the same width… in this case it’s possible to align cells with the same cell’s position above and below it in adjacent rows. However if the column cells are oriented vertically, space is not reserved vertically to match the space used in rows above and below… that can only be done if the treeview is set to use a fixed row height. (actually, it would be technically possible to do where only the last cell defines the difference in height, but that would be very tricky both for the GtkCellArea to handle as well as for the calling GtkTreeView widget, for reasons I wont get into in this post, in the end I think its a very logical tradeoff).
So, here’s some illustration of the combo box in action, delegating a large portion of the work to GtkTreeMenu.
GtkComboBox using GtkTreeMenu using GtkCellArea
For convenience sake, instead of adding lots of code to testcombo.c I just added a combo-box reflecting the same model and cell area already defined in testtreemenu:
Note in this shot that the combo box is taller than the contents but is still at it’s minimum size. This was always a requirement because the combo box should not start changing size depending on what item is selected (of course). However now instead of some jumbled iterative code in gtkcombobox.c, this is achieved by telling the cellview it packs onto itself to “fit-model”. The GtkCellView in turn assumes the job of properly requesting enough space to fit the entire GtkTreeModel for any selection it might receive.
Heres another basic shot with another row selected (with the tallest / longest wrapping text):
This row constitutes the tallest size for the combo box and is the reason for requesting so much space. Note that since we’ve set the third cell to “align” with adjacent cells, there is a gap between the second and third cell (Actually if you fire the test up yourself you will find the effect quite nice when using keynav or mouse scroller to navigate through items, since the last cell always stays aligned with previously shown selections).
But the part that hurt my brain the most to get right was…
Vertically stacked Cells
In the case of vertically stacked cells, alignments only work on the GtkCellView that is displayed on top of the combo box. Since the GtkCellView on top needs to request enough space for any row in the model, it can afford to allocate a fixed height to the underlying GtkCellArea which does the rendering (i.e. the height used to display every row of data is a constant height).
However a compromise is made for the menu items, since they naturally use a different height for every menu item the alignments are thrown away and ignored (expand space is also irrelevant here because a menu never receives more space than it requested).
As you can see here every individual menu item uses only exactly the height which it needs.
Now, of course this example is only here to show the potential of what can be done with new menus and combo boxes… the above example is not exactly a “nice” menu to render with cells vertically stacked, however vertically stacking menus might still be attractive.
Or better yet, if your really hard-core you could take it to the next level and write a tabular GtkCellArea and use that to render the cells in your combo-boxes and menus (for instance, a thumbnail on the left and then some vertically stacked text/icon on the right might be interesting).
Although at Openismus we were only particularly interested in achieving proper alignments of cells in combo boxes and menus (for the normal case of multiple cells rendered horizontally), GtkCellArea brings alot of new stuff into the game of rendering cells.
Stay tuned for the actual GtkTreeView using GtkCellArea to render its cells ๐
Update
Murray wanted a normal screen shot displaying how a basic combo-box drop down menu can be properly aligned so I went ahead and added a (simpler) test case to testcombo this time displaying aligned cells in the drop down menu.
Here we have a normal combo box displaying more than a single column and the cells are setup to “align” with cells in adjacent rows (note that the “align” child property of cells is meaningless for the first cell in a box, because it has no preceding cells it is always placed at the beginning of the allocation… however this might not be the case for right-to-left text direction, I still need to finalize the details of rtl layouting).
Good morning, afternoon, night Planet… I haven’t been regularly blogging and so sorry to start off with a weekend post but surely I will have some more posts following in the week.
This post is something of a follow up on this post, the height-for-width GtkTreeViews which never landed in GTK+ last summer are now on the verge of landing… after a lot of work internally refactoring GTK+ cell layouting algorithms, here’s a peek at what we’ve been doing at Openismus for GTK+.
What is GtkCellArea ?
You can read a detailed thread on gtk-devel-list where I originally proposed the new API, however I’ll include a brief overview here in this post.
Essentially GtkCellArea is an abstract container class for rendering GtkCellRenderers and is meant to abstract the layouting of cells in an area to be rendered onto a widget… one of the goals here is to completely centralize the cell layouting code in GTK+ so that widgets like GtkTreeView and GtkIconView don’t have to do the work of rendering individual cells manually. Another main goal is to provide an abstract coding interface to an area of cells; this opens up the road for cells to be rendered in different ways than your typical horizontally oriented list of cells that GtkTreeViewColumn currently does.
GtkCellArea “stuff” is composed of the following classes:
GtkCellArea: an abstract class to render cells in an area
GtkCellAreaContext: an abstract class to hold geometrical context of size requests and allocations over a series of GtkTreeModel rows.
GtkCellAreaBox: the first concrete GtkCellArea which is an orientable ‘box’, when oriented horizontally it behaves like a GtkTreeViewColumn
GtkCellAreaBoxContext: the GtkCellAreaContext created and used by GtkCellAreaBox.
Some things the GtkCellArea currently does:
Implements packing “cell properties” for GtkCellRenderers. GtkCellArea subclasses can declare packing properties to define how a cell is to be layed out in the area (this is analogous to how GtkContainer subclasses define child placement with its packing properties).
Provides GtkBuilder support to setup packing “cell properties” when <cell-packing> tags are specified in the children of a GtkCellLayout widget (also in the same way GtkContainer does it).
Provides a focus navigation interface analogous to GtkWidgetClass->focus so that cell area can navigate focus in a semantically similar way that GtkWidget does (this of course simplifies the work for widgets that render cells when navigating focus internally from cell to cell and area to area).
Provides cell-editing logic to bookkeep what is the currently edited cell and editing widget and a method to cancel the current edit, essentially a widget that renders cells only has to handle the GtkCellArea::add_editable/GtkCellArea::remove_editable signals.
Provides a method to handle events, currently this is only used to activate/start editing cells inside an area where only the area itself can know where the cell is positioned, but potentially it can provide a way for GtkCellArea to also render widgets into a treeview or another cell layouting widget (provided that the widget sends all the important events to the cell area in focus or at the pointer position).
So, enough of the terse technical jargon, lets move on to some snapshots ofthe GtkCellArea in action.
GtkCellArea in action
The following screen shots were taken from the treeview-refactor branch which includes the initial GtkCellArea work. The initial test case for GtkCellArea is tests/testcellarea; it’s compiled with a ‘mock treeview’ called cellareascaffold.c, without being scrollable or doing any of the fancy treeview features such as rubberband selction or drag-n-drop, I’m happy to say it gets the treeview basics done in less than 1500 lines of code.
Here is the first shot of what you see when you fire up testcellarea:
An interesting thing to note here is that the second GtkCellRendererPixbuf cellย (the icons) is not “aligned” while the third cell with the wrapping text is aligned, alignments with the GtkCellAreaBox are optional and implemented as a packing property of the area.
As the CellAreaScaffold testing widget does not scroll, I’ve just packed it into a GtkFrame to show how vertical space can be relinquished when given a wider allocation:
The GtkCellArea of course also properly handles configuration of expanding cells (also via a child “cell packing” property):
And of course, the alignment of every cell can also be configured:
The GtkCellAreaBox is also GtkOrientable:
Moving on to another test case, the GtkCellArea also implements internal keyboard navigation and the painting of focus on cells:
There is also the concept of “focus siblings” implemented in GtkCellArea, this lets you place focus on a cell’s neighbor while a given cell is in focus:
This lets you decide which cells in the area should also have focus when a given cell has focus… siblings of focusable cells also cause the focusable cell to activate when they are “clicked”:
The GtkCellArea as I mentioned above also makes cell editing much easier, the CellAreaScaffold only has to recieve the ::add-editable and ::remove-editable signals, when ::add-editable is invoked, it comes with a brand new editable widget and a GdkRectangle dictating the area which the editable widget should be placed, the editable widget needs to be a GtkContainer of sorts and just add the editable widget in that size and position at the right time and then remove it when ::remove-editable is invoked.
That pretty much concludes chapter one in the GtkCellArea saga, Kristian Rietveld, our GtkTreeView master has been working with me in parallel over the past weeks to get GtkCellArea integrated as the rendering delegate of GtkTreeViewColumn.
But that’s not all ! while I’ve been waiting on GtkTreeView integration I’ve got a head start on refactoring GtkComboBox to render it’s menus with the new framework, so far I’ve come up with GtkTreeMenu which will reduce the huge mess of a codebase that is GtkComboBox considerably… and also open up many new avenues by making it possible to generate menus from GtkTreeModel. The GtkTreeMenu code is available in the combo-refactor branch.
GtkTreeMenu Basics
GtkTreeMenu starts off with all of the rich benefits of GtkCellArea, areas can be rendered with various cells, various alignments and expand configurations, in various orientations etc. Here are some shots from tests/testtreemenu from the afore mentioned combo-refactor branch:
Now also we can align all the cells:
In the above screen shot we can observe the usefulness of GtkCellAreaContext, note here that every GtkTreeMenu (each submenu is itself a GtkTreeMenu) share the same GtkCellArea, however they each have a private GtkCellAreaContext which is used to request / align / allocate the size to use when rendering the area. In this way leafs of each tree get the same cell alignments however the overall width of each submenu can be different (cells in submenus are aligned with cells in the same submenu but not aligned with cells in parent menus).
Another detail of GtkTreeMenu is that it uses a GtkTreeMenuHeaderFunc to decide whether it should include a menu header for the parent item which had a submenu. This is important for combo-boxes since combo boxes need to be able to actually select every row in the GtkTreeModel including rows which have children:
Pie in the Sky
Whether or not GtkTreeMenu should be an exposed class or only an internal detail of implementing GtkComboBox is a question that we’ve been tossing around on irc these past days. Interestingly, with some more work in this area GtkMenuBar and GtkToolBar could also be rendered using cellviews and GtkCellArea… in other words the main application toolbar or menubar could be simply built off of a GtkTreeModel. Even fancier still, would be to have GtkApplication actually implement GtkTreeModel for its menu and toolbar actions and just build the application menus automagically, possibly easing the integration of menubars on OSX and making things make alot more sense in general. Ofcourse this kind of approach has a lot of details that need consideration, menu accelerator key and the like are one of them… but it does sound like a tempting approach to just get rid of most of the hand-built GtkMenuItem API (and also finally drop GtkUIManager in favor of using GtkTreeMenus…).
Those are just some ideas… that might inspire one of you hackers… to come and make GTK+ 3.0 more rocking than ever ๐
Stay tuned for more news on GtkTreeView refactoring !
It seems for the moment I will be unreachable by my gmail account, today google sent me a rude surprise:
Of course I could have suspected something like this was going to happen, I started receiving some similar warning splash screens from google this week in the disguise of “Protect your account, give us some alternative contact information”, they gave the “option” to provide a mobile phone number or alternative email account (of course I have an alternative anonymous hotmail account they can use to reactivate my account, the account at hotmail is still valid but I suppose for them its not enough).
Well I guess push has finally come to shove and their user interface provides me no alternative to reactivating my account other than to provide them with some mobile cell phone number.
This is crossing the line; obviously if my account had been hijacked the hijacker could just as well provide any cell phone number to have continued access to my account – the motive behind this harassment is plain to me and the way they are going about it is just plain sneaky.
No, google has no right to know who is the human being behind the persona that is “tristan.van.berkom@gmail.com”, they can speculate whatever they want while going through the contents of my account which I expect they are already sharing with a number of criminal organizations and governments…ย however I am not yet desperate enough to sign my own death warrant by volunteering them any further personal information than what traffic passes through my account.
If you value your anonymity on the internet… I think it’s about time to salvage your gmail content before they take it hostage from you too !
UPDATE:
@foobar:
Ofcourse I wrote them something via the “contact support” link, I’m waiting for a reply now we’ll see.
I may however find someone I trust to obtain an anonymous phone number for this purpose but that seems a little overboard.
I’ve been back for a few weeks now from taking a month vacation in Mexico with my girlfriend; heres a courtesy picture of us standing on top of the world… or at least on top of a pyramid ๐
… and the great news is that I’m continuing my employment with Openismus GmbH indefinitely, working specifically on GTK+ and GNOME.
So let’s recap on what’s been going on in GTK+ height-for-width resizing land since my last post.
Out of the patches that were available on the GTK+ native-layout branch, we landed the work on GtkExpander allowing the expander labels to wrap but still havent finished the work on wrapping text inside treeviews.
Similar to the GtkExpander implementation, we added support for wrapping/ellipsizing text in GtkFrame label widgets (to see this all in action you can try the ./tests/testheightforwidth demo from GTK+ git master at any time, I wont include shots for the GtkFrame here as it works pretty much exactly as the expander does).
So instead of running full till into another revision on the GtkTreeView height-for-width patches I took a different approach and moved right along to implement naturally sizing GtkComboBox (which we landed in GTK+ git master last week).
Some might wonder what is the relation between combo boxes and treeviews. The key point here is that they both end up using GtkCellRenderers to render content; the combo box by way of the GtkCellView widget. Since the cell renderer modifications for height-for-width GTK+ was a huge patch; implementing GtkComboBox first was a good excuse to pull that work in first and hopefully simplify the work that needs to still be done for treeviews.
So without further adieu here are some shots of how the combo box is performing in height-for-width land:
So far not too much to observe, the above combo box renders the liststore with a wrapping cell renderer, the combo box below renders the same liststore but uses ellipsizing cell renderers instead.
For the wrapping renderer, you need only specify the “wrap-width” which will be used as a minimum width request, if no “max-width-chars” was set on the cell renderer then the renderer will request the fully unwrapped text width as a natural width.
For ellipsizing renderers, you just specify the ellipsize mode and again the renderer will try to request the full text width as a natural size.
In this (above) shot we see the text unwrap fully when the combo is allocated sufficient space to display the underlying cell renders (and similarly the lower combo box need not ellipsize at this size).
And finally, at their smallest possible size the cell renderer text wraps up to the minimum width which was specified by the user/programmer via the GtkCellRendererText:wrap-width property.
Well once I got that far I thought it would be enough… until I clicked on a streached out combo box and found that the menu items were still requesting the height for the minimum cell width instead of the height for the menu’s allocated width (imagine a menu with random looking menuitem heights and text that doesnt quite fit the vertical allocation).
So we went on to implementing the natural size allocation in GtkMenu and the coresponding requests in GtkMenuShell:
Note in this screenshot some menu items wrap while some dont wrap, however they are all allocated the correct height.
Here at the minimum width all of the items are wrapping and they still get allocated a correct height.
And with combo boxes doing height-for-width requests.. finally we were able to close this nasty bug.
Enjoy ! … and stay tuned for another episode of wrapping/ellipsizing text in treeview widgets ๐
These last weeks I’ve been working on finishing the remaining bits of the height-for-width layout system for GTK+.
The GtkExtendedLayout interface, which has recently been renamed to GtkSizeRequest has been merged into GTK+ recently with only some basic features leveraging the new code (the new GtkSizeRequest interface allows widgets to trade height for width when negotiating their geometry, read this informative post for more details on how this works).
I’m going to be putting a branch together to be reviewed but here’s a sneak preview of what’s been added in height-for-width land.
Wrapping expander labels:
When the expander is allocated something smaller:
At it’s smallest size:
Ok ok I know expanders are not that exciting… I’m only posting them cause the screenshots have pretty colours in them…
Naturally sizing Tree Views
Ok this is the juice, as you might guess working anything new into the treeview code is … some kind of nightmare… so first the easy part… here are some ellipsizing cell renderers packed into some columns in a view to show how it naturally sizes:
And when you shrink it:
Wrapping Cell Renderers in Tree Views
Ok heres the wild stuff, first of all I have to say I’m not very proud of all the cute kittens I had to slay to get this done… that is to say that there is an interesting new problem for scrolled windows that parent height for width widgets that may result in deadly feedback loops that lockup your desktop… thankfully I found a trick to avoid it. It’s not that pretty and in the long term the hack should be replaced… with… well with something generally more kind to your kittens.
All that said… it does work and calculate row-height for width asynchronously in the background and only when columns are set to resize etc etc… hopefully this wont be much of a performance hit for views that handle large datasets.
The above shows the treeview at its full width; it’s packed in a scrolled window with automatic scrollbars.
When you shrink the view the row heights will be recalculated and redisplayed, the horizontal scrollbar of the scrolled window will only appear if the child view is allocated less than its minimum possible width.
This particular view can be resized very slim, just because the minimum width-chars of the renderers are not set and so they are all permitted to get pretty small:
While I’m happy to have got as far as wrapping text in treeview’s; that was only the hardest challenge of the GtkCellRenderer brand – after this there is still more to be done for GtkIconView, GtkCellView and consequently, GtkComboBox.
And of course, all of this fancy cell renderer stuff is going to have to pass review and all… but we’re getting there !
And I’m proud to say that all these recent developments have been brought to you by Openismus GmbH.