Skip to content

Instantly share code, notes, and snippets.

@8785496
Created April 13, 2017 10:39
Show Gist options
  • Select an option

  • Save 8785496/044b4de69e2ce2e6df30a0f29a13de04 to your computer and use it in GitHub Desktop.

Select an option

Save 8785496/044b4de69e2ce2e6df30a0f29a13de04 to your computer and use it in GitHub Desktop.
Text editor wxWidgets
// Main.cpp
#include <wx/wx.h>
#include "App.h"
IMPLEMENT_APP(App)
// App.h
#include <wx/wx.h>
#include "Frame.h"
class App : public wxApp
{
public:
bool OnInit();
};
bool App::OnInit()
{
Frame<wxFileDialog> *frame = new Frame<wxFileDialog>();
frame->Show(true);
return true;
}
// Frame.h
#pragma once
#include <wx/wx.h>
#include "CodeTextCtrl.h"
template <class FileDialog>
class Frame : public wxFrame
{
public:
Frame();
CodeTextCtrl *text;
protected:
void OnNew(wxCommandEvent& event);
void OnOpen(wxCommandEvent& event);
void OnSaveAs(wxCommandEvent& event);
void OnSave(wxCommandEvent& event);
void OnExit(wxCommandEvent& event);
void OnModified(wxStyledTextEvent& event);
wxString fileName;
};
template <class FileDialog>
Frame<FileDialog>::Frame() : wxFrame(NULL, wxID_ANY, "Текстовый редактор C++", wxDefaultPosition, wxSize(800, 600))
{
text = new CodeTextCtrl(this);
wxBoxSizer* sizer = new wxBoxSizer(wxVERTICAL);
sizer->Add(text, 1, wxEXPAND);
SetSizer(sizer);
wxMenu *menuFile = new wxMenu;
menuFile->Append(wxID_NEW, "&Создать...\tCtrl-N", "Создать новый файл");
menuFile->AppendSeparator();
menuFile->Append(wxID_OPEN, "&Открыть...\tCtrl-O", "Открыть файл");
menuFile->AppendSeparator();
menuFile->Append(wxID_SAVE, "&Сохранить\tCtrl-S", "Сохранить изменения");
menuFile->Append(wxID_SAVEAS, "&Сохранить как...", "Сохранить файл как...");
menuFile->AppendSeparator();
menuFile->Append(wxID_EXIT, "&Выход", "Закрыть программу");
wxMenuBar *menuBar = new wxMenuBar;
menuBar->Append(menuFile, "&Файл");
SetMenuBar(menuBar);
CreateStatusBar();
SetStatusText("Текстовый редактор кода C++ с подсветкой синтаксиса");
Bind(wxEVT_MENU, &Frame::OnExit, this, wxID_EXIT);
Bind(wxEVT_MENU, &Frame::OnNew, this, wxID_NEW);
Bind(wxEVT_MENU, &Frame::OnOpen, this, wxID_OPEN);
Bind(wxEVT_MENU, &Frame::OnSaveAs, this, wxID_SAVEAS);
Bind(wxEVT_MENU, &Frame::OnSave, this, wxID_SAVE);
Bind(wxEVT_STC_CHANGE, &Frame::OnModified, this);
}
template <class FileDialog>
void Frame<FileDialog>::OnNew(wxCommandEvent & event)
{
fileName = "";
text->ClearAll();
SetStatusText("Новый файл");
}
template <class FileDialog>
void Frame<FileDialog>::OnOpen(wxCommandEvent & event)
{
FileDialog openFileDialog(this, "Открыть файл", "", "",
"Файлы исходного кода (*.cpp)|*.cpp|Заголовочные файлы (*.h)|*.h", wxFD_OPEN | wxFD_FILE_MUST_EXIST);
if (openFileDialog.ShowModal() == wxID_CANCEL)
return;
fileName = openFileDialog.GetPath();
if (text->LoadFile(fileName))
SetStatusText("Открыт файл: " + fileName);
else
SetStatusText("Не возможно открыть файл: " + fileName);
}
template <class FileDialog>
void Frame<FileDialog>::OnSaveAs(wxCommandEvent & event)
{
FileDialog saveFileDialog(this, "Сохранить файл", "", "",
"Файлы исходного кода (*.cpp)|*.cpp|Заголовочные файлы (*.h)|*.h", wxFD_SAVE | wxFD_OVERWRITE_PROMPT);
if (saveFileDialog.ShowModal() == wxID_CANCEL)
return;
fileName = saveFileDialog.GetPath();
if (text->SaveFile(fileName))
SetStatusText("Файл сохранен как: " + fileName);
else
SetStatusText("Не возможно сохранить файл: " + fileName);
}
template<class FileDialog>
inline void Frame<FileDialog>::OnSave(wxCommandEvent & event)
{
if (fileName.length() > 0) {
if (text->GetModify()) {
if (text->SaveFile(fileName))
SetStatusText("Изменения сохранены");
else
SetStatusText("Не возможно сохранить изменения");
}
}
else {
OnSaveAs(event);
}
}
template <class FileDialog>
void Frame<FileDialog>::OnExit(wxCommandEvent& event)
{
Close(true);
}
template<class FileDialog>
void Frame<FileDialog>::OnModified(wxStyledTextEvent & event)
{
if (text->GetModify()) {
SetStatusText("Файл изменен");
}
else {
SetStatusText("Нет изменений для сохранения");
}
}
// CodeTextCtrl.h
#pragma once
#include <wx/wx.h>
#include <wx/stc/stc.h>
class CodeTextCtrl : public wxStyledTextCtrl
{
private:
const int MARGIN_LINE_NUMBERS = 0;
const wxString CPP_WORD_1 =
"asm else new this"
"auto enum operator throw "
"bool explicit private true "
"break export protected try "
"case extern public typedef "
"catch false register typeid "
"char float reinterpret_cast typename "
"class for return union "
"const friend short unsigned "
"const_cast goto signed using "
"continue if sizeof virtual "
"default inline static void "
"delete int static__cast volatile "
"do long struct wchar_t "
"double mutable switch while "
"dynamic_cast namespace template";
const int MARKER_TAB = 1;
const int MARKER_EOF = 2;
int markerHandlerEOF = 0;
public:
CodeTextCtrl(wxWindow *);
const int MASK_TAB = (1 << MARKER_TAB);
const int MASK_EOF = (1 << MARKER_EOF);
void OnModified(wxStyledTextEvent& event);
};
// CodeTextCtrl.cpp
#include <wx/wx.h>
#include <wx/stc/stc.h>
#include "CodeTextCtrl.h"
CodeTextCtrl::CodeTextCtrl(wxWindow *parent) : wxStyledTextCtrl(parent)
{
StyleClearAll();
SetLexer(wxSTC_LEX_CPP);
SetMarginWidth(MARGIN_LINE_NUMBERS, 50);
StyleSetForeground(wxSTC_STYLE_LINENUMBER, wxColour(75, 75, 75));
StyleSetBackground(wxSTC_STYLE_LINENUMBER, wxColour(220, 220, 220));
SetMarginType(MARGIN_LINE_NUMBERS, wxSTC_MARGIN_NUMBER);
SetWrapMode(wxSTC_WRAP_NONE); // other choice is wxSTC_WRAP_WORD
SetUseHorizontalScrollBar(false);
wxFont font(8, wxFONTFAMILY_MODERN, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL);
StyleSetFont(wxSTC_STYLE_LINENUMBER, font);
StyleSetFont(wxSTC_STYLE_DEFAULT, font);
StyleSetFont(wxSTC_C_STRING, font);
StyleSetFont(wxSTC_C_STRING, font);
StyleSetFont(wxSTC_C_PREPROCESSOR, font);
StyleSetFont(wxSTC_C_IDENTIFIER, font);
StyleSetFont(wxSTC_C_NUMBER, font);
StyleSetFont(wxSTC_C_CHARACTER, font);
StyleSetFont(wxSTC_C_WORD, font);
StyleSetFont(wxSTC_C_WORD2, font);
StyleSetFont(wxSTC_C_COMMENT, font);
StyleSetFont(wxSTC_C_COMMENTLINE, font);
StyleSetFont(wxSTC_C_COMMENTDOC, font);
StyleSetFont(wxSTC_C_COMMENTDOCKEYWORD, font);
StyleSetFont(wxSTC_C_COMMENTDOCKEYWORDERROR, font);
StyleSetFont(wxSTC_C_OPERATOR, font);
StyleSetFont(wxSTC_C_DEFAULT, font);
StyleSetForeground(wxSTC_C_STRING, wxColour(150, 0, 0));
StyleSetForeground(wxSTC_C_PREPROCESSOR, wxColour(165, 105, 0));
StyleSetForeground(wxSTC_C_IDENTIFIER, wxColour(40, 0, 60));
StyleSetForeground(wxSTC_C_NUMBER, wxColour(0, 150, 0));
StyleSetForeground(wxSTC_C_CHARACTER, wxColour(150, 0, 0));
StyleSetForeground(wxSTC_C_WORD, wxColour(0, 0, 150));
StyleSetForeground(wxSTC_C_WORD2, wxColour(0, 150, 0));
StyleSetForeground(wxSTC_C_COMMENT, wxColour(150, 150, 150));
StyleSetForeground(wxSTC_C_COMMENTLINE, wxColour(150, 150, 150));
StyleSetForeground(wxSTC_C_COMMENTDOC, wxColour(150, 150, 150));
StyleSetForeground(wxSTC_C_COMMENTDOCKEYWORD, wxColour(0, 0, 200));
StyleSetForeground(wxSTC_C_COMMENTDOCKEYWORDERROR, wxColour(0, 0, 200));
SetKeyWords(0, CPP_WORD_1);
SetEdgeMode(wxSTC_EDGE_BACKGROUND);
SetEdgeColour(wxColour("red"));
SetEdgeColumn(120);
//SetViewWhiteSpace(wxSTC_WS_VISIBLEALWAYS);
wxColor yellow("yellow");
MarkerDefine(MARKER_TAB, wxSTC_MARK_ARROW);
MarkerSetForeground(MARKER_TAB, yellow);
MarkerSetBackground(MARKER_TAB, yellow);
wxColor orange("orange");
MarkerDefine(MARKER_EOF, wxSTC_MARK_ARROW);
MarkerSetForeground(MARKER_EOF, orange);
MarkerSetBackground(MARKER_EOF, orange);
SetUseTabs(false);
SetTabWidth(4);
SetIndent(4);
Bind(wxEVT_STC_MODIFIED, &CodeTextCtrl::OnModified, this);
}
void CodeTextCtrl::OnModified(wxStyledTextEvent & event)
{
int type = event.GetModificationType();
if ((type & (wxSTC_MOD_INSERTTEXT | wxSTC_MOD_DELETETEXT)) == 0)
return;
int linesAdded = event.GetLinesAdded();
int position = event.GetPosition();
int curLine = LineFromPosition(position);
int lineCount = GetLineCount();
for (int j = curLine; (j <= j + linesAdded) && (j < lineCount); ++j) {
int marker = MarkerGet(j);
bool isTAB = (MASK_TAB & marker) > 0;
wxString line = GetLineText(j);
int i = line.find("\t");
if (i > -1) { // в строке найден символ "\t"
if (!isTAB) { // в строке нет маркера TAB
MarkerAdd(j, MARKER_TAB);
}
}
else { // в строке не найден символ "\t"
if (isTAB) { // установлен маркер TAB
MarkerDelete(j, MARKER_TAB);
}
}
}
if (LineLength(lineCount - 1) > 0) { // длина последней строки больше 0
int markerLine = MarkerLineFromHandle(markerHandlerEOF);
if (markerLine != lineCount - 1)
markerHandlerEOF = MarkerAdd(lineCount - 1, MARKER_EOF);
}
else {
MarkerDeleteHandle(markerHandlerEOF);
markerHandlerEOF = 0;
}
}
// Tests.cpp
#include <gtest/gtest.h>
#include <wx/wx.h>
#include <Frame.h>
#include <CodeTextCtrl.h>
#include <string>
#include <fstream>
const std::string SOME_TEXT_IN("some text in");
const std::string SOME_TEXT_OUT("some text out");
const std::string FILE_NAME("test");
class MockFileDialog
{
public:
MockFileDialog(wxWindow *parent,
const wxString& message = wxFileSelectorPromptStr,
const wxString& defaultDir = wxEmptyString,
const wxString& defaultFile = wxEmptyString,
const wxString& wildCard = wxFileSelectorDefaultWildcardStr,
long style = wxFD_DEFAULT_STYLE,
const wxPoint& pos = wxDefaultPosition,
const wxSize& sz = wxDefaultSize,
const wxString& name = wxFileDialogNameStr) {};
wxString GetPath() {
return wxString(FILE_NAME);
};
int ShowModal() {
return wxID_OPEN;
};
};
TEST(CodeText, TabSpace)
{
wxFrame frame(NULL, wxID_ANY, "");
CodeTextCtrl text(&frame);
const char *textRaw = "1 line\n2\tline\n3 line\n4\tline\n";
text.InsertTextRaw(0, textRaw);
int maskMarkersLine1 = text.MarkerGet(0);
int maskMarkersLine2 = text.MarkerGet(1);
int maskMarkersLine3 = text.MarkerGet(2);
int maskMarkersLine4 = text.MarkerGet(3);
// В первой строке маркер не установлен
ASSERT_EQ(maskMarkersLine1 & text.MASK_TAB, 0);
// Во второй строке маркер установлен
ASSERT_GT(maskMarkersLine2 & text.MASK_TAB, 0);
// В третьей строке маркер не установлен
ASSERT_EQ(maskMarkersLine3 & text.MASK_TAB, 0);
// В четвертой строке маркер установлен
ASSERT_GT(maskMarkersLine4 & text.MASK_TAB, 0);
}
TEST(CodeText, EndOfFile)
{
wxFrame frame(NULL, wxID_ANY, "");
CodeTextCtrl text(&frame);
const char *textRaw = "first line\nsecond line";
int pos = text.GetLastPosition();
text.InsertTextRaw(pos, textRaw);
int lastLineNumber = text.GetLineCount() - 1;
int maskMarkers = text.MarkerGet(lastLineNumber);
// В последней строке установлен маркер
ASSERT_GT(maskMarkers & text.MASK_EOF, 0);
}
TEST(MenuCommand, New)
{
Frame<MockFileDialog> frame;
// Заполняем редактор произвольныи текстом
frame.text->SetText(wxString(SOME_TEXT_IN));
ASSERT_LT(0, frame.text->GetTextLength());
// Команда меню "Создать" должна очищать текст в редакторе
wxCommandEvent evt(wxEVT_MENU, wxID_NEW);
frame.GetEventHandler()->ProcessEvent(evt);
ASSERT_EQ(0, frame.text->GetTextLength());
}
TEST(MenuCommand, Open)
{
Frame<MockFileDialog> frame;
std::ofstream file(FILE_NAME);
file << SOME_TEXT_IN;
file.close();
// Команда меню "Открыть..." загружает текст в редактор из файла
wxCommandEvent evt(wxEVT_MENU, wxID_OPEN);
frame.GetEventHandler()->ProcessEvent(evt);
const std::string result = frame.text->GetText().ToStdString();
ASSERT_EQ(std::string(SOME_TEXT_IN), result);
}
TEST(MenuCommand, SaveAs)
{
Frame<MockFileDialog> frame;
frame.text->SetText(wxString(SOME_TEXT_OUT));
// Команда меню "Сохранить как..." сохраняет текст из редактора в файл
wxCommandEvent evt(wxEVT_MENU, wxID_SAVEAS);
frame.GetEventHandler()->ProcessEvent(evt);
std::string result;
std::ifstream file(FILE_NAME);
std::getline(file, result);
ASSERT_EQ(SOME_TEXT_OUT, result);
}
TEST(MenuCommand, Save)
{
Frame<MockFileDialog> frame;
std::ofstream file(FILE_NAME);
file << SOME_TEXT_IN;
file.close();
// Команда меню "Открыть..." загружает текст в редактор из файла
wxCommandEvent evt(wxEVT_MENU, wxID_OPEN);
frame.GetEventHandler()->ProcessEvent(evt);
int lastPos = frame.text->GetLastPosition();
frame.text->InsertTextRaw(lastPos, SOME_TEXT_OUT.c_str());
// Команда меню "Сохранить" сохраняет изменения в файл
wxCommandEvent evt2(wxEVT_MENU, wxID_SAVE);
frame.GetEventHandler()->ProcessEvent(evt2);
std::string result;
std::ifstream file2(FILE_NAME);
std::getline(file2, result);
ASSERT_EQ(SOME_TEXT_IN + SOME_TEXT_OUT, result);
}
@Diaz123-droid
Copy link

Wxwidgets is one hell of a ride for me as a beginner because there's just so much to explore. I've been trying to find out how to save files with wxwidgets and I think am in the right place. Thanks very much.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment