1 // -*- c-basic-offset: 4 -*-
2 
3 /** @file GLPreviewFrame.cpp
4  *
5  *  @brief implementation of GLPreviewFrame Class
6  *
7  *  @author James Legg and Pablo d'Angelo <pablo.dangelo@web.de>
8  *  @author Darko Makreshanski
9  *
10  *  This program is free software; you can redistribute it and/or
11  *  modify it under the terms of the GNU General Public
12  *  License as published by the Free Software Foundation; either
13  *  version 2 of the License, or (at your option) any later version.
14  *
15  *  This software 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 GNU
18  *  General Public License for more details.
19  *
20  *  You should have received a copy of the GNU General Public
21  *  License along with this software. If not, see
22  *  <http://www.gnu.org/licenses/>.
23  *
24  */
25 
26 #include <bitset>
27 #include <limits>
28 #include <iostream>
29 
30 #include "hugin_config.h"
31 
32 #include <GL/glew.h>
33 
34 #include "panoinc_WX.h"
35 #include "panoinc.h"
36 #include <wx/msgdlg.h>
37 
38 #include "base_wx/platform.h"
39 #include "base_wx/wxPlatform.h"
40 #include "base_wx/LensTools.h"
41 #include "algorithms/optimizer/ImageGraph.h"
42 #include "algorithms/basic/LayerStacks.h"
43 #include <algorithms/basic/CalculateOptimalROI.h>
44 #include <algorithms/basic/CalculateCPStatistics.h>
45 #include <algorithms/nona/FitPanorama.h>
46 #include <algorithms/basic/CalculateMeanExposure.h>
47 
48 #include "base_wx/MyProgressDialog.h"
49 #include "base_wx/wxPanoCommand.h"
50 
51 #include "hugin/config_defaults.h"
52 #include "hugin/GLPreviewFrame.h"
53 #include "hugin/huginApp.h"
54 #include "hugin/MainFrame.h"
55 #include "hugin/ImagesPanel.h"
56 #include "base_wx/CommandHistory.h"
57 #include "hugin/GLViewer.h"
58 #include "hugin/TextKillFocusHandler.h"
59 #include "hugin/PanoOperation.h"
60 #include "hugin/PanoOutputDialog.h"
61 #include "base_wx/PTWXDlg.h"
62 #include "vigra_ext/InterestPoints.h"
63 #include "vigra_ext/Correlation.h"
64 #include "algorithms/control_points/CleanCP.h"
65 #include "hugin_utils/openmp_lock.h"
66 
67 extern "C" {
68 #include <pano13/queryfeature.h>
69 }
70 
71 #include "ToolHelper.h"
72 #include "Tool.h"
73 #include "DragTool.h"
74 #include "PreviewCropTool.h"
75 #include "PreviewIdentifyTool.h"
76 #include "PreviewCameraTool.h"
77 #include "PreviewDifferenceTool.h"
78 #include "PreviewPanoMaskTool.h"
79 #include "PreviewControlPointTool.h"
80 #include "PreviewLayoutLinesTool.h"
81 #include "PreviewColorPickerTool.h"
82 #include "PreviewGuideTool.h"
83 #include "PreviewEditCPTool.h"
84 
85 #include "ProjectionGridTool.h"
86 #include "PanosphereSphereTool.h"
87 
88 #include "OverviewCameraTool.h"
89 #include "OverviewOutlinesTool.h"
90 
91 #include <wx/progdlg.h>
92 #include <wx/infobar.h>
93 
94 // a random id, hope this doesn't break something..
95 enum {
96     ID_TOGGLE_BUT = wxID_HIGHEST+500,
97     PROJ_PARAM_NAMES_ID = wxID_HIGHEST+1300,
98     PROJ_PARAM_VAL_ID = wxID_HIGHEST+1400,
99     PROJ_PARAM_SLIDER_ID = wxID_HIGHEST+1500,
100     PROJ_PARAM_RESET_ID = wxID_HIGHEST+1550,
101     ID_TOGGLE_BUT_LEAVE = wxID_HIGHEST+1600,
102     ID_FULL_SCREEN = wxID_HIGHEST+1710,
103     ID_SHOW_ALL = wxID_HIGHEST+1711,
104     ID_SHOW_NONE = wxID_HIGHEST+1712,
105     ID_HIDE_HINTS = wxID_HIGHEST+1715
106 };
107 
108 /** enum, which contains all different toolbar modes */
109 enum{
110     mode_assistant=0,
111     mode_preview,
112     mode_layout,
113     mode_projection,
114     mode_drag,
115     mode_crop
116 };
117 
118 //------------------------------------------------------------------------------
BEGIN_EVENT_TABLE(GLwxAuiFloatingFrame,wxAuiFloatingFrame)119 BEGIN_EVENT_TABLE(GLwxAuiFloatingFrame, wxAuiFloatingFrame)
120     EVT_ACTIVATE(GLwxAuiFloatingFrame::OnActivate)
121 END_EVENT_TABLE()
122 
123 BEGIN_EVENT_TABLE(GLPreviewFrame, wxFrame)
124     EVT_CLOSE(GLPreviewFrame::OnClose)
125     EVT_SHOW(GLPreviewFrame::OnShowEvent)
126     //for some reason only key up is sent, key down event is not sent
127 //    EVT_KEY_DOWN(GLPreviewFrame::KeyDown)
128 //    EVT_KEY_UP(GLPreviewFrame::KeyUp)
129     EVT_BUTTON(XRCID("preview_center_tool"), GLPreviewFrame::OnCenterHorizontally)
130     EVT_BUTTON(XRCID("preview_fit_pano_tool"), GLPreviewFrame::OnFitPano)
131     EVT_BUTTON(XRCID("preview_fit_pano_tool2"), GLPreviewFrame::OnFitPano)
132     EVT_BUTTON(XRCID("preview_straighten_pano_tool"), GLPreviewFrame::OnStraighten)
133     EVT_BUTTON(XRCID("apply_num_transform"), GLPreviewFrame::OnNumTransform)
134     EVT_TEXT_ENTER(XRCID("input_yaw"), GLPreviewFrame::OnNumTransform)
135     EVT_TEXT_ENTER(XRCID("input_pitch"), GLPreviewFrame::OnNumTransform)
136     EVT_TEXT_ENTER(XRCID("input_roll"), GLPreviewFrame::OnNumTransform)
137     EVT_TEXT_ENTER(XRCID("input_x"), GLPreviewFrame::OnNumTransform)
138     EVT_TEXT_ENTER(XRCID("input_y"), GLPreviewFrame::OnNumTransform)
139     EVT_TEXT_ENTER(XRCID("input_z"), GLPreviewFrame::OnNumTransform)
140     EVT_BUTTON(ID_SHOW_ALL, GLPreviewFrame::OnShowAll)
141     EVT_BUTTON(ID_SHOW_NONE, GLPreviewFrame::OnShowNone)
142     EVT_CHECKBOX(XRCID("preview_photometric_tool"), GLPreviewFrame::OnPhotometric)
143     EVT_TOGGLEBUTTON(XRCID("preview_identify_toggle_button"), GLPreviewFrame::OnIdentify)
144     EVT_TOGGLEBUTTON(XRCID("preview_color_picker_toggle_button"), GLPreviewFrame::OnColorPicker)
145     EVT_TOGGLEBUTTON(XRCID("preview_edit_cp_toggle_button"), GLPreviewFrame::OnEditCPTool)
146     EVT_CHECKBOX(XRCID("preview_control_point_tool"), GLPreviewFrame::OnControlPoint)
147     EVT_BUTTON(XRCID("preview_autocrop_tool"), GLPreviewFrame::OnAutocrop)
148     EVT_BUTTON(XRCID("preview_stack_autocrop_tool"), GLPreviewFrame::OnStackAutocrop)
149     EVT_NOTEBOOK_PAGE_CHANGED(XRCID("mode_toolbar_notebook"), GLPreviewFrame::OnSelectMode)
150     EVT_NOTEBOOK_PAGE_CHANGING(XRCID("mode_toolbar_notebook"), GLPreviewFrame::OnToolModeChanging)
151     EVT_BUTTON(ID_HIDE_HINTS, GLPreviewFrame::OnHideProjectionHints)
152     EVT_BUTTON(XRCID("exposure_default_button"), GLPreviewFrame::OnDefaultExposure)
153     EVT_SPIN_DOWN(XRCID("exposure_spin"), GLPreviewFrame::OnDecreaseExposure)
154     EVT_SPIN_UP(XRCID("exposure_spin"), GLPreviewFrame::OnIncreaseExposure)
155     EVT_SPIN_DOWN(XRCID("range_compression_spin"), GLPreviewFrame::OnRangeCompressionDecrease)
156     EVT_SPIN_UP(XRCID("range_compression_spin"), GLPreviewFrame::OnRangeCompressionIncrease)
157     EVT_TEXT_ENTER(XRCID("range_compression_text"), GLPreviewFrame::OnRangeCompressionChanged)
158     EVT_CHOICE(XRCID("blend_mode_choice"), GLPreviewFrame::OnBlendChoice)
159     EVT_CHOICE(XRCID("drag_mode_choice"), GLPreviewFrame::OnDragChoice)
160     EVT_CHOICE(XRCID("projection_choice"), GLPreviewFrame::OnProjectionChoice)
161     EVT_CHOICE(XRCID("overview_mode_choice"), GLPreviewFrame::OnOverviewModeChoice)
162     EVT_CHOICE(XRCID("preview_guide_choice_crop"), GLPreviewFrame::OnGuideChanged)
163     EVT_CHOICE(XRCID("preview_guide_choice_drag"), GLPreviewFrame::OnGuideChanged)
164     EVT_CHOICE(XRCID("preview_guide_choice_proj"), GLPreviewFrame::OnGuideChanged)
165     EVT_MENU(XRCID("action_show_overview"), GLPreviewFrame::OnOverviewToggle)
166     EVT_MENU(XRCID("action_show_grid"), GLPreviewFrame::OnSwitchPreviewGrid)
167     EVT_MENU(ID_CREATE_CP, GLPreviewFrame::OnCreateCP)
168     EVT_MENU(ID_REMOVE_CP, GLPreviewFrame::OnRemoveCP)
169     EVT_MENU_CLOSE(GLPreviewFrame::OnMenuClose)
170 #ifndef __WXMAC__
171 	EVT_COMMAND_SCROLL(XRCID("layout_scale_slider"), GLPreviewFrame::OnLayoutScaleChange)
172 	EVT_SCROLL_CHANGED(GLPreviewFrame::OnChangeFOV)
173 	EVT_COMMAND_SCROLL_CHANGED(XRCID("layout_scale_slider"), GLPreviewFrame::OnLayoutScaleChange)
174 #else
175     EVT_SCROLL_THUMBRELEASE(GLPreviewFrame::OnChangeFOV)
176     EVT_COMMAND_SCROLL(XRCID("layout_scale_slider"), GLPreviewFrame::OnLayoutScaleChange)
177     EVT_SCROLL_CHANGED(GLPreviewFrame::OnChangeFOV)
178     EVT_COMMAND_SCROLL_THUMBTRACK(XRCID("layout_scale_slider"), GLPreviewFrame::OnLayoutScaleChange)
179 #endif
180 	EVT_SCROLL_THUMBTRACK(GLPreviewFrame::OnTrackChangeFOV)
181     EVT_TEXT_ENTER(XRCID("pano_text_hfov"), GLPreviewFrame::OnHFOVChanged )
182     EVT_TEXT_ENTER(XRCID("pano_text_vfov"), GLPreviewFrame::OnVFOVChanged )
183     EVT_TEXT_ENTER(XRCID("pano_val_roi_left"), GLPreviewFrame::OnROIChanged)
184     EVT_TEXT_ENTER(XRCID("pano_val_roi_top"), GLPreviewFrame::OnROIChanged)
185     EVT_TEXT_ENTER(XRCID("pano_val_roi_right"), GLPreviewFrame::OnROIChanged)
186     EVT_TEXT_ENTER(XRCID("pano_val_roi_bottom"), GLPreviewFrame::OnROIChanged)
187     EVT_BUTTON(XRCID("reset_crop_button"), GLPreviewFrame::OnResetCrop)
188     EVT_TEXT_ENTER(XRCID("exposure_text"), GLPreviewFrame::OnExposureChanged)
189     EVT_COMMAND_RANGE(PROJ_PARAM_VAL_ID,PROJ_PARAM_VAL_ID+PANO_PROJECTION_MAX_PARMS,wxEVT_COMMAND_TEXT_ENTER,GLPreviewFrame::OnProjParameterChanged)
190     EVT_BUTTON(PROJ_PARAM_RESET_ID, GLPreviewFrame::OnProjParameterReset)
191     EVT_TOOL(ID_FULL_SCREEN, GLPreviewFrame::OnFullScreen)
192     EVT_COLOURPICKER_CHANGED(XRCID("preview_background"), GLPreviewFrame::OnPreviewBackgroundColorChanged)
193     EVT_MENU(XRCID("ID_SHOW_FULL_SCREEN_PREVIEW"), GLPreviewFrame::OnFullScreen)
194     EVT_MENU(XRCID("action_show_main_frame"), GLPreviewFrame::OnShowMainFrame)
195     EVT_MENU(XRCID("action_exit_preview"), GLPreviewFrame::OnUserExit)
196     EVT_CHOICE     ( XRCID("ass_lens_type"), GLPreviewFrame::OnLensTypeChanged)
197     EVT_TEXT_ENTER ( XRCID("ass_focal_length"), GLPreviewFrame::OnFocalLengthChanged)
198     EVT_TEXT_ENTER ( XRCID("ass_crop_factor"), GLPreviewFrame::OnCropFactorChanged)
199     EVT_BUTTON     ( XRCID("ass_load_images_button"), GLPreviewFrame::OnLoadImages)
200     EVT_BUTTON     ( XRCID("ass_align_button"), GLPreviewFrame::OnAlign)
201     EVT_BUTTON     ( XRCID("ass_create_button"), GLPreviewFrame::OnCreate)
202     // context menu of select all button
203     EVT_MENU(XRCID("selectMenu_selectAll"), GLPreviewFrame::OnSelectAllMenu)
204     EVT_MENU(XRCID("selectMenu_selectMedian"), GLPreviewFrame::OnSelectMedianMenu)
205     EVT_MENU(XRCID("selectMenu_selectBrightest"), GLPreviewFrame::OnSelectDarkestMenu)
206     EVT_MENU(XRCID("selectMenu_selectDarkest"), GLPreviewFrame::OnSelectBrightestMenu)
207     EVT_MENU(XRCID("selectMenu_keepCurrentSelection"), GLPreviewFrame::OnSelectKeepSelection)
208     EVT_MENU(XRCID("selectMenu_resetSelection"), GLPreviewFrame::OnSelectResetSelection)
209 END_EVENT_TABLE()
210 
211 BEGIN_EVENT_TABLE(ImageToogleButtonEventHandler, wxEvtHandler)
212     EVT_ENTER_WINDOW(ImageToogleButtonEventHandler::OnEnter)
213     EVT_LEAVE_WINDOW(ImageToogleButtonEventHandler::OnLeave)
214     EVT_TOGGLEBUTTON(-1, ImageToogleButtonEventHandler::OnChange)
215 END_EVENT_TABLE()
216 
217 BEGIN_EVENT_TABLE(ImageGroupButtonEventHandler, wxEvtHandler)
218     EVT_ENTER_WINDOW(ImageGroupButtonEventHandler::OnEnter)
219     EVT_LEAVE_WINDOW(ImageGroupButtonEventHandler::OnLeave)
220     EVT_CHECKBOX(-1, ImageGroupButtonEventHandler::OnChange)
221 END_EVENT_TABLE()
222 
223 #define PF_STYLE (wxMAXIMIZE_BOX | wxMINIMIZE_BOX | wxRESIZE_BORDER | wxSYSTEM_MENU | wxCAPTION | wxCLOSE_BOX | wxCLIP_CHILDREN)
224 GLwxAuiFloatingFrame* GLwxAuiManager::CreateFloatingFrame(wxWindow* parent, const wxAuiPaneInfo& p)
225 {
226     DEBUG_DEBUG("CREATING FLOATING FRAME");
227     frame->PauseResize();
228     GLwxAuiFloatingFrame* fl_frame = new GLwxAuiFloatingFrame(parent, this, p);
229     DEBUG_DEBUG("CREATED FLOATING FRAME");
230     return fl_frame;
231 }
232 
OnActivate(wxActivateEvent & evt)233 void GLwxAuiFloatingFrame::OnActivate(wxActivateEvent& evt)
234 {
235     DEBUG_DEBUG("FRAME ACTIVATE");
236     GLPreviewFrame * frame = ((GLwxAuiManager*) GetOwnerManager())->getPreviewFrame();
237     frame->ContinueResize();
238     evt.Skip();
239 }
240 
OnMoveFinished()241 void GLwxAuiFloatingFrame::OnMoveFinished()
242 {
243     DEBUG_DEBUG("FRAME ON MOVE FINISHED");
244     GLPreviewFrame * frame = ((GLwxAuiManager*) GetOwnerManager())->getPreviewFrame();
245     frame->PauseResize();
246     wxAuiFloatingFrame::OnMoveFinished();
247     DEBUG_DEBUG("FRAME AFTER ON MOVE FINISHED");
248 }
249 
PauseResize()250 void GLPreviewFrame::PauseResize()
251 {
252     DEBUG_DEBUG("PAUSE RESIZE");
253     GLresize = false;
254 }
255 
ContinueResize()256 void GLPreviewFrame::ContinueResize()
257 {
258     GLresize = true;
259     wxSizeEvent event = wxSizeEvent(wxSize());
260     m_GLPreview->Resized(event);
261     m_GLOverview->Resized(event);
262 }
263 
264 #include <iostream>
GLPreviewFrame(wxFrame * frame,HuginBase::Panorama & pano)265 GLPreviewFrame::GLPreviewFrame(wxFrame * frame, HuginBase::Panorama &pano)
266     : wxFrame(frame,-1, _("Fast Panorama preview"), wxDefaultPosition, wxDefaultSize,
267               PF_STYLE),
268       m_pano(pano)
269 {
270 
271 	DEBUG_TRACE("");
272 
273     // initialize pointer
274     preview_helper = NULL;
275     panosphere_overview_helper = NULL;
276     plane_overview_helper = NULL;
277     crop_tool = NULL;
278     drag_tool = NULL;
279     color_picker_tool = NULL;
280     edit_cp_tool = NULL;
281     overview_drag_tool = NULL;
282     identify_tool = NULL ;
283     camera_tool = NULL;
284     panosphere_overview_identify_tool = NULL;
285     plane_overview_identify_tool = NULL;
286     difference_tool = NULL;
287     plane_difference_tool = NULL;
288     panosphere_difference_tool = NULL;
289     pano_mask_tool = NULL;
290     preview_guide_tool = NULL;
291     m_guiLevel=GUI_SIMPLE;
292 #ifdef __WXGTK__
293     loadedLayout=false;
294 #endif
295 
296     m_mode = -1;
297     m_oldProjFormat = -1;
298     // add a status bar
299     CreateStatusBar(3);
300     int widths[3] = {-3, 150, 150};
301     SetStatusWidths(3, widths);
302     SetStatusText(wxT(""),1);
303     SetStatusText(wxT(""),2);
304     wxConfigBase * cfg = wxConfigBase::Get();
305 
306     wxPanel *tool_panel = wxXmlResource::Get()->LoadPanel(this,wxT("mode_panel"));
307     XRCCTRL(*this,"preview_center_tool",wxButton)->SetBitmapMargins(0,0);
308     XRCCTRL(*this,"preview_fit_pano_tool",wxButton)->SetBitmapMargins(0,0);
309     XRCCTRL(*this,"preview_straighten_pano_tool",wxButton)->SetBitmapMargins(0,0);
310     XRCCTRL(*this,"preview_fit_pano_tool2",wxButton)->SetBitmapMargins(0,0);
311     XRCCTRL(*this,"preview_autocrop_tool",wxButton)->SetBitmapMargins(0,0);
312     XRCCTRL(*this,"preview_stack_autocrop_tool",wxButton)->SetBitmapMargins(0,0);
313 
314     m_tool_notebook = XRCCTRL(*this, "mode_toolbar_notebook", wxNotebook);
315     m_identify_togglebutton = XRCCTRL(*this, "preview_identify_toggle_button", wxToggleButton);
316     m_colorpicker_togglebutton = XRCCTRL(*this, "preview_color_picker_toggle_button", wxToggleButton);
317     m_editCP_togglebutton = XRCCTRL(*this, "preview_edit_cp_toggle_button", wxToggleButton);
318     wxBitmap bitmap;
319 #if !wxCHECK_VERSION(3,1,1)
320     bitmap.LoadFile(huginApp::Get()->GetXRCPath() + wxT("data/identify_tool.png"), wxBITMAP_TYPE_PNG);
321     m_identify_togglebutton->SetBitmap(bitmap, wxTOP);
322     bitmap.LoadFile(huginApp::Get()->GetXRCPath() + wxT("data/preview_white_balance.png"), wxBITMAP_TYPE_PNG);
323     m_colorpicker_togglebutton->SetBitmap(bitmap, wxTOP);
324     bitmap.LoadFile(huginApp::Get()->GetXRCPath() + wxT("data/preview_control_point_tool.png"), wxBITMAP_TYPE_PNG);
325     m_editCP_togglebutton->SetBitmap(bitmap, wxTOP);
326 #endif
327 
328     //build menu bar
329 #ifdef __WXMAC__
330     wxApp::s_macExitMenuItemId = XRCID("action_exit_preview");
331 #endif
332     wxMenuBar* simpleMenu=wxXmlResource::Get()->LoadMenuBar(this, wxT("preview_simple_menu"));
333     m_filemenuSimple=wxXmlResource::Get()->LoadMenu(wxT("preview_file_menu"));
334     m_filemenuAdvanced = wxXmlResource::Get()->LoadMenu(wxT("preview_file_menu_advanced"));
335     MainFrame::Get()->GetFileHistory()->UseMenu(m_filemenuSimple->FindItem(XRCID("menu_mru_preview"))->GetSubMenu());
336     MainFrame::Get()->GetFileHistory()->UseMenu(m_filemenuAdvanced->FindItem(XRCID("menu_mru_preview"))->GetSubMenu());
337     MainFrame::Get()->GetFileHistory()->AddFilesToMenu();
338     simpleMenu->Insert(0, m_filemenuSimple, _("&File"));
339     SetMenuBar(simpleMenu);
340 
341     // initialize preview background color
342     wxString c = cfg->Read(wxT("/GLPreviewFrame/PreviewBackground"),wxT(HUGIN_PREVIEW_BACKGROUND));
343     m_preview_background_color = wxColour(c);
344     XRCCTRL(*this, "preview_background", wxColourPickerCtrl)->SetColour(m_preview_background_color);
345     XRCCTRL(*this, "preview_background", wxColourPickerCtrl)->Refresh();
346     XRCCTRL(*this, "preview_background", wxColourPickerCtrl)->Update();
347 
348     m_topsizer = new wxBoxSizer( wxVERTICAL );
349 
350     wxPanel * toggle_panel = new wxPanel(this);
351 
352     bool overview_hidden;
353     cfg->Read(wxT("/GLPreviewFrame/overview_hidden"), &overview_hidden, false);
354     GetMenuBar()->FindItem(XRCID("action_show_overview"))->Check(!overview_hidden);
355 
356     m_ToggleButtonSizer = new wxStaticBoxSizer(
357         new wxStaticBox(toggle_panel, -1, _("displayed images")),
358     wxHORIZONTAL );
359     toggle_panel->SetSizer(m_ToggleButtonSizer);
360 
361 	m_ButtonPanel = new wxScrolledWindow(toggle_panel, -1, wxDefaultPosition, wxDefaultSize, wxTAB_TRAVERSAL);
362 	//Horizontal scroll bars only
363 	m_ButtonPanel->SetScrollRate(10, 0);
364     m_ButtonSizer = new wxBoxSizer(wxHORIZONTAL);
365     m_ButtonPanel->SetAutoLayout(true);
366 	m_ButtonPanel->SetSizer(m_ButtonSizer);
367 
368     wxPanel *panel = new wxPanel(toggle_panel);
369     bitmap.LoadFile(huginApp::Get()->GetXRCPath()+wxT("data/preview_show_all.png"),wxBITMAP_TYPE_PNG);
370     wxString showAllLabel(_("All"));
371     showAllLabel.Append(wxT("\u25bc"));
372     m_selectAllButton = new wxButton(panel, ID_SHOW_ALL, showAllLabel, wxDefaultPosition, wxDefaultSize, wxBU_EXACTFIT);
373     m_selectAllButton->SetBitmap(bitmap, wxLEFT);
374     m_selectAllButton->SetBitmapMargins(0, 0);
375     m_selectAllButton->Connect(wxEVT_CONTEXT_MENU, wxContextMenuEventHandler(GLPreviewFrame::OnSelectContextMenu), NULL, this);
376     m_selectAllMenu = wxXmlResource::Get()->LoadMenu(wxT("preview_select_menu"));
377     // read last used setting
378     long mode = cfg->Read(wxT("/GLPreviewFrame/SelectAllMode"), 0l);
379     m_selectAllMode = static_cast<SelectAllMode>(mode);
380     switch (m_selectAllMode)
381     {
382         case SELECT_MEDIAN_IMAGES:
383             m_selectAllMenu->Check(XRCID("selectMenu_selectMedian"), true);
384             break;
385         case SELECT_DARKEST_IMAGES:
386             m_selectAllMenu->Check(XRCID("selectMenu_selectDarkest"), true);
387             break;
388         case SELECT_BRIGHTEST_IMAGES:
389             m_selectAllMenu->Check(XRCID("selectMenu_selectBrightest"), true);
390             break;
391         case SELECT_ALL_IMAGES:
392         default:
393             m_selectAllMenu->Check(XRCID("selectMenu_selectAll"), true);
394             break;
395     };
396     m_selectKeepSelection = (cfg->Read(wxT("/GLPreviewFrame/SelectAllKeepSelection"), 1l) == 1l);
397     if (m_selectKeepSelection)
398     {
399         m_selectAllMenu->Check(XRCID("selectMenu_keepCurrentSelection"), true);
400     }
401     else
402     {
403         m_selectAllMenu->Check(XRCID("selectMenu_resetSelection"), true);
404     };
405     bitmap.LoadFile(huginApp::Get()->GetXRCPath()+wxT("data/preview_show_none.png"),wxBITMAP_TYPE_PNG);
406     wxButton* select_none=new wxButton(panel,ID_SHOW_NONE,_("None"),wxDefaultPosition,wxDefaultSize,wxBU_EXACTFIT);
407     select_none->SetBitmap(bitmap,wxLEFT);
408     select_none->SetBitmapMargins(0,0);
409 
410     wxBoxSizer *sizer = new wxBoxSizer(wxHORIZONTAL);
411     sizer->Add(m_selectAllButton,0,wxALIGN_CENTER_VERTICAL | wxLEFT | wxTOP | wxBOTTOM,5);
412     sizer->Add(select_none,0,wxALIGN_CENTER_VERTICAL | wxRIGHT | wxTOP | wxBOTTOM,5);
413     panel->SetSizer(sizer);
414     m_ToggleButtonSizer->Add(panel, 0, wxALIGN_CENTER_VERTICAL);
415     m_ToggleButtonSizer->Add(m_ButtonPanel, 1, wxALIGN_CENTER_VERTICAL, 0);
416 
417     m_topsizer->Add(tool_panel, 0, wxEXPAND | wxALL, 2);
418     m_topsizer->Add(toggle_panel, 0, wxEXPAND | wxBOTTOM, 5);
419 
420     m_infoBar = new wxInfoBar(this);
421     m_infoBar->AddButton(ID_HIDE_HINTS,_("Hide"));
422     m_infoBar->Connect(ID_HIDE_HINTS,wxEVT_COMMAND_BUTTON_CLICKED,wxCommandEventHandler(GLPreviewFrame::OnHideProjectionHints),NULL,this);
423     m_topsizer->Add(m_infoBar, 0, wxEXPAND);
424 
425     //create panel that will hold gl canvases
426     wxPanel * vis_panel = new wxPanel(this);
427 
428     wxPanel * preview_panel = new wxPanel(vis_panel);
429     wxPanel * overview_panel = new wxPanel(vis_panel);
430 
431     // create our Viewers
432     int args[] = {WX_GL_RGBA, WX_GL_DOUBLEBUFFER, 0};
433     m_GLPreview = new GLPreview(preview_panel, pano, args, this);
434     m_GLOverview = new GLOverview(overview_panel, pano, args, this, m_GLPreview->GetContext());
435     m_GLOverview->SetMode(GLOverview::PANOSPHERE);
436 
437 #ifdef __WXGTK__
438     // on wxGTK we can not create the OpenGL context with a hidden window
439     // therefore we need to create the overview window open and later hide it
440     overview_hidden=false;
441 #endif
442     m_GLOverview->SetActive(!overview_hidden);
443 
444     // set the AUI manager to our panel
445     m_mgr = new GLwxAuiManager(this, m_GLPreview, m_GLOverview);
446     m_mgr->SetManagedWindow(vis_panel);
447     vis_panel->SetMinSize(wxSize(200,150));
448 
449     //create the sizer for the preview
450     wxFlexGridSizer * flexSizer = new wxFlexGridSizer(2,0,5,5);
451     flexSizer->AddGrowableCol(0);
452     flexSizer->AddGrowableRow(0);
453 
454     //overview sizer
455     wxBoxSizer * overview_sizer = new wxBoxSizer(wxVERTICAL);
456 
457 
458     flexSizer->Add(m_GLPreview,
459                   1,        // not vertically stretchable
460                   wxEXPAND | // horizontally stretchable
461                   wxALL,    // draw border all around
462                   5);       // border width
463 
464     m_VFOVSlider = new wxSlider(preview_panel, -1, 1,
465                                 1, 180,
466                                 wxDefaultPosition, wxDefaultSize,
467                                 wxSL_VERTICAL | wxSL_AUTOTICKS,
468                                 wxDefaultValidator,
469                                 _("VFOV"));
470     m_VFOVSlider->SetLineSize(1);
471     m_VFOVSlider->SetPageSize(10);
472     m_VFOVSlider->SetTickFreq(5);
473     m_VFOVSlider->SetToolTip(_("drag to change the vertical field of view"));
474 
475     flexSizer->Add(m_VFOVSlider, 0, wxEXPAND);
476 
477     m_HFOVSlider = new wxSlider(preview_panel, -1, 1,
478                                 1, 360,
479                                 wxDefaultPosition, wxDefaultSize,
480                                 wxSL_HORIZONTAL | wxSL_AUTOTICKS,
481                                 wxDefaultValidator,
482                                 _("HFOV"));
483     m_HFOVSlider->SetPageSize(10);
484     m_HFOVSlider->SetLineSize(1);
485     m_HFOVSlider->SetTickFreq(5);
486 
487     m_HFOVSlider->SetToolTip(_("drag to change the horizontal field of view"));
488 
489     m_HFOVText = XRCCTRL(*this, "pano_text_hfov" ,wxTextCtrl);
490     DEBUG_ASSERT(m_HFOVText);
491     m_HFOVText->PushEventHandler(new TextKillFocusHandler(this));
492     m_VFOVText = XRCCTRL(*this, "pano_text_vfov" ,wxTextCtrl);
493     DEBUG_ASSERT(m_VFOVText);
494     m_VFOVText->PushEventHandler(new TextKillFocusHandler(this));
495 
496     m_ROILeftTxt = XRCCTRL(*this, "pano_val_roi_left", wxTextCtrl);
497     DEBUG_ASSERT(m_ROILeftTxt);
498     m_ROILeftTxt->PushEventHandler(new TextKillFocusHandler(this));
499 
500     m_ROIRightTxt = XRCCTRL(*this, "pano_val_roi_right", wxTextCtrl);
501     DEBUG_ASSERT(m_ROIRightTxt);
502     m_ROIRightTxt->PushEventHandler(new TextKillFocusHandler(this));
503 
504     m_ROITopTxt = XRCCTRL(*this, "pano_val_roi_top", wxTextCtrl);
505     DEBUG_ASSERT(m_ROITopTxt);
506     m_ROITopTxt->PushEventHandler(new TextKillFocusHandler(this));
507 
508     m_ROIBottomTxt = XRCCTRL(*this, "pano_val_roi_bottom", wxTextCtrl);
509     DEBUG_ASSERT(m_ROIBottomTxt);
510     m_ROIBottomTxt->PushEventHandler(new TextKillFocusHandler(this));
511 
512     m_GuideChoiceCrop = XRCCTRL(*this, "preview_guide_choice_crop", wxChoice);
513     m_GuideChoiceProj = XRCCTRL(*this, "preview_guide_choice_proj", wxChoice);
514     m_GuideChoiceDrag = XRCCTRL(*this, "preview_guide_choice_drag", wxChoice);
515     int guide=cfg->Read(wxT("/GLPreviewFrame/guide"),0l);
516     m_GuideChoiceCrop->SetSelection(guide);
517     m_GuideChoiceProj->SetSelection(guide);
518     m_GuideChoiceDrag->SetSelection(guide);
519 
520     flexSizer->Add(m_HFOVSlider, 0, wxEXPAND);
521 
522     m_overviewCommandPanel = wxXmlResource::Get()->LoadPanel(overview_panel,wxT("overview_command_panel"));
523     m_OverviewModeChoice = XRCCTRL(*this, "overview_mode_choice", wxChoice);
524     m_overviewCommandPanel->SetSize(0,0,200,20,wxSIZE_AUTO_WIDTH);
525 
526     overview_sizer->Add(m_overviewCommandPanel, 0, wxEXPAND);
527     overview_sizer->Add(m_GLOverview, 1, wxEXPAND);
528 
529     bool showGrid;
530     cfg->Read(wxT("/GLPreviewFrame/showPreviewGrid"),&showGrid,true);
531     GetMenuBar()->FindItem(XRCID("action_show_grid"))->Check(showGrid);
532 
533     preview_panel->SetSizer(flexSizer);
534     overview_panel->SetSizer(overview_sizer);
535 
536     m_mgr->AddPane(preview_panel,
537         wxAuiPaneInfo(
538             ).Name(wxT("preview")
539             ).MinSize(300,200
540             ).CloseButton(false
541             ).CaptionVisible(false
542             ).Caption(_("Preview")
543             ).Floatable(false
544             ).Dockable(false
545             ).Center(
546             )
547         );
548 
549     m_mgr->AddPane(overview_panel,
550         wxAuiPaneInfo(
551             ).Name(wxT("overview")
552             ).MinSize(300,200
553             ).CloseButton(false
554             ).CaptionVisible(
555             ).Caption(_("Overview")
556             ).FloatingSize(100,100
557             ).FloatingPosition(500,500
558             ).Dockable(true
559             ).PinButton(
560             ).Left(
561             ).Show(!overview_hidden
562             )
563         );
564 
565 
566     m_topsizer->Add(vis_panel, 1, wxEXPAND);
567 
568     //assistant related controls
569     m_imagesText = XRCCTRL(*this, "ass_load_images_text", wxStaticText);
570     DEBUG_ASSERT(m_imagesText);
571 
572     m_lensTypeChoice = XRCCTRL(*this, "ass_lens_type", wxChoice);
573     DEBUG_ASSERT(m_lensTypeChoice);
574     FillLensProjectionList(m_lensTypeChoice);
575     m_lensTypeChoice->SetSelection(0);
576 
577     m_focalLengthText = XRCCTRL(*this, "ass_focal_length", wxTextCtrl);
578     DEBUG_ASSERT(m_focalLengthText);
579     m_focalLengthText->PushEventHandler(new TextKillFocusHandler(this));
580 
581     m_cropFactorText = XRCCTRL(*this, "ass_crop_factor", wxTextCtrl);
582     DEBUG_ASSERT(m_cropFactorText);
583     m_cropFactorText->PushEventHandler(new TextKillFocusHandler(this));
584 
585     m_alignButton = XRCCTRL(*this, "ass_align_button", wxButton);
586     DEBUG_ASSERT(m_alignButton);
587     m_alignButton->Disable();
588 
589     m_createButton = XRCCTRL(*this, "ass_create_button", wxButton);
590     DEBUG_ASSERT(m_createButton);
591     m_createButton->Disable();
592 
593     m_ProjectionChoice = XRCCTRL(*this,"projection_choice",wxChoice);
594 
595     /* populate with all available projection types */
596     int nP = panoProjectionFormatCount();
597     for(int n=0; n < nP; n++) {
598         pano_projection_features proj;
599         if (panoProjectionFeaturesQuery(n, &proj)) {
600             wxString str2(proj.name, wxConvLocal);
601             m_ProjectionChoice->Append(wxGetTranslation(str2));
602         }
603     }
604     m_ProjectionChoice->SetSelection(2);
605 
606     //////////////////////////////////////////////////////
607     // Blend mode
608     // remaining blend mode should be added after OpenGL context has been created
609     // see FillBlendMode()
610     m_differenceIndex = -1;
611     // create choice item
612     m_BlendModeChoice = XRCCTRL(*this,"blend_mode_choice",wxChoice);
613     m_BlendModeChoice->Append(_("normal"));
614     m_BlendModeChoice->SetSelection(0);
615 
616     m_DragModeChoice = XRCCTRL(*this, "drag_mode_choice", wxChoice);
617     SetGuiLevel(GUI_SIMPLE);
618     bool individualDrag;
619     cfg->Read(wxT("/GLPreviewFrame/individualDragMode"), &individualDrag, false);
620     if(individualDrag)
621     {
622         m_DragModeChoice->SetSelection(1);
623     }
624     else
625     {
626         m_DragModeChoice->SetSelection(0);
627     };
628     // default drag mode
629     GLPreviewFrame::DragChoiceLayout(0);
630 
631     // TODO implement hdr display in OpenGL, if possible?
632     // Disabled until someone can figure out HDR display in OpenGL.
633     /*
634     //////////////////////////////////////////////////////
635     // LDR, HDR
636     blendModeSizer->Add(new wxStaticText(this, -1, _("Output:")),
637                         0,        // not vertically strechable
638                         wxALL | wxALIGN_CENTER_VERTICAL, // draw border all around
639                         5);       // border width
640 
641     m_choices[0] = _("LDR");
642     m_choices[1] = _("HDR");
643     m_outputModeChoice = new wxChoice(this, ID_OUTPUTMODE_CHOICE,
644                                       wxDefaultPosition, wxDefaultSize,
645                                       2, m_choices);
646     m_outputModeChoice->SetSelection(0);
647     blendModeSizer->Add(m_outputModeChoice,
648                         0,
649                         wxALL | wxALIGN_CENTER_VERTICAL,
650                         5);
651     */
652 
653     /////////////////////////////////////////////////////
654     // exposure
655     m_defaultExposureBut = XRCCTRL(*this, "exposure_default_button", wxBitmapButton);
656 
657     m_exposureTextCtrl = XRCCTRL(*this, "exposure_text", wxTextCtrl);
658     m_exposureTextCtrl->PushEventHandler(new TextKillFocusHandler(this));
659 
660     m_exposureSpinBut = XRCCTRL(*this, "exposure_spin", wxSpinButton);
661     m_exposureSpinBut->SetValue(0);
662     m_exposureSpinBut->SetMaxSize(wxSize(-1, m_exposureTextCtrl->GetSize().GetHeight()));
663 
664     m_rangeCompressionTextCtrl = XRCCTRL(*this, "range_compression_text", wxTextCtrl);
665     m_rangeCompressionTextCtrl->PushEventHandler(new TextKillFocusHandler(this));
666 
667     m_rangeCompressionSpinBut = XRCCTRL(*this, "range_compression_spin", wxSpinButton);
668     m_rangeCompressionSpinBut->SetValue(0);
669     m_rangeCompressionSpinBut->SetMaxSize(wxSize(-1, m_rangeCompressionTextCtrl->GetSize().GetHeight()));
670 
671     m_projection_panel = XRCCTRL(*this, "projection_panel", wxPanel);
672     m_projParamSizer = new wxBoxSizer(wxHORIZONTAL);
673 
674     wxBitmapButton * resetProjButton=new wxBitmapButton(m_projection_panel, PROJ_PARAM_RESET_ID,
675         wxArtProvider::GetBitmap(wxART_REDO));
676     resetProjButton->SetToolTip(_("Resets the projection's parameters to their default values."));
677     m_projParamSizer->Add(resetProjButton, 0, wxLEFT | wxRIGHT | wxALIGN_CENTER_VERTICAL, 5);
678 
679     m_projParamNamesLabel.resize(PANO_PROJECTION_MAX_PARMS);
680     m_projParamTextCtrl.resize(PANO_PROJECTION_MAX_PARMS);
681     m_projParamSlider.resize(PANO_PROJECTION_MAX_PARMS);
682 
683     for (int i=0; i < PANO_PROJECTION_MAX_PARMS; i++) {
684 
685         wxBoxSizer* paramBoxSizer = new wxBoxSizer(wxVERTICAL);
686         m_projParamNamesLabel[i] = new wxStaticText(m_projection_panel, PROJ_PARAM_NAMES_ID+i, _("param:"));
687         paramBoxSizer->Add(m_projParamNamesLabel[i],
688                         0,        // not vertically strechable
689                         wxLEFT | wxRIGHT, // draw border all around
690                         5);       // border width
691         m_projParamTextCtrl[i] = new wxTextCtrl(m_projection_panel, PROJ_PARAM_VAL_ID+i, wxT("0"),
692                                     wxDefaultPosition, wxSize(35,-1), wxTE_PROCESS_ENTER);
693         m_projParamTextCtrl[i]->PushEventHandler(new TextKillFocusHandler(this));
694         paramBoxSizer->Add(m_projParamTextCtrl[i],
695                         0,        // not vertically strechable
696                         wxLEFT | wxRIGHT, // draw border all around
697                         5);       // border width
698 
699         m_projParamSizer->Add(paramBoxSizer);
700         m_projParamSlider[i] = new wxSlider(m_projection_panel, PROJ_PARAM_SLIDER_ID+i, 0, -90, 90);
701         m_projParamSizer->Add(m_projParamSlider[i],
702                         1,        // not vertically strechable
703                         wxLEFT | wxRIGHT | wxALIGN_CENTER_VERTICAL , // draw border all around
704                         5);       // border width
705     }
706 
707     m_projection_panel->GetSizer()->Add(m_projParamSizer, 1, wxALIGN_CENTER_VERTICAL);
708 
709     // do not show projection param sizer
710     m_projection_panel->GetSizer()->Show(m_projParamSizer, false, true);
711 
712     // the initial size as calculated by the sizers
713     this->SetSizer( m_topsizer );
714     m_topsizer->SetSizeHints( this );
715 
716     // set the minimize icon
717 #ifdef __WXMSW__
718     wxIcon myIcon(huginApp::Get()->GetXRCPath() + wxT("data/hugin.ico"),wxBITMAP_TYPE_ICO);
719 #else
720     wxIcon myIcon(huginApp::Get()->GetXRCPath() + wxT("data/hugin.png"),wxBITMAP_TYPE_PNG);
721 #endif
722     SetIcon(myIcon);
723 
724     m_pano.addObserver(this);
725 
726     RestoreFramePosition(this, wxT("GLPreviewFrame"));
727 
728 #ifdef __WXMSW__
729     // wxFrame does have a strange background color on Windows..
730     this->SetBackgroundColour(m_GLPreview->GetBackgroundColour());
731 #endif
732 
733     m_showProjectionHints = cfg->Read(wxT("/GLPreviewFrame/ShowProjectionHints"), HUGIN_SHOW_PROJECTION_HINTS) == 1;
734     m_degDigits = wxConfigBase::Get()->Read(wxT("/General/DegreeFractionalDigitsEdit"),3);
735 
736      // tell the manager to "commit" all the changes just made
737     m_mgr->Update();
738 
739     if (cfg->Read(wxT("/GLPreviewFrame/isShown"), 0l) != 0)
740     {
741 #if defined __WXMSW__ || defined __WXMAC__
742         InitPreviews();
743         Show();
744 #else
745         Show();
746         LoadOpenGLLayout();
747 #endif
748     }
749     SetDropTarget(new PanoDropTarget(m_pano, true));
750 #if defined __WXMAC__
751     Layout();
752     Update();
753 #endif
754 }
755 
LoadOpenGLLayout()756 void GLPreviewFrame::LoadOpenGLLayout()
757 {
758 #ifdef __WXGTK__
759     if(loadedLayout)
760     {
761         return;
762     };
763     loadedLayout=true;
764 #endif
765     wxString OpenGLLayout=wxConfig::Get()->Read(wxT("/GLPreviewFrame/OpenGLLayout"));
766     if(!OpenGLLayout.IsEmpty())
767     {
768         m_mgr->LoadPerspective(OpenGLLayout,true);
769 #ifdef __WXGTK__
770         if(!GetMenuBar()->FindItem(XRCID("action_show_overview"))->IsChecked())
771         {
772             wxAuiPaneInfo &inf = m_mgr->GetPane(wxT("overview"));
773             if (inf.IsOk())
774             {
775                 inf.Hide();
776             }
777             m_GLOverview->SetActive(false);
778         };
779         m_mgr->Update();
780         wxShowEvent dummy;
781         dummy.SetShow(true);
782         OnShowEvent(dummy);
783 #endif
784     };
785     FillBlendChoice();
786 };
787 
StorePositionAndSize()788 void GLPreviewFrame::StorePositionAndSize()
789 {
790     wxConfigBase * cfg = wxConfigBase::Get();
791 
792     StoreFramePosition(this, wxT("GLPreviewFrame"));
793 
794     if ( (!this->IsIconized()) && (! this->IsMaximized()) && this->IsShown()) {
795         cfg->Write(wxT("/GLPreviewFrame/isShown"), 1l);
796     } else {
797         cfg->Write(wxT("/GLPreviewFrame/isShown"), 0l);
798     }
799 
800     cfg->Write(wxT("/GLPreviewFrame/blendMode"), m_BlendModeChoice->GetSelection());
801     cfg->Write(wxT("/GLPreviewFrame/OpenGLLayout"), m_mgr->SavePerspective());
802     cfg->Write(wxT("/GLPreviewFrame/overview_hidden"), !(GetMenuBar()->FindItem(XRCID("action_show_overview"))->IsChecked()));
803     cfg->Write(wxT("/GLPreviewFrame/showPreviewGrid"), GetMenuBar()->FindItem(XRCID("action_show_grid"))->IsChecked());
804     cfg->Write(wxT("/GLPreviewFrame/individualDragMode"), individualDragging());
805     cfg->Write(wxT("/GLPreviewFrame/guide"),m_GuideChoiceProj->GetSelection());
806 };
807 
~GLPreviewFrame()808 GLPreviewFrame::~GLPreviewFrame()
809 {
810     DEBUG_TRACE("dtor writing config");
811     StorePositionAndSize();
812 
813     // delete all of the tools. When the preview is never used we never get an
814     // OpenGL context and therefore don't create the tools.
815     if (crop_tool)
816     {
817         preview_helper->DeactivateTool(crop_tool); delete crop_tool;
818         preview_helper->DeactivateTool(drag_tool); delete drag_tool;
819         preview_helper->DeactivateTool(color_picker_tool); delete color_picker_tool;
820         preview_helper->DeactivateTool(edit_cp_tool); delete edit_cp_tool;
821         preview_helper->DeactivateTool(identify_tool); delete identify_tool;
822         preview_helper->DeactivateTool(difference_tool); delete difference_tool;
823         preview_helper->DeactivateTool(pano_mask_tool); delete pano_mask_tool;
824         preview_helper->DeactivateTool(preview_control_point_tool); delete preview_control_point_tool;
825         preview_helper->DeactivateTool(m_preview_layoutLinesTool); delete m_preview_layoutLinesTool;
826         preview_helper->DeactivateTool(preview_projection_grid); delete preview_projection_grid;
827         preview_helper->DeactivateTool(preview_guide_tool); delete preview_guide_tool;
828     }
829     if (panosphere_overview_identify_tool) {
830         panosphere_overview_helper->DeactivateTool(overview_drag_tool); delete overview_drag_tool;
831         panosphere_overview_helper->DeactivateTool(panosphere_overview_camera_tool); delete panosphere_overview_camera_tool;
832         panosphere_overview_helper->DeactivateTool(panosphere_overview_identify_tool); delete panosphere_overview_identify_tool;
833         panosphere_overview_helper->DeactivateTool(panosphere_sphere_tool); delete panosphere_sphere_tool;
834         panosphere_overview_helper->DeactivateTool(overview_projection_grid); delete overview_projection_grid;
835         panosphere_overview_helper->DeactivateTool(overview_outlines_tool); delete overview_outlines_tool;
836         panosphere_overview_helper->DeactivateTool(panosphere_difference_tool); delete panosphere_difference_tool;
837         panosphere_overview_helper->DeactivateTool(m_panosphere_layoutLinesTool); delete m_panosphere_layoutLinesTool;
838         panosphere_overview_helper->DeactivateTool(panosphere_control_point_tool); delete panosphere_control_point_tool;
839     }
840     if (plane_overview_identify_tool) {
841         plane_overview_helper->DeactivateTool(plane_overview_identify_tool); delete plane_overview_identify_tool;
842         plane_overview_helper->DeactivateTool(plane_overview_camera_tool); delete plane_overview_camera_tool;
843         plane_overview_helper->DeactivateTool(plane_difference_tool); delete plane_difference_tool;
844         plane_overview_helper->DeactivateTool(plane_overview_outlines_tool); delete plane_overview_outlines_tool;
845         plane_overview_helper->DeactivateTool(m_plane_layoutLinesTool); delete m_plane_layoutLinesTool;
846         plane_overview_helper->DeactivateTool(plane_control_point_tool); delete plane_control_point_tool;
847     }
848     m_focalLengthText->PopEventHandler(true);
849     m_cropFactorText->PopEventHandler(true);
850     m_exposureTextCtrl->PopEventHandler(true);
851     m_HFOVText->PopEventHandler(true);
852     m_rangeCompressionTextCtrl->PopEventHandler(true);
853     m_VFOVText->PopEventHandler(true);
854     m_ROILeftTxt->PopEventHandler(true);
855     m_ROIRightTxt->PopEventHandler(true);
856     m_ROITopTxt->PopEventHandler(true);
857     m_ROIBottomTxt->PopEventHandler(true);
858     for (int i=0; i < m_ToggleButtons.size(); i++)
859     {
860         m_ToggleButtons[i]->PopEventHandler(true);
861         m_GroupToggleButtons[i]->PopEventHandler(true);
862     }
863     for (int i=0; i < PANO_PROJECTION_MAX_PARMS; i++)
864     {
865         m_projParamTextCtrl[i]->PopEventHandler(true);
866     };
867     m_pano.removeObserver(this);
868 
869      // deinitialize the frame manager
870      m_mgr->UnInit();
871      if (m_mgr) {
872         delete m_mgr;
873      }
874      if(m_guiLevel!=GUI_SIMPLE)
875      {
876          delete m_filemenuSimple;
877      }
878      else
879      {
880          delete m_filemenuAdvanced;
881      };
882 
883     DEBUG_TRACE("dtor end");
884 }
885 
InitPreviews()886 void GLPreviewFrame::InitPreviews()
887 {
888     if(preview_helper==NULL || panosphere_overview_helper==NULL || plane_overview_helper==NULL)
889     {
890         m_GLPreview->SetUpContext();
891         m_GLOverview->SetUpContext();
892         LoadOpenGLLayout();
893     };
894 };
895 
896 /**
897 * Update tools and GUI elements according to blend mode choice
898 */
updateBlendMode()899 void GLPreviewFrame::updateBlendMode()
900 {
901     if (m_BlendModeChoice != NULL)
902     {
903         int index=m_BlendModeChoice->GetSelection();
904         if(index==0)
905         {
906             // normal mode
907             if (preview_helper != NULL
908                 && difference_tool != NULL)
909             {
910                 preview_helper->DeactivateTool(difference_tool);
911             };
912 
913             if (panosphere_overview_helper != NULL
914                 && panosphere_difference_tool != NULL)
915             {
916                 panosphere_overview_helper->DeactivateTool(panosphere_difference_tool);
917             };
918 
919             if (plane_overview_helper != NULL
920                 && plane_difference_tool != NULL)
921             {
922                 plane_overview_helper->DeactivateTool(plane_difference_tool);
923             };
924 
925 
926         }
927         else
928         {
929             if(index==m_differenceIndex)
930             {
931                 // difference mode
932                 if (preview_helper != NULL
933                     && identify_tool != NULL
934                     && difference_tool != NULL )
935                 {
936                     identify_tool->setConstantOn(false);
937 //                    preview_helper->DeactivateTool(identify_tool);
938                     m_identify_togglebutton->SetValue(false);
939                     preview_helper->ActivateTool(difference_tool);
940                     CleanButtonColours();
941                 };
942 
943                 // difference mode
944                 if (panosphere_overview_helper != NULL
945                     && panosphere_overview_identify_tool != NULL
946                     && panosphere_difference_tool != NULL)
947                 {
948 //                    panosphere_overview_helper->DeactivateTool(panosphere_overview_identify_tool);
949                     panosphere_overview_identify_tool->setConstantOn(false);
950                     panosphere_overview_helper->ActivateTool(panosphere_difference_tool);
951                 };
952 
953                 // difference mode
954                 if (plane_overview_helper != NULL
955                     && plane_overview_identify_tool != NULL
956                     && plane_difference_tool != NULL)
957                 {
958 //                    plane_overview_helper->DeactivateTool(plane_overview_identify_tool);
959                     plane_overview_identify_tool->setConstantOn(false);
960                     plane_overview_helper->ActivateTool(plane_difference_tool);
961                 };
962 
963             }
964             else
965             {
966                 DEBUG_WARN("Unknown blend mode selected");
967             };
968         }
969     }
970 }
971 
UpdateRoiDisplay(const HuginBase::PanoramaOptions opts)972 void GLPreviewFrame::UpdateRoiDisplay(const HuginBase::PanoramaOptions opts)
973 {
974     m_ROILeftTxt->ChangeValue(wxString::Format(wxT("%d"), opts.getROI().left() ));
975     m_ROIRightTxt->ChangeValue(wxString::Format(wxT("%d"), opts.getROI().right() ));
976     m_ROITopTxt->ChangeValue(wxString::Format(wxT("%d"), opts.getROI().top() ));
977     m_ROIBottomTxt->ChangeValue(wxString::Format(wxT("%d"), opts.getROI().bottom() ));
978 };
979 
panoramaChanged(HuginBase::Panorama & pano)980 void GLPreviewFrame::panoramaChanged(HuginBase::Panorama &pano)
981 {
982     m_lensTypeChoice->Enable(pano.getNrOfImages()>0);
983     m_focalLengthText->Enable(pano.getNrOfImages()>0);
984     m_cropFactorText->Enable(pano.getNrOfImages()>0);
985     m_alignButton->Enable(pano.getNrOfImages()>0);
986 
987     if(pano.getNrOfImages()==0)
988     {
989         m_createButton->Disable();
990         m_imagesText->SetLabel(_("No images loaded."));
991     }
992     else
993     {
994         bool enableCreate = false;
995         // check if images are at position 0
996         for (size_t i = 0; i < pano.getNrOfImages(); ++i)
997         {
998             const HuginBase::SrcPanoImage& img = pano.getImage(i);
999             if (img.getYaw() != 0.0 || img.getPitch() != 0.0 || img.getRoll() != 0.0)
1000             {
1001                 enableCreate = true;
1002                 break;
1003             };
1004         };
1005         if (!enableCreate && pano.getNrOfImages() == 1)
1006         {
1007             // some more checks for single image projects
1008             if (pano.getOptions().getProjection() != HuginBase::PanoramaOptions::EQUIRECTANGULAR)
1009             {
1010                 enableCreate = true;
1011             };
1012             if (pano.getOptions().getROI() != vigra::Rect2D(pano.getOptions().getSize()))
1013             {
1014                 enableCreate = true;
1015             };
1016         };
1017         // disable create button after loading images
1018         const std::string lastCmd=PanoCommand::GlobalCmdHist::getInstance().getLastCommandName();
1019         if (lastCmd == "add images" || lastCmd== "add and distribute images")
1020         {
1021             enableCreate = false;
1022         }
1023         m_createButton->Enable(enableCreate);
1024 
1025         // in wxWidgets 2.9, format must have types that exactly match.
1026         // However std::size_t could be any unsiged integer, so we cast it to
1027         // unsigned long.int to be on the safe side.
1028         wxString imgMsg = wxString::Format(_("%lu images loaded."), (unsigned long int) pano.getNrOfImages());
1029         m_imagesText->SetLabel(imgMsg);
1030 
1031         // update data in lens display
1032         const HuginBase::SrcPanoImage& img = pano.getImage(0);
1033         SelectListValue(m_lensTypeChoice, img.getProjection());
1034         if (img.getProjection() == HuginBase::SrcPanoImage::EQUIRECTANGULAR || img.getProjection() == HuginBase::SrcPanoImage::PANORAMIC)
1035         {
1036             XRCCTRL(*this, "ass_text_focal_length", wxStaticText)->SetLabel(_("Field of View:"));
1037             m_focalLengthText->ChangeValue(hugin_utils::doubleTowxString(img.getHFOV(), m_degDigits));
1038             XRCCTRL(*this, "ass_text_unit_focal_length", wxStaticText)->SetLabel(_("deg"));
1039             XRCCTRL(*this, "ass_text_crop_factor", wxStaticText)->Hide();
1040             m_cropFactorText->Hide();
1041             XRCCTRL(*this, "ass_text_unit_crop_factor", wxStaticText)->Hide();
1042         }
1043         else
1044         {
1045             XRCCTRL(*this, "ass_text_focal_length", wxStaticText)->SetLabel(_("Focal length:"));
1046             double focal_length = HuginBase::SrcPanoImage::calcFocalLength(img.getProjection(), img.getHFOV(), img.getCropFactor(), img.getSize());
1047             // use ChangeValue explicit, SetValue would create EVT_TEXT event which collides with our TextKillFocusHandler
1048             m_focalLengthText->ChangeValue(hugin_utils::doubleTowxString(focal_length, m_degDigits));
1049             XRCCTRL(*this, "ass_text_unit_focal_length", wxStaticText)->SetLabel("mm");
1050             XRCCTRL(*this, "ass_text_crop_factor", wxStaticText)->Show();
1051             m_cropFactorText->Show();
1052             m_cropFactorText->ChangeValue(hugin_utils::doubleTowxString(img.getCropFactor(), m_degDigits));
1053             XRCCTRL(*this, "ass_text_unit_crop_factor", wxStaticText)->Show();
1054         };
1055         m_focalLengthText->GetParent()->Layout();
1056     }
1057 
1058     if (pano.getNrOfImages() > 1)
1059     {
1060         // in wxWidgets 2.9, format must have types that exactly match.
1061         // However std::size_t could be any unsiged integer, so we cast it to
1062         // unsigned long.int to be on the safe side.
1063         wxString alignMsg = wxString::Format(_("Images are connected by %lu control points.\n"), (unsigned long int) pano.getCtrlPoints().size());
1064 
1065         if (m_pano.getNrOfCtrlPoints() > 0)
1066         {
1067             // find components..
1068             HuginGraph::ImageGraph graph(m_pano);
1069             const HuginGraph::ImageGraph::Components comps = graph.GetComponents();
1070             if (comps.size() > 1)
1071             {
1072                 alignMsg += wxString::Format(_("%lu unconnected image groups found: %s\n"), static_cast<unsigned long int>(comps.size()), Components2Str(comps).c_str());
1073             }
1074             else
1075             {
1076                 if (m_pano.needsOptimization())
1077                 {
1078                     alignMsg += _("Images or control points have changed, new alignment is needed.");
1079                 }
1080                 else
1081                 {
1082                     HuginBase::CalculateCPStatisticsError calcStats(m_pano, MainFrame::Get()->GetOptimizeOnlyActiveImages(), MainFrame::Get()->GetOptimizeIgnoreLineCp());
1083                     calcStats.run();
1084                     const double max = calcStats.getResultMax();
1085                     const double mean = calcStats.getResultMean();
1086 
1087                     if (max != 0.0)
1088                     {
1089                         alignMsg = alignMsg + wxString::Format(_("Mean error after optimization: %.1f pixel, max: %.1f"), mean, max);
1090                     }
1091                 }
1092             }
1093         }
1094         wxStaticText* statusCtrl = XRCCTRL(*this, "ass_status_text", wxStaticText);
1095         statusCtrl->SetLabel(alignMsg);
1096         statusCtrl->InvalidateBestSize();
1097         m_tool_notebook->GetPage(0)->Layout();
1098         Refresh();
1099     }
1100     else
1101     {
1102         XRCCTRL(*this, "ass_status_text", wxStaticText)->SetLabel(wxT(""));
1103     };
1104 
1105     GetMenuBar()->Enable(XRCID("ID_EDITUNDO"), PanoCommand::GlobalCmdHist::getInstance().canUndo());
1106     GetMenuBar()->Enable(XRCID("ID_EDITREDO"), PanoCommand::GlobalCmdHist::getInstance().canRedo());
1107 
1108     // TODO: update meaningful help text and dynamic links to relevant tabs
1109 
1110     const HuginBase::PanoramaOptions & opts = pano.getOptions();
1111 
1112     wxString projection;
1113     m_ProjectionChoice->SetSelection(opts.getProjection());
1114     m_VFOVSlider->Enable( opts.fovCalcSupported(opts.getProjection()) );
1115 
1116     // No HDR display yet.
1117     /*
1118     m_outputModeChoice->SetSelection(opts.outputMode);
1119     if (opts.outputMode == PanoramaOptions::OUTPUT_HDR) {
1120         m_exposureTextCtrl->Hide();
1121         m_defaultExposureBut->Hide();
1122         m_decExposureBut->Hide();
1123         m_incExposureBut->Hide();
1124     } else {
1125         m_exposureTextCtrl->Show();
1126         m_defaultExposureBut->Show();
1127         m_decExposureBut->Show();
1128         m_incExposureBut->Show();
1129     }*/
1130     m_exposureTextCtrl->ChangeValue(wxString(hugin_utils::doubleToString(opts.outputExposureValue,2).c_str(), wxConvLocal));
1131     m_rangeCompressionTextCtrl->ChangeValue(wxString(hugin_utils::doubleToString(opts.outputRangeCompression, 1).c_str(), wxConvLocal));
1132 
1133     const bool activeImgs = !pano.getActiveImages().empty();
1134 
1135     // TODO: enable display of parameters and set their limits, if projection has some.
1136 
1137     int nParam = opts.m_projFeatures.numberOfParameters;
1138     bool relayout = false;
1139     // if the projection format has changed
1140     if (opts.getProjection() != m_oldProjFormat) {
1141         DEBUG_DEBUG("Projection format changed");
1142         if (nParam) {
1143             // show parameters and update labels.
1144             m_projection_panel->GetSizer()->Show(m_projParamSizer, true, true);
1145             int i;
1146             for (i=0; i < nParam; i++) {
1147                 const pano_projection_parameter * pp = & (opts.m_projFeatures.parm[i]);
1148                 wxString str2(pp->name, wxConvLocal);
1149                 str2 = wxGetTranslation(str2);
1150                 m_projParamNamesLabel[i]->SetLabel(str2);
1151                 m_projParamSlider[i]->SetRange(hugin_utils::roundi(pp->minValue), hugin_utils::roundi(pp->maxValue));
1152             }
1153             for(;i < PANO_PROJECTION_MAX_PARMS; i++) {
1154                 m_projParamNamesLabel[i]->Hide();
1155                 m_projParamSlider[i]->Hide();
1156                 m_projParamTextCtrl[i]->Hide();
1157             }
1158             relayout = true;
1159         } else {
1160             m_projection_panel->GetSizer()->Show(m_projParamSizer, false, true);
1161             relayout = true;
1162         }
1163     }
1164     if (nParam) {
1165         // display new values
1166         std::vector<double> params = opts.getProjectionParameters();
1167         assert((int) params.size() == nParam);
1168         for (int i=0; i < nParam; i++) {
1169             wxString val = wxString(hugin_utils::doubleToString(params[i],1).c_str(), wxConvLocal);
1170             m_projParamTextCtrl[i]->ChangeValue(wxString(val.wc_str(), wxConvLocal));
1171             m_projParamSlider[i]->SetValue(hugin_utils::roundi(params[i]));
1172         }
1173     }
1174     if (relayout) {
1175         m_projection_panel->Layout();
1176         Refresh();
1177     }
1178     SetStatusText(wxString::Format(wxT("%.1f x %.1f"), opts.getHFOV(), opts.getVFOV()),2);
1179     m_HFOVSlider->SetValue(hugin_utils::roundi(opts.getHFOV()));
1180     m_VFOVSlider->SetValue(hugin_utils::roundi(opts.getVFOV()));
1181     std::string val;
1182     val = hugin_utils::doubleToString(opts.getHFOV(),1);
1183     m_HFOVText->ChangeValue(wxString(val.c_str(), wxConvLocal));
1184     val = hugin_utils::doubleToString(opts.getVFOV(),1);
1185     m_VFOVText->ChangeValue(wxString(val.c_str(), wxConvLocal));
1186     m_VFOVText->Enable(opts.fovCalcSupported(opts.getProjection()));
1187 
1188     m_oldProjFormat = opts.getProjection();
1189 
1190     XRCCTRL(*this,"preview_autocrop_tool",wxButton)->Enable(activeImgs);
1191     XRCCTRL(*this,"preview_stack_autocrop_tool",wxButton)->Enable(activeImgs);
1192     UpdateRoiDisplay(opts);
1193 
1194     if(m_showProjectionHints)
1195     {
1196         ShowProjectionWarnings();
1197     };
1198     redrawPreview();
1199 }
1200 
panoramaImagesChanged(HuginBase::Panorama & pano,const HuginBase::UIntSet & changed)1201 void GLPreviewFrame::panoramaImagesChanged(HuginBase::Panorama &pano, const HuginBase::UIntSet &changed)
1202 {
1203     DEBUG_TRACE("");
1204 
1205     bool dirty = false;
1206 
1207     unsigned int nrImages = pano.getNrOfImages();
1208     unsigned int nrButtons = m_ToggleButtons.size();
1209 
1210     GetMenuBar()->Enable(XRCID("action_optimize"), nrImages > 0);
1211 
1212 //    m_displayedImgs.clear();
1213 
1214     // remove items for nonexisting images
1215     for (int i=nrButtons-1; i>=(int)nrImages; i--)
1216     {
1217         m_ButtonSizer->Detach(m_ToggleButtonPanel[i]);
1218         // Image toggle buttons have a event handler on the stack which
1219         // must be removed before the buttons get destroyed.
1220         m_ToggleButtons[i]->PopEventHandler();
1221         m_GroupToggleButtons[i]->PopEventHandler();
1222         delete m_ToggleButtons[i];
1223         delete m_GroupToggleButtons[i];
1224         delete m_ToggleButtonPanel[i];
1225         m_ToggleButtons.pop_back();
1226         m_GroupToggleButtons.pop_back();
1227         m_ToggleButtonPanel.pop_back();
1228         delete toogle_button_event_handlers[i];
1229         toogle_button_event_handlers.pop_back();
1230         delete toggle_group_button_event_handlers[i];
1231         toggle_group_button_event_handlers.pop_back();
1232         dirty = true;
1233     }
1234 
1235     //change overview mode to panosphere if the translation plane parameter are non zero
1236     if (m_GLOverview->GetMode() == GLOverview::PLANE)
1237     {
1238         if (HasNonZeroTranslationPlaneParameters())
1239         {
1240             m_GLOverview->SetMode(GLOverview::PANOSPHERE);
1241             m_OverviewModeChoice->SetSelection(0);
1242             //check if drag mode is mosaic, if so reset to normal
1243             if(drag_tool)
1244             {
1245                 if(drag_tool->getDragMode()==DragTool::drag_mode_mosaic)
1246                 {
1247                     m_DragModeChoice->SetSelection(m_DragModeChoice->GetSelection()-2);
1248                     drag_tool->setDragMode(DragTool::drag_mode_normal);
1249                     EnableGroupCheckboxes(individualDragging());
1250                     // adjust the layout
1251                     DragChoiceLayout(m_DragModeChoice->GetSelection());
1252                 };
1253             };
1254         }
1255     }
1256 
1257     // add buttons
1258     if ( nrImages >= nrButtons ) {
1259         for(HuginBase::UIntSet::const_iterator it = changed.begin(); it != changed.end(); ++it){
1260             if (*it >= nrButtons) {
1261                 // create new item.
1262 //                wxImage * bmp = new wxImage(sz.GetWidth(), sz.GetHeight());
1263                 //put wxToggleButton in a wxPanel because
1264                 //on Windows the background colour of wxToggleButton can't be changed
1265                 wxPanel *pan = new wxPanel(m_ButtonPanel);
1266                 wxBoxSizer * siz = new wxBoxSizer(wxVERTICAL);
1267                 pan->SetSizer(siz);
1268                 wxToggleButton * but = new wxToggleButton(pan,
1269                                                           ID_TOGGLE_BUT + *it,
1270                                                           wxString::Format(wxT("%d"),*it),
1271                                                           wxDefaultPosition, wxDefaultSize,
1272                                                           wxBU_EXACTFIT);
1273 
1274                 wxCheckBox *butcheck = new wxCheckBox(pan, wxID_ANY, wxT(""));
1275 
1276 #if defined __WXMSW__ || defined __WXMAC__
1277                 //we need a border around the button to see the colored panel
1278                 //because changing backgroundcolor of wxToggleButton does not work in wxMSW
1279                 siz->AddSpacer(5);
1280                 siz->Add(butcheck, 0, wxALIGN_CENTRE_HORIZONTAL | wxFIXED_MINSIZE, 0);
1281                 siz->Add(but,0,wxLEFT | wxRIGHT | wxBOTTOM , 5);
1282 #else
1283                 siz->Add(but,0,wxALL ,0);
1284                 siz->Add(butcheck, 0, wxALL | wxFIXED_MINSIZE, 0);
1285 #endif
1286                 // for the identification tool to work, we need to find when the
1287                 // mouse enters and exits the button. We use a custom event
1288                 // handler, which will also toggle the images:
1289                 ImageToogleButtonEventHandler * event_handler = new ImageToogleButtonEventHandler(*it, m_identify_togglebutton, &m_pano);
1290                 event_handler->AddIdentifyTool(&identify_tool);
1291                 event_handler->AddIdentifyTool(&panosphere_overview_identify_tool);
1292                 event_handler->AddIdentifyTool(&plane_overview_identify_tool);
1293                 toogle_button_event_handlers.push_back(event_handler);
1294                 but->PushEventHandler(event_handler);
1295 
1296                 ImageGroupButtonEventHandler * group_event_handler = new
1297                     ImageGroupButtonEventHandler(*it, this, &m_pano);
1298                 group_event_handler->AddDragTool((DragTool**) &drag_tool);
1299                 group_event_handler->AddDragTool((DragTool**) &overview_drag_tool);
1300                 group_event_handler->AddIdentifyTool(&identify_tool);
1301                 group_event_handler->AddIdentifyTool(&panosphere_overview_identify_tool);
1302                 group_event_handler->AddIdentifyTool(&plane_overview_identify_tool);
1303                 toggle_group_button_event_handlers.push_back(group_event_handler);
1304                 butcheck->PushEventHandler(group_event_handler);
1305                 butcheck->Show(individualDragging() && m_mode==mode_drag);
1306 
1307                 but->SetValue(true);
1308                 m_ButtonSizer->Add(pan,
1309                                    0,
1310                                    wxLEFT | wxTOP,
1311                                    0);
1312                 m_ToggleButtons.push_back(but);
1313                 m_GroupToggleButtons.push_back(butcheck);
1314                 m_ToggleButtonPanel.push_back(pan);
1315                 dirty = true;
1316             }
1317         }
1318     }
1319 
1320     // update existing items
1321     HuginBase::UIntSet displayedImages = m_pano.getActiveImages();
1322     for (unsigned i=0; i < nrImages; i++) {
1323         m_ToggleButtons[i]->SetValue(set_contains(displayedImages, i));
1324         wxFileName tFilename(wxString (pano.getImage(i).getFilename().c_str(), HUGIN_CONV_FILENAME));
1325         m_ToggleButtons[i]->SetToolTip(tFilename.GetFullName());
1326     }
1327 
1328     if (dirty) {
1329         m_ButtonSizer->FitInside(m_ButtonPanel);
1330         Layout();
1331         SendSizeEvent();
1332 		DEBUG_INFO("New m_ButtonPanel width: " << (m_ButtonPanel->GetSize()).GetWidth());
1333 		DEBUG_INFO("New m_ButtonPanel Height: " << (m_ButtonPanel->GetSize()).GetHeight());
1334     }
1335     if(nrImages==0)
1336     {
1337         SetMode(mode_assistant);
1338         m_tool_notebook->ChangeSelection(mode_assistant);
1339     };
1340     for(size_t i=2; i<m_tool_notebook->GetPageCount();i++)
1341     {
1342         m_tool_notebook->GetPage(i)->Enable(nrImages!=0);
1343     };
1344     redrawPreview();
1345 }
1346 
redrawPreview()1347 void GLPreviewFrame::redrawPreview()
1348 {
1349     m_GLPreview->Refresh();
1350     m_GLOverview->Refresh();
1351 }
1352 
ResetPreviewZoom()1353 void GLPreviewFrame::ResetPreviewZoom()
1354 {
1355     if (preview_helper)
1356     {
1357         m_GLPreview->m_visualization_state->SetZoomLevel(1.0);
1358     };
1359 }
1360 
OnShowEvent(wxShowEvent & e)1361 void GLPreviewFrame::OnShowEvent(wxShowEvent& e)
1362 {
1363 
1364     DEBUG_TRACE("OnShow");
1365     bool toggle_on = GetMenuBar()->FindItem(XRCID("action_show_overview"))->IsChecked();
1366     wxAuiPaneInfo &inf = m_mgr->GetPane(wxT("overview"));
1367     if (inf.IsOk()) {
1368         if (e.IsShown()) {
1369             if (!inf.IsShown() && toggle_on ) {
1370                 inf.Show();
1371                 m_mgr->Update();
1372             }
1373         } else {
1374             if (inf.IsFloating() && inf.IsShown()) {
1375                 DEBUG_DEBUG("hiding overview float");
1376                 inf.Hide();
1377                 m_mgr->Update();
1378             }
1379         }
1380     }
1381 
1382 }
1383 
1384 //the following methods are to substitude the GLViewer KeyUp and KeyDown methods
1385 //so that tools use key events that happen globally to the preview frame
1386 //however only key up event is sent, and not key down
1387 //so until this is resolved they will remain to be handled by GLViewer
KeyDown(wxKeyEvent & e)1388 void GLPreviewFrame::KeyDown(wxKeyEvent& e)
1389 {
1390     if (preview_helper) {
1391         preview_helper->KeypressEvent(e.GetKeyCode(), e.GetModifiers(), true);
1392     }
1393     if (GetMenuBar()->FindItem(XRCID("action_show_overview"))->IsChecked()) {
1394         if(m_GLOverview->GetMode() == GLOverview::PLANE) {
1395             if (plane_overview_helper) {
1396                 plane_overview_helper->KeypressEvent(e.GetKeyCode(), e.GetModifiers(), true);
1397             }
1398         } else if (m_GLOverview->GetMode() == GLOverview::PANOSPHERE) {
1399             if (panosphere_overview_helper) {
1400                 panosphere_overview_helper->KeypressEvent(e.GetKeyCode(), e.GetModifiers(), true);
1401             }
1402         }
1403 
1404     }
1405     e.Skip();
1406 }
1407 
KeyUp(wxKeyEvent & e)1408 void GLPreviewFrame::KeyUp(wxKeyEvent& e)
1409 {
1410     if (preview_helper) {
1411         preview_helper->KeypressEvent(e.GetKeyCode(), e.GetModifiers(), false);
1412     }
1413     if (GetMenuBar()->FindItem(XRCID("action_show_overview"))->IsChecked()) {
1414         if(m_GLOverview->GetMode() == GLOverview::PLANE) {
1415             if (plane_overview_helper) {
1416                 plane_overview_helper->KeypressEvent(e.GetKeyCode(), e.GetModifiers(), false);
1417             }
1418         } else if (m_GLOverview->GetMode() == GLOverview::PANOSPHERE) {
1419             if (panosphere_overview_helper) {
1420                 panosphere_overview_helper->KeypressEvent(e.GetKeyCode(), e.GetModifiers(), false);
1421             }
1422         }
1423 
1424     }
1425     e.Skip();
1426 }
1427 
1428 
1429 
OnOverviewToggle(wxCommandEvent & e)1430 void GLPreviewFrame::OnOverviewToggle(wxCommandEvent& e)
1431 {
1432     DEBUG_TRACE("overview toggle");
1433     bool toggle_on = GetMenuBar()->FindItem(XRCID("action_show_overview"))->IsChecked();
1434     wxAuiPaneInfo &inf = m_mgr->GetPane(wxT("overview"));
1435     if (inf.IsOk()) {
1436         if (inf.IsShown() && !toggle_on) {
1437             inf.Hide();
1438             m_GLOverview->SetActive(false);
1439             m_mgr->Update();
1440         } else if (!(inf.IsShown() && toggle_on)) {
1441             inf.Show();
1442 #if defined __WXMSW__ || defined __WXMAC__
1443             m_GLOverview->SetActive(true);
1444             m_mgr->Update();
1445 #else
1446             m_mgr->Update();
1447             m_GLOverview->SetActive(true);
1448 #endif
1449         }
1450     }
1451 }
1452 
OnSwitchPreviewGrid(wxCommandEvent & e)1453 void GLPreviewFrame::OnSwitchPreviewGrid(wxCommandEvent & e)
1454 {
1455     if(GetMenuBar()->FindItem(XRCID("action_show_grid"))->IsChecked())
1456     {
1457         preview_helper->ActivateTool(preview_projection_grid);
1458         panosphere_overview_helper->ActivateTool(overview_projection_grid);
1459     }
1460     else
1461     {
1462         preview_helper->DeactivateTool(preview_projection_grid);
1463         panosphere_overview_helper->DeactivateTool(overview_projection_grid);
1464     }
1465     m_GLPreview->Refresh();
1466     m_GLOverview->Refresh();
1467 }
1468 
OnClose(wxCloseEvent & event)1469 void GLPreviewFrame::OnClose(wxCloseEvent& event)
1470 {
1471     DEBUG_TRACE("OnClose")
1472     // do not close, just hide if we're not forced
1473     if(m_guiLevel==GUI_SIMPLE)
1474     {
1475         if(!MainFrame::Get()->CloseProject(event.CanVeto(), MainFrame::CLOSE_PROGRAM))
1476         {
1477            if (event.CanVeto())
1478            {
1479                event.Veto();
1480                return;
1481            };
1482         };
1483         MainFrame::Get()->Close(true);
1484     }
1485     else
1486     {
1487         if (event.CanVeto())
1488         {
1489             event.Veto();
1490             Hide();
1491             DEBUG_DEBUG("hiding");
1492         }
1493         else
1494         {
1495             DEBUG_DEBUG("closing");
1496             this->Destroy();
1497         }
1498     };
1499 }
1500 
1501 #if 0
1502 // need to add the wxChoice somewhere
1503 void PreviewFrame::OnProjectionChanged()
1504 {
1505     PanoramaOptions opt = m_pano.getOptions();
1506     int lt = m_ProjectionChoice->GetSelection();
1507     wxString Ip;
1508     switch ( lt ) {
1509     case PanoramaOptions::RECTILINEAR:       Ip = _("Rectilinear"); break;
1510     case PanoramaOptions::CYLINDRICAL:       Ip = _("Cylindrical"); break;
1511     case PanoramaOptions::EQUIRECTANGULAR:   Ip = _("Equirectangular"); break;
1512     }
1513     opt.projectionFormat = (PanoramaOptions::ProjectionFormat) lt;
1514     PanoCommand::GlobalCmdHist::getInstance().addCommand(
1515         new PanoCommand::SetPanoOptionsCmd( pano, opt )
1516         );
1517     DEBUG_DEBUG ("Projection changed: "  << lt << ":" << Ip )
1518 
1519 
1520 }
1521 #endif
1522 
OnCenterHorizontally(wxCommandEvent & e)1523 void GLPreviewFrame::OnCenterHorizontally(wxCommandEvent & e)
1524 {
1525     if (m_pano.getActiveImages().empty()) return;
1526 
1527     PanoCommand::GlobalCmdHist::getInstance().addCommand(
1528         new PanoCommand::CenterPanoCmd(m_pano)
1529         );
1530 }
1531 
OnStraighten(wxCommandEvent & e)1532 void GLPreviewFrame::OnStraighten(wxCommandEvent & e)
1533 {
1534     if (m_pano.getNrOfImages() == 0) return;
1535 
1536     PanoCommand::GlobalCmdHist::getInstance().addCommand(
1537         new PanoCommand::StraightenPanoCmd(m_pano)
1538         );
1539 }
1540 
OnFitPano(wxCommandEvent & e)1541 void GLPreviewFrame::OnFitPano(wxCommandEvent & e)
1542 {
1543     if (m_pano.getActiveImages().empty()) return;
1544 
1545     DEBUG_TRACE("");
1546     HuginBase::PanoramaOptions opt = m_pano.getOptions();
1547     HuginBase::CalculateFitPanorama fitPano(m_pano);
1548     fitPano.run();
1549     opt.setHFOV(fitPano.getResultHorizontalFOV());
1550     opt.setHeight(hugin_utils::roundi(fitPano.getResultHeight()));
1551 
1552     PanoCommand::GlobalCmdHist::getInstance().addCommand(
1553         new PanoCommand::SetPanoOptionsCmd( m_pano, opt )
1554         );
1555 
1556     DEBUG_INFO ( "new fov: [" << opt.getHFOV() << " "<< opt.getVFOV() << "] => height: " << opt.getHeight() );
1557 }
1558 
OnShowAll(wxCommandEvent & e)1559 void GLPreviewFrame::OnShowAll(wxCommandEvent & e)
1560 {
1561     if (m_pano.getNrOfImages() == 0) return;
1562 
1563     HuginBase::UIntSet displayedImgs;
1564     if (m_selectAllMode == SELECT_ALL_IMAGES)
1565     {
1566         fill_set(displayedImgs, 0, m_pano.getNrOfImages() - 1);
1567     }
1568     else
1569     {
1570         if (m_selectKeepSelection)
1571         {
1572             displayedImgs = m_pano.getActiveImages();
1573         };
1574         std::vector<HuginBase::UIntVector> stackedImg = HuginBase::getSortedStacks(&m_pano);
1575         for (size_t i = 0; i < stackedImg.size(); ++i)
1576         {
1577             switch (m_selectAllMode)
1578             {
1579                 case SELECT_BRIGHTEST_IMAGES:
1580                     displayedImgs.insert(*(stackedImg[i].rbegin()));
1581                     break;
1582                 case SELECT_DARKEST_IMAGES:
1583                     displayedImgs.insert(*(stackedImg[i].begin()));
1584                     break;
1585                 case SELECT_MEDIAN_IMAGES:
1586                 default:
1587                     displayedImgs.insert(stackedImg[i][stackedImg[i].size() / 2]);
1588                     break;
1589             };
1590         };
1591     };
1592     PanoCommand::GlobalCmdHist::getInstance().addCommand(
1593         new PanoCommand::SetActiveImagesCmd(m_pano, displayedImgs)
1594         );
1595 }
1596 
OnShowNone(wxCommandEvent & e)1597 void GLPreviewFrame::OnShowNone(wxCommandEvent & e)
1598 {
1599     if (m_pano.getNrOfImages() == 0) return;
1600 
1601     DEBUG_ASSERT(m_pano.getNrOfImages() == m_ToggleButtons.size());
1602     for (unsigned int i=0; i < m_pano.getNrOfImages(); i++) {
1603         m_ToggleButtons[i]->SetValue(false);
1604     }
1605     HuginBase::UIntSet displayedImgs;
1606     PanoCommand::GlobalCmdHist::getInstance().addCommand(
1607         new PanoCommand::SetActiveImagesCmd(m_pano, displayedImgs)
1608         );
1609 }
1610 
OnNumTransform(wxCommandEvent & e)1611 void GLPreviewFrame::OnNumTransform(wxCommandEvent & e)
1612 {
1613     if (m_pano.getNrOfImages() == 0) return;
1614 
1615     wxString text;
1616     double y;
1617     double p;
1618     double r;
1619     double x;
1620     double z;
1621 
1622     int index = m_DragModeChoice->GetSelection();
1623     switch (index) {
1624         case 0: //normal
1625         case 1: //normal, individual
1626             //@TODO limit numeric transform to selected images
1627             text = XRCCTRL(*this,"input_yaw",wxTextCtrl)->GetValue();
1628             if(!hugin_utils::stringToDouble(std::string(text.mb_str(wxConvLocal)), y))
1629             {
1630                 wxBell();
1631                 wxMessageBox(_("Yaw value must be numeric."),_("Warning"),wxOK | wxICON_ERROR,this);
1632                 return;
1633             }
1634             text = XRCCTRL(*this,"input_pitch",wxTextCtrl)->GetValue();
1635             if (!hugin_utils::stringToDouble(std::string(text.mb_str(wxConvLocal)), p))
1636             {
1637                 wxBell();
1638                 wxMessageBox(_("Pitch value must be numeric."),_("Warning"),wxOK | wxICON_ERROR,this);
1639                 return;
1640             }
1641             text = XRCCTRL(*this,"input_roll",wxTextCtrl)->GetValue();
1642             if (!hugin_utils::stringToDouble(std::string(text.mb_str(wxConvLocal)), r))
1643             {
1644                 wxBell();
1645                 wxMessageBox(_("Roll value must be numeric."),_("Warning"),wxOK | wxICON_ERROR,this);
1646                 return;
1647             }
1648             PanoCommand::GlobalCmdHist::getInstance().addCommand(
1649                     new PanoCommand::RotatePanoCmd(m_pano, y, p, r)
1650                 );
1651             break;
1652         case 2: //mosaic
1653         case 3: //mosaic, individual
1654             //@TODO limit numeric transform to selected images
1655             text = XRCCTRL(*this,"input_x",wxTextCtrl)->GetValue();
1656             if (!hugin_utils::stringToDouble(std::string(text.mb_str(wxConvLocal)), x))
1657             {
1658                 wxBell();
1659                 wxMessageBox(_("X value must be numeric."),_("Warning"),wxOK | wxICON_ERROR,this);
1660                 return;
1661             }
1662             text = XRCCTRL(*this,"input_y",wxTextCtrl)->GetValue();
1663             if (!hugin_utils::stringToDouble(std::string(text.mb_str(wxConvLocal)), y))
1664             {
1665                 wxBell();
1666                 wxMessageBox(_("Y value must be numeric."),_("Warning"),wxOK | wxICON_ERROR,this);
1667                 return;
1668             }
1669             text = XRCCTRL(*this,"input_z",wxTextCtrl)->GetValue();
1670             if(!hugin_utils::stringToDouble(std::string(text.mb_str(wxConvLocal)), z))
1671             {
1672                 wxBell();
1673                 wxMessageBox(_("Z value must be numeric."),_("Warning"),wxOK | wxICON_ERROR,this);
1674                 return;
1675             }
1676             PanoCommand::GlobalCmdHist::getInstance().addCommand(
1677                     new PanoCommand::TranslatePanoCmd(m_pano, x, y, z)
1678                 );
1679             break;
1680     }
1681 }
1682 
OnExposureChanged(wxCommandEvent & e)1683 void GLPreviewFrame::OnExposureChanged(wxCommandEvent & e)
1684 {
1685     HuginBase::PanoramaOptions opts = m_pano.getOptions();
1686     // exposure
1687     wxString text = m_exposureTextCtrl->GetValue();
1688     DEBUG_INFO ("target exposure = " << text.mb_str(wxConvLocal) );
1689     double p = 0;
1690     if (text != wxT("")) {
1691         if (!hugin_utils::str2double(text, p)) {
1692             wxLogError(_("Value must be numeric."));
1693             return;
1694         }
1695     }
1696     opts.outputExposureValue = p;
1697     PanoCommand::GlobalCmdHist::getInstance().addCommand(
1698             new PanoCommand::SetPanoOptionsCmd( m_pano, opts )
1699                                            );
1700 }
1701 
OnRangeCompressionIncrease(wxSpinEvent & e)1702 void GLPreviewFrame::OnRangeCompressionIncrease(wxSpinEvent & e)
1703 {
1704     HuginBase::PanoramaOptions opt = m_pano.getOptions();
1705     opt.outputRangeCompression = std::min(opt.outputRangeCompression + 1.0, 20.0);
1706     PanoCommand::GlobalCmdHist::getInstance().addCommand(
1707         new PanoCommand::SetPanoOptionsCmd(m_pano, opt)
1708     );
1709 }
1710 
OnRangeCompressionDecrease(wxSpinEvent & e)1711 void GLPreviewFrame::OnRangeCompressionDecrease(wxSpinEvent & e)
1712 {
1713     HuginBase::PanoramaOptions opt = m_pano.getOptions();
1714     opt.outputRangeCompression = std::max(opt.outputRangeCompression - 1.0, 0.0);
1715     PanoCommand::GlobalCmdHist::getInstance().addCommand(
1716         new PanoCommand::SetPanoOptionsCmd(m_pano, opt)
1717     );
1718 }
1719 
OnRangeCompressionChanged(wxCommandEvent & e)1720 void GLPreviewFrame::OnRangeCompressionChanged(wxCommandEvent & e)
1721 {
1722     HuginBase::PanoramaOptions opts = m_pano.getOptions();
1723     // range compression
1724     const wxString text = m_rangeCompressionTextCtrl->GetValue();
1725     if (!text.IsEmpty())
1726     {
1727         double p = 0;
1728         if (!hugin_utils::str2double(text, p))
1729         {
1730             wxLogError(_("Value must be numeric."));
1731             return;
1732         };
1733         if (p < 0 || p>20)
1734         {
1735             wxLogError(_("Value for range compression is outside of valid range."));
1736             return;
1737         };
1738         if (p != opts.outputRangeCompression)
1739         {
1740             opts.outputRangeCompression = p;
1741             PanoCommand::GlobalCmdHist::getInstance().addCommand(
1742                 new PanoCommand::SetPanoOptionsCmd(m_pano, opts)
1743             );
1744         };
1745     };
1746 }
1747 
1748 
OnProjParameterChanged(wxCommandEvent & e)1749 void GLPreviewFrame::OnProjParameterChanged(wxCommandEvent & e)
1750 {
1751     HuginBase::PanoramaOptions opts = m_pano.getOptions();
1752     int nParam = opts.m_projFeatures.numberOfParameters;
1753     std::vector<double> para = opts.getProjectionParameters();
1754     for (int i = 0; i < nParam; i++) {
1755         if (e.GetEventObject() == m_projParamTextCtrl[i]) {
1756             wxString text = m_projParamTextCtrl[i]->GetValue();
1757             DEBUG_INFO ("param " << i << ":  = " << text.mb_str(wxConvLocal) );
1758             double p = 0;
1759             if (text != wxT("")) {
1760                 if (!hugin_utils::str2double(text, p)) {
1761                     wxLogError(_("Value must be numeric."));
1762                     return;
1763                 }
1764             }
1765             para[i] = p;
1766         }
1767     }
1768     opts.setProjectionParameters(para);
1769     PanoCommand::GlobalCmdHist::getInstance().addCommand(
1770             new PanoCommand::SetPanoOptionsCmd( m_pano, opts )
1771                                            );
1772 }
1773 
OnProjParameterReset(wxCommandEvent & e)1774 void GLPreviewFrame::OnProjParameterReset(wxCommandEvent &e)
1775 {
1776     HuginBase::PanoramaOptions opts = m_pano.getOptions();
1777     opts.resetProjectionParameters();
1778     PanoCommand::GlobalCmdHist::getInstance().addCommand(
1779         new PanoCommand::SetPanoOptionsCmd(m_pano, opts)
1780         );
1781 };
1782 
OnChangeFOV(wxScrollEvent & e)1783 void GLPreviewFrame::OnChangeFOV(wxScrollEvent & e)
1784 {
1785     DEBUG_TRACE("");
1786 
1787     HuginBase::PanoramaOptions opt = m_pano.getOptions();
1788 
1789     if (e.GetEventObject() == m_HFOVSlider) {
1790         DEBUG_DEBUG("HFOV changed (slider): " << e.GetInt() << " == " << m_HFOVSlider->GetValue());
1791         opt.setHFOV(e.GetInt());
1792     } else if (e.GetEventObject() == m_VFOVSlider) {
1793         DEBUG_DEBUG("VFOV changed (slider): " << e.GetInt());
1794         opt.setVFOV(e.GetInt());
1795     } else if (e.GetEventObject() == XRCCTRL(*this,"layout_scale_slider",wxSlider)) {
1796         DEBUG_DEBUG("Layout scale changed (slider): " << e.GetInt());
1797         GLPreviewFrame::OnLayoutScaleChange(e);
1798     } else {
1799         int nParam = opt.m_projFeatures.numberOfParameters;
1800         std::vector<double> para = opt.getProjectionParameters();
1801         for (int i = 0; i < nParam; i++) {
1802             if (e.GetEventObject() == m_projParamSlider[i]) {
1803                 // update
1804                 para[i] = e.GetInt();
1805                 break;
1806             }
1807         }
1808         opt.setProjectionParameters(para);
1809 		opt.setHFOV(m_HFOVSlider->GetValue());
1810 		opt.setVFOV(m_VFOVSlider->GetValue());
1811     }
1812 
1813     PanoCommand::GlobalCmdHist::getInstance().addCommand(
1814         new PanoCommand::SetPanoOptionsCmd( m_pano, opt )
1815         );
1816 }
1817 
OnTrackChangeFOV(wxScrollEvent & e)1818 void GLPreviewFrame::OnTrackChangeFOV(wxScrollEvent & e)
1819 {
1820     DEBUG_TRACE("");
1821     DEBUG_TRACE("fov change " << e.GetInt());
1822     HuginBase::PanoramaOptions opt = m_pano.getOptions();
1823 
1824     if (e.GetEventObject() == m_HFOVSlider) {
1825         opt.setHFOV(e.GetInt());
1826     } else if (e.GetEventObject() == m_VFOVSlider) {
1827         opt.setVFOV(e.GetInt());
1828     } else {
1829         int nParam = opt.m_projFeatures.numberOfParameters;
1830         std::vector<double> para = opt.getProjectionParameters();
1831         for (int i = 0; i < nParam; i++) {
1832             if (e.GetEventObject() == m_projParamSlider[i]) {
1833                 // update
1834                 para[i] = e.GetInt();
1835                 m_projParamTextCtrl[i]->ChangeValue(wxString::Format("%d", e.GetInt()));
1836                 break;
1837             }
1838         }
1839         opt.setProjectionParameters(para);
1840     }
1841     // we only actually update the panorama fully when the mouse is released.
1842     // As we are dragging it we don't want to create undo events, but we would
1843     // like to update the display, so we change the GLViewer's ViewState and
1844     // request a redraw.
1845     m_GLPreview->m_view_state->SetOptions(&opt);
1846     m_GLPreview->Refresh();
1847 }
1848 
OnBlendChoice(wxCommandEvent & e)1849 void GLPreviewFrame::OnBlendChoice(wxCommandEvent & e)
1850 {
1851     if (e.GetEventObject() == m_BlendModeChoice)
1852     {
1853         updateBlendMode();
1854     }
1855     else
1856     {
1857         // FIXME DEBUG_WARN("wxChoice event from unknown object received");
1858     }
1859 }
1860 
OnDragChoice(wxCommandEvent & e)1861 void GLPreviewFrame::OnDragChoice(wxCommandEvent & e)
1862 {
1863     if (drag_tool)
1864     {
1865         DragTool::DragMode newDragMode=DragTool::drag_mode_normal;
1866         int index = m_DragModeChoice->GetSelection();
1867         switch (index) {
1868             case 0: //normal
1869             case 1:
1870                 newDragMode=DragTool::drag_mode_normal;
1871                 break;
1872             case 2: //mosaic
1873             case 3:
1874                 newDragMode=DragTool::drag_mode_mosaic;
1875                 break;
1876         }
1877         if(newDragMode==DragTool::drag_mode_mosaic)
1878         {
1879             if(HasNonZeroTranslationPlaneParameters())
1880             {
1881                 if(wxMessageBox(_("The mosaic/plane mode works only correct for a remapping plane of yaw=0 and pitch=0.\nBut your project has non-zero Tpy and Tpp parameters.\nShould the Tpy and Tpp parameters reset to zero?"),
1882 #ifdef __WXMSW__
1883                     _("Hugin"),
1884 #else
1885                     wxEmptyString,
1886 #endif
1887                     wxYES_NO | wxICON_QUESTION, this) == wxYES)
1888                 {
1889                     ResetTranslationPlaneParameters();
1890                 }
1891                 else
1892                 {
1893                     m_DragModeChoice->SetSelection(index-2);
1894                     return;
1895                 };
1896             };
1897             //switch overview mode to plane
1898             UpdateOverviewMode(1);
1899             m_OverviewModeChoice->SetSelection(1);
1900         }
1901         else
1902         {
1903             //new mode is normal
1904             //set overview back to panosphere mode
1905             UpdateOverviewMode(0);
1906             m_OverviewModeChoice->SetSelection(0);
1907             m_GLOverview->m_visualization_state->ForceRequireRedraw();
1908             m_GLOverview->m_visualization_state->SetDirtyViewport();
1909         };
1910         //update drag mode
1911         drag_tool->setDragMode(newDragMode);
1912         EnableGroupCheckboxes(individualDragging());
1913         // adjust the layout
1914         DragChoiceLayout(index);
1915     };
1916 };
1917 
HasNonZeroTranslationPlaneParameters()1918 bool GLPreviewFrame::HasNonZeroTranslationPlaneParameters()
1919 {
1920     size_t nr = m_pano.getNrOfImages();
1921     for (size_t i = 0 ; i < nr; i++)
1922     {
1923         if (m_pano.getSrcImage(i).getTranslationPlaneYaw() != 0 ||
1924             m_pano.getSrcImage(i).getTranslationPlanePitch() != 0)
1925         {
1926             return true;
1927         };
1928     }
1929     return false;
1930 };
1931 
ResetTranslationPlaneParameters()1932 void GLPreviewFrame::ResetTranslationPlaneParameters()
1933 {
1934     HuginBase::UIntSet imgs;
1935     HuginBase::Panorama newPan = m_pano.duplicate();
1936     size_t nr = newPan.getNrOfImages();
1937     for (size_t i = 0 ; i < nr ; i++)
1938     {
1939         HuginBase::SrcPanoImage img = newPan.getSrcImage(i);
1940         img.setTranslationPlaneYaw(0);
1941         img.setTranslationPlanePitch(0);
1942         newPan.setSrcImage(i,img);
1943         imgs.insert(i);
1944     }
1945     PanoCommand::GlobalCmdHist::getInstance().addCommand(
1946         new PanoCommand::UpdateImagesVariablesCmd(m_pano, imgs, newPan.getVariables())
1947     );
1948 };
1949 
UpdateOverviewMode(int newMode)1950 bool GLPreviewFrame::UpdateOverviewMode(int newMode)
1951 {
1952     GLOverview::OverviewMode newOverviewMode=GLOverview::PANOSPHERE;
1953     if(newMode==1)
1954     {
1955         newOverviewMode=GLOverview::PLANE;
1956     };
1957     if(m_GLOverview->GetMode()==newOverviewMode)
1958     {
1959         return true;
1960     };
1961     if (m_GLOverview->GetMode() == GLOverview::PANOSPHERE)
1962     {
1963         if (!HasNonZeroTranslationPlaneParameters())
1964         {
1965             m_GLOverview->SetMode(GLOverview::PLANE);
1966             return true;
1967         }
1968         else
1969         {
1970             if(wxMessageBox(_("The mosaic/plane mode works only correct for a remapping plane of yaw=0 and pitch=0.\nBut your project has non-zero Tpy and Tpp parameters.\nShould the Tpy and Tpp parameters reset to zero?"),
1971 #ifdef __WXMSW__
1972                 _("Hugin"),
1973 #else
1974                 wxEmptyString,
1975 #endif
1976                 wxYES_NO | wxICON_QUESTION, this) == wxYES)
1977             {
1978                 ResetTranslationPlaneParameters();
1979                 m_GLOverview->SetMode(GLOverview::PLANE);
1980                 return true;
1981             }
1982             else
1983             {
1984                 return false;
1985             };
1986         };
1987     }
1988     else
1989     {
1990         m_GLOverview->SetMode(GLOverview::PANOSPHERE);
1991         return true;
1992     }
1993 };
1994 
OnOverviewModeChoice(wxCommandEvent & e)1995 void GLPreviewFrame::OnOverviewModeChoice( wxCommandEvent & e)
1996 {
1997     if(UpdateOverviewMode(m_OverviewModeChoice->GetSelection()))
1998     {
1999         m_GLOverview->m_visualization_state->ForceRequireRedraw();
2000         m_GLOverview->m_visualization_state->SetDirtyViewport();
2001         //set drag mode to normal if new mode is panosphere mode
2002         if(m_GLOverview->GetMode()==GLOverview::PANOSPHERE && m_DragModeChoice->GetSelection()>1)
2003         {
2004             m_DragModeChoice->SetSelection(m_DragModeChoice->GetSelection()-2);
2005             OnDragChoice(e);
2006         };
2007     }
2008     else
2009     {
2010         //change mode was not successful or canceled by user, set mode choice back
2011         if(m_GLOverview->GetMode()==GLOverview::PANOSPHERE)
2012         {
2013             m_OverviewModeChoice->SetSelection(0);
2014         }
2015         else
2016         {
2017             m_OverviewModeChoice->SetSelection(1);
2018         };
2019     };
2020 };
2021 
DragChoiceLayout(int index)2022 void GLPreviewFrame::DragChoiceLayout( int index )
2023 {
2024     // visibility of controls based on selected drag mode
2025     bool normalMode=index==0 || index==1;
2026     XRCCTRL(*this,"label_yaw",wxStaticText)->Show(normalMode);
2027     XRCCTRL(*this,"input_yaw",wxTextCtrl)->Show(normalMode);
2028     XRCCTRL(*this,"label_pitch",wxStaticText)->Show(normalMode);
2029     XRCCTRL(*this,"input_pitch",wxTextCtrl)->Show(normalMode);
2030     XRCCTRL(*this,"label_roll",wxStaticText)->Show(normalMode);
2031     XRCCTRL(*this,"input_roll",wxTextCtrl)->Show(normalMode);
2032     XRCCTRL(*this,"label_x",wxStaticText)->Show(!normalMode);
2033     XRCCTRL(*this,"input_x",wxTextCtrl)->Show(!normalMode);
2034     XRCCTRL(*this,"label_y",wxStaticText)->Show(!normalMode);
2035     XRCCTRL(*this,"input_y",wxTextCtrl)->Show(!normalMode);
2036     XRCCTRL(*this,"label_z",wxStaticText)->Show(!normalMode);
2037     XRCCTRL(*this,"input_z",wxTextCtrl)->Show(!normalMode);
2038     // redraw layout to compress empty space
2039     XRCCTRL(*this,"apply_num_transform",wxButton)->GetParent()->Layout();
2040 }
2041 
OnDefaultExposure(wxCommandEvent & e)2042 void GLPreviewFrame::OnDefaultExposure( wxCommandEvent & e )
2043 {
2044     if (m_pano.getNrOfImages() > 0) {
2045         HuginBase::PanoramaOptions opt = m_pano.getOptions();
2046         opt.outputExposureValue = HuginBase::CalculateMeanExposure::calcMeanExposure(m_pano);
2047         PanoCommand::GlobalCmdHist::getInstance().addCommand(
2048                 new PanoCommand::SetPanoOptionsCmd( m_pano, opt )
2049                                                );
2050     }
2051 }
2052 
OnIncreaseExposure(wxSpinEvent & e)2053 void GLPreviewFrame::OnIncreaseExposure( wxSpinEvent & e )
2054 {
2055     HuginBase::PanoramaOptions opt = m_pano.getOptions();
2056     opt.outputExposureValue = opt.outputExposureValue + 1.0/3;
2057     PanoCommand::GlobalCmdHist::getInstance().addCommand(
2058             new PanoCommand::SetPanoOptionsCmd( m_pano, opt )
2059                                             );
2060 }
2061 
OnDecreaseExposure(wxSpinEvent & e)2062 void GLPreviewFrame::OnDecreaseExposure( wxSpinEvent & e )
2063 {
2064     HuginBase::PanoramaOptions opt = m_pano.getOptions();
2065     opt.outputExposureValue = opt.outputExposureValue - 1.0/3;
2066     PanoCommand::GlobalCmdHist::getInstance().addCommand(
2067             new PanoCommand::SetPanoOptionsCmd( m_pano, opt )
2068                                            );
2069 }
2070 
OnProjectionChoice(wxCommandEvent & e)2071 void GLPreviewFrame::OnProjectionChoice( wxCommandEvent & e )
2072 {
2073     if (e.GetEventObject() == m_ProjectionChoice) {
2074         HuginBase::PanoramaOptions opt = m_pano.getOptions();
2075         int lt = m_ProjectionChoice->GetSelection();
2076         wxString Ip;
2077         opt.setProjection((HuginBase::PanoramaOptions::ProjectionFormat) lt);
2078         PanoCommand::GlobalCmdHist::getInstance().addCommand(
2079                 new PanoCommand::SetPanoOptionsCmd( m_pano, opt )
2080                                             );
2081         DEBUG_DEBUG ("Projection changed: "  << lt);
2082         m_projection_panel->Layout();
2083         Refresh();
2084     } else {
2085         // FIXME DEBUG_WARN("wxChoice event from unknown object received");
2086     }
2087 }
2088 
2089 /* We don't have an OpenGL hdr display yet
2090 void GLPreviewFrame::OnOutputChoice( wxCommandEvent & e)
2091 {
2092     if (e.GetEventObject() == m_outputModeChoice) {
2093         PanoramaOptions opt = m_pano.getOptions();
2094         int lt = m_outputModeChoice->GetSelection();
2095         wxString Ip;
2096         opt.outputMode = ( (PanoramaOptions::OutputMode) lt );
2097         PanoCommand::GlobalCmdHist::getInstance().addCommand(
2098                 new PanoCommand::SetPanoOptionsCmd( m_pano, opt )
2099                                                );
2100 
2101     } else {
2102         // FIXME DEBUG_WARN("wxChoice event from unknown object received");
2103     }
2104 }
2105 */
2106 
SetStatusMessage(wxString message)2107 void GLPreviewFrame::SetStatusMessage(wxString message)
2108 {
2109     SetStatusText(message, 0);
2110 }
2111 
OnPhotometric(wxCommandEvent & e)2112 void GLPreviewFrame::OnPhotometric(wxCommandEvent & e)
2113 {
2114     m_GLPreview->SetPhotometricCorrect(e.IsChecked());
2115 }
2116 
MakePreviewTools(PreviewToolHelper * preview_helper_in)2117 void GLPreviewFrame::MakePreviewTools(PreviewToolHelper *preview_helper_in)
2118 {
2119     // create the tool objects.
2120     // we delay this until we have an OpenGL context so that they are free to
2121     // create texture objects and display lists before they are used.
2122     preview_helper = preview_helper_in;
2123     crop_tool = new PreviewCropTool(preview_helper);
2124     drag_tool = new PreviewDragTool(preview_helper);
2125     color_picker_tool = new PreviewColorPickerTool(preview_helper);
2126     edit_cp_tool = new PreviewEditCPTool(preview_helper);
2127     identify_tool = new PreviewIdentifyTool(preview_helper, this, true);
2128     preview_helper->ActivateTool(identify_tool);
2129     camera_tool = new PreviewCameraTool(preview_helper);
2130     preview_helper->ActivateTool(camera_tool);
2131     difference_tool = new PreviewDifferenceTool(preview_helper);
2132     pano_mask_tool = new PreviewPanoMaskTool(preview_helper);
2133     preview_control_point_tool = new PreviewControlPointTool(preview_helper);
2134     m_preview_layoutLinesTool = new PreviewLayoutLinesTool(preview_helper);
2135 
2136     preview_projection_grid = new PreviewProjectionGridTool(preview_helper);
2137     if(GetMenuBar()->FindItem(XRCID("action_show_grid"))->IsChecked())
2138     {
2139         preview_helper->ActivateTool(preview_projection_grid);
2140     };
2141     preview_guide_tool = new PreviewGuideTool(preview_helper);
2142     preview_guide_tool->SetGuideStyle((PreviewGuideTool::Guides)m_GuideChoiceProj->GetSelection());
2143 
2144     // activate tools that are always active.
2145     preview_helper->ActivateTool(pano_mask_tool);
2146     // update the blend mode which activates some tools
2147     updateBlendMode();
2148     m_GLPreview->SetPhotometricCorrect(true);
2149     // update toolbar
2150     SetMode(mode_assistant);
2151 }
2152 
MakePanosphereOverviewTools(PanosphereOverviewToolHelper * panosphere_overview_helper_in)2153 void GLPreviewFrame::MakePanosphereOverviewTools(PanosphereOverviewToolHelper *panosphere_overview_helper_in)
2154 {
2155     panosphere_overview_helper = panosphere_overview_helper_in;
2156     overview_drag_tool = new OverviewDragTool(panosphere_overview_helper);
2157     panosphere_overview_camera_tool = new PanosphereOverviewCameraTool(panosphere_overview_helper);
2158     panosphere_overview_helper->ActivateTool(panosphere_overview_camera_tool);
2159     panosphere_overview_identify_tool = new PreviewIdentifyTool(panosphere_overview_helper, this, false);
2160     panosphere_overview_helper->ActivateTool(panosphere_overview_identify_tool);
2161 
2162     panosphere_sphere_tool = new PanosphereSphereTool(panosphere_overview_helper, GetPreviewBackgroundColor());
2163     panosphere_overview_helper->ActivateTool(panosphere_sphere_tool);
2164 
2165     overview_projection_grid = new PanosphereOverviewProjectionGridTool(panosphere_overview_helper);
2166     if(GetMenuBar()->FindItem(XRCID("action_show_grid"))->IsChecked())
2167     {
2168         panosphere_overview_helper->ActivateTool(overview_projection_grid);
2169     }
2170 
2171 
2172     overview_outlines_tool = new PanosphereOverviewOutlinesTool(panosphere_overview_helper, m_GLPreview);
2173     panosphere_overview_helper->ActivateTool(overview_outlines_tool);
2174     panosphere_difference_tool = new PreviewDifferenceTool(panosphere_overview_helper);
2175 
2176     m_panosphere_layoutLinesTool = new PreviewLayoutLinesTool(panosphere_overview_helper);
2177     panosphere_control_point_tool = new PreviewControlPointTool(panosphere_overview_helper);
2178 
2179 
2180 
2181 }
2182 
MakePlaneOverviewTools(PlaneOverviewToolHelper * plane_overview_helper_in)2183 void GLPreviewFrame::MakePlaneOverviewTools(PlaneOverviewToolHelper *plane_overview_helper_in)
2184 {
2185     plane_overview_helper = plane_overview_helper_in;
2186     plane_overview_identify_tool = new PreviewIdentifyTool(plane_overview_helper, this, false);
2187     plane_overview_helper->ActivateTool(plane_overview_identify_tool);
2188 
2189     plane_overview_camera_tool = new PlaneOverviewCameraTool(plane_overview_helper);
2190     plane_overview_helper->ActivateTool(plane_overview_camera_tool);
2191     plane_difference_tool = new PreviewDifferenceTool(plane_overview_helper);
2192 
2193     plane_overview_outlines_tool = new PlaneOverviewOutlinesTool(plane_overview_helper, m_GLPreview);
2194     plane_overview_helper->ActivateTool(plane_overview_outlines_tool);
2195 
2196     m_plane_layoutLinesTool = new PreviewLayoutLinesTool(plane_overview_helper);
2197     plane_control_point_tool = new PreviewControlPointTool(plane_overview_helper);
2198 
2199 }
2200 
OnIdentify(wxCommandEvent & e)2201 void GLPreviewFrame::OnIdentify(wxCommandEvent & e)
2202 {
2203     SetStatusText(wxT(""), 0); // blank status text as it refers to an old tool.
2204     if (e.IsChecked())
2205     {
2206         m_BlendModeChoice->SetSelection(0);
2207         preview_helper->DeactivateTool(difference_tool);
2208         panosphere_overview_helper->DeactivateTool(panosphere_difference_tool);
2209         plane_overview_helper->DeactivateTool(plane_difference_tool);
2210         identify_tool->setConstantOn(true);
2211         panosphere_overview_identify_tool->setConstantOn(true);
2212         plane_overview_identify_tool->setConstantOn(true);
2213 //        TurnOffTools(preview_helper->ActivateTool(identify_tool));
2214 //        TurnOffTools(panosphere_overview_helper->ActivateTool(panosphere_overview_identify_tool));
2215 //        TurnOffTools(plane_overview_helper->ActivateTool(plane_overview_identify_tool));
2216     } else {
2217         identify_tool->setConstantOn(false);
2218         panosphere_overview_identify_tool->setConstantOn(false);
2219         plane_overview_identify_tool->setConstantOn(false);
2220 //        preview_helper->DeactivateTool(identify_tool);
2221 //        panosphere_overview_helper->DeactivateTool(panosphere_overview_identify_tool);
2222 //        plane_overview_helper->DeactivateTool(plane_overview_identify_tool);
2223         CleanButtonColours();
2224     }
2225     m_GLPreview->Refresh();
2226     m_GLOverview->Refresh();
2227 }
2228 
OnControlPoint(wxCommandEvent & e)2229 void GLPreviewFrame::OnControlPoint(wxCommandEvent & e)
2230 {
2231     if (!m_editCP_togglebutton->GetValue())
2232     {
2233         //process event only if edit cp tool is disabled
2234         SetStatusText(wxT(""), 0); // blank status text as it refers to an old tool.
2235         if (e.IsChecked())
2236         {
2237             TurnOffTools(preview_helper->ActivateTool(preview_control_point_tool));
2238             TurnOffTools(panosphere_overview_helper->ActivateTool(panosphere_control_point_tool));
2239             TurnOffTools(plane_overview_helper->ActivateTool(plane_control_point_tool));
2240         }
2241         else {
2242             preview_helper->DeactivateTool(preview_control_point_tool);
2243             panosphere_overview_helper->DeactivateTool(panosphere_control_point_tool);
2244             plane_overview_helper->DeactivateTool(plane_control_point_tool);
2245         }
2246         m_GLPreview->Refresh();
2247         m_GLOverview->Refresh();
2248     };
2249 }
2250 
TurnOffTools(std::set<Tool * > tools)2251 void GLPreviewFrame::TurnOffTools(std::set<Tool*> tools)
2252 {
2253     std::set<Tool*>::iterator i;
2254     for (i = tools.begin(); i != tools.end(); ++i)
2255     {
2256         if (*i == crop_tool)
2257         {
2258             // cover up the guidelines
2259             m_GLPreview->Refresh();
2260         } else if (*i == drag_tool)
2261         {
2262             // cover up its boxes
2263             m_GLPreview->Refresh();
2264         } else if (*i == identify_tool)
2265         {
2266             // disabled the identify tool, toggle its button off.
2267             m_identify_togglebutton->SetValue(false);
2268             // cover up its indicators and restore normal button colours.
2269             m_GLPreview->Refresh();
2270             m_GLOverview->Refresh();
2271             CleanButtonColours();
2272         } else if (*i == preview_control_point_tool)
2273         {
2274             // disabled the control point tool.
2275             XRCCTRL(*this,"preview_control_point_tool",wxCheckBox)->SetValue(false);
2276             // cover up the control point lines.
2277             m_GLPreview->Refresh();
2278             m_GLOverview->Refresh();
2279         }
2280     }
2281 }
2282 
SetImageButtonColour(unsigned int image_nr,unsigned char red,unsigned char green,unsigned char blue)2283 void GLPreviewFrame::SetImageButtonColour(unsigned int image_nr,
2284                                           unsigned char red,
2285                                           unsigned char green,
2286                                           unsigned char blue)
2287 {
2288     // 0, 0, 0 indicates we want to go back to the system colour.
2289     // TODO: Maybe we should test this better on different themes.
2290 #if defined __WXMSW__ || defined __WXMAC__
2291     if (red || green || blue)
2292     {
2293         // the identify tool wants us to highlight an image button in the given
2294         // colour, to match up with the display in the preview.
2295         // on windows change the color of the surhugin_utils::rounding wxPanel
2296         m_ToggleButtonPanel[image_nr]->SetBackgroundColour(wxColour(red, green, blue));
2297     }
2298     else
2299     {
2300         // return to the normal colour
2301         m_ToggleButtonPanel[image_nr]->SetBackgroundColour(m_ToggleButtonPanel[image_nr]->GetParent()->GetBackgroundColour());
2302     }
2303     m_ToggleButtonPanel[image_nr]->Refresh();
2304 #else
2305     if (red || green || blue)
2306     {
2307         // change the color of the wxToggleButton
2308         m_ToggleButtons[image_nr]->SetBackgroundStyle(wxBG_STYLE_COLOUR);
2309         m_ToggleButtons[image_nr]->SetBackgroundColour(wxColour(red, green, blue));
2310         // black should be visible on the button's vibrant colours.
2311         m_ToggleButtons[image_nr]->SetForegroundColour(wxColour(0, 0, 0));
2312     }
2313     else
2314     {
2315         // return to the normal colour
2316         m_ToggleButtons[image_nr]->SetBackgroundStyle(wxBG_STYLE_SYSTEM);
2317         m_ToggleButtons[image_nr]->SetBackgroundColour(wxNullColour);
2318         m_ToggleButtons[image_nr]->SetForegroundColour(wxNullColour);
2319     };
2320     m_ToggleButtons[image_nr]->Refresh();
2321 #endif
2322 }
2323 
CleanButtonColours()2324 void GLPreviewFrame::CleanButtonColours()
2325 {
2326     // when we turn off the identification tool, any buttons that were coloured
2327     // to match the image in the preview should be given back the system themed
2328     // colours.
2329     unsigned int nr_images = m_pano.getNrOfImages();
2330     for (unsigned image = 0; image < nr_images; image++)
2331     {
2332 #if defined __WXMSW__ || defined __WXMAC__
2333         m_ToggleButtonPanel[image]->SetBackgroundColour(m_ToggleButtonPanel[image]->GetParent()->GetBackgroundColour());
2334         m_ToggleButtonPanel[image]->Refresh();
2335 #else
2336         m_ToggleButtons[image]->SetBackgroundStyle(wxBG_STYLE_SYSTEM);
2337         m_ToggleButtons[image]->SetBackgroundColour(wxNullColour);
2338         m_ToggleButtons[image]->SetForegroundColour(wxNullColour);
2339         m_ToggleButtons[image]->Refresh();
2340 #endif
2341     }
2342 }
2343 
OnColorPicker(wxCommandEvent & e)2344 void GLPreviewFrame::OnColorPicker(wxCommandEvent &e)
2345 {
2346     // blank status text as it refers to an old tool.
2347     SetStatusText(wxT(""), 0);
2348     if (e.IsChecked())
2349     {
2350         // deactivate delete cp tool if active
2351         preview_helper->DeactivateTool(edit_cp_tool);
2352         m_editCP_togglebutton->SetValue(false);
2353         preview_helper->ActivateTool(color_picker_tool);
2354     }
2355     else
2356     {
2357         preview_helper->DeactivateTool(color_picker_tool);
2358     };
2359     m_GLPreview->Refresh();
2360 };
2361 
UpdateGlobalWhiteBalance(double redFactor,double blueFactor)2362 void GLPreviewFrame::UpdateGlobalWhiteBalance(double redFactor, double blueFactor)
2363 {
2364     PanoCommand::GlobalCmdHist::getInstance().addCommand(
2365         new PanoCommand::UpdateWhiteBalance(m_pano, redFactor, blueFactor)
2366         );
2367     //now toggle button and deactivate tool
2368     m_colorpicker_togglebutton->SetValue(false);
2369     //direct deactivation of tool does not work because this function is called by the tool itself
2370     //so we are send an event to deactivate the tool
2371     wxCommandEvent e(wxEVT_COMMAND_TOOL_CLICKED, XRCID("preview_color_picker_tool"));
2372     e.SetInt(0);
2373     GetEventHandler()->AddPendingEvent(e);
2374 };
2375 
OnEditCPTool(wxCommandEvent & e)2376 void GLPreviewFrame::OnEditCPTool(wxCommandEvent &e)
2377 {
2378     // blank status text as it refers to an old tool.
2379     SetStatusText(wxT(""), 0);
2380     if (e.IsChecked())
2381     {
2382         // deactivate color picker tool
2383         preview_helper->DeactivateTool(color_picker_tool);
2384         m_colorpicker_togglebutton->SetValue(false);
2385         // show automatically all cp
2386         preview_helper->ActivateTool(preview_control_point_tool);
2387         preview_helper->ActivateTool(edit_cp_tool);
2388     }
2389     else
2390     {
2391         if (!XRCCTRL(*this, "preview_control_point_tool", wxCheckBox)->GetValue())
2392         {
2393             preview_helper->DeactivateTool(preview_control_point_tool);
2394         };
2395         preview_helper->DeactivateTool(edit_cp_tool);
2396     };
2397     m_GLPreview->Refresh();
2398 };
2399 
ImageToogleButtonEventHandler(unsigned int image_number_in,wxToggleButton * identify_button_in,HuginBase::Panorama * m_pano_in)2400 ImageToogleButtonEventHandler::ImageToogleButtonEventHandler(
2401                                   unsigned int image_number_in,
2402                                   wxToggleButton* identify_button_in,
2403                                   HuginBase::Panorama * m_pano_in)
2404 {
2405     image_number = image_number_in;
2406     m_identify_button = identify_button_in;
2407     m_pano = m_pano_in;
2408 }
2409 
OnEnter(wxMouseEvent & e)2410 void ImageToogleButtonEventHandler::OnEnter(wxMouseEvent & e)
2411 {
2412     // When using the identify tool, we want to identify image locations when
2413     // the user moves the mouse over the image buttons, but only if the image
2414     // is being shown.
2415     if (
2416         m_identify_button->GetValue() &&
2417         m_pano->getActiveImages().count(image_number))
2418     {
2419         std::vector<PreviewIdentifyTool**>::iterator it;
2420         for(it = identify_tools.begin() ; it != identify_tools.end() ; ++it) {
2421             (*(*it))->ShowImageNumber(image_number);
2422         }
2423     }
2424     e.Skip();
2425 }
2426 
OnLeave(wxMouseEvent & e)2427 void ImageToogleButtonEventHandler::OnLeave(wxMouseEvent & e)
2428 {
2429     // if the mouse left one of the image toggle buttons with the identification
2430     // tool active, we should stop showing the image indicator for that button.
2431     if (
2432         m_identify_button->GetValue() &&
2433         m_pano->getActiveImages().count(image_number))
2434     {
2435         std::vector<PreviewIdentifyTool**>::iterator it;
2436         for(it = identify_tools.begin() ; it != identify_tools.end() ; ++it) {
2437             (*(*it))->StopShowingImages();
2438         }
2439     }
2440     e.Skip();
2441 }
2442 
OnChange(wxCommandEvent & e)2443 void ImageToogleButtonEventHandler::OnChange(wxCommandEvent & e)
2444 {
2445     // the user is turning on or off an image using its button. We want to turn
2446     // the indicators on and off if appropriate correctly to. We use OnEnter
2447     // and OnLeave for the indicators, but these only work when the image is
2448     // showing, so we are carefull of the order:
2449     HuginBase::UIntSet activeImages = m_pano->getActiveImages();
2450     wxMouseEvent null_event;
2451     if (e.IsChecked()) {
2452         activeImages.insert(image_number);
2453         PanoCommand::GlobalCmdHist::getInstance().addCommand(
2454             new PanoCommand::SetActiveImagesCmd(*m_pano, activeImages)
2455         );
2456         OnEnter(null_event);
2457     } else {
2458         OnLeave(null_event);
2459         activeImages.erase(image_number);
2460         PanoCommand::GlobalCmdHist::getInstance().addCommand(
2461             new PanoCommand::SetActiveImagesCmd(*m_pano, activeImages)
2462         );
2463     }
2464 }
2465 
AddIdentifyTool(PreviewIdentifyTool ** identify_tool_in)2466 void ImageToogleButtonEventHandler::AddIdentifyTool(PreviewIdentifyTool** identify_tool_in) {
2467     identify_tools.push_back(identify_tool_in);
2468 }
2469 
ImageGroupButtonEventHandler(unsigned int image_number,GLPreviewFrame * frame_in,HuginBase::Panorama * m_pano)2470 ImageGroupButtonEventHandler::ImageGroupButtonEventHandler(unsigned int image_number, GLPreviewFrame* frame_in, HuginBase::Panorama* m_pano)
2471     : image_number(image_number), frame(frame_in), m_pano(m_pano) {}
2472 
AddIdentifyTool(PreviewIdentifyTool ** identify_tool_in)2473 void ImageGroupButtonEventHandler::AddIdentifyTool(PreviewIdentifyTool** identify_tool_in) {
2474     identify_tools.push_back(identify_tool_in);
2475 }
2476 
2477 
OnEnter(wxMouseEvent & e)2478 void ImageGroupButtonEventHandler::OnEnter(wxMouseEvent & e)
2479 {
2480     //mark the image
2481     if (m_pano->getActiveImages().count(image_number))
2482     {
2483         std::vector<PreviewIdentifyTool**>::iterator it;
2484         for(it = identify_tools.begin() ; it != identify_tools.end() ; ++it) {
2485             (*(*it))->ShowImageNumber(image_number);
2486         }
2487     }
2488     e.Skip();
2489 }
2490 
OnLeave(wxMouseEvent & e)2491 void ImageGroupButtonEventHandler::OnLeave(wxMouseEvent & e)
2492 {
2493     //unmark the image
2494     if (m_pano->getActiveImages().count(image_number))
2495     {
2496         std::vector<PreviewIdentifyTool**>::iterator it;
2497         for(it = identify_tools.begin() ; it != identify_tools.end() ; ++it) {
2498             (*(*it))->StopShowingImages();
2499         }
2500     }
2501     e.Skip();
2502 }
2503 
OnChange(wxCommandEvent & e)2504 void ImageGroupButtonEventHandler::OnChange(wxCommandEvent & e)
2505 {
2506     wxMouseEvent null_event;
2507     if (e.IsChecked()) {
2508         frame->AddImageToDragGroup(image_number,false);
2509         OnEnter(null_event);
2510     } else {
2511         OnLeave(null_event);
2512         frame->RemoveImageFromDragGroup(image_number,false);
2513     }
2514 }
2515 
AddDragTool(DragTool ** drag_tool_in)2516 void ImageGroupButtonEventHandler::AddDragTool(DragTool** drag_tool_in) {
2517     drag_tools.push_back(drag_tool_in);
2518 }
2519 
individualDragging()2520 bool GLPreviewFrame::individualDragging()
2521 {
2522     return m_DragModeChoice->GetSelection()==1 ||
2523            m_DragModeChoice->GetSelection()==3;
2524 }
2525 
ToggleImageInDragGroup(unsigned int image_nr,bool update_check_box)2526 void GLPreviewFrame::ToggleImageInDragGroup(unsigned int image_nr, bool update_check_box) {
2527     if (imageDragGroup.count(image_nr) == 0) {
2528         this->AddImageToDragGroup(image_nr, update_check_box);
2529     } else {
2530         this->RemoveImageFromDragGroup(image_nr, update_check_box);
2531     }
2532 }
RemoveImageFromDragGroup(unsigned int image_nr,bool update_check_box)2533 void GLPreviewFrame::RemoveImageFromDragGroup(unsigned int image_nr, bool update_check_box) {
2534     imageDragGroup.erase(image_nr);
2535     if (update_check_box) {
2536         m_GroupToggleButtons[image_nr]->SetValue(false);
2537     }
2538 }
AddImageToDragGroup(unsigned int image_nr,bool update_check_box)2539 void GLPreviewFrame::AddImageToDragGroup(unsigned int image_nr, bool update_check_box) {
2540     imageDragGroup.insert(image_nr);
2541     if (update_check_box) {
2542         m_GroupToggleButtons[image_nr]->SetValue(true);
2543     }
2544 }
SetDragGroupImages(HuginBase::UIntSet imageDragGroup_in,bool update_check_box)2545 void GLPreviewFrame::SetDragGroupImages(HuginBase::UIntSet imageDragGroup_in, bool update_check_box) {
2546     imageDragGroup.swap(imageDragGroup_in);
2547     std::vector<wxCheckBox*>::iterator it;
2548     unsigned int nr = 0;
2549     for(it = m_GroupToggleButtons.begin() ; it != m_GroupToggleButtons.end() ; ++it) {
2550         (*it)->SetValue(imageDragGroup.count(nr++)>0);
2551     }
2552 }
GetDragGroupImages()2553 HuginBase::UIntSet GLPreviewFrame::GetDragGroupImages() {
2554     return imageDragGroup;
2555 }
ClearDragGroupImages(bool update_check_box)2556 void GLPreviewFrame::ClearDragGroupImages(bool update_check_box) {
2557     imageDragGroup.clear();
2558     std::vector<wxCheckBox*>::iterator it;
2559     for(it = m_GroupToggleButtons.begin() ; it != m_GroupToggleButtons.end() ; ++it) {
2560         (*it)->SetValue(false);
2561     }
2562 }
2563 
EnableGroupCheckboxes(bool isShown)2564 void GLPreviewFrame::EnableGroupCheckboxes(bool isShown)
2565 {
2566     std::vector<wxCheckBox*>::iterator it;
2567     for(it = m_GroupToggleButtons.begin() ; it != m_GroupToggleButtons.end() ; ++it)
2568     {
2569         (*it)->Show(isShown);
2570     }
2571     Layout();
2572 };
2573 
2574 /** call this method only with existing OpenGL context */
FillBlendChoice()2575 void GLPreviewFrame::FillBlendChoice()
2576 {
2577     if(PreviewDifferenceTool::CheckOpenGLCanDifference())
2578         m_differenceIndex=m_BlendModeChoice->Append(_("difference"));
2579     // update size
2580     m_BlendModeChoice->InvalidateBestSize();
2581     m_BlendModeChoice->GetParent()->Layout();
2582     Refresh();
2583     // get blend mode last state
2584     unsigned int oldMode = wxConfigBase::Get()->Read(wxT("/GLPreviewFrame/blendMode"), 0l);
2585     // limit old state to max available states
2586     if (oldMode >= m_BlendModeChoice->GetCount())
2587     {
2588         oldMode = 0;
2589     }
2590     m_BlendModeChoice->SetSelection(oldMode);
2591     updateBlendMode();
2592 };
2593 
OnAutocrop(wxCommandEvent & e)2594 void GLPreviewFrame::OnAutocrop(wxCommandEvent &e)
2595 {
2596     DEBUG_INFO("Dirty ROI Calc\n");
2597     if (m_pano.getActiveImages().empty())
2598     {
2599         return;
2600     };
2601 
2602     vigra::Rect2D newROI;
2603     {
2604         ProgressReporterDialog progress(0, _("Autocrop"), _("Calculating optimal crop"), this);
2605         HuginBase::CalculateOptimalROI cropPano(m_pano, &progress);
2606         cropPano.run();
2607         if (cropPano.hasRunSuccessfully())
2608         {
2609             newROI = cropPano.getResultOptimalROI();
2610         };
2611     };
2612 
2613     //set the ROI - fail if the right/bottom is zero, meaning all zero
2614     if(!newROI.isEmpty())
2615     {
2616         HuginBase::PanoramaOptions opt = m_pano.getOptions();
2617         opt.setROI(newROI);
2618         PanoCommand::GlobalCmdHist::getInstance().addCommand(
2619             new PanoCommand::SetPanoOptionsCmd(m_pano, opt )
2620             );
2621     }
2622 }
2623 
OnStackAutocrop(wxCommandEvent & e)2624 void GLPreviewFrame::OnStackAutocrop(wxCommandEvent &e)
2625 {
2626     DEBUG_INFO("Dirty ROI Calc\n");
2627     if (m_pano.getActiveImages().empty())
2628     {
2629         return;
2630     };
2631 
2632     vigra::Rect2D newROI;
2633     {
2634         ProgressReporterDialog progress(0, _("Autocrop"), _("Calculating optimal crop"), this);
2635         HuginBase::UIntSet activeImages = m_pano.getActiveImages();
2636         std::vector<HuginBase::UIntSet> stackImgs = getHDRStacks(m_pano, activeImages, m_pano.getOptions());
2637         HuginBase::CalculateOptimalROI cropPano(m_pano, &progress);
2638         //only use hdr autocrop for projects with stacks
2639         //otherwise fall back to "normal" autocrop
2640         if (stackImgs.size()<activeImages.size())
2641         {
2642             cropPano.setStacks(stackImgs);
2643         }
2644         cropPano.run();
2645         if (cropPano.hasRunSuccessfully())
2646         {
2647             newROI = cropPano.getResultOptimalROI();
2648         };
2649     };
2650 
2651     //set the ROI - fail if the right/bottom is zero, meaning all zero
2652     if(!newROI.isEmpty())
2653     {
2654         HuginBase::PanoramaOptions opt = m_pano.getOptions();
2655         opt.setROI(newROI);
2656         PanoCommand::GlobalCmdHist::getInstance().addCommand(
2657             new PanoCommand::SetPanoOptionsCmd(m_pano, opt )
2658             );
2659     }
2660 }
2661 
OnFullScreen(wxCommandEvent & e)2662 void GLPreviewFrame::OnFullScreen(wxCommandEvent & e)
2663 {
2664     ShowFullScreen(!IsFullScreen(), wxFULLSCREEN_NOBORDER | wxFULLSCREEN_NOCAPTION);
2665 };
2666 
SetMode(int newMode)2667 void GLPreviewFrame::SetMode(int newMode)
2668 {
2669     if(m_mode==newMode)
2670         return;
2671     SetStatusText(wxT(""), 0); // blank status text as it refers to an old tool.
2672     switch(m_mode)
2673     {
2674         case mode_assistant:
2675         case mode_preview:
2676             // switch off identify and show cp tool
2677             identify_tool->setConstantOn(false);
2678             panosphere_overview_identify_tool->setConstantOn(false);
2679             plane_overview_identify_tool->setConstantOn(false);
2680             preview_helper->DeactivateTool(color_picker_tool);
2681             m_colorpicker_togglebutton->SetValue(false);
2682 //            preview_helper->DeactivateTool(identify_tool);
2683 //            panosphere_overview_helper->DeactivateTool(panosphere_overview_identify_tool);
2684 //            plane_overview_helper->DeactivateTool(plane_overview_identify_tool);
2685             preview_helper->DeactivateTool(edit_cp_tool);
2686             m_editCP_togglebutton->SetValue(false);
2687 
2688             CleanButtonColours();
2689             m_identify_togglebutton->SetValue(false);
2690             preview_helper->DeactivateTool(preview_control_point_tool);
2691             panosphere_overview_helper->DeactivateTool(panosphere_control_point_tool);
2692             plane_overview_helper->DeactivateTool(plane_control_point_tool);
2693             XRCCTRL(*this,"preview_control_point_tool",wxCheckBox)->SetValue(false);
2694             break;
2695         case mode_layout:
2696             // disable layout mode.
2697             preview_helper->DeactivateTool(m_preview_layoutLinesTool);
2698             panosphere_overview_helper->DeactivateTool(m_panosphere_layoutLinesTool);
2699             plane_overview_helper->DeactivateTool(m_plane_layoutLinesTool);
2700             // reactivate identify and camera tool when leaving layout mode
2701             preview_helper->ActivateTool(identify_tool);
2702             preview_helper->ActivateTool(camera_tool);
2703             panosphere_overview_helper->ActivateTool(panosphere_overview_identify_tool);
2704             plane_overview_helper->ActivateTool(plane_overview_identify_tool);
2705             m_GLPreview->SetLayoutMode(false);
2706             m_GLOverview->SetLayoutMode(false);
2707             // Switch the panorama mask back on.
2708             preview_helper->ActivateTool(pano_mask_tool);
2709             //restore blend mode
2710             m_BlendModeChoice->SetSelection(non_layout_blend_mode);
2711             updateBlendMode();
2712             break;
2713         case mode_projection:
2714             preview_helper->DeactivateTool(preview_guide_tool);
2715             break;
2716         case mode_drag:
2717             preview_helper->DeactivateTool(preview_guide_tool);
2718             preview_helper->DeactivateTool(drag_tool);
2719             panosphere_overview_helper->DeactivateTool(overview_drag_tool);
2720             if (individualDragging()) {
2721                 std::vector<wxCheckBox*>::iterator it;
2722                 for(it = m_GroupToggleButtons.begin() ; it != m_GroupToggleButtons.end() ; ++it) {
2723                     (*it)->Show(false);
2724                 }
2725             }
2726             break;
2727         case mode_crop:
2728             preview_helper->DeactivateTool(preview_guide_tool);
2729             preview_helper->DeactivateTool(crop_tool);
2730             break;
2731     };
2732     m_mode=newMode;
2733     wxScrollEvent dummy;
2734     switch(m_mode)
2735     {
2736         case mode_assistant:
2737         case mode_preview:
2738             break;
2739         case mode_layout:
2740             //save blend mode setting, set to normal for layout mode
2741             non_layout_blend_mode=m_BlendModeChoice->GetSelection();
2742             m_BlendModeChoice->SetSelection(0);
2743             updateBlendMode();
2744             // turn off things not used in layout mode.
2745             preview_helper->DeactivateTool(pano_mask_tool);
2746             preview_helper->DeactivateTool(camera_tool);
2747             // deactivate identify tool in layout mode
2748             preview_helper->DeactivateTool(identify_tool);
2749             panosphere_overview_helper->DeactivateTool(panosphere_overview_identify_tool);
2750             plane_overview_helper->DeactivateTool(plane_overview_identify_tool);
2751             m_GLPreview->SetLayoutMode(true);
2752             m_GLOverview->SetLayoutMode(true);
2753             preview_helper->ActivateTool(m_preview_layoutLinesTool);
2754             panosphere_overview_helper->ActivateTool(m_panosphere_layoutLinesTool);
2755             plane_overview_helper->ActivateTool(m_plane_layoutLinesTool);
2756             // we need to update the meshes after switch to layout mode
2757             // otherwise the following update of scale has no meshes to scale
2758             m_GLPreview->Update();
2759             m_GLOverview->Update();
2760             OnLayoutScaleChange(dummy);
2761             break;
2762         case mode_projection:
2763             preview_helper->ActivateTool(preview_guide_tool);
2764             break;
2765         case mode_drag:
2766             preview_helper->ActivateTool(preview_guide_tool);
2767             TurnOffTools(preview_helper->ActivateTool(drag_tool));
2768             TurnOffTools(panosphere_overview_helper->ActivateTool(overview_drag_tool));
2769             if (individualDragging()) {
2770                 std::vector<wxCheckBox*>::iterator it;
2771                 for(it = m_GroupToggleButtons.begin() ; it != m_GroupToggleButtons.end() ; ++it) {
2772                     (*it)->Show(true);
2773                 }
2774             }
2775             break;
2776         case mode_crop:
2777             TurnOffTools(preview_helper->ActivateTool(crop_tool));
2778             preview_helper->ActivateTool(preview_guide_tool);
2779             break;
2780     };
2781     //enable group checkboxes only for drag mode tab
2782     EnableGroupCheckboxes(m_mode==mode_drag && individualDragging());
2783     m_GLPreview->Refresh();
2784 };
2785 
OnSelectMode(wxNotebookEvent & e)2786 void GLPreviewFrame::OnSelectMode(wxNotebookEvent &e)
2787 {
2788     if(m_mode!=-1)
2789         SetMode(e.GetSelection());
2790 };
2791 
OnToolModeChanging(wxNotebookEvent & e)2792 void GLPreviewFrame::OnToolModeChanging(wxNotebookEvent &e)
2793 {
2794     if(m_pano.getNrOfImages()==0 && e.GetOldSelection()==0)
2795     {
2796         wxBell();
2797         e.Veto();
2798     };
2799 };
2800 
OnROIChanged(wxCommandEvent & e)2801 void GLPreviewFrame::OnROIChanged ( wxCommandEvent & e )
2802 {
2803     HuginBase::PanoramaOptions opt = m_pano.getOptions();
2804     long left, right, top, bottom;
2805     if (!m_ROITopTxt->GetValue().ToLong(&top)) {
2806         wxLogError(_("Top needs to be an integer bigger than 0"));
2807         return;
2808     }
2809     if (!m_ROILeftTxt->GetValue().ToLong(&left)) {
2810         wxLogError(_("left needs to be an integer bigger than 0"));
2811         return;
2812     }
2813     if (!m_ROIRightTxt->GetValue().ToLong(&right)) {
2814         wxLogError(_("right needs to be an integer bigger than 0"));
2815         return;
2816     }
2817     if (!m_ROIBottomTxt->GetValue().ToLong(&bottom)) {
2818         wxLogError(_("bottom needs to be an integer bigger than 0"));
2819         return;
2820     }
2821     opt.setROI(vigra::Rect2D(left, top, right, bottom));
2822     // make sure that left is really to the left of right
2823     if(opt.getROI().width()<1) {
2824         wxLogError(_("left boundary must be smaller than right"));
2825         UpdateRoiDisplay(m_pano.getOptions());
2826         return;
2827     }
2828     // make sure that top is really higher than bottom
2829     if(opt.getROI().height()<1) {
2830         wxLogError(_("top boundary must be smaller than bottom"));
2831         UpdateRoiDisplay(m_pano.getOptions());
2832         return;
2833     }
2834 
2835     PanoCommand::GlobalCmdHist::getInstance().addCommand(
2836             new PanoCommand::SetPanoOptionsCmd( m_pano, opt )
2837                                            );
2838 };
2839 
OnResetCrop(wxCommandEvent & e)2840 void GLPreviewFrame::OnResetCrop(wxCommandEvent &e)
2841 {
2842     HuginBase::PanoramaOptions opt = m_pano.getOptions();
2843     opt.setROI(vigra::Rect2D(0,0,opt.getWidth(),opt.getHeight()));
2844     PanoCommand::GlobalCmdHist::getInstance().addCommand(new PanoCommand::SetPanoOptionsCmd(m_pano, opt));
2845 };
2846 
OnHFOVChanged(wxCommandEvent & e)2847 void GLPreviewFrame::OnHFOVChanged ( wxCommandEvent & e )
2848 {
2849     HuginBase::PanoramaOptions opt = m_pano.getOptions();
2850 
2851 
2852     wxString text = m_HFOVText->GetValue();
2853     DEBUG_INFO ("HFOV = " << text.mb_str(wxConvLocal) );
2854     if (text == wxT("")) {
2855         return;
2856     }
2857 
2858     double hfov;
2859     if (!hugin_utils::str2double(text, hfov)) {
2860         wxLogError(_("Value must be numeric."));
2861         return;
2862     }
2863 
2864     if ( hfov <=0 || hfov > opt.getMaxHFOV()) {
2865         wxLogError(wxString::Format(
2866             _("Invalid HFOV value. Maximum HFOV for this projection is %lf."),
2867             opt.getMaxHFOV()));
2868         hfov=opt.getMaxHFOV();
2869     }
2870     opt.setHFOV(hfov);
2871     // recalculate panorama height...
2872     PanoCommand::GlobalCmdHist::getInstance().addCommand(
2873         new PanoCommand::SetPanoOptionsCmd( m_pano, opt )
2874         );
2875 
2876     DEBUG_INFO ( "new hfov: " << hfov )
2877 };
2878 
OnVFOVChanged(wxCommandEvent & e)2879 void GLPreviewFrame::OnVFOVChanged ( wxCommandEvent & e )
2880 {
2881     HuginBase::PanoramaOptions opt = m_pano.getOptions();
2882 
2883     wxString text = m_VFOVText->GetValue();
2884     DEBUG_INFO ("VFOV = " << text.mb_str(wxConvLocal) );
2885     if (text == wxT("")) {
2886         return;
2887     }
2888 
2889     double vfov;
2890     if (!hugin_utils::str2double(text, vfov)) {
2891         wxLogError(_("Value must be numeric."));
2892         return;
2893     }
2894 
2895     if ( vfov <=0 || vfov > opt.getMaxVFOV()) {
2896         wxLogError(wxString::Format(
2897             _("Invalid VFOV value. Maximum VFOV for this projection is %lf."),
2898             opt.getMaxVFOV()));
2899         vfov = opt.getMaxVFOV();
2900     }
2901     opt.setVFOV(vfov);
2902     // recalculate panorama height...
2903     PanoCommand::GlobalCmdHist::getInstance().addCommand(
2904         new PanoCommand::SetPanoOptionsCmd( m_pano, opt )
2905         );
2906 
2907     DEBUG_INFO ( "new vfov: " << vfov )
2908 };
2909 
OnLayoutScaleChange(wxScrollEvent & e)2910 void GLPreviewFrame::OnLayoutScaleChange(wxScrollEvent &e)
2911 {
2912     if(m_mode==mode_layout)
2913     {
2914         double scale_factor=XRCCTRL(*this,"layout_scale_slider",wxSlider)->GetValue();
2915         m_GLPreview->SetLayoutScale(10.0 - sqrt(scale_factor));
2916         m_GLOverview->SetLayoutScale(10.0 - sqrt(scale_factor));
2917         m_GLPreview->Refresh();
2918         m_GLOverview->Refresh();
2919     };
2920 };
2921 
ShowProjectionWarnings()2922 void GLPreviewFrame::ShowProjectionWarnings()
2923 {
2924     HuginBase::PanoramaOptions opts = m_pano.getOptions();
2925     double hfov = opts.getHFOV();
2926     double vfov = opts.getVFOV();
2927     double maxfov = hfov > vfov ? hfov : vfov;
2928     wxString message;
2929     // If this is set to true, offer rectilinear as an alternative if it fits.
2930     bool rectilinear_option = false;
2931     switch (opts.getProjection()) {
2932         case HuginBase::PanoramaOptions::RECTILINEAR:
2933             if (maxfov > 120.0) {
2934                             // wide rectilinear image
2935                 message = _("With a wide field of view, panoramas with rectilinear projection get very stretched towards the edges.\n");
2936                 if (vfov < 110) {
2937                     message += _("Since the field of view is only very wide in the horizontal direction, try a cylindrical projection instead.");
2938                 } else {
2939                     message += _("For a very wide panorama, try equirectangular projection instead.");
2940                 }
2941                 message += wxT(" ");
2942                 message += _("You could also try Panini projection.");
2943             }
2944             break;
2945         case HuginBase::PanoramaOptions::CYLINDRICAL:
2946             if (vfov > 120.0) {
2947                 message = _("With a wide vertical field of view, panoramas with cylindrical projection get very stretched at the top and bottom.\nAn equirectangular projection would fit the same content in less vertical space.");
2948             } else rectilinear_option = true;
2949             break;
2950         case HuginBase::PanoramaOptions::EQUIRECTANGULAR:
2951             if (vfov < 110.0 && hfov > 120.0)
2952             {
2953                 message = _("Since the vertical field of view is not too wide, you could try setting the panorama projection to cylindrical.\nCylindrical projection preserves vertical lines, unlike equirectangular.");
2954             } else rectilinear_option = true;
2955             break;
2956         case HuginBase::PanoramaOptions::FULL_FRAME_FISHEYE:
2957             if (maxfov < 280.0) {
2958                 rectilinear_option = true;
2959                 message = _("Stereographic projection is conformal, unlike this Fisheye panorama projection.\nA conformal projection preserves angles around a point, which often makes it easier on the eye.");
2960             }
2961             break;
2962         case HuginBase::PanoramaOptions::STEREOGRAPHIC:
2963             if (maxfov > 300.0) {
2964                 message = _("Panoramas with stereographic projection and a very wide field of view stretch the image around the edges a lot.\nThe Fisheye panorama projection compresses it, so you can fit in a wide field of view and still have a reasonable coverage of the middle.");
2965             } else rectilinear_option = true;
2966             break;
2967         default:
2968             rectilinear_option = true;
2969     }
2970     if (rectilinear_option && maxfov < 110.0) {
2971         message = _("Setting the panorama to rectilinear projection would keep the straight lines straight.");
2972     }
2973     if (message.IsEmpty()) {
2974         // no message needed.
2975         m_infoBar->Dismiss();
2976     } else {
2977         m_infoBar->ShowMessage(message, wxICON_INFORMATION);
2978     }
2979 };
2980 
SetShowProjectionHints(bool new_value)2981 void GLPreviewFrame::SetShowProjectionHints(bool new_value)
2982 {
2983     m_showProjectionHints=new_value;
2984     if(!m_showProjectionHints)
2985     {
2986         m_infoBar->Dismiss();
2987     };
2988 };
2989 
OnHideProjectionHints(wxCommandEvent & e)2990 void GLPreviewFrame::OnHideProjectionHints(wxCommandEvent &e)
2991 {
2992     wxMessageBox(_("You have hidden the infobar, which shows hints about selection of projection.\nIf you want to see the bar again, activate the bar in the preferences again."),
2993 #ifdef __WXMSW__
2994         _("Hugin"),
2995 #else
2996         wxT(""),
2997 #endif
2998         wxOK | wxICON_INFORMATION, this);
2999 
3000     wxConfigBase* cfg=wxConfigBase::Get();
3001     cfg->Write(wxT("/GLPreviewFrame/ShowProjectionHints"), false);
3002     m_showProjectionHints=false;
3003     cfg->Flush();
3004     e.Skip();
3005 };
3006 
UpdateIdentifyTools(std::set<unsigned int> new_image_set)3007 void GLPreviewFrame::UpdateIdentifyTools(std::set<unsigned int> new_image_set)
3008 {
3009     if(identify_tool)
3010     {
3011         identify_tool->UpdateWithNewImageSet(new_image_set);
3012     };
3013     if(panosphere_overview_identify_tool)
3014     {
3015         panosphere_overview_identify_tool->UpdateWithNewImageSet(new_image_set);
3016     };
3017     if(plane_overview_identify_tool)
3018     {
3019         plane_overview_identify_tool->UpdateWithNewImageSet(new_image_set);
3020     };
3021 }
3022 
OnPreviewBackgroundColorChanged(wxColourPickerEvent & e)3023 void GLPreviewFrame::OnPreviewBackgroundColorChanged(wxColourPickerEvent & e) {
3024     m_preview_background_color = XRCCTRL(*this, "preview_background", wxColourPickerCtrl)->GetColour();
3025     wxString c = m_preview_background_color.GetAsString(wxC2S_HTML_SYNTAX);
3026     wxConfigBase* cfg=wxConfigBase::Get();
3027     cfg->Write(wxT("/GLPreviewFrame/PreviewBackground"), c);
3028     cfg->Flush();
3029     panosphere_sphere_tool->SetPreviewBackgroundColor(m_preview_background_color);
3030     m_GLPreview->SetViewerBackground(m_preview_background_color);
3031     m_GLOverview->SetViewerBackground(m_preview_background_color);
3032     redrawPreview();
3033 }
3034 
GetPreviewBackgroundColor()3035 wxColor GLPreviewFrame::GetPreviewBackgroundColor() {
3036   return m_preview_background_color;
3037 }
3038 
OnGuideChanged(wxCommandEvent & e)3039 void GLPreviewFrame::OnGuideChanged(wxCommandEvent &e)
3040 {
3041     if(preview_guide_tool)
3042     {
3043         int selection=e.GetSelection();
3044         preview_guide_tool->SetGuideStyle((PreviewGuideTool::Guides)selection);
3045         //synchronize wxChoice in projection and crop tab
3046         m_GuideChoiceCrop->SetSelection(selection);
3047         m_GuideChoiceProj->SetSelection(selection);
3048         m_GuideChoiceDrag->SetSelection(selection);
3049         redrawPreview();
3050     };
3051 };
3052 
SetGuiLevel(GuiLevel newLevel)3053 void GLPreviewFrame::SetGuiLevel(GuiLevel newLevel)
3054 {
3055     int old_selection=m_DragModeChoice->GetSelection();
3056     if(old_selection==wxNOT_FOUND)
3057     {
3058         old_selection=0;
3059     };
3060     m_DragModeChoice->Clear();
3061     m_DragModeChoice->Append(_("normal"));
3062     m_DragModeChoice->Append(_("normal, individual"));
3063     if(newLevel==GUI_EXPERT)
3064     {
3065         m_DragModeChoice->Append(_("mosaic"));
3066         m_DragModeChoice->Append(_("mosaic, individual"));
3067         m_DragModeChoice->SetSelection(old_selection);
3068     }
3069     else
3070     {
3071         if(old_selection>1)
3072         {
3073             m_DragModeChoice->SetSelection(old_selection-2);
3074         }
3075         else
3076         {
3077             m_DragModeChoice->SetSelection(old_selection);
3078         };
3079     };
3080     DragChoiceLayout(m_DragModeChoice->GetSelection());
3081     wxCommandEvent dummy;
3082     OnDragChoice(dummy);
3083 
3084     old_selection=m_OverviewModeChoice->GetSelection();
3085     m_OverviewModeChoice->Clear();
3086     m_OverviewModeChoice->Append(_("Panosphere"));
3087     if(newLevel==GUI_EXPERT)
3088     {
3089         m_OverviewModeChoice->Append(_("Mosaic plane"));
3090     };
3091     if(newLevel==GUI_EXPERT && old_selection==1)
3092     {
3093         m_OverviewModeChoice->SetSelection(1);
3094     }
3095     else
3096     {
3097         m_GLOverview->SetMode(GLOverview::PANOSPHERE);
3098         m_OverviewModeChoice->SetSelection(0);
3099     };
3100     m_overviewCommandPanel->Show(newLevel==GUI_EXPERT);
3101     m_overviewCommandPanel->GetParent()->Layout();
3102     if(newLevel==GUI_SIMPLE)
3103     {
3104 #ifdef __WXMAC__
3105         wxApp::s_macExitMenuItemId = XRCID("action_exit_preview");
3106 #endif
3107         if(m_guiLevel!=GUI_SIMPLE)
3108         {
3109             GetMenuBar()->Remove(0);
3110             GetMenuBar()->Insert(0, m_filemenuSimple, _("&File"));
3111         };
3112         SetTitle(MainFrame::Get()->GetTitle());
3113     }
3114     else
3115     {
3116 #ifdef __WXMAC__
3117         wxApp::s_macExitMenuItemId = XRCID("action_exit_hugin");
3118 #endif
3119         if(m_guiLevel==GUI_SIMPLE)
3120         {
3121             GetMenuBar()->Remove(0);
3122             GetMenuBar()->Insert(0, m_filemenuAdvanced, _("&File"));
3123         };
3124         SetTitle(_("Fast Panorama preview"));
3125     };
3126     m_guiLevel=newLevel;
3127     // update menu items
3128     switch(m_guiLevel)
3129     {
3130         case GUI_SIMPLE:
3131             GetMenuBar()->FindItem(XRCID("action_gui_simple"))->Check();
3132             break;
3133         case GUI_ADVANCED:
3134             GetMenuBar()->FindItem(XRCID("action_gui_advanced"))->Check();
3135             break;
3136         case GUI_EXPERT:
3137             GetMenuBar()->FindItem(XRCID("action_gui_expert"))->Check();
3138             break;
3139     };
3140 };
3141 
OnShowMainFrame(wxCommandEvent & e)3142 void GLPreviewFrame::OnShowMainFrame(wxCommandEvent &e)
3143 {
3144     MainFrame::Get()->Show();
3145     MainFrame::Get()->Raise();
3146 };
3147 
OnUserExit(wxCommandEvent & e)3148 void GLPreviewFrame::OnUserExit(wxCommandEvent &e)
3149 {
3150     Close();
3151 };
3152 
ShowFisheyeCropHint()3153 void ShowFisheyeCropHint()
3154 {
3155     if (wxConfig::Get()->Read(wxT("/ShowFisheyeCropHint"), 1l) == 1)
3156     {
3157         // show hint about crop and open tab when requested
3158         wxDialog dlg;
3159         wxXmlResource::Get()->LoadDialog(&dlg, NULL, wxT("fisheye_show_crop_dlg"));
3160         if (dlg.ShowModal() == wxID_OK)
3161         {
3162             MainFrame::Get()->ShowMaskEditor(0, true);
3163         };
3164         if (XRCCTRL(dlg, "fisheye_crop_dont_ask_checkbox", wxCheckBox)->IsChecked())
3165         {
3166             wxConfig::Get()->Write(wxT("/ShowFisheyeCropHint"), 0l);
3167         };
3168     };
3169 }
3170 
OnLoadImages(wxCommandEvent & e)3171 void GLPreviewFrame::OnLoadImages( wxCommandEvent & e )
3172 {
3173     // load the images.
3174     PanoOperation::AddImageOperation addImage;
3175     HuginBase::UIntSet images;
3176     PanoCommand::PanoCommand* cmd=addImage.GetCommand(wxGetActiveWindow(), m_pano, images, m_guiLevel);
3177     if(cmd==NULL)
3178     {
3179         return;
3180     }
3181     //distribute images only if the existing images are not connected
3182     //otherwise it would destruct the existing image pattern
3183     const bool distributeImages=m_pano.getNrOfCtrlPoints()==0;
3184 
3185     const long autoAlign = wxConfigBase::Get()->Read(wxT("/Assistant/autoAlign"), HUGIN_ASS_AUTO_ALIGN);
3186     if (autoAlign)
3187     {
3188         PanoCommand::GlobalCmdHist::getInstance().addCommand(cmd);
3189         wxCommandEvent dummy;
3190         OnAlign(dummy);
3191     }
3192     else
3193     {
3194         std::vector<PanoCommand::PanoCommand*> cmds;
3195         cmds.push_back(cmd);
3196         if(distributeImages)
3197         {
3198             cmds.push_back(new PanoCommand::DistributeImagesCmd(m_pano));
3199             cmds.push_back(new PanoCommand::CenterPanoCmd(m_pano));
3200         };
3201         PanoCommand::CombinedPanoCommand* combinedCmd = new PanoCommand::CombinedPanoCommand(m_pano, cmds);
3202         combinedCmd->setName("add and distribute images");
3203         PanoCommand::GlobalCmdHist::getInstance().addCommand(combinedCmd);
3204         if(m_pano.getImage(0).isCircularCrop())
3205         {
3206             // show hint about crop for fisheye images
3207             // skip display if we read the information from our lens database
3208             HuginBase::FileMetaData metaData=m_pano.getImage(0).getFileMetadata();
3209             HuginBase::FileMetaData::const_iterator pos = metaData.find("readProjectionFromDB");
3210             if(!(pos != metaData.end() && pos->second == "true"))
3211             {
3212                 ShowFisheyeCropHint();
3213             };
3214         };
3215     };
3216 }
3217 
OnAlign(wxCommandEvent & e)3218 void GLPreviewFrame::OnAlign( wxCommandEvent & e )
3219 {
3220     MainFrame::Get()->RunAssistant(this);
3221 }
3222 
OnCreate(wxCommandEvent & e)3223 void GLPreviewFrame::OnCreate( wxCommandEvent & e )
3224 {
3225     PanoOutputDialog dlg(this, m_pano, m_guiLevel);
3226     if(dlg.ShowModal()==wxID_OK)
3227     {
3228         PanoCommand::GlobalCmdHist::getInstance().addCommand(
3229             new PanoCommand::SetPanoOptionsCmd(m_pano, dlg.GetNewPanoramaOptions())
3230             );
3231         wxCommandEvent dummy;
3232         MainFrame::Get()->OnDoStitch(dummy);
3233     };
3234 }
3235 
OnLensTypeChanged(wxCommandEvent & e)3236 void GLPreviewFrame::OnLensTypeChanged (wxCommandEvent & e)
3237 {
3238     // uses enum Lens::LensProjectionFormat from PanoramaMemento.h
3239     size_t var = GetSelectedValue(m_lensTypeChoice);
3240     const HuginBase::SrcPanoImage& img=m_pano.getImage(0);
3241     if (img.getProjection() != (HuginBase::Lens::LensProjectionFormat) var)
3242     {
3243         double fl = HuginBase::SrcPanoImage::calcFocalLength(img.getProjection(), img.getHFOV(), img.getCropFactor(), img.getSize());
3244         HuginBase::UIntSet imgs;
3245         imgs.insert(0);
3246         std::vector<PanoCommand::PanoCommand*> commands;
3247         commands.push_back(
3248                 new PanoCommand::ChangeImageProjectionCmd(
3249                                     m_pano,
3250                                     imgs,
3251                                     (HuginBase::SrcPanoImage::Projection) var
3252                                 )
3253             );
3254 
3255         commands.push_back(new PanoCommand::UpdateFocalLengthCmd(m_pano, imgs, fl));
3256         switch (var)
3257         {
3258             case HuginBase::SrcPanoImage::RECTILINEAR:
3259             case HuginBase::SrcPanoImage::FULL_FRAME_FISHEYE:
3260             case HuginBase::SrcPanoImage::FISHEYE_STEREOGRAPHIC:
3261             case HuginBase::SrcPanoImage::FISHEYE_EQUISOLID:
3262                 // rectilinear and some fisheye lens, apply command unconditionally
3263                 PanoCommand::GlobalCmdHist::getInstance().addCommand(
3264                     new PanoCommand::CombinedPanoCommand(m_pano, commands));
3265                 break;
3266             case HuginBase::SrcPanoImage::PANORAMIC:
3267                 {
3268                     // cylindrical projection, ask user again
3269                     wxMessageDialog dlg(this, _("Are you sure that the *input* images are in cylindrical projection?"),
3270     #ifdef __WXMSW__
3271                         "Hugin",
3272     #else
3273                         wxEmptyString,
3274     #endif
3275                         wxYES_NO | wxNO_DEFAULT | wxICON_WARNING);
3276                     dlg.SetExtendedMessage(_("If the images are straight from a camera it is very unlikely that the input projection is cylindrical."));
3277                     if (dlg.ShowModal() == wxID_YES)
3278                     {
3279                         // apply command
3280                         PanoCommand::GlobalCmdHist::getInstance().addCommand(
3281                             new PanoCommand::CombinedPanoCommand(m_pano, commands));
3282                     }
3283                     else
3284                     {
3285                         // reset selection
3286                         SelectListValue(m_lensTypeChoice, img.getProjection());
3287                     };
3288                 };
3289                 break;
3290             case HuginBase::SrcPanoImage::EQUIRECTANGULAR:
3291                 if (img.getWidth() == 2 * img.getHeight())
3292                 {
3293                     // image is 2:1, switch to equirectangular
3294                     PanoCommand::GlobalCmdHist::getInstance().addCommand(
3295                         new PanoCommand::CombinedPanoCommand(m_pano, commands));
3296                 }
3297                 else
3298                 {
3299                     // image is not 2:1, show warning
3300                     wxMessageDialog dlg(this, _("Are you sure that the *input* images are equirectangular images?"),
3301 #ifdef __WXMSW__
3302                         "Hugin",
3303 #else
3304                         wxEmptyString,
3305 #endif
3306                         wxYES_NO | wxNO_DEFAULT | wxICON_WARNING);
3307                     dlg.SetExtendedMessage(wxString::Format(_("An equirectangular image normally has a ratio of 2:1. But this image has the dimensions %dx%d."), img.getWidth(), img.getHeight()));
3308                     if (dlg.ShowModal() == wxID_YES)
3309                     {
3310                         // apply command
3311                         PanoCommand::GlobalCmdHist::getInstance().addCommand(
3312                             new PanoCommand::CombinedPanoCommand(m_pano, commands));
3313                     }
3314                     else
3315                     {
3316                         // reset selection
3317                         SelectListValue(m_lensTypeChoice, img.getProjection());
3318                     };
3319                 };
3320                 break;
3321             case HuginBase::SrcPanoImage::CIRCULAR_FISHEYE:
3322             case HuginBase::SrcPanoImage::FISHEYE_ORTHOGRAPHIC:
3323             case HuginBase::SrcPanoImage::FISHEYE_THOBY:
3324                 // fisheye lens, with circular crop
3325                 // apply command
3326                 PanoCommand::GlobalCmdHist::getInstance().addCommand(
3327                     new PanoCommand::CombinedPanoCommand(m_pano, commands));
3328                 // now show hint about crop
3329                 ShowFisheyeCropHint();
3330                 break;
3331         };
3332     };
3333 }
3334 
OnFocalLengthChanged(wxCommandEvent & e)3335 void GLPreviewFrame::OnFocalLengthChanged(wxCommandEvent & e)
3336 {
3337     if (m_pano.getNrOfImages() == 0)
3338     {
3339         return;
3340     };
3341 
3342     // always change first lens
3343     wxString text = m_focalLengthText->GetValue();
3344     DEBUG_INFO("focal length: " << text.mb_str(wxConvLocal));
3345     double val;
3346     if (!hugin_utils::str2double(text, val))
3347     {
3348         return;
3349     }
3350     //no negative values, no zero input please
3351     if (val<0.1)
3352     {
3353         wxBell();
3354         return;
3355     };
3356 
3357     // always change first lens...
3358     if (m_pano.getImage(0).getProjection() == HuginBase::SrcPanoImage::EQUIRECTANGULAR || m_pano.getImage(0).getProjection() == HuginBase::SrcPanoImage::PANORAMIC)
3359     {
3360         HuginBase::VariableMap vars;
3361         vars.insert(std::make_pair("v", HuginBase::Variable("v", val)));
3362         PanoCommand::GlobalCmdHist::getInstance().addCommand(
3363             new PanoCommand::UpdateImageVariablesCmd(m_pano, 0, vars)
3364         );
3365     }
3366     else
3367     {
3368         HuginBase::UIntSet images0;
3369         images0.insert(0);
3370         PanoCommand::GlobalCmdHist::getInstance().addCommand(
3371             new PanoCommand::UpdateFocalLengthCmd(m_pano, images0, val)
3372         );
3373     };
3374 }
3375 
OnCropFactorChanged(wxCommandEvent & e)3376 void GLPreviewFrame::OnCropFactorChanged(wxCommandEvent & e)
3377 {
3378     if (m_pano.getNrOfImages() == 0)
3379     {
3380         return;
3381     };
3382 
3383     wxString text = m_cropFactorText->GetValue();
3384     DEBUG_INFO("crop factor: " << text.mb_str(wxConvLocal));
3385     double val;
3386     if (!hugin_utils::str2double(text, val))
3387     {
3388         return;
3389     }
3390     //no negative values, no zero input please
3391     if (val<0.1)
3392     {
3393         wxBell();
3394         return;
3395     };
3396 
3397     HuginBase::UIntSet images;
3398     images.insert(0);
3399     PanoCommand::GlobalCmdHist::getInstance().addCommand(
3400         new PanoCommand::UpdateCropFactorCmd(m_pano,images,val)
3401     );
3402 }
3403 
3404 // remove cp, relatively easy, we get the selected cp from the edit cp tool
OnRemoveCP(wxCommandEvent & e)3405 void GLPreviewFrame::OnRemoveCP(wxCommandEvent & e)
3406 {
3407     edit_cp_tool->SetMenuProcessed();
3408     PanoCommand::GlobalCmdHist::getInstance().addCommand(new PanoCommand::RemoveCtrlPointsCmd(m_pano, edit_cp_tool->GetFoundCPs()));
3409     // ask user, if pano should be optimized
3410     long afterEditCPAction = wxConfig::Get()->Read(wxT("/EditCPAfterAction"), 0l);
3411     bool optimize = false;
3412     if (afterEditCPAction == 0)
3413     {
3414         wxDialog dlg;
3415         wxXmlResource::Get()->LoadDialog(&dlg, this, wxT("edit_cp_optimize_dialog"));
3416         XRCCTRL(dlg, "edit_cp_text1", wxStaticText)->SetLabel(wxString::Format(_("%lu control points were removed from the panorama.\n\nShould the panorama now be re-optimized?"), static_cast<unsigned long int>(edit_cp_tool->GetFoundCPs().size())));
3417         XRCCTRL(dlg, "edit_cp_text2", wxStaticText)->SetLabel(wxString::Format(_("Current selected optimizer strategy is \"%s\"."), MainFrame::Get()->GetCurrentOptimizerString().c_str()));
3418         dlg.Fit();
3419         optimize = (dlg.ShowModal() == wxID_OK);
3420         if (XRCCTRL(dlg, "edit_cp_dont_show_again_checkbox", wxCheckBox)->GetValue())
3421         {
3422             if (optimize)
3423             {
3424                 wxConfig::Get()->Write(wxT("/EditCPAfterAction"), 1l);
3425             }
3426             else
3427             {
3428                 wxConfig::Get()->Write(wxT("/EditCPAfterAction"), 2l);
3429             };
3430         };
3431     }
3432     else
3433     {
3434         optimize = (afterEditCPAction == 1);
3435     }
3436     if (optimize)
3437     {
3438         // invoke optimization routine
3439         wxCommandEvent ev(wxEVT_COMMAND_BUTTON_CLICKED, XRCID("action_optimize"));
3440         MainFrame::Get()->GetEventHandler()->AddPendingEvent(ev);
3441     };
3442 };
3443 
3444 // some helper for cp generation
3445 // maximal width for remapping for cp generating
3446 #define MAX_DIMENSION 1600
3447 struct FindStruct
3448 {
3449     size_t imgNr;
3450     vigra::BRGBImage image;
3451     vigra::BImage mask;
3452 };
3453 
3454 typedef std::vector<FindStruct> FindVector;
3455 typedef std::multimap<double, vigra::Diff2D> MapPoints;
3456 
3457 static hugin_omp::Lock cpLock;
3458 
OnCreateCP(wxCommandEvent & e)3459 void GLPreviewFrame::OnCreateCP(wxCommandEvent & e)
3460 {
3461     edit_cp_tool->SetMenuProcessed();
3462     vigra::Rect2D roi = edit_cp_tool->GetSelectedROI();
3463     HuginBase::UIntSet imgs = HuginBase::getImagesinROI(m_pano, m_pano.getActiveImages(), roi);
3464     // some checking of conditions
3465     if (imgs.empty())
3466     {
3467         wxMessageBox(_("The selected region contains no active image.\nPlease select a region which is covered by at least 2 images."),
3468 #ifdef __WXMSW__
3469             _("Hugin"),
3470 #else
3471             wxT(""),
3472 #endif
3473             wxOK | wxICON_INFORMATION, this);
3474         return;
3475     };
3476     if (imgs.size() < 2)
3477     {
3478         wxMessageBox(_("The selected region is only covered by a single image.\nCan't create control points for a single image."),
3479 #ifdef __WXMSW__
3480             _("Hugin"),
3481 #else
3482             wxT(""),
3483 #endif
3484             wxOK | wxICON_INFORMATION, this);
3485         return;
3486     };
3487     if (roi.width() > 0.25 * m_pano.getOptions().getWidth())
3488     {
3489         if(wxMessageBox(_("The selected rectangle is very big.\nThis function is only intended for smaller areas. Otherwise unwanted side effect can appear.\n\nProceed anyway?"),
3490 #ifdef __WXMSW__
3491             _("Hugin"),
3492 #else
3493             wxT(""),
3494 #endif
3495             wxYES_NO | wxICON_INFORMATION, this) == wxNO)
3496         {
3497             return;
3498         };
3499     }
3500     HuginBase::PanoramaOptions opts = m_pano.getOptions();
3501     opts.setROI(roi);
3502     // don't correct exposure
3503     opts.outputExposureValue = 0;
3504     // don't use GPU for remapping, this interfere with the fast preview window
3505     opts.remapUsingGPU = false;
3506     // rescale if size is too big
3507     if (roi.width() > MAX_DIMENSION)
3508     {
3509         opts.setWidth(opts.getWidth() * MAX_DIMENSION / roi.width(), true);
3510         roi = opts.getROI();
3511     };
3512     HuginBase::CPVector cps;
3513     {
3514         ProgressReporterDialog progress(2*imgs.size()+1, _("Searching control points"), _("Processing"), this);
3515         // remap all images to panorama projection
3516         FindVector cpInfos;
3517         HuginBase::CPVector tempCps;
3518         for (HuginBase::UIntSet::const_iterator it = imgs.begin(); it != imgs.end(); ++it)
3519         {
3520             const size_t imgNr = *it;
3521             if (!progress.updateDisplayValue(_("Remap image to panorama projection...")))
3522             {
3523                 return;
3524             };
3525             FindStruct findStruct;
3526             findStruct.imgNr = imgNr;
3527             // remap image to panorama projection
3528             ImageCache::ImageCacheRGB8Ptr CachedImg = ImageCache::getInstance().getImage(m_pano.getImage(imgNr).getFilename())->get8BitImage();
3529 
3530             HuginBase::Nona::RemappedPanoImage<vigra::BRGBImage, vigra::BImage>* remapped = new HuginBase::Nona::RemappedPanoImage<vigra::BRGBImage, vigra::BImage>;
3531             HuginBase::SrcPanoImage srcImg = m_pano.getSrcImage(imgNr);
3532             // don't correct exposure
3533             srcImg.setExposureValue(0);
3534             remapped->setPanoImage(srcImg, opts, roi);
3535             remapped->remapImage(vigra::srcImageRange(*CachedImg), vigra_ext::INTERP_CUBIC, &progress);
3536             if (!progress.updateDisplay())
3537             {
3538                 delete remapped;
3539                 return;
3540             };
3541             findStruct.image = remapped->m_image;
3542             findStruct.mask = remapped->m_mask;
3543             delete remapped;
3544             cpInfos.push_back(findStruct);
3545         };
3546         if (cpInfos.size() > 1)
3547         {
3548             // match keypoints in all image pairs
3549             // select a sensible grid size depending on ratio of selected region, maximal should it be 25 regions
3550             unsigned gridx = hugin_utils::roundi(sqrt((double)roi.width() / (double)roi.height() * 25));
3551             if (gridx < 1)
3552             {
3553                 gridx = 1;
3554             }
3555             unsigned gridy = hugin_utils::roundi(25 / gridx);
3556             if (gridy < 1)
3557             {
3558                 gridy = 1;
3559             }
3560             while (roi.width() / gridx < 20 && gridx > 1)
3561             {
3562                 --gridx;
3563             };
3564             while (roi.height() / gridy < 20 && gridy > 1)
3565             {
3566                 --gridy;
3567             };
3568             // template width
3569             const long templWidth = 20;
3570             // search width
3571             const long sWidth = 100;
3572             // match all images with all
3573             for (size_t img1 = 0; img1 < cpInfos.size() - 1; ++img1)
3574             {
3575                 if (!progress.updateDisplayValue(_("Matching interest points...")))
3576                 {
3577                     return;
3578                 };
3579                 vigra::Size2D size(cpInfos[img1].image.width(), cpInfos[img1].image.height());
3580                 // create a number of sub-regions
3581                 std::vector<vigra::Rect2D> rects;
3582                 for (unsigned party = 0; party < gridy; party++)
3583                 {
3584                     for (unsigned partx = 0; partx < gridx; partx++)
3585                     {
3586                         vigra::Rect2D rect(partx*size.x / gridx, party*size.y / gridy,
3587                             (partx + 1)*size.x / gridx, (party + 1)*size.y / gridy);
3588                         rect &= vigra::Rect2D(size);
3589                         if (rect.width()>0 && rect.height()>0)
3590                         {
3591                             rects.push_back(rect);
3592                         };
3593                     };
3594                 };
3595 
3596                 if (!progress.updateDisplay())
3597                 {
3598                     return;
3599                 };
3600 
3601 #pragma omp parallel for schedule(dynamic)
3602                 for (int i = 0; i < rects.size(); ++i)
3603                 {
3604                     MapPoints points;
3605                     vigra::Rect2D rect(rects[i]);
3606                     // run interest point detection in sub-region
3607                     vigra_ext::findInterestPointsPartial(srcImageRange(cpInfos[img1].image, vigra::RGBToGrayAccessor<vigra::RGBValue<vigra::UInt8> >()), rect, 2, 5 * 8, points);
3608                     //check if all points are inside the given image
3609                     MapPoints validPoints;
3610                     for (MapPoints::const_iterator it = points.begin(); it != points.end(); ++it)
3611                     {
3612                         if (cpInfos[img1].mask(it->second.x, it->second.y)>0)
3613                         {
3614                             validPoints.insert(*it);
3615                         };
3616                     };
3617 
3618                     if (!validPoints.empty())
3619                     {
3620                         // now fine-tune the interest points with all other images
3621                         for (size_t img2 = img1 + 1; img2 < cpInfos.size(); ++img2)
3622                         {
3623                             unsigned nGood = 0;
3624                             // loop over all points, starting with the highest corner score
3625                             for (MapPoints::const_reverse_iterator it = validPoints.rbegin(); it != validPoints.rend(); ++it)
3626                             {
3627                                 if (nGood >= 2)
3628                                 {
3629                                     // we have enough points, stop
3630                                     break;
3631                                 }
3632                                 //check if point is covered by second image
3633                                 if (cpInfos[img2].mask(it->second.x, it->second.y) == 0)
3634                                 {
3635                                     continue;
3636                                 };
3637                                 // finally fine-tune point
3638                                 vigra_ext::CorrelationResult res = vigra_ext::PointFineTune(cpInfos[img1].image, vigra::RGBToGrayAccessor<vigra::RGBValue<vigra::UInt8> >(), it->second, templWidth,
3639                                     cpInfos[img2].image, vigra::RGBToGrayAccessor<vigra::RGBValue<vigra::UInt8> >(), it->second, sWidth);
3640                                 if (res.maxi < 0.9)
3641                                 {
3642                                     continue;
3643                                 }
3644                                 nGood++;
3645                                 // add control point
3646                                 {
3647                                     hugin_omp::ScopedLock sl(cpLock);
3648                                     tempCps.push_back(HuginBase::ControlPoint(cpInfos[img1].imgNr, it->second.x, it->second.y,
3649                                         cpInfos[img2].imgNr, res.maxpos.x, res.maxpos.y, HuginBase::ControlPoint::X_Y));
3650                                 };
3651                             };
3652                         };
3653                     };
3654                 };
3655                 // free memory
3656                 cpInfos[img1].image.resize(0, 0);
3657                 cpInfos[img1].mask.resize(0, 0);
3658             };
3659 
3660             // transform coordinates back to image space
3661             for (size_t i = 0; i < tempCps.size(); ++i)
3662             {
3663                 HuginBase::ControlPoint cp = tempCps[i];
3664                 hugin_utils::FDiff2D p1(cp.x1 + roi.left(), cp.y1 + roi.top());
3665                 hugin_utils::FDiff2D p1Img;
3666                 HuginBase::PTools::Transform transform;
3667                 transform.createTransform(m_pano.getImage(cp.image1Nr), opts);
3668                 if (transform.transformImgCoord(p1Img, p1))
3669                 {
3670                     hugin_utils::FDiff2D p2(cp.x2 + roi.left(), cp.y2 + roi.top());
3671                     hugin_utils::FDiff2D p2Img;
3672                     transform.createTransform(m_pano.getImage(cp.image2Nr), opts);
3673                     if (transform.transformImgCoord(p2Img, p2))
3674                     {
3675                         cp.x1 = p1Img.x;
3676                         cp.y1 = p1Img.y;
3677                         cp.x2 = p2Img.x;
3678                         cp.y2 = p2Img.y;
3679                         cps.push_back(cp);
3680                     };
3681                 };
3682             };
3683 
3684             if (!cps.empty())
3685             {
3686                 // check newly found control points
3687                 // create copy
3688                 HuginBase::Panorama copyPano=m_pano.duplicate();
3689                 // remove all cps and set only the new found cp
3690                 copyPano.setCtrlPoints(cps);
3691                 // now create a subpano with only the selected images
3692                 HuginBase::Panorama subPano = copyPano.getSubset(imgs);
3693                 // clean control points
3694                 if (!progress.updateDisplayValue(_("Checking results...")))
3695                 {
3696                     return;
3697                 };
3698                 deregisterPTWXDlgFcn();
3699                 HuginBase::UIntSet invalidCP = HuginBase::getCPoutsideLimit(subPano);
3700                 registerPTWXDlgFcn();
3701                 if (!invalidCP.empty())
3702                 {
3703                     for (HuginBase::UIntSet::const_reverse_iterator it = invalidCP.rbegin(); it != invalidCP.rend(); ++it)
3704                     {
3705                         cps.erase(cps.begin() + *it);
3706                     };
3707                 }
3708                 // force closing progress dialog
3709                 if (!progress.updateDisplayValue())
3710                 {
3711                     return;
3712                 };
3713                 PanoCommand::GlobalCmdHist::getInstance().addCommand(new PanoCommand::AddCtrlPointsCmd(m_pano, cps));
3714                 // ask user, if pano should be optimized
3715                 long afterEditCPAction = wxConfig::Get()->Read(wxT("/EditCPAfterAction"), 0l);
3716                 bool optimize = false;
3717                 if (afterEditCPAction == 0)
3718                 {
3719                     // close progress window, otherwise the dialog don't autoamtically get the focus
3720                     wxYield();
3721                     wxDialog dlg;
3722                     wxXmlResource::Get()->LoadDialog(&dlg, this, wxT("edit_cp_optimize_dialog"));
3723                     XRCCTRL(dlg, "edit_cp_text1", wxStaticText)->SetLabel(wxString::Format(_("%lu control points were added to the panorama.\n\nShould the panorama now be re-optimized?"), static_cast<unsigned long int>(cps.size())));
3724                     XRCCTRL(dlg, "edit_cp_text2", wxStaticText)->SetLabel(wxString::Format(_("Current selected optimizer strategy is \"%s\"."), MainFrame::Get()->GetCurrentOptimizerString().c_str()));
3725                     dlg.Fit();
3726                     optimize = (dlg.ShowModal() == wxID_OK);
3727                     if (XRCCTRL(dlg, "edit_cp_dont_show_again_checkbox", wxCheckBox)->GetValue())
3728                     {
3729                         if (optimize)
3730                         {
3731                             wxConfig::Get()->Write(wxT("/EditCPAfterAction"), 1l);
3732                         }
3733                         else
3734                         {
3735                             wxConfig::Get()->Write(wxT("/EditCPAfterAction"), 2l);
3736                         };
3737                     };
3738                 }
3739                 else
3740                 {
3741                     optimize = (afterEditCPAction == 1);
3742                 }
3743                 if (optimize)
3744                 {
3745                     // invoke optimization routine
3746                     wxCommandEvent ev(wxEVT_COMMAND_BUTTON_CLICKED, XRCID("action_optimize"));
3747                     MainFrame::Get()->GetEventHandler()->AddPendingEvent(ev);
3748                 };
3749             };
3750         };
3751     };
3752     // finally redraw
3753     m_GLPreview->Update();
3754     m_GLPreview->Refresh();
3755 };
3756 
3757 // handle menu close event to redraw preview, so that selection rectangle is hidden
OnMenuClose(wxMenuEvent & e)3758 void GLPreviewFrame::OnMenuClose(wxMenuEvent & e)
3759 {
3760     m_GLPreview->Refresh();
3761     e.Skip();
3762 };
3763 
OnSelectContextMenu(wxContextMenuEvent & e)3764 void GLPreviewFrame::OnSelectContextMenu(wxContextMenuEvent& e)
3765 {
3766     wxPoint point = e.GetPosition();
3767     // If from keyboard
3768     if (point.x == -1 && point.y == -1)
3769     {
3770         point = m_selectAllButton->GetPosition();
3771     }
3772     else
3773     {
3774         point = ScreenToClient(point);
3775     }
3776     PopupMenu(m_selectAllMenu, point);
3777 };
3778 
OnSelectAllMenu(wxCommandEvent & e)3779 void GLPreviewFrame::OnSelectAllMenu(wxCommandEvent& e)
3780 {
3781     wxConfig::Get()->Write(wxT("/GLPreviewFrame/SelectAllMode"), 0l);
3782     m_selectAllMode = SELECT_ALL_IMAGES;
3783 };
3784 
OnSelectMedianMenu(wxCommandEvent & e)3785 void GLPreviewFrame::OnSelectMedianMenu(wxCommandEvent& e)
3786 {
3787     wxConfig::Get()->Write(wxT("/GLPreviewFrame/SelectAllMode"), 1l);
3788     m_selectAllMode = SELECT_MEDIAN_IMAGES;
3789 };
3790 
OnSelectBrightestMenu(wxCommandEvent & e)3791 void GLPreviewFrame::OnSelectBrightestMenu(wxCommandEvent& e)
3792 {
3793     wxConfig::Get()->Write(wxT("/GLPreviewFrame/SelectAllMode"), 2l);
3794     m_selectAllMode = SELECT_BRIGHTEST_IMAGES;
3795 };
3796 
OnSelectDarkestMenu(wxCommandEvent & e)3797 void GLPreviewFrame::OnSelectDarkestMenu(wxCommandEvent& e)
3798 {
3799     wxConfig::Get()->Write(wxT("/GLPreviewFrame/SelectAllMode"), 3l);
3800     m_selectAllMode = SELECT_DARKEST_IMAGES;
3801 };
3802 
OnSelectKeepSelection(wxCommandEvent & e)3803 void GLPreviewFrame::OnSelectKeepSelection(wxCommandEvent& e)
3804 {
3805     wxConfig::Get()->Write(wxT("/GLPreviewFrame/SelectAllKeepSelection"), true);
3806     m_selectKeepSelection = true;
3807 };
3808 
OnSelectResetSelection(wxCommandEvent & e)3809 void GLPreviewFrame::OnSelectResetSelection(wxCommandEvent& e)
3810 {
3811     wxConfig::Get()->Write(wxT("/GLPreviewFrame/SelectAllKeepSelection"), false);
3812     m_selectKeepSelection = false;
3813 };
3814