SkillAgentSearch skills...

Phantomstyle

Cross-platform QStyle for traditionalists

Install / Use

/learn @randrew/Phantomstyle
About this skill

Quality Score

0/100

Supported Platforms

Universal

README

And some say it's still using desktop computers, even to this day 👻

phantom screenshot light

phantom screenshot dark

More screenshots

Phantom Style

Phantom is a QStyle for Qt which began as an overhaul of QFusionStyle. Similar to Fusion, it's designed to be a looks-the-same cross-platform style. It looks native to nobody, but familiar to many. It has the visual appearance of a traditional GUI, and does not adopt a "modern flat" style. Compared to Fusion, it has many fixes, objective improvements, and subjective improvements:

Usage

Built into an application

Add src/phantom/phantom.pri to your qmake .pro file for your project. There are no additional dependencies. It's also safe to construct a PhantomStyle object before instantiating a QApplication, because it doesn't interact with the environment or anything else.

As a QStylePlugin

A style plugin is available: phantomstyleplugin.pro

Compatibility

Tested on Qt 5.9 and later, but should work on earlier versions as well. Builds with MSVC (tested with 2017), GCC and clang.

Uses auto from C++11, so C++11 is needed. C++14 and later are not needed.

Changes from QFusionStyle

  • Fixed many code and logic errors: unaligned reads/writes, dead and unreachable code paths, redundant allocations, unused variables.

  • Fixed many drawing mistakes: filled regions which are never seen, off-by-1 and misalignment, unnecessary QPainter transformations, unnecessary use of anti-aliasing for solid rectangles, misaligned arrows in scrollbar buttons and spinboxes, garbage lines and artifacts in the grooves of scrollbars.

  • Fixed bad drawing at high DPI: QPen lines which are misaligned, incorrect line thickness, broken and interrupted lines between connected elements (tabs and tab bars, etc.), misaligned or disconnect outlines and their associated inner fills, incorrect scaling of certain parts of a shape and others unscaled, unnecessary use of QPen anti-aliased lines to draw straight rectangles of constant width.

  • Fixed bad drawing in right-to-left layout: borders and outlines on the wrong side of rectangles (headers in item views, spinboxes, line edit borders), edges and off-by-1 adjustments made to bounding rectangles (tab frame and tab shapes, menu bar rulers, toolbar separators, grip handles), misalignment of icons and shapes (indicators in menu items, check boxes, radio button labels), clipped and invisible text (progress bar labels.)

  • Fixed broken metrics and sizing calculations for menu items, which over time lead to QFusionStyle having to have more and more "safety space" added to the horizontal size of menu items to avoid clipping stuff off. Phantom has correct sizing of menu items, and doesn't make menus any wider than necessary.

  • Replaced many constant sizes and pixel metrics with font-based calculations: menu items (and more) now derive their metrics from the font being used, so that they look more consistent across platforms which may use fonts for menus that are distinct from other widgets. A constant, even when DPI scaled, may give too little or too much space when the font size varies across a larger range than you predicted.

  • Removed all use of QPixmapCache.

    • QFusionStyle would aggressively cache the results of drawing certain shapes (buttons shapes, for example) based on the input parameters of the style option (size, state, palette, etc.) While this would speed up subsequent repaints with the same input parameters, the initial painting is slower.

    • QFusionStyle's use of QPixmapCache would lead to full occupancy of the global QPixmapCache almost immediately: create a window with a few buttons, then drag-resize the window. Within a few moments, all 10 megabytes of the default QPixmapCache have been filled. Not only does this bloat memory usage if the QPixmapCache would otherwise not have been used, but it causes legitimate uses of the QPixmapCache to have their contents evicted on a regular basis.

    • QFusionStyle's use of QPixmapCache requires allocating and deallocating string keys alongside what should have been simple painting operations.

    • QFusionStyle's generated cache keys were too fragile: in several cases, the cached pixmap would never be re-used, because the calculated cache key would never be the same on subsequent calls to draw the widget.

    • PhantomStyle draws significantly faster than QFusionStyle, and the caching is no longer needed.

  • Removed all use of gradients and explicit alpha blending.

    • QPainter has no color management, and on pixel buffers, blends in unmanaged 8-bit color. This means that blending operations between two colors (for example, a gradient, or an alpha blend of one color on top of another) produce unintuitive results. While your gradient that you chose and tested with a light color scheme might appear fine, when used with a QPalette with darker colors, the results may have far too little or too much contrast. Hue shifting and unintended darkening or lightening also may occur.

    • QPainter has no dithering capabilities, so banding would occur.

    • QPainter's gradients and alpha blending are slow.

    • The alpha blending done by QFusionStyle was almost always between two constant colors that were known ahead of time, such as a shadow on top of a base color, or a groupbox background on top of a window. The resulting blended color could instead simply be calculated ahead of time and painted as a solid rectangle, which is faster and can be color-corrected.

    • Overuse of gradients makes QFusionStyle look like it's from a specific time period (mid-2000s) instead of no time period at all.

    • Note that hue shifting and lightness shifting will still occur on the edges of anti-aliased shapes, like roundrect corners. This can only be solved by QPainter being changed to perform color-correct blending.

  • Changed derived color calculations to use CIELUV-like colorspace

    • QColor's .darker() and .lighter() were used by QFusionStyle to calculate derived colors from another color. For example, outlines on a box, or highlights on the inside of edges. QColor's .darker(), .lighter(), .lightness(), and other functions have no rigor or defined meaning -- the numbers are arbitrary and the output is unpredictable except when the input color is similar to whatever the programmer or designer tested it with. Using .lighter(120) on a near-black color will produce a different amount of contrast than .lighter(120) on a brighter color.

    • PhantomStyle instead uses a pseudo-CIELUV colorspace to derive its colors, provided by some core code from the hsluv-c library. While not perfect, it's a significant improvement, and allows PhantomStyle to more consistently work with both light and dark QPalettes.

  • Removed many implicit QPen and QBrush allocations caused by calling setBrush() and setPen() with QColor arguments. Instead, QPen and QBrush instances are now persisted in a small cache (in small flat array, not a QHash) that uses an accurate QPalette hash key calculation. (QPalette::cacheKey() is not used, because it is prone to changing even when the underlying values are the same.) This saves many, many small heap allocations that would occur when QFusionStyle was performing painting operations.

  • Disabled animations.

    • Though there are not many uses of animations in QtWidgets, they could cause problems. For example, dragging a QToolBar from its location in a QMainWindow to another location would attempt to animate the layout changes in the UI. But for complicated UIs in a large window, this would be too slow to re-layout and repaint in realtime, and the UI would freeze up during the time it should have been animating. This could cause the drop zone detection to give incorrect results, and then the UI would both stutter spastically and repeatedly freeze up during the drag operation.
  • Disabled and removed most mouse-over/hover repainting.

    • QFusionStyle, for many widgets, would paint with different colors when the user moused over certain elements, like buttons. However, on modern composited desktops and especially when combined with event coalescing and hardware-accelerated mouse drawing that skips the main compositing path, this would cause the repainting of widgets to appear to occur long after the mouse had already passed over the widget. The result would be a subtle and persistent feeling of lag throughout in the UI.

    • For some widgets, QFusionStyle's alternate painting in the mouseover state was either not noticeable or identical, resulting in redundant repainting and event dispatching as the user moved their mouse cursor across the UI.

    • Qt::WA_Hover and alternate painting is still used where it makes good sense: menu items, tool buttons, and a few other cases.

  • Fixed style hints which affected the operation of QMenus.

    • QFusionStyle specified "sloppy" submenu closing via SH_Menu_SloppySubMenus, but didn't also specify that the submenus should not be closed after a timeout if nothing else is moused over (SH_Menu_SubMenuDontStartSloppyOnLeave). It also did not specify SH_Menu_SubMenuUniDirection and several other hints which should have been specified, which would cause the reactions of a QMenu t

Related Skills

View on GitHub
GitHub Stars332
CategoryDevelopment
Updated20d ago
Forks41

Languages

C++

Security Score

100/100

Audited on Mar 6, 2026

No findings