Initial commit

This commit is contained in:
Morten Delenk 2016-05-15 12:45:15 +02:00
commit da448cdfc6
698 changed files with 37867 additions and 0 deletions

47
GNUmakefile Normal file
View file

@ -0,0 +1,47 @@
ifeq ($(platform),)
hiroflags = $(cppflags) $(flags) -DHIRO_REFERENCE
hirolink =
endif
ifeq ($(platform),windows)
ifeq ($(hiro),)
hiro := windows
endif
ifeq ($(hiro),windows)
hiroflags = $(cppflags) $(flags) -DHIRO_WINDOWS
hirolink = -lkernel32 -luser32 -lgdi32 -ladvapi32 -lole32 -lcomctl32 -lcomdlg32 -luxtheme -lmsimg32 -lshlwapi
endif
ifeq ($(hiro),gtk)
hiroflags = $(cppflags) $(flags) -DHIRO_GTK $(shell pkg-config --cflags gtk+-2.0 gtksourceview-2.0)
hirolink = $(shell pkg-config --libs gtk+-2.0 gtksourceview-2.0)
endif
endif
ifeq ($(platform),macosx)
ifeq ($(hiro),)
hiro := cocoa
endif
ifeq ($(hiro),cocoa)
hiroflags = $(objcppflags) $(flags) -w -DHIRO_COCOA
hirolink = -framework Cocoa -framework Carbon
endif
endif
ifneq ($(filter $(platform),linux bsd),)
ifeq ($(hiro),)
hiro := gtk
endif
ifeq ($(hiro),gtk)
hiroflags = $(cppflags) $(flags) -DHIRO_GTK $(shell pkg-config --cflags gtk+-2.0 gtksourceview-2.0)
hirolink = -lX11 $(shell pkg-config --libs gtk+-2.0 gtksourceview-2.0)
endif
ifeq ($(hiro),qt)
hiroflags = $(cppflags) $(flags) -DHIRO_QT $(shell pkg-config --cflags QtCore QtGui)
hirolink = -lX11 $(shell pkg-config --libs QtCore QtGui)
endif
endif

25
cocoa/action/action.cpp Normal file
View file

@ -0,0 +1,25 @@
#if defined(Hiro_Action)
namespace hiro {
auto pAction::construct() -> void {
}
auto pAction::destruct() -> void {
}
auto pAction::setEnabled(bool enabled) -> void {
@autoreleasepool {
[cocoaAction setEnabled:enabled];
}
}
auto pAction::setVisible(bool visible) -> void {
@autoreleasepool {
[cocoaAction setHidden:!visible];
}
}
}
#endif

16
cocoa/action/action.hpp Normal file
View file

@ -0,0 +1,16 @@
#if defined(Hiro_Action)
namespace hiro {
struct pAction : pObject {
Declare(Action, Object)
auto setEnabled(bool enabled) -> void override;
auto setVisible(bool visible) -> void override;
NSMenuItem* cocoaAction = nullptr;
};
}
#endif

View file

@ -0,0 +1,56 @@
#if defined(Hiro_MenuCheckItem)
@implementation CocoaMenuCheckItem : NSMenuItem
-(id) initWith:(hiro::mMenuCheckItem&)menuCheckItemReference {
if(self = [super initWithTitle:@"" action:@selector(activate) keyEquivalent:@""]) {
menuCheckItem = &menuCheckItemReference;
[self setTarget:self];
}
return self;
}
-(void) activate {
menuCheckItem->state.checked = !menuCheckItem->state.checked;
auto state = menuCheckItem->state.checked ? NSOnState : NSOffState;
[self setState:state];
menuCheckItem->doToggle();
}
@end
namespace hiro {
auto pMenuCheckItem::construct() -> void {
@autoreleasepool {
cocoaAction = cocoaMenuCheckItem = [[CocoaMenuCheckItem alloc] initWith:self()];
pAction::construct();
setChecked(state().checked);
setText(state().text);
}
}
auto pMenuCheckItem::destruct() -> void {
@autoreleasepool {
[cocoaAction release];
}
}
auto pMenuCheckItem::setChecked(bool checked) -> void {
@autoreleasepool {
auto state = checked ? NSOnState : NSOffState;
[cocoaAction setState:state];
}
}
auto pMenuCheckItem::setText(const string& text) -> void {
@autoreleasepool {
[cocoaAction setTitle:[NSString stringWithUTF8String:text]];
}
}
}
#endif

View file

@ -0,0 +1,24 @@
#if defined(Hiro_MenuCheckItem)
@interface CocoaMenuCheckItem : NSMenuItem {
@public
hiro::mMenuCheckItem* menuCheckItem;
}
-(id) initWith:(hiro::mMenuCheckItem&)checkItem;
-(void) activate;
@end
namespace hiro {
struct pMenuCheckItem : pAction {
Declare(MenuCheckItem, Action)
auto setChecked(bool checked) -> void;
auto setText(const string& text) -> void;
CocoaMenuCheckItem* cocoaMenuCheckItem = nullptr;
};
}
#endif

View file

@ -0,0 +1,53 @@
#if defined(Hiro_MenuItem)
@implementation CocoaMenuItem : NSMenuItem
-(id) initWith:(hiro::mMenuItem&)menuItemReference {
if(self = [super initWithTitle:@"" action:@selector(activate) keyEquivalent:@""]) {
menuItem = &menuItemReference;
[self setTarget:self];
}
return self;
}
-(void) activate {
menuItem->doActivate();
}
@end
namespace hiro {
auto pMenuItem::construct() -> void {
@autoreleasepool {
cocoaAction = cocoaMenuItem = [[CocoaMenuItem alloc] initWith:self()];
pAction::construct();
setIcon(state().icon);
setText(state().text);
}
}
auto pMenuItem::destruct() -> void {
@autoreleasepool {
[cocoaAction release];
}
}
auto pMenuItem::setIcon(const image& icon) -> void {
@autoreleasepool {
uint size = 15; //there is no API to retrieve the optimal size
[cocoaAction setImage:NSMakeImage(icon, size, size)];
}
}
auto pMenuItem::setText(const string& text) -> void {
@autoreleasepool {
[cocoaAction setTitle:[NSString stringWithUTF8String:text]];
}
}
}
#endif

View file

@ -0,0 +1,24 @@
#if defined(Hiro_MenuItem)
@interface CocoaMenuItem : NSMenuItem {
@public
hiro::mMenuItem* menuItem;
}
-(id) initWith:(hiro::mMenuItem&)menuItem;
-(void) activate;
@end
namespace hiro {
struct pMenuItem : pAction {
Declare(MenuItem, Action)
auto setIcon(const image& icon) -> void;
auto setText(const string& text) -> void;
CocoaMenuItem* cocoaMenuItem = nullptr;
};
}
#endif

View file

@ -0,0 +1,68 @@
#if defined(Hiro_MenuRadioItem)
@implementation CocoaMenuRadioItem : NSMenuItem
-(id) initWith:(hiro::mMenuRadioItem&)menuRadioItemReference {
if(self = [super initWithTitle:@"" action:@selector(activate) keyEquivalent:@""]) {
menuRadioItem = &menuRadioItemReference;
[self setTarget:self];
[self setOnStateImage:[NSImage imageNamed:@"NSMenuRadio"]];
}
return self;
}
-(void) activate {
menuRadioItem->setChecked();
menuRadioItem->doActivate();
}
@end
namespace hiro {
auto pMenuRadioItem::construct() -> void {
@autoreleasepool {
cocoaAction = cocoaMenuRadioItem = [[CocoaMenuRadioItem alloc] initWith:self()];
pAction::construct();
if(state().checked) setChecked();
setText(state().text);
}
}
auto pMenuRadioItem::destruct() -> void {
@autoreleasepool {
[cocoaAction release];
}
}
auto pMenuRadioItem::setChecked() -> void {
@autoreleasepool {
if(auto group = state().group) {
for(auto& weak : group->state.objects) {
if(auto object = weak.acquire()) {
if(auto self = object->self()) {
if(auto p = dynamic_cast<pMenuRadioItem*>(self)) {
auto state = this == p ? NSOnState : NSOffState;
[p->cocoaAction setState:state];
}
}
}
}
}
}
}
auto pMenuRadioItem::setGroup(sGroup group) -> void {
}
auto pMenuRadioItem::setText(const string& text) -> void {
@autoreleasepool {
[cocoaAction setTitle:[NSString stringWithUTF8String:text]];
}
}
}
#endif

View file

@ -0,0 +1,25 @@
#if defined(Hiro_MenuRadioItem)
@interface CocoaMenuRadioItem : NSMenuItem {
@public
hiro::mMenuRadioItem* menuRadioItem;
}
-(id) initWith:(hiro::mMenuRadioItem&)menuRadioItem;
-(void) activate;
@end
namespace hiro {
struct pMenuRadioItem : pAction {
Declare(MenuRadioItem, Action)
auto setChecked() -> void;
auto setGroup(sGroup group) -> void;
auto setText(const string& text) -> void;
CocoaMenuRadioItem* cocoaMenuRadioItem = nullptr;
};
}
#endif

View file

@ -0,0 +1,20 @@
#if defined(Hiro_MenuSeparator)
namespace hiro {
auto pMenuSeparator::construct() -> void {
@autoreleasepool {
cocoaAction = cocoaSeparator = [[NSMenuItem separatorItem] retain];
pAction::construct();
}
}
auto pMenuSeparator::destruct() -> void {
@autoreleasepool {
[cocoaAction release];
}
}
}
#endif

View file

@ -0,0 +1,13 @@
#if defined(Hiro_MenuSeparator)
namespace hiro {
struct pMenuSeparator : pAction {
Declare(MenuSeparator, Action)
NSMenuItem* cocoaSeparator = nullptr;
};
}
#endif

72
cocoa/action/menu.cpp Normal file
View file

@ -0,0 +1,72 @@
#if defined(Hiro_Menu)
@implementation CocoaMenu : NSMenuItem
-(id) initWith:(hiro::mMenu&)menuReference {
if(self = [super initWithTitle:@"" action:nil keyEquivalent:@""]) {
menu = &menuReference;
cocoaMenu = [[NSMenu alloc] initWithTitle:@""];
[self setSubmenu:cocoaMenu];
}
return self;
}
-(NSMenu*) cocoaMenu {
return cocoaMenu;
}
@end
namespace hiro {
auto pMenu::construct() -> void {
@autoreleasepool {
cocoaAction = cocoaMenu = [[CocoaMenu alloc] initWith:self()];
pAction::construct();
setIcon(state().icon);
setText(state().text);
}
}
auto pMenu::destruct() -> void {
@autoreleasepool {
[[cocoaAction cocoaMenu] release];
[cocoaAction release];
}
}
auto pMenu::append(sAction action) -> void {
@autoreleasepool {
if(auto pAction = action->self()) {
[[cocoaAction cocoaMenu] addItem:pAction->cocoaAction];
}
}
}
auto pMenu::remove(sAction action) -> void {
@autoreleasepool {
if(auto pAction = action->self()) {
[[cocoaAction cocoaMenu] removeItem:pAction->cocoaAction];
}
}
}
auto pMenu::setIcon(const image& icon) -> void {
@autoreleasepool {
uint size = 15; //there is no API to retrieve the optimal size
[cocoaAction setImage:NSMakeImage(icon, size, size)];
}
}
auto pMenu::setText(const string& text) -> void {
@autoreleasepool {
[[cocoaAction cocoaMenu] setTitle:[NSString stringWithUTF8String:text]];
[cocoaAction setTitle:[NSString stringWithUTF8String:text]];
}
}
}
#endif

27
cocoa/action/menu.hpp Normal file
View file

@ -0,0 +1,27 @@
#if defined(Hiro_Menu)
@interface CocoaMenu : NSMenuItem {
@public
hiro::mMenu* menu;
NSMenu* cocoaMenu;
}
-(id) initWith:(hiro::mMenu&)menu;
-(NSMenu*) cocoaMenu;
@end
namespace hiro {
struct pMenu : pAction {
Declare(Menu, Action)
auto append(sAction action) -> void;
auto remove(sAction action) -> void;
auto setIcon(const image& icon) -> void;
auto setText(const string& text) -> void;
CocoaMenu* cocoaMenu = nullptr;
};
}
#endif

93
cocoa/application.cpp Normal file
View file

@ -0,0 +1,93 @@
#if defined(Hiro_Application)
@implementation CocoaDelegate : NSObject
-(NSApplicationTerminateReply) applicationShouldTerminate:(NSApplication*)sender {
using hiro::Application;
if(Application::state.cocoa.onQuit) Application::Cocoa::doQuit();
else Application::quit();
return NSTerminateCancel;
}
-(BOOL) applicationShouldHandleReopen:(NSApplication*)application hasVisibleWindows:(BOOL)flag {
using hiro::Application;
if(Application::state.cocoa.onActivate) Application::Cocoa::doActivate();
return NO;
}
-(void) run:(NSTimer*)timer {
using hiro::Application;
if(Application::state.onMain) Application::doMain();
}
-(void) updateInDock:(NSTimer*)timer {
NSArray* windows = [NSApp windows];
for(uint n = 0; n < [windows count]; n++) {
NSWindow* window = [windows objectAtIndex:n];
if([window isMiniaturized]) {
[window updateInDock];
}
}
}
@end
CocoaDelegate* cocoaDelegate = nullptr;
namespace hiro {
auto pApplication::run() -> void {
//NSTimer* timer = [NSTimer scheduledTimerWithTimeInterval:0.1667 target:cocoaDelegate selector:@selector(updateInDock:) userInfo:nil repeats:YES];
if(Application::state.onMain) {
NSTimer* timer = [NSTimer scheduledTimerWithTimeInterval:0.0 target:cocoaDelegate selector:@selector(run:) userInfo:nil repeats:YES];
//below line is needed to run application during window resize; however it has a large performance penalty on the resize smoothness
//[[NSRunLoop currentRunLoop] addTimer:timer forMode:NSEventTrackingRunLoopMode];
}
@autoreleasepool {
[NSApp run];
}
}
auto pApplication::pendingEvents() -> bool {
bool result = false;
@autoreleasepool {
NSEvent* event = [NSApp nextEventMatchingMask:NSAnyEventMask untilDate:[NSDate distantPast] inMode:NSDefaultRunLoopMode dequeue:NO];
if(event != nil) result = true;
}
return result;
}
auto pApplication::processEvents() -> void {
@autoreleasepool {
while(!Application::state.quit) {
NSEvent* event = [NSApp nextEventMatchingMask:NSAnyEventMask untilDate:[NSDate distantPast] inMode:NSDefaultRunLoopMode dequeue:YES];
if(event == nil) break;
[event retain];
[NSApp sendEvent:event];
[event release];
}
}
}
auto pApplication::quit() -> void {
@autoreleasepool {
[NSApp stop:nil];
NSEvent* event = [NSEvent otherEventWithType:NSApplicationDefined location:NSMakePoint(0, 0) modifierFlags:0 timestamp:0.0 windowNumber:0 context:nil subtype:0 data1:0 data2:0];
[NSApp postEvent:event atStart:true];
}
}
auto pApplication::initialize() -> void {
@autoreleasepool {
[NSApplication sharedApplication];
cocoaDelegate = [[CocoaDelegate alloc] init];
[NSApp setDelegate:cocoaDelegate];
}
}
}
#endif

24
cocoa/application.hpp Normal file
View file

@ -0,0 +1,24 @@
#if defined(Hiro_Application)
@interface CocoaDelegate : NSObject <NSApplicationDelegate> {
}
-(NSApplicationTerminateReply) applicationShouldTerminate:(NSApplication*)sender;
-(BOOL) applicationShouldHandleReopen:(NSApplication*)application hasVisibleWindows:(BOOL)flag;
-(void) run:(NSTimer*)timer;
-(void) updateInDock:(NSTimer*)timer;
@end
namespace hiro {
struct pApplication {
static auto run() -> void;
static auto pendingEvents() -> bool;
static auto processEvents() -> void;
static auto quit() -> void;
static auto initialize() -> void;
};
}
#endif

73
cocoa/browser-window.cpp Normal file
View file

@ -0,0 +1,73 @@
#if defined(Hiro_BrowserWindow)
namespace hiro {
auto pBrowserWindow::directory(BrowserWindow::State& state) -> string {
string result;
@autoreleasepool {
NSOpenPanel* panel = [NSOpenPanel openPanel];
if(state.title) [panel setTitle:[NSString stringWithUTF8String:state.title]];
[panel setCanChooseDirectories:YES];
[panel setCanChooseFiles:NO];
if([panel runModalForDirectory:[NSString stringWithUTF8String:state.path] file:nil] == NSOKButton) {
NSArray* names = [panel filenames];
const char* name = [[names objectAtIndex:0] UTF8String];
if(name) result = name;
}
}
return result;
}
auto pBrowserWindow::open(BrowserWindow::State& state) -> string {
string result;
@autoreleasepool {
NSMutableArray* filters = [[NSMutableArray alloc] init];
for(auto& rule : state.filters) {
string pattern = rule.split("(", 1L)(1).rtrim(")", 1L);
if(!pattern.empty()) [filters addObject:[NSString stringWithUTF8String:pattern]];
}
NSOpenPanel* panel = [NSOpenPanel openPanel];
if(state.title) [panel setTitle:[NSString stringWithUTF8String:state.title]];
[panel setCanChooseDirectories:NO];
[panel setCanChooseFiles:YES];
[panel setAllowedFileTypes:filters];
if([panel runModalForDirectory:[NSString stringWithUTF8String:state.path] file:nil] == NSOKButton) {
NSArray* names = [panel filenames];
const char* name = [[names objectAtIndex:0] UTF8String];
if(name) result = name;
}
[filters release];
}
return result;
}
auto pBrowserWindow::save(BrowserWindow::State& state) -> string {
string result;
@autoreleasepool {
NSMutableArray* filters = [[NSMutableArray alloc] init];
for(auto& rule : state.filters) {
string pattern = rule.split("(", 1L)(1).rtrim(")", 1L);
if(!pattern.empty()) [filters addObject:[NSString stringWithUTF8String:pattern]];
}
NSSavePanel* panel = [NSSavePanel savePanel];
if(state.title) [panel setTitle:[NSString stringWithUTF8String:state.title]];
[panel setAllowedFileTypes:filters];
if([panel runModalForDirectory:[NSString stringWithUTF8String:state.path] file:nil] == NSOKButton) {
NSArray* names = [panel filenames];
const char* name = [[names objectAtIndex:0] UTF8String];
if(name) result = name;
}
[filters release];
}
return result;
}
}
#endif

13
cocoa/browser-window.hpp Normal file
View file

@ -0,0 +1,13 @@
#if defined(Hiro_BrowserWindow)
namespace hiro {
struct pBrowserWindow {
static auto directory(BrowserWindow::State& state) -> string;
static auto open(BrowserWindow::State& state) -> string;
static auto save(BrowserWindow::State& state) -> string;
};
}
#endif

22
cocoa/desktop.cpp Normal file
View file

@ -0,0 +1,22 @@
#if defined(Hiro_Desktop)
namespace hiro {
auto pDesktop::size() -> Size {
@autoreleasepool {
NSRect primary = [[[NSScreen screens] objectAtIndex:0] frame];
return {(int)primary.size.width, (int)primary.size.height};
}
}
auto pDesktop::workspace() -> Geometry {
@autoreleasepool {
auto screen = Desktop::size();
NSRect area = [[[NSScreen screens] objectAtIndex:0] visibleFrame];
return {(int)area.origin.x, (int)(screen.height() - area.size.height - area.origin.y), (int)area.size.width, (int)area.size.height};
}
}
}
#endif

12
cocoa/desktop.hpp Normal file
View file

@ -0,0 +1,12 @@
#if defined(Hiro_Desktop)
namespace hiro {
struct pDesktop {
static auto size() -> Size;
static auto workspace() -> Geometry;
};
}
#endif

51
cocoa/font.cpp Normal file
View file

@ -0,0 +1,51 @@
#if defined(Hiro_Font)
namespace hiro {
auto pFont::size(const Font& font, const string& text) -> Size {
@autoreleasepool {
if(NSFont* nsFont = create(font)) {
return size(nsFont, text);
}
}
return {0, 0};
}
auto pFont::size(NSFont* font, const string& text) -> Size {
@autoreleasepool {
NSString* cocoaText = [NSString stringWithUTF8String:text];
NSDictionary* fontAttributes = [NSDictionary dictionaryWithObjectsAndKeys:font, NSFontAttributeName, nil];
NSSize size = [cocoaText sizeWithAttributes:fontAttributes];
return {(int)size.width, (int)size.height};
}
}
auto pFont::family(const string& family) -> string {
if(family == Font::Sans ) return "Lucida Grande";
if(family == Font::Serif) return "Georgia";
if(family == Font::Mono ) return "Menlo";
return "Lucida Grande";
}
auto pFont::create(const Font& font) -> NSFont* {
auto fontName = family(font.family());
NSString* family = [NSString stringWithUTF8String:fontName];
CGFloat size = (float)(font.size() ? font.size() : 8);
NSFontTraitMask traits = 0;
if(font.bold()) traits |= NSBoldFontMask;
if(font.italic()) traits |= NSItalicFontMask;
//note: below properties are not exposed by hiro::Font; traits are saved here for possible future use
//if(font.narrow()) traits |= NSNarrowFontMask;
//if(font.expanded()) traits |= NSExpandedFontMask;
//if(font.condensed()) traits |= NSCondensedFontMask;
//if(font.smallCaps()) traits |= NSSmallCapsFontMask;
size *= 1.5; //scale to point sizes (for consistency with other operating systems)
return [[NSFontManager sharedFontManager] fontWithFamily:family traits:traits weight:5 size:size];
}
}
#endif

14
cocoa/font.hpp Normal file
View file

@ -0,0 +1,14 @@
#if defined(Hiro_Font)
namespace hiro {
struct pFont {
static auto size(const Font& font, const string& text) -> Size;
static auto size(NSFont* font, const string& text) -> Size;
static auto family(const string& family) -> string;
static auto create(const Font& font) -> NSFont*;
};
}
#endif

13
cocoa/group.cpp Normal file
View file

@ -0,0 +1,13 @@
#if defined(Hiro_Group)
namespace hiro {
auto pGroup::construct() -> void {
}
auto pGroup::destruct() -> void {
}
}
#endif

11
cocoa/group.hpp Normal file
View file

@ -0,0 +1,11 @@
#if defined(Hiro_Group)
namespace hiro {
struct pGroup : pObject {
Declare(Group, Object);
};
}
#endif

6
cocoa/header.hpp Normal file
View file

@ -0,0 +1,6 @@
#define decimal CocoaDecimal
#import <Cocoa/Cocoa.h>
#import <Carbon/Carbon.h>
#undef decimal
#include <nall/run.hpp>

16
cocoa/keyboard.cpp Normal file
View file

@ -0,0 +1,16 @@
#if defined(Hiro_Keyboard)
namespace hiro {
auto pKeyboard::poll() -> vector<bool> {
vector<bool> result;
return result;
}
auto pKeyboard::pressed(uint code) -> bool {
return false;
}
}
#endif

12
cocoa/keyboard.hpp Normal file
View file

@ -0,0 +1,12 @@
#if defined(Hiro_Keyboard)
namespace hiro {
struct pKeyboard {
static auto poll() -> vector<bool>;
static auto pressed(uint code) -> bool;
};
}
#endif

33
cocoa/layout.cpp Normal file
View file

@ -0,0 +1,33 @@
#if defined(Hiro_Layout)
namespace hiro {
auto pLayout::construct() -> void {
for(auto& sizable : state().sizables) sizable->construct();
}
auto pLayout::destruct() -> void {
for(auto& sizable : state().sizables) sizable->destruct();
}
auto pLayout::setEnabled(bool enabled) -> void {
for(auto& sizable : state().sizables) {
if(auto self = sizable->self()) self->setEnabled(enabled && sizable->enabled(true));
}
}
auto pLayout::setFont(const Font& font) -> void {
for(auto& sizable : state().sizables) {
if(auto self = sizable->self()) self->setFont(font ? font : sizable->font(true));
}
}
auto pLayout::setVisible(bool visible) -> void {
for(auto& sizable : state().sizables) {
if(auto self = sizable->self()) self->setVisible(visible && sizable->visible(true));
}
}
}
#endif

15
cocoa/layout.hpp Normal file
View file

@ -0,0 +1,15 @@
#if defined(Hiro_Layout)
namespace hiro {
struct pLayout : pSizable {
Declare(Layout, Sizable);
auto setEnabled(bool enabled) -> void override;
auto setFont(const Font& font) -> void override;
auto setVisible(bool visible) -> void override;
};
}
#endif

40
cocoa/menu-bar.cpp Normal file
View file

@ -0,0 +1,40 @@
#if defined(Hiro_MenuBar)
namespace hiro {
auto pMenuBar::construct() -> void {
}
auto pMenuBar::destruct() -> void {
}
auto pMenuBar::append(sMenu menu) -> void {
@autoreleasepool {
if(auto parent = _parent()) {
if(auto pMenu = menu->self()) {
[[parent->cocoaWindow menuBar] addItem:pMenu->cocoaAction];
}
}
}
}
auto pMenuBar::remove(sMenu menu) -> void {
@autoreleasepool {
if(auto parent = _parent()) {
if(auto pMenu = menu->self()) {
[[parent->cocoaWindow menuBar] removeItem:pMenu->cocoaAction];
}
}
}
}
auto pMenuBar::_parent() -> maybe<pWindow&> {
if(auto parent = self().parentWindow()) {
if(auto self = parent->self()) return *self;
}
return nothing;
}
}
#endif

16
cocoa/menu-bar.hpp Normal file
View file

@ -0,0 +1,16 @@
#if defined(Hiro_MenuBar)
namespace hiro {
struct pMenuBar : pObject {
Declare(MenuBar, Object)
auto append(sMenu menu) -> void;
auto remove(sMenu menu) -> void;
auto _parent() -> maybe<pWindow&>;
};
}
#endif

83
cocoa/message-window.cpp Normal file
View file

@ -0,0 +1,83 @@
#if defined(Hiro_MessageWindow)
namespace hiro {
enum class MessageWindowType : uint { Error, Information, Question, Warning };
auto MessageWindow_dialog(MessageWindow::State& state, MessageWindowType type) -> MessageWindow::Response {
@autoreleasepool {
NSAlert* alert = [[[NSAlert alloc] init] autorelease];
if(state.title) [alert setMessageText:[NSString stringWithUTF8String:state.title]];
[alert setInformativeText:[NSString stringWithUTF8String:state.text]];
switch(state.buttons) {
case MessageWindow::Buttons::Ok:
[alert addButtonWithTitle:@"Ok"];
break;
case MessageWindow::Buttons::OkCancel:
[alert addButtonWithTitle:@"Ok"];
[alert addButtonWithTitle:@"Cancel"];
break;
case MessageWindow::Buttons::YesNo:
[alert addButtonWithTitle:@"Yes"];
[alert addButtonWithTitle:@"No"];
break;
case MessageWindow::Buttons::YesNoCancel:
[alert addButtonWithTitle:@"Yes"];
[alert addButtonWithTitle:@"No"];
[alert addButtonWithTitle:@"Cancel"];
break;
}
switch(type) {
case MessageWindowType::Error: [alert setAlertStyle:NSCriticalAlertStyle]; break;
case MessageWindowType::Information: [alert setAlertStyle:NSInformationalAlertStyle]; break;
case MessageWindowType::Question: [alert setAlertStyle:NSInformationalAlertStyle]; break;
case MessageWindowType::Warning: [alert setAlertStyle:NSWarningAlertStyle]; break;
}
NSInteger response = [alert runModal];
//[alert beginSheetModalForWindow:parent.p.cocoaWindow modalDelegate:self didEndSelector:@selector(...) contextInfo:nil];
switch(state.buttons) {
case MessageWindow::Buttons::Ok:
if(response == NSAlertFirstButtonReturn) return MessageWindow::Response::Ok;
break;
case MessageWindow::Buttons::OkCancel:
if(response == NSAlertFirstButtonReturn) return MessageWindow::Response::Ok;
if(response == NSAlertSecondButtonReturn) return MessageWindow::Response::Cancel;
break;
case MessageWindow::Buttons::YesNo:
if(response == NSAlertFirstButtonReturn) return MessageWindow::Response::Yes;
if(response == NSAlertSecondButtonReturn) return MessageWindow::Response::No;
break;
case MessageWindow::Buttons::YesNoCancel:
if(response == NSAlertFirstButtonReturn) return MessageWindow::Response::Yes;
if(response == NSAlertSecondButtonReturn) return MessageWindow::Response::No;
if(response == NSAlertThirdButtonReturn) return MessageWindow::Response::Cancel;
break;
}
}
throw;
}
auto pMessageWindow::error(MessageWindow::State& state) -> MessageWindow::Response {
return MessageWindow_dialog(state, MessageWindowType::Error);
}
auto pMessageWindow::information(MessageWindow::State& state) -> MessageWindow::Response {
return MessageWindow_dialog(state, MessageWindowType::Information);
}
auto pMessageWindow::question(MessageWindow::State& state) -> MessageWindow::Response {
return MessageWindow_dialog(state, MessageWindowType::Question);
}
auto pMessageWindow::warning(MessageWindow::State& state) -> MessageWindow::Response {
return MessageWindow_dialog(state, MessageWindowType::Warning);
}
}
#endif

14
cocoa/message-window.hpp Normal file
View file

@ -0,0 +1,14 @@
#if defined(Hiro_MessageWindow)
namespace hiro {
struct pMessageWindow {
static auto error(MessageWindow::State& state) -> MessageWindow::Response;
static auto information(MessageWindow::State& state) -> MessageWindow::Response;
static auto question(MessageWindow::State& state) -> MessageWindow::Response;
static auto warning(MessageWindow::State& state) -> MessageWindow::Response;
};
}
#endif

25
cocoa/monitor.cpp Normal file
View file

@ -0,0 +1,25 @@
#if defined(Hiro_Monitor)
namespace hiro {
auto pMonitor::count() -> uint {
@autoreleasepool {
return [[NSScreen screens] count];
}
}
auto pMonitor::geometry(uint monitor) -> Geometry {
@autoreleasepool {
NSRect rectangle = [[[NSScreen screens] objectAtIndex:monitor] frame];
return {(int)rectangle.origin.x, (int)rectangle.origin.y, (int)rectangle.size.width, (int)rectangle.size.height};
}
}
auto pMonitor::primary() -> uint {
//on OS X, the primary monitor is always the first monitor
return 0;
}
}
#endif

13
cocoa/monitor.hpp Normal file
View file

@ -0,0 +1,13 @@
#if defined(Hiro_Monitor)
namespace hiro {
struct pMonitor {
static auto count() -> uint;
static auto geometry(uint monitor) -> Geometry;
static auto primary() -> uint;
};
}
#endif

15
cocoa/mouse.cpp Normal file
View file

@ -0,0 +1,15 @@
#if defined(Hiro_Mouse)
namespace hiro {
auto pMouse::position() -> Position {
return {0, 0};
}
auto pMouse::pressed(Mouse::Button button) -> bool {
return false;
}
}
#endif

12
cocoa/mouse.hpp Normal file
View file

@ -0,0 +1,12 @@
#if defined(Hiro_Mouse)
namespace hiro {
struct pMouse {
static auto position() -> Position;
static auto pressed(Mouse::Button button) -> bool;
};
}
#endif

35
cocoa/object.cpp Normal file
View file

@ -0,0 +1,35 @@
#if defined(Hiro_Object)
namespace hiro {
auto pObject::construct() -> void {
}
auto pObject::destruct() -> void {
}
auto pObject::focused() const -> bool {
return false;
}
auto pObject::remove() -> void {
}
auto pObject::reset() -> void {
}
auto pObject::setEnabled(bool enabled) -> void {
}
auto pObject::setFocused() -> void {
}
auto pObject::setFont(const Font& font) -> void {
}
auto pObject::setVisible(bool visible) -> void {
}
}
#endif

31
cocoa/object.hpp Normal file
View file

@ -0,0 +1,31 @@
#if defined(Hiro_Object)
namespace hiro {
struct pObject {
pObject(mObject& reference) : reference(reference) {}
virtual ~pObject() {}
auto self() const -> mObject& { return (mObject&)reference; }
auto state() const -> mObject::State& { return self().state; }
virtual auto construct() -> void;
virtual auto destruct() -> void;
virtual auto focused() const -> bool;
virtual auto remove() -> void;
virtual auto reset() -> void;
virtual auto setEnabled(bool enabled) -> void;
virtual auto setFocused() -> void;
virtual auto setFont(const Font& font) -> void;
virtual auto setVisible(bool visible) -> void;
auto locked() const -> bool { return locks != 0; }
auto lock() -> void { ++locks; }
auto unlock() -> void { --locks; }
mObject& reference;
signed locks = 0;
};
}
#endif

60
cocoa/platform.cpp Normal file
View file

@ -0,0 +1,60 @@
#include "platform.hpp"
#include "utility.cpp"
#include "font.cpp"
#include "desktop.cpp"
#include "monitor.cpp"
#include "keyboard.cpp"
#include "mouse.cpp"
#include "browser-window.cpp"
#include "message-window.cpp"
#include "object.cpp"
#include "group.cpp"
#include "timer.cpp"
#include "window.cpp"
#include "status-bar.cpp"
#include "menu-bar.cpp"
#include "popup-menu.cpp"
#include "action/action.cpp"
#include "action/menu.cpp"
#include "action/menu-separator.cpp"
#include "action/menu-item.cpp"
#include "action/menu-check-item.cpp"
#include "action/menu-radio-item.cpp"
#include "sizable.cpp"
#include "layout.cpp"
#include "widget/widget.cpp"
#include "widget/button.cpp"
#include "widget/canvas.cpp"
#include "widget/check-button.cpp"
#include "widget/check-label.cpp"
#include "widget/combo-button.cpp"
#include "widget/combo-button-item.cpp"
#include "widget/console.cpp"
#include "widget/frame.cpp"
#include "widget/hex-edit.cpp"
#include "widget/horizontal-scroll-bar.cpp"
#include "widget/horizontal-slider.cpp"
#include "widget/label.cpp"
#include "widget/line-edit.cpp"
#include "widget/list-view.cpp"
#include "widget/list-view-header.cpp"
#include "widget/list-view-column.cpp"
#include "widget/list-view-item.cpp"
#include "widget/list-view-cell.cpp"
#include "widget/progress-bar.cpp"
#include "widget/radio-button.cpp"
#include "widget/radio-label.cpp"
#include "widget/tab-frame.cpp"
#include "widget/tab-frame-item.cpp"
#include "widget/text-edit.cpp"
#include "widget/vertical-scroll-bar.cpp"
#include "widget/vertical-slider.cpp"
#include "widget/viewport.cpp"
#include "application.cpp"

74
cocoa/platform.hpp Normal file
View file

@ -0,0 +1,74 @@
namespace hiro {
struct pFont;
struct pWindow;
struct pMenu;
struct pLayout;
struct pWidget;
}
#define Declare(Name, Base) \
p##Name(m##Name& reference) : p##Base(reference) {} \
auto self() const -> m##Name& { return (m##Name&)reference; } \
auto state() const -> m##Name::State& { return self().state; } \
auto construct() -> void override; \
auto destruct() -> void override; \
#include "font.hpp"
#include "desktop.hpp"
#include "monitor.hpp"
#include "keyboard.hpp"
#include "mouse.hpp"
#include "browser-window.hpp"
#include "message-window.hpp"
#include "object.hpp"
#include "group.hpp"
#include "timer.hpp"
#include "window.hpp"
#include "status-bar.hpp"
#include "menu-bar.hpp"
#include "popup-menu.hpp"
#include "action/action.hpp"
#include "action/menu.hpp"
#include "action/menu-separator.hpp"
#include "action/menu-item.hpp"
#include "action/menu-check-item.hpp"
#include "action/menu-radio-item.hpp"
#include "sizable.hpp"
#include "layout.hpp"
#include "widget/widget.hpp"
#include "widget/button.hpp"
#include "widget/canvas.hpp"
#include "widget/check-button.hpp"
#include "widget/check-label.hpp"
#include "widget/combo-button.hpp"
#include "widget/combo-button-item.hpp"
#include "widget/console.hpp"
#include "widget/frame.hpp"
#include "widget/hex-edit.hpp"
#include "widget/horizontal-scroll-bar.hpp"
#include "widget/horizontal-slider.hpp"
#include "widget/label.hpp"
#include "widget/line-edit.hpp"
#include "widget/list-view.hpp"
#include "widget/list-view-header.hpp"
#include "widget/list-view-column.hpp"
#include "widget/list-view-item.hpp"
#include "widget/list-view-cell.hpp"
#include "widget/progress-bar.hpp"
#include "widget/radio-button.hpp"
#include "widget/radio-label.hpp"
#include "widget/tab-frame.hpp"
#include "widget/tab-frame-item.hpp"
#include "widget/text-edit.hpp"
#include "widget/vertical-scroll-bar.hpp"
#include "widget/vertical-slider.hpp"
#include "widget/viewport.hpp"
#undef Declare
#include "application.hpp"

22
cocoa/popup-menu.cpp Normal file
View file

@ -0,0 +1,22 @@
#if defined(Hiro_PopupMenu)
namespace hiro {
auto pPopupMenu::construct() -> void {
}
auto pPopupMenu::destruct() -> void {
}
auto pPopupMenu::append(sAction action) -> void {
}
auto pPopupMenu::remove(sAction action) -> void {
}
auto pPopupMenu::setVisible(bool visible) -> void {
}
}
#endif

15
cocoa/popup-menu.hpp Normal file
View file

@ -0,0 +1,15 @@
#if defined(Hiro_PopupMenu)
namespace hiro {
struct pPopupMenu : pObject {
Declare(PopupMenu, Object)
auto append(sAction action) -> void;
auto remove(sAction action) -> void;
auto setVisible(bool visible) -> void;
};
}
#endif

20
cocoa/sizable.cpp Normal file
View file

@ -0,0 +1,20 @@
#if defined(Hiro_Sizable)
namespace hiro {
auto pSizable::construct() -> void {
}
auto pSizable::destruct() -> void {
}
auto pSizable::minimumSize() const -> Size {
return {0, 0};
}
auto pSizable::setGeometry(Geometry geometry) -> void {
}
}
#endif

14
cocoa/sizable.hpp Normal file
View file

@ -0,0 +1,14 @@
#if defined(Hiro_Sizable)
namespace hiro {
struct pSizable : pObject {
Declare(Sizable, Object)
virtual auto minimumSize() const -> Size;
virtual auto setGeometry(Geometry geometry) -> void;
};
}
#endif

53
cocoa/status-bar.cpp Normal file
View file

@ -0,0 +1,53 @@
#if defined(Hiro_StatusBar)
namespace hiro {
auto pStatusBar::construct() -> void {
}
auto pStatusBar::destruct() -> void {
}
auto pStatusBar::setEnabled(bool enabled) -> void {
@autoreleasepool {
if(auto parent = _parent()) {
[[parent->cocoaWindow statusBar] setEnabled:enabled];
}
}
}
auto pStatusBar::setFont(const Font& font) -> void {
@autoreleasepool {
if(auto parent = _parent()) {
[[parent->cocoaWindow statusBar] setFont:pFont::create(font)];
}
}
}
auto pStatusBar::setText(const string& text) -> void {
@autoreleasepool {
if(auto parent = _parent()) {
[[parent->cocoaWindow statusBar] setStringValue:[NSString stringWithUTF8String:state().text]];
}
}
}
auto pStatusBar::setVisible(bool visible) -> void {
@autoreleasepool {
if(auto parent = _parent()) {
[[parent->cocoaWindow statusBar] setHidden:!visible];
parent->setGeometry(parent->state().geometry);
}
}
}
auto pStatusBar::_parent() -> maybe<pWindow&> {
if(auto parent = self().parentWindow()) {
if(auto self = parent->self()) return *self;
}
return nothing;
}
}
#endif

18
cocoa/status-bar.hpp Normal file
View file

@ -0,0 +1,18 @@
#if defined(Hiro_StatusBar)
namespace hiro {
struct pStatusBar : pObject {
Declare(StatusBar, Object)
auto setEnabled(bool enabled) -> void override;
auto setFont(const Font& font) -> void override;
auto setText(const string& text) -> void;
auto setVisible(bool visible) -> void override;
auto _parent() -> maybe<pWindow&>;
};
}
#endif

67
cocoa/timer.cpp Normal file
View file

@ -0,0 +1,67 @@
#if defined(Hiro_Timer)
@implementation CocoaTimer : NSObject
-(id) initWith:(hiro::mTimer&)timerReference {
if(self = [super init]) {
timer = &timerReference;
instance = nil;
}
return self;
}
-(NSTimer*) instance {
return instance;
}
-(void) update {
if(instance) {
[instance invalidate];
instance = nil;
}
if(timer->enabled()) {
instance = [NSTimer
scheduledTimerWithTimeInterval:timer->state.interval / 1000.0
target:self selector:@selector(run:) userInfo:nil repeats:YES
];
}
}
-(void) run:(NSTimer*)instance {
if(timer->enabled()) {
timer->doActivate();
}
}
@end
namespace hiro {
auto pTimer::construct() -> void {
@autoreleasepool {
cocoaTimer = [[CocoaTimer alloc] initWith:self()];
}
}
auto pTimer::destruct() -> void {
@autoreleasepool {
if([cocoaTimer instance]) [[cocoaTimer instance] invalidate];
[cocoaTimer release];
}
}
auto pTimer::setEnabled(bool enabled) -> void {
@autoreleasepool {
[cocoaTimer update];
}
}
auto pTimer::setInterval(uint interval) -> void {
@autoreleasepool {
[cocoaTimer update];
}
}
}
#endif

27
cocoa/timer.hpp Normal file
View file

@ -0,0 +1,27 @@
#if defined(Hiro_Timer)
@interface CocoaTimer : NSObject {
@public
hiro::mTimer* timer;
NSTimer* instance;
}
-(id) initWith:(hiro::mTimer&)timer;
-(NSTimer*) instance;
-(void) update;
-(void) run:(NSTimer*)instance;
@end
namespace hiro {
struct pTimer : pObject {
Declare(Timer, Object)
auto setEnabled(bool enabled) -> void;
auto setInterval(uint interval) -> void;
CocoaTimer* cocoaTimer = nullptr;
};
}
#endif

48
cocoa/utility.cpp Normal file
View file

@ -0,0 +1,48 @@
auto NSMakeColor(const hiro::Color& color) -> NSColor* {
return [NSColor colorWithRed:(color.red() / 255.0) green:(color.green() / 255.0) blue:(color.blue() / 255.0) alpha:(color.alpha() / 255.0)];
}
auto NSMakeImage(image icon, uint scaleWidth = 0, uint scaleHeight = 0) -> NSImage* {
if(!icon) return nil;
if(scaleWidth && scaleHeight) icon.scale(scaleWidth, scaleHeight);
icon.transform(0, 32, 255u << 24, 255u << 0, 255u << 8, 255u << 16); //Cocoa stores images in ABGR format
//create NSImage from memory
NSImage* cocoaImage = [[[NSImage alloc] initWithSize:NSMakeSize(icon.width(), icon.height())] autorelease];
NSBitmapImageRep* bitmap = [[[NSBitmapImageRep alloc]
initWithBitmapDataPlanes:nil
pixelsWide:icon.width() pixelsHigh:icon.height()
bitsPerSample:8 samplesPerPixel:4 hasAlpha:YES
isPlanar:NO colorSpaceName:NSCalibratedRGBColorSpace
bitmapFormat:NSAlphaNonpremultipliedBitmapFormat
bytesPerRow:(4 * icon.width()) bitsPerPixel:32
] autorelease];
memory::copy([bitmap bitmapData], icon.data(), 4 * icon.width() * icon.height());
[cocoaImage addRepresentation:bitmap];
return cocoaImage;
}
auto DropPathsOperation(id<NSDraggingInfo> sender) -> NSDragOperation {
NSPasteboard* pboard = [sender draggingPasteboard];
if([[pboard types] containsObject:NSFilenamesPboardType]) {
if([sender draggingSourceOperationMask] & NSDragOperationGeneric) {
return NSDragOperationGeneric;
}
}
return NSDragOperationNone;
}
auto DropPaths(id<NSDraggingInfo> sender) -> lstring {
lstring paths;
NSPasteboard* pboard = [sender draggingPasteboard];
if([[pboard types] containsObject:NSFilenamesPboardType]) {
NSArray* files = [pboard propertyListForType:NSFilenamesPboardType];
for(uint n = 0; n < [files count]; n++) {
string path = [[files objectAtIndex:n] UTF8String];
if(directory::exists(path) && !path.endsWith("/")) path.append("/");
paths.append(path);
}
}
return paths;
}

90
cocoa/widget/button.cpp Normal file
View file

@ -0,0 +1,90 @@
#if defined(Hiro_Button)
@implementation CocoaButton : NSButton
-(id) initWith:(hiro::mButton&)buttonReference {
if(self = [super initWithFrame:NSMakeRect(0, 0, 0, 0)]) {
button = &buttonReference;
[self setTarget:self];
[self setAction:@selector(activate:)];
//NSRoundedBezelStyle has a fixed height; which breaks both icons and larger/smaller text
[self setBezelStyle:NSRegularSquareBezelStyle];
}
return self;
}
-(IBAction) activate:(id)sender {
button->doActivate();
}
@end
namespace hiro {
auto pButton::construct() -> void {
@autoreleasepool {
cocoaView = cocoaButton = [[CocoaButton alloc] initWith:self()];
pWidget::construct();
setBordered(state().bordered);
setIcon(state().icon);
setOrientation(state().orientation);
setText(state().text);
}
}
auto pButton::destruct() -> void {
@autoreleasepool {
[cocoaView removeFromSuperview];
[cocoaView release];
}
}
auto pButton::minimumSize() const -> Size {
Size size = pFont::size(self().font(true), state().text);
if(state().orientation == Orientation::Horizontal) {
size.setWidth(size.width() + state().icon.width());
size.setHeight(max(size.height(), state().icon.height()));
}
if(state().orientation == Orientation::Vertical) {
size.setWidth(max(size.width(), state().icon.width()));
size.setHeight(size.height() + state().icon.height());
}
return {size.width() + (state().text ? 20 : 8), size.height() + 8};
}
auto pButton::setBordered(bool bordered) -> void {
}
auto pButton::setGeometry(Geometry geometry) -> void {
pWidget::setGeometry({
geometry.x() - 2, geometry.y() - 2,
geometry.width() + 4, geometry.height() + 4
});
}
auto pButton::setIcon(const image& icon) -> void {
@autoreleasepool {
[cocoaView setImage:NSMakeImage(icon)];
}
}
auto pButton::setOrientation(Orientation orientation) -> void {
@autoreleasepool {
if(orientation == Orientation::Horizontal) [cocoaView setImagePosition:NSImageLeft];
if(orientation == Orientation::Vertical ) [cocoaView setImagePosition:NSImageAbove];
}
}
auto pButton::setText(const string& text) -> void {
@autoreleasepool {
[cocoaView setTitle:[NSString stringWithUTF8String:text]];
}
}
}
#endif

28
cocoa/widget/button.hpp Normal file
View file

@ -0,0 +1,28 @@
#if defined(Hiro_Button)
@interface CocoaButton : NSButton {
@public
hiro::mButton* button;
}
-(id) initWith:(hiro::mButton&)button;
-(IBAction) activate:(id)sender;
@end
namespace hiro {
struct pButton : pWidget {
Declare(Button, Widget)
auto minimumSize() const -> Size override;
auto setBordered(bool bordered) -> void;
auto setGeometry(Geometry geometry) -> void override;
auto setIcon(const image& icon) -> void;
auto setOrientation(Orientation orientation) -> void;
auto setText(const string& text) -> void;
CocoaButton* cocoaButton = nullptr;
};
}
#endif

208
cocoa/widget/canvas.cpp Normal file
View file

@ -0,0 +1,208 @@
#if defined(Hiro_Canvas)
@implementation CocoaCanvas : NSImageView
-(id) initWith:(hiro::mCanvas&)canvasReference {
if(self = [super initWithFrame:NSMakeRect(0, 0, 0, 0)]) {
canvas = &canvasReference;
[self setEditable:NO]; //disable image drag-and-drop functionality
NSTrackingArea* area = [[[NSTrackingArea alloc] initWithRect:[self frame]
options:NSTrackingMouseMoved | NSTrackingMouseEnteredAndExited | NSTrackingActiveInKeyWindow | NSTrackingInVisibleRect
owner:self userInfo:nil
] autorelease];
[self addTrackingArea:area];
}
return self;
}
-(NSDragOperation) draggingEntered:(id<NSDraggingInfo>)sender {
return DropPathsOperation(sender);
}
-(BOOL) performDragOperation:(id<NSDraggingInfo>)sender {
lstring paths = DropPaths(sender);
if(paths.empty()) return NO;
canvas->doDrop(paths);
return YES;
}
-(void) mouseButton:(NSEvent*)event down:(BOOL)isDown {
if(isDown) {
switch([event buttonNumber]) {
case 0: return canvas->doMousePress(hiro::Mouse::Button::Left);
case 1: return canvas->doMousePress(hiro::Mouse::Button::Right);
case 2: return canvas->doMousePress(hiro::Mouse::Button::Middle);
}
} else {
switch([event buttonNumber]) {
case 0: return canvas->doMouseRelease(hiro::Mouse::Button::Left);
case 1: return canvas->doMouseRelease(hiro::Mouse::Button::Right);
case 2: return canvas->doMouseRelease(hiro::Mouse::Button::Middle);
}
}
}
-(void) mouseExited:(NSEvent*)event {
canvas->doMouseLeave();
}
-(void) mouseMove:(NSEvent*)event {
if([event window] == nil) return;
NSPoint location = [self convertPoint:[event locationInWindow] fromView:nil];
canvas->doMouseMove({(int)location.x, (int)([self frame].size.height - 1 - location.y)});
}
-(void) mouseDown:(NSEvent*)event {
[self mouseButton:event down:YES];
}
-(void) mouseUp:(NSEvent*)event {
[self mouseButton:event down:NO];
}
-(void) mouseDragged:(NSEvent*)event {
[self mouseMove:event];
}
-(void) rightMouseDown:(NSEvent*)event {
[self mouseButton:event down:YES];
}
-(void) rightMouseUp:(NSEvent*)event {
[self mouseButton:event down:NO];
}
-(void) rightMouseDragged:(NSEvent*)event {
[self mouseMove:event];
}
-(void) otherMouseDown:(NSEvent*)event {
[self mouseButton:event down:YES];
}
-(void) otherMouseUp:(NSEvent*)event {
[self mouseButton:event down:NO];
}
-(void) otherMouseDragged:(NSEvent*)event {
[self mouseMove:event];
}
@end
namespace hiro {
auto pCanvas::construct() -> void {
@autoreleasepool {
cocoaView = cocoaCanvas = [[CocoaCanvas alloc] initWith:self()];
pWidget::construct();
setDroppable(state().droppable);
}
}
auto pCanvas::destruct() -> void {
@autoreleasepool {
[cocoaView removeFromSuperview];
[cocoaView release];
}
}
auto pCanvas::minimumSize() const -> Size {
if(auto& icon = state().icon) return {(int)icon.width(), (int)icon.height()};
return {0, 0};
}
auto pCanvas::setColor(Color color) -> void {
update();
}
auto pCanvas::setDroppable(bool droppable) -> void {
@autoreleasepool {
if(droppable) {
[cocoaCanvas registerForDraggedTypes:[NSArray arrayWithObject:NSFilenamesPboardType]];
} else {
[cocoaCanvas unregisterDraggedTypes];
}
}
}
auto pCanvas::setGeometry(Geometry geometry) -> void {
pWidget::setGeometry(geometry);
update();
}
auto pCanvas::setGradient(Gradient gradient) -> void {
update();
}
auto pCanvas::setIcon(const image& icon) -> void {
update();
}
auto pCanvas::update() -> void {
_rasterize();
@autoreleasepool {
[cocoaView setNeedsDisplay:YES];
}
}
auto pCanvas::_rasterize() -> void {
@autoreleasepool {
int width = 0;
int height = 0;
if(auto& icon = state().icon) {
width = icon.width();
height = icon.height();
} else {
width = pSizable::state().geometry.width();
height = pSizable::state().geometry.height();
}
if(width <= 0 || height <= 0) return;
if(width != surfaceWidth || height != surfaceHeight) {
[cocoaView setImage:nil];
[surface release];
surface = nullptr;
bitmap = nullptr;
}
surfaceWidth = width;
surfaceHeight = height;
if(!surface) {
surface = [[[NSImage alloc] initWithSize:NSMakeSize(width, height)] autorelease];
bitmap = [[[NSBitmapImageRep alloc]
initWithBitmapDataPlanes:nil
pixelsWide:width pixelsHigh:height
bitsPerSample:8 samplesPerPixel:4 hasAlpha:YES
isPlanar:NO colorSpaceName:NSCalibratedRGBColorSpace
bitmapFormat:NSAlphaNonpremultipliedBitmapFormat
bytesPerRow:(width * 4) bitsPerPixel:32
] autorelease];
[surface addRepresentation:bitmap];
[cocoaView setImage:surface];
}
auto target = (uint32*)[bitmap bitmapData];
if(auto icon = state().icon) {
icon.transform();
memory::copy(target, icon.data(), icon.size());
} else if(auto& gradient = state().gradient) {
auto& colors = gradient.state.colors;
image fill;
fill.allocate(width, height);
fill.gradient(colors[0].value(), colors[1].value(), colors[2].value(), colors[3].value());
memory::copy(target, fill.data(), fill.size());
} else {
uint32 color = state().color.value();
for(auto n : range(width * height)) target[n] = color;
}
}
}
}
#endif

48
cocoa/widget/canvas.hpp Normal file
View file

@ -0,0 +1,48 @@
#if defined(Hiro_Canvas)
@interface CocoaCanvas : NSImageView {
@public
hiro::mCanvas* canvas;
}
-(id) initWith:(hiro::mCanvas&)canvas;
-(NSDragOperation) draggingEntered:(id<NSDraggingInfo>)sender;
-(BOOL) performDragOperation:(id<NSDraggingInfo>)sender;
-(void) mouseButton:(NSEvent*)event down:(BOOL)isDown;
-(void) mouseExited:(NSEvent*)event;
-(void) mouseMove:(NSEvent*)event;
-(void) mouseDown:(NSEvent*)event;
-(void) mouseUp:(NSEvent*)event;
-(void) mouseDragged:(NSEvent*)event;
-(void) rightMouseDown:(NSEvent*)event;
-(void) rightMouseUp:(NSEvent*)event;
-(void) rightMouseDragged:(NSEvent*)event;
-(void) otherMouseDown:(NSEvent*)event;
-(void) otherMouseUp:(NSEvent*)event;
-(void) otherMouseDragged:(NSEvent*)event;
@end
namespace hiro {
struct pCanvas : pWidget {
Declare(Canvas, Widget)
auto minimumSize() const -> Size;
auto setColor(Color color) -> void;
auto setDroppable(bool droppable) -> void;
auto setGeometry(Geometry geometry) -> void override;
auto setGradient(Gradient gradient) -> void;
auto setIcon(const image& icon) -> void;
auto update() -> void;
auto _rasterize() -> void;
CocoaCanvas* cocoaCanvas = nullptr;
NSImage* surface = nullptr;
NSBitmapImageRep* bitmap = nullptr;
uint surfaceWidth = 0;
uint surfaceHeight = 0;
};
}
#endif

View file

@ -0,0 +1,99 @@
#if defined(Hiro_CheckButton)
@implementation CocoaCheckButton : NSButton
-(id) initWith:(hiro::mCheckButton&)checkButtonReference {
if(self = [super initWithFrame:NSMakeRect(0, 0, 0, 0)]) {
checkButton = &checkButtonReference;
[self setTarget:self];
[self setAction:@selector(activate:)];
[self setBezelStyle:NSRegularSquareBezelStyle];
[self setButtonType:NSOnOffButton];
}
return self;
}
-(IBAction) activate:(id)sender {
checkButton->state.checked = [self state] != NSOffState;
checkButton->doToggle();
}
@end
namespace hiro {
auto pCheckButton::construct() -> void {
@autoreleasepool {
cocoaView = cocoaCheckButton = [[CocoaCheckButton alloc] initWith:self()];
pWidget::construct();
setBordered(state().bordered);
setChecked(state().checked);
setIcon(state().icon);
setOrientation(state().orientation);
setText(state().text);
}
}
auto pCheckButton::destruct() -> void {
@autoreleasepool {
[cocoaView removeFromSuperview];
[cocoaView release];
}
}
auto pCheckButton::minimumSize() const -> Size {
Size size = pFont::size(self().font(true), state().text);
if(state().orientation == Orientation::Horizontal) {
size.setWidth(size.width() + state().icon.width());
size.setHeight(max(size.height(), state().icon.height()));
}
if(state().orientation == Orientation::Vertical) {
size.setWidth(max(size.width(), state().icon.width()));
size.setHeight(size.height() + state().icon.height());
}
return {size.width() + (state().text ? 20 : 8), size.height() + 8};
}
auto pCheckButton::setBordered(bool bordered) -> void {
}
auto pCheckButton::setChecked(bool checked) -> void {
@autoreleasepool {
[cocoaView setState:checked ? NSOnState : NSOffState];
}
}
auto pCheckButton::setGeometry(Geometry geometry) -> void {
pWidget::setGeometry({
geometry.x() - 2, geometry.y() - 2,
geometry.width() + 4, geometry.height() + 4
});
}
auto pCheckButton::setIcon(const image& icon) -> void {
@autoreleasepool {
[cocoaView setImage:NSMakeImage(icon)];
}
}
auto pCheckButton::setOrientation(Orientation orientation) -> void {
@autoreleasepool {
if(orientation == Orientation::Horizontal) [cocoaView setImagePosition:NSImageLeft];
if(orientation == Orientation::Vertical ) [cocoaView setImagePosition:NSImageAbove];
}
}
auto pCheckButton::setText(const string& text) -> void {
@autoreleasepool {
[cocoaView setTitle:[NSString stringWithUTF8String:text]];
}
}
}
#endif

View file

@ -0,0 +1,29 @@
#if defined(Hiro_CheckButton)
@interface CocoaCheckButton : NSButton {
@public
hiro::mCheckButton* checkButton;
}
-(id) initWith:(hiro::mCheckButton&)checkButton;
-(IBAction) activate:(id)sender;
@end
namespace hiro {
struct pCheckButton : pWidget {
Declare(CheckButton, Widget)
auto minimumSize() const -> Size override;
auto setBordered(bool bordered) -> void;
auto setChecked(bool checked) -> void;
auto setGeometry(Geometry geometry) -> void override;
auto setIcon(const image& icon) -> void;
auto setOrientation(Orientation orientation) -> void;
auto setText(const string& text) -> void;
CocoaCheckButton* cocoaCheckButton = nullptr;
};
}
#endif

View file

@ -0,0 +1,68 @@
#if defined(Hiro_CheckLabel)
@implementation CocoaCheckLabel : NSButton
-(id) initWith:(hiro::mCheckLabel&)checkLabelReference {
if(self = [super initWithFrame:NSMakeRect(0, 0, 0, 0)]) {
checkLabel = &checkLabelReference;
[self setTarget:self];
[self setAction:@selector(activate:)];
[self setButtonType:NSSwitchButton];
}
return self;
}
-(IBAction) activate:(id)sender {
checkLabel->state.checked = [self state] != NSOffState;
checkLabel->doToggle();
}
@end
namespace hiro {
auto pCheckLabel::construct() -> void {
@autoreleasepool {
cocoaView = cocoaCheckLabel = [[CocoaCheckLabel alloc] initWith:self()];
pWidget::construct();
setChecked(state().checked);
setText(state().text);
}
}
auto pCheckLabel::destruct() -> void {
@autoreleasepool {
[cocoaView removeFromSuperview];
[cocoaView release];
}
}
auto pCheckLabel::minimumSize() const -> Size {
Size size = pFont::size(self().font(true), state().text);
return {size.width() + 20, size.height()};
}
auto pCheckLabel::setChecked(bool checked) -> void {
@autoreleasepool {
[cocoaView setState:checked ? NSOnState : NSOffState];
}
}
auto pCheckLabel::setGeometry(Geometry geometry) -> void {
pWidget::setGeometry({
geometry.x() - 2, geometry.y(),
geometry.width() + 4, geometry.height()
});
}
auto pCheckLabel::setText(const string& text) -> void {
@autoreleasepool {
[cocoaView setTitle:[NSString stringWithUTF8String:text]];
}
}
}
#endif

View file

@ -0,0 +1,26 @@
#if defined(Hiro_CheckLabel)
@interface CocoaCheckLabel : NSButton {
@public
hiro::mCheckLabel* checkLabel;
}
-(id) initWith:(hiro::mCheckLabel&)checkLabel;
-(IBAction) activate:(id)sender;
@end
namespace hiro {
struct pCheckLabel : pWidget {
Declare(CheckLabel, Widget)
auto minimumSize() const -> Size override;
auto setChecked(bool checked) -> void;
auto setGeometry(Geometry geometry) -> void;
auto setText(const string& text) -> void;
CocoaCheckLabel* cocoaCheckLabel = nullptr;
};
}
#endif

View file

@ -0,0 +1,39 @@
#if defined(Hiro_ComboButton)
namespace hiro {
auto pComboButtonItem::construct() -> void {
}
auto pComboButtonItem::destruct() -> void {
}
auto pComboButtonItem::setIcon(const image& icon) -> void {
}
auto pComboButtonItem::setSelected() -> void {
@autoreleasepool {
if(auto parent = _parent()) {
[parent->cocoaView selectItemAtIndex:self().offset()];
}
}
}
auto pComboButtonItem::setText(const string& text) -> void {
@autoreleasepool {
if(auto parent = _parent()) {
[[parent->cocoaView itemAtIndex:self().offset()] setTitle:[NSString stringWithUTF8String:text]];
}
}
}
auto pComboButtonItem::_parent() -> maybe<pComboButton&> {
if(auto parent = self().parentComboButton()) {
if(auto self = parent->self()) return *self;
}
return nothing;
}
}
#endif

View file

@ -0,0 +1,17 @@
#if defined(Hiro_ComboButton)
namespace hiro {
struct pComboButtonItem : pObject {
Declare(ComboButtonItem, Object)
auto setIcon(const image& icon) -> void;
auto setSelected() -> void;
auto setText(const string& text) -> void;
auto _parent() -> maybe<pComboButton&>;
};
}
#endif

View file

@ -0,0 +1,81 @@
#if defined(Hiro_ComboButton)
@implementation CocoaComboButton : NSPopUpButton
-(id) initWith:(hiro::mComboButton&)comboButtonReference {
if(self = [super initWithFrame:NSMakeRect(0, 0, 0, 0) pullsDown:NO]) {
comboButton = &comboButtonReference;
[self setTarget:self];
[self setAction:@selector(activate:)];
}
return self;
}
-(IBAction) activate:(id)sender {
if(auto p = comboButton->self()) p->_updateSelected([self indexOfSelectedItem]);
comboButton->doChange();
}
@end
namespace hiro {
auto pComboButton::construct() -> void {
@autoreleasepool {
cocoaView = cocoaComboButton = [[CocoaComboButton alloc] initWith:self()];
pWidget::construct();
}
}
auto pComboButton::destruct() -> void {
@autoreleasepool {
[cocoaView removeFromSuperview];
[cocoaView release];
}
}
auto pComboButton::append(sComboButtonItem item) -> void {
@autoreleasepool {
[cocoaView addItemWithTitle:[NSString stringWithUTF8String:item->text()]];
}
}
auto pComboButton::minimumSize() const -> Size {
auto font = self().font(true);
int maximumWidth = 0;
for(auto& item : state().items) {
maximumWidth = max(maximumWidth, pFont::size(font, item->state.text).width());
}
Size size = pFont::size(font, " ");
return {maximumWidth + 36, size.height() + 6};
}
auto pComboButton::remove(sComboButtonItem item) -> void {
@autoreleasepool {
[cocoaView removeItemAtIndex:item->offset()];
}
}
auto pComboButton::reset() -> void {
@autoreleasepool {
[cocoaView removeAllItems];
}
}
auto pComboButton::setGeometry(Geometry geometry) -> void {
pWidget::setGeometry({
geometry.x() - 2, geometry.y(),
geometry.width() + 4, geometry.height()
});
}
auto pComboButton::_updateSelected(signed selected) -> void {
for(auto& item : state().items) {
item->state.selected = item->offset() == selected;
}
}
}
#endif

View file

@ -0,0 +1,29 @@
#if defined(Hiro_ComboButton)
@interface CocoaComboButton : NSPopUpButton {
@public
hiro::mComboButton* comboButton;
}
-(id) initWith:(hiro::mComboButton&)comboButton;
-(IBAction) activate:(id)sender;
@end
namespace hiro {
struct pComboButton : pWidget {
Declare(ComboButton, Widget)
auto append(sComboButtonItem item) -> void;
auto minimumSize() const -> Size override;
auto remove(sComboButtonItem item) -> void;
auto reset() -> void;
auto setGeometry(Geometry geometry) -> void override;
auto _updateSelected(signed selected) -> void;
CocoaComboButton* cocoaComboButton = nullptr;
};
}
#endif

46
cocoa/widget/console.cpp Normal file
View file

@ -0,0 +1,46 @@
#if defined(Hiro_Console)
@implementation CocoaConsole : NSScrollView
-(id) initWith:(phoenix::Console&)consoleReference {
if(self = [super initWithFrame:NSMakeRect(0, 0, 0, 0)]) {
console = &consoleReference;
}
return self;
}
@end
namespace hiro {
void pConsole::print(string text) {
}
void pConsole::reset() {
}
void pConsole::setBackgroundColor(Color color) {
}
void pConsole::setForegroundColor(Color color) {
}
void pConsole::setPrompt(string prompt) {
}
void pConsole::constructor() {
@autoreleasepool {
cocoaView = cocoaConsole = [[CocoaConsole alloc] initWith:console];
}
}
void pConsole::destructor() {
@autoreleasepool {
[cocoaView removeFromSuperview];
[cocoaView release];
}
}
}
#endif

29
cocoa/widget/console.hpp Normal file
View file

@ -0,0 +1,29 @@
#if defined(Hiro_Console)
@interface CocoaConsole : NSScrollView {
@public
phoenix::Console* console;
}
-(id) initWith:(phoenix::Console&)console;
@end
namespace hiro {
struct pConsole : public pWidget {
Console& console;
CocoaConsole* cocoaConsole = nullptr;
void print(string text);
void reset();
void setBackgroundColor(Color color);
void setForegroundColor(Color color);
void setPrompt(string prompt);
pConsole(Console& console) : pWidget(console), console(console) {}
void constructor();
void destructor();
};
}
#endif

87
cocoa/widget/frame.cpp Normal file
View file

@ -0,0 +1,87 @@
#if defined(Hiro_Frame)
@implementation CocoaFrame : NSBox
-(id) initWith:(hiro::mFrame&)frameReference {
if(self = [super initWithFrame:NSMakeRect(0, 0, 0, 0)]) {
frame = &frameReference;
[self setTitle:@""];
}
return self;
}
@end
namespace hiro {
auto pFrame::construct() -> void {
@autoreleasepool {
cocoaView = cocoaFrame = [[CocoaFrame alloc] initWith:self()];
pWidget::construct();
setText(state().text);
}
}
auto pFrame::destruct() -> void {
@autoreleasepool {
[cocoaView removeFromSuperview];
[cocoaView release];
}
}
auto pFrame::append(sLayout layout) -> void {
}
auto pFrame::remove(sLayout layout) -> void {
}
auto pFrame::setEnabled(bool enabled) -> void {
pWidget::setEnabled(enabled);
if(auto layout = _layout()) layout->setEnabled(layout->self().enabled(true));
}
auto pFrame::setFont(const Font& font) -> void {
@autoreleasepool {
[cocoaView setTitleFont:pFont::create(font)];
}
if(auto layout = _layout()) layout->setFont(layout->self().font(true));
}
auto pFrame::setGeometry(Geometry geometry) -> void {
bool empty = !state().text;
Size size = pFont::size(self().font(true), state().text);
pWidget::setGeometry({
geometry.x() - 3, geometry.y() - (empty ? size.height() - 2 : 1),
geometry.width() + 6, geometry.height() + (empty ? size.height() + 2 : 5)
});
if(auto layout = state().layout) {
layout->setGeometry({
geometry.x() + 1, geometry.y() + (empty ? 1 : size.height() - 2),
geometry.width() - 2, geometry.height() - (empty ? 1 : size.height() - 1)
});
}
}
auto pFrame::setText(const string& text) -> void {
@autoreleasepool {
[cocoaView setTitle:[NSString stringWithUTF8String:text]];
}
}
auto pFrame::setVisible(bool visible) -> void {
pWidget::setVisible(visible);
if(auto layout = _layout()) layout->setVisible(layout->self().visible(true));
}
auto pFrame::_layout() -> maybe<pLayout&> {
if(auto layout = state().layout) {
if(auto self = layout->self()) return *self;
}
return nothing;
}
}
#endif

30
cocoa/widget/frame.hpp Normal file
View file

@ -0,0 +1,30 @@
#if defined(Hiro_Frame)
@interface CocoaFrame : NSBox {
@public
hiro::mFrame* frame;
}
-(id) initWith:(hiro::mFrame&)frame;
@end
namespace hiro {
struct pFrame : pWidget {
Declare(Frame, Widget)
auto append(sLayout layout) -> void;
auto remove(sLayout layout) -> void;
auto setEnabled(bool enabled) -> void override;
auto setFont(const Font& font) -> void override;
auto setGeometry(Geometry geometry) -> void override;
auto setText(const string& text) -> void;
auto setVisible(bool visible) -> void override;
auto _layout() -> maybe<pLayout&>;
CocoaFrame* cocoaFrame = nullptr;
};
}
#endif

52
cocoa/widget/hex-edit.cpp Normal file
View file

@ -0,0 +1,52 @@
#if defined(Hiro_HexEdit)
@implementation CocoaHexEdit : NSScrollView
-(id) initWith:(phoenix::HexEdit&)hexEditReference {
if(self = [super initWithFrame:NSMakeRect(0, 0, 0, 0)]) {
hexEdit = &hexEditReference;
}
return self;
}
@end
namespace hiro {
void pHexEdit::setBackgroundColor(Color color) {
}
void pHexEdit::setColumns(unsigned columns) {
}
void pHexEdit::setForegroundColor(Color color) {
}
void pHexEdit::setLength(unsigned length) {
}
void pHexEdit::setOffset(unsigned offset) {
}
void pHexEdit::setRows(unsigned rows) {
}
void pHexEdit::update() {
}
void pHexEdit::constructor() {
@autoreleasepool {
cocoaView = cocoaHexEdit = [[CocoaHexEdit alloc] initWith:hexEdit];
}
}
void pHexEdit::destructor() {
@autoreleasepool {
[cocoaView removeFromSuperview];
[cocoaView release];
}
}
}
#endif

31
cocoa/widget/hex-edit.hpp Normal file
View file

@ -0,0 +1,31 @@
#if defined(Hiro_HexEdit)
@interface CocoaHexEdit : NSScrollView {
@public
phoenix::HexEdit* hexEdit;
}
-(id) initWith:(phoenix::HexEdit&)hexEdit;
@end
namespace hiro {
struct pHexEdit : public pWidget {
HexEdit& hexEdit;
CocoaHexEdit* cocoaHexEdit = nullptr;
void setBackgroundColor(Color color);
void setColumns(unsigned columns);
void setForegroundColor(Color color);
void setLength(unsigned length);
void setOffset(unsigned offset);
void setRows(unsigned rows);
void update();
pHexEdit(HexEdit& hexEdit) : pWidget(hexEdit), hexEdit(hexEdit) {}
void constructor();
void destructor();
};
}
#endif

View file

@ -0,0 +1,94 @@
#if defined(Hiro_HorizontalScrollBar)
@implementation CocoaHorizontalScrollBar : NSScroller
-(id) initWith:(hiro::mHorizontalScrollBar&)horizontalScrollBarReference {
if(self = [super initWithFrame:NSMakeRect(0, 0, 1, 0)]) {
horizontalScrollBar = &horizontalScrollBarReference;
[self setTarget:self];
[self setAction:@selector(scroll:)];
[self setControlSize:NSRegularControlSize];
[self setScrollerStyle:NSScrollerStyleLegacy];
[self setEnabled:YES];
[self update];
}
return self;
}
-(void) update {
double d = 1.0 / horizontalScrollBar->state.length;
double f = d * horizontalScrollBar->state.position;
[self setDoubleValue:f];
[self setKnobProportion:d];
}
-(IBAction) scroll:(id)sender {
auto& state = horizontalScrollBar->state;
switch([self hitPart]) {
case NSScrollerIncrementLine:
case NSScrollerIncrementPage:
if(state.position < state.length - 1) state.position++;
[self update];
break;
case NSScrollerDecrementLine:
case NSScrollerDecrementPage:
if(state.position) state.position--;
[self update];
break;
case NSScrollerKnob:
state.position = [self doubleValue] * state.length;
break;
}
horizontalScrollBar->doChange();
}
@end
namespace hiro {
auto pHorizontalScrollBar::construct() -> void {
@autoreleasepool {
cocoaView = cocoaHorizontalScrollBar = [[CocoaHorizontalScrollBar alloc] initWith:self()];
pWidget::construct();
setLength(state().length);
setPosition(state().position);
}
}
auto pHorizontalScrollBar::destruct() -> void {
@autoreleasepool {
[cocoaView removeFromSuperview];
[cocoaView release];
}
}
auto pHorizontalScrollBar::minimumSize() const -> Size {
@autoreleasepool {
return {32, (int)[NSScroller scrollerWidthForControlSize:NSRegularControlSize scrollerStyle:NSScrollerStyleLegacy]};
}
}
auto pHorizontalScrollBar::setLength(uint length) -> void {
@autoreleasepool {
[cocoaView update];
}
}
auto pHorizontalScrollBar::setPosition(uint position) -> void {
@autoreleasepool {
[cocoaView update];
}
}
}
#endif

View file

@ -0,0 +1,26 @@
#if defined(Hiro_HorizontalScrollBar)
@interface CocoaHorizontalScrollBar : NSScroller {
@public
hiro::mHorizontalScrollBar* horizontalScrollBar;
}
-(id) initWith:(hiro::mHorizontalScrollBar&)horizontalScrollBar;
-(void) update;
-(IBAction) scroll:(id)sender;
@end
namespace hiro {
struct pHorizontalScrollBar : pWidget {
Declare(HorizontalScrollBar, Widget)
auto minimumSize() const -> Size override;
auto setLength(uint length) -> void;
auto setPosition(uint position) -> void;
CocoaHorizontalScrollBar* cocoaHorizontalScrollBar = nullptr;
};
}
#endif

View file

@ -0,0 +1,67 @@
#if defined(Hiro_HorizontalSlider)
@implementation CocoaHorizontalSlider : NSSlider
-(id) initWith:(hiro::mHorizontalSlider&)horizontalSliderReference {
if(self = [super initWithFrame:NSMakeRect(0, 0, 1, 0)]) {
horizontalSlider = &horizontalSliderReference;
[self setTarget:self];
[self setAction:@selector(activate:)];
[self setMinValue:0];
}
return self;
}
-(IBAction) activate:(id)sender {
horizontalSlider->state.position = [self doubleValue];
horizontalSlider->doChange();
}
@end
namespace hiro {
auto pHorizontalSlider::construct() -> void {
@autoreleasepool {
cocoaView = cocoaHorizontalSlider = [[CocoaHorizontalSlider alloc] initWith:self()];
pWidget::construct();
setLength(state().length);
setPosition(state().position);
}
}
auto pHorizontalSlider::destruct() -> void {
@autoreleasepool {
[cocoaView removeFromSuperview];
[cocoaView release];
}
}
auto pHorizontalSlider::minimumSize() const -> Size {
return {48, 20};
}
auto pHorizontalSlider::setGeometry(Geometry geometry) -> void {
pWidget::setGeometry({
geometry.x() - 2, geometry.y(),
geometry.width() + 4, geometry.height()
});
}
auto pHorizontalSlider::setLength(uint length) -> void {
@autoreleasepool {
[cocoaView setMaxValue:length];
}
}
auto pHorizontalSlider::setPosition(uint position) -> void {
@autoreleasepool {
[cocoaView setDoubleValue:position];
}
}
}
#endif

View file

@ -0,0 +1,26 @@
#if defined(Hiro_HorizontalSlider)
@interface CocoaHorizontalSlider : NSSlider {
@public
hiro::mHorizontalSlider* horizontalSlider;
}
-(id) initWith:(hiro::mHorizontalSlider&)horizontalSlider;
-(IBAction) activate:(id)sender;
@end
namespace hiro {
struct pHorizontalSlider : pWidget {
Declare(HorizontalSlider, Widget)
auto minimumSize() const -> Size override;
auto setGeometry(Geometry geometry) -> void;
auto setLength(uint length) -> void;
auto setPosition(uint position) -> void;
CocoaHorizontalSlider* cocoaHorizontalSlider = nullptr;
};
}
#endif

77
cocoa/widget/label.cpp Normal file
View file

@ -0,0 +1,77 @@
#if defined(Hiro_Label)
@implementation CocoaLabel : NSTextView
-(id) initWith:(hiro::mLabel&)labelReference {
if(self = [super initWithFrame:NSMakeRect(0, 0, 0, 0)]) {
label = &labelReference;
[self setDrawsBackground:NO];
[self setEditable:NO];
[self setRichText:NO];
}
return self;
}
@end
namespace hiro {
auto pLabel::construct() -> void {
@autoreleasepool {
cocoaView = cocoaLabel = [[CocoaLabel alloc] initWith:self()];
pWidget::construct();
setAlignment(state().alignment);
setText(state().text);
}
}
auto pLabel::destruct() -> void {
@autoreleasepool {
[cocoaView removeFromSuperview];
[cocoaView release];
}
}
auto pLabel::minimumSize() const -> Size {
return pFont::size(self().font(true), state().text);
}
auto pLabel::setAlignment(Alignment alignment) -> void {
@autoreleasepool {
NSMutableParagraphStyle* paragraphStyle = [[NSParagraphStyle defaultParagraphStyle] mutableCopy];
paragraphStyle.alignment = NSTextAlignmentCenter;
if(alignment.horizontal() < 0.333) paragraphStyle.alignment = NSTextAlignmentLeft;
if(alignment.horizontal() > 0.666) paragraphStyle.alignment = NSTextAlignmentRight;
[cocoaView setDefaultParagraphStyle:paragraphStyle];
}
}
auto pLabel::setGeometry(Geometry geometry) -> void {
//NSTextView does not support vertical text centering:
//simulate this by adjusting the geometry placement (reduce height, move view down)
uint height = pFont::size(self().font(true), state().text).height();
auto offset = geometry;
if(geometry.height() > height) {
uint diff = geometry.height() - height;
offset.setY(offset.y() + (diff >> 1));
offset.setHeight(offset.height() - (diff >> 1));
}
pWidget::setGeometry({
offset.x() - 6, offset.y(),
offset.width() + 12, offset.height()
});
}
auto pLabel::setText(const string& text) -> void {
@autoreleasepool {
[cocoaView setString:[NSString stringWithUTF8String:text]];
}
}
}
#endif

25
cocoa/widget/label.hpp Normal file
View file

@ -0,0 +1,25 @@
#if defined(Hiro_Label)
@interface CocoaLabel : NSTextView {
@public
hiro::mLabel* label;
}
-(id) initWith:(hiro::mLabel&)label;
@end
namespace hiro {
struct pLabel : pWidget {
Declare(Label, Widget)
auto minimumSize() const -> Size override;
auto setAlignment(Alignment alignment) -> void;
auto setGeometry(Geometry geometry) -> void override;
auto setText(const string& text) -> void;
CocoaLabel* cocoaLabel = nullptr;
};
}
#endif

View file

@ -0,0 +1,83 @@
#if defined(Hiro_LineEdit)
@implementation CocoaLineEdit : NSTextField
-(id) initWith:(hiro::mLineEdit&)lineEditReference {
if(self = [super initWithFrame:NSMakeRect(0, 0, 0, 0)]) {
lineEdit = &lineEditReference;
[self setDelegate:self];
[self setTarget:self];
[self setAction:@selector(activate:)];
//prevent focus changes from generating activate event
[[self cell] setSendsActionOnEndEditing:NO];
}
return self;
}
-(void) textDidChange:(NSNotification*)n {
lineEdit->doChange();
}
-(IBAction) activate:(id)sender {
lineEdit->doActivate();
}
@end
namespace hiro {
auto pLineEdit::construct() -> void {
@autoreleasepool {
cocoaView = cocoaLineEdit = [[CocoaLineEdit alloc] initWith:self()];
pWidget::construct();
setBackgroundColor(state().backgroundColor);
setEditable(state().editable);
setForegroundColor(state().foregroundColor);
setText(state().text);
}
}
auto pLineEdit::destruct() -> void {
@autoreleasepool {
[cocoaView removeFromSuperview];
[cocoaView release];
}
}
auto pLineEdit::minimumSize() const -> Size {
Size size = pFont::size(self().font(true), state().text);
return {size.width() + 10, size.height() + 8};
}
auto pLineEdit::setBackgroundColor(Color color) -> void {
}
auto pLineEdit::setEditable(bool editable) -> void {
@autoreleasepool {
[cocoaView setEditable:editable];
}
}
auto pLineEdit::setForegroundColor(Color color) -> void {
}
auto pLineEdit::setText(const string& text) -> void {
@autoreleasepool {
[cocoaView setStringValue:[NSString stringWithUTF8String:text]];
}
}
/*
auto pLineEdit::text() const -> string {
@autoreleasepool {
return [[cocoaView stringValue] UTF8String];
}
}
*/
}
#endif

View file

@ -0,0 +1,28 @@
#if defined(Hiro_LineEdit)
@interface CocoaLineEdit : NSTextField <NSTextFieldDelegate> {
@public
hiro::mLineEdit* lineEdit;
}
-(id) initWith:(hiro::mLineEdit&)lineEdit;
-(void) textDidChange:(NSNotification*)n;
-(IBAction) activate:(id)sender;
@end
namespace hiro {
struct pLineEdit : pWidget {
Declare(LineEdit, Widget)
auto minimumSize() const -> Size override;
auto setBackgroundColor(Color color) -> void;
auto setEditable(bool editable) -> void;
auto setForegroundColor(Color color) -> void;
auto setText(const string& text) -> void;
CocoaLineEdit* cocoaLineEdit = nullptr;
};
}
#endif

View file

@ -0,0 +1,50 @@
#if defined(Hiro_ListView)
namespace hiro {
auto pListViewCell::construct() -> void {
}
auto pListViewCell::destruct() -> void {
}
auto pListViewCell::setAlignment(Alignment alignment) -> void {
}
auto pListViewCell::setBackgroundColor(Color color) -> void {
}
auto pListViewCell::setCheckable(bool checkable) -> void {
}
auto pListViewCell::setChecked(bool checked) -> void {
}
auto pListViewCell::setForegroundColor(Color color) -> void {
}
auto pListViewCell::setIcon(const image& icon) -> void {
}
auto pListViewCell::setText(const string& text) -> void {
@autoreleasepool {
if(auto pListView = _grandparent()) {
[[pListView->cocoaView content] reloadData];
}
}
}
auto pListViewCell::_grandparent() -> maybe<pListView&> {
if(auto parent = _parent()) return parent->_parent();
}
auto pListViewCell::_parent() -> maybe<pListViewItem&> {
if(auto parent = self().parentListViewItem()) {
if(auto self = parent->self()) return *self;
}
return nothing;
}
}
#endif

View file

@ -0,0 +1,22 @@
#if defined(Hiro_ListView)
namespace hiro {
struct pListViewCell : pObject {
Declare(ListViewCell, Object)
auto setAlignment(Alignment alignment) -> void;
auto setBackgroundColor(Color color) -> void;
auto setCheckable(bool checkable) -> void;
auto setChecked(bool checked) -> void;
auto setForegroundColor(Color color) -> void;
auto setIcon(const image& icon) -> void;
auto setText(const string& text) -> void;
auto _grandparent() -> maybe<pListView&>;
auto _parent() -> maybe<pListViewItem&>;
};
}
#endif

View file

@ -0,0 +1,87 @@
#if defined(Hiro_ListView)
namespace hiro {
auto pListViewColumn::construct() -> void {
@autoreleasepool {
if(auto listView = _grandparent()) {
[listView->cocoaView reloadColumns];
}
}
}
auto pListViewColumn::destruct() -> void {
@autoreleasepool {
if(auto listView = _grandparent()) {
[listView->cocoaView reloadColumns];
}
}
}
auto pListViewColumn::setActive() -> void {
}
auto pListViewColumn::setAlignment(Alignment alignment) -> void {
}
auto pListViewColumn::setBackgroundColor(Color color) -> void {
}
auto pListViewColumn::setEditable(bool editable) -> void {
}
auto pListViewColumn::setExpandable(bool expandable) -> void {
}
auto pListViewColumn::setFont(const Font& font) -> void {
}
auto pListViewColumn::setForegroundColor(Color color) -> void {
}
auto pListViewColumn::setHorizontalAlignment(double alignment) -> void {
}
auto pListViewColumn::setIcon(const image& icon) -> void {
}
auto pListViewColumn::setResizable(bool resizable) -> void {
}
auto pListViewColumn::setSortable(bool sortable) -> void {
}
auto pListViewColumn::setText(const string& text) -> void {
@autoreleasepool {
if(auto pListView = _grandparent()) {
NSTableColumn* tableColumn = [[pListView->cocoaView content] tableColumnWithIdentifier:[[NSNumber numberWithInteger:self().offset()] stringValue]];
[[tableColumn headerCell] setStringValue:[NSString stringWithUTF8STring:text]];
[[pListView->cocoaView headerView] setNeedsDisplay:YES];
}
}
}
auto pListViewColumn::setVerticalAlignment(double alignment) -> void {
}
auto pListViewColumn::setVisible(bool visible) -> void {
}
auto pListViewColumn::setWidth(signed width) -> void {
}
auto pListViewColumn::_grandparent() -> maybe<pListView&> {
if(auto parent = _parent()) return parent->_parent();
return nothing;
}
auto pListViewColumn::_parent() -> maybe<pListViewHeader&> {
if(auto parent = self().parentListViewHeader()) {
if(auto self = parent->self()) return *self;
}
return nothing;
}
}
#endif

View file

@ -0,0 +1,30 @@
#if defined(Hiro_ListView)
namespace hiro {
struct pListViewColumn : pObject {
Declare(ListViewColumn, Object)
auto setActive() -> void;
auto setAlignment(Alignment alignment) -> void;
auto setBackgroundColor(Color color) -> void;
auto setEditable(bool editable) -> void;
auto setExpandable(bool expandable) -> void;
auto setFont(const Font& font) -> void override;
auto setForegroundColor(Color color) -> void;
auto setHorizontalAlignment(double) -> void;
auto setIcon(const image& icon) -> void;
auto setResizable(bool resizable) -> void;
auto setSortable(bool sortable) -> void;
auto setText(const string& text) -> void;
auto setVerticalAlignment(double) -> void;
auto setVisible(bool visible) -> void override;
auto setWidth(signed width) -> void;
auto _grandparent() -> maybe<pListView&>;
auto _parent() -> maybe<pListViewHeader&>;
};
}
#endif

View file

@ -0,0 +1,38 @@
#if defined(Hiro_ListView)
namespace hiro {
auto pListViewHeader::construct() -> void {
}
auto pListViewHeader::destruct() -> void {
}
auto pListViewHeader::append(sListViewColumn column) -> void {
}
auto pListViewHeader::remove(sListViewColumn column) -> void {
}
auto pListViewHeader::setVisible(bool visible) -> void {
@autoreleasepool {
if(auto pListView = _parent()) {
if(visible) {
[[pListView->cocoaView content] setHeaderView:[[[NSTableHeaderView alloc] init] autorelease]];
} else {
[[pListView->cocoaView content] setHeaderView:nil];
}
}
}
}
auto pListViewHeader::_parent() -> maybe<pListView&> {
if(auto parent = self().parentListView()) {
if(auto self = parent->self()) return *self;
}
return nothing;
}
}
#endif

View file

@ -0,0 +1,17 @@
#if defined(Hiro_ListView)
namespace hiro {
struct pListViewHeader : pObject {
Declare(ListViewHeader, Object)
auto append(sListViewColumn column) -> void;
auto remove(sListViewColumn column) -> void;
auto setVisible(bool visible) -> void override;
auto _parent() -> maybe<pListView&>;
};
}
#endif

View file

@ -0,0 +1,51 @@
#if defined(Hiro_ListView)
namespace hiro {
auto pListViewItem::construct() -> void {
}
auto pListViewItem::destruct() -> void {
}
auto pListViewItem::append(sListViewCell cell) -> void {
@autoreleasepool {
if(auto listView = _parent()) {
[[listView->cocoaView content] reloadData];
}
}
}
auto pListViewItem::remove(sListViewCell cell) -> void {
@autoreleasepool {
if(auto listView = _parent()) {
[[listView->cocoaView content] reloadData];
}
}
}
auto pListViewItem::setAlignment(Alignment alignment) -> void {
}
auto pListViewItem::setBackgroundColor(Color color) -> void {
}
auto pListViewItem::setFocused() -> void {
}
auto pListViewItem::setForegroundColor(Color color) -> void {
}
auto pListViewItem::setSelected(bool selected) -> void {
}
auto pListViewItem::_parent() -> maybe<pListView&> {
if(auto parent = self().parentListView()) {
if(auto self = parent->self()) return *self;
}
return nothing;
}
}
#endif

View file

@ -0,0 +1,21 @@
#if defined(Hiro_ListView)
namespace hiro {
struct pListViewItem : pObject {
Declare(ListViewItem, Object)
auto append(sListViewCell cell) -> void;
auto remove(sListViewCell cell) -> void;
auto setAlignment(Alignment alignment) -> void;
auto setBackgroundColor(Color color) -> void;
auto setFocused() -> void;
auto setForegroundColor(Color color) -> void;
auto setSelected(bool selected) -> void;
auto _parent() -> maybe<pListView&>;
};
}
#endif

455
cocoa/widget/list-view.cpp Normal file
View file

@ -0,0 +1,455 @@
#if defined(Hiro_ListView)
@implementation CocoaListView : NSScrollView
-(id) initWith:(hiro::mListView&)listViewReference {
if(self = [super initWithFrame:NSMakeRect(0, 0, 0, 0)]) {
listView = &listViewReference;
content = [[CocoaListViewContent alloc] initWithFrame:NSMakeRect(0, 0, 0, 0)];
[self setDocumentView:content];
[self setBorderType:NSBezelBorder];
[self setHasVerticalScroller:YES];
[content setDataSource:self];
[content setDelegate:self];
[content setTarget:self];
[content setDoubleAction:@selector(doubleAction:)];
[content setAllowsColumnReordering:NO];
[content setAllowsColumnResizing:YES];
[content setAllowsColumnSelection:NO];
[content setAllowsEmptySelection:YES];
[content setColumnAutoresizingStyle:NSTableViewLastColumnOnlyAutoresizingStyle];
font = nil;
[self setFont:nil];
}
return self;
}
-(void) dealloc {
[content release];
[font release];
[super dealloc];
}
-(CocoaListViewContent*) content {
return content;
}
-(NSFont*) font {
return font;
}
-(void) setFont:(NSFont*)fontPointer {
if(!fontPointer) fontPointer = [NSFont systemFontOfSize:12];
[fontPointer retain];
if(font) [font release];
font = fontPointer;
uint fontHeight = hiro::pFont::size(font, " ").height();
[content setFont:font];
[content setRowHeight:fontHeight];
[self reloadColumns];
}
-(void) reloadColumns {
while([[content tableColumns] count]) {
[content removeTableColumn:[[content tableColumns] lastObject]];
}
if(auto listViewHeader = listView->state.header) {
for(auto& listViewColumn : listViewHeader->state.columns) {
auto column = listViewColumn->offset();
NSTableColumn* tableColumn = [[NSTableColumn alloc] initWithIdentifier:[[NSNumber numberWithInteger:column] stringValue]];
NSTableHeaderCell* headerCell = [[NSTableHeaderCell alloc] initTextCell:[NSString stringWithUTF8String:listViewColumn->state.text]];
CocoaListViewCell* dataCell = [[CocoaListViewCell alloc] initWith:*listView];
[dataCell setEditable:NO];
[tableColumn setResizingMask:NSTableColumnAutoresizingMask | NSTableColumnUserResizingMask];
[tableColumn setHeaderCell:headerCell];
[tableColumn setDataCell:dataCell];
[content addTableColumn:tableColumn];
}
}
}
-(NSInteger) numberOfRowsInTableView:(NSTableView*)table {
return listView->state.items.size();
}
-(id) tableView:(NSTableView*)table objectValueForTableColumn:(NSTableColumn*)tableColumn row:(NSInteger)row {
if(auto listViewItem = listView->item(row)) {
if(auto listViewCell = listViewItem->cell([[tableColumn identifier] integerValue])) {
NSString* text = [NSString stringWithUTF8String:listViewCell->state.text];
return @{ @"text":text }; //used by type-ahead
}
}
return @{};
}
-(BOOL) tableView:(NSTableView*)table shouldShowCellExpansionForTableColumn:(NSTableColumn*)tableColumn row:(NSInteger)row {
return NO;
}
-(NSString*) tableView:(NSTableView*)table toolTipForCell:(NSCell*)cell rect:(NSRectPointer)rect tableColumn:(NSTableColumn*)tableColumn row:(NSInteger)row mouseLocation:(NSPoint)mouseLocation {
return nil;
}
-(void) tableView:(NSTableView*)tableView willDisplayCell:(id)cell forTableColumn:(NSTableColumn*)tableColumn row:(NSInteger)row {
[cell setFont:[self font]];
}
-(void) tableViewSelectionDidChange:(NSNotification*)notification {
for(auto& listViewItem : listView->state.items) {
listViewItem->state.selected = listViewItem->offset() == [content selectedRow];
}
listView->doChange();
}
-(IBAction) activate:(id)sender {
listView->doActivate();
}
-(IBAction) doubleAction:(id)sender {
if([content clickedRow] >= 0) {
[self activate:self];
}
}
@end
@implementation CocoaListViewContent : NSTableView
-(void) keyDown:(NSEvent*)event {
auto character = [[event characters] characterAtIndex:0];
if(character == NSEnterCharacter || character == NSCarriageReturnCharacter) {
if([self selectedRow] >= 0) {
[[self delegate] activate:self];
return;
}
}
[super keyDown:event];
}
@end
@implementation CocoaListViewCell : NSCell
-(id) initWith:(hiro::mListView&)listViewReference {
if(self = [super initTextCell:@""]) {
listView = &listViewReference;
buttonCell = [[NSButtonCell alloc] initTextCell:@""];
[buttonCell setButtonType:NSSwitchButton];
[buttonCell setControlSize:NSSmallControlSize];
[buttonCell setRefusesFirstResponder:YES];
[buttonCell setTarget:self];
}
return self;
}
//used by type-ahead
-(NSString*) stringValue {
return [[self objectValue] objectForKey:@"text"];
}
-(void) drawWithFrame:(NSRect)frame inView:(NSView*)view {
if(auto listViewItem = listView->item([view rowAtPoint:frame.origin])) {
if(auto listViewCell = listViewItem->cell([view columnAtPoint:frame.origin])) {
NSColor* backgroundColor = nil;
if([self isHighlighted]) backgroundColor = [NSColor alternateSelectedControlColor];
else if(!listView->enabled(true)) backgroundColor = [NSColor controlBackgroundColor];
else if(auto color = listViewCell->state.backgroundColor) backgroundColor = NSMakeColor(color);
else backgroundColor = [NSColor controlBackgroundColor];
[backgroundColor set];
[NSBezierPath fillRect:frame];
if(listViewCell->state.checkable) {
[buttonCell setHighlighted:YES];
[buttonCell setState:(listViewCell->state.checked ? NSOnState : NSOffState)];
[buttonCell drawWithFrame:frame inView:view];
frame.origin.x += frame.size.height + 2;
frame.size.width -= frame.size.height + 2;
}
if(listViewCell->state.icon) {
NSImage* image = NSMakeImage(listViewCell->state.icon, frame.size.height, frame.size.height);
[[NSGraphicsContext currentContext] saveGraphicsState];
NSRect targetRect = NSMakeRect(frame.origin.x, frame.origin.y, frame.size.height, frame.size.height);
NSRect sourceRect = NSMakeRect(0, 0, [image size].width, [image size].height);
[image drawInRect:targetRect fromRect:sourceRect operation:NSCompositeSourceOver fraction:1.0 respectFlipped:YES hints:nil];
[[NSGraphicsContext currentContext] restoreGraphicsState];
frame.origin.x += frame.size.height + 2;
frame.size.width -= frame.size.height + 2;
}
if(listViewCell->state.text) {
NSMutableParagraphStyle* paragraphStyle = [[NSParagraphStyle defaultParagraphStyle] mutableCopy];
paragraphStyle.alignment = NSTextAlignmentCenter;
if(listViewCell->state.alignment.horizontal() < 0.333) paragraphStyle.alignment = NSTextAlignmentLeft;
if(listViewCell->state.alignment.horizontal() > 0.666) paragraphStyle.alignment = NSTextAlignmentRight;
NSColor* foregroundColor = nil;
if([self isHighlighted]) foregroundColor = [NSColor alternateSelectedControlTextColor];
else if(!listView->enabled(true)) foregroundColor = [NSColor disabledControlTextColor];
else if(auto color = listViewCell->state.foregroundColor) foregroundColor = NSMakeColor(color);
else foregroundColor = [NSColor textColor];
NSString* text = [NSString stringWithUTF8String:listViewCell->state.text];
[text drawInRect:frame withAttributes:@{
NSBackgroundColorAttributeName:backgroundColor,
NSForegroundColorAttributeName:foregroundColor,
NSFontAttributeName:hiro::pFont::create(listViewCell->font(true)),
NSParagraphStyleAttributeName:paragraphStyle
}];
}
}
}
}
//needed to trigger trackMouse events
-(NSUInteger) hitTestForEvent:(NSEvent*)event inRect:(NSRect)frame ofView:(NSView*)view {
NSUInteger hitTest = [super hitTestForEvent:event inRect:frame ofView:view];
NSPoint point = [view convertPointFromBase:[event locationInWindow]];
NSRect rect = NSMakeRect(frame.origin.x, frame.origin.y, frame.size.height, frame.size.height);
if(NSMouseInRect(point, rect, [view isFlipped])) {
hitTest |= NSCellHitTrackableArea;
}
return hitTest;
}
//I am unable to get startTrackingAt:, continueTracking:, stopTracking: to work
//so instead, I have to run a modal loop on events until the mouse button is released
-(BOOL) trackMouse:(NSEvent*)event inRect:(NSRect)frame ofView:(NSView*)view untilMouseUp:(BOOL)flag {
if([event type] == NSLeftMouseDown) {
NSWindow* window = [view window];
NSEvent* nextEvent;
while((nextEvent = [window nextEventMatchingMask:(NSLeftMouseDragged | NSLeftMouseUp)])) {
if([nextEvent type] == NSLeftMouseUp) {
NSPoint point = [view convertPointFromBase:[nextEvent locationInWindow]];
NSRect rect = NSMakeRect(frame.origin.x, frame.origin.y, frame.size.height, frame.size.height);
if(NSMouseInRect(point, rect, [view isFlipped])) {
if(auto listViewItem = listView->item([view rowAtPoint:point])) {
if(auto listViewCell = listViewItem->cell([view columnAtPoint:point])) {
listViewCell->state.checked = !listViewCell->state.checked;
listView->doToggle(listViewCell->instance);
}
}
}
break;
}
}
}
return YES;
}
+(BOOL) prefersTrackingUntilMouseUp {
return YES;
}
@end
namespace hiro {
auto pListView::construct() -> void {
@autoreleasepool {
cocoaView = cocoaListView = [[CocoaListView alloc] initWith:self()];
pWidget::construct();
setAlignment(state().alignment);
setBackgroundColor(state().backgroundColor);
setBatchable(state().batchable);
setBordered(state().bordered);
setFont(self().font(true));
setForegroundColor(state().foregroundColor);
}
}
auto pListView::destruct() -> void {
@autoreleasepool {
[cocoaView removeFromSuperview];
[cocoaView release];
}
}
auto pListView::append(sListViewHeader header) -> void {
@autoreleasepool {
[cocoaView reloadColumns];
header->setVisible(header->visible());
}
}
auto pListView::append(sListViewItem item) -> void {
@autoreleasepool {
[[cocoaView content] reloadData];
}
}
auto pListView::remove(sListViewHeader header) -> void {
@autoreleasepool {
[cocoaView reloadColumns];
}
}
auto pListView::remove(sListViewItem item) -> void {
@autoreleasepool {
[[cocoaView content] reloadData];
}
}
auto pListView::resizeColumns() -> void {
@autoreleasepool {
if(auto& header = state().header) {
vector<int> widths;
int minimumWidth = 0;
int expandable = 0;
for(auto column : range(header->columnCount())) {
int width = _width(column);
widths.append(width);
minimumWidth += width;
if(header->column(column).expandable()) expandable++;
}
int maximumWidth = self().geometry().width() - 18; //include margin for vertical scroll bar
int expandWidth = 0;
if(expandable && maximumWidth > minimumWidth) {
expandWidth = (maximumWidth - minimumWidth) / expandable;
}
for(auto column : range(header->columnCount())) {
if(auto self = header->state.columns[column]->self()) {
int width = widths[column];
if(self->state().expandable) width += expandWidth;
NSTableColumn* tableColumn = [[cocoaView content] tableColumnWithIdentifier:[[NSNumber numberWithInteger:column] stringValue]];
[tableColumn setWidth:width];
}
}
}
}
}
auto pListView::setAlignment(Alignment alignment) -> void {
}
auto pListView::setBackgroundColor(Color color) -> void {
}
auto pListView::setBatchable(bool batchable) -> void {
@autoreleasepool {
[[cocoaView content] setAllowsMultipleSelection:(batchable ? YES : NO)];
}
}
auto pListView::setBordered(bool bordered) -> void {
}
auto pListView::setEnabled(bool enabled) -> void {
pWidget::setEnabled(enabled);
@autoreleasepool {
[[cocoaView content] setEnabled:enabled];
}
}
auto pListView::setFont(const Font& font) -> void {
@autoreleasepool {
[cocoaView setFont:pFont::create(font)];
}
}
auto pListView::setForegroundColor(Color color) -> void {
}
auto pListView::_cellWidth(uint row, uint column) -> uint {
uint width = 8;
if(auto pListViewItem = self().item(row)) {
if(auto pListViewCell = pListViewItem->cell(column)) {
if(pListViewCell->state.checkable) {
width += 24;
}
if(auto& icon = pListViewCell->state.icon) {
width += icon.width() + 2;
}
if(auto& text = pListViewCell->state.text) {
width += pFont::size(pListViewCell->font(true), text).width();
}
}
}
return width;
}
auto pListView::_columnWidth(uint column) -> uint {
uint width = 8;
if(auto& header = state().header) {
if(auto pListViewColumn = header->column(column)) {
if(auto& icon = pListViewColumn->state.icon) {
width += icon.width() + 2;
}
if(auto& text = pListViewColumn->state.text) {
width += pFont::size(pListViewColumn->font(true), text).width();
}
}
}
return width;
}
auto pListView::_width(uint column) -> uint {
if(auto& header = state().header) {
if(auto width = header->column(column).width()) return width;
uint width = 1;
if(!header->column(column).visible()) return width;
if(header->visible()) width = max(width, _columnWidth(column));
for(auto row : range(state().items)) {
width = max(width, _cellWidth(row, column));
}
return width;
}
return 1;
}
/*
auto pListView::autoSizeColumns() -> void {
@autoreleasepool {
if(listView.state.checkable) {
NSTableColumn* tableColumn = [[cocoaView content] tableColumnWithIdentifier:@"check"];
[tableColumn setWidth:20.0];
}
unsigned height = [[cocoaView content] rowHeight];
for(unsigned column = 0; column < max(1u, listView.state.headerText.size()); column++) {
NSTableColumn* tableColumn = [[cocoaView content] tableColumnWithIdentifier:[[NSNumber numberWithInteger:column] stringValue]];
unsigned minimumWidth = pFont::size([[tableColumn headerCell] font], listView.state.headerText(column)).width + 4;
for(unsigned row = 0; row < listView.state.text.size(); row++) {
unsigned width = pFont::size([cocoaView font], listView.state.text(row)(column)).width + 2;
if(listView.state.image(row)(height).empty() == false) width += height + 2;
if(width > minimumWidth) minimumWidth = width;
}
[tableColumn setWidth:minimumWidth];
}
[[cocoaView content] sizeLastColumnToFit];
}
}
auto pListView::setSelected(bool selected) -> void {
@autoreleasepool {
if(selected == false) {
[[cocoaView content] deselectAll:nil];
}
}
}
auto pListView::setSelection(unsigned selection) -> void {
@autoreleasepool {
[[cocoaView content] selectRowIndexes:[NSIndexSet indexSetWithIndexesInRange:NSMakeRange(selection, 1)] byExtendingSelection:NO];
}
}
*/
}
#endif

View file

@ -0,0 +1,71 @@
#if defined(Hiro_ListView)
@class CocoaListViewContent;
@interface CocoaListView : NSScrollView <NSTableViewDelegate, NSTableViewDataSource> {
@public
hiro::mListView* listView;
CocoaListViewContent* content;
NSFont* font;
}
-(id) initWith:(hiro::mListView&)listView;
-(void) dealloc;
-(CocoaListViewContent*) content;
-(NSFont*) font;
-(void) setFont:(NSFont*)font;
-(void) reloadColumns;
-(NSInteger) numberOfRowsInTableView:(NSTableView*)table;
-(id) tableView:(NSTableView*)table objectValueForTableColumn:(NSTableColumn*)tableColumn row:(NSInteger)row;
-(BOOL) tableView:(NSTableView*)table shouldShowCellExpansionForTableColumn:(NSTableColumn*)tableColumn row:(NSInteger)row;
-(NSString*) tableView:(NSTableView*)table toolTipForCell:(NSCell*)cell rect:(NSRectPointer)rect tableColumn:(NSTableColumn*)tableColumn row:(NSInteger)row mouseLocation:(NSPoint)mouseLocation;
-(void) tableView:(NSTableView*)tableView willDisplayCell:(id)cell forTableColumn:(NSTableColumn*)tableColumn row:(NSInteger)row;
-(void) tableViewSelectionDidChange:(NSNotification*)notification;
-(IBAction) activate:(id)sender;
-(IBAction) doubleAction:(id)sender;
@end
@interface CocoaListViewContent : NSTableView {
}
-(void) keyDown:(NSEvent*)event;
@end
@interface CocoaListViewCell : NSCell {
hiro::mListView* listView;
NSButtonCell* buttonCell;
}
-(id) initWith:(hiro::mListView&)listViewReference;
-(NSString*) stringValue;
-(void) drawWithFrame:(NSRect)frame inView:(NSView*)view;
-(NSUInteger) hitTestForEvent:(NSEvent*)event inRect:(NSRect)frame ofView:(NSView*)view;
-(BOOL) trackMouse:(NSEvent*)event inRect:(NSRect)frame ofView:(NSView*)view untilMouseUp:(BOOL)flag;
+(BOOL) prefersTrackingUntilMouseUp;
@end
namespace hiro {
struct pListView : pWidget {
Declare(ListView, Widget)
auto append(sListViewHeader header) -> void;
auto append(sListViewItem item) -> void;
auto remove(sListViewHeader header) -> void;
auto remove(sListViewItem item) -> void;
auto resizeColumns() -> void;
auto setAlignment(Alignment alignment) -> void;
auto setBackgroundColor(Color color) -> void;
auto setBatchable(bool batchable) -> void;
auto setBordered(bool bordered) -> void;
auto setEnabled(bool enabled) -> void override;
auto setFont(const Font& font) -> void override;
auto setForegroundColor(Color color) -> void;
auto _cellWidth(uint row, uint column) -> uint;
auto _columnWidth(uint column) -> uint;
auto _width(uint column) -> uint;
CocoaListView* cocoaListView = nullptr;
};
}
#endif

View file

@ -0,0 +1,48 @@
#if defined(Hiro_ProgressBar)
@implementation CocoaProgressBar : NSProgressIndicator
-(id) initWith:(hiro::mProgressBar&)progressBarReference {
if(self = [super initWithFrame:NSMakeRect(0, 0, 0, 0)]) {
progressBar = &progressBarReference;
[self setIndeterminate:NO];
[self setMinValue:0.0];
[self setMaxValue:100.0];
}
return self;
}
@end
namespace hiro {
auto pProgressBar::construct() -> void {
@autoreleasepool {
cocoaView = cocoaProgressBar = [[CocoaProgressBar alloc] initWith:self()];
pWidget::construct();
setPosition(state().position);
}
}
auto pProgressBar::destruct() -> void {
@autoreleasepool {
[cocoaView removeFromSuperview];
[cocoaView release];
}
}
auto pProgressBar::minimumSize() const -> Size {
return {0, 12};
}
auto pProgressBar::setPosition(uint position) -> void {
@autoreleasepool {
[cocoaView setDoubleValue:position];
}
}
}
#endif

View file

@ -0,0 +1,23 @@
#if defined(Hiro_ProgressBar)
@interface CocoaProgressBar : NSProgressIndicator {
@public
hiro::mProgressBar* progressBar;
}
-(id) initWith:(hiro::mProgressBar&)progressBar;
@end
namespace hiro {
struct pProgressBar : pWidget {
Declare(ProgressBar, Widget)
auto minimumSize() const -> Size override;
auto setPosition(uint position) -> void;
CocoaProgressBar* cocoaProgressBar = nullptr;
};
}
#endif

View file

@ -0,0 +1,114 @@
#if defined(Hiro_RadioButton)
@implementation CocoaRadioButton : NSButton
-(id) initWith:(hiro::mRadioButton&)radioButtonReference {
if(self = [super initWithFrame:NSMakeRect(0, 0, 0, 0)]) {
radioButton = &radioButtonReference;
[self setTarget:self];
[self setAction:@selector(activate:)];
[self setBezelStyle:NSRegularSquareBezelStyle];
[self setButtonType:NSOnOffButton];
}
return self;
}
-(IBAction) activate:(id)sender {
bool wasChecked = radioButton->state.checked;
radioButton->setChecked();
if(!wasChecked) radioButton->doActivate();
}
@end
namespace hiro {
auto pRadioButton::construct() -> void {
@autoreleasepool {
cocoaView = cocoaRadioButton = [[CocoaRadioButton alloc] initWith:self()];
pWidget::construct();
setBordered(state().bordered);
if(state().checked) setChecked();
setIcon(state().icon);
setOrientation(state().orientation);
setText(state().text);
}
}
auto pRadioButton::destruct() -> void {
@autoreleasepool {
[cocoaView removeFromSuperview];
[cocoaView release];
}
}
auto pRadioButton::minimumSize() const -> Size {
Size size = pFont::size(self().font(true), state().text);
if(state().orientation == Orientation::Horizontal) {
size.setWidth(size.width() + state().icon.width());
size.setHeight(max(size.height(), state().icon.height()));
}
if(state().orientation == Orientation::Vertical) {
size.setWidth(max(size.width(), state().icon.width()));
size.setHeight(size.height() + state().icon.height());
}
return {size.width() + (state().text ? 20 : 8), size.height() + 8};
}
auto pRadioButton::setBordered(bool bordered) -> void {
}
auto pRadioButton::setChecked() -> void {
@autoreleasepool {
if(auto group = state().group) {
for(auto& weak : group->state.objects) {
if(auto object = weak.acquire()) {
if(auto self = object->self()) {
if(auto p = dynamic_cast<pRadioButton*>(self)) {
auto state = this == p ? NSOnState : NSOffState;
[p->cocoaView setState:state];
}
}
}
}
}
}
}
auto pRadioButton::setGeometry(Geometry geometry) -> void {
pWidget::setGeometry({
geometry.x() - 2, geometry.y() - 2,
geometry.width() + 4, geometry.height() + 4
});
}
auto pRadioButton::setGroup(sGroup group) -> void {
}
auto pRadioButton::setIcon(const image& icon) -> void {
@autoreleasepool {
[cocoaView setImage:NSMakeImage(icon)];
}
}
auto pRadioButton::setOrientation(Orientation orientation) -> void {
@autoreleasepool {
if(orientation == Orientation::Horizontal) [cocoaView setImagePosition:NSImageLeft];
if(orientation == Orientation::Vertical ) [cocoaView setImagePosition:NSImageAbove];
}
}
auto pRadioButton::setText(const string& text) -> void {
@autoreleasepool {
[cocoaView setTitle:[NSString stringWithUTF8String:text]];
}
}
}
#endif

View file

@ -0,0 +1,30 @@
#if defined(Hiro_RadioButton)
@interface CocoaRadioButton : NSButton {
@public
hiro::mRadioButton* radioButton;
}
-(id) initWith:(hiro::mRadioButton&)radioButton;
-(IBAction) activate:(id)sender;
@end
namespace hiro {
struct pRadioButton : pWidget {
Declare(RadioButton, Widget)
auto minimumSize() const -> Size override;
auto setBordered(bool bordered) -> void;
auto setChecked() -> void;
auto setGeometry(Geometry geometry) -> void override;
auto setGroup(sGroup group) -> void;
auto setIcon(const image& icon) -> void;
auto setOrientation(Orientation orientation) -> void;
auto setText(const string& text) -> void;
CocoaRadioButton* cocoaRadioButton = nullptr;
};
}
#endif

View file

@ -0,0 +1,82 @@
#if defined(Hiro_RadioLabel)
@implementation CocoaRadioLabel : NSButton
-(id) initWith:(hiro::mRadioLabel&)radioLabelReference {
if(self = [super initWithFrame:NSMakeRect(0, 0, 0, 0)]) {
radioLabel = &radioLabelReference;
[self setTarget:self];
[self setAction:@selector(activate:)];
[self setButtonType:NSRadioButton];
}
return self;
}
-(IBAction) activate:(id)sender {
radioLabel->setChecked();
radioLabel->doActivate();
}
@end
namespace hiro {
auto pRadioLabel::construct() -> void {
@autoreleasepool {
cocoaView = cocoaRadioLabel = [[CocoaRadioLabel alloc] initWith:self()];
pWidget::construct();
if(state().checked) setChecked();
setText(state().text);
}
}
auto pRadioLabel::destruct() -> void {
@autoreleasepool {
[cocoaView removeFromSuperview];
[cocoaView release];
}
}
auto pRadioLabel::minimumSize() const -> Size {
Size size = pFont::size(self().font(true), state().text);
return {size.width() + 22, size.height()};
}
auto pRadioLabel::setChecked() -> void {
@autoreleasepool {
if(auto group = state().group) {
for(auto& weak : group->state.objects) {
if(auto object = weak.acquire()) {
if(auto self = object->self()) {
if(auto p = dynamic_cast<pRadioLabel*>(self)) {
auto state = this == p ? NSOnState : NSOffState;
[p->cocoaView setState:state];
}
}
}
}
}
}
}
auto pRadioLabel::setGeometry(Geometry geometry) -> void {
pWidget::setGeometry({
geometry.x() - 1, geometry.y(),
geometry.width() + 2, geometry.height()
});
}
auto pRadioLabel::setGroup(sGroup group) -> void {
}
auto pRadioLabel::setText(const string& text) -> void {
@autoreleasepool {
[cocoaView setTitle:[NSString stringWithUTF8String:text]];
}
}
}
#endif

View file

@ -0,0 +1,27 @@
#if defined(Hiro_RadioLabel)
@interface CocoaRadioLabel : NSButton {
@public
hiro::mRadioLabel* radioLabel;
}
-(id) initWith:(hiro::mRadioLabel&)radioLabel;
-(IBAction) activate:(id)sender;
@end
namespace hiro {
struct pRadioLabel : pWidget {
Declare(RadioLabel, Widget)
auto minimumSize() const -> Size override;
auto setChecked() -> void;
auto setGeometry(Geometry geometry) -> void override;
auto setGroup(sGroup group) -> void;
auto setText(const string& text) -> void;
CocoaRadioLabel* cocoaRadioLabel = nullptr;
};
}
#endif

View file

@ -0,0 +1,49 @@
#if defined(Hiro_TabFrame)
namespace hiro {
auto pTabFrameItem::construct() -> void {
}
auto pTabFrameItem::destruct() -> void {
}
auto pTabFrameItem::append(sLayout layout) -> void {
}
auto pTabFrameItem::remove(sLayout layout) -> void {
}
auto pTabFrameItem::setClosable(bool closable) -> void {
}
auto pTabFrameItem::setIcon(const image& icon) -> void {
}
auto pTabFrameItem::setMovable(bool movable) -> void {
}
auto pTabFrameItem::setSelected() -> void {
@autoreleasepool {
if(auto parent = _parent()) {
[parent->cocoaView selectTabViewItem:cocoaTabFrameItem];
}
}
}
auto pTabFrameItem::setText(const string& text) -> void {
@autoreleasepool {
[cocoaTabFrameItem setLabel:[NSString stringWithUTF8String:state().text]];
}
}
auto pTabFrameItem::_parent() -> maybe<pTabFrame&> {
if(auto parent = self().parentTabFrame()) {
if(auto self = parent->self()) return *self;
}
return nothing;
}
}
#endif

View file

@ -0,0 +1,23 @@
#if defined(Hiro_TabFrame)
namespace hiro {
struct pTabFrameItem : pObject {
Declare(TabFrameItem, Object)
auto append(sLayout layout) -> void;
auto remove(sLayout layout) -> void;
auto setClosable(bool closable) -> void;
auto setIcon(const image& icon) -> void;
auto setMovable(bool movable) -> void;
auto setSelected() -> void;
auto setText(const string& text) -> void;
CocoaTabFrameItem* cocoaTabFrameItem = nullptr;
auto _parent() -> maybe<pTabFrame&>;
};
}
#endif

166
cocoa/widget/tab-frame.cpp Normal file
View file

@ -0,0 +1,166 @@
#if defined(Hiro_TabFrame)
@implementation CocoaTabFrame : NSTabView
-(id) initWith:(hiro::mTabFrame&)tabFrameReference {
if(self = [super initWithFrame:NSMakeRect(0, 0, 0, 0)]) {
tabFrame = &tabFrameReference;
[self setDelegate:self];
}
return self;
}
-(void) tabView:(NSTabView*)tabView didSelectTabViewItem:(NSTabViewItem*)tabViewItem {
tabFrame->self()->_synchronizeLayout();
tabFrame->doChange();
}
@end
@implementation CocoaTabFrameItem : NSTabViewItem
-(id) initWith:(hiro::mTabFrame&)tabFrameReference {
if(self = [super initWithIdentifier:nil]) {
tabFrame = &tabFrameReference;
cocoaTabFrame = tabFrame->self()->cocoaTabFrame;
}
return self;
}
-(NSSize) sizeOfLabel:(BOOL)shouldTruncateLabel {
NSSize sizeOfLabel = [super sizeOfLabel:shouldTruncateLabel];
int selection = [cocoaTabFrame indexOfTabViewItem:self];
if(selection >= 0) {
if(auto item = tabFrame->item(selection)) {
if(item->state.icon) {
uint iconSize = hiro::pFont::size(tabFrame->font(true), " ").height();
sizeOfLabel.width += iconSize + 2;
}
}
}
return sizeOfLabel;
}
-(void) drawLabel:(BOOL)shouldTruncateLabel inRect:(NSRect)tabRect {
int selection = [cocoaTabFrame indexOfTabViewItem:self];
if(selection >= 0) {
if(auto item = tabFrame->item(selection)) {
if(item->state.icon) {
uint iconSize = hiro::pFont::size(tabFrame->font(true), " ").height();
NSImage* image = NSMakeImage(item->state.icon);
[[NSGraphicsContext currentContext] saveGraphicsState];
NSRect targetRect = NSMakeRect(tabRect.origin.x, tabRect.origin.y + 2, iconSize, iconSize);
[image drawInRect:targetRect fromRect:NSZeroRect operation:NSCompositeSourceOver fraction:1.0 respectFlipped:YES hints:nil];
[[NSGraphicsContext currentContext] restoreGraphicsState];
tabRect.origin.x += iconSize + 2;
tabRect.size.width -= iconSize + 2;
}
}
}
[super drawLabel:shouldTruncateLabel inRect:tabRect];
}
@end
namespace hiro {
auto pTabFrame::construct() -> void {
@autoreleasepool {
cocoaView = cocoaTabFrame = [[CocoaTabFrame alloc] initWith:self()];
pWidget::construct();
setNavigation(state().navigation);
}
}
auto pTabFrame::destruct() -> void {
@autoreleasepool {
[cocoaView removeFromSuperview];
[cocoaView release];
}
}
auto pTabFrame::append(sTabFrameItem item) -> void {
@autoreleasepool {
if(auto p = item->self()) {
p->cocoaTabFrameItem = [[CocoaTabFrameItem alloc] initWith:self()];
[p->cocoaTabFrameItem setLabel:[NSString stringWithUTF8String:item->state.text]];
[cocoaView addTabViewItem:p->cocoaTabFrameItem];
}
}
}
auto pTabFrame::remove(sTabFrameItem item) -> void {
@autoreleasepool {
if(auto p = item->self()) {
[cocoaView removeTabViewItem:p->cocoaTabFrameItem];
}
}
}
auto pTabFrame::setEnabled(bool enabled) -> void {
pWidget::setEnabled(enabled);
for(auto& item : state().items) {
if(auto& layout = item->state.layout) {
if(auto self = layout->self()) self->setEnabled(layout->enabled(true));
}
}
}
auto pTabFrame::setFont(const Font& font) -> void {
pWidget::setFont(font);
for(auto& item : state().items) {
if(auto& layout = item->state.layout) {
if(auto self = layout->self()) self->setFont(layout->font(true));
}
}
}
auto pTabFrame::setGeometry(Geometry geometry) -> void {
pWidget::setGeometry({
geometry.x() - 7, geometry.y() - 5,
geometry.width() + 14, geometry.height() + 6
});
geometry.setGeometry({
geometry.x() + 1, geometry.y() + 22,
geometry.width() - 2, geometry.height() - 32
});
for(auto& item : state().items) {
if(auto& layout = item->state.layout) {
layout->setGeometry(geometry);
}
}
_synchronizeLayout();
}
auto pTabFrame::setNavigation(Navigation navigation) -> void {
}
auto pTabFrame::setVisible(bool visible) -> void {
pWidget::setVisible(visible);
for(auto& item : state().items) {
if(auto& layout = item->state.layout) {
if(auto self = layout->self()) self->setVisible(layout->visible(true));
}
}
}
auto pTabFrame::_synchronizeLayout() -> void {
@autoreleasepool {
NSTabViewItem* tabViewItem = [cocoaView selectedTabViewItem];
int selected = tabViewItem ? [cocoaView indexOfTabViewItem:tabViewItem] : -1;
for(auto& item : state().items) {
item->state.selected = item->offset() == selected;
if(auto& layout = item->state.layout) {
if(auto self = layout->self()) self->setVisible(layout->visible(true) && item->selected());
}
}
}
}
}
#endif

View file

@ -0,0 +1,42 @@
#if defined(Hiro_TabFrame)
@interface CocoaTabFrame : NSTabView <NSTabViewDelegate> {
@public
hiro::mTabFrame* tabFrame;
}
-(id) initWith:(hiro::mTabFrame&)tabFrame;
-(void) tabView:(NSTabView*)tabView didSelectTabViewItem:(NSTabViewItem*)tabViewItem;
@end
@interface CocoaTabFrameItem : NSTabViewItem {
@public
hiro::mTabFrame* tabFrame;
CocoaTabFrame* cocoaTabFrame;
}
-(id) initWith:(hiro::mTabFrame&)tabFrame;
-(NSSize) sizeOfLabel:(BOOL)shouldTruncateLabel;
-(void) drawLabel:(BOOL)shouldTruncateLabel inRect:(NSRect)tabRect;
@end
namespace hiro {
struct pTabFrame : pWidget {
Declare(TabFrame, Widget)
auto append(sTabFrameItem item) -> void;
auto remove(sTabFrameItem item) -> void;
auto setEnabled(bool enabled) -> void override;
auto setFont(const Font& font) -> void override;
auto setGeometry(Geometry geometry) -> void override;
auto setNavigation(Navigation navigation) -> void;
auto setVisible(bool visible) -> void override;
auto _synchronizeLayout() -> void;
CocoaTabFrame* cocoaTabFrame = nullptr;
vector<CocoaTabFrameItem*> tabs;
};
}
#endif

119
cocoa/widget/text-edit.cpp Normal file
View file

@ -0,0 +1,119 @@
#if defined(Hiro_TextEdit)
@implementation CocoaTextEdit : NSScrollView
-(id) initWith:(hiro::mTextEdit&)textEditReference {
if(self = [super initWithFrame:NSMakeRect(0, 0, 0, 0)]) {
textEdit = &textEditReference;
content = [[[NSTextView alloc] initWithFrame:NSMakeRect(0, 0, 0, 0)] autorelease];
[content setDelegate:self];
[content setRichText:NO];
[self setBorderType:NSBezelBorder];
[self setDocumentView:content];
[self configure];
}
return self;
}
-(NSTextView*) content {
return content;
}
-(void) configure {
[content setMinSize:NSMakeSize(0, 0)];
[content setMaxSize:NSMakeSize(FLT_MAX, FLT_MAX)];
[[content textContainer] setContainerSize:NSMakeSize(FLT_MAX, FLT_MAX)];
[[content textContainer] setWidthTracksTextView:textEdit->wordWrap()];
[content setHorizontallyResizable:YES];
[content setVerticallyResizable:YES];
[content setAutoresizingMask:NSViewNotSizable];
[self setHasHorizontalScroller:!textEdit->wordWrap()];
[self setHasVerticalScroller:YES];
}
-(void) textDidChange:(NSNotification*)notification {
textEdit->state.text = [[content string] UTF8String];
textEdit->doChange();
}
@end
namespace hiro {
auto pTextEdit::construct() -> void {
@autoreleasepool {
cocoaView = cocoaTextEdit = [[CocoaTextEdit alloc] initWith:self()];
pWidget::construct();
setEditable(state().editable);
setWordWrap(state().wordWrap);
setText(state().text);
setCursor(state().cursor);
}
}
auto pTextEdit::destruct() -> void {
@autoreleasepool {
[cocoaView removeFromSuperview];
[cocoaView release];
}
}
auto pTextEdit::setBackgroundColor(Color color) -> void {
}
auto pTextEdit::setCursor(Cursor cursor) -> void {
@autoreleasepool {
//todo: handle text selection (cursor.length())
string text = [[[cocoaView content] string] UTF8String];
auto offset = min(cursor.offset(), text.length());
[[cocoaView content] setSelectedRange:NSMakeRange(offset, 0)];
}
}
auto pTextEdit::setEditable(bool editable) -> void {
@autoreleasepool {
[[cocoaView content] setEditable:(editable && self().enabled(true))];
}
}
auto pTextEdit::setEnabled(bool enabled) -> void {
pWidget::setEnabled(enabled);
setEditable(state().editable); //Cocoa lacks NSTextView::setEnabled; simulate via setEnabled()
}
auto pTextEdit::setFont(const Font& font) -> void {
@autoreleasepool {
[[cocoaView content] setFont:pFont::create(font)];
}
}
auto pTextEdit::setForegroundColor(Color color) -> void {
}
auto pTextEdit::setText(const string& text) -> void {
@autoreleasepool {
[[cocoaView content] setString:[NSString stringWithUTF8String:text]];
}
}
auto pTextEdit::setWordWrap(bool wordWrap) -> void {
@autoreleasepool {
[cocoaView configure];
}
}
auto pTextEdit::text() const -> string {
@autoreleasepool {
return [[[cocoaView content] string] UTF8String];
}
}
}
#endif

View file

@ -0,0 +1,34 @@
#if defined(Hiro_TextEdit)
@interface CocoaTextEdit : NSScrollView <NSTextViewDelegate> {
@public
hiro::mTextEdit* textEdit;
NSTextView* content;
}
-(id) initWith:(hiro::mTextEdit&)textEdit;
-(NSTextView*) content;
-(void) configure;
-(void) textDidChange:(NSNotification*)notification;
@end
namespace hiro {
struct pTextEdit : pWidget {
Declare(TextEdit, Widget)
auto setBackgroundColor(Color color) -> void;
auto setCursor(Cursor cursor) -> void;
auto setEditable(bool editable) -> void;
auto setEnabled(bool enabled) -> void override;
auto setFont(const Font& font) -> void override;
auto setForegroundColor(Color color) -> void;
auto setText(const string& text) -> void;
auto setWordWrap(bool wordWrap) -> void;
auto text() const -> string;
CocoaTextEdit* cocoaTextEdit = nullptr;
};
}
#endif

View file

@ -0,0 +1,94 @@
#if defined(Hiro_VerticalScrollBar)
@implementation CocoaVerticalScrollBar : NSScroller
-(id) initWith:(hiro::mVerticalScrollBar&)verticalScrollBarReference {
if(self = [super initWithFrame:NSMakeRect(0, 0, 0, 1)]) {
verticalScrollBar = &verticalScrollBarReference;
[self setTarget:self];
[self setAction:@selector(scroll:)];
[self setControlSize:NSRegularControlSize];
[self setScrollerStyle:NSScrollerStyleLegacy];
[self setEnabled:YES];
[self update];
}
return self;
}
-(void) update {
double d = 1.0 / verticalScrollBar->state.length;
double f = d * verticalScrollBar->state.position;
[self setDoubleValue:f];
[self setKnobProportion:d];
}
-(IBAction) scroll:(id)sender {
auto& state = verticalScrollBar->state;
switch([self hitPart]) {
case NSScrollerIncrementLine:
case NSScrollerIncrementPage:
if(state.position < state.length - 1) state.position++;
[self update];
break;
case NSScrollerDecrementLine:
case NSScrollerDecrementPage:
if(state.position) state.position--;
[self update];
break;
case NSScrollerKnob:
state.position = [self doubleValue] * state.length;
break;
}
verticalScrollBar->doChange();
}
@end
namespace hiro {
auto pVerticalScrollBar::construct() -> void {
@autoreleasepool {
cocoaView = cocoaVerticalScrollBar = [[CocoaVerticalScrollBar alloc] initWith:self()];
pWidget::construct();
setLength(state().length);
setPosition(state().position);
}
}
auto pVerticalScrollBar::destruct() -> void {
@autoreleasepool {
[cocoaView removeFromSuperview];
[cocoaView release];
}
}
auto pVerticalScrollBar::minimumSize() const -> Size {
@autoreleasepool {
return {(int)[NSScroller scrollerWidthForControlSize:NSRegularControlSize scrollerStyle:NSScrollerStyleLegacy], 32};
}
}
auto pVerticalScrollBar::setLength(uint length) -> void {
@autoreleasepool {
[cocoaView update];
}
}
auto pVerticalScrollBar::setPosition(uint position) -> void {
@autoreleasepool {
[cocoaView update];
}
}
}
#endif

View file

@ -0,0 +1,26 @@
#if defined(Hiro_VerticalScrollBar)
@interface CocoaVerticalScrollBar : NSScroller {
@public
hiro::mVerticalScrollBar* verticalScrollBar;
}
-(id) initWith:(hiro::mVerticalScrollBar&)verticalScrollBar;
-(void) update;
-(IBAction) scroll:(id)sender;
@end
namespace hiro {
struct pVerticalScrollBar : pWidget {
Declare(VerticalScrollBar, Widget)
auto minimumSize() const -> Size override;
auto setLength(uint length) -> void;
auto setPosition(uint position) -> void;
CocoaVerticalScrollBar* cocoaVerticalScrollBar = nullptr;
};
}
#endif

View file

@ -0,0 +1,67 @@
#if defined(Hiro_VerticalSlider)
@implementation CocoaVerticalSlider : NSSlider
-(id) initWith:(hiro::mVerticalSlider&)verticalSliderReference {
if(self = [super initWithFrame:NSMakeRect(0, 0, 0, 1)]) {
verticalSlider = &verticalSliderReference;
[self setTarget:self];
[self setAction:@selector(activate:)];
[self setMinValue:0];
}
return self;
}
-(IBAction) activate:(id)sender {
verticalSlider->state.position = [self doubleValue];
verticalSlider->doChange();
}
@end
namespace hiro {
auto pVerticalSlider::construct() -> void {
@autoreleasepool {
cocoaView = cocoaVerticalSlider = [[CocoaVerticalSlider alloc] initWith:self()];
pWidget::construct();
setLength(state().length);
setPosition(state().position);
}
}
auto pVerticalSlider::destruct() -> void {
@autoreleasepool {
[cocoaView removeFromSuperview];
[cocoaView release];
}
}
auto pVerticalSlider::minimumSize() const -> Size {
return {20, 48};
}
auto pVerticalSlider::setGeometry(Geometry geometry) -> void {
pWidget::setGeometry({
geometry.x(), geometry.y() - 2,
geometry.width(), geometry.height() + 4
});
}
auto pVerticalSlider::setLength(uint length) -> void {
@autoreleasepool {
[cocoaView setMaxValue:length];
}
}
auto pVerticalSlider::setPosition(uint position) -> void {
@autoreleasepool {
[cocoaView setDoubleValue:position];
}
}
}
#endif

Some files were not shown because too many files have changed in this diff Show more