Feature - Implemented Req: Dark Theme (from InfoPowerBroker)

MCroft

Developer
Staff member
This request got posted in community support but belongs here.

I use Darkmode in a number of places and would happily try it with KoLMafia if it were working well.

Implemented. Please enter bugs/findings/things I missed/suggestions here or create a new bug thread.

Usage: New Themes are available in Preferences>Look&Feel>Java L&F
Notes:
  • If your fonts are too small, please change Preferences>Chat Options>Use medium (or large) fonts in hypertext displays.

I added Darcula (infopowerbroker's suggested LaF) with incomplete results, in part because I think we need to think through how it works.

The simple test:

  1. add the darcula jar to lib/jar
  2. add import com.bulenkov.darcula.*; to KoLmafia.java
  3. addUIManager.installLookAndFeel( "Darcula", DarculaLaf.class.getName() ); near the top of initLookAndFeel() in KoLmafia.java

So far so good...
Dark Mode Gear Changer Tab.png

The findings:

  1. It throws a warning (WARNING: Illegal reflective access by com.bulenkov.darcula.DarculaLaf )
  2. The title of the pages is missing.
  3. The pastel sidebar is disturbingly bright with dark mode
  4. Taskbar Icons are not well-suited to dark mode
  5. gCLI is still white
  6. The design would require KoLmafia to maintain a list of acceptable add-on look-and-feel JARs and hardcode it.

The warning is my biggest concern; I don't like the idea of borrowing trouble for later.

I'm sure I can figure out the title bar thing, but it keeps me from doing a lot with the game in this state.
3-5 are cosmetic
6 is a real sticky point for me. What I'd really want to do is have some directory of LaF jars that are detected at launch and all registered so that the user can select them from the prefs. We may already have that and I don't know how to do it.
 
Last edited:
Long ago I tired to play with "global" Swing settings applied to mafia. It did not end well which may say much about my abilities with Swing. I had problems just changing a Look and Feel. There were mafia components that hardwired things that the L&F would have set so they remained the same when the L&F changed. I had similar failures trying to change font sizes.

External jar files raise some issues. If we bundle them (which is pretty much what we do now) then every user gets them and the size of the jar file increases. That may not be a concern in the First World with fast and unlimited internet connections but every so often someone comes along with a case where the jar size is a problem for them. If we don't bundle them then we need a mechanism for automagically fetching them for the users who need them.

If we do bundle then we probably should check licensing. Not every license that allows use allows bundling IIRC.

Several years ago using maven for builds was a workable solution. At build time you could specific a repository and a version number of the jar file. maven would fetch it and then use it to build. I think packaging the app for distro had the option of "bundling" the files or letting the user fetch them from the repository at install. I spent a little time looking at maven and mafia but gave up because it would have meant I was the local expert in maven and that way lies danger.

There is third party code where we rebuild from the source. Some of that is because we needed changes to make things work. Some of that is because there was no jar file being built by others for distro. If there were a project to create KoLMafia - The Next Generation I might avoid using third party source directly. I'd also reread the modern equivalents of Head First Design Patternsand Effective Java first.

I wonder if the Warning is related to a difference in the Java version we specify and what it expects?

2-4 remind me of the kinds of things I found when I was trying to use other look and feels. It would be interesting to switch to a look and feel that is already installed/built in and see whether those problems exist. If yes then they are probably mafia problems. If not then perhaps Darcula is not ready for mafia.

I think the gCLI is not a standard display controlled by Java L&F but rather something that renders HTML. So having it remain white is kind of expected.

A minimal plugin architecture could be implemented. For L&F it would scan a known directory, assume every jar there was a L&F jar and go through some magic to register a L&F. I'm not sure I am smart enough to do that now, in a way that the potential for malicious use was minimized. When I dealt with it in the past there really was no security. It was a commercial app and it was assumed that plugin writers were trusted. A plugin capability raises some of the same issues that embedding python raised.

One last point. Almost a decade ago we used jsmooth to package a release as a Windows exe. At the time, jsmooth could only deal with one jar file. If we still have a requirement to package things as a Windows .exe that restricts our options.

Bed time.
 
Having looked more closely at their site, the warning is a Java 9+ problem that they're aware of but haven't released a fix for.

One solution to the "how do we not package these things?" is to use a solution similar to scripts and TCRS that lets users fetch them from ... somewhere. That avoid big downloads and jsmooth problems. But has its own set of issues, I'm sure.

I used the built-in metal/nimbus L&F prefs and they had title bars. So it's a Darcula issue, probably. They're not the only dark-mode L&F in the sea, but Darcula is being used by IntelliJ, so there's some way to resolve the issue.

When we switch L&F in prefs, we don't reload the UI, which is probably a fixable bug and probably only worth fixing if we do go ahead with a darkmode change.
 
Oh, good. There's a replacement that doesn't have the error and doesn't have the problem with the menus.

I've now tried "FlatLaf" from FormDev Software. No errors with Java 13, requirement is 8+, and includes two dark modes and a Light mode.

License is Apache 2.0, source is on Github.
The cosmetic concerns are still there, and the management/expansion/bloating is still an issue, but it can be done if we figure out how we want to do it.

The light mode is really nice, actually...
Darkmode main Interface.png Screen Shot 2020-10-11 at 10.33.21 PM.png
 
One solution to the "how do we not package these things?" is to use a solution similar to scripts and TCRS that lets users fetch them from ... somewhere. That avoid big downloads and jsmooth problems. But has its own set of issues, I'm sure.

Yeah. I would research this just a bit. The Java security model doesn't really want the user to load classes from arbitrary jar files. There are conventions and OS level settings that can allow this but since I am lazy and reluctant to introduce things that could break I'd probably just embed the jar file and deal with the size complaints as they arise. Indeed that might be an interesting project - does KoLmafia still need all of the embedded jars?
 
I have been tormented by editing my post on mobile again. It just deletes it every time.

Anyway, I tried this many times with GTK dark mode and found, as frono did, that some controls are hard coded somewhere I can't discern.

If you need any help with this please let me know, I'm in full support!
 
Thanks, I'll definitely need help with this. For instance, I only know I can make it work on MacOS so far...

If you want to play with it, there's about 2 lines and a new jar to get to pull it in.
add the FlatLaf jar to lib/jar
add import com.formdev.flatlaf.*; to KoLmafia.java
add
UIManager.installLookAndFeel( "FlatMap Dark", FlatDarkLaf.class.getName() );
UIManager.installLookAndFeel( "FlatMap Darcula", FlatDarculaLaf.class.getName() );
UIManager.installLookAndFeel( "Flat Light", FlatLightLaf.class.getName() );
near the top of initLookAndFeel() in KoLmafia.java

I think there are three things to do, assuming we go with the "add this to the jars directory" method. It adds 500-ish K, which is a trade-off

0: get the Laf working. Yay, it does! Mostly.
1: identify anything that still needs to be done and decide if we want to do it.
1.5: decide if that amount of work is worth it. Sounds like there is interest, as long as it doesn't get too hairy.
2: change the prefs to select the LookandFeelInfo.getName() instead of LookandFeelInfo.getClassName().
3: get the prefs change to apply when applied, rather than when we feel restart.

2 and 3 are required, but are worth fixing on a "while it's getting fixed..." basis.

Unfortunately, Item -1 is fix the build system on my laptop, which is reporting that it can't find the FlatLaf jar for some reason.

Beyond that (possibly beyond 1.0 and possibly beyond 'ever'), I am wondering about the possibility of sets of text colors, either "light" and "dark" or allow the user to save them per-theme basis. FlatLaf has a "isDark()" method for their Lafs, but its not universal. We might have to store our own little mapping. And while I was looking at it, font color changes are also not getting updated when the prefs are changed. Fixing #3 can also probably be applied to fixing that...

There are also FlatLaf customizations (e.g. do we want separators between tabs)? that could be added if we had strong opinions about separators between tabs...
 
While waiting to figure out your build system you can always change the L&F to to something already supported and try and identify elements that ignore L&F. It can't hurt to fix them whether we go dark or not and our inability to fix them may influence the success potential. Point me in the right direction and I might even be able to make the component obey.
 
I don't think there's a lot to fix, but I could definitely use some additional eyes on the project.

I think there are some masking issues with icons, and we might want higher-res icons, if there are any such available.

I did a once-through of the menu items to see what had a big white space. It's the gCLI, FamiliarTrainer, Trophy Arranger, Mini-Browser, Council of Loathing, and chat. Also the background on CustomCombat>Special. I think that's a list of "places KoL shows you HTML", so it's not surprising. Not sure it needs fixing. Maybe something with a transparent background so we can just let the box's dark, light, or grey color bleed through? Maybe nothing and we say "yep, that's how it works"...

The default font colors aren't great for dark mode, but that's user-configurable (with the same need-to-invalidate the gui to get it to repaint as the Laf in the first place). My solution post-version-1 is what I suggested above, which would be to have a set of font colors that worked well that we could switch to.

The Christmas colors on the sidebar don't bother me as much as I'd've thought, but it might be nice of those were configurable, probably in the same dark/light config

There's a thing that MacOS does, that's fixable in the Info.plist, where you have to set NSRequiresAquaSystemAppearance to No (or you get a stylish grey title bar instead of a stylish black title bar). You can't do that trivially for the jar file, but you can add it to your command line. Or we can find out how IntelliJ fixed it and do that. :).
 
please test!

TIL (at 3AM) -- the importance of not updating SwingUI frames on the main thread.
TI(also)L (at 10AM) how to use SwingUtilities.invokeLater() with a nice lamda function to let Swing do it the Swing way. :)

Task status
-1: fix the build. Build fixed. This was broken by this change, because IJ is too smart. ANT cannot use reflection to get the class name from a library jar at compile time, but IJ can. Fixed by just using a string.
0: Still works.
1 & 1.5: I could definitely use beta testers to determine what else needs to be fixed before this is landed. Please try the attached patch file.
2: Display name not class done. Doesn't change how we store it, just how we display it in prefs. Had to fiddle a bit to get the setSelected part to work.
3: refresh on change. done. used preference listener.

get the flatlaf jar (I used 0.43), Apply the patch, and you can change themes with wild abandon, including to two different dark variants (or we can get rid of one if we don't like it).
View attachment LookAndFeel.patch

It's Apache 2.0 licensed, so if we have to add license text somewhere, we'll want to do that when we land it.
 
Last edited:
Oh, and poking around the FormDesigner FlatLaf page, they have implemented themes, so we could, too (in the future, if we wanted to).

They resolve a lot of Frono's issues by using a .json.theme definition to allow them to be installable.

Anyone who wants to carry that football can look here.
 
Last edited:
Licenses go into lib/licenses.

Code to handle those goes in swingui/listener/LicenseDisplayListener.java.
I made an effort to update that with newly added software, a while ago, but I don't know why it doesn't show every single license from the licenses directory.
 
Licenses go into lib/licenses.

Code to handle those goes in swingui/listener/LicenseDisplayListener.java.

I still 100% do not know how to make a patch using svn diff that includes a file that hasn't been added to the source tree. I'm sure it's possible, but until then, here's two files...

View attachment LookAndFeel_v2.patch and View attachment flatlaf-license.txt
I made an effort to update that with newly added software, a while ago, but I don't know why it doesn't show every single license from the licenses directory.

It's doable, assuming none of those licenses are "source code only" things.
 
Well, the good news is that I found where to fix the white background for the elements, and it makes sense to get rid of the hardcoded value...

Just comment out 1 line in RequestPane.java's constructor.
Code:
// Ensure that the background is off-white so that the
// text is always legible.

[COLOR="#FF0000"]//[/COLOR] this.setBackground( new Color( 252, 252, 252 ) );
Screen Shot 2020-10-13 at 4.24.43 PM.png
 
I think there are some masking issues with icons, and we might want higher-res icons, if there are any such available.

I mentioned this to Aenimus and he'd be happy to either mock up some higher-res KoL style icons (or indeed not KoL style if that would be better), but he'll respond on here later.
 
Well, the good news is that I found where to fix the white background for the elements, and it makes sense to get rid of the hardcoded value...

Just comment out 1 line in RequestPane.java's constructor.
Code:
// Ensure that the background is off-white so that the
// text is always legible.

[COLOR="#FF0000"]//[/COLOR] this.setBackground( new Color( 252, 252, 252 ) );
View attachment 9891

Cool. If you do that does the L&F both set the background and assume some responsibility for legibility? That means the L&F's default background and text color are compatible?
 
L&F doesn't promise you that you can't set purple-text on a purple background, but all the backgrounds I checked (all the built-in ones plus the 3 from FlatMap) were readable to me. Above is a screenshot of FlatMap Dark Laf showing the gCLI Frame.

Below is some of our colored text in the gCLI. It might affect people who use ash scripts and set their own colors for text, but they could adjust their scripts or use a different L&F. Primary colors pop.
Screen Shot 2020-10-13 at 6.32.21 PM.png

Since we're curating the Laf's we allow, I think it's reasonably safe to say that we wouldn't put one in that caused a problem with the background/foreground.

I have some problems with the colors for item crappy/fair/good/better/best/epic/whatever/ludicrous, but KoLmafia has a preference for setting those.
 
L&F doesn't promise you that you can't set purple-text on a purple background, but all the backgrounds I checked (all the built-in ones plus the 3 from FlatMap) were readable to me.

That's what I wanted. If a default works that is the promise I wanted.

We might make this happen. How cool is that?
 
List of issues I've seen:
1: Icons. Previously mentioned.
2: Maximizer "Other options available..." text wraps and cuts off half of line 2.
3: Game Description Window effects are Bright Blue and Bold. This is not coming from prefs.
4: AdventureFrame has a fixed width, and so does AdventureSelectPanel. This seems to cause a problem with the size of the adventure count field. It all fixed itself when I resized the window, so it might've been me.
 
Back
Top