1 # ##### BEGIN GPL LICENSE BLOCK #####
3 # This program is free software; you can redistribute it and/or
4 # modify it under the terms of the GNU General Public License
5 # as published by the Free Software Foundation; either version 2
6 # of the License, or (at your option) any later version.
8 # This program is distributed in the hope that it will be useful,
9 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # GNU General Public License for more details.
13 # You should have received a copy of the GNU General Public License
14 # along with this program; if not, write to the Free Software Foundation,
15 # Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
17 # ##### END GPL LICENSE BLOCK #####
22 "name": "Screencast Keys",
23 "author": "Paulo Gomes, Bart Crouch, John E. Herrenyo, Gaia Clary, Pablo Vazquez",
25 "blender": (2, 66, 0),
26 "location": "3D View > Properties Panel > Screencast Keys",
28 "description": "Display keys pressed in the 3D View, "
29 "useful for screencasts.",
30 "wiki_url": "http://wiki.blender.org/index.php/Extensions:2.6/"
31 "Py/Scripts/3D_interaction/Screencast_Key_Status_Tool",
32 "tracker_url": "http://projects.blender.org/tracker/index.php?"
33 "func=detail&aid=21612",
34 "category": "3D View"}
46 def getDisplayLocation(context
):
48 mouse_size
= scene
.screencast_keys_mouse_size
50 pos_x
= int( (context
.region
.width
- mouse_size
* MOUSE_RATIO
) * \
51 scene
.screencast_keys_pos_x
/ 100)
52 pos_y
= int( (context
.region
.height
- mouse_size
) *
53 scene
.screencast_keys_pos_y
/ 100)
58 def getBoundingBox(current_width
, current_height
, new_text
):
59 w
,h
= blf
.dimensions(0,new_text
)
64 return(current_width
, current_height
)
67 def draw_callback_px_text(self
, context
):
68 wm
= context
.window_manager
70 if not wm
.screencast_keys_keys
:
73 font_size
= sc
.screencast_keys_font_size
74 mouse_size
= sc
.screencast_keys_mouse_size
75 box_draw
= sc
.screencast_keys_box_draw
76 pos_x
, pos_y
= getDisplayLocation(context
)
77 label_time_max
= sc
.screencast_keys_fade_time
79 # draw text in the 3D View
80 blf
.size(0, sc
.screencast_keys_font_size
, 72)
81 blf
.enable(0, blf
.SHADOW
)
82 blf
.shadow_offset(0, 1, -1)
83 blf
.shadow(0, 5, 0.0, 0.0, 0.0, 0.8)
85 font_color_r
, font_color_g
, font_color_b
, font_color_alpha
= sc
.screencast_keys_text_color
87 row_count
= len(self
.key
)
91 if sc
.screencast_keys_mouse_position
== 'left':
92 keypos_x
+= mouse_size
* MOUSE_RATIO
* 1.7
93 if sc
.screencast_keys_mouse
!= 'icon':
94 keypos_x
-= mouse_size
* MOUSE_RATIO
95 if sc
.screencast_keys_mouse_position
== 'right' and sc
.screencast_keys_mouse
!= 'icon':
100 # we want to make sure we can shift vertically the text if the mouse is big,
101 # but don't care if aligned to right
102 if mouse_size
> font_size
*row_count
and not sc
.screencast_keys_mouse_position
== 'right':
103 shift
= (mouse_size
- font_size
*row_count
) / 2
105 text_width
, text_height
= 0,0
109 for i
in range(len(self
.key
)):
110 label_time
= time
.time() - self
.time
[i
]
111 if label_time
< label_time_max
: # only display key-presses of last 2 seconds
112 if label_time
> (label_time_max
/ 1.2):
114 if label_time
> (label_time_max
/ 1.1):
116 keypos_y
= pos_y
+ shift
+ font_size
*(i
+0.1)
118 blf
.position(0, keypos_x
, keypos_y
, 0)
119 alpha
= min(1.0, max(0.0, label_time_max
* (label_time_max
- label_time
)))
120 bgl
.glColor4f(font_color_r
, font_color_g
, font_color_b
, font_color_alpha
* alpha
)
121 blf
.draw(0, self
.key
[i
])
122 text_width
, text_height
= getBoundingBox(text_width
, text_height
,
131 # disable shadows so they don't appear all over blender
133 blf
.disable(0, blf
.SHADOW
)
135 # get rid of status texts that aren't displayed anymore
136 self
.key
= self
.key
[:final
]
137 self
.time
= self
.time
[:final
]
139 # draw graphical representation of the mouse
140 if sc
.screencast_keys_mouse
== 'icon':
141 for shape
in ["mouse", "left_button", "middle_button", "right_button"]:
142 draw_mouse(context
, shape
, "outline", font_color_alpha
* 0.4)
145 for i
in range(len(self
.mouse
)):
146 click_time
= time
.time() - self
.mouse_time
[i
]
148 shape
= map_mouse_event(self
.mouse
[i
])
150 alpha
= min(1.0, max(0.0, 2 * (2 - click_time
)))
151 draw_mouse(context
, shape
, "filled", alpha
)
156 # get rid of mouse clicks that aren't displayed anymore
157 self
.mouse
= self
.mouse
[:final
]
158 self
.mouse_time
= self
.mouse_time
[:final
]
160 def draw_callback_px_box(self
, context
):
161 wm
= context
.window_manager
164 if not wm
.screencast_keys_keys
:
167 font_size
= sc
.screencast_keys_font_size
168 mouse_size
= sc
.screencast_keys_mouse_size
170 if sc
.screencast_keys_mouse_position
== 'right':
173 box_draw
= sc
.screencast_keys_box_draw
174 pos_x
, pos_y
= getDisplayLocation(context
)
176 # get text-width/height to resize the box
177 blf
.size(0, sc
.screencast_keys_font_size
, 72)
178 box_width
, box_height
= sc
.screencast_keys_box_width
,0
181 box_hide
= sc
.screencast_keys_box_hide
182 label_time_max
= sc
.screencast_keys_fade_time
184 for i
in range(len(self
.key
)):
185 label_time
= time
.time() - self
.time
[i
]
187 if label_time
< label_time_max
: # only display key-presses of last 4 seconds
188 box_width
, box_height
= getBoundingBox(box_width
, box_height
, self
.key
[i
])
195 # Got the size right, now draw box using proper colors
196 box_color_r
, box_color_g
, box_color_b
, box_color_alpha
= sc
.screencast_keys_box_color
198 if box_draw
and not box_hide
:
201 x0
= max(0, pos_x
- padding_x
)
202 y0
= max(0, pos_y
- padding_y
)
203 x1
= pos_x
+ box_width
+ mouse_size
* MOUSE_RATIO
* 1.3 + padding_x
204 y1
= pos_y
+ max(mouse_size
, font_size
* row_count
) + padding_y
205 positions
= [[x0
, y0
], [x0
, y1
], [x1
, y1
], [x1
, y0
]]
206 settings
= [[bgl
.GL_QUADS
, min(0.0, box_color_alpha
)], [bgl
.GL_LINE_LOOP
, min(0.0, box_color_alpha
)]]
208 for mode
, box_alpha
in settings
:
209 bgl
.glEnable(bgl
.GL_BLEND
)
211 bgl
.glColor4f(box_color_r
, box_color_g
, box_color_b
, box_color_alpha
)
212 for v1
, v2
in positions
:
213 bgl
.glVertex2f(v1
, v2
)
216 if sc
.screencast_keys_show_operator
:
217 draw_last_operator(context
, pos_x
, pos_y
)
219 if sc
.screencast_keys_timer_show
:
220 draw_timer(context
, pos_x
, pos_y
)
222 # get rid of status texts that aren't displayed anymore
223 self
.key
= self
.key
[:final
]
224 self
.time
= self
.time
[:final
]
227 def draw_callback_px(self
, context
):
228 draw_callback_px_text(self
, context
)
229 draw_callback_px_box(self
, context
)
232 def draw_last_operator(context
, pos_x
, pos_y
):
234 wm
= context
.window_manager
236 font_color_r
, font_color_g
, font_color_b
, font_color_alpha
= sc
.screencast_keys_text_color
237 pos_x
, pos_y
= getDisplayLocation(context
)
240 last_operator
= wm
.operators
[-1].bl_label
242 blf
.enable(0, blf
.SHADOW
)
243 blf
.shadow_offset(0, 1, -1)
244 blf
.shadow(0, 5, 0.0, 0.0, 0.0, 0.8)
245 blf
.size(0, sc
.screencast_keys_font_size
, 36)
246 blf
.position(0, pos_x
- 14, pos_y
- 30, 0)
247 bgl
.glColor4f(font_color_r
, font_color_g
, font_color_b
, font_color_alpha
* 0.8)
248 blf
.draw(0, "Last: %s" % (last_operator
))
249 blf
.disable(0, blf
.SHADOW
)
251 def draw_timer(context
, pos_x
, pos_y
):
254 #calculate overall time
255 overall_time
= datetime
.timedelta(seconds
=int(time
.time() - ScreencastKeysStatus
.overall_time
[0]))
257 timer_color_r
, timer_color_g
, timer_color_b
, timer_color_alpha
= sc
.screencast_keys_timer_color
258 pos_x
= context
.region
.width
- (sc
.screencast_keys_timer_size
* 12) + 12
262 blf
.size(0, sc
.screencast_keys_timer_size
, 72)
263 blf
.position(0, pos_x
, pos_y
, 0)
264 bgl
.glColor4f(timer_color_r
, timer_color_g
, timer_color_b
, timer_color_alpha
)
265 blf
.draw(0, "Elapsed Time: %s" % (overall_time
))
267 def draw_mouse(context
, shape
, style
, alpha
):
270 mouse_size
= sc
.screencast_keys_mouse_size
271 font_size
= sc
.screencast_keys_font_size
272 box_draw
= sc
.screencast_keys_box_draw
274 pos_x
, pos_y
= getDisplayLocation(context
)
276 if sc
.screencast_keys_mouse_position
== 'left':
278 if sc
.screencast_keys_mouse_position
== 'right':
279 offset_x
= context
.region
.width
- pos_x
- (mouse_size
* MOUSE_RATIO
)
282 if font_size
> mouse_size
:
283 offset_y
+= (font_size
- mouse_size
) / 2
285 shape_data
= get_shape_data(shape
)
287 bgl
.glTranslatef(offset_x
, offset_y
, 0)
290 r
, g
, b
, a
= sc
.screencast_keys_text_color
291 bgl
.glEnable(bgl
.GL_BLEND
)
292 bgl
.glColor4f(r
, g
, b
, alpha
)
294 # inner shape for filled style
295 if style
== "filled":
298 inner_shape
.append(i
[0])
303 shape_segment
[0] = [mouse_size
* k
for k
in shape_segment
[0]]
304 shape_segment
[1] = [mouse_size
* k
for k
in shape_segment
[1]]
305 shape_segment
[2] = [mouse_size
* k
for k
in shape_segment
[2]]
306 shape_segment
[3] = [mouse_size
* k
for k
in shape_segment
[3]]
309 shape_buffer
= bgl
.Buffer(bgl
.GL_FLOAT
, [4, 3], shape_segment
)
311 # create the map and draw the triangle fan
312 bgl
.glMap1f(bgl
.GL_MAP1_VERTEX_3
, 0.0, 1.0, 3, 4, shape_buffer
)
313 bgl
.glEnable(bgl
.GL_MAP1_VERTEX_3
)
315 if style
== "outline":
316 bgl
.glBegin(bgl
.GL_LINE_STRIP
)
317 else: # style == "filled"
318 bgl
.glBegin(bgl
.GL_TRIANGLE_FAN
)
320 bgl
.glEvalCoord1f(j
/ 10.0)
321 x
, y
, z
= shape_segment
[3]
323 # make sure the last vertex is indeed the last one, to avoid gaps
324 bgl
.glVertex3f(x
, y
, z
)
326 bgl
.glDisable(bgl
.GL_MAP1_VERTEX_3
)
329 if style
== "filled":
330 bgl
.glBegin(bgl
.GL_TRIANGLE_FAN
)
331 for i
in inner_shape
:
332 j
= [mouse_size
* k
for k
in i
]
334 bgl
.glVertex3f(x
, y
, z
)
337 bgl
.glTranslatef(-offset_x
, -offset_y
, 0)
339 # hardcoded data to draw the graphical represenation of the mouse
340 def get_shape_data(shape
):
343 data
= [[[0.404, 0.032, 0.0],
348 [-0.015, 0.465, 0.0],
349 [-0.005, 0.564, 0.0],
354 [0.264, 1.002, 0.0]],
355 [[0.264, 1.002, 0.0],
362 [0.499, 0.213, 0.0]],
363 [[0.499, 0.213, 0.0],
366 [0.404, 0.032, 0.0]]]
367 elif shape
== "left_button":
368 data
= [[[0.154, 0.763, 0.0],
371 [0.066, 0.751, 0.0]],
372 [[0.066, 0.751, 0.0],
375 [0.039, 0.767, 0.0]],
376 [[0.039, 0.767, 0.0],
383 [0.191, 0.972, 0.0]],
384 [[0.191, 0.972, 0.0],
387 [0.199, 0.852, 0.0]],
388 [[0.199, 0.852, 0.0],
391 [0.154, 0.763, 0.0]]]
392 elif shape
== "middle_button":
393 data
= [[[0.301, 0.8, 0.0],
425 elif shape
== "middle_down_button":
426 data
= [[[0.301, 0.8, 0.0],
442 elif shape
== "middle_up_button":
443 data
= [[[0.270, 0.873, 0.0],
462 [0.270, 0.873, 0.0]]]
463 elif shape
== "right_button":
464 data
= [[[0.375, 0.763, 0.0],
467 [0.462, 0.751, 0.0]],
468 [[0.462, 0.751, 0.0],
471 [0.489, 0.767, 0.0]],
472 [[0.489, 0.767, 0.0],
479 [0.338, 0.972, 0.0]],
480 [[0.338, 0.972, 0.0],
483 [0.329, 0.852, 0.0]],
484 [[0.329, 0.852, 0.0],
487 [0.375, 0.763, 0.0]]]
492 # return the shape that belongs to the given event
493 def map_mouse_event(event
):
496 if event
== 'LEFTMOUSE':
497 shape
= "left_button"
498 elif event
== 'MIDDLEMOUSE':
499 shape
= "middle_button"
500 elif event
== 'RIGHTMOUSE':
501 shape
= "right_button"
502 elif event
== 'WHEELDOWNMOUSE':
503 shape
= "middle_down_button"
504 elif event
== 'WHEELUPMOUSE':
505 shape
= "middle_up_button"
509 class ScreencastKeysStatus(bpy
.types
.Operator
):
510 bl_idname
= "view3d.screencast_keys"
511 bl_label
= "Screencast Keys"
512 bl_description
= "Display keys pressed in the 3D View"
513 last_activity
= 'NONE'
519 def handle_add(self
, context
):
520 ScreencastKeysStatus
._handle
= bpy
.types
.SpaceView3D
.draw_handler_add(draw_callback_px
, (self
, context
), 'WINDOW', 'POST_PIXEL')
521 ScreencastKeysStatus
._timer
= context
.window_manager
.event_timer_add(0.075, context
.window
)
524 def handle_remove(context
):
525 if ScreencastKeysStatus
._handle
is not None:
526 context
.window_manager
.event_timer_remove(ScreencastKeysStatus
._timer
)
527 bpy
.types
.SpaceView3D
.draw_handler_remove(ScreencastKeysStatus
._handle
, 'WINDOW')
528 ScreencastKeysStatus
._handle
= None
529 ScreencastKeysStatus
._timer
= None
531 def modal(self
, context
, event
):
533 context
.area
.tag_redraw()
535 if event
.type == 'TIMER':
536 # no input, so no need to change the display
537 return {'PASS_THROUGH'}
539 scene
= context
.scene
540 # keys that shouldn't show up in the 3D View
541 mouse_keys
= ['MOUSEMOVE','MIDDLEMOUSE','LEFTMOUSE',
542 'RIGHTMOUSE', 'WHEELDOWNMOUSE','WHEELUPMOUSE']
543 ignore_keys
= ['LEFT_SHIFT', 'RIGHT_SHIFT', 'LEFT_ALT',
544 'RIGHT_ALT', 'LEFT_CTRL', 'RIGHT_CTRL', 'TIMER',
545 'MOUSEMOVE', 'INBETWEEN_MOUSEMOVE']
546 if scene
.screencast_keys_mouse
!= 'text':
547 ignore_keys
.extend(mouse_keys
)
549 if event
.value
== 'PRESS' or (event
.value
== 'RELEASE' and \
550 self
.last_activity
== 'KEYBOARD' and event
.type in mouse_keys
):
551 # add key-press to display-list
555 sc_keys
.append("Ctrl ")
557 sc_keys
.append("Alt ")
559 sc_keys
.append("Shift ")
565 if event
.type not in ignore_keys
and event
.type in self
.key
[0]:
566 mods
= "+ ".join(sc_keys
)
567 old_mods
= "+ ".join(self
.key
[0].split("+ ")[:-1])
569 amount
= self
.key
[0].split(" x")
571 sc_amount
= " x" + str(int(amount
[-1]) + 1)
577 if event
.type not in ignore_keys
:
578 #print("Recorded as key")
579 sc_keys
.append(event
.type)
580 self
.key
.insert(0, "+ ".join(sc_keys
) + sc_amount
)
581 self
.time
.insert(0, time
.time())
583 elif event
.type in mouse_keys
and \
584 scene
.screencast_keys_mouse
== 'icon':
585 #print("Recorded as mouse press")
586 self
.mouse
.insert(0, event
.type)
587 self
.mouse_time
.insert(0, time
.time())
589 if event
.type in mouse_keys
:
590 self
.last_activity
= 'MOUSE'
592 self
.last_activity
= 'KEYBOARD'
593 #print("Last activity set to:", self.last_activity)
595 if not context
.window_manager
.screencast_keys_keys
:
597 ScreencastKeysStatus
.handle_remove(context
)
600 return {'PASS_THROUGH'}
602 def cancel(self
, context
):
603 if context
.window_manager
.screencast_keys_keys
:
604 ScreencastKeysStatus
.handle_remove(context
)
605 context
.window_manager
.screencast_keys_keys
= False
607 def invoke(self
, context
, event
):
608 if context
.area
.type == 'VIEW_3D':
609 if context
.window_manager
.screencast_keys_keys
is False:
610 # operator is called for the first time, start everything
611 context
.window_manager
.screencast_keys_keys
= True
616 ScreencastKeysStatus
.overall_time
= []
617 ScreencastKeysStatus
.handle_add(self
, context
)
618 ScreencastKeysStatus
.overall_time
.insert(0, time
.time())
619 context
.window_manager
.modal_handler_add(self
)
620 return {'RUNNING_MODAL'}
622 # operator is called again, stop displaying
623 context
.window_manager
.screencast_keys_keys
= False
628 ScreencastKeysStatus
.overall_time
= []
631 self
.report({'WARNING'}, "3D View not found, can't run Screencast Keys")
634 class ScreencastKeysTimerReset(bpy
.types
.Operator
):
636 bl_idname
= "view3d.screencast_keys_timer_reset"
637 bl_label
= "Reset Timer"
638 bl_description
= "Set the timer back to zero"
640 def execute(self
, context
):
641 ScreencastKeysStatus
.overall_time
= [time
.time()]
645 # properties used by the script
646 def init_properties():
647 scene
= bpy
.types
.Scene
648 wm
= bpy
.types
.WindowManager
650 scene
.screencast_keys_pos_x
= bpy
.props
.IntProperty(
652 description
="Margin on the X axis",
656 scene
.screencast_keys_pos_y
= bpy
.props
.IntProperty(
658 description
="Margin on the Y axis",
662 scene
.screencast_keys_font_size
= bpy
.props
.IntProperty(
664 description
="Text size displayed on 3D View",
665 default
=24, min=10, max=150)
666 scene
.screencast_keys_mouse_size
= bpy
.props
.IntProperty(
668 description
="Mouse size displayed on 3D View",
669 default
=33, min=10, max=150)
670 scene
.screencast_keys_text_color
= bpy
.props
.FloatVectorProperty(
671 name
="Text / Icon Color",
672 description
="Color for the text and mouse icon",
673 default
=(1.0, 1.0, 1.0, 1.0),
678 scene
.screencast_keys_box_color
= bpy
.props
.FloatVectorProperty(
680 description
="Box color",
681 default
=(0.0, 0.0, 0.0, 0.3),
686 scene
.screencast_keys_box_width
= bpy
.props
.IntProperty(
688 description
="Box default width (resizes with text if needed)",
693 scene
.screencast_keys_mouse
= bpy
.props
.EnumProperty(
694 items
=(("none", "No Mouse", "Don't display mouse events"),
695 ("icon", "Icon", "Display graphical representation of "\
697 ("text", "Text", "Display mouse events as text lines")),
698 name
="Mouse Display",
699 description
="Display mouse events",
701 scene
.screencast_keys_mouse_position
= bpy
.props
.EnumProperty(
702 items
=(("left", "Left", "Align to the left"),
703 ("right", "Right", "Align to the right")),
704 name
="Icon Position",
705 description
="Align the mouse icon on the 3D View",
707 scene
.screencast_keys_box_draw
= bpy
.props
.BoolProperty(
709 description
= "Display a bounding box behind the text",
711 scene
.screencast_keys_box_hide
= bpy
.props
.BoolProperty(
713 description
= "Hide the box when no key is pressed",
715 scene
.screencast_keys_fade_time
= bpy
.props
.FloatProperty(
716 name
="Fade Out Time",
717 description
= "Time in seconds for keys to last on screen",
724 scene
.screencast_keys_show_operator
= bpy
.props
.BoolProperty(
725 name
="Display Last Operator",
726 description
= "Display the last operator used",
728 scene
.screencast_keys_timer_show
= bpy
.props
.BoolProperty(
729 name
="Display Timer",
730 description
= "Counter of the elapsed time in H:MM:SS since the script started",
732 scene
.screencast_keys_timer_size
= bpy
.props
.IntProperty(
734 description
="Time size displayed on 3D View",
735 default
=12, min=8, max=100)
736 scene
.screencast_keys_timer_color
= bpy
.props
.FloatVectorProperty(
738 description
="Color for the time display",
739 default
=(1.0, 1.0, 1.0, 0.3),
745 # Runstate initially always set to False
746 # note: it is not stored in the Scene, but in window manager:
747 wm
.screencast_keys_keys
= bpy
.props
.BoolProperty(default
=False)
750 # removal of properties when script is disabled
751 def clear_properties():
753 "screencast_keys_keys",
754 "screencast_keys_mouse",
755 "screencast_keys_font_size",
756 "screencast_keys_mouse_size",
757 "screencast_keys_mouse_position",
758 "screencast_keys_fade_time",
759 "screencast_keys_pos_x",
760 "screencast_keys_pos_y",
761 "screencast_keys_box_draw",
762 "screencast_keys_text_color",
763 "screencast_keys_box_color",
764 "screencast_keys_box_hide",
765 "screencast_keys_box_width",
766 "screencast_keys_show_operator",
767 "screencast_keys_timer_show",
768 "screencast_keys_timer_color",
769 "screencast_keys_timer_size",
772 wm
= bpy
.context
.window_manager
779 class OBJECT_PT_keys_status(bpy
.types
.Panel
):
780 bl_label
= "Screencast Keys"
781 bl_space_type
= "VIEW_3D"
782 bl_region_type
= "UI"
784 def draw(self
, context
):
786 wm
= context
.window_manager
789 if not wm
.screencast_keys_keys
:
790 layout
.operator("view3d.screencast_keys", text
="Start Display",
793 layout
.operator("view3d.screencast_keys", text
="Stop Display",
796 split
= layout
.split()
799 sub
= col
.column(align
=True)
800 sub
.label(text
="Size:")
801 sub
.prop(sc
, "screencast_keys_font_size", text
="Text")
802 sub
.prop(sc
, "screencast_keys_mouse_size", text
="Mouse")
805 sub
= col
.column(align
=True)
806 sub
.label(text
="Position:")
807 sub
.prop(sc
, "screencast_keys_pos_x", text
="X")
808 sub
.prop(sc
, "screencast_keys_pos_y", text
="Y")
810 row
= layout
.row(align
=True)
811 row
.prop(sc
, "screencast_keys_text_color")
812 row
= layout
.row(align
=True)
813 row
.prop(sc
, "screencast_keys_fade_time")
817 row
= layout
.row(align
=True)
818 row
.prop(sc
, "screencast_keys_mouse", text
="Mouse")
819 row
= layout
.row(align
=True)
820 row
.enabled
= sc
.screencast_keys_mouse
== 'icon'
821 row
.prop(sc
, "screencast_keys_mouse_position", expand
=True)
823 layout
.label(text
="Display:")
824 row
= layout
.row(align
=True)
825 row
.prop(sc
, "screencast_keys_box_draw", text
="Box")
826 row
= layout
.row(align
=True)
827 row
.active
= sc
.screencast_keys_box_draw
828 row
.prop(sc
, "screencast_keys_box_color", text
="")
829 row
.prop(sc
, "screencast_keys_box_hide", text
="Hide")
830 row
= layout
.row(align
=True)
831 row
.active
= sc
.screencast_keys_box_draw
832 row
.prop(sc
, "screencast_keys_box_width")
833 row
= layout
.row(align
=True)
834 row
.prop(sc
, "screencast_keys_show_operator", text
="Last Operator")
836 split
= layout
.split()
839 sub
= col
.column(align
=True)
840 sub
.prop(sc
, "screencast_keys_timer_show", text
="Time")
842 sub
= col
.column(align
=True)
843 sub
.active
= sc
.screencast_keys_timer_show
844 sub
.prop(sc
, "screencast_keys_timer_color", text
="")
846 row
= layout
.row(align
=True)
847 row
.enabled
= sc
.screencast_keys_timer_show
848 row
.prop(sc
, "screencast_keys_timer_size")
849 row
= layout
.row(align
=True)
850 row
.enabled
= sc
.screencast_keys_timer_show
851 row
.operator("view3d.screencast_keys_timer_reset", text
="Reset")
853 classes
= (ScreencastKeysStatus
,
854 ScreencastKeysTimerReset
,
855 OBJECT_PT_keys_status
)
858 # store keymaps here to access after registration
865 bpy
.utils
.register_class(c
)
867 wm
= bpy
.context
.window_manager
868 kc
= wm
.keyconfigs
.addon
870 km
= kc
.keymaps
.new(name
='3D View', space_type
='VIEW_3D')
871 kmi
= km
.keymap_items
.new('view3d.screencast_keys', 'C', 'PRESS', shift
=True, alt
=True)
872 addon_keymaps
.append((km
, kmi
))
877 ScreencastKeysStatus
.handle_remove(bpy
.context
)
880 bpy
.utils
.unregister_class(c
)
883 for km
, kmi
in addon_keymaps
:
884 km
.keymap_items
.remove(kmi
)
885 addon_keymaps
.clear()
890 if __name__
== "__main__":