Skip to content

Commit

Permalink
Added bind_operator method to bl_ui_button
Browse files Browse the repository at this point in the history
  • Loading branch information
mmmrqs committed May 28, 2023
1 parent d13f8c8 commit 7f97766
Show file tree
Hide file tree
Showing 4 changed files with 90 additions and 77 deletions.
5 changes: 4 additions & 1 deletion __init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand All @@ -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

Expand Down
87 changes: 41 additions & 46 deletions bl_ui_button.py
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand All @@ -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

Expand Down Expand Up @@ -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):
Expand All @@ -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):
Expand Down Expand Up @@ -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
Expand All @@ -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)

Expand Down Expand Up @@ -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

Expand All @@ -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)
Expand Down Expand Up @@ -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))
Expand All @@ -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)
Expand All @@ -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)
self.text_color = (0.8, 0.0, 0.0, 1.0)
66 changes: 39 additions & 27 deletions demo_panel_op.py
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand All @@ -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

Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand All @@ -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
Expand All @@ -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)
Expand Down
9 changes: 6 additions & 3 deletions prefs.py
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand All @@ -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

Expand Down Expand Up @@ -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="")

Expand Down

0 comments on commit 7f97766

Please sign in to comment.