mirror of
git://git.tartarus.org/simon/puzzles.git
synced 2025-04-21 16:05:44 -07:00
Dynamically frob the menu bar to achieve selection of game presets.
[originally from svn r5176]
This commit is contained in:
208
macosx.m
208
macosx.m
@ -5,9 +5,6 @@
|
|||||||
*
|
*
|
||||||
* - status bar support.
|
* - status bar support.
|
||||||
*
|
*
|
||||||
* - preset selection. Should be reasonably simple: just a matter
|
|
||||||
* of dynamically frobbing the menu bar.
|
|
||||||
*
|
|
||||||
* - configurability. Will no doubt involve learning all about the
|
* - configurability. Will no doubt involve learning all about the
|
||||||
* dialog control side of Cocoa.
|
* dialog control side of Cocoa.
|
||||||
*
|
*
|
||||||
@ -48,6 +45,20 @@
|
|||||||
* _worst_ this should involve a new Halibut back end, but I
|
* _worst_ this should involve a new Halibut back end, but I
|
||||||
* think help is HTML round here anyway so perhaps we can work
|
* think help is HTML round here anyway so perhaps we can work
|
||||||
* with what we already have.
|
* with what we already have.
|
||||||
|
*
|
||||||
|
* - Can we arrange for a pop-up menu from the Dock icon which
|
||||||
|
* launches specific games, perhaps?
|
||||||
|
*
|
||||||
|
* Grotty implementation details that could probably be improved:
|
||||||
|
*
|
||||||
|
* - I am _utterly_ unconvinced that NSImageView was the right way
|
||||||
|
* to go about having a window with a reliable backing store! It
|
||||||
|
* just doesn't feel right; NSImageView is a _control_. Is there
|
||||||
|
* a simpler way?
|
||||||
|
*
|
||||||
|
* - Resizing is currently very bad; rather than bother to work
|
||||||
|
* out how to resize the NSImageView, I just splatter and
|
||||||
|
* recreate it.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include <ctype.h>
|
#include <ctype.h>
|
||||||
@ -88,6 +99,59 @@ void get_random_seed(void **randseed, int *randseedsize)
|
|||||||
*randseedsize = sizeof(time_t);
|
*randseedsize = sizeof(time_t);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ----------------------------------------------------------------------
|
||||||
|
* Global variables.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The `Type' menu. We frob this dynamically to allow the user to
|
||||||
|
* choose a preset set of settings from the current game.
|
||||||
|
*/
|
||||||
|
NSMenu *typemenu;
|
||||||
|
|
||||||
|
/* ----------------------------------------------------------------------
|
||||||
|
* Tiny extension to NSMenuItem which carries a payload of a `void
|
||||||
|
* *', allowing several menu items to invoke the same message but
|
||||||
|
* pass different data through it.
|
||||||
|
*/
|
||||||
|
@interface DataMenuItem : NSMenuItem
|
||||||
|
{
|
||||||
|
void *payload;
|
||||||
|
int payload_free;
|
||||||
|
}
|
||||||
|
- (void)setPayload:(void *)d;
|
||||||
|
- (void)setPayloadFree:(BOOL)yesno;
|
||||||
|
- (void *)getPayload;
|
||||||
|
@end
|
||||||
|
@implementation DataMenuItem
|
||||||
|
- (id)initWithTitle:(NSString *)title
|
||||||
|
action:(SEL)act
|
||||||
|
keyEquivalent:(NSString *)key
|
||||||
|
{
|
||||||
|
payload = NULL;
|
||||||
|
payload_free = NO;
|
||||||
|
return [super initWithTitle:title action:act keyEquivalent:key];
|
||||||
|
}
|
||||||
|
- (void)setPayload:(void *)d
|
||||||
|
{
|
||||||
|
payload = d;
|
||||||
|
}
|
||||||
|
- (void)setPayloadFree:(BOOL)yesno
|
||||||
|
{
|
||||||
|
payload_free = yesno;
|
||||||
|
}
|
||||||
|
- (void *)getPayload
|
||||||
|
{
|
||||||
|
return payload;
|
||||||
|
}
|
||||||
|
- (void)dealloc
|
||||||
|
{
|
||||||
|
if (payload_free)
|
||||||
|
sfree(payload);
|
||||||
|
[super dealloc];
|
||||||
|
}
|
||||||
|
@end
|
||||||
|
|
||||||
/* ----------------------------------------------------------------------
|
/* ----------------------------------------------------------------------
|
||||||
* The front end presented to midend.c.
|
* The front end presented to midend.c.
|
||||||
*
|
*
|
||||||
@ -215,6 +279,26 @@ struct frontend {
|
|||||||
@end
|
@end
|
||||||
|
|
||||||
@implementation GameWindow
|
@implementation GameWindow
|
||||||
|
- (void)setupContentView
|
||||||
|
{
|
||||||
|
NSSize size = {0,0};
|
||||||
|
int w, h;
|
||||||
|
|
||||||
|
midend_size(me, &w, &h);
|
||||||
|
size.width = w;
|
||||||
|
size.height = h;
|
||||||
|
|
||||||
|
fe.image = [[NSImage alloc] initWithSize:size];
|
||||||
|
[fe.image setFlipped:YES];
|
||||||
|
fe.view = [[MyImageView alloc]
|
||||||
|
initWithFrame:[self contentRectForFrameRect:[self frame]]];
|
||||||
|
[fe.view setImage:fe.image];
|
||||||
|
[fe.view setWindow:self];
|
||||||
|
|
||||||
|
midend_redraw(me);
|
||||||
|
|
||||||
|
[self setContentView:fe.view];
|
||||||
|
}
|
||||||
- (id)initWithGame:(const game *)g
|
- (id)initWithGame:(const game *)g
|
||||||
{
|
{
|
||||||
NSRect rect = { {0,0}, {0,0} };
|
NSRect rect = { {0,0}, {0,0} };
|
||||||
@ -258,17 +342,9 @@ struct frontend {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fe.image = [[NSImage alloc] initWithSize:rect.size];
|
[self setupContentView];
|
||||||
[fe.image setFlipped:YES];
|
|
||||||
fe.view = [[MyImageView alloc]
|
|
||||||
initWithFrame:[self contentRectForFrameRect:[self frame]]];
|
|
||||||
[fe.view setImage:fe.image];
|
|
||||||
[fe.view setWindow:self];
|
|
||||||
[self setContentView:fe.view];
|
|
||||||
[self setIgnoresMouseEvents:NO];
|
[self setIgnoresMouseEvents:NO];
|
||||||
|
|
||||||
midend_redraw(me);
|
|
||||||
|
|
||||||
[self center]; /* :-) */
|
[self center]; /* :-) */
|
||||||
|
|
||||||
return self;
|
return self;
|
||||||
@ -375,6 +451,84 @@ struct frontend {
|
|||||||
[self processButton:'r'&0x1F x:-1 y:-1];
|
[self processButton:'r'&0x1F x:-1 y:-1];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
- (void)clearTypeMenu
|
||||||
|
{
|
||||||
|
while ([typemenu numberOfItems] > 1)
|
||||||
|
[typemenu removeItemAtIndex:0];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)becomeKeyWindow
|
||||||
|
{
|
||||||
|
int n;
|
||||||
|
|
||||||
|
[self clearTypeMenu];
|
||||||
|
|
||||||
|
[super becomeKeyWindow];
|
||||||
|
|
||||||
|
n = midend_num_presets(me);
|
||||||
|
|
||||||
|
if (n > 0) {
|
||||||
|
[typemenu insertItem:[NSMenuItem separatorItem] atIndex:0];
|
||||||
|
while (n--) {
|
||||||
|
char *name;
|
||||||
|
game_params *params;
|
||||||
|
DataMenuItem *item;
|
||||||
|
|
||||||
|
midend_fetch_preset(me, n, &name, ¶ms);
|
||||||
|
|
||||||
|
item = [[[DataMenuItem alloc]
|
||||||
|
initWithTitle:[NSString stringWithCString:name]
|
||||||
|
action:NULL keyEquivalent:@""]
|
||||||
|
autorelease];
|
||||||
|
|
||||||
|
[item setEnabled:YES];
|
||||||
|
[item setTarget:self];
|
||||||
|
[item setAction:@selector(presetGame:)];
|
||||||
|
[item setPayload:params];
|
||||||
|
[item setPayloadFree:YES];
|
||||||
|
|
||||||
|
[typemenu insertItem:item atIndex:0];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)resignKeyWindow
|
||||||
|
{
|
||||||
|
[self clearTypeMenu];
|
||||||
|
[super resignKeyWindow];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)close
|
||||||
|
{
|
||||||
|
[self clearTypeMenu];
|
||||||
|
[super close];
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)resizeForNewGameParams
|
||||||
|
{
|
||||||
|
NSSize size = {0,0};
|
||||||
|
int w, h;
|
||||||
|
|
||||||
|
midend_size(me, &w, &h);
|
||||||
|
size.width = w;
|
||||||
|
size.height = h;
|
||||||
|
|
||||||
|
NSDisableScreenUpdates();
|
||||||
|
[self setContentSize:size];
|
||||||
|
[self setupContentView];
|
||||||
|
NSEnableScreenUpdates();
|
||||||
|
}
|
||||||
|
|
||||||
|
- (void)presetGame:(id)sender
|
||||||
|
{
|
||||||
|
game_params *params = [sender getPayload];
|
||||||
|
|
||||||
|
midend_set_params(me, params);
|
||||||
|
midend_new_game(me);
|
||||||
|
|
||||||
|
[self resizeForNewGameParams];
|
||||||
|
}
|
||||||
|
|
||||||
@end
|
@end
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -576,29 +730,6 @@ NSMenuItem *newitem(NSMenu *parent, char *title, char *key,
|
|||||||
parent, title, key, target, action);
|
parent, title, key, target, action);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ----------------------------------------------------------------------
|
|
||||||
* Tiny extension to NSMenuItem which carries a payload of a `const
|
|
||||||
* game *', allowing our AppController to work out _which_ game
|
|
||||||
* needs to be launched when it receives a newGame message.
|
|
||||||
*/
|
|
||||||
@interface GameMenuItem : NSMenuItem
|
|
||||||
{
|
|
||||||
const game *ourgame;
|
|
||||||
}
|
|
||||||
- (void)setGame:(const game *)g;
|
|
||||||
- (const game *)getGame;
|
|
||||||
@end
|
|
||||||
@implementation GameMenuItem
|
|
||||||
- (void)setGame:(const game *)g
|
|
||||||
{
|
|
||||||
ourgame = g;
|
|
||||||
}
|
|
||||||
- (const game *)getGame
|
|
||||||
{
|
|
||||||
return ourgame;
|
|
||||||
}
|
|
||||||
@end
|
|
||||||
|
|
||||||
/* ----------------------------------------------------------------------
|
/* ----------------------------------------------------------------------
|
||||||
* AppController: the object which receives the messages from all
|
* AppController: the object which receives the messages from all
|
||||||
* menu selections that aren't standard OS X functions.
|
* menu selections that aren't standard OS X functions.
|
||||||
@ -613,7 +744,7 @@ NSMenuItem *newitem(NSMenu *parent, char *title, char *key,
|
|||||||
|
|
||||||
- (IBAction)newGame:(id)sender
|
- (IBAction)newGame:(id)sender
|
||||||
{
|
{
|
||||||
const game *g = [sender getGame];
|
const game *g = [sender getPayload];
|
||||||
id win;
|
id win;
|
||||||
|
|
||||||
win = [[GameWindow alloc] initWithGame:g];
|
win = [[GameWindow alloc] initWithGame:g];
|
||||||
@ -655,10 +786,10 @@ int main(int argc, char **argv)
|
|||||||
|
|
||||||
for (i = 0; i < gamecount; i++) {
|
for (i = 0; i < gamecount; i++) {
|
||||||
id item =
|
id item =
|
||||||
initnewitem([GameMenuItem allocWithZone:[NSMenu menuZone]],
|
initnewitem([DataMenuItem allocWithZone:[NSMenu menuZone]],
|
||||||
menu, gamelist[i]->name, "", controller,
|
menu, gamelist[i]->name, "", controller,
|
||||||
@selector(newGame:));
|
@selector(newGame:));
|
||||||
[item setGame:gamelist[i]];
|
[item setPayload:(void *)gamelist[i]];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -673,6 +804,7 @@ int main(int argc, char **argv)
|
|||||||
item = newitem(menu, "Close", "w", NULL, @selector(performClose:));
|
item = newitem(menu, "Close", "w", NULL, @selector(performClose:));
|
||||||
|
|
||||||
menu = newsubmenu([NSApp mainMenu], "Type");
|
menu = newsubmenu([NSApp mainMenu], "Type");
|
||||||
|
typemenu = menu;
|
||||||
item = newitem(menu, "Custom", "", NULL, @selector(customGameType:));
|
item = newitem(menu, "Custom", "", NULL, @selector(customGameType:));
|
||||||
|
|
||||||
menu = newsubmenu([NSApp mainMenu], "Window");
|
menu = newsubmenu([NSApp mainMenu], "Window");
|
||||||
|
Reference in New Issue
Block a user