Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make Qt tabs looks great again #20

Closed
dgdavid opened this issue Apr 16, 2021 · 29 comments
Closed

Make Qt tabs looks great again #20

dgdavid opened this issue Apr 16, 2021 · 29 comments
Labels
tracked Tracked elsewhere (Bugzilla, Jira, Trello)

Comments

@dgdavid
Copy link
Contributor

dgdavid commented Apr 16, 2021

Currently, the libyui Qt tabs feature two styles issues

  • The tab texts fill all content's width evenly distributed among them. This usually results in unnecessary wide tabs, especially when there is just a couple of them.

  • The content does not take the same background of the selected tab, which produces some lack of context since the background is the same for the whole dialog.

yast2-storage-ng yast2-users
partitioner yast-users

Taking a look to SLE 11 and SLE 12 documentation those issues are more evident. See below yast2-users screenshots, which talk by themselves.

SLE 11 SLE 12
yast2_users_main_gtk SLE12yast2_users_main_gtk

I was trying to fix them via QSS, but it didn't work. I suspect that some changes are needed in the library, but for me it's hard to say where even after looking at https://github.com/libyui/libyui/blob/master/libyui-qt/src/YQDumbTab.cc and https://doc.qt.io/qt-5/qtabwidget.html.

So, IMHO it would be nice to have the same behavior as it had back in SLE 11. It helps to identify better the elements and their relations in the UI.

@dgdavid dgdavid changed the title Make tabs looks great again Make Qt tabs looks great again Apr 16, 2021
@ancorgs
Copy link
Contributor

ancorgs commented Apr 16, 2021

Sad but true. Reviewing that yast2-users screen in SLE11 -> SLE12 -> SLE15... it looks to me like it gets both uglier and less intuitive on each iteration.

@ancorgs ancorgs added the tracked Tracked elsewhere (Bugzilla, Jira, Trello) label Apr 29, 2021
@ancorgs
Copy link
Contributor

ancorgs commented Apr 29, 2021

Labeled as "tracked" since I created this https://trello.com/c/WaSOYCD3/4683-make-qt-tabs-looks-great-again

@shundhammer
Copy link
Contributor

shundhammer commented May 3, 2021

The width of those individual tabs is most likely (99%) determined by the QStyle deep inside Qt. That might have changed between SLE-12 and SLE-15. Not sure, but it might still have been Qt4 in SLE-12; right now we use Qt5, and Qt6 is on its way.

You can try to use a different QStyle with the -style ... command line argument; see also https://doc.qt.io/qt-5/qstyle.html .

@shundhammer
Copy link
Contributor

shundhammer commented May 3, 2021

The code in libyui/libyui-qt:

https://github.com/libyui/libyui/blob/master/libyui-qt/src/YQDumbTab.cc#L76-L87

Each tab page corresponds to one YItem, for which this addItems() method creates one Qt counterpart with QTabBar::insertTab() in the internal QTabBar.

I didn't find any special property in the QTabBar that we could use to easily change this "fill the entire width of the tab bar" behaviour.

@shundhammer
Copy link
Contributor

shundhammer commented May 3, 2021

Testing styles on my Xubuntu 18.04 LTS (Xfce4) desktop with qdirstat -style fusion (which is the default for Qt applications on my desktop) and the window made wider to demonstrate this behaviour:

QDirStat-config-style-fusion

qdirstat -style adwaita (the widget theme / Qt style of my Xfce desktop):

QDirStat-config-style-adwaita

qdirstat -style windows (yes, it's ugly):

QDirStat-config-style-windows

@shundhammer
Copy link
Contributor

shundhammer commented May 3, 2021

Testing in my up-to-date Tumbleweed VM with the DumbTab1.rb example from yast-ycp-bindings/examples:

  • y2base ./DumbTab1.rb qt (default style):

DumbTab1-example-default

  • y2base ./DumbTab1.rb qt -style windows:

DumbTab1-example-style-windows

  • y2base ./DumbTab1.rb qt -style fusion:

DumbTab1-example-style-fusion

  • y2base ./DumbTab1.rb qt -style plastique:

DumbTab1-example-style-plastique

  • y2base ./DumbTab1.rb qt -style cleanlooks:

DumbTab1-example-style-cleanlooks


So it always stretches the entire width of the tab bar. On that same VM, QDirStat behaves the same as in the previous comment, i.e. some styles stretch the tabs all over the tab bar, some don't.

@shundhammer
Copy link
Contributor

diff --git a/libyui-qt/src/YQDumbTab.cc b/libyui-qt/src/YQDumbTab.cc
index 48e620d9..ee0b6622 100644
--- a/libyui-qt/src/YQDumbTab.cc
+++ b/libyui-qt/src/YQDumbTab.cc
@@ -59,6 +59,7 @@ YQDumbTab::YQDumbTab( YWidget *       parent )
     Q_CHECK_PTR( _tabBar );
 
     _tabBar->setSizePolicy( QSizePolicy( QSizePolicy::Preferred, QSizePolicy::Preferred ) ); // hor/vert
+    _tabBar->setExpanding( false );
     setFocusProxy( _tabBar );
     setFocusPolicy( Qt::TabFocus );
  • y2base ./DumbTab1.rb qt (default style):

DumbTab1-example-default

  • y2base ./DumbTab1.rb qt -style fusion:

DumbTab1-example-style-fusion

  • y2base ./DumbTab1.rb qt -style windows:

DumbTab1-example-style-windows

@shundhammer
Copy link
Contributor

So maybe the default for this QTabBar::setExpanding() changed between SLE-12 and SLE-15 (or between Qt4 and Qt5).

@shundhammer
Copy link
Contributor

Duh; I had looked at the documentation of QTabWidget, but we are using a QTabBar here:

https://doc.qt.io/qt-5/qtabbar.html#expanding-prop

expanding : bool

When expanding is true QTabBar will expand the tabs to use the empty space.

By default the value is true.

This property was introduced in Qt 4.5.

@dgdavid
Copy link
Contributor Author

dgdavid commented May 3, 2021

Testing styles on my Xubuntu 18.04 LTS (Xfce4) desktop with qdirstat -style fusion (which is the default for Qt applications on my desktop) and the window made wider to demonstrate this behaviour:

[...]

Note: In your QDirStat examples, the tab is visually wrapping its content too.

@shundhammer
Copy link
Contributor

Note: In your QDirStat examples, the tab is visually wrapping its content too.

I don't quite understand?!

@dgdavid
Copy link
Contributor Author

dgdavid commented May 3, 2021

Note: In your QDirStat examples, the tab is visually wrapping its content too.

I don't quite understand?!

My fault 😅

I meant that the select tab is delimiting its content better (by using a different background and even a border). See your first screenshots

QDirStat-config-style-fusion

And compare it with the includes ones in the PR's description.

@shundhammer
Copy link
Contributor

That might be one difference between the QTabWidget and the QTabBar.

We could also experiment with those other properties of QTabBar:

@shundhammer
Copy link
Contributor

shundhammer commented May 4, 2021

I did a little software archaeology and a trip down Memory Lane and found out / remembered why we are using a QTabBar and not a full-fledged QTabWidget:

Our widget is called the DumbTab for a reason: It's very dumb. It just acts like a row of buttons on the top of the page, and replacing the content when the user switches to another page has to be done manually on the application level: The DumbTab just sends an event, and the application has to use an internal ReplacePoint to exchange the content.

This was the compromise to make tabs possible in the first place in the context of our YaST UI engine: Geometry management is done on the libyui level, so libyui has to manage the widgets, query their preferred size, add up the sizes of the individual widgets in the hierarchy, calculate how much space is left over or missing, and resize the child widgets accordingly. This is the basic premise of being able to bring the GUI (Qt) and text (NCurses) worlds together.

When we started YaST2, we had no tabs of any kind; it was contrary to the entire idea of YaST which was to provide a simple user interface, collecting information in a sequence of very simple wizard pages.

Of course it didn't take long until somebody wanted tabs, and we had a HUGE discussion about it: On one side those (including myself) advocating simplicity and arguing that a UI that needs tabs is really out of place in the YaST environment, on the other side those who wanted the user to be able to micromanage everything.

The micromanagers won that dispute, and we had to come up with tabs somehow. I offered a compromise: To retain our UI-independent layout engine, provide only very dumb tabs that would act very much like buttons, and use a ReplacePoint so the application can exchange the tab page content.

Thus, the DumbTab was born. It was an accepted compromise that it would be dumb; and oh boy, it was; and it is!

Being dumb was the premise to make tabs possible at all. Being dumb meant we could work around the complications and limitations that a high-level GUI toolkit like Qt would impose on us.

But being dumb also meant a certain extent of ugliness; and that's what we see here.

@shundhammer
Copy link
Contributor

The problem with using a full-fledged QTabWidget is that a QTabWidget uses a QTabBar for the tabs (just like we do) and a QWidgetStack to manage the pages that the tabs correspond to. The QTabWidget manages everything else completely by itself: Geometry management, bringing the right page to the foreground when the corresponding tab is clicked; all those things.

And it adds a little eye candy: Some margin around itself with a slightly contrasting color (a darker color in our default light grey color scheme); and some 3D borders to give the impression of cardboard filing register cards. It's quite subtle, but as you observed, it works to give some visual impression.

And that is what we don't have. We have only the QTabBar and a plain empty widget below; no subtle 3D effect, no different shading. The inactive tabs have a slightly darker shade of color, but it doesn't give much of a visual cue.

It looks ugly. There is no other way of saying that. It's the archetypical case of "if you put lipstick on a pig, it's still a pig". ;-)

@shundhammer
Copy link
Contributor

So I experimented a bit with putting at least some lipstick on that pig. I used the DumbTab2.rb example from yast-ycp-bindings/examples as a base.

First I changed only the dialog size to something reasonable, but that's all:

DumbTab2.rb

DumbTab2-default

Yikes. That thing sure is ugly.

Adding some VSpacing

DumbTab-top-vspacing

This just adds some little VSpacing( 0.4 ) at the top. It's not much of a change, yet it already gives a much better visual impression.

Adding a MarginBox

DumbTab-no-frame

Now it's obvious that we don't have any 3D effect around the content. This looks very much out of place.

Adding a Frame Outside

DumbTab-frame-outside

This is a bit better, but it doesn't feel right: The 3D impression of the cardboard filing card is just not there. The impression falls apart at the top.

And of course we just introduced yet another case of the button not properly lining up with other lines; in this case the frame we just added. This is not a pixel-perfect science.

Adding a Frame Inside

DumbTab-frame-inside

This also doesn't look right, and it has even more alignment problems.


Verdict

Putting lipstick on the pig really didn't magically turn it from a pig into a diva (Miss Piggy might disagree).

As a simple measure, adding a subtle VSpacing just above the DumbTab appears to be the best approach; it doesn't cost us much, and it gives us some improvement.

Mid-term, we could do that in YQDumbTab.cc.

@shundhammer
Copy link
Contributor

shundhammer commented May 4, 2021

Emulate a QTabWidget on the libyui-qt Level?

It's tempting to think along the lines of "wait, we could do that ourselves": YDumbTab already is a children manager widget, albeit only with one single child which is usually a subtree with a YReplacePoint that is used by the application.

It already does some layout management: It has to consider the height of the tab bar and add it to its single child's preferred height.

So we could extend that concept a bit and also reserve some more screen space around the content, and the concrete UI's implementation (YQDumbTab) could draw that 3D border around it to give the proper impression of that cardboard filing card. It could also use a different fill color on the outside to give a better 3D impression.

To do that, we'd have to go down to the low-level widget drawing routines of QStyle and its derived classes and do low-level Qt painting with QPainter and QStyleHints. This is possible, but not easy, and it involves a ton of subtle problems when Qt takes its style from the current desktop's theme, be it KDE Plasma, GNOME or whatever.

So, we could give the pig cosmetic surgery and turn it into a FrankenPig; but even a FrankenPig is still a pig... ;-)

Nevermind the screws on the forehead... ;-)

@dgdavid
Copy link
Contributor Author

dgdavid commented May 4, 2021

@shundhammer,

Thanks a lot for the detailed explanations.

If I understood them correctly, after the DumbTab was born, YaST always has been using it when to place content in tabs Right? If so, why did they look better in SLE 11? What else changed?

Sorry if I overlooked some key detail that already answered those questions.

@shundhammer
Copy link
Contributor

shundhammer commented May 4, 2021

After the tab width is fixed, it acutally doesn't look that much different between SLE-11 and now.

SLE-11 for sure used Qt4, and there were probably some subtle QStyle changes between Qt4 and today's Qt5. If you look closely, they used more contrasting colors for the inactive tabs; but other than that, it's not much different from today.

Edit: I just had another look, and in that yellowish theme they use the same color for the active tab as for the tab content (i.e. for normal widgets), whereas that newer theme in your screenshots has a much lighter color for the active tab. But that's just a matter of that theme; if you look at my screenshots further below, that theme also uses the same color for both (which is what I would expect).

@dgdavid
Copy link
Contributor Author

dgdavid commented May 4, 2021

If you look closely, they used more contrasting colors for the inactive tabs; but other than that, it's not much different from today.

I see a few more differences: a border and a different background for the selected tab content (the same background that the one used for the title)

SLE 11 SLE 15
yast2_users_main_gtk yast-users

@dgdavid
Copy link
Contributor Author

dgdavid commented May 4, 2021

Edit: I just had another look, and in that yellowish theme they use the same color for the active tab as for the tab content (i.e. for normal widgets), whereas that newer theme in your screenshots have a much lighter color for the active tab.

Ah, you updated your comment at the same time I was writing mine :) :) That's what I meant.

But that's just a matter of that theme; if you look at my screenshots further below, that theme also uses the same color for both (which is what I would expect).

So, it'd be nice to know how to fix it at theme level (if possible).

@shundhammer
Copy link
Contributor

Yes, but that's entirely QStyle-related. Some of them are just plain ugly in certain aspects. They gave up a lot of 3D effects; at SLE-11 times it looked much more like the Windows style (see above). 3D effects fell out of fashion in the designer world; today's mantra is flat and monochrome (yuck).

@joseivanlopez
Copy link
Contributor

Thanks @shundhammer, great explanation!

I agree, the "Adding a MarginBox" version seems to be a good option for improving the current dialogs. Stretching the tabs and using the same color for the active tab as for the content help a lot. Anyway, delimiting the tab content with a border could be useful too, for example, for visually associating the buttons with the tab content (e.g., Add, Edit and Delete buttons).

BTW, I see you have a PR #31 for stretching tabs. Do we need more code changes to accomplish the rest of improvements (add extra margins and use the same colors)? Or is it a matter of adapting styles? Do you know what styles (class names, element id, etc) we have to adapt in order to add visual borders in the content of the tab like SLE-11? Thanks!

@shundhammer
Copy link
Contributor

@joseivanlopez : Do you really mean "adding a MarginBox", or "adding a VSpacing"? I find the MarginBox version irritating; it's visually more confusing than doing nothing at all since the 3D effect morphs into a flat grey area.

shundhammer added a commit to shundhammer/libyui that referenced this issue May 19, 2021
shundhammer added a commit to shundhammer/libyui that referenced this issue May 27, 2021
shundhammer added a commit to shundhammer/libyui that referenced this issue May 31, 2021
@shundhammer
Copy link
Contributor

Added to Bugzilla as https://bugzilla.opensuse.org/show_bug.cgi?id=1186705

@shundhammer
Copy link
Contributor

PR: #31

@shundhammer
Copy link
Contributor

Screenshots with the Fix

new-tabs-widget-demo-3a

new-tabs-widget-demo-3c

new-tabs-yast2-bootloader-1

new-tabs-yast2-bootloader-2

new-tabs-yast2-bootloader-3

new-tabs-yast2-lan-01

new-tabs-yast2-lan-02

new-tabs-yast2-users-old-1

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
tracked Tracked elsewhere (Bugzilla, Jira, Trello)
Projects
None yet
Development

No branches or pull requests

4 participants