-- see copyright notice in wxLdb.lua local print = print local wx = require( "wx" ) _G.print = print -- override wx print function with original one local mainthread = require( "mainthread" ) local assert = assert local setmetatable = setmetatable local getmetatable = getmetatable local string = string local tostring = tostring local pairs = pairs local ipairs = ipairs local table = table local type = type local next = next module( "ui.luaExplorer" ) local meta = { __index = {} } local evaluableItemMeta = { __index = {} } local promptString = "" local function escapeString( str ) for i = 1, #str do if string.sub( str, i, i ) == "\000" then str = string.sub( str, 1, i-1 ).."(NULL)"..string.sub( str, i+1 ) end end return str end function new( parent, interactive ) local self = { interactive = interactive } setmetatable( self, meta ) local flags = wx.wxTR_HIDE_ROOT + wx.wxTR_LINES_AT_ROOT + wx.wxTR_HAS_BUTTONS if interactive then flags = flags + wx.wxTR_EDIT_LABELS end self.tree = wx.wxTreeCtrl( parent, wx.wxID_ANY, wx.wxDefaultPosition, wx.wxDefaultSize, flags ) self.root = self.tree:AddRoot( "root" ) self.complexValues = {} self.tree:Connect( wx.wxEVT_COMMAND_TREE_ITEM_EXPANDING, function( event ) self:onExpanding_( event ) end ) self.tree:Connect( wx.wxEVT_COMMAND_TREE_ITEM_COLLAPSED, function( event ) self:onCollapsed_( event ) end ) if interactive then self.tree:Connect( wx.wxEVT_COMMAND_TREE_BEGIN_LABEL_EDIT, function( event ) self:onBeginEdit_( event ) end ) self.tree:Connect( wx.wxEVT_COMMAND_TREE_END_LABEL_EDIT, function( event ) self:onEdited_( event ) end ) self.tree:Connect( wx.wxEVT_COMMAND_TREE_KEY_DOWN, function( event ) self:onKeyDown_( event ) end ) self.tree:AppendItem( self.root, promptString ) end return self end function meta.__index:getRoot() return self.tree end function meta.__index:setData( data ) self:releaseHierarchy_( self.root ) assert( next( self.complexValues ) == nil ) --for _, cval in pairs( self.complexValues ) do -- cval:release() --end --self.complexValues = {} self.tree:DeleteChildren( self.root ) if data ~= nil then for _, entry in ipairs( data ) do self:append_( self.root, entry ) end end end function meta.__index:append_( parent, entry ) local value local t = type( entry.value ) local isComplex = false if t == "table" then value = entry.value.short if value ~= nil and (entry.value.type == "string" or entry.value.type == "proxy") then value = escapeString( value ) end if entry.value.id ~= nil then isComplex = true end elseif t == "string" then value = "\""..escapeString( entry.value ).."\"" elseif t == "nil" then value = nil else value = tostring( entry.value ) end local node if value == nil then node = self.tree:AppendItem( parent, entry.name ) else node = self.tree:AppendItem( parent, entry.name.." = "..value ) end if isComplex then self.tree:SetItemHasChildren( node, true ) self.complexValues[node:GetValue()] = entry.value end end function meta.__index:onExpanding_( event ) local item = event:GetItem() local cval = assert( self.complexValues[item:GetValue()] ) local value = cval:get() for _, entry in ipairs( value ) do self:append_( item, entry ) end end function meta.__index:onCollapsed_( event ) local item = event:GetItem() self:releaseHierarchy_( item ) self.tree:DeleteChildren( item ) self.tree:SetItemHasChildren( item, true ) end function meta.__index:releaseHierarchy_( item ) local child = self.tree:GetFirstChild( item ) while child:IsOk() do local cval = self.complexValues[child:GetValue()] if cval ~= nil then cval:release() self.complexValues[child:GetValue()] = nil end self:releaseHierarchy_( child ) child = self.tree:GetNextSibling( child ) end end function meta.__index:refresh() assert( self.interactive ) local exprItem = self.tree:GetFirstChild( self.root ) while exprItem:IsOk() do self:releaseHierarchy_( exprItem ) self.tree:Collapse( exprItem ) self.tree:DeleteChildren( exprItem ) if self.complexValues[exprItem:GetValue()] ~= nil then self.tree:SetItemHasChildren( exprItem, true ) end exprItem = self.tree:GetNextSibling( exprItem ) end for _, cval in pairs( self.complexValues ) do assert( getmetatable( cval ) == evaluableItemMeta ) -- all other values should have been released end end function meta.__index:clear() local item = self.root self:releaseHierarchy_( item ) self.tree:DeleteChildren( item ) end function meta.__index:onBeginEdit_( event ) local item = event:GetItem() local parent = self.tree:GetItemParent( item ) if parent:GetValue() ~= self.root:GetValue() then event:Veto() -- only direct children of root can be edited end end function meta.__index:onEdited_( event ) local item = event:GetItem() assert( self.tree:GetItemParent( item ):GetValue() == self.root:GetValue() ) self:releaseHierarchy_( item ) self.tree:Collapse( item ) self.tree:DeleteChildren( item ) local expr = event:GetLabel() local cval = { evaluate = function() return self.evaluateCallback( expr ) end } setmetatable( cval, evaluableItemMeta ) self.complexValues[item:GetValue()] = cval self.tree:SetItemHasChildren( item, true ) if self.tree:GetLastChild( self.root ):GetValue() == item:GetValue() then self.tree:AppendItem( self.root, promptString ) end self.tree:Expand( item ) end function meta.__index:onKeyDown_( event ) if event:GetKeyCode() == wx.WXK_DELETE then local item = self.tree:GetSelection() if item:IsOk() then local parent = self.tree:GetItemParent( item ) if parent:GetValue() == self.root:GetValue() and item:GetValue() ~= self.tree:GetLastChild( self.root ):GetValue() then self:releaseHierarchy_( item ) self.tree:Delete( item ) end end end end function evaluableItemMeta.__index:get() return self.evaluate() end function evaluableItemMeta.__index:release() -- nothing to do end