invoke_props_dialog()とマウスの事前移動を利用して、ポップアップメニューを常に指定位置・マウス相対位置に表示する方法を紹介する。
相対位置で、マウスの位置とかぶらないようにメニューを表示したり、
絶対位置で、作業の邪魔にならない画面端にメニューを表示したりすることができる。
Blenderのポップアップメニュー表示方法
Blenderのポップアップメニューには、 invoke_props_dialog() とinvoke_popup()がある。
それぞれ Operator の invoke の return に渡すことで、 draw に用意されたメニューが、マウス位置に表示される。
- invoke_props_dialog()
- OKボタンが下に表示され、OKをクリックするとexecuteが実行される。
- オプションを調整してからなんらかの処理を実行する、という機能に便利。
- invoke_popup()
- マウスを画面外から離すとすぐに消える。
- メニューを表示した後、楽に閉じたいときに便利。
ソースコード
ポップアップメニューはマウス位置に表示されるので、そのマウス位置を実行前に動かせば、メニューが表示される位置を変えることができる。
表示した後に1度だけ、マウスを元の位置に戻す処理を入れればよい。
(マウス位置が変わるので、invoke_popupにはこの方法は利用できない)
- マウスからの相対位置
- マウス位置を基準としたオプションの値の位置に出現させます。
- ウィンドウからの絶対位置
- X位置は、アクティブなエディターの左端からの位置です。
- Y位置は、ウィンドウ全体からの位置です。
- (X0としてもポップアップ画面が端に食い込むようにはなりません)
- (Y位置はポップアップ画面の縦幅によっては変わります)
import bpy from bpy.props import * from bpy.types import Panel, Operator class MISCMENU_OT_main(Operator): bl_idname = "miscmenu.misc_menu" bl_label = "Misc Menu" bl_description = "" bl_options = {'REGISTER', 'UNDO'} items = [ ("MOUSE","Mouse Position",""), ("MOUSE_RELATIVE","Mouse Relative",""), ("WINDOW_ABSOLUTE","Window Absolute","The X position is from the left edge of the active editor.\nY position is the position from the whole window"), ] window_position : EnumProperty(default="WINDOW_ABSOLUTE",name="Window Position",items= items) loc_x : IntProperty(name="X Location",default=300) loc_y : IntProperty(name="Y Location",default=600) menu_width : IntProperty(default=330, name = "Menu Width", description = "Width setting when menu layout is broken. \n Blender Settings-> Interface-> If 'Resolution Scale' is set to a value smaller than 1,\n icons may be squished together so closely",min = 0) def invoke(self, context, event): # マウス位置を保存 self.mouse_snap = False self.old_mouse_x = event.mouse_x self.old_mouse_y = event.mouse_y # アクティブエリアのサイズ a = bpy.context.area for r in a.regions: if r.type == 'WINDOW': win_x = r.x win_y = r.y break # マウスからの相対位置 if self.window_position == "MOUSE_RELATIVE": bpy.context.window.cursor_warp(event.mouse_x + self.loc_x,event.mouse_y + self.loc_y) # Xは、エディター左上からの絶対位置 # Yは、ウィンドウからの絶対位置(エディターのY位置の取得方法がわからなかった) elif self.window_position == "WINDOW_ABSOLUTE": bpy.context.window.cursor_warp(win_x + self.loc_x, bpy.context.window.height - self.loc_y) return context.window_manager.invoke_props_dialog(self, width=self.menu_width) def draw(self, context): ad_prefs = preference() if ad_prefs.use_dialog: if not self.mouse_snap: # 描画開始の最初だけ実行し、マウス位置を元に戻す self.mouse_snap = True bpy.context.window.cursor_warp(self.old_mouse_x, self.old_mouse_y) main_menu(self, context) def execute(self, context): return {'FINISHED'}