diff --git a/__init__.py b/__init__.py index 4b23332..c2714a8 100644 --- a/__init__.py +++ b/__init__.py @@ -35,7 +35,7 @@ # 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.2 (09.30.2021) - by Marcelo M. Marques +# v1.0.2 (10.31.2021) - by Marcelo M. Marques # Chang: updated version with improvements and some clean up # v1.0.1 (09.20.2021) - by Marcelo M. Marques diff --git a/bl_ui_button.py b/bl_ui_button.py index 8def706..2b3aec6 100644 --- a/bl_ui_button.py +++ b/bl_ui_button.py @@ -32,7 +32,7 @@ # --- ### Change log -# v1.0.2 (09.30.2021) - by Marcelo M. Marques +# 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 # v1.0.1 (09.20.2021) - by Marcelo M. Marques diff --git a/bl_ui_draw_op.py b/bl_ui_draw_op.py index ff8531f..77466c0 100644 --- a/bl_ui_draw_op.py +++ b/bl_ui_draw_op.py @@ -32,10 +32,12 @@ # --- ### Change log -# v1.0.2 (09.30.2021) - by Marcelo M. Marques +# v1.0.2 (10.31.2021) - by Marcelo M. Marques # Added: 'region_pointer' class level property to indicate the region in which the drag_panel operator instance has been invoked(). # Added: 'valid_modes' property to indicate the 'bpy.context.mode' valid values for displaying the panel. +# Added: 'valid_scenario' function to validate whether the events must be handled by the widgets during a modal pass. # Added: 'get_region_pointer' function to retrieve the value of the 'region_pointer' class level property. +# Added: 'get_quadview_index' function to retrieve the region under which the mouse is hovering or being clicked. # Added: 'get_3d_area_and_region' function to retrieve the correct area and region (because those are not guaranteed to remain # the same after maximizing/restoring screen areas). # Added: 'valid_display_mode' function to determine whether the user has moved out of the valid area/region. @@ -156,15 +158,11 @@ def modal(self, context, event): if self.__finished: return {'FINISHED'} - area, region, abend = get_3d_area_and_region() - - if abend: - self.finish() - if self.terminate_execution(area, region): - self.finish() + valid, area, region = self.valid_scenario(context, event) if area: area.tag_redraw() - if self.handle_widget_events(event): + if valid: + if self.handle_widget_events(event, area, region): return {'RUNNING_MODAL'} # Not using this escape option, but left it here for documentation purpose @@ -173,7 +171,34 @@ def modal(self, context, event): return {'PASS_THROUGH'} - def handle_widget_events(self, event): + def valid_scenario(self, context, event): + valid = True + area, region, abend = get_3d_area_and_region() + if abend: + self.finish() + valid = False + elif not (area and region): + # Return but do not finish + valid = False + elif self.terminate_execution(area, region): + area.tag_redraw() + self.finish() + valid = False + elif event.type != 'TIMER': + # Check whether it is drawing on the same region where the panel was initially opened + mouse_region = get_quadview_index(context, event.mouse_x, event.mouse_y)[0] + if mouse_region is None or mouse_region.as_pointer() != self.get_region_pointer(): + # Not the same region, so skip handling events at this time + valid = False + return (valid, area, region) + + def handle_widget_events(self, event, area, region): + # Consider not a valid display mode when the overridable custom function + # returns True (meaning that it wants to suppress the rendering anyway). + if event.type != 'TIMER': + if self.suppress_rendering(area, region): + return False + result = False for widget in self.widgets: if widget.visible or event.type == 'TIMER': @@ -218,6 +243,15 @@ def draw_callback_px(self, op, context): # -- end of the personalized criteria for the given addon -- return + # Check whether it is drawing on the same region where the panel was initially opened + for region in context.area.regions: + if region.type == 'WINDOW': + if context.region == region: + if region.as_pointer() != self.get_region_pointer(): + # Not the same region, so skip drawing there + return + break + # This is to detect when user moved into an undesired 'bpy.context.mode' # and it will check also the programmer's defined suppress_rendering function if valid_display_mode(self.valid_modes, self.suppress_rendering): @@ -227,6 +261,23 @@ def draw_callback_px(self, op, context): # --- ### Helper functions +def get_quadview_index(context, x, y): + for area in context.screen.areas: + if area.type != 'VIEW_3D': + continue + is_quadview = (len(area.spaces.active.region_quadviews) == 0) + i = -1 + for region in area.regions: + if region.type == 'WINDOW': + i += 1 + if (x >= region.x and + y >= region.y and + x < region.width + region.x and + y < region.height + region.y): + return (region, area.spaces.active, None if is_quadview else i) + return (None, None, None) + + def get_3d_area_and_region(prefs=None): abend = False try: @@ -278,12 +329,12 @@ def valid_display_mode(valid_modes, suppress_rendering=None): return False area, region, abend = get_3d_area_and_region() - if abend: + if abend or not area or not region: return False else: if suppress_rendering is not None: # Consider not a valid display mode when the overridable custom function - # returns True (meaning that it wants to suppress the rendering at all). + # returns True (meaning that it wants to suppress the rendering anyway). if suppress_rendering(area, region): return False return True diff --git a/bl_ui_slider.py b/bl_ui_slider.py index d0c18b1..f538365 100644 --- a/bl_ui_slider.py +++ b/bl_ui_slider.py @@ -32,7 +32,7 @@ # --- ### Change log -# v1.0.2 (09.30.2021) - by Marcelo M. Marques +# v1.0.2 (10.31.2021) - by Marcelo M. Marques # Added: 'valid_modes' parm in the 'init' function and a call to 'super().init_mode' so we get everything correctly initialized. # Chang: improved reliability on 'mouse_exit' and 'button_mouse_down' overridable functions by conditioning the returned value diff --git a/bl_ui_textbox.py b/bl_ui_textbox.py index 7e94645..0b5ce64 100644 --- a/bl_ui_textbox.py +++ b/bl_ui_textbox.py @@ -32,7 +32,7 @@ # --- ### Change log -# v1.0.2 (09.30.21) - by Marcelo M. Marques +# v1.0.2 (10.31.2021) - by Marcelo M. Marques # Added: Logic to change state during a mouse move action so that the textbox background color is correctly set # v1.0.1 (09.20.2021) - by Marcelo M. Marques diff --git a/bl_ui_up_down.py b/bl_ui_up_down.py index 47a02b8..b2d5ec2 100644 --- a/bl_ui_up_down.py +++ b/bl_ui_up_down.py @@ -32,7 +32,7 @@ # --- ### Change log -# (09.30.2021) - by Marcelo M. Marques +# (10.31.2021) - by Marcelo M. Marques # Added: License, header and warning message. ### \/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/\/ ### diff --git a/bl_ui_widget.py b/bl_ui_widget.py index 0318b37..1954bf5 100644 --- a/bl_ui_widget.py +++ b/bl_ui_widget.py @@ -32,7 +32,7 @@ # --- ### Change log -# v1.0.2 (09.30.2021) - by Marcelo M. Marques +# v1.0.2 (10.31.2021) - by Marcelo M. Marques # Added: 'valid_modes' property to indicate the 'bpy.context.mode' valid values for displaying the panel. # Added: 'init_mode' function to allow the 'bl_ui_slider' subclass to call it without triggering an update from the former 'init' function. # Chang: How we determine whether the user has moved out of the valid area/region, now using the 'valid_display_mode()' function. @@ -40,7 +40,7 @@ # Chang: 'handle_event' function to rely on area and region values retrieved by 'get_3d_area_and_region()'. Also replaced the event's # mouse_region_x|y by calculated values using mouse_x|y and region.x|y because the former mouse_region_x|y stopped working # after the change on 'bl_ui_draw_op.invoke' method which switches the workspace back and forth. -# Chang: improved reliability on 'timer_event', 'mouse_down', 'mouse_move', 'mouse_up', 'mouse_enter' and 'mouse_exit' overridable +# Chang: improved reliability on 'timer_event', 'mouse_down', 'mouse_move', 'mouse_up', 'mouse_enter' and 'mouse_exit' overridable # functions by conditioning the returned value # v1.0.1 (09.20.2021) - by Marcelo M. Marques diff --git a/demo_panel_op.py b/demo_panel_op.py index 39c0f99..caece98 100644 --- a/demo_panel_op.py +++ b/demo_panel_op.py @@ -32,7 +32,7 @@ # --- ### Change log -# v1.0.2 (09.30.2021) - by Marcelo M. Marques +# v1.0.2 (10.31.2021) - by Marcelo M. Marques # Added: 'valid_modes' property to indicate the 'bpy.context.mode' valid values for displaying the panel. # Added: 'suppress_rendering' function that can be optionally used to control render bypass of the panel widget. # Added: 'area' and 'region' input parameters to the overridable 'terminate_execution()' function. @@ -362,11 +362,6 @@ def suppress_rendering(self, area, region): If not included here the function in the superclass just returns 'False' and rendering is always executed. When 'True" is returned below, the rendering of the entire panel is bypassed and it is not drawn on screen. ''' - if bpy.context.region.as_pointer() != self.get_region_pointer(): - # Avoid drawing the remote panel simultaneously in every duplicated area. - # The self.get_region_pointer() returns the 'region.as_pointer' value that was saved in the class variable - # when operator was initially invoked (in the case of this demo it will correspond to the N-Panel's region). - return True return False def terminate_execution(self, area, region): diff --git a/prefs.py b/prefs.py index af0ed73..5d2d62e 100644 --- a/prefs.py +++ b/prefs.py @@ -32,7 +32,7 @@ # --- ### Change log -# v1.0.2 (09.30.2021) - by Marcelo M. Marques +# v1.0.2 (10.31.2021) - by Marcelo M. Marques # Chang: the logic that retrieves region.width of the 3d view screen which has the Remote Control # v1.0.1 (09.20.2021) - by Marcelo M. Marques @@ -194,7 +194,6 @@ def execute(self, context): panX = 100 # Panel X coordinate, for top-left corner (some default, case it fails below) panY = panH + 40 - 1 # Panel Y coordinate, for top-left corner - # Here the region is used instead of area because data is retrieved from bpy.data.screens['Layout'] region = get_3d_area_and_region(prefs=True)[1] if region: if bpy.context.preferences.addons[__package__].preferences.RC_UI_BIND: