Newer
Older
# ##### 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 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 #####
bl_info = {
'name': "Screencast Keys",
'author': 'Paulo Gomes, Bart Crouch, John E. Herrenyo, Gaia Clary, Pablo Vazquez',
'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
def getDisplayLocation(context):
scene = context.scene
mouse_size = scene.screencast_keys_mouse_size
pos_x = int( (context.region.width - mouse_size * MOUSE_RATIO) * \
scene.screencast_keys_pos_x / 100)
scene.screencast_keys_pos_y / 100)
return(pos_x, pos_y)
def getBoundingBox(current_width, current_height, new_text):
w,h = blf.dimensions(0,new_text)
if w > current_width:
current_width = w
current_height += h
wm = context.window_manager
sc = context.scene
if not wm.screencast_keys_keys:
return
font_size = sc.screencast_keys_font_size
mouse_size = sc.screencast_keys_mouse_size
pos_x, pos_y = getDisplayLocation(context)
blf.size(0, sc.screencast_keys_font_size, 72)
blf.enable(0, blf.SHADOW)
blf.shadow_offset(0, 1, -1)
blf.shadow(0, 5, 0.0, 0.0, 0.0, 0.8)
font_color_r, font_color_g, font_color_b, font_color_alpha = sc.screencast_keys_text_color
final = 0
row_count = len(self.key)
keypos_x = pos_x
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
# 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
text_width, text_height = 0,0
row_count = 0
alpha = 1.0
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.position(0, keypos_x, keypos_y , 0)
alpha = min(1.0, max(0.0, label_time_max * (label_time_max - label_time)))
bgl.glColor4f(font_color_r, font_color_g, font_color_b, font_color_alpha * alpha)
blf.draw(0, self.key[i])
text_width, text_height = getBoundingBox(text_width, text_height,
self.key[i])
else:
break
# remove blurriness
# disable shadows so they don't appear all over blender
blf.blur(0,0)
blf.disable(0, blf.SHADOW)
# get rid of status texts that aren't displayed anymore
self.key = self.key[:final]
self.time = self.time[:final]
# draw graphical representation of the mouse
if sc.screencast_keys_mouse == 'icon':
for shape in ["mouse", "left_button", "middle_button", "right_button"]:
draw_mouse(context, shape, "outline", font_color_alpha * 0.4)
final = 0
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)
else:
break
# get rid of mouse clicks that aren't displayed anymore
self.mouse = self.mouse[:final]
self.mouse_time = self.mouse_time[:final]
def draw_callback_px_box(self, context):
wm = context.window_manager
sc = context.scene
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)
# get text-width/height to resize the box
blf.size(0, sc.screencast_keys_font_size, 72)
box_width, box_height = sc.screencast_keys_box_width,0
final = 0
row_count = 0
box_hide = sc.screencast_keys_box_hide
label_time_max = sc.screencast_keys_fade_time
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 4 seconds
box_width, box_height = getBoundingBox(box_width, box_height, self.key[i])
row_count += 1
final = i + 1
# 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
padding_x = 16
padding_y = 12
x0 = max(0, pos_x - padding_x)
y0 = max(0, pos_y - padding_y)
x1 = pos_x + box_width + mouse_size * MOUSE_RATIO * 1.3 + padding_x
y1 = pos_y + max(mouse_size, font_size * row_count) + padding_y
settings = [[bgl.GL_QUADS, min(0.0, box_color_alpha)], [bgl.GL_LINE_LOOP, min(0.0, box_color_alpha)]]
for mode, box_alpha in settings:
bgl.glEnable(bgl.GL_BLEND)
bgl.glBegin(mode)
bgl.glColor4f(box_color_r, box_color_g, box_color_b, box_color_alpha)
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)
# get rid of status texts that aren't displayed anymore
self.key = self.key[:final]
self.time = self.time[:final]
def draw_last_operator(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)
#calculate overall time
overall_time = datetime.timedelta(seconds=int(time.time() - ScreencastKeysStatus.overall_time[0]))
timer_color_r, timer_color_g, timer_color_b, timer_color_alpha = sc.screencast_keys_timer_color
pos_x = context.region.width - (sc.screencast_keys_timer_size * 12) + 12
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))
def draw_mouse(context, shape, style, alpha):
# shape and position
sc = context.scene
mouse_size = sc.screencast_keys_mouse_size
font_size = sc.screencast_keys_font_size
pos_x, pos_y = getDisplayLocation(context)
if sc.screencast_keys_mouse_position == 'left':
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
bgl.glEnable(bgl.GL_BLEND)
# inner shape for filled style
if style == "filled":
inner_shape = []
for i in shape_data:
inner_shape.append(i[0])
# 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]]
# create the buffer
shape_buffer = bgl.Buffer(bgl.GL_FLOAT, [4, 3], shape_segment)
# create the map and draw the triangle fan
bgl.glMap1f(bgl.GL_MAP1_VERTEX_3, 0.0, 1.0, 3, 4, shape_buffer)
bgl.glEnable(bgl.GL_MAP1_VERTEX_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)
# hardcoded data to draw the graphical represenation of the mouse
def get_shape_data(shape):
data = []
if shape == "mouse":
[0.059, 0.126, 0.0],
[0.04, 0.213, 0.0]],
[[0.04, 0.213, 0.0],
[-0.015, 0.465, 0.0],
[-0.005, 0.564, 0.0],
[0.032, 0.87, 0.0]],
[[0.032, 0.87, 0.0],
[0.05, 0.973, 0.0],
[0.16, 1.002, 0.0],
[0.264, 1.002, 0.0]],
[[0.264, 1.002, 0.0],
[0.369, 1.002, 0.0],
[0.478, 0.973, 0.0],
[0.497, 0.87, 0.0]],
[[0.497, 0.87, 0.0],
[0.533, 0.564, 0.0],
[0.554, 0.465, 0.0],
[0.499, 0.213, 0.0]],
[[0.499, 0.213, 0.0],
[0.490, 0.126, 0.0],
elif shape == "left_button":
data = [[[0.154, 0.763, 0.0],
[0.126, 0.755, 0.0],
[0.12, 0.754, 0.0],
[0.066, 0.751, 0.0]],
[[0.066, 0.751, 0.0],
[0.043, 0.75, 0.0],
[0.039, 0.757, 0.0],
[0.039, 0.767, 0.0]],
[[0.039, 0.767, 0.0],
[0.047, 0.908, 0.0],
[0.078, 0.943, 0.0],
[0.155, 0.97, 0.0]],
[[0.155, 0.97, 0.0],
[0.174, 0.977, 0.0],
[0.187, 0.975, 0.0],
[0.191, 0.972, 0.0]],
[[0.191, 0.972, 0.0],
[0.203, 0.958, 0.0],
[0.205, 0.949, 0.0],
[0.199, 0.852, 0.0]],
[[0.199, 0.852, 0.0],
[0.195, 0.77, 0.0],
[0.18, 0.771, 0.0],
[0.154, 0.763, 0.0]]]
elif shape == "middle_button":
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
data = [[[0.301, 0.8, 0.0],
[0.298, 0.768, 0.0],
[0.231, 0.768, 0.0],
[0.228, 0.8, 0.0]],
[[0.228, 0.8, 0.0],
[0.226, 0.817, 0.0],
[0.225, 0.833, 0.0],
[0.224, 0.85, 0.0]],
[[0.224, 0.85, 0.0],
[0.222, 0.873, 0.0],
[0.222, 0.877, 0.0],
[0.224, 0.9, 0.0]],
[[0.224, 0.9, 0.0],
[0.225, 0.917, 0.0],
[0.226, 0.933, 0.0],
[0.228, 0.95, 0.0]],
[[0.228, 0.95, 0.0],
[0.231, 0.982, 0.0],
[0.298, 0.982, 0.0],
[0.301, 0.95, 0.0]],
[[0.301, 0.95, 0.0],
[0.302, 0.933, 0.0],
[0.303, 0.917, 0.0],
[0.305, 0.9, 0.0]],
[[0.305, 0.9, 0.0],
[0.307, 0.877, 0.0],
[0.307, 0.873, 0.0],
[0.305, 0.85, 0.0]],
[[0.305, 0.85, 0.0],
[0.303, 0.833, 0.0],
[0.302, 0.817, 0.0],
[0.301, 0.8, 0.0]]]
data = [[[0.301, 0.8, 0.0],
[0.298, 0.768, 0.0],
[0.231, 0.768, 0.0],
[0.228, 0.8, 0.0]],
[[0.228, 0.8, 0.0],
[0.226, 0.817, 0.0],
[0.225, 0.833, 0.0],
[0.224, 0.85, 0.0]],
[[0.224, 0.85, 0.0],
[0.264, 0.873, 0.0],
[0.284, 0.873, 0.0],
[0.305, 0.85, 0.0]],
[[0.305, 0.85, 0.0],
[0.303, 0.833, 0.0],
[0.302, 0.817, 0.0],
data = [[[0.270, 0.873, 0.0],
[0.264, 0.873, 0.0],
[0.222, 0.877, 0.0],
[0.224, 0.9, 0.0]],
[[0.224, 0.9, 0.0],
[0.225, 0.917, 0.0],
[0.226, 0.933, 0.0],
[0.228, 0.95, 0.0]],
[[0.228, 0.95, 0.0],
[0.231, 0.982, 0.0],
[0.298, 0.982, 0.0],
[0.301, 0.95, 0.0]],
[[0.301, 0.95, 0.0],
[0.302, 0.933, 0.0],
[0.303, 0.917, 0.0],
[0.305, 0.9, 0.0]],
[[0.305, 0.9, 0.0],
[0.307, 0.877, 0.0],
[0.284, 0.873, 0.0],
elif shape == "right_button":
data = [[[0.375, 0.763, 0.0],
[0.402, 0.755, 0.0],
[0.408, 0.754, 0.0],
[0.462, 0.751, 0.0]],
[[0.462, 0.751, 0.0],
[0.486, 0.75, 0.0],
[0.49, 0.757, 0.0],
[0.489, 0.767, 0.0]],
[[0.489, 0.767, 0.0],
[0.481, 0.908, 0.0],
[0.451, 0.943, 0.0],
[0.374, 0.97, 0.0]],
[[0.374, 0.97, 0.0],
[0.354, 0.977, 0.0],
[0.341, 0.975, 0.0],
[0.338, 0.972, 0.0]],
[[0.338, 0.972, 0.0],
[0.325, 0.958, 0.0],
[0.324, 0.949, 0.0],
[0.329, 0.852, 0.0]],
[[0.329, 0.852, 0.0],
[0.334, 0.77, 0.0],
[0.348, 0.771, 0.0],
[0.375, 0.763, 0.0]]]
return(data)
# return the shape that belongs to the given event
def map_mouse_event(event):
shape = False
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"
Campbell Barton
committed
_handle_a = None
_handle_b = None
def modal(self, context, event):
if context.area:
context.area.tag_redraw()
if event.type == 'TIMER':
# no input, so no need to change the display
return {'PASS_THROUGH'}
mouse_keys = ['MOUSEMOVE','MIDDLEMOUSE','LEFTMOUSE',
'RIGHTMOUSE', 'WHEELDOWNMOUSE','WHEELUPMOUSE']
ignore_keys = ['LEFT_SHIFT', 'RIGHT_SHIFT', 'LEFT_ALT',
'RIGHT_ALT', 'LEFT_CTRL', 'RIGHT_CTRL', 'TIMER']
ignore_keys.extend(mouse_keys)
if event.value == 'PRESS' or (event.value == 'RELEASE' and \
self.last_activity == 'KEYBOARD' and event.type in mouse_keys):
# add key-press to display-list
sc_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:
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 not in ignore_keys:
sc_keys.append(event.type)
self.key.insert(0, "+ ".join(sc_keys) + sc_amount)
self.time.insert(0, time.time())
elif event.type in mouse_keys and \
scene.screencast_keys_mouse == 'icon':
self.mouse.insert(0, event.type)
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
Campbell Barton
committed
context.region.callback_remove(self._handle_a)
context.region.callback_remove(self._handle_b)
return {'CANCELLED'}
return {'PASS_THROUGH'}
def cancel(self, context):
if context.window_manager.screencast_keys_keys:
Campbell Barton
committed
context.region.callback_remove(self._handle_a)
context.region.callback_remove(self._handle_b)
context.window_manager.screencast_keys_keys = False
return {'CANCELLED'}
def invoke(self, context, event):
if context.area.type == 'VIEW_3D':
if context.window_manager.screencast_keys_keys is False:
# operator is called for the first time, start everything
context.window_manager.screencast_keys_keys = True
self.key = []
self.time = []
self.mouse = []
self.mouse_time = []
Campbell Barton
committed
self._handle_a = context.region.callback_add(draw_callback_px_box,
Campbell Barton
committed
self._handle_b = context.region.callback_add(draw_callback_px_text,
(self, context), 'POST_PIXEL')
self._timer = context.window_manager.event_timer_add(0.075,
ScreencastKeysStatus.overall_time.insert(0, time.time())
Campbell Barton
committed
context.window_manager.modal_handler_add(self)
return {'RUNNING_MODAL'}
else:
# operator is called again, stop displaying
context.window_manager.screencast_keys_keys = False
self.key = []
self.time = []
self.mouse = []
self.mouse_time = []
return {'CANCELLED'}
else:
self.report({'WARNING'}, "3D View not found, can't run Screencast Keys")
return {'CANCELLED'}
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"
def execute(self, context):
ScreencastKeysStatus.overall_time = [time.time()]
return {'FINISHED'}
# properties used by the script
def init_properties():
wm = bpy.types.WindowManager
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",
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)
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),
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)
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")),
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",
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,
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",
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)
# Runstate initially always set to False
# note: it is not stored in the Scene, but in window manager:
wm.screencast_keys_keys = bpy.props.BoolProperty(default=False)
# removal of properties when script is disabled
def clear_properties():
props = ["screencast_keys_keys", "screencast_keys_mouse",
"screencast_keys_font_size", "screencast_keys_mouse_size",
"screencast_keys_mouse_position", "screencast_keys_fade_time",
"screencast_keys_pos_x", "screencast_keys_pos_y",
"screencast_keys_box_draw", "screencast_keys_text_color",
"screencast_keys_box_color", "screencast_keys_box_hide",
"screencast_keys_box_width", "screencast_keys_show_operator",
"screencast_keys_timer_show", "screencast_keys_timer_color",
"screencast_keys_timer_size" ]
for p in props:
if bpy.context.window_manager.get(p) != None:
del bpy.context.window_manager[p]
try:
x = getattr(bpy.types.WindowManager, p)
del x
except:
pass
# defining the panel
class OBJECT_PT_keys_status(bpy.types.Panel):
bl_label = "Screencast Keys"
bl_space_type = "VIEW_3D"
bl_region_type = "UI"
def draw(self, context):
sc = context.scene
wm = context.window_manager
layout = self.layout
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)
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 = 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)
kc = bpy.context.window_manager.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)
def unregister():
for c in classes:
bpy.utils.unregister_class(c)
kc = bpy.context.window_manager.keyconfigs.addon
if kc:
km = kc.keymaps['3D View']
for item in km.keymap_items:
if item.idname == 'view3d.screencast_keys':
km.keymap_items.remove(item)
break
clear_properties()
if __name__ == "__main__":