// table to hold all settings for this wizard PluginSettings <- { Type = 0 // cbToolPlugin Name = _T("") Title = _T("") Version = _T("") Description = _T("") Author = _T("") Email = _T("") Website = _T("") ThanksTo = _T("") HasConfig = false HasMenu = false HasModuleMenu = false HasToolbar = false } WxVersion <- 0; //0 - wx 2.8, 1 - wx 3.0, 2 - wx 3.1 // ----------------------------------------------------------------------------- // init wizard function BeginWizard() { local wiz_type = Wizard.GetWizardType(); local intro_msg = _T("Welcome to the new Code::Blocks plugin wizard!\n" + "This wizard will guide you to create a new Code::Blocks plugin.\n\n"); if (PLATFORM == PLATFORM_MSW) { intro_msg += _T("\nVERY IMPORTANT NOTE:\n\n" + "Code::Blocks is built with the GNU GCC compiler and links to\n" + "the monolithic unicode wxWidgets DLL.\n" + "This means that you must have exactly this setup to be able to\n" + "build the generated plugin.\n" + "You must also have defined two global variables:\n" + " 1. $(#cb) pointing to Code::Blocks base dir (where CodeBlocks.cbp is)\n" + " 2. $(#wx) pointing to wxWidgets base directory\n\n\n"); } intro_msg += _T("When you 're ready to proceed, please click \"Next\"..."); Wizard.AddInfoPage(_T("PluginIntro"), intro_msg); Wizard.AddProjectPathPage(); Wizard.AddPage(_T("PluginOptions")); Wizard.AddPage(_T("PluginInfo")); local options = _T("wxWidgets 2.8.x;wxWidgets 3.0.x;wxWidgets 3.1.x"); if (PLATFORM != PLATFORM_MSW) options += _T(";system default"); // Select wxwidgets version. local wxVersionMsg = _T("Please select the wxWidgets version you want to use for the default configuration."); Wizard.AddGenericSingleChoiceListPage(_T("wxVersionPage"), wxVersionMsg, options, WxVersion); Wizard.AddCompilerPage(_T(""), _T("gcc*"), true, false); } // ----------------------------------------------------------------------------- // entering plugin options page function OnEnter_PluginOptions(fwd) { // update options state OnClick_cmbPluginType(); } // ----------------------------------------------------------------------------- // enable/disable available options based on selected plugin type function OnClick_cmbPluginType() { PluginSettings.Type = Wizard.GetComboboxSelection(_T("cmbPluginType")); local isTool = PluginSettings.Type == 1; local isMime = PluginSettings.Type == 2; local isWizard = PluginSettings.Type == 3; Wizard.EnableWindow(_T("chkHasConfig"), !isWizard); Wizard.EnableWindow(_T("chkHasMenu"), !isTool && !isMime && !isWizard); Wizard.EnableWindow(_T("chkHasModuleMenu"), !isTool && !isMime && !isWizard); Wizard.EnableWindow(_T("chkHasToolbar"), !isTool && !isMime && !isWizard); } // ----------------------------------------------------------------------------- // leaving plugin options page, validate entered values function OnLeave_PluginOptions(fwd) { if (fwd) { // read text values entered PluginSettings.Name = Wizard.GetTextControlValue(_T("txtPluginName")); PluginSettings.Type = Wizard.GetComboboxSelection(_T("cmbPluginType")); PluginSettings.HasConfig = Wizard.IsCheckboxChecked(_T("chkHasConfig")); PluginSettings.HasMenu = Wizard.IsCheckboxChecked(_T("chkHasMenu")); PluginSettings.HasModuleMenu = Wizard.IsCheckboxChecked(_T("chkHasModuleMenu")); PluginSettings.HasToolbar = Wizard.IsCheckboxChecked(_T("chkHasToolbar")); // check that essentials were filled in if (PluginSettings.Name.IsEmpty()) { ShowWarning(_T("You have to enter the plugin's name before you can proceed...")); return false; } } return true; } // ----------------------------------------------------------------------------- // entering plugin info page, set some default values function OnEnter_PluginInfo(fwd) { if (fwd) { // set the title same as the project title if (Wizard.GetTextControlValue(_T("txtTitle")).IsEmpty()) Wizard.SetTextControlValue(_T("txtTitle"), Wizard.GetProjectTitle()); if (Wizard.GetTextControlValue(_T("txtVersion")).IsEmpty()) Wizard.SetTextControlValue(_T("txtVersion"), _T("0.1")); // load config Wizard.SetTextControlValue(_T("txtAuthor"), GetConfigManager().Read(_T("/cb_plugin_wizard/author"), _T(""))); Wizard.SetTextControlValue(_T("txtEmail"), GetConfigManager().Read(_T("/cb_plugin_wizard/email"), _T(""))); Wizard.SetTextControlValue(_T("txtWebsite"), GetConfigManager().Read(_T("/cb_plugin_wizard/website"), _T(""))); } } // ----------------------------------------------------------------------------- // leaving plugin info page, validate entered values function OnLeave_PluginInfo(fwd) { if (fwd) { // read text values entered PluginSettings.Title = Wizard.GetTextControlValue(_T("txtTitle")); PluginSettings.Version = Wizard.GetTextControlValue(_T("txtVersion")); PluginSettings.Description = Wizard.GetTextControlValue(_T("txtDescription")); PluginSettings.Author = Wizard.GetTextControlValue(_T("txtAuthor")); PluginSettings.Email = Wizard.GetTextControlValue(_T("txtEmail")); PluginSettings.Website = Wizard.GetTextControlValue(_T("txtWebsite")); PluginSettings.ThanksTo = Wizard.GetTextControlValue(_T("txtThanksTo")); // check that essentials were filled in if (PluginSettings.Name.IsEmpty() || PluginSettings.Version.IsEmpty()) { ShowWarning(_T("You have to fill the Title and Version fields before you can proceed...")); return false; } PluginSettings.Name = GetFixedProjectName(PluginSettings.Name); } // save config GetConfigManager().Write(_T("/cb_plugin_wizard/author"), PluginSettings.Author); GetConfigManager().Write(_T("/cb_plugin_wizard/email"), PluginSettings.Email); GetConfigManager().Write(_T("/cb_plugin_wizard/website"), PluginSettings.Website); return true; } //////////////////////////////////////////////////////////////////////////////// // wxWidgets' version page //////////////////////////////////////////////////////////////////////////////// function OnEnter_wxVersionPage(fwd) { if (fwd) { WxVersion = Wizard.GetListboxSelection(_T("GenericChoiceList")); } return true; } function OnLeave_wxVersionPage(fwd) { if (fwd) { WxVersion = Wizard.GetListboxSelection(_T("GenericChoiceList")); } return true; } // ----------------------------------------------------------------------------- // each time, return a string of the form "filename.ext;contents" // you can change the return string based on // return an empty string to denote that no more files are to be generated function GetGeneratedFile(file_index) { switch (file_index) { // header file case 0: return PluginSettings.Name + DOT_EXT_H + _T(";") + GenerateHeader(); // source file case 1: return PluginSettings.Name + DOT_EXT_CPP + _T(";") + GenerateSource(); // manifest case 2: return _T("manifest") + DOT_EXT_XML + _T(";") + GenerateManifest(); } return _T(""); // no more generated files } // Return the path to the devel folder based on the wx version we are targeting function GetBaseDevelPath(version) { if (PLATFORM == PLATFORM_MSW) { if (version == 0) return _T("$(#cb)\\devel"); else if (version == 1 || version == 2) return _T("$(#cb)\\devel30"); } else { if (version == 0) return _T("$(#cb)/devel"); else if (version == 1 || version == 2 || version == 3) return _T("$(#cb)/devel30"); }; } // ----------------------------------------------------------------------------- // Setup the project options. // We create three targets: // * make_cbplugin: // This target creates a .cbplugin archive that can be distributed and installed in codeblocks via the plugin // manager. Uses the selected wx version. // * to_codeblocks_wx28 and to_codeblocks_wx30: // These targets copy the binary output and the resources directly to the "devel" and "devel30" sub folder of your // codeblocks development folder provided by the $(#cb) global variable. This allows to debug the plugin easily. // If the debugging process is started, codeblocks starts gdb with "$(#cb)/devel/codeblocks" as host application // with the "debug" personality to create some kind of isolation from the working environment. function SetupProject(project) { SetupProjectBuildOptions(project); // Create the "default" target local target = project.GetBuildTarget(_T("default")); if (IsNull(target)) target = project.AddBuildTarget(_T("default")); SetupTarget(target, true, WxVersion); // Create plugin distribution file. target.AddCommandsAfterBuild(_T("zip -j9 ") + PluginSettings.Name + _T(".cbplugin ") + target.GetOutputFilename() + _T(" ") + PluginSettings.Name + _T(".zip")); // Create the "to_codeblocks_wx28" target local target28 = project.GetBuildTarget(_T("to_codeblocks_wx28")); if (IsNull(target28)) target28 = project.AddBuildTarget(_T("to_codeblocks_wx28")); SetupTarget(target28, false, 0); // Create the "to_codeblocks_wx30" target local target30 = project.GetBuildTarget(_T("to_codeblocks_wx30")); if (IsNull(target30)) target30 = project.AddBuildTarget(_T("to_codeblocks_wx30")); SetupTarget(target30, false, 1); // Add files to the wx28 and wx30 targets, they are not added for some reason. for (local i = 0; i < project.GetFilesCount(); i++) project.GetFile(i).AddBuildTarget(target28.GetTitle()); for (local i = 0; i < project.GetFilesCount(); i++) project.GetFile(i).AddBuildTarget(target30.GetTitle()); // Merge all targets in a single virtual target, so the user can rebuild everything at once. local virtualTargets = wxArrayString(); virtualTargets.Add(target.GetTitle(), 1); virtualTargets.Add(target28.GetTitle(), 1); virtualTargets.Add(target30.GetTitle(), 1); project.DefineVirtualBuildTarget(_T("All"), virtualTargets); return true; } function SetupProjectBuildOptions(project) { if (PLATFORM == PLATFORM_MSW) { project.AddCompilerOption(_T("-DBUILDING_PLUGIN")); project.AddCompilerOption(_T("-DHAVE_W32API_H")); project.AddCompilerOption(_T("-D__WXMSW__")); project.AddCompilerOption(_T("-DWXUSINGDLL")); project.AddCompilerOption(_T("-DcbDEBUG")); project.AddCompilerOption(_T("-DCB_PRECOMP")); project.AddCompilerOption(_T("-DWX_PRECOMP")); project.AddCompilerOption(_T("-DwxUSE_UNICODE")); project.AddCompilerOption(_T("-pipe")); project.AddCompilerOption(_T("-mthreads")); project.AddCompilerOption(_T("-fmessage-length=0")); project.AddCompilerOption(_T("-fexceptions")); project.AddCompilerOption(_T("-Winvalid-pch")); project.AddCompilerOption(_T("-std=gnu++11")); project.AddLinkerOption(_T("-mthreads")); project.AddIncludeDir(_T("$(#cb)\\include")); project.AddIncludeDir(_T("$(#cb)\\sdk\\wxscintilla\\include")); project.AddIncludeDir(_T("$(#cb)\\include\\tinyxml")); } else { project.AddCompilerOption(_T("-std=c++11")); project.AddCompilerOption(_T("-fPIC")); project.AddLinkerOption(_T("-Wl,--no-undefined")); } } // Setup all target common parameters for the targets function SetupTarget(target, isSystemWide, targetWxVersion) { if (IsNull(target)) return false; target.SetTargetType(ttDynamicLib); target.SetOutputFilename(PluginSettings.Name); target.SetCreateDefFile(false); target.SetCreateStaticLib(false); target.SetObjectOutput(_T(".objs/") + target.GetTitle()); if (PLATFORM == PLATFORM_MSW) { target.SetHostApplication(GetBaseDevelPath(targetWxVersion) + _T("\\codeblocks") + DOT_EXT_EXECUTABLE); if (targetWxVersion == 0) { target.AddIncludeDir(_T("$(#wx.include)")); target.AddIncludeDir(_T("$(#wx.lib)\\gcc_dll\\mswu")); target.AddLinkLib(_T("wxmsw28u")); target.AddLibDir(_T("$(#wx.lib)\\gcc_dll")); } else if (targetWxVersion == 1) { target.AddIncludeDir(_T("$(#wx30.include)")); target.AddIncludeDir(_T("$(#wx30.lib)\\gcc_dll\\mswu")); target.AddLinkLib(_T("wxmsw30u")); target.AddLibDir(_T("$(#wx30.lib)\\gcc_dll")); } else if (targetWxVersion == 2) { target.AddIncludeDir(_T("$(#wx31.include)")); target.AddIncludeDir(_T("$(#wx31.lib)\\gcc_dll\\mswu")); target.AddLinkLib(_T("wxmsw31u")); target.AddLibDir(_T("$(#wx31.lib)\\gcc_dll")); } target.AddLibDir(GetBaseDevelPath(targetWxVersion)); target.AddLinkLib(_T("codeblocks")); } else { if (isSystemWide) { target.AddCompilerOption(_T("`pkg-config --cflags codeblocks`")); target.AddLinkerOption(_T("`pkg-config --libs codeblocks`")); } else { local develPath = GetBaseDevelPath(targetWxVersion); target.SetHostApplication(develPath + _T("/codeblocks") + DOT_EXT_EXECUTABLE); target.AddLibDir(develPath); target.SetWorkingDir(develPath); target.AddLinkLib(_T("codeblocks")); target.AddIncludeDir(_T("$(#cb)/include")); target.AddIncludeDir(_T("$(#cb)/sdk/wxscintilla/include")); target.AddIncludeDir(_T("$(#cb)/include/tinyxml")); } local WxVersionFlag; if (targetWxVersion == 0) WxVersionFlag = _T(" --version=2.8"); else if (targetWxVersion == 1) WxVersionFlag = _T(" --version=3.0"); else if (targetWxVersion == 2) WxVersionFlag = _T(" --version=3.1"); else if (targetWxVersion == 3) WxVersionFlag = _T(""); target.AddCompilerOption(_T("`wx-config --cflags ") + WxVersionFlag + _T("`")); target.AddLinkerOption(_T("`wx-config --libs ") + WxVersionFlag + _T("`")); } local zipFilePath; if (isSystemWide) zipFilePath = PluginSettings.Name + _T(".zip"); else { // "to_codeblocks" has to copy multiple files to the $(#cb)\devel folder. This is a platform specific process local basePath = GetBaseDevelPath(targetWxVersion) + _T("/share/codeblocks/"); zipFilePath = basePath + PluginSettings.Name + _T(".zip"); target.SetOutputFilename(basePath + _T("plugins/") + PluginSettings.Name); local executionParameters = _T("--debug-log --multiple-instance --no-splash-screen --verbose -p debug"); if (PLATFORM == PLATFORM_MSW) executionParameters += _T(" --no-dde --no-check-associations "); else executionParameters += _T(" --no-ipc "); target.SetExecutionParameters(executionParameters); } target.AddCommandsAfterBuild(_T("zip -j9 ") + zipFilePath + _T(" manifest") + DOT_EXT_XML); target.SetAlwaysRunPostBuildSteps (true) DebugSymbolsOn(target, Wizard.GetCompilerID()); return true; } //////////////////////////////////////////////////////////////////////////////// // // locally defined functions below // //////////////////////////////////////////////////////////////////////////////// // ----------------------------------------------------------------------------- // return the header contents string function GenerateHeader() { local path = Wizard.FindTemplateFile(GetTemplateFile(DOT_EXT_H)); local buffer = IO.ReadFileContents(path); // create header guard word local guard = PluginSettings.Name + DOT_EXT_H + _T("_INCLUDED"); guard.MakeUpper(); guard.Replace(_T(" "), _T("_")); guard.Replace(_T("."), _T("_")); buffer.Replace(_T("[GUARD_WORD]"), guard); return SubstituteMacros(buffer); } // ----------------------------------------------------------------------------- // return the implementation contents string function GenerateSource() { local path = Wizard.FindTemplateFile(GetTemplateFile(DOT_EXT_CPP)); local buffer = IO.ReadFileContents(path); return SubstituteMacros(buffer); } // ----------------------------------------------------------------------------- // return the manifest contents string function GenerateManifest() { local path = Wizard.FindTemplateFile(_T("plugins/templates/manifest_template.xml")); local buffer = IO.ReadFileContents(path); return SubstituteMacros(buffer); } // ----------------------------------------------------------------------------- // return the template's filename, appending as an extension (must include the dot) function GetTemplateFile(dot_ext) { local template_file = _T(""); switch (PluginSettings.Type) { // generic plugin case 0: template_file = _T("plugins/templates/generic_template") + dot_ext; break; // tool plugin case 1: template_file = _T("plugins/templates/tool_template") + dot_ext; break; // mime plugin case 2: template_file = _T("plugins/templates/mime_template") + dot_ext; break; // wizard plugin case 3: template_file = _T("plugins/templates/wizard_template") + dot_ext; break; default: break; // error } return template_file; } // ----------------------------------------------------------------------------- // substitute all plugin macros in function SubstituteMacros(buffer) { // handle [IF] / [ENDIF] pairs buffer = HandleDirective(buffer, _T("HAS_CONFIGURE"), PluginSettings.HasConfig); buffer = HandleDirective(buffer, _T("HAS_MENU"), PluginSettings.HasMenu); buffer = HandleDirective(buffer, _T("HAS_MODULE_MENU"), PluginSettings.HasModuleMenu); buffer = HandleDirective(buffer, _T("HAS_TOOLBAR"), PluginSettings.HasToolbar); buffer = HandleDirective(buffer, _T("NEED_EVENTS"), PluginSettings.HasMenu || PluginSettings.HasModuleMenu || PluginSettings.HasToolbar); // macros substitution buffer.Replace(_T("[PLUGIN_SDK_VERSION_MAJOR]"), _T("") + PLUGIN_SDK_VERSION_MAJOR); buffer.Replace(_T("[PLUGIN_SDK_VERSION_MINOR]"), _T("") + PLUGIN_SDK_VERSION_MINOR); buffer.Replace(_T("[PLUGIN_SDK_VERSION_RELEASE]"), _T("") + PLUGIN_SDK_VERSION_RELEASE); buffer.Replace(_T("[PLUGIN_NAME]"), PluginSettings.Name); buffer.Replace(_T("[PLUGIN_TITLE]"), PluginSettings.Title); buffer.Replace(_T("[PLUGIN_VERSION]"), PluginSettings.Version); buffer.Replace(_T("[PLUGIN_DESCRIPTION]"), PluginSettings.Description); buffer.Replace(_T("[PROJECT_NAME]"), Wizard.GetProjectName()); buffer.Replace(_T("[AUTHOR_NAME]"), PluginSettings.Author); buffer.Replace(_T("[AUTHOR_EMAIL]"), PluginSettings.Email); buffer.Replace(_T("[AUTHOR_WWW]"), PluginSettings.Website); buffer.Replace(_T("[THANKS_TO]"), PluginSettings.ThanksTo); buffer.Replace(_T("[HEADER_FILENAME]"), PluginSettings.Name + DOT_EXT_H); buffer.Replace(_T("[NOW]"), ReplaceMacros(_T("$(TODAY)"), false)); return buffer; } // ----------------------------------------------------------------------------- // if is true, removes the [IF ] and [ENDIF ] // macros. // if is false, removes everything enclosed by the [IF ] // and [ENDIF ] macros (including them). function HandleDirective(buffer, directive, enabled) { local dir_if = _T("[IF ") + directive + _T("]"); local dir_endif = _T("[ENDIF ") + directive + _T("]"); local findStart = buffer.Find(dir_if); if (findStart == -1) return buffer; local findEnd = buffer.Find(dir_endif); if (findEnd == -1 || findEnd <= findStart) return buffer; // look for [ELSE] local block = buffer.Mid(findStart, findEnd - findStart); local findElse = block.Find(_T("[ELSE]")); // findElse is in "local scope", i.e. offset from findStart if (!enabled) { if (findElse == -1) { // remove whole section buffer.Remove(findStart, (findEnd - findStart) + dir_endif.Length()); } else { // remove [ENDIF] buffer.Remove(findEnd, dir_endif.Length()); // remove from [IF] to [ELSE] (including) buffer.Remove(findStart, findElse + 6); // 6 is the [ELSE] size } } else { if (findElse == -1) { // just remove the directives // we must remove the [ENDIF] first because if we removed the [IF] it would // render the findEnd index invalid! buffer.Remove(findEnd, dir_endif.Length()); buffer.Remove(findStart, dir_if.Length()); } else { // remove from [ELSE] to [ENDIF] local start = findStart + findElse; buffer.Remove(start, (findEnd - start) + dir_endif.Length()); // remove from [IF] buffer.Remove(findStart, dir_if.Length()); } } return buffer; }