/* viDOOM - level editor for DOOM Copyright (C) 2000 Ian Cowburn (ianc@noddybox.demon.co.uk) 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, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ------------------------------------------------------------------------- Editor generic event handler definitions */ static const char rcs_id[]="$Id$"; #include "config.h" #include "globals.h" #include #include "editvar.h" #include "platgui.h" #include "mem.h" /* ---------------------------------------- PREDICATE FUNCTIONS */ static int PredSelected(void *a,void *b) { int *i1,*i2; i1=a; i2=b; return(*i1==*i2); } /* ---------------------------------------- OBJECT LOCATORS */ void GenericCheckMouse(void) { static PLAT_MENU gen_menu[]={{"Insert",TM_INSERT},{NULL,0}}; Object *o; int f; Iterator i; int temp_select=FALSE; int map_x,map_y; TRACE; map_x=XToMap(ms.x); map_y=YToMap(ms.y); /* If an object is already selected then see if it is still over it */ if (current!=-1) { o=MapElem(map,current); if (!(PositionOnObject(map_x,map_y,o->data))) { if (o->select!=SELECT_SELECTED) SetSelect(current,SELECT_NONE); current=-1; DrawObject(o->data,o->select); DrawObjectInfo(); } } if (current==-1) for(f=0;(fdata) { if (PositionOnObject(map_x,map_y,o->data)) { current=f; if (o->select!=SELECT_SELECTED) SetSelect(current,SELECT_OVER); DrawObject(o->data,o->select); DrawObjectInfo(); } } } /* Do selection box if shift pressed */ if ((ms.b&GFX_BUTLEFT)&&(ms.shift)) { GFXEvent e; int x1,y1,x2,y2; GFX_set_XOR_mode(); do { int w,h; do { GFX_await_input_full(&e); } while(e.type!=GFX_MOUSE_EVENT); w=e.mouse.x-ms.x; h=e.mouse.y-ms.y; GFX_rect(ms.x,ms.y,w,h,WHITE); GFX_redraw(); GFX_rect(ms.x,ms.y,w,h,WHITE); } while(e.mouse.b&GFX_BUTLEFT); GFX_clear_XOR_mode(); GFX_redraw(); x1=MIN(XToMap(ms.x),XToMap(e.mouse.x)); y1=MIN(YToMap(ms.y),YToMap(e.mouse.y)); x2=MAX(XToMap(ms.x),XToMap(e.mouse.x)); y2=MAX(YToMap(ms.y),YToMap(e.mouse.y)); if (!(e.mouse.ctrl|ms.ctrl)) ClearSelection(); SelectBox(x1,y1,x2,y2); memcpy(&ms,&e.mouse,sizeof(e.mouse)); FullRedraw(); } else /* Handle left (select) and right (menu) buttons */ { if (ms.b&GFX_BUTLEFT) if (current==-1) { if (!ms.ctrl) { ClearSelection(); FullRedraw(); } } else { if (ms.ctrl) { o=MapElem(map,current); if (o->select==SELECT_SELECTED) { if ((i=ListFindElem(selected,PredSelected,¤t))) { i=IteratorDelete(i); i=IteratorClear(i); } SetSelect(current,SELECT_NONE); DrawObject(o->data,SELECT_NONE); } else { SetSelect(current,SELECT_SELECTED); ListAppend(selected,¤t); DrawObject(o->data,SELECT_SELECTED); } } else { ClearSelectionLeaveCurrent(); SetSelect(current,SELECT_SELECTED); ListAppend(selected,¤t); FullRedraw(); } } /* If the middle or right button is pressed over an object, check adding the object to the selected list */ if ((ms.b&(GFX_BUTRIGHT|GFX_BUTMIDDLE))&&(current!=-1)) { /* If there is currently nothing selected then this object is selected for the duration of the move or menu operation */ if (ListSize(selected)==0) { temp_select=TRUE; ListAppend(selected,¤t); o=MapElem(map,current); SetSelect(current,SELECT_SELECTED); DrawObject(o->data,o->select); } else if (hover_select!=HOVER_NONE) { o=MapElem(map,current); if (o->select!=SELECT_SELECTED) { if (hover_select==HOVER_SINGLE) ClearSelectionLeaveCurrent(); o=MapElem(map,current); SetSelect(current,SELECT_SELECTED); ListAppend(selected,¤t); FullRedraw(); } } } /* If the middle button is pressed move the object. This is provided as a shortcut to the menu move option */ if ((ms.b&GFX_BUTMIDDLE)&&(ListSize(selected))) MoveObject(); /* If the right button is pressed selected the editting options */ if (ms.b&GFX_BUTRIGHT) if (ListSize(selected)) ObjectMenu(); else switch(GUI_menu(typename,ms.x,ms.y,gen_menu,GUI_CANCEL)) { case TM_INSERT: ObjectInsert(); break; default: break; } if ((temp_select)&&(!new_selection)) { ClearSelection(); FullRedraw(); } } } /* ---------------------------------------- INPUT HANDLERS */ void SetEditMode(int mode) { TRACE; ClearSelection(); current=-1; edit_mode=mode; switch(mode) { case SECTOR_MODE: typename="Sector"; map=sector; PositionOnObject=PositionOnObject_SECTOR; SelectBox=SelectBox_SECTOR; SelectByType=SelectByType_SECTOR; DrawObject=DrawObject_SECTOR; DrawObjectInfo=DrawObjectInfo_SECTOR; DrawObjectHeader=DrawObjectHeader_SECTOR; MoveObject=MoveObject_SECTOR; RotateObject=RotateObject_SECTOR; ScaleObject=ScaleObject_SECTOR; SetTagObject=SetTagObject_SECTOR; LocateObject=LocateObject_SECTOR; ObjectMenu=ObjectMenu_SECTOR; ObjectInsert=ObjectInsert_SECTOR; ObjectDelete=ObjectDelete_SECTOR; ObjectKey=ObjectKey_SECTOR; ObjectHasTag=ObjectHasTag_SECTOR; SetSelect=SetSelect_GENERIC; ObjectOverlaid=ObjectOverlaid_SECTOR; break; case LINEDEF_MODE: typename="Linedef"; map=linedef; PositionOnObject=PositionOnObject_LINEDEF; SelectBox=SelectBox_LINEDEF; SelectByType=SelectByType_LINEDEF; DrawObject=DrawObject_LINEDEF; DrawObjectInfo=DrawObjectInfo_LINEDEF; DrawObjectHeader=DrawObjectHeader_LINEDEF; MoveObject=MoveObject_LINEDEF; RotateObject=RotateObject_LINEDEF; ScaleObject=ScaleObject_LINEDEF; SetTagObject=SetTagObject_LINEDEF; LocateObject=LocateObject_LINEDEF; ObjectMenu=ObjectMenu_LINEDEF; ObjectInsert=ObjectInsert_LINEDEF; ObjectDelete=ObjectDelete_LINEDEF; ObjectKey=ObjectKey_LINEDEF; ObjectHasTag=ObjectHasTag_LINEDEF; SetSelect=SetSelect_GENERIC; ObjectOverlaid=ObjectOverlaid_LINEDEF; break; case VERTEX_MODE: typename="Vertex"; map=vertex; PositionOnObject=PositionOnObject_VERTEX; SelectBox=SelectBox_VERTEX; SelectByType=SelectByType_VERTEX; DrawObject=DrawObject_VERTEX; DrawObjectInfo=DrawObjectInfo_VERTEX; DrawObjectHeader=DrawObjectHeader_VERTEX; MoveObject=MoveObject_VERTEX; RotateObject=RotateObject_VERTEX; ScaleObject=ScaleObject_VERTEX; SetTagObject=SetTagObject_VERTEX; LocateObject=LocateObject_VERTEX; ObjectMenu=ObjectMenu_VERTEX; ObjectInsert=ObjectInsert_VERTEX; ObjectDelete=ObjectDelete_VERTEX; ObjectKey=ObjectKey_VERTEX; ObjectHasTag=ObjectHasTag_VERTEX; SetSelect=SetSelect_GENERIC; ObjectOverlaid=ObjectOverlaid_VERTEX; break; case THING_MODE: typename="Thing"; map=thing; PositionOnObject=PositionOnObject_THING; SelectBox=SelectBox_THING; SelectByType=SelectByType_THING; DrawObject=DrawObject_THING; DrawObjectInfo=DrawObjectInfo_THING; DrawObjectHeader=DrawObjectHeader_THING; MoveObject=MoveObject_THING; RotateObject=RotateObject_THING; ScaleObject=ScaleObject_THING; SetTagObject=SetTagObject_THING; LocateObject=LocateObject_THING; ObjectMenu=ObjectMenu_THING; ObjectInsert=ObjectInsert_THING; ObjectDelete=ObjectDelete_THING; ObjectKey=ObjectKey_THING; ObjectHasTag=ObjectHasTag_THING; SetSelect=SetSelect_GENERIC; ObjectOverlaid=ObjectOverlaid_THING; break; case MULTI_MODE: GenerateMultiMap(); typename="Multimode"; map=multimap; PositionOnObject=PositionOnObject_MULTI; SelectBox=SelectBox_MULTI; SelectByType=SelectByType_MULTI; DrawObject=DrawObject_MULTI; DrawObjectInfo=DrawObjectInfo_MULTI; DrawObjectHeader=DrawObjectHeader_MULTI; MoveObject=MoveObject_MULTI; RotateObject=RotateObject_MULTI; ScaleObject=ScaleObject_MULTI; SetTagObject=SetTagObject_MULTI; LocateObject=LocateObject_MULTI; ObjectMenu=ObjectMenu_MULTI; ObjectInsert=ObjectInsert_MULTI; ObjectDelete=ObjectDelete_MULTI; ObjectKey=ObjectKey_MULTI; ObjectHasTag=ObjectHasTag_MULTI; SetSelect=SetSelect_MULTI; ObjectOverlaid=ObjectOverlaid_MULTI; break; } GenericCheckMouse(); FullRedraw(); } /* This handles the keys that should usable in all modes (movement, scale, grid, etc) */ void HandleMoveKey(GFXKey k, int check_mouse) { int cx,cy; TRACE; if (k.code!=GFX_ASCII) switch(k.code) { case GFX_DOWN: if (k.ctrl) oy-=scale; else oy-=scale*(k.shift ? 60 : 20); if (check_mouse) GenericCheckMouse(); FullRedraw(); break; case GFX_UP: if (k.ctrl) oy+=scale; else oy+=scale*(k.shift ? 60 : 20); if (check_mouse) GenericCheckMouse(); FullRedraw(); break; case GFX_RIGHT: if (k.ctrl) ox+=scale; else ox+=scale*(k.shift ? 60 : 20); if (check_mouse) GenericCheckMouse(); FullRedraw(); break; case GFX_LEFT: if (k.ctrl) ox-=scale; else ox-=scale*(k.shift ? 60 : 20); if (check_mouse) GenericCheckMouse(); FullRedraw(); break; case GFX_PGDN: if ((--scale)<1) scale=1; else { cx=ox+(scale+1)*SCRW/2; cy=oy-(scale+1)*SCRH/2; ox=cx-(scale)*SCRW/2; oy=cy+(scale)*SCRH/2; } if (check_mouse) GenericCheckMouse(); FullRedraw(); break; case GFX_PGUP: if ((++scale)>32) scale=32; else { cx=ox+(scale-1)*SCRW/2; cy=oy-(scale-1)*SCRH/2; ox=cx-(scale)*SCRW/2; oy=cy+(scale)*SCRH/2; } if (check_mouse) GenericCheckMouse(); FullRedraw(); break; default: break; } else switch(toupper(k.ascii)) { case 'G': grid_onoff=!grid_onoff; FullRedraw(); break; case 'X': grid_lock=!grid_lock; DrawHeader(); break; case 'Q': grid_size/=2; if (grid_size<2) grid_size=2; FullRedraw(); break; case 'W': grid_size*=2; if (grid_size>512) grid_size=512; FullRedraw(); break; #ifdef DEBUG case 'D': case 'd': { static PLAT_MENU debug_menu[]= { {"Dump current selection list",1}, {"Save screen",2}, {NULL,-1} }; switch(GUI_menu("DEBUG",0,0,debug_menu,-1)) { case 1: { static char ds[128]; Iterator i; int *f; Debug(("No selections : %d\n",ListSize(selected))); i=ListIterator(selected); ds[0]=0; while(i) { f=IteratorData(i); if (strlen(ds)>60) { Debug(("%s\n",ds)); ds[0]=0; } sprintf(ds+strlen(ds),"%d, ",*f); i=IteratorNext(i); } strcat(ds,""); Debug(("%s\n",ds)); } break; case 2: { static int i=0; char p[10]; sprintf(p,"pic%d.bmp",i++); GFX_save_screen(p); } break; default: break; } break; } #endif default: break; } } void HandleKey(GFXKey k) { Object *o; int f; TRACE; HandleMoveKey(k,TRUE); ObjectKey(k); if (k.code!=GFX_ASCII) switch(k.code) { case GFX_F1: for(f=0;general_help_keys[f];f++) { char title[80]; sprintf(title,"HELP (Keys) Page %d",f+1); GuiInfoBox(title,"%s",general_help_keys[f]); FullRedraw(); } GuiInfoBox("HELP (Mouse)","%s",general_help_mouse); FullRedraw(); break; case GFX_F2: { char s[128]; sprintf(s,"%s Mode Keys",typename); GuiInfoBox(s,"%s",mode_help[edit_mode]); FullRedraw(); break; } case GFX_TAB: if (k.shift) SetEditMode(PREV_MODE(edit_mode)); else SetEditMode(NEXT_MODE(edit_mode)); break; case GFX_INSERT: ObjectInsert(); break; case GFX_DELETE: ObjectDelete(); break; case GFX_F9: if (k.shift) { ListEmpty(selected); for(f=0;fdata) if (o->select==SELECT_SELECTED) SetSelect(f,SELECT_NONE); else { SetSelect(f,SELECT_SELECTED); ListAppend(selected,&f); } } } else ClearSelection(); FullRedraw(); break; case GFX_F10: if (k.shift) { SelectByType(); FullRedraw(); } else if ((k.alt)||(k.ctrl)) { char title[128]; char **pick; ObjDesc *od; int no,sel; od=ObjectOverlaid(XToMap(ms.x),YToMap(ms.y),&no); if (od) { pick=Grab(sizeof(char *)*(no+1)); for(f=0;fdata) { SetSelect(f,SELECT_SELECTED); ListAppend(selected,&f); } } FullRedraw(); } break; case GFX_F11: { static int last_sel=0; Iterator i; int *n; Object *o; if (ListSize(selected)) { if (k.shift) last_sel--; else last_sel++; if (last_sel<0) last_sel=ListSize(selected)-1; if (last_sel>=ListSize(selected)) last_sel=0; i=ListIterator(selected); for(f=0;fdata); } IteratorClear(i); FullRedraw(); } break; } case GFX_F3: MergeWad(); /* In Multi mode we must notify the MultiMap that new vertexes and things have been added. This should always be safe as new objects are added at the end of the current objects (ie. holes in the maps are not filled in), so the current selection is safe. */ if (edit_mode==MULTI_MODE) GenerateMultiMap(); break; case GFX_F4: { int tmp; tmp=TmpAddCurrent(); if (ListSize(selected)) { MoveObject(); if (tmp) ListEmpty(selected); } break; } case GFX_F5: { static double last_rot=0.0; int tmp; tmp=TmpAddCurrent(); rotate_dialog[D_ROTATE].data.d=last_rot; if (ListSize(selected)) { if (GUI_dialog("Rotate",D_ROTATE_NO,rotate_dialog)) { last_rot=rotate_dialog[D_ROTATE].data.d; RotateObject(-last_rot); FullRedraw(); } if (tmp) ListEmpty(selected); } break; } case GFX_F6: { static double last_scale=1.0; int tmp; tmp=TmpAddCurrent(); scale_dialog[D_SCALE].data.d=last_scale; if (ListSize(selected)) { if (GUI_dialog("Scale",D_SCALE_NO,scale_dialog)) { ScaleObject(last_scale=scale_dialog[D_SCALE].data.d); FullRedraw(); } if (tmp) ListEmpty(selected); } break; } case GFX_F7: if (k.shift) { static int last_tag=0; int f; Object *o; tag_dialog[D_TAG].data.i=last_tag; if (GUI_dialog("Tag number to select",D_TAG_NO,tag_dialog)) { last_tag=tag_dialog[D_TAG].data.i; for(f=0;fdata)&&(ObjectHasTag(o->data,last_tag))) { SetSelect(f,SELECT_SELECTED); ListAppend(selected,&f); } } FullRedraw(); } } else { static int last_tag=0; int tmp; tmp=TmpAddCurrent(); tag_dialog[D_TAG].data.i=last_tag; if (ListSize(selected)) { if (GUI_dialog("Tag number",D_TAG_NO,tag_dialog)) { SetTagObject(last_tag=tag_dialog[D_TAG].data.i); DrawObjectInfo(); } if (tmp) ListEmpty(selected); } } break; case GFX_F8: if (edit_mode!=MULTI_MODE) { static int last_no=0; objno_dialog[D_OBJNO].data.i=last_no; if (GUI_dialog("Object number",D_OBJNO_NO,objno_dialog)) { Object *o; int f; f=objno_dialog[D_OBJNO].data.i; o=MapElem(map,f); if ((o)&&(o->data)) { last_no=objno_dialog[D_OBJNO].data.i; if (k.shift) { SetSelect(f,SELECT_SELECTED); ListAppend(selected,&f); } LocateObject(o->data); GenericCheckMouse(); FullRedraw(); } else { GuiInfoBox("ERROR","Object does not exist"); FullRedraw(); } } } break; case GFX_ESC: quit=TRUE; break; default: break; } else switch(toupper(k.ascii)) { case 'R': FullRedraw(); break; case 'S': SetEditMode(SECTOR_MODE); break; case 'L': SetEditMode(LINEDEF_MODE); break; case 'V': SetEditMode(VERTEX_MODE); break; case 'T': SetEditMode(THING_MODE); break; case 'C': SetEditMode(MULTI_MODE); break; case '[': { int tmp; tmp=TmpAddCurrent(); if (ListSize(selected)) { RotateObject(5.0); if (tmp) ListEmpty(selected); FullRedraw(); } break; } case ']': { int tmp; tmp=TmpAddCurrent(); if (ListSize(selected)) { RotateObject(-5.0); if (tmp) ListEmpty(selected); FullRedraw(); } break; } case '{': { int tmp; tmp=TmpAddCurrent(); if (ListSize(selected)) { ScaleObject(0.90); if (tmp) ListEmpty(selected); FullRedraw(); } break; } case '}': { int tmp; tmp=TmpAddCurrent(); if (ListSize(selected)) { ScaleObject(1.10); if (tmp) ListEmpty(selected); FullRedraw(); } break; } default: break; } } void HandleMouse(GFXMouse m) { TRACE; memcpy(&ms,&m,sizeof(m)); GenericCheckMouse(); DrawHeader(); } /* END OF FILE */