Beispiel #1
0
    def __init__(self, tool):
        Panel.__init__(self)
        self.macro_steps = []
        self.current_step = 0
        self._filter_json = None
        self.keys_panel = None
        self.filterOptionsPanel = None
        self.filterSelect = ChoiceButton([],
                                         choose=self.filterChanged,
                                         doNotTranslate=True)
        self.binding_button = Button(
            "",
            action=self.bind_key,
            tooltipText="Click to bind this filter to a key")

        self.filterLabel = Label("Filter:", fg_color=(177, 177, 255, 255))
        self.filterLabel.mouse_down = lambda x: mcplatform.platform_open(
            directories.getFiltersDir())
        self.filterLabel.tooltipText = "Click to open filters folder"

        self.macro_button = Button("Record Macro",
                                   action=self.start_record_macro)
        self.filterSelectRow = Row((self.filterLabel, self.filterSelect,
                                    self.macro_button, self.binding_button))

        self.confirmButton = Button("Filter", action=self.confirm)

        self._recording = False
        self._save_macro = False
        self.tool = tool
        self.selectedName = self.filter_json.get("Last Filter Opened", "")
Beispiel #2
0
    def __init__(self, tool):
        Panel.__init__(self, name='Panel.BrushPanel')
        self.tool = tool
        """
        presets, modeRow and styleRow are always created, no matter
        what brush is selected. styleRow can be disabled by putting disableStyleButton = True
        in the brush file.
        """
        presets = self.createPresetRow()

        self.brushModeButtonLabel = Label("Mode:")
        self.brushModeButton = ChoiceButton(
            sorted([mode for mode in tool.brushModes]),
            width=150,
            choose=self.brushModeChanged,
            doNotTranslate=True,
        )
        modeRow = Row([self.brushModeButtonLabel, self.brushModeButton])

        self.brushStyleButtonLabel = Label("Style:")
        self.brushStyleButton = ValueButton(ref=ItemRef(
            self.tool.options, "Style"),
                                            action=self.tool.swapBrushStyles,
                                            width=150)

        styleRow = Row([self.brushStyleButtonLabel, self.brushStyleButton])
        self.brushModeButton.selectedChoice = self.tool.selectedBrushMode
        optionsColumn = []
        optionsColumn.extend([presets, modeRow])
        if not getattr(tool.brushMode, 'disableStyleButton', False):
            optionsColumn.append(styleRow)
        """
        We're going over all options in the selected brush module, and making
        a field for all of them.
        """
        for r in tool.brushMode.inputs:
            row = []
            for key, value in r.items():
                field = self.createField(key, value)
                row.append(field)
            row = Row(row)
            optionsColumn.append(row)
        if getattr(tool.brushMode, 'addPasteButton', False):
            importButton = Button("Import", action=tool.importPaste)
            importRow = Row([importButton])
            optionsColumn.append(importRow)
        optionsColumn = Column(optionsColumn, spacing=0)
        self.add(optionsColumn)
        self.shrink_wrap()
Beispiel #3
0
    def createPresetRow(self):
        """
        Creates the brush preset widget, called by BrushPanel when creating the panel.
        """
        self.presets = ["Load Preset"]
        self.presets.extend(self.getBrushFileList())
        self.presets.append('Remove Presets')

        self.presetListButton = ChoiceButton(self.presets, width=100, choose=self.presetSelected)
        self.presetListButton.selectedChoice = "Load Preset"
        self.saveButton = Button("Save as Preset", action=self.openSavePresetDialog)

        presetListButtonRow = Row([self.presetListButton])
        saveButtonRow = Row([self.saveButton])
        row = Row([presetListButtonRow, saveButtonRow])
        widget = GLBackground()
        widget.bg_color = (0.8, 0.8, 0.8, 0.8)
        widget.add(row)
        widget.shrink_wrap()
        widget.anchor = "whtr"
        return widget
Beispiel #4
0
    def __init__(self, tool):
        Panel.__init__(self, name='Panel.FilterToolPanel')
        self.macro_steps = []
        self.current_step = 0
        self._filter_json = None
        self.keys_panel = None
        self.filterOptionsPanel = None
        self.filterSelect = ChoiceButton([], choose=self.filterChanged, doNotTranslate=True)
        self.binding_button = Button("", action=self.bind_key,
                                     tooltipText="Click to bind this filter to a key")

        self.filterLabel = Label("Filter:", fg_color=(177, 177, 255, 255))
        self.filterLabel.mouse_down = lambda x: mcplatform.platform_open(directories.getFiltersDir())
        self.filterLabel.tooltipText = "Click to open filters folder"

        self.macro_button = Button("Record Macro", action=self.start_record_macro)
        self.filterSelectRow = Row((self.filterLabel, self.filterSelect,
                                    self.macro_button, self.binding_button))

        self.confirmButton = Button("Filter", action=self.confirm)

        self._recording = False
        self._save_macro = False
        self.tool = tool
        self.selectedName = self.filter_json.get("Last Filter Opened", "")
        
        
        utils = FilterUtils(
                            editor=tool.editor, 
                            materials=self.tool.editor.level.materials,
                            custom_widget=tool.editor.addExternalWidget,
                            resize_selection_box=tool.editor._resize_selection_box
                            )
        utils_module = imp.new_module("filter_utils")
        utils_module = utils
        sys.modules["filter_utils"] = utils_module
Beispiel #5
0
def GeneratorPanel():
    panel = Widget()
    panel.chunkHeight = 64
    panel.grass = True
    panel.simulate = False
    panel.snapshot = False

    jarStorage = MCServerChunkGenerator.getDefaultJarStorage()
    if jarStorage:
        jarStorage.reloadVersions()

    generatorChoice = ChoiceButton(["Minecraft Server", "Flatland"])
    panel.generatorChoice = generatorChoice
    col = [Row((Label("Generator:"), generatorChoice))]
    noVersionsRow = Label(
        "Will automatically download and use the latest version")
    versionContainer = Widget()

    heightinput = IntInputRow("Height: ",
                              ref=AttrRef(panel, "chunkHeight"),
                              min=0,
                              max=255)
    grassinput = CheckBoxLabel("Grass", ref=AttrRef(panel, "grass"))
    flatPanel = Column([heightinput, grassinput], align="l")

    def generatorChoiceChanged():
        serverPanel.visible = generatorChoice.selectedChoice == "Minecraft Server"
        flatPanel.visible = not serverPanel.visible

    generatorChoice.choose = generatorChoiceChanged

    versionChoice = None

    if len(jarStorage.versions):

        def checkForUpdates():
            def _check():
                yield
                jarStorage.downloadCurrentServer(panel.snapshot)
                yield

            showProgress("Checking for server updates...", _check())
            versionChoice.choices = sorted(jarStorage.versions, reverse=True)
            versionChoice.choiceIndex = 0

        versionChoice = ChoiceButton(sorted(jarStorage.versions, reverse=True))
        versionChoice.set_size_for_text(200)
        versionChoiceRow = (Row(
            (Label("Server version:"), versionChoice, Label("or"),
             Button("Check for Updates", action=checkForUpdates))))
        panel.versionChoice = versionChoice
        versionContainer.add(versionChoiceRow)
    else:
        versionContainer.add(noVersionsRow)

    versionContainer.shrink_wrap()

    menu = Menu("Advanced", [("Open Server Storage", "revealStorage"),
                             ("Reveal World Cache", "revealCache"),
                             ("Delete World Cache", "clearCache")])

    def presentMenu():
        i = menu.present(advancedButton.parent, advancedButton.topleft)
        if i != -1:
            (revealStorage, revealCache, clearCache)[i]()

    advancedButton = Button("Advanced...", presentMenu)

    @alertException
    def revealStorage():
        mcplatform.platform_open(jarStorage.cacheDir)

    @alertException
    def revealCache():
        mcplatform.platform_open(MCServerChunkGenerator.worldCacheDir)

    # revealCacheRow = Row((Label("Minecraft Server Storage: "), Button("Open Folder", action=revealCache, tooltipText="Click me to install your own minecraft_server.jar if you have any.")))

    @alertException
    def clearCache():
        MCServerChunkGenerator.clearWorldCache()

    simRow = CheckBoxLabel(
        "Simulate world",
        ref=AttrRef(panel, "simulate"),
        tooltipText=
        "Simulate the world for a few seconds after generating it. Reduces the save file size by processing all of the TileTicks."
    )
    useSnapshotServer = CheckBoxLabel(
        "Use snapshot versions",
        ref=AttrRef(panel, "snapshot"),
        tooltipText="Uses the Latest Snapshot Terrain Generation")

    simRow = Row((simRow, advancedButton), anchor="lrh")
    #deleteCacheRow = Row((Label("Delete Temporary World File Cache?"), Button("Delete Cache!", action=clearCache, tooltipText="Click me if you think your chunks are stale.")))

    serverPanel = Column([useSnapshotServer, versionContainer, simRow],
                         align="l")

    col.append(serverPanel)
    col = Column(col, align="l")
    col.add(flatPanel)
    flatPanel.topleft = serverPanel.topleft
    flatPanel.visible = False
    panel.add(col)

    panel.shrink_wrap()

    def generate(level, arg, useWorldType="DEFAULT"):
        useServer = generatorChoice.selectedChoice == "Minecraft Server"

        if useServer:

            def _createChunks():
                if versionChoice:
                    version = versionChoice.selectedChoice
                else:
                    version = None
                gen = MCServerChunkGenerator(version=version)

                if isinstance(arg, pymclevel.BoundingBox):
                    for i in gen.createLevelIter(level,
                                                 arg,
                                                 simulate=panel.simulate,
                                                 worldType=useWorldType):
                        yield i
                else:
                    for i in gen.generateChunksInLevelIter(
                            level, arg, simulate=panel.simulate):
                        yield i

        else:

            def _createChunks():
                height = panel.chunkHeight
                grass = panel.grass and pymclevel.alphaMaterials.Grass.ID or pymclevel.alphaMaterials.Dirt.ID
                if isinstance(arg, pymclevel.BoundingBox):
                    chunks = list(arg.chunkPositions)
                else:
                    chunks = arg

                if level.dimNo in (-1, 1):
                    maxskylight = 0
                else:
                    maxskylight = 15

                for i, (cx, cz) in enumerate(chunks):

                    yield i, len(chunks)
                    #surface = blockInput.blockInfo

                    #for cx, cz in :
                    try:
                        level.createChunk(cx, cz)
                    except ValueError, e:  # chunk already present
                        print e
                        continue
                    else:
                        ch = level.getChunk(cx, cz)
                        if height > 0:
                            stoneHeight = max(0, height - 5)
                            grassHeight = max(0, height - 1)

                            ch.Blocks[:, :, grassHeight] = grass
                            ch.Blocks[:, :, stoneHeight:
                                      grassHeight] = pymclevel.alphaMaterials.Dirt.ID
                            ch.Blocks[:, :, :
                                      stoneHeight] = pymclevel.alphaMaterials.Stone.ID

                            ch.Blocks[:, :,
                                      0] = pymclevel.alphaMaterials.Bedrock.ID
                            ch.SkyLight[:, :, height:] = maxskylight
                            if maxskylight:
                                ch.HeightMap[:] = height

                        else:
                            ch.SkyLight[:] = maxskylight

                        ch.needsLighting = False
                        ch.dirty = True

        return _createChunks()
Beispiel #6
0
 def __init__(self, value=None):
     Widget.__init__(self)
     self.choiceButton = ChoiceButton(self.choices)
     self.add(self.choiceButton)
     self.shrink_wrap()
Beispiel #7
0
def GeneratorPanel():
    panel = Widget()
    panel.chunkHeight = 64
    panel.grass = True
    panel.simulate = False
    panel.snapshot = False

    jarStorage = MCServerChunkGenerator.getDefaultJarStorage()
    if jarStorage:
        jarStorage.reloadVersions()

    generatorChoice = ChoiceButton(["Minecraft Server", "Flatland"])
    panel.generatorChoice = generatorChoice
    col = [Row((Label("Generator:"), generatorChoice))]
    noVersionsRow = Label("Will automatically download and use the latest version")
    versionContainer = Widget()

    heightinput = IntInputRow("Height: ", ref=AttrRef(panel, "chunkHeight"), min=0, max=255)
    grassinput = CheckBoxLabel("Grass", ref=AttrRef(panel, "grass"))
    flatPanel = Column([heightinput, grassinput], align="l")

    def generatorChoiceChanged():
        serverPanel.visible = generatorChoice.selectedChoice == "Minecraft Server"
        flatPanel.visible = not serverPanel.visible

    generatorChoice.choose = generatorChoiceChanged

    versionChoice = None

    if len(jarStorage.versions):
        def checkForUpdates():
            def _check():
                yield
                jarStorage.downloadCurrentServer(panel.snapshot)
                yield

            showProgress("Checking for server updates...", _check())
            versionChoice.choices = sorted(jarStorage.versions, reverse=True)
            versionChoice.choiceIndex = 0

        versionChoice = ChoiceButton(sorted(jarStorage.versions, reverse=True))
        versionChoice.set_size_for_text(200)
        versionChoiceRow = (Row((
            Label("Server version:"),
            versionChoice,
            Label("or"),
            Button("Check for Updates", action=checkForUpdates))))
        panel.versionChoice = versionChoice
        versionContainer.add(versionChoiceRow)
    else:
        versionContainer.add(noVersionsRow)

    versionContainer.shrink_wrap()

    menu = Menu("Advanced", [
        ("Open Server Storage", "revealStorage"),
        ("Reveal World Cache", "revealCache"),
        ("Delete World Cache", "clearCache")
    ])

    def presentMenu():
        i = menu.present(advancedButton.parent, advancedButton.topleft)
        if i != -1:
            (revealStorage, revealCache, clearCache)[i]()

    advancedButton = Button("Advanced...", presentMenu)

    @alertException
    def revealStorage():
        mcplatform.platform_open(jarStorage.cacheDir)

    @alertException
    def revealCache():
        mcplatform.platform_open(MCServerChunkGenerator.worldCacheDir)

    # revealCacheRow = Row((Label("Minecraft Server Storage: "), Button("Open Folder", action=revealCache, tooltipText="Click me to install your own minecraft_server.jar if you have any.")))

    @alertException
    def clearCache():
        MCServerChunkGenerator.clearWorldCache()

    simRow = CheckBoxLabel("Simulate world", ref=AttrRef(panel, "simulate"),
                           tooltipText="Simulate the world for a few seconds after generating it. Reduces the save file size by processing all of the TileTicks.")
    useSnapshotServer = CheckBoxLabel("Use snapshot versions", ref=AttrRef(panel, "snapshot"),
                                      tooltipText="Uses the Latest Snapshot Terrain Generation")

    simRow = Row((simRow, advancedButton), anchor="lrh")
    #deleteCacheRow = Row((Label("Delete Temporary World File Cache?"), Button("Delete Cache!", action=clearCache, tooltipText="Click me if you think your chunks are stale.")))

    serverPanel = Column([useSnapshotServer, versionContainer, simRow], align="l")

    col.append(serverPanel)
    col = Column(col, align="l")
    col.add(flatPanel)
    flatPanel.topleft = serverPanel.topleft
    flatPanel.visible = False
    panel.add(col)

    panel.shrink_wrap()

    def generate(level, arg, useWorldType="DEFAULT"):
        useServer = generatorChoice.selectedChoice == "Minecraft Server"

        if useServer:
            def _createChunks():
                if versionChoice:
                    version = versionChoice.selectedChoice
                else:
                    version = None
                gen = MCServerChunkGenerator(version=version)

                if isinstance(arg, pymclevel.BoundingBox):
                    for i in gen.createLevelIter(level, arg, simulate=panel.simulate, worldType=useWorldType):
                        yield i
                else:
                    for i in gen.generateChunksInLevelIter(level, arg, simulate=panel.simulate):
                        yield i

        else:
            def _createChunks():
                height = panel.chunkHeight
                grass = panel.grass and pymclevel.alphaMaterials.Grass.ID or pymclevel.alphaMaterials.Dirt.ID
                if isinstance(arg, pymclevel.BoundingBox):
                    chunks = list(arg.chunkPositions)
                else:
                    chunks = arg

                if level.dimNo in (-1, 1):
                    maxskylight = 0
                else:
                    maxskylight = 15

                for i, (cx, cz) in enumerate(chunks):

                    yield i, len(chunks)
                    #surface = blockInput.blockInfo

                    #for cx, cz in :
                    try:
                        level.createChunk(cx, cz)
                    except ValueError, e:  # chunk already present
                        print e
                        continue
                    else:
                        ch = level.getChunk(cx, cz)
                        if height > 0:
                            stoneHeight = max(0, height - 5)
                            grassHeight = max(0, height - 1)

                            ch.Blocks[:, :, grassHeight] = grass
                            ch.Blocks[:, :, stoneHeight:grassHeight] = pymclevel.alphaMaterials.Dirt.ID
                            ch.Blocks[:, :, :stoneHeight] = pymclevel.alphaMaterials.Stone.ID

                            ch.Blocks[:, :, 0] = pymclevel.alphaMaterials.Bedrock.ID
                            ch.SkyLight[:, :, height:] = maxskylight
                            if maxskylight:
                                ch.HeightMap[:] = height

                        else:
                            ch.SkyLight[:] = maxskylight

                        ch.needsLighting = False
                        ch.dirty = True

        return _createChunks()
Beispiel #8
0
    def reload(self):
        for i in list(self.subwidgets):
            self.remove(i)

        tool = self.tool

        # Display "No filter modules found" if there are no filters
        if len(tool.filterModules) is 0:
            self.add(Label("No filter modules found!"))
            self.shrink_wrap()
            return

        names_list = sorted(
            [n for n in tool.filterNames if not n.startswith("[")])

        # We get a list of names like ["[foo] bar", "[test] thing"]
        # The to sort on is created by splitting on "[": "[foo", " bar" and then
        # removing the first char: "foo", "bar"

        subfolder_names_list = sorted(
            [n for n in tool.filterNames if n.startswith("[")],
            key=lambda x: x.split("]")[0][1:])

        names_list.extend(subfolder_names_list)
        names_list.extend(
            [macro for macro in self.filter_json["Macros"].keys()])

        if self.selectedName is None or self.selectedName not in names_list:
            self.selectedName = names_list[0]

        # Remove any keybindings that don't have a filter
        for (i, j) in config.config.items("Filter Keys"):
            if i == "__name__":
                continue
            if not any([i == m.lower() for m in names_list]):
                config.config.remove_option("Filter Keys", i)

        self.filterSelect.choices = names_list

        name = self.selectedName.lower()
        names = [k for (k, v) in config.config.items("Filter Keys")]
        btn_name = config.config.get("Filter Keys",
                                     name) if name in names else "*"
        self.binding_button.set_text(btn_name)

        self.filterOptionsPanel = None
        while self.filterOptionsPanel is None:
            module = self.tool.filterModules.get(self.selectedName, None)
            if module is not None:
                try:
                    self.filterOptionsPanel = FilterModuleOptions(self.tool,
                                                                  module,
                                                                  _parent=self)
                except Exception as e:
                    alert(
                        _("Error creating filter inputs for {0}: {1}").format(
                            module, e))
                    traceback.print_exc()
                    self.tool.filterModules.pop(self.selectedName)
                    self.selectedName = tool.filterNames[0]

                if len(tool.filterNames) == 0:
                    raise ValueError("No filters loaded!")
                if not self._recording:
                    self.confirmButton.set_text("Filter")
            else:  # We verified it was an existing macro already
                macro_data = self.filter_json["Macros"][self.selectedName]
                self.filterOptionsPanel = MacroModuleOptions(macro_data)
                self.confirmButton.set_text("Run Macro")

        # This has to be recreated every time in case a macro has a longer name then everything else.
        self.filterSelect = ChoiceButton(names_list,
                                         choose=self.filterChanged,
                                         doNotTranslate=True)
        self.filterSelect.selectedChoice = self.selectedName
        self.filterSelectRow = Row((self.filterLabel, self.filterSelect,
                                    self.macro_button, self.binding_button))

        self.add(
            Column((self.filterSelectRow, self.filterOptionsPanel,
                    self.confirmButton)))

        self.shrink_wrap()

        if self.parent:
            height = self.parent.mainViewport.height - self.parent.toolbar.height
            self.centery = height / 2 + self.parent.subwidgets[0].height

        if self.selectedName in self.tool.savedOptions:
            self.filterOptionsPanel.options = self.tool.savedOptions[
                self.selectedName]
Beispiel #9
0
    def makeTabPage(self, tool, inputs, trn=None, **kwargs):
        page = Widget(**kwargs)
        page.is_gl_container = True
        rows = []
        cols = []
        max_height = tool.editor.mainViewport.height - tool.editor.toolbar.height - tool.editor.subwidgets[0].height -\
            self._parent.filterSelectRow.height - self._parent.confirmButton.height - self.pages.tab_height

        page.optionDict = {}
        page.tool = tool
        title = "Tab"

        for optionSpec in inputs:
            optionName = optionSpec[0]
            optionType = optionSpec[1]
            if trn is not None:
                n = trn._(optionName)
            else:
                n = optionName
            if n == optionName:
                oName = _(optionName)
            else:
                oName = n
            if isinstance(optionType, tuple):
                if isinstance(optionType[0], (int, long, float)):
                    if len(optionType) == 3:
                        val, min, max = optionType
                        increment = 0.1
                    elif len(optionType) == 2:
                        min, max = optionType
                        val = min
                        increment = 0.1
                    else:
                        val, min, max, increment = optionType

                    rows.append(
                        addNumField(page, optionName, oName, val, min, max,
                                    increment))

                if isinstance(optionType[0], (str, unicode)):
                    isChoiceButton = False

                    if optionType[0] == "string":
                        kwds = []
                        wid = None
                        val = None
                        for keyword in optionType:
                            if isinstance(
                                    keyword,
                                (str, unicode)) and keyword != "string":
                                kwds.append(keyword)
                        for keyword in kwds:
                            splitWord = keyword.split('=')
                            if len(splitWord) > 1:
                                v = None

                                try:
                                    v = int(splitWord[1])
                                except ValueError:
                                    pass

                                key = splitWord[0]
                                if v is not None:
                                    if key == "width":
                                        wid = v
                                else:
                                    if key == "value":
                                        val = "=".join(splitWord[1:])

                        if val is None:
                            val = ""
                        if wid is None:
                            wid = 200

                        field = TextFieldWrapped(value=val, width=wid)
                        page.optionDict[optionName] = AttrRef(field, 'value')

                        row = Row((Label(oName, doNotTranslate=True), field))
                        rows.append(row)
                    else:
                        isChoiceButton = True

                    if isChoiceButton:
                        if trn is not None:
                            __ = trn._
                        else:
                            __ = _
                        choices = [__("%s" % a) for a in optionType]
                        choiceButton = ChoiceButton(choices,
                                                    doNotTranslate=True)
                        page.optionDict[optionName] = AttrRef(
                            choiceButton, 'selectedChoice')

                        rows.append(
                            Row((Label(oName,
                                       doNotTranslate=True), choiceButton)))

            elif isinstance(optionType, bool):
                cbox = CheckBox(value=optionType)
                page.optionDict[optionName] = AttrRef(cbox, 'value')

                row = Row((Label(oName, doNotTranslate=True), cbox))
                rows.append(row)

            elif isinstance(optionType, (int, float)):
                rows.append(addNumField(self, optionName, oName, optionType))

            elif optionType == "blocktype" or isinstance(
                    optionType, pymclevel.materials.Block):
                blockButton = BlockButton(tool.editor.level.materials)
                if isinstance(optionType, pymclevel.materials.Block):
                    blockButton.blockInfo = optionType

                row = Column((Label(oName, doNotTranslate=True), blockButton))
                page.optionDict[optionName] = AttrRef(blockButton, 'blockInfo')

                rows.append(row)
            elif optionType == "label":
                rows.append(wrapped_label(oName, 50, doNotTranslate=True))

            elif optionType == "string":
                inp = None
                # not sure how to pull values from filters,
                # but leaves it open for the future. Use this variable to set field width.
                if inp is not None:
                    size = inp
                else:
                    size = 200
                field = TextFieldWrapped(value="")
                row = TextInputRow(oName,
                                   ref=AttrRef(field, 'value'),
                                   width=size,
                                   doNotTranslate=True)
                page.optionDict[optionName] = AttrRef(field, 'value')
                rows.append(row)

            elif optionType == "title":
                title = oName

            elif type(
                    optionType) == list and optionType[0].lower() == "nbttree":
                kw = {'close_text': None, 'load_text': None}
                if len(optionType) >= 3:

                    def close():
                        self.pages.show_page(self.pages.pages[optionType[2]])

                    kw['close_action'] = close
                    kw['close_text'] = "Go Back"
                if len(optionType) >= 4:
                    if optionType[3]:
                        kw['load_text'] = optionType[3]
                if hasattr(self.module, 'nbt_ok_action'):
                    kw['ok_action'] = getattr(self.module, 'nbt_ok_action')
                self.nbttree = NBTExplorerToolPanel(self.tool.editor,
                                                    nbtObject=optionType[1],
                                                    height=max_height,
                                                    no_header=True,
                                                    copy_data=False,
                                                    **kw)
                self.module.set_tree(self.nbttree.tree)
                for meth_name in dir(self.module):
                    if meth_name.startswith('nbttree_'):
                        setattr(self.nbttree.tree.treeRow,
                                meth_name.split('nbttree_')[-1],
                                getattr(self.module, meth_name))
                        # elif meth_name.startswith('nbt_'):
                        #     setattr(self.nbttree, meth_name.split('nbt_')[-1], getattr(self.module, meth_name))
                page.optionDict[optionName] = AttrRef(self, 'rebuildTabPage')
                rows.append(self.nbttree)
                self.nbttree.page = len(self.pgs)

            else:
                raise ValueError(("Unknown option type", optionType))

        height = sum(r.height for r in rows) + (len(rows) - 1) * self.spacing

        if height > max_height:
            h = 0
            for i, r in enumerate(rows):
                h += r.height
                if h > height / 2:
                    if rows[:i]:
                        cols.append(Column(rows[:i], spacing=0))
                    rows = rows[i:]
                    break

        if len(rows):
            cols.append(Column(rows, spacing=0))

        if len(cols):
            page.add(Row(cols, spacing=0))
        page.shrink_wrap()

        return title, page, page._rect