232 lines
8.1 KiB
Objective-C
232 lines
8.1 KiB
Objective-C
#import <Cocoa/Cocoa.h>
|
|
#import <Carbon/Carbon.h>
|
|
#import <LuaSkin/LuaSkin.h>
|
|
|
|
#define USERDATA_TAG "hs.hints.hint"
|
|
|
|
#define get_screen_arg(L, idx) (__bridge NSScreen*)*((void**)luaL_checkudata(L, idx, "hs.screen"))
|
|
#define get_hint_arg(L, idx) (__bridge HintWindow*)*((void**)luaL_checkudata(L, idx, USERDATA_TAG))
|
|
|
|
@interface HintView : NSView {
|
|
@private
|
|
NSString *text;
|
|
NSImage *icon;
|
|
NSSize textSize;
|
|
}
|
|
|
|
+ (void)initCache:(NSString*)fontName fontSize:(CGFloat)fontSize iconAlpha:(CGFloat)iconAlpha;
|
|
- (id)initWithFrame:(NSRect)frame fontName:(NSString*)fontName fontSize:(CGFloat)fontSize iconAlpha:(CGFloat)iconAlpha;
|
|
- (void)setIconFromBundleID:(NSString*)appRef;
|
|
|
|
@property (strong, nonatomic) NSString *text;
|
|
@property (strong, nonatomic) NSImage *icon;
|
|
|
|
@end
|
|
|
|
@implementation HintView
|
|
|
|
@synthesize text,icon;
|
|
|
|
static const float hintHeight = 75.0;
|
|
|
|
static NSColor *hintBackgroundColor = nil;
|
|
static NSColor *hintFontColor = nil;
|
|
static NSFont *hintFont = nil;
|
|
static NSRect iconFrame;
|
|
static NSDictionary *hintTextAttributes;
|
|
static float hintIconAlpha = 0.95;
|
|
|
|
+ (void)initCache:(NSString*)fontName fontSize:(CGFloat)fontSize iconAlpha:(CGFloat)iconAlpha {
|
|
iconFrame = NSMakeRect(0, 0, hintHeight, hintHeight);
|
|
hintBackgroundColor = [NSColor colorWithSRGBRed:0.0 green:0.0 blue:0.0 alpha:0.65];
|
|
hintFontColor = [NSColor whiteColor];
|
|
if (fontName) {
|
|
hintFont = [NSFont fontWithName:fontName size:fontSize];
|
|
} else {
|
|
hintFont = [NSFont systemFontOfSize:(fontSize > 0.0 ? fontSize : 25.0)];
|
|
}
|
|
hintIconAlpha = iconAlpha;
|
|
hintTextAttributes = [NSDictionary dictionaryWithObjectsAndKeys:hintFont,
|
|
NSFontAttributeName,
|
|
hintFontColor,
|
|
NSForegroundColorAttributeName, nil];
|
|
}
|
|
|
|
- (id)initWithFrame:(NSRect)frame fontName:(NSString*)fontName fontSize:(CGFloat)fontSize iconAlpha:(CGFloat)iconAlpha {
|
|
self = [super initWithFrame:frame];
|
|
if (self) {
|
|
[self setWantsLayer:YES];
|
|
[self setIcon:nil];
|
|
[HintView initCache:fontName fontSize:fontSize iconAlpha:iconAlpha];
|
|
}
|
|
return self;
|
|
}
|
|
|
|
- (void)setIconFromBundleID:(NSString*)appBundle {
|
|
NSString *path = [[NSWorkspace sharedWorkspace] absolutePathForAppBundleWithIdentifier:appBundle];
|
|
NSImage *theIcon = [[NSWorkspace sharedWorkspace] iconForFile:path];
|
|
[self setIcon:theIcon];
|
|
}
|
|
|
|
- (void)drawCenteredText:(NSString *)string bounds:(NSRect)rect attributes:(NSDictionary *)attributes {
|
|
NSPoint origin = NSMakePoint(rect.origin.x + (hintHeight/4) + 10,
|
|
rect.origin.y + (hintHeight - textSize.height) / 2);
|
|
[string drawAtPoint:origin withAttributes:attributes];
|
|
}
|
|
|
|
- (void)setText:(NSString *)newText {
|
|
text = newText;
|
|
textSize = [text sizeWithAttributes:hintTextAttributes];
|
|
// Might need to resize if text is long
|
|
CGFloat newWidth = textSize.width + hintHeight/2 + 20;
|
|
if(newWidth > 100) {
|
|
self.frame = NSMakeRect(self.frame.origin.x, self.frame.origin.y, newWidth, hintHeight);
|
|
NSRect newWinFrame = self.window.frame;
|
|
newWinFrame.size.width = newWidth;
|
|
[[self window] setFrame:newWinFrame display:YES];
|
|
}
|
|
}
|
|
|
|
- (void)drawRect:(NSRect __unused)dirtyRect {
|
|
[[NSGraphicsContext currentContext] saveGraphicsState];
|
|
[[NSGraphicsContext currentContext] setShouldAntialias:YES];
|
|
|
|
if (icon != nil) {
|
|
[icon drawInRect:iconFrame fromRect:NSZeroRect operation:NSCompositingOperationSourceOver fraction:hintIconAlpha];
|
|
}
|
|
|
|
// get label info for sizing
|
|
|
|
// draw the rounded rect
|
|
[hintBackgroundColor set];
|
|
float cornerSize = 10;
|
|
NSBezierPath *path = [NSBezierPath bezierPathWithRoundedRect:
|
|
CGRectMake(self.bounds.origin.x + (hintHeight / 4),
|
|
self.bounds.origin.y + (hintHeight / 4),
|
|
20 + textSize.width, hintHeight / 2)
|
|
xRadius:cornerSize yRadius:cornerSize];
|
|
[path fill];
|
|
|
|
// draw hint letter
|
|
[self drawCenteredText:text
|
|
bounds:self.bounds
|
|
attributes:hintTextAttributes];
|
|
[[NSGraphicsContext currentContext] restoreGraphicsState];
|
|
}
|
|
|
|
@end
|
|
|
|
@interface HintWindow : NSWindow
|
|
- (HintWindow*)initWithPoint:(CGPoint)pt text:(NSString*)txt
|
|
forApp:(NSString*)bundle onScreen:(NSScreen*)screen fontName:(NSString*)fontName fontSize:(CGFloat)fontSize iconAlpha:(CGFloat)iconAlpha;
|
|
@end
|
|
|
|
@implementation HintWindow
|
|
|
|
- (HintWindow*)initWithPoint:(CGPoint)pt text:(NSString*)txt
|
|
forApp:(NSString*)bundle onScreen:(NSScreen*)screen fontName:(NSString*)fontName fontSize:(CGFloat)fontSize iconAlpha:(CGFloat)iconAlpha {
|
|
CGFloat height = 75;
|
|
CGRect frame = NSMakeRect(pt.x - (height/2.0),
|
|
screen.frame.size.height - pt.y - (height/2.0), 100, 75);
|
|
self = [super initWithContentRect:frame
|
|
styleMask:NSWindowStyleMaskBorderless
|
|
backing:NSBackingStoreBuffered
|
|
defer:NO
|
|
screen:screen];
|
|
if (self) {
|
|
[self setOpaque:NO];
|
|
[self setBackgroundColor:[NSColor colorWithDeviceRed:0.0 green:0.0 blue:0.0 alpha:0.0]];
|
|
[self makeKeyAndOrderFront:NSApp];
|
|
[self setLevel:(NSScreenSaverWindowLevel - 1)];
|
|
HintView *label = [[HintView alloc] initWithFrame:frame fontName:fontName fontSize:fontSize iconAlpha:iconAlpha];
|
|
[self setContentView:label];
|
|
[label setIconFromBundleID:bundle];
|
|
[label setText:txt];
|
|
}
|
|
return self;
|
|
}
|
|
|
|
- (BOOL)canBecomeKeyWindow {
|
|
return YES;
|
|
}
|
|
@end
|
|
|
|
static int hint_close(lua_State* L) {
|
|
HintWindow* hint = get_hint_arg(L, 1);
|
|
[hint close];
|
|
hint = nil;
|
|
lua_pushnil(L);
|
|
lua_setmetatable(L, -2);
|
|
return 0;
|
|
}
|
|
|
|
static int hint_eq(lua_State* L) {
|
|
HintWindow* screenA = get_hint_arg(L, 1);
|
|
HintWindow* screenB = get_hint_arg(L, 2);
|
|
lua_pushboolean(L, screenA == screenB);
|
|
return 1;
|
|
}
|
|
|
|
void new_hint(lua_State* L, HintWindow* screen) {
|
|
void** hintptr = lua_newuserdata(L, sizeof(HintWindow**));
|
|
*hintptr = (__bridge_retained void*)screen;
|
|
|
|
luaL_getmetatable(L, USERDATA_TAG);
|
|
lua_setmetatable(L, -2);
|
|
}
|
|
|
|
static int hints_test(lua_State* L) {
|
|
HintWindow *win = [[HintWindow alloc] initWithPoint:NSMakePoint(1000, 200) text:@"J" forApp:@"com.kapeli.dash" onScreen:[NSScreen mainScreen] fontName:nil fontSize:0.0 iconAlpha:0.0];
|
|
new_hint(L, win);
|
|
return 1;
|
|
}
|
|
|
|
static int hints_new(lua_State* L) {
|
|
NSString* fontName = nil;
|
|
CGFloat fontSize = 0.0;
|
|
CGFloat x = luaL_checknumber(L, 1);
|
|
CGFloat y = luaL_checknumber(L, 2);
|
|
NSString* msg = [NSString stringWithUTF8String: luaL_checkstring(L, 3)];
|
|
NSString* app = [NSString stringWithUTF8String: luaL_checkstring(L, 4)];
|
|
NSScreen *screen = get_screen_arg(L, 5);
|
|
if (!lua_isnoneornil(L, 6) && lua_isstring(L, 6)) {
|
|
fontName = [NSString stringWithUTF8String:luaL_tolstring(L, 6, NULL)];
|
|
}
|
|
if (!lua_isnoneornil(L, 7) && lua_isnumber(L, 7)) {
|
|
fontSize = (CGFloat)lua_tonumber(L, 7);
|
|
}
|
|
CGFloat iconAlpha = (CGFloat)lua_tonumber(L, 8);
|
|
|
|
HintWindow *win = [[HintWindow alloc] initWithPoint:NSMakePoint(x, y) text:msg forApp:app onScreen:screen fontName:fontName fontSize:fontSize iconAlpha:iconAlpha];
|
|
new_hint(L, win);
|
|
return 1;
|
|
}
|
|
|
|
static int userdata_tostring(lua_State* L) {
|
|
lua_pushstring(L, [[NSString stringWithFormat:@"%s: (%p)", USERDATA_TAG, lua_topointer(L, 1)] UTF8String]) ;
|
|
return 1 ;
|
|
}
|
|
|
|
static const luaL_Reg hintslib[] = {
|
|
{"test", hints_test},
|
|
{"new", hints_new},
|
|
|
|
{NULL, NULL} // necessary sentinel
|
|
};
|
|
|
|
static const luaL_Reg hints_metalib[] = {
|
|
{"__eq", hint_eq},
|
|
{"__gc", hint_close},
|
|
{"__tostring", userdata_tostring},
|
|
{"close", hint_close},
|
|
|
|
{NULL, NULL}
|
|
};
|
|
|
|
int luaopen_hs_libhints(lua_State* L) {
|
|
LuaSkin *skin = [LuaSkin sharedWithState:L];
|
|
[skin registerLibraryWithObject:USERDATA_TAG functions:hintslib metaFunctions:nil objectFunctions:hints_metalib];
|
|
|
|
return 1;
|
|
}
|