#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()) ); }