Page Menu
Home
Search
Configure Global Search
Log In
Files
F18839
development_macros_recorder.py
Public
Actions
Download File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Award Token
Authored By
dima glib (dairin0d)
Nov 13 2013, 4:12 PM
Size
12 KB
Subscribers
None
development_macros_recorder.py
View Options
# ***** BEGIN GPL LICENSE BLOCK *****
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
# ***** END GPL LICENSE BLOCK *****
# <pep8-80 compliant>
bl_info
=
{
"name"
:
"Macros Recorder"
,
"author"
:
"dairin0d"
,
"version"
:
(
1
,
0
),
"blender"
:
(
2
,
6
,
0
),
"location"
:
"Text Editor -> Text -> Record Macro"
,
"description"
:
"Record macros to text blocks"
,
"warning"
:
""
,
"wiki_url"
:
"http://wiki.blender.org/index.php/Extensions:2.6/Py/"
\
"Scripts/Development/Macros_Recorder"
,
"tracker_url"
:
"http://projects.blender.org/tracker/"
\
"?func=detail&aid=31325"
,
"category"
:
"Development"
}
#============================================================================#
import
bpy
from
mathutils
import
Vector
class
StringItem
(
bpy
.
types
.
PropertyGroup
):
value
=
bpy
.
props
.
StringProperty
()
class
SceneMacros
(
bpy
.
types
.
PropertyGroup
):
ops
=
bpy
.
props
.
CollectionProperty
(
type
=
StringItem
)
def
clear
(
self
):
while
self
.
ops
:
self
.
ops
.
remove
(
0
)
def
make_entry
(
self
,
op
):
idname
=
op
.
bl_idname
.
replace
(
"_OT_"
,
"."
)
.
lower
()
props
=
op
.
properties
rna_props
=
op
.
rna_type
.
properties
args
=
[]
for
k
,
v
in
props
.
items
():
rna_prop
=
rna_props
[
k
]
prop_type
=
rna_prop
.
type
if
prop_type
==
'ENUM'
:
if
not
rna_prop
.
enum_items
:
# Somebody forgot to declare items for this enum.
# We can only ignore this property.
continue
v
=
repr
(
rna_prop
.
enum_items
[
v
]
.
identifier
)
else
:
is_array
=
(
type
(
v
)
.
__name__
==
"IDPropertyArray"
)
if
is_array
:
if
prop_type
==
'BOOLEAN'
:
v
=
tuple
(
bool
(
item
)
for
item
in
v
)
else
:
v
=
tuple
(
v
)
elif
prop_type
==
'BOOLEAN'
:
v
=
bool
(
v
)
args
.
append
(
"
%s
=
%s
"
%
(
k
,
v
))
return
(
"bpy.ops.
%s
(
%s
)"
%
(
idname
,
", "
.
join
(
args
)))
def
_add
(
self
,
op
):
if
isinstance
(
op
,
str
):
entry
=
op
else
:
entry
=
self
.
make_entry
(
op
)
op_storage
=
self
.
ops
.
add
()
op_storage
.
value
=
entry
def
add
(
self
,
op
):
self
.
_add
(
op
)
def
add_diff
(
self
,
diff
):
for
op
in
diff
:
self
.
_add
(
op
)
def
replace_last
(
self
,
op
):
if
not
self
.
ops
:
op_storage
=
self
.
ops
.
add
()
else
:
op_storage
=
self
.
ops
[
len
(
self
.
ops
)
-
1
]
op_storage
.
value
=
self
.
make_entry
(
op
)
def
write_macro_text
(
self
,
textblock
):
textblock
.
clear
()
code_template
=
\
"""
import bpy
from mathutils import Vector
class MacroOperator(bpy.types.Operator):
bl_idname = "macro.{0}"
bl_label = "{1}"
def execute(self, context):
{2}
return {3}
def register():
bpy.utils.register_module(__name__)
def unregister():
bpy.utils.unregister_module(__name__)
if __name__ == "__main__":
register()
"""
.
strip
()
op_name
=
textblock
.
name
.
replace
(
"."
,
"_"
)
op_label
=
bpy
.
path
.
display_name
(
textblock
.
name
.
replace
(
"."
,
" "
))
tabs
=
" "
lines
=
"
\n
"
.
join
((
tabs
+
op
.
value
)
for
op
in
self
.
ops
)
code
=
code_template
.
format
(
op_name
,
op_label
,
lines
,
"{'FINISHED'}"
)
textblock
.
write
(
code
)
class
SceneDiff
:
def
__init__
(
self
,
context
):
scene
=
context
.
scene
wm
=
context
.
window_manager
self
.
scene_hash
=
hash
(
scene
)
self
.
operators_count
=
len
(
wm
.
operators
)
self
.
selected
=
None
self
.
active
=
None
self
.
cursor
=
None
self
.
pivot
=
None
self
.
pivot_align
=
None
self
.
orientation
=
None
def
process
(
self
,
context
):
scene
=
context
.
scene
undo_redo
=
False
scene_hash
=
hash
(
scene
)
if
self
.
scene_hash
!=
scene_hash
:
self
.
scene_hash
=
scene_hash
undo_redo
=
True
active_obj
=
context
.
object
selected
=
set
(
obj
.
name
for
obj
in
context
.
selected_objects
)
active
=
(
active_obj
.
name
if
active_obj
else
None
)
cursor
=
Vector
(
scene
.
cursor_location
)
v3d
=
MacroRecorder
.
v3d
if
v3d
:
cursor
=
v3d
.
cursor_location
pivot
=
v3d
.
pivot_point
pivot_align
=
v3d
.
use_pivot_point_align
orientation
=
v3d
.
transform_orientation
else
:
pivot
=
None
pivot_align
=
None
orientation
=
None
if
self
.
selected
is
None
:
self
.
selected
=
selected
if
self
.
active
is
None
:
self
.
active
=
active
if
self
.
cursor
is
None
:
self
.
cursor
=
cursor
if
self
.
pivot
is
None
:
self
.
pivot
=
pivot
if
self
.
pivot_align
is
None
:
self
.
pivot_align
=
pivot_align
if
self
.
orientation
is
None
:
self
.
orientation
=
orientation
is_updated
=
False
if
active_obj
:
if
'EDIT'
in
active_obj
.
mode
:
if
active_obj
.
is_updated
or
active_obj
.
is_updated_data
:
is_updated
=
True
data
=
active_obj
.
data
if
data
.
is_updated
or
data
.
is_updated_data
:
is_updated
=
True
wm
=
context
.
window_manager
operators_count
=
len
(
wm
.
operators
)
if
(
operators_count
!=
self
.
operators_count
)
or
undo_redo
or
is_updated
:
n_added
=
operators_count
-
self
.
operators_count
if
n_added
>
0
:
scene
.
macros
.
add_diff
(
wm
.
operators
[
-
n_added
:])
elif
undo_redo
:
scene
.
macros
.
add_diff
(
wm
.
operators
)
elif
is_updated
and
(
n_added
==
0
)
and
wm
.
operators
:
scene
.
macros
.
replace_last
(
wm
.
operators
[
-
1
])
self
.
operators_count
=
operators_count
else
:
selected_diff
=
selected
.
difference
(
self
.
selected
)
unselected_diff
=
self
.
selected
.
difference
(
selected
)
prefix
=
"context.scene.objects"
for
name
in
unselected_diff
:
scene
.
macros
.
add
(
"
%s
[
%s
].select = False"
%
(
prefix
,
repr
(
name
)))
for
name
in
selected_diff
:
scene
.
macros
.
add
(
"
%s
[
%s
].select = True"
%
(
prefix
,
repr
(
name
)))
if
active
!=
self
.
active
:
scene
.
macros
.
add
(
"{0}.active = {0}[{1}]"
.
format
(
prefix
,
repr
(
name
)))
if
cursor
!=
self
.
cursor
:
cursor_context
=
(
"space_data"
if
v3d
else
"scene"
)
scene
.
macros
.
add
(
"context.
%s
.cursor_location =
%s
"
%
(
cursor_context
,
repr
(
cursor
)))
if
(
pivot
is
not
None
)
and
(
pivot
!=
self
.
pivot
):
scene
.
macros
.
add
(
"context.space_data.pivot_point =
%s
"
%
repr
(
pivot
))
if
(
pivot_align
is
not
None
)
and
(
pivot_align
!=
self
.
pivot_align
):
scene
.
macros
.
add
(
"context.space_data."
\
"use_pivot_point_align =
%s
"
%
repr
(
pivot_align
))
if
(
orientation
is
not
None
)
and
(
orientation
!=
self
.
orientation
):
scene
.
macros
.
add
(
"context.space_data."
\
"transform_orientation =
%s
"
%
repr
(
orientation
))
if
selected
!=
self
.
selected
:
self
.
selected
=
selected
if
active
!=
self
.
active
:
self
.
active
=
active
if
cursor
!=
self
.
cursor
:
self
.
cursor
=
cursor
if
pivot
!=
self
.
pivot
:
self
.
pivot
=
pivot
if
pivot_align
!=
self
.
pivot_align
:
self
.
pivot_align
=
pivot_align
if
orientation
!=
self
.
orientation
:
self
.
orientation
=
orientation
is_macro_recording
=
False
macro_window
=
None
macro_recorder
=
None
def
process_diff
(
scene
):
if
not
is_macro_recording
:
return
if
bpy
.
context
.
window
!=
macro_window
:
return
macro_recorder
.
process
(
bpy
.
context
)
class
MacroRecorder
(
bpy
.
types
.
Operator
):
"""Record operators to a text block"""
bl_idname
=
"wm.record_macro"
bl_label
=
"Toggle macro recording"
v3d
=
None
@classmethod
def
poll
(
cls
,
context
):
return
context
.
space_data
.
type
in
{
'TEXT_EDITOR'
,
'VIEW_3D'
}
def
invoke
(
self
,
context
,
event
):
global
is_macro_recording
global
macro_window
global
macro_recorder
if
not
is_macro_recording
:
macro_recorder
=
SceneDiff
(
context
)
for
scene
in
bpy
.
data
.
scenes
:
scene
.
macros
.
clear
()
is_macro_recording
=
True
macro_window
=
context
.
window
bpy
.
ops
.
ed
.
undo_push
(
message
=
"Record Macro"
)
if
context
.
space_data
.
type
==
'VIEW_3D'
:
MacroRecorder
.
v3d
=
context
.
space_data
else
:
MacroRecorder
.
v3d
=
None
#for scene in bpy.data.scenes:
# scene.macros.clear()
else
:
text_block
=
bpy
.
data
.
texts
.
new
(
"macro"
)
context
.
scene
.
macros
.
write_macro_text
(
text_block
)
if
context
.
space_data
.
type
==
'TEXT_EDITOR'
:
context
.
space_data
.
text
=
text_block
else
:
self
.
report
({
'INFO'
},
"Created
%s
"
%
text_block
.
name
)
is_macro_recording
=
False
macro_window
=
None
macro_text_block
=
None
MacroRecorder
.
v3d
=
None
bpy
.
ops
.
ed
.
undo_push
(
message
=
"End Recording"
)
macro_recorder
=
None
return
{
'FINISHED'
}
def
menu_func_draw
(
self
,
context
):
text
=
(
"Recording... (Stop)"
if
is_macro_recording
else
"Record Macro"
)
icon
=
(
'CANCEL'
if
is_macro_recording
else
'REC'
)
self
.
layout
.
operator
(
"wm.record_macro"
,
text
=
text
,
icon
=
icon
)
class
VIEW3D_PT_macro
(
bpy
.
types
.
Panel
):
bl_space_type
=
'VIEW_3D'
bl_region_type
=
'TOOLS'
bl_label
=
"Macro"
def
draw
(
self
,
context
):
pass
def
draw_header
(
self
,
context
):
icon
=
(
'CANCEL'
if
is_macro_recording
else
'REC'
)
self
.
layout
.
operator
(
"wm.record_macro"
,
text
=
""
,
icon
=
icon
)
#============================================================================#
def
register
():
bpy
.
utils
.
register_class
(
StringItem
)
bpy
.
utils
.
register_class
(
SceneMacros
)
bpy
.
utils
.
register_class
(
MacroRecorder
)
bpy
.
utils
.
register_class
(
VIEW3D_PT_macro
)
bpy
.
types
.
Scene
.
macros
=
bpy
.
props
.
PointerProperty
(
type
=
SceneMacros
)
bpy
.
types
.
TEXT_MT_text
.
append
(
menu_func_draw
)
bpy
.
app
.
handlers
.
scene_update_post
.
append
(
process_diff
)
def
unregister
():
bpy
.
app
.
handlers
.
scene_update_post
.
remove
(
process_diff
)
bpy
.
types
.
TEXT_MT_text
.
remove
(
menu_func_draw
)
del
bpy
.
types
.
Scene
.
macros
bpy
.
utils
.
unregister_class
(
VIEW3D_PT_macro
)
bpy
.
utils
.
unregister_class
(
MacroRecorder
)
bpy
.
utils
.
unregister_class
(
SceneMacros
)
bpy
.
utils
.
unregister_class
(
StringItem
)
if
__name__
==
"__main__"
:
register
()
File Metadata
Details
Mime Type
text/x-python
Storage Engine
local-disk
Storage Format
Raw Data
Storage Handle
c3/c1/14c7aebfbe17c0e2e12910059530
Event Timeline
Log In to Comment