├── .DS_Store ├── .gitignore ├── DetectingTableView.h ├── DetectingTableView.m ├── English.lproj ├── InfoPlist.strings └── MainMenu.xib ├── JGMenuItem.h ├── JGMenuItem.m ├── PaddedTextFieldCell.h ├── PaddedTextFieldCell.m ├── README.markdown ├── Status View + Coloring ├── .DS_Store ├── CustomStatusItemView.h ├── CustomStatusItemView.m ├── FullMenuView.h └── FullMenuView.m ├── StatusItem-Info.plist ├── StatusItem.xcodeproj ├── joshuagarnham.pbxuser ├── joshuagarnham.perspectivev3 ├── project.pbxproj ├── project.xcworkspace │ ├── contents.xcworkspacedata │ ├── xcshareddata │ │ └── StatusItem.xccheckout │ └── xcuserdata │ │ └── joshuagarnham.xcuserdatad │ │ └── UserInterfaceState.xcuserstate ├── xcshareddata │ └── xcschemes │ │ └── StatusItem.xcscheme └── xcuserdata │ └── joshuagarnham.xcuserdatad │ └── xcschemes │ └── xcschememanagement.plist ├── StatusItemAppDelegate.h ├── StatusItemAppDelegate.m ├── StatusItem_Prefix.pch ├── Window ├── BorderlessWindow.h ├── BorderlessWindow.m ├── JGMenuWindow.xib ├── JGMenuWindowController.h ├── JGMenuWindowController.m ├── NSBezierPath+PXRoundedRectangleAdditions.h ├── NSBezierPath+PXRoundedRectangleAdditions.m ├── RoundWindowFrameView.h └── RoundWindowFrameView.m ├── img.png └── main.m /.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SquaredTiki/JGMenuWindow/34b583bf9875915da8a3442e27cf880b5bd283f5/.DS_Store -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DSStore -------------------------------------------------------------------------------- /DetectingTableView.h: -------------------------------------------------------------------------------- 1 | @interface DetectingTableView : NSTableView 2 | { 3 | NSTrackingRectTag trackingTag; 4 | } 5 | @end -------------------------------------------------------------------------------- /DetectingTableView.m: -------------------------------------------------------------------------------- 1 | 2 | #import "DetectingTableView.h" 3 | 4 | @implementation DetectingTableView 5 | 6 | - (void)awakeFromNib 7 | { 8 | [[self window] setAcceptsMouseMovedEvents:YES]; 9 | trackingTag = [self addTrackingRect:[self frame] owner:self userData:nil assumeInside:NO]; 10 | } 11 | 12 | - (void)dealloc 13 | { 14 | [self removeTrackingRect:trackingTag]; 15 | [super dealloc]; 16 | } 17 | 18 | - (void)viewDidEndLiveResize 19 | { 20 | [super viewDidEndLiveResize]; 21 | 22 | [self removeTrackingRect:trackingTag]; 23 | trackingTag = [self addTrackingRect:[self frame] owner:self userData:nil assumeInside:NO]; 24 | } 25 | 26 | - (void)mouseDown:(NSEvent *)event { 27 | // Pass it on to window controller view 28 | [[[[self window] contentView] superview] mouseDownInTableViewWithEvent:event]; 29 | // [super mouseDown:event]; 30 | } 31 | 32 | @end -------------------------------------------------------------------------------- /English.lproj/InfoPlist.strings: -------------------------------------------------------------------------------- 1 | /* Localized versions of Info.plist keys */ 2 | 3 | -------------------------------------------------------------------------------- /JGMenuItem.h: -------------------------------------------------------------------------------- 1 | // 2 | // JGMenuItem.h 3 | // StatusItem 4 | // 5 | // Created by Joshua Garnham on 17/04/2011. 6 | // Copyright 2011 __MyCompanyName__. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "JGMenuWindowController.h" 11 | 12 | @class JGMenuWindowController; 13 | 14 | @interface JGMenuItem : NSObject { 15 | NSString *title; 16 | id target; 17 | SEL action; 18 | NSImage *image; 19 | BOOL enabled; 20 | JGMenuWindowController *submenu; 21 | } 22 | 23 | @property (nonatomic, retain, readonly) NSString *title; 24 | @property (nonatomic, assign, readonly) id target; 25 | @property (nonatomic, assign, readonly) SEL action; 26 | @property (nonatomic, copy) NSImage *image; 27 | @property (nonatomic, assign) BOOL enabled; 28 | @property (nonatomic, retain) JGMenuWindowController *submenu; 29 | 30 | - (id)initWithTitle:(NSString *)title target:(id)target action:(SEL)action; 31 | + (NSString *)seperatorItem; 32 | 33 | @end 34 | -------------------------------------------------------------------------------- /JGMenuItem.m: -------------------------------------------------------------------------------- 1 | // 2 | // JGMenuItem.m 3 | // StatusItem 4 | // 5 | // Created by Joshua Garnham on 17/04/2011. 6 | // Copyright 2011 __MyCompanyName__. All rights reserved. 7 | // 8 | 9 | #import "JGMenuItem.h" 10 | 11 | @implementation JGMenuItem 12 | @synthesize title, target, action, enabled, submenu; 13 | @dynamic image; 14 | 15 | - (id)initWithTitle:(NSString *)str target:(id)trg action:(SEL)act { 16 | self = [super init]; 17 | if (self) { 18 | title = [str copy]; 19 | target = trg; 20 | action = act; 21 | enabled = YES; 22 | } 23 | return self; 24 | } 25 | 26 | + (NSString *)seperatorItem { 27 | return [[self alloc] initWithTitle:@"--[SEPERATOR]--" target:NULL action:NULL]; 28 | } 29 | 30 | - (NSImage *)image { 31 | return image; 32 | } 33 | 34 | - (void)setImage:(NSImage *)newImage { 35 | [image release]; 36 | image = [newImage copy]; 37 | } 38 | 39 | @end 40 | -------------------------------------------------------------------------------- /PaddedTextFieldCell.h: -------------------------------------------------------------------------------- 1 | // 2 | // PaddedTextFieldCell.h 3 | // StatusItem 4 | // 5 | // Created by Joshua Garnham on 17/04/2011. 6 | // Copyright 2011 __MyCompanyName__. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | 12 | @interface PaddedTextFieldCell : NSTextFieldCell { 13 | int leftMargin; 14 | } 15 | 16 | @property (nonatomic, assign) int leftMargin; 17 | 18 | @end 19 | -------------------------------------------------------------------------------- /PaddedTextFieldCell.m: -------------------------------------------------------------------------------- 1 | // 2 | // PaddedTextFieldCell.m 3 | // StatusItem 4 | // 5 | // Created by Joshua Garnham on 17/04/2011. 6 | // Copyright 2011 __MyCompanyName__. All rights reserved. 7 | // 8 | 9 | #import "PaddedTextFieldCell.h" 10 | 11 | @implementation PaddedTextFieldCell 12 | @dynamic leftMargin; 13 | 14 | - (void)drawInteriorWithFrame:(NSRect)cellFrame 15 | inView:(NSView *)controlView 16 | { 17 | if (leftMargin == 0) 18 | leftMargin = 15; 19 | cellFrame.origin.x += leftMargin; 20 | cellFrame.size.width -= leftMargin; 21 | [super drawInteriorWithFrame:cellFrame 22 | inView:controlView]; 23 | } 24 | 25 | - (void)selectWithFrame:(NSRect)aRect 26 | inView:(NSView *)controlView 27 | editor:(NSText *)textObj 28 | delegate:(id)anObject 29 | start:(NSInteger)selStart 30 | length:(NSInteger)selLength 31 | { 32 | aRect.origin.x += leftMargin; 33 | aRect.size.width -= leftMargin; 34 | [super selectWithFrame:aRect 35 | inView:controlView 36 | editor:textObj 37 | delegate:anObject 38 | start:selStart 39 | length:selLength]; 40 | } 41 | 42 | - (NSRect)_focusRingFrameForFrame:(NSRect)frame 43 | cellFrame:(NSRect)cellFrame 44 | { 45 | return [[self controlView] bounds]; 46 | } 47 | 48 | - (int)leftMargin { 49 | return leftMargin; 50 | } 51 | 52 | - (void)setLeftMargin:(int)newMargin { 53 | leftMargin = newMargin; 54 | } 55 | 56 | @end 57 | -------------------------------------------------------------------------------- /README.markdown: -------------------------------------------------------------------------------- 1 | # JGMenuWindow 2 | 3 | The main aim of this project was to create a `NSWindow` and `NSTableView` with the appearance of a normal `NSMenu`. The benefits of this means that you can have a text field in what appears to be an `NSMenu`. 4 | 5 | This project allows you to do this as you have an option to set a header view as well as the menu items, the header view will appear at the top and with the items just below much alike to Spotlight. 6 | 7 | # How To Use 8 | 9 | Simply copy the required files to your project and initialise the controller like so: 10 | 11 | menuController = [[[JGMenuWindowController alloc] initWithWindowNibName:@"JGMenuWindow"] retain]; 12 | 13 | This will create the status item in the menu bar and set up all the actions for it. From there just set the properties you want like the `menuItems` and/or the `headerView`. 14 | 15 | # Demo App 16 | 17 | The project is simply a demo which shows how it can be used in a similar fashion to Spotlight. If you are unsure how to use it just check the demo out. 18 | 19 | # What Makes it better than a normal NSMenu? 20 | 21 | The main advantages over a normal NSMenu are: 22 | 23 | - live updating of menu items 24 | - fully responsive text fields (or anything that uses a field editor) 25 | - has option to appear as an Apple Pro menu 26 | 27 | But most importantly it is **fully customizable** which the Apple Pro menu option stands an example of. 28 | 29 | # Limitations 30 | 31 | As this was only a quick project there are some limitations: 32 | 33 | - you cannot set a custom view for each item (because of `NSTableView`) 34 | 35 | # Screenshot 36 | 37 | ![Screen](http://idzr.org/xd4e) 38 | 39 | # Attribution 40 | 41 | If you are using JGMenuWindow in your project please make sure you leave credit where credit is due. -------------------------------------------------------------------------------- /Status View + Coloring/.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SquaredTiki/JGMenuWindow/34b583bf9875915da8a3442e27cf880b5bd283f5/Status View + Coloring/.DS_Store -------------------------------------------------------------------------------- /Status View + Coloring/CustomStatusItemView.h: -------------------------------------------------------------------------------- 1 | // 2 | // CustomStatusItemView.h 3 | // StatusItem 4 | // 5 | // Created by Joshua Garnham on 14/04/2011. 6 | // Copyright 2011 __MyCompanyName__. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | 12 | @interface CustomStatusItemView : NSView { 13 | NSStatusItem *statusItem; 14 | 15 | id target; 16 | SEL selectingAction; 17 | SEL deselectingAction; 18 | 19 | BOOL highlighted; 20 | 21 | NSImage *image; 22 | NSImage *alternateImage; 23 | 24 | NSString *title; 25 | 26 | NSAttributedString *_attributedTitle; 27 | } 28 | 29 | @property (nonatomic, retain) NSStatusItem *statusItem; 30 | @property (nonatomic, assign) id target; 31 | @property (nonatomic, assign) SEL selectingAction; 32 | @property (nonatomic, assign) SEL deselectingAction; 33 | @property (nonatomic, assign) BOOL highlighted; 34 | @property (copy, nonatomic) NSImage *image; 35 | @property (copy, nonatomic) NSImage *alternateImage; 36 | @property (copy, nonatomic) NSString *title; 37 | @property (nonatomic, retain) NSAttributedString *_attributedTitle; 38 | 39 | @end 40 | -------------------------------------------------------------------------------- /Status View + Coloring/CustomStatusItemView.m: -------------------------------------------------------------------------------- 1 | // 2 | // CustomStatusItemView.m 3 | // StatusItem 4 | // 5 | // Created by Joshua Garnham on 14/04/2011. 6 | // Copyright 2011 __MyCompanyName__. All rights reserved. 7 | // 8 | 9 | #import "CustomStatusItemView.h" 10 | 11 | @implementation CustomStatusItemView 12 | @synthesize statusItem, target, selectingAction, deselectingAction, _attributedTitle; 13 | @dynamic highlighted, image, alternateImage, title; 14 | 15 | - (id)initWithFrame:(NSRect)frame { 16 | self = [super initWithFrame:frame]; 17 | if (self) { 18 | // Initialization code here. 19 | } 20 | return self; 21 | } 22 | 23 | - (void)drawRect:(NSRect)dirtyRect { 24 | NSImage *drawnImage = nil; 25 | if(highlighted) { 26 | [[NSColor selectedMenuItemColor] set]; 27 | [NSBezierPath fillRect:[self bounds]]; 28 | drawnImage = alternateImage; 29 | } else { 30 | drawnImage = image; 31 | } 32 | 33 | NSRect centeredRect = NSMakeRect(0, 0, 0, 0); 34 | if (drawnImage) { 35 | centeredRect = NSMakeRect(0, 0, [drawnImage size].width, [drawnImage size].height); 36 | // align left if we have a title 37 | if(_attributedTitle) { 38 | centeredRect.origin.x = 5; 39 | } else { 40 | centeredRect.origin.x = NSMidX([self bounds]) - ([drawnImage size].width / 2); 41 | } 42 | centeredRect.origin.y = NSMidY([self bounds]) - ([drawnImage size].height / 2); 43 | centeredRect = NSIntegralRect(centeredRect); 44 | [drawnImage drawInRect:centeredRect fromRect:NSZeroRect operation:NSCompositeSourceOver fraction:1.0]; 45 | } 46 | 47 | if(_attributedTitle) 48 | { 49 | NSRect titleRect = NSMakeRect(5 + centeredRect.size.width + centeredRect.origin.x, centeredRect.origin.y - 1, [self bounds].size.width - (centeredRect.size.width + 2) , [self bounds].size.height - centeredRect.origin.y); 50 | NSMutableAttributedString *attrTitle = [_attributedTitle mutableCopy]; 51 | if(highlighted) 52 | { 53 | NSColor *color = [NSColor selectedMenuItemTextColor]; 54 | [attrTitle addAttribute:NSForegroundColorAttributeName value:color range:NSMakeRange(0, [attrTitle length])]; 55 | } 56 | else { 57 | NSShadow *textShadow = [[NSShadow alloc] init]; 58 | [textShadow setShadowColor:[NSColor colorWithCalibratedWhite:1.0f alpha:0.6f]]; 59 | [textShadow setShadowOffset:NSMakeSize(0, -1)]; 60 | [attrTitle addAttribute:NSShadowAttributeName value:textShadow range:NSMakeRange(0, [attrTitle length])]; 61 | [textShadow release]; 62 | } 63 | [attrTitle drawInRect:titleRect]; 64 | [attrTitle release]; 65 | } 66 | 67 | if (!highlighted && image == nil && title == nil) { 68 | NSRect fullBounds = NSMakeRect([self bounds].origin.x, [self bounds].origin.y + 1, [self bounds].size.width, [self bounds].size.height - 1); 69 | [[NSColor grayColor] set]; 70 | NSRectFill( fullBounds ); 71 | } 72 | } 73 | 74 | #pragma mark Image Resizing 75 | 76 | - (void)_resizeToFitIfNeeded 77 | { 78 | if([statusItem length] == NSVariableStatusItemLength) 79 | { 80 | if (image != nil && title == nil) { 81 | NSRect newFrame = [self frame]; 82 | newFrame.size.width = [[self image] size].width + 8; // 12 px padding, 6 on each side maybe? not sure what might be the usual 83 | [self setFrame:newFrame]; 84 | } else if (image == nil && title != nil) { 85 | NSSize size = [title sizeWithAttributes:[NSDictionary dictionaryWithObject:[NSFont menuBarFontOfSize:[NSFont systemFontSize] + 2.0f] forKey:NSFontAttributeName]]; 86 | NSRect newFrame = [self frame]; 87 | newFrame.size.width = size.width + 10; 88 | [self setFrame:newFrame]; 89 | } else if (image != nil && title != nil) { 90 | NSSize size = [title sizeWithAttributes:[NSDictionary dictionaryWithObject:[NSFont menuBarFontOfSize:[NSFont systemFontSize] + 2.0f] forKey:NSFontAttributeName]]; 91 | NSRect newFrame = [self frame]; 92 | newFrame.size.width = (size.width + 10) + ([[self image] size].width + 8); 93 | [self setFrame:newFrame]; 94 | } 95 | } 96 | } 97 | 98 | #pragma mark Receiving mouse events 99 | 100 | - (void)mouseDown:(NSEvent *)theEvent 101 | { 102 | if (highlighted) { 103 | [self setHighlighted:NO]; 104 | [target performSelector:deselectingAction]; 105 | return; 106 | } 107 | [self setHighlighted:YES]; 108 | [target performSelector:selectingAction]; 109 | } 110 | 111 | #pragma mark Dynamics 112 | 113 | - (BOOL)highlighted { 114 | return highlighted; 115 | } 116 | 117 | - (void)setHighlighted:(BOOL)highlight { 118 | highlighted = highlight; 119 | [self setNeedsDisplay:YES]; 120 | } 121 | 122 | - (NSImage *)image { 123 | return image; 124 | } 125 | 126 | - (void)setImage:(NSImage *)newImage 127 | { 128 | if(newImage != image) 129 | { 130 | [image release]; 131 | image = [newImage copy]; 132 | [self _resizeToFitIfNeeded]; 133 | [self setNeedsDisplay:YES]; 134 | } 135 | } 136 | 137 | - (NSImage *)alternateImage { 138 | return alternateImage; 139 | } 140 | 141 | - (void)setAlternateImage:(NSImage *)newAltImage 142 | { 143 | if(newAltImage != alternateImage) 144 | { 145 | [alternateImage release]; 146 | alternateImage = [newAltImage copy]; 147 | [self setNeedsDisplay:YES]; 148 | } 149 | } 150 | 151 | - (NSString *)title { 152 | return title; 153 | } 154 | 155 | - (void)setTitle:(NSString *)newTitle 156 | { 157 | if(newTitle != title) 158 | { 159 | [title release]; 160 | title = [newTitle copy]; 161 | 162 | NSFont *font = [NSFont menuBarFontOfSize:[NSFont systemFontSize] + 2.0f]; // +2 seemed to make it look right, maybe missed a font method for menu? 163 | NSColor *color = [NSColor controlTextColor]; 164 | NSDictionary *attributes = [NSDictionary dictionaryWithObjectsAndKeys: 165 | font, NSFontAttributeName, 166 | color, NSForegroundColorAttributeName, 167 | nil]; 168 | NSAttributedString *attrTitle = [[NSAttributedString alloc] initWithString:self.title attributes:attributes]; 169 | _attributedTitle = [attrTitle copy]; 170 | [attrTitle release]; 171 | 172 | [self _resizeToFitIfNeeded]; 173 | [self setNeedsDisplay:YES]; 174 | } 175 | } 176 | 177 | @end 178 | -------------------------------------------------------------------------------- /Status View + Coloring/FullMenuView.h: -------------------------------------------------------------------------------- 1 | // 2 | // FullMenuView.h 3 | // StatusItem 4 | // 5 | // Created by Joshua Garnham on 07/03/2011. 6 | // Copyright 2011 __MyCompanyName__. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | 12 | @interface FullMenuView : NSView { 13 | NSTextView *fieldEditor; 14 | } 15 | 16 | @property (nonatomic, retain) NSTextView *fieldEditor; 17 | 18 | @end 19 | -------------------------------------------------------------------------------- /Status View + Coloring/FullMenuView.m: -------------------------------------------------------------------------------- 1 | // 2 | // FullMenuView.m 3 | // StatusItem 4 | // 5 | // Created by Joshua Garnham on 07/03/2011. 6 | // Copyright 2011 __MyCompanyName__. All rights reserved. 7 | // 8 | 9 | #import "FullMenuView.h" 10 | 11 | @implementation FullMenuView 12 | @synthesize fieldEditor; 13 | 14 | - (void) drawRect:(NSRect)dirtyRect 15 | { 16 | NSRect fullBounds = [self bounds]; 17 | /* fullBounds.size.height += 4; 18 | [[NSBezierPath bezierPathWithRect:fullBounds] setClip]; */ 19 | 20 | // Then do your drawing, for example... 21 | NSGradient* aGradient = 22 | [[[NSGradient alloc] 23 | initWithColorsAndLocations: 24 | [NSColor colorWithDeviceRed:0.212 green:0.369 blue:0.949 alpha:1.000], (CGFloat)0.0, 25 | [NSColor colorWithDeviceRed:0.416 green:0.529 blue:0.961 alpha:1.000], (CGFloat)1.0, 26 | nil] 27 | autorelease]; 28 | [aGradient drawInRect:fullBounds angle:90]; 29 | } 30 | 31 | 32 | @end 33 | -------------------------------------------------------------------------------- /StatusItem-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | English 7 | CFBundleExecutable 8 | ${EXECUTABLE_NAME} 9 | CFBundleIconFile 10 | 11 | CFBundleIdentifier 12 | com.yourcompany.${PRODUCT_NAME:rfc1034identifier} 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | ${PRODUCT_NAME} 17 | CFBundlePackageType 18 | APPL 19 | CFBundleShortVersionString 20 | 1.0 21 | CFBundleSignature 22 | ???? 23 | CFBundleVersion 24 | 1 25 | LSMinimumSystemVersion 26 | ${MACOSX_DEPLOYMENT_TARGET} 27 | NSMainNibFile 28 | MainMenu 29 | NSPrincipalClass 30 | NSApplication 31 | LSUIElement 32 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /StatusItem.xcodeproj/joshuagarnham.perspectivev3: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | ActivePerspectiveName 6 | Project 7 | AllowedModules 8 | 9 | 10 | BundleLoadPath 11 | 12 | MaxInstances 13 | n 14 | Module 15 | PBXSmartGroupTreeModule 16 | Name 17 | Groups and Files Outline View 18 | 19 | 20 | BundleLoadPath 21 | 22 | MaxInstances 23 | n 24 | Module 25 | PBXNavigatorGroup 26 | Name 27 | Editor 28 | 29 | 30 | BundleLoadPath 31 | 32 | MaxInstances 33 | n 34 | Module 35 | XCTaskListModule 36 | Name 37 | Task List 38 | 39 | 40 | BundleLoadPath 41 | 42 | MaxInstances 43 | n 44 | Module 45 | XCDetailModule 46 | Name 47 | File and Smart Group Detail Viewer 48 | 49 | 50 | BundleLoadPath 51 | 52 | MaxInstances 53 | 1 54 | Module 55 | PBXBuildResultsModule 56 | Name 57 | Detailed Build Results Viewer 58 | 59 | 60 | BundleLoadPath 61 | 62 | MaxInstances 63 | 1 64 | Module 65 | PBXProjectFindModule 66 | Name 67 | Project Batch Find Tool 68 | 69 | 70 | BundleLoadPath 71 | 72 | MaxInstances 73 | n 74 | Module 75 | XCProjectFormatConflictsModule 76 | Name 77 | Project Format Conflicts List 78 | 79 | 80 | BundleLoadPath 81 | 82 | MaxInstances 83 | n 84 | Module 85 | PBXBookmarksModule 86 | Name 87 | Bookmarks Tool 88 | 89 | 90 | BundleLoadPath 91 | 92 | MaxInstances 93 | n 94 | Module 95 | PBXClassBrowserModule 96 | Name 97 | Class Browser 98 | 99 | 100 | BundleLoadPath 101 | 102 | MaxInstances 103 | n 104 | Module 105 | PBXCVSModule 106 | Name 107 | Source Code Control Tool 108 | 109 | 110 | BundleLoadPath 111 | 112 | MaxInstances 113 | n 114 | Module 115 | PBXDebugBreakpointsModule 116 | Name 117 | Debug Breakpoints Tool 118 | 119 | 120 | BundleLoadPath 121 | 122 | MaxInstances 123 | n 124 | Module 125 | XCDockableInspector 126 | Name 127 | Inspector 128 | 129 | 130 | BundleLoadPath 131 | 132 | MaxInstances 133 | n 134 | Module 135 | PBXOpenQuicklyModule 136 | Name 137 | Open Quickly Tool 138 | 139 | 140 | BundleLoadPath 141 | 142 | MaxInstances 143 | 1 144 | Module 145 | PBXDebugSessionModule 146 | Name 147 | Debugger 148 | 149 | 150 | BundleLoadPath 151 | 152 | MaxInstances 153 | 1 154 | Module 155 | PBXDebugCLIModule 156 | Name 157 | Debug Console 158 | 159 | 160 | BundleLoadPath 161 | 162 | MaxInstances 163 | n 164 | Module 165 | XCSnapshotModule 166 | Name 167 | Snapshots Tool 168 | 169 | 170 | BundlePath 171 | /Developer/Library/PrivateFrameworks/DevToolsInterface.framework/Resources 172 | Description 173 | AIODescriptionKey 174 | DockingSystemVisible 175 | 176 | Extension 177 | perspectivev3 178 | FavBarConfig 179 | 180 | PBXProjectModuleGUID 181 | AFF3FDA11324BDE500BC980F 182 | XCBarModuleItemNames 183 | 184 | XCBarModuleItems 185 | 186 | 187 | FirstTimeWindowDisplayed 188 | 189 | Identifier 190 | com.apple.perspectives.project.defaultV3 191 | MajorVersion 192 | 34 193 | MinorVersion 194 | 0 195 | Name 196 | All-In-One 197 | Notifications 198 | 199 | OpenEditors 200 | 201 | PerspectiveWidths 202 | 203 | 1280 204 | 1280 205 | 206 | Perspectives 207 | 208 | 209 | ChosenToolbarItems 210 | 211 | XCToolbarPerspectiveControl 212 | active-combo-popup 213 | takeSnapshot 214 | servicesModuleSnapshots 215 | NSToolbarFlexibleSpaceItem 216 | build-and-go 217 | go 218 | NSToolbarFlexibleSpaceItem 219 | debugger-enable-breakpoints 220 | servicesModulebreakpoints 221 | 222 | ControllerClassBaseName 223 | 224 | IconName 225 | WindowOfProject 226 | Identifier 227 | perspective.project 228 | IsVertical 229 | 230 | Layout 231 | 232 | 233 | ContentConfiguration 234 | 235 | PBXBottomSmartGroupGIDs 236 | 237 | 1C37FBAC04509CD000000102 238 | 1C37FAAC04509CD000000102 239 | 1C37FABC05509CD000000102 240 | 1C37FABC05539CD112110102 241 | E2644B35053B69B200211256 242 | 1C37FABC04509CD000100104 243 | 1CC0EA4004350EF90044410B 244 | 1CC0EA4004350EF90041110B 245 | 1C77FABC04509CD000000102 246 | 247 | PBXProjectModuleGUID 248 | 1CA23ED40692098700951B8B 249 | PBXProjectModuleLabel 250 | Files 251 | PBXProjectStructureProvided 252 | yes 253 | PBXSmartGroupTreeModuleColumnData 254 | 255 | PBXSmartGroupTreeModuleColumnWidthsKey 256 | 257 | 345 258 | 259 | PBXSmartGroupTreeModuleColumnsKey_v4 260 | 261 | MainColumn 262 | 263 | 264 | PBXSmartGroupTreeModuleOutlineStateKey_v7 265 | 266 | PBXSmartGroupTreeModuleOutlineStateExpansionKey 267 | 268 | 29B97314FDCFA39411CA2CEA 269 | 080E96DDFE201D6D7F000001 270 | AFE5C642135A018000081B00 271 | AFE5C64B135A01B500081B00 272 | AFB0BF2E135ACCF1009E9BFF 273 | 29B97315FDCFA39411CA2CEA 274 | 29B97317FDCFA39411CA2CEA 275 | 1C77FABC04509CD000000102 276 | 277 | PBXSmartGroupTreeModuleOutlineStateSelectionKey 278 | 279 | 280 | 25 281 | 1 282 | 0 283 | 284 | 285 | PBXSmartGroupTreeModuleOutlineStateVisibleRectKey 286 | {{0, 0}, {345, 576}} 287 | 288 | PBXTopSmartGroupGIDs 289 | 290 | XCIncludePerspectivesSwitch 291 | 292 | 293 | GeometryConfiguration 294 | 295 | Frame 296 | {{0, 0}, {362, 594}} 297 | GroupTreeTableConfiguration 298 | 299 | MainColumn 300 | 345 301 | 302 | RubberWindowFrame 303 | 0 143 1280 635 0 0 1280 778 304 | 305 | Module 306 | PBXSmartGroupTreeModule 307 | Proportion 308 | 362pt 309 | 310 | 311 | Dock 312 | 313 | 314 | BecomeActive 315 | 316 | ContentConfiguration 317 | 318 | PBXProjectModuleGUID 319 | AFF3FD911324BDE500BC980F 320 | PBXProjectModuleLabel 321 | StatusItemAppDelegate.m 322 | PBXSplitModuleInNavigatorKey 323 | 324 | Split0 325 | 326 | PBXProjectModuleGUID 327 | AFF3FD921324BDE500BC980F 328 | PBXProjectModuleLabel 329 | StatusItemAppDelegate.m 330 | _historyCapacity 331 | 0 332 | bookmark 333 | AFB83E1F1360A24100BABC37 334 | history 335 | 336 | AFA4C5B21356DEE900C0D3CE 337 | AF998F641358993B00ACB3E5 338 | AF998F651358993B00ACB3E5 339 | AFB0C34D135B5802009E9BFF 340 | AF068589135D6D020099C76F 341 | AF068748135DB2F10099C76F 342 | AF0687DB135DBA560099C76F 343 | AF0687DC135DBA560099C76F 344 | AF0688DF135DC0570099C76F 345 | AF0688E0135DC0570099C76F 346 | AF068925135DC2DE0099C76F 347 | AF0689D5135DCC510099C76F 348 | AF068C7E135E004F0099C76F 349 | AF068CA2135E01A90099C76F 350 | AFB83758135F326E00BABC37 351 | AFB8375E135F326E00BABC37 352 | AFB837B0135F369200BABC37 353 | AFB837BC135F36F900BABC37 354 | AFB838BD135F4E0C00BABC37 355 | AFB83967135F578400BABC37 356 | AFB83AC1136025C300BABC37 357 | AFB83AF41360299400BABC37 358 | AFB83DF81360A09F00BABC37 359 | AFB83E001360A0E100BABC37 360 | AFB83E1E1360A23D00BABC37 361 | 362 | 363 | SplitCount 364 | 1 365 | 366 | StatusBarVisibility 367 | 368 | XCSharingToken 369 | com.apple.Xcode.CommonNavigatorGroupSharingToken 370 | 371 | GeometryConfiguration 372 | 373 | Frame 374 | {{0, 0}, {913, 589}} 375 | RubberWindowFrame 376 | 0 143 1280 635 0 0 1280 778 377 | 378 | Module 379 | PBXNavigatorGroup 380 | Proportion 381 | 589pt 382 | 383 | 384 | Proportion 385 | 0pt 386 | Tabs 387 | 388 | 389 | ContentConfiguration 390 | 391 | PBXProjectModuleGUID 392 | 1CA23EDF0692099D00951B8B 393 | PBXProjectModuleLabel 394 | Detail 395 | 396 | GeometryConfiguration 397 | 398 | Frame 399 | {{10, 27}, {913, -27}} 400 | 401 | Module 402 | XCDetailModule 403 | 404 | 405 | ContentConfiguration 406 | 407 | PBXProjectModuleGUID 408 | 1CA23EE00692099D00951B8B 409 | PBXProjectModuleLabel 410 | Project Find 411 | 412 | GeometryConfiguration 413 | 414 | Frame 415 | {{0, 0}, {614, 336}} 416 | 417 | Module 418 | PBXProjectFindModule 419 | 420 | 421 | ContentConfiguration 422 | 423 | PBXCVSModuleFilterTypeKey 424 | 1032 425 | PBXProjectModuleGUID 426 | 1CA23EE10692099D00951B8B 427 | PBXProjectModuleLabel 428 | SCM Results 429 | 430 | GeometryConfiguration 431 | 432 | Frame 433 | {{10, 31}, {603, 297}} 434 | 435 | Module 436 | PBXCVSModule 437 | 438 | 439 | ContentConfiguration 440 | 441 | PBXProjectModuleGUID 442 | XCMainBuildResultsModuleGUID 443 | PBXProjectModuleLabel 444 | Build Results 445 | XCBuildResultsTrigger_Collapse 446 | 1021 447 | XCBuildResultsTrigger_Open 448 | 1011 449 | 450 | GeometryConfiguration 451 | 452 | Frame 453 | {{10, 27}, {913, -27}} 454 | RubberWindowFrame 455 | 0 143 1280 635 0 0 1280 778 456 | 457 | Module 458 | PBXBuildResultsModule 459 | 460 | 461 | 462 | 463 | Proportion 464 | 913pt 465 | 466 | 467 | Name 468 | Project 469 | ServiceClasses 470 | 471 | XCModuleDock 472 | PBXSmartGroupTreeModule 473 | XCModuleDock 474 | PBXNavigatorGroup 475 | XCDockableTabModule 476 | XCDetailModule 477 | PBXProjectFindModule 478 | PBXCVSModule 479 | PBXBuildResultsModule 480 | 481 | TableOfContents 482 | 483 | AFB83764135F327000BABC37 484 | 1CA23ED40692098700951B8B 485 | AFB83765135F327000BABC37 486 | AFF3FD911324BDE500BC980F 487 | AFB83766135F327000BABC37 488 | 1CA23EDF0692099D00951B8B 489 | 1CA23EE00692099D00951B8B 490 | 1CA23EE10692099D00951B8B 491 | XCMainBuildResultsModuleGUID 492 | 493 | ToolbarConfigUserDefaultsMinorVersion 494 | 2 495 | ToolbarConfiguration 496 | xcode.toolbar.config.defaultV3 497 | 498 | 499 | ChosenToolbarItems 500 | 501 | XCToolbarPerspectiveControl 502 | active-combo-popup 503 | NSToolbarFlexibleSpaceItem 504 | debugger-enable-breakpoints 505 | build-and-go 506 | com.apple.ide.PBXToolbarStopButton 507 | NSToolbarFlexibleSpaceItem 508 | go 509 | debugger-pause 510 | debugger-step-over 511 | debugger-step-out 512 | NSToolbarFlexibleSpaceItem 513 | servicesModulebreakpoints 514 | debugger-show-console-window 515 | 516 | ControllerClassBaseName 517 | PBXDebugSessionModule 518 | IconName 519 | DebugTabIcon 520 | Identifier 521 | perspective.debug 522 | IsVertical 523 | 524 | Layout 525 | 526 | 527 | ContentConfiguration 528 | 529 | PBXProjectModuleGUID 530 | 1CCC7628064C1048000F2A68 531 | PBXProjectModuleLabel 532 | Debugger Console 533 | 534 | GeometryConfiguration 535 | 536 | Frame 537 | {{0, 0}, {1280, 108}} 538 | 539 | Module 540 | PBXDebugCLIModule 541 | Proportion 542 | 108pt 543 | 544 | 545 | ContentConfiguration 546 | 547 | Debugger 548 | 549 | HorizontalSplitView 550 | 551 | _collapsingFrameDimension 552 | 0.0 553 | _indexOfCollapsedView 554 | 0 555 | _percentageOfCollapsedView 556 | 0.0 557 | isCollapsed 558 | yes 559 | sizes 560 | 561 | {{0, 0}, {625, 235}} 562 | {{625, 0}, {655, 235}} 563 | 564 | 565 | VerticalSplitView 566 | 567 | _collapsingFrameDimension 568 | 0.0 569 | _indexOfCollapsedView 570 | 0 571 | _percentageOfCollapsedView 572 | 0.0 573 | isCollapsed 574 | yes 575 | sizes 576 | 577 | {{0, 0}, {1280, 235}} 578 | {{0, 235}, {1280, 246}} 579 | 580 | 581 | 582 | LauncherConfigVersion 583 | 8 584 | PBXProjectModuleGUID 585 | 1CCC7629064C1048000F2A68 586 | PBXProjectModuleLabel 587 | Debug 588 | 589 | GeometryConfiguration 590 | 591 | DebugConsoleVisible 592 | None 593 | DebugConsoleWindowFrame 594 | {{200, 200}, {500, 300}} 595 | DebugSTDIOWindowFrame 596 | {{200, 200}, {500, 300}} 597 | Frame 598 | {{0, 113}, {1280, 481}} 599 | PBXDebugSessionStackFrameViewKey 600 | 601 | DebugVariablesTableConfiguration 602 | 603 | Name 604 | 120 605 | Value 606 | 85 607 | Summary 608 | 425 609 | 610 | Frame 611 | {{625, 0}, {655, 235}} 612 | 613 | 614 | Module 615 | PBXDebugSessionModule 616 | Proportion 617 | 481pt 618 | 619 | 620 | Name 621 | Debug 622 | ServiceClasses 623 | 624 | XCModuleDock 625 | PBXDebugCLIModule 626 | PBXDebugSessionModule 627 | PBXDebugProcessAndThreadModule 628 | PBXDebugProcessViewModule 629 | PBXDebugThreadViewModule 630 | PBXDebugStackFrameViewModule 631 | PBXNavigatorGroup 632 | 633 | TableOfContents 634 | 635 | AFB83767135F327000BABC37 636 | 1CCC7628064C1048000F2A68 637 | 1CCC7629064C1048000F2A68 638 | AFB83768135F327000BABC37 639 | AFB83769135F327000BABC37 640 | AFB8376A135F327000BABC37 641 | AFB8376B135F327000BABC37 642 | AFF3FD911324BDE500BC980F 643 | 644 | ToolbarConfigUserDefaultsMinorVersion 645 | 2 646 | ToolbarConfiguration 647 | xcode.toolbar.config.debugV3 648 | 649 | 650 | PerspectivesBarVisible 651 | 652 | ShelfIsVisible 653 | 654 | SourceDescription 655 | file at '/Developer/Library/PrivateFrameworks/DevToolsInterface.framework/Resources/XCPerspectivesSpecification.xcperspec' 656 | StatusbarIsVisible 657 | 658 | TimeStamp 659 | 0.0 660 | ToolbarConfigUserDefaultsMinorVersion 661 | 2 662 | ToolbarDisplayMode 663 | 1 664 | ToolbarIsVisible 665 | 666 | ToolbarSizeMode 667 | 1 668 | Type 669 | Perspectives 670 | UpdateMessage 671 | 672 | WindowJustification 673 | 5 674 | WindowOrderList 675 | 676 | AFB8376D135F327000BABC37 677 | AFB8376E135F327000BABC37 678 | /Users/joshuagarnham/Desktop/Projects/Obj-C/Tests/StatusItem/StatusItem.xcodeproj 679 | 680 | WindowString 681 | 0 143 1280 635 0 0 1280 778 682 | WindowToolsV3 683 | 684 | 685 | Identifier 686 | windowTool.debugger 687 | Layout 688 | 689 | 690 | Dock 691 | 692 | 693 | ContentConfiguration 694 | 695 | Debugger 696 | 697 | HorizontalSplitView 698 | 699 | _collapsingFrameDimension 700 | 0.0 701 | _indexOfCollapsedView 702 | 0 703 | _percentageOfCollapsedView 704 | 0.0 705 | isCollapsed 706 | yes 707 | sizes 708 | 709 | {{0, 0}, {317, 164}} 710 | {{317, 0}, {377, 164}} 711 | 712 | 713 | VerticalSplitView 714 | 715 | _collapsingFrameDimension 716 | 0.0 717 | _indexOfCollapsedView 718 | 0 719 | _percentageOfCollapsedView 720 | 0.0 721 | isCollapsed 722 | yes 723 | sizes 724 | 725 | {{0, 0}, {694, 164}} 726 | {{0, 164}, {694, 216}} 727 | 728 | 729 | 730 | LauncherConfigVersion 731 | 8 732 | PBXProjectModuleGUID 733 | 1C162984064C10D400B95A72 734 | PBXProjectModuleLabel 735 | Debug - GLUTExamples (Underwater) 736 | 737 | GeometryConfiguration 738 | 739 | DebugConsoleDrawerSize 740 | {100, 120} 741 | DebugConsoleVisible 742 | None 743 | DebugConsoleWindowFrame 744 | {{200, 200}, {500, 300}} 745 | DebugSTDIOWindowFrame 746 | {{200, 200}, {500, 300}} 747 | Frame 748 | {{0, 0}, {694, 380}} 749 | RubberWindowFrame 750 | 321 238 694 422 0 0 1440 878 751 | 752 | Module 753 | PBXDebugSessionModule 754 | Proportion 755 | 100% 756 | 757 | 758 | Proportion 759 | 100% 760 | 761 | 762 | Name 763 | Debugger 764 | ServiceClasses 765 | 766 | PBXDebugSessionModule 767 | 768 | StatusbarIsVisible 769 | 1 770 | TableOfContents 771 | 772 | 1CD10A99069EF8BA00B06720 773 | 1C0AD2AB069F1E9B00FABCE6 774 | 1C162984064C10D400B95A72 775 | 1C0AD2AC069F1E9B00FABCE6 776 | 777 | ToolbarConfiguration 778 | xcode.toolbar.config.debugV3 779 | WindowString 780 | 321 238 694 422 0 0 1440 878 781 | WindowToolGUID 782 | 1CD10A99069EF8BA00B06720 783 | WindowToolIsVisible 784 | 0 785 | 786 | 787 | Identifier 788 | windowTool.build 789 | Layout 790 | 791 | 792 | Dock 793 | 794 | 795 | ContentConfiguration 796 | 797 | PBXProjectModuleGUID 798 | 1CD0528F0623707200166675 799 | PBXProjectModuleLabel 800 | <No Editor> 801 | PBXSplitModuleInNavigatorKey 802 | 803 | Split0 804 | 805 | PBXProjectModuleGUID 806 | 1CD052900623707200166675 807 | 808 | SplitCount 809 | 1 810 | 811 | StatusBarVisibility 812 | 1 813 | 814 | GeometryConfiguration 815 | 816 | Frame 817 | {{0, 0}, {500, 215}} 818 | RubberWindowFrame 819 | 192 257 500 500 0 0 1280 1002 820 | 821 | Module 822 | PBXNavigatorGroup 823 | Proportion 824 | 218pt 825 | 826 | 827 | BecomeActive 828 | 1 829 | ContentConfiguration 830 | 831 | PBXProjectModuleGUID 832 | XCMainBuildResultsModuleGUID 833 | PBXProjectModuleLabel 834 | Build Results 835 | 836 | GeometryConfiguration 837 | 838 | Frame 839 | {{0, 222}, {500, 236}} 840 | RubberWindowFrame 841 | 192 257 500 500 0 0 1280 1002 842 | 843 | Module 844 | PBXBuildResultsModule 845 | Proportion 846 | 236pt 847 | 848 | 849 | Proportion 850 | 458pt 851 | 852 | 853 | Name 854 | Build Results 855 | ServiceClasses 856 | 857 | PBXBuildResultsModule 858 | 859 | StatusbarIsVisible 860 | 1 861 | TableOfContents 862 | 863 | 1C78EAA5065D492600B07095 864 | 1C78EAA6065D492600B07095 865 | 1CD0528F0623707200166675 866 | XCMainBuildResultsModuleGUID 867 | 868 | ToolbarConfiguration 869 | xcode.toolbar.config.buildV3 870 | WindowString 871 | 192 257 500 500 0 0 1280 1002 872 | 873 | 874 | Identifier 875 | windowTool.find 876 | Layout 877 | 878 | 879 | Dock 880 | 881 | 882 | Dock 883 | 884 | 885 | ContentConfiguration 886 | 887 | PBXProjectModuleGUID 888 | 1CDD528C0622207200134675 889 | PBXProjectModuleLabel 890 | <No Editor> 891 | PBXSplitModuleInNavigatorKey 892 | 893 | Split0 894 | 895 | PBXProjectModuleGUID 896 | 1CD0528D0623707200166675 897 | 898 | SplitCount 899 | 1 900 | 901 | StatusBarVisibility 902 | 1 903 | 904 | GeometryConfiguration 905 | 906 | Frame 907 | {{0, 0}, {781, 167}} 908 | RubberWindowFrame 909 | 62 385 781 470 0 0 1440 878 910 | 911 | Module 912 | PBXNavigatorGroup 913 | Proportion 914 | 781pt 915 | 916 | 917 | Proportion 918 | 50% 919 | 920 | 921 | BecomeActive 922 | 1 923 | ContentConfiguration 924 | 925 | PBXProjectModuleGUID 926 | 1CD0528E0623707200166675 927 | PBXProjectModuleLabel 928 | Project Find 929 | 930 | GeometryConfiguration 931 | 932 | Frame 933 | {{8, 0}, {773, 254}} 934 | RubberWindowFrame 935 | 62 385 781 470 0 0 1440 878 936 | 937 | Module 938 | PBXProjectFindModule 939 | Proportion 940 | 50% 941 | 942 | 943 | Proportion 944 | 428pt 945 | 946 | 947 | Name 948 | Project Find 949 | ServiceClasses 950 | 951 | PBXProjectFindModule 952 | 953 | StatusbarIsVisible 954 | 1 955 | TableOfContents 956 | 957 | 1C530D57069F1CE1000CFCEE 958 | 1C530D58069F1CE1000CFCEE 959 | 1C530D59069F1CE1000CFCEE 960 | 1CDD528C0622207200134675 961 | 1C530D5A069F1CE1000CFCEE 962 | 1CE0B1FE06471DED0097A5F4 963 | 1CD0528E0623707200166675 964 | 965 | WindowString 966 | 62 385 781 470 0 0 1440 878 967 | WindowToolGUID 968 | 1C530D57069F1CE1000CFCEE 969 | WindowToolIsVisible 970 | 0 971 | 972 | 973 | FirstTimeWindowDisplayed 974 | 975 | Identifier 976 | windowTool.snapshots 977 | IsVertical 978 | 979 | Layout 980 | 981 | 982 | Dock 983 | 984 | 985 | ContentConfiguration 986 | 987 | PBXProjectModuleGUID 988 | AFE4E50B1356D9BF001FA9F6 989 | PBXProjectModuleLabel 990 | Snapshots 991 | 992 | GeometryConfiguration 993 | 994 | Frame 995 | {{0, 0}, {300, 509}} 996 | RubberWindowFrame 997 | 21 205 300 550 0 0 1280 778 998 | 999 | Module 1000 | XCSnapshotModule 1001 | Proportion 1002 | 509pt 1003 | 1004 | 1005 | Proportion 1006 | 509pt 1007 | 1008 | 1009 | Name 1010 | Snapshots 1011 | ServiceClasses 1012 | 1013 | XCSnapshotModule 1014 | 1015 | StatusbarIsVisible 1016 | 1017 | TableOfContents 1018 | 1019 | AFE4E50C1356D9BF001FA9F6 1020 | AFE4E50D1356D9BF001FA9F6 1021 | AFE4E50B1356D9BF001FA9F6 1022 | 1023 | ToolbarConfiguration 1024 | xcode.toolbar.config.snapshots 1025 | WindowString 1026 | 21 205 300 550 0 0 1280 778 1027 | WindowToolGUID 1028 | AFE4E50C1356D9BF001FA9F6 1029 | WindowToolIsVisible 1030 | 1031 | 1032 | 1033 | FirstTimeWindowDisplayed 1034 | 1035 | Identifier 1036 | windowTool.debuggerConsole 1037 | IsVertical 1038 | 1039 | Layout 1040 | 1041 | 1042 | Dock 1043 | 1044 | 1045 | ContentConfiguration 1046 | 1047 | PBXProjectModuleGUID 1048 | 1C78EAAC065D492600B07095 1049 | PBXProjectModuleLabel 1050 | Debugger Console 1051 | 1052 | GeometryConfiguration 1053 | 1054 | Frame 1055 | {{0, 0}, {440, 359}} 1056 | RubberWindowFrame 1057 | 21 355 440 400 0 0 1280 778 1058 | 1059 | Module 1060 | PBXDebugCLIModule 1061 | Proportion 1062 | 359pt 1063 | 1064 | 1065 | Proportion 1066 | 359pt 1067 | 1068 | 1069 | Name 1070 | Debugger Console 1071 | ServiceClasses 1072 | 1073 | PBXDebugCLIModule 1074 | 1075 | StatusbarIsVisible 1076 | 1077 | TableOfContents 1078 | 1079 | 1C530D5B069F1CE1000CFCEE 1080 | AF99943413598C0C00ACB3E5 1081 | 1C78EAAC065D492600B07095 1082 | 1083 | ToolbarConfiguration 1084 | xcode.toolbar.config.consoleV3 1085 | WindowString 1086 | 21 355 440 400 0 0 1280 778 1087 | WindowToolGUID 1088 | 1C530D5B069F1CE1000CFCEE 1089 | WindowToolIsVisible 1090 | 1091 | 1092 | 1093 | Identifier 1094 | windowTool.scm 1095 | Layout 1096 | 1097 | 1098 | Dock 1099 | 1100 | 1101 | ContentConfiguration 1102 | 1103 | PBXProjectModuleGUID 1104 | 1C78EAB2065D492600B07095 1105 | PBXProjectModuleLabel 1106 | <No Editor> 1107 | PBXSplitModuleInNavigatorKey 1108 | 1109 | Split0 1110 | 1111 | PBXProjectModuleGUID 1112 | 1C78EAB3065D492600B07095 1113 | 1114 | SplitCount 1115 | 1 1116 | 1117 | StatusBarVisibility 1118 | 1 1119 | 1120 | GeometryConfiguration 1121 | 1122 | Frame 1123 | {{0, 0}, {452, 0}} 1124 | RubberWindowFrame 1125 | 743 379 452 308 0 0 1280 1002 1126 | 1127 | Module 1128 | PBXNavigatorGroup 1129 | Proportion 1130 | 0pt 1131 | 1132 | 1133 | BecomeActive 1134 | 1 1135 | ContentConfiguration 1136 | 1137 | PBXProjectModuleGUID 1138 | 1CD052920623707200166675 1139 | PBXProjectModuleLabel 1140 | SCM 1141 | 1142 | GeometryConfiguration 1143 | 1144 | ConsoleFrame 1145 | {{0, 259}, {452, 0}} 1146 | Frame 1147 | {{0, 7}, {452, 259}} 1148 | RubberWindowFrame 1149 | 743 379 452 308 0 0 1280 1002 1150 | TableConfiguration 1151 | 1152 | Status 1153 | 30 1154 | FileName 1155 | 199 1156 | Path 1157 | 197.09500122070312 1158 | 1159 | TableFrame 1160 | {{0, 0}, {452, 250}} 1161 | 1162 | Module 1163 | PBXCVSModule 1164 | Proportion 1165 | 262pt 1166 | 1167 | 1168 | Proportion 1169 | 266pt 1170 | 1171 | 1172 | Name 1173 | SCM 1174 | ServiceClasses 1175 | 1176 | PBXCVSModule 1177 | 1178 | StatusbarIsVisible 1179 | 1 1180 | TableOfContents 1181 | 1182 | 1C78EAB4065D492600B07095 1183 | 1C78EAB5065D492600B07095 1184 | 1C78EAB2065D492600B07095 1185 | 1CD052920623707200166675 1186 | 1187 | ToolbarConfiguration 1188 | xcode.toolbar.config.scmV3 1189 | WindowString 1190 | 743 379 452 308 0 0 1280 1002 1191 | 1192 | 1193 | Identifier 1194 | windowTool.breakpoints 1195 | IsVertical 1196 | 0 1197 | Layout 1198 | 1199 | 1200 | Dock 1201 | 1202 | 1203 | BecomeActive 1204 | 1 1205 | ContentConfiguration 1206 | 1207 | PBXBottomSmartGroupGIDs 1208 | 1209 | 1C77FABC04509CD000000102 1210 | 1211 | PBXProjectModuleGUID 1212 | 1CE0B1FE06471DED0097A5F4 1213 | PBXProjectModuleLabel 1214 | Files 1215 | PBXProjectStructureProvided 1216 | no 1217 | PBXSmartGroupTreeModuleColumnData 1218 | 1219 | PBXSmartGroupTreeModuleColumnWidthsKey 1220 | 1221 | 168 1222 | 1223 | PBXSmartGroupTreeModuleColumnsKey_v4 1224 | 1225 | MainColumn 1226 | 1227 | 1228 | PBXSmartGroupTreeModuleOutlineStateKey_v7 1229 | 1230 | PBXSmartGroupTreeModuleOutlineStateExpansionKey 1231 | 1232 | 1C77FABC04509CD000000102 1233 | 1234 | PBXSmartGroupTreeModuleOutlineStateSelectionKey 1235 | 1236 | 1237 | 0 1238 | 1239 | 1240 | PBXSmartGroupTreeModuleOutlineStateVisibleRectKey 1241 | {{0, 0}, {168, 350}} 1242 | 1243 | PBXTopSmartGroupGIDs 1244 | 1245 | XCIncludePerspectivesSwitch 1246 | 0 1247 | 1248 | GeometryConfiguration 1249 | 1250 | Frame 1251 | {{0, 0}, {185, 368}} 1252 | GroupTreeTableConfiguration 1253 | 1254 | MainColumn 1255 | 168 1256 | 1257 | RubberWindowFrame 1258 | 315 424 744 409 0 0 1440 878 1259 | 1260 | Module 1261 | PBXSmartGroupTreeModule 1262 | Proportion 1263 | 185pt 1264 | 1265 | 1266 | ContentConfiguration 1267 | 1268 | PBXProjectModuleGUID 1269 | 1CA1AED706398EBD00589147 1270 | PBXProjectModuleLabel 1271 | Detail 1272 | 1273 | GeometryConfiguration 1274 | 1275 | Frame 1276 | {{190, 0}, {554, 368}} 1277 | RubberWindowFrame 1278 | 315 424 744 409 0 0 1440 878 1279 | 1280 | Module 1281 | XCDetailModule 1282 | Proportion 1283 | 554pt 1284 | 1285 | 1286 | Proportion 1287 | 368pt 1288 | 1289 | 1290 | MajorVersion 1291 | 3 1292 | MinorVersion 1293 | 0 1294 | Name 1295 | Breakpoints 1296 | ServiceClasses 1297 | 1298 | PBXSmartGroupTreeModule 1299 | XCDetailModule 1300 | 1301 | StatusbarIsVisible 1302 | 1 1303 | TableOfContents 1304 | 1305 | 1CDDB66807F98D9800BB5817 1306 | 1CDDB66907F98D9800BB5817 1307 | 1CE0B1FE06471DED0097A5F4 1308 | 1CA1AED706398EBD00589147 1309 | 1310 | ToolbarConfiguration 1311 | xcode.toolbar.config.breakpointsV3 1312 | WindowString 1313 | 315 424 744 409 0 0 1440 878 1314 | WindowToolGUID 1315 | 1CDDB66807F98D9800BB5817 1316 | WindowToolIsVisible 1317 | 1 1318 | 1319 | 1320 | Identifier 1321 | windowTool.debugAnimator 1322 | Layout 1323 | 1324 | 1325 | Dock 1326 | 1327 | 1328 | Module 1329 | PBXNavigatorGroup 1330 | Proportion 1331 | 100% 1332 | 1333 | 1334 | Proportion 1335 | 100% 1336 | 1337 | 1338 | Name 1339 | Debug Visualizer 1340 | ServiceClasses 1341 | 1342 | PBXNavigatorGroup 1343 | 1344 | StatusbarIsVisible 1345 | 1 1346 | ToolbarConfiguration 1347 | xcode.toolbar.config.debugAnimatorV3 1348 | WindowString 1349 | 100 100 700 500 0 0 1280 1002 1350 | 1351 | 1352 | Identifier 1353 | windowTool.bookmarks 1354 | Layout 1355 | 1356 | 1357 | Dock 1358 | 1359 | 1360 | Module 1361 | PBXBookmarksModule 1362 | Proportion 1363 | 166pt 1364 | 1365 | 1366 | Proportion 1367 | 166pt 1368 | 1369 | 1370 | Name 1371 | Bookmarks 1372 | ServiceClasses 1373 | 1374 | PBXBookmarksModule 1375 | 1376 | StatusbarIsVisible 1377 | 0 1378 | WindowString 1379 | 538 42 401 187 0 0 1280 1002 1380 | 1381 | 1382 | Identifier 1383 | windowTool.projectFormatConflicts 1384 | Layout 1385 | 1386 | 1387 | Dock 1388 | 1389 | 1390 | Module 1391 | XCProjectFormatConflictsModule 1392 | Proportion 1393 | 100% 1394 | 1395 | 1396 | Proportion 1397 | 100% 1398 | 1399 | 1400 | Name 1401 | Project Format Conflicts 1402 | ServiceClasses 1403 | 1404 | XCProjectFormatConflictsModule 1405 | 1406 | StatusbarIsVisible 1407 | 0 1408 | WindowContentMinSize 1409 | 450 300 1410 | WindowString 1411 | 50 850 472 307 0 0 1440 877 1412 | 1413 | 1414 | Identifier 1415 | windowTool.classBrowser 1416 | Layout 1417 | 1418 | 1419 | Dock 1420 | 1421 | 1422 | BecomeActive 1423 | 1 1424 | ContentConfiguration 1425 | 1426 | OptionsSetName 1427 | Hierarchy, all classes 1428 | PBXProjectModuleGUID 1429 | 1CA6456E063B45B4001379D8 1430 | PBXProjectModuleLabel 1431 | Class Browser - NSObject 1432 | 1433 | GeometryConfiguration 1434 | 1435 | ClassesFrame 1436 | {{0, 0}, {369, 96}} 1437 | ClassesTreeTableConfiguration 1438 | 1439 | PBXClassNameColumnIdentifier 1440 | 208 1441 | PBXClassBookColumnIdentifier 1442 | 22 1443 | 1444 | Frame 1445 | {{0, 0}, {616, 353}} 1446 | MembersFrame 1447 | {{0, 105}, {369, 395}} 1448 | MembersTreeTableConfiguration 1449 | 1450 | PBXMemberTypeIconColumnIdentifier 1451 | 22 1452 | PBXMemberNameColumnIdentifier 1453 | 216 1454 | PBXMemberTypeColumnIdentifier 1455 | 94 1456 | PBXMemberBookColumnIdentifier 1457 | 22 1458 | 1459 | PBXModuleWindowStatusBarHidden2 1460 | 1 1461 | RubberWindowFrame 1462 | 597 125 616 374 0 0 1280 1002 1463 | 1464 | Module 1465 | PBXClassBrowserModule 1466 | Proportion 1467 | 354pt 1468 | 1469 | 1470 | Proportion 1471 | 354pt 1472 | 1473 | 1474 | Name 1475 | Class Browser 1476 | ServiceClasses 1477 | 1478 | PBXClassBrowserModule 1479 | 1480 | StatusbarIsVisible 1481 | 0 1482 | TableOfContents 1483 | 1484 | 1C78EABA065D492600B07095 1485 | 1C78EABB065D492600B07095 1486 | 1CA6456E063B45B4001379D8 1487 | 1488 | ToolbarConfiguration 1489 | xcode.toolbar.config.classbrowser 1490 | WindowString 1491 | 597 125 616 374 0 0 1280 1002 1492 | 1493 | 1494 | Identifier 1495 | windowTool.refactoring 1496 | IncludeInToolsMenu 1497 | 0 1498 | Layout 1499 | 1500 | 1501 | Dock 1502 | 1503 | 1504 | BecomeActive 1505 | 1 1506 | GeometryConfiguration 1507 | 1508 | Frame 1509 | {0, 0}, {500, 335} 1510 | RubberWindowFrame 1511 | {0, 0}, {500, 335} 1512 | 1513 | Module 1514 | XCRefactoringModule 1515 | Proportion 1516 | 100% 1517 | 1518 | 1519 | Proportion 1520 | 100% 1521 | 1522 | 1523 | Name 1524 | Refactoring 1525 | ServiceClasses 1526 | 1527 | XCRefactoringModule 1528 | 1529 | WindowString 1530 | 200 200 500 356 0 0 1920 1200 1531 | 1532 | 1533 | 1534 | 1535 | -------------------------------------------------------------------------------- /StatusItem.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 1DDD58160DA1D0A300B32029 /* MainMenu.xib in Resources */ = {isa = PBXBuildFile; fileRef = 1DDD58140DA1D0A300B32029 /* MainMenu.xib */; }; 11 | 256AC3DA0F4B6AC300CF3369 /* StatusItemAppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 256AC3D90F4B6AC300CF3369 /* StatusItemAppDelegate.m */; }; 12 | 8D11072B0486CEB800E47090 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 089C165CFE840E0CC02AAC07 /* InfoPlist.strings */; }; 13 | 8D11072D0486CEB800E47090 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 29B97316FDCFA39411CA2CEA /* main.m */; settings = {ATTRIBUTES = (); }; }; 14 | 8D11072F0486CEB800E47090 /* Cocoa.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 1058C7A1FEA54F0111CA2CBB /* Cocoa.framework */; }; 15 | AF068675135D76240099C76F /* img.png in Resources */ = {isa = PBXBuildFile; fileRef = AF068674135D76240099C76F /* img.png */; }; 16 | AFB0BF31135ACD09009E9BFF /* PaddedTextFieldCell.m in Sources */ = {isa = PBXBuildFile; fileRef = AFB0BF30135ACD09009E9BFF /* PaddedTextFieldCell.m */; }; 17 | AFB0C1CF135B4D3F009E9BFF /* JGMenuItem.m in Sources */ = {isa = PBXBuildFile; fileRef = AFB0C1CE135B4D3F009E9BFF /* JGMenuItem.m */; }; 18 | AFC6E46E135786800022B65F /* DetectingTableView.m in Sources */ = {isa = PBXBuildFile; fileRef = AFC6E46D135786800022B65F /* DetectingTableView.m */; }; 19 | AFE5C647135A018000081B00 /* CustomStatusItemView.m in Sources */ = {isa = PBXBuildFile; fileRef = AFE5C644135A018000081B00 /* CustomStatusItemView.m */; }; 20 | AFE5C648135A018000081B00 /* FullMenuView.m in Sources */ = {isa = PBXBuildFile; fileRef = AFE5C646135A018000081B00 /* FullMenuView.m */; }; 21 | AFE5C655135A01B500081B00 /* BorderlessWindow.m in Sources */ = {isa = PBXBuildFile; fileRef = AFE5C64D135A01B500081B00 /* BorderlessWindow.m */; }; 22 | AFE5C656135A01B500081B00 /* JGMenuWindow.xib in Resources */ = {isa = PBXBuildFile; fileRef = AFE5C64E135A01B500081B00 /* JGMenuWindow.xib */; }; 23 | AFE5C657135A01B500081B00 /* JGMenuWindowController.m in Sources */ = {isa = PBXBuildFile; fileRef = AFE5C650135A01B500081B00 /* JGMenuWindowController.m */; }; 24 | AFE5C658135A01B500081B00 /* NSBezierPath+PXRoundedRectangleAdditions.m in Sources */ = {isa = PBXBuildFile; fileRef = AFE5C652135A01B500081B00 /* NSBezierPath+PXRoundedRectangleAdditions.m */; }; 25 | AFE5C659135A01B500081B00 /* RoundWindowFrameView.m in Sources */ = {isa = PBXBuildFile; fileRef = AFE5C654135A01B500081B00 /* RoundWindowFrameView.m */; }; 26 | /* End PBXBuildFile section */ 27 | 28 | /* Begin PBXFileReference section */ 29 | 089C165DFE840E0CC02AAC07 /* English */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.strings; name = English; path = English.lproj/InfoPlist.strings; sourceTree = ""; }; 30 | 1058C7A1FEA54F0111CA2CBB /* Cocoa.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Cocoa.framework; path = /System/Library/Frameworks/Cocoa.framework; sourceTree = ""; }; 31 | 13E42FB307B3F0F600E4EEF1 /* CoreData.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreData.framework; path = /System/Library/Frameworks/CoreData.framework; sourceTree = ""; }; 32 | 1DDD58150DA1D0A300B32029 /* English */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = English; path = English.lproj/MainMenu.xib; sourceTree = ""; }; 33 | 256AC3D80F4B6AC300CF3369 /* StatusItemAppDelegate.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = StatusItemAppDelegate.h; sourceTree = ""; }; 34 | 256AC3D90F4B6AC300CF3369 /* StatusItemAppDelegate.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = StatusItemAppDelegate.m; sourceTree = ""; }; 35 | 256AC3F00F4B6AF500CF3369 /* StatusItem_Prefix.pch */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = StatusItem_Prefix.pch; sourceTree = ""; }; 36 | 29B97316FDCFA39411CA2CEA /* main.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 37 | 29B97324FDCFA39411CA2CEA /* AppKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = AppKit.framework; path = /System/Library/Frameworks/AppKit.framework; sourceTree = ""; }; 38 | 29B97325FDCFA39411CA2CEA /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = /System/Library/Frameworks/Foundation.framework; sourceTree = ""; }; 39 | 8D1107310486CEB800E47090 /* StatusItem-Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; path = "StatusItem-Info.plist"; sourceTree = ""; }; 40 | 8D1107320486CEB800E47090 /* StatusItem.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = StatusItem.app; sourceTree = BUILT_PRODUCTS_DIR; }; 41 | AF068674135D76240099C76F /* img.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = img.png; sourceTree = ""; }; 42 | AFB0BF2F135ACD09009E9BFF /* PaddedTextFieldCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = PaddedTextFieldCell.h; sourceTree = ""; }; 43 | AFB0BF30135ACD09009E9BFF /* PaddedTextFieldCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = PaddedTextFieldCell.m; sourceTree = ""; }; 44 | AFB0C1CD135B4D3F009E9BFF /* JGMenuItem.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JGMenuItem.h; sourceTree = ""; }; 45 | AFB0C1CE135B4D3F009E9BFF /* JGMenuItem.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JGMenuItem.m; sourceTree = ""; }; 46 | AFC6E46C135786800022B65F /* DetectingTableView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = DetectingTableView.h; sourceTree = ""; }; 47 | AFC6E46D135786800022B65F /* DetectingTableView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = DetectingTableView.m; sourceTree = ""; }; 48 | AFE5C643135A018000081B00 /* CustomStatusItemView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = CustomStatusItemView.h; sourceTree = ""; }; 49 | AFE5C644135A018000081B00 /* CustomStatusItemView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = CustomStatusItemView.m; sourceTree = ""; }; 50 | AFE5C645135A018000081B00 /* FullMenuView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FullMenuView.h; sourceTree = ""; }; 51 | AFE5C646135A018000081B00 /* FullMenuView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FullMenuView.m; sourceTree = ""; }; 52 | AFE5C64C135A01B500081B00 /* BorderlessWindow.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = BorderlessWindow.h; sourceTree = ""; }; 53 | AFE5C64D135A01B500081B00 /* BorderlessWindow.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = BorderlessWindow.m; sourceTree = ""; }; 54 | AFE5C64E135A01B500081B00 /* JGMenuWindow.xib */ = {isa = PBXFileReference; lastKnownFileType = file.xib; path = JGMenuWindow.xib; sourceTree = ""; }; 55 | AFE5C64F135A01B500081B00 /* JGMenuWindowController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = JGMenuWindowController.h; sourceTree = ""; }; 56 | AFE5C650135A01B500081B00 /* JGMenuWindowController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = JGMenuWindowController.m; sourceTree = ""; }; 57 | AFE5C651135A01B500081B00 /* NSBezierPath+PXRoundedRectangleAdditions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = "NSBezierPath+PXRoundedRectangleAdditions.h"; sourceTree = ""; }; 58 | AFE5C652135A01B500081B00 /* NSBezierPath+PXRoundedRectangleAdditions.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = "NSBezierPath+PXRoundedRectangleAdditions.m"; sourceTree = ""; }; 59 | AFE5C653135A01B500081B00 /* RoundWindowFrameView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = RoundWindowFrameView.h; sourceTree = ""; }; 60 | AFE5C654135A01B500081B00 /* RoundWindowFrameView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = RoundWindowFrameView.m; sourceTree = ""; }; 61 | /* End PBXFileReference section */ 62 | 63 | /* Begin PBXFrameworksBuildPhase section */ 64 | 8D11072E0486CEB800E47090 /* Frameworks */ = { 65 | isa = PBXFrameworksBuildPhase; 66 | buildActionMask = 2147483647; 67 | files = ( 68 | 8D11072F0486CEB800E47090 /* Cocoa.framework in Frameworks */, 69 | ); 70 | runOnlyForDeploymentPostprocessing = 0; 71 | }; 72 | /* End PBXFrameworksBuildPhase section */ 73 | 74 | /* Begin PBXGroup section */ 75 | 080E96DDFE201D6D7F000001 /* Classes */ = { 76 | isa = PBXGroup; 77 | children = ( 78 | AFE5C642135A018000081B00 /* Status View + Coloring */, 79 | AFE5C64B135A01B500081B00 /* Window */, 80 | AFB0BF2E135ACCF1009E9BFF /* Table View */, 81 | AFB0C1CD135B4D3F009E9BFF /* JGMenuItem.h */, 82 | AFB0C1CE135B4D3F009E9BFF /* JGMenuItem.m */, 83 | 256AC3D80F4B6AC300CF3369 /* StatusItemAppDelegate.h */, 84 | 256AC3D90F4B6AC300CF3369 /* StatusItemAppDelegate.m */, 85 | ); 86 | name = Classes; 87 | sourceTree = ""; 88 | }; 89 | 1058C7A0FEA54F0111CA2CBB /* Linked Frameworks */ = { 90 | isa = PBXGroup; 91 | children = ( 92 | 1058C7A1FEA54F0111CA2CBB /* Cocoa.framework */, 93 | ); 94 | name = "Linked Frameworks"; 95 | sourceTree = ""; 96 | }; 97 | 1058C7A2FEA54F0111CA2CBB /* Other Frameworks */ = { 98 | isa = PBXGroup; 99 | children = ( 100 | 29B97324FDCFA39411CA2CEA /* AppKit.framework */, 101 | 13E42FB307B3F0F600E4EEF1 /* CoreData.framework */, 102 | 29B97325FDCFA39411CA2CEA /* Foundation.framework */, 103 | ); 104 | name = "Other Frameworks"; 105 | sourceTree = ""; 106 | }; 107 | 19C28FACFE9D520D11CA2CBB /* Products */ = { 108 | isa = PBXGroup; 109 | children = ( 110 | 8D1107320486CEB800E47090 /* StatusItem.app */, 111 | ); 112 | name = Products; 113 | sourceTree = ""; 114 | }; 115 | 29B97314FDCFA39411CA2CEA /* StatusItem */ = { 116 | isa = PBXGroup; 117 | children = ( 118 | 080E96DDFE201D6D7F000001 /* Classes */, 119 | 29B97315FDCFA39411CA2CEA /* Other Sources */, 120 | 29B97317FDCFA39411CA2CEA /* Resources */, 121 | 29B97323FDCFA39411CA2CEA /* Frameworks */, 122 | 19C28FACFE9D520D11CA2CBB /* Products */, 123 | ); 124 | name = StatusItem; 125 | sourceTree = ""; 126 | }; 127 | 29B97315FDCFA39411CA2CEA /* Other Sources */ = { 128 | isa = PBXGroup; 129 | children = ( 130 | 256AC3F00F4B6AF500CF3369 /* StatusItem_Prefix.pch */, 131 | 29B97316FDCFA39411CA2CEA /* main.m */, 132 | ); 133 | name = "Other Sources"; 134 | sourceTree = ""; 135 | }; 136 | 29B97317FDCFA39411CA2CEA /* Resources */ = { 137 | isa = PBXGroup; 138 | children = ( 139 | AF068674135D76240099C76F /* img.png */, 140 | 8D1107310486CEB800E47090 /* StatusItem-Info.plist */, 141 | 089C165CFE840E0CC02AAC07 /* InfoPlist.strings */, 142 | 1DDD58140DA1D0A300B32029 /* MainMenu.xib */, 143 | ); 144 | name = Resources; 145 | sourceTree = ""; 146 | }; 147 | 29B97323FDCFA39411CA2CEA /* Frameworks */ = { 148 | isa = PBXGroup; 149 | children = ( 150 | 1058C7A0FEA54F0111CA2CBB /* Linked Frameworks */, 151 | 1058C7A2FEA54F0111CA2CBB /* Other Frameworks */, 152 | ); 153 | name = Frameworks; 154 | sourceTree = ""; 155 | }; 156 | AFB0BF2E135ACCF1009E9BFF /* Table View */ = { 157 | isa = PBXGroup; 158 | children = ( 159 | AFC6E46C135786800022B65F /* DetectingTableView.h */, 160 | AFC6E46D135786800022B65F /* DetectingTableView.m */, 161 | AFB0BF2F135ACD09009E9BFF /* PaddedTextFieldCell.h */, 162 | AFB0BF30135ACD09009E9BFF /* PaddedTextFieldCell.m */, 163 | ); 164 | name = "Table View"; 165 | sourceTree = ""; 166 | }; 167 | AFE5C642135A018000081B00 /* Status View + Coloring */ = { 168 | isa = PBXGroup; 169 | children = ( 170 | AFE5C643135A018000081B00 /* CustomStatusItemView.h */, 171 | AFE5C644135A018000081B00 /* CustomStatusItemView.m */, 172 | AFE5C645135A018000081B00 /* FullMenuView.h */, 173 | AFE5C646135A018000081B00 /* FullMenuView.m */, 174 | ); 175 | path = "Status View + Coloring"; 176 | sourceTree = ""; 177 | }; 178 | AFE5C64B135A01B500081B00 /* Window */ = { 179 | isa = PBXGroup; 180 | children = ( 181 | AFE5C64C135A01B500081B00 /* BorderlessWindow.h */, 182 | AFE5C64D135A01B500081B00 /* BorderlessWindow.m */, 183 | AFE5C64E135A01B500081B00 /* JGMenuWindow.xib */, 184 | AFE5C64F135A01B500081B00 /* JGMenuWindowController.h */, 185 | AFE5C650135A01B500081B00 /* JGMenuWindowController.m */, 186 | AFE5C651135A01B500081B00 /* NSBezierPath+PXRoundedRectangleAdditions.h */, 187 | AFE5C652135A01B500081B00 /* NSBezierPath+PXRoundedRectangleAdditions.m */, 188 | AFE5C653135A01B500081B00 /* RoundWindowFrameView.h */, 189 | AFE5C654135A01B500081B00 /* RoundWindowFrameView.m */, 190 | ); 191 | path = Window; 192 | sourceTree = ""; 193 | }; 194 | /* End PBXGroup section */ 195 | 196 | /* Begin PBXNativeTarget section */ 197 | 8D1107260486CEB800E47090 /* StatusItem */ = { 198 | isa = PBXNativeTarget; 199 | buildConfigurationList = C01FCF4A08A954540054247B /* Build configuration list for PBXNativeTarget "StatusItem" */; 200 | buildPhases = ( 201 | 8D1107290486CEB800E47090 /* Resources */, 202 | 8D11072C0486CEB800E47090 /* Sources */, 203 | 8D11072E0486CEB800E47090 /* Frameworks */, 204 | ); 205 | buildRules = ( 206 | ); 207 | dependencies = ( 208 | ); 209 | name = StatusItem; 210 | productInstallPath = "$(HOME)/Applications"; 211 | productName = StatusItem; 212 | productReference = 8D1107320486CEB800E47090 /* StatusItem.app */; 213 | productType = "com.apple.product-type.application"; 214 | }; 215 | /* End PBXNativeTarget section */ 216 | 217 | /* Begin PBXProject section */ 218 | 29B97313FDCFA39411CA2CEA /* Project object */ = { 219 | isa = PBXProject; 220 | attributes = { 221 | LastUpgradeCheck = 0510; 222 | }; 223 | buildConfigurationList = C01FCF4E08A954540054247B /* Build configuration list for PBXProject "StatusItem" */; 224 | compatibilityVersion = "Xcode 3.2"; 225 | developmentRegion = English; 226 | hasScannedForEncodings = 1; 227 | knownRegions = ( 228 | English, 229 | Japanese, 230 | French, 231 | German, 232 | ); 233 | mainGroup = 29B97314FDCFA39411CA2CEA /* StatusItem */; 234 | projectDirPath = ""; 235 | projectRoot = ""; 236 | targets = ( 237 | 8D1107260486CEB800E47090 /* StatusItem */, 238 | ); 239 | }; 240 | /* End PBXProject section */ 241 | 242 | /* Begin PBXResourcesBuildPhase section */ 243 | 8D1107290486CEB800E47090 /* Resources */ = { 244 | isa = PBXResourcesBuildPhase; 245 | buildActionMask = 2147483647; 246 | files = ( 247 | 8D11072B0486CEB800E47090 /* InfoPlist.strings in Resources */, 248 | 1DDD58160DA1D0A300B32029 /* MainMenu.xib in Resources */, 249 | AFE5C656135A01B500081B00 /* JGMenuWindow.xib in Resources */, 250 | AF068675135D76240099C76F /* img.png in Resources */, 251 | ); 252 | runOnlyForDeploymentPostprocessing = 0; 253 | }; 254 | /* End PBXResourcesBuildPhase section */ 255 | 256 | /* Begin PBXSourcesBuildPhase section */ 257 | 8D11072C0486CEB800E47090 /* Sources */ = { 258 | isa = PBXSourcesBuildPhase; 259 | buildActionMask = 2147483647; 260 | files = ( 261 | 8D11072D0486CEB800E47090 /* main.m in Sources */, 262 | 256AC3DA0F4B6AC300CF3369 /* StatusItemAppDelegate.m in Sources */, 263 | AFC6E46E135786800022B65F /* DetectingTableView.m in Sources */, 264 | AFE5C647135A018000081B00 /* CustomStatusItemView.m in Sources */, 265 | AFE5C648135A018000081B00 /* FullMenuView.m in Sources */, 266 | AFE5C655135A01B500081B00 /* BorderlessWindow.m in Sources */, 267 | AFE5C657135A01B500081B00 /* JGMenuWindowController.m in Sources */, 268 | AFE5C658135A01B500081B00 /* NSBezierPath+PXRoundedRectangleAdditions.m in Sources */, 269 | AFE5C659135A01B500081B00 /* RoundWindowFrameView.m in Sources */, 270 | AFB0BF31135ACD09009E9BFF /* PaddedTextFieldCell.m in Sources */, 271 | AFB0C1CF135B4D3F009E9BFF /* JGMenuItem.m in Sources */, 272 | ); 273 | runOnlyForDeploymentPostprocessing = 0; 274 | }; 275 | /* End PBXSourcesBuildPhase section */ 276 | 277 | /* Begin PBXVariantGroup section */ 278 | 089C165CFE840E0CC02AAC07 /* InfoPlist.strings */ = { 279 | isa = PBXVariantGroup; 280 | children = ( 281 | 089C165DFE840E0CC02AAC07 /* English */, 282 | ); 283 | name = InfoPlist.strings; 284 | sourceTree = ""; 285 | }; 286 | 1DDD58140DA1D0A300B32029 /* MainMenu.xib */ = { 287 | isa = PBXVariantGroup; 288 | children = ( 289 | 1DDD58150DA1D0A300B32029 /* English */, 290 | ); 291 | name = MainMenu.xib; 292 | sourceTree = ""; 293 | }; 294 | /* End PBXVariantGroup section */ 295 | 296 | /* Begin XCBuildConfiguration section */ 297 | C01FCF4B08A954540054247B /* Debug */ = { 298 | isa = XCBuildConfiguration; 299 | buildSettings = { 300 | ALWAYS_SEARCH_USER_PATHS = NO; 301 | COMBINE_HIDPI_IMAGES = YES; 302 | COPY_PHASE_STRIP = NO; 303 | GCC_DYNAMIC_NO_PIC = NO; 304 | GCC_ENABLE_FIX_AND_CONTINUE = YES; 305 | GCC_MODEL_TUNING = G5; 306 | GCC_OPTIMIZATION_LEVEL = 0; 307 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 308 | GCC_PREFIX_HEADER = StatusItem_Prefix.pch; 309 | INFOPLIST_FILE = "StatusItem-Info.plist"; 310 | INSTALL_PATH = "$(HOME)/Applications"; 311 | PRODUCT_NAME = StatusItem; 312 | SDKROOT = macosx; 313 | }; 314 | name = Debug; 315 | }; 316 | C01FCF4C08A954540054247B /* Release */ = { 317 | isa = XCBuildConfiguration; 318 | buildSettings = { 319 | ALWAYS_SEARCH_USER_PATHS = NO; 320 | COMBINE_HIDPI_IMAGES = YES; 321 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 322 | GCC_MODEL_TUNING = G5; 323 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 324 | GCC_PREFIX_HEADER = StatusItem_Prefix.pch; 325 | INFOPLIST_FILE = "StatusItem-Info.plist"; 326 | INSTALL_PATH = "$(HOME)/Applications"; 327 | PRODUCT_NAME = StatusItem; 328 | SDKROOT = macosx; 329 | }; 330 | name = Release; 331 | }; 332 | C01FCF4F08A954540054247B /* Debug */ = { 333 | isa = XCBuildConfiguration; 334 | buildSettings = { 335 | GCC_C_LANGUAGE_STANDARD = gnu99; 336 | GCC_OPTIMIZATION_LEVEL = 0; 337 | GCC_WARN_ABOUT_RETURN_TYPE = YES; 338 | GCC_WARN_UNUSED_VARIABLE = YES; 339 | ONLY_ACTIVE_ARCH = YES; 340 | PREBINDING = NO; 341 | SDKROOT = macosx; 342 | }; 343 | name = Debug; 344 | }; 345 | C01FCF5008A954540054247B /* Release */ = { 346 | isa = XCBuildConfiguration; 347 | buildSettings = { 348 | GCC_C_LANGUAGE_STANDARD = gnu99; 349 | GCC_WARN_ABOUT_RETURN_TYPE = YES; 350 | GCC_WARN_UNUSED_VARIABLE = YES; 351 | PREBINDING = NO; 352 | SDKROOT = macosx; 353 | }; 354 | name = Release; 355 | }; 356 | /* End XCBuildConfiguration section */ 357 | 358 | /* Begin XCConfigurationList section */ 359 | C01FCF4A08A954540054247B /* Build configuration list for PBXNativeTarget "StatusItem" */ = { 360 | isa = XCConfigurationList; 361 | buildConfigurations = ( 362 | C01FCF4B08A954540054247B /* Debug */, 363 | C01FCF4C08A954540054247B /* Release */, 364 | ); 365 | defaultConfigurationIsVisible = 0; 366 | defaultConfigurationName = Release; 367 | }; 368 | C01FCF4E08A954540054247B /* Build configuration list for PBXProject "StatusItem" */ = { 369 | isa = XCConfigurationList; 370 | buildConfigurations = ( 371 | C01FCF4F08A954540054247B /* Debug */, 372 | C01FCF5008A954540054247B /* Release */, 373 | ); 374 | defaultConfigurationIsVisible = 0; 375 | defaultConfigurationName = Release; 376 | }; 377 | /* End XCConfigurationList section */ 378 | }; 379 | rootObject = 29B97313FDCFA39411CA2CEA /* Project object */; 380 | } 381 | -------------------------------------------------------------------------------- /StatusItem.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /StatusItem.xcodeproj/project.xcworkspace/xcshareddata/StatusItem.xccheckout: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDESourceControlProjectFavoriteDictionaryKey 6 | 7 | IDESourceControlProjectIdentifier 8 | 1DF070B9-6683-4E30-B529-8D2E0756660C 9 | IDESourceControlProjectName 10 | StatusItem 11 | IDESourceControlProjectOriginsDictionary 12 | 13 | 892D84E7-24E4-456D-993B-4CF9CDB60DC4 14 | https://github.com/SquaredTiki/JGMenuWindow.git 15 | 16 | IDESourceControlProjectPath 17 | StatusItem.xcodeproj/project.xcworkspace 18 | IDESourceControlProjectRelativeInstallPathDictionary 19 | 20 | 892D84E7-24E4-456D-993B-4CF9CDB60DC4 21 | ../.. 22 | 23 | IDESourceControlProjectURL 24 | https://github.com/SquaredTiki/JGMenuWindow.git 25 | IDESourceControlProjectVersion 26 | 110 27 | IDESourceControlProjectWCCIdentifier 28 | 892D84E7-24E4-456D-993B-4CF9CDB60DC4 29 | IDESourceControlProjectWCConfigurations 30 | 31 | 32 | IDESourceControlRepositoryExtensionIdentifierKey 33 | public.vcs.git 34 | IDESourceControlWCCIdentifierKey 35 | 892D84E7-24E4-456D-993B-4CF9CDB60DC4 36 | IDESourceControlWCCName 37 | JGMenuWindow 38 | 39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /StatusItem.xcodeproj/xcshareddata/xcschemes/StatusItem.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 32 | 33 | 44 | 45 | 51 | 52 | 53 | 54 | 55 | 56 | 64 | 65 | 71 | 72 | 73 | 74 | 76 | 77 | 80 | 81 | 82 | -------------------------------------------------------------------------------- /StatusItem.xcodeproj/xcuserdata/joshuagarnham.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | StatusItem.xcscheme 8 | 9 | orderHint 10 | 0 11 | 12 | 13 | SuppressBuildableAutocreation 14 | 15 | 8D1107260486CEB800E47090 16 | 17 | primary 18 | 19 | 20 | 21 | 22 | 23 | -------------------------------------------------------------------------------- /StatusItemAppDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // StatusItemAppDelegate.h 3 | // StatusItem 4 | // 5 | // Created by Joshua Garnham on 07/03/2011. 6 | // Copyright 2011 __MyCompanyName__. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "JGMenuWindowController.h" 11 | 12 | @interface StatusItemAppDelegate : NSObject { 13 | NSWindow *window; 14 | 15 | IBOutlet NSView *customView; 16 | IBOutlet NSSearchField *searchField; 17 | 18 | JGMenuWindowController *menuController; 19 | } 20 | 21 | @property (assign) IBOutlet NSWindow *window; 22 | 23 | @end 24 | -------------------------------------------------------------------------------- /StatusItemAppDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | // StatusItemAppDelegate.m 3 | // StatusItem 4 | // 5 | // Created by Joshua Garnham on 07/03/2011. 6 | // Copyright 2011 __MyCompanyName__. All rights reserved. 7 | // 8 | 9 | #import "StatusItemAppDelegate.h" 10 | 11 | @implementation StatusItemAppDelegate 12 | 13 | @synthesize window; 14 | 15 | - (void)applicationDidFinishLaunching:(NSNotification *)aNotification { 16 | menuController = [[[JGMenuWindowController alloc] initWithWindowNibName:@"JGMenuWindow"] retain]; 17 | [menuController setHeaderView:customView]; 18 | [menuController setMenuDelegate:self]; 19 | [menuController setStatusItemTitle:@"Search"]; 20 | // [menuController setStatusItemImage:[NSImage imageNamed:@"img.png"]]; 21 | 22 | /* NSMutableArray *items = [[NSMutableArray alloc] init]; 23 | for (int i = 0; i < 6; i++) { 24 | if (i==3) 25 | [items addObject:[JGMenuItem seperatorItem]]; 26 | JGMenuItem *menuItem = [[JGMenuItem alloc] initWithTitle:[NSString stringWithFormat:@"Result %i", i] target:self action:@selector(itemSelected)]; 27 | if (i==2) { 28 | JGMenuItem *title = [[JGMenuItem alloc] initWithTitle:@"You can't select me." target:nil action:NULL]; 29 | [title setEnabled:NO]; 30 | [items addObject:title]; 31 | } 32 | if (i==3) { 33 | [menuItem setImage:[NSImage imageNamed:@"img.png"]]; 34 | JGMenuWindowController *subController = [[JGMenuWindowController alloc] initWithWindowNibName:@"JGMenuWindow"]; 35 | [subController setIsStatusItem:NO]; 36 | JGMenuItem *subItem = [[JGMenuItem alloc] initWithTitle:@"i'm a lone sub item :(" target:self action:NULL]; 37 | [subController setMenuItems:[NSArray arrayWithObject:subItem]]; 38 | [menuItem setSubmenu:subController]; 39 | } 40 | [items addObject:menuItem]; 41 | } 42 | [menuController setMenuItems:items]; */ 43 | } 44 | 45 | #pragma mark Showing and Hiding Table 46 | 47 | - (void)showTableView { 48 | NSMutableArray *items = [[NSMutableArray alloc] init]; 49 | for (int i = 0; i < 6; i++) { 50 | if (i==3) 51 | [items addObject:[JGMenuItem seperatorItem]]; 52 | JGMenuItem *menuItem = [[JGMenuItem alloc] initWithTitle:[NSString stringWithFormat:@"Result %i", i] target:self action:@selector(itemSelected)]; 53 | if (i==2) { 54 | JGMenuItem *title = [[JGMenuItem alloc] initWithTitle:@"You can't select me." target:nil action:NULL]; 55 | [title setEnabled:NO]; 56 | [items addObject:title]; 57 | } 58 | if (i==3) { 59 | [menuItem setImage:[NSImage imageNamed:@"img.png"]]; 60 | JGMenuWindowController *subController = [[JGMenuWindowController alloc] initWithWindowNibName:@"JGMenuWindow"]; 61 | [subController setIsStatusItem:NO]; 62 | JGMenuItem *subItem = [[JGMenuItem alloc] initWithTitle:@"i'm a lone sub item :(" target:self action:NULL]; 63 | [subController setMenuItems:[NSArray arrayWithObject:subItem]]; 64 | [menuItem setSubmenu:subController]; 65 | } 66 | [items addObject:menuItem]; 67 | } 68 | [menuController setMenuItems:items]; 69 | [menuController highlightMenuItemAtIndex:0]; 70 | } 71 | 72 | - (void)hideTableView { 73 | [menuController setMenuItems:nil]; 74 | } 75 | 76 | - (void)itemSelected { 77 | JGMenuWindowController *subController = [[JGMenuWindowController alloc] initWithWindowNibName:@"JGMenuWindow"]; 78 | [subController setIsStatusItem:NO]; 79 | NSMutableArray *items = [[NSMutableArray alloc] init]; 80 | for (int i = 0; i < 6; i++) { 81 | if (i==3) 82 | [items addObject:[JGMenuItem seperatorItem]]; 83 | JGMenuItem *menuItem = [[JGMenuItem alloc] initWithTitle:[NSString stringWithFormat:@"Result %i", i] target:self action:NULL]; 84 | if (i==4) { 85 | JGMenuWindowController *subController = [[JGMenuWindowController alloc] initWithWindowNibName:@"JGMenuWindow"]; 86 | [subController setIsStatusItem:NO]; 87 | JGMenuItem *subItem = [[JGMenuItem alloc] initWithTitle:@"i'm another lone sub item" target:self action:NULL]; 88 | [subController setMenuItems:[NSArray arrayWithObject:subItem]]; 89 | [menuItem setSubmenu:subController]; 90 | } 91 | [items addObject:menuItem]; 92 | } 93 | [subController setProMode:YES]; 94 | [subController setMenuItems:items]; 95 | [subController popUpContextMenuAtPoint:NSMakePoint(500, 500)]; 96 | } 97 | 98 | #pragma mark JGMenuWindowDelegate 99 | 100 | - (void)menuWillOpen { 101 | [searchField becomeFirstResponder]; // Even though it will happen automatically, just to be on the safe side… 102 | } 103 | 104 | #pragma mark NSControlTextEditingDelegate 105 | 106 | - (BOOL)control:(NSControl *)control textShouldBeginEditing:(NSText *)fieldEditor { 107 | if (![searchField.stringValue isEqualToString:@""] && [searchField.stringValue length] <= 1) { 108 | [self showTableView]; 109 | } 110 | return YES; 111 | } 112 | 113 | - (void)controlTextDidChange:(NSNotification *)obj { 114 | if (![searchField.stringValue isEqualToString:@""] && [searchField.stringValue length] <= 1) { 115 | [self showTableView]; 116 | } else if ([searchField.stringValue isEqualToString:@""]) { 117 | [self hideTableView]; 118 | } 119 | } 120 | 121 | @end 122 | -------------------------------------------------------------------------------- /StatusItem_Prefix.pch: -------------------------------------------------------------------------------- 1 | // 2 | // Prefix header for all source files of the 'StatusItem' target in the 'StatusItem' project 3 | // 4 | 5 | #ifdef __OBJC__ 6 | #import 7 | #endif 8 | -------------------------------------------------------------------------------- /Window/BorderlessWindow.h: -------------------------------------------------------------------------------- 1 | // 2 | // BorderlessWindow.h 3 | // IDZR 4 | // 5 | // Created by Joshua Garnham on 27/12/2010. 6 | // Copyright 2010 __MyCompanyName__. All rights reserved. 7 | // 8 | 9 | #import 10 | @interface BorderlessWindow : NSWindow { 11 | NSView *childContentView; 12 | } 13 | 14 | @end 15 | -------------------------------------------------------------------------------- /Window/BorderlessWindow.m: -------------------------------------------------------------------------------- 1 | // 2 | // BorderlessWindow.m 3 | // IDZR 4 | // 5 | // Created by Joshua Garnham on 27/12/2010. 6 | // Copyright 2010 __MyCompanyName__. All rights reserved. 7 | // 8 | 9 | #import "BorderlessWindow.h" 10 | #import "RoundWindowFrameView.h" 11 | 12 | @implementation BorderlessWindow 13 | 14 | - (id)initWithContentRect:(NSRect)contentRect 15 | styleMask:(NSUInteger)aStyle 16 | backing:(NSBackingStoreType)bufferingType 17 | defer:(BOOL)flag 18 | { 19 | if ((self = [super initWithContentRect:contentRect 20 | styleMask:NSBorderlessWindowMask 21 | backing:bufferingType 22 | defer:flag])) 23 | { 24 | [self setOpaque:NO]; 25 | [self setBackgroundColor:[NSColor clearColor]]; 26 | [self setLevel:NSPopUpMenuWindowLevel+1]; 27 | } 28 | 29 | return(self); 30 | } 31 | 32 | // setContentView: 33 | // 34 | // Keep our frame view as the content view and make the specified "aView" 35 | // the child of that. 36 | // 37 | - (void)setContentView:(NSView *)aView 38 | { 39 | if ([childContentView isEqualTo:aView]) 40 | { 41 | //return; 42 | } 43 | 44 | NSRect bounds = [self frame]; 45 | bounds.origin = NSZeroPoint; 46 | 47 | RoundWindowFrameView *frameView = [super contentView]; 48 | if (!frameView) 49 | { 50 | frameView = [[[RoundWindowFrameView alloc] initWithFrame:bounds] autorelease]; 51 | 52 | [super setContentView:frameView]; 53 | } 54 | 55 | childContentView = aView; 56 | [childContentView setFrame:[self contentRectForFrameRect:bounds]]; 57 | [childContentView setAutoresizingMask:NSViewWidthSizable | NSViewHeightSizable]; 58 | [frameView addSubview:childContentView]; 59 | } 60 | 61 | - (NSView *)contentView 62 | { 63 | return childContentView; 64 | } 65 | 66 | - (BOOL) canBecomeKeyWindow { return YES; } 67 | - (BOOL) canBecomeMainWindow { return YES; } 68 | - (BOOL) acceptsFirstResponder { return YES; } 69 | - (BOOL) becomeFirstResponder { return YES; } 70 | - (BOOL) resignFirstResponder { return YES; } 71 | 72 | @end 73 | -------------------------------------------------------------------------------- /Window/JGMenuWindow.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 1060 5 | 10J3250 6 | 851 7 | 1038.35 8 | 461.00 9 | 10 | com.apple.InterfaceBuilder.CocoaPlugin 11 | 851 12 | 13 | 14 | YES 15 | 16 | 17 | 18 | YES 19 | com.apple.InterfaceBuilder.CocoaPlugin 20 | 21 | 22 | YES 23 | 24 | YES 25 | 26 | 27 | YES 28 | 29 | 30 | 31 | YES 32 | 33 | JGMenuWindowController 34 | 35 | 36 | FirstResponder 37 | 38 | 39 | NSApplication 40 | 41 | 42 | 15 43 | 2 44 | {{196, 218}, {252, 292}} 45 | 1618477056 46 | Window 47 | BorderlessWindow 48 | 49 | {1.79769e+308, 1.79769e+308} 50 | 51 | 52 | 256 53 | 54 | YES 55 | 56 | 57 | 268 58 | 59 | YES 60 | 61 | 62 | -2147483380 63 | {{0, 1}, {252, 67}} 64 | 65 | YES 66 | 67 | -2080244224 68 | 134217728 69 | I'm A Big Button 70 | 71 | LucidaGrande 72 | 13 73 | 1044 74 | 75 | 76 | -2033434369 77 | 162 78 | 79 | 80 | 400 81 | 75 82 | 83 | 84 | 85 | {{0, 225}, {252, 67}} 86 | 87 | NSView 88 | 89 | 90 | 91 | 4397 92 | 93 | YES 94 | 95 | 96 | 2304 97 | 98 | YES 99 | 100 | 101 | 4397 102 | {252, 225} 103 | 104 | YES 105 | 106 | 107 | -2147483392 108 | {{224, 0}, {16, 17}} 109 | 110 | 111 | YES 112 | 113 | 249 114 | 10 115 | 1000 116 | 117 | 75628096 118 | 2048 119 | 120 | 121 | LucidaGrande 122 | 11 123 | 3100 124 | 125 | 126 | 3 127 | MC4zMzMzMzI5ODU2AA 128 | 129 | 130 | 6 131 | System 132 | headerTextColor 133 | 134 | 3 135 | MAA 136 | 137 | 138 | 139 | 140 | 337772096 141 | 2048 142 | Text Cell 143 | 144 | LucidaGrande 145 | 14 146 | 16 147 | 148 | 149 | 150 | 6 151 | System 152 | controlBackgroundColor 153 | 154 | 3 155 | MC42NjY2NjY2NjY3AA 156 | 157 | 158 | 159 | 6 160 | System 161 | controlTextColor 162 | 163 | 164 | 165 | 1 166 | YES 167 | 168 | 169 | 170 | 3 171 | 2 172 | 173 | 4 174 | MSAwAA 175 | 176 | 177 | 4 178 | MC44IDAAA 179 | 180 | 18 181 | -1774190592 182 | 183 | 184 | 4 185 | 15 186 | 0 187 | YES 188 | 0 189 | 190 | 191 | {252, 225} 192 | 193 | 194 | 195 | 196 | 6 197 | System 198 | alternateSelectedControlColor 199 | 200 | 1 201 | MCAwIDEAA 202 | 203 | 204 | 2 205 | 206 | 207 | 208 | -2147483392 209 | {{-100, -100}, {15, 102}} 210 | 211 | 212 | _doScroller: 213 | 0.94047619047619047 214 | 215 | 216 | 217 | -2147483392 218 | {{-100, -100}, {223, 15}} 219 | 220 | 1 221 | 222 | _doScroller: 223 | 0.95845697329376855 224 | 225 | 226 | {{0, -2}, {252, 225}} 227 | 228 | 229 | 0 230 | 231 | 232 | 233 | QSAAAEEgAABBoAAAQaAAAA 234 | 235 | 236 | {252, 292} 237 | 238 | 239 | {{0, 0}, {1680, 1028}} 240 | {1.79769e+308, 1.79769e+308} 241 | 242 | 243 | 244 | 245 | YES 246 | 247 | 248 | _headerView 249 | 250 | 251 | 252 | 16 253 | 254 | 255 | 256 | itemsTable 257 | 258 | 259 | 260 | 17 261 | 262 | 263 | 264 | window 265 | 266 | 267 | 268 | 19 269 | 270 | 271 | 272 | delegate 273 | 274 | 275 | 276 | 20 277 | 278 | 279 | 280 | dataSource 281 | 282 | 283 | 284 | 21 285 | 286 | 287 | 288 | 289 | YES 290 | 291 | 0 292 | 293 | 294 | 295 | 296 | 297 | -2 298 | 299 | 300 | File's Owner 301 | 302 | 303 | -1 304 | 305 | 306 | First Responder 307 | 308 | 309 | -3 310 | 311 | 312 | Application 313 | 314 | 315 | 1 316 | 317 | 318 | YES 319 | 320 | 321 | 322 | 323 | 324 | 2 325 | 326 | 327 | YES 328 | 329 | 330 | 331 | 332 | 333 | 334 | 3 335 | 336 | 337 | YES 338 | 339 | 340 | 341 | 342 | 343 | 5 344 | 345 | 346 | YES 347 | 348 | 349 | 350 | 351 | 352 | 353 | 354 | 6 355 | 356 | 357 | YES 358 | 359 | 360 | 361 | 362 | 363 | 7 364 | 365 | 366 | 367 | 368 | 8 369 | 370 | 371 | 372 | 373 | 9 374 | 375 | 376 | YES 377 | 378 | 379 | 380 | 381 | 382 | 10 383 | 384 | 385 | 386 | 387 | 22 388 | 389 | 390 | YES 391 | 392 | 393 | 394 | 395 | 396 | 23 397 | 398 | 399 | 400 | 401 | 402 | 403 | YES 404 | 405 | YES 406 | 1.IBEditorWindowLastContentRect 407 | 1.IBPluginDependency 408 | 1.IBWindowTemplateEditedContentRect 409 | 1.NSWindowTemplate.visibleAtLaunch 410 | 1.WindowOrigin 411 | 1.editorWindowContentRectSynchronizationRect 412 | 10.CustomClassName 413 | 10.IBPluginDependency 414 | 2.IBPluginDependency 415 | 22.IBPluginDependency 416 | 23.IBPluginDependency 417 | 3.IBPluginDependency 418 | 3.IBViewBoundsToFrameTransform 419 | 5.IBPluginDependency 420 | 5.IBViewBoundsToFrameTransform 421 | 6.CustomClassName 422 | 6.IBPluginDependency 423 | 6.IBViewBoundsToFrameTransform 424 | 7.IBPluginDependency 425 | 8.IBPluginDependency 426 | 9.IBPluginDependency 427 | 428 | 429 | YES 430 | {{482, 103}, {252, 292}} 431 | com.apple.InterfaceBuilder.CocoaPlugin 432 | {{482, 103}, {252, 292}} 433 | 434 | {196, 240} 435 | {{202, 428}, {480, 270}} 436 | PaddedTextFieldCell 437 | com.apple.InterfaceBuilder.CocoaPlugin 438 | com.apple.InterfaceBuilder.CocoaPlugin 439 | com.apple.InterfaceBuilder.CocoaPlugin 440 | com.apple.InterfaceBuilder.CocoaPlugin 441 | com.apple.InterfaceBuilder.CocoaPlugin 442 | 443 | AQAAAABDYQAAA 444 | 445 | com.apple.InterfaceBuilder.CocoaPlugin 446 | 447 | P4AAAL+AAAAAAAAAw1cAAA 448 | 449 | DetectingTableView 450 | com.apple.InterfaceBuilder.CocoaPlugin 451 | 452 | com.apple.InterfaceBuilder.CocoaPlugin 453 | com.apple.InterfaceBuilder.CocoaPlugin 454 | com.apple.InterfaceBuilder.CocoaPlugin 455 | 456 | 457 | 458 | YES 459 | 460 | 461 | YES 462 | 463 | 464 | 465 | 466 | YES 467 | 468 | 469 | YES 470 | 471 | 472 | 473 | 23 474 | 475 | 476 | 477 | YES 478 | 479 | BorderlessWindow 480 | NSWindow 481 | 482 | IBProjectSource 483 | Window/BorderlessWindow.h 484 | 485 | 486 | 487 | DetectingTableView 488 | NSTableView 489 | 490 | IBProjectSource 491 | DetectingTableView.h 492 | 493 | 494 | 495 | JGMenuWindowController 496 | NSWindowController 497 | 498 | YES 499 | 500 | YES 501 | _headerView 502 | itemsTable 503 | menuDelegate 504 | 505 | 506 | YES 507 | NSView 508 | NSTableView 509 | id 510 | 511 | 512 | 513 | YES 514 | 515 | YES 516 | _headerView 517 | itemsTable 518 | menuDelegate 519 | 520 | 521 | YES 522 | 523 | _headerView 524 | NSView 525 | 526 | 527 | itemsTable 528 | NSTableView 529 | 530 | 531 | menuDelegate 532 | id 533 | 534 | 535 | 536 | 537 | IBProjectSource 538 | Window/JGMenuWindowController.h 539 | 540 | 541 | 542 | PaddedTextFieldCell 543 | NSTextFieldCell 544 | 545 | IBProjectSource 546 | PaddedTextFieldCell.h 547 | 548 | 549 | 550 | 551 | YES 552 | 553 | NSActionCell 554 | NSCell 555 | 556 | IBFrameworkSource 557 | AppKit.framework/Headers/NSActionCell.h 558 | 559 | 560 | 561 | NSApplication 562 | NSResponder 563 | 564 | IBFrameworkSource 565 | AppKit.framework/Headers/NSApplication.h 566 | 567 | 568 | 569 | NSApplication 570 | 571 | IBFrameworkSource 572 | AppKit.framework/Headers/NSApplicationScripting.h 573 | 574 | 575 | 576 | NSApplication 577 | 578 | IBFrameworkSource 579 | AppKit.framework/Headers/NSColorPanel.h 580 | 581 | 582 | 583 | NSApplication 584 | 585 | IBFrameworkSource 586 | AppKit.framework/Headers/NSHelpManager.h 587 | 588 | 589 | 590 | NSApplication 591 | 592 | IBFrameworkSource 593 | AppKit.framework/Headers/NSPageLayout.h 594 | 595 | 596 | 597 | NSApplication 598 | 599 | IBFrameworkSource 600 | AppKit.framework/Headers/NSUserInterfaceItemSearching.h 601 | 602 | 603 | 604 | NSButton 605 | NSControl 606 | 607 | IBFrameworkSource 608 | AppKit.framework/Headers/NSButton.h 609 | 610 | 611 | 612 | NSButtonCell 613 | NSActionCell 614 | 615 | IBFrameworkSource 616 | AppKit.framework/Headers/NSButtonCell.h 617 | 618 | 619 | 620 | NSCell 621 | NSObject 622 | 623 | IBFrameworkSource 624 | AppKit.framework/Headers/NSCell.h 625 | 626 | 627 | 628 | NSControl 629 | NSView 630 | 631 | IBFrameworkSource 632 | AppKit.framework/Headers/NSControl.h 633 | 634 | 635 | 636 | NSFormatter 637 | NSObject 638 | 639 | IBFrameworkSource 640 | Foundation.framework/Headers/NSFormatter.h 641 | 642 | 643 | 644 | NSMenu 645 | NSObject 646 | 647 | IBFrameworkSource 648 | AppKit.framework/Headers/NSMenu.h 649 | 650 | 651 | 652 | NSObject 653 | 654 | IBFrameworkSource 655 | AppKit.framework/Headers/NSAccessibility.h 656 | 657 | 658 | 659 | NSObject 660 | 661 | 662 | 663 | NSObject 664 | 665 | 666 | 667 | NSObject 668 | 669 | 670 | 671 | NSObject 672 | 673 | 674 | 675 | NSObject 676 | 677 | IBFrameworkSource 678 | AppKit.framework/Headers/NSDictionaryController.h 679 | 680 | 681 | 682 | NSObject 683 | 684 | IBFrameworkSource 685 | AppKit.framework/Headers/NSDragging.h 686 | 687 | 688 | 689 | NSObject 690 | 691 | IBFrameworkSource 692 | AppKit.framework/Headers/NSFontManager.h 693 | 694 | 695 | 696 | NSObject 697 | 698 | IBFrameworkSource 699 | AppKit.framework/Headers/NSFontPanel.h 700 | 701 | 702 | 703 | NSObject 704 | 705 | IBFrameworkSource 706 | AppKit.framework/Headers/NSKeyValueBinding.h 707 | 708 | 709 | 710 | NSObject 711 | 712 | 713 | 714 | NSObject 715 | 716 | IBFrameworkSource 717 | AppKit.framework/Headers/NSNibLoading.h 718 | 719 | 720 | 721 | NSObject 722 | 723 | IBFrameworkSource 724 | AppKit.framework/Headers/NSOutlineView.h 725 | 726 | 727 | 728 | NSObject 729 | 730 | IBFrameworkSource 731 | AppKit.framework/Headers/NSPasteboard.h 732 | 733 | 734 | 735 | NSObject 736 | 737 | IBFrameworkSource 738 | AppKit.framework/Headers/NSSavePanel.h 739 | 740 | 741 | 742 | NSObject 743 | 744 | IBFrameworkSource 745 | AppKit.framework/Headers/NSTableView.h 746 | 747 | 748 | 749 | NSObject 750 | 751 | IBFrameworkSource 752 | AppKit.framework/Headers/NSToolbarItem.h 753 | 754 | 755 | 756 | NSObject 757 | 758 | IBFrameworkSource 759 | AppKit.framework/Headers/NSView.h 760 | 761 | 762 | 763 | NSObject 764 | 765 | IBFrameworkSource 766 | Foundation.framework/Headers/NSArchiver.h 767 | 768 | 769 | 770 | NSObject 771 | 772 | IBFrameworkSource 773 | Foundation.framework/Headers/NSClassDescription.h 774 | 775 | 776 | 777 | NSObject 778 | 779 | IBFrameworkSource 780 | Foundation.framework/Headers/NSError.h 781 | 782 | 783 | 784 | NSObject 785 | 786 | IBFrameworkSource 787 | Foundation.framework/Headers/NSFileManager.h 788 | 789 | 790 | 791 | NSObject 792 | 793 | IBFrameworkSource 794 | Foundation.framework/Headers/NSKeyValueCoding.h 795 | 796 | 797 | 798 | NSObject 799 | 800 | IBFrameworkSource 801 | Foundation.framework/Headers/NSKeyValueObserving.h 802 | 803 | 804 | 805 | NSObject 806 | 807 | IBFrameworkSource 808 | Foundation.framework/Headers/NSKeyedArchiver.h 809 | 810 | 811 | 812 | NSObject 813 | 814 | IBFrameworkSource 815 | Foundation.framework/Headers/NSObject.h 816 | 817 | 818 | 819 | NSObject 820 | 821 | IBFrameworkSource 822 | Foundation.framework/Headers/NSObjectScripting.h 823 | 824 | 825 | 826 | NSObject 827 | 828 | IBFrameworkSource 829 | Foundation.framework/Headers/NSPortCoder.h 830 | 831 | 832 | 833 | NSObject 834 | 835 | IBFrameworkSource 836 | Foundation.framework/Headers/NSRunLoop.h 837 | 838 | 839 | 840 | NSObject 841 | 842 | IBFrameworkSource 843 | Foundation.framework/Headers/NSScriptClassDescription.h 844 | 845 | 846 | 847 | NSObject 848 | 849 | IBFrameworkSource 850 | Foundation.framework/Headers/NSScriptKeyValueCoding.h 851 | 852 | 853 | 854 | NSObject 855 | 856 | IBFrameworkSource 857 | Foundation.framework/Headers/NSScriptObjectSpecifiers.h 858 | 859 | 860 | 861 | NSObject 862 | 863 | IBFrameworkSource 864 | Foundation.framework/Headers/NSScriptWhoseTests.h 865 | 866 | 867 | 868 | NSObject 869 | 870 | IBFrameworkSource 871 | Foundation.framework/Headers/NSThread.h 872 | 873 | 874 | 875 | NSObject 876 | 877 | IBFrameworkSource 878 | Foundation.framework/Headers/NSURL.h 879 | 880 | 881 | 882 | NSObject 883 | 884 | IBFrameworkSource 885 | Foundation.framework/Headers/NSURLConnection.h 886 | 887 | 888 | 889 | NSObject 890 | 891 | IBFrameworkSource 892 | Foundation.framework/Headers/NSURLDownload.h 893 | 894 | 895 | 896 | NSResponder 897 | 898 | IBFrameworkSource 899 | AppKit.framework/Headers/NSInterfaceStyle.h 900 | 901 | 902 | 903 | NSResponder 904 | NSObject 905 | 906 | IBFrameworkSource 907 | AppKit.framework/Headers/NSResponder.h 908 | 909 | 910 | 911 | NSScrollView 912 | NSView 913 | 914 | IBFrameworkSource 915 | AppKit.framework/Headers/NSScrollView.h 916 | 917 | 918 | 919 | NSScroller 920 | NSControl 921 | 922 | IBFrameworkSource 923 | AppKit.framework/Headers/NSScroller.h 924 | 925 | 926 | 927 | NSTableColumn 928 | NSObject 929 | 930 | IBFrameworkSource 931 | AppKit.framework/Headers/NSTableColumn.h 932 | 933 | 934 | 935 | NSTableView 936 | NSControl 937 | 938 | 939 | 940 | NSTextFieldCell 941 | NSActionCell 942 | 943 | IBFrameworkSource 944 | AppKit.framework/Headers/NSTextFieldCell.h 945 | 946 | 947 | 948 | NSView 949 | 950 | IBFrameworkSource 951 | AppKit.framework/Headers/NSClipView.h 952 | 953 | 954 | 955 | NSView 956 | 957 | IBFrameworkSource 958 | AppKit.framework/Headers/NSMenuItem.h 959 | 960 | 961 | 962 | NSView 963 | 964 | IBFrameworkSource 965 | AppKit.framework/Headers/NSRulerView.h 966 | 967 | 968 | 969 | NSView 970 | NSResponder 971 | 972 | 973 | 974 | NSWindow 975 | 976 | IBFrameworkSource 977 | AppKit.framework/Headers/NSDrawer.h 978 | 979 | 980 | 981 | NSWindow 982 | NSResponder 983 | 984 | IBFrameworkSource 985 | AppKit.framework/Headers/NSWindow.h 986 | 987 | 988 | 989 | NSWindow 990 | 991 | IBFrameworkSource 992 | AppKit.framework/Headers/NSWindowScripting.h 993 | 994 | 995 | 996 | NSWindowController 997 | NSResponder 998 | 999 | showWindow: 1000 | id 1001 | 1002 | 1003 | showWindow: 1004 | 1005 | showWindow: 1006 | id 1007 | 1008 | 1009 | 1010 | IBFrameworkSource 1011 | AppKit.framework/Headers/NSWindowController.h 1012 | 1013 | 1014 | 1015 | 1016 | 0 1017 | IBCocoaFramework 1018 | 1019 | com.apple.InterfaceBuilder.CocoaPlugin.macosx 1020 | 1021 | 1022 | 1023 | com.apple.InterfaceBuilder.CocoaPlugin.InterfaceBuilder3 1024 | 1025 | 1026 | YES 1027 | ../StatusItem.xcodeproj 1028 | 3 1029 | 1030 | 1031 | -------------------------------------------------------------------------------- /Window/JGMenuWindowController.h: -------------------------------------------------------------------------------- 1 | // 2 | // JGMenuWindowController.h 3 | // StatusItem 4 | // 5 | // Created by Joshua Garnham on 15/04/2011. 6 | // Copyright 2011 __MyCompanyName__. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "CustomStatusItemView.h" 11 | #import "RoundWindowFrameView.h" 12 | #import "DetectingTableView.h" 13 | #import "BorderlessWindow.h" 14 | #import "JGMenuItem.h" 15 | #import "PaddedTextFieldCell.h" 16 | 17 | #define DLog(fmt, ...) NSLog((@"%s [Line %d] " fmt), __PRETTY_FUNCTION__, __LINE__, ##__VA_ARGS__); 18 | 19 | @protocol JGMenuWindowDelegate 20 | 21 | @optional 22 | - (void)menuWillOpen; 23 | - (void)menuWillClose; 24 | - (BOOL)shouldCloseMenuAfterSelectingRow:(int)row; 25 | 26 | @end 27 | 28 | @class JGMenuItem; 29 | 30 | @interface JGMenuWindowController : NSWindowController { 31 | @private /* PRIVATE VARIABLES */ 32 | 33 | NSStatusItem *statusItem; // The Primary Status Item 34 | CustomStatusItemView *customStatusView; // PRIVATE: The Custom view within the status item 35 | 36 | NSTableView *itemsTable; // PRIVATE: The table where the items are displaye 37 | int mouseOverRow; // PRIVATE: Used to store which row the mouse is hovering over 38 | 39 | NSView *_headerView; // PRIVATE: The header view conainer 40 | 41 | NSTimer *timer; // PRIVATE: Used for fade out. 42 | 43 | float timeHovering; // PRIVATE: Amount of time hovering on a single point USED TO PREVENT DRAWING ISSUE 44 | BOOL isSelecting; // PRIVATE: Whether or not is selecting 45 | 46 | JGMenuItem *itemWithOpenSubmenu; 47 | JGMenuWindowController *parentMenu; 48 | BOOL isMovingBackToParent; 49 | 50 | @public 51 | 52 | NSArray *menuItems; // An array of JGMenuItem's which can be set and which will be displayed 53 | NSView *headerView; // An optional headerView to be displayed at the top of the menu in a similar way to spotlight 54 | 55 | id menuDelegate; // The delegate which will recieve the optional method calls 56 | 57 | NSImage *statusItemImage; // Relayed to the customStatusView to set the Status Item image 58 | NSImage *statusItemAlternateImage; // Relayed to the customStatusView to set the Status Item alternate image 59 | NSString *statusItemTitle; // Relayed to the customStatusView to set the Status Item title 60 | 61 | BOOL isStatusItem; // Default is YES 62 | BOOL proMode; // Want your menu to look like those in the Apple Pro apps? then set this to YES! 63 | } 64 | 65 | @property (assign) IBOutlet NSTableView *itemsTable; 66 | @property (assign, readonly) IBOutlet NSView *_headerView; 67 | @property (nonatomic, retain) NSArray *menuItems; 68 | @property (nonatomic, retain) NSView *headerView; 69 | @property (nonatomic, retain) id menuDelegate; 70 | @property (nonatomic, copy) NSImage *statusItemImage; 71 | @property (nonatomic, copy) NSImage *statusItemAlternateImage; 72 | @property (nonatomic, copy) NSString *statusItemTitle; 73 | @property (nonatomic, assign) BOOL isStatusItem; 74 | @property (nonatomic, assign) BOOL proMode; 75 | @property (nonatomic, retain) JGMenuWindowController *parentMenu; // PRIVATE: Even though this is a property it should only be accessed by another menu controller 76 | @property (nonatomic, assign) int mouseOverRow; // PRIVATE: Even though this is a property it should only be accessed by another menu controller 77 | 78 | 79 | - (void)highlightMenuItemAtIndex:(int)rowIndex; // Forcefully highlight a menu item 80 | - (void)closeWindow; // Close window with fade out 81 | - (void)popUpContextMenuAtPoint:(NSPoint)point; // Pop up the menu at a specific point 82 | 83 | @end 84 | -------------------------------------------------------------------------------- /Window/JGMenuWindowController.m: -------------------------------------------------------------------------------- 1 | // 2 | // JGMenuWindowController.m 3 | // StatusItem 4 | // 5 | // Created by Joshua Garnham on 15/04/2011. 6 | // Copyright 2011 __MyCompanyName__. All rights reserved. 7 | // 8 | 9 | #import "JGMenuWindowController.h" 10 | 11 | @interface JGMenuWindowController() 12 | 13 | - (void)loadHeights; 14 | - (BOOL)loadHeightsWithWindowOrigin:(NSPoint)origin whichIsSubmenu:(BOOL)isSubmenu; 15 | 16 | @end 17 | 18 | @implementation JGMenuWindowController 19 | @synthesize itemsTable, _headerView, menuDelegate, proMode, parentMenu, mouseOverRow; 20 | @dynamic menuItems, headerView, statusItemImage, statusItemAlternateImage, statusItemTitle, isStatusItem; 21 | 22 | - (id)initWithWindowNibName:(NSString *)windowNibName { 23 | self = [super initWithWindowNibName:windowNibName]; 24 | if (self) { 25 | // Set up status item 26 | NSStatusBar *bar = [NSStatusBar systemStatusBar]; 27 | 28 | statusItem = [bar statusItemWithLength:NSVariableStatusItemLength]; 29 | [statusItem retain]; 30 | 31 | customStatusView = [[CustomStatusItemView alloc] initWithFrame:NSMakeRect(0, 0, 30, 20)]; 32 | [customStatusView setTarget:self]; 33 | [customStatusView setSelectingAction:@selector(statusItemSelected:)]; 34 | [customStatusView setDeselectingAction:@selector(statusItemDeselected:)]; 35 | [customStatusView setStatusItem:statusItem]; 36 | [statusItem setView:customStatusView]; 37 | 38 | // Set delegates 39 | [(RoundWindowFrameView *)[[self.window contentView] superview] setTableDelegate:self]; 40 | [[self window] setDelegate:self]; 41 | 42 | // Set up ivars 43 | mouseOverRow = -1; 44 | } 45 | return self; 46 | } 47 | 48 | #pragma mark Misc. 49 | 50 | - (void)highlightMenuItemAtIndex:(int)rowIndex { 51 | mouseOverRow = rowIndex; 52 | [itemsTable reloadData]; 53 | } 54 | 55 | #pragma mark Opening menu without status items 56 | 57 | - (void)popUpContextMenuAtPoint:(NSPoint)point { 58 | if (timer) { // Window shouldn't be closing right now. Stop the timer. 59 | [timer invalidate]; 60 | [timer release]; 61 | timer = nil; 62 | [self.window setAlphaValue:1.0]; 63 | } 64 | 65 | [self loadHeightsWithWindowOrigin:point whichIsSubmenu:NO]; 66 | [(RoundWindowFrameView *)[[self.window contentView] superview] setAllCornersRounded:YES]; 67 | [(RoundWindowFrameView *)[[self.window contentView] superview] setProMode:proMode]; 68 | [self.window makeKeyAndOrderFront:self]; 69 | [[NSApplication sharedApplication] activateIgnoringOtherApps:YES]; 70 | } 71 | 72 | #pragma mark Dealing with submenu's 73 | 74 | - (void)popUpSubmenuAtPoint:(NSPoint)point whichIsSide:(int)preferedSide { 75 | if (timer) { // Window shouldn't be closing right now. Stop the timer. 76 | [timer invalidate]; 77 | [timer release]; 78 | timer = nil; 79 | [self.window setAlphaValue:1.0]; 80 | } 81 | 82 | BOOL side = ![self loadHeightsWithWindowOrigin:point whichIsSubmenu:YES]; // Returns 0 = right while we want 0 = left 83 | NSLog(@"side = %i", side); 84 | [(RoundWindowFrameView *)[[self.window contentView] superview] setIsSubmenuOnSide:side]; 85 | [self setProMode:parentMenu.proMode]; // Respects parent's style 86 | [(RoundWindowFrameView *)[[self.window contentView] superview] setProMode:proMode]; 87 | [self.window makeKeyAndOrderFront:self]; 88 | [[NSApplication sharedApplication] activateIgnoringOtherApps:YES]; 89 | } 90 | 91 | - (void)displaySubmenuForRow:(NSNumber *)numRow { 92 | int row = [numRow intValue]; 93 | 94 | if (mouseOverRow == row) { 95 | if (itemWithOpenSubmenu == nil) { 96 | JGMenuItem *item = [menuItems objectAtIndex:row]; 97 | 98 | itemWithOpenSubmenu = item; // Do it before so as to ensure main menu does not close 99 | 100 | NSRect rectOfSubmenuRow = [itemsTable rectOfRow:row]; 101 | NSRect windowConvert = [[self.window.contentView superview] convertRect:rectOfSubmenuRow fromView:itemsTable]; 102 | NSRect screenConvert = NSMakeRect(self.window.frame.origin.x + windowConvert.origin.x, self.window.frame.origin.y + windowConvert.origin.y, rectOfSubmenuRow.size.width, rectOfSubmenuRow.size.height); 103 | 104 | [[item submenu] setParentMenu:self]; 105 | [[item submenu] popUpSubmenuAtPoint:NSMakePoint(screenConvert.origin.x + self.window.frame.size.width, screenConvert.origin.y - 4) whichIsSide:0]; 106 | 107 | [itemsTable reloadData]; 108 | } 109 | } 110 | } 111 | 112 | #pragma mark Handling changes to the window 113 | 114 | - (void)windowDidBecomeKey:(NSNotification *)notification { 115 | isMovingBackToParent = NO; 116 | } 117 | 118 | - (void)windowDidResignKey:(NSNotification *)notification { 119 | if (itemWithOpenSubmenu != nil) 120 | return; 121 | else { 122 | NSLog(@"SELF window"); 123 | [self closeWindow]; 124 | } 125 | } 126 | 127 | - (void)closeWindow { 128 | if ([menuDelegate respondsToSelector:@selector(menuWillClose)]) 129 | [menuDelegate menuWillClose]; 130 | 131 | if (parentMenu != nil && !isMovingBackToParent) { 132 | // NSLog(@"close above menu"); 133 | [parentMenu closeWindow]; 134 | } 135 | 136 | timer = [[NSTimer scheduledTimerWithTimeInterval:0.05 target:self selector:@selector(fade:) userInfo:nil repeats:YES] retain]; 137 | [customStatusView setHighlighted:NO]; 138 | } 139 | 140 | - (void)fade:(NSTimer *)theTimer 141 | { 142 | if ([self.window alphaValue] > 0.0) { 143 | // If window is still partially opaque, reduce its opacity. 144 | [self.window setAlphaValue:[self.window alphaValue] - 0.3]; 145 | } else { 146 | // Otherwise, if window is completely transparent, destroy the timer and close the window. 147 | [timer invalidate]; 148 | [timer release]; 149 | timer = nil; 150 | 151 | // NSLog(@"called"); 152 | 153 | [self.window close]; 154 | 155 | // Make the window fully opaque again for next time. 156 | [self.window setAlphaValue:1.0]; 157 | } 158 | } 159 | 160 | #pragma mark Handling changes to menuItems and headerView 161 | 162 | - (NSArray *)menuItems { 163 | return menuItems; 164 | } 165 | 166 | - (void)setMenuItems:(NSArray *)items { 167 | menuItems = [items copy]; 168 | 169 | // Work out headerView sizing based on string size 170 | if (headerView == nil) { 171 | float width = 0; 172 | for (JGMenuItem *item in menuItems) { 173 | NSSize size = [item.title sizeWithAttributes:[NSDictionary dictionaryWithObject:[NSFont fontWithName: @"Lucida Grande" size: 13] forKey:NSFontAttributeName]]; 174 | int amountToAdd = 40; 175 | if (item.submenu != nil) 176 | amountToAdd += 15; 177 | if (size.width + amountToAdd > width) 178 | width = size.width + amountToAdd; 179 | } 180 | headerView = [[NSView alloc] initWithFrame:NSMakeRect(0, 0, width, 0)]; 181 | } 182 | 183 | [itemsTable reloadData]; 184 | [self loadHeights]; 185 | } 186 | 187 | - (NSView *)headerView { 188 | return headerView; 189 | } 190 | 191 | - (void)setHeaderView:(NSView *)view { 192 | headerView = view; 193 | [self loadHeights]; 194 | } 195 | 196 | #pragma mark Handling changes to dynamic properties to be relayed to status item view 197 | 198 | - (NSImage *)statusItemImage { 199 | return statusItemImage; 200 | } 201 | 202 | - (void)setStatusItemImage:(NSImage *)newImage 203 | { 204 | if(newImage != statusItemImage) 205 | { 206 | [statusItemImage release]; 207 | statusItemImage = [newImage copy]; 208 | [customStatusView setImage:statusItemImage]; 209 | } 210 | } 211 | 212 | - (NSImage *)statusItemAlternateImage { 213 | return statusItemAlternateImage; 214 | } 215 | 216 | - (void)setStatusItemAlternateImage:(NSImage *)newAltImage 217 | { 218 | if(newAltImage != statusItemAlternateImage) 219 | { 220 | [statusItemAlternateImage release]; 221 | statusItemAlternateImage = [newAltImage copy]; 222 | [customStatusView setAlternateImage:statusItemAlternateImage]; 223 | } 224 | } 225 | 226 | - (NSString *)statusItemTitle { 227 | return statusItemTitle; 228 | } 229 | 230 | - (void)setStatusItemTitle:(NSString *)newTitle 231 | { 232 | if(newTitle != statusItemTitle) 233 | { 234 | [statusItemTitle release]; 235 | statusItemTitle = [newTitle copy]; 236 | [customStatusView setTitle:statusItemTitle]; 237 | } 238 | } 239 | 240 | #pragma mark Handling the Status Item 241 | 242 | - (BOOL)isStatusItem { 243 | return isStatusItem; 244 | } 245 | 246 | - (void)setIsStatusItem:(BOOL)flag { 247 | isStatusItem = flag; 248 | if (flag == NO) { 249 | [[NSStatusBar systemStatusBar] removeStatusItem:statusItem]; 250 | [statusItem release]; 251 | statusItem = nil; 252 | [customStatusView release]; 253 | customStatusView = nil; 254 | } else { 255 | NSStatusBar *bar = [NSStatusBar systemStatusBar]; 256 | 257 | statusItem = [bar statusItemWithLength:NSVariableStatusItemLength]; 258 | [statusItem retain]; 259 | 260 | customStatusView = [[CustomStatusItemView alloc] initWithFrame:NSMakeRect(0, 0, 30, 20)]; 261 | [customStatusView setTarget:self]; 262 | [customStatusView setSelectingAction:@selector(statusItemSelected:)]; 263 | [customStatusView setDeselectingAction:@selector(statusItemDeselected:)]; 264 | [customStatusView setStatusItem:statusItem]; 265 | [statusItem setView:customStatusView]; 266 | } 267 | } 268 | 269 | - (BOOL)loadHeightsWithWindowOrigin:(NSPoint)point whichIsSubmenu:(BOOL)isSubmenu { 270 | NSRect newFrame = [[customStatusView window] frame]; 271 | 272 | // Work out the _headerView's (basically a container) frame from the actually headerView frame 273 | 274 | NSRect _headerViewOldFrame = _headerView.frame; 275 | _headerViewOldFrame.origin.x = 0; 276 | _headerViewOldFrame.origin.y = self.window.frame.size.height - headerView.frame.size.height; 277 | _headerViewOldFrame.size.height = headerView.frame.size.height; 278 | _headerViewOldFrame.size.width = headerView.frame.size.width; 279 | [_headerView setFrame:_headerViewOldFrame]; 280 | 281 | NSRect headerViewOldFrame = headerView.frame; 282 | headerViewOldFrame.origin.x = 0; 283 | headerViewOldFrame.origin.y = 0; 284 | [headerView setFrame:headerViewOldFrame]; 285 | 286 | // Add the headerView as a subview to the container 287 | 288 | [_headerView addSubview:headerView]; 289 | 290 | // Work out the height of the cells in the table view 291 | 292 | int sizeOfCellsInTableView = 0; 293 | 294 | // if ([menuItems count] != 0) { 295 | // sizeOfCellsInTableView = (20 * [menuItems count]) + 6; 296 | // } 297 | 298 | for (JGMenuItem *item in menuItems) { 299 | sizeOfCellsInTableView += [itemsTable rectOfRow:[menuItems indexOfObject:item]].size.height; 300 | } 301 | 302 | if ([menuItems count] != 0) 303 | sizeOfCellsInTableView = sizeOfCellsInTableView + 6; 304 | 305 | // Adjust what will be window frame 306 | 307 | newFrame.size.width = headerView.frame.size.width; 308 | newFrame.size.height = sizeOfCellsInTableView + headerView.frame.size.height; 309 | newFrame.origin.y = point.y; 310 | newFrame.origin.x = point.x; 311 | 312 | // Decide which side to draw the menu 313 | 314 | CGFloat xOrigin = newFrame.origin.x; 315 | 316 | BOOL whichSide = 0; // 0 = shown to the right, 1 = shown to the left 317 | NSRect screenRect = [[NSScreen mainScreen] frame]; 318 | 319 | if ((newFrame.origin.x + newFrame.size.width) > screenRect.size.width) 320 | whichSide = 1; 321 | 322 | NSLog(@"%i && %i && %i", whichSide, isSubmenu, parentMenu != nil); 323 | if (whichSide && isSubmenu && parentMenu != nil) { 324 | NSLog(@"is changing"); 325 | xOrigin = xOrigin - parentMenu.window.frame.size.width - newFrame.size.width; 326 | } 327 | 328 | newFrame.origin.x = xOrigin; 329 | 330 | // Set the windows frame 331 | 332 | [self.window setFrame:newFrame display:YES]; 333 | 334 | // Adjust Table view frame, has to be done after window frame change other wise there are some complications with autoresizing 335 | 336 | if ([menuItems count] != 0) { 337 | NSRect tableOldFrame = itemsTable.frame; 338 | tableOldFrame.origin.x = 0; 339 | tableOldFrame.origin.y = 0; 340 | tableOldFrame.size.height = sizeOfCellsInTableView; 341 | tableOldFrame.size.width = headerView.frame.size.width; 342 | tableOldFrame = NSIntegralRect(tableOldFrame); 343 | [itemsTable setFrame:tableOldFrame]; 344 | [[[itemsTable tableColumns] objectAtIndex:0] setWidth:tableOldFrame.size.width]; 345 | [[[itemsTable superview] superview] setFrame:NSMakeRect(tableOldFrame.origin.x, tableOldFrame.origin.y - 2, tableOldFrame.size.width, tableOldFrame.size.height)]; 346 | } 347 | 348 | return whichSide; 349 | } 350 | 351 | - (void)loadHeights { 352 | NSRect newFrame = [[customStatusView window] frame]; 353 | 354 | // Work out the _headerView's (basically a container) frame from the actually headerView frame 355 | 356 | NSRect _headerViewOldFrame = _headerView.frame; 357 | _headerViewOldFrame.origin.x = 0; 358 | _headerViewOldFrame.origin.y = self.window.frame.size.height - headerView.frame.size.height; 359 | _headerViewOldFrame.size.height = headerView.frame.size.height; 360 | _headerViewOldFrame.size.width = headerView.frame.size.width; 361 | [_headerView setFrame:_headerViewOldFrame]; 362 | 363 | NSRect headerViewOldFrame = headerView.frame; 364 | headerViewOldFrame.origin.x = 0; 365 | headerViewOldFrame.origin.y = 0; 366 | [headerView setFrame:headerViewOldFrame]; 367 | 368 | // Add the headerView as a subview to the container 369 | 370 | [_headerView addSubview:headerView]; 371 | 372 | // Work out the height of the cells in the table view 373 | 374 | int sizeOfCellsInTableView = 0; 375 | 376 | // if ([menuItems count] != 0) { 377 | // sizeOfCellsInTableView = (20 * [menuItems count]) + 6; 378 | // } 379 | 380 | for (JGMenuItem *item in menuItems) { 381 | sizeOfCellsInTableView += [itemsTable rectOfRow:[menuItems indexOfObject:item]].size.height; 382 | } 383 | 384 | if ([menuItems count] != 0) 385 | sizeOfCellsInTableView = sizeOfCellsInTableView + 6; 386 | 387 | // Adjust what will be window frame 388 | 389 | newFrame.size.width = headerView.frame.size.width; 390 | newFrame.size.height = sizeOfCellsInTableView + headerView.frame.size.height; 391 | newFrame.origin.y = newFrame.origin.y - (sizeOfCellsInTableView + headerView.frame.size.height); 392 | newFrame.origin.x = newFrame.origin.x; 393 | 394 | // Decide which side to draw the menu 395 | 396 | CGFloat xOrigin = newFrame.origin.x; 397 | 398 | BOOL whichSide = 0; // 0 = shown to the right, 1 = shown to the left 399 | NSRect screenRect = [[NSScreen mainScreen] frame]; 400 | NSRect statusItemRect = [[customStatusView window] frame]; 401 | 402 | if ((statusItemRect.origin.x + headerView.frame.size.width) > screenRect.size.width) 403 | whichSide = 1; 404 | 405 | if (whichSide) { 406 | xOrigin = xOrigin - self.window.frame.size.width + customStatusView.frame.size.width; 407 | } 408 | 409 | newFrame.origin.x = xOrigin; 410 | 411 | // Set the windows frame 412 | 413 | [self.window setFrame:newFrame display:YES]; 414 | 415 | // Adjust Table view frame, has to be done after window frame change other wise there are some complications with autoresizing 416 | 417 | if ([menuItems count] != 0) { 418 | NSRect tableOldFrame = itemsTable.frame; 419 | tableOldFrame.origin.x = 0; 420 | tableOldFrame.origin.y = 0; 421 | tableOldFrame.size.height = sizeOfCellsInTableView; 422 | tableOldFrame.size.width = headerView.frame.size.width; 423 | tableOldFrame = NSIntegralRect(tableOldFrame); 424 | [itemsTable setFrame:tableOldFrame]; 425 | [[[itemsTable tableColumns] objectAtIndex:0] setWidth:tableOldFrame.size.width]; 426 | [[[itemsTable superview] superview] setFrame:NSMakeRect(tableOldFrame.origin.x, tableOldFrame.origin.y - 2, tableOldFrame.size.width, tableOldFrame.size.height)]; 427 | } 428 | } 429 | 430 | - (void)statusItemDeselected:(id)sender { 431 | [self closeWindow]; 432 | } 433 | 434 | - (void)statusItemSelected:(id)sender { 435 | NSLog(@"selected"); 436 | 437 | NSMenu *fakeMenu = [[NSMenu alloc] init]; // Used to make sure another menu such as Spotlight will disapear when this is opened 438 | [statusItem popUpStatusItemMenu:fakeMenu]; 439 | 440 | if (timer) { // Window shouldn't be closing right now. Stop the timer. 441 | [timer invalidate]; 442 | [timer release]; 443 | timer = nil; 444 | [self.window setAlphaValue:1.0]; 445 | } 446 | 447 | if ([menuDelegate respondsToSelector:@selector(menuWillOpen)]) 448 | [menuDelegate menuWillOpen]; 449 | 450 | mouseOverRow = -1; 451 | isSelecting = NO; 452 | 453 | [self loadHeights]; 454 | [(RoundWindowFrameView *)[[self.window contentView] superview] setProMode:proMode]; 455 | [self.window makeKeyAndOrderFront:self]; 456 | [[NSApplication sharedApplication] activateIgnoringOtherApps:YES]; 457 | } 458 | 459 | #pragma mark TableDetectionDelegate 460 | 461 | - (void)flashHighlightForRowThenClose:(NSNumber *)row { 462 | mouseOverRow = -1; 463 | [itemsTable reloadData]; 464 | timer = [[NSTimer scheduledTimerWithTimeInterval:0.1 target:self selector:@selector(resetMouseOverRowToAndClose:) userInfo:row repeats:NO] retain]; 465 | } 466 | 467 | - (void)resetMouseOverRowToAndClose:(NSTimer *)sender { 468 | mouseOverRow = [[sender userInfo] intValue]; 469 | [itemsTable reloadData]; 470 | if ([menuDelegate respondsToSelector:@selector(shouldCloseMenuAfterSelectingRow:)]) { 471 | if ([menuDelegate shouldCloseMenuAfterSelectingRow:[[sender userInfo] intValue]]) { 472 | [timer invalidate]; 473 | [timer release]; 474 | timer = nil; 475 | [self closeWindow]; 476 | } 477 | } else { 478 | [timer invalidate]; 479 | [timer release]; 480 | timer = nil; 481 | [self closeWindow]; 482 | } 483 | } 484 | 485 | - (void)mouseMovedIntoLocation:(NSPoint)loc { 486 | [timer invalidate]; 487 | [timer release]; 488 | timer = nil; 489 | timeHovering = 0; 490 | 491 | timer = [[NSTimer scheduledTimerWithTimeInterval:0.1 target:self selector:@selector(upTime) userInfo:nil repeats:YES] retain]; 492 | 493 | mouseOverRow = [itemsTable rowAtPoint:[itemsTable convertPoint:loc fromView:nil]]; 494 | 495 | if (itemWithOpenSubmenu != nil && mouseOverRow != [menuItems indexOfObject:itemWithOpenSubmenu]) { 496 | itemWithOpenSubmenu = nil; 497 | } 498 | 499 | [itemsTable reloadData]; 500 | } 501 | 502 | - (void)mouseMovedOutOfViewToLoc:(NSPoint)loc { 503 | [timer invalidate]; 504 | [timer release]; 505 | timer = nil; 506 | timeHovering = 0; 507 | 508 | if (mouseOverRow != -1 && itemWithOpenSubmenu == nil) { 509 | mouseOverRow = -1; 510 | [itemsTable reloadData]; 511 | } 512 | 513 | NSPoint convertedLoc = NSMakePoint(self.window.frame.origin.x + loc.x, self.window.frame.origin.y + loc.y); 514 | 515 | // NSLog(@"parentMenuOrigin = %@", NSStringFromPoint([parentMenu window].frame.origin)); 516 | // NSLog(@"convertedLoc = %@", NSStringFromPoint(convertedLoc)); 517 | 518 | if (parentMenu != nil) { 519 | // i know i'm a submenu 520 | if (convertedLoc.x > parentMenu.window.frame.origin.x && convertedLoc.y > parentMenu.window.frame.origin.y && convertedLoc.x < parentMenu.window.frame.origin.x + parentMenu.window.frame.size.width && convertedLoc.y < parentMenu.window.frame.origin.y + parentMenu.window.frame.size.height) { 521 | int mouseAtLoc = [parentMenu.itemsTable rowAtPoint:[parentMenu.itemsTable convertPoint:[parentMenu.window convertScreenToBase:convertedLoc] fromView:nil]]; 522 | if (mouseAtLoc == parentMenu.mouseOverRow) 523 | return; 524 | 525 | isMovingBackToParent = YES; 526 | [parentMenu.window makeKeyAndOrderFront:self]; 527 | } 528 | } else { 529 | // i may be the main menu but i still need to respect my little brother and make him active if the mouse heads towards him. i'm nice aren't i? 530 | if (convertedLoc.x > itemWithOpenSubmenu.submenu.window.frame.origin.x && convertedLoc.y > itemWithOpenSubmenu.submenu.window.frame.origin.y && convertedLoc.x < itemWithOpenSubmenu.submenu.window.frame.origin.x + itemWithOpenSubmenu.submenu.window.frame.size.width && convertedLoc.y < itemWithOpenSubmenu.submenu.window.frame.origin.y + itemWithOpenSubmenu.submenu.window.frame.size.height) { 531 | [itemWithOpenSubmenu.submenu.window makeKeyAndOrderFront:self]; 532 | } 533 | } 534 | } 535 | 536 | - (void)mouseDownAtLocation:(NSPoint)loc { 537 | int row = [itemsTable rowAtPoint:[itemsTable convertPoint:loc fromView:nil]]; 538 | if (row >= 0) { 539 | isSelecting = YES; 540 | [self flashHighlightForRowThenClose:[NSNumber numberWithInt:row]]; 541 | JGMenuItem *selectedItem = [menuItems objectAtIndex:row]; 542 | [[selectedItem target] performSelector:[selectedItem action] withObject:selectedItem]; 543 | } 544 | } 545 | 546 | - (void)upTime { 547 | timeHovering += 0.1; 548 | 549 | if (mouseOverRow != -1 && [[menuItems objectAtIndex:mouseOverRow] submenu] != nil && itemWithOpenSubmenu == nil && timeHovering >= 0.1) { 550 | // [self performSelector:@selector(displaySubmenuForRow:) withObject:[NSNumber numberWithInt:mouseOverRow] afterDelay:0.1]; 551 | [self displaySubmenuForRow:[NSNumber numberWithInt:mouseOverRow]]; 552 | } 553 | } 554 | 555 | - (void)escapeKeyPressed { 556 | [self closeWindow]; 557 | } 558 | 559 | #pragma mark NSTableViewDataSource 560 | 561 | - (NSInteger)numberOfRowsInTableView:(NSTableView *)aTableView { 562 | return [menuItems count]; 563 | } 564 | 565 | - (id)tableView:(NSTableView *)aTableView objectValueForTableColumn:(NSTableColumn *)aTableColumn row:(NSInteger)rowIndex { 566 | if ([[[menuItems objectAtIndex:rowIndex] title] isEqualToString:@"--[SEPERATOR]--"]) 567 | return @""; 568 | return [[menuItems objectAtIndex:rowIndex] title]; 569 | } 570 | 571 | #pragma mark NSTableViewDelegate 572 | 573 | - (CGFloat)tableView:(NSTableView *)tableView heightOfRow:(NSInteger)rowIndex { 574 | if ([[[menuItems objectAtIndex:rowIndex] title] isEqualToString:@"--[SEPERATOR]--"]) 575 | return 10; 576 | if ([[menuItems objectAtIndex:rowIndex] image] != nil) 577 | if ([[menuItems objectAtIndex:rowIndex] image].size.height + 2 >= 18) 578 | return [[menuItems objectAtIndex:rowIndex] image].size.height + 2; // 2 for padding specificially got 16*16 images 579 | return 18; 580 | } 581 | 582 | - (BOOL)tableView:(NSTableView *)aTableView shouldSelectRow:(NSInteger)rowIndex { 583 | return NO; 584 | } 585 | 586 | - (void)tableView:(NSTableView *)aTableView willDisplayCell:(id)aCell forTableColumn:(NSTableColumn *)aTableColumn row:(int)rowIndex 587 | { 588 | //NSLog(@"row index %i. time hovering %f", rowIndex, timeHovering); 589 | 590 | if (timeHovering > 1 && rowIndex == mouseOverRow && isSelecting == NO) { 591 | // NSLog(@"RETURN AND STOP --------------------------------------------------------"); 592 | return; 593 | } 594 | 595 | //NSLog(@"willdisplaycell"); 596 | 597 | JGMenuItem *item = [menuItems objectAtIndex:rowIndex]; 598 | 599 | if (item.enabled == NO) { 600 | [aCell setTextColor:[NSColor colorWithDeviceRed:0.502 green:0.502 blue:0.565 alpha:1.000]]; 601 | return; 602 | } 603 | 604 | // Draw seperator 605 | 606 | if ([[item title] isEqualToString:@"--[SEPERATOR]--"]) { 607 | NSRect rowRect = [aTableView rectOfRow:rowIndex]; 608 | rowRect.origin.x = 1; 609 | rowRect.origin.y += (int) (NSHeight(rowRect)/2); 610 | rowRect.size.width = rowRect.size.width - 2; 611 | rowRect.size.height = 1.0; 612 | [[NSColor colorWithDeviceWhite:0.871 alpha:1.000] set]; 613 | if (proMode) 614 | [[NSColor colorWithDeviceWhite:0.3 alpha:1.000] set]; 615 | NSRectFill(rowRect); 616 | return; 617 | } 618 | 619 | // Draw highlight 620 | 621 | if (mouseOverRow == rowIndex && ([aTableView selectedRow] != rowIndex) && item.enabled == YES) { 622 | if ([aTableView lockFocusIfCanDraw]) { 623 | NSRect rowRect = [aTableView rectOfRow:rowIndex]; 624 | //NSRect columnRect = [aTableView rectOfColumn:[[aTableView tableColumns] indexOfObject:aTableColumn]]; 625 | 626 | if (!proMode) { 627 | NSGradient* aGradient = 628 | [[[NSGradient alloc] 629 | initWithColorsAndLocations: 630 | [NSColor colorWithDeviceRed:0.416 green:0.529 blue:0.961 alpha:1.000], (CGFloat)0.0, 631 | [NSColor colorWithDeviceRed:0.212 green:0.365 blue:0.949 alpha:1.000], (CGFloat)1.0, 632 | nil] 633 | autorelease]; 634 | NSRect rectToDraw = rowRect; 635 | rectToDraw.size.height = rowRect.size.height - 1; 636 | rectToDraw.origin.y = rectToDraw.origin.y + 1; 637 | [aGradient drawInRect:rectToDraw angle:90]; 638 | 639 | NSRect upperLineRect = [aTableView rectOfRow:rowIndex]; 640 | upperLineRect.origin.y = upperLineRect.origin.y + 1; 641 | upperLineRect.size.height = 1.0; 642 | [[NSColor colorWithDeviceRed:0.376 green:0.498 blue:0.925 alpha:1.000] set]; 643 | NSRectFill(upperLineRect); 644 | 645 | NSRect lowerLineRect = [aTableView rectOfRow:rowIndex]; 646 | lowerLineRect.origin.y = NSMaxY(lowerLineRect) - 1; 647 | lowerLineRect.size.height = 1.0; 648 | [[NSColor colorWithDeviceRed:0.169 green:0.318 blue:0.914 alpha:1.000] set]; 649 | NSRectFill(lowerLineRect); 650 | 651 | [aTableView unlockFocus]; 652 | 653 | [aCell setTextColor:[NSColor selectedMenuItemTextColor]]; 654 | } else { 655 | NSGradient* aGradient = 656 | [[[NSGradient alloc] 657 | initWithColorsAndLocations: 658 | [NSColor colorWithDeviceWhite:0.925 alpha:1.000], (CGFloat)0.0, 659 | [NSColor colorWithDeviceWhite:0.753 alpha:1.000], (CGFloat)1.0, 660 | nil] 661 | autorelease]; 662 | NSRect rectToDraw = rowRect; 663 | rectToDraw.size.height = rowRect.size.height - 1; 664 | rectToDraw.origin.y = rectToDraw.origin.y + 1; 665 | [aGradient drawInRect:rectToDraw angle:90]; 666 | 667 | [aTableView unlockFocus]; 668 | 669 | [aCell setTextColor:[NSColor blackColor]]; 670 | } 671 | } 672 | } else if (item.enabled == YES) { 673 | [aCell setTextColor:[NSColor blackColor]]; 674 | 675 | if (proMode) 676 | [aCell setTextColor:[NSColor whiteColor]]; 677 | } 678 | 679 | // Draw Disclosure Indicator for items with submenu 680 | 681 | if (item.submenu != nil && mouseOverRow != rowIndex) { 682 | // Not highlighted 683 | NSRect rowRect = [aTableView rectOfRow:rowIndex]; 684 | CGPoint originToDrawFrom = CGPointMake(rowRect.origin.x + headerView.frame.size.width - 20, NSMidY(rowRect) - 5); // Bottom left origin. Uses headerView width because rowRect width does not stay constant 685 | CGContextRef context = [[NSGraphicsContext currentContext] graphicsPort]; 686 | 687 | CGContextSetRGBStrokeColor(context, 0.3, 0.6, 1.0, 1.0); 688 | CGContextSetRGBFillColor(context, 0.3, 0.6, 1.0, 1.0); 689 | CGContextSetLineWidth(context, 2.0); 690 | CGContextMoveToPoint(context, 10.0, 30.0); 691 | 692 | CGPoint addLines[] = 693 | { 694 | CGPointMake(originToDrawFrom.x, originToDrawFrom.y), 695 | CGPointMake(originToDrawFrom.x, originToDrawFrom.y + 10.0), 696 | CGPointMake(originToDrawFrom.x + 1.0, originToDrawFrom.y + 10.0), 697 | CGPointMake(originToDrawFrom.x + 8.0, originToDrawFrom.y + 5.0), 698 | CGPointMake(originToDrawFrom.x + 1.0, originToDrawFrom.y), 699 | CGPointMake(originToDrawFrom.x, originToDrawFrom.y), 700 | }; 701 | CGContextAddLines(context, addLines, sizeof(addLines)/sizeof(addLines[0])); 702 | 703 | if (!proMode) 704 | [[NSColor colorWithDeviceRed:0.424 green:0.424 blue:0.427 alpha:1.000] setFill]; 705 | else 706 | [[NSColor colorWithDeviceWhite:0.761 alpha:1.000] setFill]; 707 | 708 | CGContextDrawPath(context, kCGPathFill); 709 | } else if (item.submenu != nil && mouseOverRow == rowIndex) { 710 | // Highlighted 711 | NSRect rowRect = [aTableView rectOfRow:rowIndex]; 712 | CGPoint originToDrawFrom = CGPointMake(rowRect.origin.x + headerView.frame.size.width - 20, NSMidY(rowRect) - 5); // Bottom left origin. Uses headerView width because rowRect width does not stay constant 713 | 714 | CGContextRef context = [[NSGraphicsContext currentContext] graphicsPort]; 715 | 716 | CGContextSetRGBStrokeColor(context, 0.3, 0.6, 1.0, 1.0); 717 | CGContextSetRGBFillColor(context, 0.3, 0.6, 1.0, 1.0); 718 | CGContextSetLineWidth(context, 2.0); 719 | CGContextMoveToPoint(context, 10.0, 30.0); 720 | 721 | CGPoint addLines[] = 722 | { 723 | CGPointMake(originToDrawFrom.x, originToDrawFrom.y), 724 | CGPointMake(originToDrawFrom.x, originToDrawFrom.y + 10.0), 725 | CGPointMake(originToDrawFrom.x + 1.0, originToDrawFrom.y + 10.0), 726 | CGPointMake(originToDrawFrom.x + 8.0, originToDrawFrom.y + 5.0), 727 | CGPointMake(originToDrawFrom.x + 1.0, originToDrawFrom.y), 728 | CGPointMake(originToDrawFrom.x, originToDrawFrom.y), 729 | }; 730 | CGContextAddLines(context, addLines, sizeof(addLines)/sizeof(addLines[0])); 731 | 732 | if (!proMode) 733 | [[NSColor whiteColor] setFill]; 734 | else 735 | [[NSColor colorWithDeviceWhite:0.255 alpha:1.000] setFill]; 736 | 737 | CGContextDrawPath(context, kCGPathFill); 738 | } 739 | 740 | // Now Draw Image 741 | 742 | NSImage *image = [[menuItems objectAtIndex:rowIndex] image]; 743 | 744 | if (image) { 745 | NSRect rowRect = [aTableView rectOfRow:rowIndex]; 746 | NSRect centeredRect = NSMakeRect(0, 0, [image size].width, [image size].height); 747 | centeredRect.origin.x = 17; 748 | centeredRect.origin.y = NSMidY(rowRect) - (([image size].height / 2) - 1); 749 | centeredRect = NSIntegralRect(centeredRect); 750 | [image setFlipped:YES]; 751 | [image drawAtPoint:centeredRect.origin fromRect:NSZeroRect operation:NSCompositeSourceOver fraction:1.0]; 752 | 753 | // Pad the text accross further 754 | [(PaddedTextFieldCell *)aCell setLeftMargin:15 + image.size.width + 3]; 755 | } else { 756 | [(PaddedTextFieldCell *)aCell setLeftMargin:15]; 757 | } 758 | } 759 | 760 | @end 761 | -------------------------------------------------------------------------------- /Window/NSBezierPath+PXRoundedRectangleAdditions.h: -------------------------------------------------------------------------------- 1 | // 2 | // NSBezierPath+PXRoundedRectangleAdditions.h 3 | // Pixen 4 | // 5 | // Created by Andy Matuschak on 7/3/05. 6 | // Copyright 2005 Open Sword Group. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | typedef enum _OSCornerTypes 12 | { 13 | OSTopLeftCorner = 1, 14 | OSBottomLeftCorner = 2, 15 | OSTopRightCorner = 4, 16 | OSBottomRightCorner = 8 17 | } OSCornerType; 18 | 19 | @interface NSBezierPath(PXRoundedRectangle) 20 | + (NSBezierPath *) bezierPathWithRoundedRect: (NSRect)aRect cornerRadius: (float)radius; 21 | + (NSBezierPath *) bezierPathWithRoundedRect: (NSRect)aRect cornerRadius: (float)radius inCorners:(OSCornerType)corners; 22 | @end 23 | -------------------------------------------------------------------------------- /Window/NSBezierPath+PXRoundedRectangleAdditions.m: -------------------------------------------------------------------------------- 1 | // 2 | // NSBezierPath+PXRoundedRectangleAdditions.m 3 | // Pixen 4 | // 5 | // Created by Andy Matuschak on 7/3/05. 6 | // Copyright 2005 Open Sword Group. All rights reserved. 7 | // 8 | 9 | #import "NSBezierPath+PXRoundedRectangleAdditions.h" 10 | 11 | 12 | @implementation NSBezierPath(RoundedRectangle) 13 | 14 | + (NSBezierPath *) bezierPathWithRoundedRect: (NSRect)aRect cornerRadius: (float)radius inCorners:(OSCornerType)corners 15 | { 16 | NSBezierPath* path = [self bezierPath]; 17 | radius = MIN(radius, 0.5f * MIN(NSWidth(aRect), NSHeight(aRect))); 18 | NSRect rect = NSInsetRect(aRect, radius, radius); 19 | 20 | if (corners & OSBottomLeftCorner) 21 | { 22 | [path appendBezierPathWithArcWithCenter:NSMakePoint(NSMinX(rect), NSMinY(rect)) radius:radius startAngle:180.0 endAngle:270.0]; 23 | } 24 | else 25 | { 26 | NSPoint cornerPoint = NSMakePoint(NSMinX(aRect), NSMinY(aRect)); 27 | [path appendBezierPathWithPoints:&cornerPoint count:1]; 28 | } 29 | 30 | if (corners & OSBottomRightCorner) 31 | { 32 | [path appendBezierPathWithArcWithCenter:NSMakePoint(NSMaxX(rect), NSMinY(rect)) radius:radius startAngle:270.0 endAngle:360.0]; 33 | } 34 | else 35 | { 36 | NSPoint cornerPoint = NSMakePoint(NSMaxX(aRect), NSMinY(aRect)); 37 | [path appendBezierPathWithPoints:&cornerPoint count:1]; 38 | } 39 | 40 | if (corners & OSTopRightCorner) 41 | { 42 | [path appendBezierPathWithArcWithCenter:NSMakePoint(NSMaxX(rect), NSMaxY(rect)) radius:radius startAngle: 0.0 endAngle: 90.0]; 43 | } 44 | else 45 | { 46 | NSPoint cornerPoint = NSMakePoint(NSMaxX(aRect), NSMaxY(aRect)); 47 | [path appendBezierPathWithPoints:&cornerPoint count:1]; 48 | } 49 | 50 | if (corners & OSTopLeftCorner) 51 | { 52 | [path appendBezierPathWithArcWithCenter:NSMakePoint(NSMinX(rect), NSMaxY(rect)) radius:radius startAngle: 90.0 endAngle:180.0]; 53 | } 54 | else 55 | { 56 | NSPoint cornerPoint = NSMakePoint(NSMinX(aRect), NSMaxY(aRect)); 57 | [path appendBezierPathWithPoints:&cornerPoint count:1]; 58 | } 59 | 60 | [path closePath]; 61 | return path; 62 | } 63 | 64 | + (NSBezierPath*)bezierPathWithRoundedRect:(NSRect)aRect cornerRadius:(float)radius 65 | { 66 | return [NSBezierPath bezierPathWithRoundedRect:aRect cornerRadius:radius inCorners:OSTopLeftCorner | OSTopRightCorner | OSBottomLeftCorner | OSBottomRightCorner]; 67 | } 68 | 69 | @end 70 | -------------------------------------------------------------------------------- /Window/RoundWindowFrameView.h: -------------------------------------------------------------------------------- 1 | // 2 | // RoundWindowFrameView.h 3 | // RoundWindow 4 | // 5 | // Created by Matt Gallagher on 12/12/08. 6 | // Copyright 2008 Matt Gallagher. All rights reserved. 7 | // 8 | // Permission is given to use this source code file without charge in any 9 | // project, commercial or otherwise, entirely at your risk, with the condition 10 | // that any redistribution (in part or whole) of source code must retain 11 | // this copyright and permission notice. Attribution in compiled projects is 12 | // appreciated but not required. 13 | // 14 | 15 | #import 16 | 17 | @protocol TableDetectionDelegate 18 | 19 | - (void)mouseMovedIntoLocation:(NSPoint)loc; 20 | - (void)mouseMovedOutOfViewToLoc:(NSPoint)loc; 21 | - (void)mouseDownAtLocation:(NSPoint)loc; 22 | - (void)escapeKeyPressed; 23 | 24 | @end 25 | 26 | #import "JGMenuWindowController.h" 27 | 28 | @interface RoundWindowFrameView : NSView 29 | { 30 | id tableDelegate; 31 | BOOL allCornersRounded; 32 | BOOL proMode; 33 | 34 | BOOL _isSubmenu; 35 | int _submenuSide; 36 | } 37 | 38 | @property (nonatomic, retain) id tableDelegate; 39 | @property (nonatomic, assign) BOOL allCornersRounded; 40 | @property (nonatomic, assign) BOOL proMode; 41 | 42 | - (void)setIsSubmenuOnSide:(int)side; // 0 == left. 1 == right. 43 | 44 | @end 45 | -------------------------------------------------------------------------------- /Window/RoundWindowFrameView.m: -------------------------------------------------------------------------------- 1 | // 2 | // RoundWindowFrameView.m 3 | // RoundWindow 4 | // 5 | // Created by Matt Gallagher on 12/12/08. 6 | // Copyright 2008 Matt Gallagher. All rights reserved. 7 | // 8 | // Permission is given to use this source code file without charge in any 9 | // project, commercial or otherwise, entirely at your risk, with the condition 10 | // that any redistribution (in part or whole) of source code must retain 11 | // this copyright and permission notice. Attribution in compiled projects is 12 | // appreciated but not required. 13 | // 14 | 15 | #import "RoundWindowFrameView.h" 16 | #import "NSBezierPath+PXRoundedRectangleAdditions.h" 17 | 18 | @implementation RoundWindowFrameView 19 | @synthesize tableDelegate; 20 | @dynamic allCornersRounded, proMode; 21 | 22 | // 23 | // drawRect: 24 | // 25 | // Draws the frame of the window. 26 | // 27 | - (void)drawRect:(NSRect)rect 28 | { 29 | [[NSColor clearColor] set]; 30 | NSRectFill(rect); 31 | 32 | if (proMode == NO) { 33 | NSBezierPath *path; 34 | 35 | if (allCornersRounded) 36 | path = [NSBezierPath bezierPathWithRoundedRect:[self bounds] cornerRadius:5]; 37 | else if (_isSubmenu && _submenuSide == 0) 38 | path = [NSBezierPath bezierPathWithRoundedRect:[self bounds] cornerRadius:5 inCorners:OSBottomLeftCorner | OSBottomRightCorner | OSTopLeftCorner]; 39 | else if (_isSubmenu && _submenuSide == 1) 40 | path = [NSBezierPath bezierPathWithRoundedRect:[self bounds] cornerRadius:5 inCorners:OSBottomLeftCorner | OSBottomRightCorner | OSTopRightCorner]; 41 | else 42 | path = [NSBezierPath bezierPathWithRoundedRect:[self bounds] cornerRadius:5 inCorners:OSBottomLeftCorner | OSBottomRightCorner]; 43 | 44 | 45 | NSGradient* aGradient = [[[NSGradient alloc] initWithColorsAndLocations: 46 | [NSColor colorWithDeviceWhite:1 alpha:0.97], (CGFloat)0.0, 47 | [NSColor colorWithDeviceWhite:1 alpha:0.97], (CGFloat)1.0, 48 | nil] autorelease]; 49 | [aGradient drawInBezierPath:path angle:90]; 50 | } else { 51 | NSBezierPath *path; 52 | 53 | if (allCornersRounded) 54 | path = [NSBezierPath bezierPathWithRoundedRect:[self bounds] cornerRadius:5]; 55 | else if (_isSubmenu && _submenuSide == 0) 56 | path = [NSBezierPath bezierPathWithRoundedRect:[self bounds] cornerRadius:5 inCorners:OSBottomLeftCorner | OSBottomRightCorner | OSTopLeftCorner]; 57 | else if (_isSubmenu && _submenuSide == 1) 58 | path = [NSBezierPath bezierPathWithRoundedRect:[self bounds] cornerRadius:5 inCorners:OSBottomLeftCorner | OSBottomRightCorner | OSTopRightCorner]; 59 | else 60 | path = [NSBezierPath bezierPathWithRoundedRect:[self bounds] cornerRadius:5 inCorners:OSBottomLeftCorner | OSBottomRightCorner]; 61 | 62 | NSGradient* aGradient = [[[NSGradient alloc] initWithColorsAndLocations: 63 | [NSColor colorWithDeviceWhite:0 alpha:0.97], (CGFloat)0.0, 64 | [NSColor colorWithDeviceWhite:0 alpha:0.97], (CGFloat)1.0, 65 | nil] autorelease]; 66 | [aGradient drawInBezierPath:path angle:90]; 67 | } 68 | } 69 | 70 | #pragma mark Dynamics 71 | 72 | - (BOOL)allCornersRounded { 73 | return allCornersRounded; 74 | } 75 | 76 | - (void)setAllCornersRounded:(BOOL)flag { 77 | allCornersRounded = flag; 78 | [self setNeedsDisplay:YES]; 79 | } 80 | 81 | - (void)setIsSubmenuOnSide:(int)side { 82 | _isSubmenu = YES; 83 | _submenuSide = side; 84 | [self setNeedsDisplay:YES]; 85 | } 86 | 87 | - (BOOL)proMode { 88 | return proMode; 89 | } 90 | 91 | - (void)setProMode:(BOOL)flag { 92 | proMode = flag; 93 | [self setNeedsDisplay:YES]; 94 | } 95 | 96 | #pragma mark Events 97 | 98 | - (void)mouseMoved:(NSEvent*)theEvent 99 | { 100 | NSPoint location = [theEvent locationInWindow]; 101 | 102 | if (location.x > 0 && location.y > 0 && location.x < self.frame.size.width && location.y < self.frame.size.height) { 103 | if ([tableDelegate respondsToSelector:@selector(mouseMovedIntoLocation:)]) 104 | [tableDelegate mouseMovedIntoLocation:location]; 105 | } else { 106 | if ([tableDelegate respondsToSelector:@selector(mouseMovedOutOfViewToLoc:)]) 107 | [tableDelegate mouseMovedOutOfViewToLoc:location]; 108 | } 109 | } 110 | 111 | - (void)mouseDownInTableViewWithEvent:(NSEvent *)event { 112 | NSPoint location = [event locationInWindow]; 113 | 114 | if (location.x > 0 && location.y > 0) { 115 | if ([tableDelegate respondsToSelector:@selector(mouseDownAtLocation:)]) 116 | [tableDelegate mouseDownAtLocation:location]; 117 | } 118 | } 119 | 120 | - (void)keyUp:(NSEvent *)event { 121 | NSString *chars = [event characters]; 122 | unichar character = [chars characterAtIndex: 0]; 123 | 124 | if (character == 27) { 125 | if ([tableDelegate respondsToSelector:@selector(escapeKeyPressed)]) 126 | [tableDelegate escapeKeyPressed]; 127 | } 128 | 129 | [super keyUp:event]; 130 | } 131 | 132 | @end 133 | -------------------------------------------------------------------------------- /img.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/SquaredTiki/JGMenuWindow/34b583bf9875915da8a3442e27cf880b5bd283f5/img.png -------------------------------------------------------------------------------- /main.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // StatusItem 4 | // 5 | // Created by Joshua Garnham on 07/03/2011. 6 | // Copyright 2011 __MyCompanyName__. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | int main(int argc, char *argv[]) 12 | { 13 | return NSApplicationMain(argc, (const char **) argv); 14 | } 15 | --------------------------------------------------------------------------------