From 11cb91fb8e9398625e5b2fea152ab81b7894e24b Mon Sep 17 00:00:00 2001 From: Swann Martinez Date: Wed, 13 Mar 2019 17:02:53 +0100 Subject: [PATCH] feat(rcf): improve UI --- net_operators.py | 200 +++++++++++++++++++++++++---------------------- net_ui.py | 120 +++++++++++++++++++++------- 2 files changed, 197 insertions(+), 123 deletions(-) diff --git a/net_operators.py b/net_operators.py index 06a12de..ea8ada3 100644 --- a/net_operators.py +++ b/net_operators.py @@ -1,3 +1,4 @@ +from bpy_extras import view3d_utils import bpy from . import net_components from . import net_ui @@ -19,7 +20,7 @@ server = None context = None -COLOR_TABLE = [(1,0,0,1),(0,1,0,1),(0,0,1,1)] +COLOR_TABLE = [(1, 0, 0, 1), (0, 1, 0, 1), (0, 0, 1, 1)] NATIVE_TYPES = ( bpy.types.IntProperty, bpy.types.FloatProperty, @@ -27,10 +28,6 @@ NATIVE_TYPES = ( bpy.types.StringProperty, ) -import mathutils -import gpu -from gpu_extras.batch import batch_for_shader -from bpy_extras import view3d_utils def view3d_find(): for area in bpy.context.window.screen.areas: @@ -40,68 +37,71 @@ def view3d_find(): for region in area.regions: if region.type == 'WINDOW': return area, region, rv3d - + break - + return None, None, None -def get_target(region, rv3d,coord): + +def get_target(region, rv3d, coord): view_vector = view3d_utils.region_2d_to_vector_3d(region, rv3d, coord) ray_origin = view3d_utils.region_2d_to_origin_3d(region, rv3d, coord) - target = ray_origin +view_vector - return [target.x,target.y,target.z] + target = ray_origin + view_vector + return [target.x, target.y, target.z] + def get_client_view_rect(): area, region, rv3d = view3d_find() - v1 = [0,0,0] - v2 = [0,0,0] - v3 = [0,0,0] - v4 = [0,0,0] + v1 = [0, 0, 0] + v2 = [0, 0, 0] + v3 = [0, 0, 0] + v4 = [0, 0, 0] - width = region.width height = region.height - v1 = get_target(region,rv3d,(0,0)) - v3 = get_target(region,rv3d,(0,height)) - v2 = get_target(region,rv3d,(width,height)) - v4 = get_target(region,rv3d,(width,0)) + v1 = get_target(region, rv3d, (0, 0)) + v3 = get_target(region, rv3d, (0, height)) + v2 = get_target(region, rv3d, (width, height)) + v4 = get_target(region, rv3d, (width, 0)) coords = (v1, v2, v3, v4) indices = ( - (1, 3), (2, 1), (3, 0),(2,0) + (1, 3), (2, 1), (3, 0), (2, 0) ) return coords + def get_client_view_rect(): area, region, rv3d = view3d_find() - v1 = [0,0,0] - v2 = [0,0,0] - v3 = [0,0,0] - v4 = [0,0,0] + v1 = [0, 0, 0] + v2 = [0, 0, 0] + v3 = [0, 0, 0] + v4 = [0, 0, 0] - width = region.width height = region.height - v1 = get_target(region,rv3d,(0,0)) - v3 = get_target(region,rv3d,(0,height)) - v2 = get_target(region,rv3d,(width,height)) - v4 = get_target(region,rv3d,(width,0)) + v1 = get_target(region, rv3d, (0, 0)) + v3 = get_target(region, rv3d, (0, height)) + v2 = get_target(region, rv3d, (width, height)) + v4 = get_target(region, rv3d, (width, 0)) coords = (v1, v2, v3, v4) indices = ( - (1, 3), (2, 1), (3, 0),(2,0) + (1, 3), (2, 1), (3, 0), (2, 0) ) return coords + def get_client_2d(coords): area, region, rv3d = view3d_find() - return view3d_utils.location_3d_to_region_2d(region,rv3d,coords) - + return view3d_utils.location_3d_to_region_2d(region, rv3d, coords) + + class UpdateClientView(bpy.types.Operator): bl_idname = "session.update_client" bl_label = "update client" @@ -118,15 +118,14 @@ class UpdateClientView(bpy.types.Operator): def poll(cls, context): return True - def invoke(self, context,event): - self.coords = get_client_view_rect() + def invoke(self, context, event): + self.coords = get_client_view_rect() context.window_manager.modal_handler_add(self) self.register_handlers(context) return {"RUNNING_MODAL"} - def modal(self, context, event): if context.area: context.area.tag_redraw() @@ -134,33 +133,33 @@ class UpdateClientView(bpy.types.Operator): if event.type in {"TIMER"}: current_coords = get_client_view_rect() # Update local view - if current_coords != self.coords: + if current_coords != self.coords: global client - self.coords= current_coords + self.coords = current_coords key = "net/clients/{}".format(client.id.decode()) - + client.push_update(key, 'client', current_coords) print("update") - if event.type in {"ESC"}: - self.unregister_handlers(context) - return {"CANCELLED"} - + self.unregister_handlers(context) + return {"CANCELLED"} return {"PASS_THROUGH"} - def register_handlers(self,context): - self.update_event = context.window_manager.event_timer_add(0.1, window=context.window) + def register_handlers(self, context): + self.update_event = context.window_manager.event_timer_add( + 0.1, window=context.window) - def unregister_handlers(self,context): + def unregister_handlers(self, context): context.window_manager.event_timer_remove(self.draw_event) - + def finish(self): self.unregister_handlers() return {"FINISHED"} + def on_scene_evalutation(scene): # TODO: viewer representation # TODO: Live update only selected object @@ -268,9 +267,11 @@ def refresh_window(): bpy.ops.wm.redraw_timer(type='DRAW_WIN_SWAP', iterations=1) + def init_scene(msg): pass + def update_scene(msg): global client @@ -294,13 +295,15 @@ def update_scene(msg): else: logger.debug('no need to update scene on our own') + def update_ui(msg): """ Update collaborative UI elements """ pass -recv_callbacks = [update_scene,update_ui] + +recv_callbacks = [update_scene, update_ui] post_init_callbacks = [refresh_window] @@ -328,8 +331,8 @@ class session_join(bpy.types.Operator): client_factory = rna_translation.RNAFactory() print("{}".format(client_factory.__class__.__name__)) client = net_components.Client( - id=username, - on_recv=recv_callbacks, + id=username, + on_recv=recv_callbacks, on_post_init=post_init_callbacks, factory=client_factory) # time.sleep(1) @@ -432,7 +435,7 @@ class session_stop(bpy.types.Operator): net_settings = context.scene.session_settings bpy.app.timers.unregister(observer) - + if server: server.stop() del server @@ -446,7 +449,6 @@ class session_stop(bpy.types.Operator): else: logger.debug("No server/client running.") - return {"FINISHED"} @@ -457,50 +459,59 @@ class session_settings(bpy.types.PropertyGroup): port = bpy.props.IntProperty(name="5555") buffer = bpy.props.StringProperty(name="None") is_running = bpy.props.BoolProperty(name="is_running", default=False) + hide_users = bpy.props.BoolProperty(name="is_running", default=False) + hide_settings = bpy.props.BoolProperty(name="hide_settings", default=False) + hide_properties = bpy.props.BoolProperty(name="hide_properties", default=True) update_frequency = bpy.props.FloatProperty( name="update_frequency", default=0.008) + class session_draw_clients(bpy.types.Operator): bl_idname = "session.draw" bl_label = "draw clients" bl_description = "Description that shows in blender tooltips" bl_options = {"REGISTER"} - position = bpy.props.FloatVectorProperty(default=(0,0,0)) + position = bpy.props.FloatVectorProperty(default=(0, 0, 0)) + def __init__(self): super().__init__() - self.draw_items = [] + self.draw_items = [] self.draw3d_handle = None self.draw2d_handle = None - self.draw_event = None - self.coords = None - + self.draw_event = None + self.coords = None @classmethod def poll(cls, context): return True - def invoke(self, context,event): - # - self.coords = get_client_view_rect() + def invoke(self, context, event): + # + self.coords = get_client_view_rect() self.create_batch() self.register_handlers(context) context.window_manager.modal_handler_add(self) return {"RUNNING_MODAL"} - def register_handlers(self,context): - self.draw3d_handle = bpy.types.SpaceView3D.draw_handler_add(self.draw3d_callback, (), 'WINDOW', 'POST_VIEW') - self.draw2d_handle = bpy.types.SpaceView3D.draw_handler_add(self.draw2d_callback, (), 'WINDOW', 'POST_PIXEL') + def register_handlers(self, context): + self.draw3d_handle = bpy.types.SpaceView3D.draw_handler_add( + self.draw3d_callback, (), 'WINDOW', 'POST_VIEW') + self.draw2d_handle = bpy.types.SpaceView3D.draw_handler_add( + self.draw2d_callback, (), 'WINDOW', 'POST_PIXEL') - self.draw_event = context.window_manager.event_timer_add(0.1, window=context.window) + self.draw_event = context.window_manager.event_timer_add( + 0.1, window=context.window) - def unregister_handlers(self,context): - if self.draw_event and self.draw3d_handle: - context.window_manager.event_timer_remove(self.draw_event) - bpy.types.SpaceView3D.draw_handler_remove(self.draw3d_handle,"WINDOW") - bpy.types.SpaceView3D.draw_handler_remove(self.draw2d_handle,"WINDOW") + def unregister_handlers(self, context): + if self.draw_event and self.draw3d_handle and self.draw2d_handle: + context.window_manager.event_timer_remove(self.draw_event) + bpy.types.SpaceView3D.draw_handler_remove( + self.draw3d_handle, "WINDOW") + bpy.types.SpaceView3D.draw_handler_remove( + self.draw2d_handle, "WINDOW") self.draw_items.clear() self.draw3d_handle = None @@ -511,48 +522,47 @@ class session_draw_clients(bpy.types.Operator): global client index = 0 for key, values in client.property_map.items(): - - if values.mtype == "client" and values.id != client.id: - - indices = ( - (1, 3), (2, 1), (3, 0),(2,0) - ) - shader = gpu.shader.from_builtin('3D_UNIFORM_COLOR') - batch = batch_for_shader(shader, 'LINES', {"pos": values.body}, indices=indices) + if values.mtype == "client" and values.id != client.id: + indices = ( + (1, 3), (2, 1), (3, 0), (2, 0) + ) - self.draw_items.append((shader,batch, (values.body[1],values.id.decode()),COLOR_TABLE[index])) + shader = gpu.shader.from_builtin('3D_UNIFORM_COLOR') + batch = batch_for_shader( + shader, 'LINES', {"pos": values.body}, indices=indices) - index+=1 + self.draw_items.append( + (shader, batch, (values.body[1], values.id.decode()), COLOR_TABLE[index])) + + index += 1 def draw3d_callback(self): - + bgl.glLineWidth(3) - for shader,batch,font,color in self.draw_items: + for shader, batch, font, color in self.draw_items: shader.bind() shader.uniform_float("color", color) batch.draw(shader) - - def draw2d_callback(self): - for shader,batch,font,color in self.draw_items: - coords = get_client_2d(font[0]) - + for shader, batch, font, color in self.draw_items: + coords = get_client_2d(font[0]) + try: blf.position(0, coords[0], coords[1]+10, 0) blf.size(0, 10, 72) - blf.color(0,color[0],color[1],color[2],color[3]) + blf.color(0, color[0], color[1], color[2], color[3]) blf.draw(0, font[1]) - + except: pass def modal(self, context, event): if context.area: context.area.tag_redraw() - + if not context.scene.session_settings.is_running: self.finish(context) @@ -561,22 +571,22 @@ class session_draw_clients(bpy.types.Operator): if client: # Local view update current_coords = get_client_view_rect() - if current_coords != self.coords: - self.coords= current_coords + if current_coords != self.coords: + self.coords = current_coords key = "net/clients/{}".format(client.id.decode()) - + client.push_update(key, 'client', current_coords) - + # Draw clients if len(client.property_map) > 0: self.unregister_handlers(context) self.create_batch() - + self.register_handlers(context) - + return {"PASS_THROUGH"} - def finish(self,context): + def finish(self, context): self.unregister_handlers(context) return {"FINISHED"} diff --git a/net_ui.py b/net_ui.py index bab0b97..d4f88c1 100644 --- a/net_ui.py +++ b/net_ui.py @@ -3,21 +3,22 @@ from . import net_components from . import net_operators -class SessionPanel(bpy.types.Panel): +class SessionSettingsPanel(bpy.types.Panel): """Creates a Panel in the scene context of the properties editor""" - bl_label = "bl network" - bl_idname = "SCENE_PT_layout" + bl_label = "NET settings" + bl_idname = "SCENE_PT_SessionSettings" bl_space_type = 'PROPERTIES' bl_region_type = 'WINDOW' bl_context = "scene" def draw_header(self, context): - net_settings = context.scene.session_settings + pass + # net_settings = context.scene.session_settings - if net_settings.is_running: - self.layout.label(text="",icon='HIDE_OFF') - else: - self.layout.label(text="",icon='HIDE_ON') + # if net_settings.is_running: + # self.layout.label(text="",icon='HIDE_OFF') + # else: + # self.layout.label(text="",icon='HIDE_ON') # self.layout.label(text="Offline") def draw(self, context): @@ -31,26 +32,11 @@ class SessionPanel(bpy.types.Panel): if net_operators.client: row.label(text="Net frequency:") row.prop(net_settings,"update_frequency",text="") - row = layout.row(align=True) - row.prop(net_settings,"buffer", text="") - row.operator("session.add_prop", text="",icon="ADD").property_path = net_settings.buffer row = layout.row() - # Debug area + - row = layout.row() - area_msg = row.box() - if len(net_operators.client.property_map) > 0: - for key,values in net_operators.client.property_map.items(): - item_box = area_msg.box() - detail_item_box = item_box.row() - # detail_item_box = item_box.row() - detail_item_box.label(text="{} ({}) ".format(key, values.mtype, values.id.decode())) - detail_item_box.operator("session.remove_prop",text="",icon="X").property_path = key - else: - area_msg.label(text="Empty") - row = layout.row() - row.operator("session.stop") + row.operator("session.stop", text="exit session") else: row = layout.row() @@ -61,10 +47,88 @@ class SessionPanel(bpy.types.Panel): row.operator("session.create") row = layout.row() - # row.operator("session.draw") - # row.operator("session.update_client") + +class SessionUsersPanel(bpy.types.Panel): + """Creates a Panel in the scene context of the properties editor""" + bl_label = "NET users" + bl_idname = "SCENE_PT_SessionUsers" + bl_space_type = 'PROPERTIES' + bl_region_type = 'WINDOW' + bl_context = "scene" + + @classmethod + def poll(cls, context): + return net_operators.client + + def draw(self, context): + layout = self.layout + + net_settings = context.scene.session_settings + scene = context.scene + # Create a simple row. + row = layout.row() + + if net_operators.client: + if len(net_operators.client.property_map) > 0: + for key,values in net_operators.client.property_map.items(): + if 'client' in key: + info = "" + item_box = row.box() + detail_item_box = item_box.row() + + if values.id == net_operators.client.id: + info = "(self)" + # detail_item_box = item_box.row() + detail_item_box.label(text="{} {}".format(values.id.decode(),info)) + row = layout.row() + else: + row.label(text="Empty") + + row = layout.row() + + + +class SessionPropertiesPanel(bpy.types.Panel): + """Creates a Panel in the scene context of the properties editor""" + bl_label = "NET properties" + bl_idname = "SCENE_PT_layout" + bl_space_type = 'PROPERTIES' + bl_region_type = 'WINDOW' + bl_context = "scene" + + @classmethod + def poll(cls, context): + return net_operators.client + + def draw(self, context): + layout = self.layout + + net_settings = context.scene.session_settings + scene = context.scene + # Create a simple row. + row = layout.row() + + if net_operators.client: + row = layout.row(align=True) + row.prop(net_settings,"buffer", text="") + row.operator("session.add_prop", text="",icon="ADD").property_path = net_settings.buffer + row = layout.row() + # Property area + area_msg = row.box() + if len(net_operators.client.property_map) > 0: + for key,values in net_operators.client.property_map.items(): + item_box = area_msg.box() + detail_item_box = item_box.row() + # detail_item_box = item_box.row() + detail_item_box.label(text="{} ({}) ".format(key, values.mtype, values.id.decode())) + detail_item_box.operator("session.remove_prop",text="",icon="X").property_path = key + else: + area_msg.label(text="Empty") + classes = ( - SessionPanel, + SessionSettingsPanel, + SessionUsersPanel, + SessionPropertiesPanel, )