> Read More... | Digg This!

Typically, "tip of the day" feature is not really loved. Often, the dialog for showing the tip blocks the main view of the application. Worse, this dialog is even modal, you have to click it to make it disappear.
For SpeedCrunch upcoming version 0.8, I play around with the idea of showing a short tip as a yellowish widget inside the main window. It will disappear automatically after couple of seconds (even with some smooth translucent and animation effect). I'm still thinking whether the tip should be displayed at start up, or only from a menu item.

I hope this kind of tip is non-intrusive and yet allows the users to learn a thing or two about SpeedCrunch features.
So, what do you think?
(Yes, I know there is typo in the screenshot :-)
Alternating row colors is a very common user interface pattern, the most used example is the playlist in Apple iTunes. With different color every other row, the table or a long list looks more pleasant and easier to use.
However, if your list is rather vertical than horizontal, i.e. it is not that wide, but rather quite tall, and only consists of one or two columns, sometimes it helps to color not every row but a group of row. The example is shown here. The leftmost list widget has the same white color for all rows, the middle one uses alternating row colors (which looks rather "busy"), and the last one colors every 3 rows. Which one do you think is better?
If your list is an instance of QListWidget, QListView or anything derived from QAbstractItemView, it is very easy to enable the alternating colors, just use alternatingRowColors property.
Alas, for grouped alternating colors for QListWidget, you must do some additional work, e.g. (works well for rather static items):
int group = 3;
list->setUpdatesEnabled( false );
for(int i = 0; i < list->count(); i++)
{
QListWidgetItem* item = list->item(i);
QBrush c = ((int)(i/group))&1 ? palette().base() : palette().alternateBase();
item->setBackground( c );
}
list->setUpdatesEnabled( true );
Multiple column list is often made from QTreeWidget with only top level tree items. In this case, grouped alternating colors can be achieved using e.g. (for two columns, create a loop for more):
int group = 3;
tree->setUpdatesEnabled( false );
for(int i = 0; i < tree->topLevelItemCount(); i++)
{
QTreeWidgetItem* item = tree->topLevelItem(i);
QBrush c = ((int)(i/group))&1 ? palette().base() : palette().alternateBase();
item->setBackground( 0, c );
item->setBackground( 1, c );
}
tree->setUpdatesEnabled( true );
You can of course save some microseconds if you cycle the background color while iterating the items.
In addition, you may want to put some logic to prevent coloring if the number is item is e.g. less that 2*group. Otherwise, 4-item list will look odd, as only the last item has different background color.
Time flies. KOffice sprint weekend in Berlin was just over. I couldn't believe I was on my bed again this morning. It was lots of fun, plenty of food, interesting talks, endless excitement, and most importantly, I got see many great fellow KOffice hackers in real-life.
In terms of lines of code, I wasn't that productive. But I did managed to fix the annoying column/row resizing tip in KSpread and cleaned up some stuff so that krazy score is going to the sane level again. I checked our list of bugs and already had plan for few of them. The unit test for some spreadsheet functions would hopefully get some love as well. Also, thanks to our filter framework, I could work on a Karbon filter even before Karbon 2.0 is 100% ready. And I promised jaham that I'll help with the SVG to/from ODG stuff. There as also a buzz to finally start really using my latest work on KoXmlReader for all KOffice ODF loading code so that we won't have problem with memory consumption again when working with big documents.
For more details, summary and pictures, see KOffice ODF Sprint Kick on the Dot™.
So it'll be my n-th trip to Berlin. We're going to have KOffice ODF Weekend, supported by KDE e.V and KDAB. 17 heads, lots of hacking, and rainy weather look like a great combination.
Finally, SpeedCrunch version 0.7 has been released. Compared to the last beta, this final release has some fixes for potential crash (due to Q3TextEdit), which is also reported in Launchpad.
So, get it while it's hot. Packages are already available for Windows, Mac OS X (universal binary), Fedora, OpenSUSE, Gentoo, and Debian. Or just compile it from source if you feel brave. See the download page for details.
For some stuff which will make it into the upcoming 0.8, I'm still preparing an interesting screencast. Stay tuned.
Thanks to QDockWidget::toggleViewAction, if you want to create an action (and placed in in the menu, for example) to switch a dock widget on and off, it is very simple indeed. The text of the action will be the title of the dock. If you have more than dock widgets, this can be combined together in a sub menu "Show Docks", just as illustrated below:

When that menu item (and the corresponding action) is checked/unchecked by the user, magically the dock will show/disappear.
But what if you want to create your own toggle action? For example, you want to customize the text of the action to be a bit more descriptive, say "Show Function List". Or perhaps you just want the total control.
Well, you can create your own actions and get this result:

which can be realized by the following code:
m_actions->showHistory = new QAction( tr("Show Expression &History"), this );
m_actions->showFunctions = new QAction( tr("Show &Functions List"), this );
m_actions->showHistory->setToggleAction( true );
m_actions->showFunctions->setToggleAction( true );
connect( m_actions->showHistory, SIGNAL( toggled(bool) ),
m_historyDock, SLOT( setVisible(bool) ) );
connect( m_actions->showFunctions, SIGNAL( toggled(bool) ),
m_functionsDock, SLOT( setVisible(bool) ) );
So far so good. Everytime you toggle the menu item, the docks can disappear and reappear.
However, it's not completely foolproof. You can, infact, make the dock disappear by closing it manually, i.e. clicking on the X button on the dock title bar. But by doing that, the "checked" status of the action itself is not properly adjusted (i.e. it is still "checked" while the dock is long gone).
With Qt 4.3, the solution is easy: use visibilityChanged signal of QDockWidget:
connect( m_historyDock, SIGNAL( visibilityChanged(bool) ),
m_actions->showHistory, SLOT( setChecked(bool) ) );
connect( m_functionsDock, SIGNAL( visibilityChanged(bool) ),
m_actions->showFunctions, SLOT( setChecked(bool) ) );
If, for whatever reason, you're stucked with Qt 4.2, then you have to find another remedy since visibilityChanged does not exist there. There are many ways to do this.
A particularly complicated but looks-elegant solution is by hijacking trapping the show and hide event of the docks using eventFilter trick. So, hook the event filters during docks construction:
m_historyDock->installEventFilter( this ); m_functionsDock->installEventFilter( this );
and do something like this in the window's event filter:
bool MyWindow::eventFilter( QObject* object, QEvent* event )
{
if( object == m_historyDock )
if( event->type() == QEvent::Hide || event->type() == QEvent::Show )
m_actions->showHistory->setChecked( event->type() == QEvent::Show );
if( object == m_functionsDock )
if( event->type() == QEvent::Hide || event->type() == QEvent::Show )
m_actions->showFunctions->setChecked( event->type() == QEvent::Show );
return false;
}
Looks good? Not really. Because for all this trouble, you can just do the same in these two lines of code (the simple and yet effective solution):
connect( m_historyDock->toggleViewAction(), SIGNAL( toggled( bool ) ),
m_actions->showHistory, SLOT( setChecked( bool ) ) );
connect( m_functionsDock->toggleViewAction(), SIGNAL( toggled( bool ) ),
m_actions->showFunctions, SLOT( setChecked( bool ) ) );
Any other solution, perhaps?
Warning: don't try this in real world's application!
One advantage of dock widgets (using QDockWidget) is that the docks can be "stacked", either programatically using tabifyDockWidget or when the user explicitly places one dock on top of another. Example is shown below (for future version of SpeedCrunch, more about this in another blog post). There are two dock widgets: History and Functions, and at the moment they are stacked.

However, apparently the tab bar (QTabBar) which is used to choose the dock is always placed at the bottom. Or, using the Qt's terminology, it has the shape of QTabBar::RoundedSouth. Since there are other possibilities for tab bar's shape, e.g. RoundedNorth, would it be possible to make something like this, where the tab is place at the top?

Unfortunately until Qt 4.2 this is not possible yet (issue 146772), although according to issue 145880, "vertical tab bar layout" will be possible in Qt 4.3.
Just for fun, I found a very hackish way to make RoundedNorth for the tab bar (hence, the screenshot above). The trick is to find the tab bar using run-time introspection feature of Qt and then change the geometry manually. If I know in advance that there will be only one tab bar in my main window and there are only two dock widgets, this can be accomplished with a private slot like this:
void MainWindow::hackTabbedDocks()
{
QDockWidget* topDock = d->historyDock;
if( topDock->height() == 0)
topDock = d->functionsDock;
QList<QTabBar *> allTabs = findChildren<QTabBar *>();
for(int ii = 0; ii < allTabs.size(); ++ii)
{
QTabBar* tab = allTabs[ii];
if(tab->parentWidget() == this)
{
if(tab->geometry().top() > topDock->geometry().top())
{
tab->setShape( QTabBar::RoundedNorth );
int h = tab->geometry().height();
tab->move(tab->geometry().left(), topDock->geometry().top());
topDock->move(topDock->geometry().left(), topDock->geometry().top()+h);
}
break;
}
}
}
I found out, I always need to call this slot twice so that it can work. To simplify, there two other slots which manage it:
void MainWindow::handleTabChange()
{
QTimer::singleShot(0, this, SLOT(hack1()));
}
void MainWindow::hack1()
{
hackTabbedDocks();
QTimer::singleShot(100, this, SLOT(hackTabbedDocks()));
}
And I need to bind any signals which indicate that the tab bar has been relayouted, e.g. when a new tab is selected , when it is resized, etc, to handleTabChange slot above. For illustration purpose, let's just do the first. Of course, this can be done only when tab bar already exists. So, time for another silly slot:
void MainWindow::initHack()
{
QList<QTabBar *> allTabs = findChildren<QTabBar *>();
for(int ii = 0; ii < allTabs.size(); ++ii)
{
QTabBar* tab = allTabs[ii];
if(tab->parentWidget() == this)
{
connect(tab, SIGNAL(currentChanged(int)), this, SLOT(handleTabChange()));
break;
}
}
handleTabChange();
}
which will be called from MainWindow's constructor by abusing QTimer once more:
tabifyDockWidget( d->historyDock, d->functionsDock ); QTimer::singleShot(0, this, SLOT(initHack()));
That's it!
The big disadvantage of this trick is obvious: flicker occurs everytime you do something with the docks, e.g. changing the tab. It will be quite annoying, but all of this is just a hack anyway. So was it fun? Yes. Useful? No.
(I guess the real "solution" is only waiting for the Trolls to implement it)
Consider the following simple operation, where k is integer and p is prime:
int i = k % p;
Typically this will be assembled to (sorry, x86 only):
mov eax, k cdq idiv p
where the result is available in register EDX.
Such IDIV instruction has a latency of more than 40 cycles on Intel Pentium or AMD64 processor family. Hence, for optimization purposes, it is best to avoid integer division.
The above division/modulus operation can be avoided if the prime number p is chosen to be the Mersenne primes only, i.e there is a positive integer s such as p = 2s-1. In 32-bit range, there are Mersenne primes: 3, 7, 31, 127, 8191, 131071, 524287, and 2147483647.
The modulus operator with Mersenne prime can be simplified as:
int i = (k & p) + (k >> s); return (i >= p) ? i - p : i;
One possible assembler implementation is as follows.
; assume edx = k, ebx = p, ecx = s ; result is in eax mov eax, edx sar edx, cl ; k >> s and eax, ebx ; k & p add eax, edx ; eax is i = (k & p) + (k >> s) mov edx, eax ; edx is also i sub edx, ebx ; i - p cmp eax, ebx ; only if (i >= p) cmovge eax, edx ; then eax is (i-p)
Note that with the help of CMOVGE (6 cycles latency on Pentium 4), there is no need for real branching (which is expensive). Although the code is longer compared to the IDIV version, it executes much faster. Still faster if the range k is limited so that only a decrement operator is needed. Even faster of course if p is constant.
Last time I used this is for hash table (micro)optimization, because the number of stored items is known and I can live with a table whose size is a Mersenne prime. That's indeed a very special case only.
BTW this is off-topic, but thanks for those who mailed/texted me after this post. Nothing happened to me, I'm just fine. Those lines are from Keane's latest single (guess which one?), picked for no particular reason other that it's a good ballad.