• Updated 2023-07-12: Hello, Guest! Welcome back, and be sure to check out this follow-up post about our outage a week or so ago.

Kaleidoscope Scheme to Appearance Theme Conversion

Dennis Nedry

Well-known member
Some very VERRRRY preliminary hacking. The scope of this project shall not include hacking of any Kaleidoscope specific resources until permission is granted or some other justifiable reason. This initially intends only to convert ics8, ics# and cicn resources into pxm# resources. Consequently, themes that utilize the wnd# resource, such as Scherzo, shall not be convertable within this scope, because this requires the electronic parsing of a wnd# resource in a program other than Kaleidoscope, which is apparently forbidden somehow. But we don't have to worry about that yet, there's plenty that we can do without touching that.

So far, it loads a k-scheme resource file into memory, then converts ics8 and ics# window widget resources from memory into their respective pxm# resources. These pxm# resources are a lossless conversion, so they must reference an 8-bit system color palette stored in 'clut' ID 128 (not included). This 'clut' resource is apparently not included in the System file (surprising), so you can get it from inside of Resourcerer's own resource fork, clut ID 72, if you wish to copy the generated pxm# resources into a working theme. Note that you will also probably have to add clut ID 128 to the tdat resource of the modified theme. Details, details....

During the conversion, the new 'pxm#' resources are written to an output text file, output.c. At the end of all conversions, the 'tdat' resource is built and stored in there as well. Output.c is in such a format that it must be built with "Rez", which can be found in /Developer/Tools/ in your Xcode installation. This will turn it into a resource file that can be opened with ResEdit or Resourcerer. This is much easier for me than trying to directly create a resource fork.

Next to do is parsing 'cicn' data. That is a bit of a project in itself due to different color depths. Themes do not support alpha transparency, so schemes that use alpha transparent 'cicn's will not ever be able to be converted properly without creating a system extension. But alpha transparent cicns only work with wnd# resources I think, so for we're probably in the clear for that. Alpha transparency, custom cursors, selectable color variations, and selectable checkbox styles are all of the features of k-schemes that are not supported in themes as far as I am aware. Neither support the Right-to-left interface that is found hidden in themes. This was presumably for localizations with text that reads right-to-left. The only feature existing in themes and not schemes that I'm aware of is the ability to align an image to the top, left corner of the screen. This is useful for large (>16x16) Apple menu icons and alternate selected state icon. You can see that in AquaMaX. I can't imagine any other use.

If anybody has any comments, concerns, praise, hate, etc, I'd like to hear it. I had a pole about this earlier and there didn't seem to be a whole lot of response to it. I think it could be cool, it's definitely quite the curiosity to consider converting schemes to themes. Even converting themes back to schemes might be interesting, as some themes have custom cursors stored in them that would finally spring to life in a scheme.

http://www.d.umn.edu/~bold0070/projects/scheme2theme/

edit

Also to be noted is that schemes properly support separate masks for pressed and unpressed window widget states whereas themes leave artifact of the opposite state in unmasked areas (appearance manager does not redraw the window underneath widgets when they change state). So I have elected to use the ics# mask of the unpressed state for both pressed and unpressed forms of all widgets. The worst-case effect of this is distortion of the pressed state, but this distortion will result in proper-looking unpressed state when the widget is returned to the unpressed state.

Also, all 'ppat' resources can be used DIRECTLY in themes without modification. Only proper referencing must be generated. ('plut' and 'tdat' entries)

 

Dennis Nedry

Well-known member
rsrc_read.cpp is my very own C++ resource fork parser. This should work for any file with a valid resource fork. It is quite extensively functional for a first rev. Though I'm sure they exist, I wasn't able to find any C++ libraries that would allow me to access individual resource data in a file.

Does anyone know of a library that I could have used instead? I would LOVE to have some easy read/write resource functions.

 

Dennis Nedry

Well-known member
Well apparently I can convert 'cicn's now. Look at the window frame! Does this look familiar? :) (Onyx)

This is still very preliminary, it only supports 8-bit 'cicn's right now. It extracts the color table from the 'cicn', stores it as a 'clut' resource, and then builds a 'pxm#' resource. the 'pxm#' contains all little trimmed pieces of images from the original 'cicn' and references the new color table. Each displayed pixel is a lossless conversion.

As you'll see, I didn't get to the racing stripes or the title text, and in fact, I also did not do the zoom box or grow box even though those wouldn't normally be on this window. Also, proper collapsing of the window and the small 1-pixel shadow isn't finished. I noticed that Kaleidoscope uses embossed text for the title bar - that's another feature not supported in themes.

Anyway, it's progress. I still haven't touched any resource types created by the Kaleidoscope people, such as 'wnd#'. These are all Apple's own data structures that I'm working with.

Picture 4.png

 

Dennis Nedry

Well-known member
cicn to pxm# conversion has become more robust now, supporting 1, 2, 4, and 8 bit depth. It also allows me to copy rectangle areas from the cicn to the pxm# with a single function call, regardless of bit depth. This expands compatibility from just Onyx to include Ice and Sherbet. Also, shadows and collapse functionality are fixed now.

Ironically, the System 7 scheme that Kaleidoscope comes with, that they copied from Apple would require me to access their wnd# resource to make a conversion into a theme! They can copy from Apple but I can't copy from them? That's a little hypocritical.

Picture 5.png

Picture 6.png

Picture 7.png

 

PowerPup

Well-known member
Wow, this is brilliant progress you're making. :) Though I've noticed that the UI elements (tab and stuff) look normal in the new Onyx pic. Was that from having Kaleidoscope on by accident maybe?

Anyway, great work Dennis. :D I should go through my MacAddict CDs and find that Scheme Editor I messed around with once. ;)

 

Dennis Nedry

Well-known member
So far, I have only worked on the regular document window frame, which includes the close/collapse/zoom boxes. Everything else defaults to Apple Platinum. However, once the document window is done, the same code can be adapted to much more easily convert all of the other elements, like tabs, pop-up menus, etc.

In the first picture, you actually see the Appearance Manager defaulting back to the Sosumi theme for the tabs and things. I had initially built on top of Sosumi, but now I am able to build from scratch and allow Apple Platinum to show through.

The windows that you see are from Kaleidoscope Schemes, but they are being run with Apple's Appearance Manager. Kaleidoscope was not running when I took any of these pictures.

 

Dennis Nedry

Well-known member
A bit more progress. The racing stripes and title text are working now. It took a fair bit of head smashing to get through all the different behaviors of the title text, it acts a little bit differently depending on if there is a zoom box or not, especially as the window gets too small to display the text. But it's doing well now. Also, I ran into a strange inconsistency between cicn and pxm# data. pxm# requires all image data to exist within an even number of bytes per row, whereas cicn can be any whole number of bytes.

Say that you have a 1-bit image that is 17 pixels wide. In cicn, each row must be a whole number of bytes, so:

bits -> bytes

8 -> 1

16 -> 2

24 -> 3

32 -> 4

The nearest one for cicn is 24 bits, or 3 bytes per row. The remaining 7 bits just go to waste, they're clipped off and you don't see them, but they're in there.

In pxm#, the nearest one is 32 bits, or 4 bytes per row, because it must be an even number of bytes. So this requires more wasted bits (aka padding) that must be inserted.

I got through that one, that took a fair bit of effort but we're good.

The latest image shows working ppat (racing stripes), which proves a functional plut resource, and also it shows a 1-bit transparent pxm# (border around racing stripes). And the growbox.

Themes support separate images for vertical-only and horizontal-only zoom boxes, which is apparently not supported in Kaleidoscope as far as I can tell.

Do have a look at http://www.d.umn.edu/~bold0070/projects/scheme2theme/ for the latest source code. This code does not spit out a working theme file! There are a couple of necessary resources missing that must still be scavenged form a working theme. It does spit out some working theme resources though.

Picture 15.png

 

Dennis Nedry

Well-known member
Not much to show for it, but I have made progress creating the clr# (theme text color) resource and have added the ability to update a color in the clr# based on a particular pixel in a cicn. Because cicns have color tables, the "get pixel color" function first finds the pixel based on x, y coordinates, reads the index stored there, and looks up that index in the color table. It returns the 3x16bit color. With that color, you are then able to call another function to overwrite a default color already stored in the clr# resource.

Since this functionality is similar to plut resources, I went ahead and polished plut first. It now supports user and required plut resources. Required pluts start with default values that can be overwritten just like the clr# resource.

The only visible effect is that now the document window's title text is converted to the right color automatically.

I have run into an issue when converting the inactive document window frame in Onyx. The image is 1-bit and for some reason it is not parsing correctly. It ends up being twice the width that it should be.

 

Dennis Nedry

Well-known member
That one was nasty. It was 2 problems. First I forgot one of these types of things:

buffer = new unsigned char[1024];

So some memory was being written over. Also, I fixed the excessive width problem - I just had to copy the trimmed width from the cicn to the pxm#. I was using the untrimmed width, which includes the padding. The inactive document window frame should be done in a short period of time now. I'll post it as an edit if it's quick enough, otherwise I'll just make a new post again.

edit

I spy a glitch in the Ice grow box!

Picture 3.png

Picture 4.png

Picture 5.png

 

Dennis Nedry

Well-known member
The Ice grow box was more padding issues. In some cases, the cicn will have too much padding. The cicn to pxm# converter is now fully-aware of increasing or decreasing padding at the end of each row as necessary.

edit

If anybody else is interested in helping with this project, do chime in. I won't be unemployed forever. :D

Picture 6.png

 

Dennis Nedry

Well-known member
I guess I hadn't even tried until just now but it appears that none of the downloads even work in the scheme archive! Most of the schemes in the archive are wnd# schemes though, so this converter is of no use for them.

 

Dennis Nedry

Well-known member
All of the window frame types except for utility and side utility windows are done now. Anyone who has played with themes should get a good chuckle from the familiar Theme Checker 3 / AppearanceSamplePPC test messages. :lol:

edit

I went ahead and uploaded the latest code (v0.2). This contains a read-me that steps you through exactly how to try it. You need to have Xcode installed, and classic mode or a Mac OS 8.5 - 9.2.2 Mac to try the converted theme on.

It's a little bit messy code, but for a hack, it works pretty well. Let me know if you try running it and if my instructions were good enough. I tried to make it so that you could do it even if you hadn't programmed or used xcode before.

http://www.d.umn.edu/~bold0070/projects/scheme2theme/

onyx.gif

ice.gif

sherbet.gif

 

olePigeon

Well-known member
Awesome! Keep up the great work. It's too bad you didn't work on this back in the day. :p I remember that Apple had their own official utility for converting Kaleidoscope to Apple themes, it was something I always wanted. :)

 

Dennis Nedry

Well-known member
I'm glad you like it! I did work on themes back in the day, at the very end before OS X came out. I was only in high school though. I made several themes, but I didn't have the ability to make a program that accesses resource forks and shifts around bits and bytes the way this one does. I didn't even understand pxm# color tables so all of my old themes are 24-bit color -- way slower and larger file size than they need to be. I mitigated that with the use of color table ppats when possible, but those are only useful for non-transparent images.

 

Dennis Nedry

Well-known member
More progress. I have rewritten most of the cicn to pxm# converter so it is much more flexible now. The pxm# no longer has to be the same size as the cicn. This allowed me to fix a growbox size bug that you might have seen in Sherbet. Now when you copy a rectangle, you can automatically copy the mask with it if you want, that's a nice feature. Also, its more intuitive to add more indexes to pxm# images. All of the padding conversion hackery is gone now - this is automatically taken care of just by the way that it's written now.

Mostly there has just been a lot of cleanup. I've done a few visible things with text colors and background colors that you can see in the image.

I've discovered a future issue: scroll bar buttons. In schemes, pressed, unpressed, inactive, and disabled versions are each in separate cicns with separate color tables, but in themes, they are REQUIRED to be in the same pxm# resource. So I have to mess with color tables to get these to work, and I think that the only reasonable solution is to use the 32-bit pxm# mode, where each pixel is stored directly with a 32-bit color. If I do that, then I don't even have to use color tables at all. It's not a perfect solution. Doing a whole theme in 32-bit mode makes it less responsive, but for these small parts it may be okay.

I want to work on scroll bars soon because they currently crash the converted theme if you click them...

Picture 6.png

 

Dennis Nedry

Well-known member
The program parses cinf resources now. SHHHHHHHHHHHH! (These are Kaleidoscope proprietary resources.) I won't release the code for this until we at least go to some reasonable effort to get permission from the Kaleidoscope guy if we can find him.

So the converter uses the cinf resource to parse out the cicn images for controls. For example, sliders, tabs, buttons, etc. The image part of it is working already, but there won't be a one-size-fits-all layo resource like there was for window frames, so that has yet to be developed. The layo resource tells themes where to put images and gives them clickable / visible characteristics. So I will have to convert info from the cinf into the layo for each control.

Scroll bar buttons will be a whole separate header and source file I think, I'll put that off. There are other things I can do that affect a whole range or parts in the theme.

Concerning the "wnd#" resources, those are tricky because of stretch and collapse regions. I'm not exactly sure how to translate those into a layo. layos use centering coordinates and collapse items individually, which is more versatile. It seems that this should be possible with some clever hacking. But once again, wnd# is Kaleidoscope-proprietary.

 
Top