diff options
author | randomguy3 <randomguy3@7c02a99a-9b00-45e3-bf44-6f3dd7fddb64> | 2012-01-18 10:05:06 +0000 |
---|---|---|
committer | randomguy3 <randomguy3@7c02a99a-9b00-45e3-bf44-6f3dd7fddb64> | 2012-01-18 10:05:06 +0000 |
commit | dcf64eac4fdb246cf6fb169c1279b67966478173 (patch) | |
tree | 563a9b0bfff1050775f693f5832683ad2590d1b2 /tikzit/src/gtk/GraphInputHandler.m | |
parent | 0dc14c2123819e1996d989b766c87571ac4a2866 (diff) |
Rename src/linux to src/gtk (which is more accurate)
git-svn-id: https://tikzit.svn.sourceforge.net/svnroot/tikzit/trunk@392 7c02a99a-9b00-45e3-bf44-6f3dd7fddb64
Diffstat (limited to 'tikzit/src/gtk/GraphInputHandler.m')
-rw-r--r-- | tikzit/src/gtk/GraphInputHandler.m | 410 |
1 files changed, 410 insertions, 0 deletions
diff --git a/tikzit/src/gtk/GraphInputHandler.m b/tikzit/src/gtk/GraphInputHandler.m new file mode 100644 index 0000000..4d77045 --- /dev/null +++ b/tikzit/src/gtk/GraphInputHandler.m @@ -0,0 +1,410 @@ +/* + * Copyright 2011 Alex Merry <alex.merry@kdemail.net> + * Copyright 2010 Chris Heunen + * + * 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 <http://www.gnu.org/licenses/>. + */ + +#import "GraphInputHandler.h" +#import <gdk/gdkkeysyms.h> +#import "Edge+Render.h" + +static const InputMask unionSelectMask = ShiftMask; + +@implementation GraphInputHandler +- (id) initWithGraphRenderer:(GraphRenderer*)r { + self = [super init]; + + if (self) { + renderer = r; + mode = SelectMode; + state = QuietState; + edgeFuzz = 3.0f; + leaderNode = nil; + modifyEdge = nil; + selectionBoxContents = [[NSMutableSet alloc] initWithCapacity:10]; + grabbedResizeHandle = NoHandle; + } + + return self; +} + +- (TikzDocument*) doc { + return [renderer document]; +} + +- (void) deselectAllNodes { + [[[self doc] pickSupport] deselectAllNodes]; +} + +- (void) deselectAllEdges { + [[[self doc] pickSupport] deselectAllEdges]; +} + +- (void) deselectAll { + [[[self doc] pickSupport] deselectAllNodes]; + [[[self doc] pickSupport] deselectAllEdges]; +} + +- (void) shiftNodesByMovingLeader:(Node*)leader to:(NSPoint)to { + Transformer *transformer = [renderer transformer]; + + NSPoint from = [transformer toScreen:[leader point]]; + //to = [[renderer grid] snapScreenPoint:to]; + float dx = to.x - from.x; + float dy = to.y - from.y; + + for (Node *node in [[[self doc] pickSupport] selectedNodes]) { + NSPoint p = [transformer toScreen:[node point]]; + p.x += dx; + p.y += dy; + p = [[renderer grid] snapScreenPoint:p]; + [node setPoint:[transformer fromScreen:p]]; + } +} + +- (float) edgeFuzz { + return edgeFuzz; +} + +- (void) setEdgeFuzz:(float)fuzz { + edgeFuzz = fuzz; +} + +- (InputMode) mode { + return mode; +} + +- (void) resetState { + state = QuietState; +} + +- (void) setMode:(InputMode)m { + if (mode != m) { + if (mode == BoundingBoxMode) { + [renderer setBoundingBoxHandlesShown:NO]; + } + mode = m; + [self deselectAll]; + if (m == BoundingBoxMode) { + [renderer setBoundingBoxHandlesShown:YES]; + } + } +} + +- (BOOL) circleWithCenter:(NSPoint)c andRadius:(float)r containsPoint:(NSPoint)p { + return (NSDistanceBetweenPoints(c, p) <= r); +} + +- (void) lookForControlPointAt:(NSPoint)pos { + const float cpr = [Edge controlPointRadius]; + for (Edge *e in [[[self doc] pickSupport] selectedEdges]) { + NSPoint cp1 = [[renderer transformer] toScreen:[e cp1]]; + if ([self circleWithCenter:cp1 andRadius:cpr containsPoint:pos]) { + state = DragEdgeControlPoint1; + modifyEdge = e; + [[self doc] startModifyEdge:e]; + return; + } + NSPoint cp2 = [[renderer transformer] toScreen:[e cp2]]; + if ([self circleWithCenter:cp2 andRadius:cpr containsPoint:pos]) { + state = DragEdgeControlPoint2; + modifyEdge = e; + [[self doc] startModifyEdge:e]; + return; + } + } +} + +- (void) mousePressAt:(NSPoint)pos withButton:(MouseButton)button andMask:(InputMask)mask { + dragOrigin = pos; + + // we should already be in a quiet state, but no harm in making sure + state = QuietState; + + if (mode == HandMode || mask == ControlMask) { + state = CanvasDragState; + oldOrigin = [[renderer transformer] origin]; + } else if (mode == DrawEdgeMode) { + leaderNode = [renderer anyNodeAt:pos]; + if (leaderNode != nil) { + state = EdgeDragState; + } + } else if (mode == BoundingBoxMode) { + state = BoundingBoxState; + grabbedResizeHandle = [renderer boundingBoxResizeHandleAt:pos]; + [[self doc] startChangeBoundingBox]; + if (grabbedResizeHandle == NoHandle) { + [[[self doc] graph] setBoundingBox:NSZeroRect]; + [renderer setBoundingBoxHandlesShown:NO]; + } + } else if (mode == SelectMode) { + modifyEdge = nil; + [self lookForControlPointAt:pos]; + + if (modifyEdge == nil) { + // we didn't find a control point + + BOOL unionSelect = (mask & unionSelectMask); + + leaderNode = [renderer anyNodeAt:pos]; + // if we hit a node, deselect other nodes (if Shift is up) and go to move mode + if (leaderNode != nil) { + BOOL alreadySelected = [[self doc] isNodeSelected:leaderNode]; + if (!unionSelect && !alreadySelected) { + [self deselectAllEdges]; + [self deselectAllNodes]; + } + if (unionSelect && alreadySelected) { + state = ToggleSelectState; + } else { + [[[self doc] pickSupport] selectNode:leaderNode]; + state = MoveSelectedNodesState; + oldLeaderPos = [leaderNode point]; + [[self doc] startShiftNodes:[[[self doc] pickSupport] selectedNodes]]; + } + } + + // if mouse did not hit a node, check if mouse hit an edge + if (leaderNode == nil) { + Edge *edge = [renderer anyEdgeAt:pos withFuzz:edgeFuzz]; + if (edge != nil) { + BOOL alreadySelected = [[self doc] isEdgeSelected:edge]; + if (!unionSelect) { + [self deselectAll]; + } + if (unionSelect && alreadySelected) { + [[[self doc] pickSupport] deselectEdge:edge]; + } else { + [[[self doc] pickSupport] selectEdge:edge]; + } + } else { + // if mouse did not hit anything, put us in box mode + if (!unionSelect) { + [self deselectAll]; + } + [selectionBoxContents removeAllObjects]; + state = SelectBoxState; + } + } + } + } +} + +- (void) mouseReleaseAt:(NSPoint)pos withButton:(MouseButton)button andMask:(InputMask)mask { + if (state == SelectBoxState) { + BOOL shouldDeselect = !(mask & unionSelectMask); + if (shouldDeselect) { + [self deselectAllEdges]; + } + [[[self doc] pickSupport] selectAllNodes:selectionBoxContents + replacingSelection:shouldDeselect]; + [renderer clearSelectionBox]; + } else if (state == ToggleSelectState) { + [[[self doc] pickSupport] deselectNode:leaderNode]; + leaderNode = nil; + } else if (state == MoveSelectedNodesState) { + if (NSEqualPoints (oldLeaderPos, [leaderNode point])) { + [[self doc] cancelShiftNodes]; + } else { + [[self doc] endShiftNodes]; + } + leaderNode = nil; + } else if (state == DragEdgeControlPoint1 || state == DragEdgeControlPoint2) { + // FIXME: check if there was any real change + [[self doc] endModifyEdge]; + } else if (state == EdgeDragState) { + [renderer clearHalfEdge]; + Node *targ = [renderer anyNodeAt:pos]; + if (targ != nil) { + [[self doc] addEdgeFrom:leaderNode to:targ]; + } + } else if (state == QuietState && mode == CreateNodeMode) { + Transformer *transformer = [renderer transformer]; + NSPoint nodePoint = [transformer fromScreen:[[renderer grid] snapScreenPoint:pos]]; + [[self doc] addNodeAt:nodePoint]; + } else if (state == BoundingBoxState) { + [[self doc] endChangeBoundingBox]; + [renderer setBoundingBoxHandlesShown:YES]; + } + + state = QuietState; +} + +- (void) mouseDoubleClickAt:(NSPoint)pos withButton:(MouseButton)button andMask:(InputMask)mask { + if (mode != SelectMode) { + return; + } + if (state != QuietState) { + return; + } + // convert bend mode on edge under mouse cursor + Edge *edge = [renderer anyEdgeAt:pos withFuzz:edgeFuzz]; + if (edge != nil) { + [[self doc] startModifyEdge:edge]; + if ([edge bendMode]==EdgeBendModeBasic) { + [edge convertBendToAngles]; + [edge setBendMode:EdgeBendModeInOut]; + } else { + [edge setBendMode:EdgeBendModeBasic]; + } + [[self doc] endModifyEdge]; + + [self deselectAllEdges]; + [[[self doc] pickSupport] selectEdge:edge]; + } +} + +- (void) mouseMoveTo:(NSPoint)pos withButtons:(MouseButton)buttons andMask:(InputMask)mask { + Transformer *transformer = [renderer transformer]; + + if (state == ToggleSelectState) { + state = MoveSelectedNodesState; + oldLeaderPos = [leaderNode point]; + [[self doc] startShiftNodes:[[[self doc] pickSupport] selectedNodes]]; + } + + if (state == SelectBoxState) { + NSRect selectionBox = NSRectAroundPoints(dragOrigin, pos); + [renderer setSelectionBox:selectionBox]; + + NSEnumerator *enumerator = [[self doc] nodeEnumerator]; + Node *node; + while ((node = [enumerator nextObject]) != nil) { + NSPoint nodePos = [transformer toScreen:[node point]]; + if (NSPointInRect(nodePos, selectionBox)) { + if (![selectionBoxContents member:node]) { + [selectionBoxContents addObject:node]; + [renderer invalidateNode:node]; + } + } else { + if ([selectionBoxContents member:node]) { + [selectionBoxContents removeObject:node]; + [renderer invalidateNode:node]; + } + } + } + } else if (state == MoveSelectedNodesState) { + if (leaderNode != nil) { + [self shiftNodesByMovingLeader:leaderNode to:pos]; + NSPoint shiftSoFar; + shiftSoFar.x = [leaderNode point].x - oldLeaderPos.x; + shiftSoFar.y = [leaderNode point].y - oldLeaderPos.y; + [[self doc] shiftNodesUpdate:shiftSoFar]; + } + } else if (state == DragEdgeControlPoint1 || state == DragEdgeControlPoint2) { + // invalidate once before we start changing it: we may be shrinking + // the control circles + [[self doc] modifyEdgeCheckPoint]; + if (state == DragEdgeControlPoint1) { + [modifyEdge moveCp1To:[transformer fromScreen:pos] + withWeightCourseness:0.1f + andBendCourseness:15 + forceLinkControlPoints:(mask & ControlMask)]; + } else { + [modifyEdge moveCp2To:[transformer fromScreen:pos] + withWeightCourseness:0.1f + andBendCourseness:15 + forceLinkControlPoints:(mask & ControlMask)]; + } + [[self doc] modifyEdgeCheckPoint]; + } else if (state == EdgeDragState) { + [renderer setHalfEdgeFrom:leaderNode to:pos]; + } else if (state == BoundingBoxState) { + Grid *grid = [renderer grid]; + Graph *graph = [[self doc] graph]; + if (grabbedResizeHandle == NoHandle) { + NSRect bbox = NSRectAroundPoints( + [grid snapScreenPoint:dragOrigin], + [grid snapScreenPoint:pos] + ); + [graph setBoundingBox:[transformer rectFromScreen:bbox]]; + } else { + NSRect bbox = [transformer rectToScreen:[graph boundingBox]]; + NSPoint p2 = [grid snapScreenPoint:pos]; + + if (grabbedResizeHandle == NorthWestHandle || + grabbedResizeHandle == NorthHandle || + grabbedResizeHandle == NorthEastHandle) { + + float dy = p2.y - NSMinY(bbox); + if (dy < bbox.size.height) { + bbox.origin.y += dy; + bbox.size.height -= dy; + } else { + bbox.origin.y = NSMaxY(bbox); + bbox.size.height = 0; + } + + } else if (grabbedResizeHandle == SouthWestHandle || + grabbedResizeHandle == SouthHandle || + grabbedResizeHandle == SouthEastHandle) { + + float dy = p2.y - NSMaxY(bbox); + if (-dy < bbox.size.height) { + bbox.size.height += dy; + } else { + bbox.size.height = 0; + } + } + + if (grabbedResizeHandle == NorthWestHandle || + grabbedResizeHandle == WestHandle || + grabbedResizeHandle == SouthWestHandle) { + + float dx = p2.x - NSMinX(bbox); + if (dx < bbox.size.width) { + bbox.origin.x += dx; + bbox.size.width -= dx; + } else { + bbox.origin.x = NSMaxX(bbox); + bbox.size.width = 0; + } + + } else if (grabbedResizeHandle == NorthEastHandle || + grabbedResizeHandle == EastHandle || + grabbedResizeHandle == SouthEastHandle) { + + float dx = p2.x - NSMaxX(bbox); + if (-dx < bbox.size.width) { + bbox.size.width += dx; + } else { + bbox.size.width = 0; + } + } + [graph setBoundingBox:[transformer rectFromScreen:bbox]]; + } + [[self doc] changeBoundingBoxCheckPoint]; + } else if (state == CanvasDragState) { + NSPoint newOrigin = oldOrigin; + newOrigin.x += pos.x - dragOrigin.x; + newOrigin.y += pos.y - dragOrigin.y; + [[renderer transformer] setOrigin:newOrigin]; + [renderer invalidateGraph]; + } +} + +- (void) mouseScrolledAt:(NSPoint)pos inDirection:(ScrollDirection)dir withMask:(InputMask)mask { + if (mask == ControlMask) { + if (dir == ScrollUp) { + [[renderer surface] zoomInAboutPoint:pos]; + } else if (dir == ScrollDown) { + [[renderer surface] zoomOutAboutPoint:pos]; + } + } +} + +@end + +// vim:ft=objc:ts=8:et:sts=4:sw=4 |