Reimplement aven's cavern log window
[survex.git] / src / guicontrol.cc
blobd4d1d1f598fd337fca03b17cb7547ae224bc64c3
1 //
2 // guicontrol.cc
3 //
4 // Handlers for events relating to the display of a survey.
5 //
6 // Copyright (C) 2000-2002,2005 Mark R. Shinwell
7 // Copyright (C) 2001,2003,2004,2005,2006,2011,2012,2014,2015,2016 Olly Betts
8 //
9 // This program is free software; you can redistribute it and/or modify
10 // it under the terms of the GNU General Public License as published by
11 // the Free Software Foundation; either version 2 of the License, or
12 // (at your option) any later version.
14 // This program is distributed in the hope that it will be useful,
15 // but WITHOUT ANY WARRANTY; without even the implied warranty of
16 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 // GNU General Public License for more details.
19 // You should have received a copy of the GNU General Public License
20 // along with this program; if not, write to the Free Software
21 // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
24 #include <config.h>
26 #include "guicontrol.h"
27 #include "gfxcore.h"
28 #include <wx/confbase.h>
30 const int DISPLAY_SHIFT = 10;
31 const double FLYFREE_SHIFT = 0.2;
32 const double ROTATE_STEP = 2.0;
34 GUIControl::GUIControl()
35 : dragging(NO_DRAG)
37 m_View = NULL;
38 m_ReverseControls = false;
39 m_LastDrag = drag_NONE;
42 void GUIControl::SetView(GfxCore* view)
44 m_View = view;
47 bool GUIControl::MouseDown() const
49 return (dragging != NO_DRAG);
52 void GUIControl::HandleTilt(wxPoint point)
54 // Handle a mouse movement during tilt mode.
56 // wxGTK (at least) fails to update the cursor while dragging.
57 m_View->UpdateCursor(GfxCore::CURSOR_ROTATE_VERTICALLY);
59 int dy = point.y - m_DragStart.y;
61 if (m_ReverseControls != m_View->GetPerspective()) dy = -dy;
63 m_View->TiltCave(Double(dy) * 0.36);
65 m_DragStart = point;
67 m_View->ForceRefresh();
70 void GUIControl::HandleTranslate(wxPoint point)
72 // Handle a mouse movement during translation mode.
74 // wxGTK (at least) fails to update the cursor while dragging.
75 m_View->UpdateCursor(GfxCore::CURSOR_DRAGGING_HAND);
77 int dx = point.x - m_DragStart.x;
78 int dy = point.y - m_DragStart.y;
80 if (m_ReverseControls) {
81 dx = -dx;
82 dy = -dy;
85 if (m_View->GetPerspective())
86 m_View->MoveViewer(0, -dy * .1, dx * .1);
87 else
88 m_View->TranslateCave(dx, dy);
90 m_DragStart = point;
93 void GUIControl::HandleScaleRotate(wxPoint point)
95 // Handle a mouse movement during scale/rotate mode.
97 // wxGTK (at least) fails to update the cursor while dragging.
98 m_View->UpdateCursor(GfxCore::CURSOR_ZOOM_ROTATE);
100 int dx, dy;
101 int threshold;
102 if (m_ScaleRotateLock == lock_NONE) {
103 // Dragging to scale or rotate but we've not decided which yet.
104 dx = point.x - m_DragRealStart.x;
105 dy = point.y - m_DragRealStart.y;
106 threshold = 8 * 8;
107 } else {
108 dx = point.x - m_DragStart.x;
109 dy = point.y - m_DragStart.y;
110 threshold = 5;
112 int dx2 = dx * dx;
113 int dy2 = dy * dy;
114 if (dx2 + dy2 < threshold) return;
116 switch (m_ScaleRotateLock) {
117 case lock_NONE:
118 if (dx2 > dy2) {
119 m_ScaleRotateLock = lock_ROTATE;
120 // m_View->UpdateCursor(GfxCore::CURSOR_ROTATE_HORIZONTALLY);
121 } else {
122 m_ScaleRotateLock = lock_SCALE;
123 // m_View->UpdateCursor(GfxCore::CURSOR_ZOOM);
125 break;
126 case lock_SCALE:
127 if (dx2 >= 8 * dy2) {
128 m_ScaleRotateLock = lock_ROTATE;
129 // m_View->UpdateCursor(GfxCore::CURSOR_ROTATE_HORIZONTALLY);
131 break;
132 case lock_ROTATE:
133 if (dy2 >= 8 * dx2) {
134 m_ScaleRotateLock = lock_SCALE;
135 // m_View->UpdateCursor(GfxCore::CURSOR_ZOOM);
137 break;
140 if (m_ScaleRotateLock == lock_ROTATE) {
141 dy = 0;
142 } else {
143 dx = 0;
146 if (m_ReverseControls) {
147 dx = -dx;
148 dy = -dy;
151 if (m_View->GetPerspective()) {
152 if (dy) m_View->MoveViewer(-dy * .1, 0, 0);
153 } else {
154 // up/down => scale.
155 if (dy) m_View->SetScale(m_View->GetScale() * pow(1.06, 0.08 * dy));
156 // left/right => rotate.
157 if (dx) m_View->TurnCave(Double(dx) * -0.36);
158 if (dx || dy) m_View->ForceRefresh();
161 m_DragStart = point;
164 void GUIControl::HandleTiltRotate(wxPoint point)
166 // Handle a mouse movement during tilt/rotate mode.
167 if (m_View->IsExtendedElevation()) return;
169 // wxGTK (at least) fails to update the cursor while dragging.
170 m_View->UpdateCursor(GfxCore::CURSOR_ROTATE_EITHER_WAY);
172 int dx = point.x - m_DragStart.x;
173 int dy = point.y - m_DragStart.y;
175 if (m_ReverseControls != m_View->GetPerspective()) {
176 dx = -dx;
177 dy = -dy;
180 // left/right => rotate, up/down => tilt.
181 // Make tilt less sensitive than rotate as that feels better.
182 m_View->TurnCave(Double(dx) * -0.36);
183 m_View->TiltCave(Double(dy) * 0.18);
185 m_View->ForceRefresh();
187 m_DragStart = point;
190 void GUIControl::HandleRotate(wxPoint point)
192 // Handle a mouse movement during rotate mode.
193 if (m_View->IsExtendedElevation()) return;
195 // wxGTK (at least) fails to update the cursor while dragging.
196 m_View->UpdateCursor(GfxCore::CURSOR_ROTATE_HORIZONTALLY);
198 int dx = point.x - m_DragStart.x;
199 int dy = point.y - m_DragStart.y;
201 if (m_ReverseControls != m_View->GetPerspective()) {
202 dx = -dx;
203 dy = -dy;
206 // left/right => rotate.
207 m_View->TurnCave(Double(dx) * -0.36);
209 m_View->ForceRefresh();
211 m_DragStart = point;
214 void GUIControl::RestoreCursor()
216 if (m_View->HereIsReal()) {
217 m_View->UpdateCursor(GfxCore::CURSOR_POINTING_HAND);
218 } else {
219 m_View->UpdateCursor(GfxCore::CURSOR_DEFAULT);
223 void GUIControl::HandleNonDrag(const wxPoint & point) {
224 if (m_View->IsFullScreen()) {
225 if (m_View->FullScreenModeShowingMenus()) {
226 if (point.y > 8)
227 m_View->FullScreenModeShowMenus(false);
228 } else {
229 if (point.y == 0) {
230 m_View->FullScreenModeShowMenus(true);
234 if (m_View->CheckHitTestGrid(point, false)) {
235 m_View->UpdateCursor(GfxCore::CURSOR_POINTING_HAND);
236 } else if (m_View->PointWithinScaleBar(point)) {
237 m_View->UpdateCursor(GfxCore::CURSOR_HORIZONTAL_RESIZE);
238 } else if (m_View->PointWithinCompass(point)) {
239 m_View->UpdateCursor(GfxCore::CURSOR_ROTATE_HORIZONTALLY);
240 } else if (m_View->PointWithinClino(point)) {
241 m_View->UpdateCursor(GfxCore::CURSOR_ROTATE_VERTICALLY);
242 } else {
243 RestoreCursor();
248 // Mouse event handling methods
251 void GUIControl::OnMouseMove(wxMouseEvent& event)
253 // Mouse motion event handler.
254 if (!m_View->HasData()) return;
256 // Ignore moves which don't change the position.
257 if (event.GetPosition() == m_DragStart) {
258 return;
261 static long timestamp = LONG_MIN;
262 if (dragging != NO_DRAG && m_ScaleRotateLock != lock_NONE &&
263 timestamp != LONG_MIN) {
264 // If no motion for a second, reset the direction lock.
265 if (event.GetTimestamp() - timestamp >= 1000) {
266 m_ScaleRotateLock = lock_NONE;
267 m_DragRealStart = m_DragStart;
268 RestoreCursor();
271 timestamp = event.GetTimestamp();
273 wxPoint point(event.GetPosition());
275 // Check hit-test grid (only if no buttons are pressed).
276 if (!event.LeftIsDown() && !event.MiddleIsDown() && !event.RightIsDown()) {
277 HandleNonDrag(point);
280 // Update coordinate display if in plan view,
281 // or altitude if in elevation view.
282 m_View->SetCoords(point);
284 switch (dragging) {
285 case LEFT_DRAG:
286 switch (m_LastDrag) {
287 case drag_COMPASS:
288 // Drag in heading indicator.
289 m_View->SetCompassFromPoint(point);
290 break;
291 case drag_ELEV:
292 // Drag in clinometer.
293 m_View->SetClinoFromPoint(point);
294 break;
295 case drag_SCALE:
296 m_View->SetScaleBarFromOffset(point.x - m_DragLast.x);
297 break;
298 case drag_MAIN:
299 if (event.ControlDown()) {
300 HandleTiltRotate(point);
301 } else {
302 HandleScaleRotate(point);
304 break;
305 case drag_ZOOM:
306 m_View->SetZoomBox(m_DragStart, point, !event.ShiftDown(), event.ControlDown());
307 break;
308 case drag_NONE:
309 // Shouldn't happen?! FIXME: assert or something.
310 break;
312 break;
313 case MIDDLE_DRAG:
314 HandleTilt(point);
315 break;
316 case RIGHT_DRAG:
317 HandleTranslate(point);
318 break;
319 case NO_DRAG:
320 break;
323 m_DragLast = point;
326 void GUIControl::OnLButtonDown(wxMouseEvent& event)
328 if (m_View->HasData()) {
329 m_DragStart = m_DragRealStart = event.GetPosition();
331 if (m_View->PointWithinCompass(m_DragStart)) {
332 m_LastDrag = drag_COMPASS;
333 m_View->UpdateCursor(GfxCore::CURSOR_ROTATE_HORIZONTALLY);
334 } else if (m_View->PointWithinClino(m_DragStart)) {
335 m_LastDrag = drag_ELEV;
336 m_View->UpdateCursor(GfxCore::CURSOR_ROTATE_VERTICALLY);
337 } else if (m_View->PointWithinScaleBar(m_DragStart)) {
338 m_LastDrag = drag_SCALE;
339 m_View->UpdateCursor(GfxCore::CURSOR_HORIZONTAL_RESIZE);
340 } else if (event.ShiftDown()) {
341 m_LastDrag = drag_ZOOM;
342 m_View->UpdateCursor(GfxCore::CURSOR_ZOOM);
343 } else {
344 if (event.ControlDown() && !m_View->IsExtendedElevation()) {
345 m_View->UpdateCursor(GfxCore::CURSOR_ROTATE_EITHER_WAY);
346 } else {
347 m_View->UpdateCursor(GfxCore::CURSOR_ZOOM_ROTATE);
350 m_LastDrag = drag_MAIN;
351 m_ScaleRotateLock = lock_NONE;
354 // We need to release and recapture for the cursor to update (noticed
355 // with wxGTK).
356 if (dragging != NO_DRAG) m_View->ReleaseMouse();
357 m_View->CaptureMouse();
359 dragging = LEFT_DRAG;
363 void GUIControl::OnLButtonUp(wxMouseEvent& event)
365 if (m_View->HasData()) {
366 if (dragging != LEFT_DRAG)
367 return;
369 if (event.MiddleIsDown()) {
370 if (m_LastDrag == drag_ZOOM)
371 m_View->UnsetZoomBox();
372 OnMButtonDown(event);
373 return;
376 if (event.RightIsDown()) {
377 if (m_LastDrag == drag_ZOOM)
378 m_View->UnsetZoomBox();
379 OnRButtonDown(event);
380 return;
383 if (m_LastDrag == drag_ZOOM) {
384 m_View->ZoomBoxGo();
387 m_View->ReleaseMouse();
389 m_LastDrag = drag_NONE;
390 dragging = NO_DRAG;
392 m_View->DragFinished();
394 if (event.GetPosition() == m_DragRealStart) {
395 // Just a "click"...
396 m_View->CheckHitTestGrid(m_DragStart, true);
397 RestoreCursor();
398 } else {
399 HandleNonDrag(event.GetPosition());
404 void GUIControl::OnMButtonDown(wxMouseEvent& event)
406 if (m_View->HasData() && !m_View->IsExtendedElevation()) {
407 m_DragStart = event.GetPosition();
409 m_View->UpdateCursor(GfxCore::CURSOR_ROTATE_VERTICALLY);
411 if (dragging != NO_DRAG) {
412 if (m_LastDrag == drag_ZOOM)
413 m_View->UnsetZoomBox();
414 // We need to release and recapture for the cursor to update
415 // (noticed with wxGTK).
416 m_View->ReleaseMouse();
418 m_View->CaptureMouse();
419 dragging = MIDDLE_DRAG;
423 void GUIControl::OnMButtonUp(wxMouseEvent& event)
425 if (m_View->HasData()) {
426 if (dragging != MIDDLE_DRAG)
427 return;
429 if (event.LeftIsDown()) {
430 OnLButtonDown(event);
431 return;
434 if (event.RightIsDown()) {
435 OnRButtonDown(event);
436 return;
439 dragging = NO_DRAG;
440 m_View->ReleaseMouse();
441 m_View->DragFinished();
443 RestoreCursor();
447 void GUIControl::OnRButtonDown(wxMouseEvent& event)
449 if (m_View->HasData()) {
450 if (dragging != NO_DRAG) {
451 if (m_LastDrag == drag_ZOOM)
452 m_View->UnsetZoomBox();
453 // We need to release and recapture for the cursor to update
454 // (noticed with wxGTK).
455 m_View->ReleaseMouse();
456 dragging = NO_DRAG;
459 if (m_View->HandleRClick(event.GetPosition()))
460 return;
462 m_DragStart = event.GetPosition();
464 m_View->UpdateCursor(GfxCore::CURSOR_DRAGGING_HAND);
466 m_View->CaptureMouse();
467 dragging = RIGHT_DRAG;
471 void GUIControl::OnRButtonUp(wxMouseEvent& event)
473 if (dragging != RIGHT_DRAG)
474 return;
476 if (event.LeftIsDown()) {
477 OnLButtonDown(event);
478 return;
481 if (event.MiddleIsDown()) {
482 OnMButtonDown(event);
483 return;
486 m_LastDrag = drag_NONE;
487 m_View->ReleaseMouse();
489 dragging = NO_DRAG;
491 RestoreCursor();
493 m_View->DragFinished();
496 void GUIControl::OnMouseWheel(wxMouseEvent& event) {
497 int dy = event.GetWheelRotation();
498 if (m_View->GetPerspective()) {
499 m_View->MoveViewer(-dy, 0, 0);
500 } else {
501 m_View->SetScale(m_View->GetScale() * pow(1.06, -0.04 * dy));
502 m_View->ForceRefresh();
506 void GUIControl::OnDisplayOverlappingNames()
508 m_View->ToggleOverlappingNames();
511 void GUIControl::OnDisplayOverlappingNamesUpdate(wxUpdateUIEvent& cmd)
513 cmd.Enable(m_View->HasData() && m_View->ShowingStationNames());
514 cmd.Check(m_View->ShowingOverlappingNames());
517 void GUIControl::OnColourByDepth()
519 if (m_View->ColouringBy() == COLOUR_BY_DEPTH) {
520 m_View->SetColourBy(COLOUR_BY_NONE);
521 } else {
522 m_View->SetColourBy(COLOUR_BY_DEPTH);
526 void GUIControl::OnColourByDate()
528 if (m_View->ColouringBy() == COLOUR_BY_DATE) {
529 m_View->SetColourBy(COLOUR_BY_NONE);
530 } else {
531 m_View->SetColourBy(COLOUR_BY_DATE);
535 void GUIControl::OnColourByError()
537 if (m_View->ColouringBy() == COLOUR_BY_ERROR) {
538 m_View->SetColourBy(COLOUR_BY_NONE);
539 } else {
540 m_View->SetColourBy(COLOUR_BY_ERROR);
544 void GUIControl::OnColourByHError()
546 if (m_View->ColouringBy() == COLOUR_BY_H_ERROR) {
547 m_View->SetColourBy(COLOUR_BY_NONE);
548 } else {
549 m_View->SetColourBy(COLOUR_BY_H_ERROR);
553 void GUIControl::OnColourByVError()
555 if (m_View->ColouringBy() == COLOUR_BY_V_ERROR) {
556 m_View->SetColourBy(COLOUR_BY_NONE);
557 } else {
558 m_View->SetColourBy(COLOUR_BY_V_ERROR);
562 void GUIControl::OnColourByGradient()
564 if (m_View->ColouringBy() == COLOUR_BY_GRADIENT) {
565 m_View->SetColourBy(COLOUR_BY_NONE);
566 } else {
567 m_View->SetColourBy(COLOUR_BY_GRADIENT);
571 void GUIControl::OnColourByLength()
573 if (m_View->ColouringBy() == COLOUR_BY_LENGTH) {
574 m_View->SetColourBy(COLOUR_BY_NONE);
575 } else {
576 m_View->SetColourBy(COLOUR_BY_LENGTH);
580 void GUIControl::OnColourBySurvey()
582 if (m_View->ColouringBy() == COLOUR_BY_SURVEY) {
583 m_View->SetColourBy(COLOUR_BY_NONE);
584 } else {
585 m_View->SetColourBy(COLOUR_BY_SURVEY);
589 void GUIControl::OnColourByStyle()
591 if (m_View->ColouringBy() == COLOUR_BY_STYLE) {
592 m_View->SetColourBy(COLOUR_BY_NONE);
593 } else {
594 m_View->SetColourBy(COLOUR_BY_STYLE);
598 void GUIControl::OnColourByUpdate(wxUpdateUIEvent& cmd)
600 cmd.Enable(m_View->HasData());
603 void GUIControl::OnColourByDepthUpdate(wxUpdateUIEvent& cmd)
605 cmd.Enable(m_View->HasData());
606 cmd.Check(m_View->ColouringBy() == COLOUR_BY_DEPTH);
609 void GUIControl::OnColourByDateUpdate(wxUpdateUIEvent& cmd)
611 cmd.Enable(m_View->HasData());
612 cmd.Check(m_View->ColouringBy() == COLOUR_BY_DATE);
615 void GUIControl::OnColourByErrorUpdate(wxUpdateUIEvent& cmd)
617 cmd.Enable(m_View->HasData());
618 cmd.Check(m_View->ColouringBy() == COLOUR_BY_ERROR);
621 void GUIControl::OnColourByHErrorUpdate(wxUpdateUIEvent& cmd)
623 cmd.Enable(m_View->HasData());
624 cmd.Check(m_View->ColouringBy() == COLOUR_BY_H_ERROR);
627 void GUIControl::OnColourByVErrorUpdate(wxUpdateUIEvent& cmd)
629 cmd.Enable(m_View->HasData());
630 cmd.Check(m_View->ColouringBy() == COLOUR_BY_V_ERROR);
633 void GUIControl::OnColourByGradientUpdate(wxUpdateUIEvent& cmd)
635 cmd.Enable(m_View->HasData());
636 cmd.Check(m_View->ColouringBy() == COLOUR_BY_GRADIENT);
639 void GUIControl::OnColourByLengthUpdate(wxUpdateUIEvent& cmd)
641 cmd.Enable(m_View->HasData());
642 cmd.Check(m_View->ColouringBy() == COLOUR_BY_LENGTH);
645 void GUIControl::OnColourBySurveyUpdate(wxUpdateUIEvent& cmd)
647 cmd.Enable(m_View->HasData());
648 cmd.Check(m_View->ColouringBy() == COLOUR_BY_SURVEY);
651 void GUIControl::OnColourByStyleUpdate(wxUpdateUIEvent& cmd)
653 cmd.Enable(m_View->HasData());
654 cmd.Check(m_View->ColouringBy() == COLOUR_BY_STYLE);
657 void GUIControl::OnShowCrosses()
659 m_View->ToggleCrosses();
662 void GUIControl::OnShowCrossesUpdate(wxUpdateUIEvent& cmd)
664 cmd.Enable(m_View->HasData());
665 cmd.Check(m_View->ShowingCrosses());
668 void GUIControl::OnShowStationNames()
670 m_View->ToggleStationNames();
673 void GUIControl::OnShowStationNamesUpdate(wxUpdateUIEvent& cmd)
675 cmd.Enable(m_View->HasData());
676 cmd.Check(m_View->ShowingStationNames());
679 void GUIControl::OnShowSurveyLegs()
681 m_View->ToggleUndergroundLegs();
684 void GUIControl::OnShowSurveyLegsUpdate(wxUpdateUIEvent& cmd)
686 cmd.Enable(m_View->HasData() && m_View->HasUndergroundLegs());
687 cmd.Check(m_View->ShowingUndergroundLegs());
690 void GUIControl::OnHideSplays()
692 m_View->SetSplaysMode(SHOW_HIDE);
695 void GUIControl::OnShowSplaysDashed()
697 m_View->SetSplaysMode(SHOW_DASHED);
700 void GUIControl::OnShowSplaysFaded()
702 m_View->SetSplaysMode(SHOW_FADED);
705 void GUIControl::OnShowSplaysNormal()
707 m_View->SetSplaysMode(SHOW_NORMAL);
710 void GUIControl::OnSplaysUpdate(wxUpdateUIEvent& cmd)
712 cmd.Enable(m_View->HasData() && m_View->HasSplays());
715 void GUIControl::OnHideSplaysUpdate(wxUpdateUIEvent& cmd)
717 cmd.Enable(m_View->HasData() && m_View->HasSplays());
718 cmd.Check(m_View->ShowingSplaysMode() == SHOW_HIDE);
721 void GUIControl::OnShowSplaysDashedUpdate(wxUpdateUIEvent& cmd)
723 cmd.Enable(m_View->HasData() && m_View->HasSplays());
724 cmd.Check(m_View->ShowingSplaysMode() == SHOW_DASHED);
727 void GUIControl::OnShowSplaysFadedUpdate(wxUpdateUIEvent& cmd)
729 cmd.Enable(m_View->HasData() && m_View->HasSplays());
730 cmd.Check(m_View->ShowingSplaysMode() == SHOW_FADED);
733 void GUIControl::OnShowSplaysNormalUpdate(wxUpdateUIEvent& cmd)
735 cmd.Enable(m_View->HasData() && m_View->HasSplays());
736 cmd.Check(m_View->ShowingSplaysMode() == SHOW_NORMAL);
739 void GUIControl::OnHideDupes() {
740 m_View->SetDupesMode(SHOW_HIDE);
743 void GUIControl::OnShowDupesDashed() {
744 m_View->SetDupesMode(SHOW_DASHED);
747 void GUIControl::OnShowDupesFaded() {
748 m_View->SetDupesMode(SHOW_FADED);
751 void GUIControl::OnShowDupesNormal() {
752 m_View->SetDupesMode(SHOW_NORMAL);
755 void GUIControl::OnDupesUpdate(wxUpdateUIEvent& cmd) {
756 cmd.Enable(m_View->HasData() && m_View->HasDupes());
759 void GUIControl::OnHideDupesUpdate(wxUpdateUIEvent& cmd) {
760 cmd.Enable(m_View->HasData() && m_View->HasDupes());
761 cmd.Check(m_View->ShowingDupesMode() == SHOW_HIDE);
764 void GUIControl::OnShowDupesDashedUpdate(wxUpdateUIEvent& cmd) {
765 cmd.Enable(m_View->HasData() && m_View->HasDupes());
766 cmd.Check(m_View->ShowingDupesMode() == SHOW_DASHED);
769 void GUIControl::OnShowDupesFadedUpdate(wxUpdateUIEvent& cmd) {
770 cmd.Enable(m_View->HasData() && m_View->HasDupes());
771 cmd.Check(m_View->ShowingDupesMode() == SHOW_FADED);
774 void GUIControl::OnShowDupesNormalUpdate(wxUpdateUIEvent& cmd) {
775 cmd.Enable(m_View->HasData() && m_View->HasDupes());
776 cmd.Check(m_View->ShowingDupesMode() == SHOW_NORMAL);
779 void GUIControl::OnMoveEast()
781 m_View->TurnCaveTo(90.0);
782 m_View->ForceRefresh();
785 void GUIControl::OnMoveEastUpdate(wxUpdateUIEvent& cmd)
787 cmd.Enable(m_View->HasData() && !m_View->IsExtendedElevation() && m_View->GetCompassValue() != 90.0);
790 void GUIControl::OnMoveNorth()
792 m_View->TurnCaveTo(0.0);
793 m_View->ForceRefresh();
796 void GUIControl::OnMoveNorthUpdate(wxUpdateUIEvent& cmd)
798 cmd.Enable(m_View->HasData() && m_View->GetCompassValue() != 0.0);
801 void GUIControl::OnMoveSouth()
803 m_View->TurnCaveTo(180.0);
804 m_View->ForceRefresh();
807 void GUIControl::OnMoveSouthUpdate(wxUpdateUIEvent& cmd)
809 cmd.Enable(m_View->HasData() && m_View->GetCompassValue() != 180.0);
812 void GUIControl::OnMoveWest()
814 m_View->TurnCaveTo(270.0);
815 m_View->ForceRefresh();
818 void GUIControl::OnMoveWestUpdate(wxUpdateUIEvent& cmd)
820 cmd.Enable(m_View->HasData() && !m_View->IsExtendedElevation() && m_View->GetCompassValue() != 270.0);
823 void GUIControl::OnToggleRotation()
825 m_View->ToggleRotation();
828 void GUIControl::OnToggleRotationUpdate(wxUpdateUIEvent& cmd)
830 cmd.Enable(m_View->HasData() && !m_View->IsExtendedElevation());
831 cmd.Check(m_View->HasData() && m_View->IsRotating());
834 void GUIControl::OnReverseControls()
836 m_ReverseControls = !m_ReverseControls;
839 void GUIControl::OnReverseControlsUpdate(wxUpdateUIEvent& cmd)
841 cmd.Enable(m_View->HasData());
842 cmd.Check(m_ReverseControls);
845 void GUIControl::OnReverseDirectionOfRotation()
847 m_View->ReverseRotation();
850 void GUIControl::OnReverseDirectionOfRotationUpdate(wxUpdateUIEvent& cmd)
852 cmd.Enable(m_View->HasData() && !m_View->IsExtendedElevation());
855 void GUIControl::OnStepOnceAnticlockwise(bool accel)
857 if (m_View->GetPerspective()) {
858 m_View->TurnCave(accel ? -5.0 * ROTATE_STEP : -ROTATE_STEP);
859 } else {
860 m_View->TurnCave(accel ? 5.0 * ROTATE_STEP : ROTATE_STEP);
862 m_View->ForceRefresh();
865 void GUIControl::OnStepOnceClockwise(bool accel)
867 if (m_View->GetPerspective()) {
868 m_View->TurnCave(accel ? 5.0 * ROTATE_STEP : ROTATE_STEP);
869 } else {
870 m_View->TurnCave(accel ? -5.0 * ROTATE_STEP : -ROTATE_STEP);
872 m_View->ForceRefresh();
875 void GUIControl::OnDefaults()
877 m_View->Defaults();
880 void GUIControl::OnDefaultsUpdate(wxUpdateUIEvent& cmd)
882 cmd.Enable(m_View->HasData());
885 void GUIControl::OnElevation()
887 // Switch to elevation view.
889 m_View->SwitchToElevation();
892 void GUIControl::OnElevationUpdate(wxUpdateUIEvent& cmd)
894 cmd.Enable(m_View->HasData() && !m_View->IsExtendedElevation() && !m_View->ShowingElevation());
897 void GUIControl::OnHigherViewpoint(bool accel)
899 // Raise the viewpoint.
900 if (m_View->GetPerspective()) {
901 m_View->TiltCave(accel ? 5.0 * ROTATE_STEP : ROTATE_STEP);
902 } else {
903 m_View->TiltCave(accel ? -5.0 * ROTATE_STEP : -ROTATE_STEP);
905 m_View->ForceRefresh();
908 void GUIControl::OnLowerViewpoint(bool accel)
910 // Lower the viewpoint.
911 if (m_View->GetPerspective()) {
912 m_View->TiltCave(accel ? -5.0 * ROTATE_STEP : -ROTATE_STEP);
913 } else {
914 m_View->TiltCave(accel ? 5.0 * ROTATE_STEP : ROTATE_STEP);
916 m_View->ForceRefresh();
919 void GUIControl::OnPlan()
921 // Switch to plan view.
922 m_View->SwitchToPlan();
925 void GUIControl::OnPlanUpdate(wxUpdateUIEvent& cmd)
927 cmd.Enable(m_View->HasData() && !m_View->IsExtendedElevation() && !m_View->ShowingPlan());
930 void GUIControl::OnShiftDisplayDown(bool accel)
932 if (m_View->GetPerspective())
933 m_View->MoveViewer(0, accel ? 5 * FLYFREE_SHIFT : FLYFREE_SHIFT, 0);
934 else
935 m_View->TranslateCave(0, accel ? 5 * DISPLAY_SHIFT : DISPLAY_SHIFT);
938 void GUIControl::OnShiftDisplayLeft(bool accel)
940 if (m_View->GetPerspective())
941 m_View->MoveViewer(0, 0, accel ? 5 * FLYFREE_SHIFT : FLYFREE_SHIFT);
942 else
943 m_View->TranslateCave(accel ? -5 * DISPLAY_SHIFT : -DISPLAY_SHIFT, 0);
946 void GUIControl::OnShiftDisplayRight(bool accel)
948 if (m_View->GetPerspective())
949 m_View->MoveViewer(0, 0, accel ? -5 * FLYFREE_SHIFT : -FLYFREE_SHIFT);
950 else
951 m_View->TranslateCave(accel ? 5 * DISPLAY_SHIFT : DISPLAY_SHIFT, 0);
954 void GUIControl::OnShiftDisplayUp(bool accel)
956 if (m_View->GetPerspective())
957 m_View->MoveViewer(0, accel ? -5 * FLYFREE_SHIFT : -FLYFREE_SHIFT, 0);
958 else
959 m_View->TranslateCave(0, accel ? -5 * DISPLAY_SHIFT : -DISPLAY_SHIFT);
962 void GUIControl::OnZoomIn(bool accel)
964 // Increase the scale.
966 if (m_View->GetPerspective()) {
967 m_View->MoveViewer(accel ? 5 * FLYFREE_SHIFT : FLYFREE_SHIFT, 0, 0);
968 } else {
969 m_View->SetScale(m_View->GetScale() * (accel ? 1.1236 : 1.06));
970 m_View->ForceRefresh();
974 void GUIControl::OnZoomOut(bool accel)
976 // Decrease the scale.
978 if (m_View->GetPerspective()) {
979 m_View->MoveViewer(accel ? -5 * FLYFREE_SHIFT : -FLYFREE_SHIFT, 0, 0);
980 } else {
981 m_View->SetScale(m_View->GetScale() / (accel ? 1.1236 : 1.06));
982 m_View->ForceRefresh();
986 void GUIControl::OnToggleScalebar()
988 m_View->ToggleScaleBar();
991 void GUIControl::OnToggleScalebarUpdate(wxUpdateUIEvent& cmd)
993 cmd.Enable(m_View->HasData());
994 cmd.Check(m_View->ShowingScaleBar());
997 void GUIControl::OnToggleColourKey()
999 m_View->ToggleColourKey();
1002 void GUIControl::OnToggleColourKeyUpdate(wxUpdateUIEvent& cmd)
1004 cmd.Enable(m_View->HasData() && m_View->ColouringBy() != COLOUR_BY_NONE);
1005 cmd.Check(m_View->ShowingColourKey());
1008 void GUIControl::OnViewCompass()
1010 m_View->ToggleCompass();
1013 void GUIControl::OnViewCompassUpdate(wxUpdateUIEvent& cmd)
1015 cmd.Enable(m_View->HasData() && !m_View->IsExtendedElevation());
1016 cmd.Check(m_View->ShowingCompass());
1019 void GUIControl::OnViewClino()
1021 m_View->ToggleClino();
1024 void GUIControl::OnViewClinoUpdate(wxUpdateUIEvent& cmd)
1026 cmd.Enable(m_View->HasData() && !m_View->IsExtendedElevation());
1027 cmd.Check(m_View->ShowingClino());
1030 void GUIControl::OnShowSurface()
1032 m_View->ToggleSurfaceLegs();
1035 void GUIControl::OnShowSurfaceUpdate(wxUpdateUIEvent& cmd)
1037 cmd.Enable(m_View->HasData() && m_View->HasSurfaceLegs());
1038 cmd.Check(m_View->ShowingSurfaceLegs());
1041 void GUIControl::OnShowEntrances()
1043 m_View->ToggleEntrances();
1046 void GUIControl::OnShowEntrancesUpdate(wxUpdateUIEvent& cmd)
1048 cmd.Enable(m_View->HasData() && (m_View->GetNumEntrances() > 0));
1049 cmd.Check(m_View->ShowingEntrances());
1052 void GUIControl::OnShowFixedPts()
1054 m_View->ToggleFixedPts();
1057 void GUIControl::OnShowFixedPtsUpdate(wxUpdateUIEvent& cmd)
1059 cmd.Enable(m_View->HasData() && (m_View->GetNumFixedPts() > 0));
1060 cmd.Check(m_View->ShowingFixedPts());
1063 void GUIControl::OnShowExportedPts()
1065 m_View->ToggleExportedPts();
1068 void GUIControl::OnShowExportedPtsUpdate(wxUpdateUIEvent& cmd)
1070 cmd.Enable(m_View->HasData() && (m_View->GetNumExportedPts() > 0));
1071 cmd.Check(m_View->ShowingExportedPts());
1074 void GUIControl::OnViewGrid()
1076 m_View->ToggleGrid();
1079 void GUIControl::OnViewGridUpdate(wxUpdateUIEvent& cmd)
1081 cmd.Enable(m_View->HasData());
1082 cmd.Check(m_View->ShowingGrid());
1085 void GUIControl::OnIndicatorsUpdate(wxUpdateUIEvent& cmd)
1087 cmd.Enable(m_View->HasData());
1090 void GUIControl::OnViewPerspective()
1092 m_View->TogglePerspective();
1093 // Force update of coordinate display.
1094 if (m_View->GetPerspective()) {
1095 m_View->MoveViewer(0, 0, 0);
1096 } else {
1097 m_View->ClearCoords();
1101 void GUIControl::OnViewPerspectiveUpdate(wxUpdateUIEvent& cmd)
1103 cmd.Enable(m_View->HasData() && !m_View->IsExtendedElevation());
1104 cmd.Check(m_View->GetPerspective());
1107 void GUIControl::OnViewSmoothShading()
1109 m_View->ToggleSmoothShading();
1112 void GUIControl::OnViewSmoothShadingUpdate(wxUpdateUIEvent& cmd)
1114 cmd.Enable(m_View->HasData());
1115 cmd.Check(m_View->GetSmoothShading());
1118 void GUIControl::OnViewTextured()
1120 m_View->ToggleTextured();
1123 void GUIControl::OnViewTexturedUpdate(wxUpdateUIEvent& cmd)
1125 cmd.Enable(m_View->HasData());
1126 cmd.Check(m_View->GetTextured());
1129 void GUIControl::OnViewFog()
1131 m_View->ToggleFog();
1134 void GUIControl::OnViewFogUpdate(wxUpdateUIEvent& cmd)
1136 cmd.Enable(m_View->HasData());
1137 cmd.Check(m_View->GetFog());
1140 void GUIControl::OnViewSmoothLines()
1142 m_View->ToggleAntiAlias();
1145 void GUIControl::OnViewSmoothLinesUpdate(wxUpdateUIEvent& cmd)
1147 cmd.Enable(m_View->HasData());
1148 cmd.Check(m_View->GetAntiAlias());
1151 void GUIControl::OnToggleMetric()
1153 m_View->ToggleMetric();
1155 wxConfigBase::Get()->Write(wxT("metric"), m_View->GetMetric());
1156 wxConfigBase::Get()->Flush();
1159 void GUIControl::OnToggleMetricUpdate(wxUpdateUIEvent& cmd)
1161 cmd.Enable(m_View->HasData());
1162 cmd.Check(m_View->GetMetric());
1165 void GUIControl::OnToggleDegrees()
1167 m_View->ToggleDegrees();
1169 wxConfigBase::Get()->Write(wxT("degrees"), m_View->GetDegrees());
1170 wxConfigBase::Get()->Flush();
1173 void GUIControl::OnToggleDegreesUpdate(wxUpdateUIEvent& cmd)
1175 cmd.Enable(m_View->HasData());
1176 cmd.Check(m_View->GetDegrees());
1179 void GUIControl::OnTogglePercent()
1181 m_View->TogglePercent();
1183 wxConfigBase::Get()->Write(wxT("percent"), m_View->GetPercent());
1184 wxConfigBase::Get()->Flush();
1187 void GUIControl::OnTogglePercentUpdate(wxUpdateUIEvent& cmd)
1189 cmd.Enable(m_View->HasData());
1190 cmd.Check(m_View->GetPercent());
1193 void GUIControl::OnToggleTubes()
1195 m_View->ToggleTubes();
1198 void GUIControl::OnToggleTubesUpdate(wxUpdateUIEvent& cmd)
1200 cmd.Enable(m_View->HasData() && m_View->HasTubes());
1201 cmd.Check(m_View->GetTubes());
1204 void GUIControl::OnCancelDistLine()
1206 m_View->ClearTreeSelection();
1209 void GUIControl::OnCancelDistLineUpdate(wxUpdateUIEvent& cmd)
1211 cmd.Enable(m_View->ShowingMeasuringLine());
1214 void GUIControl::OnKeyPress(wxKeyEvent &e)
1216 if (!m_View->HasData() ||
1217 (e.GetModifiers() &~ (wxMOD_CONTROL|wxMOD_SHIFT))) {
1218 // Pass on the event if there's no survey data, or if any modifier keys
1219 // other than Ctrl and Shift are pressed.
1220 e.Skip();
1221 return;
1224 // The changelog says this is meant to keep animation going while keys are
1225 // pressed, but that happens anyway (on linux at least - perhaps it helps
1226 // on windows?) FIXME : check!
1227 //bool refresh = m_View->Animate();
1229 switch (e.GetKeyCode()) {
1230 case '/': case '?':
1231 if (m_View->CanLowerViewpoint() && !m_View->IsExtendedElevation())
1232 OnLowerViewpoint(e.GetModifiers() == wxMOD_SHIFT);
1233 break;
1234 case '\'': case '@': case '"': // both shifted forms - US and UK kbd
1235 if (m_View->CanRaiseViewpoint() && !m_View->IsExtendedElevation())
1236 OnHigherViewpoint(e.GetModifiers() == wxMOD_SHIFT);
1237 break;
1238 case 'C': case 'c':
1239 if (!m_View->IsExtendedElevation() && !m_View->IsRotating())
1240 OnStepOnceAnticlockwise(e.GetModifiers() == wxMOD_SHIFT);
1241 break;
1242 case 'V': case 'v':
1243 if (!m_View->IsExtendedElevation() && !m_View->IsRotating())
1244 OnStepOnceClockwise(e.GetModifiers() == wxMOD_SHIFT);
1245 break;
1246 case ']': case '}':
1247 OnZoomIn(e.GetModifiers() == wxMOD_SHIFT);
1248 break;
1249 case '[': case '{':
1250 OnZoomOut(e.GetModifiers() == wxMOD_SHIFT);
1251 break;
1252 case 'N': case 'n':
1253 OnMoveNorth();
1254 break;
1255 case 'S': case 's':
1256 OnMoveSouth();
1257 break;
1258 case 'E': case 'e':
1259 if (!m_View->IsExtendedElevation())
1260 OnMoveEast();
1261 break;
1262 case 'W': case 'w':
1263 if (!m_View->IsExtendedElevation())
1264 OnMoveWest();
1265 break;
1266 case 'Z': case 'z':
1267 if (!m_View->IsExtendedElevation())
1268 m_View->RotateFaster(e.GetModifiers() == wxMOD_SHIFT);
1269 break;
1270 case 'X': case 'x':
1271 if (!m_View->IsExtendedElevation())
1272 m_View->RotateSlower(e.GetModifiers() == wxMOD_SHIFT);
1273 break;
1274 case 'R': case 'r':
1275 if (!m_View->IsExtendedElevation())
1276 OnReverseDirectionOfRotation();
1277 break;
1278 case 'P': case 'p':
1279 if (!m_View->IsExtendedElevation() && !m_View->ShowingPlan())
1280 OnPlan();
1281 break;
1282 case 'L': case 'l':
1283 if (!m_View->IsExtendedElevation() && !m_View->ShowingElevation())
1284 OnElevation();
1285 break;
1286 case 'O': case 'o':
1287 OnDisplayOverlappingNames();
1288 break;
1289 case WXK_DELETE:
1290 if (e.GetModifiers() == 0)
1291 OnDefaults();
1292 break;
1293 case WXK_RETURN:
1294 if (e.GetModifiers() == 0) {
1295 // For compatibility with older versions.
1296 if (!m_View->IsExtendedElevation() && !m_View->IsRotating())
1297 m_View->StartRotation();
1299 break;
1300 case WXK_SPACE:
1301 if (e.GetModifiers() == 0) {
1302 if (!m_View->IsExtendedElevation())
1303 OnToggleRotation();
1305 break;
1306 case WXK_LEFT:
1307 if ((e.GetModifiers() &~ wxMOD_SHIFT) == wxMOD_CONTROL) {
1308 if (!m_View->IsExtendedElevation() && !m_View->IsRotating())
1309 OnStepOnceAnticlockwise(e.GetModifiers() == wxMOD_SHIFT);
1310 } else {
1311 OnShiftDisplayLeft(e.GetModifiers() == wxMOD_SHIFT);
1313 break;
1314 case WXK_RIGHT:
1315 if ((e.GetModifiers() &~ wxMOD_SHIFT) == wxMOD_CONTROL) {
1316 if (!m_View->IsExtendedElevation() && !m_View->IsRotating())
1317 OnStepOnceClockwise(e.GetModifiers() == wxMOD_SHIFT);
1318 } else {
1319 OnShiftDisplayRight(e.GetModifiers() == wxMOD_SHIFT);
1321 break;
1322 case WXK_UP:
1323 if ((e.GetModifiers() &~ wxMOD_SHIFT) == wxMOD_CONTROL) {
1324 if (m_View->CanRaiseViewpoint() && !m_View->IsExtendedElevation())
1325 OnHigherViewpoint(e.GetModifiers() == wxMOD_SHIFT);
1326 } else {
1327 OnShiftDisplayUp(e.GetModifiers() == wxMOD_SHIFT);
1329 break;
1330 case WXK_DOWN:
1331 if ((e.GetModifiers() &~ wxMOD_SHIFT) == wxMOD_CONTROL) {
1332 if (m_View->CanLowerViewpoint() && !m_View->IsExtendedElevation())
1333 OnLowerViewpoint(e.GetModifiers() == wxMOD_SHIFT);
1334 } else {
1335 OnShiftDisplayDown(e.GetModifiers() == wxMOD_SHIFT);
1337 break;
1338 case WXK_ESCAPE:
1339 if (e.GetModifiers() == 0) {
1340 if (m_View->ShowingMeasuringLine()) {
1341 OnCancelDistLine();
1342 } else if (m_View->IsFullScreen()) {
1343 // Cancel full-screen mode on "Escape" if it isn't cancelling
1344 // the measuring line.
1345 m_View->FullScreenMode();
1348 break;
1349 case WXK_F2:
1350 if (e.GetModifiers() == 0)
1351 m_View->ToggleFatFinger();
1352 break;
1353 case WXK_F3:
1354 if (e.GetModifiers() == 0)
1355 m_View->ToggleHitTestDebug();
1356 break;
1357 case WXK_F4: {
1358 if (e.GetModifiers() == 0) {
1359 const wxChar * msg;
1360 #if wxDEBUG_LEVEL
1361 if (wxTheAssertHandler)
1362 wxTheAssertHandler = NULL;
1363 else
1364 wxSetDefaultAssertHandler();
1365 if (wxTheAssertHandler)
1366 msg = wxT("Assertions enabled");
1367 else
1368 msg = wxT("Assertions disabled");
1369 #else
1370 msg = wxT("wxWidgets was built without assertions");
1371 #endif
1372 wxMessageBox(msg, wxT("Aven Debug"), wxOK | wxICON_INFORMATION);
1374 break;
1376 case WXK_F5:
1377 if (e.GetModifiers() == 0) {
1378 m_View->InvalidateAllLists();
1379 m_View->ForceRefresh();
1381 break;
1382 case WXK_F6:
1383 if (e.GetModifiers() == 0)
1384 m_View->ToggleRenderStats();
1385 break;
1386 default:
1387 e.Skip();
1390 //if (refresh) m_View->ForceRefresh();
1393 void GUIControl::OnViewFullScreenUpdate(wxUpdateUIEvent& cmd)
1395 cmd.Check(m_View->IsFullScreen());
1398 void GUIControl::OnViewFullScreen()
1400 m_View->FullScreenMode();
1403 void GUIControl::OnViewBoundingBoxUpdate(wxUpdateUIEvent& cmd)
1405 cmd.Enable(m_View->HasData());
1406 cmd.Check(m_View->DisplayingBoundingBox());
1409 void GUIControl::OnViewBoundingBox()
1411 m_View->ToggleBoundingBox();
1414 void GUIControl::OnViewTerrainUpdate(wxUpdateUIEvent& cmd)
1416 cmd.Enable(m_View->HasTerrain());
1417 cmd.Check(m_View->DisplayingTerrain());
1420 void GUIControl::OnViewTerrain()
1422 m_View->ToggleTerrain();