import bpy
import gpu
from gpu_extras.batch import batch_for_shader
from bpy.types import Operator
from bpy.props import BoolProperty
from ... utils.blender_ui import get_dpi, get_dpi_factor
from ... graphics.drawing2d import draw_text, set_drawing_dpi
from ... utility import addon
from ... utility import method_handler
from . import infobar
from ... utility.base_modal_controls import Base_Modal_Controls
class HOPS_OT_BoolScroll(Operator):
bl_idname = "hops.bool_scroll"
bl_label = "Scroll Booleans"
bl_description = "Use the scroll wheel to scroll through boolean modifiers on the selected object"
additive: BoolProperty()
def invoke(self, context, event):
self.base_controls = Base_Modal_Controls(context, event)
self.start_mouse_position = [event.mouse_region_x, event.mouse_region_y]
self.modifiers = [mod for mod in context.object.modifiers if mod.type == "BOOLEAN"]
self.bools = {None: None}
self.bool_index = 0
self.all_mods = False
self.loop = False
self.original_obj = context.object
for mod in self.modifiers:
if mod.object is not None:
self.bools.update({mod: {"original_show_viewport": mod.show_viewport, "override": False, "hide": mod.object.hide_viewport}})
if len(self.bools) == 1:
return {'CANCELLED'}
args = (context, )
self.draw_handler = bpy.types.SpaceView3D.draw_handler_add(self.draw_ui, args, "WINDOW", "POST_PIXEL")
context.window_manager.modal_handler_add(self)
infobar.initiate(self)
return {'RUNNING_MODAL'}
def modal(self, context, event):
self.base_controls.update(context, event)
if self.base_controls.pass_through:
return {'PASS_THROUGH'}
if self.base_controls.scroll:
self.bool_index += self.base_controls.scroll
if self.loop:
if self.bool_index >= len(self.bools):
self.bool_index = 0
if self.bool_index < 0:
self.bool_index = len(self.bools) - 1
else:
self.bool_index = max(min(self.bool_index, len(self.bools) - 1), 0)
if event.type == 'L' and event.value == 'PRESS':
self.loop = not self.loop
if event.type == 'A' and event.value == 'RELEASE':
if self.bools[list(self.bools.keys())[self.bool_index]] is not None:
# if list(self.bools.keys())[self.bool_index] is not None:
override_value = self.bools[list(self.bools.keys())[self.bool_index]]["override"]
self.bools[list(self.bools.keys())[self.bool_index]]["override"] = not override_value
self.original_obj.select_set(True)
context.view_layer.objects.active = self.original_obj
if event.type == 'M' and event.value == 'PRESS':
self.all_mods = not self.all_mods
self.bools = {None: None}
self.bool_index = 0
for mod in self.bools:
if mod is not None:
mod.show_viewport = self.bools[mod]["original_show_viewport"]
for mod in context.object.modifiers:
if self.all_mods:
self.bools.update({mod: {"original_show_viewport": mod.show_viewport, "override": False}})
if self.additive:
for count, mod in enumerate(self.bools):
if mod is not None:
if count <= self.bool_index:
mod.show_viewport = True
else:
mod.show_viewport = False
if self.bools[mod]["override"] or self.bools[list(self.bools.keys())[self.bool_index]] is None:
mod.show_viewport = False
else:
for mod in self.bools:
if mod is not None and hasattr(mod, "object"):
mod.show_viewport = self.bools[mod]["override"] # hide all mods except for those pressed A on.
mod.object.select_set(False)
mod.object.hide_viewport = True
if mod.show_viewport: # show and select objects that have modifier being shown in viewport.
mod.object.hide_viewport = False
mod.object.select_set(True)
if self.bools[list(self.bools.keys())[self.bool_index]] is not None:
current_bool = list(self.bools.keys())[self.bool_index]
current_bool.show_viewport = True # show viewport on the current mod.
if hasattr(current_bool, "object"):
current_bool.object.hide_viewport = False
current_bool.object.select_set(True)
if event.type == "H" and event.value == "PRESS":
addon.preference().property.hops_modal_help = not addon.preference().property.hops_modal_help
if self.base_controls.confirm or event.type in { 'RET', 'NUMPAD_ENTER'}:
self.finish()
for mod in self.bools:
if mod is not None and hasattr(mod, "object"):
if not mod.show_viewport:
mod.object.hide_viewport = True
else:
mod.object.hide_viewport = False
mod.object.select_set(True)
if not self.additive:
if hasattr(current_bool, "object") and current_bool.object is not None:
context.active_object.select_set(False)
current_bool.object.select_set(True)
context.view_layer.objects.active = current_bool.object
infobar.remove(self)
return {"FINISHED"}
if self.base_controls.tilde:
bpy.context.space_data.overlay.show_overlays = not bpy.context.space_data.overlay.show_overlays
if self.base_controls.cancel or event.type in { 'BACK_SPACE'}:
self.finish()
for mod in self.bools:
if mod is not None:
mod.show_viewport = self.bools[mod]["original_show_viewport"]
infobar.remove(self)
return {'CANCELLED'}
context.area.tag_redraw()
return {'RUNNING_MODAL'}
def finish(self):
# bpy.types.SpaceView3D.draw_handler_remove(self.draw_handler, "WINDOW")
self.remove_ui()
infobar.remove(self)
return {"FINISHED"}
def draw_ui(self, context):
method_handler(self._draw_ui,
arguments = (context, ),
identifier = 'Bool Regular Scroll UI Shader',
exit_method = self.remove_ui)
def _draw_ui(self, context):
x, y = self.start_mouse_position
object = context.active_object
set_drawing_dpi(get_dpi())
factor = get_dpi_factor()
offset = 5
l1 = (-1, 23, 4, 44)
l2 = (46, 23, 4, 220)
l4 = (46, 42, 26, 220)
vertices = (
(x + (l1[0] - offset) * factor, y + l1[1] * factor), (x + l1[0] * factor, y + l1[2] * factor), (x + (l1[3] - offset) * factor, y + l1[1] * factor), (x + l1[3] * factor, y + l1[2] * factor),
(x + (l2[0] - offset) * factor, y + l2[1] * factor), (x + l2[0] * factor, y + l2[2] * factor), (x + (l2[3] - offset) * factor, y + l2[1] * factor), (x + l2[3] * factor, y + l2[2] * factor),
(x + (l4[0] - offset) * factor, y + l4[1] * factor), (x + l4[0] * factor, y + l4[2] * factor), (x + (l4[3] - offset) * factor, y + l4[1] * factor), (x + l4[3] * factor, y + l4[2] * factor))
l1 = (l1[0] - 15, l1[1], l1[2], l1[0] - 6)
vertices2 = (
(x + (l1[0] - offset) * factor, y + l1[1] * factor), (x + l1[0] * factor, y + l1[2] * factor), (x + (l1[3] - offset) * factor, y + l1[1] * factor), (x + l1[3] * factor, y + l1[2] * factor))
indices = (
(0, 1, 2), (1, 2, 3), (4, 5, 6), (5, 6, 7), (8, 9, 10), (9, 10, 11))
indices2 = (
(0, 1, 2), (1, 2, 3))
built_in_shader = 'UNIFORM_COLOR' if bpy.app.version[0] >=4 else '2D_UNIFORM_COLOR'
shader = gpu.shader.from_builtin(built_in_shader)
batch = batch_for_shader(shader, 'TRIS', {"pos": vertices}, indices=indices)
shader.bind()
shader.uniform_float("color", addon.preference().color.Hops_hud_color)
gpu.state.blend_set('ALPHA')
batch.draw(shader)
gpu.state.blend_set('NONE')
shader2 = gpu.shader.from_builtin(built_in_shader)
batch2 = batch_for_shader(shader2, 'TRIS', {"pos": vertices2}, indices=indices2)
shader2.bind()
shader2.uniform_float("color", addon.preference().color.Hops_hud_help_color)
gpu.state.blend_set('ALPHA')
batch2.draw(shader2)
gpu.state.blend_set('NONE')
red = [1, 0.15, 0.15, 0.9]
draw_text("{}".format(self.bool_index),
x + 25 * factor, y + 9 * factor, size=12, color=addon.preference().color.Hops_hud_text_color)
if list(self.bools.keys())[self.bool_index] is not None:
mod = list(self.bools.keys())[self.bool_index]
name_color = addon.preference().color.Hops_hud_help_color
if not mod.show_viewport and self.additive:
name_color = red
if hasattr(mod, "object"):
draw_text("{}".format(mod.object.name),
x + 50 * factor, y + 9 * factor, size=12, color=addon.preference().color.Hops_hud_text_color)
draw_text("{}".format(mod.name),
x + 50 * factor, y + 28 * factor, size=12, color=(name_color))
self.draw_help(context, x, y, factor)
def draw_help(self, context, x, y, factor):
color_text2 = addon.preference().color.Hops_hud_help_color
if addon.preference().property.hops_modal_help:
draw_text(" scroll - change boolean visibility",
x + 45 * factor, y - 14 * factor, size=11, color=color_text2)
draw_text(" a - toggle current visibility",
x + 45 * factor, y - 26 * factor, size=11, color=color_text2)
draw_text(" m - use only booleans / all modifiers",
x + 45 * factor, y - 38 * factor, size=11, color=color_text2)
draw_text(" l - toggle looping",
x + 45 * factor, y - 50 * factor, size=11, color=color_text2)
else:
draw_text(" H - Show/Hide Help",
x + 45 * factor, y - 14 * factor, size=11, color=color_text2)
def remove_ui(self):
if self.draw_handler:
self.draw_handler = bpy.types.SpaceView3D.draw_handler_remove(self.draw_handler, "WINDOW")