diff --git a/layout-files-examples/2-3-grid.json b/layout-files-examples/2-3-grid.json new file mode 100644 index 00000000..5266aa36 --- /dev/null +++ b/layout-files-examples/2-3-grid.json @@ -0,0 +1,30 @@ +{ + "tab1": [ + { + "children": [ + { + "command": "bash" + }, + { + "command": "bash" + }, + { + "command": "bash" + } + ] + }, + { + "children": [ + { + "command": "bash" + }, + { + "command": "bash" + }, + { + "command": "bash" + } + ] + } + ] +} diff --git a/layout-files-examples/2-columns.json b/layout-files-examples/2-columns.json new file mode 100644 index 00000000..8030d45a --- /dev/null +++ b/layout-files-examples/2-columns.json @@ -0,0 +1,11 @@ +{ + "vertical": false, + "tab1": [ + { + "command": "bash" + }, + { + "command": "bash" + } + ] +} diff --git a/layout-files-examples/3-rows.json b/layout-files-examples/3-rows.json new file mode 100644 index 00000000..560857ab --- /dev/null +++ b/layout-files-examples/3-rows.json @@ -0,0 +1,13 @@ +{ + "tab1": [ + { + "command": "bash" + }, + { + "command": "bash" + }, + { + "command": "bash" + } + ] +} diff --git a/layout-files-examples/3-tabs-2-rows.json b/layout-files-examples/3-tabs-2-rows.json new file mode 100644 index 00000000..0dc7f9bd --- /dev/null +++ b/layout-files-examples/3-tabs-2-rows.json @@ -0,0 +1,26 @@ +{ + "tab1": [ + { + "command": "bash" + }, + { + "command": "bash" + } + ], + "tab2": [ + { + "command": "bash" + }, + { + "command": "bash" + } + ], + "tab3": [ + { + "command": "bash" + }, + { + "command": "bash" + } + ] +} diff --git a/layout-files-examples/3-tabs-3-columns.json b/layout-files-examples/3-tabs-3-columns.json new file mode 100644 index 00000000..ae9e103c --- /dev/null +++ b/layout-files-examples/3-tabs-3-columns.json @@ -0,0 +1,36 @@ +{ + "vertical": false, + "tab1": [ + { + "command": "bash" + }, + { + "command": "bash" + }, + { + "command": "bash" + } + ], + "tab2": [ + { + "command": "bash" + }, + { + "command": "bash" + }, + { + "command": "bash" + } + ], + "tab3": [ + { + "command": "bash" + }, + { + "command": "bash" + }, + { + "command": "bash" + } + ] +} diff --git a/layout-files-examples/4-4-grid.json b/layout-files-examples/4-4-grid.json new file mode 100644 index 00000000..5266aa36 --- /dev/null +++ b/layout-files-examples/4-4-grid.json @@ -0,0 +1,30 @@ +{ + "tab1": [ + { + "children": [ + { + "command": "bash" + }, + { + "command": "bash" + }, + { + "command": "bash" + } + ] + }, + { + "children": [ + { + "command": "bash" + }, + { + "command": "bash" + }, + { + "command": "bash" + } + ] + } + ] +} diff --git a/terminatorlib/layoutfile.py b/terminatorlib/layoutfile.py new file mode 100644 index 00000000..ff25933b --- /dev/null +++ b/terminatorlib/layoutfile.py @@ -0,0 +1,124 @@ +from .util import dbg, err +from os import path +import sys +import json +import traceback + +class LayoutFile(object): + def build_single_tab_layout(self, layoutjson, vertical): + dbg ('Budiling a single tab layout from json: %s ' % layoutjson) + + result = { + 'root': { + 'type': 'Window' + } + } + + if len(layoutjson) == 1: + self.build_terminal_layout(layoutjson, result, 'root', 0) + else: + self.build_container_layout(layoutjson, result, 'root', 0, vertical) + + return result + + def build_multi_tab_layout(self, layoutjson, vertical): + dbg ('Budiling multi tabs layout from json: %s ' % layoutjson) + + tabs = { + 'type': 'Notebook', + 'parent': 'root', + 'labels': [] + } + + result = { + 'root': { + 'type': 'Window' + }, + 'tabs': tabs + } + + counter = 0 + + for tab in layoutjson: + tabs['labels'].append(tab) + if len(layoutjson[tab]) == 1: + self.build_terminal_layout(layoutjson[tab][0], result, 'tabs', counter) + else: + self.build_container_layout(layoutjson[tab], result, 'tabs', counter, vertical) + counter += 1 + + return result + + def build_terminal_layout(self, layoutjson, children, parent, order): + dbg ('Building a terminal from json: %s' % layoutjson) + + children[parent + "." + str(order)] = { + 'type': 'Terminal', + 'order': order, + 'parent': parent, + 'command': layoutjson['command'] + } + + def build_container_layout(self, layoutjson, children, parent, order, vertical): + dbg ('Building %s layout from json: %s' % ("vertical" if vertical else "horizental", layoutjson)) + + counter = 0 + actualparent = parent + + for pane in layoutjson: + if counter < (len(layoutjson) - 1): + containername = parent + "." + str(order) + "." + str(counter) + ratio = (100 / (len(layoutjson) - counter)) / 100 + children[containername] = { + 'type': 'VPaned' if vertical else 'HPaned', + 'order': order + counter, + 'ratio': round(ratio, 2), + 'parent': actualparent + } + actualparent = containername + + if 'children' in pane: + if len(pane['children']) == 1: + self.build_terminal_layout(pane, pane['children'], containername, counter) + else: + self.build_container_layout(pane['children'], children, containername, counter, False if vertical else True) + else: + self.build_terminal_layout(pane, children, containername, counter) + + counter += 1 + + def get_layout_file(self, layoutname): + if (not path.exists(layoutname)): + return None + + dbg('Loading layout from a file: %s' % layoutname) + + layoutjson = None + + try: + with open(layoutname) as json_file: + layoutjson = json.load(json_file) + except Exception as ex: + err('Error loading layout file %s (%s)' % (layoutname, ex)) + return None + + try: + vertical = True + if "vertical" in layoutjson: + vertical = layoutjson["vertical"] + del layoutjson["vertical"] + + result = None + + if len(layoutjson) == 1: + firstitem = next(iter(layoutjson.values())) + result = self.build_single_tab_layout(firstitem, vertical) + else: + result = self.build_multi_tab_layout(layoutjson, vertical) + + dbg('Json layout is: %s' % result) + return result + except Exception as ex: + err('Error building a layout from file %s (%s)' % (layoutname, ex)) + traceback.print_exc(ex) + return None diff --git a/terminatorlib/terminator.py b/terminatorlib/terminator.py index c634f98e..1ba97332 100644 --- a/terminatorlib/terminator.py +++ b/terminatorlib/terminator.py @@ -16,6 +16,7 @@ from .keybindings import Keybindings from .util import dbg, err, enumerate_descendants from .factory import Factory from .version import APP_NAME, APP_VERSION +from .layoutfile import LayoutFile try: from gi.repository import GdkX11 @@ -227,10 +228,13 @@ class Terminator(Borg): layout = copy.deepcopy(self.config.layout_get_config(layoutname)) if not layout: - # User specified a non-existent layout. default to one Terminal - err('layout %s not defined' % layout) - self.new_window() - return + layoutfile = LayoutFile() + layout = layoutfile.get_layout_file(layoutname) + if not layout: + # User specified a non-existent layout. default to one Terminal + err('layout %s not defined' % layout) + self.new_window() + return # Wind the flat objects into a hierarchy hierarchy = {}