From 7f9776646709dc34af13afb460ca8db1351c7b19 Mon Sep 17 00:00:00 2001 From: mmmrqs Date: Sun, 28 May 2023 15:55:30 -0300 Subject: [PATCH] Added bind_operator method to bl_ui_button --- __init__.py | 5 ++- bl_ui_button.py | 87 +++++++++++++++++++++++------------------------- demo_panel_op.py | 66 +++++++++++++++++++++--------------- prefs.py | 9 +++-- 4 files changed, 90 insertions(+), 77 deletions(-) diff --git a/__init__.py b/__init__.py index adea83d..a7049e7 100644 --- a/__init__.py +++ b/__init__.py @@ -20,7 +20,7 @@ bl_info = {"name": "BL UI Widgets", "description": "UI Widgets to draw in the 3D view", "author": "Marcelo M. Marques (fork of Jayanam's original project)", - "version": (1, 0, 5), + "version": (1, 0, 6), "blender": (3, 0, 0), "location": "View3D > side panel ([N]), [BL_UI_Widget] tab", "support": "COMMUNITY", @@ -35,6 +35,9 @@ # Note: Because the way Blender's Preferences window displays the Addon version number, # I am forced to keep this file in sync with the greatest version number of all modules. +# v1.0.6 (05.27.2023) - by Marcelo M. Marques +# Chang: updated version to keep this file in sync + # v1.0.5 (03.06.2023) - by Marcelo M. Marques # Chang: updated version to keep this file in sync diff --git a/bl_ui_button.py b/bl_ui_button.py index 67ca5fb..d2750f2 100644 --- a/bl_ui_button.py +++ b/bl_ui_button.py @@ -15,14 +15,13 @@ # Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. # # ##### END GPL LICENSE BLOCK ##### -import os.path # --- ### Header bl_info = {"name": "BL UI Widgets", "description": "UI Widgets to draw in the 3D view", "author": "Marcelo M. Marques (fork of Jayanam's original project)", - "version": (1, 0, 2), - "blender": (2, 80, 75), + "version": (1, 0, 3), + "blender": (3, 0, 0), "location": "View3D > viewport area", "support": "COMMUNITY", "category": "3D View", @@ -33,6 +32,9 @@ # --- ### Change log +# v1.0.3 (05.27.2023) - by atticus-lv +# Added: 'bind_operator' function to automatically get info from a given operator idname and bind it to the button + # v1.0.2 (10.31.2021) - by Marcelo M. Marques # Chang: improved reliability on 'mouse_down' and 'mouse_up' overridable functions by conditioning the returned value @@ -73,9 +75,10 @@ # --- ### Imports import bpy import blf +import os.path -from .bl_ui_patch import BL_UI_Patch -from .bl_ui_label import BL_UI_Label +from . bl_ui_patch import BL_UI_Patch +from . bl_ui_label import BL_UI_Label class BL_UI_Button(BL_UI_Patch): @@ -87,35 +90,35 @@ def __init__(self, x, y, width, height): self._text = "Button" self._textwo = "" - self._text_color = None # Button text color (first row) - self._text_highlight = None # Button high color (first row) - self._textwo_color = None # Button text color (second row) - self._textwo_highlight = None # Button high color (second row) - - self._style = 'TOOL' # Button color styles are: {TOOL,RADIO,TOGGLE,NUMBER_CLICK,NUMBER_SLIDE,TEXTBOX} - self._bg_color = None # Button face color (when pressed state == 0) - self._selected_color = None # Button face color (when pressed state == 3) - self._outline_color = None # Button outline color - self._roundness = None # Button corners roundness factor [0..1] - self._radius = 8.5 # Button corners circular radius - self._rounded_corners = (1, 1, 1, 1) # 1=Round/0=Straight, coords:(bottomLeft,topLeft,topRight,bottomRight) - self._has_shadow = True # Indicates whether a shadow must be drawn around the button - self._alignment = 'CENTER' # Text alignment options: {CENTER,LEFT,RIGHT} - - self._text_size = None # Button text line 1 size - self._textwo_size = None # Button text line 2 size - self._text_margin = 0 # Margin for left aligned text (used by slider and textbox objects) - - self._text_kerning = None # Button text kerning (True/False) - self._text_shadow_size = None # Button text shadow size - self._text_shadow_offset_x = None # Button text shadow offset x (positive goes right) - self._text_shadow_offset_y = None # Button text shadow offset y (negative goes down) - self._text_shadow_color = None # Button text shadow color [0..1] = gray tone, from dark to clear - self._text_shadow_alpha = None # Button text shadow alpha value [0..1] + self._text_color = None # Button text color (first row) + self._text_highlight = None # Button high color (first row) + self._textwo_color = None # Button text color (second row) + self._textwo_highlight = None # Button high color (second row) + + self._style = 'TOOL' # Button color styles are: {TOOL,RADIO,TOGGLE,NUMBER_CLICK,NUMBER_SLIDE,TEXTBOX} + self._bg_color = None # Button face color (when pressed state == 0) + self._selected_color = None # Button face color (when pressed state == 3) + self._outline_color = None # Button outline color + self._roundness = None # Button corners roundness factor [0..1] + self._radius = 8.5 # Button corners circular radius + self._rounded_corners = (1, 1, 1, 1) # 1=Round/0=Straight, coords:(bottomLeft,topLeft,topRight,bottomRight) + self._has_shadow = True # Indicates whether a shadow must be drawn around the button + self._alignment = 'CENTER' # Text alignment options: {CENTER,LEFT,RIGHT} + + self._text_size = None # Button text line 1 size + self._textwo_size = None # Button text line 2 size + self._text_margin = 0 # Margin for left aligned text (used by slider and textbox objects) + + self._text_kerning = None # Button text kerning (True/False) + self._text_shadow_size = None # Button text shadow size + self._text_shadow_offset_x = None # Button text shadow offset x (positive goes right) + self._text_shadow_offset_y = None # Button text shadow offset y (negative goes down) + self._text_shadow_color = None # Button text shadow color [0..1] = gray tone, from dark to clear + self._text_shadow_alpha = None # Button text shadow alpha value [0..1] self._textpos = (x, y) - self.__state = 0 # 0 is UP; 1 is Down; 2 is Hover when not pressed or down; 3 is Pressed + self.__state = 0 # 0 is UP; 1 is Down; 2 is Hover when not pressed or down; 3 is Pressed @property def state(self): @@ -370,8 +373,7 @@ def draw_text(self): if self._is_enabled and (self.button_pressed_func(self) or self.__state in [1, 3, 5]): text_color = tuple(widget_style.text_sel) + (1.0,) if self._text_highlight is None else self._text_highlight - textwo_color = tuple(widget_style.text_sel) + ( - 1.0,) if self._textwo_highlight is None else self._textwo_highlight + textwo_color = tuple(widget_style.text_sel) + (1.0,) if self._textwo_highlight is None else self._textwo_highlight else: text_color = tuple(widget_style.text) + (1.0,) if self._text_color is None else self._text_color textwo_color = tuple(widget_style.text) + (1.0,) if self._textwo_color is None else self._textwo_color @@ -390,8 +392,7 @@ def draw_text(self): if bpy.app.version >= (3, 0, 0): # 3.00 issue: 'font_kerning_style' has become extinct text_kerning = False else: - text_kerning = ( - widget_style.font_kerning_style == 'FITTED') if self._text_kerning is None else self._text_kerning + text_kerning = (widget_style.font_kerning_style == 'FITTED') if self._text_kerning is None else self._text_kerning if text_kerning: blf.enable(0, blf.KERNING_DEFAULT) @@ -433,8 +434,7 @@ def draw_text(self): if self._style in {'NUMBER_CLICK', 'NUMBER_SLIDE', 'TEXTBOX'}: top_margin = int((self.height - normal1) / 2.0) else: - top_margin = int( - (self.height - int(round(normal1 + 0.499)) - int(round(normal2 + 0.499)) - middle_gap) / 2.0) + top_margin = int((self.height - int(round(normal1 + 0.499)) - int(round(normal2 + 0.499)) - middle_gap) / 2.0) textpos_y = self.y_screen - top_margin - int(round(normal1 + 0.499)) + 1 @@ -445,8 +445,7 @@ def draw_text(self): shadow_alpha = widget_style.shadow_alpha if self._text_shadow_alpha is None else self._text_shadow_alpha if self._text != "": - if self._alignment == 'LEFT' or self._style in {'NUMBER_SLIDE', 'TEXTBOX'} or ( - self._style == 'NUMBER_CLICK' and self._is_mslider): + if self._alignment == 'LEFT' or self._style in {'NUMBER_SLIDE', 'TEXTBOX'} or (self._style == 'NUMBER_CLICK' and self._is_mslider): textpos_x = self.x_screen + self._text_margin elif self._alignment == 'RIGHT': textpos_x = self.x_screen + int((self.width - (length1 / over_scale)) - self._text_margin) @@ -580,10 +579,9 @@ def mouse_up_over(self): # Up state self.__state = 0 - def bind_operator(self, bl_idname: str, text: str | None = None, - icon_path=None, icon_only=True, - **kwargs): + def bind_operator(self, bl_idname: str, text: str | None = None, icon_path=None, icon_only=True, **kwargs): from bpy.app.translations import pgettext_iface as _tips + op = getattr(getattr(bpy.ops, bl_idname.split('.')[0]), bl_idname.split('.')[1]) self.enabled = op.poll() self.set_mouse_up(lambda widget, event, x, y: op('INVOKE_DEFAULT', **kwargs)) @@ -592,13 +590,10 @@ def bind_operator(self, bl_idname: str, text: str | None = None, self.style = 'RADIO' self.description = _tips(op_type.description) self.python_cmd = f'bpy.ops.{bl_idname}()' - if icon_path is None: self.text = _tips(op_type.name) if text is None else text return - err = None - if os.path.exists(os.path.realpath(icon_path)): try: self.set_image(icon_path) @@ -614,4 +609,4 @@ def bind_operator(self, bl_idname: str, text: str | None = None, else: self.text = _tips('Error') + _tips('Path') self.textwo = _tips(op_type.name) if text is None else text - self.text_color = (0.8, 0.0, 0.0, 1.0) \ No newline at end of file + self.text_color = (0.8, 0.0, 0.0, 1.0) diff --git a/demo_panel_op.py b/demo_panel_op.py index 39bcdc8..472b46b 100644 --- a/demo_panel_op.py +++ b/demo_panel_op.py @@ -20,8 +20,8 @@ bl_info = {"name": "BL UI Widgets", "description": "UI Widgets to draw in the 3D view", "author": "Marcelo M. Marques (fork of Jayanam's original project)", - "version": (1, 0, 5), - "blender": (2, 80, 75), + "version": (1, 0, 6), + "blender": (3, 0, 0), "location": "View3D > viewport area", "support": "COMMUNITY", "category": "3D View", @@ -32,6 +32,9 @@ # --- ### Change log +# v1.0.6 (05.27.2023) - by atticus-lv +# Chang: Added example on how to use the new bind_operator function -- see code for the 'self.button3' below + # v1.0.5 (03.06.2023) - by Marcelo M. Marques # Added: 'time_step' property to allow customization of the interval in seconds between timer events @@ -202,23 +205,23 @@ def __init__(self): self.button2.state = 3 btnC += 1 # - # self.button3 = BL_UI_Button((btnX + ((btnW - 1 + btnG) * btnC)), btnY, btnW, btnH) - # self.button3.style = 'RADIO' - # self.button3.text = "ADD" - # self.button3.text_size = 13 - # self.button3.rounded_corners = (0, 0, 0, 0) - # self.button3.set_mouse_up(self.button3_click) - # self.button3.set_button_pressed(self.button3_pressed) - # self.button3.description = "Adds one little 'MONKEY' object to 3D View area" - # self.button3.python_cmd = "bpy.ops.object.dp_ot_draw_operator.button3_click()" - # if self.button3_pressed(self.button3): - # self.button3.state = 3 - + # For this next example it is shown the old/standard style for defining a button (see the "if True" section) and the alternative + # style (as of v1.0.6, see the 'else' section) that is to use the newly added bind_operator method (which is more compact). + # Notice that by using the new method there is not a way to call custom functions though. This may get enhanced in the future. self.button3 = BL_UI_Button((btnX + ((btnW - 1 + btnG) * btnC)), btnY, btnW, btnH) - self.button3.bind_operator('mesh.primitive_monkey_add',text ='ADD') - # self.button3.bind_operator('mesh.primitive_monkey_add',text ='ADD',icon_path=r'ERROR PATH TEST') - self.text_size = 13 + self.button3.text_size = 13 self.button3.rounded_corners = (0, 0, 0, 0) + if True: + self.button3.style = 'RADIO' + self.button3.text = "ADD" + self.button3.set_mouse_up(self.button3_click) + self.button3.set_button_pressed(self.button3_pressed) + self.button3.description = "Adds one little 'MONKEY' object to 3D View area" + self.button3.python_cmd = "bpy.ops.object.dp_ot_draw_operator.button3_click()" + self.button3.rounded_corners = (0, 0, 0, 0) + else: + self.button3.bind_operator('mesh.primitive_monkey_add', text ='ADD') + # self.button3.bind_operator('mesh.primitive_monkey_add', text ='ADD', icon_path=r'ERROR PATH TEST') if self.button3_pressed(self.button3): self.button3.state = 3 btnC += 1 @@ -453,6 +456,15 @@ def terminate_execution(self, area, region, event): # -- Button press handlers + # This is a sample when a context override is needed to work around the 'context is incorrect' error condition when calling bps operators + # def btn_click(self, widget, event, x, y): + # for window in bpy.context.window_manager.windows: + # for area in window.screen.areas: + # if area.type == 'VIEW_3D': + # with bpy.context.temp_override(window=window, area=area, region=area.regions[-1]): + # bpy.ops.view3d.view_axis(type = 'TOP') + # return True + def button1_click(self, widget, event, x, y): self.button2.enabled = True self.button3.enabled = True @@ -473,11 +485,11 @@ def button4_click(self, widget, event, x, y): self.button3.enabled = False self.press_only(4) -# I am not even obligated to create any of these functions, see? -# button5 does not have an active function tied to it at all. -# -# def button5_click(self, widget, event, x, y): -# # Miss Me + # I am not even obligated to create any of these functions, see? + # button5 does not have an active function bound to it at all. + # + # def button5_click(self, widget, event, x, y): + # do_something() def button6_click(self, widget, event, x, y): var = bpy.context.scene.var @@ -499,11 +511,11 @@ def button3_pressed(self, widget): def button4_pressed(self, widget): return (bpy.context.scene.var.OpState4) -# I am not even obligated to create any of these functions, see? -# button5 does not have an active function tied to it at all. -# -# def button5_pressed(self, widget): -# return (bpy.context.scene.var.OpState5) + # I am not even obligated to create any of these functions, see? + # button5 does not have an active function tied to it at all. + # + # def button5_pressed(self, widget): + # return (bpy.context.scene.var.OpState5) def button6_pressed(self, widget): return (bpy.context.scene.var.OpState6) diff --git a/prefs.py b/prefs.py index 8c901a5..08ee0ec 100644 --- a/prefs.py +++ b/prefs.py @@ -20,8 +20,8 @@ bl_info = {"name": "BL UI Widgets", "description": "UI Widgets to draw in the 3D view", "author": "Marcelo M. Marques (fork of Jayanam's original project)", - "version": (1, 0, 3), - "blender": (2, 80, 75), + "version": (1, 0, 4), + "blender": (3, 0, 0), "location": "View3D > viewport area", "support": "COMMUNITY", "category": "3D View", @@ -32,6 +32,9 @@ # --- ### Change log +# v1.0.4 (05.27.2023) - by Marcelo M. Marques +# Chang: Added atticus-lv to the acknowledges list for his kindly contributions to this addon + # v1.0.3 (09.25.2022) - by Marcelo M. Marques # Chang: Just small updates in some comments on the code @@ -172,7 +175,7 @@ def draw(self, context): box.label(text=" - BL UI Widgets original project by Jayanam (jayanam.games@gmail.com)") box.label(text=" (download it from https://github.com/jayanam/bl_ui_widgets)") box.label(text="") - box.label(text=" Special thanks to: @batFINGER, Shane Ambler (sambler), vananders, and many others,") + box.label(text=" Special thanks to: atticus-lv, @batFINGER, Shane Ambler, vananders, and many others,") box.label(text=" for their posts on the community forums, which have been crucial for making this addon.") box.label(text="")