diff --git a/source/tools/atlas/AtlasUI/ErrorReporter/ErrorReporter.cpp b/source/tools/atlas/AtlasUI/ErrorReporter/ErrorReporter.cpp index 9392b0cdee..b8bcc13427 100644 --- a/source/tools/atlas/AtlasUI/ErrorReporter/ErrorReporter.cpp +++ b/source/tools/atlas/AtlasUI/ErrorReporter/ErrorReporter.cpp @@ -1,706 +1,706 @@ -/** - * ========================================================================= - * File : ErrorReporter.cpp - * Project : 0 A.D. - * Description : preview and send crashlogs to server. - * - * @author jan@wildfiregames.com, joe@wildfiregames.com - * ========================================================================= - */ - -/* - * based on dbgrptg.cpp, - * Copyright (c) 2005 Vadim Zeitlin - * License: wxWindows license - */ - -#include "precompiled.h" - -#if 0 - -#include "wx/statline.h" -#include "wx/mimetype.h" - -static const wxChar* DIALOG_TITLE = _T("WildfireGames Reporting Utility"); -static const wxChar* PROBLEM_TITLE = _T("Problem Report for 0AD"); -static const wxChar* DIALOG_REGRET = _T("Much to our regret, we must report the program has encountered a problem.\n"); -static const wxChar* DIALOG_REPGEN = _T("A problem report has been generated in the directory\n"); -static const wxChar* DIALOG_SPACER = _T("\n"); -static const wxChar* DIALOG_FILES = _T("The report contains the files listed below.\nWe believe they hold information that will help us to improve the program,\nso please take a minute and send them!\n"); -static const wxChar* DIALOG_PRIVACY = _T("If any of these files contain private information,\nplease uncheck them and they will be removed from the report.\n"); -static const wxChar* DIALOG_RESPECT = _T("We respect your privacy so if you do not wish to send us this problem report\nwe understand and you can use the \"Cancel\" button.\n"); -static const wxChar* DIALOG_APOLOGY = _T("Thank you and we're sorry for the inconvenience!\n"); -static const wxChar* DIALOG_ADDL_INFO = _T("If you have any additional information pertaining to this problem report,\n please enter it here and it will be joined to it:"); -// This is displayed to indicate a successful upload of the report file. -static const wxChar* DIALOG_UPLOAD = _T("Report successfully uploaded."); -// Default location for the crash files to include in the report file. -static const wxChar* LOGS_LOCATION = _T("C:\\0AD\\BINARIES\\LOGS\\"); - - -// ---------------------------------------------------------------------------- -// wxDumpPreviewDlg: simple class for showing ASCII preview of dump files -// ---------------------------------------------------------------------------- - -class wxDumpPreviewDlg : public wxDialog -{ -public: - wxDumpPreviewDlg(wxWindow *parent, - const wxString& title, - const wxString& text); - -private: - // the text we show - wxTextCtrl *m_text; - - DECLARE_NO_COPY_CLASS(wxDumpPreviewDlg) -}; - -wxDumpPreviewDlg::wxDumpPreviewDlg(wxWindow *parent, const wxString& title, const wxString& text) -: wxDialog(parent, wxID_ANY, title, wxDefaultPosition, wxDefaultSize, wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER) -{ - // create controls - // --------------- - - // use wxTE_RICH2 style to avoid 64kB limit under MSW and display big files - // faster than with wxTE_RICH - m_text = new wxTextCtrl(this, wxID_ANY, wxEmptyString, - wxPoint(0, 0), wxDefaultSize, - wxTE_MULTILINE | - wxTE_READONLY | - wxTE_NOHIDESEL | - wxTE_RICH2); - m_text->SetValue(text); - - // use fixed-width font - m_text->SetFont(wxFont(12, wxFONTFAMILY_TELETYPE, - wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL)); - - wxButton *btnClose = new wxButton(this, wxID_CANCEL, _("Close")); - - - // layout them - // ----------- - - wxSizer *sizerTop = new wxBoxSizer(wxVERTICAL), - *sizerBtns = new wxBoxSizer(wxHORIZONTAL); - - sizerBtns->Add(btnClose, 0, 0, 1); - - sizerTop->Add(m_text, 1, wxEXPAND); - sizerTop->Add(sizerBtns, 0, wxALIGN_RIGHT | wxTOP | wxBOTTOM | wxRIGHT, 1); - - // set the sizer &c - // ---------------- - - // make the text window bigger to show more contents of the file - sizerTop->SetItemMinSize(m_text, 600, 300); - SetSizer(sizerTop); - - Layout(); - Fit(); - - m_text->SetFocus(); -} - -// ---------------------------------------------------------------------------- -// wxDumpOpenExternalDlg: choose a command for opening the given file -// ---------------------------------------------------------------------------- - -class wxDumpOpenExternalDlg : public wxDialog -{ -public: - wxDumpOpenExternalDlg(wxWindow *parent, const wxFileName& filename); - - // return the command chosed by user to open this file - const wxString& GetCommand() const { return m_command; } - - wxString m_command; - -private: - -#if wxUSE_FILEDLG - void OnBrowse(wxCommandEvent& event); -#endif // wxUSE_FILEDLG - - DECLARE_EVENT_TABLE() - DECLARE_NO_COPY_CLASS(wxDumpOpenExternalDlg) -}; - -BEGIN_EVENT_TABLE(wxDumpOpenExternalDlg, wxDialog) - -#if wxUSE_FILEDLG -EVT_BUTTON(wxID_MORE, wxDumpOpenExternalDlg::OnBrowse) -#endif - -END_EVENT_TABLE() - - -wxDumpOpenExternalDlg::wxDumpOpenExternalDlg(wxWindow *parent, const wxFileName& filename) -: wxDialog(parent, wxID_ANY, -wxString::Format -( - _("Open file \"%s\""), - filename.GetFullPath().c_str() -) -) -{ - // create controls - // --------------- - - wxSizer *sizerTop = new wxBoxSizer(wxVERTICAL); - sizerTop->Add(new wxStaticText(this, wxID_ANY, - wxString::Format - ( - _("Enter command to open file \"%s\":"), - filename.GetFullName().c_str() - )), - wxSizerFlags().Border()); - - wxSizer *sizerH = new wxBoxSizer(wxHORIZONTAL); - - wxTextCtrl *command = new wxTextCtrl - ( - this, - wxID_ANY, - wxEmptyString, - wxDefaultPosition, - wxSize(250, wxDefaultCoord), - 0 -#if wxUSE_VALIDATORS - ,wxTextValidator(wxFILTER_NONE, &m_command) -#endif - ); - sizerH->Add(command, - wxSizerFlags(1).Align(wxALIGN_CENTER_VERTICAL)); - -#if wxUSE_FILEDLG - - wxButton *browse = new wxButton(this, wxID_MORE, wxT(">>"), - wxDefaultPosition, wxDefaultSize, - wxBU_EXACTFIT); - sizerH->Add(browse, - wxSizerFlags(0).Align(wxALIGN_CENTER_VERTICAL). Border(wxLEFT)); - -#endif // wxUSE_FILEDLG - - sizerTop->Add(sizerH, wxSizerFlags(0).Expand().Border()); - - sizerTop->Add(new wxStaticLine(this), wxSizerFlags().Expand().Border()); - - sizerTop->Add(CreateStdDialogButtonSizer(wxOK | wxCANCEL), - wxSizerFlags().Align(wxALIGN_RIGHT).Border()); - - // set the sizer &c - // ---------------- - - SetSizer(sizerTop); - - Layout(); - Fit(); - - command->SetFocus(); -} - -#if wxUSE_FILEDLG - -void wxDumpOpenExternalDlg::OnBrowse(wxCommandEvent& ) -{ - wxFileName fname(m_command); - wxFileDialog dlg(this, - wxFileSelectorPromptStr, - fname.GetPathWithSep(), - fname.GetFullName() -#ifdef __WXMSW__ - , _("Executable files (*.exe)|*.exe|All files (*.*)|*.*||") -#endif // __WXMSW__ - ); - if ( dlg.ShowModal() == wxID_OK ) - { - m_command = dlg.GetPath(); - TransferDataToWindow(); - } -} - -#endif // wxUSE_FILEDLG - -// ---------------------------------------------------------------------------- -// wxDebugReportDialog: class showing debug report to the user -// ---------------------------------------------------------------------------- - -class wxDebugReportDialog : public wxDialog -{ -public: - wxDebugReportDialog(wxDebugReport& dbgrpt); - - virtual bool TransferDataToWindow(); - virtual bool TransferDataFromWindow(); - -private: - void OnView(wxCommandEvent& ); - void OnViewUpdate(wxUpdateUIEvent& ); - void OnOpen(wxCommandEvent& ); - - - // small helper: add wxEXPAND and wxALL flags - static wxSizerFlags SizerFlags(int proportion) - { - return wxSizerFlags(proportion).Expand().Border(); - } - - - wxDebugReport& m_dbgrpt; - - wxCheckListBox *m_checklst; - wxTextCtrl *m_notes; - - wxArrayString m_files; - - DECLARE_EVENT_TABLE() - DECLARE_NO_COPY_CLASS(wxDebugReportDialog) -}; - -// ============================================================================ -// wxDebugReportDialog implementation -// ============================================================================ - -BEGIN_EVENT_TABLE(wxDebugReportDialog, wxDialog) -EVT_BUTTON(wxID_VIEW_DETAILS, wxDebugReportDialog::OnView) -EVT_UPDATE_UI(wxID_VIEW_DETAILS, wxDebugReportDialog::OnViewUpdate) -EVT_BUTTON(wxID_OPEN, wxDebugReportDialog::OnOpen) -EVT_UPDATE_UI(wxID_OPEN, wxDebugReportDialog::OnViewUpdate) -END_EVENT_TABLE() - - -// ---------------------------------------------------------------------------- -// construction -// ---------------------------------------------------------------------------- -/** - * wxDebugReportDialog: This contains modifications to implement changes to - * the content of the dialog. - * - * @param wxDebugReport & dbgrpt reference to compressed report file. - **/ -wxDebugReportDialog::wxDebugReportDialog(wxDebugReport& dbgrpt) -: wxDialog(NULL, wxID_ANY, - wxString(DIALOG_TITLE), - wxDefaultPosition, - wxDefaultSize, - wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER), - m_dbgrpt(dbgrpt) -{ - // upper part of the dialog: explanatory message - wxString msg; - msg << DIALOG_REGRET - << DIALOG_REPGEN - << _T("\"") << dbgrpt.GetDirectory() << _T("\"\n") - << DIALOG_SPACER - << DIALOG_FILES - << DIALOG_PRIVACY - << DIALOG_RESPECT - << DIALOG_SPACER - << DIALOG_APOLOGY - ; - - const wxSizerFlags flagsFixed(SizerFlags(0)); - const wxSizerFlags flagsExpand(SizerFlags(1)); - const wxSizerFlags flagsExpand2(SizerFlags(2)); - - wxSizer *sizerPreview = new wxStaticBoxSizer(wxVERTICAL, this, PROBLEM_TITLE); - sizerPreview->Add(CreateTextSizer(msg), SizerFlags(0).Centre()); - - // ... and the list of files in this debug report with buttons to view them - wxSizer *sizerFileBtns = new wxBoxSizer(wxVERTICAL); - sizerFileBtns->AddStretchSpacer(1); - sizerFileBtns->Add(new wxButton(this, wxID_VIEW_DETAILS, _T("&View...")), - wxSizerFlags().Border(wxBOTTOM)); - sizerFileBtns->Add(new wxButton(this, wxID_OPEN, _T("&Open...")), - wxSizerFlags().Border(wxTOP)); - sizerFileBtns->AddStretchSpacer(1); - - m_checklst = new wxCheckListBox(this, wxID_ANY); - - wxSizer *sizerFiles = new wxBoxSizer(wxHORIZONTAL); - sizerFiles->Add(m_checklst, flagsExpand); - sizerFiles->Add(sizerFileBtns, flagsFixed); - - sizerPreview->Add(sizerFiles, flagsExpand2); - - - // lower part of the dialog: notes field - wxSizer *sizerNotes = new wxStaticBoxSizer(wxVERTICAL, this, _("&Notes:")); - - msg = DIALOG_ADDL_INFO; - - m_notes = new wxTextCtrl(this, wxID_ANY, wxEmptyString, - wxDefaultPosition, wxDefaultSize, - wxTE_MULTILINE); - - sizerNotes->Add(CreateTextSizer(msg), flagsFixed); - sizerNotes->Add(m_notes, flagsExpand); - - - wxSizer *sizerTop = new wxBoxSizer(wxVERTICAL); - sizerTop->Add(sizerPreview, flagsExpand2); - sizerTop->AddSpacer(5); - sizerTop->Add(sizerNotes, flagsExpand); - sizerTop->Add(CreateStdDialogButtonSizer(wxOK | wxCANCEL), flagsFixed); - - SetSizerAndFit(sizerTop); - Layout(); - CentreOnScreen(); -} - -// ---------------------------------------------------------------------------- -// data exchange -// ---------------------------------------------------------------------------- - -bool wxDebugReportDialog::TransferDataToWindow() -{ - // all files are included in the report by default - const size_t count = m_dbgrpt.GetFilesCount(); - for ( size_t n = 0; n < count; n++ ) - { - wxString name, desc; - if ( m_dbgrpt.GetFile(n, &name, &desc) ) - { - m_checklst->Append(name + _T(" (") + desc + _T(')')); - m_checklst->Check(n); - - m_files.Add(name); - } - } - - return true; -} - -bool wxDebugReportDialog::TransferDataFromWindow() -{ - // any unchecked files should be removed from the report - const size_t count = m_checklst->GetCount(); - for ( size_t n = 0; n < count; n++ ) - { - if ( !m_checklst->IsChecked(n) ) - { - m_dbgrpt.RemoveFile(m_files[n]); - } - } - - // if the user entered any notes, add them to the report - const wxString notes = m_notes->GetValue(); - if ( !notes.empty() ) - { - // for now filename fixed, could make it configurable in the future... - m_dbgrpt.AddText(_T("notes.txt"), notes, _T("user notes")); - } - - return true; -} - -// ---------------------------------------------------------------------------- -// event handlers -// ---------------------------------------------------------------------------- - -void wxDebugReportDialog::OnView(wxCommandEvent& ) -{ - const int sel = m_checklst->GetSelection(); - wxCHECK_RET( sel != wxNOT_FOUND, _T("invalid selection in OnView()") ); - - wxFileName fn(m_dbgrpt.GetDirectory(), m_files[sel]); - wxString str; - - wxFFile file(fn.GetFullPath()); - if ( file.IsOpened() && file.ReadAll(&str) ) - { - wxDumpPreviewDlg dlg(this, m_files[sel], str); - dlg.ShowModal(); - } -} - -void wxDebugReportDialog::OnOpen(wxCommandEvent& ) -{ - const int sel = m_checklst->GetSelection(); - wxCHECK_RET( sel != wxNOT_FOUND, _T("invalid selection in OnOpen()") ); - - wxFileName fn(m_dbgrpt.GetDirectory(), m_files[sel]); - - // try to get the command to open this kind of files ourselves - wxString command; -#if wxUSE_MIMETYPE - wxFileType * - ft = wxTheMimeTypesManager->GetFileTypeFromExtension(fn.GetExt()); - if ( ft ) - { - command = ft->GetOpenCommand(fn.GetFullPath()); - delete ft; - } -#endif // wxUSE_MIMETYPE - - // if we couldn't, ask the user - if ( command.empty() ) - { - wxDumpOpenExternalDlg dlg(this, fn); - if ( dlg.ShowModal() == wxID_OK ) - { - // get the command chosen by the user and append file name to it - - // if we don't have place marker for file name in the command... - wxString cmd = dlg.GetCommand(); - if ( !cmd.empty() ) - { -#if wxUSE_MIMETYPE - if ( cmd.find(_T('%')) != wxString::npos ) - { - command = wxFileType::ExpandCommand(cmd, fn.GetFullPath()); - } - else // no %s nor %1 -#endif // wxUSE_MIMETYPE - { - // append the file name to the end - command << cmd << _T(" \"") << fn.GetFullPath() << _T('"'); - } - } - } - } - - if ( !command.empty() ) - ::wxExecute(command); -} - -void wxDebugReportDialog::OnViewUpdate(wxUpdateUIEvent& event) -{ - int sel = m_checklst->GetSelection(); - if (sel >= 0) - { - wxFileName fn(m_dbgrpt.GetDirectory(), m_files[sel]); - event.Enable(fn.FileExists()); - } - else - event.Enable(false); -} - - -// ============================================================================ -// wxDebugReportPreviewStd implementation -// ============================================================================ - -bool wxDebugReportPreviewStd::Show(wxDebugReport& dbgrpt) const -{ - if ( !dbgrpt.GetFilesCount() ) - return false; - - wxDebugReportDialog dlg(dbgrpt); - -#ifdef __WXMSW__ - // before entering the event loop (from ShowModal()), block the event - // handling for all other windows as this could result in more crashes - wxEventLoop::SetCriticalWindow(&dlg); -#endif // __WXMSW__ - - return dlg.ShowModal() == wxID_OK && dbgrpt.GetFilesCount() != 0; -} - - - - - - - - - - - - -// ---------------------------------------------------------------------------- -// custom debug reporting class -// ---------------------------------------------------------------------------- - -// this is your custom debug reporter: it will use curl program (which should -// be available) to upload the crash report to the given URL (which should be -// set up by you) -class MyDebugReport : public wxDebugReportUpload -{ -public: - MyDebugReport() - : wxDebugReportUpload(_T("http://your.url.here/"), _T("report:file"), _T("action")) - { - //This would be the place to put the compressed file in a custom directory - //but since the directory member is private, it would require pulling in yet - //another wxWidget module to modify and I decided against it and take the - //time and date based random location generator. (JAC - 4/16/07) - } - -protected: - // this is called with the contents of the server response: you will - // probably want to parse the XML document in OnServerReply() instead of - // just dumping it as I do - virtual bool OnServerReply(const wxArrayString& reply) - { - if ( reply.IsEmpty() ) - { - wxLogError(_T("Didn't receive the expected server reply.")); - return false; - } - - wxString s(_T("Server replied:\n")); - - const size_t count = reply.GetCount(); - for ( size_t n = 0; n < count; n++ ) - { - s << _T('\t') << reply[n] << _T('\n'); - } - - wxLogMessage(_T("%s"), s.c_str()); - - return true; - } - /** - * DoProcess: This is called by the wxWidgets Dialog when OK is clicked. - * Since it overrides a virtual method we must make sure - * that DoProcess() of the parent class is called. - * - * @return bool true if upload was successful, false otherwise. - **/ - virtual bool DoProcess() - { - //Call the DoProcess of the parent class and make sure it is successful. - if ( !wxDebugReportCompress::DoProcess() ) - return false; - - //Shell execute the curl command with the appropriate arguments - //for the custom application of this class: - // - //C:\curl-7.16.0\curl -v -F upfile=@"" --trace trace.txt - // - //The -v and the --trace trace.txt arguments are for debugging and are not required. - wxArrayString output, errors; - int rc = wxExecute(wxString::Format - ( - _T("%s -v -F %s=@\"%s\" --trace trace.txt %s"), - _T("C:\\curl-7.16.0\\curl"), - _T("upfile"), - GetCompressedFileName().c_str(), - _T("http://kaxa.findhere.org/0ad/upload.php") - ), - output, - errors); - //Check the result for errors and log them with wxWidgets. - if ( rc == -1 ) - { - wxLogError(_("Failed to execute curl, please install it in PATH.")); - } - else if ( rc != 0 ) - { - const size_t count = errors.GetCount(); - if ( count ) - { - for ( size_t n = 0; n < count; n++ ) - { - wxLogWarning(_T("%s"), errors[n].c_str()); - } - } - - wxLogError(_("Failed to upload the debug report (error code %d)."), rc); - } - else // rc == 0 - { - //this causes a crash and I have no incentive to debug it - //if ( OnServerReply(output) ) - return true; - } - - return false; - } -}; - -// another possibility would be to build email library from contrib and use -// this class, after uncommenting it: -#if 0 - -#include "wx/net/email.h" - -class MyDebugReport : public wxDebugReportCompress -{ -public: - virtual bool DoProcess() - { - if ( !wxDebugReportCompress::DoProcess() ) - return false; - wxMailMessage msg(GetReportName() + _T(" crash report"), - _T("vadim@wxwindows.org"), - wxEmptyString, // mail body - wxEmptyString, // from address - GetCompressedFileName(), - _T("crashreport.zip")); - - return wxEmail::Send(msg); - } -}; - -#endif // 0 - -// ---------------------------------------------------------------------------- -// application class -// ---------------------------------------------------------------------------- - -bool m_uploadReport = true; - -//m_generateReport = false; //Flag to report back to wxWidgets that indicates -//whether the DoProcess() method should be called. -//GenerateReport(false); //Create the compressed report file. -//The argument is not used in this version but -//is meant to indicate whether crash files already -//existed and the calling method did not create new ones. -//false means the crash files were recently generated... -//true means they already existed. - -// this is where we really generate the debug report -//void GenerateReport(bool CrashFilesExist); - - -void GenerateReport() -{ - wxDebugReportCompress *report = m_uploadReport ? new MyDebugReport - : new wxDebugReportCompress; - wxString fn1, fn2, fn3; - fn1 = _T(LOGS_LOCATION); - fn1 += _T("crashlog.dmp"); - fn2 = _T(LOGS_LOCATION); - fn2 += _T("crashlog.txt"); - - if(wxFileExists(fn1)) - report->AddFile(fn1, _T("memory dump")); - else - wxLogError(_T("crashlog.dmp not found!")); - if(wxFileExists(fn2)) - report->AddFile(fn2, _T("debug information")); - else - wxLogError(_T("crashlog.txt not found!")); - - //Then call the built in wxWidgets dialog which is modified to be - //customizable for each individual project and can be found in - // *****dbgrptg.cpp***** - bool m_generateReport = wxDebugReportPreviewStd().Show(*report); - if ( m_generateReport ) - { //User clicked OK - if ( report->Process() ) - { - if ( m_uploadReport ) - { - wxLogMessage(DIALOG_UPLOAD); - } - else - { - wxLogMessage(_T("Report generated in \"%s\"."), - report->GetCompressedFileName().c_str()); - report->Reset(); - } - } - // remove all crashlog files whether or not upload was successful!! - wxRemove(fn1); - wxRemove(fn2); - } - //delete the compressed report file always!! - delete report; -} - -#endif +/** + * ========================================================================= + * File : ErrorReporter.cpp + * Project : 0 A.D. + * Description : preview and send crashlogs to server. + * + * @author jan@wildfiregames.com, joe@wildfiregames.com + * ========================================================================= + */ + +/* + * based on dbgrptg.cpp, + * Copyright (c) 2005 Vadim Zeitlin + * License: wxWindows license + */ + +#include "precompiled.h" + +#if 0 + +#include "wx/statline.h" +#include "wx/mimetype.h" + +static const wxChar* DIALOG_TITLE = _T("WildfireGames Reporting Utility"); +static const wxChar* PROBLEM_TITLE = _T("Problem Report for 0AD"); +static const wxChar* DIALOG_REGRET = _T("Much to our regret, we must report the program has encountered a problem.\n"); +static const wxChar* DIALOG_REPGEN = _T("A problem report has been generated in the directory\n"); +static const wxChar* DIALOG_SPACER = _T("\n"); +static const wxChar* DIALOG_FILES = _T("The report contains the files listed below.\nWe believe they hold information that will help us to improve the program,\nso please take a minute and send them!\n"); +static const wxChar* DIALOG_PRIVACY = _T("If any of these files contain private information,\nplease uncheck them and they will be removed from the report.\n"); +static const wxChar* DIALOG_RESPECT = _T("We respect your privacy so if you do not wish to send us this problem report\nwe understand and you can use the \"Cancel\" button.\n"); +static const wxChar* DIALOG_APOLOGY = _T("Thank you and we're sorry for the inconvenience!\n"); +static const wxChar* DIALOG_ADDL_INFO = _T("If you have any additional information pertaining to this problem report,\n please enter it here and it will be joined to it:"); +// This is displayed to indicate a successful upload of the report file. +static const wxChar* DIALOG_UPLOAD = _T("Report successfully uploaded."); +// Default location for the crash files to include in the report file. +static const wxChar* LOGS_LOCATION = _T("C:\\0AD\\BINARIES\\LOGS\\"); + + +// ---------------------------------------------------------------------------- +// wxDumpPreviewDlg: simple class for showing ASCII preview of dump files +// ---------------------------------------------------------------------------- + +class wxDumpPreviewDlg : public wxDialog +{ +public: + wxDumpPreviewDlg(wxWindow *parent, + const wxString& title, + const wxString& text); + +private: + // the text we show + wxTextCtrl *m_text; + + DECLARE_NO_COPY_CLASS(wxDumpPreviewDlg) +}; + +wxDumpPreviewDlg::wxDumpPreviewDlg(wxWindow *parent, const wxString& title, const wxString& text) +: wxDialog(parent, wxID_ANY, title, wxDefaultPosition, wxDefaultSize, wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER) +{ + // create controls + // --------------- + + // use wxTE_RICH2 style to avoid 64kB limit under MSW and display big files + // faster than with wxTE_RICH + m_text = new wxTextCtrl(this, wxID_ANY, wxEmptyString, + wxPoint(0, 0), wxDefaultSize, + wxTE_MULTILINE | + wxTE_READONLY | + wxTE_NOHIDESEL | + wxTE_RICH2); + m_text->SetValue(text); + + // use fixed-width font + m_text->SetFont(wxFont(12, wxFONTFAMILY_TELETYPE, + wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL)); + + wxButton *btnClose = new wxButton(this, wxID_CANCEL, _("Close")); + + + // layout them + // ----------- + + wxSizer *sizerTop = new wxBoxSizer(wxVERTICAL), + *sizerBtns = new wxBoxSizer(wxHORIZONTAL); + + sizerBtns->Add(btnClose, 0, 0, 1); + + sizerTop->Add(m_text, 1, wxEXPAND); + sizerTop->Add(sizerBtns, 0, wxALIGN_RIGHT | wxTOP | wxBOTTOM | wxRIGHT, 1); + + // set the sizer &c + // ---------------- + + // make the text window bigger to show more contents of the file + sizerTop->SetItemMinSize(m_text, 600, 300); + SetSizer(sizerTop); + + Layout(); + Fit(); + + m_text->SetFocus(); +} + +// ---------------------------------------------------------------------------- +// wxDumpOpenExternalDlg: choose a command for opening the given file +// ---------------------------------------------------------------------------- + +class wxDumpOpenExternalDlg : public wxDialog +{ +public: + wxDumpOpenExternalDlg(wxWindow *parent, const wxFileName& filename); + + // return the command chosed by user to open this file + const wxString& GetCommand() const { return m_command; } + + wxString m_command; + +private: + +#if wxUSE_FILEDLG + void OnBrowse(wxCommandEvent& event); +#endif // wxUSE_FILEDLG + + DECLARE_EVENT_TABLE() + DECLARE_NO_COPY_CLASS(wxDumpOpenExternalDlg) +}; + +BEGIN_EVENT_TABLE(wxDumpOpenExternalDlg, wxDialog) + +#if wxUSE_FILEDLG +EVT_BUTTON(wxID_MORE, wxDumpOpenExternalDlg::OnBrowse) +#endif + +END_EVENT_TABLE() + + +wxDumpOpenExternalDlg::wxDumpOpenExternalDlg(wxWindow *parent, const wxFileName& filename) +: wxDialog(parent, wxID_ANY, +wxString::Format +( + _("Open file \"%s\""), + filename.GetFullPath().c_str() +) +) +{ + // create controls + // --------------- + + wxSizer *sizerTop = new wxBoxSizer(wxVERTICAL); + sizerTop->Add(new wxStaticText(this, wxID_ANY, + wxString::Format + ( + _("Enter command to open file \"%s\":"), + filename.GetFullName().c_str() + )), + wxSizerFlags().Border()); + + wxSizer *sizerH = new wxBoxSizer(wxHORIZONTAL); + + wxTextCtrl *command = new wxTextCtrl + ( + this, + wxID_ANY, + wxEmptyString, + wxDefaultPosition, + wxSize(250, wxDefaultCoord), + 0 +#if wxUSE_VALIDATORS + ,wxTextValidator(wxFILTER_NONE, &m_command) +#endif + ); + sizerH->Add(command, + wxSizerFlags(1).Align(wxALIGN_CENTER_VERTICAL)); + +#if wxUSE_FILEDLG + + wxButton *browse = new wxButton(this, wxID_MORE, wxT(">>"), + wxDefaultPosition, wxDefaultSize, + wxBU_EXACTFIT); + sizerH->Add(browse, + wxSizerFlags(0).Align(wxALIGN_CENTER_VERTICAL). Border(wxLEFT)); + +#endif // wxUSE_FILEDLG + + sizerTop->Add(sizerH, wxSizerFlags(0).Expand().Border()); + + sizerTop->Add(new wxStaticLine(this), wxSizerFlags().Expand().Border()); + + sizerTop->Add(CreateStdDialogButtonSizer(wxOK | wxCANCEL), + wxSizerFlags().Align(wxALIGN_RIGHT).Border()); + + // set the sizer &c + // ---------------- + + SetSizer(sizerTop); + + Layout(); + Fit(); + + command->SetFocus(); +} + +#if wxUSE_FILEDLG + +void wxDumpOpenExternalDlg::OnBrowse(wxCommandEvent& ) +{ + wxFileName fname(m_command); + wxFileDialog dlg(this, + wxFileSelectorPromptStr, + fname.GetPathWithSep(), + fname.GetFullName() +#ifdef __WXMSW__ + , _("Executable files (*.exe)|*.exe|All files (*.*)|*.*||") +#endif // __WXMSW__ + ); + if ( dlg.ShowModal() == wxID_OK ) + { + m_command = dlg.GetPath(); + TransferDataToWindow(); + } +} + +#endif // wxUSE_FILEDLG + +// ---------------------------------------------------------------------------- +// wxDebugReportDialog: class showing debug report to the user +// ---------------------------------------------------------------------------- + +class wxDebugReportDialog : public wxDialog +{ +public: + wxDebugReportDialog(wxDebugReport& dbgrpt); + + virtual bool TransferDataToWindow(); + virtual bool TransferDataFromWindow(); + +private: + void OnView(wxCommandEvent& ); + void OnViewUpdate(wxUpdateUIEvent& ); + void OnOpen(wxCommandEvent& ); + + + // small helper: add wxEXPAND and wxALL flags + static wxSizerFlags SizerFlags(int proportion) + { + return wxSizerFlags(proportion).Expand().Border(); + } + + + wxDebugReport& m_dbgrpt; + + wxCheckListBox *m_checklst; + wxTextCtrl *m_notes; + + wxArrayString m_files; + + DECLARE_EVENT_TABLE() + DECLARE_NO_COPY_CLASS(wxDebugReportDialog) +}; + +// ============================================================================ +// wxDebugReportDialog implementation +// ============================================================================ + +BEGIN_EVENT_TABLE(wxDebugReportDialog, wxDialog) +EVT_BUTTON(wxID_VIEW_DETAILS, wxDebugReportDialog::OnView) +EVT_UPDATE_UI(wxID_VIEW_DETAILS, wxDebugReportDialog::OnViewUpdate) +EVT_BUTTON(wxID_OPEN, wxDebugReportDialog::OnOpen) +EVT_UPDATE_UI(wxID_OPEN, wxDebugReportDialog::OnViewUpdate) +END_EVENT_TABLE() + + +// ---------------------------------------------------------------------------- +// construction +// ---------------------------------------------------------------------------- +/** + * wxDebugReportDialog: This contains modifications to implement changes to + * the content of the dialog. + * + * @param wxDebugReport & dbgrpt reference to compressed report file. + **/ +wxDebugReportDialog::wxDebugReportDialog(wxDebugReport& dbgrpt) +: wxDialog(NULL, wxID_ANY, + wxString(DIALOG_TITLE), + wxDefaultPosition, + wxDefaultSize, + wxDEFAULT_DIALOG_STYLE | wxRESIZE_BORDER), + m_dbgrpt(dbgrpt) +{ + // upper part of the dialog: explanatory message + wxString msg; + msg << DIALOG_REGRET + << DIALOG_REPGEN + << _T("\"") << dbgrpt.GetDirectory() << _T("\"\n") + << DIALOG_SPACER + << DIALOG_FILES + << DIALOG_PRIVACY + << DIALOG_RESPECT + << DIALOG_SPACER + << DIALOG_APOLOGY + ; + + const wxSizerFlags flagsFixed(SizerFlags(0)); + const wxSizerFlags flagsExpand(SizerFlags(1)); + const wxSizerFlags flagsExpand2(SizerFlags(2)); + + wxSizer *sizerPreview = new wxStaticBoxSizer(wxVERTICAL, this, PROBLEM_TITLE); + sizerPreview->Add(CreateTextSizer(msg), SizerFlags(0).Centre()); + + // ... and the list of files in this debug report with buttons to view them + wxSizer *sizerFileBtns = new wxBoxSizer(wxVERTICAL); + sizerFileBtns->AddStretchSpacer(1); + sizerFileBtns->Add(new wxButton(this, wxID_VIEW_DETAILS, _T("&View...")), + wxSizerFlags().Border(wxBOTTOM)); + sizerFileBtns->Add(new wxButton(this, wxID_OPEN, _T("&Open...")), + wxSizerFlags().Border(wxTOP)); + sizerFileBtns->AddStretchSpacer(1); + + m_checklst = new wxCheckListBox(this, wxID_ANY); + + wxSizer *sizerFiles = new wxBoxSizer(wxHORIZONTAL); + sizerFiles->Add(m_checklst, flagsExpand); + sizerFiles->Add(sizerFileBtns, flagsFixed); + + sizerPreview->Add(sizerFiles, flagsExpand2); + + + // lower part of the dialog: notes field + wxSizer *sizerNotes = new wxStaticBoxSizer(wxVERTICAL, this, _("&Notes:")); + + msg = DIALOG_ADDL_INFO; + + m_notes = new wxTextCtrl(this, wxID_ANY, wxEmptyString, + wxDefaultPosition, wxDefaultSize, + wxTE_MULTILINE); + + sizerNotes->Add(CreateTextSizer(msg), flagsFixed); + sizerNotes->Add(m_notes, flagsExpand); + + + wxSizer *sizerTop = new wxBoxSizer(wxVERTICAL); + sizerTop->Add(sizerPreview, flagsExpand2); + sizerTop->AddSpacer(5); + sizerTop->Add(sizerNotes, flagsExpand); + sizerTop->Add(CreateStdDialogButtonSizer(wxOK | wxCANCEL), flagsFixed); + + SetSizerAndFit(sizerTop); + Layout(); + CentreOnScreen(); +} + +// ---------------------------------------------------------------------------- +// data exchange +// ---------------------------------------------------------------------------- + +bool wxDebugReportDialog::TransferDataToWindow() +{ + // all files are included in the report by default + const size_t count = m_dbgrpt.GetFilesCount(); + for ( size_t n = 0; n < count; n++ ) + { + wxString name, desc; + if ( m_dbgrpt.GetFile(n, &name, &desc) ) + { + m_checklst->Append(name + _T(" (") + desc + _T(')')); + m_checklst->Check(n); + + m_files.Add(name); + } + } + + return true; +} + +bool wxDebugReportDialog::TransferDataFromWindow() +{ + // any unchecked files should be removed from the report + const size_t count = m_checklst->GetCount(); + for ( size_t n = 0; n < count; n++ ) + { + if ( !m_checklst->IsChecked(n) ) + { + m_dbgrpt.RemoveFile(m_files[n]); + } + } + + // if the user entered any notes, add them to the report + const wxString notes = m_notes->GetValue(); + if ( !notes.empty() ) + { + // for now filename fixed, could make it configurable in the future... + m_dbgrpt.AddText(_T("notes.txt"), notes, _T("user notes")); + } + + return true; +} + +// ---------------------------------------------------------------------------- +// event handlers +// ---------------------------------------------------------------------------- + +void wxDebugReportDialog::OnView(wxCommandEvent& ) +{ + const int sel = m_checklst->GetSelection(); + wxCHECK_RET( sel != wxNOT_FOUND, _T("invalid selection in OnView()") ); + + wxFileName fn(m_dbgrpt.GetDirectory(), m_files[sel]); + wxString str; + + wxFFile file(fn.GetFullPath()); + if ( file.IsOpened() && file.ReadAll(&str) ) + { + wxDumpPreviewDlg dlg(this, m_files[sel], str); + dlg.ShowModal(); + } +} + +void wxDebugReportDialog::OnOpen(wxCommandEvent& ) +{ + const int sel = m_checklst->GetSelection(); + wxCHECK_RET( sel != wxNOT_FOUND, _T("invalid selection in OnOpen()") ); + + wxFileName fn(m_dbgrpt.GetDirectory(), m_files[sel]); + + // try to get the command to open this kind of files ourselves + wxString command; +#if wxUSE_MIMETYPE + wxFileType * + ft = wxTheMimeTypesManager->GetFileTypeFromExtension(fn.GetExt()); + if ( ft ) + { + command = ft->GetOpenCommand(fn.GetFullPath()); + delete ft; + } +#endif // wxUSE_MIMETYPE + + // if we couldn't, ask the user + if ( command.empty() ) + { + wxDumpOpenExternalDlg dlg(this, fn); + if ( dlg.ShowModal() == wxID_OK ) + { + // get the command chosen by the user and append file name to it + + // if we don't have place marker for file name in the command... + wxString cmd = dlg.GetCommand(); + if ( !cmd.empty() ) + { +#if wxUSE_MIMETYPE + if ( cmd.find(_T('%')) != wxString::npos ) + { + command = wxFileType::ExpandCommand(cmd, fn.GetFullPath()); + } + else // no %s nor %1 +#endif // wxUSE_MIMETYPE + { + // append the file name to the end + command << cmd << _T(" \"") << fn.GetFullPath() << _T('"'); + } + } + } + } + + if ( !command.empty() ) + ::wxExecute(command); +} + +void wxDebugReportDialog::OnViewUpdate(wxUpdateUIEvent& event) +{ + int sel = m_checklst->GetSelection(); + if (sel >= 0) + { + wxFileName fn(m_dbgrpt.GetDirectory(), m_files[sel]); + event.Enable(fn.FileExists()); + } + else + event.Enable(false); +} + + +// ============================================================================ +// wxDebugReportPreviewStd implementation +// ============================================================================ + +bool wxDebugReportPreviewStd::Show(wxDebugReport& dbgrpt) const +{ + if ( !dbgrpt.GetFilesCount() ) + return false; + + wxDebugReportDialog dlg(dbgrpt); + +#ifdef __WXMSW__ + // before entering the event loop (from ShowModal()), block the event + // handling for all other windows as this could result in more crashes + wxEventLoop::SetCriticalWindow(&dlg); +#endif // __WXMSW__ + + return dlg.ShowModal() == wxID_OK && dbgrpt.GetFilesCount() != 0; +} + + + + + + + + + + + + +// ---------------------------------------------------------------------------- +// custom debug reporting class +// ---------------------------------------------------------------------------- + +// this is your custom debug reporter: it will use curl program (which should +// be available) to upload the crash report to the given URL (which should be +// set up by you) +class MyDebugReport : public wxDebugReportUpload +{ +public: + MyDebugReport() + : wxDebugReportUpload(_T("http://your.url.here/"), _T("report:file"), _T("action")) + { + //This would be the place to put the compressed file in a custom directory + //but since the directory member is private, it would require pulling in yet + //another wxWidget module to modify and I decided against it and take the + //time and date based random location generator. (JAC - 4/16/07) + } + +protected: + // this is called with the contents of the server response: you will + // probably want to parse the XML document in OnServerReply() instead of + // just dumping it as I do + virtual bool OnServerReply(const wxArrayString& reply) + { + if ( reply.IsEmpty() ) + { + wxLogError(_T("Didn't receive the expected server reply.")); + return false; + } + + wxString s(_T("Server replied:\n")); + + const size_t count = reply.GetCount(); + for ( size_t n = 0; n < count; n++ ) + { + s << _T('\t') << reply[n] << _T('\n'); + } + + wxLogMessage(_T("%s"), s.c_str()); + + return true; + } + /** + * DoProcess: This is called by the wxWidgets Dialog when OK is clicked. + * Since it overrides a virtual method we must make sure + * that DoProcess() of the parent class is called. + * + * @return bool true if upload was successful, false otherwise. + **/ + virtual bool DoProcess() + { + //Call the DoProcess of the parent class and make sure it is successful. + if ( !wxDebugReportCompress::DoProcess() ) + return false; + + //Shell execute the curl command with the appropriate arguments + //for the custom application of this class: + // + //C:\curl-7.16.0\curl -v -F upfile=@"" --trace trace.txt + // + //The -v and the --trace trace.txt arguments are for debugging and are not required. + wxArrayString output, errors; + int rc = wxExecute(wxString::Format + ( + _T("%s -v -F %s=@\"%s\" --trace trace.txt %s"), + _T("C:\\curl-7.16.0\\curl"), + _T("upfile"), + GetCompressedFileName().c_str(), + _T("http://kaxa.findhere.org/0ad/upload.php") + ), + output, + errors); + //Check the result for errors and log them with wxWidgets. + if ( rc == -1 ) + { + wxLogError(_("Failed to execute curl, please install it in PATH.")); + } + else if ( rc != 0 ) + { + const size_t count = errors.GetCount(); + if ( count ) + { + for ( size_t n = 0; n < count; n++ ) + { + wxLogWarning(_T("%s"), errors[n].c_str()); + } + } + + wxLogError(_("Failed to upload the debug report (error code %d)."), rc); + } + else // rc == 0 + { + //this causes a crash and I have no incentive to debug it + //if ( OnServerReply(output) ) + return true; + } + + return false; + } +}; + +// another possibility would be to build email library from contrib and use +// this class, after uncommenting it: +#if 0 + +#include "wx/net/email.h" + +class MyDebugReport : public wxDebugReportCompress +{ +public: + virtual bool DoProcess() + { + if ( !wxDebugReportCompress::DoProcess() ) + return false; + wxMailMessage msg(GetReportName() + _T(" crash report"), + _T("vadim@wxwindows.org"), + wxEmptyString, // mail body + wxEmptyString, // from address + GetCompressedFileName(), + _T("crashreport.zip")); + + return wxEmail::Send(msg); + } +}; + +#endif // 0 + +// ---------------------------------------------------------------------------- +// application class +// ---------------------------------------------------------------------------- + +bool m_uploadReport = true; + +//m_generateReport = false; //Flag to report back to wxWidgets that indicates +//whether the DoProcess() method should be called. +//GenerateReport(false); //Create the compressed report file. +//The argument is not used in this version but +//is meant to indicate whether crash files already +//existed and the calling method did not create new ones. +//false means the crash files were recently generated... +//true means they already existed. + +// this is where we really generate the debug report +//void GenerateReport(bool CrashFilesExist); + + +void GenerateReport() +{ + wxDebugReportCompress *report = m_uploadReport ? new MyDebugReport + : new wxDebugReportCompress; + wxString fn1, fn2, fn3; + fn1 = _T(LOGS_LOCATION); + fn1 += _T("crashlog.dmp"); + fn2 = _T(LOGS_LOCATION); + fn2 += _T("crashlog.txt"); + + if(wxFileExists(fn1)) + report->AddFile(fn1, _T("memory dump")); + else + wxLogError(_T("crashlog.dmp not found!")); + if(wxFileExists(fn2)) + report->AddFile(fn2, _T("debug information")); + else + wxLogError(_T("crashlog.txt not found!")); + + //Then call the built in wxWidgets dialog which is modified to be + //customizable for each individual project and can be found in + // *****dbgrptg.cpp***** + bool m_generateReport = wxDebugReportPreviewStd().Show(*report); + if ( m_generateReport ) + { //User clicked OK + if ( report->Process() ) + { + if ( m_uploadReport ) + { + wxLogMessage(DIALOG_UPLOAD); + } + else + { + wxLogMessage(_T("Report generated in \"%s\"."), + report->GetCompressedFileName().c_str()); + report->Reset(); + } + } + // remove all crashlog files whether or not upload was successful!! + wxRemove(fn1); + wxRemove(fn2); + } + //delete the compressed report file always!! + delete report; +} + +#endif diff --git a/source/tools/atlas/AtlasUI/ScenarioEditor/Sections/Trigger/Trigger.cpp b/source/tools/atlas/AtlasUI/ScenarioEditor/Sections/Trigger/Trigger.cpp index 9be1ceaed6..4f183dd69e 100644 --- a/source/tools/atlas/AtlasUI/ScenarioEditor/Sections/Trigger/Trigger.cpp +++ b/source/tools/atlas/AtlasUI/ScenarioEditor/Sections/Trigger/Trigger.cpp @@ -1,1733 +1,1733 @@ -#include "precompiled.h" - -#include "Trigger.h" -#include "GameInterface/Messages.h" -#include "CustomControls/Buttons/ActionButton.h" -#include "ScenarioEditor/ScenarioEditor.h" -#include "ScenarioEditor/Tools/Common/MiscState.h" - -#include "wx/treectrl.h" -#include "wx/listctrl.h" -#include "wx/notebook.h" -#include -#include - -using namespace AtlasMessage; - -BEGIN_EVENT_TABLE(TriggerSidebar, Sidebar) -EVT_TREE_BEGIN_DRAG(wxID_ANY, TriggerSidebar::onTreeDrag) -EVT_TREE_END_LABEL_EDIT(wxID_ANY, TriggerSidebar::onTreeNameChange) -EVT_TREE_SEL_CHANGED(wxID_ANY, TriggerSidebar::onTreeSelChange) -EVT_LIST_ITEM_SELECTED(TriggerSidebar::ID_CondList, TriggerSidebar::onCondSelect) -EVT_LIST_ITEM_SELECTED(TriggerSidebar::ID_EffectList, TriggerSidebar::onEffectSelect) -EVT_NOTEBOOK_PAGE_CHANGED(wxID_ANY, TriggerSidebar::onPageChange) -END_EVENT_TABLE() - - -class TriggerTreeCtrl : public wxTreeCtrl -{ -public: - TriggerTreeCtrl(TriggerSidebar* parent, wxWindowID id = wxID_ANY, const wxPoint& pos = wxDefaultPosition, - const wxSize& size = wxDefaultSize, long style = wxTR_HAS_BUTTONS ) - : wxTreeCtrl(parent, id, pos, size, style), m_Sidebar(parent) { } - - void onClick(wxMouseEvent& evt); - -private: - TriggerSidebar* m_Sidebar; - DECLARE_EVENT_TABLE(); -}; - -BEGIN_EVENT_TABLE(TriggerTreeCtrl, wxTreeCtrl) -EVT_LEFT_DOWN(TriggerTreeCtrl::onClick) -END_EVENT_TABLE() - - -struct LogicBlockHelper -{ - LogicBlockHelper() { index = -1; end = false; } - LogicBlockHelper(int _index, bool _end) : index(_index), end(_end) {} - int index; - bool end; - - bool operator< ( const LogicBlockHelper& rhs ) const - { - return index < rhs.index; - } - bool operator== ( const LogicBlockHelper& rhs ) const - { - return index == rhs.index; - } -}; -class TriggerSpecText : public wxTextCtrl -{ - typedef void (*callback)(void* data, std::wstring input, int parameter); - -public: - TriggerSpecText(wxWindow* parent, std::wstring label, const wxPoint& pos, const wxSize& size, - int parameter, std::wstring dataType, callback func, void* data) - : wxTextCtrl(parent, wxID_ANY, wxString( label.c_str() ), pos, size, wxTE_PROCESS_ENTER), - m_DataType(dataType), m_Parameter(parameter), m_Data(data), m_Callback(func) - { - } - void onTextEnter(wxCommandEvent& WXUNUSED(evt)); - - //Disallow invalid input - bool VerifyInput(std::wstring& input) - { - std::wstringstream stream(input); - if ( m_DataType == L"int" ) - { - int test; - stream >> test; - return !stream.fail(); - } - else if ( m_DataType == L"real" ) - { - float test; - stream >> test; - return !stream.fail(); - } - else if ( m_DataType == L"bool" ) - { - bool test; - stream >> test; - return !stream.fail(); - } - else if ( m_DataType == L"string" ) - { - //Make strings appear as strings to javascript - std::wstring quote(L"\""); - input.insert(0, quote); - input.append(quote); - return true; - } - else - { - wxFAIL_MSG(L"Invalid input type for trigger specification"); - return false; - } - } -private: - void* m_Data; - int m_Parameter; - std::wstring m_DataType; - callback m_Callback; - - DECLARE_EVENT_TABLE(); - -}; -BEGIN_EVENT_TABLE(TriggerSpecText, wxTextCtrl) -EVT_TEXT_ENTER(wxID_ANY, TriggerSpecText::onTextEnter) -END_EVENT_TABLE() - -class TriggerSpecChoice : public wxChoice -{ - typedef void (*callback)(void* data, std::wstring input, int parameter); - -public: - TriggerSpecChoice(TriggerBottomBar* parent, std::wstring label, const wxPoint& pos, - const wxSize& size, const wxArrayString& strings, int parameter, callback func, void* data); - - void onChoice(wxCommandEvent& evt); - -private: - TriggerBottomBar* m_Parent; - callback m_Callback; - int m_Parameter; - void* m_Data; - - DECLARE_EVENT_TABLE(); -}; - -BEGIN_EVENT_TABLE(TriggerSpecChoice, wxChoice) -EVT_CHOICE(wxID_ANY, TriggerSpecChoice::onChoice) -END_EVENT_TABLE() - -class TriggerBottomBar; - -class TriggerEntitySelector : public wxPanel -{ - typedef void (*callback)(void* data, std::wstring input, int parameter); - enum { ID_SELECTION, ID_VIEW }; -public: - - TriggerEntitySelector(TriggerBottomBar* parent, std::wstring label, const wxPoint& pos, - const wxSize& size, int parameter, callback func, void* data); - - void onSelectionClick(wxCommandEvent& WXUNUSED(evt)) - { - std::wstring code(L"["); - std::wstringstream stream; - for ( size_t i = 0; i < g_SelectedObjects.size(); ++i ) - { - stream << g_SelectedObjects[i]; - if ( i != g_SelectedObjects.size()-1 ) - stream << L", "; - } - - code.append(stream.str()); - code.append(L"]"); - (*m_Callback)(m_Data, code, m_Parameter); - POST_MESSAGE(SetSelectionPreview, (g_SelectedObjects)); - } - void onViewClick(wxCommandEvent& WXUNUSED(evt)); - -private: - int m_Parameter; - callback m_Callback; - TriggerBottomBar* m_Parent; - void* m_Data; - - DECLARE_EVENT_TABLE(); -}; -BEGIN_EVENT_TABLE(TriggerEntitySelector, wxPanel) -EVT_BUTTON(TriggerEntitySelector::ID_SELECTION, TriggerEntitySelector::onSelectionClick) -EVT_BUTTON(TriggerEntitySelector::ID_VIEW, TriggerEntitySelector::onViewClick) -END_EVENT_TABLE() - -class TriggerPointPlacer : public wxPanel -{ - enum { ID_Set, ID_View }; - typedef void (*callback)(void* data, std::wstring input, int parameter); -public: - - TriggerPointPlacer(wxWindow* parent, const wxPoint& pos, - const wxSize& size, int parameter, callback func, void* data) : m_Callback(func), - wxPanel(parent, wxID_ANY, pos), m_Parameter(parameter), m_Data(data) - { - wxBoxSizer* mainSizer = new wxBoxSizer(wxVERTICAL); - SetSizer(mainSizer); - mainSizer->Add( new wxButton(this, ID_Set, L"Set point", pos, size) ); - mainSizer->Add( new wxButton(this, ID_View, L"View", pos, size) ); - } - - - void onSet(wxCommandEvent& WXUNUSED(evt)) - { - qGetWorldPosition query( wxGetMousePosition().x, wxGetMousePosition().y ); - query.Post(); - Position pos = query.position; - wxString wxForm = wxString::Format(L"Vector(%f, %f, %f)", pos.type0.x, pos.type0.y, pos.type0.z); - - std::wstring convert = (std::wstring)wxForm; - (*m_Callback)(m_Data, convert, m_Parameter); - POST_MESSAGE(TriggerToggleSelector, (true, pos)); - } - - void onView(wxCommandEvent& WXUNUSED(evt)) - { - //POST_MESSAGE( TriggerToggleSelector, (pos) ); - } - -private: - int m_Parameter; - void* m_Data; - callback m_Callback; - bool m_MouseCapture; - - DECLARE_EVENT_TABLE(); -}; - -BEGIN_EVENT_TABLE(TriggerPointPlacer, wxPanel) -EVT_BUTTON(TriggerPointPlacer::ID_Set, TriggerPointPlacer::onSet) -EVT_BUTTON(TriggerPointPlacer::ID_View, TriggerPointPlacer::onView) -END_EVENT_TABLE() - - -class TriggerListCtrl : public wxListCtrl -{ -public: - TriggerListCtrl(wxWindow* parent, TriggerSidebar* sidebar, bool condition, wxWindowID id, const wxPoint& pos = wxDefaultPosition, - const wxSize& size = wxDefaultSize, long style = wxLC_ICON) - : wxListCtrl(parent, id, pos, size, style), m_Sidebar(sidebar), m_Condition(condition) - { - } - void onClick(wxMouseEvent& evt); - - TriggerSidebar* m_Sidebar; - bool m_Condition; -private: - DECLARE_EVENT_TABLE(); -}; -BEGIN_EVENT_TABLE(TriggerListCtrl, wxListCtrl) -EVT_LEFT_DOWN(TriggerListCtrl::onClick) -END_EVENT_TABLE() - - -class TriggerPage : public wxPanel -{ -public: - TriggerPage(wxWindow* parent, TriggerSidebar* sidebar, long ID, wxString title, bool condition) - : wxPanel(parent), m_Sidebar(sidebar), m_Condition(condition) - - { - wxBoxSizer* sizer = new wxBoxSizer(wxHORIZONTAL); - - m_List = new TriggerListCtrl(this, sidebar, condition, ID, wxDefaultPosition, - wxSize(132, 210), wxLC_REPORT | wxLC_SINGLE_SEL); - m_List->InsertColumn(0, title, wxLIST_FORMAT_LEFT, 100); - - sizer->Add(m_List); - SetSizer(sizer); - } - - wxListCtrl* m_List; - TriggerSidebar* m_Sidebar; - bool m_Condition; -}; - - -class TriggerItemData : public wxTreeItemData, public sTrigger -{ -public: - TriggerItemData(TriggerSidebar* sidebar, const std::wstring& name, bool group) - : m_Sidebar(sidebar), sTrigger(name), m_Group(group), m_CondCount(0), m_EffectCount(0) {} - TriggerItemData(TriggerSidebar* sidebar, const sTrigger& trigger, bool group) - : m_Sidebar(sidebar), sTrigger(trigger), m_Group(group), m_CondCount(0), m_EffectCount(0) {} - - TriggerSidebar* m_Sidebar; - size_t m_CondCount, m_EffectCount; - bool m_Group; - std::list m_BlockIndices, m_BlockEndIndices; //index in sidebar list - - void AddBlock(const int block, const int index) - { - std::vector copy = *logicBlocks; - std::vector notCopy = *logicNots; - copy.push_back(block); - notCopy.push_back(false); - - logicBlocks = copy; - logicNots = notCopy; - m_BlockIndices.push_back(index); - } - void AddBlockEnd(const int block, const int index) - { - std::vector copy = *logicBlockEnds; - copy.push_back(block); - logicBlockEnds = copy; - m_BlockEndIndices.push_back(index); - } - - void ResetBlockIndices() - { - std::vector newLogicBlocks, newLogicBlockEnds; - m_BlockIndices.clear(); - m_BlockEndIndices.clear(); - int conditionCount = 0; - - for (int i=0; im_ConditionPage->m_List->GetItemCount(); ++i) - { - if ( m_Sidebar->m_ConditionPage->m_List->GetItemText(i) == m_Sidebar->m_LogicBlockString ) - { - newLogicBlocks.push_back(conditionCount); - m_BlockIndices.push_back(i); - } - - //Block ends belong to current condition, hence conditionCount-1 - else if ( m_Sidebar->m_ConditionPage->m_List->GetItemText(i) == m_Sidebar->m_LogicBlockEndString ) - { - if ( conditionCount == 0 ) - newLogicBlockEnds.push_back(0); - else - newLogicBlockEnds.push_back(conditionCount-1); - m_BlockEndIndices.push_back(i); - } - else - ++conditionCount; - } - logicBlocks = newLogicBlocks; - logicBlockEnds = newLogicBlockEnds; - } -}; - - -void onTriggerParameter(void* data, std::wstring paramString, int parameter); - - -class TriggerBottomBar : public wxPanel -{ - enum { ID_TimeEdit, ID_CondNameEdit, ID_EffectNameEdit, ID_TriggerNameEdit, ID_RunsEdit, - ID_EffectChoice, ID_CondChoice, - ID_TimeRadio, ID_LogicRadio, - ID_NotCheck, ID_ActiveCheck, ID_LogicNotCheck }; - -public: - enum { NO_VIEW, TRIGGER_VIEW, CONDITION_VIEW, EFFECT_VIEW, LOGIC_END_VIEW, LOGIC_VIEW }; - - TriggerBottomBar(TriggerSidebar* sidebar, wxWindow* parent) - : wxPanel(parent), m_Sidebar(sidebar) - { - m_Sizer = new wxBoxSizer(wxHORIZONTAL); - SetSizer(m_Sizer); - m_DependentStatus = NO_VIEW; - } - - int GetDependentStatus() - { - return m_DependentStatus; - } - void SetSpecs(std::vector conditions, std::vector effects) - { - m_ConditionSpecs = conditions; - m_EffectSpecs = effects; - } - - wxArrayString GetConditionNames() - { - wxArrayString ret; - for ( size_t i = 0; i < m_ConditionSpecs.size(); ++i ) - ret.Add( wxString(m_ConditionSpecs[i].displayName.c_str()) ); - return ret; - } - wxArrayString GetEffectNames() - { - wxArrayString ret; - for ( size_t i = 0; i < m_EffectSpecs.size(); ++i ) - ret.Add( wxString(m_EffectSpecs[i].displayName.c_str()) ); - return ret; - } - - void onEffectChoice(wxCommandEvent& evt) - { - //Retrieve specification corresponding to selection - if ( m_Sidebar->m_SelectedEffect != -1 ) - { - std::vector::iterator it = std::find( m_EffectSpecs.begin(), - m_EffectSpecs.end(), std::wstring(evt.GetString()) ); - DisplayTriggerSpec(*it); - } - } - - void onCondChoice(wxCommandEvent& evt) - { - if ( m_Sidebar->m_SelectedCond != -1 ) - { - std::vector::iterator it = std::find( m_ConditionSpecs.begin(), - m_ConditionSpecs.end(), std::wstring(evt.GetString()) ); - DisplayTriggerSpec(*it); - } - } - - void onTimeEnter(wxCommandEvent& WXUNUSED(evt)) - { - float fValue; - std::wstringstream stream( std::wstring(m_TimeEdit->GetValue()) ); - stream >> fValue; - - if ( stream.fail() ) - { - wxBell(); - return; - } - - m_Sidebar->GetSelectedItemData()->timeValue = fValue; - wxString value = wxString::Format(L"%.2f", fValue); - m_TimeEdit->SetValue(value); - m_Sidebar->UpdateEngineData(); - } - - void onConditionEnter(wxCommandEvent& WXUNUSED(evt)) - { - if ( m_Sidebar->m_SelectedCond == -1 ) - return; - - std::vector conditions = *m_Sidebar->GetSelectedItemData()->conditions; - int condition = m_Sidebar->GetConditionCount(m_Sidebar->m_SelectedCond); - - if ( condition == 0 ) - conditions[0].name = std::wstring( m_ConditionEdit->GetValue() ); - else - conditions[condition-1] = std::wstring( m_ConditionEdit->GetValue() ); - - m_Sidebar->GetSelectedItemData()->conditions = conditions; - m_Sidebar->UpdateLists(); - m_Sidebar->UpdateEngineData(); - } - void onEffectEnter(wxCommandEvent& WXUNUSED(evt)) - { - if ( m_Sidebar->m_SelectedEffect== -1 ) - return; - - std::vector effects = *m_Sidebar->GetSelectedItemData()->effects; - effects[m_Sidebar->m_SelectedEffect].name = std::wstring( m_EffectEdit->GetValue() ); - m_Sidebar->GetSelectedItemData()->effects = effects; - m_Sidebar->UpdateLists(); - m_Sidebar->UpdateEngineData(); - } - void onTriggerEnter(wxCommandEvent& WXUNUSED(evt)) - { - TriggerItemData* data = m_Sidebar->GetSelectedItemData(); - if ( data == NULL || m_Sidebar->m_TriggerTree->GetSelection() == m_Sidebar->m_TriggerTree->GetRootItem() ) - return; - - wxString name = m_TriggerEdit->GetValue(); - data->name = std::wstring(name); - m_Sidebar->m_TriggerTree->SetItemText(m_Sidebar->m_TriggerTree->GetSelection(), name); - m_Sidebar->UpdateEngineData(); - } - - void onRunsEnter(wxCommandEvent& WXUNUSED(evt)) - { - int iValue; - std::wstringstream stream( std::wstring(m_RunsEdit->GetValue()) ); - stream >> iValue; - - if ( stream.fail() ) - { - wxBell(); - return; - } - - m_Sidebar->GetSelectedItemData()->maxRuns = iValue; - m_Sidebar->UpdateEngineData(); - } - - void onLogicRadio(wxCommandEvent& evt) - { - if ( m_Sidebar->m_SelectedCond == -1 ) - return; - std::vector conditions = *m_Sidebar->GetSelectedItemData()->conditions; - int condition = m_Sidebar->GetConditionCount(m_Sidebar->m_SelectedCond); - conditions[condition-1].linkLogic = evt.GetInt() + 1; - - m_Sidebar->GetSelectedItemData()->conditions = conditions; - m_Sidebar->UpdateLists(); - m_Sidebar->UpdateEngineData(); - } - void onActiveCheck(wxCommandEvent& evt) - { - m_Sidebar->GetSelectedItemData()->active = (evt.GetInt() == 1); - m_Sidebar->UpdateEngineData(); - } - void onNotCheck(wxCommandEvent& evt) - { - if ( m_Sidebar->m_SelectedCond == -1 ) - return; - std::vector conditions = *m_Sidebar->GetSelectedItemData()->conditions; - int condition = m_Sidebar->GetConditionCount(m_Sidebar->m_SelectedCond); - bool value = (evt.GetInt() == 1); - conditions[condition-1].negated = value; - - m_Sidebar->GetSelectedItemData()->conditions = conditions; - m_Sidebar->UpdateLists(); - m_Sidebar->UpdateEngineData(); - } - - void onLogicNotCheck(wxCommandEvent& evt) - { - TriggerItemData* data = m_Sidebar->GetSelectedItemData(); - - int logicIndex = m_Sidebar->GetLogicBlockCount(m_Sidebar->m_SelectedCond) - 1; - std::vector nots = *data->logicNots; - nots[logicIndex] = evt.IsChecked(); - data->logicNots = nots; - } - - void DisplayTriggerSpec(const sTriggerSpec& spec) - { - if ( m_Sizer->Detach(m_ParameterSizer) ) - { - m_ParameterSizer->DeleteWindows(); - delete m_ParameterSizer; - //m_Sizer->Layout(); - // Layout(); - } - - //m_ParameterSizer = new wxStaticBoxSizer(wxVERTICAL, this, L"Parameters"); - m_ParameterSizer = new wxBoxSizer(wxVERTICAL); - wxBoxSizer* hRow = NULL; - std::vector parameters = *spec.parameters; - std::vector stringParameters; - int row = -1; - - //Set parameter data to new data if change is needed - if ( m_Sidebar->m_Notebook->GetCurrentPage() == m_Sidebar->m_ConditionPage ) - { - std::vector conditions = *m_Sidebar->GetSelectedItemData()->conditions; - int condition = m_Sidebar->GetConditionCount(m_Sidebar->m_SelectedCond) - 1 ; - if ( *conditions[condition].displayName != *spec.displayName ) - { - std::vector newParameters(parameters.size()); - conditions[condition].parameters = newParameters; - conditions[condition].displayName = *spec.displayName; - conditions[condition].functionName = *spec.functionName; - m_Sidebar->GetSelectedItemData()->conditions = conditions; - m_Sidebar->UpdateEngineData(); - } - stringParameters = *(*m_Sidebar->GetSelectedItemData()->conditions) - [m_Sidebar->m_SelectedCond].parameters; - } - else - { - std::vector effects = *m_Sidebar->GetSelectedItemData()->effects; - if ( *effects[m_Sidebar->m_SelectedEffect].displayName != *spec.displayName ) - { - std::vector newParameters(parameters.size()); - effects[m_Sidebar->m_SelectedEffect].parameters = newParameters; - effects[m_Sidebar->m_SelectedEffect].displayName = *spec.displayName; - effects[m_Sidebar->m_SelectedEffect].functionName = *spec.functionName; - m_Sidebar->GetSelectedItemData()->effects = effects; - m_Sidebar->UpdateEngineData(); - } - stringParameters = *(*m_Sidebar->GetSelectedItemData()->effects) - [m_Sidebar->m_SelectedEffect].parameters; - } - - //Add all parameters to sizer - for ( std::vector::iterator it=parameters.begin(); it!=parameters.end(); ++it ) - { - if ( it->row != row ) - { - row = it->row; - hRow = new wxBoxSizer(wxHORIZONTAL); - m_ParameterSizer->Add(hRow); - } - - - if ( *it->windowType == std::wstring(L"text") ) - { - hRow->Add( new wxStaticText(this, wxID_ANY, wxString( (*it->name).c_str() ), - wxPoint(it->xPos, it->yPos)) ); - wxTextCtrl* text = new TriggerSpecText(this, L"", wxDefaultPosition, wxSize(it->xSize, it->ySize), - it->parameterOrder, *it->inputType, &onTriggerParameter, this); - - hRow->Add( text, 0, wxLEFT, 5 ); - wxString fill( stringParameters[it->parameterOrder].c_str() ); - - //Trim quotes - if ( *it->inputType == L"string" && fill.size() > 0 ) - { - fill.erase(0, 1); - fill.erase(fill.size()-1, 1); - } - text->SetValue(fill); - } - - else if ( *it->windowType == std::wstring(L"choice") ) - { - qGetTriggerChoices qChoices(*spec.functionName + *it->name); - qChoices.Post(); - std::vector choices = *qChoices.choices; - wxArrayString strings; - - for ( size_t i = 0; i < choices.size(); ++i ) - strings.Add( wxString(choices[i].c_str()) ); - - hRow->Add( new wxStaticText(this, wxID_ANY, wxString( (*it->name).c_str() ), - wxPoint(it->xPos, it->yPos)) ); - wxChoice* choice = new TriggerSpecChoice( this, L"", wxDefaultPosition, wxSize(it->xSize, it->ySize), - strings, it->parameterOrder, &onTriggerParameter, this ); - - hRow->Add(choice); - choice->SetStringSelection( wxString(stringParameters[it->parameterOrder].c_str()) ); - } - - else if ( *it->windowType == std::wstring(L"entity_selector") ) - { - hRow->Add( new wxStaticText(this, wxID_ANY, wxString((*it->name).c_str())) ); - hRow->Add( new TriggerEntitySelector(this, L"Select", wxDefaultPosition, - wxSize(it->xSize, it->ySize), it->parameterOrder, &onTriggerParameter, this) ); - } - - else if ( *it->windowType == std::wstring(L"point_placer") ) - { - hRow->Add( new wxStaticText(this, wxID_ANY, wxString((*it->name).c_str())) ); - hRow->Add( new TriggerPointPlacer(this, wxDefaultPosition, wxSize(it->xSize, it->ySize), - it->parameterOrder, &onTriggerParameter, this) ); - } - else - { - wxFAIL_MSG(L"Invalid window type for trigger specification"); - row = -1; - //do something else... - } - } - - //(If nothing was added, it won't be automatically delted) - if ( row < 0 ) - { - delete hRow; - delete m_ParameterSizer; - } - else - m_Sizer->Add(m_ParameterSizer, 0, wxLEFT, 5); - - m_Sizer->Layout(); - Layout(); - } - - void FillConditionData() - { - if ( m_Sidebar->m_SelectedCond == -1 ) - return; - - TriggerItemData* itemData = m_Sidebar->GetSelectedItemData(); - int iCondition = m_Sidebar->GetConditionCount(m_Sidebar->m_SelectedCond); - if ( iCondition <= 0 ) - return; - sTriggerCondition condition = (*itemData->conditions)[iCondition-1]; - wxString display( (*condition.displayName).c_str() ); - m_ConditionEdit->SetValue( wxString(condition.name.c_str()) ); - - if ( display != L"" ) - { - std::vector::iterator it = std::find( m_ConditionSpecs.begin(), - m_ConditionSpecs.end(), std::wstring(display) ); - if ( it != m_ConditionSpecs.end() ) - { - m_ConditionChoice->SetStringSelection(display); - DisplayTriggerSpec(*it); - } - } - else - m_ConditionChoice->SetStringSelection(display); - - if ( condition.linkLogic == 0 || condition.linkLogic == 1 ) - m_LogicRadio->SetSelection(0); - else - m_LogicRadio->SetSelection(1); - - m_NotCheck->SetValue(condition.negated); - } - - void FillEffectData() - { - TriggerItemData* itemData = m_Sidebar->GetSelectedItemData(); - sTriggerEffect effect = (*itemData->effects)[m_Sidebar->m_SelectedEffect]; - wxString display( (*effect.displayName).c_str() ); - - m_EffectEdit->SetValue( wxString(effect.name.c_str()) ); - if ( display != L"" ) - { - std::vector::iterator it = std::find( m_EffectSpecs.begin(), - m_EffectSpecs.end(), std::wstring(display) ); - if ( it != m_EffectSpecs.end() ) - { - m_EffectChoice->SetStringSelection(display); - DisplayTriggerSpec(*it); - } - } - //m_TimeRadio->SetSelection(effect.loop); - - float timeVal = itemData->timeValue; - wxString value = wxString::Format(L"%.2f", timeVal); - m_TimeEdit->SetValue(value); - } - - void FillTriggerData() - { - if ( m_DependentStatus != TRIGGER_VIEW ) - return; - TriggerItemData* itemData = m_Sidebar->GetSelectedItemData(); - m_TriggerEdit->SetValue( wxString( (*itemData->name).c_str()) ); - m_ActiveCheck->SetValue(itemData->active); - int runs = itemData->maxRuns; - m_RunsEdit->SetValue( wxString( wxString::Format(L"%d", runs)) ); - - } - - void FillLogicData() - { - std::vector nots = *m_Sidebar->GetSelectedItemData()->logicNots; - m_LogicNotCheck->SetValue( nots[m_Sidebar->GetLogicBlockCount(m_Sidebar->m_SelectedCond)-1] ); - } - - - void ToEffectView() - { - DestroyChildren(); - m_Sizer = new wxBoxSizer(wxHORIZONTAL); - m_DependentSizer = new wxStaticBoxSizer(wxVERTICAL, this, wxString(L"Trigger Editor")); - SetSizer(m_Sizer, true); - - m_DependentSizer = new wxStaticBoxSizer(wxVERTICAL, this, wxString(L"Trigger Editor")); - wxStaticText* name = new wxStaticText(this, wxID_ANY, wxString(L"Name:")); - wxStaticText* effect = new wxStaticText(this, wxID_ANY, wxString(L"Effect:")); - m_EffectEdit = new wxTextCtrl(this, ID_EffectNameEdit, _T(""), wxDefaultPosition, - wxSize(100, 18), wxTE_PROCESS_ENTER); - - wxArrayString effectNames = GetEffectNames(); - wxString radioChoice[] = { wxString(L"Delay"), wxString(L"Loop") }; - m_EffectChoice = new wxChoice(this, ID_EffectChoice, wxDefaultPosition, wxSize(100, 13), effectNames); - - m_TimeRadio = new wxRadioBox(this, ID_TimeRadio, _T("Execution type"), - wxDefaultPosition, wxDefaultSize, 2, radioChoice, 2, wxRA_SPECIFY_COLS); - - wxStaticText* time = new wxStaticText(this, wxID_ANY, wxString(L"Time:")); - m_TimeEdit = new wxTextCtrl(this, ID_TimeEdit, _T(""), wxDefaultPosition, - wxSize(100, 18), wxTE_PROCESS_ENTER); - - wxBoxSizer* hNameHolder = new wxBoxSizer(wxHORIZONTAL); - wxBoxSizer* hEffectHolder = new wxBoxSizer(wxHORIZONTAL); - wxBoxSizer* hTimeHolder = new wxBoxSizer(wxHORIZONTAL); - - hNameHolder->Add(name); - hNameHolder->Add(m_EffectEdit, 0, wxLEFT, 5); - hEffectHolder->Add(effect); - hEffectHolder->Add(m_EffectChoice, 0, wxLEFT, 5); - hTimeHolder->Add(time); - hTimeHolder->Add(m_TimeEdit, 0, wxLEFT, 5); - - m_DependentSizer->Add(hNameHolder, 0, wxTOP, 5); - m_DependentSizer->Add(hEffectHolder, 0, wxTOP, 5); - m_DependentSizer->Add(m_TimeRadio, 0, wxTOP | wxALIGN_CENTER, 10); - m_DependentSizer->Add(hTimeHolder, 0, wxTOP | wxALIGN_CENTER, 5); - - m_Sizer->Add(m_DependentSizer); - m_Sizer->Layout(); - Layout(); - m_DependentStatus = EFFECT_VIEW; - } - - void ToConditionView() - { - DestroyChildren(); - m_Sizer = new wxBoxSizer(wxHORIZONTAL); - m_DependentSizer = new wxStaticBoxSizer(wxVERTICAL, this, wxString(L"Trigger Editor")); - SetSizer(m_Sizer, true); - - wxStaticText* name = new wxStaticText(this, wxID_ANY, wxString(L"Name:")); - wxStaticText* condition = new wxStaticText(this, wxID_ANY, wxString(L"Condition:")); - m_ConditionEdit = new wxTextCtrl(this, ID_CondNameEdit, _T(""), wxDefaultPosition, - wxSize(100, 18), wxTE_PROCESS_ENTER); - - wxArrayString conditionNames = GetConditionNames(); - wxString radioChoice[] = { wxString(L"And"), wxString(L"Or") }; - m_ConditionChoice = new wxChoice(this, ID_CondChoice, wxDefaultPosition, - wxSize(100, 13), conditionNames); - - m_LogicRadio = new wxRadioBox(this, ID_LogicRadio, _T("Link logic:"), - wxDefaultPosition, wxDefaultSize, 2, radioChoice, 2, wxRA_SPECIFY_COLS); - - m_NotCheck = new wxCheckBox(this, ID_NotCheck, wxString(L"Not ")); - - wxBoxSizer* hNameHolder = new wxBoxSizer(wxHORIZONTAL); - wxBoxSizer* hConditionHolder = new wxBoxSizer(wxHORIZONTAL); - wxBoxSizer* hLogicHolder = new wxBoxSizer(wxHORIZONTAL); - - hNameHolder->Add(name); - hNameHolder->Add(m_ConditionEdit, 0, wxLEFT | wxALIGN_CENTER, 5); - hConditionHolder->Add(condition); - hConditionHolder->Add(m_ConditionChoice, 0, wxLEFT | wxALIGN_CENTER, 5); - hLogicHolder->Add(m_LogicRadio, 0, 0, 5); - hLogicHolder->Add(m_NotCheck, 0, wxLEFT | wxALIGN_CENTER, 5); - - m_DependentSizer->Add(hNameHolder, 0, wxTOP, 5); - m_DependentSizer->Add(hConditionHolder, 0, wxTOP, 5); - m_DependentSizer->Add(hLogicHolder, 0, wxALIGN_CENTER | wxTOP, 10); - - m_Sizer->Add(m_DependentSizer); - m_Sizer->Layout(); - Layout(); - m_DependentStatus = CONDITION_VIEW; - } - - void ToTriggerView() - { - DestroyChildren(); - m_Sizer = new wxBoxSizer(wxHORIZONTAL); - m_DependentSizer = new wxStaticBoxSizer(wxVERTICAL, this, wxString(L"Trigger Editor")); - SetSizer(m_Sizer, true); - - wxStaticText* name = new wxStaticText(this, wxID_ANY, wxString(L"Name:")); - m_TriggerEdit = new wxTextCtrl(this, ID_TriggerNameEdit, _T(""), wxDefaultPosition, - wxSize(100, 18), wxTE_PROCESS_ENTER); - - wxStaticText* runs = new wxStaticText(this, wxID_ANY, wxString(L"Maximum runs:")); - m_RunsEdit = new wxTextCtrl(this, ID_RunsEdit, wxString(L"-1"), wxDefaultPosition, wxSize(100, 18)); - m_ActiveCheck = new wxCheckBox(this, ID_ActiveCheck, wxString(L"Active: ")); - - wxBoxSizer* nameHolder = new wxBoxSizer(wxHORIZONTAL), *runsHolder = new wxBoxSizer(wxHORIZONTAL); - - nameHolder->Add(name); - nameHolder->Add(m_TriggerEdit, 0, wxLEFT, 5); - runsHolder->Add(runs); - runsHolder->Add(m_RunsEdit, 0, wxLEFT, 5); - - m_DependentSizer->Add(nameHolder); - m_DependentSizer->Add(runsHolder, 0, wxTOP, 5); - m_DependentSizer->Add(m_ActiveCheck, 0, wxTOP, 5); - - m_Sizer->Add(m_DependentSizer); - m_Sizer->Layout(); - Layout(); - m_DependentStatus = TRIGGER_VIEW; - } - //void ToLogicEndView(); - - void ToLogicView() - { - DestroyChildren(); - m_Sizer = new wxBoxSizer(wxHORIZONTAL); - m_DependentSizer = new wxStaticBoxSizer(wxVERTICAL, this, wxString(L"Trigger Editor")); - SetSizer(m_Sizer, true); - - m_LogicNotCheck = new wxCheckBox(this, ID_LogicNotCheck, L"Not"); - m_DependentSizer->Add(m_LogicNotCheck); - m_Sizer->Add(m_DependentSizer, 0, wxTOP | wxLEFT | wxALIGN_LEFT, 10); - m_Sizer->Layout(); - Layout(); - m_DependentStatus = LOGIC_VIEW; - } - void ToNoView() - { - if ( m_DependentStatus == NO_VIEW ) - return; - DestroyChildren(); - m_DependentStatus = NO_VIEW; - m_Sidebar->m_ConditionPage->m_List->DeleteAllItems(); - m_Sidebar->m_EffectPage->m_List->DeleteAllItems(); - } - - TriggerSidebar* m_Sidebar; - -private: - - wxBoxSizer* m_Sizer, *m_ParameterSizer; - wxStaticBoxSizer* m_DependentSizer; //dependent = effect/condition - - wxTextCtrl* m_TimeEdit, *m_ConditionEdit, *m_EffectEdit, *m_TriggerEdit, *m_RunsEdit; - wxCheckBox* m_ActiveCheck, *m_NotCheck, *m_LogicNotCheck; - wxChoice* m_ConditionChoice, *m_EffectChoice; - wxRadioBox* m_LogicRadio, *m_TimeRadio, m_LogicEndRadio; - - std::vector m_ConditionSpecs, m_EffectSpecs; - - int m_DependentStatus; - - DECLARE_EVENT_TABLE(); -}; - - -BEGIN_EVENT_TABLE(TriggerBottomBar, wxPanel) -EVT_TEXT_ENTER(TriggerBottomBar::ID_TimeEdit, TriggerBottomBar::onTimeEnter) -EVT_TEXT_ENTER(TriggerBottomBar::ID_CondNameEdit, TriggerBottomBar::onConditionEnter) -EVT_TEXT_ENTER(TriggerBottomBar::ID_EffectNameEdit, TriggerBottomBar::onEffectEnter) -EVT_TEXT_ENTER(TriggerBottomBar::ID_TriggerNameEdit, TriggerBottomBar::onTriggerEnter) -EVT_TEXT_ENTER(TriggerBottomBar::ID_RunsEdit, TriggerBottomBar::onRunsEnter) -EVT_CHOICE(TriggerBottomBar::ID_EffectChoice, TriggerBottomBar::onEffectChoice) -EVT_CHOICE(TriggerBottomBar::ID_CondChoice, TriggerBottomBar::onCondChoice) - -EVT_RADIOBOX(TriggerBottomBar::ID_LogicRadio, TriggerBottomBar::onLogicRadio) -EVT_CHECKBOX(TriggerBottomBar::ID_ActiveCheck, TriggerBottomBar::onActiveCheck) -EVT_CHECKBOX(TriggerBottomBar::ID_NotCheck, TriggerBottomBar::onNotCheck) -EVT_CHECKBOX(TriggerBottomBar::ID_LogicNotCheck, TriggerBottomBar::onLogicNotCheck) -//EVT_RADIOBOX(TriggerBotomBar::ID_TimeRadio, TriggerBottomBar::onTimeRadio) -END_EVENT_TABLE() - - -void TriggerTreeCtrl::onClick(wxMouseEvent& evt) -{ - if ( m_Sidebar->m_TriggerTree->GetSelection() == m_Sidebar->m_TriggerTree->GetRootItem() || - !m_Sidebar->m_TriggerTree->GetSelection() ) - { - m_Sidebar->m_TriggerBottom->ToNoView(); - } - else - { - m_Sidebar->m_TriggerBottom->ToTriggerView(); - m_Sidebar->m_TriggerBottom->FillTriggerData(); - } - evt.Skip(); -} - -void TriggerListCtrl::onClick(wxMouseEvent& evt) -{ - evt.Skip(); - if ( m_Condition ) - { - if ( m_Sidebar->m_SelectedCond < 0 ) - return; - - if ( m_Sidebar->m_ConditionPage->m_List->GetItemText(m_Sidebar->m_SelectedCond) - == m_Sidebar->m_LogicBlockEndString ) - { - m_Sidebar->m_TriggerBottom->ToNoView(); - } - else if ( m_Sidebar->m_ConditionPage->m_List->GetItemText(m_Sidebar->m_SelectedCond) - == m_Sidebar->m_LogicBlockString ) - { - m_Sidebar->m_TriggerBottom->ToLogicView(); - m_Sidebar->m_TriggerBottom->FillLogicData(); - } - else - { - m_Sidebar->m_TriggerBottom->ToConditionView(); - m_Sidebar->m_TriggerBottom->FillConditionData(); - } - } - else - { - m_Sidebar->m_TriggerBottom->ToEffectView(); - if ( m_Sidebar->m_SelectedEffect != -1 ) - m_Sidebar->m_TriggerBottom->FillEffectData(); - } - -} - - -TriggerEntitySelector::TriggerEntitySelector(TriggerBottomBar* parent, std::wstring label, - const wxPoint& pos, const wxSize& size, int parameter, callback func, void* data) - : wxPanel(parent), m_Parent(parent), m_Parameter(parameter), m_Callback(func), m_Data(data) -{ - wxBoxSizer* MainSizer = new wxBoxSizer(wxVERTICAL); - SetSizer(MainSizer); - MainSizer->Add( new wxButton(this, ID_SELECTION, wxString(label.c_str()), pos, size) ); - MainSizer->Add( new wxButton(this, ID_VIEW, L"View", pos, size) ); -} -void TriggerEntitySelector::onViewClick(wxCommandEvent& WXUNUSED(evt)) -{ - std::wstring handles; - if ( m_Parent->m_Sidebar->m_Notebook->GetCurrentPage() == m_Parent->m_Sidebar->m_ConditionPage ) - { - std::vector conditions = *m_Parent->m_Sidebar->GetSelectedItemData()->conditions; - int condition = m_Parent->m_Sidebar->GetConditionCount(m_Parent->m_Sidebar->m_SelectedCond) - 1 ; - std::vector parameters = *conditions[condition].parameters; - handles = parameters[m_Parameter]; - } - else - { - std::vector effects = *m_Parent->m_Sidebar->GetSelectedItemData()->effects; - int effect = m_Parent->m_Sidebar->m_SelectedEffect; - std::vector parameters = *effects[effect].parameters; - handles = parameters[m_Parameter]; - } - - std::vector IDList; - size_t previous = handles.find(L"[")+1, current; - - //remove "]" - if ( handles.size() ) - handles.erase(handles.size()-1); - - while ( (current = handles.find(L", ", previous)) != std::wstring::npos ) - { - std::wstringstream toInt(handles.substr(previous, current - previous)); - int newID; - toInt >> newID; - IDList.push_back(newID); - previous = current+1; - } - - std::wstringstream toInt( handles.substr(previous) ); - int newID; - toInt >> newID; - IDList.push_back(newID); - g_SelectedObjects = IDList; - POST_MESSAGE(SetSelectionPreview, (g_SelectedObjects)); -} - -void TriggerSpecText::onTextEnter(wxCommandEvent& WXUNUSED(evt)) -{ - std::wstring text( GetValue().wc_str() ); - - if ( VerifyInput(text) ) - (*m_Callback)(m_Data, text, m_Parameter ); - else - wxBell(); -} - -TriggerSpecChoice::TriggerSpecChoice(TriggerBottomBar* parent, std::wstring label, const wxPoint& pos, - const wxSize& size, const wxArrayString& strings, int parameter, callback func, void* data) - : wxChoice(parent, wxID_ANY, pos, size, strings), m_Callback(func), m_Data(data), - m_Parent(parent), m_Parameter(parameter) - { - } -void TriggerSpecChoice::onChoice(wxCommandEvent& evt) -{ - (*m_Callback)(m_Data, std::wstring( evt.GetString().wc_str() ), m_Parameter); -} -void onTriggerParameter(void* data, std::wstring paramString, int parameter) -{ - TriggerBottomBar* bottomBar = static_cast(data); - - if ( bottomBar->m_Sidebar->m_Notebook->GetSelection() == 0 ) - { - if ( bottomBar->m_Sidebar->m_SelectedCond == -1 ) - return; - std::vector conditions = *bottomBar->m_Sidebar->GetSelectedItemData()->conditions; - std::vector parameters = *conditions[bottomBar->m_Sidebar->m_SelectedCond].parameters; - - parameters[parameter] = paramString; - conditions[bottomBar->m_Sidebar->m_SelectedCond].parameters = parameters; - bottomBar->m_Sidebar->GetSelectedItemData()->conditions = conditions; - } - else - { - if ( bottomBar->m_Sidebar->m_SelectedEffect == -1 ) - return; - std::vector effects = *bottomBar->m_Sidebar->GetSelectedItemData()->effects; - std::vector parameters = *effects[bottomBar->m_Sidebar->m_SelectedEffect].parameters; - - parameters[parameter] = paramString; - effects[bottomBar->m_Sidebar->m_SelectedEffect].parameters = parameters; - bottomBar->m_Sidebar->GetSelectedItemData()->effects = effects; - } - bottomBar->m_Sidebar->UpdateEngineData(); -} - -void onGroupPush(void* data) -{ - TriggerSidebar* sidebar = static_cast(data); - if ( !sidebar->m_TriggerTree->GetSelection()) - return; - if ( !sidebar->IsGroupSelected() ) - return; - - wxString name = wxString::Format(L"Group %d", sidebar->m_GroupCount); - wxTreeItemId ID = sidebar->m_TriggerTree->AppendItem( sidebar->m_TriggerTree->GetSelection(), - name, -1, -1, new TriggerItemData(sidebar, std::wstring(name), true) ); - sidebar->m_TriggerTree->EnsureVisible(ID); - ++sidebar->m_GroupCount; - - sidebar->UpdateEngineData(); -} - -void onTriggerPush(void* data) -{ - TriggerSidebar* sidebar = static_cast(data); - wxTreeItemId ID = sidebar->m_TriggerTree->GetSelection(); - - if ( !sidebar->IsGroupSelected() ) - ID = sidebar->m_TriggerTree->GetItemParent(ID); - - wxString name = wxString::Format(L"Trigger %d", sidebar->m_TriggerCount); - TriggerItemData* itemData = new TriggerItemData(sidebar, std::wstring(name), false); - itemData->group = std::wstring( sidebar->m_TriggerTree->GetItemText(ID) ); - - ID = sidebar->m_TriggerTree->AppendItem(ID, name, -1, -1, itemData); - sidebar->m_TriggerTree->Expand( sidebar->m_TriggerTree->GetRootItem() ); - - ++sidebar->m_TriggerCount; - sidebar->m_TriggerTree->SelectItem(ID); - sidebar->UpdateEngineData(); -} - -void onDeleteTreePush(void* data) -{ - TriggerSidebar* sidebar = static_cast(data); - if ( sidebar->m_TriggerTree->GetSelection() == sidebar->m_TriggerTree->GetRootItem() ) - return; - - if ( wxMessageBox( wxString(L"Are you sure you want to delete this item?"), - wxString(L"Caution"), wxYES_NO ) == wxYES ) - { - sidebar->m_TriggerTree->Delete(sidebar->m_TriggerTree->GetSelection()); - sidebar->m_TriggerTree->EnsureVisible( sidebar->m_TriggerTree->GetRootItem() ); - sidebar->m_TriggerBottom->FillTriggerData(); - } - - sidebar->UpdateEngineData(); -} - -void onConditionPush(void* data) -{ - TriggerSidebar* sidebar = static_cast(data); - if ( sidebar->IsGroupSelected() ) - return; - - sidebar->m_Notebook->SetSelection(0); - TriggerItemData* itemData = sidebar->GetSelectedItemData(); - std::wstring name = std::wstring( wxString::Format(L"Condition %d", itemData->m_CondCount).wc_str() ); - - if ( itemData->m_CondCount == 0 ) - sidebar->m_SelectedCond = 0; - - ++itemData->m_CondCount; - - std::vector conditions = *itemData->conditions; - conditions.push_back( sTriggerCondition(name) ); - itemData->conditions = conditions; - - long count = sidebar->m_ConditionPage->m_List->GetItemCount(); - - sidebar->m_ConditionPage->m_List->InsertItem(count, wxString(name.c_str()) ); - sidebar->m_ConditionPage->m_List->EnsureVisible(count); - sidebar->m_ConditionPage->m_List->SetItemState(count, wxLIST_STATE_SELECTED, wxLIST_STATE_SELECTED); - - sidebar->m_TriggerBottom->ToConditionView(); //Some data is not valid, so reset - sidebar->m_TriggerBottom->FillConditionData(); - - sidebar->UpdateEngineData(); -} - -void onEffectPush(void* data) -{ - TriggerSidebar* sidebar = static_cast(data); - if ( sidebar->IsGroupSelected() ) - return; - - sidebar->m_Notebook->SetSelection(1); - TriggerItemData* itemData = sidebar->GetSelectedItemData(); - std::wstring name = std::wstring( wxString::Format(L"Effect %d", itemData->m_EffectCount).wc_str() ); - - if ( itemData->m_EffectCount == 0 ) - sidebar->m_SelectedEffect = 0; - ++itemData->m_EffectCount; - - std::vector effects = *itemData->effects; - effects.push_back( sTriggerEffect(name) ); - itemData->effects = effects; - - long count = sidebar->m_EffectPage->m_List->GetItemCount(); - sidebar->m_EffectPage->m_List->InsertItem(count, wxString(name.c_str()) ); - sidebar->m_EffectPage->m_List->EnsureVisible(count); - sidebar->m_EffectPage->m_List->SetItemState(count, wxLIST_STATE_SELECTED, wxLIST_STATE_SELECTED); - - sidebar->m_TriggerBottom->ToEffectView(); - sidebar->m_TriggerBottom->FillEffectData(); - - sidebar->UpdateEngineData(); -} - -void onDeleteBookPush(void* data) -{ - TriggerSidebar* sidebar = static_cast(data); - wxListCtrl* list = static_cast(sidebar->m_Notebook->GetCurrentPage())->m_List; - if ( !list ) - return; - - TriggerItemData* itemData = sidebar->GetSelectedItemData(); - //Is condition? -- valid selection? - if ( list == sidebar->m_ConditionPage->m_List && sidebar->m_SelectedCond != -1 ) - { - std::wstring text(sidebar->m_ConditionPage->m_List->GetItemText(sidebar->m_SelectedCond) ); - int conditionCount = sidebar->GetConditionCount(sidebar->m_SelectedCond); - - if ( text == std::wstring(sidebar->m_LogicBlockString.wc_str()) ) - { - std::vector blocks = *itemData->logicBlocks; - if ( conditionCount == 0 ) - { - blocks.erase( std::find(blocks.begin(), blocks.end(), 0) ); - itemData->m_BlockIndices.erase( std::find( itemData->m_BlockIndices.begin(), - itemData->m_BlockIndices.end(), sidebar->m_SelectedCond ) ); - } - else - { - blocks.erase( std::find(blocks.begin(), blocks.end(), conditionCount) ); - itemData->m_BlockIndices.erase( std::find( itemData->m_BlockIndices.begin(), - itemData->m_BlockIndices.end(), sidebar->m_SelectedCond ) ); - } - itemData->logicBlocks = blocks; - } - - else if ( text == std::wstring(sidebar->m_LogicBlockEndString.wc_str()) ) - { - std::vector blockEnds = *itemData->logicBlockEnds; - if ( conditionCount == 0 ) - { - blockEnds.erase( std::find(blockEnds.begin(), blockEnds.end(), 0) ); - itemData->m_BlockEndIndices.erase( std::find( itemData->m_BlockEndIndices.begin(), - itemData->m_BlockEndIndices.end(), sidebar->m_SelectedCond ) ); - } - else - { - blockEnds.erase( std::find(blockEnds.begin(), blockEnds.end(), conditionCount-1) ); - itemData->m_BlockEndIndices.erase( std::find( itemData->m_BlockEndIndices.begin(), - itemData->m_BlockEndIndices.end(), sidebar->m_SelectedCond ) ); - } - itemData->logicBlockEnds = blockEnds; - } - - else - { - std::vector conditions = *itemData->conditions; - conditions.erase( std::find(conditions.begin(), conditions.end(), text) ); - itemData->conditions = conditions; - } - - list->DeleteItem( sidebar->m_SelectedCond ); - itemData->ResetBlockIndices(); - - if ( sidebar->m_SelectedCond == list->GetItemCount() ) - { - sidebar->m_SelectedCond = -1; - sidebar->m_TriggerBottom->ToNoView(); - } - else - sidebar->m_TriggerBottom->FillConditionData(); - } - - else if ( list == sidebar->m_EffectPage->m_List && sidebar->m_SelectedEffect != -1) - { - std::vector effects = *itemData->effects; - effects.erase( std::find( effects.begin(), effects.end(), std::wstring( - list->GetItemText(sidebar->m_SelectedEffect)) ) ); - itemData->effects = effects; - - list->DeleteItem( sidebar->m_SelectedEffect ); - - if ( itemData->effects.GetSize() == 0 || sidebar->m_SelectedEffect == list->GetItemCount() ) - { - sidebar->m_SelectedEffect = -1; - sidebar->m_TriggerBottom->ToNoView(); - } - else - sidebar->m_TriggerBottom->FillEffectData(); - } - sidebar->UpdateLists(); - sidebar->UpdateEngineData(); -} - -void onLogicBlockPush(void* data) -{ - TriggerSidebar* sidebar = static_cast(data); - sidebar->m_Notebook->SetSelection(0); - - if ( sidebar->IsGroupSelected() ) - return; - - int limit = sidebar->m_SelectedCond; - if ( sidebar->m_SelectedCond == -1 ) - limit = sidebar->m_ConditionPage->m_List->GetItemCount()-1; - - int conditionCount = sidebar->GetConditionCount(limit); - if ( conditionCount == 0 ) - { - sidebar->GetSelectedItemData()->AddBlock(0, 0); - sidebar->UpdateLists(); - return; - } - - sidebar->GetSelectedItemData()->AddBlock(conditionCount, limit); - sidebar->UpdateLists(); - sidebar->m_TriggerBottom->ToLogicView(); //Some data is not valid, so reset - sidebar->m_TriggerBottom->FillLogicData(); - sidebar->UpdateEngineData(); -} - -void onBlockEndPush(void* data) -{ - TriggerSidebar* sidebar = static_cast(data); - sidebar->m_Notebook->SetSelection(0); - - if ( sidebar->IsGroupSelected() ) - return; - - int limit = sidebar->m_SelectedCond; - if ( sidebar->m_SelectedCond == -1 ) - limit = sidebar->m_ConditionPage->m_List->GetItemCount()-1; - - int conditionCount = sidebar->GetConditionCount(limit); - if ( conditionCount == 0 ) - { - sidebar->GetSelectedItemData()->AddBlockEnd(0, 0); - sidebar->UpdateLists(); - return; - } - - sidebar->GetSelectedItemData()->AddBlockEnd(conditionCount-1, limit); - sidebar->UpdateLists(); -} - - -TriggerSidebar::TriggerSidebar(ScenarioEditor& scenarioEditor, wxWindow* sidebarContainer, wxWindow* bottomBarContainer) -: Sidebar(scenarioEditor, sidebarContainer, bottomBarContainer), m_GroupCount(0), m_TriggerCount(0), - m_SelectedCond(-1), m_SelectedEffect(-1) -{ - m_TriggerBottom = new TriggerBottomBar(this, bottomBarContainer); - m_BottomBar = m_TriggerBottom; - - m_TriggerTree = new TriggerTreeCtrl(this, wxID_ANY, wxDefaultPosition, - wxSize(140, 220), wxTR_HAS_BUTTONS | wxTR_EDIT_LABELS); - m_TriggerTree->AddRoot(L"Triggers", -1, -1, new TriggerItemData(this, L"Triggers", true)); - m_TriggerTree->SelectItem( m_TriggerTree->GetRootItem() ); - m_TriggerTree->Expand( m_TriggerTree->GetRootItem() ); - - - wxBoxSizer* hHolder = new wxBoxSizer(wxHORIZONTAL); - wxBoxSizer* vHolder = new wxBoxSizer(wxVERTICAL); - wxBoxSizer* vButtons = new wxBoxSizer(wxVERTICAL); - - ActionButton* trigButton = new ActionButton( this, L"Trigger", &onTriggerPush, - this, wxSize(50, 20) ); - ActionButton* groupButton = new ActionButton( this, L"Group", &onGroupPush, - this, wxSize(50, 20) ); - ActionButton* deleteButton = new ActionButton( this, L"Delete", &onDeleteTreePush, - this, wxSize(50, 20) ); - - ActionButton* conditionButton = new ActionButton( this, L"Condition", - &onConditionPush, this, wxSize(54, 20) ); - ActionButton* effectButton = new ActionButton( this, L"Effect", - &onEffectPush, this, wxSize(50, 20) ); - ActionButton* bookDelete = new ActionButton( this, L"Delete", - &onDeleteBookPush, this, wxSize(50, 20) ); - ActionButton* logicBlock = new ActionButton( this, L"Block", - &onLogicBlockPush, this, wxSize(50, 20) ); - ActionButton* logicBlockEnd = new ActionButton( this, L"Block End", - &onBlockEndPush, this, wxSize(50, 20) ); - - - m_LogicBlockString = wxString(L"--------------------"); - m_LogicBlockEndString = wxString(L"==========="); - wxStaticText* bottomTitle = new wxStaticText( this, wxID_ANY, _T("Conditions and Effects") ); - m_Notebook = new wxNotebook(this, wxID_ANY, wxDefaultPosition, - wxSize(132, 210), wxNB_TOP); - - m_ConditionPage = new TriggerPage(m_Notebook, this, ID_CondList, wxString(L"Conditions"), true); - m_EffectPage = new TriggerPage(m_Notebook, this, ID_EffectList, wxString(L"Effects"), false); - - m_Notebook->AddPage( m_ConditionPage, _T("Conditions") ); - m_Notebook->AddPage( m_EffectPage, _T("Effects") ); - m_Notebook->SetPageSize(wxSize(130, 240)); - - vButtons->Add(trigButton); - vButtons->Add(groupButton); - vButtons->Add(deleteButton); - vButtons->Add(conditionButton, 0, wxTOP, 190); - vButtons->Add(effectButton); - vButtons->Add(bookDelete); - vButtons->Add(logicBlock); - vButtons->Add(logicBlockEnd); - - vHolder->Add(m_TriggerTree, 0, wxTOP, 15); - vHolder->Add(bottomTitle, 0, wxALIGN_CENTER | wxTOP, 5); - vHolder->Add(m_Notebook, 0, wxTOP, 5 ); - - hHolder->Add(vHolder); - hHolder->Add(vButtons, 0, wxALIGN_CENTER); - m_MainSizer->Add(hHolder); -} - -int TriggerSidebar::GetConditionCount(int limit) -{ - int conditionCount = 0; - wxListCtrl* list = m_ConditionPage->m_List; - for ( int i = 0; i <= limit; ++i ) - { - if ( list->GetItemText(i) != m_LogicBlockString && list->GetItemText(i) != m_LogicBlockEndString) - ++conditionCount; - } - return conditionCount; -} - -int TriggerSidebar::GetLogicBlockCount(int limit) -{ - int logicCount = 0; - wxListCtrl* list = m_ConditionPage->m_List; - for ( int i = 0; i <= limit; ++i ) - { - if ( list->GetItemText(i) == m_LogicBlockString ) - ++logicCount; - } - return logicCount; -} -void TriggerSidebar::OnFirstDisplay() -{ - qGetTriggerData dataQuery; - dataQuery.Post(); - m_TriggerBottom->SetSpecs(*dataQuery.conditions, *dataQuery.effects); - - //Add all loaded triggers to the tree - const std::vector triggerGroups = *dataQuery.groups; - std::vector::const_iterator it = std::find( triggerGroups.begin(), - triggerGroups.end(), std::wstring(L"Triggers") ); - - if ( it != triggerGroups.end() ) - { - wxTreeItemId invalid; - AddGroupTree(*it, invalid); - m_TriggerTree->Expand( m_TriggerTree->GetRootItem() ); - } -} - -void TriggerSidebar::AddGroupTree(const sTriggerGroup& group, wxTreeItemId parent) -{ - wxTreeItemId newID; - wxString text( (*group.name).c_str() ); - - //Make sure root item doesn't already exist - if ( !parent && !m_TriggerTree->GetRootItem() ) - newID = m_TriggerTree->AddRoot(text, -1, -1, new TriggerItemData(this, *group.name, true)); - else if ( parent ) - newID = m_TriggerTree->AppendItem(parent, text); - else - newID = m_TriggerTree->GetRootItem(); - - const std::vector triggerBuf = *group.triggers; - const std::vector groupBuf = *group.children; - - for ( size_t i = 0; i < group.children.GetSize(); ++i ) - AddGroupTree( *std::find(m_TriggerGroups.begin(), m_TriggerGroups.end(), groupBuf[i]), newID ); - - for ( size_t i = 0; i < group.triggers.GetSize(); ++i ) - { - std::wstring trigName = *triggerBuf[i].name; - size_t condMax = 0, effectMax = 0; - - //Make triggers start where user last left off - if ( trigName.find(L"Trigger ") == 0 ) - { - trigName.erase(0, 8); //remove "Trigger " - std::wstringstream toInt(trigName); - size_t convert; - toInt >> convert; - ++convert; - - if ( !toInt.fail() ) - { - if ( convert > m_TriggerCount ) - m_TriggerCount = convert; - } - } - std::vector conditions = *triggerBuf[i].conditions; - std::vector effects = *triggerBuf[i].effects; - - for ( size_t j = 0; j < conditions.size(); ++j ) - { - std::wstring condName = *conditions[j].name; - - if ( condName.find(L"Condition ") == 0 ) - { - condName.erase(0, 10); - std::wstringstream toInt(condName); - size_t convert; - toInt >> convert; - ++convert; - - if ( !toInt.fail() ) - { - if ( convert > condMax ) - condMax = convert; - } - } - } - - for ( size_t j = 0; j < effects.size(); ++j ) - { - std::wstring effectName = *effects[j].name; - - if ( effectName .find(L"Effect ") == 0 ) - { - effectName.erase(0, 7); - std::wstringstream toInt(effectName); - size_t convert; - toInt >> convert; - ++convert; - - if ( !toInt.fail() ) - { - if ( convert > effectMax ) - effectMax = convert; - } - } - } - TriggerItemData* newTriggerData = new TriggerItemData(this, triggerBuf[i], false); - newTriggerData->m_CondCount = condMax; - newTriggerData->m_EffectCount = effectMax; - m_TriggerTree->AppendItem( newID, wxString( triggerBuf[i].name.c_str() ), -1, -1, newTriggerData); - } -} - - -void TriggerSidebar::onPageChange(wxNotebookEvent& evt) -{ - if ( evt.GetSelection() == 0 ) - { - m_TriggerBottom->ToConditionView(); - if ( m_SelectedCond != -1 ) - m_TriggerBottom->FillConditionData(); - return; - } - m_TriggerBottom->ToEffectView(); - if ( m_SelectedEffect != -1 ) - m_TriggerBottom->FillEffectData(); -} - -void TriggerSidebar::onTreeDrag(wxTreeEvent& WXUNUSED(evt)) -{ - //evt.Allow(); -} - -void TriggerSidebar::onTreeNameChange(wxTreeEvent& evt) -{ - ToDerived( m_TriggerTree->GetItemData(evt.GetItem()) )->name = std::wstring( - evt.GetLabel().wc_str()); - UpdateEngineData(); -} - -void TriggerSidebar::onTreeSelChange(wxTreeEvent& evt) -{ - //Prevent other triggers from trying to use previous data - m_SelectedCond = -1; - m_SelectedEffect = -1; - - if ( evt.GetItem() == m_TriggerTree->GetRootItem() ) - { - m_TriggerBottom->ToNoView(); - return; - } - - if ( m_TriggerBottom->GetDependentStatus() != TriggerBottomBar::TRIGGER_VIEW ) - m_TriggerBottom->ToTriggerView(); - m_TriggerBottom->FillTriggerData(); - - UpdateLists(); -} -void TriggerSidebar::UpdateLists() -{ - TriggerItemData* data = GetSelectedItemData(); - m_ConditionPage->m_List->Freeze(); - m_ConditionPage->m_List->DeleteAllItems(); - m_EffectPage->m_List->Freeze(); - m_EffectPage->m_List->DeleteAllItems(); - - const Shareable* conditions = data->conditions.GetBuffer(); - for ( size_t i = 0; i < data->conditions.GetSize(); ++i ) - { - m_ConditionPage->m_List->InsertItem( m_ConditionPage->m_List-> - GetItemCount(), wxString(conditions[i]->name.c_str()) ); - } - - const Shareable* effects = data->effects.GetBuffer(); - for ( size_t i = 0; i < data->effects.GetSize(); ++i ) - { - m_EffectPage->m_List->InsertItem(m_EffectPage->m_List->GetItemCount(), - wxString(effects[i]->name.c_str()) ); - } - - //These must be merged and sorted because adding them out-of-order screws up the list - std::list sortedBlocks; - std::list blocks = data->m_BlockIndices, blockEnds = data->m_BlockEndIndices; - - for ( std::list::iterator it = blocks.begin(); it != blocks.end(); ++it ) - sortedBlocks.push_back( LogicBlockHelper(*it, false) ); - for ( std::list::iterator it = blockEnds.begin(); it != blockEnds.end(); ++it ) - sortedBlocks.push_back( LogicBlockHelper(*it, true) ); - - sortedBlocks.sort(); - for ( std::list::iterator it = sortedBlocks.begin(); it != sortedBlocks.end(); ++it ) - { - if ( it->end ) - m_ConditionPage->m_List->InsertItem(it->index, m_LogicBlockEndString); - else - m_ConditionPage->m_List->InsertItem(it->index, m_LogicBlockString); - } - - m_ConditionPage->m_List->Thaw(); - m_EffectPage->m_List->Thaw(); -} - -void TriggerSidebar::onCondSelect(wxListEvent& evt) -{ - m_SelectedCond = evt.GetIndex(); - //if ( m_TriggerBottom->GetDependentStatus() != TriggerBottomBar::CONDITION_VIEW ) - if ( m_ConditionPage->m_List->GetItemText(m_SelectedCond) - == m_LogicBlockEndString ) - { - m_TriggerBottom->ToNoView(); - } - else if ( m_ConditionPage->m_List->GetItemText(m_SelectedCond) - == m_LogicBlockString ) - { - m_TriggerBottom->ToLogicView(); - - if ( m_SelectedCond != -1 ) - m_TriggerBottom->FillLogicData(); - } - else - { - m_TriggerBottom->ToConditionView(); - if ( m_SelectedCond != -1 ) - m_TriggerBottom->FillConditionData(); - } -} -void TriggerSidebar::onEffectSelect(wxListEvent& evt) -{ - m_SelectedEffect = evt.GetIndex(); - //if ( m_TriggerBottom->GetDependentStatus() != TriggerBottomBar::EFFECT_VIEW ) - m_TriggerBottom->ToEffectView(); - m_TriggerBottom->FillEffectData(); -} - -bool TriggerSidebar::IsGroupSelected() -{ - if ( ToDerived( m_TriggerTree->GetItemData(m_TriggerTree->GetSelection()) )->m_Group ) - return true; - return false; -} - -sTrigger TriggerSidebar::CreateTrigger(TriggerItemData* data) -{ - sTrigger trigger; - - trigger.active = data->active; - trigger.group = data->group; - trigger.maxRuns = data->maxRuns; - trigger.name = data->name; - trigger.timeValue = data->timeValue; - - trigger.logicBlockEnds = data->logicBlockEnds; - trigger.logicBlocks = data->logicBlocks; - trigger.conditions = data->conditions; - trigger.effects = data->effects; - trigger.logicNots = data->logicNots; - - return trigger; -} - -void TriggerSidebar::CreateGroup(std::vector& groupList, sTriggerGroup& parent, wxTreeItemId index) -{ - wxTreeItemIdValue cookie; - std::vector triggers; - sTriggerGroup group( std::wstring(m_TriggerTree->GetItemText(index)) ); - group.parentName = parent.name; - - //Add this group to parent's child group - std::vector parentChildren = *parent.children; - parentChildren.push_back(*group.parentName); - parent.children = parentChildren; - - for ( wxTreeItemId ID = m_TriggerTree->GetFirstChild(index, cookie); ID.IsOk(); - ID = m_TriggerTree->GetNextChild(index, cookie) ) - { - TriggerItemData* itemData = ToDerived( m_TriggerTree->GetItemData(ID) ); - if ( itemData->m_Group ) - CreateGroup(groupList, group, ID); - else - triggers.push_back( CreateTrigger(itemData) ); - } - - group.triggers = triggers; - groupList.push_back(group); -} - -void TriggerSidebar::UpdateEngineData() -{ - wxTreeItemIdValue cookie; - wxTreeItemId root = m_TriggerTree->GetRootItem(); - - //Find all root groups - std::vector groups; - std::vector triggers; - sTriggerGroup rootGroup(L"Triggers"); - - for ( wxTreeItemId ID = m_TriggerTree->GetFirstChild(root, cookie); ID.IsOk(); - ID = m_TriggerTree->GetNextChild(root, cookie) ) - { - TriggerItemData* itemData = ToDerived( m_TriggerTree->GetItemData(ID) ); - if ( itemData->m_Group ) - CreateGroup(groups, rootGroup, ID); - else - triggers.push_back( CreateTrigger(itemData) ); - } - - rootGroup.triggers = triggers; - groups.push_back(rootGroup); - POST_COMMAND( SetAllTriggers, (groups) ); -} -TriggerItemData* TriggerSidebar::ToDerived(wxTreeItemData* data) -{ - return ( static_cast(data) ); -} -TriggerItemData* TriggerSidebar::GetSelectedItemData() -{ - if ( !m_TriggerTree->GetSelection() ) - m_TriggerTree->SelectItem(m_TriggerTree->GetRootItem()); - return ToDerived( m_TriggerTree->GetItemData(m_TriggerTree->GetSelection()) ); - -} - +#include "precompiled.h" + +#include "Trigger.h" +#include "GameInterface/Messages.h" +#include "CustomControls/Buttons/ActionButton.h" +#include "ScenarioEditor/ScenarioEditor.h" +#include "ScenarioEditor/Tools/Common/MiscState.h" + +#include "wx/treectrl.h" +#include "wx/listctrl.h" +#include "wx/notebook.h" +#include +#include + +using namespace AtlasMessage; + +BEGIN_EVENT_TABLE(TriggerSidebar, Sidebar) +EVT_TREE_BEGIN_DRAG(wxID_ANY, TriggerSidebar::onTreeDrag) +EVT_TREE_END_LABEL_EDIT(wxID_ANY, TriggerSidebar::onTreeNameChange) +EVT_TREE_SEL_CHANGED(wxID_ANY, TriggerSidebar::onTreeSelChange) +EVT_LIST_ITEM_SELECTED(TriggerSidebar::ID_CondList, TriggerSidebar::onCondSelect) +EVT_LIST_ITEM_SELECTED(TriggerSidebar::ID_EffectList, TriggerSidebar::onEffectSelect) +EVT_NOTEBOOK_PAGE_CHANGED(wxID_ANY, TriggerSidebar::onPageChange) +END_EVENT_TABLE() + + +class TriggerTreeCtrl : public wxTreeCtrl +{ +public: + TriggerTreeCtrl(TriggerSidebar* parent, wxWindowID id = wxID_ANY, const wxPoint& pos = wxDefaultPosition, + const wxSize& size = wxDefaultSize, long style = wxTR_HAS_BUTTONS ) + : wxTreeCtrl(parent, id, pos, size, style), m_Sidebar(parent) { } + + void onClick(wxMouseEvent& evt); + +private: + TriggerSidebar* m_Sidebar; + DECLARE_EVENT_TABLE(); +}; + +BEGIN_EVENT_TABLE(TriggerTreeCtrl, wxTreeCtrl) +EVT_LEFT_DOWN(TriggerTreeCtrl::onClick) +END_EVENT_TABLE() + + +struct LogicBlockHelper +{ + LogicBlockHelper() { index = -1; end = false; } + LogicBlockHelper(int _index, bool _end) : index(_index), end(_end) {} + int index; + bool end; + + bool operator< ( const LogicBlockHelper& rhs ) const + { + return index < rhs.index; + } + bool operator== ( const LogicBlockHelper& rhs ) const + { + return index == rhs.index; + } +}; +class TriggerSpecText : public wxTextCtrl +{ + typedef void (*callback)(void* data, std::wstring input, int parameter); + +public: + TriggerSpecText(wxWindow* parent, std::wstring label, const wxPoint& pos, const wxSize& size, + int parameter, std::wstring dataType, callback func, void* data) + : wxTextCtrl(parent, wxID_ANY, wxString( label.c_str() ), pos, size, wxTE_PROCESS_ENTER), + m_DataType(dataType), m_Parameter(parameter), m_Data(data), m_Callback(func) + { + } + void onTextEnter(wxCommandEvent& WXUNUSED(evt)); + + //Disallow invalid input + bool VerifyInput(std::wstring& input) + { + std::wstringstream stream(input); + if ( m_DataType == L"int" ) + { + int test; + stream >> test; + return !stream.fail(); + } + else if ( m_DataType == L"real" ) + { + float test; + stream >> test; + return !stream.fail(); + } + else if ( m_DataType == L"bool" ) + { + bool test; + stream >> test; + return !stream.fail(); + } + else if ( m_DataType == L"string" ) + { + //Make strings appear as strings to javascript + std::wstring quote(L"\""); + input.insert(0, quote); + input.append(quote); + return true; + } + else + { + wxFAIL_MSG(L"Invalid input type for trigger specification"); + return false; + } + } +private: + void* m_Data; + int m_Parameter; + std::wstring m_DataType; + callback m_Callback; + + DECLARE_EVENT_TABLE(); + +}; +BEGIN_EVENT_TABLE(TriggerSpecText, wxTextCtrl) +EVT_TEXT_ENTER(wxID_ANY, TriggerSpecText::onTextEnter) +END_EVENT_TABLE() + +class TriggerSpecChoice : public wxChoice +{ + typedef void (*callback)(void* data, std::wstring input, int parameter); + +public: + TriggerSpecChoice(TriggerBottomBar* parent, std::wstring label, const wxPoint& pos, + const wxSize& size, const wxArrayString& strings, int parameter, callback func, void* data); + + void onChoice(wxCommandEvent& evt); + +private: + TriggerBottomBar* m_Parent; + callback m_Callback; + int m_Parameter; + void* m_Data; + + DECLARE_EVENT_TABLE(); +}; + +BEGIN_EVENT_TABLE(TriggerSpecChoice, wxChoice) +EVT_CHOICE(wxID_ANY, TriggerSpecChoice::onChoice) +END_EVENT_TABLE() + +class TriggerBottomBar; + +class TriggerEntitySelector : public wxPanel +{ + typedef void (*callback)(void* data, std::wstring input, int parameter); + enum { ID_SELECTION, ID_VIEW }; +public: + + TriggerEntitySelector(TriggerBottomBar* parent, std::wstring label, const wxPoint& pos, + const wxSize& size, int parameter, callback func, void* data); + + void onSelectionClick(wxCommandEvent& WXUNUSED(evt)) + { + std::wstring code(L"["); + std::wstringstream stream; + for ( size_t i = 0; i < g_SelectedObjects.size(); ++i ) + { + stream << g_SelectedObjects[i]; + if ( i != g_SelectedObjects.size()-1 ) + stream << L", "; + } + + code.append(stream.str()); + code.append(L"]"); + (*m_Callback)(m_Data, code, m_Parameter); + POST_MESSAGE(SetSelectionPreview, (g_SelectedObjects)); + } + void onViewClick(wxCommandEvent& WXUNUSED(evt)); + +private: + int m_Parameter; + callback m_Callback; + TriggerBottomBar* m_Parent; + void* m_Data; + + DECLARE_EVENT_TABLE(); +}; +BEGIN_EVENT_TABLE(TriggerEntitySelector, wxPanel) +EVT_BUTTON(TriggerEntitySelector::ID_SELECTION, TriggerEntitySelector::onSelectionClick) +EVT_BUTTON(TriggerEntitySelector::ID_VIEW, TriggerEntitySelector::onViewClick) +END_EVENT_TABLE() + +class TriggerPointPlacer : public wxPanel +{ + enum { ID_Set, ID_View }; + typedef void (*callback)(void* data, std::wstring input, int parameter); +public: + + TriggerPointPlacer(wxWindow* parent, const wxPoint& pos, + const wxSize& size, int parameter, callback func, void* data) : m_Callback(func), + wxPanel(parent, wxID_ANY, pos), m_Parameter(parameter), m_Data(data) + { + wxBoxSizer* mainSizer = new wxBoxSizer(wxVERTICAL); + SetSizer(mainSizer); + mainSizer->Add( new wxButton(this, ID_Set, L"Set point", pos, size) ); + mainSizer->Add( new wxButton(this, ID_View, L"View", pos, size) ); + } + + + void onSet(wxCommandEvent& WXUNUSED(evt)) + { + qGetWorldPosition query( wxGetMousePosition().x, wxGetMousePosition().y ); + query.Post(); + Position pos = query.position; + wxString wxForm = wxString::Format(L"Vector(%f, %f, %f)", pos.type0.x, pos.type0.y, pos.type0.z); + + std::wstring convert = (std::wstring)wxForm; + (*m_Callback)(m_Data, convert, m_Parameter); + POST_MESSAGE(TriggerToggleSelector, (true, pos)); + } + + void onView(wxCommandEvent& WXUNUSED(evt)) + { + //POST_MESSAGE( TriggerToggleSelector, (pos) ); + } + +private: + int m_Parameter; + void* m_Data; + callback m_Callback; + bool m_MouseCapture; + + DECLARE_EVENT_TABLE(); +}; + +BEGIN_EVENT_TABLE(TriggerPointPlacer, wxPanel) +EVT_BUTTON(TriggerPointPlacer::ID_Set, TriggerPointPlacer::onSet) +EVT_BUTTON(TriggerPointPlacer::ID_View, TriggerPointPlacer::onView) +END_EVENT_TABLE() + + +class TriggerListCtrl : public wxListCtrl +{ +public: + TriggerListCtrl(wxWindow* parent, TriggerSidebar* sidebar, bool condition, wxWindowID id, const wxPoint& pos = wxDefaultPosition, + const wxSize& size = wxDefaultSize, long style = wxLC_ICON) + : wxListCtrl(parent, id, pos, size, style), m_Sidebar(sidebar), m_Condition(condition) + { + } + void onClick(wxMouseEvent& evt); + + TriggerSidebar* m_Sidebar; + bool m_Condition; +private: + DECLARE_EVENT_TABLE(); +}; +BEGIN_EVENT_TABLE(TriggerListCtrl, wxListCtrl) +EVT_LEFT_DOWN(TriggerListCtrl::onClick) +END_EVENT_TABLE() + + +class TriggerPage : public wxPanel +{ +public: + TriggerPage(wxWindow* parent, TriggerSidebar* sidebar, long ID, wxString title, bool condition) + : wxPanel(parent), m_Sidebar(sidebar), m_Condition(condition) + + { + wxBoxSizer* sizer = new wxBoxSizer(wxHORIZONTAL); + + m_List = new TriggerListCtrl(this, sidebar, condition, ID, wxDefaultPosition, + wxSize(132, 210), wxLC_REPORT | wxLC_SINGLE_SEL); + m_List->InsertColumn(0, title, wxLIST_FORMAT_LEFT, 100); + + sizer->Add(m_List); + SetSizer(sizer); + } + + wxListCtrl* m_List; + TriggerSidebar* m_Sidebar; + bool m_Condition; +}; + + +class TriggerItemData : public wxTreeItemData, public sTrigger +{ +public: + TriggerItemData(TriggerSidebar* sidebar, const std::wstring& name, bool group) + : m_Sidebar(sidebar), sTrigger(name), m_Group(group), m_CondCount(0), m_EffectCount(0) {} + TriggerItemData(TriggerSidebar* sidebar, const sTrigger& trigger, bool group) + : m_Sidebar(sidebar), sTrigger(trigger), m_Group(group), m_CondCount(0), m_EffectCount(0) {} + + TriggerSidebar* m_Sidebar; + size_t m_CondCount, m_EffectCount; + bool m_Group; + std::list m_BlockIndices, m_BlockEndIndices; //index in sidebar list + + void AddBlock(const int block, const int index) + { + std::vector copy = *logicBlocks; + std::vector notCopy = *logicNots; + copy.push_back(block); + notCopy.push_back(false); + + logicBlocks = copy; + logicNots = notCopy; + m_BlockIndices.push_back(index); + } + void AddBlockEnd(const int block, const int index) + { + std::vector copy = *logicBlockEnds; + copy.push_back(block); + logicBlockEnds = copy; + m_BlockEndIndices.push_back(index); + } + + void ResetBlockIndices() + { + std::vector newLogicBlocks, newLogicBlockEnds; + m_BlockIndices.clear(); + m_BlockEndIndices.clear(); + int conditionCount = 0; + + for (int i=0; im_ConditionPage->m_List->GetItemCount(); ++i) + { + if ( m_Sidebar->m_ConditionPage->m_List->GetItemText(i) == m_Sidebar->m_LogicBlockString ) + { + newLogicBlocks.push_back(conditionCount); + m_BlockIndices.push_back(i); + } + + //Block ends belong to current condition, hence conditionCount-1 + else if ( m_Sidebar->m_ConditionPage->m_List->GetItemText(i) == m_Sidebar->m_LogicBlockEndString ) + { + if ( conditionCount == 0 ) + newLogicBlockEnds.push_back(0); + else + newLogicBlockEnds.push_back(conditionCount-1); + m_BlockEndIndices.push_back(i); + } + else + ++conditionCount; + } + logicBlocks = newLogicBlocks; + logicBlockEnds = newLogicBlockEnds; + } +}; + + +void onTriggerParameter(void* data, std::wstring paramString, int parameter); + + +class TriggerBottomBar : public wxPanel +{ + enum { ID_TimeEdit, ID_CondNameEdit, ID_EffectNameEdit, ID_TriggerNameEdit, ID_RunsEdit, + ID_EffectChoice, ID_CondChoice, + ID_TimeRadio, ID_LogicRadio, + ID_NotCheck, ID_ActiveCheck, ID_LogicNotCheck }; + +public: + enum { NO_VIEW, TRIGGER_VIEW, CONDITION_VIEW, EFFECT_VIEW, LOGIC_END_VIEW, LOGIC_VIEW }; + + TriggerBottomBar(TriggerSidebar* sidebar, wxWindow* parent) + : wxPanel(parent), m_Sidebar(sidebar) + { + m_Sizer = new wxBoxSizer(wxHORIZONTAL); + SetSizer(m_Sizer); + m_DependentStatus = NO_VIEW; + } + + int GetDependentStatus() + { + return m_DependentStatus; + } + void SetSpecs(std::vector conditions, std::vector effects) + { + m_ConditionSpecs = conditions; + m_EffectSpecs = effects; + } + + wxArrayString GetConditionNames() + { + wxArrayString ret; + for ( size_t i = 0; i < m_ConditionSpecs.size(); ++i ) + ret.Add( wxString(m_ConditionSpecs[i].displayName.c_str()) ); + return ret; + } + wxArrayString GetEffectNames() + { + wxArrayString ret; + for ( size_t i = 0; i < m_EffectSpecs.size(); ++i ) + ret.Add( wxString(m_EffectSpecs[i].displayName.c_str()) ); + return ret; + } + + void onEffectChoice(wxCommandEvent& evt) + { + //Retrieve specification corresponding to selection + if ( m_Sidebar->m_SelectedEffect != -1 ) + { + std::vector::iterator it = std::find( m_EffectSpecs.begin(), + m_EffectSpecs.end(), std::wstring(evt.GetString()) ); + DisplayTriggerSpec(*it); + } + } + + void onCondChoice(wxCommandEvent& evt) + { + if ( m_Sidebar->m_SelectedCond != -1 ) + { + std::vector::iterator it = std::find( m_ConditionSpecs.begin(), + m_ConditionSpecs.end(), std::wstring(evt.GetString()) ); + DisplayTriggerSpec(*it); + } + } + + void onTimeEnter(wxCommandEvent& WXUNUSED(evt)) + { + float fValue; + std::wstringstream stream( std::wstring(m_TimeEdit->GetValue()) ); + stream >> fValue; + + if ( stream.fail() ) + { + wxBell(); + return; + } + + m_Sidebar->GetSelectedItemData()->timeValue = fValue; + wxString value = wxString::Format(L"%.2f", fValue); + m_TimeEdit->SetValue(value); + m_Sidebar->UpdateEngineData(); + } + + void onConditionEnter(wxCommandEvent& WXUNUSED(evt)) + { + if ( m_Sidebar->m_SelectedCond == -1 ) + return; + + std::vector conditions = *m_Sidebar->GetSelectedItemData()->conditions; + int condition = m_Sidebar->GetConditionCount(m_Sidebar->m_SelectedCond); + + if ( condition == 0 ) + conditions[0].name = std::wstring( m_ConditionEdit->GetValue() ); + else + conditions[condition-1] = std::wstring( m_ConditionEdit->GetValue() ); + + m_Sidebar->GetSelectedItemData()->conditions = conditions; + m_Sidebar->UpdateLists(); + m_Sidebar->UpdateEngineData(); + } + void onEffectEnter(wxCommandEvent& WXUNUSED(evt)) + { + if ( m_Sidebar->m_SelectedEffect== -1 ) + return; + + std::vector effects = *m_Sidebar->GetSelectedItemData()->effects; + effects[m_Sidebar->m_SelectedEffect].name = std::wstring( m_EffectEdit->GetValue() ); + m_Sidebar->GetSelectedItemData()->effects = effects; + m_Sidebar->UpdateLists(); + m_Sidebar->UpdateEngineData(); + } + void onTriggerEnter(wxCommandEvent& WXUNUSED(evt)) + { + TriggerItemData* data = m_Sidebar->GetSelectedItemData(); + if ( data == NULL || m_Sidebar->m_TriggerTree->GetSelection() == m_Sidebar->m_TriggerTree->GetRootItem() ) + return; + + wxString name = m_TriggerEdit->GetValue(); + data->name = std::wstring(name); + m_Sidebar->m_TriggerTree->SetItemText(m_Sidebar->m_TriggerTree->GetSelection(), name); + m_Sidebar->UpdateEngineData(); + } + + void onRunsEnter(wxCommandEvent& WXUNUSED(evt)) + { + int iValue; + std::wstringstream stream( std::wstring(m_RunsEdit->GetValue()) ); + stream >> iValue; + + if ( stream.fail() ) + { + wxBell(); + return; + } + + m_Sidebar->GetSelectedItemData()->maxRuns = iValue; + m_Sidebar->UpdateEngineData(); + } + + void onLogicRadio(wxCommandEvent& evt) + { + if ( m_Sidebar->m_SelectedCond == -1 ) + return; + std::vector conditions = *m_Sidebar->GetSelectedItemData()->conditions; + int condition = m_Sidebar->GetConditionCount(m_Sidebar->m_SelectedCond); + conditions[condition-1].linkLogic = evt.GetInt() + 1; + + m_Sidebar->GetSelectedItemData()->conditions = conditions; + m_Sidebar->UpdateLists(); + m_Sidebar->UpdateEngineData(); + } + void onActiveCheck(wxCommandEvent& evt) + { + m_Sidebar->GetSelectedItemData()->active = (evt.GetInt() == 1); + m_Sidebar->UpdateEngineData(); + } + void onNotCheck(wxCommandEvent& evt) + { + if ( m_Sidebar->m_SelectedCond == -1 ) + return; + std::vector conditions = *m_Sidebar->GetSelectedItemData()->conditions; + int condition = m_Sidebar->GetConditionCount(m_Sidebar->m_SelectedCond); + bool value = (evt.GetInt() == 1); + conditions[condition-1].negated = value; + + m_Sidebar->GetSelectedItemData()->conditions = conditions; + m_Sidebar->UpdateLists(); + m_Sidebar->UpdateEngineData(); + } + + void onLogicNotCheck(wxCommandEvent& evt) + { + TriggerItemData* data = m_Sidebar->GetSelectedItemData(); + + int logicIndex = m_Sidebar->GetLogicBlockCount(m_Sidebar->m_SelectedCond) - 1; + std::vector nots = *data->logicNots; + nots[logicIndex] = evt.IsChecked(); + data->logicNots = nots; + } + + void DisplayTriggerSpec(const sTriggerSpec& spec) + { + if ( m_Sizer->Detach(m_ParameterSizer) ) + { + m_ParameterSizer->DeleteWindows(); + delete m_ParameterSizer; + //m_Sizer->Layout(); + // Layout(); + } + + //m_ParameterSizer = new wxStaticBoxSizer(wxVERTICAL, this, L"Parameters"); + m_ParameterSizer = new wxBoxSizer(wxVERTICAL); + wxBoxSizer* hRow = NULL; + std::vector parameters = *spec.parameters; + std::vector stringParameters; + int row = -1; + + //Set parameter data to new data if change is needed + if ( m_Sidebar->m_Notebook->GetCurrentPage() == m_Sidebar->m_ConditionPage ) + { + std::vector conditions = *m_Sidebar->GetSelectedItemData()->conditions; + int condition = m_Sidebar->GetConditionCount(m_Sidebar->m_SelectedCond) - 1 ; + if ( *conditions[condition].displayName != *spec.displayName ) + { + std::vector newParameters(parameters.size()); + conditions[condition].parameters = newParameters; + conditions[condition].displayName = *spec.displayName; + conditions[condition].functionName = *spec.functionName; + m_Sidebar->GetSelectedItemData()->conditions = conditions; + m_Sidebar->UpdateEngineData(); + } + stringParameters = *(*m_Sidebar->GetSelectedItemData()->conditions) + [m_Sidebar->m_SelectedCond].parameters; + } + else + { + std::vector effects = *m_Sidebar->GetSelectedItemData()->effects; + if ( *effects[m_Sidebar->m_SelectedEffect].displayName != *spec.displayName ) + { + std::vector newParameters(parameters.size()); + effects[m_Sidebar->m_SelectedEffect].parameters = newParameters; + effects[m_Sidebar->m_SelectedEffect].displayName = *spec.displayName; + effects[m_Sidebar->m_SelectedEffect].functionName = *spec.functionName; + m_Sidebar->GetSelectedItemData()->effects = effects; + m_Sidebar->UpdateEngineData(); + } + stringParameters = *(*m_Sidebar->GetSelectedItemData()->effects) + [m_Sidebar->m_SelectedEffect].parameters; + } + + //Add all parameters to sizer + for ( std::vector::iterator it=parameters.begin(); it!=parameters.end(); ++it ) + { + if ( it->row != row ) + { + row = it->row; + hRow = new wxBoxSizer(wxHORIZONTAL); + m_ParameterSizer->Add(hRow); + } + + + if ( *it->windowType == std::wstring(L"text") ) + { + hRow->Add( new wxStaticText(this, wxID_ANY, wxString( (*it->name).c_str() ), + wxPoint(it->xPos, it->yPos)) ); + wxTextCtrl* text = new TriggerSpecText(this, L"", wxDefaultPosition, wxSize(it->xSize, it->ySize), + it->parameterOrder, *it->inputType, &onTriggerParameter, this); + + hRow->Add( text, 0, wxLEFT, 5 ); + wxString fill( stringParameters[it->parameterOrder].c_str() ); + + //Trim quotes + if ( *it->inputType == L"string" && fill.size() > 0 ) + { + fill.erase(0, 1); + fill.erase(fill.size()-1, 1); + } + text->SetValue(fill); + } + + else if ( *it->windowType == std::wstring(L"choice") ) + { + qGetTriggerChoices qChoices(*spec.functionName + *it->name); + qChoices.Post(); + std::vector choices = *qChoices.choices; + wxArrayString strings; + + for ( size_t i = 0; i < choices.size(); ++i ) + strings.Add( wxString(choices[i].c_str()) ); + + hRow->Add( new wxStaticText(this, wxID_ANY, wxString( (*it->name).c_str() ), + wxPoint(it->xPos, it->yPos)) ); + wxChoice* choice = new TriggerSpecChoice( this, L"", wxDefaultPosition, wxSize(it->xSize, it->ySize), + strings, it->parameterOrder, &onTriggerParameter, this ); + + hRow->Add(choice); + choice->SetStringSelection( wxString(stringParameters[it->parameterOrder].c_str()) ); + } + + else if ( *it->windowType == std::wstring(L"entity_selector") ) + { + hRow->Add( new wxStaticText(this, wxID_ANY, wxString((*it->name).c_str())) ); + hRow->Add( new TriggerEntitySelector(this, L"Select", wxDefaultPosition, + wxSize(it->xSize, it->ySize), it->parameterOrder, &onTriggerParameter, this) ); + } + + else if ( *it->windowType == std::wstring(L"point_placer") ) + { + hRow->Add( new wxStaticText(this, wxID_ANY, wxString((*it->name).c_str())) ); + hRow->Add( new TriggerPointPlacer(this, wxDefaultPosition, wxSize(it->xSize, it->ySize), + it->parameterOrder, &onTriggerParameter, this) ); + } + else + { + wxFAIL_MSG(L"Invalid window type for trigger specification"); + row = -1; + //do something else... + } + } + + //(If nothing was added, it won't be automatically delted) + if ( row < 0 ) + { + delete hRow; + delete m_ParameterSizer; + } + else + m_Sizer->Add(m_ParameterSizer, 0, wxLEFT, 5); + + m_Sizer->Layout(); + Layout(); + } + + void FillConditionData() + { + if ( m_Sidebar->m_SelectedCond == -1 ) + return; + + TriggerItemData* itemData = m_Sidebar->GetSelectedItemData(); + int iCondition = m_Sidebar->GetConditionCount(m_Sidebar->m_SelectedCond); + if ( iCondition <= 0 ) + return; + sTriggerCondition condition = (*itemData->conditions)[iCondition-1]; + wxString display( (*condition.displayName).c_str() ); + m_ConditionEdit->SetValue( wxString(condition.name.c_str()) ); + + if ( display != L"" ) + { + std::vector::iterator it = std::find( m_ConditionSpecs.begin(), + m_ConditionSpecs.end(), std::wstring(display) ); + if ( it != m_ConditionSpecs.end() ) + { + m_ConditionChoice->SetStringSelection(display); + DisplayTriggerSpec(*it); + } + } + else + m_ConditionChoice->SetStringSelection(display); + + if ( condition.linkLogic == 0 || condition.linkLogic == 1 ) + m_LogicRadio->SetSelection(0); + else + m_LogicRadio->SetSelection(1); + + m_NotCheck->SetValue(condition.negated); + } + + void FillEffectData() + { + TriggerItemData* itemData = m_Sidebar->GetSelectedItemData(); + sTriggerEffect effect = (*itemData->effects)[m_Sidebar->m_SelectedEffect]; + wxString display( (*effect.displayName).c_str() ); + + m_EffectEdit->SetValue( wxString(effect.name.c_str()) ); + if ( display != L"" ) + { + std::vector::iterator it = std::find( m_EffectSpecs.begin(), + m_EffectSpecs.end(), std::wstring(display) ); + if ( it != m_EffectSpecs.end() ) + { + m_EffectChoice->SetStringSelection(display); + DisplayTriggerSpec(*it); + } + } + //m_TimeRadio->SetSelection(effect.loop); + + float timeVal = itemData->timeValue; + wxString value = wxString::Format(L"%.2f", timeVal); + m_TimeEdit->SetValue(value); + } + + void FillTriggerData() + { + if ( m_DependentStatus != TRIGGER_VIEW ) + return; + TriggerItemData* itemData = m_Sidebar->GetSelectedItemData(); + m_TriggerEdit->SetValue( wxString( (*itemData->name).c_str()) ); + m_ActiveCheck->SetValue(itemData->active); + int runs = itemData->maxRuns; + m_RunsEdit->SetValue( wxString( wxString::Format(L"%d", runs)) ); + + } + + void FillLogicData() + { + std::vector nots = *m_Sidebar->GetSelectedItemData()->logicNots; + m_LogicNotCheck->SetValue( nots[m_Sidebar->GetLogicBlockCount(m_Sidebar->m_SelectedCond)-1] ); + } + + + void ToEffectView() + { + DestroyChildren(); + m_Sizer = new wxBoxSizer(wxHORIZONTAL); + m_DependentSizer = new wxStaticBoxSizer(wxVERTICAL, this, wxString(L"Trigger Editor")); + SetSizer(m_Sizer, true); + + m_DependentSizer = new wxStaticBoxSizer(wxVERTICAL, this, wxString(L"Trigger Editor")); + wxStaticText* name = new wxStaticText(this, wxID_ANY, wxString(L"Name:")); + wxStaticText* effect = new wxStaticText(this, wxID_ANY, wxString(L"Effect:")); + m_EffectEdit = new wxTextCtrl(this, ID_EffectNameEdit, _T(""), wxDefaultPosition, + wxSize(100, 18), wxTE_PROCESS_ENTER); + + wxArrayString effectNames = GetEffectNames(); + wxString radioChoice[] = { wxString(L"Delay"), wxString(L"Loop") }; + m_EffectChoice = new wxChoice(this, ID_EffectChoice, wxDefaultPosition, wxSize(100, 13), effectNames); + + m_TimeRadio = new wxRadioBox(this, ID_TimeRadio, _T("Execution type"), + wxDefaultPosition, wxDefaultSize, 2, radioChoice, 2, wxRA_SPECIFY_COLS); + + wxStaticText* time = new wxStaticText(this, wxID_ANY, wxString(L"Time:")); + m_TimeEdit = new wxTextCtrl(this, ID_TimeEdit, _T(""), wxDefaultPosition, + wxSize(100, 18), wxTE_PROCESS_ENTER); + + wxBoxSizer* hNameHolder = new wxBoxSizer(wxHORIZONTAL); + wxBoxSizer* hEffectHolder = new wxBoxSizer(wxHORIZONTAL); + wxBoxSizer* hTimeHolder = new wxBoxSizer(wxHORIZONTAL); + + hNameHolder->Add(name); + hNameHolder->Add(m_EffectEdit, 0, wxLEFT, 5); + hEffectHolder->Add(effect); + hEffectHolder->Add(m_EffectChoice, 0, wxLEFT, 5); + hTimeHolder->Add(time); + hTimeHolder->Add(m_TimeEdit, 0, wxLEFT, 5); + + m_DependentSizer->Add(hNameHolder, 0, wxTOP, 5); + m_DependentSizer->Add(hEffectHolder, 0, wxTOP, 5); + m_DependentSizer->Add(m_TimeRadio, 0, wxTOP | wxALIGN_CENTER, 10); + m_DependentSizer->Add(hTimeHolder, 0, wxTOP | wxALIGN_CENTER, 5); + + m_Sizer->Add(m_DependentSizer); + m_Sizer->Layout(); + Layout(); + m_DependentStatus = EFFECT_VIEW; + } + + void ToConditionView() + { + DestroyChildren(); + m_Sizer = new wxBoxSizer(wxHORIZONTAL); + m_DependentSizer = new wxStaticBoxSizer(wxVERTICAL, this, wxString(L"Trigger Editor")); + SetSizer(m_Sizer, true); + + wxStaticText* name = new wxStaticText(this, wxID_ANY, wxString(L"Name:")); + wxStaticText* condition = new wxStaticText(this, wxID_ANY, wxString(L"Condition:")); + m_ConditionEdit = new wxTextCtrl(this, ID_CondNameEdit, _T(""), wxDefaultPosition, + wxSize(100, 18), wxTE_PROCESS_ENTER); + + wxArrayString conditionNames = GetConditionNames(); + wxString radioChoice[] = { wxString(L"And"), wxString(L"Or") }; + m_ConditionChoice = new wxChoice(this, ID_CondChoice, wxDefaultPosition, + wxSize(100, 13), conditionNames); + + m_LogicRadio = new wxRadioBox(this, ID_LogicRadio, _T("Link logic:"), + wxDefaultPosition, wxDefaultSize, 2, radioChoice, 2, wxRA_SPECIFY_COLS); + + m_NotCheck = new wxCheckBox(this, ID_NotCheck, wxString(L"Not ")); + + wxBoxSizer* hNameHolder = new wxBoxSizer(wxHORIZONTAL); + wxBoxSizer* hConditionHolder = new wxBoxSizer(wxHORIZONTAL); + wxBoxSizer* hLogicHolder = new wxBoxSizer(wxHORIZONTAL); + + hNameHolder->Add(name); + hNameHolder->Add(m_ConditionEdit, 0, wxLEFT | wxALIGN_CENTER, 5); + hConditionHolder->Add(condition); + hConditionHolder->Add(m_ConditionChoice, 0, wxLEFT | wxALIGN_CENTER, 5); + hLogicHolder->Add(m_LogicRadio, 0, 0, 5); + hLogicHolder->Add(m_NotCheck, 0, wxLEFT | wxALIGN_CENTER, 5); + + m_DependentSizer->Add(hNameHolder, 0, wxTOP, 5); + m_DependentSizer->Add(hConditionHolder, 0, wxTOP, 5); + m_DependentSizer->Add(hLogicHolder, 0, wxALIGN_CENTER | wxTOP, 10); + + m_Sizer->Add(m_DependentSizer); + m_Sizer->Layout(); + Layout(); + m_DependentStatus = CONDITION_VIEW; + } + + void ToTriggerView() + { + DestroyChildren(); + m_Sizer = new wxBoxSizer(wxHORIZONTAL); + m_DependentSizer = new wxStaticBoxSizer(wxVERTICAL, this, wxString(L"Trigger Editor")); + SetSizer(m_Sizer, true); + + wxStaticText* name = new wxStaticText(this, wxID_ANY, wxString(L"Name:")); + m_TriggerEdit = new wxTextCtrl(this, ID_TriggerNameEdit, _T(""), wxDefaultPosition, + wxSize(100, 18), wxTE_PROCESS_ENTER); + + wxStaticText* runs = new wxStaticText(this, wxID_ANY, wxString(L"Maximum runs:")); + m_RunsEdit = new wxTextCtrl(this, ID_RunsEdit, wxString(L"-1"), wxDefaultPosition, wxSize(100, 18)); + m_ActiveCheck = new wxCheckBox(this, ID_ActiveCheck, wxString(L"Active: ")); + + wxBoxSizer* nameHolder = new wxBoxSizer(wxHORIZONTAL), *runsHolder = new wxBoxSizer(wxHORIZONTAL); + + nameHolder->Add(name); + nameHolder->Add(m_TriggerEdit, 0, wxLEFT, 5); + runsHolder->Add(runs); + runsHolder->Add(m_RunsEdit, 0, wxLEFT, 5); + + m_DependentSizer->Add(nameHolder); + m_DependentSizer->Add(runsHolder, 0, wxTOP, 5); + m_DependentSizer->Add(m_ActiveCheck, 0, wxTOP, 5); + + m_Sizer->Add(m_DependentSizer); + m_Sizer->Layout(); + Layout(); + m_DependentStatus = TRIGGER_VIEW; + } + //void ToLogicEndView(); + + void ToLogicView() + { + DestroyChildren(); + m_Sizer = new wxBoxSizer(wxHORIZONTAL); + m_DependentSizer = new wxStaticBoxSizer(wxVERTICAL, this, wxString(L"Trigger Editor")); + SetSizer(m_Sizer, true); + + m_LogicNotCheck = new wxCheckBox(this, ID_LogicNotCheck, L"Not"); + m_DependentSizer->Add(m_LogicNotCheck); + m_Sizer->Add(m_DependentSizer, 0, wxTOP | wxLEFT | wxALIGN_LEFT, 10); + m_Sizer->Layout(); + Layout(); + m_DependentStatus = LOGIC_VIEW; + } + void ToNoView() + { + if ( m_DependentStatus == NO_VIEW ) + return; + DestroyChildren(); + m_DependentStatus = NO_VIEW; + m_Sidebar->m_ConditionPage->m_List->DeleteAllItems(); + m_Sidebar->m_EffectPage->m_List->DeleteAllItems(); + } + + TriggerSidebar* m_Sidebar; + +private: + + wxBoxSizer* m_Sizer, *m_ParameterSizer; + wxStaticBoxSizer* m_DependentSizer; //dependent = effect/condition + + wxTextCtrl* m_TimeEdit, *m_ConditionEdit, *m_EffectEdit, *m_TriggerEdit, *m_RunsEdit; + wxCheckBox* m_ActiveCheck, *m_NotCheck, *m_LogicNotCheck; + wxChoice* m_ConditionChoice, *m_EffectChoice; + wxRadioBox* m_LogicRadio, *m_TimeRadio, m_LogicEndRadio; + + std::vector m_ConditionSpecs, m_EffectSpecs; + + int m_DependentStatus; + + DECLARE_EVENT_TABLE(); +}; + + +BEGIN_EVENT_TABLE(TriggerBottomBar, wxPanel) +EVT_TEXT_ENTER(TriggerBottomBar::ID_TimeEdit, TriggerBottomBar::onTimeEnter) +EVT_TEXT_ENTER(TriggerBottomBar::ID_CondNameEdit, TriggerBottomBar::onConditionEnter) +EVT_TEXT_ENTER(TriggerBottomBar::ID_EffectNameEdit, TriggerBottomBar::onEffectEnter) +EVT_TEXT_ENTER(TriggerBottomBar::ID_TriggerNameEdit, TriggerBottomBar::onTriggerEnter) +EVT_TEXT_ENTER(TriggerBottomBar::ID_RunsEdit, TriggerBottomBar::onRunsEnter) +EVT_CHOICE(TriggerBottomBar::ID_EffectChoice, TriggerBottomBar::onEffectChoice) +EVT_CHOICE(TriggerBottomBar::ID_CondChoice, TriggerBottomBar::onCondChoice) + +EVT_RADIOBOX(TriggerBottomBar::ID_LogicRadio, TriggerBottomBar::onLogicRadio) +EVT_CHECKBOX(TriggerBottomBar::ID_ActiveCheck, TriggerBottomBar::onActiveCheck) +EVT_CHECKBOX(TriggerBottomBar::ID_NotCheck, TriggerBottomBar::onNotCheck) +EVT_CHECKBOX(TriggerBottomBar::ID_LogicNotCheck, TriggerBottomBar::onLogicNotCheck) +//EVT_RADIOBOX(TriggerBotomBar::ID_TimeRadio, TriggerBottomBar::onTimeRadio) +END_EVENT_TABLE() + + +void TriggerTreeCtrl::onClick(wxMouseEvent& evt) +{ + if ( m_Sidebar->m_TriggerTree->GetSelection() == m_Sidebar->m_TriggerTree->GetRootItem() || + !m_Sidebar->m_TriggerTree->GetSelection() ) + { + m_Sidebar->m_TriggerBottom->ToNoView(); + } + else + { + m_Sidebar->m_TriggerBottom->ToTriggerView(); + m_Sidebar->m_TriggerBottom->FillTriggerData(); + } + evt.Skip(); +} + +void TriggerListCtrl::onClick(wxMouseEvent& evt) +{ + evt.Skip(); + if ( m_Condition ) + { + if ( m_Sidebar->m_SelectedCond < 0 ) + return; + + if ( m_Sidebar->m_ConditionPage->m_List->GetItemText(m_Sidebar->m_SelectedCond) + == m_Sidebar->m_LogicBlockEndString ) + { + m_Sidebar->m_TriggerBottom->ToNoView(); + } + else if ( m_Sidebar->m_ConditionPage->m_List->GetItemText(m_Sidebar->m_SelectedCond) + == m_Sidebar->m_LogicBlockString ) + { + m_Sidebar->m_TriggerBottom->ToLogicView(); + m_Sidebar->m_TriggerBottom->FillLogicData(); + } + else + { + m_Sidebar->m_TriggerBottom->ToConditionView(); + m_Sidebar->m_TriggerBottom->FillConditionData(); + } + } + else + { + m_Sidebar->m_TriggerBottom->ToEffectView(); + if ( m_Sidebar->m_SelectedEffect != -1 ) + m_Sidebar->m_TriggerBottom->FillEffectData(); + } + +} + + +TriggerEntitySelector::TriggerEntitySelector(TriggerBottomBar* parent, std::wstring label, + const wxPoint& pos, const wxSize& size, int parameter, callback func, void* data) + : wxPanel(parent), m_Parent(parent), m_Parameter(parameter), m_Callback(func), m_Data(data) +{ + wxBoxSizer* MainSizer = new wxBoxSizer(wxVERTICAL); + SetSizer(MainSizer); + MainSizer->Add( new wxButton(this, ID_SELECTION, wxString(label.c_str()), pos, size) ); + MainSizer->Add( new wxButton(this, ID_VIEW, L"View", pos, size) ); +} +void TriggerEntitySelector::onViewClick(wxCommandEvent& WXUNUSED(evt)) +{ + std::wstring handles; + if ( m_Parent->m_Sidebar->m_Notebook->GetCurrentPage() == m_Parent->m_Sidebar->m_ConditionPage ) + { + std::vector conditions = *m_Parent->m_Sidebar->GetSelectedItemData()->conditions; + int condition = m_Parent->m_Sidebar->GetConditionCount(m_Parent->m_Sidebar->m_SelectedCond) - 1 ; + std::vector parameters = *conditions[condition].parameters; + handles = parameters[m_Parameter]; + } + else + { + std::vector effects = *m_Parent->m_Sidebar->GetSelectedItemData()->effects; + int effect = m_Parent->m_Sidebar->m_SelectedEffect; + std::vector parameters = *effects[effect].parameters; + handles = parameters[m_Parameter]; + } + + std::vector IDList; + size_t previous = handles.find(L"[")+1, current; + + //remove "]" + if ( handles.size() ) + handles.erase(handles.size()-1); + + while ( (current = handles.find(L", ", previous)) != std::wstring::npos ) + { + std::wstringstream toInt(handles.substr(previous, current - previous)); + int newID; + toInt >> newID; + IDList.push_back(newID); + previous = current+1; + } + + std::wstringstream toInt( handles.substr(previous) ); + int newID; + toInt >> newID; + IDList.push_back(newID); + g_SelectedObjects = IDList; + POST_MESSAGE(SetSelectionPreview, (g_SelectedObjects)); +} + +void TriggerSpecText::onTextEnter(wxCommandEvent& WXUNUSED(evt)) +{ + std::wstring text( GetValue().wc_str() ); + + if ( VerifyInput(text) ) + (*m_Callback)(m_Data, text, m_Parameter ); + else + wxBell(); +} + +TriggerSpecChoice::TriggerSpecChoice(TriggerBottomBar* parent, std::wstring label, const wxPoint& pos, + const wxSize& size, const wxArrayString& strings, int parameter, callback func, void* data) + : wxChoice(parent, wxID_ANY, pos, size, strings), m_Callback(func), m_Data(data), + m_Parent(parent), m_Parameter(parameter) + { + } +void TriggerSpecChoice::onChoice(wxCommandEvent& evt) +{ + (*m_Callback)(m_Data, std::wstring( evt.GetString().wc_str() ), m_Parameter); +} +void onTriggerParameter(void* data, std::wstring paramString, int parameter) +{ + TriggerBottomBar* bottomBar = static_cast(data); + + if ( bottomBar->m_Sidebar->m_Notebook->GetSelection() == 0 ) + { + if ( bottomBar->m_Sidebar->m_SelectedCond == -1 ) + return; + std::vector conditions = *bottomBar->m_Sidebar->GetSelectedItemData()->conditions; + std::vector parameters = *conditions[bottomBar->m_Sidebar->m_SelectedCond].parameters; + + parameters[parameter] = paramString; + conditions[bottomBar->m_Sidebar->m_SelectedCond].parameters = parameters; + bottomBar->m_Sidebar->GetSelectedItemData()->conditions = conditions; + } + else + { + if ( bottomBar->m_Sidebar->m_SelectedEffect == -1 ) + return; + std::vector effects = *bottomBar->m_Sidebar->GetSelectedItemData()->effects; + std::vector parameters = *effects[bottomBar->m_Sidebar->m_SelectedEffect].parameters; + + parameters[parameter] = paramString; + effects[bottomBar->m_Sidebar->m_SelectedEffect].parameters = parameters; + bottomBar->m_Sidebar->GetSelectedItemData()->effects = effects; + } + bottomBar->m_Sidebar->UpdateEngineData(); +} + +void onGroupPush(void* data) +{ + TriggerSidebar* sidebar = static_cast(data); + if ( !sidebar->m_TriggerTree->GetSelection()) + return; + if ( !sidebar->IsGroupSelected() ) + return; + + wxString name = wxString::Format(L"Group %d", sidebar->m_GroupCount); + wxTreeItemId ID = sidebar->m_TriggerTree->AppendItem( sidebar->m_TriggerTree->GetSelection(), + name, -1, -1, new TriggerItemData(sidebar, std::wstring(name), true) ); + sidebar->m_TriggerTree->EnsureVisible(ID); + ++sidebar->m_GroupCount; + + sidebar->UpdateEngineData(); +} + +void onTriggerPush(void* data) +{ + TriggerSidebar* sidebar = static_cast(data); + wxTreeItemId ID = sidebar->m_TriggerTree->GetSelection(); + + if ( !sidebar->IsGroupSelected() ) + ID = sidebar->m_TriggerTree->GetItemParent(ID); + + wxString name = wxString::Format(L"Trigger %d", sidebar->m_TriggerCount); + TriggerItemData* itemData = new TriggerItemData(sidebar, std::wstring(name), false); + itemData->group = std::wstring( sidebar->m_TriggerTree->GetItemText(ID) ); + + ID = sidebar->m_TriggerTree->AppendItem(ID, name, -1, -1, itemData); + sidebar->m_TriggerTree->Expand( sidebar->m_TriggerTree->GetRootItem() ); + + ++sidebar->m_TriggerCount; + sidebar->m_TriggerTree->SelectItem(ID); + sidebar->UpdateEngineData(); +} + +void onDeleteTreePush(void* data) +{ + TriggerSidebar* sidebar = static_cast(data); + if ( sidebar->m_TriggerTree->GetSelection() == sidebar->m_TriggerTree->GetRootItem() ) + return; + + if ( wxMessageBox( wxString(L"Are you sure you want to delete this item?"), + wxString(L"Caution"), wxYES_NO ) == wxYES ) + { + sidebar->m_TriggerTree->Delete(sidebar->m_TriggerTree->GetSelection()); + sidebar->m_TriggerTree->EnsureVisible( sidebar->m_TriggerTree->GetRootItem() ); + sidebar->m_TriggerBottom->FillTriggerData(); + } + + sidebar->UpdateEngineData(); +} + +void onConditionPush(void* data) +{ + TriggerSidebar* sidebar = static_cast(data); + if ( sidebar->IsGroupSelected() ) + return; + + sidebar->m_Notebook->SetSelection(0); + TriggerItemData* itemData = sidebar->GetSelectedItemData(); + std::wstring name = std::wstring( wxString::Format(L"Condition %d", itemData->m_CondCount).wc_str() ); + + if ( itemData->m_CondCount == 0 ) + sidebar->m_SelectedCond = 0; + + ++itemData->m_CondCount; + + std::vector conditions = *itemData->conditions; + conditions.push_back( sTriggerCondition(name) ); + itemData->conditions = conditions; + + long count = sidebar->m_ConditionPage->m_List->GetItemCount(); + + sidebar->m_ConditionPage->m_List->InsertItem(count, wxString(name.c_str()) ); + sidebar->m_ConditionPage->m_List->EnsureVisible(count); + sidebar->m_ConditionPage->m_List->SetItemState(count, wxLIST_STATE_SELECTED, wxLIST_STATE_SELECTED); + + sidebar->m_TriggerBottom->ToConditionView(); //Some data is not valid, so reset + sidebar->m_TriggerBottom->FillConditionData(); + + sidebar->UpdateEngineData(); +} + +void onEffectPush(void* data) +{ + TriggerSidebar* sidebar = static_cast(data); + if ( sidebar->IsGroupSelected() ) + return; + + sidebar->m_Notebook->SetSelection(1); + TriggerItemData* itemData = sidebar->GetSelectedItemData(); + std::wstring name = std::wstring( wxString::Format(L"Effect %d", itemData->m_EffectCount).wc_str() ); + + if ( itemData->m_EffectCount == 0 ) + sidebar->m_SelectedEffect = 0; + ++itemData->m_EffectCount; + + std::vector effects = *itemData->effects; + effects.push_back( sTriggerEffect(name) ); + itemData->effects = effects; + + long count = sidebar->m_EffectPage->m_List->GetItemCount(); + sidebar->m_EffectPage->m_List->InsertItem(count, wxString(name.c_str()) ); + sidebar->m_EffectPage->m_List->EnsureVisible(count); + sidebar->m_EffectPage->m_List->SetItemState(count, wxLIST_STATE_SELECTED, wxLIST_STATE_SELECTED); + + sidebar->m_TriggerBottom->ToEffectView(); + sidebar->m_TriggerBottom->FillEffectData(); + + sidebar->UpdateEngineData(); +} + +void onDeleteBookPush(void* data) +{ + TriggerSidebar* sidebar = static_cast(data); + wxListCtrl* list = static_cast(sidebar->m_Notebook->GetCurrentPage())->m_List; + if ( !list ) + return; + + TriggerItemData* itemData = sidebar->GetSelectedItemData(); + //Is condition? -- valid selection? + if ( list == sidebar->m_ConditionPage->m_List && sidebar->m_SelectedCond != -1 ) + { + std::wstring text(sidebar->m_ConditionPage->m_List->GetItemText(sidebar->m_SelectedCond) ); + int conditionCount = sidebar->GetConditionCount(sidebar->m_SelectedCond); + + if ( text == std::wstring(sidebar->m_LogicBlockString.wc_str()) ) + { + std::vector blocks = *itemData->logicBlocks; + if ( conditionCount == 0 ) + { + blocks.erase( std::find(blocks.begin(), blocks.end(), 0) ); + itemData->m_BlockIndices.erase( std::find( itemData->m_BlockIndices.begin(), + itemData->m_BlockIndices.end(), sidebar->m_SelectedCond ) ); + } + else + { + blocks.erase( std::find(blocks.begin(), blocks.end(), conditionCount) ); + itemData->m_BlockIndices.erase( std::find( itemData->m_BlockIndices.begin(), + itemData->m_BlockIndices.end(), sidebar->m_SelectedCond ) ); + } + itemData->logicBlocks = blocks; + } + + else if ( text == std::wstring(sidebar->m_LogicBlockEndString.wc_str()) ) + { + std::vector blockEnds = *itemData->logicBlockEnds; + if ( conditionCount == 0 ) + { + blockEnds.erase( std::find(blockEnds.begin(), blockEnds.end(), 0) ); + itemData->m_BlockEndIndices.erase( std::find( itemData->m_BlockEndIndices.begin(), + itemData->m_BlockEndIndices.end(), sidebar->m_SelectedCond ) ); + } + else + { + blockEnds.erase( std::find(blockEnds.begin(), blockEnds.end(), conditionCount-1) ); + itemData->m_BlockEndIndices.erase( std::find( itemData->m_BlockEndIndices.begin(), + itemData->m_BlockEndIndices.end(), sidebar->m_SelectedCond ) ); + } + itemData->logicBlockEnds = blockEnds; + } + + else + { + std::vector conditions = *itemData->conditions; + conditions.erase( std::find(conditions.begin(), conditions.end(), text) ); + itemData->conditions = conditions; + } + + list->DeleteItem( sidebar->m_SelectedCond ); + itemData->ResetBlockIndices(); + + if ( sidebar->m_SelectedCond == list->GetItemCount() ) + { + sidebar->m_SelectedCond = -1; + sidebar->m_TriggerBottom->ToNoView(); + } + else + sidebar->m_TriggerBottom->FillConditionData(); + } + + else if ( list == sidebar->m_EffectPage->m_List && sidebar->m_SelectedEffect != -1) + { + std::vector effects = *itemData->effects; + effects.erase( std::find( effects.begin(), effects.end(), std::wstring( + list->GetItemText(sidebar->m_SelectedEffect)) ) ); + itemData->effects = effects; + + list->DeleteItem( sidebar->m_SelectedEffect ); + + if ( itemData->effects.GetSize() == 0 || sidebar->m_SelectedEffect == list->GetItemCount() ) + { + sidebar->m_SelectedEffect = -1; + sidebar->m_TriggerBottom->ToNoView(); + } + else + sidebar->m_TriggerBottom->FillEffectData(); + } + sidebar->UpdateLists(); + sidebar->UpdateEngineData(); +} + +void onLogicBlockPush(void* data) +{ + TriggerSidebar* sidebar = static_cast(data); + sidebar->m_Notebook->SetSelection(0); + + if ( sidebar->IsGroupSelected() ) + return; + + int limit = sidebar->m_SelectedCond; + if ( sidebar->m_SelectedCond == -1 ) + limit = sidebar->m_ConditionPage->m_List->GetItemCount()-1; + + int conditionCount = sidebar->GetConditionCount(limit); + if ( conditionCount == 0 ) + { + sidebar->GetSelectedItemData()->AddBlock(0, 0); + sidebar->UpdateLists(); + return; + } + + sidebar->GetSelectedItemData()->AddBlock(conditionCount, limit); + sidebar->UpdateLists(); + sidebar->m_TriggerBottom->ToLogicView(); //Some data is not valid, so reset + sidebar->m_TriggerBottom->FillLogicData(); + sidebar->UpdateEngineData(); +} + +void onBlockEndPush(void* data) +{ + TriggerSidebar* sidebar = static_cast(data); + sidebar->m_Notebook->SetSelection(0); + + if ( sidebar->IsGroupSelected() ) + return; + + int limit = sidebar->m_SelectedCond; + if ( sidebar->m_SelectedCond == -1 ) + limit = sidebar->m_ConditionPage->m_List->GetItemCount()-1; + + int conditionCount = sidebar->GetConditionCount(limit); + if ( conditionCount == 0 ) + { + sidebar->GetSelectedItemData()->AddBlockEnd(0, 0); + sidebar->UpdateLists(); + return; + } + + sidebar->GetSelectedItemData()->AddBlockEnd(conditionCount-1, limit); + sidebar->UpdateLists(); +} + + +TriggerSidebar::TriggerSidebar(ScenarioEditor& scenarioEditor, wxWindow* sidebarContainer, wxWindow* bottomBarContainer) +: Sidebar(scenarioEditor, sidebarContainer, bottomBarContainer), m_GroupCount(0), m_TriggerCount(0), + m_SelectedCond(-1), m_SelectedEffect(-1) +{ + m_TriggerBottom = new TriggerBottomBar(this, bottomBarContainer); + m_BottomBar = m_TriggerBottom; + + m_TriggerTree = new TriggerTreeCtrl(this, wxID_ANY, wxDefaultPosition, + wxSize(140, 220), wxTR_HAS_BUTTONS | wxTR_EDIT_LABELS); + m_TriggerTree->AddRoot(L"Triggers", -1, -1, new TriggerItemData(this, L"Triggers", true)); + m_TriggerTree->SelectItem( m_TriggerTree->GetRootItem() ); + m_TriggerTree->Expand( m_TriggerTree->GetRootItem() ); + + + wxBoxSizer* hHolder = new wxBoxSizer(wxHORIZONTAL); + wxBoxSizer* vHolder = new wxBoxSizer(wxVERTICAL); + wxBoxSizer* vButtons = new wxBoxSizer(wxVERTICAL); + + ActionButton* trigButton = new ActionButton( this, L"Trigger", &onTriggerPush, + this, wxSize(50, 20) ); + ActionButton* groupButton = new ActionButton( this, L"Group", &onGroupPush, + this, wxSize(50, 20) ); + ActionButton* deleteButton = new ActionButton( this, L"Delete", &onDeleteTreePush, + this, wxSize(50, 20) ); + + ActionButton* conditionButton = new ActionButton( this, L"Condition", + &onConditionPush, this, wxSize(54, 20) ); + ActionButton* effectButton = new ActionButton( this, L"Effect", + &onEffectPush, this, wxSize(50, 20) ); + ActionButton* bookDelete = new ActionButton( this, L"Delete", + &onDeleteBookPush, this, wxSize(50, 20) ); + ActionButton* logicBlock = new ActionButton( this, L"Block", + &onLogicBlockPush, this, wxSize(50, 20) ); + ActionButton* logicBlockEnd = new ActionButton( this, L"Block End", + &onBlockEndPush, this, wxSize(50, 20) ); + + + m_LogicBlockString = wxString(L"--------------------"); + m_LogicBlockEndString = wxString(L"==========="); + wxStaticText* bottomTitle = new wxStaticText( this, wxID_ANY, _T("Conditions and Effects") ); + m_Notebook = new wxNotebook(this, wxID_ANY, wxDefaultPosition, + wxSize(132, 210), wxNB_TOP); + + m_ConditionPage = new TriggerPage(m_Notebook, this, ID_CondList, wxString(L"Conditions"), true); + m_EffectPage = new TriggerPage(m_Notebook, this, ID_EffectList, wxString(L"Effects"), false); + + m_Notebook->AddPage( m_ConditionPage, _T("Conditions") ); + m_Notebook->AddPage( m_EffectPage, _T("Effects") ); + m_Notebook->SetPageSize(wxSize(130, 240)); + + vButtons->Add(trigButton); + vButtons->Add(groupButton); + vButtons->Add(deleteButton); + vButtons->Add(conditionButton, 0, wxTOP, 190); + vButtons->Add(effectButton); + vButtons->Add(bookDelete); + vButtons->Add(logicBlock); + vButtons->Add(logicBlockEnd); + + vHolder->Add(m_TriggerTree, 0, wxTOP, 15); + vHolder->Add(bottomTitle, 0, wxALIGN_CENTER | wxTOP, 5); + vHolder->Add(m_Notebook, 0, wxTOP, 5 ); + + hHolder->Add(vHolder); + hHolder->Add(vButtons, 0, wxALIGN_CENTER); + m_MainSizer->Add(hHolder); +} + +int TriggerSidebar::GetConditionCount(int limit) +{ + int conditionCount = 0; + wxListCtrl* list = m_ConditionPage->m_List; + for ( int i = 0; i <= limit; ++i ) + { + if ( list->GetItemText(i) != m_LogicBlockString && list->GetItemText(i) != m_LogicBlockEndString) + ++conditionCount; + } + return conditionCount; +} + +int TriggerSidebar::GetLogicBlockCount(int limit) +{ + int logicCount = 0; + wxListCtrl* list = m_ConditionPage->m_List; + for ( int i = 0; i <= limit; ++i ) + { + if ( list->GetItemText(i) == m_LogicBlockString ) + ++logicCount; + } + return logicCount; +} +void TriggerSidebar::OnFirstDisplay() +{ + qGetTriggerData dataQuery; + dataQuery.Post(); + m_TriggerBottom->SetSpecs(*dataQuery.conditions, *dataQuery.effects); + + //Add all loaded triggers to the tree + const std::vector triggerGroups = *dataQuery.groups; + std::vector::const_iterator it = std::find( triggerGroups.begin(), + triggerGroups.end(), std::wstring(L"Triggers") ); + + if ( it != triggerGroups.end() ) + { + wxTreeItemId invalid; + AddGroupTree(*it, invalid); + m_TriggerTree->Expand( m_TriggerTree->GetRootItem() ); + } +} + +void TriggerSidebar::AddGroupTree(const sTriggerGroup& group, wxTreeItemId parent) +{ + wxTreeItemId newID; + wxString text( (*group.name).c_str() ); + + //Make sure root item doesn't already exist + if ( !parent && !m_TriggerTree->GetRootItem() ) + newID = m_TriggerTree->AddRoot(text, -1, -1, new TriggerItemData(this, *group.name, true)); + else if ( parent ) + newID = m_TriggerTree->AppendItem(parent, text); + else + newID = m_TriggerTree->GetRootItem(); + + const std::vector triggerBuf = *group.triggers; + const std::vector groupBuf = *group.children; + + for ( size_t i = 0; i < group.children.GetSize(); ++i ) + AddGroupTree( *std::find(m_TriggerGroups.begin(), m_TriggerGroups.end(), groupBuf[i]), newID ); + + for ( size_t i = 0; i < group.triggers.GetSize(); ++i ) + { + std::wstring trigName = *triggerBuf[i].name; + size_t condMax = 0, effectMax = 0; + + //Make triggers start where user last left off + if ( trigName.find(L"Trigger ") == 0 ) + { + trigName.erase(0, 8); //remove "Trigger " + std::wstringstream toInt(trigName); + size_t convert; + toInt >> convert; + ++convert; + + if ( !toInt.fail() ) + { + if ( convert > m_TriggerCount ) + m_TriggerCount = convert; + } + } + std::vector conditions = *triggerBuf[i].conditions; + std::vector effects = *triggerBuf[i].effects; + + for ( size_t j = 0; j < conditions.size(); ++j ) + { + std::wstring condName = *conditions[j].name; + + if ( condName.find(L"Condition ") == 0 ) + { + condName.erase(0, 10); + std::wstringstream toInt(condName); + size_t convert; + toInt >> convert; + ++convert; + + if ( !toInt.fail() ) + { + if ( convert > condMax ) + condMax = convert; + } + } + } + + for ( size_t j = 0; j < effects.size(); ++j ) + { + std::wstring effectName = *effects[j].name; + + if ( effectName .find(L"Effect ") == 0 ) + { + effectName.erase(0, 7); + std::wstringstream toInt(effectName); + size_t convert; + toInt >> convert; + ++convert; + + if ( !toInt.fail() ) + { + if ( convert > effectMax ) + effectMax = convert; + } + } + } + TriggerItemData* newTriggerData = new TriggerItemData(this, triggerBuf[i], false); + newTriggerData->m_CondCount = condMax; + newTriggerData->m_EffectCount = effectMax; + m_TriggerTree->AppendItem( newID, wxString( triggerBuf[i].name.c_str() ), -1, -1, newTriggerData); + } +} + + +void TriggerSidebar::onPageChange(wxNotebookEvent& evt) +{ + if ( evt.GetSelection() == 0 ) + { + m_TriggerBottom->ToConditionView(); + if ( m_SelectedCond != -1 ) + m_TriggerBottom->FillConditionData(); + return; + } + m_TriggerBottom->ToEffectView(); + if ( m_SelectedEffect != -1 ) + m_TriggerBottom->FillEffectData(); +} + +void TriggerSidebar::onTreeDrag(wxTreeEvent& WXUNUSED(evt)) +{ + //evt.Allow(); +} + +void TriggerSidebar::onTreeNameChange(wxTreeEvent& evt) +{ + ToDerived( m_TriggerTree->GetItemData(evt.GetItem()) )->name = std::wstring( + evt.GetLabel().wc_str()); + UpdateEngineData(); +} + +void TriggerSidebar::onTreeSelChange(wxTreeEvent& evt) +{ + //Prevent other triggers from trying to use previous data + m_SelectedCond = -1; + m_SelectedEffect = -1; + + if ( evt.GetItem() == m_TriggerTree->GetRootItem() ) + { + m_TriggerBottom->ToNoView(); + return; + } + + if ( m_TriggerBottom->GetDependentStatus() != TriggerBottomBar::TRIGGER_VIEW ) + m_TriggerBottom->ToTriggerView(); + m_TriggerBottom->FillTriggerData(); + + UpdateLists(); +} +void TriggerSidebar::UpdateLists() +{ + TriggerItemData* data = GetSelectedItemData(); + m_ConditionPage->m_List->Freeze(); + m_ConditionPage->m_List->DeleteAllItems(); + m_EffectPage->m_List->Freeze(); + m_EffectPage->m_List->DeleteAllItems(); + + const Shareable* conditions = data->conditions.GetBuffer(); + for ( size_t i = 0; i < data->conditions.GetSize(); ++i ) + { + m_ConditionPage->m_List->InsertItem( m_ConditionPage->m_List-> + GetItemCount(), wxString(conditions[i]->name.c_str()) ); + } + + const Shareable* effects = data->effects.GetBuffer(); + for ( size_t i = 0; i < data->effects.GetSize(); ++i ) + { + m_EffectPage->m_List->InsertItem(m_EffectPage->m_List->GetItemCount(), + wxString(effects[i]->name.c_str()) ); + } + + //These must be merged and sorted because adding them out-of-order screws up the list + std::list sortedBlocks; + std::list blocks = data->m_BlockIndices, blockEnds = data->m_BlockEndIndices; + + for ( std::list::iterator it = blocks.begin(); it != blocks.end(); ++it ) + sortedBlocks.push_back( LogicBlockHelper(*it, false) ); + for ( std::list::iterator it = blockEnds.begin(); it != blockEnds.end(); ++it ) + sortedBlocks.push_back( LogicBlockHelper(*it, true) ); + + sortedBlocks.sort(); + for ( std::list::iterator it = sortedBlocks.begin(); it != sortedBlocks.end(); ++it ) + { + if ( it->end ) + m_ConditionPage->m_List->InsertItem(it->index, m_LogicBlockEndString); + else + m_ConditionPage->m_List->InsertItem(it->index, m_LogicBlockString); + } + + m_ConditionPage->m_List->Thaw(); + m_EffectPage->m_List->Thaw(); +} + +void TriggerSidebar::onCondSelect(wxListEvent& evt) +{ + m_SelectedCond = evt.GetIndex(); + //if ( m_TriggerBottom->GetDependentStatus() != TriggerBottomBar::CONDITION_VIEW ) + if ( m_ConditionPage->m_List->GetItemText(m_SelectedCond) + == m_LogicBlockEndString ) + { + m_TriggerBottom->ToNoView(); + } + else if ( m_ConditionPage->m_List->GetItemText(m_SelectedCond) + == m_LogicBlockString ) + { + m_TriggerBottom->ToLogicView(); + + if ( m_SelectedCond != -1 ) + m_TriggerBottom->FillLogicData(); + } + else + { + m_TriggerBottom->ToConditionView(); + if ( m_SelectedCond != -1 ) + m_TriggerBottom->FillConditionData(); + } +} +void TriggerSidebar::onEffectSelect(wxListEvent& evt) +{ + m_SelectedEffect = evt.GetIndex(); + //if ( m_TriggerBottom->GetDependentStatus() != TriggerBottomBar::EFFECT_VIEW ) + m_TriggerBottom->ToEffectView(); + m_TriggerBottom->FillEffectData(); +} + +bool TriggerSidebar::IsGroupSelected() +{ + if ( ToDerived( m_TriggerTree->GetItemData(m_TriggerTree->GetSelection()) )->m_Group ) + return true; + return false; +} + +sTrigger TriggerSidebar::CreateTrigger(TriggerItemData* data) +{ + sTrigger trigger; + + trigger.active = data->active; + trigger.group = data->group; + trigger.maxRuns = data->maxRuns; + trigger.name = data->name; + trigger.timeValue = data->timeValue; + + trigger.logicBlockEnds = data->logicBlockEnds; + trigger.logicBlocks = data->logicBlocks; + trigger.conditions = data->conditions; + trigger.effects = data->effects; + trigger.logicNots = data->logicNots; + + return trigger; +} + +void TriggerSidebar::CreateGroup(std::vector& groupList, sTriggerGroup& parent, wxTreeItemId index) +{ + wxTreeItemIdValue cookie; + std::vector triggers; + sTriggerGroup group( std::wstring(m_TriggerTree->GetItemText(index)) ); + group.parentName = parent.name; + + //Add this group to parent's child group + std::vector parentChildren = *parent.children; + parentChildren.push_back(*group.parentName); + parent.children = parentChildren; + + for ( wxTreeItemId ID = m_TriggerTree->GetFirstChild(index, cookie); ID.IsOk(); + ID = m_TriggerTree->GetNextChild(index, cookie) ) + { + TriggerItemData* itemData = ToDerived( m_TriggerTree->GetItemData(ID) ); + if ( itemData->m_Group ) + CreateGroup(groupList, group, ID); + else + triggers.push_back( CreateTrigger(itemData) ); + } + + group.triggers = triggers; + groupList.push_back(group); +} + +void TriggerSidebar::UpdateEngineData() +{ + wxTreeItemIdValue cookie; + wxTreeItemId root = m_TriggerTree->GetRootItem(); + + //Find all root groups + std::vector groups; + std::vector triggers; + sTriggerGroup rootGroup(L"Triggers"); + + for ( wxTreeItemId ID = m_TriggerTree->GetFirstChild(root, cookie); ID.IsOk(); + ID = m_TriggerTree->GetNextChild(root, cookie) ) + { + TriggerItemData* itemData = ToDerived( m_TriggerTree->GetItemData(ID) ); + if ( itemData->m_Group ) + CreateGroup(groups, rootGroup, ID); + else + triggers.push_back( CreateTrigger(itemData) ); + } + + rootGroup.triggers = triggers; + groups.push_back(rootGroup); + POST_COMMAND( SetAllTriggers, (groups) ); +} +TriggerItemData* TriggerSidebar::ToDerived(wxTreeItemData* data) +{ + return ( static_cast(data) ); +} +TriggerItemData* TriggerSidebar::GetSelectedItemData() +{ + if ( !m_TriggerTree->GetSelection() ) + m_TriggerTree->SelectItem(m_TriggerTree->GetRootItem()); + return ToDerived( m_TriggerTree->GetItemData(m_TriggerTree->GetSelection()) ); + +} + diff --git a/source/tools/atlas/AtlasUI/ScenarioEditor/Sections/Trigger/Trigger.h b/source/tools/atlas/AtlasUI/ScenarioEditor/Sections/Trigger/Trigger.h index f8b50ad73e..3da3e58329 100644 --- a/source/tools/atlas/AtlasUI/ScenarioEditor/Sections/Trigger/Trigger.h +++ b/source/tools/atlas/AtlasUI/ScenarioEditor/Sections/Trigger/Trigger.h @@ -1,87 +1,87 @@ -/* Desc: interface for creation and editing of triggers. Interprets - XML specifications then uses this to construct layout. -*/ - -#include "../Common/Sidebar.h" -#include "GameInterface/Messages.h" - -class TriggerItemData; -class TriggerTreeCtrl; -class TriggerBottomBar; -class TriggerPage; -class wxTreeItemId; -class wxTreeItemData; -class wxTreeEvent; -class wxListEvent; -class wxNotebook; -class wxNotebookEvent; -class wxTreeEvent; -class wxListEvent; - -class TriggerSidebar : public Sidebar -{ -public: - enum { ID_CondList, ID_EffectList }; - - TriggerSidebar(ScenarioEditor& scenarioEditor, wxWindow* sidebarContainer, wxWindow* bottomBarContainer); - - void onTreeDrag(wxTreeEvent& evt); - void onTreeNameChange(wxTreeEvent& evt); - //void onTreeDelete(wxTreeEvent& evt); - void onTreeSelChange(wxTreeEvent& evt); - void onTreeCollapse(wxTreeEvent& evt); - void onListSelect(wxListEvent& evt); - void onEffectSelect(wxListEvent& evt); - void onCondSelect(wxListEvent& evt); - void onPageChange(wxNotebookEvent& evt); - - bool IsGroupSelected(); - TriggerItemData* ToDerived(wxTreeItemData* data); - TriggerItemData* GetSelectedItemData(); - - //Finds condition number (index+1) of m_SelectedCond [needed because of logic blocks] - int GetConditionCount(int limit); - int GetLogicBlockCount(int limit); - void UpdateLists(); - void UpdateEngineData(); - - //AtlasMessage::sTriggerList m_TriggerList; - - TriggerBottomBar* m_TriggerBottom; - TriggerTreeCtrl* m_TriggerTree; - TriggerPage* m_ConditionPage, *m_EffectPage; - wxNotebook* m_Notebook; - - size_t m_TriggerCount, m_GroupCount; - long m_SelectedCond, m_SelectedEffect, m_SelectedCondIndex, m_SelectedEffectIndex; - wxString m_LogicBlockString, m_LogicBlockEndString; - -protected: - virtual void OnFirstDisplay(); - -private: - struct copyIfRootChild - { - copyIfRootChild(std::vector& groupList) : m_groupList(groupList) {} - void operator() ( const AtlasMessage::sTriggerGroup& group ) - { - if ( *group.parentName == std::wstring(L"Triggers") ) - m_groupList.push_back(group); - } - private: - std::vector& m_groupList; - }; - - void AddGroupTree(const AtlasMessage::sTriggerGroup& group, wxTreeItemId parent); - - void CreateGroup(std::vector& groupList, - AtlasMessage::sTriggerGroup& parent, wxTreeItemId index); - - AtlasMessage::sTrigger CreateTrigger(TriggerItemData* data); - - std::vector m_TriggerGroups; - - DECLARE_EVENT_TABLE(); -}; - - +/* Desc: interface for creation and editing of triggers. Interprets + XML specifications then uses this to construct layout. +*/ + +#include "../Common/Sidebar.h" +#include "GameInterface/Messages.h" + +class TriggerItemData; +class TriggerTreeCtrl; +class TriggerBottomBar; +class TriggerPage; +class wxTreeItemId; +class wxTreeItemData; +class wxTreeEvent; +class wxListEvent; +class wxNotebook; +class wxNotebookEvent; +class wxTreeEvent; +class wxListEvent; + +class TriggerSidebar : public Sidebar +{ +public: + enum { ID_CondList, ID_EffectList }; + + TriggerSidebar(ScenarioEditor& scenarioEditor, wxWindow* sidebarContainer, wxWindow* bottomBarContainer); + + void onTreeDrag(wxTreeEvent& evt); + void onTreeNameChange(wxTreeEvent& evt); + //void onTreeDelete(wxTreeEvent& evt); + void onTreeSelChange(wxTreeEvent& evt); + void onTreeCollapse(wxTreeEvent& evt); + void onListSelect(wxListEvent& evt); + void onEffectSelect(wxListEvent& evt); + void onCondSelect(wxListEvent& evt); + void onPageChange(wxNotebookEvent& evt); + + bool IsGroupSelected(); + TriggerItemData* ToDerived(wxTreeItemData* data); + TriggerItemData* GetSelectedItemData(); + + //Finds condition number (index+1) of m_SelectedCond [needed because of logic blocks] + int GetConditionCount(int limit); + int GetLogicBlockCount(int limit); + void UpdateLists(); + void UpdateEngineData(); + + //AtlasMessage::sTriggerList m_TriggerList; + + TriggerBottomBar* m_TriggerBottom; + TriggerTreeCtrl* m_TriggerTree; + TriggerPage* m_ConditionPage, *m_EffectPage; + wxNotebook* m_Notebook; + + size_t m_TriggerCount, m_GroupCount; + long m_SelectedCond, m_SelectedEffect, m_SelectedCondIndex, m_SelectedEffectIndex; + wxString m_LogicBlockString, m_LogicBlockEndString; + +protected: + virtual void OnFirstDisplay(); + +private: + struct copyIfRootChild + { + copyIfRootChild(std::vector& groupList) : m_groupList(groupList) {} + void operator() ( const AtlasMessage::sTriggerGroup& group ) + { + if ( *group.parentName == std::wstring(L"Triggers") ) + m_groupList.push_back(group); + } + private: + std::vector& m_groupList; + }; + + void AddGroupTree(const AtlasMessage::sTriggerGroup& group, wxTreeItemId parent); + + void CreateGroup(std::vector& groupList, + AtlasMessage::sTriggerGroup& parent, wxTreeItemId index); + + AtlasMessage::sTrigger CreateTrigger(TriggerItemData* data); + + std::vector m_TriggerGroups; + + DECLARE_EVENT_TABLE(); +}; + + diff --git a/source/tools/atlas/GameInterface/Handlers/CinemaHandler.cpp b/source/tools/atlas/GameInterface/Handlers/CinemaHandler.cpp index cc77bb7214..b7a12bbe05 100644 --- a/source/tools/atlas/GameInterface/Handlers/CinemaHandler.cpp +++ b/source/tools/atlas/GameInterface/Handlers/CinemaHandler.cpp @@ -1,179 +1,179 @@ -#include "precompiled.h" - -#include "MessageHandler.h" -#include "../CommandProc.h" -#include "graphics/Camera.h" -#include "graphics/CinemaTrack.h" -#include "graphics/GameView.h" -#include "ps/Game.h" -#include "ps/CStr.h" -#include "ps/CLogger.h" -#include "ps/Filesystem.h" -#include "maths/MathUtil.h" -#include "maths/Quaternion.h" -#include "lib/res/graphics/ogl_tex.h" - -#define LOG_CATEGORY "Cinema" - -namespace AtlasMessage { - - -sCinemaPath ConstructCinemaPath(const CCinemaPath* source) -{ - sCinemaPath path; - const CCinemaData* data = source->GetData(); - path.mode = data->m_Mode; - path.style = data->m_Style; - path.growth = data->m_Growth; - path.timescale = data->m_Timescale; - path.change = data->m_Switch; - - return path; -} -CCinemaData ConstructCinemaData(const sCinemaPath& path) -{ - CCinemaData data; - data.m_Growth = data.m_GrowthCount = path.growth; - data.m_Switch = path.change; - data.m_Mode = path.mode; - data.m_Style = path.style; - - return data; -} -sCinemaSplineNode ConstructCinemaNode(const SplineData& data) -{ - sCinemaSplineNode node; - node.px = data.Position.X; - node.py = data.Position.Y; - node.pz = data.Position.Z; - - node.rx = data.Rotation.X; - node.ry = data.Rotation.Y; - node.rz = data.Rotation.Z; - node.t = data.Distance; - - return node; -} - -std::vector GetCurrentPaths() -{ - const std::map& paths = g_Game->GetView()->GetCinema()->GetAllPaths(); - std::vector atlasPaths; - - for ( std::map::const_iterator it=paths.begin(); it!=paths.end(); it++ ) - { - sCinemaPath path = ConstructCinemaPath(&it->second); - path.name = it->first; - - const std::vector& nodes = it->second.GetAllNodes(); - std::vector atlasNodes; - - for ( size_t i=0; i 2 ) - { - for ( size_t i=atlasNodes.size()-2; i>0; --i ) - atlasNodes[i].t = atlasNodes[i-1].t; - } - atlasNodes.back().t = atlasNodes.front().t; - atlasNodes.front().t = back; - } - path.nodes = atlasNodes; - atlasPaths.push_back(path); - } - return atlasPaths; -} - -void SetCurrentPaths(const std::vector& atlasPaths) -{ - std::map paths; - - for ( std::vector::const_iterator it=atlasPaths.begin(); it!=atlasPaths.end(); it++ ) - { - CStrW pathName(*it->name); - paths[pathName] = CCinemaPath(); - paths[pathName].SetTimescale(it->timescale); - - const sCinemaPath& atlasPath = *it; - const std::vector nodes = *atlasPath.nodes; - TNSpline spline; - CCinemaData data = ConstructCinemaData(atlasPath); - - for ( size_t j=0; jGetView()->GetCinema()->SetAllPaths(paths); -} -QUERYHANDLER(GetCameraInfo) -{ - sCameraInfo info; - CMatrix3D* cam = &g_Game->GetView()->GetCamera()->m_Orientation; - - CQuaternion quatRot = cam->GetRotation(); - quatRot.Normalize(); - CVector3D rotation = quatRot.ToEulerAngles(); - rotation.X = RADTODEG(rotation.X); - rotation.Y = RADTODEG(rotation.Y); - rotation.Z = RADTODEG(rotation.Z); - CVector3D translation = cam->GetTranslation(); - - info.pX = translation.X; - info.pY = translation.Y; - info.pZ = translation.Z; - info.rX = rotation.X; - info.rY = rotation.Y; - info.rZ = rotation.Z; - msg->info = info; -} - -MESSAGEHANDLER(CinemaEvent) -{ - CCinemaManager* manager = g_Game->GetView()->GetCinema(); - - if ( msg->mode == eCinemaEventMode::SMOOTH ) - manager->OverridePath(*msg->path); - else if ( msg->mode == eCinemaEventMode::IMMEDIATE_PATH ) - manager->MoveToPointAt(msg->t); - else if ( msg->mode == eCinemaEventMode::RESET ) - g_Game->GetView()->ResetCamera(); - else if ( msg->mode == eCinemaEventMode::SELECT ) - manager->SetCurrentPath(*msg->path, msg->drawCurrent, msg->lines); - else - debug_assert(false); -} - -BEGIN_COMMAND(SetCinemaPaths) -{ - std::vector m_oldPaths, m_newPaths; - void Do() - { - m_oldPaths = GetCurrentPaths(); - m_newPaths = *msg->paths; - Redo(); - } - void Redo() - { - SetCurrentPaths(m_newPaths); - } - void Undo() - { - SetCurrentPaths(m_oldPaths); - } -}; -END_COMMAND(SetCinemaPaths) - -QUERYHANDLER(GetCinemaPaths) -{ - msg->paths = GetCurrentPaths(); -} - -} +#include "precompiled.h" + +#include "MessageHandler.h" +#include "../CommandProc.h" +#include "graphics/Camera.h" +#include "graphics/CinemaTrack.h" +#include "graphics/GameView.h" +#include "ps/Game.h" +#include "ps/CStr.h" +#include "ps/CLogger.h" +#include "ps/Filesystem.h" +#include "maths/MathUtil.h" +#include "maths/Quaternion.h" +#include "lib/res/graphics/ogl_tex.h" + +#define LOG_CATEGORY "Cinema" + +namespace AtlasMessage { + + +sCinemaPath ConstructCinemaPath(const CCinemaPath* source) +{ + sCinemaPath path; + const CCinemaData* data = source->GetData(); + path.mode = data->m_Mode; + path.style = data->m_Style; + path.growth = data->m_Growth; + path.timescale = data->m_Timescale; + path.change = data->m_Switch; + + return path; +} +CCinemaData ConstructCinemaData(const sCinemaPath& path) +{ + CCinemaData data; + data.m_Growth = data.m_GrowthCount = path.growth; + data.m_Switch = path.change; + data.m_Mode = path.mode; + data.m_Style = path.style; + + return data; +} +sCinemaSplineNode ConstructCinemaNode(const SplineData& data) +{ + sCinemaSplineNode node; + node.px = data.Position.X; + node.py = data.Position.Y; + node.pz = data.Position.Z; + + node.rx = data.Rotation.X; + node.ry = data.Rotation.Y; + node.rz = data.Rotation.Z; + node.t = data.Distance; + + return node; +} + +std::vector GetCurrentPaths() +{ + const std::map& paths = g_Game->GetView()->GetCinema()->GetAllPaths(); + std::vector atlasPaths; + + for ( std::map::const_iterator it=paths.begin(); it!=paths.end(); it++ ) + { + sCinemaPath path = ConstructCinemaPath(&it->second); + path.name = it->first; + + const std::vector& nodes = it->second.GetAllNodes(); + std::vector atlasNodes; + + for ( size_t i=0; i 2 ) + { + for ( size_t i=atlasNodes.size()-2; i>0; --i ) + atlasNodes[i].t = atlasNodes[i-1].t; + } + atlasNodes.back().t = atlasNodes.front().t; + atlasNodes.front().t = back; + } + path.nodes = atlasNodes; + atlasPaths.push_back(path); + } + return atlasPaths; +} + +void SetCurrentPaths(const std::vector& atlasPaths) +{ + std::map paths; + + for ( std::vector::const_iterator it=atlasPaths.begin(); it!=atlasPaths.end(); it++ ) + { + CStrW pathName(*it->name); + paths[pathName] = CCinemaPath(); + paths[pathName].SetTimescale(it->timescale); + + const sCinemaPath& atlasPath = *it; + const std::vector nodes = *atlasPath.nodes; + TNSpline spline; + CCinemaData data = ConstructCinemaData(atlasPath); + + for ( size_t j=0; jGetView()->GetCinema()->SetAllPaths(paths); +} +QUERYHANDLER(GetCameraInfo) +{ + sCameraInfo info; + CMatrix3D* cam = &g_Game->GetView()->GetCamera()->m_Orientation; + + CQuaternion quatRot = cam->GetRotation(); + quatRot.Normalize(); + CVector3D rotation = quatRot.ToEulerAngles(); + rotation.X = RADTODEG(rotation.X); + rotation.Y = RADTODEG(rotation.Y); + rotation.Z = RADTODEG(rotation.Z); + CVector3D translation = cam->GetTranslation(); + + info.pX = translation.X; + info.pY = translation.Y; + info.pZ = translation.Z; + info.rX = rotation.X; + info.rY = rotation.Y; + info.rZ = rotation.Z; + msg->info = info; +} + +MESSAGEHANDLER(CinemaEvent) +{ + CCinemaManager* manager = g_Game->GetView()->GetCinema(); + + if ( msg->mode == eCinemaEventMode::SMOOTH ) + manager->OverridePath(*msg->path); + else if ( msg->mode == eCinemaEventMode::IMMEDIATE_PATH ) + manager->MoveToPointAt(msg->t); + else if ( msg->mode == eCinemaEventMode::RESET ) + g_Game->GetView()->ResetCamera(); + else if ( msg->mode == eCinemaEventMode::SELECT ) + manager->SetCurrentPath(*msg->path, msg->drawCurrent, msg->lines); + else + debug_assert(false); +} + +BEGIN_COMMAND(SetCinemaPaths) +{ + std::vector m_oldPaths, m_newPaths; + void Do() + { + m_oldPaths = GetCurrentPaths(); + m_newPaths = *msg->paths; + Redo(); + } + void Redo() + { + SetCurrentPaths(m_newPaths); + } + void Undo() + { + SetCurrentPaths(m_oldPaths); + } +}; +END_COMMAND(SetCinemaPaths) + +QUERYHANDLER(GetCinemaPaths) +{ + msg->paths = GetCurrentPaths(); +} + +} diff --git a/source/tools/atlas/GameInterface/Handlers/TriggerHandler.cpp b/source/tools/atlas/GameInterface/Handlers/TriggerHandler.cpp index c0ef240664..e942970403 100644 --- a/source/tools/atlas/GameInterface/Handlers/TriggerHandler.cpp +++ b/source/tools/atlas/GameInterface/Handlers/TriggerHandler.cpp @@ -1,346 +1,346 @@ -#include "precompiled.h" - -#include "MessageHandler.h" -#include "../CommandProc.h" -#include "../Shareable.h" - -#include "simulation/TriggerManager.h" -#include "ps/Game.h" -#include "graphics/GameView.h" -#include "graphics/CinemaTrack.h" - -namespace AtlasMessage { - -sTriggerSpec TriggerSpecToAtlas(const CTriggerSpec& spec) -{ - sTriggerSpec atlasSpec; - std::vector< sTriggerParameter > atlasParameters; - const std::set& parameters = spec.GetParameters(); - - for ( std::set::const_iterator it=parameters.begin(); it!=parameters.end(); ++it ) - { - sTriggerParameter atlasParam; - atlasParam.column = it->column; - atlasParam.inputType = it->inputType; - atlasParam.name = it->name; - atlasParam.parameterOrder = it->parameterOrder; - atlasParam.row = it->row; - - atlasParam.windowType = it->windowType; - atlasParam.xPos = it->xPos; - atlasParam.yPos = it->yPos; - atlasParam.xSize = it->xSize; - atlasParam.ySize = it->ySize; - atlasParameters.push_back(atlasParam); - } - atlasSpec.functionName = spec.functionName; - atlasSpec.displayName = spec.displayName; - atlasSpec.parameters = atlasParameters; - return atlasSpec; -} - -sTrigger TriggerToAtlas(const MapTrigger& trigger) -{ - sTrigger atlasTrigger; - atlasTrigger.active = trigger.active; - atlasTrigger.timeValue = trigger.timeValue; - atlasTrigger.maxRuns = trigger.maxRunCount; - atlasTrigger.group = trigger.groupName; - atlasTrigger.name = trigger.name; - - std::vector atlasNots; - std::vector atlasBlocks, atlasBlockEnds; - - for ( std::set::const_iterator it = trigger.logicBlocks.begin(); - it != trigger.logicBlocks.end(); ++it ) - { - atlasBlocks.push_back( (int)it->index ); - atlasNots.push_back( it->negated ); - } - for ( std::set::const_iterator it = trigger.logicBlockEnds.begin(); - it != trigger.logicBlockEnds.end(); ++it ) - { - atlasBlockEnds.push_back( (int)*it ); - } - atlasTrigger.logicNots = atlasNots; - atlasTrigger.logicBlocks = atlasBlocks; - atlasTrigger.logicBlockEnds = atlasBlockEnds; - - std::vector atlasConditions; - std::vector atlasEffects; - - for ( std::list::const_iterator it = trigger.conditions.begin(); - it != trigger.conditions.end(); ++it ) - { - sTriggerCondition atlasCondition; - atlasCondition.linkLogic = it->linkLogic; - atlasCondition.name = it->name; - atlasCondition.functionName = it->functionName; - atlasCondition.displayName = it->displayName; - atlasCondition.negated = it->negated; - std::vector parameters; - - for ( std::list::const_iterator it2=it->parameters.begin(); - it2 != it->parameters.end(); ++it2 ) - { - parameters.push_back( std::wstring(it2->c_str()) ); - } - - atlasCondition.parameters = parameters; - atlasConditions.push_back(atlasCondition); - } - - for ( std::list::const_iterator it = trigger.effects.begin(); - it != trigger.effects.end(); ++it ) - { - sTriggerEffect atlasEffect; - std::vector parameters; - atlasEffect.name = it->name; - atlasEffect.functionName = it->functionName; - atlasEffect.displayName = it->displayName; - - for ( std::list::const_iterator it2 = it->parameters.begin(); - it2 != it->parameters.end(); ++it2 ) - { - parameters.push_back( std::wstring(it2->c_str()) ); - } - atlasEffect.parameters = parameters; - atlasEffects.push_back( atlasEffect ); - } - - atlasTrigger.conditions = atlasConditions; - atlasTrigger.effects = atlasEffects; - return atlasTrigger; -} - -sTriggerGroup GroupToAtlas(const MapTriggerGroup& group) -{ - sTriggerGroup atlasGroup; - atlasGroup.parentName = group.parentName; - atlasGroup.name = group.name; - - std::vector atlasTriggers; - std::vector atlasChildren; - for ( std::list::const_iterator it = group.triggers.begin(); - it != group.triggers.end(); ++it ) - { - atlasTriggers.push_back( TriggerToAtlas(*it) ); - } - for ( std::list::const_iterator it = group.childGroups.begin(); - it != group.childGroups.end(); ++it ) - { - atlasChildren.push_back( std::wstring(it->c_str()) ); - } - - atlasGroup.triggers = atlasTriggers; - atlasGroup.children = atlasChildren; - return atlasGroup; -} - -MapTrigger AtlasToTrigger(const sTrigger& trigger) -{ - MapTrigger engineTrigger; - - engineTrigger.active = trigger.active; - engineTrigger.groupName = *trigger.group; - - std::vector blockEnds = *trigger.logicBlockEnds, blocks = *trigger.logicBlocks; - std::copy( blockEnds.begin(), blockEnds.end(), inserter(engineTrigger.logicBlockEnds, engineTrigger.logicBlockEnds.begin()) ); - std::copy( blocks.begin(), blocks.end(), inserter(engineTrigger.logicBlocks, engineTrigger.logicBlocks.begin()) ); - - engineTrigger.maxRunCount = trigger.maxRuns; - engineTrigger.name = *trigger.name; - engineTrigger.timeValue = trigger.timeValue; - - std::vector conditions = *trigger.conditions; - std::vector effects = *trigger.effects; - - for ( std::vector::const_iterator it = conditions.begin(); it != conditions.end(); ++it ) - { - engineTrigger.conditions.push_back( MapTriggerCondition() ); - MapTriggerCondition* cond = &engineTrigger.conditions.back(); - - cond->functionName = *it->functionName; - cond->displayName = *it->displayName; - cond->linkLogic = it->linkLogic; - cond->name = *it->name; - cond->negated = it->negated; - - std::vector parameters = *it->parameters; - for ( std::vector::const_iterator it2 = parameters.begin(); it2 != parameters.end(); ++it2 ) - { - cond->parameters.push_back( CStrW(*it2) ); - } - } - - for ( std::vector::const_iterator it = effects.begin(); it != effects.end(); ++it ) - { - engineTrigger.effects.push_back( MapTriggerEffect() ); - MapTriggerEffect* effect = &engineTrigger.effects.back(); - - effect->functionName = *it->functionName; - effect->displayName = *it->displayName; - effect->name = *it->name; - std::vector parameters = *it->parameters; - - for ( std::vector::const_iterator it2 = parameters.begin(); it2 != parameters.end(); ++it2 ) - { - effect->parameters.push_back( CStrW(*it2) ); - } - } - - return engineTrigger; -} - - -MapTriggerGroup AtlasToGroup(const sTriggerGroup& group) -{ - MapTriggerGroup engineGroup; - engineGroup.parentName = *group.parentName; - engineGroup.name = *group.name; - - std::list engineTriggers; - std::vector atlasChildren = *group.children; - std::vector atlasTriggers = *group.triggers; - - for ( std::vector::const_iterator it = atlasTriggers.begin(); - it != atlasTriggers.end(); ++it ) - { - engineTriggers.push_back( AtlasToTrigger(*it) ); - } - for ( std::vector::const_iterator it = atlasChildren.begin(); it != atlasChildren.end(); ++it ) - engineGroup.childGroups.push_back(*it); - - engineGroup.triggers = engineTriggers; - return engineGroup; -} - -std::vector GetCurrentTriggers() -{ - const std::list& groups = g_TriggerManager.GetAllTriggerGroups(); - std::vector atlasGroups; - - for ( std::list::const_iterator it = groups.begin(); it != groups.end(); ++it ) - atlasGroups.push_back( GroupToAtlas(*it) ); - return atlasGroups; -} - -void SetCurrentTriggers(const std::vector& groups) -{ - std::list engineGroups; - for ( std::vector::const_iterator it = groups.begin(); it != groups.end(); ++it ) - engineGroups.push_back( AtlasToGroup(*it) ); - g_TriggerManager.SetAllGroups(engineGroups); -} - -QUERYHANDLER(GetTriggerData) -{ - const std::list& conditions = g_TriggerManager.GetAllConditions(); - const std::list& effects = g_TriggerManager.GetAllEffects(); - std::vector atlasConditions; - std::vector atlasEffects; - - for ( std::list::const_iterator it=conditions.begin(); it!=conditions.end(); ++it ) - atlasConditions.push_back( TriggerSpecToAtlas(*it) ); - for ( std::list::const_iterator it=effects.begin(); it!=effects.end(); ++it ) - atlasEffects.push_back( TriggerSpecToAtlas(*it) ); - - msg->conditions = atlasConditions; - msg->effects = atlasEffects; - msg->groups = GetCurrentTriggers(); -} - -QUERYHANDLER(GetTriggerChoices) -{ - CStrW selectedName(*msg->name); - std::vector choices = g_TriggerManager.GetTriggerChoices(selectedName); - std::vector translations = g_TriggerManager.GetTriggerTranslations(selectedName); - - if ( choices.empty() ) - return; - - //If a special list (i.e. uses engine data) - if ( choices.size() == 1 ) - { - - if ( choices[0] == std::wstring(L"ATLAS_CINEMA_LIST") ) - { - choices.clear(); - const std::map& paths = g_Game->GetView()->GetCinema()->GetAllPaths(); - for ( std::map::const_iterator it = paths.begin(); it != paths.end(); ++it ) - { - choices.push_back(it->first); - translations.push_back( L"\"" + it->first + L"\"" ); //Strings need quotes in JS - } - } - else if ( choices[0] == std::wstring(L"ATLAS_TRIGGER_LIST") ) - { - choices.clear(); - const std::list& groups = g_TriggerManager.GetAllTriggerGroups(); - for ( std::list::const_iterator it = groups.begin(); - it != groups.end(); ++it ) - { - for ( std::list::const_iterator it2 = it->triggers.begin(); - it2 != it->triggers.end(); ++it2 ) - { - choices.push_back(it2->name); - translations.push_back( L"\"" + it2->name + L"\"" ); - } - } - } - else if ( choices[0] == std::wstring(L"ATLAS_TRIG_GROUP_LIST") ) - { - choices.clear(); - const std::list& groups = g_TriggerManager.GetAllTriggerGroups(); - for ( std::list::const_iterator it = groups.begin(); - it != groups.end(); ++it ) - { - choices.push_back(it->name); - translations.push_back( L"\"" + it->name + L"\"" ); - } - } - else - debug_warn("Invalid special choice list for trigger specification parameter"); - } - msg->choices = choices; - msg->translations = translations; -} - -QUERYHANDLER(GetWorldPosition) -{ - Position pos; - pos.type1.x = msg->x; - pos.type1.y = msg->y; - CVector3D worldPos = pos.GetWorldSpace(); - Position ret(worldPos.X, worldPos.Y, worldPos.Z); - msg->position = ret; -} -BEGIN_COMMAND(SetAllTriggers) -{ - std::vector m_oldGroups, m_newGroups; - - void Do() - { - m_oldGroups = GetCurrentTriggers(); - m_newGroups = *msg->groups; - Redo(); - } - void Redo() - { - SetCurrentTriggers(m_newGroups); - } - void Undo() - { - SetCurrentTriggers(m_oldGroups); - } -}; -END_COMMAND(SetAllTriggers) - - -MESSAGEHANDLER(TriggerToggleSelector) -{ - //TODO: Draw stuff - UNUSED2(msg); -} - -} +#include "precompiled.h" + +#include "MessageHandler.h" +#include "../CommandProc.h" +#include "../Shareable.h" + +#include "simulation/TriggerManager.h" +#include "ps/Game.h" +#include "graphics/GameView.h" +#include "graphics/CinemaTrack.h" + +namespace AtlasMessage { + +sTriggerSpec TriggerSpecToAtlas(const CTriggerSpec& spec) +{ + sTriggerSpec atlasSpec; + std::vector< sTriggerParameter > atlasParameters; + const std::set& parameters = spec.GetParameters(); + + for ( std::set::const_iterator it=parameters.begin(); it!=parameters.end(); ++it ) + { + sTriggerParameter atlasParam; + atlasParam.column = it->column; + atlasParam.inputType = it->inputType; + atlasParam.name = it->name; + atlasParam.parameterOrder = it->parameterOrder; + atlasParam.row = it->row; + + atlasParam.windowType = it->windowType; + atlasParam.xPos = it->xPos; + atlasParam.yPos = it->yPos; + atlasParam.xSize = it->xSize; + atlasParam.ySize = it->ySize; + atlasParameters.push_back(atlasParam); + } + atlasSpec.functionName = spec.functionName; + atlasSpec.displayName = spec.displayName; + atlasSpec.parameters = atlasParameters; + return atlasSpec; +} + +sTrigger TriggerToAtlas(const MapTrigger& trigger) +{ + sTrigger atlasTrigger; + atlasTrigger.active = trigger.active; + atlasTrigger.timeValue = trigger.timeValue; + atlasTrigger.maxRuns = trigger.maxRunCount; + atlasTrigger.group = trigger.groupName; + atlasTrigger.name = trigger.name; + + std::vector atlasNots; + std::vector atlasBlocks, atlasBlockEnds; + + for ( std::set::const_iterator it = trigger.logicBlocks.begin(); + it != trigger.logicBlocks.end(); ++it ) + { + atlasBlocks.push_back( (int)it->index ); + atlasNots.push_back( it->negated ); + } + for ( std::set::const_iterator it = trigger.logicBlockEnds.begin(); + it != trigger.logicBlockEnds.end(); ++it ) + { + atlasBlockEnds.push_back( (int)*it ); + } + atlasTrigger.logicNots = atlasNots; + atlasTrigger.logicBlocks = atlasBlocks; + atlasTrigger.logicBlockEnds = atlasBlockEnds; + + std::vector atlasConditions; + std::vector atlasEffects; + + for ( std::list::const_iterator it = trigger.conditions.begin(); + it != trigger.conditions.end(); ++it ) + { + sTriggerCondition atlasCondition; + atlasCondition.linkLogic = it->linkLogic; + atlasCondition.name = it->name; + atlasCondition.functionName = it->functionName; + atlasCondition.displayName = it->displayName; + atlasCondition.negated = it->negated; + std::vector parameters; + + for ( std::list::const_iterator it2=it->parameters.begin(); + it2 != it->parameters.end(); ++it2 ) + { + parameters.push_back( std::wstring(it2->c_str()) ); + } + + atlasCondition.parameters = parameters; + atlasConditions.push_back(atlasCondition); + } + + for ( std::list::const_iterator it = trigger.effects.begin(); + it != trigger.effects.end(); ++it ) + { + sTriggerEffect atlasEffect; + std::vector parameters; + atlasEffect.name = it->name; + atlasEffect.functionName = it->functionName; + atlasEffect.displayName = it->displayName; + + for ( std::list::const_iterator it2 = it->parameters.begin(); + it2 != it->parameters.end(); ++it2 ) + { + parameters.push_back( std::wstring(it2->c_str()) ); + } + atlasEffect.parameters = parameters; + atlasEffects.push_back( atlasEffect ); + } + + atlasTrigger.conditions = atlasConditions; + atlasTrigger.effects = atlasEffects; + return atlasTrigger; +} + +sTriggerGroup GroupToAtlas(const MapTriggerGroup& group) +{ + sTriggerGroup atlasGroup; + atlasGroup.parentName = group.parentName; + atlasGroup.name = group.name; + + std::vector atlasTriggers; + std::vector atlasChildren; + for ( std::list::const_iterator it = group.triggers.begin(); + it != group.triggers.end(); ++it ) + { + atlasTriggers.push_back( TriggerToAtlas(*it) ); + } + for ( std::list::const_iterator it = group.childGroups.begin(); + it != group.childGroups.end(); ++it ) + { + atlasChildren.push_back( std::wstring(it->c_str()) ); + } + + atlasGroup.triggers = atlasTriggers; + atlasGroup.children = atlasChildren; + return atlasGroup; +} + +MapTrigger AtlasToTrigger(const sTrigger& trigger) +{ + MapTrigger engineTrigger; + + engineTrigger.active = trigger.active; + engineTrigger.groupName = *trigger.group; + + std::vector blockEnds = *trigger.logicBlockEnds, blocks = *trigger.logicBlocks; + std::copy( blockEnds.begin(), blockEnds.end(), inserter(engineTrigger.logicBlockEnds, engineTrigger.logicBlockEnds.begin()) ); + std::copy( blocks.begin(), blocks.end(), inserter(engineTrigger.logicBlocks, engineTrigger.logicBlocks.begin()) ); + + engineTrigger.maxRunCount = trigger.maxRuns; + engineTrigger.name = *trigger.name; + engineTrigger.timeValue = trigger.timeValue; + + std::vector conditions = *trigger.conditions; + std::vector effects = *trigger.effects; + + for ( std::vector::const_iterator it = conditions.begin(); it != conditions.end(); ++it ) + { + engineTrigger.conditions.push_back( MapTriggerCondition() ); + MapTriggerCondition* cond = &engineTrigger.conditions.back(); + + cond->functionName = *it->functionName; + cond->displayName = *it->displayName; + cond->linkLogic = it->linkLogic; + cond->name = *it->name; + cond->negated = it->negated; + + std::vector parameters = *it->parameters; + for ( std::vector::const_iterator it2 = parameters.begin(); it2 != parameters.end(); ++it2 ) + { + cond->parameters.push_back( CStrW(*it2) ); + } + } + + for ( std::vector::const_iterator it = effects.begin(); it != effects.end(); ++it ) + { + engineTrigger.effects.push_back( MapTriggerEffect() ); + MapTriggerEffect* effect = &engineTrigger.effects.back(); + + effect->functionName = *it->functionName; + effect->displayName = *it->displayName; + effect->name = *it->name; + std::vector parameters = *it->parameters; + + for ( std::vector::const_iterator it2 = parameters.begin(); it2 != parameters.end(); ++it2 ) + { + effect->parameters.push_back( CStrW(*it2) ); + } + } + + return engineTrigger; +} + + +MapTriggerGroup AtlasToGroup(const sTriggerGroup& group) +{ + MapTriggerGroup engineGroup; + engineGroup.parentName = *group.parentName; + engineGroup.name = *group.name; + + std::list engineTriggers; + std::vector atlasChildren = *group.children; + std::vector atlasTriggers = *group.triggers; + + for ( std::vector::const_iterator it = atlasTriggers.begin(); + it != atlasTriggers.end(); ++it ) + { + engineTriggers.push_back( AtlasToTrigger(*it) ); + } + for ( std::vector::const_iterator it = atlasChildren.begin(); it != atlasChildren.end(); ++it ) + engineGroup.childGroups.push_back(*it); + + engineGroup.triggers = engineTriggers; + return engineGroup; +} + +std::vector GetCurrentTriggers() +{ + const std::list& groups = g_TriggerManager.GetAllTriggerGroups(); + std::vector atlasGroups; + + for ( std::list::const_iterator it = groups.begin(); it != groups.end(); ++it ) + atlasGroups.push_back( GroupToAtlas(*it) ); + return atlasGroups; +} + +void SetCurrentTriggers(const std::vector& groups) +{ + std::list engineGroups; + for ( std::vector::const_iterator it = groups.begin(); it != groups.end(); ++it ) + engineGroups.push_back( AtlasToGroup(*it) ); + g_TriggerManager.SetAllGroups(engineGroups); +} + +QUERYHANDLER(GetTriggerData) +{ + const std::list& conditions = g_TriggerManager.GetAllConditions(); + const std::list& effects = g_TriggerManager.GetAllEffects(); + std::vector atlasConditions; + std::vector atlasEffects; + + for ( std::list::const_iterator it=conditions.begin(); it!=conditions.end(); ++it ) + atlasConditions.push_back( TriggerSpecToAtlas(*it) ); + for ( std::list::const_iterator it=effects.begin(); it!=effects.end(); ++it ) + atlasEffects.push_back( TriggerSpecToAtlas(*it) ); + + msg->conditions = atlasConditions; + msg->effects = atlasEffects; + msg->groups = GetCurrentTriggers(); +} + +QUERYHANDLER(GetTriggerChoices) +{ + CStrW selectedName(*msg->name); + std::vector choices = g_TriggerManager.GetTriggerChoices(selectedName); + std::vector translations = g_TriggerManager.GetTriggerTranslations(selectedName); + + if ( choices.empty() ) + return; + + //If a special list (i.e. uses engine data) + if ( choices.size() == 1 ) + { + + if ( choices[0] == std::wstring(L"ATLAS_CINEMA_LIST") ) + { + choices.clear(); + const std::map& paths = g_Game->GetView()->GetCinema()->GetAllPaths(); + for ( std::map::const_iterator it = paths.begin(); it != paths.end(); ++it ) + { + choices.push_back(it->first); + translations.push_back( L"\"" + it->first + L"\"" ); //Strings need quotes in JS + } + } + else if ( choices[0] == std::wstring(L"ATLAS_TRIGGER_LIST") ) + { + choices.clear(); + const std::list& groups = g_TriggerManager.GetAllTriggerGroups(); + for ( std::list::const_iterator it = groups.begin(); + it != groups.end(); ++it ) + { + for ( std::list::const_iterator it2 = it->triggers.begin(); + it2 != it->triggers.end(); ++it2 ) + { + choices.push_back(it2->name); + translations.push_back( L"\"" + it2->name + L"\"" ); + } + } + } + else if ( choices[0] == std::wstring(L"ATLAS_TRIG_GROUP_LIST") ) + { + choices.clear(); + const std::list& groups = g_TriggerManager.GetAllTriggerGroups(); + for ( std::list::const_iterator it = groups.begin(); + it != groups.end(); ++it ) + { + choices.push_back(it->name); + translations.push_back( L"\"" + it->name + L"\"" ); + } + } + else + debug_warn("Invalid special choice list for trigger specification parameter"); + } + msg->choices = choices; + msg->translations = translations; +} + +QUERYHANDLER(GetWorldPosition) +{ + Position pos; + pos.type1.x = msg->x; + pos.type1.y = msg->y; + CVector3D worldPos = pos.GetWorldSpace(); + Position ret(worldPos.X, worldPos.Y, worldPos.Z); + msg->position = ret; +} +BEGIN_COMMAND(SetAllTriggers) +{ + std::vector m_oldGroups, m_newGroups; + + void Do() + { + m_oldGroups = GetCurrentTriggers(); + m_newGroups = *msg->groups; + Redo(); + } + void Redo() + { + SetCurrentTriggers(m_newGroups); + } + void Undo() + { + SetCurrentTriggers(m_oldGroups); + } +}; +END_COMMAND(SetAllTriggers) + + +MESSAGEHANDLER(TriggerToggleSelector) +{ + //TODO: Draw stuff + UNUSED2(msg); +} + +}