// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.

// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with this program; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.

// parentframe.cpp
// These are the top-level and child windows of the application.
// 2007-12-27, Christoph Schmidt-Hieber, University of Freiburg

#ifdef _STFDEBUG
#include <iostream>
#endif
// For compilers that support precompilation, includes "wx/wx.h".
#include <wx/wxprec.h>
#include <wx/grid.h>
#include <wx/artprov.h>
#include <wx/printdlg.h>
#include <wx/file.h>
#include <wx/filename.h>
#include <wx/stdpaths.h>
#include <wx/progdlg.h>
#include <wx/splitter.h>
#include <wx/choicdlg.h>
#include <wx/aboutdlg.h>
#include <wx/protocol/http.h>
#include <wx/sstream.h>
#include <wx/progdlg.h>
#include <wx/settings.h>


#ifdef __BORLANDC__
#pragma hdrstop
#endif

#ifndef WX_PRECOMP
#include <wx/wx.h>
#endif

#if !wxUSE_DOC_VIEW_ARCHITECTURE
#error You must set wxUSE_DOC_VIEW_ARCHITECTURE to 1 in setup.h!
#endif

#if !wxUSE_MDI_ARCHITECTURE
#error You must set wxUSE_MDI_ARCHITECTURE to 1 in setup.h!
#endif

#include "stfconf.h"
#if !defined(PACKAGE_VERSION) && defined(VERSION)
#define PACKAGE_VERSION VERSION
#endif
#ifndef PACKAGE_VERSION
#define PACKAGE_VERSION "unknown"
#endif
#include "./app.h"
#include "./doc.h"
#include "./view.h"
#include "./graph.h"
#include "./table.h"
#include "./printout.h"
#include "./dlgs/convertdlg.h"
#include "./dlgs/smalldlgs.h"
#include "./copygrid.h"
#include "./../../libstfio/atf/atflib.h"
#if defined(WITH_BIOSIG)
    #include "./../../libstfio/biosig/biosiglib.h"
#endif
#include "./../../libstfio/igor/igorlib.h"

#include "./childframe.h"
#include "./parentframe.h"
#include "./../../libstfnum/levmar/levmar.h"

#ifndef wxS_DIR_DEFAULT
#define wxS_DIR_DEFAULT 0777
#endif

namespace {

wxSize GetToolbarBitmapSize(const wxWindow& window)
{
    const wxSize logicalSize(20, 20);
#if wxCHECK_VERSION(3, 1, 0)
    return window.FromDIP(logicalSize);
#else
    return logicalSize;
#endif
}

int GetToolbarIconPixelSize(const wxWindow& window)
{
    const wxSize iconSize = GetToolbarBitmapSize(window);
    return wxMax(iconSize.GetWidth(), iconSize.GetHeight());
}

int SelectToolbarIconBucket(const wxWindow& window)
{
    const int px = GetToolbarIconPixelSize(window);
    if (px >= 50) {
        return 60;
    }
    if (px >= 30) {
        return 40;
    }
    return 20;
}

wxString ResolveToolbarIconBaseDir()
{
    static wxString cached;
    if (!cached.IsEmpty()) {
        return cached;
    }

    wxFileName exePath(wxStandardPaths::Get().GetExecutablePath());
    wxFileName climb(exePath.GetPath(), wxEmptyString);

    wxArrayString candidates;

#ifdef STF_TOOLBAR_SOURCE_DIR
    {
        wxFileName sourceCompileTime(wxString::FromUTF8(STF_TOOLBAR_SOURCE_DIR), wxEmptyString);
        sourceCompileTime.Normalize(wxPATH_NORM_DOTS);
        candidates.Add(sourceCompileTime.GetPath());
    }
#endif

    auto addCandidate = [&candidates](const wxFileName& anchor, const wxArrayString& dirs) {
        wxFileName path(anchor);
        for (size_t i = 0; i < dirs.GetCount(); ++i) {
            path.AppendDir(dirs[i]);
        }
        path.Normalize(wxPATH_NORM_DOTS);
        candidates.Add(path.GetPath());
    };

    // Probe several ancestor levels because Windows multi-config generators
    // place the executable under an extra config directory (e.g. Debug/Release).
    for (int depth = 0; depth <= 6; ++depth) {
        wxArrayString sourceDirs;
        sourceDirs.Add(wxT("src"));
        sourceDirs.Add(wxT("stimfit"));
        sourceDirs.Add(wxT("res"));
        sourceDirs.Add(wxT("toolbar"));
        addCandidate(climb, sourceDirs);

        wxArrayString installDirs;
        installDirs.Add(wxT("share"));
        installDirs.Add(wxT("stimfit"));
        installDirs.Add(wxT("toolbar"));
        addCandidate(climb, installDirs);
#ifdef __WXMAC__
        wxArrayString bundleDirs;
        bundleDirs.Add(wxT("Resources"));
        bundleDirs.Add(wxT("toolbar"));
        addCandidate(climb, bundleDirs);
#endif
        if (climb.GetDirCount() == 0) {
            break;
        }
        climb.RemoveLastDir();
    }

    wxFileName cwdSource(wxGetCwd(), wxEmptyString);
    cwdSource.AppendDir(wxT("src"));
    cwdSource.AppendDir(wxT("stimfit"));
    cwdSource.AppendDir(wxT("res"));
    cwdSource.AppendDir(wxT("toolbar"));
    cwdSource.Normalize(wxPATH_NORM_DOTS);
    candidates.Add(cwdSource.GetPath());

    for (size_t i = 0; i < candidates.GetCount(); ++i) {
        wxFileName probe(candidates[i], wxEmptyString);
        probe.AppendDir(wxT("20"));
        probe.SetFullName(wxT("open.png"));
        if (probe.FileExists()) {
            cached = candidates[i];
            return cached;
        }
    }

    return wxEmptyString;
}

wxBitmap TbBitmap(const wxWindow& window, const wxString& iconName, const wxArtID& fallbackArt)
{
    const wxString baseDir = ResolveToolbarIconBaseDir();
    if (!baseDir.IsEmpty()) {
        const int bucket = SelectToolbarIconBucket(window);
        wxFileName iconPath(baseDir, wxEmptyString);
        iconPath.AppendDir(wxString::Format(wxT("%d"), bucket));
        iconPath.SetFullName(iconName + wxT(".png"));
        if (iconPath.FileExists()) {
            wxBitmap loaded(iconPath.GetFullPath(), wxBITMAP_TYPE_PNG);
            if (loaded.IsOk()) {
                return loaded;
            }
        }

        wxFileName fallback20(baseDir, wxEmptyString);
        fallback20.AppendDir(wxT("20"));
        fallback20.SetFullName(iconName + wxT(".png"));
        if (fallback20.FileExists()) {
            wxBitmap loaded(fallback20.GetFullPath(), wxBITMAP_TYPE_PNG);
            if (loaded.IsOk()) {
                return loaded;
            }
        }
    }

    return wxArtProvider::GetBitmap(fallbackArt, wxART_TOOLBAR, GetToolbarBitmapSize(window));
}

#ifdef WITH_PYTHON
#if PY_MAJOR_VERSION >= 3
PyObject* wxPyMake_wxObject(wxObject* source, bool setThisOwn)
{
    bool checkEvtHandler = true;
    PyObject* target = NULL;
    bool isEvtHandler = false;
    bool isSizer = false;

    if (source) {
        // If it's derived from wxEvtHandler then there may
        // already be a pointer to a Python object that we can use
        // in the OOR data.
        if (checkEvtHandler && wxIsKindOf(source, wxEvtHandler)) {
            isEvtHandler = true;
            wxEvtHandler* eh = (wxEvtHandler*)source;
            wxPyClientData* data = (wxPyClientData*)eh->GetClientObject();
            if (data) {
                target = data->GetData();
            }
        }

        // Also check for wxSizer
        if (!target && wxIsKindOf(source, wxSizer)) {
            isSizer = true;
            wxSizer* sz = (wxSizer*)source;
            wxPyClientData* data = (wxPyClientData*)sz->GetClientObject();
            if (data) {
                target = data->GetData();
            }
        }
        if (!target) {
            // Otherwise make it the old fashioned way by making a new shadow
            // object and putting this pointer in it.  Look up the class
            // heirarchy until we find a class name that is located in the
            // python module.
            const wxClassInfo* info = source->GetClassInfo();
            wxString name = info->GetClassName();
            wxString childname = name.Clone();
            if (info) {
                target = wxPyConstructObject((void*)source, name.c_str(), setThisOwn);
                while (target == NULL) {
                    info = info->GetBaseClass1();
                    name = info->GetClassName();
                    if (name == childname)
                        break;
                    childname = name.Clone();
                    target = wxPyConstructObject((void*)source, name.c_str(), setThisOwn);
                }
                if (target && isEvtHandler)
                    ((wxEvtHandler*)source)->SetClientObject(new wxPyClientData(target));
                if (target && isSizer)
                    ((wxSizer*)source)->SetClientObject(new wxPyClientData(target));
            } else {
                wxString msg(wxT("wxPython class not found for "));
                msg += source->GetClassInfo()->GetClassName();
                PyErr_SetString(PyExc_NameError, msg.mbc_str());
                target = NULL;
            }
        }
    } else {  // source was NULL so return None.
        Py_INCREF(Py_None); target = Py_None;
    }
    return target;
}
#endif
#endif

} // namespace

IMPLEMENT_CLASS(wxStfParentFrame, wxStfParentType)
BEGIN_EVENT_TABLE(wxStfParentFrame, wxStfParentType)
EVT_MENU(wxID_HELP, wxStfParentFrame::OnHelp)
EVT_MENU(ID_UPDATE, wxStfParentFrame::OnCheckUpdate)
EVT_MENU(wxID_ABOUT, wxStfParentFrame::OnAbout)

EVT_TOOL(ID_TOOL_SELECT,wxStfParentFrame::OnToggleSelect)
EVT_TOOL(ID_TOOL_FIRST, wxStfParentFrame::OnToolFirst)
EVT_TOOL(ID_TOOL_NEXT, wxStfParentFrame::OnToolNext)
EVT_TOOL(ID_TOOL_PREVIOUS, wxStfParentFrame::OnToolPrevious)
EVT_TOOL(ID_TOOL_LAST, wxStfParentFrame::OnToolLast)
EVT_TOOL(ID_TOOL_XENL, wxStfParentFrame::OnToolXenl)
EVT_TOOL(ID_TOOL_XSHRINK, wxStfParentFrame::OnToolXshrink)
EVT_TOOL(ID_TOOL_YENL, wxStfParentFrame::OnToolYenl)
EVT_TOOL(ID_TOOL_YSHRINK, wxStfParentFrame::OnToolYshrink)
EVT_TOOL(ID_TOOL_UP, wxStfParentFrame::OnToolUp)
EVT_TOOL(ID_TOOL_DOWN, wxStfParentFrame::OnToolDown)
EVT_TOOL(ID_TOOL_FIT, wxStfParentFrame::OnToolFit)
EVT_TOOL(ID_TOOL_LEFT, wxStfParentFrame::OnToolLeft)
EVT_TOOL(ID_TOOL_RIGHT, wxStfParentFrame::OnToolRight)

EVT_TOOL(ID_TOOL_SNAPSHOT_WMF, wxStfParentFrame::OnToolSnapshotwmf)

EVT_TOOL(ID_TOOL_CH1, wxStfParentFrame::OnToolCh1)
EVT_TOOL(ID_TOOL_CH2, wxStfParentFrame::OnToolCh2)

EVT_TOOL(ID_TOOL_MEASURE, wxStfParentFrame::OnToolMeasure)
EVT_TOOL(ID_TOOL_PEAK,wxStfParentFrame::OnToolPeak)
EVT_TOOL(ID_TOOL_BASE,wxStfParentFrame::OnToolBase)
EVT_TOOL(ID_TOOL_DECAY,wxStfParentFrame::OnToolDecay)
#ifdef WITH_PSLOPE
EVT_TOOL(ID_TOOL_PSLOPE,wxStfParentFrame::OnToolPSlope)
#endif
EVT_TOOL(ID_TOOL_LATENCY,wxStfParentFrame::OnToolLatency)
EVT_TOOL(ID_TOOL_ZOOM,wxStfParentFrame::OnToolZoom)
EVT_TOOL(ID_TOOL_EVENT,wxStfParentFrame::OnToolEvent)
EVT_TOOL(ID_TOOL_ANNOTATION, wxStfParentFrame::OnToolAnnotation)
EVT_TOOL(ID_TOOL_FITDECAY, wxStfParentFrame::OnToolFitdecay)

EVT_MENU(ID_CONVERT, wxStfParentFrame::OnConvert)

EVT_MENU(ID_AVERAGE, wxStfParentFrame::OnAverage)
EVT_MENU(ID_ALIGNEDAVERAGE, wxStfParentFrame::OnAlignedAverage)
EVT_MENU( ID_VIEW_RESULTS, wxStfParentFrame::OnViewResults)
EVT_MENU( ID_CH2BASE, wxStfParentFrame::OnCh2base )
EVT_MENU( ID_CH2POS, wxStfParentFrame::OnCh2pos )
EVT_MENU( ID_CH2ZOOM, wxStfParentFrame::OnCh2zoom )
EVT_MENU( ID_CH2BASEZOOM, wxStfParentFrame::OnCh2basezoom )
EVT_MENU( ID_SCALE, wxStfParentFrame::OnScale )
EVT_MENU( ID_VIEW_DARK_TRACE, wxStfParentFrame::OnDarkTraceDisplay )

EVT_MENU( ID_PRINT_PRINT, wxStfParentFrame::OnPrint)

EVT_MENU( ID_MPL, wxStfParentFrame::OnMpl)
EVT_MENU( ID_MPL_SPECTRUM,wxStfParentFrame::OnMplSpectrum)
EVT_MENU( ID_PRINT_PAGE_SETUP, wxStfParentFrame::OnPageSetup)
EVT_MENU( ID_SAVEPERSPECTIVE, wxStfParentFrame::OnSaveperspective )
EVT_MENU( ID_LOADPERSPECTIVE, wxStfParentFrame::OnLoadperspective )
EVT_MENU( ID_RESTOREPERSPECTIVE, wxStfParentFrame::OnRestoreperspective )
#ifdef WITH_PYTHON
EVT_MENU( ID_VIEW_SHELL, wxStfParentFrame::OnViewshell )
EVT_CHOICE( ID_PY_SHELL_BACKEND, wxStfParentFrame::OnShellBackendChoice )
#endif
#if 0
EVT_MENU( ID_LATENCYSTART_MAXSLOPE, wxStfParentFrame::OnLStartMaxslope )
EVT_MENU( ID_LATENCYSTART_HALFRISE, wxStfParentFrame::OnLStartHalfrise )
EVT_MENU( ID_LATENCYSTART_PEAK, wxStfParentFrame::OnLStartPeak )
EVT_MENU( ID_LATENCYSTART_MANUAL, wxStfParentFrame::OnLStartManual )
EVT_MENU( ID_LATENCYEND_FOOT, wxStfParentFrame::OnLEndFoot )
EVT_MENU( ID_LATENCYEND_MAXSLOPE, wxStfParentFrame::OnLEndMaxslope )
EVT_MENU( ID_LATENCYEND_PEAK, wxStfParentFrame::OnLEndPeak )
EVT_MENU( ID_LATENCYEND_HALFRISE, wxStfParentFrame::OnLEndHalfrise )
EVT_MENU( ID_LATENCYEND_MANUAL, wxStfParentFrame::OnLEndManual )
EVT_MENU( ID_LATENCYWINDOW, wxStfParentFrame::OnLWindow )
#endif
END_EVENT_TABLE()

wxStfParentFrame::wxStfParentFrame(wxDocManager *manager, wxFrame *frame, const wxString& title,
                 const wxPoint& pos, const wxSize& size, long type):
wxStfParentType(manager, frame, wxID_ANY, title, pos, size, type, _T("myFrame"))
#ifdef WITH_PYTHON
, m_shellBackendChoice(NULL)
#endif
, mpl_figno(0)
{
    // ::wxInitAllImageHandlers();

    m_mgr.SetManagedWindow(this);
#ifndef __WXMAC__
    m_mgr.SetFlags(
        wxAUI_MGR_ALLOW_FLOATING |
        wxAUI_MGR_TRANSPARENT_DRAG |
        wxAUI_MGR_VENETIAN_BLINDS_HINT |
        wxAUI_MGR_ALLOW_ACTIVE_PANE
                   );
#else
    m_mgr.SetFlags(
        wxAUI_MGR_DEFAULT
                   );
#endif
#if wxUSE_DRAG_AND_DROP
    m_drop = new wxStfFileDrop; // obviously gets deleted when the frame is destructed
    SetDropTarget(m_drop);
#endif
    m_printData.reset(new wxPrintData);

    // initial paper size
    //	m_printData->SetQuality(wxPRINT_QUALITY_HIGH);
    //	int ppi = m_printData->GetQuality();
    m_printData->SetPaperId(wxPAPER_A4);
    // initial orientation
    m_printData->SetOrientation(wxLANDSCAPE);
    m_pageSetupData.reset(new wxPageSetupDialogData);
    // copy over initial paper size from print record
    m_pageSetupData->SetPrintData(*m_printData);
    // Set some initial page margins in mm.
    m_pageSetupData->SetMarginTopLeft(wxPoint(15, 15));
    m_pageSetupData->SetMarginBottomRight(wxPoint(15, 15));

    // create some toolbars

    wxStfToolBar* tb1 = CreateStdTb();
    tb1->Realize();

    m_scaleToolBar=CreateScaleTb();
    m_scaleToolBar->Realize();

    wxStfToolBar* tb4=CreateEditTb();
    tb4->Realize();

    m_cursorToolBar=CreateCursorTb();
    m_cursorToolBar->Realize();

    // add the toolbars to the manager
    m_mgr.AddPane( tb1, wxAuiPaneInfo().Name(wxT("tb1")).Caption(wxT("Std Toolbar")).ToolbarPane().Resizable(false).
                   Position(0).Top().Gripper().RightDockable(false) );

#ifdef __WXMAC__
    int xpos = 64, ypos = 32;
#endif
    m_mgr.AddPane( m_cursorToolBar, wxAuiPaneInfo().Name(wxT("tb2")).Caption(wxT("Edit Toolbar")).
                   ToolbarPane().Resizable(false).
#ifndef __WXMAC__
                   Position(1).Top().Gripper().RightDockable(false) );
#else
                   Dockable(false).Float().FloatingPosition(xpos, ypos) );
    xpos += m_cursorToolBar->GetSize().GetWidth()+8;
#endif
    m_mgr.AddPane( tb4, wxAuiPaneInfo().Name(wxT("tb4")).Caption(wxT("Analysis Toolbar")).
                   ToolbarPane().Resizable(false).
#ifndef __WXMAC__
                   Position(2).Top().Gripper().RightDockable(false) );
#else
                   Dockable(false).Float().FloatingPosition(xpos,ypos) );
    xpos += tb4->GetSize().GetWidth()+8;
#endif
    m_mgr.AddPane( m_scaleToolBar, wxAuiPaneInfo().Name(wxT("m_scaleToolBar")).Caption(wxT("Navigation Toolbar")).
                   ToolbarPane().Resizable(false).
#ifndef __WXMAC__
                   Position(3).Top().Gripper().RightDockable(false) );
#else
                   Dockable(false).Float().FloatingPosition(xpos,ypos) );
#endif

    SetMouseQual( stf::measure_cursor );

#ifdef WITH_PYTHON
#if PY_MAJOR_VERSION >= 3
#define STF_PY_SHELL_MODULE wxT("embedded_shell_selector")
#else
#if defined(STF_PY_SHELL_BACKEND_LEGACY)
#define STF_PY_SHELL_MODULE wxT("embedded_stf")
#elif defined(STF_PY_SHELL_BACKEND_JUPYTER)
#define STF_PY_SHELL_MODULE wxT("embedded_shell_ipython")
#else
#define STF_PY_SHELL_MODULE wxT("embedded_shell_modern")
#endif
#endif
    wxFileName stfExePath(wxStandardPaths::Get().GetExecutablePath());
    const wxString stfExeDir = stfExePath.GetPath();
    wxFileName stfSourcePyPath(stfExeDir, wxEmptyString);
    stfSourcePyPath.AppendDir(wxT(".."));
    stfSourcePyPath.AppendDir(wxT("src"));
    stfSourcePyPath.AppendDir(wxT("stimfit"));
    stfSourcePyPath.AppendDir(wxT("py"));
    stfSourcePyPath.Normalize(wxPATH_NORM_DOTS);
    const wxString stfSourcePyDir = stfSourcePyPath.GetPath();

    wxFileName stfBuildPyPath(stfExeDir, wxEmptyString);
    stfBuildPyPath.AppendDir(wxT("src"));
    stfBuildPyPath.AppendDir(wxT("stimfit"));
    stfBuildPyPath.AppendDir(wxT("py"));
    stfBuildPyPath.Normalize(wxPATH_NORM_DOTS);
    const wxString stfBuildPyDir = stfBuildPyPath.GetPath();

    wxFileName stfWorkspacePyPath(stfExeDir, wxEmptyString);
    stfWorkspacePyPath.AppendDir(wxT(".."));
    stfWorkspacePyPath.AppendDir(wxT(".."));
    stfWorkspacePyPath.AppendDir(wxT("src"));
    stfWorkspacePyPath.AppendDir(wxT("stimfit"));
    stfWorkspacePyPath.AppendDir(wxT("py"));
    stfWorkspacePyPath.Normalize(wxPATH_NORM_DOTS);
    const wxString stfWorkspacePyDir = stfWorkspacePyPath.GetPath();

    wxFileName stfNestedBuildPyPath(stfExeDir, wxEmptyString);
    stfNestedBuildPyPath.AppendDir(wxT(".."));
    stfNestedBuildPyPath.AppendDir(wxT(".."));
    stfNestedBuildPyPath.AppendDir(wxT(".."));
    stfNestedBuildPyPath.AppendDir(wxT("src"));
    stfNestedBuildPyPath.AppendDir(wxT("stimfit"));
    stfNestedBuildPyPath.AppendDir(wxT("py"));
    stfNestedBuildPyPath.Normalize(wxPATH_NORM_DOTS);
    const wxString stfNestedBuildPyDir = stfNestedBuildPyPath.GetPath();

    wxFileName stfInstallPyPath(stfExeDir, wxEmptyString);
    stfInstallPyPath.AppendDir(wxT(".."));
    stfInstallPyPath.AppendDir(wxT("lib"));
    stfInstallPyPath.AppendDir(wxT("stimfit"));
    stfInstallPyPath.Normalize(wxPATH_NORM_DOTS);
    const wxString stfInstallPyDir = stfInstallPyPath.GetPath();

    wxFileName stfBundleInstallPyPath(stfExeDir, wxEmptyString);
    stfBundleInstallPyPath.AppendDir(wxT(".."));
    stfBundleInstallPyPath.AppendDir(wxT(".."));
    stfBundleInstallPyPath.AppendDir(wxT(".."));
    stfBundleInstallPyPath.AppendDir(wxT("lib"));
    stfBundleInstallPyPath.AppendDir(wxT("stimfit"));
    stfBundleInstallPyPath.Normalize(wxPATH_NORM_DOTS);
    const wxString stfBundleInstallPyDir = stfBundleInstallPyPath.GetPath();

    auto stfPyEscape = [](const wxString& path) {
        wxString escaped(path);
        escaped.Replace(wxT("\\"), wxT("\\\\"));
        escaped.Replace(wxT("'"), wxT("\\'"));
        return escaped;
    };

    const wxString stfExeDirEscaped = stfPyEscape(stfExeDir);
    const wxString stfSourcePyDirEscaped = stfPyEscape(stfSourcePyDir);
    const wxString stfBuildPyDirEscaped = stfPyEscape(stfBuildPyDir);
    const wxString stfWorkspacePyDirEscaped = stfPyEscape(stfWorkspacePyDir);
    const wxString stfNestedBuildPyDirEscaped = stfPyEscape(stfNestedBuildPyDir);
    const wxString stfInstallPyDirEscaped = stfPyEscape(stfInstallPyDir);
    const wxString stfBundleInstallPyDirEscaped = stfPyEscape(stfBundleInstallPyDir);
    int stfShellBackendSelection = wxGetApp().wxGetProfileInt(wxT("Settings"), wxT("PyShellBackend"), 2);
    if (stfShellBackendSelection < 0 || stfShellBackendSelection > 2) {
        stfShellBackendSelection = 2;
    }
    wxString stfDefaultShellKey = wxT("ipython");
    if (stfShellBackendSelection == 0) {
        stfDefaultShellKey = wxT("legacy");
    } else if (stfShellBackendSelection == 1) {
        stfDefaultShellKey = wxT("modern");
    }

    python_code2 << wxT("import os\n")
                 << wxT("os.environ['STF_EMBEDDED_SHELL']='1'\n")
#if PY_MAJOR_VERSION >= 3
                 << wxT("os.environ['STF_PY_SHELL_DEFAULT']='") << stfDefaultShellKey << wxT("'\n")
                 << wxT("os.environ['STF_PY_SHELL_HIDE_INTERNAL_SELECTOR']='1'\n")
#endif
                 << wxT("os.environ.pop('PYTHONSTARTUP', None)\n")
                 << wxT("os.environ.pop('PYTHONINSPECT', None)\n")
                 << wxT("import sys\n")
                 << wxT("sys.path.append('.')\n")
                 << wxT("sys.path.append('") << stfExeDirEscaped << wxT("')\n")
                 << wxT("sys.path.append('") << stfSourcePyDirEscaped << wxT("')\n")
                 << wxT("sys.path.append('") << stfBuildPyDirEscaped << wxT("')\n")
                 << wxT("sys.path.append('") << stfWorkspacePyDirEscaped << wxT("')\n")
                 << wxT("sys.path.append('") << stfNestedBuildPyDirEscaped << wxT("')\n")
                 << wxT("sys.path.append('") << stfInstallPyDirEscaped << wxT("')\n")
                 << wxT("sys.path.append('") << stfBundleInstallPyDirEscaped << wxT("')\n")
                 << wxT("import ") << STF_PY_SHELL_MODULE << wxT("\n")
                 << wxT("\n")
                 << wxT("def makeWindow(parent, figsize=(8,6)):\n")
                 << wxT("    win = ") << STF_PY_SHELL_MODULE << wxT(".MyPanel(parent)\n")
                 << wxT("    return win\n")
                 << wxT("\n")
#if PY_MAJOR_VERSION < 3
                 << wxT("import embedded_mpl\n")
                 << wxT("def plotWindowMpl(parent, figsize=(8,6)):\n")
                 << wxT("    win = embedded_mpl.MplPanel(parent, figsize)\n")
                 << wxT("    win.plot_screen()\n")
                 << wxT("    return win\n")
                 << wxT("\n")
                 << wxT("def spectrumWindowMpl(parent, figsize=(8,6)):\n")
                 << wxT("    win = embedded_mpl.MplPanel(parent, figsize)\n")
                 << wxT("    win.plot_spectrum()\n")
                 << wxT("    return win\n")
                 << wxT("\n")
                 << wxT("def makeWindowMpl(parent, figsize=(8,6)):\n")
                 << wxT("    win = embedded_mpl.MplPanel(parent, figsize)\n")
                 << wxT("    return win\n")
#endif
    ;
    /*  The window remains open after the main application has been closed; deactivated for the time being.
     *  RedirectStdio();
     */
    bool show = wxGetApp().wxGetProfileInt(wxT("Settings"),wxT("ViewShell"), 1);
    wxWindow* pPython = MakePythonWindow("makeWindow", "pythonShell", "Python Shell", show,
#ifdef __WXMAC__
                                         true
#else
                                         false, false, GetClientSize().GetWidth(), GetClientSize().GetHeight()/5
#endif                                         
                                     ).cppWindow;
    if ( pPython == 0 ) {
        wxGetApp().ErrorMsg(wxT("Can't create a window for the python shell\nPointer is zero"));
    }

#ifdef _STFDEBUG
#ifdef _WINDOWS
    wxGetApp().InfoMsg( python_code2 );
#else
    std::cout << "python startup script:\n" << std::string( python_code2.char_str() );
#endif // _WINDOWS
#endif // _STFDEBUG
#else // WITH_PYTHON
    m_mgr.Update();
#endif // WITH_PYTHON

    wxStatusBar* pStatusBar = new wxStatusBar(this, wxID_ANY, wxST_SIZEGRIP);
    SetStatusBar(pStatusBar);
    //int widths[] = { 60, 60, -1 };
    //pStatusBar->SetFieldWidths(WXSIZEOF(widths), widths);
    //pStatusBar->SetStatusText(wxT("Test"), 0);
}

wxStfParentFrame::~wxStfParentFrame() {
    // deinitialize the frame manager
#ifdef WITH_PYTHON
    // write visibility of the shell to config:
    bool shell_state = m_mgr.GetPane(wxT("pythonShell")).IsShown();
    wxGetApp().wxWriteProfileInt( wxT("Settings"),wxT("ViewShell"), int(shell_state) );
#endif
    m_mgr.UnInit();
}

wxStfToolBar* wxStfParentFrame::CreateStdTb() {
    wxStfToolBar* tb1=new wxStfToolBar( this, wxID_ANY, wxDefaultPosition, wxDefaultSize,
                                        wxAUI_TB_DEFAULT_STYLE );
    const wxSize iconSize = GetToolbarBitmapSize(*this);
    tb1->SetToolBitmapSize(iconSize);
    tb1->AddTool( wxID_OPEN,
                  wxT("Open"),
                  TbBitmap(*this, wxT("open"), wxART_FILE_OPEN),
                  wxT("Open file"),
                  wxITEM_NORMAL );
    tb1->AddTool( wxID_SAVEAS,
                  wxT("Save"),
                  TbBitmap(*this, wxT("save"), wxART_FILE_SAVE_AS),
                  wxT("Save traces"),
                  wxITEM_NORMAL );
    tb1->AddTool( ID_PRINT_PRINT,
                  wxT("Print"),
                  TbBitmap(*this, wxT("print"), wxART_PRINT),
                  wxT("Print traces"),
                  wxITEM_NORMAL );
#if PY_MAJOR_VERSION >= 3
    tb1->AddStretchSpacer(1);
    wxArrayString shellChoices;
    shellChoices.Add(wxT("Legacy"));
    shellChoices.Add(wxT("Modern"));
    shellChoices.Add(wxT("IPython"));
    m_shellBackendChoice = new wxChoice(tb1, ID_PY_SHELL_BACKEND, wxDefaultPosition, wxDefaultSize, shellChoices);
    int selectedShell = wxGetApp().wxGetProfileInt(wxT("Settings"), wxT("PyShellBackend"), 2);
    if (selectedShell < 0 || selectedShell > 2) {
        selectedShell = 2;
    }
    m_shellBackendChoice->SetSelection(selectedShell);
    tb1->AddControl(m_shellBackendChoice, wxT("Python shell backend"));
#endif
    return tb1;
}

wxStfToolBar* wxStfParentFrame::CreateScaleTb() {
    wxStfToolBar* scaleToolBar =
        new wxStfToolBar( this, wxID_ANY, wxDefaultPosition, wxDefaultSize, wxAUI_TB_DEFAULT_STYLE );
    scaleToolBar->SetToolBitmapSize(GetToolbarBitmapSize(*this));
    scaleToolBar->AddTool( ID_TOOL_FIRST,
                           wxT("First"),
                           TbBitmap(*this, wxT("first"), wxART_GOTO_FIRST),
                           wxT("Go to first trace"),
                           wxITEM_NORMAL );
    scaleToolBar->AddTool( ID_TOOL_PREVIOUS,
                           wxT("Prev."),
                           TbBitmap(*this, wxT("previous"), wxART_GO_BACK),
                           wxT("Go to previous trace (left cursor)"),
                           wxITEM_NORMAL );
    scaleToolBar->AddTool( ID_TOOL_NEXT,
                           wxT("Next"),
                           TbBitmap(*this, wxT("next"), wxART_GO_FORWARD),
                           wxT("Go to next trace (right cursor)"),
                           wxITEM_NORMAL );
    scaleToolBar->AddTool( ID_TOOL_LAST,
                           wxT("Last"),
                           TbBitmap(*this, wxT("last"), wxART_GOTO_LAST),
                           wxT("Go to last trace"),
                           wxITEM_NORMAL );
    scaleToolBar->AddSeparator();
    scaleToolBar->AddTool( ID_TOOL_LEFT,
                           wxT("Left"),
                           TbBitmap(*this, wxT("left"), wxART_GO_BACK),
                           wxT("Move traces left (CTRL+left cursor)"),
                           wxITEM_NORMAL );
    scaleToolBar->AddTool( ID_TOOL_RIGHT,
                           wxT("Right"),
                           TbBitmap(*this, wxT("right"), wxART_GO_FORWARD),
                           wxT("Move traces right (CTRL+right cursor)"),
                           wxITEM_NORMAL );
    scaleToolBar->AddTool( ID_TOOL_FIT,
                           wxT("Fit"),
                           TbBitmap(*this, wxT("fit"), wxART_GO_HOME),
                           wxT("Fit traces to window (\"F\")"),
                           wxITEM_NORMAL );
    scaleToolBar->AddTool( ID_TOOL_UP,
                           wxT("Up"),
                           TbBitmap(*this, wxT("up"), wxART_GO_UP),
                           wxT("Move traces up (up cursor)"),
                           wxITEM_NORMAL );
    scaleToolBar->AddTool( ID_TOOL_DOWN,
                           wxT("Down"),
                           TbBitmap(*this, wxT("down"), wxART_GO_DOWN),
                           wxT("Move traces down (down cursor)"),
                           wxITEM_NORMAL );
    scaleToolBar->AddTool( ID_TOOL_XENL,
                           wxT("Zoom X"),
                           TbBitmap(*this, wxT("zoom_in_x"), wxART_GO_UP),
                           wxT("Enlarge x-scale (CTRL + \"+\")"),
                           wxITEM_NORMAL );
    scaleToolBar->AddTool( ID_TOOL_XSHRINK,
                           wxT("Shrink X"),
                           TbBitmap(*this, wxT("zoom_out_x"), wxART_GO_DOWN),
                           wxT("Shrink x-scale (CTRL + \"-\")"),
                           wxITEM_NORMAL );
    scaleToolBar->AddTool( ID_TOOL_YENL,
                           wxT("Zoom Y"),
                           TbBitmap(*this, wxT("zoom_in_y"), wxART_GO_UP),
                           wxT("Enlarge y-scale (\"+\")"),
                           wxITEM_NORMAL );
    scaleToolBar->AddTool( ID_TOOL_YSHRINK,
                           wxT("Shrink Y"),
                           TbBitmap(*this, wxT("zoom_out_y"), wxART_GO_DOWN),
                           wxT("Shrink y-scale (\"-\")"),
                           wxITEM_NORMAL );
    scaleToolBar->AddSeparator();
    scaleToolBar->AddTool( ID_TOOL_CH1,
                           wxT("Ch 1"),
                           TbBitmap(*this, wxT("ch1"), wxART_INFORMATION),
                           wxT("Scaling applies to active (black) channel (\"1\")"),
                           wxITEM_CHECK );
    scaleToolBar->AddTool( ID_TOOL_CH2,
                           wxT("Ch 2"),
                           TbBitmap(*this, wxT("ch2"), wxART_HELP),
                           wxT("Scaling applies to reference (red) channel (\"2\")"),
                           wxITEM_CHECK );
    return scaleToolBar;
}

wxStfToolBar* wxStfParentFrame::CreateEditTb() {
    wxStfToolBar* tb4= new wxStfToolBar( this, wxID_ANY, wxDefaultPosition, wxDefaultSize,
                                         wxAUI_TB_DEFAULT_STYLE );
    tb4->SetToolBitmapSize(GetToolbarBitmapSize(*this));
    tb4->AddTool( ID_AVERAGE,
                  wxT("Mean"),
                  TbBitmap(*this, wxT("mean"), wxART_LIST_VIEW),
                  wxT("Average of selected traces"),
                  wxITEM_NORMAL );
    tb4->AddTool( ID_ALIGNEDAVERAGE,
                  wxT("Aligned"),
                  TbBitmap(*this, wxT("aligned"), wxART_TICK_MARK),
                  wxT("Aligned average of selected traces"),
                  wxITEM_NORMAL );
    tb4->AddTool( ID_TOOL_FITDECAY,
                  wxT("Fit"),
                  TbBitmap(*this, wxT("fitdecay"), wxART_FIND),
                  wxT("Fit function to data"),
                  wxITEM_NORMAL );
    tb4->AddTool( ID_VIEWTABLE,
                  wxT("Table"),
                  TbBitmap(*this, wxT("table"), wxART_REPORT_VIEW),
                  wxT("View current trace as a table"),
                  wxITEM_NORMAL );
    return tb4;
}

wxStfToolBar* wxStfParentFrame::CreateCursorTb() {
    wxStfToolBar* cursorToolBar = new wxStfToolBar( this, wxID_ANY, wxDefaultPosition, wxDefaultSize,
                                                    wxAUI_TB_DEFAULT_STYLE );
    cursorToolBar->SetToolBitmapSize(GetToolbarBitmapSize(*this));
    cursorToolBar->AddTool( ID_TOOL_SELECT,
                            wxT("Select"),
                            TbBitmap(*this, wxT("select"), wxART_TICK_MARK),
                            wxT("Select or unselect this trace (\"S\" / \"R\")"),
                            wxITEM_CHECK );
    // cursorToolBar->AddTool( ID_TOOL_REMOVE,
    //                         wxT("Unselect"),
    //                         wxBitmap( bin ),
    //                         wxT("Unselect this trace (\"R\")"),
    //                         wxITEM_NORMAL );
    cursorToolBar->AddSeparator();
    cursorToolBar->AddTool( ID_MPL,
                            wxT("Snapshot"),
                            TbBitmap(*this, wxT("snapshot"), wxART_FILE_SAVE),
                            wxT("Create snapshot with matplotlib"),
                            wxITEM_NORMAL );

    cursorToolBar->AddTool( ID_TOOL_SNAPSHOT_WMF,
                            wxT("WMF Snapshot"),
                            TbBitmap(*this, wxT("wmf_snapshot"), wxART_COPY),
                            wxT("Copy vectorized image to clipboard"),
                            wxITEM_NORMAL );

    cursorToolBar->AddSeparator();
    cursorToolBar->AddTool( ID_TOOL_MEASURE,
                            _T("Measure"),
                            TbBitmap(*this, wxT("measure"), wxART_CROSS_MARK),
                            wxT("Mouse selects measurement (crosshair) cursor (\"M\")"),
                            wxITEM_CHECK );
    cursorToolBar->AddTool( ID_TOOL_PEAK,
                            _T("Peak"),
                            TbBitmap(*this, wxT("peak"), wxART_GO_UP),
                            wxT("Mouse selects peak cursors (\"P\")"),
                            wxITEM_CHECK );
    cursorToolBar->AddTool( ID_TOOL_BASE,
                            _T("Base"),
                            TbBitmap(*this, wxT("base"), wxART_GO_DOWN),
                            wxT("Mouse selects base cursors (\"B\")"),
                            wxITEM_CHECK );
    cursorToolBar->AddTool( ID_TOOL_DECAY,
                            _T("Fit"),
                            TbBitmap(*this, wxT("decay"), wxART_FIND),
                            wxT("Mouse selects fit cursors (\"D\")"),
                            wxITEM_CHECK );
    cursorToolBar->AddTool( ID_TOOL_LATENCY,
                            _T("Latency"),
                            TbBitmap(*this, wxT("latency"), wxART_QUESTION),
                            wxT("Mouse selects latency cursors (\"L\")"),
                            wxITEM_CHECK );
#ifdef WITH_PSLOPE
    cursorToolBar->AddTool( ID_TOOL_PSLOPE,
                            _T("Slope"),
                            TbBitmap(*this, wxT("pslope"), wxART_GO_FORWARD),
                            wxT("Mouse selects slope cursors (\"O\")"),
                            wxITEM_CHECK );
#endif
    cursorToolBar->AddTool( ID_TOOL_ZOOM,
                            _T("Zoom"),
                            TbBitmap(*this, wxT("zoom"), wxART_FIND),
                            wxT("Draw a zoom window with left mouse button (\"Z\")"),
                            wxITEM_CHECK );
        cursorToolBar->AddTool( ID_TOOL_EVENT,
                                _T("Events"),
                                TbBitmap(*this, wxT("event"), wxART_WARNING),
                                wxT( "Add, erase or extract events manually with right mouse button (\"E\")" ),
                                wxITEM_CHECK );
        cursorToolBar->AddTool( ID_TOOL_ANNOTATION,
                                _T("Annotations"),
                                TbBitmap(*this, wxT("annotation"), wxART_INFORMATION),
                                wxT( "Add, remove, erase or export/import annotations manually with right mouse button (\"N\")" ),
                                wxITEM_CHECK );
    return cursorToolBar;
}

#if 0
#if defined(WITH_BIOSIG)
    #define CREDIT_BIOSIG "Biosig import using libbiosig http://biosig.sf.net\n\n"
#else 
    #define CREDIT_BIOSIG ""
#endif
#endif

void wxStfParentFrame::OnAbout(wxCommandEvent& WXUNUSED(event) )
{
	wxAboutDialogInfo info;
	info.SetName(wxT("Stimfit"));
	info.SetVersion(wxString(PACKAGE_VERSION, wxConvLocal));
	info.SetWebSite(wxT("http://www.stimfit.org"));
	wxString about = wxString(wxT("Credits:\n\nOriginal idea (Stimfit for DOS):\n\
    Peter Jonas, Physiology Department, University of Freiburg\n\n\
    Fourier transform:\nFFTW, http://www.fftw.org\n\n\
    Levenberg-Marquardt non-linear regression, version ") + wxString(wxT(LM_VERSION)) + wxT("\n\
    Manolis Lourakis, http://www.ics.forth.gr/~lourakis/levmar/ \n\n")) +

#if defined(WITH_BIOSIG)
    wxString( wxT("BioSig import using libbiosig\n") ) + 
    //+ wxString( wxT("version ") + wxT(BIOSIG_VERSION ) ) +
    wxString( wxT("http://biosig.sf.net\n\n") ) +
#endif

    wxString(wxT("Documentation:\n\
    Jose Guzman\n\n\
    Event detection algorithms:\n\
    Jonas, P., Major, G. & Sakmann B. (1993) J Physiol 472:615-63\n\
    Clements, J. D. & Bekkers, J. M. (1997) Biophys J 73:220-229\n\
    Pernía-Andrade,  A.J., et al., (2012) Biophys J 103:1429-39.\n\n\
    Thanks to Bill Anderson (www.winltp.com) for helpful suggestions"));
	info.SetDescription(about);
	info.SetCopyright(wxT("(C) 2001-2015 Christoph Schmidt-Hieber <christsc@gmx.de>\n\
    Christoph Schmidt-Hieber, University College London\n\
    Published under the GNU general public license (http://www.gnu.org/licenses/gpl.html)"));

	wxAboutBox(info);
}

void wxStfParentFrame::OnHelp(wxCommandEvent& WXUNUSED(event) )
{
    wxLaunchDefaultBrowser( wxT("http://www.stimfit.org/doc/sphinx/index.html") );
}

std::vector<int> ParseVersionString( const wxString& VersionString ) {
    std::vector<int> VersionInt(5);
    
    const char pt = '.';
    
    // Major version:
    long major=0;
    wxString sMajor = VersionString.BeforeFirst(pt);
    if ( sMajor.length() == VersionString.length() ) {
        major = 0;
    } else {
        sMajor.ToLong( &major );
    }
    VersionInt[0] = major;

    // Minor version:
    long minor=0;
    wxString sMinor1 = VersionString.AfterFirst(pt);
    if ( sMinor1.empty() ) {
        minor = 0;
    } else {
        wxString sMinor = sMinor1.BeforeFirst(pt);
        if ( sMinor1.length() == sMinor.length() ) {
            minor = 0;
        } else {
            sMinor.ToLong( &minor );
        }
    }
    VersionInt[1] = minor;

    // Build version:
    long build=0;
    wxString sBuild = VersionString.AfterLast(pt);
    if ( sBuild.empty() ) {
        build = 0;
    } else {
        sBuild.ToLong( &build );
    }
    VersionInt[2] = build;
    return VersionInt;
}

bool CompVersion( const std::vector<int>& version ) {
    // Get current version:
    wxString currentString(PACKAGE_VERSION, wxConvLocal);
    std::vector<int> current = ParseVersionString(currentString);
    if (version[0] > current[0]) {
        return true;
    } else {
        if (version[0] == current[0]) {
            if (version[1] > current[1]) {
                return true;
            } else {
                if (version[1] == current[1]) {
                    if (version[2] > current[2]) {
                        return true;
                    } else {
                        return false;
                    }
                } else {
                    // version[0] == current[0] && version[1] < current[1]
                    return false;
                }
            }
        } else {
            // version[0] < current[0]
            return false;
        }
    }
}

void wxStfParentFrame::CheckUpdate( wxProgressDialog* progDlg ) const {
    
#if defined (__MINGW32__)
    wxString address(wxT("/latest_mingw"));
#elif defined (_WINDOWS)
    wxString address(wxT("/latest_windows"));
#elif defined (__APPLE__)
    wxString address(wxT("/latest_mac"));
#else
    wxString address(wxT("/latest_linux"));
#endif
   
    wxHTTP http;
    http.SetHeader( wxT("Accept") , wxT("text/*") );
    http.SetHeader( wxT("User-Agent"), wxT("Mozilla") );
    http.SetTimeout( 1 ); // seconds

    // Note that Connect() wants a host address, not an URL. 80 is the server's port.
    wxString server( wxT("www.stimfit.org") );
    if( http.Connect(server) )  {
        if(wxInputStream* in_stream = http.GetInputStream (address)) {
            wxString verS;
            int c_int = in_stream->GetC();
            while ( c_int != wxEOF ) {
                if (progDlg != NULL) {
                    progDlg->Pulse( wxT("Reading version information...") );
                }
                verS << wxChar(c_int);
                c_int = in_stream->GetC();
            }
            wxDELETE(in_stream);
            std::vector<int> version = ParseVersionString( verS );
            if ( CompVersion(version) ) {
                wxString msg;
                msg << wxT("A newer version of Stimfit (")
                    << verS << wxT(") is available. ")
                    << wxT("Would you like to download it now?");
                wxMessageDialog newversion( NULL, msg, wxT("New version available"), wxYES_NO );
                if ( newversion.ShowModal() == wxID_YES ) {
                    wxLaunchDefaultBrowser( wxT("http://code.google.com/p/stimfit/downloads/list") );
                }
            } else {
                if (progDlg != NULL) {
                    wxMessageDialog newversion( NULL, wxT("You already have the newest version"), wxT("No new version available"), wxOK );
                    newversion.ShowModal();
                }
            }
        } else {
            if (progDlg != NULL) {
                wxGetApp().ErrorMsg( wxT("Couldn't retrieve update information. Are you connected to the internet?") );
            }
        }
    } else {
        if (progDlg != NULL) {
            wxGetApp().ErrorMsg( wxT("Couldn't connect to server. Are you connected to the internet?") );
        }
    }
}

void wxStfParentFrame::OnCheckUpdate(wxCommandEvent& WXUNUSED(event) )
{
    wxProgressDialog progDlg( wxT("Checking for updates"), wxT("Connecting to server..."),
                              100, NULL, wxPD_SMOOTH | wxPD_AUTO_HIDE );
    
    CheckUpdate( &progDlg );
}

void wxStfParentFrame::OnConvert(wxCommandEvent& WXUNUSED(event) ) {

    int nfiles; // files to convert
    wxString src_ext; // extension of the source file
    wxString dest_ext; // extesion of the destiny file

    // "Convert files" Dialog (see wxStfConvertDlg in smalldlgs.cpp)
    wxStfConvertDlg myDlg(this);
    if(myDlg.ShowModal() == wxID_OK) {

		stfio::filetype ift = myDlg.GetSrcFileExt();
		stfio::filetype eft = myDlg.GetDestFileExt();
        src_ext = myDlg.GetSrcFilter();

        // wxProgressDialog
        wxProgressDialog progDlg( wxT("CFS conversion utility"), wxT("Starting file conversion"),
            100, NULL, wxPD_SMOOTH | wxPD_AUTO_HIDE | wxPD_APP_MODAL );

        wxArrayString srcFilenames(myDlg.GetSrcFileNames());
        nfiles = srcFilenames.size(); // number of files to convert
        wxString myDestDir = myDlg.GetDestDir();

        for (std::size_t nFile=0; nFile<srcFilenames.size(); ++nFile) {
            wxString progStr;

            // Strip source directory from source file name:
            wxFileName srcWxFilename(srcFilenames[nFile]);
            srcWxFilename.MakeRelativeTo(myDlg.GetSrcDir());
            srcWxFilename.ClearExt();
            wxString destFilename(myDlg.GetDestDir() +
                                  wxFileName::GetPathSeparators(wxPATH_NATIVE) +
                                  srcWxFilename.GetFullPath() +
                                  stf::std2wx(stfio::findExtension(myDlg.GetDestFileExt())));

            wxString target_path = wxFileName(destFilename).GetPath();
            if (!wxFileName::DirExists(target_path)) {
                wxFileName::Mkdir(target_path, wxS_DIR_DEFAULT, wxPATH_MKDIR_FULL);
            }

            if ( eft == stfio::atf ) {
                destFilename += wxT(".atf");
            }

            // Update progress bar:
            progStr << wxT("Converting file #") << (int)nFile + 1
                << wxT(" of ") << (int)srcFilenames.size() << wxT("\n")
                << srcFilenames[nFile] << wxT(" -> ") << destFilename;
            progDlg.Update(
                (int)(((double)nFile/(double)srcFilenames.size())*100.0),
                progStr
                );

            // Open source file and convert:
            Recording sourceFile;
            try {

                stf::wxProgressInfo progDlgIn("Reading file", "Opening file", 100);
                stfio::importFile(stf::wx2std(srcFilenames[nFile]), ift, sourceFile, wxGetApp().GetTxtImport(), progDlgIn);

                stf::wxProgressInfo progDlgOut("Writing file", "Opening file", 100);
                switch ( eft ) {
                 case stfio::atf:
                     stfio::exportATFFile(stf::wx2std(destFilename), sourceFile);
                     dest_ext = wxT("deprecated: Axon textfile [*.atf] (will be disabled in future)");
                     break;
                 case stfio::igor:
                     stfio::exportIGORFile(stf::wx2std(destFilename), sourceFile, progDlgOut);
                     dest_ext = wxT("Igor binary file [*.ibw]");
                     break;

#if defined(WITH_BIOSIG)
                 case stfio::biosig:
                     stfio::exportBiosigFile(stf::wx2std(destFilename), sourceFile, progDlgOut);
                     dest_ext = wxT("Biosig/GDF [*.gdf]");
                     break;
#endif
                 default:
                     wxString errorMsg(wxT("Unknown export file type\n"));
                     wxGetApp().ErrorMsg(errorMsg);
                     return;
                }
            }
           catch (const std::runtime_error& e) {
                wxString errorMsg(wxT("Error opening file\n"));
                errorMsg += wxT("Runtime Error\n");
                errorMsg += wxString( e.what(), wxConvLocal );
                wxGetApp().ExceptMsg(errorMsg);
                return;
            }

            catch (const std::exception& e) {
                wxString errorMsg(wxT("Error opening file\n"));
                errorMsg += wxT("Exception\n");
                errorMsg += wxString( e.what(), wxConvLocal );
                wxGetApp().ExceptMsg(errorMsg);
                return;
            }
        }
    // Show now a smal information dialog
    //std::count << srcFilter.c_str() << std::endl;
    wxString msg;
    msg = wxString::Format(wxT("%i"), nfiles);
    msg << src_ext;
    msg << wxT(" files \nwere converted to ");
    msg << dest_ext;
	wxMessageDialog Simple(this, msg);
	Simple.ShowModal();
    } // end of wxStfConvertDlg

}

// Creates a graph. Called from view.cpp when a new drawing
// view is created.
wxStfGraph *wxStfParentFrame::CreateGraph(wxView *view, wxStfChildFrame *parent)
{
    int width=800, height=600;
    parent->GetClientSize(&width, &height);

    // Non-retained graph
    wxStfGraph *graph = new wxStfGraph(
        view,
        parent,
#ifndef __APPLE__
        wxPoint(0, 0),
#else
        wxDefaultPosition,
#endif
        wxSize(width, height),
        wxFULL_REPAINT_ON_RESIZE | wxWANTS_CHARS
        );

    return graph;
}


void wxStfParentFrame::OnPrint(wxCommandEvent& WXUNUSED(event))
{
    if (wxGetApp().GetActiveDoc()==NULL) return;

    wxPrintDialogData printDialogData(* m_printData);

    wxPrinter printer(& printDialogData);

    wxStfPreprintDlg myDlg(this);
    if (myDlg.ShowModal()!=wxID_OK) return;
    wxStfView* pView=wxGetApp().GetActiveView();
    pView->GetGraph()->set_downsampling(myDlg.GetDownSampling());
    pView->GetGraph()->set_noGimmicks(!myDlg.GetGimmicks());

    wxStfPrintout printout(_T("Trace printout"));

    if (!printer.Print(this, &printout, true /*prompt*/))
    {
        if (wxPrinter::GetLastError() == wxPRINTER_ERROR)
            wxMessageBox(
            _T("There was a problem printing.\nPerhaps your current printer is not set correctly?"),
            _T("Printing"),
            wxOK
            );
        else
            wxMessageBox(_T("You canceled printing"), _T("Printing"), wxOK);
    } else {
        (*m_printData) = printer.GetPrintDialogData().GetPrintData();
    }
}

void wxStfParentFrame::OnMpl(wxCommandEvent& WXUNUSED(event))
{
    if (wxGetApp().GetActiveDoc()==NULL) return;

#ifdef WITH_PYTHON
    std::ostringstream mgr_name;
    mgr_name << "mpl" << GetMplFigNo();
    wxWindow* pPython = MakePythonWindow("plotWindowMpl", mgr_name.str(), "Matplotlib", true, false, true, 800, 600).cppWindow;
    
    if ( pPython == 0 ) 
#endif
        wxGetApp().ErrorMsg(wxT("Can not create figure (python/matplotlib is not available)"));
}

void wxStfParentFrame::OnMplSpectrum(wxCommandEvent& WXUNUSED(event))
{
    if (wxGetApp().GetActiveDoc()==NULL) return;

#ifdef WITH_PYTHON
    std::ostringstream mgr_name;
    mgr_name << "mpl" << GetMplFigNo();
    wxWindow* pPython = MakePythonWindow("spectrumWindowMpl", mgr_name.str(), "Matplotlib", true, false, true, 800, 600).cppWindow;
    
    if ( pPython == 0 ) 
#endif
        wxGetApp().ErrorMsg(wxT("Can not create figure (python/matplotlib is not available)"));
}

void wxStfParentFrame::OnPageSetup(wxCommandEvent& WXUNUSED(event))
{
    (*m_pageSetupData) = *m_printData;

    wxPageSetupDialog pageSetupDialog(this, m_pageSetupData.get());
    pageSetupDialog.ShowModal();

    (*m_printData) = pageSetupDialog.GetPageSetupDialogData().GetPrintData();
    (*m_pageSetupData) = pageSetupDialog.GetPageSetupDialogData();
}

void wxStfParentFrame::OnToggleSelect(wxCommandEvent& WXUNUSED(event)) {
    wxStfDoc* pDoc=wxGetApp().GetActiveDoc();
    if (pDoc!=NULL) {
        pDoc->ToggleSelect();
    }
}

void wxStfParentFrame::OnToolFirst(wxCommandEvent& WXUNUSED(event)) {
    wxStfView* pView=wxGetApp().GetActiveView();
    if (pView!=NULL) {
        pView->GetGraph()->OnFirst();
    }
}

void wxStfParentFrame::OnToolNext(wxCommandEvent& WXUNUSED(event)) {
    wxStfView* pView=wxGetApp().GetActiveView();
    if (pView!=NULL) {
        pView->GetGraph()->OnNext();
    }
}

void wxStfParentFrame::OnToolPrevious(wxCommandEvent& WXUNUSED(event)) {
    wxStfView* pView=wxGetApp().GetActiveView();
    if (pView!=NULL) {
        pView->GetGraph()->OnPrevious();
    }
}

void wxStfParentFrame::OnToolLast(wxCommandEvent& WXUNUSED(event)) {
    wxStfView* pView=wxGetApp().GetActiveView();
    if (pView!=NULL) {
        pView->GetGraph()->OnLast();
    }
}

void wxStfParentFrame::OnToolXenl(wxCommandEvent& WXUNUSED(event)) {
    wxStfView* pView=wxGetApp().GetActiveView();
    if (pView!=NULL) {
        pView->GetGraph()->OnXenllo();
    }
}

void wxStfParentFrame::OnToolXshrink(wxCommandEvent& WXUNUSED(event)) {
    wxStfView* pView=wxGetApp().GetActiveView();
    if (pView!=NULL) {
        pView->GetGraph()->OnXshrinklo();
    }
}

void wxStfParentFrame::OnToolYenl(wxCommandEvent& WXUNUSED(event)) {
    wxStfView* pView=wxGetApp().GetActiveView();
    if (pView!=NULL) {
        pView->GetGraph()->OnYenllo();
    }
}

void wxStfParentFrame::OnToolYshrink(wxCommandEvent& WXUNUSED(event)) {
    wxStfView* pView=wxGetApp().GetActiveView();
    if (pView!=NULL) {
        pView->GetGraph()->OnYshrinklo();
    }
}

void wxStfParentFrame::OnToolUp(wxCommandEvent& WXUNUSED(event)) {
    wxStfView* pView=wxGetApp().GetActiveView();
    if (pView!=NULL) {
        pView->GetGraph()->OnUp();
    }
}

void wxStfParentFrame::OnToolDown(wxCommandEvent& WXUNUSED(event)) {
    wxStfView* pView=wxGetApp().GetActiveView();
    if (pView!=NULL) {
        pView->GetGraph()->OnDown();
    }
}

void wxStfParentFrame::OnToolFit(wxCommandEvent& WXUNUSED(event)) {
    wxStfView* pView=wxGetApp().GetActiveView();
    if (pView!=NULL) {
        pView->GetGraph()->Fittowindow(true);
    }
}

void wxStfParentFrame::OnToolLeft(wxCommandEvent& WXUNUSED(event)) {
    wxStfView* pView=wxGetApp().GetActiveView();
    if (pView!=NULL) {
        pView->GetGraph()->OnLeft();
    }
}

void wxStfParentFrame::OnToolRight(wxCommandEvent& WXUNUSED(event)) {
    wxStfView* pView=wxGetApp().GetActiveView();
    if (pView!=NULL) {
        pView->GetGraph()->OnRight();
    }
}

void wxStfParentFrame::OnToolCh1(wxCommandEvent& WXUNUSED(event)) {
    // activate channel 1 if no channel is active:
    if (!m_scaleToolBar->GetToolToggled(ID_TOOL_CH1) &&
        !m_scaleToolBar->GetToolToggled(ID_TOOL_CH2)) {
            m_scaleToolBar->ToggleTool(ID_TOOL_CH1,true);
    }
    m_scaleToolBar->Refresh();
    
}

void wxStfParentFrame::OnToolCh2(wxCommandEvent& WXUNUSED(event)) {
    // activate channel 1 if no channel is active:
    if (!m_scaleToolBar->GetToolToggled(ID_TOOL_CH1) &&
        !m_scaleToolBar->GetToolToggled(ID_TOOL_CH2)) {
            m_scaleToolBar->ToggleTool(ID_TOOL_CH1,true);
    }
    m_scaleToolBar->Refresh();
}

void wxStfParentFrame::OnToolFitdecay(wxCommandEvent& toolEvent) {
    wxStfDoc* pDoc=wxGetApp().GetActiveDoc();
    if (pDoc!=NULL) {
        pDoc->FitDecay(toolEvent);
    }
}

void wxStfParentFrame::SetSingleChannel(bool value) {
    if (!m_scaleToolBar) return;
    if (value) {
        if (!m_scaleToolBar->GetToolEnabled(ID_TOOL_CH1))
            m_scaleToolBar->EnableTool(ID_TOOL_CH1,true);
        if (m_scaleToolBar->GetToolEnabled(ID_TOOL_CH2))
            m_scaleToolBar->EnableTool(ID_TOOL_CH2,false);
    } else {
        if (!m_scaleToolBar->GetToolEnabled(ID_TOOL_CH1))
            m_scaleToolBar->EnableTool(ID_TOOL_CH1,true);
        if (!m_scaleToolBar->GetToolEnabled(ID_TOOL_CH2))
            m_scaleToolBar->EnableTool(ID_TOOL_CH2,true);
    }

    // Make sure at least one value is selected:
    if (!m_scaleToolBar->GetToolToggled(ID_TOOL_CH1) &&
        (value || !m_scaleToolBar->GetToolToggled(ID_TOOL_CH2))) {
        m_scaleToolBar->ToggleTool(ID_TOOL_CH1, true);
    }
    m_scaleToolBar->Refresh();
}

void wxStfParentFrame::OnToolSnapshotwmf(wxCommandEvent& WXUNUSED(event)) {
    wxStfView* pView=wxGetApp().GetActiveView();
    if (pView!=NULL) {
        pView->GetGraph()->Snapshotwmf();
    }
}

void wxStfParentFrame::OnToolMeasure(wxCommandEvent& WXUNUSED(event)) {
    SetMouseQual( stf::measure_cursor );
}

void wxStfParentFrame::OnToolPeak(wxCommandEvent& WXUNUSED(event)) {
    SetMouseQual( stf::peak_cursor );
}

void wxStfParentFrame::OnToolBase(wxCommandEvent& WXUNUSED(event)) {
    SetMouseQual( stf::base_cursor );
}

void wxStfParentFrame::OnToolDecay(wxCommandEvent& WXUNUSED(event)) {
    SetMouseQual( stf::decay_cursor );
}

#ifdef WITH_PSLOPE
void wxStfParentFrame::OnToolPSlope(wxCommandEvent& WXUNUSED(event)) {
    SetMouseQual( stf::pslope_cursor );
}
#endif

void wxStfParentFrame::OnToolLatency(wxCommandEvent& WXUNUSED(event)) {
    SetMouseQual( stf::latency_cursor );
}

void wxStfParentFrame::OnToolZoom(wxCommandEvent& WXUNUSED(event)) {
    SetMouseQual( stf::zoom_cursor );
}

void wxStfParentFrame::OnToolEvent(wxCommandEvent& WXUNUSED(event)) {
    SetMouseQual( stf::event_cursor );
}

void wxStfParentFrame::OnToolAnnotation(wxCommandEvent& WXUNUSED(event)) {
    SetMouseQual( stf::annotation_cursor );
}

void wxStfParentFrame::OnCh2zoom(wxCommandEvent& WXUNUSED(event)) {
    wxStfView* pView=wxGetApp().GetActiveView();
    if (pView!=NULL) {
        pView->GetGraph()->Ch2zoom();
    }
}

void wxStfParentFrame::OnCh2base(wxCommandEvent& WXUNUSED(event)) {
    wxStfView* pView=wxGetApp().GetActiveView();
    if (pView!=NULL) {
        pView->GetGraph()->Ch2base();
    }
}

void wxStfParentFrame::OnCh2pos(wxCommandEvent& WXUNUSED(event)) {
    wxStfView* pView=wxGetApp().GetActiveView();
    if (pView!=NULL) {
        pView->GetGraph()->Ch2pos();
    }
}

void wxStfParentFrame::OnCh2basezoom(wxCommandEvent& WXUNUSED(event)) {
    wxStfView* pView=wxGetApp().GetActiveView();
    if (pView!=NULL) {
        pView->GetGraph()->Ch2basezoom();
    }
}

void wxStfParentFrame::OnViewResults(wxCommandEvent& WXUNUSED(event)) {
    wxStfChildFrame* pChild=(wxStfChildFrame*)GetActiveChild();
    if (pChild!=NULL) {
        pChild->GetCopyGrid()->ViewResults();
    }
}

void wxStfParentFrame::OnScale(wxCommandEvent& WXUNUSED(event)) {
    wxStfView* pView=wxGetApp().GetActiveView();
    if (pView!=NULL) {
        if (GetActiveChild()->GetMenuBar() && GetActiveChild()->GetMenuBar()->GetMenu(2)->IsChecked(ID_SCALE)) {
            wxGetApp().wxWriteProfileInt(wxT("Settings"),wxT("ViewScaleBars"),1);
            wxGetApp().set_isBars(true);
        } else {
            wxGetApp().wxWriteProfileInt(wxT("Settings"),wxT("ViewScaleBars"),0);
            wxGetApp().set_isBars(false);
        }
        if (pView->GetGraph() != NULL)
            pView->GetGraph()->Refresh();
    }
}

void wxStfParentFrame::OnDarkTraceDisplay(wxCommandEvent& WXUNUSED(event)) {
    wxStfView* pView = wxGetApp().GetActiveView();
    if (pView != NULL) {
        const bool useDarkTraceDisplay =
            GetActiveChild()->GetMenuBar() &&
            GetActiveChild()->GetMenuBar()->GetMenu(2)->IsChecked(ID_VIEW_DARK_TRACE);

        wxGetApp().wxWriteProfileInt(
            wxT("Settings"),
            wxT("ViewDarkTraceDisplay"),
            useDarkTraceDisplay ? 1 : 0
        );
        wxGetApp().set_isDarkTraceDisplay(useDarkTraceDisplay);

        if (pView->GetGraph() != NULL) {
            pView->GetGraph()->ApplyTraceDisplayTheme(useDarkTraceDisplay);
            pView->GetGraph()->Refresh();
        }
    }
}

void wxStfParentFrame::OnAverage(wxCommandEvent& WXUNUSED(event)) {
    wxStfDoc* pDoc=wxGetApp().GetActiveDoc();
    if (pDoc!=NULL) {
        pDoc->CreateAverage(false,false);
    }
}

void wxStfParentFrame::OnAlignedAverage(wxCommandEvent& WXUNUSED(event)) {
    wxStfDoc* pDoc=wxGetApp().GetActiveDoc();
    if (pDoc!=NULL) {
        pDoc->CreateAverage(false,true);
    }
}

#if 0
void wxStfParentFrame::OnUserdef(wxCommandEvent& event) {
    wxStfDoc* pDoc=wxGetApp().GetActiveDoc();
    if (pDoc!=NULL) {
        pDoc->Userdef(event.GetId()-ID_USERDEF1);
    }
}
#endif

void wxStfParentFrame::OnSaveperspective(wxCommandEvent& WXUNUSED(event)) {
    wxStfChildFrame* pChild=(wxStfChildFrame*)GetActiveChild();
    if (pChild!=NULL) {
        pChild->Saveperspective();
    }
}

void wxStfParentFrame::OnLoadperspective(wxCommandEvent& WXUNUSED(event)) {
    wxStfChildFrame* pChild=(wxStfChildFrame*)GetActiveChild();
    if (pChild!=NULL) {
        pChild->Loadperspective();
    }
}

void wxStfParentFrame::OnRestoreperspective(wxCommandEvent& WXUNUSED(event)) {
    wxStfChildFrame* pChild=(wxStfChildFrame*)GetActiveChild();
    if (pChild!=NULL) {
        pChild->Restoreperspective();
    }
}

#ifdef WITH_PYTHON
void wxStfParentFrame::OnViewshell(wxCommandEvent& WXUNUSED(event)) {
    // Save the current visibility state:
    bool old_state = m_mgr.GetPane(wxT("pythonShell")).IsShown();
    // Toggle python shell visibility:
    m_mgr.GetPane(wxT("pythonShell")).Show( !old_state );
    wxGetApp().wxWriteProfileInt( wxT("Settings"),wxT("ViewShell"), int(!old_state) );
    m_mgr.Update();
}

void wxStfParentFrame::OnShellBackendChoice(wxCommandEvent& WXUNUSED(event)) {
    if (m_shellBackendChoice == NULL) {
        return;
    }

    const int selection = m_shellBackendChoice->GetSelection();
    if (selection == wxNOT_FOUND) {
        return;
    }

    wxString backend = wxT("ipython");
    if (selection == 0) {
        backend = wxT("legacy");
    } else if (selection == 1) {
        backend = wxT("modern");
    }

    wxGetApp().wxWriteProfileInt(wxT("Settings"), wxT("PyShellBackend"), selection);
    SelectEmbeddedShellBackend(backend);
}

void wxStfParentFrame::RedirectStdio()
{
    // This is a helpful little tidbit to help debugging and such.  It
    // redirects Python's stdout and stderr to a window that will popup
    // only on demand when something is printed, like a traceback.

    wxString python_redirect;
    python_redirect = wxT("import sys, wx\n");
    python_redirect << wxT("output = wx.PyOnDemandOutputWindow()\n");
    python_redirect << wxT("sys.stdin = sys.stderr = output\n");
    python_redirect << wxT("del sys, wx\n");

    wxPyBlock_t blocked = wxPyBeginBlockThreads();
#if ((wxCHECK_VERSION(2, 9, 0) || defined(MODULE_ONLY)) && !defined(__WXMAC__))
    PyRun_SimpleString(python_redirect);
#else
    PyRun_SimpleString(python_redirect.char_str());
#endif

    wxPyEndBlockThreads(blocked);
}

bool wxStfParentFrame::SelectEmbeddedShellBackend(const wxString& backend)
{
#if PY_MAJOR_VERSION >= 3
    wxPyBlock_t blocked = wxPyBeginBlockThreads();

    wxString python_cmd;
    python_cmd << wxT("import stimfit_shell_api\n");
    python_cmd << wxT("stimfit_shell_api.set_shell_backend('") << backend << wxT("')\n");

#if ((wxCHECK_VERSION(2, 9, 0) || defined(MODULE_ONLY)) && !defined(__WXMAC__))
    int status = PyRun_SimpleString(python_cmd);
#else
    int status = PyRun_SimpleString(python_cmd.char_str());
#endif

    wxPyEndBlockThreads(blocked);
    return status == 0;
#else
    (void)backend;
    return false;
#endif
}

new_wxwindow wxStfParentFrame::MakePythonWindow(const std::string& windowFunc, const std::string& mgr_name, const std::string& caption, bool show,
                                                bool full, bool isfloat, int width, int height, double mpl_width, double mpl_height)
{
    // More complex embedded situations will require passing C++ objects to
    // Python and/or returning objects from Python to be used in C++.  This
    // sample shows one way to do it.  NOTE: The above code could just have
    // easily come from a file, or the whole thing could be in the Python
    // module that is imported and manipulated directly in this C++ code.  See
    // the Python API for more details.

    wxWindow* window = NULL;
    PyObject* result;

    // As always, first grab the GIL
    wxPyBlock_t blocked = wxPyBeginBlockThreads();

    RedirectStdio();

    // Now make a dictionary to serve as the global namespace when the code is
    // executed.  Put a reference to the builtins module in it.  (Yes, the
    // names are supposed to be different, I don't know why...)
    PyObject* globals = PyDict_New();
    PyObject* arg = NULL;
    PyObject* py_mpl_width = NULL;
    PyObject* py_mpl_height = NULL;
    PyObject* figsize = NULL;
    PyObject* argtuple = NULL;
#if PY_MAJOR_VERSION >= 3
    PyObject* builtins = PyImport_ImportModule("builtins");
#else
    PyObject* builtins = PyImport_ImportModule("__builtin__");
#endif
    PyDict_SetItemString(globals, "__builtins__", builtins);
    Py_DECREF(builtins);

    // Execute the code to make the makeWindow function
    result = PyRun_String(python_code2.c_str(), Py_file_input, globals, globals);
    // Was there an exception?
    if (!result) {
        PyErr_Print();
        wxGetApp().ErrorMsg(wxT("Couldn't initialize python shell"));
        Py_DECREF(globals);
        wxPyEndBlockThreads(blocked);
        return NULL;
    }
    Py_DECREF(result);

    // Now there should be an object named 'makeWindow' in the dictionary that
    // we can grab a pointer to:
    PyObject* func = NULL;
    func = PyDict_GetItemString(globals, windowFunc.c_str());
    if (!PyCallable_Check(func)) {
        PyErr_Print();
        wxGetApp().ErrorMsg(wxT("Couldn't initialize window for the python shell"));
        Py_DECREF(globals);
        wxPyEndBlockThreads(blocked);
        return NULL;
    }

    // Now build an argument tuple and call the Python function.  Notice the
    // use of another wxPython API to take a wxWindows object and build a
    // wxPython object that wraps it.
    arg = wxPyMake_wxObject(this, false);
    wxASSERT(arg != NULL);
    py_mpl_width = PyFloat_FromDouble(mpl_width);
    wxASSERT(py_mpl_width != NULL);
    py_mpl_height = PyFloat_FromDouble(mpl_height);
    wxASSERT(py_mpl_height != NULL);
    figsize = PyTuple_New(2);
    PyTuple_SET_ITEM(figsize, 0, py_mpl_width);
    PyTuple_SET_ITEM(figsize, 1, py_mpl_height);
    argtuple = PyTuple_New(2);
    PyTuple_SET_ITEM(argtuple, 0, arg);
    PyTuple_SET_ITEM(argtuple, 1, figsize);
    arg = NULL;
    py_mpl_width = NULL;
    py_mpl_height = NULL;
    figsize = NULL;
    result = PyObject_CallObject(func, argtuple);
    Py_DECREF(argtuple);
    argtuple = NULL;

    // Was there an exception?
    if (!result) {
        PyErr_Print();
        wxGetApp().ErrorMsg(wxT("Couldn't create window for the python shell"));
        Py_DECREF(globals);
        wxPyEndBlockThreads(blocked);
        return NULL;
    }
    else {
        // Otherwise, get the returned window out of Python-land and
        // into C++-ville...
#if PY_MAJOR_VERSION >= 3
        if (!wxPyConvertWrappedPtr(result, (void**)&window, _T("wxWindow"))) {
#else
        if (!wxPyConvertSwigPtr(result, (void**)&window, _T("wxWindow"))) {
#endif
            PyErr_Print();
            wxGetApp().ErrorMsg(wxT("Returned object was not a wxWindow!"));
            Py_DECREF(result);
            Py_DECREF(globals);
            wxPyEndBlockThreads(blocked);
            return NULL;
        }
        Py_DECREF(result);
    }

    // Release the python objects we still have
    Py_DECREF(globals);

    // Finally, after all Python stuff is done, release the GIL
    wxPyEndBlockThreads(blocked);

    if (!full) {
        if (isfloat) {
            m_mgr.AddPane(window, wxAuiPaneInfo().Name(stf::std2wx(mgr_name)).
                          CloseButton(true).
                          Show(show).Caption(stf::std2wx(caption)).Float().
                          BestSize(width, height));
        } else {
            m_mgr.AddPane(window, wxAuiPaneInfo().Name(stf::std2wx(mgr_name)).
                          CloseButton(true).
                          Show(show).Caption(stf::std2wx(caption)).Dockable(true).Bottom().
                          BestSize(width, height));
        }
    } else {
        m_mgr.AddPane(window, wxAuiPaneInfo().Name(stf::std2wx(mgr_name)).
                      Floatable(false).CaptionVisible(false).
                      BestSize(GetClientSize().GetWidth(), GetClientSize().GetHeight()).Fixed());
    }
    m_mgr.Update();

    return new_wxwindow(window, result);
}
#endif

void wxStfParentFrame::OnLStartMaxslope(wxCommandEvent& WXUNUSED(event)) {
    wxStfView* pView=wxGetApp().GetActiveView();
    wxStfDoc* pDoc=wxGetApp().GetActiveDoc();
    if (pView!=NULL && pDoc!=NULL) {
        // get previous mode:
        //		bool prevMode=pDoc->GetLatencyStartMode()==stfio::riseMode;
        // toggle on if it wasn't the previous mode:
        //		if (!prevMode) {
        pDoc->SetLatencyStartMode(stf::riseMode);
        wxGetApp().wxWriteProfileInt(wxT("Settings"),
                                     wxT("LatencyStartMode"),
                                     pDoc->GetLatencyStartMode());
        if (pView->GetGraph()!=NULL)
            pView->GetGraph()->Refresh();
    }
}

void wxStfParentFrame::OnLStartHalfrise(wxCommandEvent& WXUNUSED(event)) {
    wxStfView* pView=wxGetApp().GetActiveView();
    wxStfDoc* pDoc=wxGetApp().GetActiveDoc();
    if (pView!=NULL && pDoc!=NULL) {
        pDoc->SetLatencyStartMode(stf::halfMode);
        wxGetApp().wxWriteProfileInt(
                                     wxT("Settings"),
                                     wxT("LatencyStartMode"),
                                     pDoc->GetLatencyStartMode()
                                     );
        if (pView->GetGraph()!=NULL)
            pView->GetGraph()->Refresh();
    }

}

void wxStfParentFrame::OnLStartPeak(wxCommandEvent& WXUNUSED(event)) {
    wxStfView* pView=wxGetApp().GetActiveView();
    wxStfDoc* pDoc=wxGetApp().GetActiveDoc();
    if (pView!=NULL && pDoc!=NULL) {
        pDoc->SetLatencyStartMode(stf::peakMode);
        wxGetApp().wxWriteProfileInt( wxT("Settings"), wxT("LatencyStartMode"), pDoc->GetLatencyStartMode() );
        if (pView->GetGraph()!=NULL)
            pView->GetGraph()->Refresh();
    }
}

void wxStfParentFrame::OnLStartManual(wxCommandEvent& WXUNUSED(event)) {
    wxStfView* pView=wxGetApp().GetActiveView();
    wxStfDoc* pDoc=wxGetApp().GetActiveDoc();
    if (pView!=NULL && pDoc!=NULL) {
        // Always keep manual mode as a default, even if attempted to uncheck:
        pDoc->SetLatencyStartMode(stf::manualMode);
        wxGetApp().wxWriteProfileInt(
            wxT("Settings"),
            wxT("LatencyStartMode"),
            pDoc->GetLatencyStartMode()
            );
        if (pView->GetGraph()!=NULL)
            pView->GetGraph()->Refresh();
    }
}

void wxStfParentFrame::OnLEndFoot(wxCommandEvent& WXUNUSED(event)) {
    wxStfView* pView=wxGetApp().GetActiveView();
    wxStfDoc* pDoc=wxGetApp().GetActiveDoc();
    if (pView!=NULL && pDoc!=NULL) {
        pDoc->SetLatencyEndMode(stf::footMode);
	wxGetApp().wxWriteProfileInt(
                                     wxT("Settings"),
                                     wxT("LatencyEndMode"),
                                     pDoc->GetLatencyEndMode()
                                     );
        if (pView->GetGraph()!=NULL)
            pView->GetGraph()->Refresh();
    }
}

void wxStfParentFrame::OnLEndMaxslope(wxCommandEvent& WXUNUSED(event)) {
    wxStfView* pView=wxGetApp().GetActiveView();
    wxStfDoc* pDoc=wxGetApp().GetActiveDoc();
    if (pView!=NULL && pDoc!=NULL) {
        pDoc->SetLatencyEndMode(stf::riseMode);
        wxGetApp().wxWriteProfileInt(
                                     wxT("Settings"),
                                     wxT("LatencyEndMode"),
                                     pDoc->GetLatencyEndMode()
                                     );
        if (pView->GetGraph()!=NULL)
            pView->GetGraph()->Refresh();
    }
}

void wxStfParentFrame::OnLEndHalfrise(wxCommandEvent& WXUNUSED(event)) {
    wxStfView* pView=wxGetApp().GetActiveView();
    wxStfDoc* pDoc=wxGetApp().GetActiveDoc();
    if (pView!=NULL && pDoc!=NULL) {
        pDoc->SetLatencyEndMode(stf::halfMode);
        wxGetApp().wxWriteProfileInt( wxT("Settings"), wxT("LatencyEndMode"), pDoc->GetLatencyEndMode() );
        if (pView->GetGraph()!=NULL)
            pView->GetGraph()->Refresh();
    }
}

void wxStfParentFrame::OnLEndPeak(wxCommandEvent& WXUNUSED(event)) {
    wxStfView* pView=wxGetApp().GetActiveView();
    wxStfDoc* pDoc=wxGetApp().GetActiveDoc();
    if (pView!=NULL && pDoc!=NULL) {
        pDoc->SetLatencyEndMode(stf::peakMode);
        wxGetApp().wxWriteProfileInt( wxT("Settings"), wxT("LatencyEndMode"), pDoc->GetLatencyEndMode() );
        if (pView->GetGraph()!=NULL)
            pView->GetGraph()->Refresh();
    }

}

void wxStfParentFrame::OnLEndManual(wxCommandEvent& WXUNUSED(event)) {
    wxStfView* pView=wxGetApp().GetActiveView();
    wxStfDoc* pDoc=wxGetApp().GetActiveDoc();
    if (pView!=NULL && pDoc!=NULL) {
        pDoc->SetLatencyEndMode(stf::manualMode);
        wxGetApp().wxWriteProfileInt( wxT("Settings"), wxT("LatencyEndMode"), pDoc->GetLatencyEndMode() );
        if (pView->GetGraph()!=NULL)
            pView->GetGraph()->Refresh();
    }

}
# if 0
void wxStfParentFrame::OnLWindow(wxCommandEvent& WXUNUSED(event)) {
    wxStfView* pView=wxGetApp().GetActiveView();
    wxStfDoc* pDoc=wxGetApp().GetActiveDoc();
    if (pView!=NULL) {
        // Select
        if (GetActiveChild()->GetMenuBar() && GetActiveChild()->GetMenuBar()->GetMenu(1)->IsChecked(ID_LATENCYWINDOW)) {
            wxGetApp().wxWriteProfileInt( wxT("Settings"), wxT("LatencyWindowMode"), stf::windowMode );
            pDoc->SetLatencyWindowMode(stf::windowMode);
        } else {
            wxGetApp().wxWriteProfileInt( wxT("Settings"), wxT("LatencyWindowMode"), stf::defaultMode );
            pDoc->SetLatencyWindowMode(stf::defaultMode);
        }
        if (pView->GetGraph()!=NULL)
            pView->GetGraph()->Refresh();
    }
}

#endif
stf::cursor_type wxStfParentFrame::GetMouseQual() const {
    if (m_cursorToolBar->GetToolToggled(ID_TOOL_MEASURE))
        return stf::measure_cursor;
    if (m_cursorToolBar->GetToolToggled(ID_TOOL_PEAK))
        return stf::peak_cursor;
    if (m_cursorToolBar->GetToolToggled(ID_TOOL_BASE))
        return stf::base_cursor;
    if (m_cursorToolBar->GetToolToggled(ID_TOOL_DECAY))
        return stf::decay_cursor;
    if (m_cursorToolBar->GetToolToggled(ID_TOOL_LATENCY))
        return stf::latency_cursor;
    if (m_cursorToolBar->GetToolToggled(ID_TOOL_ZOOM))
        return stf::zoom_cursor;
    if (m_cursorToolBar->GetToolToggled(ID_TOOL_EVENT))
        return stf::event_cursor;
    if (m_cursorToolBar->GetToolToggled(ID_TOOL_ANNOTATION))
        return stf::annotation_cursor;
#ifdef WITH_PSLOPE
    if (m_cursorToolBar->GetToolToggled(ID_TOOL_PSLOPE))
        return stf::pslope_cursor;
#endif
    return stf::undefined_cursor;
}

void wxStfParentFrame::SetMouseQual(stf::cursor_type value) {

    if (m_cursorToolBar == NULL)
        return;

    // Need to set everything to false explicitly first:
    m_cursorToolBar->ToggleTool(ID_TOOL_MEASURE,false);
    m_cursorToolBar->ToggleTool(ID_TOOL_PEAK,false);
    m_cursorToolBar->ToggleTool(ID_TOOL_BASE,false);
    m_cursorToolBar->ToggleTool(ID_TOOL_DECAY,false);
    m_cursorToolBar->ToggleTool(ID_TOOL_LATENCY,false);
    m_cursorToolBar->ToggleTool(ID_TOOL_ZOOM,false);
    m_cursorToolBar->ToggleTool(ID_TOOL_EVENT,false);
    m_cursorToolBar->ToggleTool(ID_TOOL_ANNOTATION,false);
#ifdef WITH_PSLOPE
    m_cursorToolBar->ToggleTool(ID_TOOL_PSLOPE,false);
#endif

    // Then set the state of the selected button:
    if (value==stf::measure_cursor)
        m_cursorToolBar->ToggleTool(ID_TOOL_MEASURE,true);
    if (value==stf::peak_cursor)
        m_cursorToolBar->ToggleTool(ID_TOOL_PEAK,true);
    if (value==stf::base_cursor)
        m_cursorToolBar->ToggleTool(ID_TOOL_BASE,true);
    if (value==stf::decay_cursor)
        m_cursorToolBar->ToggleTool(ID_TOOL_DECAY,true);
    if (value==stf::latency_cursor)
        m_cursorToolBar->ToggleTool(ID_TOOL_LATENCY,true);
#ifdef WITH_PSLOPE
    if (value==stf::pslope_cursor)
        m_cursorToolBar->ToggleTool(ID_TOOL_PSLOPE,true);
#endif
    if (value==stf::zoom_cursor)
        m_cursorToolBar->ToggleTool(ID_TOOL_ZOOM,true);
    if (value==stf::event_cursor)
        m_cursorToolBar->ToggleTool(ID_TOOL_EVENT,true);
    if (value == stf::annotation_cursor)
        m_cursorToolBar->ToggleTool(ID_TOOL_ANNOTATION, true);
    m_cursorToolBar->Refresh();
}

void wxStfParentFrame::SetSelectedButton(bool selected) {
    if (m_cursorToolBar==NULL)
        return;

    m_cursorToolBar->ToggleTool(ID_TOOL_SELECT, selected);
    m_cursorToolBar->Refresh();
}

stf::zoom_channels wxStfParentFrame::GetZoomQual() const {
    if (m_scaleToolBar->GetToolToggled(ID_TOOL_CH1)) {
        if (m_scaleToolBar->GetToolToggled(ID_TOOL_CH2)) {
            return stf::zoomboth;
        } else {
            return stf::zoomch1;
        }
    }
    return stf::zoomch2;
}

void wxStfParentFrame::SetZoomQual(stf::zoom_channels value) {
    if (m_scaleToolBar==NULL)
        return;

    if (value==stf::zoomch1) {
        m_scaleToolBar->ToggleTool(ID_TOOL_CH1,true);
        m_scaleToolBar->ToggleTool(ID_TOOL_CH2,false);
    }
    if (value==stf::zoomch2) {
        m_scaleToolBar->ToggleTool(ID_TOOL_CH1,false);
        m_scaleToolBar->ToggleTool(ID_TOOL_CH2,true);
    }
    if (value==stf::zoomboth) {
        m_scaleToolBar->ToggleTool(ID_TOOL_CH1,true);
        m_scaleToolBar->ToggleTool(ID_TOOL_CH2,true);
    }
    m_scaleToolBar->Refresh();
}
