From 6dec55b0d212fa3a57c3d4e6e7e93e1ff3b109b1 Mon Sep 17 00:00:00 2001 From: Tim Warren Date: Thu, 16 Apr 2015 17:03:27 -0400 Subject: [PATCH] Code folding, save on close prompting, and more --- config/languages.json | 2 +- src/TyroApp.cpp | 6 +- src/TyroApp.h | 7 +- src/definitions.h | 33 ++++--- src/widgets/EditPane.cpp | 173 ++++++++++++++++++++++++++--------- src/widgets/EditPane.h | 7 +- src/widgets/MainFrame.cpp | 58 +++++++++--- src/widgets/MainFrame.h | 5 +- src/widgets/TabContainer.cpp | 27 +----- src/widgets/TabContainer.h | 2 - 10 files changed, 213 insertions(+), 107 deletions(-) diff --git a/config/languages.json b/config/languages.json index 29cdd10..9743f9a 100644 --- a/config/languages.json +++ b/config/languages.json @@ -51,7 +51,7 @@ "makefile": { "file_pattern": "Makefile;makefile.*,configure.*;*.mak", "keywords": [ - "" + "subst patsubst strip findstring filter filter-out sort word wordlist words firstword lastword dir notdir suffix basename foreach file call value eval origin flavor shell guile" ] }, "php": { diff --git a/src/TyroApp.cpp b/src/TyroApp.cpp index b6cf528..881ecb1 100644 --- a/src/TyroApp.cpp +++ b/src/TyroApp.cpp @@ -15,12 +15,16 @@ IMPLEMENT_APP(TyroApp); bool TyroApp::OnInit() { + this->SetAppName(APP_NAME); + this->SetVendorName(APP_VENDOR); + MainFrame* frame = new MainFrame(0L, _("Tyro")); + SetTopWindow(frame); + frame->Layout(); frame->CenterOnScreen(); frame->Show(true); - SetTopWindow(frame); return true; } diff --git a/src/TyroApp.h b/src/TyroApp.h index 5a15f3a..a1fd646 100644 --- a/src/TyroApp.h +++ b/src/TyroApp.h @@ -18,9 +18,10 @@ class TyroApp : public wxApp { friend class MainFrame; - public: - virtual bool OnInit(); - virtual int OnExit(); +public: + virtual bool OnInit(); + virtual int OnExit(); +private: }; #endif // TYROAPP_H diff --git a/src/definitions.h b/src/definitions.h index f5f84db..2b45572 100644 --- a/src/definitions.h +++ b/src/definitions.h @@ -5,6 +5,10 @@ #ifndef DEFINITIONS_H #define DEFINITIONS_H +// Application config +const wxString APP_NAME = _T("Tyro"); +const wxString APP_VENDOR = _T("Aviat Ion"); + // EditPane file extension to lexer mapping typedef pair StringConstMapData; typedef map StringConstMap; @@ -29,24 +33,23 @@ const wxString TYRO_FILE_OPEN_WILDCARDS = _T("Text (*.txt)|*.txt"); const wxString TYRO_FILE_SAVE_WILDCARDS = - _T("HTML/XHTML (*.html)|*.html|") - _T("CSS (*.css)|*.css|") - _T("JavaScript(*.js)|*.js|") - _T("SQL (*.sql)|*.sql|") - _T("Perl (*.pl, *.cgi)|*.pl;*.cgi|") - _T("PHP (*.php)|*.php|") - _T("Java (*.java)|*.java|") - _T("Fortran (*.f9*, *.f, *.for)|*.f9*;*.f,*.for|") - _T("Pascal (*.pas, *.inc, *.pp)|*.pas;*.inc;*.pp|") + _T("All files (*.*)|*.*|") + _T("Bash (*.sh, *.bsh) |*.sh;*.bsh|") + _T("Batch (*.bat, *.cmd, *.nt)|*.bat;*.cmd,*.nt|") _T("C/C++ (*.c,*.cpp,*.h)| *.c;*.cc;*.cpp;*.cxx;*.cs;*.h;*.hh;*.hpp;*.hxx;*.sma;*.cp |") - _T("Makefile |Makefile|") + _T("CSS (*.css)|*.css|") + _T("Fortran (*.f9*, *.f, *.for)|*.f9*;*.f,*.for|") + _T("HTML/XHTML (*.html, *.htm)|*.htm*|") + _T("Java (*.java)|*.java|") + _T("JavaScript(*.js)|*.js|") + _T("Makefile |Makefile;makefile.*;MAKEFILE;configure.*;*.mak|") + _T("Pascal (*.pas, *.inc, *.pp)|*.pas;*.inc;*.pp|") + _T("Perl (*.pl, *.cgi)|*.pl;*.pm;*.cgi;*.pod|") + _T("PHP (*.php)|*.php|") _T("Ruby (*.rb)|*.rb|") - _T("Blitz Basic files (*.bb)|*.bb|") + _T("SQL (*.sql)|*.sql|") _T("TCL (*.tcl)|*.tcl|") - _T("Bash (*.sh) |*.sh|") - _T("Batch (*.bat)|*.bat|") - _T("Text (*.txt)|*.txt|") - _T("Other (*.*)|*.*"); + _T("Text (*.txt)|*.txt"); diff --git a/src/widgets/EditPane.cpp b/src/widgets/EditPane.cpp index 5a0d641..f711176 100644 --- a/src/widgets/EditPane.cpp +++ b/src/widgets/EditPane.cpp @@ -6,6 +6,7 @@ EditPane::EditPane( ) : wxStyledTextCtrl (parent, id, pos, size, style) { config = new TyroConfig(); + lexerMap["batch"] = wxSTC_LEX_BATCH; lexerMap["caml"] = wxSTC_LEX_CAML; lexerMap["cmake"] = wxSTC_LEX_CMAKE; @@ -14,10 +15,12 @@ EditPane::EditPane( lexerMap["js"] = wxSTC_LEX_CPP; lexerMap["html"] = wxSTC_LEX_HTML; lexerMap["makefile"] = wxSTC_LEX_MAKEFILE; - lexerMap["php"] = wxSTC_LEX_PHPSCRIPT; + lexerMap["php"] = wxSTC_LEX_PHPSCRIPT | wxSTC_LEX_HTML; lexerMap["perl"] = wxSTC_LEX_PERL; lexerMap["python"] = wxSTC_LEX_PYTHON; lexerMap["shell"] = wxSTC_LEX_BASH; + + this->BindEvents(); } EditPane::~EditPane() @@ -25,40 +28,6 @@ EditPane::~EditPane() delete config; } -string EditPane::GetLangByFile(const wxString &filename) -{ - JsonValue langList = config->GetRoot(); - JsonValue::iterator it; - - // Loop through each language to find a matching file pattern - for (it = langList.begin(); it != langList.end(); ++it) - { - string lang = it.key().asString(); - - - // Parse the file pattern - wxString file_pattern((*it)["file_pattern"].asString()); - - file_pattern.Lower(); - - while ( ! file_pattern.empty()) - { - wxString cur = file_pattern.BeforeFirst(';'); - if ( - (cur == filename) || - (cur == (filename.BeforeLast('.') + _T(".*"))) || - (cur == (_T("*.") + filename.AfterLast('.'))) - ) - { - return lang; - } - file_pattern = file_pattern.AfterFirst(';'); - } - } - - return ""; -} - /** * Encapsulate lexer selection when opening a file * @@ -68,10 +37,18 @@ string EditPane::GetLangByFile(const wxString &filename) bool EditPane::LoadAndHighlight(wxString filePath) { fileName = filePath; - string lang = this->GetLangByFile(filePath); + string lang = this->GetLangByFile(); this->StyleClearAll(); + // Font setup + wxFont *defaultFont = wxFont::New( + 14, + wxFONTFAMILY_MODERN, + wxFONTFLAG_ANTIALIASED, + "Anonymous Pro" + ); + if (lexerMap.count(lang) > 0) { this->SetLexer(lexerMap[lang]); @@ -88,21 +65,17 @@ bool EditPane::LoadAndHighlight(wxString filePath) for(int i = 0; i <= wxSTC_STYLE_MAX; i++) { this->StyleSetBackground(i, wxColor(253, 246, 227)); - this->StyleSetFaceName(i, "Anonymous Pro"); + this->StyleSetFont(i, *defaultFont); } this->StyleSetForeground (wxSTC_STYLE_DEFAULT, wxColor(101, 123, 131)); this->StyleSetForeground(wxSTC_STYLE_INDENTGUIDE, wxColor(147, 161, 161)); - this->SetMarginWidth (MARGIN_LINE_NUMBERS, 50); + this->SetMarginWidth (MARGIN_LINE_NUMBERS, TextWidth(wxSTC_STYLE_LINENUMBER, _T("_9999"))); this->StyleSetForeground (wxSTC_STYLE_LINENUMBER, wxColor(147, 161, 161)); this->StyleSetBackground (wxSTC_STYLE_LINENUMBER, wxColor(238, 232, 213)); this->SetMarginType (MARGIN_LINE_NUMBERS, wxSTC_MARGIN_NUMBER); - this->SetProperty (wxT("fold"), wxT("1") ); - this->SetProperty (wxT("fold.comment"), wxT("1") ); - this->SetProperty (wxT("fold.compact"), wxT("1") ); - this->StyleSetForeground(wxSTC_C_DEFAULT, wxColor(101, 123, 131)); this->StyleSetForeground(wxSTC_C_OPERATOR, wxColor(101, 123, 131)); this->StyleSetForeground(wxSTC_C_HASHQUOTEDSTRING, wxColor(181, 137, 0)); @@ -125,6 +98,33 @@ bool EditPane::LoadAndHighlight(wxString filePath) this->StyleSetBold(wxSTC_C_COMMENTDOCKEYWORD, true); this->StyleSetBold(wxSTC_C_OPERATOR, true); + // Set up Code folding + this->SetProperty(wxT("fold"), wxT("1")); + this->SetProperty(wxT("fold.comment"), wxT("1")); + this->SetProperty(wxT("fold.compact"), wxT("1")); + this->SetProperty(wxT("fold.html"), wxT("1")); + this->SetFoldFlags(wxSTC_FOLDFLAG_LINEBEFORE_CONTRACTED | wxSTC_FOLDFLAG_LINEAFTER_CONTRACTED); + this->SetMarginType(MARGIN_FOLD, wxSTC_MARGIN_SYMBOL); + this->SetMarginWidth(MARGIN_FOLD, 16); + this->SetMarginSensitive(MARGIN_FOLD, true); + this->SetMarginMask(MARGIN_FOLD, wxSTC_MASK_FOLDERS); + this->MarkerDefine (wxSTC_MARKNUM_FOLDER, wxSTC_MARK_BOXPLUSCONNECTED, _T("WHITE"), _T("BLACK")); + this->MarkerDefine (wxSTC_MARKNUM_FOLDEROPEN, wxSTC_MARK_BOXMINUSCONNECTED, _T("WHITE"), _T("BLACK")); + this->MarkerDefine (wxSTC_MARKNUM_FOLDERSUB, wxSTC_MARK_VLINE, _T("BLACK"), _T("BLACK")); + this->MarkerDefine (wxSTC_MARKNUM_FOLDEREND, wxSTC_MARK_CIRCLEPLUSCONNECTED, _T("WHITE"), _T("BLACK")); + this->MarkerDefine (wxSTC_MARKNUM_FOLDEROPENMID, wxSTC_MARK_CIRCLEMINUSCONNECTED, _T("WHITE"), _T("BLACK")); + this->MarkerDefine (wxSTC_MARKNUM_FOLDERMIDTAIL, wxSTC_MARK_TCORNER, _T("BLACK"), _T("BLACK")); + this->MarkerDefine (wxSTC_MARKNUM_FOLDERTAIL, wxSTC_MARK_LCORNER, _T("BLACK"), _T("BLACK")); + + this->SetLayoutCache (wxSTC_CACHE_NONE); + this->SetUseHorizontalScrollBar(1); + + // set spaces and indention + this->SetTabWidth(4); + this->SetUseTabs(true); + this->SetTabIndents(true); + this->SetBackSpaceUnIndents(true); + if (keywords_array.isArray()) { for(int i = 0; i < keywords_array.size(); i++) @@ -134,9 +134,96 @@ bool EditPane::LoadAndHighlight(wxString filePath) } else { + string typeMap[] = {"null", "int", "unsigned int", "double", "string", "boolean", "array", "object"}; + + cerr << "current lang is:" << lang << endl; cerr << "keywords array is not an array" << endl; - cerr << "keyword array is a " << keywords_array.type() << endl; + cerr << "keyword array is a " << typeMap[keywords_array.type()] << endl; } return this->LoadFile(filePath); } + +string EditPane::GetLangByFile() +{ + JsonValue langList = config->GetRoot(); + JsonValue::iterator it; + + wxFileName fname(this->fileName); + wxString curr_file = fname.GetFullName(); + + // Loop through each language to find a matching file pattern + for (it = langList.begin(); it != langList.end(); ++it) + { + string lang = it.key().asString(); + + + // Parse the file pattern + wxString file_pattern((*it)["file_pattern"].asString()); + + file_pattern.Lower(); + + while ( ! file_pattern.empty()) + { + wxString cur = file_pattern.BeforeFirst(';'); + if ( + (cur == curr_file) || + (cur == (curr_file.BeforeLast('.') + _T(".*"))) || + (cur == (_T("*.") + curr_file.AfterLast('.'))) + ) + { + return lang; + } + file_pattern = file_pattern.AfterFirst(';'); + } + } + + return ""; +} + +bool EditPane::SaveFile() +{ + if ( ! this->fileName) + { + wxFileDialog dlg ( + this, + _T("Save file"), + wxEmptyString, + wxEmptyString, + TYRO_FILE_SAVE_WILDCARDS, + wxFD_SAVE | wxFD_OVERWRITE_PROMPT + ); + + if (dlg.ShowModal() != wxID_OK) return false; + this->fileName = dlg.GetPath(); + } + + return this->SaveFile(this->fileName); +} + +bool EditPane::SaveFile(const wxString &filename) +{ + if ( ! this->IsModified()) return true; + return wxStyledTextCtrl::SaveFile(filename); +} + +bool EditPane::IsModified() +{ + return (GetModify() && !GetReadOnly()); +} + +void EditPane::BindEvents() +{ + Bind(wxEVT_STC_MARGINCLICK, &EditPane::OnMarginClick, this, wxID_ANY); +} + +void EditPane::OnMarginClick(wxStyledTextEvent& event) +{ + if (event.GetMargin() == MARGIN_FOLD) { + int lineClick = this->LineFromPosition (event.GetPosition()); + int levelClick = this->GetFoldLevel (lineClick); + if ((levelClick & wxSTC_FOLDLEVELHEADERFLAG) > 0) { + this->ToggleFold (lineClick); + } + } +} diff --git a/src/widgets/EditPane.h b/src/widgets/EditPane.h index 9cf3978..74f5465 100644 --- a/src/widgets/EditPane.h +++ b/src/widgets/EditPane.h @@ -22,8 +22,11 @@ public: ); ~EditPane(); wxString fileName; - string GetLangByFile(const wxString &filename); + string GetLangByFile(); bool LoadAndHighlight(wxString filePath); + bool SaveFile(); + bool SaveFile(const wxString &filename); + bool IsModified(); private: StringConstMap lexerMap; StringConstMap::iterator lexerMapIt; @@ -33,6 +36,8 @@ private: MARGIN_LINE_NUMBERS, MARGIN_FOLD }; + void BindEvents(); + void OnMarginClick(wxStyledTextEvent &event); }; #endif // TYRODOC_FRAME_H diff --git a/src/widgets/MainFrame.cpp b/src/widgets/MainFrame.cpp index 2d38f0e..8cf52c9 100644 --- a/src/widgets/MainFrame.cpp +++ b/src/widgets/MainFrame.cpp @@ -1,11 +1,6 @@ /** * Main Application Frame */ - -#ifdef WX_PRECOMP -#include "wx_pch.h" -#endif - #include "MainFrame.h" MainFrame::MainFrame(wxFrame *frame, const wxString& title) @@ -23,16 +18,14 @@ MainFrame::MainFrame(wxFrame *frame, const wxString& title) wxBoxSizer *base_sizer = new wxBoxSizer(wxVERTICAL); base_sizer->Add(notebook, 1, wxEXPAND | wxALL, 5); - base_sizer->SetContainingWindow(this); base_sizer->SetMinSize(600,400); - - SetSizerAndFit(base_sizer); this->DisableEditControls(); - - // Finally, bind events this->BindEvents(); + + // Do the layout + SetSizerAndFit(base_sizer); } @@ -52,6 +45,7 @@ void MainFrame::SetupToolbar() #include "../../resources/xpm/file_add.xpm" #include "../../resources/xpm/folder.xpm" #include "../../resources/xpm/diskette.xpm" + #include "../../resources/xpm/close.xpm" #include "../../resources/xpm/copy.xpm" #include "../../resources/xpm/scissors.xpm" #include "../../resources/xpm/clipboard.xpm" @@ -59,6 +53,7 @@ void MainFrame::SetupToolbar() wxBitmap new_file_icon(file_add); wxBitmap open_file_icon(folder); wxBitmap save_file_icon(diskette); + wxBitmap close_file_icon(close); wxBitmap copy_icon(copy); wxBitmap cut_icon(scissors); wxBitmap paste_icon(clipboard); @@ -66,6 +61,7 @@ void MainFrame::SetupToolbar() wxBitmap new_file_icon = wxArtProvider::GetBitmap(wxART_NEW); wxBitmap open_file_icon = wxArtProvider::GetBitmap(wxART_FILE_OPEN); wxBitmap save_file_icon = wxArtProvider::GetBitmap(wxART_FILE_SAVE); + wxBitmap close_file_icon = wxArtProvider::GetBitmap(wxART_FILE_CLOSE); wxBitmap copy_icon = wxArtProvider::GetBitmap(wxART_COPY); wxBitmap cut_icon = wxArtProvider::GetBitmap(wxART_CUT); wxBitmap paste_icon = wxArtProvider::GetBitmap(wxART_PASTE); @@ -78,6 +74,7 @@ void MainFrame::SetupToolbar() toolBar->AddTool(wxID_NEW, "New", new_file_icon, "New file"); toolBar->AddTool(wxID_OPEN, "Open", open_file_icon, "Open file"); toolBar->AddTool(wxID_SAVE, "Save", save_file_icon, "Save file"); + toolBar->AddTool(wxID_CLOSE, "Close", close_file_icon, "Close file"); toolBar->AddSeparator(); toolBar->AddTool(wxID_COPY, "Copy", copy_icon, "Copy"); toolBar->AddTool(wxID_CUT, "Cut", cut_icon, "Cut"); @@ -139,7 +136,7 @@ void MainFrame::BindEvents() Bind(wxEVT_COMMAND_MENU_SELECTED, &MainFrame::OnOpen, this, wxID_OPEN); Bind(wxEVT_COMMAND_MENU_SELECTED, &MainFrame::OnSave, this, wxID_SAVE); Bind(wxEVT_COMMAND_MENU_SELECTED, &MainFrame::OnSaveAs, this, wxID_SAVEAS); - Bind(wxEVT_CLOSE_WINDOW, &TabContainer::OnClose, notebook, wxID_CLOSE); + Bind(wxEVT_COMMAND_MENU_SELECTED, &MainFrame::OnCloseTab, this, wxID_CLOSE); Bind(wxEVT_COMMAND_MENU_SELECTED, &MainFrame::OnAbout, this, wxID_ABOUT); Bind(wxEVT_COMMAND_MENU_SELECTED, &MainFrame::OnQuit, this, wxID_EXIT); Bind(wxEVT_COMMAND_MENU_SELECTED, &MainFrame::OnEditCut, this, wxID_CUT); @@ -172,9 +169,42 @@ void MainFrame::OnOpen(wxCommandEvent &WXUNUSED(event)) notebook->AddTab(filename); } -void MainFrame::OnFileClose(wxCommandEvent &WXUNUSED(event)) +void MainFrame::OnCloseTab(wxCommandEvent &WXUNUSED(event)) { - // @TODO Implement OnFileClose + int current_tab = notebook->GetSelection(); + EditPane *editor = notebook->GetCurrentEditor(); + if (editor->IsModified()) + { + int Msgbox_Choice = wxMessageBox( + _T("File has not been saved, save file before closing?"), + _T("Modified File"), + wxYES_NO | wxCANCEL | wxICON_QUESTION, + this + ); + + if (Msgbox_Choice == wxYES) + { + editor->SaveFile(); + if (editor->IsModified()) + { + wxMessageBox(_("File could not be saved"), _("Error"), wxOK | wxICON_EXCLAMATION); + return; + } + //notebook->DeletePage(current_tab); + } + else if (Msgbox_Choice == wxCANCEL) + { + return; + } + } + + notebook->DeletePage(current_tab); + + // Disable controls + if (notebook->GetPageCount() == 0) + { + this->DisableEditControls(); + } } void MainFrame::OnSave(wxCommandEvent &WXUNUSED(event)) @@ -296,4 +326,4 @@ void MainFrame::DisableEditControls() toolBar->EnableTool(wxID_COPY, false); toolBar->EnableTool(wxID_CUT, false); toolBar->EnableTool(wxID_PASTE, false); -} +} \ No newline at end of file diff --git a/src/widgets/MainFrame.h b/src/widgets/MainFrame.h index ac6c40e..e843dd7 100644 --- a/src/widgets/MainFrame.h +++ b/src/widgets/MainFrame.h @@ -8,6 +8,8 @@ #include "../wx_common.h" #include "../TyroApp.h" +#include +#include #include #include "TabContainer.h" @@ -31,6 +33,7 @@ class MainFrame: public wxFrame idMenuQuit = 1000, idMenuAbout }; + wxRect DetermineFrameSize(); void SetupMenu(); void SetupToolbar(); void SetupStatusBar(); @@ -48,7 +51,7 @@ class MainFrame: public wxFrame void OnEditSelectAll(wxCommandEvent &event); void OnEditUndo(wxCommandEvent &event); void OnEditRedo(wxCommandEvent &event); - void OnClose(wxCloseEvent &event); + void OnCloseTab(wxCommandEvent &event); void OnQuit(wxCommandEvent &event); void OnAbout(wxCommandEvent &event); }; diff --git a/src/widgets/TabContainer.cpp b/src/widgets/TabContainer.cpp index 48687d9..ae17d67 100644 --- a/src/widgets/TabContainer.cpp +++ b/src/widgets/TabContainer.cpp @@ -5,7 +5,6 @@ #include "TabContainer.h" static unsigned long untitled_document_count = 0; -static unsigned long open_document_count = 0; TabContainer::TabContainer( wxWindow* parent, @@ -22,7 +21,6 @@ TabContainer::~TabContainer() {} void TabContainer::AddTab() { untitled_document_count++; - open_document_count++; wxString caption; @@ -35,8 +33,6 @@ void TabContainer::AddTab() void TabContainer::AddTab(wxString filePath) { - open_document_count++; - wxFileName fileName(filePath); wxString caption= fileName.GetFullName(); @@ -63,25 +59,4 @@ void TabContainer::AddTab(wxString filePath) EditPane *TabContainer::GetCurrentEditor() { return (EditPane *) this->GetCurrentPage(); -} - -void TabContainer::OnClose(wxCloseEvent &event) -{ - //EditPane *currentTab = this->GetCurrentEditor(); - - if (event.CanVeto() && false)//currentTab->isModified()) - { - if ( - wxMessageBox("The file has not been saved... continue closing?", - "Please confirm", - wxICON_QUESTION | wxYES_NO - ) != wxYES - ) - { - event.Veto(); - return; - } - } - - Destroy(); -} +} \ No newline at end of file diff --git a/src/widgets/TabContainer.h b/src/widgets/TabContainer.h index 38fc9a9..55e042b 100644 --- a/src/widgets/TabContainer.h +++ b/src/widgets/TabContainer.h @@ -29,8 +29,6 @@ public: ~TabContainer(); void AddTab(); void AddTab(wxString filePath); - void OnEditSelectAll(wxCommandEvent &event); - void OnClose(wxCloseEvent &event); EditPane *GetCurrentEditor(); private: };