#import "qedefs.h" id xyview_i; id scalemenu_i, gridmenu_i, scrollview_i, gridbutton_i, scalebutton_i; vec3_t xy_viewnormal; // v_forward for xy view float xy_viewdist; // clip behind this plane @implementation XYView /* ================== initFrame: ================== */ - initFrame:(const NXRect *)frameRect { [super initFrame:frameRect]; [self allocateGState]; NXSetRect (&realbounds, 0,0,0,0); gridsize = 16; scale = 1.0; xyview_i = self; xy_viewnormal[2] = -1; xy_viewdist = -1024; // // initialize the pop up menus // scalemenu_i = [[PopUpList alloc] init]; [scalemenu_i setTarget: self]; [scalemenu_i setAction: @selector(scaleMenuTarget:)]; [scalemenu_i addItem: "12.5%"]; [scalemenu_i addItem: "25%"]; [scalemenu_i addItem: "50%"]; [scalemenu_i addItem: "75%"]; [scalemenu_i addItem: "100%"]; [scalemenu_i addItem: "200%"]; [scalemenu_i addItem: "300%"]; [[scalemenu_i itemList] selectCellAt: 4 : 0]; scalebutton_i = NXCreatePopUpListButton(scalemenu_i); gridmenu_i = [[PopUpList alloc] init]; [gridmenu_i setTarget: self]; [gridmenu_i setAction: @selector(gridMenuTarget:)]; [gridmenu_i addItem: "grid 1"]; [gridmenu_i addItem: "grid 2"]; [gridmenu_i addItem: "grid 4"]; [gridmenu_i addItem: "grid 8"]; [gridmenu_i addItem: "grid 16"]; [gridmenu_i addItem: "grid 32"]; [gridmenu_i addItem: "grid 64"]; [[gridmenu_i itemList] selectCellAt: 4 : 0]; gridbutton_i = NXCreatePopUpListButton(gridmenu_i); // initialize the scroll view scrollview_i = [[PopScrollView alloc] initFrame: frameRect button1: scalebutton_i button2: gridbutton_i ]; [scrollview_i setLineScroll: 64]; [scrollview_i setAutosizing: NX_WIDTHSIZABLE | NX_HEIGHTSIZABLE]; // link objects together [[scrollview_i setDocView: self] free]; 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 selectedCol]; [quakeed_i updateXY]; return self; } - setDrawMode: (drawmode_t)mode { drawmode = mode; [mode_radio_i selectCellAt:0: mode]; [quakeed_i updateXY]; return self; } - (float)currentScale { return scale; } /* =================== setOrigin:scale: =================== */ - setOrigin: (NXPoint *)pt scale: (float)sc { NXRect sframe; NXRect newbounds; // // calculate the area visible in the cliprect // scale = sc; [superview getFrame: &sframe]; [superview getFrame: &newbounds]; newbounds.origin = *pt; newbounds.size.width /= scale; newbounds.size.height /= scale; // // union with the realbounds // NXUnionRect (&realbounds, &newbounds); // // redisplay everything // [quakeed_i disableDisplay]; // // size this view // [self sizeTo: newbounds.size.width : newbounds.size.height]; [self setDrawOrigin: newbounds.origin.x : newbounds.origin.y]; [self moveTo: newbounds.origin.x : newbounds.origin.y]; // // scroll and scale the clip view // [superview setDrawSize : sframe.size.width/scale : sframe.size.height/scale]; [superview setDrawOrigin: pt->x : pt->y]; [quakeed_i reenableDisplay]; [scrollview_i display]; return self; } - centerOn: (vec3_t)org { NXRect sbounds; NXPoint mid, delta; [[xyview_i superview] getBounds: &sbounds]; mid.x = sbounds.origin.x + sbounds.size.width/2; mid.y = sbounds.origin.y + sbounds.size.height/2; delta.x = org[0] - mid.x; delta.y = org[1] - mid.y; sbounds.origin.x += delta.x; sbounds.origin.y += delta.y; [self setOrigin: &sbounds.origin scale: scale]; return self; } /* ================== newSuperBounds When superview is resized ================== */ - newSuperBounds { NXRect r; [superview getBounds: &r]; [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: (NXRect *)nb { NXRect sbounds; realbounds = *nb; // // calculate the area visible in the cliprect // [superview getBounds: &sbounds]; NXUnionRect (nb, &sbounds); // // size this view // [quakeed_i disableDisplay]; [self suspendNotifyAncestorWhenFrameChanged:YES]; [self sizeTo: sbounds.size.width : sbounds.size.height]; [self setDrawOrigin: sbounds.origin.x : sbounds.origin.y]; [self moveTo: sbounds.origin.x : sbounds.origin.y]; [self suspendNotifyAncestorWhenFrameChanged:NO]; [scrollview_i reflectScroll: superview]; [quakeed_i reenableDisplay]; [[scrollview_i horizScroller] display]; [[scrollview_i vertScroller] display]; return self; } /* ==================== scaleMenuTarget: Called when the scaler popup on the window is used ==================== */ - scaleMenuTarget: sender { char const *item; NXRect visrect, sframe; float nscale; item = [[sender selectedCell] title]; sscanf (item,"%f",&nscale); nscale /= 100; if (nscale == scale) return NULL; // keep the center of the view constant [superview getBounds: &visrect]; [superview getFrame: &sframe]; visrect.origin.x += visrect.size.width/2; visrect.origin.y += visrect.size.height/2; visrect.origin.x -= sframe.size.width/2/nscale; visrect.origin.y -= sframe.size.height/2/nscale; [self setOrigin: &visrect.origin scale: nscale]; return self; } /* ============== zoomIn ============== */ - zoomIn: (NXPoint *)constant { id itemlist; int selected, numrows, numcollumns; NXRect visrect; NXPoint ofs, new; // // set the popup // itemlist = [scalemenu_i itemList]; [itemlist getNumRows: &numrows numCols:&numcollumns]; selected = [itemlist selectedRow] + 1; if (selected >= numrows) return NULL; [itemlist selectCellAt: selected : 0]; [scalebutton_i setTitle: [[itemlist selectedCell] title]]; // // zoom the view // [superview getBounds: &visrect]; 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: (NXPoint *)constant { id itemlist; int selected, numrows, numcollumns; NXRect visrect; NXPoint ofs, new; // // set the popup // itemlist = [scalemenu_i itemList]; [itemlist getNumRows: &numrows numCols:&numcollumns]; selected = [itemlist selectedRow] - 1; if (selected < 0) return NULL; [itemlist selectCellAt: selected : 0]; [scalebutton_i setTitle: [[itemlist selectedCell] title]]; // // zoom the view // [superview getBounds: &visrect]; 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]; 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; void linestart (float r, float g, float b) { beginUserPath (upath,NO); cur_linecolor[0] = r; cur_linecolor[1] = g; cur_linecolor[2] = b; } void lineflush (void) { if (!upath->numberOfPoints) return; endUserPath (upath, dps_ustroke); PSsetrgbcolor (cur_linecolor[0], cur_linecolor[1], cur_linecolor[2]); sendUserPath (upath); beginUserPath (upath,NO); } 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 (); cur_linecolor[0] = r; cur_linecolor[1] = g; cur_linecolor[2] = b; } void XYmoveto (vec3_t pt) { if (upath->numberOfPoints > 2048) lineflush (); UPmoveto (upath, pt[0], pt[1]); } void XYlineto (vec3_t pt) { UPlineto (upath, pt[0], pt[1]); } /* ============ 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: (const NXRect *)rect { int x,y, stopx, stopy; float top,bottom,right,left; char text[10]; BOOL showcoords; 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; PSsetlinewidth (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= right) stopx -= gridsize; if (stopy >= top) stopy -= gridsize; beginUserPath (upath,NO); for ( ; y<=stopy ; y+= gridsize) if (y&63) { UPmoveto (upath, left, y); UPlineto (upath, right, y); } for ( ; x<=stopx ; x+= gridsize) if (x&63) { UPmoveto (upath, x, top); UPlineto (upath, x, bottom); } endUserPath (upath, dps_ustroke); PSsetrgbcolor (0.8,0.8,1.0); // thin grid color sendUserPath (upath); } // // tiles // PSsetgray (0); // 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= right) stopx -= 64; if (stopy >= top) stopy -= 64; beginUserPath (upath,NO); for ( ; y<=stopy ; y+= 64) { if (showcoords) { sprintf (text, "%i",y); PSmoveto(left,y); PSshow(text); } UPmoveto (upath, left, y); UPlineto (upath, right, y); } for ( ; x<=stopx ; x+= 64) { if (showcoords) { sprintf (text, "%i",x); PSmoveto(x,bottom+2); PSshow(text); } UPmoveto (upath, x, top); UPlineto (upath, x, bottom); } endUserPath (upath, dps_ustroke); PSsetgray (12.0/16); sendUserPath (upath); } return self; } /* ================== drawWire ================== */ - drawWire: (const NXRect *)rects { NXRect visRect; int i,j, c, c2; id ent, brush; vec3_t mins, maxs; BOOL drawnames; drawnames = [quakeed_i showNames]; if ([quakeed_i showCoordinates]) // if coords are showing, update everything { [self getVisibleRect:&visRect]; rects = &visRect; xy_draw_rect = *rects; } NXRectClip(rects); // erase window NXEraseRect (rects); // draw grid [self drawGrid: rects]; // draw all entities, world first so entities take priority linestart (0,0,0); c = [map_i count]; for (i=0 ; i=0 ; j--) { brush = [ent objectAt: j]; if ( [brush selected] ) continue; if ([brush regioned]) continue; [brush XYDrawSelf]; } if (i > 0 && drawnames) { // draw entity names brush = [ent objectAt: 0]; if (![brush regioned]) { [brush getMins: mins maxs: maxs]; PSmoveto(mins[0], mins[1]); PSsetrgbcolor (0,0,0); PSshow([ent valueForQKey: "classname"]); } } } lineflush (); // resize if needed newrect.origin.x -= gridsize; newrect.origin.y -= gridsize; newrect.size.width += 2*gridsize; newrect.size.height += 2*gridsize; if (!NXEqualRect (&newrect, &realbounds)) [self newRealBounds: &newrect]; return self; } /* ============= drawSolid ============= */ - drawSolid { unsigned char *planes[5]; NXRect visRect; [self getVisibleRect:&visRect]; // // 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:NX_RETAINED]; planes[0] = (unsigned char *)r_picbuffer; NXDrawBitmap( &visRect, r_width, r_height, 8, 3, 32, r_width*4, NO, NO, NX_RGBColorSpace, planes ); NXPing (); [[self window] setBackingType:NX_BUFFERED]; [self unlockFocus]; return self; } /* =================== drawSelf =================== */ NXRect xy_draw_rect; - drawSelf:(const NXRect *)rects :(int)rectCount { static float drawtime; // static to shut up compiler warning if (timedrawing) drawtime = I_FloatTime (); xy_draw_rect = *rects; newrect.origin.x = newrect.origin.y = 99999; newrect.size.width = newrect.size.height = -2*99999; // setup for text PSselectfont("Helvetica-Medium",10/scale); PSrotate(0); if (drawmode == dr_texture || drawmode == dr_flat) [self drawSolid]; else [self drawWire: rects]; if (timedrawing) { NXPing (); drawtime = I_FloatTime() - drawtime; printf ("CameraView drawtime: %5.3f\n", drawtime); } return self; } /* =============================================================================== USER INTERACTION =============================================================================== */ /* ================ dragLoop: ================ */ static NXPoint oldreletive; - dragFrom: (NXEvent *)startevent useGrid: (BOOL)ug callback: (void (*) (float dx, float dy)) callback { NXEvent *event; NXPoint startpt, newpt; NXPoint reletive, delta; startpt = startevent->location; [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) { event = [NXApp getNextEvent: NX_LMOUSEUPMASK | NX_LMOUSEDRAGGEDMASK | NX_RMOUSEUPMASK | NX_RMOUSEDRAGGEDMASK | NX_APPDEFINEDMASK]; if (event->type == NX_LMOUSEUP || event->type == NX_RMOUSEUP) break; if (event->type == NX_APPDEFINED) { // doesn't work. grrr. [quakeed_i applicationDefined:event]; continue; } newpt = event->location; [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: (NXEvent*)theEvent { qprintf ("dragging selection"); [self dragFrom: theEvent useGrid: YES callback: DragCallback ]; [quakeed_i updateAll]; qprintf (""); return self; } //============================================================================ void ScrollCallback (float dx, float dy) { NXRect basebounds; NXPoint neworg; float scale; [ [xyview_i superview] getBounds: &basebounds]; [xyview_i convertRectFromSuperview: &basebounds]; 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: (NXEvent*)theEvent { qprintf ("scrolling view"); [self dragFrom: theEvent useGrid: YES callback: ScrollCallback ]; qprintf (""); 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: (NXEvent*)theEvent { NXPoint pt; qprintf ("changing camera direction"); pt= theEvent->location; [self convertPoint:&pt fromView:NULL]; direction[0] = pt.x; direction[1] = pt.y; DirectionCallback (0,0); [self dragFrom: theEvent useGrid: NO callback: DirectionCallback ]; qprintf (""); 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: (NXEvent*)theEvent { id owner; texturedef_t td; NXPoint pt; qprintf ("sizing new brush"); pt= theEvent->location; [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]; qprintf (""); return self; } //============================================================================ void ControlCallback (float dx, float dy) { int i; for (i=0 ; ilocation; [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; qprintf ("dragging brush plane"); pt= theEvent->location; [self convertPoint:&pt fromView:NULL]; [self dragFrom: theEvent useGrid: YES callback: ControlCallback ]; [[map_i selectedBrush] removeIfInvalid]; [quakeed_i updateAll]; qprintf (""); return YES; } - (BOOL)shearDragFrom: (NXEvent*)theEvent { NXPoint 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->location; [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; qprintf ("dragging brush plane"); pt= theEvent->location; [self convertPoint:&pt fromView:NULL]; [self dragFrom: theEvent useGrid: YES callback: ControlCallback ]; [br removeIfInvalid]; [quakeed_i updateAll]; qprintf (""); return YES; } /* =============================================================================== INPUT METHODS =============================================================================== */ /* =================== mouseDown =================== */ - mouseDown:(NXEvent *)theEvent { NXPoint pt; id ent; vec3_t p1, p2; int flags; pt= theEvent->location; [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->flags & (NX_SHIFTMASK | NX_CONTROLMASK | NX_ALTERNATEMASK | NX_COMMANDMASK); // // shift click to select / deselect a brush from the world // if (flags == NX_SHIFTMASK) { [map_i selectRay: p1 : p2 : YES]; return self; } // // cmd-shift click to set a target/targetname entity connection // if (flags == (NX_SHIFTMASK|NX_COMMANDMASK) ) { [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->data.mouse.click > 1) { qprintf ("positioned Z checker"); [zview_i setPoint: &pt]; [quakeed_i newinstance]; [quakeed_i updateZ]; return self; } // check eye if ( [cameraview_i XYmouseDown: &pt flags: theEvent->flags] ) 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]) { qprintf ("missed"); return self; } return [self newBrushDragFrom: theEvent]; } // // control click = position and drag camera // if (flags == NX_CONTROLMASK) { [cameraview_i setXYOrigin: &pt]; [quakeed_i newinstance]; [cameraview_i display]; [cameraview_i XYmouseDown: &pt flags: theEvent->flags]; qprintf (""); return self; } // // command click = drag Z checker // if (flags == NX_COMMANDMASK) { // check single plane dragging [self shearDragFrom: theEvent]; return self; qprintf ("moving Z checker"); [zview_i setXYOrigin: &pt]; [quakeed_i updateAll]; [zview_i XYmouseDown: &pt]; qprintf (""); return self; } // // alt click = set entire brush texture // if (flags == NX_ALTERNATEMASK) { if (drawmode != dr_texture) { qprintf ("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 == (NX_CONTROLMASK | NX_ALTERNATEMASK) ) { if (drawmode != dr_texture) { qprintf ("No texture setting except in texture mode!\n"); NopSound (); return self; } [map_i setTextureRay: p1 : p2 : NO]; [quakeed_i updateAll]; return self; } qprintf ("bad flags for click"); NopSound (); return self; } /* =================== rightMouseDown =================== */ - rightMouseDown:(NXEvent *)theEvent { NXPoint pt; int flags; pt= theEvent->location; [self convertPoint:&pt fromView:NULL]; flags = theEvent->flags & (NX_SHIFTMASK | NX_CONTROLMASK | NX_ALTERNATEMASK | NX_COMMANDMASK); if (flags == NX_COMMANDMASK) { return [self scrollDragFrom: theEvent]; } if (flags == NX_ALTERNATEMASK) { return [clipper_i XYClick: pt]; } if (flags == 0 || flags == NX_CONTROLMASK) { return [self directionDragFrom: theEvent]; } qprintf ("bad flags for click"); NopSound (); return self; } @end