基本版本

This commit is contained in:
2026-02-27 12:31:38 +08:00
commit 7ef53ce6cf
11 changed files with 967 additions and 0 deletions

17
.clang-format Normal file
View File

@@ -0,0 +1,17 @@
BasedOnStyle: LLVM
IndentWidth: 4
PointerAlignment: Left
AccessModifierOffset: -4
BreakBeforeBraces: Custom
BraceWrapping:
AfterFunction: true
AfterClass: true
Cpp11BracedListStyle: true
ReflowComments: true
SpacesBeforeTrailingComments: 3
TabWidth: 4
ConstructorInitializerAllOnOneLineOrOnePerLine: true
ColumnLimit: 130
AllowShortBlocksOnASingleLine: Never
AllowShortFunctionsOnASingleLine: None
AllowShortEnumsOnASingleLine: false

45
.gitignore vendored Normal file
View File

@@ -0,0 +1,45 @@
# Prerequisites
*.d
.idea
cmake-build-*
# Compiled Object files
*.slo
*.lo
*.o
*.obj
# Precompiled Headers
*.gch
*.pch
# Compiled Dynamic libraries
*.so
*.dylib
*.dll
# Fortran module files
*.mod
*.smod
# Compiled Static libraries
*.lai
*.la
*.a
*.lib
!lebo_motor.lib
!lebo_motor.dll
!liblebo_motor.so
# Executables
*.exe
*.out
*.app
build
*.user
compile_commands.json
.vs
out
.cache
CMakeLists.txt.*

173
.vscode/settings.json vendored Normal file
View File

@@ -0,0 +1,173 @@
{
"files.autoSave": "onFocusChange",
"editor.fontSize": 14,
"cmake.configureOnOpen": true,
"editor.fontFamily": "'Maple Mono NL NF CN Light', 'Maple Mono NL NF CN Light', 'Maple Mono NL NF CN Light'",
"cmake.debugConfig": {
"type": "lldb",
"console": "externalTerminal",
"setupCommands": [
{
"description": "Enable pretty-printing for gdb",
"text": "-enable-pretty-printing",
"ignoreFailures": true
}
],
"args": []
},
"cmake.configureSettings": {
"CMAKE_PREFIX_PATH": "C:/local",
},
"cmake.configureArgs": [
"-Wno-dev"
],
"cmake.options.statusBarVisibility": "visible",
"cmake.generator": "Ninja",
"C_Cpp.default.compileCommands": "${workspaceRoot}/build/compile_commands.json",
"C_Cpp.default.cppStandard": "c++17",
"C_Cpp.default.configurationProvider": "ms-vscode.cmake-tools",
"editor.inlayHints.enabled": "off",
"editor.unicodeHighlight.allowedLocales": {
"ja": true,
"zh-hant": true,
"zh-hans": true
},
"files.associations": {
"string": "cpp",
"any": "cpp",
"array": "cpp",
"atomic": "cpp",
"bit": "cpp",
"bitset": "cpp",
"cctype": "cpp",
"charconv": "cpp",
"chrono": "cpp",
"clocale": "cpp",
"cmath": "cpp",
"codecvt": "cpp",
"compare": "cpp",
"concepts": "cpp",
"condition_variable": "cpp",
"cstdarg": "cpp",
"cstddef": "cpp",
"cstdint": "cpp",
"cstdio": "cpp",
"cstdlib": "cpp",
"cstring": "cpp",
"ctime": "cpp",
"cwchar": "cpp",
"cwctype": "cpp",
"deque": "cpp",
"forward_list": "cpp",
"list": "cpp",
"map": "cpp",
"set": "cpp",
"unordered_map": "cpp",
"unordered_set": "cpp",
"vector": "cpp",
"exception": "cpp",
"algorithm": "cpp",
"functional": "cpp",
"iterator": "cpp",
"memory": "cpp",
"memory_resource": "cpp",
"numeric": "cpp",
"optional": "cpp",
"random": "cpp",
"ratio": "cpp",
"source_location": "cpp",
"string_view": "cpp",
"system_error": "cpp",
"tuple": "cpp",
"type_traits": "cpp",
"utility": "cpp",
"format": "cpp",
"initializer_list": "cpp",
"iomanip": "cpp",
"iosfwd": "cpp",
"iostream": "cpp",
"istream": "cpp",
"limits": "cpp",
"mutex": "cpp",
"new": "cpp",
"numbers": "cpp",
"ostream": "cpp",
"queue": "cpp",
"ranges": "cpp",
"semaphore": "cpp",
"shared_mutex": "cpp",
"span": "cpp",
"sstream": "cpp",
"stdexcept": "cpp",
"stop_token": "cpp",
"streambuf": "cpp",
"text_encoding": "cpp",
"thread": "cpp",
"cfenv": "cpp",
"cinttypes": "cpp",
"typeinfo": "cpp",
"variant": "cpp",
"ios": "cpp",
"locale": "cpp",
"xfacet": "cpp",
"xhash": "cpp",
"xiosbase": "cpp",
"xlocale": "cpp",
"xlocbuf": "cpp",
"xlocinfo": "cpp",
"xlocmes": "cpp",
"xlocmon": "cpp",
"xlocnum": "cpp",
"xloctime": "cpp",
"xmemory": "cpp",
"xstring": "cpp",
"xtr1common": "cpp",
"xutility": "cpp",
"coroutine": "cpp",
"csignal": "cpp",
"future": "cpp",
"stdfloat": "cpp",
"regex": "cpp",
"stack": "cpp",
"valarray": "cpp",
"filesystem": "cpp",
"qmainwindow": "cpp",
"qlabel": "cpp",
"*.in": "cpp",
"fstream": "cpp",
"xmemory0": "cpp",
"xstddef": "cpp",
"xtree": "cpp",
"qxmlstreamwriter": "cpp",
"qgraphicsdropshadoweffect": "cpp",
"qpushbutton": "cpp",
"qpainter": "cpp",
"qdialog": "cpp",
"quuid": "cpp",
"complex": "cpp",
"expected": "cpp",
"qmessagebox": "cpp"
},
"editor.tokenColorCustomizations": {
"textMateRules": [
{
"scope": "googletest.failed",
"settings": {
"foreground": "#f00"
}
},
{
"scope": "googletest.passed",
"settings": {
"foreground": "#0f0"
}
},
{
"scope": "googletest.run",
"settings": {
"foreground": "#0f0"
}
}
]
}
}

27
CMakeLists.txt Normal file
View File

@@ -0,0 +1,27 @@
cmake_minimum_required(VERSION 3.16)
project(cmakeCreate LANGUAGES CXX)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
if (MSVC)
add_compile_options(/utf-8)
endif()
set(CMAKE_DEBUG_POSTFIX "d")
set(LIBRARY_OUTPUT_PATH ${PROJECT_BINARY_DIR}/lib/${CMAKE_BUILD_TYPE})
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${PROJECT_BINARY_DIR}/bin/${CMAKE_BUILD_TYPE}/)
find_package(wxWidgets CONFIG REQUIRED)
set(SOURCES
src/mainframe.h
src/mainframe.cpp
res/ico.rc
res/manifest.rc
)
include_directories(src)
add_executable(cmakeCreate main.cpp ${SOURCES})
target_link_libraries(cmakeCreate PRIVATE wx::core wx::base wx::stc)
set_target_properties(cmakeCreate PROPERTIES WIN32_EXECUTABLE TRUE)

26
main.cpp Normal file
View File

@@ -0,0 +1,26 @@
#include "mainframe.h"
class CWxNewProject : public wxApp
{
public:
virtual bool OnInit()
{
wxString title = wxString::Format(wxT("创建cmake工程 v1.0.0"));
auto* f = new MainFrame(title);
f->Show(true);
f->SetIcon(wxICON(IDI_ICON1));
#ifdef __WXMSW__
SetProcessDPIAware();
#endif
return true;
}
virtual int OnExit()
{
return wxApp::OnExit();
}
};
IMPLEMENT_APP(CWxNewProject);
DECLARE_APP(CWxNewProject);

BIN
res/ico.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 66 KiB

1
res/ico.rc Normal file
View File

@@ -0,0 +1 @@
IDI_ICON1 ICON DISCARDABLE "ico.ico"

1
res/manifest.rc Normal file
View File

@@ -0,0 +1 @@
1 24 "manifest.xml"

42
res/manifest.xml Normal file
View File

@@ -0,0 +1,42 @@
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
<assemblyIdentity
version="1.0.0.0"
processorArchitecture="*"
name="cmakeCreate"
type="win32"/>
<description>Your Application Description</description>
<!-- 启用 Windows 通用控件 -->
<dependency>
<dependentAssembly>
<assemblyIdentity
type="win32"
name="Microsoft.Windows.Common-Controls"
version="6.0.0.0"
processorArchitecture="*"
publicKeyToken="6595b64144ccf1df"
language="*"/>
</dependentAssembly>
</dependency>
<!-- 启用 DPI 感知 -->
<asmv3:application xmlns:asmv3="urn:schemas-microsoft-com:asm.v3">
<asmv3:windowsSettings>
<dpiAware xmlns="http://schemas.microsoft.com/SMI/2005/WindowsSettings">true</dpiAware>
<dpiAwareness xmlns="http://schemas.microsoft.com/SMI/2016/WindowsSettings">PerMonitorV2</dpiAwareness>
</asmv3:windowsSettings>
</asmv3:application>
<!-- 请求管理员权限(可选) -->
<!--
<trustInfo xmlns="urn:schemas-microsoft-com:asm.v3">
<security>
<requestedPrivileges>
<requestedExecutionLevel level="requireAdministrator" uiAccess="false"/>
</requestedPrivileges>
</security>
</trustInfo>
-->
</assembly>

573
src/mainframe.cpp Normal file
View File

@@ -0,0 +1,573 @@
#include "mainframe.h"
#include <wx/dir.h>
#include <wx/dirdlg.h>
#include <wx/file.h>
#include <wx/fileconf.h>
#include <wx/filename.h>
#include <wx/filesys.h>
#include <wx/msgdlg.h>
#include <wx/stdpaths.h>
#include <wx/utils.h>
MainFrame::MainFrame(const wxString& title) : wxFrame(nullptr, wxID_ANY, title)
{
SetSize(wxSize(1100, 600));
InitControl();
InitCMakeSyntaxHighlighting();
configDir_ = GetConfigDir();
ShowConfig();
ShowExist();
LoadConfig();
}
void MainFrame::InitControl()
{
addID_ = wxNewId();
delID_ = wxNewId();
wxPanel* mainPanel = new wxPanel(this, wxID_ANY);
listBox_ = new wxListBox(mainPanel, wxID_ANY, wxDefaultPosition, wxSize(200, -1));
listBox_->Bind(wxEVT_COMMAND_LISTBOX_SELECTED, &MainFrame::OnListBoxSelected, this);
listBox_->Bind(wxEVT_CONTEXT_MENU, &MainFrame::OnRightClick, this);
textCtrl_ = new wxStyledTextCtrl(mainPanel, wxID_ANY);
btnNewer_ = new wxButton(mainPanel, wxID_ANY, wxT("新建工程"));
btnExit_ = new wxButton(mainPanel, wxID_ANY, wxT("退出"));
btnRefresh_ = new wxButton(mainPanel, wxID_ANY, wxT("刷新列表"));
btnRefresh_->Bind(wxEVT_COMMAND_BUTTON_CLICKED, &MainFrame::ShowConfig, this);
btnSelectPath_ = new wxButton(mainPanel, wxID_ANY, wxT("选择路径"));
//
btnSave_ = new wxButton(mainPanel, wxID_ANY, wxT("保存"), wxDefaultPosition, wxSize(150, -1));
textPath_ = new wxTextCtrl(mainPanel, wxID_ANY);
auto* labelProjectName = new wxStaticText(mainPanel, wxID_ANY, wxT("项目名称:"));
projectName_ = new wxTextCtrl(mainPanel, wxID_ANY);
//
btnExit_->SetMinSize(wxSize(150, -1));
btnNewer_->SetMinSize(wxSize(150, -1));
//
btnOpenPrjDir_ = new wxButton(mainPanel, wxID_ANY, wxT("打开项目目录"));
auto* staticSelectPath = new wxStaticText(mainPanel, wxID_ANY, wxT("工程目录:"));
wxBoxSizer* selectSizer = new wxBoxSizer(wxHORIZONTAL);
selectSizer->Add(staticSelectPath, 0, wxALL | wxCENTER, 2);
selectSizer->Add(textPath_, 1, wxALL | wxEXPAND, 2);
selectSizer->Add(btnSelectPath_, 0, wxALL | wxCENTER, 2);
selectSizer->Add(btnOpenPrjDir_, 0, wxALL | wxCENTER, 2);
//
curFileTitle_ = new wxStaticText(mainPanel, wxID_ANY, wxT("无当前文件"));
auto* centerSizer = new wxBoxSizer(wxVERTICAL);
centerSizer->Add(curFileTitle_, 0, wxALL | wxLEFT, 2);
centerSizer->Add(textCtrl_, 1, wxALL | wxEXPAND, 2);
centerSizer->Add(selectSizer, 0, wxALL | wxEXPAND, 2);
//
btnOpenResDir_ = new wxButton(mainPanel, wxID_ANY, wxT("打开模板目录"));
auto* controlSizer = new wxBoxSizer(wxVERTICAL);
controlSizer->Add(btnRefresh_, 0, wxALL | wxEXPAND, 2);
controlSizer->Add(btnSave_, 0, wxALL | wxEXPAND, 2);
controlSizer->Add(btnOpenResDir_, 0, wxALL | wxEXPAND, 2);
controlSizer->AddStretchSpacer(1);
controlSizer->Add(labelProjectName, 0, wxALL | wxLEFT, 2);
controlSizer->Add(projectName_, 0, wxALL | wxEXPAND, 2);
controlSizer->Add(btnNewer_, 0, wxALL | wxCENTER, 2);
controlSizer->Add(btnExit_, 0, wxALL | wxCENTER, 2);
//
auto* topSizer = new wxBoxSizer(wxHORIZONTAL);
topSizer->Add(listBox_, 0, wxALL | wxEXPAND, 2);
topSizer->Add(centerSizer, 3, wxALL | wxEXPAND, 2);
topSizer->Add(controlSizer, 0, wxALL | wxEXPAND, 2);
SetMinSize(wxSize(800, 500));
mainPanel->SetSizer(topSizer);
btnExit_->Bind(wxEVT_COMMAND_BUTTON_CLICKED, &MainFrame::OnExitClick, this);
btnNewer_->Bind(wxEVT_COMMAND_BUTTON_CLICKED, &MainFrame::OnNewerClick, this);
btnSelectPath_->Bind(wxEVT_COMMAND_BUTTON_CLICKED, &MainFrame::OnSelectPathClick, this);
btnSave_->Bind(wxEVT_COMMAND_BUTTON_CLICKED, &MainFrame::SaveCurrent, this);
btnOpenResDir_->Bind(wxEVT_COMMAND_BUTTON_CLICKED, &MainFrame::OpenResDir, this);
btnOpenPrjDir_->Bind(wxEVT_COMMAND_BUTTON_CLICKED, &MainFrame::OpenPrjDir, this);
Bind(wxEVT_MENU, &MainFrame::DelMenu, this, delID_);
Bind(wxEVT_MENU, &MainFrame::AddMenu, this, addID_);
}
void MainFrame::OnNewerClick(wxCommandEvent& event)
{
wxString targetPath = textPath_->GetValue().Trim();
if (targetPath.IsEmpty()) {
wxMessageBox(wxT("目标路径不能为空"), wxT("错误"), wxOK | wxICON_ERROR, this);
return;
}
if (!wxDirExists(targetPath)) {
wxMessageBox(wxString::Format(wxT("目标路径不存在:\n%s"), targetPath), wxT("错误"), wxOK | wxICON_ERROR, this);
return;
}
wxString projectName = projectName_->GetValue().Trim();
if (projectName.IsEmpty()) {
wxMessageBox(wxT("项目名称不能为空"), wxT("错误"), wxOK | wxICON_ERROR, this);
return;
}
wxString destDir = wxFileName::DirName(targetPath).GetFullPath();
destDir += wxFileName::GetPathSeparator() + projectName;
destDir = Normalize(destDir);
if (wxDirExists(destDir)) {
wxMessageBox(wxString::Format(wxT("目标目录已存在:\n%s"), destDir), wxT("错误"), wxOK | wxICON_ERROR, this);
return;
}
wxString sourceDir = configDir_ + wxFileName::GetPathSeparator() + curFileTitle_->GetLabelText();
sourceDir = Normalize(sourceDir);
if (!wxDirExists(sourceDir)) {
wxMessageBox(wxString::Format(wxT("源目录不存在:\n%s"), sourceDir), wxT("错误"), wxOK | wxICON_ERROR, this);
return;
}
if (!wxFileName::Mkdir(destDir, 0755, wxPATH_MKDIR_FULL)) {
wxMessageBox(wxString::Format(wxT("无法创建目录:\n%s"), destDir), wxT("错误"), wxOK | wxICON_ERROR, this);
return;
}
wxDir dir(sourceDir);
wxString filename;
bool success = true;
wxString errorFile;
if (dir.GetFirst(&filename, wxEmptyString, wxDIR_FILES | wxDIR_DIRS)) {
do {
wxString sourceItem = sourceDir + wxFileName::GetPathSeparator() + filename;
wxString destItem = destDir + wxFileName::GetPathSeparator() + filename;
sourceItem = Normalize(sourceItem);
destItem = Normalize(destItem);
if (wxDirExists(sourceItem)) {
if (!wxFileName::Mkdir(destItem, 0755, wxPATH_MKDIR_FULL)) {
success = false;
errorFile = filename;
break;
}
if (!CopyDirectory(sourceItem, destItem, projectName)) {
success = false;
errorFile = filename;
break;
}
} else {
if (!wxCopyFile(sourceItem, destItem)) {
success = false;
errorFile = filename;
break;
}
if (filename == wxT("CMakeLists.txt")) {
ProcessCMakeListsFile(destItem, projectName);
}
}
} while (success && dir.GetNext(&filename));
}
if (success) {
wxMessageBox(wxString::Format(wxT("成功创建项目:\n%s\n并复制所有文件"), destDir), wxT("完成"), wxOK | wxICON_INFORMATION,
this);
} else {
wxMessageBox(wxString::Format(wxT("复制文件失败:\n%s"), errorFile), wxT("错误"), wxOK | wxICON_ERROR, this);
wxFileName::Rmdir(destDir, wxPATH_RMDIR_RECURSIVE);
}
SaveConfig();
}
void MainFrame::OnExitClick(wxCommandEvent& event)
{
Close(true);
}
void MainFrame::OnSelectPathClick(wxCommandEvent& event)
{
wxDirDialog dirDialog(this, wxT("选择工程创建所在目录"), textPath_->GetValue(), wxDD_DEFAULT_STYLE | wxDD_DIR_MUST_EXIST);
if (dirDialog.ShowModal() == wxID_OK) {
wxString selectedPath = dirDialog.GetPath();
textPath_->SetValue(selectedPath);
}
}
wxString MainFrame::GetConfigDir()
{
wxString exePath = wxStandardPaths::Get().GetExecutablePath();
wxFileName exeFile(exePath);
wxString parentDir = exeFile.GetPath(wxPATH_GET_VOLUME | wxPATH_GET_SEPARATOR);
wxString configDir = parentDir + wxFileName::GetPathSeparator() + wxT("res");
wxFileName configDirFile(configDir);
configDirFile.Normalize(wxPATH_NORM_ALL);
if (!configDirFile.DirExists()) {
if (!wxFileName::Mkdir(configDirFile.GetFullPath(), 0755, wxPATH_MKDIR_FULL)) {
wxLogError(wxT("无法创建配置目录: %s"), configDirFile.GetFullPath());
return wxEmptyString;
}
wxLogMessage(wxT("已创建配置目录: %s"), configDirFile.GetFullPath());
}
return configDirFile.GetFullPath();
}
void MainFrame::ShowConfig()
{
listBox_->Clear();
if (configDir_.empty()) {
wxMessageBox(wxT("配置目录路径为空"));
return;
}
if (!wxDirExists(configDir_)) {
if (!wxFileName::Mkdir(configDir_, 0755, wxPATH_MKDIR_FULL)) {
wxMessageBox(wxString::Format(wxT("无法创建配置目录: %s"), configDir_));
return;
}
wxMessageBox(wxString::Format(wxT("已创建配置目录: %s"), configDir_));
}
wxDir dir(configDir_);
if (!dir.IsOpened()) {
wxMessageBox(wxString::Format(wxT("无法打开配置目录: %s"), configDir_));
return;
}
wxString dirName;
bool cont = dir.GetFirst(&dirName, wxEmptyString, wxDIR_DIRS);
while (cont) {
wxString fullPath = configDir_ + wxFileName::GetPathSeparator() + dirName;
if (wxDirExists(fullPath)) {
listBox_->Append(dirName);
int lastIndex = listBox_->GetCount() - 1;
listBox_->SetClientData(lastIndex, new wxString(fullPath));
}
cont = dir.GetNext(&dirName);
}
}
void MainFrame::ShowConfig(wxCommandEvent& event)
{
ShowConfig();
}
void MainFrame::OnListBoxSelected(wxCommandEvent& event)
{
wxString cmakeContent;
int selection = listBox_->GetSelection();
if (selection == wxNOT_FOUND) {
return;
}
wxString selectedText = listBox_->GetString(selection);
wxString fullPath = configDir_ + wxFileName::GetPathSeparator() + selectedText;
if (!wxDirExists(fullPath)) {
wxMessageBox(wxString::Format(wxT("目录不存在: %s"), fullPath), wxT("错误"), wxOK | wxICON_ERROR, this);
return;
}
curFileTitle_->SetLabel(selectedText);
currentFilePath_ = fullPath + wxFileName::GetPathSeparator() + wxT("CMakeLists.txt");
if (!wxFileExists(currentFilePath_)) {
textCtrl_->SetValue(cmakeContent);
return;
}
wxFile cmakeFile(currentFilePath_);
if (!cmakeFile.IsOpened()) {
wxMessageBox(wxT("无法打开CMakeLists.txt文件"), wxT("错误"), wxOK | wxICON_ERROR, this);
return;
}
cmakeFile.ReadAll(&cmakeContent);
cmakeFile.Close();
textCtrl_->SetValue(cmakeContent);
}
void MainFrame::InitCMakeSyntaxHighlighting()
{
textCtrl_->SetLexer(wxSTC_LEX_CMAKE);
// 基础样式配置
textCtrl_->StyleSetForeground(wxSTC_CMAKE_DEFAULT, *wxBLACK);
textCtrl_->StyleSetForeground(wxSTC_CMAKE_COMMENT, wxColour(0, 128, 0)); // 绿色注释
// 字符串类型
textCtrl_->StyleSetForeground(wxSTC_CMAKE_STRINGDQ, wxColour(163, 21, 21)); // 红色双引号字符串
textCtrl_->StyleSetForeground(wxSTC_CMAKE_STRINGLQ, wxColour(163, 21, 21)); // 红色左单引号
textCtrl_->StyleSetForeground(wxSTC_CMAKE_STRINGRQ, wxColour(163, 21, 21)); // 红色右单引号
// 命令和参数
textCtrl_->StyleSetForeground(wxSTC_CMAKE_COMMANDS, wxColour(0, 0, 255)); // 蓝色命令
textCtrl_->StyleSetBold(wxSTC_CMAKE_COMMANDS, true);
textCtrl_->StyleSetForeground(wxSTC_CMAKE_PARAMETERS, wxColour(255, 105, 0)); // 橙色参数
// 变量和数字
textCtrl_->StyleSetForeground(wxSTC_CMAKE_VARIABLE, wxColour(128, 0, 128)); // 紫色变量
textCtrl_->StyleSetForeground(wxSTC_CMAKE_STRINGVAR, wxColour(128, 0, 128)); // 紫色字符串变量
textCtrl_->StyleSetForeground(wxSTC_CMAKE_NUMBER, wxColour(0, 100, 0)); // 深绿色数字
// 控制结构
textCtrl_->StyleSetForeground(wxSTC_CMAKE_WHILEDEF, wxColour(0, 0, 139)); // 深蓝色while
textCtrl_->StyleSetForeground(wxSTC_CMAKE_FOREACHDEF, wxColour(0, 0, 139)); // 深蓝色foreach
textCtrl_->StyleSetForeground(wxSTC_CMAKE_IFDEFINEDEF, wxColour(0, 0, 139)); // 深蓝色if
textCtrl_->StyleSetForeground(wxSTC_CMAKE_MACRODEF, wxColour(139, 0, 139)); // 深紫色宏
const char* cmakeCommands = "add_executable add_library target_link_libraries "
"find_package if else endif foreach endfunction project cmake_minimum_required"
"while endwhile macro endmacro function set add_compile_options";
textCtrl_->SetKeyWords(0, cmakeCommands);
textCtrl_->StyleSetBackground(wxSTC_CMAKE_DEFAULT, wxColour(255, 255, 255));
}
void MainFrame::SaveCurrent(wxCommandEvent& event)
{
if (currentFilePath_.empty()) {
wxMessageBox(wxT("当前无配置选择"), wxT("提示"), wxOK | wxICON_ERROR, this);
return;
}
wxFile cmakeFile(currentFilePath_, wxFile::write);
if (!cmakeFile.IsOpened()) {
wxMessageBox(wxT("无法打开CMakeLists.txt文件"), wxT("错误"), wxOK | wxICON_ERROR, this);
return;
}
wxString content = textCtrl_->GetValue();
if (!cmakeFile.Write(content)) {
wxMessageBox(wxString::Format(wxT("写入文件失败: %s"), currentFilePath_), wxT("错误"), wxOK | wxICON_ERROR, this);
cmakeFile.Close();
return;
}
cmakeFile.Close();
wxMessageBox(wxT("已保存"));
}
void MainFrame::OnRightClick(wxCommandEvent& event)
{
wxMenu menu;
bool hasSelection = (listBox_->GetSelection() != wxNOT_FOUND);
menu.Append(addID_, wxT("添加"));
menu.AppendSeparator();
menu.Append(delID_, wxT("删除"))->Enable(hasSelection);
listBox_->PopupMenu(&menu);
}
void MainFrame::AddMenu(wxCommandEvent& event)
{
wxTextEntryDialog dialog(this, wxT("请输入新条目名称:"), wxT("添加新条目"), wxEmptyString, wxOK | wxCANCEL | wxCENTRE);
if (dialog.ShowModal() != wxID_OK) {
return;
}
wxString newItem = dialog.GetValue().Trim();
if (newItem.IsEmpty()) {
wxMessageBox(wxT("条目名称不能为空"), wxT("错误"), wxOK | wxICON_ERROR, this);
return;
}
wxString newDir = configDir_ + wxFileName::GetPathSeparator() + newItem;
if (!wxFileName::Mkdir(newDir, 0755, wxPATH_MKDIR_FULL)) {
wxMessageBox(wxT("无法创建目录: ") + newDir, wxT("错误"), wxOK | wxICON_ERROR, this);
return;
}
listBox_->Append(newItem);
listBox_->SetSelection(listBox_->GetCount() - 1);
curFileTitle_->SetLabel(newItem);
currentFilePath_ = newDir + wxFileName::GetPathSeparator() + wxT("CMakeLists.txt");
textCtrl_->SetValue(wxEmptyString);
}
void MainFrame::DelMenu(wxCommandEvent& event)
{
int selection = listBox_->GetSelection();
if (selection == wxNOT_FOUND) {
return;
}
wxString selectedItem = listBox_->GetString(selection);
wxString targetDir = Normalize(configDir_ + wxFileName::GetPathSeparator() + selectedItem);
wxString msg = wxString::Format(wxT("确定要删除目录:\n%s\n及其所有内容吗?"), targetDir);
wxMessageDialog dlg(this, msg, wxT("确认删除"), wxYES_NO | wxNO_DEFAULT | wxICON_WARNING);
if (dlg.ShowModal() != wxID_YES) {
return;
}
if (wxDirExists(targetDir)) {
wxFileName::Rmdir(targetDir, wxPATH_RMDIR_RECURSIVE);
listBox_->Delete(selection);
ShowExist();
} else {
wxMessageBox(wxString::Format(wxT("目录 %s 不存在"), targetDir), wxT("错误"), wxOK | wxICON_ERROR, this);
}
}
void MainFrame::ShowExist()
{
if (!listBox_ || listBox_->IsEmpty()) {
return;
}
wxString firstItem = listBox_->GetString(0);
listBox_->SetSelection(0);
wxString selectedText = firstItem;
wxString fullPath = Normalize(configDir_ + wxFileName::GetPathSeparator() + selectedText);
if (!wxDirExists(fullPath)) {
wxMessageBox(wxString::Format(wxT("目录不存在: %s"), fullPath), wxT("错误"), wxOK | wxICON_ERROR, this);
return;
}
wxString cmakeContent;
curFileTitle_->SetLabel(selectedText);
currentFilePath_ = Normalize(fullPath + wxFileName::GetPathSeparator() + wxT("CMakeLists.txt"));
if (!wxFileExists(currentFilePath_)) {
textCtrl_->SetValue(cmakeContent);
return;
}
wxFile cmakeFile(currentFilePath_);
if (!cmakeFile.IsOpened()) {
wxMessageBox(wxT("无法打开CMakeLists.txt文件"), wxT("错误"), wxOK | wxICON_ERROR, this);
return;
}
cmakeFile.ReadAll(&cmakeContent);
cmakeFile.Close();
textCtrl_->SetValue(cmakeContent);
}
void MainFrame::OpenDir(const wxString& path)
{
if (!wxDirExists(path)) {
wxMessageBox(wxString::Format(wxT("目录不存在:\n%s"), path), wxT("错误"), wxOK | wxICON_ERROR, this);
return;
}
bool success = wxLaunchDefaultApplication(path);
if (!success) {
#ifdef __WXMSW__
wxString cmd = wxT("explorer \"") + path + wxT("\"");
#elif defined(__WXMAC__)
wxString cmd = wxT("open \"") + path + wxT("\"");
#else // Linux/Unix
wxString cmd = wxT("xdg-open \"") + path + wxT("\"");
#endif
success = wxExecute(cmd) != 0;
}
if (!success) {
wxMessageBox(wxString::Format(wxT("无法打开目录:\n%s"), path), wxT("错误"), wxOK | wxICON_ERROR, this);
}
}
void MainFrame::OpenResDir(wxCommandEvent& event)
{
OpenDir(configDir_);
}
void MainFrame::OpenPrjDir(wxCommandEvent& event)
{
OpenDir(textPath_->GetValue());
}
wxString MainFrame::Normalize(const wxString& path)
{
wxFileName configDirFile(path);
configDirFile.Normalize(wxPATH_NORM_ALL);
return configDirFile.GetFullPath();
}
void MainFrame::SaveConfig()
{
if (!wxFileName::DirExists(configDir_)) {
if (!wxFileName::Mkdir(configDir_, 0755, wxPATH_MKDIR_FULL)) {
wxLogError(wxT("无法创建配置目录: %s"), configDir_);
return;
}
}
wxString configFile = configDir_ + wxFileName::GetPathSeparator() + wxT("newproject.ini");
wxFileConfig config(wxEmptyString, wxEmptyString, configFile, wxEmptyString, wxCONFIG_USE_LOCAL_FILE);
config.Write(wxT("/Paths/TextPath"), textPath_->GetValue());
config.Write(wxT("/Paths/ProjectName"), projectName_->GetValue());
config.Flush();
}
void MainFrame::LoadConfig()
{
wxString configFile = configDir_ + wxFileName::GetPathSeparator() + wxT("newproject.ini");
if (!wxFileName::FileExists(configFile)) {
return;
}
wxFileConfig config(wxEmptyString, wxEmptyString, configFile, wxEmptyString, wxCONFIG_USE_LOCAL_FILE);
wxString textPath, projectName;
if (config.Read(wxT("/Paths/TextPath"), &textPath)) {
textPath_->SetValue(textPath);
}
if (config.Read(wxT("/Paths/ProjectName"), &projectName)) {
projectName_->SetValue(projectName);
}
}
bool MainFrame::CopyDirectory(const wxString& source, const wxString& dest, const wxString& projectName)
{
wxDir dir(source);
wxString filename;
bool success = true;
if (dir.GetFirst(&filename, wxEmptyString, wxDIR_FILES | wxDIR_DIRS)) {
do {
wxString sourceItem = source + wxFileName::GetPathSeparator() + filename;
wxString destItem = dest + wxFileName::GetPathSeparator() + filename;
sourceItem = Normalize(sourceItem);
destItem = Normalize(destItem);
if (wxDirExists(sourceItem)) {
if (!wxFileName::Mkdir(destItem, 0755, wxPATH_MKDIR_FULL)) {
success = false;
break;
}
if (!CopyDirectory(sourceItem, destItem, projectName)) {
success = false;
break;
}
} else {
if (!wxCopyFile(sourceItem, destItem)) {
success = false;
break;
}
if (filename == wxT("CMakeLists.txt")) {
ProcessCMakeListsFile(destItem, projectName);
}
}
} while (success && dir.GetNext(&filename));
}
return success;
}
void MainFrame::ProcessCMakeListsFile(const wxString& filePath, const wxString& projectName)
{
wxFile file(filePath, wxFile::read);
if (file.IsOpened()) {
wxString content;
file.ReadAll(&content);
file.Close();
content.Replace(wxT("PJNAME"), projectName);
wxFile dest(filePath, wxFile::write);
if (dest.IsOpened()) {
dest.Write(content);
dest.Close();
} else {
wxMessageBox(wxString::Format(wxT("无法打开文件进行修改: %s"), filePath));
}
} else {
wxMessageBox(wxString::Format(wxT("无法读取源文件: %s"), filePath));
}
}

62
src/mainframe.h Normal file
View File

@@ -0,0 +1,62 @@
#ifndef MAINFRAME_H
#define MAINFRAME_H
#include <wx/button.h>
#include <wx/listbox.h>
#include <wx/stc/stc.h>
#include <wx/textctrl.h>
#include <wx/wx.h>
class MainFrame : public wxFrame
{
public:
explicit MainFrame(const wxString& title);
private:
void InitControl();
private:
void OnNewerClick(wxCommandEvent& event);
void OnExitClick(wxCommandEvent& event);
void OnSelectPathClick(wxCommandEvent& event);
wxString GetConfigDir();
void ShowConfig(wxCommandEvent& event);
void ShowConfig();
void OnListBoxSelected(wxCommandEvent& event);
void InitCMakeSyntaxHighlighting();
void SaveCurrent(wxCommandEvent& event);
void OnRightClick(wxCommandEvent& event);
void AddMenu(wxCommandEvent& event);
void DelMenu(wxCommandEvent& event);
void ShowExist();
void OpenResDir(wxCommandEvent& event);
void OpenPrjDir(wxCommandEvent& event);
wxString Normalize(const wxString& path);
void SaveConfig();
void LoadConfig();
bool CopyDirectory(const wxString& source, const wxString& dest, const wxString& projectName);
void ProcessCMakeListsFile(const wxString& filePath, const wxString& projectName);
void OpenDir(const wxString& path);
private:
wxListBox* listBox_;
wxStyledTextCtrl* textCtrl_;
wxButton* btnNewer_;
wxButton* btnExit_;
wxButton* btnSelectPath_;
wxTextCtrl* textPath_;
wxString configDir_;
wxTextCtrl* projectName_;
wxButton* btnRefresh_;
wxButton* btnSave_;
wxString currentFilePath_;
wxStaticText* curFileTitle_;
wxButton* btnOpenResDir_;
wxButton* btnOpenPrjDir_;
private:
wxWindowID addID_;
wxWindowID delID_;
};
#endif // MAINFRAME_H