File: space_properties.py

package info (click to toggle)
blender 4.3.2%2Bdfsg-2
  • links: PTS, VCS
  • area: main
  • in suites: sid, trixie
  • size: 309,564 kB
  • sloc: cpp: 2,385,210; python: 330,236; ansic: 280,972; xml: 2,446; sh: 972; javascript: 317; makefile: 170
file content (154 lines) | stat: -rw-r--r-- 5,042 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
# SPDX-FileCopyrightText: 2009-2023 Blender Authors
#
# SPDX-License-Identifier: GPL-2.0-or-later

from bpy.types import Header, Panel
from rna_prop_ui import PropertyPanel


class PROPERTIES_HT_header(Header):
    bl_space_type = 'PROPERTIES'

    def draw(self, context):
        layout = self.layout
        view = context.space_data
        region = context.region
        ui_scale = context.preferences.system.ui_scale

        layout.template_header()

        layout.separator_spacer()

        # The following is an ugly attempt to make the search button center-align better visually.
        # A dummy icon is inserted that has to be scaled as the available width changes.
        content_size_est = 160 * ui_scale
        layout_scale = min(1, max(0, (region.width / content_size_est) - 1))
        if layout_scale > 0:
            row = layout.row()
            row.scale_x = layout_scale
            row.label(icon='BLANK1')

        layout.prop(view, "search_filter", icon='VIEWZOOM', text="")

        layout.separator_spacer()

        layout.popover(panel="PROPERTIES_PT_options", text="")


class PROPERTIES_PT_navigation_bar(Panel):
    bl_space_type = 'PROPERTIES'
    bl_region_type = 'NAVIGATION_BAR'
    bl_label = "Navigation Bar"
    bl_options = {'HIDE_HEADER'}

    def draw(self, context):
        layout = self.layout

        view = context.space_data

        layout.scale_x = 1.4
        layout.scale_y = 1.4
        if view.search_filter:
            layout.prop_tabs_enum(
                view, "context", data_highlight=view,
                property_highlight="tab_search_results", icon_only=True,
            )
        else:
            layout.prop_tabs_enum(view, "context", icon_only=True)


class PROPERTIES_PT_options(Panel):
    """Show options for the properties editor"""
    bl_space_type = 'PROPERTIES'
    bl_region_type = 'HEADER'
    bl_label = "Options"

    def draw(self, context):
        layout = self.layout

        space = context.space_data

        col = layout.column()
        col.label(text="Sync with Outliner")
        col.row().prop(space, "outliner_sync", expand=True)


class PropertiesAnimationMixin:
    """Mix-in class for Animation panels.

    This class can be used to show a generic 'Animation' panel for IDs shown in
    the properties editor. Specific ID types need specific subclasses.

    For an example, see DATA_PT_camera_animation in properties_data_camera.py
    """
    bl_space_type = 'PROPERTIES'
    bl_region_type = 'WINDOW'
    bl_context = "data"
    bl_label = "Animation"
    bl_options = {'DEFAULT_CLOSED'}
    bl_order = PropertyPanel.bl_order - 1  # Order just above the Custom Properties.

    _animated_id_context_property = ""
    """context.{_animatable_id_context_property} is used to find the animated ID."""

    @classmethod
    def _animated_id(cls, context):
        assert cls._animated_id_context_property, "set _animated_id_context_property on {!r}".format(cls)

        # If the pinned ID is of a different type, there could still be a an ID
        # for which to show this panel. For example, a camera object can be
        # pinned, and then this panel can be shown for its camera data.
        return getattr(context, cls._animated_id_context_property, None)

    @classmethod
    def poll(cls, context):
        animated_id = cls._animated_id(context)
        return animated_id is not None

    def draw(self, context):
        layout = self.layout

        col = layout.column(align=True)
        col.use_property_split = True
        col.use_property_decorate = False
        self.draw_action_and_slot_selector(context, col, self._animated_id(context))

    @classmethod
    def draw_action_and_slot_selector(cls, context, layout, animated_id):
        if not animated_id:
            class_list = [c.__name__ for c in cls.mro()]
            print("PropertiesAnimationMixin: no animatable data-block, this is a bug "
                  "in one of these classes: {!r}".format(class_list))
            layout.label(text="No animatable data-block, please report as bug", icon='ERROR')
            return

        layout.template_action(animated_id, new="action.new", unlink="action.unlink")

        if not context.preferences.experimental.use_animation_baklava:
            return

        adt = animated_id.animation_data
        if not adt or not adt.action:
            return

        # Only show the slot selector when a layered Action is assigned.
        if adt.action.is_action_layered:
            layout.context_pointer_set("animated_id", animated_id)
            layout.template_search(
                adt, "action_slot",
                adt, "action_slots",
                new="anim.slot_new_for_id",
                unlink="anim.slot_unassign_from_id",
            )


classes = (
    PROPERTIES_HT_header,
    PROPERTIES_PT_navigation_bar,
    PROPERTIES_PT_options,
)

if __name__ == "__main__":  # only for live edit.
    from bpy.utils import register_class
    for cls in classes:
        register_class(cls)