diff --git a/zbstudio/packages/Singe.fbp b/zbstudio/packages/Singe.fbp
new file mode 100644
index 000000000..3727dbc10
--- /dev/null
+++ b/zbstudio/packages/Singe.fbp
@@ -0,0 +1,656 @@
+
+
+
+
+
diff --git a/zbstudio/packages/singetoolbar.lua b/zbstudio/packages/singetoolbar.lua
new file mode 100644
index 000000000..87735a62d
--- /dev/null
+++ b/zbstudio/packages/singetoolbar.lua
@@ -0,0 +1,227 @@
+--[[
+ *
+ * Singe 2
+ * Copyright (C) 2006-2024 Scott Duensing
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ *
+--]]
+
+
+local id = ID("singetoolbar.singemenu")
+local tool
+local settings
+
+
+local function configureSinge(self)
+
+ UI = {}
+
+ UI.dlgSinge = wx.wxDialog (wx.NULL, wx.wxID_ANY, "Singe Configuration", wx.wxDefaultPosition, wx.wxDefaultSize, wx.wxDEFAULT_DIALOG_STYLE )
+ UI.dlgSinge:SetSizeHints( wx.wxSize( 500,-1 ), wx.wxDefaultSize )
+
+ UI.fgSizer1 = wx.wxFlexGridSizer( 0, 2, 0, 0 )
+ UI.fgSizer1:AddGrowableCol( 1 )
+ UI.fgSizer1:SetFlexibleDirection( wx.wxBOTH )
+ UI.fgSizer1:SetNonFlexibleGrowMode( wx.wxFLEX_GROWMODE_SPECIFIED )
+
+ UI.lblSinge = wx.wxStaticText( UI.dlgSinge, wx.wxID_ANY, "Singe:", wx.wxDefaultPosition, wx.wxDefaultSize, wx.wxALIGN_RIGHT )
+ UI.lblSinge:Wrap( -1 )
+
+ UI.fgSizer1:Add( UI.lblSinge, 0, wx.wxALIGN_CENTER_VERTICAL + wx.wxALIGN_RIGHT + wx.wxALL + wx.wxEXPAND, 5 )
+
+ UI.filePickSinge = wx.wxFilePickerCtrl( UI.dlgSinge, wx.wxID_ANY, "", "Select Singe Binary", "*.*", wx.wxDefaultPosition, wx.wxDefaultSize, wx.wxFLP_DEFAULT_STYLE + wx.wxFLP_FILE_MUST_EXIST + wx.wxFLP_OPEN + wx.wxFLP_USE_TEXTCTRL )
+ UI.fgSizer1:Add( UI.filePickSinge, 0, wx.wxALL + wx.wxEXPAND, 5 )
+
+ UI.lblScript = wx.wxStaticText( UI.dlgSinge, wx.wxID_ANY, "Script:", wx.wxDefaultPosition, wx.wxDefaultSize, 0 )
+ UI.lblScript:Wrap( -1 )
+
+ UI.fgSizer1:Add( UI.lblScript, 0, wx.wxALIGN_CENTER_VERTICAL + wx.wxALIGN_RIGHT + wx.wxALL + wx.wxEXPAND, 5 )
+
+ UI.filePickScript = wx.wxFilePickerCtrl( UI.dlgSinge, wx.wxID_ANY, "", "Select a file", "*.*", wx.wxDefaultPosition, wx.wxDefaultSize, wx.wxFLP_DEFAULT_STYLE + wx.wxFLP_FILE_MUST_EXIST + wx.wxFLP_OPEN + wx.wxFLP_USE_TEXTCTRL )
+ UI.fgSizer1:Add( UI.filePickScript, 0, wx.wxALL + wx.wxEXPAND, 5 )
+
+ UI.lblVideo = wx.wxStaticText( UI.dlgSinge, wx.wxID_ANY, "Video:", wx.wxDefaultPosition, wx.wxDefaultSize, 0 )
+ UI.lblVideo:Wrap( -1 )
+
+ UI.fgSizer1:Add( UI.lblVideo, 0, wx.wxALIGN_CENTER_VERTICAL + wx.wxALIGN_RIGHT + wx.wxALL + wx.wxEXPAND, 5 )
+
+ UI.filePickVideo = wx.wxFilePickerCtrl( UI.dlgSinge, wx.wxID_ANY, "", "Select a file", "*.*", wx.wxDefaultPosition, wx.wxDefaultSize, wx.wxFLP_DEFAULT_STYLE + wx.wxFLP_FILE_MUST_EXIST + wx.wxFLP_OPEN + wx.wxFLP_USE_TEXTCTRL )
+ UI.fgSizer1:Add( UI.filePickVideo, 0, wx.wxALL + wx.wxEXPAND, 5 )
+
+ UI.lblOptions = wx.wxStaticText( UI.dlgSinge, wx.wxID_ANY, "Options:", wx.wxDefaultPosition, wx.wxDefaultSize, 0 )
+ UI.lblOptions:Wrap( -1 )
+
+ UI.fgSizer1:Add( UI.lblOptions, 0, wx.wxALIGN_CENTER_VERTICAL + wx.wxALIGN_RIGHT + wx.wxALL, 5 )
+
+ UI.txtOptions = wx.wxTextCtrl( UI.dlgSinge, wx.wxID_ANY, "", wx.wxDefaultPosition, wx.wxDefaultSize, 0 )
+ UI.fgSizer1:Add( UI.txtOptions, 0, wx.wxALL + wx.wxEXPAND, 5 )
+
+ UI.fgSizer1:Add( 0, 20, 1, wx.wxEXPAND, 5 )
+ UI.fgSizer1:Add( 0, 20, 1, wx.wxEXPAND, 5 )
+
+ UI.fgSizer1:Add( 0, 0, 1, wx.wxEXPAND, 5 )
+
+ UI.m_sdbSizer1 = wx.wxStdDialogButtonSizer()
+ UI.m_sdbSizer1OK = wx.wxButton( UI.dlgSinge, wx.wxID_OK, "" )
+ UI.m_sdbSizer1:AddButton( UI.m_sdbSizer1OK )
+ UI.m_sdbSizer1Cancel = wx.wxButton( UI.dlgSinge, wx.wxID_CANCEL, "" )
+ UI.m_sdbSizer1:AddButton( UI.m_sdbSizer1Cancel )
+ UI.m_sdbSizer1:Realize();
+
+ UI.fgSizer1:Add( UI.m_sdbSizer1, 1, wx.wxEXPAND, 5 )
+
+ UI.fgSizer1:Add( 0, 20, 1, wx.wxEXPAND, 5 )
+ UI.fgSizer1:Add( 0, 20, 1, wx.wxEXPAND, 5 )
+
+ UI.dlgSinge:SetSizer( UI.fgSizer1 )
+ UI.dlgSinge:Layout()
+ UI.fgSizer1:Fit( UI.dlgSinge )
+
+ UI.dlgSinge:Centre( wx.wxBOTH )
+
+ -- Don't let users type in filename boxes
+ UI.filePickSinge:GetTextCtrl():Connect( wx.wxEVT_KEY_DOWN, function(event) end )
+ UI.filePickScript:GetTextCtrl():Connect( wx.wxEVT_KEY_DOWN, function(event) end )
+ UI.filePickVideo:GetTextCtrl():Connect( wx.wxEVT_KEY_DOWN, function(event) end )
+
+ if settings then
+ if settings.singe then UI.filePickSinge:GetTextCtrl():SetValue(settings.singe) end
+ if settings.script then UI.filePickScript:GetTextCtrl():SetValue(settings.script) end
+ if settings.video then UI.filePickVideo:GetTextCtrl():SetValue(settings.video) end
+ if settings.options then UI.txtOptions:SetValue(settings.options) end
+ end
+
+ UI.m_sdbSizer1Cancel:Connect( wx.wxEVT_COMMAND_BUTTON_CLICKED, function(event)
+ event:Skip()
+ end )
+
+ UI.m_sdbSizer1OK:Connect( wx.wxEVT_COMMAND_BUTTON_CLICKED, function(event)
+ settings.singe = UI.filePickSinge:GetTextCtrl():GetValue()
+ settings.script = UI.filePickScript:GetTextCtrl():GetValue()
+ settings.video = UI.filePickVideo:GetTextCtrl():GetValue()
+ settings.options = UI.txtOptions:GetValue()
+ self:SetSettings(settings)
+ event:Skip()
+ end )
+
+ wx.wxGetApp():SetTopWindow(UI.dlgSinge)
+
+ UI.dlgSinge:ShowModal()
+ UI.dlgSinge:Destroy()
+end
+
+
+local function singeEnd(s)
+ ide:GetOutput():Write(s)
+end
+
+
+local function startSinge()
+ local projectPath = ide:GetProject()
+
+ if not(projectPath) then
+ ide:GetOutput():Write("No project path has been defined.\n")
+ return
+ end
+
+ --ide:ExecuteCommand(settings.singe .. ' ' .. settings.options, projectPath, singeEnd)
+
+ ide:Print(tprint(settings))
+ ide:Print(ide:GetProject())
+end
+
+
+return {
+ name = "Add `Singe` toolbar button",
+ description = "Adds a menu item and toolbar button that will launch `Singe`",
+ author = "Scott Duensing",
+ version = 1.00,
+ dependencies = "1.0",
+
+ onRegister = function(self)
+ local menu = ide:FindTopMenu("&Project")
+ menu:Append(id, "Singe Configuration")
+ ide:GetMainFrame():Connect(id, wx.wxEVT_COMMAND_MENU_SELECTED, function() configureSinge(self) end)
+
+ settings = self:GetSettings()
+
+ local tb = ide:GetToolBar()
+ tool = tb:AddTool(id, "Singe"..KSC(id), wx.wxBitmap({
+ "16 16 136 2",
+ " c None",
+ ". c #374D34", "+ c #375137", "@ c #344D33", "# c #39503B",
+ "$ c #445A49", "% c #3F5543", "& c #354A31", "* c #395137",
+ "= c #385138", "- c #354E35", "; c #3D5441", "> c #77886B",
+ ", c #9AA880", "' c #829271", ") c #405646", "! c #314730",
+ "~ c #344A31", "{ c #385137", "] c #3A5239", "^ c #374D37",
+ "/ c #889674", "( c #CFD9A2", "_ c #D3DDA4", ": c #C1CB98",
+ "< c #4A5F4E", "[ c #3D5346", "} c #394E41", "| c #344C36",
+ "1 c #395238", "2 c #374F36", "3 c #435743", "4 c #BFCA97",
+ "5 c #C0CA97", "6 c #BDC796", "7 c #95A27D", "8 c #3D5341",
+ "9 c #51695C", "0 c #526A5B", "a c #4D6456", "b c #39503D",
+ "c c #576850", "d c #CAD5A0", "e c #BBC696", "f c #849272",
+ "g c #435742", "h c #354C35", "i c #3E5447", "j c #4A6154",
+ "k c #425747", "l c #445948", "m c #496051", "n c #3D5340",
+ "o c #475B41", "p c #4C6047", "q c #394D38", "r c #506045",
+ "s c #85926D", "t c #344C35", "u c #324933", "v c #364D36",
+ "w c #374E37", "x c #375037", "y c #39533A", "z c #395339",
+ "A c #4B5E42", "B c #3E543A", "C c #3D523A", "D c #2B412D",
+ "E c #314832", "F c #314831", "G c #365037", "H c #375237",
+ "I c #324B32", "J c #5F7052", "K c #828D69", "L c #324931",
+ "M c #354D34", "N c #365036", "O c #314A31", "P c #364E35",
+ "Q c #334A32", "R c #405440", "S c #2C442D", "T c #375238",
+ "U c #385238", "V c #2F472F", "W c #29402A", "X c #324932",
+ "Y c #273D28", "Z c #30472F", "` c #334830", " . c #293D27",
+ ".. c #2B422B", "+. c #365137", "@. c #314A32", "#. c #2B422C",
+ "$. c #324A32", "%. c #30452F", "&. c #213522", "*. c #1D321F",
+ "=. c #3D563B", "-. c #385338", ";. c #385237", ">. c #314931",
+ ",. c #29412B", "'. c #273D29", "). c #2E432D", "!. c #4B6045",
+ "~. c #98A57C", "{. c #395338", "]. c #273E2A", "^. c #2E422D",
+ "/. c #697959", "(. c #BAC696", "_. c #3C533A", ":. c #2F4730",
+ "<. c #2E472F", "[. c #304830", "}. c #50634A", "|. c #475D43",
+ "1. c #273E28", "2. c #3E503A", "3. c #96A27C", "4. c #3A543A",
+ "5. c #B2BD90", "6. c #B7C294", "7. c #55644A", "8. c #485B44",
+ "9. c #395239", "0. c #395138", "a. c #385036", "b. c #3A5037",
+ "c. c #384F36", "d. c #828F6D", "e. c #5B694D",
+ " . + @ + # $ % ",
+ " & * = - ; > , ' ) ",
+ " ! ~ { ] ^ / ( _ : < ",
+ " [ } | ] 1 2 3 4 5 6 7 8 ",
+ " 9 0 0 a b 1 2 c d e f g h ",
+ " i j k l m n h o p q r s t ",
+ " u v w w x y z z A B C ",
+ " D E x - F - G H I J K ",
+ " L M - + N + O P Q R ",
+ " S + T U T I V W X Y ",
+ "Z ` ...{ +.+.H H @...#.$.W ",
+ "%.&.*.@ =.H T U -.;.N >.U ,. ",
+ " '.).!.~.-.T H -.-.{.1 { ]. ",
+ " ^./.(._.:.<.[.}.|._.1. ",
+ " 2.3.J = T U 4.5.6.7. ",
+ " 8.9.0.a.b.c.d.e. "
+ }))
+ tb:Realize()
+ end,
+
+ onUnRegister = function(self)
+ local tb = ide:GetToolBar()
+ tb:DeleteTool(tool)
+ tb:Realize()
+
+ ide:RemoveMenuItem(id)
+ end,
+}
diff --git a/zbstudio/user.lua b/zbstudio/user.lua
new file mode 100644
index 000000000..9f2c00cd8
--- /dev/null
+++ b/zbstudio/user.lua
@@ -0,0 +1,12 @@
+editor.specmap.singe = 'lua'
+
+editor.tabwidth = 4
+editor.usetabs = true
+editor.usewrap = false
+editor.whitespace = true
+editor.autoactivate = true
+
+styles = loadfile('cfg/tomorrow.lua')('TomorrowNightBright')
+stylesoutshell = styles -- apply the same scheme to Output/Console windows
+styles.auxwindow = styles.text -- apply text colors to auxiliary windows
+styles.whitespace = {fg = {75, 75, 75}}