Set 3 values at once in vectorProperty using get () set () (absolute location example)

it’s part of a bigger addon, but I isolated the code in a small addon. ‘double middle click’ to open the menu.

example

Projet sans titre

"""TODO: same about rotation""" 

bl_info = {
    "name": " ABSOLUTE",
    "author": "1COD",
    "version": (1, 0, 0),
    "blender": (2, 93, 0),
    "location": "View3D",
    "description": "children absolute coordinates double midle click",
    "warning": "",
    "wiki_url": "",
    "category": "Menu"
}

import bpy
from mathutils import Vector, Matrix

class ABSOLUTE_properties(bpy.types.PropertyGroup):
    def get_float(self):
        ob = bpy.context.active_object
        if not ob:
            return
        if self.get('abs', None):
            return ob.matrix_world.translation 
        else:
            return ob.location


    def set_float(self, value):
        self["Temp"] = value

    def update_float(self, context):
        ob = context.active_object
        if not ob:
            return
        loc = self.Temp
        if self.abs:
            mw = ob.matrix_world
            if ob.parent and ob.parent_type in {'VERTEX', 'VERTEX_3'}:
                ob.location += ob.parent.matrix_world.to_quaternion().to_matrix().to_4x4().inverted()@(Vector(loc)-mw.translation)
            else:
                mw.translation = Vector(loc)            
        else:
            ob.location = Vector(loc) 
            
    abs: bpy.props.BoolProperty()
    Temp: bpy.props.FloatVectorProperty(subtype='XYZ',)
    abs_location : bpy.props.FloatVectorProperty(
    get=get_float,
    set=set_float,
    update=update_float,
    subtype='XYZ',
    name = "Position",
    options={'ANIMATABLE'}, 
    precision = 4
    )

    @classmethod
    def register(cls):
        bpy.types.Scene.acc = bpy.props.PointerProperty(type=cls)

    @classmethod
    def unregister(cls):
        del bpy.types.Scene.acc


class ABSOLUTE_PT_child_coordinates(bpy.types.Panel):
    bl_label = "absolute child coordinates menu"
    bl_space_type = 'PROPERTIES'
    bl_region_type = 'WINDOW'
    bl_context = "0data"
    # bl_options = {'DEFAULT_CLOSED'}
    bl_ui_units_x = 9

    def draw(self, context):
        layout = self.layout
        object = context.object
        scene = context.scene
        layout.separator(factor=2)
        layout.column().prop(scene.acc, "abs", text="Absolute Location")
        layout.column().label(text='(enter x/y/z in 3 steps)')
        label = "Absolute Loc (parented objects)" if scene.acc.abs else "Location"
        layout.column().prop(scene.acc, "abs_location", text=label)


classes = (ABSOLUTE_properties, ABSOLUTE_PT_child_coordinates)

addon_keymaps = []


def register():
    for cls in classes:
        bpy.utils.register_class(cls)
    wm = bpy.context.window_manager
    kc = wm.keyconfigs.addon

    if kc:
        km = wm.keyconfigs.addon.keymaps.new(
            name='3D View', space_type='VIEW_3D')
        kmi = km.keymap_items.new('wm.call_panel', 'MIDDLEMOUSE', 'DOUBLE_CLICK')
        kmi.properties.name = "ABSOLUTE_PT_child_coordinates"
        kmi.properties.keep_open = True
        addon_keymaps.append((km, kmi))


def unregister():
    for cls in classes:
        bpy.utils.unregister_class(cls)

    wm = bpy.context.window_manager
    kc = wm.keyconfigs.addon
    if kc is not None:
        for km, kmi in addon_keymaps:
            km.keymap_items.remove(kmi)

    addon_keymaps.clear()

if __name__ == "__main__":
    register()

the problem is that I can’t set 3 coordinates at once like over a normal location prop in the blender tool menu

Forgive if I misunderstand, but…

loc = self.Temp

Both of these are technically pointers to the original data. If I understand your issue correctly, you change the variables when you first change. shallow copy vs. deepcopy

1 Like

do you think putting a deepcopy() somewhere could solve the problem?

well it was not super easy but now this is working :slight_smile:

Projet sans titre

if you have a location like (1,0,0) and you enter 2,2,2
“value”, in the set, is (2,0,0) the first round, then (1,2,0) this is first coords x and z 1,0 and the 2 between and so then (1,0,2)
so we replace each round one value in the final location. I created some properties to permute values and one boolvectorproperty to not replace same value twice.

"""TODO: same about rotation""" 

bl_info = {
    "name": " ABSOLUTE",
    "author": "1COD",
    "version": (1, 0, 0),
    "blender": (2, 93, 0),
    "location": "View3D",
    "description": "children absolute coordinates double midle click",
    "warning": "",
    "wiki_url": "",
    "category": "Menu"
}

import bpy
from mathutils import Vector, Matrix
from copy import deepcopy

class ABSOLUTE_properties(bpy.types.PropertyGroup):

    def get_float(self):
        ob = bpy.context.active_object
        if not ob:
            return

        if self.abs:
            self.Temp0 = ob.matrix_world.translation[:]
            return ob.matrix_world.translation 
        else:
            self.Temp0 = ob.location[:]
            return ob.location
            
    def set_float(self, value):
        Temp = self.Temp
        Temp0 = self.Temp0
        Temp1 = self.Temp1
        if value[0] != Temp0[0] and not Temp1[0]:
            Temp[0] = value[0]
            Temp1[0] = True
        if value[1] != Temp0[1] and not Temp1[1]:
            Temp[1] = value[1]
            Temp1[1] = True
        if value[2] != Temp0[2] and not Temp1[2]:
            Temp[2] = value[2]
            Temp1[2]=True

    def update_float(self, context):
        ob = context.active_object
        if not ob:
            return

        loc = self.Temp
        if self.abs:
            mw = ob.matrix_world
            if ob.parent and ob.parent_type in {'VERTEX', 'VERTEX_3'}:
                ob.location += ob.parent.matrix_world.to_quaternion().to_matrix().to_4x4().inverted()@(Vector(loc)-mw.translation)
            else:
                mw.translation = Vector(loc)            
        else:
            ob.location = Vector(loc)
            print('loc###',loc)
        self.Temp1 =(False,False,False)
            
    abs: bpy.props.BoolProperty()
    Temp: bpy.props.FloatVectorProperty(subtype='XYZ',)
    Temp0: bpy.props.FloatVectorProperty(subtype='XYZ',)
    Temp1: bpy.props.BoolVectorProperty(size=3)
    abs_location : bpy.props.FloatVectorProperty(
    get=get_float,
    set=set_float,
    update=update_float,
    subtype='XYZ',
    name = "Position",
    options={'ANIMATABLE'}, 
    precision = 4
    )

    @classmethod
    def register(cls):
        bpy.types.Scene.acc = bpy.props.PointerProperty(type=cls)

    @classmethod
    def unregister(cls):
        del bpy.types.Scene.acc


class ABSOLUTE_PT_child_coordinates(bpy.types.Panel):
    bl_label = "absolute child coordinates menu"
    bl_space_type = 'PROPERTIES'
    bl_region_type = 'WINDOW'
    bl_context = ""
    bl_ui_units_x = 9

    def draw(self, context):
        layout = self.layout
        object = context.object
        scene = context.scene
        layout.separator(factor=2)
        layout.column().prop(scene.acc, "abs", text="Absolute Location")
        label = "Absolute Loc (on children)" if scene.acc.abs else "Location"
        layout.column().prop(scene.acc, "abs_location", text=label)


classes = (ABSOLUTE_properties, ABSOLUTE_PT_child_coordinates)

addon_keymaps = []


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

    wm = bpy.context.window_manager
    kc = wm.keyconfigs.addon

    if kc:
        km = wm.keyconfigs.addon.keymaps.new(
            name='3D View', space_type='VIEW_3D')
        kmi = km.keymap_items.new('wm.call_panel', 'MIDDLEMOUSE', 'DOUBLE_CLICK')
        kmi.properties.name = "ABSOLUTE_PT_child_coordinates"
        kmi.properties.keep_open = True
        addon_keymaps.append((km, kmi))


def unregister():
    for cls in classes:
        bpy.utils.unregister_class(cls)

    wm = bpy.context.window_manager
    kc = wm.keyconfigs.addon
    if kc is not None:
        for km, kmi in addon_keymaps:
            km.keymap_items.remove(kmi)

    addon_keymaps.clear()

if __name__ == "__main__":
    register()