Usability, that old b****r

Usability is hot — especially usability for Linux Desktop Environments. After all, we (that’s the lde (Linux Desktop Environments) developers) want the misguides Windows-using masses to switch, and join us, and be enlightened, now don’t we?

Well, I don’t. I don’t care — what I want, in the first place, is an environment that enables me to do my work. And my work consists of  coding, writing (novels, blog entries and articles), messing with photographs, listening to music, playing the occasional game while waiting for a long compile, emailing, browsing, imming — you get the picture. And not only do I want to be enabled to do that, I want to feel comfortable.

KDE, with its myriad config options, with its minicli with completion, its excellent terminal emulator Konsole, its email client that tries to guess when I’ve forgotten an attachment, its insanely powerful file manager has always managed to make me feel comfortable. Empowered. Strong in the knowledge that this computer is serving me.

But in the outside world, evil forces are shaping the mindsets of other KDE developers in a dark and Sheldrakian field. Gnome used to be the epitome of power; it sunk to a third-rate (after Windows) imitation of MacOS. Gnome has its GConfEdit, Windows its Regedit, OS X its NetConfig. All three are tissue towels to stop the bleeding from their respective user-level config apps. All three make a noise while drinking soup — that’s to say, in case you haven’t read your Emily Post nor your Wodehouse, they suck. And now, infected by this leprous mentality that tries to hide all that’s powerful from users, KDE developers are disembowelling, emasculating KControlCenter by moving useful options, options even my eight-year-old daughters use with glee, out and away.

As I said in a answer on the kde-core mailing list to Aaron J. Seigo,

[KDE] should be about empowering every user — including the users people normally call ‘power users’. And, messing with configuration options has nothing to do with usability. People moan about config options on websites like OSNews, but from my own observation, 100% of children under ten years old like messing with config options to see what happens better than playing Klickety, and 100% of bored office workers rather mess with config options, especially for gui things, to see what happens than read the Onion for the second time.

Real usability is about not surprising people: about consistent keyboard shortcuts, about never changing the location of a menu option, about never crashing, about never disappointing someone’s expectations, about never making fonts disappear, about always having the same mdi interface out of the box, about using the same toolbar button icons, about not placing awfully similar toolbar buttons like ‘find’ and ‘zoom’ right next to each other. And about not alienating your existing user base by dis-empowering them.

Okay — let me substantiate that last list with examples from KDE:

  • KMail and KNode are both apps that read messages. In KNode you go to the previous message in the list with ‘b’ — ‘p’ posts a message. In KMail, you have to use ‘p’ — ‘b’ goes to the first mail folder that starts with a ‘b’.
  • There’s a system menu, a venerable institution that dates from Windows 3.0, which took it from Motif. In KDE, it always had a certain order; with 3.2, the order is subtly changed, and now finger reflexes no longer work.
  • Crashes are still part of the daily grind, I’m afraid. Kopete is a bad example, as is KMail.
  • I’d used Gaim for quite a long time, and Gaim keeps a log of all my IM exchanges. Kopete might be able to do that, too, but it’s a plugin, and the wording in the text of that plugin is weird enough that even I, who is regarded as a geek, and therefore not a user, cannot understand what’s going to happen if I enable it.
  • There are several paint-like apps in KDE, but none of them use the same icons for brushes, etc. Now that’s going to be fixed, but it’s bad to start with.
  • Konqueror has find, zoom in and zoom out next to each other. Three magnifying glasses with squiggles around them. Even after five years of KDE use, I still press the wrong button.
  • And then there are suddenly config options disappearing… But that means we’re back at the start of this entry, so redo from start, if you please.

The Goal

The goal of the Free Software Movement is to enable people to understand, to learn from, to improve, to adapt, and to share the technology that increasingly runs every human life. That’s what Eben Moglen said in his 23 February address at Harvard, as transcribed at Groklaw.

You know, I couldn’t have put it better myself, but then, that’s why I quote, instead of being quoted, so that’s all right. People (and they’re often spokespeople, too) tend to get a bit hysterical about the damage done to core values of the human race like profitability and things like that — but, when it comes down to it, getting more doss isn’t what it’s all about.

It’s about being a human, being created in the image of God. And God being in essence a Being of relations within Himself (thus the Trinity), and with us, we are supposed to be beings in relation with each other. And while being in litigation is a form of being in a relation, I don’t think it’s a good relation.

Sharing is a relationship that’s given pretty high priority by God, especially sharing when you’d rather keep your stuff to yourself. We need to share that which we have that will make our fellow beings happier. People are happy when they can make things (being created in the image of a Creator). People need to be able to make things. Sharing the knowledge to make things is sharing that which our fellows need. And just that is enough justification already for sharing the fruits of our individual intellectual pursuits.

We’re living together, and living together means sharing what we hold dear and which the other needs. And people need now, more than ever, a chance to master the technology that otherwise would live their lives for them.

And if you don’t care for the theology or don’t buy my argument, then there’s more than enough to convince any reasonable, well-thinking person in Eben Moglen’s speech, and much better formulated than what I’m trying to say.

James Richard Tyrer speaks out:

“Someone posted that TQM had to be forced on people. Possibly, but the question is whether after it is forced on them that they ever want to go back to working without it?”

I’ve been a professional software developer for more than ten years now, and I’ve been through all the fads, all the processes, all the acronyms. The only ‘process’ that ever gave me any pleasure was extreme programming, and even then only the pair programming with a congenial colleague part. Yes, having experienced the kind of top-down, heavy-handed programmer-shackling that TQM and the other acronyms stand for, I say: never again.

The problem, James, with TQM is not the Q, it is the M (and the T a bit, because Total reeks of totaliarism). If I am donating my time and my work as a volunteer to an open source project, I’ll be damned before I’ll allow myself to be managed. Especially by someone who hasn’t earned my respect at all. And there’s no way, short of taking away my CVS account, you can force me to comply.

If someone whose work I admire tells me to fix this, do that, or pull up my socks and start producing better code, I’ll probably heed him or her. But that’s the only kind of management I’ll accept.

Suggestions, snide remarks about lack of commitment, snipes and other pointy-haired behavior won’t influence me in the least. Which translates to: if you want to have real influence, James, learn C++, and learn it well. Impress me. With something more substantial than flaunting an acm.org email address.

A dashed little comma

Can spoil four evenings. Now I know that I am not at peak form when working in the fumes of paint, and we have had painters in the house for three days (they did a beautiful job, and I heartily recommend them: Steenbruggen in Deventer) — but, dash it, see if you can spot the mistake in this Makefile.am:

INCLUDES  = -I$(srcdir)/../ $(KOFFICE_INCLUDES)  -I$(interfacedir) $(KOPAINTER_INCLUDES) $(all_includes)

noinst_LTLIBRARIES = libkiscapabilitymediator.la
libkiscapabilitymediator_la_LIBADD = ./paintops/libkispaintops.la
libkiscapabilitymediator_la_SOURCES = kis_capability_mediator.cc kis_abstract_capability.cc, kis_composite_op.cc kis_paint_op.cc

libkiscapabilitymediator_la_METASOURCES = AUTO

SUBDIRS = paintops

Seen it? I only spotted it tonight. You’d get really weird errors in the linking stage of the main Krita lib, but linking the core lib just worked…

On the other hand, things are hotting up a bit. Patrick Julien is busy as ever with his day (and night) job, but two more people have come on board, and there’s another friendly soul who likes helping me out with performance issues. So — there’s life again in the five year old dog!

What — am I a hacker, or what?

There’s this heading ‘hacking’ on Fading Memories, isn’t it? Hacking, and not coding. But what’s a hacker — when it comes down to it? It’s, perhaps, someone who’s been sharing code against all odds for longer than he cares to remember, someone who has a sense of esthetic regarding code, even more than regarding ephemera like user interfaces. Perhaps a hacker is a coder who’s just that little bit harder to herd.

So — what am I — I mean, am I, or not? Not exceptionally bright, like Paul Graham, but I’ve been coding since 1982, been using Linux since 1993, been learning a new programming language every — on average — three years. I think I know by now; I’m a hacker, and I dislike being herded.

Not that there’s much chance of that: whenever people show up and try to convince coding people that Process is Paramount (note nice reference to Quick Service) and TQM is king (or is that Queen?), I smile enigmatically (not that that is much use in an on-line discussion) and refrain in a refined way from commenting that those attempts are futile and vainglorious. There’s no way someone who cannot code for toffee can get me — let alone people who can code really well — to do his bidding. I’ll follow my own agenda, thank you very much. If you like it, fine, tickled to death, I’m sure, if not, learn C++ yourself, it’s not that difficult, my dear man.

So, if I’m a hacker — what’s my forte. Not audacity of design. Not actual knowledge — when working on Krita more than half the time I do not know what I’m doing. I have little math and less computer science. But a kind of dogged going on coding, because I want to see what it does and learn what makes it tick. That’s my ticket. Sometimes a programmer’s gotta do what he gotta do.

A while — quite a while, actually — ago, there was a bit on O’Reilly Network that tangentially discussed the set of features that makes a hacker a hacker. In the cause of full disclosure and unmitigated boasting I must add that I: hate Heinlein (silly racist right-wing loony), like Tolkien, like van Gulik better, play the clarinet, fence, despise gun-bunnies, wish I had the
necessary moral righteousness to conform more closely to the ideals of the FSF, still play RPG’s, know zilch about RPGi-the-language, know (a bit or quite well, it depends) various basics, PL-SQL, SQL, C++, Pascal, Java, C++, Python, SGML, XML and, scraping the barrel a bit, SNOBOL. I paint a bit, have written a novel, a book, a number of articles, am a linguist — but all that is mere outer trappings.

The most important thing is, I think, that whenever I see something that’s cool, that seems to work, I want to know why, and how, and more importantly, how can I make things like that, or even better. Preferably better. That whatever I do seldom is better isn’t the point. It’s the attempt that counts — in a Newt Pulsifer kind of way. That, and being unherdable, of course.

Which neatly brings me back, and from there to another rant: Why do so many people who take a certain philosophy lock stock and barrel think they’re the ones who think, while the poor shmucks who have chosen something else must be incapable of cogitation?

People who think they have achieved a freedom of thought because they’ve bought into the free-thinkers thing seem to me pretty naive — given to take a label for its contents, for one thing.

Give me one of the great Gregories (Nyssa, Nazianze, the Great) any day above those shallow ‘thinkers’ who cannot get beyond ‘Either one believes, and does not think, or one thinks, and does not believe’ (Bert Keizer in Trouw, this week).

Just like Frederic Brooks, I think, therefore I believe

Some progress, at least

Progress with Krita has been slow, the past two weeks, considering that I’ve been at home nearly permanently. Still, I’ve been working on some things, and thinking about others.

There’s now an eraser tool, and a line tool, and I made a start porting the stamp tool. At least, I thought that it was a stamp tool, but it turns out it is a tool that paints with patterns instead of brushes, not something that takes the last selected bit of the image, and paints with that. Perhaps I’d better wait for Patrick Julien to checkin the odds and ends for selecting and pasting he says he has lying about, and make a start on a convolve tool.

I also ported (that’s to say, copy, paste, search & replace) a large number of less interesting composition operations to Krita from GraphicsMagick, after I was given the green light by Leonard Rosenthol about the licensing. The more interesting composition operations are harder to port, since they either work on a whole image at a time, instead of on regions, or they use a number of extra functions from GraphicsMagick that I don’t feel the urge to port, too.

A persistent pain in the neck with working on Krita (or C++, perhaps, I am not sure), is the hard-coded nature of everything. With Python I can define a number of classes, perhaps even dynamically, read a list of classnames in a Python list from a configuration file, iterate over the list and instantiate the classes — easy as pie. But that’s because in Python, classes are an object; in C++ classes are — I don’t know what, exactly, but not objects, and no fun either. Look at Python:

class A: pass 
class B: pass
class C: pass
class D: pass

l = []

for clsname in file("classes.cfg").read().split():
	l.append(eval(clsname))	
print l

Of course, this is a very simple-minded example, but image a situation where you have a large number of classes, say — for the sake of argument — composition operators, one class per op, and you have a smaller number of image types, and some comp. ops. are useful for all image types, others only for a few, and others again for only one. The GUI, of course, must show only the relevant composition ops in the various listboxes. And when I add one, I don’t want to have to go through all the code to add those.

But still, I’m prepared to do precisely that: hardcode the instances of the relevant ops in the correct places, Krita, however, currently doesn’t have anything like that. There is a long enumeration in kis_global.h; there are user-visible string somewhere else, and a big switch statement that uses the enum to switch between function calls.

Here, I should create a factory that creates all defined ops, and some kind of a database that ties together all functionality, preferably defined in a configuration file, but hardcoding will do for now. I’m not sure about naming; I need something that forms the basis of all these capabilities that are now described in enums, and inherit from there.

Likewise, KisPainter is big monolith that looks a lot like QPainter. It combines geometric functions with simple paint functions, but that’s unpleasant, because I would prefer to have one function for creating lines that I can feed not only brush types and things, but also paint operations: hard paint, soft paint, airbrush, convolve, erase — so, instead of:

void eraseCircle(Qpoint p1, Q_INT32 radius);
void eraseLine(QPoint p1, QPoint p2);
void eraseAt(QPoint p);

void eraseLine(Qpoint p1, Q_INT32 radius);
void paintLine(QPoint p1, QPoint p2):
void paintAt(QPoint p)

void convolveCircle(...

I’d like:

class PaintOp;
class erase;
class convolve;
class paint;

class KisPainter{
...
void line(const PaintOp & op, QPoint p1, QPoint p2);
void circle(const PaintOp & op, QPoint p1, Q{Point p2);

Etcetera… Add in a CompositeOp class hierarchy, and life will almost seem to be as sweet as Python makes possible again. Of course, there’s more… We already have a KisResource structure that handles brushes, patterns and other bits of artistic licentiousness that are read from disk; here we have a lot of code duplication, even though the process is fairly dynamic.

And I should finish that convolve tool.

No hacking…

Hacking is just as much a necessity of life as breathing, writing or eating. But sometimes, it’s impossible to go on working, even though you’re all in the flow.

Like when Johanna decides that she’ll punish you for putting a row of books on her favourite sleeping spot; she won’t move to the other side of the desk, but in front of kis_strategy_colorspace_rgb.cc

The books have been put back to the left side of the desk, where I prefer to push my monitor so I have some deskspace for reading, but well, one  cannot have everything, and it is nice, having a sleeping ball of black, cuddly fur on your desk while working.

(And the other reason for not working on Krita is that the fever has dropped off a bit, and I’m just too tired right now, so excuse no new commits, I’m  just goofing off and looking through my stack of photos…Here’s a piccy of another cat, Hendrik, reading Dostoievsky, which I think is pretty nice.)

Why Free Software, and why hacking even when quite ill?

This article by an anonymous person tells you why — near the bottom: And now a word from our corporate sponsors

Let the stuffed shirts and corporate bigwigs make money from the Free code. Let the pundits question what it will take for Linux to succeed on the Desktop. There is massive innovation in Linux userspace, driven by the same geeky joy that, in another era and in other fields is called “intellectual curiosity.” That’s what I see as the main force behind the Open Source movement; not corporate possibilities, as the LinuxWorld convention pretends, but brutal candor, mischievous smartness, self-mocking over-eagerness. The corporate successes of Linux are just the results of an overflow of energy, the excesses being mopped up. The hacker ethic is driving the corporations. We don’t need them, but they need us.

Intellectual curiosity it is — that, and the intense desire to make things, to, in fact, create. Before I kept a blog, I already found it necessary to write about that — Apologia, because people kept mailing me, asking why the thingy I found it necessary to spend time on creative pursuits, like conlanging or world building.

And now I’m not only working on a novel, on a language database application, on a KDE paint application, but also studying theology and messing with real paint again.

Worrying about composition

Gah! I never had proper maths at school, and I dare say that if someone had tried to teach me maths at the tender age of eleven or twelve, I’d probably have bucked like race horse that’s harnessed in front of a brewery sledge. But the fact that my maths teacher walked out of the class when I was in the second form, to never return, didn’t help either. Not that I ever thought I had missed something essential.

Until now, that is. Graphics == maths, it seems. And not simple algebra eiher. So I am trying to understand what the various composition modes do — reading the literature, starting with the Porter-Duff article that appears to have started it all, and working my way through the GraphicsMagick source code, and I am finding it hard going.

And then there’s the mess that Krita’s UI is, a rich archeological dig where you can find code from 1999 to 2003, all written by different people with different goals and different styles, and practically nothing finished, or even in a working state. I should scrap that GUI and start again, only that’s going to take even more time from that most elusive of goals: a working eraser too.

Anyway, here’s a snippet of GraphicsMagick code, for the ‘in’ composition operation:

	if (source.opacity == TransparentOpacity)
	{
		destination=source;
		break;
	}
	if (destination.opacity == TransparentOpacity)
		break;
	pixel.opacity=(double) (((double) MaxRGB-source.opacity)*
				(MaxRGB-destination.opacity)/MaxRGB);

	destination.red=(Quantum) (((double) MaxRGB-source.opacity)*
	   (MaxRGB-destination.opacity)*source.red/MaxRGB/pixel.opacity+0.5);

	destination.green=(Quantum) (((double) MaxRGB-source.opacity)*
	     (MaxRGB-destination.opacity)*source.green/MaxRGB/pixel.opacity+0.5);

	destination.blue=(Quantum) (((double) MaxRGB-source.opacity)*
	    (MaxRGB-destination.opacity)*source.blue/MaxRGB/pixel.opacity+0.5);
	destination.opacity=(Quantum) (MaxRGB-pixel.opacity+0.5);
	break;

And here’s how I think it should be translated into Krita:

d = dst;
s = src;

if (d[PIXEL_ALPHA] == OPACITY_TRANSPARENT)
	continue;

if (s[PIXEL_ALPHA] == OPACITY_TRANSPARENT) {
	memcpy(d, s, stride * sizeof(QUANTUM));
	continue;

}

alpha = (double) (((double) QUANTUM_MAX - s[PIXEL_ALPHA]) * (QUANTUM_MAX - d[PIXEL_ALPHA]) / QUANTUM_MAX);
d[PIXEL_RED]   = (QUANTUM) (((double) QUANTUM_MAX - s[PIXEL_ALPHA]) * (QUANTUM_MAX - d[PIXEL_ALPHA]) * s[PIXEL_RED] / QUANTUM_MAX / alpha + 0.5);
d[PIXEL_GREEN] = (QUANTUM) (((double) QUANTUM_MAX - s[PIXEL_ALPHA]) * (QUANTUM_MAX - d[PIXEL_ALPHA]) * s[PIXEL_GREEN] / QUANTUM_MAX / alpha + 0.5);
d[PIXEL_BLUE]  = (QUANTUM) (((double) QUANTUM_MAX - s[PIXEL_ALPHA]) * (QUANTUM_MAX - d[PIXEL_ALPHA]) * s[PIXEL_BLUE] / QUANTUM_MAX / alpha + 0.5);
d[PIXEL_ALPHA] = (QUANTUM) (QUANTUM_MAX - alpha + 0.5);

dst += dststride;
src += srcstride;

But it doesn’t seem to work:

I am not completely sure what ‘in’ ought to do, but I am fairly certain that it isn’t ‘paint vertical black lines’ if I’ve selected a purple brush…

That dashed TODO list keeps growing

I’ve spent the better part of this week rather feverishly (literally, I’m afraid) hacking on Krita, trying to bring it up to KPaint-level feature-wise, at least, and all that seems to happen is that my TODO list is growing.

Yesterday I fixed that silly slider that regulates the spacing with which brushes are painted on the canvas, did some code clean-ups and made sure the correct cursors are used. And I updated that TODO list:

* The tabs for images inside a document seem to be broken :-(
* Brush cursor shapes for tools (updating cursors from the tools doesn't work yet).
* Give each layer its own imagetype; allow layers of diverse types in one image.
* Option dialog for tools
* Make tools kparts
* Fix scrollbars
* make brush tool antialiased; make un-antialiased pen tool
* If you have a tablet, you can have more than one active tool at a time: 
	stylus, eraser, pointer and your ordinary mouse, not to mention
	the possibility of having several styluses.
* Implement saving/loading of tool properties.
* redo configuration dialog
* Find a way to set the hourglass cursor when doing complex things from
	e.g. KisPainter.
* Make pipe brushes pay attention to the instructions in the 'parasite'
* Use patterns and gradients while painting

....

And that’s just the bit that got added this week. And I would really like to bring some more structure in the /core source directory, and make a  separate library of the KisPaintDevice/KisPainter code. But that’s a refactoring that can be done at a later stage, when I’m more confident of my C++ abilities. I am growing more confident — I think I could put C++ on my curriculum vitae by now.

The thing that’s most needed at the moment is more tools; that will flesh out the KisPainter interface and give me a reason to improve the user interface. Having more than one layer type in one image would be a good thing, too. That would make it easy to have a CMYK or B/W layer and a layer with spot colour on top.