#include "ospanel_osx.inl"
#include "oscontrol_osx.inl"
#include "../ospanel.h"
#include "../oscontrol.inl"
#include "../osgui.inl"
#include <core/arrst.h>
#include <core/heap.h>
#include <sewer/cassert.h>
#if !defined(__MACOS__)
#error This file is only for OSX
#endif
typedef struct _area_t Area;
struct _area_t
{
void *obj;
NSRect rect;
NSColor *bgcolor;
NSColor *skcolor;
};
DeclSt(Area);
@interface OSXPanel : NSView
{
@public
NSScrollView *scroll;
CGSize content_size;
ArrSt(Area) *areas;
}
@end
@implementation OSXPanel
- (void)dealloc
{
[super dealloc];
heap_auditor_delete("OSXPanel");
}
- (void)drawRect:(NSRect)rect
{
[super drawRect:rect];
if (self->areas != NULL)
{
arrst_foreach(area, self->areas, Area)
if (area->bgcolor != nil)
{
[area->bgcolor set];
NSRectFill(area->rect);
}
if (area->skcolor != NULL)
{
[area->skcolor set];
NSFrameRect(area->rect);
}
arrst_end()
}
}
- (BOOL)isFlipped
{
return YES;
}
@end
OSPanel *ospanel_create(const uint32_t flags)
{
OSXPanel *panel = nil;
heap_auditor_add("OSXPanel");
panel = [[OSXPanel alloc] initWithFrame:NSZeroRect];
panel->areas = NULL;
panel->content_size = CGSizeMake(-1, -1);
[panel setAutoresizesSubviews:NO];
if (flags & ekVIEW_HSCROLL || flags & ekVIEW_VSCROLL)
{
NSScrollView *scroll = [[NSScrollView alloc] initWithFrame:NSZeroRect];
[scroll setDrawsBackground:NO];
[scroll setDocumentView:panel];
[scroll setHasHorizontalScroller:(flags & ekVIEW_HSCROLL) ? YES : NO];
[scroll setHasVerticalScroller:(flags & ekVIEW_VSCROLL) ? YES : NO];
[scroll setAutohidesScrollers:YES];
[scroll setBorderType:(flags & ekVIEW_BORDER) ? NSGrooveBorder : NSNoBorder];
panel->scroll = scroll;
return cast(scroll, OSPanel);
}
else
{
panel->scroll = nil;
return cast(panel, OSPanel);
}
}
static void i_remove_area(Area *area)
{
if (area->bgcolor != nil)
[area->bgcolor release];
if (area->skcolor != nil)
[area->skcolor release];
}
static OSXPanel *i_get_panel(const OSPanel *panel)
{
cassert_no_null(panel);
if ([cast(panel, NSView) isKindOfClass:[OSXPanel class]])
{
return cast(panel, OSXPanel);
}
else
{
NSScrollView *scroll = cast(panel, NSScrollView);
cassert([[scroll documentView] isKindOfClass:[OSXPanel class]]);
return [scroll documentView];
}
}
void ospanel_destroy(OSPanel **panel)
{
OSXPanel *lpanel = nil;
NSScrollView *scroll = nil;
cassert_no_null(panel);
lpanel = i_get_panel(*panel);
cassert_no_null(lpanel);
cassert([[lpanel subviews] count] == 0);
if (lpanel->areas != NULL)
arrst_destroy(&lpanel->areas, i_remove_area, Area);
scroll = lpanel->scroll;
[lpanel release];
if (scroll != nil)
[scroll release];
*panel = NULL;
}
BOOL _ospanel_is(NSView *view)
{
return [view isKindOfClass:[OSXPanel class]];
}
void _ospanel_destroy(OSPanel **panel)
{
OSXPanel *lpanel = nil;
NSArray *subviews;
NSUInteger i, num_elems;
cassert_no_null(panel);
lpanel = i_get_panel(*panel);
cassert_no_null(lpanel);
subviews = [lpanel subviews];
num_elems = [subviews count];
for (i = 0; i < num_elems; ++i)
{
NSView *child = [subviews objectAtIndex:0];
_oscontrol_detach_and_destroy(dcast(&child, OSControl), *panel);
cassert([subviews count] == num_elems - i - 1);
}
ospanel_destroy(panel);
}
void ospanel_area(OSPanel *panel, void *obj, const color_t bgcolor, const color_t skcolor, const real32_t x, const real32_t y, const real32_t width, const real32_t height)
{
OSXPanel *lpanel = i_get_panel(panel);
cassert_no_null(lpanel);
if (obj != NULL)
{
Area *area = NULL;
if (lpanel->areas == NULL)
lpanel->areas = arrst_create(Area);
arrst_foreach(larea, lpanel->areas, Area)
if (larea->obj == obj)
{
area = larea;
break;
}
arrst_end()
if (area == NULL)
{
area = arrst_new(lpanel->areas, Area);
area->obj = obj;
area->bgcolor = nil;
area->skcolor = nil;
}
area->rect.origin.x = (CGFloat)x;
area->rect.origin.y = (CGFloat)y;
area->rect.size.width = (CGFloat)width;
area->rect.size.height = (CGFloat)height;
if (area->bgcolor != nil)
{
[area->bgcolor release];
area->bgcolor = nil;
}
if (area->skcolor != nil)
{
[area->skcolor release];
area->skcolor = nil;
}
if (bgcolor != 0)
area->bgcolor = [_oscontrol_color(bgcolor) retain];
if (skcolor != 0)
area->skcolor = [_oscontrol_color(skcolor) retain];
}
else
{
if (lpanel->areas != NULL)
arrst_clear(lpanel->areas, i_remove_area, Area);
}
}
void ospanel_scroller_size(const OSPanel *panel, real32_t *width, real32_t *height)
{
if ([cast(panel, NSView) isKindOfClass:[NSScrollView class]])
{
NSScrollView *scroll = cast(panel, NSScrollView);
if (width)
{
NSScroller *scroller = [scroll verticalScroller];
*width = 0;
if (scroller != nil)
*width = (real32_t)[scroller frame].size.width;
}
if (height)
{
NSScroller *scroller = [scroll horizontalScroller];
*height = 0;
if (scroller != nil)
*height = (real32_t)[scroller frame].size.height;
}
}
else
{
if (width)
*width = 16;
if (height)
*height = 16;
}
}
static void i_OnUpdateSize(OSPanel *panel)
{
OSXPanel *lpanel = i_get_panel(panel);
if ([cast(panel, NSView) isKindOfClass:[NSScrollView class]])
{
CGFloat diff = 0;
NSScroller *scroller = [cast(panel, NSScrollView) verticalScroller];
if (scroller != nil && [scroller isHidden] == NO)
diff = [scroller frame].size.width;
[lpanel setFrame:NSMakeRect(0, 0, lpanel->content_size.width - diff, lpanel->content_size.height)];
}
else
{
cassert(lpanel->content_size.width == -1);
cassert(lpanel->content_size.height == -1);
}
}
void ospanel_content_size(OSPanel *panel, const real32_t width, const real32_t height, const real32_t line_width, const real32_t line_height)
{
OSXPanel *lpanel = i_get_panel(panel);
cassert([cast(panel, NSView) isKindOfClass:[NSScrollView class]]);
cassert(lpanel == [cast(panel, NSScrollView) documentView]);
unref(line_width);
unref(line_height);
lpanel->content_size.width = (CGFloat)width;
lpanel->content_size.height = (CGFloat)height;
i_OnUpdateSize(panel);
}
void ospanel_display(OSPanel *panel)
{
OSXPanel *lpanel = i_get_panel(panel);
[lpanel setNeedsDisplay:YES];
}
void ospanel_attach(OSPanel *panel, OSPanel *parent_panel)
{
_oscontrol_attach_to_parent(cast(panel, NSView), cast(parent_panel, NSView));
}
void ospanel_detach(OSPanel *panel, OSPanel *parent_panel)
{
_oscontrol_detach_from_parent(cast(panel, NSView), cast(parent_panel, NSView));
}
void ospanel_visible(OSPanel *panel, const bool_t visible)
{
_oscontrol_set_visible(cast(panel, NSView), visible);
}
void ospanel_enabled(OSPanel *panel, const bool_t enabled)
{
unref(panel);
unref(enabled);
}
void ospanel_size(const OSPanel *panel, real32_t *width, real32_t *height)
{
_oscontrol_get_size(cast(panel, NSView), width, height);
}
void ospanel_origin(const OSPanel *panel, real32_t *x, real32_t *y)
{
_oscontrol_get_origin(cast(panel, NSView), x, y);
}
void ospanel_frame(OSPanel *panel, const real32_t x, const real32_t y, const real32_t width, const real32_t height)
{
_oscontrol_set_frame(cast(panel, NSView), x, y, width, height);
i_OnUpdateSize(panel);
}
void _ospanel_attach_control(OSPanel *panel, NSView *control)
{
OSXPanel *lpanel = i_get_panel(panel);
_oscontrol_attach_to_parent(control, cast(lpanel, NSView));
}
void _ospanel_detach_control(OSPanel *panel, NSView *control)
{
OSXPanel *lpanel = i_get_panel(panel);
_oscontrol_detach_from_parent(control, cast(lpanel, NSView));
}
bool_t _ospanel_with_scroll(const OSPanel *panel)
{
OSXPanel *lpanel = i_get_panel(panel);
return (bool_t)(lpanel->scroll != nil);
}
void _ospanel_scroll(OSPanel *panel, const int32_t x, const int32_t y)
{
NSPoint origin;
OSXPanel *lpanel = i_get_panel(panel);
cassert_no_null(lpanel->scroll);
origin = [lpanel->scroll documentVisibleRect].origin;
if (x != INT32_MAX)
origin.x = (CGFloat)x;
if (y != INT32_MAX)
origin.y = (CGFloat)y;
[[lpanel->scroll contentView] scrollToPoint:origin];
[lpanel->scroll reflectScrolledClipView:[lpanel->scroll contentView]];
}
void _ospanel_scroll_frame(const OSPanel *panel, OSFrame *rect)
{
NSRect frame;
OSXPanel *lpanel = i_get_panel(panel);
cassert_no_null(rect);
cassert_no_null(lpanel->scroll);
frame = [lpanel->scroll documentVisibleRect];
rect->left = (int32_t)frame.origin.x;
rect->top = (int32_t)frame.origin.y;
rect->right = rect->left + (int32_t)frame.size.width;
rect->bottom = rect->top + (int32_t)frame.size.height;
}