Merge branch '218-new-ui-ux-implementation' into 'develop'
New UI/UX implementation See merge request slumber/multi-user!140
@ -61,6 +61,7 @@ def register():
|
||||
from . import operators
|
||||
from . import handlers
|
||||
from . import ui
|
||||
from . import icons
|
||||
from . import preferences
|
||||
from . import addon_updater_ops
|
||||
|
||||
@ -70,6 +71,7 @@ def register():
|
||||
operators.register()
|
||||
handlers.register()
|
||||
ui.register()
|
||||
icons.register()
|
||||
except ModuleNotFoundError as e:
|
||||
raise Exception(module_error_msg)
|
||||
logging.error(module_error_msg)
|
||||
@ -83,7 +85,9 @@ def register():
|
||||
type=preferences.SessionUser
|
||||
)
|
||||
bpy.types.WindowManager.user_index = bpy.props.IntProperty()
|
||||
bpy.types.WindowManager.server_index = bpy.props.IntProperty()
|
||||
bpy.types.TOPBAR_MT_file_import.append(operators.menu_func_import)
|
||||
bpy.types.TOPBAR_MT_file_export.append(operators.menu_func_export)
|
||||
|
||||
|
||||
def unregister():
|
||||
@ -91,14 +95,17 @@ def unregister():
|
||||
from . import operators
|
||||
from . import handlers
|
||||
from . import ui
|
||||
from . import icons
|
||||
from . import preferences
|
||||
from . import addon_updater_ops
|
||||
|
||||
bpy.types.TOPBAR_MT_file_import.remove(operators.menu_func_import)
|
||||
bpy.types.TOPBAR_MT_file_export.remove(operators.menu_func_export)
|
||||
|
||||
presence.unregister()
|
||||
addon_updater_ops.unregister()
|
||||
ui.unregister()
|
||||
icons.unregister()
|
||||
handlers.unregister()
|
||||
operators.unregister()
|
||||
preferences.unregister()
|
||||
@ -107,5 +114,6 @@ def unregister():
|
||||
del bpy.types.ID.uuid
|
||||
del bpy.types.WindowManager.online_users
|
||||
del bpy.types.WindowManager.user_index
|
||||
del bpy.types.WindowManager.server_index
|
||||
|
||||
environment.unregister()
|
||||
|
45
multi_user/icons/__init__.py
Normal file
@ -0,0 +1,45 @@
|
||||
# ##### BEGIN GPL LICENSE BLOCK #####
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
#
|
||||
# ##### END GPL LICENSE BLOCK #####
|
||||
|
||||
import bpy
|
||||
import os
|
||||
|
||||
from pathlib import Path
|
||||
import bpy.utils.previews
|
||||
|
||||
def register():
|
||||
|
||||
global icons_col
|
||||
|
||||
pcoll = bpy.utils.previews.new()
|
||||
icons_dir = os.path.join(os.path.dirname(__file__), ".")
|
||||
for png in Path(icons_dir).rglob("*.png"):
|
||||
pcoll.load(png.stem, str(png), "IMAGE")
|
||||
|
||||
icons_col = pcoll
|
||||
|
||||
|
||||
def unregister():
|
||||
|
||||
global icons_col
|
||||
|
||||
try:
|
||||
bpy.utils.previews.remove(icons_col)
|
||||
except Exception:
|
||||
pass
|
||||
|
||||
icons_col = None
|
BIN
multi_user/icons/repository_merge.png
Normal file
After Width: | Height: | Size: 6.5 KiB |
BIN
multi_user/icons/repository_push.png
Normal file
After Width: | Height: | Size: 4.2 KiB |
BIN
multi_user/icons/server_offline.png
Normal file
After Width: | Height: | Size: 6.7 KiB |
BIN
multi_user/icons/server_online.png
Normal file
After Width: | Height: | Size: 9.5 KiB |
BIN
multi_user/icons/session_status_offline.png
Normal file
After Width: | Height: | Size: 9.4 KiB |
BIN
multi_user/icons/session_status_online.png
Normal file
After Width: | Height: | Size: 13 KiB |
BIN
multi_user/icons/session_status_waiting.png
Normal file
After Width: | Height: | Size: 11 KiB |
@ -1 +1 @@
|
||||
Subproject commit 15dc5c62c07a3e0025a82d87022f5073c019e7e9
|
||||
Subproject commit d283d39e9cac6a5a8dcedf049220c764063ac8a9
|
@ -20,6 +20,7 @@ import asyncio
|
||||
import copy
|
||||
import gzip
|
||||
import logging
|
||||
from multi_user.preferences import ServerPreset
|
||||
import os
|
||||
import queue
|
||||
import random
|
||||
@ -28,6 +29,7 @@ import string
|
||||
import sys
|
||||
import time
|
||||
import traceback
|
||||
from uuid import uuid4
|
||||
from datetime import datetime
|
||||
from operator import itemgetter
|
||||
from pathlib import Path
|
||||
@ -56,7 +58,7 @@ from replication.repository import Repository
|
||||
|
||||
from . import bl_types, environment, shared_data, timers, ui, utils
|
||||
from .handlers import on_scene_update, sanitize_deps_graph
|
||||
from .presence import SessionStatusWidget, renderer, view3d_find
|
||||
from .presence import SessionStatusWidget, renderer, view3d_find, refresh_sidebar_view
|
||||
from .timers import registry
|
||||
|
||||
background_execution_queue = Queue()
|
||||
@ -81,7 +83,6 @@ def session_callback(name):
|
||||
def initialize_session():
|
||||
"""Session connection init hander
|
||||
"""
|
||||
settings = utils.get_preferences()
|
||||
runtime_settings = bpy.context.window_manager.session
|
||||
|
||||
if not runtime_settings.is_host:
|
||||
@ -108,7 +109,6 @@ def initialize_session():
|
||||
for d in deleyables:
|
||||
d.register()
|
||||
|
||||
|
||||
# Step 5: Clearing history
|
||||
utils.flush_history()
|
||||
|
||||
@ -142,16 +142,143 @@ def on_connection_end(reason="none"):
|
||||
if isinstance(handler, logging.FileHandler):
|
||||
logger.removeHandler(handler)
|
||||
if reason != "user":
|
||||
bpy.ops.session.notify('INVOKE_DEFAULT', message=f"Disconnected from session. Reason: {reason}. ")
|
||||
bpy.ops.session.notify('INVOKE_DEFAULT', message=f"Disconnected from session. Reason: {reason}. ") #TODO: change op session.notify to add ui + change reason (in replication->interface)
|
||||
|
||||
def setup_logging():
|
||||
""" Session setup logging (host/connect)
|
||||
"""
|
||||
settings = utils.get_preferences()
|
||||
logger = logging.getLogger()
|
||||
if len(logger.handlers) == 1:
|
||||
formatter = logging.Formatter(
|
||||
fmt='%(asctime)s CLIENT %(levelname)-8s %(message)s',
|
||||
datefmt='%H:%M:%S'
|
||||
)
|
||||
|
||||
start_time = datetime.now().strftime('%Y_%m_%d_%H-%M-%S')
|
||||
log_directory = os.path.join(
|
||||
settings.cache_directory,
|
||||
f"multiuser_{start_time}.log")
|
||||
|
||||
os.makedirs(settings.cache_directory, exist_ok=True)
|
||||
|
||||
handler = logging.FileHandler(log_directory, mode='w')
|
||||
logger.addHandler(handler)
|
||||
|
||||
for handler in logger.handlers:
|
||||
if isinstance(handler, logging.NullHandler):
|
||||
continue
|
||||
|
||||
handler.setFormatter(formatter)
|
||||
|
||||
def setup_timer():
|
||||
""" Session setup timer (host/connect)
|
||||
"""
|
||||
settings = utils.get_preferences()
|
||||
deleyables.append(timers.ClientUpdate())
|
||||
deleyables.append(timers.DynamicRightSelectTimer())
|
||||
deleyables.append(timers.ApplyTimer(timeout=settings.depsgraph_update_rate))
|
||||
|
||||
session_update = timers.SessionStatusUpdate()
|
||||
session_user_sync = timers.SessionUserSync()
|
||||
session_background_executor = timers.MainThreadExecutor(execution_queue=background_execution_queue)
|
||||
session_listen = timers.SessionListenTimer(timeout=0.001)
|
||||
|
||||
session_listen.register()
|
||||
session_update.register()
|
||||
session_user_sync.register()
|
||||
session_background_executor.register()
|
||||
|
||||
deleyables.append(session_background_executor)
|
||||
deleyables.append(session_update)
|
||||
deleyables.append(session_user_sync)
|
||||
deleyables.append(session_listen)
|
||||
deleyables.append(timers.AnnotationUpdates())
|
||||
|
||||
def get_active_server_preset(context):
|
||||
active_index = context.window_manager.server_index
|
||||
server_presets = utils.get_preferences().server_preset
|
||||
|
||||
active_index = active_index if active_index <= len(server_presets)-1 else 0
|
||||
|
||||
return server_presets[active_index]
|
||||
|
||||
# OPERATORS
|
||||
class SessionStartOperator(bpy.types.Operator):
|
||||
bl_idname = "session.start"
|
||||
bl_label = "start"
|
||||
class SessionConnectOperator(bpy.types.Operator):
|
||||
bl_idname = "session.connect"
|
||||
bl_label = "connect"
|
||||
bl_description = "connect to a net server"
|
||||
|
||||
host: bpy.props.BoolProperty(default=False)
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
return True
|
||||
|
||||
def execute(self, context):
|
||||
global deleyables
|
||||
|
||||
settings = utils.get_preferences()
|
||||
users = bpy.data.window_managers['WinMan'].online_users
|
||||
active_server = get_active_server_preset()
|
||||
admin_pass = active_server.admin_password if active_server.use_admin_password else None
|
||||
server_pass = active_server.server_password if active_server.use_server_password else None
|
||||
|
||||
users.clear()
|
||||
deleyables.clear()
|
||||
|
||||
setup_logging()
|
||||
|
||||
bpy_protocol = bl_types.get_data_translation_protocol()
|
||||
|
||||
# Check if supported_datablocks are up to date before starting the
|
||||
# the session
|
||||
for dcc_type_id in bpy_protocol.implementations.keys():
|
||||
if dcc_type_id not in settings.supported_datablocks:
|
||||
logging.info(f"{dcc_type_id} not found, \
|
||||
regenerate type settings...")
|
||||
settings.generate_supported_types()
|
||||
|
||||
|
||||
if bpy.app.version[1] >= 91:
|
||||
python_binary_path = sys.executable
|
||||
else:
|
||||
python_binary_path = bpy.app.binary_path_python
|
||||
|
||||
repo = Repository(
|
||||
rdp=bpy_protocol,
|
||||
username=settings.username)
|
||||
|
||||
# Join a session
|
||||
if not active_server.use_admin_password:
|
||||
utils.clean_scene()
|
||||
|
||||
try:
|
||||
porcelain.remote_add(
|
||||
repo,
|
||||
'origin',
|
||||
active_server.ip,
|
||||
active_server.port,
|
||||
server_password=server_pass,
|
||||
admin_password=admin_pass)
|
||||
session.connect(
|
||||
repository= repo,
|
||||
timeout=settings.connection_timeout,
|
||||
server_password=server_pass,
|
||||
admin_password=admin_pass
|
||||
)
|
||||
except Exception as e:
|
||||
self.report({'ERROR'}, str(e))
|
||||
logging.error(str(e))
|
||||
|
||||
# Background client updates service
|
||||
setup_timer()
|
||||
|
||||
return {"FINISHED"}
|
||||
|
||||
|
||||
class SessionHostOperator(bpy.types.Operator):
|
||||
bl_idname = "session.host"
|
||||
bl_label = "host"
|
||||
bl_description = "host server"
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
@ -163,33 +290,13 @@ class SessionStartOperator(bpy.types.Operator):
|
||||
settings = utils.get_preferences()
|
||||
runtime_settings = context.window_manager.session
|
||||
users = bpy.data.window_managers['WinMan'].online_users
|
||||
admin_pass = settings.password
|
||||
admin_pass = settings.host_admin_password if settings.host_use_admin_password else None
|
||||
server_pass = settings.host_server_password if settings.host_use_server_password else None
|
||||
|
||||
users.clear()
|
||||
deleyables.clear()
|
||||
|
||||
logger = logging.getLogger()
|
||||
if len(logger.handlers) == 1:
|
||||
formatter = logging.Formatter(
|
||||
fmt='%(asctime)s CLIENT %(levelname)-8s %(message)s',
|
||||
datefmt='%H:%M:%S'
|
||||
)
|
||||
|
||||
start_time = datetime.now().strftime('%Y_%m_%d_%H-%M-%S')
|
||||
log_directory = os.path.join(
|
||||
settings.cache_directory,
|
||||
f"multiuser_{start_time}.log")
|
||||
|
||||
os.makedirs(settings.cache_directory, exist_ok=True)
|
||||
|
||||
handler = logging.FileHandler(log_directory, mode='w')
|
||||
logger.addHandler(handler)
|
||||
|
||||
for handler in logger.handlers:
|
||||
if isinstance(handler, logging.NullHandler):
|
||||
continue
|
||||
|
||||
handler.setFormatter(formatter)
|
||||
setup_logging()
|
||||
|
||||
bpy_protocol = bl_types.get_data_translation_protocol()
|
||||
|
||||
@ -212,80 +319,38 @@ class SessionStartOperator(bpy.types.Operator):
|
||||
username=settings.username)
|
||||
|
||||
# Host a session
|
||||
if self.host:
|
||||
if settings.init_method == 'EMPTY':
|
||||
utils.clean_scene()
|
||||
if settings.init_method == 'EMPTY':
|
||||
utils.clean_scene()
|
||||
|
||||
runtime_settings.is_host = True
|
||||
runtime_settings.internet_ip = environment.get_ip()
|
||||
try:
|
||||
# Init repository
|
||||
for scene in bpy.data.scenes:
|
||||
porcelain.add(repo, scene)
|
||||
|
||||
try:
|
||||
# Init repository
|
||||
for scene in bpy.data.scenes:
|
||||
porcelain.add(repo, scene)
|
||||
|
||||
porcelain.remote_add(
|
||||
repo,
|
||||
'origin',
|
||||
'127.0.0.1',
|
||||
settings.port,
|
||||
admin_password=admin_pass)
|
||||
session.host(
|
||||
repository= repo,
|
||||
remote='origin',
|
||||
timeout=settings.connection_timeout,
|
||||
password=admin_pass,
|
||||
cache_directory=settings.cache_directory,
|
||||
server_log_level=logging.getLevelName(
|
||||
logging.getLogger().level),
|
||||
)
|
||||
except Exception as e:
|
||||
self.report({'ERROR'}, repr(e))
|
||||
logging.error(f"Error: {e}")
|
||||
traceback.print_exc()
|
||||
# Join a session
|
||||
else:
|
||||
if not runtime_settings.admin:
|
||||
utils.clean_scene()
|
||||
# regular session, no password needed
|
||||
admin_pass = None
|
||||
|
||||
try:
|
||||
porcelain.remote_add(
|
||||
repo,
|
||||
'origin',
|
||||
settings.ip,
|
||||
settings.port,
|
||||
admin_password=admin_pass)
|
||||
session.connect(
|
||||
repository= repo,
|
||||
timeout=settings.connection_timeout,
|
||||
password=admin_pass
|
||||
)
|
||||
except Exception as e:
|
||||
self.report({'ERROR'}, str(e))
|
||||
logging.error(str(e))
|
||||
porcelain.remote_add(
|
||||
repo,
|
||||
'origin',
|
||||
'127.0.0.1',
|
||||
settings.host_port,
|
||||
server_password=server_pass,
|
||||
admin_password=admin_pass)
|
||||
session.host(
|
||||
repository= repo,
|
||||
remote='origin',
|
||||
timeout=settings.connection_timeout,
|
||||
server_password=server_pass,
|
||||
admin_password=admin_pass,
|
||||
cache_directory=settings.cache_directory,
|
||||
server_log_level=logging.getLevelName(
|
||||
logging.getLogger().level),
|
||||
)
|
||||
except Exception as e:
|
||||
self.report({'ERROR'}, repr(e))
|
||||
logging.error(f"Error: {e}")
|
||||
traceback.print_exc()
|
||||
|
||||
# Background client updates service
|
||||
deleyables.append(timers.ClientUpdate())
|
||||
deleyables.append(timers.DynamicRightSelectTimer())
|
||||
deleyables.append(timers.ApplyTimer(timeout=settings.depsgraph_update_rate))
|
||||
|
||||
session_update = timers.SessionStatusUpdate()
|
||||
session_user_sync = timers.SessionUserSync()
|
||||
session_background_executor = timers.MainThreadExecutor(execution_queue=background_execution_queue)
|
||||
session_listen = timers.SessionListenTimer(timeout=0.001)
|
||||
|
||||
session_listen.register()
|
||||
session_update.register()
|
||||
session_user_sync.register()
|
||||
session_background_executor.register()
|
||||
|
||||
deleyables.append(session_background_executor)
|
||||
deleyables.append(session_update)
|
||||
deleyables.append(session_user_sync)
|
||||
deleyables.append(session_listen)
|
||||
deleyables.append(timers.AnnotationUpdates())
|
||||
setup_timer()
|
||||
|
||||
return {"FINISHED"}
|
||||
|
||||
@ -783,7 +848,6 @@ class SessionStopAutoSaveOperator(bpy.types.Operator):
|
||||
|
||||
return {'FINISHED'}
|
||||
|
||||
|
||||
class SessionLoadSaveOperator(bpy.types.Operator, ImportHelper):
|
||||
bl_idname = "session.load"
|
||||
bl_label = "Load session save"
|
||||
@ -831,12 +895,90 @@ class SessionLoadSaveOperator(bpy.types.Operator, ImportHelper):
|
||||
class SessionPresetServerAdd(bpy.types.Operator):
|
||||
"""Add a server to the server list preset"""
|
||||
bl_idname = "session.preset_server_add"
|
||||
bl_label = "add server preset"
|
||||
bl_description = "add the current server to the server preset list"
|
||||
bl_label = "Add server preset"
|
||||
bl_description = "add a server to the server preset list"
|
||||
bl_options = {"REGISTER"}
|
||||
|
||||
name : bpy.props.StringProperty(default="server_preset")
|
||||
|
||||
server_name: bpy.props.StringProperty(default="")
|
||||
ip: bpy.props.StringProperty(default="127.0.0.1")
|
||||
port: bpy.props.IntProperty(default=5555)
|
||||
use_server_password: bpy.props.BoolProperty(default=False)
|
||||
server_password: bpy.props.StringProperty(default="", subtype = "PASSWORD")
|
||||
use_admin_password: bpy.props.BoolProperty(default=False)
|
||||
admin_password: bpy.props.StringProperty(default="", subtype = "PASSWORD")
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
return True
|
||||
|
||||
def invoke(self, context, event):
|
||||
self.server_name = ""
|
||||
self.ip = "127.0.0.1"
|
||||
self.port = 5555
|
||||
self.use_server_password = False
|
||||
self.server_password = ""
|
||||
self.use_admin_password = False
|
||||
self.admin_password = ""
|
||||
|
||||
assert(context)
|
||||
return context.window_manager.invoke_props_dialog(self)
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
|
||||
row = layout.row()
|
||||
row.prop(self, "server_name", text="Server name")
|
||||
row = layout.row(align = True)
|
||||
row.prop(self, "ip", text="IP+port")
|
||||
row.prop(self, "port", text="")
|
||||
row = layout.row()
|
||||
col = row.column()
|
||||
col.prop(self, "use_server_password", text="Server password:")
|
||||
col = row.column()
|
||||
col.enabled = True if self.use_server_password else False
|
||||
col.prop(self, "server_password", text="")
|
||||
row = layout.row()
|
||||
col = row.column()
|
||||
col.prop(self, "use_admin_password", text="Admin password:")
|
||||
col = row.column()
|
||||
col.enabled = True if self.use_admin_password else False
|
||||
col.prop(self, "admin_password", text="")
|
||||
|
||||
def execute(self, context):
|
||||
assert(context)
|
||||
|
||||
settings = utils.get_preferences()
|
||||
existing_preset = settings.get_server_preset(self.server_name)
|
||||
|
||||
new_server = existing_preset if existing_preset else settings.server_preset.add()
|
||||
new_server.name = str(uuid4())
|
||||
new_server.server_name = self.server_name
|
||||
new_server.ip = self.ip
|
||||
new_server.port = self.port
|
||||
new_server.use_server_password = self.use_server_password
|
||||
new_server.server_password = self.server_password
|
||||
new_server.use_admin_password = self.use_admin_password
|
||||
new_server.admin_password = self.admin_password
|
||||
|
||||
refresh_sidebar_view()
|
||||
|
||||
if new_server == existing_preset :
|
||||
self.report({'INFO'}, "Server '" + self.server_name + "' edited")
|
||||
else :
|
||||
self.report({'INFO'}, "New '" + self.server_name + "' server preset")
|
||||
|
||||
return {'FINISHED'}
|
||||
|
||||
|
||||
class SessionPresetServerEdit(bpy.types.Operator): # TODO : use preset, not settings
|
||||
"""Edit a server to the server list preset"""
|
||||
bl_idname = "session.preset_server_edit"
|
||||
bl_label = "Edit server preset"
|
||||
bl_description = "Edit a server from the server preset list"
|
||||
bl_options = {"REGISTER"}
|
||||
|
||||
target_server_name: bpy.props.StringProperty(default="None")
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
return True
|
||||
@ -847,35 +989,39 @@ class SessionPresetServerAdd(bpy.types.Operator):
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
|
||||
col = layout.column()
|
||||
settings = utils.get_preferences()
|
||||
settings_active_server = settings.server_preset.get(self.target_server_name)
|
||||
|
||||
col.prop(settings, "server_name", text="server name")
|
||||
row = layout.row()
|
||||
row.prop(settings_active_server, "server_name", text="Server name")
|
||||
row = layout.row(align = True)
|
||||
row.prop(settings_active_server, "ip", text="IP+port")
|
||||
row.prop(settings_active_server, "port", text="")
|
||||
row = layout.row()
|
||||
col = row.column()
|
||||
col.prop(settings_active_server, "use_server_password", text="Server password:")
|
||||
col = row.column()
|
||||
col.enabled = True if settings_active_server.use_server_password else False
|
||||
col.prop(settings_active_server, "server_password", text="")
|
||||
row = layout.row()
|
||||
col = row.column()
|
||||
col.prop(settings_active_server, "use_admin_password", text="Admin password:")
|
||||
col = row.column()
|
||||
col.enabled = True if settings_active_server.use_admin_password else False
|
||||
col.prop(settings_active_server, "admin_password", text="")
|
||||
|
||||
def execute(self, context):
|
||||
assert(context)
|
||||
|
||||
settings = utils.get_preferences()
|
||||
settings_active_server = settings.server_preset.get(self.target_server_name)
|
||||
|
||||
existing_preset = settings.server_preset.get(settings.server_name)
|
||||
refresh_sidebar_view()
|
||||
|
||||
new_server = existing_preset if existing_preset else settings.server_preset.add()
|
||||
new_server.name = settings.server_name
|
||||
new_server.server_ip = settings.ip
|
||||
new_server.server_port = settings.port
|
||||
new_server.server_password = settings.password
|
||||
|
||||
settings.server_preset_interface = settings.server_name
|
||||
|
||||
if new_server == existing_preset :
|
||||
self.report({'INFO'}, "Server '" + settings.server_name + "' override")
|
||||
else :
|
||||
self.report({'INFO'}, "New '" + settings.server_name + "' server preset")
|
||||
self.report({'INFO'}, "Server '" + settings_active_server.server_name + "' edited")
|
||||
|
||||
return {'FINISHED'}
|
||||
|
||||
|
||||
class SessionPresetServerRemove(bpy.types.Operator):
|
||||
"""Remove a server to the server list preset"""
|
||||
bl_idname = "session.preset_server_remove"
|
||||
@ -883,6 +1029,8 @@ class SessionPresetServerRemove(bpy.types.Operator):
|
||||
bl_description = "remove the current server from the server preset list"
|
||||
bl_options = {"REGISTER"}
|
||||
|
||||
target_server_name: bpy.props.StringProperty(default="None")
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
return True
|
||||
@ -891,19 +1039,77 @@ class SessionPresetServerRemove(bpy.types.Operator):
|
||||
assert(context)
|
||||
|
||||
settings = utils.get_preferences()
|
||||
|
||||
settings.server_preset.remove(settings.server_preset.find(settings.server_preset_interface))
|
||||
settings.server_preset.remove(settings.server_preset.find(self.target_server_name))
|
||||
|
||||
return {'FINISHED'}
|
||||
|
||||
class RefreshServerStatus(bpy.types.Operator):
|
||||
bl_idname = "session.get_info"
|
||||
bl_label = "Get session info"
|
||||
bl_description = "Get session info"
|
||||
|
||||
target_server: bpy.props.StringProperty(default="127.0.0.1:5555")
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
return (session.state != STATE_ACTIVE)
|
||||
|
||||
def execute(self, context):
|
||||
settings = utils.get_preferences()
|
||||
|
||||
for server in settings.server_preset:
|
||||
infos = porcelain.request_session_info(f"{server.ip}:{server.port}", timeout=settings.ping_timeout)
|
||||
server.is_online = True if infos else False
|
||||
if server.is_online:
|
||||
server.is_private = infos.get("private")
|
||||
|
||||
return {'FINISHED'}
|
||||
|
||||
class GetDoc(bpy.types.Operator):
|
||||
"""Get the documentation of the addon"""
|
||||
bl_idname = "doc.get"
|
||||
bl_label = "Multi-user's doc"
|
||||
bl_description = "Go to the doc of the addon"
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
return True
|
||||
|
||||
def execute(self, context):
|
||||
assert(context)
|
||||
bpy.ops.wm.url_open(url="https://slumber.gitlab.io/multi-user/index.html")
|
||||
|
||||
return {'FINISHED'}
|
||||
|
||||
class FirstLaunch(bpy.types.Operator):
|
||||
"""First time lauching the addon"""
|
||||
bl_idname = "firstlaunch.verify"
|
||||
bl_label = "First launch"
|
||||
bl_description = "First time lauching the addon"
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
return True
|
||||
|
||||
def execute(self, context):
|
||||
assert(context)
|
||||
settings = utils.get_preferences()
|
||||
settings.is_first_launch = False
|
||||
settings.server_preset.clear()
|
||||
prefs = bpy.context.preferences.addons[__package__].preferences
|
||||
prefs.generate_default_presets()
|
||||
return {'FINISHED'}
|
||||
|
||||
def menu_func_import(self, context):
|
||||
self.layout.operator(SessionLoadSaveOperator.bl_idname, text='Multi-user session snapshot (.db)')
|
||||
|
||||
def menu_func_export(self, context):
|
||||
self.layout.operator(SessionSaveBackupOperator.bl_idname, text='Multi-user session snapshot (.db)')
|
||||
|
||||
|
||||
classes = (
|
||||
SessionStartOperator,
|
||||
SessionConnectOperator,
|
||||
SessionHostOperator,
|
||||
SessionStopOperator,
|
||||
SessionPropertyRemoveOperator,
|
||||
SessionSnapUserOperator,
|
||||
@ -920,7 +1126,11 @@ classes = (
|
||||
SessionStopAutoSaveOperator,
|
||||
SessionPurgeOperator,
|
||||
SessionPresetServerAdd,
|
||||
SessionPresetServerEdit,
|
||||
SessionPresetServerRemove,
|
||||
RefreshServerStatus,
|
||||
GetDoc,
|
||||
FirstLaunch,
|
||||
)
|
||||
|
||||
|
||||
|
@ -17,6 +17,7 @@
|
||||
|
||||
import random
|
||||
import logging
|
||||
from uuid import uuid4
|
||||
import bpy
|
||||
import string
|
||||
import re
|
||||
@ -25,7 +26,7 @@ import os
|
||||
from pathlib import Path
|
||||
|
||||
from . import bl_types, environment, addon_updater_ops, presence, ui
|
||||
from .utils import get_preferences, get_expanded_icon
|
||||
from .utils import get_preferences, get_expanded_icon, get_folder_size
|
||||
from replication.constants import RP_COMMON
|
||||
from replication.interface import session
|
||||
|
||||
@ -33,15 +34,21 @@ from replication.interface import session
|
||||
IP_REGEX = re.compile("^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$")
|
||||
HOSTNAME_REGEX = re.compile("^(([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]*[a-zA-Z0-9])\.)*([A-Za-z0-9]|[A-Za-z0-9][A-Za-z0-9\-]*[A-Za-z0-9])$")
|
||||
|
||||
#SERVER PRESETS AT LAUNCH
|
||||
DEFAULT_PRESETS = {
|
||||
"localhost" : {
|
||||
"server_ip": "localhost",
|
||||
"server_port": 5555,
|
||||
"server_password": "admin"
|
||||
"server_name": "localhost",
|
||||
"ip": "localhost",
|
||||
"port": 5555,
|
||||
"use_admin_password": True,
|
||||
"admin_password": "admin",
|
||||
"server_password": ""
|
||||
},
|
||||
"public session" : {
|
||||
"server_ip": "51.75.71.183",
|
||||
"server_port": 5555,
|
||||
"server_name": "public session",
|
||||
"ip": "51.75.71.183",
|
||||
"port": 5555,
|
||||
"admin_password": "",
|
||||
"server_password": ""
|
||||
},
|
||||
}
|
||||
@ -78,11 +85,6 @@ def update_ip(self, context):
|
||||
logging.error("Wrong IP format")
|
||||
self['ip'] = "127.0.0.1"
|
||||
|
||||
def update_server_preset_interface(self, context):
|
||||
self.server_name = self.server_preset.get(self.server_preset_interface).name
|
||||
self.ip = self.server_preset.get(self.server_preset_interface).server_ip
|
||||
self.port = self.server_preset.get(self.server_preset_interface).server_port
|
||||
self.password = self.server_preset.get(self.server_preset_interface).server_password
|
||||
|
||||
def update_directory(self, context):
|
||||
new_dir = Path(self.cache_directory)
|
||||
@ -110,9 +112,15 @@ class ReplicatedDatablock(bpy.types.PropertyGroup):
|
||||
icon: bpy.props.StringProperty()
|
||||
|
||||
class ServerPreset(bpy.types.PropertyGroup):
|
||||
server_ip: bpy.props.StringProperty()
|
||||
server_port: bpy.props.IntProperty(default=5555)
|
||||
server_password: bpy.props.StringProperty(default="admin", subtype = "PASSWORD")
|
||||
server_name: bpy.props.StringProperty(default="")
|
||||
ip: bpy.props.StringProperty(default="127.0.0.1", update=update_ip)
|
||||
port: bpy.props.IntProperty(default=5555)
|
||||
use_server_password: bpy.props.BoolProperty(default=False)
|
||||
server_password: bpy.props.StringProperty(default="", subtype = "PASSWORD")
|
||||
use_admin_password: bpy.props.BoolProperty(default=False)
|
||||
admin_password: bpy.props.StringProperty(default="", subtype = "PASSWORD")
|
||||
is_online: bpy.props.BoolProperty(default=False)
|
||||
is_private: bpy.props.BoolProperty(default=False)
|
||||
|
||||
def set_sync_render_settings(self, value):
|
||||
self['sync_render_settings'] = value
|
||||
@ -162,35 +170,60 @@ class ReplicationFlags(bpy.types.PropertyGroup):
|
||||
class SessionPrefs(bpy.types.AddonPreferences):
|
||||
bl_idname = __package__
|
||||
|
||||
ip: bpy.props.StringProperty(
|
||||
name="ip",
|
||||
description='Distant host ip',
|
||||
default="localhost",
|
||||
update=update_ip)
|
||||
# User settings
|
||||
username: bpy.props.StringProperty(
|
||||
name="Username",
|
||||
default=f"user_{random_string_digits()}"
|
||||
)
|
||||
client_color: bpy.props.FloatVectorProperty(
|
||||
name="client_instance_color",
|
||||
description='User color',
|
||||
subtype='COLOR',
|
||||
default=randomColor())
|
||||
port: bpy.props.IntProperty(
|
||||
name="port",
|
||||
description='Distant host port',
|
||||
default=5555
|
||||
default=randomColor()
|
||||
)
|
||||
# Current server settings
|
||||
server_name: bpy.props.StringProperty(
|
||||
name="server_name",
|
||||
description="Custom name of the server",
|
||||
default='localhost',
|
||||
)
|
||||
password: bpy.props.StringProperty(
|
||||
name="password",
|
||||
default=random_string_digits(),
|
||||
server_index: bpy.props.IntProperty(
|
||||
name="server_index",
|
||||
description="index of the server",
|
||||
)
|
||||
# User host session settings
|
||||
host_port: bpy.props.IntProperty(
|
||||
name="host_port",
|
||||
description='Distant host port',
|
||||
default=5555
|
||||
)
|
||||
host_use_server_password: bpy.props.BoolProperty(
|
||||
name="use_server_password",
|
||||
description='Use session password',
|
||||
default=False
|
||||
)
|
||||
host_server_password: bpy.props.StringProperty(
|
||||
name="server_password",
|
||||
description='Session password',
|
||||
subtype='PASSWORD'
|
||||
)
|
||||
host_use_admin_password: bpy.props.BoolProperty(
|
||||
name="use_admin_password",
|
||||
description='Use admin password',
|
||||
default=True
|
||||
)
|
||||
host_admin_password: bpy.props.StringProperty(
|
||||
name="admin_password",
|
||||
description='Admin password',
|
||||
subtype='PASSWORD',
|
||||
default='admin'
|
||||
)
|
||||
# Other
|
||||
is_first_launch: bpy.props.BoolProperty(
|
||||
name="is_fnirst_launch",
|
||||
description="First time lauching the addon",
|
||||
default=True
|
||||
)
|
||||
sync_flags: bpy.props.PointerProperty(
|
||||
type=ReplicationFlags
|
||||
)
|
||||
@ -214,6 +247,11 @@ class SessionPrefs(bpy.types.AddonPreferences):
|
||||
description='connection timeout before disconnection',
|
||||
default=5000
|
||||
)
|
||||
ping_timeout: bpy.props.IntProperty(
|
||||
name='ping timeout',
|
||||
description='check if servers are online',
|
||||
default=500
|
||||
)
|
||||
# Replication update settings
|
||||
depsgraph_update_rate: bpy.props.FloatProperty(
|
||||
name='depsgraph update rate (s)',
|
||||
@ -225,11 +263,12 @@ class SessionPrefs(bpy.types.AddonPreferences):
|
||||
description="Remove filecache from memory",
|
||||
default=False
|
||||
)
|
||||
# for UI
|
||||
# For UI
|
||||
category: bpy.props.EnumProperty(
|
||||
name="Category",
|
||||
description="Preferences Category",
|
||||
items=[
|
||||
('PREF', "Preferences", "Preferences of this add-on"),
|
||||
('CONFIG', "Configuration", "Configuration of this add-on"),
|
||||
('UPDATE', "Update", "Update this add-on"),
|
||||
],
|
||||
@ -273,38 +312,58 @@ class SessionPrefs(bpy.types.AddonPreferences):
|
||||
step=1,
|
||||
subtype='PERCENTAGE',
|
||||
)
|
||||
presence_mode_distance: bpy.props.FloatProperty(
|
||||
name="Distance mode visibilty",
|
||||
description="Adjust the distance visibilty of user's mode",
|
||||
presence_text_distance: bpy.props.FloatProperty(
|
||||
name="Distance text visibilty",
|
||||
description="Adjust the distance visibilty of user's mode/name",
|
||||
min=0.1,
|
||||
max=1000,
|
||||
max=10000,
|
||||
default=100,
|
||||
)
|
||||
conf_session_identity_expanded: bpy.props.BoolProperty(
|
||||
name="Identity",
|
||||
description="Identity",
|
||||
default=True
|
||||
default=False
|
||||
)
|
||||
conf_session_net_expanded: bpy.props.BoolProperty(
|
||||
name="Net",
|
||||
description="net",
|
||||
default=True
|
||||
default=False
|
||||
)
|
||||
conf_session_hosting_expanded: bpy.props.BoolProperty(
|
||||
name="Rights",
|
||||
description="Rights",
|
||||
default=False
|
||||
)
|
||||
conf_session_rep_expanded: bpy.props.BoolProperty(
|
||||
name="Replication",
|
||||
description="Replication",
|
||||
default=False
|
||||
)
|
||||
conf_session_cache_expanded: bpy.props.BoolProperty(
|
||||
name="Cache",
|
||||
description="cache",
|
||||
default=False
|
||||
)
|
||||
conf_session_log_expanded: bpy.props.BoolProperty(
|
||||
name="conf_session_log_expanded",
|
||||
description="conf_session_log_expanded",
|
||||
default=False
|
||||
)
|
||||
conf_session_ui_expanded: bpy.props.BoolProperty(
|
||||
name="Interface",
|
||||
description="Interface",
|
||||
default=False
|
||||
)
|
||||
sidebar_repository_shown: bpy.props.BoolProperty(
|
||||
name="sidebar_repository_shown",
|
||||
description="sidebar_repository_shown",
|
||||
default=False
|
||||
)
|
||||
sidebar_advanced_shown: bpy.props.BoolProperty(
|
||||
name="sidebar_advanced_shown",
|
||||
description="sidebar_advanced_shown",
|
||||
default=False
|
||||
)
|
||||
sidebar_advanced_rep_expanded: bpy.props.BoolProperty(
|
||||
name="sidebar_advanced_rep_expanded",
|
||||
description="sidebar_advanced_rep_expanded",
|
||||
@ -315,6 +374,11 @@ class SessionPrefs(bpy.types.AddonPreferences):
|
||||
description="sidebar_advanced_log_expanded",
|
||||
default=False
|
||||
)
|
||||
sidebar_advanced_hosting_expanded: bpy.props.BoolProperty(
|
||||
name="sidebar_advanced_hosting_expanded",
|
||||
description="sidebar_advanced_hosting_expanded",
|
||||
default=False
|
||||
)
|
||||
sidebar_advanced_net_expanded: bpy.props.BoolProperty(
|
||||
name="sidebar_advanced_net_expanded",
|
||||
description="sidebar_advanced_net_expanded",
|
||||
@ -371,12 +435,6 @@ class SessionPrefs(bpy.types.AddonPreferences):
|
||||
name="server preset",
|
||||
type=ServerPreset,
|
||||
)
|
||||
server_preset_interface: bpy.props.EnumProperty(
|
||||
name="servers",
|
||||
description="servers enum",
|
||||
items=server_list_callback,
|
||||
update=update_server_preset_interface,
|
||||
)
|
||||
|
||||
# Custom panel
|
||||
panel_category: bpy.props.StringProperty(
|
||||
@ -386,38 +444,28 @@ class SessionPrefs(bpy.types.AddonPreferences):
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
|
||||
layout.row().prop(self, "category", expand=True)
|
||||
|
||||
if self.category == 'PREF':
|
||||
grid = layout.column()
|
||||
|
||||
box = grid.box()
|
||||
row = box.row()
|
||||
# USER SETTINGS
|
||||
split = row.split(factor=0.7, align=True)
|
||||
split.prop(self, "username", text="User")
|
||||
split.prop(self, "client_color", text="")
|
||||
|
||||
row = box.row()
|
||||
row.label(text="Hide settings:")
|
||||
row = box.row()
|
||||
row.prop(self, "sidebar_advanced_shown", text="Hide “Advanced” settings in side pannel (Not in session)")
|
||||
row = box.row()
|
||||
row.prop(self, "sidebar_repository_shown", text="Hide “Repository” settings in side pannel (In session)")
|
||||
|
||||
if self.category == 'CONFIG':
|
||||
grid = layout.column()
|
||||
|
||||
# USER INFORMATIONS
|
||||
box = grid.box()
|
||||
box.prop(
|
||||
self, "conf_session_identity_expanded", text="User information",
|
||||
icon=get_expanded_icon(self.conf_session_identity_expanded),
|
||||
emboss=False)
|
||||
if self.conf_session_identity_expanded:
|
||||
box.row().prop(self, "username", text="name")
|
||||
box.row().prop(self, "client_color", text="color")
|
||||
|
||||
# NETWORK SETTINGS
|
||||
box = grid.box()
|
||||
box.prop(
|
||||
self, "conf_session_net_expanded", text="Networking",
|
||||
icon=get_expanded_icon(self.conf_session_net_expanded),
|
||||
emboss=False)
|
||||
|
||||
if self.conf_session_net_expanded:
|
||||
box.row().prop(self, "ip", text="Address")
|
||||
row = box.row()
|
||||
row.label(text="Port:")
|
||||
row.prop(self, "port", text="")
|
||||
row = box.row()
|
||||
row.label(text="Init the session from:")
|
||||
row.prop(self, "init_method", text="")
|
||||
|
||||
# HOST SETTINGS
|
||||
box = grid.box()
|
||||
box.prop(
|
||||
@ -425,9 +473,57 @@ class SessionPrefs(bpy.types.AddonPreferences):
|
||||
icon=get_expanded_icon(self.conf_session_hosting_expanded),
|
||||
emboss=False)
|
||||
if self.conf_session_hosting_expanded:
|
||||
row = box.row()
|
||||
row.prop(self, "host_port", text="Port: ")
|
||||
row = box.row()
|
||||
row.label(text="Init the session from:")
|
||||
row.prop(self, "init_method", text="")
|
||||
row = box.row()
|
||||
col = row.column()
|
||||
col.prop(self, "host_use_server_password", text="Server password:")
|
||||
col = row.column()
|
||||
col.enabled = True if self.host_use_server_password else False
|
||||
col.prop(self, "host_server_password", text="")
|
||||
row = box.row()
|
||||
col = row.column()
|
||||
col.prop(self, "host_use_admin_password", text="Admin password:")
|
||||
col = row.column()
|
||||
col.enabled = True if self.host_use_admin_password else False
|
||||
col.prop(self, "host_admin_password", text="")
|
||||
|
||||
# NETWORKING
|
||||
box = grid.box()
|
||||
box.prop(
|
||||
self, "conf_session_net_expanded", text="Network",
|
||||
icon=get_expanded_icon(self.conf_session_net_expanded),
|
||||
emboss=False)
|
||||
if self.conf_session_net_expanded:
|
||||
row = box.row()
|
||||
row.label(text="Timeout (ms):")
|
||||
row.prop(self, "connection_timeout", text="")
|
||||
row = box.row()
|
||||
row.label(text="Server ping (ms):")
|
||||
row.prop(self, "ping_timeout", text="")
|
||||
|
||||
# REPLICATION
|
||||
box = grid.box()
|
||||
box.prop(
|
||||
self, "conf_session_rep_expanded", text="Replication",
|
||||
icon=get_expanded_icon(self.conf_session_rep_expanded),
|
||||
emboss=False)
|
||||
if self.conf_session_rep_expanded:
|
||||
row = box.row()
|
||||
row.prop(self.sync_flags, "sync_render_settings")
|
||||
row = box.row()
|
||||
row.prop(self.sync_flags, "sync_active_camera")
|
||||
row = box.row()
|
||||
row.prop(self.sync_flags, "sync_during_editmode")
|
||||
row = box.row()
|
||||
if self.sync_flags.sync_during_editmode:
|
||||
warning = row.box()
|
||||
warning.label(text="Don't use this with heavy meshes !", icon='ERROR')
|
||||
row = box.row()
|
||||
row.prop(self, "depsgraph_update_rate", text="Apply delay")
|
||||
|
||||
# CACHE SETTINGS
|
||||
box = grid.box()
|
||||
@ -438,25 +534,18 @@ class SessionPrefs(bpy.types.AddonPreferences):
|
||||
if self.conf_session_cache_expanded:
|
||||
box.row().prop(self, "cache_directory", text="Cache directory")
|
||||
box.row().prop(self, "clear_memory_filecache", text="Clear memory filecache")
|
||||
|
||||
# INTERFACE SETTINGS
|
||||
box.row().operator('session.clear_cache', text=f"Clear cache ({get_folder_size(self.cache_directory)})")
|
||||
|
||||
# LOGGING
|
||||
box = grid.box()
|
||||
box.prop(
|
||||
self, "conf_session_ui_expanded", text="Interface",
|
||||
icon=get_expanded_icon(self.conf_session_ui_expanded),
|
||||
self, "conf_session_log_expanded", text="Logging",
|
||||
icon=get_expanded_icon(self.conf_session_log_expanded),
|
||||
emboss=False)
|
||||
if self.conf_session_ui_expanded:
|
||||
box.row().prop(self, "panel_category", text="Panel category", expand=True)
|
||||
if self.conf_session_log_expanded:
|
||||
row = box.row()
|
||||
row.label(text="Session widget:")
|
||||
|
||||
col = box.column(align=True)
|
||||
col.prop(self, "presence_hud_scale", expand=True)
|
||||
|
||||
col.prop(self, "presence_hud_hpos", expand=True)
|
||||
col.prop(self, "presence_hud_vpos", expand=True)
|
||||
|
||||
col.prop(self, "presence_mode_distance", expand=True)
|
||||
row.label(text="Log level:")
|
||||
row.prop(self, 'logging_level', text="")
|
||||
|
||||
if self.category == 'UPDATE':
|
||||
from . import addon_updater_ops
|
||||
@ -477,18 +566,31 @@ class SessionPrefs(bpy.types.AddonPreferences):
|
||||
new_db.icon = impl.bl_icon
|
||||
new_db.bl_name = impl.bl_id
|
||||
|
||||
# Get a server preset through its name
|
||||
def get_server_preset(self, name):
|
||||
existing_preset = None
|
||||
|
||||
# custom at launch server preset
|
||||
for server_preset in self.server_preset :
|
||||
if server_preset.server_name == name :
|
||||
existing_preset = server_preset
|
||||
|
||||
return existing_preset
|
||||
|
||||
# Custom at launch server preset
|
||||
def generate_default_presets(self):
|
||||
for preset_name, preset_data in DEFAULT_PRESETS.items():
|
||||
existing_preset = self.server_preset.get(preset_name)
|
||||
existing_preset = self.get_server_preset(preset_name)
|
||||
if existing_preset :
|
||||
continue
|
||||
new_server = self.server_preset.add()
|
||||
new_server.name = preset_name
|
||||
new_server.server_ip = preset_data.get('server_ip')
|
||||
new_server.server_port = preset_data.get('server_port')
|
||||
new_server.name = str(uuid4())
|
||||
new_server.server_name = preset_data.get('server_name')
|
||||
new_server.ip = preset_data.get('ip')
|
||||
new_server.port = preset_data.get('port')
|
||||
new_server.use_server_password = preset_data.get('use_server_password',False)
|
||||
new_server.server_password = preset_data.get('server_password',None)
|
||||
new_server.use_admin_password = preset_data.get('use_admin_password',False)
|
||||
new_server.admin_password = preset_data.get('admin_password',None)
|
||||
|
||||
|
||||
def client_list_callback(scene, context):
|
||||
@ -576,11 +678,6 @@ class SessionProps(bpy.types.PropertyGroup):
|
||||
description='Connect as admin',
|
||||
default=False
|
||||
)
|
||||
internet_ip: bpy.props.StringProperty(
|
||||
name="internet ip",
|
||||
default="no found",
|
||||
description='Internet interface ip',
|
||||
)
|
||||
user_snap_running: bpy.props.BoolProperty(
|
||||
default=False
|
||||
)
|
||||
|
443
multi_user/ui.py
@ -16,7 +16,9 @@
|
||||
# ##### END GPL LICENSE BLOCK #####
|
||||
|
||||
|
||||
from logging import log
|
||||
import bpy
|
||||
import bpy.utils.previews
|
||||
|
||||
from .utils import get_preferences, get_expanded_icon, get_folder_size, get_state_str
|
||||
from replication.constants import (ADDED, ERROR, FETCHED,
|
||||
@ -71,157 +73,124 @@ class SESSION_PT_settings(bpy.types.Panel):
|
||||
|
||||
def draw_header(self, context):
|
||||
layout = self.layout
|
||||
settings = get_preferences()
|
||||
|
||||
from multi_user import icons
|
||||
offline_icon = icons.icons_col["session_status_offline"]
|
||||
waiting_icon = icons.icons_col["session_status_waiting"]
|
||||
online_icon = icons.icons_col["session_status_online"]
|
||||
|
||||
if session and session.state != STATE_INITIAL:
|
||||
cli_state = session.state
|
||||
state = session.state
|
||||
connection_icon = "KEYTYPE_MOVING_HOLD_VEC"
|
||||
connection_icon = offline_icon
|
||||
|
||||
if state == STATE_ACTIVE:
|
||||
connection_icon = 'PROP_ON'
|
||||
connection_icon = online_icon
|
||||
else:
|
||||
connection_icon = 'PROP_CON'
|
||||
connection_icon = waiting_icon
|
||||
|
||||
layout.label(text=f"Session - {get_state_str(cli_state)}", icon=connection_icon)
|
||||
layout.label(text=f"{str(settings.server_name)} - {get_state_str(cli_state)}", icon_value=connection_icon.icon_id)
|
||||
else:
|
||||
layout.label(text=f"Session - v{__version__}",icon="PROP_OFF")
|
||||
layout.label(text=f"Multi-user - v{__version__}", icon="ANTIALIASED")
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
row = layout.row()
|
||||
runtime_settings = context.window_manager.session
|
||||
settings = get_preferences()
|
||||
|
||||
if hasattr(context.window_manager, 'session'):
|
||||
# STATE INITIAL
|
||||
if not session \
|
||||
or (session and session.state == STATE_INITIAL):
|
||||
pass
|
||||
else:
|
||||
progress = session.state_progress
|
||||
row = layout.row()
|
||||
if settings.is_first_launch:
|
||||
# USER SETTINGS
|
||||
row = layout.row()
|
||||
row.label(text="1. Enter your username and color:")
|
||||
row = layout.row()
|
||||
split = row.split(factor=0.7, align=True)
|
||||
split.prop(settings, "username", text="")
|
||||
split.prop(settings, "client_color", text="")
|
||||
|
||||
current_state = session.state
|
||||
info_msg = None
|
||||
# DOC
|
||||
row = layout.row()
|
||||
row.label(text="2. New here ? See the doc:")
|
||||
row = layout.row()
|
||||
row.operator("doc.get", text="Documentation", icon="HELP")
|
||||
|
||||
# START
|
||||
row = layout.row()
|
||||
row.label(text="3: Start the Multi-user:")
|
||||
row = layout.row()
|
||||
row.scale_y = 2
|
||||
row.operator("firstlaunch.verify", text="Continue")
|
||||
|
||||
if not settings.is_first_launch:
|
||||
if hasattr(context.window_manager, 'session'):
|
||||
# STATE INITIAL
|
||||
if not session \
|
||||
or (session and session.state == STATE_INITIAL):
|
||||
layout = self.layout
|
||||
settings = get_preferences()
|
||||
server_preset = settings.server_preset
|
||||
selected_server = context.window_manager.server_index if context.window_manager.server_index<=len(server_preset)-1 else 0
|
||||
active_server_name = server_preset[selected_server].name if len(server_preset)>=1 else ""
|
||||
is_server_selected = True if active_server_name else False
|
||||
|
||||
if current_state in [STATE_ACTIVE]:
|
||||
row = row.grid_flow(row_major=True, columns=0, even_columns=True, even_rows=False, align=True)
|
||||
row.prop(settings.sync_flags, "sync_render_settings",text="",icon_only=True, icon='SCENE')
|
||||
row.prop(settings.sync_flags, "sync_during_editmode", text="",icon_only=True, icon='EDITMODE_HLT')
|
||||
row.prop(settings.sync_flags, "sync_active_camera", text="",icon_only=True, icon='VIEW_CAMERA')
|
||||
# SERVER LIST
|
||||
row = layout.row()
|
||||
box = row.box()
|
||||
box.scale_y = 0.7
|
||||
split = box.split(factor=0.7)
|
||||
split.label(text="Server")
|
||||
split.label(text="Online")
|
||||
|
||||
row= layout.row()
|
||||
col = row.column(align=True)
|
||||
col.operator("session.get_info", icon="FILE_REFRESH", text="")
|
||||
|
||||
if current_state in [STATE_ACTIVE] and runtime_settings.is_host:
|
||||
info_msg = f"LAN: {runtime_settings.internet_ip}"
|
||||
if current_state == STATE_LOBBY:
|
||||
info_msg = "Waiting for the session to start."
|
||||
row = layout.row()
|
||||
col = row.column(align=True)
|
||||
col.template_list("SESSION_UL_network", "", settings, "server_preset", context.window_manager, "server_index")
|
||||
col.separator()
|
||||
connectOp = col.row()
|
||||
connectOp.operator("session.host", text="Host")
|
||||
connectopcol = connectOp.column()
|
||||
connectopcol.enabled =is_server_selected
|
||||
connectopcol.operator("session.connect", text="Connect")
|
||||
|
||||
if info_msg:
|
||||
info_box = row.box()
|
||||
info_box.row().label(text=info_msg,icon='INFO')
|
||||
col = row.column(align=True)
|
||||
col.operator("session.preset_server_add", icon="ADD", text="") # TODO : add conditions (need a name, etc..)
|
||||
row_visible = col.row(align=True)
|
||||
col_visible = row_visible.column(align=True)
|
||||
col_visible.enabled = is_server_selected
|
||||
col_visible.operator("session.preset_server_remove", icon="REMOVE", text="").target_server_name = active_server_name
|
||||
col_visible.separator()
|
||||
col_visible.operator("session.preset_server_edit", icon="GREASEPENCIL", text="").target_server_name = active_server_name
|
||||
|
||||
# Progress bar
|
||||
if current_state in [STATE_SYNCING, STATE_SRV_SYNC, STATE_WAITING]:
|
||||
info_box = row.box()
|
||||
info_box.row().label(text=printProgressBar(
|
||||
progress['current'],
|
||||
progress['total'],
|
||||
length=16
|
||||
))
|
||||
else:
|
||||
exitbutton = layout.row()
|
||||
exitbutton.scale_y = 1.5
|
||||
exitbutton.operator("session.stop", icon='QUIT', text="Disconnect")
|
||||
|
||||
layout.row().operator("session.stop", icon='QUIT', text="Exit")
|
||||
progress = session.state_progress
|
||||
current_state = session.state
|
||||
info_msg = None
|
||||
|
||||
if current_state == STATE_LOBBY:
|
||||
row= layout.row()
|
||||
info_msg = "Waiting for the session to start."
|
||||
|
||||
class SESSION_PT_settings_network(bpy.types.Panel):
|
||||
bl_idname = "MULTIUSER_SETTINGS_NETWORK_PT_panel"
|
||||
bl_label = "Network"
|
||||
bl_space_type = 'VIEW_3D'
|
||||
bl_region_type = 'UI'
|
||||
bl_parent_id = 'MULTIUSER_SETTINGS_PT_panel'
|
||||
if info_msg:
|
||||
info_box = row.box()
|
||||
info_box.row().label(text=info_msg,icon='INFO')
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
return not session \
|
||||
or (session and session.state == 0)
|
||||
|
||||
def draw_header(self, context):
|
||||
self.layout.label(text="", icon='URL')
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
|
||||
runtime_settings = context.window_manager.session
|
||||
settings = get_preferences()
|
||||
|
||||
# USER SETTINGS
|
||||
row = layout.row()
|
||||
row.prop(runtime_settings, "session_mode", expand=True)
|
||||
row = layout.row()
|
||||
|
||||
col = row.row(align=True)
|
||||
col.prop(settings, "server_preset_interface", text="")
|
||||
col.operator("session.preset_server_add", icon='ADD', text="")
|
||||
col.operator("session.preset_server_remove", icon='REMOVE', text="")
|
||||
|
||||
row = layout.row()
|
||||
box = row.box()
|
||||
|
||||
if runtime_settings.session_mode == 'HOST':
|
||||
row = box.row()
|
||||
row.label(text="Port:")
|
||||
row.prop(settings, "port", text="")
|
||||
row = box.row()
|
||||
row.label(text="Start from:")
|
||||
row.prop(settings, "init_method", text="")
|
||||
row = box.row()
|
||||
row.label(text="Admin password:")
|
||||
row.prop(settings, "password", text="")
|
||||
row = box.row()
|
||||
row.operator("session.start", text="HOST").host = True
|
||||
else:
|
||||
row = box.row()
|
||||
row.prop(settings, "ip", text="IP")
|
||||
row = box.row()
|
||||
row.label(text="Port:")
|
||||
row.prop(settings, "port", text="")
|
||||
|
||||
row = box.row()
|
||||
row.prop(runtime_settings, "admin", text='Connect as admin', icon='DISCLOSURE_TRI_DOWN' if runtime_settings.admin
|
||||
else 'DISCLOSURE_TRI_RIGHT')
|
||||
if runtime_settings.admin:
|
||||
row = box.row()
|
||||
row.label(text="Password:")
|
||||
row.prop(settings, "password", text="")
|
||||
row = box.row()
|
||||
row.operator("session.start", text="CONNECT").host = False
|
||||
|
||||
class SESSION_PT_settings_user(bpy.types.Panel):
|
||||
bl_idname = "MULTIUSER_SETTINGS_USER_PT_panel"
|
||||
bl_label = "User info"
|
||||
bl_space_type = 'VIEW_3D'
|
||||
bl_region_type = 'UI'
|
||||
bl_parent_id = 'MULTIUSER_SETTINGS_PT_panel'
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
return not session \
|
||||
or (session and session.state == 0)
|
||||
|
||||
def draw_header(self, context):
|
||||
self.layout.label(text="", icon='USER')
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
|
||||
runtime_settings = context.window_manager.session
|
||||
settings = get_preferences()
|
||||
|
||||
row = layout.row()
|
||||
# USER SETTINGS
|
||||
row.prop(settings, "username", text="name")
|
||||
|
||||
row = layout.row()
|
||||
row.prop(settings, "client_color", text="color")
|
||||
row = layout.row()
|
||||
# PROGRESS BAR
|
||||
if current_state in [STATE_SYNCING, STATE_SRV_SYNC, STATE_WAITING]:
|
||||
row= layout.row()
|
||||
row.label(text=f"Status: {get_state_str(current_state)}")
|
||||
row= layout.row()
|
||||
info_box = row.box()
|
||||
info_box.label(text=printProgressBar(
|
||||
progress['current'],
|
||||
progress['total'],
|
||||
length=16
|
||||
))
|
||||
|
||||
|
||||
class SESSION_PT_advanced_settings(bpy.types.Panel):
|
||||
@ -234,19 +203,45 @@ class SESSION_PT_advanced_settings(bpy.types.Panel):
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
settings = get_preferences()
|
||||
return not session \
|
||||
or (session and session.state == 0)
|
||||
or (session and session.state == 0) \
|
||||
and not settings.sidebar_advanced_shown \
|
||||
and not settings.is_first_launch
|
||||
|
||||
def draw_header(self, context):
|
||||
self.layout.label(text="", icon='PREFERENCES')
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
|
||||
runtime_settings = context.window_manager.session
|
||||
settings = get_preferences()
|
||||
|
||||
|
||||
#ADVANCED HOST
|
||||
host_selection = layout.row().box()
|
||||
host_selection.prop(
|
||||
settings, "sidebar_advanced_hosting_expanded", text="Hosting",
|
||||
icon=get_expanded_icon(settings.sidebar_advanced_hosting_expanded),
|
||||
emboss=False)
|
||||
if settings.sidebar_advanced_hosting_expanded:
|
||||
host_selection_row = host_selection.row()
|
||||
host_selection_row.prop(settings, "host_port", text="Port:")
|
||||
host_selection_row = host_selection.row()
|
||||
host_selection_row.label(text="Init the session from:")
|
||||
host_selection_row.prop(settings, "init_method", text="")
|
||||
host_selection_row = host_selection.row()
|
||||
host_selection_col = host_selection_row.column()
|
||||
host_selection_col.prop(settings, "host_use_server_password", text="Server password:")
|
||||
host_selection_col = host_selection_row.column()
|
||||
host_selection_col.enabled = True if settings.host_use_server_password else False
|
||||
host_selection_col.prop(settings, "host_server_password", text="")
|
||||
host_selection_row = host_selection.row()
|
||||
host_selection_col = host_selection_row.column()
|
||||
host_selection_col.prop(settings, "host_use_admin_password", text="Admin password:")
|
||||
host_selection_col = host_selection_row.column()
|
||||
host_selection_col.enabled = True if settings.host_use_admin_password else False
|
||||
host_selection_col.prop(settings, "host_admin_password", text="")
|
||||
|
||||
#ADVANCED NET
|
||||
net_section = layout.row().box()
|
||||
net_section.prop(
|
||||
settings,
|
||||
@ -254,12 +249,15 @@ class SESSION_PT_advanced_settings(bpy.types.Panel):
|
||||
text="Network",
|
||||
icon=get_expanded_icon(settings.sidebar_advanced_net_expanded),
|
||||
emboss=False)
|
||||
|
||||
if settings.sidebar_advanced_net_expanded:
|
||||
net_section_row = net_section.row()
|
||||
net_section_row.label(text="Timeout (ms):")
|
||||
net_section_row.prop(settings, "connection_timeout", text="")
|
||||
net_section_row = net_section.row()
|
||||
net_section_row.label(text="Server ping (ms):")
|
||||
net_section_row.prop(settings, "ping_timeout", text="")
|
||||
|
||||
#ADVANCED REPLICATION
|
||||
replication_section = layout.row().box()
|
||||
replication_section.prop(
|
||||
settings,
|
||||
@ -267,16 +265,12 @@ class SESSION_PT_advanced_settings(bpy.types.Panel):
|
||||
text="Replication",
|
||||
icon=get_expanded_icon(settings.sidebar_advanced_rep_expanded),
|
||||
emboss=False)
|
||||
|
||||
if settings.sidebar_advanced_rep_expanded:
|
||||
replication_section_row = replication_section.row()
|
||||
|
||||
replication_section_row = replication_section.row()
|
||||
replication_section_row.prop(settings.sync_flags, "sync_render_settings")
|
||||
replication_section_row = replication_section.row()
|
||||
replication_section_row.prop(settings.sync_flags, "sync_active_camera")
|
||||
replication_section_row = replication_section.row()
|
||||
|
||||
replication_section_row.prop(settings.sync_flags, "sync_during_editmode")
|
||||
replication_section_row = replication_section.row()
|
||||
if settings.sync_flags.sync_during_editmode:
|
||||
@ -285,7 +279,7 @@ class SESSION_PT_advanced_settings(bpy.types.Panel):
|
||||
replication_section_row = replication_section.row()
|
||||
replication_section_row.prop(settings, "depsgraph_update_rate", text="Apply delay")
|
||||
|
||||
|
||||
#ADVANCED CACHE
|
||||
cache_section = layout.row().box()
|
||||
cache_section.prop(
|
||||
settings,
|
||||
@ -303,6 +297,8 @@ class SESSION_PT_advanced_settings(bpy.types.Panel):
|
||||
cache_section_row.prop(settings, "clear_memory_filecache", text="")
|
||||
cache_section_row = cache_section.row()
|
||||
cache_section_row.operator('session.clear_cache', text=f"Clear cache ({get_folder_size(settings.cache_directory)})")
|
||||
|
||||
#ADVANCED LOG
|
||||
log_section = layout.row().box()
|
||||
log_section.prop(
|
||||
settings,
|
||||
@ -310,11 +306,11 @@ class SESSION_PT_advanced_settings(bpy.types.Panel):
|
||||
text="Logging",
|
||||
icon=get_expanded_icon(settings.sidebar_advanced_log_expanded),
|
||||
emboss=False)
|
||||
|
||||
if settings.sidebar_advanced_log_expanded:
|
||||
log_section_row = log_section.row()
|
||||
log_section_row.label(text="Log level:")
|
||||
log_section_row.prop(settings, 'logging_level', text="")
|
||||
|
||||
class SESSION_PT_user(bpy.types.Panel):
|
||||
bl_idname = "MULTIUSER_USER_PT_panel"
|
||||
bl_label = "Online users"
|
||||
@ -324,7 +320,8 @@ class SESSION_PT_user(bpy.types.Panel):
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
return session and session.state in [STATE_ACTIVE, STATE_LOBBY]
|
||||
return session \
|
||||
and session.state in [STATE_ACTIVE, STATE_LOBBY]
|
||||
|
||||
def draw_header(self, context):
|
||||
self.layout.label(text="", icon='USER')
|
||||
@ -336,9 +333,8 @@ class SESSION_PT_user(bpy.types.Panel):
|
||||
settings = get_preferences()
|
||||
active_user = online_users[selected_user] if len(
|
||||
online_users)-1 >= selected_user else 0
|
||||
runtime_settings = context.window_manager.session
|
||||
|
||||
# Create a simple row.
|
||||
#USER LIST
|
||||
row = layout.row()
|
||||
box = row.box()
|
||||
split = box.split(factor=0.35)
|
||||
@ -353,6 +349,7 @@ class SESSION_PT_user(bpy.types.Panel):
|
||||
layout.template_list("SESSION_UL_users", "", context.window_manager,
|
||||
"online_users", context.window_manager, "user_index")
|
||||
|
||||
#OPERATOR ON USER
|
||||
if active_user != 0 and active_user.username != settings.username:
|
||||
row = layout.row()
|
||||
user_operations = row.split()
|
||||
@ -436,57 +433,8 @@ class SESSION_UL_users(bpy.types.UIList):
|
||||
split.label(text=scene_current)
|
||||
split.label(text=ping)
|
||||
|
||||
|
||||
class SESSION_PT_presence(bpy.types.Panel):
|
||||
bl_idname = "MULTIUSER_MODULE_PT_panel"
|
||||
bl_label = "Presence overlay"
|
||||
bl_space_type = 'VIEW_3D'
|
||||
bl_region_type = 'UI'
|
||||
bl_parent_id = 'MULTIUSER_SETTINGS_PT_panel'
|
||||
bl_options = {'DEFAULT_CLOSED'}
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
return not session \
|
||||
or (session and session.state in [STATE_INITIAL, STATE_ACTIVE])
|
||||
|
||||
def draw_header(self, context):
|
||||
self.layout.prop(context.window_manager.session,
|
||||
"enable_presence", text="",icon='OVERLAY')
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
|
||||
settings = context.window_manager.session
|
||||
pref = get_preferences()
|
||||
layout.active = settings.enable_presence
|
||||
|
||||
row = layout.row()
|
||||
row = row.grid_flow(row_major=True, columns=0, even_columns=True, even_rows=False, align=True)
|
||||
row.prop(settings, "presence_show_selected",text="",icon_only=True, icon='CUBE')
|
||||
row.prop(settings, "presence_show_user", text="",icon_only=True, icon='CAMERA_DATA')
|
||||
row.prop(settings, "presence_show_mode", text="",icon_only=True, icon='OBJECT_DATAMODE')
|
||||
row.prop(settings, "presence_show_far_user", text="",icon_only=True, icon='SCENE_DATA')
|
||||
|
||||
col = layout.column()
|
||||
if settings.presence_show_mode :
|
||||
row = col.column()
|
||||
row.prop(pref, "presence_mode_distance", expand=True)
|
||||
|
||||
col.prop(settings, "presence_show_session_status")
|
||||
if settings.presence_show_session_status :
|
||||
row = col.column()
|
||||
row.active = settings.presence_show_session_status
|
||||
row.prop(pref, "presence_hud_scale", expand=True)
|
||||
row = col.column(align=True)
|
||||
row.active = settings.presence_show_session_status
|
||||
row.prop(pref, "presence_hud_hpos", expand=True)
|
||||
row.prop(pref, "presence_hud_vpos", expand=True)
|
||||
|
||||
|
||||
def draw_property(context, parent, property_uuid, level=0):
|
||||
settings = get_preferences()
|
||||
runtime_settings = context.window_manager.session
|
||||
item = session.repository.graph.get(property_uuid)
|
||||
type_id = item.data.get('type_id')
|
||||
area_msg = parent.row(align=True)
|
||||
@ -506,15 +454,18 @@ def draw_property(context, parent, property_uuid, level=0):
|
||||
detail_item_box.label(text=f"{name}")
|
||||
|
||||
# Operations
|
||||
|
||||
have_right_to_modify = (item.owner == settings.username or \
|
||||
item.owner == RP_COMMON) and item.state != ERROR
|
||||
|
||||
from multi_user import icons
|
||||
sync_status = icons.icons_col["repository_push"] #TODO: Link all icons to the right sync (push/merge/issue). For issue use "UNLINKED" for icon
|
||||
# sync_status = icons.icons_col["repository_merge"]
|
||||
|
||||
if have_right_to_modify:
|
||||
detail_item_box.operator(
|
||||
"session.commit",
|
||||
text="",
|
||||
icon='TRIA_UP').target = item.uuid
|
||||
icon_value=sync_status.icon_id).target = item.uuid
|
||||
detail_item_box.separator()
|
||||
|
||||
if item.state in [FETCHED, UP]:
|
||||
@ -546,12 +497,40 @@ def draw_property(context, parent, property_uuid, level=0):
|
||||
else:
|
||||
detail_item_box.label(text="", icon="DECORATE_LOCKED")
|
||||
|
||||
class SESSION_PT_sync(bpy.types.Panel):
|
||||
bl_idname = "MULTIUSER_SYNC_PT_panel"
|
||||
bl_label = "Synchronize"
|
||||
bl_space_type = 'VIEW_3D'
|
||||
bl_region_type = 'UI'
|
||||
bl_parent_id = 'MULTIUSER_SETTINGS_PT_panel'
|
||||
bl_options = {'DEFAULT_CLOSED'}
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
return session \
|
||||
and session.state in [STATE_ACTIVE]
|
||||
|
||||
def draw_header(self, context):
|
||||
self.layout.label(text="", icon='UV_SYNC_SELECT')
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
settings = get_preferences()
|
||||
|
||||
row= layout.row()
|
||||
row = row.grid_flow(row_major=True, columns=0, even_columns=True, even_rows=False, align=True)
|
||||
row.prop(settings.sync_flags, "sync_render_settings",text="",icon_only=True, icon='SCENE')
|
||||
row.prop(settings.sync_flags, "sync_during_editmode", text="",icon_only=True, icon='EDITMODE_HLT')
|
||||
row.prop(settings.sync_flags, "sync_active_camera", text="",icon_only=True, icon='VIEW_CAMERA')
|
||||
|
||||
|
||||
class SESSION_PT_repository(bpy.types.Panel):
|
||||
bl_idname = "MULTIUSER_PROPERTIES_PT_panel"
|
||||
bl_label = "Repository"
|
||||
bl_space_type = 'VIEW_3D'
|
||||
bl_region_type = 'UI'
|
||||
bl_parent_id = 'MULTIUSER_SETTINGS_PT_panel'
|
||||
bl_options = {'DEFAULT_CLOSED'}
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
@ -565,7 +544,8 @@ class SESSION_PT_repository(bpy.types.Panel):
|
||||
return hasattr(context.window_manager, 'session') and \
|
||||
session and \
|
||||
(session.state == STATE_ACTIVE or \
|
||||
session.state == STATE_LOBBY and admin)
|
||||
session.state == STATE_LOBBY and admin) and \
|
||||
not settings.sidebar_repository_shown
|
||||
|
||||
def draw_header(self, context):
|
||||
self.layout.label(text="", icon='OUTLINER_OB_GROUP_INSTANCE')
|
||||
@ -579,19 +559,18 @@ class SESSION_PT_repository(bpy.types.Panel):
|
||||
|
||||
usr = session.online_users.get(settings.username)
|
||||
|
||||
row = layout.row()
|
||||
|
||||
if session.state == STATE_ACTIVE:
|
||||
if 'SessionBackupTimer' in registry:
|
||||
row = layout.row()
|
||||
row.alert = True
|
||||
row.operator('session.cancel_autosave', icon="CANCEL")
|
||||
row.alert = False
|
||||
else:
|
||||
row.operator('session.save', icon="FILE_TICK")
|
||||
# else:
|
||||
# row.operator('session.save', icon="FILE_TICK")
|
||||
|
||||
box = layout.box()
|
||||
row = box.row()
|
||||
row.prop(runtime_settings, "filter_owned", text="Show only owned Nodes", icon_only=True, icon="DECORATE_UNLOCKED")
|
||||
row.prop(runtime_settings, "filter_owned", text="Only show owned data blocks", icon_only=True, icon="DECORATE_UNLOCKED")
|
||||
row = box.row()
|
||||
row.prop(runtime_settings, "filter_name", text="Filter")
|
||||
row = box.row()
|
||||
@ -612,8 +591,10 @@ class SESSION_PT_repository(bpy.types.Panel):
|
||||
layout.row().label(text="Empty")
|
||||
|
||||
elif session.state == STATE_LOBBY and usr and usr['admin']:
|
||||
row = layout.row()
|
||||
row.operator("session.init", icon='TOOL_SETTINGS', text="Init")
|
||||
else:
|
||||
row = layout.row()
|
||||
row.label(text="Waiting to start")
|
||||
|
||||
class VIEW3D_PT_overlay_session(bpy.types.Panel):
|
||||
@ -634,41 +615,65 @@ class VIEW3D_PT_overlay_session(bpy.types.Panel):
|
||||
layout.active = settings.enable_presence
|
||||
|
||||
row = layout.row()
|
||||
row = row.grid_flow(row_major=True, columns=0, even_columns=True, even_rows=False, align=True)
|
||||
row.prop(settings, "presence_show_selected",text="",icon_only=True, icon='CUBE')
|
||||
row.prop(settings, "presence_show_user", text="",icon_only=True, icon='CAMERA_DATA')
|
||||
row.prop(settings, "presence_show_mode", text="",icon_only=True, icon='OBJECT_DATAMODE')
|
||||
row.prop(settings, "presence_show_far_user", text="",icon_only=True, icon='SCENE_DATA')
|
||||
|
||||
row.prop(settings, "presence_show_selected",text="Selected Objects")
|
||||
|
||||
row = layout.row(align=True)
|
||||
row.prop(settings, "presence_show_user", text="Users camera")
|
||||
row.prop(settings, "presence_show_mode", text="Users mode")
|
||||
|
||||
col = layout.column()
|
||||
if settings.presence_show_mode :
|
||||
if settings.presence_show_mode or settings.presence_show_user:
|
||||
row = col.column()
|
||||
row.prop(pref, "presence_mode_distance", expand=True)
|
||||
|
||||
row.prop(pref, "presence_text_distance", expand=True)
|
||||
|
||||
row = col.column()
|
||||
row.prop(settings, "presence_show_far_user", text="Users on different scenes")
|
||||
|
||||
col.prop(settings, "presence_show_session_status")
|
||||
if settings.presence_show_session_status :
|
||||
row = col.column()
|
||||
row.active = settings.presence_show_session_status
|
||||
row.prop(pref, "presence_hud_scale", expand=True)
|
||||
row = col.column(align=True)
|
||||
row.active = settings.presence_show_session_status
|
||||
row.prop(pref, "presence_hud_hpos", expand=True)
|
||||
row.prop(pref, "presence_hud_vpos", expand=True)
|
||||
split = layout.split()
|
||||
text_pos = split.column(align=True)
|
||||
text_pos.active = settings.presence_show_session_status
|
||||
text_pos.prop(pref, "presence_hud_hpos", expand=True)
|
||||
text_pos.prop(pref, "presence_hud_vpos", expand=True)
|
||||
text_scale = split.column()
|
||||
text_scale.active = settings.presence_show_session_status
|
||||
text_scale.prop(pref, "presence_hud_scale", expand=True)
|
||||
|
||||
|
||||
class SESSION_UL_network(bpy.types.UIList):
|
||||
def draw_item(self, context, layout, data, item, icon, active_data, active_propname, index, flt_flag):
|
||||
settings = get_preferences()
|
||||
server_name = '-'
|
||||
server_status = 'BLANK1'
|
||||
server_private = 'BLANK1'
|
||||
|
||||
server_name = item.server_name
|
||||
|
||||
split = layout.split(factor=0.7)
|
||||
if item.is_private:
|
||||
server_private = 'LOCKED'
|
||||
split.label(text=server_name, icon=server_private)
|
||||
else:
|
||||
split.label(text=server_name)
|
||||
|
||||
from multi_user import icons
|
||||
server_status = icons.icons_col["server_offline"]
|
||||
if item.is_online:
|
||||
server_status = icons.icons_col["server_online"]
|
||||
split.label(icon_value=server_status.icon_id)
|
||||
|
||||
classes = (
|
||||
SESSION_UL_users,
|
||||
SESSION_UL_network,
|
||||
SESSION_PT_settings,
|
||||
SESSION_PT_settings_user,
|
||||
SESSION_PT_settings_network,
|
||||
SESSION_PT_presence,
|
||||
SESSION_PT_advanced_settings,
|
||||
SESSION_PT_user,
|
||||
SESSION_PT_sync,
|
||||
SESSION_PT_repository,
|
||||
VIEW3D_PT_overlay_session,
|
||||
)
|
||||
|
||||
|
||||
register, unregister = bpy.utils.register_classes_factory(classes)
|
||||
|
||||
if __name__ == "__main__":
|
||||
|