Dockable Layout #4042
ljilekor
started this conversation in
Ideas / Feature Requests
Dockable Layout
#4042
Replies: 2 comments
-
Vue3 GoldenLayout (Vue2 also available) Another Vue component DockingLayout No dependencies DockView and many others... |
Beta Was this translation helpful? Give feedback.
0 replies
-
I tried implementing GoldenLayout in NiceGui. Can anyone help with this please? from nicegui import ui
from nicegui.element import Element
import json
from typing import Dict, Any, Callable, List, Optional
from nicegui import events
import uuid
class GoldenLayout(Element):
def __init__(self, config: Optional[Dict[str, Any]] = None, on_event: Optional[Callable] = None, **kwargs):
super().__init__(tag='div', **kwargs)
self.config = config or {"content": []}
self.on_event = on_event
self._event_handlers: Dict[str, List[Callable]] = {}
self.layout_id = f'goldenlayout-{self.id}'
self.style('width: 100%; height: 600px; display: block;')
self.is_initialized = False
self.on('mounted', self.init_layout)
self.component_callbacks = {}
print(f'GoldenLayout component {self.id} created')
def init_layout(self,e):
print(f"init_layout called for {self.id}, is_initialized {self.is_initialized}")
if self.is_initialized:
print(f'skipping init {self.id} since already initialized')
return
self.is_initialized = True
ui.add_head_html(f"""
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/golden-layout/1.5.9/css/goldenlayout-base.css">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/golden-layout/1.5.9/css/goldenlayout-dark-theme.css">
<script src="https://cdnjs.cloudflare.com/ajax/libs/golden-layout/1.5.9/goldenlayout.min.js"></script>
""")
self.run_method("init_layout_js",self.config,self.layout_id, self.id)
def add_event_handler(self, event_name: str, handler: Callable):
"""
Adds an event handler for the specified GoldenLayout event.
Args:
event_name (str): The name of the GoldenLayout event to listen to (e.g., 'itemCreated', 'stateChanged').
handler (Callable): The callback function to be executed when the event occurs.
"""
if event_name not in self._event_handlers:
self._event_handlers[event_name] = []
self._event_handlers[event_name].append(handler)
self.run_method("add_event_handler_js",event_name,self.layout_id, self.id)
def handle_event(self,event):
event_name = event.args['event_name']
print(f'handling event {event_name} in {self.id} with data {event.args}')
if event_name in self._event_handlers:
for handler in self._event_handlers[event_name]:
handler(event)
def _get_props(self):
return {"on_event": self.handle_event }
def get_layout_config(self) -> Dict[str,Any]:
return self.run_method("get_layout_config_js",self.layout_id)
def set_layout_config(self, config: Dict[str, Any]):
print(f'set_layout_config called for {self.id}')
self.config = config
self.run_method("set_layout_config_js", config, self.layout_id)
self.update()
def register_component_callback(self, callback: Callable):
"""
Registers a callback function to handle component creation events in GoldenLayout.
Args:
callback (Callable): A callback function that takes the container, component name, and component state as arguments.
"""
self.component_callbacks[self.id] = callback
self.run_method("register_component_callback_js",self.id)
@staticmethod
def init_layout_js(config: Dict[str, Any],layout_id: str, element_id: str):
return f"""
console.log('init_layout_js called for {element_id}')
const container = document.getElementById('{element_id}');
container.style.display = 'block'
const layout = new GoldenLayout( {json.dumps(config)},container);
layout.id = "{layout_id}";
layout.init();
window.goldenLayouts = window.goldenLayouts || {{}};
window.goldenLayouts["{layout_id}"] = layout;
const registerComponentCallback = window.registerComponentCallback_{element_id}
layout.on('itemCreated', function(item){{
console.log('itemCreated event in js ',item);
if(item.type === "component" && registerComponentCallback)
registerComponentCallback(item.container, item.config.componentName, item.config.componentState, item.id);
}})
"""
@staticmethod
def add_event_handler_js(event_name:str, layout_id:str,element_id:str):
return f"""
console.log('add_event_handler_js called for {element_id} event {event_name}')
const layout = window.goldenLayouts["{layout_id}"];
layout.on( '{event_name}', (event) => {{
let eventData = {{'event_name': '{event_name}'}};
if(event)
eventData['data'] = JSON.parse(JSON.stringify(event));
else
eventData['data'] = null;
console.log('golden event {event_name}:', eventData)
element = document.getElementById('{element_id}')
element.dispatchEvent(new CustomEvent('vue_event', {{
detail: {{
args: eventData
}}
}}))
}});
"""
@staticmethod
def get_layout_config_js(layout_id: str):
return f"""
const layout = window.goldenLayouts["{layout_id}"];
return layout.toConfig();
"""
@staticmethod
def set_layout_config_js(config: Dict[str,Any],layout_id: str):
return f"""
console.log('set_layout_config_js called for {layout_id}')
const layout = window.goldenLayouts["{layout_id}"];
layout.loadLayout( {json.dumps(config)} );
"""
@staticmethod
def register_component_callback_js(element_id:str):
return f"""
window.registerComponentCallback_{element_id} = function (container,componentName, componentState, componentId){{
console.log('register_component_callback_js',container,componentName,componentState, componentId);
const div = document.createElement('div')
div.setAttribute("id", componentId)
div.style.width = '100%';
div.style.height = '100%';
container.getElement().append(div)
container.getElement().attr("element_id",'{element_id}');
const element = document.getElementById('{element_id}');
const eventData = {{ 'container': div, 'componentName': componentName, 'componentState':componentState, "element_id": '{element_id}', 'componentId': componentId }};
element.dispatchEvent(new CustomEvent('vue_event', {{
detail: {{
args: eventData
}}
}}))
}}
"""
def generate_id():
return str(uuid.uuid4())
config = {
"settings": {
"hasHeaders": True,
"constrainDragToContainer": True,
"reorderEnabled": True,
"selectionEnabled": True,
},
"content": [
{
"type": "row",
"id": generate_id(),
"content": [
{
"type": "component",
"componentName": "testComponent",
"id": generate_id(),
"componentState": {"text": "this is a test"}
}
]
}
]
}
def handle_item_created(e):
print('item created', e.args)
def handle_state_changed(e):
print('state changed', e.args)
def handle_selection_changed(e):
print('selection changed', e.args)
def create_component(container,componentName, componentState, element_id, componentId):
print(f"create_component called for {componentName} {componentId}")
if componentName == "testComponent":
with ui.element("div", container=container) as div_container:
div_container.style("width: 100%; height: 100%; display: block;")
ui.label(componentState['text']).style("background-color:red; width: 100%; height: 100%; display: block;")
elif componentName == "secondComponent":
with ui.element("div", container=container) as div_container:
div_container.style("width: 100%; height: 100%; display: block;")
ui.label(componentState['text']).style("background-color:blue; width: 100%; height: 100%; display: block;")
elif componentName == "newComponent":
with ui.element("div", container=container) as div_container:
div_container.style("width: 100%; height: 100%; display: block;")
ui.label(componentState['text']).style("background-color:green; width: 100%; height: 100%; display: block;")
else:
with ui.element("div", container=container) as div_container:
div_container.style("width: 100%; height: 100%; display: block;")
ui.label("unknown component", container=container)
with ui.column() as main:
golden_layout = GoldenLayout(config = config)
golden_layout.add_event_handler('itemCreated',handle_item_created)
golden_layout.add_event_handler('stateChanged', handle_state_changed)
golden_layout.add_event_handler('selectionChanged',handle_selection_changed)
ui.button("Get Layout", on_click = lambda : print(golden_layout.get_layout_config()))
def update_layout():
new_config = {
"settings": {
"hasHeaders": True,
"constrainDragToContainer": True,
"reorderEnabled": True,
"selectionEnabled": True,
},
"content": [
{
"type": "row",
"id": generate_id(),
"content": [
{
"type": "component",
"id": generate_id(),
"componentName": "newComponent",
"componentState": {"text": "this is the new component"}
}
]
}
]
}
golden_layout.set_layout_config(new_config)
ui.button("Set Layout", on_click = update_layout )
def component_created(event):
component = event.args
container = component['container']
component_name = component['componentName']
component_state = component['componentState']
element_id = component['element_id']
component_id = component['componentId']
create_component(container,component_name,component_state, element_id, component_id)
golden_layout.register_component_callback(component_created)
ui.run() |
Beta Was this translation helpful? Give feedback.
0 replies
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
-
Implementing GoldenLayout in Nicegui would be an amazing and meaningful enhancement.
try it out !
Beta Was this translation helpful? Give feedback.
All reactions