Yesterday talks were wicked interesting, especially the Alexis talk about the new animation framework was really breathtaking.
Aaanyways, this is kinda a synopsis of what i talked about in my part during
the talk session yesterday at Tokamak, slides
here,
it’s quickly written in few minutes, so the english it’s a total horror,
but i feel it could be kinda interesting anyways 🙂
Themes
Pretty much everything you see in Plasma is based on SVG graphics,
this means that you have a really high degree of customizability
controlled by the Plasma theme. This also means that compared to
classical Qt themes the entry barrier is significantly lower, because
of course you have to be a good designer to make one, but not a
programmer, while to do a Qt theme you have to be both and this is a
really really rare thing.
Also, since themes are pure graphics without binary code they are
completely platform independent so they can be distributed trough the
GHNS framework.
Being vector graphics, we can display them without problem from
very little screen to huge monsters when we will have 600dpi screens
that won’t be a problem, specially for the theme elements based on
the FrameSvg concept.
From a programmer point of view using the theme graphics is quite
easy too, because the two main classes that manages Svg themes (Svg
and FrameSvg) are very abstracted, so you won’t have to bother that
the graphics is actually a Svg.
Plasma themes will be installed under your KDE installation prefix
under share/apps/desktopthemes. The filesystem structure inside the
theme has got two main subfolders: widgets, meant for element
drawn on canvas and dialogs, meant for elements that are
actually a top level window. There are two particular and optional
subfolders: the first is locolor, that will have the same two
widgets and dialogs subfolders meant to be used when the theme is
displayed on screens with less than 16 bit color depth.
The other folder is called opaque and has replacements for
the elements that are a top level widget when the desktop effects are
turned off, that’s because in this case we won’t be able to have a
semitransparent window, so we won’t be able to have luxuries like
antialiased borders or drop shadows, if you have a rounded border
there you should use the good old pixelart tecnique from the 80’s.
In order to load an Svg from the current theme is sufficient to
use the setImagePath() function of Plasma::Svg, where you don’t have
to worry neither of the path of the theme or the svg or svgz
extension, so something like “widgets/background” will suffice.
If you are writing a scripted applet you can also include the
graphics alongside the applet code and distribute everything in a
single package, from a javascript applet for instance it will be
sufficient to call the function plasmoid.findSvg(“foo”) and the
proper foo.svg file will be located for you.
That said however now i have to get a bit annoying with some
advices: you should be really really careful when you add custom
graphics in your applet, both when you install it alongside your c++
applet and also when you embed it in the package of your scripted
applet, because your additional graphics must work with as much
themes as possible, and this is an hell lot difficult. You should at
least try it with both a dark and a light theme, but in the end… if
you want to do that, think again 🙂
Boring implementation details
Usually in your applet won’t have to directly paint Svgs, because
if you just use the default plasma widgets you’ll have the svg
painting done for you, but if you have to draw some svg elements you
have to know two classes: Plasma::Svg and Plasma::FrameSvg.
The mighty machine that manages all the svg painting in Plasma is
the Plasma::svg class, that internally uses the QSvgRenderer class,
but optimizes it as much as possible: in the context of the whole
Plasma application for each svg file we get an unique shared svg
renderer and the rendering result is saved to disk thanks to a
KPixmapCache, that can avoid the creation of renderer to a satisfatry
degree: in the second plasma start won’t be created a single renderer
until you resize something, saving a bit of startup time and some
megs of ram.
The most important functions you are interested if you want to use
a Svg are its several paint functions (overloaded with QPoints or
QRects as parameters) the already mentioned setImagePath() resize()
and various functions to access the svg sub elements like
hasElement(), elementSize() and elementRect().
The other class used in plasma to render Svgs works at a slightly
higher level of abstraction and is Plasma::FrameSvg. Usually widgets
are mostly rectangular things, but even if Svg is scalable that
doesn’t mean the result will look pretty, take a look at the slides
example for instance, where a
default applet background is heavily vertically stretched, so the
horizontal borders become thicker that the vertical ones, and to make
things worse they usually aren’t even an integer number of pixels
making the result to look really blurred.
So, what is there in the default applet background? We can see
there are actually 9 pieces: the corners, the edges and the central
part (called with a great stretch of fantasy center, top, topleft,
topright, left,right,bottom, bottomright and bottomleft). When the
thing will get painted not all elements will be scaled, it’s
important that the corners won’t be never ever scaled, while the
horizontal edges will be scaled only horizontally and similarly the
vertical edges will be scaled only vertically, while the center
element will scale freely.
From a boring code standpoint FrameSvg inherit the Svg class, so
all the stuff that is available in Svg is available in FrameSvg too,
but with the difference that you want to resize the image with
resizeFrame() that uses the method i talked before and you’ll paint
the correctly resize Svg with paintFrame(), while paint() is still
useful to paint single elements in the Svg. Also a single Svg can
contain multiple series of 9 elements, with the names differentiated
by a proper prefix, that can be chosen with the setElementPrefix()
function.
> Pretty much everything you see in Plasma is based on SVG graphics, this means that you have a really high degree of customizability controlled by the Plasma theme.
Not really. It’s just barely higher than for a bitmap-image-based theme. It’s a lot less flexible than a C++ theme, such as the Qt styles:
* It can’t use C/C++ libraries to draw items. So making something like QGtkStyle for Plasma (i.e. calling the GTK+, Qt or whatever theming API to do the actual drawing) is impossible.
* The theme has little to no influence over the placement of subitems. For example, a Qt style can decide where to put the buttons of a QScrollBar (some themes put both buttons above or below the scrollbar, there’s also the “up, scrollbar, up repeated, down” layout). A Plasma theme can’t do the same for a Plasma::ScrollBar, it can only change the images of the buttons. A lot of the look&feel is actually hardcoded in Plasma.
* A Qt style has access to a lot of state information through the QStyleOption mechanism, and can even query the widget directly for more. For example, it is possible to draw something completely different for a pushbutton with an icon or for a pushbutton with text.
* Code can actually work with pixels while still being able to adapt to changing dimensions (as your sizes can be arbitrary formulas), so you can get a better look than with a resized SVG in many cases.
* All the above issues also imply that matching the look of something else exactly (i.e. to implement not only something like QGtkStyle, but even something like Cleanlooks or Plastique) is practically impossible.
* KWin window decorations are even more powerful than Qt Styles, they can add arbitrary buttons to the window decoration and act on them with custom code. Plasma themes can do no such thing for Plasma applets (and no, I won’t call them widgets 😉 ).
Case in point, here’s how I’d like Plasma applets to look in my theme: They should look like a toolbox (mini-window), with a small title bar (smaller than for a window, it should be clear it’s not a window) containing the name of the applet and having a [X] close button at the right (which actually deletes the applet, of course) and drag borders which resize the applet just like a window. (The current Plasma resize mechanism is ugly.) Inside, I want the widgets (pushbuttons, scrollbars, tabbars etc.) to be drawn using my regular Qt 4 theme, Quarticurve (a port of Bluecurve), or at least to look indistinguishible from it. Can I do that with SVG themes? If yes, how? (And yes, this is really a rhetorical question, I’m fairly sure it’s impossible, though I’d be happy to be proven wrong.)
Oh, and if you don’t understand the above description, I can do a mockup of it, though my drawing skills are not at the level of my coding skills, so the mockup will probably not be pixel-perfect, I could do much better in code. 😉 (Yet another reason why I think SVG is not for everyone.) And thus I’ll only do it if actually needed.
> This also means that compared to classical Qt themes the entry barrier is significantly lower, because of course you have to be a good designer to make one, but not a programmer, while to do a Qt theme you have to be both and this is a really really rare thing.
But this comes at a huge price in flexibility.
IMHO Plasma really needs support for C++ themes. Unfortunately, retrofitting it into an API designed around SVG all over the place is going to be hard. 🙁
Oh, and I forgot one detail in the description of my theme idea: applets should of course only have the title bar and drag borders if they’re on the desktop, not if they’re on a panel.
Yes, it is, and it was kinda a conscious design decision, because two really important things we wanted to achieve were, complete architecture independence, so download with get hot new stuff, without any building involved and the ability for artists to draw their own theme with zero help from a coder.
that said, some of the elements are actually drawn by a custom qstyle, so it’s not excluded that in the future more items will be drawn by that and it could be exposed and changed by a custom one.
but i kinda doubt that.
And how many times did Kicker mimic the Qt theme exactly? What about Superkaramba?
I personally prefer Plasma over these two any day: the colours match, configuration is consistent, I don’t have to spend time how to change each plasmoid individually…
With the, “Desktop Theme Details” section in System Settings, I can also change the look of just about any element to an SVG file that I’ve made. I couldn’t do that with Kicker.