def execute(self, context): #add a textbox to display information. attach it to this #add a persisetent callback on scene update #which monitors the status of the ODC #clear previous handlers clear_help_handlers() global implant_help_app_handle implant_help_app_handle = bpy.app.handlers.scene_update_pre.append(implant_help_parser) global help_display_box if help_display_box != None: del help_display_box help_text = 'Open Dental Implant Help Wizard \n' selections = odcutils.implant_selection(bpy.context) #weird, how do I specify better arguments? sel_names = [item.name for item in selections] help_text += 'Selected Implants: ' + ', '.join(sel_names) + '\n' help_text += 'Next Step: ' + 'TBA' help_display_box = TextBox(context,500,500,300,100,10,20, help_text) help_display_box.snap_to_corner(context, corner = [0,1]) global implant_help_draw_handle implant_help_draw_handle = bpy.types.SpaceView3D.draw_handler_add(odc_help_draw, (self, context), 'WINDOW', 'POST_PIXEL') return {'FINISHED'}
def invoke(self, context, event): settings = get_settings() libpath = settings.ortho_lib assets = obj_list_from_lib(libpath) if settings.bracket in assets: current_obs = [ob.name for ob in bpy.data.objects] obj_from_lib(settings.ortho_lib, settings.bracket) for ob in bpy.data.objects: if ob.name not in current_obs: Bracket = ob Bracket.hide = False context.scene.objects.link(Bracket) else: Bracket = None if context.object and context.object.type == 'MESH': self.bracket_manager = BracketDataManager( context, snap_type='OBJECT', snap_object=context.object, name='Bracket', bracket=Bracket) self.bracket_slicer = BracektSlicer(context, self.bracket_manager) else: self.bracket_manager = BracketDataManager(context, snap_type='SCENE', snap_object=None, name='Bracket', bracket=Bracket) self.bracket_slicer = None help_txt = "DRAW MARGIN OUTLINE\n\nLeft Click on model to place bracket.\n G to grab \n S to show slice \n ENTER to confirm \n ESC to cancel" self.help_box = TextBox(context, 500, 500, 300, 200, 10, 20, help_txt) self.help_box.snap_to_corner(context, corner=[1, 1]) self.mode = 'start' self._handle = bpy.types.SpaceView3D.draw_handler_add( bracket_placement_draw_callback, (self, context), 'WINDOW', 'POST_PIXEL') context.window_manager.modal_handler_add(self) return {'RUNNING_MODAL'}
def invoke(self, context, event): settings = get_settings() dbg = settings.debug if context.space_data.region_3d.is_perspective: #context.space_data.region_3d.is_perspective = False bpy.ops.view3d.view_persportho() if context.space_data.type != 'VIEW_3D': self.report({'WARNING'}, "Active space must be a View3d") return {'CANCELLED'} #gather all the teeth in the scene TODO, keep better track self.target = 11 self.message = "Set axis for " + str(self.target) if context.mode != 'OBJECT': bpy.ops.object.mode_set(mode='OBJECT') #check for an armature bpy.ops.object.select_all(action='DESELECT') help_txt = "Left click on the tooth indicated to label it. Right click skip a tooth \n Up or Dn Arrow to change label\n Enter to finish \n ESC to cancel" self.help_box = TextBox(context, 500, 500, 300, 200, 10, 20, help_txt) self.help_box.fit_box_width_to_text_lines() self.help_box.fit_box_height_to_text_lines() self.help_box.snap_to_corner(context, corner=[1, 1]) aspect, mid = menu_utils.view3d_get_size_and_mid(context) self.target_box = TextBox(context, mid[0], aspect[1] - 20, 300, 200, 10, 20, self.message) self.target_box.format_and_wrap_text() self.target_box.fit_box_width_to_text_lines() self.target_box.fit_box_height_to_text_lines() self.mode = 'main' context.window_manager.modal_handler_add(self) self._handle = bpy.types.SpaceView3D.draw_handler_add( rapid_label_teeth_callback, (self, context), 'WINDOW', 'POST_PIXEL') return {'RUNNING_MODAL'}
def execute(self, context): #add a textbox to display information. attach it to this #add a persisetent callback on scene update #which monitors the status of the ODC #clear previous handlers clear_help_handlers() global guide_help_app_handle guide_help_app_handle = bpy.app.handlers.scene_update_pre.append(guide_help_parser) global help_display_box if help_display_box != None: del help_display_box help_text = 'Open Dental Guide Help Wizard \n' help_text += 'Next Step: ' + 'TBA' help_display_box = TextBox(context,500,500,300,100,10,20, help_text) help_display_box.snap_to_corner(context, corner = [0,1]) global guide_help_draw_handle guide_help_draw_handle = bpy.types.SpaceView3D.draw_handler_add(odc_help_draw, (self, context), 'WINDOW', 'POST_PIXEL') return {'FINISHED'}
class OPENDENTAL_OT_add_bone_roots(bpy.types.Operator): """Set the axis and direction of the roots for crowns from view""" bl_idname = "opendental.add_bone_roots" bl_label = "Add bone roots" bl_options = {'REGISTER', 'UNDO'} @classmethod def poll(self, context): if context.mode != 'OBJECT': return False else: return True def set_axis(self, context, event): if not self.target: return empty_name = self.target.name + 'root_empty' if empty_name in context.scene.objects: ob = context.scene.objects[empty_name] ob.empty_draw_type = 'SINGLE_ARROW' ob.empty_draw_size = 10 else: ob = bpy.data.objects.new(empty_name, None) ob.empty_draw_type = 'SINGLE_ARROW' ob.empty_draw_size = 10 context.scene.objects.link(ob) coord = (event.mouse_region_x, event.mouse_region_y) v3d = context.space_data rv3d = v3d.region_3d view_vector = view3d_utils.region_2d_to_vector_3d( context.region, rv3d, coord) ray_origin = view3d_utils.region_2d_to_origin_3d( context.region, rv3d, coord) ray_target = ray_origin + (view_vector * 1000) if bversion() < '002.077.000': res, obj, loc, no, mx = context.scene.ray_cast( ray_origin, ray_target) else: res, loc, no, ind, obj, mx = context.scene.ray_cast( ray_origin, view_vector) if res: if obj != self.target: return ob.location = loc else: return if ob.rotation_mode != 'QUATERNION': ob.rotation_mode = 'QUATERNION' vrot = rv3d.view_rotation ob.rotation_quaternion = vrot def advance_next_prep(self, context): if self.target == None: self.target = self.units[0] ind = self.units.index(self.target) prev = int(math.fmod(ind + 1, len(self.units))) self.target = self.units[prev] self.message = "Set axis for %s" % self.target.name self.target_box.raw_text = self.message self.target_box.format_and_wrap_text() self.target_box.fit_box_width_to_text_lines() for obj in context.scene.objects: obj.select = False self.target.select = True context.space_data.region_3d.view_location = self.target.location def select_prev_unit(self, context): if self.target == None: self.target = self.units[0] ind = self.units.index(self.target) prev = int(math.fmod(ind - 1, len(self.units))) self.target = self.units[prev] self.message = "Set axis for %s" % self.target.name self.target_box.raw_text = self.message self.target_box.format_and_wrap_text() self.target_box.fit_box_width_to_text_lines() for obj in context.scene.objects: obj.select = False self.target.select = True context.space_data.region_3d.view_location = self.target.location def update_selection(self, context): if not len(context.selected_objects): self.message = "Right Click to Select" self.target = None return if context.selected_objects[0] not in self.units: self.message = "Selected Object must be tooth" self.target = None return self.target = context.selected_objects[0] self.message = "Set axis for %s" % self.target.name self.target_box.raw_text = self.message self.target_box.format_and_wrap_text() self.target_box.fit_box_width_to_text_lines() def empties_to_bones(self, context): bpy.ops.object.select_all(action='DESELECT') arm_ob = bpy.data.objects['Roots'] arm_ob.select = True context.scene.objects.active = arm_ob bpy.ops.object.mode_set(mode='EDIT') for ob in self.units: e = context.scene.objects.get(ob.name + 'root_empty') b = arm_ob.data.edit_bones.get(ob.name + 'root') if e != None and b != None: b.transform( e.matrix_world) #this gets the local x,y,z in order Z = e.matrix_world.to_quaternion() * Vector((0, 0, 1)) b.tail.xyz = e.location b.head.xyz = e.location - 16 * Z b.head_radius = 1.5 b.tail_radius = 2.5 context.scene.objects.unlink(e) e.user_clear() bpy.data.objects.remove(e) else: print('missing bone or empty') bpy.ops.object.mode_set(mode='OBJECT') def modal_main(self, context, event): # general navigation nmode = self.modal_nav(event) if nmode != '': return nmode #stop here and tell parent modal to 'PASS_THROUGH' if event.type in {'RIGHTMOUSE'} and event.value == 'PRESS': self.update_selection(context) return 'pass' elif event.type == 'RIGHTMOUSE' and event.value == 'RELEASE': self.update_selection(context) if len(context.selected_objects): context.space_data.region_3d.view_location = context.selected_objects[ 0].location return 'main' elif event.type in {'LEFTMOUSE'} and event.value == 'PRESS': self.set_axis(context, event) self.advance_next_prep(context) return 'main' elif event.type in {'DOWN_ARROW'} and event.value == 'PRESS': self.select_prev_unit(context) return 'main' elif event.type in {'UP_ARROW'} and event.value == 'PRESS': self.advance_next_prep(context) return 'main' elif event.type in {'ESC'}: #keep track of and delete new objects? reset old transforms? return 'cancel' elif event.type in {'RET'} and event.value == 'PRESS': self.empties_to_bones(context) return 'finish' return 'main' def modal_nav(self, event): events_nav = { 'MIDDLEMOUSE', 'WHEELINMOUSE', 'WHEELOUTMOUSE', 'WHEELUPMOUSE', 'WHEELDOWNMOUSE' } #TODO, better navigation, another tutorial handle_nav = False handle_nav |= event.type in events_nav if handle_nav: return 'nav' return '' def modal(self, context, event): context.area.tag_redraw() FSM = {} FSM['main'] = self.modal_main FSM['pass'] = self.modal_main FSM['nav'] = self.modal_nav nmode = FSM[self.mode](context, event) if nmode == 'nav': return {'PASS_THROUGH'} if nmode in {'finish', 'cancel'}: #clean up callbacks bpy.types.SpaceView3D.draw_handler_remove(self._handle, 'WINDOW') return {'FINISHED'} if nmode == 'finish' else {'CANCELLED'} if nmode == 'pass': self.mode = 'main' return {'PASS_THROUGH'} if nmode: self.mode = nmode return {'RUNNING_MODAL'} def invoke(self, context, event): settings = get_settings() dbg = settings.debug if context.space_data.region_3d.is_perspective: #context.space_data.region_3d.is_perspective = False bpy.ops.view3d.view_persportho() if context.space_data.type != 'VIEW_3D': self.report({'WARNING'}, "Active space must be a View3d") return {'CANCELLED'} #gather all the teeth in the scene TODO, keep better track self.units = [] for i in TOOTH_NUMBERS: ob = context.scene.objects.get(str(i)) if ob != None and not ob.hide: self.units.append(ob) if not len(self.units): self.report({ 'ERROR' }, "There are no teeth in the scene!, Teeth must be named 2 digits eg 11 or 46" ) return {'CANCELLED'} self.target = self.units[0] self.message = "Set axis for %s" % self.target.name #check for an armature bpy.ops.object.select_all(action='DESELECT') if context.mode != 'OBJECT': bpy.ops.object.mode_set(mode='OBJECT') if context.scene.objects.get('Roots'): root_arm = context.scene.objects.get('Roots') root_arm.select = True root_arm.hide = False context.scene.objects.active = root_arm bpy.ops.object.mode_set(mode='EDIT') for ob in self.units: if ob.name + 'root' not in root_arm.data.bones: bpy.ops.armature.bone_primitive_add(name=ob.name + 'root') else: root_data = bpy.data.armatures.new('Roots') root_arm = bpy.data.objects.new('Roots', root_data) context.scene.objects.link(root_arm) root_arm.select = True context.scene.objects.active = root_arm bpy.ops.object.mode_set(mode='EDIT') for ob in self.units: bpy.ops.armature.bone_primitive_add(name=ob.name + 'root') bpy.ops.object.mode_set(mode='OBJECT') root_arm.select = False self.units[0].select = True help_txt = "Right click to select a tooth \n Align View with root, mes and distal\n Up Arrow and Dn Arrow to select different units \n Left click in middle of prep to set axis \n Enter to finish \n ESC to cancel" self.help_box = TextBox(context, 500, 500, 300, 200, 10, 20, help_txt) self.help_box.fit_box_width_to_text_lines() self.help_box.fit_box_height_to_text_lines() self.help_box.snap_to_corner(context, corner=[1, 1]) aspect, mid = menu_utils.view3d_get_size_and_mid(context) self.target_box = TextBox(context, mid[0], aspect[1] - 20, 300, 200, 10, 20, self.message) self.target_box.format_and_wrap_text() self.target_box.fit_box_width_to_text_lines() self.target_box.fit_box_height_to_text_lines() self.mode = 'main' context.window_manager.modal_handler_add(self) self._handle = bpy.types.SpaceView3D.draw_handler_add( insertion_axis_draw_callback, (self, context), 'WINDOW', 'POST_PIXEL') return {'RUNNING_MODAL'}
class OPENDENTAL_OT_fast_label_teeth(bpy.types.Operator): """Label teeth by clicking on them""" bl_idname = "opendental.fast_label_teeth" bl_label = "Fast Label Teeth" bl_options = {'REGISTER', 'UNDO'} @classmethod def poll(self, context): if context.mode != 'OBJECT': return False else: return True def set_axis(self, context, event): coord = (event.mouse_region_x, event.mouse_region_y) v3d = context.space_data rv3d = v3d.region_3d view_vector = view3d_utils.region_2d_to_vector_3d( context.region, rv3d, coord) ray_origin = view3d_utils.region_2d_to_origin_3d( context.region, rv3d, coord) ray_target = ray_origin + (view_vector * 1000) if bversion() < '002.077.000': res, obj, loc, no, mx = context.scene.ray_cast( ray_origin, ray_target) else: res, loc, no, ind, obj, mx = context.scene.ray_cast( ray_origin, view_vector) if res: obj.name = str(self.target) for ob in bpy.data.objects: ob.select = False obj.select = True obj.show_name = True context.scene.objects.active = obj bpy.ops.object.origin_set(type='ORIGIN_GEOMETRY', center='BOUNDS') return True else: return False def advance_next_prep(self, context): def next_ind(n): if math.fmod(n, 10) < 7: return n + 1 elif math.fmod(n, 10) == 7: if n == 17: return 21 elif n == 27: return 31 elif n == 37: return 41 elif n == 47: return 11 self.target = next_ind(self.target) self.message = "Click on tooth % i" % self.target self.target_box.raw_text = self.message self.target_box.format_and_wrap_text() self.target_box.fit_box_width_to_text_lines() def select_prev_unit(self, context): def prev_ind(n): if math.fmod(n, 10) > 1: return n - 1 elif math.fmod(n, 10) == 1: if n == 11: return 41 elif n == 21: return 11 elif n == 31: return 21 elif n == 41: return 31 self.target = prev_ind(self.target) self.message = "Click on tooth %i" % self.target self.target_box.raw_text = self.message self.target_box.format_and_wrap_text() self.target_box.fit_box_width_to_text_lines() def modal_main(self, context, event): # general navigation nmode = self.modal_nav(event) if nmode != '': return nmode #stop here and tell parent modal to 'PASS_THROUGH' if event.type in {'RIGHTMOUSE'} and event.value == 'PRESS': self.advance_next_prep(context) return 'pass' elif event.type in {'LEFTMOUSE'} and event.value == 'PRESS': res = self.set_axis(context, event) if res: self.advance_next_prep(context) return 'main' elif event.type in {'DOWN_ARROW'} and event.value == 'PRESS': self.select_prev_unit(context) return 'main' elif event.type in {'UP_ARROW'} and event.value == 'PRESS': self.advance_next_prep(context) return 'main' elif event.type in {'ESC'}: #keep track of and delete new objects? reset old transforms? return 'cancel' elif event.type in {'RET'} and event.value == 'PRESS': #self.empties_to_bones(context) return 'finish' return 'main' def modal_nav(self, event): events_nav = { 'MIDDLEMOUSE', 'WHEELINMOUSE', 'WHEELOUTMOUSE', 'WHEELUPMOUSE', 'WHEELDOWNMOUSE' } #TODO, better navigation, another tutorial handle_nav = False handle_nav |= event.type in events_nav if handle_nav: return 'nav' return '' def modal(self, context, event): context.area.tag_redraw() FSM = {} FSM['main'] = self.modal_main FSM['pass'] = self.modal_main FSM['nav'] = self.modal_nav nmode = FSM[self.mode](context, event) if nmode == 'nav': return {'PASS_THROUGH'} if nmode in {'finish', 'cancel'}: #clean up callbacks bpy.types.SpaceView3D.draw_handler_remove(self._handle, 'WINDOW') return {'FINISHED'} if nmode == 'finish' else {'CANCELLED'} if nmode == 'pass': self.mode = 'main' return {'PASS_THROUGH'} if nmode: self.mode = nmode return {'RUNNING_MODAL'} def invoke(self, context, event): settings = get_settings() dbg = settings.debug if context.space_data.region_3d.is_perspective: #context.space_data.region_3d.is_perspective = False bpy.ops.view3d.view_persportho() if context.space_data.type != 'VIEW_3D': self.report({'WARNING'}, "Active space must be a View3d") return {'CANCELLED'} #gather all the teeth in the scene TODO, keep better track self.target = 11 self.message = "Set axis for " + str(self.target) if context.mode != 'OBJECT': bpy.ops.object.mode_set(mode='OBJECT') #check for an armature bpy.ops.object.select_all(action='DESELECT') help_txt = "Left click on the tooth indicated to label it. Right click skip a tooth \n Up or Dn Arrow to change label\n Enter to finish \n ESC to cancel" self.help_box = TextBox(context, 500, 500, 300, 200, 10, 20, help_txt) self.help_box.fit_box_width_to_text_lines() self.help_box.fit_box_height_to_text_lines() self.help_box.snap_to_corner(context, corner=[1, 1]) aspect, mid = menu_utils.view3d_get_size_and_mid(context) self.target_box = TextBox(context, mid[0], aspect[1] - 20, 300, 200, 10, 20, self.message) self.target_box.format_and_wrap_text() self.target_box.fit_box_width_to_text_lines() self.target_box.fit_box_height_to_text_lines() self.mode = 'main' context.window_manager.modal_handler_add(self) self._handle = bpy.types.SpaceView3D.draw_handler_add( rapid_label_teeth_callback, (self, context), 'WINDOW', 'POST_PIXEL') return {'RUNNING_MODAL'}
def invoke(self, context, event): settings = get_settings() dbg = settings.debug if context.space_data.region_3d.is_perspective: #context.space_data.region_3d.is_perspective = False bpy.ops.view3d.view_persportho() if context.space_data.type != 'VIEW_3D': self.report({'WARNING'}, "Active space must be a View3d") return {'CANCELLED'} #gather all the teeth in the scene TODO, keep better track self.units = [] for i in TOOTH_NUMBERS: ob = context.scene.objects.get(str(i)) if ob != None and not ob.hide: self.units.append(ob) if not len(self.units): self.report({ 'ERROR' }, "There are no teeth in the scene!, Teeth must be named 2 digits eg 11 or 46" ) return {'CANCELLED'} self.target = self.units[0] self.message = "Set axis for %s" % self.target.name #check for an armature bpy.ops.object.select_all(action='DESELECT') if context.mode != 'OBJECT': bpy.ops.object.mode_set(mode='OBJECT') if context.scene.objects.get('Roots'): root_arm = context.scene.objects.get('Roots') root_arm.select = True root_arm.hide = False context.scene.objects.active = root_arm bpy.ops.object.mode_set(mode='EDIT') for ob in self.units: if ob.name + 'root' not in root_arm.data.bones: bpy.ops.armature.bone_primitive_add(name=ob.name + 'root') else: root_data = bpy.data.armatures.new('Roots') root_arm = bpy.data.objects.new('Roots', root_data) context.scene.objects.link(root_arm) root_arm.select = True context.scene.objects.active = root_arm bpy.ops.object.mode_set(mode='EDIT') for ob in self.units: bpy.ops.armature.bone_primitive_add(name=ob.name + 'root') bpy.ops.object.mode_set(mode='OBJECT') root_arm.select = False self.units[0].select = True help_txt = "Right click to select a tooth \n Align View with root, mes and distal\n Up Arrow and Dn Arrow to select different units \n Left click in middle of prep to set axis \n Enter to finish \n ESC to cancel" self.help_box = TextBox(context, 500, 500, 300, 200, 10, 20, help_txt) self.help_box.fit_box_width_to_text_lines() self.help_box.fit_box_height_to_text_lines() self.help_box.snap_to_corner(context, corner=[1, 1]) aspect, mid = menu_utils.view3d_get_size_and_mid(context) self.target_box = TextBox(context, mid[0], aspect[1] - 20, 300, 200, 10, 20, self.message) self.target_box.format_and_wrap_text() self.target_box.fit_box_width_to_text_lines() self.target_box.fit_box_height_to_text_lines() self.mode = 'main' context.window_manager.modal_handler_add(self) self._handle = bpy.types.SpaceView3D.draw_handler_add( insertion_axis_draw_callback, (self, context), 'WINDOW', 'POST_PIXEL') return {'RUNNING_MODAL'}
def invoke(self, context, event): layers_copy = [layer for layer in context.scene.layers] context.scene.layers[0] = True tooth = odcutils.tooth_selection(context)[0] self.tooth = tooth sce = bpy.context.scene a = tooth.name prep = tooth.prep_model margin = str(a + "_Margin") self.crv = None self.margin_manager = None if margin in bpy.data.objects: self.report({ 'WARNING' }, "you have already made a margin for this tooth, hit esc and then undo if you didn't want to replace it" ) if prep and prep in bpy.data.objects: Prep = bpy.data.objects[prep] Prep.hide = False L = Prep.location ###Keep a list of unhidden objects for o in sce.objects: if o.name != prep and not o.hide: o.hide = True self.crv = CurveDataManager(context, snap_type='OBJECT', snap_object=Prep, shrink_mod=True, name=margin) self.margin_manager = MarginSlicer(tooth, context, self.crv) else: self.report({ 'WARNING' }, "There is no prep for this tooth, your margin will snap to the master model or all objects in scene" ) master = sce.odc_props.master if master and master in bpy.data.objects: Master = bpy.data.objects[master] if prep not in bpy.data.objects: self.crv = CurveDataManager(context, snap_type='OBJECT', snap_object=Master, shrink_mod=True, name=margin) self.margin_manager = MarginSlicer(tooth, context, self.crv) else: self.report({'WARNING'}, "No master model...there are risks!") if not self.crv: self.crv = CurveDataManager(context, snap_type='SCENE', snap_object=None, shrink_mod=False, name=margin) tooth.margin = self.crv.crv_obj.name help_txt = "DRAW MARGIN OUTLINE\n\nLeft Click on model to draw outline \nRight click to delete a point \nLeft Click last point to make loop \n G to grab \n S to show slice \n ENTER to confirm \n ESC to cancel" self.help_box = TextBox(context, 500, 500, 300, 200, 10, 20, help_txt) self.help_box.snap_to_corner(context, corner=[1, 1]) self.mode = 'main' self._handle = bpy.types.SpaceView3D.draw_handler_add( icrnmgn_draw_callback, (self, context), 'WINDOW', 'POST_PIXEL') context.window_manager.modal_handler_add(self) return {'RUNNING_MODAL'}
class OPENDENTAL_OT_mark_crown_margin(bpy.types.Operator): """Mark Margin. Draw a line with the mouse to extrude bezier curves""" bl_idname = "opendental.mark_crown_margin" bl_label = "Mark Crown Margin" bl_options = {'REGISTER', 'UNDO'} @classmethod def poll(cls, context): #restoration exists and is in scene teeth = odcutils.tooth_selection(context) if teeth != []: #This can only happen one tooth at a time #tooth = teeth[0] #return tooth.prep_model in bpy.data.objects return True else: return False def modal_nav(self, event): events_nav = { 'MIDDLEMOUSE', 'WHEELINMOUSE', 'WHEELOUTMOUSE', 'WHEELUPMOUSE', 'WHEELDOWNMOUSE' } #TODO, better navigation, another tutorial handle_nav = False handle_nav |= event.type in events_nav if handle_nav: return 'nav' return '' def modal_main(self, context, event): # general navigation nmode = self.modal_nav(event) if nmode != '': return nmode #stop here and tell parent modal to 'PASS_THROUGH' #after navigation filter, these are relevant events in this state if event.type == 'G' and event.value == 'PRESS': if self.crv.grab_initiate(): return 'grab' else: #error, need to select a point return 'main' if event.type == 'MOUSEMOVE': self.crv.hover(context, event.mouse_region_x, event.mouse_region_y) return 'main' if event.type == 'LEFTMOUSE' and event.value == 'PRESS': x, y = event.mouse_region_x, event.mouse_region_y self.crv.click_add_point(context, x, y) return 'main' if event.type == 'RIGHTMOUSE' and event.value == 'PRESS': self.crv.click_delete_point(mode='mouse') return 'main' if event.type == 'X' and event.value == 'PRESS': self.crv.delete_selected(mode='selected') return 'main' if event.type == 'S' and event.value == 'PRESS' and self.margin_manager: self.margin_manager.prepare_slice() return 'slice' if event.type == 'RET' and event.value == 'PRESS': return 'finish' elif event.type == 'ESC' and event.value == 'PRESS': del_obj = self.crv.crv_obj context.scene.objects.unlink(del_obj) bpy.data.objects.remove(del_obj) self.tooth.margin = '' return 'cancel' return 'main' def modal_grab(self, context, event): # no navigation in grab mode if event.type == 'LEFTMOUSE' and event.value == 'PRESS': #confirm location self.crv.grab_confirm() return 'main' elif event.type in {'RIGHTMOUSE', 'ESC'} and event.value == 'PRESS': #put it back! self.crv.grab_cancel() return 'main' elif event.type == 'MOUSEMOVE': #update the b_pt location self.crv.grab_mouse_move(context, event.mouse_region_x, event.mouse_region_y) return 'grab' def modal_slice(self, context, event): # no navigation in grab mode if event.type == 'LEFTMOUSE' and event.value == 'PRESS': #confirm location self.margin_manager.slice_confirm() return 'main' elif event.type in {'RIGHTMOUSE', 'ESC'} and event.value == 'PRESS': #put it back! self.margin_manager.slice_cancel() return 'main' elif event.type == 'MOUSEMOVE': #update the b_pt location self.margin_manager.slice_mouse_move(context, event.mouse_region_x, event.mouse_region_y) return 'slice' def modal(self, context, event): context.area.tag_redraw() FSM = {} FSM['main'] = self.modal_main FSM['grab'] = self.modal_grab FSM['slice'] = self.modal_slice FSM['nav'] = self.modal_nav nmode = FSM[self.mode](context, event) if nmode == 'nav': return {'PASS_THROUGH'} if nmode in {'finish', 'cancel'}: #clean up callbacks bpy.types.SpaceView3D.draw_handler_remove(self._handle, 'WINDOW') return {'FINISHED'} if nmode == 'finish' else {'CANCELLED'} if nmode: self.mode = nmode return {'RUNNING_MODAL'} def invoke(self, context, event): layers_copy = [layer for layer in context.scene.layers] context.scene.layers[0] = True tooth = odcutils.tooth_selection(context)[0] self.tooth = tooth sce = bpy.context.scene a = tooth.name prep = tooth.prep_model margin = str(a + "_Margin") self.crv = None self.margin_manager = None if margin in bpy.data.objects: self.report({ 'WARNING' }, "you have already made a margin for this tooth, hit esc and then undo if you didn't want to replace it" ) if prep and prep in bpy.data.objects: Prep = bpy.data.objects[prep] Prep.hide = False L = Prep.location ###Keep a list of unhidden objects for o in sce.objects: if o.name != prep and not o.hide: o.hide = True self.crv = CurveDataManager(context, snap_type='OBJECT', snap_object=Prep, shrink_mod=True, name=margin) self.margin_manager = MarginSlicer(tooth, context, self.crv) else: self.report({ 'WARNING' }, "There is no prep for this tooth, your margin will snap to the master model or all objects in scene" ) master = sce.odc_props.master if master and master in bpy.data.objects: Master = bpy.data.objects[master] if prep not in bpy.data.objects: self.crv = CurveDataManager(context, snap_type='OBJECT', snap_object=Master, shrink_mod=True, name=margin) self.margin_manager = MarginSlicer(tooth, context, self.crv) else: self.report({'WARNING'}, "No master model...there are risks!") if not self.crv: self.crv = CurveDataManager(context, snap_type='SCENE', snap_object=None, shrink_mod=False, name=margin) tooth.margin = self.crv.crv_obj.name help_txt = "DRAW MARGIN OUTLINE\n\nLeft Click on model to draw outline \nRight click to delete a point \nLeft Click last point to make loop \n G to grab \n S to show slice \n ENTER to confirm \n ESC to cancel" self.help_box = TextBox(context, 500, 500, 300, 200, 10, 20, help_txt) self.help_box.snap_to_corner(context, corner=[1, 1]) self.mode = 'main' self._handle = bpy.types.SpaceView3D.draw_handler_add( icrnmgn_draw_callback, (self, context), 'WINDOW', 'POST_PIXEL') context.window_manager.modal_handler_add(self) return {'RUNNING_MODAL'}
class OPENDENTAL_OT_place_bracket(bpy.types.Operator): """Place Bracket on surface of selected object""" bl_idname = "opendental.place_ortho_bracket" bl_label = "Ortho Bracket Place" bl_options = {'REGISTER', 'UNDO'} @classmethod def poll(cls, context): if context.mode == "OBJECT" and context.object != None: return True else: return False def modal_nav(self, event): events_nav = { 'MIDDLEMOUSE', 'WHEELINMOUSE', 'WHEELOUTMOUSE', 'WHEELUPMOUSE', 'WHEELDOWNMOUSE' } #TODO, better navigation, another tutorial handle_nav = False handle_nav |= event.type in events_nav if handle_nav: return 'nav' return '' def modal_main(self, context, event): # general navigation nmode = self.modal_nav(event) if nmode != '': return nmode #stop here and tell parent modal to 'PASS_THROUGH' if event.type == 'G' and event.value == 'PRESS' and self.bracket_slicer: self.bracket_slicer.prepare_slice() return 'grab' if event.type == 'T' and event.value == 'PRESS' and self.bracket_slicer: self.bracket_slicer.prepare_slice() return 'torque' if event.type == 'R' and event.value == 'PRESS' and self.bracket_slicer: self.bracket_slicer.prepare_slice() return 'rotate' if event.type == 'S' and event.value == 'PRESS' and self.bracket_slicer: self.bracket_slicer.prepare_slice() return 'tip' if event.type == 'MOUSEMOVE': return 'main' if event.type == 'LEFTMOUSE' and event.value == 'PRESS': x, y = event.mouse_region_x, event.mouse_region_y self.bracket_manager.place_bracket(context, x, y) return 'main' if event.type == 'RET' and event.value == 'PRESS': if self.bracket_slicer: self.bracket_slicer.cache_slice_to_grease(context) return 'finish' elif event.type == 'ESC' and event.value == 'PRESS': del_obj = self.bracket_manager.bracket_obj context.scene.objects.unlink(del_obj) bpy.data.objects.remove(del_obj) return 'cancel' return 'main' def modal_torque(self, context, event): # no navigation in grab mode if event.type in {'LEFTMOUSE', 'RET', 'ENTER' } and event.value == 'PRESS': #confirm location self.bracket_slicer.slice_confirm() return 'main' elif event.type in {'RIGHTMOUSE', 'ESC'} and event.value == 'PRESS': #put it back! self.bracket_slicer.slice_cancel() return 'main' #elif event.type == 'MOUSEMOVE': #update the b_pt location # self.bracket_slicer.slice_mouse_move(context,event.mouse_region_x, event.mouse_region_y) # return 'torque' elif event.type in { 'WHEELUPMOUSE', 'WHEELDOWNMOUSE', 'UP_ARROW', 'DOWN_ARROW' }: self.bracket_manager.torque_event(event.type, event.shift) self.bracket_slicer.slice() return 'torque' def modal_rotate(self, context, event): # no navigation in grab mode if event.type in {'LEFTMOUSE', 'RET', 'ENTER' } and event.value == 'PRESS': #confirm location self.bracket_slicer.slice_confirm() return 'main' elif event.type in {'RIGHTMOUSE', 'ESC'} and event.value == 'PRESS': #put it back! self.bracket_slicer.slice_cancel() return 'main' #commented out, no longer want to move the mouse #elif event.type == 'MOUSEMOVE': #update the b_pt location # self.bracket_slicer.slice_mouse_move(context,event.mouse_region_x, event.mouse_region_y) # return 'rotate' elif event.type in { 'WHEELUPMOUSE', 'WHEELDOWNMOUSE', 'LEFT_ARROW', 'RIGHT_ARROW' }: self.bracket_manager.rotate_event(event.type, event.shift) self.bracket_slicer.slice() return 'rotate' else: return 'rotate' def modal_tip(self, context, event): # no navigation in grab mode if event.type in {'LEFTMOUSE', 'RET', 'ENTER' } and event.value == 'PRESS': #confirm location self.bracket_slicer.slice_confirm() return 'main' elif event.type in {'RIGHTMOUSE', 'ESC'} and event.value == 'PRESS': #put it back! self.bracket_slicer.slice_cancel() return 'main' #commented out, no longer want to move the mouse #elif event.type == 'MOUSEMOVE': #update the b_pt location # self.bracket_slicer.slice_mouse_move(context,event.mouse_region_x, event.mouse_region_y) # return 'rotate' elif event.type in { 'WHEELUPMOUSE', 'WHEELDOWNMOUSE', 'LEFT_ARROW', 'RIGHT_ARROW' }: self.bracket_manager.spin_event(event.type, event.shift) self.bracket_slicer.slice() return 'tip' else: return 'tip' def modal_start(self, context, event): if event.type == 'LEFTMOUSE' and event.value == 'PRESS': #confirm location self.bracket_slicer.slice_confirm() return 'main' elif event.type == 'MOUSEMOVE': x, y = event.mouse_region_x, event.mouse_region_y self.bracket_manager.place_bracket(context, x, y, normal=True) self.bracket_slicer.slice_mouse_move(context, event.mouse_region_x, event.mouse_region_y) return 'start' elif event.type in { 'WHEELUPMOUSE', 'WHEELDOWNMOUSE', 'UP_ARROW', 'DOWN_ARROW' }: self.bracket_manager.spin_event(event.type, event.shift) self.bracket_slicer.slice() return 'start' elif event.type == "RIGTMOUSE" and event.value == 'PRESS': del_obj = self.bracket_manager.bracket_obj context.scene.objects.unlink(del_obj) bpy.data.objects.remove(del_obj) return 'cancel' else: return 'start' def modal_grab(self, context, event): # no navigation in grab mode #uses the slicer to manage the grab if event.type == 'LEFTMOUSE' and event.value == 'PRESS': #confirm location self.bracket_slicer.slice_confirm() return 'main' elif event.type in {'RIGHTMOUSE', 'ESC'} and event.value == 'PRESS': #put it back! self.bracket_slicer.slice_cancel() return 'main' elif event.type == 'MOUSEMOVE': #update the b_pt location self.bracket_slicer.slice_mouse_move(context, event.mouse_region_x, event.mouse_region_y) return 'grab' elif event.type in { 'WHEELUPMOUSE', 'WHEELDOWNMOUSE', 'UP_ARROW', 'DOWN_ARROW' }: self.bracket_manager.spin_event(event.type, event.shift) self.bracket_slicer.slice() return 'grab' def modal(self, context, event): context.area.tag_redraw() FSM = {} FSM['start'] = self.modal_start FSM['main'] = self.modal_main FSM['rotate'] = self.modal_rotate FSM['grab'] = self.modal_grab FSM['torque'] = self.modal_torque FSM['tip'] = self.modal_tip FSM['nav'] = self.modal_nav nmode = FSM[self.mode](context, event) if nmode == 'nav': return {'PASS_THROUGH'} if nmode in {'finish', 'cancel'}: #clean up callbacks bpy.types.SpaceView3D.draw_handler_remove(self._handle, 'WINDOW') return {'FINISHED'} if nmode == 'finish' else {'CANCELLED'} if nmode: self.mode = nmode return {'RUNNING_MODAL'} def invoke(self, context, event): settings = get_settings() libpath = settings.ortho_lib assets = obj_list_from_lib(libpath) if settings.bracket in assets: current_obs = [ob.name for ob in bpy.data.objects] obj_from_lib(settings.ortho_lib, settings.bracket) for ob in bpy.data.objects: if ob.name not in current_obs: Bracket = ob Bracket.hide = False context.scene.objects.link(Bracket) else: Bracket = None if context.object and context.object.type == 'MESH': self.bracket_manager = BracketDataManager( context, snap_type='OBJECT', snap_object=context.object, name='Bracket', bracket=Bracket) self.bracket_slicer = BracektSlicer(context, self.bracket_manager) else: self.bracket_manager = BracketDataManager(context, snap_type='SCENE', snap_object=None, name='Bracket', bracket=Bracket) self.bracket_slicer = None help_txt = "DRAW MARGIN OUTLINE\n\nLeft Click on model to place bracket.\n G to grab \n S to show slice \n ENTER to confirm \n ESC to cancel" self.help_box = TextBox(context, 500, 500, 300, 200, 10, 20, help_txt) self.help_box.snap_to_corner(context, corner=[1, 1]) self.mode = 'start' self._handle = bpy.types.SpaceView3D.draw_handler_add( bracket_placement_draw_callback, (self, context), 'WINDOW', 'POST_PIXEL') context.window_manager.modal_handler_add(self) return {'RUNNING_MODAL'}