123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225 |
- #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;
- }
- -(void) resetCursorRects {
- if(auto mouseCursor = NSMakeCursor(canvas->mouseCursor())) {
- [self addCursorRect:self.bounds cursor:mouseCursor];
- }
- }
- -(NSDragOperation) draggingEntered:(id<NSDraggingInfo>)sender {
- return DropPathsOperation(sender);
- }
- -(BOOL) performDragOperation:(id<NSDraggingInfo>)sender {
- auto paths = DropPaths(sender);
- if(!paths) 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) mouseEntered:(NSEvent*)event {
- canvas->doMouseEnter();
- }
- -(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();
- }
- }
- 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::setAlignment(Alignment) -> void {
- update();
- }
- 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::setFocusable(bool focusable) -> void {
- //TODO
- }
- 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];
- }
- }
- //todo: support cases where the icon size does not match the canvas size (alignment)
- 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 = 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:NSDeviceRGBColorSpace
- bitmapFormat:NSAlphaNonpremultipliedBitmapFormat
- bytesPerRow:(width * 4) bitsPerPixel:32
- ] autorelease];
- [surface addRepresentation:bitmap];
- [cocoaView setImage:surface];
- }
- auto target = (uint32_t*)[bitmap bitmapData];
- if(auto icon = state().icon) {
- icon.transform(0, 32, 255u << 24, 255u << 0, 255u << 8, 255u << 16); //Cocoa uses ABGR format
- 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_t color = state().color.value();
- for(auto n : range(width * height)) target[n] = color;
- }
- }
- }
- }
- #endif
|