Windows and global mapping

Published Wednesday January 14th, 2009
9 Comments on Windows and global mapping
Posted in Graphics View, Qt

There are a few problems left to solve for how Qt’s widgets are embedded inside a QGraphicsScene. Each problem is a bit tricky, at least I think so. I’ll list a few and try to explain.

1) Mapping between global coordinates and scene/item coordinates.

QWidget can map its local coordinates to and from global (desktop) coordinates. This is useful for positioning popups or other windows relative to the widget (since window positions are always defined in global coordinates). It’s also useful for ensuring that something is close to the mouse cursor. There’s basically many use cases for global coordinates, and mapping to and from them. For some event handlers, Qt does this for you automatically, such as QWidget::mousePressEvent().


void Widget::mousePressEvent(QMouseEvent *event)
{
QMenu menu;
menu.add…
menu.add…
menu.add…
menu.exec(mapToGlobal(event->pos()));
// or simply menu.exec(event->globalPos());
}

Now the problem. One vanilla Qt widget can only appear in one spot, one desktop. In Graphics View, it can appear in several places (e.g., in the chip demo). This means QCursor::pos() can mean different things to a widget, and in particular, QWidget::mapToGlobal() and QWidget::mapFromGlobal(). What do these functions really mean to a widget that is embedded inside a QGraphicsProxyWidget? Why does Graphics View support multiple views again? πŸ˜› It’s clear that with only one view, this problem is trivial to solve. What would you expect for the above mouse handler if the widget is embedded in a multi-view application?

It’s likely that when a widget wants to map to and from global coordinates, then it’s as a response to either key or mouse input, and it’s likely that the correct view has input focus. So QWidget::mapToGlobal() could mean: map to the desktop of the single view if there’s only one, or the active input view, if any. If there are several views but none qualify, pick the one closest to the cursor? If not, map to scene. (Yup, you may have two views, each on a different desktop. It’s a corner case, its importance depending on which parts are important in any particular project.) Behind each unhandled corner-case lies a pool of subtle bugs.

QWidget::mapToGlobal() could just mean “map to/from scene”. While consistent, this is also completely useless… QWidget::mapTo/FromGlobal are almost exclusively called from inside a widget that’s otherwise unaware of Graphics View. The result is expected to be in desktop coordinates, and the mapping relative to the widget.

2) To embed or not to embed.

If you embed a widget, its child windows and popups are also embedded. This makes sense sometimes, otherwise not. It’s nice to be able to scale your whole UI to get resolution independence, and also see that your popups and file dialogs are scaled. If you don’t want to scale the windows; just scale the rest of the UI, you can pass 0 for the parent of the window. That’s if you’re in control. If you’re not, widgets like QComboBox will open a popup whose parent is the QComboBox itself, and the popup is embedded automatically. You have no choice. πŸ˜›

It’s clear from our users’ feedback, and from the Plasma team in KDE, that sometimes you want this and sometimes you don’t.

So what do we do? We could add a widget attribute that you could set on a widget, that ensures that it never auto-embeds any of its subwindows. In retrospect, perhaps this flag should have been the default, or rather that there was a flag that you could set that prevents this from happening. We also have the option of adding this as an option to QGraphicsProxyWidget; proxy->setAutoEmbedChildWindows(false).

But then there’s the case where a widget just never should be embedded, regardless of its parent. Examples may be tooltips, drag icons, and whatsthis-labels. Should it be the widget’s responsibility to “tag itself” for never being embedded (Qt::WA_DontEmbedInGraphicsView), or is also this an option controlled by the embedder?

I’m sure the answers will pop up one of these days. πŸ˜‰ Maybe you have some ideas you could share?

(Btw, the fact that embedded popups/windows aren’t constrained to fit inside the viewport is a bug that’s still not closed, but hopefully soon will be.)

Do you like this? Share it
Share on LinkedInGoogle+Share on FacebookTweet about this on Twitter

Posted in Graphics View, Qt

9 comments

notmart says:

hmm, both approaches have advantages and disadvantages, i do see some cases when you would want even popup and tooltips embedded, like if for some reasons you want to have 2 views on the same stuff so you want tooltips appearing on both, or jou just want a minimal system with a graphicsview and not even care about a windowing system…
but it’s also true that you can end up with really ugly things, like popups being cutted away because they go outside the view or even appearing in embrassing places (like stuff appearing at top of the screen in plasma because on the scene the panel is on top of the desktop)
sooo what about not embedding child widdows by default unless told so by proxy->setAutoEmbedChildWindows(true)?
are there default widgets where would be saner to embed child windows by default? (can’t think about any atm but could be wrong :p)

Scorp1us says:

Finally, some news that’s not about the license change!

What is “global”?

Maybe you could let us set the “global” context.
w->setGlobalContext(QDesktopWidget*);
w->setGlobalContext(QGraphicsView*);
w->setGlobalContext(QGraphicsScene*);

I’d take a similar approach for the other issue
w->setChildParent(QWidget *);
w->setChildParent(QGraphicsItem *);

Ralf says:

Hi Andreas,
are these the only problems left with WoC? πŸ˜‰ Did you solve the problem with modality of dialogs? During the WoC Session on the Munich DevDays I asked BjΓΈrn Erik how you deal with this: Given a QPushButton “Open File” in a QGraphicsScene, which connects to a slot where you call the static method QFileDialog::getOpenFileName(). This is supposed to open a non-modal FileDialog, but (at least in one of the first 4.5 snapshots), you could easily click on the button and get as many non-modal FileDialogs as you liked πŸ˜‰ Has this issue been addressed yet?

Ralf

Andreas says:

Ralf, you’re right, modality is also not supported, and we don’t have any always-on-top flag neither (which is quite important for windows). QGV is and will always be a subset of what QWidget is in Qt 4, and WoC isn’t meant as a full replacement for QWidget at all; it just adds support for embedding widgets inside a scene. Every feature we can add with little effort that brings the two closer together is a good idea for the long-term. Minimize the gap :-). I’m still thinking that some day in the future there is no QWidget vs. QGraphicsItem, but only one widget system that supports more than what either two can do today…

Ralf says:

@Andreas: (sorry, I mixed modal and non-modal in my previous post) It gets even more interesting if you think of two views showing the same scene, where a modal dialog pops up πŸ˜‰
Which GraphicsView and which item gets the events?! I don’t think that a “correct” solution exist, but something has to be done about this, otherwise you’ll get into trouble. Consider Marius’ blog on Next Generation Item views: http://labs.trolltech.com/blogs/2008/10/24/itemviews-the-next-generation/
If you display a tree view with this NGItemViews and try to delete something, there might be a call to QMessageBox::question(“Do you really want to delete..”) or similar. If modality does not work in this case, you can get any side effect you never dared to dream of πŸ˜‰

osx says:

Hi Andreas,

WoC support for OS X platform is not in line with Windows and Linux platforms

Widgets are always rendered in its original size (ie. no scale) and then drawn onto canvas which in case of either scaling down or up gives very poor user experience since fonts and other primitives are not rendered at device resolution.

Any platform also does not support manipulation of Z-ordering.
And there are issues with Focus Policy with embedded widgets (ie. it does not really work)

Other than that Graphics View is very good module and above issue when resolved would make it even better. Do you have any plans to address these issues (especially OS X rendering, since OS X provides resolution independence….)

Andreas says:

osx, yes that’s true and we are aware of it. We’ve looked for solutions for some time but haven’t found any way to render mac style widgets in a resolution independent way, and with good performance. Have you tried setting QPlastiqueStyle on the scene (or similar?)?

osx says:

Hi Andreas,

That was one of the first things i tried but without any improvement in quality. In fact I looked into Qt sources and noticed that 1×1 rendering of a widget into an offscreen pixmap (OS X conditional compilation code path).

What is really confusing to me is that since Qt has support for QStyle’s and CSS where almost every component of any widget can be customized that actual rendering of such widgets can not be done directly through the QPainter (as it is the case with OSX)
I know that perhaps this is wrong blog, but if you could shed some light at what issues are there that are preventing OS X widgets behaving exactly like Win32 and Linux Qt distributions.

HipPriest says:

It’s good to see Qt addressing this design issue. Fresco had a unified widget/structured graphic API, what, 15 years ago? Along with resolution and language independence. Alas, Fresco’s adoption never matched its technical excellence, while Gtk and Qt got the momentum. It always bothered me that in Gtk and Qt I would essentially have to write three versions of my widgets, one for normal forms, one for canvases, and one for list/tree/tables.

Obviously retrofitting these features into an existing design is not easy, as is documented in these blogs. But it is wonderful that it is finally happening in a popular toolkit like Qt. I hope you will also look at unifying list/tree/table items as well.

Commenting closed.

Get started today with Qt Download now