Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fixture selection previous/next by keyboard #83

Merged
merged 4 commits into from
Dec 17, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 42 additions & 0 deletions __init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
import time
import json
import uuid as py_uuid
import re

from dmx.pymvr import GeneralSceneDescription
from dmx.mvr import extract_mvr_textures, process_mvr_child_list
Expand Down Expand Up @@ -152,15 +153,31 @@ class DMX(PropertyGroup):
DMX_OT_Programmer_Set_Ignore_Movement,
DMX_OT_Programmer_Unset_Ignore_Movement,
DMX_PT_DMX_OSC,
DMX_OT_Fixture_ForceRemove,
DMX_OT_Fixture_SelectNext,
DMX_OT_Fixture_SelectPrevious,
DMX_PT_Programmer)

linkedToFile = False
_keymaps = []

def register():
for cls in DMX.classes_setup:
bpy.utils.register_class(cls)

# register key shortcuts
wm = bpy.context.window_manager
km = wm.keyconfigs.addon.keymaps.new(name='3D View Generic', space_type='VIEW_3D')
kmi = km.keymap_items.new('dmx.fixture_next', 'RIGHT_ARROW', 'PRESS', ctrl=True)
DMX._keymaps.append((km, kmi))
kmi = km.keymap_items.new('dmx.fixture_previous', 'LEFT_ARROW', 'PRESS', ctrl=True)
DMX._keymaps.append((km, kmi))

def unregister():
# unregister keymaps
for km, kmi in DMX._keymaps: km.keymap_items.remove(kmi)
DMX._keymaps.clear()

if (DMX.linkedToFile):
for cls in DMX.classes:
bpy.utils.unregister_class(cls)
Expand Down Expand Up @@ -192,6 +209,10 @@ def unregister():
name = "DMX Address",
default = True)

column_fixture_remove: BoolProperty(
name = "Remove Fixture",
default = False)

collection: PointerProperty(
name = "DMX Collection",
type = Collection)
Expand Down Expand Up @@ -997,6 +1018,27 @@ def selectedFixtures(self):
break
return selected


def sortedFixtures(self):
def string_to_pairs(s, pairs=re.compile(r"(\D*)(\d*)").findall):
return [(text.lower(), int(digits or 0)) for (text, digits) in pairs(s)[:-1]]

sorting_order = self.fixtures_sorting_order

if sorting_order == "ADDRESS":
fixtures = sorted(self.fixtures, key=lambda c: string_to_pairs(str(c.universe*1000+c.address)))
elif sorting_order == "NAME":
fixtures = sorted(self.fixtures, key=lambda c: string_to_pairs(c.name))
elif sorting_order == "FIXTURE_ID":
fixtures = sorted(self.fixtures, key=lambda c: string_to_pairs(str(c.fixture_id)))
elif sorting_order == "UNIT_NUMBER":
fixtures = sorted(self.fixtures, key=lambda c: string_to_pairs(str(c.unit_number)))
else:
fixtures = self.fixtures

return fixtures


def addMVR(self, file_name):

bpy.app.handlers.depsgraph_update_post.clear()
Expand Down
5 changes: 4 additions & 1 deletion fixture.py
Original file line number Diff line number Diff line change
Expand Up @@ -767,6 +767,8 @@ def get_mobile_type(self, mobile_type):


def get_root(self, model_collection):
if model_collection.objects is None:
return None
for obj in model_collection.objects:
if obj.get("geometry_root", False):
return obj
Expand Down Expand Up @@ -815,7 +817,8 @@ def select(self):

def unselect(self):
dmx = bpy.context.scene.dmx
self.objects["Root"].object.select_set(False)
if "Root" in self.objects:
self.objects["Root"].object.select_set(False)
if ('Target' in self.objects):
self.objects['Target'].object.select_set(False)
if "2D Symbol" in self.objects:
Expand Down
98 changes: 75 additions & 23 deletions panels/fixtures.py
Original file line number Diff line number Diff line change
Expand Up @@ -206,11 +206,6 @@ def onProfile(self, context):
#update = onAddTarget,
default = True)

uuid: StringProperty(
name = "UUID",
description = "Unique ID, used for MVR",
default = str(py_uuid.uuid4())
)
re_address_only: BoolProperty(
name = "Re-address only",
description="Do not rebuild the model structure",
Expand All @@ -232,7 +227,8 @@ def onProfile(self, context):
def draw(self, context):
layout = self.layout
col = layout.column()
col.prop(self, "name")
if not self.re_address_only:
col.prop(self, "name")
col.context_pointer_set("add_edit_panel", self)
text_profile = "GDTF Profile"
if (self.profile != ""):
Expand All @@ -241,11 +237,13 @@ def draw(self, context):
text_profile = text_profile[0] + " > " + text_profile[1]
else:
text_profile = "Unknown manufacturer" + " > " + text_profile[0]
col.menu("DMX_MT_Fixture_Manufacturers", text = text_profile)
if not self.re_address_only:
col.menu("DMX_MT_Fixture_Manufacturers", text = text_profile)
text_mode = "DMX Mode"
if (self.mode != ""):
text_mode = self.mode
col.menu("DMX_MT_Fixture_Mode", text = text_mode)
if not self.re_address_only:
col.menu("DMX_MT_Fixture_Mode", text = text_mode)
col.prop(self, "universe")
col.prop(self, "address")
col.prop(self, "fixture_id")
Expand Down Expand Up @@ -302,6 +300,7 @@ def execute(self, context):
if (len(selected) == 1):
fixture = selected[0]
if (self.name != fixture.name and self.name in bpy.data.collections):
self.report({'ERROR'}, "Fixture named " + self.name + " already exists")
return {'CANCELLED'}
if not self.re_address_only:
fixture.build(self.name, self.profile, self.mode, self.universe, self.address, self.gel_color, self.display_beams, self.add_target, uuid = fixture.uuid, fixture_id = fixture.fixture_id)
Expand All @@ -320,6 +319,7 @@ def execute(self, context):
for i, fixture in enumerate(selected):
name = self.name + ' ' + str(i+1)
if (name != fixture.name and name in bpy.data.collections):
self.report({'ERROR'}, "Fixture named " + self.name + " already exists")
return {'CANCELLED'}
for i, fixture in enumerate(selected):
name = (self.name + ' ' + str(i+1)) if (self.name != '*') else fixture.name
Expand Down Expand Up @@ -480,6 +480,56 @@ def execute(self, context):

# Panel #

class DMX_OT_Fixture_SelectPrevious(Operator):
bl_label = " "
bl_idname = "dmx.fixture_previous"
bl_description = "Select Previous Fixture"
bl_options = {'UNDO'}

def execute(self, context):
scene = context.scene
dmx = scene.dmx
selected_all = dmx.selectedFixtures()
fixtures = dmx.sortedFixtures()

for fixture in fixtures:
fixture.unselect()

for selected in selected_all:
for idx, fixture in enumerate(fixtures):
if fixture == selected:
idx -= 1
if idx < 0:
idx = len(fixtures)-1
fixtures[idx].select()
break
return {'FINISHED'}

class DMX_OT_Fixture_SelectNext(Operator):
bl_label = " "
bl_idname = "dmx.fixture_next"
bl_description = "Select Next Fixture"
bl_options = {'UNDO'}

def execute(self, context):
scene = context.scene
dmx = scene.dmx
selected_all = dmx.selectedFixtures()
fixtures = dmx.sortedFixtures()

for fixture in fixtures:
fixture.unselect()

for selected in selected_all:
for idx, fixture in enumerate(fixtures):
if fixture == selected:
idx += 1
if idx > len(fixtures)-1:
idx = 0
fixtures[idx].select()
break
return {'FINISHED'}

class DMX_OT_Fixture_Item(Operator):
bl_label = "DMX > Fixture > Item"
bl_idname = "dmx.fixture_item"
Expand All @@ -491,6 +541,17 @@ def execute(self, context):
return {'FINISHED'}


class DMX_OT_Fixture_ForceRemove(Operator):
bl_label = ""
bl_idname = "dmx.force_remove_fixture"
bl_description = "Remove fixture"
bl_options = {'UNDO'}

def execute(self, context):
print("Removing fixture", context.fixture)
dmx = context.scene.dmx
dmx.removeFixture(context.fixture)
return {'FINISHED'}

class DMX_PT_Fixture_Columns_Setup(Panel):
bl_label = "Display Columns"
Expand All @@ -517,6 +578,8 @@ def draw(self, context):
row = layout.row()
row.prop(dmx, "column_dmx_address")
row = layout.row()
row.prop(dmx, "column_fixture_remove")
row = layout.row()
row.prop(dmx, "fixtures_sorting_order")


Expand All @@ -530,28 +593,14 @@ class DMX_PT_Fixtures(Panel):
bl_context = "objectmode"

def draw(self, context):
def string_to_pairs(s, pairs=re.compile(r"(\D*)(\d*)").findall):
return [(text.lower(), int(digits or 0)) for (text, digits) in pairs(s)[:-1]]

layout = self.layout
scene = context.scene
dmx = scene.dmx

if (len(scene.dmx.fixtures)):
box = layout.box()
col = box.column()
sorting_order = dmx.fixtures_sorting_order

if sorting_order == "ADDRESS":
fixtures = sorted(dmx.fixtures, key=lambda c: string_to_pairs(str(c.universe*1000+c.address)))
elif sorting_order == "NAME":
fixtures = sorted(dmx.fixtures, key=lambda c: string_to_pairs(c.name))
elif sorting_order == "FIXTURE_ID":
fixtures = sorted(dmx.fixtures, key=lambda c: string_to_pairs(str(c.fixture_id)))
elif sorting_order == "UNIT_NUMBER":
fixtures = sorted(dmx.fixtures, key=lambda c: string_to_pairs(str(c.unit_number)))
else:
fixtures = dmx.fixtures
fixtures = dmx.sortedFixtures()

for fixture in fixtures:
selected = False
Expand Down Expand Up @@ -588,5 +637,8 @@ def string_to_pairs(s, pairs=re.compile(r"(\D*)(\d*)").findall):
c = row.column()
c.label(text=f"{fixture.universe}.{fixture.address}")
c.ui_units_x = 2

if dmx.column_fixture_remove:
row.operator('dmx.force_remove_fixture', icon="CANCEL")

layout.menu('DMX_MT_Fixture', text="Fixtures", icon="OUTLINER_DATA_LIGHT")
4 changes: 3 additions & 1 deletion panels/groups.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
#

import bpy
import json

from bpy.props import (StringProperty)

Expand All @@ -21,8 +22,9 @@
class DMX_UL_Group(UIList):
def draw_item(self, context, layout, data, item, icon, active_data, active_propname, index):
icon = "GROUP_VERTEX"
fixture_count = len(json.loads(item.dump))
if self.layout_type in {'DEFAULT', 'COMPACT'}:
layout.label(text = item.name, icon = icon)
layout.label(text = f"{item.name} ({fixture_count})", icon = icon)
elif self.layout_type in {'GRID'}:
layout.alignment = 'CENTER'
layout.label(text="", icon = icon)
Expand Down
Loading