From d827762474e90e9db682e5c0694255777fc473c2 Mon Sep 17 00:00:00 2001 From: Bart Crouch <bartius.crouch@gmail.com> Date: Thu, 5 Jan 2012 15:24:18 +0000 Subject: [PATCH] pep8 compliancy general code cleaning reset multiplier after text has disappeared support for mousewheel in icon-display improved fading, using a timer --- space_view3d_screencast_keys.py | 324 +++++++++++++++++--------------- 1 file changed, 169 insertions(+), 155 deletions(-) diff --git a/space_view3d_screencast_keys.py b/space_view3d_screencast_keys.py index be431f41b..8494a9ff1 100644 --- a/space_view3d_screencast_keys.py +++ b/space_view3d_screencast_keys.py @@ -16,12 +16,14 @@ # # ##### END GPL LICENSE BLOCK ##### +# <pep8 compliant> + bl_info = { 'name': 'Screencast Keys', - 'author': 'Paulo Gomes, Bart Crouch, John E. Herrenyo', - 'version': (1, 4), - 'blender': (2, 5, 9), - 'api': 39933, + 'author': 'Paulo Gomes, Bart Crouch, John E. Herrenyo, Gaia Clary', + 'version': (1, 5), + 'blender': (2, 6, 1), + 'api': 43073, 'location': 'View3D > Properties panel > Screencast Keys', 'warning': '', 'description': 'Display keys pressed in the 3d-view, '\ @@ -33,53 +35,47 @@ bl_info = { 'category': '3D View'} -# ##### -# -# Modification history: -# - Version 1,4 -# - 07-sep-2011 (Gaia Clary): -# - settings now stored in blend file -# - grouping mouse&text -# - mouse_size and font_size separated -# - boundingBox for improved readability. -# - missing mouse "release" clicks added -# -# #### - - import bgl import blf import bpy import time + MOUSE_RATIO = 0.535 + def getDisplayLocation(context): - sc = context.scene - mouse_size = sc.screencast_keys_mouse_size - pos_x = int( (context.region.width - mouse_size*MOUSE_RATIO) * sc.screencast_keys_pos_x / 100) - pos_y = int( (context.region.height - mouse_size) * sc.screencast_keys_pos_y / 100) - return pos_x, pos_y + 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) + pos_y = int( (context.region.height - mouse_size) * + 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 - return current_width, current_height + + return(current_width, current_height) + def draw_callback_px(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 link = sc.screencast_keys_link pos_x, pos_y = getDisplayLocation(context) - # draw text in the 3d-view # ======================== blf.size(0, sc.screencast_keys_font_size, 72) @@ -107,17 +103,17 @@ def draw_callback_px(self, context): alpha = min(1.0, max(0.0, 2 * (2 - label_time))) bgl.glColor4f(r, g, b, alpha) blf.draw(0, self.key[i]) - text_width, text_height = getBoundingBox(text_width, text_height, self.key[i]) + text_width, text_height = getBoundingBox(text_width, text_height, + self.key[i]) row_count += 1 - final = i + final = i + 1 else: break # get rid of status texts that aren't displayed anymore - self.key = self.key[:final+1] - self.time = self.time[:final+1] - - + self.key = self.key[:final] + self.time = self.time[:final] + # draw graphical representation of the mouse # ========================================== if sc.screencast_keys_mouse == 'icon': @@ -132,49 +128,32 @@ def draw_callback_px(self, context): if shape: alpha = min(1.0, max(0.0, 2 * (2 - click_time))) draw_mouse(context, shape, "filled", alpha) - final = i + final = i + 1 else: break - # get rid of mouse clicks that aren't displayed anymore - self.mouse = self.mouse[:final+1] - self.mouse_time = self.mouse_time[:final+1] - + self.mouse = self.mouse[:final] + self.mouse_time = self.mouse_time[:final] # Draw border (if enabled) # ======================== - if link == True and row_count > 0: - bgl.glEnable(bgl.GL_BLEND) - bgl.glBegin(bgl.GL_QUADS) - bgl.glLineWidth(2) - bgl.glColor4f(r, g, b, 0.2) - drawRectangle(pos_x , pos_y , text_width+mouse_size*MOUSE_RATIO*1.3 , max(mouse_size, font_size*row_count), 4 ) - bgl.glEnd() - bgl.glBegin(bgl.GL_LINES) - bgl.glColor4f(r, g, b, alpha ) - drawRectangle(pos_x , pos_y , text_width+mouse_size*MOUSE_RATIO*1.3 , max(mouse_size, font_size*row_count), 4 ) - bgl.glEnd() - - -# Draw a line. currently not used. -def drawLinef(from_x, from_y, to_x, to_y): - bgl.glVertex2f(from_x, from_y) - bgl.glVertex2f(to_x, to_y) - - -# Draw a rectangle. Currently not used -def drawRectangle (ox, oy, ow, oh, padding=0): - - x = ox - 2*padding - y = oy - padding - w = ow + 4 * padding - h = oh + 2 * padding - - drawLinef(x, y, x+w, y) - drawLinef(x+w, y, x+w, y+h) - drawLinef(x+w, y+h, x , y+h) - drawLinef(x , y+h, x , y) + if link and row_count > 0: + padding = 8 + x0 = max(0, pos_x - padding) + y0 = max(0, pos_y - padding) + x1 = pos_x + text_width + mouse_size * MOUSE_RATIO * 1.3 + padding + y1 = pos_y + max(mouse_size, font_size * row_count) + padding + positions = [[x0, y0], [x0, y1], [x1, y1], [x1, y0]] + settings = [[bgl.GL_QUADS, min(0.2, alpha)], [bgl.GL_LINE_LOOP, alpha]] + + for mode, box_alpha in settings: + bgl.glEnable(bgl.GL_BLEND) + bgl.glBegin(mode) + bgl.glColor4f(r, g, b, box_alpha) + for v1, v2 in positions: + bgl.glVertex2f(v1, v2) + bgl.glEnd() def draw_mouse(context, shape, style, alpha): @@ -185,7 +164,7 @@ def draw_mouse(context, shape, style, alpha): link = sc.screencast_keys_link pos_x, pos_y = getDisplayLocation(context) - if link==True: + if link: offset_x = pos_x else: offset_x = context.region.width - pos_x - (mouse_size * MOUSE_RATIO) @@ -193,7 +172,7 @@ def draw_mouse(context, shape, style, alpha): 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) @@ -201,15 +180,14 @@ def draw_mouse(context, shape, style, alpha): # color r, g, b = sc.screencast_keys_color bgl.glEnable(bgl.GL_BLEND) - #bgl.glBlendFunc(bgl.GL_SRC_ALPHA, bgl.GL_ONE_MINUS_SRC_ALPHA) - #bgl.glColor4f(r, g, b, alpha) - + bgl.glColor4f(r, g, b, alpha) + # 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 @@ -217,16 +195,14 @@ def draw_mouse(context, shape, style, alpha): 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) - bgl.glColor4f(r, g, b, alpha) - if style == "outline": bgl.glBegin(bgl.GL_LINE_STRIP) else: # style == "filled" @@ -234,22 +210,21 @@ def draw_mouse(context, shape, style, alpha): 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.glColor4f(r, g, b, alpha) 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) @@ -339,6 +314,44 @@ def get_shape_data(shape): [0.303, 0.833, 0.0], [0.302, 0.817, 0.0], [0.301, 0.8, 0.0]]] + elif shape == "middle_down_button": + 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], + [0.301, 0.8, 0.0]]] + elif shape == "middle_up_button": + 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], + [0.270, 0.873, 0.0]]] elif shape == "right_button": data = [[[0.375, 0.763, 0.0], [0.402, 0.755, 0.0], @@ -364,20 +377,25 @@ def get_shape_data(shape): [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) @@ -387,34 +405,38 @@ class ScreencastKeysStatus(bpy.types.Operator): bl_description = "Display keys pressed in the 3D-view" last_activity = 'NONE' + _handle = None + _timer = None + def modal(self, context, event): if context.area: context.area.tag_redraw() - sc = context.scene + + 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'] - if sc.screencast_keys_mouse != 'text': + if scene.screencast_keys_mouse != 'text': ignore_keys.extend(mouse_keys) - - #if (event.value != "NOTHING" and event.value != "PRESS"): - # print (event.value, event.type, "Previous activity was: ", self.last_activity) - - if event.value == 'PRESS' or (event.value == 'RELEASE' and self.last_activity == 'KEYBOARD' and event.type in 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: @@ -430,14 +452,15 @@ class ScreencastKeysStatus(bpy.types.Operator): sc_amount = " x2" del self.key[0] del self.time[0] - + if event.type not in ignore_keys: #print("Recorded as key") 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 sc.screencast_keys_mouse == 'icon': + + elif event.type in mouse_keys and \ + scene.screencast_keys_mouse == 'icon': #print("Recorded as mouse press") self.mouse.insert(0, event.type) self.mouse_time.insert(0, time.time()) @@ -447,22 +470,22 @@ class ScreencastKeysStatus(bpy.types.Operator): else: self.last_activity = 'KEYBOARD' #print("Last activity set to:", self.last_activity) - + if not context.window_manager.screencast_keys_keys: # stop script + context.window_manager.event_timer_remove(self._timer) context.region.callback_remove(self._handle) return {'CANCELLED'} return {'PASS_THROUGH'} - def cancel(self, context): if context.window_manager.screencast_keys_keys: + context.window_manager.event_timer_remove(self._timer) context.region.callback_remove(self._handle) 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 == False: @@ -475,6 +498,8 @@ class ScreencastKeysStatus(bpy.types.Operator): self.mouse_time = [] self._handle = context.region.callback_add(draw_callback_px, (self, context), 'POST_PIXEL') + self._timer = context.window_manager.event_timer_add(0.05, + context.window) return {'RUNNING_MODAL'} else: # operator is called again, stop displaying @@ -491,62 +516,52 @@ class ScreencastKeysStatus(bpy.types.Operator): # properties used by the script def init_properties(): - - sc = bpy.types.Scene + scene = bpy.types.Scene wm = bpy.types.WindowManager - sc.screencast_keys_pos_x = bpy.props.IntProperty( - name="Pos X", - description="Margin on the x axis", - default=5, - min=0, - max=100) - - sc.screencast_keys_pos_y = bpy.props.IntProperty( - name="Pos Y", - description="Margin on the y axis", - default=10, - min=0, - max=100) - - sc.screencast_keys_font_size = bpy.props.IntProperty( - name="Font", - description="Fontsize", - default=20, min=10, max=150) - - sc.screencast_keys_mouse_size = bpy.props.IntProperty( - name="Mouse", - description="Mousesize", - default=60, min=10, max=150) - - - sc.screencast_keys_color = bpy.props.FloatVectorProperty( - name="Color", - description="Font color", - default=(1.0, 1.0, 1.0), - min=0, - max=1, - subtype='COLOR') - - sc.screencast_keys_mouse = bpy.props.EnumProperty( - items=(("none", "None", "Don't display mouse events"), - ("icon", "Icon", "Display graphical represenation of "\ - "the mouse"), - ("text", "Text", "Display mouse events as text lines")), - name="Mouse display", - description="Display mouse events", - default='text') - - sc.screencast_keys_link = bpy.props.BoolProperty( - name="Group Mouse & Text", - description = "Link mouse to text", - default = False) - - print ("Screencast Keys: initialized from AddOn default settings.") + scene.screencast_keys_pos_x = bpy.props.IntProperty( + name="Pos X", + description="Margin on the x axis", + default=5, + min=0, + max=100) + scene.screencast_keys_pos_y = bpy.props.IntProperty( + name="Pos Y", + description="Margin on the y axis", + default=10, + min=0, + max=100) + scene.screencast_keys_font_size = bpy.props.IntProperty( + name="Font", + description="Fontsize", + default=20, min=10, max=150) + scene.screencast_keys_mouse_size = bpy.props.IntProperty( + name="Mouse", + description="Mousesize", + default=60, min=10, max=150) + scene.screencast_keys_color = bpy.props.FloatVectorProperty( + name="Color", + description="Font color", + default=(1.0, 1.0, 1.0), + min=0, + max=1, + subtype='COLOR') + scene.screencast_keys_mouse = bpy.props.EnumProperty( + items=(("none", "None", "Don't display mouse events"), + ("icon", "Icon", "Display graphical represenation of "\ + "the mouse"), + ("text", "Text", "Display mouse events as text lines")), + name="Mouse display", + description="Display mouse events", + default='text') + scene.screencast_keys_link = bpy.props.BoolProperty( + name="Group Mouse & Text", + description = "Link mouse to text", + default = False) # 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) + wm.screencast_keys_keys = bpy.props.BoolProperty(default=False) # removal of properties when script is disabled @@ -569,19 +584,19 @@ 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') - + col = layout.column(align=True) row = col.row(align=True) row.prop(sc, "screencast_keys_pos_x") @@ -593,7 +608,7 @@ class OBJECT_PT_keys_status(bpy.types.Panel): row.prop(sc, "screencast_keys_mouse", text="Mouse") row = col.row(align=True) row.prop(sc, "screencast_keys_link") - + layout.prop(sc, "screencast_keys_color") @@ -615,4 +630,3 @@ def unregister(): if __name__ == "__main__": register() - -- GitLab