From 0421a96749743868554d44585050b1b3d04864d2 Mon Sep 17 00:00:00 2001 From: Aleks Kissinger Date: Thu, 4 Jan 2018 15:58:21 +0100 Subject: removed website --- tikzit-old/src/gtk/WidgetSurface.m | 630 +++++++++++++++++++++++++++++++++++++ 1 file changed, 630 insertions(+) create mode 100644 tikzit-old/src/gtk/WidgetSurface.m (limited to 'tikzit-old/src/gtk/WidgetSurface.m') diff --git a/tikzit-old/src/gtk/WidgetSurface.m b/tikzit-old/src/gtk/WidgetSurface.m new file mode 100644 index 0000000..004e722 --- /dev/null +++ b/tikzit-old/src/gtk/WidgetSurface.m @@ -0,0 +1,630 @@ +/* + * Copyright 2011 Alex Merry + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#import "WidgetSurface.h" +#import "gtkhelpers.h" +#import "InputDelegate.h" +#import "CairoRenderContext.h" + +// {{{ Internal interfaces +// {{{ GTK+ callbacks +static gboolean configure_event_cb (GtkWidget *widget, GdkEventConfigure *event, WidgetSurface *surface); +static void realize_cb (GtkWidget *widget, WidgetSurface *surface); +static gboolean expose_event_cb (GtkWidget *widget, GdkEventExpose *event, WidgetSurface *surface); +static gboolean button_press_event_cb (GtkWidget *widget, GdkEventButton *event, WidgetSurface *surface); +static gboolean button_release_event_cb (GtkWidget *widget, GdkEventButton *event, WidgetSurface *surface); +static gboolean motion_notify_event_cb (GtkWidget *widget, GdkEventMotion *event, WidgetSurface *surface); +static gboolean key_press_event_cb (GtkWidget *widget, GdkEventKey *event, WidgetSurface *surface); +static gboolean key_release_event_cb (GtkWidget *widget, GdkEventKey *event, WidgetSurface *surface); +static gboolean scroll_event_cb (GtkWidget *widget, GdkEventScroll *event, WidgetSurface *surface); +static void set_cursor (GtkWidget *widget, GdkCursor *cursor); +static void unref_cursor (gpointer cursor, GClosure *closure); +// }}} + +@interface WidgetSurface (Private) +- (void) updateTransformer; +- (void) widgetSizeChanged:(NSNotification*)notification; +- (void) handleExposeEvent:(GdkEventExpose*)event; +- (void) updateLastKnownSize; +- (void) zoomTo:(CGFloat)scale aboutPoint:(NSPoint)p; +- (void) zoomTo:(CGFloat)scale; +- (void) addToEventMask:(GdkEventMask)values; +- (void) removeFromEventMask:(GdkEventMask)values; +@end +// }}} +// {{{ API +@implementation WidgetSurface + +- (id) init { + return [self initWithWidget:gtk_drawing_area_new ()]; +} + +- (id) initWithWidget:(GtkWidget*)w { + self = [super init]; + + if (self) { + widget = w; + g_object_ref_sink (G_OBJECT (widget)); + defaultScale = 1.0f; + transformer = [[Transformer alloc] init]; + [transformer setFlippedAboutXAxis:YES]; + [self updateLastKnownSize]; + g_object_set (G_OBJECT (widget), "events", GDK_STRUCTURE_MASK, NULL); + g_signal_connect (widget, "expose-event", G_CALLBACK (expose_event_cb), self); + g_signal_connect (widget, "configure-event", G_CALLBACK (configure_event_cb), self); + g_signal_connect (widget, "realize", G_CALLBACK (realize_cb), self); + g_signal_connect (widget, "button-press-event", G_CALLBACK (button_press_event_cb), self); + g_signal_connect (widget, "button-release-event", G_CALLBACK (button_release_event_cb), self); + g_signal_connect (widget, "motion-notify-event", G_CALLBACK (motion_notify_event_cb), self); + g_signal_connect (widget, "key-press-event", G_CALLBACK (key_press_event_cb), self); + g_signal_connect (widget, "key-release-event", G_CALLBACK (key_release_event_cb), self); + g_signal_connect (widget, "scroll-event", G_CALLBACK (scroll_event_cb), self); + [[NSNotificationCenter defaultCenter] addObserver:self + selector:@selector(widgetSizeChanged:) + name:@"SurfaceSizeChanged" + object:self]; + if ([self canFocus]) { + [self addToEventMask:GDK_BUTTON_PRESS_MASK]; + } else { + [self removeFromEventMask:GDK_BUTTON_PRESS_MASK]; + } + } + + return self; +} + +- (void) dealloc { + [[NSNotificationCenter defaultCenter] removeObserver:self]; + [transformer release]; + g_object_unref (G_OBJECT (widget)); + + [super dealloc]; +} + +- (void) invalidateRect:(NSRect)rect { + if (!NSIsEmptyRect (rect)) { + GdkWindow *window = gtk_widget_get_window (widget); + if (window) { + GdkRectangle g_rect = gdk_rectangle_from_ns_rect (rect); + gdk_window_invalidate_rect (window, &g_rect, TRUE); + } + } +} + +- (void) invalidate { + GdkWindow *window = gtk_widget_get_window (widget); + if (window) { + GdkRegion *visible = gdk_drawable_get_visible_region (GDK_DRAWABLE (window)); + gdk_window_invalidate_region (window, visible, TRUE); + gdk_region_destroy (visible); + } +} + +- (id) createRenderContext { + return [CairoRenderContext contextForWidget:widget]; +} + +- (int) width { + int width = 0; + GdkWindow *window = gtk_widget_get_window (widget); + if (window) { + gdk_drawable_get_size (window, &width, NULL); + } + return width; +} + +- (int) height { + int height = 0; + GdkWindow *window = gtk_widget_get_window (widget); + if (window) { + gdk_drawable_get_size (window, NULL, &height); + } + return height; +} + +- (void) setSizeRequestWidth:(double)width height:(double)height { + gtk_widget_set_size_request (widget, width, height); +} + +- (Transformer*) transformer { + return transformer; +} + +- (GtkWidget*) widget { + return widget; +} + +- (void) setRenderDelegate:(id )delegate { + // NB: no retention! + renderDelegate = delegate; + if (renderDelegate == nil) { + [self removeFromEventMask:GDK_EXPOSURE_MASK]; + } else { + [self addToEventMask:GDK_EXPOSURE_MASK]; + } +} + +- (id) inputDelegate { + return inputDelegate; +} + +- (void) setInputDelegate:(id)delegate { + if (delegate == inputDelegate) { + return; + } + buttonPressesRequired = NO; + if (inputDelegate != nil) { + [self removeFromEventMask:GDK_POINTER_MOTION_MASK + | GDK_BUTTON_PRESS_MASK + | GDK_BUTTON_RELEASE_MASK + | GDK_KEY_PRESS_MASK + | GDK_KEY_RELEASE_MASK]; + } + inputDelegate = delegate; + if (delegate != nil) { + GdkEventMask mask = 0; + if ([delegate respondsToSelector:@selector(mousePressAt:withButton:andMask:)]) { + buttonPressesRequired = YES; + mask |= GDK_BUTTON_PRESS_MASK; + } + if ([delegate respondsToSelector:@selector(mouseReleaseAt:withButton:andMask:)]) { + mask |= GDK_BUTTON_RELEASE_MASK; + } + if ([delegate respondsToSelector:@selector(mouseDoubleClickAt:withButton:andMask:)]) { + buttonPressesRequired = YES; + mask |= GDK_BUTTON_PRESS_MASK; + } + if ([delegate respondsToSelector:@selector(mouseMoveTo:withButtons:andMask:)]) { + mask |= GDK_POINTER_MOTION_MASK; + } + if ([delegate respondsToSelector:@selector(keyPressed:withMask:)]) { + mask |= GDK_KEY_PRESS_MASK; + } + if ([delegate respondsToSelector:@selector(keyReleased:withMask:)]) { + mask |= GDK_KEY_RELEASE_MASK; + } + [self addToEventMask:mask]; + } +} + +- (id ) renderDelegate { + return renderDelegate; +} + +- (void) setKeepCentered:(BOOL)centered { + keepCentered = centered; + [self updateTransformer]; +} + +- (BOOL) keepCentered { + return keepCentered; +} + +- (BOOL) canFocus { + return gtk_widget_get_can_focus (widget); +} + +- (void) setCanFocus:(BOOL)focus { + gtk_widget_set_can_focus (widget, focus); + if (focus) { + [self addToEventMask:GDK_BUTTON_PRESS_MASK]; + } else if (!buttonPressesRequired) { + [self removeFromEventMask:GDK_BUTTON_PRESS_MASK]; + } +} + +- (BOOL) hasFocus { + return gtk_widget_has_focus (widget); +} + +- (void) renderFocus { + GdkWindow *window = gtk_widget_get_window (widget); + if (window) { + int width = 0; + int height = 0; + gdk_drawable_get_size (window, &width, &height); + gtk_paint_focus (gtk_widget_get_style (widget), + window, + GTK_STATE_NORMAL, + NULL, + widget, + NULL, + 0, + 0, + width, + height + ); + } +} + +- (CGFloat) defaultScale { + return defaultScale; +} + +- (void) setDefaultScale:(CGFloat)newDefault { + if (defaultScale != newDefault) { + CGFloat oldDefault = defaultScale; + defaultScale = newDefault; + + CGFloat scale = [transformer scale]; + scale *= (newDefault / oldDefault); + [transformer setScale:scale]; + [self invalidate]; + } +} + +- (void) zoomIn { + CGFloat scale = [transformer scale]; + scale *= 1.2f; + [self zoomTo:scale]; +} + +- (void) zoomOut { + CGFloat scale = [transformer scale]; + scale /= 1.2f; + [self zoomTo:scale]; +} + +- (void) zoomReset { + [self zoomTo:defaultScale]; +} + +- (void) zoomInAboutPoint:(NSPoint)p { + CGFloat scale = [transformer scale]; + scale *= 1.2f; + [self zoomTo:scale aboutPoint:p]; +} + +- (void) zoomOutAboutPoint:(NSPoint)p { + CGFloat scale = [transformer scale]; + scale /= 1.2f; + [self zoomTo:scale aboutPoint:p]; +} + +- (void) zoomResetAboutPoint:(NSPoint)p { + [self zoomTo:defaultScale aboutPoint:p]; +} + +- (void) setCursor:(Cursor)c { + GdkCursor *cursor = NULL; + switch (c) { + case ResizeRightCursor: + cursor = gdk_cursor_new (GDK_RIGHT_SIDE); + break; + case ResizeBottomRightCursor: + cursor = gdk_cursor_new (GDK_BOTTOM_RIGHT_CORNER); + break; + case ResizeBottomCursor: + cursor = gdk_cursor_new (GDK_BOTTOM_SIDE); + break; + case ResizeBottomLeftCursor: + cursor = gdk_cursor_new (GDK_BOTTOM_LEFT_CORNER); + break; + case ResizeLeftCursor: + cursor = gdk_cursor_new (GDK_LEFT_SIDE); + break; + case ResizeTopLeftCursor: + cursor = gdk_cursor_new (GDK_TOP_LEFT_CORNER); + break; + case ResizeTopCursor: + cursor = gdk_cursor_new (GDK_TOP_SIDE); + break; + case ResizeTopRightCursor: + cursor = gdk_cursor_new (GDK_TOP_RIGHT_CORNER); + break; + default: break; + } + GdkWindow *window = gtk_widget_get_window (widget); + g_signal_handlers_disconnect_matched (window, + G_SIGNAL_MATCH_FUNC, 0, 0, NULL, + G_CALLBACK (set_cursor), NULL); + if (window) { + gdk_window_set_cursor (window, cursor); + if (cursor != NULL) { + gdk_cursor_unref (cursor); + } + } else { + g_signal_connect_data (widget, + "realize", G_CALLBACK (set_cursor), cursor, + unref_cursor, 0); + } +} + +@end +// }}} +// {{{ Private +@implementation WidgetSurface (Private) +- (void) widgetSizeChanged:(NSNotification*)notification { + [self updateTransformer]; + [self updateLastKnownSize]; +} + +- (void) updateTransformer { + if (keepCentered) { + GdkWindow *window = gtk_widget_get_window (widget); + if (window) { + int width = 0; + int height = 0; + gdk_drawable_get_size (window, &width, &height); + NSPoint origin; + if (lastKnownSize.width < 1 || lastKnownSize.height < 1) { + origin.x = (float)width / 2.0f; + origin.y = (float)height / 2.0f; + } else { + origin = [transformer origin]; + origin.x += ((float)width - lastKnownSize.width) / 2.0f; + origin.y += ((float)height - lastKnownSize.height) / 2.0f; + } + [transformer setOrigin:origin]; + } + } +} + +- (void) handleExposeEvent:(GdkEventExpose*)event { + if (renderDelegate != nil) { + NSRect area = gdk_rectangle_to_ns_rect (event->area); + + id context = [CairoRenderContext contextForWidget:widget]; + [context rect:area]; + [context clipToPath]; + [renderDelegate renderWithContext:context onSurface:self]; + } +} + +- (void) updateLastKnownSize { + GdkWindow *window = gtk_widget_get_window (widget); + if (window) { + int width = 0; + int height = 0; + gdk_drawable_get_size (window, &width, &height); + lastKnownSize.width = (float)width; + lastKnownSize.height = (float)height; + } else { + lastKnownSize = NSZeroSize; + } +} + +- (void) zoomTo:(CGFloat)scale aboutPoint:(NSPoint)p { + NSPoint graphP = [transformer fromScreen:p]; + + [transformer setScale:scale]; + + NSPoint newP = [transformer toScreen:graphP]; + NSPoint origin = [transformer origin]; + origin.x += p.x - newP.x; + origin.y += p.y - newP.y; + [transformer setOrigin:origin]; + + [self invalidate]; +} + +- (void) zoomTo:(CGFloat)scale { + NSPoint centre = NSMakePoint (lastKnownSize.width/2.0f, lastKnownSize.height/2.0f); + [self zoomTo:scale aboutPoint:centre]; +} + +- (void) addToEventMask:(GdkEventMask)values { + GdkEventMask mask; + g_object_get (G_OBJECT (widget), "events", &mask, NULL); + mask |= values; + g_object_set (G_OBJECT (widget), "events", mask, NULL); +} + +- (void) removeFromEventMask:(GdkEventMask)values { + GdkEventMask mask; + g_object_get (G_OBJECT (widget), "events", &mask, NULL); + mask ^= values; + if (buttonPressesRequired || [self canFocus]) { + mask |= GDK_BUTTON_PRESS_MASK; + } + g_object_set (G_OBJECT (widget), "events", mask, NULL); +} + +@end +// }}} +// {{{ GTK+ callbacks +static gboolean configure_event_cb(GtkWidget *widget, GdkEventConfigure *event, WidgetSurface *surface) { + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; + [[NSNotificationCenter defaultCenter] postNotificationName:@"SurfaceSizeChanged" object:surface]; + [pool drain]; + return FALSE; +} + +static void realize_cb (GtkWidget *widget, WidgetSurface *surface) { + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; + [surface updateTransformer]; + [pool drain]; +} + +static gboolean expose_event_cb(GtkWidget *widget, GdkEventExpose *event, WidgetSurface *surface) { + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; + [surface handleExposeEvent:event]; + [pool drain]; + return FALSE; +} + +InputMask mask_from_gdk_modifier_state (GdkModifierType state) { + InputMask mask = 0; + if (state & GDK_SHIFT_MASK) { + mask |= ShiftMask; + } + if (state & GDK_CONTROL_MASK) { + mask |= ControlMask; + } + if (state & GDK_META_MASK) { + mask |= MetaMask; + } + return mask; +} + +ScrollDirection scroll_dir_from_gdk_scroll_dir (GdkScrollDirection dir) { + switch (dir) { + case GDK_SCROLL_UP: return ScrollUp; + case GDK_SCROLL_DOWN: return ScrollDown; + case GDK_SCROLL_LEFT: return ScrollLeft; + case GDK_SCROLL_RIGHT: return ScrollRight; + default: NSLog(@"Invalid scroll direction %i", (int)dir); return ScrollDown; + } +} + +MouseButton buttons_from_gdk_modifier_state (GdkModifierType state) { + MouseButton buttons = 0; + if (state & GDK_BUTTON1_MASK) { + buttons |= LeftButton; + } + if (state & GDK_BUTTON2_MASK) { + buttons |= MiddleButton; + } + if (state & GDK_BUTTON3_MASK) { + buttons |= RightButton; + } + if (state & GDK_BUTTON4_MASK) { + buttons |= Button4; + } + if (state & GDK_BUTTON5_MASK) { + buttons |= Button5; + } + return buttons; +} + +static gboolean button_press_event_cb(GtkWidget *widget, GdkEventButton *event, WidgetSurface *surface) { + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; + + if ([surface canFocus]) { + if (!gtk_widget_has_focus (widget)) { + gtk_widget_grab_focus (widget); + } + } + + id delegate = [surface inputDelegate]; + if (delegate != nil) { + NSPoint pos = NSMakePoint (event->x, event->y); + MouseButton button = (MouseButton)event->button; + InputMask mask = mask_from_gdk_modifier_state (event->state); + if (event->type == GDK_BUTTON_PRESS && [delegate respondsToSelector:@selector(mousePressAt:withButton:andMask:)]) { + [delegate mousePressAt:pos withButton:button andMask:mask]; + } + if (event->type == GDK_2BUTTON_PRESS && [delegate respondsToSelector:@selector(mouseDoubleClickAt:withButton:andMask:)]) { + [delegate mouseDoubleClickAt:pos withButton:button andMask:mask]; + } + } + + [pool drain]; + return FALSE; +} + +static gboolean button_release_event_cb(GtkWidget *widget, GdkEventButton *event, WidgetSurface *surface) { + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; + + id delegate = [surface inputDelegate]; + if (delegate != nil) { + if ([delegate respondsToSelector:@selector(mouseReleaseAt:withButton:andMask:)]) { + NSPoint pos = NSMakePoint (event->x, event->y); + MouseButton button = (MouseButton)event->button; + InputMask mask = mask_from_gdk_modifier_state (event->state); + [delegate mouseReleaseAt:pos withButton:button andMask:mask]; + } + } + + [pool drain]; + return FALSE; +} + +static gboolean motion_notify_event_cb(GtkWidget *widget, GdkEventMotion *event, WidgetSurface *surface) { + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; + + id delegate = [surface inputDelegate]; + if (delegate != nil) { + if ([delegate respondsToSelector:@selector(mouseMoveTo:withButtons:andMask:)]) { + NSPoint pos = NSMakePoint (event->x, event->y); + MouseButton buttons = buttons_from_gdk_modifier_state (event->state); + InputMask mask = mask_from_gdk_modifier_state (event->state); + [delegate mouseMoveTo:pos withButtons:buttons andMask:mask]; + } + } + + [pool drain]; + return FALSE; +} + +static gboolean key_press_event_cb(GtkWidget *widget, GdkEventKey *event, WidgetSurface *surface) { + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; + + id delegate = [surface inputDelegate]; + if (delegate != nil) { + if ([delegate respondsToSelector:@selector(keyPressed:withMask:)]) { + InputMask mask = mask_from_gdk_modifier_state (event->state); + [delegate keyPressed:event->keyval withMask:mask]; + } + } + + [pool drain]; + return FALSE; +} + +static gboolean key_release_event_cb(GtkWidget *widget, GdkEventKey *event, WidgetSurface *surface) { + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; + + id delegate = [surface inputDelegate]; + if (delegate != nil) { + if ([delegate respondsToSelector:@selector(keyReleased:withMask:)]) { + InputMask mask = mask_from_gdk_modifier_state (event->state); + [delegate keyReleased:event->keyval withMask:mask]; + } + } + + [pool drain]; + return FALSE; +} + +static gboolean scroll_event_cb (GtkWidget *widget, GdkEventScroll *event, WidgetSurface *surface) { + NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init]; + + id delegate = [surface inputDelegate]; + if (delegate != nil) { + if ([delegate respondsToSelector:@selector(mouseScrolledAt:inDirection:withMask:)]) { + NSPoint pos = NSMakePoint (event->x, event->y); + InputMask mask = mask_from_gdk_modifier_state (event->state); + ScrollDirection dir = scroll_dir_from_gdk_scroll_dir (event->direction); + [delegate mouseScrolledAt:pos + inDirection:dir + withMask:mask]; + } + } + + [pool drain]; + return FALSE; +} + +static void unref_cursor (gpointer cursor, GClosure *closure) { + if (cursor != NULL) { + gdk_cursor_unref ((GdkCursor*)cursor); + } +} + +static void set_cursor (GtkWidget *widget, GdkCursor *cursor) { + GdkWindow *window = gtk_widget_get_window (widget); + if (window) { + gdk_window_set_cursor (window, cursor); + if (cursor != NULL) { + gdk_cursor_unref (cursor); + } + } +} +// }}} + +// vim:ft=objc:ts=8:et:sts=4:sw=4:foldmethod=marker -- cgit v1.2.3