Hugin trunk 0.1
Loading...
Searching...
No Matches
ImagesTree.cpp
Go to the documentation of this file.
1// -*- c-basic-offset: 4 -*-
2
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 "hugin_config.h"
27#include "panoinc_WX.h"
28#include "panoinc.h"
29
30#include "base_wx/wxPlatform.h"
31#include "base_wx/LensTools.h"
32#include "hugin/ImagesTree.h"
34#include "base_wx/platform.h"
35#include "base_wx/wxutils.h"
40#include "base_wx/PanoCommand.h"
43#include "hugin/huginApp.h"
44#include "hugin/MainFrame.h"
46#include <wx/renderer.h>
47
48enum
49{
60};
61
62class ImagesTreeData : public wxTreeItemData
63{
64public:
65 explicit ImagesTreeData(const long& nr) : m_nr(nr) { };
66 const long GetImgNr() const { return m_nr;};
68 const long GetGroupNr() const { return -(m_nr+1);};
69 const bool IsGroup() const { return (m_nr<0); };
70
71private:
72 long m_nr;
73};
74
75// Define a constructor for the Images Panel
87
89 const wxPoint& pos,
90 const wxSize& size,
91 long style,
92 const wxString& name)
93{
94 DEBUG_TRACE("List");
96 {
97 return false;
98 }
99
100 DEBUG_TRACE("Tree, adding columns");
101 m_configClassName = "/ImagesTree";
103 DEBUG_TRACE("");
104 m_degDigits = wxConfigBase::Get()->Read("/General/DegreeFractionalDigits",1);
105 m_pixelDigits = wxConfigBase::Get()->Read("/General/PixelFractionalDigits",1);
106 m_distDigits = wxConfigBase::Get()->Read("/General/DistortionFractionalDigits",3);
107 //create root
108 m_root=AddRoot("root");
109 // bind event handler
116 // for working double click we need also the menu handler on ID_EDIT
122
123 return true;
124}
125
127{
128 size_t counter=0;
129#define ADDCOLUMN(header, mapName, width, align, isEditable, IVE, tooltip) \
130 AddColumn(header, width, align, -1, true, false, tooltip);\
131 m_columnMap[mapName]=counter;\
132 m_columnVector.push_back(mapName);\
133 if(isEditable)\
134 {\
135 m_editableColumns.insert(counter);\
136 };\
137 m_variableVector.push_back(IVE);\
138 counter++;
139 ADDCOLUMN("#", "imgNr", 35, wxALIGN_LEFT, false, HuginBase::ImageVariableGroup::IVE_Filename, _("Image number"))
140 ADDCOLUMN(_("Filename"), "filename", 200, wxALIGN_LEFT, false, HuginBase::ImageVariableGroup::IVE_Filename, _("Filename"))
141 ADDCOLUMN(_("Width"), "width", 60, wxALIGN_RIGHT, false, HuginBase::ImageVariableGroup::IVE_Filename, _("Image width"))
142 ADDCOLUMN(_("Height"), "height", 60, wxALIGN_RIGHT, false, HuginBase::ImageVariableGroup::IVE_Filename, _("Image height"))
143 ADDCOLUMN(_("Anchor"), "anchor", 60, wxALIGN_RIGHT, false, HuginBase::ImageVariableGroup::IVE_Filename, _("Anchor image for position and/or exposure"))
144 ADDCOLUMN(_("# Ctrl Pnts"), "cps", 60, wxALIGN_RIGHT, false, HuginBase::ImageVariableGroup::IVE_Filename, _("Number of control points in this image"))
145 ADDCOLUMN(_("Lens no."), "lensNr", 60, wxALIGN_RIGHT, false, HuginBase::ImageVariableGroup::IVE_Filename, _("Assigned lens number"))
146 ADDCOLUMN(_("Stack no."), "stackNr", 60, wxALIGN_RIGHT, false, HuginBase::ImageVariableGroup::IVE_Filename, _("Assigned stack number"))
147
148 ADDCOLUMN(_("Maker"), "maker", 100, wxALIGN_LEFT, false, HuginBase::ImageVariableGroup::IVE_Filename, _("Camera maker"))
149 ADDCOLUMN(_("Model"), "model", 100, wxALIGN_LEFT, false, HuginBase::ImageVariableGroup::IVE_Filename, _("Camera model"))
150 ADDCOLUMN(_("Lens"), "lens", 100, wxALIGN_LEFT, false, HuginBase::ImageVariableGroup::IVE_Filename, _("Used lens"))
151 ADDCOLUMN(_("Capture date"), "date", 100, wxALIGN_LEFT, false, HuginBase::ImageVariableGroup::IVE_Filename, _("Date, image was taken"))
152 ADDCOLUMN(_("Focal length"), "focallength", 80, wxALIGN_LEFT, false, HuginBase::ImageVariableGroup::IVE_Filename, _("Focal length"))
153 ADDCOLUMN(_("Aperture"), "aperture", 50, wxALIGN_LEFT, false, HuginBase::ImageVariableGroup::IVE_Filename, _("Aperture"))
154 ADDCOLUMN(_("Shutter Speed"), "time", 50, wxALIGN_LEFT, false, HuginBase::ImageVariableGroup::IVE_Filename, _("Shutter speed"))
155 ADDCOLUMN(_("ISO"), "iso", 50, wxALIGN_LEFT, false, HuginBase::ImageVariableGroup::IVE_Filename, _("ISO speed"))
156
157 ADDCOLUMN(_("Yaw (y)"), "y", 60, wxALIGN_LEFT, true, HuginBase::ImageVariableGroup::IVE_Yaw, _("Yaw"))
158 ADDCOLUMN(_("Pitch (p)"), "p", 60, wxALIGN_LEFT, true, HuginBase::ImageVariableGroup::IVE_Yaw, _("Pitch"))
159 ADDCOLUMN(_("Roll (r)"), "r", 60, wxALIGN_LEFT, true, HuginBase::ImageVariableGroup::IVE_Yaw, _("Roll"))
160 ADDCOLUMN("X (TrX)", "TrX", 60, wxALIGN_LEFT, true, HuginBase::ImageVariableGroup::IVE_Yaw, _("Camera translation X"))
161 ADDCOLUMN("Y (TrY)", "TrY", 60, wxALIGN_LEFT, true, HuginBase::ImageVariableGroup::IVE_Yaw, _("Camera translation Y"))
162 ADDCOLUMN("Z (TrZ)", "TrZ", 60, wxALIGN_LEFT, true, HuginBase::ImageVariableGroup::IVE_Yaw, _("Camera translation Z"))
163 ADDCOLUMN(_("Plane yaw"), "Tpy", 60, wxALIGN_LEFT, true, HuginBase::ImageVariableGroup::IVE_Yaw, _("Translation remap plane yaw"))
164 ADDCOLUMN(_("Plane pitch"), "Tpp", 60, wxALIGN_LEFT, true, HuginBase::ImageVariableGroup::IVE_Yaw, _("Translation remap plane pitch"))
165 ADDCOLUMN(_("Camera translation"), "cam_trans", 60, wxALIGN_LEFT, true, HuginBase::ImageVariableGroup::IVE_Yaw, _("Camera translation"))
166
167 ADDCOLUMN(_("Lens type (f)"), "projection", 100, wxALIGN_LEFT, false, HuginBase::ImageVariableGroup::IVE_Filename, _("Lens type (rectilinear, fisheye, equirectangular, ...)"))
168 ADDCOLUMN(_("Hfov (v)"), "v", 80, wxALIGN_LEFT, true, HuginBase::ImageVariableGroup::IVE_HFOV, _("Horizontal field of view (v)"))
169 ADDCOLUMN("a", "a", 40, wxALIGN_LEFT, true, HuginBase::ImageVariableGroup::IVE_RadialDistortion, _("Radial distortion (a)"))
170 ADDCOLUMN("b", "b", 40, wxALIGN_LEFT, true, HuginBase::ImageVariableGroup::IVE_RadialDistortion, _("Radial distortion (b, barrel)"))
171 ADDCOLUMN("c", "c", 40, wxALIGN_LEFT, true, HuginBase::ImageVariableGroup::IVE_RadialDistortion, _("Radial distortion (c)"))
172 ADDCOLUMN("d", "d", 40, wxALIGN_LEFT, true, HuginBase::ImageVariableGroup::IVE_RadialDistortionCenterShift, _("Horizontal image center shift (d)"))
173 ADDCOLUMN("e", "e", 40, wxALIGN_LEFT, true, HuginBase::ImageVariableGroup::IVE_RadialDistortionCenterShift, _("Vertical image center shift (e)"))
174 ADDCOLUMN("g", "g", 40, wxALIGN_LEFT, true, HuginBase::ImageVariableGroup::IVE_Shear, _("Horizontal image shearing (g)"))
175 ADDCOLUMN("t", "t", 40, wxALIGN_LEFT, true, HuginBase::ImageVariableGroup::IVE_Shear, _("Vertical image shearing (t)"))
176
177 ADDCOLUMN("EV", "Eev", 50, wxALIGN_LEFT, true, HuginBase::ImageVariableGroup::IVE_ExposureValue, _("Exposure value (Eev)"))
178 ADDCOLUMN("Er", "Er", 40, wxALIGN_LEFT, true, HuginBase::ImageVariableGroup::IVE_WhiteBalanceRed, _("Red multiplier (Er)"))
179 ADDCOLUMN("Eb", "Eb", 40, wxALIGN_LEFT, true, HuginBase::ImageVariableGroup::IVE_WhiteBalanceBlue, _("Blue multiplier (Eb)"))
180 ADDCOLUMN("Vb", "Vb", 40, wxALIGN_LEFT, true, HuginBase::ImageVariableGroup::IVE_RadialVigCorrCoeff, _("Vignetting (Vb, Vc, Vd)"))
181 ADDCOLUMN("Vc", "Vc", 40, wxALIGN_LEFT, true, HuginBase::ImageVariableGroup::IVE_RadialVigCorrCoeff, _("Vignetting (Vb, Vc, Vd)"))
182 ADDCOLUMN("Vd", "Vd", 40, wxALIGN_LEFT, true, HuginBase::ImageVariableGroup::IVE_RadialVigCorrCoeff, _("Vignetting (Vb, Vc, Vd)"))
183 ADDCOLUMN("Vx", "Vx", 40, wxALIGN_LEFT, true, HuginBase::ImageVariableGroup::IVE_RadialVigCorrCenterShift, _("Horizontal vignetting center shift (Vx)"))
184 ADDCOLUMN("Vy", "Vy", 40, wxALIGN_LEFT, true, HuginBase::ImageVariableGroup::IVE_RadialVigCorrCenterShift, _("Vertical vignetting center shift (Vy)"))
185 ADDCOLUMN(_("Response type"), "response", 80, wxALIGN_LEFT, false, HuginBase::ImageVariableGroup::IVE_Filename, _("Camera response type"))
186 ADDCOLUMN("Ra", "Ra", 40, wxALIGN_LEFT, true, HuginBase::ImageVariableGroup::IVE_EMoRParams, _("Camera response parameter"))
187 ADDCOLUMN("Rb", "Rb", 40, wxALIGN_LEFT, true, HuginBase::ImageVariableGroup::IVE_EMoRParams, _("Camera response parameter"))
188 ADDCOLUMN("Rc", "Rc", 40, wxALIGN_LEFT, true, HuginBase::ImageVariableGroup::IVE_EMoRParams, _("Camera response parameter"))
189 ADDCOLUMN("Rd", "Rd", 40, wxALIGN_LEFT, true, HuginBase::ImageVariableGroup::IVE_EMoRParams, _("Camera response parameter"))
190 ADDCOLUMN("Re", "Re", 40, wxALIGN_LEFT, true, HuginBase::ImageVariableGroup::IVE_EMoRParams, _("Camera response parameter"))
191
192 //empty column to have enough space on the right side
194
195 //get saved width
196 for ( int j=0; j < GetColumnCount() ; j++ )
197 {
198 // -1 is auto
199 int width = wxConfigBase::Get()->Read(wxString::Format(m_configClassName+"/ColumnWidth%d", j ), -1);
200 if(width != -1)
201 SetColumnWidth(j, width);
202 }
203};
204
218
225
227{
229 {
230 Freeze();
232 Thaw();
233#ifdef __WXGTK__
234 Refresh();
235#endif
236 };
238 {
240 fill_set(imgs, 0, pano.getNrOfImages()-1);
241 panoramaImagesChanged(pano, imgs);
242 };
243 m_needsUpdate=true;
244};
245
247{
248 DEBUG_TRACE("");
249
250 Freeze();
252 // Make sure the part numbers are up to date before writing them to the table.
256 //if the number of lenses or stacks have changed we need to update all images
257 //because the changed images set contains only the list of the changed imagges
258 //but not these images where the stack or lens number has changed because
259 //an images has been inserted
260 if(pano.getNrOfImages()>0)
261 {
264 {
265 fill_set(changedImgs, 0, pano.getNrOfImages()-1);
266 };
267 };
269 {
271 {
273 };
275 {
277 };
278 };
280 {
282 if(m_pano->getNrOfImages()>0)
283 {
284 fill_set(imgs,0,m_pano->getNrOfImages()-1);
285 };
287 }
288 else
289 {
291 switch (m_groupMode)
292 {
293 case GROUP_LENS:
295 break;
296 case GROUP_STACK:
298 break;
301 break;
303 imageGroups=getExposureLayers(*m_pano,m_pano->getActiveImages(), m_pano->getOptions());
304 break;
305 case GROUP_NONE:
306 // this branch is never reached
307 // it is just to silence a compiler warning
308 break;
309 }
310
311 size_t nrItems=GetChildrenCount(m_root,false);
312 if(nrItems!=imageGroups.size())
313 {
314 if(nrItems<imageGroups.size())
315 {
316 for(size_t i=nrItems;i<imageGroups.size();i++)
317 {
318 AppendItem(m_root,wxEmptyString,-1,-1,new ImagesTreeData(-(long)i-1));
319 };
320 }
321 else
322 {
323 while(GetChildrenCount(m_root,false)>imageGroups.size())
324 {
327 Delete(item);
328 };
329 };
330 };
331
334 size_t i=0;
335 while(item.IsOk())
336 {
340 };
341 };
342 // updates checkboxes images for optimizer variables
344 {
346 };
348 {
350 };
351
352 Thaw();
353 m_needsUpdate = false;
354
355 // HACK! need to notify clients anyway... send dummy event..
356 // lets hope our clients query for the selected images with GetSelected()
357 // and do not try to interpret the event.
358 wxListEvent e;
359 e.SetEventType(wxEVT_COMMAND_LIST_ITEM_SELECTED);
360 e.m_itemIndex = -1;
361 GetEventHandler()->ProcessEvent(e);
362}
363
365{
367 // NAMEisLinked returns always false, if the lens or stacks contains only a single image
368 // so add a special handling for this case
369 bool isSingleImage = false;
370 if (m_groupMode != GROUP_NONE)
371 {
373 };
374 wxString s;
375 const size_t imgNr=itemData->GetImgNr();
376 const HuginBase::SrcPanoImage & img = m_pano->getImage(imgNr);
377 wxFileName fn(wxString (img.getFilename().c_str(), HUGIN_CONV_FILENAME));
378
379 s << imgNr;
380 SetItemText(item, m_columnMap["imgNr"], s);
381 s.Clear();
382 SetItemText(item, m_columnMap["filename"], fn.GetFullName() );
383 SetItemText(item, m_columnMap["width"], wxString::Format("%d", img.getSize().width()));
384 SetItemText(item, m_columnMap["height"], wxString::Format("%d", img.getSize().height()));
385
388 {
389 flags.Append("A");
390 }
391 else
392 {
393 flags.Append("-");
394 }
395 if (m_pano->getOptions().colorReferenceImage == imgNr)
396 {
397 flags.Append("C");
398 }
399 else
400 {
401 flags.Append("-");
402 };
403 SetItemText(item, m_columnMap["anchor"], flags);
404 std::vector<unsigned int> cps = m_pano->getCtrlPointsForImage(imgNr);
405 s << cps.size();
406 SetItemText(item, m_columnMap["cps"], s);
407 s.Clear();
408 const unsigned int stackNumber = m_variable_groups->getStacks().getPartNumber(imgNr);
409 SetItemText(item, m_columnMap["stackNr"], wxString::Format("%u", stackNumber));
410 const unsigned int lensNr=m_variable_groups->getLenses().getPartNumber(imgNr);
411 SetItemText(item, m_columnMap["lensNr"], wxString::Format("%u", lensNr));
412
413 SetItemText(item, m_columnMap["maker"], wxString(img.getExifMake().c_str(), wxConvLocal));
414 SetItemText(item, m_columnMap["model"], wxString(img.getExifModel().c_str(), wxConvLocal));
415 SetItemText(item, m_columnMap["lens"], wxString(img.getExifLens().c_str(), wxConvLocal));
421
422 if (m_groupMode == GROUP_STACK && (img.YawisLinked() || isSingleImage))
423 {
433 }
434 else
435 {
442 SetItemText(item, m_columnMap["Tpy"], hugin_utils::doubleTowxString(img.getTranslationPlaneYaw(), m_degDigits));
443 SetItemText(item, m_columnMap["Tpp"], hugin_utils::doubleTowxString(img.getTranslationPlanePitch(), m_degDigits));
444 wxString text=_("not active");
445 if(img.getX()!=0.0 || img.getY()!=0.0 || img.getZ()!=0.0 || img.getTranslationPlaneYaw()!=0.0 || img.getTranslationPlanePitch()!=0.0)
446 {
447 text=_("active");
448 };
449 text.Prepend(" ");
450 SetItemText(item, m_columnMap["cam_trans"], text);
451 };
452
454 {
455 SetItemText(item, m_columnMap["projection"], wxEmptyString);
457 }
458 else
459 {
460 SetItemText(item, m_columnMap["projection"], getProjectionString(img));
461 SetItemText(item, m_columnMap["response"], getResponseString(img));
462 };
463
464 if (m_groupMode == GROUP_LENS && (img.HFOVisLinked() || isSingleImage))
465 {
467 }
468 else
469 {
471 };
472
473 if (m_groupMode == GROUP_LENS && (img.RadialDistortionisLinked() || isSingleImage))
474 {
478 }
479 else
480 {
481 std::vector<double> dist=img.getRadialDistortion();
485 };
486
487 if (m_groupMode == GROUP_LENS && (img.RadialDistortionCenterShiftisLinked() || isSingleImage))
488 {
491 }
492 else
493 {
494 hugin_utils::FDiff2D p=img.getRadialDistortionCenterShift();
497 };
498
499 if (m_groupMode == GROUP_LENS && (img.ShearisLinked() || isSingleImage))
500 {
503 }
504 else
505 {
506 hugin_utils::FDiff2D p=img.getShear();
509 };
510
511 if (m_groupMode == GROUP_LENS && (img.ExposureValueisLinked() || isSingleImage))
512 {
514 }
515 else
516 {
518 };
519
520 if (m_groupMode == GROUP_LENS && (img.WhiteBalanceRedisLinked() || isSingleImage))
521 {
523 }
524 else
525 {
526 SetItemText(item, m_columnMap["Er"], hugin_utils::doubleTowxString(img.getWhiteBalanceRed(), m_pixelDigits+1));
527 };
528
529 if (m_groupMode == GROUP_LENS && (img.WhiteBalanceBlueisLinked() || isSingleImage))
530 {
532 }
533 else
534 {
535 SetItemText(item, m_columnMap["Eb"], hugin_utils::doubleTowxString(img.getWhiteBalanceBlue(), m_pixelDigits+1));
536 };
537
538 if (m_groupMode == GROUP_LENS && (img.RadialVigCorrCoeffisLinked() || isSingleImage))
539 {
543 }
544 else
545 {
546 std::vector<double> dist=img.getRadialVigCorrCoeff();
550 };
551
552 if (m_groupMode == GROUP_LENS && (img.RadialVigCorrCenterShiftisLinked() || isSingleImage))
553 {
556 }
557 else
558 {
559 hugin_utils::FDiff2D p=img.getRadialVigCorrCenterShift();
562 };
563
564 if (m_groupMode == GROUP_LENS && (img.EMoRParamsisLinked() || isSingleImage))
565 {
571 }
572 else
573 {
574 if (img.getResponseType() == HuginBase::SrcPanoImage::RESPONSE_EMOR)
575 {
576 // display Ra..Re only when response type is emor
577 // otherwise they have no meaning
578 std::vector<float> vec = img.getEMoRParams();
584 }
585 else
586 {
592 };
593 };
594};
595
597{
599 switch(m_groupMode)
600 {
601 case GROUP_LENS:
602 SetItemText(item, 1, wxString::Format(_("Lens %ld"),itemData->GetGroupNr()));
603 break;
604 case GROUP_STACK:
605 SetItemText(item, 1, wxString::Format(_("Stack %ld"),itemData->GetGroupNr()));
606 break;
608 SetItemText(item, 1, wxString::Format(_("Output stack %ld"),itemData->GetGroupNr()));
609 break;
611 SetItemText(item, 1, wxString::Format(_("Output exposure layer %ld"),itemData->GetGroupNr()));
612 break;
613 case GROUP_NONE:
614 // this branch is never reached
615 // it is just to silence a compiler warning
616 break;
617 }
618 SetItemBold(item,1,true);
621 // NAMEisLinked returns always false, if the lens or stacks contains only a single image
622 // so add a special handling for this case
623 bool haveSingleChild = false;
624 if (m_groupMode != GROUP_NONE)
625 {
626 haveSingleChild = (GetChildrenCount(item, false) == 1);
627 };
628 if(childItem.IsOk())
629 {
631 const HuginBase::SrcPanoImage& img=m_pano->getImage(data->GetImgNr());
632
633 if (m_groupMode == GROUP_STACK && (img.YawisLinked() || haveSingleChild))
634 {
641 SetItemText(item, m_columnMap["Tpy"], hugin_utils::doubleTowxString(img.getTranslationPlaneYaw(), m_degDigits));
642 SetItemText(item, m_columnMap["Tpp"], hugin_utils::doubleTowxString(img.getTranslationPlanePitch(), m_degDigits));
643 wxString text=_("not active");
644 if(img.getX()!=0.0 || img.getY()!=0.0 || img.getZ()!=0.0 || img.getTranslationPlaneYaw()!=0.0 || img.getTranslationPlanePitch()!=0.0)
645 {
646 text=_("active");
647 };
648 text.Prepend(" ");
649 SetItemText(item, m_columnMap["cam_trans"], text);
650 }
651 else
652 {
662 };
663
665 {
666 SetItemText(item, m_columnMap["projection"], getProjectionString(img));
667 SetItemText(item, m_columnMap["response"], getResponseString(img));
668 }
669 else
670 {
671 SetItemText(item, m_columnMap["projection"], wxEmptyString);
673 };
674
675 if (m_groupMode == GROUP_LENS && (img.HFOVisLinked() || haveSingleChild))
676 {
678 }
679 else
680 {
682 };
683
684 if (m_groupMode == GROUP_LENS && (img.RadialDistortionisLinked() || haveSingleChild))
685 {
686 std::vector<double> dist=img.getRadialDistortion();
690 }
691 else
692 {
696 };
697
698 if (m_groupMode == GROUP_LENS && (img.RadialDistortionCenterShiftisLinked() || haveSingleChild))
699 {
700 hugin_utils::FDiff2D p=img.getRadialDistortionCenterShift();
703 }
704 else
705 {
708 };
709
710 if (m_groupMode == GROUP_LENS && (img.ShearisLinked() || haveSingleChild))
711 {
712 hugin_utils::FDiff2D p=img.getShear();
715 }
716 else
717 {
720 };
721
722 if (m_groupMode == GROUP_LENS && (img.ExposureValueisLinked() || haveSingleChild))
723 {
725 }
726 else
727 {
729 };
730
731 if (m_groupMode == GROUP_LENS && (img.WhiteBalanceRedisLinked() || haveSingleChild))
732 {
733 SetItemText(item, m_columnMap["Er"], hugin_utils::doubleTowxString(img.getWhiteBalanceRed(), m_pixelDigits+1));
734 }
735 else
736 {
738 };
739
740 if (m_groupMode == GROUP_LENS && (img.WhiteBalanceBlueisLinked() || haveSingleChild))
741 {
742 SetItemText(item, m_columnMap["Eb"], hugin_utils::doubleTowxString(img.getWhiteBalanceBlue(), m_pixelDigits+1));
743 }
744 else
745 {
747 };
748
749 if (m_groupMode == GROUP_LENS && (img.RadialVigCorrCoeffisLinked() || haveSingleChild))
750 {
751 std::vector<double> dist=img.getRadialVigCorrCoeff();
755 }
756 else
757 {
761 };
762
763 if (m_groupMode == GROUP_LENS && (img.RadialVigCorrCenterShiftisLinked() || haveSingleChild))
764 {
765 hugin_utils::FDiff2D p=img.getRadialVigCorrCenterShift();
768 }
769 else
770 {
773 };
774
775 if (m_groupMode == GROUP_LENS && (img.getResponseType() == HuginBase::SrcPanoImage::RESPONSE_EMOR && (img.EMoRParamsisLinked()) || haveSingleChild))
776 {
777 std::vector<float> vec=img.getEMoRParams();
783 }
784 else
785 {
791 };
792 };
793};
794
796{
797 size_t nrItems=GetChildrenCount(parent,false);
798 bool forceUpdate=false;
799 if(nrItems!=imgs.size())
800 {
801 forceUpdate=true;
802 if(nrItems<imgs.size())
803 {
804 for(size_t i=nrItems;i<imgs.size();i++)
805 {
807 };
808 }
809 else
810 {
811 while(GetChildrenCount(parent,false)>imgs.size())
812 {
815 Delete(item);
816 };
817 };
818 };
819 //now update values
822 HuginBase::UIntSet::const_iterator it=imgs.begin();
823 while(item.IsOk())
824 {
825 ImagesTreeData* data=static_cast<ImagesTreeData*>(GetItemData(item));
826 if(it==imgs.end())
827 {
828 break;
829 };
830 bool needsUpdate=false;
831 if(data->GetImgNr()!=*it)
832 {
833 data->SetImgNr(*it);
834 needsUpdate=true;
835 }
836 else
837 {
839 {
840 needsUpdate=true;
841 };
842 };
844 {
846 changed.erase(*it);
847 };
849 ++it;
850 };
851};
852
854{
858 while(item.IsOk())
859 {
860 ImagesTreeData* data=static_cast<ImagesTreeData*>(GetItemData(item));
861 HuginBase::UIntSet imgNrs;
862 if(data->IsGroup())
863 {
866 while(child.IsOk())
867 {
868 data=static_cast<ImagesTreeData*>(GetItemData(child));
869 imgNrs.insert(data->GetImgNr());
871 };
872 }
873 else
874 {
875 imgNrs.insert(data->GetImgNr());
876 };
877 if(!imgNrs.empty())
878 {
879 for(size_t i=0;i<GetColumnCount();i++)
880 {
882 {
883 if (GetItemText(item, i).IsEmpty())
884 {
885 // item with no text can have no checkbox
886 // this can happen with linked variables
887 SetItemImage(item, i, -1);
888 }
889 else
890 {
891 bool opt=false;
892 for(HuginBase::UIntSet::const_iterator it=imgNrs.begin(); it!=imgNrs.end() && !opt;++it)
893 {
894 if(m_columnVector[i]=="cam_trans")
895 {
896 opt=set_contains(optVec[*it], "TrX") &&
897 set_contains(optVec[*it], "TrY") &&
898 set_contains(optVec[*it], "TrZ") &&
899 set_contains(optVec[*it], "Tpy") &&
900 set_contains(optVec[*it], "Tpp");
901 }
902 else
903 {
905 };
906 };
907 SetItemImage(item, i, opt ? 1 : 0);
908 };
909 };
910 };
911 };
913 };
914};
915
917{
920 if(GetSelections (selected)>0)
921 {
922 for(size_t i=0;i<selected.size();i++)
923 {
924 ImagesTreeData* data=static_cast<ImagesTreeData*>(GetItemData(selected[i]));
925 if(data->IsGroup())
926 {
929 while(item.IsOk())
930 {
931 data=static_cast<ImagesTreeData*>(GetItemData(item));
932 imgs.insert(data->GetImgNr());
934 };
935 }
936 else
937 {
938 imgs.insert(data->GetImgNr());
939 };
940 };
941 }
942 return imgs;
943}
944
950
952{
954 {
955 int colNum = e.GetColumn();
956 wxConfigBase::Get()->Write( m_configClassName+wxString::Format("/ColumnWidth%d",colNum), GetColumnWidth(colNum) );
957 }
958}
959
966
968{
969 //create bitmaps for different checkboxes state
970 wxRendererNative& renderer = wxRendererNative::Get();
971 const wxSize checkBoxSize = renderer.GetCheckBoxSize(this);
972 wxImageList* checkboxImageList = new wxImageList(checkBoxSize.GetWidth(), checkBoxSize.GetHeight(), true, 0);
975 // unchecked checkbox
976 dc.Clear();
977 renderer.DrawCheckBox(this, dc, wxRect(checkBoxSize));
978 dc.SelectObject(wxNullBitmap);
980 // checked checkbox
981 dc.SelectObject(checkBoxImage);
982 dc.Clear();
983 renderer.DrawCheckBox(this, dc, wxRect(checkBoxSize), wxCONTROL_CHECKED);
984 dc.SelectObject(wxNullBitmap);
986 // mouse over unchecked checkbox
987 dc.SelectObject(checkBoxImage);
988 dc.Clear();
989 renderer.DrawCheckBox(this, dc, wxRect(checkBoxSize), wxCONTROL_CURRENT);
990 dc.SelectObject(wxNullBitmap);
992 // mouse over checked checkbox
993 dc.SelectObject(checkBoxImage);
994 dc.Clear();
996 dc.SelectObject(wxNullBitmap);
998
1000}
1001
1003{
1004 m_optimizerMode=true;
1005 // connnect events with handlers
1008 // build image list with check box images
1010 // activate edit mode
1011 for(HuginBase::UIntSet::const_iterator it=m_editableColumns.begin(); it!=m_editableColumns.end(); ++it)
1012 {
1013 if(m_columnVector[*it]!="cam_trans")
1014 {
1015 SetColumnEditable(*it,true);
1016 };
1017 };
1018}
1019
1021{
1022 // dpi has changed, we need to update the images of the checkboxes
1023 if (m_optimizerMode)
1024 {
1026 Refresh();
1027 };
1028}
1029
1031{
1033 {
1036 {
1037 SetWindowStyle(GetWindowStyle() | wxTR_NO_LINES);
1038 }
1039 else
1040 {
1041 SetWindowStyle(GetWindowStyle() & ~wxTR_NO_LINES);
1042 };
1044 HuginBase::UIntSet imgs;
1045 if(m_pano->getNrOfImages()>0)
1046 {
1047 fill_set(imgs,0,m_pano->getNrOfImages()-1);
1048 };
1050 // reset already modified tag
1051 m_needsUpdate = true;
1053 };
1054};
1055
1057{
1059
1066
1075
1085
1095
1110
1111 Refresh();
1112};
1113
1115{
1116 m_selectedColumn=e.GetInt();
1117 wxMenu menu;
1118 bool allowMenuExtension=true;
1119 if(e.GetItem().IsOk())
1120 {
1121 //click on item
1123 {
1124 bool emptyText=GetItemText(e.GetItem(),m_selectedColumn).IsEmpty();
1125 ImagesTreeData* data=static_cast<ImagesTreeData*>(GetItemData(e.GetItem()));
1126 bool varIsLinkable = false;
1127 if (m_groupMode == GROUP_LENS)
1128 {
1129 varIsLinkable = m_variableVector[m_selectedColumn] != HuginBase::ImageVariableGroup::IVE_Yaw &&
1131 }
1132 else
1133 {
1134 if (m_groupMode == GROUP_STACK)
1135 {
1136 varIsLinkable = m_variableVector[m_selectedColumn] == HuginBase::ImageVariableGroup::IVE_Yaw;
1137 }
1138 };
1139 if(varIsLinkable)
1140 {
1141 if(data->IsGroup())
1142 {
1143 if(emptyText)
1144 {
1145 menu.Append(ID_LINK,_("Link"));
1147 }
1148 else
1149 {
1150 menu.Append(ID_UNLINK, _("Unlink"));
1152 };
1153 }
1154 else
1155 {
1156 if(emptyText)
1157 {
1158 menu.Append(ID_UNLINK,_("Unlink"));
1160 }
1161 else
1162 {
1163 menu.Append(ID_LINK, _("Link"));
1165 };
1166 };
1167 menu.AppendSeparator();
1168 };
1169 if(m_optimizerMode)
1170 {
1171 if(data->IsGroup() == emptyText)
1172 {
1173 if(m_groupMode==GROUP_LENS && m_variableVector[m_selectedColumn]!=HuginBase::ImageVariableGroup::IVE_Yaw)
1174 {
1175 menu.Append(ID_SELECT_LENS_STACK, _("Select all for current lens"));
1177 menu.Append(ID_UNSELECT_LENS_STACK, _("Unselect all for current lens"));
1179 };
1180 if(m_groupMode==GROUP_STACK && m_variableVector[m_selectedColumn]==HuginBase::ImageVariableGroup::IVE_Yaw)
1181 {
1182 menu.Append(ID_SELECT_LENS_STACK, _("Select all for current stack"));
1184 menu.Append(ID_UNSELECT_LENS_STACK, _("Unselect all for current stack"));
1186 };
1187 };
1188 if(m_columnVector[m_selectedColumn]!="cam_trans")
1189 {
1190 menu.Append(ID_SELECT_ALL, _("Select all"));
1192 };
1193 menu.Append(ID_UNSELECT_ALL, _("Unselect all"));
1195 menu.AppendSeparator();
1196 }
1197 };
1198 menu.Append(ID_EDIT, _("Edit image variables..."));
1199 // handler for ID_EDIT is already Bind() in ImagesTreeCtrl::Create to make it work with double click,
1200 // so no need to call Bind again
1202 {
1204 if (selectedImages.size() == 1)
1205 {
1206 if (m_pano->getImage(*selectedImages.begin()).getActive())
1207 {
1208 menu.Append(ID_DEACTIVATE_IMAGE, _("Deactivate image"));
1210 }
1211 else
1212 {
1213 menu.Append(ID_ACTIVATE_IMAGE, _("Activate image"));
1215 };
1216 }
1217 else
1218 {
1219 menu.Append(ID_ACTIVATE_IMAGE, _("Activate images"));
1221 menu.Append(ID_DEACTIVATE_IMAGE, _("Deactivate images"));
1223 };
1224 };
1225 }
1226 else
1227 {
1229 {
1230 if(m_columnVector[m_selectedColumn]!="cam_trans")
1231 {
1232 menu.Append(ID_SELECT_ALL, _("Select all"));
1234 };
1235 menu.Append(ID_UNSELECT_ALL, _("Unselect all"));
1237 allowMenuExtension=false;
1238 }
1239 };
1241 {
1242 if(menu.GetMenuItemCount()>0)
1243 {
1244 menu.AppendSeparator();
1245 };
1246 int id=ID_OPERATION_START;
1247 m_menuOperation.clear();
1249 wxMenu* subMenu=new wxMenu();
1251 if(subMenu->GetMenuItemCount()>0)
1252 {
1253 menu.Append(-1,_("Lens"), subMenu);
1254 }
1255 else
1256 {
1257 delete subMenu;
1258 };
1260 {
1261 subMenu=new wxMenu();
1263 if(subMenu->GetMenuItemCount()>0)
1264 {
1265 menu.Append(-1,_("Stacks"), subMenu);
1266 }
1267 else
1268 {
1269 delete subMenu;
1270 };
1271 };
1272 subMenu=new wxMenu();
1274 if(subMenu->GetMenuItemCount()>0)
1275 {
1276 menu.Append(-1, _("Control points"), subMenu);
1277 }
1278 else
1279 {
1280 delete subMenu;
1281 };
1282 subMenu=new wxMenu();
1284 if(subMenu->GetMenuItemCount()>0)
1285 {
1286 menu.Append(-1, _("Reset"), subMenu);
1287 }
1288 else
1289 {
1290 delete subMenu;
1291 };
1292 };
1293 if(menu.GetMenuItemCount()>0)
1294 {
1295 PopupMenu(&menu);
1296 };
1297 e.Skip();
1298};
1299
1301{
1303 for(size_t i=0; i<operations->size(); i++)
1304 {
1305 if((*operations)[i]->IsEnabled(*m_pano, imgs, m_guiLevel))
1306 {
1307 menu->Append(id, (*operations)[i]->GetLabel());
1308 m_menuOperation[id]=(*operations)[i];
1310 id++;
1311 }
1312 };
1313}
1314
1316{
1317 const wxColour normalColour = wxSystemSettings::GetColour(wxSYS_COLOUR_WINDOWTEXT);
1318 const wxColour disabledColour = wxSystemSettings::GetColour(wxSYS_COLOUR_GRAYTEXT);
1320 {
1323 while (item.IsOk())
1324 {
1326 bool isActive = true;
1327 if (itemData->IsGroup())
1328 {
1331 while (child.IsOk())
1332 {
1335 if (isActive)
1336 {
1337 break;
1338 };
1340 };
1341 }
1342 else
1343 {
1344 isActive = m_pano->getImage(itemData->GetImgNr()).getActive();
1345 };
1346 if (isActive)
1347 {
1349 }
1350 else
1351 {
1353 };
1354 if(itemData->IsGroup())
1355 {
1358 while (child.IsOk())
1359 {
1361 if (m_pano->getImage(childItemData->GetImgNr()).getActive())
1362 {
1364 }
1365 else
1366 {
1368 };
1370 };
1371 };
1373 };
1374 }
1375 else
1376 {
1379 while (item.IsOk())
1380 {
1383 if (itemData->IsGroup())
1384 {
1387 while (child.IsOk())
1388 {
1391 };
1392 };
1394 };
1395 };
1396};
1397
1399{
1400 m_selectedColumn=e.GetColumn();
1401 wxMenu menu;
1403 {
1404 menu.Append(ID_SELECT_ALL, _("Select all"));
1406 menu.Append(ID_UNSELECT_ALL, _("Unselect all"));
1408 PopupMenu(&menu);
1409 };
1410 e.Skip();
1411}
1412void ImagesTreeCtrl::OnActivateImage(wxCommandEvent & e)
1413{
1414 HuginBase::UIntSet activeImages = m_pano->getActiveImages();
1416 std::copy(selectedImages.begin(), selectedImages.end(), std::inserter(activeImages, activeImages.end()));
1418 new PanoCommand::SetActiveImagesCmd(*m_pano, activeImages)
1419 );
1420};
1421
1423{
1424 HuginBase::UIntSet activeImages = m_pano->getActiveImages();
1427 std::set_difference(activeImages.begin(), activeImages.end(), selectedImages.begin(), selectedImages.end(), std::inserter(newActiveImages, newActiveImages.end()));
1430 );
1431};
1432
1434{
1436 if(!images.empty() && m_variableVector[m_selectedColumn]!=HuginBase::ImageVariableGroup::IVE_Filename)
1437 {
1438 std::set<HuginBase::ImageVariableGroup::ImageVariableEnum> variables;
1439 variables.insert(m_variableVector[m_selectedColumn]);
1440 if(m_variableVector[m_selectedColumn]==HuginBase::ImageVariableGroup::IVE_Yaw)
1441 {
1442 variables.insert(HuginBase::ImageVariableGroup::IVE_Pitch);
1443 variables.insert(HuginBase::ImageVariableGroup::IVE_Roll);
1444 variables.insert(HuginBase::ImageVariableGroup::IVE_X);
1445 variables.insert(HuginBase::ImageVariableGroup::IVE_Y);
1446 variables.insert(HuginBase::ImageVariableGroup::IVE_Z);
1447 variables.insert(HuginBase::ImageVariableGroup::IVE_TranslationPlaneYaw);
1448 variables.insert(HuginBase::ImageVariableGroup::IVE_TranslationPlanePitch);
1449 };
1451 {
1454 );
1455 }
1456 else
1457 {
1460 );
1461 };
1462 };
1463};
1464
1466{
1468};
1469
1471{
1472 UnLinkImageVariables(false);
1473};
1474
1476{
1478 if(!imgs.empty())
1479 {
1480 ImageVariableDialog dlg(this, m_pano, imgs);
1481 dlg.SetGuiLevel(m_guiLevel);
1482 switch(m_displayMode)
1483 {
1484 case DISPLAY_LENS:
1485 dlg.SelectTab(1);
1486 break;
1490 if(m_selectedColumn==m_columnMap["response"] ||
1496 {
1497 dlg.SelectTab(3);
1498 }
1499 else
1500 {
1501 dlg.SelectTab(2);
1502 };
1503 break;
1504 default:
1505 break;
1506 };
1507 dlg.ShowModal();
1508 };
1509};
1510
1512{
1514 if(m_pano->getNrOfImages()>0 && !m_dragging)
1515 {
1517 if(!m_draggingImages.empty())
1518 {
1519 if((m_groupMode==GROUP_NONE && m_draggingImages.size()==1 && !ctrlPressed) ||
1521 {
1522 e.Allow();
1524 m_dragging=true;
1525 };
1526 };
1527 };
1528};
1529
1531{
1532 //we can't use wxEVT_TREE_END_DRAG because this event is fire several times, e.g. when
1533 // the mouse leaves the area of the tree
1534 // so we are listing to left mouse up, as described in documentation
1535 if(m_dragging)
1536 {
1538 m_dragging=false;
1539 wxTreeItemId item=HitTest(e.GetPosition());
1541 {
1542 size_t img1=*m_draggingImages.begin();
1543 size_t img2=-1;
1544 if(item.IsOk())
1545 {
1546 ImagesTreeData* data=static_cast<ImagesTreeData*>(GetItemData(item));
1547 img2=data->GetImgNr();
1548 }
1549 else
1550 {
1551 //we are checking the points above, if we find then
1552 // an item, the user drop it below the last item, if not
1553 // the drop happened right beside the item
1554 wxPoint pos(e.GetPosition());
1555 pos.y-=10;
1556 while(pos.y>0)
1557 {
1558 item=HitTest(pos);
1559 if(item.IsOk())
1560 {
1561 img2=m_pano->getNrOfImages()-1;
1562 break;
1563 };
1564 pos.y-=10;
1565 };
1566 };
1567 if(img2!=-1)
1568 {
1569 if(img1!=img2)
1570 {
1572 new PanoCommand::MoveImageCmd(*m_pano, img1, img2)
1573 );
1574 // now update drag images groups in fast preview window, this information is not stored in Panorama class
1576 if (!images.empty() && images.size() < m_pano->getNrOfImages())
1577 {
1578 std::vector<bool> imgList(m_pano->getNrOfImages(), false);
1579 for (auto& i : images)
1580 {
1581 imgList[i] = true;
1582 };
1583 const bool moveImageChecked = imgList[img1];
1584 imgList.erase(imgList.begin() + img1);
1585 if (img2 < imgList.size())
1586 {
1587 imgList.insert(imgList.begin() + img2, moveImageChecked);
1588 }
1589 else
1590 {
1591 imgList.push_back(moveImageChecked);
1592 };
1593 images.clear();
1594 for (size_t i = 0; i < imgList.size(); ++i)
1595 {
1596 if (imgList[i])
1597 {
1598 images.insert(i);
1599 };
1600 };
1602 };
1603 };
1604 };
1605 }
1606 else
1607 {
1608 //dragging to stack/lenses
1609 if(item.IsOk())
1610 {
1611 ImagesTreeData* data=static_cast<ImagesTreeData*>(GetItemData(item));
1612 long groupNr=-1;
1613 if(data->IsGroup())
1614 {
1615 groupNr=data->GetGroupNr();
1616 }
1617 else
1618 {
1620 if(item.IsOk())
1621 {
1622 data=static_cast<ImagesTreeData*>(GetItemData(item));
1623 groupNr=data->GetGroupNr();
1624 };
1625 };
1626 if(groupNr>=0)
1627 {
1629 {
1632 );
1633 }
1634 else
1635 {
1638 );
1639 };
1640 };
1641 }
1642 else // item not ok, drop not on existing item, create new lens/stack
1643 {
1645 {
1648 );
1649 }
1650 else
1651 {
1654 );
1655 }
1656 };
1657 }
1658 m_draggingImages.clear();
1659 }
1660 else
1661 {
1662 if (m_optimizerMode && m_leftDownItem.IsOk())
1663 {
1664 int flags;
1665 int col;
1666 wxTreeItemId item = HitTest(e.GetPosition(), flags, col);
1667 // check if left up is on the same item as left down
1669 {
1670 HuginBase::UIntSet imgs;
1672 if (markSelected)
1673 {
1674 // if the user clicked on one of the selected pass the selection to all selected images
1675 imgs = GetSelectedImages();
1676 }
1677 else
1678 {
1679 // the user clicked on a non-selected images, work only on this image
1680 // or all images of the clicked lens/stack
1682 if (data->IsGroup())
1683 {
1686 while (childItem.IsOk())
1687 {
1688 data = static_cast<ImagesTreeData*>(GetItemData(childItem));
1689 imgs.insert(data->GetImgNr());
1691 };
1692 }
1693 else
1694 {
1695 imgs.insert(data->GetImgNr());
1696 };
1697 };
1699 std::set<std::string> var;
1700 if (m_columnVector[m_leftDownColumn] == "cam_trans")
1701 {
1702 var.insert("TrX");
1703 var.insert("TrY");
1704 var.insert("TrZ");
1705 var.insert("Tpy");
1706 var.insert("Tpp");
1707 }
1708 else
1709 {
1710 var.insert(m_columnVector[m_leftDownColumn]);
1712 {
1713 var.insert("Tpy");
1714 var.insert("Tpp");
1715 };
1717 {
1718 var.insert("Vb");
1719 var.insert("Vc");
1720 var.insert("Vd");
1721 };
1723 {
1724 var.insert("Vx");
1725 var.insert("Vy");
1726 };
1729 {
1730 var.insert("Ra");
1731 var.insert("Rb");
1732 var.insert("Rc");
1733 var.insert("Rd");
1734 var.insert("Re");
1735 };
1736 };
1737 bool deactivate = false;
1738 if (markSelected)
1739 {
1740 // check which state the clicked image have
1742 }
1743 else
1744 {
1745 for (std::set<std::string>::const_iterator varIt = var.begin(); varIt != var.end(); ++varIt)
1746 {
1747 //search, if image variable is marked for optimise for at least one image of group
1748 for (HuginBase::UIntSet::const_iterator imgIt = imgs.begin(); imgIt != imgs.end() && !deactivate; ++imgIt)
1749 {
1750 if (set_contains(optVec[*imgIt], *varIt))
1751 {
1752 deactivate = true;
1753 };
1754 };
1755 };
1756 };
1757 // now deactivate or activate the image variable for optimisation
1758 if (deactivate)
1759 {
1760 for (std::set<std::string>::const_iterator varIt = var.begin(); varIt != var.end(); ++varIt)
1761 {
1762 for (HuginBase::UIntSet::const_iterator imgIt = imgs.begin(); imgIt != imgs.end(); ++imgIt)
1763 {
1764 optVec[*imgIt].erase(*varIt);
1765 };
1766 }
1767 }
1768 else
1769 {
1770 for (std::set<std::string>::const_iterator varIt = var.begin(); varIt != var.end(); ++varIt)
1771 {
1772 for (HuginBase::UIntSet::const_iterator imgIt = imgs.begin(); imgIt != imgs.end(); ++imgIt)
1773 {
1774 optVec[*imgIt].insert(*varIt);
1775 };
1776 };
1777 };
1780 );
1781 m_leftDownItem.Unset();
1782 return;
1783 };
1784 };
1785 if (m_leftDownItem.IsOk())
1786 {
1787 m_leftDownItem.Unset();
1788 };
1789 e.Skip();
1790 };
1791};
1792
1794{
1795 if (!m_dragging)
1796 {
1797 if (e.LeftDown())
1798 {
1799 // force end editing
1800 EndEdit(false);
1801 // find where user clicked
1802 int flags;
1803 int col;
1804 wxTreeItemId item = HitTest(e.GetPosition(), flags, col);
1805 if (item.IsOk() && (flags & wxTREE_HITTEST_ONITEMICON))
1806 {
1808 {
1809 if (!GetItemText(item, col).IsEmpty())
1810 {
1811 // store for later and stop processing this event further
1814 return;
1815 };
1816 };
1817 };
1818 };
1819 };
1820 e.Skip();
1821};
1822
1824{
1825 int flags;
1826 int col;
1827 wxTreeItemId item = HitTest(e.GetPosition(), flags, col);
1828 if (item.IsOk() && (flags & wxTREE_HITTEST_ONITEMICON))
1829 {
1830 // mouse moved over optimizer checkbox
1831 int imgNr = GetItemImage(item, col);
1832 if (imgNr >= 0 && imgNr < 2)
1833 {
1834 // update checkbox image and store position for later
1835 SetItemImage(item, col, imgNr + 2);
1838 };
1839 }
1840 else
1841 {
1842 // mouse moved from checkbox away, so update images
1843 if (m_lastCurrentItem.IsOk())
1844 {
1846 if (imgNr > 1)
1847 {
1849 };
1850 m_lastCurrentItem.Unset();
1851 };
1852 };
1853 e.Skip();
1854};
1855
1857{
1858 std::set<std::string> imgVars;
1859 std::string var=m_columnVector[m_selectedColumn];
1860 if(var=="cam_trans")
1861 {
1862 imgVars.insert("TrX");
1863 imgVars.insert("TrY");
1864 imgVars.insert("TrZ");
1865 imgVars.insert("Tpy");
1866 imgVars.insert("Tpp");
1867 }
1868 else
1869 {
1870 imgVars.insert(var);
1871 if(var=="Vb" || var=="Vc" || var=="Vd")
1872 {
1873 imgVars.insert("Vb");
1874 imgVars.insert("Vc");
1875 imgVars.insert("Vd");
1876 };
1877 if(var=="Vx" || var=="Vy")
1878 {
1879 imgVars.insert("Vx");
1880 imgVars.insert("Vy");
1881 };
1882 if(var=="Ra" || var=="Rb" || var=="Rc" || var=="Rd" || var=="Re")
1883 {
1884 imgVars.insert("Ra");
1885 imgVars.insert("Rb");
1886 imgVars.insert("Rc");
1887 imgVars.insert("Rd");
1888 imgVars.insert("Re");
1889 };
1890
1891 };
1892
1893 HuginBase::UIntSet imgs;
1894 if(allImages)
1895 {
1896 fill_set(imgs, 0, m_pano->getNrOfImages()-1);
1897 }
1898 else
1899 {
1902 {
1903 for(size_t i=0;i<selectedItem.size();i++)
1904 {
1907 if(data->IsGroup())
1908 {
1910 }
1911 else
1912 {
1914 };
1917 while(item.IsOk())
1918 {
1919 data=static_cast<ImagesTreeData*>(GetItemData(item));
1920 imgs.insert(data->GetImgNr());
1922 };
1923 };
1924 };
1925 };
1926
1928 for(HuginBase::UIntSet::iterator img=imgs.begin(); img!=imgs.end(); ++img)
1929 {
1930 for(std::set<std::string>::const_iterator it=imgVars.begin(); it!=imgVars.end(); ++it)
1931 {
1932 if(select)
1933 {
1934 if((*it=="y" || *it=="p" || *it=="r" || *it=="TrX" || *it=="TrY" || *it=="TrZ" || *it=="Tpy" || *it=="Tpp") &&
1936 {
1937 optVec[*img].erase(*it);
1938 continue;
1939 };
1940 if(*it=="Eev" && (*img==m_pano->getOptions().colorReferenceImage || m_pano->getImage(*img).ExposureValueisLinkedWith(m_pano->getImage(m_pano->getOptions().colorReferenceImage))))
1941 {
1942 optVec[*img].erase(*it);
1943 continue;
1944 };
1945 if (*it == "Er" && (*img == m_pano->getOptions().colorReferenceImage || m_pano->getImage(*img).WhiteBalanceRedisLinkedWith(m_pano->getImage(m_pano->getOptions().colorReferenceImage))))
1946 {
1947 optVec[*img].erase(*it);
1948 continue;
1949 };
1950 if (*it == "Eb" && (*img == m_pano->getOptions().colorReferenceImage || m_pano->getImage(*img).WhiteBalanceBlueisLinkedWith(m_pano->getImage(m_pano->getOptions().colorReferenceImage))))
1951 {
1952 optVec[*img].erase(*it);
1953 continue;
1954 };
1955 optVec[*img].insert(*it);
1956 }
1957 else
1958 {
1959 optVec[*img].erase(*it);
1960 };
1961 };
1962 };
1965 );
1966};
1967
1968void ImagesTreeCtrl::OnSelectAll(wxCommandEvent &e)
1969{
1970 SelectAllParameters(true, true);
1971};
1972
1973void ImagesTreeCtrl::OnUnselectAll(wxCommandEvent &e)
1974{
1975 SelectAllParameters(false, true);
1976};
1977
1979{
1980 SelectAllParameters(true, false);
1981};
1982
1984{
1985 SelectAllParameters(false, false);
1986};
1987
1989{
1990 switch(e.GetKeyCode())
1991 {
1992 case WXK_INSERT:
1993 {
1994 wxCommandEvent ev(wxEVT_COMMAND_MENU_SELECTED, XRCID("action_add_images"));
1995 MainFrame::Get()->GetEventHandler()->AddPendingEvent(ev);
1996 break;
1997 };
1998 case WXK_DELETE:
1999 {
2001 if(!imgs.empty())
2002 {
2003 // remove all marked images from cache
2004 for (auto& img : imgs)
2005 {
2006 ImageCache::getInstance().removeImage(m_pano->getImage(img).getFilename());
2007 };
2008 // now remove images from panorama object
2011 );
2012 };
2013 break;
2014 };
2015#if defined __WXMAC__
2016 case 'A':
2017 case 'a':
2018 // check for cmd+A -> select all
2019 if (e.GetExtraLong() == wxMOD_CMD)
2020 {
2021 SelectAll();
2022 };
2023 break;
2024#endif
2025 case 1: //Ctrl+A
2026 {
2027 SelectAll();
2028 break;
2029 }
2030 default:
2031 e.Skip();
2032 };
2033};
2034
2036{
2037 m_editOldString=GetItemText(e.GetItem(), e.GetInt());
2038 if(m_editOldString.IsEmpty())
2039 {
2040 e.Veto();
2041 }
2042 else
2043 {
2044 ImagesTreeData* data=static_cast<ImagesTreeData*>(GetItemData(e.GetItem()));
2045 if(data->IsGroup())
2046 {
2048 wxTreeItemId item=GetFirstChild(e.GetItem(), cookie);
2049 data=static_cast<ImagesTreeData*>(GetItemData(item));
2050 };
2051 m_editVal=m_pano->getImage(data->GetImgNr()).getVar(m_columnVector[e.GetInt()]);
2052 SetItemText(e.GetItem(), e.GetInt(), hugin_utils::doubleTowxString(m_editVal));
2053 e.Allow();
2054 };
2055};
2056
2058{
2059 if(e.IsEditCancelled())
2060 {
2061 //restore old string
2062 SetItemText(e.GetItem(), e.GetInt(), m_editOldString);
2063 Refresh();
2064 }
2065 else
2066 {
2067 double val;
2068 if(!hugin_utils::str2double(e.GetLabel(),val))
2069 {
2070 //restore old string
2071 SetItemText(e.GetItem(), e.GetInt(), m_editOldString);
2072 Refresh();
2073 e.Veto();
2074 }
2075 else
2076 {
2077 //only update if value was changed
2078 if(val!=m_editVal)
2079 {
2080 ImagesTreeData* data=static_cast<ImagesTreeData*>(GetItemData(e.GetItem()));
2081 if(data->IsGroup())
2082 {
2084 wxTreeItemId item=GetFirstChild(e.GetItem(), cookie);
2085 data=static_cast<ImagesTreeData*>(GetItemData(item));
2086 };
2087 HuginBase::UIntSet imgs;
2088 imgs.insert(data->GetImgNr());
2089 if(m_columnVector[e.GetInt()]=="v")
2090 {
2091 if(m_pano->getImage(data->GetImgNr()).getProjection()==HuginBase::SrcPanoImage::FISHEYE_ORTHOGRAPHIC && val>190)
2092 {
2094 wxString::Format(_("You have given a field of view of %.2f degrees.\n But the orthographic projection is limited to a field of view of 180 degress.\nDo you want still use that high value?"), val),
2095 _("Hugin"), wxICON_EXCLAMATION | wxYES_NO, this) == wxNO)
2096 {
2097 //restore old string
2098 SetItemText(e.GetItem(), e.GetInt(), m_editOldString);
2099 Refresh();
2100 e.Veto();
2101 e.Skip();
2102 return;
2103 };
2104 };
2105 };
2106 HuginBase::Variable var(m_columnVector[e.GetInt()], val);
2108 new PanoCommand::SetVariableCmd(*m_pano, imgs, var)
2109 );
2110 //we need to veto the event otherwise the internal
2111 //function does update the text to the full number
2112 e.Veto();
2113 }
2114 else
2115 {
2116 //restore old string
2117 SetItemText(e.GetItem(), e.GetInt(), m_editOldString);
2118 Refresh();
2119 };
2120 };
2121 };
2122 e.Skip();
2123};
2124
2134
2136{
2137 if(!m_optimizerMode)
2138 {
2139 int flags;
2140 int col;
2141 wxTreeItemId item=HitTest(e.GetPosition(), flags, col);
2144 GetEventHandler()->AddPendingEvent(commandEvent);
2145 };
2146 e.Skip();
2147};
2148
2149IMPLEMENT_DYNAMIC_CLASS(ImagesTreeCtrl, wxTreeListCtrl)
2150
2152 : wxTreeListCtrlXmlHandler()
2153{
2154}
2155
2157{
2159
2160 cp->Create(m_parentAsWindow,
2161 GetID(),
2162 GetPosition(), GetSize(),
2163 GetStyle("style"),
2164 GetName());
2165
2166 SetupWindow( cp);
2167
2168 return cp;
2169}
2170
2172{
2173 return IsOfClass(node, "ImagesTreeList");
2174}
2175
2176IMPLEMENT_DYNAMIC_CLASS(ImagesTreeCtrlXmlHandler, wxTreeListCtrlXmlHandler)
2177
2178
GuiLevel
Definition GuiLevel.h:32
@ GUI_EXPERT
Definition GuiLevel.h:35
@ GUI_ADVANCED
Definition GuiLevel.h:34
@ GUI_SIMPLE
Definition GuiLevel.h:33
Definition of dialog to edit image variables.
Declare the ImageVariableGroup and ImageVariableGroupObserver classes.
#define ADDCOLUMN(header, mapName, width, align, isEditable, IVE, tooltip)
@ ID_SELECT_ALL
@ ID_ACTIVATE_IMAGE
@ ID_UNSELECT_ALL
@ ID_LINK
@ ID_UNSELECT_LENS_STACK
@ ID_DEACTIVATE_IMAGE
@ ID_SELECT_LENS_STACK
@ ID_EDIT
@ ID_UNLINK
@ ID_OPERATION_START
declaration of main image tree control
declaration of functions to handle stacks and layers
wxString getProjectionString(const HuginBase::SrcPanoImage &img)
Returns translated projection for given image.
wxString getResponseString(const HuginBase::SrcPanoImage &img)
Returns translated response type for given SrcPanoImage.
some helper classes for graphes
Somewhere to specify what variables belong to what.
HuginBase::UIntSet GetDragGroupImages()
void SetDragGroupImages(HuginBase::UIntSet imageDragGroup_in, bool update_check_box=true)
@ RESPONSE_EMOR
empirical model of response
std::size_t getNumberOfParts() const
get the number of parts.
unsigned int getPartNumber(unsigned int imageNr) const
Get a part number from an image number.
UIntSetVector getPartsSet() const
return a vector which contains a HuginBase::UIntSet for each group with the corresponding images numb...
static const std::set< ConstImageVariableGroup::ImageVariableEnum > & getLensVariables()
Get the set of lens image variables.
static const std::set< ConstImageVariableGroup::ImageVariableEnum > & getStackVariables()
Get the set of stack image variables.
Model for a panorama.
Definition Panorama.h:153
const SrcPanoImage & getImage(std::size_t nr) const
get a panorama image, counting starts with 0
Definition Panorama.h:211
const PanoramaOptions & getOptions() const
returns the options for this panorama
Definition Panorama.h:481
std::vector< unsigned int > getCtrlPointsForImage(unsigned int imgNr) const
return all control points for a given image.
Definition Panorama.cpp:83
void addObserver(PanoramaObserver *o)
add a panorama observer.
bool removeObserver(PanoramaObserver *observer)
remove a panorama observer.
const OptimizeVector & getOptimizeVector() const
return the optimize settings stored inside panorama
Definition Panorama.h:454
UIntSet getActiveImages() const
get active images
std::size_t getNrOfImages() const
number of images.
Definition Panorama.h:205
All variables of a source image.
ImageVariableGroup & getStacks()
Get the ImageVariableGroup representing the group of stack variables.
ImageVariableGroup & getLenses()
Get the ImageVariableGroup representing the group of lens variables.
void update()
Update part numbers for each variable group.
a variable has a value and a name.
Dialog for editing image variables.
virtual wxObject * DoCreateResource()
virtual bool CanHandle(wxXmlNode *node)
the main images tree control, used on images and optimizer tabs
Definition ImagesTree.h:37
HuginBase::StandardImageVariableGroups * m_variable_groups
Definition ImagesTree.h:173
void OnExecuteOperation(wxCommandEvent &e)
menu event handler for PanoOperation (context menu items)
void UpdateItemFont()
update the font colour for all items
void OnMouseMove(wxMouseEvent &e)
event handler for mouse motion, handles focussing of check boxes
wxTreeItemId m_leftDownItem
stores where left mouse click happend
Definition ImagesTree.h:217
std::vector< HuginBase::ImageVariableGroup::ImageVariableEnum > m_variableVector
vector for easier access to linking information
Definition ImagesTree.h:194
void OnContextMenu(wxTreeEvent &e)
event handler to display context menu
void OnActivateImage(wxCommandEvent &e)
event handler for activate image
void OnBeginEdit(wxTreeEvent &e)
event handler for beginning editing
void GenerateSubMenu(wxMenu *menu, PanoOperation::PanoOperationVector *operations, int &id)
generates submenu for given PanoOperationVector
void UpdateGroupText(wxTreeItemId item)
updates the information fot the given lens/stack in the tree
void OnSelectLensStack(wxCommandEvent &e)
event handler for select all optimizer variables for selected lens/stack
void UpdateImageText(wxTreeItemId item)
updates the information for the given image in tree
void CreateCheckboxImages()
create image list with necessary images of checkboxes
void OnEditImageVariables(wxCommandEvent &e)
event handler for showing image variables editing dialog
long m_leftDownColumn
Definition ImagesTree.h:218
bool m_optimizerMode
true, if in optimizer mode
Definition ImagesTree.h:182
bool Create(wxWindow *parent, wxWindowID id=wxID_ANY, const wxPoint &pos=wxDefaultPosition, const wxSize &size=wxDefaultSize, long style=wxTAB_TRAVERSAL, const wxString &name="panel")
creates the control
void OnUnselectLensStack(wxCommandEvent &e)
event handler for unselect all optimizer variables for selected lens/stack
void OnBeginDrag(wxTreeEvent &e)
event handler when dragging begins, veto if dragging is not possible
wxTreeItemId m_lastCurrentItem
stores last item on which the mouse was hovering
Definition ImagesTree.h:214
bool m_needsUpdate
helper variable for update of output stacks/layers
Definition ImagesTree.h:208
virtual ~ImagesTreeCtrl(void)
destructor
HuginBase::Panorama * m_pano
Definition ImagesTree.h:168
void OnSelectAll(wxCommandEvent &e)
event handler for select all optimizer variables
HuginBase::UIntSet GetSelectedImages()
returns the selected images
void SelectAllParameters(bool select, bool allImages)
select/unselect all variables in the active column @select true selects all, false unselect all @allI...
void SetGuiLevel(GuiLevel newSetting)
sets the GuiLevel of the control
void OnLinkImageVariables(wxCommandEvent &e)
event handler for linking image variables
HuginBase::UIntSet m_editableColumns
set, which contains editable columns (all column which contains numeric image variables
Definition ImagesTree.h:192
void OnDeactivateImage(wxCommandEvent &e)
event handler for deactivate image
void Init(HuginBase::Panorama *pano)
initialization, connects all control with Panorama, register observer
std::map< std::string, size_t > m_columnMap
map for easier access to column information
Definition ImagesTree.h:188
void OnHeaderContextMenu(wxListEvent &e)
event handler for context menu on header
void OnColumnWidthChange(wxListEvent &e)
event handler, when column width was changed, save into wxConfig
void SetGroupMode(GroupMode newMode)
sets the group mode to given mode
GroupMode m_groupMode
the active group mode
Definition ImagesTree.h:170
void panoramaImagesChanged(HuginBase::Panorama &pano, const HuginBase::UIntSet &imgNr)
receive the update signal and update display accordingly
void OnUnselectAll(wxCommandEvent &e)
event handler for unselect all optimizer variables
void SetOptimizerMode()
sets to control into optimizer mode
size_t m_selectedColumn
selected column
Definition ImagesTree.h:198
void OnUnlinkImageVariables(wxCommandEvent &e)
event handler for unlinking image variables
GroupMode
enumeration for grouping mode
Definition ImagesTree.h:41
void CreateColumns()
creates all columns and stores information in m_columnMap, m_columnVector, m_editableColumns and m_va...
void OnLeftDblClick(wxMouseEvent &e)
event handler for left double click
std::map< int, PanoOperation::PanoOperation * > m_menuOperation
map with current active context menu PanoOperation
Definition ImagesTree.h:196
wxString m_editOldString
wxString, as shown before editing started
Definition ImagesTree.h:206
void UnLinkImageVariables(bool linked)
helper procedure for link/unlink image variables
void OnLeftDown(wxMouseEvent &e)
event handler for left mouse down, handles toggle of optimizer variables
bool m_markDisabledImages
true, if disabled images should be marked with other font color
Definition ImagesTree.h:184
GuiLevel m_guiLevel
stores the active GuiLevel
Definition ImagesTree.h:180
long m_lastCurrentCol
Definition ImagesTree.h:215
void SetDisplayMode(DisplayMode newMode)
sets the display mode to given mode
void UpdateOptimizerVariables()
updates the display of the optimizer variables (set font)
bool m_dragging
true, if dragging
Definition ImagesTree.h:202
DisplayMode
enumeration for display mode, limits the displayed columns
Definition ImagesTree.h:50
@ DISPLAY_PHOTOMETRICS_LENSES
Definition ImagesTree.h:57
@ DISPLAY_PHOTOMETRICS_IMAGES
Definition ImagesTree.h:56
void OnLeftUp(wxMouseEvent &e)
event handler for left up, handles end of dragging and updates of optimizer variables states
HuginBase::UIntSet m_draggingImages
UIntSet of dragging images.
Definition ImagesTree.h:200
wxTreeItemId m_root
pointer to root item, not shown
Definition ImagesTree.h:211
virtual void panoramaChanged(HuginBase::Panorama &pano)
receives notification about panorama changes
double m_editVal
value, which is currently edited
Definition ImagesTree.h:204
void UpdateGroup(wxTreeItemId parent, const HuginBase::UIntSet imgs, HuginBase::UIntSet &changed)
updates the given group, updates number of images and the images itself
void OnDpiChanged(wxDPIChangedEvent &e)
event handler for updating dpi
void MarkActiveImages(const bool markActive)
sets the flag, if active/disabled image should be marked with different colour
void OnChar(wxTreeEvent &e)
event handler for key events
void OnEndEdit(wxTreeEvent &e)
event handler for ending editing, updates the Panorama with modified value
DisplayMode m_displayMode
the active display mode
Definition ImagesTree.h:186
ImagesTreeCtrl()
general constructor
wxString m_configClassName
Definition ImagesTree.h:221
std::vector< std::string > m_columnVector
vector for easier access to column information
Definition ImagesTree.h:190
const bool IsGroup() const
const long GetImgNr() const
void SetImgNr(long newImgNr)
const long GetGroupNr() const
ImagesTreeData(const long &nr)
static MainFrame * Get()
hack.. kind of a pseudo singleton...
GLPreviewFrame * getGLPreview()
Change the linking of some variables across parts of an ImageVariableGroup containing some specified ...
Switch the part number of an image.
void addCommand(PanoCommand *command, bool execute=true)
Adds a command to the history.
static GlobalCmdHist & getInstance()
move image from position1 to position2
Make a new part in a ImageVariableGroup for a set of images, given the variables that make up the gro...
Base class for all panorama commands.
Definition Command.h:39
remove multiple images from a panorama
Definition PanoCommand.h:95
update a single variable, possibly for a group of images
updates the optimize vector, aka all variables which should be optimized
simple class that forward the drop to the mainframe
Definition MainFrame.h:62
base class for different PanoOperations derived classes should overwrite protected PanoOperation::Get...
virtual PanoCommand::PanoCommand * GetCommand(wxWindow *parent, HuginBase::Panorama &pano, HuginBase::UIntSet images, GuiLevel guiLevel)
returns the appropriate PanoCommand::PanoCommand to be inserted into GlobalCmdHistory,...
void SetItemText(const wxTreeItemId &item, const wxString &text)
wxTreeItemData * GetItemData(const wxTreeItemId &item) const
wxTreeItemId GetNext(const wxTreeItemId &item) const
size_t GetSelections(wxArrayTreeItemIds &) const
void AddColumn(const wxString &text, int width=DEFAULT_COL_WIDTH, int flag=wxALIGN_LEFT, int image=-1, bool shown=true, bool edit=false, const wxString &tooltip=wxEmptyString)
size_t GetChildrenCount(const wxTreeItemId &item, bool recursively=true)
bool IsSelected(const wxTreeItemId &item) const
wxTreeItemId AddRoot(const wxString &text, int image=-1, int selectedImage=-1, wxTreeItemData *data=NULL)
void SetItemImage(const wxTreeItemId &item, int image, wxTreeItemIcon which=wxTreeItemIcon_Normal)
void Refresh(bool erase=TRUE, const wxRect *rect=NULL)
wxString GetItemText(const wxTreeItemId &item) const
wxTreeItemId AppendItem(const wxTreeItemId &parent, const wxString &text, int image=-1, int selectedImage=-1, wxTreeItemData *data=NULL)
void SetColumnWidth(int column, int width)
void SetColumnEditable(int column, bool edit=true)
int GetColumnWidth(int column) const
void SetColumnShown(int column, bool shown=true)
void ExpandAll(const wxTreeItemId &item)
int GetItemImage(const wxTreeItemId &item, wxTreeItemIcon which=wxTreeItemIcon_Normal) const
wxTreeItemId HitTest(const wxPoint &point)
void SetItemTextColour(const wxTreeItemId &item, const wxColour &colour)
void DeleteChildren(const wxTreeItemId &item)
void AssignImageList(wxImageList *imageList)
wxTreeItemId GetItemParent(const wxTreeItemId &item) const
wxTreeItemId GetFirstChild(const wxTreeItemId &item, wxTreeItemIdValue &cookie) const
void SetItemBold(const wxTreeItemId &item, bool bold=true)
void EndEdit(bool isCancelled)
void Delete(const wxTreeItemId &item)
wxTreeItemId GetLastChild(const wxTreeItemId &item, wxTreeItemIdValue &cookie) const
wxTreeItemId GetNextChild(const wxTreeItemId &item, wxTreeItemIdValue &cookie) const
static uint16_t flags
implementation of huginApp Class
#define HUGIN_CONV_FILENAME
Definition platform.h:40
#define DEBUG_ASSERT(cond)
Definition utils.h:80
#define DEBUG_TRACE(msg)
Definition utils.h:67
wxString GetIso(const HuginBase::SrcPanoImage *img)
returns formatted iso value
wxString GetFocalLength(const HuginBase::SrcPanoImage *img)
return focallength and focallength 35 mm as wxString
wxString GetExifDateTime(const HuginBase::SrcPanoImage *img)
returns Exif DateTimeOriginal as formatted wxString
wxString GetExposureTime(const HuginBase::SrcPanoImage *img)
returns formatted exposure time
wxString GetAperture(const HuginBase::SrcPanoImage *img)
returns formatted aperture value
std::vector< std::set< std::string > > OptimizeVector
std::vector< UIntSet > UIntSetVector
std::set< unsigned int > UIntSet
PanoOperationVector * GetStacksOperationVector()
returns list of PanoOperation for stacks
PanoOperationVector * GetImagesOperationVector()
returns list of PanoOperation for work with images
std::vector< PanoOperation * > PanoOperationVector
PanoOperationVector * GetControlPointsOperationVector()
returns list of PanoOperation for work with control points
PanoOperationVector * GetLensesOperationVector()
returns list of PanoOperation for work with lenses
PanoOperationVector * GetResetOperationVector()
returns list of PanoOperation for resetting
bool str2double(const wxString &s, double &d)
wxString doubleTowxString(double d, int digits)
int HuginMessageBox(const wxString &message, const wxString &caption, int style, wxWindow *parent)
Definition wxutils.cpp:176
include file for the hugin project
include file for the hugin project
bool set_contains(const _Container &c, const typename _Container::key_type &key)
Definition stl_utils.h:74
void fill_set(_Container &c, typename _Container::key_type begin, typename _Container::key_type end)
Definition stl_utils.h:81
std::vector< deghosting::BImagePtr > threshold(const std::vector< deghosting::FImagePtr > &inputImages, const double threshold, const uint16_t flags)
Threshold function used for creating alpha masks for images.
Definition threshold.h:41
platform/compiler specific stuff.