Back to index

texmacs  1.0.7.15
aqua_menu.mm
Go to the documentation of this file.
00001 
00002 /******************************************************************************
00003 * MODULE     : aqua_menu.h
00004 * DESCRIPTION: Aqua menu proxies
00005 * COPYRIGHT  : (C) 2007  Massimiliano Gubinelli
00006 *******************************************************************************
00007 * This software falls under the GNU general public license version 3 or later.
00008 * It comes WITHOUT ANY WARRANTY WHATSOEVER. For details, see the file LICENSE
00009 * in the root directory or <http://www.gnu.org/licenses/gpl-3.0.html>.
00010 ******************************************************************************/
00011 
00012 #include "mac_cocoa.h"
00013 #include "aqua_menu.h"
00014 #include "aqua_utilities.h"
00015 //#include "aqua_renderer.h"
00016 #include "aqua_renderer.h"
00017 #include "aqua_simple_widget.h"
00018 #include "aqua_basic_widgets.h"
00019 
00020 #include "widget.hpp" 
00021 #include "message.hpp"
00022 #include "analyze.hpp"
00023 
00024 #include "promise.hpp"
00025 #include <typeinfo>
00026 
00027 #import "TMView.h"
00028 
00029 NSMenu *alloc_menu() { return [NSMenu alloc]; }
00030 NSMenuItem *alloc_menuitem() { return [NSMenuItem alloc]; }
00031 
00032 class aqua_menu_rep : public aqua_widget_rep  {
00033 public:
00034        NSMenuItem *item;
00035        aqua_menu_rep(NSMenuItem* _item) : item(_item) { [item retain]; }
00036        ~aqua_menu_rep()  { [item release]; }
00037 
00038        virtual void send (slot s, blackbox val);
00039        virtual widget make_popup_widget (); 
00040        virtual widget popup_window_widget (string s); 
00041 
00042   virtual TMMenuItem *as_menuitem() { return (TMMenuItem *)item; }
00043 
00044 };
00045 
00046 widget aqua_menu_rep::make_popup_widget ()
00047 {
00048        return this;
00049 }
00050 
00051 widget aqua_menu_rep::popup_window_widget (string s)
00052 {
00053        [item setTitle:to_nsstring(s)];
00054        return this;
00055 }
00056 
00057 
00058 void aqua_menu_rep::send (slot s, blackbox val) {
00059   switch (s) {
00060   case SLOT_POSITION:
00061     {
00062       ASSERT (type_box (val) == type_helper<coord2>::id, "type mismatch");
00063     }
00064     break;
00065   case SLOT_VISIBILITY:
00066     {  
00067       check_type<bool> (val, "SLOT_VISIBILITY");
00068       bool flag = open_box<bool> (val);
00069       (void) flag;
00070     }  
00071     break;
00072   case SLOT_MOUSE_GRAB:
00073     {  
00074       check_type<bool> (val, "SLOT_MOUSE_GRAB");
00075       bool flag = open_box<bool> (val);
00076       (void) flag;
00077       [NSMenu popUpContextMenu:[item submenu] withEvent:[NSApp currentEvent] forView:( (aqua_view_widget_rep*)(the_keyboard_focus.rep))->view ];
00078     }  
00079     //               send_mouse_grab (THIS, val);
00080     break;
00081     
00082   default:
00083     FAILED ("cannot handle slot type");
00084   }
00085 }
00086 
00087 #if 0
00088 class aqua_menu_text_rep : public aqua_basic_widget_rep {
00089 public:
00090        NSString *text;
00091        aqua_menu_text_rep(NSString* _text) : text(_text) { [text retain]; }
00092        ~aqua_menu_text_rep()  { [text release]; }
00093 };
00094 
00095 #endif
00096 
00097 
00098 @interface TMMenuItem : NSMenuItem
00099 {
00100        command_rep *cmd;
00101        simple_widget_rep* wid;// an eventual box widget (see tm_button.cpp)
00102 }
00103 - (void)setCommand:(command_rep *)_c;
00104 - (void)setWidget:(simple_widget_rep *)_w;
00105 - (void)doit;
00106 @end
00107 
00108 @implementation TMMenuItem
00109 - (void)setCommand:(command_rep *)_c 
00110 {  
00111        if (cmd) { DEC_COUNT_NULL(cmd); } cmd = _c; 
00112        if (cmd) {
00113               INC_COUNT_NULL(cmd);
00114          [self setAction:@selector(doit)];
00115          [self setTarget:self];
00116        }
00117 }
00118 - (void)setWidget:(simple_widget_rep *)_w
00119 {  
00120        if (wid) { DEC_COUNT_NULL(wid); } wid = _w; 
00121        if (wid) {
00122               INC_COUNT_NULL(wid);
00123        }
00124 }
00125 - (void)dealloc { [self setCommand:NULL];  [self setWidget:NULL];  [super dealloc]; }
00126 - (void)doit {       if (cmd) cmd->apply(); }
00127 
00128 
00129 - (NSImage*) image
00130 {
00131   NSImage *img = [super image];
00132   if ((!img)&&(wid))
00133   {
00134     SI width, height;
00135     wid->handle_get_size_hint (width,height);
00136     NSSize s = NSMakeSize(width/PIXEL,height/PIXEL);
00137     
00138     img = [[[NSImage alloc] initWithSize:s] autorelease];
00139     [img lockFocus];
00140     
00141     basic_renderer r = the_aqua_renderer();
00142     int x1 = 0;
00143     int y1 = s.height;
00144     int x2 = s.width;
00145     int y2 = 0;
00146     
00147     r -> begin([NSGraphicsContext currentContext]);
00148     
00149     r -> encode (x1,y1);
00150     r -> encode (x2,y2);
00151     r -> set_clipping (x1,y1,x2,y2);
00152     wid -> handle_repaint (x1,y1,x2,y2);
00153     r->end();
00154     [img unlockFocus];
00155     //[img setFlipped:YES];
00156     [super setImage:img];                 
00157     [self setWidget:NULL];
00158   }
00159   return img;
00160 }
00161 @end
00162 
00163 
00164 
00165 @interface TMLazyMenu : NSMenu
00166 {
00167        promise_rep<widget> *pm;
00168        BOOL forced;
00169 }
00170 - (void)setPromise:(promise_rep<widget> *)p;
00171 @end
00172 
00173 @implementation TMLazyMenu
00174 - (void)setPromise:(promise_rep<widget> *)p 
00175 { 
00176        if (pm) { DEC_COUNT_NULL(pm); }  pm = p;  INC_COUNT_NULL(pm); 
00177        forced = NO;
00178        [self setDelegate:self];
00179 }
00180 - (void)dealloc { [self setPromise:NULL]; [super dealloc]; }
00181 
00182 - (void)menuNeedsUpdate:(NSMenu *)menu
00183 {
00184        if (!forced) {
00185               widget w = pm->eval();
00186               aqua_menu_rep *wid = (aqua_menu_rep*)(w.rep); 
00187               NSMenu *menu2 = [wid->item submenu];
00188               unsigned count = [menu2 numberOfItems];
00189               for (unsigned j=0; j<count; j++)
00190               {
00191                      NSMenuItem *itm = [[[menu2 itemAtIndex:0] retain] autorelease];
00192                      [menu2 removeItem:itm];
00193                      [menu insertItem:itm atIndex:j];
00194               }
00195               DEC_COUNT_NULL(pm); pm = NULL;
00196               forced = YES;
00197        }
00198 }
00199 
00200 - (BOOL)menuHasKeyEquivalent:(NSMenu *)menu forEvent:(NSEvent *)event target:(id *)target action:(SEL *)action
00201 {
00202        return NO;
00203        // disable keyboard handling for lazy menus
00204 }
00205 @end
00206 
00207 
00208 
00209 /******************************************************************************
00210  * Widgets for the construction of menus
00211  ******************************************************************************/
00212 
00213 widget horizontal_menu (array<widget> a) 
00214 // a horizontal menu made up of the widgets in a
00215 {
00216        NSMenuItem* mi = [[alloc_menuitem() initWithTitle:@"Menu" action:NULL keyEquivalent:@""] autorelease];
00217        NSMenu *menu = [[alloc_menu() init] autorelease];
00218        for(int i = 0; i < N(a); i++) {
00219               if (is_nil(a[i])) 
00220                      break;
00221       [menu addItem: concrete(a[i])->as_menuitem()];
00222        };
00223        [mi setSubmenu:menu];
00224        return tm_new <aqua_menu_rep> (mi);       
00225 }
00226 
00227 widget
00228 horizontal_list (array<widget> a) {
00229   return horizontal_menu (a);
00230 }  
00231 
00232 widget minibar_menu (array<widget> a) {
00233   return horizontal_menu (a);
00234 }
00235 
00236 widget vertical_menu (array<widget> a) { return horizontal_menu(a); }
00237 // a vertical menu made up of the widgets in a
00238 
00239 widget
00240 vertical_list (array<widget> a) {
00241   return vertical_menu (a);
00242 }
00243 
00244 @interface TMTileView : NSMatrix
00245 {
00246        int cols;
00247 }
00248 - (id) initWithObjects:(NSArray*)objs cols:(int)_cols;
00249 - (void) click:(TMTileView*)tile;
00250 @end
00251 
00252 
00253 @implementation TMTileView
00254 - (void) dealloc
00255 {
00256        [super dealloc];
00257 }
00258 - (id) initWithObjects:(NSArray*)objs cols:(int)_cols
00259 {
00260        self = [super init];
00261        if (self != nil) {
00262               int current_col;
00263               int current_row;
00264               cols = _cols;
00265               current_col = cols;
00266               current_row = -1;
00267               [self setCellSize:NSMakeSize(20,20)];
00268               [self renewRows:0 columns:cols];
00269     NSEnumerator *en = [objs objectEnumerator];
00270               NSMenuItem *mi;
00271               while ((mi = [en nextObject])) {
00272                      if (current_col == cols) {
00273                             current_col=0; current_row++;
00274                             [self addRow];
00275                      }
00276                      NSImageCell *cell = [[[NSImageCell alloc] initImageCell:[mi image]] autorelease];
00277        //            [cell setImage:[mi image]];
00278                      [cell setRepresentedObject:mi];
00279                      [self putCell:cell atRow:current_row column:current_col];
00280                      current_col++;                     
00281               }
00282               
00283               [self setTarget:self];
00284               [self setAction:@selector(click:)];
00285               [self sizeToCells];
00286        }
00287        return self;
00288 }
00289 
00290 - (void) click:(TMTileView*)tile
00291 {
00292        // on mouse up, we want to dismiss the menu being tracked
00293        NSMenuItem* mi = [self enclosingMenuItem];
00294        //[[mi menu] performSelector:@selector(cancelTracking) withObject:nil afterDelay:0.0];
00295        [[mi menu] cancelTracking];
00296   TMMenuItem* item =  [(NSCell*)[self selectedCell]  representedObject];
00297 //     [item performSelector:@selector(doit) withObject:nil afterDelay:0.0];
00298        [item doit];
00299 }
00300 
00301 #if 0
00302 - (void)mouseDown:(NSEvent*)event
00303 {
00304        [super mouseDown:event];    
00305        // on mouse up, we want to dismiss the menu being tracked
00306        NSMenu* menu = [[self enclosingMenuItem] menu];
00307        [menu cancelTracking];
00308        
00309 }
00310 #endif
00311 @end
00312 
00313 
00314 
00315 
00316 
00317 widget tile_menu (array<widget> a, int cols) 
00318 // a menu rendered as a table of cols columns wide & made up of widgets in a
00319 { 
00320 //     return horizontal_menu(a); 
00321        NSMutableArray *tiles = [NSMutableArray arrayWithCapacity:N(a)];
00322        for(int i = 0; i < N(a); i++) {
00323               if (is_nil(a[i]))  break;
00324 //            [tiles addObject:( (aqua_menu_rep*)(a[i].rep))->item];
00325       [tiles addObject:concrete(a[i])->as_menuitem()];
00326        };
00327        TMTileView* tv = [[[TMTileView alloc] initWithObjects:tiles cols:cols] autorelease];
00328        
00329        NSMenuItem* mi = [[[NSMenuItem alloc] initWithTitle:@"Tile" action:NULL keyEquivalent:@""] autorelease];
00330 
00331        
00332        [mi setView:tv];
00333        return tm_new <aqua_menu_rep> (mi);
00334        
00335 }
00336 
00337 
00338 
00339 widget menu_separator (bool vertical) { return tm_new <aqua_menu_rep> ([NSMenuItem separatorItem]); }
00340 // a horizontal or vertical menu separator
00341 widget menu_group (string name, int style)
00342 // a menu group; the name should be greyed and centered
00343 {
00344        (void) style;
00345        NSMenuItem* mi = [[alloc_menuitem() initWithTitle:to_nsstring_utf8(name) action:NULL keyEquivalent:@""] autorelease];
00346 
00347        //     NSAttributedString *str = [mi attributedTitle];
00348        NSMutableParagraphStyle *pstyle = [[[NSParagraphStyle defaultParagraphStyle] mutableCopy] autorelease];
00349 //     NSMutableParagraphStyle *style = [(NSParagraphStyle*)[str attribute:NSParagraphStyleAttributeName atIndex:0 effectiveRange:NULL] mutableCopy];
00350        [pstyle setAlignment: NSCenterTextAlignment];
00351        [mi setAttributedTitle:[[[NSAttributedString alloc] 
00352                                initWithString: [mi title]
00353                                    attributes: [NSDictionary 
00354                                       dictionaryWithObjectsAndKeys:pstyle, NSParagraphStyleAttributeName, nil]]
00355                                 autorelease]];
00356        return tm_new <aqua_menu_rep> (mi);
00357 }
00358 
00359 widget pulldown_button (widget w, promise<widget> pw) 
00360 // a button w with a lazy pulldown menu pw
00361 {
00362 //     NSString *title = (is_nil(w)? @"":((aqua_menu_text_rep*)w.rep)->text);
00363 //     NSMenuItem *mi = [[alloc_menuitem() initWithTitle:title action:NULL keyEquivalent:@""] autorelease];
00364 //     TMMenuItem* mi =  (TMMenuItem*)((aqua_menu_rep*)w.rep) -> item;
00365   TMMenuItem* mi = concrete(w) -> as_menuitem();
00366    
00367   TMLazyMenu *lm = [[[TMLazyMenu alloc] init] autorelease];
00368        [lm setPromise:pw.rep];
00369        [mi setSubmenu: lm];
00370        return tm_new <aqua_menu_rep> (mi);
00371 }
00372 
00373 widget pullright_button (widget w, promise<widget> pw)
00374 // a button w with a lazy pullright menu pw
00375 {
00376        return pulldown_button(w, pw);
00377 }
00378 
00379 
00380 TMMenuItem * aqua_text_widget_rep::as_menuitem()
00381 {
00382   return [[[TMMenuItem alloc] initWithTitle:to_nsstring_utf8(str) action:NULL keyEquivalent:@""] autorelease];
00383 }
00384 
00385 TMMenuItem * aqua_image_widget_rep::as_menuitem()
00386 {
00387 #if 0
00388   CGImageRef cgi = the_aqua_renderer()->xpm_image(image);
00389   NSImage *img = [[[NSImage alloc] init] autorelease];
00390   [img addRepresentation:[[NSBitmapImageRep alloc ] initWithCGImage: cgi]];
00391 #else
00392   NSImage *img = the_aqua_renderer()->xpm_image(image);
00393 #endif
00394   //   TMMenuItem *mi = [[[TMMenuItem alloc] initWithTitle:to_nsstring(as_string(file_name)) action:NULL keyEquivalent:@""] autorelease];
00395   TMMenuItem *mi = [[[TMMenuItem alloc] initWithTitle:@"" action:NULL keyEquivalent:@""] autorelease];
00396   [mi setRepresentedObject:img];
00397   [mi setImage:img];
00398   
00399   return  mi;
00400 }
00401 
00402 TMMenuItem * aqua_balloon_widget_rep::as_menuitem()
00403 {
00404   TMMenuItem *mi = ((aqua_widget_rep*)text.rep)->as_menuitem();
00405   [mi setToolTip:to_nsstring(((aqua_text_widget_rep*)hint.rep)->str)];
00406   return mi;
00407 }
00408 
00409 
00410 widget menu_button (widget w, command cmd, string pre, string ks, int style)
00411 // a command button with an optional prefix (o, * or v) and
00412 // keyboard shortcut; if ok does not hold, then the button is greyed
00413 {
00414   bool ok= (style & WIDGET_STYLE_INERT) == 0;
00415   TMMenuItem *mi = nil;
00416   
00417   if (typeid(*(w.rep)) == typeid(simple_widget_rep)) {
00418     mi = [[[TMMenuItem alloc] init] autorelease];
00419     [mi setWidget:(simple_widget_rep*)w.rep];
00420   } else  {
00421     mi = ((aqua_widget_rep*)w.rep)->as_menuitem();
00422   }
00423 
00424   [mi setCommand: cmd.rep];
00425   [mi setEnabled:(ok ? YES : NO)];
00426        // FIXME: implement complete prefix handling and keyboard shortcuts
00427        // cout << "ks: "<< ks << "\n";
00428        [mi setState:(pre!="" ? NSOnState: NSOffState)];
00429        if (pre == "v") {
00430        } else if (pre == "*") {
00431 //            [mi setOnStateImage:[NSImage imageNamed:@"TMStarMenuBullet"]];
00432        } else if (pre == "o") {
00433        }
00434        return tm_new <aqua_menu_rep> (mi);
00435 }
00436 
00437 widget balloon_widget (widget w, widget help) 
00438 // given a button widget w, specify a help balloon which should be displayed
00439 // when the user leaves the mouse pointer on the button for a small while
00440 { 
00441   return tm_new <aqua_balloon_widget_rep> (w,help);
00442 }
00443 
00444 widget text_widget (string s, int style, color col, bool tsp) 
00445 // a text widget with a given color, transparency and language
00446 {
00447   (void) style;
00448   string t= tm_var_encode (s);
00449   return tm_new <aqua_text_widget_rep> (t,col,tsp);
00450 }
00451 widget xpm_widget (url file_name)// { return widget(); }
00452 // a widget with an X pixmap icon
00453 {
00454   return tm_new <aqua_image_widget_rep> (file_name);
00455 #if 0  
00456        NSImage *image = the_aqua_renderer()->xpm_image(file_name);
00457 //     TMMenuItem *mi = [[[TMMenuItem alloc] initWithTitle:to_nsstring(as_string(file_name)) action:NULL keyEquivalent:@""] autorelease];
00458        TMMenuItem *mi = [[[TMMenuItem alloc] initWithTitle:@"" action:NULL keyEquivalent:@""] autorelease];
00459        [mi setRepresentedObject:image];
00460        [mi setImage:image];
00461   return tm_new <aqua_menu_rep> (mi);
00462 //     return new aqua_menu_text_rep(to_nsstring(as_string(file_name)));
00463 #endif
00464 }
00465 
00466 NSMenu* to_nsmenu(widget w)
00467 {
00468   if (typeid(*w.rep) == typeid(aqua_menu_rep)) {
00469     aqua_menu_rep *ww = ((aqua_menu_rep*)w.rep);
00470        NSMenu *m =[[[ww->item submenu] retain] autorelease];
00471        [ww->item setSubmenu:nil];
00472        return m;
00473   }
00474   else return nil;
00475 }
00476 
00477 NSMenuItem* to_nsmenuitem(widget w)
00478 {
00479        return ((aqua_menu_rep*)w.rep)->item;
00480 }
00481 
00482  TMMenuItem *simple_widget_rep::as_menuitem()
00483 {
00484   TMMenuItem *mi = [[[TMMenuItem alloc] init] autorelease];
00485   [mi setWidget:this];
00486   return mi;
00487 }
00488