semagnum / light-painter

Blender add-on that creates lights based on where the user paints.
https://semagnum.github.io/light-painter/
GNU General Public License v3.0
310 stars 6 forks source link

Unlocking Light Painter when cursor is over tools or header #53

Closed semagnum closed 10 months ago

semagnum commented 10 months ago

Anytime the cursor goes without the bounding boxes of the tools or N panel (including the spaces below them - Blender's code doesn't differentiate), the cursor returns to normal when using Light Painter tools. This enables users to click on other tools or buttons as needed (for example, enable rendered shading view if they don't know the shortcut).

Light Painter also cancels itself out when it sees it's no longer the current tool (ie you click on the select tool during Light Painter).

But artists may prefer just being locked into the modal and having to cancel the tool themselves. Will take user feedback on preferences.

(edit: the code also assumes the tool and area headers are at the top, when they could also be on the bottom. If cursor remains unlocked, handle this use case)

semagnum commented 10 months ago

Is this code just to show detecting whether the cursor is over the n-panel and therefore let the event pass through? Light Painter already does this. The issue is not discussing adding this. It's whether it should be removed (and not just for the n-panel, but other areas like the tools or header menus).

Let me know if my understanding of your code is incorrect.

chenpaner commented 10 months ago

from mathutils import Vector
class LIGHTPAINTER_OT_Lamp(bpy.types.Operator, BaseLightPaintTool, LampUtils):
    ......
    def extra_paint_controls(self, context, event):
        check_region(self,context,event)

        mouse_x = event.mouse_x
        if is_event_command(event, 'TYPE_TOGGLE'):
                    next_index = (LAMP_TYPES_ORDER.index(self.lamp_type) + 1) % len(LAMP_TYPES_ORDER)
                    self.lamp_type = LAMP_TYPES_ORDER[next_index]

        elif self.in_view_3d:  #When the mouse is in the 3D view,and not in the tools or N panel
            if self.old_event is not None:
                if self.old_event == 'OFFSET_MODE':
                    is_event_command(event, 'OFFSET_MODE')
                    self.set_drag_attr('offset', mouse_x)
                elif self.old_event == 'SIZE_MODE':
                    is_event_command(event, 'SIZE_MODE')
                    self.set_drag_attr('radius', mouse_x, drag_increment=0.01, drag_precise_increment=0.001)
                elif self.old_event == 'POWER_MODE':
                    is_event_command(event, 'POWER_MODE')
                    self.set_drag_attr('power', mouse_x, drag_increment=10, drag_precise_increment=1)
            else:
                if is_event_command(event, 'OFFSET_MODE'):
                    self.old_event = 'OFFSET_MODE'
                    self.set_drag_attr('offset', mouse_x)

                elif is_event_command(event, 'SIZE_MODE'):
                    self.old_event = 'SIZE_MODE'
                    self.set_drag_attr('radius', mouse_x, drag_increment=0.01, drag_precise_increment=0.001)

                elif is_event_command(event, 'POWER_MODE'):
                    self.old_event = 'POWER_MODE'
                    self.set_drag_attr('power', mouse_x, drag_increment=10, drag_precise_increment=1)

                #The following two are attempts to exit the three simulation states and clear old_event, otherwise it will be an infinite loop and cannot exit.
                #But neither of the following two operations work
                #maybe need add other event to clean old_event

                # elif event.type == 'RIGHTMOUSE' :
                #     if event.value == 'PRESS':
                #         self.old_event = None
                #         print("Old Event:", self.old_event)
                #         pass
                # else: 
                #     self.old_event = None
                #     print("Old Event:", self.old_event)

            print("Old Event:", self.old_event)

        elif is_event_command(event, 'RELATIVE_POWER_TOGGLE'):
                    self.is_power_relative = not self.is_power_relative

        elif self.check_axis_event(event):
            pass  # if True, event is handled
        elif self.check_visibility_event(event):
            pass  # if True, event is handled

        else:
            return False

        return True
    ......

def check_region(self,context,event):
    try:
        self.in_view_3d = False
        for area in context.screen.areas:
            if area.type == "VIEW_3D" :
                for region in context.area.regions:
                    if region.type == "TOOLS":
                        t_panel = region
                    elif region.type == "UI":
                        ui_panel = region
                view_3d_region_x = Vector((context.area.x + t_panel.width, context.area.x + context.area.width - (ui_panel.width+1)))
                view_3d_region_y = Vector((context.region.y, context.region.y + context.region.height))
                if (event.mouse_x > view_3d_region_x[0] and event.mouse_x < view_3d_region_x[1] \
                and event.mouse_y > view_3d_region_y[0] and event.mouse_y < view_3d_region_y[1]):
                    self.in_view_3d = True
                    return True
    except:
        pass
semagnum commented 10 months ago

Thank you for testing that :) the check_region is helpful. I started working on a solution yesterday, hopefully have it released soon.

I haven't found any other existing Blender tools or modal operators that allow clicking buttons in external regions while running, not even the knife tool. So maybe Light Painter should do the same. Will keep thinking on it.

semagnum commented 10 months ago

PR merged:

blocks all cursor input within area, including side panels and tool header. May add this back later, but it assumes too much and can cause confusion why input stops working where the cursor is below (but not in) side panels.

Cursor over other areas (but not in drag mode) will still click buttons, which will help for those using multiple 3D views to see different angles and tweaks. Closing, will release this version.