Grouped page control

Actually I have written three page controls so far (who knew that I would need all of them). So here they are:

  • BAPageControl: features several fixed styles and allows to specify colors for active and inactive dots
  • BACustomPageControl: you can specify images for active and inactive dots
  • BAGroupedPageControl: when you have too many pages to fit on screen you can show them in groups

And in this post I will talk about this last control—BAGroupedPageControl.

The problem that I faced with one of my apps is that I had too many pages for the page control to show. The first solution was to add "continuous" styles to the BAPageControl and they work very well indeed. The idea is to show individual dots when the number of pages is small enough for dots to fit in screen bounds. But when they don’t fit show something like progress indicator so you have a sense where you are in the list of pages. The downside of this approach is that the control changes visually too much, which could be confusing.

My next solution was to introduce grouping so that pages are packed in groups and only one of the groups is visible at any given moment (the group which contains the current page). To indicate that there are more pages available I draw tiny arrows at the sides of the control.

Grouped Page Control

Speaking of API it is the same as in BAPageControl minus "continuous" styles. There is one additional property to specify the number of pages per group.

I also had plans to sell this control on sites which specialize on selling reusable components. For several months it was available at binpress.com but they all gone without a single purchase.

Grouped Page Control Sales

So now this control is a part of the BaseAppKit framework, enjoy!

BACustomPageControl: page control replacement with images for dots

I already have written a UIPageControl replacement which supports more styles but it is still not extensible. If your designer gives you two images—one for active dot and another for inactive dots—you can’t use them. So I have created one more control class which exposes almost the same API but instead of having a number of styles and two colors it allows you to specify two images. And that’s it.

Custom Page Control

The class is BACustomPageControl and it is a part of BaseAppKit framework.

You may ask "Why not add images to the existing BAPageControl which you advertised before?" So I thought about this and decided that it does not make much sense. Controls have the same API and could be easily replaced so if you decide to use another one it is as easy as changing the class name in one place. On the other hand extending BAPageControl with new properties will make it more complex to use because now you have to figure out which combination of properties makes sense and which does not.

So I hope you will find it useful. As always sample code is a part of BADemo project.

ImageOptim

I always thought that Xcode produces the most compact PNG files but this not seems to be the case. Turns out that there is a tool that does better job at optimizing PNGs.

Manually optimizing images with ImageAlpha reduced entire application size by more than a half (33.4MB down to 16.3MB). Images alone were 65% smaller and were displayed 2.5 times quicker than Xcode-optimized ones.



Since Xcode conversion can be disabled and iOS supports standard PNGs, such big size and speed savings are possible in actual AppStore applications.

Pong game with Qt

The next incarnation of the Pong game written in C++ is called QPong because it uses Qt toolkit to provide its UI. The source code is available on Github as Xcode project. All base classes were copied without any modifications but integration with Qt required some fine adjustments in a way the project is built.

Since Qt is written in C++ there is no need to mix any languages as it was the case with Cocoa Pong application. Nonetheless I still have to create a custom implementation of the game’s drawing context class which is called QDrawingContext:

#include <QtGui/QtGui>
#include "DrawingContext.h"

class QDrawingContext : public Pong::DrawingContext {

public:
    QDrawingContext(QPainter *painter);
    virtual ~QDrawingContext();
    virtual void setFillColor(Pong::RGBColor const &color);
    virtual void fillRectangle(Pong::Rectangle bounds);
    virtual void fillOval(Pong::Rectangle bounds);

private:
    QPainter *_painter;
    QColor _qFillColor;
};

Note that I left #include statements and they reference ‘QtGui/QtGui’ instead of just ‘QtGui’ because that’s how you should do it in Xcode. Its implementation uses QPainter to do the actual drawing:

QDrawingContext::QDrawingContext(QPainter *painter) : _qFillColor(0, 0, 0) {
    _painter = painter;
}

QDrawingContext::~QDrawingContext() {
}

void QDrawingContext::setFillColor(Pong::RGBColor const &color) {
    DrawingContext::setFillColor(color);
    _qFillColor = QColor(color.red * 255, color.green * 255, color.blue * 255);
}

void QDrawingContext::fillRectangle(Pong::Rectangle bounds) {
    _painter->setBrush(_qFillColor);
    QRectF qbounds = QRectFromRectangle(bounds);
    _painter->drawRect(qbounds);
}

void QDrawingContext::fillOval(Pong::Rectangle bounds) {
    _painter->setBrush(_qFillColor);
    QRectF qbounds = QRectFromRectangle(bounds);
    _painter->drawEllipse(qbounds);
}

Although integration was easy for the source code it was not so for the IDE. It turns out that Qt has its own compiler called ‘moc’ which generates some additional C++ code for classes with Q_OBJECT macro. It is required to provide certain meta-information about the object and should be a part of the build process. Hopefully I was not the first person to cope with this so I found this handy post that explains how to make Xcode to create mocables. My version is roughly the same:

cd "$PROJECT_DIR"/QPong
rm -f QPong.pro
qmake -project -o QPong.pro
qmake -spec macx-g++ QPong.pro
make mocables

Note that you have to call this script before compilation phase. You should actually run it once first to generate moc_* files and add them to the project so they got compiled with the rest of the project files.

Pong game with Objective-C++

My weekend project was to write a Pong game in C++ and make it portable enough to work with different UI toolkits. The first incarnation is called XPong and uses Cocoa to provide native UI for the game. It is published on Github and could be compiled and launched on OS X.

The natural way to integrate C++ and Objective-C code is to use Objective-C++ which is basically a mix of the two without any new features. Naturally you either declare C++ class which makes use of Objective-C objects or otherwise define an Objective-C class which makes use of C++ code. On the project level if you have a portable C++ module you typically have to use this module from Objective-C application and instrument the module to call back the Objective-C frameworks.

Using Objective-C in C++ classes

Let’s look at example: objects in the Pong game have to draw themselves, and to do so they should call Cocoa APIs. In particular they have to use NSBezierPath to fill rectangles and ovals. To localize dependency on particular drawing methods Pong game introduces abstract class DrawingContext:

class DrawingContext {

public:
    DrawingContext() : _fillColor(RGBColor(1)) {}
    virtual ~DrawingContext() {}
    RGBColor fillColor() const { return _fillColor; }
    virtual void setFillColor(RGBColor const &color) { _fillColor = color; }
    virtual void fillRectangle(Rectangle bounds) = 0;
    virtual void fillOval(Rectangle bounds) = 0;

private:
    RGBColor _fillColor;
};

Note that it is a proper C++ class which requires subclasses to implement actual painting functions using appropriate system APIs. In the XPong project we define XDrawingContext class which extends DrawingContext and implements these methods. Note that implementation file should be called XDrawingContext.mm so Xcode will know that it is an Objective-C++ code. Here is a header file for XDrawingContext:

class XDrawingContext : public Pong::DrawingContext {

public:
    XDrawingContext(NSGraphicsContext *xcontext);
    virtual ~XDrawingContext();
    virtual void setFillColor(Pong::RGBColor const &color);
    virtual void fillRectangle(Pong::Rectangle bounds);
    virtual void fillOval(Pong::Rectangle bounds);

private:
    NSGraphicsContext *_xcontext;
};

And its implementation:

XDrawingContext::XDrawingContext(NSGraphicsContext *xcontext) {
    _xcontext = [xcontext retain];
}

XDrawingContext::~XDrawingContext() {
    [_xcontext release];
}

void XDrawingContext::setFillColor(Pong::RGBColor const &color) {
    DrawingContext::setFillColor(color);
    NSColor *xcolor = [NSColor colorWithDeviceRed:color.red
                                            green:color.green
                                             blue:color.blue
                                            alpha:1];
    [xcolor setFill];
}

void XDrawingContext::fillRectangle(Pong::Rectangle bounds) {
    NSBezierPath *path =
        [NSBezierPath bezierPathWithRect:NSRectFromRectangle(bounds)];
    [path fill];
}

void XDrawingContext::fillOval(Pong::Rectangle bounds) {
    NSBezierPath *path =
        [NSBezierPath bezierPathWithOvalInRect:NSRectFromRectangle(bounds)];
    [path fill];
}

So that’s how you call Objective-C from C++: just implement C++ class and use Objective-C calls within method implementations.

Using C++ in Objective-C classes

The next example is GameView class. It is a custom Cocoa view which will draw Pong game objects in itself and will forward user input to it. Here is its header file:

@interface GameView : NSView

@property(assign) Pong::Drawable *gameContent;
@property(assign) Pong::InputHandler *gameResponder;

@end

And here is the implementation:

@implementation GameView

@synthesize gameContent = _gameContent;
@synthesize gameResponder = _gameResponder;

- (void)drawRect:(NSRect)rect {
    [[NSColor grayColor] set];
    NSRectFill(rect);
    NSGraphicsContext *xcontext = [NSGraphicsContext currentContext];
    XDrawingContext context(xcontext);
    if (self.gameContent) {
        self.gameContent->draw(context);
    }
}

- (void)keyDown:(NSEvent *)theEvent {
    if ([theEvent.characters length] > 0) {
        const char c = [theEvent.characters characterAtIndex:0];
        if (self.gameResponder) {
            self.gameResponder->handleKey(c);
        }
    }
}

@end

I omitted some irrelevant details to show only what is important. GameView has two properties which are pointers to C++ classes. We can’t release and retain C++ objects so I declare properties with ‘assign’ so the caller will manage their life span. Implementation of GameView methods simply invoke methods of C++ objects and that’s how it works.

Objective-C++ provides an easy way to integrate C++ and Objective-C code. You literally use ‘mm’ extension for the files, mix the code and it works.

Apple is working on grid view?

Recently I posted an update for my Deviations app and got this rejection notice from Apple:

We found that your app uses one or more non-public APIs, which is not in compliance with the App Store Review Guidelines. The use of non-public APIs is not permissible because it can lead to a poor user experience should these APIs change.

We found the following non-public API/s in your app:

gridView:heightForHeaderInSection:
gridView:numberOfRowsInSection:
gridView:viewForHeaderInSection:
numberOfSectionsInGridView:

What changed is that I’ve added a grid component to the BaseAppKit library which has these methods defined. Review team seems to be using a tool which checks only method signatures without considering class or protocol which defines them and obviously there is some ‘private’ component with these methods. And obviously it’s a grid.

So I’m actually pretty much happy to discover this because it could mean that iOS could soon have a nice built-in grid component which I dearly miss…