Uli's Web Site
[ Zathras.de - Uli's Web Site ]
Other Sites: Stories
Abi 2000
Stargate: Resurgence
Lost? Site Map!
     home | blog | moose | programming | articles >> blog

 Blog Topics

15 Most Recent [RSS]

 Less work through Xcode and shell scripts
2011-12-16 @600
 iTunesCantComplain released
2011-10-28 @954
 Dennis Ritchie deceased
2011-10-13 @359
 Thank you, Steve.
2011-10-06 @374
 Cocoa Text System everywhere...
2011-03-27 @788
 Blog migration
2011-01-29 @520
 All you need to know about the Mac keyboard
2010-08-09 @488
 Review: Sherlock
2010-07-31 @978
 Playing with Objective C on Debian
2010-05-08 @456
 Fruit vs. Obst
2010-05-08 @439
 Mixed-language ambiguity
2010-04-15 @994
 Uli's 12:07 AM Law
2010-04-12 @881
 Uli's 1:24 AM Law
2010-04-12 @874
 Uli's 6:28 AM Law
2010-04-12 @869
 Uli's 3:57 PM Law
2010-04-12 @867


Using Cocoa in SuperCompiler

After my Introduction to SuperCompiler, let's go and do something slightly more advanced. Let's write our first useful XCMD that does something you wouldn't be able to do in straight SuperTalk.

In fact, what we will be doing is write some Cocoa code that will let us find out what "control tint color" the user has selected, Aqua or Graphite. This can be very handy when drawing your own user interface elements, because you'll want them to be blue or grey, depending on what tint the user chose. So, fire up SuperCard and open the SuperCompiler project and we can get going...

Finding your way around Apple's documentation

Then open a web browser and open Apple's Developer web site. Somewhere there you will find a link to the Reference documentation. At the time of writing, it's at the left under the heading "Reference Library" and is a link called Reference. There, click on Cocoa to get to Apple's Cocoa reference documentation, i.e. their equivalent to SuperCard's SuperTalk Language Guide.

We want to do something related to drawing and graphics, so we click on Graphics and Imaging. In the following list, you'll find two mentions of colors, CIColor and NSColor. Everything that is "normal" in Cocoa generally starts with "NS" ("NextStep"). Stuff that starts with other letters is for more complex things. "CI" for example stands for "CoreImage" and is part of Apple's fast, new drawing stuff for effects, so let's look at the NSColor documentation.

We could probably have found this page much more quickly by just using Google's advanced search and telling it to only look for stuff on developer.apple.com, but since you'll not always know that you are looking for control tints, it's better we took the scenic route this time around.

Basics of using Cocoa in SuperCompiler

If you scroll around a little, you will find a Cocoa command that is called "currentControlTint", and in its entry, you'll find a "typewritten" line which looks like this:

+ (NSControlTint)currentControlTint
This is called a prototype, and is pretty much what you need to know to use a command. You have to know that in Cocoa every command is associated with an object. Like in SuperCard, where each handler is in some object's script. We have the documentation for NSColor here, so these commands all belong in NSColor's script.

This command is actually a function. The "NSControlTint" in brackets is a description of the return value you can expect from this function. Click on it on Apple's web site to see a description of it. To use this command in SuperCompiler, you use it the following way, making sure you write the uppercase/lowercase characters exactly as shown in Apple's documentation:

put [NSColor currentControlTint] into myTint
This is intentionally similar to how you would write it in Objective C to make it easier to work with Apple's documentation. If you were to write this in SuperTalk somehow, it would be equivalent to:
put currentControlTint() via NSColor into myTint
Now, if you look at the description for NSControlTint, you'll find that it is basically a list of numbers. They're constants. Just like SuperTalk has "pi" to mean 3.14..., we have NSBlueControlTint to mean 1, NSGraphiteControlTint to mean 6 etc.

So, if we were to give up easily, we would write the following XFcn:

function currentControlTint
  put [NSColor currentControlTint] into theTint
  if theTint = 1 then
    return "aqua"
  else if theTint = 6 then
    return "graphite"
  end if
end currentControlTint
But really, wouldn't it be much nicer to have the actual color for our tint? So, let's look some more through the documentation. Maybe we can find a way to get from an NSControlTint to a color?

We can improve him!

Yes, there is "colorForControlTint:" and in its entry, you'll find its prototype, which looks like this:

+ (NSColor *)colorForControlTint:(NSControlTint)controlTint

Now, you need to know that NSColor is a class. A class is an object that is a factory for creating other objects. There is only one factory, but it can be used to create any number of objects, whose "ID" you can then put in a variable. Then you can call functions from the script of that object. The plus sign at the start of the prototype of this function and currentControlTint above means that this command is in the factory's script. Commands that have a minus sign at the start are ones that are in the scripts of objects you create using the factory.

This time, the return value is described as "NSColor *". The asterisk means that it is some sort of "object ID". Now, since we can easily get at NSColor just by writing "NSColor", an ID can only mean this will be an actual color created by our NSColor factory. That sounds like we're on the right track!

The "(NSControlTint)controlTint" part after the colon is the description of the one parameter this function takes. It's roughly equivalent to

function colorForControlTint controlTint
The parts in brackets are simply descriptions of what to put in controlTint or what the function will give back. With that knowledge, let's extend our XFcn:
function currentControlTint
  put [NSColor currentControlTint] into theTint
  put [NSColor colorForControlTint: theTint] into theColor
  -- what now ... ?
end currentControlTint
Okay, so now we have an NSColor object in theColor. How do we get at its color info? Well, scroll around a little. This time, ignore all the nice methods with "+" signs. You'll come across three nice functions named
-(float) redComponent
-(float) greenComponent
-(float) blueComponent
That sounds good. Now, if you read SuperCompiler's Help, in particular the chapter on calling system functions, you'll know that "float" is a floating point number. That's because in Cocoa, color values go from 0 to 1, not from 0 to 255 like in SuperCard... but that's nothing a little multiplication won't cure.

Okay, so we call the redComponent handler on theColor in our XFcn:

function currentControlTint
  put [NSColor currentControlTint] into theTint
  put [NSColor colorForControlTint: theTint] into theColor
  return [theColor redComponent]
end currentControlTint

A slight bump in the road...

Now, if you try this out by typing put currentControlTint() in the message box, you'll find that this doesn't work. Your XFcn will give back empty, and if you look at the console, you'd find the following error message:

2006-12-03 23:41:35.215 SuperCard 4.6[8051] Objective C error:
*** -redComponent not defined for the
NSColor NSNamedColorSpace System blueControlTintColor;
need to first convert colorspace.
This complains that our color doesn't understand the redComponent function. What? Yes, well, he reason for this is that Cocoa's colors aren't just RGB triplets. They can be everything from named patterns to CMYK or HSB colors. So, what you need to do is convert this color into an RGB color. To do that, we'll search some more through the docs, what looks good is:
- (NSColor *)colorUsingColorSpaceName:(NSString *)colorSpace
Now NSString is just a string of text. And while this function returns "NSColor*", it has a "-" at the start, so it's not a function in the factory, but rather a function that other colors have. Trouble is, what is a color space name? Well, I guess we'll have to google for that, because there's no nice clickable link to a description available. Eventually, you'll find Apple's documentation for color spaces, and Table 1 on that page holds a list of color space names.

NSDeviceRGBColorSpace looks good. So we'll use that name:

put [theColor colorUsingColorSpaceName: "NSDeviceRGBColorSpace"] into rgbColor
And now we have a color that understands our redComponent function!

The final polish, or hungarian, or ...

Now, let's finish our XFcn; we want all three color components, and since they only go from 0 to 1, but we need 0 to 255, we'll also multiply each of the components by 255. Since this may give a fractional number, we'll also have to use trunc() to truncate the number to an integer. The result is the following XFcn:

function currentControlTint
  put [NSColor currentControlTint] into theTint
  put [NSColor colorForControlTint: theTint] into theColor
  put [theColor colorUsingColorSpaceName: "NSDeviceRGBColorSpace"] into rgbColor
  put trunc([rgbColor redComponent] *255) into theRed
  put trunc([rgbColor greenComponent] *255) into theGreen
  put trunc([rgbColor blueComponent] *255) into theBlue
  return theRed & "," & theGreen & "," & theBlue
end currentControlTint
That's it. Click the "Create XCMD" button and when it's finished type "put currentControlTint()" into the message box, and see the current control tint color!

That concludes our first trip into writing our first SuperCompiler XCMD. I admit this doesn't look a lot like SuperTalk anymore, but the advantage is that you can do stuff like this when needed, and use regular SuperTalk whenever that is sufficient. You can conquer the world from the comfort of SuperTalk, so to say.

Questions? Comments? Suggestions for future SuperCompiler tutorials? And remember, I hang out on the SuperCardXCmd mailing list, so if you want to try this, ask questions there and I'll help you sort out any issues you may have.

Reader Comments: (RSS Feed)
No comments yet
Or E-Mail Uli privately.

Created: 2006-12-03 @064 Last change: 2006-12-04 @119 | Home | Admin | Edit
© Copyright 2003-2023 by M. Uli Kusterer, all rights reserved.