Substance comes with built-in support for animating state transitions for the core Swing components, as well as for all the Flamingo components.

Let’s take a look at this screenshot from the component states documentation:

Here we see how one of the Substance skins (Office Silver 2007) provides different visuals for different component states – light yellow for rollover, light orange for selected, deeper orange for pressed, etc. As the component – such as JButton in this case – reacts to the user interaction and changes state, Substance smoothly animates the visuals of that component to reflect the new state. In the case of our JButton, that includes the inner fill, the border and the text.

This comes particularly handy for skins that mix light and dark visuals for different states of the same component. Here is the same UI under the Magellan skin:

Note how the selected button uses light text on dark background, while the rollover selected button uses dark text on light background. If your UI uses the Magellan skin (or any other skin that uses a mix of light and dark color schemes), Substance will do the right thing to animate all relevant parts of your UI as the user interacts with it.

What about the icons?

This is a screenshot of the main Substance demo app running under the Nebula Amethyst skin. As UIs with lots of icons can get pretty busy, Substance provides APIs to theme the icons based on the current skin visuals.

The APIs are in the SubstanceCortex class, one in the GlobalScope to apply on all icons in your app, and one in the ComponentScope to configure icon theming for the specific control:

  • SubstanceCortex.GlobalScope.setIconThemingType for global icon theming
  • SubstanceCortex.ComponentScope.setIconThemingType for per-component icon theming

At the present moment, two icon theming types are supported. The first is SubstanceSlices.IconThemingType.USE_ENABLED_WHEN_INACTIVE which works best for multi-color / multi-tone icons and Substance skins with multi-color color schemes. Here is the same UI with this icon theming type:

Take a look at the icons in the toolbar. The icon for the active / selected button (bold A) is still in full original color, but the rest of the icons have been themed with the colors of the enabled color scheme configured for the toolbar area of the Nebula Amethyst skin. This work well in this particular case because:

  • The original Tango icons have enough contrast to continue being easily recognizable when they are themed in what is essentially a mono-chrome purple color palette
  • Nebula Amethyst skin uses color schemes with different background colors for the ultra light to ultra dark range, so that when these colors are used to theme the original icons, the icons remain crisp and legible.

The second option is SubstanceSlices.IconThemingType.FOLLOW_FOREGROUND which works best for single-tone icons found in such popular icon packs as Material, Ionicons, Friconix, Flexicons, Font Awesome and many others:

In this screenshot of the same UI from earlier under the Magellan skin, all the buttons use the same help icon from the Material icon pack converted by Photon. At runtime, Substance themes the icon to follow the foreground / text color of the button for a consistent look across all component states.

Any day now

October 13th, 2020

Checking in on an earlier post from last year on being skeptical on the whole self-driving cars thing, I got reminded of this article from last April and the quote from Elon Musk:

As for full autonomy, Musk noted: “the software problem should not be minimized.” He continued that, “it’s a very difficult software problem.” Still, he promised that Teslas will be capable of self-driving by the end of this year and self-driving robo-taxis will be on the road in 2020. Also, in two years, the company will be making cars without steering wheels or pedals at all.

“If you fast forward a year, maybe a year three months, we’ll have over a million robo-taxis on the road.”

Usually futurists give themselves a bit more breathing room, say 25-30 years. By which time they are either no longer with us, or can claim to have been let down by the inept technologists who have failed to deliver on their “vision”. In this particular case though, Tesla is barely struggling to get to level 2 which is basic, partial automation. We’re quite a long way off from a million robo-taxis on the road.

In the meanwhile, Tesla’s official page on autopilot is using some clever wording that makes it seem that they are already at full self driving level 5 (highlights mine):

All new Tesla cars have the hardware needed in the future for full self-driving in almost all circumstances. The system is designed to be able to conduct short and long distance trips with no action required by the person in the driver’s seat.

All you will need to do is get in and tell your car where to go. If you don’t say anything, the car will look at your calendar and take you there as the assumed destination or just home if nothing is on the calendar. Your Tesla will figure out the optimal route, navigate urban streets (even without lane markings), manage complex intersections with traffic lights, stop signs and roundabouts, and handle densely packed freeways with cars moving at high speed. When you arrive at your destination, simply step out at the entrance and your car will enter park seek mode, automatically search for a spot and park itself. A tap on your phone summons it back to you.

Sprinkle a few “will”s in there, and you make it sound like it’s yours once you buy one of their cars. While the press kit is a bit more realistic, bringing it down quite a few notches (highlights mine):

Autopilot is an advanced driver assistance system that is classified as a Level 2 automated system according to SAE J3016, which is endorsed by the National Highway Traffic Safety Administration. This means Autopilot also helps with driver supervision. One of our main motivations for Autopilot is to help increase road safety, and it’s this philosophy that drives our development, validation, and rollout decisions.

Autopilot is intended for use only with a fully attentive driver who has their hands on the wheel and is prepared to take over at any time. While Autopilot is designed to become more capable over time, in its current form, it is not a self-driving system, it does not turn a Tesla into an autonomous vehicle, and it does not allow the driver to abdicate responsibility.

So maybe, at some point in the future, it “will” be there. But not any day now, despite the ongoing barrage of lofty promises.

The future of movie theaters

October 8th, 2020

There’s a lot of things going on in the world, and in this little (more on this in a moment) corner of the world, one recent article brought together a few points that have been on my mind recently. As the nature of trade organizations go, they are paid to represent the interests of that particular slice of market. Sometimes it invariably means that you end up, wilfully or not, misrepresenting the reality in order to put your bosses in the most favorable light possible. Here is the head of NATO (the other one, National Association of Theatre Owners) talking about big budget movies going to streaming services:

I really don’t get the big budget movie going straight to a streaming service business model. I don’t exactly know how Disney made out with “Mulan,” but I don’t think it was a gigantic success financially. In a premium VOD model, you have to hope that people will pay $20 to watch a movie at home. Maybe that will work during a pandemic, but you won’t have the same kind of profits that you get when you have a standard theatrical release.

That sounds like a nice, awfully round number, that surely has lots of relevant research to back it up. Let’s try and unpack the numbers.

The average price of a movie ticket in US in 2019 was just over $9. Where does that money go? Turning to the excellent series of articles by Stephen Follows (here and here), we can see that around half the money left after paying the sales tax goes to the movie theater itself. There’s also distributor’s fees (which are quite high in overseas markets), sales agents fees, paying back investors etc. The big studios never talk about these numbers publicly, but I think that they are maybe seeing somewhere between $1 and $3 from the movie ticket price itself.

If that big budget movie cost $100M to make, that’s an awful lot of movie tickets to sell to cover not only the cost of making the movie, but also the cost of marketing and promoting it (that can be anywhere between 50% and 150% of the cost of making it). You need to make somewhere around $300M to get your initial investment back and start making profit. It’s no wonder that the big studios (Universal, Paramount, Warner, Disney and Columbia) have been taking fewer bets on new big stories without any “proven” track record, and instead churning out yet another installment and yet another sequel and yet another spin-off in the same universe. It’s also no wonder that these big studios are just small subsidiaries of much larger entertainment conglomerates. How much larger?

Domestic box office in 2019 was $11.4B, and globally it reached $42.5B. Now, again, this is not something that goes straight to the studios’ revenue column. Take away the 50% that the movie theater takes, take away another 20-30% that the overseas distributor charges you, take away all the additional fees detailed in Stephen’s posts, and maybe, just maybe you can put $10B collectively into the revenue column.

Universal is part of NBCUniversal which is, in turn, part of Comcast. Comcast revenue for 2019 was $108.9B. Paramount is part of ViacomCBS. Warner is part of WarnerMedia (along with HBO and CNN) which is, in turn, part of AT&T. AT&T revenue for 2019 was $181B. Disney (after having acquired Pixar, Marvel, Lucasfilm and 20th Century Fox) ruled the domestic market in 2019 with almost 40% share, and the parent conglomerate reported the revenue of $69.5B for 2019.

In the global scheme of things for these entertainment conglomerates, the movie business per se is almost a rounding error in the corporate spreadsheets. Not releasing “Wonder Woman 1984” or “Fast & Furious 9” is not going to be the end of them. And they can still continue doing that sweet cross-promotion thing by selling toys and other branded merchandise. But I digressed a bit. Let’s go back to the business of running a movie theater.

Apparently though, you’re not really in the business of running a movie theater. You’re actually in the business of selling ridiculously overpriced popcorn, candy and soda. So much so, in fact, that the coalition of the biggest and most popular movie theaters in San Fransisco is refusing to open up their doors if they are not allowed to charge the insane 400-500% markup for their stale popcorn, run-of-the-mill candy bars and soda cups that are filled to the brim with ice cubes. Even though the movie theaters are taking 50% off the top of every single ticket they are selling, they can’t turn a profit without the concession stand! But I digressed again. Let’s step back a bit more.

It used to be that the movie theater was the only viable screen to watch those big stories on. Well before the age of smartphones and dirt-cheap tablets, the TV screens were just not good. They were tiny, they were grainy, the picture was weirdly distorted, the colors were off, and that’s just off the top of my head. But that time is long gone, at least for the vast majority of viewers domestically and internationally. Yes, the initial investment of hundreds (and sometimes a couple of thousands) of dollars into a decent widescreen flat TV and a high-speed Internet connection is needed. But that has happened gradually over the last decade already.

There’s so much great content that is only available outside of the movie theaters. Just to throw a few names out there. Game of Thrones. Black Mirror. Ozark. Stranger Things. The Handmaid’s Tale. Westworld. Watchmen. Is there anybody out there refusing to watch one of these shows because they are not in the movie theater? Was “Interstellar” so much better in IMAX when you had to share it with a group of teenagers just a couple of rows ahead that were constantly on their phones? Was “1917” that much better on the big screen when a young couple have brought their screaming baby in because they didn’t – or couldn’t – afford the babysitter for the night? For that matter, was it worth paying $50 for the babysitter back when “Avatar” came out in 3D and the theaters were packed to the brim? I watched all of these again and again on my TV at home, and the size of the screen simply didn’t matter. And I’m not even talking about movies that I never watched in a movie theater. Movies like “North by Northwest”, “Key Largo” or “The Philadelphia Story”. Or more recent ones like “The Neon Demon”, “Moonrise Kingdom” and “Crimson Peak”.

“Mulan” is an amazing deal at $30. It’s a family movie. A family of four would pay $36 for the tickets, but also at least another $20 for the concessions. But let’s be realistic. It’s not another $20. It’s more like another $30 or $40. For something that you can literally get at $8 in your local grocery story. The exact same thing. But I digress again.

Disney gets to keep all of that money except for the tax. Instead of getting maybe $8-10 from that family of four, it gets to keep all of it. Sure, it might not see the same huge numbers that it used to see from the theatrical releases in the last few years, but if it makes back the same money, what difference does it make to Disney? It doesn’t even need to sell as many “units” to as many people to get the same profit. It already has a digital delivery platform – same as all the other big studios. It can afford to lose half the viewers (individual ticket buyers), and will still get the same money on its balance spreadsheet.

From Disney’s perspective, they are cutting out so many middlemen. Including the one that is the focus of this story. The one that claims to be such an indispensable part of the entire industry, and yet the one that can only turn profit by charging insane markups on concessions.

We’re in the middle of a global pandemic. It is dramatically accelerating changes across so many industries. The push and pull between the studios, the theaters and the streaming platforms was there all along in the last few years. It might have taken another 10-15 years to start cutting out the middlemen, to have the studios forge more immediate relationships with their customers – us, the viewers.

A part of me wishes that the studios were a bit more desperate to release the big blockbusters that were scheduled all through 2020 and then postponed again and again. A part of me wishes to see what kinds of innovations we might see down the road when going to a movie theater is not considered to be a vital part of releasing a movie. Does Disney make some sort of a Marvel Pass that lets me in on all that franchise movies and shows for a flat $50 a year? Do I get a refund if I stopped watching a movie partway through because I didn’t like it? Do I get some sort of a discount for watching the next “Fast & Furious” if I already paid the full price for the last one?

Back to the original quote, one last time. We only have one data point so far. Disney is charging $30 to watch “Mulan” at home. It’s a family movie. So it’s more like $7-8 per person for a family of four. And you save yourself another $25-30 by getting your own soda and popcorn. Netflix is certainly not charging people per show. In my bright future where I can get any new movie I want on the day it is globally available, it’s probably going to be closer to the current rental price. Maybe $5 for a mid-budget one, and around $10 for one of those big blockbusters. Because you don’t need to charge more when you cut out that concession-stand middleman out of the picture.



Radiance 3.5.0

October 5th, 2020

It gives me great pleasure to announce the fifth major release of Radiance. Let’s get to what’s been fixed, and what’s been added. First, I’m going to use emojis to mark different parts of it like this:

💔 marks an incompatible API / binary change
😻 marks new features
🤷‍♀️ marks bug fixes and general improvements

Dependencies for core libraries

  • Gradle from 6.4.1 to 6.6.1
  • Kotlin from 1.3.72 to 1.4.10
  • Kotlin coroutines from 1.3.7 to 1.3.9


  • 💔 Remove support for watermarks
  • 💔 Convert SubstanceSkin.ColorSchemes into an interface
  • 😻 Support for overlay colors with SubstanceSkin.setOverlayColor
  • 💔 Support for specifying derived colors in color scheme files
  • 😻 New API to mark a label as title pane text
  • 😻 Text highlights that respect decoration areas
  • 💔 Moved the Green Magic skin from substance-extras to the core substance module (see the screenshot of this skin above)
  • 💔 Aligned signatures of ComponentState.getActiveStates and ComponentState.getAllStates
  • 🤷‍♀️ Improved menu search widget UX
  • 🤷‍♀️ Correct layout for edit context menu under RTL
  • 🤷‍♀️ Fix concurrent modification exception thrown when ghost icon animations are enabled


  • 💔 Pass command projection instead of command in ribbon contextual menu listener
  • 💔 Remove AbstractCommandButton class. Everything is in the JCommandButton class now.
  • 😻 New CommandButtonPresentationModel.Builder.setPopupHorizontalGravity API to contol horizontal alignment of command button popups
  • 🤷‍♀️ Fix crash in opening a command popup menu from taskbar
  • 🤷‍♀️ Fix memory leaks caused by model listeners
  • 🤷‍♀️ Fix for root key tip chain not showing popup key tips of anchored commands
  • 🤷‍♀️ Fix for overlays on ribbon popup content in the title pane / taskbar


  • 🤷‍♀️ Fix inconsistent usage of conversion from duration fraction to timeline position

This release has mostly been focused on stabilizing and improving the overall API surface of the various Radiance modules. There’s still a long road ahead to continue exploring the never-ending depths of what it takes to write elegant and high-performing desktop applications in Swing. If you’re in the business of writing just such apps, I’d love for you to take this Radiance release for a spin. Click here to get the instructions on how to add Radiance to your builds. And don’t forget that all of the modules require Java 9 to build and run.