cat /dev/maxilys

A glance in the mind of a KDE/Linux developer to see how ideas turn into code.

2006-07-27

KDE: Beauty of code

A challenge! I want a challenge, something that would be difficult to code! To make Serenity react to a click on a label was too easy.

Less than 20 lines of code and that was it. A click on a label in front of a combobox and the drop-down menu appears, another click and the menu closes itself. A click on a label in front of any editable widget and here comes the cursor at the end of the contained text. Amazing! ;-) Well, in fact, that's Qt which is amazing.

Just to satisfy my developer's hypertrophied ego, here are the lines to put in the event filter:


if ( ::qt_cast<QLabel*>(obj) && (ev->type() == QEvent::MouseButtonPress) )
{
QMouseEvent* what = dynamic_cast<QMouseEvent*>(ev);
if (what->button() != Qt::LeftButton) // Accept only the left button.
return false;
QLabel* label = static_cast<QLabel*>(obj);
if (! label->buddy()) // No buddy, do nothing.
return false;
QWidget* buddy = label->buddy();
if (! buddy->isWidgetType()) // Safety measure.
return false;
buddy->setFocus(); // Set focus for all editable widgets.
//
// Don't click on a slider!
if (! ::qt_cast<QSlider*>(buddy))
{
// Fake a mouse click for non-editable widgets.
QMouseEvent me(QEvent::MouseButtonPress,
QPoint(0,0),
Qt::LeftButton, Qt::LeftButton);
QApplication::sendEvent(buddy, &me);
// Don't forget to release that button!
me = QMouseEvent(QEvent::MouseButtonRelease,
QPoint(0,0),
Qt::LeftButton, Qt::LeftButton);
QApplication::sendEvent(buddy, &me);
}
return false;
}


For those who understand this kind of stuff: Don't forget to polish the QLabel widget. And if I explicitely forbid a fake click on a QSlider, that's because such a click brings the slider to the far left of its groove.

Serenity made a new step in the direction of the Fitts' law. I don't know if such a thing could be implemented in KDE. I mean, it's possible to implement it in KStyle but there are some issues. Not all labels are linked to the widget they introduce and when they are, it means they must have a keyboard shortcut. That problem of liaison is easy to solve, it depends only on the interface. This problem of shortcuts is more complex. Only a limited amount of them can exist at the same time in a dialog. To make things easy, it should have to be possible to connect a label with a widget without implying a shortcut. Qt doesn't allow this. It only happen when it falls short of letters to use as shortcuts. I wouldn't call that an optimal solution.

This discussion must be brought to a "higher level". Once you've started to click on labels within KDE, you will also realize that it doesn't work within the gnomish applications, even with the GTK-Qt engine. Another problem of inconsistency on the Linux desktop...

I keep this feature as an experimental feature that belongs only to Serenity for the time being. If other style developers adopt it --and improve it-- then maybe a revolution would start. ;-)

2006-07-26

KDE: Resistance... again!

I couldn't resist to the urge to stick my nose back into Serenity. I said I wouldn't touch it so often after version 1.0. I almost kept my promess...

There was that tiny detail I couldn't get out of my mind. Somebody released a style where the arrows of the spinwidgets are disabled when the spinwidget has reached its minimal or maximal value. I didn't remember who or what style but last time I updated QtCurve, I saw its spinwidgets.

I never use QtCurve but it's part of the few styles I update whenever a new version is released. So I can keep on digging into recent sources. Although I don't do it much any more. Serenity is like me, it has its oddities that can't be found anywhere else... and digging into Qt and KDE is much more what I need now. Whatever...

Well, QtCurve's spinwidgets. I looked into the sources, found what I wanted, make a little detour into Qt documentation and that was it. No special trick is required. Serenity just asks to Qt if the arrows are enabled and it draws them accordingly. So easy... ;-) ...when you know what you're looking for.

I did this last week. Yesterday I launched the GIMP and lovingly draw a new icon theme for Serenity's window decoration... pixel by pixel, just the way I like to do it. :-D I didn't add it to the sources yet. All I can say is that it was one of those ideas I've kept on the back of my head for a long time: Letters as symbols.

Serenity already has mathematical symbol as icons --in its eponym icontheme. So I drew letters in a Times style. Some letters were easy to choose. "X", "?" and "S" for, respectively, the close, help and sticky buttons. I chose a little caps "A" and a little caps "B" for the "Keep above" and "Keep below" buttons. I put "A" to the top and "B" to the bottom so that the design of the icons also give indications of their use. The --not so-- hard part was to choose the letters for the menu, minimize and maximize buttons. I chose "K" for the menu because that's the way almost all Serenity's iconthemes are. So I could use what came first to my mind when I thought about a letters-like icontheme: "m" for minimize and "M" for maximize. Here's the result:

[Alpha icontheme preview]


I made a little fake with the GIMP. Simply implementing this new icontheme in the windec would have been waaaaay much faster. Some people apparently enjoy doing things the hard way. ;-) (Temporary icontheme name: Alpha... because of a lack of imagination.)

Tomorrow, I'll deal with the Fitts' law. One of its rules says that the bigger the target is, the easier it is for the user to point and click. (Totally approximatively.) All this idea came from what Florian Grässle proposes in his blog about KDE's interface.

Use toolbar icons with text: The only thing I can do here is to hurry to send my patch to KDE-devel in order to correct this weird grey-bluish color used by the hovered labels. I already said so somewhere else but, before to make it KDE's default behavior, some deep thoughts will have to be given to shorten the labels. When I see that the label of the smallest icon in Konqueror's toolbar is "Delete the content of this bar"... I burst into laughter. Sure, it will increase the size of the target... but isn't it just a little exaggerated? :-D Whatever, I will always revert to small icons without label!

Take advantage of unused space between menu entries: Nothing can be done right now. Well, in fact, you can reduce the space in between the menu entries to nothing but there's no way to enlarge the menu entries themselves, neither within KDE nor Qt. Maybe KMenuBar could do something like adding white spaces around every menu label or arbitrarily enlarge the widgets on the fly. I don't know if it's possible without seeing the menu entries getting indefinitely wider and wider. Well, at least, that would be funny. ;-)

Make the whole width of checkboxes clickable: I totally disagree. I would be strange to be able to click --apparently-- on an empty space and to trigger an action. The other way around: No hover reaction unless the mouse is over the label or the checkbox is just right. This is the way Serenity works and I had such a hard time achieving this behavior. Besides, some checkbox widgets are so oversized that it would look ridiculous.

Introduce a dedicated resize handle: No thank you! To be able to pull any border of a window is waaaaay much better than having to move the window around in order to release some space around the resize handle before to finally be able to resize the window. The problem is with the users thinking that any space given to the window decoration is a wasted space. Look at all the highest rated windec on KDE-Look. They all have a thin border... expect Powder. (Boy, oh boy! How did my windec reach 78%? Maybe should I update it too?) Any way, resizing windows isn't my major activity. Every application was resized once in the past to suit my liking and unless I don't like this size any more, I don't resize. Sometimes I maximize a window to full width or full height but that's all.

Populate taskbar from left to right instead of from top to bottom: I don't feel much concerned. My taskbar is on an autohide panel. I don't see or use it often enough to bother how the taskbuttons are ordered. My usual use of the taskbar is to restore a minimized window once in a while so I always have to look for what I want.

In maximized windows make scrollbars edge aware: Good luck with this one. Serenity is able to remove the border from a maximized window but it can't remove the frames in it so that the scrollbar gets to the border of the screen. There will always be one pixel --at least. Any way, who cares? Who still uses the scrollbars with our mouse wheels? If I was able to remove the arrowbuttons and never had to bother they weren't here any more, that's because the scrollbars have become more a visual indication than a widget thanks to the mousewheel.

Make systray "edge aware": Here is another frame problem. Even if the frame is invisible, there is at least one pixel around the systray and the icon can't be at the border of the screen. To have a mouseover effect like with the toolbuttons may help a little. When you move the mouse cursor, if something happens (a mouseover highlight), it triggers a reflex to slow down. It should prevent you from actually reaching the border of the screen.

Connect labels with their respective [...] widget: This proposal is interesting. There is often a label with a keyboard shortcut in front of the editlines, comboboxes, spinwidgets, etc. When you use the shortcut, it activates the focus on the related widget so you can directly use it with the keyboard. But what happens when you click on such a label? Nothing. On an HTML page, it looks like you click directly on the widget instead of the label. That's an interesting behavior.

Some gears started spinning in my head. Can this behavior be reproduced with the regular widgets? The answer is yes --theoretically. What I have to do is catch the mouse click in the event filter, check if there is a "buddy" (Official Qt terminology) attached to the label and, in that case, construct a QMouseEvent for this "buddy". I haven't thought yet about how to trigger the event, I need to dig into Qt's docs. Theoretically, it will work.

I'm already gone...

2006-07-05

KDE: Tomorrow is today

It's been a while since last time. But --at least-- I don't come here to say nothing. So here are the last news: A new version of Serenity is on its way... again!

I did just two things to the window decoration. First, I added a new button style: toolbutton. In other words, the buttons remain flat and only the icons are visible until mouseover or activation. Then you got a button background. I don't really like it. It's too flat for my taste but I left it. Maybe somebody will like it.

Yeah, there's something I learned during this development: Once released, a style doesn't really belong to you only anymore but to the users too. If I worked only for me, half of the features wouldn't be available. That's would be easier... but where would be the fun?

Second, I changed the window frame to be no thicker than 1 pixel. I was thinking that 2 pixels were useful to really separate one window from another. I tested and it wasn't. I can live with just 1 pixel.

Now, the widget style. I was happy to satisfy my control obsession. I didn't noticed it but my style disabled a useful feature: the menu auto-closure --that is the possibility to close a menu in clicking on its menu entry once opened. That's silly but I never used this feature because I didn't know it existed. In the Atari world where I lived before, I was used to click outside of a menu to close it. That's what I kept on going. My experience with the "Dark Side" was too short for me to get bad habits. Any way, I reactivated this feature.

It wasn't easy to do because Serenity was fooling Qt to prevent it from drawing etched text --I just can't stand etched text.-- but my trick also deactivated the menu auto-closure. The solution was as easy as I said on KDE-Look: I had to prevent Qt from drawing any text by itself. To do so, I just copied QStyle::drawItem() from Qt sources and pasted it into Serenity::drawItem(), without forgetting to remove absolutely everything that was related to etched text. So Qt keeps on drawing text but with the settings I want. I could removed my trick --an invalid styleHint() returned value-- and the menu auto-closure was back. Now, I can almost feel sorry for all the time and hard work it took me to find this trick. ;-)

Next, I took care of the tabs. Somebody wanted flat tabs. Why not? I'm not obliged to use them. However, along the way, I found that I kinda prefer colorless tabs. And when I say colorless, I mean active tabs which don't use the highlight color. I did that and then absolutely flat tabs. It was a little too flat so I added gradients. And that's it, I got 5 available styles for the active tabs. A little image:

[Tabs version 1.0]


And I almost forgot to say that the tabs can now be centered. I find it disturbing but the tabs were the only thing that wasn't centered in Serenity. I added a little switch.

Next, I fixed the QToolButtons. Well, in fact, there was a problem only with the label. I thought that there was no mentionable difference in between KToolButton and QToolButton. I was wrong... and Serenity had a problem.

I thought that the button to burn in K3B should be more visible. I touched Serenity sources and... suddenly, there was a label above the icon. Ho! My mistake! :-)

I looked into Qt sources to see what it was doing. I re-wrote it my way and better. Yes, I dare to say better because Serenity makes QToolButton respect the reverse layout when needed. To make KDE respect the reverse layout with its KToolButton, I had to patch it. I don't use any Right-To-Left script but I made extensive tests so that Serenity copes with them and I stumbled more than once on the limitations of Qt or KDE. Serenity always does better whenever possible.

Last thing for today: A new scrollbar style. It doesn't mimic the look of any existing GUI, it removes the arrow buttons. A few day ago, an old post from Max Howell re-appeared on Planet KDE. He proposed a patch to definitively remove the buttons arrows from one's KDE. IMHO, that was too extreme... but also the kind of thing a style could do.

Max was saying that the arrow buttons of the scrollbars were the less used buttons of KDE. I rather agreed with him. Apart when I played a lot with them while styling them, I just don't use them. Never. I use the mousewheel everywhere. So, let's remove these buttons!

With the help of Max's patch, it took me no time to implement this feature. It was telling me just what I had to take care of.

$ make
$ su
password:
# make install ; exit

That was it. Look at this image. This is a preview of the next version 1.0 of Serenity. Tomorrow is today... at least for me. ;-)

On the image, you can see centered tabs with the colorless look, the (new) non-solid separators, and the arrowless scrollbar sliders.

Well, "arrowless" is a bit of an exaggeration. Actually, there are tiny arrows on the tips of the slider to remind you what this strange looking widget is. The arrows aren't working, they are here just to make the slider look better. (I will probably melt them a little more with the background.) So you have a perfectly working scrollbar but without useless arrow buttons to shrink a slider that has not always enough room. And since this is a selectable feature, no problem for those who have no mousewheel (e.g. a laptop).

I can hardly wait to release Serenity 1.0! If things go as expected, this week-end should be the day...