Fix:graphics_cocoa:Better main argument handling
[profile/ivi/navit.git] / navit / navit / graphics / cocoa / graphics_cocoa.m
1 #include "config.h"
2 #include "config_.h"
3 #include "debug.h"
4 #include "plugin.h"
5 #include "point.h"
6 #include "window.h"
7 #include "graphics.h"
8 #include "event.h"
9 #include "item.h"
10 #include "callback.h"
11 #include "color.h"
12 #include <glib.h>
13 #include <iconv.h>
14
15 #ifdef __IPHONE_OS_VERSION_MIN_REQUIRED
16 #define USE_UIKIT 1
17 #else
18 #define USE_UIKIT 0
19 #endif
20
21 #if USE_UIKIT
22 #import <UIKit/UIKit.h>
23 #define NSRect CGRect
24 #define NSMakeRect CGRectMake
25
26 CGContextRef
27 current_context(void)
28 {
29         return UIGraphicsGetCurrentContext();
30 }
31
32 #else
33 #import <Cocoa/Cocoa.h>
34 #define UIView NSView
35 #define UIViewController NSViewController
36 #define UIApplicationDelegate NSApplicationDelegate
37 #define UIWindow NSWindow
38 #define UIApplication NSApplication
39 #define UIApplicationMain(a,b,c,d) NSApplicationMain(a,b)
40 #define UIScreen NSScreen
41 #define UIEvent NSEvent
42 #define applicationFrame frame
43
44 CGContextRef
45 current_context(void)
46 {
47         return [[NSGraphicsContext currentContext] graphicsPort];
48 }
49
50 #endif
51
52
53 @interface NavitView : UIView {
54 @public
55         CGLayerRef layer;
56         CGContextRef layer_context;
57         struct graphics_priv *graphics;
58 }
59
60 @end
61
62 static struct graphics_priv {
63         struct window win;
64         NavitView *view;
65         struct callback_list *cbl;
66         int w;
67         int h;
68 } *global_graphics_cocoa;
69
70 iconv_t utf8_macosroman;
71
72 struct graphics_gc_priv {
73         CGFloat rgba[4];
74         int w;
75 };
76
77 struct graphics_font_priv {
78         int size;
79         char *name;
80 };
81
82
83
84 @implementation NavitView
85
86 - (void)drawRect:(NSRect)rect
87 {
88 #if 0
89         NSLog(@"NavitView:drawRect...");
90 #endif
91
92         CGContextRef X = current_context();
93
94         CGContextDrawLayerAtPoint(X, CGPointZero, layer);
95 }
96
97 #if USE_UIKIT
98 - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event
99 {
100         NSArray *arr=touches.allObjects;
101         UITouch *touch=[arr objectAtIndex: 0];
102         struct CGPoint pc=[touch locationInView: self];
103         struct point p;
104         p.x=pc.x;
105         p.y=pc.y;
106         dbg(0,"Enter count=%d %d %d\n",touches.count,p.x,p.y);
107         callback_list_call_attr_3(graphics->cbl, attr_button, GINT_TO_POINTER(1), GINT_TO_POINTER(1), (void *)&p);
108 }
109
110
111 - (void)touchesCancelled:(NSSet *)touches withEvent:(UIEvent *)event
112 {
113         NSArray *arr=touches.allObjects;
114         UITouch *touch=[arr objectAtIndex: 0];
115         struct CGPoint pc=[touch locationInView: self];
116         struct point p;
117         p.x=pc.x;
118         p.y=pc.y;
119         dbg(0,"Enter count=%d %d %d\n",touches.count,p.x,p.y);
120         callback_list_call_attr_3(graphics->cbl, attr_button, GINT_TO_POINTER(0), GINT_TO_POINTER(1), (void *)&p);
121 }
122
123 - (void)touchesEnded:(NSSet *)touches withEvent:(UIEvent *)event
124 {
125         NSArray *arr=touches.allObjects;
126         UITouch *touch=[arr objectAtIndex: 0];
127         struct CGPoint pc=[touch locationInView: self];
128         struct point p;
129         p.x=pc.x;
130         p.y=pc.y;
131         dbg(0,"Enter count=%d %d %d\n",touches.count,p.x,p.y);
132         callback_list_call_attr_3(graphics->cbl, attr_button, GINT_TO_POINTER(0), GINT_TO_POINTER(1), (void *)&p);
133 }
134
135 - (void)touchesMoved:(NSSet *)touches withEvent:(UIEvent *)event
136 {
137         NSArray *arr=touches.allObjects;
138         UITouch *touch=[arr objectAtIndex: 0];
139         struct CGPoint pc=[touch locationInView: self];
140         struct point p;
141         p.x=pc.x;
142         p.y=pc.y;
143         dbg(0,"Enter count=%d %d %d\n",touches.count,p.x,p.y);
144         callback_list_call_attr_1(graphics->cbl, attr_motion, (void *)&p);
145 }
146
147 #else
148 - (void)mouseDown:(UIEvent *)theEvent
149 {
150         struct point p;
151         p.x=theEvent.locationInWindow.x;
152         p.y=graphics->h-theEvent.locationInWindow.y;
153         
154         dbg(0,"Enter %d %d\n",p.x,p.y);
155         callback_list_call_attr_3(graphics->cbl, attr_button, GINT_TO_POINTER(1), GINT_TO_POINTER(1), (void *)&p);
156 }
157
158 - (void)mouseUp:(UIEvent *)theEvent
159 {
160         struct point p;
161         p.x=theEvent.locationInWindow.x;
162         p.y=graphics->h-theEvent.locationInWindow.y;
163         
164         dbg(0,"Enter %d %d\n",p.x,p.y);
165         callback_list_call_attr_3(graphics->cbl, attr_button, GINT_TO_POINTER(0), GINT_TO_POINTER(1), (void *)&p);
166 }
167
168 - (void)mouseDragged:(UIEvent *)theEvent
169 {
170         struct point p;
171         p.x=theEvent.locationInWindow.x;
172         p.y=graphics->h-theEvent.locationInWindow.y;
173         
174         dbg(0,"Enter %d %d\n",p.x,p.y);
175         callback_list_call_attr_1(graphics->cbl, attr_motion, (void *)&p);
176 }
177 #endif
178
179 - (void)dealloc {
180         [super dealloc];
181 }
182
183
184 @end
185
186 @interface NavitViewController : UIViewController
187 {
188         NSRect frame;
189         CGLayerRef layer;
190 }
191
192 @property (nonatomic) NSRect frame;
193
194 - (id) init_withFrame : (NSRect) _frame;
195
196 @end
197
198
199
200 @implementation NavitViewController
201
202 @synthesize frame;
203
204 - (id) init_withFrame : (NSRect) _frame
205 {
206         NSLog(@"init with frame\n");
207         frame = _frame;
208         return [self init];
209 }
210
211 - (void)loadView
212 {
213         NSLog(@"loadView");
214         NavitView* myV = [NavitView alloc];
215
216         if (global_graphics_cocoa) {
217                 global_graphics_cocoa->view=myV;
218                 global_graphics_cocoa->w=frame.size.width;
219                 global_graphics_cocoa->h=frame.size.height;
220                 myV->graphics=global_graphics_cocoa;
221         }
222
223         CGContextRef X = current_context();
224         CGRect lr=CGRectMake(0, 0, frame.size.width, frame.size.height);
225         myV->layer=CGLayerCreateWithContext(X, lr.size, NULL);
226         myV->layer_context=CGLayerGetContext(myV->layer);
227 #if !USE_UIKIT
228         CGContextScaleCTM(myV->layer_context, 1, -1);
229         CGContextTranslateCTM(myV->layer_context, 0, -frame.size.height);
230 #endif
231         CGContextSetRGBFillColor(myV->layer_context, 1, 1, 1, 1);
232         CGContextSetRGBStrokeColor(myV->layer_context, 1, 1, 1, 1);
233         CGContextFillRect(myV->layer_context, lr);
234
235         [myV initWithFrame: frame];
236
237         [self setView: myV];
238
239         [myV release];
240 }
241
242 - (void)didReceiveMemoryWarning {
243         // Releases the view if it doesn't have a superview.
244         [super didReceiveMemoryWarning];
245
246         // Release any cached data, images, etc that aren't in use.
247 }
248
249 - (void)viewDidUnload {
250         // Release any retained subviews of the main view.
251         // e.g. self.myOutlet = nil;
252 }
253
254
255 - (void)dealloc {
256         [super dealloc];
257 }
258
259 @end
260
261 @class NavitViewController;
262
263 @interface NavitAppDelegate : NSObject <UIApplicationDelegate> {
264         UIWindow *window;
265         NavitViewController *viewController;
266 }
267
268 @property (nonatomic, retain) /*IBOutlet*/ UIWindow *window;
269 @property (nonatomic, retain) /*IBOutlet*/ NavitViewController *viewController;
270
271 @end
272
273
274 @implementation NavitAppDelegate
275
276 @synthesize window;
277 @synthesize viewController;
278
279
280 #if USE_UIKIT
281 - (BOOL)application:(UIApplication *)application
282 didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
283 #else
284 - (void)
285 applicationDidFinishLaunching:(NSNotification *)aNotification
286 #endif
287 {
288         NSLog(@"DidFinishLaunching\n");
289 #if USE_UIKIT
290         [[UIApplication sharedApplication] setStatusBarHidden:NO];
291 #endif
292
293         NSRect appFrame = [UIScreen mainScreen].applicationFrame;
294
295         self.viewController = [[[NavitViewController alloc] init_withFrame : appFrame] autorelease];
296
297         NSRect windowRect = NSMakeRect(0, 0, appFrame.size.width, appFrame.size.height);
298
299 #if USE_UIKIT
300         self.window = [[[UIWindow alloc] initWithFrame:windowRect] autorelease];
301 #else
302         self.window = [[[UIWindow alloc] initWithContentRect:windowRect styleMask:NSBorderlessWindowMask backing:NSBackingStoreBuffered defer:NO] autorelease];
303 #endif
304         utf8_macosroman=iconv_open("MACROMAN","UTF-8");
305
306 #if USE_UIKIT
307         [window addSubview:viewController.view];
308         [window makeKeyAndVisible];
309 #else
310         NSWindowController * controller = [[NSWindowController alloc] initWithWindow : window];
311         NSLog(@"Setting view\n");
312         [viewController loadView];
313         [window setContentView : viewController.view];
314         [controller setWindow : window];
315         [controller showWindow : nil];
316
317 #endif
318
319         if (global_graphics_cocoa) {
320                 callback_list_call_attr_2(global_graphics_cocoa->cbl, attr_resize, (int)appFrame.size.width, (int)appFrame.size.height);
321                 
322         }
323
324 #if USE_UIKIT
325         return YES;
326 #endif
327 }
328
329
330 - (void)dealloc {
331         [viewController release];
332         [window release];
333         [super dealloc];
334 }
335
336
337 @end
338
339
340 static void
341 draw_mode(struct graphics_priv *gr, enum draw_mode_num mode)
342 {
343         if (mode == draw_mode_end) {
344                 dbg(0,"end\n");
345 #if USE_UIKIT
346                 [gr->view setNeedsDisplay];
347 #else
348                 [gr->view display];
349 #endif
350         }
351 }
352
353 static void
354 draw_lines(struct graphics_priv *gr, struct graphics_gc_priv *gc, struct point *p, int count)
355 {
356         CGPoint points[count];
357         int i;
358         for (i = 0 ; i < count ; i++) {
359                 points[i].x=p[i].x;
360                 points[i].y=p[i].y;
361         }
362         CGContextSetStrokeColor(gr->view->layer_context, gc->rgba);
363         CGContextSetLineWidth(gr->view->layer_context, gc->w);
364         CGContextSetLineCap(gr->view->layer_context, kCGLineCapRound);
365         CGContextBeginPath(gr->view->layer_context);
366         CGContextAddLines(gr->view->layer_context, points, count);
367         CGContextStrokePath(gr->view->layer_context);
368         
369 }
370
371 static void
372 draw_polygon(struct graphics_priv *gr, struct graphics_gc_priv *gc, struct point *p, int count)
373 {
374         CGPoint points[count];
375         int i;
376         for (i = 0 ; i < count ; i++) {
377                 points[i].x=p[i].x;
378                 points[i].y=p[i].y;
379         }
380         CGContextSetFillColor(gr->view->layer_context, gc->rgba);
381         CGContextBeginPath(gr->view->layer_context);
382         CGContextAddLines(gr->view->layer_context, points, count);
383         CGContextFillPath(gr->view->layer_context);
384 }
385
386 static void
387 draw_rectangle(struct graphics_priv *gr, struct graphics_gc_priv *gc, struct point *p, int w, int h)
388 {
389         CGRect lr=CGRectMake(p->x, p->y, w, h);
390         CGContextSetFillColor(gr->view->layer_context, gc->rgba);
391         CGContextFillRect(gr->view->layer_context, lr);
392 }
393
394 static void
395 draw_text(struct graphics_priv *gr, struct graphics_gc_priv *fg, struct graphics_gc_priv *bg, struct graphics_font_priv *font, char *text, struct point *p, int dx, int dy)
396 {
397         size_t len,inlen=strlen(text)+1,outlen=strlen(text)+1;
398         char outb[outlen];
399         char *inp=text,*outp=outb;
400
401         len=iconv (utf8_macosroman, &inp, &inlen, &outp, &outlen);
402
403         CGContextSetFillColor(gr->view->layer_context, fg->rgba);
404
405         CGContextSelectFont(gr->view->layer_context, font->name, font->size/16.0, kCGEncodingMacRoman);
406         CGContextSetTextDrawingMode(gr->view->layer_context, kCGTextFill);
407         CGAffineTransform xform = CGAffineTransformMake(dx/65536.0, dy/65536.0, dy/65536.0, -dx/65536.0, 0.0f, 0.0f);
408         CGContextSetTextMatrix(gr->view->layer_context, xform);
409         CGContextShowTextAtPoint(gr->view->layer_context, p->x, p->y, outb, strlen(outb));
410 }
411
412 static void
413 draw_image(struct graphics_priv *gr, struct graphics_gc_priv *fg, struct point *p, struct graphics_image_priv *img)
414 {
415         CGImageRef imgc=(CGImageRef) img;
416         int w=CGImageGetWidth(imgc);
417         int h=CGImageGetHeight(imgc);
418         CGRect rect=CGRectMake(0, 0, w, h);
419         CGContextSaveGState(gr->view->layer_context);
420         CGContextTranslateCTM(gr->view->layer_context, p->x, p->y+h);
421         CGContextScaleCTM(gr->view->layer_context, 1.0, -1.0);
422         CGContextDrawImage(gr->view->layer_context, rect, imgc);
423         CGContextRestoreGState(gr->view->layer_context);
424 }
425
426 static void font_destroy(struct graphics_font_priv *font)
427 {
428         g_free(font);
429 }
430
431 static struct graphics_font_methods font_methods = {
432         font_destroy
433 };
434
435 static struct graphics_font_priv *font_new(struct graphics_priv *gr, struct graphics_font_methods *meth, char *font,  int size, int flags)
436 {
437         struct graphics_font_priv *ret=g_new0(struct graphics_font_priv, 1);
438         *meth=font_methods;
439
440         ret->size=size;
441         ret->name="Helvetica";
442         return ret;
443 }
444
445 static void
446 gc_destroy(struct graphics_gc_priv *gc)
447 {
448         g_free(gc);
449 }
450
451 static void
452 gc_set_linewidth(struct graphics_gc_priv *gc, int w)
453 {
454         gc->w=w;
455 }
456
457 static void
458 gc_set_dashes(struct graphics_gc_priv *gc, int w, int offset, unsigned char *dash_list, int n)
459 {
460 }
461
462 static void
463 gc_set_foreground(struct graphics_gc_priv *gc, struct color *c)
464 {
465         gc->rgba[0]=c->r/65535.0;
466         gc->rgba[1]=c->g/65535.0;
467         gc->rgba[2]=c->b/65535.0;
468         gc->rgba[3]=c->a/65535.0;
469 }
470
471 static void
472 gc_set_background(struct graphics_gc_priv *gc, struct color *c)
473 {
474 }
475
476 static void
477 gc_set_stipple(struct graphics_gc_priv *gc, struct graphics_image_priv *img)
478 {
479 }
480
481 static struct graphics_gc_methods gc_methods = {
482         gc_destroy, 
483         gc_set_linewidth, 
484         gc_set_dashes,
485         gc_set_foreground,
486         gc_set_background,
487         gc_set_stipple,
488 };
489
490 static struct graphics_gc_priv *gc_new(struct graphics_priv *gr, struct graphics_gc_methods *meth)
491 {
492         struct graphics_gc_priv *gc=g_new(struct graphics_gc_priv, 1);
493         gc->w=1;
494
495         *meth=gc_methods;
496         return gc;
497 }
498
499
500 static void
501 background_gc(struct graphics_priv *gr, struct graphics_gc_priv *gc)
502 {
503 }
504
505
506 static struct graphics_image_priv *
507 image_new(struct graphics_priv *gra, struct graphics_image_methods *meth, char *path, int *w, int *h, struct point *hot, int rotation)
508 {
509         NSString *s=[[NSString alloc]initWithCString:path encoding:NSMacOSRomanStringEncoding];
510         CGDataProviderRef imgDataProvider = CGDataProviderCreateWithCFData((CFDataRef)[NSData dataWithContentsOfFile:s]);
511         [s release];
512
513         if (!imgDataProvider)
514                 return NULL;
515
516         CGImageRef image = CGImageCreateWithPNGDataProvider(imgDataProvider, NULL, true, kCGRenderingIntentDefault);
517         CGDataProviderRelease(imgDataProvider);
518         dbg(0,"size %dx%d\n",CGImageGetWidth(image),CGImageGetHeight(image));
519         if (w)
520                 *w=CGImageGetWidth(image);
521         if (h)
522                 *h=CGImageGetHeight(image);
523         if (hot) {
524                 hot->x=CGImageGetWidth(image)/2;
525                 hot->y=CGImageGetHeight(image)/2;
526         }
527         return image;
528 }
529
530 static void *
531 get_data(struct graphics_priv *this, const char *type)
532 {
533         dbg(0,"enter\n");
534         if (strcmp(type,"window"))
535                 return NULL;
536         return &this->win;
537 }
538
539 static void
540 image_free(struct graphics_priv *gr, struct graphics_image_priv *priv)
541 {
542         CGImageRelease(priv);
543 }
544
545 static void
546 get_text_bbox(struct graphics_priv *gr, struct graphics_font_priv *font, char *text, int dx, int dy, struct point *ret, int estimate)
547 {
548         int len = g_utf8_strlen(text, -1);
549         int xMin = 0;
550         int yMin = 0;
551         int yMax = 13*font->size/256;
552         int xMax = 9*font->size*len/256;
553
554         ret[0].x = xMin;
555         ret[0].y = -yMin;
556         ret[1].x = xMin;
557         ret[1].y = -yMax;
558         ret[2].x = xMax;
559         ret[2].y = -yMax;
560         ret[3].x = xMax;
561         ret[3].y = -yMin;
562 }
563
564 static struct graphics_methods graphics_methods = {
565         NULL, /* graphics_destroy, */
566         draw_mode,
567         draw_lines,
568         draw_polygon,
569         draw_rectangle,
570         NULL, /* draw_circle, */
571         draw_text, 
572         draw_image,
573         NULL, /* draw_image_warp, */
574         NULL, /* draw_restore, */
575         NULL, /* draw_drag, */
576         font_new,
577         gc_new,
578         background_gc,
579         NULL, /* overlay_new, */
580         image_new,
581         get_data,
582         image_free,
583         get_text_bbox,
584         NULL, /* overlay_disable, */
585         NULL, /* overlay_resize, */
586         NULL, /* set_attr, */
587 };
588
589
590
591 struct graphics_priv *
592 graphics_cocoa_new(struct navit *nav, struct graphics_methods *meth, struct attr **attrs, struct callback_list *cbl)
593 {
594         struct graphics_priv *ret;
595         *meth=graphics_methods;
596         dbg(0,"enter\n");
597         if(!event_request_system("cocoa","graphics_cocoa"))
598                 return NULL;
599         ret=g_new0(struct graphics_priv, 1);
600         ret->cbl=cbl;
601         global_graphics_cocoa=ret;
602         return ret;
603 }
604
605 static void
606 event_cocoa_main_loop_run(void)
607 {
608
609         dbg(0,"enter\n");
610 #if 0
611         NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
612         NSString *documentsDirectory = [paths objectAtIndex:0];
613         NSString *logPath = [documentsDirectory stringByAppendingPathComponent:@"console.log"];
614         freopen("/tmp/log.txt","a+",stderr);
615         NSLog(@"Test\n");
616 #endif
617         NSAutoreleasePool * pool = [[NSAutoreleasePool alloc] init];
618 #if USE_UIKIT
619         dbg(0,"calling main\n");
620         int retval = UIApplicationMain(main_argc, main_argv, nil, @"NavitAppDelegate");
621         dbg(0,"retval=%d\n",retval);
622 #else
623         NavitAppDelegate * delegate = [[NavitAppDelegate alloc] init];
624         NSApplication * application = [NSApplication sharedApplication];
625         [application setDelegate:delegate];
626         NSLog(@"Test\n");
627
628         [NSApp run];
629
630         [delegate release];
631 #endif
632         [pool release];
633 }
634
635 @interface NavitTimer : NSObject{
636 @public
637         struct callback *cb;
638         NSTimer *timer;
639 }
640 - (void)onTimer:(NSTimer*)theTimer;
641
642 @end
643
644 @implementation NavitTimer
645
646 - (void)onTimer:(NSTimer*)theTimer
647 {
648         callback_call_0(cb);
649 }
650
651
652 @end
653
654 struct event_idle {
655         struct callback *cb;
656         NSTimer *timer;
657 };
658
659 static void *
660 event_cocoa_add_timeout(int timeout, int multi, struct callback *cb)
661 {
662         NavitTimer *ret=[[NavitTimer alloc]init];
663         ret->cb=cb;
664         ret->timer=[NSTimer scheduledTimerWithTimeInterval:(timeout/1000.0) target:ret selector:@selector(onTimer:) userInfo:nil repeats:multi?YES:NO];
665         dbg(0,"timer=%p\n",ret->timer);
666         return ret;
667 }
668
669
670 static void
671 event_cocoa_remove_timeout(struct event_timeout *ev)
672 {
673         NavitTimer *t=(NavitTimer *)ev;
674         
675         [t->timer invalidate];
676         [t release];
677 }
678
679
680 static struct event_idle *
681 event_cocoa_add_idle(int priority, struct callback *cb)
682 {
683         NavitTimer *ret=[[NavitTimer alloc]init];
684         ret->cb=cb;
685         ret->timer=[NSTimer scheduledTimerWithTimeInterval:(0.0) target:ret selector:@selector(onTimer:) userInfo:nil repeats:YES];
686
687         dbg(0,"timer=%p\n",ret->timer);
688         return ret;
689 }
690
691 static void
692 event_cocoa_remove_idle(struct event_idle *ev)
693 {
694         NavitTimer *t=(NavitTimer *)ev;
695         
696         [t->timer invalidate];
697         [t release];
698 }
699
700 static struct event_methods event_cocoa_methods = {
701         event_cocoa_main_loop_run,
702         NULL, /* event_cocoa_main_loop_quit, */
703         NULL, /* event_cocoa_add_watch, */
704         NULL, /* event_cocoa_remove_watch, */
705         event_cocoa_add_timeout,
706         event_cocoa_remove_timeout,
707         event_cocoa_add_idle,
708         event_cocoa_remove_idle, 
709         NULL, /* event_cocoa_call_callback, */
710 };
711
712
713 static struct event_priv *
714 event_cocoa_new(struct event_methods *meth)
715 {
716         dbg(0,"enter\n");
717         *meth=event_cocoa_methods;
718         return NULL;
719 }
720
721
722 void
723 plugin_init(void)
724 {
725         dbg(0,"enter\n");
726         plugin_register_graphics_type("cocoa", graphics_cocoa_new);
727         plugin_register_event_type("cocoa", event_cocoa_new);
728 }