1 //------------------------------------------------------------------------
2 //  COMMAND FUNCTIONS
3 //------------------------------------------------------------------------
4 //
5 //  Eureka DOOM Editor
6 //
7 //  Copyright (C) 2001-2018 Andrew Apted
8 //  Copyright (C) 1997-2003 Andr� Majorel et al
9 //
10 //  This program is free software; you can redistribute it and/or
11 //  modify it under the terms of the GNU General Public License
12 //  as published by the Free Software Foundation; either version 2
13 //  of the License, or (at your option) any later version.
14 //
15 //  This program is distributed in the hope that it will be useful,
16 //  but WITHOUT ANY WARRANTY; without even the implied warranty of
17 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18 //  GNU General Public License for more details.
19 //
20 //------------------------------------------------------------------------
21 //
22 //  Based on Yadex which incorporated code from DEU 5.21 that was put
23 //  in the public domain in 1994 by Rapha�l Quinet and Brendon Wyber.
24 //
25 //------------------------------------------------------------------------
26 
27 #include "main.h"
28 
29 #include "e_checks.h"
30 #include "e_cutpaste.h"
31 #include "e_hover.h"
32 #include "r_grid.h"
33 #include "e_linedef.h"
34 #include "e_main.h"
35 #include "e_objects.h"
36 #include "e_sector.h"
37 #include "e_path.h"
38 #include "e_vertex.h"
39 #include "m_config.h"
40 #include "m_editlump.h"
41 #include "m_events.h"
42 #include "m_loadsave.h"
43 #include "m_nodes.h"
44 #include "r_render.h"
45 #include "r_subdiv.h"
46 #include "ui_window.h"
47 #include "ui_about.h"
48 #include "ui_misc.h"
49 #include "ui_prefs.h"
50 
51 
52 // config items
53 int minimum_drag_pixels = 5;
54 
55 
CMD_Nothing()56 void CMD_Nothing()
57 {
58 	/* hey jude, don't make it bad */
59 }
60 
61 
CMD_MetaKey()62 void CMD_MetaKey()
63 {
64 	if (edit.sticky_mod)
65 	{
66 		ClearStickyMod();
67 		return;
68 	}
69 
70 	Status_Set("META...");
71 
72 	edit.sticky_mod = MOD_META;
73 }
74 
75 
CMD_EditMode()76 void CMD_EditMode()
77 {
78 	char mode = tolower(EXEC_Param[0][0]);
79 
80 	if (! mode || ! strchr("lstvr", mode))
81 	{
82 		Beep("Bad parameter for EditMode: '%s'", EXEC_Param[0]);
83 		return;
84 	}
85 
86 	Editor_ChangeMode(mode);
87 }
88 
89 
CMD_Select()90 void CMD_Select()
91 {
92 	if (edit.render3d)
93 		return;
94 
95 	// FIXME : action in effect?
96 
97 	// FIXME : split_line in effect?
98 
99 	if (edit.highlight.is_nil())
100 	{
101 		Beep("Nothing under cursor");
102 		return;
103 	}
104 
105 	Selection_Toggle(edit.highlight);
106 	RedrawMap();
107 }
108 
109 
CMD_SelectAll()110 void CMD_SelectAll()
111 {
112 	Editor_ClearErrorMode();
113 
114 	int total = NumObjects(edit.mode);
115 
116 	Selection_Push();
117 
118 	edit.Selected->change_type(edit.mode);
119 	edit.Selected->frob_range(0, total-1, BOP_ADD);
120 
121 	RedrawMap();
122 }
123 
124 
CMD_UnselectAll()125 void CMD_UnselectAll()
126 {
127 	Editor_ClearErrorMode();
128 
129 	if (edit.action == ACT_DRAW_LINE ||
130 		edit.action == ACT_TRANSFORM)
131 	{
132 		Editor_ClearAction();
133 	}
134 
135 	Selection_Clear();
136 
137 	RedrawMap();
138 }
139 
140 
CMD_InvertSelection()141 void CMD_InvertSelection()
142 {
143 	// do not clear selection when in error mode
144 	edit.error_mode = false;
145 
146 	int total = NumObjects(edit.mode);
147 
148 	if (edit.Selected->what_type() != edit.mode)
149 	{
150 		// convert the selection
151 		selection_c *prev_sel = edit.Selected;
152 		edit.Selected = new selection_c(edit.mode, true /* extended */);
153 
154 		ConvertSelection(prev_sel, edit.Selected);
155 		delete prev_sel;
156 	}
157 
158 	edit.Selected->frob_range(0, total-1, BOP_TOGGLE);
159 
160 	RedrawMap();
161 }
162 
163 
CMD_Quit()164 void CMD_Quit()
165 {
166 	Main_Quit();
167 }
168 
169 
CMD_Undo()170 void CMD_Undo()
171 {
172 	if (! BA_Undo())
173 	{
174 		Beep("No operation to undo");
175 		return;
176 	}
177 
178 	RedrawMap();
179 	main_win->UpdatePanelObj();
180 }
181 
182 
CMD_Redo()183 void CMD_Redo()
184 {
185 	if (! BA_Redo())
186 	{
187 		Beep("No operation to redo");
188 		return;
189 	}
190 
191 	RedrawMap();
192 	main_win->UpdatePanelObj();
193 }
194 
195 
SetGamma(int new_val)196 static void SetGamma(int new_val)
197 {
198 	usegamma = CLAMP(0, new_val, 4);
199 
200 	W_UpdateGamma();
201 
202 	// for OpenGL, need to reload all images
203 	if (main_win && main_win->canvas)
204 		main_win->canvas->DeleteContext();
205 
206 	Status_Set("gamma level %d", usegamma);
207 
208 	RedrawMap();
209 }
210 
211 
CMD_SetVar()212 void CMD_SetVar()
213 {
214 	const char *var_name = EXEC_Param[0];
215 	const char *value    = EXEC_Param[1];
216 
217 	if (! var_name[0])
218 	{
219 		Beep("Set: missing var name");
220 		return;
221 	}
222 
223 	if (! value[0])
224 	{
225 		Beep("Set: missing value");
226 		return;
227 	}
228 
229 	 int  int_val = atoi(value);
230 	bool bool_val = (int_val > 0);
231 
232 
233 	if (y_stricmp(var_name, "3d") == 0)
234 	{
235 		Render3D_Enable(bool_val);
236 	}
237 	else if (y_stricmp(var_name, "browser") == 0)
238 	{
239 		Editor_ClearAction();
240 
241 		int want_vis   = bool_val ? 1 : 0;
242 		int is_visible = main_win->browser->visible() ? 1 : 0;
243 
244 		if (want_vis != is_visible)
245 			main_win->BrowserMode('/');
246 	}
247 	else if (y_stricmp(var_name, "grid") == 0)
248 	{
249 		grid.SetShown(bool_val);
250 	}
251 	else if (y_stricmp(var_name, "snap") == 0)
252 	{
253 		grid.SetSnap(bool_val);
254 	}
255 	else if (y_stricmp(var_name, "sprites") == 0)
256 	{
257 		edit.thing_render_mode = int_val;
258 		RedrawMap();
259 	}
260 	else if (y_stricmp(var_name, "obj_nums") == 0)
261 	{
262 		edit.show_object_numbers = bool_val;
263 		RedrawMap();
264 	}
265 	else if (y_stricmp(var_name, "gamma") == 0)
266 	{
267 		SetGamma(int_val);
268 	}
269 	else if (y_stricmp(var_name, "ratio") == 0)
270 	{
271 		grid.ratio = CLAMP(0, int_val, 7);
272 		main_win->info_bar->UpdateRatio();
273 		RedrawMap();
274 	}
275 	else if (y_stricmp(var_name, "sec_render") == 0)
276 	{
277 		int_val = CLAMP(0, int_val, (int)SREND_SoundProp);
278 		edit.sector_render_mode = (sector_rendering_mode_e) int_val;
279 
280 		if (edit.render3d)
281 			Render3D_Enable(false);
282 
283 		// need sectors mode for sound propagation display
284 		if (edit.sector_render_mode == SREND_SoundProp && edit.mode != OBJ_SECTORS)
285 			Editor_ChangeMode('s');
286 
287 		RedrawMap();
288 	}
289 	else
290 	{
291 		Beep("Set: unknown var: %s", var_name);
292 	}
293 }
294 
295 
CMD_ToggleVar()296 void CMD_ToggleVar()
297 {
298 	const char *var_name = EXEC_Param[0];
299 
300 	if (! var_name[0])
301 	{
302 		Beep("Toggle: missing var name");
303 		return;
304 	}
305 
306 	if (y_stricmp(var_name, "3d") == 0)
307 	{
308 		Render3D_Enable(! edit.render3d);
309 	}
310 	else if (y_stricmp(var_name, "browser") == 0)
311 	{
312 		Editor_ClearAction();
313 
314 		main_win->BrowserMode('/');
315 	}
316 	else if (y_stricmp(var_name, "recent") == 0)
317 	{
318 		main_win->browser->ToggleRecent();
319 	}
320 	else if (y_stricmp(var_name, "grid") == 0)
321 	{
322 		grid.ToggleShown();
323 	}
324 	else if (y_stricmp(var_name, "snap") == 0)
325 	{
326 		grid.ToggleSnap();
327 	}
328 	else if (y_stricmp(var_name, "sprites") == 0)
329 	{
330 		edit.thing_render_mode = ! edit.thing_render_mode;
331 		RedrawMap();
332 	}
333 	else if (y_stricmp(var_name, "obj_nums") == 0)
334 	{
335 		edit.show_object_numbers = ! edit.show_object_numbers;
336 		RedrawMap();
337 	}
338 	else if (y_stricmp(var_name, "gamma") == 0)
339 	{
340 		SetGamma((usegamma >= 4) ? 0 : usegamma + 1);
341 	}
342 	else if (y_stricmp(var_name, "ratio") == 0)
343 	{
344 		if (grid.ratio >= 7)
345 			grid.ratio = 0;
346 		else
347 			grid.ratio++;
348 
349 		main_win->info_bar->UpdateRatio();
350 		RedrawMap();
351 	}
352 	else if (y_stricmp(var_name, "sec_render") == 0)
353 	{
354 		if (edit.sector_render_mode >= SREND_SoundProp)
355 			edit.sector_render_mode = SREND_Nothing;
356 		else
357 			edit.sector_render_mode = (sector_rendering_mode_e)(1 + (int)edit.sector_render_mode);
358 		RedrawMap();
359 	}
360 	else
361 	{
362 		Beep("Toggle: unknown var: %s", var_name);
363 	}
364 }
365 
366 
CMD_BrowserMode()367 void CMD_BrowserMode()
368 {
369 	if (! EXEC_Param[0][0])
370 	{
371 		Beep("BrowserMode: missing mode");
372 		return;
373 	}
374 
375 	char mode = toupper(EXEC_Param[0][0]);
376 
377 	if (! (mode == 'L' || mode == 'S' || mode == 'O' ||
378 	       mode == 'T' || mode == 'F' || mode == 'G'))
379 	{
380 		Beep("Unknown browser mode: %s", EXEC_Param[0]);
381 		return;
382 	}
383 
384 	// if that browser is already open, close it now
385 	if (main_win->browser->visible() &&
386 		main_win->browser->GetMode() == mode &&
387 		! Exec_HasFlag("/force") &&
388 		! Exec_HasFlag("/recent"))
389 	{
390 		main_win->BrowserMode(0);
391 		return;
392 	}
393 
394 	main_win->BrowserMode(mode);
395 
396 	if (Exec_HasFlag("/recent"))
397 	{
398 		main_win->browser->ToggleRecent(true /* force */);
399 	}
400 }
401 
402 
CMD_Scroll()403 void CMD_Scroll()
404 {
405 	// these are percentages
406 	float delta_x = atof(EXEC_Param[0]);
407 	float delta_y = atof(EXEC_Param[1]);
408 
409 	if (delta_x == 0 && delta_y == 0)
410 	{
411 		Beep("Bad parameter to Scroll: '%s' %s'", EXEC_Param[0], EXEC_Param[1]);
412 		return;
413 	}
414 
415 	int base_size = (main_win->canvas->w() + main_win->canvas->h()) / 2;
416 
417 	delta_x = delta_x * base_size / 100.0 / grid.Scale;
418 	delta_y = delta_y * base_size / 100.0 / grid.Scale;
419 
420 	grid.Scroll(delta_x, delta_y);
421 }
422 
423 
NAV_Scroll_Left_release(void)424 static void NAV_Scroll_Left_release(void)
425 {
426 	edit.nav_left = 0;
427 }
428 
CMD_NAV_Scroll_Left()429 void CMD_NAV_Scroll_Left()
430 {
431 	if (! EXEC_CurKey)
432 		return;
433 
434 	if (! edit.is_navigating)
435 		Editor_ClearNav();
436 
437 	float perc = atof(EXEC_Param[0]);
438 	int base_size = (main_win->canvas->w() + main_win->canvas->h()) / 2;
439 	edit.nav_left = perc * base_size / 100.0 / grid.Scale;
440 
441 	Nav_SetKey(EXEC_CurKey, &NAV_Scroll_Left_release);
442 }
443 
444 
NAV_Scroll_Right_release(void)445 static void NAV_Scroll_Right_release(void)
446 {
447 	edit.nav_right = 0;
448 }
449 
CMD_NAV_Scroll_Right()450 void CMD_NAV_Scroll_Right()
451 {
452 	if (! EXEC_CurKey)
453 		return;
454 
455 	if (! edit.is_navigating)
456 		Editor_ClearNav();
457 
458 	float perc = atof(EXEC_Param[0]);
459 	int base_size = (main_win->canvas->w() + main_win->canvas->h()) / 2;
460 	edit.nav_right = perc * base_size / 100.0 / grid.Scale;
461 
462 	Nav_SetKey(EXEC_CurKey, &NAV_Scroll_Right_release);
463 }
464 
465 
NAV_Scroll_Up_release(void)466 static void NAV_Scroll_Up_release(void)
467 {
468 	edit.nav_up = 0;
469 }
470 
CMD_NAV_Scroll_Up()471 void CMD_NAV_Scroll_Up()
472 {
473 	if (! EXEC_CurKey)
474 		return;
475 
476 	if (! edit.is_navigating)
477 		Editor_ClearNav();
478 
479 	float perc = atof(EXEC_Param[0]);
480 	int base_size = (main_win->canvas->w() + main_win->canvas->h()) / 2;
481 	edit.nav_up = perc * base_size / 100.0 / grid.Scale;
482 
483 	Nav_SetKey(EXEC_CurKey, &NAV_Scroll_Up_release);
484 }
485 
486 
NAV_Scroll_Down_release(void)487 static void NAV_Scroll_Down_release(void)
488 {
489 	edit.nav_down = 0;
490 }
491 
CMD_NAV_Scroll_Down()492 void CMD_NAV_Scroll_Down()
493 {
494 	if (! EXEC_CurKey)
495 		return;
496 
497 	if (! edit.is_navigating)
498 		Editor_ClearNav();
499 
500 	float perc = atof(EXEC_Param[0]);
501 	int base_size = (main_win->canvas->w() + main_win->canvas->h()) / 2;
502 	edit.nav_down = perc * base_size / 100.0 / grid.Scale;
503 
504 	Nav_SetKey(EXEC_CurKey, &NAV_Scroll_Down_release);
505 }
506 
507 
NAV_MouseScroll_release(void)508 static void NAV_MouseScroll_release(void)
509 {
510 	Editor_ScrollMap(+1);
511 }
512 
CMD_NAV_MouseScroll()513 void CMD_NAV_MouseScroll()
514 {
515 	if (! EXEC_CurKey)
516 		return;
517 
518 	edit.panning_speed = atof(EXEC_Param[0]);
519 	edit.panning_lax = Exec_HasFlag("/LAX");
520 
521 	if (! edit.is_navigating)
522 		Editor_ClearNav();
523 
524 	if (Nav_SetKey(EXEC_CurKey, &NAV_MouseScroll_release))
525 	{
526 		// begin
527 		Editor_ScrollMap(-1);
528 	}
529 }
530 
531 
532 static void DoBeginDrag();
533 
534 
CheckBeginDrag()535 void CheckBeginDrag()
536 {
537 	if (! edit.clicked.valid())
538 		return;
539 
540 	if (! edit.click_check_drag)
541 		return;
542 
543 	// can drag things and sector planes in 3D mode
544 	if (edit.render3d && !(edit.mode == OBJ_THINGS || edit.mode == OBJ_SECTORS))
545 		return;
546 
547 	int pixel_dx = Fl::event_x() - edit.click_screen_x;
548 	int pixel_dy = Fl::event_y() - edit.click_screen_y;
549 
550 	if (MAX(abs(pixel_dx), abs(pixel_dy)) < minimum_drag_pixels)
551 		return;
552 
553 	// if highlighted object is in selection, we drag the selection,
554 	// otherwise we drag just this one object.
555 
556 	if (edit.click_force_single || !edit.Selected->get(edit.clicked.num))
557 		edit.dragged = edit.clicked;
558 	else
559 		edit.dragged.clear();
560 
561 	DoBeginDrag();
562 }
563 
DoBeginDrag()564 static void DoBeginDrag()
565 {
566 	edit.drag_start_x = edit.drag_cur_x = edit.click_map_x;
567 	edit.drag_start_y = edit.drag_cur_y = edit.click_map_y;
568 	edit.drag_start_z = edit.drag_cur_z = edit.click_map_z;
569 
570 	edit.drag_screen_dx  = edit.drag_screen_dy = 0;
571 	edit.drag_thing_num  = -1;
572 	edit.drag_other_vert = -1;
573 
574 	// the focus is only used when grid snapping is on
575 	GetDragFocus(&edit.drag_focus_x, &edit.drag_focus_y, edit.click_map_x, edit.click_map_y);
576 
577 	if (edit.render3d)
578 	{
579 		if (edit.mode == OBJ_SECTORS)
580 			edit.drag_sector_dz = 0;
581 
582 		if (edit.mode == OBJ_THINGS)
583 		{
584 			edit.drag_thing_num = edit.clicked.num;
585 			edit.drag_thing_floorh = edit.drag_start_z;
586 			edit.drag_thing_up_down = (Level_format != MAPF_Doom && !grid.snap);
587 
588 			// get thing's floor
589 			if (edit.drag_thing_num >= 0)
590 			{
591 				const Thing *T = Things[edit.drag_thing_num];
592 
593 				Objid sec;
594 				GetNearObject(sec, OBJ_SECTORS, T->x(), T->y());
595 
596 				if (sec.valid())
597 					edit.drag_thing_floorh = Sectors[sec.num]->floorh;
598 			}
599 		}
600 	}
601 
602 	// in vertex mode, show all the connected lines too
603 	if (edit.drag_lines)
604 	{
605 		delete edit.drag_lines;
606 		edit.drag_lines = NULL;
607 	}
608 
609 	if (edit.mode == OBJ_VERTICES)
610 	{
611 		edit.drag_lines = new selection_c(OBJ_LINEDEFS);
612 		ConvertSelection(edit.Selected, edit.drag_lines);
613 
614 		// find opposite end-point when dragging a single vertex
615 		if (edit.dragged.valid())
616 			edit.drag_other_vert = Vertex_FindDragOther(edit.dragged.num);
617 	}
618 
619 	edit.clicked.clear();
620 
621 	Editor_SetAction(ACT_DRAG);
622 
623 	main_win->canvas->redraw();
624 }
625 
626 
ACT_SelectBox_release(void)627 static void ACT_SelectBox_release(void)
628 {
629 	// check if cancelled or overridden
630 	if (edit.action != ACT_SELBOX)
631 		return;
632 
633 	Editor_ClearAction();
634 	Editor_ClearErrorMode();
635 
636 	// a mere click and release will unselect everything
637 	double x1 = 0, y1 = 0, x2 = 0, y2 = 0;
638 	if (! main_win->canvas->SelboxGet(x1, y1, x2, y2))
639 	{
640 		ExecuteCommand("UnselectAll");
641 		return;
642 	}
643 
644 	SelectObjectsInBox(edit.Selected, edit.mode, x1, y1, x2, y2);
645 	RedrawMap();
646 }
647 
648 
ACT_Drag_release(void)649 static void ACT_Drag_release(void)
650 {
651 	// check if cancelled or overridden
652 	if (edit.action != ACT_DRAG)
653 	{
654 		edit.dragged.clear();
655 		return;
656 	}
657 
658 	if (edit.render3d)
659 	{
660 		if (edit.mode == OBJ_THINGS)
661 			Render3D_DragThings();
662 
663 		if (edit.mode == OBJ_SECTORS)
664 			Render3D_DragSectors();
665 	}
666 
667 	// note: DragDelta needs edit.dragged
668 	double dx, dy;
669 	main_win->canvas->DragDelta(&dx, &dy);
670 
671 	Objid dragged(edit.dragged);
672 	edit.dragged.clear();
673 
674 	if (edit.drag_lines)
675 		edit.drag_lines->clear_all();
676 
677 	if (! edit.render3d && (dx || dy))
678 	{
679 		if (dragged.valid())
680 			DragSingleObject(dragged, dx, dy);
681 		else
682 			MoveObjects(edit.Selected, dx, dy);
683 	}
684 
685 	Editor_ClearAction();
686 
687 	RedrawMap();
688 }
689 
690 
ACT_Click_release(void)691 static void ACT_Click_release(void)
692 {
693 	Objid click_obj(edit.clicked);
694 	edit.clicked.clear();
695 
696 	edit.click_check_drag = false;
697 
698 
699 	if (edit.action == ACT_SELBOX)
700 	{
701 		ACT_SelectBox_release();
702 		return;
703 	}
704 	else if (edit.action == ACT_DRAG)
705 	{
706 		ACT_Drag_release();
707 		return;
708 	}
709 
710 	// check if cancelled or overridden
711 	if (edit.action != ACT_CLICK)
712 		return;
713 
714 	if (edit.click_check_select && click_obj.valid())
715 	{
716 		// only toggle selection if it's the same object as before
717 		Objid near_obj;
718 		if (edit.render3d)
719 			near_obj = edit.highlight;
720 		else
721 			GetNearObject(near_obj, edit.mode, edit.map_x, edit.map_y);
722 
723 		if (near_obj.num == click_obj.num)
724 			Selection_Toggle(click_obj);
725 	}
726 
727 	Editor_ClearAction();
728 	Editor_ClearErrorMode();
729 
730 	RedrawMap();
731 }
732 
CMD_ACT_Click()733 void CMD_ACT_Click()
734 {
735 	if (! EXEC_CurKey)
736 		return;
737 
738 	// require a highlighted object in 3D mode
739 	if (edit.render3d && edit.highlight.is_nil())
740 		return;
741 
742 	if (! Nav_ActionKey(EXEC_CurKey, &ACT_Click_release))
743 		return;
744 
745 	edit.click_check_select = ! Exec_HasFlag("/noselect");
746 	edit.click_check_drag   = ! Exec_HasFlag("/nodrag");
747 	edit.click_force_single = false;
748 
749 	// remember some state (for drag detection)
750 	edit.click_screen_x = Fl::event_x();
751 	edit.click_screen_y = Fl::event_y();
752 
753 	edit.click_map_x = edit.map_x;
754 	edit.click_map_y = edit.map_y;
755 	edit.click_map_z = edit.map_z;
756 
757 	// handle 3D mode, skip stuff below which only makes sense in 2D
758 	if (edit.render3d)
759 	{
760 		if (edit.highlight.type == OBJ_THINGS)
761 		{
762 			const Thing *T = Things[edit.highlight.num];
763 			edit.drag_point_dist = r_view.DistToViewPlane(T->x(), T->y());
764 		}
765 		else
766 		{
767 			edit.drag_point_dist = r_view.DistToViewPlane(edit.map_x, edit.map_y);
768 		}
769 
770 		edit.clicked = edit.highlight;
771 		Editor_SetAction(ACT_CLICK);
772 		return;
773 	}
774 
775 	// check for splitting a line, and ensure we can drag the vertex
776 	if (! Exec_HasFlag("/nosplit") &&
777 		edit.mode == OBJ_VERTICES &&
778 		edit.split_line.valid() &&
779 		edit.action != ACT_DRAW_LINE)
780 	{
781 		int split_ld = edit.split_line.num;
782 
783 		edit.click_force_single = true;   // if drag vertex, force single-obj mode
784 		edit.click_check_select = false;  // do NOT select the new vertex
785 
786 		// check if both ends are in selection, if so (and only then)
787 		// shall we select the new vertex
788 		const LineDef *L = LineDefs[split_ld];
789 
790 		bool want_select = edit.Selected->get(L->start) && edit.Selected->get(L->end);
791 
792 		BA_Begin();
793 		BA_Message("split linedef #%d", split_ld);
794 
795 		int new_vert = BA_New(OBJ_VERTICES);
796 
797 		Vertex *V = Vertices[new_vert];
798 
799 		V->SetRawXY(edit.split_x, edit.split_y);
800 
801 		SplitLineDefAtVertex(split_ld, new_vert);
802 
803 		BA_End();
804 
805 		if (want_select)
806 			edit.Selected->set(new_vert);
807 
808 		edit.clicked = Objid(OBJ_VERTICES, new_vert);
809 		Editor_SetAction(ACT_CLICK);
810 
811 		RedrawMap();
812 		return;
813 	}
814 
815 	// find the object under the pointer.
816 	GetNearObject(edit.clicked, edit.mode, edit.map_x, edit.map_y);
817 
818 	// clicking on an empty space starts a new selection box
819 	if (edit.click_check_select && edit.clicked.is_nil())
820 	{
821 		edit.selbox_x1 = edit.selbox_x2 = edit.map_x;
822 		edit.selbox_y1 = edit.selbox_y2 = edit.map_y;
823 
824 		Editor_SetAction(ACT_SELBOX);
825 		return;
826 	}
827 
828 	Editor_SetAction(ACT_CLICK);
829 }
830 
831 
CMD_ACT_SelectBox()832 void CMD_ACT_SelectBox()
833 {
834 	if (edit.render3d)
835 		return;
836 
837 	if (! EXEC_CurKey)
838 		return;
839 
840 	if (! Nav_ActionKey(EXEC_CurKey, &ACT_SelectBox_release))
841 		return;
842 
843 	edit.selbox_x1 = edit.selbox_x2 = edit.map_x;
844 	edit.selbox_y1 = edit.selbox_y2 = edit.map_y;
845 
846 	Editor_SetAction(ACT_SELBOX);
847 }
848 
849 
CMD_ACT_Drag()850 void CMD_ACT_Drag()
851 {
852 	if (! EXEC_CurKey)
853 		return;
854 
855 	if (edit.Selected->empty())
856 	{
857 		Beep("Nothing to drag");
858 		return;
859 	}
860 
861 	if (! Nav_ActionKey(EXEC_CurKey, &ACT_Drag_release))
862 		return;
863 
864 	// we only drag the selection, never a single object
865 	edit.dragged.clear();
866 
867 	DoBeginDrag();
868 }
869 
870 
Transform_Update()871 void Transform_Update()
872 {
873 	double dx1 = edit.map_x - edit.trans_param.mid_x;
874 	double dy1 = edit.map_y - edit.trans_param.mid_y;
875 
876 	double dx0 = edit.trans_start_x - edit.trans_param.mid_x;
877 	double dy0 = edit.trans_start_y - edit.trans_param.mid_y;
878 
879 	edit.trans_param.scale_x = edit.trans_param.scale_y = 1;
880 	edit.trans_param.skew_x  = edit.trans_param.skew_y  = 0;
881 	edit.trans_param.rotate  = 0;
882 
883 	if (edit.trans_mode == TRANS_K_Rotate || edit.trans_mode == TRANS_K_RotScale)
884 	{
885 		int angle1 = (int)ComputeAngle(dx1, dy1);
886 		int angle0 = (int)ComputeAngle(dx0, dy0);
887 
888 		edit.trans_param.rotate = angle1 - angle0;
889 
890 //		fprintf(stderr, "angle diff : %1.2f\n", edit.trans_rotate * 360.0 / 65536.0);
891 	}
892 
893 	switch (edit.trans_mode)
894 	{
895 		case TRANS_K_Scale:
896 		case TRANS_K_RotScale:
897 			dx1 = MAX(abs(dx1), abs(dy1));
898 			dx0 = MAX(abs(dx0), abs(dy0));
899 
900 			if (dx0)
901 			{
902 				edit.trans_param.scale_x = dx1 / (float)dx0;
903 				edit.trans_param.scale_y = edit.trans_param.scale_x;
904 			}
905 			break;
906 
907 		case TRANS_K_Stretch:
908 			if (dx0) edit.trans_param.scale_x = dx1 / (float)dx0;
909 			if (dy0) edit.trans_param.scale_y = dy1 / (float)dy0;
910 			break;
911 
912 		case TRANS_K_Rotate:
913 			// already done
914 			break;
915 
916 		case TRANS_K_Skew:
917 			if (abs(dx0) >= abs(dy0))
918 			{
919 				if (dx0) edit.trans_param.skew_y = (dy1 - dy0) / (float)dx0;
920 			}
921 			else
922 			{
923 				if (dy0) edit.trans_param.skew_x = (dx1 - dx0) / (float)dy0;
924 			}
925 			break;
926 	}
927 
928 	main_win->canvas->redraw();
929 }
930 
931 
ACT_Transform_release(void)932 static void ACT_Transform_release(void)
933 {
934 	// check if cancelled or overridden
935 	if (edit.action != ACT_TRANSFORM)
936 		return;
937 
938 	if (edit.trans_lines)
939 		edit.trans_lines->clear_all();
940 
941 	TransformObjects(edit.trans_param);
942 
943 	Editor_ClearAction();
944 
945 	RedrawMap();
946 }
947 
CMD_ACT_Transform()948 void CMD_ACT_Transform()
949 {
950 	if (edit.render3d)
951 		return;
952 
953 	if (! EXEC_CurKey)
954 		return;
955 
956 	if (edit.Selected->empty())
957 	{
958 		Beep("Nothing to scale");
959 		return;
960 	}
961 
962 	const char *keyword = EXEC_Param[0];
963 	transform_keyword_e  mode;
964 
965 	if (! keyword[0])
966 	{
967 		Beep("ACT_Transform: missing keyword");
968 		return;
969 	}
970 	else if (y_stricmp(keyword, "scale") == 0)
971 	{
972 		mode = TRANS_K_Scale;
973 	}
974 	else if (y_stricmp(keyword, "stretch") == 0)
975 	{
976 		mode = TRANS_K_Stretch;
977 	}
978 	else if (y_stricmp(keyword, "rotate") == 0)
979 	{
980 		mode = TRANS_K_Rotate;
981 	}
982 	else if (y_stricmp(keyword, "rotscale") == 0)
983 	{
984 		mode = TRANS_K_RotScale;
985 	}
986 	else if (y_stricmp(keyword, "skew") == 0)
987 	{
988 		mode = TRANS_K_Skew;
989 	}
990 	else
991 	{
992 		Beep("ACT_Transform: unknown keyword: %s", keyword);
993 		return;
994 	}
995 
996 
997 	if (! Nav_ActionKey(EXEC_CurKey, &ACT_Transform_release))
998 		return;
999 
1000 
1001 	double middle_x, middle_y;
1002 	Objs_CalcMiddle(edit.Selected, &middle_x, &middle_y);
1003 
1004 	edit.trans_mode = mode;
1005 	edit.trans_start_x = edit.map_x;
1006 	edit.trans_start_y = edit.map_y;
1007 
1008 	edit.trans_param.Clear();
1009 	edit.trans_param.mid_x = middle_x;
1010 	edit.trans_param.mid_y = middle_y;
1011 
1012 	if (edit.trans_lines)
1013 	{
1014 		delete edit.trans_lines;
1015 		edit.trans_lines = NULL;
1016 	}
1017 
1018 	if (edit.mode == OBJ_VERTICES)
1019 	{
1020 		edit.trans_lines = new selection_c(OBJ_LINEDEFS);
1021 		ConvertSelection(edit.Selected, edit.trans_lines);
1022 	}
1023 
1024 	Editor_SetAction(ACT_TRANSFORM);
1025 }
1026 
1027 
CMD_WHEEL_Scroll()1028 void CMD_WHEEL_Scroll()
1029 {
1030 	float speed = atof(EXEC_Param[0]);
1031 
1032 	if (Exec_HasFlag("/LAX"))
1033 	{
1034 		keycode_t mod = Fl::event_state() & MOD_ALL_MASK;
1035 
1036 		if (mod & MOD_SHIFT)
1037 			speed /= 3.0;
1038 		else if (mod & MOD_COMMAND)
1039 			speed *= 3.0;
1040 	}
1041 
1042 	float delta_x =     wheel_dx;
1043 	float delta_y = 0 - wheel_dy;
1044 
1045 	int base_size = (main_win->canvas->w() + main_win->canvas->h()) / 2;
1046 
1047 	speed = speed * base_size / 100.0 / grid.Scale;
1048 
1049 	grid.Scroll(delta_x * speed, delta_y * speed);
1050 }
1051 
1052 
CMD_Merge()1053 void CMD_Merge()
1054 {
1055 	switch (edit.mode)
1056 	{
1057 		case OBJ_VERTICES:
1058 			CMD_VT_Merge();
1059 			break;
1060 
1061 		case OBJ_LINEDEFS:
1062 			CMD_LIN_MergeTwo();
1063 			break;
1064 
1065 		case OBJ_SECTORS:
1066 			CMD_SEC_Merge();
1067 			break;
1068 
1069 		case OBJ_THINGS:
1070 			CMD_TH_Merge();
1071 			break;
1072 
1073 		default:
1074 			Beep("Cannot merge that");
1075 			break;
1076 	}
1077 }
1078 
1079 
CMD_Disconnect()1080 void CMD_Disconnect()
1081 {
1082 	switch (edit.mode)
1083 	{
1084 		case OBJ_VERTICES:
1085 			CMD_VT_Disconnect();
1086 			break;
1087 
1088 		case OBJ_LINEDEFS:
1089 			CMD_LIN_Disconnect();
1090 			break;
1091 
1092 		case OBJ_SECTORS:
1093 			CMD_SEC_Disconnect();
1094 			break;
1095 
1096 		case OBJ_THINGS:
1097 			CMD_TH_Disconnect();
1098 			break;
1099 
1100 		default:
1101 			Beep("Cannot disconnect that");
1102 			break;
1103 	}
1104 }
1105 
1106 
CMD_Zoom()1107 void CMD_Zoom()
1108 {
1109 	int delta = atoi(EXEC_Param[0]);
1110 
1111 	if (delta == 0)
1112 	{
1113 		Beep("Zoom: bad or missing value");
1114 		return;
1115 	}
1116 
1117 	int mid_x = edit.map_x;
1118 	int mid_y = edit.map_y;
1119 
1120 	if (Exec_HasFlag("/center"))
1121 	{
1122 		mid_x = I_ROUND(grid.orig_x);
1123 		mid_y = I_ROUND(grid.orig_y);
1124 	}
1125 
1126 	Editor_Zoom(delta, mid_x, mid_y);
1127 }
1128 
1129 
CMD_ZoomWholeMap()1130 void CMD_ZoomWholeMap()
1131 {
1132 	if (edit.render3d)
1133 		Render3D_Enable(false);
1134 
1135 	ZoomWholeMap();
1136 }
1137 
1138 
CMD_ZoomSelection()1139 void CMD_ZoomSelection()
1140 {
1141 	if (edit.Selected->empty())
1142 	{
1143 		Beep("No selection to zoom");
1144 		return;
1145 	}
1146 
1147 	GoToSelection();
1148 }
1149 
1150 
CMD_GoToCamera()1151 void CMD_GoToCamera()
1152 {
1153 	if (edit.render3d)
1154 		Render3D_Enable(false);
1155 
1156 	double x, y; float angle;
1157 	Render3D_GetCameraPos(&x, &y, &angle);
1158 
1159 	grid.MoveTo(x, y);
1160 
1161 	RedrawMap();
1162 }
1163 
1164 
CMD_PlaceCamera()1165 void CMD_PlaceCamera()
1166 {
1167 	if (edit.render3d)
1168 	{
1169 		Beep("Not supported in 3D view");
1170 		return;
1171 	}
1172 
1173 	if (! edit.pointer_in_window)
1174 	{
1175 		// IDEA: turn cursor into cross, wait for click in map window
1176 
1177 		Beep("Mouse is not over map");
1178 		return;
1179 	}
1180 
1181 	double x = edit.map_x;
1182 	double y = edit.map_y;
1183 
1184 	Render3D_SetCameraPos(x, y);
1185 
1186 	if (Exec_HasFlag("/open3d"))
1187 	{
1188 		Render3D_Enable(true);
1189 	}
1190 
1191 	RedrawMap();
1192 }
1193 
1194 
CMD_MoveObjects_Dialog()1195 void CMD_MoveObjects_Dialog()
1196 {
1197 	soh_type_e unselect = Selection_Or_Highlight();
1198 	if (unselect == SOH_Empty)
1199 	{
1200 		Beep("Nothing to move");
1201 		return;
1202 	}
1203 
1204 	bool want_dz = (edit.mode == OBJ_SECTORS);
1205 	// can move things vertically in Hexen/UDMF formats
1206 	if (edit.mode == OBJ_THINGS && Level_format != MAPF_Doom)
1207 		want_dz = true;
1208 
1209 	UI_MoveDialog * dialog = new UI_MoveDialog(want_dz);
1210 
1211 	dialog->Run();
1212 
1213 	delete dialog;
1214 
1215 	if (unselect == SOH_Unselect)
1216 		Selection_Clear(true /* nosave */);
1217 }
1218 
1219 
CMD_ScaleObjects_Dialog()1220 void CMD_ScaleObjects_Dialog()
1221 {
1222 	soh_type_e unselect = Selection_Or_Highlight();
1223 	if (unselect == SOH_Empty)
1224 	{
1225 		Beep("Nothing to scale");
1226 		return;
1227 	}
1228 
1229 	UI_ScaleDialog * dialog = new UI_ScaleDialog();
1230 
1231 	dialog->Run();
1232 
1233 	delete dialog;
1234 
1235 	if (unselect == SOH_Unselect)
1236 		Selection_Clear(true /* nosave */);
1237 }
1238 
1239 
CMD_RotateObjects_Dialog()1240 void CMD_RotateObjects_Dialog()
1241 {
1242 	soh_type_e unselect = Selection_Or_Highlight();
1243 	if (unselect == SOH_Empty)
1244 	{
1245 		Beep("Nothing to rotate");
1246 		return;
1247 	}
1248 
1249 	UI_RotateDialog * dialog = new UI_RotateDialog();
1250 
1251 	dialog->Run();
1252 
1253 	delete dialog;
1254 
1255 	if (unselect == SOH_Unselect)
1256 		Selection_Clear(true /* nosave */);
1257 }
1258 
1259 
CMD_GRID_Bump()1260 void CMD_GRID_Bump()
1261 {
1262 	int delta = atoi(EXEC_Param[0]);
1263 
1264 	delta = (delta >= 0) ? +1 : -1;
1265 
1266 	grid.AdjustStep(delta);
1267 }
1268 
1269 
CMD_GRID_Set()1270 void CMD_GRID_Set()
1271 {
1272 	int step = atoi(EXEC_Param[0]);
1273 
1274 	if (step < 2 || step > 4096)
1275 	{
1276 		Beep("Bad grid step");
1277 		return;
1278 	}
1279 
1280 	grid.ForceStep(step);
1281 }
1282 
1283 
CMD_GRID_Zoom()1284 void CMD_GRID_Zoom()
1285 {
1286 	// target scale is positive for NN:1 and negative for 1:NN
1287 
1288 	double scale = atof(EXEC_Param[0]);
1289 
1290 	if (scale == 0)
1291 	{
1292 		Beep("Bad scale");
1293 		return;
1294 	}
1295 
1296 	if (scale < 0)
1297 		scale = -1.0 / scale;
1298 
1299 	float S1 = grid.Scale;
1300 
1301 	grid.NearestScale(scale);
1302 
1303 	grid.RefocusZoom(edit.map_x, edit.map_y, S1);
1304 }
1305 
1306 
CMD_BR_CycleCategory()1307 void CMD_BR_CycleCategory()
1308 {
1309 	if (! main_win->browser->visible())
1310 	{
1311 		Beep("Browser not open");
1312 		return;
1313 	}
1314 
1315 	int dir = (atoi(EXEC_Param[0]) >= 0) ? +1 : -1;
1316 
1317 	main_win->browser->CycleCategory(dir);
1318 }
1319 
1320 
CMD_BR_ClearSearch()1321 void CMD_BR_ClearSearch()
1322 {
1323 	if (! main_win->browser->visible())
1324 	{
1325 		Beep("Browser not open");
1326 		return;
1327 	}
1328 
1329 	main_win->browser->ClearSearchBox();
1330 }
1331 
1332 
CMD_BR_Scroll()1333 void CMD_BR_Scroll()
1334 {
1335 	if (! main_win->browser->visible())
1336 	{
1337 		Beep("Browser not open");
1338 		return;
1339 	}
1340 
1341 	if (! EXEC_Param[0][0])
1342 	{
1343 		Beep("BR_Scroll: missing value");
1344 		return;
1345 	}
1346 
1347 	int delta = atoi(EXEC_Param[0]);
1348 
1349 	main_win->browser->Scroll(delta);
1350 }
1351 
1352 
CMD_DefaultProps()1353 void CMD_DefaultProps()
1354 {
1355 	main_win->ShowDefaultProps();
1356 }
1357 
1358 
CMD_FindDialog()1359 void CMD_FindDialog()
1360 {
1361 	main_win->ShowFindAndReplace();
1362 }
1363 
1364 
CMD_FindNext()1365 void CMD_FindNext()
1366 {
1367 	main_win->find_box->FindNext();
1368 }
1369 
1370 
CMD_RecalcSectors()1371 void CMD_RecalcSectors()
1372 {
1373 	Subdiv_InvalidateAll();
1374 	RedrawMap();
1375 }
1376 
1377 
CMD_LogViewer()1378 void CMD_LogViewer()
1379 {
1380 	LogViewer_Open();
1381 }
1382 
1383 
CMD_OnlineDocs()1384 void CMD_OnlineDocs()
1385 {
1386 	int rv = fl_open_uri("http://eureka-editor.sourceforge.net/?n=Docs.Index");
1387 	if (rv == 1)
1388 		Status_Set("Opened web browser");
1389 	else
1390 		Beep("Failed to open web browser");
1391 }
1392 
1393 
CMD_AboutDialog()1394 void CMD_AboutDialog()
1395 {
1396 	DLG_AboutText();
1397 }
1398 
1399 
1400 //------------------------------------------------------------------------
1401 
1402 
1403 static editor_command_t  command_table[] =
1404 {
1405 	/* ---- miscellaneous / UI stuff ---- */
1406 
1407 	{	"Nothing", "Misc",
1408 		&CMD_Nothing
1409 	},
1410 
1411 	{	"Set", "Misc",
1412 		&CMD_SetVar,
1413 		/* flags */ NULL,
1414 		/* keywords */ "3d browser gamma grid obj_nums ratio sec_render snap sprites"
1415 	},
1416 
1417 	{	"Toggle", "Misc",
1418 		&CMD_ToggleVar,
1419 		/* flags */ NULL,
1420 		/* keywords */ "3d browser gamma grid obj_nums ratio sec_render snap recent sprites"
1421 	},
1422 
1423 	{	"MetaKey", "Misc",
1424 		&CMD_MetaKey
1425 	},
1426 
1427 	{	"EditMode", "Misc",
1428 		&CMD_EditMode,
1429 		/* flags */ NULL,
1430 		/* keywords */ "thing line sector vertex"
1431 	},
1432 
1433 	{	"OpMenu",  "Misc",
1434 		&CMD_OperationMenu
1435 	},
1436 
1437 	{	"MapCheck", "Misc",
1438 		&CMD_MapCheck,
1439 		/* flags */ NULL,
1440 		/* keywords */ "all major vertices sectors linedefs things textures tags current"
1441 	},
1442 
1443 
1444 	/* ----- 2D canvas ----- */
1445 
1446 	{	"Scroll",  "2D View",
1447 		&CMD_Scroll
1448 	},
1449 
1450 	{	"GRID_Bump",  "2D View",
1451 		&CMD_GRID_Bump
1452 	},
1453 
1454 	{	"GRID_Set",  "2D View",
1455 		&CMD_GRID_Set
1456 	},
1457 
1458 	{	"GRID_Zoom",  "2D View",
1459 		&CMD_GRID_Zoom
1460 	},
1461 
1462 	{	"ACT_SelectBox", "2D View",
1463 		&CMD_ACT_SelectBox
1464 	},
1465 
1466 	{	"WHEEL_Scroll",  "2D View",
1467 		&CMD_WHEEL_Scroll
1468 	},
1469 
1470 	{	"NAV_Scroll_Left",  "2D View",
1471 		&CMD_NAV_Scroll_Left
1472 	},
1473 
1474 	{	"NAV_Scroll_Right",  "2D View",
1475 		&CMD_NAV_Scroll_Right
1476 	},
1477 
1478 	{	"NAV_Scroll_Up",  "2D View",
1479 		&CMD_NAV_Scroll_Up
1480 	},
1481 
1482 	{	"NAV_Scroll_Down",  "2D View",
1483 		&CMD_NAV_Scroll_Down
1484 	},
1485 
1486 	{	"NAV_MouseScroll", "2D View",
1487 		&CMD_NAV_MouseScroll
1488 	},
1489 
1490 
1491 	/* ----- FILE menu ----- */
1492 
1493 	{	"NewProject",  "File",
1494 		&CMD_NewProject
1495 	},
1496 
1497 	{	"ManageProject",  "File",
1498 		&CMD_ManageProject
1499 	},
1500 
1501 	{	"OpenMap",  "File",
1502 		&CMD_OpenMap
1503 	},
1504 
1505 	{	"GivenFile",  "File",
1506 		&CMD_GivenFile,
1507 		/* flags */ NULL,
1508 		/* keywords */ "next prev first last current"
1509 	},
1510 
1511 	{	"FlipMap",  "File",
1512 		&CMD_FlipMap,
1513 		/* flags */ NULL,
1514 		/* keywords */ "next prev first last"
1515 	},
1516 
1517 	{	"SaveMap",  "File",
1518 		&CMD_SaveMap
1519 	},
1520 
1521 	{	"ExportMap",  "File",
1522 		&CMD_ExportMap
1523 	},
1524 
1525 	{	"FreshMap",  "File",
1526 		&CMD_FreshMap
1527 	},
1528 
1529 	{	"CopyMap",  "File",
1530 		&CMD_CopyMap
1531 	},
1532 
1533 	{	"RenameMap",  "File",
1534 		&CMD_RenameMap
1535 	},
1536 
1537 	{	"DeleteMap",  "File",
1538 		&CMD_DeleteMap
1539 	},
1540 
1541 	{	"Quit",  "File",
1542 		&CMD_Quit
1543 	},
1544 
1545 
1546 	/* ----- EDIT menu ----- */
1547 
1548 	{	"Undo",   "Edit",
1549 		&CMD_Undo
1550 	},
1551 
1552 	{	"Redo",   "Edit",
1553 		&CMD_Redo
1554 	},
1555 
1556 	{	"Insert",	"Edit",
1557 		&CMD_Insert,
1558 		/* flags */ "/continue /nofill"
1559 	},
1560 
1561 	{	"Delete",	"Edit",
1562 		&CMD_Delete,
1563 		/* flags */ "/keep"
1564 	},
1565 
1566 	{	"Clipboard_Cut",   "Edit",
1567 		&CMD_Clipboard_Cut
1568 	},
1569 
1570 	{	"Clipboard_Copy",   "Edit",
1571 		&CMD_Clipboard_Copy
1572 	},
1573 
1574 	{	"Clipboard_Paste",   "Edit",
1575 		&CMD_Clipboard_Paste
1576 	},
1577 
1578 	{	"Select",	"Edit",
1579 		&CMD_Select
1580 	},
1581 
1582 	{	"SelectAll",	"Edit",
1583 		&CMD_SelectAll
1584 	},
1585 
1586 	{	"UnselectAll",	"Edit",
1587 		&CMD_UnselectAll
1588 	},
1589 
1590 	{	"InvertSelection",	"Edit",
1591 		&CMD_InvertSelection
1592 	},
1593 
1594 	{	"LastSelection",	"Edit",
1595 		&CMD_LastSelection
1596 	},
1597 
1598 	{	"CopyAndPaste",   "Edit",
1599 		&CMD_CopyAndPaste
1600 	},
1601 
1602 	{	"CopyProperties",   "Edit",
1603 		&CMD_CopyProperties,
1604 		/* flags */ "/reverse"
1605 	},
1606 
1607 	{	"PruneUnused",   "Edit",
1608 		&CMD_PruneUnused
1609 	},
1610 
1611 	{	"MoveObjectsDialog",   "Edit",
1612 		&CMD_MoveObjects_Dialog
1613 	},
1614 
1615 	{	"ScaleObjectsDialog",   "Edit",
1616 		&CMD_ScaleObjects_Dialog
1617 	},
1618 
1619 	{	"RotateObjectsDialog",   "Edit",
1620 		&CMD_RotateObjects_Dialog
1621 	},
1622 
1623 
1624 	/* ----- VIEW menu ----- */
1625 
1626 	{	"Zoom",  "View",
1627 		&CMD_Zoom,
1628 		/* flags */ "/center"
1629 	},
1630 
1631 	{	"ZoomWholeMap",  "View",
1632 		&CMD_ZoomWholeMap
1633 	},
1634 
1635 	{	"ZoomSelection",  "View",
1636 		&CMD_ZoomSelection
1637 	},
1638 
1639 	{	"DefaultProps",  "View",
1640 		&CMD_DefaultProps
1641 	},
1642 
1643 	{	"FindDialog",  "View",
1644 		&CMD_FindDialog
1645 	},
1646 
1647 	{	"FindNext",  "View",
1648 		&CMD_FindNext
1649 	},
1650 
1651 	{	"GoToCamera",  "View",
1652 		&CMD_GoToCamera
1653 	},
1654 
1655 	{	"PlaceCamera",  "View",
1656 		&CMD_PlaceCamera,
1657 		/* flags */ "/open3d"
1658 	},
1659 
1660 	{	"JumpToObject",  "View",
1661 		&CMD_JumpToObject
1662 	},
1663 
1664 
1665 	/* ------ TOOLS menu ------ */
1666 
1667 	{	"PreferenceDialog",  "Tools",
1668 		&CMD_Preferences
1669 	},
1670 
1671 	{	"TestMap",  "Tools",
1672 		&CMD_TestMap
1673 	},
1674 
1675 	{	"RecalcSectors",  "Tools",
1676 		&CMD_RecalcSectors
1677 	},
1678 
1679 	{	"BuildAllNodes",  "Tools",
1680 		&CMD_BuildAllNodes
1681 	},
1682 
1683 	{	"EditLump",  "Tools",
1684 		&CMD_EditLump,
1685 		/* flags */ "/header /scripts"
1686 	},
1687 
1688 	{	"AddBehavior",  "Tools",
1689 		&CMD_AddBehaviorLump
1690 	},
1691 
1692 	{	"LogViewer",  "Tools",
1693 		&CMD_LogViewer
1694 	},
1695 
1696 
1697 	/* ------ HELP menu ------ */
1698 
1699 	{	"OnlineDocs",  "Help",
1700 		&CMD_OnlineDocs
1701 	},
1702 
1703 	{	"AboutDialog",  "Help",
1704 		&CMD_AboutDialog
1705 	},
1706 
1707 
1708 	/* ----- general operations ----- */
1709 
1710 	{	"Merge",	"General",
1711 		&CMD_Merge,
1712 		/* flags */ "/keep"
1713 	},
1714 
1715 	{	"Disconnect",	"General",
1716 		&CMD_Disconnect
1717 	},
1718 
1719 	{	"Mirror",	"General",
1720 		&CMD_Mirror,
1721 		/* flags */ NULL,
1722 		/* keywords */ "horiz vert"
1723 	},
1724 
1725 	{	"Rotate90",	"General",
1726 		&CMD_Rotate90,
1727 		/* flags */ NULL,
1728 		/* keywords */ "cw acw"
1729 	},
1730 
1731 	{	"Enlarge",	"General",
1732 		&CMD_Enlarge
1733 	},
1734 
1735 	{	"Shrink",	"General",
1736 		&CMD_Shrink
1737 	},
1738 
1739 	{	"Quantize",	"General",
1740 		&CMD_Quantize
1741 	},
1742 
1743 	{	"ApplyTag",	"General",
1744 		&CMD_ApplyTag,
1745 		/* flags */ NULL,
1746 		/* keywords */ "fresh last"
1747 	},
1748 
1749 	{	"ACT_Click", "General",
1750 		&CMD_ACT_Click,
1751 		/* flags */ "/noselect /nodrag /nosplit"
1752 	},
1753 
1754 	{	"ACT_Drag", "General",
1755 		&CMD_ACT_Drag
1756 	},
1757 
1758 	{	"ACT_Transform", "General",
1759 		&CMD_ACT_Transform,
1760 		/* flags */ NULL,
1761 		/* keywords */ "scale stretch rotate rotscale skew"
1762 	},
1763 
1764 
1765 	/* ------ LineDef mode ------ */
1766 
1767 	{	"LIN_Align", NULL,
1768 		&CMD_LIN_Align,
1769 		/* flags */ "/x /y /right /clear"
1770 	},
1771 
1772 	{	"LIN_Flip", NULL,
1773 		&CMD_LIN_Flip,
1774 		/* flags */ "/force"
1775 	},
1776 
1777 	{	"LIN_SwapSides", NULL,
1778 		&CMD_LIN_SwapSides
1779 	},
1780 
1781 	{	"LIN_SplitHalf", NULL,
1782 		&CMD_LIN_SplitHalf
1783 	},
1784 
1785 	{	"LIN_SelectPath", NULL,
1786 		&CMD_LIN_SelectPath,
1787 		/* flags */ "/fresh /onesided /sametex"
1788 	},
1789 
1790 
1791 	/* ------ Sector mode ------ */
1792 
1793 	{	"SEC_Floor", NULL,
1794 		&CMD_SEC_Floor
1795 	},
1796 
1797 	{	"SEC_Ceil", NULL,
1798 		&CMD_SEC_Ceil
1799 	},
1800 
1801 	{	"SEC_Light", NULL,
1802 		&CMD_SEC_Light
1803 	},
1804 
1805 	{	"SEC_SelectGroup", NULL,
1806 		&CMD_SEC_SelectGroup,
1807 		/* flags */ "/fresh /can_walk /doors /floor_h /floor_tex /ceil_h /ceil_tex /light /tag /special"
1808 	},
1809 
1810 	{	"SEC_SwapFlats", NULL,
1811 		&CMD_SEC_SwapFlats
1812 	},
1813 
1814 
1815 	/* ------ Thing mode ------ */
1816 
1817 	{	"TH_Spin", NULL,
1818 		&CMD_TH_SpinThings
1819 	},
1820 
1821 
1822 	/* ------ Vertex mode ------ */
1823 
1824 	{	"VT_ShapeLine", NULL,
1825 		&CMD_VT_ShapeLine
1826 	},
1827 
1828 	{	"VT_ShapeArc", NULL,
1829 		&CMD_VT_ShapeArc
1830 	},
1831 
1832 
1833 	/* -------- Browser -------- */
1834 
1835 	{	"BrowserMode", "Browser",
1836 		&CMD_BrowserMode,
1837 		/* flags */ "/recent",
1838 		/* keywords */ "obj tex flat line sec genline"
1839 	},
1840 
1841 	{	"BR_CycleCategory", "Browser",
1842 		&CMD_BR_CycleCategory
1843 	},
1844 
1845 	{	"BR_ClearSearch", "Browser",
1846 		&CMD_BR_ClearSearch
1847 	},
1848 
1849 	{	"BR_Scroll", "Browser",
1850 		&CMD_BR_Scroll
1851 	},
1852 
1853 	// end of command list
1854 	{	NULL, NULL, 0, NULL  }
1855 };
1856 
1857 
Editor_RegisterCommands()1858 void Editor_RegisterCommands()
1859 {
1860 	M_RegisterCommandList(command_table);
1861 }
1862 
1863 
1864 //--- editor settings ---
1865 // vi:ts=4:sw=4:noexpandtab
1866