Sunday, January 17, 2010

Moving MFC icons to Cocoa

Working my way through the timeline MFC to Cocoa conversion I have once again bumped up against graphic resources. Various components in the UI have graphic resources (icons). Back when I was getting the basic engine to work I compiled out all things of this ilk with a huge amount of other things with a

#define _NO_UI.

A part of my approach is that the structure of the new UI follows the PC version very closely so I am bumping into the way that Icons are handled within Cello as a whole. Basically this I am gradually working my way through some of these #if _NO_UI blocks.

Existing graphic resources in the PC version are stored as .bmp files. Each file typically has a number of icons. The various components that comprise the system (such as the 20-30 effects) have factory functions that specify a name for the component, and a bitmap resource with an offset as an icon. This is achieved by all the components inheriting from a base class that maintains this. The upshot is that I have to tackle this base class and bring it into line, and because I hit the constructor, I also have to attend to the many sub-classes that use icons.

In the OSX version of Cello I use NSImage to represent an icon - and as an alternative to specifying an icon resource and offset simply specify a name. This name is the name is nothing more than the filename that of the icon that appears in the bundle. I have written a really simple wrapper based on boost intrusive_ptr that wraps the NSImage for use in C++. The existing icons are appropriate to Windows and will look really out of place in OSX but that is a problem for another day and a problem that I hope to hand over to an icon designer. For place-holder icons I take the existing icons bring them to my old Power-PC and use an old copy of Photoshop to turn them into individual PNG files.

Monday, January 11, 2010

Mutating MFC to Cocoa

I am making progress converting the view hierarchy of the timeline to cocoa. In the about face I am working through the classes and interfaces that are defined in MFC and attempting a mechanical conversion where possible. In my first cut I do the following:
  • Mutate the all 'interface' definitions to protocols.
  • Mutate all pure virtual base classes into protocols.
  • Mutate all other classes as objective C classes.
  • Where a class is based on multiple inheritance of a C++ class (typically mix-in classes) this is expressed as a protocol and I write a subclass of the mix-in class that funnels calls to an object of that protocol.
  • Comment out what is obviously not needed for a first cut.
I do the conversion bit by bit getting the compiler to guide me. It is a relentless, tireless guide. At best I get logic and code that is very close to what I need at worst I get a fill-in-the-dots template. Importantly the code dovetails in nicely into the existing code.

Sunday, January 3, 2010

C++ Observers in Objective C

Cello has various notifications that are posted to observers. This is a good and fine thing - the observers are generally UI components and in the PC version of Cello are C++ classes. The form is that through multiple inheritance of a mix-in class a class becomes an observer. It overrides the observation methods and handles the notifications. The rub comes with Objective-C.

Under OSX all the UI components are Objective C classes these can not inherit (neither multiply nor singly) from a C++ class - yet they need to be observers. So how to solve the problem? There seem to be two possibilities:
  1. Get the Objective C classes to "somehow" observe.
  2. Reroute all messages through the NSNotification system.
I have chosen the first option. Why? Well I want to use as much of the original code as possible and I don't want to have to serialize all the information that is passed to the observer as Objective C objects.

So how to do it? The method I chose is fairly simple. It goes like this:
  • For each observer write an equivalent protocol to the virtual method(s) in the C++ mix-in class.
  • Write a C++ class that is a subclass of the C++ mix-in observer and forwards the observations to an Objective C object that conforms to the protocol.
  • Now write your Objective-C class. It should conform to the protocol. It also has a member that is a pointer to the forward class that it owns (creates and destroys) and forwards the messages.
It is a modest fiddle - but works well.

Saturday, January 2, 2010

TimeLine - an about-face

Sometimes programming is about heading down a blind alley. I guess that thing to do in these situations is to know when to call it a day and head back. So this is what I am doing with my current work on the timeline.

So why the about face? What I was doing with the Timeline was to develop a slot in replacement for something a bit like a NSTableView but with all the capabilities rewired for a TimeLine. My idea was to provide a protocol that would be expressive enough to allow a fairly simple mesh between the Objective C and C++ in a controller class. Thus the controller class would be a thin shim or adaptor between the two things. This idea is workable - but the question is "how much work?" On the other hand I have a suite of classes though based on MFC do the job. This is code that is written and works. Having written the code for the row labels in the timeline I started working on the column (or timeline) header. Starting work on this I used the existing class as a guide for functionality etc. The further I worked with this the less certain I became. For example selection in this view is handled within the Cello engine and just reflected in the view. This is currently encapsulated in a C++ class. I can either
  • Wrap this in a cocoa class:
  • Serialize it into an NSDictionary
  • Project the C++ class directly into cocoa.
My approach with this project has been to aspire to the path of least resistance. This is to try and get the project up and running as quickly as reasonably possible, but also I have no desire to rewrite things that work. The original Cello source code is very well written, lovingly commented - why not use what I can?

So my revised approach is to use what I can of the MFC in the user interface. So what was a SOKTimeLineView that is an MFC based class is now an CHTimeLineView a subclass of NSView. The bulk of the methods I am rewriting as Cocoa in Objective C++. This is simply not hard - just copy and paste in the methods and fiddle them about. If I specify the views as having flipped coordinates even the coordinate calculations for drawing are more or less right.

As with all of these things there is something to loose - and what is to loose? Well mixing C++ and Objective-C is a bit of a nasty thing. Under 32-bit there are two incompatible exception models. So I will have to tread with care and make sure that I don't end up propagating C++ exceptions through AppKit. The other thing to loose is the work I have done - but the reality is that it will not be entirely lost. I imagine that the bulk of what I have written I can simply transplant.