#include "QF/sys.h" #include "XYView.h" #include "ZView.h" #include "CameraView.h" #include "Clipper.h" #include "QuakeEd.h" #include "Map.h" #include "Entity.h" #include "PopScrollView.h" id xyview_i; id scrollview_i, gridbutton_i, scalebutton_i; vec3_t xy_viewnormal; // v_forward for xy view float xy_viewdist; // clip behind this plane @implementation NSView(XYView) -(void) setFrame:(NSRect) frame bounds:(NSRect) bounds scale:(NSSize) scale { // XXX[quakeed_i disableDisplay]; //[self setPostsFrameChangedNotifications:NO]; //[self setPostsBoundsChangedNotifications:NO]; [self setFrame: frame]; if (_boundsMatrix) { //FIXME workaround for a bug (?) in GNUstep NSAffineTransformStruct t = [_boundsMatrix transformStruct]; t.m11 = t.m22 = 1; t.m12 = t.m21 = 0; [_boundsMatrix setTransformStruct: t]; } [self setBounds: bounds]; if (_boundsMatrix) { //FIXME workaround for a bug (?) in GNUstep NSAffineTransformStruct t = [_boundsMatrix transformStruct]; t.tX *= scale.width; t.tY *= scale.height; [_boundsMatrix setTransformStruct: t]; } //[self setPostsFrameChangedNotifications:YES]; //[self setPostsBoundsChangedNotifications:YES]; // XXX[quakeed_i reenableDisplay]; } @end @implementation XYView /* ================== initWithFrame: ================== */ - initWithFrame:(NSRect) frameRect { [super initWithFrame:frameRect]; [self allocateGState]; realbounds = NSMakeRect (0, 0, 0, 0); gridsize = 16; scale = 1.0; xyview_i = self; xy_viewnormal[2] = -1; xy_viewdist = -1024; // // initialize the pop up menus // scalebutton_i =[[NSPopUpButton alloc] init]; [scalebutton_i setTarget:self]; [scalebutton_i setAction: @selector (scaleMenuTarget:)]; [scalebutton_i addItemWithTitle:@"12.5%"]; [scalebutton_i addItemWithTitle:@"25%"]; [scalebutton_i addItemWithTitle:@"50%"]; [scalebutton_i addItemWithTitle:@"75%"]; [scalebutton_i addItemWithTitle:@"100%"]; [scalebutton_i addItemWithTitle:@"200%"]; [scalebutton_i addItemWithTitle:@"300%"]; [scalebutton_i sizeToFit]; [scalebutton_i selectItemAtIndex:4]; gridbutton_i =[[NSPopUpButton alloc] init]; [gridbutton_i setTarget:self]; [gridbutton_i setAction: @selector (gridMenuTarget:)]; [gridbutton_i addItemWithTitle:@"grid 1"]; [gridbutton_i addItemWithTitle:@"grid 2"]; [gridbutton_i addItemWithTitle:@"grid 4"]; [gridbutton_i addItemWithTitle:@"grid 8"]; [gridbutton_i addItemWithTitle:@"grid 16"]; [gridbutton_i addItemWithTitle:@"grid 32"]; [gridbutton_i addItemWithTitle:@"grid 64"]; [gridbutton_i sizeToFit]; [gridbutton_i selectItemAtIndex:4]; // initialize the scroll view scrollview_i = [[PopScrollView alloc] initWithFrame: frameRect button1: scalebutton_i button2: gridbutton_i]; [scrollview_i setLineScroll:64]; [scrollview_i setAutoresizingMask:(NSViewWidthSizable | NSViewHeightSizable)]; // link objects together [scrollview_i setDocumentView:self]; return scrollview_i; } -(BOOL) acceptsFirstResponder { return YES; } -setModeRadio:m { // this should be set from IB, but because I toss myself in a // popscrollview the connection gets lost mode_radio_i = m; [mode_radio_i setTarget:self]; [mode_radio_i setAction: @selector (drawMode:)]; return self; } -drawMode:sender { drawmode =[sender selectedColumn]; [quakeed_i updateXY]; return self; } -setDrawMode:(drawmode_t) mode { drawmode = mode; [mode_radio_i selectCellAtRow: 0 column:mode]; [quakeed_i updateXY]; return self; } -(float) currentScale { return scale; } -setOrigin:(NSPoint)pt scale:(float) sc { NSRect sframe; NSRect bounds; NSClipView *cv = (NSClipView *) _super_view; // calculate the area visible in the cliprect scale = sc; bounds = [_super_view bounds]; bounds.origin = pt; bounds.size.width /= scale; bounds.size.height /= scale; // union with the realbounds bounds = NSUnionRect (realbounds, bounds); sframe = bounds; sframe.origin.x *= scale; sframe.origin.y *= scale; sframe.size.width *= scale; sframe.size.height *= scale; // redisplay everything // size this view [quakeed_i disableFlushWindow]; [self setFrame:sframe bounds:bounds scale:NSMakeSize (scale, scale)]; // scroll the clip view pt.x *= scale; pt.y *= scale; [cv setBoundsOrigin:pt]; [scrollview_i reflectScrolledClipView: cv]; [quakeed_i enableFlushWindow]; [scrollview_i display]; return self; } -centerOn:(vec3_t) org { NSRect sbounds; NSPoint mid, origin; sbounds = [_super_view bounds]; mid.x = sbounds.size.width / 2; mid.y = sbounds.size.height / 2; origin.x = org[0] - mid.x / scale; origin.y = org[1] - mid.y / scale; [self setOrigin: origin scale:scale]; return self; } /* ================== newSuperBounds When superview is resized ================== */ -newSuperBounds { NSRect r; r =[[self superview] bounds]; [self newRealBounds:r]; return self; } /* =================== newRealBounds Called when the realbounds rectangle is changed. Should only change the scroll bars, not cause any redraws. If realbounds has shrunk, nothing will change. =================== */ -newRealBounds:(NSRect) nb { NSRect bounds; NSRect sframe; realbounds = nb; // calculate the area visible in the cliprect bounds = [_super_view bounds]; bounds.origin.x /= scale; bounds.origin.y /= scale; bounds.size.width /= scale; bounds.size.height /= scale; bounds = NSUnionRect (realbounds, bounds); sframe = bounds; sframe.origin.x *= scale; sframe.origin.y *= scale; sframe.size.width *= scale; sframe.size.height *= scale; // size this view [quakeed_i disableFlushWindow]; [self setFrame:sframe bounds:bounds scale:NSMakeSize (scale, scale)]; [quakeed_i enableFlushWindow]; [scrollview_i reflectScrolledClipView:[scrollview_i contentView]]; return self; } /* ==================== scaleMenuTarget: Called when the scaler popup on the window is used ==================== */ -scaleMenuTarget:sender { char const *item; NSRect rect; NSPoint mid, org, origin; float nscale; item =[[[sender selectedCell] title] cString]; sscanf (item, "%f", &nscale); nscale /= 100; if (nscale == scale) return NULL; // keep the center of the view constant rect = [_super_view bounds]; mid.x = rect.size.width / 2; mid.y = rect.size.height / 2; org.x = (rect.origin.x + mid.x) / scale; org.y = (rect.origin.y + mid.y) / scale; origin.x = org.x - mid.x / nscale; origin.y = org.y - mid.y / nscale; [self setOrigin: origin scale:nscale]; return self; } /* ============== zoomIn ============== */ -zoomIn:(NSPoint *) constant { id itemlist, selectedItem; int selected, numrows; NSRect visrect; NSPoint ofs, new; // // set the popup // itemlist =[scalebutton_i itemArray]; numrows =[itemlist count]; selectedItem =[scalebutton_i selectedItem]; selected =[itemlist indexOfObject:selectedItem] + 1; if (selected >= numrows) return NULL; [scalebutton_i selectItemAtIndex:selected]; // // zoom the view // visrect =[[self superview] bounds]; ofs.x = constant->x - visrect.origin.x; ofs.y = constant->y - visrect.origin.y; new.x = constant->x - ofs.x / 2; new.y = constant->y - ofs.y / 2; [self setOrigin: new scale:scale * 2]; return self; } /* ============== zoomOut ============== */ -zoomOut:(NSPoint *) constant { id itemlist, selectedItem; int selected; NSRect visrect; NSPoint ofs, new; // // set the popup // itemlist =[scalebutton_i itemArray]; selectedItem =[scalebutton_i selectedItem]; selected =[itemlist indexOfObject:selectedItem] - 1; if (selected < 0) return NULL; [scalebutton_i selectItemAtIndex:selected]; // // zoom the view // visrect =[[self superview] bounds]; ofs.x = constant->x - visrect.origin.x; ofs.y = constant->y - visrect.origin.y; new.x = constant->x - ofs.x * 2; new.y = constant->y - ofs.y * 2; [self setOrigin: new scale:scale / 2]; return self; } /* ==================== gridMenuTarget: Called when the scaler popup on the window is used ==================== */ -gridMenuTarget:sender { char const *item; int grid; item =[[[sender selectedCell] title] cString]; sscanf (item, "grid %d", &grid); if (grid == gridsize) return NULL; gridsize = grid; [quakeed_i updateAll]; return self; } /* ==================== snapToGrid ==================== */ -(float) snapToGrid:(float) f { int i; i = rint (f / gridsize); return i * gridsize; } -(int) gridsize { return gridsize; } /* =================== addToScrollRange:: =================== */ -addToScrollRange: (float) x:(float) y; { if (x < newrect.origin.x) { newrect.size.width += newrect.origin.x - x; newrect.origin.x = x; } if (y < newrect.origin.y) { newrect.size.height += newrect.origin.y - y; newrect.origin.y = y; } if (x > newrect.origin.x + newrect.size.width) newrect.size.width += x - (newrect.origin.x + newrect.size.width); if (y > newrect.origin.y + newrect.size.height) newrect.size.height += y - (newrect.origin.y + newrect.size.height); return self; } /* =================== superviewChanged =================== */ -superviewChanged { [self newRealBounds:realbounds]; return self; } /* =============================================================================== DRAWING METHODS =============================================================================== */ vec3_t cur_linecolor; NSBezierPath *path; void linestart (float r, float g, float b) { [path removeAllPoints]; VectorSet (r, g, b, cur_linecolor); } void lineflush (void) { if ([path isEmpty]) return; // endUserPath (upath, dps_ustroke); [[NSColor colorWithCalibratedRed: cur_linecolor[0] green: cur_linecolor[1] blue: cur_linecolor[2] alpha: 1.0] set]; [path stroke]; [path removeAllPoints]; } void linecolor (float r, float g, float b) { if (cur_linecolor[0] == r && cur_linecolor[1] == g && cur_linecolor[2] == b) return; // do nothing lineflush (); VectorSet (r, g, b, cur_linecolor); } void XYmoveto (vec3_t pt) { NSPoint point = { pt[0], pt[1] }; if ([path elementCount] > 2048) lineflush (); [path moveToPoint:point]; } void XYlineto (vec3_t pt) { NSPoint point = { pt[0], pt[1] }; [path lineToPoint:point]; } /* ============ drawGrid Draws tile markings every 64 units, and grid markings at the grid scale if the grid lines are greater than or equal to 4 pixels apart Rect is in global world (unscaled) coordinates ============ */ -drawGrid:(NSRect) rect { int x, y, stopx, stopy; float top, bottom, right, left; NSMutableDictionary *attribs = [NSMutableDictionary dictionary]; BOOL showcoords; NSPoint point; showcoords =[quakeed_i showCoordinates]; left = rect.origin.x - 1; bottom = rect.origin.y - 1; right = rect.origin.x + rect.size.width + 2; top = rect.origin.y + rect.size.height + 2; [path removeAllPoints]; [path setLineWidth: 0.15]; // // grid // // can't just divide by grid size because of negetive coordinate // truncating direction // if (gridsize >= 4 / scale) { y = floor (bottom / gridsize); stopy = floor (top / gridsize); x = floor (left / gridsize); stopx = floor (right / gridsize); y *= gridsize; stopy *= gridsize; x *= gridsize; stopx *= gridsize; if (y < bottom) y += gridsize; if (x < left) x += gridsize; if (stopx >= right) stopx -= gridsize; if (stopy >= top) stopy -= gridsize; [path removeAllPoints]; for (; y <= stopy; y += gridsize) if (y & 63) { point.x = left; point.y = y; [path moveToPoint:point]; point.x = right; [path lineToPoint:point]; } for (; x <= stopx; x += gridsize) if (x & 63) { point.x = x; point.y = top; [path moveToPoint:point]; point.y = bottom; [path lineToPoint:point]; } // endUserPath (upath, dps_ustroke); [[NSColor colorWithCalibratedRed: 0.8 green: 0.8 blue: 1.0 alpha: 1.0] set]; // thin grid color [path stroke]; } // // tiles // [[NSColor colorWithCalibratedWhite: 0.0 / 16.0 alpha: 1.0] set]; // for text if (scale > 4.0 / 64) { y = floor (bottom / 64); stopy = floor (top / 64); x = floor (left / 64); stopx = floor (right / 64); y *= 64; stopy *= 64; x *= 64; stopx *= 64; if (y < bottom) y += 64; if (x < left) x += 64; if (stopx >= right) stopx -= 64; if (stopy >= top) stopy -= 64; [path removeAllPoints]; for (; y <= stopy; y += 64) { if (showcoords) { NSString *s = [NSString stringWithFormat: @"%i", y]; [s drawAtPoint: NSMakePoint (left, y) withAttributes: attribs]; } [path moveToPoint:point]; point.x = right; [path lineToPoint:point]; } for (; x <= stopx; x += 64) { if (showcoords) { NSString *s = [NSString stringWithFormat: @"%i", x]; [s drawAtPoint: NSMakePoint (x, bottom + 2) withAttributes: attribs]; } point.x = x; point.y = top; [path moveToPoint:point]; point.y = bottom; [path lineToPoint:point]; } // endUserPath (upath, dps_ustroke); [[NSColor colorWithCalibratedWhite: 12.0 / 16.0 alpha: 1.0] set]; [path stroke]; } [path setLineWidth: 1]; return self; } /* ================== drawWire ================== */ -drawWire:(NSRect) rect { NSRect visRect; int i, j, c, c2; id ent, brush; vec3_t mins, maxs; BOOL drawnames; NSMutableDictionary *attribs = [NSMutableDictionary dictionary]; drawnames =[quakeed_i showNames]; if ([quakeed_i showCoordinates]) // if coords are showing, update // everything { visRect =[self visibleRect]; rect = visRect; xy_draw_rect = rect; } NSRectClip (rect); // erase window NSEraseRect (rect); // draw grid [self drawGrid:rect]; // draw all entities, world first so entities take priority linestart (0, 0, 0); c =[map_i count]; for (i = 0; i < c; i++) { ent =[map_i objectAtIndex:i]; c2 =[ent count]; for (j = c2 - 1; j >= 0; j--) { brush =[ent objectAtIndex:j]; if ([brush selected]) continue; if ([brush regioned]) continue; [brush XYDrawSelf]; } if (i > 0 && drawnames) { // draw entity names brush =[ent objectAtIndex:0]; if (![brush regioned]) { const char *classname = [ent valueForQKey:"classname"]; NSString *s = [NSString stringWithCString: classname]; [[NSColor colorWithCalibratedWhite: 0.0 / 16.0 alpha: 1.0] set]; [brush getMins: mins maxs:maxs]; [s drawAtPoint: NSMakePoint (mins[0], mins[1]) withAttributes: attribs]; } } } lineflush (); // resize if needed newrect.origin.x -= gridsize; newrect.origin.y -= gridsize; newrect.size.width += 2 * gridsize; newrect.size.height += 2 * gridsize; if (!NSEqualRects (newrect, realbounds)) [self newRealBounds:newrect]; return self; } /* ============= drawSolid ============= */ -drawSolid { const unsigned char *planes[5]; NSRect visRect; visRect =[self visibleRect]; // // draw the image into imagebuffer // r_origin[0] = visRect.origin.x; r_origin[1] = visRect.origin.y; r_origin[2] = scale / 2; // using Z as a scale for the 2D // projection r_width = visRect.size.width * r_origin[2]; r_height = visRect.size.height * r_origin[2]; if (r_width != xywidth || r_height != xyheight) { xywidth = r_width; xyheight = r_height; if (xypicbuffer) { free (xypicbuffer); free (xyzbuffer); } xypicbuffer = malloc (r_width * (r_height + 1) * 4); xyzbuffer = malloc (r_width * (r_height + 1) * 4); } r_picbuffer = xypicbuffer; r_zbuffer = xyzbuffer; REN_BeginXY (); REN_ClearBuffers (); // // render the entities // [map_i makeAllPerform:@selector (XYRenderSelf)]; // // display the output // [self lockFocus]; [[self window] setBackingType:NSBackingStoreRetained]; planes[0] = (unsigned char *) r_picbuffer; NSDrawBitmap (visRect, r_width, r_height, 8, 3, 32, r_width * 4, NO, NO, NSCalibratedRGBColorSpace, planes); // NSPing (); [[self window] setBackingType:NSBackingStoreBuffered]; [self unlockFocus]; return self; } /* =================== drawSelf =================== */ NSRect xy_draw_rect; -drawRect: (NSRect) rect { float drawtime = 0; if (timedrawing) drawtime = Sys_DoubleTime (); xy_draw_rect = rect; newrect.origin.x = newrect.origin.y = 99999; newrect.size.width = newrect.size.height = -2 * 99999; // setup for text [[NSFont systemFontOfSize: 10] set]; if (drawmode == dr_texture || drawmode == dr_flat) { [quakeed_i xyNoRestore: [self visibleRect]]; [self drawSolid]; } else { [quakeed_i xyNoRestore: rect]; [self drawWire:rect]; } if (timedrawing) { // NSPing (); drawtime = Sys_DoubleTime () - drawtime; printf ("CameraView drawtime: %5.3f\n", drawtime); } return self; } /* =============================================================================== USER INTERACTION =============================================================================== */ /* ================ dragLoop: ================ */ static NSPoint oldreletive; -dragFrom: (NSEvent *) startevent useGrid: (BOOL) ug callback:(void (*)(float dx, float dy)) callback { NSEvent *event; NSPoint startpt, newpt; NSPoint reletive, delta; startpt =[startevent locationInWindow]; startpt =[self convertPoint: startpt fromView:NULL]; oldreletive.x = oldreletive.y = 0; if (ug) { startpt.x =[self snapToGrid:startpt.x]; startpt.y =[self snapToGrid:startpt.y]; } while (1) { unsigned eventMask = NSLeftMouseUpMask | NSLeftMouseDraggedMask | NSRightMouseUpMask | NSRightMouseDraggedMask | NSApplicationDefinedMask; event =[NSApp nextEventMatchingMask: eventMask untilDate:[NSDate distantFuture] inMode: NSEventTrackingRunLoopMode dequeue:YES]; if ([event type] == NSLeftMouseUp ||[event type] == NSRightMouseUp) break; if ([event type] == NSApplicationDefined) { // doesn't work. grrr. // [quakeed_i applicationDefined:event]; continue; } newpt =[event locationInWindow]; newpt =[self convertPoint: newpt fromView:NULL]; if (ug) { newpt.x =[self snapToGrid:newpt.x]; newpt.y =[self snapToGrid:newpt.y]; } reletive.x = newpt.x - startpt.x; reletive.y = newpt.y - startpt.y; if (reletive.x == oldreletive.x && reletive.y == oldreletive.y) continue; delta.x = reletive.x - oldreletive.x; delta.y = reletive.y - oldreletive.y; oldreletive = reletive; callback (delta.x, delta.y); } return self; } //============================================================================ void DragCallback (float dx, float dy) { sb_translate[0] = dx; sb_translate[1] = dy; sb_translate[2] = 0; [map_i makeSelectedPerform:@selector (translate)]; [quakeed_i redrawInstance]; } -selectionDragFrom:(NSEvent *) theEvent { Sys_Printf ("dragging selection\n"); [self dragFrom: theEvent useGrid: YES callback:DragCallback]; [quakeed_i updateAll]; return self; } //============================================================================ void ScrollCallback (float dx, float dy) { NSRect basebounds; NSPoint neworg; float scale; basebounds =[[xyview_i superview] bounds]; [xyview_i convertRect: basebounds fromView:[xyview_i superview]]; neworg.x = basebounds.origin.x - dx; neworg.y = basebounds.origin.y - dy; scale =[xyview_i currentScale]; oldreletive.x -= dx; oldreletive.y -= dy; [xyview_i setOrigin: neworg scale:scale]; } -scrollDragFrom:(NSEvent *) theEvent { Sys_Printf ("scrolling view\n"); [self dragFrom: theEvent useGrid: YES callback:ScrollCallback]; return self; } //============================================================================ vec3_t direction; void DirectionCallback (float dx, float dy) { vec3_t org; float ya; direction[0] += dx; direction[1] += dy; [cameraview_i getOrigin:org]; if (direction[0] == org[0] && direction[1] == org[1]) return; ya = atan2 (direction[1] - org[1], direction[0] - org[0]); [cameraview_i setOrigin: org angle:ya]; [quakeed_i newinstance]; [cameraview_i display]; } -directionDragFrom:(NSEvent *) theEvent { NSPoint pt; Sys_Printf ("changing camera direction\n"); pt =[theEvent locationInWindow]; pt =[self convertPoint: pt fromView:NULL]; direction[0] = pt.x; direction[1] = pt.y; DirectionCallback (0, 0); [self dragFrom: theEvent useGrid: NO callback:DirectionCallback]; return self; } //============================================================================ id newbrush; vec3_t neworg, newdrag; void NewCallback (float dx, float dy) { vec3_t min, max; int i; newdrag[0] += dx; newdrag[1] += dy; for (i = 0; i < 3; i++) { if (neworg[i] < newdrag[i]) { min[i] = neworg[i]; max[i] = newdrag[i]; } else { min[i] = newdrag[i]; max[i] = neworg[i]; } } [newbrush setMins: min maxs:max]; [quakeed_i redrawInstance]; } -newBrushDragFrom:(NSEvent *) theEvent { id owner; texturedef_t td; NSPoint pt; Sys_Printf ("sizing new brush\n"); pt =[theEvent locationInWindow]; pt =[self convertPoint: pt fromView:NULL]; neworg[0] =[self snapToGrid:pt.x]; neworg[1] =[self snapToGrid:pt.y]; neworg[2] =[map_i currentMinZ]; newdrag[0] = neworg[0]; newdrag[1] = neworg[1]; newdrag[2] =[map_i currentMaxZ]; owner =[map_i currentEntity]; [texturepalette_i getTextureDef:&td]; newbrush =[[SetBrush alloc] initOwner: owner mins: neworg maxs: newdrag texture:&td]; [owner addObject:newbrush]; [newbrush setSelected:YES]; [self dragFrom: theEvent useGrid: YES callback:NewCallback]; [newbrush removeIfInvalid]; [quakeed_i updateCamera]; return self; } //============================================================================ void ControlCallback (float dx, float dy) { int i; for (i = 0; i < numcontrolpoints; i++) { controlpoints[i][0] += dx; controlpoints[i][1] += dy; } [[map_i selectedBrush] calcWindings]; [quakeed_i redrawInstance]; } -(BOOL) planeDragFrom:(NSEvent *) theEvent { NSPoint pt; vec3_t dragpoint; if ([map_i numSelected] != 1) return NO; pt =[theEvent locationInWindow]; pt =[self convertPoint: pt fromView:NULL]; dragpoint[0] = pt.x; dragpoint[1] = pt.y; dragpoint[2] = 2048; [[map_i selectedBrush] getXYdragface:dragpoint]; if (!numcontrolpoints) return NO; Sys_Printf ("dragging brush plane\n"); pt =[theEvent locationInWindow]; pt =[self convertPoint: pt fromView:NULL]; [self dragFrom: theEvent useGrid: YES callback:ControlCallback]; [[map_i selectedBrush] removeIfInvalid]; [quakeed_i updateAll]; return YES; } -(BOOL) shearDragFrom:(NSEvent *) theEvent { NSPoint pt; vec3_t dragpoint; vec3_t p1, p2; float time; id br; int face; if ([map_i numSelected] != 1) return NO; br =[map_i selectedBrush]; pt =[theEvent locationInWindow]; pt =[self convertPoint: pt fromView:NULL]; // if the XY point is inside the brush, make the point on top p1[0] = pt.x; p1[1] = pt.y; VectorCopy (p1, p2); p1[2] = -2048 * xy_viewnormal[2]; p2[2] = 2048 * xy_viewnormal[2]; VectorCopy (p1, dragpoint); [br hitByRay: p1: p2: &time:&face]; if (time > 0) { dragpoint[2] = p1[2] + (time - 0.01) * xy_viewnormal[2]; } else { [br getMins: p1 maxs:p2]; dragpoint[2] = (p1[2] + p2[2]) / 2; } [br getXYShearPoints:dragpoint]; if (!numcontrolpoints) return NO; Sys_Printf ("dragging brush plane\n"); pt =[theEvent locationInWindow]; pt =[self convertPoint: pt fromView:NULL]; [self dragFrom: theEvent useGrid: YES callback:ControlCallback]; [br removeIfInvalid]; [quakeed_i updateAll]; return YES; } /* =============================================================================== INPUT METHODS =============================================================================== */ /* =================== mouseDown =================== */ -mouseDown:(NSEvent *) theEvent { NSPoint pt; id ent; vec3_t p1, p2; int flags; pt =[theEvent locationInWindow]; pt =[self convertPoint: pt fromView:NULL]; p1[0] = p2[0] = pt.x; p1[1] = p2[1] = pt.y; p1[2] = xy_viewnormal[2] * -4096; p2[2] = xy_viewnormal[2] * 4096; flags = [theEvent modifierFlags] & (NSShiftKeyMask | NSControlKeyMask | NSAlternateKeyMask | NSCommandKeyMask); // shift click to select / deselect a brush from the world if (flags == NSShiftKeyMask) { [map_i selectRay: p1: p2:YES]; return self; } // cmd-shift click to set a target/targetname entity connection if (flags == (NSShiftKeyMask | NSCommandKeyMask)) { [map_i entityConnect: p1:p2]; return self; } // bare click to either drag selection, or rubber band a new brush if (flags == 0) { // if double click, position Z checker if ([theEvent clickCount] > 1) { Sys_Printf ("positioned Z checker\n"); [zview_i setPoint:&pt]; [quakeed_i newinstance]; [quakeed_i updateZ]; return self; } // check eye if ([cameraview_i XYmouseDown: &pt flags:[theEvent modifierFlags]]) return self; // camera move // check z post if ([zview_i XYmouseDown:&pt]) return self; // z view move // check clippers if ([clipper_i XYDrag:&pt]) return self; // check single plane dragging if ([self planeDragFrom:theEvent]) return self; // check selection ent =[map_i grabRay: p1:p2]; if (ent) return[self selectionDragFrom:theEvent]; if ([map_i numSelected]) { Sys_Printf ("missed\n"); return self; } return[self newBrushDragFrom:theEvent]; } // control click = position and drag camera if (flags == NSControlKeyMask) { [cameraview_i setXYOrigin:&pt]; [quakeed_i newinstance]; [cameraview_i display]; [cameraview_i XYmouseDown: &pt flags:[theEvent modifierFlags]]; return self; } // command click = drag Z checker if (flags == NSCommandKeyMask) { // check single plane dragging [self shearDragFrom:theEvent]; return self; Sys_Printf ("moving Z checker\n"); [zview_i setXYOrigin:&pt]; [quakeed_i updateAll]; [zview_i XYmouseDown:&pt]; return self; } // alt click = set entire brush texture if (flags == NSAlternateKeyMask) { if (drawmode != dr_texture) { Sys_Printf ("No texture setting except in texture mode!\n"); NopSound (); return self; } [map_i setTextureRay: p1: p2:YES]; [quakeed_i updateAll]; return self; } // ctrl-alt click = set single face texture if (flags == (NSControlKeyMask | NSAlternateKeyMask)) { if (drawmode != dr_texture) { Sys_Printf ("No texture setting except in texture mode!\n"); NopSound (); return self; } [map_i setTextureRay: p1: p2:NO]; [quakeed_i updateAll]; return self; } Sys_Printf ("bad flags for click %x\n", flags); NopSound (); return self; } /* =================== rightMouseDown =================== */ -rightMouseDown:(NSEvent *) theEvent { NSPoint pt; int flags; pt =[theEvent locationInWindow]; pt =[self convertPoint: pt fromView:NULL]; flags = [theEvent modifierFlags] & (NSShiftKeyMask | NSControlKeyMask | NSAlternateKeyMask | NSCommandKeyMask); if (flags == NSCommandKeyMask) { return[self scrollDragFrom:theEvent]; } if (flags == NSAlternateKeyMask) { return[clipper_i XYClick:pt]; } if (flags == 0 || flags == NSControlKeyMask) { return[self directionDragFrom:theEvent]; } Sys_Printf ("bad flags for click\n"); NopSound (); return self; } @end