2

Bug in addon to change header color dynamically

I made an add-on that changes the theme color of the header if the automatic keyframe feature is enabled.

The color change function works fine.

However, the following bug occurs in the object gizmo transform gizmo.

  • Mouse hovers no longer highlight
  • Drag operation is delayed a little

    Why do bugs occur in Gizmo by changing the theme color? I have no idea.

enter image description here

python

import bpy

bl_info = {
    "name" : "header_color_change",
    "author" : "Bookyakuno",
    "version" : (1, 0, 0),
    "blender" : (2, 80, 0),
    "location" : "hoge",
    "description" : "hoge",
    "category" : "UI"
}


def TEST_HT_header_color_change(self, context):
    layout = self.layout
    layout.label(text="")


    if bpy.context.scene.tool_settings.use_keyframe_insert_auto == True:
        bpy.context.preferences.themes[0].topbar.space.header = (0.4, 0.000000, 0.000000, 1.000000)

    else:
        bpy.context.preferences.themes[0].topbar.space.header = (0.137255, 0.137255, 0.137255, 1.000000)

    return {'FINISHED'}


def register():
    bpy.types.TOPBAR_HT_upper_bar.append(TEST_HT_header_color_change)

def unregister():
    bpy.types.TOPBAR_HT_upper_bar.remove(TEST_HT_header_color_change)

if __name__ == "__main__":
    register()

'''

Duarte Farrajota Ramos
  • 59,425
  • 39
  • 130
  • 187
Bookyakuno
  • 43
  • 1
  • 6

2 Answers2

3

I think that the issue comes from changing preference data during a UI draw, that is, you are accessing data that should not be altered while drawing the UI.

An alternative approach that seems to work is using handlers to alter the theme settings. In 2.80 the scene_update_* handlers have been renamed to depsgraph_update_*.

def TEST_prefset(scene):
    prefs = bpy.context.preferences

    if scene.tool_settings.use_keyframe_insert_auto == True:
        prefs.themes[0].topbar.space.header = (0.4, 0.000000, 0.000000, 1.000000)

    else:
        prefs.themes[0].topbar.space.header = (0.137255, 0.137255, 0.137255, 1.000000)


def register():
    bpy.app.handlers.depsgraph_update_post.append(TEST_prefset)

def unregister():
    bpy.app.handlers.depsgraph_update_post.remove(TEST_prefset)
sambler
  • 55,387
  • 3
  • 59
  • 192
  • I found that my method was not appropriate.

    The code attached to the reference fixed the Gizmo bug, but it didn't load at Blender startup and it didn't work (it will work if you reload the add-on itself every time). Therefore, I improved it to read by "load_post" using "persistent", This method is loaded at boot time.

    Thank you for teaching me the handler. header_color_change.py - github

    – Bookyakuno Jun 07 '19 at 14:26
1

In a draw callback

As an alternative to using onload and update handlers, could make it a draw callback on the 3d view space.

The added bonus here is can write some text to screen, in addition to or instead of colouring header.

EDIT minor adjustment to keep themes bg color. Only tested running from console.

import blf
import bpy

bl_info = { "name": "New Object", "author": "Your Name Here", "version": (1, 0), "blender": (2, 80, 0), "location": "View3D > Add > Mesh > New Object", "description": "Adds a new Mesh Object", "warning": "", "wiki_url": "", "category": "Add Mesh", }

highlight_color = (0.4, 0, 0, 1)

class DrawingClass: def init(self, prop): print("INT DC") from bpy import context self.prop = prop self.col = context.preferences.themes[0].topbar.space.header[:] self.handle = bpy.types.SpaceView3D.draw_handler_add( self.draw_text_callback, (), 'WINDOW', 'POST_PIXEL')

def draw_text_callback(self):
    from bpy import context
    font_id = 0  # XXX, need to find out how best to get this.
    if not hasattr(context, "scene"):
        return None
    scene = context.scene
    if scene.tool_settings.use_keyframe_insert_auto:
        context.preferences.themes[0].topbar.space.header = highlight_color
        # draw some text
        blf.position(font_id, 15, 50, 0)
        blf.size(font_id, 20, 72)
        blf.draw(font_id, "%s %s" % (context.scene.name, self.prop))

    else:
        context.preferences.themes[0].topbar.space.header = self.col

def remove_handle(self):
    from bpy import context
    context.preferences.themes[0].topbar.space.header = self.col
    bpy.types.SpaceView3D.draw_handler_remove(self.handle, 'WINDOW')


dc = None

def register(): global dc dc = DrawingClass("Draw This On Screen")

def unregister(): global dc if dc: dc.remove_handle() dc = None

if name == "main": register()

batFINGER
  • 84,216
  • 10
  • 108
  • 233