4 // Main frame handling for Aven.
6 // Copyright (C) 2000-2002,2005,2006 Mark R. Shinwell
7 // Copyright (C) 2001-2003,2004,2005,2006,2010,2011,2012,2013,2014,2015,2016 Olly Betts
8 // Copyright (C) 2005 Martin Green
10 // This program is free software; you can redistribute it and/or modify
11 // it under the terms of the GNU General Public License as published by
12 // the Free Software Foundation; either version 2 of the License, or
13 // (at your option) any later version.
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.
20 // You should have received a copy of the GNU General Public License
21 // along with this program; if not, write to the Free Software
22 // Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
29 #include "cavernlog.h"
35 #include "img_hosted.h"
36 #include "namecompare.h"
41 #include <wx/confbase.h>
42 //#include <wx/filefn.h>
43 #include <wx/filename.h>
45 #include <wx/imaglist.h>
46 #include <wx/process.h>
48 #ifdef USING_GENERIC_TOOLBAR
49 # include <wx/sysopt.h>
61 #define TOOL(x) wxBitmap(wxT(#x), wxBITMAP_TYPE_PNG_RESOURCE)
63 // XPM files declare the array as static, but we also want it to be const too.
64 // This avoids a compiler warning, and also means the data can go in a
65 // read-only page and be shared between processes.
66 #define static static const
67 #include "../lib/icons/aven.xpm"
68 #include "../lib/icons/log.xpm"
69 #include "../lib/icons/open.xpm"
70 #include "../lib/icons/open_pres.xpm"
71 #include "../lib/icons/rotation.xpm"
72 #include "../lib/icons/plan.xpm"
73 #include "../lib/icons/elevation.xpm"
74 #include "../lib/icons/defaults.xpm"
75 #include "../lib/icons/names.xpm"
76 #include "../lib/icons/crosses.xpm"
77 #include "../lib/icons/entrances.xpm"
78 #include "../lib/icons/fixed_pts.xpm"
79 #include "../lib/icons/exported_pts.xpm"
80 #include "../lib/icons/ug_legs.xpm"
81 #include "../lib/icons/surface_legs.xpm"
82 #include "../lib/icons/tubes.xpm"
83 #include "../lib/icons/solid_surface.xpm"
84 #include "../lib/icons/pres_frew.xpm"
85 #include "../lib/icons/pres_rew.xpm"
86 #include "../lib/icons/pres_go_back.xpm"
87 #include "../lib/icons/pres_pause.xpm"
88 #include "../lib/icons/pres_go.xpm"
89 #include "../lib/icons/pres_ff.xpm"
90 #include "../lib/icons/pres_fff.xpm"
91 #include "../lib/icons/pres_stop.xpm"
92 #include "../lib/icons/find.xpm"
93 #include "../lib/icons/hideresults.xpm"
94 #include "../lib/icons/survey_tree.xpm"
95 #include "../lib/icons/pres_tree.xpm"
97 #define TOOL(x) wxBITMAP(x)
102 const static int img2aven_tab
[] = {
103 #include "img2aven.h"
109 flags
&= (sizeof(img2aven_tab
) / sizeof(img2aven_tab
[0]) - 1);
110 return img2aven_tab
[flags
];
113 class AvenSplitterWindow
: public wxSplitterWindow
{
117 explicit AvenSplitterWindow(MainFrm
*parent_
)
118 : wxSplitterWindow(parent_
, -1, wxDefaultPosition
, wxDefaultSize
,
124 void OnSplitterDClick(wxSplitterEvent
&) {
125 parent
->ToggleSidePanel();
129 DECLARE_EVENT_TABLE()
132 BEGIN_EVENT_TABLE(AvenSplitterWindow
, wxSplitterWindow
)
133 EVT_SPLITTER_DCLICK(-1, AvenSplitterWindow::OnSplitterDClick
)
136 class EditMarkDlg
: public wxDialog
{
137 wxTextCtrl
* easting
, * northing
, * altitude
;
138 wxTextCtrl
* angle
, * tilt_angle
, * scale
, * time
;
140 // TRANSLATORS: Title of dialog to edit a waypoint in a presentation.
141 EditMarkDlg(wxWindow
* parent
, const PresentationMark
& p
)
142 : wxDialog(parent
, 500, wmsg(/*Edit Waypoint*/404))
144 easting
= new wxTextCtrl(this, 601, wxString::Format(wxT("%.3f"), p
.GetX()));
145 northing
= new wxTextCtrl(this, 602, wxString::Format(wxT("%.3f"), p
.GetY()));
146 altitude
= new wxTextCtrl(this, 603, wxString::Format(wxT("%.3f"), p
.GetZ()));
147 angle
= new wxTextCtrl(this, 604, wxString::Format(wxT("%.3f"), p
.angle
));
148 tilt_angle
= new wxTextCtrl(this, 605, wxString::Format(wxT("%.3f"), p
.tilt_angle
));
149 scale
= new wxTextCtrl(this, 606, wxString::Format(wxT("%.3f"), p
.scale
));
151 time
= new wxTextCtrl(this, 607, wxString::Format(wxT("%.3f"), p
.time
));
152 } else if (p
.time
< 0.0) {
153 time
= new wxTextCtrl(this, 607, wxString::Format(wxT("*%.3f"), -p
.time
));
155 time
= new wxTextCtrl(this, 607, wxT("0"));
158 wxBoxSizer
* coords
= new wxBoxSizer(wxHORIZONTAL
);
159 coords
->Add(new wxStaticText(this, 610, wxT("(")), 0, wxALIGN_CENTRE_VERTICAL
);
160 coords
->Add(easting
, 1);
161 coords
->Add(new wxStaticText(this, 611, wxT(",")), 0, wxALIGN_CENTRE_VERTICAL
);
162 coords
->Add(northing
, 1);
163 coords
->Add(new wxStaticText(this, 612, wxT(",")), 0, wxALIGN_CENTRE_VERTICAL
);
164 coords
->Add(altitude
, 1);
165 coords
->Add(new wxStaticText(this, 613, wxT(")")), 0, wxALIGN_CENTRE_VERTICAL
);
166 wxBoxSizer
* vert
= new wxBoxSizer(wxVERTICAL
);
167 vert
->Add(coords
, 0, wxALL
, 8);
168 wxBoxSizer
* r2
= new wxBoxSizer(wxHORIZONTAL
);
169 r2
->Add(new wxStaticText(this, 614, wmsg(/*Bearing*/259) + wxT(": ")), 0, wxALIGN_CENTRE_VERTICAL
);
171 vert
->Add(r2
, 0, wxALL
, 8);
172 wxBoxSizer
* r3
= new wxBoxSizer(wxHORIZONTAL
);
173 r3
->Add(new wxStaticText(this, 615, wmsg(/*Elevation*/118) + wxT(": ")), 0, wxALIGN_CENTRE_VERTICAL
);
175 vert
->Add(r3
, 0, wxALL
, 8);
176 wxBoxSizer
* r4
= new wxBoxSizer(wxHORIZONTAL
);
177 r4
->Add(new wxStaticText(this, 616, wmsg(/*Scale*/154) + wxT(": ")), 0, wxALIGN_CENTRE_VERTICAL
);
179 /* TRANSLATORS: Note after "Scale" field in dialog to edit a waypoint
180 * in a presentation. */
181 r4
->Add(new wxStaticText(this, 617, wmsg(/* (unused in perspective view)*/278)),
182 0, wxALIGN_CENTRE_VERTICAL
);
183 vert
->Add(r4
, 0, wxALL
, 8);
185 wxBoxSizer
* r5
= new wxBoxSizer(wxHORIZONTAL
);
186 /* TRANSLATORS: Field label in dialog to edit a waypoint in a
188 r5
->Add(new wxStaticText(this, 616, wmsg(/*Time: */279)), 0, wxALIGN_CENTRE_VERTICAL
);
190 /* TRANSLATORS: units+info after time field in dialog to edit a
191 * waypoint in a presentation. */
192 r5
->Add(new wxStaticText(this, 617, wmsg(/* secs (0 = auto; *6 = 6 times auto)*/282)),
193 0, wxALIGN_CENTRE_VERTICAL
);
194 vert
->Add(r5
, 0, wxALL
, 8);
196 wxBoxSizer
* buttons
= new wxBoxSizer(wxHORIZONTAL
);
197 wxButton
* cancel
= new wxButton(this, wxID_CANCEL
);
198 buttons
->Add(cancel
, 0, wxALL
, 8);
199 wxButton
* ok
= new wxButton(this, wxID_OK
);
201 buttons
->Add(ok
, 0, wxALL
, 8);
202 vert
->Add(buttons
, 0, wxALL
|wxALIGN_RIGHT
);
207 vert
->SetSizeHints(this);
209 PresentationMark
GetMark() const {
211 Vector3
v(wxAtof(easting
->GetValue()),
212 wxAtof(northing
->GetValue()),
213 wxAtof(altitude
->GetValue()));
214 a
= wxAtof(angle
->GetValue());
215 t
= wxAtof(tilt_angle
->GetValue());
216 s
= wxAtof(scale
->GetValue());
217 wxString str
= time
->GetValue();
218 if (!str
.empty() && str
[0u] == '*') str
[0u] = '-';
220 return PresentationMark(v
, a
, t
, s
, T
);
224 DECLARE_EVENT_TABLE()
227 // Write a value without trailing zeros after the decimal point.
228 static void write_double(double d
, FILE * fh
) {
230 sprintf(buf
, "%.21f", d
);
231 char * p
= strchr(buf
, ',');
233 size_t l
= strlen(buf
);
234 while (l
> 1 && buf
[l
- 1] == '0') --l
;
235 if (l
> 1 && buf
[l
- 1] == '.') --l
;
236 fwrite(buf
, l
, 1, fh
);
239 class AvenPresList
: public wxListCtrl
{
242 vector
<PresentationMark
> entries
;
249 AvenPresList(MainFrm
* mainfrm_
, wxWindow
* parent
, GfxCore
* gfx_
)
250 : wxListCtrl(parent
, listctrl_PRES
, wxDefaultPosition
, wxDefaultSize
,
251 wxLC_REPORT
|wxLC_VIRTUAL
),
252 mainfrm(mainfrm_
), gfx(gfx_
), current_item(-1), modified(false),
255 InsertColumn(0, wmsg(/*Easting*/378));
256 InsertColumn(1, wmsg(/*Northing*/379));
257 InsertColumn(2, wmsg(/*Altitude*/335));
260 void OnBeginLabelEdit(wxListEvent
& event
) {
261 event
.Veto(); // No editting allowed
263 void OnDeleteItem(wxListEvent
& event
) {
264 long item
= event
.GetIndex();
265 if (current_item
== item
) {
267 } else if (current_item
> item
) {
270 entries
.erase(entries
.begin() + item
);
271 SetItemCount(entries
.size());
274 void OnDeleteAllItems(wxListEvent
&) {
276 SetItemCount(entries
.size());
277 filename
= wxString();
279 force_save_as
= true;
281 void OnListKeyDown(wxListEvent
& event
) {
282 switch (event
.GetKeyCode()) {
284 long item
= GetNextItem(-1, wxLIST_NEXT_ALL
,
285 wxLIST_STATE_SELECTED
);
288 // - 1 because the indices were shifted by DeleteItem()
289 item
= GetNextItem(item
- 1, wxLIST_NEXT_ALL
,
290 wxLIST_STATE_SELECTED
);
295 //printf("event.GetIndex() = %ld %d\n", event.GetIndex(), event.GetKeyCode());
299 void OnActivated(wxListEvent
& event
) {
300 // Jump to this view.
301 long item
= event
.GetIndex();
302 gfx
->SetView(entries
[item
]);
304 void OnFocused(wxListEvent
& event
) {
305 current_item
= event
.GetIndex();
307 void OnRightClick(wxListEvent
& event
) {
308 long item
= event
.GetIndex();
310 AddMark(item
, gfx
->GetView());
313 EditMarkDlg
edit(mainfrm
, entries
[item
]);
314 if (edit
.ShowModal() == wxID_OK
) {
315 entries
[item
] = edit
.GetMark();
318 void OnChar(wxKeyEvent
& event
) {
319 switch (event
.GetKeyCode()) {
321 if (event
.GetModifiers() == wxMOD_CONTROL
) {
322 if (current_item
!= -1 &&
323 size_t(current_item
) < entries
.size()) {
324 AddMark(current_item
, entries
[current_item
]);
327 AddMark(current_item
);
331 // Already handled in OnListKeyDown.
333 case WXK_UP
: case WXK_DOWN
:
337 gfx
->OnKeyPress(event
);
340 void AddMark(long item
= -1) {
341 AddMark(item
, gfx
->GetView());
343 void AddMark(long item
, const PresentationMark
& mark
) {
344 if (item
== -1) item
= entries
.size();
345 entries
.insert(entries
.begin() + item
, mark
);
346 SetItemCount(entries
.size());
349 virtual wxString
OnGetItemText(long item
, long column
) const {
350 if (item
< 0 || item
>= (long)entries
.size()) return wxString();
351 const PresentationMark
& p
= entries
[item
];
354 case 0: v
= p
.GetX(); break;
355 case 1: v
= p
.GetY(); break;
356 case 2: v
= p
.GetZ(); break;
358 case 3: v
= p
.angle
; break;
359 case 4: v
= p
.tilt_angle
; break;
360 case 5: v
= p
.scale
; break;
361 case 6: v
= p
.time
; break;
363 default: return wxString();
365 return wxString::Format(wxT("%ld"), (long)v
);
367 void Save(bool use_default_name
) {
368 wxString fnm
= filename
;
369 if (!use_default_name
|| force_save_as
) {
370 AvenAllowOnTop
ontop(mainfrm
);
372 wxString
ext(wxT("*.fly"));
374 wxString ext
= wmsg(/*Aven presentations*/320);
375 ext
+= wxT("|*.fly");
377 wxFileDialog
dlg(this, wmsg(/*Select an output filename*/319),
378 wxString(), fnm
, ext
,
379 wxFD_SAVE
|wxFD_OVERWRITE_PROMPT
);
380 if (dlg
.ShowModal() != wxID_OK
) return;
384 FILE * fh_pres
= wxFopen(fnm
, wxT("w"));
386 wxGetApp().ReportError(wxString::Format(wmsg(/*Error writing to file “%s”*/110), fnm
.c_str()));
389 vector
<PresentationMark
>::const_iterator i
;
390 for (i
= entries
.begin(); i
!= entries
.end(); ++i
) {
391 const PresentationMark
&p
= *i
;
392 write_double(p
.GetX(), fh_pres
);
394 write_double(p
.GetY(), fh_pres
);
396 write_double(p
.GetZ(), fh_pres
);
398 write_double(p
.angle
, fh_pres
);
400 write_double(p
.tilt_angle
, fh_pres
);
402 write_double(p
.scale
, fh_pres
);
405 write_double(p
.time
, fh_pres
);
412 force_save_as
= false;
414 void New(const wxString
&fnm
) {
416 wxFileName::SplitPath(fnm
, NULL
, NULL
, &filename
, NULL
, wxPATH_NATIVE
);
417 filename
+= wxT(".fly");
418 force_save_as
= true;
420 bool Load(const wxString
&fnm
) {
421 FILE * fh_pres
= wxFopen(fnm
, wxT("r"));
424 m
.Printf(wmsg(/*Couldn’t open file “%s”*/24), fnm
.c_str());
425 wxGetApp().ReportError(m
);
430 while (!feof(fh_pres
)) {
433 while (i
< sizeof(buf
) - 1) {
434 int ch
= GETC(fh_pres
);
435 if (ch
== EOF
|| ch
== '\n' || ch
== '\r') break;
440 double x
, y
, z
, a
, t
, s
, T
;
441 int c
= sscanf(buf
, "%lf %lf %lf %lf %lf %lf %lf", &x
, &y
, &z
, &a
, &t
, &s
, &T
);
444 while ((p
= strchr(p
, '.'))) *p
++ = ',';
445 c
= sscanf(buf
, "%lf %lf %lf %lf %lf %lf %lf", &x
, &y
, &z
, &a
, &t
, &s
, &T
);
448 wxGetApp().ReportError(wxString::Format(wmsg(/*Error in format of presentation file “%s”*/323), fnm
.c_str()));
453 AddMark(item
, PresentationMark(Vector3(x
, y
, z
), a
, t
, s
, T
));
460 force_save_as
= false;
463 bool Modified() const { return modified
; }
464 bool Empty() const { return entries
.empty(); }
465 PresentationMark
GetPresMark(int which
) {
466 long item
= current_item
;
467 if (which
== MARK_FIRST
) {
469 } else if (which
== MARK_NEXT
) {
471 } else if (which
== MARK_PREV
) {
474 if (item
== -1 || item
== (long)entries
.size())
475 return PresentationMark();
476 if (item
!= current_item
) {
478 if (current_item
!= -1) {
479 wxListCtrl::SetItemState(current_item
, wxLIST_STATE_FOCUSED
,
482 wxListCtrl::SetItemState(item
, wxLIST_STATE_FOCUSED
,
483 wxLIST_STATE_FOCUSED
);
485 return entries
[item
];
490 DECLARE_NO_COPY_CLASS(AvenPresList
)
491 DECLARE_EVENT_TABLE()
494 BEGIN_EVENT_TABLE(EditMarkDlg
, wxDialog
)
497 BEGIN_EVENT_TABLE(AvenPresList
, wxListCtrl
)
498 EVT_LIST_BEGIN_LABEL_EDIT(listctrl_PRES
, AvenPresList::OnBeginLabelEdit
)
499 EVT_LIST_DELETE_ITEM(listctrl_PRES
, AvenPresList::OnDeleteItem
)
500 EVT_LIST_DELETE_ALL_ITEMS(listctrl_PRES
, AvenPresList::OnDeleteAllItems
)
501 EVT_LIST_KEY_DOWN(listctrl_PRES
, AvenPresList::OnListKeyDown
)
502 EVT_LIST_ITEM_ACTIVATED(listctrl_PRES
, AvenPresList::OnActivated
)
503 EVT_LIST_ITEM_FOCUSED(listctrl_PRES
, AvenPresList::OnFocused
)
504 EVT_LIST_ITEM_RIGHT_CLICK(listctrl_PRES
, AvenPresList::OnRightClick
)
505 EVT_CHAR(AvenPresList::OnChar
)
508 BEGIN_EVENT_TABLE(MainFrm
, wxFrame
)
509 EVT_TEXT(textctrl_FIND
, MainFrm::OnFind
)
510 EVT_TEXT_ENTER(textctrl_FIND
, MainFrm::OnGotoFound
)
511 EVT_MENU(wxID_FIND
, MainFrm::OnGotoFound
)
512 EVT_MENU(button_HIDE
, MainFrm::OnHide
)
513 EVT_UPDATE_UI(button_HIDE
, MainFrm::OnHideUpdate
)
514 EVT_IDLE(MainFrm::OnIdle
)
516 EVT_MENU(wxID_OPEN
, MainFrm::OnOpen
)
517 EVT_MENU(menu_FILE_OPEN_TERRAIN
, MainFrm::OnOpenTerrain
)
518 EVT_MENU(menu_FILE_LOG
, MainFrm::OnShowLog
)
519 EVT_MENU(wxID_PRINT
, MainFrm::OnPrint
)
520 EVT_MENU(menu_FILE_PAGE_SETUP
, MainFrm::OnPageSetup
)
521 EVT_MENU(menu_FILE_SCREENSHOT
, MainFrm::OnScreenshot
)
522 // EVT_MENU(wxID_PREFERENCES, MainFrm::OnFilePreferences)
523 EVT_MENU(menu_FILE_EXPORT
, MainFrm::OnExport
)
524 EVT_MENU(menu_FILE_EXTEND
, MainFrm::OnExtend
)
525 EVT_MENU(wxID_EXIT
, MainFrm::OnQuit
)
526 EVT_MENU_RANGE(wxID_FILE1
, wxID_FILE9
, MainFrm::OnMRUFile
)
528 EVT_MENU(menu_PRES_NEW
, MainFrm::OnPresNew
)
529 EVT_MENU(menu_PRES_OPEN
, MainFrm::OnPresOpen
)
530 EVT_MENU(menu_PRES_SAVE
, MainFrm::OnPresSave
)
531 EVT_MENU(menu_PRES_SAVE_AS
, MainFrm::OnPresSaveAs
)
532 EVT_MENU(menu_PRES_MARK
, MainFrm::OnPresMark
)
533 EVT_MENU(menu_PRES_FREWIND
, MainFrm::OnPresFRewind
)
534 EVT_MENU(menu_PRES_REWIND
, MainFrm::OnPresRewind
)
535 EVT_MENU(menu_PRES_REVERSE
, MainFrm::OnPresReverse
)
536 EVT_MENU(menu_PRES_PLAY
, MainFrm::OnPresPlay
)
537 EVT_MENU(menu_PRES_FF
, MainFrm::OnPresFF
)
538 EVT_MENU(menu_PRES_FFF
, MainFrm::OnPresFFF
)
539 EVT_MENU(menu_PRES_PAUSE
, MainFrm::OnPresPause
)
540 EVT_MENU(wxID_STOP
, MainFrm::OnPresStop
)
541 EVT_MENU(menu_PRES_EXPORT_MOVIE
, MainFrm::OnPresExportMovie
)
543 EVT_UPDATE_UI(menu_PRES_NEW
, MainFrm::OnPresNewUpdate
)
544 EVT_UPDATE_UI(menu_PRES_OPEN
, MainFrm::OnPresOpenUpdate
)
545 EVT_UPDATE_UI(menu_PRES_SAVE
, MainFrm::OnPresSaveUpdate
)
546 EVT_UPDATE_UI(menu_PRES_SAVE_AS
, MainFrm::OnPresSaveAsUpdate
)
547 EVT_UPDATE_UI(menu_PRES_MARK
, MainFrm::OnPresMarkUpdate
)
548 EVT_UPDATE_UI(menu_PRES_FREWIND
, MainFrm::OnPresFRewindUpdate
)
549 EVT_UPDATE_UI(menu_PRES_REWIND
, MainFrm::OnPresRewindUpdate
)
550 EVT_UPDATE_UI(menu_PRES_REVERSE
, MainFrm::OnPresReverseUpdate
)
551 EVT_UPDATE_UI(menu_PRES_PLAY
, MainFrm::OnPresPlayUpdate
)
552 EVT_UPDATE_UI(menu_PRES_FF
, MainFrm::OnPresFFUpdate
)
553 EVT_UPDATE_UI(menu_PRES_FFF
, MainFrm::OnPresFFFUpdate
)
554 EVT_UPDATE_UI(menu_PRES_PAUSE
, MainFrm::OnPresPauseUpdate
)
555 EVT_UPDATE_UI(wxID_STOP
, MainFrm::OnPresStopUpdate
)
556 EVT_UPDATE_UI(menu_PRES_EXPORT_MOVIE
, MainFrm::OnPresExportMovieUpdate
)
558 EVT_CLOSE(MainFrm::OnClose
)
559 EVT_SET_FOCUS(MainFrm::OnSetFocus
)
561 EVT_MENU(menu_ROTATION_TOGGLE
, MainFrm::OnToggleRotation
)
562 EVT_MENU(menu_ROTATION_REVERSE
, MainFrm::OnReverseDirectionOfRotation
)
563 EVT_MENU(menu_ORIENT_MOVE_NORTH
, MainFrm::OnMoveNorth
)
564 EVT_MENU(menu_ORIENT_MOVE_EAST
, MainFrm::OnMoveEast
)
565 EVT_MENU(menu_ORIENT_MOVE_SOUTH
, MainFrm::OnMoveSouth
)
566 EVT_MENU(menu_ORIENT_MOVE_WEST
, MainFrm::OnMoveWest
)
567 EVT_MENU(menu_ORIENT_PLAN
, MainFrm::OnPlan
)
568 EVT_MENU(menu_ORIENT_ELEVATION
, MainFrm::OnElevation
)
569 EVT_MENU(menu_ORIENT_DEFAULTS
, MainFrm::OnDefaults
)
570 EVT_MENU(menu_VIEW_SHOW_LEGS
, MainFrm::OnShowSurveyLegs
)
571 EVT_MENU(menu_SPLAYS_HIDE
, MainFrm::OnHideSplays
)
572 EVT_MENU(menu_SPLAYS_SHOW_DASHED
, MainFrm::OnShowSplaysDashed
)
573 EVT_MENU(menu_SPLAYS_SHOW_FADED
, MainFrm::OnShowSplaysFaded
)
574 EVT_MENU(menu_SPLAYS_SHOW_NORMAL
, MainFrm::OnShowSplaysNormal
)
575 EVT_MENU(menu_DUPES_HIDE
, MainFrm::OnHideDupes
)
576 EVT_MENU(menu_DUPES_SHOW_DASHED
, MainFrm::OnShowDupesDashed
)
577 EVT_MENU(menu_DUPES_SHOW_FADED
, MainFrm::OnShowDupesFaded
)
578 EVT_MENU(menu_DUPES_SHOW_NORMAL
, MainFrm::OnShowDupesNormal
)
579 EVT_MENU(menu_VIEW_SHOW_CROSSES
, MainFrm::OnShowCrosses
)
580 EVT_MENU(menu_VIEW_SHOW_ENTRANCES
, MainFrm::OnShowEntrances
)
581 EVT_MENU(menu_VIEW_SHOW_FIXED_PTS
, MainFrm::OnShowFixedPts
)
582 EVT_MENU(menu_VIEW_SHOW_EXPORTED_PTS
, MainFrm::OnShowExportedPts
)
583 EVT_MENU(menu_VIEW_SHOW_NAMES
, MainFrm::OnShowStationNames
)
584 EVT_MENU(menu_VIEW_SHOW_OVERLAPPING_NAMES
, MainFrm::OnDisplayOverlappingNames
)
585 EVT_MENU(menu_COLOUR_BY_DEPTH
, MainFrm::OnColourByDepth
)
586 EVT_MENU(menu_COLOUR_BY_DATE
, MainFrm::OnColourByDate
)
587 EVT_MENU(menu_COLOUR_BY_ERROR
, MainFrm::OnColourByError
)
588 EVT_MENU(menu_COLOUR_BY_GRADIENT
, MainFrm::OnColourByGradient
)
589 EVT_MENU(menu_COLOUR_BY_LENGTH
, MainFrm::OnColourByLength
)
590 EVT_MENU(menu_VIEW_SHOW_SURFACE
, MainFrm::OnShowSurface
)
591 EVT_MENU(menu_VIEW_GRID
, MainFrm::OnViewGrid
)
592 EVT_MENU(menu_VIEW_BOUNDING_BOX
, MainFrm::OnViewBoundingBox
)
593 EVT_MENU(menu_VIEW_PERSPECTIVE
, MainFrm::OnViewPerspective
)
594 EVT_MENU(menu_VIEW_SMOOTH_SHADING
, MainFrm::OnViewSmoothShading
)
595 EVT_MENU(menu_VIEW_TEXTURED
, MainFrm::OnViewTextured
)
596 EVT_MENU(menu_VIEW_FOG
, MainFrm::OnViewFog
)
597 EVT_MENU(menu_VIEW_SMOOTH_LINES
, MainFrm::OnViewSmoothLines
)
598 EVT_MENU(menu_VIEW_FULLSCREEN
, MainFrm::OnViewFullScreen
)
599 EVT_MENU(menu_VIEW_SHOW_TUBES
, MainFrm::OnToggleTubes
)
600 EVT_MENU(menu_VIEW_TERRAIN
, MainFrm::OnViewTerrain
)
601 EVT_MENU(menu_IND_COMPASS
, MainFrm::OnViewCompass
)
602 EVT_MENU(menu_IND_CLINO
, MainFrm::OnViewClino
)
603 EVT_MENU(menu_IND_COLOUR_KEY
, MainFrm::OnToggleColourKey
)
604 EVT_MENU(menu_IND_SCALE_BAR
, MainFrm::OnToggleScalebar
)
605 EVT_MENU(menu_CTL_SIDE_PANEL
, MainFrm::OnViewSidePanel
)
606 EVT_MENU(menu_CTL_METRIC
, MainFrm::OnToggleMetric
)
607 EVT_MENU(menu_CTL_DEGREES
, MainFrm::OnToggleDegrees
)
608 EVT_MENU(menu_CTL_PERCENT
, MainFrm::OnTogglePercent
)
609 EVT_MENU(menu_CTL_REVERSE
, MainFrm::OnReverseControls
)
610 EVT_MENU(menu_CTL_CANCEL_DIST_LINE
, MainFrm::OnCancelDistLine
)
611 EVT_MENU(wxID_ABOUT
, MainFrm::OnAbout
)
613 EVT_UPDATE_UI(menu_FILE_OPEN_TERRAIN
, MainFrm::OnOpenTerrainUpdate
)
614 EVT_UPDATE_UI(menu_FILE_LOG
, MainFrm::OnShowLogUpdate
)
615 EVT_UPDATE_UI(wxID_PRINT
, MainFrm::OnPrintUpdate
)
616 EVT_UPDATE_UI(menu_FILE_SCREENSHOT
, MainFrm::OnScreenshotUpdate
)
617 EVT_UPDATE_UI(menu_FILE_EXPORT
, MainFrm::OnExportUpdate
)
618 EVT_UPDATE_UI(menu_FILE_EXTEND
, MainFrm::OnExtendUpdate
)
619 EVT_UPDATE_UI(menu_ROTATION_TOGGLE
, MainFrm::OnToggleRotationUpdate
)
620 EVT_UPDATE_UI(menu_ROTATION_REVERSE
, MainFrm::OnReverseDirectionOfRotationUpdate
)
621 EVT_UPDATE_UI(menu_ORIENT_MOVE_NORTH
, MainFrm::OnMoveNorthUpdate
)
622 EVT_UPDATE_UI(menu_ORIENT_MOVE_EAST
, MainFrm::OnMoveEastUpdate
)
623 EVT_UPDATE_UI(menu_ORIENT_MOVE_SOUTH
, MainFrm::OnMoveSouthUpdate
)
624 EVT_UPDATE_UI(menu_ORIENT_MOVE_WEST
, MainFrm::OnMoveWestUpdate
)
625 EVT_UPDATE_UI(menu_ORIENT_PLAN
, MainFrm::OnPlanUpdate
)
626 EVT_UPDATE_UI(menu_ORIENT_ELEVATION
, MainFrm::OnElevationUpdate
)
627 EVT_UPDATE_UI(menu_ORIENT_DEFAULTS
, MainFrm::OnDefaultsUpdate
)
628 EVT_UPDATE_UI(menu_VIEW_SHOW_LEGS
, MainFrm::OnShowSurveyLegsUpdate
)
629 EVT_UPDATE_UI(menu_VIEW_SPLAYS
, MainFrm::OnSplaysUpdate
)
630 EVT_UPDATE_UI(menu_SPLAYS_HIDE
, MainFrm::OnHideSplaysUpdate
)
631 EVT_UPDATE_UI(menu_SPLAYS_SHOW_DASHED
, MainFrm::OnShowSplaysDashedUpdate
)
632 EVT_UPDATE_UI(menu_SPLAYS_SHOW_FADED
, MainFrm::OnShowSplaysFadedUpdate
)
633 EVT_UPDATE_UI(menu_SPLAYS_SHOW_NORMAL
, MainFrm::OnShowSplaysNormalUpdate
)
634 EVT_UPDATE_UI(menu_VIEW_DUPES
, MainFrm::OnDupesUpdate
)
635 EVT_UPDATE_UI(menu_DUPES_HIDE
, MainFrm::OnHideDupesUpdate
)
636 EVT_UPDATE_UI(menu_DUPES_SHOW_DASHED
, MainFrm::OnShowDupesDashedUpdate
)
637 EVT_UPDATE_UI(menu_DUPES_SHOW_FADED
, MainFrm::OnShowDupesFadedUpdate
)
638 EVT_UPDATE_UI(menu_DUPES_SHOW_NORMAL
, MainFrm::OnShowDupesNormalUpdate
)
639 EVT_UPDATE_UI(menu_VIEW_SHOW_CROSSES
, MainFrm::OnShowCrossesUpdate
)
640 EVT_UPDATE_UI(menu_VIEW_SHOW_ENTRANCES
, MainFrm::OnShowEntrancesUpdate
)
641 EVT_UPDATE_UI(menu_VIEW_SHOW_FIXED_PTS
, MainFrm::OnShowFixedPtsUpdate
)
642 EVT_UPDATE_UI(menu_VIEW_SHOW_EXPORTED_PTS
, MainFrm::OnShowExportedPtsUpdate
)
643 EVT_UPDATE_UI(menu_VIEW_SHOW_NAMES
, MainFrm::OnShowStationNamesUpdate
)
644 EVT_UPDATE_UI(menu_VIEW_SHOW_SURFACE
, MainFrm::OnShowSurfaceUpdate
)
645 EVT_UPDATE_UI(menu_VIEW_SHOW_OVERLAPPING_NAMES
, MainFrm::OnDisplayOverlappingNamesUpdate
)
646 EVT_UPDATE_UI(menu_VIEW_COLOUR_BY
, MainFrm::OnColourByUpdate
)
647 EVT_UPDATE_UI(menu_COLOUR_BY_DEPTH
, MainFrm::OnColourByDepthUpdate
)
648 EVT_UPDATE_UI(menu_COLOUR_BY_DATE
, MainFrm::OnColourByDateUpdate
)
649 EVT_UPDATE_UI(menu_COLOUR_BY_ERROR
, MainFrm::OnColourByErrorUpdate
)
650 EVT_UPDATE_UI(menu_COLOUR_BY_GRADIENT
, MainFrm::OnColourByGradientUpdate
)
651 EVT_UPDATE_UI(menu_COLOUR_BY_LENGTH
, MainFrm::OnColourByLengthUpdate
)
652 EVT_UPDATE_UI(menu_VIEW_GRID
, MainFrm::OnViewGridUpdate
)
653 EVT_UPDATE_UI(menu_VIEW_BOUNDING_BOX
, MainFrm::OnViewBoundingBoxUpdate
)
654 EVT_UPDATE_UI(menu_VIEW_PERSPECTIVE
, MainFrm::OnViewPerspectiveUpdate
)
655 EVT_UPDATE_UI(menu_VIEW_SMOOTH_SHADING
, MainFrm::OnViewSmoothShadingUpdate
)
656 EVT_UPDATE_UI(menu_VIEW_TEXTURED
, MainFrm::OnViewTexturedUpdate
)
657 EVT_UPDATE_UI(menu_VIEW_FOG
, MainFrm::OnViewFogUpdate
)
658 EVT_UPDATE_UI(menu_VIEW_SMOOTH_LINES
, MainFrm::OnViewSmoothLinesUpdate
)
659 EVT_UPDATE_UI(menu_VIEW_FULLSCREEN
, MainFrm::OnViewFullScreenUpdate
)
660 EVT_UPDATE_UI(menu_VIEW_SHOW_TUBES
, MainFrm::OnToggleTubesUpdate
)
661 EVT_UPDATE_UI(menu_VIEW_TERRAIN
, MainFrm::OnViewTerrainUpdate
)
662 EVT_UPDATE_UI(menu_IND_COMPASS
, MainFrm::OnViewCompassUpdate
)
663 EVT_UPDATE_UI(menu_IND_CLINO
, MainFrm::OnViewClinoUpdate
)
664 EVT_UPDATE_UI(menu_IND_COLOUR_KEY
, MainFrm::OnToggleColourKeyUpdate
)
665 EVT_UPDATE_UI(menu_IND_SCALE_BAR
, MainFrm::OnToggleScalebarUpdate
)
666 EVT_UPDATE_UI(menu_CTL_INDICATORS
, MainFrm::OnIndicatorsUpdate
)
667 EVT_UPDATE_UI(menu_CTL_SIDE_PANEL
, MainFrm::OnViewSidePanelUpdate
)
668 EVT_UPDATE_UI(menu_CTL_REVERSE
, MainFrm::OnReverseControlsUpdate
)
669 EVT_UPDATE_UI(menu_CTL_CANCEL_DIST_LINE
, MainFrm::OnCancelDistLineUpdate
)
670 EVT_UPDATE_UI(menu_CTL_METRIC
, MainFrm::OnToggleMetricUpdate
)
671 EVT_UPDATE_UI(menu_CTL_DEGREES
, MainFrm::OnToggleDegreesUpdate
)
672 EVT_UPDATE_UI(menu_CTL_PERCENT
, MainFrm::OnTogglePercentUpdate
)
675 class LabelCmp
: public greater
<const LabelInfo
*> {
678 explicit LabelCmp(wxChar separator_
) : separator(separator_
) {}
679 bool operator()(const LabelInfo
* pt1
, const LabelInfo
* pt2
) {
680 return name_cmp(pt1
->GetText(), pt2
->GetText(), separator
) < 0;
684 class LabelPlotCmp
: public greater
<const LabelInfo
*> {
687 explicit LabelPlotCmp(wxChar separator_
) : separator(separator_
) {}
688 bool operator()(const LabelInfo
* pt1
, const LabelInfo
* pt2
) {
689 int n
= pt1
->get_flags() - pt2
->get_flags();
691 wxString l1
= pt1
->GetText().AfterLast(separator
);
692 wxString l2
= pt2
->GetText().AfterLast(separator
);
693 n
= name_cmp(l1
, l2
, separator
);
695 // Prefer non-2-nodes...
697 // if leaf names are the same, prefer shorter labels as we can
698 // display more of them
699 n
= pt1
->GetText().length() - pt2
->GetText().length();
701 // make sure that we don't ever compare different labels as equal
702 return name_cmp(pt1
->GetText(), pt2
->GetText(), separator
) < 0;
706 #if wxUSE_DRAG_AND_DROP
707 class DnDFile
: public wxFileDropTarget
{
709 explicit DnDFile(MainFrm
*parent
) : m_Parent(parent
) { }
710 virtual bool OnDropFiles(wxCoord
, wxCoord
,
711 const wxArrayString
&filenames
);
718 DnDFile::OnDropFiles(wxCoord
, wxCoord
, const wxArrayString
&filenames
)
720 // Load a survey file by drag-and-drop.
721 assert(filenames
.GetCount() > 0);
723 if (filenames
.GetCount() != 1) {
724 /* TRANSLATORS: error if you try to drag multiple files to the aven
726 wxGetApp().ReportError(wmsg(/*You may only view one 3d file at a time.*/336));
730 m_Parent
->OpenFile(filenames
[0]);
735 MainFrm::MainFrm(const wxString
& title
, const wxPoint
& pos
, const wxSize
& size
) :
736 wxFrame(NULL
, 101, title
, pos
, size
, wxDEFAULT_FRAME_STYLE
),
738 m_Gfx(NULL
), m_Log(NULL
),
739 m_NumEntrances(0), m_NumFixedPts(0), m_NumExportedPts(0),
741 m_HasUndergroundLegs(false),
742 m_HasSplays(false), m_HasDupes(false), m_HasSurfaceLegs(false),
743 m_HasErrorInformation(false), m_IsExtendedElevation(false),
744 pending_find(false), fullscreen_showing_menus(false)
750 // The peculiar name is so that the icon is the first in the file
751 // (required by Microsoft Windows for this type of icon)
752 SetIcon(wxICON(AAA_aven
));
754 SetIcon(wxICON(aven
));
757 #if wxCHECK_VERSION(3,1,0)
758 // Add a full screen button to the right upper corner of title bar under OS
760 EnableFullScreenView();
764 CreateStatusBar(2, wxST_SIZEGRIP
);
767 int widths
[2] = { -1 /* variable width */, -1 };
768 GetStatusBar()->SetStatusWidths(2, widths
);
770 #ifdef __X__ // wxMotif or wxX11
774 // X seems to require a forced resize.
775 SetSize(-1, -1, x
, y
);
778 #if wxUSE_DRAG_AND_DROP
779 SetDropTarget(new DnDFile(this));
783 void MainFrm::CreateMenuBar()
785 // Create the menus and the menu bar.
787 wxMenu
* filemenu
= new wxMenu
;
788 // wxID_OPEN stock label lacks the ellipses
789 /* TRANSLATORS: Aven menu items. An “&” goes before the letter of any
792 * The string "\t" separates the menu text and any accelerator key.
794 * "File" menu. The accelerators must be different within this group.
795 * c.f. 201, 380, 381. */
796 filemenu
->Append(wxID_OPEN
, wmsg(/*&Open...\tCtrl+O*/220));
797 /* TRANSLATORS: Open a "Terrain file" - i.e. a digital model of the
799 filemenu
->Append(menu_FILE_OPEN_TERRAIN
, wmsg(/*Open &Terrain...*/453));
800 filemenu
->AppendCheckItem(menu_FILE_LOG
, wmsg(/*Show &Log*/144));
801 filemenu
->AppendSeparator();
802 // wxID_PRINT stock label lacks the ellipses
803 filemenu
->Append(wxID_PRINT
, wmsg(/*&Print...\tCtrl+P*/380));
804 filemenu
->Append(menu_FILE_PAGE_SETUP
, wmsg(/*P&age Setup...*/381));
805 filemenu
->AppendSeparator();
806 /* TRANSLATORS: In the "File" menu */
807 filemenu
->Append(menu_FILE_SCREENSHOT
, wmsg(/*&Screenshot...*/201));
808 filemenu
->Append(menu_FILE_EXPORT
, wmsg(/*&Export as...*/382));
809 /* TRANSLATORS: In the "File" menu - c.f. n:191 */
810 filemenu
->Append(menu_FILE_EXTEND
, wmsg(/*E&xtended Elevation...*/247));
812 // On wxMac the "Quit" menu item will be moved elsewhere, so we suppress
814 filemenu
->AppendSeparator();
816 // We suppress the "Help" menu under OS X as it would otherwise end up as
817 // an empty menu, but we need to add the "About" menu item somewhere. It
818 // really doesn't matter where as wxWidgets will move it to the "Apple"
820 filemenu
->Append(wxID_ABOUT
);
822 filemenu
->Append(wxID_EXIT
);
824 m_history
.UseMenu(filemenu
);
825 m_history
.Load(*wxConfigBase::Get());
827 wxMenu
* rotmenu
= new wxMenu
;
828 /* TRANSLATORS: "Rotation" menu. The accelerators must be different within
829 * this group. Tickable menu item which toggles auto rotation.
830 * Please don't translate "Space" - that's the shortcut key to use which
831 * wxWidgets needs to parse and it should then handle translating.
833 rotmenu
->AppendCheckItem(menu_ROTATION_TOGGLE
, wmsg(/*Au&to-Rotate\tSpace*/231));
834 rotmenu
->AppendSeparator();
835 rotmenu
->Append(menu_ROTATION_REVERSE
, wmsg(/*&Reverse Direction*/234));
837 wxMenu
* orientmenu
= new wxMenu
;
838 orientmenu
->Append(menu_ORIENT_MOVE_NORTH
, wmsg(/*View &North*/240));
839 orientmenu
->Append(menu_ORIENT_MOVE_EAST
, wmsg(/*View &East*/241));
840 orientmenu
->Append(menu_ORIENT_MOVE_SOUTH
, wmsg(/*View &South*/242));
841 orientmenu
->Append(menu_ORIENT_MOVE_WEST
, wmsg(/*View &West*/243));
842 orientmenu
->AppendSeparator();
843 orientmenu
->Append(menu_ORIENT_PLAN
, wmsg(/*&Plan View*/248));
844 orientmenu
->Append(menu_ORIENT_ELEVATION
, wmsg(/*Ele&vation*/249));
845 orientmenu
->AppendSeparator();
846 orientmenu
->Append(menu_ORIENT_DEFAULTS
, wmsg(/*Restore De&fault View*/254));
848 wxMenu
* presmenu
= new wxMenu
;
849 presmenu
->Append(menu_PRES_NEW
, wmsg(/*&New Presentation*/311));
850 presmenu
->Append(menu_PRES_OPEN
, wmsg(/*&Open Presentation...*/312));
851 presmenu
->Append(menu_PRES_SAVE
, wmsg(/*&Save Presentation*/313));
852 presmenu
->Append(menu_PRES_SAVE_AS
, wmsg(/*Sa&ve Presentation As...*/314));
853 presmenu
->AppendSeparator();
854 /* TRANSLATORS: "Mark" as in "Mark this position" */
855 presmenu
->Append(menu_PRES_MARK
, wmsg(/*&Mark*/315));
856 /* TRANSLATORS: "Play" as in "Play back a recording" */
857 presmenu
->AppendCheckItem(menu_PRES_PLAY
, wmsg(/*Pla&y*/316));
858 presmenu
->Append(menu_PRES_EXPORT_MOVIE
, wmsg(/*&Export as Movie...*/317));
860 wxMenu
* viewmenu
= new wxMenu
;
862 /* TRANSLATORS: Items in the "View" menu: */
863 viewmenu
->AppendCheckItem(menu_VIEW_SHOW_NAMES
, wmsg(/*Station &Names\tCtrl+N*/270));
864 /* TRANSLATORS: Toggles drawing of 3D passages */
865 viewmenu
->AppendCheckItem(menu_VIEW_SHOW_TUBES
, wmsg(/*Passage &Tubes\tCtrl+T*/346));
866 /* TRANSLATORS: Toggles drawing the surface of the Earth */
867 viewmenu
->AppendCheckItem(menu_VIEW_TERRAIN
, wmsg(/*Terr&ain*/449));
868 viewmenu
->AppendCheckItem(menu_VIEW_SHOW_CROSSES
, wmsg(/*&Crosses\tCtrl+X*/271));
869 viewmenu
->AppendCheckItem(menu_VIEW_GRID
, wmsg(/*&Grid\tCtrl+G*/297));
870 viewmenu
->AppendCheckItem(menu_VIEW_BOUNDING_BOX
, wmsg(/*&Bounding Box\tCtrl+B*/318));
871 viewmenu
->AppendSeparator();
872 /* TRANSLATORS: Here a "survey leg" is a set of measurements between two
873 * "survey stations". */
874 viewmenu
->AppendCheckItem(menu_VIEW_SHOW_LEGS
, wmsg(/*&Underground Survey Legs\tCtrl+L*/272));
875 /* TRANSLATORS: Here a "survey leg" is a set of measurements between two
876 * "survey stations". */
877 viewmenu
->AppendCheckItem(menu_VIEW_SHOW_SURFACE
, wmsg(/*&Surface Survey Legs\tCtrl+F*/291));
879 wxMenu
* splaymenu
= new wxMenu
;
880 /* TRANSLATORS: Item in the "Splay Legs" and "Duplicate Legs" submenus - if
881 * this is selected, such legs are not shown. */
882 splaymenu
->AppendCheckItem(menu_SPLAYS_HIDE
, wmsg(/*&Hide*/407));
883 /* TRANSLATORS: Item in the "Splay Legs" and "Duplicate Legs" submenus - if
884 * this is selected, aven will show such legs with dashed lines. */
885 splaymenu
->AppendCheckItem(menu_SPLAYS_SHOW_DASHED
, wmsg(/*&Dashed*/250));
886 /* TRANSLATORS: Item in the "Splay Legs" and "Duplicate Legs" submenus - if
887 * this is selected, aven will show such legs with less bright colours. */
888 splaymenu
->AppendCheckItem(menu_SPLAYS_SHOW_FADED
, wmsg(/*&Fade*/408));
889 /* TRANSLATORS: Item in the "Splay Legs" and "Duplicate Legs" submenus - if
890 * this is selected, such legs are shown the same as other legs. */
891 splaymenu
->AppendCheckItem(menu_SPLAYS_SHOW_NORMAL
, wmsg(/*&Show*/409));
892 viewmenu
->Append(menu_VIEW_SPLAYS
, wmsg(/*Spla&y Legs*/406), splaymenu
);
894 wxMenu
* dupemenu
= new wxMenu
;
895 dupemenu
->AppendCheckItem(menu_DUPES_HIDE
, wmsg(/*&Hide*/407));
896 dupemenu
->AppendCheckItem(menu_DUPES_SHOW_DASHED
, wmsg(/*&Dashed*/250));
897 dupemenu
->AppendCheckItem(menu_DUPES_SHOW_FADED
, wmsg(/*&Fade*/408));
898 dupemenu
->AppendCheckItem(menu_DUPES_SHOW_NORMAL
, wmsg(/*&Show*/409));
899 viewmenu
->Append(menu_VIEW_DUPES
, wmsg(/*&Duplicate Legs*/251), dupemenu
);
901 viewmenu
->AppendSeparator();
902 viewmenu
->AppendCheckItem(menu_VIEW_SHOW_OVERLAPPING_NAMES
, wmsg(/*&Overlapping Names*/273));
904 wxMenu
* colourbymenu
= new wxMenu
;
905 colourbymenu
->AppendCheckItem(menu_COLOUR_BY_DEPTH
, wmsg(/*Colour by &Depth*/292));
906 colourbymenu
->AppendCheckItem(menu_COLOUR_BY_DATE
, wmsg(/*Colour by D&ate*/293));
907 colourbymenu
->AppendCheckItem(menu_COLOUR_BY_ERROR
, wmsg(/*Colour by &Error*/289));
908 colourbymenu
->AppendCheckItem(menu_COLOUR_BY_GRADIENT
, wmsg(/*Colour by &Gradient*/85));
909 colourbymenu
->AppendCheckItem(menu_COLOUR_BY_LENGTH
, wmsg(/*Colour by &Length*/82));
911 viewmenu
->Append(menu_VIEW_COLOUR_BY
, wmsg(/*Co&lour by*/450), colourbymenu
);
913 viewmenu
->AppendSeparator();
914 viewmenu
->AppendCheckItem(menu_VIEW_SHOW_ENTRANCES
, wmsg(/*Highlight &Entrances*/294));
915 viewmenu
->AppendCheckItem(menu_VIEW_SHOW_FIXED_PTS
, wmsg(/*Highlight &Fixed Points*/295));
916 viewmenu
->AppendCheckItem(menu_VIEW_SHOW_EXPORTED_PTS
, wmsg(/*Highlight E&xported Points*/296));
917 viewmenu
->AppendSeparator();
919 /* TRANSLATORS: Please don't translate "Escape" - that's the shortcut key
920 * to use which wxWidgets needs to parse and it should then handle
923 viewmenu
-> Append(menu_VIEW_CANCEL_DIST_LINE
, wmsg(/*&Cancel Measuring Line\tEscape*/281));
925 viewmenu
->AppendCheckItem(menu_VIEW_PERSPECTIVE
, wmsg(/*&Perspective*/237));
926 // FIXME: enable this viewmenu->AppendCheckItem(menu_VIEW_SMOOTH_SHADING, wmsg(/*&Smooth Shading*/?!?);
927 viewmenu
->AppendCheckItem(menu_VIEW_TEXTURED
, wmsg(/*Textured &Walls*/238));
928 /* TRANSLATORS: Toggles OpenGL "Depth Fogging" - feel free to translate
929 * using that term instead if it gives a better translation which most
930 * users will understand. */
931 viewmenu
->AppendCheckItem(menu_VIEW_FOG
, wmsg(/*Fade Distant Ob&jects*/239));
932 /* TRANSLATORS: Here a "survey leg" is a set of measurements between two
933 * "survey stations". */
934 viewmenu
->AppendCheckItem(menu_VIEW_SMOOTH_LINES
, wmsg(/*Smoot&hed Survey Legs*/298));
935 viewmenu
->AppendSeparator();
937 // F11 on OS X is used by the desktop (for speaker volume and/or window
938 // navigation). The standard OS X shortcut for full screen mode is
939 // Ctrl-Command-F which in wxWidgets terms is RawCtrl+Ctrl+F.
940 wxString wxmac_fullscreen
= wmsg(/*Full Screen &Mode\tF11*/356);
941 wxmac_fullscreen
.Replace(wxT("\tF11"), wxT("\tRawCtrl+Ctrl+F"), false);
942 viewmenu
->AppendCheckItem(menu_VIEW_FULLSCREEN
, wxmac_fullscreen
);
943 // FIXME: On OS X, the standard wording here is "Enter Full Screen" and
944 // "Exit Full Screen", depending whether we are in full screen mode or not,
945 // and this isn't a checked menu item.
947 viewmenu
->AppendCheckItem(menu_VIEW_FULLSCREEN
, wmsg(/*Full Screen &Mode\tF11*/356));
950 viewmenu
->AppendSeparator();
951 viewmenu
-> Append(wxID_PREFERENCES
, wmsg(/*&Preferences...*/347));
955 wxMenu
* ctlmenu
= new wxMenu
;
956 ctlmenu
->AppendCheckItem(menu_CTL_REVERSE
, wmsg(/*&Reverse Sense\tCtrl+R*/280));
957 ctlmenu
->AppendSeparator();
959 // wxGTK (at least with GTK+ v2.24), if we specify a short-cut here then
960 // the key handler isn't called, so we can't exit full screen mode on
961 // Escape. wxGTK doesn't actually show the "Escape" shortcut text in the
962 // menu item, so removing it doesn't make any visual difference, and doing
963 // so allows Escape to still cancel the measuring line, but also serve to
964 // exit full screen mode if no measuring line is shown.
965 wxString wxgtk_cancelline
= wmsg(/*&Cancel Measuring Line\tEscape*/281);
966 wxgtk_cancelline
.Replace(wxT("\tEscape"), wxT(""), false);
967 ctlmenu
->Append(menu_CTL_CANCEL_DIST_LINE
, wxgtk_cancelline
);
969 // With wxMac and wxMSW, we can have the short-cut on the menu and still
970 // have Escape handled by the key handler to exit full screen mode.
971 ctlmenu
->Append(menu_CTL_CANCEL_DIST_LINE
, wmsg(/*&Cancel Measuring Line\tEscape*/281));
973 ctlmenu
->AppendSeparator();
974 wxMenu
* indmenu
= new wxMenu
;
975 indmenu
->AppendCheckItem(menu_IND_COMPASS
, wmsg(/*&Compass*/274));
976 indmenu
->AppendCheckItem(menu_IND_CLINO
, wmsg(/*C&linometer*/275));
977 /* TRANSLATORS: The "Colour Key" is the thing in aven showing which colour
978 * corresponds to which depth, date, survey closure error, etc. */
979 indmenu
->AppendCheckItem(menu_IND_COLOUR_KEY
, wmsg(/*Colour &Key*/276));
980 indmenu
->AppendCheckItem(menu_IND_SCALE_BAR
, wmsg(/*&Scale Bar*/277));
981 ctlmenu
->Append(menu_CTL_INDICATORS
, wmsg(/*&Indicators*/299), indmenu
);
982 ctlmenu
->AppendCheckItem(menu_CTL_SIDE_PANEL
, wmsg(/*&Side Panel*/337));
983 ctlmenu
->AppendSeparator();
984 ctlmenu
->AppendCheckItem(menu_CTL_METRIC
, wmsg(/*&Metric*/342));
985 ctlmenu
->AppendCheckItem(menu_CTL_DEGREES
, wmsg(/*&Degrees*/343));
986 ctlmenu
->AppendCheckItem(menu_CTL_PERCENT
, wmsg(/*&Percent*/430));
989 wxMenuBar
* menubar
= new wxMenuBar();
990 /* TRANSLATORS: Aven menu titles. An “&” goes before the letter of any
991 * accelerator key. The accelerators must be different within this group
993 menubar
->Append(filemenu
, wmsg(/*&File*/210));
994 menubar
->Append(rotmenu
, wmsg(/*&Rotation*/211));
995 menubar
->Append(orientmenu
, wmsg(/*&Orientation*/212));
996 menubar
->Append(viewmenu
, wmsg(/*&View*/213));
998 menubar
->Append(ctlmenu
, wmsg(/*&Controls*/214));
1000 // TRANSLATORS: "Presentation" in the sense of a talk with a slideshow -
1001 // the items in this menu allow the user to animate between preset
1003 menubar
->Append(presmenu
, wmsg(/*&Presentation*/216));
1005 // On wxMac the "About" menu item will be moved elsewhere, so we suppress
1006 // this menu since it will then be empty.
1007 wxMenu
* helpmenu
= new wxMenu
;
1008 helpmenu
->Append(wxID_ABOUT
);
1010 menubar
->Append(helpmenu
, wmsg(/*&Help*/215));
1012 SetMenuBar(menubar
);
1015 void MainFrm::MakeToolBar()
1017 // Make the toolbar.
1019 #ifdef USING_GENERIC_TOOLBAR
1020 // This OS-X-specific code is only needed to stop the toolbar icons getting
1021 // scaled up, which just makes them look nasty and fuzzy. Once we have
1022 // larger versions of the icons, we can drop this code.
1023 wxSystemOptions::SetOption(wxT("mac.toolbar.no-native"), 1);
1024 wxToolBar
* toolbar
= new wxToolBar(this, wxID_ANY
, wxDefaultPosition
,
1025 wxDefaultSize
, wxNO_BORDER
|wxTB_FLAT
|wxTB_NODIVIDER
|wxTB_NOALIGN
);
1026 wxBoxSizer
* sizer
= new wxBoxSizer(wxVERTICAL
);
1027 sizer
->Add(toolbar
, 0, wxEXPAND
);
1030 wxToolBar
* toolbar
= wxFrame::CreateToolBar();
1034 toolbar
->SetMargins(5, 5);
1037 // FIXME: TRANSLATE tooltips
1038 toolbar
->AddTool(wxID_OPEN
, wxT("Open"), TOOL(open
), wxT("Open a survey file for viewing"));
1039 toolbar
->AddTool(menu_PRES_OPEN
, wxT("Open presentation"), TOOL(open_pres
), wxT("Open a presentation"));
1040 toolbar
->AddCheckTool(menu_FILE_LOG
, wxT("View log"), TOOL(log
), wxNullBitmap
, wxT("View log from processing survey data"));
1041 toolbar
->AddSeparator();
1042 toolbar
->AddCheckTool(menu_ROTATION_TOGGLE
, wxT("Toggle rotation"), TOOL(rotation
), wxNullBitmap
, wxT("Toggle rotation"));
1043 toolbar
->AddTool(menu_ORIENT_PLAN
, wxT("Plan"), TOOL(plan
), wxT("Switch to plan view"));
1044 toolbar
->AddTool(menu_ORIENT_ELEVATION
, wxT("Elevation"), TOOL(elevation
), wxT("Switch to elevation view"));
1045 toolbar
->AddTool(menu_ORIENT_DEFAULTS
, wxT("Default view"), TOOL(defaults
), wxT("Restore default view"));
1046 toolbar
->AddSeparator();
1047 toolbar
->AddCheckTool(menu_VIEW_SHOW_NAMES
, wxT("Names"), TOOL(names
), wxNullBitmap
, wxT("Show station names"));
1048 toolbar
->AddCheckTool(menu_VIEW_SHOW_CROSSES
, wxT("Crosses"), TOOL(crosses
), wxNullBitmap
, wxT("Show crosses on stations"));
1049 toolbar
->AddCheckTool(menu_VIEW_SHOW_ENTRANCES
, wxT("Entrances"), TOOL(entrances
), wxNullBitmap
, wxT("Highlight entrances"));
1050 toolbar
->AddCheckTool(menu_VIEW_SHOW_FIXED_PTS
, wxT("Fixed points"), TOOL(fixed_pts
), wxNullBitmap
, wxT("Highlight fixed points"));
1051 toolbar
->AddCheckTool(menu_VIEW_SHOW_EXPORTED_PTS
, wxT("Exported points"), TOOL(exported_pts
), wxNullBitmap
, wxT("Highlight exported stations"));
1052 toolbar
->AddSeparator();
1053 toolbar
->AddCheckTool(menu_VIEW_SHOW_LEGS
, wxT("Underground legs"), TOOL(ug_legs
), wxNullBitmap
, wxT("Show underground surveys"));
1054 toolbar
->AddCheckTool(menu_VIEW_SHOW_SURFACE
, wxT("Surface legs"), TOOL(surface_legs
), wxNullBitmap
, wxT("Show surface surveys"));
1055 toolbar
->AddCheckTool(menu_VIEW_SHOW_TUBES
, wxT("Tubes"), TOOL(tubes
), wxNullBitmap
, wxT("Show passage tubes"));
1056 toolbar
->AddCheckTool(menu_VIEW_TERRAIN
, wxT("Terrain"), TOOL(solid_surface
), wxNullBitmap
, wxT("Show terrain"));
1057 toolbar
->AddSeparator();
1058 toolbar
->AddCheckTool(menu_PRES_FREWIND
, wxT("Fast Rewind"), TOOL(pres_frew
), wxNullBitmap
, wxT("Very Fast Rewind"));
1059 toolbar
->AddCheckTool(menu_PRES_REWIND
, wxT("Rewind"), TOOL(pres_rew
), wxNullBitmap
, wxT("Fast Rewind"));
1060 toolbar
->AddCheckTool(menu_PRES_REVERSE
, wxT("Backwards"), TOOL(pres_go_back
), wxNullBitmap
, wxT("Play Backwards"));
1061 toolbar
->AddCheckTool(menu_PRES_PAUSE
, wxT("Pause"), TOOL(pres_pause
), wxNullBitmap
, wxT("Pause"));
1062 toolbar
->AddCheckTool(menu_PRES_PLAY
, wxT("Go"), TOOL(pres_go
), wxNullBitmap
, wxT("Play"));
1063 toolbar
->AddCheckTool(menu_PRES_FF
, wxT("FF"), TOOL(pres_ff
), wxNullBitmap
, wxT("Fast Forward"));
1064 toolbar
->AddCheckTool(menu_PRES_FFF
, wxT("Very FF"), TOOL(pres_fff
), wxNullBitmap
, wxT("Very Fast Forward"));
1065 toolbar
->AddTool(wxID_STOP
, wxT("Stop"), TOOL(pres_stop
), wxT("Stop"));
1067 toolbar
->AddSeparator();
1068 m_FindBox
= new wxTextCtrl(toolbar
, textctrl_FIND
, wxString(), wxDefaultPosition
,
1069 wxDefaultSize
, wxTE_PROCESS_ENTER
);
1070 toolbar
->AddControl(m_FindBox
);
1071 /* TRANSLATORS: "Find stations" button tooltip */
1072 toolbar
->AddTool(wxID_FIND
, wmsg(/*Find*/332), TOOL(find
)/*, "Search for station name"*/);
1073 /* TRANSLATORS: "Hide stations" button default tooltip */
1074 toolbar
->AddTool(button_HIDE
, wmsg(/*Hide*/333), TOOL(hideresults
)/*, "Hide search results"*/);
1079 void MainFrm::CreateSidePanel()
1081 m_Splitter
= new AvenSplitterWindow(this);
1082 #ifdef USING_GENERIC_TOOLBAR
1083 // This OS-X-specific code is only needed to stop the toolbar icons getting
1084 // scaled up, which just makes them look nasty and fuzzy. Once we have
1085 // larger versions of the icons, we can drop this code.
1086 GetSizer()->Add(m_Splitter
, 1, wxEXPAND
);
1090 m_Notebook
= new wxNotebook(m_Splitter
, 400, wxDefaultPosition
,
1092 wxBK_BOTTOM
| wxBK_LEFT
);
1093 m_Notebook
->Show(false);
1095 wxPanel
* panel
= new wxPanel(m_Notebook
);
1096 m_Tree
= new AvenTreeCtrl(this, panel
);
1098 // m_RegexpCheckBox = new wxCheckBox(find_panel, -1,
1099 // msg(/*Regular expression*/));
1101 wxBoxSizer
*panel_sizer
= new wxBoxSizer(wxVERTICAL
);
1102 panel_sizer
->Add(m_Tree
, 1, wxALL
| wxEXPAND
, 2);
1103 panel
->SetAutoLayout(true);
1104 panel
->SetSizer(panel_sizer
);
1105 // panel_sizer->SetSizeHints(panel);
1107 m_Control
= new GUIControl();
1108 m_Gfx
= new GfxCore(this, m_Splitter
, m_Control
);
1109 m_Control
->SetView(m_Gfx
);
1111 // Presentation panel:
1112 wxPanel
* prespanel
= new wxPanel(m_Notebook
);
1114 m_PresList
= new AvenPresList(this, prespanel
, m_Gfx
);
1116 wxBoxSizer
*pres_panel_sizer
= new wxBoxSizer(wxVERTICAL
);
1117 pres_panel_sizer
->Add(m_PresList
, 1, wxALL
| wxEXPAND
, 2);
1118 prespanel
->SetAutoLayout(true);
1119 prespanel
->SetSizer(pres_panel_sizer
);
1121 // Overall tabbed structure:
1122 // FIXME: this assumes images are 15x15
1123 wxImageList
* image_list
= new wxImageList(15, 15);
1124 image_list
->Add(TOOL(survey_tree
));
1125 image_list
->Add(TOOL(pres_tree
));
1126 m_Notebook
->SetImageList(image_list
);
1127 /* TRANSLATORS: labels for tabbed side panel this is for the tab with the
1128 * tree hierarchy of survey station names */
1129 m_Notebook
->AddPage(panel
, wmsg(/*Surveys*/376), true, 0);
1130 m_Notebook
->AddPage(prespanel
, wmsg(/*Presentation*/377), false, 1);
1132 m_Splitter
->Initialize(m_Gfx
);
1135 bool MainFrm::LoadData(const wxString
& file
, const wxString
& prefix
)
1137 // Load survey data from file, centre the dataset around the origin,
1138 // and prepare the data for drawing.
1145 // Load the processed survey data.
1146 img
* survey
= img_open_survey(file
.utf8_str(), prefix
.utf8_str());
1148 wxString m
= wxString::Format(wmsg(img_error2msg(img_error())), file
.c_str());
1149 wxGetApp().ReportError(m
);
1153 m_IsExtendedElevation
= survey
->is_extended_elevation
;
1155 m_Tree
->DeleteAllItems();
1157 // Create a list of all the leg vertices, counting them and finding the
1158 // extent of the survey at the same time.
1161 m_NumExportedPts
= 0;
1163 m_HasUndergroundLegs
= false;
1164 m_HasSplays
= false;
1166 m_HasSurfaceLegs
= false;
1167 m_HasErrorInformation
= false;
1169 // FIXME: discard existing presentation? ask user about saving if we do!
1171 // Delete any existing list entries.
1174 Double xmin
= DBL_MAX
;
1175 Double xmax
= -DBL_MAX
;
1176 Double ymin
= DBL_MAX
;
1177 Double ymax
= -DBL_MAX
;
1178 Double zmin
= DBL_MAX
;
1179 Double zmax
= -DBL_MAX
;
1181 m_DepthMin
= DBL_MAX
;
1182 Double depthmax
= -DBL_MAX
;
1184 m_DateMin
= INT_MAX
;
1186 complete_dateinfo
= true;
1188 for (unsigned f
= 0; f
!= sizeof(traverses
) / sizeof(traverses
[0]); ++f
) {
1189 traverses
[f
].clear();
1193 // Ultimately we probably want different types (subclasses perhaps?) for
1194 // underground and surface data, so we don't need to store LRUD for surface
1196 traverse
* current_traverse
= NULL
;
1197 vector
<XSect
> * current_tube
= NULL
;
1199 map
<wxString
, LabelInfo
*> labelmap
;
1200 list
<LabelInfo
*>::const_iterator last_mapped_label
= m_Labels
.begin();
1203 img_point prev_pt
= {0,0,0};
1204 bool current_polyline_is_surface
= false;
1205 int current_flags
= 0;
1206 bool pending_move
= false;
1207 // When legs within a traverse have different surface/splay/duplicate
1208 // flags, we split it into contiguous traverses of each flag combination,
1209 // but we need to track these so we can assign the error statistics to all
1210 // of them. So we keep counts of how many of each combination we've
1211 // generated for the current traverse.
1212 size_t n_traverses
[8];
1213 memset(n_traverses
, 0, sizeof(n_traverses
));
1216 if (++items
% 200 == 0) {
1217 long pos
= ftell(survey
->fh
);
1218 int progress
= int((double(pos
) / double(file_size
)) * 100.0);
1219 // SetProgress(progress);
1224 result
= img_read_item(survey
, &pt
);
1227 memset(n_traverses
, 0, sizeof(n_traverses
));
1228 pending_move
= true;
1233 // Update survey extents.
1234 if (pt
.x
< xmin
) xmin
= pt
.x
;
1235 if (pt
.x
> xmax
) xmax
= pt
.x
;
1236 if (pt
.y
< ymin
) ymin
= pt
.y
;
1237 if (pt
.y
> ymax
) ymax
= pt
.y
;
1238 if (pt
.z
< zmin
) zmin
= pt
.z
;
1239 if (pt
.z
> zmax
) zmax
= pt
.z
;
1241 int date
= survey
->days1
;
1243 date
+= (survey
->days2
- date
) / 2;
1244 if (date
< m_DateMin
) m_DateMin
= date
;
1245 if (date
> datemax
) datemax
= date
;
1247 complete_dateinfo
= false;
1250 int flags
= survey
->flags
&
1251 (img_FLAG_SURFACE
|img_FLAG_SPLAY
|img_FLAG_DUPLICATE
);
1252 bool is_surface
= (flags
& img_FLAG_SURFACE
);
1253 bool is_splay
= (flags
& img_FLAG_SPLAY
);
1254 bool is_dupe
= (flags
& img_FLAG_DUPLICATE
);
1257 if (pt
.z
< m_DepthMin
) m_DepthMin
= pt
.z
;
1258 if (pt
.z
> depthmax
) depthmax
= pt
.z
;
1265 current_flags
!= flags
) {
1266 if (!current_polyline_is_surface
&& current_traverse
) {
1267 //FixLRUD(*current_traverse);
1270 ++n_traverses
[flags
];
1271 // Start new traverse (surface or underground).
1273 m_HasSurfaceLegs
= true;
1275 m_HasUndergroundLegs
= true;
1276 // The previous point was at a surface->ug transition.
1277 if (current_polyline_is_surface
) {
1278 if (prev_pt
.z
< m_DepthMin
) m_DepthMin
= prev_pt
.z
;
1279 if (prev_pt
.z
> depthmax
) depthmax
= prev_pt
.z
;
1282 traverses
[flags
].push_back(traverse());
1283 current_traverse
= &traverses
[flags
].back();
1284 current_traverse
->flags
= survey
->flags
;
1286 current_polyline_is_surface
= is_surface
;
1287 current_flags
= flags
;
1290 // Update survey extents. We only need to do this if
1291 // there's a pending move, since for a surface <->
1292 // underground transition, we'll already have handled
1294 if (prev_pt
.x
< xmin
) xmin
= prev_pt
.x
;
1295 if (prev_pt
.x
> xmax
) xmax
= prev_pt
.x
;
1296 if (prev_pt
.y
< ymin
) ymin
= prev_pt
.y
;
1297 if (prev_pt
.y
> ymax
) ymax
= prev_pt
.y
;
1298 if (prev_pt
.z
< zmin
) zmin
= prev_pt
.z
;
1299 if (prev_pt
.z
> zmax
) zmax
= prev_pt
.z
;
1302 current_traverse
->push_back(PointInfo(prev_pt
));
1305 current_traverse
->push_back(PointInfo(pt
, date
));
1308 pending_move
= false;
1313 wxString
s(survey
->label
, wxConvUTF8
);
1315 // If label isn't valid UTF-8 then this conversion will
1316 // give an empty string. In this case, assume that the
1317 // label is CP1252 (the Microsoft superset of ISO8859-1).
1318 static wxCSConv
ConvCP1252(wxFONTENCODING_CP1252
);
1319 s
= wxString(survey
->label
, ConvCP1252
);
1321 // Or if that doesn't work (ConvCP1252 doesn't like
1322 // strings with some bytes in) let's just go for
1324 s
= wxString(survey
->label
, wxConvISO8859_1
);
1327 int flags
= img2aven(survey
->flags
);
1328 LabelInfo
* label
= new LabelInfo(pt
, s
, flags
);
1329 if (label
->IsEntrance()) {
1332 if (label
->IsFixedPt()) {
1335 if (label
->IsExportedPt()) {
1338 m_Labels
.push_back(label
);
1343 if (!current_tube
) {
1344 // Start new current_tube.
1345 tubes
.push_back(vector
<XSect
>());
1346 current_tube
= &tubes
.back();
1350 wxString
label(survey
->label
, wxConvUTF8
);
1351 map
<wxString
, LabelInfo
*>::const_iterator p
;
1352 p
= labelmap
.find(label
);
1353 if (p
!= labelmap
.end()) {
1356 // Initialise labelmap lazily - we may have no
1358 list
<LabelInfo
*>::const_iterator i
;
1359 if (labelmap
.empty()) {
1360 i
= m_Labels
.begin();
1362 i
= last_mapped_label
;
1365 while (i
!= m_Labels
.end() && (*i
)->GetText() != label
) {
1366 labelmap
[(*i
)->GetText()] = *i
;
1369 last_mapped_label
= i
;
1370 if (i
== m_Labels
.end()) {
1371 // Unattached cross-section - ignore for now.
1372 printf("unattached cross-section\n");
1373 if (current_tube
->size() <= 1)
1374 tubes
.resize(tubes
.size() - 1);
1375 current_tube
= NULL
;
1376 if (!m_Labels
.empty())
1377 --last_mapped_label
;
1381 labelmap
[label
] = lab
;
1384 int date
= survey
->days1
;
1386 date
+= (survey
->days2
- date
) / 2;
1387 if (date
< m_DateMin
) m_DateMin
= date
;
1388 if (date
> datemax
) datemax
= date
;
1391 current_tube
->push_back(XSect(*lab
, date
, survey
->l
, survey
->r
, survey
->u
, survey
->d
));
1396 // Finish off current_tube.
1397 // If there's only one cross-section in the tube, just
1398 // discard it for now. FIXME: we should handle this
1399 // when we come to skinning the tubes.
1400 if (current_tube
&& current_tube
->size() <= 1)
1401 tubes
.resize(tubes
.size() - 1);
1402 current_tube
= NULL
;
1405 case img_ERROR_INFO
: {
1406 if (survey
->E
== 0.0) {
1407 // Currently cavern doesn't spot all articulating traverses
1408 // so we assume that any traverse with no error isn't part
1409 // of a loop. FIXME: fix cavern!
1412 m_HasErrorInformation
= true;
1413 for (size_t f
= 0; f
!= sizeof(traverses
) / sizeof(traverses
[0]); ++f
) {
1414 list
<traverse
>::reverse_iterator t
= traverses
[f
].rbegin();
1415 size_t n
= n_traverses
[f
];
1418 assert(t
!= traverses
[f
].rend());
1419 t
->n_legs
= survey
->n_legs
;
1420 t
->length
= survey
->length
;
1434 // FIXME: Do we need to reset all these? - Olly
1436 m_NumExportedPts
= 0;
1438 m_HasUndergroundLegs
= false;
1439 m_HasSplays
= false;
1440 m_HasSurfaceLegs
= false;
1444 wxString m
= wxString::Format(wmsg(img_error2msg(img_error())), file
.c_str());
1445 wxGetApp().ReportError(m
);
1453 } while (result
!= img_STOP
);
1455 if (!current_polyline_is_surface
&& current_traverse
) {
1456 //FixLRUD(*current_traverse);
1459 // Finish off current_tube.
1460 // If there's only one cross-section in the tube, just
1461 // discard it for now. FIXME: we should handle this
1462 // when we come to skinning the tubes.
1463 if (current_tube
&& current_tube
->size() <= 1)
1464 tubes
.resize(tubes
.size() - 1);
1466 separator
= survey
->separator
;
1467 m_Title
= wxString(survey
->title
, wxConvUTF8
);
1468 m_DateStamp_numeric
= survey
->datestamp_numeric
;
1470 m_cs_proj
= wxString(survey
->cs
, wxConvUTF8
);
1472 m_cs_proj
= wxString();
1474 if (strcmp(survey
->datestamp
, "?") == 0) {
1475 /* TRANSLATORS: used a processed survey with no processing date/time info */
1476 m_DateStamp
= wmsg(/*Date and time not available.*/108);
1477 } else if (survey
->datestamp
[0] == '@') {
1478 const struct tm
* tm
= localtime(&m_DateStamp_numeric
);
1480 /* TRANSLATORS: This is the date format string used to timestamp .3d
1481 * files internally. Probably best to keep it the same for all
1483 strftime(buf
, 256, msg(/*%a,%Y.%m.%d %H:%M:%S %Z*/107), tm
);
1484 m_DateStamp
= wxString(buf
, wxConvUTF8
);
1486 if (m_DateStamp
.empty()) {
1487 m_DateStamp
= wxString(survey
->datestamp
, wxConvUTF8
);
1491 // Check we've actually loaded some legs or stations!
1492 if (!m_HasUndergroundLegs
&& !m_HasSurfaceLegs
&& m_Labels
.empty()) {
1493 wxString m
= wxString::Format(wmsg(/*No survey data in 3d file “%s”*/202), file
.c_str());
1494 wxGetApp().ReportError(m
);
1498 if (traverses
[0].empty() &&
1499 traverses
[1].empty() &&
1500 traverses
[2].empty() &&
1501 traverses
[3].empty() &&
1502 traverses
[4].empty() &&
1503 traverses
[5].empty() &&
1504 traverses
[6].empty() &&
1505 traverses
[7].empty()) {
1506 // No legs, so get survey extents from stations
1507 list
<LabelInfo
*>::const_iterator i
;
1508 for (i
= m_Labels
.begin(); i
!= m_Labels
.end(); ++i
) {
1509 if ((*i
)->GetX() < xmin
) xmin
= (*i
)->GetX();
1510 if ((*i
)->GetX() > xmax
) xmax
= (*i
)->GetX();
1511 if ((*i
)->GetY() < ymin
) ymin
= (*i
)->GetY();
1512 if ((*i
)->GetY() > ymax
) ymax
= (*i
)->GetY();
1513 if ((*i
)->GetZ() < zmin
) zmin
= (*i
)->GetZ();
1514 if ((*i
)->GetZ() > zmax
) zmax
= (*i
)->GetZ();
1518 m_Ext
.assign(xmax
- xmin
, ymax
- ymin
, zmax
- zmin
);
1520 if (datemax
< m_DateMin
) m_DateMin
= datemax
;
1521 m_DateExt
= datemax
- m_DateMin
;
1523 // Centre the dataset around the origin.
1524 CentreDataset(Vector3(xmin
, ymin
, zmin
));
1526 if (depthmax
< m_DepthMin
) {
1530 m_DepthExt
= depthmax
- m_DepthMin
;
1531 m_DepthMin
-= m_Offsets
.GetZ();
1535 printf("time to load = %.3f\n", (double)timer
.Time());
1538 // Update window title.
1539 SetTitle(m_Title
+ " - " APP_NAME
);
1541 // Sort the labels ready for filling the tree.
1542 m_Labels
.sort(LabelCmp(separator
));
1544 // Fill the tree of stations and prefixes.
1545 wxString root_name
= wxFileNameFromPath(file
);
1546 if (!prefix
.empty()) {
1548 root_name
+= prefix
;
1551 FillTree(root_name
);
1553 // Sort labels so that entrances are displayed in preference,
1554 // then fixed points, then exported points, then other points.
1556 // Also sort by leaf name so that we'll tend to choose labels
1557 // from different surveys, rather than labels from surveys which
1558 // are earlier in the list.
1559 m_Labels
.sort(LabelPlotCmp(separator
));
1561 if (!m_FindBox
->GetValue().empty()) {
1562 // Highlight any stations matching the current search.
1566 m_FileProcessed
= file
;
1572 // Run along a newly read in traverse and make up plausible LRUD where
1575 MainFrm::FixLRUD(traverse
& centreline
)
1577 assert(centreline
.size() > 1);
1579 Double last_size
= 0;
1580 vector
<PointInfo
>::iterator i
= centreline
.begin();
1581 while (i
!= centreline
.end()) {
1582 // Get the coordinates of this vertex.
1583 Point
& pt_v
= *i
++;
1586 if (i
!= centreline
.end()) {
1587 Double h
= sqrd(i
->GetX() - pt_v
.GetX()) +
1588 sqrd(i
->GetY() - pt_v
.GetY());
1589 Double v
= sqrd(i
->GetZ() - pt_v
.GetZ());
1590 if (h
+ v
> 30.0 * 30.0) {
1591 Double scale
= 30.0 / sqrt(h
+ v
);
1595 size
= sqrt(h
+ v
/ 9);
1597 if (i
== centreline
.begin() + 1) {
1601 // Intermediate segment.
1602 swap(size
, last_size
);
1611 Double
& l
= pt_v
.l
;
1612 Double
& r
= pt_v
.r
;
1613 Double
& u
= pt_v
.u
;
1614 Double
& d
= pt_v
.d
;
1616 if (l
== 0 && r
== 0 && u
== 0 && d
== 0) {
1617 l
= r
= u
= d
= -size
;
1619 if (l
< 0 && r
< 0) {
1622 l
= -(2 * size
- r
);
1623 if (l
>= 0) l
= -0.01;
1625 r
= -(2 * size
- l
);
1626 if (r
>= 0) r
= -0.01;
1628 if (u
< 0 && d
< 0) {
1631 u
= -(2 * size
- d
);
1632 if (u
>= 0) u
= -0.01;
1634 d
= -(2 * size
- u
);
1635 if (d
>= 0) d
= -0.01;
1642 void MainFrm::FillTree(const wxString
& root_name
)
1644 // Create the root of the tree.
1645 wxTreeItemId treeroot
= m_Tree
->AddRoot(root_name
);
1647 // Fill the tree of stations and prefixes.
1648 stack
<wxTreeItemId
> previous_ids
;
1649 wxString current_prefix
;
1650 wxTreeItemId current_id
= treeroot
;
1652 list
<LabelInfo
*>::iterator pos
= m_Labels
.begin();
1653 while (pos
!= m_Labels
.end()) {
1654 LabelInfo
* label
= *pos
++;
1656 if (label
->IsAnon()) continue;
1658 // Determine the current prefix.
1659 wxString prefix
= label
->GetText().BeforeLast(separator
);
1661 // Determine if we're still on the same prefix.
1662 if (prefix
== current_prefix
) {
1663 // no need to fiddle with branches...
1665 // If not, then see if we've descended to a new prefix.
1666 else if (prefix
.length() > current_prefix
.length() &&
1667 prefix
.StartsWith(current_prefix
) &&
1668 (prefix
[current_prefix
.length()] == separator
||
1669 current_prefix
.empty())) {
1670 // We have, so start as many new branches as required.
1671 int current_prefix_length
= current_prefix
.length();
1672 current_prefix
= prefix
;
1673 size_t next_dot
= current_prefix_length
;
1674 if (!next_dot
) --next_dot
;
1676 size_t prev_dot
= next_dot
+ 1;
1678 // Extract the next bit of prefix.
1679 next_dot
= prefix
.find(separator
, prev_dot
+ 1);
1681 wxString bit
= prefix
.substr(prev_dot
, next_dot
- prev_dot
);
1682 assert(!bit
.empty());
1684 // Add the current tree ID to the stack.
1685 previous_ids
.push(current_id
);
1687 // Append the new item to the tree and set this as the current branch.
1688 current_id
= m_Tree
->AppendItem(current_id
, bit
);
1689 m_Tree
->SetItemData(current_id
, new TreeData(prefix
.substr(0, next_dot
)));
1690 } while (next_dot
!= wxString::npos
);
1692 // Otherwise, we must have moved up, and possibly then down again.
1695 bool ascent_only
= (prefix
.length() < current_prefix
.length() &&
1696 current_prefix
.StartsWith(prefix
) &&
1697 (current_prefix
[prefix
.length()] == separator
||
1700 // Find out how much of the current prefix and the new prefix
1702 // Note that we require a match of a whole number of parts
1704 size_t n
= min(prefix
.length(), current_prefix
.length());
1706 for (i
= 0; i
< n
&& prefix
[i
] == current_prefix
[i
]; ++i
) {
1707 if (prefix
[i
] == separator
) count
= i
+ 1;
1710 count
= prefix
.length() + 1;
1713 // Extract the part of the current prefix after the bit (if any)
1714 // which has matched.
1715 // This gives the prefixes to ascend over.
1716 wxString prefixes_ascended
= current_prefix
.substr(count
);
1718 // Count the number of prefixes to ascend over.
1719 int num_prefixes
= prefixes_ascended
.Freq(separator
);
1721 // Reverse up over these prefixes.
1722 for (int i
= 1; i
<= num_prefixes
; i
++) {
1725 current_id
= previous_ids
.top();
1729 // Add branches for this new part.
1730 size_t next_dot
= count
- 1;
1732 size_t prev_dot
= next_dot
+ 1;
1734 // Extract the next bit of prefix.
1735 next_dot
= prefix
.find(separator
, prev_dot
+ 1);
1737 wxString bit
= prefix
.substr(prev_dot
, next_dot
- prev_dot
);
1738 assert(!bit
.empty());
1740 // Add the current tree ID to the stack.
1741 previous_ids
.push(current_id
);
1743 // Append the new item to the tree and set this as the current branch.
1744 current_id
= m_Tree
->AppendItem(current_id
, bit
);
1745 m_Tree
->SetItemData(current_id
, new TreeData(prefix
.substr(0, next_dot
)));
1746 } while (next_dot
!= wxString::npos
);
1749 current_prefix
= prefix
;
1752 // Now add the leaf.
1753 wxString bit
= label
->GetText().AfterLast(separator
);
1754 assert(!bit
.empty());
1755 wxTreeItemId id
= m_Tree
->AppendItem(current_id
, bit
);
1756 m_Tree
->SetItemData(id
, new TreeData(label
));
1757 label
->tree_id
= id
;
1758 // Set the colour for an item in the survey tree.
1759 if (label
->IsEntrance()) {
1760 // Entrances are green (like entrance blobs).
1761 m_Tree
->SetItemTextColour(id
, wxColour(0, 255, 40));
1762 } else if (label
->IsSurface()) {
1763 // Surface stations are dark green.
1764 m_Tree
->SetItemTextColour(id
, wxColour(49, 158, 79));
1768 m_Tree
->Expand(treeroot
);
1769 m_Tree
->SetEnabled();
1772 void MainFrm::CentreDataset(const Vector3
& vmin
)
1774 // Centre the dataset around the origin.
1776 m_Offsets
= vmin
+ (m_Ext
* 0.5);
1778 for (unsigned f
= 0; f
!= sizeof(traverses
) / sizeof(traverses
[0]); ++f
) {
1779 list
<traverse
>::iterator t
= traverses
[f
].begin();
1780 while (t
!= traverses
[f
].end()) {
1781 assert(t
->size() > 1);
1782 vector
<PointInfo
>::iterator pos
= t
->begin();
1783 while (pos
!= t
->end()) {
1784 Point
& point
= *pos
++;
1791 list
<vector
<XSect
> >::iterator i
= tubes
.begin();
1792 while (i
!= tubes
.end()) {
1793 assert(i
->size() > 1);
1794 vector
<XSect
>::iterator pos
= i
->begin();
1795 while (pos
!= i
->end()) {
1796 Point
& point
= *pos
++;
1802 list
<LabelInfo
*>::iterator lpos
= m_Labels
.begin();
1803 while (lpos
!= m_Labels
.end()) {
1804 Point
& point
= **lpos
++;
1809 void MainFrm::OnMRUFile(wxCommandEvent
& event
)
1811 wxString
f(m_history
.GetHistoryFile(event
.GetId() - wxID_FILE1
));
1812 if (!f
.empty()) OpenFile(f
);
1815 void MainFrm::AddToFileHistory(const wxString
& file
)
1817 if (wxIsAbsolutePath(file
)) {
1818 m_history
.AddFileToHistory(file
);
1820 wxString abs
= wxGetCwd();
1821 abs
+= wxCONFIG_PATH_SEPARATOR
;
1823 m_history
.AddFileToHistory(abs
);
1825 wxConfigBase
*b
= wxConfigBase::Get();
1830 void MainFrm::OpenFile(const wxString
& file
, const wxString
& survey
)
1832 wxBusyCursor hourglass
;
1834 // Check if this is an unprocessed survey data file.
1835 if (file
.length() > 4 && file
[file
.length() - 4] == '.') {
1836 wxString
ext(file
, file
.length() - 3, 3);
1838 if (ext
== wxT("svx") || ext
== wxT("dat") || ext
== wxT("mak")) {
1839 CavernLogWindow
* log
= new CavernLogWindow(this, survey
, m_Splitter
);
1840 wxWindow
* win
= m_Splitter
->GetWindow1();
1841 m_Splitter
->ReplaceWindow(win
, log
);
1843 if (m_Splitter
->GetWindow2() == NULL
) {
1844 if (win
!= m_Gfx
) win
->Destroy();
1846 if (m_Splitter
->IsSplit()) m_Splitter
->Unsplit();
1849 if (wxFileExists(file
)) AddToFileHistory(file
);
1851 // Log window will tell us to load file if it successfully completes.
1856 if (!LoadData(file
, survey
))
1858 AddToFileHistory(file
);
1859 InitialiseAfterLoad(file
, survey
);
1861 // If aven is showing the log for a .svx file and you load a .3d file, then
1862 // at this point m_Log will be the log window for the .svx file, so destroy
1863 // it - it should never legitimately be set if we get here.
1870 void MainFrm::InitialiseAfterLoad(const wxString
& file
, const wxString
& prefix
)
1872 if (m_SashPosition
< 0) {
1873 // Calculate sane default width for side panel.
1876 GetClientSize(&x
, &y
);
1886 // Do this before we potentially delete the log window which may own the
1887 // wxString which parameter file refers to!
1888 bool same_file
= (file
== m_File
);
1893 wxWindow
* win
= NULL
;
1894 if (m_Splitter
->GetWindow2() == NULL
) {
1895 win
= m_Splitter
->GetWindow1();
1896 if (win
== m_Gfx
) win
= NULL
;
1899 if (!IsFullScreen()) {
1900 m_Splitter
->SplitVertically(m_Notebook
, m_Gfx
, m_SashPosition
);
1902 was_showing_sidepanel_before_fullscreen
= true;
1905 m_Gfx
->Initialise(same_file
);
1908 // FIXME: check it actually is the log window!
1909 if (m_Log
&& m_Log
!= win
)
1915 if (!IsFullScreen()) {
1916 m_Notebook
->Show(true);
1923 void MainFrm::HideLog(wxWindow
* log_window
)
1925 if (!IsFullScreen()) {
1926 m_Splitter
->SplitVertically(m_Notebook
, m_Gfx
, m_SashPosition
);
1932 if (!IsFullScreen()) {
1933 m_Notebook
->Show(true);
1941 // UI event handlers
1944 // For Unix we want "*.svx;*.SVX" while for Windows we only want "*.svx".
1948 # define CASE(X) ";" X
1951 void MainFrm::OnOpen(wxCommandEvent
&)
1953 AvenAllowOnTop
ontop(this);
1955 wxString filetypes
= wxT("*.3d");
1958 filetypes
.Printf(wxT("%s|*.3d;*.svx;*.plt;*.plf;*.dat;*.mak;*.adj;*.sht;*.una;*.xyz"
1959 CASE("*.3D;*.SVX;*.PLT;*.PLF;*.DAT;*.MAK;*.ADJ;*.SHT;*.UNA;*.XYZ")
1960 "|%s|*.3d" CASE("*.3D")
1961 "|%s|*.svx" CASE("*.SVX")
1962 "|%s|*.plt;*.plf" CASE("*.PLT;*.PLF")
1963 "|%s|*.dat;*.mak" CASE("*.DAT;*.MAK")
1964 "|%s|*.adj;*.sht;*.una;*.xyz" CASE("*.ADJ;*.SHT;*.UNA;*.XYZ")
1966 /* TRANSLATORS: Here "survey" is a "cave map" rather than
1967 * list of questions - it should be translated to the
1968 * terminology that cavers using the language would use.
1970 wmsg(/*All survey files*/229).c_str(),
1971 /* TRANSLATORS: Survex is the name of the software, and "3d" refers to a
1972 * file extension, so neither should be translated. */
1973 wmsg(/*Survex 3d files*/207).c_str(),
1974 /* TRANSLATORS: Survex is the name of the software, and "svx" refers to a
1975 * file extension, so neither should be translated. */
1976 wmsg(/*Survex svx files*/329).c_str(),
1977 /* TRANSLATORS: "Compass" as in Larry Fish’s cave
1978 * surveying package, so probably shouldn’t be translated
1980 wmsg(/*Compass PLT files*/324).c_str(),
1981 /* TRANSLATORS: "Compass" as in Larry Fish’s cave
1982 * surveying package, so should not be translated
1984 wmsg(/*Compass DAT and MAK files*/330).c_str(),
1985 /* TRANSLATORS: "CMAP" is Bob Thrun’s cave surveying
1986 * package, so don’t translate it. */
1987 wmsg(/*CMAP XYZ files*/325).c_str(),
1988 wmsg(/*All files*/208).c_str(),
1989 wxFileSelectorDefaultWildcardStr
);
1991 /* TRANSLATORS: Here "survey" is a "cave map" rather than list of questions
1992 * - it should be translated to the terminology that cavers using the
1993 * language would use.
1995 * File->Open dialog: */
1996 wxFileDialog
dlg(this, wmsg(/*Select a survey file to view*/206),
1997 wxString(), wxString(),
1998 filetypes
, wxFD_OPEN
|wxFD_FILE_MUST_EXIST
);
1999 if (dlg
.ShowModal() == wxID_OK
) {
2000 OpenFile(dlg
.GetPath());
2004 void MainFrm::OnOpenTerrain(wxCommandEvent
&)
2008 if (m_cs_proj
.empty()) {
2009 wxMessageBox(wxT("No coordinate system specified in survey data"));
2014 wxString filetypes
= wxT("*.*");
2017 filetypes
.Printf(wxT("%s|*.bil;*.hgt;*.zip" CASE("*.BIL;*.HGT;*.ZIP")
2019 wmsg(/*Terrain files*/452).c_str(),
2020 wmsg(/*All files*/208).c_str(),
2021 wxFileSelectorDefaultWildcardStr
);
2023 /* TRANSLATORS: "Terrain file" being a digital model of the terrain (e.g. a
2024 * grid of height values). */
2025 wxFileDialog
dlg(this, wmsg(/*Select a terrain file to view*/451),
2026 wxString(), wxString(),
2027 filetypes
, wxFD_OPEN
|wxFD_FILE_MUST_EXIST
);
2028 if (dlg
.ShowModal() == wxID_OK
&& m_Gfx
->LoadDEM(dlg
.GetPath())) {
2029 if (!m_Gfx
->DisplayingTerrain()) m_Gfx
->ToggleTerrain();
2033 void MainFrm::OnShowLog(wxCommandEvent
&)
2036 HideLog(m_Splitter
->GetWindow1());
2039 wxWindow
* win
= m_Splitter
->GetWindow1();
2040 m_Splitter
->ReplaceWindow(win
, m_Log
);
2042 if (m_Splitter
->IsSplit()) {
2043 m_SashPosition
= m_Splitter
->GetSashPosition(); // save width of panel
2044 m_Splitter
->Unsplit();
2051 void MainFrm::OnScreenshot(wxCommandEvent
&)
2053 AvenAllowOnTop
ontop(this);
2055 wxFileName::SplitPath(m_File
, NULL
, NULL
, &baseleaf
, NULL
, wxPATH_NATIVE
);
2056 /* TRANSLATORS: title of the save screenshot dialog */
2057 wxFileDialog
dlg(this, wmsg(/*Save Screenshot*/321), wxString(),
2058 baseleaf
+ wxT(".png"),
2059 wxT("*.png"), wxFD_SAVE
|wxFD_OVERWRITE_PROMPT
);
2060 if (dlg
.ShowModal() == wxID_OK
) {
2061 static bool png_handled
= false;
2063 #if 0 // FIXME : enable this to allow other export formats...
2064 ::wxInitAllImageHandlers();
2066 wxImage::AddHandler(new wxPNGHandler
);
2070 if (!m_Gfx
->SaveScreenshot(dlg
.GetPath(), wxBITMAP_TYPE_PNG
)) {
2071 wxGetApp().ReportError(wxString::Format(wmsg(/*Error writing to file “%s”*/110), dlg
.GetPath().c_str()));
2076 void MainFrm::OnScreenshotUpdate(wxUpdateUIEvent
& event
)
2078 event
.Enable(!m_File
.empty());
2081 void MainFrm::OnFilePreferences(wxCommandEvent
&)
2084 m_PrefsDlg
= new PrefsDlg(m_Gfx
, this);
2085 m_PrefsDlg
->Show(true);
2089 void MainFrm::OnPrint(wxCommandEvent
&)
2091 m_Gfx
->OnPrint(m_File
, m_Title
, m_DateStamp
, m_DateStamp_numeric
, m_cs_proj
);
2094 void MainFrm::PrintAndExit()
2096 m_Gfx
->OnPrint(m_File
, m_Title
, m_DateStamp
, m_DateStamp_numeric
, m_cs_proj
, true);
2099 void MainFrm::OnPageSetup(wxCommandEvent
&)
2101 wxPageSetupDialog
dlg(this, wxGetApp().GetPageSetupDialogData());
2102 if (dlg
.ShowModal() == wxID_OK
) {
2103 wxGetApp().SetPageSetupDialogData(dlg
.GetPageSetupData());
2107 void MainFrm::OnExport(wxCommandEvent
&)
2109 m_Gfx
->OnExport(m_File
, m_Title
, m_DateStamp
, m_DateStamp_numeric
, m_cs_proj
);
2112 void MainFrm::OnExtend(wxCommandEvent
&)
2114 wxString output
= m_Survey
;
2115 if (output
.empty()) {
2116 wxFileName::SplitPath(m_File
, NULL
, NULL
, &output
, NULL
, wxPATH_NATIVE
);
2118 output
+= wxT("_extend.3d");
2120 AvenAllowOnTop
ontop(this);
2122 wxString
ext(wxT("*.3d"));
2124 /* TRANSLATORS: Survex is the name of the software, and "3d" refers to a
2125 * file extension, so neither should be translated. */
2126 wxString ext
= wmsg(/*Survex 3d files*/207);
2127 ext
+= wxT("|*.3d");
2129 wxFileDialog
dlg(this, wmsg(/*Select an output filename*/319),
2130 wxString(), output
, ext
,
2131 wxFD_SAVE
|wxFD_OVERWRITE_PROMPT
);
2132 if (dlg
.ShowModal() != wxID_OK
) return;
2133 output
= dlg
.GetPath();
2135 wxString cmd
= get_command_path(L
"extend");
2136 cmd
= escape_for_shell(cmd
, false);
2137 if (!m_Survey
.empty()) {
2138 cmd
+= wxT(" --survey=");
2139 cmd
+= escape_for_shell(m_Survey
, false);
2141 cmd
+= wxT(" --show-breaks ");
2142 cmd
+= escape_for_shell(m_FileProcessed
, true);
2144 cmd
+= escape_for_shell(output
, true);
2145 if (wxExecute(cmd
, wxEXEC_SYNC
) < 0) {
2147 m
.Printf(wmsg(/*Couldn’t run external command: “%s”*/17), cmd
.c_str());
2149 m
+= wxString(strerror(errno
), wxConvUTF8
);
2151 wxGetApp().ReportError(m
);
2154 if (LoadData(output
, wxString()))
2155 InitialiseAfterLoad(output
, wxString());
2158 void MainFrm::OnQuit(wxCommandEvent
&)
2160 if (m_PresList
->Modified()) {
2161 AvenAllowOnTop
ontop(this);
2162 // FIXME: better to ask "Do you want to save your changes?" and offer [Save] [Discard] [Cancel]
2163 /* TRANSLATORS: and the question in that box */
2164 if (wxMessageBox(wmsg(/*The current presentation has been modified. Abandon unsaved changes?*/327),
2165 /* TRANSLATORS: title of message box */
2166 wmsg(/*Modified Presentation*/326),
2167 wxOK
|wxCANCEL
|wxICON_QUESTION
) == wxCANCEL
) {
2171 wxConfigBase
*b
= wxConfigBase::Get();
2172 if (IsFullScreen()) {
2173 b
->Write(wxT("width"), -2);
2174 b
->DeleteEntry(wxT("height"));
2175 } else if (IsMaximized()) {
2176 b
->Write(wxT("width"), -1);
2177 b
->DeleteEntry(wxT("height"));
2180 GetSize(&width
, &height
);
2181 b
->Write(wxT("width"), width
);
2182 b
->Write(wxT("height"), height
);
2188 void MainFrm::OnClose(wxCloseEvent
&)
2190 wxCommandEvent dummy
;
2194 void MainFrm::OnAbout(wxCommandEvent
&)
2196 AvenAllowOnTop
ontop(this);
2198 // GetIcon() returns an invalid wxIcon under OS X.
2199 AboutDlg
dlg(this, wxICON(aven
));
2201 AboutDlg
dlg(this, GetIcon());
2207 void MainFrm::UpdateStatusBar()
2209 if (!here_text
.empty()) {
2210 GetStatusBar()->SetStatusText(here_text
);
2211 GetStatusBar()->SetStatusText(dist_text
, 1);
2212 } else if (!coords_text
.empty()) {
2213 GetStatusBar()->SetStatusText(coords_text
);
2214 GetStatusBar()->SetStatusText(distfree_text
, 1);
2216 GetStatusBar()->SetStatusText(wxString());
2217 GetStatusBar()->SetStatusText(wxString(), 1);
2221 void MainFrm::ClearTreeSelection()
2223 m_Tree
->UnselectAll();
2228 void MainFrm::ClearCoords()
2230 if (!coords_text
.empty()) {
2231 coords_text
= wxString();
2236 void MainFrm::SetCoords(const Vector3
&v
)
2238 Double x
= v
.GetX();
2239 Double y
= v
.GetY();
2240 Double z
= v
.GetZ();
2242 if (m_Gfx
->GetMetric()) {
2245 x
/= METRES_PER_FOOT
;
2246 y
/= METRES_PER_FOOT
;
2247 z
/= METRES_PER_FOOT
;
2250 /* TRANSLATORS: show coordinates (N = North or Northing, E = East or
2252 coords_text
.Printf(wmsg(/*%.2f E, %.2f N*/338), x
, y
);
2253 coords_text
+= wxString::Format(wxT(", %s %.2f%s"),
2254 wmsg(/*Altitude*/335).c_str(),
2255 z
, wmsg(units
).c_str());
2256 distfree_text
= wxString();
2260 const LabelInfo
* MainFrm::GetTreeSelection() const {
2261 wxTreeItemData
* sel_wx
;
2262 if (!m_Tree
->GetSelectionData(&sel_wx
)) return NULL
;
2264 const TreeData
* data
= static_cast<const TreeData
*>(sel_wx
);
2265 if (!data
->IsStation()) return NULL
;
2267 return data
->GetLabel();
2270 void MainFrm::SetCoords(Double x
, Double y
, const LabelInfo
* there
)
2272 wxString
& s
= coords_text
;
2273 if (m_Gfx
->GetMetric()) {
2274 s
.Printf(wmsg(/*%.2f E, %.2f N*/338), x
, y
);
2276 s
.Printf(wmsg(/*%.2f E, %.2f N*/338),
2277 x
/ METRES_PER_FOOT
, y
/ METRES_PER_FOOT
);
2280 wxString
& t
= distfree_text
;
2282 if (m_Gfx
->ShowingMeasuringLine() && there
) {
2283 Vector3
delta(x
- m_Offsets
.GetX() - there
->GetX(),
2284 y
- m_Offsets
.GetY() - there
->GetY(), 0);
2285 Double dh
= sqrt(delta
.GetX()*delta
.GetX() + delta
.GetY()*delta
.GetY());
2286 Double brg
= deg(atan2(delta
.GetX(), delta
.GetY()));
2287 if (brg
< 0) brg
+= 360;
2290 /* TRANSLATORS: Used in Aven:
2291 * From <stationname>: H 12.24m, Brg 234.5°
2293 from_str
.Printf(wmsg(/*From %s*/339), there
->name_or_anon().c_str());
2295 if (m_Gfx
->GetDegrees()) {
2296 brg_unit
= /*°*/344;
2298 brg
*= 400.0 / 360.0;
2299 brg_unit
= /*ᵍ*/345;
2303 if (m_Gfx
->GetMetric()) {
2306 dh
/= METRES_PER_FOOT
;
2309 /* TRANSLATORS: "H" is short for "Horizontal", "Brg" for "Bearing" (as
2310 * in Compass bearing) */
2311 t
.Printf(wmsg(/*%s: H %.2f%s, Brg %03.1f%s*/374),
2312 from_str
.c_str(), dh
, wmsg(units
).c_str(),
2313 brg
, wmsg(brg_unit
).c_str());
2319 void MainFrm::SetAltitude(Double z
, const LabelInfo
* there
)
2323 if (m_Gfx
->GetMetric()) {
2326 alt
/= METRES_PER_FOOT
;
2329 coords_text
.Printf(wxT("%s %.2f%s"), wmsg(/*Altitude*/335).c_str(),
2330 alt
, wmsg(units
).c_str());
2332 wxString
& t
= distfree_text
;
2334 if (m_Gfx
->ShowingMeasuringLine() && there
) {
2335 Double dz
= z
- m_Offsets
.GetZ() - there
->GetZ();
2338 from_str
.Printf(wmsg(/*From %s*/339), there
->name_or_anon().c_str());
2340 if (!m_Gfx
->GetMetric()) {
2341 dz
/= METRES_PER_FOOT
;
2343 // TRANSLATORS: "V" is short for "Vertical"
2344 t
.Printf(wmsg(/*%s: V %.2f%s*/375), from_str
.c_str(),
2345 dz
, wmsg(units
).c_str());
2351 void MainFrm::ShowInfo(const LabelInfo
*here
, const LabelInfo
*there
)
2357 m_Tree
->SetHere(wxTreeItemId());
2358 // Don't clear "There" mark here.
2359 if (here_text
.empty() && dist_text
.empty()) return;
2360 here_text
= wxString();
2361 dist_text
= wxString();
2366 Vector3 v
= *here
+ m_Offsets
;
2367 wxString
& s
= here_text
;
2368 Double x
= v
.GetX();
2369 Double y
= v
.GetY();
2370 Double z
= v
.GetZ();
2372 if (m_Gfx
->GetMetric()) {
2375 x
/= METRES_PER_FOOT
;
2376 y
/= METRES_PER_FOOT
;
2377 z
/= METRES_PER_FOOT
;
2380 s
.Printf(wmsg(/*%.2f E, %.2f N*/338), x
, y
);
2381 s
+= wxString::Format(wxT(", %s %.2f%s"), wmsg(/*Altitude*/335).c_str(),
2382 z
, wmsg(units
).c_str());
2384 s
+= here
->name_or_anon();
2385 m_Gfx
->SetHere(here
);
2386 m_Tree
->SetHere(here
->tree_id
);
2388 if (m_Gfx
->ShowingMeasuringLine() && there
) {
2389 Vector3 delta
= *here
- *there
;
2391 Double d_horiz
= sqrt(delta
.GetX()*delta
.GetX() +
2392 delta
.GetY()*delta
.GetY());
2393 Double dr
= delta
.magnitude();
2394 Double dz
= delta
.GetZ();
2396 Double brg
= deg(atan2(delta
.GetX(), delta
.GetY()));
2397 if (brg
< 0) brg
+= 360;
2399 Double grd
= deg(atan2(delta
.GetZ(), d_horiz
));
2402 from_str
.Printf(wmsg(/*From %s*/339), there
->name_or_anon().c_str());
2405 if (m_Gfx
->GetMetric()) {
2408 d_horiz
/= METRES_PER_FOOT
;
2409 dr
/= METRES_PER_FOOT
;
2410 dz
/= METRES_PER_FOOT
;
2413 wxString len_unit
= wmsg(units
);
2414 /* TRANSLATORS: "H" is short for "Horizontal", "V" for "Vertical" */
2415 hv_str
.Printf(wmsg(/*H %.2f%s, V %.2f%s*/340),
2416 d_horiz
, len_unit
.c_str(), dz
, len_unit
.c_str());
2418 if (m_Gfx
->GetDegrees()) {
2419 brg_unit
= /*°*/344;
2421 brg
*= 400.0 / 360.0;
2422 brg_unit
= /*ᵍ*/345;
2426 if (m_Gfx
->GetPercent()) {
2429 } else if (grd
< -89.99) {
2432 grd
= int(100 * tan(rad(grd
)));
2434 if (grd
> 99999 || grd
< -99999) {
2435 grd_str
= grd
> 0 ? wxT("+") : wxT("-");
2436 /* TRANSLATORS: infinity symbol - used for the percentage gradient on
2437 * vertical angles. */
2438 grd_str
+= wmsg(/*∞*/431);
2441 } else if (m_Gfx
->GetDegrees()) {
2442 grd_unit
= /*°*/344;
2444 grd
*= 400.0 / 360.0;
2445 grd_unit
= /*ᵍ*/345;
2447 if (grd_str
.empty()) {
2448 grd_str
.Printf(wxT("%+02.1f%s"), grd
, wmsg(grd_unit
).c_str());
2451 wxString
& d
= dist_text
;
2452 /* TRANSLATORS: "Dist" is short for "Distance", "Brg" for "Bearing" (as
2453 * in Compass bearing) and "Grd" for "Gradient" (the slope angle
2454 * measured by the clino) */
2455 d
.Printf(wmsg(/*%s: %s, Dist %.2f%s, Brg %03.1f%s, Grd %s*/341),
2456 from_str
.c_str(), hv_str
.c_str(),
2457 dr
, len_unit
.c_str(),
2458 brg
, wmsg(brg_unit
).c_str(),
2461 dist_text
= wxString();
2467 void MainFrm::DisplayTreeInfo(const wxTreeItemData
* item
)
2469 const TreeData
* data
= static_cast<const TreeData
*>(item
);
2470 if (data
&& data
->IsStation()) {
2471 m_Gfx
->SetHereFromTree(data
->GetLabel());
2477 void MainFrm::TreeItemSelected(const wxTreeItemData
* item
, bool zoom
)
2479 const TreeData
* data
= static_cast<const TreeData
*>(item
);
2480 if (data
&& data
->IsStation()) {
2481 const LabelInfo
* label
= data
->GetLabel();
2482 if (zoom
) m_Gfx
->CentreOn(*label
);
2483 m_Gfx
->SetThere(label
);
2484 dist_text
= wxString();
2485 // FIXME: Need to update dist_text (From ... etc)
2486 // But we don't currently know where "here" is at this point in the
2489 dist_text
= wxString();
2493 // Must be the root.
2494 m_FindBox
->SetValue(wxString());
2496 wxCommandEvent dummy
;
2499 } else if (data
&& !data
->IsStation()) {
2500 m_FindBox
->SetValue(data
->GetSurvey() + wxT(".*"));
2502 wxCommandEvent dummy
;
2509 void MainFrm::OnPresNew(wxCommandEvent
&)
2511 if (m_PresList
->Modified()) {
2512 AvenAllowOnTop
ontop(this);
2513 // FIXME: better to ask "Do you want to save your changes?" and offer [Save] [Discard] [Cancel]
2514 if (wxMessageBox(wmsg(/*The current presentation has been modified. Abandon unsaved changes?*/327),
2515 wmsg(/*Modified Presentation*/326),
2516 wxOK
|wxCANCEL
|wxICON_QUESTION
) == wxCANCEL
) {
2520 m_PresList
->New(m_File
);
2521 if (!ShowingSidePanel()) ToggleSidePanel();
2522 // Select the presentation page in the notebook.
2523 m_Notebook
->SetSelection(1);
2526 void MainFrm::OnPresOpen(wxCommandEvent
&)
2528 AvenAllowOnTop
ontop(this);
2529 if (m_PresList
->Modified()) {
2530 // FIXME: better to ask "Do you want to save your changes?" and offer [Save] [Discard] [Cancel]
2531 if (wxMessageBox(wmsg(/*The current presentation has been modified. Abandon unsaved changes?*/327),
2532 wmsg(/*Modified Presentation*/326),
2533 wxOK
|wxCANCEL
|wxICON_QUESTION
) == wxCANCEL
) {
2538 wxFileDialog
dlg(this, wmsg(/*Select a presentation to open*/322), wxString(), wxString(),
2539 wxT("*.fly"), wxFD_OPEN
);
2541 wxFileDialog
dlg(this, wmsg(/*Select a presentation to open*/322), wxString(), wxString(),
2542 wxString::Format(wxT("%s|*.fly|%s|%s"),
2543 wmsg(/*Aven presentations*/320).c_str(),
2544 wmsg(/*All files*/208).c_str(),
2545 wxFileSelectorDefaultWildcardStr
),
2546 wxFD_OPEN
|wxFD_FILE_MUST_EXIST
);
2548 if (dlg
.ShowModal() == wxID_OK
) {
2549 if (!m_PresList
->Load(dlg
.GetPath())) {
2552 // FIXME : keep a history of loaded/saved presentations, like we do for
2553 // loaded surveys...
2554 // Select the presentation page in the notebook.
2555 m_Notebook
->SetSelection(1);
2559 void MainFrm::OnPresSave(wxCommandEvent
&)
2561 m_PresList
->Save(true);
2564 void MainFrm::OnPresSaveAs(wxCommandEvent
&)
2566 m_PresList
->Save(false);
2569 void MainFrm::OnPresMark(wxCommandEvent
&)
2571 m_PresList
->AddMark();
2574 void MainFrm::OnPresFRewind(wxCommandEvent
&)
2576 m_Gfx
->PlayPres(-100);
2579 void MainFrm::OnPresRewind(wxCommandEvent
&)
2581 m_Gfx
->PlayPres(-10);
2584 void MainFrm::OnPresReverse(wxCommandEvent
&)
2586 m_Gfx
->PlayPres(-1);
2589 void MainFrm::OnPresPlay(wxCommandEvent
&)
2594 void MainFrm::OnPresFF(wxCommandEvent
&)
2596 m_Gfx
->PlayPres(10);
2599 void MainFrm::OnPresFFF(wxCommandEvent
&)
2601 m_Gfx
->PlayPres(100);
2604 void MainFrm::OnPresPause(wxCommandEvent
&)
2609 void MainFrm::OnPresStop(wxCommandEvent
&)
2611 m_Gfx
->PlayPres(0, false);
2614 void MainFrm::OnPresExportMovie(wxCommandEvent
&)
2617 AvenAllowOnTop
ontop(this);
2618 // FIXME : Taking the leaf of the currently loaded presentation as the
2619 // default might make more sense?
2621 wxFileName::SplitPath(m_File
, NULL
, NULL
, &baseleaf
, NULL
, wxPATH_NATIVE
);
2622 wxFileDialog
dlg(this, wmsg(/*Export Movie*/331), wxString(),
2623 baseleaf
+ wxT(".mp4"),
2624 wxT("MPEG|*.mp4|OGG|*.ogv|AVI|*.avi|QuickTime|*.mov|WMV|*.wmv;*.asf"),
2625 wxFD_SAVE
|wxFD_OVERWRITE_PROMPT
);
2626 if (dlg
.ShowModal() == wxID_OK
) {
2627 // Error is reported by GfxCore.
2628 (void)m_Gfx
->ExportMovie(dlg
.GetPath());
2631 wxGetApp().ReportError(wxT("Movie generation support code not present"));
2635 PresentationMark
MainFrm::GetPresMark(int which
)
2637 return m_PresList
->GetPresMark(which
);
2640 void MainFrm::RestrictTo(const wxString
& survey
)
2642 // The station names will change, so clear the current search.
2643 wxCommandEvent dummy
;
2646 wxString new_prefix
;
2647 if (!survey
.empty()) {
2648 if (!m_Survey
.empty()) {
2649 new_prefix
= m_Survey
;
2650 new_prefix
+= separator
;
2652 new_prefix
+= survey
;
2654 // Reload the processed data rather rather than potentially reprocessing.
2655 if (!LoadData(m_FileProcessed
, new_prefix
))
2657 InitialiseAfterLoad(m_File
, new_prefix
);
2660 void MainFrm::OnOpenTerrainUpdate(wxUpdateUIEvent
& event
)
2662 event
.Enable(!m_File
.empty());
2665 void MainFrm::OnPresNewUpdate(wxUpdateUIEvent
& event
)
2667 event
.Enable(!m_File
.empty());
2670 void MainFrm::OnPresOpenUpdate(wxUpdateUIEvent
& event
)
2672 event
.Enable(!m_File
.empty());
2675 void MainFrm::OnPresSaveUpdate(wxUpdateUIEvent
& event
)
2677 event
.Enable(!m_PresList
->Empty());
2680 void MainFrm::OnPresSaveAsUpdate(wxUpdateUIEvent
& event
)
2682 event
.Enable(!m_PresList
->Empty());
2685 void MainFrm::OnPresMarkUpdate(wxUpdateUIEvent
& event
)
2687 event
.Enable(!m_File
.empty());
2690 void MainFrm::OnPresFRewindUpdate(wxUpdateUIEvent
& event
)
2692 event
.Enable(m_Gfx
&& m_Gfx
->GetPresentationMode());
2693 event
.Check(m_Gfx
&& m_Gfx
->GetPresentationSpeed() < -10);
2696 void MainFrm::OnPresRewindUpdate(wxUpdateUIEvent
& event
)
2698 event
.Enable(m_Gfx
&& m_Gfx
->GetPresentationMode());
2699 event
.Check(m_Gfx
&& m_Gfx
->GetPresentationSpeed() == -10);
2702 void MainFrm::OnPresReverseUpdate(wxUpdateUIEvent
& event
)
2704 event
.Enable(m_Gfx
&& m_Gfx
->GetPresentationMode());
2705 event
.Check(m_Gfx
&& m_Gfx
->GetPresentationSpeed() == -1);
2708 void MainFrm::OnPresPlayUpdate(wxUpdateUIEvent
& event
)
2710 event
.Enable(!m_PresList
->Empty());
2711 event
.Check(m_Gfx
&& m_Gfx
->GetPresentationMode() &&
2712 m_Gfx
->GetPresentationSpeed() == 1);
2715 void MainFrm::OnPresFFUpdate(wxUpdateUIEvent
& event
)
2717 event
.Enable(m_Gfx
&& m_Gfx
->GetPresentationMode());
2718 event
.Check(m_Gfx
&& m_Gfx
->GetPresentationSpeed() == 10);
2721 void MainFrm::OnPresFFFUpdate(wxUpdateUIEvent
& event
)
2723 event
.Enable(m_Gfx
&& m_Gfx
->GetPresentationMode());
2724 event
.Check(m_Gfx
&& m_Gfx
->GetPresentationSpeed() > 10);
2727 void MainFrm::OnPresPauseUpdate(wxUpdateUIEvent
& event
)
2729 event
.Enable(m_Gfx
&& m_Gfx
->GetPresentationMode());
2730 event
.Check(m_Gfx
&& m_Gfx
->GetPresentationSpeed() == 0);
2733 void MainFrm::OnPresStopUpdate(wxUpdateUIEvent
& event
)
2735 event
.Enable(m_Gfx
&& m_Gfx
->GetPresentationMode());
2738 void MainFrm::OnPresExportMovieUpdate(wxUpdateUIEvent
& event
)
2740 event
.Enable(!m_PresList
->Empty());
2743 void MainFrm::OnFind(wxCommandEvent
&)
2745 pending_find
= true;
2748 void MainFrm::OnIdle(wxIdleEvent
&)
2755 void MainFrm::DoFind()
2757 pending_find
= false;
2758 wxBusyCursor hourglass
;
2759 // Find stations specified by a string or regular expression pattern.
2761 wxString pattern
= m_FindBox
->GetValue();
2762 if (pattern
.empty()) {
2763 // Hide any search result highlights.
2764 list
<LabelInfo
*>::iterator pos
= m_Labels
.begin();
2765 while (pos
!= m_Labels
.end()) {
2766 LabelInfo
* label
= *pos
++;
2767 label
->clear_flags(LFLAG_HIGHLIGHTED
);
2769 m_NumHighlighted
= 0;
2771 int re_flags
= wxRE_NOSUB
;
2773 if (true /* case insensitive */) {
2774 re_flags
|= wxRE_ICASE
;
2777 bool substring
= true;
2778 if (false /*m_RegexpCheckBox->GetValue()*/) {
2779 re_flags
|= wxRE_EXTENDED
;
2780 } else if (true /* simple glob-style */) {
2782 for (size_t i
= 0; i
< pattern
.size(); i
++) {
2783 wxChar ch
= pattern
[i
];
2784 // ^ only special at start; $ at end. But this is simpler...
2786 case '^': case '$': case '.': case '[': case '\\':
2803 re_flags
|= wxRE_BASIC
;
2806 for (size_t i
= 0; i
< pattern
.size(); i
++) {
2807 wxChar ch
= pattern
[i
];
2808 // ^ only special at start; $ at end. But this is simpler...
2810 case '^': case '$': case '*': case '.': case '[': case '\\':
2816 re_flags
|= wxRE_BASIC
;
2820 // FIXME "0u" required to avoid compilation error with g++-3.0
2821 if (pattern
.empty() || pattern
[0u] != '^') pattern
= wxT('^') + pattern
;
2822 // FIXME: this fails to cope with "\$" at the end of pattern...
2823 if (pattern
[pattern
.size() - 1] != '$') pattern
+= wxT('$');
2827 if (!regex
.Compile(pattern
, re_flags
)) {
2834 list
<LabelInfo
*>::iterator pos
= m_Labels
.begin();
2835 while (pos
!= m_Labels
.end()) {
2836 LabelInfo
* label
= *pos
++;
2838 if (regex
.Matches(label
->GetText())) {
2839 label
->set_flags(LFLAG_HIGHLIGHTED
);
2842 label
->clear_flags(LFLAG_HIGHLIGHTED
);
2846 m_NumHighlighted
= found
;
2848 // Re-sort so highlighted points get names in preference
2849 if (found
) m_Labels
.sort(LabelPlotCmp(separator
));
2852 m_Gfx
->UpdateBlobs();
2853 m_Gfx
->ForceRefresh();
2855 if (!m_NumHighlighted
) {
2856 GetToolBar()->SetToolShortHelp(button_HIDE
, wmsg(/*No matches were found.*/328));
2858 /* TRANSLATORS: "Hide stations" button tooltip when stations are found
2860 GetToolBar()->SetToolShortHelp(button_HIDE
, wxString::Format(wmsg(/*Hide %d found stations*/334).c_str(), m_NumHighlighted
));
2864 void MainFrm::OnGotoFound(wxCommandEvent
&)
2866 if (!m_NumHighlighted
) {
2867 wxGetApp().ReportError(wmsg(/*No matches were found.*/328));
2871 Double xmin
= DBL_MAX
;
2872 Double xmax
= -DBL_MAX
;
2873 Double ymin
= DBL_MAX
;
2874 Double ymax
= -DBL_MAX
;
2875 Double zmin
= DBL_MAX
;
2876 Double zmax
= -DBL_MAX
;
2878 list
<LabelInfo
*>::iterator pos
= m_Labels
.begin();
2879 while (pos
!= m_Labels
.end()) {
2880 LabelInfo
* label
= *pos
++;
2882 if (label
->get_flags() & LFLAG_HIGHLIGHTED
) {
2883 if (label
->GetX() < xmin
) xmin
= label
->GetX();
2884 if (label
->GetX() > xmax
) xmax
= label
->GetX();
2885 if (label
->GetY() < ymin
) ymin
= label
->GetY();
2886 if (label
->GetY() > ymax
) ymax
= label
->GetY();
2887 if (label
->GetZ() < zmin
) zmin
= label
->GetZ();
2888 if (label
->GetZ() > zmax
) zmax
= label
->GetZ();
2892 m_Gfx
->SetViewTo(xmin
, xmax
, ymin
, ymax
, zmin
, zmax
);
2896 void MainFrm::OnHide(wxCommandEvent
&)
2898 m_FindBox
->SetValue(wxString());
2899 GetToolBar()->SetToolShortHelp(button_HIDE
, wmsg(/*Hide*/333));
2902 void MainFrm::OnHideUpdate(wxUpdateUIEvent
& ui
)
2904 ui
.Enable(m_NumHighlighted
!= 0);
2907 void MainFrm::OnViewSidePanel(wxCommandEvent
&)
2912 void MainFrm::ToggleSidePanel()
2914 // Toggle display of the side panel.
2918 if (m_Splitter
->IsSplit()) {
2919 m_SashPosition
= m_Splitter
->GetSashPosition(); // save width of panel
2920 m_Splitter
->Unsplit(m_Notebook
);
2922 m_Notebook
->Show(true);
2924 m_Splitter
->SplitVertically(m_Notebook
, m_Gfx
, m_SashPosition
);
2928 void MainFrm::OnViewSidePanelUpdate(wxUpdateUIEvent
& ui
)
2930 ui
.Enable(!m_File
.empty());
2931 ui
.Check(ShowingSidePanel());
2934 bool MainFrm::ShowingSidePanel()
2936 return m_Splitter
->IsSplit();
2939 void MainFrm::ViewFullScreen() {
2941 // On OS X, wxWidgets doesn't currently hide the toolbar or statusbar in
2942 // full screen mode (last checked with 3.0.2), but it is easy to do
2944 if (!IsFullScreen()) {
2945 GetToolBar()->Hide();
2946 GetStatusBar()->Hide();
2950 ShowFullScreen(!IsFullScreen());
2951 fullscreen_showing_menus
= false;
2953 was_showing_sidepanel_before_fullscreen
= ShowingSidePanel();
2954 if (was_showing_sidepanel_before_fullscreen
)
2958 if (!IsFullScreen()) {
2959 GetStatusBar()->Show();
2960 GetToolBar()->Show();
2961 #ifdef USING_GENERIC_TOOLBAR
2968 bool MainFrm::FullScreenModeShowingMenus() const
2970 return fullscreen_showing_menus
;
2973 void MainFrm::FullScreenModeShowMenus(bool show
)
2975 if (!IsFullScreen() || show
== fullscreen_showing_menus
)
2978 // On OS X, enabling the menu bar while in full
2979 // screen mode doesn't have any effect, so instead
2980 // make moving the mouse to the top of the screen
2981 // drop us out of full screen mode for now.
2984 GetMenuBar()->Show(show
);
2985 fullscreen_showing_menus
= show
;