Professional Documents
Culture Documents
Space View3d Screencast Keys - Py
Space View3d Screencast Keys - Py
Space View3d Screencast Keys - Py
#
# 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 2
# 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, write to the Free Software Foundation,
# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
#
# ##### END GPL LICENSE BLOCK #####
# <pep8 compliant>
bl_info = {
"name": "Screencast Keys",
"author": "Paulo Gomes, Bart Crouch, John E. Herrenyo, Gaia Clary, Pablo
Vazquez",
"version": (1, 7),
"blender": (2, 66, 0),
"location": "3D View > Properties Panel > Screencast Keys",
"warning": "",
"description": "Display keys pressed in the 3D View, "
"useful for screencasts.",
"wiki_url": "http://wiki.blender.org/index.php/Extensions:2.6/"
"Py/Scripts/3D_interaction/Screencast_Key_Status_Tool",
"tracker_url": "http://projects.blender.org/tracker/index.php?"
"func=detail&aid=21612",
"category": "3D View"}
import bgl
import blf
import bpy
import time
import datetime
MOUSE_RATIO = 0.535
def getDisplayLocation(context):
scene = context.scene
mouse_size = scene.screencast_keys_mouse_size
return(pos_x, pos_y)
return(current_width, current_height)
font_size = sc.screencast_keys_font_size
mouse_size = sc.screencast_keys_mouse_size
box_draw = sc.screencast_keys_box_draw
pos_x, pos_y = getDisplayLocation(context)
label_time_max = sc.screencast_keys_fade_time
keypos_x = pos_x
if sc.screencast_keys_mouse_position == 'left':
keypos_x += mouse_size * MOUSE_RATIO * 1.7
if sc.screencast_keys_mouse != 'icon':
keypos_x -= mouse_size * MOUSE_RATIO
if sc.screencast_keys_mouse_position == 'right' and sc.screencast_keys_mouse !=
'icon':
keypos_x = pos_x
shift = 0
# we want to make sure we can shift vertically the text if the mouse is big,
# but don't care if aligned to right
if mouse_size > font_size*row_count and not sc.screencast_keys_mouse_position
== 'right':
shift = (mouse_size - font_size*row_count) / 2
for i in range(len(self.key)):
label_time = time.time() - self.time[i]
if label_time < label_time_max: # only display key-presses of last 2
seconds
if label_time > (label_time_max / 1.2):
blf.blur(0, 1)
if label_time > (label_time_max / 1.1):
blf.blur(0, 3)
keypos_y = pos_y + shift + font_size*(i+0.1)
# remove blurriness
for i in range(len(self.mouse)):
click_time = time.time() - self.mouse_time[i]
if click_time < 2:
shape = map_mouse_event(self.mouse[i])
if shape:
alpha = min(1.0, max(0.0, 2 * (2 - click_time)))
draw_mouse(context, shape, "filled", alpha)
final = i + 1
else:
break
if not wm.screencast_keys_keys:
return
font_size = sc.screencast_keys_font_size
mouse_size = sc.screencast_keys_mouse_size
if sc.screencast_keys_mouse_position == 'right':
mouse_size = 25
box_draw = sc.screencast_keys_box_draw
pos_x, pos_y = getDisplayLocation(context)
for i in range(len(self.key)):
label_time = time.time() - self.time[i]
# Got the size right, now draw box using proper colors
box_color_r, box_color_g, box_color_b, box_color_alpha =
sc.screencast_keys_box_color
if sc.screencast_keys_show_operator:
draw_last_operator(context, pos_x, pos_y)
if sc.screencast_keys_timer_show:
draw_timer(context, pos_x, pos_y)
wm = context.window_manager
sc = context.scene
font_color_r, font_color_g, font_color_b, font_color_alpha =
sc.screencast_keys_text_color
pos_x, pos_y = getDisplayLocation(context)
if wm.operators:
last_operator = wm.operators[-1].bl_label
blf.enable(0, blf.SHADOW)
blf.shadow_offset(0, 1, -1)
blf.shadow(0, 5, 0.0, 0.0, 0.0, 0.8)
blf.size(0, sc.screencast_keys_font_size, 36)
blf.position(0, pos_x - 14, pos_y - 30, 0)
bgl.glColor4f(font_color_r, font_color_g, font_color_b, font_color_alpha *
0.8)
blf.draw(0, "Last: %s" % (last_operator))
blf.disable(0, blf.SHADOW)
sc = context.scene
#calculate overall time
overall_time = datetime.timedelta(seconds=int(time.time() -
ScreencastKeysStatus.overall_time[0]))
#draw time
blf.size(0, sc.screencast_keys_timer_size, 72)
blf.position(0, pos_x, pos_y, 0)
bgl.glColor4f(timer_color_r, timer_color_g, timer_color_b, timer_color_alpha)
blf.draw(0, "Elapsed Time: %s" % (overall_time))
if sc.screencast_keys_mouse_position == 'left':
offset_x = pos_x
if sc.screencast_keys_mouse_position == 'right':
offset_x = context.region.width - pos_x - (mouse_size * MOUSE_RATIO)
offset_y = pos_y
if font_size > mouse_size:
offset_y += (font_size - mouse_size) / 2
shape_data = get_shape_data(shape)
bgl.glTranslatef(offset_x, offset_y, 0)
# color
r, g, b, a = sc.screencast_keys_text_color
bgl.glEnable(bgl.GL_BLEND)
bgl.glColor4f(r, g, b, alpha)
# outer shape
for i in shape_data:
shape_segment = i
shape_segment[0] = [mouse_size * k for k in shape_segment[0]]
shape_segment[1] = [mouse_size * k for k in shape_segment[1]]
shape_segment[2] = [mouse_size * k for k in shape_segment[2]]
shape_segment[3] = [mouse_size * k for k in shape_segment[3]]
if style == "outline":
bgl.glBegin(bgl.GL_LINE_STRIP)
else: # style == "filled"
bgl.glBegin(bgl.GL_TRIANGLE_FAN)
for j in range(10):
bgl.glEvalCoord1f(j / 10.0)
x, y, z = shape_segment[3]
# make sure the last vertex is indeed the last one, to avoid gaps
bgl.glVertex3f(x, y, z)
bgl.glEnd()
bgl.glDisable(bgl.GL_MAP1_VERTEX_3)
# draw interior
if style == "filled":
bgl.glBegin(bgl.GL_TRIANGLE_FAN)
for i in inner_shape:
j = [mouse_size * k for k in i]
x, y, z = j
bgl.glVertex3f(x, y, z)
bgl.glEnd()
bgl.glTranslatef(-offset_x, -offset_y, 0)
return(data)
if event == 'LEFTMOUSE':
shape = "left_button"
elif event == 'MIDDLEMOUSE':
shape = "middle_button"
elif event == 'RIGHTMOUSE':
shape = "right_button"
elif event == 'WHEELDOWNMOUSE':
shape = "middle_down_button"
elif event == 'WHEELUPMOUSE':
shape = "middle_up_button"
return(shape)
class ScreencastKeysStatus(bpy.types.Operator):
bl_idname = "view3d.screencast_keys"
bl_label = "Screencast Keys"
bl_description = "Display keys pressed in the 3D View"
last_activity = 'NONE'
_handle = None
_timer = None
@staticmethod
def handle_add(self, context):
ScreencastKeysStatus._handle =
bpy.types.SpaceView3D.draw_handler_add(draw_callback_px, (self, context), 'WINDOW',
'POST_PIXEL')
ScreencastKeysStatus._timer = context.window_manager.event_timer_add(0.075,
context.window)
@staticmethod
def handle_remove(context):
if ScreencastKeysStatus._handle is not None:
context.window_manager.event_timer_remove(ScreencastKeysStatus._timer)
bpy.types.SpaceView3D.draw_handler_remove(ScreencastKeysStatus._handle,
'WINDOW')
ScreencastKeysStatus._handle = None
ScreencastKeysStatus._timer = None
if event.type == 'TIMER':
# no input, so no need to change the display
return {'PASS_THROUGH'}
scene = context.scene
# keys that shouldn't show up in the 3D View
mouse_keys = ['MOUSEMOVE','MIDDLEMOUSE','LEFTMOUSE',
'RIGHTMOUSE', 'WHEELDOWNMOUSE','WHEELUPMOUSE']
ignore_keys = ['LEFT_SHIFT', 'RIGHT_SHIFT', 'LEFT_ALT',
'RIGHT_ALT', 'LEFT_CTRL', 'RIGHT_CTRL', 'TIMER',
'MOUSEMOVE', 'INBETWEEN_MOUSEMOVE']
if scene.screencast_keys_mouse != 'text':
ignore_keys.extend(mouse_keys)
if event.ctrl:
sc_keys.append("Ctrl ")
if event.alt:
sc_keys.append("Alt ")
if event.shift:
sc_keys.append("Shift ")
sc_amount = ""
if self.key:
#print("Is a key")
if event.type not in ignore_keys and event.type in self.key[0]:
mods = "+ ".join(sc_keys)
old_mods = "+ ".join(self.key[0].split("+ ")[:-1])
if mods == old_mods:
amount = self.key[0].split(" x")
if len(amount) >= 2:
sc_amount = " x" + str(int(amount[-1]) + 1)
else:
sc_amount = " x2"
del self.key[0]
del self.time[0]
if event.type in mouse_keys:
self.last_activity = 'MOUSE'
else:
self.last_activity = 'KEYBOARD'
#print("Last activity set to:", self.last_activity)
if not context.window_manager.screencast_keys_keys:
# stop script
ScreencastKeysStatus.handle_remove(context)
return {'CANCELLED'}
return {'PASS_THROUGH'}
class ScreencastKeysTimerReset(bpy.types.Operator):
"""Reset Timer"""
bl_idname = "view3d.screencast_keys_timer_reset"
bl_label = "Reset Timer"
bl_description = "Set the timer back to zero"
scene.screencast_keys_pos_x = bpy.props.IntProperty(
name="Position X",
description="Margin on the X axis",
default=3,
min=0,
max=100)
scene.screencast_keys_pos_y = bpy.props.IntProperty(
name="Position Y",
description="Margin on the Y axis",
default=10,
min=0,
max=100)
scene.screencast_keys_font_size = bpy.props.IntProperty(
name="Text Size",
description="Text size displayed on 3D View",
default=24, min=10, max=150)
scene.screencast_keys_mouse_size = bpy.props.IntProperty(
name="Mouse Size",
description="Mouse size displayed on 3D View",
default=33, min=10, max=150)
scene.screencast_keys_text_color = bpy.props.FloatVectorProperty(
name="Text / Icon Color",
description="Color for the text and mouse icon",
default=(1.0, 1.0, 1.0, 1.0),
min=0.1,
max=1,
subtype='COLOR',
size=4)
scene.screencast_keys_box_color = bpy.props.FloatVectorProperty(
name="Box Color",
description="Box color",
default=(0.0, 0.0, 0.0, 0.3),
min=0,
max=1,
subtype='COLOR',
size=4)
scene.screencast_keys_box_width = bpy.props.IntProperty(
name="Box Width",
description="Box default width (resizes with text if needed)",
default = 0,
min = 0,
max = 2048,
soft_max = 1024)
scene.screencast_keys_mouse = bpy.props.EnumProperty(
items=(("none", "No Mouse", "Don't display mouse events"),
("icon", "Icon", "Display graphical representation of "\
"the mouse"),
("text", "Text", "Display mouse events as text lines")),
name="Mouse Display",
description="Display mouse events",
default='icon')
scene.screencast_keys_mouse_position = bpy.props.EnumProperty(
items=(("left", "Left", "Align to the left"),
("right", "Right", "Align to the right")),
name="Icon Position",
description="Align the mouse icon on the 3D View",
default='left')
scene.screencast_keys_box_draw = bpy.props.BoolProperty(
name="Display Box",
description = "Display a bounding box behind the text",
default = True)
scene.screencast_keys_box_hide = bpy.props.BoolProperty(
name="Hide Box",
description = "Hide the box when no key is pressed",
default = False)
scene.screencast_keys_fade_time = bpy.props.FloatProperty(
name="Fade Out Time",
description = "Time in seconds for keys to last on screen",
default = 3.5,
min = 0.5,
max = 10.0,
soft_max = 5.0,
step = 10,
subtype = 'TIME')
scene.screencast_keys_show_operator = bpy.props.BoolProperty(
name="Display Last Operator",
description = "Display the last operator used",
default = True)
scene.screencast_keys_timer_show = bpy.props.BoolProperty(
name="Display Timer",
description = "Counter of the elapsed time in H:MM:SS since the script
started",
default = False)
scene.screencast_keys_timer_size = bpy.props.IntProperty(
name="Time Size",
description="Time size displayed on 3D View",
default=12, min=8, max=100)
scene.screencast_keys_timer_color = bpy.props.FloatVectorProperty(
name="Time Color",
description="Color for the time display",
default=(1.0, 1.0, 1.0, 0.3),
min=0,
max=1,
subtype='COLOR',
size=4)
wm = bpy.context.window_manager
for p in props:
if p in wm:
del wm[p]
if not wm.screencast_keys_keys:
layout.operator("view3d.screencast_keys", text="Start Display",
icon = "PLAY")
else:
layout.operator("view3d.screencast_keys", text="Stop Display",
icon = "PAUSE")
split = layout.split()
col = split.column()
sub = col.column(align=True)
sub.label(text="Size:")
sub.prop(sc, "screencast_keys_font_size", text="Text")
sub.prop(sc, "screencast_keys_mouse_size", text="Mouse")
col = split.column()
sub = col.column(align=True)
sub.label(text="Position:")
sub.prop(sc, "screencast_keys_pos_x", text="X")
sub.prop(sc, "screencast_keys_pos_y", text="Y")
row = layout.row(align=True)
row.prop(sc, "screencast_keys_text_color")
row = layout.row(align=True)
row.prop(sc, "screencast_keys_fade_time")
layout.separator()
row = layout.row(align=True)
row.prop(sc, "screencast_keys_mouse", text="Mouse")
row = layout.row(align=True)
row.enabled = sc.screencast_keys_mouse == 'icon'
row.prop(sc, "screencast_keys_mouse_position", expand=True)
layout.label(text="Display:")
row = layout.row(align=True)
row.prop(sc, "screencast_keys_box_draw", text="Box")
row = layout.row(align=True)
row.active = sc.screencast_keys_box_draw
row.prop(sc, "screencast_keys_box_color", text="")
row.prop(sc, "screencast_keys_box_hide", text="Hide")
row = layout.row(align=True)
row.active = sc.screencast_keys_box_draw
row.prop(sc, "screencast_keys_box_width")
row = layout.row(align=True)
row.prop(sc, "screencast_keys_show_operator", text="Last Operator")
split = layout.split()
col = split.column()
sub = col.column(align=True)
sub.prop(sc, "screencast_keys_timer_show", text="Time")
col = split.column()
sub = col.column(align=True)
sub.active = sc.screencast_keys_timer_show
sub.prop(sc, "screencast_keys_timer_color", text="")
row = layout.row(align=True)
row.enabled = sc.screencast_keys_timer_show
row.prop(sc, "screencast_keys_timer_size")
row = layout.row(align=True)
row.enabled = sc.screencast_keys_timer_show
row.operator("view3d.screencast_keys_timer_reset", text="Reset")
classes = (ScreencastKeysStatus,
ScreencastKeysTimerReset,
OBJECT_PT_keys_status)
def register():
init_properties()
for c in classes:
bpy.utils.register_class(c)
wm = bpy.context.window_manager
kc = wm.keyconfigs.addon
if kc:
km = kc.keymaps.new(name='3D View', space_type='VIEW_3D')
kmi = km.keymap_items.new('view3d.screencast_keys', 'C', 'PRESS',
shift=True, alt=True)
addon_keymaps.append((km, kmi))
def unregister():
# incase its enabled
ScreencastKeysStatus.handle_remove(bpy.context)
for c in classes:
bpy.utils.unregister_class(c)
clear_properties()
if __name__ == "__main__":
register()