-- Copyright 2011-18 Paul Kulchenko, ZeroBrane LLC -- authors: Luxinia Dev (Eike Decker & Christoph Kubisch) -- Lomtik Software (J. Winwood & John Labenski) --------------------------------------------------------- local ide = ide local unpack = table.unpack or unpack do local font, config = wx.wxTreeCtrl():GetFont(), ide.config.filetree if config.fontsize then font:SetPointSize(config.fontsize) end if config.fontname then font:SetFaceName(config.fontname) end ide.font.tree = font end -- ---------------------------------------------------------------------------- -- Create the wxFrame -- ---------------------------------------------------------------------------- local function createFrame() local frame = ide:GetMainFrame() -- retrieve or create as needed frame:Center() -- update best size of the toolbar after resizing frame:Connect(wx.wxEVT_SIZE, function(event) local mgr = ide:GetUIManager() local toolbar = mgr:GetPane("toolbar") if toolbar and toolbar:IsOk() then toolbar:BestSize(event:GetSize():GetWidth(), ide:GetToolBar():GetClientSize():GetHeight()) mgr:Update() end end) if wx.wxMenuBar.SetAutoWindowMenu then wx.wxMenuBar.SetAutoWindowMenu(false) end local menuBar = wx.wxMenuBar() local statusBar = frame:CreateStatusBar(5) local section_width = statusBar:GetTextExtent("OVRW") statusBar:SetStatusStyles({wx.wxSB_FLAT, wx.wxSB_FLAT, wx.wxSB_FLAT, wx.wxSB_FLAT, wx.wxSB_FLAT}) statusBar:SetStatusWidths({-1, section_width, section_width, section_width*5, section_width*5}) statusBar:SetStatusText(ide:GetProperty("statuswelcome", "")) statusBar:Connect(wx.wxEVT_LEFT_DOWN, function (event) local rect = wx.wxRect() statusBar:GetFieldRect(4, rect) if rect:Contains(event:GetPosition()) then -- click on the interpreter section local interpreter = ide:GetInterpreter() if interpreter and interpreter.takeparameters and interpreter:GetCommandLineArg() then rect:SetWidth(statusBar:GetTextExtent(ide:GetInterpreter():GetName()..": ")) if not rect:Contains(event:GetPosition()) then local menuitem = ide:FindMenuItem(ID.COMMANDLINEPARAMETERS) if menuitem then local menu = ide:MakeMenu { { ID.COMMANDLINEPARAMETERS, TR("Command Line Parameters...")..KSC(ID.COMMANDLINEPARAMETERS) }, } local cmdargs = ide:GetPackage("core.project"):GetCmdLines() local curargs = interpreter:GetCommandLineArg() if #cmdargs > 1 or cmdargs[1] ~= curargs then menu:PrependSeparator() end local function setParams(ev) ide:SetCommandLineParameters(menu:GetLabel(ev:GetId())) end -- do in the reverse order as `Prepend` is used; -- skip the currently set parameters for i = #cmdargs, 1, -1 do if cmdargs[i] ~= curargs then local id = ID("status.commandparameters."..i) menu:Prepend(id, cmdargs[i]) menu:Connect(id, wx.wxEVT_COMMAND_MENU_SELECTED, setParams) end end statusBar:PopupMenu(menu) end return end end local menuitem = ide:FindMenuItem(ID.INTERPRETER) if menuitem then local menu = ide:CloneMenu(menuitem:GetSubMenu()) if menu then statusBar:PopupMenu(menu) end end end end) local mgr = wxaui.wxAuiManager() mgr:SetManagedWindow(frame) -- allow the panes to be larger than the defalt 1/3 of the main window size mgr:SetDockSizeConstraint(0.8,0.8) frame.menuBar = menuBar frame.statusBar = statusBar frame.uimgr = mgr return frame end local function SCinB(id) -- shortcut in brackets local osx = ide.osname == "Macintosh" local shortcut = KSC(id):gsub("\t","") return shortcut and #shortcut > 0 and (" ("..shortcut:gsub("%f[%w]Ctrl", osx and "Cmd" or "Ctrl")..")") or "" end local function menuDropDownPosition(event) local tb = event:GetEventObject():DynamicCast('wxAuiToolBar') local rect = tb:GetToolRect(event:GetId()) return ide.frame:ScreenToClient(tb:ClientToScreen(rect:GetBottomLeft())) end local function createToolBar(frame) local toolBar = wxaui.wxAuiToolBar(frame, wx.wxID_ANY, wx.wxDefaultPosition, wx.wxDefaultSize, wxaui.wxAUI_TB_PLAIN_BACKGROUND) local iconsize = ide:GetBestIconSize() local toolBmpSize = wx.wxSize(iconsize, iconsize) local icons = ide.config.toolbar.icons local needseparator = false for _, id in ipairs(icons) do if icons[id] ~= false then -- skip explicitly disabled icons if id == ID.SEPARATOR and toolBar:GetToolCount() > 0 then needseparator = true else local iconmap = ide.config.toolbar.iconmap[id] if iconmap then if needseparator then toolBar:AddSeparator() needseparator = false end local icon, description = unpack(iconmap) local isbitmap = type(icon) == "userdata" and icon:GetClassInfo():GetClassName() == "wxBitmap" local bitmap = isbitmap and icon or ide:GetBitmap(icon, "TOOLBAR", toolBmpSize) toolBar:AddTool(id, "", bitmap, (TR)(description)..SCinB(id)) end end end end toolBar:SetToolDropDown(ID.OPEN, true) toolBar:Connect(ID.OPEN, wxaui.wxEVT_COMMAND_AUITOOLBAR_TOOL_DROPDOWN, function(event) if event:IsDropDownClicked() then local menu = wx.wxMenu({}) FileRecentListUpdate(menu) toolBar:PopupMenu(menu, menuDropDownPosition(event)) else event:Skip() end end) toolBar:SetToolDropDown(ID.PROJECTDIRCHOOSE, true) toolBar:Connect(ID.PROJECTDIRCHOOSE, wxaui.wxEVT_COMMAND_AUITOOLBAR_TOOL_DROPDOWN, function(event) if event:IsDropDownClicked() then local menu = wx.wxMenu({}) FileTreeProjectListUpdate(menu, 0) toolBar:PopupMenu(menu, menuDropDownPosition(event)) else event:Skip() end end) toolBar:GetArtProvider():SetElementSize(wxaui.wxAUI_TBART_GRIPPER_SIZE, 0) toolBar:Realize() frame.toolBar = toolBar return toolBar end local function getTabWindow(event, nb) local tabctrl = event:GetEventObject():DynamicCast("wxAuiTabCtrl") local idx = event:GetSelection() -- index within the current tab ctrl local win = tabctrl:GetPage(idx).window return win and idx ~= wx.wxNOT_FOUND and nb:GetPageIndex(win) or wx.wxNOT_FOUND, tabctrl end local function isPreview(win) return ide.findReplace ~= nil and ide.findReplace:IsPreview(win) end local function createNotebook(frame) -- notebook for editors local notebook = ide:CreateNotebook(frame, wx.wxID_ANY, wx.wxDefaultPosition, wx.wxDefaultSize, wxaui.wxAUI_NB_DEFAULT_STYLE + wxaui.wxAUI_NB_TAB_EXTERNAL_MOVE + wxaui.wxAUI_NB_WINDOWLIST_BUTTON + wx.wxNO_BORDER) -- there is a protected method in wxwidgets, but it's not available in wxlua, -- so use a workaround to find the tab control that the page belongs to. function notebook:GetTabCtrl(win) local pg = win and self:GetPageIndex(win) >= 0 and win or self:GetCurrentPage() if not pg then return nil end local px,py = pg:GetScreenPosition():GetXY() local point = wx.wxPoint(px,py-10) -- right above the page in the notebook local ctrl = wx.wxFindWindowAtPoint(point) return ctrl and ctrl:DynamicCast("wxAuiTabCtrl") or nil end -- wxEVT_SET_FOCUS could be used, but it only works on Windows with wx2.9.5+ notebook:Connect(wxaui.wxEVT_COMMAND_AUINOTEBOOK_PAGE_CHANGED, function (event) -- skip setting focus when exiting, as it may cause looping on macOS if ide:IsExiting() then return end local doc = ide:GetDocument(notebook:GetCurrentPage()) -- skip activation when any of the following is true: -- (1) there is no document yet, the editor tab was just added, -- so no changes needed as there will be a proper later call; -- (2) on OSX from AddPage event when changing from the last tab -- (this is to work around a duplicate event generated in this case -- that first activates the added tab and then some other tab (2.9.5)). local double = (ide.osname == 'Macintosh' and event:GetOldSelection() == notebook:GetPageCount() and debug:traceback():find("'AddPage'")) if doc and doc:GetTabIndex() and not double then doc:SetActive() end end) notebook:Connect(wxaui.wxEVT_COMMAND_AUINOTEBOOK_PAGE_CLOSE, function (event) local idx = event:GetSelection() if idx ~= wx.wxNOT_FOUND then local doc = ide:GetDocument(notebook:GetPage(idx)) if doc then -- make sure that the doc is in the same notebook and is not moved somewhere local i, nb = doc:GetTabIndex() if i == idx and nb == notebook then doc:Close() end end end event:Veto() -- don't propagate the event as the page is already closed end) notebook:Connect(wxaui.wxEVT_COMMAND_AUINOTEBOOK_BG_DCLICK, function (event) -- as this event can be on different tab controls, -- need to find the control to add the page to local tabctrl = event:GetEventObject():DynamicCast("wxAuiTabCtrl") -- check if the active page is in the current control local active = tabctrl:GetActivePage() if (active >= 0 and tabctrl:GetPage(active).window ~= notebook:GetPage(notebook:GetSelection())) then -- if not, need to activate the control that was clicked on; -- find the last window and switch to it (assuming there is always one) assert(tabctrl:GetPageCount() >= 1, "Expected at least one page in a notebook tab control.") local lastwin = tabctrl:GetPage(tabctrl:GetPageCount()-1).window notebook:SetSelection(notebook:GetPageIndex(lastwin)) end NewFile() end) -- tabs can be dragged around which may change their indexes; -- when this happens stored indexes need to be updated to reflect the change. -- there is DRAG_DONE event that I'd prefer to use, but it -- doesn't fire for some reason using wxwidgets 2.9.5 (tested on Windows). if ide.wxver >= "2.9.5" then notebook:Connect(wxaui.wxEVT_COMMAND_AUINOTEBOOK_END_DRAG, function (event) local selection = getTabWindow(event, notebook) if selection == wx.wxNOT_FOUND then return end -- set the selection on the dragged tab to reset its state -- workaround for wxwidgets issue http://trac.wxwidgets.org/ticket/15071 notebook:SetSelection(selection) -- select the content of the tab after drag is done local doc = ide:GetDocument(notebook:GetPage(selection)) if doc then doc:SetActive() end event:Skip() end) end local selection notebook:Connect(wxaui.wxEVT_COMMAND_AUINOTEBOOK_TAB_RIGHT_UP, function (event) -- event:GetSelection() returns the index *inside the current tab*; -- for split notebooks, this may not be the same as the index -- in the notebook we are interested in here local idx = event:GetSelection() if idx == wx.wxNOT_FOUND then return end local tabctrl = event:GetEventObject():DynamicCast("wxAuiTabCtrl") -- save the editor from the tab initiating the event selection = tabctrl:GetPage(idx).window -- save tab index the event is for local curindex = notebook:GetSelection() local selindex = notebook:GetPageIndex(selection) if curindex ~= selindex then notebook:SetSelection(selindex) end local tree = ide:GetProjectTree() local startfile = tree:GetStartFile() local menu = ide:MakeMenu { { ID.CLOSE, TR("&Close Page") }, { ID.CLOSEALL, TR("Close A&ll Pages") }, { ID.CLOSEOTHER, TR("Close &Other Pages") }, { ID.CLOSESEARCHRESULTS, TR("Close Search Results Pages") }, { }, { ID.SAVE, TR("&Save") }, { ID.SAVEAS, TR("Save &As...") }, { }, { ID.SETSTARTFILE, TR("Set As Start File") }, { ID.UNSETSTARTFILE, TR("Unset '%s' As Start File"):format(startfile or "") }, { }, { ID.COPYFULLPATH, TR("Copy Full Path") }, { ID.SHOWLOCATION, TR("Open Containing Folder") }, { ID.REFRESHSEARCHRESULTS, TR("Refresh Search Results") }, } local fpath = ide:GetDocument(selection):GetFilePath() if not fpath or not tree:FindItem(fpath) then menu:Enable(ID.SETSTARTFILE, false) end if not startfile then menu:Destroy(ID.UNSETSTARTFILE) end PackageEventHandle("onMenuEditorTab", menu, notebook, event, notebook:GetPageIndex(selection)) -- popup statuses are not refreshed on Linux, so do it manually if ide.osname == "Unix" then UpdateMenuUI(menu, notebook) end notebook:PopupMenu(menu) -- restore selection if it has changed if curindex ~= selindex then notebook:SetSelection(curindex) end end) local function IfAtLeastOneTab(event) event:Enable(notebook:GetPageCount() > 0) end notebook:Connect(ID.SETSTARTFILE, wx.wxEVT_COMMAND_MENU_SELECTED, function() local fpath = ide:GetDocument(selection):GetFilePath() if fpath then ide:GetProjectTree():SetStartFile(fpath) end end) notebook:Connect(ID.UNSETSTARTFILE, wx.wxEVT_COMMAND_MENU_SELECTED, function() ide:GetProjectTree():SetStartFile() end) notebook:Connect(ID.SAVE, wx.wxEVT_COMMAND_MENU_SELECTED, function() ide:GetDocument(selection):Save() end) notebook:Connect(ID.SAVE, wx.wxEVT_UPDATE_UI, function(event) local doc = ide:GetDocument(selection) event:Enable(doc:IsModified() or doc:IsNew()) end) notebook:Connect(ID.SAVEAS, wx.wxEVT_COMMAND_MENU_SELECTED, function() SaveFileAs(selection) end) notebook:Connect(ID.SAVEAS, wx.wxEVT_UPDATE_UI, IfAtLeastOneTab) -- the following three methods require handling of closing in the idle event, -- because of wxwidgets issue that causes crash on OSX when the last page is closed -- (http://trac.wxwidgets.org/ticket/15417) notebook:Connect(ID.CLOSE, wx.wxEVT_UPDATE_UI, IfAtLeastOneTab) notebook:Connect(ID.CLOSE, wx.wxEVT_COMMAND_MENU_SELECTED, function() ide:DoWhenIdle(function() ide:GetDocument(selection):Close() end) end) notebook:Connect(ID.CLOSEALL, wx.wxEVT_UPDATE_UI, IfAtLeastOneTab) notebook:Connect(ID.CLOSEALL, wx.wxEVT_COMMAND_MENU_SELECTED, function() ide:DoWhenIdle(function() ide:GetDocument(selection):CloseAll({scope = "section"}) end) end) notebook:Connect(ID.CLOSEOTHER, wx.wxEVT_UPDATE_UI, function(event) event:Enable(notebook:GetPageCount() > 1) end) notebook:Connect(ID.CLOSEOTHER, wx.wxEVT_COMMAND_MENU_SELECTED, function() ide:DoWhenIdle(function() ide:GetDocument(selection):CloseAll({keep = true, scope = "section"}) end) end) notebook:Connect(ID.CLOSESEARCHRESULTS, wx.wxEVT_UPDATE_UI, function(event) local ispreview = false for p = 0, notebook:GetPageCount()-1 do ispreview = ispreview or isPreview(notebook:GetPage(p)) end event:Enable(ispreview) end) notebook:Connect(ID.CLOSESEARCHRESULTS, wx.wxEVT_COMMAND_MENU_SELECTED, function() ide:DoWhenIdle(function() for p = notebook:GetPageCount()-1, 0, -1 do local editor = notebook:GetPage(p) if isPreview(editor) then ide:GetDocument(editor):Close() end end end) end) notebook:Connect(ID.REFRESHSEARCHRESULTS, wx.wxEVT_UPDATE_UI, function(event) event:Enable(isPreview(selection)) end) notebook:Connect(ID.REFRESHSEARCHRESULTS, wx.wxEVT_COMMAND_MENU_SELECTED, function() ide.findReplace:RefreshResults(selection) end) notebook:Connect(ID.SHOWLOCATION, wx.wxEVT_COMMAND_MENU_SELECTED, function() ShowLocation(ide:GetDocument(selection):GetFilePath()) end) notebook:Connect(ID.SHOWLOCATION, wx.wxEVT_UPDATE_UI, IfAtLeastOneTab) notebook:Connect(ID.COPYFULLPATH, wx.wxEVT_COMMAND_MENU_SELECTED, function() ide:CopyToClipboard(ide:GetDocument(selection):GetFilePath()) end) frame.notebook = notebook return notebook end local function addDND(notebook) -- this handler allows dragging tabs into this notebook notebook:Connect(wxaui.wxEVT_COMMAND_AUINOTEBOOK_ALLOW_DND, function (event) local notebookfrom = event:GetDragSource() if notebookfrom ~= ide.frame.notebook then -- disable cross-notebook movement of specific tabs local idx = event:GetSelection() if idx == wx.wxNOT_FOUND then return end local win = notebookfrom:GetPage(idx) if not win then return end local winid = win:GetId() if (ide:IsValidCtrl(ide:GetOutput()) and winid == ide:GetOutput():GetId()) or (ide:IsValidCtrl(ide:GetConsole()) and winid == ide:GetConsole():GetId()) or (ide:IsValidCtrl(ide:GetProjectTree()) and winid == ide:GetProjectTree():GetId()) or isPreview(win) -- search results preview then return end local mgr = ide.frame.uimgr local pane = mgr:GetPane(notebookfrom) if not pane:IsOk() then return end -- not a managed window if pane:IsFloating() then notebookfrom:GetParent():Hide() else pane:Hide() mgr:Update() end mgr:DetachPane(notebookfrom) -- this is a workaround for wxwidgets bug (2.9.5+) that combines -- content from two windows when tab is dragged over an active tab. local mouse = wx.wxGetMouseState() local mouseatpoint = wx.wxPoint(mouse:GetX(), mouse:GetY()) local ok, tabs = pcall(function() return wx.wxFindWindowAtPoint(mouseatpoint):DynamicCast("wxAuiTabCtrl") end) if ok then tabs:SetNoneActive() end event:Allow() end end) -- these handlers allow dragging tabs out of this notebook. -- I couldn't find a good way to stop dragging event as it's not known -- where the event is going to end when it's started, so we manipulate -- the flag that allows splits and disable it when needed. -- It is then enabled in BEGIN_DRAG event. notebook:Connect(wxaui.wxEVT_COMMAND_AUINOTEBOOK_BEGIN_DRAG, function (event) event:Skip() -- allow dragging if it was disabled earlier local flags = notebook:GetWindowStyleFlag() if bit.band(flags, wxaui.wxAUI_NB_TAB_SPLIT) == 0 then notebook:SetWindowStyleFlag(flags + wxaui.wxAUI_NB_TAB_SPLIT) end end) -- there is currently no support in wxAuiNotebook for dragging tabs out. -- This is implemented as removing a tab that was dragged out and -- recreating it with the right control. This is complicated by the fact -- that tabs can be split, so if the destination is withing the area where -- splits happen, the tab is not removed. notebook:Connect(wxaui.wxEVT_COMMAND_AUINOTEBOOK_END_DRAG, function (event) event:Skip() local mgr = ide.frame.uimgr local win = mgr:GetPane(notebook).window local x = win:GetScreenPosition():GetX() local y = win:GetScreenPosition():GetY() local w, h = win:GetSize():GetWidth(), win:GetSize():GetHeight() local selection, tabctrl = getTabWindow(event, notebook) if selection == wx.wxNOT_FOUND then return end local mouse = wx.wxGetMouseState() local mx, my = mouse:GetX(), mouse:GetY() if mx < x or mx > x + w or my < y or my > y + h then -- disallow split as the target is outside the notebook local flags = notebook:GetWindowStyleFlag() if bit.band(flags, wxaui.wxAUI_NB_TAB_SPLIT) ~= 0 then notebook:SetWindowStyleFlag(flags - wxaui.wxAUI_NB_TAB_SPLIT) end if ide.wxver < "3.0" then -- don't allow dragging out single tabs from tab ctrl -- as wxwidgets doesn't like removing pages from split notebooks. if tabctrl:GetPageCount() == 1 then return end end -- don't allow last pages to be dragged out from Project and Output notebooks if (notebook == ide:GetProjectNotebook() or notebook == ide:GetOutputNotebook()) and notebook:GetPageCount() == 1 then return end local label = notebook:GetPageText(selection) local pane = ide:RestorePanelByLabel(label) if pane then pane:FloatingPosition(mx-10, my-10) pane:Show() notebook:RemovePage(selection) mgr:Update() return end end -- set the selection on the dragged tab to reset its state -- workaround for wxwidgets issue http://trac.wxwidgets.org/ticket/15071 notebook:SetSelection(selection) -- set focus on the content of the selected tab notebook:GetPage(selection):SetFocus() end) end local function createBottomNotebook(frame) -- bottomnotebook (errorlog,shellbox) local bottomnotebook = ide:CreateNotebook(frame, wx.wxID_ANY, wx.wxDefaultPosition, wx.wxDefaultSize, wxaui.wxAUI_NB_DEFAULT_STYLE + wxaui.wxAUI_NB_TAB_EXTERNAL_MOVE - wxaui.wxAUI_NB_CLOSE_ON_ACTIVE_TAB + wx.wxNO_BORDER) addDND(bottomnotebook) bottomnotebook:Connect(wxaui.wxEVT_COMMAND_AUINOTEBOOK_PAGE_CHANGED, function (event) -- skip setting focus when exiting, as it may cause looping on macOS if ide:IsExiting() then return end local nb = event:GetEventObject():DynamicCast("wxAuiNotebook") -- set focus on the new page local idx = event:GetSelection() if idx == wx.wxNOT_FOUND then return end nb:GetPage(idx):SetFocus() local preview = isPreview(nb:GetPage(nb:GetSelection())) local flags = nb:GetWindowStyleFlag() if preview and bit.band(flags, wxaui.wxAUI_NB_CLOSE_ON_ACTIVE_TAB) == 0 then nb:SetWindowStyleFlag(flags + wxaui.wxAUI_NB_CLOSE_ON_ACTIVE_TAB) elseif not preview and bit.band(flags, wxaui.wxAUI_NB_CLOSE_ON_ACTIVE_TAB) ~= 0 then nb:SetWindowStyleFlag(flags - wxaui.wxAUI_NB_CLOSE_ON_ACTIVE_TAB) end end) -- disallow tabs closing bottomnotebook:Connect(wxaui.wxEVT_COMMAND_AUINOTEBOOK_PAGE_CLOSE, function (event) local nb = event:GetEventObject():DynamicCast("wxAuiNotebook") if isPreview(nb:GetPage(nb:GetSelection())) then event:Skip() else event:Veto() end end) local selection bottomnotebook:Connect(wxaui.wxEVT_COMMAND_AUINOTEBOOK_TAB_RIGHT_UP, function (event) -- event:GetSelection() returns the index *inside the current tab*; -- for split notebooks, this may not be the same as the index -- in the notebook we are interested in here local idx = event:GetSelection() if idx == wx.wxNOT_FOUND then return end local tabctrl = event:GetEventObject():DynamicCast("wxAuiTabCtrl") -- save tab index the event is for selection = bottomnotebook:GetPageIndex(tabctrl:GetPage(idx).window) local menu = ide:MakeMenu { { ID.CLOSE, TR("&Close Page") }, { ID.CLOSESEARCHRESULTS, TR("Close Search Results Pages") }, { }, { ID.REFRESHSEARCHRESULTS, TR("Refresh Search Results") }, } PackageEventHandle("onMenuOutputTab", menu, bottomnotebook, event, selection) -- popup statuses are not refreshed on Linux, so do it manually if ide.osname == "Unix" then UpdateMenuUI(menu, bottomnotebook) end bottomnotebook:PopupMenu(menu) end) bottomnotebook:Connect(ID.CLOSE, wx.wxEVT_COMMAND_MENU_SELECTED, function() ide:DoWhenIdle(function() bottomnotebook:DeletePage(selection) end) end) bottomnotebook:Connect(ID.CLOSE, wx.wxEVT_UPDATE_UI, function(event) event:Enable(isPreview(bottomnotebook:GetPage(selection))) end) bottomnotebook:Connect(ID.CLOSESEARCHRESULTS, wx.wxEVT_COMMAND_MENU_SELECTED, function() ide:DoWhenIdle(function() for p = bottomnotebook:GetPageCount()-1, 0, -1 do if isPreview(bottomnotebook:GetPage(p)) then bottomnotebook:DeletePage(p) end end end) end) bottomnotebook:Connect(ID.CLOSESEARCHRESULTS, wx.wxEVT_UPDATE_UI, function(event) local ispreview = false for p = 0, bottomnotebook:GetPageCount()-1 do ispreview = ispreview or isPreview(bottomnotebook:GetPage(p)) end event:Enable(ispreview) end) bottomnotebook:Connect(ID.REFRESHSEARCHRESULTS, wx.wxEVT_UPDATE_UI, function(event) event:Enable(isPreview(bottomnotebook:GetPage(selection))) end) bottomnotebook:Connect(ID.REFRESHSEARCHRESULTS, wx.wxEVT_COMMAND_MENU_SELECTED, function() ide.findReplace:RefreshResults(bottomnotebook:GetPage(selection)) end) local errorlog = ide:CreateStyledTextCtrl(bottomnotebook, wx.wxID_ANY, wx.wxDefaultPosition, wx.wxDefaultSize, wx.wxBORDER_NONE) errorlog:Connect(wx.wxEVT_CONTEXT_MENU, function (event) local menu = ide:MakeMenu { { ID.UNDO, TR("&Undo")..KSC(ID.UNDO) }, { ID.REDO, TR("&Redo")..KSC(ID.REDO) }, { }, { ID.CUT, TR("Cu&t")..KSC(ID.CUT) }, { ID.COPY, TR("&Copy")..KSC(ID.COPY) }, { ID.PASTE, TR("&Paste")..KSC(ID.PASTE) }, { ID.SELECTALL, TR("Select &All")..KSC(ID.SELECTALL) }, { }, { ID.CLEAROUTPUT, TR("C&lear Output Window")..KSC(ID.CLEAROUTPUT) }, } PackageEventHandle("onMenuOutput", menu, errorlog, event) -- popup statuses are not refreshed on Linux, so do it manually if ide.osname == "Unix" then UpdateMenuUI(menu, errorlog) end errorlog:PopupMenu(menu) end) -- connect to the main frame, so it can be called from anywhere frame:Connect(ID.CLEAROUTPUT, wx.wxEVT_COMMAND_MENU_SELECTED, function(event) ide:GetOutput():Erase() end) local shellbox = ide:CreateStyledTextCtrl(bottomnotebook, wx.wxID_ANY, wx.wxDefaultPosition, wx.wxDefaultSize, wx.wxBORDER_NONE) local menupos shellbox:Connect(wx.wxEVT_CONTEXT_MENU, function (event) local menu = ide:MakeMenu { { ID.UNDO, TR("&Undo")..KSC(ID.UNDO) }, { ID.REDO, TR("&Redo")..KSC(ID.REDO) }, { }, { ID.CUT, TR("Cu&t")..KSC(ID.CUT) }, { ID.COPY, TR("&Copy")..KSC(ID.COPY) }, { ID.PASTE, TR("&Paste")..KSC(ID.PASTE) }, { ID.SELECTALL, TR("Select &All")..KSC(ID.SELECTALL) }, { }, { ID.SELECTCONSOLECOMMAND, TR("&Select Command") }, { ID.CLEARCONSOLE, TR("C&lear Console Window")..KSC(ID.CLEARCONSOLE) }, } menupos = event:GetPosition() PackageEventHandle("onMenuConsole", menu, shellbox, event) -- popup statuses are not refreshed on Linux, so do it manually if ide.osname == "Unix" then UpdateMenuUI(menu, shellbox) end shellbox:PopupMenu(menu) end) shellbox:Connect(ID.SELECTCONSOLECOMMAND, wx.wxEVT_COMMAND_MENU_SELECTED, function(event) ConsoleSelectCommand(menupos) end) -- connect to the main frame, so it can be called from anywhere frame:Connect(ID.CLEARCONSOLE, wx.wxEVT_COMMAND_MENU_SELECTED, function(event) ide:GetConsole():Erase() end) bottomnotebook:AddPage(errorlog, TR("Output"), true) bottomnotebook:AddPage(shellbox, TR("Local console"), false) bottomnotebook.errorlog = errorlog bottomnotebook.shellbox = shellbox frame.bottomnotebook = bottomnotebook return bottomnotebook end local function createProjNotebook(frame) local projnotebook = ide:CreateNotebook(frame, wx.wxID_ANY, wx.wxDefaultPosition, wx.wxDefaultSize, wxaui.wxAUI_NB_DEFAULT_STYLE + wxaui.wxAUI_NB_TAB_EXTERNAL_MOVE - wxaui.wxAUI_NB_CLOSE_ON_ACTIVE_TAB + wx.wxNO_BORDER) addDND(projnotebook) -- disallow tabs closing projnotebook:Connect(wxaui.wxEVT_COMMAND_AUINOTEBOOK_PAGE_CLOSE, function (event) event:Veto() end) frame.projnotebook = projnotebook return projnotebook end -- ---------------------------------------------------------------------------- -- Add the child windows to the frame local frame = createFrame() createToolBar(frame) createNotebook(frame) createProjNotebook(frame) createBottomNotebook(frame) do local mgr = frame.uimgr mgr:AddPane(frame.toolBar, wxaui.wxAuiPaneInfo(): Name("toolbar"):Caption("Toolbar"): ToolbarPane():Top():CloseButton(false):PaneBorder(false): LeftDockable(false):RightDockable(false)) mgr:AddPane(frame.notebook, wxaui.wxAuiPaneInfo(): Name("notebook"): CenterPane():PaneBorder(false)) mgr:AddPane(frame.projnotebook, wxaui.wxAuiPaneInfo(): Name("projpanel"):CaptionVisible(false): MinSize(200,200):BestSize(300,300):FloatingSize(200,400): Left():Layer(1):Position(1):PaneBorder(false): CloseButton(true):MaximizeButton(false):PinButton(true)) mgr:AddPane(frame.bottomnotebook, wxaui.wxAuiPaneInfo(): Name("bottomnotebook"):CaptionVisible(false): MinSize(100,100):BestSize(200,200):FloatingSize(400,200): Bottom():Layer(1):Position(1):PaneBorder(false): CloseButton(true):MaximizeButton(false):PinButton(true)) if type(ide.config.bordersize) == 'number' then for _, uimgr in pairs {mgr, frame.notebook:GetAuiManager(), frame.bottomnotebook:GetAuiManager(), frame.projnotebook:GetAuiManager()} do uimgr:GetArtProvider():SetMetric(wxaui.wxAUI_DOCKART_SASH_SIZE, -- scale bordersize on Windows, as macOS and Linux/GTK3 do the scaling ide.config.bordersize*(ide.osname == "Windows" and ide:GetContentScaleFactor() or 1)) end end for _, nb in pairs {frame.bottomnotebook, frame.projnotebook} do nb:Connect(wxaui.wxEVT_COMMAND_AUINOTEBOOK_BG_DCLICK, function() PaneFloatToggle(nb) end) end for _, nb in pairs {frame.notebook, frame.bottomnotebook, frame.projnotebook} do nb:SetArtProvider(ide:GetTabArt()) end mgr.defaultPerspective = mgr:SavePerspective() end