problems to edit diffuse color from def draw...

Hi all,

I’m a bit lost (due to my lacks in python…).
I wrote a thermic plugin for architecture, with a part dedicated to ‘R’ calculation and attribution of A++,A+,A,B… labels.
Everything works almost fine (even external icons) but the ultimate goal would be to change the diffuse color of the material in function of this label(result).
At this stage I’m into a def draw, and the codes I’ve commented in the image always return me ’ Writing to ID classes in this context is not allowed’.
Does anyone have an idea on a workaround?


codes and test scene can be found here:
http://www.tmaes.be/web/fr/component/phocadownload/category/1-artoki.html?download=1:artoki-energy-0-0-7

I hope I’ve been understandable, thanks in advance!


tmaes

edit:
to be complete I also tried to pass by a button that edits all material slots with a color parameter(here is the class code where mat color is a material custom property):

def execute(self, context):
for i in bpy.context.active_object.material_slots:
#print(i)
print(i.material.diffuse_color)
print(i.material.mat_color)
i.material.diffuse_color[0]=i.material.mat_color[0]
i.material.diffuse_color[1]=i.material.mat_color[1]
i.material.diffuse_color[2]=i.material.mat_color[2]
return {‘FINISHED’}

it was nearly working, but it gave the same mat_color at every material slot…(didn’t understand why … object oriented things maybe)

Use a callback to change ID datablocks on property changes. Changing them during draw calls is not possible.

http://www.blender.org/api/blender_python_api_2_74_release/bpy.props.html#update-example

Ok, thank you for the fast answer, let me one week to understand those 2 lines! :o ( this kind of brain sport is really a pain for me…)

Thanks again!

Here’s a minimal example:

import bpy

def update_cb(self, context):
    ob = context.object
    for mat in ob.data.materials:
        if self.prop <= 3.3:
            mat.diffuse_color = (1, 0, self.prop * 0.05)
        elif self.prop <= 6.6:
            mat.diffuse_color = (0, 1 * (1 - self.prop * 0.1), 0)
        else:
            mat.diffuse_color = (0, 0, 1 * (2 - self.prop * 0.2))

bpy.types.Object.prop = bpy.props.FloatProperty(min=0, max=10, update=update_cb)

def draw_func(self, context):
    layout = self.layout
    layout.prop(context.object, "prop")
    
bpy.types.MATERIAL_PT_context_material.prepend(draw_func)

Run the code in text editor, then select an object with material and go to Material tab. Slide the slider at the very top of the panel and see the diffuse color changing (conditions and color calculations are fully arbitrary).

thanks 1000 times it’s exactly that… I tried your 1st code yesterday and had almost understood.*

is it the last line(of the second sample) that explains to draw it in material panel? I tried before (without success :slight_smile: ) to put props like this at the top of this panel…

  • in fact seeing that it worked I tried it and got stuck on an other part of my code:D:
    in the beginning of the script I create props for the different layers that can compose a wall. In the panel, if you tell (in a prop) that there are 5 layers, it has to prepare 5 sets of props etc… as I was unable to do it dynamicly, I created it the hard way, by creating 10 sets of props:
bpy.types.Material.mat_depth_1 = bpy.props.FloatProperty(name="Material 1 depth",precision=1)
bpy.types.Material.mat_depth_2 = bpy.props.FloatProperty(name="Material 2 depth",precision=1)
bpy.types.Material.mat_depth_3 = bpy.props.FloatProperty(name="Material 3 depth",precision=1)
bpy.types.Material.mat_depth_4 = bpy.props.FloatProperty(name="Material 4 depth",precision=1)
bpy.types.Material.mat_depth_5 = bpy.props.FloatProperty(name="Material 5 depth",precision=1)
bpy.types.Material.mat_depth_6 = bpy.props.FloatProperty(name="Material 6 depth",precision=1)
bpy.types.Material.mat_depth_7 = bpy.props.FloatProperty(name="Material 7 depth",precision=1)
bpy.types.Material.mat_depth_8 = bpy.props.FloatProperty(name="Material 8 depth",precision=1)
bpy.types.Material.mat_depth_9 = bpy.props.FloatProperty(name="Material 9 depth",precision=1)
bpy.types.Material.mat_depth_10 = bpy.props.FloatProperty(name="Material 10 depth",precision=1)

I thought with your callback that I could do it a more sexy way, but I got stuck when i try to pass a variable in the prop type declaration : (weird code direct from my brain, I can figure it’s absurd to pass a string there)


for i in range(5):
bpy.types.Material.mat_depth_+str(i) = bpy.props.FloatProperty(name="Material "+str(i)+" depth",precision=1)

I post it in case you have ideas on this too (and I go back to try by myself)

best regards!


tmaes

The last line prepends a draw function to the existing material panel indeed (PT stands for panel type). You can create your own panel too of course, but for testing purposes, I find it easier to add to existing panels. Own panels will usually appear below all others by default, but you can re-order them if needed.

If you need a fixed number of float properties, and no more than 32, it’s advisable to use FloatVectorProperty() instead of multiple FloatProperty()s.

For a dynamic amount of properties, use CollectionProperty(). You could use an additional IntProperty() with callback to control the amount of elements in the collection, but I wouldn’t recommend that. It’s usually better if the user can add and remove elements as necessary via a template_list with + and - buttons (like for materials).

bpy.types.Material.mat_depth_+str(i) is a syntax error. Correct would be:

setattr(bpy.types.Material, "mat_depth_" + str(i), bpy.props.FloatProperty())

you made my day (uh … month)

cheers!